diff --git a/CREDITS b/CREDITS
--- a/CREDITS
+++ b/CREDITS
@@ -34,8 +34,9 @@ N: Dave Airlie
 E: airlied@linux.ie
 W: http://www.csn.ul.ie/~airlied
 D: NFS over TCP patches
-S: University of Limerick
-S: Ireland
+D: in-kernel DRM Maintainer
+S: Longford, Ireland
+S: Sydney, Australia
 
 N: Tigran A. Aivazian
 E: tigran@veritas.com
@@ -328,8 +329,6 @@ S: Brimson, MN  55602
 S: USA
 
 N: Hennus Bergman
-E: hennus@cybercomm.nl
-W: http://www.cybercomm.nl/~hennus/
 P: 1024/77D50909 76 99 FD 31 91 E1 96 1C  90 BB 22 80 62 F6 BD 63
 D: Author and maintainer of the QIC-02 tape driver
 S: The Netherlands
@@ -340,7 +339,7 @@ W: http://tomas.nocrew.org/
 D: dsp56k device driver
 
 N: Ross Biro
-E: bir7@leland.Stanford.Edu
+E: ross.biro@gmail.com
 D: Original author of the Linux networking code
 
 N: Anton Blanchard
@@ -841,6 +840,11 @@ E: cort@fsmlabs.com
 W: http://www.fsmlabs.com/linuxppcbk.html
 D: PowerPC
 
+N: Daniel Drake
+E: dsd@gentoo.org
+D: USBAT02 CompactFlash support in usb-storage
+S: UK
+
 N: Oleg Drokin
 E: green@ccssu.crimea.ua
 W: http://www.ccssu.crimea.ua/~green
@@ -878,13 +882,12 @@ S: Blacksburg, Virginia 24061
 S: USA
 
 N: Randy Dunlap
-E: rddunlap@osdl.org
+E: rdunlap@xenotime.net
 W: http://www.xenotime.net/linux/linux.html
 W: http://www.linux-usb.org
 D: Linux-USB subsystem, USB core/UHCI/printer/storage drivers
 D: x86 SMP, ACPI, bootflag hacking
-S: 12725 SW Millikan Way, Suite 400
-S: Beaverton, Oregon 97005
+S: (ask for current address)
 S: USA
 
 N: Bob Dunlop
@@ -1095,7 +1098,7 @@ S: Brazil
 
 N: Kumar Gala
 E: kumar.gala@freescale.com
-D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support
+D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support
 S: Austin, Texas 78729
 S: USA
 
@@ -1954,7 +1957,8 @@ S: Germany
 N: Colin Leroy
 E: colin@colino.net
 W: http://www.geekounet.org/
-D: PowerMac adt7467 fan driver
+D: PowerMac adt746x fan driver
+D: Random fixing of various drivers (macintosh, usb, sound)
 S: Toulouse
 S: France
 
@@ -2471,13 +2475,9 @@ S: Potsdam, New York 13676
 S: USA
 
 N: Dave Neuer
-E: dneuer@innovation-charter.com
-E: mr_fred_smoothie@yahoo.com
+E: dave.neuer@pobox.com
 D: Helped implement support for Compaq's H31xx series iPAQs
 D: Other mostly minor tweaks & bugfixes
-S: 325 E. Main St., Suite 3
-S: Carnegie, PA 15105
-S: USA
 
 N: Michael Neuffer
 E: mike@i-Connect.Net
@@ -3294,6 +3294,7 @@ D: Author of the new e2fsck
 D: Author of job control and system call restart code
 D: Author of ramdisk device driver
 D: Author of loopback device driver
+D: Author of /dev/random driver
 S: MIT Room E40-343
 S: 1 Amherst Street
 S: Cambridge, Massachusetts 02139
@@ -3351,10 +3352,11 @@ S: Santa Clara, CA 95054
 S: USA
 
 N: Matthias Urlichs
-E: urlichs@noris.de
-E: urlichs@smurf.sub.org
+E: smurf@smurf.noris.de
+E: smurf@debian.org
+E: matthias@urlichs.de
 D: Consultant, developer, kernel hacker
-D: Playing with Streams, ISDN, and BSD networking code for Linux
+D: In a previous life, worked on Streams/ISDN/BSD networking code for Linux
 S: Schleiermacherstrasse 12
 S: 90491 Nuernberg
 S: Germany
@@ -3426,6 +3428,7 @@ N: Jeroen Vreeken
 E: pe1rxq@amsat.org
 W: http://www.chello.nl/~j.vreeken/
 D: SE401 usb webcam driver
+D: ZD1201 usb wireless lan driver
 S: Maastrichterweg 63
 S: 5554 GG Valkenswaard
 S: The Netherlands
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -12,8 +12,6 @@ Following translations are available on 
 
 00-INDEX
 	- this file.
-BK-usage/
-	- directory with info on BitKeeper.
 BUG-HUNTING
 	- brute force method of doing binary search of patches to find bug.
 Changes
diff --git a/Documentation/BK-usage/00-INDEX b/Documentation/BK-usage/00-INDEX
deleted file mode 100644
--- a/Documentation/BK-usage/00-INDEX
+++ /dev/null
@@ -1,51 +0,0 @@
-bk-kernel-howto.txt: Description of kernel workflow under BitKeeper
-
-bk-make-sum: Create summary of changesets in one repository and not
-another, typically in preparation to be sent to an upstream maintainer.
-Typical usage:
-	cd my-updated-repo
-	bk-make-sum ~/repo/original-repo
-	mv /tmp/linus.txt ../original-repo.txt
-
-bksend: Create readable text output containing summary of changes, GNU
-patch of the changes, and BK metadata of changes (as needed for proper
-importing into BitKeeper by an upstream maintainer).  This output is
-suitable for emailing BitKeeper changes.  The recipient of this output
-may pipe it directly to 'bk receive'.
-
-bz64wrap: helper script. Uncompressed input is piped to this script,
-which compresses its input, and then outputs the uu-/base64-encoded
-version of the compressed input.
-
-cpcset: Copy changeset between unrelated repositories.
-Attempts to preserve changeset user, user address, description, in
-addition to the changeset (the patch) itself.
-Typical usage:
-	cd my-updated-repo
-	bk changes	# looking for a changeset...
-	cpcset 1.1511 . ../another-repo
-
-csets-to-patches: Produces a delta of two BK repositories, in the form
-of individual files, each containing a single cset as a GNU patch.
-Output is several files, each with the filename "/tmp/rev-$REV.patch"
-Typical usage:
-	cd my-updated-repo
-	bk changes -L ~/repo/original-repo 2>&1 | \
-		perl csets-to-patches
-
-cset-to-linus: Produces a delta of two BK repositories, in the form of
-changeset descriptions, with 'diffstat' output created for each
-individual changset.
-Typical usage:
-	cd my-updated-repo
-	bk changes -L ~/repo/original-repo 2>&1 | \
-		perl cset-to-linus > summary.txt
-
-gcapatch:  Generates patch containing changes in local repository.
-Typical usage:
-	cd my-updated-repo
-	gcapatch > foo.patch
-
-unbz64wrap: Reverse an encoded, compressed data stream created by
-bz64wrap into an uncompressed, typically text/plain output.
-
diff --git a/Documentation/BK-usage/bk-kernel-howto.txt b/Documentation/BK-usage/bk-kernel-howto.txt
deleted file mode 100644
--- a/Documentation/BK-usage/bk-kernel-howto.txt
+++ /dev/null
@@ -1,283 +0,0 @@
-
-		   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 (except the root/original, of course).
-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 changes -L <parent>", 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).
-
-
-3) Is there an easy way to generate One Big Patch versus mainline,
-   for my long-lived kernel branch?
-A. Yes.  This requires BK 3.x, though.
-
-	bk export -tpatch -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+
-
diff --git a/Documentation/BK-usage/bk-make-sum b/Documentation/BK-usage/bk-make-sum
deleted file mode 100755
--- a/Documentation/BK-usage/bk-make-sum
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh -e
-# DIR=$HOME/BK/axp-2.5
-# cd $DIR
-
-LINUS_REPO=$1
-DIRBASE=`basename $PWD`
-
-{
-cat <<EOT
-Please do a
-
-	bk pull bk://gkernel.bkbits.net/$DIRBASE
-
-This will update the following files:
-
-EOT
-
-bk export -tpatch -hdu -r`bk repogca $LINUS_REPO`,+ | 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 --git a/Documentation/BK-usage/bksend b/Documentation/BK-usage/bksend
deleted file mode 100755
--- a/Documentation/BK-usage/bksend
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/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 --git a/Documentation/BK-usage/bz64wrap b/Documentation/BK-usage/bz64wrap
deleted file mode 100755
--- a/Documentation/BK-usage/bz64wrap
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/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 --git a/Documentation/BK-usage/cpcset b/Documentation/BK-usage/cpcset
deleted file mode 100755
--- a/Documentation/BK-usage/cpcset
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-#
-# Purpose: Copy changeset patch and description from one
-#	   repository to another, unrelated one.
-#
-# usage:  cpcset [revision] [from-repository] [to-repository]
-#
-
-REV=$1
-FROM=$2
-TO=$3
-TMPF=/tmp/cpcset.$$
-
-rm -f $TMPF*
-
-CWD_SAVE=`pwd`
-cd $FROM
-bk changes -r$REV			|	\
-	grep -v '^ChangeSet'		|	\
-	sed -e 's/^  //g' > $TMPF.log
-
-USERHOST=`bk changes -r$REV | grep '^ChangeSet' | awk '{print $4}'`
-export BK_USER=`echo $USERHOST | awk '-F@' '{print $1}'`
-export BK_HOST=`echo $USERHOST | awk '-F@' '{print $2}'`
-
-bk export -tpatch -hdu -r$REV > $TMPF.patch && \
-cd $CWD_SAVE && \
-cd $TO && \
-bk import -tpatch -CFR -y"`cat $TMPF.log`" $TMPF.patch . && \
-bk commit -y"`cat $TMPF.log`"
-
-rm -f $TMPF*
-
-echo changeset $REV copied.
-echo ""
-
diff --git a/Documentation/BK-usage/cset-to-linus b/Documentation/BK-usage/cset-to-linus
deleted file mode 100755
--- a/Documentation/BK-usage/cset-to-linus
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/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 --git a/Documentation/BK-usage/csets-to-patches b/Documentation/BK-usage/csets-to-patches
deleted file mode 100755
--- a/Documentation/BK-usage/csets-to-patches
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/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 --git a/Documentation/BK-usage/gcapatch b/Documentation/BK-usage/gcapatch
deleted file mode 100755
--- a/Documentation/BK-usage/gcapatch
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-#
-# Purpose: Generate GNU diff of local changes versus canonical top-of-tree
-#
-# Usage: gcapatch > foo.patch
-#
-
-bk export -tpatch -hdu -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+
diff --git a/Documentation/BK-usage/unbz64wrap b/Documentation/BK-usage/unbz64wrap
deleted file mode 100755
--- a/Documentation/BK-usage/unbz64wrap
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/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 --git a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -339,7 +339,7 @@ o  <http://prdownloads.sourceforge.net/e
 
 JFSutils
 --------
-o  <http://oss.software.ibm.com/jfs>
+o  <http://jfs.sourceforge.net/>
 
 Reiserfsprogs
 -------------
@@ -357,14 +357,14 @@ Quota-tools
 ----------
 o  <http://sourceforge.net/projects/linuxquota/>
 
-Jade
-----
-o  <ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz>
-
 DocBook Stylesheets
 -------------------
 o  <http://nwalsh.com/docbook/dsssl/>
 
+XMLTO XSLT Frontend
+-------------------
+o  <http://cyberelk.net/tim/xmlto/>
+
 Intel P6 microcode
 ------------------
 o  <http://www.urbanmyth.org/microcode/>
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -443,15 +443,9 @@ Only streaming mappings specify a direct
 implicitly have a direction attribute setting of
 PCI_DMA_BIDIRECTIONAL.
 
-The SCSI subsystem provides mechanisms for you to easily obtain
-the direction to use, in the SCSI command:
-
-	scsi_to_pci_dma_dir(SCSI_DIRECTION)
-
-Where SCSI_DIRECTION is obtained from the 'sc_data_direction'
-member of the SCSI command your driver is working on.  The
-mentioned interface above returns a value suitable for passing
-into the streaming DMA mapping interfaces below.
+The SCSI subsystem tells you the direction to use in the
+'sc_data_direction' member of the SCSI command your driver is
+working on.
 
 For Networking drivers, it's a rather simple affair.  For transmit
 packets, map/unmap them with the PCI_DMA_TODEVICE direction
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -6,56 +6,58 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-DOCBOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
-	    kernel-hacking.sgml kernel-locking.sgml via-audio.sgml \
-	    deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
-	    writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \
-	    kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \
-	    gadget.sgml libata.sgml mtdnand.sgml librs.sgml
+DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
+	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
+	    procfs-guide.xml writing_usb_driver.xml scsidrivers.xml \
+	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
+	    gadget.xml libata.xml mtdnand.xml librs.xml
 
 ###
 # The build process is as follows (targets):
-#              (sgmldocs)
-# file.tmpl --> file.sgml +--> file.ps  (psdocs)
-#                         +--> file.pdf  (pdfdocs)
-#                         +--> DIR=file  (htmldocs)
-#                         +--> man/      (mandocs)
+#              (xmldocs)
+# file.tmpl --> file.xml +--> file.ps   (psdocs)
+#                        +--> file.pdf  (pdfdocs)
+#                        +--> DIR=file  (htmldocs)
+#                        +--> man/      (mandocs)
 
 ###
 # The targets that may be used.
-.PHONY:	sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs
+.PHONY:	xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs
 
 BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
-sgmldocs: $(BOOKS)
+xmldocs: $(BOOKS)
+sgmldocs: xmldocs
 
-PS := $(patsubst %.sgml, %.ps, $(BOOKS))
+PS := $(patsubst %.xml, %.ps, $(BOOKS))
 psdocs: $(PS)
 
-PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
+PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
 pdfdocs: $(PDF)
 
-HTML := $(patsubst %.sgml, %.html, $(BOOKS))
+HTML := $(patsubst %.xml, %.html, $(BOOKS))
 htmldocs: $(HTML)
 
-MAN := $(patsubst %.sgml, %.9, $(BOOKS))
+MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
 
 installmandocs: mandocs
-	$(MAKEMAN) install Documentation/DocBook/man
+	mkdir -p /usr/local/man/man9/
+	install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/
 
 ###
 #External programs used
 KERNELDOC = scripts/kernel-doc
 DOCPROC   = scripts/basic/docproc
-SPLITMAN  = $(PERL) $(srctree)/scripts/split-man
-MAKEMAN   = $(PERL) $(srctree)/scripts/makeman
+
+XMLTOFLAGS = -m Documentation/DocBook/stylesheet.xsl
+#XMLTOFLAGS += --skip-validation
 
 ###
 # DOCPROC is used for two purposes:
 # 1) To generate a dependency list for a .tmpl file
 # 2) To preprocess a .tmpl file and call kernel-doc with
 #     appropriate parameters.
-# The following rules are used to generate the .sgml documentation
+# The following rules are used to generate the .xml documentation
 # required to generate the final targets. (ps, pdf, html).
 quiet_cmd_docproc = DOCPROC $@
       cmd_docproc = SRCTREE=$(srctree)/ $(DOCPROC) doc $< >$@
@@ -69,7 +71,7 @@ define rule_docproc
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
-%.sgml: %.tmpl FORCE
+%.xml: %.tmpl FORCE
 	$(call if_changed_rule,docproc)
 
 ###
@@ -87,53 +89,52 @@ $(BOOKS): $(KERNELDOC)
 ###
 # procfs guide uses a .c file as example code.
 # This requires an explicit dependency
-C-procfs-example = procfs_example.sgml
+C-procfs-example = procfs_example.xml
 C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example))
-$(obj)/procfs-guide.sgml: $(C-procfs-example2)
+$(obj)/procfs-guide.xml: $(C-procfs-example2)
 
 ###
 # Rules to generate postscript, PDF and HTML
 # db2html creates a directory. Generate a html file used for timestamp
 
-quiet_cmd_db2ps = DB2PS   $@
-      cmd_db2ps = db2ps -o $(dir $@) $<
-%.ps : %.sgml
-	@(which db2ps > /dev/null 2>&1) || \
-	 (echo "*** You need to install DocBook stylesheets ***"; \
+quiet_cmd_db2ps = XMLTO    $@
+      cmd_db2ps = xmlto ps $(XMLTOFLAGS) -o $(dir $@) $<
+%.ps : %.xml
+	@(which xmlto > /dev/null 2>&1) || \
+	 (echo "*** You need to install xmlto ***"; \
 	  exit 1)
 	$(call cmd,db2ps)
 
-quiet_cmd_db2pdf = DB2PDF  $@
-      cmd_db2pdf = db2pdf -o $(dir $@) $<
-%.pdf : %.sgml
-	@(which db2pdf > /dev/null 2>&1) || \
-	 (echo "*** You need to install DocBook stylesheets ***"; \
+quiet_cmd_db2pdf = XMLTO   $@
+      cmd_db2pdf = xmlto pdf $(XMLTOFLAGS) -o $(dir $@) $<
+%.pdf : %.xml
+	@(which xmlto > /dev/null 2>&1) || \
+	 (echo "*** You need to install xmlto ***"; \
 	  exit 1)
 	$(call cmd,db2pdf)
 
-quiet_cmd_db2html = DB2HTML $@
-      cmd_db2html = db2html -o $(patsubst %.html,%,$@) $< &&		      \
-		echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/book1.html"> \
+quiet_cmd_db2html = XMLTO  $@
+      cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
+		echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
          Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
 
-%.html:	%.sgml
-	@(which db2html > /dev/null 2>&1) || \
-	 (echo "*** You need to install DocBook stylesheets ***"; \
+%.html:	%.xml
+	@(which xmlto > /dev/null 2>&1) || \
+	 (echo "*** You need to install xmlto ***"; \
 	  exit 1)
 	@rm -rf $@ $(patsubst %.html,%,$@)
 	$(call cmd,db2html)
 	@if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \
             cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi
 
-###
-# Rule to generate man files - output is placed in the man subdirectory
-
-%.9:	%.sgml
-ifneq ($(KBUILD_SRC),)
-	$(Q)mkdir -p $(objtree)/Documentation/DocBook/man
-endif
-	$(SPLITMAN) $< $(objtree)/Documentation/DocBook/man "$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)"
-	$(MAKEMAN) convert $(objtree)/Documentation/DocBook/man $<
+quiet_cmd_db2man = XMLTO   $@
+      cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi
+%.9 : %.xml
+	@(which xmlto > /dev/null 2>&1) || \
+	 (echo "*** You need to install xmlto ***"; \
+	  exit 1)
+	$(call cmd,db2man)
+	@touch $@
 
 ###
 # Rules to generate postscripts and PNG imgages from .fig format files
@@ -156,8 +157,8 @@ quiet_cmd_fig2png = FIG2PNG $@
 	$(call cmd,fig2png)
 
 ###
-# Rule to convert a .c file to inline SGML documentation
-%.sgml: %.c
+# Rule to convert a .c file to inline XML documentation
+%.xml: %.c
 	@echo '  GEN     $@'
 	@(                            \
 	   echo "<programlisting>";   \
@@ -171,24 +172,24 @@ quiet_cmd_fig2png = FIG2PNG $@
 # Help targets as used by the top-level makefile
 dochelp:
 	@echo  '  Linux kernel internal documentation in different formats:'
-	@echo  '  sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF)'
+	@echo  '  xmldocs (XML DocBook), psdocs (Postscript), pdfdocs (PDF)'
 	@echo  '  htmldocs (HTML), mandocs (man pages, use installmandocs to install)'
 
 ###
 # Temporary files left by various tools
 clean-files := $(DOCBOOKS) \
-	$(patsubst %.sgml, %.dvi,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.aux,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.tex,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.log,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.out,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.ps,   $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.pdf,  $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.html, $(DOCBOOKS)) \
-	$(patsubst %.sgml, %.9,    $(DOCBOOKS)) \
+	$(patsubst %.xml, %.dvi,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.aux,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.tex,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.log,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.out,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.ps,   $(DOCBOOKS)) \
+	$(patsubst %.xml, %.pdf,  $(DOCBOOKS)) \
+	$(patsubst %.xml, %.html, $(DOCBOOKS)) \
+	$(patsubst %.xml, %.9,    $(DOCBOOKS)) \
 	$(C-procfs-example)
 
-clean-dirs := $(patsubst %.sgml,%,$(DOCBOOKS))
+clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS))
 
 #man put files in man subdir - traverse down
 subdir- := man/
diff --git a/Documentation/DocBook/deviceiobook.tmpl b/Documentation/DocBook/deviceiobook.tmpl
--- a/Documentation/DocBook/deviceiobook.tmpl
+++ b/Documentation/DocBook/deviceiobook.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="DoingIO">
  <bookinfo>
diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl
--- a/Documentation/DocBook/gadget.tmpl
+++ b/Documentation/DocBook/gadget.tmpl
@@ -1,4 +1,7 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
 <book id="USB-Gadget-API">
   <bookinfo>
     <title>USB Gadget API for Linux</title>
diff --git a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl
--- a/Documentation/DocBook/journal-api.tmpl
+++ b/Documentation/DocBook/journal-api.tmpl
@@ -1,4 +1,7 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
 <book id="LinuxJBDAPI">
  <bookinfo>
   <title>The Linux Journalling API</title>
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -1,4 +1,7 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
 <book id="LinuxKernelAPI">
  <bookinfo>
   <title>The Linux Kernel API</title>
@@ -46,13 +49,33 @@
 !Iinclude/asm-i386/unaligned.h
      </sect1>
 
-<!-- FIXME:
-  kernel/sched.c has no docs, which stuffs up the sgml.  Comment
-  out until somebody adds docs.  KAO
      <sect1><title>Delaying, scheduling, and timer routines</title>
-X!Ekernel/sched.c
+!Iinclude/linux/sched.h
+!Ekernel/sched.c
+!Ekernel/timer.c
+     </sect1>
+     <sect1><title>Internal Functions</title>
+!Ikernel/exit.c
+!Ikernel/signal.c
      </sect1>
-KAO -->
+
+     <sect1><title>Kernel objects manipulation</title>
+<!--
+X!Iinclude/linux/kobject.h
+-->
+!Elib/kobject.c
+     </sect1>
+
+     <sect1><title>Kernel utility functions</title>
+!Iinclude/linux/kernel.h
+<!-- This needs to clean up to make kernel-doc happy
+X!Ekernel/printk.c
+ -->
+!Ekernel/panic.c
+!Ekernel/sys.c
+!Ekernel/rcupdate.c
+     </sect1>
+
   </chapter>
 
   <chapter id="adt">
@@ -78,7 +101,9 @@ KAO -->
 !Elib/vsprintf.c
      </sect1>
      <sect1><title>String Manipulation</title>
-!Ilib/string.c
+<!-- All functions are exported at now
+X!Ilib/string.c
+ -->
 !Elib/string.c
      </sect1>
      <sect1><title>Bit Operations</title>
@@ -95,6 +120,33 @@ KAO -->
 !Iinclude/asm-i386/uaccess.h
 !Iarch/i386/lib/usercopy.c
      </sect1>
+     <sect1><title>More Memory Management Functions</title>
+!Iinclude/linux/rmap.h
+!Emm/readahead.c
+!Emm/filemap.c
+!Emm/memory.c
+!Emm/vmalloc.c
+!Emm/mempool.c
+!Emm/page-writeback.c
+!Emm/truncate.c
+     </sect1>
+  </chapter>
+
+
+  <chapter id="ipc">
+     <title>Kernel IPC facilities</title>
+
+     <sect1><title>IPC utilities</title>
+!Iipc/util.c
+     </sect1>
+  </chapter>
+
+  <chapter id="kfifo">
+     <title>FIFO Buffer</title>
+     <sect1><title>kfifo interface</title>
+!Iinclude/linux/kfifo.h
+!Ekernel/kfifo.c
+     </sect1>
   </chapter>
 
   <chapter id="proc">
@@ -103,6 +155,10 @@ KAO -->
      <sect1><title>sysctl interface</title>
 !Ekernel/sysctl.c
      </sect1>
+
+     <sect1><title>proc filesystem interface</title>
+!Ifs/proc/base.c
+     </sect1>
   </chapter>
 
   <chapter id="debugfs">
@@ -116,6 +172,10 @@ KAO -->
 
   <chapter id="vfs">
      <title>The Linux VFS</title>
+     <sect1><title>The Filesystem types</title>
+!Iinclude/linux/fs.h
+!Einclude/linux/fs.h
+     </sect1>
      <sect1><title>The Directory Cache</title>
 !Efs/dcache.c
 !Iinclude/linux/dcache.h
@@ -131,13 +191,31 @@ KAO -->
 !Efs/locks.c
 !Ifs/locks.c
      </sect1>
+     <sect1><title>Other Functions</title>
+!Efs/mpage.c
+!Efs/namei.c
+!Efs/buffer.c
+!Efs/bio.c
+!Efs/seq_file.c
+!Efs/filesystems.c
+!Efs/fs-writeback.c
+!Efs/block_dev.c
+     </sect1>
   </chapter>
 
   <chapter id="netcore">
      <title>Linux Networking</title>
+     <sect1><title>Networking Base Types</title>
+!Iinclude/linux/net.h
+     </sect1>
      <sect1><title>Socket Buffer Functions</title>
 !Iinclude/linux/skbuff.h
+!Iinclude/net/sock.h
+!Enet/socket.c
 !Enet/core/skbuff.c
+!Enet/core/sock.c
+!Enet/core/datagram.c
+!Enet/core/stream.c
      </sect1>
      <sect1><title>Socket Filter</title>
 !Enet/core/filter.c
@@ -147,6 +225,14 @@ KAO -->
 !Enet/core/gen_stats.c
 !Enet/core/gen_estimator.c
      </sect1>
+     <sect1><title>SUN RPC subsystem</title>
+<!-- The !D functionality is not perfect, garbage has to be protected by comments
+!Dnet/sunrpc/sunrpc_syms.c
+-->
+!Enet/sunrpc/xdr.c
+!Enet/sunrpc/svcsock.c
+!Enet/sunrpc/sched.c
+     </sect1>
   </chapter>
 
   <chapter id="netdev">
@@ -183,11 +269,26 @@ X!Ekernel/module.c
 !Iarch/i386/kernel/irq.c
      </sect1>
 
+     <sect1><title>Resources Management</title>
+!Ekernel/resource.c
+     </sect1>
+
      <sect1><title>MTRR Handling</title>
 !Earch/i386/kernel/cpu/mtrr/main.c
      </sect1>
      <sect1><title>PCI Support Library</title>
 !Edrivers/pci/pci.c
+!Edrivers/pci/pci-driver.c
+!Edrivers/pci/remove.c
+!Edrivers/pci/pci-acpi.c
+<!-- kerneldoc does not understand to __devinit
+X!Edrivers/pci/search.c
+ -->
+!Edrivers/pci/msi.c
+!Edrivers/pci/bus.c
+!Edrivers/pci/hotplug.c
+!Edrivers/pci/probe.c
+!Edrivers/pci/rom.c
      </sect1>
      <sect1><title>PCI Hotplug Support Library</title>
 !Edrivers/pci/hotplug/pci_hotplug_core.c
@@ -212,6 +313,14 @@ X!Earch/i386/kernel/mca.c
 !Efs/devfs/base.c
   </chapter>
 
+  <chapter id="sysfs">
+     <title>The Filesystem for Exporting Kernel Objects</title>
+!Efs/sysfs/file.c
+!Efs/sysfs/dir.c
+!Efs/sysfs/symlink.c
+!Efs/sysfs/bin.c
+  </chapter>
+
   <chapter id="security">
      <title>Security Framework</title>
 !Esecurity/security.c
@@ -222,6 +331,61 @@ X!Earch/i386/kernel/mca.c
 !Ekernel/power/pm.c
   </chapter>
 
+  <chapter id="devdrivers">
+     <title>Device drivers infrastructure</title>
+     <sect1><title>Device Drivers Base</title>
+<!--
+X!Iinclude/linux/device.h
+-->
+!Edrivers/base/driver.c
+!Edrivers/base/class_simple.c
+!Edrivers/base/core.c
+!Edrivers/base/firmware_class.c
+!Edrivers/base/transport_class.c
+!Edrivers/base/dmapool.c
+<!-- Cannot be included, because
+     attribute_container_add_class_device_adapter
+ and attribute_container_classdev_to_container
+     exceed allowed 44 characters maximum
+X!Edrivers/base/attribute_container.c
+-->
+!Edrivers/base/sys.c
+<!--
+X!Edrivers/base/interface.c
+-->
+!Edrivers/base/platform.c
+!Edrivers/base/bus.c
+     </sect1>
+     <sect1><title>Device Drivers Power Management</title>
+!Edrivers/base/power/main.c
+!Edrivers/base/power/resume.c
+!Edrivers/base/power/suspend.c
+     </sect1>
+     <sect1><title>Device Drivers ACPI Support</title>
+<!-- Internal functions only
+X!Edrivers/acpi/sleep/main.c
+X!Edrivers/acpi/sleep/wakeup.c
+X!Edrivers/acpi/motherboard.c
+X!Edrivers/acpi/bus.c
+-->
+!Edrivers/acpi/scan.c
+<!-- No correct structured comments
+X!Edrivers/acpi/pci_bind.c
+-->
+     </sect1>
+     <sect1><title>Device drivers PnP support</title>
+!Edrivers/pnp/core.c
+<!-- No correct structured comments
+X!Edrivers/pnp/system.c
+ -->
+!Edrivers/pnp/card.c
+!Edrivers/pnp/driver.c
+!Edrivers/pnp/manager.c
+!Edrivers/pnp/support.c
+     </sect1>
+  </chapter>
+
+
   <chapter id="blkdev">
      <title>Block Devices</title>
 !Edrivers/block/ll_rw_blk.c
@@ -239,7 +403,23 @@ X!Earch/i386/kernel/mca.c
 
   <chapter id="snddev">
      <title>Sound Devices</title>
+!Iinclude/sound/core.h
 !Esound/sound_core.c
+!Iinclude/sound/pcm.h
+!Esound/core/pcm.c
+!Esound/core/device.c
+!Esound/core/info.c
+!Esound/core/rawmidi.c
+!Esound/core/sound.c
+!Esound/core/memory.c
+!Esound/core/pcm_memory.c
+!Esound/core/init.c
+!Esound/core/isadma.c
+!Esound/core/control.c
+!Esound/core/pcm_lib.c
+!Esound/core/hwdep.c
+!Esound/core/pcm_native.c
+!Esound/core/memalloc.c
 <!-- FIXME: Removed for now since no structured comments in source
 X!Isound/sound_firmware.c
 -->
@@ -247,6 +427,7 @@ X!Isound/sound_firmware.c
 
   <chapter id="uart16x50">
      <title>16x50 UART Driver</title>
+!Iinclude/linux/serial_core.h
 !Edrivers/serial/serial_core.c
 !Edrivers/serial/8250.c
   </chapter>
@@ -299,9 +480,11 @@ X!Isound/sound_firmware.c
      <sect1><title>Frame Buffer Memory</title>
 !Edrivers/video/fbmem.c
      </sect1>
+<!--
      <sect1><title>Frame Buffer Console</title>
-!Edrivers/video/console/fbcon.c
+X!Edrivers/video/console/fbcon.c
      </sect1>
+-->
      <sect1><title>Frame Buffer Colormap</title>
 !Edrivers/video/fbcmap.c
      </sect1>
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="lk-hacking-guide">
  <bookinfo>
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="LKLockingGuide">
  <bookinfo>
@@ -236,12 +238,12 @@
      your task will put itself on the queue, and be woken up when the
      semaphore is released.  This means the CPU will do something
      else while you are waiting, but there are many cases when you
-     simply can't sleep (see <xref linkend="sleeping-things">), and so
+     simply can't sleep (see <xref linkend="sleeping-things"/>), and so
      have to use a spinlock instead.
    </para>
    <para>
      Neither type of lock is recursive: see
-     <xref linkend="deadlock">.
+     <xref linkend="deadlock"/>.
    </para>
    </sect1>
  
@@ -326,7 +328,7 @@
     <para>
       Note that you can also use <function>spin_lock_irq()</function>
       or <function>spin_lock_irqsave()</function> here, which stop
-      hardware interrupts as well: see <xref linkend="hardirq-context">.
+      hardware interrupts as well: see <xref linkend="hardirq-context"/>.
     </para>
 
     <para>
@@ -403,7 +405,7 @@
 
      <para>
        The same softirq can run on the other CPUs: you can use a
-       per-CPU array (see <xref linkend="per-cpu">) for better
+       per-CPU array (see <xref linkend="per-cpu"/>) for better
        performance.  If you're going so far as to use a softirq,
        you probably care about scalable performance enough
        to justify the extra complexity.
@@ -545,120 +547,120 @@
    </para>
    <table>
 <title>Table of Locking Requirements</title>
-<TGROUP COLS="11">
-<TBODY>
-<ROW>
-<ENTRY></ENTRY>
-<ENTRY>IRQ Handler A</ENTRY>
-<ENTRY>IRQ Handler B</ENTRY>
-<ENTRY>Softirq A</ENTRY>
-<ENTRY>Softirq B</ENTRY>
-<ENTRY>Tasklet A</ENTRY>
-<ENTRY>Tasklet B</ENTRY>
-<ENTRY>Timer A</ENTRY>
-<ENTRY>Timer B</ENTRY>
-<ENTRY>User Context A</ENTRY>
-<ENTRY>User Context B</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>IRQ Handler A</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>IRQ Handler B</ENTRY>
-<ENTRY>spin_lock_irqsave</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Softirq A</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Softirq B</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Tasklet A</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Tasklet B</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Timer A</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>Timer B</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>spin_lock</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>User Context A</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-<ROW>
-<ENTRY>User Context B</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_irq</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>spin_lock_bh</ENTRY>
-<ENTRY>down_interruptible</ENTRY>
-<ENTRY>None</ENTRY>
-</ROW>
-
-</TBODY>
-</TGROUP>
-</TABLE>
+<tgroup cols="11">
+<tbody>
+<row>
+<entry></entry>
+<entry>IRQ Handler A</entry>
+<entry>IRQ Handler B</entry>
+<entry>Softirq A</entry>
+<entry>Softirq B</entry>
+<entry>Tasklet A</entry>
+<entry>Tasklet B</entry>
+<entry>Timer A</entry>
+<entry>Timer B</entry>
+<entry>User Context A</entry>
+<entry>User Context B</entry>
+</row>
+
+<row>
+<entry>IRQ Handler A</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>IRQ Handler B</entry>
+<entry>spin_lock_irqsave</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>Softirq A</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+</row>
+
+<row>
+<entry>Softirq B</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+</row>
+
+<row>
+<entry>Tasklet A</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>Tasklet B</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>Timer A</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>Timer B</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>spin_lock</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>User Context A</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>None</entry>
+</row>
+
+<row>
+<entry>User Context B</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_irq</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>spin_lock_bh</entry>
+<entry>down_interruptible</entry>
+<entry>None</entry>
+</row>
+
+</tbody>
+</tgroup>
+</table>
 </sect1>
 </chapter>
 
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="libataDevGuide">
  <bookinfo>
@@ -12,7 +14,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2003</year>
+   <year>2003-2005</year>
    <holder>Jeff Garzik</holder>
   </copyright>
 
@@ -42,30 +44,38 @@
 
 <toc></toc>
 
-  <chapter id="libataThanks">
-     <title>Thanks</title>
+  <chapter id="libataIntroduction">
+     <title>Introduction</title>
   <para>
-  The bulk of the ATA knowledge comes thanks to long conversations with
-  Andre Hedrick (www.linux-ide.org).
+  libATA is a library used inside the Linux kernel to support ATA host
+  controllers and devices.  libATA provides an ATA driver API, class
+  transports for ATA and ATAPI devices, and SCSI&lt;-&gt;ATA translation
+  for ATA devices according to the T10 SAT specification.
   </para>
   <para>
-  Thanks to Alan Cox for pointing out similarities 
-  between SATA and SCSI, and in general for motivation to hack on
-  libata.
-  </para>
-  <para>
-  libata's device detection
-  method, ata_pio_devchk, and in general all the early probing was
-  based on extensive study of Hale Landis's probe/reset code in his
-  ATADRVR driver (www.ata-atapi.com).
+  This Guide documents the libATA driver API, library functions, library
+  internals, and a couple sample ATA low-level drivers.
   </para>
   </chapter>
 
   <chapter id="libataDriverApi">
      <title>libata Driver API</title>
+     <para>
+     struct ata_port_operations is defined for every low-level libata
+     hardware driver, and it controls how the low-level driver
+     interfaces with the ATA and SCSI layers.
+     </para>
+     <para>
+     FIS-based drivers will hook into the system with ->qc_prep() and
+     ->qc_issue() high-level hooks.  Hardware which behaves in a manner
+     similar to PCI IDE hardware may utilize several generic helpers,
+     defining at a bare minimum the bus I/O addresses of the ATA shadow
+     register blocks.
+     </para>
      <sect1>
         <title>struct ata_port_operations</title>
 
+	<sect2><title>Disable ATA port</title>
 	<programlisting>
 void (*port_disable) (struct ata_port *);
 	</programlisting>
@@ -76,6 +86,9 @@ void (*port_disable) (struct ata_port *)
 	unplug).
 	</para>
 
+	</sect2>
+
+	<sect2><title>Post-IDENTIFY device configuration</title>
 	<programlisting>
 void (*dev_config) (struct ata_port *, struct ata_device *);
 	</programlisting>
@@ -86,6 +99,9 @@ void (*dev_config) (struct ata_port *, s
 	issue of SET FEATURES - XFER MODE, and prior to operation.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Set PIO/DMA mode</title>
 	<programlisting>
 void (*set_piomode) (struct ata_port *, struct ata_device *);
 void (*set_dmamode) (struct ata_port *, struct ata_device *);
@@ -106,6 +122,9 @@ void (*post_set_mode) (struct ata_port *
 	->set_dma_mode() is only called if DMA is possible.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Taskfile read/write</title>
 	<programlisting>
 void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
 void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -118,6 +137,9 @@ void (*tf_read) (struct ata_port *ap, st
 	taskfile register values.
 	</para>
 
+	</sect2>
+
+	<sect2><title>ATA command execute</title>
 	<programlisting>
 void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
 	</programlisting>
@@ -127,17 +149,37 @@ void (*exec_command)(struct ata_port *ap
 	->tf_load(), to be initiated in hardware.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Per-cmd ATAPI DMA capabilities filter</title>
+	<programlisting>
+int (*check_atapi_dma) (struct ata_queued_cmd *qc);
+	</programlisting>
+
+	<para>
+Allow low-level driver to filter ATA PACKET commands, returning a status
+indicating whether or not it is OK to use DMA for the supplied PACKET
+command.
+	</para>
+
+	</sect2>
+
+	<sect2><title>Read specific ATA shadow registers</title>
 	<programlisting>
 u8   (*check_status)(struct ata_port *ap);
-void (*dev_select)(struct ata_port *ap, unsigned int device);
+u8   (*check_altstatus)(struct ata_port *ap);
+u8   (*check_err)(struct ata_port *ap);
 	</programlisting>
 
 	<para>
-	Reads the Status ATA shadow register from hardware.  On some
-	hardware, this has the side effect of clearing the interrupt
-	condition.
+	Reads the Status/AltStatus/Error ATA shadow register from
+	hardware.  On some hardware, reading the Status register has
+	the side effect of clearing the interrupt condition.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Select ATA device on bus</title>
 	<programlisting>
 void (*dev_select)(struct ata_port *ap, unsigned int device);
 	</programlisting>
@@ -145,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, 
 	<para>
 	Issues the low-level hardware command(s) that causes one of N
 	hardware devices to be considered 'selected' (active and
-	available for use) on the ATA bus.
+	available for use) on the ATA bus.  This generally has no
+meaning on FIS-based devices.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Reset ATA bus</title>
 	<programlisting>
 void (*phy_reset) (struct ata_port *ap);
 	</programlisting>
@@ -160,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap);
 	functions ata_bus_reset() or sata_phy_reset() for this hook.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Control PCI IDE BMDMA engine</title>
 	<programlisting>
 void (*bmdma_setup) (struct ata_queued_cmd *qc);
 void (*bmdma_start) (struct ata_queued_cmd *qc);
+void (*bmdma_stop) (struct ata_port *ap);
+u8   (*bmdma_status) (struct ata_port *ap);
 	</programlisting>
 
 	<para>
-	When setting up an IDE BMDMA transaction, these hooks arm
-	(->bmdma_setup) and fire (->bmdma_start) the hardware's DMA
-	engine.
+When setting up an IDE BMDMA transaction, these hooks arm
+(->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop)
+the hardware's DMA engine.  ->bmdma_status is used to read the standard
+PCI IDE DMA Status register.
 	</para>
 
+	<para>
+These hooks are typically either no-ops, or simply not implemented, in
+FIS-based drivers.
+	</para>
+
+	</sect2>
+
+	<sect2><title>High-level taskfile hooks</title>
 	<programlisting>
 void (*qc_prep) (struct ata_queued_cmd *qc);
 int (*qc_issue) (struct ata_queued_cmd *qc);
@@ -188,20 +248,26 @@ int (*qc_issue) (struct ata_queued_cmd *
 	->qc_issue is used to make a command active, once the hardware
 	and S/G tables have been prepared.  IDE BMDMA drivers use the
 	helper function ata_qc_issue_prot() for taskfile protocol-based
-	dispatch.  More advanced drivers roll their own ->qc_issue
-	implementation, using this as the "issue new ATA command to
-	hardware" hook.
+	dispatch.  More advanced drivers implement their own ->qc_issue.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Timeout (error) handling</title>
 	<programlisting>
 void (*eng_timeout) (struct ata_port *ap);
 	</programlisting>
 
 	<para>
-	This is a high level error handling function, called from the
-	error handling thread, when a command times out.
+This is a high level error handling function, called from the
+error handling thread, when a command times out.  Most newer
+hardware will implement its own error handling code here.  IDE BMDMA
+drivers may use the helper function ata_eng_timeout().
 	</para>
 
+	</sect2>
+
+	<sect2><title>Hardware interrupt handling</title>
 	<programlisting>
 irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
 void (*irq_clear) (struct ata_port *);
@@ -214,6 +280,9 @@ void (*irq_clear) (struct ata_port *);
 	is quiet.
 	</para>
 
+	</sect2>
+
+	<sect2><title>SATA phy read/write</title>
 	<programlisting>
 u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
 void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
@@ -225,6 +294,9 @@ void (*scr_write) (struct ata_port *ap, 
 	if ->phy_reset hook called the sata_phy_reset() helper function.
 	</para>
 
+	</sect2>
+
+	<sect2><title>Init and shutdown</title>
 	<programlisting>
 int (*port_start) (struct ata_port *ap);
 void (*port_stop) (struct ata_port *ap);
@@ -238,15 +310,17 @@ void (*host_stop) (struct ata_host_set *
 	tasks.  
 	</para>
 	<para>
-	->host_stop() is called when the rmmod or hot unplug process
-	begins.  The hook must stop all hardware interrupts, DMA
-	engines, etc.
-	</para>
-	<para>
 	->port_stop() is called after ->host_stop().  It's sole function
 	is to release DMA/memory resources, now that they are no longer
 	actively being used.
 	</para>
+	<para>
+	->host_stop() is called after all ->port_stop() calls
+have completed.  The hook must finalize hardware shutdown, release DMA
+and other resources, etc.
+	</para>
+
+	</sect2>
 
      </sect1>
   </chapter>
@@ -277,4 +351,24 @@ void (*host_stop) (struct ata_host_set *
 !Idrivers/scsi/sata_sil.c
   </chapter>
 
+  <chapter id="libataThanks">
+     <title>Thanks</title>
+  <para>
+  The bulk of the ATA knowledge comes thanks to long conversations with
+  Andre Hedrick (www.linux-ide.org), and long hours pondering the ATA
+  and SCSI specifications.
+  </para>
+  <para>
+  Thanks to Alan Cox for pointing out similarities 
+  between SATA and SCSI, and in general for motivation to hack on
+  libata.
+  </para>
+  <para>
+  libata's device detection
+  method, ata_pio_devchk, and in general all the early probing was
+  based on extensive study of Hale Landis's probe/reset code in his
+  ATADRVR driver (www.ata-atapi.com).
+  </para>
+  </chapter>
+
 </book>
diff --git a/Documentation/DocBook/librs.tmpl b/Documentation/DocBook/librs.tmpl
--- a/Documentation/DocBook/librs.tmpl
+++ b/Documentation/DocBook/librs.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="Reed-Solomon-Library-Guide">
  <bookinfo>
@@ -223,7 +225,7 @@ int numerr, errpos[8];
 .....
 /* Decode 512 byte in data8.*/
 numerr = decode_rs8 (rs_decoder, NULL, NULL, 512, syn, 0, errpos, 0, corr);
-for (i = 0; i < numerr; i++) {
+for (i = 0; i &lt; numerr; i++) {
 	do_error_correction_in_your_buffer(errpos[i], corr[i]);
 }
 		</programlisting>
diff --git a/Documentation/DocBook/lsm.tmpl b/Documentation/DocBook/lsm.tmpl
--- a/Documentation/DocBook/lsm.tmpl
+++ b/Documentation/DocBook/lsm.tmpl
@@ -1,6 +1,9 @@
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
 <article class="whitepaper" id="LinuxSecurityModule" lang="en">
- <artheader>
+ <articleinfo>
  <title>Linux Security Modules:  General Security Hooks for Linux</title>
  <authorgroup>
  <author>
@@ -28,7 +31,7 @@
  </affiliation>
  </author>
  </authorgroup>
- </artheader>
+ </articleinfo>
 
 <sect1><title>Introduction</title>
 
@@ -84,7 +87,7 @@ security; it merely provides the infrast
 modules.  The LSM kernel patch also moves most of the capabilities
 logic into an optional security module, with the system defaulting
 to the traditional superuser logic.  This capabilities module
-is discussed further in <XRef LinkEnd="cap">.
+is discussed further in <xref linkend="cap"/>.
 </para>
 
 <para>
diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl
--- a/Documentation/DocBook/mcabook.tmpl
+++ b/Documentation/DocBook/mcabook.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="MCAGuide">
  <bookinfo>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="MTD-NAND-Guide">
  <bookinfo>
@@ -238,9 +240,9 @@ static void board_hwcontrol(struct mtd_i
 	struct nand_chip *this = (struct nand_chip *) mtd->priv;
 	switch(cmd){
 		case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT;  break;
-		case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break;
+		case NAND_CTL_CLRCLE: this->IO_ADDR_W &amp;= ~CLE_ADRR_BIT; break;
 		case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT;  break;
-		case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break;
+		case NAND_CTL_CLRALE: this->IO_ADDR_W &amp;= ~ALE_ADRR_BIT; break;
 	}
 }
 		</programlisting>
@@ -391,7 +393,7 @@ static void board_select_chip (struct mt
 	/* Deselect all chips, set all nCE pins high */
 	GPIO(BOARD_NAND_NCE) |= 0xff;	
 	if (chip >= 0)
-		GPIO(BOARD_NAND_NCE) &= ~ (1 << chip);	
+		GPIO(BOARD_NAND_NCE) &amp;= ~ (1 &lt;&lt; chip);
 }
 		</programlisting>
 		<para>
@@ -405,8 +407,8 @@ static void board_select_chip (struct mt
 	struct nand_chip *this = (struct nand_chip *) mtd->priv;
 	
 	/* Deselect all chips */
-	this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
-	this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
+	this->IO_ADDR_R &amp;= ~BOARD_NAND_ADDR_MASK;
+	this->IO_ADDR_W &amp;= ~BOARD_NAND_ADDR_MASK;
 	switch (chip) {
 	case 0:
 		this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl
--- a/Documentation/DocBook/procfs-guide.tmpl
+++ b/Documentation/DocBook/procfs-guide.tmpl
@@ -1,6 +1,7 @@
-<!-- -*- sgml -*- -->
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[
-<!ENTITY procfsexample SYSTEM "procfs_example.sgml">
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY procfsexample SYSTEM "procfs_example.xml">
 ]>
 
 <book id="LKProcfsGuide">
@@ -205,7 +206,7 @@
         function will return a pointer to the freshly created
         <structname>struct proc_dir_entry</structname>; otherwise it
         will return <constant>NULL</constant>. <xref
-        linkend="userland"> describes how to do something useful with
+        linkend="userland"/> describes how to do something useful with
         regular files.
       </para>
 
@@ -221,7 +222,7 @@
     <para>
       If you only want to be able to read the file, the function
       <function>create_proc_read_entry</function> described in <xref
-      linkend="convenience"> may be used to create and initialise
+      linkend="convenience"/> may be used to create and initialise
       the procfs entry in one single call.
     </para>
     </sect1>
@@ -298,7 +299,7 @@
         the <structname>struct proc_dir_entry</structname> before
         <function>remove_proc_entry</function> is called (that is: if
         there was some <structfield>data</structfield> allocated, of
-        course). See <xref linkend="usingdata"> for more information
+        course). See <xref linkend="usingdata"/> for more information
         on using the <structfield>data</structfield> entry.
       </para>
     </sect1>
@@ -333,7 +334,7 @@ entry->write_proc = write_proc_foo;
       If you only want to use a the
       <structfield>read_proc</structfield>, the function
       <function>create_proc_read_entry</function> described in <xref
-      linkend="convenience"> may be used to create and initialise the
+      linkend="convenience"/> may be used to create and initialise the
       procfs entry in one single call.
     </para>
 
@@ -386,7 +387,7 @@ entry->write_proc = write_proc_foo;
         The parameter <parameter>start</parameter> doesn't seem to be
         used anywhere in the kernel. The <parameter>data</parameter>
         parameter can be used to create a single call back function for
-        several files, see <xref linkend="usingdata">.
+        several files, see <xref linkend="usingdata"/>.
       </para>
 
       <para>
@@ -395,7 +396,7 @@ entry->write_proc = write_proc_foo;
       </para>
 
       <para>
-        <xref linkend="example"> shows how to use a read call back
+        <xref linkend="example"/> shows how to use a read call back
         function.
       </para>
     </sect1>
@@ -429,12 +430,12 @@ entry->write_proc = write_proc_foo;
         kernel's memory space, so it should first be copied to kernel
         space with <function>copy_from_user</function>. The
         <parameter>file</parameter> parameter is usually
-        ignored. <xref linkend="usingdata"> shows how to use the
+        ignored. <xref linkend="usingdata"/> shows how to use the
         <parameter>data</parameter> parameter.
       </para>
 
       <para>
-        Again, <xref linkend="example"> shows how to use this call back
+        Again, <xref linkend="example"/> shows how to use this call back
         function.
       </para>
     </sect1>
@@ -525,10 +526,10 @@ int foo_read_func(char *page, char **sta
       <para>
         This function creates a regular file in exactly the same way
         as <function>create_proc_entry</function> from <xref
-        linkend="regularfile"> does, but also allows to set the read
+        linkend="regularfile"/> does, but also allows to set the read
         function <parameter>read_proc</parameter> in one call. This
         function can set the <parameter>data</parameter> as well, like
-        explained in <xref linkend="usingdata">.
+        explained in <xref linkend="usingdata"/>.
       </para>
     </sect1>
 
diff --git a/Documentation/DocBook/scsidrivers.tmpl b/Documentation/DocBook/scsidrivers.tmpl
--- a/Documentation/DocBook/scsidrivers.tmpl
+++ b/Documentation/DocBook/scsidrivers.tmpl
@@ -1,5 +1,6 @@
-<!-- -*- sgml -*- -->
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="scsidrivers">
  <bookinfo>
diff --git a/Documentation/DocBook/sis900.tmpl b/Documentation/DocBook/sis900.tmpl
--- a/Documentation/DocBook/sis900.tmpl
+++ b/Documentation/DocBook/sis900.tmpl
@@ -1,25 +1,27 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="SiS900Guide">
 
 <bookinfo>
 
-<title>SiS 900/7016 Fast Ethernet Device Driver</Title>
+<title>SiS 900/7016 Fast Ethernet Device Driver</title>
 
 <authorgroup>
 <author>
-<FirstName>Ollie</FirstName>
+<firstname>Ollie</firstname>
 <surname>Lho</surname>
 </author>
 
 <author>
-<FirstName>Lei Chun</FirstName>
+<firstname>Lei Chun</firstname>
 <surname>Chang</surname>
 </author>
 </authorgroup>
 
-<edition>Document Revision: 0.3 for SiS900 driver v1.06 & v1.07</edition>
-<PubDate>November 16, 2000</PubDate>
+<edition>Document Revision: 0.3 for SiS900 driver v1.06 &amp; v1.07</edition>
+<pubdate>November 16, 2000</pubdate>
 
 <copyright>
  <year>1999</year>
@@ -48,21 +50,21 @@
  </para>
 </legalnotice>
 
-<Abstract>
-<Para>
+<abstract>
+<para>
 This document gives some information on installation and usage of SiS 900/7016
 device driver under Linux.
-</Para>
-</Abstract>
+</para>
+</abstract>
 
 </bookinfo>
 
 <toc></toc>
 
 <chapter id="intro">
- <Title>Introduction</Title>
+ <title>Introduction</title>
 
-<Para>
+<para>
 This document describes the revision 1.06 and 1.07 of SiS 900/7016 Fast Ethernet 
 device driver under Linux. The driver is developed by Silicon Integrated
 System Corp. and distributed freely under the GNU General Public License (GPL).
@@ -70,265 +72,265 @@ The driver can be compiled as a loadable
 version 2.2.x. (rev. 1.06)
 With minimal changes, the driver can also be used under 2.3.x and 2.4.x kernel 
 (rev. 1.07), please see 
-<XRef LinkEnd="install">. If you are intended to 
+<xref linkend="install"/>. If you are intended to
 use the driver for earlier kernels, you are on your own.
-</Para>
+</para>
 
-<Para>
+<para>
 The driver is tested with usual TCP/IP applications including
 FTP, Telnet, Netscape etc. and is used constantly by the developers.
-</Para>
+</para>
 
-<Para>
+<para>
 Please send all comments/fixes/questions to
-<ULink URL="mailto:lcchang@sis.com.tw">Lei-Chun Chang</ULink>.
-</Para>
+<ulink url="mailto:lcchang@sis.com.tw">Lei-Chun Chang</ulink>.
+</para>
 </chapter>
 
 <chapter id="changes">
- <Title>Changes</Title>
+ <title>Changes</title>
 
-<Para>
+<para>
 Changes made in Revision 1.07
 
-<OrderedList>
-<ListItem>
-<Para>
+<orderedlist>
+<listitem>
+<para>
 Separation of sis900.c and sis900.h in order to move most 
 constant definition to sis900.h (many of those constants were
 corrected)
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Clean up PCI detection, the pci-scan from Donald Becker were not used,
 just simple pci&lowbar;find&lowbar;*.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 MII detection is modified to support multiple mii transceiver.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Bugs in read&lowbar;eeprom, mdio&lowbar;* were removed.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Lot of sis900 irrelevant comments were removed/changed and
 more comments were added to reflect the real situation.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Clean up of physical/virtual address space mess in buffer 
 descriptors.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Better transmit/receive error handling.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 The driver now uses zero-copy single buffer management
 scheme to improve performance.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Names of variables were changed to be more consistent.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Clean up of auo-negotiation and timer code.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Automatic detection and change of PHY on the fly.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Bug in mac probing fixed.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Fix 630E equalier problem by modifying the equalizer workaround rule.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Support for ICS1893 10/100 Interated PHYceiver.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Support for media select by ifconfig.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 Added kernel-doc extratable documentation.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-</OrderedList>
-</Para>
+</orderedlist>
+</para>
 </chapter>
 
 <chapter id="tested">
- <Title>Tested Environment</Title>
+ <title>Tested Environment</title>
 
-<Para>
+<para>
 This driver is developed on the following hardware
 
-<ItemizedList>
-<ListItem>
+<itemizedlist>
+<listitem>
 
-<Para>
+<para>
 Intel Celeron 500 with SiS 630 (rev 02) chipset
-</Para>
-</ListItem>
-<ListItem>
+</para>
+</listitem>
+<listitem>
 
-<Para>
+<para>
 SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-</ItemizedList>
+</itemizedlist>
 
 and tested with these software environments
 
-<ItemizedList>
-<ListItem>
+<itemizedlist>
+<listitem>
 
-<Para>
+<para>
 Red Hat Linux version 6.2
-</Para>
-</ListItem>
-<ListItem>
+</para>
+</listitem>
+<listitem>
 
-<Para>
+<para>
 Linux kernel version 2.4.0
-</Para>
-</ListItem>
-<ListItem>
+</para>
+</listitem>
+<listitem>
 
-<Para>
+<para>
 Netscape version 4.6
-</Para>
-</ListItem>
-<ListItem>
+</para>
+</listitem>
+<listitem>
 
-<Para>
+<para>
 NcFTP 3.0.0 beta 18
-</Para>
-</ListItem>
-<ListItem>
+</para>
+</listitem>
+<listitem>
 
-<Para>
+<para>
 Samba version 2.0.3
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-</ItemizedList>
+</itemizedlist>
 
-</Para>
+</para>
 
 </chapter>
 
 <chapter id="files">
-<Title>Files in This Package</Title>
+<title>Files in This Package</title>
 
-<Para>
+<para>
 In the package you can find these files:
-</Para>
+</para>
 
-<Para>
-<VariableList>
+<para>
+<variablelist>
 
-<VarListEntry>
-<Term>sis900.c</Term>
-<ListItem>
-<Para>
+<varlistentry>
+<term>sis900.c</term>
+<listitem>
+<para>
 Driver source file in C 
-</Para>
-</ListItem>
-</VarListEntry>
-
-<VarListEntry>
-<Term>sis900.h</Term>
-<ListItem>
-<Para>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>sis900.h</term>
+<listitem>
+<para>
 Header file for sis900.c
-</Para>
-</ListItem>
-</VarListEntry>
-
-<VarListEntry>
-<Term>sis900.sgml</Term>
-<ListItem>
-<Para>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>sis900.sgml</term>
+<listitem>
+<para>
 DocBook SGML source of the document
-</Para>
-</ListItem>
-</VarListEntry>
-
-<VarListEntry>
-<Term>sis900.txt</Term>
-<ListItem>
-<Para>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>sis900.txt</term>
+<listitem>
+<para>
 Driver document in plain text
-</Para>
-</ListItem>
-</VarListEntry>
+</para>
+</listitem>
+</varlistentry>
 
-</VariableList>
-</Para>
+</variablelist>
+</para>
 </chapter>
 
 <chapter id="install">
- <Title>Installation</Title>
+ <title>Installation</title>
 
-<Para>
+<para>
 Silicon Integrated System Corp. is cooperating closely with core Linux Kernel
 developers. The revisions of SiS 900 driver are distributed by the usuall channels
 for kernel tar files and patches. Those kernel tar files for official kernel and
 patches for kernel pre-release can be download at 
-<ULink URL="http://ftp.kernel.org/pub/linux/kernel/">official kernel ftp site</ULink> 
+<ulink url="http://ftp.kernel.org/pub/linux/kernel/">official kernel ftp site</ulink>
 and its mirrors.
 The 1.06 revision can be found in kernel version later than 2.3.15 and pre-2.2.14, 
 and 1.07 revision can be found in kernel version 2.4.0.
 If you have no prior experience in networking under Linux, please read
-<ULink URL="http://www.tldp.org/">Ethernet HOWTO</ULink> and
-<ULink URL="http://www.tldp.org/">Networking HOWTO</ULink> available from
+<ulink url="http://www.tldp.org/">Ethernet HOWTO</ulink> and
+<ulink url="http://www.tldp.org/">Networking HOWTO</ulink> available from
 Linux Documentation Project (LDP).
-</Para>
+</para>
 
-<Para>
+<para>
 The driver is bundled in release later than 2.2.11 and 2.3.15 so this 
 is the most easy case. 
 Be sure you have the appropriate packages for compiling kernel source.
@@ -338,63 +340,63 @@ in kernel release, you should have your 
 <filename>sis900.c</filename> and <filename>sis900.h</filename> 
 copied into <filename class="directory">/usr/src/linux/drivers/net/</filename> first.
 There are two alternative ways to install the driver
-</Para>
+</para>
 
-<Sect1>
-<Title>Building the driver as loadable module</Title>
+<sect1>
+<title>Building the driver as loadable module</title>
 
-<Para>
+<para>
 To build the driver as a loadable kernel module you have to reconfigure
 the kernel to activate network support by
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 make menuconfig
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 Choose <quote>Loadable module support  ---></quote>, 
 then select <quote>Enable loadable module support</quote>.
-</Para>
+</para>
 
-<Para>
+<para>
 Choose <quote>Network Device Support  ---></quote>, select 
 <quote>Ethernet (10 or 100Mbit)</quote>.
 Then select <quote>EISA, VLB, PCI and on board controllers</quote>, 
 and choose <quote>SiS 900/7016 PCI Fast Ethernet Adapter support</quote> 
 to <quote>M</quote>.
-</Para>
+</para>
 
-<Para>
+<para>
 After reconfiguring the kernel, you can make the driver module by
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 make modules
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 The driver should be compiled with no errors. After compiling the driver,
 the driver can be installed to proper place by
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 make modules_install
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 Load the driver into kernel by
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 insmod sis900
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 When loading the driver into memory, some information message can be view by
-</Para>
+</para>
 
-<Para>
+<para>
 <screen>
 dmesg
 </screen>
@@ -404,103 +406,103 @@ or
 <screen>
 cat /var/log/message
 </screen>
-</Para>
+</para>
 
-<Para>
+<para>
 If the driver is loaded properly you will have messages similar to this:
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 sis900.c: v1.07.06  11/07/2000
 eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
 eth0: SiS 900 Internal MII PHY transceiver found at address 1.
 eth0: Using SiS 900 Internal MII PHY as default
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 showing the version of the driver and the results of probing routine.
-</Para>
+</para>
 
-<Para>
+<para>
 Once the driver is loaded, network can be brought up by
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 /sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK media TYPE
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 where IPADDR, BROADCAST, NETMASK are your IP address, broadcast address and
 netmask respectively. TYPE is used to set medium type used by the device. 
 Typical values are "10baseT"(twisted-pair 10Mbps Ethernet) or "100baseT"
 (twisted-pair 100Mbps Ethernet). For more information on how to configure 
 network interface, please refer to  
-<ULink URL="http://www.tldp.org/">Networking HOWTO</ULink>.
-</Para>
+<ulink url="http://www.tldp.org/">Networking HOWTO</ulink>.
+</para>
 
-<Para>
+<para>
 The link status is also shown by kernel messages. For example, after the
 network interface is activated, you may have the message:
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 eth0: Media Link On 100mbps full-duplex
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 If you try to unplug the twist pair (TP) cable you will get
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 eth0: Media Link Off
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 indicating that the link is failed.
-</Para>
-</Sect1>
+</para>
+</sect1>
 
-<Sect1>
-<Title>Building the driver into kernel</Title>
+<sect1>
+<title>Building the driver into kernel</title>
 
-<Para>
+<para>
 If you want to make the driver into kernel, choose <quote>Y</quote> 
 rather than <quote>M</quote> on 
 <quote>SiS 900/7016 PCI Fast Ethernet Adapter support</quote> 
 when configuring the kernel. Build the kernel image in the usual way
-</Para>
+</para>
 
-<Para><screen>
+<para><screen>
 make clean
 
 make bzlilo
-</screen></Para>
+</screen></para>
 
-<Para>
+<para>
 Next time the system reboot, you have the driver in memory.
-</Para>
+</para>
 
-</Sect1>
+</sect1>
 </chapter>
 
 <chapter id="problems">
- <Title>Known Problems and Bugs</Title>
+ <title>Known Problems and Bugs</title>
 
-<Para>
+<para>
 There are some known problems and bugs. If you find any other bugs please 
-mail to <ULink URL="mailto:lcchang@sis.com.tw">lcchang@sis.com.tw</ULink>
+mail to <ulink url="mailto:lcchang@sis.com.tw">lcchang@sis.com.tw</ulink>
 
-<OrderedList>
+<orderedlist>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 AM79C901 HomePNA PHY is not thoroughly tested, there may be some 
 bugs in the <quote>on the fly</quote> change of transceiver. 
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 A bug is hidden somewhere in the receive buffer management code, 
 the bug causes NULL pointer reference in the kernel. This fault is 
 caught before bad things happen and reported with the message:
@@ -509,70 +511,70 @@ caught before bad things happen and repo
 eth0: NULL pointer encountered in Rx ring, skipping 
 </computeroutput>
 
-which can be viewed with <Literal remap="tt">dmesg</Literal> or 
-<Literal remap="tt">cat /var/log/message</Literal>.
-</Para>
-</ListItem>
+which can be viewed with <literal remap="tt">dmesg</literal> or
+<literal remap="tt">cat /var/log/message</literal>.
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 The media type change from 10Mbps to 100Mbps twisted-pair ethernet 
 by ifconfig causes the media link down.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-</OrderedList>
-</Para>
+</orderedlist>
+</para>
 </chapter>
 
 <chapter id="RHistory">
- <Title>Revision History</Title>
+ <title>Revision History</title>
 
-<Para>
-<ItemizedList>
+<para>
+<itemizedlist>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 November 13, 2000, Revision 1.07, seventh release, 630E problem fixed 
 and further clean up.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 November 4, 1999, Revision 1.06, Second release, lots of clean up
 and optimization.
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-<ListItem>
-<Para>
+<listitem>
+<para>
 August 8, 1999, Revision 1.05, Initial Public Release
-</Para>
-</ListItem>
+</para>
+</listitem>
 
-</ItemizedList>
-</Para>
+</itemizedlist>
+</para>
 </chapter>
 
 <chapter id="acknowledgements">
- <Title>Acknowledgements</Title>
+ <title>Acknowledgements</title>
 
-<Para>
+<para>
 This driver was originally derived form 
-<ULink URL="mailto:becker@cesdis1.gsfc.nasa.gov">Donald Becker</ULink>'s
-<ULink URL="ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/kern-2.3/pci-skeleton.c"
->pci-skeleton</ULink> and
-<ULink URL="ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/kern-2.3/rtl8139.c"
->rtl8139</ULink> drivers. Donald also provided various suggestion
+<ulink url="mailto:becker@cesdis1.gsfc.nasa.gov">Donald Becker</ulink>'s
+<ulink url="ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/kern-2.3/pci-skeleton.c"
+>pci-skeleton</ulink> and
+<ulink url="ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/kern-2.3/rtl8139.c"
+>rtl8139</ulink> drivers. Donald also provided various suggestion
 regarded with improvements made in revision 1.06.
-</Para>
+</para>
 
-<Para>
+<para>
 The 1.05 revision was created by 
-<ULink URL="mailto:cmhuang@sis.com.tw">Jim Huang</ULink>, AMD 79c901 
-support was added by <ULink URL="mailto:lcs@sis.com.tw">Chin-Shan Li</ULink>.
-</Para>
+<ulink url="mailto:cmhuang@sis.com.tw">Jim Huang</ulink>, AMD 79c901
+support was added by <ulink url="mailto:lcs@sis.com.tw">Chin-Shan Li</ulink>.
+</para>
 </chapter>
 
 <chapter id="functions">
diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl
new file mode 100644
--- /dev/null
+++ b/Documentation/DocBook/stylesheet.xsl
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<param name="chunk.quietly">1</param>
+<param name="funcsynopsis.style">ansi</param>
+</stylesheet>
diff --git a/Documentation/DocBook/tulip-user.tmpl b/Documentation/DocBook/tulip-user.tmpl
deleted file mode 100644
--- a/Documentation/DocBook/tulip-user.tmpl
+++ /dev/null
@@ -1,325 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-
-<book id="TulipUserGuide">
- <bookinfo>
-  <title>Tulip Driver User's Guide</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Jeff</firstname>
-    <surname>Garzik</surname>
-    <affiliation>
-     <address>
-      <email>jgarzik@pobox.com</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>2001</year>
-   <holder>Jeff Garzik</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="intro">
-    <title>Introduction</title>
-<para>
-The Tulip Ethernet Card Driver
-is maintained by Jeff Garzik (<email>jgarzik@pobox.com</email>).
-</para>
-
-<para>
-The Tulip driver was developed by Donald Becker and changed by
-Jeff Garzik, Takashi Manabe and a cast of thousands.
-</para>
-
-<para>
-For 2.4.x and later kernels, the Linux Tulip driver is available at
-<ULink URL="http://sourceforge.net/projects/tulip/">http://sourceforge.net/projects/tulip/</ULink>
-</para>
-
-<para>
-	This driver is for the Digital "Tulip" Ethernet adapter interface.
-	It should work with most DEC 21*4*-based chips/ethercards, as well as
-	with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
-</para>
-
-<para>
-        The original author may be reached as becker@scyld.com, or C/O
-        Scyld Computing Corporation,
-        410 Severn Ave., Suite 210,
-        Annapolis MD 21403
-</para>
-
-<para>
-	Additional information on Donald Becker's tulip.c
-	is available at <ULink URL="http://www.scyld.com/network/tulip.html">http://www.scyld.com/network/tulip.html</ULink>
-</para>
-
-  </chapter>
-
-  <chapter id="drvr-compat">
-    <title>Driver Compatibility</title>
-
-<para>
-This device driver is designed for the DECchip "Tulip", Digital's
-single-chip ethernet controllers for PCI (now owned by Intel).
-Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143.  Similar work-alike
-chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
-supported.
-</para>
-
-<para>
-These chips are used on at least 140 unique PCI board designs.  The great
-number of chips and board designs supported is the reason for the
-driver size and complexity.  Almost of the increasing complexity is in the
-board configuration and media selection code.  There is very little
-increasing in the operational critical path length.
-</para>
-  </chapter>
-
-  <chapter id="board-settings">
-    <title>Board-specific Settings</title>
-
-<para>
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS preferably should assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-</para>
-
-<para>
-Some boards have EEPROMs tables with default media entry.  The factory default
-is usually "autoselect".  This should only be overridden when using
-transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
-for forcing full-duplex when used with old link partners that do not do
-autonegotiation.
-</para>
-  </chapter>
-
-  <chapter id="driver-operation">
-    <title>Driver Operation</title>
-
-<sect1><title>Ring buffers</title>
-
-<para>
-The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
-This driver uses statically allocated rings of Rx and Tx descriptors, set at
-compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
-for the Rx ring buffers at open() time and passes the skb->data field to the
-Tulip as receive data buffers.  When an incoming frame is less than
-RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
-copied to the new skbuff.  When the incoming frame is larger, the skbuff is
-passed directly up the protocol stack and replaced by a newly allocated
-skbuff.
-</para>
-
-<para>
-The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-using a full-sized skbuff for small frames vs. the copying costs of larger
-frames.  For small frames the copying cost is negligible (esp. considering
-that we are pre-loading the cache with immediately useful header
-information).  For large frames the copying cost is non-trivial, and the
-larger copy might flush the cache of useful data.  A subtle aspect of this
-choice is that the Tulip only receives into longword aligned buffers, thus
-the IP header at offset 14 isn't longword aligned for further processing.
-Copied frames are put into the new skbuff at an offset of "+2", thus copying
-has the beneficial effect of aligning the IP header and preloading the
-cache.
-</para>
-
-</sect1>
-
-<sect1><title>Synchronization</title>
-<para>
-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 other software.
-</para>
-
-<para>
-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 'tp->tx_full' flag.
-</para>
-
-<para>
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.)	 After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-</para>
-
-</sect1>
-
-  </chapter>
-
-  <chapter id="errata">
-    <title>Errata</title>
-
-<para>
-The old DEC databooks were light on details.
-The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written.  Hmmm, now how is that possible?
-</para>
-
-<para>
-The DEC SROM format is very badly designed not precisely defined, leading to
-part of the media selection junkheap below.  Some boards do not have EEPROM
-media tables and need to be patched up.  Worse, other boards use the DEC
-design kit media table when it isn't correct for their board.
-</para>
-
-<para>
-We cannot use MII interrupts because there is no defined GPIO pin to attach
-them.  The MII transceiver status is polled using an kernel timer.
-</para>
-  </chapter>
-
-  <chapter id="changelog">
-    <title>Driver Change History</title>
-
-    <sect1><title>Version 0.9.14 (February 20, 2001)</title>
-    <itemizedlist>
-    <listitem><para>Fix PNIC problems (Manfred Spraul)</para></listitem>
-    <listitem><para>Add new PCI id for Accton comet</para></listitem>
-    <listitem><para>Support Davicom tulips</para></listitem>
-    <listitem><para>Fix oops in eeprom parsing</para></listitem>
-    <listitem><para>Enable workarounds for early PCI chipsets</para></listitem>
-    <listitem><para>IA64, hppa csr0 support</para></listitem>
-    <listitem><para>Support media types 5, 6</para></listitem>
-    <listitem><para>Interpret a bit more of the 21142 SROM extended media type 3</para></listitem>
-    <listitem><para>Add missing delay in eeprom reading</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.11 (November 3, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Eliminate extra bus accesses when sharing interrupts (prumpf)</para></listitem>
-    <listitem><para>Barrier following ownership descriptor bit flip (prumpf)</para></listitem>
-    <listitem><para>Endianness fixes for >14 addresses in setup frames (prumpf)</para></listitem>
-    <listitem><para>Report link beat to kernel/userspace via netif_carrier_*. (kuznet)</para></listitem>
-    <listitem><para>Better spinlocking in set_rx_mode.</para></listitem>
-    <listitem><para>Fix I/O resource request failure error messages (DaveM catch)</para></listitem>
-    <listitem><para>Handle DMA allocation failure.</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.10 (September 6, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Simple interrupt mitigation (via jamal)</para></listitem>
-    <listitem><para>More PCI ids</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.9 (August 11, 2000)</title>
-    <itemizedlist>
-    <listitem><para>More PCI ids</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.8 (July 13, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Correct signed/unsigned comparison for dummy frame index</para></listitem>
-    <listitem><para>Remove outdated references to struct enet_statistics</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.7 (June 17, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Timer cleanups (Andrew Morton)</para></listitem>
-    <listitem><para>Alpha compile fix (somebody?)</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.6 (May 31, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Revert 21143-related support flag patch</para></listitem>
-    <listitem><para>Add HPPA/media-table debugging printk</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.5 (May 30, 2000)</title>
-    <itemizedlist>
-    <listitem><para>HPPA support (willy@puffingroup)</para></listitem>
-    <listitem><para>CSR6 bits and tulip.h cleanup (Chris Smith)</para></listitem>
-    <listitem><para>Improve debugging messages a bit</para></listitem>
-    <listitem><para>Add delay after CSR13 write in t21142_start_nway</para></listitem>
-    <listitem><para>Remove unused ETHER_STATS code</para></listitem>
-    <listitem><para>Convert 'extern inline' to 'static inline' in tulip.h (Chris Smith)</para></listitem>
-    <listitem><para>Update DS21143 support flags in tulip_chip_info[]</para></listitem>
-    <listitem><para>Use spin_lock_irq, not _irqsave/restore, in tulip_start_xmit()</para></listitem>
-    <listitem><para>Add locking to set_rx_mode()</para></listitem>
-    <listitem><para>Fix race with chip setting DescOwned bit (Hal Murray)</para></listitem>
-    <listitem><para>Request 100% of PIO and MMIO resource space assigned to card</para></listitem>
-    <listitem><para>Remove error message from pci_enable_device failure</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.4.3 (April 14, 2000)</title>
-    <itemizedlist>
-    <listitem><para>mod_timer fix (Hal Murray)</para></listitem>
-    <listitem><para>PNIC2 resuscitation (Chris Smith)</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.4.2 (March 21, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Fix 21041 CSR7, CSR13/14/15 handling</para></listitem>
-    <listitem><para>Merge some PCI ids from tulip 0.91x</para></listitem>
-    <listitem><para>Merge some HAS_xxx flags and flag settings from tulip 0.91x</para></listitem>
-    <listitem><para>asm/io.h fix (submitted by many) and cleanup</para></listitem>
-    <listitem><para>s/HAS_NWAY143/HAS_NWAY/</para></listitem>
-    <listitem><para>Cleanup 21041 mode reporting</para></listitem>
-    <listitem><para>Small code cleanups</para></listitem>
-    </itemizedlist>
-    </sect1>
-
-    <sect1><title>Version 0.9.4.1 (March 18, 2000)</title>
-    <itemizedlist>
-    <listitem><para>Finish PCI DMA conversion (davem)</para></listitem>
-    <listitem><para>Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet)</para></listitem>
-    <listitem><para>PCI DMA fix (kuznet)</para></listitem>
-    <listitem><para>eeprom.c code cleanup</para></listitem>
-    <listitem><para>Remove Xircom Tulip crud</para></listitem>
-    </itemizedlist>
-    </sect1>
-  </chapter>
-
-</book>
diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl
--- a/Documentation/DocBook/usb.tmpl
+++ b/Documentation/DocBook/usb.tmpl
@@ -1,4 +1,7 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
 <book id="Linux-USB-API">
  <bookinfo>
   <title>The Linux-USB Host Side API</title>
diff --git a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl
deleted file mode 100644
--- a/Documentation/DocBook/via-audio.tmpl
+++ /dev/null
@@ -1,595 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-
-<book id="ViaAudioGuide">
- <bookinfo>
-  <title>Via 686 Audio Driver for Linux</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Jeff</firstname>
-    <surname>Garzik</surname>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>1999-2001</year>
-   <holder>Jeff Garzik</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="intro">
-      <title>Introduction</title>
-  <para>
-  	The Via VT82C686A "super southbridge" chips contain
-	AC97-compatible audio logic which features dual 16-bit stereo
-	PCM sound channels (full duplex), plus a third PCM channel intended for use
-	in hardware-assisted FM synthesis.
-  </para>
-  <para>
-  	The current Linux kernel audio driver for this family of chips
-	supports audio playback and recording, but hardware-assisted
-	FM features, and hardware buffer direct-access (mmap)
-	support are not yet available.
-  </para>
-  <para>
-  	This driver supports any Linux kernel version after 2.4.10.
-  </para>
-  <para>
-	Please send bug reports to the mailing list <email>linux-via@gtf.org</email>.
-	To subscribe, e-mail <email>majordomo@gtf.org</email> with
-  </para>
-  <programlisting>
-	subscribe linux-via
-  </programlisting>
-  <para>
-	in the body of the message.
-  </para>
-  </chapter>
-  
-  <chapter id="install">
-      <title>Driver Installation</title>
-  <para>
-  	To use this audio driver, select the
-	CONFIG_SOUND_VIA82CXXX option in the section Sound during kernel configuration.
-	Follow the usual kernel procedures for rebuilding the kernel,
-	or building and installing driver modules.
-  </para>
-  <para>
-  	To make this driver the default audio driver, you can add the
-	following to your /etc/conf.modules file:
-  </para>
-  <programlisting>
-	alias sound via82cxxx_audio
-  </programlisting>
-  <para>
-  	Note that soundcore and ac97_codec support modules
-	are also required for working audio, in addition to
-	the via82cxxx_audio module itself.
-  </para>
-  </chapter>
-  
-  <chapter id="reportbug">
-      <title>Submitting a bug report</title>
-  <sect1 id="bugrepdesc"><title>Description of problem</title>
-  <para>
-	Describe the application you were using to play/record sound, and how
-	to reproduce the problem.
-  </para>
-  </sect1>
-  <sect1 id="bugrepdiag"><title>Diagnostic output</title>
-  <para>
-	Obtain the via-audio-diag diagnostics program from
-	http://sf.net/projects/gkernel/ and provide a dump of the
-	audio chip's registers while the problem is occurring.  Sample command line:
-  </para>
-  <programlisting>
-	./via-audio-diag -aps > diag-output.txt
-  </programlisting>
-  </sect1>
-  <sect1 id="bugrepdebug"><title>Driver debug output</title>
-  <para>
-	Define <constant>VIA_DEBUG</constant> at the beginning of the driver, then capture and email
-	the kernel log output.  This can be viewed in the system kernel log (if
-	enabled), or via the dmesg program.  Sample command line:
-  </para>
-  <programlisting>
-	dmesg > /tmp/dmesg-output.txt
-  </programlisting>
-  </sect1>
-  <sect1 id="bugrepprintk"><title>Bigger kernel message buffer</title>
-  <para>
-	If you wish to increase the size of the buffer displayed by dmesg, then
-	change the <constant>LOG_BUF_LEN</constant> macro at the top of linux/kernel/printk.c, recompile
-	your kernel, and pass the <constant>LOG_BUF_LEN</constant> value to dmesg.  Sample command line with
-	<constant>LOG_BUF_LEN</constant> == 32768:
-  </para>
-  <programlisting>
-	dmesg -s 32768 > /tmp/dmesg-output.txt
-  </programlisting>
-  </sect1>
-  </chapter>
-  
-  <chapter id="bugs">
-     <title>Known Bugs And Assumptions</title>
-  <para>
-  <variablelist>
-    <varlistentry><term>Low volume</term>
-    <listitem>
-    <para>
-	Volume too low on many systems.  Workaround:  use mixer program
-	such as xmixer to increase volume.
-    </para>
-    </listitem></varlistentry>
-
-  </variablelist>
-	
-  </para>
-  </chapter>
-
-  <chapter id="thanks">
-      <title>Thanks</title>
-  <para>
-	Via for providing e-mail support, specs, and NDA'd source code.
-  </para>
-  <para>
-	MandrakeSoft for providing hacking time.
-  </para>
-  <para>
-	AC97 mixer interface fixes and debugging by Ron Cemer <email>roncemer@gte.net</email>.
-  </para>
-  <para>
-	Rui Sousa <email>rui.sousa@conexant.com</email>, for bugfixing
-	MMAP support, and several other notable fixes that resulted from
-	his hard work and testing.
-  </para>
-  <para>
-	Adrian Cox <email>adrian@humboldt.co.uk</email>, for bugfixing
-	MMAP support, and several other notable fixes that resulted from
-	his hard work and testing.
-  </para>
-  <para>
-  	Thomas Sailer for further bugfixes.
-  </para>
-  </chapter>
-  
-  <chapter id="notes">
-     <title>Random Notes</title>
-  <para>
-	Two /proc pseudo-files provide diagnostic information.  This is generally
-	not useful to most users.  Power users can disable CONFIG_SOUND_VIA82CXXX_PROCFS,
-	and remove the /proc support code.  Once
-	version 2.0.0 is released, the /proc support code will be disabled by
-	default.  Available /proc pseudo-files:
-  </para>
-  <programlisting>
-	/proc/driver/via/0/info
-	/proc/driver/via/0/ac97
-  </programlisting>
-  <para>
-	This driver by default supports all PCI audio devices which report
-	a vendor id of 0x1106, and a device id of 0x3058.  Subsystem vendor
-	and device ids are not examined.
-  </para>
-  <para>
-	GNU indent formatting options:
-  <programlisting>
--kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl
-  </programlisting>
-  </para>
-  <para>
-	Via has graciously donated e-mail support and source code to help further
-	the development of this driver.  Their assistance has been invaluable
-	in the design and coding of the next major version of this driver.
-  </para>
-  <para>
-	The Via audio chip apparently provides a second PCM scatter-gather
-	DMA channel just for FM data, but does not have a full hardware MIDI
-	processor.  I haven't put much thought towards a solution here, but it
-	might involve using SoftOSS midi wave table, or simply disabling MIDI
-	support altogether and using the FM PCM channel as a second (input? output?)
-  </para>
-  </chapter>
-
-  <chapter id="changelog">
-      <title>Driver ChangeLog</title>
-
-<sect1 id="version191"><title>
-Version 1.9.1
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    DSP read/write bugfixes from Thomas Sailer.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Add new PCI id for single-channel use of Via 8233.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Other bug fixes, tweaks, new ioctls.
-    </para>
-   </listitem>
-
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version1115"><title>
-Version 1.1.15
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    Support for variable fragment size and variable fragment number (Rui
-    Sousa)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read &
-    write mode (Rui Sousa)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Mmaped sound is now fully functional. (Rui Sousa)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Make sure to enable PCI device before reading any of its PCI
-    config information. (fixes potential hotplug problems)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Clean up code a bit and add more internal function documentation.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    AC97 codec access fixes (Adrian Cox)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Big endian fixes (Adrian Cox)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    MIDI support (Adrian Cox)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Detect and report locked-rate AC97 codecs.  If your hardware only
-    supports 48Khz (locked rate), then your recording/playback software
-    must upsample or downsample accordingly.  The hardware cannot do it.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Use new pci_request_regions and pci_disable_device functions in
-    kernel 2.4.6.
-    </para>
-   </listitem>
-
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version1114"><title>
-Version 1.1.14
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    Use VM_RESERVE when available, to eliminate unnecessary page faults.
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version1112"><title>
-Version 1.1.12
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    mmap bug fixes from Linus.
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version1111"><title>
-Version 1.1.11
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    Many more bug fixes.  mmap enabled by default, but may still be buggy.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Uses new and spiffy method of mmap'ing the DMA buffer, based
-    on a suggestion from Linus.
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version1110"><title>
-Version 1.1.10
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    Many bug fixes.  mmap enabled by default, but may still be buggy.
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version119"><title>
-Version 1.1.9
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    Redesign and rewrite audio playback implementation.  (faster and smaller, hopefully)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Implement recording and full duplex (DSP_CAP_DUPLEX) support.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Make procfs support optional.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Quick interrupt status check, to lessen overhead in interrupt
-    sharing situations.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Add mmap(2) support.  Disabled for now, it is still buggy and experimental.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Surround all syscalls with a semaphore for cheap and easy SMP protection.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Fix bug in channel shutdown (hardware channel reset) code.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Remove unnecessary spinlocks (better performance).
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Eliminate "unknown AFMT" message by using a different method
-    of selecting the best AFMT_xxx sound sample format for use.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Support for realtime hardware pointer position reporting
-    (DSP_CAP_REALTIME, SNDCTL_DSP_GETxPTR ioctls)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Support for capture/playback triggering
-    (DSP_CAP_TRIGGER, SNDCTL_DSP_SETTRIGGER ioctls)
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    SNDCTL_DSP_SETDUPLEX and SNDCTL_DSP_POST ioctls now handled.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Rewrite open(2) and close(2) logic to allow only one user at
-    a time.  All other open(2) attempts will sleep until they succeed.
-    FIXME: open(O_RDONLY) and open(O_WRONLY) should be allowed to succeed.
-    </para>
-   </listitem>
-
-   <listitem>
-    <para>
-    Reviewed code to ensure that SMP and multiple audio devices
-    are fully supported.
-    </para>
-   </listitem>
-
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version118"><title>
-Version 1.1.8
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
-    	Clean up interrupt handler output.  Fixes the following kernel error message:
-    </para>
-  	<programlisting>
-	unhandled interrupt ...
-  	</programlisting>
-   </listitem>
-
-   <listitem>
-    <para>
-    	Convert documentation to DocBook, so that PDF, HTML and PostScript (.ps) output is readily
-	available.
-    </para>
-   </listitem>
-
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version117"><title>
-Version 1.1.7
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
- Fix module unload bug where mixer device left registered
-  after driver exit
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version116"><title>
-Version 1.1.6
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
- Rewrite via_set_rate to mimic ALSA basic AC97 rate setting
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Remove much dead code
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Complete spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Fix build problem in via_dsp_ioctl
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Optimize included headers to eliminate headers found in linux/sound
-	</para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version115"><title>
-Version 1.1.5
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
- Disable some overly-verbose debugging code
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Remove unnecessary sound locks
-   </para>
-   </listitem>
-   <listitem>
-    <para>
- Fix some ioctls for better time resolution
-    </para>
-   </listitem>
-   <listitem>
-    <para>
- Begin spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-<sect1 id="version114"><title>
-Version 1.1.4
-</title>
-  <itemizedlist spacing="compact">
-   <listitem>
-    <para>
- Completed rewrite of driver.  Eliminated SoundBlaster compatibility
-  completely, and now uses the much-faster scatter-gather DMA engine.
-    </para>
-   </listitem>
-  </itemizedlist>
-</sect1>
-
-  </chapter>
-  
-  <chapter id="intfunctions">
-     <title>Internal Functions</title>
-!Isound/oss/via82cxxx_audio.c
-  </chapter>
-
-</book>
-
-
diff --git a/Documentation/DocBook/videobook.tmpl b/Documentation/DocBook/videobook.tmpl
--- a/Documentation/DocBook/videobook.tmpl
+++ b/Documentation/DocBook/videobook.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="V4LGuide">
  <bookinfo>
@@ -180,23 +182,23 @@ int __init myradio_init(struct video_ini
    <tgroup cols="3" align="left">
    <tbody>
    <row>
-        <entry>VFL_TYPE_RADIO</><entry>/dev/radio{n}</><entry>
+        <entry>VFL_TYPE_RADIO</entry><entry>/dev/radio{n}</entry><entry>
 
         Radio devices are assigned in this block. As with all of these
         selections the actual number assignment is done by the video layer
         accordijng to what is free.</entry>
 	</row><row>
-        <entry>VFL_TYPE_GRABBER</><entry>/dev/video{n}</><entry>
+        <entry>VFL_TYPE_GRABBER</entry><entry>/dev/video{n}</entry><entry>
         Video capture devices and also -- counter-intuitively for the name --
         hardware video playback devices such as MPEG2 cards.</entry>
 	</row><row>
-        <entry>VFL_TYPE_VBI</><entry>/dev/vbi{n}</><entry>
+        <entry>VFL_TYPE_VBI</entry><entry>/dev/vbi{n}</entry><entry>
         The VBI devices capture the hidden lines on a television picture
         that carry further information like closed caption data, teletext
         (primarily in Europe) and now Intercast and the ATVEC internet
         television encodings.</entry>
 	</row><row>
-        <entry>VFL_TYPE_VTX</><entry>/dev/vtx[n}</><entry>
+        <entry>VFL_TYPE_VTX</entry><entry>/dev/vtx[n}</entry><entry>
         VTX is 'Videotext' also known as 'Teletext'. This is a system for
         sending numbered, 40x25, mostly textual page images over the hidden
         lines. Unlike the /dev/vbi interfaces, this is for 'smart' decoder 
@@ -301,25 +303,25 @@ static int radio_ioctl(struct video_devi
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-        <entry>name</><entry>The device text name. This is intended for the user.</>
+        <entry>name</entry><entry>The device text name. This is intended for the user.</entry>
 	</row><row>
-        <entry>channels</><entry>The number of different channels you can tune on
+        <entry>channels</entry><entry>The number of different channels you can tune on
                         this card. It could even by zero for a card that has
                         no tuning capability. For our simple FM radio it is 1. 
                         An AM/FM radio would report 2.</entry>
 	</row><row>
-        <entry>audios</><entry>The number of audio inputs on this device. For our
+        <entry>audios</entry><entry>The number of audio inputs on this device. For our
                         radio there is only one audio input.</entry>
 	</row><row>
-        <entry>minwidth,minheight</><entry>The smallest size the card is capable of capturing
+        <entry>minwidth,minheight</entry><entry>The smallest size the card is capable of capturing
 		        images in. We set these to zero. Radios do not
                         capture pictures</entry>
 	</row><row>
-        <entry>maxwidth,maxheight</><entry>The largest image size the card is capable of
+        <entry>maxwidth,maxheight</entry><entry>The largest image size the card is capable of
                                       capturing. For our radio we report 0.
 				</entry>
 	</row><row>
-        <entry>type</><entry>This reports the capabilities of the device, and
+        <entry>type</entry><entry>This reports the capabilities of the device, and
                         matches the field we filled in in the struct
                         video_device when registering.</entry>
     </row>
@@ -375,26 +377,26 @@ static int radio_ioctl(struct video_devi
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-        <entry>int tuner</><entry>The number of the tuner in question</entry>
+        <entry>int tuner</entry><entry>The number of the tuner in question</entry>
    </row><row>
-        <entry>char name[32]</><entry>A text description of this tuner. "FM" will do fine.
+        <entry>char name[32]</entry><entry>A text description of this tuner. "FM" will do fine.
                         This is intended for the application.</entry>
    </row><row>
-        <entry>u32 flags</>
+        <entry>u32 flags</entry>
         <entry>Tuner capability flags</entry>
    </row>
    <row>
-        <entry>u16 mode</><entry>The current reception mode</entry>
+        <entry>u16 mode</entry><entry>The current reception mode</entry>
 
    </row><row>
-        <entry>u16 signal</><entry>The signal strength scaled between 0 and 65535. If
+        <entry>u16 signal</entry><entry>The signal strength scaled between 0 and 65535. If
                         a device cannot tell the signal strength it should
                         report 65535. Many simple cards contain only a 
                         signal/no signal bit. Such cards will report either
                         0 or 65535.</entry>
 
    </row><row>
-        <entry>u32 rangelow, rangehigh</><entry>
+        <entry>u32 rangelow, rangehigh</entry><entry>
                         The range of frequencies supported by the radio
                         or TV. It is scaled according to the VIDEO_TUNER_LOW
                         flag.</entry>
@@ -408,20 +410,20 @@ static int radio_ioctl(struct video_devi
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-	<entry>VIDEO_TUNER_PAL</><entry>A PAL TV tuner</entry>
+	<entry>VIDEO_TUNER_PAL</entry><entry>A PAL TV tuner</entry>
 	</row><row>
-        <entry>VIDEO_TUNER_NTSC</><entry>An NTSC (US) TV tuner</entry>
+        <entry>VIDEO_TUNER_NTSC</entry><entry>An NTSC (US) TV tuner</entry>
 	</row><row>
-        <entry>VIDEO_TUNER_SECAM</><entry>A SECAM (French) TV tuner</entry>
+        <entry>VIDEO_TUNER_SECAM</entry><entry>A SECAM (French) TV tuner</entry>
 	</row><row>
-        <entry>VIDEO_TUNER_LOW</><entry>
+        <entry>VIDEO_TUNER_LOW</entry><entry>
              The tuner frequency is scaled in 1/16th of a KHz
              steps. If not it is in 1/16th of a MHz steps
 	</entry>
 	</row><row>
-        <entry>VIDEO_TUNER_NORM</><entry>The tuner can set its format</entry>
+        <entry>VIDEO_TUNER_NORM</entry><entry>The tuner can set its format</entry>
 	</row><row>
-        <entry>VIDEO_TUNER_STEREO_ON</><entry>The tuner is currently receiving a stereo signal</entry>
+        <entry>VIDEO_TUNER_STEREO_ON</entry><entry>The tuner is currently receiving a stereo signal</entry>
         </row>
     </tbody>
     </tgroup>
@@ -431,13 +433,13 @@ static int radio_ioctl(struct video_devi
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-                <entry>VIDEO_MODE_PAL</><entry>PAL Format</entry>
+                <entry>VIDEO_MODE_PAL</entry><entry>PAL Format</entry>
    </row><row>
-                <entry>VIDEO_MODE_NTSC</><entry>NTSC Format (USA)</entry>
+                <entry>VIDEO_MODE_NTSC</entry><entry>NTSC Format (USA)</entry>
    </row><row>
-                <entry>VIDEO_MODE_SECAM</><entry>French Format</entry>
+                <entry>VIDEO_MODE_SECAM</entry><entry>French Format</entry>
    </row><row>
-                <entry>VIDEO_MODE_AUTO</><entry>A device that does not need to do
+                <entry>VIDEO_MODE_AUTO</entry><entry>A device that does not need to do
                                         TV format switching</entry>
    </row>
     </tbody>
@@ -521,7 +523,7 @@ static unsigned long current_freq;
                         if(copy_from_user(arg, &amp;freq, 
                                 sizeof(unsigned long))!=0)
                                 return -EFAULT;
-                        if(hardware_set_freq(freq)<0)
+                        if(hardware_set_freq(freq)&lt;0)
                                 return -EINVAL;
                         current_freq = freq;
                         return 0;
@@ -582,32 +584,32 @@ static int current_volume=0;
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-   <entry>audio</><entry>The input the user wishes to query</>
+   <entry>audio</entry><entry>The input the user wishes to query</entry>
    </row><row>
-   <entry>volume</><entry>The volume setting on a scale of 0-65535</>
+   <entry>volume</entry><entry>The volume setting on a scale of 0-65535</entry>
    </row><row>
-   <entry>base</><entry>The base level on a scale of 0-65535</>
+   <entry>base</entry><entry>The base level on a scale of 0-65535</entry>
    </row><row>
-   <entry>treble</><entry>The treble level on a scale of 0-65535</>
+   <entry>treble</entry><entry>The treble level on a scale of 0-65535</entry>
    </row><row>
-   <entry>flags</><entry>The features this audio device supports
+   <entry>flags</entry><entry>The features this audio device supports
    </entry>
    </row><row>
-   <entry>name</><entry>A text name to display to the user. We picked 
-                        "Radio" as it explains things quite nicely.</>
+   <entry>name</entry><entry>A text name to display to the user. We picked
+                        "Radio" as it explains things quite nicely.</entry>
    </row><row>
-   <entry>mode</><entry>The current reception mode for the audio
+   <entry>mode</entry><entry>The current reception mode for the audio
 
                 We report MONO because our card is too stupid to know if it is in
                 mono or stereo. 
    </entry>
    </row><row>
-   <entry>balance</><entry>The stereo balance on a scale of 0-65535, 32768 is
-                        middle.</>
+   <entry>balance</entry><entry>The stereo balance on a scale of 0-65535, 32768 is
+                        middle.</entry>
    </row><row>
-   <entry>step</><entry>The step by which the volume control jumps. This is
+   <entry>step</entry><entry>The step by which the volume control jumps. This is
                         used to help make it easy for applications to set 
-                        slider behaviour.</>   
+                        slider behaviour.</entry>
    </row>
    </tbody>
    </tgroup>
@@ -617,15 +619,15 @@ static int current_volume=0;
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-                <entry>VIDEO_AUDIO_MUTE</><entry>The audio is currently muted. We
+                <entry>VIDEO_AUDIO_MUTE</entry><entry>The audio is currently muted. We
                                         could fake this in our driver but we
                                         choose not to bother.</entry>
    </row><row>
-                <entry>VIDEO_AUDIO_MUTABLE</><entry>The input has a mute option</entry>
+                <entry>VIDEO_AUDIO_MUTABLE</entry><entry>The input has a mute option</entry>
    </row><row>
-                <entry>VIDEO_AUDIO_TREBLE</><entry>The  input has a treble control</entry>
+                <entry>VIDEO_AUDIO_TREBLE</entry><entry>The  input has a treble control</entry>
    </row><row>
-                <entry>VIDEO_AUDIO_BASS</><entry>The input has a base control</entry>
+                <entry>VIDEO_AUDIO_BASS</entry><entry>The input has a base control</entry>
    </row>
    </tbody>
    </tgroup>
@@ -635,13 +637,13 @@ static int current_volume=0;
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-                <entry>VIDEO_SOUND_MONO</><entry>Mono sound</entry>
+                <entry>VIDEO_SOUND_MONO</entry><entry>Mono sound</entry>
    </row><row>
-                <entry>VIDEO_SOUND_STEREO</><entry>Stereo sound</entry>
+                <entry>VIDEO_SOUND_STEREO</entry><entry>Stereo sound</entry>
    </row><row>
-                <entry>VIDEO_SOUND_LANG1</><entry>Alternative language 1 (TV specific)</entry>
+                <entry>VIDEO_SOUND_LANG1</entry><entry>Alternative language 1 (TV specific)</entry>
    </row><row>
-                <entry>VIDEO_SOUND_LANG2</><entry>Alternative language 2 (TV specific)</entry>
+                <entry>VIDEO_SOUND_LANG2</entry><entry>Alternative language 2 (TV specific)</entry>
    </row>
    </tbody>
    </tgroup>
@@ -866,37 +868,37 @@ static struct video_device my_camera
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-<entry>VID_TYPE_CAPTURE</><entry>We support image capture</>
+<entry>VID_TYPE_CAPTURE</entry><entry>We support image capture</entry>
 </row><row>
-<entry>VID_TYPE_TELETEXT</><entry>A teletext capture device (vbi{n])</>
+<entry>VID_TYPE_TELETEXT</entry><entry>A teletext capture device (vbi{n])</entry>
 </row><row>
-<entry>VID_TYPE_OVERLAY</><entry>The image can be directly overlaid onto the
-                                frame buffer</>
+<entry>VID_TYPE_OVERLAY</entry><entry>The image can be directly overlaid onto the
+                                frame buffer</entry>
 </row><row>
-<entry>VID_TYPE_CHROMAKEY</><entry>Chromakey can be used to select which parts
-                                of the image to display</>
+<entry>VID_TYPE_CHROMAKEY</entry><entry>Chromakey can be used to select which parts
+                                of the image to display</entry>
 </row><row>
-<entry>VID_TYPE_CLIPPING</><entry>It is possible to give the board a list of
-                                rectangles to draw around. </>
+<entry>VID_TYPE_CLIPPING</entry><entry>It is possible to give the board a list of
+                                rectangles to draw around. </entry>
 </row><row>
-<entry>VID_TYPE_FRAMERAM</><entry>The video capture goes into the video memory
+<entry>VID_TYPE_FRAMERAM</entry><entry>The video capture goes into the video memory
                                 and actually changes it. Applications need
                                 to know this so they can clean up after the
-                                card</>
+                                card</entry>
 </row><row>
-<entry>VID_TYPE_SCALES</><entry>The image can be scaled to various sizes,
-                                rather than being a single fixed size.</>
+<entry>VID_TYPE_SCALES</entry><entry>The image can be scaled to various sizes,
+                                rather than being a single fixed size.</entry>
 </row><row>
-<entry>VID_TYPE_MONOCHROME</><entry>The capture will be monochrome. This isn't a 
+<entry>VID_TYPE_MONOCHROME</entry><entry>The capture will be monochrome. This isn't a
                                 complete answer to the question since a mono
                                 camera on a colour capture card will still
-                                produce mono output.</>
+                                produce mono output.</entry>
 </row><row>
-<entry>VID_TYPE_SUBCAPTURE</><entry>The card allows only part of its field of
+<entry>VID_TYPE_SUBCAPTURE</entry><entry>The card allows only part of its field of
                                 view to be captured. This enables
                                 applications to avoid copying all of a large
                                 image into memory when only some section is
-                                relevant.</>
+                                relevant.</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1207,18 +1209,18 @@ static int camera_ioctl(struct video_dev
    <tbody>
    <row>
 
-   <entry>channel</><entry>The channel number we are selecting</entry>
+   <entry>channel</entry><entry>The channel number we are selecting</entry>
    </row><row>
-   <entry>name</><entry>The name for this channel. This is intended
+   <entry>name</entry><entry>The name for this channel. This is intended
                    to describe the port to the user.
                    Appropriate names are therefore things like
                    "Camera" "SCART input"</entry>
    </row><row>
-   <entry>flags</><entry>Channel properties</entry>
+   <entry>flags</entry><entry>Channel properties</entry>
    </row><row>
-   <entry>type</><entry>Input type</entry>
+   <entry>type</entry><entry>Input type</entry>
    </row><row>
-   <entry>norm</><entry>The current television encoding being used
+   <entry>norm</entry><entry>The current television encoding being used
                    if relevant for this channel.
     </entry>
     </row>
@@ -1229,9 +1231,9 @@ static int camera_ioctl(struct video_dev
     <tgroup cols="2" align="left">
     <tbody>
     <row>
-        <entry>VIDEO_VC_TUNER</><entry>Channel has a tuner.</entry>
+        <entry>VIDEO_VC_TUNER</entry><entry>Channel has a tuner.</entry>
    </row><row>
-        <entry>VIDEO_VC_AUDIO</><entry>Channel has audio.</entry>
+        <entry>VIDEO_VC_AUDIO</entry><entry>Channel has audio.</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1240,11 +1242,11 @@ static int camera_ioctl(struct video_dev
     <tgroup cols="2" align="left">
     <tbody>
     <row>
-        <entry>VIDEO_TYPE_TV</><entry>Television input.</entry>
+        <entry>VIDEO_TYPE_TV</entry><entry>Television input.</entry>
    </row><row>
-        <entry>VIDEO_TYPE_CAMERA</><entry>Fixed camera input.</entry>
+        <entry>VIDEO_TYPE_CAMERA</entry><entry>Fixed camera input.</entry>
    </row><row>
-	<entry>0</><entry>Type is unknown.</entry>
+	<entry>0</entry><entry>Type is unknown.</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1253,13 +1255,13 @@ static int camera_ioctl(struct video_dev
     <tgroup cols="2" align="left">
     <tbody>
     <row>
-        <entry>VIDEO_MODE_PAL</><entry>PAL encoded Television</entry>
+        <entry>VIDEO_MODE_PAL</entry><entry>PAL encoded Television</entry>
    </row><row>
-        <entry>VIDEO_MODE_NTSC</><entry>NTSC (US) encoded Television</entry>
+        <entry>VIDEO_MODE_NTSC</entry><entry>NTSC (US) encoded Television</entry>
    </row><row>
-        <entry>VIDEO_MODE_SECAM</><entry>SECAM (French) Television </entry>
+        <entry>VIDEO_MODE_SECAM</entry><entry>SECAM (French) Television </entry>
    </row><row>
-        <entry>VIDEO_MODE_AUTO</><entry>Automatic switching, or format does not
+        <entry>VIDEO_MODE_AUTO</entry><entry>Automatic switching, or format does not
                                 matter</entry>
     </row>
     </tbody>
@@ -1339,14 +1341,14 @@ static int camera_ioctl(struct video_dev
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-   <entry>GREY</><entry>Linear greyscale. This is for simple cameras and the
-                        like</>
+   <entry>GREY</entry><entry>Linear greyscale. This is for simple cameras and the
+                        like</entry>
    </row><row>
-   <entry>RGB565</><entry>The top 5 bits hold 32 red levels, the next six bits 
-                        hold green and the low 5 bits hold blue. </>
+   <entry>RGB565</entry><entry>The top 5 bits hold 32 red levels, the next six bits
+                        hold green and the low 5 bits hold blue. </entry>
    </row><row>
-   <entry>RGB555</><entry>The top bit is clear. The red green and blue levels
-                        each occupy five bits.</>
+   <entry>RGB555</entry><entry>The top bit is clear. The red green and blue levels
+                        each occupy five bits.</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1477,32 +1479,32 @@ static struct video_buffer capture_fb;
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-        <entry>width</><entry>The width in pixels of the desired image. The card
-                        may use a smaller size if this size is not available</>
+        <entry>width</entry><entry>The width in pixels of the desired image. The card
+                        may use a smaller size if this size is not available</entry>
 	</row><row>
-        <entry>height</><entry>The height of the image. The card may use a smaller
-                        size if this size is not available.</>
+        <entry>height</entry><entry>The height of the image. The card may use a smaller
+                        size if this size is not available.</entry>
 	</row><row>
-        <entry>x</><entry>   The X position of the top left of the window. This
+        <entry>x</entry><entry>   The X position of the top left of the window. This
                         is in pixels relative to the left hand edge of the
                         picture. Not all cards can display images aligned on
                         any pixel boundary. If the position is unsuitable
                         the card adjusts the image right and reduces the
-                        width.</>
+                        width.</entry>
 	</row><row>
-        <entry>y</><entry>   The Y position of the top left of the window. This
+        <entry>y</entry><entry>   The Y position of the top left of the window. This
                         is counted in pixels relative to the top edge of the
                         picture. As with the width if the card cannot
                         display  starting on this line it will adjust the
-                        values.</>
+                        values.</entry>
 	</row><row>
-        <entry>chromakey</><entry>The colour (expressed in RGB32 format) for the
-                        chromakey colour if chroma keying is being used. </>
+        <entry>chromakey</entry><entry>The colour (expressed in RGB32 format) for the
+                        chromakey colour if chroma keying is being used. </entry>
 	</row><row>
-        <entry>clips</><entry>An array of rectangles that must not be drawn
-			over.</>
+        <entry>clips</entry><entry>An array of rectangles that must not be drawn
+			over.</entry>
 	</row><row>
-        <entry>clipcount</><entry>The number of clips in this array.</>
+        <entry>clipcount</entry><entry>The number of clips in this array.</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1514,11 +1516,11 @@ static struct video_buffer capture_fb;
    <tgroup cols="2" align="left">
    <tbody>
    <row>
-        <entry>x, y</><entry>Co-ordinates relative to the display</>
+        <entry>x, y</entry><entry>Co-ordinates relative to the display</entry>
 	</row><row>
-        <entry>width, height</><entry>Width and height in pixels</>
+        <entry>width, height</entry><entry>Width and height in pixels</entry>
 	</row><row>
-        <entry>next</><entry>A spare field for the application to use</>
+        <entry>next</entry><entry>A spare field for the application to use</entry>
     </row>
     </tbody>
     </tgroup>
@@ -1550,9 +1552,9 @@ static struct video_buffer capture_fb;
                         struct video_window v;
                         if(copy_from_user(&amp;v, arg, sizeof(v)))
                                 return -EFAULT;
-                        if(v.width > 640 || v.height > 480)
+                        if(v.width &gt; 640 || v.height &gt; 480)
                                 return -EINVAL;
-                        if(v.width < 16 || v.height < 16)
+                        if(v.width &lt; 16 || v.height &lt; 16)
                                 return -EINVAL;
                         hardware_set_key(v.chromakey);
                         hardware_set_window(v);
diff --git a/Documentation/DocBook/wanbook.tmpl b/Documentation/DocBook/wanbook.tmpl
--- a/Documentation/DocBook/wanbook.tmpl
+++ b/Documentation/DocBook/wanbook.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="WANGuide">
  <bookinfo>
diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl
--- a/Documentation/DocBook/writing_usb_driver.tmpl
+++ b/Documentation/DocBook/writing_usb_driver.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="USBDeviceDriver">
  <bookinfo>
diff --git a/Documentation/DocBook/z8530book.tmpl b/Documentation/DocBook/z8530book.tmpl
--- a/Documentation/DocBook/z8530book.tmpl
+++ b/Documentation/DocBook/z8530book.tmpl
@@ -1,4 +1,6 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <book id="Z85230Guide">
  <bookinfo>
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -342,6 +342,7 @@ You can change this at module load time 
        irqs=<irq1>,<irq2>... trydefaults=[0|1]
        regspacings=<sp1>,<sp2>,... regsizes=<size1>,<size2>,...
        regshifts=<shift1>,<shift2>,...
+       slave_addrs=<addr1>,<addr2>,...
 
 Each of these except si_trydefaults is a list, the first item for the
 first interface, second item for the second interface, etc.
@@ -383,6 +384,10 @@ Since the register size may be larger th
 be in the lower 8 bits.  The regshifts parameter give the amount to shift
 the data to get to the actual IPMI data.
 
+The slave_addrs specifies the IPMI address of the local BMC.  This is
+usually 0x20 and the driver defaults to that, but in case it's not, it
+can be specified when the driver starts up.
+
 When compiled into the kernel, the addresses can be specified on the
 kernel command line as:
 
@@ -392,6 +397,7 @@ kernel command line as:
        ipmi_si.regspacings=<sp1>,<sp2>,...
        ipmi_si.regsizes=<size1>,<size2>,...
        ipmi_si.regshifts=<shift1>,<shift2>,...
+       ipmi_si.slave_addrs=<addr1>,<addr2>,...
 
 It works the same as the module parameters of the same names.
 
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -108,8 +108,9 @@ year saw a paper describing an RCU imple
 2004 has seen a Linux-Journal article on use of RCU in dcache
 [McKenney04a], a performance comparison of locking to RCU on several
 different CPUs [McKenney04b], a dissertation describing use of RCU in a
-number of operating-system kernels [PaulEdwardMcKenneyPhD], and a paper
-describing how to make RCU safe for soft-realtime applications [Sarma04c].
+number of operating-system kernels [PaulEdwardMcKenneyPhD], a paper
+describing how to make RCU safe for soft-realtime applications [Sarma04c],
+and a paper describing SELinux performance with RCU [JamesMorris04b].
 
 
 Bibtex Entries
@@ -341,6 +342,17 @@ Dipankar Sarma"
 ,pages="18-26"
 }
 
+@techreport{Friedberg03a
+,author="Stuart A. Friedberg"
+,title="Lock-Free Wild Card Search Data Structure and Method"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="2003"
+,number="US Patent 6,662,184 (contributed under GPL)"
+,month="December"
+,pages="112"
+}
+
 @article{McKenney04a
 ,author="Paul E. McKenney and Dipankar Sarma and Maneesh Soni"
 ,title="Scaling dcache with {RCU}"
@@ -373,6 +385,9 @@ in Operating System Kernels"
 ,school="OGI School of Science and Engineering at
 Oregon Health and Sciences University"
 ,year="2004"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf}
+[Viewed October 15, 2004]"
 }
 
 @Conference{Sarma04c
@@ -385,3 +400,13 @@ Oregon Health and Sciences University"
 ,month="June"
 ,pages="182-191"
 }
+
+@unpublished{JamesMorris04b
+,Author="James Morris"
+,Title="Recent Developments in {SELinux} Kernel Performance"
+,month="December"
+,year="2004"
+,note="Available:
+\url{http://www.livejournal.com/users/james_morris/2153.html}
+[Viewed December 10, 2004]"
+}
diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt
--- a/Documentation/RCU/UP.txt
+++ b/Documentation/RCU/UP.txt
@@ -2,11 +2,11 @@ RCU on Uniprocessor Systems
 
 
 A common misconception is that, on UP systems, the call_rcu() primitive
-may immediately invoke its function, and that the synchronize_kernel
+may immediately invoke its function, and that the synchronize_rcu()
 primitive may return immediately.  The basis of this misconception
 is that since there is only one CPU, it should not be necessary to
 wait for anything else to get done, since there are no other CPUs for
-anything else to be happening on.  Although this approach will sort of
+anything else to be happening on.  Although this approach will -sort- -of-
 work a surprising amount of the time, it is a very bad idea in general.
 This document presents two examples that demonstrate exactly how bad an
 idea this is.
@@ -44,14 +44,14 @@ its arguments would cause it to fail to 
 underlying RCU, namely that call_rcu() defers invoking its arguments until
 all RCU read-side critical sections currently executing have completed.
 
-Quick Quiz: why is it -not- legal to invoke synchronize_kernel() in
+Quick Quiz: why is it -not- legal to invoke synchronize_rcu() in
 this case?
 
 
 Summary
 
 Permitting call_rcu() to immediately invoke its arguments or permitting
-synchronize_kernel() to immediately return breaks RCU, even on a UP system.
+synchronize_rcu() to immediately return breaks RCU, even on a UP system.
 So do not do it!  Even on a UP system, the RCU infrastructure -must-
 respect grace periods.
 
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -32,7 +32,10 @@ over a rather long period of time, but i
 	them -- even x86 allows reads to be reordered), and be prepared
 	to explain why this added complexity is worthwhile.  If you
 	choose #c, be prepared to explain how this single task does not
-	become a major bottleneck on big multiprocessor machines.
+	become a major bottleneck on big multiprocessor machines (for
+	example, if the task is updating information relating to itself
+	that other tasks can read, there by definition can be no
+	bottleneck).
 
 2.	Do the RCU read-side critical sections make proper use of
 	rcu_read_lock() and friends?  These primitives are needed
@@ -89,27 +92,34 @@ over a rather long period of time, but i
 		"_rcu()" list-traversal primitives, such as the
 		list_for_each_entry_rcu().
 
-	b.	If the list macros are being used, the list_del_rcu(),
-		list_add_tail_rcu(), and list_del_rcu() primitives must
-		be used in order to prevent weakly ordered machines from
-		misordering structure initialization and pointer planting.
+	b.	If the list macros are being used, the list_add_tail_rcu()
+		and list_add_rcu() primitives must be used in order
+		to prevent weakly ordered machines from misordering
+		structure initialization and pointer planting.
 		Similarly, if the hlist macros are being used, the
-		hlist_del_rcu() and hlist_add_head_rcu() primitives
-		are required.
+		hlist_add_head_rcu() primitive is required.
 
-	c.	Updates must ensure that initialization of a given
+	c.	If the list macros are being used, the list_del_rcu()
+		primitive must be used to keep list_del()'s pointer
+		poisoning from inflicting toxic effects on concurrent
+		readers.  Similarly, if the hlist macros are being used,
+		the hlist_del_rcu() primitive is required.
+
+		The list_replace_rcu() primitive may be used to
+		replace an old structure with a new one in an
+		RCU-protected list.
+
+	d.	Updates must ensure that initialization of a given
 		structure happens before pointers to that structure are
 		publicized.  Use the rcu_assign_pointer() primitive
 		when publicizing a pointer to a structure that can
 		be traversed by an RCU read-side critical section.
 
-		[The rcu_assign_pointer() primitive is in process.]
-
 5.	If call_rcu(), or a related primitive such as call_rcu_bh(),
 	is used, the callback function must be written to be called
 	from softirq context.  In particular, it cannot block.
 
-6.	Since synchronize_kernel() blocks, it cannot be called from
+6.	Since synchronize_rcu() can block, it cannot be called from
 	any sort of irq context.
 
 7.	If the updater uses call_rcu(), then the corresponding readers
@@ -125,9 +135,9 @@ over a rather long period of time, but i
 	such cases is a must, of course!  And the jury is still out on
 	whether the increased speed is worth it.
 
-8.	Although synchronize_kernel() is a bit slower than is call_rcu(),
+8.	Although synchronize_rcu() is a bit slower than is call_rcu(),
 	it usually results in simpler code.  So, unless update performance
-	is important or the updaters cannot block, synchronize_kernel()
+	is important or the updaters cannot block, synchronize_rcu()
 	should be used in preference to call_rcu().
 
 9.	All RCU list-traversal primitives, which include
@@ -155,3 +165,14 @@ over a rather long period of time, but i
 	you -must- use the "_rcu()" variants of the list macros.
 	Failing to do so will break Alpha and confuse people reading
 	your code.
+
+11.	Note that synchronize_rcu() -only- guarantees to wait until
+	all currently executing rcu_read_lock()-protected RCU read-side
+	critical sections complete.  It does -not- necessarily guarantee
+	that all currently running interrupts, NMIs, preempt_disable()
+	code, or idle loops will complete.  Therefore, if you do not have
+	rcu_read_lock()-protected read-side critical sections, do -not-
+	use synchronize_rcu().
+
+	If you want to wait for some of these other things, you might
+	instead need to use synchronize_irq() or synchronize_sched().
diff --git a/Documentation/RCU/listRCU.txt b/Documentation/RCU/listRCU.txt
--- a/Documentation/RCU/listRCU.txt
+++ b/Documentation/RCU/listRCU.txt
@@ -32,6 +32,7 @@ implementation of audit_filter_task() mi
 		enum audit_state   state;
 
 		read_lock(&auditsc_lock);
+		/* Note: audit_netlink_sem held by caller. */
 		list_for_each_entry(e, &audit_tsklist, list) {
 			if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
 				read_unlock(&auditsc_lock);
@@ -55,6 +56,7 @@ This means that RCU can be easily applie
 		enum audit_state   state;
 
 		rcu_read_lock();
+		/* Note: audit_netlink_sem held by caller. */
 		list_for_each_entry_rcu(e, &audit_tsklist, list) {
 			if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
 				rcu_read_unlock();
@@ -139,12 +141,15 @@ Normally, the write_lock() and write_unl
 a spin_lock() and a spin_unlock(), but in this case, all callers hold
 audit_netlink_sem, so no additional locking is required.  The auditsc_lock
 can therefore be eliminated, since use of RCU eliminates the need for
-writers to exclude readers.
+writers to exclude readers.  Normally, the write_lock() calls would
+be converted into spin_lock() calls.
 
 The list_del(), list_add(), and list_add_tail() primitives have been
 replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu().
 The _rcu() list-manipulation primitives add memory barriers that are
-needed on weakly ordered CPUs (most of them!).
+needed on weakly ordered CPUs (most of them!).  The list_del_rcu()
+primitive omits the pointer poisoning debug-assist code that would
+otherwise cause concurrent readers to fail spectacularly.
 
 So, when readers can tolerate stale data and when entries are either added
 or deleted, without in-place modification, it is very easy to use RCU!
@@ -166,6 +171,7 @@ otherwise, the added fields would need t
 		struct audit_newentry *ne;
 
 		write_lock(&auditsc_lock);
+		/* Note: audit_netlink_sem held by caller. */
 		list_for_each_entry(e, list, list) {
 			if (!audit_compare_rule(rule, &e->rule)) {
 				e->rule.action = newaction;
@@ -199,8 +205,7 @@ RCU ("read-copy update") its name.  The 
 				audit_copy_rule(&ne->rule, &e->rule);
 				ne->rule.action = newaction;
 				ne->rule.file_count = newfield_count;
-				list_add_rcu(ne, e);
-				list_del(e);
+				list_replace_rcu(e, ne);
 				call_rcu(&e->rcu, audit_free_rule, e);
 				return 0;
 			}
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
--- a/Documentation/RCU/rcu.txt
+++ b/Documentation/RCU/rcu.txt
@@ -43,7 +43,9 @@ o	If I am running on a uniprocessor kern
 
 o	How can I see where RCU is currently used in the Linux kernel?
 
-	Search for "rcu_read_lock", "call_rcu", and "synchronize_kernel".
+	Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
+	"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
+	"synchronize_rcu", and "synchronize_net".
 
 o	What guidelines should I follow when writing code that uses RCU?
 
diff --git a/Documentation/SecurityBugs b/Documentation/SecurityBugs
new file mode 100644
--- /dev/null
+++ b/Documentation/SecurityBugs
@@ -0,0 +1,38 @@
+Linux kernel developers take security very seriously.  As such, we'd
+like to know when a security bug is found so that it can be fixed and
+disclosed as quickly as possible.  Please report security bugs to the
+Linux kernel security team.
+
+1) Contact
+
+The Linux kernel security team can be contacted by email at
+<security@kernel.org>.  This is a private list of security officers
+who will help verify the bug report and develop and release a fix.
+It is possible that the security team will bring in extra help from
+area maintainers to understand and fix the security vulnerability.
+
+As it is with any bug, the more information provided the easier it
+will be to diagnose and fix.  Please review the procedure outlined in
+REPORTING-BUGS if you are unclear about what information is helpful.
+Any exploit code is very helpful and will not be released without
+consent from the reporter unless it has already been made public.
+
+2) Disclosure
+
+The goal of the Linux kernel security team is to work with the
+bug submitter to bug resolution as well as disclosure.  We prefer
+to fully disclose the bug as soon as possible.  It is reasonable to
+delay disclosure when the bug or the fix is not yet fully understood,
+the solution is not well-tested or for vendor coordination.  However, we
+expect these delays to be short, measurable in days, not weeks or months.
+A disclosure date is negotiated by the security team working with the
+bug submitter as well as vendors.  However, the kernel security team
+holds the final say when setting a disclosure date.  The timeframe for
+disclosure is from immediate (esp. if it's already publically known)
+to a few weeks.  As a basic default policy, we expect report date to
+disclosure date to be on the order of 7 days.
+
+3) Non-disclosure agreements
+
+The Linux kernel security team is not a formal body and therefore unable
+to enter any non-disclosure agreements.
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -118,13 +118,18 @@ Linux kernel mailing list:		
 	linux-kernel@vger.kernel.org
 	[mail majordomo@vger.kernel.org to subscribe]
 
+Linux Device Drivers, Third Edition (covers 2.6.10):
+	http://lwn.net/Kernel/LDD3/  (free version)
+
 Kernel traffic:
 	Weekly summary of kernel list activity (much easier to read)
 	http://www.kerneltraffic.org/kernel-traffic/
 
 LWN.net:
 	Weekly summary of kernel development activity - http://lwn.net/
-	2.6 driver porting information:
+	2.6 API changes:
+		http://lwn.net/Articles/2.6-kernel-api/
+	Porting drivers from prior kernels to 2.6:
 		http://lwn.net/Articles/driver-porting/
 
 KernelTrap:
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -271,7 +271,7 @@ patch, which certifies that you wrote it
 pass it on as a open-source patch.  The rules are pretty simple: if you
 can certify the below:
 
-        Developer's Certificate of Origin 1.0
+        Developer's Certificate of Origin 1.1
 
         By making a contribution to this project, I certify that:
 
@@ -291,6 +291,12 @@ can certify the below:
             person who certified (a), (b) or (c) and I have not modified
             it.
 
+	(d) I understand and agree that this project and the contribution
+	    are public and that a record of the contribution (including all
+	    personal information I submit with it, including my sign-off) is
+	    maintained indefinitely and may be redistributed consistent with
+	    this project or the open source license(s) involved.
+
 then you just add a line saying
 
 	Signed-off-by: Random J Developer <random@developer.org>
diff --git a/Documentation/aoe/aoe.txt b/Documentation/aoe/aoe.txt
--- a/Documentation/aoe/aoe.txt
+++ b/Documentation/aoe/aoe.txt
@@ -4,11 +4,28 @@ The EtherDrive (R) HOWTO for users of 2.
 
   It has many tips and hints!
 
+The aoetools are userland programs that are designed to work with this
+driver.  The aoetools are on sourceforge.
+
+  http://aoetools.sourceforge.net/
+
+The scripts in this Documentation/aoe directory are intended to
+document the use of the driver and are not necessary if you install
+the aoetools.
+
+
 CREATING DEVICE NODES
 
-  Users of udev should find device nodes created automatically.  Two
-  scripts are provided in Documentation/aoe as examples of static
-  device node creation for using the aoe driver.
+  Users of udev should find the block device nodes created
+  automatically, but to create all the necessary device nodes, use the
+  udev configuration rules provided in udev.txt (in this directory).
+
+  There is a udev-install.sh script that shows how to install these
+  rules on your system.
+
+  If you are not using udev, two scripts are provided in
+  Documentation/aoe as examples of static device node creation for
+  using the aoe driver.
 
     rm -rf /dev/etherd
     sh Documentation/aoe/mkdevs.sh /dev/etherd
@@ -28,14 +45,15 @@ USING DEVICE NODES
 
   "echo eth2 eth4 > /dev/etherd/interfaces" tells the aoe driver to
   limit ATA over Ethernet traffic to eth2 and eth4.  AoE traffic from
-  untrusted networks should be ignored as a matter of security.
+  untrusted networks should be ignored as a matter of security.  See
+  also the aoe_iflist driver option described below.
 
   "echo > /dev/etherd/discover" tells the driver to find out what AoE
   devices are available.
 
   These character devices may disappear and be replaced by sysfs
-  counterparts, so distribution maintainers are encouraged to create
-  scripts that use these devices.
+  counterparts.  Using the commands in aoetools insulates users from
+  these implementation details.
 
   The block devices are named like this:
 
@@ -59,7 +77,8 @@ USING SYSFS
   through which we are communicating with the remote AoE device.
 
   There is a script in this directory that formats this information
-  in a convenient way.
+  in a convenient way.  Users with aoetools can use the aoe-stat
+  command.
 
   root@makki root# sh Documentation/aoe/status.sh 
      e10.0            eth3              up
@@ -82,3 +101,23 @@ USING SYSFS
       e4.7            eth1              up
       e4.8            eth1              up
       e4.9            eth1              up
+
+  Use /sys/module/aoe/parameters/aoe_iflist (or better, the driver
+  option discussed below) instead of /dev/etherd/interfaces to limit
+  AoE traffic to the network interfaces in the given
+  whitespace-separated list.  Unlike the old character device, the
+  sysfs entry can be read from as well as written to.
+
+  It's helpful to trigger discovery after setting the list of allowed
+  interfaces.  The aoetools package provides an aoe-discover script
+  for this purpose.  You can also directly use the
+  /dev/etherd/discover special file described above.
+
+DRIVER OPTIONS
+
+  There is a boot option for the built-in aoe driver and a
+  corresponding module parameter, aoe_iflist.  Without this option,
+  all network interfaces may be used for ATA over Ethernet.  Here is a
+  usage example for the module parameter.
+
+    modprobe aoe_iflist="eth1 eth3"
diff --git a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh
--- a/Documentation/aoe/mkdevs.sh
+++ b/Documentation/aoe/mkdevs.sh
@@ -5,6 +5,7 @@ n_partitions=${n_partitions:-16}
 
 if test "$#" != "1"; then
 	echo "Usage: sh `basename $0` {dir}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir}" 1>&2
 	exit 1
 fi
 dir=$1
diff --git a/Documentation/aoe/mkshelf.sh b/Documentation/aoe/mkshelf.sh
--- a/Documentation/aoe/mkshelf.sh
+++ b/Documentation/aoe/mkshelf.sh
@@ -2,6 +2,7 @@
 
 if test "$#" != "2"; then
 	echo "Usage: sh `basename $0` {dir} {shelfaddress}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir} {shelfaddress}" 1>&2
 	exit 1
 fi
 n_partitions=${n_partitions:-16}
diff --git a/Documentation/aoe/status.sh b/Documentation/aoe/status.sh
--- a/Documentation/aoe/status.sh
+++ b/Documentation/aoe/status.sh
@@ -4,19 +4,18 @@
 set -e
 format="%8s\t%8s\t%8s\n"
 me=`basename $0`
+sysd=${sysfs_dir:-/sys}
 
 # printf "$format" device mac netif state
 
-test -z "`mount | grep sysfs`" && {
+# Suse 9.1 Pro doesn't put /sys in /etc/mtab
+#test -z "`mount | grep sysfs`" && {
+test ! -d "$sysd/block" && {
 	echo "$me Error: sysfs is not mounted" 1>&2
 	exit 1
 }
-test -z "`lsmod | grep '^aoe'`" && {
-	echo  "$me Error: aoe module is not loaded" 1>&2
-	exit 1
-}
 
-for d in `ls -d /sys/block/etherd* 2>/dev/null | grep -v p` end; do
+for d in `ls -d $sysd/block/etherd* 2>/dev/null | grep -v p` end; do
 	# maybe ls comes up empty, so we use "end"
 	test $d = end && continue
 
diff --git a/Documentation/aoe/todo.txt b/Documentation/aoe/todo.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/aoe/todo.txt
@@ -0,0 +1,14 @@
+There is a potential for deadlock when allocating a struct sk_buff for
+data that needs to be written out to aoe storage.  If the data is
+being written from a dirty page in order to free that page, and if
+there are no other pages available, then deadlock may occur when a
+free page is needed for the sk_buff allocation.  This situation has
+not been observed, but it would be nice to eliminate any potential for
+deadlock under memory pressure.
+
+Because ATA over Ethernet is not fragmented by the kernel's IP code,
+the destructore member of the struct sk_buff is available to the aoe
+driver.  By using a mempool for allocating all but the first few
+sk_buffs, and by registering a destructor, we should be able to
+efficiently allocate sk_buffs without introducing any potential for
+deadlock.
diff --git a/Documentation/aoe/udev-install.sh b/Documentation/aoe/udev-install.sh
new file mode 100644
--- /dev/null
+++ b/Documentation/aoe/udev-install.sh
@@ -0,0 +1,30 @@
+# install the aoe-specific udev rules from udev.txt into 
+# the system's udev configuration
+# 
+
+me="`basename $0`"
+
+# find udev.conf, often /etc/udev/udev.conf
+# (or environment can specify where to find udev.conf)
+#
+if test -z "$conf"; then
+	if test -r /etc/udev/udev.conf; then
+		conf=/etc/udev/udev.conf
+	else
+		conf="`find /etc -type f -name udev.conf 2> /dev/null`"
+		if test -z "$conf" || test ! -r "$conf"; then
+			echo "$me Error: no udev.conf found" 1>&2
+			exit 1
+		fi
+	fi
+fi
+
+# find the directory where udev rules are stored, often
+# /etc/udev/rules.d
+#
+rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`"
+if test -z "$rules_d" || test ! -d "$rules_d"; then
+	echo "$me Error: cannot find udev rules directory" 1>&2
+	exit 1
+fi
+sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules"
diff --git a/Documentation/aoe/udev.txt b/Documentation/aoe/udev.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/aoe/udev.txt
@@ -0,0 +1,23 @@
+# These rules tell udev what device nodes to create for aoe support.
+# They may be installed along the following lines (adjusted to what
+# you see on your system).
+# 
+#   ecashin@makki ~$ su
+#   Password:
+#   bash# find /etc -type f -name udev.conf
+#   /etc/udev/udev.conf
+#   bash# grep udev_rules= /etc/udev/udev.conf
+#   udev_rules="/etc/udev/rules.d/"
+#   bash# ls /etc/udev/rules.d/
+#   10-wacom.rules  50-udev.rules
+#   bash# cp /path/to/linux-2.6.xx/Documentation/aoe/udev.txt \
+#           /etc/udev/rules.d/60-aoe.rules
+#  
+
+# aoe char devices
+SUBSYSTEM="aoe", KERNEL="discover",	NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM="aoe", KERNEL="err",		NAME="etherd/%k", GROUP="disk", MODE="0440"
+SUBSYSTEM="aoe", KERNEL="interfaces",	NAME="etherd/%k", GROUP="disk", MODE="0220"
+
+# aoe block devices     
+KERNEL="etherd*",       NAME="%k", GROUP="disk"
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
--- a/Documentation/arm/IXP2000
+++ b/Documentation/arm/IXP2000
@@ -45,7 +45,7 @@ MAILING LISTS REGARDING THE INTEL SDK.
 
 4. Usage Notes
 
-- The IXP2000 platforms ususally have rather complex PCI bus topologies
+- The IXP2000 platforms usually have rather complex PCI bus topologies
   with large memory space requirements. In addition, b/c of the way the
   Intel SDK is designed, devices are enumerated in a very specific
   way. B/c of this this, we use "pci=firmware" option in the kernel
diff --git a/Documentation/arm/Samsung-S3C24XX/H1940.txt b/Documentation/arm/Samsung-S3C24XX/H1940.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/H1940.txt
@@ -0,0 +1,40 @@
+		HP IPAQ H1940
+		=============
+
+http://www.handhelds.org/projects/h1940.html
+
+Introduction
+------------
+
+  The HP H1940 is a S3C2410 based handheld device, with
+  bluetooth connectivity.
+
+
+Support
+-------
+
+  A variety of information is available
+
+  handhelds.org project page:
+
+    http://www.handhelds.org/projects/h1940.html
+
+  handhelds.org wiki page:
+
+    http://handhelds.org/moin/moin.cgi/HpIpaqH1940
+
+  Herbert Pötzl pages:
+
+    http://vserver.13thfloor.at/H1940/
+
+
+Maintainers
+-----------
+
+  This project is being maintained and developed by a variety
+  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+
+  Thanks to the many others who have also provided support.
+
+
+(c) 2005 Ben Dooks
\ No newline at end of file
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -7,8 +7,8 @@ Introduction
 ------------
 
   The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
-  by the 's3c2410' architecture of ARM Linux. Currently the S3C2410 is
-  the only supported CPU in this range.
+  by the 's3c2410' architecture of ARM Linux. Currently the S3C2410 and
+  the S3C2440 are supported CPUs.
 
 
 Configuration
@@ -36,6 +36,10 @@ Machines
 
     Samsung's own development board, geared for PDA work.
 
+  Samsung/Meritech SMDK2440
+
+    The S3C2440 compatible version of the SMDK2440
+
   Thorcom VR1000
 
     Custom embedded board
@@ -44,12 +48,41 @@ Machines
 
     Handheld (IPAQ), available in several varieties
 
-
   HP iPAQ rx3715
 
     S3C2440 based IPAQ, with a number of variations depending on
     features shipped.
 
+  Acer N30
+
+    A S3C2410 based PDA from Acer.  There is a Wiki page at
+    http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+
+
+Adding New Machines
+-------------------
+
+  The archicture has been designed to support as many machines as can
+  be configured for it in one kernel build, and any future additions
+  should keep this in mind before altering items outside of their own
+  machine files.
+
+  Machine definitions should be kept in linux/arch/arm/mach-s3c2410,
+  and there are a number of examples that can be looked at.
+
+  Read the kernel patch submission policies as well as the
+  Documentation/arm directory before submitting patches. The
+  ARM kernel series is managed by Russell King, and has a patch system
+  located at http://www.arm.linux.org.uk/developer/patches/
+  as well as mailing lists that can be found from the same site.
+
+  As a courtesy, please notify <ben-linux@fluff.org> of any new
+  machines or other modifications.
+
+  Any large scale modifications, or new drivers should be discussed
+  on the ARM kernel mailing list (linux-arm-kernel) before being
+  attempted.
+
 
 NAND
 ----
@@ -98,6 +131,9 @@ Port Contributors
   Klaus Fetscher
   Dimitry Andric
   Shannon Holland
+  Guillaume Gourat (NexVision)
+  Christer Weinigel (wingel) (Acer N30)
+  Lucas Correia Villa Real (S3C2400 port)
 
 
 Document Changes
@@ -108,6 +144,11 @@ Document Changes
   25 Oct 2004 - BJD - Added Dimitry Andric to list of contributors
   25 Oct 2004 - BJD - Updated the MTD from the 2.6.9 merge
   21 Jan 2005 - BJD - Added rx3715, added Shannon to contributors
+  10 Feb 2005 - BJD - Added Guillaume Gourat to contributors
+  02 Mar 2005 - BJD - Added SMDK2440 to list of machines
+  06 Mar 2005 - BJD - Added Christer Weinigel
+  08 Mar 2005 - BJD - Added LCVR to list of people, updated introduction
+  08 Mar 2005 - BJD - Added section on adding machines
 
 Document Author
 ---------------
diff --git a/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt b/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt
@@ -0,0 +1,56 @@
+		Samsung/Meritech SMDK2440
+		=========================
+
+Introduction
+------------
+
+  The SMDK2440 is a two part evaluation board for the Samsung S3C2440
+  processor. It includes support for LCD, SmartMedia, Audio, SD and
+  10MBit Ethernet, and expansion headers for various signals, including
+  the camera and unused GPIO.
+
+
+Configuration
+-------------
+
+  To set the default configuration, use `make smdk2440_defconfig` which
+  will configure the common features of this board, or use
+  `make s3c2410_config` to include support for all s3c2410/s3c2440 machines
+
+
+Support
+-------
+
+  Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which
+  includes linux based USB download tools.
+
+  Some of the h1940 patches that can be found from the H1940 project
+  site at http://www.handhelds.org/projects/h1940.html can also be
+  applied to this board.
+
+
+Peripherals
+-----------
+
+  There is no current support for any of the extra peripherals on the
+  base-board itself.
+
+
+MTD
+---
+
+  The NAND flash should be supported by the in kernel MTD NAND support,
+  NOR flash will be added later.
+
+
+Maintainers
+-----------
+
+  This board is being maintained by Ben Dooks, for more info, see
+  http://www.fluff.org/ben/smdk2440/
+
+  Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440,
+  and to Simtec Electronics for allowing me time to work on this.
+
+
+(c) 2004 Ben Dooks
\ No newline at end of file
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -142,6 +142,11 @@ changes occur:
 	The ia64 sn2 platform is one example of a platform
 	that uses this interface.
 
+8) void lazy_mmu_prot_update(pte_t pte)
+	This interface is called whenever the protection on
+	any user PTEs change.  This interface provides a notification
+	to architecture specific code to take appropiate action.
+
 
 Next, we have the cache flushing interfaces.  In general, when Linux
 is changing an existing virtual-->physical mapping to a new value,
@@ -155,7 +160,7 @@ the sequence will be in one of the follo
 	   change_range_of_page_tables(mm, start, end);
 	   flush_tlb_range(vma, start, end);
 
-	3) flush_cache_page(vma, addr);
+	3) flush_cache_page(vma, addr, pfn);
 	   set_pte(pte_pointer, new_pte_val);
 	   flush_tlb_page(vma, addr);
 
@@ -203,7 +208,7 @@ Here are the routines, one by one:
 	call flush_cache_page (see below) for each entry which may be
 	modified.
 
-3) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+3) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
 
 	This time we need to remove a PAGE_SIZE sized range
 	from the cache.  The 'vma' is the backing structure used by
@@ -213,8 +218,14 @@ Here are the routines, one by one:
 	executable (and thus could be in the 'instruction cache' in
 	"Harvard" type cache layouts).
 
+	The 'pfn' indicates the physical page frame (shift this value
+	left by PAGE_SHIFT to get the physical address) that 'addr'
+	translates to.  It is this mapping which should be removed from
+	the cache.
+
 	After running, there will be no entries in the cache for
-	'vma->vm_mm' for virtual address 'addr'.
+	'vma->vm_mm' for virtual address 'addr' which translates
+	to 'pfn'.
 
 	This is used primarily during fault processing.
 
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -15,6 +15,8 @@ This driver is known to work with the fo
 	* SA 6400 U320 Expansion Module
 	* SA 6i
 	* SA P600
+	* SA P800
+	* SA E400
 
 If nodes are not already created in the /dev/cciss directory, run as root:
 
diff --git a/Documentation/cdrom/mcd b/Documentation/cdrom/mcd
deleted file mode 100644
--- a/Documentation/cdrom/mcd
+++ /dev/null
@@ -1,4 +0,0 @@
-This driver does not support XA or MultiSession CDs (PhotoCDs). Use the
-experimental driver mcdx.c for that.
-
-You can use mcd for one interface, and mcdx for another.
diff --git a/Documentation/cdrom/mcdx b/Documentation/cdrom/mcdx
--- a/Documentation/cdrom/mcdx
+++ b/Documentation/cdrom/mcdx
@@ -1,16 +1,3 @@
-This is a first attempt to create an `improved' driver for the Mitsumi drives.
-It is able to "live together" with mcd.c, if you have at least two Mitsumi
-drives: each driver can use its own drive.
-
-To allow this "coexistence" as long as mcdx.c is not a superset of mcd.c,
-this driver has to use its own device files. We use MAJOR 20 for it. So,
-you have to do
-
- # mknod /dev/mcdx0 b 20 0
- # mknod /dev/mcdx1 b 20 1
-
-and so on, one entry for each drive to support, once.
-
 If you are using the driver as a module, you can specify your ports and IRQs
 like
 
@@ -25,9 +12,7 @@ This driver:
         ordinary CDs;
     o   supports up to 5 drives (of course, you'll need free 
         IRQs, i/o ports and slots);
-    o   uses much less kernel memory than the standard mcd driver
-        (no extra driver internal buffers!).
-    o   plays audio (like the `old' driver, I hope)
+    o   plays audio
 
 This version doesn't support yet:
 
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
--- a/Documentation/cdrom/packet-writing.txt
+++ b/Documentation/cdrom/packet-writing.txt
@@ -62,6 +62,14 @@ generates aligned writes.
 	# mount /dev/pktcdvd/dev_name /cdrom -t udf -o rw,noatime
 
 
+Packet writing for DVD-RAM media
+--------------------------------
+
+DVD-RAM discs are random writable, so using the pktcdvd driver is not
+necessary. However, using the pktcdvd driver can improve performance
+in the same way it does for DVD+RW media.
+
+
 Notes
 -----
 
diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/cpu-freq/cpufreq-stats.txt
@@ -0,0 +1,128 @@
+
+     CPU frequency and voltage scaling statictics in the Linux(TM) kernel
+
+
+             L i n u x    c p u f r e q - s t a t s   d r i v e r
+
+                       - information for users -
+
+
+             Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+Contents
+1. Introduction
+2. Statistics Provided (with example)
+3. Configuring cpufreq-stats
+
+
+1. Introduction
+
+cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
+This statistics is provided in /sysfs as a bunch of read_only interfaces. This
+interface (when configured) will appear in a seperate directory under cpufreq
+in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
+Various statistics will form read_only files under this directory.
+
+This driver is designed to be independent of any particular cpufreq_driver
+that may be running on your CPU. So, it will work with any cpufreq_driver.
+
+
+2. Statistics Provided (with example)
+
+cpufreq stats provides following statistics (explained in detail below).
+-  time_in_state
+-  total_trans
+-  trans_table
+
+All the statistics will be from the time the stats driver has been inserted 
+to the time when a read of a particular statistic is done. Obviously, stats 
+driver will not have any information about the the frequcny transitions before
+the stats driver insertion.
+
+--------------------------------------------------------------------------------
+<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
+total 0
+drwxr-xr-x  2 root root    0 May 14 16:06 .
+drwxr-xr-x  3 root root    0 May 14 15:58 ..
+-r--r--r--  1 root root 4096 May 14 16:06 time_in_state
+-r--r--r--  1 root root 4096 May 14 16:06 total_trans
+-r--r--r--  1 root root 4096 May 14 16:06 trans_table
+--------------------------------------------------------------------------------
+
+-  time_in_state
+This gives the amount of time spent in each of the frequencies supported by
+this CPU. The cat output will have "<frequency> <time>" pair in each line, which
+will mean this CPU spent <time> usertime units of time at <frequency>. Output
+will have one line for each of the supported freuencies. usertime units here 
+is 10mS (similar to other time exported in /proc).
+
+--------------------------------------------------------------------------------
+<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state 
+3600000 2089
+3400000 136
+3200000 34
+3000000 67
+2800000 172488
+--------------------------------------------------------------------------------
+
+
+-  total_trans
+This gives the total number of frequency transitions on this CPU. The cat 
+output will have a single count which is the total number of frequency
+transitions.
+
+--------------------------------------------------------------------------------
+<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
+20
+--------------------------------------------------------------------------------
+
+-  trans_table
+This will give a fine grained information about all the CPU frequency
+transitions. The cat output here is a two dimensional matrix, where an entry
+<i,j> (row i, column j) represents the count of number of transitions from 
+Freq_i to Freq_j. Freq_i is in descending order with increasing rows and 
+Freq_j is in descending order with increasing columns. The output here also 
+contains the actual freq values for each row and column for better readability.
+
+--------------------------------------------------------------------------------
+<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
+   From  :    To
+         :   3600000   3400000   3200000   3000000   2800000 
+  3600000:         0         5         0         0         0 
+  3400000:         4         0         2         0         0 
+  3200000:         0         1         0         2         0 
+  3000000:         0         0         1         0         3 
+  2800000:         0         0         0         2         0 
+--------------------------------------------------------------------------------
+
+
+3. Configuring cpufreq-stats
+
+To configure cpufreq-stats in your kernel
+Config Main Menu
+	Power management options (ACPI, APM)  --->
+		CPU Frequency scaling  --->
+			[*] CPU Frequency scaling
+			<*>   CPU frequency translation statistics 
+			[*]     CPU frequency translation statistics details
+
+
+"CPU Frequency scaling" (CONFIG_CPU_FREQ) should be enabled to configure
+cpufreq-stats.
+
+"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT) provides the
+basic statistics which includes time_in_state and total_trans.
+
+"CPU frequency translation statistics details" (CONFIG_CPU_FREQ_STAT_DETAILS)
+provides fine grained cpufreq stats by trans_table. The reason for having a
+seperate config option for trans_table is:
+- trans_table goes against the traditional /sysfs rule of one value per
+  interface. It provides a whole bunch of value in a 2 dimensional matrix
+  form.
+
+Once these two options are enabled and your CPU supports cpufrequency, you
+will be able to see the CPU frequency statistics in /sysfs.
+
+
+
+
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/cpusets.txt
@@ -0,0 +1,414 @@
+				CPUSETS
+				-------
+
+Copyright (C) 2004 BULL SA.
+Written by Simon.Derr@bull.net
+
+Portions Copyright (c) 2004 Silicon Graphics, Inc.
+Modified by Paul Jackson <pj@sgi.com>
+
+CONTENTS:
+=========
+
+1. Cpusets
+  1.1 What are cpusets ?
+  1.2 Why are cpusets needed ?
+  1.3 How are cpusets implemented ?
+  1.4 How do I use cpusets ?
+2. Usage Examples and Syntax
+  2.1 Basic Usage
+  2.2 Adding/removing cpus
+  2.3 Setting flags
+  2.4 Attaching processes
+3. Questions
+4. Contact
+
+1. Cpusets
+==========
+
+1.1 What are cpusets ?
+----------------------
+
+Cpusets provide a mechanism for assigning a set of CPUs and Memory
+Nodes to a set of tasks.
+
+Cpusets constrain the CPU and Memory placement of tasks to only
+the resources within a tasks current cpuset.  They form a nested
+hierarchy visible in a virtual file system.  These are the essential
+hooks, beyond what is already present, required to manage dynamic
+job placement on large systems.
+
+Each task has a pointer to a cpuset.  Multiple tasks may reference
+the same cpuset.  Requests by a task, using the sched_setaffinity(2)
+system call to include CPUs in its CPU affinity mask, and using the
+mbind(2) and set_mempolicy(2) system calls to include Memory Nodes
+in its memory policy, are both filtered through that tasks cpuset,
+filtering out any CPUs or Memory Nodes not in that cpuset.  The
+scheduler will not schedule a task on a CPU that is not allowed in
+its cpus_allowed vector, and the kernel page allocator will not
+allocate a page on a node that is not allowed in the requesting tasks
+mems_allowed vector.
+
+If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct
+ancestor or descendent, may share any of the same CPUs or Memory Nodes.
+
+User level code may create and destroy cpusets by name in the cpuset
+virtual file system, manage the attributes and permissions of these
+cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
+specify and query to which cpuset a task is assigned, and list the
+task pids assigned to a cpuset.
+
+
+1.2 Why are cpusets needed ?
+----------------------------
+
+The management of large computer systems, with many processors (CPUs),
+complex memory cache hierarchies and multiple Memory Nodes having
+non-uniform access times (NUMA) presents additional challenges for
+the efficient scheduling and memory placement of processes.
+
+Frequently more modest sized systems can be operated with adequate
+efficiency just by letting the operating system automatically share
+the available CPU and Memory resources amongst the requesting tasks.
+
+But larger systems, which benefit more from careful processor and
+memory placement to reduce memory access times and contention,
+and which typically represent a larger investment for the customer,
+can benefit from explictly placing jobs on properly sized subsets of
+the system.
+
+This can be especially valuable on:
+
+    * Web Servers running multiple instances of the same web application,
+    * Servers running different applications (for instance, a web server
+      and a database), or
+    * NUMA systems running large HPC applications with demanding
+      performance characteristics.
+
+These subsets, or "soft partitions" must be able to be dynamically
+adjusted, as the job mix changes, without impacting other concurrently
+executing jobs.
+
+The kernel cpuset patch provides the minimum essential kernel
+mechanisms required to efficiently implement such subsets.  It
+leverages existing CPU and Memory Placement facilities in the Linux
+kernel to avoid any additional impact on the critical scheduler or
+memory allocator code.
+
+
+1.3 How are cpusets implemented ?
+---------------------------------
+
+Cpusets provide a Linux kernel (2.6.7 and above) mechanism to constrain
+which CPUs and Memory Nodes are used by a process or set of processes.
+
+The Linux kernel already has a pair of mechanisms to specify on which
+CPUs a task may be scheduled (sched_setaffinity) and on which Memory
+Nodes it may obtain memory (mbind, set_mempolicy).
+
+Cpusets extends these two mechanisms as follows:
+
+ - Cpusets are sets of allowed CPUs and Memory Nodes, known to the
+   kernel.
+ - Each task in the system is attached to a cpuset, via a pointer
+   in the task structure to a reference counted cpuset structure.
+ - Calls to sched_setaffinity are filtered to just those CPUs
+   allowed in that tasks cpuset.
+ - Calls to mbind and set_mempolicy are filtered to just
+   those Memory Nodes allowed in that tasks cpuset.
+ - The root cpuset contains all the systems CPUs and Memory
+   Nodes.
+ - For any cpuset, one can define child cpusets containing a subset
+   of the parents CPU and Memory Node resources.
+ - The hierarchy of cpusets can be mounted at /dev/cpuset, for
+   browsing and manipulation from user space.
+ - A cpuset may be marked exclusive, which ensures that no other
+   cpuset (except direct ancestors and descendents) may contain
+   any overlapping CPUs or Memory Nodes.
+ - You can list all the tasks (by pid) attached to any cpuset.
+
+The implementation of cpusets requires a few, simple hooks
+into the rest of the kernel, none in performance critical paths:
+
+ - in main/init.c, to initialize the root cpuset at system boot.
+ - in fork and exit, to attach and detach a task from its cpuset.
+ - in sched_setaffinity, to mask the requested CPUs by what's
+   allowed in that tasks cpuset.
+ - in sched.c migrate_all_tasks(), to keep migrating tasks within
+   the CPUs allowed by their cpuset, if possible.
+ - in the mbind and set_mempolicy system calls, to mask the requested
+   Memory Nodes by what's allowed in that tasks cpuset.
+ - in page_alloc, to restrict memory to allowed nodes.
+ - in vmscan.c, to restrict page recovery to the current cpuset.
+
+In addition a new file system, of type "cpuset" may be mounted,
+typically at /dev/cpuset, to enable browsing and modifying the cpusets
+presently known to the kernel.  No new system calls are added for
+cpusets - all support for querying and modifying cpusets is via
+this cpuset file system.
+
+Each task under /proc has an added file named 'cpuset', displaying
+the cpuset name, as the path relative to the root of the cpuset file
+system.
+
+The /proc/<pid>/status file for each task has two added lines,
+displaying the tasks cpus_allowed (on which CPUs it may be scheduled)
+and mems_allowed (on which Memory Nodes it may obtain memory),
+in the format seen in the following example:
+
+  Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
+  Mems_allowed:   ffffffff,ffffffff
+
+Each cpuset is represented by a directory in the cpuset file system
+containing the following files describing that cpuset:
+
+ - cpus: list of CPUs in that cpuset
+ - mems: list of Memory Nodes in that cpuset
+ - cpu_exclusive flag: is cpu placement exclusive?
+ - mem_exclusive flag: is memory placement exclusive?
+ - tasks: list of tasks (by pid) attached to that cpuset
+
+New cpusets are created using the mkdir system call or shell
+command.  The properties of a cpuset, such as its flags, allowed
+CPUs and Memory Nodes, and attached tasks, are modified by writing
+to the appropriate file in that cpusets directory, as listed above.
+
+The named hierarchical structure of nested cpusets allows partitioning
+a large system into nested, dynamically changeable, "soft-partitions".
+
+The attachment of each task, automatically inherited at fork by any
+children of that task, to a cpuset allows organizing the work load
+on a system into related sets of tasks such that each set is constrained
+to using the CPUs and Memory Nodes of a particular cpuset.  A task
+may be re-attached to any other cpuset, if allowed by the permissions
+on the necessary cpuset file system directories.
+
+Such management of a system "in the large" integrates smoothly with
+the detailed placement done on individual tasks and memory regions
+using the sched_setaffinity, mbind and set_mempolicy system calls.
+
+The following rules apply to each cpuset:
+
+ - Its CPUs and Memory Nodes must be a subset of its parents.
+ - It can only be marked exclusive if its parent is.
+ - If its cpu or memory is exclusive, they may not overlap any sibling.
+
+These rules, and the natural hierarchy of cpusets, enable efficient
+enforcement of the exclusive guarantee, without having to scan all
+cpusets every time any of them change to ensure nothing overlaps a
+exclusive cpuset.  Also, the use of a Linux virtual file system (vfs)
+to represent the cpuset hierarchy provides for a familiar permission
+and name space for cpusets, with a minimum of additional kernel code.
+
+1.4 How do I use cpusets ?
+--------------------------
+
+In order to minimize the impact of cpusets on critical kernel
+code, such as the scheduler, and due to the fact that the kernel
+does not support one task updating the memory placement of another
+task directly, the impact on a task of changing its cpuset CPU
+or Memory Node placement, or of changing to which cpuset a task
+is attached, is subtle.
+
+If a cpuset has its Memory Nodes modified, then for each task attached
+to that cpuset, the next time that the kernel attempts to allocate
+a page of memory for that task, the kernel will notice the change
+in the tasks cpuset, and update its per-task memory placement to
+remain within the new cpusets memory placement.  If the task was using
+mempolicy MPOL_BIND, and the nodes to which it was bound overlap with
+its new cpuset, then the task will continue to use whatever subset
+of MPOL_BIND nodes are still allowed in the new cpuset.  If the task
+was using MPOL_BIND and now none of its MPOL_BIND nodes are allowed
+in the new cpuset, then the task will be essentially treated as if it
+was MPOL_BIND bound to the new cpuset (even though its numa placement,
+as queried by get_mempolicy(), doesn't change).  If a task is moved
+from one cpuset to another, then the kernel will adjust the tasks
+memory placement, as above, the next time that the kernel attempts
+to allocate a page of memory for that task.
+
+If a cpuset has its CPUs modified, then each task using that
+cpuset does _not_ change its behavior automatically.  In order to
+minimize the impact on the critical scheduling code in the kernel,
+tasks will continue to use their prior CPU placement until they
+are rebound to their cpuset, by rewriting their pid to the 'tasks'
+file of their cpuset.  If a task had been bound to some subset of its
+cpuset using the sched_setaffinity() call, and if any of that subset
+is still allowed in its new cpuset settings, then the task will be
+restricted to the intersection of the CPUs it was allowed on before,
+and its new cpuset CPU placement.  If, on the other hand, there is
+no overlap between a tasks prior placement and its new cpuset CPU
+placement, then the task will be allowed to run on any CPU allowed
+in its new cpuset.  If a task is moved from one cpuset to another,
+its CPU placement is updated in the same way as if the tasks pid is
+rewritten to the 'tasks' file of its current cpuset.
+
+In summary, the memory placement of a task whose cpuset is changed is
+updated by the kernel, on the next allocation of a page for that task,
+but the processor placement is not updated, until that tasks pid is
+rewritten to the 'tasks' file of its cpuset.  This is done to avoid
+impacting the scheduler code in the kernel with a check for changes
+in a tasks processor placement.
+
+There is an exception to the above.  If hotplug funtionality is used
+to remove all the CPUs that are currently assigned to a cpuset,
+then the kernel will automatically update the cpus_allowed of all
+tasks attached to CPUs in that cpuset to allow all CPUs.  When memory
+hotplug functionality for removing Memory Nodes is available, a
+similar exception is expected to apply there as well.  In general,
+the kernel prefers to violate cpuset placement, over starving a task
+that has had all its allowed CPUs or Memory Nodes taken offline.  User
+code should reconfigure cpusets to only refer to online CPUs and Memory
+Nodes when using hotplug to add or remove such resources.
+
+There is a second exception to the above.  GFP_ATOMIC requests are
+kernel internal allocations that must be satisfied, immediately.
+The kernel may drop some request, in rare cases even panic, if a
+GFP_ATOMIC alloc fails.  If the request cannot be satisfied within
+the current tasks cpuset, then we relax the cpuset, and look for
+memory anywhere we can find it.  It's better to violate the cpuset
+than stress the kernel.
+
+To start a new job that is to be contained within a cpuset, the steps are:
+
+ 1) mkdir /dev/cpuset
+ 2) mount -t cpuset none /dev/cpuset
+ 3) Create the new cpuset by doing mkdir's and write's (or echo's) in
+    the /dev/cpuset virtual file system.
+ 4) Start a task that will be the "founding father" of the new job.
+ 5) Attach that task to the new cpuset by writing its pid to the
+    /dev/cpuset tasks file for that cpuset.
+ 6) fork, exec or clone the job tasks from this founding father task.
+
+For example, the following sequence of commands will setup a cpuset
+named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
+and then start a subshell 'sh' in that cpuset:
+
+  mount -t cpuset none /dev/cpuset
+  cd /dev/cpuset
+  mkdir Charlie
+  cd Charlie
+  /bin/echo 2-3 > cpus
+  /bin/echo 1 > mems
+  /bin/echo $$ > tasks
+  sh
+  # The subshell 'sh' is now running in cpuset Charlie
+  # The next line should display '/Charlie'
+  cat /proc/self/cpuset
+
+In the case that a change of cpuset includes wanting to move already
+allocated memory pages, consider further the work of IWAMOTO
+Toshihiro <iwamoto@valinux.co.jp> for page remapping and memory
+hotremoval, which can be found at:
+
+  http://people.valinux.co.jp/~iwamoto/mh.html
+
+The integration of cpusets with such memory migration is not yet
+available.
+
+In the future, a C library interface to cpusets will likely be
+available.  For now, the only way to query or modify cpusets is
+via the cpuset file system, using the various cd, mkdir, echo, cat,
+rmdir commands from the shell, or their equivalent from C.
+
+The sched_setaffinity calls can also be done at the shell prompt using
+SGI's runon or Robert Love's taskset.  The mbind and set_mempolicy
+calls can be done at the shell prompt using the numactl command
+(part of Andi Kleen's numa package).
+
+2. Usage Examples and Syntax
+============================
+
+2.1 Basic Usage
+---------------
+
+Creating, modifying, using the cpusets can be done through the cpuset
+virtual filesystem.
+
+To mount it, type:
+# mount -t cpuset none /dev/cpuset
+
+Then under /dev/cpuset you can find a tree that corresponds to the
+tree of the cpusets in the system. For instance, /dev/cpuset
+is the cpuset that holds the whole system.
+
+If you want to create a new cpuset under /dev/cpuset:
+# cd /dev/cpuset
+# mkdir my_cpuset
+
+Now you want to do something with this cpuset.
+# cd my_cpuset
+
+In this directory you can find several files:
+# ls
+cpus  cpu_exclusive  mems  mem_exclusive  tasks
+
+Reading them will give you information about the state of this cpuset:
+the CPUs and Memory Nodes it can use, the processes that are using
+it, its properties.  By writing to these files you can manipulate
+the cpuset.
+
+Set some flags:
+# /bin/echo 1 > cpu_exclusive
+
+Add some cpus:
+# /bin/echo 0-7 > cpus
+
+Now attach your shell to this cpuset:
+# /bin/echo $$ > tasks
+
+You can also create cpusets inside your cpuset by using mkdir in this
+directory.
+# mkdir my_sub_cs
+
+To remove a cpuset, just use rmdir:
+# rmdir my_sub_cs
+This will fail if the cpuset is in use (has cpusets inside, or has
+processes attached).
+
+2.2 Adding/removing cpus
+------------------------
+
+This is the syntax to use when writing in the cpus or mems files
+in cpuset directories:
+
+# /bin/echo 1-4 > cpus		-> set cpus list to cpus 1,2,3,4
+# /bin/echo 1,2,3,4 > cpus	-> set cpus list to cpus 1,2,3,4
+
+2.3 Setting flags
+-----------------
+
+The syntax is very simple:
+
+# /bin/echo 1 > cpu_exclusive 	-> set flag 'cpu_exclusive'
+# /bin/echo 0 > cpu_exclusive 	-> unset flag 'cpu_exclusive'
+
+2.4 Attaching processes
+-----------------------
+
+# /bin/echo PID > tasks
+
+Note that it is PID, not PIDs. You can only attach ONE task at a time.
+If you have several tasks to attach, you have to do it one after another:
+
+# /bin/echo PID1 > tasks
+# /bin/echo PID2 > tasks
+	...
+# /bin/echo PIDn > tasks
+
+
+3. Questions
+============
+
+Q: what's up with this '/bin/echo' ?
+A: bash's builtin 'echo' command does not check calls to write() against
+   errors. If you use it in the cpuset file system, you won't be
+   able to tell whether a command succeeded or failed.
+
+Q: When I attach processes, only the first of the line gets really attached !
+A: We can only return one error code per call to write(). So you should also
+   put only ONE pid.
+
+4. Contact
+==========
+
+Web: http://www.bullopensource.org/cpuset
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -234,6 +234,9 @@ Whirlpool algorithm contributors:
 Anubis algorithm contributors:
   Aaron Grothe
 
+Tiger algorithm contributors:
+  Aaron Grothe
+
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
 Please send any credits updates or corrections to:
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -2754,6 +2754,8 @@ Your cooperation is appreciated.
 		 50 = /dev/ttyIOC40		Altix serial card
 		    ...
 		 81 = /dev/ttyIOC431		Altix serial card
+		 82 = /dev/ttyVR0               NEC VR4100 series SIU
+		 83 = /dev/ttyVR1               NEC VR4100 series DSIU
 
 205 char	Low-density serial ports (alternate device)
 		  0 = /dev/culu0		Callout device for ttyLU0
@@ -2788,6 +2790,8 @@ Your cooperation is appreciated.
 		 50 = /dev/cuioc40		Callout device for ttyIOC40
 		    ...
 		 81 = /dev/cuioc431		Callout device for ttyIOC431
+		 82 = /dev/cuvr0                Callout device for ttyVR0
+		 83 = /dev/cuvr1                Callout device for ttyVR1
 
 
 206 char	OnStream SC-x0 tape devices
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
new file mode 100644
--- /dev/null
+++ b/Documentation/dontdiff
@@ -0,0 +1,140 @@
+*.a
+*.aux
+*.bin
+*.cpio
+*.css
+*.dvi
+*.eps
+*.gif
+*.grep
+*.grp
+*.gz
+*.html
+*.jpeg
+*.ko
+*.log
+*.lst
+*.mod.c
+*.o
+*.orig
+*.out
+*.pdf
+*.png
+*.ps
+*.rej
+*.s
+*.sgml
+*.so
+*.tex
+*.ver
+*.xml
+*_MODULES
+*_vga16.c
+*cscope*
+*~
+.*
+.cscope
+53c700_d.h
+53c8xx_d.h*
+BitKeeper
+COPYING
+CREDITS
+CVS
+ChangeSet
+Kerntypes
+MODS.txt
+Module.symvers
+PENDING
+SCCS
+System.map*
+TAGS
+aic7*reg.h*
+aic7*reg_print.c*
+aic7*seq.h*
+aicasm
+aicdb.h*
+asm
+asm_offsets.*
+autoconf.h*
+bbootsect
+bin2c
+binkernel.spec
+bootsect
+bsetup
+btfixupprep
+build
+bvmlinux
+bzImage*
+classlist.h*
+comp*.log
+compile.h*
+config
+config-*
+config_data.h*
+conmakehash
+consolemap_deftbl.c*
+crc32table.h*
+cscope.*
+defkeymap.c*
+devlist.h*
+docproc
+dummy_sym.c*
+elfconfig.h*
+filelist
+fixdep
+fore200e_mkfirm
+fore200e_pca_fw.c*
+gen-devlist
+gen-kdb_cmds.c*
+gen_crc32table
+gen_init_cpio
+genksyms
+gentbl
+ikconfig.h*
+initramfs_list
+kallsyms
+kconfig
+kconfig.tk
+keywords.c*
+ksym.c*
+ksym.h*
+lex.c*
+logo_*.c
+logo_*_clut224.c
+logo_*_mono.c
+lxdialog
+make_times_h
+map
+maui_boot.h
+mk_elfconfig
+mkdep
+mktables
+modpost
+modversions.h*
+offsets.h
+oui.c*
+parse.c*
+parse.h*
+pnmtologo
+ppc_defs.h*
+promcon_tbl.c*
+pss_boot.h
+raid6altivec*.c
+raid6int*.c
+raid6tables.c
+setup
+sim710_d.h*
+sm_tbl*
+split-include
+tags
+times.h*
+tkparse
+trix_boot.h
+version.h*
+vmlinux
+vmlinux-*
+vmlinux.lds
+vsyscall.lds
+wanxlfw.inc
+uImage
+zImage
diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
--- a/Documentation/driver-model/bus.txt
+++ b/Documentation/driver-model/bus.txt
@@ -18,7 +18,7 @@ struct bus_type {
 	int		(*match)(struct device * dev, struct device_driver * drv);
 	int		(*hotplug) (struct device *dev, char **envp, 
 				    int num_envp, char *buffer, int buffer_size);
-	int		(*suspend)(struct device * dev, u32 state);
+	int		(*suspend)(struct device * dev, pm_message_t state);
 	int		(*resume)(struct device * dev);
 };
 
diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
--- a/Documentation/driver-model/driver.txt
+++ b/Documentation/driver-model/driver.txt
@@ -16,7 +16,7 @@ struct device_driver {
         int     (*probe)        (struct device * dev);
         int     (*remove)       (struct device * dev);
 
-        int     (*suspend)      (struct device * dev, u32 state, u32 level);
+        int     (*suspend)      (struct device * dev, pm_message_t state, u32 level);
         int     (*resume)       (struct device * dev, u32 level);
 
         void    (*release)      (struct device_driver * drv);
@@ -195,7 +195,7 @@ device; i.e. anything in the device's dr
 If the device is still present, it should quiesce the device and place
 it into a supported low-power state.
 
-	int	(*suspend)	(struct device * dev, u32 state, u32 level);
+	int	(*suspend)	(struct device * dev, pm_message_t state, u32 level);
 
 suspend is called to put the device in a low power state. There are
 several stages to successfully suspending a device, which is denoted in
diff --git a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb
--- a/Documentation/dvb/README.dibusb
+++ b/Documentation/dvb/README.dibusb
@@ -1,7 +1,7 @@
-Documentation for dib3000mb frontend driver and dibusb device driver
+Documentation for dib3000* frontend drivers and dibusb device driver
 ====================================================================
 
-Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de),
+Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de),
 
 dibusb and dib3000mb/mc drivers based on GPL code, which has
 
@@ -46,7 +46,7 @@ Produced and reselled by KWorld:
 
 Others:
 -------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner) 
+- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
 	http://82.161.246.249/products-tvbox.html
 
 - Compro Videomate DVB-U2000 - DVB-T USB (2)
@@ -74,19 +74,27 @@ Supported devices USB2.0
 
 - Artec T1 USB TVBOX (FX2) (2)
 
+- Hauppauge WinTV NOVA-T USB2
+	http://www.hauppauge.com/
+
+- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
+
 - DiBcom USB2.0 DVB-T reference device (non-public)
 
 1) It is working almost.
-2) No test reports received yet. 
+2) No test reports received yet.
 
 
 0. NEWS:
-  2004-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
+  2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
+  2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
+  2005-01-31 - distorted streaming is finally gone for USB1.1 devices
+  2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
              - first almost working version for HanfTek UMT-010
-             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek
-  2004-01-10 - refactoring completed, now everything is very delightful
+             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
+  2005-01-10 - refactoring completed, now everything is very delightful
              - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
-               Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich. 
+               Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
   2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
   2004-12-26 - refactored the dibusb-driver, splitted into separate files
              - i2c-probing enabled
@@ -106,7 +114,7 @@ Supported devices USB2.0
   2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
   2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
                to Amaury Demol for reporting
-             - changed usb TS transfer method (several urbs, stopping transfer 
+             - changed usb TS transfer method (several urbs, stopping transfer
                before setting a new pid)
   2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
                to Christian Motschke for reporting
@@ -149,13 +157,20 @@ You can either use "get_dvb_firmware dib
 can get it directly via
 
 for USB1.1 (AN2135)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw
 
 for USB1.1 (AN2235) (a few Artec T1 devices)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-an2235-1.fw?rev=1.1&content-type=text/plain
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
+
+for USB2.0 (FX2) Hauppauge, DiBcom
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-6.0.0.5.fw
+
+for USB2.0 ADSTech/Kworld USB2.0
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-adstech-usb2-1.fw
+
+for USB2.0 HanfTek
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
 
-for USB2.0 (FX2)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-6.0.0.5.fw?rev=1.1&content-type=text/plain
 
 1.2. Compiling
 
@@ -191,13 +206,13 @@ turned on.
 
 At this point you should be able to start a dvb-capable application. For myself
 I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
-in vdr (at least the USB2.0 one) is working. 
+in vdr is working now also.
 
 2. Known problems and bugs
 
-- none this time
+- Don't remove the USB device while running an DVB application, your system will die.
 
-2.1. Adding support for devices 
+2.1. Adding support for devices
 
 It is not possible to determine the range of devices based on the DiBcom
 reference designs. This is because the reference design of DiBcom can be sold
@@ -213,56 +228,51 @@ of the device. I will add it to this lis
 others.
 
 If you are familar with C you can also add the VID and PID of the device to
-the dvb-dibusb.h-file and create a patch and send it over to me or to 
+the dvb-dibusb-core.c-file and create a patch and send it over to me or to
 the linux-dvb mailing list, _after_ you have tried compiling and modprobing
 it.
 
 2.2. USB1.1 Bandwidth limitation
 
-Most of the current supported devices are USB1.1 and thus they have a
+Most of the currently supported devices are USB1.1 and thus they have a
 maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
 This is not enough for receiving the complete transport stream of a
 DVB-T channel (which can be about 16 MBit/s). Normally this is not a
 problem, if you only want to watch TV (this does not apply for HDTV),
-but watching a channel while recording another channel on the same 
-frequency simply does not work. This applies to all USB1.1 DVB-T 
-devices, not only dibusb)
-
-A special problem of the dibusb for the USB1.1 is, that the USB control
-IC has a problem with write accesses while having MPEG2-streaming
-enabled. When you set another pid while receiving MPEG2-TS it happens, that
-the stream is disturbed and probably data is lost (results in distortions of
-the video or strange beeps within the audio stream). DiBcom is preparing a
-firmware especially for Linux which perhaps solves the problem.
-
-Especially VDR users are victoms of this bug. VDR frequently requests new PIDs
-due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
-these features is maybe a solution. Additionally this behaviour of VDR exceeds
-the USB1.1 bandwidth.
-
-Update:
-For the USB1.1 and VDR some work has been done (patches and comments are still 
-very welcome). Maybe the problem is solved in the meantime because I now use
-the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
+but watching a channel while recording another channel on the same
+frequency simply does not work very well. This applies to all USB1.1
+DVB-T devices, not just dibusb)
+
+Update: For the USB1.1 and VDR some work has been done (patches and comments
+are still very welcome). Maybe the problem is solved in the meantime because I
+now use the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
 linux-dvb software filter is able to get the best of the garbled TS.
 
+The bug, where the TS is distorted by a heavy usage of the device is gone
+definitely. All dibusb-devices I was using (Twinhan, Kworld, DiBcom) are
+working like charm now with VDR. Sometimes I even was able to record a channel
+and watch another one.
+
 2.3. Comments
 
-Patches, comments and suggestions are very very welcome
+Patches, comments and suggestions are very very welcome.
 
 3. Acknowledgements
 	Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
-    providing specs, code and help, on which the dvb-dibusb, dib3000mb and 
+    providing specs, code and help, on which the dvb-dibusb, dib3000mb and
     dib3000mc are based.
 
    David Matthews for identifying a new device type (Artec T1 with AN2235)
     and for extending dibusb with remote control event handling. Thank you.
 
    Alex Woods for frequently answering question about usb and dvb
-    stuff, a big thank you
+    stuff, a big thank you.
 
    Bernd Wagner for helping with huge bug reports and discussions.
 
+   Gunnar Wittich and Joachim von Caron for their trust for giving me
+    root-shells on their machines to implement support for new devices.
+
    Some guys on the linux-dvb mailing list for encouraging me
 
    Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop
new file mode 100644
--- /dev/null
+++ b/Documentation/dvb/README.flexcop
@@ -0,0 +1,205 @@
+This README escorted the skystar2-driver rewriting procedure. It describes the
+state of the new flexcop-driver set and some internals are written down here
+too.
+
+This document hopefully describes things about the flexcop and its
+device-offsprings. Goal was to write an easy-to-write and easy-to-read set of
+drivers based on the skystar2.c and other information.
+
+Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been
+touched and rewritten.
+
+History & News
+==============
+  2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana)
+
+
+
+
+General coding processing
+=========================
+
+We should proceed as follows (as long as no one complains):
+
+0) Think before start writing code!
+
+1) rewriting the skystar2.c with the help of the flexcop register descriptions
+and splitting up the files to a pci-bus-part and a flexcop-part.
+The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the
+device-specific part and b2c2-flexcop.ko for the common flexcop-functions.
+
+2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c
+and other pci drivers)
+
+3) make some beautification (see 'Improvements when rewriting (refactoring) is
+done')
+
+4) Testing the new driver and maybe substitute the skystar2.c with it, to reach
+a wider tester audience.
+
+5) creating an usb-bus-part using the already written flexcop code for the pci
+card.
+
+Idea: create a kernel-object for the flexcop and export all important
+functions. This option saves kernel-memory, but maybe a lot of functions have
+to be exported to kernel namespace.
+
+
+Current situation
+=================
+
+0) Done :)
+1) Done (some minor issues left)
+2) Done
+3) Not ready yet, more information is necessary
+4) next to be done (see the table below)
+5) USB driver is working (yes, there are some minor issues)
+
+What seems to be ready?
+-----------------------
+
+1) Rewriting
+1a) i2c is cut off from the flexcop-pci.c and seems to work
+1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1e) eeprom (reading MAC address)
+1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me))
+1f) misc. register accesses for reading parameters (e.g. resetting, revision)
+1g) pid/mac filter (flexcop-hw-filter.c)
+1i) dvb-stuff initialization in flexcop.c (done)
+1h) dma stuff (now just using the size-irq, instead of all-together, to be done)
+1j) remove flexcop initialization from flexcop-pci.c completely (done)
+1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO')
+1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from
+non-static where possible, moved code to proper places)
+
+2) Search for errors in the leftover of flexcop-pci.c (partially done)
+5a) add MAC address reading
+5c) feeding of ISOC data to the software demux (format of the isochronous data
+and speed optimization, no real error) (thanks to Vadim Catana)
+
+What to do in the near future?
+--------------------------------------
+(no special order here)
+
+5) USB driver
+5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting)
+
+Testing changes
+---------------
+
+O             = item is working
+P             = item is partially working
+X             = item is not working
+N             = item does not apply here
+<empty field> = item need to be examined
+
+       | PCI                               | USB
+item   | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312
+-------+-------+---------+---------+-------+-------+---------+---------+-------
+1a)    | O     |         |         |       | N     | N       | N       | N
+1b)    | O     |         |         |       |       |         | O       |
+1c)    | N     | N       |         |       | N     | N       | O       |
+1d)    |                 O                 |                 O
+1e)    |                 O                 |                 O
+1f)    |                                   P
+1g)    |                                   O
+1h)    |                 P                 |
+1i)    |                 O                 |                 N
+1j)    |                 O                 |                 N
+1l)    |                 O                 |                 N
+2)     |                 O                 |                 N
+5a)    |                 N                 |                 O
+5b)*   |                 N                 |
+5c)    |                 N                 |                 O
+
+* - not done yet
+
+Known bugs and problems and TODO
+--------------------------------
+
+1g/h/l) when pid filtering is enabled on the pci card
+
+DMA usage currently:
+  The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first
+  address and triggers an IRQ when it's full and starts writing to the second
+  address. When the second address is full, the IRQ is triggered again, and
+  the flexcop writes to first address again, and so on.
+  The buffersize of each address is currently 640*188 bytes.
+
+  Problem is, when using hw-pid-filtering and doing some low-bandwidth
+  operation (like scanning) the buffers won't be filled enough to trigger
+  the IRQ. That's why:
+
+  When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ
+  is triggered.  Is the current write address of DMA1 different to the one
+  during the last IRQ, then the data is passed to the demuxer.
+
+  There is an additional DMA-IRQ-method: packet count IRQ. This isn't
+  implemented correctly yet.
+
+  The solution is to disable HW PID filtering, but I don't know how the DVB
+  API software demux behaves on slow systems with 45MBit/s TS.
+
+Solved bugs :)
+--------------
+1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't
+working)
+SOLUTION: also index 0 was affected, because net_translation is done for
+these indexes by default
+
+5b) isochronous transfer does only work in the first attempt (for the Sky2PC
+USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really
+woke up again (don't know if this need fixes, see
+flexcop-fe-tuner.c:flexcop_sleep)
+
+NEWS: when the driver is loaded and unloaded and loaded again (w/o doing
+anything in the while the driver is loaded the first time), no transfers take
+place anymore.
+
+Improvements when rewriting (refactoring) is done
+=================================================
+
+- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control
+  (enable sleeping for other demods than dvb-s)
+- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA)
+
+Debugging
+---------
+- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it
+  with this flexcop, this is important, because i2c is now using the
+  flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for
+  that, please tell us so).
+
+Everything which is identical in the following table, can be put into a common
+flexcop-module.
+
+                  PCI                  USB
+-------------------------------------------------------------------------------
+Different:
+Register access:  accessing IO memory  USB control message
+I2C bus:          I2C bus of the FC    USB control message
+Data transfer:    DMA                  isochronous transfer
+EEPROM transfer:  through i2c bus      not clear yet
+
+Identical:
+Streaming:                 accessing registers
+PID Filtering:             accessing registers
+Sram destinations:         accessing registers
+Tuner/Demod:                     I2C bus
+DVB-stuff:            can be written for common use
+
+Acknowledgements (just for the rewriting part)
+================
+
+Bjarne Steinsbo thought a lot in the first place of the pci part for this code
+sharing idea.
+
+Andreas Oberritter for providing a recent PCI initialization template
+(pluto2.c).
+
+Boleslaw Ciesielski for pointing out a problem with firmware loader.
+
+Vadim Catana for correcting the USB transfer.
+
+comments, critics and ideas to linux-dvb@linuxtv.org.
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -17,74 +17,53 @@ Because of this, you need to enable
 "Device drivers" => "Multimedia devices"
   => "Video For Linux" => "BT848 Video For Linux"
 
+Furthermore you need to enable
+"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+  => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+
 2) Loading Modules
 ==================
 
 In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us. Next you need the common dvb-bt8xx device driver
-and one frontend driver.
-
-The bttv driver will HANG YOUR SYSTEM IF YOU DO NOT SPECIFY THE CORRECT 
-CARD ID!
-
-(If you don't get your card running and you suspect that the card id you're
-using is wrong, have a look at "bttv-cards.c" for a list of possible card
-ids.)
-
-Pay attention to failures when you load the frontend drivers
-(e.g. dmesg, /var/log/messages).
+i2c communication for us, plus the common dvb-bt8xx device driver.
+The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
+TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
 
 3a) Nebula / Pinnacle PCTV
 --------------------------
 
-   $ modprobe bttv i2c_hw=1 card=0x68
-   $ modprobe dvb-bt8xx
-   
-For Nebula cards use the "nxt6000" frontend driver:
-   $ modprobe nxt6000
+   $ modprobe bttv (normally bttv is being loaded automatically by kmod)
+   $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
 
-For Pinnacle PCTV cards use the "cx24110" frontend driver:
-   $ modprobe cx24110
 
-3b) TwinHan
------------
+3b) TwinHan and Clones
+--------------------------
 
    $ modprobe bttv i2c_hw=1 card=0x71
    $ modprobe dvb-bt8xx
    $ modprobe dst
 
-The value 0x71 will override the PCI type detection for dvb-bt8xx, which 
-is necessary for TwinHan cards.#
+The value 0x71 will override the PCI type detection for dvb-bt8xx,
+which  is necessary for TwinHan cards.
 
-If you're having an older card (blue color circuit) and card=0x71 locks your
-machine, try using 0x68, too. If that does not work, ask on the DVB mailing list.
+If you're having an older card (blue color circuit) and card=0x71 locks
+your machine, try using 0x68, too. If that does not work, ask on the
+mailing list.
 
-The DST module takes a couple of useful parameters, in case the
-dst drivers fails to detect your type of card correctly.
+The DST module takes a couple of useful parameters.
 
-dst_type takes values 0 (satellite), 1 (terrestial TV), 2 (cable).
+verbose takes values 0 to 5. These values control the verbosity level.
 
-dst_type_flags takes bit combined values:
-1 = new tuner type packets. You can use this if your card is detected
-    and you have debug and you continually see the tuner packets not
-    working (make sure not a basic problem like dish alignment etc.)
+debug takes values 0 and 1. You can either disable or enable debugging.
 
-2 = TS 204. If your card tunes OK, but the picture is terrible, seemingly
-    breaking up in one half continually, and crc fails a lot, then
-    this is worth a try (or trying to turn off)
+dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
+0x20 means it has a Conditional Access slot.
 
-4 = has symdiv. Some cards, mostly without new tuner packets, require
-    a symbol division algorithm. Doesn't apply to terrestial TV.
-
-You can also specify a value to have the autodetected values turned off
-(e.g. 0). The autodected values are determined bythe cards 'response
+The autodected values are determined bythe cards 'response
 string' which you can see in your logs e.g.
 
-dst_check_ci: recognize DST-MOT
-
-or 
+dst_get_device_id: Recognise [DSTMCI]
 
-dst_check_ci: unable to recognize DSTXCI or STXCI
 
 --
-Authors: Richard Walker, Jamie Honan, Michael Hunold
+Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/dvb/ci.txt
@@ -0,0 +1,219 @@
+* For the user
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+NOTE: This document describes the usage of the high level CI API as
+in accordance to the Linux DVB API. This is a not a documentation for the,
+existing low level CI API.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To utilize the High Level CI capabilities,
+
+(1*) This point is valid only for the Twinhan/clones
+  For the Twinhan/Twinhan clones, the dst_ca module handles the CI
+  hardware handling.This module is loaded automatically if a CI
+  (Common Interface, that holds the CAM (Conditional Access Module)
+  is detected.
+
+(2) one requires a userspace application, ca_zap. This small userland
+  application is in charge of sending the descrambling related information
+  to the CAM.
+
+This application requires the following to function properly as of now.
+
+	(a) Tune to a valid channel, with szap.
+	  eg: $ szap -c channels.conf -r "TMC" -x
+
+	(b) a channels.conf containing a valid PMT PID
+
+	  eg: TMC:11996:h:0:27500:278:512:650:321
+
+	  here 278 is a valid PMT PID. the rest of the values are the
+	  same ones that szap uses.
+
+	(c) after running a szap, you have to run ca_zap, for the
+	  descrambler to function,
+
+	  eg: $ ca_zap patched_channels.conf "TMC"
+
+	  The patched means a patch to apply to scan, such that scan can
+	  generate a channels.conf_with pmt, which has this PMT PID info
+	  (NOTE: szap cannot use this channels.conf with the PMT_PID)
+
+
+	(d) Hopeflly Enjoy your favourite subscribed channel as you do with
+	  a FTA card.
+
+(3) Currently ca_zap, and dst_test, both are meant for demonstration
+  purposes only, they can become full fledged applications if necessary.
+
+
+* Cards that fall in this category
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+At present the cards that fall in this category are the Twinhan and it's
+clones, these cards are available as VVMER, Tomato, Hercules, Orange and
+so on.
+
+* CI modules that are supported
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The CI module support is largely dependant upon the firmware on the cards
+Some cards do support almost all of the available CI modules. There is
+nothing much that can be done in order to make additional CI modules
+working with these cards.
+
+Modules that have been tested by this driver at present are
+
+(1) Irdeto 1 and 2 from SCM
+(2) Viaccess from SCM
+(3) Dragoncam
+
+* The High level CI API
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* For the programmer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+With the High Level CI approach any new card with almost any random
+architecture can be implemented with this style, the definitions
+insidethe switch statement can be easily adapted for any card, thereby
+eliminating the need for any additional ioctls.
+
+The disadvantage is that the driver/hardware has to manage the rest. For
+the application programmer it would be as simple as sending/receiving an
+array to/from the CI ioctls as defined in the Linux DVB API. No changes
+have been made in the API to accomodate this feature.
+
+
+* Why the need for another CI interface ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This is one of the most commonly asked question. Well a nice question.
+Strictly speaking this is not a new interface.
+
+The CI interface is defined in the DVB API in ca.h as
+
+typedef struct ca_slot_info {
+	int num;               /* slot number */
+
+	int type;              /* CA interface this slot supports */
+#define CA_CI            1     /* CI high level interface */
+#define CA_CI_LINK       2     /* CI link layer level interface */
+#define CA_CI_PHYS       4     /* CI physical layer level interface */
+#define CA_DESCR         8     /* built-in descrambler */
+#define CA_SC          128     /* simple smart card interface */
+
+	unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
+
+
+
+This CI interface follows the CI high level interface, which is not
+implemented by most applications. Hence this area is revisited.
+
+This CI interface is quite different in the case that it tries to
+accomodate all other CI based devices, that fall into the other categories
+
+This means that this CI interface handles the EN50221 style tags in the
+Application layer only and no session management is taken care of by the
+application. The driver/hardware will take care of all that.
+
+This interface is purely an EN50221 interface exchanging APDU's. This
+means that no session management, link layer or a transport layer do
+exist in this case in the application to driver communication. It is
+as simple as that. The driver/hardware has to take care of that.
+
+
+With this High Level CI interface, the interface can be defined with the
+regular ioctls.
+
+All these ioctls are also valid for the High level CI interface
+
+#define CA_RESET          _IO('o', 128)
+#define CA_GET_CAP        _IOR('o', 129, ca_caps_t)
+#define CA_GET_SLOT_INFO  _IOR('o', 130, ca_slot_info_t)
+#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
+#define CA_GET_MSG        _IOR('o', 132, ca_msg_t)
+#define CA_SEND_MSG       _IOW('o', 133, ca_msg_t)
+#define CA_SET_DESCR      _IOW('o', 134, ca_descr_t)
+#define CA_SET_PID        _IOW('o', 135, ca_pid_t)
+
+
+On querying the device, the device yields information thus
+
+CA_GET_SLOT_INFO
+----------------------------
+Command = [info]
+APP: Number=[1]
+APP: Type=[1]
+APP: flags=[1]
+APP: CI High level interface
+APP: CA/CI Module Present
+
+CA_GET_CAP
+----------------------------
+Command = [caps]
+APP: Slots=[1]
+APP: Type=[1]
+APP: Descrambler keys=[16]
+APP: Type=[1]
+
+CA_SEND_MSG
+----------------------------
+Descriptors(Program Level)=[ 09 06 06 04 05 50 ff f1]
+Found CA descriptor @ program level
+
+(20) ES type=[2] ES pid=[201]  ES length =[0 (0x0)]
+(25) ES type=[4] ES pid=[301]  ES length =[0 (0x0)]
+ca_message length is 25 (0x19) bytes
+EN50221 CA MSG=[ 9f 80 32 19 03 01 2d d1 f0 08 01 09 06 06 04 05 50 ff f1 02 e0 c9 00 00 04 e1 2d 00 00]
+
+
+Not all ioctl's are implemented in the driver from the API, the other
+features of the hardware that cannot be implemented by the API are achieved
+using the CA_GET_MSG and CA_SEND_MSG ioctls. An EN50221 style wrapper is
+used to exchange the data to maintain compatibility with other hardware.
+
+
+/* a message to/from a CI-CAM */
+typedef struct ca_msg {
+	unsigned int index;
+	unsigned int type;
+	unsigned int length;
+	unsigned char msg[256];
+} ca_msg_t;
+
+
+The flow of data can be described thus,
+
+
+
+
+
+	App (User)
+	-----
+	parse
+	  |
+	  |
+	  v
+	en50221 APDU (package)
+   --------------------------------------
+   |	  |				| High Level CI driver
+   |	  |				|
+   |	  v				|
+   |	en50221 APDU (unpackage)	|
+   |	  |				|
+   |	  |				|
+   |	  v				|
+   |	sanity checks			|
+   |	  |				|
+   |	  |				|
+   |	  v				|
+   |	do (H/W dep)			|
+   --------------------------------------
+	  |    Hardware
+	  |
+	  v
+
+
+
+
+The High Level CI interface uses the EN50221 DVB standard, following a
+standard ensures futureproofness.
diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt
--- a/Documentation/dvb/contributors.txt
+++ b/Documentation/dvb/contributors.txt
@@ -72,5 +72,8 @@ Kenneth Aafløy <ke-aa@frisurf.no>
 Ernst Peinlich <e.peinlich@inode.at>
   for tuning/DiSEqC support for the DEC 3000-s
 
+Peter Beutner <p.beutner@gmx.net>
+  for the IR code for the ttusb-dec driver
+
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt
--- a/Documentation/dvb/faq.txt
+++ b/Documentation/dvb/faq.txt
@@ -35,7 +35,7 @@ Some very frequently asked questions abo
 	Note: Only very recent versions of Mplayer and xine can decode.
 	MPEG2 transport streams (TS) directly. Then, run
 	'[sct]zap channelname -r' in one xterm, and keep it running,
-	and start 'mplayer - < /dev/dvb/adapter0/dvr0' or 
+	and start 'mplayer - < /dev/dvb/adapter0/dvr0' or
 	'xine stdin://mpeg2 < /dev/dvb/adapter0/dvr0' in a second xterm.
 	That's all far from perfect, but it seems no one has written
 	a nice DVB application which includes a builtin software MPEG
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -22,14 +22,15 @@ use File::Temp qw/ tempdir /;
 use IO::Handle;
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
-		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002" );
+		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002",
+		"or51211", "or51132_qam", "or51132_vsb");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
 $cid = $ARGV[0];
 
 # Do it!
-for($i=0; $i < scalar(@components); $i++) {
+for ($i=0; $i < scalar(@components); $i++) {
     if ($cid eq $components[$i]) {
 	$outfile = eval($cid);
 	die $@ if $@;
@@ -79,8 +80,8 @@ sub sp887x {
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
     unshield("$tmpdir/$cabfile", $tmpdir);
-    verify("$tmpdir/sc_main.mc", $hash);
-    copy("$tmpdir/sc_main.mc", $outfile);
+    verify("$tmpdir/ZEnglish/sc_main.mc", $hash);
+    copy("$tmpdir/ZEnglish/sc_main.mc", $outfile);
 
     $outfile;
 }
@@ -106,7 +107,7 @@ sub tda10045 {
 sub tda10046 {
     my $sourcefile = "tt_budget_217g.zip";
     my $url = "http://www.technotrend.de/new/217g/$sourcefile";
-    my $hash = "a25b579e37109af60f4a36c37893957c";
+    my $hash = "6a7e1e2f2644b162ff0502367553c72d";
     my $outfile = "dvb-fe-tda10046.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
@@ -114,7 +115,7 @@ sub tda10046 {
 
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
-    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24479, "$tmpdir/fwtmp");
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24478, "$tmpdir/fwtmp");
     verify("$tmpdir/fwtmp", $hash);
     copy("$tmpdir/fwtmp", $outfile);
 
@@ -122,9 +123,9 @@ sub tda10046 {
 }
 
 sub av7110 {
-    my $sourcefile = "dvb-ttpci-01.fw-261c";
-    my $url = "http://www.linuxtv.org/download/dvb/firmware/$sourcefile";
-    my $hash = "7b263de6b0b92d2347319c65adc7d4fb";
+    my $sourcefile = "dvb-ttpci-01.fw-261d";
+    my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
+    my $hash = "603431b6259715a8e88f376a53b64e2f";
     my $outfile = "dvb-ttpci-01.fw";
 
     checkstandard();
@@ -222,7 +223,7 @@ sub vp7041 {
 }
 
 sub dibusb {
-	my $url = "http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain";
+	my $url = "http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw";
 	my $outfile = "dvb-dibusb-5.0.0.11.fw";
 	my $hash = "fa490295a527360ca16dcdf3224ca243";
 
@@ -251,6 +252,45 @@ sub nxt2002 {
     $outfile;
 }
 
+sub or51211 {
+    my $fwfile = "dvb-fe-or51211.fw";
+    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $hash = "d830949c771a289505bf9eafc225d491";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url);
+    verify($fwfile, $hash);
+
+    $fwfile;
+}
+
+sub or51132_qam {
+    my $fwfile = "dvb-fe-or51132-qam.fw";
+    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $hash = "7702e8938612de46ccadfe9b413cb3b5";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url);
+    verify($fwfile, $hash);
+
+    $fwfile;
+}
+
+sub or51132_vsb {
+    my $fwfile = "dvb-fe-or51132-vsb.fw";
+    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+    my $hash = "c16208e02f36fc439a557ad4c613364a";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url);
+    verify($fwfile, $hash);
+
+    $fwfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
@@ -292,7 +332,7 @@ sub unzip {
 sub unshield {
     my ($sourcefile, $todir) = @_;
 
-    system("unshield -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
+    system("unshield x -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
 }
 
 sub verify {
diff --git a/Documentation/dvb/readme.txt b/Documentation/dvb/readme.txt
--- a/Documentation/dvb/readme.txt
+++ b/Documentation/dvb/readme.txt
@@ -5,8 +5,9 @@ The main development site and CVS reposi
 drivers is http://linuxtv.org/.
 
 The developer mailing list linux-dvb is also hosted there,
-see http://linuxtv.org/mailinglists.xml. Please check
-the archive http://linuxtv.org/mailinglists/linux-dvb/
+see http://linuxtv.org/lists.php. Please check
+the archive http://linuxtv.org/pipermail/linux-dvb/
+and the Wiki http://linuxtv.org/wiki/
 before asking newbie questions on the list.
 
 API documentation, utilities and test/example programs
@@ -15,7 +16,7 @@ are available as part of the old driver 
 We plan to split this into separate packages, but it's not
 been done yet.
 
-http://linuxtv.org/download/dvb/
+http://linuxtv.org/downloads/
 
 What's inside this directory:
 
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -15,3 +15,71 @@ Why:	It has been unmaintained for a numb
 	against the LSB, and can be replaced by using udev.
 Who:	Greg Kroah-Hartman <greg@kroah.com>
 
+---------------------------
+
+What:	ACPI S4bios support
+When:	May 2005
+Why:	Noone uses it, and it probably does not work, anyway. swsusp is
+	faster, more reliable, and people are actually using it.
+Who:	Pavel Machek <pavel@suse.cz>
+
+---------------------------
+
+What:	PCI Name Database (CONFIG_PCI_NAMES)
+When:	July 2005
+Why:	It bloats the kernel unnecessarily, and is handled by userspace better
+	(pciutils supports it.)  Will eliminate the need to try to keep the
+	pci.ids file in sync with the sf.net database all of the time.
+Who:	Greg Kroah-Hartman <gregkh@suse.de>
+
+---------------------------
+
+What:	io_remap_page_range() (macro or function)
+When:	September 2005
+Why:	Replaced by io_remap_pfn_range() which allows more memory space
+	addressabilty (by using a pfn) and supports sparc & sparc64
+	iospace as part of the pfn.
+Who:	Randy Dunlap <rddunlap@osdl.org>
+
+---------------------------
+
+What:	register_ioctl32_conversion() / unregister_ioctl32_conversion()
+When:	April 2005
+Why:	Replaced by ->compat_ioctl in file_operations and other method
+	vecors.
+Who:	Andi Kleen <ak@muc.de>, Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
+What:	RCU API moves to EXPORT_SYMBOL_GPL
+When:	April 2006
+Files:	include/linux/rcupdate.h, kernel/rcupdate.c
+Why:	Outside of Linux, the only implementations of anything even
+	vaguely resembling RCU that I am aware of are in DYNIX/ptx,
+	VM/XA, Tornado, and K42.  I do not expect anyone to port binary
+	drivers or kernel modules from any of these, since the first two
+	are owned by IBM and the last two are open-source research OSes.
+	So these will move to GPL after a grace period to allow
+	people, who might be using implementations that I am not aware
+	of, to adjust to this upcoming change.
+Who:	Paul E. McKenney <paulmck@us.ibm.com>
+
+---------------------------
+
+What:	IEEE1394 Audio and Music Data Transmission Protocol driver,
+	Connection Management Procedures driver
+When:	November 2005
+Files:	drivers/ieee1394/{amdtp,cmp}*
+Why:	These are incomplete, have never worked, and are better implemented
+	in userland via raw1394 (see http://freebob.sourceforge.net/ for
+	example.)
+Who:	Jody McIntyre <scjody@steamballoon.com>
+
+---------------------------
+
+What:	raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
+When:	November 2005
+Why:	Deprecated in favour of the new ioctl-based rawiso interface, which is
+	more efficient.  You should really be using libraw1394 for raw1394
+	access anyway.
+Who:	Jody McIntyre <scjody@steamballoon.com>
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -104,6 +104,8 @@ prototypes:
 	void (*clear_inode) (struct inode *);
 	void (*umount_begin) (struct super_block *);
 	int (*show_options)(struct seq_file *, struct vfsmount *);
+	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
+	ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 
 locking rules:
 	All may block.
@@ -126,10 +128,17 @@ remount_fs:		no	yes	maybe		(see below)
 clear_inode:		no
 umount_begin:		yes	no	no
 show_options:		no				(vfsmount->sem)
+quota_read:		no	no	no		(see below)
+quota_write:		no	no	no		(see below)
 
 ->read_inode() is not a method - it's a callback used in iget().
 ->remount_fs() will have the s_umount lock if it's already mounted.
 When called from get_sb_single, it does NOT have the s_umount lock.
+->quota_read() and ->quota_write() functions are both guaranteed to
+be the only ones operating on the quota file by the quota code (via
+dqio_sem) (unless an admin really wants to screw up something and
+writes to quota files with quotas on). For other details about locking
+see also dquot_operations section.
 
 --------------------------- file_system_type ---------------------------
 prototypes:
@@ -210,8 +219,12 @@ This may also be done to avoid internal 
 If the filesytem is called for sync then it must wait on any
 in-progress I/O and then start new I/O.
 
-The filesystem should unlock the page synchronously, before returning
-to the caller.
+The filesystem should unlock the page synchronously, before returning to the
+caller, unless ->writepage() returns special WRITEPAGE_ACTIVATE
+value. WRITEPAGE_ACTIVATE means that page cannot really be written out
+currently, and VM should stop calling ->writepage() on this page for some
+time. VM does this by moving page to the head of the active list, hence the
+name.
 
 Unless the filesystem is going to redirty_page_for_writepage(), unlock the page
 and return zero, writepage *must* run set_page_writeback() against the page,
@@ -442,23 +455,46 @@ in sys_read() and friends.
 
 --------------------------- dquot_operations -------------------------------
 prototypes:
-	void (*initialize) (struct inode *, short);
-	void (*drop) (struct inode *);
-	int (*alloc_block) (const struct inode *, unsigned long, char);
+	int (*initialize) (struct inode *, int);
+	int (*drop) (struct inode *);
+	int (*alloc_space) (struct inode *, qsize_t, int);
 	int (*alloc_inode) (const struct inode *, unsigned long);
-	void (*free_block) (const struct inode *, unsigned long);
-	void (*free_inode) (const struct inode *, unsigned long);
-	int (*transfer) (struct dentry *, struct iattr *);
+	int (*free_space) (struct inode *, qsize_t);
+	int (*free_inode) (const struct inode *, unsigned long);
+	int (*transfer) (struct inode *, struct iattr *);
+	int (*write_dquot) (struct dquot *);
+	int (*acquire_dquot) (struct dquot *);
+	int (*release_dquot) (struct dquot *);
+	int (*mark_dirty) (struct dquot *);
+	int (*write_info) (struct super_block *, int);
+
+These operations are intended to be more or less wrapping functions that ensure
+a proper locking wrt the filesystem and call the generic quota operations.
+
+What filesystem should expect from the generic quota functions:
+
+		FS recursion	Held locks when called
+initialize:	yes		maybe dqonoff_sem
+drop:		yes		-
+alloc_space:	->mark_dirty()	-
+alloc_inode:	->mark_dirty()	-
+free_space:	->mark_dirty()	-
+free_inode:	->mark_dirty()	-
+transfer:	yes		-
+write_dquot:	yes		dqonoff_sem or dqptr_sem
+acquire_dquot:	yes		dqonoff_sem or dqptr_sem
+release_dquot:	yes		dqonoff_sem or dqptr_sem
+mark_dirty:	no		-
+write_info:	yes		dqonoff_sem
+
+FS recursion means calling ->quota_read() and ->quota_write() from superblock
+operations.
+
+->alloc_space(), ->alloc_inode(), ->free_space(), ->free_inode() are called
+only directly by the filesystem and do not call any fs functions only
+the ->mark_dirty() operation.
 
-locking rules:
-		BKL
-initialize:	no
-drop:		no
-alloc_block:	yes
-alloc_inode:	yes
-free_block:	yes
-free_inode:	yes
-transfer:	no
+More details about quota locking can be found in fs/dquot.c.
 
 --------------------------- vm_operations_struct -----------------------------
 prototypes:
diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
--- a/Documentation/filesystems/jfs.txt
+++ b/Documentation/filesystems/jfs.txt
@@ -1,13 +1,6 @@
 IBM's Journaled File System (JFS) for Linux
 
-JFS Homepage:  http://oss.software.ibm.com/jfs/
-
-Team members
-------------
-Dave Kleikamp      shaggy@austin.ibm.com  
-Dave Blaschke      blaschke@us.ibm.com
-Steve Best         sbest@us.ibm.com
-Barry Arndt        barndt@us.ibm.com
+JFS Homepage:  http://jfs.sourceforge.net/
 
 The following mount options are supported:
 
@@ -15,6 +8,7 @@ iocharset=name	Character set to use for 
 		ASCII.  The default is to do no conversion.  Use
 		iocharset=utf8 for UTF8 translations.  This requires
 		CONFIG_NLS_UTF8 to be set in the kernel .config file.
+		iocharset=none specifies the default behavior explicitly.
 
 resize=value	Resize the volume to <value> blocks.  JFS only supports
 		growing a volume, not shrinking it.  This option is only
@@ -38,4 +32,4 @@ errors=panic		Panic and halt the machine
 Please send bugs, comments, cards and letters to shaggy@austin.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/.
+"Mail list Subscribe" at our web page http://jfs.sourceforge.net/
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -909,16 +909,6 @@ nr_free_inodes
 Represents the  number of free inodes. Ie. The number of inuse inodes is
 (nr_inodes - nr_free_inodes).
 
-super-nr and super-max
-----------------------
-
-Again, super  block structures are allocated by the kernel, but not freed. The
-file super-max  contains  the  maximum  number  of super block handlers, where
-super-nr shows the number of currently allocated ones.
-
-Every mounted file system needs a super block, so if you plan to mount lots of
-file systems, you may want to increase these numbers.
-
 aio-nr and aio-max-nr
 ---------------------
 
@@ -1754,18 +1744,25 @@ settings contain additional options to s
 
 In the interface directories you'll find the following entries:
 
-base_reachable_time
--------------------
+base_reachable_time, base_reachable_time_ms
+-------------------------------------------
 
 A base  value  used for computing the random reachable time value as specified
 in RFC2461.
 
-retrans_time
-------------
+Expression of base_reachable_time, which is deprecated, is in seconds.
+Expression of base_reachable_time_ms is in milliseconds.
+
+retrans_time, retrans_time_ms
+-----------------------------
 
-The time,  expressed  in  jiffies  (1/100 sec), between retransmitted Neighbor
-Solicitation messages.  Used  for  address  resolution  and  to determine if a
-neighbor is unreachable.
+The time between retransmitted Neighbor Solicitation messages.
+Used for address resolution and to determine if a neighbor is
+unreachable.
+
+Expression of retrans_time, which is deprecated, is in 1/100 seconds (for
+IPv4) or in jiffies (for IPv6).
+Expression of retrans_time_ms is in milliseconds.
 
 unres_qlen
 ----------
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -7,7 +7,6 @@ that support it.  For example, a given b
      |-- 0000:17:00.0
      |   |-- class
      |   |-- config
-     |   |-- detach_state
      |   |-- device
      |   |-- irq
      |   |-- local_cpus
@@ -19,7 +18,7 @@ that support it.  For example, a given b
      |   |-- subsystem_device
      |   |-- subsystem_vendor
      |   `-- vendor
-     `-- detach_state
+     `-- ...
 
 The topmost element describes the PCI domain and bus number.  In this case,
 the domain number is 0000 and the bus number is 17 (both values are in hex).
@@ -31,7 +30,6 @@ files, each with their own function.
        ----		   --------
        class		   PCI class (ascii, ro)
        config		   PCI config space (binary, rw)
-       detach_state	   connection status (bool, rw)
        device		   PCI device (ascii, ro)
        irq		   IRQ number (ascii, ro)
        local_cpus	   nearby CPU mask (cpumask, ro)
@@ -85,4 +83,4 @@ useful return codes should be provided.
 
 Legacy resources are protected by the HAVE_PCI_LEGACY define.  Platforms
 wishing to support legacy functionality should define it and provide
-pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
\ No newline at end of file
+pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-ali1535
@@ -0,0 +1,42 @@
+Kernel driver i2c-ali1535
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1535 (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>,
+	Dan Eaton <dan.eaton@rocketlogix.com>,
+	Stephen Rousset<stephen.rousset@rocketlogix.com>
+												
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1535 South Bridge.
+
+The M1535 is a South bridge for portable systems. It is very similar to the
+M15x3 South bridges also produced by Acer Labs Inc.  Some of the registers
+within the part have moved and some have been redefined slightly.
+Additionally, the sequencing of the SMBus transactions has been modified to
+be more consistent with the sequencing recommended by the manufacturer and
+observed through testing.  These changes are reflected in this driver and
+can be identified by comparing this driver to the i2c-ali15x3 driver. For
+an overview of these chips see http://www.acerlabs.com
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-ali1563
@@ -0,0 +1,27 @@
+Kernel driver i2c-ali1563
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1563 (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Author: Patrick Mochel <mochel@digitalimplant.org>
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1563 South Bridge.
+
+For an overview of these chips see http://www.acerlabs.com
+
+The M1563 southbridge is deceptively similar to the M1533, with a few
+notable exceptions. One of those happens to be the fact they upgraded the
+i2c core to be SMBus 2.0 compliant, and happens to be almost identical to
+the i2c controller found in the Intel 801 south bridges. 
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-ali15x3
@@ -0,0 +1,112 @@
+Kernel driver i2c-ali15x3
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1533 and 1543C (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Module Parameters
+-----------------
+
+* force_addr: int
+  Initialize the base address of the i2c controller
+
+
+Notes
+-----
+
+The force_addr parameter is useful for boards that don't set the address in
+the BIOS. Does not do a PCI force; the device must still be present in
+lspci. Don't use this unless the driver complains that the base address is
+not set.
+
+Example: 'modprobe i2c-ali15x3 force_addr=0xe800'
+
+SMBus periodically hangs on ASUS P5A motherboards and can only be cleared
+by a power cycle. Cause unknown (see Issues below).
+
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1541 and M1543C South Bridges.
+
+The M1543C is a South bridge for desktop systems.
+The M1541 is a South bridge for portable systems.
+They are part of the following ALI chipsets:
+   
+ * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and 
+ 		100MHz CPU Front Side bus
+ * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz 
+ 		CPU Front Side bus
+   Some Aladdin V motherboards:
+	Asus P5A
+	Atrend ATC-5220
+	BCM/GVC VP1541
+	Biostar M5ALA
+	Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't
+                            enable the 7101 device! **)
+	Iwill XA100 Plus
+	Micronics C200
+	Microstar (MSI) MS-5169
+
+  * "Aladdin IV" includes the M1541 Socket 7 North bridge
+   		with host bus up to 83.3 MHz.
+
+For an overview of these chips see http://www.acerlabs.com. At this time the
+full data sheets on the web site are password protected, however if you
+contact the ALI office in San Jose they may give you the password.
+
+The M1533/M1543C devices appear as FOUR separate devices on the PCI bus. An
+output of lspci will show something similar to the following:
+
+  00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03)
+  00:03.0 Bridge: Acer Laboratories Inc. M7101      <= THIS IS THE ONE WE NEED
+  00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3)
+  00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1)
+
+** IMPORTANT **
+** If you have a M1533 or M1543C on the board and you get
+** "ali15x3: Error: Can't detect ali15x3!"
+** then run lspci.
+** If you see the 1533 and 5229 devices but NOT the 7101 device,
+** then you must enable ACPI, the PMU, SMB, or something similar
+** in the BIOS. 
+** The driver won't work if it can't find the M7101 device.
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+Features 
+-------- 
+
+This driver controls the SMB Host only. The SMB Slave
+controller on the M15X3 is not enabled. This driver does not use
+interrupts.
+
+
+Issues
+------
+
+This driver requests the I/O space for only the SMB
+registers. It doesn't use the ACPI region.
+
+On the ASUS P5A motherboard, there are several reports that
+the SMBus will hang and this can only be resolved by
+powering off the computer. It appears to be worse when the board
+gets hot, for example under heavy CPU load, or in the summer.
+There may be electrical problems on this board.
+On the P5A, the W83781D sensor chip is on both the ISA and
+SMBus. Therefore the SMBus hangs can generally be avoided
+by accessing the W83781D on the ISA bus only.
+
diff --git a/Documentation/i2c/busses/i2c-amd756 b/Documentation/i2c/busses/i2c-amd756
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-amd756
@@ -0,0 +1,25 @@
+Kernel driver i2c-amd756
+
+Supported adapters:
+  * AMD 756
+  * AMD 766
+  * AMD 768
+  * AMD 8111
+    Datasheets: Publicly available on AMD website
+
+  * nVidia nForce
+    Datasheet: Unavailable
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>,
+	Philip Edelbrock <phil@netroedge.com> 
+
+Description
+-----------
+
+This driver supports the AMD 756, 766, 768 and 8111 Peripheral Bus
+Controllers, and the nVidia nForce.
+
+Note that for the 8111, there are two SMBus adapters. The SMBus 1.0 adapter
+is supported by this driver, and the SMBus 2.0 adapter is supported by the
+i2c-amd8111 driver.
diff --git a/Documentation/i2c/busses/i2c-amd8111 b/Documentation/i2c/busses/i2c-amd8111
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-amd8111
@@ -0,0 +1,41 @@
+Kernel driver i2c-adm8111
+
+Supported adapters:
+    * AMD-8111 SMBus 2.0 PCI interface
+
+Datasheets:
+	AMD datasheet not yet available, but almost everything can be found
+	in publically available ACPI 2.0 specification, which the adapter 
+	follows.
+
+Author: Vojtech Pavlik <vojtech@suse.cz>
+
+Description
+-----------
+
+If you see something like this:
+
+00:07.2 SMBus: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 (rev 02)
+        Subsystem: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0
+        Flags: medium devsel, IRQ 19
+        I/O ports at d400 [size=32]
+
+in your 'lspci -v', then this driver is for your chipset.
+
+Process Call Support
+--------------------
+
+Supported.
+
+SMBus 2.0 Support
+-----------------
+
+Supported. Both PEC and block process call support is implemented. Slave
+mode or host notification are not yet implemented.
+
+Notes
+-----
+
+Note that for the 8111, there are two SMBus adapters. The SMBus 2.0 adapter
+is supported by this driver, and the SMBus 1.0 adapter is supported by the
+i2c-amd756 driver.
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-i801
@@ -0,0 +1,80 @@
+Kernel driver i2c-i801
+
+Supported adapters:
+  * Intel 82801AA and 82801AB (ICH and ICH0 - part of the
+    '810' and '810E' chipsets)
+  * Intel 82801BA (ICH2 - part of the '815E' chipset)
+  * Intel 82801CA/CAM (ICH3)
+  * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported)
+  * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
+  * Intel 6300ESB
+  * Intel 82801FB/FR/FW/FRW (ICH6)
+  * Intel ICH7
+    Datasheets: Publicly available at the Intel website
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Mark Studebaker <mdsxyz123@yahoo.com>
+
+
+Module Parameters
+-----------------
+
+* force_addr: int
+  Forcibly enable the ICH at the given address. EXTREMELY DANGEROUS!
+
+
+Description
+-----------
+
+The ICH (properly known as the 82801AA), ICH0 (82801AB), ICH2 (82801BA),
+ICH3 (82801CA/CAM) and later devices are Intel chips that are a part of
+Intel's '810' chipset for Celeron-based PCs, '810E' chipset for
+Pentium-based PCs, '815E' chipset, and others.
+
+The ICH chips contain at least SEVEN separate PCI functions in TWO logical
+PCI devices. An output of lspci will show something similar to the
+following:
+
+  00:1e.0 PCI bridge: Intel Corporation: Unknown device 2418 (rev 01)
+  00:1f.0 ISA bridge: Intel Corporation: Unknown device 2410 (rev 01)
+  00:1f.1 IDE interface: Intel Corporation: Unknown device 2411 (rev 01)
+  00:1f.2 USB Controller: Intel Corporation: Unknown device 2412 (rev 01)
+  00:1f.3 Unknown class [0c05]: Intel Corporation: Unknown device 2413 (rev 01)
+
+The SMBus controller is function 3 in device 1f. Class 0c05 is SMBus Serial
+Controller.
+
+If you do NOT see the 24x3 device at function 3, and you can't figure out
+any way in the BIOS to enable it,
+
+The ICH chips are quite similar to Intel's PIIX4 chip, at least in the
+SMBus controller.
+
+See the file i2c-piix4 for some additional information.
+
+
+Process Call Support
+--------------------
+
+Not supported.
+
+
+I2C Block Read Support
+----------------------
+
+Not supported at the moment.
+
+
+SMBus 2.0 Support
+-----------------
+
+The 82801DB (ICH4) and later chips support several SMBus 2.0 features.
+
+**********************
+The lm_sensors project gratefully acknowledges the support of Texas
+Instruments in the initial development of this driver.
+
+The lm_sensors project gratefully acknowledges the support of Intel in the
+development of SMBus 2.0 / ICH4 features of this driver.
diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-i810
@@ -0,0 +1,46 @@
+Kernel driver i2c-i810
+
+Supported adapters:
+  * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH)
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+	Ralph Metzler <rjkm@thp.uni-koeln.de>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Mark Studebaker <mdsxyz123@yahoo.com>
+
+Description 
+----------- 
+
+WARNING: If you have an '810' or '815' motherboard, your standard I2C
+temperature sensors are most likely on the 801's I2C bus. You want the
+i2c-i801 driver for those, not this driver.
+
+Now for the i2c-i810...
+
+The GMCH chip contains two I2C interfaces.
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. It may be connected to a
+TV-out chip such as the BT869 or possibly to a digital flat-panel display.
+
+Features
+-------- 
+
+Both busses use the i2c-algo-bit driver for 'bit banging'
+and support for specific transactions is provided by i2c-algo-bit.
+
+Issues
+------
+
+If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1),
+the test may fail; if so, the i2c-i810 driver won't be inserted. However,
+we think this has been fixed.
diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nforce2
@@ -0,0 +1,41 @@
+Kernel driver i2c-nforce2
+
+Supported adapters:
+  * nForce2 MCP                10de:0064 
+  * nForce2 Ultra 400 MCP      10de:0084 
+  * nForce3 Pro150 MCP         10de:00D4 
+  * nForce3 250Gb MCP          10de:00E4 
+  * nForce4 MCP	       	       10de:0052
+
+Datasheet: not publically available, but seems to be similar to the
+           AMD-8111 SMBus 2.0 adapter.
+
+Authors:
+	Hans-Frieder Vogt <hfvogt@arcor.de>, 
+	Thomas Leibold <thomas@plx.com>, 
+        Patrick Dreker <patrick@dreker.de>
+	
+Description
+-----------
+
+i2c-nforce2 is a driver for the SMBuses included in the nVidia nForce2 MCP.
+
+If your 'lspci -v' listing shows something like the following,
+
+00:01.1 SMBus: nVidia Corporation: Unknown device 0064 (rev a2)
+        Subsystem: Asustek Computer, Inc.: Unknown device 0c11
+        Flags: 66Mhz, fast devsel, IRQ 5
+        I/O ports at c000 [size=32]
+        Capabilities: <available only to root>
+
+then this driver should support the SMBuses of your motherboard.
+
+
+Notes
+-----
+
+The SMBus adapter in the nForce2 chipset seems to be very similar to the
+SMBus 2.0 adapter in the AMD-8111 southbridge. However, I could only get
+the driver to work with direct I/O access, which is different to the EC
+interface of the AMD-8111. Tested on Asus A7N8X. The ACPI DSDT table of the
+Asus A7N8X lists two SMBuses, both of which are supported by this driver.
diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-parport
@@ -0,0 +1,154 @@
+Kernel driver i2c-parport
+
+Author: Jean Delvare <khali@linux-fr.org> 
+
+This is a unified driver for several i2c-over-parallel-port adapters,
+such as the ones made by Philips, Velleman or ELV. This driver is
+meant as a replacement for the older, individual drivers:
+ * i2c-philips-par
+ * i2c-elv
+ * i2c-velleman
+ * video/i2c-parport (NOT the same as this one, dedicated to home brew
+                      teletext adapters)
+
+It currently supports the following devices:
+ * Philips adapter
+ * home brew teletext adapter
+ * Velleman K8000 adapter
+ * ELV adapter
+ * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032)
+
+These devices use different pinout configurations, so you have to tell
+the driver what you have, using the type module parameter. There is no
+way to autodetect the devices. Support for different pinout configurations
+can be easily added when needed.
+
+
+Building your own adapter
+-------------------------
+
+If you want to build you own i2c-over-parallel-port adapter, here is
+a sample electronics schema (credits go to Sylvain Munaut):
+
+Device                                                      PC
+Side          ___________________Vdd (+)                    Side
+               |    |         |
+              ---  ---       ---
+              | |  | |       | |
+              |R|  |R|       |R|
+              | |  | |       | |
+              ---  ---       ---
+               |    |         |
+               |    |    /|   |
+SCL  ----------x--------o |-----------x-------------------  pin 2
+                    |    \|   |       |
+                    |         |       |
+                    |   |\    |       |
+SDA  ----------x----x---| o---x---------------------------  pin 13
+               |        |/            |
+               |                      |
+               |         /|           |
+               ---------o |----------------x--------------  pin 3
+                         \|           |    |
+                                      |    |
+                                     ---  ---
+                                     | |  | |
+                                     |R|  |R|
+                                     | |  | |
+                                     ---  ---
+                                      |    | 
+                                     ###  ###
+                                     GND  GND
+        
+Remarks:
+ - This is the exact pinout and electronics used on the Analog Devices
+   evaluation boards.
+                   /|
+ - All inverters -o |- must be 74HC05, they must be open collector output.
+                   \|
+ - All resitors are 10k.
+ - Pins 18-25 of the parallel port connected to GND.
+ - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high.
+   The ADM1032 evaluation board uses D4-D7. Beware that the amount of
+   current you can draw from the parallel port is limited. Also note that
+   all connected lines MUST BE driven at the same state, else you'll short
+   circuit the output buffers! So plugging the I2C adapter after loading
+   the i2c-parport module might be a good safety since data line state
+   prior to init may be unknown. 
+ - This is 5V!
+ - Obviously you cannot read SCL (so it's not really standard-compliant).
+   Pretty easy to add, just copy the SDA part and use another input pin.
+   That would give (ELV compatible pinout):
+
+
+Device                                                      PC
+Side          ______________________________Vdd (+)         Side
+               |    |            |    |
+              ---  ---          ---  ---
+              | |  | |          | |  | |
+              |R|  |R|          |R|  |R|
+              | |  | |          | |  | |
+              ---  ---          ---  ---
+               |    |            |    |
+               |    |      |\    |    |
+SCL  ----------x--------x--| o---x------------------------  pin 15
+                    |   |  |/         | 
+                    |   |             |
+                    |   |   /|        |
+                    |   ---o |-------------x--------------  pin 2
+                    |       \|        |    |
+                    |                 |    |
+                    |                 |    |
+                    |      |\         |    |
+SDA  ---------------x---x--| o--------x-------------------  pin 10
+                        |  |/              |
+                        |                  |
+                        |   /|             |
+                        ---o |------------------x---------  pin 3
+                            \|             |    |
+                                           |    |
+                                          ---  ---
+                                          | |  | |
+                                          |R|  |R|
+                                          | |  | |
+                                          ---  ---
+                                           |    | 
+                                          ###  ###
+                                          GND  GND
+
+
+If possible, you should use the same pinout configuration as existing
+adapters do, so you won't even have to change the code.
+
+
+Similar (but different) drivers
+-------------------------------
+
+This driver is NOT the same as the i2c-pport driver found in the i2c
+package. The i2c-pport driver makes use of modern parallel port features so
+that you don't need additional electronics. It has other restrictions
+however, and was not ported to Linux 2.6 (yet).
+
+This driver is also NOT the same as the i2c-pcf-epp driver found in the
+lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port as
+an I2C bus directly. Instead, it uses it to control an external I2C bus
+master. That driver was not ported to Linux 2.6 (yet) either.
+
+
+Legacy documentation for Velleman adapter
+-----------------------------------------
+
+Useful links:
+Velleman                http://www.velleman.be/
+Velleman K8000 Howto    http://howto.htlw16.ac.at/k8000-howto.html
+
+The project has lead to new libs for the Velleman K8000 and K8005:
+  LIBK8000 v1.99.1 and LIBK8005 v0.21
+With these libs, you can control the K8000 interface card and the K8005
+stepper motor card with the simple commands which are in the original
+Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and
+many more, using /dev/velleman.
+  http://home.wanadoo.nl/hihihi/libk8000.htm
+  http://home.wanadoo.nl/hihihi/libk8005.htm
+  http://struyve.mine.nu:8080/index.php?block=k8000
+  http://sourceforge.net/projects/libk8005/
diff --git a/Documentation/i2c/busses/i2c-parport-light b/Documentation/i2c/busses/i2c-parport-light
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-parport-light
@@ -0,0 +1,11 @@
+Kernel driver i2c-parport-light
+
+Author: Jean Delvare <khali@linux-fr.org> 
+
+This driver is a light version of i2c-parport. It doesn't depend        
+on the parport driver, and uses direct I/O access instead. This might be
+prefered on embedded systems where wasting memory for the clean but heavy
+parport handling is not an option. The drawback is a reduced portability
+and the impossibility to daisy-chain other parallel port devices.                 
+  
+Please see i2c-parport for documentation.
diff --git a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-pca-isa
@@ -0,0 +1,23 @@
+Kernel driver i2c-pca-isa
+
+Supported adapters:
+This driver supports ISA boards using the Philips PCA 9564 
+Parallel bus to I2C bus controller 
+
+Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems 
+
+Module Parameters
+-----------------
+
+* base int
+ I/O base address
+* irq int
+ IRQ interrupt 
+* clock int 
+ Clock rate as described in table 1 of PCA9564 datasheet
+
+Description
+-----------
+
+This driver supports ISA boards using the Philips PCA 9564 
+Parallel bus to I2C bus controller 
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -0,0 +1,72 @@
+Kernel driver i2c-piix4
+
+Supported adapters:
+  * Intel 82371AB PIIX4 and PIIX4E
+  * Intel 82443MX (440MX)
+    Datasheet: Publicly available at the Intel website
+  * ServerWorks OSB4, CSB5 and CSB6 southbridges
+    Datasheet: Only available via NDA from ServerWorks
+  * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
+    Datasheet: Publicly available at the SMSC website http://www.smsc.com
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>
+	Philip Edelbrock <phil@netroedge.com>
+
+
+Module Parameters
+-----------------
+
+* force: int
+  Forcibly enable the PIIX4. DANGEROUS!
+* force_addr: int
+  Forcibly enable the PIIX4 at the given address. EXTREMELY DANGEROUS!
+* fix_hstcfg: int
+  Fix config register. Needed on some boards (Force CPCI735).
+
+
+Description
+-----------
+
+The PIIX4 (properly known as the 82371AB) is an Intel chip with a lot of
+functionality. Among other things, it implements the PCI bus. One of its
+minor functions is implementing a System Management Bus. This is a true 
+SMBus - you can not access it on I2C levels. The good news is that it
+natively understands SMBus commands and you do not have to worry about
+timing problems. The bad news is that non-SMBus devices connected to it can
+confuse it mightily. Yes, this is known to happen...
+
+Do 'lspci -v' and see whether it contains an entry like this:
+
+0000:00:02.3 Bridge: Intel Corp. 82371AB/EB/MB PIIX4 ACPI (rev 02)
+	     Flags: medium devsel, IRQ 9
+
+Bus and device numbers may differ, but the function number must be
+identical (like many PCI devices, the PIIX4 incorporates a number of
+different 'functions', which can be considered as separate devices). If you
+find such an entry, you have a PIIX4 SMBus controller.
+
+On some computers (most notably, some Dells), the SMBus is disabled by
+default. If you use the insmod parameter 'force=1', the kernel module will
+try to enable it. THIS IS VERY DANGEROUS! If the BIOS did not set up a
+correct address for this module, you could get in big trouble (read:
+crashes, data corruption, etc.). Try this only as a last resort (try BIOS
+updates first, for example), and backup first! An even more dangerous
+option is 'force_addr=<IOPORT>'. This will not only enable the PIIX4 like
+'force' foes, but it will also set a new base I/O port address. The SMBus
+parts of the PIIX4 needs a range of 8 of these addresses to function
+correctly. If these addresses are already reserved by some other device,
+you will get into big trouble! DON'T USE THIS IF YOU ARE NOT VERY SURE
+ABOUT WHAT YOU ARE DOING!
+
+The PIIX4E is just an new version of the PIIX4; it is supported as well.
+The PIIX/PIIX3 does not implement an SMBus or I2C bus, so you can't use
+this driver on those mainboards.
+
+The ServerWorks Southbridges, the Intel 440MX, and the Victory766 are
+identical to the PIIX4 in I2C/SMBus support.
+
+A few OSB4 southbridges are known to be misconfigured by the BIOS. In this
+case, you have you use the fix_hstcfg module parameter. Do not use it
+unless you know you have to, because in some cases it also breaks
+configuration on southbridges that don't need it.
diff --git a/Documentation/i2c/busses/i2c-prosavage b/Documentation/i2c/busses/i2c-prosavage
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-prosavage
@@ -0,0 +1,23 @@
+Kernel driver i2c-prosavage
+
+Supported adapters:
+	
+	S3/VIA KM266/VT8375 aka ProSavage8 
+	S3/VIA KM133/VT8365 aka Savage4 
+
+Author: Henk Vergonet <henk@god.dyndns.org>
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or
+'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The second interface is a general-purpose I2C bus.
+
+Usefull for gaining access to the TV Encoder chips.
+
diff --git a/Documentation/i2c/busses/i2c-savage4 b/Documentation/i2c/busses/i2c-savage4
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-savage4
@@ -0,0 +1,26 @@
+Kernel driver i2c-savage4
+
+Supported adapters:
+  * Savage4
+  * Savage2000
+
+Authors: 
+	Alexander Wold <awold@bigfoot.com>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com> 
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master'
+or 'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The DDC bus is not yet supported because its register
+is not directly memory-mapped.
+
+The second interface is a general-purpose I2C bus. This is the only
+interface supported by the driver at the moment.
+
diff --git a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-sis5595
@@ -0,0 +1,59 @@
+Kernel driver i2c-sis5595
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>,
+        Mark D. Studebaker <mdsxyz123@yahoo.com>,
+	Philip Edelbrock <phil@netroedge.com> 
+
+Supported adapters:
+  * Silicon Integrated Systems Corp. SiS5595 Southbridge
+    Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
+
+Note: all have mfr. ID 0x1039. 
+
+   SUPPORTED            PCI ID           
+        5595            0008 
+ 
+   Note: these chips contain a 0008 device which is incompatible with the 
+         5595. We recognize these by the presence of the listed 
+         "blacklist" PCI ID and refuse to load. 
+ 
+   NOT SUPPORTED        PCI ID          BLACKLIST PCI ID         
+         540            0008            0540 
+         550            0008            0550 
+        5513            0008            5511 
+        5581            0008            5597 
+        5582            0008            5597 
+        5597            0008            5597 
+        5598            0008            5597/5598 
+         630            0008            0630 
+         645            0008            0645 
+         646            0008            0646 
+         648            0008            0648 
+         650            0008            0650 
+         651            0008            0651 
+         730            0008            0730 
+         735            0008            0735 
+         745            0008            0745 
+         746            0008            0746 
+
+Module Parameters
+-----------------
+
+* force_addr=0xaddr	Set the I/O base address. Useful for boards
+			that don't set the address in the BIOS. Does not do a
+			PCI force; the device must still be present in lspci.
+			Don't use this unless the driver complains that the
+			base address is not set.
+
+Description
+-----------
+
+i2c-sis5595 is a true SMBus host driver for motherboards with the SiS5595
+southbridges.
+
+WARNING: If you are trying to access the integrated sensors on the SiS5595
+chip, you want the sis5595 driver for those, not this driver. This driver
+is a BUS driver, not a CHIP driver. A BUS driver is used by other CHIP
+drivers to access chips on the bus.
+
diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-sis630
@@ -0,0 +1,49 @@
+Kernel driver i2c-sis630
+
+Supported adapters:
+  * Silicon Integrated Systems Corp (SiS)
+	630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/)
+	730 chipset
+  * Possible other SiS chipsets ?
+
+Author: Alexander Malysh <amalysh@web.de>
+
+Module Parameters
+-----------------
+
+* force = [1|0] Forcibly enable the SIS630. DANGEROUS!
+		This can be interesting for chipsets not named
+		above to check if it works for you chipset, but DANGEROUS!
+		
+* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, 
+			what your BIOS use). DANGEROUS! This should be a bit 
+			faster, but freeze some systems (i.e. my Laptop).
+
+
+Description
+-----------
+
+This SMBus only driver is known to work on motherboards with the above
+named chipsets.
+
+If you see something like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+or like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+in your 'lspci' output , then this driver is for your chipset.
+
+Thank You
+---------
+Philip Edelbrock <phil@netroedge.com>
+- testing SiS730 support
+Mark M. Hoffman <mhoffman@lightlink.com>
+- bug fixes
+ 
+To anyone else which I forgot here ;), thanks!
+
diff --git a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis69x
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-sis69x
@@ -0,0 +1,73 @@
+Kernel driver i2c-sis96x
+
+Replaces 2.4.x i2c-sis645
+
+Supported adapters:
+  * Silicon Integrated Systems Corp (SiS)
+    Any combination of these host bridges:
+	645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746
+    and these south bridges:
+    	961, 962, 963(L) 
+
+Author: Mark M. Hoffman <mhoffman@lightlink.com>
+
+Description
+-----------
+
+This SMBus only driver is known to work on motherboards with the above
+named chipset combinations. The driver was developed without benefit of a
+proper datasheet from SiS. The SMBus registers are assumed compatible with
+those of the SiS630, although they are located in a completely different
+place. Thanks to Alexander Malysh <amalysh@web.de> for providing the
+SiS630 datasheet (and  driver).
+
+The command "lspci" as root should produce something like these lines:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645
+00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016
+
+or perhaps this...
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 
+00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961
+00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016
+
+(kernel versions later than 2.4.18 may fill in the "Unknown"s)
+
+If you cant see it please look on quirk_sis_96x_smbus
+(drivers/pci/quirks.c) (also if southbridge detection fails)
+
+I suspect that this driver could be made to work for the following SiS
+chipsets as well: 635, and 635T. If anyone owns a board with those chips
+AND is willing to risk crashing & burning an otherwise well-behaved kernel
+in the name of progress... please contact me at <mhoffman@lightlink.com> or
+via the project's mailing list: <sensors@stimpy.netroedge.com>.  Please
+send bug reports and/or success stories as well.
+
+
+TO DOs
+------
+
+* The driver does not support SMBus block reads/writes; I may add them if a
+scenario is found where they're needed.
+
+
+Thank You
+---------
+
+Mark D. Studebaker <mdsxyz123@yahoo.com>
+ - design hints and bug fixes
+Alexander Maylsh <amalysh@web.de>
+ - ditto, plus an important datasheet... almost the one I really wanted
+Hans-Günter Lütke Uphues <hg_lu@t-online.de>
+ - patch for SiS735
+Robert Zwerus <arzie@dds.nl>
+ - testing for SiS645DX
+Kianusch Sayah Karadji <kianusch@sk-tech.net>
+ - patch for SiS645DX/962
+Ken Healy
+ - patch for SiS655
+
+To anyone else who has written w/ feedback, thanks!
+
diff --git a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-via
@@ -0,0 +1,34 @@
+Kernel driver i2c-via
+
+Supported adapters:
+  * VIA Technologies, InC. VT82C586B
+    Datasheet: Publicly available at the VIA website
+
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+Description
+-----------
+
+i2c-via is an i2c bus driver for motherboards with VIA chipset.
+
+The following VIA pci chipsets are supported:
+ - MVP3, VP3, VP2/97, VPX/97 
+ - others with South bridge VT82C586B
+
+Your lspci listing must show this :
+
+ Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10)
+
+    Problems?
+ 
+ Q: You have VT82C586B on the motherboard, but not in the listing. 
+ 
+ A: Go to your BIOS setup, section PCI devices or similar.
+    Turn USB support on, and try again. 
+
+ Q: No error messages, but still i2c doesn't seem to work.
+
+ A: This can happen. This driver uses the pins VIA recommends in their
+    datasheets, but there are several ways the motherboard manufacturer
+    can actually wire the lines.
+
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -0,0 +1,47 @@
+Kernel driver i2c-viapro
+
+Supported adapters:
+  * VIA Technologies, Inc. VT82C596A/B
+    Datasheet: Sometimes available at the VIA website
+
+  * VIA Technologies, Inc. VT82C686A/B 
+    Datasheet: Sometimes available at the VIA website
+
+  * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237
+    Datasheet: available on request from Via
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>,  
+	Philip Edelbrock <phil@netroedge.com>, 
+	Kyösti Mälkki <kmalkki@cc.hut.fi>, 
+	Mark D. Studebaker <mdsxyz123@yahoo.com> 
+
+Module Parameters
+-----------------
+
+* force: int
+  Forcibly enable the SMBus controller. DANGEROUS!
+* force_addr: int
+  Forcibly enable the SMBus at the given address. EXTREMELY DANGEROUS!
+
+Description
+-----------
+
+i2c-viapro is a true SMBus host driver for motherboards with one of the
+supported VIA southbridges.
+
+Your lspci -n listing must show one of these :
+
+ device 1106:3050   (VT82C596 function 3)
+ device 1106:3051   (VT82C596 function 3)
+ device 1106:3057   (VT82C686 function 4)
+ device 1106:3074   (VT8233)
+ device 1106:3147   (VT8233A)
+ device 1106:8235   (VT8231)
+ devide 1106:3177   (VT8235)
+ devide 1106:3227   (VT8237)
+
+If none of these show up, you should look in the BIOS for settings like
+enable ACPI / SMBus or even USB.
+
+
diff --git a/Documentation/i2c/busses/i2c-voodoo3 b/Documentation/i2c/busses/i2c-voodoo3
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-voodoo3
@@ -0,0 +1,62 @@
+Kernel driver i2c-voodoo3
+
+Supported adapters:
+  * 3dfx Voodoo3 based cards
+  * Voodoo Banshee based cards
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Ralph Metzler <rjkm@thp.uni-koeln.de>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Philip Edelbrock <phil@netroedge.com>
+	
+The code is based upon Ralph's test code (he did the hard stuff ;')
+
+Description
+-----------
+
+The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or
+'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. The intent by 3dfx was
+to allow manufacturers to add extra chips to the video card such as a
+TV-out chip such as the BT869 or possibly even I2C based temperature
+sensors like the ADM1021 or LM75.
+
+Stability
+---------
+
+Seems to be stable on the test machine, but needs more testing on other
+machines. Simultaneous accesses of the DDC and I2C busses may cause errors.
+
+Supported Devices
+-----------------
+
+Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP
+3000' which has a tv-out feature (s-video or composite).  According to the
+docs and discussions, this code should work for any Voodoo3 based cards as
+well as Voodoo Banshee based cards.  The DDC interface has been tested on a
+Voodoo Banshee card.
+	
+Issues
+------
+
+Probably many, but it seems to work OK on my system. :')
+
+
+External Device Connection
+--------------------------
+
+The digital video input jumpers give availability to the I2C bus. 
+Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are     
+the I2C clock and I2C data lines, respectively. +5V and GND are probably
+also easily available making the addition of extra I2C/SMBus devices easy
+to implement.
diff --git a/Documentation/i2c/busses/scx200_acb b/Documentation/i2c/busses/scx200_acb
new file mode 100644
--- /dev/null
+++ b/Documentation/i2c/busses/scx200_acb
@@ -0,0 +1,14 @@
+Kernel driver scx200_acb
+
+Author: Christer Weinigel <wingel@nano-system.com>
+
+Module Parameters
+-----------------
+
+* base: int
+  Base addresses for the ACCESS.bus controllers
+
+Description
+-----------
+
+Enable the use of the ACCESS.bus controllers of a SCx200 processor.
diff --git a/Documentation/i2c/i2c-parport b/Documentation/i2c/i2c-parport
deleted file mode 100644
--- a/Documentation/i2c/i2c-parport
+++ /dev/null
@@ -1,156 +0,0 @@
-==================
-i2c-parport driver
-==================
-
-2004-07-06, Jean Delvare
-
-This is a unified driver for several i2c-over-parallel-port adapters,
-such as the ones made by Philips, Velleman or ELV. This driver is
-meant as a replacement for the older, individual drivers:
- * i2c-philips-par
- * i2c-elv
- * i2c-velleman
- * video/i2c-parport (NOT the same as this one, dedicated to home brew
-                      teletext adapters)
-
-It currently supports the following devices:
- * Philips adapter
- * home brew teletext adapter
- * Velleman K8000 adapter
- * ELV adapter
- * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032)
-
-These devices use different pinout configurations, so you have to tell
-the driver what you have, using the type module parameter. There is no
-way to autodetect the devices. Support for different pinout configurations
-can be easily added when needed.
-
-
-Building your own adapter
--------------------------
-
-If you want to build you own i2c-over-parallel-port adapter, here is
-a sample electronics schema (credits go to Sylvain Munaut):
-
-Device                                                      PC
-Side          ___________________Vdd (+)                    Side
-               |    |         |
-              ---  ---       ---
-              | |  | |       | |
-              |R|  |R|       |R|
-              | |  | |       | |
-              ---  ---       ---
-               |    |         |
-               |    |    /|   |
-SCL  ----------x--------o |-----------x-------------------  pin 2
-                    |    \|   |       |
-                    |         |       |
-                    |   |\    |       |
-SDA  ----------x----x---| o---x---------------------------  pin 13
-               |        |/            |
-               |                      |
-               |         /|           |
-               ---------o |----------------x--------------  pin 3
-                         \|           |    |
-                                      |    |
-                                     ---  ---
-                                     | |  | |
-                                     |R|  |R|
-                                     | |  | |
-                                     ---  ---
-                                      |    | 
-                                     ###  ###
-                                     GND  GND
-        
-Remarks:
- - This is the exact pinout and electronics used on the Analog Devices
-   evaluation boards.
-                   /|
- - All inverters -o |- must be 74HC05, they must be open collector output.
-                   \|
- - All resitors are 10k.
- - Pins 18-25 of the parallel port connected to GND.
- - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high.
-   The ADM1032 evaluation board uses D4-D7. Beware that the amount of
-   current you can draw from the parallel port is limited. Also note that
-   all connected lines MUST BE driven at the same state, else you'll short
-   circuit the output buffers! So plugging the I2C adapter after loading
-   the i2c-parport module might be a good safety since data line state
-   prior to init may be unknown. 
- - This is 5V!
- - Obviously you cannot read SCL (so it's not really standard-compliant).
-   Pretty easy to add, just copy the SDA part and use another input pin.
-   That would give (ELV compatible pinout):
-
-
-Device                                                      PC
-Side          ______________________________Vdd (+)         Side
-               |    |            |    |
-              ---  ---          ---  ---
-              | |  | |          | |  | |
-              |R|  |R|          |R|  |R|
-              | |  | |          | |  | |
-              ---  ---          ---  ---
-               |    |            |    |
-               |    |      |\    |    |
-SCL  ----------x--------x--| o---x------------------------  pin 15
-                    |   |  |/         | 
-                    |   |             |
-                    |   |   /|        |
-                    |   ---o |-------------x--------------  pin 2
-                    |       \|        |    |
-                    |                 |    |
-                    |                 |    |
-                    |      |\         |    |
-SDA  ---------------x---x--| o--------x-------------------  pin 10
-                        |  |/              |
-                        |                  |
-                        |   /|             |
-                        ---o |------------------x---------  pin 3
-                            \|             |    |
-                                           |    |
-                                          ---  ---
-                                          | |  | |
-                                          |R|  |R|
-                                          | |  | |
-                                          ---  ---
-                                           |    | 
-                                          ###  ###
-                                          GND  GND
-
-
-If possible, you should use the same pinout configuration as existing
-adapters do, so you won't even have to change the code.
-
-
-Similar (but different) drivers
--------------------------------
-
-This driver is NOT the same as the i2c-pport driver found in the i2c package.
-The i2c-pport driver makes use of modern parallel port features so that
-you don't need additional electronics. It has other restrictions however, and
-was not ported to Linux 2.6 (yet).
-
-This driver is also NOT the same as the i2c-pcf-epp driver found in the
-lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port
-as an I2C bus directly. Instead, it uses it to control an external I2C bus
-master. That driver was not ported to Linux 2.6 (yet) either.
-
-
-Legacy documentation for Velleman adapter
------------------------------------------
-
-Useful links:
-Velleman                http://www.velleman.be/
-Velleman K8000 Howto    http://howto.htlw16.ac.at/k8000-howto.html
-
-The project has lead to new libs for the Velleman K8000 and K8005:
-  LIBK8000 v1.99.1 and LIBK8005 v0.21
-With these libs, you can control the K8000 interface card and the K8005
-stepper motor card with the simple commands which are in the original
-Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and
-many more, using /dev/velleman.
-  http://home.wanadoo.nl/hihihi/libk8000.htm
-  http://home.wanadoo.nl/hihihi/libk8005.htm
-  http://struyve.mine.nu:8080/index.php?block=k8000
-  http://sourceforge.net/projects/libk8005/
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients
--- a/Documentation/i2c/porting-clients
+++ b/Documentation/i2c/porting-clients
@@ -49,9 +49,8 @@ Technical changes:
   static void lm75_update_client(struct i2c_client *client);
 
 * [Sysctl] All sysctl stuff is of course gone (defines, ctl_table
-  and functions). Instead, right after the static id definition
-  line, you have to define show and set functions for each sysfs
-  file. Only define set for writable values. Take a look at an
+  and functions). Instead, you have to define show and set functions for
+  each sysfs file. Only define set for writable values. Take a look at an
   existing 2.6 driver for details (lm78 for example). Don't forget
   to define the attributes for each file (this is that step that
   links callback functions). Use the file names specified in
@@ -86,6 +85,7 @@ Technical changes:
   Replace the sysctl directory registration by calls to
   device_create_file. Move the driver initialization before any
   sysfs file creation.
+  Drop client->id.
 
 * [Init] Limits must not be set by the driver (can be done later in
   user-space). Chip should not be reset default (although a module
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -344,9 +344,6 @@ detection just fails for this address, r
 
 For now, you can ignore the `flags' parameter. It is there for future use.
 
-  /* Unique ID allocation */
-  static int foo_id = 0;
-
   int foo_detect_client(struct i2c_adapter *adapter, int address, 
                         unsigned short flags, int kind)
   {
@@ -482,7 +479,6 @@ For now, you can ignore the `flags' para
     data->type = kind;
     /* SENSORS ONLY END */
 
-    new_client->id = foo_id++; /* Automatically unique */
     data->valid = 0; /* Only if you use this field */
     init_MUTEX(&data->update_lock); /* Only if you use this field */
 
@@ -642,7 +638,7 @@ contains the i2c address, so you do not 
 parameter contains the bytes the read/write, the third the length of the
 buffer. Returned is the actual number of bytes read/written.
   
-  extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+  extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,
                           int num);
 
 This sends a series of messages. Each message can be a read or write,
diff --git a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt
--- a/Documentation/i386/zero-page.txt
+++ b/Documentation/i386/zero-page.txt
@@ -79,6 +79,6 @@ Offset	Type		Description
 0x22c   unsigned long	ramdisk_max
 0x230   16 bytes 	trampoline
 0x290 - 0x2cf		EDD_MBR_SIG_BUFFER (edd.S)
-0x2d0 - 0x600		E820MAP
-0x600 - 0x7ff		EDDBUF (edd.S) for disk signature read sector
-0x600 - 0x7eb		EDDBUF (edd.S) for edd data
+0x2d0 - 0xd00		E820MAP
+0xd00 - 0xeff		EDDBUF (edd.S) for disk signature read sector
+0xd00 - 0xeeb		EDDBUF (edd.S) for edd data
diff --git a/Documentation/infiniband/ipoib.txt b/Documentation/infiniband/ipoib.txt
--- a/Documentation/infiniband/ipoib.txt
+++ b/Documentation/infiniband/ipoib.txt
@@ -32,14 +32,13 @@ Debugging Information
   mcast_debug_level to 1.  These parameters can be controlled at
   runtime through files in /sys/module/ib_ipoib/.
 
-  CONFIG_INFINIBAND_IPOIB_DEBUG also enables the "ipoib_debugfs"
+  CONFIG_INFINIBAND_IPOIB_DEBUG also enables files in the debugfs
   virtual filesystem.  By mounting this filesystem, for example with
 
-    mkdir -p /ipoib_debugfs
-    mount -t ipoib_debugfs none /ipoib_debufs
+    mount -t debugfs none /sys/kernel/debug
 
   it is possible to get statistics about multicast groups from the
-  files /ipoib_debugfs/ib0_mcg and so on.
+  files /sys/kernel/debug/ipoib/ib0_mcg and so on.
 
   The performance impact of this option is negligible, so it
   is safe to enable this option with debug_level set to 0 for normal
diff --git a/Documentation/ioctl/hdio.txt b/Documentation/ioctl/hdio.txt
--- a/Documentation/ioctl/hdio.txt
+++ b/Documentation/ioctl/hdio.txt
@@ -573,26 +573,43 @@ HDIO_DRIVE_TASKFILE		execute raw taskfil
 	  EFAULT	req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
 	  EPERM		req_cmd == TASKFILE_MULTI_OUT and drive
 	  		multi-count not yet set.
-
+	  EIO		Drive failed the command.
 
 	notes:
 
-	  [1] Currently (2.6.8), both the input and output buffers are
-	  copied from the user and written back to the user, even when
-	  not used.  This may be a bug.
-
-	  [2] The out_flags and in_flags are returned to the user after
-	  the ioctl completes.	Currently (2.6.8) these are the same
-	  as the input values, unchanged.  In the future, they may have
-	  more significance.
-
-	  Extreme caution should be used with using this ioctl.  A
-	  mistake can easily corrupt data or hang the system.
-
-	  The argument to the ioctl is a pointer to a region of memory
-	  containing a ide_task_request_t structure, followed by an
-	  optional buffer of data to be transmitted to the drive,
-	  followed by an optional buffer to receive data from the drive.
+	  [1] READ THE FOLLOWING NOTES *CAREFULLY*.  THIS IOCTL IS
+	  FULL OF GOTCHAS.  Extreme caution should be used with using
+	  this ioctl.  A mistake can easily corrupt data or hang the
+	  system.
+
+	  [2] Both the input and output buffers are copied from the
+	  user and written back to the user, even when not used.
+
+	  [3] If one or more bits are set in out_flags and in_flags is
+	  zero, the following values are used for in_flags.all and
+	  written back into in_flags on completion.
+
+	   * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8)
+	     if LBA48 addressing is enabled for the drive
+	   * IDE_TASKFILE_STD_IN_FLAGS
+	     if CHS/LBA28
+
+	  The association between in_flags.all and each enable
+	  bitfield flips depending on endianess; fortunately, TASKFILE
+	  only uses inflags.b.data bit and ignores all other bits.
+	  The end result is that, on any endian machines, it has no
+	  effect other than modifying in_flags on completion.
+
+	  [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit)
+	  except for four drives per port chipsets.  For four drives
+	  per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first
+	  pair and (0x80|DEV_bit|LBA_bit) for the second pair.
+
+	  [5] The argument to the ioctl is a pointer to a region of
+	  memory containing a ide_task_request_t structure, followed
+	  by an optional buffer of data to be transmitted to the
+	  drive, followed by an optional buffer to receive data from
+	  the drive.
 
 	  Command is passed to the disk drive via the ide_task_request_t
 	  structure, which contains these fields:
@@ -611,11 +628,66 @@ HDIO_DRIVE_TASKFILE		execute raw taskfil
 	    out_size		output (user->drive) buffer size, bytes
 	    in_size		input (drive->user) buffer size, bytes
 
-	  This ioctl does not necessarily respect all flags in the
-	  out_flags and in_flags values -- some taskfile registers
-	  may be written or read even if not requested in the flags.
-	  Unused fields of io_ports[] and hob_ports[] should be set
-	  to zero.
+	  When out_flags is zero, the following registers are loaded.
+
+	    HOB_FEATURE		If the drive supports LBA48
+	    HOB_NSECTOR		If the drive supports LBA48
+	    HOB_SECTOR		If the drive supports LBA48
+	    HOB_LCYL		If the drive supports LBA48
+	    HOB_HCYL		If the drive supports LBA48
+	    FEATURE
+	    NSECTOR
+	    SECTOR
+	    LCYL
+	    HCYL
+	    SELECT		First, masked with 0xE0 if LBA48, 0xEF
+				otherwise; then, or'ed with the default
+				value of SELECT.
+
+	  If any bit in out_flags is set, the following registers are loaded.
+
+	    HOB_DATA		If out_flags.b.data is set.  HOB_DATA will
+				travel on DD8-DD15 on little endian machines
+				and on DD0-DD7 on big endian machines.
+	    DATA		If out_flags.b.data is set.  DATA will
+				travel on DD0-DD7 on little endian machines
+				and on DD8-DD15 on big endian machines.
+	    HOB_NSECTOR		If out_flags.b.nsector_hob is set
+	    HOB_SECTOR		If out_flags.b.sector_hob is set
+	    HOB_LCYL		If out_flags.b.lcyl_hob is set
+	    HOB_HCYL		If out_flags.b.hcyl_hob is set
+	    FEATURE		If out_flags.b.feature is set
+	    NSECTOR		If out_flags.b.nsector is set
+	    SECTOR		If out_flags.b.sector is set
+	    LCYL		If out_flags.b.lcyl is set
+	    HCYL		If out_flags.b.hcyl is set
+	    SELECT		Or'ed with the default value of SELECT and
+				loaded regardless of out_flags.b.select.
+
+	  Taskfile registers are read back from the drive into
+	  {io|hob}_ports[] after the command completes iff one of the
+	  following conditions is met; otherwise, the original values
+	  will be written back, unchanged.
+
+	    1. The drive fails the command (EIO).
+	    2. One or more than one bits are set in out_flags.
+	    3. The requested data_phase is TASKFILE_NO_DATA.
+
+	    HOB_DATA		If in_flags.b.data is set.  It will contain
+				DD8-DD15 on little endian machines and
+				DD0-DD7 on big endian machines.
+	    DATA		If in_flags.b.data is set.  It will contain
+				DD0-DD7 on little endian machines and
+				DD8-DD15 on big endian machines.
+	    HOB_FEATURE		If the drive supports LBA48
+	    HOB_NSECTOR		If the drive supports LBA48
+	    HOB_SECTOR		If the drive supports LBA48
+	    HOB_LCYL		If the drive supports LBA48
+	    HOB_HCYL		If the drive supports LBA48
+	    NSECTOR
+	    SECTOR
+	    LCYL
+	    HCYL
 
 	  The data_phase field describes the data transfer to be
 	  performed.  Value is one of:
@@ -626,27 +698,30 @@ HDIO_DRIVE_TASKFILE		execute raw taskfil
 	    TASKFILE_MULTI_OUT
 	    TASKFILE_IN_OUT
 	    TASKFILE_IN_DMA
-	    TASKFILE_IN_DMAQ
+	    TASKFILE_IN_DMAQ		== IN_DMA (queueing not supported)
 	    TASKFILE_OUT_DMA
-	    TASKFILE_OUT_DMAQ
-	    TASKFILE_P_IN
-	    TASKFILE_P_IN_DMA
-	    TASKFILE_P_IN_DMAQ
-	    TASKFILE_P_OUT
-	    TASKFILE_P_OUT_DMA
-	    TASKFILE_P_OUT_DMAQ
+	    TASKFILE_OUT_DMAQ		== OUT_DMA (queueing not supported)
+	    TASKFILE_P_IN		unimplemented
+	    TASKFILE_P_IN_DMA		unimplemented
+	    TASKFILE_P_IN_DMAQ		unimplemented
+	    TASKFILE_P_OUT		unimplemented
+	    TASKFILE_P_OUT_DMA		unimplemented
+	    TASKFILE_P_OUT_DMAQ		unimplemented
 
 	  The req_cmd field classifies the command type.  It may be
 	  one of:
 
 	    IDE_DRIVE_TASK_NO_DATA
-	    IDE_DRIVE_TASK_SET_XFER
+	    IDE_DRIVE_TASK_SET_XFER	unimplemented
 	    IDE_DRIVE_TASK_IN
-	    IDE_DRIVE_TASK_OUT
+	    IDE_DRIVE_TASK_OUT		unimplemented
 	    IDE_DRIVE_TASK_RAW_WRITE
 
-
-
+	  [6] Do not access {in|out}_flags->all except for resetting
+	  all the bits.  Always access individual bit fields.  ->all
+	  value will flip depending on endianess.  For the same
+	  reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS
+	  constants defined in hdreg.h.
 
 
 
@@ -663,7 +738,13 @@ HDIO_DRIVE_CMD			execute a special drive
 
 	inputs:
 
-	  Taskfile register values:
+	  Commands other than WIN_SMART
+	    args[0]	COMMAND
+	    args[1]	NSECTOR
+	    args[2]	FEATURE
+	    args[3]	NSECTOR
+
+	  WIN_SMART
 	    args[0]	COMMAND
 	    args[1]	SECTOR
 	    args[2]	FEATURE
@@ -682,11 +763,28 @@ HDIO_DRIVE_CMD			execute a special drive
 	error returns:
 	  EACCES	Access denied:  requires CAP_SYS_RAWIO
 	  ENOMEM	Unable to allocate memory for task
+	  EIO		Drive reports error
 
 	notes:
 
-	  Taskfile registers IDE_LCYL, IDE_HCYL, and IDE_SELECT are
-	  set to zero before executing the command.
+	  [1] For commands other than WIN_SMART, args[1] should equal
+	  args[3].  SECTOR, LCYL and HCYL are undefined.  For
+	  WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL
+	  respectively.  In both cases SELECT will contain the default
+	  value for the drive.  Please refer to HDIO_DRIVE_TASKFILE
+	  notes for the default value of SELECT.
+
+	  [2] If NSECTOR value is greater than zero and the drive sets
+	  DRQ when interrupting for the command, NSECTOR * 512 bytes
+	  are read from the device into the area following NSECTOR.
+	  In the above example, the area would be
+	  args[4..4+XFER_SIZE].  16bit PIO is used regardless of
+	  HDIO_SET_32BIT setting.
+
+	  [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER
+	  && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA
+	  mode, IDE driver will try to tune the transfer mode of the
+	  drive accordingly.
 
 
 
@@ -726,7 +824,14 @@ HDIO_DRIVE_TASK			execute task and speci
 	error returns:
 	  EACCES	Access denied:  requires CAP_SYS_RAWIO
 	  ENOMEM	Unable to allocate memory for task
+	  ENOMSG	Device is not a disk drive.
+	  EIO		Drive failed the command.
+
+	notes:
 
+	  [1] DEV bit (0x10) of SELECT register is ignored and the
+	  appropriate value for the drive is used.  All other bits
+	  are used unaltered.
 
 
 
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -48,7 +48,7 @@ Menu attributes
 A menu entry can have a number of attributes. Not all of them are
 applicable everywhere (see syntax).
 
-- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
+- type definition: "bool"/"tristate"/"string"/"hex"/"int"
   Every config option must have a type. There are only two basic types:
   tristate and string, the other types are based on these two. The type
   definition optionally accepts an input prompt, so these two examples
@@ -100,7 +100,7 @@ applicable everywhere (see syntax).
   symbols.
 
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
-  This allows to limit the range of possible input values for integer
+  This allows to limit the range of possible input values for int
   and hex symbols. The user can only input a value which is larger than
   or equal to the first symbol and smaller than or equal to the second
   symbol.
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -39,6 +39,13 @@
    
      ON-LINE DOCS:
        
+     * Title: "Linux Device Drivers, Third Edition"
+       Author: Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman
+       URL: http://lwn.net/Kernel/LDD3/
+       Description: A 600-page book covering the (2.6.10) driver
+       programming API and kernel hacking in general.  Available under the
+       Creative Commons Attribution-ShareAlike 2.0 license.
+
      * Title: "The Linux Kernel"
        Author: David A. Rusling.
        URL: http://www.tldp.org/LDP/tlk/tlk.html
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -67,17 +67,22 @@ restrictions referred to are that the re
 	SCSI	Appropriate SCSI support is enabled.
 			A lot of drivers has their options described inside of
 			Documentation/scsi/.
+	SELINUX SELinux support is enabled.
 	SERIAL	Serial support is enabled.
 	SMP	The kernel is an SMP kernel.
 	SPARC	Sparc architecture is enabled.
 	SWSUSP	Software suspension is enabled.
 	TS	Appropriate touchscreen support is enabled.
 	USB	USB support is enabled.
+	USBHID	USB Human Interface Device support is enabled.
 	V4L	Video For Linux support is enabled.
 	VGA	The VGA console has been enabled.
 	VT	Virtual terminal support is enabled.
 	WDT	Watchdog support is enabled.
 	XT	IBM PC/XT MFM hard disk support is enabled.
+	X86-64	X86-64 architecture is enabled.
+			More X86-64 boot options can be found in
+			Documentation/x86_64/boot-options.txt .
 
 In addition, the following text indicates that the option:
 
@@ -295,6 +300,14 @@ running once the system is up.
 			See header of drivers/cdrom/cdu31a.c.
 
 	chandev=	[HW,NET] Generic channel device initialisation
+
+	checkreqprot	[SELINUX] Set initial checkreqprot flag value.
+			Format: { "0" | "1" }
+			See security/selinux/Kconfig help text.
+			0 -- check protection applied by kernel (includes any implied execute protection).
+			1 -- check protection requested by application.
+			Default value is set via a kernel config option.
+			Value can be changed at runtime via /selinux/checkreqprot.
  
  	clock=		[BUGS=IA-32, HW] gettimeofday timesource override. 
 			Forces specified timesource (if avaliable) to be used
@@ -393,7 +406,7 @@ running once the system is up.
 
 	dtc3181e=	[HW,SCSI]
 
-	earlyprintk=	[x86, x86_64]
+	earlyprintk=	[IA-32, X86-64]
 			earlyprintk=vga
 			earlyprintk=serial[,ttySn[,baudrate]]
 
@@ -435,6 +448,14 @@ running once the system is up.
 			See Documentation/block/as-iosched.txt
 			and Documentation/block/deadline-iosched.txt for details.
 
+	enforcing	[SELINUX] Set initial enforcing status.
+			Format: {"0" | "1"}
+			See security/selinux/Kconfig help text.
+			0 -- permissive (log only, no denials).
+			1 -- enforcing (deny and log).
+			Default value is 0.
+			Value can be changed at runtime via /selinux/enforce.
+
 	es1370=		[HW,OSS]
 			Format: <lineout>[,<micbias>]
 			See also header of sound/oss/es1370.c.
@@ -514,11 +535,14 @@ running once the system is up.
 	i8042.dumbkbd	[HW] Pretend that controlled can only read data from
 			     keyboard and can not control its state
 			     (Don't attempt to blink the leds)
-	i8042.noacpi	[HW] Don't use ACPI to discover KBD/AUX controller
-			     settings
 	i8042.noaux	[HW] Don't check for auxiliary (== mouse) port
 	i8042.nomux	[HW] Don't check presence of an active multiplexing
 			     controller
+	i8042.nopnp	[HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
+			     controllers
+	i8042.panicblink=
+			[HW] Frequency with which keyboard LEDs should blink
+			     when kernel panics (default is 0.5 sec)
 	i8042.reset	[HW] Reset the controller during init and cleanup
 	i8042.unlock	[HW] Unlock (ignore) the keylock
 
@@ -614,6 +638,9 @@ running once the system is up.
 
 	keepinitrd	[HW,ARM]
 
+	kstack=N	[IA-32, X86-64] Print N words from the kernel stack
+			in oops dumps.
+
 	l2cr=		[PPC]
 
 	lapic		[IA-32,APIC] Enable the local APIC even if BIOS disabled it.
@@ -634,6 +661,20 @@ running once the system is up.
 	logibm.irq=	[HW,MOUSE] Logitech Bus Mouse Driver
 			Format: <irq>
 
+	loglevel=	All Kernel Messages with a loglevel smaller than the
+			console loglevel will be printed to the console. It can
+			also be changed with klogd or other programs. The
+			loglevels are defined as follows:
+
+			0 (KERN_EMERG)		system is unusable
+			1 (KERN_ALERT)		action must be taken immediately
+			2 (KERN_CRIT)		critical conditions
+			3 (KERN_ERR)		error conditions
+			4 (KERN_WARNING)	warning conditions
+			5 (KERN_NOTICE)		normal but significant condition
+			6 (KERN_INFO)		informational
+			7 (KERN_DEBUG)		debug-level messages
+
 	log_buf_len=n	Sets the size of the printk ring buffer, in bytes.
 			Format is n, nk, nM.  n must be a power of two.  The
 			default is set in kernel config.
@@ -776,6 +817,10 @@ running once the system is up.
 	mtdparts=	[MTD]
 			See drivers/mtd/cmdline.c.
 
+	mtouchusb.raw_coordinates=
+			[HW] Make the MicroTouch USB driver use raw coordinates ('y', default)
+			or cooked coordinates ('n')
+
 	n2=		[NET] SDL Inc. RISCom/N2 synchronous serial card
 
 	NCR_D700=	[HW,SCSI]
@@ -825,7 +870,7 @@ running once the system is up.
 
 	noexec		[IA-64]
 
-	noexec		[i386, x86_64]
+	noexec		[IA-32, X86-64]
 			noexec=on: enable non-executable mappings (default)
 			noexec=off: disable nn-executable mappings
 
@@ -837,6 +882,13 @@ running once the system is up.
 			instruction doesn't work correctly and not to
 			use it.
 
+	nohalt		[IA-64] Tells the kernel not to use the power saving
+			function PAL_HALT_LIGHT when idle. This increases
+			power-consumption. On the positive side, it reduces
+			interrupt wake-up latency, which may improve performance
+			in certain environments such as networked servers or
+			real-time systems.
+
 	noirqdebug	[IA-32] Disables the code which attempts to detect and
 			disable unhandled interrupt sources.
 
@@ -1146,10 +1198,16 @@ running once the system is up.
 
 	scsi_logging=	[SCSI]
 
-	serialnumber	[BUGS=IA-32]
+	selinux		[SELINUX] Disable or enable SELinux at boot time.
+			Format: { "0" | "1" }
+			See security/selinux/Kconfig help text.
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+			If enabled at boot time, /selinux/disable can be used
+			later to disable prior to initial policy load.
 
-	sf16fm=		[HW] SF16FMI radio driver for Linux
-			Format: <io>
+	serialnumber	[BUGS=IA-32]
 
 	sg_def_reserved_size=
 			[SCSI]
@@ -1345,9 +1403,6 @@ running once the system is up.
 	sym53c416=	[HW,SCSI]
 			See header of drivers/scsi/sym53c416.c.
 
-	sym53c8xx=	[HW,SCSI]
-			See Documentation/scsi/ncr53c8xx.txt.
-
 	t128=		[HW,SCSI]
 			See header of drivers/scsi/t128.c.
 
@@ -1356,6 +1411,8 @@ running once the system is up.
 	thash_entries=	[KNL,NET]
 			Set number of hash buckets for TCP connection
 
+	time		Show timing data prefixed to each printk message line
+
 	tipar.timeout=	[HW,PPT]
 			Set communications timeout in tenths of a second
 			(default 15).
@@ -1393,6 +1450,9 @@ running once the system is up.
 			Format: <io>,<irq>
 
 	usb-handoff	[HW] Enable early USB BIOS -> OS handoff
+
+	usbhid.mousepoll=
+			[USBHID] The interval which mice are to be polled at.
  
 	video=		[FB] Frame buffer configuration
 			See Documentation/fb/modedb.txt.
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -151,8 +151,8 @@ The key service provides a number of fea
      by using PR_JOIN_SESSION_KEYRING. It is permitted to request an anonymous
      new one, or to attempt to create or join one of a specific name.
 
-     The ownership of the thread and process-specific keyrings changes when
-     the real UID and GID of the thread changes.
+     The ownership of the thread keyring changes when the real UID and GID of
+     the thread changes.
 
  (*) Each user ID resident in the system holds two special keyrings: a user
      specific keyring and a default user session keyring. The default session
@@ -606,8 +606,12 @@ open call, and the key released upon clo
 due to two different users opening the same file is left to the filesystem
 author to solve.
 
-When accessing a key's payload data, the key->lock should be at least read
-locked, or else the data may be changed by update during the access.
+When accessing a key's payload data, key->lock should be at least read locked,
+or else the data may be changed by an update being performed from userspace
+whilst the driver or filesystem is trying to access it. If no update method is
+supplied, then the key's payload may be accessed without holding a lock as
+there is no way to change it, provided it can be guaranteed that the key's
+type definition won't go away.
 
 (*) To search for a key, call:
 
@@ -719,13 +723,19 @@ The structure has a number of fields, so
 
  (*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
 
-     This method is called to attach a payload to a key during
-     construction. The payload attached need not bear any relation to the data
-     passed to this function.
+     This method is called to attach a payload to a key during construction.
+     The payload attached need not bear any relation to the data passed to
+     this function.
 
      If the amount of data attached to the key differs from the size in
      keytype->def_datalen, then key_payload_reserve() should be called.
 
+     This method does not have to lock the key in order to attach a payload.
+     The fact that KEY_FLAG_INSTANTIATED is not set in key->flags prevents
+     anything else from gaining access to the key.
+
+     This method may sleep if it wishes.
+
 
  (*) int (*duplicate)(struct key *key, const struct key *source);
 
@@ -734,8 +744,8 @@ The structure has a number of fields, so
      the new key. The data length on the new key will have been updated and
      the quota adjusted already.
 
-     The source key will be locked against change on the source->sem, so it is
-     safe to sleep here.
+     This method will be called with the source key's semaphore read-locked to
+     prevent its payload from being changed. It is safe to sleep here.
 
 
  (*) int (*update)(struct key *key, const void *data, size_t datalen);
@@ -749,30 +759,47 @@ The structure has a number of fields, so
      type is committed to changing the key because it's already been altered,
      so all memory allocation must be done first.
 
-     The key will be locked against other changers on key->sem, so it is safe
-     to sleep here.
-
      key_payload_reserve() should be called with the key->lock write locked,
      and the changes to the key's attached payload should be made before the
      key is locked.
 
+     The key will have its semaphore write-locked before this method is
+     called. Any changes to the key should be made with the key's rwlock
+     write-locked also. It is safe to sleep here.
+
 
  (*) int (*match)(const struct key *key, const void *desc);
 
      This method is called to match a key against a description. It should
      return non-zero if the two match, zero if they don't.
 
+     This method should not need to lock the key in any way. The type and
+     description can be considered invariant, and the payload should not be
+     accessed (the key may not yet be instantiated).
+
+     It is not safe to sleep in this method; the caller may hold spinlocks.
+
 
  (*) void (*destroy)(struct key *key);
 
      This method is optional. It is called to discard the payload data on a
      key when it is being destroyed.
 
+     This method does not need to lock the key; it can consider the key as
+     being inaccessible. Note that the key's type may have changed before this
+     function is called.
+
+     It is not safe to sleep in this method; the caller may hold spinlocks.
+
 
  (*) void (*describe)(const struct key *key, struct seq_file *p);
 
      This method is optional. It is called during /proc/keys reading to
-     summarise a key in text form.
+     summarise a key's description and payload in text form.
+
+     This method will be called with the key's rwlock read-locked. This will
+     prevent the key's payload and state changing; also the description should
+     not change. This also means it is not safe to sleep in this method.
 
 
  (*) long (*read)(const struct key *key, char __user *buffer, size_t buflen);
@@ -785,6 +812,12 @@ The structure has a number of fields, so
      If successful, the blob size that could be produced should be returned
      rather than the size copied.
 
+     This method will be called with the key's semaphore read-locked. This
+     will prevent the key's payload changing. It is not necessary to also
+     read-lock key->lock when accessing the key's payload. It is safe to sleep
+     in this method, such as might happen when the userspace buffer is
+     accessed.
+
 
 ============================
 REQUEST-KEY CALLBACK SERVICE
diff --git a/Documentation/kref.txt b/Documentation/kref.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/kref.txt
@@ -0,0 +1,216 @@
+
+krefs allow you to add reference counters to your objects.  If you
+have objects that are used in multiple places and passed around, and
+you don't have refcounts, your code is almost certainly broken.  If
+you want refcounts, krefs are the way to go.
+
+To use a kref, add one to your data structures like:
+
+struct my_data
+{
+	.
+	.
+	struct kref refcount;
+	.
+	.
+};
+
+The kref can occur anywhere within the data structure.
+
+You must initialize the kref after you allocate it.  To do this, call
+kref_init as so:
+
+     struct my_data *data;
+
+     data = kmalloc(sizeof(*data), GFP_KERNEL);
+     if (!data)
+            return -ENOMEM;
+     kref_init(&data->refcount);
+
+This sets the refcount in the kref to 1.
+
+Once you have an initialized kref, you must follow the following
+rules:
+
+1) If you make a non-temporary copy of a pointer, especially if
+   it can be passed to another thread of execution, you must
+   increment the refcount with kref_get() before passing it off:
+       kref_get(&data->refcount);
+   If you already have a valid pointer to a kref-ed structure (the
+   refcount cannot go to zero) you may do this without a lock.
+
+2) When you are done with a pointer, you must call kref_put():
+       kref_put(&data->refcount, data_release);
+   If this is the last reference to the pointer, the release
+   routine will be called.  If the code never tries to get
+   a valid pointer to a kref-ed structure without already
+   holding a valid pointer, it is safe to do this without
+   a lock.
+
+3) If the code attempts to gain a reference to a kref-ed structure
+   without already holding a valid pointer, it must serialize access
+   where a kref_put() cannot occur during the kref_get(), and the
+   structure must remain valid during the kref_get().
+
+For example, if you allocate some data and then pass it to another
+thread to process:
+
+void data_release(struct kref *ref)
+{
+	struct my_data *data = container_of(ref, struct my_data, refcount);
+	kfree(data);
+}
+
+void more_data_handling(void *cb_data)
+{
+	struct my_data *data = cb_data;
+	.
+	. do stuff with data here
+	.
+	kref_put(data, data_release);
+}
+
+int my_data_handler(void)
+{
+	int rv = 0;
+	struct my_data *data;
+	struct task_struct *task;
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	kref_init(&data->refcount);
+
+	kref_get(&data->refcount);
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+	        kref_put(&data->refcount, data_release);
+		goto out;
+	}
+
+	.
+	. do stuff with data here
+	.
+ out:
+	kref_put(&data->refcount, data_release);
+	return rv;
+}
+
+This way, it doesn't matter what order the two threads handle the
+data, the kref_put() handles knowing when the data is not referenced
+any more and releasing it.  The kref_get() does not require a lock,
+since we already have a valid pointer that we own a refcount for.  The
+put needs no lock because nothing tries to get the data without
+already holding a pointer.
+
+Note that the "before" in rule 1 is very important.  You should never
+do something like:
+
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+		goto out;
+	} else
+		/* BAD BAD BAD - get is after the handoff */
+		kref_get(&data->refcount);
+
+Don't assume you know what you are doing and use the above construct.
+First of all, you may not know what you are doing.  Second, you may
+know what you are doing (there are some situations where locking is
+involved where the above may be legal) but someone else who doesn't
+know what they are doing may change the code or copy the code.  It's
+bad style.  Don't do it.
+
+There are some situations where you can optimize the gets and puts.
+For instance, if you are done with an object and enqueuing it for
+something else or passing it off to something else, there is no reason
+to do a get then a put:
+
+	/* Silly extra get and put */
+	kref_get(&obj->ref);
+	enqueue(obj);
+	kref_put(&obj->ref, obj_cleanup);
+
+Just do the enqueue.  A comment about this is always welcome:
+
+	enqueue(obj);
+	/* We are done with obj, so we pass our refcount off
+	   to the queue.  DON'T TOUCH obj AFTER HERE! */
+
+The last rule (rule 3) is the nastiest one to handle.  Say, for
+instance, you have a list of items that are each kref-ed, and you wish
+to get the first one.  You can't just pull the first item off the list
+and kref_get() it.  That violates rule 3 because you are not already
+holding a valid pointer.  You must add locks or semaphores.  For
+instance:
+
+static DECLARE_MUTEX(sem);
+static LIST_HEAD(q);
+struct my_data
+{
+	struct kref      refcount;
+	struct list_head link;
+};
+
+static struct my_data *get_entry()
+{
+	struct my_data *entry = NULL;
+	down(&sem);
+	if (!list_empty(&q)) {
+		entry = container_of(q.next, struct my_q_entry, link);
+		kref_get(&entry->refcount);
+	}
+	up(&sem);
+	return entry;
+}
+
+static void release_entry(struct kref *ref)
+{
+	struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+	list_del(&entry->link);
+	kfree(entry);
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	kref_put(&entry->refcount, release_entry);
+	up(&sem);
+}
+
+The kref_put() return value is useful if you do not want to hold the
+lock during the whole release operation.  Say you didn't want to call
+kfree() with the lock held in the example above (since it is kind of
+pointless to do so).  You could use kref_put() as follows:
+
+static void release_entry(struct kref *ref)
+{
+	/* All work is done after the return from kref_put(). */
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	if (kref_put(&entry->refcount, release_entry)) {
+		list_del(&entry->link);
+		up(&sem);
+		kfree(entry);
+	} else
+		up(&sem);
+}
+
+This is really more useful if you have to call other routines as part
+of the free operations that could take a long time or might claim the
+same lock.  Note that doing everything in the release routine is still
+preferred as it is a little neater.
+
+
+Corey Minyard <minyard@acm.org>
+
+A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
+presentation on krefs, which can be found at:
+  http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+and:
+  http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
diff --git a/Documentation/networking/DLINK.txt b/Documentation/networking/DLINK.txt
--- a/Documentation/networking/DLINK.txt
+++ b/Documentation/networking/DLINK.txt
@@ -178,10 +178,9 @@ Released 1994-06-13
 	7. ACKNOWLEDGMENTS.
 
 	These drivers wouldn't have been done without the base
-	(and support) from Ross Biro <bir7@leland.stanford.edu>,
-	and D-Link Systems Inc.  The driver relies upon GPL-ed
-	source from D-Link Systems Inc. and from Russel Nelson at
-	Crynwr Software <nelson@crynwr.com>.
+	(and support) from Ross Biro, and D-Link Systems Inc.
+	The driver relies upon GPL-ed source from D-Link Systems Inc.
+	and from Russel Nelson at Crynwr Software <nelson@crynwr.com>.
 
 	Additional input also from:
 	Donald Becker <becker@super.org>, Alan Cox <A.Cox@swansea.ac.uk>
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -1,5 +1,5 @@
 
-                   Linux Ethernet Bonding Driver mini-howto
+                   Linux Ethernet Bonding Driver HOWTO
 
 Initial release : Thomas Davis <tadavis at lbl.gov>
 Corrections, HA extensions : 2000/10/03-15 :
@@ -9,8 +9,11 @@ Corrections, HA extensions : 2000/10/03-
   - Janice Girouard <girouard at us dot ibm dot com>
   - Jay Vosburgh <fubar at us dot ibm dot com>
 
+Reorganized and updated Feb 2005 by Jay Vosburgh
+
 Note :
 ------
+	
 The bonding driver originally came from Donald Becker's beowulf patches for
 kernel 2.0. It has changed quite a bit since, and the original tools from
 extreme-linux and beowulf sites will not work with this version of the driver.
@@ -18,218 +21,190 @@ extreme-linux and beowulf sites will not
 For new versions of the driver, patches for older kernels and the updated
 userspace tools, please follow the links at the end of this file.
 
-
 Table of Contents
 =================
 
-Installation
-Bond Configuration
-Module Parameters
-Configuring Multiple Bonds
-Switch Configuration
-Verifying Bond Configuration
-Frequently Asked Questions
-High Availability
-Promiscuous Sniffing notes
-8021q VLAN support
-Limitations
-Resources and Links
-
-
-Installation
-============
-
-1) Build kernel with the bonding driver
----------------------------------------
-For the latest version of the bonding driver, use kernel 2.4.12 or above
-(otherwise you will need to apply a patch).
-
-Configure kernel with `make menuconfig/xconfig/config', and select "Bonding
-driver support" in the "Network device support" section. It is recommended
-to configure the driver as module since it is currently the only way to
-pass parameters to the driver and configure more than one bonding device.
-
-Build and install the new kernel and modules.
-
-2) Get and install the userspace tools
---------------------------------------
-This version of the bonding driver requires updated ifenslave program. The
-original one from extreme-linux and beowulf will not work. Kernels 2.4.12
-and above include the updated version of ifenslave.c in
-Documentation/networking directory. For older kernels, please follow the
-links at the end of this file.
-
-IMPORTANT!!!  If you are running on Redhat 7.1 or greater, you need
-to be careful because /usr/include/linux is no longer a symbolic link
-to /usr/src/linux/include/linux.  If you build ifenslave while this is
-true, ifenslave will appear to succeed but your bond won't work.  The purpose
-of the -I option on the ifenslave compile line is to make sure it uses
-/usr/src/linux/include/linux/if_bonding.h instead of the version from
-/usr/include/linux.
-
-To install ifenslave.c, do:
-    # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave
-    # cp ifenslave /sbin/ifenslave
+1. Bonding Driver Installation
 
+2. Bonding Driver Options
 
-Bond Configuration
-==================
+3. Configuring Bonding Devices
+3.1	Configuration with sysconfig support
+3.2	Configuration with initscripts support
+3.3	Configuring Bonding Manually
+3.4	Configuring Multiple Bonds
 
-You will need to add at least the following line to /etc/modprobe.conf
-so the bonding driver will automatically load when the bond0 interface is
-configured. Refer to the modprobe.conf manual page for specific modprobe.conf
-syntax details. The Module Parameters section of this document describes each
-bonding driver parameter.
-
-	alias bond0 bonding
-
-Use standard distribution techniques to define the bond0 network interface. For
-example, on modern Red Hat distributions, create an ifcfg-bond0 file in
-the /etc/sysconfig/network-scripts directory that resembles the following:
+5. Querying Bonding Configuration
+5.1	Bonding Configuration
+5.2	Network Configuration
 
-DEVICE=bond0
-IPADDR=192.168.1.1
-NETMASK=255.255.255.0
-NETWORK=192.168.1.0
-BROADCAST=192.168.1.255
-ONBOOT=yes
-BOOTPROTO=none
-USERCTL=no
+6. Switch Configuration
 
-(use appropriate values for your network above)
+7. 802.1q VLAN Support
 
-All interfaces that are part of a bond should have SLAVE and MASTER
-definitions. For example, in the case of Red Hat, if you wish to make eth0 and
-eth1 a part of the bonding interface bond0, their config files (ifcfg-eth0 and
-ifcfg-eth1) should resemble the following:
+8. Link Monitoring
+8.1	ARP Monitor Operation
+8.2	Configuring Multiple ARP Targets
+8.3	MII Monitor Operation
 
-DEVICE=eth0
-USERCTL=no
-ONBOOT=yes
-MASTER=bond0
-SLAVE=yes
-BOOTPROTO=none
+9. Potential Trouble Sources
+9.1	Adventures in Routing
+9.2	Ethernet Device Renaming
+9.3	Painfully Slow Or No Failed Link Detection By Miimon
 
-Use DEVICE=eth1 in the ifcfg-eth1 config file. If you configure a second
-bonding interface (bond1), use MASTER=bond1 in the config file to make the
-network interface be a slave of bond1.
-
-Restart the networking subsystem or just bring up the bonding device if your
-administration tools allow it. Otherwise, reboot. On Red Hat distros you can
-issue `ifup bond0' or `/etc/rc.d/init.d/network restart'.
-
-If the administration tools of your distribution do not support
-master/slave notation in configuring network interfaces, you will need to
-manually configure the bonding device with the following commands:
-
-    # /sbin/ifconfig bond0 192.168.1.1 netmask 255.255.255.0 \
-      broadcast 192.168.1.255 up
-
-    # /sbin/ifenslave bond0 eth0
-    # /sbin/ifenslave bond0 eth1
-
-(use appropriate values for your network above)
-
-You can then create a script containing these commands and place it in the
-appropriate rc directory.
-
-If you specifically need all network drivers loaded before the bonding driver,
-adding the following line to modprobe.conf will cause the network driver for
-eth0 and eth1 to be loaded before the bonding driver.
-
-install bond0 /sbin/modprobe -a eth0 eth1 && /sbin/modprobe bonding
-
-Be careful not to reference bond0 itself at the end of the line, or modprobe
-will die in an endless recursive loop.
-
-If running SNMP agents, the bonding driver should be loaded before any network
-drivers participating in a bond. This requirement is due to the the interface
-index (ipAdEntIfIndex) being associated to the first interface found with a
-given IP address. That is, there is only one ipAdEntIfIndex for each IP
-address. For example, if eth0 and eth1 are slaves of bond0 and the driver for
-eth0 is loaded before the bonding driver, the interface for the IP address
-will be associated with the eth0 interface. This configuration is shown below,
-the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0
-in the ifDescr table (ifDescr.2).
+10. SNMP agents
 
-     interfaces.ifTable.ifEntry.ifDescr.1 = lo
-     interfaces.ifTable.ifEntry.ifDescr.2 = eth0
-     interfaces.ifTable.ifEntry.ifDescr.3 = eth1
-     interfaces.ifTable.ifEntry.ifDescr.4 = eth2
-     interfaces.ifTable.ifEntry.ifDescr.5 = eth3
-     interfaces.ifTable.ifEntry.ifDescr.6 = bond0
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 5
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 4
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+11. Promiscuous mode
 
-This problem is avoided by loading the bonding driver before any network
-drivers participating in a bond. Below is an example of loading the bonding
-driver first, the IP address 192.168.1.1 is correctly associated with
-ifDescr.2.
+12. High Availability Information
+12.1	High Availability in a Single Switch Topology
+12.1.1		Bonding Mode Selection for Single Switch Topology
+12.1.2		Link Monitoring for Single Switch Topology
+12.2	High Availability in a Multiple Switch Topology
+12.2.1		Bonding Mode Selection for Multiple Switch Topology
+12.2.2		Link Monitoring for Multiple Switch Topology
+12.3	Switch Behavior Issues for High Availability
 
-     interfaces.ifTable.ifEntry.ifDescr.1 = lo
-     interfaces.ifTable.ifEntry.ifDescr.2 = bond0
-     interfaces.ifTable.ifEntry.ifDescr.3 = eth0
-     interfaces.ifTable.ifEntry.ifDescr.4 = eth1
-     interfaces.ifTable.ifEntry.ifDescr.5 = eth2
-     interfaces.ifTable.ifEntry.ifDescr.6 = eth3
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 6
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 5
-     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+13. Hardware Specific Considerations
+13.1	IBM BladeCenter
 
-While some distributions may not report the interface name in ifDescr,
-the association between the IP address and IfIndex remains and SNMP
-functions such as Interface_Scan_Next will report that association.
+14. Frequently Asked Questions
 
+15. Resources and Links
 
-Module Parameters
-=================
 
-Optional parameters for the bonding driver can be supplied as command line
-arguments to the insmod command. Typically, these parameters are specified in
-the file /etc/modprobe.conf (see the manual page for modprobe.conf). The
-available bonding driver parameters are listed below. If a parameter is not
-specified the default value is used. When initially configuring a bond, it
-is recommended "tail -f /var/log/messages" be run in a separate window to
-watch for bonding driver error messages.
-
-It is critical that either the miimon or arp_interval and arp_ip_target
-parameters be specified, otherwise serious network degradation will occur
-during link failures.
+1. Bonding Driver Installation
+==============================
+
+	Most popular distro kernels ship with the bonding driver
+already available as a module and the ifenslave user level control
+program installed and ready for use. If your distro does not, or you
+have need to compile bonding from source (e.g., configuring and
+installing a mainline kernel from kernel.org), you'll need to perform
+the following steps:
+
+1.1 Configure and build the kernel with bonding
+-----------------------------------------------
+
+	The latest version of the bonding driver is available in the
+drivers/net/bonding subdirectory of the most recent kernel source
+(which is available on http://kernel.org).
+
+	Prior to the 2.4.11 kernel, the bonding driver was maintained
+largely outside the kernel tree; patches for some earlier kernels are
+available on the bonding sourceforge site, although those patches are
+still several years out of date.  Most users will want to use either
+the most recent kernel from kernel.org or whatever kernel came with
+their distro.
+
+	Configure kernel with "make menuconfig" (or "make xconfig" or
+"make config"), then select "Bonding driver support" in the "Network
+device support" section.  It is recommended that you configure the
+driver as module since it is currently the only way to pass parameters
+to the driver or configure more than one bonding device.
+
+	Build and install the new kernel and modules, then proceed to
+step 2.
+
+1.2 Install ifenslave Control Utility
+-------------------------------------
+
+	The ifenslave user level control program is included in the
+kernel source tree, in the file Documentation/networking/ifenslave.c.
+It is generally recommended that you use the ifenslave that
+corresponds to the kernel that you are using (either from the same
+source tree or supplied with the distro), however, ifenslave
+executables from older kernels should function (but features newer
+than the ifenslave release are not supported).  Running an ifenslave
+that is newer than the kernel is not supported, and may or may not
+work.
+
+	To install ifenslave, do the following:
+
+# gcc -Wall -O -I/usr/src/linux/include ifenslave.c -o ifenslave
+# cp ifenslave /sbin/ifenslave
+
+	If your kernel source is not in "/usr/src/linux," then replace
+"/usr/src/linux/include" in the above with the location of your kernel
+source include directory.
+
+	You may wish to back up any existing /sbin/ifenslave, or, for
+testing or informal use, tag the ifenslave to the kernel version
+(e.g., name the ifenslave executable /sbin/ifenslave-2.6.10).
+
+IMPORTANT NOTE:
+
+	If you omit the "-I" or specify an incorrect directory, you
+may end up with an ifenslave that is incompatible with the kernel
+you're trying to build it for.  Some distros (e.g., Red Hat from 7.1
+onwards) do not have /usr/include/linux symbolically linked to the
+default kernel source include directory.
+
+
+2. Bonding Driver Options
+=========================
+
+	Options for the bonding driver are supplied as parameters to
+the bonding module at load time.  They may be given as command line
+arguments to the insmod or modprobe command, but are usually specified
+in either the /etc/modprobe.conf configuration file, or in a
+distro-specific configuration file (some of which are detailed in the
+next section).
+
+	The available bonding driver parameters are listed below. If a
+parameter is not specified the default value is used.  When initially
+configuring a bond, it is recommended "tail -f /var/log/messages" be
+run in a separate window to watch for bonding driver error messages.
+
+	It is critical that either the miimon or arp_interval and
+arp_ip_target parameters be specified, otherwise serious network
+degradation will occur during link failures.  Very few devices do not
+support at least miimon, so there is really no reason not to use it.
+
+	Options with textual values will accept either the text name
+	or, for backwards compatibility, the option value.  E.g.,
+	"mode=802.3ad" and "mode=4" set the same mode.
+
+	The parameters are as follows:
 
 arp_interval
 
-        Specifies the ARP monitoring frequency in milli-seconds.
-        If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the
-        switch should be configured in a mode that evenly distributes packets
-        across all links - such as round-robin. If the switch is configured to
-        distribute the packets in an XOR fashion, all replies from the ARP
-        targets will be received on the same link which could cause the other
-        team members to fail. ARP monitoring should not be used in conjunction
-        with miimon. A value of 0 disables ARP monitoring. The default value
-        is 0.
+	Specifies the ARP monitoring frequency in milli-seconds. If
+	ARP monitoring is used in a load-balancing mode (mode 0 or 2),
+	the switch should be configured in a mode that evenly
+	distributes packets across all links - such as round-robin. If
+	the switch is configured to distribute the packets in an XOR
+	fashion, all replies from the ARP targets will be received on
+	the same link which could cause the other team members to
+	fail. ARP monitoring should not be used in conjunction with
+	miimon. A value of 0 disables ARP monitoring. The default
+	value is 0.
 
 arp_ip_target
 
-	Specifies the ip addresses to use when arp_interval is > 0. These
-	are the targets of the ARP request sent to determine the health of
-	the link to the targets. Specify these values in ddd.ddd.ddd.ddd
-	format. Multiple ip adresses must be seperated by a comma. At least
-	one ip address needs to be given for ARP monitoring to work. The
-	maximum number of targets that can be specified is set at 16.
+	Specifies the ip addresses to use when arp_interval is > 0.
+	These are the targets of the ARP request sent to determine the
+	health of the link to the targets.  Specify these values in
+	ddd.ddd.ddd.ddd format.  Multiple ip adresses must be
+	seperated by a comma.  At least one IP address must be given
+	for ARP monitoring to function.  The maximum number of targets
+	that can be specified is 16.  The default value is no IP
+	addresses.
 
 downdelay
 
-        Specifies the delay time in milli-seconds to disable a link after a
-        link failure has been detected. This should be a multiple of miimon
-        value, otherwise the value will be rounded. The default value is 0.
+	Specifies the time, in milliseconds, to wait before disabling
+	a slave after a link failure has been detected.  This option
+	is only valid for the miimon link monitor.  The downdelay
+	value should be a multiple of the miimon value; if not, it
+	will be rounded down to the nearest multiple.  The default
+	value is 0.
 
 lacp_rate
 
-        Option specifying the rate in which we'll ask our link partner to
-	transmit LACPDU packets in 802.3ad mode.  Possible values are:
+	Option specifying the rate in which we'll ask our link partner
+	to transmit LACPDU packets in 802.3ad mode.  Possible values
+	are:
 
 	slow or 0
 		Request partner to transmit LACPDUs every 30 seconds (default)
@@ -246,69 +221,76 @@ max_bonds
 
 miimon
 
-        Specifies the frequency in milli-seconds that MII link monitoring
-        will occur. A value of zero disables MII link monitoring. A value
-        of 100 is a good starting point. See High Availability section for
-        additional information. The default value is 0.
+	Specifies the frequency in milli-seconds that MII link
+	monitoring will occur.  A value of zero disables MII link
+	monitoring.  A value of 100 is a good starting point.  The
+	use_carrier option, below, affects how the link state is
+	determined.  See the High Availability section for additional
+	information.  The default value is 0.
 
 mode
 
 	Specifies one of the bonding policies. The default is
-	round-robin (balance-rr).  Possible values are (you can use
-	either the text or numeric option):
+	balance-rr (round robin).  Possible values are:
 
 	balance-rr or 0
 
-		Round-robin policy: Transmit in a sequential order
-		from the first available slave through the last. This
-		mode provides load balancing and fault tolerance.
+		Round-robin policy: Transmit packets in sequential
+		order from the first available slave through the
+		last.  This mode provides load balancing and fault
+		tolerance.
 
 	active-backup or 1
 
 		Active-backup policy: Only one slave in the bond is
-		active. A different slave becomes active if, and only
-		if, the active slave fails. The bond's MAC address is
+		active.  A different slave becomes active if, and only
+		if, the active slave fails.  The bond's MAC address is
 		externally visible on only one port (network adapter)
 		to avoid confusing the switch.  This mode provides
-		fault tolerance.
+		fault tolerance.  The primary option affects the
+		behavior of this mode.
 
 	balance-xor or 2
 
 		XOR policy: Transmit based on [(source MAC address
-		XOR'd with destination MAC address) modula slave
-		count]. This selects the same slave for each
-		destination MAC address. This mode provides load
+		XOR'd with destination MAC address) modulo slave
+		count].  This selects the same slave for each
+		destination MAC address.  This mode provides load
 		balancing and fault tolerance.
 
 	broadcast or 3
 
 		Broadcast policy: transmits everything on all slave
-		interfaces. This mode provides fault tolerance.
+		interfaces.  This mode provides fault tolerance.
 
 	802.3ad or 4
 
-		IEEE 802.3ad Dynamic link aggregation. Creates aggregation
-		groups that share the same speed and duplex settings.
-		Transmits and receives on all slaves in the active
-		aggregator.
+		IEEE 802.3ad Dynamic link aggregation.  Creates
+		aggregation groups that share the same speed and
+		duplex settings.  Utilizes all slaves in the active
+		aggregator according to the 802.3ad specification.
 
 		Pre-requisites:
 
-		1. Ethtool support in the base drivers for retrieving the
-		speed and duplex of each slave.
+		1. Ethtool support in the base drivers for retrieving
+		the speed and duplex of each slave.
 
 		2. A switch that supports IEEE 802.3ad Dynamic link
 		aggregation.
 
+		Most switches will require some type of configuration
+		to enable 802.3ad mode.
+
 	balance-tlb or 5
 
-		Adaptive transmit load balancing: channel bonding that does
-		not require any special switch support. The outgoing
-		traffic is distributed according to the current load
-		(computed relative to the speed) on each slave. Incoming
-		traffic is received by the current slave. If the receiving
-		slave fails, another slave takes over the MAC address of
-		the failed receiving slave.
+		Adaptive transmit load balancing: channel bonding that
+		does not require any special switch support.  The
+		outgoing traffic is distributed according to the
+		current load (computed relative to the speed) on each
+		slave.  Incoming traffic is received by the current
+		slave.  If the receiving slave fails, another slave
+		takes over the MAC address of the failed receiving
+		slave.
 
 		Prerequisite:
 
@@ -317,205 +299,452 @@ mode
 
 	balance-alb or 6
 
-		Adaptive load balancing: includes balance-tlb + receive
-		load balancing (rlb) for IPV4 traffic and does not require
-		any special switch support. The receive load balancing is
-		achieved by ARP negotiation. The bonding driver intercepts
-		the ARP Replies sent by the server on their way out and
-		overwrites the src hw address with the unique hw address of
-		one of the slaves in the bond such that different clients
-		use different hw addresses for the server.
-
-		Receive traffic from connections created by the server is
-		also balanced. When the server sends an ARP Request the
-		bonding driver copies and saves the client's IP information
-		from the ARP. When the ARP Reply arrives from the client,
-		its hw address is retrieved and the bonding driver
-		initiates an ARP reply to this client assigning it to one
-		of the slaves in the bond. A problematic outcome of using
-		ARP negotiation for balancing is that each time that an ARP
-		request is broadcasted it uses the hw address of the
-		bond. Hence, clients learn the hw address of the bond and
-		the balancing of receive traffic collapses to the current
-		salve. This is handled by sending updates (ARP Replies) to
-		all the clients with their assigned hw address such that
-		the traffic is redistributed. Receive traffic is also
-		redistributed when a new slave is added to the bond and
-		when an inactive slave is re-activated. The receive load is
-		distributed sequentially (round robin) among the group of
-		highest speed slaves in the bond.
-
-		When a link is reconnected or a new slave joins the bond
-		the receive traffic is redistributed among all active
-		slaves in the bond by intiating ARP Replies with the
-		selected mac address to each of the clients. The updelay
-		modeprobe parameter must be set to a value equal or greater
-		than the switch's forwarding delay so that the ARP Replies
-		sent to the clients will not be blocked by the switch.
+		Adaptive load balancing: includes balance-tlb plus
+		receive load balancing (rlb) for IPV4 traffic, and
+		does not require any special switch support.  The
+		receive load balancing is achieved by ARP negotiation.
+		The bonding driver intercepts the ARP Replies sent by
+		the local system on their way out and overwrites the
+		source hardware address with the unique hardware
+		address of one of the slaves in the bond such that
+		different peers use different hardware addresses for
+		the server.
+
+		Receive traffic from connections created by the server
+		is also balanced.  When the local system sends an ARP
+		Request the bonding driver copies and saves the peer's
+		IP information from the ARP packet.  When the ARP
+		Reply arrives from the peer, its hardware address is
+		retrieved and the bonding driver initiates an ARP
+		reply to this peer assigning it to one of the slaves
+		in the bond.  A problematic outcome of using ARP
+		negotiation for balancing is that each time that an
+		ARP request is broadcast it uses the hardware address
+		of the bond.  Hence, peers learn the hardware address
+		of the bond and the balancing of receive traffic
+		collapses to the current slave.  This is handled by
+		sending updates (ARP Replies) to all the peers with
+		their individually assigned hardware address such that
+		the traffic is redistributed.  Receive traffic is also
+		redistributed when a new slave is added to the bond
+		and when an inactive slave is re-activated.  The
+		receive load is distributed sequentially (round robin)
+		among the group of highest speed slaves in the bond.
+
+		When a link is reconnected or a new slave joins the
+		bond the receive traffic is redistributed among all
+		active slaves in the bond by intiating ARP Replies
+		with the selected mac address to each of the
+		clients. The updelay parameter (detailed below) must
+		be set to a value equal or greater than the switch's
+		forwarding delay so that the ARP Replies sent to the
+		peers will not be blocked by the switch.
 
 		Prerequisites:
 
-		1. Ethtool support in the base drivers for retrieving the
-		speed of each slave.
+		1. Ethtool support in the base drivers for retrieving
+		the speed of each slave.
 
-		2. Base driver support for setting the hw address of a
-		device also when it is open. This is required so that there
-		will always be one slave in the team using the bond hw
-		address (the curr_active_slave) while having a unique hw
-		address for each slave in the bond. If the curr_active_slave
-		fails it's hw address is swapped with the new curr_active_slave
-		that was chosen.
+		2. Base driver support for setting the hardware
+		address of a device while it is open.  This is
+		required so that there will always be one slave in the
+		team using the bond hardware address (the
+		curr_active_slave) while having a unique hardware
+		address for each slave in the bond.  If the
+		curr_active_slave fails its hardware address is
+		swapped with the new curr_active_slave that was
+		chosen.
 
 primary
 
-        A string (eth0, eth2, etc) to equate to a primary device. If this
-        value is entered, and the device is on-line, it will be used first
-        as the output media. Only when this device is off-line, will
-        alternate devices be used. Otherwise, once a failover is detected
-        and a new default output is chosen, it will remain the output media
-        until it too fails. This is useful when one slave was preferred
-        over another, i.e. when one slave is 1000Mbps and another is
-        100Mbps. If the 1000Mbps slave fails and is later restored, it may
-        be preferred the faster slave gracefully become the active slave -
-        without deliberately failing the 100Mbps slave. Specifying a
-        primary is only valid in active-backup mode.
+	A string (eth0, eth2, etc) specifying which slave is the
+	primary device.  The specified device will always be the
+	active slave while it is available.  Only when the primary is
+	off-line will alternate devices be used.  This is useful when
+	one slave is preferred over another, e.g., when one slave has
+	higher throughput than another.
+
+	The primary option is only valid for active-backup mode.
 
 updelay
 
-        Specifies the delay time in milli-seconds to enable a link after a
-        link up status has been detected. This should be a multiple of miimon
-        value, otherwise the value will be rounded. The default value is 0.
+	Specifies the time, in milliseconds, to wait before enabling a
+	slave after a link recovery has been detected.  This option is
+	only valid for the miimon link monitor.  The updelay value
+	should be a multiple of the miimon value; if not, it will be
+	rounded down to the nearest multiple.  The default value is 0.
 
 use_carrier
 
-        Specifies whether or not miimon should use MII or ETHTOOL
-        ioctls vs. netif_carrier_ok() to determine the link status.
-        The MII or ETHTOOL ioctls are less efficient and utilize a
-        deprecated calling sequence within the kernel.  The
-        netif_carrier_ok() relies on the device driver to maintain its
-        state with netif_carrier_on/off; at this writing, most, but
-        not all, device drivers support this facility.
-
-        If bonding insists that the link is up when it should not be,
-        it may be that your network device driver does not support
-        netif_carrier_on/off.  This is because the default state for
-        netif_carrier is "carrier on." In this case, disabling
-        use_carrier will cause bonding to revert to the MII / ETHTOOL
-        ioctl method to determine the link state.
-
-        A value of 1 enables the use of netif_carrier_ok(), a value of
-        0 will use the deprecated MII / ETHTOOL ioctls.  The default
-        value is 1.
-
-
-Configuring Multiple Bonds
-==========================
-
-If several bonding interfaces are required, either specify the max_bonds
-parameter (described above), or load the driver multiple times.  Using
-the max_bonds parameter is less complicated, but has the limitation that
-all bonding instances created will have the same options.  Loading the
-driver multiple times allows each instance of the driver to have differing
-options.
-
-For example, to configure two bonding interfaces, one with mii link
-monitoring performed every 100 milliseconds, and one with ARP link
-monitoring performed every 200 milliseconds, the /etc/conf.modules should
-resemble the following:
+	Specifies whether or not miimon should use MII or ETHTOOL
+	ioctls vs. netif_carrier_ok() to determine the link
+	status. The MII or ETHTOOL ioctls are less efficient and
+	utilize a deprecated calling sequence within the kernel.  The
+	netif_carrier_ok() relies on the device driver to maintain its
+	state with netif_carrier_on/off; at this writing, most, but
+	not all, device drivers support this facility.
+
+	If bonding insists that the link is up when it should not be,
+	it may be that your network device driver does not support
+	netif_carrier_on/off.  The default state for netif_carrier is
+	"carrier on," so if a driver does not support netif_carrier,
+	it will appear as if the link is always up.  In this case,
+	setting use_carrier to 0 will cause bonding to revert to the
+	MII / ETHTOOL ioctl method to determine the link state.
+
+	A value of 1 enables the use of netif_carrier_ok(), a value of
+	0 will use the deprecated MII / ETHTOOL ioctls.  The default
+	value is 1.
+
+
+
+3. Configuring Bonding Devices
+==============================
+
+	There are, essentially, two methods for configuring bonding:
+with support from the distro's network initialization scripts, and
+without.  Distros generally use one of two packages for the network
+initialization scripts: initscripts or sysconfig.  Recent versions of
+these packages have support for bonding, while older versions do not.
+
+	We will first describe the options for configuring bonding for
+distros using versions of initscripts and sysconfig with full or
+partial support for bonding, then provide information on enabling
+bonding without support from the network initialization scripts (i.e.,
+older versions of initscripts or sysconfig).
+
+	If you're unsure whether your distro uses sysconfig or
+initscripts, or don't know if it's new enough, have no fear.
+Determining this is fairly straightforward.
+
+	First, issue the command:
+
+$ rpm -qf /sbin/ifup
+
+	It will respond with a line of text starting with either
+"initscripts" or "sysconfig," followed by some numbers.  This is the
+package that provides your network initialization scripts.
+
+	Next, to determine if your installation supports bonding,
+issue the command:
+
+$ grep ifenslave /sbin/ifup
+
+	If this returns any matches, then your initscripts or
+sysconfig has support for bonding.
+
+3.1 Configuration with sysconfig support
+----------------------------------------
+
+	This section applies to distros using a version of sysconfig
+with bonding support, for example, SuSE Linux Enterprise Server 9.
+
+	SuSE SLES 9's networking configuration system does support
+bonding, however, at this writing, the YaST system configuration
+frontend does not provide any means to work with bonding devices.
+Bonding devices can be managed by hand, however, as follows.
+
+	First, if they have not already been configured, configure the
+slave devices.  On SLES 9, this is most easily done by running the
+yast2 sysconfig configuration utility.  The goal is for to create an
+ifcfg-id file for each slave device.  The simplest way to accomplish
+this is to configure the devices for DHCP.  The name of the
+configuration file for each device will be of the form:
+
+ifcfg-id-xx:xx:xx:xx:xx:xx
+
+	Where the "xx" portion will be replaced with the digits from
+the device's permanent MAC address.
+
+	Once the set of ifcfg-id-xx:xx:xx:xx:xx:xx files has been
+created, it is necessary to edit the configuration files for the slave
+devices (the MAC addresses correspond to those of the slave devices).
+Before editing, the file will contain muliple lines, and will look
+something like this:
+
+BOOTPROTO='dhcp'
+STARTMODE='on'
+USERCTL='no'
+UNIQUE='XNzu.WeZGOGF+4wE'
+_nm_name='bus-pci-0001:61:01.0'
+
+	Change the BOOTPROTO and STARTMODE lines to the following:
+
+BOOTPROTO='none'
+STARTMODE='off'
+
+	Do not alter the UNIQUE or _nm_name lines.  Remove any other
+lines (USERCTL, etc).
+
+	Once the ifcfg-id-xx:xx:xx:xx:xx:xx files have been modified,
+it's time to create the configuration file for the bonding device
+itself.  This file is named ifcfg-bondX, where X is the number of the
+bonding device to create, starting at 0.  The first such file is
+ifcfg-bond0, the second is ifcfg-bond1, and so on.  The sysconfig
+network configuration system will correctly start multiple instances
+of bonding.
+
+	The contents of the ifcfg-bondX file is as follows:
+
+BOOTPROTO="static"
+BROADCAST="10.0.2.255"
+IPADDR="10.0.2.10"
+NETMASK="255.255.0.0"
+NETWORK="10.0.2.0"
+REMOTE_IPADDR=""
+STARTMODE="onboot"
+BONDING_MASTER="yes"
+BONDING_MODULE_OPTS="mode=active-backup miimon=100"
+BONDING_SLAVE0="eth0"
+BONDING_SLAVE1="eth1"
+
+	Replace the sample BROADCAST, IPADDR, NETMASK and NETWORK
+values with the appropriate values for your network.
+
+	Note that configuring the bonding device with BOOTPROTO='dhcp'
+does not work; the scripts attempt to obtain the device address from
+DHCP prior to adding any of the slave devices.  Without active slaves,
+the DHCP requests are not sent to the network.
+
+	The STARTMODE specifies when the device is brought online.
+The possible values are:
+
+	onboot:	 The device is started at boot time.  If you're not
+		 sure, this is probably what you want.
+
+	manual:	 The device is started only when ifup is called
+		 manually.  Bonding devices may be configured this
+		 way if you do not wish them to start automatically
+		 at boot for some reason.
+
+	hotplug: The device is started by a hotplug event.  This is not
+		 a valid choice for a bonding device.
+
+	off or ignore: The device configuration is ignored.
+
+	The line BONDING_MASTER='yes' indicates that the device is a
+bonding master device.  The only useful value is "yes."
+
+	The contents of BONDING_MODULE_OPTS are supplied to the
+instance of the bonding module for this device.  Specify the options
+for the bonding mode, link monitoring, and so on here.  Do not include
+the max_bonds bonding parameter; this will confuse the configuration
+system if you have multiple bonding devices.
+
+	Finally, supply one BONDING_SLAVEn="ethX" for each slave,
+where "n" is an increasing value, one for each slave, and "ethX" is
+the name of the slave device (eth0, eth1, etc).
+
+	When all configuration files have been modified or created,
+networking must be restarted for the configuration changes to take
+effect.  This can be accomplished via the following:
+
+# /etc/init.d/network restart
+
+	Note that the network control script (/sbin/ifdown) will
+remove the bonding module as part of the network shutdown processing,
+so it is not necessary to remove the module by hand if, e.g., the
+module paramters have changed.
+
+	Also, at this writing, YaST/YaST2 will not manage bonding
+devices (they do not show bonding interfaces on its list of network
+devices).  It is necessary to edit the configuration file by hand to
+change the bonding configuration.
+
+	Additional general options and details of the ifcfg file
+format can be found in an example ifcfg template file:
+
+/etc/sysconfig/network/ifcfg.template
+
+	Note that the template does not document the various BONDING_
+settings described above, but does describe many of the other options.
+
+3.2 Configuration with initscripts support
+------------------------------------------
+
+	This section applies to distros using a version of initscripts
+with bonding support, for example, Red Hat Linux 9 or Red Hat
+Enterprise Linux version 3.  On these systems, the network
+initialization scripts have some knowledge of bonding, and can be
+configured to control bonding devices.
+
+	These distros will not automatically load the network adapter
+driver unless the ethX device is configured with an IP address.
+Because of this constraint, users must manually configure a
+network-script file for all physical adapters that will be members of
+a bondX link.  Network script files are located in the directory:
+
+/etc/sysconfig/network-scripts
+
+	The file name must be prefixed with "ifcfg-eth" and suffixed
+with the adapter's physical adapter number.  For example, the script
+for eth0 would be named /etc/sysconfig/network-scripts/ifcfg-eth0.
+Place the following text in the file:
 
-alias bond0 bonding
-alias bond1 bonding
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+MASTER=bond0
+SLAVE=yes
+BOOTPROTO=none
 
-options bond0 miimon=100
-options bond1 -o bonding1 arp_interval=200 arp_ip_target=10.0.0.1
+	The DEVICE= line will be different for every ethX device and
+must correspond with the name of the file, i.e., ifcfg-eth1 must have
+a device line of DEVICE=eth1.  The setting of the MASTER= line will
+also depend on the final bonding interface name chosen for your bond.
+As with other network devices, these typically start at 0, and go up
+one for each device, i.e., the first bonding instance is bond0, the
+second is bond1, and so on.
+
+	Next, create a bond network script.  The file name for this
+script will be /etc/sysconfig/network-scripts/ifcfg-bondX where X is
+the number of the bond.  For bond0 the file is named "ifcfg-bond0",
+for bond1 it is named "ifcfg-bond1", and so on.  Within that file,
+place the following text:
 
-Configuring Multiple ARP Targets
-================================
+DEVICE=bond0
+IPADDR=192.168.1.1
+NETMASK=255.255.255.0
+NETWORK=192.168.1.0
+BROADCAST=192.168.1.255
+ONBOOT=yes
+BOOTPROTO=none
+USERCTL=no
 
-While ARP monitoring can be done with just one target, it can be useful
-in a High Availability setup to have several targets to monitor. In the
-case of just one target,  the target itself may go down or have a problem
-making it unresponsive to ARP requests. Having an additional target (or
-several) increases the reliability of the ARP monitoring.
+	Be sure to change the networking specific lines (IPADDR,
+NETMASK, NETWORK and BROADCAST) to match your network configuration.
 
-Multiple ARP targets must be seperated by commas as follows:
+	Finally, it is necessary to edit /etc/modules.conf to load the
+bonding module when the bond0 interface is brought up.  The following
+sample lines in /etc/modules.conf will load the bonding module, and
+select its options:
 
-# example options for ARP monitoring with three targets
 alias bond0 bonding
-options bond0 arp_interval=60 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
+options bond0 mode=balance-alb miimon=100
 
-For just a single target the options would resemble:
+	Replace the sample parameters with the appropriate set of
+options for your configuration.
 
-# example options for ARP monitoring with one target
+	Finally run "/etc/rc.d/init.d/network restart" as root.  This
+will restart the networking subsystem and your bond link should be now
+up and running.
+
+
+3.3 Configuring Bonding Manually
+--------------------------------
+
+	This section applies to distros whose network initialization
+scripts (the sysconfig or initscripts package) do not have specific
+knowledge of bonding.  One such distro is SuSE Linux Enterprise Server
+version 8.
+
+	The general methodology for these systems is to place the
+bonding module parameters into /etc/modprobe.conf, then add modprobe
+and/or ifenslave commands to the system's global init script.  The
+name of the global init script differs; for sysconfig, it is
+/etc/init.d/boot.local and for initscripts it is /etc/rc.d/rc.local.
+
+	For example, if you wanted to make a simple bond of two e100
+devices (presumed to be eth0 and eth1), and have it persist across
+reboots, edit the appropriate file (/etc/init.d/boot.local or
+/etc/rc.d/rc.local), and add the following:
+
+modprobe bonding -obond0 mode=balance-alb miimon=100
+modprobe e100
+ifconfig bond0 192.168.1.1 netmask 255.255.255.0 up
+ifenslave bond0 eth0
+ifenslave bond0 eth1
+
+	Replace the example bonding module parameters and bond0
+network configuration (IP address, netmask, etc) with the appropriate
+values for your configuration.  The above example loads the bonding
+module with the name "bond0," this simplifies the naming if multiple
+bonding modules are loaded (each successive instance of the module is
+given a different name, and the module instance names match the
+bonding interface names).
+
+	Unfortunately, this method will not provide support for the
+ifup and ifdown scripts on the bond devices.  To reload the bonding
+configuration, it is necessary to run the initialization script, e.g.,
+
+# /etc/init.d/boot.local
+
+	or
+
+# /etc/rc.d/rc.local
+
+	It may be desirable in such a case to create a separate script
+which only initializes the bonding configuration, then call that
+separate script from within boot.local.  This allows for bonding to be
+enabled without re-running the entire global init script.
+
+	To shut down the bonding devices, it is necessary to first
+mark the bonding device itself as being down, then remove the
+appropriate device driver modules.  For our example above, you can do
+the following:
+
+# ifconfig bond0 down
+# rmmod bond0
+# rmmod e100
+
+	Again, for convenience, it may be desirable to create a script
+with these commands.
+
+
+3.4 Configuring Multiple Bonds
+------------------------------
+
+	This section contains information on configuring multiple
+bonding devices with differing options.  If you require multiple
+bonding devices, but all with the same options, see the "max_bonds"
+module paramter, documented above.
+
+	To create multiple bonding devices with differing options, it
+is necessary to load the bonding driver multiple times.  Note that
+current versions of the sysconfig network initialization scripts
+handle this automatically; if your distro uses these scripts, no
+special action is needed.  See the section Configuring Bonding
+Devices, above, if you're not sure about your network initialization
+scripts.
+
+	To load multiple instances of the module, it is necessary to
+specify a different name for each instance (the module loading system
+requires that every loaded module, even multiple instances of the same
+module, have a unique name).  This is accomplished by supplying
+multiple sets of bonding options in /etc/modprobe.conf, for example:
+	
 alias bond0 bonding
-options bond0 arp_interval=60 arp_ip_target=192.168.0.100
-
-Potential Problems When Using ARP Monitor
-=========================================
+options bond0 -o bond0 mode=balance-rr miimon=100
 
-1. Driver support
-
-The ARP monitor relies on the network device driver to maintain two
-statistics: the last receive time (dev->last_rx), and the last
-transmit time (dev->trans_start).  If the network device driver does
-not update one or both of these, then the typical result will be that,
-upon startup, all links in the bond will immediately be declared down,
-and remain that way.  A network monitoring tool (tcpdump, e.g.) will
-show ARP requests and replies being sent and received on the bonding
-device.
-
-The possible resolutions for this are to (a) fix the device driver, or
-(b) discontinue the ARP monitor (using miimon as an alternative, for
-example).
-
-2. Adventures in Routing
-
-When bonding is set up with the ARP monitor, it is important that the
-slave devices not have routes that supercede routes of the master (or,
-generally, not have routes at all).  For example, suppose the bonding
-device bond0 has two slaves, eth0 and eth1, and the routing table is
-as follows:
-
-Kernel IP routing table
-Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
-10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth0
-10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth1
-10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 bond0
-127.0.0.0       0.0.0.0         255.0.0.0       U        40 0          0 lo
+alias bond1 bonding
+options bond1 -o bond1 mode=balance-alb miimon=50
 
-In this case, the ARP monitor (and ARP itself) may become confused,
-because ARP requests will be sent on one interface (bond0), but the
-corresponding reply will arrive on a different interface (eth0).  This
-reply looks to ARP as an unsolicited ARP reply (because ARP matches
-replies on an interface basis), and is discarded.  This will likely
-still update the receive/transmit times in the driver, but will lose
-packets.
-
-The resolution here is simply to insure that slaves do not have routes
-of their own, and if for some reason they must, those routes do not
-supercede routes of their master.  This should generally be the case,
-but unusual configurations or errant manual or automatic static route
-additions may cause trouble.
+	will load the bonding module two times.  The first instance is
+named "bond0" and creates the bond0 device in balance-rr mode with an
+miimon of 100.  The second instance is named "bond1" and creates the
+bond1 device in balance-alb mode with an miimon of 50.
 
-Switch Configuration
-====================
+	This may be repeated any number of times, specifying a new and
+unique name in place of bond0 or bond1 for each instance.
 
-While the switch does not need to be configured when the active-backup,
-balance-tlb or balance-alb policies (mode=1,5,6) are used, it does need to
-be configured for the round-robin, XOR, broadcast, or 802.3ad policies
-(mode=0,2,3,4).
+	When the appropriate module paramters are in place, then
+configure bonding according to the instructions for your distro.
 
+5. Querying Bonding Configuration 
+=================================
 
-Verifying Bond Configuration
-============================
+5.1 Bonding Configuration
+-------------------------
 
-1) Bonding information files
-----------------------------
-The bonding driver information files reside in the /proc/net/bonding directory.
+	Each bonding device has a read-only file residing in the
+/proc/net/bonding directory.  The file contents include information
+about the bonding configuration, options and state of each slave.
 
-Sample contents of /proc/net/bonding/bond0 after the driver is loaded with
-parameters of mode=0 and miimon=1000 is shown below.
+	For example, the contents of /proc/net/bonding/bond0 after the
+driver is loaded with parameters of mode=0 and miimon=1000 is
+generally as follows:
 
+	Ethernet Channel Bonding Driver: 2.6.1 (October 29, 2004)
         Bonding Mode: load balancing (round-robin)
         Currently Active Slave: eth0
         MII Status: up
@@ -531,15 +760,23 @@ parameters of mode=0 and miimon=1000 is 
         MII Status: up
         Link Failure Count: 1
 
-2) Network verification
------------------------
-The network configuration can be verified using the ifconfig command. In
-the example below, the bond0 interface is the master (MASTER) while eth0 and
-eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address
-(HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC
-address for each slave.
+	The precise format and contents will change depending upon the
+bonding configuration, state, and version of the bonding driver.
+
+5.2 Network configuration
+-------------------------
+
+	The network configuration can be inspected using the ifconfig
+command.  Bonding devices will have the MASTER flag set; Bonding slave
+devices will have the SLAVE flag set.  The ifconfig output does not
+contain information on which slaves are associated with which masters.
+
+	In the example below, the bond0 interface is the master
+(MASTER) while eth0 and eth1 are slaves (SLAVE). Notice all slaves of
+bond0 have the same MAC address (HWaddr) as bond0 for all modes except
+TLB and ALB that require a unique MAC address for each slave.
 
-[root]# /sbin/ifconfig
+# /sbin/ifconfig
 bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
           inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
           UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
@@ -563,430 +800,819 @@ eth1      Link encap:Ethernet  HWaddr 00
           collisions:0 txqueuelen:100
           Interrupt:9 Base address:0x1400
 
+6. Switch Configuration
+=======================
 
-Frequently Asked Questions
-==========================
+	For this section, "switch" refers to whatever system the
+bonded devices are directly connected to (i.e., where the other end of
+the cable plugs into).  This may be an actual dedicated switch device,
+or it may be another regular system (e.g., another computer running
+Linux),
+
+	The active-backup, balance-tlb and balance-alb modes do not
+require any specific configuration of the switch.
+
+	The 802.3ad mode requires that the switch have the appropriate
+ports configured as an 802.3ad aggregation.  The precise method used
+to configure this varies from switch to switch, but, for example, a
+Cisco 3550 series switch requires that the appropriate ports first be
+grouped together in a single etherchannel instance, then that
+etherchannel is set to mode "lacp" to enable 802.3ad (instead of
+standard EtherChannel).
+
+	The balance-rr, balance-xor and broadcast modes generally
+require that the switch have the appropriate ports grouped together.
+The nomenclature for such a group differs between switches, it may be
+called an "etherchannel" (as in the Cisco example, above), a "trunk
+group" or some other similar variation.  For these modes, each switch
+will also have its own configuration options for the switch's transmit
+policy to the bond.  Typical choices include XOR of either the MAC or
+IP addresses.  The transmit policy of the two peers does not need to
+match.  For these three modes, the bonding mode really selects a
+transmit policy for an EtherChannel group; all three will interoperate
+with another EtherChannel group.
+
+
+7. 802.1q VLAN Support
+======================
+
+	It is possible to configure VLAN devices over a bond interface
+using the 8021q driver.  However, only packets coming from the 8021q
+driver and passing through bonding will be tagged by default.  Self
+generated packets, for example, bonding's learning packets or ARP
+packets generated by either ALB mode or the ARP monitor mechanism, are
+tagged internally by bonding itself.  As a result, bonding must
+"learn" the VLAN IDs configured above it, and use those IDs to tag
+self generated packets.
+
+	For reasons of simplicity, and to support the use of adapters
+that can do VLAN hardware acceleration offloding, the bonding
+interface declares itself as fully hardware offloaing capable, it gets
+the add_vid/kill_vid notifications to gather the necessary
+information, and it propagates those actions to the slaves.  In case
+of mixed adapter types, hardware accelerated tagged packets that
+should go through an adapter that is not offloading capable are
+"un-accelerated" by the bonding driver so the VLAN tag sits in the
+regular location.
+
+	VLAN interfaces *must* be added on top of a bonding interface
+only after enslaving at least one slave.  The bonding interface has a
+hardware address of 00:00:00:00:00:00 until the first slave is added.
+If the VLAN interface is created prior to the first enslavement, it
+would pick up the all-zeroes hardware address.  Once the first slave
+is attached to the bond, the bond device itself will pick up the
+slave's hardware address, which is then available for the VLAN device.
+
+	Also, be aware that a similar problem can occur if all slaves
+are released from a bond that still has one or more VLAN interfaces on
+top of it.  When a new slave is added, the bonding interface will
+obtain its hardware address from the first slave, which might not
+match the hardware address of the VLAN interfaces (which was
+ultimately copied from an earlier slave).
+
+	There are two methods to insure that the VLAN device operates
+with the correct hardware address if all slaves are removed from a
+bond interface:
+
+	1. Remove all VLAN interfaces then recreate them
+
+	2. Set the bonding interface's hardware address so that it
+matches the hardware address of the VLAN interfaces.
+
+	Note that changing a VLAN interface's HW address would set the
+underlying device -- i.e. the bonding interface -- to promiscouos
+mode, which might not be what you want.
 
-1.  Is it SMP safe?
-
-	Yes. The old 2.0.xx channel bonding patch was not SMP safe.
-	The new driver was designed to be SMP safe from the start.
 
-2.  What type of cards will work with it?
-
-	Any Ethernet type cards (you can even mix cards - a Intel
-	EtherExpress PRO/100 and a 3com 3c905b, for example).
-	You can even bond together Gigabit Ethernet cards!
+8. Link Monitoring
+==================
 
-3.  How many bonding devices can I have?
+	The bonding driver at present supports two schemes for
+monitoring a slave device's link state: the ARP monitor and the MII
+monitor.
+
+	At the present time, due to implementation restrictions in the
+bonding driver itself, it is not possible to enable both ARP and MII
+monitoring simultaneously.
+
+8.1 ARP Monitor Operation
+-------------------------
+
+	The ARP monitor operates as its name suggests: it sends ARP
+queries to one or more designated peer systems on the network, and
+uses the response as an indication that the link is operating.  This
+gives some assurance that traffic is actually flowing to and from one
+or more peers on the local network.
+
+	The ARP monitor relies on the device driver itself to verify
+that traffic is flowing.  In particular, the driver must keep up to
+date the last receive time, dev->last_rx, and transmit start time,
+dev->trans_start.  If these are not updated by the driver, then the
+ARP monitor will immediately fail any slaves using that driver, and
+those slaves will stay down.  If networking monitoring (tcpdump, etc)
+shows the ARP requests and replies on the network, then it may be that
+your device driver is not updating last_rx and trans_start.
 
-	There is no limit.
+8.2 Configuring Multiple ARP Targets
+------------------------------------
 
-4.  How many slaves can a bonding device have?
+	While ARP monitoring can be done with just one target, it can
+be useful in a High Availability setup to have several targets to
+monitor.  In the case of just one target, the target itself may go
+down or have a problem making it unresponsive to ARP requests.  Having
+an additional target (or several) increases the reliability of the ARP
+monitoring.
 
-	Limited by the number of network interfaces Linux supports and/or the
-	number of network cards you can place in your system.
+	Multiple ARP targets must be seperated by commas as follows:
 
-5.  What happens when a slave link dies?
+# example options for ARP monitoring with three targets
+alias bond0 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
 
-	If your ethernet cards support MII or ETHTOOL link status monitoring
-        and the MII monitoring has been enabled in the driver (see description
-        of module parameters), there will be no adverse consequences. This
-        release of the bonding driver knows how to get the MII information and
-	enables or disables its slaves according to their link status.
-	See section on High Availability for additional information.
-
-	For ethernet cards not supporting MII status, the arp_interval and
-        arp_ip_target parameters must be specified for bonding to work
-        correctly. If packets have not been sent or received during the
-        specified arp_interval duration, an ARP request is sent to the
-        targets to generate send and receive traffic. If after this
-        interval, either the successful send and/or receive count has not
-        incremented, the next slave in the sequence will become the active
-        slave.
-
-	If neither mii_monitor and arp_interval is configured, the bonding
-	driver will not handle this situation very well. The driver will
-	continue to send packets but some packets will be lost. Retransmits
-	will cause serious degradation of performance (in the case when one
-	of two slave links fails, 50% packets will be lost, which is a serious
-	problem for both TCP and UDP).
+	For just a single target the options would resemble:
 
-6.  Can bonding be used for High Availability?
+# example options for ARP monitoring with one target
+alias bond0 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.100
 
-        Yes, if you use MII monitoring and ALL your cards support MII link
-        status reporting. See section on High Availability for more
-        information.
 
-7.  Which switches/systems does it work with?
+8.3 MII Monitor Operation
+-------------------------
 
-	In round-robin and XOR mode, it works with systems that support
-	trunking:
+	The MII monitor monitors only the carrier state of the local
+network interface.  It accomplishes this in one of three ways: by
+depending upon the device driver to maintain its carrier state, by
+querying the device's MII registers, or by making an ethtool query to
+the device.
+
+	If the use_carrier module parameter is 1 (the default value),
+then the MII monitor will rely on the driver for carrier state
+information (via the netif_carrier subsystem).  As explained in the
+use_carrier parameter information, above, if the MII monitor fails to
+detect carrier loss on the device (e.g., when the cable is physically
+disconnected), it may be that the driver does not support
+netif_carrier.
+
+	If use_carrier is 0, then the MII monitor will first query the
+device's (via ioctl) MII registers and check the link state.  If that
+request fails (not just that it returns carrier down), then the MII
+monitor will make an ethtool ETHOOL_GLINK request to attempt to obtain
+the same information.  If both methods fail (i.e., the driver either
+does not support or had some error in processing both the MII register
+and ethtool requests), then the MII monitor will assume the link is
+up.
 
-	* Many Cisco switches and routers (look for EtherChannel support).
-	* SunTrunking software.
-	* Alteon AceDirector switches / WebOS (use Trunks).
-	* BayStack Switches (trunks must be explicitly configured). Stackable
-	  models (450) can define trunks between ports on different physical
-	  units.
-	* Linux bonding, of course !
-
-	In 802.3ad mode, it works with with systems that support IEEE 802.3ad
-	Dynamic Link Aggregation:
-
-	* Extreme networks Summit 7i (look for link-aggregation).
-	* Many Cisco switches and routers (look for LACP support; this may
-	  require an upgrade to your IOS software; LACP support was added
-	  by Cisco in late 2002).
-	* Foundry Big Iron 4000
+9. Potential Sources of Trouble
+===============================
 
-        In active-backup, balance-tlb and balance-alb modes, it should work
-        with any Layer-II switch.
+9.1 Adventures in Routing
+-------------------------
 
+	When bonding is configured, it is important that the slave
+devices not have routes that supercede routes of the master (or,
+generally, not have routes at all).  For example, suppose the bonding
+device bond0 has two slaves, eth0 and eth1, and the routing table is
+as follows:
 
-8.  Where does a bonding device get its MAC address from?
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth0
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth1
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 bond0
+127.0.0.0       0.0.0.0         255.0.0.0       U        40 0          0 lo
 
-	If not explicitly configured with ifconfig, the MAC address of the
-	bonding device is taken from its first slave device. This MAC address
-	is then passed to all following slaves and remains persistent (even if
-	the the first slave is removed) until the bonding device is brought
-	down or reconfigured.
+	This routing configuration will likely still update the
+receive/transmit times in the driver (needed by the ARP monitor), but
+may bypass the bonding driver (because outgoing traffic to, in this
+case, another host on network 10 would use eth0 or eth1 before bond0).
+
+	The ARP monitor (and ARP itself) may become confused by this
+configuration, because ARP requests (generated by the ARP monitor)
+will be sent on one interface (bond0), but the corresponding reply
+will arrive on a different interface (eth0).  This reply looks to ARP
+as an unsolicited ARP reply (because ARP matches replies on an
+interface basis), and is discarded.  The MII monitor is not affected
+by the state of the routing table.
+
+	The solution here is simply to insure that slaves do not have
+routes of their own, and if for some reason they must, those routes do
+not supercede routes of their master.  This should generally be the
+case, but unusual configurations or errant manual or automatic static
+route additions may cause trouble.
 
-	If you wish to change the MAC address, you can set it with ifconfig:
+9.2 Ethernet Device Renaming
+----------------------------
 
-	  # ifconfig bond0 hw ether 00:11:22:33:44:55
+	On systems with network configuration scripts that do not
+associate physical devices directly with network interface names (so
+that the same physical device always has the same "ethX" name), it may
+be necessary to add some special logic to either /etc/modules.conf or
+/etc/modprobe.conf (depending upon which is installed on the system).
 
-	The MAC address can be also changed by bringing down/up the device
-	and then changing its slaves (or their order):
+	For example, given a modules.conf containing the following:
 
-	  # ifconfig bond0 down ; modprobe -r bonding
-	  # ifconfig bond0 .... up
-	  # ifenslave bond0 eth...
+alias bond0 bonding
+options bond0 mode=some-mode miimon=50
+alias eth0 tg3
+alias eth1 tg3
+alias eth2 e1000
+alias eth3 e1000
+
+	If neither eth0 and eth1 are slaves to bond0, then when the
+bond0 interface comes up, the devices may end up reordered.  This
+happens because bonding is loaded first, then its slave device's
+drivers are loaded next.  Since no other drivers have been loaded,
+when the e1000 driver loads, it will receive eth0 and eth1 for its
+devices, but the bonding configuration tries to enslave eth2 and eth3
+(which may later be assigned to the tg3 devices).
+
+	Adding the following:
+
+add above bonding e1000 tg3
+
+	causes modprobe to load e1000 then tg3, in that order, when
+bonding is loaded.  This command is fully documented in the
+modules.conf manual page.
+
+	On systems utilizing modprobe.conf (or modprobe.conf.local),
+an equivalent problem can occur.  In this case, the following can be
+added to modprobe.conf (or modprobe.conf.local, as appropriate), as
+follows (all on one line; it has been split here for clarity):
+
+install bonding /sbin/modprobe tg3; /sbin/modprobe e1000;
+	/sbin/modprobe --ignore-install bonding
+
+	This will, when loading the bonding module, rather than
+performing the normal action, instead execute the provided command.
+This command loads the device drivers in the order needed, then calls
+modprobe with --ingore-install to cause the normal action to then take
+place.  Full documentation on this can be found in the modprobe.conf
+and modprobe manual pages.
+
+9.3. Painfully Slow Or No Failed Link Detection By Miimon
+---------------------------------------------------------
+
+	By default, bonding enables the use_carrier option, which
+instructs bonding to trust the driver to maintain carrier state.
+
+	As discussed in the options section, above, some drivers do
+not support the netif_carrier_on/_off link state tracking system.
+With use_carrier enabled, bonding will always see these links as up,
+regardless of their actual state.
+
+	Additionally, other drivers do support netif_carrier, but do
+not maintain it in real time, e.g., only polling the link state at
+some fixed interval.  In this case, miimon will detect failures, but
+only after some long period of time has expired.  If it appears that
+miimon is very slow in detecting link failures, try specifying
+use_carrier=0 to see if that improves the failure detection time.  If
+it does, then it may be that the driver checks the carrier state at a
+fixed interval, but does not cache the MII register values (so the
+use_carrier=0 method of querying the registers directly works).  If
+use_carrier=0 does not improve the failover, then the driver may cache
+the registers, or the problem may be elsewhere.
+
+	Also, remember that miimon only checks for the device's
+carrier state.  It has no way to determine the state of devices on or
+beyond other ports of a switch, or if a switch is refusing to pass
+traffic while still maintaining carrier on.
+
+10. SNMP agents
+===============
+
+	If running SNMP agents, the bonding driver should be loaded
+before any network drivers participating in a bond.  This requirement
+is due to the the interface index (ipAdEntIfIndex) being associated to
+the first interface found with a given IP address.  That is, there is
+only one ipAdEntIfIndex for each IP address.  For example, if eth0 and
+eth1 are slaves of bond0 and the driver for eth0 is loaded before the
+bonding driver, the interface for the IP address will be associated
+with the eth0 interface.  This configuration is shown below, the IP
+address 192.168.1.1 has an interface index of 2 which indexes to eth0
+in the ifDescr table (ifDescr.2).
 
-	This method will automatically take the address from the next slave
-	that will be added.
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth3
+     interfaces.ifTable.ifEntry.ifDescr.6 = bond0
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 4
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
 
-	To restore your slaves' MAC addresses, you need to detach them
-	from the bond (`ifenslave -d bond0 eth0'). The bonding driver will then
-	restore the MAC addresses that the slaves had before they were enslaved.
+	This problem is avoided by loading the bonding driver before
+any network drivers participating in a bond.  Below is an example of
+loading the bonding driver first, the IP address 192.168.1.1 is
+correctly associated with ifDescr.2.
 
-9.  Which transmit polices can be used?
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = bond0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.6 = eth3
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 6
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
 
-	Round-robin, based on the order of enslaving, the output device
-	is selected base on the next available slave. Regardless of
-	the source and/or destination of the packet.
+	While some distributions may not report the interface name in
+ifDescr, the association between the IP address and IfIndex remains
+and SNMP functions such as Interface_Scan_Next will report that
+association.
 
-	Active-backup policy that ensures that one and only one device will
-	transmit at any given moment. Active-backup policy is useful for
-	implementing high availability solutions using two hubs (see
-	section on High Availability).
+11. Promiscuous mode
+====================
 
-	XOR, based on (src hw addr XOR dst hw addr) % slave count. This
-	policy selects the same slave for each destination hw address.
+	When running network monitoring tools, e.g., tcpdump, it is
+common to enable promiscuous mode on the device, so that all traffic
+is seen (instead of seeing only traffic destined for the local host).
+The bonding driver handles promiscuous mode changes to the bonding
+master device (e.g., bond0), and propogates the setting to the slave
+devices.
+
+	For the balance-rr, balance-xor, broadcast, and 802.3ad modes,
+the promiscuous mode setting is propogated to all slaves.
+
+	For the active-backup, balance-tlb and balance-alb modes, the
+promiscuous mode setting is propogated only to the active slave.
+
+	For balance-tlb mode, the active slave is the slave currently
+receiving inbound traffic.
+
+	For balance-alb mode, the active slave is the slave used as a
+"primary."  This slave is used for mode-specific control traffic, for
+sending to peers that are unassigned or if the load is unbalanced.
+
+	For the active-backup, balance-tlb and balance-alb modes, when
+the active slave changes (e.g., due to a link failure), the
+promiscuous setting will be propogated to the new active slave.
+
+12. High Availability Information
+=================================
+
+	High Availability refers to configurations that provide
+maximum network availability by having redundant or backup devices,
+links and switches between the host and the rest of the world.
+
+	There are currently two basic methods for configuring to
+maximize availability. They are dependent on the network topology and
+the primary goal of the configuration, but in general, a configuration
+can be optimized for maximum available bandwidth, or for maximum
+network availability.
+
+12.1 High Availability in a Single Switch Topology
+--------------------------------------------------
+
+	If two hosts (or a host and a switch) are directly connected
+via multiple physical links, then there is no network availability
+penalty for optimizing for maximum bandwidth: there is only one switch
+(or peer), so if it fails, you have no alternative access to fail over
+to.
 
-	Broadcast policy transmits everything on all slave interfaces.
+Example 1 : host to switch (or other host)
 
-	802.3ad, based on XOR but distributes traffic among all interfaces
-	in the active aggregator.
+          +----------+                          +----------+
+          |          |eth0                  eth0|  switch  |
+          | Host A   +--------------------------+    or    |
+          |          +--------------------------+  other   |
+          |          |eth1                  eth1|  host    |
+          +----------+                          +----------+
 
-	Transmit load balancing (balance-tlb) balances the traffic
-	according to the current load on each slave. The balancing is
-	clients based and the least loaded slave is selected for each new
-	client. The load of each slave is calculated relative to its speed
-	and enables load balancing in mixed speed teams.
 
-	Adaptive load balancing (balance-alb) uses the Transmit load
-	balancing for the transmit load. The receive load is balanced only
-	among the group of highest speed active slaves in the bond. The
-	load is distributed with round-robin i.e. next available slave in
-	the high speed group of active slaves.
+12.1.1 Bonding Mode Selection for single switch topology
+--------------------------------------------------------
 
-High Availability
-=================
+	This configuration is the easiest to set up and to understand,
+although you will have to decide which bonding mode best suits your
+needs.  The tradeoffs for each mode are detailed below:
+
+balance-rr: This mode is the only mode that will permit a single
+	TCP/IP connection to stripe traffic across multiple
+	interfaces. It is therefore the only mode that will allow a
+	single TCP/IP stream to utilize more than one interface's
+	worth of throughput.  This comes at a cost, however: the
+	striping often results in peer systems receiving packets out
+	of order, causing TCP/IP's congestion control system to kick
+	in, often by retransmitting segments.
+
+	It is possible to adjust TCP/IP's congestion limits by
+	altering the net.ipv4.tcp_reordering sysctl parameter.  The
+	usual default value is 3, and the maximum useful value is 127.
+	For a four interface balance-rr bond, expect that a single
+	TCP/IP stream will utilize no more than approximately 2.3
+	interface's worth of throughput, even after adjusting
+	tcp_reordering.
+
+	If you are utilizing protocols other than TCP/IP, UDP for
+	example, and your application can tolerate out of order
+	delivery, then this mode can allow for single stream datagram
+	performance that scales near linearly as interfaces are added
+	to the bond.
+
+	This mode requires the switch to have the appropriate ports
+	configured for "etherchannel" or "trunking."
+
+active-backup: There is not much advantage in this network topology to
+	the active-backup mode, as the inactive backup devices are all
+	connected to the same peer as the primary.  In this case, a
+	load balancing mode (with link monitoring) will provide the
+	same level of network availability, but with increased
+	available bandwidth.  On the plus side, it does not require
+	any configuration of the switch.
+
+balance-xor: This mode will limit traffic such that packets destined
+	for specific peers will always be sent over the same
+	interface.  Since the destination is determined by the MAC
+	addresses involved, this may be desirable if you have a large
+	network with many hosts.  It is likely to be suboptimal if all
+	your traffic is passed through a single router, however.  As
+	with balance-rr, the switch ports need to be configured for
+	"etherchannel" or "trunking."
+
+broadcast: Like active-backup, there is not much advantage to this
+	mode in this type of network topology.
+
+802.3ad: This mode can be a good choice for this type of network
+	topology.  The 802.3ad mode is an IEEE standard, so all peers
+	that implement 802.3ad should interoperate well.  The 802.3ad
+	protocol includes automatic configuration of the aggregates,
+	so minimal manual configuration of the switch is needed
+	(typically only to designate that some set of devices is
+	usable for 802.3ad).  The 802.3ad standard also mandates that
+	frames be delivered in order (within certain limits), so in
+	general single connections will not see misordering of
+	packets.  The 802.3ad mode does have some drawbacks: the
+	standard mandates that all devices in the aggregate operate at
+	the same speed and duplex.  Also, as with all bonding load
+	balance modes other than balance-rr, no single connection will
+	be able to utilize more than a single interface's worth of
+	bandwidth.  Additionally, the linux bonding 802.3ad
+	implementation distributes traffic by peer (using an XOR of
+	MAC addresses), so in general all traffic to a particular
+	destination will use the same interface.  Finally, the 802.3ad
+	mode mandates the use of the MII monitor, therefore, the ARP
+	monitor is not available in this mode.
+
+balance-tlb: This mode is also a good choice for this type of
+	topology.  It has no special switch configuration
+	requirements, and balances outgoing traffic by peer, in a
+	vaguely intelligent manner (not a simple XOR as in balance-xor
+	or 802.3ad mode), so that unlucky MAC addresses will not all
+	"bunch up" on a single interface.  Interfaces may be of
+	differing speeds.  On the down side, in this mode all incoming
+	traffic arrives over a single interface, this mode requires
+	certain ethtool support in the network device driver of the
+	slave interfaces, and the ARP monitor is not available.
+
+balance-alb: This mode is everything that balance-tlb is, and more. It
+	has all of the features (and restrictions) of balance-tlb, and
+	will also balance incoming traffic from peers (as described in
+	the Bonding Module Options section, above).  The only extra
+	down side to this mode is that the network device driver must
+	support changing the hardware address while the device is
+	open.
+
+12.1.2 Link Monitoring for Single Switch Topology
+-------------------------------------------------
+
+	The choice of link monitoring may largely depend upon which
+mode you choose to use.  The more advanced load balancing modes do not
+support the use of the ARP monitor, and are thus restricted to using
+the MII monitor (which does not provide as high a level of assurance
+as the ARP monitor).
+
+
+12.2 High Availability in a Multiple Switch Topology
+----------------------------------------------------
+
+	With multiple switches, the configuration of bonding and the
+network changes dramatically.  In multiple switch topologies, there is
+a tradeoff between network availability and usable bandwidth.
 
-To implement high availability using the bonding driver, the driver needs to be
-compiled as a module, because currently it is the only way to pass parameters
-to the driver. This may change in the future.
-
-High availability is achieved by using MII or ETHTOOL status reporting. You
-need to verify that all your interfaces support MII or ETHTOOL link status
-reporting.  On Linux kernel 2.2.17, all the 100 Mbps capable drivers and
-yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting
-is available for interface eth0, type "ethtool eth0" and the "Link detected:"
-line should contain the correct link status. If your system has an interface
-that does not support MII or ETHTOOL status reporting, a failure of its link
-will not be detected! A message indicating MII and ETHTOOL is not supported by
-a network driver is logged when the bonding driver is loaded with a non-zero
-miimon value.
-
-The bonding driver can regularly check all its slaves links using the ETHTOOL
-IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The
-check interval is specified by the module argument "miimon" (MII monitoring).
-It takes an integer that represents the checking time in milliseconds. It
-should not come to close to (1000/HZ) (10 milli-seconds on i386) because it
-may then reduce the system interactivity. A value of 100 seems to be a good
-starting point. It means that a dead link will be detected at most 100
-milli-seconds after it goes down.
-
-Example:
-
-   # modprobe bonding miimon=100
-
-Or, put the following line in /etc/modprobe.conf:
-
-   options bond0 miimon=100
-
-There are currently two policies for high availability. They are dependent on
-whether:
-
-   a) hosts are connected to a single host or switch that support trunking
-
-   b) hosts are connected to several different switches or a single switch that
-      does not support trunking
-
-
-1) High Availability on a single switch or host - load balancing
-----------------------------------------------------------------
-It is the easiest to set up and to understand. Simply configure the
-remote equipment (host or switch) to aggregate traffic over several
-ports (Trunk, EtherChannel, etc.) and configure the bonding interfaces.
-If the module has been loaded with the proper MII option, it will work
-automatically. You can then try to remove and restore different links
-and see in your logs what the driver detects. When testing, you may
-encounter problems on some buggy switches that disable the trunk for a
-long time if all ports in a trunk go down. This is not Linux, but really
-the switch (reboot it to ensure).
+	Below is a sample network, configured to maximize the
+availability of the network:
 
-Example 1 : host to host at twice the speed
+                |                                     |
+                |port3                           port3|
+          +-----+----+                          +-----+----+
+          |          |port2       ISL      port2|          |
+          | switch A +--------------------------+ switch B |
+          |          |                          |          |
+          +-----+----+                          +-----++---+
+                |port1                           port1|
+                |             +-------+               |
+                +-------------+ host1 +---------------+
+                         eth0 +-------+ eth1
 
-          +----------+                          +----------+
-          |          |eth0                  eth0|          |
-          | Host A   +--------------------------+  Host B  |
-          |          +--------------------------+          |
-          |          |eth1                  eth1|          |
-          +----------+                          +----------+
+	In this configuration, there is a link between the two
+switches (ISL, or inter switch link), and multiple ports connecting to
+the outside world ("port3" on each switch).  There is no technical
+reason that this could not be extended to a third switch.
+
+12.2.1 Bonding Mode Selection for Multiple Switch Topology
+----------------------------------------------------------
+
+	In a topology such as this, the active-backup and broadcast
+modes are the only useful bonding modes; the other modes require all
+links to terminate on the same peer for them to behave rationally.
+
+active-backup: This is generally the preferred mode, particularly if
+	the switches have an ISL and play together well.  If the
+	network configuration is such that one switch is specifically
+	a backup switch (e.g., has lower capacity, higher cost, etc),
+	then the primary option can be used to insure that the
+	preferred link is always used when it is available.
+
+broadcast: This mode is really a special purpose mode, and is suitable
+	only for very specific needs.  For example, if the two
+	switches are not connected (no ISL), and the networks beyond
+	them are totally independant.  In this case, if it is
+	necessary for some specific one-way traffic to reach both
+	independent networks, then the broadcast mode may be suitable.
+
+12.2.2 Link Monitoring Selection for Multiple Switch Topology
+-------------------------------------------------------------
+
+	The choice of link monitoring ultimately depends upon your
+switch.  If the switch can reliably fail ports in response to other
+failures, then either the MII or ARP monitors should work.  For
+example, in the above example, if the "port3" link fails at the remote
+end, the MII monitor has no direct means to detect this.  The ARP
+monitor could be configured with a target at the remote end of port3,
+thus detecting that failure without switch support.
+
+	In general, however, in a multiple switch topology, the ARP
+monitor can provide a higher level of reliability in detecting link
+failures.  Additionally, it should be configured with multiple targets
+(at least one for each switch in the network).  This will insure that,
+regardless of which switch is active, the ARP monitor has a suitable
+target to query.
+
+
+12.3 Switch Behavior Issues for High Availability
+-------------------------------------------------
+
+	You may encounter issues with the timing of link up and down
+reporting by the switch.
+
+	First, when a link comes up, some switches may indicate that
+the link is up (carrier available), but not pass traffic over the
+interface for some period of time.  This delay is typically due to
+some type of autonegotiation or routing protocol, but may also occur
+during switch initialization (e.g., during recovery after a switch
+failure).  If you find this to be a problem, specify an appropriate
+value to the updelay bonding module option to delay the use of the
+relevant interface(s).
+
+	Second, some switches may "bounce" the link state one or more
+times while a link is changing state.  This occurs most commonly while
+the switch is initializing.  Again, an appropriate updelay value may
+help, but note that if all links are down, then updelay is ignored
+when any link becomes active (the slave closest to completing its
+updelay is chosen).
+
+	Note that when a bonding interface has no active links, the
+driver will immediately reuse the first link that goes up, even if
+updelay parameter was specified.  If there are slave interfaces
+waiting for the updelay timeout to expire, the interface that first
+went into that state will be immediately reused.  This reduces down
+time of the network if the value of updelay has been overestimated.
+
+	In addition to the concerns about switch timings, if your
+switches take a long time to go into backup mode, it may be desirable
+to not activate a backup interface immediately after a link goes down.
+Failover may be delayed via the downdelay bonding module option.
+
+13. Hardware Specific Considerations
+====================================
+
+	This section contains additional information for configuring
+bonding on specific hardware platforms, or for interfacing bonding
+with particular switches or other devices.
+
+13.1 IBM BladeCenter
+--------------------
+
+	This applies to the JS20 and similar systems.
+
+	On the JS20 blades, the bonding driver supports only
+balance-rr, active-backup, balance-tlb and balance-alb modes.  This is
+largely due to the network topology inside the BladeCenter, detailed
+below.
+
+JS20 network adapter information
+--------------------------------
+
+	All JS20s come with two Broadcom Gigabit Ethernet ports
+integrated on the planar.  In the BladeCenter chassis, the eth0 port
+of all JS20 blades is hard wired to I/O Module #1; similarly, all eth1
+ports are wired to I/O Module #2.  An add-on Broadcom daughter card
+can be installed on a JS20 to provide two more Gigabit Ethernet ports.
+These ports, eth2 and eth3, are wired to I/O Modules 3 and 4,
+respectively.
+
+	Each I/O Module may contain either a switch or a passthrough
+module (which allows ports to be directly connected to an external
+switch).  Some bonding modes require a specific BladeCenter internal
+network topology in order to function; these are detailed below.
 
-  On each host :
-     # modprobe bonding miimon=100
-     # ifconfig bond0 addr
-     # ifenslave bond0 eth0 eth1
+	Additional BladeCenter-specific networking information can be
+found in two IBM Redbooks (www.ibm.com/redbooks):
 
-Example 2 : host to switch at twice the speed
+"IBM eServer BladeCenter Networking Options"
+"IBM eServer BladeCenter Layer 2-7 Network Switching"
 
-          +----------+                          +----------+
-          |          |eth0                 port1|          |
-          | Host A   +--------------------------+  switch  |
-          |          +--------------------------+          |
-          |          |eth1                 port2|          |
-          +----------+                          +----------+
+BladeCenter networking configuration
+------------------------------------
 
-  On host A :                             On the switch :
-     # modprobe bonding miimon=100           # set up a trunk on port1
-     # ifconfig bond0 addr                     and port2
-     # ifenslave bond0 eth0 eth1
+	Because a BladeCenter can be configured in a very large number
+of ways, this discussion will be confined to describing basic
+configurations.
+
+	Normally, Ethernet Switch Modules (ESM) are used in I/O
+modules 1 and 2.  In this configuration, the eth0 and eth1 ports of a
+JS20 will be connected to different internal switches (in the
+respective I/O modules).
+
+	An optical passthru module (OPM) connects the I/O module
+directly to an external switch.  By using OPMs in I/O module #1 and
+#2, the eth0 and eth1 interfaces of a JS20 can be redirected to the
+outside world and connected to a common external switch.
+
+	Depending upon the mix of ESM and OPM modules, the network
+will appear to bonding as either a single switch topology (all OPM
+modules) or as a multiple switch topology (one or more ESM modules,
+zero or more OPM modules).  It is also possible to connect ESM modules
+together, resulting in a configuration much like the example in "High
+Availability in a multiple switch topology."
+
+Requirements for specifc modes
+------------------------------
+
+	The balance-rr mode requires the use of OPM modules for
+devices in the bond, all connected to an common external switch.  That
+switch must be configured for "etherchannel" or "trunking" on the
+appropriate ports, as is usual for balance-rr.
+
+	The balance-alb and balance-tlb modes will function with
+either switch modules or passthrough modules (or a mix).  The only
+specific requirement for these modes is that all network interfaces
+must be able to reach all destinations for traffic sent over the
+bonding device (i.e., the network must converge at some point outside
+the BladeCenter).
+
+	The active-backup mode has no additional requirements.
+
+Link monitoring issues
+----------------------
+
+	When an Ethernet Switch Module is in place, only the ARP
+monitor will reliably detect link loss to an external switch.  This is
+nothing unusual, but examination of the BladeCenter cabinet would
+suggest that the "external" network ports are the ethernet ports for
+the system, when it fact there is a switch between these "external"
+ports and the devices on the JS20 system itself.  The MII monitor is
+only able to detect link failures between the ESM and the JS20 system.
+
+	When a passthrough module is in place, the MII monitor does
+detect failures to the "external" port, which is then directly
+connected to the JS20 system.
+
+Other concerns
+--------------
+
+	The Serial Over LAN link is established over the primary
+ethernet (eth0) only, therefore, any loss of link to eth0 will result
+in losing your SoL connection.  It will not fail over with other
+network traffic.
+
+	It may be desirable to disable spanning tree on the switch
+(either the internal Ethernet Switch Module, or an external switch) to
+avoid fail-over delays issues when using bonding.
+
+	
+14. Frequently Asked Questions
+==============================
 
+1.  Is it SMP safe?
 
-2) High Availability on two or more switches (or a single switch without
-   trunking support)
----------------------------------------------------------------------------
-This mode is more problematic because it relies on the fact that there
-are multiple ports and the host's MAC address should be visible on one
-port only to avoid confusing the switches.
+	Yes. The old 2.0.xx channel bonding patch was not SMP safe.
+The new driver was designed to be SMP safe from the start.
 
-If you need to know which interface is the active one, and which ones are
-backup, use ifconfig. All backup interfaces have the NOARP flag set.
+2.  What type of cards will work with it?
 
-To use this mode, pass "mode=1" to the module at load time :
+	Any Ethernet type cards (you can even mix cards - a Intel
+EtherExpress PRO/100 and a 3com 3c905b, for example).  They need not
+be of the same speed.
 
-    # modprobe bonding miimon=100 mode=active-backup
+3.  How many bonding devices can I have?
 
-	or:
+	There is no limit.
 
-    # modprobe bonding miimon=100 mode=1
+4.  How many slaves can a bonding device have?
 
-Or, put in your /etc/modprobe.conf :
+	This is limited only by the number of network interfaces Linux
+supports and/or the number of network cards you can place in your
+system.
 
-    options bond0 miimon=100 mode=active-backup
+5.  What happens when a slave link dies?
 
-Example 1: Using multiple host and multiple switches to build a "no single
-point of failure" solution.
+	If link monitoring is enabled, then the failing device will be
+disabled.  The active-backup mode will fail over to a backup link, and
+other modes will ignore the failed link.  The link will continue to be
+monitored, and should it recover, it will rejoin the bond (in whatever
+manner is appropriate for the mode). See the section on High
+Availability for additional information.
+	
+	Link monitoring can be enabled via either the miimon or
+arp_interval paramters (described in the module paramters section,
+above).  In general, miimon monitors the carrier state as sensed by
+the underlying network device, and the arp monitor (arp_interval)
+monitors connectivity to another host on the local network.
+
+	If no link monitoring is configured, the bonding driver will
+be unable to detect link failures, and will assume that all links are
+always available.  This will likely result in lost packets, and a
+resulting degredation of performance.  The precise performance loss
+depends upon the bonding mode and network configuration.
 
+6.  Can bonding be used for High Availability?
 
-                |                                     |
-                |port3                           port3|
-          +-----+----+                          +-----+----+
-          |          |port7       ISL      port7|          |
-          | switch A +--------------------------+ switch B |
-          |          +--------------------------+          |
-          |          |port8                port8|          |
-          +----++----+                          +-----++---+
-          port2||port1                           port1||port2
-               ||             +-------+               ||
-               |+-------------+ host1 +---------------+|
-               |         eth0 +-------+ eth1           |
-               |                                       |
-               |              +-------+                |
-               +--------------+ host2 +----------------+
-                         eth0 +-------+ eth1
+	Yes.  See the section on High Availability for details.
 
-In this configuration, there is an ISL - Inter Switch Link (could be a trunk),
-several servers (host1, host2 ...) attached to both switches each, and one or
-more ports to the outside world (port3...). One and only one slave on each host
-is active at a time, while all links are still monitored (the system can
-detect a failure of active and backup links).
-
-Each time a host changes its active interface, it sticks to the new one until
-it goes down. In this example, the hosts are negligibly affected by the
-expiration time of the switches' forwarding tables.
-
-If host1 and host2 have the same functionality and are used in load balancing
-by another external mechanism, it is good to have host1's active interface
-connected to one switch and host2's to the other. Such system will survive
-a failure of a single host, cable, or switch. The worst thing that may happen
-in the case of a switch failure is that half of the hosts will be temporarily
-unreachable until the other switch expires its tables.
+7.  Which switches/systems does it work with?
 
-Example 2: Using multiple ethernet cards connected to a switch to configure
-           NIC failover (switch is not required to support trunking).
+	The full answer to this depends upon the desired mode.
 
+	In the basic balance modes (balance-rr and balance-xor), it
+works with any system that supports etherchannel (also called
+trunking).  Most managed switches currently available have such
+support, and many unmananged switches as well.
+
+	The advanced balance modes (balance-tlb and balance-alb) do
+not have special switch requirements, but do need device drivers that
+support specific features (described in the appropriate section under
+module paramters, above).
+
+	In 802.3ad mode, it works with with systems that support IEEE
+802.3ad Dynamic Link Aggregation.  Most managed and many unmanaged
+switches currently available support 802.3ad.
 
-          +----------+                          +----------+
-          |          |eth0                 port1|          |
-          | Host A   +--------------------------+  switch  |
-          |          +--------------------------+          |
-          |          |eth1                 port2|          |
-          +----------+                          +----------+
+        The active-backup mode should work with any Layer-II switch.
 
-  On host A :                                 On the switch :
-     # modprobe bonding miimon=100 mode=1     # (optional) minimize the time
-     # ifconfig bond0 addr                    # for table expiration
-     # ifenslave bond0 eth0 eth1
+8.  Where does a bonding device get its MAC address from?
 
-Each time the host changes its active interface, it sticks to the new one until
-it goes down. In this example, the host is strongly affected by the expiration
-time of the switch forwarding table.
+	If not explicitly configured with ifconfig, the MAC address of
+the bonding device is taken from its first slave device. This MAC
+address is then passed to all following slaves and remains persistent
+(even if the the first slave is removed) until the bonding device is
+brought down or reconfigured.
+
+	If you wish to change the MAC address, you can set it with
+ifconfig:
+
+# ifconfig bond0 hw ether 00:11:22:33:44:55
+
+	The MAC address can be also changed by bringing down/up the
+device and then changing its slaves (or their order):
+
+# ifconfig bond0 down ; modprobe -r bonding
+# ifconfig bond0 .... up
+# ifenslave bond0 eth...
 
+	This method will automatically take the address from the next
+slave that is added.
 
-3) Adapting to your switches' timing
-------------------------------------
-If your switches take a long time to go into backup mode, it may be
-desirable not to activate a backup interface immediately after a link goes
-down. It is possible to delay the moment at which a link will be
-completely disabled by passing the module parameter "downdelay" (in
-milliseconds, must be a multiple of miimon).
-
-When a switch reboots, it is possible that its ports report "link up" status
-before they become usable. This could fool a bond device by causing it to
-use some ports that are not ready yet. It is possible to delay the moment at
-which an active link will be reused by passing the module parameter "updelay"
-(in milliseconds, must be a multiple of miimon).
-
-A similar situation can occur when a host re-negotiates a lost link with the
-switch (a case of cable replacement).
-
-A special case is when a bonding interface has lost all slave links. Then the
-driver will immediately reuse the first link that goes up, even if updelay
-parameter was specified. (If there are slave interfaces in the "updelay" state,
-the interface that first went into that state will be immediately reused.) This
-allows to reduce down-time if the value of updelay has been overestimated.
-
-Examples :
-
-    # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000
-    # modprobe bonding miimon=100 mode=balance-rr downdelay=0 updelay=5000
-
-
-Promiscuous Sniffing notes
-==========================
-
-If you wish to bond channels together for a network sniffing
-application --- you wish to run tcpdump, or ethereal, or an IDS like
-snort, with its input aggregated from multiple interfaces using the
-bonding driver --- then you need to handle the Promiscuous interface
-setting by hand. Specifically, when you "ifconfing bond0 up" you
-must add the promisc flag there; it will be propagated down to the
-slave interfaces at ifenslave time; a full example might look like:
-
-   ifconfig bond0 promisc up
-   for if in eth1 eth2 ...;do
-       ifconfig $if up
-       ifenslave bond0 $if
-   done
-   snort ... -i bond0 ...
-
-Ifenslave also wants to propagate addresses from interface to
-interface, appropriately for its design functions in HA and channel
-capacity aggregating; but it works fine for unnumbered interfaces;
-just ignore all the warnings it emits.
+	To restore your slaves' MAC addresses, you need to detach them
+from the bond (`ifenslave -d bond0 eth0'). The bonding driver will
+then restore the MAC addresses that the slaves had before they were
+enslaved.
 
+15. Resources and Links
+=======================
 
-8021q VLAN support
-==================
+The latest version of the bonding driver can be found in the latest
+version of the linux kernel, found on http://kernel.org
 
-It is possible to configure VLAN devices over a bond interface using the 8021q
-driver. However, only packets coming from the 8021q driver and passing through
-bonding will be tagged by default. Self generated packets, like bonding's
-learning packets or ARP packets generated by either ALB mode or the ARP
-monitor mechanism, are tagged internally by bonding itself. As a result,
-bonding has to "learn" what VLAN IDs are configured on top of it, and it uses
-those IDs to tag self generated packets.
-
-For simplicity reasons, and to support the use of adapters that can do VLAN
-hardware acceleration offloding, the bonding interface declares itself as
-fully hardware offloaing capable, it gets the add_vid/kill_vid notifications
-to gather the necessary information, and it propagates those actions to the
-slaves.
-In case of mixed adapter types, hardware accelerated tagged packets that should
-go through an adapter that is not offloading capable are "un-accelerated" by the
-bonding driver so the VLAN tag sits in the regular location.
-
-VLAN interfaces *must* be added on top of a bonding interface only after
-enslaving at least one slave. This is because until the first slave is added the
-bonding interface has a HW address of 00:00:00:00:00:00, which will be copied by
-the VLAN interface when it is created.
-
-Notice that a problem would occur if all slaves are released from a bond that
-still has VLAN interfaces on top of it. When later coming to add new slaves, the
-bonding interface would get a HW address from the first slave, which might not
-match that of the VLAN interfaces. It is recommended that either all VLANs are
-removed and then re-added, or to manually set the bonding interface's HW
-address so it matches the VLAN's. (Note: changing a VLAN interface's HW address
-would set the underlying device -- i.e. the bonding interface -- to promiscouos
-mode, which might not be what you want).
-
-
-Limitations
-===========
-The main limitations are :
-  - only the link status is monitored. If the switch on the other side is
-    partially down (e.g. doesn't forward anymore, but the link is OK), the link
-    won't be disabled. Another way to check for a dead link could be to count
-    incoming frames on a heavily loaded host. This is not applicable to small
-    servers, but may be useful when the front switches send multicast
-    information on their links (e.g. VRRP), or even health-check the servers.
-    Use the arp_interval/arp_ip_target parameters to count incoming/outgoing
-    frames.
+Discussions regarding the bonding driver take place primarily on the
+bonding-devel mailing list, hosted at sourceforge.net.  If you have
+questions or problems, post them to the list.
 
+bonding-devel@lists.sourceforge.net
 
+https://lists.sourceforge.net/lists/listinfo/bonding-devel
 
-Resources and Links
-===================
+There is also a project site on sourceforge.
 
-Current development on this driver is posted to:
- - http://www.sourceforge.net/projects/bonding/
+http://www.sourceforge.net/projects/bonding
 
 Donald Becker's Ethernet Drivers and diag programs may be found at :
  - http://www.scyld.com/network/
 
-You will also find a lot of information regarding Ethernet, NWay, MII, etc. at
-www.scyld.com.
-
-Patches for 2.2 kernels are at Willy Tarreau's site :
- - http://wtarreau.free.fr/pub/bonding/
- - http://www-miaif.lip6.fr/~tarreau/pub/bonding/
-
-To get latest informations about Linux Kernel development, please consult
-the Linux Kernel Mailing List Archives at :
-   http://www.ussg.iu.edu/hypermail/linux/kernel/
+You will also find a lot of information regarding Ethernet, NWay, MII,
+etc. at www.scyld.com.
 
 -- END --
diff --git a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
--- a/Documentation/networking/e100.txt
+++ b/Documentation/networking/e100.txt
@@ -140,8 +140,7 @@ Additional Configurations
   NAPI
   ----
 
-  NAPI (Rx polling mode) is supported in the e100 driver. NAPI is enabled
-  or disabled based on the configuration of the kernel. 
+  NAPI (Rx polling mode) is supported in the e100 driver.
 
   See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI.
 
diff --git a/Documentation/networking/ethertap.txt b/Documentation/networking/ethertap.txt
deleted file mode 100644
--- a/Documentation/networking/ethertap.txt
+++ /dev/null
@@ -1,268 +0,0 @@
-NOTE: Ethertap is now an obsolete facility, and is scheduled
-      to be removed in the 2.5.x kernel series.  Those writing
-      applications using ethertap should convert their code to
-      use the TUN/TAP driver instead, see 'tuntap.txt' in this
-      directory for more details.  -DaveM
-
-Ethertap programming mini-HOWTO
--------------------------------
-
-The ethertap driver was written by Jay Schulist <jschlst@samba.org>,
-you should contact him for further information. This document was written by
-bert hubert <bert.hubert@netherlabs.nl>. Updates are welcome.
-
-What ethertap can do for you
-----------------------------
-
-Ethertap allows you to easily run your own network stack from userspace.
-Tunnels can benefit greatly from this. You can also use it to do network
-experiments. The alternative would be to use a raw socket to send data and
-use libpcap to receive it. Using ethertap saves you this multiplicity and
-also does ARP for you if you want.
-
-The more technical blurb:
-
-Ethertap provides packet reception and transmission for user space programs.
-It can be viewed as a simple Ethernet device, which instead of receiving
-packets from a network wire, it receives them from user space.
-
-Ethertap can be used for anything from AppleTalk to IPX to even building
-bridging tunnels. It also has many other general purpose uses.
-
-Configuring your kernel
------------------------
-
-Firstly, you need this in Networking Options:
-
-	#
-	# Code maturity level options
-	#
-	CONFIG_EXPERIMENTAL=y
-
-Then you need Netlink support:
-
-	CONFIG_NETLINK=y
-
-This allows the kernel to exchange data with userspace applications. There
-are two ways of doing this, the new way works with netlink sockets and I
-have no experience with that yet. ANK uses it in his excellent iproute2
-package, see for example rtmon.c. iproute2 can be found on
-ftp://ftp.tux.org/pub/net/ip-routing/iproute2*
-
-The new way is described, partly in netlink(7), available on 
-http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3
-
-There is also a Netlink-HOWTO, available on http://snafu.freedom.org/linux2.2/docs/netlink-HOWTO.html
-Sadly I know of no code using ethertap with this new interface.
-
-The older way works by opening character special files with major node 36.
-Enable this with:
-
-	CONFIG_NETLINK_DEV=m
-
-Please be advised that this support is going to be dropped somewhere in the
-future!
-
-Then finally in the Network Devices section, 
-
-	CONFIG_ETHERTAP=m
-
-You can include it directly in the kernel if you want, of course, no need
-for modules.
-
-Setting it all up
------------------
-
-First we need to create the /dev/tap0 device node:
-
-	# mknod /dev/tap0 c 36 16
-	# mknod /dev/tap1 c 36 17
-	(etc)
-
-Include the relevant modules (ethertap.o, netlink_dev.o, perhaps netlink.o),
-and bring up your tap0 device:
-
-	# ifconfig tap0 10.0.0.123 up
-
-Now your device is up and running, you can ping it as well. This is what
-confused me to no end, because nothing is connected to our ethertap as yet,
-how is it that we can ping it?
-
-It turns out that the ethertap is just like a regular network interface -
-even when it's down you can ping it. We need to route stuff to it:
-
-	# route add -host 10.0.0.124 gw 10.0.0.123
-
-Now we can read /dev/tap0 and when we ping 10.0.0.124 from our
-localhost, output should appear on the screen.
-
-	# cat /dev/tap0
-	:ßVU:9````````````````````````þýþET@?'
-
-
-Getting this to work from other hosts
--------------------------------------
-
-For this to work, you often need proxy ARP. 
-
-	# echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp 
-
-eth0 here stands for the interface that connects to 'other hosts'.
-
-Chances are that you are trying this on a non-routing desktop computer, so
-you need to enable ip forwarding:
-
-	# echo 1 > /proc/sys/net/ipv4/ip_forward 
-
-You should now be able to ping 10.0.0.124 from other hosts on your
-10.0.0.0/8 subnet. If you are using public ip space, it should work from
-everywhere.
-
-ARP
----
-
-If we were to take things very literally, your tcp/ip pseudo stack would
-also have to implement ARP and MAC addresses. This is often a bit silly as
-the ethertap device is a figment of our imagination anyway. However, should
-you want to go 'all the way', you can add the 'arp' flag to ifconfig:
-
-	# ifconfig tap0 10.0.0.123 up arp
-
-This may also be useful when implementing a bridge, which needs to bridge
-ARP packets as well.
-
-The sample program below will no longer work then, because it does not
-implement ARP. 
-
-Sample program
---------------
-
-A sample program is included somewhere in the bowels of the netfilter
-source. I've extracted this program and list it here. It implements a very
-tiny part of the IP stack and can respond to any pings it receives. It gets
-confused if it receives ARP, as it tries to parse it by treating it as an IP
-packet.
-
-/* Simple program to listen to /dev/tap0 and reply to pings. */
-#include <fcntl.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#if defined(__GLIBC__) && (__GLIBC__ == 2)
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-#else
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#endif
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-
-u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum)
-{
-	u_int32_t sum = 0;
-	u_int16_t *ptr = buffer;
-
-	while (len > 1)  {
-		sum += *ptr++;
-		len -= 2;
-	}
-	if (len) {
-		union {
-			u_int8_t byte;
-			u_int16_t wyde;
-		} odd;
-		odd.wyde = 0;
-		odd.byte = *((u_int8_t *)ptr);
-		sum += odd.wyde;
-	}
-	sum = (sum >> 16) + (sum & 0xFFFF);
-	sum += prevsum;
-	return (sum + (sum >> 16));
-}
-
-int main()
-{
-	int fd, len;
-	union {
-		struct {
-			char etherhdr[16];
-			struct iphdr ip;
-		} fmt;
-		unsigned char raw[65536];
-	} u;
-
-	fd = open("/dev/tap0", O_RDWR);
-	if (fd < 0) {
-		perror("Opening `/dev/tap0'");
-		return 1;
-	}
-
-	/* u.fmt.ip.ihl in host order!  Film at 11. */
-	while ((len = read(fd, &u, sizeof(u))) > 0) {
-		u_int32_t tmp;
- 		struct icmphdr *icmp
-			= (void *)((u_int32_t *)&u.fmt.ip + u.fmt.ip.ihl );
-		struct tcphdr *tcp = (void *)icmp;
-		struct udphdr *udp = (void *)icmp;
-		
-		fprintf(stderr, "SRC = %u.%u.%u.%u DST = %u.%u.%u.%u\n",
-			(ntohl(u.fmt.ip.saddr) >> 24) & 0xFF,
-			(ntohl(u.fmt.ip.saddr) >> 16) & 0xFF,
-			(ntohl(u.fmt.ip.saddr) >> 8) & 0xFF,
-			(ntohl(u.fmt.ip.saddr) >> 0) & 0xFF,
-			(ntohl(u.fmt.ip.daddr) >> 24) & 0xFF,
-			(ntohl(u.fmt.ip.daddr) >> 16) & 0xFF,
-			(ntohl(u.fmt.ip.daddr) >> 8) & 0xFF,
-			(ntohl(u.fmt.ip.daddr) >> 0) & 0xFF);
-
-		switch (u.fmt.ip.protocol) {
-		case IPPROTO_ICMP:
-			if (icmp->type == ICMP_ECHO) {
-				fprintf(stderr, "PONG! (iphdr = %u bytes)\n",
-					(unsigned int)((char *)icmp
-						       - (char *)&u.fmt.ip));
-
-				/* Turn it around */
-				tmp = u.fmt.ip.saddr;
-				u.fmt.ip.saddr = u.fmt.ip.daddr;
-				u.fmt.ip.daddr = tmp;
-
-				icmp->type = ICMP_ECHOREPLY;
-				icmp->checksum = 0;
-				icmp->checksum
-					= ~csum_partial(icmp,
-							ntohs(u.fmt.ip.tot_len)
-							- u.fmt.ip.ihl*4, 0);
-
-				{
-					unsigned int i;
-					for (i = 44;
-					     i < ntohs(u.fmt.ip.tot_len); i++){
-						printf("%u:0x%02X ", i,
-						       ((unsigned char *)
-							&u.fmt.ip)[i]);
-					}
-					printf("\n");
-				}
-				write(fd, &u, len);
-			}
-			break;
-		case IPPROTO_TCP:
-			fprintf(stderr, "TCP: %u -> %u\n", ntohs(tcp->source),
-				ntohs(tcp->dest));
-			break;
-
-		case IPPROTO_UDP:
-			fprintf(stderr, "UDP: %u -> %u\n", ntohs(udp->source),
-				ntohs(udp->dest));
-			break;
-		}
-	}
-	if (len < 0)
-		perror("Reading from `/dev/tap0'");
-	else fprintf(stderr, "Empty read from `/dev/tap0'");
-	return len < 0 ? 1 : 0;
-}
-			
diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt
--- a/Documentation/networking/ixgb.txt
+++ b/Documentation/networking/ixgb.txt
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/10GbE Family of Adapters
 ================================================================
 
-September 13, 2004
+November 17, 2004
 
 
 Contents
@@ -18,8 +18,7 @@ In This Release
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/10GbE Family 
-of Adapters, version 1.0.x.  This driver includes support for Itanium(TM)2 and
-EM64T systems.
+of Adapters, version 1.0.x.  
 
 For questions related to hardware requirements, refer to the documentation 
 supplied with your Intel PRO/10GbE adapter. All hardware requirements listed 
@@ -71,8 +70,8 @@ Default: Read from the EEPROM
     Ethernet PAUSE frames.
 
 RxDescriptors
-Valid Range: 64-4096
-Default Value: 1024
+Valid Range: 64-512
+Default Value: 512
     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 
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -51,6 +51,8 @@ dev->hard_start_xmit:
 	set_multicast_list
 	Context: BHs disabled
 	Notes: netif_queue_stopped() is guaranteed false
+               Interrupts must be enabled when calling hard_start_xmit.
+                (Interrupts must also be enabled when enabling the BH handler.)
 	Return codes: 
 	o NETDEV_TX_OK everything ok. 
 	o NETDEV_TX_BUSY Cannot transmit packet, try later 
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -12,7 +12,7 @@ Don is no longer the prime maintainer of
 Please report problems to one or more of:
 
   Andrew Morton <andrewm@uow.edu.au>
-  Netdev mailing list <netdev@oss.sgi.com>
+  Netdev mailing list <netdev@vger.kernel.org>
   Linux kernel mailing list <linux-kernel@vger.kernel.org>
 
 Please note the 'Reporting and Diagnosing Problems' section at the end
diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt
--- a/Documentation/nommu-mmap.txt
+++ b/Documentation/nommu-mmap.txt
@@ -36,20 +36,35 @@ and it's also much more restricted in th
 	In the MMU case: VM regions backed by pages read from file; changes to
 	the underlying file are reflected in the mapping; copied across fork.
 
-	In the no-MMU case: VM regions backed by arbitrary contiguous runs of
-	pages into which the appropriate bit of the file is read; any remaining
-	bit of the mapping is cleared; such mappings are shared if possible;
-	writes to the file do not affect the mapping; writes to the mapping are
-	visible in other processes (no MMU protection), but should not happen.
+	In the no-MMU case:
+
+         - If one exists, the kernel will re-use an existing mapping to the
+           same segment of the same file if that has compatible permissions,
+           even if this was created by another process.
+
+         - If possible, the file mapping will be directly on the backing device
+           if the backing device has the BDI_CAP_MAP_DIRECT capability and
+           appropriate mapping protection capabilities. Ramfs, romfs, cramfs
+           and mtd might all permit this.
+
+	 - If the backing device device can't or won't permit direct sharing,
+           but does have the BDI_CAP_MAP_COPY capability, then a copy of the
+           appropriate bit of the file will be read into a contiguous bit of
+           memory and any extraneous space beyond the EOF will be cleared
+
+	 - Writes to the file do not affect the mapping; writes to the mapping
+	   are visible in other processes (no MMU protection), but should not
+	   happen.
 
  (*) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, PROT_WRITE
 
 	In the MMU case: like the non-PROT_WRITE case, except that the pages in
 	question get copied before the write actually happens. From that point
-	on writes to that page in the file no longer get reflected into the
-	mapping's backing pages.
+	on writes to the file underneath that page no longer get reflected into
+	the mapping's backing pages. The page is then backed by swap instead.
 
-	In the no-MMU case: works exactly as for the non-PROT_WRITE case.
+	In the no-MMU case: works much like the non-PROT_WRITE case, except
+	that a copy is always taken and never shared.
 
  (*) Regular file / blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
@@ -70,6 +85,15 @@ and it's also much more restricted in th
 	as for the MMU case. If the filesystem does not provide any such
 	support, then the mapping request will be denied.
 
+ (*) Memory backed blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
+
+	In the MMU case: As for ordinary regular files.
+
+	In the no-MMU case: As for memory backed regular files, but the
+	blockdev must be able to provide a contiguous run of pages without
+	truncate being called. The ramdisk driver could do this if it allocated
+	all its memory as a contiguous array upfront.
+
  (*) Memory backed chardev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
 	In the MMU case: As for ordinary regular files.
@@ -95,12 +119,12 @@ FURTHER NOTES ON NO-MMU MMAP
  (*) Supplying MAP_FIXED or a requesting a particular mapping address will
      result in an error.
 
- (*) Files mapped privately must have a read method provided by the driver or
-     filesystem so that the contents can be read into the memory allocated. An
+ (*) Files mapped privately usually have to have a read method provided by the
+     driver or filesystem so that the contents can be read into the memory
+     allocated if mmap() chooses not to map the backing device directly. An
      error will result if they don't. This is most likely to be encountered
      with character device files, pipes, fifos and sockets.
 
-
 ============================================
 PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
 ============================================
@@ -111,6 +135,15 @@ to get a proposed address for the mappin
 doesn't wish to honour the mapping because it's too long, at a weird offset,
 under some unsupported combination of flags or whatever.
 
+The driver should also provide backing device information with capabilities set
+to indicate the permitted types of mapping on such devices. The default is
+assumed to be readable and writable, not executable, and only shareable
+directly (can't be copied).
+
+The file->f_op->mmap() operation will be called to actually inaugurate the
+mapping. It can be rejected at that point. Returning the ENOSYS error will
+cause the mapping to be copied instead if BDI_CAP_MAP_COPY is specified.
+
 The vm_ops->close() routine will be invoked when the last mapping on a chardev
 is removed. An existing mapping will be shared, partially or not, if possible
 without notifying the driver.
@@ -120,7 +153,22 @@ return -ENOSYS. This will be taken to me
 want to handle it, despite the fact it's got an operation. For instance, it
 might try directing the call to a secondary driver which turns out not to
 implement it. Such is the case for the framebuffer driver which attempts to
-direct the call to the device-specific driver.
+direct the call to the device-specific driver. Under such circumstances, the
+mapping request will be rejected if BDI_CAP_MAP_COPY is not specified, and a
+copy mapped otherwise.
+
+IMPORTANT NOTE:
+
+	Some types of device may present a different appearance to anyone
+	looking at them in certain modes. Flash chips can be like this; for
+	instance if they're in programming or erase mode, you might see the
+	status reflected in the mapping, instead of the data.
+
+	In such a case, care must be taken lest userspace see a shared or a
+	private mapping showing such information when the driver is busy
+	controlling the device. Remember especially: private executable
+	mappings may still be mapped directly off the device under some
+	circumstances!
 
 
 ==============================================
@@ -139,3 +187,12 @@ memory.
 
 Memory backed devices are indicated by the mapping's backing device info having
 the memory_backed flag set.
+
+
+========================================
+PROVIDING SHAREABLE BLOCK DEVICE SUPPORT
+========================================
+
+Provision of shared mappings on block device files is exactly the same as for
+character devices. If there isn't a real device underneath, then the driver
+should allocate sufficient contiguous memory to honour any supported mapping.
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -1,23 +1,22 @@
+NOTE: ksymoops is useless on 2.6.  Please use the Oops in its original format
+(from dmesg, etc).  Ignore any references in this or other docs to "decoding
+the Oops" or "running it through ksymoops".  If you post an Oops fron 2.6 that
+has been run through ksymoops, people will just tell you to repost it.
+
 Quick Summary
 -------------
 
-Install ksymoops from
-ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops
-Read the ksymoops man page.
-ksymoops < the_oops.txt
-
-and send the output the maintainer of the kernel area that seems to be
-involved with the problem, not to the ksymoops maintainer. Don't worry
-too much about getting the wrong person. If you are unsure send it to
-the person responsible for the code relevant to what you were doing.
-If it occurs repeatably try and describe how to recreate it. Thats
-worth even more than the oops
+Find the Oops and send it to the maintainer of the kernel area that seems to be
+involved with the problem.  Don't worry too much about getting the wrong person.
+If you are unsure send it to the person responsible for the code relevant to
+what you were doing.  If it occurs repeatably try and describe how to recreate
+it.  That's worth even more than the oops.
 
 If you are totally stumped as to whom to send the report, send it to 
 linux-kernel@vger.kernel.org. Thanks for your help in making Linux as
 stable as humanly possible.
 
-Where is the_oops.txt?
+Where is the Oops?
 ----------------------
 
 Normally the Oops text is read from the kernel buffers by klogd and
@@ -43,15 +42,14 @@ the disk is not available then you have 
     them yourself.  Search kernel archives for kmsgdump, lkcd and
     oops+smram.
 
-No matter how you capture the log output, feed the resulting file to
-ksymoops along with /proc/ksyms and /proc/modules that applied at the
-time of the crash.  /var/log/ksymoops can be useful to capture the
-latter, man ksymoops for details.
-
 
 Full Information
 ----------------
 
+NOTE: the message from Linus below applies to 2.4 kernel.  I have preserved it
+for historical reasons, and because some of the information in it still
+applies.  Especially, please ignore any references to ksymoops. 
+
 From: Linus Torvalds <torvalds@osdl.org>
 
 How to track down an Oops.. [originally a mail to linux-kernel]
diff --git a/Documentation/parisc/00-INDEX b/Documentation/parisc/00-INDEX
--- a/Documentation/parisc/00-INDEX
+++ b/Documentation/parisc/00-INDEX
@@ -1,10 +1,6 @@
 00-INDEX
 	- this file.
-IODC.txt
-	- Documentation IODC
 debugging
 	- some debugging hints for real-mode code
-mm
-	- Documentation on parisc mm status
 registers
 	- current/planned usage of registers
diff --git a/Documentation/parport.txt b/Documentation/parport.txt
--- a/Documentation/parport.txt
+++ b/Documentation/parport.txt
@@ -264,5 +264,5 @@ the DMA channel, and try with:
     io=0x378 irq=7 dma=none (for PIO)
     io=0x378 irq=7 dma=3 (for DMA)
 --
-Philip.Blundell@pobox.com
+philb@gnu.org
 tim@cyberelk.net
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -99,10 +99,10 @@ where all fields are passed in as hexade
 Users need pass only as many fields as necessary; vendor, device,
 subvendor, and subdevice fields default to PCI_ANY_ID (FFFFFFFF),
 class and classmask fields default to 0, and driver_data defaults to
-0UL.  Device drivers must call
-   pci_dynids_set_use_driver_data(pci_driver *, 1)
-in order for the driver_data field to get passed to the driver.
-Otherwise, only a 0 is passed in that field.
+0UL.  Device drivers must initialize use_driver_data in the dynids struct
+in their pci_driver struct prior to calling pci_register_driver in order
+for the driver_data field to get passed to the driver. Otherwise, only a
+0 is passed in that field.
 
 When the driver exits, it just calls pci_unregister_driver() and the PCI layer
 automatically calls the remove hook for all devices handled by the driver.
@@ -279,6 +279,7 @@ pci_for_each_dev_reverse()	Superseded by
 pci_for_each_bus()		Superseded by pci_find_next_bus()
 pci_find_device()		Superseded by pci_get_device()
 pci_find_subsys()		Superseded by pci_get_subsys()
+pci_find_slot()			Superseded by pci_get_slot()
 pcibios_find_class()		Superseded by pci_get_class()
 pci_find_class()		Superseded by pci_get_class()
 pci_(read|write)_*_nodev()	Superseded by pci_bus_(read|write)_*()
diff --git a/Documentation/pm.txt b/Documentation/pm.txt
--- a/Documentation/pm.txt
+++ b/Documentation/pm.txt
@@ -222,23 +222,6 @@ communicate with drivers through the exi
 management interface.
 
 /*
- * Send a request to a single device
- *
- * Parameters:
- *   dev - PM device previously returned from pm_register or pm_find
- *   rqst - request type
- *   data - data, if any, associated with the request
- *
- * Returns: 0 if the request is successful
- *          See "pm_callback" return for errors
- *
- * Details: Forward request to device callback and, if a suspend
- *          or resume request, update the pm_dev "state" field
- *          appropriately
- */
-int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data);
-
-/*
  * Send a request to all devices
  *
  * Parameters:
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -15,7 +15,7 @@ The methods to suspend and resume device
 
 struct bus_type {
        ...
-       int             (*suspend)(struct device * dev, u32 state);
+       int             (*suspend)(struct device * dev, pm_message_t state);
        int             (*resume)(struct device * dev);
 };
 
@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand thi
 #READY_AFTER_RESUME
 #
 
-Driver Detach Power Management
-
-The kernel now supports the ability to place a device in a low-power
-state when it is detached from its driver, which happens when its
-module is removed. 
-
-Each device contains a 'detach_state' file in its sysfs directory
-which can be used to control this state. Reading from this file
-displays what the current detach state is set to. This is 0 (On) by
-default. A user may write a positive integer value to this file in the
-range of 1-4 inclusive. 
-
-A value of 1-3 will indicate the device should be placed in that
-low-power state, which will cause ->suspend() to be called for that
-device. A value of 4 indicates that the device should be shutdown, so
-->shutdown() will be called for that device. 
-
-The driver is responsible for reinitializing the device when the
-module is re-inserted during it's ->probe() (or equivalent) method. 
-The driver core will not call any extra functions when binding the
-device to the driver. 
 
 pm_message_t meaning
 
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -165,40 +165,9 @@ Description:
 These functions are intended for use by individual drivers, and are defined in 
 struct pci_driver:
 
-        int  (*save_state) (struct pci_dev *dev, u32 state);
-        int  (*suspend) (struct pci_dev *dev, u32 state);
+        int  (*suspend) (struct pci_dev *dev, pm_message_t state);
         int  (*resume) (struct pci_dev *dev);
-        int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);
-
-
-save_state
-----------
-
-Usage:
-
-if (dev->driver && dev->driver->save_state)
-	dev->driver->save_state(dev,state);
-
-The driver should use this callback to save device state. It should take into
-account the current state of the device and the requested state in order to
-avoid any unnecessary operations.
-
-For example, a video card that supports all 4 states (D0-D3), all controller
-context is preserved when entering D1, but the screen is placed into a low power
-state (blanked). 
-
-The driver can also interpret this function as a notification that it may be
-entering a sleep state in the near future. If it knows that the device cannot
-enter the requested state, either because of lack of support for it, or because
-the device is middle of some critical operation, then it should fail.
-
-This function should not be used to set any state in the device or the driver
-because the device may not actually enter the sleep state (e.g. another driver
-later causes causes a global state transition to fail).
-
-Note that in intermediate low power states, a device's I/O and memory spaces may
-be disabled and may not be available in subsequent transitions to lower power
-states.
+        int  (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);
 
 
 suspend
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -1,7 +1,7 @@
 
 		Video issues with S3 resume
 		~~~~~~~~~~~~~~~~~~~~~~~~~~~
-		  2003-2004, Pavel Machek
+		  2003-2005, Pavel Machek
 
 During S3 resume, hardware needs to be reinitialized. For most
 devices, this is easy, and kernel driver knows how to do
@@ -11,33 +11,160 @@ boot video card. (Kernel usually does no
 driver -- vesafb and vgacon are widely used).
 
 This is not problem for swsusp, because during swsusp resume, BIOS is
-run normally so video card is normally initialized.
-
-There are three types of systems where video works after S3 resume:
-
-* systems where video state is preserved over S3. (Athlon HP Omnibook xe3s)
-
-* systems where it is possible to call video bios during S3
-  resume. Unfortunately, it is not correct to call video BIOS at that
-  point, but it happens to work on some machines. Use
-  acpi_sleep=s3_bios (Athlon64 desktop system)
-
-* systems that initialize video card into vga text mode and where BIOS
-  works well enough to be able to set video mode. Use
-  acpi_sleep=s3_mode on these. (Toshiba 4030cdt)
-
-* on some systems s3_bios kicks video into text mode, and
-  acpi_sleep=s3_bios,s3_mode is needed (Toshiba Satellite P10-554)
-
-* radeon systems, where X can soft-boot your video card. You'll need
-  patched X, and plain text console (no vesafb or radeonfb), see
-  http://www.doesi.gmxhome.de/linux/tm800s3/s3.html. (Acer TM 800)
+run normally so video card is normally initialized. S3 has absolutely
+no chance of working with SMP/HT. Be sure it to turn it off before
+testing (swsusp should work ok, OTOH).
+
+There are a few types of systems where video works after S3 resume:
+
+(1) systems where video state is preserved over S3.
+
+(2) systems where it is possible to call the video BIOS during S3
+  resume. Unfortunately, it is not correct to call the video BIOS at
+  that point, but it happens to work on some machines. Use
+  acpi_sleep=s3_bios.
+
+(3) systems that initialize video card into vga text mode and where
+  the BIOS works well enough to be able to set video mode. Use
+  acpi_sleep=s3_mode on these.
+
+(4) on some systems s3_bios kicks video into text mode, and
+  acpi_sleep=s3_bios,s3_mode is needed.
+
+(5) radeon systems, where X can soft-boot your video card. You'll need
+  a new enough X, and a plain text console (no vesafb or radeonfb). See
+  http://www.doesi.gmxhome.de/linux/tm800s3/s3.html for more information.
+  Alternatively, you should use vbetool (6) instead.
+
+(6) other radeon systems, where vbetool is enough to bring system back
+  to life. It needs text console to be working. Do vbetool vbestate
+  save > /tmp/delme; echo 3 > /proc/acpi/sleep; vbetool post; vbetool
+  vbestate restore < /tmp/delme; setfont <whatever>, and your video
+  should work.
+
+(7) on some systems, it is possible to boot most of kernel, and then
+  POSTing bios works. Ole Rohne has patch to do just that at
+  http://dev.gentoo.org/~marineam/patch-radeonfb-2.6.11-rc2-mm2.
 
 Now, if you pass acpi_sleep=something, and it does not work with your
-bios, you'll get hard crash during resume. Be carefull.
+bios, you'll get a hard crash during resume. Be careful. Also it is
+safest to do your experiments with plain old VGA console. The vesafb
+and radeonfb (etc) drivers have a tendency to crash the machine during
+resume.
 
-You may have system where none of above works. At that point you
+You may have a system where none of above works. At that point you
 either invent another ugly hack that works, or write proper driver for
 your video card (good luck getting docs :-(). Maybe suspending from X
 (proper X, knowing your hardware, not XF68_FBcon) might have better
 chance of working.
+
+Table of known working systems:
+
+Model                           hack (or "how to do it")
+------------------------------------------------------------------------------
+Acer Aspire 1406LC		ole's late BIOS init (7), turn off DRI
+Acer TM 242FX			vbetool (6)
+Acer TM C300                    vga=normal (only suspend on console, not in X), vbetool (6)
+Acer TM 4052LCi		        s3_bios (2)
+Acer TM 636Lci			s3_bios vga=normal (2)
+Acer TM 650 (Radeon M7)		vga=normal plus boot-radeon (5) gets text console back
+Acer TM 660			??? (*)
+Acer TM 800			vga=normal, X patches, see webpage (5) or vbetool (6)
+Acer TM 803			vga=normal, X patches, see webpage (5) or vbetool (6)
+Acer TM 803LCi			vga=normal, vbetool (6)
+Arima W730a			vbetool needed (6)
+Asus L2400D                     s3_mode (3)(***) (S1 also works OK)
+Asus L3350M (SiS 740)           (6)
+Asus L3800C (Radeon M7)		s3_bios (2) (S1 also works OK)
+Asus M6887Ne			vga=normal, s3_bios (2), use radeon driver instead of fglrx in x.org
+Athlon64 desktop prototype	s3_bios (2)
+Compal CL-50			??? (*)
+Compaq Armada E500 - P3-700     none (1) (S1 also works OK)
+Compaq Evo N620c		vga=normal, s3_bios (2)
+Dell 600m, ATI R250 Lf		none (1), but needs xorg-x11-6.8.1.902-1
+Dell D600, ATI RV250            vga=normal and X, or try vbestate (6)
+Dell Inspiron 4000		??? (*)
+Dell Inspiron 500m		??? (*)
+Dell Inspiron 600m		??? (*)
+Dell Inspiron 8200		??? (*)
+Dell Inspiron 8500		??? (*)
+Dell Inspiron 8600		??? (*)
+eMachines athlon64 machines	vbetool needed (6) (someone please get me model #s)
+HP NC6000			s3_bios, may not use radeonfb (2); or vbetool (6)
+HP NX7000			??? (*)
+HP Pavilion ZD7000		vbetool post needed, need open-source nv driver for X
+HP Omnibook XE3	athlon version	none (1)
+HP Omnibook XE3GC		none (1), video is S3 Savage/IX-MV
+IBM TP T20, model 2647-44G	none (1), video is S3 Inc. 86C270-294 Savage/IX-MV, vesafb gets "interesting" but X work.
+IBM TP A31 / Type 2652-M5G      s3_mode (3) [works ok with BIOS 1.04 2002-08-23, but not at all with BIOS 1.11 2004-11-05 :-(]
+IBM TP R32 / Type 2658-MMG      none (1)
+IBM TP R40 2722B3G		??? (*)
+IBM TP R50p / Type 1832-22U     s3_bios (2)
+IBM TP R51			none (1)
+IBM TP T30	236681A		??? (*)
+IBM TP T40 / Type 2373-MU4      none (1)
+IBM TP T40p			none (1)
+IBM TP R40p			s3_bios (2)
+IBM TP T41p			s3_bios (2), switch to X after resume
+IBM TP T42			s3_bios (2)
+IBM ThinkPad T42p (2373-GTG)	s3_bios (2)
+IBM TP X20			??? (*)
+IBM TP X30			s3_bios (2)
+IBM TP X31 / Type 2672-XXH      none (1), use radeontool (http://fdd.com/software/radeon/) to turn off backlight.
+IBM Thinkpad X40 Type 2371-7JG  s3_bios,s3_mode (4)
+Medion MD4220			??? (*)
+Samsung P35			vbetool needed (6)
+Sharp PC-AR10 (ATI rage)	none (1)
+Sony Vaio PCG-F403		??? (*)
+Sony Vaio PCG-N505SN		??? (*)
+Sony Vaio vgn-s260		X or boot-radeon can init it (5)
+Toshiba Libretto L5		none (1)
+Toshiba Satellite 4030CDT	s3_mode (3)
+Toshiba Satellite 4080XCDT      s3_mode (3)
+Toshiba Satellite 4090XCDT      ??? (*)
+Toshiba Satellite P10-554       s3_bios,s3_mode (4)(****)
+Uniwill 244IIO			??? (*)
+
+
+(*) from http://www.ubuntulinux.org/wiki/HoaryPMResults, not sure
+    which options to use. If you know, please tell me.
+
+(***) To be tested with a newer kernel.
+
+(****) Not with SMP kernel, UP only.
+
+VBEtool details
+~~~~~~~~~~~~~~~
+(with thanks to Carl-Daniel Hailfinger)
+
+First, boot into X and run the following script ONCE:
+#!/bin/bash
+statedir=/root/s3/state
+mkdir -p $statedir
+chvt 2
+sleep 1
+vbetool vbestate save >$statedir/vbe
+
+
+To suspend and resume properly, call the following script as root:
+#!/bin/bash
+statedir=/root/s3/state
+curcons=`fgconsole`
+fuser /dev/tty$curcons 2>/dev/null|xargs ps -o comm= -p|grep -q X && chvt 2
+cat /dev/vcsa >$statedir/vcsa
+sync
+echo 3 >/proc/acpi/sleep
+sync
+vbetool post
+vbetool vbestate restore <$statedir/vbe
+cat $statedir/vcsa >/dev/vcsa
+rckbd restart
+chvt $[curcons%6+1]
+chvt $curcons
+
+
+Unless you change your graphics card or other hardware configuration,
+the state once saved will be OK for every resume afterwards.
+NOTE: The "rckbd restart" command may be different for your
+distribution. Simply replace it with the command you would use to
+set the fonts on screen.
diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt
--- a/Documentation/powerpc/hvcs.txt
+++ b/Documentation/powerpc/hvcs.txt
@@ -347,8 +347,8 @@ address that is created by firmware.  An
 looks like the following:
 
 	Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls
-	.   current_vty   devspec  name          partner_vtys
-	..  detach_state  index    partner_clcs  vterm_state
+	.   current_vty   devspec       name          partner_vtys
+	..  index         partner_clcs  vterm_state
 
 Each entry is provided, by default with a "name" attribute.  Reading the
 "name" attribute will reveal the device type as shown in the following
diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
--- a/Documentation/s390/cds.txt
+++ b/Documentation/s390/cds.txt
@@ -56,12 +56,16 @@ read_dev_chars()	
    read device characteristics
    
 read_conf_data()
+read_conf_data_lpm()
    read configuration data.
 
 ccw_device_get_ciw()
    get commands from extended sense data.
 
 ccw_device_start()	
+ccw_device_start_timeout()
+ccw_device_start_key()
+ccw_device_start_key_timeout()
    initiate an I/O request.
 
 ccw_device_resume()
@@ -197,19 +201,21 @@ The read_dev_chars() function returns :
           operational.
 
 
-read_conf_data() - Read Configuration Data
+read_conf_data(), read_conf_data_lpm() - Read Configuration Data
 
 Retrieve the device dependent configuration data. Please have a look at your 
 device dependent I/O commands for the device specific layout of the node 
-descriptor elements. 
+descriptor elements. read_conf_data_lpm() will retrieve the configuration data
+for a specific path.
 
-The function is meant to be called with an irq handler in place; that is,
+The function is meant to be called with the device already enabled; that is,
 at earliest during set_online() processing.
 
 The function may be called enabled or disabled, but the device must not be
 locked
 
-int read_conf_data(struct ccw_device, void **buffer, int *length, __u8 lpm);
+int read_conf_data(struct ccw_device, void **buffer, int *length);
+int read_conf_data_lpm(struct ccw_device, void **buffer, int *length, __u8 lpm);
 
 cdev   - the ccw_device the data is requested for.
 buffer - Pointer to a buffer pointer. The read_conf_data() routine
@@ -263,6 +269,25 @@ int ccw_device_start(struct ccw_device *
 		     unsigned long intparm,
 		     __u8 lpm,
 		     unsigned long flags);
+int ccw_device_start_timeout(struct ccw_device *cdev,
+			     struct ccw1 *cpa,
+			     unsigned long intparm,
+			     __u8 lpm,
+			     unsigned long flags,
+			     int expires);
+int ccw_device_start_key(struct ccw_device *cdev,
+			 struct ccw1 *cpa,
+			 unsigned long intparm,
+			 __u8 lpm,
+			 __u8 key,
+			 unsigned long flags);
+int ccw_device_start_key_timeout(struct ccw_device *cdev,
+				 struct ccw1 *cpa,
+				 unsigned long intparm,
+				 __u8 lpm,
+				 __u8 key,
+				 unsigned long flags,
+				 int expires);
 
 cdev         : ccw_device the I/O is destined for
 cpa          : logical start address of channel program
@@ -272,7 +297,12 @@ user_intparm : user specific interrupt i
                particular I/O request.
 lpm          : defines the channel path to be used for a specific I/O
                request. A value of 0 will make cio use the opm.
+key	     : the storage key to use for the I/O (useful for operating on a
+	       storage with a storage key != default key)
 flag         : defines the action to be performed for I/O processing
+expires      : timeout value in jiffies. The common I/O layer will terminate
+	       the running program after this and call the interrupt handler
+	       with ERR_PTR(-ETIMEDOUT) as irb.
 
 Possible flag values are :
 
@@ -327,6 +357,13 @@ current (last) I/O request. In case of a
 interrupt will be presented to indicate I/O completion as the I/O request was
 never started, even though ccw_device_start() returned with successful completion.
 
+The irb may contain an error value, and the device driver should check for this
+first:
+
+-ETIMEDOUT: the common I/O layer terminated the request after the specified
+            timeout value
+-EIO:       the common I/O layer terminated the request due to an error state
+
 If the concurrent sense flag in the extended status word in the irb is set, the
 field irb->scsw.count describes the numer of device specific sense bytes
 available in the extended control word irb->scsw.ecw[0]. No device sensing by
diff --git a/Documentation/scsi/ChangeLog.lpfc b/Documentation/scsi/ChangeLog.lpfc
new file mode 100644
--- /dev/null
+++ b/Documentation/scsi/ChangeLog.lpfc
@@ -0,0 +1,1865 @@
+Known issues :
+	* Please read the associated RELEASE-NOTES file !!!
+	* This source release intended for upstream kernel releases only!
+
+Changes from 20050323 to 20050413
+
+	* Changed version number to 8.0.28
+	* Fixed build warning for 2.6.12-rc2 kernels: mempool_alloc now
+	  requires a function which takes an unsigned int for gfp_flags.
+	* Removed pci dma sync calls to coherent/consistent pci memory.
+	* Merged patch from Christoph Hellwig <hch@lst.de>: split helpers
+	  for fabric and nport logins out of lpfc_cmpl_els_flogi.
+	* Removed sysfs attributes that are used to dump the various
+	  discovery lists.
+	* Fix for issue where not all luns are seen.  Search all lists
+	  other than unmap list in lpfc_find_target().  Otherwise INQUIRY
+	  to luns on nodes in NPR or other relevant states (PLOGI,
+	  PRLI...) are errored back and scan() terminates.
+	* Removed FC_TRANSPORT_PATCHESxxx defines.  They're in 2.6.12-rc1.
+	* Compare return value of lpfc_scsi_tgt_reset against SCSI
+	  midlayer codes SUCCESS/FAILED which that function returns rather
+	  than SLI return code.
+	* Removed extraneous calls to lpfc_sli_next_iotag which should
+	  only be called from lpfc_sli_submit_iocb.  Also make
+	  lpfc_sli_next_iotag static.
+	* Added PCI ID for LP10000-S.
+	* Changes in lpfc_abort_handler(): Return SUCCESS if we did not
+	  find command in both TX and TX completion queues.  Return ERROR
+	  if we timed out waiting for command to complete after abort was
+	  issued.
+	* Zero-out response sense length in lpfc_scsi_prep_cmnd to prevent
+	  interpretation of stale sense length when the command completes
+	  - was causing spurious 0710 messages.
+	* Moved clearing of host_scribble inside host_lock in IO
+	  completion path.
+	* Fixed a bunch of mixed tab/space indentation.
+	* Allow hex format numbers in sysfs attribute setting.  Fix
+	  application hang when invalid numbers are used in sysfs
+	  settings.
+	* Removed extra iotag allocation by lpfc_abort_handler.
+	* Clear host_scribble in the scsi_cmnd structure when failing in
+	  queuecommand.
+	* Changed logic at top of lpfc_abort_handler so that if the
+	  command's host_scibble field is NULL, return SUCCESS because the
+	  driver has already returned the command to the midlayer.
+
+Changes from 20050308 to 20050323
+
+	* Changed version number to 8.0.27
+	* Changed a few lines from patch submitted by Christoph Hellwig
+	  (3/19). MAILBOX_WSIZE * (uint32_t) is replaced with an
+	  equivalent MAILBOX_CMDSIZE macro.
+	* Merged patch from Christoph Hellwig (3/19): some misc patches
+	  against the latest drivers:
+	  - stop using volatile.  if you need special ordering use memory
+	    barriers but that doesn't seem to be the case here
+	  - switch lpfc_sli_pcimem_bcopy to take void * arguments.
+	  - remove typecast for constants - a U postfix marks them
+	    unsigned int in C
+	  - add a MAILBOX_CMD_SIZE macro, as most users of
+	    MAILBOX_CMD_WSIZE didn't really want the word count
+	  - kill struct lpfc_scsi_dma_buf and embedded the two members
+	    directly in struct lpfc_scsi_buf
+	  - don't call dma_sync function on allocations from
+	    pci_pool_alloc - it's only for streaming mappings (pci_map_*)
+	* Merged patch from Christoph Hellwig (3/19) - nlp_failMask isn't
+	  ever used by the driver, just reported to userspace (and that in
+	  a multi-value file which is against the sysfs guidelines).
+	* Change pci_module_init to pci_register_module() with appropriate
+	  ifdefs.
+	* Added #include <linux/dma-mapping.h> as required by the DMA
+	  32bit and 64bit defines on some archs.
+	* Merged patch from Christoph Hellwig (03/19) - fix initialization
+	  order - scsi_add_host must happen last from scsi POV. Also some
+	  minor style/comment fixups.
+	* Fixed use of TRANSPORT_PATCHES_V2 by changing to
+	  FC_TRANSPORT_PATCHES_V2.
+
+Changes from 20050223 to 20050308
+
+	* Changed version number to 8.0.26
+	* Revise TRANSPORT_PATCHES_V2 so that lpfc_target is removed and
+	  rport data is used instead. Removed device_queue_hash[].
+	* Changed RW attributes of scan_down, max_luns and fcp_bind_method
+	  to R only.
+	* Fixed RSCN handling during initial link initialization.
+	* Fixed issue with receiving PLOGI handling when node is on NPR
+	  list and marked for ADISC.
+	* Fixed RSCN timeout issues.
+	* Reduced severity of "SCSI layer issued abort device" message to
+	  KERN_WARNING.
+	* Feedback from Christoph Hellwig (on 2/5) - In the LPFC_EVT_SCAN
+	  case the caller already has the target ID handly, so pass that
+	  one in evt_arg1.
+	* Fix compile warning/resultant panic in
+	  lpfc_register_remote_port().
+
+Changes from 20050215 to 20050223
+
+	* Changed version number to 8.0.25
+	* Add appropriate comments to lpfc_sli.c.
+	* Use DMA_64BIT_MASK and DMA_32BIT_MASK defines instead of
+	  0xffffffffffffffffULL & 0xffffffffULL respectively.  Use pci
+	  equivalents instead of dma_set_mask and also modify condition
+	  clause to actually exit on error condition.
+	* Restart els timeout handler only if txcmplq_cnt. On submission,
+	  mod_timer the els_tmofunc.  This prevents the worker thread from
+	  waking up the els_tmo handler un-necessarily.  The thread was
+	  being woken up even when there were no pending els commands.
+	* Added new typedefs for abort and reset functions.
+	* Collapsed lpfc_sli_abort_iocb_xxx into a single function.
+	* Collapsed lpfc_sli_sum_iocb_xxx into a single function.
+	* Removed TXQ from all abort and reset handlers since it is never
+	  used.
+	* Fixed Oops panic in 8.0.23 (reported on SourceForge).  The
+	  driver was not handling LPFC_IO_POLL cases correctly in
+	  fast_ring_event and was setting the tgt_reset timeout to 0 in
+	  lpfc_reset_bus_handler.  This 0 timeout would not allow the FW
+	  to timeout ABTS's on bad targets and allow the driver to have an
+	  iocb on two lists.  Also split the lpfc_sli_ringtxcmpl_get
+	  function into two routines to match the fast and slow completion
+	  semantics - ELS completions worked for the wrong reasons.  Also
+	  provided new log message number - had two 0326 entries.
+	* Removed unused #define LPFC_SCSI_INITIAL_BPL_SIZE.
+	* Removed unused struct lpfc_node_farp_pend definition.
+	* Removed unused #define LPFC_SLIM2_PAGE_AREA.
+	* Changed zeros used as pointers to NULL.
+	* Removed unneeded braces around single line in lpfc_do_work.
+	* Close humongous memory leak in lpfc_sli.c - driver was losing 13
+	  iocbq structures per LIP.
+	* Removed last of GFP_ATOMIC allocations.
+	* Locks are not taken outside of nportdisc, hbadisc, els and most
+	  of the init, sli, mbox and ct groups of functions
+	* Fix comment for lpfc_sli_iocb_cmd_type to fit within 80 columns.
+	* Replaced wait_event() with wait_event_interruptible().
+	  wait_event() puts the woker thread in an UNINTERRUPTIBLE state
+	  causing it to figure in load average calculations. Also add a
+	  BUG_ON to the ret code of wait_event_interruptible() since the
+	  premise is that the worker thread is signal-immune.
+
+Changes from 20050208 to 20050215
+
+	* Changed version number to 8.0.24
+	* Fixed a memory leak of iocbq structure.  For ELS solicited iocbs
+	  sli layer now frees the response iocbs after processing it.
+	* Closed large memory leak -- we were losing 13 iocbq structures
+	  per LIP.
+	* Changing EIO and ENOMEM to -EIO and -ENOMEM respectively.
+	* Cleanup of lpfc_sli_iocb_cmd_type array and typing of iocb type.
+	* Implemented Christoph Hellwig's feedback from 02/05: Remove
+	  macros putLunHigh, putLunLow. Use lpfc_put_lun() inline instead.
+	* Integrated Christoph Hellwig's feedback from 02/05: Instead of
+	  cpu_to_be32(), use swab16((uint16_t)lun). This is the same as
+	  "swab16() on LE" and "<<16 on BE".
+	* Added updates for revised FC remote port patch (dev_loss_tmo
+	  moved to rport, hostdata renamed dd_data, add fc_remote_host()
+	  on shutdown).
+	* Removed unnecessary function prototype.
+	* Added code to prevent waking up worker thread after the exit of
+	  worker thread.  Fixes panic seen with insmod/rmmod testing with
+	  70 disks.
+	* Integrated Christoph Hellwig's patch from 1/30: Make some
+	  variables/code static (namely lpfcAlpaArray and
+	  process_nodev_timeout()).
+	* Integrated Christoph Hellwig's patch from 1/30: Use
+	  switch...case instead of if...else if...else if while decoding
+	  JDEC id.
+
+Changes from 20050201 to 20050208
+
+	* Changed version number to 8.0.23
+	* Make lpfc_work_done, lpfc_get_scsi_buf,
+	  lpfc_mbx_process_link_up, lpfc_mbx_issue_link_down and
+	  lpfc_sli_chipset_init static.
+	* Cleaned up references to list_head->next field in the driver.
+	* Replaced lpfc_discq_post_event with lpfc_workq_post_event.
+	* Implmented Christoph Hellwig's review from 2/5: Check for return
+	  values of kmalloc.
+	* Integrated Christoph Hellwig's patch from 1/30: Protecting
+	  scan_tmo and friends in !FC_TRANSPORT_PATCHES_V2 &&
+	  !USE_SCAN_TARGET.
+	* Integrated Christoph Hellwig's patch from 1/30: Some fixes in
+	  the evt handling area.
+	* Integrated Christoph Hellwig's patch from 1/30: Remove usage of
+	  intr_inited variable. The interrupt initilization from OS side
+	  now happens in lpfc_probe_one().
+	* Integrated Christoph Hellwig's patch from 1/30: remove shim
+	  lpfc_alloc_transport_attr - remove shim lpfc_alloc_shost_attrs -
+	  remove shim lpfc_scsi_host_init - allocate phba mem in scsi's
+	  hostdata readjust code so that they are no use after free's
+	  (don't use after scsi_host_put) - make lpfc_alloc_sysfs_attr
+	  return errors
+	* Fixed panic in lpfc_probe_one(). Do not delete in a list
+	  iterator that is not safe.
+	* Clean up fast lookup array of the fcp_ring when aborting iocbs.
+	* Following timeout handlers moved to the lpfc worker thread:
+	  lpfc_disc_timeout, lpfc_els_timeout, lpfc_mbox, lpfc_fdmi_tmo,
+	  lpfc_nodev_timeout, lpfc_els_retry_delay.
+	* Removed unused NLP_NS_NODE #define.
+	* Integrated Christoph Hellwig's patch from 1/30: remove unused
+	  lpfc_hba_list; remove unused lpfc_rdrev_wd30; remove
+	  lpfc_get_brd_no and use Linux provided IDR.
+	* Changed board reset procedure so that lpfc_sli_send_reset()
+	  writes the INITFF bit and leaves lpfc_sli_brdreset() to clear
+	  the bit.
+	* Removed outfcpio sysfs device attribute.
+	* VPD changes: 1) Modify driver to use the model name and
+	  description from the VPD data if it exists 2) Rework use of DUMP
+	  mailbox command to support HBAs with 256 bytes of SLIM.
+	* Fixed compile error for implicit definition of struct
+	  scsi_target
+
+Changes from 20050124 to 20050201
+
+	* Changed version number to 8.0.22
+	* Moved discovery timeout handler to worker thread. There are
+	  function calls in this function which are not safe to call from
+	  HW interrupt context.
+	* Removed free_irq from the error path of HBA initialization.
+	  This will fix the free of uninitialised IRQ when config_port
+	  fails.
+	* Make sure function which processes unsolicited IOCBs on ELS ring
+	  still is called with the lock held.
+	* Clear LA bit from work_ha when we are not supposed to handle LA.
+	* Fix double locking bug in the error handling part of
+	  lpfc_mbx_cmpl_read_la.
+	* Implemented fast IOCB processing for FCP ring.
+	* Since mboxes are now unconditionally allocated outside of the
+	  lock, free them in cases where they are not used.
+	* Moved out a couple of GFP_ATOMICs in lpfc_disc_timeout, to
+	  before locks so that they can GFP_KERNEL instead. Also cleaned
+	  up code.
+	* Collapsed interrupt handling code into one function.
+	* Removed event posting and handling of solicited and unsolicited
+	  iocbs.
+	* Remove ELS ring handling leftovers from the lpfc_sli_inter().
+	* ELS ring (any slow ring) moved from the lpfc_sli_inter() into a
+	  worker thread.  Link Attention, Mbox Attention, and Error
+	  Attention, as well as slow rings' attention is passed to the
+	  worker thread via worker thread copy of Host Attention
+	  register. Corresponding events are removed from the event queue
+	  handling.
+	* Add entries to hba structure to delegate some functionality from
+	  the lpfc_sli_inter() to a worker thread.
+	* Reduced used of GFP_ATOMIC for memory allocations.
+	* Moved locks deeper in order to change GFP_ATOMIC to GFP_KERNEL.
+	* IOCB initialization fix for Raw IO.
+	* Removed qcmdcnt, iodonecnt, errcnt from lpfc_target and from
+	  driver.
+	* Added call to lpfc_els_abort in lpfc_free_node.  Modified
+	  lpfc_els_abort to reset txq and txcmplq iterator after a
+	  iocb_cmpl call.
+	* Fixed a use after free issue in lpfc_init.c.
+	* Defined default mailbox completion routine and removed code in
+	  the sli layer which checks the mbox_cmpl == 0 to free mail box
+	  resources.
+	* In lpfc_workq_post_event, clean up comment formatting and remove
+	  unneeded cast of kmalloc's return.
+	* Removed loop which calls fc_remote_port_unblock and
+	  fc_remote_port_delete for every target as this same effect is
+	  accomplished by the scsi_remove_host call.
+	* Minor cleanup of header files.  Stop header files including
+	  other header files.  Removed sentinels which hide multiple
+	  inclusions.  Removed unneeded #include directives.
+	* Fixed memory leaks in mailbox error paths.
+	* Moved lock from around of lpfc_work_done to lpfc_work_done
+	  itself.
+	* Removed typedef for LPFC_WORK_EVT_t and left just struct
+	  lpfc_work_evt to comply with linux_scsi review coding style.
+	* Fixed some trailing whitespaces, spaces used for indentation and
+	  ill-formatting multiline comments.
+	* Bug fix for Raw IO errors.  Reuse of IOCBs now mandates setting
+	  of ulpPU and fcpi_parm to avoid incorrect read check of Write IO
+	  and incorrect read length.
+
+Changes from 20050110 to 20050124
+
+	* Changed version number to 8.0.21
+	* Removed unpleasant casting in the definition and use of
+	  lpfc_disc_action function pointer array.
+	* Makefile cleanup.  Use ?= operator for setting default
+	  KERNELVERSION and BASEINCLUDE values.  Use $(PWD) consistently.
+	* Removed call to lpfc_sli_intr from lpfc_config_port_post.  All
+	  Linux systems will service hardware interrupts while bringing up
+	  the driver.
+	* Christoph Hellwig change request: Reorg of contents of
+	  lpfc_hbadisc.c, lpfc_scsi.h, lpfc_init.c, lpfc_sli.c,
+	  lpfc_attr.c, lpfc_scsi.c.
+	* Renamed discovery thread to lpfc_worker thread.  Moved handling
+	  of error attention and link attention and mbox event handler to
+	  lpfc_worker thread.
+	* Removed .proc_info and .proc_name from the driver template and
+	  associated code.
+	* Removed check of FC_UNLOADING flag in lpfc_queuecommand to
+	  determine what result to return.
+	* Move modification of FC_UNLOADING flag under host_lock.
+	* Fix IOERR_RCV_BUFFER_WAITING handling for CT and ELS subsystem.
+	* Workaround firmware bug for IOERR_RCV_BUFFER_WAITING on ELS
+	  ring.
+	* Fixed a couple lpfc_post_buffer problems in lpfc_init.c.
+	* Add missing spaces to the parameter descriptions for
+	  lpfc_cr_delay, lpfc_cr_count and lpfc_discovery_threads.
+	* Lock before calling lpfc_sli_hba_down().
+	* Fix leak of "host" in the error path in the remove_one() path.
+	* Fix comment for lpfc_cr_count.  It defaults to 1.
+	* Fix issue where we are calling lpfc_disc_done() recursively from
+	  lpfc_linkdown(), but list_for_each_entry_safe() is not safe for
+	  such use.
+	* Bump lpfc_discovery_threads (count of outstading ELS commands in
+	  discovery) to 32
+	* If the SCSI midlayer tries to recover from an error on a lun
+	  while the corresponding target is in the NPR state, lpfc driver
+	  will reject all the resets. This will cause the target to be
+	  moved to offline state and block all the I/Os. The fix for this
+	  is to delay the lun reset to a target which is not in MAPPED
+	  state until the target is rediscovered or nodev timeout is
+	  fired.
+
+Changes from 20041229 to 20050110
+
+	* Changed version number to 8.0.20
+	* rport fix: use new fc_remote_port_rolechg() function instead of
+	  direct structure change
+	* rport fix: last null pointer check
+	* Phase II of GFP_ATOMIC effort.  Replaced iocb_mem_pool and
+	  scsibuf_mem_pool with kmalloc and linked list.  Inserted list
+	  operations for mempool_alloc calls.  General code cleanup.  All
+	  abort and reset routines converted.  Handle_ring_event
+	  converted.
+	* If the mbox_cmpl == lpfc_sli_wake_mbox_wait in
+	  lpfc_sli_handle_mb_event, pmb->context1 points to a waitq. Do
+	  not free the structure.
+	* rport fixes: fix for rmmod crash
+	* rport fixes: when receiving PRLI's, set node/rport role values
+	* rport fixes: fix for unload and for fabric port deletes
+	* VPD info bug fix.
+	* lpfc_linkdown() should be able to process all outstanding events
+	  by calling lpfc_disc_done() even if it is called from
+	  lpfc_disc_done() Moving all events from phba->dpc_disc to local
+	  local_dpc_disc prevents those events from being processed.
+	  Removing that queue. From now on we should not see "Illegal
+	  State Transition" messages.
+	* Release host lock and enable interrupts when calling
+	  del_timer_sync()
+	* All related to rports: Clean up issues with rport deletion
+	  Convert to using block/unblock on list remove (was del/add)
+	  Moved rport delete to freenode - so rport tracks node.
+	* rport fixes: for fport, get maxframe and class support
+	  information
+	* Added use of wait_event to work with kthread interface.
+	* Ensure that scsi_transport_fc.h is always pulled in by
+	  lpfc_scsiport.c
+	* In remote port changes: no longer nulling target->pnode when
+	  removing from mapped list. Pnode get nulled when the node is
+	  freed (after nodev tmo). This bug was causing i/o recieved in
+	  the small window while the device was blocked to be errored w/
+	  did_no_connect. With the fix, it returns host_busy
+	  (per the pre-remote port changes).
+	* Merge in support for fc transport remote port use. This removes
+	  any consistent bindings within the driver. All scanning is now
+	  on a per-target basis driven by the discovery engine.
+
+Changes from 20041220 to 20041229
+
+	* Changed version number to 8.0.19
+	* Fixed bug for handling RSCN type 3.  Terminate RSCN mode
+	  properly after ADISC handling completes.
+	* Add list_remove_head macro.  Macro cleans up memory allocation
+	  list handling.  Also clean up lpfc_reset_bus_handler - routine
+	  does not need to allocate its own scsi_cmnd and scsi_device
+	  structures.
+	* Fixed potential discovery bug, nlp list corrutpion fix potential
+	  memory leak
+	* Part 1 of the memory allocation rework request by linux-scsi.
+	  This effort fixes the number of bdes per scsi_buf to 64, makes
+	  the scatter-gather count a module parameter, builds a linked
+	  list of scsi_bufs, and removes all dependencies on lpfc_mem.h.
+	* Reverted lpfc_do_dpc, probe_one, remove_one to original
+	  implementation.  Too many problems (driver not completing
+	  initial discovery, and IO not starting to disks).  Backs out
+	  kthread patch.
+	* Fix race condition in lpfc_do_dpc.  If wake_up interrupt occurs
+	  while lpfc_do_dpc is running disc_done and the dpc list is
+	  empty, the latest insertion is missed and the schedule_timeout
+	  does not wakeup.  The sleep interval is MAX_SCHEDULE_TIMEOUT
+	  defined as ~0UL >> 1, a very large number.  Hacked it to 5*HZ
+	  for now.
+	* Fixed bug introduced when discovery thread implementation was
+	  moved to kthread. kthread_stop() is not able to wake up thread
+	  waiting on a semaphore and "modprobe -r lpfc" is not always
+	  (most of the times) able to complete. Fix is in not using
+	  semaphore for the interruptable sleep.
+	* Small Makefile cleanup - Remove remnants of 2.4 vs. 2.6
+	  determination.
+
+Changes from 20041213 to 20041220
+
+	* Changed version number to 8.0.18
+	* Janitorial cleanup after removal of sliinit and ringinit[] ring
+	  statistic is owned by the ring and SLI stats are in sli
+	  structure.
+	* Integrated patch from Christoph Hellwig <hch@lst.de> Kill
+	  compile warnings on 64 bit platforms: %variables for %llx format
+	  specifiers must be caste to long long because %(u)int64_t can
+	  just be long on 64bit platforms.
+	* Integrated patch from Christoph Hellwig <hch@lst.de> Removes
+	  dead code.
+	* Integrated patch from Christoph Hellwig <hch@lst.de>: use
+	  kthread interface.
+	* Print LPFC_MODULE_DESC banner in module init routine.
+	* Removed sliinit structure and ringinit[] array.
+	* Changed log message number from 324 to 326 in lpfc_sli.c.
+	* Wait longer for commands to complete in lpfc_reset_bus_handler
+	  and lpfc_reset_bus_handler.  Also use schedule_timeout() instead
+	  of msleep() and add error message in lpfc_abort_handler()
+	* When setting lpfc_nodev_tmo, from dev_loss set routine, make 1
+	  sec minimum value.
+	* Functions which assume lock being held were called without lock
+	  and kernel complained about unlocking lock which is not locked.
+	* Added code in linkdown to unreg if we know login session will be
+	  terminated.
+	* Removed automap config parameter and fixed up use_adisc logic to
+	  include FCP2 devices.
+
+Changes from 20041207 to 20041213
+
+	* Changed version number to 8.0.17
+	* Fix sparse warnings by adding __iomem markers to lpfc_compat.h.
+	* Fix some sparse warnings -- 0 used as NULL pointer.
+	* Make sure there's a space between every if and it's (.
+	* Fix some overly long lines and make sure hard tabs are used for
+	  indentation.
+	* Remove all trailing whitespace.
+	* Integrate Christoph Hellwig's patch for 8.0.14: if
+	  pci_module_init fails we need to release the transport template.
+ 	  (also don't print the driver name at startup, linux drivers can
+	  be loaded without hardware present, and noise in the log for
+	  that case is considered unpolite, better print messages only for
+	  hardware actually found).
+	* Integrate Christoph Hellwig's patch for 8.0.14: Add missing
+	  __iomem annotations, remove broken casts, mark functions static.
+	  Only major changes is chaning of some offsets from word-based to
+	  byte-based so we cans simply do void pointer arithmetics (gcc
+	  extension) instead of casting to uint32_t.
+	* Integrate Christoph Hellwig's patch for 8.0.14: flag is always
+	  LPFC_SLI_ABORT_IMED, aka 0 - remove dead code.
+	* Modified preprocessor #ifdef, #if, #ifndef to reflect upstream
+	  kernel submission.  Clean build with make clean;make and make
+	  clean;make ADVANCED=1 on SMP x86, 2.6.10-rc2 on RHEL 4 Beta
+	  1. IO with a few lips and a long cable pull behaved accordingly.
+	* Implement full VPD support.
+	* Abort handler will try to wait for abort completion before
+	  returning.  Fixes some panics in iocb completion code path.
+
+Changes from 20041130 to 20041207
+	
+	* Changed version number to 8.0.16
+	* Hung dt session fix.  When the midlayer calls to abort a scsi
+	  command, make sure the driver does not complete post-abort
+	  handler.  Just NULL the iocb_cmpl callback handler and let SLI
+	  take over.
+	* Add Read check that uses SLI option to validate all READ data
+	  actually received.
+
+
+Changes from 20041123 to 20041130
+
+	* Changed version number to 8.0.15
+	* Ifdef'd unused "binary" attributes by DFC_DEBUG for clean
+	  compiles
+	* Stop DID_ERROR from showing up along with QUEUE_FULL set by the
+	  Clarion array (SCSI error ret. val.  0x70028) There is no need
+	  for driver to hard fail command which was failed by the target
+	  device.
+	* Fix for Scsi device scan bug reported on SourceForge.  Driver
+	  was returning a DID_ERROR in lpfc_handle_fcp_error causing
+	  midlayer to mark report luns as failing even though it
+	  succeeded.
+	* Don't ignore SCSI status on underrun conditions for inquiries,
+	  test unit ready's, etc.  This was causing us to lose
+	  reservation conflicts, etc
+
+Changes from 20041018 to 20041123
+	
+	* Changed version number to 8.0.14
+	* Added new function "iterator" lpfc_sli_next_iocb_slot() which
+	  returns pointer to iocb entry at cmdidx if queue is not full.
+	  It also updates next_cmdidx, and local_getidx (but not cmdidx)
+	* lpfc_sli_submit_iocb() copies next_cmdidx into cmdidx. Now it is
+	  the only place were we are updating cmdidx.
+	* lpfc_sli_update_ring() is split in to two --
+	  lpfc_sli_update_ring() and lpfc_sli_update_full_ring().
+	* lpfc_sli_update_ring() don't to read back correct value of
+	  cmdidx.
+	* Simplified lpfc_sli_resume_iocb() and its use.
+	* New static function lpfc_sli_next_iocb(phba, pring, &piocb) to
+	  iterate through commands in the TX queue and new command (at the
+	  end).
+	* Reduced max_lun to 256 (due to issues reported to some arrays).
+	  Fixed comment, and macro values so def=256, min=1, max=32768.
+	* Fix an obvious typo/bug: kfree was used to free lpfc_scsi_buf
+	  instead of mempool_free in lpfc_scsiport.c.
+	* Suppress nodev_tmo message for FABRIC nodes.
+	* Fixed some usage of plain integer as NULL pointer.
+	* Bug fix for FLOGI cmpl, lpfc_els_chk_latt error path code
+	  cleanup.
+	* Fixup lpfc_els_chk_latt() to have Fabric NPorts go thru
+	  discovery state machine as well.
+	* Fixes to lpfc_els_chk_latt().
+	* Use DID not SCSI target id as a port_id and add some missing
+	  locks in lpfc_fcp.c.
+	* Changed eh_abort_handler to return FAILED if command is not
+	  found in driver.
+	* Fix crash: paging request at virtual address 0000000000100108 -
+	  a result of removing from the txcmpl list item which was already
+	  removed (100100 is a LIST_POISON1 value from the next pointer
+	  and 8 is an offset of the "prev") Driver runs out of iotags and
+	  does not handle that case well. The root of the proble is in the
+	  initialization code in lpfc_sli.c
+	* Changes to work with proposed linux kernel patch to support
+	  hotplug.
+	* Zero out seg_cnt in prep_io failure path to prevent double sg
+	  unmap calls.
+	* Fix setting of upper 32 bits for Host Group Ring Pointers if in
+	  SLIM. Old code was inappropriately masking off low order bits.
+	* Use scsi_[activate|deactivate]_tcq calls provided in scsi_tcq.h.
+	* Integrated patch from Christoph Hellwig (hch@lst.de): don't call
+	  pci_dma_sync_* on coherent memory. pci_dma_sync_* is need and
+	  must be used only with streaming dma mappings pci_map_*, not
+	  coherent mappings.  Note: There are more consistent mappings
+	  that are using pci_dma_sync calls. Probably these should be
+	  removed as well.
+	* Modified lpfc_free_scsi_buf to accomodate all three scsi_buf
+	  free types to alleviate miscellaneous panics with cable pull
+	  testing.
+	* Set hotplug to default 0 and lpfc_target_remove to not remove
+	  devices unless hotplug is enabled.
+	* Fixed discovery bug: plogi cmpl uses ndlp after its freed.
+	* Fixed discovery bug: rnid acc cmpl, can potentially use ndlp
+	  after its freed.
+	* Modularize code path in lpfc_target_remove().
+	* Changes to support SCSI hotplug (ifdef'ed out because they need
+	  kernel support USE_SCAN_TARGET requires kernel support to export
+	  the interface to scsi_scan_target and to move the SCAN_WILD_CARD
+	  define to a general scsi header file.  USE_RESCAN_HOST requires
+	  kernel support to export an interface to scan_scsi_host() with
+	  the rescan flag turned on).
+	* Removed redundant variable declaration of lpfc_linkdown_tmo.
+	* Fix for large port count remove test.
+	* Added check to see if BAR1 register is valid before using BAR1
+	  register for programming config_port mail box command.
+	* Added lpfc_scsi_hotplug to enable/disable driver support of SCSI
+	  hotplug.
+	* Changed lpfc_disc_neverdev() to lpfc_disc_illegal() and changed
+	  lpfc_disc_nodev() to lpfc_disc_noop().  Adjusted appropriate
+	  events to use these routines.
+	* Add support for SCSI device hotplug.
+	* Take dummy lpfc_target's into account for lpfc_slave_destroy().
+	* Bug fix to store WWPN / WWNN in NameServer / FDMI lpfc_nodelist
+	  entries.
+	* Added slavecnt in lpfc_target for diagnostic purposes.
+	* Added lpfc_hba load/unload flags to take care of special cases
+	  for add/remove device.
+	* Have target add/remove delay before scanning.
+	* Have rmmod path cleanup blocked devices before scsi_remove_host.
+	* Added a #define for msleep for 2.6.5 kernels.
+	* In reset bus handler if memory allocation fails, return FAILED
+	  and not SUCCESS.
+	* Have lpfc eh handlers, bus_reset and lun_reset, wait for all
+	  associated I/Os to complete before returning.
+	* Fix memset byte count in lpfc_hba_init so that
+	  LP1050 would initialize correctly.
+	* Backround nodev_timeout processing to DPC This enables us to
+	  unblock (stop dev_loss_tmo) when appopriate.
+	* Fix array discovery with multiple luns.  The max_luns was 0 at
+	  the time the host structure was intialized.  lpfc_cfg_params
+	  then set the max_luns to the correct value afterwards.
+	* Remove unused define LPFC_MAX_LUN and set the default value of
+	  lpfc_max_lun parameter to 512.
+	* Reduced stack usage of lpfc_hba_init.
+	* Cleaned up the following warning generated by
+	  scripts/checkincludes.pl lpfc_fcp.c: scsi/scsi_cmnd.h is
+	  included more than once.
+	* Replaced "set_current_state(TASK_UNINTERRUPTIBLE);
+	  schedule_timeout(timeout)" with "msleep(timeout)".
+	* Fixnode was loosing starget when rediscovered. We saw messages
+	  like: lpfc 0000:04:02.0: 0:0263 Cannot block scsi target as a
+	  result.  Moved starget field into struct lpfc_target which is
+	  referenced from the node.
+	* Add additional SLI layer logging in lpfc_sli.c.
+	* Ignore more unexpected completions in lpfc_nportdisc.c.
+	* Can not call lpfc_target_unblock from the soft interrupt
+	  context.  It seems to be not nessasery to unblock target from
+	  nodev timeout.
+	* Introduce and use less lethal event handler for unexpected
+	  events in lpfc_nportdisc.c.
+	* Can not call fc_target_(un)block() functions with interrupts
+	  disabled in lpfc_scsiport.c.
+	* Added new configuration parameter, lpfc_max_luns range 1-32768,
+	  default 32768.
+	* Allow lpfc_fcp.c to call lpfc_get_hba_sym_node_name().
+	* Increase nodev timeout from 20 seconds to 30 seconds.
+	* Replace some kfree((void*)ptr) with kfree(ptr).
+	* Make 3 functions static: lpfc_get_hba_sym_node_name,
+	  lpfc_intr_prep and lpfc_setup_slim_access.  Move lpfc_intr_prep
+	  and lpfc_setup_slim_access so they're defined before being used.
+	* Remove an unecessary list_del() in lpfc_hbadisc.c.
+	* Set nlp_state before calling lpfc_nlp_list() since this will
+	  potentially call fc_target_unblock which may cause a race in
+	  queuecommand by releasing host_lock.
+	* Since lpfc_nodev_tmo < dev_loss_tmo remove queuecommand
+	  DID_BAD_TARGET return for now.
+	* Fix a problem with rcv logo.
+	* Remove unused portstatistics_t structure.
+	* Remove #if 0 and unnecessary checks in lpfc_fcp.c.
+	* Simplify lpfc_issue_lip: Extra layer of protection removed.
+	* Grab lock before calling lpfc_sli_issue_mbox(phba, pmb,
+	  MBX_NOWAIT) in lpfc_sli_issue_mbox_wait().
+
+Changes from 20040920 to 20041018
+
+	* Changed version number to 8.0.13
+	* Hide some attributes using #ifndef DFC_DEBUG ... #endif.
+	* Modify Makefile to (1) make BUILD_NO_DEBUG=1 will hide some
+	  (binary) attributes (2) make BUILD_FC_TRANS=0 will build driver
+	  for 2.6.5 kernel with block/unblock patch.
+	* Modified #ifdef names.
+	* Added support for proposed FC transport host attributes (which
+	  replaces some of the attributes we had local to the driver).
+	  Removed the binary statistics sysfs attribute.
+	* Added extra ELS verbose logging for ELS responses.
+	* Added recognition for BUILD_FC_TRANS=2 to Makefile to define
+	  FC_TRANS_VER2.
+	* Add a pointer for link stats allocation.
+	* Exported lpfc_get_hba_sym_node_name for use by FC_TRANS_VER2
+	  sysfs routines.
+	* Fix discovery problem in lip testing: if device sends an ELS cmd
+	  (i.e. LOGO) before our FLOGI completes it should be LS_RJT'ed.
+	* Moved #defines around to provide target_add/remove for upstream
+	  kernel deliverables only not SLES9.  Provided ifdefs to #include
+	  target_block/unblock only if FC_TRANS_VER1.
+	* Add sanity check in lpfc_nlp_list move setting nlp_Target
+	  outside #ifdef.
+	* Added a blocked member to the lpfc_target structure for
+	  block/unblock.  This member allows the driver to know when to
+	  unblock for pci_remove_one or pci_add_one.  #ifdef'd some more
+	  block/unblock stuff and removed some defensive checks from
+	  target_block/unblock.
+	* Moved + 5 second window to dev_loss_tmo setting and updated
+	  comments.
+	* Removed NULL target check from target_block/unblock and fixed up
+	  a few comments.
+	* Enable sysfs attributes on 2.6.5 kernels and remove extra
+	  compatibility code.
+	* Remove any and all trailing whitespace.
+	* Added message 0718 and return error when dma_map_single fails.
+	* Changed the fcpCntl2 commands to include an FCP_ prefix to get
+	  rid of build warnings on later 2.6.9-rc kernels.  Build
+	  conflicts with scsi/scsi.h.  Remove inclusions of scsi/scsi.h
+	  from hbadisc.c, sli.c, and fcp.c since these modules had no
+	  dependencies on scsi.h.
+	* Fixed a bug with RSCN handling. A RSCN received on one device,
+	  shouldn't affect other devices not referenced by the RSCN.
+	* Moved #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) to include
+	  lpfc_jedec_to_ascii to prevent warning in SLES 9.
+	* Update Makefile to account for SLES 9 and scsi-target upstream
+	  kernel.
+	* This checkin provides block/unblock hooks for the upstream scsi
+	  target kernel and 2.6.5 on SLES9 SP1 with the block/unblock
+	  patch.
+	* Discovery changes regarding setting targetp->pnode and
+	  ndlp->nlp_Target Ensure fc_target_* routines are called properly
+	  from discovery.  Remove list_del's from lpfc_cleanup().  Ensure
+	  all the lpfc_consistent_bind_* routines don't set any driver
+	  structure objects.
+	* Fix for timeout of READ_LA or READ_SPARAM mailbox command
+	  causing panic.
+	* Cleanup list_del()'s for Discovery ndlp lists.
+	* Bug fixes for some insmod/rmmod crashes, link down crashes and
+	  device loss crashes.
+	* Removed NLP_SEARCH_DEQUE.
+	* Call lpfc_target_unblock only if the targetp is nonNull and with
+	  the host_lock held.
+	* Added qcmdcnt back along with misc bug fixes to discovery.
+	* Changed tgt_io to outfcpio lpfc_fcp.c.
+	* Fixed errors caused by LIP and cable pulls both with and without
+	  block/unblock patch.
+	* For now we have to call fc_target_unblock and fc_target_block
+	  with interrupts enabled.
+	* Save seg_cnt from dma_map_sg.  Save scatter-gather start address
+	  and pass back to dma_unmap_sg in error with seg_cnt.
+	* Incorporating block/unblock calls into driver with ifdefs.  This
+	  change is supported by scsi-target-2.6 kernel and forward only.
+	* Merged in some discovery bug fixes and added tgt io counters.
+	* Added sysfs attributes/interfaces: read only attribute
+	  "management_version" and write only attribute "issue_lip".
+	* Fix build on big endian machines: while #if was OK with
+	  __BIG_ENDIAN which defined as 4321, __BIG_ENDIAN_BITFIELD has to
+	  be tested with #ifdef because it does not have any value, it is
+	  either defined or not.
+	* Add fabric_name and port_type attributes.
+	* Change mdelay to msleep.  mdelay works, but wastefully uses cpu
+	  resources without a lock held. Revert to msleep.  Tested with
+	  sg_reset for bus and three attached targets.
+	* Added the customary #ifndef...#define...#endif to
+	  lpfc_version.h.
+	* Integrate patches from Christoph Hellwig: two new helpers common
+	  to lpfc_sli_resume_iocb and lpfc_sli_issue_iocb - singificant
+	  cleanup of those two functions - the unused SLI_IOCB_USE_TXQ is
+	  gone - lpfc_sli_issue_iocb_wait loses it's flags argument
+	  totally.
+	* Fix in lpfc_sli.c: we can not store a 5 bit value in a 4-bit
+	  field.
+	* Moved some routines out of lpfc_fcp.c into more appropriate
+	  files.
+	* Whitespace cleanup: remove all trailing whitespace.
+	* Make lpfc_disc_ndlp_show static to lpfc_fcp.c.
+	* Remove leftover printk and replace some with
+	  printk(KERN_WARNING)
+	* Trivial: fix a few long lines and a soft tab.
+	* Remove warnings generated by Sparse against driver (make
+	  C=1). Mostly these are "using integer as pointer warnings"
+	  i.e. use NULL instead of 0.
+	* Integrated patch from Christoph Hellwig: Quite a lot of changes
+	  here, the most notable is that the phba->slim2p lpfc_dmabuf goes
+	  away in favour of a typede pointer and a dma_addr_t.  Due to the
+	  typed pointer lots of the cast mess can go away, and while at it
+	  I also replaced the messy SLI2_SLIM_t with a simple struct
+	  lpfc2_sli2_slim that only contains the part of the union we care
+	  about while using SLI2_SLIM_SIZE for all size calculations
+	  directly.
+	* Integrated patch from Christoph Hellwig: This streamlines the
+	  I/O completion path a little more, especially taking care of
+	  fast-pathing the non-error case.  Also removes tons of dead
+	  members and defines from lpfc_scsi.h - e.g. lpfc_target is down
+	  to nothing more then the lpfc_nodelist pointer.
+	* Added binary sysfs file to issue mbox commands
+	* Replaced #if __BIG_ENDIAN with #if __BIG_ENDIAN_BITFIELD for
+	  compatibility with the user space applications.
+	* Decrease the amount of data in proc_info.
+	* Condense nodelist flag members.
+	* Expand INFO for discovery sysfs shost entries.
+	* Notify user if information exceeds 4k sysfs limit.
+	* Removed a bunch of unused #defines.
+	* Added initial sysfs discovery shost attributes.
+	* Remove unused #defines lpfc_disc.h.
+	* Fixed failMask nodelist settings.
+	* Cleanup some old comments / unused variables.
+	* Add LP101 to list of recognized adapters.
+
+Changes from 20040908 to 20040920
+
+	* Changed version number to 8.0.12
+	* Removed used #defines: DEFAULT_PCI_LATENCY_CLOCKS and
+	  PCI_LATENCY_VALUE from lpfc_hw.h.
+	* Changes to accomodate rnid.
+	* Fix RSCN handling so RSCN NS queries only effect NPorts found in
+	  RSCN data.
+	* If we rcv a plogi on a NPort queued up for discovery, clear the
+	  NLP_NPR_2B_DISC bit since rcv plogi logic will force NPort thru
+	  discovery.
+	* Ensure lpfc_target is also cleaned up in lpfc_cleanup().
+	* Preliminary changes for block/unblock kernel API extensions in
+	  progress with linux-scsi list.  These are name changes and
+	  prototype changes only.
+	* Added send_abts flag to lpfc_els_abort. For rcv LOGO when ADISC
+	  sent, the XRI of the LOGO rcv'ed is the same as the ADISC
+	  sent. Thus we cannot ABTS the ADISC before sending the LOGO ACC.
+	* Weed out some unused fc_flags.  Add FC_DISC_TMO.
+	* board_online sysfs attribute added to support libdfc functions
+	  InitDiagEnv and SetBrdEnv.
+	* Streamline code in lpfc_els_retry fixup abort case in
+	  lpfc_els_timeout_handler().
+	* Flush discovery/ELS events when we bring SLI layer down.
+	* ctlreg and slimem binary attributes added to support libdfc
+	  read/write mem/ctl functions.
+	* Integrated Christoph Hellwig's patch: Cleanup
+	  lpfc_sli_ringpostbuf_get.
+	* Modified lpfc_slave_alloc and lpfc_slave_destroy to allocate and
+	  free a dummy target pointer.  This allows queuecommand to skip
+	  the NULL target pointer check and avoid the console spam when
+	  slave_alloc fails.
+	* Fix cfg_scan_down logic, it was reversed.
+	* Init list head ctrspbuflist.
+	* Change name of lpfc_driver_abort to lpfc_els_abort since it is
+	  only valid for ELS ring.
+	* Remove unused third argument for lpfc_consistent_bind_get().
+	* Fix up iotag fields in lpfc_prep_els_iocb().
+	* Remove log message on code path triggered by lpfc_els_abort().
+	* Set host->unique_id in lpfc_fcp.c.
+	* Removed deadwood: lpfc_target.pHba not necessary anymore.
+	* Integrated patch from Christoph Hellwig: remove dead
+	  SLI_IOCB_POLL handling.
+	* Integrated patch from Christoph Hellwig: Streamline I/O
+	  submission and completion path a little.
+	* Remove unnecessary lpfc_brd_no.  Ensure brd_no assignment is
+	  unique.
+	* Removed unused MAX_FCP_LUN.
+	* Use mod_timer instead of add_timer for fdmi in lpfc_ct.c.
+	* Fixed misc discovery problems.
+	* Move stopping timers till just before lpfc_mem_free() call.
+	* Fix up NameServer reglogin error path.
+	* Cleanup possible outstanding discovery timers on rmmod.
+	* Fix discovery NPort to NPort pt2pt problem.
+	* Get rid of ip_tmofunc / scsi_tmofunc.
+	* Integrated patch from Christoph Hellwig:
+	  lpfc_disc_done/lpfc_do_dpc cleanup - lpfc_disc_done can return
+	  void - move lpfc_do_dpc and lpfc_disc_done to lpfc_hbadisc.c -
+	  remove checking of list emptiness before calling lpfc_disc_done,
+	  it handles the emtpy list case just fine and the additional
+	  instructions cost less then the bustlocked spinlock operations.
+	* Integrated patch from Christoph Hellwig: This adds a new 64bit
+	  counter instead, brd_no isn't reused anymore.  Also some tiny
+	  whitespace cleanups in surrounding code.
+	* Reorder functions in lpfc_els.c to remove need for prototypes.
+	* Removed unsed prototypes from lpfc_crtn.h -
+	  lpfc_ip_timeout_handler, lpfc_read_pci and lpfc_revoke.
+	* Removed some unused prototypes from lpfc_crtn.h -
+	  lpfc_scsi_hba_reset, lpfc_scsi_issue_inqsn,
+	  lpfc_scsi_issue_inqp0, lpfc_scsi_timeout_handler.
+	* Integrated patch from Christoph Hellwig: remove TRUE/FALSE
+	  usage.
+	* Integrated patch from Christoph Hellwig: Remove unused function
+	  prototypes lpfc_set_pkt_len and lpfc_get_pkt_data from
+	  lpfc_crtn.h - fixes build warnings.
+	* Removed unused struct lpfc_dmabufip definition from lpfc_mem.h.
+	* Removed pre-2.6.5 MODULE_VERSION macro from lpfc_compat.h.
+	* Fixing missing static and removing dead code.
+	* Adding nodewwn, portwwn and portfcid shost attributes.
+	* Initial support for CT via sysfs. request payloads of size less
+	  than PAGE_SIZE and rsp payloads of size PAGE_SIZE are supported.
+	  Driver maintains a list of rsp's and passes back rsp's
+	  corresponding to the pid of the calling process.
+	* Support for RefreshInformation, GetAdapterAttributes,
+	  GetPortStatistics.
+	* Make nodev-tmo default to 20 seconds.
+	* Fix up some DSM error cases, unreg_login rpi where needed.
+	* Fix up comments for fc_target_block / fc_target_unblock.
+	* Fix up code for scsi_block_requests / scsi_unblock_requests.
+	* Add NLP_FCP_TARGET for nodeinfo support.
+	* Move suspend/resume in lpfc_nlp_list under appropriate case -
+	  Used host_lock for DPC to avoid race (remove dpc_lock)
+	* Fix some corner cases for PLOGI receive - simplify error case
+	  for cmpl_reglogin_reglogin_issue.
+	* Bug fix for ppc64 EEH MMIO panic - always do readl after
+	  writel's of HBA registers to force flush.
+	* Get rid of initial static routine declarations in lpfc_hbadisc.c
+	  and lpfc_els.c.
+	* Updates to discovery processing.
+
+Changes from 20040823 to 20040908
+
+	* Changed version number to 8.0.11
+	* Removed persistent binding code.
+	* Display both ASC and ASCQ info.
+	* Fixed link down->up transitions when linkdown tmo expires. Fix
+	  was in the defensive error checking at the start of
+	  queuecommand.
+	* Removed lpfc_scsi_timeout_handler as this timer is no longer
+	  required.  The midlayer will exhaust retries and then call
+	  lpfc_abort_handler, lpfc_reset_lun_handler, and
+	  lpfc_reset_target_handler.
+	* Minimal support for SCSI flat space addressing/volume set
+	  addressing.  Use 16 bits of LUN address so that flat
+	  addressing/VSA will work.
+	* Changed 2 occurences of if( 1 != f(x)) to if(f(x) != 1)
+	* Drop include of lpfc_cfgparm.h.
+	* Reduce stack usage of lpfc_fdmi_cmd in lpfc_ct.c.
+	* Add minimum range checking property to /sys write/store
+	  functions.
+	* Fix display of node_name and port_name via fc transport
+	  attr.
+	* Removed biosparam code.
+	* Removed range checking. phba->config[] array elements are now
+	  embedded into the hba struct. lpfc_config_setup() has been
+	  removed.
+	* Collapsed lpfc_scsi_cmd_start into lpfc_queuecommand and cleaned
+	  up combined routines.
+	* Removed unused prototypes myprint and
+	  lpfc_sched_service_high_priority_queue.
+	* Removed unused function lpfc_nodev.
+	* Removed scsi_cmnd->timeout_per_command cancelation. SCSI midlayer
+	  now times out all commands - FW is instructed to not timeout.
+	* Removed polling code from lpfc_scsi_cmd_start. Reorganized
+	  queuecommand and cmd_start some.
+
+Changes from 20040810 to 20040823
+
+	* Changed version number to 8.0.10
+	* Additional timer changes as per Arjan / Christoph's comments.
+	* Used mod_timer() instead of del_timer_sync() where appropriate.
+	* Fixed a use after free case (panic on 2.6.8.1 with
+	  CONFIG_DEBUG_SLAB set).
+	* Fix compile warning in lpfc_fcp.c.
+	* Minor fix for log message, that prints unassigned brdno which is
+	  zero.
+	* Move scsi_host_alloc() to the beginning of probe_one(). This
+	  ensures that host_lock is available at later stages and also
+	  avoids tons of unnecessary initializing if host_alloc()
+	  fails.
+	* Removed else clause from lpfc_slave_configure that set
+	  sdev->queue_depth.  The driver informs the midlayer of its
+	  setting in the template and only overrides if queue tagging is
+	  enabled.
+	* Added PCI_DEVICE_ID_ZEPHYR and PCI_DEVICE_ID_ZFLY (Junior
+	  Zephyr) support
+
+Changes from 20040730 to 20040810
+	
+	* Changed version number to 8.0.9
+	* Removed per HBA driver lock.  Driver now uses the host->host_lock
+	* Restored support for the 2.6.5 kernel for those linux distributions
+	  shipped with the 2.6.5 kernel.
+	* Applied patch from Christoph Hellwig (hch@infradead.org) as follows
+	  "[PATCH] use scsi host private data in ->proc_info.  
+	* Applied patch from Christoph Hellwig (hch@infradead.org) as follows
+	  "Re: [Emulex] Ready for next round.  This patch cleans up the memory 
+	  allocation routines a little and fixes a missing mempool_destroy and
+	  some missing error handling."
+	* Changed pointers assignments from 0 to NULL.
+	* Added fixes to the lpfc_reset_lun_handler and lpfc_reset_bus_handler
+	  entry points that caused kernel to Oops or hang.
+	* Added fixes to targetless hosts that caused modprobe and insmod to hang.
+	* Ongoing cleanup to many files
+	  
+Changes from 20040723 to 20040730
+
+	* Changed version number to 8.0.8
+	* Removed unused LPFN_DRIVER_VERSION #define.
+	* Folded lpfc_findnode_scsiid into lpfc_find_target, its only
+	  caller.
+	* Removed 2 unneeded arguments to lpfc_find_target (lun and
+	  create_flag).
+	* Make lpfc_sli_reset_on_init = 1
+	* Minor cleanup to quieten sparse.
+	* Removed missing function = 0 in tmo routine in lpfc_els.c.
+	* Moved additional binding parameters into lpfc_defaults.c:
+	  lpfc_automap / lpfc_fcp_bind_method
+	* Use msecs_to_jiffies() where applicable.
+	* Only use queue depth attribute only after SLI HBA setup was
+	  completed.
+	* Put in memory barriers for PPC
+	* Added PCI_DEVICE_ID_HELIOS and PCI_DEVICE_ID_JFLY (Junior
+	  Helios) support
+	* Added 4&10 gigabit choices in user option link_speed
+	* Updated timer logic: Set timer data after init_timer use
+	  timer_pending() instead of expires.
+	* Removed some remnants of IP over FC support from Kconfig and
+	  Makefile.
+	* Remove redundant prototypes for lpfc_handle_eratt,
+	  lpfc_handle_latt and lpfc_read_pci.
+	* Ongoing cleanup of lpfc_init.c.
+	* Changed LPFC_CFG_DFT_HBA_Q_DEPTH -> LPFC_CFG_HBA_Q_DEPTH.
+	* Another cleanup stab at lpfc_ct.c. Remove castings, structure
+	  code sanely, remove redundant code, reorganize code so that
+	  functions are invoked after definition.
+
+Changes from 20040716 to 20040723
+
+	* Changed version number to 8.0.7
+	* Cleanup of lpfc_ct.c. Removed number of casts, removed tons of
+	  dead/redundant code, cleaned up badly and poorly written code,
+	  cleaned up return values.
+	* Fixed Persistent binding implementation
+	* Removed all references to lpfc_scsi_req_tmo
+	* Removed last references to lun_skip config parameter.
+	* Removed LPFC_DEV_RPTLUN node failure bit because we don't issue
+	  REPORT_LUNS from the driver anymore.
+	* Removed LUN-tracking in driver.  Removed lpfc_lun struct and
+	  moved any functionality we still need to lpfc_target.
+	* Added new lpfc_jedec_to_ascii() call and replace two instances
+	  of duplicate code with calls to this function.
+	* Removed Volume Set Addressing handling on LUN IDs.
+	* Applied patch from Christoph Hellwig (hch@infradead.org) that
+	  removes dead code belonging to lpfc_build_scsi_cmnd() and its
+	  call path. This is related to the recently removed report_lun
+	  code.
+
+Changes from 20040709 to 20040716
+
+	* Changed version number to 8.0.6
+	* Removed internal report LUNs usage.  Removed functions:
+	  lpfc_disc_issue_rptlun, lpfc_disc_cmpl_rptlun,
+	  lpfc_disc_retry_rptlun and their use.
+	* Removed usused scheduler prototypes in lpfc_crtn.h
+	* Replace lpfc_geportname() with generic memcmp().
+	* Rearrange code in lpfc_rcv_plogi_plogi_issue() to make it a
+	  little more readable.
+	* Remove redundant port_cmp != 2 check in if
+	  (!port_cmp) { .... if (port_cmp != 2).... }
+	* Clock changes: removed struct clk_data and timerList.
+	* Clock changes: seperate nodev_tmo and els_retry_delay into 2
+	  seperate timers and convert to 1 argument changed
+	  LPFC_NODE_FARP_PEND_t to struct lpfc_node_farp_pend convert
+	  ipfarp_tmo to 1 argument convert target struct tmofunc and
+	  rtplunfunc to 1 argument * cr_count, cr_delay and
+	  discovery_threads are only needed to be module_params and not
+	  visible via sysfs.
+
+Changes from 20040614 to 20040709
+
+	* Changed version number to 8.0.5
+	* Make lpfc_info static.
+	* Make lpfc_get_scsi_buf static.
+	* Print a warning if pci_set_mwi returns an error.
+	* Changed SERV_PARM to struct serv_parm.
+	* Changed LS_RJT to struct ls_rjt.
+	* Changed CSP to struct csp.
+	* Changed CLASS_PARMS to struct class_parms.
+	* Some cosmetic coding style cleanups to lpfc_fcp.c.
+	* Providing a sysfs interface that dumps the last 32
+	  LINK_[UP|DOWN] and RSCN events.
+	* Get rid of delay_iodone timer.
+	* Remove qfull timers and qfull logic.
+	* Convert mbox_tmo, nlp_xri_tmo to 1 argment clock handler
+	* Removed duplicate extern defs of the bind variables.
+	* Streamline usage of the defines CLASS2 and CLASS3, removing
+	  un-necessary checks on config[LPFC_CFG_FCP_CLASS].
+	* Moving the persistent binding variables to new file
+	  lpfc_defaults.c
+	* Changed LPFC_SCSI_BUF_t to struct lpfc_scsi_buf.
+	* Moved config specific code from probe_one() into
+	  config_setup(). Removing a redundant check on scandown value
+	  from bind_setup() as this is already done in config_setup().
+	* Changed LPFC_SLI_t to struct lpfc_sli.
+	* Changed FCP_CMND to struct fcp_cmnd.
+	* Changed FCP_RSP to struct fcp_rsp.
+	* Remove the need for buf_tmo.
+	* Changed ULP_BDE64 to struct ulp_bde64.
+	* Changed ULP_BDE to struct ulp_bde.
+	* Cleanup lpfc_os_return_scsi_cmd() and it's call path.
+	* Removed lpfc_no_device_delay.
+	* Consolidating lpfc_hba_put_event() into lpfc_put_event().
+	* Removed following attributes and their functionality:
+	  lpfc_extra_io_tmo, lpfc_nodev_holdio, lpfc_delay_rsp_err,
+	  lpfc_tgt_queue_depth and lpfc_check_cond_err.
+	* Clock changes consolidating timers, just in the struct lpfc_hba,
+	  to get rid of clkData and pass only one argument to timeout
+	  routine. Also, removing need for outstanding clock linked list
+	  to stop these timers at rmmod.
+	* Move lpfc.conf contents into lpfc_fcp.c. Removing per adapter
+	  attributes in favor of global attributes.
+	* Fix a potential null pointer reference of pmbuf in lpfc_ct.c.
+	* On reset_lun, issue LUN_RESET as opposed to ABORT_TASK_SET.
+	* Removed SCSI_REQ_TMO related code.
+	* Introducing two new defines LPFC_ATTR_R and LPFC_ATTR_RW that do
+	  a module_param, MODULE_PARM_DESC, lpfc_param_show,
+	  [lpfc_param_store] and CLASS_DEVICE_ATTRIBUTE.
+	* Properly clean up when allocation of a linked BDE fails in the
+	  SCSI queuecommand path.
+	* Fail SCSI command if dma_map_sg call fails.
+	* Remove unused macros SWAP_ALWAYS and SWAP_ALWAYS16.
+	* Reset context2 to 0 on exit in
+	  lpfc_sli_issue_iocb_wait_high_priority() and
+	  lpfc_sli_issue_iocb_wait().
+	* Arranging lpfc_scsiport.c to follow style of use after
+	  definition. This removes the need for the cruft of forward
+	  declarations. Also removing a redundant #define ScsiResult as it
+	  already available elsewhere.
+	* Applying "Streamline lpfc error handling" patch from Christoph
+	  Hellwig (hch@infradead.org) with following modifications: fix
+	  mem leaks, remove some misplaced code that need not be there,
+	  print a message on exit (old code prints two (entry/exit)), make
+	  ret values consistent (either 1/0 or SUCCESS/FAILURE), keep all
+	  eh routines in a single file (lpfc_scsiport.c).
+	* Move contents of lpfc_module_param.h into lpfc_fcp.c.
+	* Changed sysfs attributes to CLASS_DEVICE_ATTRIBUTES (previously
+	  DEVICE_ATTRIBUTES). They now appear in
+	  /sys/class/scsi_host/hostx (previously in
+	  /sys/bus/pci/drivers/lpfc/devx).
+	* Removed lpfc_syfs.h and lpfc_sysfs.c.
+	* Cleanup of config params.  Throttle params have been removed.
+	  max_lun has been removed. max_target is replaced with a #define,
+	  lun_skip is removed.  Remove ipfc config params and related
+	  code.
+	* Changed DMABUF_t usage to struct lpfc_dmabuf.
+	* Downsizing iCfgParam structure to include a_string, a_low, a_hi
+	  and a_default values only.
+	* Free SCSI buf safety memory pool on shutdown to eliminate memory
+	  leak.
+	* Change lpfc_printf_log to a #define. Also include phba->brd_no
+	  and newline in the print string rather than in the #define.
+	* Remove code that optionally locates Host Group Pointers in host
+	  memory SLIM since this is no longer needed for PPC64, once
+	  CONFIG_PORT uses HBA's view of its BAR0.
+	* Removed the forward declarations of the sli functions and
+	  rearranging the code in lpfc_sli.c.
+	* Removed the preamble functionality from logging.
+	* Make lpfc_sli_hba_setup() return negative error codes on error
+	  and correct the comment left over in lpfc_fcp.c
+	* Removed the lpfc_loadtime variable.
+	* Put a space between all ifs and their open parens '('.
+	* Change Studly_Caps LPFC_SCSI_BUF_t to struct lpfc_scsi_buf.
+	* Fixed insmod hang after hardware error.
+	* Relocated scsi_host alloc to before we enable the interrupt
+	  handler
+	* Add .tmp_versions directory to Makefile clean target.  This
+	  directory is created in the 2.6.5+ build process (with Red Hat
+	  kernels at least).
+	* Changing phba->config to kmalloc lpfc_icfgparam and not
+	  *phba->config. This is manifesting itself as a panic in
+	  pci_release_region().
+	* Fix for firmware download / board reset problem.
+	* Integrated patch from Christoph Hellwig (hch@infradead.org) to
+	  reorganize and cleanup lpfc_fcp.c
+	* Don't abort commands immediately when there is an RSCN event to
+	  give driver time to rediscover targets before the midlayer
+	  retries the SCSI commands.
+
+Changes from 20040604 to 20040614
+
+	* Changed version number to 8.0.4
+	* Removed lpfc_valid_lun function.
+	* Added scsi_buf safety pool to address scsi_buf failures in
+	  queuecommand under low memory conditions.  Allocations now come
+	  from kmalloc initially, but if kmalloc fails, the allocation
+	  comes from the safety pool.
+	* Modified lpfc_slave_alloc to only set the scsi_device->hostdata
+	  pointer if the driver has discovered the target.  This routine
+	  always returns success now as well since no error ever occurs in
+	  the alloc routine.
+	* Mask only info and warning messages.  Print all error messages
+	  irrespective of mask.
+	* Removing lpfc_log_chk_msg_disabled()
+	* Changed lpfc_printf_log to take struct lpfc_hba * directly
+	  instead of a "board number".
+	* Convert dma_sync_single to pci_dma_sync_single_for_{device/cpu}.
+	* Implemented new style log messages. The message strings are now
+	  embedded in the call to lpfc_printf_log.
+	* Decreased FLOGI discovery timeout to 20 seconds.
+	* On error in lpfc_pci_probe_one() return -1 and not 1.
+	* Allow for board numbers that are not sequential, paving the way
+	  for hotplug support.
+	* scsi_add_host() can fail, so wrap it around in an if(). Also
+	  initiate scsi_scan_host() after attaching the sysfs attributes.
+	* lpfc_release_version is used only in lpfc_ct.c, so move it there
+	  and mark it as static.
+	* Removed lpfc_sleep_ms and replaced with mdelay or schedule calls
+	  directly
+	* Removed all (struct list_head *) casts from clkData-related list
+	  handling in list_add, list_del macros.
+	* Removed EXPORT_SYMBOLs.
+	* Removed LPFC_MIN_QFULL and lpfc_qthrottle_up.
+	* Replace LPFCSCSITARGET_t with struct lpfc_target.
+	* Replace LPFCSCSILUN_t with struct lpfc_lun.
+	* Remove unused struct declarations (fcPathId and fcRouteId) from
+	  lpfc_scsi.h.
+	* Rewrite use of FC transport attributes.
+	* Fix crash when link is lost.  This was due to lpfc_delay_iodone
+	  calling list_del on an object that was never put on a list.
+	* Remove trailing spaces at the end of all lines.
+	* Set MAX_FCP_TARGET to 256 from 0xff.  Set MAX_FCP_LUN and
+	  MAX_FCP_CMDS to their decimal equivalents and updated
+	  documentation.
+
+Changes from 20040526 to 20040604
+
+	* Changed version number to 8.0.3
+	* Completed sysfs FC transport support.
+	* Removed unused fields in SCSI LUN and SCSI Target structures:
+	  void *pTargetProto; void *pTargetOSEnv; void *pLunOSEnv;
+	* Modified list_for_each to list_for_each_entry. Modified
+	  list_for_each_safe to list_for_each_entry_safe.
+	* Remove lpfc_dfc.h file.
+	* Changed pHba->phba, pCommand->pcmd
+	* Changed plogi_ndlp -> plogindlp, pos_tmp->postmp, pRsp->prsp,
+	  pCmd->pcmd
+	* Changed pText -> ptext
+	* Changed p_tmp_buff -> ptmpbuff
+	* Changed pBufList -> pbuflist, pRsp -> prsp, pCmd -> pcmd
+	* Changed *pos_tmp -> *postmp, *p_mbuf -> *pmbuf
+	* Following changes are made to the SCSI fast path: Added
+	  DMA_BUF_t member to the lpfc_scsi_buf_t.  This will reduce a
+	  memory allocation in the scsi fast path.  Added check for
+	  targetp == NULL in the scsi fast path.  Increased number of
+	  scatter gather entries in lpfc_scsi_dma_ext to 4 from 3 and
+	  changed the size of lpfc_scsi_dma_ext to 264
+	* Fixing some missing static lpfc_nportdisc.c.
+	* Reordered #include lines so that lpfc.h doesn't have to #include
+	  other header files.
+	* Remove lpfc_get_hba_sym_node_name() as a global EXPORT and make
+	  it static.
+	* Move struct clk_data definition from lpfc_hw.h to lpfc_sli.h.
+	* Changed LPFC_IOCBQ_t to struct lpfc_iocbq.
+	* Changed LPFC_SLI_RING_t to struct lpfc_sli_ring.
+	* Changed LPFC_NODELIST_t to struct lpfc_nodelist.
+	* Rearranged lpfc_nportdisc.c by moving state machine array
+	  (lpfc_disc_action) and the one function that uses it,
+	  lpfc_disc_state_machine, to the end of the file, removing the
+	  need for the raft of prototypes at the top.
+	* Changed LPFC_BINDLIST_t to struct lpfc_bindlist.
+	* Removed lpfc_issue_ct_rsp(), lpfc_sleep(), lpfc_add_bind(),
+	  lpfc_del_bind(), lpfc_sli_wake_mbox_wait() and
+	  lpfc_sli_issue_mbox_wait().
+	* Fixed a large number of overly-long lines.
+	* Fixed some discovery problems: Introduced deferred ndlp removal
+	  when in DSM to avoid panic when in nested DMSs Fix NportId
+	  fffc01 handling to not relogin after LOGO fixed handling of LOGO
+	  on PLOGI issue.
+	* Changed SLI_CT_REQUEST to lpfc_sli_ct_request.
+	* Changed NAME_TYPE to struct lpfc_name.
+	* Changed lpfcCfgParam_t to struct lpfc_cfgparam.
+	* Changed LPFC_STAT_t to struct lpfc_stats.
+	* Changed HBAEVT_t to struct lpfc_hba_event.
+	* Changed Studly_Caps lpfcHBA_t to struct lpfc_hba.
+	* Removed no longer used tasklet_running flag.
+	* Removing *PSOME_VAR typedefs and using SOME_VAR* directly.
+	* Changing .use_clustering to ENABLE_CLUSTERING.
+	* Modify lpfc_queuecommand to return SCSI_MLQUEUE_HOST_BUSY when
+	  it can't queue a SCSI command.  Also, remove cmnds_in_flight
+	  member of struct lpfcHBA for 2.6 kernels as it was only needed
+	  to determine what to return from queuecommand.
+	* Change return type of lpfc_evt_iocb_free to void as it doesn't
+	  return anything.
+	* Remove unused cmnd_retry_list and in_retry members in struct
+	  lpfcHBA.
+	* Remove some instances of unneeded casting of kmalloc's return in
+	  lpfc_scsiport.c
+	* Remove lpfc_linux_attach() and lpfc_linux_detach(). Integrate
+	  them into lpfc_probe_one() and lpfc_release_one() respectively.
+	* Remove lpfc_num_iocbs, lpfc_num_bufs module parameters
+	* Remove #defines for NUM_NODES, NUM_BUFS and NUM_IOCBS
+
+Changes from 20040515 to 20040526
+
+	* Changing version number to 8.0.2.
+	* Including dma-mapping.h as one of the include headers.  Also
+	  rearrange the #include order.
+	* Make functions static as appropriate.
+	* queuecommand() will now return SCSI_MLQUEUE_HOST_BUSY instead of
+	  1 to backpressure midlayer.
+	* Removed function prototypes for lpfc_start_timer() and
+	  lpfc_stop_timer()
+	* Changed timer support to be inline.  Clk_data is now declared
+	  right next to the corresponding timer_list entry so we don't
+	  have to allocate these clk_data dynamically.
+	* Add readls after writels to PCI space to flush the writes.
+	* Fix misspelled word "safety" in function names.
+	* Fix up comments in lpfc.conf for per HBA parameters to reflect
+	  new implementation.
+	* Change lpfc_proc_info handler to get the Nodename from
+	  fc_nodename and not fc_portname.
+	* Fix up some comments and whitespace in lpfc_fcp.c.
+	* Formatting changes: get rid of leading spaces in code
+	* Move discovery processing from tasklet to a kernel thread.
+	* Move ndlp node from unmap list to map list if ADISC completed
+	  successfully.
+	* Flush all the ELS IOCBs when there is a link event.
+	* LP9802 qdepth is twice the LP9802DC qdepth.  Delay
+	  elx_sched_init after READ_CONFIG to get max_xri from the
+	  firmware.  Reset ELX_CFG_DFT_HBA_Q_DEPTH to max_xri after
+	  READ_CONFIG
+	* Fix fc_get_cfg_parm() to be more robust and support embedded hex
+	  values.  The lpfc_param's are now defined as:
+	  lpfc_log_verbose="lpfc:0,lpfc0:0x10,lpfc1:4,lpfc100:0xffff" The
+	  "," delimter does not matter. It can be anything or not exist at
+	  all. ie param = "lpfc:0lpfc0:0x10.lpfc1:4txtlpfc100:0xffff" will
+	  also work.  Additionally the string is treated as case
+	  insensitive.
+	* Changed all usage of lpfc_find_lun_device() to lpfc_find_lun().
+	* Removed unnecessary wrappers lpfc_find_lun_device() and
+	  lpfc_tran_find_lun().
+	* Switch from using internal bus/id/lun to similar data from
+	  scsi_device structure.
+	* Eliminate one-line function lpfc_find_target()
+	* Added slave_alloc, slave_destory
+	* lpfc_scsi_cmd_start can now acquire lun pointer from
+	  scsi_device->hostdata, which is setup in slave_alloc.
+	* Eliminate unnecessary checking on every cmd just to see if we
+	  are accessing the device the first time.
+	* Remove assumption in lpfc_reset_lun_handler that a valid
+	  lpfc_scsi_buf is hung off of linux's scsi_cmnd->host_scribble
+	  when our reset is called.
+
+Changes from 20040507 to 20040515
+
+	* Changed version to 8.0.1
+	* Fixed crash on driver rmmod after error injection tests and
+	  lpfc_tasklet deadlock.
+	* Modified lpfc.conf to remove limit on number of support hosts
+	* Removed HBAAPI 
+	* Removed duplication of SCSI opcodes from lpfc_fcp.h that are
+	  available in scsi/scsi.h
+	* Rework module_param usage
+	* Added MODULE_PARAM_DESC for various module_params
+	* Removed #define EXPORT_SYMTAB
+	* Removed #includes of if_arp.h and rtnetlink.h
+	* Removed string "Open Source" from MODULE_DESC
+	* Cleanup duplicated string definitions used by MODULE_DESC
+	* Renamed lpfc_pci_[detect|release] to lpfc_pci_[probe|remove]_one
+	* Fix formatting of lpfc_driver
+	* Remove unnecessary memset to 0 of lpfcDRVR
+	* Attach driver attributes always unless pci_module_init failed
+	* Remove all one-line wrappers from lpfc_mem.
+	* Remove lpfc_sysfs_set_[show|store] as it is no longer needed
+	* Redo lpfc_sysfs_params_[show|store] to one value per attribute rule
+	* Breakdown lpfc_sysfs_info_show into smaller one value per attribute
+	* Use device attributes instead of driver attributes where appropriate
+	* Remove no longer needed EXPORT_SYMBOLs
+	* Remove some unused code (1600 msg's related)
+
+Changes from 20040429 to 20040507
+
+	* Change version to 8.0.0
+	* Fix the number of cmd / rsp ring entries in lpfc_fcp.c to match
+	  the divisions setup in lpfc_hw.h.
+	* Remove phba->iflag reference.
+	* Several locking improvements.
+	* Remove functions lpfc_drvr_init_lock, lpfc_drvr_lock,
+	  lpfc_drvr_unlock and lpfc_hipri_*.
+	* Remove LPFC_DRVR_LOCK and LPFC_DRVR_UNLOCK macros.
+	* Make lpfc_info() use lpfc_get_hba_model_desc() instead of
+	  rewriting almost identical code.
+	* Fix 1 overly long line in each of lpfc_cfgparm.h, lpfc_ftp.c and
+	  lpfc_sli.c.
+	* Fix build for Red Hat 2.6.3 kernel by #defining MODULE_VERSION
+	  only if it isn't already defined.
+	* Change elx_sli_issue_mbox_wait to return correct error code to
+	  the caller.
+	* In some of the els completion routines, after calling
+	  lpfc_elx_chk_latt, driver ignores the return code of the
+	  lpfc_elx_chk_latt. This will prevent the discovery state machine
+	  restarting correctly when there are link events in the middle of
+	  discovery state machine running. Fix this by exiting discovery
+	  state machine if lpfc_els_chk_latt returns a non zero value.
+	* Removed MAX_LPFC_BRDS from lpfc_diag.h
+	* Removed unused first_check.
+	* Remove some unused fields and defines.
+	* Change lpfc-param names to lpfc_param.
+	* Add use of MODULE_VERSION macro for 2.6 kernels.
+	* Shorten length of some of the comment lines to make them more
+	  readable.
+	* Move FCP_* definitions to their own header file, lpfc_fcp.h.
+	* Remove unused prototypes from lpfc_crtn.h: fcptst, iptst,
+	  lpfc_DELAYMS.
+	* Remove duplicated prototypes from lpfc_crtn.h:
+	  lpfc_config_port_prep, lpfc_config_port_post,
+	  lpfc_hba_down_prep.
+	* Removed some unused export_symbols.
+	* Install driver files into */drivers/scsi/lpfc instead of
+	  */drivers/scsi.
+
+Changes from 20040426 to 20040429
+
+	* Declared export symbol lpfc_page_alloc and lpfc_page_free
+	* Changed lpfc version number to 6.98.3
+	* Move the definition of MAX_LPFC_BRDS to the only header file
+	  that uses it (lpfc_diag.h).
+	* Change lpfc_sli_wake_iocb_wait to do a regular wake_up since
+	  lpfc_sli_issue_iocb_wait now sleeps uninterruptible.
+	* Replace list_for_each() with list_for_each_safe() when a list
+	  element could be deleted.
+	* Fix IOCB memory leak
+
+Changes from 20040416 to 20040426
+
+	* Change lpfc_config_port_prep() to interpret word 4 of the DUMP
+	  mbox response as a byte-count
+	* Add info attribute to sysfs
+	* Minor formatting (spaces to tabs) cleanup in lpfc_sched.h
+	* Remove unused log message number 732
+	* Completing MODULE_PARM -> module_param changes
+	* Removed unused targetenable module parameter
+	* Removed locks from lpfc_sli_issue_mbox_wait routine
+	* Removed code that retry 29,00 check condition
+	* Removed code that manipulates rspSnsLen.
+	* Fix use of lun-q-depth config param
+	* Fix severity inconsistency with log message 249
+	* Removed lpfc_max_target from lpfc_linux_attach
+	* Replace references to lpfcDRVR.pHba[] with lpfc_get_phba_by_inst()
+	* Change lpfc_param to lpfc-param
+	* Partially removed 32 HBA restriction within driver.  Incorported
+	  lpfc_instcnt, lpfc_instance[], and pHba[] into lpfcDRVR
+	  structure Added routines lpfc_get_phba_by_inst()
+	  lpfc_get_inst_by_phba() lpfc_check_valid_phba()
+	* Turn on attributes "set" & "params" by default.
+	* Further formatting/whitespace/line length cleanup on: lpfc_ct.c
+	  lpfc_els.c lpfc_fcp.c lpfc_hbadisc.c lpfc_init.c lpfc_ipport.c
+	  lpfc_mbox.c lpfc_nportdisc.c lpfc_sched.c lpfc_sched.h
+	  lpfc_scsi.h lpfc_scsiport.c lpfc_sli.c and lpfc_sli.h
+	* Add log message 249 to log any unsupported device addressing
+	  modes encountered.
+	* Add support for 256 targets and 256 LUNs
+	* Fixed panic in lpfc_linkdown.
+	* Removed (struct list_head*) casting in several calls to list_del
+	* Free irq reservation and kill running timers when insmod or
+	  modprobe are killed via ctrl-c
+	* Remove drivers/scsi from include path
+	* Wrap use of log message 311 in macro
+	* Detect failure return from pci_map_sg call in lpfc_os_prep_io
+	* Fix use-after-free of IOCB in lpfc_sli_process_sol_iocb which
+	  was causing an Oops on 2.6.5 kernel.
+	* Cleanup use of several gotos not used for error exit.
+	* Replace memcpy_toio() and memcpy_toio() with endian-dependent
+	  lpfc_memcpy_to_slim() and lpfc_memcpy_from_slim() so that for
+	  big endian hosts like PPC64, the SLIM is accessed 4 bytes at a
+	  time instead of as a byte-stream.
+
+Changes from 20040409 to 20040416
+
+	* The scsi_register and scsi_alloc_host OS calls can fail and
+	  return a zero-valued host pointer.  A ctrl-C on 2.6 kernels
+	  during driver load will cause this and the driver to panic.
+	  Fixed this bug.  Also found a bug in the error_x handling with
+	  lpfc_sli_hba_down - it was in the wrong place and the driver
+	  lock was not held, but needed to be (in lpfc_linux_attach) Fixed
+	  both.  Did some minor comment clean up.
+	* Removed unwanted (void *) castings.
+	* Replace define of INVALID_PHYS, with kernel 2.6.5's
+	  dma_mapping_error() and add a inline function for earlier
+	  kernels.  Remove lpfc_bad_scatterlist().
+	* Clean up formatting in hbaapi.h, lpfc.h, lpfc_cfgparm.h,
+	  lpfc_crtn.h, lpfc_ct.c, lpfc_diag.h, lpfc_disc.h, lpfc_els.c,
+	  lpfc_fcp.c, lpfc_hbadisc.c, lpfc_hw.h, lpfc_init.c,
+	  lpfc_ipport.c, lpfc_logmsg.c, lpfc_logmsg.h and lpfc_scsiport.c
+	  - mostly replacing groups of 8 spaces with hard tabs and keeping
+	  lines to 80 column max..
+	* Removed LPFC_DRVR_LOCK call from lpfc_unblock_requests for 2.4
+	  kernels.  The lpfc_scsi_done routine already unlocks the driver
+	  lock since it expects this lock to be held.
+	* Removed global lock capabilities from driver lock routines
+	* Remove SA_INTERRUPT flag from request_irq
+	* Move dma_addr_t cast inside of getPaddr macro as everywhere
+	  getPaddr is used, the return is cast to dma_addr_t.
+	* Clean up formatting in lpfc_sli.c and lpfc_sysfs.c - mostly
+	   replacing groups of 8 spaces with hard tabs and keeping lines
+	   to 80 column max.
+	* Fix build for RHEL 2.1 BOOT kernels by always #including
+	  interrupt.h in lpfc.h.
+	* Fix RHEL 3 build by #defining EXPORT_SYMTAB.
+	* Replace sprintf with snprintf in lpfc_proc_info.
+	* Fix build warnings on 2.6 kernels - remove no longer used calls
+	  to  character device initialization.
+	* Initial support code for discovery in tasklet conversion.
+	* Removing char interface and ioctl code.
+	* Change all elx prefixes to lpfc
+	* Replace lpfc_write_slim() & lpfc_read_slim() with memcpy_toio(),
+	  memcpy_fromio(), writel() & readl().
+
+Changes from 20040402 to 20040409
+
+	* Replaced lpfc_read_hbaregs_plus_offset and
+	  lpfc_write_hbaregs_plus_offset functions with readl and writel.
+	* Get rid of long mdelay's in insmod path
+	* Changed the way our pci_device_id structures are initialized
+	* Replace lpfc_read/write_CA/HA/HC/HS with calls to readl() &
+	  writel() directly.
+	* Increase SLI2_SLIM to 16K Increase cmd / rsp IOCBs accordingly
+	* Removed lpfc_els_chk_latt from the lpfc_config_post function.
+	  lpfc_els_chk_latt will enable the link event interrupts when
+	  flogi is pending which causes two discovery state machines
+	  running parallely.
+	* Add pci_disable_device to unload path.
+	* Move lpfc_sleep_event from lpfc_fcp.c to lpfc_util_ioctl.c
+	* Call dma_map_single() & pci_map_single() directly instead of via
+	  macro lpfc_pci_map().  Allow address 0 for PPC64.
+	* Change sleep to uninterruptible in lpfc_sli_issue_icob_wait
+	  because this function doesn't handle signals.
+	* Move lpfc_wakeup_event from lpfc_fcp.c to lpfc_ioctl.c
+	* Remove unneeded #include <linux/netdevice.h>
+	* Remove unused clock variables lpfc_clkCnt and lpfc_sec_clk.
+	* Get rid of capitalization of function names.
+	* Removed lpfc_addr_sprintf.
+	* Implemented gotos in lpfc_linux_attach for error cases.
+	* Replace mlist->dma.list = dmp->dma.list; to mlist = dmp.
+	* Remove functions lpfc_get_OsNameVersion and elx_wakeup. Change
+	  elx_wakeup to wake_up_interruptible
+	* Add function lpfc_get_os_nameversion and change
+	  lpfc_get_OsNameVersion to lpfc_get_os_nameversion.
+	* Remove lpfc_get_OsNameVersion
+	* Change driver name to a consistent lpfc in every visible place.
+	* Fix build warning: removed unused variable ret in lpfc_fdmi_tmo.
+	* Remove lpfc_utsname_nodename_check function
+	* Remove functions lpfc_register_intr and lpfc_unregister_intr
+	* Fill in owner field in lpfc_ops file_operations struct and
+	  remove now unnecessary open and close entry points.
+	* Change function name prefixes from elx_ to lpfc_
+	* Remove special case check for TUR in elx_os_prep_io()
+	* Renamed elx_scsi.h to lpfc_scsi.h
+	* Renamed elx_sched.h to lpfc_sched.h
+	* Renamed elx_mem.h to lpfc_mem.h
+	* Renamed elx_sli.h to lpfc_sli.h
+	* Renamed elx_logmsg.h to lpfc_logmsg.h
+	* Renamed elx.h to lpfc.h
+	* Renamed elx_sli.c to lpfc_sli.c
+	* Renamed elx_sched.c to lpfc_sched.c
+	* Renamed elx_mem.c to lpfc_mem.c
+	* Renamed elx_logmsg.c to lpfc_logmsg.c
+	* Renamed lpfcLINUXfcp.c lpfc_fcp.c
+	* Renamed elx_clock.c to lpfc_clock.c
+	* Reduce stack usage in lpfc_info().
+	* Move lpip_stats structure from lpfc_hba.h to lpfc_ip.h.
+	* Move lpfc_stats and HBAEVT_t structures from lpfc_hba.h to
+	  lpfc.h
+	* Remove lpfc_hba.h
+	* Remove duplicate rc definitions from 
+	* Removed code which used next pointer to store mbox structure.
+	* Cleaned up list iterations.
+	* Removed non list manipulation of the next pointers.
+	* Change list_del()/INIT_LIST_HEAD sequences to list_del_init()
+	* In ELX_IOCBQ_t: Moved hipri_trigger field to iocb_flag. Combined
+	  hipri_wait_queue and rsp_iocb in union
+	* Replaced casting from list_head with list_entry macro.
+	* Added ct_ndlp_context field to the ELX_IOCBQ_t.
+	* Do not use DMABUf_t list to store ndlp context
+	* Return 0 from lpfc_process_iotcl_util() when ELX_INITBRDS
+	  succeeds.
+	* remove elx_os_scsiport.h
+	* Do not use DMABUf_t list to hold rpi context
+	* Replace elx_cfg_* names with lpfc_cfg-*
+	* Moved FCP activity to ring 0.  Moved ELS/CT activity to ring 2.
+	* Clean up formatting of elx_sli.h (tabs for indents, 80 column
+	  lines).
+	* Remove unused elxclock declaration in elx_sli.h.
+	* Since everywhere IOCB_ENTRY is used, the return value is cast,
+	  move the cast into the macro.
+	* Split ioctls out into seperate files
+
+Changes from 20040326 to 20040402
+
+	* Updated ChangeLog for 20040402 SourceForge drop.
+	* Use safe list iterator for ndlp list
+	* Added code to return NLP_STE_FREED_NODE from the discovery
+	  state machine functions if the node is freed from the
+	  function.
+	* Fixes to DMABUF_t handling
+	* Fix for load error in discovery
+	* Remove loop_cnt variable from lpfc_rcv_plogi_unused_node.
+	* Remove nle. reference.
+        * Remove support for building 2.4 drivers
+	* Remove elx_util.h and replace elx_disc.h with lpfc_disc.h
+	* Implemented the Linux list macros in the discovery code.
+	  Also moved elx_disc.h contents into lpfc_disc.h
+	* Unused variable cleanup
+	* Use Linux list macros for DMABUF_t
+	* Break up ioctls into 3 sections, dfc, util, hbaapi
+	  rearranged code so this could be easily seperated into a
+	  differnet module later All 3 are currently turned on by
+	  defines in lpfc_ioctl.c LPFC_DFC_IOCTL, LPFC_UTIL_IOCTL,
+	  LPFC_HBAAPI_IOCTL
+	* Misc cleanup: some goto's; add comments; clarify function
+	  args
+	* Added code to use list macro for ELXSCSITARGET_t.
+	* New list implementation for ELX_MBOXQ_t
+	* Cleaned up some list_head casting.
+	* Put IPFC ifdef around two members of struct lpfc_nodelist.
+	* Cleaned up iocb list using list macros and list_head data
+	  structure.
+	* lpfc_online() was missing some timer routines that were
+	  started by lpfc_linux_attach().  These routines are now also
+	  started by lpfc_online().  lpfc_offline() only stopped
+	  els_timeout routine.  It now stops all timeout routines
+	  associated with that hba.
+	* Replace seperate next and prev pointers in struct
+	  lpfc_bindlist with list_head type.  In elxHBA_t, replace
+	  fc_nlpbind_start and _end with fc_nlpbind_list and use
+	  list_head macros to access it.
+	* Fix ulpStatus for aborting I/Os overlaps with newer firmware
+	  ulpStatus values
+	* Rework params_show/store to be consistent as the other
+	  routines.  Remove generic'ness and rely on set attribute.
+	* Remove unused log message.
+	* Collapse elx_crtn.h and prod_crtn.h into lpfc_crtn.h
+	* Ifdef Scheduler specific routines
+	* Removed following ununsed ioclt's: ELX_READ_IOCB
+	  ELX_READ_MEMSEG ELX_READ_BINFO ELX_READ_EINVAL ELX_READ_LHBA
+	  ELX_READ_LXHBA ELX_SET ELX_DBG LPFC_TRACE 
+	* Removed variable fc_dbg_flg
+	* Fixed a bug where HBA_Q_DEPTH was set incorrectly for
+	  3-digit HBAs.  Also changed can_queue so midlayer will only
+	  send (HBA_Q_DEPTH - 10) cmds.
+	* Clean up code in the error path, check condition.  Remove
+	  ununsed sense-related fields in lun structure.
+	* Added code for safety pools for following objects: mbuf/bpl,
+	  mbox, iocb, ndlp, bind
+	* Wrapped '#include <elx_sched.h>' in '#ifdef USE_SCHEDULER'.
+	* Fixed 'make clean' target.
+        * Build now ignores elx_sched.o, and includes lpfc_sysfs.o.
+	* Wrapped lpfndd.o target in BUILD_IPFC ifdef.
+	* Removed elx_os.h inclusion in implementation files.
+	* Removed ELX_OS_IO_t data structure and put data direction
+	  and non scatter/gather physical address into the scsi buffer
+	  structure directly.  Moved DRVR_LOCK, putPaddr, getPaddr
+	  macros and some defines into elx.h since they are required
+	  by the whole driver.
+	* Migrated following ioctls (debug) ELX_DISPLAY_PCI_ALL
+	  ELX_DEVP ELX_READ_BPLIST ELX_RESET_QDEPTH ELX_STAT.
+	* Step 1 of attempt to move all Debug ioctls to sysfs.
+	  Implemented the following IOCTLs in sysfs: ELX_WRITE_HC
+	  ELX_WRITE_HS ELX_WRITE_HA ELX_WRITE_CA ELX_READ_HC
+	  ELX_READ_HS ELX_READ_HA ELX_READ_CA ELX_READ_MB ELX_RESET
+	  ELX_READ_HBA ELX_INSTANCE ELX_LIP.  Also introduced
+	  attribute "set" to be used in conjuction with the above
+	  attributes.
+	* Removed DLINK, enque and deque declarations now that clock
+	  doesn't use them anymore
+	* Separated install rule so that BUILD_IPFC has to be set when
+	  make is called in order for the install rule to attempt to
+	  copy the lpfndd.o driver.  This change fixes a bug that
+	  occurs because the install rule by default attempted to
+	  install lpfndd.o, whereas the default make rule did not by
+	  default build lpfndd.o.
+	* Keep track if hbaapi index numbers need to be refreshed.
+	* Removed prod_os.h from include list.
+	* Removed LPFC_LOCK and LPFC_UNLOCK macros.  Added OS calls
+	  into elx_os_scsiport.c.  This file is now empty.
+	* Added spin_lock_irqsave and spin_unlock_irqrestore calls
+	  into code directly and removed LPFC_LOCK_ and _UNLOCK_
+	  macros
+	* Remove references to "elx_clock.h"
+	* Added utsname.h to include list.  The previous checkin to
+	  elx_os.h removed its inclusion of utsname.h since there is
+	  precious little in the file.  However, lpfcLINUXfcp.c needs
+	  it and now has it.
+	* Removed some commented-out code
+	* Removed elx_lck_t data structure, stray elxDRVR_t type, and
+	  include from file.  No longer used.
+	* Removed two PCI Sync defines.  Removed includes - not
+	  needed.  Cleaned up macro lines.
+	* Added two functions from elxLINUXfcp.c.  These functions
+	  were IPFC specific.
+	* Removed hipri lock abstractions and added OS call into code.
+	  Removed elx_lck_t and added spinlock_t directly. Moved two
+	  IPFC functions into lpfc_ipport.c
+	* Moved IP specific structures to lpfc_ip.h file.
+	* lpfc_ipfarp_timeout() uses system timer.  Remove all usages
+	  of old internal clock support.
+	* Made changes to compile without IPFC support for the default
+	  build.  Added ifdef IPFC for all lpfc_ip.h includes.
+	* Patched elx_free_scsi_buf
+  	* Removed elx_sched.o from 2.6 dependencies
+	* Reworked lpfc_pcimap.
+	* Use Linux swap macros to replace ELX swapping macros
+	  (SWAP_SHORT, SWAP_LONG, SWAP_DATA, SWAP_DATA16,
+	  PCIMEM_SHORT, PCIMEM_LONG, PCIMEM_DATA).
+	* move in_interrupt() check inside of elx_sleep_ms()
+	* Moved location of pci.h include.
+	* Restored elx_lck_t types in elxHBA_t.
+	* Removed elx_pci_dma_sync call.  Also removed some PCI
+	  defines from elx_hw.h and removed the spinlock_t locks that
+	  are no longer used in elx.h
+	* elx_iodone() now uses system timer.
+  	* elx_qfull_retry() now uses system timer.
+	* lpfc_put_buf(), lpfc_ip_xri_timeout() and
+	  lpfc_ip_timeout_handler() now use system timer.
+	* lpfc_fdmi_tmo() and lpfc_qthrottle_up() now use system
+          timer.
+	* Removed num_bufs and num_iocbs configuration parameters.
+	* Fixed a memory corruption bug. This was caused by a memory
+	  write to ndlp structure from lpfc_cmpl_els_acc function.
+	  This ndlp structure was freed from lpfc_els_unsol_event.
+	* lpfc_disc_timeout() and lpfc_establish_link_tmo() now use
+	  system timer.  Also update lpfc_els_retry_delay() to do a
+	  single lock release at the end.
+	* Remove use of PAN (pseudo adapter number).
+	* Reintroduced usage of the cross compiler for building on
+	  ppc64 to remove build errors that were cropping up when
+	  using the standard gcc compiler.
+	* Fix no-unlock-before return in lpfc_els_retry_delay which was
+	  causing  a deadlock on insmod in some environments.
+	* Minor format changes fix up comments
+	* Create utility clock function elx_start_timer() and
+	  elx_stop_timer().  All timeout routines now use these common
+	  routines.
+	* Minor formating changes fix up comments
+	* Minor formatting changes get rid of failover defines for
+	  syntax checking
+	* Minor formatting changes remove ISCSI defines.
+	* Fix typo in install target for 2.4 kernels.
+	* Removed unused elx_scsi_add_timer extern function
+	  declaration.
+	* Cleanup casting around DMA masks.
+	* Comment out lpfndd.o modules_install section as lpfndd.o is
+	  not generated if CONFIG_NET_LPFC is not set. Also refer to
+	  BASEINCLUDE only in out of kernel source module builds as it
+	  will not exist otherwise.
+	* Removed unused malloc counters from lpfcLINUXfcp.c.
+	* Remove some unnecessary #includes in lpfcLINUXfcp.c
+	* Remove unncessary #includes in elxLINUXfcp.c
+	* Minor formatting cleanups in Makefile to avoid some
+          linewrapping.
+	* Removed unused elx_mem_pool data structure.
+	* Remove several unnecessary #includes.
+	* Moving fix for memory leak in ioctl lip area to sysfs's lip.
+	* Removed unused elx_dma_handle_t elx_acc_handle_t
+	  FC_MAX_SEGSZ and FC_MAX_POOL.
+	* Rewrite of Makefile. Fixes breakages with make -j4 during
+	  kernel compile. Does not recompile all files on every
+	  build. Uses the kernel build's definitions of CFLAGS,
+	  MODFLAGS etc. Removed "make rpm" option.
+	* Removed unused #defines CLOSED, DEAD, OPENED, NORMAL_OPEN
+	  and unneeded #include of elx_sched.h in elx.h.
+	* Several log message updates
+	* Add PCI_DEVICE_ID_FIREFLY for LP6000
+	* Fixed known issues in 20040326: driver crashes on rmmod in
+	  both 2.4 and 2.6 kernels
+	
+
+Changes from 20040319 to 20040326
+
+	* Updated ChangeLog for 20040326 SourceForge drop.
+	* remove lpfc_isr / lpfc_tmr logic fixed up 8 spaces from
+	  previous checkins with tabs
+	* replace elx_in_intr() with in_interrupt()
+	* Remove unused messages 1602 and 1603.
+	* Fix the following issues with log messages: Remove unused
+	  messages 406, 407, 409, 927, 928, 1201, 1202, 1204, 1205, 1206
+	  and 1207.  Create a new message 738 to fix duplicate instances
+	  of 736.
+	* Removed remaining pci interface abstractions from elxLINUXfcp.c.
+	  Implemented OS calls directly in all remaining files and cleaned
+	  up modules.  Removed prototypes as well.
+	* Removed following functions/structures elx_mem_dmapool
+	  elx_idx_dmapool elx_size_dmapool elx_kmem_lock dfc_data_alloc
+	  dfc_data_free dfc_mem struct mbuf_info elx_acc_handle_t
+	  data_handle elx_dma_handle_t dma_handle struct elx_memseg
+	  MEMSEG_t
+	* lpfc_els_timeout_handler() now uses system timer.
+	* Further cleanup of #ifdef powerpc
+	* lpfc_scsi_timeout_handler() now uses system timer.
+	* Replace common driver's own defines for endianess w/ Linux's
+	  __BIG_ENDIAN etc.
+	* Added #ifdef IPFC for all IPFC specific code.
+	* lpfc_disc_retry_rptlun() now uses system timer.
+	* lpfc_npr_timeout() now uses system timer.
+	* Modified detect code, on insmod, to only wait a max of 2 secs if
+	  link comes up and there are no devices.
+	* Move remaining message logging functions into
+	  elx_logmsg.c/elx_logmsg.h.
+	* Added code to clear link attention bit when there is a pending
+	  link event and the memory allocation for read_la mail box
+	  command fails.
+	* Removed function calls for mapping bar registers and allocating
+	  kernel virtual memory mappings to the mapped bars Removed
+	  prototypes, lpfc_driver_cache_line, and pci_bar1_map rename to
+	  pci_bar2_map.
+	* Allocate mbox only if the hba_state is in ready state.
+	* Complete lip support via sysfs. To lip, echo brdnum >
+	  /sys/bus/pci/drivers/lpfc/lip.
+	* moving sysfs show/store implementations to lpfc_sysfs.c. Also add
+	  support for lip.
+	* Add files: lpfc_sysfs.c, lpfc_sysfs.h
+	* move LPFC_DRIVER_NAME and LPFC_MODULE_DESC out of lpfcLINUXfcp.c
+	  to lpfc_version.h, since it is now needed in lpfc_sysfs.c
+	* elx_mbox_timeout now uses system timer
+	* Changed lpfc_nodev_timeout, lpfc_els_retry_delay and
+	  lpfc_linkdown_timeout to use the system timer instead of
+	  internal clock support.
+	* Move remaining message logging functions in elx_util.c to
+	  elx_logmsg.c.
+	* Remove some unnecessary typecasting.
+	* Remove log message that is no longer used (was used by
+	  elx_str_atox).
+	* Replaced DLINK_t and SLINK_t by standard Linux list_head
+	* Removed deque macro
+	* Replaced ELX_DLINK_t ans ELX_SLINK_t by Linux struct list_head
+	  (except for clock)
+	* Removed following functions from code: linux_kmalloc linux_kfree
+	  elx_alloc_bigbuf elx_free_bigbuf
+	* Removed following abstract functions from the code.  elx_malloc
+	  elx_free elx_ip_get_rcv_buf elx_ip_free_rcv_buf
+	  elx_mem_alloc_dmabuf elx_mem_alloc_dmabufext elx_mem_alloc_dma
+	  elx_mem_alloc_buf lpfc_bufmap
+	* Removed custom PCI configuration #defines and replaced with
+	  OS-provided #defines. Also added linux/pci.h to *.c files.
+	* Remove elx_str_ctox.	Replace elx_str_atox with sscanf.
+	* Many indentation/whitespace fixes.
+	* Replace elx_str_ctox with isxdigit where it was only used to
+	  check the value of a character.
+	* Removed following functions from the code.  elx_kmem_free
+	  elx_kmem_alloc elx_kmem_zalloc
+	* Change use of 2.4 SCSI typedef Scsi_Host_Template to	struct
+	  scsi_host_template for 2.6 kernels.
+	* Change use of 2.4 SCSI typedefs (Scsi_Device, Scsi_Cmnd,
+	  Scsi_Request) the their real struct names.
+	* Move 2.6 compatibility irqreturn definitions to lpfc_compat.h.
+	  Protect these definitions from conflicting with similar ones in
+	  later 2.4 kernels.
+	* Remove unused definitions: LINUX_TGT_t, LINUX_LUN_t,
+	  LINUX_BUF_t, elx_lun_t, SET_ADAPTER_STATUS.
+	* Convert pci_ calls to linux 2.6 dma_ equivalents.
+	* Removed unused types: struct buf, struct sc_buf, T_SCSIBUF
+	  typedef.
+	* Fix Makefile so that 2.4 drivers don't always rebuild all files.
+	* Remove unused _static_ and fc_lun_t definitions.
+	* Cleaned up some memory pool implementation code.
+	* Fix panic with char dev changes. Turns out that 2.6.4 code does
+	  the same in kernel space with the 2.4 interface style
+	  definitions. So remove the new char dev code altogether.
+	* Remove typecasting from fc_get_cfg_param and consolidate
+	  multiple instances of the parameter switch into a single
+	  instance.
+	* Use lpfc_is_LC_HBA() macro that tests pcidev->device directly
+	  instead of saving a private copy that undergoes varied shifting
+	  & casting.
+	* Removed usage of all memory pools.
+
+Changes from 20040312 to 20040319
+	
+	* Use dev_warn instead of printk for 2.6 kernels
+	* Correct Iocbq completion routine for 2.6 kernel case
+	* Change void *pOSCmd to Scsi_Smnd *pCmd
+	* Change void *pOScmd to struct sk_buff *pCmd
+	* Remove data directon code.
+	* Removed memory pool for buf/bpl buffers and use kmalloc/kfree
+	  pci_pool_alloc/free directly.
+	* Move PPC check for DMA address 0 in scatter-gather list, into
+	  lpfc_compat.h
+	* Always use pci_unmap_single() instead of pci_unmap_page()
+	* Clean up the 2.6 vs 2.4 #if blocks.
+	* Conditionalize Scheduler
+	* Add a comment to explain a little what the first Makefile
+	  section does.
+	* Removed lpfc_intr_post
+	* Sysfs new display format. Also added write functionality. You
+	  can [ echo "0 log_verbose 3" >
+	  /sys/bus/pci/drivers/lpfc/params]. Hex support yet to be added.
+	* Removed several #ifdef powerpc, including for a discovery issue
+	  in lpfc_ValidLun()
+	* Change elx_printf_log to use vsprintf.
+	* Added lpfc_compat.h provides macros to aid compilation in the
+	  Linux 2.4 kernel over various platform architectures.  Initially
+	  support mapping to a DMA address.
+	* Removed memory pool for nlp/bind buffers and use kmalloc/kfree
+	  directly.
+	* Removed memory pool for iocb buffers and use kmalloc/kfree
+	  directly.
+	* Removed memory pool for mailbox buffers and use kmalloc/kfree
+	  directly.
+	* Cleaned up back and forth casts
+	* Initial support for sysfs for 2.6 kernel.
+	* Changed elx_dma_addr_t to dma_addr_t
+	* Fix a 2.6 kernel check to be >= 2.6.0 instead of > (was missing
+	  2.6.0).
+	* Remove elx_printf and elx_str_sprintf. Replace elx_print with
+	  printk.
+	* Replace elx_printf with printk.
+	* Replace elx_str_sprintf with sprintf.
+	* Removed the mem_lock, its prototype, function, macro, and
+	  iflags.
+	* Use kmalloc/kfree for ELX_SCSI_BUF_t
+	* Use linux pci_pools for SCSI_DMA_EXT
+	* Use linux pci_pools for BPLs.
+	* Minor cleanup of DFC args for PPC64.
+	* Several small indentation cleanups.
+	* New Linux 2.6 style of char device registration.
+	* Migrated members of LPFCHBA_t and LINUX_HBA_t into elxHBA_t
+	* Use strcpy, strncmp, isdigit, strlen instead of abstractions
+	* Cleanup of driver_template.
+	* Facilitate compile time turn on/off of lpfc_network_on.
+	* Split large source files into smaller, better named ones.
+
+Changes from 2.10a to 20040312
+
+	* Fix build for 2.4 kernels
+	* Move driver version macros into lpfc_version.h file.
+	* Fixed data miscompare with LIP.
+	* Removed elx_sli, elx_ioc, elx_disc, elx_sch routines,
+	  prototypes, and reference points.
+	* Correct the space insertions with hardtabs
+	* Remove routine call pointers in ELX_SLI_INIT_t struct.
+	* Removed module locks except for drvr, mem, and clock.
+	* Removed unused module locks from sourcebase. Kept drvr_lock,
+	  mem_lock, and clock_lock.
+	* Change NULL to 0
diff --git a/Documentation/scsi/lpfc.txt b/Documentation/scsi/lpfc.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/scsi/lpfc.txt
@@ -0,0 +1,83 @@
+
+LPFC Driver Release Notes:
+
+=============================================================================
+
+
+                               IMPORTANT:
+
+  Starting in the 8.0.17 release, the driver began to be targeted strictly
+  toward the upstream kernel. As such, we removed #ifdefs for older kernels
+  (pre 2.6.10). The 8.0.16 release should be used if the driver is to be
+  run on one of the older kernels.
+
+  The proposed modifications to the transport layer for FC remote ports
+  and extended attribute support is now part of the upstream kernel
+  as of 2.6.12. We no longer need to provide patches for this support,
+  nor a *full* version which has old an new kernel support.
+  
+  The driver now requires a 2.6.12 (if pre-release, 2.6.12-rc1) or later
+  kernel.
+  
+  Please heed these dependencies....
+
+
+   ********************************************************************
+
+
+The following information is provided for additional background on the
+history of the driver as we push for upstream acceptance.
+
+Cable pull and temporary device Loss:
+
+  In older revisions of the lpfc driver, the driver internally queued i/o 
+  received from the midlayer. In the cases where a cable was pulled, link
+  jitter, or a device temporarily loses connectivity (due to its cable
+  being removed, a switch rebooting, or a device reboot), the driver could
+  hide the disappearance of the device from the midlayer. I/O's issued to
+  the LLDD would simply be queued for a short duration, allowing the device
+  to reappear or link come back alive, with no inadvertant side effects
+  to the system. If the driver did not hide these conditions, i/o would be
+  errored by the driver, the mid-layer would exhaust its retries, and the
+  device would be taken offline. Manual intervention would be required to
+  re-enable the device.
+
+  The community supporting kernel.org has driven an effort to remove
+  internal queuing from all LLDDs. The philosophy is that internal
+  queuing is unnecessary as the block layer already performs the 
+  queuing. Removing the queues from the LLDD makes a more predictable
+  and more simple LLDD.
+
+  As a potential new addition to kernel.org, the 8.x driver was asked to
+  have all internal queuing removed. Emulex complied with this request.
+  In explaining the impacts of this change, Emulex has worked with the
+  community in modifying the behavior of the SCSI midlayer so that SCSI
+  devices can be temporarily suspended while transport events (such as
+  those described) can occur.  
+
+  The proposed patch was posted to the linux-scsi mailing list. The patch
+  is contained in the 2.6.10-rc2 (and later) patch kits. As such, this
+  patch is part of the standard 2.6.10 kernel.
+
+  By default, the driver expects the patches for block/unblock interfaces
+  to be present in the kernel. No #define needs to be set to enable support.
+
+
+Kernel Support
+
+  This source package is targeted for the upstream kernel only. (See notes
+  at the top of this file). It relies on interfaces that are slowing
+  migrating into the kernel.org kernel.
+
+  At this time, the driver requires the 2.6.12 (if pre-release, 2.6.12-rc1)
+  kernel.
+
+  If a driver is needed for older kernels please utilize the 8.0.16
+  driver sources.
+
+
+Patches
+
+  Thankfully, at this time, patches are not needed.
+
+
diff --git a/Documentation/scsi/qla2xxx.revision.notes b/Documentation/scsi/qla2xxx.revision.notes
deleted file mode 100644
--- a/Documentation/scsi/qla2xxx.revision.notes
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * QLogic ISP2200 and ISP2300 Linux Driver Revision List File.
- *
- ********************************************************************
- *
- * Revision History
- *
- *  Rev  8.00.00b8	December 5, 2003	AV
- *	- Instruct mid-layer to perform initial scan.
- *
- *  Rev  8.00.00b7	December 5, 2003	AV
- *	- Resync with Linux Kernel 2.6.0-test11.
- *	- Add basic NVRAM parser (extras/qla_nvr).
- *
- *  Rev  8.00.00b7-pre11 December 3, 2003	AV
- *	- Sanitize the scsi_qla_host structure:
- *	  - Purge unused elements.
- *	  - Reorganize high-priority members (cache coherency).
- *	- Add support for NVRAM access via a sysfs binary attribute:
- *	  - Consolidate semaphore locking access.
- *	- Fix more PCI posting issues.
- *	- Add extras directory for dump/NVRAM tools.
- *	- Remove unused qla_vendor.c file.
- *
- *  Rev  8.00.00b7-pre11 November 26, 2003	DG/AV
- *	- Merge several patches from Christoph Hellwig [hch@lst.de]:
- *	  - in Linux 2.6 both pci and the scsi layer use the generic
- *	    dma direction bits, use them directly instead of the scsi
- *	    and pci variants and the (noop) conversion routines.
- *	- Fix _IOXX_BAD() usage for external IOCTL interface.
- *	- Use atomic construct for HA loop_state member.
- *	- Add generic model description text for HBA types.
- *
- *  Rev  8.00.00b7-pre5	November 17, 2003	AV
- *	- Merge several patches from Christoph Hellwig [hch@lst.de]:
- *	  - patch to split the driver into a common qla2xxx.ko and a
- *	    qla2?00.ko for each HBA type - the latter modules are
- *	    only very small wrappers, mostly for the firmware
- *	    images, all the meat is in the common qla2xxx.ko.
- *	  - make the failover code optional.
- *	  - kill useless lock_kernel in dpc thread startup.
- *	  - no need for modversions hacks in 2.6 (or 2.4).
- *	  - kill qla2x00_register_with_Linux.
- *	  - simplify EH code, cmd or it's hostdata can't be NULL, no
- *	    need to search whether the host it's ours, the midlayer
- *	    makes sure it won't call into a driver for some else
- *	    host.
- *	- Merge several patches from Jes Sorensen
- *	  [jes@wildopensource.com]:
- *	  - Call qla2x00_config_dma_addressing() before performing
- *	    any consistent allocations. This is required since the
- *	    dma mask settings will affect the memory
- *	    pci_alloc_consistent() will return.
- *	  - Call pci_set_consistent_dma_mask() to allow for 64 bit
- *	    consistent allocations, required on some platforms such
- *	    as the SN2.
- *	  - Wait 20 usecs (not sure how long is really necessary,
- *	    but this seems safe) after setting CSR_ISP_SOFT_RESET in
- *	    the ctrl_status register as the card doesn't respond to
- *	    PCI reads while in reset state. This causes a machine
- *	    check on some architectures.
- *	  - Flush PCI writes before calling udelay() to ensure the
- *	    write is not sitting idle in-flight for a while before
- *	    hitting the hardware.
- *	  - Include linux/vmalloc.h in qla_os.c since it uses
- *	    vmalloc().
- *	  - Use auto-negotiate link speed when using default
- *	    parameters rather than NVRAM settings. Disable NVRAM
- *	    reading on SN2 since it's not possible to execute the
- *	    HBA's BIOS on an SN2. I suggest doing something similar
- *	    for all architectures that do not provide x86 BIOS
- *	    emulation.
- *	- Clean-up slab-cache allocations:
- *	  - locking.
- *	  - mempool allocations in case of low-memory situations.
- *	- Fallback to GA_NXT scan if GID_PT call returns more than
- *	  MAX_FIBRE_DEVICES.
- *	- Preserve iterating port ID across GA_NXT calls in
- *	  qla2x00_find_all_fabric_devs().
- *	- Pre-calculate ASCII firmware dump length as to not incur the
- *	  cost-to-calculate at each invocation of a read().
- *
- *  Rev  8.00.00b6	November 4, 2003	AV
- *	- Add new 2300 TPX firmware (3.02.18).
- *
- *  Rev  8.00.00b6-pre25 October 20, 2003	RA/AV
- *	- Resync with Linux Kernel 2.6.0-test9.
- *	- Rework firmware dump process:
- *	  - Use binary attribute within sysfs tree.
- *	  - Add user-space tool (gdump.sh) to retrieve formatted
- *	    buffer.
- *	  - Add ISP2100 support.
- *	- Use a slab cache for SRB allocations to reduce memory
- *	  pressure.
- *	- Initial conversion of driver logging methods to a new
- *	  qla_printk() function which uses dev_printk (Daniel
- *	  Stekloff, IBM).
- *	- Further reduce stack usage in qla2x00_configure_local_loop()
- *	  and qla2x00_find_all_fabric_devs().
- *	- Separate port state used for routing of I/O's from port
- *	  mgmt-login retry etc.
- *
- *  Rev  8.00.00b6-pre19 October 13, 2003	AV
- *	- Resync with Linux Kernel 2.6.0-test7-bk5.
- *	- Add intelligent RSCN event handling:
- *	  - reduce scan time during 'port' RSCN events by only
- *	    querying specified port ids.
- *	  - Available on ISP23xx cards only.
- *	- Increase maximum number of recognizable targets from 256
- *	  to 512.
- *	  - Backend changes were previously added to support TPX
- *	    (2K logins) firmware.  Mid-layer can now scan for targets
- *	    (H, B, T, L) where 512 < T >= 0.
- *	- Remove IP support from driver.
- *	  - Switch firmware types from IP->TP for ISP22xx and
- *	    IPX->TPX for ISP23xx cards.
- *	  - Remove files qla_ip.[ch].
- *	- Remove type designations from firmware filenames.
- *
- *  Rev  8.00.00b6-pre11 September 15, 2003	DG/AV
- *	- Resync with 6.06.00.
- *	- Resync with Linux Kernel 2.6.0-test5-bk3.
- *	- Add new 2300 IPX firmware (3.02.15).
- *
- *  Rev  8.00.00b5	July 31, 2003		AV
- *	- Always create an fc_lun_t entry for lun 0 - as the mid-
- *	  layer requires access to this lun for discovery to occur.
- *	- General sanitizing:
- *	  - Add generic firmware option definitions.
- *	  - Generalize retrieval/update of firmware options.
- *	  - Fix compile errors which occur with extended debug.
- *	  - Handle failure cases for scsi_add_host() and
- *	    down_interruptible().
- *	- Host template updates:
- *	  - Use standard bios_param callback function.
- *	  - Disable clustering.
- *	  - Remove unchecked_is_dma entry.
- *
- *  Rev  8.00.00b5-pre5	July 29, 2003		DG/AV
- *	- Resync with 6.06.00b13.
- *	- Resync with Linux Kernel 2.6.0-test2.
- *	- Pass the complete loop_id, not the masked (0xff) value
- *	  while issuing mailbox commands (qla_mbx.c/qla_fo.c/
- *	  qla_iocb.c/qla_init.c).
- *	- Properly handle zero-length return status for an RLC CDB.
- *	- Create an fclun_t structure for 'disconnected' luns,
- *	  peripheral-qualifier of 001b.
- *	- Remove unused LIP-sequence register access during AE 8010.
- *	- Generalize qla2x00_mark_device_lost() to handle forced 
- *	  login request -- modify all direct/indirect invocations 
- *	  with proper flag.
- *	- Save RSCN notification (AE 8015h) data in a proper and 
- *	  consistent format (domain, area, al_pa).
- *	- General sanitizing:
- *	  - scsi_qla_host structure member reordering for cache-line
- *	    coherency.
- *	  - Remove unused SCSI opcodes, endian-swap definitions.
- *	  - Remove CMD_* pre-processor defines.
- *	  - Remove unused SCSIFCHOTSWAP/GAMAP/MULTIHOST codes.
- *	- Backout patch which added a per-scsi_qla_host scsi host
- *	  spinlock, since mid-layer already defines one.
- *	- Add new 2300 IPX firmware (3.02.15).
- *
- *  Rev  8.00.00b4	July 14, 2003		RA/DG/AV
- *	- Resync with 6.06.00b12.
- *	- Resync with Linux Kernel 2.6.0-test1.
- *	- Remove IOCB throttling code -- originally #if'd.
- *	- Remove apidev_*() routines since proc_mknod() has been
- *	  removed -- need alternate IOCTL interface.
- *	- Merge several performance/fix patches from Arjan van de
- *	  Ven:
- *	  - Undefined operation >> 32.
- *	  - No need to acquire mid-layer lock during command
- *	    callback. 
- *	  - Use a per-HBA mid-layer lock.
- *	  - Use a non-locked cycle for setting the count of the
- *	    newly allocated sp (qla2x00_get_new_sp()).
- *	  - Modify semantic behavior of qla2x00_queuecommand():
- *	    - Reduce cacheline bouncing by having I/Os submitted
- *	      by the IRQ handler.
- *	    - Remove extraneous calls to qla2x00_next() during I/O
- *	      queuing.
- *	  - Use list_splice_init() during qla2x00_done() handling
- *	    of commands to reduce list_lock contention.
- *	  - RIO mode support for ISP2200:
- *	    - Implementation differs slightly from original patch.
- *	  - Do not use bottom-half handler (tasklet/work queue)
- *	    for qla2x00_done() processing.
- *
- *  Rev  8.00.00b4-pre22 July 12, 2003		AV
- *	- Check for 'Process Response Queue' requests early during
- *	  the Host Status check.
- *	- General sanitizing:
- *	  - srb_t structure rewrite, removal of unused members.
- *	  - Remove unused fcdev array, fabricid, and PORT_*
- *	    definitions.
- *	  - Remove unused config_reg_t PCI definitions.
- *	- Add new 2200 IP firmware (2.02.06).
- *	- Add new 2300 IPX firmware (3.02.14).
- *
- *  Rev  8.00.00b4-pre19 June 30, 2003		AV
- *	- Resync with Linux Kernel 2.5.73-bk8.
- *	- Rework IOCB command queuing methods:
- *	  - Upper-layer driver *MUST* properly set the direction
- *	    bit of SCSI commands.
- *	  - Generalize 32bit/64bit queuing path functions.
- *	  - Remove costly page-boundary cross check when using
- *	    64bit address capable IOCBs.
- *
- *  Rev  8.00.00b4-pre15 June 19, 2003		AV
- *	- Resync with 6.06.00b11.
- *	- Continue fcport list consolidation work:
- *	  - Updated IOCTL implementations to use new fcports 
- *	    list.
- *	- Modified product ID check to not verify ISP chip
- *	  revision -- ISP2312 v3 (qla2x00_chip_diag()).
- *	- Add new 2300 IPX firmware (3.02.13):
- *
- *  Rev  8.00.00b4-pre13 June 19, 2003		AV
- *	- Fix build process for qla2100 driver -- no support
- *	  for IP.
- *	- SCSI host template modifications:
- *	  - Set sg_tablesize based on the derived DMA mask.
- *	  - Increase max_sectors since only limit within RISC
- *	    is transfer of (((2^32) - 1) >> 9) sectors.
- *
- *  Rev  8.00.00b4-pre12 June 18, 2003		RA, DG, RL, AV
- *	- Resync with 6.06.00b10.
- *	- Resync with Linux Kernel 2.5.72.
- *	- Initial fcport list consolidation work:
- *	  - fcports/fcinitiators/fcdev/fc_ip --> ha->fcports
- *	    list.
- *
- *  Rev  8.00.00b4-pre7	 June 05, 2003		AV
- *	- Properly release PCI resouces in init-failure case.
- *	- Reconcile disparite function return code definitions.
- *
- *  Rev  8.00.00b4-pre4	 June 03, 2003		AV
- *	- Resync with Linux Kernel 2.5.70-bk8:
- *	  - SHT proc_info() changes.
- *	- Restructure SNS Generic Services routines:
- *	  - Add qla_gs.c file to driver distribution.
- *	- Configure PCI latency timer for ISP23xx.
- *
- *  Rev  8.00.00b4-pre3	 June 02, 2003		RA, DG, RL, AV
- *	- Resync with 6.06.00b5.
- *	- Rework (again) PCI I/O space configuration
- *	  (Anton Blanchard):
- *	  - Use pci_set_mwi() routine;
- *	    - Remove uneeded qla2x00_set_cache_line() function.
- *	  - Remove extraneous modification of PCI_COMMAND word.
- *
- *  Rev  8.00.00b3 	 May 29, 2003		AV
- *	- Resync with Linux Kernel 2.5.70.
- *	- Move RISC paused check from ISR fast-path.
- *
- *  Rev  8.00.00b3-pre8 May 26, 2003		AV
- *	- Add new 2300 IPX firmware (3.02.12):
- *	- Rework PCI I/O space configuration.
- *
- *  Rev  8.00.00b3-pre6	May 22, 2003		RA, DG, RL, AV
- *	- Resync with 6.06.00b3.
- *
- *  Rev  8.00.00b3-pre4	May 21 2003		AV
- *	- Add new 2300 IPX firmware (3.02.11):
- *	  - Remove 2300 TPX firmware from distribution.
- *
- *  Rev  8.00.00b3-pre3	May 21 2003		AV
- *	- Properly setup PCI configuation space during
- *	  initialization:
- *	  - Properly configure Memory-Mapped I/O during early
- *	    configuration stage.
- *	- Rework IP functionality to support 2k logins.
- *	- Add new 2300 IPX firmware (3.02.11):
- *	  - Remove 2300 TPX firmware from distribution.
- *
- *  Rev  8.00.00b3-pre2	May ??, 2003		RA, DG, RL, AV
- *	- Resync with 6.06.00b1.
- *
- *  Rev  8.00.00b3-pre1	May ??, 2003		RA, DG, RL, AV
- *	- Resync with 6.05.00.
- *
- *  Rev  8.00.00b2	May 19, 2003		AV
- *	- Simplify dma_addr_t handling during command queuing given
- *	  new block-layer defined restrictions:
- *	  - Physical addresses not spanning 4GB boundaries.
- *	- Firmware versions: 2100 TP (1.19.24), 2200 IP (2.02.05),
- *	  2300 TPX (3.02.10).
- *
- *  Rev  8.00.00b2-pre1	May 13, 2003		AV
- *	- Add support for new 'Hotplug initialization' model. 
- *	- Simplify host template by removing unused callbacks.
- *	- Use scsicam facilities to determine geometry.
- *	- Fix compilation issues for non-ISP23xx builds:
- *	  - Correct register references in qla_dbg.c.
- *	  - Correct Makefile build process.
- *
- *  Rev  8.00.00b1	May 05, 2003		AV
- *	- Resync with Linux Kernel 2.5.69.
- *	- Firmware versions: 2100 TP (1.19.24), 2200 TP (2.02.05),
- *	  2300 TPX (3.02.10).
- *
- *  Rev  8.00.00b1-pre45 April ??, 2003		AV
- *	- Resync with Linux Kernel 2.5.68-bk11:
- *	- Fix improper return-code assignment during fabric
- *	  discovery.
- *	- Remove additional extraneous #defines from
- *	  qla_settings.h.
- *	  - USE_PORTNAME -- FO will always use portname.
- *	- Default queue depth size set to 64.
- *
- *  Rev  8.00.00b1-pre42 April ??, 2003		AV
- *	- Convert bottom-half tasklet to a work_queue.
- *	- Initial basic coding of dynamic queue depth handling
- *	  during QUEUE FULL statuses.
- *	- Fix mailbox interface problem with
- *	  qla2x00_get_retry_cnt().
- *
- *  Rev  8.00.00b1-pre41 April ??, 2003		AV
- *	- Convert build defines qla2[1|2|3]00 macros to
- *	  qla2[1|2|3]xx due to module name stringification clashes.
- *	- Add additional ISP2322 checks during board configuration.
- *
- *  Rev  8.00.00b1-pre40 April ??, 2003		AV
- *	- Resync with Linux Kernel 2.5.68-bk8:
- *	  - Updated IRQ handler interface.
- *	- Add ISP dump code (stub) in case of SYSTEM_ERROR on
- *	  ISP2100.
- *	- Add new 2200 IP firmware (2.02.05).
- *
- *  Rev  8.00.00b1-pre39 April ??, 2003		AV
- *	- Resync with Linux Kernel 2.5.68.
- *	- Add simple build.sh script to aid in external compilation.
- *	- Clean-break with Kernel 2.4 compatibility.
- *	  - Rework DPC routine -- completion routines for signaling.
- *	- Re-add HBAAPI character device node for IOCTL support.
- *	- Remove residual QLA2X_PERFORMANCE defines.
- *	- Allocate SP pool via __get_free_pages() rather than
- *	  individual kmalloc()'s.
- *	- Inform SCSI mid-layer of 16-byte CDB support
- *	  (host->max_cmd_len):
- *	  - Remove unecessary 'more_cdb' handling code from
- *	    qla_iocb.c and qla_xioct.c.
- *	- Reduce duplicate code in fabric scanning logic (MS IOCB
- *	  preparation).
- *	- Add ISP dump code in case of SYSTEM_ERROR.
- *	- Remove 2300 VIX firmware from distribution:
- *	  - Add initial code for IPX support.
- *	- Add new 2300 TPX firmware (3.02.10).
- *
- *  Rev  8.00.00b1-pre34 April ??, 2003		AV
- *	- Resync with Linux Kernel 2.5.67.
- *	- Use domain/area/al_pa fields when displaying PortID 
- *	  values -- addresses endianess issues.
- *	- Rework large case statement to check 'common' CDB commands
- *	  early in qla2x00_get_cmd_direction().
- *
- *  Rev  8.00.00b1-pre31 April ??, 2003		AV
- *	- Update makefile to support PPC64 build.
- *	- Retool NVRAM configuration routine and structures:
- *	  - Consoldate ISP21xx/ISP22xx/ISP23xx configuration
- *	    (struct nvram_t).
- *	  - Remove big/little endian support structures in favor of
- *	    simplified bit-operations within byte fields.
- *	- Fix long-standing 'static' buffer sharing problem in 
- *	  qla2x00_configure_fabric().
- *
- *  Rev  8.00.00b1-pre30 April ??, 2003		AV
- *	- Complete implementation of GID_PT scan.
- *	- Use consistent MS IOCB invocation method to query SNS:
- *	  - Add RNN_ID and RSNN_NN registrations in a fabric.
- *	- Remove unused Mailbox Command 6Eh (Send SNS) support
- *	  structures.
- *	- Use 64bit safe IOCBs while issuing INQUIRY and RLC during
- *	  topology scan.
- *	- Until reimplementation of fcdev_t/fcport list
- *	  consolidation, valid loop_id ranges are still limited from
- *	  0x00 through 0xFF -- enforce this within the code.
- *
- *  Rev  8.00.00b1-pre27 March ??, 2003		AV
- *	- Resync with 6.05.00b9.
- *	- Retool HBA PCI configuration -- qla2x00_pci_config().
- *	- Remove inconsistent use of delay routines (UDELAY/SYS*).
- *	- Continue to teardown/clean/add comments and debug
- *	  routines.
- *	- Properly swap bytes of the device's nodename in
- *	  qla2x00_configure_local_loop().
- *
- *  Rev  8.00.00b1-pre25 March ??, 2003		AV
- *	- Resync with 6.05.00b8.
- *
- *  Rev  8.00.00b1-pre23 March ??, 2003		AV
- *	- Remove (#define) IOCB usage throttling.
- *	- Abstract interrupt polling with qla2x00_poll().
- *	- Modify lun scanning logic:
- *	  - If the device does not support the SCSI Report Luns
- *	    command, the driver will now only scan from 0 to the
- *	    max#-luns as defined in the NVRAM (BIOS), rather than
- *	    blindly scanning from 0 to 255 -- which could result in
- *	    an increase in startup time when running against slow
- *	    (JBOD) devices.
- *	- Rework reset logic in qla2x00_reset_chip() (spec).
- *
- *  Rev  8.00.00b1-pre22 March ??, 2003		AV
- *	- Resync with 6.05.00b7.
- *	- Cleanup (rewrite) ISR handler.
- *	- Rename kmem_zalloc --> qla2x00_kmem_zalloc():
- *	  - This function will eventually be removed.
- *	- Add new 2300 VIX firmware (3.02.09):
- *	  - Support for Tape, Fabric, 2K logins, IP, and VI.
- *
- *  Rev  8.00.00b1-pre18 March ??, 2003		AV
- *	- Support 232x type ISPs.
- *	- Support single firmware for each ISP type:
- *	  - Restructure brd_info/fw_info methods.
- *	  - Streamline firmware load process.
- *	  - Properly query firmware for version information.
- *	- Remove extraneous scsi_qla_host members:
- *	  - device_id ==> pdev->device
- *	- Fix fc4 features (RFF_ID) registration.
- *	- Convert kmem_zalloc --> qla2x00_kmem_zalloc().
- *	- Remove unused/extraneous #defines (USE_PORTNAME).
- *
- *  Rev  8.00.00b1-pre14 March ??, 2003		AV
- *	- Resync with 6.05.00b6.
- *	- Initial source-code restructuring effort.
- *	  - Build procedure.
- *	  - Source file layout -- intuitive component layout.
- *	  - Remove unused #defines (*PERFORMANCE, WORD_FW_LOAD, etc).
- *	- Add support for 2K logins (TPX -- firmware).
- *	- Add module parameter ql2xsuspendcount.
- *	- Add new 2200 IP/TP firmware (2.02.04).
- *
- *  Rev  8.00.00b1-pre9	March ??, 2003	RL/DG/RA/AV
- *	- Use kernel struct list_head for fcport and fclun lists.
- *	- Remove extraneous (L|M)S_64BITS() and QL21_64*() defines.
- *
- *  Rev  8.00.00b1-pre8	February 28, 2003	RL/DG/RA/AV
- *	- Resync with 6.05.00b3.
- *
- *  Rev  8.00.00b1-pre7	February 23, 2003	RL/DG/RA/AV
- *	- Add alternate fabric scanning logic (GID_PT/GNN_ID/GPN_ID).
- *	- Remove use of deprecated function check_region().
- *	- Add new 2300 IP/TP firmware (3.02.08).
- *
- *  Rev  8.00.00b1-pre5	January 28, 2003	RL/DG/RA/AV
- *	- Resync with 6.05.00b3.
- *	- Consolidate device_reg structure definitions for ISP types.
- *	- Add support for new queue-depth selection.
- *	- Add new 2300 IP/TP firmware (3.02.07).
- *
- *  Rev  8.00.00b1-pre1	January 17, 2003	AV
- *	- Initial branch from 6.04.00b8 driver.
- *	- Remove VMWARE specific code.
- *	- Add support for pci_driver interface.
- *
- ********************************************************************/
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -389,8 +389,6 @@ Summary:
    scsi_remove_host - detach and remove all SCSI devices owned by host
    scsi_report_bus_reset - report scsi _bus_ reset observed
    scsi_set_device - place device reference in host structure
-   scsi_to_pci_dma_dir - convert SCSI subsystem direction flag to PCI
-   scsi_to_sbus_dma_dir - convert SCSI subsystem direction flag to SBUS
    scsi_track_queue_full - track successive QUEUE_FULL events 
    scsi_unblock_requests - allow further commands to be queued to given host
    scsi_unregister - [calls scsi_host_put()]
@@ -757,48 +755,6 @@ void scsi_set_device(struct Scsi_Host * 
 
 
 /**
- * scsi_to_pci_dma_dir - convert SCSI subsystem direction flag to PCI
- * @scsi_data_direction: SCSI subsystem direction flag
- *
- *      Returns DMA_TO_DEVICE given SCSI_DATA_WRITE,
- *              DMA_FROM_DEVICE given SCSI_DATA_READ
- *              DMA_BIDIRECTIONAL given SCSI_DATA_UNKNOWN
- *              else returns DMA_NONE
- *
- *      Might block: no
- *
- *      Notes: The SCSI subsystem now uses the same values for these
- *      constants as the PCI subsystem so this function is a nop.
- *      The recommendation is not to use this conversion function anymore
- *      (in the 2.6 kernel series) as it is not needed.
- *
- *      Defined in: drivers/scsi/scsi.h .
- **/
-int scsi_to_pci_dma_dir(unsigned char scsi_data_direction)
-
-
-/**
- * scsi_to_sbus_dma_dir - convert SCSI subsystem direction flag to SBUS
- * @scsi_data_direction: SCSI subsystem direction flag
- *
- *      Returns DMA_TO_DEVICE given SCSI_DATA_WRITE,
- *              FROM_DEVICE given SCSI_DATA_READ
- *              DMA_BIDIRECTIONAL given SCSI_DATA_UNKNOWN
- *              else returns DMA_NONE
- *
- *      Notes: The SCSI subsystem now uses the same values for these
- *      constants as the SBUS subsystem so this function is a nop.
- *      The recommendation is not to use this conversion function anymore
- *      (in the 2.6 kernel series) as it is not needed.
- *
- *      Might block: no
- *
- *      Defined in: drivers/scsi/scsi.h .
- **/
-int scsi_to_sbus_dma_dir(unsigned char scsi_data_direction)
-
-
-/**
  * scsi_track_queue_full - track successive QUEUE_FULL events on given
  *                      device to determine if and when there is a need
  *                      to adjust the queue depth on the device.
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -2,7 +2,7 @@ This file contains brief information abo
 The driver is currently maintained by Kai Mäkisara (email
 Kai.Makisara@kolumbus.fi)
 
-Last modified: Wed Feb 25 14:09:08 2004 by makisara
+Last modified: Mon Mar  7 21:14:44 2005 by kai.makisara
 
 
 BASICS
@@ -85,6 +85,9 @@ writing and the last operation has been 
 optionally written. In both cases end of data is signified by
 returning zero bytes for two consecutive reads.
 
+If rewind, offline, bsf, or seek is done and previous tape operation was
+write, a filemark is written before moving tape.
+
 The compile options are defined in the file linux/drivers/scsi/st_options.h.
 
 4. If the open option O_NONBLOCK is used, open succeeds even if the
diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
--- a/Documentation/scsi/sym53c8xx_2.txt
+++ b/Documentation/scsi/sym53c8xx_2.txt
@@ -440,7 +440,7 @@ lilo: linux root=/dev/sda2 sym53c8xx.cmd
 The following command will install the driver module with the same
 options as above.
 
-    modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200"
+    modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200
 
 10.2 Available arguments
 
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -7,75 +7,75 @@
 Kernel Configuration
 ====================
 
-To enable the ALSA support, at least you need to build the kernel with
-the primary sound card support (CONFIG_SOUND).  Since ALSA can emulate
-the OSS, you don't have to choose any of the OSS/Free modules.  Please
-enable "OSS API emulation" (CONFIG_SND_OSSEMUL) and both OSS mixer and
-PCM supports if you want to run the OSS application with the ALSA.
+To enable ALSA support you need at least to build the kernel with
+primary sound card support (CONFIG_SOUND).  Since ALSA can emulate OSS,
+you don't have to choose any of the OSS modules.
 
-When you want to support the WaveTable functionality on some cards
-such like SB Live!, you need to enable "Sequencer support"
+Enable "OSS API emulation" (CONFIG_SND_OSSEMUL) and both OSS mixer and
+PCM supports if you want to run OSS applications with ALSA.
+
+If you want to support the WaveTable functionality on cards such as
+SB Live! then you need to enable "Sequencer support"
 (CONFIG_SND_SEQUENCER).
 
-For getting more verbose debug messages, turn on "Verbose printk" and
-"Debug" options.  For checking the memory leaks, you can turn on
-"Debug memory" option, too.  "Debug detection" will put more
-additional checks for the detection of cards.
-
-Please note that all the ALSA ISA drivers support Linux isapnp API (if
-the card supports).  You don't need to configure the PnP via
-isapnptools.
+To make ALSA debug messages more verbose, enable the "Verbose printk"
+and "Debug" options.  To check for memory leaks, turn on "Debug memory"
+too.  "Debug detection" will add checks for the detection of cards.
+
+Please note that all the ALSA ISA drivers support the Linux isapnp API
+(if the card supports ISA PnP).  You don't need to configure the cards
+using isapnptools.
 
 
 Creating ALSA devices
 =====================
 
-Use the /dev/MAKEDEV script to create the nessecary device nodes.
+This depends on your distribution, but normally you use the /dev/MAKEDEV
+script to create the necessary device nodes.  On some systems you use a
+script named 'snddevices'.
 
 
 Module parameters
 =================
 
-  A user can modify or set parameters at the load time of the module. If
-  the module supports more cards and you have got more than one card
-  of the same type, you may simply specify more values for the parameter,
-  delimited by commas.
-  
-  Note that module option names were changed in 0.9.0rc4. The 'snd_'
-  prefix was removed.
+The user can load modules with options. If the module supports more than
+one card and you have more than one card of the same type then you can
+specify multiple values for the option separated by commas.
+
+Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
   Module snd
   ----------
 
-    The module snd is the ALSA core module, which is used by all ALSA
-    card drivers.  This takes the global options for creating devices,
-    etc.
+    The core ALSA module.  It is used by all ALSA card drivers.
+    It takes the following options which have global effects.
 
-    major	- major # for sound driver
-		- default is 116
+    major	- major number for sound driver
+		- Default: 116
     cards_limit
-		- specifies card limit # for auto-loading (1-8)
-		- default is 1
-		- for auto-loading more than 1 card, specify this option
-		  together with snd-card-X aliases.
+		- limiting card index for auto-loading (1-8)
+		- Default: 1
+		- For auto-loading more than one card, specify this
+		  option together with snd-card-X aliases.
     device_mode
-		- specifies permission mask for dynamic sound device filesystem
-		  (available only when DEVFS is enabled)
-		- default value = 0666
-		- for example 'device_mode=0660'
+		- permission mask for dynamic sound device filesystem
+		- This is available only when DEVFS is enabled
+		- Default: 0666
+		- E.g.: device_mode=0660
 
   
   Module snd-pcm-oss
   ------------------
 
     The PCM OSS emulation module.
-    This module takes the options to change the mapping of devices.
+    This module takes options which change the mapping of devices.
 
     dsp_map	- PCM device number maps assigned to the 1st OSS device.
-		  (default: 0)
+		- Default: 0
     adsp_map	- PCM device number maps assigned to the 2st OSS device.
-		  (default: 1)
-    nonblock_open - Don't block opening busy PCM devices.
+		- Default: 1
+    nonblock_open
+		- Don't block opening busy PCM devices.
 
     For example, when dsp_map=2, /dev/dsp will be mapped to PCM #2 of
     the card #0.  Similarly, when adsp_map=0, /dev/adsp will be mapped
@@ -91,33 +91,39 @@ Module parameters
   Module snd-rawmidi
   ------------------
 
-    This module takes the options to change the mapping of OSS
-    devices like snd-pcm-oss module.
+    This module takes options which change the mapping of devices.
+    similar to those of the snd-pcm-oss module.
 
     midi_map	- MIDI device number maps assigned to the 1st OSS device.
-		  (default: 0)
+		- Default: 0
     amidi_map	- MIDI device number maps assigned to the 2st OSS device.
-		  (default: 1)
+		- Default: 1
 
-  Common parameters for top soundcard modules
-  -------------------------------------------
+  Common parameters for top sound card modules
+  --------------------------------------------
 
-    Each of top-level soundcard module takes some general options,
+    Each of top level sound card module takes the following options.
 
-    index	- 0-7 - index (slot #) for soundcard
-                - if not set or -1, first free index (slot #) is assigned
-    id		- user identification for card (up to 15 chars)
-		- default expression is 'card<index>' (for example card1)
-		- value is used for /proc/asound filesystem
-		- this value can be used by applications for identification
-		  of card if user does not want identify card with index number
-    enable  	- enable card.  (all cards enabled for PCI and ISA PnP cards
-		  as default.)
+    index	- index (slot #) of sound card
+		- Values: 0 through 7 or negative
+		- If nonnegative, assign that index number
+                - if negative, interpret as a bitmask of permissible
+		  indices; the first free permitted index is assigned
+		- Default: -1
+    id		- card ID (identifier or name)
+		- Can be up to 15 characters long
+		- Default: the card type
+		- A directory by this name is created under /proc/asound/
+		  containing information about the card
+		- This ID can be used instead of the index number in
+		  identifying the card
+    enable  	- enable card
+		- Default: enabled, for PCI and ISA PnP cards
 
   Module snd-ad1816a
   ------------------
 
-    Module for soundcards based on Analog Devices AD1816A/AD1815 ISA chips.
+    Module for sound cards based on Analog Devices AD1816A/AD1815 ISA chips.
 
     port	- port # for AD1816A chip (PnP setup)
     mpu_port	- port # for MPU-401 UART (PnP setup)
@@ -132,7 +138,7 @@ Module parameters
   Module snd-ad1848
   -----------------
 
-    Module for soundcards based on AD1848/AD1847/CS4248 ISA chips.
+    Module for sound cards based on AD1848/AD1847/CS4248 ISA chips.
 
     port	- port # for AD1848 chip
     irq		- IRQ # for AD1848  chip
@@ -147,7 +153,8 @@ Module parameters
     Module for ALi M5451 PCI chip.
 
     pcm_channels    - Number of hardware channels assigned for PCM
-    spdif           - Support SPDIF I/O (disabled by default)
+    spdif           - Support SPDIF I/O
+    		    - Default: disabled
 
     Module supports autoprobe and multiple chips (max 8).
 
@@ -156,7 +163,7 @@ Module parameters
   Module snd-als100
   -----------------
 
-    Module for soundcards based on Avance Logic ALS100/ALS120 ISA chips.
+    Module for sound cards based on Avance Logic ALS100/ALS120 ISA chips.
 
     port	- port # for ALS100 (SB16) chip (PnP setup)
     irq		- IRQ # for ALS100 (SB16) chip (PnP setup)
@@ -171,7 +178,7 @@ Module parameters
   Module snd-als4000
   ------------------
 
-    Module for soundcards based on Avance Logic ALS4000 PCI chip.
+    Module for sound cards based on Avance Logic ALS4000 PCI chip.
 
     joystick_port - port # for legacy joystick support.
                     0 = disabled (default), 1 = auto-detect
@@ -197,6 +204,9 @@ Module parameters
 
     Module supports up to 8 cards.
 
+    Note: The default index value of this module is -2, i.e. the first
+          slot is excluded.
+
   Module snd-au8810, snd-au8820, snd-au8830
   -----------------------------------------
 
@@ -226,7 +236,7 @@ Module parameters
   Module snd-azt2320
   ------------------
 
-    Module for soundcards based on Aztech System AZT2320 ISA chip (PnP only).
+    Module for sound cards based on Aztech System AZT2320 ISA chip (PnP only).
 
     port	- port # for AZT2320 chip (PnP setup)
     wss_port	- port # for WSS (PnP setup)
@@ -242,7 +252,7 @@ Module parameters
   Module snd-azt3328
   ------------------
 
-    Module for soundcards based on Aztech AZF3328 PCI chip.
+    Module for sound cards based on Aztech AZF3328 PCI chip.
 
     joystick	- Enable joystick (default off)
 
@@ -258,6 +268,9 @@ Module parameters
 
     Module supports up to 8 cards.
 
+    Note: The default index value of this module is -2, i.e. the first
+          slot is excluded.
+
   Module snd-ca0106
   -----------------
 
@@ -269,7 +282,7 @@ Module parameters
   Module snd-cmi8330
   ------------------
 
-    Module for soundcards based on C-Media CMI8330 ISA chips.
+    Module for sound cards based on C-Media CMI8330 ISA chips.
 
     wssport	- port # for CMI8330 chip (WSS)
     wssirq	- IRQ # for CMI8330 chip (WSS)
@@ -284,7 +297,7 @@ Module parameters
   Module snd-cmipci
   -----------------
 
-    Module for C-Media CMI8338 and 8738 PCI soundcards.
+    Module for C-Media CMI8338 and 8738 PCI sound cards.
 
     mpu_port	- 0x300,0x310,0x320,0x330, 0 = disable (default)
     fm_port     - 0x388 (default), 0 = disable (default)
@@ -297,7 +310,7 @@ Module parameters
   Module snd-cs4231
   -----------------
 
-    Module for soundcards based on CS4231 ISA chips.
+    Module for sound cards based on CS4231 ISA chips.
 
     port	- port # for CS4231 chip
     mpu_port	- port # for MPU-401 UART (optional), -1 = disable
@@ -314,7 +327,7 @@ Module parameters
   Module snd-cs4232
   -----------------
 
-    Module for soundcards based on CS4232/CS4232A ISA chips.
+    Module for sound cards based on CS4232/CS4232A ISA chips.
 
     port	- port # for CS4232 chip (PnP setup - 0x534)
     cport	- control port # for CS4232 chip (PnP setup - 0x120,0x210,0xf00)
@@ -334,7 +347,7 @@ Module parameters
   Module snd-cs4236
   -----------------
 
-    Module for soundcards based on CS4235/CS4236/CS4236B/CS4237B/
+    Module for sound cards based on CS4235/CS4236/CS4236B/CS4237B/
                                    CS4238B/CS4239 ISA chips.
 
     port	- port # for CS4236 chip (PnP setup - 0x534)
@@ -367,7 +380,7 @@ Module parameters
   Module snd-cs46xx
   -----------------
 
-    Module for PCI soundcards based on CS4610/CS4612/CS4614/CS4615/CS4622/
+    Module for PCI sound cards based on CS4610/CS4612/CS4614/CS4615/CS4622/
 				       CS4624/CS4630/CS4280 PCI chips.
 
     external_amp     - Force to enable external amplifer.
@@ -400,14 +413,14 @@ Module parameters
   Module snd-dummy
   ----------------
 
-    Module for the dummy soundcard. This soundcard doesn't do any output
+    Module for the dummy sound card. This "card" doesn't do any output
     or input, but you may use this module for any application which
-    requires a soundcard (like RealPlayer).
+    requires a sound card (like RealPlayer).
 
   Module snd-emu10k1
   ------------------
 
-    Module for EMU10K1/EMU10k2 based PCI soundcards.
+    Module for EMU10K1/EMU10k2 based PCI sound cards.
 			* Sound Blaster Live!
 			* Sound Blaster PCI 512
 			* Emu APS (partially supported)
@@ -447,7 +460,7 @@ Module parameters
   Module snd-ens1370
   ------------------
 
-    Module for Ensoniq AudioPCI ES1370 PCI soundcards.
+    Module for Ensoniq AudioPCI ES1370 PCI sound cards.
 			* SoundBlaster PCI 64
 			* SoundBlaster PCI 128
 
@@ -458,7 +471,7 @@ Module parameters
   Module snd-ens1371
   ------------------
 
-    Module for Ensoniq AudioPCI ES1371 PCI soundcards.
+    Module for Ensoniq AudioPCI ES1371 PCI sound cards.
 			* SoundBlaster PCI 64
 			* SoundBlaster PCI 128
 			* SoundBlaster Vibra PCI
@@ -471,7 +484,7 @@ Module parameters
   Module snd-es968
   ----------------
 
-    Module for soundcards based on ESS ES968 chip (PnP only).
+    Module for sound cards based on ESS ES968 chip (PnP only).
 
     port	- port # for ES968 (SB8) chip (PnP setup)
     irq		- IRQ # for ES968 (SB8) chip (PnP setup)
@@ -482,7 +495,7 @@ Module parameters
   Module snd-es1688
   -----------------
 
-    Module for ESS AudioDrive ES-1688 and ES-688 soundcards.
+    Module for ESS AudioDrive ES-1688 and ES-688 sound cards.
 
     port	- port # for ES-1688 chip (0x220,0x240,0x260)
     mpu_port	- port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
@@ -495,7 +508,7 @@ Module parameters
   Module snd-es18xx
   -----------------
 
-    Module for ESS AudioDrive ES-18xx soundcards.
+    Module for ESS AudioDrive ES-18xx sound cards.
 
     port	- port # for ES-18xx chip (0x220,0x240,0x260)
     mpu_port	- port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
@@ -514,14 +527,14 @@ Module parameters
   Module snd-es1938
   -----------------
 
-    Module for soundcards based on ESS Solo-1 (ES1938,ES1946) chips.
+    Module for sound cards based on ESS Solo-1 (ES1938,ES1946) chips.
 
     Module supports up to 8 cards and autoprobe.
 
   Module snd-es1968
   -----------------
 
-    Module for soundcards based on ESS Maestro-1/2/2E (ES1968/ES1978) chips.
+    Module for sound cards based on ESS Maestro-1/2/2E (ES1968/ES1978) chips.
 
     total_bufsize	- total buffer size in kB (1-4096kB)
     pcm_substreams_p	- playback channels (1-8, default=2)
@@ -539,7 +552,7 @@ Module parameters
   Module snd-fm801
   ----------------
 
-    Module for ForteMedia FM801 based PCI soundcards.
+    Module for ForteMedia FM801 based PCI sound cards.
 
     tea575x_tuner       - Enable TEA575x tuner
                           - 1 = MediaForte 256-PCS
@@ -553,7 +566,7 @@ Module parameters
   Module snd-gusclassic
   ---------------------
 
-    Module for Gravis UltraSound Classic soundcard.
+    Module for Gravis UltraSound Classic sound card.
 
     port	- port # for GF1 chip (0x220,0x230,0x240,0x250,0x260)
     irq		- IRQ # for GF1 chip (3,5,9,11,12,15)
@@ -568,7 +581,7 @@ Module parameters
   Module snd-gusextreme
   ---------------------
 
-    Module for Gravis UltraSound Extreme (Synergy ViperMax) soundcard.
+    Module for Gravis UltraSound Extreme (Synergy ViperMax) sound card.
 
     port	- port # for ES-1688 chip (0x220,0x230,0x240,0x250,0x260)
     gf1_port	- port # for GF1 chip (0x210,0x220,0x230,0x240,0x250,0x260,0x270)
@@ -587,7 +600,7 @@ Module parameters
   Module snd-gusmax
   -----------------
 
-    Module for Gravis UltraSound MAX soundcard.
+    Module for Gravis UltraSound MAX sound card.
 
     port	- port # for GF1 chip (0x220,0x230,0x240,0x250,0x260)
     irq		- IRQ # for GF1 chip (3,5,9,11,12,15)
@@ -599,18 +612,42 @@ Module parameters
 
     Module supports up to 8 cards and autoprobe.
     
+  Module snd-hda-intel
+  --------------------
+
+    Module for Intel HD Audio (ICH6, ICH6M, ICH7)
+
+    model	- force the model name
+
+    Module supports up to 8 cards.
+
+    Each codec may have a model table for different configurations.
+    If your machine isn't listed there, the default (usually minimal)
+    configuration is set up.  You can pass "model=<name>" option to
+    specify a certain model in such a case.  There are different
+    models depending on the codec chip.
+
+	  Model name	Description
+	  ----------    -----------
+	ALC880
+	  3stack	3-jack in back and a headphone out
+	  3stack-digout	3-jack in back, a HP out and a SPDIF out
+	  5stack	5-jack in back, 2-jack in front
+	  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
+	  w810		3-jack
+
+	CMI9880
+	  minimal	3-jack in back
+	  min_fp	3-jack in back, 2-jack in front
+	  full		6-jack in back, 2-jack in front
+	  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
+	  allout	5-jack in back, 2-jack in front, SPDIF out
+
   Module snd-hdsp
   ---------------
 
     Module for RME Hammerfall DSP audio interface(s)
 
-    precise_ptr	      - Enable precise pointer (doesn't work reliably).
-			(default = 0)
-    line_outs_monitor - Send all input and playback streams to line outs
-			by default. (default = 0)
-    force_firmware    - Force a reload of the I/O box firmware
-			(default = 0)
-
     Module supports up to 8 cards.
 
     Note: The firmware data can be automatically loaded via hotplug
@@ -628,7 +665,7 @@ Module parameters
   Module snd-ice1712
   ------------------
 
-    Module for Envy24 (ICE1712) based PCI soundcards.
+    Module for Envy24 (ICE1712) based PCI sound cards.
 			* MidiMan M Audio Delta 1010
 			* MidiMan M Audio Delta 1010LT
 			* MidiMan M Audio Delta DiO 2496
@@ -660,7 +697,7 @@ Module parameters
   Module snd-ice1724
   ------------------
 
-    Module for Envy24HT (VT/ICE1724) based PCI soundcards.
+    Module for Envy24HT (VT/ICE1724) based PCI sound cards.
 			* MidiMan M Audio Revolution 7.1
 			* AMP Ltd AUDIO2000
 			* TerraTec Aureon Sky-5.1, Space-7.1
@@ -689,7 +726,7 @@ Module parameters
                       hp_only = use headphone control as master
                       swap_hp = swap headphone and master controls
                       swap_surround = swap master and surround controls
-                      ad_shring = for AD1985, turn on OMS bit and use headphone
+                      ad_sharing = for AD1985, turn on OMS bit and use headphone
                       alc_jack = for ALC65x, turn on the jack sense mode
                       inv_eapd = inverted EAPD implementation
                       mute_led = bind EAPD bit for turning on/off mute LED
@@ -726,11 +763,14 @@ Module parameters
 
     This module supports up to 8 cards and autoprobe.
 
+    Note: The default index value of this module is -2, i.e. the first
+          slot is excluded.
+
   Module snd-interwave
   --------------------
 
     Module for Gravis UltraSound PnP, Dynasonic 3-D/Pro, STB Sound Rage 32
-    and other soundcards based on AMD InterWave (tm) chip.
+    and other sound cards based on AMD InterWave (tm) chip.
   
     port	- port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
     irq		- IRQ # for InterWave chip (3,5,9,11,12,15)
@@ -747,8 +787,8 @@ Module parameters
   Module snd-interwave-stb
   ------------------------
 
-    Module for UltraSound 32-Pro (soundcard from STB used by Compaq)
-    and other soundcards based on AMD InterWave (tm) chip with TEA6330T
+    Module for UltraSound 32-Pro (sound card from STB used by Compaq)
+    and other sound cards based on AMD InterWave (tm) chip with TEA6330T
     circuit for extended control of bass, treble and master volume.
   
     port	- port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
@@ -794,7 +834,7 @@ Module parameters
   Module snd-mixart
   -----------------
 
-    Module for Digigram miXart8 soundcards.
+    Module for Digigram miXart8 sound cards.
 
     Module supports multiple cards.
     Note: One miXart8 board will be represented as 4 alsa cards.
@@ -813,10 +853,9 @@ Module parameters
 
     port	- port number or -1 (disable)
     irq		- IRQ number or -1 (disable)
-    acpipnp	- ACPI PnP detection - 0 = disable, 1 = enable (default)
+    pnp		- PnP detection - 0 = disable, 1 = enable (default)
 
-    Module supports multiple devices (max 8) and ACPI PnP.  If PnP is not
-    used (or ACPI not enabled), port and irq must be specified.
+    Module supports multiple devices (max 8) and PnP.
     
   Module snd-mtpav
   ----------------
@@ -883,7 +922,7 @@ Module parameters
   Module snd-opl3sa2
   ------------------
 
-    Module for Yamaha OPL3-SA2/SA3 soundcards.
+    Module for Yamaha OPL3-SA2/SA3 sound cards.
 
     port	- control port # for OPL3-SA chip (0x370)
     sb_port	- SB port # for OPL3-SA chip (0x220,0x240)
@@ -903,7 +942,7 @@ Module parameters
   Module snd-opti92x-ad1848
   -------------------------
 
-    Module for soundcards based on OPTi 82c92x and Analog Devices AD1848 chips.
+    Module for sound cards based on OPTi 82c92x and Analog Devices AD1848 chips.
     Module works with OAK Mozart cards as well.
     
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
@@ -918,7 +957,7 @@ Module parameters
   Module snd-opti92x-cs4231
   -------------------------
 
-    Module for soundcards based on OPTi 82c92x and Crystal CS4231 chips.
+    Module for sound cards based on OPTi 82c92x and Crystal CS4231 chips.
     
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
     mpu_port  - port # for MPU-401 UART (0x300,0x310,0x320,0x330)
@@ -933,7 +972,7 @@ Module parameters
   Module snd-opti93x
   ------------------
 
-    Module for soundcards based on OPTi 82c93x chips.
+    Module for sound cards based on OPTi 82c93x chips.
     
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
     mpu_port  - port # for MPU-401 UART (0x300,0x310,0x320,0x330)
@@ -962,21 +1001,21 @@ Module parameters
   ----------------
 
     Module for RME Digi32, Digi32 Pro and Digi32/8 (Sek'd Prodif32, 
-    Prodif96 and Prodif Gold) soundcards.
+    Prodif96 and Prodif Gold) sound cards.
 
     Module supports up to 8 cards.
 
   Module snd-rme96
   ----------------
 
-    Module for RME Digi96, Digi96/8 and Digi96/8 PRO/PAD/PST soundcards.
+    Module for RME Digi96, Digi96/8 and Digi96/8 PRO/PAD/PST sound cards.
 
     Module supports up to 8 cards.
 
   Module snd-rme9652
   ------------------
 
-    Module for RME Digi9652 (Hammerfall, Hammerfall-Light) soundcards.
+    Module for RME Digi9652 (Hammerfall, Hammerfall-Light) sound cards.
 
     precise_ptr	- Enable precise pointer (doesn't work reliably).
 		  (default = 0)
@@ -992,7 +1031,7 @@ Module parameters
   Module snd-sa11xx-uda1341 (on arm only)
   ---------------------------------------
 
-    Module for Philips UDA1341TS on Compaq iPAQ H3600 soundcard.
+    Module for Philips UDA1341TS on Compaq iPAQ H3600 sound card.
 
     Module supports only one card.
     Module has no enable and index options.
@@ -1039,7 +1078,7 @@ Module parameters
   Module snd-sgalaxy
   ------------------
 
-    Module for Aztech Sound Galaxy soundcard.
+    Module for Aztech Sound Galaxy sound card.
 
     sbport	- Port # for SB16 interface (0x220,0x240)
     wssport	- Port # for WSS interface (0x530,0xe80,0xf40,0x604)
@@ -1079,7 +1118,7 @@ Module parameters
   Module snd-wavefront
   --------------------
 
-    Module for Turtle Beach Maui, Tropez and Tropez+ soundcards.
+    Module for Turtle Beach Maui, Tropez and Tropez+ sound cards.
 
     cs4232_pcm_port - Port # for CS4232 PCM interface.
     cs4232_pcm_irq  - IRQ # for CS4232 PCM interface (5,7,9,11,12,15).
@@ -1099,7 +1138,7 @@ Module parameters
   Module snd-sonicvibes
   ---------------------
 
-    Module for S3 SonicVibes PCI soundcards.
+    Module for S3 SonicVibes PCI sound cards.
 			* PINE Schubert 32 PCI
 
     reverb    - Reverb Enable - 1 = enable, 0 = disable (default)
@@ -1131,7 +1170,7 @@ Module parameters
   Module snd-trident
   ------------------
 
-    Module for Trident 4DWave DX/NX soundcards.
+    Module for Trident 4DWave DX/NX sound cards.
 			* Best Union  Miss Melody 4DWave PCI
 			* HIS  4DWave PCI
 			* Warpspeed  ONSpeed 4DWave PCI
@@ -1223,6 +1262,9 @@ Module parameters
 
     Module supports up to 8 cards.
 
+    Note: The default index value of this module is -2, i.e. the first
+          slot is excluded.
+
   Module snd-virmidi
   ------------------
 
@@ -1266,10 +1308,6 @@ Module parameters
 
     Module for Digigram VX-Pocket VX2 PCMCIA card.
 
-    irq_mask - IRQ bitmask, specifies the available IRQs as bits
-               (default = 0xffff, all available)
-    irq_list - List of available interrupts (default = -1, not specified)
-               4 numbers must be given (if specified).
     ibl      - Capture IBL size. (default = 0, minimum size)
 
     Module supports up to 8 cards.  The module is compiled only when
@@ -1284,9 +1322,6 @@ Module parameters
     When no hotplug fw loader is available, you need to load the
     firmware via vxloader utility in alsa-tools package.
 
-    The irq_mask and irq_list are provided to avoid allocation of
-    specific IRQs.  Usually you don't need to specify them.
-
     About capture IBL, see the description of snd-vx222 module.
 
     Note: the driver is build only when CONFIG_ISA is set.
@@ -1296,9 +1331,6 @@ Module parameters
 
     Module for Digigram VX-Pocket 440 PCMCIA card.
 
-    irq_mask - IRQ bitmask, specifies the available IRQs as bits
-    irq_list - List of available interrupts (default = -1, not specified)
-               4 numbers must be given (if specified).
     ibl      - Capture IBL size. (default = 0, minimum size)
 
     Module supports up to 8 cards.  The module is compiled only when
@@ -1313,9 +1345,6 @@ Module parameters
     When no hotplug fw loader is available, you need to load the
     firmware via vxloader utility in alsa-tools package.
 
-    The irq_mask and irq_list are provided to avoid allocation of
-    specific IRQs.  Usually you don't need to specify them.
-
     About capture IBL, see the description of snd-vx222 module.
 
     Note: the driver is build only when CONFIG_ISA is set.
@@ -1340,10 +1369,7 @@ Module parameters
   Module snd-pdaudiocf
   --------------------
 
-    Module for Sound Core PDAudioCF soundcard.
-
-    irq_mask	  - IRQ mask (PCMCIA type)
-    irq_list	  - List of available interrupts for this soundcard
+    Module for Sound Core PDAudioCF sound card.
 
     Note: the driver is build only when CONFIG_ISA is set.
 
@@ -1366,7 +1392,7 @@ Module Autoloading Support
 
 The ALSA drivers can be loaded automatically on demand by defining
 module aliases.  The string 'snd-card-%1' is requested for ALSA native
-devices where %i is soundcard number from zero to seven.
+devices where %i is sound card number from zero to seven.
 
 To auto-load an ALSA driver for OSS services, define the string
 'sound-slot-%i' where %i means the slot number for OSS, which
@@ -1379,16 +1405,16 @@ alias snd-card-0 snd-emu10k1
 alias sound-slot-0 snd-emu10k1
 ----- /etc/modprobe.conf
 
-The available number of auto-loaded soundcards depends on the module
+The available number of auto-loaded sound cards depends on the module
 option "cards_limit" of snd module.  As default it's set to 1.
 To enable the auto-loading of multiple cards, specify the number of
-soundcards in that option.
+sound cards in that option.
 
 When multiple cards are available, it'd better to specify the index
 number for each card via module option, too, so that the order of
 cards is kept consistent.
 
-An example configuration for two soundcards is like below:
+An example configuration for two sound cards is like below:
 
 ----- /etc/modprobe.conf
 # ALSA portion
@@ -1420,7 +1446,7 @@ ALSA PCM devices to OSS devices mapping
 /dev/snd/pcmC2D1[c|p]  -> /dev/adsp2               -> minor 12+32 = 44
 
 The first number from /dev/snd/pcmC{X}D{Y}[c|p] expression means
-soundcard number and second means device number.  The ALSA devices
+sound card number and second means device number.  The ALSA devices
 have either 'c' or 'p' suffix indicating the direction, capture and
 playback, respectively.
 
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -18,8 +18,8 @@
       </affiliation>
      </author>
 
-     <date>July 11, 2004</date>
-     <edition>0.3.3</edition>
+     <date>March 6, 2005</date>
+     <edition>0.3.4</edition>
 
     <abstract>
       <para>
@@ -110,9 +110,9 @@
       </para>
 
       <para>
-        One is the the trees provided as a tarball or via cvs from the
+        One is the trees provided as a tarball or via cvs from the
       ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
-      tree. To synchronize both, the ALSA driver tree is split to
+      tree. To synchronize both, the ALSA driver tree is split into
       two different trees: alsa-kernel and alsa-driver. The former
       contains purely the source codes for the Linux 2.6 (or later)
       tree. This tree is designed only for compilation on 2.6 or
@@ -766,7 +766,7 @@
       </para>
 
       <para>
-      The ALSA interfaces like PCM or control API are define in other
+      The ALSA interfaces like PCM or control API are defined in other
       header files as <filename>&lt;sound/xxx.h&gt;</filename>.
       They have to be included after
       <filename>&lt;sound/core.h&gt;</filename>.
@@ -1103,7 +1103,7 @@
           /* release the irq */
           if (chip->irq >= 0)
                   free_irq(chip->irq, (void *)chip);
-          /* release the i/o ports */
+          /* release the i/o ports & memory */
           pci_release_regions(chip->pci);
           /* disable the PCI entry */
           pci_disable_device(chip->pci);
@@ -1314,6 +1314,7 @@
       </para>
 
       <para>
+        <!-- obsolete -->
         It will reserve the i/o port region of 8 bytes of the given
       PCI device. The returned value, chip-&gt;res_port, is allocated
       via <function>kmalloc()</function> by
@@ -1936,6 +1937,7 @@
           snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           &snd_mychip_capture_ops);
           /* pre-allocation of buffers */
+          /* NOTE: this may fail */
           snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                 snd_dma_pci_data(chip->pci),
                                                 64*1024, 64*1024);
@@ -1950,7 +1952,7 @@
     <section id="pcm-interface-constructor">
       <title>Constructor</title>
       <para>
-        A pcm instance is allocated <function>snd_pcm_new()</function>
+        A pcm instance is allocated by <function>snd_pcm_new()</function>
       function. It would be better to create a constructor for pcm,
       namely, 
 
@@ -2235,7 +2237,8 @@ struct _snd_pcm_runtime {
 	unsigned char *dma_area;	/* DMA area */
 	dma_addr_t dma_addr;		/* physical bus address (not accessible from main CPU) */
 	size_t dma_bytes;		/* size of DMA area */
-	void *dma_private;		/* private DMA data for the memory allocator */
+
+	struct snd_dma_buffer *dma_buffer_p;	/* allocated buffer */
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	/* -- OSS things -- */
@@ -2250,7 +2253,7 @@ struct _snd_pcm_runtime {
 	<para>
 	  For the operators (callbacks) of each sound driver, most of
 	these records are supposed to be read-only.  Only the PCM
-	middle-layer changes / updates these info.  The excpetions are
+	middle-layer changes / updates these info.  The exceptions are
 	the hardware description (hw), interrupt callbacks
 	(transfer_ack_xxx), DMA buffer information, and the private
 	data.  Besides, if you use the standard buffer allocation
@@ -3008,6 +3011,9 @@ struct _snd_pcm_runtime {
 	current appl_ptr for the internal buffer, and this callback
 	is useful only for such a purpose.
 	</para>
+	<para>
+	  This callback is atomic.
+	</para>
       </section>
 
       <section id="pcm-interface-operators-page-callback">
@@ -3205,6 +3211,11 @@ struct _snd_pcm_runtime {
       <function>udelay()</function> or <function>mdelay()</function>.
       </para>
 
+      <para>
+      All three atomic callbacks (trigger, pointer, and ack) are
+      called with local interrupts disabled.
+      </para>
+
     </section>
     <section id="pcm-interface-constraints">
       <title>Constraints</title>
@@ -3250,7 +3261,7 @@ struct _snd_pcm_runtime {
 
       <para>
         There are many different constraints.
-        Look in <filename>sound/asound.h</filename> for a complete list.
+        Look in <filename>sound/pcm.h</filename> for a complete list.
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
@@ -4066,7 +4077,7 @@ struct _snd_pcm_runtime {
         Both <function>snd_ac97_write()</function> and
         <function>snd_ac97_update()</function> functions are used to
         set a value to the given register
-        (<constant>AC97_XXX</constant>). The different between them is
+        (<constant>AC97_XXX</constant>). The difference between them is
         that <function>snd_ac97_update()</function> doesn't write a
         value if the given value has been already set, while
         <function>snd_ac97_write()</function> always rewrites the
@@ -4152,8 +4163,8 @@ struct _snd_pcm_runtime {
       <title>Proc Files</title>
       <para>
         The ALSA AC97 interface will create a proc file such as
-      <filename>/proc/asound/card0/ac97#0</filename> and
-      <filename>ac97#0regs</filename>. You can refer to these files to
+      <filename>/proc/asound/card0/codec97#0/ac97#0-0</filename> and
+      <filename>ac97#0-0+regs</filename>. You can refer to these files to
       see the current status and registers of the codec. 
       </para>
     </section>
@@ -4200,18 +4211,6 @@ struct _snd_pcm_runtime {
       implementation of mpu401 stuff. For example, emu10k1 has its own
       mpu401 routines. 
       </para>
-
-      <para>
-        In this document, I won't explain the rawmidi interface API,
-      which is the basis of MPU401-UART implementation. 
-      </para>
-
-      <para>
-        For details, please check the source,
-      <filename>core/rawmidi.c</filename>, and examples such as
-      <filename>drivers/mpu401/mpu401_uart.c</filename> or
-      <filename>usb/usbmidi.c</filename>. 
-      </para>
     </section>
 
     <section id="midi-interface-constructor">
@@ -4335,6 +4334,354 @@ struct _snd_pcm_runtime {
 
 
 <!-- ****************************************************** -->
+<!-- RawMIDI Interface  -->
+<!-- ****************************************************** -->
+  <chapter id="rawmidi-interface">
+    <title>RawMIDI Interface</title>
+
+    <section id="rawmidi-interface-overview">
+      <title>Overview</title>
+
+      <para>
+      The raw MIDI interface is used for hardware MIDI ports that can
+      be accessed as a byte stream.  It is not used for synthesizer
+      chips that do not directly understand MIDI.
+      </para>
+
+      <para>
+      ALSA handles file and buffer management.  All you have to do is
+      to write some code to move data between the buffer and the
+      hardware.
+      </para>
+
+      <para>
+      The rawmidi API is defined in
+      <filename>&lt;sound/rawmidi.h&gt;</filename>.
+      </para>
+    </section>
+
+    <section id="rawmidi-interface-constructor">
+      <title>Constructor</title>
+
+      <para>
+      To create a rawmidi device, call the
+      <function>snd_rawmidi_new</function> function:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_t *rmidi;
+  err = snd_rawmidi_new(chip->card, "MyMIDI", 0, outs, ins, &rmidi);
+  if (err < 0)
+          return err;
+  rmidi->private_data = chip;
+  strcpy(rmidi->name, "My MIDI");
+  rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+                      SNDRV_RAWMIDI_INFO_INPUT |
+                      SNDRV_RAWMIDI_INFO_DUPLEX;
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <para>
+      The first argument is the card pointer, the second argument is
+      the ID string.
+      </para>
+
+      <para>
+      The third argument is the index of this component.  You can
+      create up to 8 rawmidi devices.
+      </para>
+
+      <para>
+      The fourth and fifth arguments are the number of output and
+      input substreams, respectively, of this device.  (A substream is
+      the equivalent of a MIDI port.)
+      </para>
+
+      <para>
+      Set the <structfield>info_flags</structfield> field to specify
+      the capabilities of the device.
+      Set <constant>SNDRV_RAWMIDI_INFO_OUTPUT</constant> if there is
+      at least one output port,
+      <constant>SNDRV_RAWMIDI_INFO_INPUT</constant> if there is at
+      least one input port,
+      and <constant>SNDRV_RAWMIDI_INFO_DUPLEX</constant> if the device
+      can handle output and input at the same time.
+      </para>
+
+      <para>
+      After the rawmidi device is created, you need to set the
+      operators (callbacks) for each substream.  There are helper
+      functions to set the operators for all substream of a device:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mymidi_output_ops);
+  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mymidi_input_ops);
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <para>
+      The operators are usually defined like this:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static snd_rawmidi_ops_t snd_mymidi_output_ops = {
+          .open =    snd_mymidi_output_open,
+          .close =   snd_mymidi_output_close,
+          .trigger = snd_mymidi_output_trigger,
+  };
+]]>
+          </programlisting>
+        </informalexample>
+      These callbacks are explained in the <link
+      linkend="rawmidi-interface-callbacks"><citetitle>Callbacks</citetitle></link>
+      section.
+      </para>
+
+      <para>
+      If there is more than one substream, you should give each one a
+      unique name:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  struct list_head *list;
+  snd_rawmidi_substream_t *substream;
+  list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
+          substream = list_entry(list, snd_rawmidi_substream_t, list);
+          sprintf(substream->name, "My MIDI Port %d", substream->number + 1);
+  }
+  /* same for SNDRV_RAWMIDI_STREAM_INPUT */
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+    </section>
+
+    <section id="rawmidi-interface-callbacks">
+      <title>Callbacks</title>
+
+      <para>
+      In all callbacks, the private data that you've set for the
+      rawmidi device can be accessed as
+      substream-&gt;rmidi-&gt;private_data.
+      <!-- <code> isn't available before DocBook 4.3 -->
+      </para>
+
+      <para>
+      If there is more than one port, your callbacks can determine the
+      port index from the snd_rawmidi_substream_t data passed to each
+      callback:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_substream_t *substream;
+  int index = substream->number;
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <section id="rawmidi-interface-op-open">
+      <title><function>open</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static int snd_xxx_open(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called when a substream is opened.
+        You can initialize the hardware here, but you should not yet
+        start transmitting/receiving data.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-close">
+      <title><function>close</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static int snd_xxx_close(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        Guess what.
+        </para>
+
+        <para>
+        The <function>open</function> and <function>close</function>
+        callbacks of a rawmidi device are serialized with a mutex,
+        and can sleep.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-trigger-out">
+      <title><function>trigger</function> callback for output
+      substreams</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_output_trigger(snd_rawmidi_substream_t *substream, int up);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called with a nonzero <parameter>up</parameter>
+        parameter when there is some data in the substream buffer that
+        must be transmitted.
+        </para>
+
+        <para>
+        To read data from the buffer, call
+        <function>snd_rawmidi_transmit_peek</function>.  It will
+        return the number of bytes that have been read; this will be
+        less than the number of bytes requested when there is no more
+        data in the buffer.
+        After the data has been transmitted successfully, call
+        <function>snd_rawmidi_transmit_ack</function> to remove the
+        data from the substream buffer:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  unsigned char data;
+  while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) {
+          if (mychip_try_to_transmit(data))
+                  snd_rawmidi_transmit_ack(substream, 1);
+          else
+                  break; /* hardware FIFO full */
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+
+        <para>
+        If you know beforehand that the hardware will accept data, you
+        can use the <function>snd_rawmidi_transmit</function> function
+        which reads some data and removes it from the buffer at once:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  while (mychip_transmit_possible()) {
+          unsigned char data;
+          if (snd_rawmidi_transmit(substream, &data, 1) != 1)
+                  break; /* no more data */
+          mychip_transmit(data);
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+
+        <para>
+        If you know beforehand how many bytes you can accept, you can
+        use a buffer size greater than one with the
+        <function>snd_rawmidi_transmit*</function> functions.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback must not sleep.  If
+        the hardware FIFO is full before the substream buffer has been
+        emptied, you have to continue transmitting data later, either
+        in an interrupt handler, or with a timer if the hardware
+        doesn't have a MIDI transmit interrupt.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback is called with a
+        zero <parameter>up</parameter> parameter when the transmission
+        of data should be aborted.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-trigger-in">
+      <title><function>trigger</function> callback for input
+      substreams</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_input_trigger(snd_rawmidi_substream_t *substream, int up);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called with a nonzero <parameter>up</parameter>
+        parameter to enable receiving data, or with a zero
+        <parameter>up</parameter> parameter do disable receiving data.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback must not sleep; the
+        actual reading of data from the device is usually done in an
+        interrupt handler.
+        </para>
+
+        <para>
+        When data reception is enabled, your interrupt handler should
+        call <function>snd_rawmidi_receive</function> for all received
+        data:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  void snd_mychip_midi_interrupt(...)
+  {
+          while (mychip_midi_available()) {
+                  unsigned char data;
+                  data = mychip_midi_read();
+                  snd_rawmidi_receive(substream, &data, 1);
+          }
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-drain">
+      <title><function>drain</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_drain(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is only used with output substreams.  This function should wait
+        until all data read from the substream buffer has been transmitted.
+        This ensures that the device can be closed and the driver unloaded
+        without losing data.
+        </para>
+
+        <para>
+        This callback is optional.  If you do not set
+        <structfield>drain</structfield> in the snd_rawmidi_ops_t
+        structure, ALSA will simply wait for 50&nbsp;milliseconds
+        instead.
+        </para>
+      </section>
+    </section>
+
+  </chapter>
+
+
+<!-- ****************************************************** -->
 <!-- Miscellaneous Devices  -->
 <!-- ****************************************************** -->
   <chapter id="misc-devices">
@@ -4633,7 +4980,7 @@ struct _snd_pcm_runtime {
         where <parameter>size</parameter> is the byte size to be
       pre-allocated and the <parameter>max</parameter> is the maximal
       size to be changed via <filename>prealloc</filename> proc file.
-      The allocator will try to get as the large area as possible
+      The allocator will try to get as large area as possible
       within the given size. 
       </para>
 
@@ -4855,7 +5202,7 @@ struct _snd_pcm_runtime {
         If your hardware supports the page table like emu10k1 or the
       buffer descriptors like via82xx, you can use the scatter-gather
       (SG) DMA. ALSA provides an interface for handling SG-buffers.
-      The API is provided in <filename>&lt;sound/pcm_sgbuf.h&gt;</filename>. 
+      The API is provided in <filename>&lt;sound/pcm.h&gt;</filename>. 
       </para>
 
       <para>
@@ -5159,12 +5506,12 @@ struct _snd_pcm_runtime {
         <programlisting>
 <![CDATA[
   #ifdef CONFIG_PM
-  static int snd_my_suspend(snd_card_t *card, unsigned int state)
+  static int snd_my_suspend(snd_card_t *card, pm_message_t state)
   {
           .... // do things for suspsend
           return 0;
   }
-  static int snd_my_resume(snd_card_t *card, unsigned int state)
+  static int snd_my_resume(snd_card_t *card)
   {
           .... // do things for suspsend
           return 0;
@@ -5193,7 +5540,7 @@ struct _snd_pcm_runtime {
       <informalexample>
         <programlisting>
 <![CDATA[
-  static int mychip_suspend(snd_card_t *card, unsigned int state)
+  static int mychip_suspend(snd_card_t *card, pm_message_t state)
   {
           /* (1) */
           mychip_t *chip = card->pm_private_data;
diff --git a/Documentation/sound/alsa/VIA82xx-mixer.txt b/Documentation/sound/alsa/VIA82xx-mixer.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/sound/alsa/VIA82xx-mixer.txt
@@ -0,0 +1,8 @@
+
+				VIA82xx mixer
+				=============
+
+On many VIA82xx boards, the 'Input Source Select' mixer control does not work.
+Setting it to 'Input2' on such boards will cause recording to hang, or fail
+with EIO (input/output error) via OSS emulation.  This control should be left
+at 'Input1' for such cards.
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/sound/alsa/hda_codec.txt
@@ -0,0 +1,299 @@
+Notes on Universal Interface for Intel High Definition Audio Codec
+------------------------------------------------------------------
+
+Takashi Iwai <tiwai@suse.de>
+
+
+[Still a draft version]
+
+
+General
+=======
+
+The snd-hda-codec module supports the generic access function for the
+High Definition (HD) audio codecs.  It's designed to be independent
+from the controller code like ac97 codec module.  The real accessors
+from/to the controller must be implemented in the lowlevel driver.
+
+The structure of this module is similar with ac97_codec module.
+Each codec chip belongs to a bus class which communicates with the
+controller.
+
+
+Initialization of Bus Instance
+==============================
+
+The card driver has to create struct hda_bus at first.  The template
+struct should be filled and passed to the constructor:
+
+struct hda_bus_template {
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+};
+
+The card driver can set and use the private_data field to retrieve its
+own data in callback functions.  The pci field is used when the patch
+needs to check the PCI subsystem IDs, so on.  For non-PCI system, it
+doesn't have to be set, of course.
+The modelname field specifies the board's specific configuration.  The
+string is passed to the codec parser, and it depends on the parser how
+the string is used.
+These fields, private_data, pci and modelname are all optional.
+
+The ops field contains the callback functions as the following:
+
+struct hda_bus_ops {
+	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
+		       unsigned int verb, unsigned int parm);
+	unsigned int (*get_response)(struct hda_codec *codec);
+	void (*private_free)(struct hda_bus *);
+};
+
+The command callback is called when the codec module needs to send a
+VERB to the controller.  It's always a single command.
+The get_response callback is called when the codec requires the answer
+for the last command.  These two callbacks are mandatory and have to
+be given.
+The last, private_free callback, is optional.  It's called in the
+destructor to release any necessary data in the lowlevel driver.
+
+The bus instance is created via snd_hda_bus_new().  You need to pass
+the card instance, the template, and the pointer to store the
+resultant bus instance.
+
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp);
+
+It returns zero if successful.  A negative return value means any
+error during creation.
+
+
+Creation of Codec Instance
+==========================
+
+Each codec chip on the board is then created on the BUS instance.
+To create a codec instance, call snd_hda_codec_new().
+
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp);
+
+The first argument is the BUS instance, the second argument is the
+address of the codec, and the last one is the pointer to store the
+resultant codec instance (can be NULL if not needed).
+
+The codec is stored in a linked list of bus instance.  You can follow
+the codec list like:
+
+	struct list_head *p;
+	struct hda_codec *codec;
+	list_for_each(p, &bus->codec_list) {
+		codec = list_entry(p, struct hda_codec, list);
+		...
+	}
+
+The codec isn't initialized at this stage properly.  The
+initialization sequence is called when the controls are built later.
+
+
+Codec Access
+============
+
+To access codec, use snd_codec_read() and snd_codec_write().
+snd_hda_param_read() is for reading parameters.
+For writing a sequence of verbs, use snd_hda_sequence_write().
+
+To retrieve the number of sub nodes connected to the given node, use
+snd_hda_get_sub_nodes().  The connection list can be obtained via
+snd_hda_get_connections() call.
+
+When an unsolicited event happens, pass the event via
+snd_hda_queue_unsol_event() so that the codec routines will process it
+later.
+
+
+(Mixer) Controls
+================
+
+To create mixer controls of all codecs, call
+snd_hda_build_controls().  It then builds the mixers and does
+initialization stuff on each codec.
+
+
+PCM Stuff
+=========
+
+snd_hda_build_pcms() gives the necessary information to create PCM
+streams.  When it's called, each codec belonging to the bus stores 
+codec->num_pcms and codec->pcm_info fields.  The num_pcms indicates
+the number of elements in pcm_info array.  The card driver is supposed
+to traverse the codec linked list, read the pcm information in
+pcm_info array, and build pcm instances according to them. 
+
+The pcm_info array contains the following record:
+
+/* PCM information for each substream */
+struct hda_pcm_stream {
+	unsigned int substreams;	/* number of substreams, 0 = not exist */
+	unsigned int channels_min;	/* min. number of channels */
+	unsigned int channels_max;	/* max. number of channels */
+	hda_nid_t nid;	/* default NID to query rates/formats/bps, or set up */
+	u32 rates;	/* supported rates */
+	u64 formats;	/* supported formats (SNDRV_PCM_FMTBIT_) */
+	unsigned int maxbps;	/* supported max. bit per sample */
+	struct hda_pcm_ops ops;
+};
+
+/* for PCM creation */
+struct hda_pcm {
+	char *name;
+	struct hda_pcm_stream stream[2];
+};
+
+The name can be passed to snd_pcm_new().  The stream field contains
+the information  for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and
+capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions.  The card driver
+should pass substreams to snd_pcm_new() for the number of substreams
+to create.
+
+The channels_min, channels_max, rates and formats should be copied to
+runtime->hw record.  They and maxbps fields are used also to compute
+the format value for the HDA codec and controller.  Call
+snd_hda_calc_stream_format() to get the format value.
+
+The ops field contains the following callback functions:
+
+struct hda_pcm_ops {
+	int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		    snd_pcm_substream_t *substream);
+	int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		     snd_pcm_substream_t *substream);
+	int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       unsigned int stream_tag, unsigned int format,
+		       snd_pcm_substream_t *substream);
+	int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       snd_pcm_substream_t *substream);
+};
+
+All are non-NULL, so you can call them safely without NULL check.
+
+The open callback should be called in PCM open after runtime->hw is
+set up.  It may override some setting and constraints additionally.
+Similarly, the close callback should be called in the PCM close.
+
+The prepare callback should be called in PCM prepare.  This will set
+up the codec chip properly for the operation.  The cleanup should be
+called in hw_free to clean up the configuration.
+
+The caller should check the return value, at least for open and
+prepare callbacks.  When a negative value is returned, some error
+occurred.
+
+
+Proc Files
+==========
+
+Each codec dumps the widget node information in
+/proc/asound/card*/codec#* file.  This information would be really
+helpful for debugging.  Please provide its contents together with the
+bug report.
+
+
+Power Management
+================
+
+It's simple:
+Call snd_hda_suspend() in the PM suspend callback.
+Call snd_hda_resume() in the PM resume callback.
+
+
+Codec Preset (Patch)
+====================
+
+To set up and handle the codec functionality fully, each codec may
+have a codec preset (patch).  It's defined in struct hda_codec_preset:
+
+	struct hda_codec_preset {
+		unsigned int id;
+		unsigned int mask;
+		unsigned int subs;
+		unsigned int subs_mask;
+		unsigned int rev;
+		const char *name;
+		int (*patch)(struct hda_codec *codec);
+	};
+
+When the codec id and codec subsystem id match with the given id and
+subs fields bitwise (with bitmask mask and subs_mask), the callback
+patch is called.  The patch callback should initialize the codec and
+set the codec->patch_ops field.  This is defined as below:
+
+	struct hda_codec_ops {
+		int (*build_controls)(struct hda_codec *codec);
+		int (*build_pcms)(struct hda_codec *codec);
+		int (*init)(struct hda_codec *codec);
+		void (*free)(struct hda_codec *codec);
+		void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+	#ifdef CONFIG_PM
+		int (*suspend)(struct hda_codec *codec, pm_message_t state);
+		int (*resume)(struct hda_codec *codec);
+	#endif
+	};
+
+The build_controls callback is called from snd_hda_build_controls().
+Similarly, the build_pcms callback is called from
+snd_hda_build_pcms().  The init callback is called after
+build_controls to initialize the hardware.
+The free callback is called as a destructor.
+
+The unsol_event callback is called when an unsolicited event is
+received.
+
+The suspend and resume callbacks are for power management.
+
+Each entry can be NULL if not necessary to be called.
+
+
+Generic Parser
+==============
+
+When the device doesn't match with any given presets, the widgets are
+parsed via th generic parser (hda_generic.c).  Its support is
+limited: no multi-channel support, for example.
+
+
+Digital I/O
+===========
+
+Call snd_hda_create_spdif_out_ctls() from the patch to create controls
+related with SPDIF out.  In the patch resume callback, call
+snd_hda_resume_spdif().
+
+
+Helper Functions
+================
+
+snd_hda_get_codec_name() stores the codec name on the given string.
+
+snd_hda_check_board_config() can be used to obtain the configuration
+information matching with the device.  Define the table with struct
+hda_board_config entries (zero-terminated), and pass it to the
+function.  The function checks the modelname given as a module
+parameter, and PCI subsystem IDs.  If the matching entry is found, it
+returns the config field value.
+
+snd_hda_add_new_ctls() can be used to create and add control entries.
+Pass the zero-terminated array of snd_kcontrol_new_t.  The same array
+can be passed to snd_hda_resume_ctls() for resume.
+Note that this will call control->put callback of these entries.  So,
+put callback should check codec->in_resume and force to restore the
+given value if it's non-zero even if the value is identical with the
+cached value.
+
+Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be
+used for the entry of snd_kcontrol_new_t.
+
+The input MUX helper callbacks for such a control are provided, too:
+snd_hda_input_mux_info() and snd_hda_input_mux_put().  See
+patch_realtek.c for example.
diff --git a/Documentation/sound/alsa/serial-u16550.txt b/Documentation/sound/alsa/serial-u16550.txt
--- a/Documentation/sound/alsa/serial-u16550.txt
+++ b/Documentation/sound/alsa/serial-u16550.txt
@@ -23,12 +23,12 @@ send the F5 NN command sequence at all; 
 
 Usage example for simple serial converter:
 
-	/sbin/setserial /dev/ttyS0 none
+	/sbin/setserial /dev/ttyS0 uart none
 	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 speed=115200
 
 Usage example for Roland SoundCanvas with 4 MIDI ports:
 
-	/sbin/setserial /dev/ttyS0 none
+	/sbin/setserial /dev/ttyS0 uart none
 	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 outs=4
 
 In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the outs
@@ -38,7 +38,7 @@ parameter to match (A=19200, B=9600).
 
 Usage example for MS-124T, with A-B switch in A position:
 
-	/sbin/setserial /dev/ttyS0 none
+	/sbin/setserial /dev/ttyS0 uart none
 	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=1 \
 			speed=19200
 
@@ -48,7 +48,7 @@ the same data to all four MIDI Out conne
 
 Usage example for S/A mode:
 
-	/sbin/setserial /dev/ttyS0 none
+	/sbin/setserial /dev/ttyS0 uart none
 	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=2
 
 In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI substreams;
@@ -64,7 +64,7 @@ one byte every 320 us per port.
 
 Usage example for M/B mode:
 
-	/sbin/setserial /dev/ttyS0 none
+	/sbin/setserial /dev/ttyS0 uart none
 	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=3
 
 The MS-124W hardware's M/A mode is currently not supported. This mode allows
diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt
--- a/Documentation/spinlocks.txt
+++ b/Documentation/spinlocks.txt
@@ -1,3 +1,29 @@
+UPDATE March 21 2005 Amit Gud <gud@eth.net>
+
+Macros SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated and will be
+removed soon. So for any new code dynamic initialization should be used:
+
+   spinlock_t xxx_lock;
+   rwlock_t xxx_rw_lock;
+
+   static int __init xxx_init(void)
+   {
+   	spin_lock_init(&xxx_lock);
+	rw_lock_init(&xxx_rw_lock);
+	...
+   }
+
+   module_init(xxx_init);
+
+Reasons for deprecation
+  - it hurts automatic lock validators
+  - it becomes intrusive for the realtime preemption patches
+
+Following discussion is still valid, however, with the dynamic initialization
+of spinlocks instead of static.
+
+-----------------------
+
 On Fri, 2 Jan 1998, Doug Ledford wrote:
 > 
 > I'm working on making the aic7xxx driver more SMP friendly (as well as
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -10,13 +10,32 @@ regardless of whatever else it is doing,
 *  How do I enable the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
-configuring the kernel. When running on a kernel with SysRq compiled in, it
-may be DISABLED at run-time using following command:
-
-        echo "0" > /proc/sys/kernel/sysrq
-
-Note that previous versions disabled sysrq by default, and you were required
-to specifically enable it at run-time. That is not the case any longer.
+configuring the kernel. When running a kernel with SysRq compiled in,
+/proc/sys/kernel/sysrq controls the functions allowed to be invoked via
+the SysRq key. By default the file contains 1 which means that every
+possible SysRq request is allowed (in older versions SysRq was disabled
+by default, and you were required to specifically enable it at run-time
+but this is not the case any more). Here is the list of possible values
+in /proc/sys/kernel/sysrq:
+   0 - disable sysrq completely
+   1 - enable all functions of sysrq
+  >1 - bitmask of allowed sysrq functions (see below for detailed function
+       description):
+          2 - enable control of console logging level
+          4 - enable control of keyboard (SAK, unraw)
+          8 - enable debugging dumps of processes etc.
+         16 - enable sync command
+         32 - enable remount read-only
+         64 - enable signalling of processes (term, kill, oom-kill)
+        128 - allow reboot/poweroff
+        256 - allow nicing of all RT tasks
+
+You can set the value in the file by the following command:
+    echo "number" >/proc/sys/kernel/sysrq
+
+Note that the value of /proc/sys/kernel/sysrq influences only the invocation
+via a keyboard. Invocation of any operation via /proc/sysrq-trigger is always
+allowed.
 
 *  How do I use the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -73,6 +92,8 @@ On all -  write a character to /proc/sys
           it so that only emergency messages like PANICs or OOPSes would
           make it to your console.)
 
+'f'	- Will call oom_kill to kill a memory hog process
+
 'e'     - Send a SIGTERM to all processes, except for init.
 
 'i'     - Send a SIGKILL to all processes, except for init.
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -93,6 +93,11 @@ write_wakeup()	-	May be called at any po
 			ldisc must be careful about setting order and to
 			handle unexpected calls. Must not sleep.
 
+			The driver is forbidden from calling this directly
+			from the ->write call from the ldisc as the ldisc
+			is permitted to call the driver write method from
+			this function. In such a situation defer it.
+
 
 Locking
 
diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
--- a/Documentation/usb/error-codes.txt
+++ b/Documentation/usb/error-codes.txt
@@ -23,6 +23,9 @@ USB-specific:
 
 -ENODEV		specified USB-device or bus doesn't exist
 
+-ENOENT		specified interface or endpoint does not exist or
+		is not enabled
+
 -ENXIO		host controller driver does not support queuing of this type
 		of urb.  (treat as a host controller bug.)
 
@@ -88,13 +91,19 @@ one or more packets could finish before 
 			   prescribed bus turn-around time
 			c) unknown USB error 
 
-			In cases b) and c) either -EPROTO or -EILSEQ
-			may be returned.  Note that often the controller
-			hardware does not distinguish among cases a),
-			b), and c), so a driver cannot tell whether
-			there was a protocol error, a failure to respond
-			(often caused by device disconnect), or some
-			other fault.
+			Note that often the controller hardware does not
+			distinguish among cases a), b), and c), so a
+			driver cannot tell whether there was a protocol
+			error, a failure to respond (often caused by
+			device disconnect), or some other fault.
+
+-ETIMEDOUT (**)		No response packet received within the prescribed
+			bus turn-around time.  This error may instead be
+			reported as -EPROTO or -EILSEQ.
+
+			Note that the synchronous USB message functions
+			also use this code to indicate timeout expired
+			before the transfer completed.
 
 -EPIPE (**)		Endpoint stalled.  For non-control endpoints,
 			reset this status with usb_clear_halt().
@@ -152,4 +161,7 @@ usb_register():
 usb_get_*/usb_set_*():
 usb_control_msg():
 usb_bulk_msg():
--ETIMEDOUT		timeout expired before the transfer completed
+-ETIMEDOUT		Timeout expired before the transfer completed.
+			In the future this code may change to -ETIME,
+			whose definition is a closer match to this sort
+			of error.
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -210,8 +210,8 @@ There are other four entries in the dire
 SN9C10x bridge, while the other two control the sensor chip. "reg" and
 "i2c_reg" hold the values of the current register index where the following
 reading/writing operations are addressed at through "val" and "i2c_val". Their
-use is not intended for end-users. Note that "i2c_reg" and "i2c_val" won't be
-created if the sensor does not actually support the standard I2C protocol or
+use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not
+be created if the sensor does not actually support the standard I2C protocol or
 its registers are not 8-bit long. Also, remember that you must be logged in as
 root before writing to them.
 
@@ -341,15 +341,8 @@ TAS5130D1B  Taiwan Advanced Sensor Corpo
 All the available control settings of each image sensor are supported through
 the V4L2 interface.
 
-If you think your camera is based on the above hardware and is not actually
-listed in the above table, you may try to add the specific USB VendorID and
-ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
-then compile, load the module again and look at the kernel output.
-If this works, please send an email to the author reporting the kernel
-messages, so that a new entry in the list of supported devices can be added.
-
 Donations of new models for further testing and support would be much
-appreciated. Non-available hardware won't be supported by the author of this
+appreciated. Non-available hardware will not be supported by the author of this
 driver.
 
 
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/usb/usbmon.txt
@@ -0,0 +1,156 @@
+* Introduction
+
+The name "usbmon" in lowercase refers to a facility in kernel which is
+used to collect traces of I/O on the USB bus. This function is analogous
+to a packet socket used by network monitoring tools such as tcpdump(1)
+or Ethereal. Similarly, it is expected that a tool such as usbdump or
+USBMon (with uppercase letters) is used to examine raw traces produced
+by usbmon.
+
+The usbmon reports requests made by peripheral-specific drivers to Host
+Controller Drivers (HCD). So, if HCD is buggy, the traces reported by
+usbmon may not correspond to bus transactions precisely. This is the same
+situation as with tcpdump.
+
+* How to use usbmon to collect raw text traces
+
+Unlike the packet socket, usbmon has an interface which provides traces
+in a text format. This is used for two purposes. First, it serves as a
+common trace exchange format for tools while most sophisticated formats
+are finalized. Second, humans can read it in case tools are not available.
+
+To collect a raw text trace, execute following steps.
+
+1. Prepare
+
+Mount debugfs (it has to be enabled in your kernel configuration), and
+load the usbmon module (if built as module). The second step is skipped
+if usbmon is built into the kernel.
+
+# mount -t debugfs none_debugs /sys/kernel/debug
+# modprobe usbmon
+
+Verify that bus sockets are present.
+
+[root@lembas zaitcev]# ls /sys/kernel/debug/usbmon
+1s  1t  2s  2t  3s  3t  4s  4t
+[root@lembas zaitcev]#
+
+# ls /sys/kernel
+
+2. Find which bus connects to the desired device
+
+Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
+the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
+The T-line will have a bus number. Example:
+
+T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
+D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0557 ProdID=2004 Rev= 1.00
+S:  Manufacturer=ATEN
+S:  Product=UC100KM V2.00
+
+Bus=03 means it's bus 3.
+
+3. Start 'cat'
+
+# cat /sys/kernel/debug/usbmon/3t > /tmp/1.mon.out
+
+This process will be reading until killed. Naturally, the output can be
+redirected to a desirable location. This is preferred, because it is going
+to be quite long.
+
+4. Perform the desired operation on the USB bus
+
+This is where you do something that creates the traffic: plug in a flash key,
+copy files, control a webcam, etc.
+
+5. Kill cat
+
+Usually it's done with a keyboard interrupt (Control-C).
+
+At this point the output file (/tmp/1.mon.out in this example) can be saved,
+sent by e-mail, or inspected with a text editor. In the last case make sure
+that the file size is not excessive for your favourite editor.
+
+* Raw text data format
+
+The '0t' type data consists of a stream of events, such as URB submission,
+URB callback, submission error. Every event is a text line, which consists
+of whitespace separated words. The number of position of words may depend
+on the event type, but there is a set of words, common for all types.
+
+Here is the list of words, from left to right:
+- URB Tag. This is used to identify URBs is normally a kernel mode address
+ of the URB structure in hexadecimal.
+- Timestamp in microseconds, a decimal number. The timestamp's resolution
+  depends on available clock, and so it can be much worse than a microsecond
+  (if the implementation uses jiffies, for example).
+- Event Type. This type refers to the format of the event, not URB type.
+  Available types are: S - submission, C - callback, E - submission error.
+- "Pipe". The pipe concept is deprecated. This is a composite word, used to
+  be derived from information in pipes. It consists of three fields, separated
+  by colons: URB type and direction, Device address, Endpoint number.
+  Type and direction are encoded with two bytes in the following manner:
+    Ci Co   Control input and output
+    Zi Zo   Isochronous input and output
+    Ii Io   Interrupt input and output
+    Bi Bo   Bulk input and output
+  Device address and Endpoint number are decimal numbers with leading zeroes
+  or 3 and 2 positions, correspondingly.
+- URB Status. This field makes no sense for submissions, but is present
+  to help scripts with parsing. In error case, it contains the error code.
+- Data Length. This is the actual length in the URB.
+- Data tag. The usbmon may not always capture data, even if length is nonzero.
+  Only if tag is '=', the data words are present.
+- Data words follow, in big endian hexadecimal format. Notice that they are
+  not machine words, but really just a byte stream split into words to make
+  it easier to read. Thus, the last word may contain from one to four bytes.
+  The length of collected data is limited and can be less than the data length
+  report in Data Length word.
+
+Here is an example of code to read the data stream in a well known programming
+language:
+
+class ParsedLine {
+	int data_len;		/* Available length of data */
+	byte data[];
+
+	void parseData(StringTokenizer st) {
+		int availwords = st.countTokens();
+		data = new byte[availwords * 4];
+		data_len = 0;
+		while (st.hasMoreTokens()) {
+			String data_str = st.nextToken();
+			int len = data_str.length() / 2;
+			int i;
+			for (i = 0; i < len; i++) {
+				data[data_len] = Byte.parseByte(
+				    data_str.substring(i*2, i*2 + 2),
+				    16);
+				data_len++;
+			}
+		}
+	}
+}
+
+This format is obviously deficient. For example, the setup packet for control
+transfers is not delivered. This will change in the future.
+
+Examples:
+
+An input control transfer to get a port status:
+
+d74ff9a0 2640288196 S Ci:001:00 -115 4 <
+d74ff9a0 2640288202 C Ci:001:00 0 4 = 01010100
+
+An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
+to a storage device at address 5:
+
+dd65f0e8 4128379752 S Bo:005:02 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
+dd65f0e8 4128379808 C Bo:005:02 0 31 >
+
+* Raw binary format and API
+
+TBD
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -6,23 +6,23 @@
   5 -> SKNet Monster TV                         [1131:4e85]
   6 -> Tevion MD 9717                          
   7 -> KNC One TV-Station RDS / Typhoon TV Tuner RDS [1131:fe01,1894:fe01]
-  8 -> KNC One TV-Station DVR                   [1894:a006]
-  9 -> Terratec Cinergy 400 TV                  [153B:1142]
- 10 -> Medion 5044
- 11 -> Kworld/KuroutoShikou SAA7130-TVPCI
- 12 -> Terratec Cinergy 600 TV                  [153B:1143]
- 13 -> Medion 7134                              [16be:0003]
- 14 -> Typhoon TV+Radio 90031
- 15 -> ELSA EX-VISION 300TV                     [1048:226b]
- 16 -> ELSA EX-VISION 500TV                     [1048:226b]
- 17 -> ASUS TV-FM 7134                          [1043:4842,1043:4830,1043:4840]
- 18 -> AOPEN VA1000 POWER                       [1131:7133]
- 19 -> 10MOONS PCI TV CAPTURE CARD              [1131:2001]
- 20 -> BMK MPEX No Tuner
- 21 -> Compro VideoMate TV                      [185b:c100]
- 22 -> Matrox CronosPlus                        [102B:48d0]
- 23 -> Medion 2819/ AverMedia M156              [1461:a70b,1461:2115]
- 24 -> BMK MPEX Tuner
+  8 -> Terratec Cinergy 400 TV                  [153B:1142]
+  9 -> Medion 5044
+ 10 -> Kworld/KuroutoShikou SAA7130-TVPCI
+ 11 -> Terratec Cinergy 600 TV                  [153B:1143]
+ 12 -> Medion 7134                              [16be:0003]
+ 13 -> Typhoon TV+Radio 90031
+ 14 -> ELSA EX-VISION 300TV                     [1048:226b]
+ 15 -> ELSA EX-VISION 500TV                     [1048:226b]
+ 16 -> ASUS TV-FM 7134                          [1043:4842,1043:4830,1043:4840]
+ 17 -> AOPEN VA1000 POWER                       [1131:7133]
+ 18 -> BMK MPEX No Tuner
+ 19 -> Compro VideoMate TV                      [185b:c100]
+ 20 -> Matrox CronosPlus                        [102B:48d0]
+ 21 -> 10MOONS PCI TV CAPTURE CARD              [1131:2001]
+ 22 -> Medion 2819/ AverMedia M156              [1461:a70b,1461:2115]
+ 23 -> BMK MPEX Tuner
+ 24 -> KNC One TV-Station DVR                   [1894:a006]
  25 -> ASUS TV-FM 7133                          [1043:4843]
  26 -> Pinnacle PCTV Stereo (saa7134)           [11bd:002b]
  27 -> Manli MuchTV M-TV002
@@ -32,3 +32,4 @@
  31 -> Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) [1019:4cb5]
  32 -> AVACS SmartTV
  33 -> AVerMedia DVD EZMaker                    [1461:10ff]
+ 34 -> LifeView FlyTV Platinum33 mini           [5168:0212]
diff --git a/Documentation/video4linux/README.cx88 b/Documentation/video4linux/README.cx88
--- a/Documentation/video4linux/README.cx88
+++ b/Documentation/video4linux/README.cx88
@@ -11,9 +11,6 @@ current status
 video
 	- Basically works.
 	- Some minor image quality glitches.
-	- Red and blue are swapped sometimes for not-yet known
-	  reasons (seems to depend on the image size, try to resize
-	  your tv app window as workaround ...).
 	- For now only capture, overlay support isn't completed yet.
 
 audio
diff --git a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
--- a/Documentation/video4linux/bttv/Cards
+++ b/Documentation/video4linux/bttv/Cards
@@ -1,9 +1,9 @@
 
 Gunther Mayer's bttv card gallery (graphical version of this text file :-)
-is available at: http://mayerg.gmxhome.de/bttv/bttv-gallery.html
+is available at: http://www.bttv-gallery.de/
 
 
-Suppported cards:
+Supported cards:
 Bt848/Bt848a/Bt849/Bt878/Bt879 cards
 ------------------------------------
 
@@ -166,6 +166,9 @@ Lifeview Flyvideo Series:
 	        or Flyvideo 3000 (SAA7134) w/Stereo TV
 		   These exist in variations w/FM and w/Remote sometimes denoted
 		   by suffixes "FM" and "R".
+  3) You have a laptop (miniPCI card):
+      Product    = FlyTV Platinum Mini
+      Model/Chip = LR212/saa7135
 
       Lifeview.com.tw states (Feb. 2002):
       "The FlyVideo2000 and FlyVideo2000s product name have renamed to FlyVideo98."
diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
--- a/Documentation/video4linux/bttv/README
+++ b/Documentation/video4linux/bttv/README
@@ -22,7 +22,7 @@ very likely specified the wrong (or no) 
 cards is in CARDLIST.bttv
 
 If bttv takes very long to load (happens sometimes with the cheap
-cards which have no tuner), try adding this to your modprobe.conf:
+cards which have no tuner), try adding this to your modules.conf:
 	options i2c-algo-bit bit_test=1
 
 For the WinTV/PVR you need one firmware file from the driver CD:
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -25,6 +25,9 @@ APICs
 
    noapictimer	 Don't set up the APIC timer
 
+   no_timer_check Don't check the IO-APIC timer. This can work around
+		 problems with incorrect timer initialization on some boards.
+
 Early Console
 
    syntax: earlyprintk=vga
diff --git a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -73,21 +73,21 @@ S: Status, one of the following:
 3C359 NETWORK DRIVER
 P:	Mike Phillips
 M:	mikep@linuxtr.net
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
 S:	Maintained
 
 3C505 NETWORK DRIVER
 P:	Philip Blundell
-M:	Philip.Blundell@pobox.com
-L:	linux-net@vger.kernel.org
+M:	philb@gnu.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 3CR990 NETWORK DRIVER
 P:	David Dillow
 M:	dave@thedillows.org
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 3W-XXXX ATA-RAID CONTROLLER DRIVER
@@ -130,7 +130,7 @@ S:	Maintained
 8169 10/100/1000 GIGABIT ETHERNET DRIVER
 P:	Francois Romieu
 M:	romieu@fr.zoreil.com
-L:	netdev@oss.sgi.com
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
@@ -143,7 +143,7 @@ S:	Maintained
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
 P:	Paul Gortmaker
 M:	p_gortmaker@yahoo.com
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 A2232 SERIAL BOARD DRIVER
@@ -155,7 +155,7 @@ S:	Maintained
 
 AIO
 P:	Benjamin LaHaise
-M:	bcrl@redhat.com
+M:	bcrl@kvack.org
 L:	linux-aio@kvack.org
 S:	Supported
 
@@ -172,14 +172,6 @@ L:	linux-sound@vger.kernel.org
 W:	http://www.stud.uni-karlsruhe.de/~uh1b/
 S:	Maintained
 
-ACP/MWAVE MODEM
-P:	Paul B Schroeder
-M:	paulsch@us.ibm.com
-P:	Mike Sullivan
-M:	sullivam@us.ibm.com
-W:	http://www.ibm.com/linux/ltc/
-S:	Supported
-
 AACRAID SCSI RAID DRIVER
 P:	Adaptec OEM Raid Solutions
 L:	linux-scsi@vger.kernel.org
@@ -247,6 +239,12 @@ L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.linux-usb.org/SpeedTouch/
 S:	Maintained
 
+ALI1563 I2C DRIVER
+P:	Rudolf Marek
+M:	r.marek@sh.cvut.cz
+L:	sensors@stimpy.netroedge.com
+S:	Maintained
+
 ALPHA PORT
 P:	Richard Henderson
 M:	rth@twiddle.net
@@ -334,7 +332,7 @@ S:	Maintained
 
 ARPD SUPPORT
 P:	Jonathan Layes
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 ASUS ACPI EXTRAS DRIVER
@@ -457,6 +455,11 @@ P:	Marcel Holtmann
 M:	marcel@holtmann.org
 S:	Maintained
 
+BLUETOOTH HCI BPA10X DRIVER
+P:	Marcel Holtmann
+M:	marcel@holtmann.org
+S:	Maintained
+
 BLUETOOTH HCI BFUSB DRIVER
 P:	Marcel Holtmann
 M:	marcel@holtmann.org
@@ -501,7 +504,7 @@ P:	Gerd Knorr
 M:	kraxel@bytesex.org
 L:	video4linux-list@redhat.com
 W:	http://bytesex.org/bttv/
-S:	Maintained
+S:	Orphan
 
 BUSLOGIC SCSI DRIVER
 P:	Leonard N. Zubkoff
@@ -596,12 +599,11 @@ W:	http://developer.axis.com
 S:	Maintained
 
 CRYPTO API
-P:	James Morris
-M:	jmorris@redhat.com
+P:	Herbert Xu
+M:	herbert@gondor.apana.org.au
 P:	David S. Miller
 M:	davem@davemloft.net
-W	http://samba.org/~jamesm/crypto/
-L:	linux-kernel@vger.kernel.org
+L:	linux-crypto@vger.kernel.org
 S:	Maintained
 
 CYBERPRO FB DRIVER
@@ -704,17 +706,10 @@ S:	Orphaned
 
 DIGI RIGHTSWITCH NETWORK DRIVER
 P:	Rick Richardson
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 W:	http://www.digi.com
 S:	Orphaned
 
-DIGIBOARD PC/XE AND PC/XI DRIVER
-P:	Christoph Lameter
-M:	christoph@lameter.com
-W:	http://www.digi.com
-L:	digilnux@digi.com
-S:	Obsolete
-
 DIRECTORY NOTIFICATION
 P:	Stephen Rothwell
 M:	sfr@canb.auug.org.au
@@ -754,8 +749,10 @@ L:	linux-kernel@vger.kernel.org
 S:	Supported
 
 DRM DRIVERS
+P:	David Airlie
+M:	airlied@linux.ie
 L:	dri-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 DSCC4 DRIVER
 P:	François Romieu
@@ -814,8 +811,8 @@ S:	Maintained
 
 ETHEREXPRESS-16 NETWORK DRIVER
 P:	Philip Blundell
-M:	Philip.Blundell@pobox.com
-L:	linux-net@vger.kernel.org
+M:	philb@gnu.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 ETHERNET BRIDGE
@@ -878,7 +875,7 @@ S:	Maintained
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
 P:	Mike McLagan
 M:	mike.mclagan@linux.org
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 FREEVXFS FILESYSTEM
@@ -910,10 +907,17 @@ L:	linux-scsi@vger.kernel.org
 W:	http://www.icp-vortex.com/
 S:	Supported
 
-GENERIC HDLC DRIVER, N2 AND C101 DRIVERS
+GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
 P:	Krzysztof Halasa
 M:	khc@pm.waw.pl
-W:	http://hq.pm.waw.pl/hdlc/
+W:	http://www.kernel.org/pub/linux/utils/net/hdlc/
+S:	Maintained
+
+HARMONY SOUND DRIVER
+P:	Kyle McMartin
+M:	kyle@parisc-linux.org
+W:	http://www.parisc-linux.org/~kyle/harmony/
+L:	parisc-linux@lists.parisc-linux.org
 S:	Maintained
 
 HAYES ESP SERIAL DRIVER
@@ -978,11 +982,6 @@ M:	mikulas@artax.karlin.mff.cuni.cz
 W:	http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 S:	Maintained
 
-HPUSBSCSI
-P:	Oliver Neukum
-M:	oliver@neukum.name
-S:	Maintained
-
 HUGETLB FILESYSTEM
 P:	William Irwin
 M:	wli@holomorphy.com
@@ -991,8 +990,8 @@ S:	Maintained
 I2C AND SENSORS DRIVERS
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
-P:	Philip Edelbrock
-M:	phil@netroedge.com
+P:	Jean Delvare
+M:	khali@linux-fr.org
 L:	sensors@stimpy.netroedge.com
 W:	http://www.lm-sensors.nu/
 S:	Maintained
@@ -1030,8 +1029,8 @@ W:	http://www.ia64-linux.org/
 S:	Maintained
 
 SN-IA64 (Itanium) SUB-PLATFORM
-P:	Jesse Barnes
-M:	jbarnes@sgi.com
+P:	Greg Edwards
+M:	edwardsg@sgi.com
 L:	linux-altix@sgi.com
 L:	linux-ia64@vger.kernel.org
 W:	http://www.sgi.com/altix
@@ -1082,9 +1081,21 @@ M:	Gadi Oxman <gadio@netvision.net.il>
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+IEEE 1394 ETHERNET (eth1394)
+L:	linux1394-devel@lists.sourceforge.net
+W:	http://www.linux1394.org/
+S:	Orphan
+
+IEEE 1394 SBP2
+L:	linux1394-devel@lists.sourceforge.net
+W:	http://www.linux1394.org/
+S:	Orphan
+
 IEEE 1394 SUBSYSTEM
 P:	Ben Collins
 M:	bcollins@debian.org
+P:	Jody McIntyre
+M:	scjody@steamballoon.com
 L:	linux1394-devel@lists.sourceforge.net
 W:	http://www.linux1394.org/
 S:	Maintained
@@ -1092,13 +1103,15 @@ S:	Maintained
 IEEE 1394 OHCI DRIVER
 P:	Ben Collins
 M:	bcollins@debian.org
+P:	Jody McIntyre
+M:	scjody@steamballoon.com
 L:	linux1394-devel@lists.sourceforge.net
 W:	http://www.linux1394.org/
 S:	Maintained
 
 IEEE 1394 PCILYNX DRIVER
-P:	Andreas Bombe
-M:	andreas.bombe@munich.netsurf.de
+P:	Jody McIntyre
+M:	scjody@steamballoon.com
 L:	linux1394-devel@lists.sourceforge.net
 W:	http://www.linux1394.org/
 S:	Maintained
@@ -1106,6 +1119,8 @@ S:	Maintained
 IEEE 1394 RAW I/O DRIVER
 P:	Ben Collins
 M:	bcollins@debian.org
+P:	Dan Dennedy
+M:	dan@dennedy.org
 L:	linux1394-devel@lists.sourceforge.net
 W:	http://www.linux1394.org/
 S:	Maintained
@@ -1200,7 +1215,7 @@ S:	Maintained
 IPX NETWORK LAYER
 P:	Arnaldo Carvalho de Melo
 M:	acme@conectiva.com.br
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 IRDA SUBSYSTEM
@@ -1247,8 +1262,8 @@ 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/jfs/
+L:	jfs-discussion@lists.sourceforge.net
+W:	http://jfs.sourceforge.net/
 S:	Supported
 
 KCONFIG
@@ -1372,7 +1387,7 @@ W:	http://www.penguinppc.org/
 L:	linuxppc-embedded@ozlabs.org
 S:	Maintained
 
-LINUX FOR POWERPC EMBEDDED PPC85XX
+LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
 P:     Kumar Gala
 M:     kumar.gala@freescale.com
 W:     http://www.penguinppc.org/
@@ -1467,7 +1482,7 @@ MARVELL MV64340 ETHERNET DRIVER
 P:	Manish Lachwani
 M:	Manish_Lachwani@pmc-sierra.com
 L:	linux-mips@linux-mips.org
-L:	netdev@oss.sgi.com
+L:	netdev@vger.kernel.org
 S:	Supported
 
 MATROX FRAMEBUFFER DRIVER
@@ -1577,13 +1592,13 @@ P:	Andrew Morton
 M:	akpm@osdl.org
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 NETWORKING [GENERAL]
 P:	Networking Team
-M:	netdev@oss.sgi.com
-L:	linux-net@vger.kernel.org
+M:	netdev@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 NETWORKING [IPv4/IPv6]
@@ -1599,7 +1614,7 @@ P:	Hideaki YOSHIFUJI
 M:	yoshfuji@linux-ipv6.org
 P:	Patrick McHardy
 M:	kaber@coreworks.de
-L:	netdev@oss.sgi.com
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 IPVS
@@ -1619,7 +1634,7 @@ NI5010 NETWORK DRIVER
 P:	Jan-Pascal van Best and Andreas Mohr
 M:	Jan-Pascal van Best <jvbest@qv3pluto.leidenuniv.nl>
 M:	Andreas Mohr <100.30936@germany.net>
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 NINJA SCSI-3 / NINJA SCSI-32Bi (16bit/CardBus) PCMCIA SCSI HOST ADAPTER DRIVER
@@ -1661,7 +1676,7 @@ P:	Peter De Shrijver
 M:	p2@ace.ulyssis.student.kuleuven.ac.be
 P:	Mike Phillips
 M:	mikep@linuxtr.net 
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
 S:	Maintained
@@ -1690,18 +1705,20 @@ P:	Pavel Roskin
 M:	proski@gnu.org
 P:	David Gibson
 M:	hermes@gibson.dropbear.id.au
-W:	http://www.ozlabs.org/people/dgibson/dldwd
+L:	orinoco-users@lists.sourceforge.net
+L:	orinoco-devel@lists.sourceforge.net
+W:	http://www.nongnu.org/orinoco/
 S:	Maintained
 
 PARALLEL PORT SUPPORT
 P:	Phil Blundell
-M:	Philip.Blundell@pobox.com
+M:	philb@gnu.org
 P:	Tim Waugh
 M:	tim@cyberelk.net
 P:	David Campbell
 M:	campbell@torque.net
 P:	Andrea Arcangeli
-M:	andrea@e-mind.com
+M:	andrea@suse.de
 L:	linux-parport@lists.infradead.org
 W:	http://people.redhat.com/twaugh/parport/
 S:	Maintained
@@ -1766,7 +1783,7 @@ S:	Unmaintained
 PCNET32 NETWORK DRIVER
 P:	Thomas Bogendörfer
 M:	tsbogend@alpha.franken.de
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 PHRAM MTD DRIVER
@@ -1778,7 +1795,7 @@ S:	Maintained
 POSIX CLOCKS and TIMERS
 P:	George Anzinger
 M:	george@mvista.com
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Supported
 
 PNP SUPPORT
@@ -1813,7 +1830,7 @@ S:	Supported
 PRISM54 WIRELESS DRIVER
 P:	Prism54 Development Team
 M:	prism54-private@prism54.org
-L:	netdev@oss.sgi.com
+L:	netdev@vger.kernel.org
 W:	http://prism54.org
 S:	Maintained
 
@@ -1843,14 +1860,14 @@ W:	http://www.alarsen.net/linux/qnx4fs/
 S:	Maintained
 
 RADEON FRAMEBUFFER DISPLAY DRIVER
-P:	Ani Joshi
-M:	ajoshi@shell.unixbox.com
+P:	Benjamin Herrenschmidt
+M:	benh@kernel.crashing.org
 L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Maintained
 
 RAGE128 FRAMEBUFFER DISPLAY DRIVER
-P:	Ani Joshi
-M:	ajoshi@shell.unixbox.com
+P:	Paul Mackerras
+M:	paulus@samba.org
 L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Maintained
 
@@ -1860,6 +1877,11 @@ M:	corey@world.std.com
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+RANDOM NUMBER DRIVER
+P:	Matt Mackall
+M:	mpm@selenic.com
+S:	Maintained
+
 REAL TIME CLOCK DRIVER
 P:	Paul Gortmaker
 M:	p_gortmaker@yahoo.com
@@ -1966,6 +1988,11 @@ M:	christer@weinigel.se
 W:	http://www.weinigel.se
 S:	Supported
 
+SECURITY CONTACT
+P:	Security Officers
+M:	security@kernel.org
+S:	Supported
+
 SELINUX SECURITY MODULE
 P:	Stephen Smalley
 M:	sds@epoch.ncsc.mil
@@ -2017,10 +2044,11 @@ W:	http://gyver.homeip.net/sis5513/index
 S:	Maintained
 
 SIS 900/7016 FAST ETHERNET DRIVER
-P:	Ollie Lho
-M:	ollie@sis.com.tw
-L:	linux-net@vger.kernel.org
-S:	Supported
+P:	Daniele Venzano
+M:	venza@brownhat.org
+W:	http://www.brownhat.org/sis900.html
+L:	netdev@vger.kernel.org
+S:	Maintained
 
 SIS FRAMEBUFFER DRIVER
 P:	Thomas Winischhofer
@@ -2028,6 +2056,12 @@ M:	thomas@winischhofer.net
 W:	http://www.winischhofer.net/linuxsisvga.shtml
 S:	Maintained	
 
+SIS USB2VGA DRIVER
+P:	Thomas Winischhofer
+M:	thomas@winischhofer.net
+W:	http://www.winischhofer.at/linuxsisusbvga.shtml
+S:	Maintained
+
 SMSC47M1 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
@@ -2072,7 +2106,7 @@ S:	Maintained
 SONIC NETWORK DRIVER
 P:	Thomas Bogendoerfer
 M:	tsbogend@alpha.franken.de
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 SONY VAIO CONTROL DEVICE DRIVER
@@ -2087,6 +2121,13 @@ M:	perex@suse.cz
 L:	alsa-devel@alsa-project.org
 S:	Maintained
 
+TPM DEVICE DRIVER
+P:	Kylene Hall
+M:	kjhall@us.ibm.com
+W:	http://tpmdd.sourceforge.net
+L:	tpmdd-devel@lists.sourceforge.net
+S:	Maintained
+
 UltraSPARC (sparc64):
 P:	David S. Miller
 M:	davem@davemloft.net
@@ -2122,7 +2163,7 @@ S:	Supported
 SPX NETWORK LAYER
 P:	Jay Schulist
 M:	jschlst@samba.org
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Supported
 
 SRM (Alpha) environment access
@@ -2162,9 +2203,10 @@ SUPERH64 (sh64)
 P:	Paul Mundt
 M:	lethal@linux-sh.org
 P:	Richard Curnow
-M:	richard.curnow@superh.com
+M:	rc@rc0.org.uk
 L:	linuxsh-shmedia-dev@lists.sourceforge.net
 W:	http://www.linux-sh.org
+W:	http://www.rc0.org.uk/sh64
 S:	Maintained
 
 SUN3/3X
@@ -2200,7 +2242,7 @@ S:	Maintained
 TOKEN-RING NETWORK DRIVER
 P:	Mike Phillips
 M:	mikep@linuxtr.net
-L:	linux-net@vger.kernel.org
+L:	netdev@vger.kernel.org
 L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
 S:	Maintained
@@ -2279,6 +2321,13 @@ L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB BLOCK DRIVER (UB ub)
+P:	Pete Zaitcev
+M:	zaitcev@redhat.com
+L:	linux-kernel@vger.kernel.org
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Supported
+
 USB BLUETOOTH TTY CONVERTER DRIVER
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
@@ -2376,6 +2425,12 @@ L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.chello.nl/~j.vreeken/se401/
 S:	Maintained
 
+USB SERIAL CYBERJACK DRIVER
+P:	Matthias Bruestle and Harald Welte
+M:	support@reiner-sct.com
+W:	http://www.reiner-sct.de/support/treiber_cyberjack.php
+S:	Maintained
+
 USB SERIAL DIGI ACCELEPORT DRIVER
 P:	Peter Berger and Al Borchers
 M:	pberger@brimson.com
@@ -2477,6 +2532,14 @@ L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.linux-projects.org
 S:	Maintained
 
+USB ZD1201 DRIVER
+P:	Jeroen Vreeken
+M:	pe1rxq@amsat.org
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://linux-lc100020.sourceforge.net
+S:	Maintained
+
 USER-MODE LINUX
 P:	Jeff Dike
 M:	jdike@karaya.com
@@ -2500,8 +2563,9 @@ P:	Roger Luethi
 M:	rl@hellgate.ch
 S:	Maintained
 
-UCLINUX
+UCLINUX (AND M68KNOMMU)
 P:	Greg Ungerer
+M:	gerg@uclinux.org
 M:	gerg@snapgear.com
 P:	David McCullough
 M:	davidm@snapgear.com
@@ -2534,7 +2598,8 @@ S:	Maintained
 VIDEO FOR LINUX
 P:	Gerd Knorr
 M:	kraxel@bytesex.org
-S:	Maintained
+L:	video4linux-list@redhat.com
+S:	Orphan
 
 W1 DALLAS'S 1-WIRE BUS
 P:	Evgeniy Polyakov
@@ -2612,11 +2677,11 @@ M:	jpr@f6fbb.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
-YMFPCI YAMAHA PCI SOUND
+YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
 P:	Pete Zaitcev
 M:	zaitcev@yahoo.com
 L:	linux-kernel@vger.kernel.org
-S:	Maintained
+S:	Obsolete
 
 Z8530 DRIVER FOR AX.25
 P:	Joerg Reuter
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 11
+SUBLEVEL = 12
 EXTRAVERSION =
 NAME=Woozy Numbat
 
@@ -18,7 +18,7 @@ MAKEFLAGS += --no-print-directory
 #
 # Most importantly: sub-Makefiles should only ever modify files in
 # their own directory. If in some directory we have a dependency on
-# a file in another dir (which doesn't happen often, but it's of
+# a file in another dir (which doesn't happen often, but it's often
 # unavoidable when linking the built-in.o targets which finally
 # turn into vmlinux), we will call a sub make in that other dir, and
 # after that we are sure that everything which is in that other dir
@@ -67,7 +67,7 @@ endif
 
 
 # kbuild supports saving output files in a separate directory.
-# To locate output files in a separate directory two syntax'es are supported.
+# To locate output files in a separate directory two syntaxes are supported.
 # In both cases the working directory must be the root of the kernel src.
 # 1) O=
 # Use "make O=dir/to/store/output/files/"
@@ -78,7 +78,8 @@ endif
 # export KBUILD_OUTPUT=dir/to/store/output/files/
 # make
 #
-# The O= assigment takes precedence over the KBUILD_OUTPUT environment variable.
+# The O= assignment takes precedence over the KBUILD_OUTPUT environment
+# variable.
 
 
 # KBUILD_SRC is set on invocation of make in OBJ directory
@@ -331,9 +332,7 @@ KALLSYMS	= scripts/kallsyms
 PERL		= perl
 CHECK		= sparse
 
-NOSTDINC_FLAGS  = -nostdinc -isystem $(shell $(CC) -print-file-name=include)
 CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__
-CHECKFLAGS     += $(NOSTDINC_FLAGS)
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
 AFLAGS_MODULE   = $(MODFLAGS)
@@ -530,6 +529,10 @@ endif
 
 include $(srctree)/arch/$(ARCH)/Makefile
 
+# arch Makefile may override CC so keep this after arch Makefile is included
+NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+CHECKFLAGS     += $(NOSTDINC_FLAGS)
+
 # warn about C99 declaration after statement
 CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
@@ -539,16 +542,14 @@ CFLAGS += $(call cc-option,-Wno-pointer-
 # Default kernel image to build when no specific target is given.
 # KBUILD_IMAGE may be overruled on the commandline or
 # set in the environment
-# Also any assingments in arch/$(ARCH)/Makefiel take precedence over
+# Also any assignments in arch/$(ARCH)/Makefile take precedence over
 # this default value
 export KBUILD_IMAGE ?= vmlinux
 
 #
 # INSTALL_PATH specifies where to place the updated kernel and system map
-# images.  Uncomment if you want to place them anywhere other than root.
-#
-
-#export	INSTALL_PATH=/boot
+# images. Default is /boot, but you can set it to other values
+export	INSTALL_PATH ?= /boot
 
 #
 # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
@@ -898,7 +899,7 @@ depmod_opts	:= -b $(INSTALL_MOD_PATH) -r
 endif
 .PHONY: _modinst_post
 _modinst_post: _modinst_
-	if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+	if [ -r System.map -a -x $(DEPMOD) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
 
 else # CONFIG_MODULES
 
@@ -1096,9 +1097,17 @@ KBUILD_MODULES := 1
 crmodverdir:
 	$(Q)mkdir -p $(MODVERDIR)
 
+.PHONY: $(objtree)/Module.symvers
+$(objtree)/Module.symvers:
+	@test -e $(objtree)/Module.symvers || ( \
+	echo; \
+	echo "  WARNING: Symbol version dump $(objtree)/Module.symvers"; \
+	echo "           is missing; modules will have no dependencies and modversions."; \
+	echo )
+
 module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
 .PHONY: $(module-dirs) modules
-$(module-dirs): crmodverdir
+$(module-dirs): crmodverdir $(objtree)/Module.symvers
 	$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
 
 modules: $(module-dirs)
@@ -1136,20 +1145,30 @@ endif # KBUILD_EXTMOD
 # Generate tags for editors
 # ---------------------------------------------------------------------------
 
+#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set
+#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
+#Adding $(srctree) adds about 20M on i386 to the size of the output file!
+
+ifeq ($(KBUILD_OUTPUT),)
+__srctree =
+else
+__srctree = $(srctree)/
+endif
+
 define all-sources
-	( find $(srctree) $(RCS_FIND_IGNORE) \
+	( find $(__srctree) $(RCS_FIND_IGNORE) \
 	       \( -name include -o -name arch \) -prune -o \
 	       -name '*.[chS]' -print; \
-	  find $(srctree)/arch/$(ARCH) $(RCS_FIND_IGNORE) \
+	  find $(__srctree)arch/$(ARCH) $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print; \
-	  find $(srctree)/security/selinux/include $(RCS_FIND_IGNORE) \
+	  find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print; \
-	  find $(srctree)/include $(RCS_FIND_IGNORE) \
+	  find $(__srctree)include $(RCS_FIND_IGNORE) \
 	       \( -name config -o -name 'asm-*' \) -prune \
 	       -o -name '*.[chS]' -print; \
-	  find $(srctree)/include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
+	  find $(__srctree)include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print; \
-	  find $(srctree)/include/asm-generic $(RCS_FIND_IGNORE) \
+	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print )
 endef
 
@@ -1171,7 +1190,7 @@ cmd_TAGS = $(all-sources) | etags -
 quiet_cmd_tags = MAKE   $@
 define cmd_tags
 	rm -f $@; \
-	CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL"`; \
+	CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL --extra=+f"`; \
 	$(all-sources) | xargs ctags $$CTAGSF -a
 endef
 
diff --git a/REPORTING-BUGS b/REPORTING-BUGS
--- a/REPORTING-BUGS
+++ b/REPORTING-BUGS
@@ -16,6 +16,10 @@ code relevant to what you were doing. If
 describe how to recreate it. That is worth even more than the oops itself.
 The list of maintainers is in the MAINTAINERS file in this directory.
 
+      If it is a security bug, please copy the Security Contact listed
+in the MAINTAINERS file.  They can help coordinate bugfix and disclosure.
+See Documentation/SecurityBugs for more infomation.
+
       If you are totally stumped as to whom to send the report, send it to
 linux-kernel@vger.kernel.org. (For more information on the linux-kernel
 mailing list see http://www.tux.org/lkml/).
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -280,6 +280,10 @@ config ISA
 	  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
 	  newer boards don't support it.  If you have ISA, say Y, otherwise N.
 
+config ISA_DMA_API
+	bool
+	default y
+
 config PCI
 	bool
 	depends on !ALPHA_JENSEN
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -176,7 +176,6 @@ EXPORT_SYMBOL(up);
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(flush_tlb_all);
 EXPORT_SYMBOL(flush_tlb_mm);
 EXPORT_SYMBOL(flush_tlb_range);
 EXPORT_SYMBOL(flush_tlb_page);
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -437,11 +437,10 @@ asmlinkage int
 osf_getdomainname(char __user *name, int namelen)
 {
 	unsigned len;
-	int i, error;
+	int i;
 
-	error = verify_area(VERIFY_WRITE, name, namelen);
-	if (error)
-		goto out;
+	if (!access_ok(VERIFY_WRITE, name, namelen))
+		return -EFAULT;
 
 	len = namelen;
 	if (namelen > 32)
@@ -454,26 +453,10 @@ osf_getdomainname(char __user *name, int
 			break;
 	}
 	up_read(&uts_sem);
- out:
-	return error;
-}
-
-asmlinkage long
-osf_shmat(int shmid, void __user *shmaddr, int shmflg)
-{
-	unsigned long raddr;
-	long err;
 
-	err = do_shmat(shmid, shmaddr, shmflg, &raddr);
-
-	/*
-	 * This works because all user-level addresses are
-	 * non-negative longs!
-	 */
-	return err ? err : (long)raddr;
+	return 0;
 }
 
-
 /*
  * The following stuff should move into a header file should it ever
  * be labeled "officially supported."  Right now, there is just enough
@@ -990,18 +973,19 @@ osf_select(int n, fd_set __user *inp, fd
 	char *bits;
 	size_t size;
 	long timeout;
-	int ret;
+	int ret = -EINVAL;
 
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
 
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
+		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
+		    || __get_user(sec, &tvp->tv_sec)
+		    || __get_user(usec, &tvp->tv_usec)) {
+		    	ret = -EFAULT;
 			goto out_nofds;
+		}
 
-		ret = -EINVAL;
 		if (sec < 0 || usec < 0)
 			goto out_nofds;
 
@@ -1011,7 +995,6 @@ osf_select(int n, fd_set __user *inp, fd
 		}
 	}
 
-	ret = -EINVAL;
 	if (n < 0 || n > current->files->max_fdset)
 		goto out_nofds;
 
@@ -1167,16 +1150,13 @@ osf_usleep_thread(struct timeval32 __use
 	if (get_tv32(&tmp, sleep))
 		goto fault;
 
-	ticks = tmp.tv_usec;
-	ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
-	ticks += tmp.tv_sec * HZ;
+	ticks = timeval_to_jiffies(&tmp);
 
 	current->state = TASK_INTERRUPTIBLE;
 	ticks = schedule_timeout(ticks);
 
 	if (remain) {
-		tmp.tv_sec = ticks / HZ;
-		tmp.tv_usec = ticks % HZ;
+		jiffies_to_timeval(ticks, &tmp);
 		if (put_tv32(remain, &tmp))
 			goto fault;
 	}
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -14,6 +14,7 @@
 #include <linux/user.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -335,7 +336,7 @@ do_sys_ptrace(long request, long pid, lo
 		/* continue and stop at next (return from) syscall */
 	case PTRACE_CONT:    /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -365,7 +366,7 @@ do_sys_ptrace(long request, long pid, lo
 
 	case PTRACE_SINGLESTEP:  /* execute single instruction. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		/* Mark single stepping.  */
 		child->thread_info->bpt_nsaved = -1;
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -111,8 +111,6 @@ struct alpha_machine_vector alpha_mv;
 int alpha_using_srm;
 #endif
 
-unsigned char aux_device_present = 0xaa;
-
 #define N(a) (sizeof(a)/sizeof(a[0]))
 
 static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long,
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -91,7 +91,7 @@ osf_sigaction(int sig, const struct osf_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags))
 			return -EFAULT;
@@ -103,7 +103,7 @@ osf_sigaction(int sig, const struct osf_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
 			return -EFAULT;
@@ -298,7 +298,7 @@ do_sigreturn(struct sigcontext __user *s
 	sigset_t set;
 
 	/* Verify that it's a good sigcontext before using it */
-	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
+	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
 		goto give_sigsegv;
 	if (__get_user(set.sig[0], &sc->sc_mask))
 		goto give_sigsegv;
@@ -336,7 +336,7 @@ do_rt_sigreturn(struct rt_sigframe __use
 	sigset_t set;
 
 	/* Verify that it's a good ucontext_t before using it */
-	if (verify_area(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
+	if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
 		goto give_sigsegv;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto give_sigsegv;
@@ -446,7 +446,7 @@ setup_frame(int sig, struct k_sigaction 
 
 	oldsp = rdusp();
 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
 	err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
@@ -497,7 +497,7 @@ setup_rt_frame(int sig, struct k_sigacti
 
 	oldsp = rdusp();
 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
 	err |= copy_siginfo_to_user(&frame->info, info);
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -78,8 +78,6 @@ static unsigned long hwrpb_cpu_present_m
 
 int smp_num_probed;		/* Internal processor count */
 int smp_num_cpus = 1;		/* Number that came online.  */
-cycles_t cacheflush_time;
-unsigned long cache_decay_ticks;
 
 extern void calibrate_delay(void);
 
@@ -177,57 +175,6 @@ smp_callin(void)
 	cpu_idle();
 }
 
-
-/*
- * 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.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-static void __init
-smp_tune_scheduling (int cpuid)
-{
-	struct percpu_struct *cpu;
-	unsigned long on_chip_cache;	/* kB */
-	unsigned long freq;		/* Hz */
-	unsigned long bandwidth = 350;	/* MB/s */
-
-	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
-				      + cpuid * hwrpb->processor_size);
-	switch (cpu->type)
-	{
-	case EV45_CPU:
-		on_chip_cache = 16 + 16;
-		break;
-
-	case EV5_CPU:
-	case EV56_CPU:
-		on_chip_cache = 8 + 8 + 96;
-		break;
-
-	case PCA56_CPU:
-		on_chip_cache = 16 + 8;
-		break;
-
-	case EV6_CPU:
-	case EV67_CPU:
-	default:
-		on_chip_cache = 64 + 64;
-		break;
-	}
-
-	freq = hwrpb->cycle_freq ? : est_cycle_freq;
-
-	cacheflush_time = (freq / 1000000) * (on_chip_cache << 10) / bandwidth;
-	cache_decay_ticks = cacheflush_time / (freq / 1000) * HZ / 1000;
-
-	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
-	       cacheflush_time/(freq/1000000),
-	       (cacheflush_time*100/(freq/1000000)) % 100);
-	printk("task migration cache decay timeout: %ld msecs.\n",
-	       (cache_decay_ticks + 1) * 1000 / HZ);
-}
-
 /* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
 static int __init
 wait_for_txrdy (unsigned long cpumask)
@@ -528,7 +475,6 @@ smp_prepare_cpus(unsigned int max_cpus)
 	current_thread_info()->cpu = boot_cpuid;
 
 	smp_store_cpu_info(boot_cpuid);
-	smp_tune_scheduling(boot_cpuid);
 	smp_setup_percpu_timer(boot_cpuid);
 
 	/* Nothing to do on a UP box, or when told not to.  */
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -164,29 +164,22 @@ srmcons_get_private_struct(struct srmcon
 	unsigned long flags;
 	int retval = 0;
 
-	spin_lock_irqsave(&srmconsp_lock, flags);
-
-	do {
-		if (srmconsp != NULL) {
-			*ps = srmconsp;
-			break;
-		}
+	if (srmconsp == NULL) {
+		spin_lock_irqsave(&srmconsp_lock, flags);
 
 		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
-		if (srmconsp == NULL) {
+		if (srmconsp == NULL)
 			retval = -ENOMEM;
-			break;
+		else {
+			srmconsp->tty = NULL;
+			spin_lock_init(&srmconsp->lock);
+			init_timer(&srmconsp->timer);
 		}
 
-		srmconsp->tty = NULL;
-		spin_lock_init(&srmconsp->lock);
-		init_timer(&srmconsp->timer);
-
-		*ps = srmconsp;
-	} while(0);
-
-	spin_unlock_irqrestore(&srmconsp_lock, flags);
+		spin_unlock_irqrestore(&srmconsp_lock, flags);
+	}
 
+	*ps = srmconsp;
 	return retval;
 }
 
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -227,7 +227,7 @@ sys_call_table:
 	.quad sys_semop
 	.quad osf_utsname
 	.quad sys_lchown
-	.quad osf_shmat
+	.quad sys_shmat
 	.quad sys_shmctl			/* 210 */
 	.quad sys_shmdt
 	.quad sys_shmget
@@ -458,6 +458,9 @@ sys_call_table:
 	.quad sys_mq_notify
 	.quad sys_mq_getsetattr
 	.quad sys_waitid
+	.quad sys_add_key
+	.quad sys_request_key			/* 440 */
+	.quad sys_keyctl
 
 	.size sys_call_table, . - sys_call_table
 	.type sys_call_table, @object
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -71,6 +71,9 @@ config GENERIC_IOMAP
 	bool
 	default y
 
+config FIQ
+	bool
+
 source "init/Kconfig"
 
 menu "System Type"
@@ -81,6 +84,8 @@ choice
 
 config ARCH_CLPS7500
 	bool "Cirrus-CL-PS7500FE"
+	select TIMER_ACORN
+	select ISA
 
 config ARCH_CLPS711X
 	bool "CLPS711x/EP721x-based"
@@ -92,6 +97,7 @@ config ARCH_CO285
 
 config ARCH_EBSA110
 	bool "EBSA-110"
+	select ISA
 	help
 	  This is an evaluation board for the StrongARM processor available
 	  from Digital. It has limited hardware on-board, including an onboard
@@ -111,18 +117,25 @@ config ARCH_FOOTBRIDGE
 
 config ARCH_INTEGRATOR
 	bool "Integrator"
+	select ARM_AMBA
+	select ICST525
 
 config ARCH_IOP3XX
 	bool "IOP3xx-based"
+	select PCI
 
 config ARCH_IXP4XX
 	bool "IXP4xx-based"
+	select DMABOUNCE
+	select PCI
 
 config ARCH_IXP2000
 	bool "IXP2400/2800-based"
+	select PCI
 
 config ARCH_L7200
 	bool "LinkUp-L7200"
+	select FIQ
 	help
 	  Say Y here if you intend to run this kernel on a LinkUp Systems
 	  L7200 Software Development Board which uses an ARM720T processor.
@@ -138,12 +151,17 @@ config ARCH_PXA
 
 config ARCH_RPC
 	bool "RiscPC"
+	select ARCH_ACORN
+	select FIQ
+	select TIMER_ACORN
 	help
 	  On the Acorn Risc-PC, Linux can support the internal IDE disk and
 	  CD-ROM interface, serial and parallel port, and the floppy drive.
 
 config ARCH_SA1100
 	bool "SA1100-based"
+	select ISA
+	select DISCONTIGMEM
 
 config ARCH_S3C2410
 	bool "Samsung S3C2410"
@@ -154,6 +172,9 @@ config ARCH_S3C2410
 
 config ARCH_SHARK
 	bool "Shark"
+	select ISA
+	select ISA_DMA
+	select PCI
 
 config ARCH_LH7A40X
 	bool "Sharp LH7A40X"
@@ -168,6 +189,8 @@ config ARCH_OMAP
 
 config ARCH_VERSATILE
 	bool "Versatile"
+	select ARM_AMBA
+	select ICST307
 	help
 	  This enables support for ARM Ltd Versatile board.
 
@@ -214,58 +237,75 @@ source "arch/arm/mach-versatile/Kconfig"
 # Definitions to make life easier
 config ARCH_ACORN
 	bool
-	depends on ARCH_RPC
-	default y
 
-config TIMER_ACORN
-	bool
-	depends on ARCH_ACORN || ARCH_CLPS7500
-	default y
+source arch/arm/mm/Kconfig
 
-#####################################################################
-# SA1111 support
-config SA1111
+#  bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
+config XSCALE_PMU
 	bool
-	depends on ASSABET_NEPONSET || SA1100_ADSBITSY || SA1100_BADGE4 || SA1100_CONSUS || SA1100_GRAPHICSMASTER || SA1100_JORNADA720 || ARCH_LUBBOCK || SA1100_PFS168 || SA1100_PT_SYSTEM3 || SA1100_XP860
+	depends on CPU_XSCALE && !XSCALE_PMU_TIMER
 	default y
 
-config SHARP_LOCOMO
-	bool
-	depends on SA1100_COLLIE
-	default y
+endmenu
 
-config SHARP_SCOOP
-	bool
-	depends on PXA_SHARPSL || SA1100_COLLIE
-	default y
+source "arch/arm/common/Kconfig"
 
 config FORCE_MAX_ZONEORDER
 	int
 	depends on SA1111
 	default "9"
 
-config DMABOUNCE
+menu "Bus support"
+
+config ARM_AMBA
+	bool
+
+config ISA
+	bool
+	help
+	  Find out whether you have ISA slots on your motherboard.  ISA is the
+	  name of a bus system, i.e. the way the CPU talks to the other stuff
+	  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+	  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+	  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+config ISA_DMA
+	bool
+
+config ISA_DMA_API
 	bool
-	depends on SA1111 || ARCH_IXP4XX
 	default y
 
-source arch/arm/mm/Kconfig
+config PCI
+	bool "PCI support" if ARCH_INTEGRATOR_AP
+	help
+	  Find out whether you have a PCI motherboard. PCI is the name of a
+	  bus system, i.e. the way the CPU talks to the other stuff inside
+	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+	  VESA. If you have PCI, say Y, otherwise N.
 
-#  bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
-config XSCALE_PMU
+	  The PCI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, contains valuable
+	  information about which PCI hardware does work under Linux and which
+	  doesn't.
+
+# Select the host bridge type
+config PCI_HOST_VIA82C505
 	bool
-	depends on CPU_XSCALE && !XSCALE_PMU_TIMER
+	depends on PCI && ARCH_SHARK
 	default y
 
-endmenu
+source "drivers/pci/Kconfig"
 
-menu "General setup"
+source "drivers/pcmcia/Kconfig"
 
-# Select various configuration options depending on the machine type
+endmenu
+
+menu "Kernel Features"
 
 config SMP
 	bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && n
+	depends on EXPERIMENTAL #&& n
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
@@ -286,75 +326,94 @@ config SMP
 
 config NR_CPUS
 	int "Maximum number of CPUs (2-32)"
+	range 2 32
 	depends on SMP
 	default "4"
 
+config PREEMPT
+	bool "Preemptible Kernel (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  This option reduces the latency of the kernel when reacting to
+	  real-time or interactive events by allowing a low priority process to
+	  be preempted even if it is in kernel mode executing a system call.
+	  This allows applications to run more reliably even when the system is
+	  under load.
+
+	  Say Y here if you are building a kernel for a desktop, embedded
+	  or real-time system.  Say N if you are unsure.
+
 config DISCONTIGMEM
 	bool
-	depends on ARCH_EDB7211 || ARCH_SA1100 || (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
-	default y
+	default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
 	help
 	  Say Y to support efficient handling of discontiguous physical memory,
 	  for architectures which are either NUMA (Non-Uniform Memory Access)
 	  or have huge holes in the physical address space for other reasons.
 	  See <file:Documentation/vm/numa> for more.
 
-# Now handle the bus types
-config PCI
-	bool "PCI support" if ARCH_INTEGRATOR_AP
-	default y if ARCH_SHARK || FOOTBRIDGE_HOST || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_IXP2000
+config LEDS
+	bool "Timer and CPU usage LEDs"
+	depends on ARCH_CDB89712 || ARCH_CO285 || ARCH_EBSA110 || \
+		   ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \
+		   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
+		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
+		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE
 	help
-	  Find out whether you have a PCI motherboard. PCI is the name of a
-	  bus system, i.e. the way the CPU talks to the other stuff inside
-	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-	  VESA. If you have PCI, say Y, otherwise N.
+	  If you say Y here, the LEDs on your machine will be used
+	  to provide useful information about your current system status.
 
-	  The PCI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>, contains valuable
-	  information about which PCI hardware does work under Linux and which
-	  doesn't.
+	  If you are compiling a kernel for a NetWinder or EBSA-285, you will
+	  be able to select which LEDs are active using the options below. If
+	  you are compiling a kernel for the EBSA-110 or the LART however, the
+	  red LED will simply flash regularly to indicate that the system is
+	  still functional. It is safe to say Y here if you have a CATS
+	  system, but the driver will do nothing.
 
-# Select the host bridge type
-config PCI_HOST_VIA82C505
-	bool
-	depends on PCI && ARCH_SHARK
-	default y
+config LEDS_TIMER
+	bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
+			    MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+	depends on LEDS
+	default y if ARCH_EBSA110
+	help
+	  If you say Y here, one of the system LEDs (the green one on the
+	  NetWinder, the amber one on the EBSA285, or the red one on the LART)
+	  will flash regularly to indicate that the system is still
+	  operational. This is mainly useful to kernel hackers who are
+	  debugging unstable kernels.
 
-config ICST525
-	bool
-	depends on ARCH_INTEGRATOR
-	default y
+	  The LART uses the same LED for both Timer LED and CPU usage LED
+	  functions. You may choose to use both, but the Timer LED function
+	  will overrule the CPU usage LED.
 
-config ICST307
-	bool
-	depends on ARCH_VERSATILE
-	default y
+config LEDS_CPU
+	bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
+			!ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+	depends on LEDS
+	help
+	  If you say Y here, the red LED will be used to give a good real
+	  time indication of CPU usage, by lighting whenever the idle task
+	  is not currently executing.
 
-config ARM_AMBA
-	bool
-	depends on ARCH_INTEGRATOR || ARCH_VERSATILE
-	default y
+	  The LART uses the same LED for both Timer LED and CPU usage LED
+	  functions. You may choose to use both, but the Timer LED function
+	  will overrule the CPU usage LED.
 
-config ISA
+config ALIGNMENT_TRAP
 	bool
-	depends on FOOTBRIDGE_HOST || ARCH_SHARK || ARCH_CLPS7500 || ARCH_EBSA110 || ARCH_CDB89712 || ARCH_EDB7211 || ARCH_SA1100 || ARCH_MX1ADS
-	default y
+	default y if !ARCH_EBSA110
 	help
-	  Find out whether you have ISA slots on your motherboard.  ISA is the
-	  name of a bus system, i.e. the way the CPU talks to the other stuff
-	  inside your box.  Other bus systems are PCI, EISA, MicroChannel
-	  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
-	  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+	  ARM processors can not fetch/store information which is not
+	  naturally aligned on the bus, i.e., a 4 byte fetch must start at an
+	  address divisible by 4. On 32-bit ARM processors, these non-aligned
+	  fetch/store instructions will be emulated in software if you say
+	  here, which has a severe performance impact. This is necessary for
+	  correct operation of some network protocols. With an IP-only
+	  configuration it is safe to say N, otherwise say Y.
 
-config ISA_DMA
-	bool
-	depends on FOOTBRIDGE_HOST || ARCH_SHARK
-	default y
+endmenu
 
-config FIQ
-	bool
-	depends on ARCH_ACORN || ARCH_L7200
-	default y
+menu "Boot options"
 
 # Compressed boot loader in ROM.  Yes, we really want to ask about
 # TEXT and BSS so we preserve their values in the config files.
@@ -388,6 +447,16 @@ config ZBOOT_ROM
 	  Say Y here if you intend to execute your compressed kernel image
 	  (zImage) directly from ROM or flash.  If unsure, say N.
 
+config CMDLINE
+	string "Default kernel command string"
+	default ""
+	help
+	  On some architectures (EBSA110 and CATS), there is currently no way
+	  for the boot loader to pass arguments to the kernel. For these
+	  architectures, you should supply some command-line options at build
+	  time by entering them here. As a minimum, you should specify the
+	  memory size and the root device (e.g., mem=64M root=/dev/nfs).
+
 config XIP_KERNEL
 	bool "Kernel Execute-In-Place from ROM"
 	depends on !ZBOOT_ROM
@@ -418,13 +487,17 @@ config XIP_PHYS_ADDR
 	  be linked for and stored to.  This address is dependent on your
 	  own flash usage.
 
+endmenu
+
 if (ARCH_SA1100 || ARCH_INTEGRATOR)
 
+menu "CPU Frequency scaling"
+
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_SA1100
 	bool
-	depends on CPU_FREQ && (SA1100_LART || SA1100_PLEB)
+	depends on CPU_FREQ && (SA1100_H3100 || SA1100_H3600 || SA1100_H3800 || SA1100_LART || SA1100_PLEB || SA1100_BADGE4 || SA1100_HACKKIT)
 	default y
 
 config CPU_FREQ_SA1110
@@ -434,7 +507,7 @@ config CPU_FREQ_SA1110
 
 config CPU_FREQ_INTEGRATOR
 	tristate "CPUfreq driver for ARM Integrator CPUs"
-	depends on ARCH_INTEGRATOR && ICST525 && CPU_FREQ
+	depends on ARCH_INTEGRATOR && CPU_FREQ
 	default y
 	help
 	  This enables the CPUfreq driver for ARM Integrator CPUs.
@@ -443,13 +516,13 @@ config CPU_FREQ_INTEGRATOR
 
 	  If in doubt, say Y.
 
-endif
+endmenu
 
-source "drivers/pci/Kconfig"
+endif
 
-source "drivers/pcmcia/Kconfig"
+menu "Floating point emulation"
 
-comment "At least one math emulation must be selected"
+comment "At least one emulation must be selected"
 
 config FPE_NWFPE
 	bool "NWFPE math emulation"
@@ -500,9 +573,24 @@ config VFP
 
 	  Say N if your target does not have VFP hardware.
 
+endmenu
+
+menu "Userspace binary formats"
+
 source "fs/Kconfig.binfmt"
 
-source "drivers/base/Kconfig"
+config ARTHUR
+	tristate "RISC OS personality"
+	help
+	  Say Y here to include the kernel code necessary if you want to run
+	  Acorn RISC OS/Arthur binaries under Linux. This code is still very
+	  experimental; if this sounds frightening, say N and sleep in peace.
+	  You can also say M here to compile this support as a module (which
+	  will be called arthur).
+
+endmenu
+
+menu "Power management options"
 
 config PM
 	bool "Power Management support"
@@ -524,19 +612,6 @@ config PM
 	  will issue the hlt instruction if nothing is to be done, thereby
 	  sending the processor to sleep and saving power.
 
-config PREEMPT
-	bool "Preemptible Kernel (EXPERIMENTAL)"
-	depends on CPU_32 && EXPERIMENTAL
-	help
-	  This option reduces the latency of the kernel when reacting to
-	  real-time or interactive events by allowing a low priority process to
-	  be preempted even if it is in kernel mode executing a system call.
-	  This allows applications to run more reliably even when the system is
-	  under load.
-
-	  Say Y here if you are building a kernel for a desktop, embedded
-	  or real-time system.  Say N if you are unsure.
-
 config APM
 	tristate "Advanced Power Management Emulation"
 	depends on PM
@@ -596,115 +671,46 @@ config APM
 	  To compile this driver as a module, choose M here: the
 	  module will be called apm.
 
-config ARTHUR
-	tristate "RISC OS personality"
-	depends on CPU_32
-	help
-	  Say Y here to include the kernel code necessary if you want to run
-	  Acorn RISC OS/Arthur binaries under Linux. This code is still very
-	  experimental; if this sounds frightening, say N and sleep in peace.
-	  You can also say M here to compile this support as a module (which
-	  will be called arthur).
-
-config CMDLINE
-	string "Default kernel command string"
-	default ""
-	help
-	  On some architectures (EBSA110 and CATS), there is currently no way
-	  for the boot loader to pass arguments to the kernel. For these
-	  architectures, you should supply some command-line options at build
-	  time by entering them here. As a minimum, you should specify the
-	  memory size and the root device (e.g., mem=64M root=/dev/nfs).
-
-config LEDS
-	bool "Timer and CPU usage LEDs"
-	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE || ARCH_IMX
-	help
-	  If you say Y here, the LEDs on your machine will be used
-	  to provide useful information about your current system status.
-
-	  If you are compiling a kernel for a NetWinder or EBSA-285, you will
-	  be able to select which LEDs are active using the options below. If
-	  you are compiling a kernel for the EBSA-110 or the LART however, the
-	  red LED will simply flash regularly to indicate that the system is
-	  still functional. It is safe to say Y here if you have a CATS
-	  system, but the driver will do nothing.
-
-config LEDS_TIMER
-	bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || MACH_MAINSTONE || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2)
-	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE || ARCH_IMX
-	default y if ARCH_EBSA110
-	help
-	  If you say Y here, one of the system LEDs (the green one on the
-	  NetWinder, the amber one on the EBSA285, or the red one on the LART)
-	  will flash regularly to indicate that the system is still
-	  operational. This is mainly useful to kernel hackers who are
-	  debugging unstable kernels.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
-config LEDS_CPU
-	bool "CPU usage LED"
-	depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2)
-	help
-	  If you say Y here, the red LED will be used to give a good real
-	  time indication of CPU usage, by lighting whenever the idle task
-	  is not currently executing.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
-config ALIGNMENT_TRAP
-	bool
-	depends on CPU_32
-	default y if !ARCH_EBSA110
-	help
-	  ARM processors can not fetch/store information which is not
-	  naturally aligned on the bus, i.e., a 4 byte fetch must start at an
-	  address divisible by 4. On 32-bit ARM processors, these non-aligned
-	  fetch/store instructions will be emulated in software if you say
-	  here, which has a severe performance impact. This is necessary for
-	  correct operation of some network protocols. With an IP-only
-	  configuration it is safe to say N, otherwise say Y.
-
 endmenu
 
-source "drivers/parport/Kconfig"
+menu "Device Drivers"
+
+source "drivers/base/Kconfig"
 
 if ALIGNMENT_TRAP
 source "drivers/mtd/Kconfig"
 endif
 
+source "drivers/parport/Kconfig"
+
 source "drivers/pnp/Kconfig"
 
 source "drivers/block/Kconfig"
 
-source "drivers/md/Kconfig"
-
 source "drivers/acorn/block/Kconfig"
 
-source "net/Kconfig"
-
-if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE
+if PCMCIA || ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX \
+	|| ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
+	|| ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE
 source "drivers/ide/Kconfig"
 endif
 
 source "drivers/scsi/Kconfig"
 
+source "drivers/md/Kconfig"
+
 source "drivers/message/fusion/Kconfig"
 
 source "drivers/ieee1394/Kconfig"
 
 source "drivers/message/i2o/Kconfig"
 
+source "net/Kconfig"
+
 source "drivers/isdn/Kconfig"
 
-#
 # input before char - char/joystick depends on it. As does USB.
-#
+
 source "drivers/input/Kconfig"
 
 source "drivers/char/Kconfig"
@@ -713,22 +719,24 @@ source "drivers/i2c/Kconfig"
 
 #source "drivers/l3/Kconfig"
 
-source "drivers/media/Kconfig"
-
-source "fs/Kconfig"
+source "drivers/misc/Kconfig"
 
-source "arch/arm/oprofile/Kconfig"
+source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
 
 source "sound/Kconfig"
 
-source "drivers/misc/Kconfig"
-
 source "drivers/usb/Kconfig"
 
 source "drivers/mmc/Kconfig"
 
+endmenu
+
+source "fs/Kconfig"
+
+source "arch/arm/oprofile/Kconfig"
+
 source "arch/arm/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -47,15 +47,6 @@ config DEBUG_ERRORS
 	  you are concerned with the code size or don't want to see these
 	  messages.
 
-config DEBUG_INFO
-	bool "Include GDB debugging information in kernel binary"
-	help
-	  Say Y here to include source-level debugging information in the
-	  `vmlinux' binary image. This is handy if you want to use gdb or
-	  addr2line to debug the kernel. It has no impact on the in-memory
-	  footprint of the running kernel but it can increase the amount of
-	  time and disk space needed for compilation of the kernel. If in
-	  doubt say N.
 
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -22,15 +22,13 @@ CFLAGS		+=-fno-omit-frame-pointer -mapcs
 endif
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
-CFLAGS		+= -mbig-endian
+CPPFLAGS	+= -mbig-endian
 AS		+= -EB
 LD		+= -EB
-AFLAGS		+= -mbig-endian
 else
-CFLAGS		+= -mlittle-endian
+CPPFLAGS	+= -mlittle-endian
 AS		+= -EL
 LD		+= -EL
-AFLAGS		+= -mlittle-endian
 endif
 
 comma = ,
diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S
--- a/arch/arm/boot/compressed/head-xscale.S
+++ b/arch/arm/boot/compressed/head-xscale.S
@@ -47,3 +47,10 @@ __XScale_start:
                orr     r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00)
 #endif
 
+#ifdef CONFIG_ARCH_IXP2000
+		mov	r1, #-1
+		mov	r0, #0xd6000000
+		str	r1, [r0, #0x14]
+		str	r1, [r0, #0x18]
+#endif
+
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -18,48 +18,30 @@
  * Please select one of the following when turning on debugging.
  */
 #ifdef DEBUG
-#if defined(CONFIG_DEBUG_DC21285_PORT)
-		.macro	loadsp, rb
-		mov	\rb, #0x42000000
-		.endm
-		.macro	writeb, rb
-		str	\rb, [r3, #0x160]
-		.endm
-#elif defined(CONFIG_DEBUG_ICEDCC)
+
+#include <asm/arch/debug-macro.S>
+
+#if defined(CONFIG_DEBUG_ICEDCC)
 		.macro	loadsp, rb
 		.endm
-		.macro writeb, rb
-		mcr	p14, 0, \rb, c0, c1, 0
-		.endm
-#elif defined(CONFIG_FOOTBRIDGE)
-		.macro	loadsp,	rb
-		mov	\rb, #0x7c000000
+		.macro writeb, ch, rb
+		mcr	p14, 0, \ch, c0, c1, 0
 		.endm
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8]
+#else
+		.macro	writeb,	ch, rb
+		senduart \ch, \rb
 		.endm
-#elif defined(CONFIG_ARCH_RPC)
+
+#if defined(CONFIG_FOOTBRIDGE) || \
+    defined(CONFIG_ARCH_RPC) || \
+    defined(CONFIG_ARCH_INTEGRATOR) || \
+    defined(CONFIG_ARCH_PXA) || \
+    defined(CONFIG_ARCH_IXP4XX) || \
+    defined(CONFIG_ARCH_IXP2000) || \
+    defined(CONFIG_ARCH_LH7A40X) || \
+    defined(CONFIG_ARCH_OMAP)
 		.macro	loadsp,	rb
-		mov	\rb, #0x03000000
-		orr	\rb, \rb, #0x00010000
-		.endm
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8 << 2]
-		.endm
-#elif defined(CONFIG_ARCH_INTEGRATOR)
-		.macro	loadsp, rb
-		mov	\rb, #0x16000000
-		.endm
-		.macro	writeb, rb
-		strb	\rb, [r3, #0]
-		.endm
-#elif defined(CONFIG_ARCH_PXA) /* Xscale-type */
-		.macro 	loadsp, rb
-		mov	\rb, #0x40000000
-		orr	\rb, \rb, #0x00100000
-		.endm
-		.macro	writeb, rb
-		strb	\rb, [r3, #0]
+		addruart \rb
 		.endm
 #elif defined(CONFIG_ARCH_SA1100)
 		.macro	loadsp, rb
@@ -70,65 +52,22 @@
 		add	\rb, \rb, #0x00010000	@ Ser1
 #  endif
 		.endm
-		.macro	writeb, rb
-		str	\rb, [r3, #0x14]	@ UTDR
-		.endm
-#elif defined(CONFIG_ARCH_IXP4XX)
-		.macro	loadsp, rb
-		mov	\rb, #0xc8000000
-		.endm
-		.macro	writeb, rb
-		str	\rb, [r3, #0]
-#elif defined(CONFIG_ARCH_IXP2000)
-		.macro	loadsp, rb
-		mov	\rb, #0xc0000000
-		orr	\rb, \rb, #0x00030000
-		.endm
-		.macro	writeb, rb
-		str	\rb, [r3, #0]
-		.endm
-#elif defined(CONFIG_ARCH_LH7A40X)
-		.macro	loadsp, rb
-		ldr	\rb, =0x80000700	@ UART2 UARTBASE
-		.endm
-		.macro	writeb, rb
-		strb	\rb, [r3, #0]
-		.endm
-#elif defined(CONFIG_ARCH_OMAP)
-		.macro  loadsp, rb
-		mov	\rb, #0xff000000	@ physical base address
-		add	\rb, \rb, #0x00fb0000
-#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
-		add	\rb, \rb, #0x00000800
-#endif
-#ifdef CONFIG_OMAP_LL_DEBUG_UART3
-		add	\rb, \rb, #0x00009000
-#endif
-		.endm
-		.macro	writeb, rb
-		strb	\rb, [r3]
-		.endm
 #elif defined(CONFIG_ARCH_IOP331)
 		.macro loadsp, rb
                 mov   	\rb, #0xff000000
                 orr     \rb, \rb, #0x00ff0000
                 orr     \rb, \rb, #0x0000f700   @ location of the UART
 		.endm
-		.macro	writeb, rb
-		str	\rb, [r3, #0]
-		.endm
 #elif defined(CONFIG_ARCH_S3C2410)
-			.macro loadsp, rb
+		.macro loadsp, rb
 		mov	\rb, #0x50000000
 		add	\rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
 		.endm
-		.macro	writeb, rb
-		strb	\rb, [r3, #0x20]
-		.endm
 #else
 #error no serial architecture defined
 #endif
 #endif
+#endif
 
 		.macro	kputc,val
 		mov	r0, \val
@@ -734,7 +673,7 @@ puts:		loadsp	r3
 1:		ldrb	r2, [r0], #1
 		teq	r2, #0
 		moveq	pc, lr
-2:		writeb	r2
+2:		writeb	r2, r3
 		mov	r1, #0x00020000
 3:		subs	r1, r1, #1
 		bne	3b
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
new file mode 100644
--- /dev/null
+++ b/arch/arm/common/Kconfig
@@ -0,0 +1,24 @@
+config ICST525
+	bool
+
+config ICST307
+	bool
+
+config SA1111
+	bool
+	select DMABOUNCE
+
+config DMABOUNCE
+	bool
+
+config TIMER_ACORN
+	bool
+
+config SHARP_LOCOMO
+	bool
+
+config SHARP_PARAM
+	bool
+
+config SHARP_SCOOP
+	bool
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_PCI_HOST_VIA82C505) += via8
 obj-$(CONFIG_DMABOUNCE)		+= dmabounce.o
 obj-$(CONFIG_TIMER_ACORN)	+= time-acorn.o
 obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
+obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
 obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -34,11 +34,33 @@
 
 #include <asm/hardware/locomo.h>
 
+/* M62332 output channel selection */
+#define M62332_EVR_CH	1	/* M62332 volume channel number  */
+				/*   0 : CH.1 , 1 : CH. 2        */
+/* DAC send data */
+#define	M62332_SLAVE_ADDR	0x4e	/* Slave address  */
+#define	M62332_W_BIT		0x00	/* W bit (0 only) */
+#define	M62332_SUB_ADDR		0x00	/* Sub address    */
+#define	M62332_A_BIT		0x00	/* A bit (0 only) */
+
+/* DAC setup and hold times (expressed in us) */
+#define DAC_BUS_FREE_TIME	5	/*   4.7 us */
+#define DAC_START_SETUP_TIME	5	/*   4.7 us */
+#define DAC_STOP_SETUP_TIME	4	/*   4.0 us */
+#define DAC_START_HOLD_TIME	5	/*   4.7 us */
+#define DAC_SCL_LOW_HOLD_TIME	5	/*   4.7 us */
+#define DAC_SCL_HIGH_HOLD_TIME	4	/*   4.0 us */
+#define DAC_DATA_SETUP_TIME	1	/*   250 ns */
+#define DAC_DATA_HOLD_TIME	1	/*   300 ns */
+#define DAC_LOW_SETUP_TIME	1	/*   300 ns */
+#define DAC_HIGH_SETUP_TIME	1	/*  1000 ns */
+
 /* the following is the overall data for the locomo chip */
 struct locomo {
 	struct device *dev;
 	unsigned long phys;
 	unsigned int irq;
+	spinlock_t lock;
 	void *base;
 };
 
@@ -50,7 +72,57 @@ struct locomo_dev_info {
 	const char *	name;
 };
 
+/* All the locomo devices.  If offset is non-zero, the mapbase for the
+ * locomo_dev will be set to the chip base plus offset.  If offset is
+ * zero, then the mapbase for the locomo_dev will be set to zero.  An
+ * offset of zero means the device only uses GPIOs or other helper
+ * functions inside this file */
 static struct locomo_dev_info locomo_devices[] = {
+	{
+		.devid 		= LOCOMO_DEVID_KEYBOARD,
+		.irq = {
+			IRQ_LOCOMO_KEY,
+		},
+		.name		= "locomo-keyboard",
+		.offset		= LOCOMO_KEYBOARD,
+		.length		= 16,
+	},
+	{
+		.devid		= LOCOMO_DEVID_FRONTLIGHT,
+		.irq		= {},
+		.name		= "locomo-frontlight",
+		.offset		= LOCOMO_FRONTLIGHT,
+		.length		= 8,
+
+	},
+	{
+		.devid		= LOCOMO_DEVID_BACKLIGHT,
+		.irq		= {},
+		.name		= "locomo-backlight",
+		.offset		= LOCOMO_BACKLIGHT,
+		.length		= 8,
+	},
+	{
+		.devid		= LOCOMO_DEVID_AUDIO,
+		.irq		= {},
+		.name		= "locomo-audio",
+		.offset		= LOCOMO_AUDIO,
+		.length		= 4,
+	},
+	{
+		.devid		= LOCOMO_DEVID_LED,
+		.irq 		= {},
+		.name		= "locomo-led",
+		.offset		= LOCOMO_LED,
+		.length		= 8,
+	},
+	{
+		.devid		= LOCOMO_DEVID_UART,
+		.irq		= {},
+		.name		= "locomo-uart",
+		.offset		= 0,
+		.length		= 0,
+	},
 };
 
 
@@ -146,7 +218,7 @@ static void locomo_key_handler(unsigned 
 	struct irqdesc *d;
 	void *mapbase = get_irq_chipdata(irq);
 
-	if (locomo_readl(mapbase + LOCOMO_KIC) & 0x0001) {
+	if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
 		d = irq_desc + LOCOMO_IRQ_KEY_START;
 		d->handle(LOCOMO_IRQ_KEY_START, d, regs);
 	}
@@ -156,27 +228,27 @@ static void locomo_key_ack_irq(unsigned 
 {
 	void *mapbase = get_irq_chipdata(irq);
 	unsigned int r;
-	r = locomo_readl(mapbase + LOCOMO_KIC);
+	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 	r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START));
-	locomo_writel(r, mapbase + LOCOMO_KIC);
+	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 }
 
 static void locomo_key_mask_irq(unsigned int irq)
 {
 	void *mapbase = get_irq_chipdata(irq);
 	unsigned int r;
-	r = locomo_readl(mapbase + LOCOMO_KIC);
+	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 	r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START));
-	locomo_writel(r, mapbase + LOCOMO_KIC);
+	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 }
 
 static void locomo_key_unmask_irq(unsigned int irq)
 {
 	void *mapbase = get_irq_chipdata(irq);
 	unsigned int r;
-	r = locomo_readl(mapbase + LOCOMO_KIC);
+	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 	r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START));
-	locomo_writel(r, mapbase + LOCOMO_KIC);
+	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
 }
 
 static struct irqchip locomo_key_chip = {
@@ -421,13 +493,11 @@ static void locomo_dev_release(struct de
 {
 	struct locomo_dev *dev = LOCOMO_DEV(_dev);
 
-	release_resource(&dev->res);
 	kfree(dev);
 }
 
 static int
-locomo_init_one_child(struct locomo *lchip, struct resource *parent,
-		      struct locomo_dev_info *info)
+locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info)
 {
 	struct locomo_dev *dev;
 	int ret;
@@ -454,25 +524,17 @@ locomo_init_one_child(struct locomo *lch
 	dev->dev.bus     = &locomo_bus_type;
 	dev->dev.release = locomo_dev_release;
 	dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask;
-	dev->res.start   = lchip->phys + info->offset;
-	dev->res.end     = dev->res.start + info->length;
-	dev->res.name    = dev->dev.bus_id;
-	dev->res.flags   = IORESOURCE_MEM;
-	dev->mapbase     = lchip->base + info->offset;
-	memmove(dev->irq, info->irq, sizeof(dev->irq));
 
-	if (info->length) {
-		ret = request_resource(parent, &dev->res);
-		if (ret) {
-			printk("LoCoMo: failed to allocate resource for %s\n",
-				dev->res.name);
-			goto out;
-		}
-	}
+	if (info->offset)
+		dev->mapbase = lchip->base + info->offset;
+	else
+		dev->mapbase = 0;
+	dev->length = info->length;
+
+	memmove(dev->irq, info->irq, sizeof(dev->irq));
 
 	ret = device_register(&dev->dev);
 	if (ret) {
-		release_resource(&dev->res);
  out:
 		kfree(dev);
 	}
@@ -504,6 +566,8 @@ __locomo_probe(struct device *me, struct
 
 	memset(lchip, 0, sizeof(struct locomo));
 
+	spin_lock_init(&lchip->lock);
+
 	lchip->dev = me;
 	dev_set_drvdata(lchip->dev, lchip);
 
@@ -523,7 +587,7 @@ __locomo_probe(struct device *me, struct
 	/* locomo initialize */
 	locomo_writel(0, lchip->base + LOCOMO_ICR);
 	/* KEYBOARD */
-	locomo_writel(0, lchip->base + LOCOMO_KIC);
+	locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
 
 	/* GPIO */
 	locomo_writel(0, lchip->base + LOCOMO_GPO);
@@ -534,8 +598,8 @@ __locomo_probe(struct device *me, struct
 	locomo_writel(0, lchip->base + LOCOMO_GIE);
 
 	/* FrontLight */
-	locomo_writel(0, lchip->base + LOCOMO_ALS);
-	locomo_writel(0, lchip->base + LOCOMO_ALD);
+	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
+	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
 	/* Longtime timer */
 	locomo_writel(0, lchip->base + LOCOMO_LTINT);
 	/* SPI */
@@ -578,7 +642,7 @@ __locomo_probe(struct device *me, struct
 		locomo_setup_irq(lchip);
 
 	for (i = 0; i < ARRAY_SIZE(locomo_devices); i++)
-		locomo_init_one_child(lchip, mem, &locomo_devices[i]);
+		locomo_init_one_child(lchip, &locomo_devices[i]);
 
 	return 0;
 
@@ -654,6 +718,238 @@ static inline struct locomo *locomo_chip
 	return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
 }
 
+void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir)
+{
+	struct locomo *lchip = locomo_chip_driver(ldev);
+	unsigned long flags;
+	unsigned int r;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+
+	r = locomo_readl(lchip->base + LOCOMO_GPD);
+	r &= ~bits;
+	locomo_writel(r, lchip->base + LOCOMO_GPD);
+
+	r = locomo_readl(lchip->base + LOCOMO_GPE);
+	if (dir)
+		r |= bits;
+	else
+		r &= ~bits;
+	locomo_writel(r, lchip->base + LOCOMO_GPE);
+
+	spin_unlock_irqrestore(&lchip->lock, flags);
+}
+
+unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits)
+{
+	struct locomo *lchip = locomo_chip_driver(ldev);
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+	ret = locomo_readl(lchip->base + LOCOMO_GPL);
+	spin_unlock_irqrestore(&lchip->lock, flags);
+
+	ret &= bits;
+	return ret;
+}
+
+unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits)
+{
+	struct locomo *lchip = locomo_chip_driver(ldev);
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+	ret = locomo_readl(lchip->base + LOCOMO_GPO);
+	spin_unlock_irqrestore(&lchip->lock, flags);
+
+	ret &= bits;
+	return ret;
+}
+
+void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set)
+{
+	struct locomo *lchip = locomo_chip_driver(ldev);
+	unsigned long flags;
+	unsigned int r;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+
+	r = locomo_readl(lchip->base + LOCOMO_GPO);
+	if (set)
+		r |= bits;
+	else
+		r &= ~bits;
+	locomo_writel(r, lchip->base + LOCOMO_GPO);
+
+	spin_unlock_irqrestore(&lchip->lock, flags);
+}
+
+static void locomo_m62332_sendbit(void *mapbase, int bit)
+{
+	unsigned int r;
+
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+
+	if (bit & 1) {
+		r = locomo_readl(mapbase + LOCOMO_DAC);
+		r |=  LOCOMO_DAC_SDAOEB;
+		locomo_writel(r, mapbase + LOCOMO_DAC);
+		udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	} else {
+		r = locomo_readl(mapbase + LOCOMO_DAC);
+		r &=  ~(LOCOMO_DAC_SDAOEB);
+		locomo_writel(r, mapbase + LOCOMO_DAC);
+		udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	}
+
+	udelay(DAC_DATA_SETUP_TIME);	/* 250 nsec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/*  4.0 usec */
+}
+
+void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel)
+{
+	struct locomo *lchip = locomo_chip_driver(ldev);
+	int i;
+	unsigned char data;
+	unsigned int r;
+	void *mapbase = lchip->base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+
+	/* Start */
+	udelay(DAC_BUS_FREE_TIME);	/* 5.0 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.0 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SDAOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_START_HOLD_TIME);	/* 5.0 usec */
+	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */
+
+	/* Send slave address and W bit (LSB is W bit) */
+	data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT;
+	for (i = 1; i <= 8; i++) {
+		locomo_m62332_sendbit(mapbase, data >> (8 - i));
+	}
+
+	/* Check A bit */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SDAOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
+	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
+		printk(KERN_WARNING "locomo: m62332_senddata Error 1\n");
+		return;
+	}
+
+	/* Send Sub address (LSB is channel select) */
+	/*    channel = 0 : ch1 select              */
+	/*            = 1 : ch2 select              */
+	data = M62332_SUB_ADDR + channel;
+	for (i = 1; i <= 8; i++) {
+		locomo_m62332_sendbit(mapbase, data >> (8 - i));
+	}
+
+	/* Check A bit */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SDAOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
+	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
+		printk(KERN_WARNING "locomo: m62332_senddata Error 2\n");
+		return;
+	}
+
+	/* Send DAC data */
+	for (i = 1; i <= 8; i++) {
+		locomo_m62332_sendbit(mapbase, dac_data >> (8 - i));
+	}
+
+	/* Check A bit */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SDAOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
+	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
+		printk(KERN_WARNING "locomo: m62332_senddata Error 3\n");
+		return;
+	}
+
+	/* stop */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r &=  ~(LOCOMO_DAC_SCLOEB);
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SDAOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */
+
+	r = locomo_readl(mapbase + LOCOMO_DAC);
+	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
+	locomo_writel(r, mapbase + LOCOMO_DAC);
+	udelay(DAC_LOW_SETUP_TIME);	/* 1000 nsec */
+	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
+
+	spin_unlock_irqrestore(&lchip->lock, flags);
+}
+
 /*
  *	LoCoMo "Register Access Bus."
  *
@@ -755,3 +1051,8 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.e
 
 EXPORT_SYMBOL(locomo_driver_register);
 EXPORT_SYMBOL(locomo_driver_unregister);
+EXPORT_SYMBOL(locomo_gpio_set_dir);
+EXPORT_SYMBOL(locomo_gpio_read_level);
+EXPORT_SYMBOL(locomo_gpio_read_output);
+EXPORT_SYMBOL(locomo_gpio_write);
+EXPORT_SYMBOL(locomo_m62332_senddata);
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
--- a/arch/arm/common/rtctime.c
+++ b/arch/arm/common/rtctime.c
@@ -94,24 +94,29 @@ void rtc_time_to_tm(unsigned long time, 
 EXPORT_SYMBOL(rtc_time_to_tm);
 
 /*
- * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ * Does the rtc_time represent a valid date/time?
  */
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+int rtc_valid_tm(struct rtc_time *tm)
 {
-	unsigned int yrs = tm->tm_year + 1900;
-
-	*time = 0;
-
-	if (yrs < 1970 ||
+	if (tm->tm_year < 70 ||
 	    tm->tm_mon >= 12 ||
 	    tm->tm_mday < 1 ||
-	    tm->tm_mday > month_days(tm->tm_mon, yrs) ||
+	    tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) ||
 	    tm->tm_hour >= 24 ||
 	    tm->tm_min >= 60 ||
 	    tm->tm_sec >= 60)
 		return -EINVAL;
 
-	*time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday,
+	return 0;
+}
+EXPORT_SYMBOL(rtc_valid_tm);
+
+/*
+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ */
+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 		       tm->tm_hour, tm->tm_min, tm->tm_sec);
 
 	return 0;
@@ -136,15 +141,21 @@ void rtc_next_alarm_time(struct rtc_time
 	next->tm_sec = alrm->tm_sec;
 }
 
-static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
+static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
 	memset(tm, 0, sizeof(struct rtc_time));
-	ops->read_time(tm);
+	return ops->read_time(tm);
 }
 
 static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
-	return ops->set_time(tm);
+	int ret;
+
+	ret = rtc_valid_tm(tm);
+	if (ret == 0)
+		ret = ops->set_time(tm);
+
+	return ret;
 }
 
 static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
@@ -152,8 +163,7 @@ static inline int rtc_read_alarm(struct 
 	int ret = -EINVAL;
 	if (ops->read_alarm) {
 		memset(alrm, 0, sizeof(struct rtc_wkalrm));
-		ops->read_alarm(alrm);
-		ret = 0;
+		ret = ops->read_alarm(alrm);
 	}
 	return ret;
 }
@@ -272,7 +282,9 @@ static int rtc_ioctl(struct inode *inode
 		break;
 
 	case RTC_RD_TIME:
-		rtc_read_time(ops, &tm);
+		ret = rtc_read_time(ops, &tm);
+		if (ret)
+			break;
 		ret = copy_to_user(uarg, &tm, sizeof(tm));
 		if (ret)
 			ret = -EFAULT;
@@ -412,17 +424,16 @@ static int rtc_read_proc(char *page, cha
 	struct rtc_wkalrm alrm;
 	struct rtc_time tm;
 	char *p = page;
-	int len;
-
-	rtc_read_time(ops, &tm);
 
-	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,
-		rtc_epoch);
+	if (rtc_read_time(ops, &tm) == 0) {
+		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,
+			rtc_epoch);
+	}
 
 	if (rtc_read_alarm(ops, &alrm) == 0) {
 		p += sprintf(p, "alrm_time\t: ");
@@ -461,13 +472,7 @@ static int rtc_read_proc(char *page, cha
 	if (ops->proc)
 		p += ops->proc(p);
 
-	len = (p - page) - off;
-	if (len < 0)
-		len = 0;
-	*eof = len <= count;
-	*start = page + off;
-
-	return len;
+	return p - page;
 }
 
 int register_rtc(struct rtc_ops *ops)
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -800,7 +800,7 @@ struct sa1111_save_data {
 
 #ifdef CONFIG_PM
 
-static int sa1111_suspend(struct device *dev, u32 state, u32 level)
+static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct sa1111 *sachip = dev_get_drvdata(dev);
 	struct sa1111_save_data *save;
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -15,47 +15,52 @@
 #include <asm/io.h>
 #include <asm/hardware/scoop.h>
 
-static void __iomem *scoop_io_base;
+#define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
 
-#define SCOOP_REG(adr) (*(volatile unsigned short*)(scoop_io_base+(adr)))
+struct  scoop_dev {
+	void  *base;
+	spinlock_t scoop_lock;
+	u32 scoop_gpwr;
+};
 
-void reset_scoop(void)
+void reset_scoop(struct device *dev)
 {
-	SCOOP_REG(SCOOP_MCR) = 0x0100;	// 00
-	SCOOP_REG(SCOOP_CDR) = 0x0000;  // 04
-	SCOOP_REG(SCOOP_CPR) = 0x0000;  // 0C
-	SCOOP_REG(SCOOP_CCR) = 0x0000;  // 10
-	SCOOP_REG(SCOOP_IMR) = 0x0000;  // 18
-	SCOOP_REG(SCOOP_IRM) = 0x00FF;  // 14
-	SCOOP_REG(SCOOP_ISR) = 0x0000;  // 1C
-	SCOOP_REG(SCOOP_IRM) = 0x0000;
-}
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
 
-static DEFINE_SPINLOCK(scoop_lock);
-static u32 scoop_gpwr;
+	SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100;  // 00
+	SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000;  // 04
+	SCOOP_REG(sdev->base,SCOOP_CPR) = 0x0000;  // 0C
+	SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000;  // 10
+	SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000;  // 18
+	SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF;  // 14
+	SCOOP_REG(sdev->base,SCOOP_ISR) = 0x0000;  // 1C
+	SCOOP_REG(sdev->base,SCOOP_IRM) = 0x0000;
+}
 
-unsigned short set_scoop_gpio(unsigned short bit)
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
 {
 	unsigned short gpio_bit;
 	unsigned long flag;
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
 
-	spin_lock_irqsave(&scoop_lock, flag);
-	gpio_bit = SCOOP_REG(SCOOP_GPWR) | bit;
-	SCOOP_REG(SCOOP_GPWR) = gpio_bit;
-	spin_unlock_irqrestore(&scoop_lock, flag);
+	spin_lock_irqsave(&sdev->scoop_lock, flag);
+	gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) | bit;
+	SCOOP_REG(sdev->base, SCOOP_GPWR) = gpio_bit;
+	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
 
 	return gpio_bit;
 }
 
-unsigned short reset_scoop_gpio(unsigned short bit)
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
 {
 	unsigned short gpio_bit;
 	unsigned long flag;
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
 
-	spin_lock_irqsave(&scoop_lock, flag);
-	gpio_bit = SCOOP_REG(SCOOP_GPWR) & ~bit;
-	SCOOP_REG(SCOOP_GPWR) = gpio_bit;
-	spin_unlock_irqrestore(&scoop_lock, flag);
+	spin_lock_irqsave(&sdev->scoop_lock, flag);
+	gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) & ~bit;
+	SCOOP_REG(sdev->base,SCOOP_GPWR) = gpio_bit;
+	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
 
 	return gpio_bit;
 }
@@ -63,25 +68,30 @@ unsigned short reset_scoop_gpio(unsigned
 EXPORT_SYMBOL(set_scoop_gpio);
 EXPORT_SYMBOL(reset_scoop_gpio);
 
-unsigned short read_scoop_reg(unsigned short reg)
+unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
 {
-	return SCOOP_REG(reg);
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	return SCOOP_REG(sdev->base,reg);
 }
 
-void write_scoop_reg(unsigned short reg, unsigned short data)
+void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
 {
-	SCOOP_REG(reg)=data;
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	SCOOP_REG(sdev->base,reg)=data;
 }
 
 EXPORT_SYMBOL(reset_scoop);
 EXPORT_SYMBOL(read_scoop_reg);
 EXPORT_SYMBOL(write_scoop_reg);
 
+#ifdef CONFIG_PM
 static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level)
 {
 	if (level == SUSPEND_POWER_DOWN) {
-		scoop_gpwr = SCOOP_REG(SCOOP_GPWR);
-		SCOOP_REG(SCOOP_GPWR) = 0;
+		struct scoop_dev *sdev = dev_get_drvdata(dev);
+
+		sdev->scoop_gpwr = SCOOP_REG(sdev->base,SCOOP_GPWR);
+		SCOOP_REG(sdev->base,SCOOP_GPWR) = 0;
 	}
 	return 0;
 }
@@ -89,13 +99,20 @@ static int scoop_suspend(struct device *
 static int scoop_resume(struct device *dev, uint32_t level)
 {
 	if (level == RESUME_POWER_ON) {
-		SCOOP_REG(SCOOP_GPWR) = scoop_gpwr;
+		struct scoop_dev *sdev = dev_get_drvdata(dev);
+
+		SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
 	}
 	return 0;
 }
+#else
+#define scoop_suspend	NULL
+#define scoop_resume	NULL
+#endif
 
 int __init scoop_probe(struct device *dev)
 {
+	struct scoop_dev *devptr;
 	struct scoop_config *inf;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -103,25 +120,50 @@ int __init scoop_probe(struct device *de
 	if (!mem)
 		return -EINVAL;
 
+	devptr = kmalloc(sizeof(struct scoop_dev), GFP_KERNEL);
+
+	if (!devptr)
+		return  -ENOMEM;
+
+	memset(devptr, 0, sizeof(struct scoop_dev));
+	spin_lock_init(&devptr->scoop_lock);
+
 	inf = dev->platform_data;
-	scoop_io_base = ioremap(mem->start, 0x1000);
-	if (!scoop_io_base)
+	devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
+
+	if (!devptr->base) {
+		kfree(devptr);
 		return -ENOMEM;
+	}
 
-	SCOOP_REG(SCOOP_MCR) = 0x0140;
+	dev_set_drvdata(dev, devptr);
 
-	reset_scoop();
+	printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
 
-	SCOOP_REG(SCOOP_GPCR) = inf->io_dir & 0xffff;
-	SCOOP_REG(SCOOP_GPWR) = inf->io_out & 0xffff;
+	SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
+	reset_scoop(dev);
+	SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
+	SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
 
 	return 0;
 }
 
+static int scoop_remove(struct device *dev)
+{
+	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	if (sdev) {
+		iounmap(sdev->base);
+		kfree(sdev);
+		dev_set_drvdata(dev, NULL);
+	}
+	return 0;
+}
+
 static struct device_driver scoop_driver = {
 	.name		= "sharp-scoop",
 	.bus		= &platform_bus_type,
 	.probe		= scoop_probe,
+	.remove 	= scoop_remove,
 	.suspend	= scoop_suspend,
 	.resume		= scoop_resume,
 };
diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/common/sharpsl_param.c
@@ -0,0 +1,60 @@
+/*
+ * Hardware parameter area specific to Sharp SL series devices
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches
+ *
+ * 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/kernel.h>
+#include <linux/string.h>
+#include <asm/mach/sharpsl_param.h>
+
+/*
+ * Certain hardware parameters determined at the time of device manufacture,
+ * typically including LCD parameters are loaded by the bootloader at the
+ * address PARAM_BASE. As the kernel will overwrite them, we need to store
+ * them early in the boot process, then pass them to the appropriate drivers.
+ * Not all devices use all paramaters but the format is common to all.
+ */
+#ifdef ARCH_SA1100
+#define PARAM_BASE	0xe8ffc000
+#else
+#define PARAM_BASE	0xa0000a00
+#endif
+#define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 )  | ( b << 8 ) | a )
+
+#define COMADJ_MAGIC	MAGIC_CHG('C','M','A','D')
+#define UUID_MAGIC	MAGIC_CHG('U','U','I','D')
+#define TOUCH_MAGIC	MAGIC_CHG('T','U','C','H')
+#define AD_MAGIC	MAGIC_CHG('B','V','A','D')
+#define PHAD_MAGIC	MAGIC_CHG('P','H','A','D')
+
+struct sharpsl_param_info sharpsl_param;
+
+void sharpsl_save_param(void)
+{
+	memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info));
+
+	if (sharpsl_param.comadj_keyword != COMADJ_MAGIC)
+		sharpsl_param.comadj=-1;
+
+	if (sharpsl_param.phad_keyword != PHAD_MAGIC)
+		sharpsl_param.phadadj=-1;
+
+	if (sharpsl_param.uuid_keyword != UUID_MAGIC)
+		sharpsl_param.uuid[0]=-1;
+
+	if (sharpsl_param.touch_keyword != TOUCH_MAGIC)
+		sharpsl_param.touch_xp=-1;
+
+	if (sharpsl_param.adadj_keyword != AD_MAGIC)
+		sharpsl_param.adadj=-1;
+}
+
+
diff --git a/arch/arm/configs/a5k_defconfig b/arch/arm/configs/a5k_defconfig
deleted file mode 100644
--- a/arch/arm/configs/a5k_defconfig
+++ /dev/null
@@ -1,522 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_ARM=y
-# CONFIG_SBUS is not set
-CONFIG_UID16=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_OBSOLETE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-CONFIG_ARCH_ARCA5K=y
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-# CONFIG_ARCH_ARC is not set
-CONFIG_ARCH_A5K=y
-
-#
-# Footbridge Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-CONFIG_ARCH_ACORN=y
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-# CONFIG_CPU_32 is not set
-CONFIG_CPU_26=y
-# CONFIG_PAGESIZE_16 is not set
-
-#
-# Processor Type
-#
-# CONFIG_DISCONTIGMEM is not set
-
-#
-# General setup
-#
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_ELF is not set
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
-
-#
-# Parallel port support
-#
-CONFIG_PARPORT=m
-CONFIG_PARPORT_PC=m
-# CONFIG_PARPORT_PC_FIFO is not set
-CONFIG_PARPORT_PC_SUPERIO=y
-# CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_SUNBPP is not set
-# CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 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=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_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Acorn-specific block devices
-#
-# CONFIG_BLK_DEV_FD1772 is not set
-CONFIG_BLK_DEV_MFM=m
-CONFIG_BLK_DEV_MFM_AUTODETECT=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK 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 is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE 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_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED 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_NET_SB1000 is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_ETHER1=y
-CONFIG_ARM_ETHER3=y
-# CONFIG_ARM_ETHERH 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_AT1700 is not set
-# CONFIG_DEPCA 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_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ATA/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_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
-
-#
-# 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_IDE_ICSIDE=y
-# CONFIG_BLK_DEV_IDEDMA_ICS is not set
-# CONFIG_IDEDMA_ICS_AUTO is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_BLK_DEV_IDE_RAPIDE is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_ATOMWIDE_SERIAL is not set
-# CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_CHARDEV=y
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-# CONFIG_PSMOUSE is not set
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_JOYSTICK is not set
-
-#
-# Input core support is needed for joysticks
-#
-# 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
-# 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=y
-CONFIG_ADFS_FS=y
-# 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_FAT_FS=m
-CONFIG_MSDOS_FS=m
-# 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_CRAMFS is not set
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG 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_SYSV_FS_WRITE 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_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 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_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ADFS=y
-CONFIG_ACORN_PARTITION_ICS=y
-CONFIG_ACORN_PARTITION_POWERTEC=y
-CONFIG_ACORN_PARTITION_RISCIX=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_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_950 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_8 is not set
-# CONFIG_NLS_ISO8859_9 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_UTF8 is not set
-
-#
-# Console drivers
-#
-CONFIG_FB=y
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_ACORN=y
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_MFB=y
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
-CONFIG_FBCON_CFB8=y
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# Kernel hacking
-#
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_NO_PGT_CACHE=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/assabet_defconfig b/arch/arm/configs/assabet_defconfig
--- a/arch/arm/configs/assabet_defconfig
+++ b/arch/arm/configs/assabet_defconfig
@@ -1,22 +1,26 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Wed Mar  9 13:13:30 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,16 +29,22 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -43,106 +53,52 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 CONFIG_SA1100_ASSABET=y
 # CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HACKKIT is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
 # CONFIG_SA1100_SSP is not set
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-# CONFIG_SA1100_USB_CHAR is not set
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Feature Selections
-#
-
-#
-# S3C2410 Implementations
-#
 
 #
 # Processor Type
@@ -152,6 +108,7 @@ CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
 CONFIG_CPU_MINICACHE=y
 
@@ -160,60 +117,86 @@ CONFIG_CPU_MINICACHE=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttySA0,38400n8 initrd=0xc0800000,3M root=/dev/ram"
+# CONFIG_XIP_KERNEL is not set
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_SA1110=y
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEBUG is not set
 # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
 # CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_24_API=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_SA1110=y
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=y
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_SA1100=y
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_FW_LOADER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="mem=32M console=ttySA0,38400n8 initrd=0xc0800000,3M root=/dev/ram"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -223,6 +206,9 @@ CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -246,10 +232,12 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-# CONFIG_MTD_CFI_B2 is not set
-CONFIG_MTD_CFI_B4=y
-# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 # CONFIG_MTD_CFI_I1 is not set
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
@@ -257,10 +245,11 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -275,8 +264,10 @@ CONFIG_MTD_SA1100=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -291,6 +282,11 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -300,12 +296,58 @@ CONFIG_MTD_SA1100=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -313,6 +355,18 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -335,6 +389,9 @@ CONFIG_INET=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -354,12 +411,12 @@ CONFIG_INET=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -411,11 +468,9 @@ CONFIG_IRLAN=m
 #
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
-# CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
 # CONFIG_ALI_FIR is not set
 CONFIG_SA1100_FIR=m
-# CONFIG_VIA_FIR is not set
 # CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
@@ -436,6 +491,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -485,51 +541,6 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -559,7 +570,6 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
@@ -596,7 +606,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -609,17 +618,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-CONFIG_SA1100_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
 
 #
@@ -634,12 +638,8 @@ CONFIG_SA1100_RTC=y
 # CONFIG_I2C is not set
 
 #
-# L3 serial bus support
+# Misc devices
 #
-CONFIG_L3=y
-CONFIG_L3_ALGOBIT=y
-CONFIG_L3_BIT_SA1100_GPIO=y
-CONFIG_BIT_SA1100_GPIO=y
 
 #
 # Multimedia devices
@@ -652,6 +652,60 @@ CONFIG_BIT_SA1100_GPIO=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
 # MMC/SD Card support
 #
 # CONFIG_MMC is not set
@@ -665,10 +719,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -684,6 +743,7 @@ CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 # CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
 # CONFIG_NTFS_FS is not set
 
 #
@@ -694,6 +754,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -711,6 +772,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -727,14 +793,13 @@ CONFIG_NFS_FS=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -752,7 +817,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -786,6 +850,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -807,84 +872,19 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_SA1100=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-CONFIG_SOUND_SA1100=y
-CONFIG_SOUND_UDA1341=y
-CONFIG_SOUND_ASSABET_UDA1341=y
-# CONFIG_SOUND_SA1100SSP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-CONFIG_MCP=y
-CONFIG_MCP_SA1100=y
-CONFIG_MCP_UCB1200=y
-CONFIG_MCP_UCB1200_AUDIO=m
-CONFIG_MCP_UCB1200_TS=y
-
-#
-# Console Switches
-#
-CONFIG_SWITCHES=y
-CONFIG_SWITCHES_SA1100=y
-CONFIG_SWITCHES_UCB1X00=y
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -893,8 +893,14 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+CONFIG_CRC_CCITT=m
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig
--- a/arch/arm/configs/badge4_defconfig
+++ b/arch/arm/configs/badge4_defconfig
@@ -1,41 +1,67 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc6-git3
+# Thu Jun  9 19:00:50 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -43,161 +69,137 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 CONFIG_SA1100_BADGE4=y
 # CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
-CONFIG_SA1111=y
-CONFIG_FORCE_MAX_ZONEORDER=9
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_H3600_SLEEVE is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_AUTCPU12 is not set
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_FORTUNET is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+# CONFIG_SA1100_SSP is not set
 
 #
 # Processor Type
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
-# CONFIG_XSCALE_PMU is not set
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
 
 #
-# General setup
+# Processor Features
+#
+CONFIG_SA1111=y
+CONFIG_DMABOUNCE=y
+CONFIG_FORCE_MAX_ZONEORDER=9
+
+#
+# Bus support
 #
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_FIQ is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
-CONFIG_HOTPLUG=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_SA1100=y
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=y
-CONFIG_PCMCIA_PROBE=y
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-# CONFIG_PCMCIA_CLPS6700 is not set
-CONFIG_PCMCIA_SA1100=y
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-CONFIG_FPE_FASTFPE=m
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=m
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
 CONFIG_BINFMT_MISC=m
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_APM is not set
 CONFIG_ARTHUR=m
-CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-CONFIG_PARPORT=m
-# CONFIG_PARPORT_PC is not set
-# CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_GSC is not set
-# CONFIG_PARPORT_SUNBPP is not set
-# CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -205,9 +207,10 @@ CONFIG_PARPORT=m
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
@@ -217,6 +220,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -229,51 +233,49 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-CONFIG_MTD_CFI_B2=y
-# CONFIG_MTD_CFI_B4 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 CONFIG_MTD_CFI_I1=y
 # CONFIG_MTD_CFI_I2 is not set
 # CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_2PARTS_IPAQ is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_EPXA10DB is not set
-# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD 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
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -281,190 +283,211 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_NOT_PC=y
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play support
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS 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_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# 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
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
-# Networking options
+# ATA/ATAPI/MFM/RLL support
 #
-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 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_IDE=m
+CONFIG_BLK_DEV_IDE=m
 
 #
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+
 #
+# IDE chipset support/bugfixes
 #
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# QoS and/or fair queueing
+# SCSI device support
 #
-# CONFIG_NET_SCHED is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
 
 #
-# Network device support
+# SCSI support type (disk, tape, CD-ROM)
 #
-CONFIG_NETDEVICES=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
 
 #
-# ARCnet devices
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-# 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
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
 
 #
-# Ethernet (10 or 100Mbit)
+# SCSI Transport Attributes
 #
-# CONFIG_NET_ETHERNET is not set
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
-# Ethernet (1000 Mbit)
+# SCSI low-level drivers
 #
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA 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_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Multi-device support (RAID and LVM)
 #
-CONFIG_NET_RADIO=y
-# CONFIG_STRIP 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_MD is not set
 
 #
-# Wireless ISA/PCI cards support
+# Fusion MPT device support
 #
-# CONFIG_WAVELAN is not set
-# CONFIG_AIRO is not set
-CONFIG_HERMES=y
 
 #
-# Wireless Pcmcia/Cardbus cards support
+# IEEE 1394 (FireWire) support
 #
-CONFIG_PCMCIA_NETWAVE=m
-CONFIG_PCMCIA_WAVELAN=m
-CONFIG_PCMCIA_HERMES=y
-CONFIG_AIRO_CS=m
-CONFIG_NET_WIRELESS=y
 
 #
-# Token Ring devices
+# I2O device support
 #
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
+# Networking support
 #
-# CONFIG_WAN is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
 
 #
-# PCMCIA network device support
+# SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=y
-CONFIG_PCMCIA_3C574=m
-CONFIG_PCMCIA_FMVJ18X=m
-CONFIG_PCMCIA_PCNET=y
-CONFIG_PCMCIA_NMCLAN=m
-CONFIG_PCMCIA_SMC91C92=m
-CONFIG_PCMCIA_XIRC2PS=m
-CONFIG_PCMCIA_AXNET=m
-# CONFIG_ARCNET_COM20020_CS is not set
-# CONFIG_PCMCIA_IBMTR is not set
-CONFIG_NET_PCMCIA_RADIO=y
-CONFIG_PCMCIA_RAYCS=m
-# CONFIG_AIRONET4500_CS is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
 
 #
-# Amateur Radio support
+# QoS and/or fair queueing
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# IrDA (infrared) support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
 CONFIG_IRDA=y
 
 #
 # IrDA protocols
 #
 CONFIG_IRLAN=y
-# CONFIG_IRNET is not set
 CONFIG_IRCOMM=y
 CONFIG_IRDA_ULTRA=y
 
@@ -483,139 +506,107 @@ CONFIG_IRDA_ULTRA=y
 # SIR device drivers
 #
 # CONFIG_IRTTY_SIR is not set
-# CONFIG_IRPORT_SIR is not set
 
 #
 # Dongle support
 #
-# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
 
 #
 # FIR device drivers
 #
 # CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
-# CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
 # CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
 CONFIG_SA1100_FIR=y
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+# CONFIG_BT_SCO is not set
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BT_BNEP is not set
+# CONFIG_BT_HIDP is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Bluetooth device drivers
 #
-CONFIG_IDE=m
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+CONFIG_BT_HCIVHCI=m
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
-# IDE, ATA and ATAPI Block devices
+# ARCnet devices
 #
-CONFIG_BLK_DEV_IDE=m
+# CONFIG_ARCNET is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Ethernet (10 or 100Mbit)
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=m
-CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
 
 #
-# IDE chipset support/bugfixes
+# Ethernet (1000 Mbit)
 #
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO 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
+# Ethernet (10000 Mbit)
 #
-CONFIG_SCSI=y
 
 #
-# SCSI support type (disk, tape, CD-ROM)
+# Token Ring devices
 #
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_SR_EXTRA_DEVS=2
-CONFIG_CHR_DEV_SG=y
+# CONFIG_TR is not set
 
 #
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
+CONFIG_NET_RADIO=y
 
 #
-# SCSI low-level drivers
+# Obsolete Wireless cards support (pre-802.11)
 #
-# 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_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_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_NCR53C7xx 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_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
 
 #
-# PCMCIA SCSI adapter support
+# Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_SCSI_PCMCIA is not set
+# CONFIG_ATMEL is not set
+CONFIG_NET_WIRELESS=y
 
 #
-# I2O device support
+# Wan interfaces
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+# CONFIG_WAN is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
@@ -626,129 +617,152 @@ CONFIG_CHR_DEV_SG=y
 # Input device 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_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_GAMEPORT_PCIGAME is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461x is not set
+
+#
+# Hardware I/O ports
+#
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_SERPORT is not set
+# CONFIG_GAMEPORT is not set
 
 #
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=115200
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_ATOMWIDE_SERIAL is not set
-# CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_PRINTER is not set
 # CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
-# I2C support
+# IPMI
 #
-CONFIG_I2C=m
-CONFIG_I2C_ALGOBIT=m
-# CONFIG_I2C_BIT_SA1100_GPIO is not set
-CONFIG_I2C_ALGOPCF=m
-CONFIG_I2C_ELEKTOR=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_PROC=m
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# L3 serial bus support
+# Watchdog Cards
 #
-CONFIG_L3=y
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Other L3 adapters
+# Watchdog Device Drivers
 #
-CONFIG_L3_SA1111=y
-# CONFIG_BIT_SA1100_GPIO is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SA1100_WATCHDOG=m
 
 #
-# Mice
+# ISA-based Watchdog Cards
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
 
 #
-# Watchdog Cards
+# USB-based Watchdog Cards
 #
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-CONFIG_SOFT_WATCHDOG=m
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_21285_WATCHDOG is not set
-# CONFIG_977_WATCHDOG is not set
-CONFIG_SA1100_WATCHDOG=m
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_INTEL_RNG is not set
+# CONFIG_USBPCWATCHDOG is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=m
-CONFIG_SA1100_RTC=m
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# PCMCIA character devices
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ELEKTOR=m
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Misc devices
 #
 
 #
@@ -759,27 +773,18 @@ CONFIG_VIDEO_DEV=y
 #
 # Video For Linux
 #
-CONFIG_VIDEO_PROC_FS=y
-# CONFIG_I2C_PARPORT is not set
 
 #
 # Video Adapters
 #
-# CONFIG_VIDEO_BT848 is not set
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_VIDEO_BWQCAM is not set
 # CONFIG_VIDEO_CQCAM is not set
 # CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_TUNER_3036 is not set
-# CONFIG_VIDEO_STRADIS is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIDEO_ZORAN_BUZ is not set
-# CONFIG_VIDEO_ZORAN_DC10 is not set
-# CONFIG_VIDEO_ZORAN_LML33 is not set
-# CONFIG_VIDEO_ZR36120 is not set
-# CONFIG_VIDEO_MEYE is not set
-# CONFIG_VIDEO_CYBERPRO is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
 
 #
 # Radio Adapters
@@ -789,215 +794,54 @@ CONFIG_VIDEO_PROC_FS=y
 # CONFIG_RADIO_RTRACK2 is not set
 # CONFIG_RADIO_AZTECH is not set
 # CONFIG_RADIO_GEMTEK is not set
-# CONFIG_RADIO_GEMTEK_PCI is not set
-# CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
-# CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_MIROPCM20_RDS is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
 # CONFIG_RADIO_ZOLTRIX is not set
 
 #
-# File systems
+# Digital Video Broadcasting Devices
 #
-# 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=m
-CONFIG_JBD=m
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-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_MINIX_FS=m
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=m
-# 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_DVB is not set
 
 #
-# Network File Systems
+# Graphics support
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=m
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=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 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 is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
+# CONFIG_FB is not set
 
 #
-# Native Language Support
+# Sound
 #
-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_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
+CONFIG_SOUND=y
 
 #
-# Sound
+# Advanced Linux Sound Architecture
 #
-CONFIG_SOUND=y
+# CONFIG_SND is not set
 
 #
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=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_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_SA1100=y
-CONFIG_SOUND_UDA1341=y
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
-# CONFIG_SOUND_H3600_UDA1341 is not set
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-CONFIG_SOUND_SA1111_UDA1341=y
-# CONFIG_SOUND_STORK_UDA1341 is not set
-# CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_STORK_AC97 is not set
 # CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
 # CONFIG_SOUND_TVMIXER is not set
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Multimedia Capabilities Port drivers
-#
-CONFIG_MCP=y
-CONFIG_MCP_SA1100=y
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_SOUND_AD1980 is not set
 
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 
@@ -1006,75 +850,105 @@ CONFIG_USB_DEBUG=y
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
 #
-# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_OHCI_HCD is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-CONFIG_USB_OHCI_SA1111=y
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
 #
 CONFIG_USB_AUDIO=y
-CONFIG_USB_BLUETOOTH=m
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+# CONFIG_USB_MIDI is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DEBUG=y
 # 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_USBAT 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
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
+# CONFIG_USB_HID is not set
 
 #
-#   Input core support is needed for USB HID
+# USB HID Boot Protocol drivers
 #
 
 #
 # USB Imaging devices
 #
-CONFIG_USB_DC2XX=m
 CONFIG_USB_MDC800=m
-CONFIG_USB_SCANNER=m
 CONFIG_USB_MICROTEK=m
-CONFIG_USB_HPUSBSCSI=m
 
 #
 # USB Multimedia devices
 #
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
 CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
 CONFIG_USB_OV511=m
-CONFIG_USB_PWC=m
 CONFIG_USB_SE401=m
+# CONFIG_USB_SN9C102 is not set
 # CONFIG_USB_STV680 is not set
-CONFIG_USB_VICAM=m
-CONFIG_USB_DSBR=m
-CONFIG_USB_DABUSB=m
-CONFIG_USB_KONICAWC=m
+CONFIG_USB_PWC=m
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_KAWETH=m
 CONFIG_USB_CATC=m
-CONFIG_USB_CDCETHER=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+# CONFIG_USB_RTL8150 is not set
 CONFIG_USB_USBNET=m
 
 #
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+CONFIG_USB_KC2190=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
 # USB port drivers
 #
 CONFIG_USB_USS720=m
@@ -1084,17 +958,24 @@ CONFIG_USB_USS720=m
 #
 CONFIG_USB_SERIAL=m
 CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRPRIME is not set
 CONFIG_USB_SERIAL_BELKIN=m
 CONFIG_USB_SERIAL_WHITEHEAT=m
 CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
 CONFIG_USB_SERIAL_EMPEG=m
 CONFIG_USB_SERIAL_FTDI_SIO=m
 CONFIG_USB_SERIAL_VISOR=m
 # CONFIG_USB_SERIAL_IPAQ is not set
 CONFIG_USB_SERIAL_IR=m
 CONFIG_USB_SERIAL_EDGEPORT=m
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
 CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR 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
@@ -1102,53 +983,265 @@ CONFIG_USB_SERIAL_KEYSPAN=m
 # 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_KEYSPAN_USA49WLC is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
 CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
 
 #
 # USB Miscellaneous drivers
 #
-CONFIG_USB_RIO500=m
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_AUERSWALD is not set
+CONFIG_USB_RIO500=m
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_TEST is not set
 
 #
-# Bluetooth support
+# USB ATM/DSL drivers
 #
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
 
 #
-# Bluetooth device drivers
+# USB Gadget Support
 #
-CONFIG_BT_HCIUSB=m
-CONFIG_BT_HCIUART=m
-CONFIG_BT_HCIVHCI=m
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_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 is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+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_ASCII 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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
-CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
 
 #
 # Library routines
 #
-# CONFIG_CRC32 is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/bast_defconfig b/arch/arm/configs/bast_defconfig
--- a/arch/arm/configs/bast_defconfig
+++ b/arch/arm/configs/bast_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Mon Nov 15 15:32:48 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 02:24:16 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,7 +28,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
@@ -35,6 +35,7 @@ CONFIG_KOBJECT_UEVENT=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -44,6 +45,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -85,12 +87,21 @@ CONFIG_ARCH_S3C2410=y
 #
 CONFIG_ARCH_BAST=y
 # CONFIG_ARCH_H1940 is not set
+# CONFIG_MACH_N30 is not set
 # CONFIG_ARCH_SMDK2410 is not set
+# CONFIG_ARCH_S3C2440 is not set
 CONFIG_MACH_VR1000=y
 # CONFIG_MACH_RX3715 is not set
+# CONFIG_MACH_OTOM is not set
+# CONFIG_MACH_NEXCODER_2440 is not set
 CONFIG_CPU_S3C2410=y
 
 #
+# S3C2410 Boot
+#
+# CONFIG_S3C2410_BOOT_WATCHDOG is not set
+
+#
 # S3C2410 Setup
 #
 CONFIG_S3C2410_DMA=y
@@ -120,53 +131,74 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 # CONFIG_XIP_KERNEL is not set
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 CONFIG_APM=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-CONFIG_PARPORT=y
-# CONFIG_PARPORT_PC is not set
-# CONFIG_PARPORT_ARC is not set
-CONFIG_PARPORT_OTHER=y
-CONFIG_PARPORT_1284=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 # CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -206,6 +238,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
 # CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -225,6 +258,7 @@ CONFIG_MTD_BAST_MAXSIZE=4
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -243,6 +277,16 @@ CONFIG_MTD_NAND_S3C2410=y
 # CONFIG_MTD_NAND_S3C2410_DEBUG is not set
 # CONFIG_MTD_NAND_S3C2410_HWECC is not set
 # CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_1284=y
 
 #
 # Plug and Play support
@@ -253,10 +297,12 @@ CONFIG_MTD_NAND_S3C2410=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
@@ -269,6 +315,39 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDE_BAST=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -276,6 +355,19 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -380,51 +472,6 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDETAPE=m
-CONFIG_BLK_DEV_IDEFLOPPY=m
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDE_BAST=y
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -447,17 +494,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -475,6 +511,17 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -485,9 +532,9 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
-# CONFIG_DIGI is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
@@ -554,6 +601,11 @@ CONFIG_S3C2410_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -582,11 +634,14 @@ CONFIG_I2C_S3C2410=y
 CONFIG_I2C_SENSOR=m
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 CONFIG_SENSORS_LM75=m
@@ -599,6 +654,7 @@ CONFIG_SENSORS_LM85=m
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -617,6 +673,10 @@ CONFIG_SENSORS_EEPROM=m
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -627,6 +687,53 @@ CONFIG_SENSORS_EEPROM=m
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -640,6 +747,10 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -692,6 +803,7 @@ CONFIG_JFFS_FS_VERBOSE=0
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -713,7 +825,6 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -793,62 +904,20 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
@@ -870,6 +939,10 @@ CONFIG_DEBUG_S3C2410_UART=0
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/cerfcube_defconfig b/arch/arm/configs/cerfcube_defconfig
--- a/arch/arm/configs/cerfcube_defconfig
+++ b/arch/arm/configs/cerfcube_defconfig
@@ -1,35 +1,51 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 14:19:40 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -39,94 +55,54 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 CONFIG_SA1100_CERF=y
 # CONFIG_SA1100_CERF_FLASH_8MB is not set
 CONFIG_SA1100_CERF_FLASH_16MB=y
 # CONFIG_SA1100_CERF_FLASH_32MB is not set
-# CONFIG_SA1100_CERF_CPLD is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HACKKIT is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
 # CONFIG_SA1100_SSP is not set
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-# CONFIG_SA1100_USB_CHAR is not set
 
 #
 # Processor Type
@@ -136,6 +112,7 @@ CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
 CONFIG_CPU_MINICACHE=y
 
@@ -144,69 +121,105 @@ CONFIG_CPU_MINICACHE=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+
+#
+# PC-card bridges
+#
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=m
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,38400 root=/dev/mtdblock3 rootfstype=jffs2 rw mem=32M init=/linuxrc"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_SA1110=y
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_24_API=y
-CONFIG_HOTPLUG=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_SA1110=y
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=m
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_SA1100=m
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 # CONFIG_FPE_NWFPE is not set
 CONFIG_FPE_FASTFPE=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_FW_LOADER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,38400 root=/dev/mtdblock3 rootfstype=jffs2 rw mem=32M init=/linuxrc"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -226,13 +239,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -247,8 +271,10 @@ CONFIG_MTD_SA1100=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -263,6 +289,11 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -272,12 +303,57 @@ CONFIG_MTD_SA1100=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -285,6 +361,18 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -307,23 +395,24 @@ CONFIG_IP_PNP_RARP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -332,37 +421,42 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
-# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -372,7 +466,6 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-CONFIG_CS8900=m
 # CONFIG_NET_POCKET is not set
 
 #
@@ -382,25 +475,16 @@ CONFIG_CS8900=m
 #
 # Ethernet (10000 Mbit)
 #
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # PCMCIA network device support
@@ -408,60 +492,18 @@ CONFIG_CS8900=m
 # CONFIG_NET_PCMCIA is not set
 
 #
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# I2O device support
+# Wan interfaces
 #
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Input device support
@@ -477,19 +519,10 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -499,6 +532,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -514,42 +554,13 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_DZ is not set
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# L3 serial bus support
-#
-CONFIG_L3=m
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
 # IPMI
@@ -561,40 +572,27 @@ CONFIG_L3=m
 #
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
 CONFIG_SA1100_WATCHDOG=m
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
 # CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_ALIM1535_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
+# CONFIG_WDT is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_SA1100_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
 
 #
@@ -604,6 +602,20 @@ CONFIG_SA1100_WATCHDOG=m
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -614,6 +626,35 @@ CONFIG_SA1100_WATCHDOG=m
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
 # MMC/SD Card support
 #
 # CONFIG_MMC is not set
@@ -632,10 +673,16 @@ CONFIG_JBD=m
 CONFIG_FS_MBCACHE=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -651,16 +698,19 @@ CONFIG_ROMFS_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -670,6 +720,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -677,6 +728,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -694,18 +750,19 @@ CONFIG_NFS_V4=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V4=y
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=m
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_GSS is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 # CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -723,17 +780,15 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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 is not set
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -758,6 +813,7 @@ CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -774,69 +830,76 @@ CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
+# Profiling support
 #
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
 #
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
 
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/clps7500_defconfig b/arch/arm/configs/clps7500_defconfig
--- a/arch/arm/configs/clps7500_defconfig
+++ b/arch/arm/configs/clps7500_defconfig
@@ -1,17 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 17:20:48 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_OBSOLETE=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -21,138 +53,177 @@ CONFIG_OBSOLETE=y
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 CONFIG_ARCH_CLPS7500=y
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_FTVPCI is not set
-# CONFIG_ARCH_TBOX is not set
-# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM710=y
+CONFIG_CPU_32v3=y
+CONFIG_CPU_CACHE_V3=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V3=y
+CONFIG_CPU_TLB_V3=y
 
 #
-# Archimedes/A5000 Implementations
+# Processor Features
 #
+CONFIG_TIMER_ACORN=y
 
 #
-# Footbridge Implementations
+# Bus support
 #
+CONFIG_ISA=y
 
 #
-# SA11x0 Implementations
+# PCCARD (PCMCIA/CardBus) support
 #
+# CONFIG_PCCARD is not set
 
 #
-# CLPS711X/EP721X Implementations
+# Kernel Features
 #
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Processor Type
+# Boot options
 #
-CONFIG_CPU_32v3=y
-# CONFIG_CPU_32v4 is not set
-# CONFIG_CPU_ARM610 is not set
-CONFIG_CPU_ARM710=y
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-# CONFIG_CPU_SA1100 is not set
-# CONFIG_DISCONTIGMEM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=16M root=nfs"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# General setup
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+
+#
+# Userspace binary formats
 #
-CONFIG_ANGELBOOT=y
-# CONFIG_PCI is not set
-CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="mem=16M root=nfs"
-# CONFIG_ALIGNMENT_TRAP is not set
 
 #
-# Parallel port support
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Device Drivers
 #
-CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_FIFO=y
-# CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_SUNBPP is not set
-# CONFIG_PARPORT_OTHER is not set
-CONFIG_PARPORT_1284=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
 
 #
-# Disk-On-Chip Device Drivers
+# User Modules And Translation Layers
 #
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_CHAR is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
-# RAM/ROM Device Drivers
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+
+#
+# Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PMC551_BUGFIX is not set
-# CONFIG_MTD_PMC551_DEBUG is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
-# Linearly Mapped Flash Device Drivers
+# Disk-On-Chip Device Drivers
 #
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
-# Drivers for chip mappings
+# NAND Flash Device Drivers
 #
+# CONFIG_MTD_NAND is not set
 
 #
-# User modules and translation layers for MTD devices
+# Parallel port support
 #
-# CONFIG_MTD_CHAR is not set
-# CONFIG_MTD_BLOCK is not set
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_1284=y
 
 #
-# Plug and Play configuration
+# Plug and Play support
 #
 # CONFIG_PNP is not set
 
@@ -162,77 +233,136 @@ CONFIG_MTD=y
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_FLD7500 is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # 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_INET_ECN is not set
+# CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
+# CONFIG_NETFILTER is not set
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -242,18 +372,34 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 CONFIG_CS89x0=y
-# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=y
 # CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
@@ -263,183 +409,340 @@ CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 # CONFIG_SLIP_SMART is not set
 # CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# Wireless LAN (non-hamradio)
+# ISDN subsystem
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_ISDN is not set
 
 #
-# Token Ring devices
+# Input device support
 #
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+CONFIG_INPUT=y
 
 #
-# Wan interfaces
+# Userland interfaces
 #
-# CONFIG_WAN is not set
-# CONFIG_ASH is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_RPCKBD=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# Amateur Radio support
+# Character devices
 #
-# CONFIG_HAMRADIO is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# IrDA (infrared) support
+# Serial drivers
 #
-# CONFIG_IRDA is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Non-8250 serial port support
 #
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
-# SCSI support
+# IPMI
 #
-# CONFIG_SCSI is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# I2O device support
+# Watchdog Cards
 #
-# CONFIG_I2O is not set
+# 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
 
 #
-# ISDN subsystem
+# Ftape, the floppy tape device driver
 #
-# CONFIG_ISDN is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Input core support
+# TPM devices
 #
-# CONFIG_INPUT is not set
+# CONFIG_TCG_TPM is not set
 
 #
-# Character devices
+# I2C support
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=y
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
 
 #
-# I2C support
+# I2C Algorithms
 #
-CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
-# Mice
+# I2C Hardware Bus support
 #
-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 is not set
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# Joysticks
+# Misc devices
 #
 
 #
-# Game port support
+# Multimedia devices
 #
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Gameport joysticks
+# Digital Video Broadcasting Devices
 #
+# CONFIG_DVB is not set
 
 #
-# Serial port support
+# Graphics support
 #
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_ACORN=y
+# CONFIG_FB_VIRTUAL is not set
 
 #
-# Serial port joysticks
+# Console display driver support
 #
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Parallel port joysticks
+# Sound
 #
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_SOUND is not set
 
 #
-# Watchdog Cards
+# USB support
 #
-# CONFIG_WATCHDOG is not set
-CONFIG_CLPS7500_FLASH=y
-# 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
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
 
 #
-# Multimedia devices
+# USB Gadget Support
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_FAT_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_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-CONFIG_MINIX_FS=y
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS 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_UFS_FS is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-CONFIG_ROOT_NFS=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
+CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -451,66 +754,50 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION 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_SMB_NLS is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# Console drivers
+# Profiling support
 #
-CONFIG_PC_KEYB=y
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FB=y
+# CONFIG_PROFILING is not set
 
 #
-# Frame-buffer support
+# Kernel hacking
 #
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_ACORN=y
-# CONFIG_CHRONTEL_7003 is not set
-# CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-CONFIG_FBCON_MFB=y
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-# 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
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
 
 #
-# Sound
+# Security options
 #
-# CONFIG_SOUND is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB support
+# Cryptographic options
 #
-# CONFIG_USB is not set
+# CONFIG_CRYPTO is not set
 
 #
-# Kernel hacking
+# Hardware crypto devices
 #
-# CONFIG_FRAME_POINTER is not set
-# CONFIG_DEBUG_ERRORS is not set
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_LL=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig
--- a/arch/arm/configs/ebsa110_defconfig
+++ b/arch/arm/configs/ebsa110_defconfig
@@ -1,40 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 18:29:48 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -43,12 +53,12 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -58,6 +68,7 @@ CONFIG_ARCH_EBSA110=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -66,7 +77,9 @@ CONFIG_ARCH_EBSA110=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Processor Type
@@ -76,6 +89,7 @@ CONFIG_CPU_SA110=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WB=y
 
@@ -84,54 +98,85 @@ CONFIG_CPU_TLB_V4WB=y
 #
 
 #
-# General setup
+# Bus support
 #
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=m
+CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+
+#
+# PC-card bridges
+#
 CONFIG_I82365=m
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_PROBE=y
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 CONFIG_FPE_FASTFPE=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
 
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
 
 #
 # Parallel port support
 #
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
 CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_PC_PCMCIA is not set
 # CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 CONFIG_PARPORT_1284=y
 
 #
@@ -145,11 +190,29 @@ CONFIG_PARPORT_1284=y
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -157,6 +220,18 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -174,7 +249,6 @@ CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_FWMARK=y
-CONFIG_IP_ROUTE_NAT=y
 # CONFIG_IP_ROUTE_MULTIPATH is not set
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
@@ -189,6 +263,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+CONFIG_IP_TCPDIAG_IPV6=y
 
 #
 # IP: Virtual Server Configuration
@@ -199,6 +276,7 @@ CONFIG_IPV6=y
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
 # CONFIG_IPV6_TUNNEL is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
@@ -207,6 +285,9 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
 CONFIG_IP_NF_FTP=y
 CONFIG_IP_NF_IRC=y
 # CONFIG_IP_NF_TFTP is not set
@@ -231,8 +312,16 @@ CONFIG_IP_NF_MATCH_HELPER=y
 CONFIG_IP_NF_MATCH_STATE=y
 CONFIG_IP_NF_MATCH_CONNTRACK=y
 # CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_TCPMSS=y
 CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
@@ -248,14 +337,11 @@ CONFIG_IP_NF_TARGET_ECN=y
 CONFIG_IP_NF_TARGET_DSCP=y
 CONFIG_IP_NF_TARGET_MARK=y
 CONFIG_IP_NF_TARGET_CLASSIFY=y
-CONFIG_IP_NF_TARGET_LOG=y
-# CONFIG_IP_NF_TARGET_ULOG is not set
-CONFIG_IP_NF_TARGET_TCPMSS=y
-# CONFIG_IP_NF_ARPTABLES is not set
 # CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP6_NF_QUEUE is not set
 CONFIG_IP6_NF_IPTABLES=y
@@ -294,12 +380,12 @@ CONFIG_IP6_NF_TARGET_MARK=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -330,6 +416,7 @@ CONFIG_ARM_AM79C961A=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -387,24 +474,6 @@ CONFIG_PPP_BSDCOMP=m
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -415,20 +484,11 @@ CONFIG_PPP_BSDCOMP=m
 # CONFIG_INPUT is not set
 
 #
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
+# Hardware I/O ports
 #
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
 
 #
 # Character devices
@@ -457,7 +517,6 @@ CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -483,16 +542,12 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_WDT is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
 
 #
@@ -502,11 +557,20 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -517,6 +581,33 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -524,10 +615,15 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 
@@ -540,7 +636,8 @@ CONFIG_AUTOFS4_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -581,9 +678,10 @@ CONFIG_NFS_V3=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
+CONFIG_LOCKD_V4=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -601,7 +699,6 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -618,39 +715,19 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -659,8 +736,13 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+CONFIG_CRC_CCITT=m
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=m
diff --git a/arch/arm/configs/edb7211_defconfig b/arch/arm/configs/edb7211_defconfig
--- a/arch/arm/configs/edb7211_defconfig
+++ b/arch/arm/configs/edb7211_defconfig
@@ -1,17 +1,49 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 21:48:12 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -21,81 +53,116 @@ CONFIG_EXPERIMENTAL=y
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+CONFIG_ARCH_CLPS711X=y
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-CONFIG_ARCH_CLPS711X=y
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CEIVA is not set
+# CONFIG_ARCH_CLEP7312 is not set
+CONFIG_ARCH_EDB7211=y
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+CONFIG_ARCH_EP7211=y
+# CONFIG_EP72XX_ROM_BOOT is not set
 
 #
-# Archimedes/A5000 Implementations
+# Processor Type
 #
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
 
 #
-# Footbridge Implementations
+# Processor Features
 #
+CONFIG_ARM_THUMB=y
 
 #
-# SA11x0 Implementations
+# Bus support
 #
+CONFIG_ISA=y
 
 #
-# CLPS711X/EP721X Implementations
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_ARCH_EDB7211=y
-CONFIG_EP7211_BOOT_MODE=y
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_ACORN is not set
-CONFIG_ARCH_EP7211=y
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-CONFIG_CPU_ARM720T=y
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-# CONFIG_CPU_SA1100 is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
 CONFIG_DISCONTIGMEM=y
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# General setup
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
 #
-# CONFIG_ANGELBOOT is not set
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -103,77 +170,133 @@ CONFIG_ALIGNMENT_TRAP=y
 # CONFIG_MTD is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # 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_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 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_INET_ECN is not set
+# CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -183,121 +306,105 @@ CONFIG_NETDEVICES=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# 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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# IrDA (infrared) support
+# Wan interfaces
 #
-# CONFIG_IRDA is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# ISDN subsystem
 #
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_ISDN is not set
 
 #
-# SCSI support
+# Input device support
 #
-# CONFIG_SCSI is not set
+# CONFIG_INPUT is not set
 
 #
-# I2O device support
+# Hardware I/O ports
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# ISDN subsystem
+# Character devices
 #
-# CONFIG_ISDN is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Input core support
+# Serial drivers
 #
-# CONFIG_INPUT is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Character devices
+# Non-8250 serial port support
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_SERIAL_CLPS711X=y
 CONFIG_SERIAL_CLPS711X_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# I2C support
+# IPMI
 #
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_JOYSTICK is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER 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
 # 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
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
@@ -305,68 +412,109 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_VIDEO_DEV is not set
 
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS 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_CRAMFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-CONFIG_MINIX_FS=y
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS 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_SYSV_FS_WRITE 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_NFS_FS is not set
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS 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_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -378,23 +526,50 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION 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_SMB_NLS is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# USB support
+# Profiling support
 #
-# CONFIG_USB is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_LL=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig
--- a/arch/arm/configs/enp2611_defconfig
+++ b/arch/arm/configs/enp2611_defconfig
@@ -1,10 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:08:24 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,20 +28,24 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -64,7 +73,9 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -87,6 +98,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -98,51 +110,75 @@ CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -181,6 +217,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -200,6 +237,7 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -214,6 +252,11 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -225,13 +268,31 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -239,6 +300,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -265,6 +340,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -284,8 +362,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -336,7 +412,6 @@ CONFIG_NET_PCI=y
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -348,7 +423,6 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -361,6 +435,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -410,25 +485,6 @@ CONFIG_DLCI_MAX=8
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -451,14 +507,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -468,6 +516,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -489,7 +544,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -515,7 +569,6 @@ CONFIG_IXP2000_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -523,11 +576,15 @@ CONFIG_IXP2000_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -538,6 +595,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -563,6 +621,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -570,20 +629,29 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -602,6 +670,10 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -612,6 +684,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -628,10 +727,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -656,6 +760,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -673,6 +778,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -695,9 +801,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -735,49 +841,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -786,6 +874,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ep80219_defconfig b/arch/arm/configs/ep80219_defconfig
--- a/arch/arm/configs/ep80219_defconfig
+++ b/arch/arm/configs/ep80219_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Thu Jan  6 10:54:33 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:34:12 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,13 +28,13 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -43,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -117,49 +119,75 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
 # CONFIG_XIP_KERNEL is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -198,6 +226,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -218,6 +247,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -232,6 +262,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -243,6 +278,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
@@ -260,6 +296,78 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# 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_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -279,6 +387,22 @@ CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_SNAPSHOT is not set
 # CONFIG_DM_MIRROR is not set
 # CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
 
 #
 # Networking support
@@ -381,7 +505,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-CONFIG_E100_NAPI=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -437,94 +560,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# 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_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA 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_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR 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_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -547,13 +582,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -563,6 +591,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -609,6 +644,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -659,7 +699,9 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -672,6 +714,8 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -691,6 +735,10 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -701,6 +749,39 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -714,7 +795,12 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 CONFIG_XFS_SECURITY=y
@@ -765,6 +851,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -831,51 +918,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
@@ -891,6 +939,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/epxa10db_defconfig b/arch/arm/configs/epxa10db_defconfig
--- a/arch/arm/configs/epxa10db_defconfig
+++ b/arch/arm/configs/epxa10db_defconfig
@@ -1,37 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:46:51 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -41,30 +53,33 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 CONFIG_ARCH_CAMELOT=y
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Epxa10db
@@ -77,28 +92,6 @@ CONFIG_PLD=y
 # CONFIG_PLD_HOTSWAP is not set
 
 #
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
 # Processor Type
 #
 CONFIG_CPU_32=y
@@ -106,6 +99,7 @@ CONFIG_CPU_ARM922T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -118,35 +112,62 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyUA0,115200 initrd=0x00200000,8M root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="mem=32M console=ttyUA0,115200 initrd=0x00200000,8M root=/dev/ram0 rw"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -154,6 +175,11 @@ CONFIG_ALIGNMENT_TRAP=y
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -161,12 +187,30 @@ CONFIG_ALIGNMENT_TRAP=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -174,6 +218,18 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -197,23 +253,24 @@ CONFIG_IP_PNP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -222,17 +279,22 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -251,68 +313,31 @@ CONFIG_NETDEVICES=y
 #
 # Ethernet (10000 Mbit)
 #
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
 
 #
-# Token Ring devices
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO 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
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
@@ -337,16 +362,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -356,6 +371,15 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -380,12 +404,6 @@ CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
 # IPMI
 #
 # CONFIG_IPMI_HANDLER is not set
@@ -396,25 +414,30 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -425,6 +448,39 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -433,10 +489,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 
@@ -449,13 +510,15 @@ CONFIG_AUTOFS4_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
@@ -484,7 +547,6 @@ CONFIG_RAMFS=y
 #
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
 CONFIG_SMB_FS=y
 # CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_CIFS is not set
@@ -496,6 +558,7 @@ CONFIG_SMB_FS=y
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -525,6 +588,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -546,41 +610,19 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -589,8 +631,14 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+CONFIG_CRC_CCITT=y
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig
--- a/arch/arm/configs/footbridge_defconfig
+++ b/arch/arm/configs/footbridge_defconfig
@@ -1,101 +1,186 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:02:24 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
 CONFIG_ARCH_FOOTBRIDGE=y
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_CLPS711X is not set
-
-#
-# Archimedes/A5000 Implementations
-#
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Footbridge Implementations
 #
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
+CONFIG_ARCH_CATS=y
+CONFIG_ARCH_PERSONAL_SERVER=y
 # CONFIG_ARCH_EBSA285_ADDIN is not set
 CONFIG_ARCH_EBSA285_HOST=y
 CONFIG_ARCH_NETWINDER=y
-
-#
-# SA11x0 Implementations
-#
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_ACORN is not set
 CONFIG_FOOTBRIDGE=y
 CONFIG_FOOTBRIDGE_HOST=y
-# CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_ARCH_EBSA285=y
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
 
 #
 # Processor Type
 #
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32=y
 CONFIG_CPU_SA110=y
-# CONFIG_DISCONTIGMEM is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
 
 #
-# General setup
+# Processor Features
+#
+
+#
+# Bus support
 #
-# CONFIG_ANGELBOOT is not set
-CONFIG_PCI=y
 CONFIG_ISA=y
 CONFIG_ISA_DMA=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_SYSCTL=y
-CONFIG_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
-# CONFIG_ARTHUR is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 # CONFIG_LEDS_CPU is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
 # Parallel port support
 #
 CONFIG_PARPORT=y
@@ -103,22 +188,18 @@ CONFIG_PARPORT_PC=y
 CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_SUNBPP is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 CONFIG_PARPORT_1284=y
 
 #
-# Memory Technology Devices (MTD)
+# Plug and Play support
 #
-# CONFIG_MTD is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
 
 #
-# Plug and Play configuration
+# Protocols
 #
-CONFIG_PNP=y
 CONFIG_ISAPNP=y
 
 #
@@ -143,11 +224,13 @@ CONFIG_PARIDE_PG=m
 #
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
+# CONFIG_PARIDE_BPCK6 is not set
 CONFIG_PARIDE_COMM=m
 CONFIG_PARIDE_DSTR=m
 CONFIG_PARIDE_FIT2=m
 CONFIG_PARIDE_FIT3=m
 CONFIG_PARIDE_EPAT=m
+# CONFIG_PARIDE_EPATC8 is not set
 CONFIG_PARIDE_EPIA=m
 CONFIG_PARIDE_FRIQ=m
 CONFIG_PARIDE_FRPW=m
@@ -158,67 +241,202 @@ CONFIG_PARIDE_ON26=m
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 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_INET_ECN is not set
+# CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-CONFIG_ATM=y
-# CONFIG_ATM_CLIP is not set
-# CONFIG_ATM_LANE is not set
+# CONFIG_NETFILTER is not set
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
+# CONFIG_IP_SCTP is not set
+CONFIG_ATM=y
+# CONFIG_ATM_CLIP is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_BR2684 is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
-CONFIG_NETDEVICES=y
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
 
 #
-# ARCnet devices
+# IrDA protocols
 #
-# CONFIG_ARCNET is not set
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+CONFIG_WINBOND_FIR=m
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -226,9 +444,17 @@ CONFIG_NETDEVICES=y
 # CONFIG_NET_SB1000 is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
 CONFIG_NET_VENDOR_3COM=y
 # CONFIG_EL1 is not set
 # CONFIG_EL2 is not set
@@ -236,313 +462,359 @@ CONFIG_NET_VENDOR_3COM=y
 # CONFIG_EL16 is not set
 # CONFIG_EL3 is not set
 # CONFIG_3C515 is not set
-# CONFIG_ELMC is not set
-# CONFIG_ELMC_II is not set
 CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_CS89x0 is not set
-CONFIG_TULIP=m
-# CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
-# CONFIG_EEPRO100_PM is not set
-# CONFIG_LNE390 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 CONFIG_NE2K_PCI=y
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
-# CONFIG_RTL8129 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_WINBOND_840 is not set
-# CONFIG_HAPPYMEAL 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_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
 # CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
 CONFIG_PPP_ASYNC=m
 # CONFIG_PPP_SYNC_TTY is not set
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPPOE=m
+# CONFIG_PPPOATM is not set
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
 CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
+# ISDN subsystem
 #
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_ISDN is not set
 
 #
-# Wan interfaces
+# Input device support
 #
-# CONFIG_WAN is not set
+CONFIG_INPUT=y
 
 #
-# Amateur Radio support
+# Userland interfaces
 #
-# CONFIG_HAMRADIO is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# IrDA (infrared) support
+# Character devices
 #
-CONFIG_IRDA=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+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_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
 
 #
-# IrDA protocols
+# Serial drivers
 #
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_OPTIONS=y
+# CONFIG_SERIAL_8250 is not set
 
 #
-#   IrDA options
+# Non-8250 serial port support
 #
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRDA_DEBUG=y
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-# CONFIG_IRTTY_SIR is not set
-# CONFIG_IRPORT_SIR is not set
-
-#
-# FIR device drivers
-#
-# CONFIG_NSC_FIR is not set
-CONFIG_WINBOND_FIR=m
-# CONFIG_TOSHIBA_FIR is not set
-# CONFIG_SMC_IRCC_FIR is not set
-
-#
-# Dongle support
-#
-# CONFIG_DONGLE is not set
+CONFIG_SERIAL_21285=y
+CONFIG_SERIAL_21285_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# IPMI
 #
-CONFIG_IDE=y
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Watchdog Cards
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-# 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_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# IDE chipset support/bugfixes
+# Watchdog Device Drivers
 #
-# 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_IDEPCI_SHARE_IRQ=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_OFFBOARD=y
-CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=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_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-CONFIG_BLK_DEV_CY82C693=y
-# 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_PDC202XX_BURST is not set
-# CONFIG_BLK_DEV_OSB4 is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_SL82C105=y
-# CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDEDMA_IVB is not set
+CONFIG_SOFT_WATCHDOG=y
+CONFIG_21285_WATCHDOG=m
+CONFIG_977_WATCHDOG=m
 
 #
-# SCSI support
+# ISA-based Watchdog Cards
 #
-# CONFIG_SCSI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
 
 #
-# IEEE 1394 (FireWire) support
+# PCI-based Watchdog Cards
 #
-# CONFIG_IEEE1394 is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
 
 #
-# I2O device support
+# USB-based Watchdog Cards
 #
-# 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
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+CONFIG_NWFLASH=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
-# ISDN subsystem
+# Ftape, the floppy tape device driver
 #
-# CONFIG_ISDN is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Input core support
+# TPM devices
 #
-# CONFIG_INPUT 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=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_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_21285=y
-CONFIG_SERIAL_21285_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=m
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
 #
 CONFIG_I2C=m
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
 # CONFIG_I2C_CHARDEV is not set
 
 #
-# Mice
+# I2C Algorithms
 #
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
-# Joysticks
+# I2C Hardware Bus support
 #
-# CONFIG_JOYSTICK is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# Input core support is needed for joysticks
+# Misc devices
 #
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-CONFIG_SOFT_WATCHDOG=y
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_MIXCOMWD is not set
-CONFIG_21285_WATCHDOG=m
-CONFIG_977_WATCHDOG=m
-CONFIG_DS1620=y
-CONFIG_NWBUTTON=y
-CONFIG_NWBUTTON_REBOOT=y
-CONFIG_NWFLASH=m
-# CONFIG_INTEL_RNG is not set
-CONFIG_NVRAM=m
-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
 
 #
 # Multimedia devices
@@ -552,23 +824,27 @@ CONFIG_VIDEO_DEV=m
 #
 # Video For Linux
 #
-CONFIG_VIDEO_PROC_FS=y
-# CONFIG_I2C_PARPORT is not set
 
 #
 # Video Adapters
 #
+# CONFIG_VIDEO_BT848 is not set
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_VIDEO_BWQCAM is not set
 # CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
 # CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_TUNER_3036 is not set
 # CONFIG_VIDEO_STRADIS is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIDEO_BUZ is not set
-# CONFIG_VIDEO_ZR36120 is not set
-CONFIG_VIDEO_CYBERPRO=m
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
 
 #
 # Radio Adapters
@@ -578,85 +854,306 @@ CONFIG_VIDEO_CYBERPRO=m
 # CONFIG_RADIO_RTRACK2 is not set
 # CONFIG_RADIO_AZTECH is not set
 # CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
-# CONFIG_RADIO_MIROPCM20 is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
 # CONFIG_RADIO_ZOLTRIX is not set
 
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO 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
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=m
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB ATM/DSL drivers
+#
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 CONFIG_ADFS_FS=m
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS 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_SYSV_FS_WRITE 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_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-CONFIG_ROOT_NFS=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS 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_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_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
 # CONFIG_ACORN_PARTITION_ICS is not set
 CONFIG_ACORN_PARTITION_ADFS=y
 # CONFIG_ACORN_PARTITION_POWERTEC is not set
@@ -667,16 +1164,19 @@ CONFIG_ACORN_PARTITION_ADFS=y
 # 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 is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
-CONFIG_NLS=y
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -693,11 +1193,15 @@ CONFIG_NLS_CODEPAGE_852=m
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 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_ASCII is not set
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_2=m
 # CONFIG_NLS_ISO8859_3 is not set
@@ -705,173 +1209,49 @@ CONFIG_NLS_ISO8859_2=m
 # CONFIG_NLS_ISO8859_5 is not set
 # CONFIG_NLS_ISO8859_6 is not set
 # CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 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=m
 # CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
+# Profiling support
 #
-CONFIG_PC_KEYB=y
-CONFIG_PC_KEYMAP=y
-CONFIG_VGA_CONSOLE=y
-CONFIG_FB=y
+# CONFIG_PROFILING 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_ACORN is not set
-# CONFIG_FB_CLPS711X is not set
-CONFIG_FB_CYBER2000=y
-# CONFIG_FB_SA1100 is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-# CONFIG_FBCON_CFB32 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=y
-# CONFIG_FBCON_HGA is not set
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_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_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_SOUND_OSS=m
-# CONFIG_SOUND_TRACEINIT is not set
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_SGALAXY is not set
-CONFIG_SOUND_ADLIB=m
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_PAS_JOYSTICK is not set
-# CONFIG_SOUND_PSS is not set
-CONFIG_SOUND_SB=m
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_YMPCI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-CONFIG_SOUND_WAVEARTIST=m
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# USB support
-#
-CONFIG_USB=m
-CONFIG_USB_DEBUG=y
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-
-#
-# USB Controllers
+# Kernel hacking
 #
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=m
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 
 #
-# USB Devices
+# Security options
 #
-CONFIG_USB_PRINTER=m
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-CONFIG_USB_AUDIO=m
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_NET1080 is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB Human Interface Devices (HID)
+# Cryptographic options
 #
+# CONFIG_CRYPTO is not set
 
 #
-#   Input core support is needed for USB HID
+# Hardware crypto devices
 #
 
 #
-# Kernel hacking
+# Library routines
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/arm/configs/fortunet_defconfig b/arch/arm/configs/fortunet_defconfig
--- a/arch/arm/configs/fortunet_defconfig
+++ b/arch/arm/configs/fortunet_defconfig
@@ -1,33 +1,58 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:51:10 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 # CONFIG_MODULES is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 CONFIG_ARCH_CLPS711X=y
 # CONFIG_ARCH_CO285 is not set
@@ -35,135 +60,122 @@ CONFIG_ARCH_CLPS711X=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
-
-#
-# SA11x0 Implementations
-#
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
-# CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_H3100 is not set
-# CONFIG_SA1100_H3600 is not set
-# CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
-# CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
-# CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
-# CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
-# CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_H3600_SLEEVE is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
 # CONFIG_ARCH_AUTCPU12 is not set
 # CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CEIVA is not set
 # CONFIG_ARCH_CLEP7312 is not set
 # CONFIG_ARCH_EDB7211 is not set
 # CONFIG_ARCH_P720T is not set
 CONFIG_ARCH_FORTUNET=y
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
 CONFIG_CPU_ARM720T=y
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
+
+#
+# Processor Features
+#
 # CONFIG_ARM_THUMB is not set
-# CONFIG_DISCONTIGMEM is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 # CONFIG_FPE_NWFPE is not set
 CONFIG_FPE_FASTFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
 # CONFIG_MTD_PARTITIONS is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_BOOTLDR_PARTS is not set
-# CONFIG_MTD_AFS_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
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -172,40 +184,48 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-CONFIG_MTD_FORTUNET=y
-# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -213,157 +233,166 @@ CONFIG_MTD_FORTUNET=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
-# 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_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI 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
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 # CONFIG_PACKET is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 # CONFIG_INET is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_NETFILTER is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET_AUNUDP is not set
-# CONFIG_ECONET_NATIVE is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 # CONFIG_NETDEVICES is not set
 
 #
-# Amateur Radio support
+# ISDN subsystem
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_ISDN is not set
 
 #
-# IrDA (infrared) support
+# Input device support
 #
-# CONFIG_IRDA is not set
+# CONFIG_INPUT is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Hardware I/O ports
 #
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# SCSI support
+# Character devices
 #
-# CONFIG_SCSI is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Synchronous Serial Interface
+# Serial drivers
 #
-# CONFIG_SSI is not set
-# CONFIG_SSI_CLPS711X is not set
-# CONFIG_SSI_JUNO is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# I2O device support
+# Non-8250 serial port support
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+CONFIG_SERIAL_CLPS711X=y
+CONFIG_SERIAL_CLPS711X_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# ISDN subsystem
+# IPMI
 #
-# CONFIG_ISDN is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# Input core support
+# Watchdog Cards
 #
-# 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_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
 
 #
-# Character devices
+# Ftape, the floppy tape device driver
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Serial drivers
+# TPM devices
 #
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-CONFIG_SERIAL_CLPS711X=y
-CONFIG_SERIAL_CLPS711X_CONSOLE=y
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
-# CONFIG_SERIAL_SA1100 is not set
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -371,219 +400,159 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
-# L3 serial bus support
+# Misc devices
+#
+
+#
+# Multimedia devices
 #
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
-# CONFIG_L3_SA1111 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Mice
+# Digital Video Broadcasting Devices
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
 
 #
-# Joysticks
+# Graphics support
 #
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_FB is not set
 
 #
-# Watchdog Cards
+# Sound
 #
-# 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
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+# CONFIG_SOUND is not set
 
 #
-# Ftape, the floppy tape device driver
+# USB support
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
 
 #
-# Multimedia devices
+# USB Gadget Support
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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
-# CONFIG_REISERFS_PROC_INFO is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_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 is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG 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 is not set
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Profiling support
 #
-# CONFIG_MCP is not set
-# CONFIG_MCP_SA1100 is not set
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_PROFILING is not set
 
 #
-# USB support
+# Kernel hacking
 #
-# CONFIG_USB is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_SA1111 is not set
-# 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
-# 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
-# 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
-# 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
-# CONFIG_USB_RIO500 is not set
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 
 #
-# Bluetooth support
+# Security options
 #
-# CONFIG_BT is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# Kernel hacking
+# Cryptographic options
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_NO_PGT_CACHE is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_ERRORS is not set
-# CONFIG_DEBUG_LL is not set
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
-# CONFIG_DEBUG_LL_SER3 is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/h3600_defconfig b/arch/arm/configs/h3600_defconfig
--- a/arch/arm/configs/h3600_defconfig
+++ b/arch/arm/configs/h3600_defconfig
@@ -1,33 +1,66 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc4
+# Thu Jun  9 01:59:03 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -35,144 +68,158 @@ CONFIG_MODULES=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
 CONFIG_SA1100_H3600=y
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_H3800 is not set
+CONFIG_SA1100_H3XXX=y
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-# CONFIG_SA1100_USB_CHAR is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+# CONFIG_SA1100_SSP is not set
+# CONFIG_H3600_SLEEVE is not set
 
 #
 # Processor Type
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# General setup
+# Processor Features
+#
+
+#
+# Bus support
 #
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-CONFIG_CPU_FREQ=y
-CONFIG_HOTPLUG=y
+CONFIG_ISA_DMA_API=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
-# CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 
 #
-# At least one math emulation must be selected
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_SA1100=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-CONFIG_PM=y
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_BOOTLDR_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
@@ -182,6 +229,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -194,49 +242,49 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-# CONFIG_MTD_CFI_B2 is not set
-CONFIG_MTD_CFI_B4=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 # CONFIG_MTD_CFI_I1 is not set
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD 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
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -244,95 +292,208 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS 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_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI 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
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 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_INET_ECN is not set
+# CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
+# CONFIG_NETFILTER is not set
 
 #
+# SCTP Configuration (EXPERIMENTAL)
 #
-#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
-CONFIG_NETDEVICES=y
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
 
 #
-# ARCnet devices
+# IrDA protocols
 #
-# CONFIG_ARCNET is not set
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+CONFIG_SA1100_FIR=m
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 # CONFIG_NET_ETHERNET is not set
@@ -340,43 +501,20 @@ CONFIG_NETDEVICES=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# 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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # PCMCIA network device support
@@ -389,316 +527,318 @@ CONFIG_PCMCIA_PCNET=y
 # 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
+# CONFIG_PCMCIA_AXNET is not set
 
 #
-# IrDA (infrared) support
+# Wan interfaces
 #
-CONFIG_IRDA=m
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# IrDA protocols
+# ISDN subsystem
 #
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-# CONFIG_IRDA_ULTRA is not set
-# CONFIG_IRDA_OPTIONS is not set
+# CONFIG_ISDN is not set
 
 #
-# Infrared-port device drivers
+# Input device support
 #
+CONFIG_INPUT=y
 
 #
-# SIR device drivers
+# Userland interfaces
 #
-# CONFIG_IRTTY_SIR is not set
-# CONFIG_IRPORT_SIR is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# Dongle support
+# Input Device Drivers
 #
-# CONFIG_DONGLE is not set
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# FIR device drivers
+# Character devices
 #
-# 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_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
-CONFIG_SA1100_FIR=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Serial drivers
 #
-CONFIG_IDE=m
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
-# IDE, ATA and ATAPI Block devices
+# Non-8250 serial port support
 #
-CONFIG_BLK_DEV_IDE=m
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# IPMI
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# IDE chipset support/bugfixes
+# Watchdog Cards
 #
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO 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
+# 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
 
 #
-# SCSI support
+# Ftape, the floppy tape device driver
 #
-# CONFIG_SCSI is not set
+# CONFIG_DRM is not set
 
 #
-# I2O device support
+# PCMCIA character devices
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# ISDN subsystem
+# TPM devices
 #
-# CONFIG_ISDN is not set
 
 #
-# Input core support
+# I2C 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_I2C is not set
 
 #
-# Character devices
+# Misc devices
 #
-CONFIG_VT=y
-# CONFIG_VT_CONSOLE is not set
-CONFIG_SERIAL=m
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Serial drivers
+# Multimedia devices
 #
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
-CONFIG_SERIAL_SA1100=y
-CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=38400
-CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_VIDEO_DEV is not set
 
 #
-# I2C support
+# Digital Video Broadcasting Devices
 #
-# CONFIG_I2C is not set
+# CONFIG_DVB is not set
 
 #
-# L3 serial bus support
+# Graphics support
 #
-CONFIG_L3=y
-CONFIG_L3_ALGOBIT=y
-CONFIG_L3_BIT_SA1100_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
-# Other L3 adapters
+# Console display driver support
 #
-# CONFIG_L3_SA1111 is not set
-CONFIG_BIT_SA1100_GPIO=y
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
 
 #
-# Mice
+# Logo configuration
 #
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=m
-# CONFIG_PSMOUSE is not set
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Joysticks
+# Sound
 #
-# CONFIG_INPUT_GAMEPORT is not set
+CONFIG_SOUND=y
 
 #
-# Input core support is needed for gameports
+# Advanced Linux Sound Architecture
 #
+# CONFIG_SND is not set
 
 #
-# Input core support is needed for joysticks
+# Open Sound System
 #
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_SOUND_PRIME is not set
 
 #
-# Watchdog Cards
+# USB support
 #
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_SA1100_RTC=m
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
 
 #
-# Ftape, the floppy tape device driver
+# USB Gadget Support
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+# CONFIG_USB_GADGET is not set
 
 #
-# PCMCIA character devices
+# MMC/SD Card support
 #
-# CONFIG_PCMCIA_SERIAL_CS is not set
-# CONFIG_MWAVE is not set
+# CONFIG_MMC is not set
 
 #
-# Multimedia devices
+# File systems
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
 
 #
-# File systems
+# XFS support
 #
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=m
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS 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_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=y
+CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 # CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
-CONFIG_ZLIB_FS_INFLATE=m
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_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=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -721,7 +861,9 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -738,209 +880,40 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
-#
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_ACORN is not set
-# CONFIG_FB_CLPS711X is not set
-CONFIG_FB_SA1100=y
-# CONFIG_FB_CYBER2000 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 is not set
-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=y
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-
-#
-# 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_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_SA1100=y
-CONFIG_SOUND_UDA1341=y
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
-CONFIG_SOUND_H3600_UDA1341=y
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-# CONFIG_SOUND_SA1111_UDA1341 is not set
-# CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-# CONFIG_MCP_SA1100 is not set
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_SA1111 is not set
-
-#
-# USB Device Class drivers
+# Profiling support
 #
-# 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
+# CONFIG_PROFILING 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
+# Kernel hacking
 #
-# CONFIG_USB_USS720 is not set
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
 
 #
-# USB Serial Converter support
+# Security options
 #
-# 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
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB Miscellaneous drivers
+# Cryptographic options
 #
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_ID75 is not set
+# CONFIG_CRYPTO is not set
 
 #
-# Bluetooth support
+# Hardware crypto devices
 #
-# CONFIG_BT is not set
 
 #
-# Kernel hacking
+# Library routines
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_NO_PGT_CACHE is not set
-# CONFIG_DEBUG_LL is not set
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/h7201_defconfig b/arch/arm/configs/h7201_defconfig
--- a/arch/arm/configs/h7201_defconfig
+++ b/arch/arm/configs/h7201_defconfig
@@ -1,12 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc1
-# Thu Sep  2 11:04:11 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:11:33 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -18,24 +20,28 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -44,6 +50,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -58,6 +65,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -66,7 +74,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_IMX is not set
 CONFIG_ARCH_H720X=y
 
@@ -85,6 +93,7 @@ CONFIG_CPU_ARM720T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_LV4T=y
 CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WT=y
 CONFIG_CPU_TLB_V4WT=y
 
@@ -94,46 +103,62 @@ CONFIG_CPU_TLB_V4WT=y
 CONFIG_ARM_THUMB=y
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=y
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_TCIC is not set
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -141,8 +166,8 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=0
-CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -184,6 +209,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -201,6 +227,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +242,11 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -222,27 +254,32 @@ CONFIG_MTD_CFI_UTIL=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# CONFIG_MD is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# Networking support
+# SCSI device support
 #
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_SCSI is not set
 
 #
-# SCSI device support
+# Multi-device support (RAID and LVM)
 #
-# CONFIG_SCSI is not set
+# CONFIG_MD is not set
 
 #
 # Fusion MPT device support
@@ -257,6 +294,13 @@ CONFIG_BLK_DEV_INITRD=y
 #
 
 #
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
 # ISDN subsystem
 #
 
@@ -278,16 +322,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -297,6 +331,15 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -315,7 +358,6 @@ CONFIG_HW_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -328,21 +370,19 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# PCMCIA character devices
+# TPM devices
 #
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -350,6 +390,10 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -359,6 +403,49 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -367,10 +454,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -412,6 +504,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -427,6 +520,7 @@ CONFIG_JFFS2_RTIME=y
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -439,61 +533,19 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -502,6 +554,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/h7202_defconfig b/arch/arm/configs/h7202_defconfig
--- a/arch/arm/configs/h7202_defconfig
+++ b/arch/arm/configs/h7202_defconfig
@@ -1,12 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc1
-# Thu Sep 30 10:30:42 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:15:45 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -18,26 +20,31 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -46,6 +53,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -60,6 +68,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -68,7 +77,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_IMX is not set
 CONFIG_ARCH_H720X=y
 
@@ -77,8 +86,8 @@ CONFIG_ARCH_H720X=y
 #
 # CONFIG_ARCH_H7201 is not set
 CONFIG_ARCH_H7202=y
-# CONFIG_ARCH_FU7202 is not set
 CONFIG_CPU_H7202=y
+# CONFIG_H7202_SERIAL23 is not set
 
 #
 # Processor Type
@@ -88,6 +97,7 @@ CONFIG_CPU_ARM720T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_LV4T=y
 CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WT=y
 CONFIG_CPU_TLB_V4WT=y
 
@@ -97,47 +107,71 @@ CONFIG_CPU_TLB_V4WT=y
 # CONFIG_ARM_THUMB is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,19200"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,19200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -175,6 +209,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -192,6 +227,7 @@ CONFIG_MTD_H720X=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -206,6 +242,11 @@ CONFIG_MTD_H720X=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -213,9 +254,27 @@ CONFIG_MTD_H720X=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -223,6 +282,18 @@ CONFIG_MTD_H720X=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -249,6 +320,8 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -268,7 +341,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -297,8 +369,6 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_SMC91X is not set
-# CONFIG_CS89x0 is not set
-CONFIG_CIRRUS=y
 
 #
 # Ethernet (1000 Mbit)
@@ -327,23 +397,6 @@ CONFIG_CIRRUS=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -366,17 +419,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_H7202=y
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -394,6 +436,16 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -417,7 +469,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -430,23 +481,30 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -457,6 +515,68 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_USB_G_SERIAL=m
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -465,10 +585,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -495,6 +620,7 @@ CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -512,6 +638,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -534,7 +661,6 @@ CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -548,6 +674,7 @@ CONFIG_SUNRPC=y
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -560,72 +687,20 @@ CONFIG_SUNRPC=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-CONFIG_USB_GADGET=m
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_PXA2XX is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_SA1100 is not set
-CONFIG_USB_GADGET_H7202=y
-CONFIG_USB_H7202=m
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
-CONFIG_USB_ZERO=m
-# CONFIG_USB_ETH is not set
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_FILE_STORAGE_TEST=y
-CONFIG_USB_G_SERIAL=m
-CONFIG_USB_G_MULTISER=m
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
@@ -635,6 +710,7 @@ CONFIG_DEBUG_USER=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -643,6 +719,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/hackkit_defconfig b/arch/arm/configs/hackkit_defconfig
--- a/arch/arm/configs/hackkit_defconfig
+++ b/arch/arm/configs/hackkit_defconfig
@@ -1,119 +1,106 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc6-git3
+# Thu Jun  9 20:58:58 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
-CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
-# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP310 Implementation Options
-#
-
-#
-# IOP310 Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 CONFIG_SA1100_HACKKIT=y
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
-# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_SSP is not set
 
 #
 # Processor Type
@@ -121,47 +108,97 @@ CONFIG_SA1100_HACKKIT=y
 CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
 
 #
 # Processor Features
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,115200 root=/dev/ram0 initrd=0xc0400000,8M init=/rootshell"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_24_API=y
-CONFIG_CPU_FREQ_26_API=y
-# CONFIG_HOTPLUG is not set
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_SA1100=y
+
+#
+# Floating point emulation
+#
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,115200 root=/dev/ram0 initrd=0xc0400000,8M init=/rootshell"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -169,8 +206,8 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=3
-# CONFIG_MTD_PARTITIONS is not set
 # CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
 
 #
 # User Modules And Translation Layers
@@ -179,6 +216,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -187,18 +225,30 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
 
@@ -206,15 +256,17 @@ CONFIG_MTD_CFI_INTELEXT=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD 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_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -222,20 +274,47 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # CONFIG_PNP is not set
 
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -243,13 +322,27 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
 # 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_NET_KEY is not set
 CONFIG_INET=y
@@ -259,54 +352,58 @@ CONFIG_INET=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_INET_ECN=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
-# CONFIG_XFRM_USER is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-
-#
-# Network device support
-#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -316,67 +413,47 @@ CONFIG_DUMMY=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI 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_ARLAN is not set
-# CONFIG_AIRONET4500 is not set
-
-#
-# Wireless ISA/PCI cards support
-#
-# CONFIG_WAVELAN is not set
-# CONFIG_AIRO is not set
-# CONFIG_HERMES is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
+# Ethernet (10000 Mbit)
 #
-# CONFIG_WAN is not set
 
 #
-# IrDA (infrared) support
+# Token Ring devices
 #
-# CONFIG_IRDA is not set
+# CONFIG_TR is not set
 
 #
-# Amateur Radio support
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_HAMRADIO is not set
+CONFIG_NET_RADIO=y
 
 #
-# ATA/ATAPI/MFM/RLL support
+# Obsolete Wireless cards support (pre-802.11)
 #
-# CONFIG_IDE is not set
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
 
 #
-# SCSI support
+# Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_SCSI is not set
+# CONFIG_ATMEL is not set
+CONFIG_NET_WIRELESS=y
 
 #
-# I2O device support
+# Wan interfaces
 #
-# CONFIG_I2O is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Input device support
@@ -392,21 +469,10 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -416,6 +482,14 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -436,23 +510,13 @@ CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# L3 serial bus support
+# IPMI
 #
-# CONFIG_L3 is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
@@ -460,88 +524,161 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-CONFIG_SA1100_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
 
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 CONFIG_CRAMFS=y
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_XFS_FS is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
-# CONFIG_CIFS is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
-CONFIG_NLS=y
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -566,6 +703,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -582,63 +720,37 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
+# Profiling support
 #
-# CONFIG_VGA_CONSOLE is not set
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SLAB=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_WAITQ=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_WAITQ=y
 CONFIG_DEBUG_ERRORS=y
-CONFIG_KALLSYMS=y
 CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
 # Security options
 #
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
@@ -646,7 +758,13 @@ CONFIG_SECURITY_CAPABILITIES=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
--- a/arch/arm/configs/integrator_defconfig
+++ b/arch/arm/configs/integrator_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc3
-# Mon Dec 20 16:08:21 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 21:14:51 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -26,7 +27,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
@@ -35,6 +35,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -44,6 +45,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -94,6 +96,7 @@ CONFIG_ARCH_INTEGRATOR_AP=y
 CONFIG_CPU_32=y
 CONFIG_CPU_ARM720T=y
 CONFIG_CPU_ARM920T=y
+# CONFIG_CPU_ARM922T is not set
 # CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 # CONFIG_CPU_ARM1022 is not set
@@ -117,68 +120,98 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+CONFIG_ICST525=y
 
 #
-# General setup
+# Bus support
 #
-CONFIG_PCI=y
-CONFIG_ICST525=y
 CONFIG_ARM_AMBA=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp mem=32M"
 # CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_24_API is not set
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_INTEGRATOR=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp mem=32M"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_AFS_PARTS=y
@@ -220,6 +253,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -237,6 +271,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -251,6 +286,11 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -262,6 +302,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -280,6 +321,12 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -287,6 +334,20 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -387,7 +448,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -441,25 +501,6 @@ CONFIG_E100=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -482,18 +523,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_AMBAKMI is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -511,6 +540,18 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -557,11 +598,20 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -572,6 +622,77 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G is not set
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO 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
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -580,6 +701,10 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -627,6 +752,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -693,90 +819,20 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_ARMCLCD is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_RIVA is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G450=y
-CONFIG_FB_MATROX_G100=y
-CONFIG_FB_MATROX_MULTIHEAD=y
-# CONFIG_FB_RADEON_OLD is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_SAVAGE is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO 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
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_WAITQ is not set
@@ -795,6 +851,10 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/iq31244_defconfig b/arch/arm/configs/iq31244_defconfig
--- a/arch/arm/configs/iq31244_defconfig
+++ b/arch/arm/configs/iq31244_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Thu Jan  6 10:53:05 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 02:10:38 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,7 +28,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
@@ -35,6 +35,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -44,6 +45,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -118,49 +120,75 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
 # CONFIG_XIP_KERNEL is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -199,6 +227,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -219,6 +248,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -233,6 +263,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -244,6 +279,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
@@ -261,6 +297,78 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# 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_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -280,6 +388,22 @@ CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_SNAPSHOT is not set
 # CONFIG_DM_MIRROR is not set
 # CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
 
 #
 # Networking support
@@ -406,94 +530,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# 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_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA 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_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR 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_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -516,13 +552,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -532,6 +561,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -578,6 +614,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -628,7 +669,9 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -641,6 +684,8 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -660,6 +705,10 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -670,6 +719,39 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -683,7 +765,12 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 CONFIG_XFS_SECURITY=y
@@ -734,6 +821,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -800,51 +888,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
@@ -860,6 +909,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/iq80321_defconfig b/arch/arm/configs/iq80321_defconfig
--- a/arch/arm/configs/iq80321_defconfig
+++ b/arch/arm/configs/iq80321_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Thu Jan  6 10:52:05 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 13:24:10 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,13 +28,13 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -43,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -117,49 +119,75 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
 # CONFIG_XIP_KERNEL is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -198,6 +226,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -218,6 +247,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -232,6 +262,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -243,6 +278,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
@@ -260,6 +296,17 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -267,6 +314,20 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -390,30 +451,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -436,13 +473,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -452,6 +482,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -498,6 +535,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -548,7 +590,9 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -561,6 +605,8 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -580,6 +626,10 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -590,6 +640,39 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -603,7 +686,12 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 CONFIG_XFS_SECURITY=y
@@ -654,6 +742,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -720,51 +809,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
@@ -780,6 +830,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/iq80331_defconfig b/arch/arm/configs/iq80331_defconfig
--- a/arch/arm/configs/iq80331_defconfig
+++ b/arch/arm/configs/iq80331_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Thu Jan  6 10:44:16 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 15:13:37 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,13 +28,13 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -43,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -117,49 +119,75 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
 # CONFIG_XIP_KERNEL is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -202,6 +230,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -222,6 +251,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -236,6 +266,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -247,6 +282,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
@@ -264,6 +300,78 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# 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_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -283,6 +391,22 @@ CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_SNAPSHOT is not set
 # CONFIG_DM_MIRROR is not set
 # CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
 
 #
 # Networking support
@@ -409,94 +533,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# 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_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA 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_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR 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_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -519,13 +555,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -535,6 +564,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -581,6 +617,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -631,7 +672,9 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -644,6 +687,8 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -663,6 +708,10 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -673,6 +722,39 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -686,7 +768,12 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 CONFIG_XFS_SECURITY=y
@@ -797,51 +884,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
@@ -857,6 +905,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/iq80332_defconfig b/arch/arm/configs/iq80332_defconfig
--- a/arch/arm/configs/iq80332_defconfig
+++ b/arch/arm/configs/iq80332_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Thu Jan  6 10:51:02 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 17:33:39 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -27,13 +28,13 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -43,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -117,49 +119,75 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
 # CONFIG_XIP_KERNEL is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -202,6 +230,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -222,6 +251,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -236,6 +266,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -247,6 +282,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
@@ -264,6 +300,78 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# 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_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -283,6 +391,22 @@ CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_SNAPSHOT is not set
 # CONFIG_DM_MIRROR is not set
 # CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
 
 #
 # Networking support
@@ -409,94 +533,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# 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_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA 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_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR 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_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -519,13 +555,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -535,6 +564,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -581,6 +617,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -631,7 +672,9 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -644,6 +687,8 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -663,6 +708,10 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -673,6 +722,39 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -686,7 +768,12 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 CONFIG_XFS_SECURITY=y
@@ -797,51 +884,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 
@@ -857,6 +905,10 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig
--- a/arch/arm/configs/ixdp2400_defconfig
+++ b/arch/arm/configs/ixdp2400_defconfig
@@ -1,10 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 21:13:38 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,20 +28,24 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -64,7 +73,9 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -88,6 +99,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -99,51 +111,75 @@ CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -182,6 +218,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -201,6 +238,7 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +253,11 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -226,13 +269,31 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -240,6 +301,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -266,6 +341,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -285,8 +363,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -337,7 +413,6 @@ CONFIG_NET_PCI=y
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -349,7 +424,6 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -362,6 +436,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -411,25 +486,6 @@ CONFIG_DLCI_MAX=8
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -452,14 +508,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -469,6 +517,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -490,7 +545,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -516,7 +570,6 @@ CONFIG_IXP2000_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -524,11 +577,15 @@ CONFIG_IXP2000_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -539,6 +596,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -564,6 +622,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -571,20 +630,29 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -603,6 +671,10 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -613,6 +685,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -629,10 +728,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -657,6 +761,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -674,6 +779,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -696,9 +802,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -736,49 +842,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -787,6 +875,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig
--- a/arch/arm/configs/ixdp2401_defconfig
+++ b/arch/arm/configs/ixdp2401_defconfig
@@ -1,10 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 21:53:55 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,20 +28,24 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -64,7 +73,9 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -88,6 +99,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -99,51 +111,75 @@ CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -182,6 +218,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -201,6 +238,7 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +253,11 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -226,13 +269,31 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -240,6 +301,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -266,6 +341,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -285,8 +363,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -338,7 +414,6 @@ CONFIG_NET_PCI=y
 CONFIG_CS89x0=y
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -350,7 +425,6 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -363,6 +437,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -412,25 +487,6 @@ CONFIG_DLCI_MAX=8
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -453,14 +509,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -470,6 +518,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -491,7 +546,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -517,7 +571,6 @@ CONFIG_IXP2000_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -525,11 +578,15 @@ CONFIG_IXP2000_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -540,6 +597,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -565,6 +623,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -572,20 +631,29 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -604,6 +672,10 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -614,6 +686,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -630,10 +729,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -658,6 +762,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -675,6 +780,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -697,9 +803,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -737,49 +843,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -788,6 +876,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig
--- a/arch/arm/configs/ixdp2800_defconfig
+++ b/arch/arm/configs/ixdp2800_defconfig
@@ -1,10 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:15:23 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,20 +28,24 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -64,7 +73,9 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -88,6 +99,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -99,51 +111,75 @@ CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -182,6 +218,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -201,6 +238,7 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +253,11 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -226,13 +269,31 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -240,6 +301,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -266,6 +341,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -285,8 +363,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -337,7 +413,6 @@ CONFIG_NET_PCI=y
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -349,7 +424,6 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -362,6 +436,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -411,25 +486,6 @@ CONFIG_DLCI_MAX=8
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -452,14 +508,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -469,6 +517,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -490,7 +545,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -516,7 +570,6 @@ CONFIG_IXP2000_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -524,11 +577,15 @@ CONFIG_IXP2000_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -539,6 +596,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -564,6 +622,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -571,20 +630,29 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -603,6 +671,10 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -613,6 +685,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -629,10 +728,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -657,6 +761,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -674,6 +779,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -696,9 +802,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -736,49 +842,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -787,6 +875,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig
--- a/arch/arm/configs/ixdp2801_defconfig
+++ b/arch/arm/configs/ixdp2801_defconfig
@@ -1,10 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:39:19 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,20 +28,24 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -64,7 +73,9 @@ CONFIG_ARCH_IXP2000=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -88,6 +99,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -99,51 +111,75 @@ CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware ixdp2x01_clock=50000000"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware ixdp2x01_clock=50000000"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
@@ -182,6 +218,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -201,6 +238,7 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +253,11 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -226,13 +269,31 @@ CONFIG_MTD_IXP2000=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -240,6 +301,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -266,6 +341,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -285,8 +363,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -338,7 +414,6 @@ CONFIG_NET_PCI=y
 CONFIG_CS89x0=y
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -350,7 +425,6 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -363,6 +437,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -412,25 +487,6 @@ CONFIG_DLCI_MAX=8
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -453,14 +509,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -470,6 +518,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -491,7 +546,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -517,7 +571,6 @@ CONFIG_IXP2000_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -525,11 +578,15 @@ CONFIG_IXP2000_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -540,6 +597,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -565,6 +623,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -572,20 +631,29 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -604,6 +672,10 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -614,6 +686,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -630,10 +729,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -658,6 +762,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -675,6 +780,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -697,9 +803,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -737,49 +843,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -788,6 +876,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -1,40 +1,51 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:53:40 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -43,52 +54,33 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -98,12 +90,15 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 #
 # IXP4xx Platforms
 #
+# CONFIG_ARCH_AVILA is not set
+CONFIG_ARCH_ADI_COYOTE=y
 CONFIG_ARCH_IXDP425=y
+# CONFIG_MACH_IXDPG425 is not set
+# CONFIG_MACH_IXDP465 is not set
 CONFIG_ARCH_IXCDP1100=y
 CONFIG_ARCH_PRPMC1100=y
-CONFIG_ARCH_ADI_COYOTE=y
-# CONFIG_ARCH_AVILA is not set
 CONFIG_ARCH_IXDP4XX=y
+# CONFIG_MACH_GTWX5715 is not set
 
 #
 # IXP4xx Options
@@ -111,45 +106,13 @@ CONFIG_ARCH_IXDP4XX=y
 # CONFIG_IXP4XX_INDIRECT_PCI is not set
 
 #
-# Intel PXA250/210 Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Core Type
-#
-
-#
-# OMAP Board Type
-#
-
-#
-# OMAP Feature Selections
-#
-
-#
-# S3C2410 Implementations
-#
-
-#
-# LH7A40X Implementations
-#
-CONFIG_DMABOUNCE=y
-
-#
 # Processor Type
 #
 CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -159,51 +122,81 @@ CONFIG_CPU_MINICACHE=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_XSCALE_PMU=y
+CONFIG_DMABOUNCE=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_PCI=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 CONFIG_APM=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -223,13 +216,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -246,8 +250,10 @@ CONFIG_MTD_IXP4XX=y
 #
 # CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -262,6 +268,13 @@ CONFIG_MTD_IXP4XX=y
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
 
 #
 # Plug and Play support
@@ -275,13 +288,88 @@ CONFIG_MTD_NAND_IDS=m
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE 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_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -289,6 +377,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -306,14 +408,14 @@ CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_FWMARK=y
-CONFIG_IP_ROUTE_NAT=y
 CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-CONFIG_NET_IPIP=m
+# CONFIG_NET_IPIP is not set
 CONFIG_NET_IPGRE=m
 CONFIG_NET_IPGRE_BROADCAST=y
 CONFIG_IP_MROUTE=y
@@ -324,6 +426,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+CONFIG_INET_TUNNEL=m
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -366,6 +471,9 @@ CONFIG_BRIDGE_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
 CONFIG_IP_NF_FTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_TFTP is not set
@@ -391,8 +499,16 @@ CONFIG_IP_NF_MATCH_STATE=m
 # CONFIG_IP_NF_MATCH_CONNTRACK is not set
 CONFIG_IP_NF_MATCH_OWNER=m
 # CONFIG_IP_NF_MATCH_PHYSDEV is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -408,15 +524,10 @@ CONFIG_IP_NF_TARGET_TOS=m
 # CONFIG_IP_NF_TARGET_DSCP is not set
 CONFIG_IP_NF_TARGET_MARK=m
 # CONFIG_IP_NF_TARGET_CLASSIFY is not set
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_RAW is not set
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 # CONFIG_IP_NF_ARP_MANGLE is not set
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
-# CONFIG_IP_NF_RAW is not set
 
 #
 # Bridge: Netfilter Configuration
@@ -455,16 +566,17 @@ CONFIG_ECONET=m
 CONFIG_ECONET_AUNUDP=y
 CONFIG_ECONET_NATIVE=y
 CONFIG_WAN_ROUTER=m
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
 # CONFIG_NET_SCH_HFSC is not set
-CONFIG_NET_SCH_CSZ=m
 # CONFIG_NET_SCH_ATM is not set
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_RED=m
@@ -473,18 +585,24 @@ CONFIG_NET_SCH_TEQL=m
 CONFIG_NET_SCH_TBF=m
 CONFIG_NET_SCH_GRED=m
 CONFIG_NET_SCH_DSMARK=m
-# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_NETEM is not set
 CONFIG_NET_SCH_INGRESS=m
 CONFIG_NET_QOS=y
 CONFIG_NET_ESTIMATOR=y
 CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
 CONFIG_NET_CLS_TCINDEX=m
 CONFIG_NET_CLS_ROUTE4=m
 CONFIG_NET_CLS_ROUTE=y
 CONFIG_NET_CLS_FW=m
 CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_NET_CLS_IND is not set
+# CONFIG_CLS_U32_MARK is not set
 CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
 CONFIG_NET_CLS_POLICE=y
 
 #
@@ -516,6 +634,7 @@ CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
 
 #
 # Tulip family network device support
@@ -530,7 +649,6 @@ CONFIG_NET_PCI=y
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -554,6 +672,7 @@ CONFIG_EEPRO100=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -580,7 +699,6 @@ CONFIG_NET_RADIO=y
 #
 # Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_AIRO is not set
 CONFIG_HERMES=y
 # CONFIG_PLX_HERMES is not set
 # CONFIG_TMD_HERMES is not set
@@ -590,6 +708,7 @@ CONFIG_PCI_HERMES=y
 #
 # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
 #
+# CONFIG_PRISM54 is not set
 CONFIG_NET_WIRELESS=y
 
 #
@@ -637,89 +756,10 @@ CONFIG_ATM_TCP=m
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-CONFIG_BLK_DEV_HPT366=y
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-CONFIG_BLK_DEV_PDC202XX_NEW=y
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE 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_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -742,14 +782,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -759,6 +791,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -780,7 +819,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -806,7 +844,6 @@ CONFIG_IXP4XX_WATCHDOG=y
 # CONFIG_WDTPCI is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -814,12 +851,15 @@ CONFIG_IXP4XX_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -830,6 +870,7 @@ CONFIG_I2C_CHARDEV=y
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -841,6 +882,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_IOP3XX is not set
 # CONFIG_I2C_ISA is not set
 CONFIG_I2C_IXP4XX=y
 # CONFIG_I2C_NFORCE2 is not set
@@ -852,26 +894,41 @@ CONFIG_I2C_IXP4XX=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
 #
 CONFIG_I2C_SENSOR=y
 # CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -883,12 +940,17 @@ CONFIG_I2C_SENSOR=y
 CONFIG_SENSORS_EEPROM=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -899,6 +961,33 @@ CONFIG_SENSORS_EEPROM=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -915,10 +1004,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -931,7 +1025,8 @@ CONFIG_FS_POSIX_ACL=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -942,6 +1037,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -959,6 +1055,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -977,14 +1078,13 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -1002,7 +1102,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -1019,49 +1118,31 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_BDI2000_XSCALE is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1070,8 +1151,13 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/jornada720_defconfig b/arch/arm/configs/jornada720_defconfig
--- a/arch/arm/configs/jornada720_defconfig
+++ b/arch/arm/configs/jornada720_defconfig
@@ -1,33 +1,64 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:10:35 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -35,136 +66,136 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
 CONFIG_SA1100_JORNADA720=y
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-CONFIG_SA1111=y
-CONFIG_FORCE_MAX_ZONEORDER=9
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_REGISTERS is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_AUTCPU12 is not set
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# Processor Type
+#
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
 CONFIG_CPU_SA1100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# General setup
+# Processor Features
+#
+CONFIG_SA1111=y
+CONFIG_DMABOUNCE=y
+CONFIG_FORCE_MAX_ZONEORDER=9
+
+#
+# Bus support
 #
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_HOTPLUG=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
+
+#
+# PC-card bridges
+#
+CONFIG_I82365=y
 # CONFIG_TCIC is not set
-# CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
-# CONFIG_MERCURY_BACKPAQ is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_PCMCIA_SA1111 is not set
+CONFIG_PCCARD_NONSTATIC=y
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="keepinitrd mem=32M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 CONFIG_FPE_FASTFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=m
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
 CONFIG_PM=y
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="keepinitrd mem=32M"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -172,14 +203,20 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=1
+# CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
-CONFIG_MTD_BOOTLDR_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -192,45 +229,49 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-CONFIG_MTD_CFI_B2=y
-CONFIG_MTD_CFI_B4=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 CONFIG_MTD_CFI_I1=y
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_H3600_BACKPAQ is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -238,49 +279,101 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # 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_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI 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
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_FILTER=y
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -289,204 +382,200 @@ CONFIG_IP_MULTICAST=y
 # 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_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
 
 #
-#   IP: Netfilter Configuration
+# IP: Netfilter Configuration
 #
 # CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES 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_IP_NF_ARPTABLES is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
-CONFIG_NETDEVICES=y
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
 
 #
-# ARCnet devices
+# IrDA protocols
 #
-# CONFIG_ARCNET is not set
+CONFIG_IRLAN=m
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+CONFIG_SA1100_FIR=m
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
 # 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
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 # CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-CONFIG_NET_RADIO=y
-# CONFIG_STRIP is not set
-CONFIG_WAVELAN=m
-CONFIG_ARLAN=m
-CONFIG_AIRONET4500=m
-CONFIG_AIRONET4500_NONCS=m
-# CONFIG_AIRONET4500_PNP is not set
-# CONFIG_AIRONET4500_PCI is not set
-# CONFIG_AIRONET4500_ISA is not set
-# CONFIG_AIRONET4500_I365 is not set
-# CONFIG_AIRONET4500_PROC is not set
-# CONFIG_AIRO is not set
-CONFIG_HERMES=m
-CONFIG_PCMCIA_HERMES=m
-CONFIG_AIRO_CS=m
-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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+CONFIG_NET_RADIO=y
 
 #
-# PCMCIA network device support
+# Obsolete Wireless cards support (pre-802.11)
 #
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=m
-CONFIG_PCMCIA_3C574=m
-CONFIG_PCMCIA_FMVJ18X=m
-CONFIG_PCMCIA_PCNET=m
-CONFIG_PCMCIA_NMCLAN=m
-CONFIG_PCMCIA_SMC91C92=m
-CONFIG_PCMCIA_XIRC2PS=m
-# CONFIG_PCMCIA_AXNET is not set
-# CONFIG_ARCNET_COM20020_CS is not set
-# CONFIG_PCMCIA_IBMTR is not set
-CONFIG_NET_PCMCIA_RADIO=y
-# CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_PCMCIA_NETWAVE is not set
+# CONFIG_STRIP is not set
+CONFIG_ARLAN=m
+CONFIG_WAVELAN=m
 CONFIG_PCMCIA_WAVELAN=m
-CONFIG_AIRONET4500_CS=m
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-# CONFIG_IRNET is not set
-CONFIG_IRCOMM=m
-# CONFIG_IRDA_ULTRA is not set
-# CONFIG_IRDA_OPTIONS is not set
+# CONFIG_PCMCIA_NETWAVE is not set
 
 #
-# Infrared-port device drivers
+# Wireless 802.11 Frequency Hopping cards support
 #
-# CONFIG_IRTTY_SIR is not set
-# CONFIG_IRPORT_SIR is not set
-# CONFIG_DONGLE is not set
-# 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_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
-CONFIG_SA1100_FIR=m
+# CONFIG_PCMCIA_RAYCS is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Wireless 802.11b ISA/PCI cards support
 #
-CONFIG_IDE=m
+CONFIG_HERMES=m
+# CONFIG_ATMEL is not set
 
 #
-# IDE, ATA and ATAPI Block devices
+# Wireless 802.11b Pcmcia/Cardbus cards support
 #
-CONFIG_BLK_DEV_IDE=m
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=m
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO 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
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
 
 #
-# SCSI support
+# PCMCIA network device support
 #
-# CONFIG_SCSI is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
 
 #
-# I2O device support
+# Wan interfaces
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
@@ -494,399 +583,337 @@ CONFIG_BLK_DEV_IDECD=m
 # CONFIG_ISDN is not set
 
 #
-# Input core support
+# Input device support
 #
 CONFIG_INPUT=y
-# CONFIG_INPUT_KEYBDEV is not set
+
+#
+# Userland interfaces
+#
 CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_SA1111 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
-# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=115200
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
-# CONFIG_NEWTONKBD is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# L3 serial bus support
+# IPMI
 #
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
-# CONFIG_L3_SA1111 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=m
-# CONFIG_PSMOUSE is not set
-# 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 is not set
-# CONFIG_INPUT_SERPORT 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
+# CONFIG_IPMI_HANDLER 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_SA1100_RTC=m
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
 # PCMCIA character devices
 #
-# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_V4L2_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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
-# CONFIG_REISERFS_PROC_INFO is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+CONFIG_DEVFS_DEBUG=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_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=y
 CONFIG_JFFS2_FS_DEBUG=2
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-# CONFIG_DRIVERFS_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_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=m
 CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# Console drivers
+# Profiling support
 #
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_PROFILING is not set
 
 #
-# Frame-buffer support
+# Kernel hacking
 #
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_ACORN is not set
-# CONFIG_FB_CLPS711X is not set
-# CONFIG_FB_SA1100 is not set
-CONFIG_FB_EPSON1356=y
-# CONFIG_FB_CYBER2000 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 is not set
-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=y
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
-# Sound
+# Security options
 #
-CONFIG_SOUND=m
-# 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_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_SA1100=m
-# CONFIG_SOUND_UDA1341 is not set
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
-# CONFIG_SOUND_H3600_UDA1341 is not set
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-# CONFIG_SOUND_SA1111_UDA1341 is not set
-# CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-# CONFIG_MCP_SA1100 is not set
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB support
+# Cryptographic options
 #
-# CONFIG_USB is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_SA1111 is not set
-# 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
-# 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
-# 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
-# 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
-# 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
-# CONFIG_USB_RIO500 is not set
+# CONFIG_CRYPTO is not set
 
 #
-# Bluetooth support
+# Hardware crypto devices
 #
-# CONFIG_BT is not set
 
 #
-# Kernel hacking
+# Library routines
 #
-CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SLAB=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
-# CONFIG_DEBUG_LL_SER3 is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/lart_defconfig b/arch/arm/configs/lart_defconfig
--- a/arch/arm/configs/lart_defconfig
+++ b/arch/arm/configs/lart_defconfig
@@ -1,35 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:53:24 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -38,90 +52,51 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HACKKIT is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
 CONFIG_SA1100_LART=y
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
 # CONFIG_SA1100_SSP is not set
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-CONFIG_SA1100_USB_CHAR=m
 
 #
 # Processor Type
@@ -131,6 +106,7 @@ CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
 CONFIG_CPU_MINICACHE=y
 
@@ -139,51 +115,84 @@ CONFIG_CPU_MINICACHE=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,9600 root=/dev/ram"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_SA1100=y
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_24_API=y
-# CONFIG_HOTPLUG is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_SA1100=y
+
+#
+# Floating point emulation
+#
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 CONFIG_APM=m
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,9600 root=/dev/ram"
-CONFIG_LEDS=y
-# CONFIG_LEDS_TIMER is not set
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -191,8 +200,8 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=1
-CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -211,10 +220,19 @@ CONFIG_MTD_BLOCK=y
 #
 # CONFIG_MTD_CFI is not set
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 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
 
 #
 # Mapping drivers for chip access
@@ -225,9 +243,11 @@ CONFIG_MTD_BLOCK=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_LART=y
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -242,6 +262,11 @@ CONFIG_MTD_LART=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -251,11 +276,56 @@ CONFIG_MTD_LART=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -263,6 +333,18 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -282,23 +364,24 @@ CONFIG_INET=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_INET_ECN=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -307,88 +390,20 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII 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_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-# CONFIG_SLIP_SMART is not set
-# CONFIG_SLIP_MODE_SLIP6 is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
 CONFIG_IRDA=m
 
 #
@@ -433,56 +448,79 @@ CONFIG_IRDA_DEBUG=y
 #
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
-# CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
 # CONFIG_ALI_FIR is not set
 CONFIG_SA1100_FIR=m
-# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
-# Bluetooth support
+# ARCnet devices
 #
-# CONFIG_BT is not set
+# CONFIG_ARCNET is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
+# Ethernet (10 or 100Mbit)
 #
-CONFIG_IDE=m
-CONFIG_BLK_DEV_IDE=m
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Ethernet (1000 Mbit)
 #
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
-# IDE chipset support/bugfixes
+# Ethernet (10000 Mbit)
 #
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI device support
+# Token Ring devices
 #
-# CONFIG_SCSI is not set
+# CONFIG_TR is not set
 
 #
-# I2O device support
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
 #
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Input device support
@@ -502,35 +540,36 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_PS2_SYNAPTICS is not set
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_INPORT is not set
 # CONFIG_MOUSE_LOGIBM is not set
 # CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -551,7 +590,33 @@ CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -559,57 +624,62 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
-# I2C Algorithms
+# Misc devices
 #
 
 #
-# I2C Hardware Bus support
+# Multimedia devices
 #
+# CONFIG_VIDEO_DEV is not set
 
 #
-# I2C Hardware Sensors Chip support
+# Digital Video Broadcasting Devices
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_DVB is not set
 
 #
-# Mice
+# Graphics support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_FB is not set
 
 #
-# IPMI
+# Console display driver support
 #
-# CONFIG_IPMI_HANDLER is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 
 #
-# Watchdog Cards
+# Sound
 #
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+CONFIG_SOUND=m
 
 #
-# Ftape, the floppy tape device driver
+# Advanced Linux Sound Architecture
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
+# CONFIG_SND is not set
 
 #
-# Multimedia devices
+# Open Sound System
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_SOUND_PRIME is not set
 
 #
-# Digital Video Broadcasting Devices
+# USB support
 #
-# CONFIG_DVB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
@@ -626,11 +696,17 @@ CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -641,21 +717,24 @@ CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -665,6 +744,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -672,6 +752,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=1
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=m
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -685,6 +770,7 @@ CONFIG_CRAMFS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 # CONFIG_NFSD_V4 is not set
@@ -693,23 +779,24 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=m
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
-CONFIG_NLS=y
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -734,6 +821,7 @@ CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -750,52 +838,24 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
+# Profiling support
 #
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -804,8 +864,14 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+CONFIG_CRC_CCITT=m
 CONFIG_CRC32=m
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/arm/configs/lpd7a400_defconfig b/arch/arm/configs/lpd7a400_defconfig
--- a/arch/arm/configs/lpd7a400_defconfig
+++ b/arch/arm/configs/lpd7a400_defconfig
@@ -1,42 +1,52 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:06:33 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 # CONFIG_IKCONFIG_PROC is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -46,7 +56,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -56,6 +65,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -64,69 +74,9 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_ARCH_SHARK is not set
 CONFIG_ARCH_LH7A40X=y
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel IXP4xx Implementation Options
-#
-
-#
-# IXP4xx Platforms
-#
-
-#
-# IXP4xx Options
-#
-
-#
-# Intel PXA2xx Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Core Type
-#
-
-#
-# OMAP Board Type
-#
-
-#
-# OMAP Feature Selections
-#
-
-#
-# S3C2410 Implementations
-#
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # LH7A40X Implementations
@@ -135,6 +85,8 @@ CONFIG_ARCH_LH7A40X=y
 CONFIG_MACH_LPD7A400=y
 # CONFIG_MACH_LPD7A404 is not set
 CONFIG_ARCH_LH7A400=y
+# CONFIG_LH7A40X_CONTIGMEM is not set
+# CONFIG_LH7A40X_ONE_BANK_PER_NODE is not set
 
 #
 # Processor Type
@@ -144,6 +96,7 @@ CONFIG_CPU_ARM922T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -156,46 +109,72 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
 #
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
 CONFIG_DISCONTIGMEM=y
-CONFIG_FIQ=y
-# CONFIG_ZBOOT_ROM is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-CONFIG_PREEMPT=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -216,13 +195,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -230,15 +220,16 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-CONFIG_MTD_LPD7A40X=y
 # CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -253,6 +244,11 @@ CONFIG_MTD_LPD7A40X=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -260,10 +256,54 @@ CONFIG_MTD_LPD7A40X=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -271,6 +311,18 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -297,6 +349,9 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -316,12 +371,12 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -372,52 +427,6 @@ CONFIG_SMC91X=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-CONFIG_IDE_POLL=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_IDE_ARM=y
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -440,14 +449,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -457,6 +458,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -479,7 +487,6 @@ CONFIG_SERIAL_LH7A40X_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -494,22 +501,28 @@ CONFIG_LEGACY_PTY_COUNT=256
 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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -520,6 +533,39 @@ CONFIG_RTC=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -533,10 +579,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -552,6 +603,8 @@ CONFIG_FS_MBCACHE=y
 CONFIG_FAT_FS=y
 # CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -562,6 +615,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -579,6 +633,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -597,9 +656,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -621,7 +680,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -655,6 +713,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -676,53 +735,31 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -731,8 +768,13 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/lpd7a404_defconfig b/arch/arm/configs/lpd7a404_defconfig
--- a/arch/arm/configs/lpd7a404_defconfig
+++ b/arch/arm/configs/lpd7a404_defconfig
@@ -1,42 +1,52 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:14:08 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 # CONFIG_IKCONFIG_PROC is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -46,7 +56,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -56,6 +65,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -64,69 +74,9 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_ARCH_SHARK is not set
 CONFIG_ARCH_LH7A40X=y
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel IXP4xx Implementation Options
-#
-
-#
-# IXP4xx Platforms
-#
-
-#
-# IXP4xx Options
-#
-
-#
-# Intel PXA2xx Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Core Type
-#
-
-#
-# OMAP Board Type
-#
-
-#
-# OMAP Feature Selections
-#
-
-#
-# S3C2410 Implementations
-#
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # LH7A40X Implementations
@@ -135,6 +85,8 @@ CONFIG_ARCH_LH7A40X=y
 # CONFIG_MACH_LPD7A400 is not set
 CONFIG_MACH_LPD7A404=y
 CONFIG_ARCH_LH7A404=y
+# CONFIG_LH7A40X_CONTIGMEM is not set
+# CONFIG_LH7A40X_ONE_BANK_PER_NODE is not set
 
 #
 # Processor Type
@@ -144,6 +96,7 @@ CONFIG_CPU_ARM922T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -156,45 +109,72 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
 #
+CONFIG_PREEMPT=y
 CONFIG_DISCONTIGMEM=y
-# CONFIG_ZBOOT_ROM is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-CONFIG_PREEMPT=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -215,13 +195,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -229,15 +220,16 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-CONFIG_MTD_LPD7A40X=y
 # CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -252,6 +244,11 @@ CONFIG_MTD_LPD7A40X=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -259,10 +256,86 @@ CONFIG_MTD_LPD7A40X=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# 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 is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -270,6 +343,18 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -296,6 +381,9 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -315,12 +403,12 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -371,85 +459,6 @@ CONFIG_SMC91X=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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
-# CONFIG_IDE_TASKFILE_IO is not set
-CONFIG_IDE_POLL=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_IDE_ARM=y
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-# CONFIG_SCSI_PROC_FS is not set
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-# CONFIG_BLK_DEV_SD is not set
-# 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 is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -469,14 +478,6 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -486,6 +487,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -508,7 +516,6 @@ CONFIG_SERIAL_LH7A40X_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -523,22 +530,28 @@ CONFIG_LEGACY_PTY_COUNT=256
 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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -549,6 +562,148 @@ CONFIG_RTC=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB ATM/DSL drivers
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -562,10 +717,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -581,6 +741,8 @@ CONFIG_FS_MBCACHE=y
 CONFIG_FAT_FS=y
 # CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -591,6 +753,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -608,6 +771,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -626,9 +794,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -650,7 +818,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -684,6 +851,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -705,152 +873,31 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_UHCI_HCD is not set
-# CONFIG_USB_SL811HS is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_BLUETOOTH_TTY is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DEBUG=y
-CONFIG_USB_STORAGE_DATAFAB=y
-# 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_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -859,8 +906,13 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig
--- a/arch/arm/configs/lubbock_defconfig
+++ b/arch/arm/configs/lubbock_defconfig
@@ -1,40 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:18:13 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -43,50 +53,33 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Intel PXA2xx Implementations
@@ -94,95 +87,110 @@ CONFIG_ARCH_PXA=y
 CONFIG_ARCH_LUBBOCK=y
 # CONFIG_MACH_MAINSTONE is not set
 # CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
 CONFIG_PXA25x=y
 
 #
-# SA11x0 Implementations
+# Processor Type
 #
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# TI OMAP Implementations
+# Processor Features
 #
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+CONFIG_SA1111=y
+CONFIG_DMABOUNCE=y
+CONFIG_FORCE_MAX_ZONEORDER=9
 
 #
-# OMAP Feature Selections
+# Bus support
 #
 
 #
-# S3C2410 Implementations
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_SA1111=y
-CONFIG_FORCE_MAX_ZONEORDER=9
-CONFIG_DMABOUNCE=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
 
 #
-# Processor Type
+# PC-card bridges
 #
-CONFIG_CPU_32=y
-CONFIG_CPU_XSCALE=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PXA2XX=y
 
 #
-# Processor Features
+# Kernel Features
 #
-# CONFIG_ARM_THUMB is not set
-CONFIG_XSCALE_PMU=y
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# General setup
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=y
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_PXA2XX=y
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -206,10 +214,12 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-# CONFIG_MTD_CFI_B2 is not set
-CONFIG_MTD_CFI_B4=y
-# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 # CONFIG_MTD_CFI_I1 is not set
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
@@ -217,10 +227,11 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -230,13 +241,16 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_LUBBOCK=y
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_SHARP_SL is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -251,6 +265,11 @@ CONFIG_MTD_LUBBOCK=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -258,9 +277,32 @@ CONFIG_MTD_LUBBOCK=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -268,6 +310,18 @@ CONFIG_MTD_LUBBOCK=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -293,6 +347,9 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -312,12 +369,12 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -381,29 +438,6 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -426,17 +460,6 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_SA1111=y
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -454,6 +477,17 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_SA1111=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -476,7 +510,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -489,16 +522,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
 
 #
@@ -508,11 +537,20 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -523,6 +561,55 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA2XX=y
+CONFIG_USB_PXA2XX=y
+CONFIG_USB_PXA2XX_SMALL=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+CONFIG_USB_G_SERIAL=y
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -531,10 +618,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -550,6 +642,7 @@ CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 # CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
 # CONFIG_NTFS_FS is not set
 
 #
@@ -577,6 +670,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -594,20 +692,20 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -637,6 +735,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -658,61 +757,23 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-CONFIG_USB_GADGET=y
-# CONFIG_USB_GADGET_NET2280 is not set
-CONFIG_USB_GADGET_PXA2XX=y
-CONFIG_USB_PXA2XX=y
-CONFIG_USB_PXA2XX_SMALL=y
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_SA1100 is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-CONFIG_USB_G_SERIAL=y
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
@@ -720,6 +781,7 @@ CONFIG_DEBUG_LL=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -728,8 +790,14 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/lusl7200_defconfig b/arch/arm/configs/lusl7200_defconfig
--- a/arch/arm/configs/lusl7200_defconfig
+++ b/arch/arm/configs/lusl7200_defconfig
@@ -1,41 +1,63 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:24:38 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_FIQ=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
-# CONFIG_NET is not set
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -43,147 +65,94 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 CONFIG_ARCH_L7200=y
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# Archimedes/A5000 Implementations
+# Processor Type
 #
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
 
 #
-# Archimedes/A5000 Implementations (select only ONE)
+# Processor Features
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
+# CONFIG_ARM_THUMB is not set
 
 #
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
-
-#
-# SA11x0 Implementations
-#
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
-# CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_H3100 is not set
-# CONFIG_SA1100_H3600 is not set
-# CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
-# CONFIG_SA1100_BADGE4 is not set
-# CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
-# CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
-# CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
-# CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
-# CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_H3600_SLEEVE is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_AUTCPU12 is not set
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_FORTUNET is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+# Bus support
+#
 
 #
-# Processor Type
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_32v5 is not set
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-CONFIG_CPU_ARM720T=y
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-# CONFIG_CPU_SA1100 is not set
-# CONFIG_CPU_XSCALE is not set
-# CONFIG_XSCALE_PMU is not set
+# CONFIG_PCCARD is not set
 
 #
-# Processor Features
+# Kernel Features
 #
-# CONFIG_ARM_THUMB is not set
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# General setup
+# Boot options
 #
-# CONFIG_DISCONTIGMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
-CONFIG_FIQ=y
+CONFIG_ZBOOT_ROM_TEXT=0x00010000
+CONFIG_ZBOOT_ROM_BSS=0xf03e0000
 CONFIG_ZBOOT_ROM=y
-CONFIG_ZBOOT_ROM_TEXT=00010000
-CONFIG_ZBOOT_ROM_BSS=f03e0000
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
+CONFIG_CMDLINE="console=tty0 console=ttyLU1,115200 root=/dev/ram initrd=0xf1000000,0x005dac7b mem=32M"
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 # CONFIG_FPE_NWFPE is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_APM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=tty0 console=ttyLU1,115200 root=/dev/ram initrd=0xf1000000,0x005dac7b mem=32M"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -191,59 +160,68 @@ CONFIG_ALIGNMENT_TRAP=y
 # CONFIG_MTD is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS 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_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# 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
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 # CONFIG_SCSI is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
 # I2O device support
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -253,37 +231,29 @@ CONFIG_BLK_DEV_INITRD=y
 # Input device 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_GAMEPORT_PCIGAME is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461x is not set
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_SERPORT is not set
 
 #
 # Character devices
 #
 # CONFIG_VT 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
@@ -296,35 +266,38 @@ CONFIG_SERIAL_NONSTANDARD=y
 # Serial drivers
 #
 # CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
 #
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# ARM Serial drivers
+# TPM devices
 #
-# CONFIG_ATOMWIDE_SERIAL is not set
-# CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
-# CONFIG_SERIAL_SA1100 is not set
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
-# CONFIG_UNIX98_PTYS is not set
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -332,154 +305,151 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_I2C is not set
 
 #
-# L3 serial bus support
+# Misc devices
 #
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
 
 #
-# Other L3 adapters
+# Multimedia devices
 #
-# CONFIG_L3_SA1111 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Mice
+# Digital Video Broadcasting Devices
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
-# Watchdog Cards
+# Graphics support
 #
-# 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
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+# CONFIG_FB is not set
 
 #
-# Ftape, the floppy tape device driver
+# Sound
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+# CONFIG_SOUND is not set
 
 #
-# Multimedia devices
+# USB support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
-# CONFIG_QFMT_V1 is not set
-# CONFIG_QFMT_V2 is not set
-# CONFIG_QIFACE_COMPAT is not set
+CONFIG_DNOTIFY=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
-# CONFIG_REISERFS_PROC_INFO is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_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_DEBUG 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 is not set
-# CONFIG_SMB_NLS is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Profiling support
 #
-# CONFIG_MCP is not set
-# CONFIG_MCP_SA1100 is not set
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_PROFILING is not set
 
 #
-# Console Switches
+# Kernel hacking
 #
-# CONFIG_SWITCHES is not set
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 
 #
-# USB support
+# Security options
 #
-# CONFIG_USB is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# Kernel hacking
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_ERRORS is not set
-# CONFIG_DEBUG_LL is not set
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
 
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
-# CONFIG_ZLIB_INFLATE is not set
-# CONFIG_ZLIB_DEFLATE is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig
--- a/arch/arm/configs/mainstone_defconfig
+++ b/arch/arm/configs/mainstone_defconfig
@@ -1,41 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sat Mar 26 20:00:45 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -44,12 +53,12 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -59,6 +68,7 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_RPC is not set
@@ -67,7 +77,9 @@ CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Intel PXA2xx Implementations
@@ -75,6 +87,7 @@ CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_LUBBOCK is not set
 CONFIG_MACH_MAINSTONE=y
 # CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
 CONFIG_PXA27x=y
 CONFIG_IWMMXT=y
 
@@ -85,6 +98,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -95,59 +109,78 @@ CONFIG_CPU_MINICACHE=y
 CONFIG_XSCALE_PMU=y
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
 #
-# CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-CONFIG_PCMCIA=y
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_PXA2XX=y
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -171,10 +204,12 @@ CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_CFI_B1 is not set
-# CONFIG_MTD_CFI_B2 is not set
-CONFIG_MTD_CFI_B4=y
-# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 # CONFIG_MTD_CFI_I1 is not set
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
@@ -182,10 +217,11 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -194,13 +230,16 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_SHARP_SL is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -215,6 +254,11 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -222,9 +266,53 @@ CONFIG_MTD_CFI_INTELEXT=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -232,6 +320,18 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -257,6 +357,9 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -276,12 +379,12 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -323,11 +426,6 @@ CONFIG_SMC91X=y
 # CONFIG_NET_RADIO is not set
 
 #
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
 # Wan interfaces
 #
 # CONFIG_WAN is not set
@@ -337,51 +435,6 @@ CONFIG_SMC91X=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -404,16 +457,6 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -428,6 +471,16 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -450,7 +503,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -463,23 +515,19 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
+# CONFIG_RAW_DRIVER is not set
 
 #
-# PCMCIA character devices
+# TPM devices
 #
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -487,6 +535,10 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -497,6 +549,61 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -505,10 +612,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -552,6 +664,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -569,9 +686,9 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -582,6 +699,7 @@ CONFIG_SUNRPC=y
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -633,63 +751,23 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_PXA=y
-# CONFIG_FB_PXA_PARAMETERS is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
@@ -697,6 +775,7 @@ CONFIG_DEBUG_LL=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -705,8 +784,13 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/mx1ads_defconfig b/arch/arm/configs/mx1ads_defconfig
--- a/arch/arm/configs/mx1ads_defconfig
+++ b/arch/arm/configs/mx1ads_defconfig
@@ -1,40 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 02:15:46 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_IOSCHED_NOOP is not set
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -44,6 +53,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -58,6 +68,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -66,8 +77,9 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
 CONFIG_ARCH_IMX=y
+# CONFIG_ARCH_H720X is not set
 
 #
 # IMX Implementations
@@ -82,6 +94,7 @@ CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -94,49 +107,73 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
 #
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-# CONFIG_CPU_FREQ is not set
+CONFIG_CMDLINE="console=ttySMX0,57600n8 ip=bootp root=/dev/nfs"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_FPE_FASTFPE=y
-# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-CONFIG_PREEMPT=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySMX0,57600n8 ip=bootp root=/dev/nfs"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -155,23 +192,33 @@ CONFIG_MTD_BLOCK=y
 #
 # CONFIG_MTD_CFI is not set
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_RAM is not set
 CONFIG_MTD_ROM=y
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_MX1ADS=y
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -186,6 +233,11 @@ CONFIG_MTD_MX1ADS=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -195,10 +247,28 @@ CONFIG_MTD_MX1ADS=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -206,6 +276,18 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -232,6 +314,9 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -251,8 +336,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -285,10 +368,10 @@ CONFIG_NETDEVICES=y
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -332,24 +415,6 @@ CONFIG_PPP_BSDCOMP=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -360,20 +425,11 @@ CONFIG_PPP_BSDCOMP=y
 # CONFIG_INPUT is not set
 
 #
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
+# Hardware I/O ports
 #
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
 
 #
 # Character devices
@@ -395,7 +451,6 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -408,25 +463,30 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=m
-# CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -437,6 +497,33 @@ CONFIG_RTC=m
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -444,10 +531,15 @@ CONFIG_RTC=m
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -477,6 +569,7 @@ CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -494,6 +587,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -512,9 +610,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -525,6 +623,7 @@ CONFIG_SUNRPC=y
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -576,46 +675,31 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -629,6 +713,8 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 # CONFIG_CRYPTO_DES is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -636,16 +722,23 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_AES is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-CONFIG_CRC16=y
+CONFIG_CRC_CCITT=y
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig
--- a/arch/arm/configs/neponset_defconfig
+++ b/arch/arm/configs/neponset_defconfig
@@ -1,122 +1,106 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Wed Mar  9 14:28:26 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
-CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP310 Implementation Options
-#
-
-#
-# IOP310 Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 CONFIG_SA1100_ASSABET=y
 CONFIG_ASSABET_NEPONSET=y
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-CONFIG_SA1100_USB_CHAR=m
-CONFIG_SA1111=y
-CONFIG_FORCE_MAX_ZONEORDER=9
+# CONFIG_SA1100_SSP is not set
 
 #
 # Processor Type
@@ -124,57 +108,102 @@ CONFIG_FORCE_MAX_ZONEORDER=9
 CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
 # Processor Features
 #
+CONFIG_SA1111=y
+CONFIG_DMABOUNCE=y
+CONFIG_FORCE_MAX_ZONEORDER=9
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-CONFIG_ZBOOT_ROM=y
-CONFIG_ZBOOT_ROM_TEXT=0x80000
-CONFIG_ZBOOT_ROM_BSS=0xc1000000
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_24_API=y
-CONFIG_CPU_FREQ_26_API=y
-CONFIG_HOTPLUG=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_SA1100=y
 CONFIG_PCMCIA_SA1111=y
 
 #
-# At least one math emulation must be selected
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x80000
+CONFIG_ZBOOT_ROM_BSS=0xc1000000
+CONFIG_ZBOOT_ROM=y
+CONFIG_CMDLINE="console=ttySA0,38400n8 cpufreq=221200 rw root=/dev/mtdblock2 mtdparts=sa1100:512K(boot),1M(kernel),2560K(initrd),4M(root) load_ramdisk=1 prompt_ramdisk=0 mem=32M noinitrd initrd=0xc0800000,3M"
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_SA1110=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 CONFIG_APM=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,38400n8 cpufreq=221200 rw root=/dev/mtdblock2 mtdparts=sa1100:512K(boot),1M(kernel),2560K(initrd),4M(root) load_ramdisk=1 prompt_ramdisk=0 mem=32M noinitrd initrd=0xc0800000,3M"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -184,6 +213,9 @@ CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -194,6 +226,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -206,37 +239,49 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 CONFIG_MTD_SA1100=y
 # CONFIG_MTD_EDB7312 is not set
-CONFIG_MTD_PCMCIA=y
-# CONFIG_MTD_UCLINUX is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD 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_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -244,7 +289,12 @@ CONFIG_MTD_PCMCIA=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # CONFIG_PNP is not set
 
@@ -253,11 +303,94 @@ CONFIG_MTD_PCMCIA=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# 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 is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA 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_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 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_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -265,14 +398,30 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -280,56 +429,70 @@ CONFIG_INET=y
 # 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_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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_MII=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 CONFIG_NET_VENDOR_SMC=y
 # CONFIG_WD80x3 is not set
 # CONFIG_ULTRA is not set
+CONFIG_SMC91X=y
 CONFIG_SMC9194=y
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
@@ -342,27 +505,20 @@ CONFIG_SMC9194=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# CONFIG_NET_RADIO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # PCMCIA network device support
@@ -376,37 +532,20 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_PCMCIA_AXNET is not set
-# CONFIG_NET_PCMCIA_RADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
 
 #
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# I2O device support
+# Wan interfaces
 #
-# CONFIG_I2O is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Input device support
@@ -416,12 +555,14 @@ CONFIG_INPUT=y
 #
 # Userland interfaces
 #
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_TSDEV=y
 CONFIG_INPUT_TSDEV_SCREEN_X=240
 CONFIG_INPUT_TSDEV_SCREEN_Y=320
-CONFIG_INPUT_TSLIBDEV=y
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -431,10 +572,11 @@ CONFIG_INPUT_TSLIBDEV=y
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_SERPORT=m
 # CONFIG_SERIO_CT82C710 is not set
 CONFIG_SERIO_SA1111=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -442,6 +584,7 @@ CONFIG_SERIO_SA1111=y
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -466,7 +609,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 # 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
@@ -481,6 +623,7 @@ CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_CONSOLE is not set
 CONFIG_SERIAL_8250_CS=y
+CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -491,65 +634,45 @@ CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=64
 
 #
-# I2C support
+# IPMI
 #
-CONFIG_I2C=y
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_SCx200_ACB is not set
-CONFIG_I2C_BIT_SA1100_GPIO=y
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_PROC=y
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# L3 serial bus support
+# Watchdog Cards
 #
-CONFIG_L3=y
-CONFIG_L3_ALGOBIT=y
-CONFIG_L3_BIT_SA1100_GPIO=y
-CONFIG_BIT_SA1100_GPIO=y
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Mice
+# Watchdog Device Drivers
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
 
 #
-# Watchdog Cards
+# ISA-based Watchdog Cards
 #
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
 # CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-CONFIG_SA1100_WATCHDOG=m
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
 # CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
+# CONFIG_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-CONFIG_SA1100_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
 
 #
@@ -559,154 +682,110 @@ CONFIG_SA1100_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
-# Multimedia devices
+# I2C support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 
 #
-# File systems
+# I2C Algorithms
 #
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_XFS_FS is not set
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
-# Network File Systems
+# I2C Hardware Bus support
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-# CONFIG_CIFS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_AFS_FS is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# Partition Types
+# Misc devices
 #
-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 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 is not set
-CONFIG_NLS=y
 
 #
-# Native Language Support
+# Multimedia devices
 #
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=m
-# 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
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Console drivers
+# Digital Video Broadcasting Devices
 #
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_DVB is not set
 
 #
-# Frame-buffer support
+# Graphics support
 #
 CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_FONTWIDTH8_ONLY=y
-# CONFIG_FONT_SUN8x16 is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-# CONFIG_FONT_MINI_4x6 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -714,48 +793,24 @@ CONFIG_FONT_ACORN_8x8=y
 CONFIG_SOUND=y
 
 #
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO 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_SA1100=y
-CONFIG_SOUND_UDA1341=y
-CONFIG_SOUND_ASSABET_UDA1341=y
-CONFIG_SOUND_SA1111_UDA1341=y
-# CONFIG_SOUND_SA1100SSP is not set
 # CONFIG_SOUND_OSS is not set
 # CONFIG_SOUND_TVMIXER is not set
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-CONFIG_MCP=y
-CONFIG_MCP_SA1100=y
-CONFIG_MCP_UCB1200=y
-CONFIG_MCP_UCB1200_AUDIO=m
-CONFIG_MCP_UCB1200_TS=y
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
+# CONFIG_SOUND_AD1980 is not set
 
 #
 # USB support
@@ -767,17 +822,20 @@ CONFIG_USB_DEBUG=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_LONG_TIMEOUT is not set
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
 #
-# CONFIG_USB_EHCI_HCD is not set
 CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_UHCI_HCD_ALT is not set
-# CONFIG_USB_SL811HS is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -789,11 +847,21 @@ CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_PRINTER is not set
 
 #
-# SCSI support is needed for USB Storage
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
 #
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 # CONFIG_USB_HID is not set
 
@@ -804,14 +872,18 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_MOUSE=m
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
 
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
 
 #
 # USB Multimedia devices
@@ -823,14 +895,14 @@ CONFIG_USB_MOUSE=m
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=m
 
 #
 # USB port drivers
@@ -844,37 +916,215 @@ CONFIG_USB_MOUSE=m
 #
 # USB Miscellaneous drivers
 #
-# CONFIG_USB_TIGL is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_TEST is not set
 
 #
-# Bluetooth support
+# USB ATM/DSL drivers
 #
-# CONFIG_BT is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_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 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 is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# 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_ASCII 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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SLAB=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_SLAB=y
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
-# CONFIG_KALLSYMS is not set
 CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
 # Security options
 #
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
@@ -882,8 +1132,14 @@ CONFIG_SECURITY_CAPABILITIES=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/netwinder_defconfig b/arch/arm/configs/netwinder_defconfig
--- a/arch/arm/configs/netwinder_defconfig
+++ b/arch/arm/configs/netwinder_defconfig
@@ -1,35 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 15:18:42 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -39,28 +54,27 @@ CONFIG_IOSCHED_DEADLINE=y
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 CONFIG_ARCH_FOOTBRIDGE=y
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Footbridge Implementations
@@ -70,24 +84,6 @@ CONFIG_ARCH_FOOTBRIDGE=y
 # CONFIG_ARCH_EBSA285_ADDIN is not set
 # CONFIG_ARCH_EBSA285_HOST is not set
 CONFIG_ARCH_NETWINDER=y
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
-
-#
-# SA11x0 Implementations
-#
 CONFIG_FOOTBRIDGE=y
 CONFIG_FOOTBRIDGE_HOST=y
 
@@ -99,6 +95,7 @@ CONFIG_CPU_SA110=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WB=y
 
@@ -107,59 +104,90 @@ CONFIG_CPU_TLB_V4WB=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_PCI=y
 CONFIG_ISA=y
 CONFIG_ISA_DMA=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0
-CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_PCI=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
 
 #
-# At least one math emulation must be selected
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=0x301"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=0x301"
-CONFIG_LEDS=y
-# CONFIG_LEDS_TIMER is not set
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
 
 #
 # Parallel port support
 #
 CONFIG_PARPORT=y
 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=y
 # CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_1284 is not set
 
 #
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -174,11 +202,87 @@ CONFIG_PARPORT_PC_SUPERIO=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE 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_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -186,6 +290,20 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -208,19 +326,19 @@ CONFIG_IP_PNP_RARP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
 #
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 
@@ -228,6 +346,9 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
 CONFIG_IP_NF_FTP=y
 # CONFIG_IP_NF_IRC is not set
 # CONFIG_IP_NF_TFTP is not set
@@ -252,21 +373,28 @@ CONFIG_IP_NF_IPTABLES=y
 # CONFIG_IP_NF_MATCH_STATE is not set
 # CONFIG_IP_NF_MATCH_CONNTRACK is not set
 # CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
 # CONFIG_IP_NF_FILTER is not set
-# CONFIG_IP_NF_NAT is not set
-# 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 is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
 # CONFIG_IP_NF_ARPTABLES is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -275,23 +403,23 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 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
@@ -299,16 +427,21 @@ CONFIG_NETDEVICES=y
 # CONFIG_ETHERTAP is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_SMC91X is not set
 # CONFIG_HAPPYMEAL 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_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -319,6 +452,7 @@ CONFIG_NET_TULIP=y
 CONFIG_TULIP=y
 # CONFIG_TULIP_MWI is not set
 CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
@@ -333,6 +467,7 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
@@ -359,300 +494,324 @@ CONFIG_NE2K_PCI=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB 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
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
 
 #
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
 
 #
-# Token Ring devices
+# Wan interfaces
 #
-# CONFIG_TR is not set
-# CONFIG_RCPCI is not set
+# CONFIG_WAN 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
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# Wan interfaces
+# ISDN subsystem
 #
-# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
 
 #
-# Amateur Radio support
+# Input device support
 #
-# CONFIG_HAMRADIO is not set
+CONFIG_INPUT=y
 
 #
-# IrDA (infrared) support
+# Userland interfaces
 #
-# CONFIG_IRDA is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# Bluetooth support
+# Input Device Drivers
 #
-# CONFIG_BT is not set
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=y
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
 
 #
-# ATA/ATAPI/MFM/RLL support
+# Hardware I/O ports
 #
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Character devices
 #
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# IDE chipset support/bugfixes
+# Serial drivers
 #
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
-# CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE 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_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
-# I2O device support
+# Non-8250 serial port support
 #
-# CONFIG_I2O is not set
+# CONFIG_SERIAL_21285 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
-# ISDN subsystem
+# IPMI
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# Input device support
+# Watchdog Cards
 #
-CONFIG_INPUT=y
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Userland interfaces
+# Watchdog Device Drivers
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+CONFIG_977_WATCHDOG=y
 
 #
-# Input I/O drivers
+# ISA-based Watchdog Cards
 #
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
 
 #
-# Input Device Drivers
+# PCI-based Watchdog Cards
 #
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_PS2_SYNAPTICS is not set
-CONFIG_MOUSE_SERIAL=y
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_PCSPKR is not set
-CONFIG_INPUT_UINPUT=y
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+CONFIG_NWFLASH=y
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
-# Character devices
+# Ftape, the floppy tape device driver
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Serial drivers
+# TPM devices
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_TCG_TPM is not set
 
 #
-# Non-8250 serial port support
+# I2C support
 #
-# CONFIG_SERIAL_DZ is not set
-# CONFIG_SERIAL_21285 is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=y
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
-# CONFIG_TIPAR is not set
+# CONFIG_I2C is not set
 
 #
-# I2C support
+# Misc devices
 #
-# CONFIG_I2C is not set
 
 #
-# I2C Algorithms
+# Multimedia devices
 #
+# CONFIG_VIDEO_DEV is not set
 
 #
-# I2C Hardware Bus support
+# Digital Video Broadcasting Devices
 #
+# CONFIG_DVB is not set
 
 #
-# I2C Hardware Sensors Chip support
+# Graphics support
 #
-# CONFIG_I2C_SENSOR is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO 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
 
 #
-# L3 serial bus support
+# Console display driver support
 #
-# CONFIG_L3 is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
 
 #
-# Mice
+# Logo configuration
 #
-CONFIG_BUSMOUSE=y
-# CONFIG_QIC02_TAPE is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# IPMI
+# Sound
 #
-# CONFIG_IPMI_HANDLER is not set
+CONFIG_SOUND=y
 
 #
-# Watchdog Cards
+# Advanced Linux Sound Architecture
 #
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_21285_WATCHDOG is not set
-CONFIG_977_WATCHDOG=y
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_ALIM1535_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
-CONFIG_DS1620=y
-CONFIG_NWBUTTON=y
-CONFIG_NWBUTTON_REBOOT=y
-CONFIG_NWFLASH=y
-# CONFIG_NVRAM is not set
-CONFIG_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+# CONFIG_SND is not set
 
 #
-# Ftape, the floppy tape device driver
+# Open Sound System
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_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_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SOUND_OSS=y
+CONFIG_SOUND_TRACEINIT=y
+CONFIG_SOUND_DMAP=y
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_MAUI is not set
+CONFIG_SOUND_YM3812=y
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+CONFIG_SOUND_WAVEARTIST=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_AD1980 is not set
 
 #
-# Multimedia devices
+# USB support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
 
 #
-# Digital Video Broadcasting Devices
+# USB Gadget Support
 #
-# CONFIG_DVB is not set
+# CONFIG_USB_GADGET is not set
 
 #
 # MMC/SD Card support
@@ -668,10 +827,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
 # CONFIG_AUTOFS4_FS is not set
 
@@ -686,17 +850,19 @@ CONFIG_JOLIET=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -706,6 +872,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -733,12 +900,13 @@ CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=y
 # CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -756,17 +924,15 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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 is not set
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -791,6 +957,7 @@ CONFIG_NLS_CODEPAGE_852=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
 # CONFIG_NLS_ISO8859_3 is not set
@@ -807,157 +974,73 @@ CONFIG_NLS_ISO8859_15=y
 CONFIG_NLS_UTF8=y
 
 #
-# Graphics support
+# Profiling support
 #
-CONFIG_FB=y
-CONFIG_FB_CYBER2000=y
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY 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_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_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_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-CONFIG_SOUND_OSS=y
-CONFIG_SOUND_TRACEINIT=y
-CONFIG_SOUND_DMAP=y
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_AD1889 is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_MAUI is not set
-CONFIG_SOUND_YM3812=y
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_YMFPCI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-CONFIG_SOUND_WAVEARTIST=y
-# CONFIG_SOUND_ALI5455 is not set
-# CONFIG_SOUND_FORTE is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_AD1980 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
 #
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
 
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig
--- a/arch/arm/configs/omap_h2_1610_defconfig
+++ b/arch/arm/configs/omap_h2_1610_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Tue Feb  1 14:01:46 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 17:52:41 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -28,7 +28,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
@@ -36,6 +35,7 @@ CONFIG_KOBJECT_UEVENT=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -45,6 +45,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -110,6 +111,8 @@ CONFIG_MACH_OMAP_H2=y
 CONFIG_OMAP_MUX=y
 # CONFIG_OMAP_MUX_DEBUG is not set
 CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
@@ -140,11 +143,8 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
 
 #
-# General setup
+# Bus support
 #
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-# CONFIG_XIP_KERNEL is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -152,39 +152,57 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 # CONFIG_PCCARD is not set
 
 #
-# PC-card bridges
+# Kernel Features
 #
+CONFIG_PREEMPT=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# At least one math emulation must be selected
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
 # CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-CONFIG_DEBUG_DRIVER=y
 CONFIG_PM=y
-CONFIG_PREEMPT=y
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -192,8 +210,8 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=3
-CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -263,6 +281,11 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -291,11 +314,58 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_ATA_OVER_ETH=m
 
 #
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# 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 is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -410,53 +480,6 @@ CONFIG_SLIP_COMPRESSED=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-# CONFIG_BLK_DEV_SD is not set
-# 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 is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -479,16 +502,6 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=y
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -499,6 +512,15 @@ CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -549,6 +571,11 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -580,7 +607,9 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -613,6 +642,10 @@ CONFIG_ISP1301_OMAP=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -623,6 +656,101 @@ CONFIG_ISP1301_OMAP=y
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 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_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -631,6 +759,10 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -702,7 +834,6 @@ CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -769,113 +900,17 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 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_OSS is not set
-# CONFIG_SOUND_TVMIXER is not set
-# CONFIG_SOUND_AD1980 is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-CONFIG_USB_GADGET=y
-# CONFIG_USB_GADGET_DEBUG_FILES is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_PXA2XX is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_SA1100 is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-CONFIG_USB_GADGET_OMAP=y
-CONFIG_USB_OMAP=y
-# CONFIG_USB_GADGET_DUALSPEED is not set
-# CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=y
-CONFIG_USB_ETH_RNDIS=y
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
@@ -905,6 +940,7 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/arm/configs/omnimeter_defconfig b/arch/arm/configs/omnimeter_defconfig
--- a/arch/arm/configs/omnimeter_defconfig
+++ b/arch/arm/configs/omnimeter_defconfig
@@ -1,113 +1,193 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 21:31:45 2005
 #
 CONFIG_ARM=y
-# CONFIG_SBUS is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_CLPS711X is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Footbridge Implementations
-#
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_BRUTUS is not set
-CONFIG_SA1100_OMNIMETER=y
 # CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_SHERMAN is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_PANGOLIN is not set
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_FREQUENCY_SCALE is not set
-# CONFIG_SA1100_VOLTAGE_SCALE is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# Processor Type
+#
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-CONFIG_CPU_32v4=y
 CONFIG_CPU_SA1100=y
-CONFIG_DISCONTIGMEM=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# General setup
+# Processor Features
+#
+
+#
+# Bus support
 #
-# CONFIG_ANGELBOOT is not set
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-CONFIG_HOTPLUG=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
 CONFIG_I82365=y
-# CONFIG_PCMCIA_CLPS6700 is not set
-CONFIG_SA1100_PCMCIA=y
-# CONFIG_H3600_SLEEVE is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+CONFIG_PCCARD_NONSTATIC=y
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="keepinitrd mem=16M root=/dev/ram ramdisk=8192 initrd=0xd0000000,4M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="keepinitrd mem=16M root=/dev/ram ramdisk=8192 initrd=0xd0000000,4M"
-# CONFIG_LEDS is not set
-# CONFIG_ALIGNMENT_TRAP is not set
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -115,38 +195,101 @@ CONFIG_CMDLINE="keepinitrd mem=16M root=
 # CONFIG_MTD is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # 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_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_FLASH is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -155,62 +298,83 @@ CONFIG_IP_MULTICAST=y
 # 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_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
 
 #
-#   IP: Netfilter Configuration
+# IP: Netfilter Configuration
 #
 # CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES 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_IP_NF_ARPTABLES is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
-# CONFIG_NET_SB1000 is not set
-# CONFIG_NET_SA1100_USB_HOST is not set
-# CONFIG_NET_SA1100_USB_CLIENT is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -222,256 +386,345 @@ CONFIG_NET_ETHERNET=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# 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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+CONFIG_NET_RADIO=y
 
 #
-# PCMCIA network device support
+# Obsolete Wireless cards support (pre-802.11)
 #
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=y
-# CONFIG_PCMCIA_3C574 is not set
-# CONFIG_PCMCIA_FMVJ18X is not set
-CONFIG_PCMCIA_PCNET=y
-# 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=y
-# CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_PCMCIA_NETWAVE is not set
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
 CONFIG_PCMCIA_WAVELAN=y
-CONFIG_AIRONET4500_CS=y
-CONFIG_PCMCIA_WVLAN=y
-CONFIG_PCMCIA_NETCARD=y
+# CONFIG_PCMCIA_NETWAVE is not set
 
 #
-# Amateur Radio support
+# Wireless 802.11 Frequency Hopping cards support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_PCMCIA_RAYCS is not set
 
 #
-# IrDA (infrared) support
+# Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_IRDA is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Wireless 802.11b Pcmcia/Cardbus cards support
 #
-CONFIG_IDE=y
+CONFIG_AIRO_CS=y
+CONFIG_PCMCIA_WL3501=y
+CONFIG_NET_WIRELESS=y
 
 #
-# IDE, ATA and ATAPI Block devices
+# PCMCIA network device support
 #
-CONFIG_BLK_DEV_IDE=y
-# 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_BLK_DEV_IDECS=y
-# 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_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=y
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=y
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
 
 #
-# SCSI support
+# Wan interfaces
 #
-# CONFIG_SCSI is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# I2O device support
+# ISDN subsystem
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
+# CONFIG_ISDN is not set
 
 #
-# ISDN subsystem
+# Input device support
 #
-# CONFIG_ISDN is not set
+CONFIG_INPUT=y
 
 #
-# Input core support
+# Userland interfaces
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL_SA1100=y
-CONFIG_SERIAL_SA1100_CONSOLE=y
-# CONFIG_TOUCHSCREEN_UCB1200 is not set
-# CONFIG_TOUCHSCREEN_BITSY is not set
-# CONFIG_TOUCHSCREEN_BITSY_KEYBOARD is not set
-# CONFIG_H3600_SLEEVE is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_SERIAL_SA1100=y
-CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=9600
-# CONFIG_TOUCHSCREEN_UCB1200 is not set
-# CONFIG_TOUCHSCREEN_BITSY is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
 
 #
-# I2C support
+# Serial drivers
 #
-# CONFIG_I2C is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Mice
+# Non-8250 serial port support
 #
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=m
-# CONFIG_PSMOUSE is not set
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Joysticks
+# IPMI
 #
-# CONFIG_JOYSTICK is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER 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_SA1100_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
-CONFIG_PCMCIA_SERIAL=y
 
 #
-# PCMCIA character device support
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
 #
-# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# 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_CRAMFS is not set
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS 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_SYSV_FS_WRITE 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_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS 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_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_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -488,11 +741,15 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 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_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -500,71 +757,47 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_5 is not set
 # CONFIG_NLS_ISO8859_6 is not set
 # CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 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
+# Profiling support
 #
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FB=y
+# CONFIG_PROFILING is not set
 
 #
-# Frame-buffer support
+# Kernel hacking
 #
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_ACORN is not set
-# CONFIG_FB_CLPS711X is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_SA1100=y
-# 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=y
-# CONFIG_FBCON_CFB8 is not set
-# CONFIG_FBCON_CFB16 is not set
-# 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=y
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
 
 #
-# Sound
+# Security options
 #
-# CONFIG_SOUND is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB support
+# Cryptographic options
 #
-# CONFIG_USB is not set
+# CONFIG_CRYPTO is not set
 
 #
-# Kernel hacking
+# Hardware crypto devices
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_DEBUG_LL=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/pleb_defconfig b/arch/arm/configs/pleb_defconfig
--- a/arch/arm/configs/pleb_defconfig
+++ b/arch/arm/configs/pleb_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Wed Nov 24 15:12:32 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:03:02 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -26,7 +27,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 # CONFIG_KOBJECT_UEVENT is not set
 # CONFIG_IKCONFIG is not set
@@ -34,6 +34,7 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -43,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -96,7 +98,6 @@ CONFIG_SA1100_PLEB=y
 # CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_SSP is not set
-# CONFIG_SA1100_USB is not set
 
 #
 # Processor Type
@@ -115,17 +116,39 @@ CONFIG_CPU_MINICACHE=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,9600 mem=16M@0xc0000000 mem=16M@0xc8000000 root=/dev/ram initrd=0xc0400000,4M"
 # CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
@@ -135,41 +158,50 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_SA1100=y
 
 #
-# At least one math emulation must be selected
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,9600 mem=16M@0xc0000000 mem=16M@0xc8000000 root=/dev/ram initrd=0xc0400000,4M"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 # CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -208,6 +240,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -225,6 +258,7 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -239,6 +273,11 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -248,10 +287,12 @@ CONFIG_MTD_SA1100=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
@@ -264,6 +305,17 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_IOSCHED_AS is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -271,6 +323,18 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -388,28 +452,6 @@ CONFIG_SMC91X=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -420,19 +462,11 @@ CONFIG_SMC91X=y
 # CONFIG_INPUT is not set
 
 #
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
+# Hardware I/O ports
 #
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
 
 #
 # Character devices
@@ -477,11 +511,20 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -492,6 +535,33 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -502,6 +572,10 @@ CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -567,7 +641,6 @@ CONFIG_NFS_DIRECTIO=y
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=m
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -633,47 +706,20 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_WAITQ is not set
@@ -692,6 +738,10 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig
new file mode 100644
--- /dev/null
+++ b/arch/arm/configs/pxa255-idp_defconfig
@@ -0,0 +1,799 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:20:17 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+CONFIG_ARCH_PXA_IDP=y
+# CONFIG_PXA_SHARPSL is not set
+CONFIG_PXA25x=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs ip=dhcp console=ttyS0,115200 mem=64M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_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
+# CONFIG_INFTL 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=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_SHARP_SL is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+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_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# 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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig
--- a/arch/arm/configs/rpc_defconfig
+++ b/arch/arm/configs/rpc_defconfig
@@ -1,124 +1,178 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Wed Mar  9 14:41:48 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
-CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_FIQ=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 CONFIG_ARCH_RPC=y
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+CONFIG_ARCH_ACORN=y
 
 #
-# Archimedes/A5000 Implementations
+# Processor Type
 #
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM610=y
+CONFIG_CPU_ARM710=y
+CONFIG_CPU_SA110=y
+CONFIG_CPU_32v3=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V3=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V3=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V3=y
+CONFIG_CPU_TLB_V4WB=y
 
 #
-# Archimedes/A5000 Implementations (select only ONE)
+# Processor Features
 #
+CONFIG_TIMER_ACORN=y
 
 #
-# CLPS711X/EP721X Implementations
+# Bus support
 #
 
 #
-# Epxa10db
+# PCCARD (PCMCIA/CardBus) support
 #
+# CONFIG_PCCARD is not set
 
 #
-# Footbridge Implementations
+# PC-card bridges
 #
 
 #
-# IOP310 Implementation Options
+# Kernel Features
 #
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# IOP310 Chipset Features
+# Boot options
 #
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
 
 #
-# Intel PXA250/210 Implementations
+# Floating point emulation
 #
 
 #
-# SA11x0 Implementations
+# At least one emulation must be selected
 #
-CONFIG_ARCH_ACORN=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 
 #
-# Processor Type
+# Userspace binary formats
 #
-CONFIG_CPU_32=y
-CONFIG_CPU_ARM610=y
-CONFIG_CPU_ARM710=y
-CONFIG_CPU_SA110=y
-CONFIG_CPU_32v3=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Processor Features
+# Power management options
 #
+# CONFIG_PM is not set
 
 #
-# General setup
+# Device Drivers
 #
-CONFIG_FIQ=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-# CONFIG_HOTPLUG is not set
 
 #
-# At least one math emulation must be selected
+# Generic Driver Options
 #
-CONFIG_FPE_NWFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-CONFIG_ALIGNMENT_TRAP=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
 
 #
 # Parallel port support
@@ -126,7 +180,6 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
 CONFIG_PARPORT_PC_CML1=y
-# CONFIG_PARPORT_SERIAL is not set
 CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_ARC is not set
@@ -134,163 +187,52 @@ CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_1284 is not set
 
 #
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
+# Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# CONFIG_MD is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # Acorn-specific block devices
 #
 
 #
-# Networking options
-#
-# CONFIG_PACKET 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=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 is not set
-# CONFIG_IPV6 is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_ETHER1=y
-CONFIG_ARM_ETHER3=y
-CONFIG_ARM_ETHERH=y
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# 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_NET_FC is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
 # ATA/ATAPI/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 is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_IDEDISK_STROKE 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
@@ -298,18 +240,22 @@ CONFIG_BLK_DEV_IDECD=y
 #
 # IDE chipset support/bugfixes
 #
-CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE_ARM=y
 CONFIG_BLK_DEV_IDE_ICSIDE=y
 CONFIG_BLK_DEV_IDEDMA_ICS=y
 CONFIG_IDEDMA_ICS_AUTO=y
 CONFIG_BLK_DEV_IDE_RAPIDE=y
-CONFIG_IDEDMA_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -319,43 +265,30 @@ CONFIG_CHR_DEV_ST=m
 # 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_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_ACARD 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_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC 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_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_SATA is not set
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_IMM=m
 # CONFIG_SCSI_IZIP_EPP16 is not set
 # CONFIG_SCSI_IZIP_SLOW_CTR is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_ACORNSCSI_3=m
 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
@@ -372,109 +305,228 @@ CONFIG_SCSI_CUMANA_1=m
 CONFIG_SCSI_OAK1=m
 
 #
-# I2O device support
+# Multi-device support (RAID and LVM)
 #
-# CONFIG_I2O is not set
+# CONFIG_MD is not set
 
 #
-# ISDN subsystem
+# Fusion MPT device support
 #
-# CONFIG_ISDN_BOOL is not set
 
 #
-# Input device support
+# IEEE 1394 (FireWire) support
 #
-CONFIG_INPUT=y
 
 #
-# Userland interfaces
+# I2O device support
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
+# Networking support
 #
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-CONFIG_SERIO_RPCKBD=y
+CONFIG_NET=y
 
 #
-# Input Device Drivers
+# Networking options
 #
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-# CONFIG_MOUSE_PS2 is not set
-# CONFIG_MOUSE_SERIAL is not set
-CONFIG_MOUSE_RISCPC=y
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_PACKET is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
 
 #
-# Character devices
+# SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
 
 #
-# Serial drivers
+# QoS and/or fair queueing
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Non-8250 serial port support
+# Network testing
 #
-CONFIG_SERIAL_8250_ACORN=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_PRINTER=m
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
-# CONFIG_TIPAR is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# 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
 
 #
-# I2C support
+# Ethernet (10 or 100Mbit)
 #
-CONFIG_I2C=y
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_PROC is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_ARM_ETHER1=y
+CONFIG_ARM_ETHER3=y
+CONFIG_ARM_ETHERH=y
+# CONFIG_SMC91X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_RPCKBD=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+CONFIG_MOUSE_RISCPC=y
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
-# L3 serial bus support
+# Non-8250 serial port support
 #
-# CONFIG_L3 is not set
+CONFIG_SERIAL_8250_ACORN=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=64
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
-# Mice
+# IPMI
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
@@ -482,84 +534,292 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
 
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_ACORN=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 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_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+CONFIG_SOUND_VIDC=m
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=m
-# CONFIG_REISERFS_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 CONFIG_ADFS_FS=y
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_XFS_FS 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_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-# CONFIG_CIFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-CONFIG_FS_MBCACHE=y
 
 #
 # Partition Types
@@ -586,11 +846,11 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_737=m
@@ -615,6 +875,7 @@ CONFIG_NLS_CODEPAGE_874=m
 CONFIG_NLS_ISO8859_8=m
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_2=m
 CONFIG_NLS_ISO8859_3=m
@@ -631,139 +892,35 @@ CONFIG_NLS_KOI8_R=m
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
+# Profiling support
 #
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_ACORN=y
-# CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-CONFIG_FBCON_MFB=y
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_ACCEL 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_VGA_PLANES is not set
-# CONFIG_FBCON_HGA is not set
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-# CONFIG_FONT_MINI_4x6 is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=m
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO 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_OSS=m
-# CONFIG_SOUND_TRACEINIT is not set
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-CONFIG_SOUND_VIDC=m
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_ERRORS=y
-# CONFIG_KALLSYMS is not set
 CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
 # Security options
 #
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
@@ -771,6 +928,12 @@ CONFIG_SECURITY_CAPABILITIES=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc1-bk5
-# Tue Jan 18 11:36:49 2005
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 17:47:45 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -28,7 +28,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
@@ -36,6 +35,7 @@ CONFIG_KOBJECT_UEVENT=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -45,6 +45,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -86,13 +87,22 @@ CONFIG_ARCH_S3C2410=y
 #
 CONFIG_ARCH_BAST=y
 CONFIG_ARCH_H1940=y
+CONFIG_MACH_N30=y
 CONFIG_ARCH_SMDK2410=y
+CONFIG_ARCH_S3C2440=y
 CONFIG_MACH_VR1000=y
 CONFIG_MACH_RX3715=y
+CONFIG_MACH_OTOM=y
+CONFIG_MACH_NEXCODER_2440=y
 CONFIG_CPU_S3C2410=y
 CONFIG_CPU_S3C2440=y
 
 #
+# S3C2410 Boot
+#
+# CONFIG_S3C2410_BOOT_WATCHDOG is not set
+
+#
 # S3C2410 Setup
 #
 CONFIG_S3C2410_DMA=y
@@ -122,11 +132,8 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
 #
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-# CONFIG_XIP_KERNEL is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -134,49 +141,63 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 # CONFIG_PCCARD is not set
 
 #
-# PC-card bridges
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
 #
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 CONFIG_APM=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-CONFIG_PARPORT=y
-# CONFIG_PARPORT_PC is not set
-# CONFIG_PARPORT_ARC is not set
-CONFIG_PARPORT_OTHER=y
-CONFIG_PARPORT_1284=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
@@ -261,6 +282,15 @@ CONFIG_MTD_NAND_S3C2410=y
 # CONFIG_MTD_NAND_NANDSIM is not set
 
 #
+# Parallel port support
+#
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_1284=y
+
+#
 # Plug and Play support
 #
 
@@ -290,11 +320,56 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_ATA_OVER_ETH=m
 
 #
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDE_BAST=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -399,51 +474,6 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDETAPE=m
-CONFIG_BLK_DEV_IDEFLOPPY=m
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDE_BAST=y
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -466,18 +496,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -495,6 +513,17 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -505,7 +534,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
-# CONFIG_DIGI is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
@@ -575,6 +603,11 @@ CONFIG_S3C2410_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -608,7 +641,9 @@ CONFIG_I2C_SENSOR=m
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 CONFIG_SENSORS_LM75=m
@@ -640,6 +675,10 @@ CONFIG_SENSORS_EEPROM=m
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -650,6 +689,53 @@ CONFIG_SENSORS_EEPROM=m
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -663,6 +749,10 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -737,7 +827,6 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -817,64 +906,16 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/shannon_defconfig b/arch/arm/configs/shannon_defconfig
--- a/arch/arm/configs/shannon_defconfig
+++ b/arch/arm/configs/shannon_defconfig
@@ -1,33 +1,63 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:26:46 2005
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_OBSOLETE=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -35,133 +65,139 @@ CONFIG_MODULES=y
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-
-#
-# Footbridge Implementations
-#
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
 CONFIG_SA1100_SHANNON=y
-# CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_SSP is not set
 
 #
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
+# Processor Type
+#
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# Processor Type
+# Processor Features
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-CONFIG_CPU_SA1100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
 
 #
-# General setup
+# Bus support
 #
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_HOTPLUG=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
-# CONFIG_I82092 is not set
+
+#
+# PC-card bridges
+#
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_SA1100=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 
 #
-# At least one math emulation must be selected
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc"
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Power management options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_PM is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
@@ -171,6 +207,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -179,36 +216,49 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
 CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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
 
 #
 # Mapping drivers for chip access
 #
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_EDB7312 is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD 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
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -216,7 +266,12 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 # CONFIG_PNP is not set
 
@@ -225,11 +280,57 @@ CONFIG_MTD_SA1100=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -237,67 +338,99 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 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_INET_ECN is not set
+# CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
+# CONFIG_NETFILTER is not set
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -309,28 +442,20 @@ CONFIG_NET_ETHERNET=y
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# CONFIG_NET_RADIO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_WAN is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # PCMCIA network device support
@@ -343,90 +468,136 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_PCMCIA_NMCLAN is not set
 CONFIG_PCMCIA_SMC91C92=y
 # CONFIG_PCMCIA_XIRC2PS is not set
-# CONFIG_NET_PCMCIA_RADIO is not set
+# CONFIG_PCMCIA_AXNET is not set
 
 #
-# Amateur Radio support
+# Wan interfaces
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# IrDA (infrared) support
+# ISDN subsystem
 #
-# CONFIG_IRDA is not set
+# CONFIG_ISDN is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Input device support
 #
-CONFIG_IDE=m
+CONFIG_INPUT=y
 
 #
-# IDE, ATA and ATAPI Block devices
+# Userland interfaces
 #
-CONFIG_BLK_DEV_IDE=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Input Device Drivers
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-# CONFIG_BLK_DEV_IDEDISK 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_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
 
 #
-# IDE chipset support/bugfixes
+# Character devices
 #
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_ATARAID is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# SCSI support
+# Serial drivers
 #
-# CONFIG_SCSI is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# I2O device support
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
 #
-# CONFIG_I2O is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# ISDN subsystem
+# Watchdog Cards
 #
-# CONFIG_ISDN is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Input core support
+# Watchdog Device Drivers
 #
-CONFIG_INPUT=y
-CONFIG_INPUT_KEYBDEV=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=y
 
 #
-# Character devices
+# ISA-based Watchdog Cards
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
 
 #
-# Serial drivers
+# Ftape, the floppy tape device driver
 #
-CONFIG_SERIAL_SA1100=y
-CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=9600
-# CONFIG_SERIAL_8250 is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -434,129 +605,168 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
-# L3 serial bus support
+# Misc devices
+#
+
+#
+# Multimedia devices
 #
-# CONFIG_L3 is not set
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Other L3 adapters
+# Digital Video Broadcasting Devices
 #
-# CONFIG_BIT_SA1100_GPIO is not set
+# CONFIG_DVB is not set
 
 #
-# Mice
+# Graphics support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
 
 #
-# Joysticks
+# Console display driver support
 #
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_SERIO is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
 
 #
-# Joysticks
+# Logo configuration
 #
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Watchdog Cards
+# Sound
 #
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-CONFIG_SA1100_WATCHDOG=y
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_SA1100_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+CONFIG_SOUND=y
 
 #
-# Ftape, the floppy tape device driver
+# Advanced Linux Sound Architecture
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+# CONFIG_SND is not set
 
 #
-# PCMCIA character devices
+# Open Sound System
 #
+# CONFIG_SOUND_PRIME is not set
 
 #
-# Multimedia devices
+# USB support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # File systems
 #
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-CONFIG_MINIX_FS=y
-# CONFIG_FREEVXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_EXT2_FS is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS 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_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -576,12 +786,12 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -604,7 +814,9 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -621,112 +833,40 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
+# Profiling support
 #
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_PROFILING is not set
 
 #
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_SA1100=y
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-# 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_BT878 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO 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_SA1100=y
-# CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_OSS is not set
-
-#
-# Multimedia Capabilities Port drivers
-#
-CONFIG_MCP=y
-CONFIG_MCP_SA1100=y
-CONFIG_MCP_UCB1200=y
-CONFIG_MCP_UCB1200_AUDIO=y
-CONFIG_MCP_UCB1200_TS=y
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-
-#
-# USB Device Class drivers
-#
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-# USB Imaging devices
-#
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-# USB port drivers
+# Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 
 #
-# USB Serial Converter support
+# Security options
 #
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
-# USB Miscellaneous drivers
+# Cryptographic options
 #
+# CONFIG_CRYPTO is not set
 
 #
-# Bluetooth support
+# Hardware crypto devices
 #
-# CONFIG_BT is not set
 
 #
-# Kernel hacking
+# Library routines
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_SPINLOCK is not set
-CONFIG_DEBUG_LL=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/shark_defconfig b/arch/arm/configs/shark_defconfig
--- a/arch/arm/configs/shark_defconfig
+++ b/arch/arm/configs/shark_defconfig
@@ -1,36 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 23:59:14 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
 CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -40,125 +54,134 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
 CONFIG_ARCH_SHARK=y
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# CLPS711X/EP721X Implementations
+# Processor Type
 #
+CONFIG_CPU_32=y
+CONFIG_CPU_SA110=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
 
 #
-# Epxa10db
+# Processor Features
 #
 
 #
-# Footbridge Implementations
+# Bus support
 #
+CONFIG_ISA=y
+CONFIG_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_HOST_VIA82C505=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
 
 #
-# IOP3xx Implementation Options
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
+# CONFIG_PCCARD is not set
 
 #
-# IOP3xx Chipset Features
+# Kernel Features
 #
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Intel PXA250/210 Implementations
+# Boot options
 #
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
 
 #
-# SA11x0 Implementations
+# Floating point emulation
 #
 
 #
-# Processor Type
+# At least one emulation must be selected
 #
-CONFIG_CPU_32=y
-CONFIG_CPU_SA110=y
-CONFIG_CPU_32v4=y
-CONFIG_CPU_ABRT_EV4=y
-CONFIG_CPU_CACHE_V4WB=y
-CONFIG_CPU_COPY_V4WB=y
-CONFIG_CPU_TLB_V4WB=y
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FPE_FASTFPE=y
 
 #
-# Processor Features
+# Userspace binary formats
 #
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# General setup
+# Power management options
 #
-CONFIG_PCI=y
-CONFIG_PCI_HOST_VIA82C505=y
-CONFIG_ISA=y
-CONFIG_ISA_DMA=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
+# CONFIG_PM is not set
 
 #
-# At least one math emulation must be selected
+# Device Drivers
 #
-# CONFIG_FPE_NWFPE is not set
-CONFIG_FPE_FASTFPE=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
 
 #
 # Generic Driver Options
 #
-# CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-# CONFIG_LEDS_CPU is not set
-CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
 
 #
 # Parallel port support
 #
 CONFIG_PARPORT=y
 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_ARC is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_1284 is not set
 
 #
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -173,12 +196,144 @@ CONFIG_PARPORT_PC_CML1=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_IDE_ARM=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX 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_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA 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_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_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS 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_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR 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_QLA2XXX=m
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -186,6 +341,21 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -205,23 +375,24 @@ CONFIG_INET=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -230,39 +401,44 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
-# CONFIG_SMC91X is not set
 # CONFIG_HAPPYMEAL 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_SMC91X is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -280,6 +456,7 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 CONFIG_CS89x0=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
@@ -306,220 +483,95 @@ CONFIG_CS89x0=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB 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
+# CONFIG_S2IO is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
+# CONFIG_TR is not set
 
 #
-# Token Ring devices
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # Wan interfaces
 #
 # CONFIG_WAN 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
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
-# Amateur Radio support
+# ISDN subsystem
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_ISDN is not set
 
 #
-# IrDA (infrared) support
+# Input device support
 #
-# CONFIG_IRDA is not set
+CONFIG_INPUT=y
 
 #
-# Bluetooth support
+# Userland interfaces
 #
-# CONFIG_BT is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=m
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_CHR_DEV_SG=m
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# 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_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 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_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_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_IPS 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_SYM53C8XX_2 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_SYM53C416 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
+# Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_PS2_SYNAPTICS is not set
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_INPORT is not set
 # CONFIG_MOUSE_LOGIBM is not set
 # CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -538,77 +590,189 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_DZ is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
 
 #
+# IPMI
+#
+# CONFIG_IPMI_HANDLER 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_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
-# I2C Algorithms
+# Misc devices
 #
 
 #
-# I2C Hardware Bus support
+# Multimedia devices
 #
+# CONFIG_VIDEO_DEV is not set
 
 #
-# I2C Hardware Sensors Chip support
+# Digital Video Broadcasting Devices
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_DVB is not set
 
 #
-# L3 serial bus support
+# Graphics support
 #
-# CONFIG_L3 is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
-# Mice
+# Console display driver support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 
 #
-# IPMI
+# Logo configuration
 #
-# CONFIG_IPMI_HANDLER is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Watchdog Cards
+# Sound
 #
-# 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
+CONFIG_SOUND=m
 
 #
-# Ftape, the floppy tape device driver
+# Advanced Linux Sound Architecture
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
+# CONFIG_SND is not set
 
 #
-# Multimedia devices
+# Open Sound System
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_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_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_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+CONFIG_SOUND_ADLIB=m
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+CONFIG_SOUND_SB=m
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_KAHLUA is not set
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_AD1980 is not set
 
 #
-# Digital Video Broadcasting Devices
+# USB support
 #
-# CONFIG_DVB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
 
 #
 # MMC/SD Card support
@@ -629,10 +793,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -650,16 +819,19 @@ CONFIG_JOLIET=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
@@ -671,6 +843,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -690,14 +863,13 @@ CONFIG_NFS_FS=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -715,16 +887,15 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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 is not set
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -749,6 +920,7 @@ CONFIG_NLS_CODEPAGE_850=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -765,142 +937,24 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-CONFIG_FB_CYBER2000=y
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY 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_PM3 is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
+# Profiling support
 #
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=m
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_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_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_SOUND_OSS=m
-# CONFIG_SOUND_TRACEINIT is not set
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_AD1889 is not set
-# CONFIG_SOUND_SGALAXY is not set
-CONFIG_SOUND_ADLIB=m
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_PSS is not set
-CONFIG_SOUND_SB=m
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_YMFPCI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-# CONFIG_SOUND_KAHLUA is not set
-# CONFIG_SOUND_ALI5455 is not set
-# CONFIG_SOUND_FORTE is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_AD1980 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -909,6 +963,12 @@ CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/simpad_defconfig b/arch/arm/configs/simpad_defconfig
--- a/arch/arm/configs/simpad_defconfig
+++ b/arch/arm/configs/simpad_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc2
-# Thu Sep 16 15:42:43 2004
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:10:36 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_IOMAP=y
 
 #
@@ -15,6 +16,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
@@ -26,22 +28,24 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -50,6 +54,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -73,46 +78,27 @@ CONFIG_ARCH_SA1100=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
 # CONFIG_SA1100_COLLIE is not set
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HACKKIT is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
 # CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
 # CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
 CONFIG_SA1100_SIMPAD=y
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_STORK is not set
 # CONFIG_SA1100_SSP is not set
-# CONFIG_SA1100_USB is not set
 
 #
 # Processor Type
@@ -122,6 +108,7 @@ CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
 CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
 CONFIG_CPU_MINICACHE=y
 
@@ -130,63 +117,91 @@ CONFIG_CPU_MINICACHE=y
 #
 
 #
-# General setup
+# Bus support
 #
-CONFIG_DISCONTIGMEM=y
 CONFIG_ISA=y
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-# CONFIG_CPU_FREQ is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+CONFIG_PCCARD=y
 # CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_SA1100=y
 
 #
-# At least one math emulation must be selected
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mtdparts=sa1100:512k(boot),1m(kernel),-(root) console=ttySA0 root=1f02 noinitrd mem=64M jffs2_orphaned_inodes=delete rootfstype=jffs2"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-CONFIG_PREEMPT=y
 CONFIG_APM=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="mtdparts=sa1100:512k(boot),1m(kernel),-(root) console=ttySA0 root=1f02 noinitrd mem=64M jffs2_orphaned_inodes=delete rootfstype=jffs2"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-# CONFIG_LEDS_CPU is not set
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -228,6 +243,7 @@ CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -246,6 +262,7 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -260,6 +277,11 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -269,11 +291,34 @@ CONFIG_MTD_SA1100=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -281,6 +326,18 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -308,6 +365,8 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -327,7 +386,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -405,10 +463,10 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
 # Bluetooth device drivers
 #
 # CONFIG_BT_HCIUART is not set
-CONFIG_BT_HCIDTL1=m
-CONFIG_BT_HCIBT3C=m
-CONFIG_BT_HCIBLUECARD=m
-CONFIG_BT_HCIBTUART=m
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
 # CONFIG_BT_HCIVHCI is not set
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
@@ -482,7 +540,7 @@ CONFIG_PCMCIA_WAVELAN=m
 #
 # Wireless 802.11b Pcmcia/Cardbus cards support
 #
-CONFIG_AIRO_CS=m
+# CONFIG_AIRO_CS is not set
 # CONFIG_PCMCIA_WL3501 is not set
 CONFIG_NET_WIRELESS=y
 
@@ -516,28 +574,6 @@ CONFIG_PPPOE=m
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -562,15 +598,6 @@ CONFIG_INPUT_EVDEV=m
 CONFIG_INPUT_EVBUG=y
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-CONFIG_SERIO_CT82C710=m
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -580,6 +607,16 @@ CONFIG_SERIO_CT82C710=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -629,11 +666,20 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -644,6 +690,71 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=m
@@ -660,10 +771,15 @@ CONFIG_REISERFS_FS=m
 CONFIG_REISERFS_PROC_INFO=y
 # CONFIG_REISERFS_FS_XATTR is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -712,6 +828,7 @@ CONFIG_JFFS_FS_VERBOSE=0
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -734,7 +851,6 @@ CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -749,6 +865,7 @@ CONFIG_SMB_FS=m
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # Native Language Support
@@ -800,75 +917,21 @@ CONFIG_NLS_ISO8859_15=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_SA1100 is not set
-CONFIG_FB_MQ200=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
@@ -879,6 +942,7 @@ CONFIG_DEBUG_LL=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -887,6 +951,10 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/arm/configs/smdk2410_defconfig b/arch/arm/configs/smdk2410_defconfig
--- a/arch/arm/configs/smdk2410_defconfig
+++ b/arch/arm/configs/smdk2410_defconfig
@@ -1,40 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Sun Mar 27 22:42:40 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -44,82 +54,51 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_SHARK is not set
 CONFIG_ARCH_S3C2410=y
-# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_VERSATILE_PB is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Core Type
-#
-
-#
-# OMAP Board Type
-#
-
-#
-# OMAP Feature Selections
-#
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# S3C2410 Implementations
+# S3C24XX Implementations
 #
 # CONFIG_ARCH_BAST is not set
 # CONFIG_ARCH_H1940 is not set
+# CONFIG_MACH_N30 is not set
 CONFIG_ARCH_SMDK2410=y
+# CONFIG_ARCH_S3C2440 is not set
 # CONFIG_MACH_VR1000 is not set
+# CONFIG_MACH_RX3715 is not set
+# CONFIG_MACH_OTOM is not set
+# CONFIG_MACH_NEXCODER_2440 is not set
+CONFIG_CPU_S3C2410=y
+
+#
+# S3C2410 Boot
+#
 
 #
-# LH7A40X Implementations
+# S3C2410 Setup
 #
+# CONFIG_S3C2410_DMA is not set
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
 
 #
 # Processor Type
@@ -129,6 +108,7 @@ CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -141,43 +121,70 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
-# General setup
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=1f04 mem=32M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
 #
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0
-CONFIG_ZBOOT_ROM_BSS=0
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 # CONFIG_FPE_NWFPE is not set
 # CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_DEBUG_DRIVER is not set
 # CONFIG_PM is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=1f04 mem=32M"
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS is not set
 
 #
 # User Modules And Translation Layers
@@ -195,13 +202,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -215,8 +233,10 @@ CONFIG_MTD_CFI_INTELEXT=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -231,6 +251,11 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -238,11 +263,34 @@ CONFIG_MTD_CFI_INTELEXT=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -250,6 +298,18 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -275,6 +335,9 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -294,12 +357,12 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -321,6 +384,7 @@ CONFIG_NETDEVICES=y
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_SMC91X is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -349,29 +413,6 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -394,16 +435,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -421,6 +452,16 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -443,7 +484,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -456,25 +496,31 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
+# CONFIG_S3C2410_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -485,6 +531,56 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_VIRTUAL=y
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -493,10 +589,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -509,7 +610,8 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -552,14 +654,13 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -573,7 +674,6 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -590,68 +690,33 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Misc devices
-#
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_ERRORS is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_LL_PRINTK=y
 CONFIG_DEBUG_S3C2410_PORT=y
 CONFIG_DEBUG_S3C2410_UART=0
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -660,7 +725,12 @@ CONFIG_DEBUG_S3C2410_UART=0
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig
--- a/arch/arm/configs/versatile_defconfig
+++ b/arch/arm/configs/versatile_defconfig
@@ -1,40 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc1-bk2
+# Mon Mar 28 00:20:50 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -44,70 +54,33 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_OMAP is not set
 CONFIG_ARCH_VERSATILE=y
-
-#
-# CLPS711X/EP721X Implementations
-#
-
-#
-# Epxa10db
-#
-
-#
-# Footbridge Implementations
-#
-
-#
-# IOP3xx Implementation Options
-#
-# CONFIG_ARCH_IOP310 is not set
-# CONFIG_ARCH_IOP321 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Intel PXA250/210 Implementations
-#
-
-#
-# SA11x0 Implementations
-#
-
-#
-# TI OMAP Implementations
-#
-
-#
-# OMAP Feature Selections
-#
-
-#
-# S3C2410 Implementations
-#
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # Versatile platform type
@@ -122,6 +95,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_ARM926T=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -133,56 +107,80 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ICST307=y
 
 #
-# General setup
+# Bus support
 #
 CONFIG_ARM_AMBA=y
-# CONFIG_ZBOOT_ROM is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=1f03 mem=32M"
+# CONFIG_XIP_KERNEL is not set
 
 #
-# PCMCIA/CardBus support
+# Floating point emulation
 #
-# CONFIG_PCMCIA is not set
 
 #
-# At least one math emulation must be selected
+# At least one emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
 # CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 
 #
-# Generic Driver Options
+# Power management options
 #
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
-# CONFIG_PREEMPT is not set
 # CONFIG_APM is not set
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=1f03 mem=32M"
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER 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_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -207,13 +205,24 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # 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_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -227,8 +236,10 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -243,6 +254,11 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # CONFIG_MTD_NAND is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -250,11 +266,29 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -262,6 +296,18 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -289,6 +335,9 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -308,12 +357,12 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -353,7 +402,6 @@ CONFIG_SMC91X=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
 
 #
 # Wan interfaces
@@ -365,29 +413,6 @@ CONFIG_SMC91X=y
 # CONFIG_NETCONSOLE is not set
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -406,22 +431,10 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_TSLIBDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_AMBAKMI=y
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -439,6 +452,17 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -469,7 +493,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=16
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -482,20 +505,21 @@ CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -506,33 +530,44 @@ CONFIG_I2C_CHARDEV=m
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
 #
 CONFIG_I2C_SENSOR=m
 # CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
@@ -543,15 +578,15 @@ CONFIG_I2C_SENSOR=m
 CONFIG_SENSORS_EEPROM=m
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# L3 serial bus support
+# Misc devices
 #
-# CONFIG_L3 is not set
 
 #
 # Multimedia devices
@@ -564,6 +599,88 @@ CONFIG_SENSORS_EEPROM=m
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_ARMCLCD=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
 # MMC/SD Card support
 #
 CONFIG_MMC=y
@@ -580,10 +697,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 CONFIG_MINIX_FS=y
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -599,6 +721,8 @@ CONFIG_ROMFS_FS=y
 CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -626,6 +750,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -650,11 +779,11 @@ CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -672,7 +801,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -706,6 +834,7 @@ CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -727,107 +856,23 @@ CONFIG_NLS_ISO8859_1=m
 # CONFIG_PROFILING is not set
 
 #
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_ARMCLCD=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-CONFIG_FONT_ACORN_8x8=y
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-# CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-CONFIG_SND_AC97_CODEC=m
-
-#
-# ALSA ARM devices
-#
-CONFIG_SND_ARMAACI=m
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-
-#
-# Console Switches
-#
-# CONFIG_SWITCHES is not set
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
@@ -835,6 +880,7 @@ CONFIG_DEBUG_LL=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -843,8 +889,14 @@ CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -31,8 +31,3 @@ head-y			:= head.o
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 
 extra-y := $(head-y) init_task.o vmlinux.lds
-
-# Spell out some dependencies that aren't automatically figured out
-$(obj)/entry-armv.o: 	$(obj)/entry-header.S include/asm-arm/constants.h
-$(obj)/entry-common.o: 	$(obj)/entry-header.S include/asm-arm/constants.h \
-			$(obj)/calls.S
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -64,6 +64,26 @@ int main(void)
   DEFINE(TI_VFPSTATE,		offsetof(struct thread_info, vfpstate));
   DEFINE(TI_IWMMXT_STATE,	(offsetof(struct thread_info, fpstate)+4)&~7);
   BLANK();
+  DEFINE(S_R0,			offsetof(struct pt_regs, ARM_r0));
+  DEFINE(S_R1,			offsetof(struct pt_regs, ARM_r1));
+  DEFINE(S_R2,			offsetof(struct pt_regs, ARM_r2));
+  DEFINE(S_R3,			offsetof(struct pt_regs, ARM_r3));
+  DEFINE(S_R4,			offsetof(struct pt_regs, ARM_r4));
+  DEFINE(S_R5,			offsetof(struct pt_regs, ARM_r5));
+  DEFINE(S_R6,			offsetof(struct pt_regs, ARM_r6));
+  DEFINE(S_R7,			offsetof(struct pt_regs, ARM_r7));
+  DEFINE(S_R8,			offsetof(struct pt_regs, ARM_r8));
+  DEFINE(S_R9,			offsetof(struct pt_regs, ARM_r9));
+  DEFINE(S_R10,			offsetof(struct pt_regs, ARM_r10));
+  DEFINE(S_FP,			offsetof(struct pt_regs, ARM_fp));
+  DEFINE(S_IP,			offsetof(struct pt_regs, ARM_ip));
+  DEFINE(S_SP,			offsetof(struct pt_regs, ARM_sp));
+  DEFINE(S_LR,			offsetof(struct pt_regs, ARM_lr));
+  DEFINE(S_PC,			offsetof(struct pt_regs, ARM_pc));
+  DEFINE(S_PSR,			offsetof(struct pt_regs, ARM_cpsr));
+  DEFINE(S_OLD_R0,		offsetof(struct pt_regs, ARM_ORIG_r0));
+  DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
+  BLANK();
 #if __LINUX_ARM_ARCH__ >= 6
   DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id));
   BLANK();
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/calls.S
  *
- *  Copyright (C) 1995-2004 Russell King
+ *  Copyright (C) 1995-2005 Russell King
  *
  * 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
@@ -10,7 +10,7 @@
  *  This file is included twice in entry-common.S
  */
 #ifndef NR_syscalls
-#define NR_syscalls 288
+#define NR_syscalls 320
 #else
 
 __syscall_start:
@@ -295,6 +295,38 @@ __syscall_start:
 		.long	sys_mq_notify
 		.long	sys_mq_getsetattr
 /* 280 */	.long	sys_waitid
+		.long	sys_socket
+		.long	sys_bind
+		.long	sys_connect
+		.long	sys_listen
+/* 285 */	.long	sys_accept
+		.long	sys_getsockname
+		.long	sys_getpeername
+		.long	sys_socketpair
+		.long	sys_send
+/* 290 */	.long	sys_sendto
+		.long	sys_recv
+		.long	sys_recvfrom
+		.long	sys_shutdown
+		.long	sys_setsockopt
+/* 295 */	.long	sys_getsockopt
+		.long	sys_sendmsg
+		.long	sys_recvmsg
+		.long	sys_semop
+		.long	sys_semget
+/* 300 */	.long	sys_semctl
+		.long	sys_msgsnd
+		.long	sys_msgrcv
+		.long	sys_msgget
+		.long	sys_msgctl
+/* 305 */	.long	sys_shmat
+		.long	sys_shmdt
+		.long	sys_shmget
+		.long	sys_shmctl
+		.long	sys_add_key
+/* 310 */	.long	sys_request_key
+		.long	sys_keyctl
+		.long	sys_semtimedop
 __syscall_end:
 
 		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -85,27 +85,21 @@ static struct expcard_blacklist __initda
 };
 
 asmlinkage extern int
-ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
+ecard_loader_reset(unsigned long base, loader_t loader);
 asmlinkage extern int
-ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
+ecard_loader_read(int off, unsigned long base, loader_t loader);
 
-static const struct ecard_id *
-ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec);
-
-static inline unsigned short
-ecard_getu16(unsigned char *v)
+static inline unsigned short ecard_getu16(unsigned char *v)
 {
 	return v[0] | v[1] << 8;
 }
 
-static inline signed long
-ecard_gets24(unsigned char *v)
+static inline signed long ecard_gets24(unsigned char *v)
 {
 	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
 }
 
-static inline ecard_t *
-slot_to_ecard(unsigned int slot)
+static inline ecard_t *slot_to_ecard(unsigned int slot)
 {
 	return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
 }
@@ -122,26 +116,31 @@ slot_to_ecard(unsigned int slot)
  * From a security standpoint, we trust the card vendors.  This
  * may be a misplaced trust.
  */
-#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
-#define POD_INT_ADDR(x)	((volatile unsigned char *)\
-			 ((BUS_ADDR((x)) - IO_BASE) + IO_START))
-
 static void ecard_task_reset(struct ecard_request *req)
 {
 	struct expansion_card *ec = req->ec;
-	if (ec->loader)
-		ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
+	struct resource *res;
+
+	res = ec->slot_no == 8
+		? &ec->resource[ECARD_RES_MEMC]
+		: ec->type == ECARD_EASI
+		  ? &ec->resource[ECARD_RES_EASI]
+		  : &ec->resource[ECARD_RES_IOCSYNC];
+
+	ecard_loader_reset(res->start, ec->loader);
 }
 
 static void ecard_task_readbytes(struct ecard_request *req)
 {
-	unsigned char *buf = (unsigned char *)req->buffer;
-	volatile unsigned char *base_addr =
-		(volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
+	struct expansion_card *ec = req->ec;
+	unsigned char *buf = req->buffer;
 	unsigned int len = req->length;
 	unsigned int off = req->address;
 
-	if (req->ec->slot_no == 8) {
+	if (ec->slot_no == 8) {
+		void __iomem *base = (void __iomem *)
+				ec->resource[ECARD_RES_MEMC].start;
+
 		/*
 		 * The card maintains an index which increments the address
 		 * into a 4096-byte page on each access.  We need to keep
@@ -161,7 +160,7 @@ static void ecard_task_readbytes(struct 
 		 * greater than the offset, reset the hardware index counter.
 		 */
 		if (off == 0 || index > off) {
-			*base_addr = 0;
+			writeb(0, base);
 			index = 0;
 		}
 
@@ -170,21 +169,24 @@ static void ecard_task_readbytes(struct 
 		 * required offset.  The read bytes are discarded.
 		 */
 		while (index < off) {
-			unsigned char byte;
-			byte = base_addr[page];
+			readb(base + page);
 			index += 1;
 		}
 
 		while (len--) {
-			*buf++ = base_addr[page];
+			*buf++ = readb(base + page);
 			index += 1;
 		}
 	} else {
+		unsigned long base = (ec->type == ECARD_EASI
+			 ? &ec->resource[ECARD_RES_EASI]
+			 : &ec->resource[ECARD_RES_IOCSYNC])->start;
+		void __iomem *pbase = (void __iomem *)base;
 
-		if (!req->use_loader || !req->ec->loader) {
+		if (!req->use_loader || !ec->loader) {
 			off *= 4;
 			while (len--) {
-				*buf++ = base_addr[off];
+				*buf++ = readb(pbase + off);
 				off += 4;
 			}
 		} else {
@@ -194,8 +196,8 @@ static void ecard_task_readbytes(struct 
 				 * expansion card loader programs.
 				 */
 				*(unsigned long *)0x108 = 0;
-				*buf++ = ecard_loader_read(off++, base_addr,
-							   req->ec->loader);
+				*buf++ = ecard_loader_read(off++, base,
+							   ec->loader);
 			}
 		}
 	}
@@ -226,7 +228,7 @@ static void ecard_init_pgtables(struct m
 	 */
 	pgd_t *src_pgd, *dst_pgd;
 
-	src_pgd = pgd_offset(mm, IO_BASE);
+	src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
 	dst_pgd = pgd_offset(mm, IO_START);
 
 	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
@@ -406,7 +408,7 @@ static void ecard_def_irq_disable(ecard_
 
 static int ecard_def_irq_pending(ecard_t *ec)
 {
-	return !ec->irqmask || ec->irqaddr[0] & ec->irqmask;
+	return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
 }
 
 static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
@@ -421,7 +423,7 @@ static void ecard_def_fiq_disable(ecard_
 
 static int ecard_def_fiq_pending(ecard_t *ec)
 {
-	return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask;
+	return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
 }
 
 static expansioncard_ops_t ecard_default_ops = {
@@ -522,7 +524,7 @@ static void ecard_dump_irq_state(void)
 			       ec->ops->irqpending(ec) ? "" : "not ");
 		else
 			printk("irqaddr %p, mask = %02X, status = %02X\n",
-			       ec->irqaddr, ec->irqmask, *ec->irqaddr);
+			       ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
 	}
 }
 
@@ -675,7 +677,7 @@ static int __init ecard_probeirqhw(void)
 #define IO_EC_MEMC8_BASE 0
 #endif
 
-unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
 {
 	unsigned long address = 0;
 	int slot = ec->slot_no;
@@ -779,55 +781,89 @@ static void ecard_proc_init(void)
 		get_ecard_dev_info);
 }
 
-#define ec_set_resource(ec,nr,st,sz,flg)			\
+#define ec_set_resource(ec,nr,st,sz)				\
 	do {							\
 		(ec)->resource[nr].name = ec->dev.bus_id;	\
 		(ec)->resource[nr].start = st;			\
 		(ec)->resource[nr].end = (st) + (sz) - 1;	\
-		(ec)->resource[nr].flags = flg;			\
+		(ec)->resource[nr].flags = IORESOURCE_MEM;	\
 	} while (0)
 
-static void __init ecard_init_resources(struct expansion_card *ec)
+static void __init ecard_free_card(struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+		if (ec->resource[i].flags)
+			release_resource(&ec->resource[i]);
+
+	kfree(ec);
+}
+
+static struct expansion_card *__init ecard_alloc_card(int type, int slot)
 {
-	unsigned long base = PODSLOT_IOC4_BASE;
-	unsigned int slot = ec->slot_no;
+	struct expansion_card *ec;
+	unsigned long base;
 	int i;
 
+	ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
+	if (!ec) {
+		ec = ERR_PTR(-ENOMEM);
+		goto nomem;
+	}
+
+	memset(ec, 0, sizeof(ecard_t));
+
+	ec->slot_no = slot;
+	ec->type = type;
+	ec->irq = NO_IRQ;
+	ec->fiq = NO_IRQ;
+	ec->dma = NO_DMA;
+	ec->ops = &ecard_default_ops;
+
+	snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
+	ec->dev.parent = NULL;
+	ec->dev.bus = &ecard_bus_type;
+	ec->dev.dma_mask = &ec->dma_mask;
+	ec->dma_mask = (u64)0xffffffff;
+
 	if (slot < 4) {
 		ec_set_resource(ec, ECARD_RES_MEMC,
 				PODSLOT_MEMC_BASE + (slot << 14),
-				PODSLOT_MEMC_SIZE, IORESOURCE_MEM);
-		base = PODSLOT_IOC0_BASE;
-	}
+				PODSLOT_MEMC_SIZE);
+		base = PODSLOT_IOC0_BASE + (slot << 14);
+	} else
+		base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
 
 #ifdef CONFIG_ARCH_RPC
 	if (slot < 8) {
 		ec_set_resource(ec, ECARD_RES_EASI,
 				PODSLOT_EASI_BASE + (slot << 24),
-				PODSLOT_EASI_SIZE, IORESOURCE_MEM);
+				PODSLOT_EASI_SIZE);
 	}
 
 	if (slot == 8) {
-		ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE,
-				NETSLOT_SIZE, IORESOURCE_MEM);
+		ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
 	} else
 #endif
 
-	for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) {
+	for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
 		ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
-				base + (slot << 14) + (i << 19),
-				PODSLOT_IOC_SIZE, IORESOURCE_MEM);
-	}
+				base + (i << 19), PODSLOT_IOC_SIZE);
 
 	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-		if (ec->resource[i].start &&
+		if (ec->resource[i].flags &&
 		    request_resource(&iomem_resource, &ec->resource[i])) {
 			printk(KERN_ERR "%s: resource(s) not available\n",
 				ec->dev.bus_id);
 			ec->resource[i].end -= ec->resource[i].start;
 			ec->resource[i].start = 0;
+			ec->resource[i].flags = 0;
 		}
 	}
+
+ nomem:
+	return ec;
 }
 
 static ssize_t ecard_show_irq(struct device *dev, char *buf)
@@ -836,16 +872,12 @@ static ssize_t ecard_show_irq(struct dev
 	return sprintf(buf, "%u\n", ec->irq);
 }
 
-static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL);
-
 static ssize_t ecard_show_dma(struct device *dev, char *buf)
 {
 	struct expansion_card *ec = ECARD_DEV(dev);
 	return sprintf(buf, "%u\n", ec->dma);
 }
 
-static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL);
-
 static ssize_t ecard_show_resources(struct device *dev, char *buf)
 {
 	struct expansion_card *ec = ECARD_DEV(dev);
@@ -861,23 +893,33 @@ static ssize_t ecard_show_resources(stru
 	return str - buf;
 }
 
-static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL);
-
 static ssize_t ecard_show_vendor(struct device *dev, char *buf)
 {
 	struct expansion_card *ec = ECARD_DEV(dev);
 	return sprintf(buf, "%u\n", ec->cid.manufacturer);
 }
 
-static DEVICE_ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL);
-
 static ssize_t ecard_show_device(struct device *dev, char *buf)
 {
 	struct expansion_card *ec = ECARD_DEV(dev);
 	return sprintf(buf, "%u\n", ec->cid.product);
 }
 
-static DEVICE_ATTR(device, S_IRUGO, ecard_show_device, NULL);
+static ssize_t ecard_show_type(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC");
+}
+
+static struct device_attribute ecard_dev_attrs[] = {
+	__ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
+	__ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
+	__ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
+	__ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
+	__ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
+	__ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
+	__ATTR_NULL,
+};
 
 
 int ecard_request_resources(struct expansion_card *ec)
@@ -927,21 +969,13 @@ ecard_probe(int slot, card_type_t type)
 	ecard_t **ecp;
 	ecard_t *ec;
 	struct ex_ecid cid;
-	int i, rc = -ENOMEM;
+	int i, rc;
 
-	ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
-	if (!ec)
+	ec = ecard_alloc_card(type, slot);
+	if (IS_ERR(ec)) {
+		rc = PTR_ERR(ec);
 		goto nomem;
-
-	memset(ec, 0, sizeof(ecard_t));
-
-	ec->slot_no	= slot;
-	ec->type	= type;
-	ec->irq		= NO_IRQ;
-	ec->fiq		= NO_IRQ;
-	ec->dma		= NO_DMA;
-	ec->card_desc	= NULL;
-	ec->ops		= &ecard_default_ops;
+	}
 
 	rc = -ENODEV;
 	if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
@@ -964,7 +998,7 @@ ecard_probe(int slot, card_type_t type)
 	ec->cid.fiqmask = cid.r_fiqmask;
 	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
 	ec->fiqaddr	=
-	ec->irqaddr	= (unsigned char *)ioaddr(ec->podaddr);
+	ec->irqaddr	= (void __iomem *)ioaddr(ec->podaddr);
 
 	if (ec->cid.is) {
 		ec->irqmask = ec->cid.irqmask;
@@ -983,14 +1017,6 @@ ecard_probe(int slot, card_type_t type)
 			break;
 		}
 
-	snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
-	ec->dev.parent = NULL;
-	ec->dev.bus    = &ecard_bus_type;
-	ec->dev.dma_mask = &ec->dma_mask;
-	ec->dma_mask = (u64)0xffffffff;
-
-	ecard_init_resources(ec);
-
 	/*
 	 * hook the interrupt handlers
 	 */
@@ -1017,17 +1043,12 @@ ecard_probe(int slot, card_type_t type)
 	slot_to_expcard[slot] = ec;
 
 	device_register(&ec->dev);
-	device_create_file(&ec->dev, &dev_attr_dma);
-	device_create_file(&ec->dev, &dev_attr_irq);
-	device_create_file(&ec->dev, &dev_attr_resource);
-	device_create_file(&ec->dev, &dev_attr_vendor);
-	device_create_file(&ec->dev, &dev_attr_device);
 
 	return 0;
 
-nodev:
-	kfree(ec);
-nomem:
+ nodev:
+	ecard_free_card(ec);
+ nomem:
 	return rc;
 }
 
@@ -1128,9 +1149,15 @@ static void ecard_drv_shutdown(struct de
 	if (drv->shutdown)
 		drv->shutdown(ec);
 	ecard_release(ec);
-	req.fn = ecard_task_reset;
-	req.ec = ec;
-	ecard_call(&req);
+
+	/*
+	 * If this card has a loader, call the reset handler.
+	 */
+	if (ec->loader) {
+		req.fn = ecard_task_reset;
+		req.ec = ec;
+		ecard_call(&req);
+	}
 }
 
 int ecard_register_driver(struct ecard_driver *drv)
@@ -1164,8 +1191,9 @@ static int ecard_match(struct device *_d
 }
 
 struct bus_type ecard_bus_type = {
-	.name	= "ecard",
-	.match	= ecard_match,
+	.name		= "ecard",
+	.dev_attrs	= ecard_dev_attrs,
+	.match		= ecard_match,
 };
 
 static int ecard_bus_init(void)
@@ -1176,7 +1204,7 @@ static int ecard_bus_init(void)
 postcore_initcall(ecard_bus_init);
 
 EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_address);
+EXPORT_SYMBOL(__ecard_address);
 EXPORT_SYMBOL(ecard_register_driver);
 EXPORT_SYMBOL(ecard_remove_driver);
 EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -14,12 +14,12 @@
  *  it to save wrong values...  Be aware!
  */
 #include <linux/config.h>
-#include <linux/init.h>
 
-#include <asm/thread_info.h>
 #include <asm/glue.h>
-#include <asm/ptrace.h>
 #include <asm/vfpmacros.h>
+#include <asm/hardware.h>		/* should be moved into entry-macro.S */
+#include <asm/arch/irqs.h>		/* should be moved into entry-macro.S */
+#include <asm/arch/entry-macro.S>
 
 #include "entry-header.S"
 
@@ -118,7 +118,7 @@ __dabt_svc:
 	@
 	@ IRQs off again before pulling preserved data off the stack
 	@
-	disable_irq r0
+	disable_irq
 
 	@
 	@ restore SPSR and restart the instruction
@@ -198,7 +198,7 @@ __und_svc:
 	@
 	@ IRQs off again before pulling preserved data off the stack
 	@
-1:	disable_irq r0
+1:	disable_irq
 
 	@
 	@ restore SPSR and restart the instruction
@@ -232,7 +232,7 @@ __pabt_svc:
 	@
 	@ IRQs off again before pulling preserved data off the stack
 	@
-	disable_irq r0
+	disable_irq
 
 	@
 	@ restore SPSR and restart the instruction
@@ -269,6 +269,12 @@ __pabt_svc:
 	add	r5, sp, #S_PC
 	ldmia	r7, {r2 - r4}			@ Get USR pc, cpsr
 
+#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+	@ make sure our user space atomic helper is aborted
+	cmp	r2, #VIRT_OFFSET
+	bichs	r3, r3, #PSR_Z_BIT
+#endif
+
 	@
 	@ We are now ready to fill in the remaining blanks on the stack:
 	@
@@ -280,13 +286,21 @@ __pabt_svc:
 	@
 	stmia	r5, {r2 - r4}
 	stmdb	r5, {sp, lr}^
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r7, r0, __temp_\sym
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
 	.endm
 
 	.align	5
 __dabt_usr:
 	usr_entry abt
-	alignment_trap r7, r0, __temp_abt
-	zero_fp
 
 	@
 	@ Call the processor-specific abort handler:
@@ -308,7 +322,7 @@ __dabt_usr:
 	@
 	@ IRQs on, then call the main handler
 	@
-	enable_irq r2
+	enable_irq
 	mov	r2, sp
 	adr	lr, ret_from_exception
 	b	do_DataAbort
@@ -316,8 +330,7 @@ __dabt_usr:
 	.align	5
 __irq_usr:
 	usr_entry irq
-	alignment_trap r7, r0, __temp_irq
-	zero_fp
+
 #ifdef CONFIG_PREEMPT
 	get_thread_info r8
 	ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
@@ -348,8 +361,7 @@ __irq_usr:
 	.align	5
 __und_usr:
 	usr_entry und
-	alignment_trap r7, r0, __temp_und
-	zero_fp
+
 	tst	r3, #PSR_T_BIT			@ Thumb mode?
 	bne	fpundefinstr			@ ignore FP
 	sub	r4, r2, #4
@@ -412,7 +424,7 @@ call_fpe:
 	movcss	r7, r5, lsr #(TIF_USING_IWMMXT + 1)
 	bcs	iwmmxt_task_enable
 #endif
-	enable_irq r7
+	enable_irq
 	add	pc, pc, r8, lsr #6
 	mov	r0, r0
 
@@ -465,9 +477,8 @@ fpundefinstr:
 	.align	5
 __pabt_usr:
 	usr_entry abt
-	alignment_trap r7, r0, __temp_abt
-	zero_fp
-	enable_irq r0				@ Enable interrupts
+
+	enable_irq				@ Enable interrupts
 	mov	r0, r2				@ address (pc)
 	mov	r1, sp				@ regs
 	bl	do_PrefetchAbort		@ call abort handler
@@ -494,8 +505,12 @@ ENTRY(__switch_to)
 	mra	r4, r5, acc0
 	stmia   ip, {r4, r5}
 #endif
+#if defined(CONFIG_HAS_TLS_REG)
+	mcr	p15, 0, r3, c13, c0, 3		@ set TLS register
+#elif !defined(CONFIG_TLS_REG_EMUL)
 	mov	r4, #0xffff0fff
-	str	r3, [r4, #-3]			@ Set TLS ptr
+	str	r3, [r4, #-15]			@ TLS val at 0xffff0ff0
+#endif
 	mcr	p15, 0, r6, c3, c0, 0		@ Set domain register
 #ifdef CONFIG_VFP
 	@ Always disable VFP so we can lazily save/restore the old
@@ -514,11 +529,215 @@ ENTRY(__switch_to)
 	ldmib	r2, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
 
 	__INIT
+
+/*
+ * User helpers.
+ *
+ * These are segment of kernel provided user code reachable from user space
+ * at a fixed address in kernel memory.  This is used to provide user space
+ * with some operations which require kernel help because of unimplemented
+ * native feature and/or instructions in many ARM CPUs. The idea is for
+ * this code to be executed directly in user mode for best efficiency but
+ * which is too intimate with the kernel counter part to be left to user
+ * libraries.  In fact this code might even differ from one CPU to another
+ * depending on the available  instruction set and restrictions like on
+ * SMP systems.  In other words, the kernel reserves the right to change
+ * this code as needed without warning. Only the entry points and their
+ * results are guaranteed to be stable.
+ *
+ * Each segment is 32-byte aligned and will be moved to the top of the high
+ * vector page.  New segments (if ever needed) must be added in front of
+ * existing ones.  This mechanism should be used only for things that are
+ * really small and justified, and not be abused freely.
+ *
+ * User space is expected to implement those things inline when optimizing
+ * for a processor that has the necessary native support, but only if such
+ * resulting binaries are already to be incompatible with earlier ARM
+ * processors due to the use of unsupported instructions other than what
+ * is provided here.  In other words don't make binaries unable to run on
+ * earlier processors just for the sake of not using these kernel helpers
+ * if your compiled code is not going to use the new instructions for other
+ * purpose.
+ */
+
+	.align	5
+	.globl	__kuser_helper_start
+__kuser_helper_start:
+
+/*
+ * Reference prototype:
+ *
+ *	int __kernel_cmpxchg(int oldval, int newval, int *ptr)
+ *
+ * Input:
+ *
+ *	r0 = oldval
+ *	r1 = newval
+ *	r2 = ptr
+ *	lr = return address
+ *
+ * Output:
+ *
+ *	r0 = returned value (zero or non-zero)
+ *	C flag = set if r0 == 0, clear if r0 != 0
+ *
+ * Clobbered:
+ *
+ *	r3, ip, flags
+ *
+ * Definition and user space usage example:
+ *
+ *	typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
+ *	#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
+ *
+ * Atomically store newval in *ptr if *ptr is equal to oldval for user space.
+ * Return zero if *ptr was changed or non-zero if no exchange happened.
+ * The C flag is also set if *ptr was changed to allow for assembly
+ * optimization in the calling code.
+ *
+ * For example, a user space atomic_add implementation could look like this:
+ *
+ * #define atomic_add(ptr, val) \
+ *	({ register unsigned int *__ptr asm("r2") = (ptr); \
+ *	   register unsigned int __result asm("r1"); \
+ *	   asm volatile ( \
+ *	       "1: @ atomic_add\n\t" \
+ *	       "ldr	r0, [r2]\n\t" \
+ *	       "mov	r3, #0xffff0fff\n\t" \
+ *	       "add	lr, pc, #4\n\t" \
+ *	       "add	r1, r0, %2\n\t" \
+ *	       "add	pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \
+ *	       "bcc	1b" \
+ *	       : "=&r" (__result) \
+ *	       : "r" (__ptr), "rIL" (val) \
+ *	       : "r0","r3","ip","lr","cc","memory" ); \
+ *	   __result; })
+ */
+
+__kuser_cmpxchg:				@ 0xffff0fc0
+
+#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+
+	/*
+	 * Poor you.  No fast solution possible...
+	 * The kernel itself must perform the operation.
+	 * A special ghost syscall is used for that (see traps.c).
+	 */
+	swi	#0x9ffff0
+	mov	pc, lr
+
+#elif __LINUX_ARM_ARCH__ < 6
+
+	/*
+	 * Theory of operation:
+	 *
+	 * We set the Z flag before loading oldval. If ever an exception
+	 * occurs we can not be sure the loaded value will still be the same
+	 * when the exception returns, therefore the user exception handler
+	 * will clear the Z flag whenever the interrupted user code was
+	 * actually from the kernel address space (see the usr_entry macro).
+	 *
+	 * The post-increment on the str is used to prevent a race with an
+	 * exception happening just after the str instruction which would
+	 * clear the Z flag although the exchange was done.
+	 */
+	teq	ip, ip			@ set Z flag
+	ldr	ip, [r2]		@ load current val
+	add	r3, r2, #1		@ prepare store ptr
+	teqeq	ip, r0			@ compare with oldval if still allowed
+	streq	r1, [r3, #-1]!		@ store newval if still allowed
+	subs	r0, r2, r3		@ if r2 == r3 the str occured
+	mov	pc, lr
+
+#else
+
+	ldrex	r3, [r2]
+	subs	r3, r3, r0
+	strexeq	r3, r1, [r2]
+	rsbs	r0, r3, #0
+	mov	pc, lr
+
+#endif
+
+	.align	5
+
+/*
+ * Reference prototype:
+ *
+ *	int __kernel_get_tls(void)
+ *
+ * Input:
+ *
+ *	lr = return address
+ *
+ * Output:
+ *
+ *	r0 = TLS value
+ *
+ * Clobbered:
+ *
+ *	the Z flag might be lost
+ *
+ * Definition and user space usage example:
+ *
+ *	typedef int (__kernel_get_tls_t)(void);
+ *	#define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0)
+ *
+ * Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
+ *
+ * This could be used as follows:
+ *
+ * #define __kernel_get_tls() \
+ *	({ register unsigned int __val asm("r0"); \
+ *         asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \
+ *	        : "=r" (__val) : : "lr","cc" ); \
+ *	   __val; })
+ */
+
+__kuser_get_tls:				@ 0xffff0fe0
+
+#if !defined(CONFIG_HAS_TLS_REG) && !defined(CONFIG_TLS_REG_EMUL)
+
+	ldr	r0, [pc, #(16 - 8)]		@ TLS stored at 0xffff0ff0
+	mov	pc, lr
+
+#else
+
+	mrc	p15, 0, r0, c13, c0, 3		@ read TLS register
+	mov	pc, lr
+
+#endif
+
+	.rep	5
+	.word	0			@ pad up to __kuser_helper_version
+	.endr
+
+/*
+ * Reference declaration:
+ *
+ *	extern unsigned int __kernel_helper_version;
+ *
+ * Definition and user space usage example:
+ *
+ *	#define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
+ *
+ * User space may read this to determine the curent number of helpers
+ * available.
+ */
+
+__kuser_helper_version:				@ 0xffff0ffc
+	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)
+
+	.globl	__kuser_helper_end
+__kuser_helper_end:
+
+
 /*
  * Vector stubs.
  *
- * This code is copied to 0x200 or 0xffff0200 so we can use branches in the
- * vectors, rather than ldr's.
+ * This code is copied to 0xffff0200 so we can use branches in the
+ * vectors, rather than ldr's.  Note that this code must not
+ * exceed 0x300 bytes.
  *
  * Common stub entry macro:
  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
@@ -539,7 +758,7 @@ vector_\name:
 	@
 	mrs	r13, cpsr
 	bic	r13, r13, #MODE_MASK
-	orr	r13, r13, #MODE_SVC
+	orr	r13, r13, #SVC_MODE
 	msr	spsr_cxsf, r13			@ switch to SVC_32 mode
 
 	and	lr, lr, #15
@@ -547,6 +766,7 @@ vector_\name:
 	movs	pc, lr				@ Changes mode and branches
 	.endm
 
+	.globl	__stubs_start
 __stubs_start:
 /*
  * Interrupt dispatcher
@@ -681,37 +901,24 @@ vector_addrexcptn:
 .LCsabt:
 	.word	__temp_abt
 
+	.globl	__stubs_end
 __stubs_end:
 
-	.equ	__real_stubs_start, .LCvectors + 0x200
+	.equ	stubs_offset, __vectors_start + 0x200 - __stubs_start
 
-.LCvectors:
+	.globl	__vectors_start
+__vectors_start:
 	swi	SYS_ERROR0
-	b	__real_stubs_start + (vector_und - __stubs_start)
-	ldr	pc, __real_stubs_start + (.LCvswi - __stubs_start)
-	b	__real_stubs_start + (vector_pabt - __stubs_start)
-	b	__real_stubs_start + (vector_dabt - __stubs_start)
-	b	__real_stubs_start + (vector_addrexcptn - __stubs_start)
-	b	__real_stubs_start + (vector_irq - __stubs_start)
-	b	__real_stubs_start + (vector_fiq - __stubs_start)
-
-ENTRY(__trap_init)
-	stmfd	sp!, {r4 - r6, lr}
-
-	mov	r0, #0xff000000
-	orr	r0, r0, #0x00ff0000		@ high vectors position
-	adr	r1, .LCvectors			@ set up the vectors
-	ldmia	r1, {r1, r2, r3, r4, r5, r6, ip, lr}
-	stmia	r0, {r1, r2, r3, r4, r5, r6, ip, lr}
-
-	add	r2, r0, #0x200
-	adr	r0, __stubs_start		@ copy stubs to 0x200
-	adr	r1, __stubs_end
-1:	ldr	r3, [r0], #4
-	str	r3, [r2], #4
-	cmp	r0, r1
-	blt	1b
-	LOADREGS(fd, sp!, {r4 - r6, pc})
+	b	vector_und + stubs_offset
+	ldr	pc, .LCvswi + stubs_offset
+	b	vector_pabt + stubs_offset
+	b	vector_dabt + stubs_offset
+	b	vector_addrexcptn + stubs_offset
+	b	vector_irq + stubs_offset
+	b	vector_fiq + stubs_offset
+
+	.globl	__vectors_end
+__vectors_end:
 
 	.data
 
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -9,19 +9,10 @@
  */
 #include <linux/config.h>
 
-#include <asm/thread_info.h>
-#include <asm/ptrace.h>
 #include <asm/unistd.h>
 
 #include "entry-header.S"
 
-/* 
- * We rely on the fact that R0 is at the bottom of the stack (due to
- * slow/fast restore user regs).
- */
-#if S_R0 != 0
-#error "Please fix"
-#endif
 
 	.align	5
 /*
@@ -30,11 +21,19 @@
  * stack.
  */
 ret_fast_syscall:
-	disable_irq r1				@ disable interrupts
+	disable_irq				@ disable interrupts
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	bne	fast_work_pending
-	fast_restore_user_regs
+
+	@ fast_restore_user_regs
+	ldr	r1, [sp, #S_OFF + S_PSR]	@ get calling cpsr
+	ldr	lr, [sp, #S_OFF + S_PC]!	@ get pc
+	msr	spsr_cxsf, r1			@ save in spsr_svc
+	ldmdb	sp, {r1 - lr}^			@ get calling r1 - lr
+	mov	r0, r0
+	add	sp, sp, #S_FRAME_SIZE - S_PC
+	movs	pc, lr				@ return & move spsr_svc into cpsr
 
 /*
  * Ok, we need to do extra processing, enter the slow path.
@@ -49,7 +48,7 @@ work_pending:
 	mov	r0, sp				@ 'regs'
 	mov	r2, why				@ 'syscall'
 	bl	do_notify_resume
-	disable_irq r1				@ disable interrupts
+	disable_irq				@ disable interrupts
 	b	no_work_pending
 
 work_resched:
@@ -59,12 +58,19 @@ work_resched:
  */
 ENTRY(ret_to_user)
 ret_slow_syscall:
-	disable_irq r1				@ disable interrupts
+	disable_irq				@ disable interrupts
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	bne	work_pending
 no_work_pending:
-	slow_restore_user_regs
+	@ slow_restore_user_regs
+	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
+	ldr	lr, [sp, #S_PC]!		@ get pc
+	msr	spsr_cxsf, r1			@ save in spsr_svc
+	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
+	mov	r0, r0
+	add	sp, sp, #S_FRAME_SIZE - S_PC
+	movs	pc, lr				@ return & move spsr_svc into cpsr
 
 /*
  * This is how we return from a fork.
@@ -116,9 +122,26 @@ ENTRY(ret_from_fork)
 
 	.align	5
 ENTRY(vector_swi)
-	save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0 - r12
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^			@ Calling sp, lr
+	mrs	r8, spsr			@ called from non-FIQ mode, so ok.
+	str	lr, [sp, #S_PC]			@ Save calling PC
+	str	r8, [sp, #S_PSR]		@ Save CPSR
+	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
 	zero_fp
-	get_scno
+
+	/*
+	 * Get the system call number.
+	 */
+#ifdef CONFIG_ARM_THUMB
+	tst	r8, #PSR_T_BIT			@ this is SPSR from save_user_regs
+	addne	scno, r7, #__NR_SYSCALL_BASE	@ put OS number in
+	ldreq	scno, [lr, #-4]
+#else
+	ldr	scno, [lr, #-4]			@ get SWI instruction
+#endif
 	arm710_bug_check scno, ip
 
 #ifdef CONFIG_ALIGNMENT_TRAP
@@ -126,14 +149,14 @@ ENTRY(vector_swi)
 	ldr	ip, [ip]
 	mcr	p15, 0, ip, c1, c0		@ update control register
 #endif
-	enable_irq ip
+	enable_irq
 
 	str	r4, [sp, #-S_OFF]!		@ push fifth arg
 
 	get_thread_info tsk
 	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
 	bic	scno, scno, #0xff000000		@ mask off SWI op-code
-	eor	scno, scno, #OS_NUMBER << 20	@ check OS number
+	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
 	adr	tbl, sys_call_table		@ load syscall table pointer
 	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
@@ -144,8 +167,8 @@ ENTRY(vector_swi)
 
 	add	r1, sp, #S_OFF
 2:	mov	why, #0				@ no longer a real syscall
-	cmp	scno, #ARMSWI_OFFSET
-	eor	r0, scno, #OS_NUMBER << 20	@ put OS number back
+	cmp	scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
+	eor	r0, scno, #__NR_SYSCALL_BASE	@ put OS number back
 	bcs	arm_syscall	
 	b	sys_ni_syscall			@ not private func
 
@@ -190,7 +213,7 @@ ENTRY(sys_call_table)
 @ r5 = syscall table
 		.type	sys_syscall, #function
 sys_syscall:
-		eor	scno, r0, #OS_NUMBER << 20
+		eor	scno, r0, #__NR_SYSCALL_BASE
 		cmp	scno, #__NR_syscall - __NR_SYSCALL_BASE
 		cmpne	scno, #NR_syscalls	@ check range
 		stmloia	sp, {r5, r6}		@ shuffle args
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -1,24 +1,11 @@
-#include <linux/config.h> /* for CONFIG_ARCH_xxxx */
+#include <linux/config.h>
+#include <linux/init.h>
 #include <linux/linkage.h>
 
 #include <asm/assembler.h>
 #include <asm/constants.h>
 #include <asm/errno.h>
-#include <asm/hardware.h>
-#include <asm/arch/irqs.h>
-#include <asm/arch/entry-macro.S>
-
-#ifndef MODE_SVC
-#define MODE_SVC 0x13
-#endif
-
-	.macro	zero_fp
-#ifdef CONFIG_FRAME_POINTER
-	mov	fp, #0
-#endif
-	.endm
-
-	.text
+#include <asm/thread_info.h>
 
 @ Bad Abort numbers
 @ -----------------
@@ -29,113 +16,44 @@
 #define BAD_IRQ		3
 #define BAD_UNDEFINSTR	4
 
-#define PT_TRACESYS	0x00000002
-
-@ OS version number used in SWIs
-@  RISC OS is 0
-@  RISC iX is 8
 @
-#define OS_NUMBER	9
-#define ARMSWI_OFFSET	0x000f0000
-
-@
-@ Stack format (ensured by USER_* and SVC_*)
+@ Most of the stack format comes from struct pt_regs, but with
+@ the addition of 8 bytes for storing syscall args 5 and 6.
 @
-#define S_FRAME_SIZE	72
-#define S_OLD_R0	68
-#define S_PSR		64
-
-#define S_PC		60
-#define S_LR		56
-#define S_SP		52
-#define S_IP		48
-#define S_FP		44
-#define S_R10		40
-#define S_R9		36
-#define S_R8		32
-#define S_R7		28
-#define S_R6		24
-#define S_R5		20
-#define S_R4		16
-#define S_R3		12
-#define S_R2		8
-#define S_R1		4
-#define S_R0		0
 #define S_OFF		8
 
-	.macro	set_cpsr_c, reg, mode
-	msr	cpsr_c, \mode
+/* 
+ * The SWI code relies on the fact that R0 is at the bottom of the stack
+ * (due to slow/fast restore user regs).
+ */
+#if S_R0 != 0
+#error "Please fix"
+#endif
+
+	.macro	zero_fp
+#ifdef CONFIG_FRAME_POINTER
+	mov	fp, #0
+#endif
 	.endm
 
 #if __LINUX_ARM_ARCH__ >= 6
-	.macro	disable_irq, temp
+	.macro	disable_irq
 	cpsid	i
 	.endm
 
-	.macro	enable_irq, temp
+	.macro	enable_irq
 	cpsie	i
 	.endm
 #else
-	.macro	disable_irq, temp
-	set_cpsr_c \temp, #PSR_I_BIT | MODE_SVC
+	.macro	disable_irq
+	msr	cpsr_c, #PSR_I_BIT | SVC_MODE
 	.endm
 
-	.macro	enable_irq, temp
-	set_cpsr_c \temp, #MODE_SVC
+	.macro	enable_irq
+	msr	cpsr_c, #SVC_MODE
 	.endm
 #endif
 
-	.macro	save_user_regs
-	sub	sp, sp, #S_FRAME_SIZE
-	stmia	sp, {r0 - r12}			@ Calling r0 - r12
-	add	r8, sp, #S_PC
-	stmdb	r8, {sp, lr}^			@ Calling sp, lr
-	mrs	r8, spsr			@ called from non-FIQ mode, so ok.
-	str	lr, [sp, #S_PC]			@ Save calling PC
-	str	r8, [sp, #S_PSR]		@ Save CPSR
-	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
-	.endm
-
-	.macro	restore_user_regs
-	ldr	r1, [sp, #S_PSR]		@ Get calling cpsr
-	disable_irq ip				@ disable IRQs
-	ldr	lr, [sp, #S_PC]!		@ Get PC
-	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r0 - lr}^			@ Get calling r0 - lr
-	mov	r0, r0
-	add	sp, sp, #S_FRAME_SIZE - S_PC
-	movs	pc, lr				@ return & move spsr_svc into cpsr
-	.endm
-
-/*
- * Must be called with IRQs already disabled.
- */
-	.macro	fast_restore_user_regs
-	ldr	r1, [sp, #S_OFF + S_PSR]	@ get calling cpsr
-	ldr	lr, [sp, #S_OFF + S_PC]!	@ get pc
-	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r1 - lr}^			@ get calling r1 - lr
-	mov	r0, r0
-	add	sp, sp, #S_FRAME_SIZE - S_PC
-	movs	pc, lr				@ return & move spsr_svc into cpsr
-	.endm
-
-/*
- * Must be called with IRQs already disabled.
- */
-	.macro	slow_restore_user_regs
-	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
-	ldr	lr, [sp, #S_PC]!		@ get pc
-	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
-	mov	r0, r0
-	add	sp, sp, #S_FRAME_SIZE - S_PC
-	movs	pc, lr				@ return & move spsr_svc into cpsr
-	.endm
-
-	.macro	mask_pc, rd, rm
-	.endm
-
 	.macro	get_thread_info, rd
 	mov	\rd, sp, lsr #13
 	mov	\rd, \rd, lsl #13
@@ -165,18 +83,3 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
-
-/*
- * Get the system call number.
- */
-	.macro	get_scno
-#ifdef CONFIG_ARM_THUMB
-	tst	r8, #PSR_T_BIT		@ this is SPSR from save_user_regs
-	addne	scno, r7, #OS_NUMBER << 20 @ put OS number in
-	ldreq	scno, [lr, #-4]
-
-#else
-	mask_pc	lr, lr
-	ldr	scno, [lr, #-4]		@ get SWI instruction
-#endif
-	.endm
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -46,12 +46,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
-#warning This file requires GCC 3.3.x or older to build.  Alternatively,
-#warning please talk to GCC people to resolve the issues with the
-#warning assembly clobber list.
-#endif
-
 static unsigned long no_fiq_insn;
 
 /* Default reacquire function
@@ -91,44 +85,43 @@ void set_fiq_handler(void *start, unsign
 
 /*
  * Taking an interrupt in FIQ mode is death, so both these functions
- * disable irqs for the duration. 
+ * disable irqs for the duration.  Note - these functions are almost
+ * entirely coded in assembly.
  */
-void set_fiq_regs(struct pt_regs *regs)
+void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs)
 {
 	register unsigned long tmp;
-	__asm__ volatile (
-	"mrs	%0, cpsr\n\
+	asm volatile (
+	"mov	ip, sp\n\
+	stmfd	sp!, {fp, ip, lr, pc}\n\
+	sub	fp, ip, #4\n\
+	mrs	%0, cpsr\n\
 	msr	cpsr_c, %2	@ select FIQ mode\n\
 	mov	r0, r0\n\
 	ldmia	%1, {r8 - r14}\n\
 	msr	cpsr_c, %0	@ return to SVC mode\n\
-	mov	r0, r0"
+	mov	r0, r0\n\
+	ldmea	fp, {fp, sp, pc}"
 	: "=&r" (tmp)
-	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)
-	/* These registers aren't modified by the above code in a way
-	   visible to the compiler, but we mark them as clobbers anyway
-	   so that GCC won't put any of the input or output operands in
-	   them.  */
-	: "r8", "r9", "r10", "r11", "r12", "r13", "r14");
+	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
 }
 
-void get_fiq_regs(struct pt_regs *regs)
+void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs)
 {
 	register unsigned long tmp;
-	__asm__ volatile (
-	"mrs	%0, cpsr\n\
+	asm volatile (
+	"mov	ip, sp\n\
+	stmfd	sp!, {fp, ip, lr, pc}\n\
+	sub	fp, ip, #4\n\
+	mrs	%0, cpsr\n\
 	msr	cpsr_c, %2	@ select FIQ mode\n\
 	mov	r0, r0\n\
 	stmia	%1, {r8 - r14}\n\
 	msr	cpsr_c, %0	@ return to SVC mode\n\
-	mov	r0, r0"
+	mov	r0, r0\n\
+	ldmea	fp, {fp, sp, pc}"
 	: "=&r" (tmp)
-	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)
-	/* These registers aren't modified by the above code in a way
-	   visible to the compiler, but we mark them as clobbers anyway
-	   so that GCC won't put any of the input or output operands in
-	   them.  */
-	: "r8", "r9", "r10", "r11", "r12", "r13", "r14");
+	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
 }
 
 int claim_fiq(struct fiq_handler *f)
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -19,14 +19,17 @@
 #include <asm/procinfo.h>
 #include <asm/ptrace.h>
 #include <asm/constants.h>
+#include <asm/thread_info.h>
 #include <asm/system.h>
 
 #define PROCINFO_MMUFLAGS	8
 #define PROCINFO_INITFUNC	12
 
+#define MACHINFO_TYPE		0
 #define MACHINFO_PHYSRAM	4
 #define MACHINFO_PHYSIO		8
 #define MACHINFO_PGOFFIO	12
+#define MACHINFO_NAME		16
 
 #ifndef CONFIG_XIP_KERNEL
 /*
@@ -101,12 +104,10 @@ ENTRY(stext)
 						@ and irqs disabled
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
-	moveq	r0, #'p'			@ yes, error 'p'
-	beq	__error
+	beq	__error_p				@ yes, error 'p'
 	bl	__lookup_machine_type		@ r5=machinfo
 	movs	r8, r5				@ invalid machine (r5=0)?
-	moveq	r0, #'a'			@ yes, error 'a'
-	beq	__error
+	beq	__error_a			@ yes, error 'a'
 	bl	__create_page_tables
 
 	/*
@@ -131,7 +132,7 @@ __switch_data:
 	.long	processor_id			@ r4
 	.long	__machine_arch_type		@ r5
 	.long	cr_alignment			@ r6
-	.long	init_thread_union+8192		@ sp
+	.long	init_thread_union + THREAD_START_SP @ sp
 
 /*
  * The following fragment of code is executed with the MMU on, and uses
@@ -359,22 +360,59 @@ __create_page_tables:
  * ought to tell the user, but since we don't have any guarantee that
  * we're even running on the right architecture, we do virtually nothing.
  *
- * r0 = ascii error character:
- *	a = invalid architecture
- *	p = invalid processor
- *	i = invalid calling convention
- *
- * Generally, only serious errors cause this.
+ * If CONFIG_DEBUG_LL is set we try to print out something about the error
+ * and hope for the best (useful if bootloader fails to pass a proper
+ * machine ID for example).
  */
-	.type	__error, %function
-__error:
+
+	.type	__error_p, %function
+__error_p:
+#ifdef CONFIG_DEBUG_LL
+	adr	r0, str_p1
+	bl	printascii
+	b	__error
+str_p1:	.asciz	"\nError: unrecognized/unsupported processor variant.\n"
+	.align
+#endif
+
+	.type	__error_a, %function
+__error_a:
 #ifdef CONFIG_DEBUG_LL
-	mov	r8, r0				@ preserve r0
-	adr	r0, err_str
+	mov	r4, r1				@ preserve machine ID
+	adr	r0, str_a1
+	bl	printascii
+	mov	r0, r4
+	bl	printhex8
+	adr	r0, str_a2
+	bl	printascii
+	adr	r3, 3f
+	ldmia	r3, {r4, r5, r6}		@ get machine desc list
+	sub	r4, r3, r4			@ get offset between virt&phys
+	add	r5, r5, r4			@ convert virt addresses to
+	add	r6, r6, r4			@ physical address space
+1:	ldr	r0, [r5, #MACHINFO_TYPE]	@ get machine type
+	bl	printhex8
+	mov	r0, #'\t'
+	bl	printch
+	ldr     r0, [r5, #MACHINFO_NAME]	@ get machine name
+	add	r0, r0, r4
 	bl	printascii
-	mov	r0, r8
+	mov	r0, #'\n'
 	bl	printch
+	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
+	cmp	r5, r6
+	blo	1b
+	adr	r0, str_a3
+	bl	printascii
+	b	__error
+str_a1:	.asciz	"\nError: unrecognized/unsupported machine ID (r1 = 0x"
+str_a2:	.asciz	").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
+str_a3:	.asciz	"\nPlease check your kernel config and/or bootloader.\n"
+	.align
 #endif
+
+	.type	__error, %function
+__error:
 #ifdef CONFIG_ARCH_RPC
 /*
  * Turn the screen red on a error - RiscPC only.
@@ -391,12 +429,6 @@ __error:
 1:	mov	r0, r0
 	b	1b
 
-#ifdef CONFIG_DEBUG_LL
-	.type	err_str, %object
-err_str:
-	.asciz	"\nError: "
-	.align
-#endif
 
 /*
  * Read processor ID register (CP#15, CR0), and look up in the linker-built
@@ -424,7 +456,7 @@ __lookup_processor_type:
 	beq	2f
 	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
 	cmp	r5, r6
-	blt	1b
+	blo	1b
 	mov	r5, #0				@ unknown processor
 2:	mov	pc, lr
 
@@ -465,12 +497,12 @@ __lookup_machine_type:
 	sub	r3, r3, r4			@ get offset between virt&phys
 	add	r5, r5, r3			@ convert virt addresses to
 	add	r6, r6, r3			@ physical address space
-1:	ldr	r3, [r5]			@ get machine type
+1:	ldr	r3, [r5, #MACHINFO_TYPE]	@ get machine type
 	teq	r3, r1				@ matches loader number?
 	beq	2f				@ found
 	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
 	cmp	r5, r6
-	blt	1b
+	blo	1b
 	mov	r5, #0				@ unknown machine
 2:	mov	pc, lr
 
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -56,6 +56,13 @@ struct irqdesc irq_desc[NR_IRQS];
 void (*init_arch_irq)(void) __initdata = NULL;
 
 /*
+ * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
+ */
+#ifndef irq_finish
+#define irq_finish(irq) do { } while (0)
+#endif
+
+/*
  * Dummy mask/unmask handler
  */
 void dummy_mask_unmask_irq(unsigned int irq)
@@ -532,6 +539,8 @@ asmlinkage void asm_do_IRQ(unsigned int 
 	if (!list_empty(&irq_pending))
 		do_pending_irqs(regs);
 
+	irq_finish(irq);
+
 	spin_unlock(&irq_controller_lock);
 	irq_exit();
 }
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -35,44 +35,16 @@ extern void _etext;
 void *module_alloc(unsigned long size)
 {
 	struct vm_struct *area;
-	struct page **pages;
-	unsigned int array_size, i;
 
 	size = PAGE_ALIGN(size);
 	if (!size)
-		goto out_null;
+		return NULL;
 
 	area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END);
 	if (!area)
-		goto out_null;
+		return NULL;
 
-	area->nr_pages = size >> PAGE_SHIFT;
-	array_size = area->nr_pages * sizeof(struct page *);
-	area->pages = pages = kmalloc(array_size, GFP_KERNEL);
-	if (!area->pages) {
-		remove_vm_area(area->addr);
-		kfree(area);
-		goto out_null;
-	}
-
-	memset(pages, 0, array_size);
-
-	for (i = 0; i < area->nr_pages; i++) {
-		pages[i] = alloc_page(GFP_KERNEL);
-		if (unlikely(!pages[i])) {
-			area->nr_pages = i;
-			goto out_no_pages;
-		}
-	}
-
-	if (map_vm_area(area, PAGE_KERNEL, &pages))
-		goto out_no_pages;
-	return area->addr;
-
- out_no_pages:
-	vfree(area->addr);
- out_null:
-	return NULL;
+	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
 }
 
 void module_free(struct module *module, void *region)
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -168,12 +168,11 @@ void machine_restart(char * __unused)
 
 EXPORT_SYMBOL(machine_restart);
 
-void show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs *regs)
 {
-	unsigned long flags;
-
-	flags = condition_codes(regs);
+	unsigned long flags = condition_codes(regs);
 
+	printk("CPU: %d\n", smp_processor_id());
 	print_symbol("PC is at %s\n", instruction_pointer(regs));
 	print_symbol("LR is at %s\n", regs->ARM_lr);
 	printk("pc : [<%08lx>]    lr : [<%08lx>]    %s\n"
@@ -213,6 +212,14 @@ void show_regs(struct pt_regs * regs)
 	}
 }
 
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
+	__show_regs(regs);
+	__backtrace();
+}
+
 void show_fpregs(struct user_fp *regs)
 {
 	int i;
@@ -249,8 +256,6 @@ static unsigned long *thread_info_head;
 static unsigned int nr_thread_info;
 
 #define EXTRA_TASK_STRUCT	4
-#define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define ll_free_task_struct(p) free_pages((unsigned long)(p),1)
 
 struct thread_info *alloc_thread_info(struct task_struct *task)
 {
@@ -267,17 +272,16 @@ struct thread_info *alloc_thread_info(st
 	}
 
 	if (!thread)
-		thread = ll_alloc_task_struct();
+		thread = (struct thread_info *)
+			   __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
 
-#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_DEBUG_STACK_USAGE
 	/*
 	 * The stack must be cleared if you want SYSRQ-T to
 	 * give sensible stack usage information
 	 */
-	if (thread) {
-		char *p = (char *)thread;
-		memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
-	}
+	if (thread)
+		memzero(thread, THREAD_SIZE);
 #endif
 	return thread;
 }
@@ -290,7 +294,7 @@ void free_thread_info(struct thread_info
 		thread_info_head = p;
 		nr_thread_info += 1;
 	} else
-		ll_free_task_struct(thread);
+		free_pages((unsigned long)thread, THREAD_SIZE_ORDER);
 }
 
 /*
@@ -343,7 +347,7 @@ copy_thread(int nr, unsigned long clone_
 	struct thread_info *thread = p->thread_info;
 	struct pt_regs *childregs;
 
-	childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1;
+	childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_START_SP)) - 1;
 	*childregs = *regs;
 	childregs->ARM_r0 = 0;
 	childregs->ARM_sp = stack_start;
@@ -440,15 +444,17 @@ EXPORT_SYMBOL(kernel_thread);
 unsigned long get_wchan(struct task_struct *p)
 {
 	unsigned long fp, lr;
-	unsigned long stack_page;
+	unsigned long stack_start, stack_end;
 	int count = 0;
 	if (!p || p == current || p->state == TASK_RUNNING)
 		return 0;
 
-	stack_page = 4096 + (unsigned long)p->thread_info;
+	stack_start = (unsigned long)(p->thread_info + 1);
+	stack_end = ((unsigned long)p->thread_info) + THREAD_SIZE;
+
 	fp = thread_saved_fp(p);
 	do {
-		if (fp < stack_page || fp > 4092+stack_page)
+		if (fp < stack_start || fp > stack_end)
 			return 0;
 		lr = pc_pointer (((unsigned long *)fp)[-1]);
 		if (!in_sched_functions(lr))
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -9,6 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -18,6 +19,7 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/init.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -608,6 +610,44 @@ static int ptrace_setfpregs(struct task_
 			      sizeof(struct user_fp)) ? -EFAULT : 0;
 }
 
+#ifdef CONFIG_IWMMXT
+
+/*
+ * Get the child iWMMXt state.
+ */
+static int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp)
+{
+	struct thread_info *thread = tsk->thread_info;
+	void *ptr = &thread->fpstate;
+
+	if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
+		return -ENODATA;
+	iwmmxt_task_disable(thread);  /* force it to ram */
+	/* The iWMMXt state is stored doubleword-aligned.  */
+	if (((long) ptr) & 4)
+		ptr += 4;
+	return copy_to_user(ufp, ptr, 0x98) ? -EFAULT : 0;
+}
+
+/*
+ * Set the child iWMMXt state.
+ */
+static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
+{
+	struct thread_info *thread = tsk->thread_info;
+	void *ptr = &thread->fpstate;
+
+	if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
+		return -EACCES;
+	iwmmxt_task_release(thread);  /* force a reload */
+	/* The iWMMXt state is stored doubleword-aligned.  */
+	if (((long) ptr) & 4)
+		ptr += 4;
+	return copy_from_user(ptr, ufp, 0x98) ? -EFAULT : 0;
+}
+
+#endif
+
 static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 {
 	unsigned long tmp;
@@ -654,7 +694,7 @@ static int do_ptrace(int request, struct
 		case PTRACE_SYSCALL:
 		case PTRACE_CONT:
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			if (request == PTRACE_SYSCALL)
 				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -689,7 +729,7 @@ static int do_ptrace(int request, struct
 		 */
 		case PTRACE_SINGLESTEP:
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			child->ptrace |= PT_SINGLESTEP;
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -719,6 +759,16 @@ static int do_ptrace(int request, struct
 			ret = ptrace_setfpregs(child, (void __user *)data);
 			break;
 
+#ifdef CONFIG_IWMMXT
+		case PTRACE_GETWMMXREGS:
+			ret = ptrace_getwmmxregs(child, (void __user *)data);
+			break;
+
+		case PTRACE_SETWMMXREGS:
+			ret = ptrace_setwmmxregs(child, (void __user *)data);
+			break;
+#endif
+
 		case PTRACE_GET_THREAD_AREA:
 			ret = put_user(child->thread_info->tp_value,
 				       (unsigned long __user *) data);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -92,8 +92,6 @@ struct cpu_user_fns cpu_user;
 struct cpu_cache_fns cpu_cache;
 #endif
 
-unsigned char aux_device_present;
-
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -102,7 +102,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -114,7 +114,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -317,7 +317,7 @@ asmlinkage int sys_sigreturn(struct pt_r
 
 	frame = (struct sigframe __user *)regs->ARM_sp;
 
-	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_NSIG_WORDS > 1
@@ -365,7 +365,7 @@ asmlinkage int sys_rt_sigreturn(struct p
 
 	frame = (struct rt_sigframe __user *)regs->ARM_sp;
 
-	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -51,13 +51,6 @@ asmlinkage int sys_pipe(unsigned long __
 	return error;
 }
 
-/*
- * This is the lowest virtual address we can permit any user space
- * mapping to be mapped at.  This is particularly important for
- * non-high vector CPUs.
- */
-#define MIN_MAP_ADDR	(PAGE_SIZE)
-
 /* common code for old and new mmaps */
 inline long do_mmap2(
 	unsigned long addr, unsigned long len,
@@ -69,7 +62,7 @@ inline long do_mmap2(
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	if (flags & MAP_FIXED && addr < MIN_MAP_ADDR)
+	if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS)
 		goto out;
 
 	error = -EBADF;
@@ -122,7 +115,7 @@ sys_arm_mremap(unsigned long addr, unsig
 {
 	unsigned long ret = -EINVAL;
 
-	if (flags & MREMAP_FIXED && new_addr < MIN_MAP_ADDR)
+	if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS)
 		goto out;
 
 	down_write(&current->mm->mmap_sem);
@@ -169,7 +162,11 @@ asmlinkage int sys_ipc(uint call, int fi
 
 	switch (call) {
 	case SEMOP:
-		return sys_semop(first, (struct sembuf __user *)ptr, second);
+		return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
+	case SEMTIMEDOP:
+		return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
+					(const struct timespec __user *)fifth);
+
 	case SEMGET:
 		return sys_semget (first, second, third);
 	case SEMCTL: {
@@ -305,7 +302,7 @@ long execve(const char *filename, char *
 		"b	ret_to_user"
 		:
 		: "r" (current_thread_info()),
-		  "Ir" (THREAD_SIZE - 8 - sizeof(regs)),
+		  "Ir" (THREAD_START_SP - sizeof(regs)),
 		  "r" (&regs),
 		  "Ir" (sizeof(regs))
 		: "r0", "r1", "r2", "r3", "ip", "memory");
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -178,7 +178,7 @@ static ssize_t leds_store(struct sys_dev
 
 static SYSDEV_ATTR(event, 0200, NULL, leds_store);
 
-static int leds_suspend(struct sys_device *dev, u32 state)
+static int leds_suspend(struct sys_device *dev, pm_message_t state)
 {
 	leds_event(led_stop);
 	return 0;
@@ -351,7 +351,7 @@ void timer_tick(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_PM
-static int timer_suspend(struct sys_device *dev, u32 state)
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
 	struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
 
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -31,9 +31,6 @@
 
 #include "ptrace.h"
 
-extern void c_backtrace (unsigned long fp, int pmode);
-extern void show_pte(struct mm_struct *mm, unsigned long addr);
-
 const char *processor_modes[]=
 { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
@@ -216,13 +213,13 @@ NORET_TYPE void die(const char *str, str
 
 	printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);
 	print_modules();
-	printk("CPU: %d\n", smp_processor_id());
-	show_regs(regs);
+	__show_regs(regs);
 	printk("Process %s (pid: %d, stack limit = 0x%p)\n",
 		tsk->comm, tsk->pid, tsk->thread_info + 1);
 
 	if (!user_mode(regs) || in_interrupt()) {
-		dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info);
+		dump_mem("Stack: ", regs->ARM_sp,
+			 THREAD_SIZE + (unsigned long)tsk->thread_info);
 		dump_backtrace(regs, tsk);
 		dump_instr(regs);
 	}
@@ -240,6 +237,19 @@ void die_if_kernel(const char *str, stru
     	die(str, regs, err);
 }
 
+static void notify_die(const char *str, struct pt_regs *regs, siginfo_t *info,
+		       unsigned long err, unsigned long trap)
+{
+	if (user_mode(regs)) {
+		current->thread.error_code = err;
+		current->thread.trap_no = trap;
+
+		force_sig_info(info->si_signo, info, current);
+	} else {
+		die(str, regs, err);
+	}
+}
+
 static LIST_HEAD(undef_hook);
 static DEFINE_SPINLOCK(undef_lock);
 
@@ -299,17 +309,12 @@ asmlinkage void do_undefinstr(struct pt_
 	}
 #endif
 
-	current->thread.error_code = 0;
-	current->thread.trap_no = 6;
-
 	info.si_signo = SIGILL;
 	info.si_errno = 0;
 	info.si_code  = ILL_ILLOPC;
 	info.si_addr  = pc;
 
-	force_sig_info(SIGILL, &info, current);
-
-	die_if_kernel("Oops - undefined instruction", regs, 0);
+	notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
@@ -362,8 +367,8 @@ static int bad_syscall(int n, struct pt_
 	info.si_addr  = (void __user *)instruction_pointer(regs) -
 			 (thumb_mode(regs) ? 2 : 4);
 
-	force_sig_info(SIGILL, &info, current);
-	die_if_kernel("Oops - bad syscall", regs, n);
+	notify_die("Oops - bad syscall", regs, &info, n, 0);
+
 	return regs->ARM_r0;
 }
 
@@ -406,9 +411,7 @@ asmlinkage int arm_syscall(int no, struc
 		info.si_code  = SEGV_MAPERR;
 		info.si_addr  = NULL;
 
-		force_sig_info(SIGSEGV, &info, current);
-
-		die_if_kernel("branch through zero", regs, 0);
+		notify_die("branch through zero", regs, &info, 0, 0);
 		return 0;
 
 	case NR(breakpoint): /* SWI BREAK_POINT */
@@ -448,15 +451,68 @@ asmlinkage int arm_syscall(int no, struc
 
 	case NR(set_tls):
 		thread->tp_value = regs->ARM_r0;
+#if defined(CONFIG_HAS_TLS_REG)
+		asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
+#elif !defined(CONFIG_TLS_REG_EMUL)
 		/*
-		 * Our user accessible TLS ptr is located at 0xffff0ffc.
-		 * On SMP read access to this address must raise a fault
-		 * and be emulated from the data abort handler.
-		 * m
+		 * User space must never try to access this directly.
+		 * Expect your app to break eventually if you do so.
+		 * The user helper at 0xffff0fe0 must be used instead.
+		 * (see entry-armv.S for details)
 		 */
-		*((unsigned long *)0xffff0ffc) = thread->tp_value;
+		*((unsigned int *)0xffff0ff0) = regs->ARM_r0;
+#endif
 		return 0;
 
+#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG
+	/*
+	 * Atomically store r1 in *r2 if *r2 is equal to r0 for user space.
+	 * Return zero in r0 if *MEM was changed or non-zero if no exchange
+	 * happened.  Also set the user C flag accordingly.
+	 * If access permissions have to be fixed up then non-zero is
+	 * returned and the operation has to be re-attempted.
+	 *
+	 * *NOTE*: This is a ghost syscall private to the kernel.  Only the
+	 * __kuser_cmpxchg code in entry-armv.S should be aware of its
+	 * existence.  Don't ever use this from user code.
+	 */
+	case 0xfff0:
+	{
+		extern void do_DataAbort(unsigned long addr, unsigned int fsr,
+					 struct pt_regs *regs);
+		unsigned long val;
+		unsigned long addr = regs->ARM_r2;
+		struct mm_struct *mm = current->mm;
+		pgd_t *pgd; pmd_t *pmd; pte_t *pte;
+
+		regs->ARM_cpsr &= ~PSR_C_BIT;
+		spin_lock(&mm->page_table_lock);
+		pgd = pgd_offset(mm, addr);
+		if (!pgd_present(*pgd))
+			goto bad_access;
+		pmd = pmd_offset(pgd, addr);
+		if (!pmd_present(*pmd))
+			goto bad_access;
+		pte = pte_offset_map(pmd, addr);
+		if (!pte_present(*pte) || !pte_write(*pte))
+			goto bad_access;
+		val = *(unsigned long *)addr;
+		val -= regs->ARM_r0;
+		if (val == 0) {
+			*(unsigned long *)addr = regs->ARM_r1;
+			regs->ARM_cpsr |= PSR_C_BIT;
+		}
+		spin_unlock(&mm->page_table_lock);
+		return val;
+
+		bad_access:
+		spin_unlock(&mm->page_table_lock);
+		/* simulate a read access fault */
+		do_DataAbort(addr, 15 + (1 << 11), regs);
+		return -1;
+	}
+#endif
+
 	default:
 		/* Calls 9f00xx..9f07ff are defined to return -ENOSYS
 		   if not implemented, rather than raising SIGILL.  This
@@ -476,7 +532,7 @@ asmlinkage int arm_syscall(int no, struc
 		       current->pid, current->comm, no);
 		dump_instr(regs);
 		if (user_mode(regs)) {
-			show_regs(regs);
+			__show_regs(regs);
 			c_backtrace(regs->ARM_fp, processor_mode(regs));
 		}
 	}
@@ -487,11 +543,48 @@ asmlinkage int arm_syscall(int no, struc
 	info.si_addr  = (void __user *)instruction_pointer(regs) -
 			 (thumb_mode(regs) ? 2 : 4);
 
-	force_sig_info(SIGILL, &info, current);
-	die_if_kernel("Oops - bad syscall(2)", regs, no);
+	notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
 	return 0;
 }
 
+#ifdef CONFIG_TLS_REG_EMUL
+
+/*
+ * We might be running on an ARMv6+ processor which should have the TLS
+ * register but for some reason we can't use it, or maybe an SMP system
+ * using a pre-ARMv6 processor (there are apparently a few prototypes like
+ * that in existence) and therefore access to that register must be
+ * emulated.
+ */
+
+static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
+{
+	int reg = (instr >> 12) & 15;
+	if (reg == 15)
+		return 1;
+	regs->uregs[reg] = current_thread_info()->tp_value;
+	regs->ARM_pc += 4;
+	return 0;
+}
+
+static struct undef_hook arm_mrc_hook = {
+	.instr_mask	= 0x0fff0fff,
+	.instr_val	= 0x0e1d0f70,
+	.cpsr_mask	= PSR_T_BIT,
+	.cpsr_val	= 0,
+	.fn		= get_tp_trap,
+};
+
+static int __init arm_mrc_hook_init(void)
+{
+	register_undef_hook(&arm_mrc_hook);
+	return 0;
+}
+
+late_initcall(arm_mrc_hook_init);
+
+#endif
+
 void __bad_xchg(volatile void *ptr, int size)
 {
 	printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
@@ -524,8 +617,7 @@ baddataabort(int code, unsigned long ins
 	info.si_code  = ILL_ILLOPC;
 	info.si_addr  = (void __user *)addr;
 
-	force_sig_info(SIGILL, &info, current);
-	die_if_kernel("unknown data abort code", regs, instr);
+	notify_die("unknown data abort code", regs, &info, instr, 0);
 }
 
 volatile void __bug(const char *file, int line, void *data)
@@ -578,9 +670,19 @@ EXPORT_SYMBOL(abort);
 
 void __init trap_init(void)
 {
-	extern void __trap_init(void);
+	extern char __stubs_start[], __stubs_end[];
+	extern char __vectors_start[], __vectors_end[];
+	extern char __kuser_helper_start[], __kuser_helper_end[];
+	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
 
-	__trap_init();
+	/*
+	 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
+	 * into the vector page, mapped at 0xffff0000, and ensure these
+	 * are visible to the instruction stream.
+	 */
+	memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);
+	memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);
+	memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz);
 	flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE);
 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -5,6 +5,7 @@
 
 #include <asm-generic/vmlinux.lds.h>
 #include <linux/config.h>
+#include <asm/thread_info.h>
 	
 OUTPUT_ARCH(arm)
 ENTRY(stext)
@@ -103,7 +104,7 @@ SECTIONS
 	__data_loc = ALIGN(4);		/* location in binary */
 	. = DATAADDR;
 #else
-	. = ALIGN(8192);
+	. = ALIGN(THREAD_SIZE);
 	__data_loc = .;
 #endif
 
@@ -160,3 +161,7 @@ SECTIONS
 	.stab.indexstr 0 : { *(.stab.indexstr) }
 	.comment 0 : { *(.comment) }
 }
+
+/* those must never be empty */
+ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
+ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h
new file mode 100644
--- /dev/null
+++ b/arch/arm/lib/bitops.h
@@ -0,0 +1,33 @@
+	.macro	bitop, instr
+	and	r2, r0, #7
+	mov	r3, #1
+	mov	r3, r3, lsl r2
+	save_and_disable_irqs ip, r2
+	ldrb	r2, [r1, r0, lsr #3]
+	\instr	r2, r2, r3
+	strb	r2, [r1, r0, lsr #3]
+	restore_irqs ip
+	mov	pc, lr
+	.endm
+
+/**
+ * testop - implement a test_and_xxx_bit operation.
+ * @instr: operational instruction
+ * @store: store instruction
+ *
+ * Note: we can trivially conditionalise the store instruction
+ * to avoid dirting the data cache.
+ */
+	.macro	testop, instr, store
+	add	r1, r1, r0, lsr #3
+	and	r3, r0, #7
+	mov	r0, #1
+	save_and_disable_irqs ip, r2
+	ldrb	r2, [r1]
+	tst	r2, r0, lsl r3
+	\instr	r2, r2, r0, lsl r3
+	\store	r2, [r1]
+	restore_irqs ip
+	moveq	r0, #0
+	mov	pc, lr
+	.endm
diff --git a/arch/arm/lib/changebit.S b/arch/arm/lib/changebit.S
--- a/arch/arm/lib/changebit.S
+++ b/arch/arm/lib/changebit.S
@@ -9,6 +9,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
                 .text
 
 /* Purpose  : Function to change a bit
@@ -17,12 +18,4 @@
 ENTRY(_change_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_change_bit_le)
-		and	r2, r0, #7
-		mov	r3, #1
-		mov	r3, r3, lsl r2
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1, r0, lsr #3]
-		eor	r2, r2, r3
-		strb	r2, [r1, r0, lsr #3]
-		restore_irqs ip
-		RETINSTR(mov,pc,lr)
+	bitop	eor
diff --git a/arch/arm/lib/clearbit.S b/arch/arm/lib/clearbit.S
--- a/arch/arm/lib/clearbit.S
+++ b/arch/arm/lib/clearbit.S
@@ -9,6 +9,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
                 .text
 
 /*
@@ -18,14 +19,4 @@
 ENTRY(_clear_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_clear_bit_le)
-		and	r2, r0, #7
-		mov	r3, #1
-		mov	r3, r3, lsl r2
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1, r0, lsr #3]
-		bic	r2, r2, r3
-		strb	r2, [r1, r0, lsr #3]
-		restore_irqs ip
-		RETINSTR(mov,pc,lr)
-
-
+	bitop	bic
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S
--- a/arch/arm/lib/io-writesw-armv4.S
+++ b/arch/arm/lib/io-writesw-armv4.S
@@ -87,9 +87,9 @@ ENTRY(__raw_writesw)
 		subs	r2, r2, #2
 		orr	ip, ip, r3, push_hbyte1
 		strh	ip, [r0]
-		bpl	2b
+		bpl	1b
 
-3:		tst	r2, #1
-2:		movne	ip, r3, lsr #8
+		tst	r2, #1
+3:		movne	ip, r3, lsr #8
 		strneh	ip, [r0]
 		mov	pc, lr
diff --git a/arch/arm/lib/setbit.S b/arch/arm/lib/setbit.S
--- a/arch/arm/lib/setbit.S
+++ b/arch/arm/lib/setbit.S
@@ -9,6 +9,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
 		.text
 
 /*
@@ -18,12 +19,4 @@
 ENTRY(_set_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_set_bit_le)
-		and	r2, r0, #7
-		mov	r3, #1
-		mov	r3, r3, lsl r2
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1, r0, lsr #3]
-		orr	r2, r2, r3
-		strb	r2, [r1, r0, lsr #3]
-		restore_irqs ip
-		RETINSTR(mov,pc,lr)
+	bitop	orr
diff --git a/arch/arm/lib/testchangebit.S b/arch/arm/lib/testchangebit.S
--- a/arch/arm/lib/testchangebit.S
+++ b/arch/arm/lib/testchangebit.S
@@ -9,21 +9,10 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
                 .text
 
 ENTRY(_test_and_change_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_change_bit_le)
-		add	r1, r1, r0, lsr #3
-		and	r3, r0, #7
-		mov	r0, #1
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1]
-		tst	r2, r0, lsl r3
-		eor	r2, r2, r0, lsl r3
-		strb	r2, [r1]
-		restore_irqs ip
-		moveq	r0, #0
-		RETINSTR(mov,pc,lr)
-
-
+	testop	eor, strb
diff --git a/arch/arm/lib/testclearbit.S b/arch/arm/lib/testclearbit.S
--- a/arch/arm/lib/testclearbit.S
+++ b/arch/arm/lib/testclearbit.S
@@ -9,21 +9,10 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
                 .text
 
 ENTRY(_test_and_clear_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_clear_bit_le)
-		add	r1, r1, r0, lsr #3	@ Get byte offset
-		and	r3, r0, #7		@ Get bit offset
-		mov	r0, #1
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1]
-		tst	r2, r0, lsl r3
-		bic	r2, r2, r0, lsl r3
-		strb	r2, [r1]
-		restore_irqs ip
-		moveq	r0, #0
-		RETINSTR(mov,pc,lr)
-
-
+	testop	bicne, strneb
diff --git a/arch/arm/lib/testsetbit.S b/arch/arm/lib/testsetbit.S
--- a/arch/arm/lib/testsetbit.S
+++ b/arch/arm/lib/testsetbit.S
@@ -9,21 +9,10 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "bitops.h"
                 .text
 
 ENTRY(_test_and_set_bit_be)
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_set_bit_le)
-		add	r1, r1, r0, lsr #3	@ Get byte offset
-		and	r3, r0, #7		@ Get bit offset
-		mov	r0, #1
-		save_and_disable_irqs ip, r2
-		ldrb	r2, [r1]
-		tst	r2, r0, lsl r3
-		orr	r2, r2, r0, lsl r3
-		strb	r2, [r1]
-		restore_irqs ip
-		moveq	r0, #0
-		RETINSTR(mov,pc,lr)
-
-
+	testop	orreq, streqb
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -10,6 +10,7 @@ config ARCH_AUTCPU12
 
 config ARCH_CDB89712
 	bool "CDB89712"
+	select ISA
 	help
 	  This is an evaluation board from Cirrus for the CS89712 processor.
 	  The board includes 2 serial ports, Ethernet, IRDA, and expansion
@@ -26,6 +27,8 @@ config ARCH_CLEP7312
 
 config ARCH_EDB7211
 	bool "EDB7211"
+	select ISA
+	select DISCONTIGMEM
 	help
 	  Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
 	  evaluation board.
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -12,6 +12,7 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/device.h>
 #include <linux/serial_8250.h>
 
 #include <asm/mach/arch.h>
@@ -305,11 +306,10 @@ static struct irqaction clps7500_timer_i
 static void __init clps7500_timer_init(void)
 {
 	ioctime_init();
-
 	setup_irq(IRQ_TIMER, &clps7500_timer_irq);
 }
 
-static struct clps7500_timer = {
+static struct sys_timer clps7500_timer = {
 	.init		= clps7500_timer_init,
 	.offset		= ioc_timer_gettimeoffset,
 };
@@ -358,9 +358,9 @@ static struct platform_device serial_dev
 	},
 };
 
-static int __init clps7500_init(void)
+static void __init clps7500_init(void)
 {
-	return platform_register_device(&serial_device);
+	platform_device_register(&serial_device);
 }
 
 MACHINE_START(CLPS7500, "CL-PS7500")
@@ -368,6 +368,7 @@ MACHINE_START(CLPS7500, "CL-PS7500")
 	BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
 	MAPIO(clps7500_map_io)
 	INITIRQ(clps7500_init_irq)
-	.timer		= &clps7500_timer,
+		.init_machine	= clps7500_init,
+		.timer		= &clps7500_timer,
 MACHINE_END
 
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -153,9 +153,9 @@ u8 __inb8(unsigned int port)
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		ret = __raw_readb(ISAIO_BASE + (port << 2));
+		ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2));
 	else {
-		void __iomem *a = ISAIO_BASE + ((port & ~1) << 1);
+		void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
 
 		/*
 		 * Shame nothing else does
@@ -174,45 +174,33 @@ u8 __inb8(unsigned int port)
  */
 u8 __inb16(unsigned int port)
 {
-	u32 ret;
+	unsigned int offset;
 
 	/*
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		ret = __raw_readb(ISAIO_BASE + (port << 2));
-	else {
-		void __iomem *a = ISAIO_BASE + ((port & ~1) << 1);
+		offset = port << 2;
+	else
+		offset = (port & ~1) << 1 | (port & 1);
 
-		/*
-		 * Shame nothing else does
-		 */
-		ret = __raw_readb(a + (port & 1));
-	}
-	return ret;
+	return __raw_readb((void __iomem *)ISAIO_BASE + offset);
 }
 
 u16 __inw(unsigned int port)
 {
-	u32 ret;
+	unsigned int offset;
 
 	/*
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		ret = __raw_readw(ISAIO_BASE + (port << 2));
+		offset = port << 2;
 	else {
-		void __iomem *a = ISAIO_BASE + ((port & ~1) << 1);
-
-		/*
-		 * Shame nothing else does
-		 */
-		if (port & 1)
-			BUG();
-
-		ret = __raw_readw(a);
+		offset = port << 1;
+		BUG_ON(port & 1);
 	}
-	return ret;
+	return __raw_readw((void __iomem *)ISAIO_BASE + offset);
 }
 
 /*
@@ -225,7 +213,7 @@ u32 __inl(unsigned int port)
 	if (SUPERIO_PORT(port) || port & 3)
 		BUG();
 
-	a = ISAIO_BASE + (port << 1);
+	a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
 
 	return __raw_readw(a) | __raw_readw(a + 4) << 16;
 }
@@ -241,9 +229,9 @@ void __outb8(u8 val, unsigned int port)
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		__raw_writeb(val, ISAIO_BASE + (port << 2));
+		__raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2));
 	else {
-		void __iomem *a = ISAIO_BASE + ((port & ~1) << 1);
+		void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
 
 		/*
 		 * Shame nothing else does
@@ -257,37 +245,33 @@ void __outb8(u8 val, unsigned int port)
 
 void __outb16(u8 val, unsigned int port)
 {
+	unsigned int offset;
+
 	/*
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		__raw_writeb(val, ISAIO_BASE + (port << 2));
-	else {
-		void __iomem *a = ISAIO_BASE + ((port & ~1) << 1);
+		offset = port << 2;
+	else
+		offset = (port & ~1) << 1 | (port & 1);
 
-		/*
-		 * Shame nothing else does
-		 */
-		__raw_writeb(val, a + (port & 1));
-	}
+	__raw_writeb(val, (void __iomem *)ISAIO_BASE + offset);
 }
 
 void __outw(u16 val, unsigned int port)
 {
-	u32 off;
+	unsigned int offset;
 
 	/*
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		off = port << 2;
+		offset = port << 2;
 	else {
-		off = port << 1;
-		if (port & 1)
-			BUG();
-
+		offset = port << 1;
+		BUG_ON(port & 1);
 	}
-	__raw_writew(val, ISAIO_BASE + off);
+	__raw_writew(val, (void __iomem *)ISAIO_BASE + offset);
 }
 
 void __outl(u32 val, unsigned int port)
@@ -300,13 +284,6 @@ EXPORT_SYMBOL(__outb16);
 EXPORT_SYMBOL(__outw);
 EXPORT_SYMBOL(__outl);
 
-extern void __arch_writesb(unsigned long virt, const void *from, int len);
-extern void __arch_writesw(unsigned long virt, const void *from, int len);
-extern void __arch_writesl(unsigned long virt, const void *from, int len);
-extern void __arch_readsb(unsigned long virt, void *from, int len);
-extern void __arch_readsw(unsigned long virt, void *from, int len);
-extern void __arch_readsl(unsigned long virt, void *from, int len);
-
 void outsb(unsigned int port, const void *from, int len)
 {
 	u32 off;
@@ -319,7 +296,7 @@ void outsb(unsigned int port, const void
 			BUG();
 	}
 
-	__raw_writesb(ISAIO_BASE + off, from, len);
+	__raw_writesb((void __iomem *)ISAIO_BASE + off, from, len);
 }
 
 void insb(unsigned int port, void *from, int len)
@@ -334,7 +311,7 @@ void insb(unsigned int port, void *from,
 			BUG();
 	}
 
-	__raw_readsb(ISAIO_BASE + off, from, len);
+	__raw_readsb((void __iomem *)ISAIO_BASE + off, from, len);
 }
 
 EXPORT_SYMBOL(outsb);
@@ -352,7 +329,7 @@ void outsw(unsigned int port, const void
 			BUG();
 	}
 
-	__raw_writesw(ISAIO_BASE + off, from, len);
+	__raw_writesw((void __iomem *)ISAIO_BASE + off, from, len);
 }
 
 void insw(unsigned int port, void *from, int len)
@@ -367,7 +344,7 @@ void insw(unsigned int port, void *from,
 			BUG();
 	}
 
-	__raw_readsw(ISAIO_BASE + off, from, len);
+	__raw_readsw((void __iomem *)ISAIO_BASE + off, from, len);
 }
 
 EXPORT_SYMBOL(outsw);
@@ -384,7 +361,7 @@ void outsl(unsigned int port, const void
 	if (SUPERIO_PORT(port) || port & 3)
 		BUG();
 
-	__raw_writesw(ISAIO_BASE + off, from, len << 1);
+	__raw_writesw((void __iomem *)ISAIO_BASE + off, from, len << 1);
 }
 
 void insl(unsigned int port, void *from, int len)
@@ -394,7 +371,7 @@ void insl(unsigned int port, void *from,
 	if (SUPERIO_PORT(port) || port & 3)
 		BUG();
 
-	__raw_readsw(ISAIO_BASE + off, from, len << 1);
+	__raw_readsw((void __iomem *)ISAIO_BASE + off, from, len << 1);
 }
 
 EXPORT_SYMBOL(outsl);
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig
--- a/arch/arm/mach-footbridge/Kconfig
+++ b/arch/arm/mach-footbridge/Kconfig
@@ -5,6 +5,9 @@ menu "Footbridge Implementations"
 config ARCH_CATS
 	bool "CATS"
 	select FOOTBRIDGE_HOST
+	select ISA
+	select ISA_DMA
+	select PCI
 	help
 	  Say Y here if you intend to run this kernel on the CATS.
 
@@ -13,6 +16,9 @@ config ARCH_CATS
 config ARCH_PERSONAL_SERVER
 	bool "Compaq Personal Server"
 	select FOOTBRIDGE_HOST
+	select ISA
+	select ISA_DMA
+	select PCI
 	---help---
 	  Say Y here if you intend to run this kernel on the Compaq
 	  Personal Server.
@@ -42,6 +48,9 @@ config ARCH_EBSA285_HOST
 	bool "EBSA285 (host mode)"
 	select ARCH_EBSA285
 	select FOOTBRIDGE_HOST
+	select ISA
+	select ISA_DMA
+	select PCI
 	help
 	  Say Y here if you intend to run this kernel on the EBSA285 card
 	  in host ("central function") mode.
@@ -51,6 +60,9 @@ config ARCH_EBSA285_HOST
 config ARCH_NETWINDER
 	bool "NetWinder"
 	select FOOTBRIDGE_HOST
+	select ISA
+	select ISA_DMA
+	select PCI
 	help
 	  Say Y here if you intend to run this kernel on the Rebel.COM
 	  NetWinder.  Information about this machine can be found at:
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -8,6 +8,7 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/tty.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -51,8 +51,6 @@ static struct irqaction footbridge_timer
  */
 static void __init footbridge_timer_init(void)
 {
-	isa_rtc_init();
-
 	timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ);
 
 	*CSR_TIMER1_CLR  = 0;
@@ -60,6 +58,8 @@ static void __init footbridge_timer_init
 	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
 
 	setup_irq(IRQ_TIMER1, &footbridge_timer_irq);
+
+	isa_rtc_init();
 }
 
 struct sys_timer footbridge_timer = {
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -4,6 +4,7 @@ menu "IMX Implementations"
 config ARCH_MX1ADS
 	bool "mx1ads"
 	depends on ARCH_IMX
+	select ISA
 	help
 	  Say Y here if you are using the Motorola MX1ADS board
 
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
--- a/arch/arm/mach-imx/dma.c
+++ b/arch/arm/mach-imx/dma.c
@@ -100,10 +100,11 @@ imx_free_dma(int dma_ch)
 static irqreturn_t
 dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int i;
+	int i, disr = DISR;
 	struct dma_channel *channel;
 	unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
 
+	DISR = disr;
 	for (i = 0; i < 11; i++) {
 		channel = &dma_channels[i];
 
@@ -136,7 +137,6 @@ dma_err_handler(int irq, void *dev_id, s
 			       i, channel->name);
 			DBOSR |= (1 << i);
 		}
-		DISR = (1 << i);
 	}
 	return IRQ_HANDLED;
 }
@@ -146,6 +146,7 @@ dma_irq_handler(int irq, void *dev_id, s
 {
 	int i, disr = DISR;
 
+	DISR = disr;
 	for (i = 0; i < 11; i++) {
 		if (disr & (1 << i)) {
 			struct dma_channel *channel = &dma_channels[i];
@@ -161,7 +162,6 @@ dma_irq_handler(int irq, void *dev_id, s
 			}
 		}
 	}
-	DISR = disr;
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
--- a/arch/arm/mach-imx/generic.c
+++ b/arch/arm/mach-imx/generic.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <asm/arch/imxfb.h>
 #include <asm/hardware.h>
 
 #include <asm/mach/map.h>
@@ -228,6 +229,14 @@ static struct platform_device imx_uart2_
 	.resource	= imx_uart2_resources,
 };
 
+static struct imxfb_mach_info imx_fb_info;
+
+void __init set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info)
+{
+	memcpy(&imx_fb_info,hard_imx_fb_info,sizeof(struct imxfb_mach_info));
+}
+EXPORT_SYMBOL(set_imx_fb_info);
+
 static struct resource imxfb_resources[] = {
 	[0] = {
 		.start	= 0x00205000,
@@ -241,9 +250,16 @@ static struct resource imxfb_resources[]
 	},
 };
 
+static u64 fb_dma_mask = ~(u64)0;
+
 static struct platform_device imxfb_device = {
 	.name		= "imx-fb",
 	.id		= 0,
+	.dev		= {
+ 		.platform_data	= &imx_fb_info,
+		.dma_mask	= &fb_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
+	},
 	.num_resources	= ARRAY_SIZE(imxfb_resources),
 	.resource	= imxfb_resources,
 };
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -216,7 +216,9 @@ integrator_timer_interrupt(int irq, void
 
 	write_seqlock(&xtime_lock);
 
-	// ...clear the interrupt
+	/*
+	 * clear the interrupt
+	 */
 	timer1->TimerClear = 1;
 
 	timer_tick(regs);
@@ -264,7 +266,7 @@ void __init integrator_time_init(unsigne
 	timer1->TimerValue   = timer_reload;
 	timer1->TimerControl = timer_ctrl;
 
-	/* 
+	/*
 	 * Make irqs happen for the system timer
 	 */
 	setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -137,7 +137,7 @@ static void __init ap_init_irq(void)
 #ifdef CONFIG_PM
 static unsigned long ic_irq_enable;
 
-static int irq_suspend(struct sys_device *dev, u32 state)
+static int irq_suspend(struct sys_device *dev, pm_message_t state)
 {
 	ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
 	return 0;
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -83,7 +83,6 @@ static struct map_desc intcp_io_desc[] _
  { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
- { 0xfc900000, 0xc9000000, SZ_4K, MT_DEVICE },
  { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE },
  { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE },
 };
@@ -420,7 +419,22 @@ static struct clcd_panel vga = {
  */
 static void cp_clcd_enable(struct clcd_fb *fb)
 {
-	cm_control(CM_CTRL_LCDMUXSEL_MASK, CM_CTRL_LCDMUXSEL_VGA);
+	u32 val;
+
+	if (fb->fb.var.bits_per_pixel <= 8)
+		val = CM_CTRL_LCDMUXSEL_VGA_8421BPP;
+	else if (fb->fb.var.bits_per_pixel <= 16)
+		val = CM_CTRL_LCDMUXSEL_VGA_16BPP;
+	else
+		val = 0; /* no idea for this, don't trust the docs */
+
+	cm_control(CM_CTRL_LCDMUXSEL_MASK|
+		   CM_CTRL_LCDEN0|
+		   CM_CTRL_LCDEN1|
+		   CM_CTRL_STATIC1|
+		   CM_CTRL_STATIC2|
+		   CM_CTRL_STATIC|
+		   CM_CTRL_n24BITEN, val);
 }
 
 static unsigned long framesize = SZ_1M;
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
--- a/arch/arm/mach-integrator/leds.c
+++ b/arch/arm/mach-integrator/leds.c
@@ -37,7 +37,7 @@ static void integrator_leds_event(led_ev
 	unsigned long flags;
 	const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
 	unsigned int update_alpha_leds;
-	
+
 	// yup, change the LEDs
 	local_irq_save(flags);
 	update_alpha_leds = 0;
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
--- a/arch/arm/mach-integrator/time.c
+++ b/arch/arm/mach-integrator/time.c
@@ -40,25 +40,32 @@ static int integrator_set_rtc(void)
 	return 1;
 }
 
-static void rtc_read_alarm(struct rtc_wkalrm *alrm)
+static int rtc_read_alarm(struct rtc_wkalrm *alrm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
+	return 0;
 }
 
-static int rtc_set_alarm(struct rtc_wkalrm *alrm)
+static inline int rtc_set_alarm(struct rtc_wkalrm *alrm)
 {
 	unsigned long time;
 	int ret;
 
-	ret = rtc_tm_to_time(&alrm->time, &time);
+	/*
+	 * At the moment, we can only deal with non-wildcarded alarm times.
+	 */
+	ret = rtc_valid_tm(&alrm->time);
+	if (ret == 0)
+		ret = rtc_tm_to_time(&alrm->time, &time);
 	if (ret == 0)
 		writel(time, rtc_base + RTC_MR);
 	return ret;
 }
 
-static void rtc_read_time(struct rtc_time *tm)
+static int rtc_read_time(struct rtc_time *tm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
+	return 0;
 }
 
 /*
@@ -69,7 +76,7 @@ static void rtc_read_time(struct rtc_tim
  * edge of the 1Hz clock, we must write the time one second
  * in advance.
  */
-static int rtc_set_time(struct rtc_time *tm)
+static inline int rtc_set_time(struct rtc_time *tm)
 {
 	unsigned long time;
 	int ret;
@@ -158,7 +165,7 @@ static int rtc_remove(struct amba_device
 
 static struct timespec rtc_delta;
 
-static int rtc_suspend(struct amba_device *dev, u32 state)
+static int rtc_suspend(struct amba_device *dev, pm_message_t state)
 {
 	struct timespec rtc;
 
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -79,31 +79,11 @@ void ixp2000_release_slowport(struct slo
 /*************************************************************************
  * Chip specific mappings shared by all IXP2000 systems
  *************************************************************************/
-static struct map_desc ixp2000_small_io_desc[] __initdata = {
+static struct map_desc ixp2000_io_desc[] __initdata = {
 	{
-		.virtual	= IXP2000_GLOBAL_REG_VIRT_BASE,
-		.physical	= IXP2000_GLOBAL_REG_PHYS_BASE,
-		.length		= IXP2000_GLOBAL_REG_SIZE,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= IXP2000_GPIO_VIRT_BASE,
-		.physical	= IXP2000_GPIO_PHYS_BASE,
-		.length		= IXP2000_GPIO_SIZE,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= IXP2000_TIMER_VIRT_BASE,
-		.physical	= IXP2000_TIMER_PHYS_BASE,
-		.length		= IXP2000_TIMER_SIZE,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= IXP2000_UART_VIRT_BASE,
-		.physical	= IXP2000_UART_PHYS_BASE,
-		.length		= IXP2000_UART_SIZE,
-		.type		= MT_DEVICE
-	}, {
-		.virtual	= IXP2000_SLOWPORT_CSR_VIRT_BASE,
-		.physical	= IXP2000_SLOWPORT_CSR_PHYS_BASE,
-		.length		= IXP2000_SLOWPORT_CSR_SIZE,
+		.virtual	= IXP2000_CAP_VIRT_BASE,
+		.physical	= IXP2000_CAP_PHYS_BASE,
+		.length		= IXP2000_CAP_SIZE,
 		.type		= MT_DEVICE
 	}, {
 		.virtual	= IXP2000_INTCTL_VIRT_BASE,
@@ -115,11 +95,7 @@ static struct map_desc ixp2000_small_io_
 		.physical	= IXP2000_PCI_CREG_PHYS_BASE,
 		.length		= IXP2000_PCI_CREG_SIZE,
 		.type		= MT_DEVICE
-	}
-};
-
-static struct map_desc ixp2000_large_io_desc[] __initdata = {
-	{
+	}, {
 		.virtual	= IXP2000_PCI_CSR_VIRT_BASE,
 		.physical	= IXP2000_PCI_CSR_PHYS_BASE,
 		.length		= IXP2000_PCI_CSR_SIZE,
@@ -157,8 +133,23 @@ static struct uart_port ixp2000_serial_p
 
 void __init ixp2000_map_io(void)
 {
-	iotable_init(ixp2000_small_io_desc, ARRAY_SIZE(ixp2000_small_io_desc));
-	iotable_init(ixp2000_large_io_desc, ARRAY_SIZE(ixp2000_large_io_desc));
+	extern unsigned int processor_id;
+
+	/*
+	 * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE for
+	 * tweaking the PMDs so XCB=101. On IXP2800s we use the normal
+	 * PMD flags.
+	 */
+	if ((processor_id & 0xfffffff0) == 0x69054190) {
+		int i;
+
+		printk(KERN_INFO "Enabling IXP2400 erratum #66 workaround\n");
+
+		for(i=0;i<ARRAY_SIZE(ixp2000_io_desc);i++)
+			ixp2000_io_desc[i].type = MT_IXP2000_DEVICE;
+	}
+
+	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
 	early_serial_setup(&ixp2000_serial_port);
 
 	/* Set slowport to 8-bit mode.  */
@@ -212,7 +203,7 @@ void __init ixp2000_init_time(unsigned l
 	ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
 	ticks_per_usec = tick_rate / 1000000;
 
-	ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy);
+	ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
 	ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
 
 	/*
@@ -220,7 +211,7 @@ void __init ixp2000_init_time(unsigned l
 	 */
 	ixp2000_reg_write(IXP2000_T4_CLD, -1);
 	ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7));
- 	next_jiffy_time = 0xffffffff - ticks_per_jiffy;
+ 	next_jiffy_time = 0xffffffff;
 
 	/* register for interrupt */
 	setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
@@ -385,7 +376,9 @@ void __init ixp2000_init_irq(void)
 	set_irq_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
 
 	/*
-	 * Enable PCI irq
+	 * Enable PCI irqs.  The actual PCI[AB] decoding is done in
+	 * entry-macro.S, so we don't need a chained handler for the
+	 * PCI interrupt source.
 	 */
 	ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI));
 	for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -6,7 +6,7 @@
  * Created 2004 by Lennert Buytenhek from the ixdp2x01 code.  The
  * original version carries the following notices:
  *
- * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
  * Maintainer: Deepak Saxena <dsaxena@plexity.net>
  *
  * Copyright (C) 2002-2003 Intel Corp.
@@ -207,7 +207,6 @@ static void __init enp2611_init_machine(
 }
 
 
-#ifdef CONFIG_ARCH_ENP2611
 MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
 	MAINTAINER("Lennert Buytenhek <buytenh@wantstofly.org>")
 	BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
@@ -217,6 +216,5 @@ MACHINE_START(ENP2611, "Radisys ENP-2611
 	.timer		= &enp2611_timer,
 	INIT_MACHINE(enp2611_init_machine)
 MACHINE_END
-#endif
 
 
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -65,19 +65,102 @@ static struct sys_timer ixdp2800_timer =
 /*************************************************************************
  * IXDP2800 PCI
  *************************************************************************/
+static void __init ixdp2800_slave_disable_pci_master(void)
+{
+	*IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+
+static void __init ixdp2800_master_wait_for_slave(void)
+{
+	volatile u32 *addr;
+
+	printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure "
+			 "its BAR sizes\n");
+
+	addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
+					PCI_BASE_ADDRESS_1);
+	do {
+		*addr = 0xffffffff;
+		cpu_relax();
+	} while (*addr != 0xfe000008);
+
+	addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
+					PCI_BASE_ADDRESS_2);
+	do {
+		*addr = 0xffffffff;
+		cpu_relax();
+	} while (*addr != 0xc0000008);
+
+	/*
+	 * Configure the slave's SDRAM BAR by hand.
+	 */
+	*addr = 0x40000008;
+}
+
+static void __init ixdp2800_slave_wait_for_master_enable(void)
+{
+	printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n");
+
+	while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0)
+		cpu_relax();
+}
+
 void __init ixdp2800_pci_preinit(void)
 {
 	printk("ixdp2x00_pci_preinit called\n");
 
-	*IXP2000_PCI_ADDR_EXT =  0x0000e000;
+	*IXP2000_PCI_ADDR_EXT = 0x0001e000;
+
+	if (!ixdp2x00_master_npu())
+		ixdp2800_slave_disable_pci_master();
 
-	*IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
 	*IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
+	*IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
 
 	ixp2000_pci_preinit();
+
+	if (ixdp2x00_master_npu()) {
+		/*
+		 * Wait until the slave set its SRAM/SDRAM BAR sizes
+		 * correctly before we proceed to scan and enumerate
+		 * the bus.
+		 */
+		ixdp2800_master_wait_for_slave();
+
+		/*
+		 * We configure the SDRAM BARs by hand because they
+		 * are 1G and fall outside of the regular allocated
+		 * PCI address space.
+		 */
+		*IXP2000_PCI_SDRAM_BAR = 0x00000008;
+	} else {
+		/*
+		 * Wait for the master to complete scanning the bus
+		 * and assigning resources before we proceed to scan
+		 * the bus ourselves.  Set pci=firmware to honor the
+		 * master's resource assignment.
+		 */
+		ixdp2800_slave_wait_for_master_enable();
+		pcibios_setup("firmware");
+	}
+}
+
+/*
+ * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside
+ * of the regular PCI window, because there's only 512M of outbound PCI
+ * memory window on each IXP, while we need 1G for each of the BARs.
+ */
+static void __devinit ixp2800_pci_fixup(struct pci_dev *dev)
+{
+	if (machine_is_ixdp2800()) {
+		dev->resource[2].start = 0;
+		dev->resource[2].end   = 0;
+		dev->resource[2].flags = 0;
+	}
 }
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup);
 
-int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
+static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
 {
 	sys->mem_offset = 0x00000000;
 
@@ -129,22 +212,47 @@ static int __init ixdp2800_pci_map_irq(s
 	} else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
 }
 
-static void ixdp2800_pci_postinit(void)
+static void __init ixdp2800_master_enable_slave(void)
 {
-	struct pci_dev *dev;
+	volatile u32 *addr;
 
-	if (ixdp2x00_master_npu()) {
-		dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
-		pci_remove_bus_device(dev);
-	} else {
-		dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
-		pci_remove_bus_device(dev);
+	printk(KERN_INFO "IXDP2800: enabling slave NPU\n");
+
+	addr = (volatile u32 *)ixp2000_pci_config_addr(0,
+					IXDP2X00_SLAVE_NPU_DEVFN,
+					PCI_COMMAND);
+
+	*addr |= PCI_COMMAND_MASTER;
+}
 
+static void __init ixdp2800_master_wait_for_slave_bus_scan(void)
+{
+	volatile u32 *addr;
+
+	printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n");
+
+	addr = (volatile u32 *)ixp2000_pci_config_addr(0,
+					IXDP2X00_SLAVE_NPU_DEVFN,
+					PCI_COMMAND);
+	while ((*addr & PCI_COMMAND_MEMORY) == 0)
+		cpu_relax();
+}
+
+static void __init ixdp2800_slave_signal_bus_scan_completion(void)
+{
+	printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n");
+	*IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY;
+}
+
+static void __init ixdp2800_pci_postinit(void)
+{
+	if (!ixdp2x00_master_npu()) {
 		ixdp2x00_slave_pci_postinit();
+		ixdp2800_slave_signal_bus_scan_completion();
 	}
 }
 
-struct hw_pci ixdp2800_pci __initdata = {
+struct __initdata hw_pci ixdp2800_pci __initdata = {
 	.nr_controllers	= 1,
 	.setup		= ixdp2800_pci_setup,
 	.preinit	= ixdp2800_pci_preinit,
@@ -155,8 +263,21 @@ struct hw_pci ixdp2800_pci __initdata = 
 
 int __init ixdp2800_pci_init(void)
 {
-	if (machine_is_ixdp2800())
+	if (machine_is_ixdp2800()) {
+		struct pci_dev *dev;
+
 		pci_common_init(&ixdp2800_pci);
+		if (ixdp2x00_master_npu()) {
+			dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+			pci_remove_bus_device(dev);
+
+			ixdp2800_master_enable_slave();
+			ixdp2800_master_wait_for_slave_bus_scan();
+		} else {
+			dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+			pci_remove_bus_device(dev);
+		}
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -3,7 +3,7 @@
  *
  * Code common to Intel IXDP2401 and IXDP2801 platforms
  *
- * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
  * Maintainer: Deepak Saxena <dsaxena@plexity.net>
  *
  * Copyright (C) 2002-2003 Intel Corp.
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -37,7 +37,7 @@ static int pci_master_aborts = 0;
 
 static int clear_master_aborts(void);
 
-static u32 *
+u32 *
 ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
 {
 	u32 *paddress;
@@ -208,15 +208,15 @@ ixp2000_pci_preinit(void)
  * use our own resource space.
  */
 static struct resource ixp2000_pci_mem_space = {
-	.start	= 0x00000000,
+	.start	= 0xe0000000,
 	.end	= 0xffffffff,
 	.flags	= IORESOURCE_MEM,
 	.name	= "PCI Mem Space"
 };
 
 static struct resource ixp2000_pci_io_space = {
-	.start	= 0x00000000,
-	.end	= 0xffffffff,
+	.start	= 0x00010000,
+	.end	= 0x0001ffff,
 	.flags	= IORESOURCE_IO,
 	.name	= "PCI I/O Space"
 };
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -41,7 +41,7 @@ config MACH_IXDP465
 	help
 	  Say 'Y' here if you want your kernel to support Intel's
 	  IXDP465 Development Platform (Also known as BMP).
-	  For more information on this platform, see Documentation/arm/IXP4xx.
+	  For more information on this platform, see <file:Documentation/arm/IXP4xx>.
 
 
 #
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -7,6 +7,5 @@ obj-y	+= common.o common-pci.o 
 obj-$(CONFIG_ARCH_IXDP4XX)	+= ixdp425-pci.o ixdp425-setup.o
 obj-$(CONFIG_MACH_IXDPG425)	+= ixdpg425-pci.o coyote-setup.o
 obj-$(CONFIG_ARCH_ADI_COYOTE)	+= coyote-pci.o coyote-setup.o
-obj-$(CONFIG_ARCH_PRPMC1100)	+= prpmc1100-pci.o prpmc1100-setup.o
 obj-$(CONFIG_MACH_GTWX5715)	+= gtwx5715-pci.o gtwx5715-setup.o
 
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -502,15 +502,6 @@ pci_set_dma_mask(struct pci_dev *dev, u6
 }
     
 int
-pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-	if (mask >= SZ_64M - 1 )
-		return 0;
-
-	return -EIO;
-}
-
-int
 pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
 {
 	if (mask >= SZ_64M - 1 )
@@ -520,7 +511,6 @@ pci_set_consistent_dma_mask(struct pci_d
 }
 
 EXPORT_SYMBOL(pci_set_dma_mask);
-EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(ixp4xx_pci_read);
 EXPORT_SYMBOL(ixp4xx_pci_write);
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -38,6 +38,10 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
+enum ixp4xx_irq_type {
+	IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
+};
+static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
 
 /*************************************************************************
  * GPIO acces functions
@@ -51,9 +55,13 @@
  */
 void gpio_line_config(u8 line, u32 style)
 {
+	static const int gpio2irq[] = {
+		6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
+	};
 	u32 enable;
 	volatile u32 *int_reg;
 	u32 int_style;
+	enum ixp4xx_irq_type irq_type;
 
 	enable = *IXP4XX_GPIO_GPOER;
 
@@ -66,24 +74,33 @@ void gpio_line_config(u8 line, u32 style
 		{
 		case (IXP4XX_GPIO_ACTIVE_HIGH):
 			int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+			irq_type = IXP4XX_IRQ_LEVEL;
 			break;
 		case (IXP4XX_GPIO_ACTIVE_LOW):
 			int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
+			irq_type = IXP4XX_IRQ_LEVEL;
 			break;
 		case (IXP4XX_GPIO_RISING_EDGE):
 			int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
+			irq_type = IXP4XX_IRQ_EDGE;
 			break;
 		case (IXP4XX_GPIO_FALLING_EDGE):
 			int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
+			irq_type = IXP4XX_IRQ_EDGE;
 			break;
 		case (IXP4XX_GPIO_TRANSITIONAL):
 			int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
+			irq_type = IXP4XX_IRQ_EDGE;
 			break;
 		default:
 			int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+			irq_type = IXP4XX_IRQ_LEVEL;
 			break;
 		}
 
+		if (style & IXP4XX_GPIO_INTSTYLE_MASK)
+			ixp4xx_config_irq(gpio2irq[line], irq_type);
+
 		if (line >= 8) {	/* pins 8-15 */ 
 			line -= 8;
 			int_reg = IXP4XX_GPIO_GPIT2R;
@@ -138,10 +155,7 @@ void __init ixp4xx_map_io(void)
  *
  * TODO: GPIO IRQs should be marked invalid until the user of the IRQ
  *       (be it PCI or something else) configures that GPIO line
- *       as an IRQ. Also, we should use a different chip structure for 
- *       level-based GPIO vs edge-based GPIO. Currently nobody needs this as 
- *       all HW that's publically available uses level IRQs, so we'll
- *       worry about it if/when we have HW to test.
+ *       as an IRQ.
  **************************************************************************/
 static void ixp4xx_irq_mask(unsigned int irq)
 {
@@ -151,12 +165,15 @@ static void ixp4xx_irq_mask(unsigned int
 		*IXP4XX_ICMR &= ~(1 << irq);
 }
 
-static void ixp4xx_irq_mask_ack(unsigned int irq)
+static void ixp4xx_irq_unmask(unsigned int irq)
 {
-	ixp4xx_irq_mask(irq);
+	if (cpu_is_ixp46x() && irq >= 32)
+		*IXP4XX_ICMR2 |= (1 << (irq - 32));
+	else
+		*IXP4XX_ICMR |= (1 << irq);
 }
 
-static void ixp4xx_irq_unmask(unsigned int irq)
+static void ixp4xx_irq_ack(unsigned int irq)
 {
 	static int irq2gpio[32] = {
 		-1, -1, -1, -1, -1, -1,  0,  1,
@@ -166,26 +183,47 @@ static void ixp4xx_irq_unmask(unsigned i
 	};
 	int line = (irq < 32) ? irq2gpio[irq] : -1;
 
-	/*
-	 * This only works for LEVEL gpio IRQs as per the IXP4xx developer's
-	 * manual. If edge-triggered, need to move it to the mask_ack.
-	 * Nobody seems to be using the edge-triggered mode on the GPIOs. 
-	 */
 	if (line >= 0)
 		gpio_line_isr_clear(line);
+}
 
-	if (cpu_is_ixp46x() && irq >= 32)
-		*IXP4XX_ICMR2 |= (1 << (irq - 32));
-	else
-		*IXP4XX_ICMR |= (1 << irq);
+/*
+ * Level triggered interrupts on GPIO lines can only be cleared when the
+ * interrupt condition disappears.
+ */
+static void ixp4xx_irq_level_unmask(unsigned int irq)
+{
+	ixp4xx_irq_ack(irq);
+	ixp4xx_irq_unmask(irq);
 }
 
-static struct irqchip ixp4xx_irq_chip = {
-	.ack	= ixp4xx_irq_mask_ack,
+static struct irqchip ixp4xx_irq_level_chip = {
+	.ack	= ixp4xx_irq_mask,
+	.mask	= ixp4xx_irq_mask,
+	.unmask	= ixp4xx_irq_level_unmask,
+};
+
+static struct irqchip ixp4xx_irq_edge_chip = {
+	.ack	= ixp4xx_irq_ack,
 	.mask	= ixp4xx_irq_mask,
 	.unmask	= ixp4xx_irq_unmask,
 };
 
+static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
+{
+	switch (type) {
+	case IXP4XX_IRQ_LEVEL:
+		set_irq_chip(irq, &ixp4xx_irq_level_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		break;
+	case IXP4XX_IRQ_EDGE:
+		set_irq_chip(irq, &ixp4xx_irq_edge_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		break;
+	}
+	set_irq_flags(irq, IRQF_VALID);
+}
+
 void __init ixp4xx_init_irq(void)
 {
 	int i = 0;
@@ -204,12 +242,9 @@ void __init ixp4xx_init_irq(void)
 		*IXP4XX_ICMR2 = 0x00;
 	}
 
+        /* Default to all level triggered */
 	for(i = 0; i < NR_IRQS; i++)
-	{
-		set_irq_chip(i, &ixp4xx_irq_chip);
-		set_irq_handler(i, do_level_IRQ);
-		set_irq_flags(i, IRQF_VALID);
-	}
+		ixp4xx_config_irq(i, IXP4XX_IRQ_LEVEL);
 }
 
 
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -3,7 +3,7 @@
  *
  * Board setup for ADI Engineering and IXDGP425 boards
  *
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * Copyright (C) 2003-2005 MontaVista Software, Inc.
  *
  * Author: Deepak Saxena <dsaxena@plexity.net>
  */
@@ -13,7 +13,7 @@
 #include <linux/device.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
-#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -24,39 +24,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-#ifdef	__ARMEB__
-#define	REG_OFFSET	3
-#else
-#define	REG_OFFSET	0
-#endif
-
-/*
- * Only one serial port is connected on the Coyote & IXDPG425
- */
-static struct uart_port coyote_serial_port = {
-	.membase	= (char*)(IXP4XX_UART2_BASE_VIRT + REG_OFFSET),
-	.mapbase	= (IXP4XX_UART2_BASE_PHYS),
-	.irq		= IRQ_IXP4XX_UART2,
-	.flags		= UPF_SKIP_TEST,
-	.iotype		= UPIO_MEM,	
-	.regshift	= 2,
-	.uartclk	= IXP4XX_UART_XTAL,
-	.line		= 0,
-	.type		= PORT_XSCALE,
-	.fifosize	= 32
-};
-
 void __init coyote_map_io(void)
 {
-	if (machine_is_ixdpg425()) {
-		coyote_serial_port.membase =
-			(char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET);
-		coyote_serial_port.mapbase = IXP4XX_UART1_BASE_PHYS;
-		coyote_serial_port.irq = IRQ_IXP4XX_UART1;
-	}
-
-	early_serial_setup(&coyote_serial_port);
-
 	ixp4xx_map_io();
 }
 
@@ -81,8 +50,35 @@ static struct platform_device coyote_fla
 	.resource	= &coyote_flash_resource,
 };
 
+static struct resource coyote_uart_resource = {
+	.start	= IXP4XX_UART2_BASE_PHYS,
+	.end	= IXP4XX_UART2_BASE_PHYS + 0x0fff,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port coyote_uart_data = {
+	.mapbase	= IXP4XX_UART2_BASE_PHYS,
+	.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+	.irq		= IRQ_IXP4XX_UART2,
+	.flags		= UPF_BOOT_AUTOCONF,
+	.iotype		= UPIO_MEM,
+	.regshift	= 2,
+	.uartclk	= IXP4XX_UART_XTAL,
+};
+
+static struct platform_device coyote_uart = {
+	.name		= "serial8250",
+	.id		= 0,
+	.dev			= {
+		.platform_data	= &coyote_uart_data,
+	},
+	.num_resources	= 1,
+	.resource	= &coyote_uart_resource,
+};
+
 static struct platform_device *coyote_devices[] __initdata = {
-	&coyote_flash
+	&coyote_flash,
+	&coyote_uart
 };
 
 static void __init coyote_init(void)
@@ -90,6 +86,14 @@ static void __init coyote_init(void)
 	*IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
 	*IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
 
+	if (machine_is_ixdpg425()) {
+		coyote_uart_data.membase =
+			(char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET);
+		coyote_uart_data.mapbase = IXP4XX_UART1_BASE_PHYS;
+		coyote_uart_data.irq = IRQ_IXP4XX_UART1;
+	}
+
+
 	ixp4xx_sys_init();
 	platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices));
 }
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -3,7 +3,7 @@
  *
  * IXDP425/IXCDP1100 board-setup 
  *
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * Copyright (C) 2003-2005 MontaVista Software, Inc.
  *
  * Author: Deepak Saxena <dsaxena@plexity.net>
  */
@@ -13,7 +13,7 @@
 #include <linux/device.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
-#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -24,46 +24,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-#ifdef	__ARMEB__
-#define	REG_OFFSET	3
-#else
-#define	REG_OFFSET	0
-#endif
-
-/*
- * IXDP425 uses both chipset serial ports
- */
-static struct uart_port ixdp425_serial_ports[] = {
-	{
-		.membase	= (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET),
-		.mapbase	= (IXP4XX_UART1_BASE_PHYS),
-		.irq		= IRQ_IXP4XX_UART1,
-		.flags		= UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM,	
-		.regshift	= 2,
-		.uartclk	= IXP4XX_UART_XTAL,
-		.line		= 0,
-		.type		= PORT_XSCALE,
-		.fifosize	= 32
-	} , {
-		.membase	= (char*)(IXP4XX_UART2_BASE_VIRT + REG_OFFSET),
-		.mapbase	= (IXP4XX_UART2_BASE_PHYS),
-		.irq		= IRQ_IXP4XX_UART2,
-		.flags		= UPF_SKIP_TEST,
-		.iotype		= UPIO_MEM,	
-		.regshift	= 2,
-		.uartclk	= IXP4XX_UART_XTAL,
-		.line		= 1,
-		.type		= PORT_XSCALE,
-		.fifosize	= 32
-	}
-};
-
 void __init ixdp425_map_io(void) 
 {
-	early_serial_setup(&ixdp425_serial_ports[0]);
-	early_serial_setup(&ixdp425_serial_ports[1]);
-
 	ixp4xx_map_io();
 }
 
@@ -102,11 +64,55 @@ static struct platform_device ixdp425_i2
 	.num_resources	= 0
 };
 
+static struct resource ixdp425_uart_resources[] = {
+	{
+		.start		= IXP4XX_UART1_BASE_PHYS,
+		.end		= IXP4XX_UART1_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM
+	},
+	{
+		.start		= IXP4XX_UART2_BASE_PHYS,
+		.end		= IXP4XX_UART2_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM
+	}
+};
+
+static struct plat_serial8250_port ixdp425_uart_data[] = {
+	{
+		.mapbase	= IXP4XX_UART1_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{
+		.mapbase	= IXP4XX_UART2_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	}
+};
+
+static struct platform_device ixdp425_uart = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev.platform_data	= ixdp425_uart_data,
+	.num_resources		= 2,
+	.resource		= ixdp425_uart_resources
+};
+
 static struct platform_device *ixdp425_devices[] __initdata = {
 	&ixdp425_i2c_controller,
-	&ixdp425_flash
+	&ixdp425_flash,
+	&ixdp425_uart
 };
 
+
 static void __init ixdp425_init(void)
 {
 	ixp4xx_sys_init();
diff --git a/arch/arm/mach-ixp4xx/prpmc1100-pci.c b/arch/arm/mach-ixp4xx/prpmc1100-pci.c
deleted file mode 100644
--- a/arch/arm/mach-ixp4xx/prpmc1100-pci.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/prpmc1100-pci.c 
- *
- * PrPMC1100 PCI initialization
- *
- * Copyright (C) 2003-2004 MontaVista Sofwtare, Inc. 
- * Based on IXDP425 code originally (C) Intel Corporation
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * PrPMC1100 PCI init code.  GPIO usage is similar to that on 
- * IXDP425, but the IRQ routing is completely different and
- * depends on what carrier you are using. This code is written
- * to work on the Motorola PrPMC800 ATX carrier board.
- *
- * 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/kernel.h>
-#include <linux/config.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-
-#include <asm/mach/pci.h>
-
-
-void __init prpmc1100_pci_preinit(void)
-{
-	gpio_line_config(PRPMC1100_PCI_INTA_PIN, 
-				IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-	gpio_line_config(PRPMC1100_PCI_INTB_PIN, 
-				IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-	gpio_line_config(PRPMC1100_PCI_INTC_PIN, 
-				IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-	gpio_line_config(PRPMC1100_PCI_INTD_PIN, 
-				IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-
-	gpio_line_isr_clear(PRPMC1100_PCI_INTA_PIN);
-	gpio_line_isr_clear(PRPMC1100_PCI_INTB_PIN);
-	gpio_line_isr_clear(PRPMC1100_PCI_INTC_PIN);
-	gpio_line_isr_clear(PRPMC1100_PCI_INTD_PIN);
-
-	ixp4xx_pci_preinit();
-}
-
-
-static int __init prpmc1100_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-	int irq = -1;
-
-	static int pci_irq_table[][4] = { 
-		{	/* IDSEL 16 - PMC A1 */
-			IRQ_PRPMC1100_PCI_INTD, 
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB, 
-			IRQ_PRPMC1100_PCI_INTC
-		}, {	/* IDSEL 17 - PRPMC-A-B */
-			IRQ_PRPMC1100_PCI_INTD, 
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB, 
-			IRQ_PRPMC1100_PCI_INTC
-		}, { 	/* IDSEL 18 - PMC A1-B */
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB, 
-			IRQ_PRPMC1100_PCI_INTC, 
-			IRQ_PRPMC1100_PCI_INTD
-		}, {	/* IDSEL 19 - Unused */
-			0, 0, 0, 0 
-		}, {	/* IDSEL 20 - P2P Bridge */
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB, 
-			IRQ_PRPMC1100_PCI_INTC, 
-			IRQ_PRPMC1100_PCI_INTD
-		}, {	/* IDSEL 21 - PMC A2 */
-			IRQ_PRPMC1100_PCI_INTC, 
-			IRQ_PRPMC1100_PCI_INTD, 
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB
-		}, {	/* IDSEL 22 - PMC A2-B */
-			IRQ_PRPMC1100_PCI_INTD, 
-			IRQ_PRPMC1100_PCI_INTA, 
-			IRQ_PRPMC1100_PCI_INTB, 
-			IRQ_PRPMC1100_PCI_INTC
-		},
-	};
-
-	if (slot >= PRPMC1100_PCI_MIN_DEVID && slot <= PRPMC1100_PCI_MAX_DEVID 
-		&& pin >= 1 && pin <= PRPMC1100_PCI_IRQ_LINES) {
-		irq = pci_irq_table[slot - PRPMC1100_PCI_MIN_DEVID][pin - 1];
-	}
-
-	return irq;
-}
-
-
-struct hw_pci prpmc1100_pci __initdata = {
-	.nr_controllers = 1,
-	.preinit =	  prpmc1100_pci_preinit,
-	.swizzle =	  pci_std_swizzle,
-	.setup =	  ixp4xx_setup,
-	.scan =		  ixp4xx_scan_bus,
-	.map_irq =	  prpmc1100_map_irq,
-};
-
-int __init prpmc1100_pci_init(void)
-{
-	if (machine_is_prpmc1100())
-		pci_common_init(&prpmc1100_pci);
-	return 0;
-}
-
-subsys_initcall(prpmc1100_pci_init);
-
diff --git a/arch/arm/mach-ixp4xx/prpmc1100-setup.c b/arch/arm/mach-ixp4xx/prpmc1100-setup.c
deleted file mode 100644
--- a/arch/arm/mach-ixp4xx/prpmc1100-setup.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/prpmc1100-setup.c
- *
- * Motorola PrPMC1100 board setup
- *
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-#ifdef	__ARMEB__
-#define	REG_OFFSET	3
-#else
-#define	REG_OFFSET	0
-#endif
-
-/*
- * Only one serial port is connected on the PrPMC1100
- */
-static struct uart_port prpmc1100_serial_port = {
-	.membase	= (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET),
-	.mapbase	= (IXP4XX_UART1_BASE_PHYS),
-	.irq		= IRQ_IXP4XX_UART1,
-	.flags		= UPF_SKIP_TEST,
-	.iotype		= UPIO_MEM,	
-	.regshift	= 2,
-	.uartclk	= IXP4XX_UART_XTAL,
-	.line		= 0,
-	.type		= PORT_XSCALE,
-	.fifosize	= 32
-};
-
-void __init prpmc1100_map_io(void)
-{
-	early_serial_setup(&prpmc1100_serial_port);
-
-	ixp4xx_map_io();
-}
-
-static struct flash_platform_data prpmc1100_flash_data = {
-	.map_name	= "cfi_probe",
-	.width		= 2,
-};
-
-static struct resource prpmc1100_flash_resource = {
-	.start		= PRPMC1100_FLASH_BASE,
-	.end		= PRPMC1100_FLASH_BASE + PRPMC1100_FLASH_SIZE,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device prpmc1100_flash = {
-	.name		= "IXP4XX-Flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data = &prpmc1100_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &prpmc1100_flash_resource,
-};
-
-static struct platform_device *prpmc1100_devices[] __initdata = {
-	&prpmc1100_flash
-};
-
-static void __init prpmc1100_init(void)
-{
-	ixp4xx_sys_init();
-
-	platform_add_devices(prpmc1100_devices, ARRAY_SIZE(prpmc1100_devices));
-}
-
-MACHINE_START(PRPMC1100, "Motorola PrPMC1100")
-        MAINTAINER("MontaVista Software, Inc.")
-        BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
-                IXP4XX_PERIPHERAL_BASE_VIRT)
-        MAPIO(prpmc1100_map_io)
-        INITIRQ(ixp4xx_init_irq)
-	.timer		= &ixp4xx_timer,
-        BOOT_PARAMS(0x0100)
-	INIT_MACHINE(prpmc1100_init)
-MACHINE_END
-
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -157,8 +157,6 @@ static struct irqchip lpd7a40x_cpld_chip
 	.unmask	= lh7a40x_unmask_cpld_irq,
 };
 
-#define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
-
 static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
 				  struct pt_regs *regs)
 {
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
--- a/arch/arm/mach-lh7a40x/common.h
+++ b/arch/arm/mach-lh7a40x/common.h
@@ -12,3 +12,5 @@ extern struct sys_timer lh7a40x_timer;
 
 extern void lh7a400_init_irq (void);
 extern void lh7a404_init_irq (void);
+
+#define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -55,8 +55,6 @@ static struct irqchip lh7a40x_cpld_chip 
 	.unmask	= lh7a40x_unmask_cpld_irq,
 };
 
-#define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
-
 static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
 				  struct pt_regs *regs)
 {
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -66,6 +66,19 @@ config MACH_OMAP_PERSEUS2
 	  Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
 	  a board.
 
+config MACH_VOICEBLUE
+	bool "Voiceblue"
+	depends on ARCH_OMAP1510
+	help
+	  Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such
+	  board.
+
+config MACH_NETSTAR
+	bool "NetStar"
+	depends on ARCH_OMAP1510
+	help
+	  Support for NetStar PBX. Say Y here if you have such a board.
+
 config MACH_OMAP_GENERIC
 	bool "Generic OMAP board"
 	depends on ARCH_OMAP1510 || ARCH_OMAP16XX
@@ -113,6 +126,38 @@ config OMAP_MUX_WARNINGS
 	  printed, it's safe to deselect OMAP_MUX for your product.
 
 choice
+        prompt "System timer"
+	default OMAP_MPU_TIMER
+
+config OMAP_MPU_TIMER
+	bool "Use mpu timer"
+	help
+	  Select this option if you want to use the OMAP mpu timer. This
+	  timer provides more intra-tick resolution than the 32KHz timer,
+	  but consumes more power.
+
+config OMAP_32K_TIMER
+	bool "Use 32KHz timer"
+	depends on ARCH_OMAP16XX
+	help
+	  Select this option if you want to enable the OMAP 32KHz timer.
+	  This timer saves power compared to the OMAP_MPU_TIMER, and has
+	  support for no tick during idle. The 32KHz timer provides less
+	  intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+	  currently only available for OMAP-16xx.
+
+endchoice
+
+config OMAP_32K_TIMER_HZ
+       int "Kernel internal timer frequency for 32KHz timer"
+       range 32 1024
+       depends on OMAP_32K_TIMER
+       default "128"
+       help
+	  Kernel internal timer frequency should be a divisor of 32768,
+	  such as 64 or 128.
+
+choice
 	prompt "Low-level debug console UART"
 	depends on ARCH_OMAP
 	default OMAP_LL_DEBUG_UART1
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
--- a/arch/arm/mach-omap/Makefile
+++ b/arch/arm/mach-omap/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_MACH_OMAP_GENERIC) += board
 obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
 obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
 obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
+obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
+obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
 
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c
--- a/arch/arm/mach-omap/board-generic.c
+++ b/arch/arm/mach-omap/board-generic.c
@@ -26,7 +26,6 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
-#include <asm/arch/serial.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c
--- a/arch/arm/mach-omap/board-h2.c
+++ b/arch/arm/mach-omap/board-h2.c
@@ -23,14 +23,17 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/clocks.h>
 #include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
 
 #include "common.h"
@@ -39,10 +42,64 @@ extern int omap_gpio_init(void);
 
 static int __initdata h2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
+static struct mtd_partition h2_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data h2_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= h2_partitions,
+	.nr_parts	= ARRAY_SIZE(h2_partitions),
+};
+
+static struct resource h2_flash_resource = {
+	.start		= OMAP_CS2B_PHYS,
+	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device h2_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h2_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &h2_flash_resource,
+};
+
 static struct resource h2_smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP1610_ETHR_START,		/* Physical */
-		.end	= OMAP1610_ETHR_START + SZ_4K,
+		.end	= OMAP1610_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -60,6 +117,7 @@ static struct platform_device h2_smc91x_
 };
 
 static struct platform_device *h2_devices[] __initdata = {
+	&h2_flash_device,
 	&h2_smc91x_device,
 };
 
diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c
--- a/arch/arm/mach-omap/board-h3.c
+++ b/arch/arm/mach-omap/board-h3.c
@@ -21,16 +21,22 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/mux.h>
-#include <asm/arch/gpio.h>
-#include <asm/mach-types.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
 
 #include "common.h"
 
@@ -38,10 +44,64 @@ extern int omap_gpio_init(void);
 
 static int __initdata h3_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
+static struct mtd_partition h3_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data h3_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= h3_partitions,
+	.nr_parts	= ARRAY_SIZE(h3_partitions),
+};
+
+static struct resource h3_flash_resource = {
+	.start		= OMAP_CS2B_PHYS,
+	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h3_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &h3_flash_resource,
+};
+
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP1710_ETHR_START,		/* Physical */
-		.end	= OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE,
+		.end	= OMAP1710_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -58,8 +118,52 @@ static struct platform_device smc91x_dev
 	.resource	= smc91x_resources,
 };
 
+#define GPTIMER_BASE		0xFFFB1400
+#define GPTIMER_REGS(x)	(0xFFFB1400 + (x * 0x800))
+#define GPTIMER_REGS_SIZE	0x46
+
+static struct resource intlat_resources[] = {
+	[0] = {
+		.start  = GPTIMER_REGS(0),	      /* Physical */
+		.end    = GPTIMER_REGS(0) + GPTIMER_REGS_SIZE,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = INT_1610_GPTIMER1,
+		.end    = INT_1610_GPTIMER1,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device intlat_device = {
+	.name	   = "omap_intlat",
+	.id	     = 0,
+	.num_resources  = ARRAY_SIZE(intlat_resources),
+	.resource       = intlat_resources,
+};
+
 static struct platform_device *devices[] __initdata = {
+	&flash_device,
         &smc91x_device,
+	&intlat_device,
+};
+
+static struct omap_usb_config h3_usb_config __initdata = {
+	/* usb1 has a Mini-AB port and external isp1301 transceiver */
+	.otg	    = 2,
+
+#ifdef CONFIG_USB_GADGET_OMAP
+	.hmc_mode       = 19,   /* 0:host(off) 1:dev|otg 2:disabled */
+#elif  defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	/* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+	.hmc_mode       = 20,   /* 1:dev|otg(off) 1:host 2:disabled */
+#endif
+
+	.pins[1]	= 3,
+};
+
+static struct omap_board_config_kernel h3_config[] = {
+	{ OMAP_TAG_USB,	 &h3_usb_config },
 };
 
 static void __init h3_init(void)
diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c
--- a/arch/arm/mach-omap/board-innovator.c
+++ b/arch/arm/mach-omap/board-innovator.c
@@ -20,21 +20,85 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/clocks.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
 
 #include "common.h"
 
 static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
+static struct mtd_partition innovator_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* rest of flash1 is a file system */
+	{
+	      .name		= "rootfs",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_16M - SZ_2M - 2 * SZ_128K,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data innovator_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= innovator_partitions,
+	.nr_parts	= ARRAY_SIZE(innovator_partitions),
+};
+
+static struct resource innovator_flash_resource = {
+	.start		= OMAP_CS0_PHYS,
+	.end		= OMAP_CS0_PHYS + SZ_32M - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device innovator_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &innovator_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &innovator_flash_resource,
+};
+
 #ifdef CONFIG_ARCH_OMAP1510
 
 /* Only FPGA needs to be mapped here. All others are done with ioremap */
@@ -46,7 +110,7 @@ static struct map_desc innovator1510_io_
 static struct resource innovator1510_smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP1510_FPGA_ETHR_START,	/* Physical */
-		.end	= OMAP1510_FPGA_ETHR_START + 16,
+		.end	= OMAP1510_FPGA_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -64,6 +128,7 @@ static struct platform_device innovator1
 };
 
 static struct platform_device *innovator1510_devices[] __initdata = {
+	&innovator_flash_device,
 	&innovator1510_smc91x_device,
 };
 
@@ -74,7 +139,7 @@ static struct platform_device *innovator
 static struct resource innovator1610_smc91x_resources[] = {
 	[0] = {
 		.start	= INNOVATOR1610_ETHR_START,		/* Physical */
-		.end	= INNOVATOR1610_ETHR_START + SZ_4K,
+		.end	= INNOVATOR1610_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -92,6 +157,7 @@ static struct platform_device innovator1
 };
 
 static struct platform_device *innovator1610_devices[] __initdata = {
+	&innovator_flash_device,
 	&innovator1610_smc91x_device,
 };
 
diff --git a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap/board-netstar.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-omap/board-netstar.c
@@ -0,0 +1,151 @@
+/*
+ * Modified from board-generic.c
+ *
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Code for Netstar OMAP board.
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern void __init omap_init_time(void);
+extern int omap_gpio_init(void);
+
+static struct resource netstar_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP_CS1_PHYS + 0x300,
+		.end	= OMAP_CS1_PHYS + 0x300 + 16,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(8),
+		.end	= OMAP_GPIO_IRQ(8),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device netstar_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(netstar_smc91x_resources),
+	.resource	= netstar_smc91x_resources,
+};
+
+static struct platform_device *netstar_devices[] __initdata = {
+	&netstar_smc91x_device,
+};
+
+static void __init netstar_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static void __init netstar_init(void)
+{
+	/* green LED */
+	omap_request_gpio(4);
+	omap_set_gpio_direction(4, 0);
+	/* smc91x reset */
+	omap_request_gpio(7);
+	omap_set_gpio_direction(7, 0);
+	omap_set_gpio_dataout(7, 1);
+	udelay(2);	/* wait at least 100ns */
+	omap_set_gpio_dataout(7, 0);
+	mdelay(50);	/* 50ms until PHY ready */
+	/* smc91x interrupt pin */
+	omap_request_gpio(8);
+	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
+
+	omap_request_gpio(12);
+	omap_request_gpio(13);
+	omap_request_gpio(14);
+	omap_request_gpio(15);
+	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_FALLING_EDGE);
+
+	platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
+
+	/* Switch on green LED */
+	omap_set_gpio_dataout(4, 0);
+	/* Switch off red LED */
+	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
+	omap_writeb(0x80, OMAP_LPG1_LCR);
+}
+
+static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static void __init netstar_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(omap_serial_ports);
+}
+
+#define MACHINE_PANICED		1
+#define MACHINE_REBOOTING	2
+#define MACHINE_REBOOT		4
+static unsigned long machine_state;
+
+static int panic_event(struct notifier_block *this, unsigned long event,
+	 void *ptr)
+{
+	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
+		return NOTIFY_DONE;
+
+	/* Switch off green LED */
+	omap_set_gpio_dataout(4, 1);
+	/* Flash red LED */
+	omap_writeb(0x78, OMAP_LPG1_LCR);
+	omap_writeb(0x01, OMAP_LPG1_PMR);	/* Enable clock */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	.notifier_call	= panic_event,
+};
+
+static int __init netstar_late_init(void)
+{
+	/* TODO: Setup front panel switch here */
+
+	/* Setup panic notifier */
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	return 0;
+}
+
+postcore_initcall(netstar_late_init);
+
+MACHINE_START(NETSTAR, "NetStar OMAP5910")
+	MAINTAINER("Ladislav Michl <michl@2n.cz>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(netstar_map_io)
+	INITIRQ(netstar_init_irq)
+	INIT_MACHINE(netstar_init)
+	.timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c
--- a/arch/arm/mach-omap/board-osk.c
+++ b/arch/arm/mach-omap/board-osk.c
@@ -35,10 +35,10 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/clocks.h>
 #include <asm/arch/gpio.h>
-#include <asm/arch/fpga.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
 
 #include "common.h"
 
@@ -52,7 +52,7 @@ static int __initdata osk_serial_ports[O
 static struct resource osk5912_smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP_OSK_ETHR_START,		/* Physical */
-		.end	= OMAP_OSK_ETHR_START + SZ_4K,
+		.end	= OMAP_OSK_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -64,13 +64,32 @@ static struct resource osk5912_smc91x_re
 
 static struct platform_device osk5912_smc91x_device = {
 	.name		= "smc91x",
-	.id		= 0,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(osk5912_smc91x_resources),
 	.resource	= osk5912_smc91x_resources,
 };
 
+static struct resource osk5912_cf_resources[] = {
+	[0] = {
+		.start	= OMAP_GPIO_IRQ(62),
+		.end	= OMAP_GPIO_IRQ(62),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device osk5912_cf_device = {
+	.name		= "omap_cf",
+	.id		= -1,
+	.dev = {
+		.platform_data	= (void *) 2 /* CS2 */,
+	},
+	.num_resources	= ARRAY_SIZE(osk5912_cf_resources),
+	.resource	= osk5912_cf_resources,
+};
+
 static struct platform_device *osk5912_devices[] __initdata = {
 	&osk5912_smc91x_device,
+	&osk5912_cf_device,
 };
 
 static void __init osk_init_smc91x(void)
@@ -80,6 +99,20 @@ static void __init osk_init_smc91x(void)
 		return;
 	}
 	omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
+
+	/* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
+	EMIFS_CCS(1) |= 0x2;
+}
+
+static void __init osk_init_cf(void)
+{
+	omap_cfg_reg(M7_1610_GPIO62);
+	if ((omap_request_gpio(62)) < 0) {
+		printk("Error requesting gpio 62 for CF irq\n");
+		return;
+	}
+	/* it's really active-low */
+	omap_set_gpio_edge_ctrl(62, OMAP_GPIO_FALLING_EDGE);
 }
 
 void osk_init_irq(void)
@@ -87,12 +120,22 @@ void osk_init_irq(void)
 	omap_init_irq();
 	omap_gpio_init();
 	osk_init_smc91x();
+	osk_init_cf();
 }
 
 static struct omap_usb_config osk_usb_config __initdata = {
-	/* has usb host and device, but no Mini-AB port */
+	/* has usb host connector (A) ... for development it can also
+	 * be used, with a NONSTANDARD gender-bending cable/dongle, as
+	 * a peripheral.
+	 */
+#ifdef	CONFIG_USB_GADGET_OMAP
+	.register_dev	= 1,
+	.hmc_mode	= 0,
+#else
 	.register_host	= 1,
 	.hmc_mode	= 16,
+	.rwc		= 1,
+#endif
 	.pins[0]	= 2,
 };
 
@@ -102,9 +145,10 @@ static struct omap_board_config_kernel o
 
 static void __init osk_init(void)
 {
-        platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
+	platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
 	omap_board_config = osk_config;
 	omap_board_config_size = ARRAY_SIZE(osk_config);
+	USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
 }
 
 static void __init osk_map_io(void)
diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c
--- a/arch/arm/mach-omap/board-perseus2.c
+++ b/arch/arm/mach-omap/board-perseus2.c
@@ -15,24 +15,25 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/clocks.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
-#include <asm/arch/serial.h>
 
 #include "common.h"
 
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.start	= H2P2_DBG_FPGA_ETHR_START,	/* Physical */
-		.end	= H2P2_DBG_FPGA_ETHR_START + SZ_4K,
+		.end	= H2P2_DBG_FPGA_ETHR_START + 0xf,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -44,6 +45,60 @@ static struct resource smc91x_resources[
 
 static int __initdata p2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 0};
 
+static struct mtd_partition p2_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* rest of flash is a file system */
+	{
+	      .name		= "rootfs",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	},
+};
+
+static struct flash_platform_data p2_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= p2_partitions,
+	.nr_parts	= ARRAY_SIZE(p2_partitions),
+};
+
+static struct resource p2_flash_resource = {
+	.start		= OMAP_FLASH_0_START,
+	.end		= OMAP_FLASH_0_START + OMAP_FLASH_0_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device p2_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &p2_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &p2_flash_resource,
+};
+
 static struct platform_device smc91x_device = {
 	.name		= "smc91x",
 	.id		= 0,
@@ -52,6 +107,7 @@ static struct platform_device smc91x_dev
 };
 
 static struct platform_device *devices[] __initdata = {
+	&p2_flash_device,
 	&smc91x_device,
 };
 
diff --git a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap/board-voiceblue.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-omap/board-voiceblue.c
@@ -0,0 +1,256 @@
+/*
+ * linux/arch/arm/mach-omap/board-voiceblue.c
+ *
+ * Modified from board-generic.c
+ *
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Code for OMAP5910 based VoiceBlue board (VoIP to GSM gateway).
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern void omap_init_time(void);
+extern int omap_gpio_init(void);
+
+static struct plat_serial8250_port voiceblue_ports[] = {
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x40000),
+		.irq		= OMAP_GPIO_IRQ(12),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x50000),
+		.irq		= OMAP_GPIO_IRQ(13),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x60000),
+		.irq		= OMAP_GPIO_IRQ(14),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x70000),
+		.irq		= OMAP_GPIO_IRQ(15),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 1,
+	.dev			= {
+		.platform_data	= voiceblue_ports,
+	},
+};
+
+static int __init ext_uart_init(void)
+{
+	return platform_device_register(&serial_device);
+}
+arch_initcall(ext_uart_init);
+
+static struct resource voiceblue_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP_CS2_PHYS + 0x300,
+		.end	= OMAP_CS2_PHYS + 0x300 + 16,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(8),
+		.end	= OMAP_GPIO_IRQ(8),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device voiceblue_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(voiceblue_smc91x_resources),
+	.resource	= voiceblue_smc91x_resources,
+};
+
+static struct platform_device *voiceblue_devices[] __initdata = {
+	&voiceblue_smc91x_device,
+};
+
+static struct omap_usb_config voiceblue_usb_config __initdata = {
+	.hmc_mode	= 3,
+	.register_host	= 1,
+	.register_dev   = 1,
+	.pins[0]	= 2,
+	.pins[1]	= 6,
+	.pins[2]	= 6,
+};
+
+static struct omap_board_config_kernel voiceblue_config[] = {
+	{ OMAP_TAG_USB, &voiceblue_usb_config },
+};
+
+static void __init voiceblue_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static void __init voiceblue_init(void)
+{
+	/* There is a good chance board is going up, so enable Power LED
+	 * (it is connected through invertor) */
+	omap_writeb(0x00, OMAP_LPG1_LCR);
+	/* Watchdog */
+	omap_request_gpio(0);
+	/* smc91x reset */
+	omap_request_gpio(7);
+	omap_set_gpio_direction(7, 0);
+	omap_set_gpio_dataout(7, 1);
+	udelay(2);	/* wait at least 100ns */
+	omap_set_gpio_dataout(7, 0);
+	mdelay(50);	/* 50ms until PHY ready */
+	/* smc91x interrupt pin */
+	omap_request_gpio(8);
+	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
+	/* 16C554 reset*/
+	omap_request_gpio(6);
+	omap_set_gpio_direction(6, 0);
+	omap_set_gpio_dataout(6, 0);
+	/* 16C554 interrupt pins */
+	omap_request_gpio(12);
+	omap_request_gpio(13);
+	omap_request_gpio(14);
+	omap_request_gpio(15);
+	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_RISING_EDGE);
+
+	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
+	omap_board_config = voiceblue_config;
+	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+}
+
+static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static void __init voiceblue_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(omap_serial_ports);
+}
+
+#define MACHINE_PANICED		1
+#define MACHINE_REBOOTING	2
+#define MACHINE_REBOOT		4
+static unsigned long machine_state;
+
+static int panic_event(struct notifier_block *this, unsigned long event,
+	 void *ptr)
+{
+	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
+		return NOTIFY_DONE;
+
+	/* Flash Power LED
+	 * (TODO: Enable clock right way (enabled in bootloader already)) */
+	omap_writeb(0x78, OMAP_LPG1_LCR);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	.notifier_call	= panic_event,
+};
+
+static int __init setup_notifier(void)
+{
+	/* Setup panic notifier */
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	return 0;
+}
+
+postcore_initcall(setup_notifier);
+
+static int wdt_gpio_state;
+
+void voiceblue_wdt_enable(void)
+{
+	omap_set_gpio_direction(0, 0);
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_dataout(0, 1);
+	omap_set_gpio_dataout(0, 0);
+	wdt_gpio_state = 0;
+}
+
+void voiceblue_wdt_disable(void)
+{
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_dataout(0, 1);
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_direction(0, 1);
+}
+
+void voiceblue_wdt_ping(void)
+{
+	if (test_bit(MACHINE_REBOOT, &machine_state))
+		return;
+
+	wdt_gpio_state = !wdt_gpio_state;
+	omap_set_gpio_dataout(0, wdt_gpio_state);
+}
+
+void voiceblue_reset(void)
+{
+	set_bit(MACHINE_REBOOT, &machine_state);
+	voiceblue_wdt_enable();
+	while (1) ;
+}
+
+EXPORT_SYMBOL(voiceblue_wdt_enable);
+EXPORT_SYMBOL(voiceblue_wdt_disable);
+EXPORT_SYMBOL(voiceblue_wdt_ping);
+
+MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
+	MAINTAINER("Ladislav Michl <michl@2n.cz>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(voiceblue_map_io)
+	INITIRQ(voiceblue_init_irq)
+	INIT_MACHINE(voiceblue_init)
+	.timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/mach-omap/clock.c
--- a/arch/arm/mach-omap/clock.c
+++ b/arch/arm/mach-omap/clock.c
@@ -17,6 +17,7 @@
 #include <asm/semaphore.h>
 #include <asm/hardware/clock.h>
 #include <asm/arch/board.h>
+#include <asm/arch/usb.h>
 
 #include "clock.h"
 
@@ -24,34 +25,41 @@ static LIST_HEAD(clocks);
 static DECLARE_MUTEX(clocks_sem);
 static DEFINE_SPINLOCK(clockfw_lock);
 static void propagate_rate(struct clk *  clk);
+/* External clock (MCLK & BCLK) functions */
+static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
+static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
+static void init_ext_clk(struct clk *  clk);
 /* MPU virtual clock functions */
-static int select_table_rate(unsigned long rate);
-static long round_to_table_rate(unsigned long rate);
+static int select_table_rate(struct clk *  clk, unsigned long rate);
+static long round_to_table_rate(struct clk *  clk, unsigned long rate);
 void clk_setdpll(__u16, __u16);
 
 struct mpu_rate rate_table[] = {
 	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
 	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
 	 */
-#if defined(CONFIG_OMAP_ARM_216MHZ) && defined(CONFIG_ARCH_OMAP16XX)
+#if defined(CONFIG_OMAP_ARM_216MHZ)
 	{ 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
 #endif
-#if defined(CONFIG_OMAP_ARM_195MHZ) && defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_OMAP_ARM_195MHZ)
 	{ 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
 #endif
-#if defined(CONFIG_OMAP_ARM_192MHZ) && defined(CONFIG_ARCH_OMAP16XX)
+#if defined(CONFIG_OMAP_ARM_192MHZ)
 	{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
 	{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
 	{  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
 	{  48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
 	{  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
 #endif
-#if defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_OMAP_ARM_182MHZ)
 	{ 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
 #endif
 #if defined(CONFIG_OMAP_ARM_168MHZ)
 	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
 #endif
+#if defined(CONFIG_OMAP_ARM_150MHZ)
+	{ 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+#endif
 #if defined(CONFIG_OMAP_ARM_120MHZ)
 	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
 #endif
@@ -174,12 +182,12 @@ static struct clk armwdt_ck = {
 	.recalc		= &watchdog_recalc,
 };
 
-static struct clk arminth_ck1610 = {
+static struct clk arminth_ck16xx = {
 	.name		= "arminth_ck",
 	.parent		= &arm_ck,
 	.flags		= CLOCK_IN_OMAP16XX,
 	.recalc		= &followparent_recalc,
-	/* Note: On 1610/1710 frequency can be divided by 2 by programming
+	/* Note: On 16xx the frequency can be divided by 2 by programming
 	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
 	 *
 	 * 1510 version is in TC clocks.
@@ -209,7 +217,7 @@ static struct clk dspmmu_ck = {
 static struct clk tc_ck = {
 	.name		= "tc_ck",
 	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
 			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
 	.rate_offset	= CKCTL_TCDIV_OFFSET,
 	.recalc		= &ckctl_recalc,
@@ -220,9 +228,9 @@ static struct clk arminth_ck1510 = {
 	.parent		= &tc_ck,
 	.flags		= CLOCK_IN_OMAP1510,
 	.recalc		= &followparent_recalc,
-	/* Note: On 1510 frequency follows TC_CK
+	/* Note: On 1510 the frequency follows TC_CK
 	 *
-	 * 1610/1710 version is in MPU clocks.
+	 * 16xx version is in MPU clocks.
 	 */
 };
 
@@ -309,7 +317,7 @@ static struct clk rhea2_ck = {
 static struct clk lcd_ck = {
 	.name		= "lcd_ck",
 	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
 			  RATE_CKCTL,
 	.enable_reg	= ARM_IDLECT2,
 	.enable_bit	= EN_LCDCK,
@@ -338,7 +346,7 @@ static struct clk uart2_ck = {
 			  RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= 30,
-	/* (1510/1610/1710)
+	/* (for both 1510 and 16xx)
 	 * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
 	 */
 };
@@ -356,42 +364,72 @@ static struct clk uart3_ck = {
 	 */
 };
 
-static struct clk usb_ck1610 = {
-	.name		= "usb_ck",
+static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
+	.name		= "usb_clko",
 	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP16XX |
+	.rate		= 6000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
 			  RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= ULPD_CLOCK_CTRL,
-	.enable_bit	= USB_MCLK_EN,
-};
-
-static struct clk usb_ck1510 = {
-	.name		= "usb_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+	.enable_bit	= USB_MCLK_EN_BIT,
 };
 
-static struct clk usb_hhc_ck = {
+static struct clk usb_hhc_ck1510 = {
 	.name		= "usb_hhc_ck",
 	/* Direct from ULPD, no parent */
 	.rate		= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+	.flags		= CLOCK_IN_OMAP1510 |
 			  RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= USB_HOST_HHC_UHOST_EN,
 };
 
-/* To be done --
-static struct clk mclk = {
+static struct clk usb_hhc_ck16xx = {
+	.name		= "usb_hhc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+	.flags		= CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
+	.enable_bit	= 8 /* UHOST_EN */,
+};
+
+static struct clk mclk_1510 = {
 	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+};
+
+static struct clk mclk_16xx = {
+	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= COM_CLK_DIV_CTRL_SEL,
+	.enable_bit	= COM_ULPD_PLL_CLK_REQ,
+	.set_rate	= &set_ext_clk_rate,
+	.round_rate	= &round_ext_clk_rate,
+	.init		= &init_ext_clk,
+};
+
+static struct clk bclk_1510 = {
+	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
 };
 
-static struct clk bclk = {
+static struct clk bclk_16xx = {
 	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= SWD_CLK_DIV_CTRL_SEL,
+	.enable_bit	= SWD_ULPD_PLL_CLK_REQ,
+	.set_rate	= &set_ext_clk_rate,
+	.round_rate	= &round_ext_clk_rate,
+	.init		= &init_ext_clk,
 };
--- to be done */
 
 static struct clk mmc1_ck = {
 	.name		= "mmc1_ck",
@@ -438,8 +476,7 @@ static struct clk *  onchip_clks[] = {
 	&armxor_ck,
 	&armtim_ck,
 	&armwdt_ck,
-	&arminth_ck1510,
-	&arminth_ck1610,
+	&arminth_ck1510,  &arminth_ck16xx,
 	/* CK_GEN2 clocks */
 	&dsp_ck,
 	&dspmmu_ck,
@@ -460,13 +497,10 @@ static struct clk *  onchip_clks[] = {
 	&uart1_ck,
 	&uart2_ck,
 	&uart3_ck,
-	&usb_ck1510,
-	&usb_ck1610,
-	&usb_hhc_ck,
-	/* To be done --
-	&mclk,
-	&bclk,
-	-- to be done */
+	&usb_clko,
+	&usb_hhc_ck1510, &usb_hhc_ck16xx,
+	&mclk_1510,  &mclk_16xx,
+	&bclk_1510,  &bclk_16xx,
 	&mmc1_ck,
 	&mmc2_ck,
 	/* Virtual clocks */
@@ -629,6 +663,13 @@ void clk_unuse(struct clk *clk)
 EXPORT_SYMBOL(clk_unuse);
 
 
+int clk_get_usecount(struct clk *clk)
+{
+        return clk->usecount;
+}
+EXPORT_SYMBOL(clk_get_usecount);
+
+
 unsigned long clk_get_rate(struct clk *clk)
 {
 	return clk->rate;
@@ -742,7 +783,7 @@ long clk_round_rate(struct clk *clk, uns
 	}
 
 	if(clk->round_rate != 0)
-		return clk->round_rate(rate);
+		return clk->round_rate(clk, rate);
 
 	return clk->rate;
 }
@@ -761,11 +802,14 @@ static void propagate_rate(struct clk * 
 }
 
 
-static int select_table_rate(unsigned long rate)
+static int select_table_rate(struct clk *  clk, unsigned long rate)
 {
 	/* Find the highest supported frequency <= rate and switch to it */
 	struct mpu_rate *  ptr;
 
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
 	for (ptr = rate_table; ptr->rate; ptr++) {
 		if (ptr->xtal != ck_ref.rate)
 			continue;
@@ -792,12 +836,15 @@ static int select_table_rate(unsigned lo
 }
 
 
-static long round_to_table_rate(unsigned long rate)
+static long round_to_table_rate(struct clk *  clk, unsigned long rate)
 {
 	/* Find the highest supported frequency <= rate */
 	struct mpu_rate *  ptr;
 	long  highest_rate;
 
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
 	highest_rate = -EINVAL;
 
 	for (ptr = rate_table; ptr->rate; ptr++) {
@@ -840,7 +887,7 @@ int clk_set_rate(struct clk *clk, unsign
 		ret = 0;
 	} else if(clk->set_rate != 0) {
 		spin_lock_irqsave(&clockfw_lock, flags);
-		ret = clk->set_rate(rate);
+		ret = clk->set_rate(clk, rate);
 		spin_unlock_irqrestore(&clockfw_lock, flags);
 	}
 
@@ -852,10 +899,79 @@ int clk_set_rate(struct clk *clk, unsign
 EXPORT_SYMBOL(clk_set_rate);
 
 
+static unsigned calc_ext_dsor(unsigned long rate)
+{
+	unsigned dsor;
+
+	/* MCLK and BCLK divisor selection is not linear:
+	 * freq = 96MHz / dsor
+	 *
+	 * RATIO_SEL range: dsor <-> RATIO_SEL
+	 * 0..6: (RATIO_SEL+2) <-> (dsor-2)
+	 * 6..48:  (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
+	 * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
+	 * can not be used.
+	 */
+	for (dsor = 2; dsor < 96; ++dsor) {
+		if ((dsor & 1) && dsor > 8)
+		  	continue;
+		if (rate >= 96000000 / dsor)
+			break;
+	}
+	return dsor;
+}
+
+
+static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	dsor = calc_ext_dsor(rate);
+	clk->rate = 96000000 / dsor;
+	if (dsor > 8)
+		ratio_bits = ((dsor - 8) / 2 + 6) << 2;
+	else
+		ratio_bits = (dsor - 2) << 2;
+
+	ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	return 0;
+}
+
+
+static long round_ext_clk_rate(struct clk *  clk, unsigned long rate)
+{
+	return 96000000 / calc_ext_dsor(rate);
+}
+
+
+static void init_ext_clk(struct clk *  clk)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	/* Determine current rate and ensure clock is based on 96MHz APLL */
+	ratio_bits = omap_readw(clk->enable_reg) & ~1;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	ratio_bits = (ratio_bits & 0xfc) >> 2;
+	if (ratio_bits > 6)
+		dsor = (ratio_bits - 6) * 2 + 8;
+	else
+		dsor = ratio_bits + 2;
+
+	clk-> rate = 96000000 / dsor;
+}
+
+
 int clk_register(struct clk *clk)
 {
 	down(&clocks_sem);
 	list_add(&clk->node, &clocks);
+	if (clk->init)
+		clk->init(clk);
 	up(&clocks_sem);
 	return 0;
 }
@@ -887,6 +1003,11 @@ int __init clk_init(void)
 			clk_register(*clkp);
 			continue;
 		}
+
+		if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) {
+			clk_register(*clkp);
+			continue;
+		}
 	}
 
 	info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
@@ -906,7 +1027,7 @@ int __init clk_init(void)
 	omap_writew(0x1000, ARM_SYSST);
 
 	/* Find the highest supported frequency and enable it */
-	if (select_table_rate(~0)) {
+	if (select_table_rate(&virtual_ck_mpu, ~0)) {
 		printk(KERN_ERR "System frequencies not set. Check your config.\n");
 		/* Guess sane values (60MHz) */
 		omap_writew(0x2290, DPLL_CTL);
diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/mach-omap/clock.h
--- a/arch/arm/mach-omap/clock.h
+++ b/arch/arm/mach-omap/clock.h
@@ -22,13 +22,14 @@ struct clk {
 	struct clk		*parent;
 	unsigned long		rate;
 	__s8			usecount;
-	__u8			flags;
+	__u16			flags;
 	__u32			enable_reg;
 	__u8			enable_bit;
 	__u8			rate_offset;
 	void			(*recalc)(struct clk *);
-	int			(*set_rate)(unsigned long);
-	long			(*round_rate)(unsigned long);
+	int			(*set_rate)(struct clk *, unsigned long);
+	long			(*round_rate)(struct clk *, unsigned long);
+	void			(*init)(struct clk *);
 };
 
 
@@ -50,6 +51,7 @@ struct mpu_rate {
 #define ENABLE_REG_32BIT	32
 #define CLOCK_IN_OMAP16XX	64
 #define CLOCK_IN_OMAP1510	128
+#define CLOCK_IN_OMAP730	256
 
 /* ARM_CKCTL bit shifts */
 #define CKCTL_PERDIV_OFFSET	0
@@ -95,8 +97,12 @@ struct mpu_rate {
 #define EN_TC2_CK	4
 
 /* Various register defines for clock controls scattered around OMAP chip */
-#define USB_MCLK_EN		4	/* In ULPD_CLKC_CTRL */
+#define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
 #define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
+#define SWD_ULPD_PLL_CLK_REQ	1	/* In SWD_CLK_DIV_CTRL_SEL */
+#define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
+#define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
+#define COM_CLK_DIV_CTRL_SEL	0xfffe0878
 
 
 int clk_register(struct clk *clk);
diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c
--- a/arch/arm/mach-omap/common.c
+++ b/arch/arm/mach-omap/common.c
@@ -263,9 +263,6 @@ static void __init _omap_map_io(void)
 	iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
 	omap_check_revision();
 
-	/* clear BM to canonicalize CS0 (not CS3) at 0000:0000 */
-	omap_writel(omap_readl(EMIFS_CONFIG) & 0x0d, EMIFS_CONFIG);
-
 #ifdef CONFIG_ARCH_OMAP730
 	if (cpu_is_omap730()) {
 		iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
@@ -436,6 +433,9 @@ void __init omap_serial_init(int ports[O
 				omap_cfg_reg(UART3_TX);
 				omap_cfg_reg(UART3_RX);
 			}
+			if (cpu_is_omap1710()) {
+				clk_enable(clk_get(0, "uart3_ck"));
+			}
 			break;
 		}
 		omap_serial_reset(&serial_platform_data[i]);
@@ -475,6 +475,12 @@ static const void *get_config(u16 tag, s
 			skip--;
 		}
 
+		if ((info->len & 0x03) != 0) {
+			/* We bail out to avoid an alignment fault */
+			printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
+			       info->len, info->tag);
+			return NULL;
+		}
 		next = (u8 *) info + sizeof(*info) + info->len;
 		if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
 			info = NULL;
@@ -484,10 +490,15 @@ static const void *get_config(u16 tag, s
 	if (info != NULL) {
 		/* Check the length as a lame attempt to check for
 		 * binary inconsistancy. */
-		if (len != NO_LENGTH_CHECK && info->len != len) {
-			printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
-			       tag, len, info->len);
-			return NULL;
+		if (len != NO_LENGTH_CHECK) {
+			/* Word-align len */
+			if (len & 0x03)
+				len = (len + 3) & ~0x03;
+			if (info->len != len) {
+				printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
+				       tag, len, info->len);
+				return NULL;
+			}
 		}
 		if (len_out != NULL)
 			*len_out = info->len;
diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c
--- a/arch/arm/mach-omap/dma.c
+++ b/arch/arm/mach-omap/dma.c
@@ -494,7 +494,7 @@ int omap_request_dma(int dev_id, const c
 	chan->data = data;
 	chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
 
-	if (cpu_is_omap16xx() || cpu_is_omap730()) {
+	if (cpu_is_omap16xx()) {
 		/* If the sync device is set, configure it dynamically. */
 		if (dev_id != 0) {
 			set_gdma_dev(free_ch + 1, dev_id);
diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c
--- a/arch/arm/mach-omap/fpga.c
+++ b/arch/arm/mach-omap/fpga.c
@@ -92,26 +92,17 @@ void innovator_fpga_IRQ_demux(unsigned i
 	u32 stat;
 	int fpga_irq;
 
-	/*
-	 * Acknowledge the parent IRQ.
-	 */
-	desc->chip->ack(irq);
+	stat = get_fpga_unmasked_irqs();
 
-	for (;;) {
-		stat = get_fpga_unmasked_irqs();
-
-		if (!stat) {
-			break;
-		}
+	if (!stat)
+		return;
 
-		for (fpga_irq = OMAP1510_IH_FPGA_BASE;
-			(fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
-			fpga_irq++, stat >>= 1) {
-			if (stat & 1) {
-				d = irq_desc + fpga_irq;
-				d->handle(fpga_irq, d, regs);
-				desc->chip->unmask(irq);
-			}
+	for (fpga_irq = OMAP1510_IH_FPGA_BASE;
+	     (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
+	     fpga_irq++, stat >>= 1) {
+		if (stat & 1) {
+			d = irq_desc + fpga_irq;
+			d->handle(fpga_irq, d, regs);
 		}
 	}
 }
@@ -177,7 +168,7 @@ void omap1510_fpga_init_irq(void)
 			set_irq_chip(i, &omap_fpga_irq);
 		}
 
-		set_irq_handler(i, do_level_IRQ);
+		set_irq_handler(i, do_edge_IRQ);
 		set_irq_flags(i, IRQF_VALID);
 	}
 
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c
--- a/arch/arm/mach-omap/gpio.c
+++ b/arch/arm/mach-omap/gpio.c
@@ -114,7 +114,7 @@ static struct gpio_bank gpio_bank_1510[2
 #ifdef CONFIG_ARCH_OMAP730
 static struct gpio_bank gpio_bank_730[7] = {
 	{ OMAP_MPUIO_BASE,     INT_730_MPUIO,	    IH_MPUIO_BASE,	METHOD_MPUIO },
-	{ OMAP730_GPIO1_BASE,  INT_GPIO_BANK1,	    IH_GPIO_BASE,	METHOD_GPIO_730 },
+	{ OMAP730_GPIO1_BASE,  INT_730_GPIO_BANK1,  IH_GPIO_BASE,	METHOD_GPIO_730 },
 	{ OMAP730_GPIO2_BASE,  INT_730_GPIO_BANK2,  IH_GPIO_BASE + 32,	METHOD_GPIO_730 },
 	{ OMAP730_GPIO3_BASE,  INT_730_GPIO_BANK3,  IH_GPIO_BASE + 64,	METHOD_GPIO_730 },
 	{ OMAP730_GPIO4_BASE,  INT_730_GPIO_BANK4,  IH_GPIO_BASE + 96,	METHOD_GPIO_730 },
@@ -307,6 +307,9 @@ int omap_get_gpio_datain(int gpio)
 	case METHOD_GPIO_1610:
 		reg += OMAP1610_GPIO_DATAIN;
 		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_DATA_INPUT;
+		break;
 	default:
 		BUG();
 		return -1;
@@ -407,13 +410,13 @@ static int _get_gpio_edge_ctrl(struct gp
 	}
 }
 
-static void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 {
 	u32 reg = bank->base;
 
 	switch (bank->method) {
 	case METHOD_MPUIO:
-		/* MPUIO irqstatus cannot be cleared one bit at a time,
+		/* MPUIO irqstatus is reset by reading the status register,
 		 * so do nothing here */
 		return;
 	case METHOD_GPIO_1510:
@@ -429,10 +432,15 @@ static void _clear_gpio_irqstatus(struct
 		BUG();
 		return;
 	}
-	__raw_writel(1 << get_gpio_index(gpio), reg);
+	__raw_writel(gpio_mask, reg);
+}
+
+static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+{
+	_clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio));
 }
 
-static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
+static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
 {
 	u32 reg = bank->base;
 	u32 l;
@@ -442,33 +450,32 @@ static void _set_gpio_irqenable(struct g
 		reg += OMAP_MPUIO_GPIO_MASKIT;
 		l = __raw_readl(reg);
 		if (enable)
-			l &= ~(1 << gpio);
+			l &= ~(gpio_mask);
 		else
-			l |= 1 << gpio;
+			l |= gpio_mask;
 		break;
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_INT_MASK;
 		l = __raw_readl(reg);
 		if (enable)
-			l &= ~(1 << gpio);
+			l &= ~(gpio_mask);
 		else
-			l |= 1 << gpio;
+			l |= gpio_mask;
 		break;
 	case METHOD_GPIO_1610:
-		if (enable) {
+		if (enable)
 			reg += OMAP1610_GPIO_SET_IRQENABLE1;
-			_clear_gpio_irqstatus(bank, gpio);
-		} else
+		else
 			reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
-		l = 1 << gpio;
+		l = gpio_mask;
 		break;
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_INT_MASK;
 		l = __raw_readl(reg);
 		if (enable)
-			l &= ~(1 << gpio);
+			l &= ~(gpio_mask);
 		else
-			l |= 1 << gpio;
+			l |= gpio_mask;
 		break;
 	default:
 		BUG();
@@ -477,6 +484,11 @@ static void _set_gpio_irqenable(struct g
 	__raw_writel(l, reg);
 }
 
+static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
+{
+	_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
+}
+
 int omap_request_gpio(int gpio)
 {
 	struct gpio_bank *bank;
@@ -523,31 +535,31 @@ void omap_free_gpio(int gpio)
 	}
 	bank->reserved_map &= ~(1 << get_gpio_index(gpio));
 	_set_gpio_direction(bank, get_gpio_index(gpio), 1);
-	_set_gpio_irqenable(bank, get_gpio_index(gpio), 0);
+	_set_gpio_irqenable(bank, gpio, 0);
+	_clear_gpio_irqstatus(bank, gpio);
 	spin_unlock(&bank->lock);
 }
 
+/*
+ * We need to unmask the GPIO bank interrupt as soon as possible to
+ * avoid missing GPIO interrupts for other lines in the bank.
+ * Then we need to mask-read-clear-unmask the triggered GPIO lines
+ * in the bank to avoid missing nested interrupts for a GPIO line.
+ * If we wait to unmask individual GPIO lines in the bank after the
+ * line's interrupt handler has been run, we may miss some nested
+ * interrupts.
+ */
 static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
 			     struct pt_regs *regs)
 {
 	u32 isr_reg = 0;
-	struct gpio_bank *bank = (struct gpio_bank *) desc->data;
+	u32 isr;
+	unsigned int gpio_irq;
+	struct gpio_bank *bank;
 
-	/*
-	 * Acknowledge the parent IRQ.
-	 */
 	desc->chip->ack(irq);
 
-	/* Since the level 1 GPIO interrupt cascade (IRQ14) is configured as
-	 * edge-sensitive, we need to unmask it here in order to avoid missing
-	 * any additional GPIO interrupts that might occur after the last time
-	 * we check for pending GPIO interrupts here.
-	 * We are relying on the fact that this interrupt handler was installed
-	 * with the SA_INTERRUPT flag so that interrupts are disabled at the
-	 * CPU while it is executing.
-	 */
-	desc->chip->unmask(irq);
-
+	bank = (struct gpio_bank *) desc->data;
 	if (bank->method == METHOD_MPUIO)
 		isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
 #ifdef CONFIG_ARCH_OMAP1510
@@ -562,20 +574,23 @@ static void gpio_irq_handler(unsigned in
 	if (bank->method == METHOD_GPIO_730)
 		isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
 #endif
-	for (;;) {
-		u32 isr = __raw_readl(isr_reg);
-		unsigned int gpio_irq;
-
-		if (!isr)
-			break;
-		gpio_irq = bank->virtual_irq_start;
-
-		for (; isr != 0; isr >>= 1, gpio_irq++) {
-			if (isr & 1) {
-				struct irqdesc *d = irq_desc + gpio_irq;
-				d->handle(gpio_irq, d, regs);
-			}
-		}
+
+	isr = __raw_readl(isr_reg);
+	_enable_gpio_irqbank(bank, isr, 0);
+	_clear_gpio_irqbank(bank, isr);
+	_enable_gpio_irqbank(bank, isr, 1);
+	desc->chip->unmask(irq);
+
+	if (unlikely(!isr))
+		return;
+
+	gpio_irq = bank->virtual_irq_start;
+	for (; isr != 0; isr >>= 1, gpio_irq++) {
+		struct irqdesc *d;
+		if (!(isr & 1))
+			continue;
+		d = irq_desc + gpio_irq;
+		d->handle(gpio_irq, d, regs);
 	}
 }
 
@@ -584,18 +599,7 @@ static void gpio_ack_irq(unsigned int ir
 	unsigned int gpio = irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = get_gpio_bank(gpio);
 
-#ifdef CONFIG_ARCH_OMAP1510
-	if (bank->method == METHOD_GPIO_1510)
-		__raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS);
-#endif
-#if defined(CONFIG_ARCH_OMAP16XX)
-	if (bank->method == METHOD_GPIO_1610)
-		__raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1);
-#endif
-#ifdef CONFIG_ARCH_OMAP730
-	if (bank->method == METHOD_GPIO_730)
-		__raw_writel(1 << (gpio & 0x1f), bank->base + OMAP730_GPIO_INT_STATUS);
-#endif
+	_clear_gpio_irqstatus(bank, gpio);
 }
 
 static void gpio_mask_irq(unsigned int irq)
@@ -603,7 +607,7 @@ static void gpio_mask_irq(unsigned int i
 	unsigned int gpio = irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = get_gpio_bank(gpio);
 
-	_set_gpio_irqenable(bank, get_gpio_index(gpio), 0);
+	_set_gpio_irqenable(bank, gpio, 0);
 }
 
 static void gpio_unmask_irq(unsigned int irq)
@@ -616,7 +620,7 @@ static void gpio_unmask_irq(unsigned int
 		       gpio);
 		_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
 	}
-	_set_gpio_irqenable(bank, get_gpio_index(gpio), 1);
+	_set_gpio_irqenable(bank, gpio, 1);
 }
 
 static void mpuio_ack_irq(unsigned int irq)
@@ -629,7 +633,7 @@ static void mpuio_mask_irq(unsigned int 
 	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
 	struct gpio_bank *bank = get_gpio_bank(gpio);
 
-	_set_gpio_irqenable(bank, get_gpio_index(gpio), 0);
+	_set_gpio_irqenable(bank, gpio, 0);
 }
 
 static void mpuio_unmask_irq(unsigned int irq)
@@ -637,7 +641,7 @@ static void mpuio_unmask_irq(unsigned in
 	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
 	struct gpio_bank *bank = get_gpio_bank(gpio);
 
-	_set_gpio_irqenable(bank, get_gpio_index(gpio), 1);
+	_set_gpio_irqenable(bank, gpio, 1);
 }
 
 static struct irqchip gpio_irq_chip = {
@@ -722,7 +726,7 @@ static int __init _omap_gpio_init(void)
 				set_irq_chip(j, &mpuio_irq_chip);
 			else
 				set_irq_chip(j, &gpio_irq_chip);
-			set_irq_handler(j, do_edge_IRQ);
+			set_irq_handler(j, do_simple_IRQ);
 			set_irq_flags(j, IRQF_VALID);
 		}
 		set_irq_chained_handler(bank->irq, gpio_irq_handler);
diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c
--- a/arch/arm/mach-omap/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap/leds-h2p2-debug.c
@@ -3,6 +3,11 @@
  *
  * Copyright 2003 by Texas Instruments Incorporated
  *
+ * There are 16 LEDs on the debug board (all green); four may be used
+ * for logical 'green', 'amber', 'red', and 'blue' (after "claiming").
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators.
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -16,78 +21,111 @@
 #include <asm/system.h>
 
 #include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
 
 #include "leds.h"
 
+
+#define GPIO_LED_RED		3
+#define GPIO_LED_GREEN		OMAP_MPUIO(4)
+
+
+#define LED_STATE_ENABLED	0x01
+#define LED_STATE_CLAIMED	0x02
+#define LED_TIMER_ON		0x04
+
+#define GPIO_IDLE		GPIO_LED_GREEN
+#define GPIO_TIMER		GPIO_LED_RED
+
+
 void h2p2_dbg_leds_event(led_event_t evt)
 {
 	unsigned long flags;
-	static unsigned long hw_led_state = 0;
+
+	static struct h2p2_dbg_fpga __iomem *fpga;
+	static u16 led_state, hw_led_state;
 
 	local_irq_save(flags);
 
+	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+		goto done;
+
 	switch (evt) {
 	case led_start:
-		hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP;
+		if (!fpga)
+			fpga = ioremap(H2P2_DBG_FPGA_START,
+						H2P2_DBG_FPGA_SIZE);
+		if (fpga) {
+			led_state |= LED_STATE_ENABLED;
+			__raw_writew(~0, &fpga->leds);
+		}
 		break;
 
 	case led_stop:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP;
-		break;
+	case led_halted:
+		/* all leds off during suspend or shutdown */
+		omap_set_gpio_dataout(GPIO_TIMER, 0);
+		omap_set_gpio_dataout(GPIO_IDLE, 0);
+		__raw_writew(~0, &fpga->leds);
+		led_state &= ~LED_STATE_ENABLED;
+		if (evt == led_halted) {
+			iounmap(fpga);
+			fpga = NULL;
+		}
+		goto done;
 
 	case led_claim:
-		hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
 		break;
 
 	case led_release:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+		led_state &= ~LED_STATE_CLAIMED;
 		break;
 
 #ifdef CONFIG_LEDS_TIMER
 	case led_timer:
-		/*
-		 * Toggle Timer LED
-		 */
-		if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER)
-			hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER;
-		else
-			hw_led_state |= H2P2_DBG_FPGA_LED_TIMER;
-		break;
+		led_state ^= LED_TIMER_ON;
+		omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON);
+		goto done;
 #endif
 
 #ifdef CONFIG_LEDS_CPU
 	case led_idle_start:
-		hw_led_state |= H2P2_DBG_FPGA_LED_IDLE;
-		break;
+		omap_set_gpio_dataout(GPIO_IDLE, 1);
+		goto done;
 
 	case led_idle_end:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE;
-		break;
+		omap_set_gpio_dataout(GPIO_IDLE, 0);
+		goto done;
 #endif
 
-	case led_halted:
-		if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED)
-			hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED;
-		else
-			hw_led_state |= H2P2_DBG_FPGA_LED_HALTED;
-		break;
-
 	case led_green_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
 		break;
-
 	case led_green_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
 		break;
 
 	case led_amber_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
 		break;
-
 	case led_amber_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
 		break;
 
 	case led_red_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
 		break;
-
 	case led_red_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+		break;
+
+	case led_blue_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+		break;
+	case led_blue_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
 		break;
 
 	default:
@@ -98,7 +136,9 @@ void h2p2_dbg_leds_event(led_event_t evt
 	/*
 	 *  Actually burn the LEDs
 	 */
-	__raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS);
+	if (led_state & LED_STATE_CLAIMED)
+		__raw_writew(~hw_led_state, &fpga->leds);
 
+done:
 	local_irq_restore(flags);
 }
diff --git a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap/leds-osk.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-omap/leds-osk.c
@@ -0,0 +1,198 @@
+/*
+ * linux/arch/arm/mach-omap/leds-osk.c
+ *
+ * LED driver for OSK, and optionally Mistral QVGA, boards
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	(1 << 0)
+#define LED_STATE_CLAIMED	(1 << 1)
+static u8 led_state;
+
+#define	GREEN_LED		(1 << 0)	/* TPS65010 LED1 */
+#define	AMBER_LED		(1 << 1)	/* TPS65010 LED2 */
+#define	RED_LED			(1 << 2)	/* TPS65010 GPIO2 */
+#define	TIMER_LED		(1 << 3)	/* Mistral board */
+#define	IDLE_LED		(1 << 4)	/* Mistral board */
+static u8 hw_led_state;
+
+
+/* TPS65010 leds are changed using i2c -- from a task context.
+ * Using one of these for the "idle" LED would be impractical...
+ */
+#define	TPS_LEDS	(GREEN_LED | RED_LED | AMBER_LED)
+
+static u8 tps_leds_change;
+
+static void tps_work(void *unused)
+{
+	for (;;) {
+		u8	leds;
+
+		local_irq_disable();
+		leds = tps_leds_change;
+		tps_leds_change = 0;
+		local_irq_enable();
+
+		if (!leds)
+			break;
+
+		/* careful:  the set_led() value is on/off/blink */
+		if (leds & GREEN_LED)
+			tps65010_set_led(LED1, !!(hw_led_state & GREEN_LED));
+		if (leds & AMBER_LED)
+			tps65010_set_led(LED2, !!(hw_led_state & AMBER_LED));
+
+		/* the gpio led doesn't have that issue */
+		if (leds & RED_LED)
+			tps65010_set_gpio_out_value(GPIO2,
+					!(hw_led_state & RED_LED));
+	}
+}
+
+static DECLARE_WORK(work, tps_work, NULL);
+
+#ifdef	CONFIG_FB_OMAP
+
+/* For now, all system indicators require the Mistral board, since that
+ * LED can be manipulated without a task context.  This LED is either red,
+ * or green, but not both; it can't give the full "disco led" effect.
+ */
+
+#define GPIO_LED_RED		3
+#define GPIO_LED_GREEN		OMAP_MPUIO(4)
+
+static void mistral_setled(void)
+{
+	int	red = 0;
+	int	green = 0;
+
+	if (hw_led_state & TIMER_LED)
+		red = 1;
+	else if (hw_led_state & IDLE_LED)
+		green = 1;
+	// else both sides are disabled
+
+	omap_set_gpio_dataout(GPIO_LED_GREEN, green);
+	omap_set_gpio_dataout(GPIO_LED_RED, red);
+}
+
+#endif
+
+void osk_leds_event(led_event_t evt)
+{
+	unsigned long	flags;
+	u16		leds;
+
+	local_irq_save(flags);
+
+	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+		goto done;
+
+	leds = hw_led_state;
+	switch (evt) {
+	case led_start:
+		led_state |= LED_STATE_ENABLED;
+		hw_led_state = 0;
+		leds = ~0;
+		break;
+
+	case led_halted:
+	case led_stop:
+		led_state &= ~LED_STATE_ENABLED;
+		hw_led_state = 0;
+		// NOTE:  work may still be pending!!
+		break;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		leds = ~0;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+#ifdef	CONFIG_FB_OMAP
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		hw_led_state ^= TIMER_LED;
+		mistral_setled();
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		hw_led_state |= IDLE_LED;
+		mistral_setled();
+		break;
+
+	case led_idle_end:
+		hw_led_state &= ~IDLE_LED;
+		mistral_setled();
+		break;
+#endif
+
+#endif	/* CONFIG_FB_OMAP */
+
+	/* "green" == tps LED1 (leftmost, normally power-good)
+	 * works only with DC adapter, not on battery power!
+	 */
+	case led_green_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= GREEN_LED;
+		break;
+	case led_green_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~GREEN_LED;
+		break;
+
+	/* "amber" == tps LED2 (middle) */
+	case led_amber_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= AMBER_LED;
+		break;
+	case led_amber_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~AMBER_LED;
+		break;
+
+	/* "red" == LED on tps gpio3 (rightmost) */
+	case led_red_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= RED_LED;
+		break;
+	case led_red_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~RED_LED;
+		break;
+
+	default:
+		break;
+	}
+
+	leds ^= hw_led_state;
+	leds &= TPS_LEDS;
+	if (leds && (led_state & LED_STATE_CLAIMED)) {
+		tps_leds_change |= leds;
+		schedule_work(&work);
+	}
+
+done:
+	local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c
--- a/arch/arm/mach-omap/leds.c
+++ b/arch/arm/mach-omap/leds.c
@@ -9,6 +9,9 @@
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
 #include "leds.h"
 
 static int __init
@@ -17,8 +20,38 @@ omap_leds_init(void)
 	if (machine_is_omap_innovator())
 		leds_event = innovator_leds_event;
 
-	else if (machine_is_omap_h2() || machine_is_omap_perseus2()) {
+	else if (machine_is_omap_h2() || machine_is_omap_perseus2())
 		leds_event = h2p2_dbg_leds_event;
+
+	else if (machine_is_omap_osk())
+		leds_event = osk_leds_event;
+
+	else
+		return -1;
+
+	if (machine_is_omap_h2()
+			|| machine_is_omap_perseus2()
+			|| machine_is_omap_osk()) {
+
+		/* LED1/LED2 pins can be used as GPIO (as done here), or by
+		 * the LPG (works even in deep sleep!), to drive a bicolor
+		 * LED on the H2 sample board, and another on the H2/P2
+		 * "surfer" expansion board.
+		 *
+		 * The same pins drive a LED on the OSK Mistral board, but
+		 * that's a different kind of LED (just one color at a time).
+		 */
+		omap_cfg_reg(P18_1610_GPIO3);
+		if (omap_request_gpio(3) == 0)
+			omap_set_gpio_direction(3, 0);
+		else
+			printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
+
+		omap_cfg_reg(MPUIO4);
+		if (omap_request_gpio(OMAP_MPUIO(4)) == 0)
+			omap_set_gpio_direction(OMAP_MPUIO(4), 0);
+		else
+			printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
 	}
 
 	leds_event(led_start);
diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h
--- a/arch/arm/mach-omap/leds.h
+++ b/arch/arm/mach-omap/leds.h
@@ -1,2 +1,3 @@
 extern void innovator_leds_event(led_event_t evt);
 extern void h2p2_dbg_leds_event(led_event_t evt);
+extern void osk_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c
--- a/arch/arm/mach-omap/ocpi.c
+++ b/arch/arm/mach-omap/ocpi.c
@@ -1,11 +1,13 @@
 /*
  * linux/arch/arm/mach-omap/ocpi.c
  *
- * Minimal OCP bus support for OMAP-1610 and OMAP-5912
+ * Minimal OCP bus support for omap16xx
  *
- * Copyright (C) 2003 - 2004 Nokia Corporation
+ * Copyright (C) 2003 - 2005 Nokia Corporation
  * Written by Tony Lindgren <tony@atomide.com>
  *
+ * Modified for clock framework by Paul Mundt <paul.mundt@nokia.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
@@ -29,8 +31,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/err.h>
 
 #include <asm/io.h>
+#include <asm/hardware/clock.h>
 #include <asm/arch/hardware.h>
 
 #define OCPI_BASE		0xfffec320
@@ -42,13 +46,12 @@
 #define OCPI_PROT		(OCPI_BASE + 0x14)
 #define OCPI_SEC		(OCPI_BASE + 0x18)
 
-#define EN_OCPI_CK		(1 << 0)
-#define IDLOCPI_ARM		(1 << 1)
-
 /* USB OHCI OCPI access error registers */
 #define HOSTUEADDR	0xfffba0e0
 #define HOSTUESTATUS	0xfffba0e4
 
+static struct clk *ocpi_ck;
+
 /*
  * Enables device access to OMAP buses via the OCPI bridge
  * FIXME: Add locking
@@ -57,16 +60,12 @@ int ocpi_enable(void)
 {
 	unsigned int val;
 
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
 	/* Make sure there's clock for OCPI */
+	clk_enable(ocpi_ck);
 
-#if defined(CONFIG_ARCH_OMAP16XX)
-        if (cpu_is_omap1610() || cpu_is_omap1710()) {
-		val = omap_readl(OMAP16XX_ARM_IDLECT3);
-		val |= EN_OCPI_CK;
-		val &= ~IDLOCPI_ARM;
-		omap_writel(val, OMAP16XX_ARM_IDLECT3);
-        }
-#endif
 	/* Enable access for OHCI in OCPI */
 	val = omap_readl(OCPI_PROT);
 	val &= ~0xff;
@@ -81,19 +80,16 @@ int ocpi_enable(void)
 }
 EXPORT_SYMBOL(ocpi_enable);
 
-int ocpi_status(void)
+static int __init omap_ocpi_init(void)
 {
-	printk("OCPI: addr: 0x%08x cmd: 0x%08x\n"
-	       "      ohci-addr: 0x%08x ohci-status: 0x%08x\n",
-	       omap_readl(OCPI_FAULT), omap_readl(OCPI_CMD_FAULT),
-	       omap_readl(HOSTUEADDR), omap_readl(HOSTUESTATUS));
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
 
-	return 1;
-}
-EXPORT_SYMBOL(ocpi_status);
+	ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
+	if (IS_ERR(ocpi_ck))
+		return PTR_ERR(ocpi_ck);
 
-static int __init omap_ocpi_init(void)
-{
+	clk_use(ocpi_ck);
 	ocpi_enable();
 	printk("OMAP OCPI interconnect driver loaded\n");
 
@@ -102,7 +98,13 @@ static int __init omap_ocpi_init(void)
 
 static void __exit omap_ocpi_exit(void)
 {
-	/* FIXME: Disable OCPI */
+	/* REVISIT: Disable OCPI */
+
+	if (!cpu_is_omap16xx())
+		return;
+
+	clk_unuse(ocpi_ck);
+	clk_put(ocpi_ck);
 }
 
 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/mach-omap/pm.c
--- a/arch/arm/mach-omap/pm.c
+++ b/arch/arm/mach-omap/pm.c
@@ -45,6 +45,7 @@
 #include <asm/arch/omap16xx.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
 #include <asm/arch/tps65010.h>
 
 #include "clock.h"
diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c
--- a/arch/arm/mach-omap/time.c
+++ b/arch/arm/mach-omap/time.c
@@ -51,6 +51,8 @@
 
 struct sys_timer omap_timer;
 
+#ifdef CONFIG_OMAP_MPU_TIMER
+
 /*
  * ---------------------------------------------------------------------------
  * MPU timer
@@ -67,6 +69,36 @@ struct sys_timer omap_timer;
 #define MPU_TIMER_AR			(1 << 1)
 #define MPU_TIMER_ST			(1 << 0)
 
+/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
+ * converted to use kHz by Kevin Hilman */
+/* convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *		ns = cycles / (freq / ns_per_sec)
+ *		ns = cycles * (ns_per_sec / freq)
+ *		ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *		ns = cycles * (10^6 / cpu_khz)
+ *
+ *	Then we use scaling math (suggested by george at mvista.com) to get:
+ *		ns = cycles * (10^6 * SC / cpu_khz / SC
+ *		ns = cycles * cyc2ns_scale / SC
+ *
+ *	And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *			-johnstul at us.ibm.com "math is hard, lets go shopping!"
+ */
+static unsigned long cyc2ns_scale;
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_khz)
+{
+	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
+}
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
 /*
  * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
  * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
@@ -112,8 +144,10 @@ static inline void omap_mpu_timer_start(
 
 unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
 {
-	/* Round up to nearest usec */
-	return ((nr_ticks * 1000) / (MPU_TICKS_PER_SEC / 2 / 1000) + 1) >> 1;
+	unsigned long long nsec;
+
+	nsec = cycles_2_ns((unsigned long long)nr_ticks);
+	return (unsigned long)nsec / 1000;
 }
 
 /*
@@ -158,22 +192,190 @@ static struct irqaction omap_mpu_timer_i
 	.handler	= omap_mpu_timer_interrupt
 };
 
+static unsigned long omap_mpu_timer1_overflows;
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
+					     struct pt_regs *regs)
+{
+	omap_mpu_timer1_overflows++;
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer1_irq = {
+	.name		= "mpu timer1 overflow",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap_mpu_timer1_interrupt
+};
+
 static __init void omap_init_mpu_timer(void)
 {
+	set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
 	omap_timer.offset = omap_mpu_timer_gettimeoffset;
+	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
 	setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
 	omap_mpu_timer_start(0, 0xffffffff);
 	omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
 }
 
 /*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long ticks = 0 - omap_mpu_timer_read(0);
+	unsigned long long ticks64;
+
+	ticks64 = omap_mpu_timer1_overflows;
+	ticks64 <<= 32;
+	ticks64 |= ticks;
+
+	return cycles_2_ns(ticks64);
+}
+#endif	/* CONFIG_OMAP_MPU_TIMER */
+
+#ifdef CONFIG_OMAP_32K_TIMER
+
+#ifdef CONFIG_ARCH_OMAP1510
+#error OMAP 32KHz timer does not currently work on 1510!
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+#define OMAP_32K_TIMER_BASE		0xfffb9000
+#define OMAP_32K_TIMER_CR		0x08
+#define OMAP_32K_TIMER_TVR		0x00
+#define OMAP_32K_TIMER_TCR		0x04
+
+#define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 100, TVR = 327.68.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD	((32768 / HZ) - 1)
+#define MAX_SKIP_JIFFIES		25
+#define TIMER_32K_SYNCHRONIZED		0xfffbc410
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate)			\
+				(((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+	omap_writew(val, reg + OMAP_32K_TIMER_BASE);
+}
+
+static inline unsigned long omap_32k_timer_read(int reg)
+{
+	return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff;
+}
+
+/*
+ * The 32KHz synchronized timer is an additional timer on 16xx.
+ * It is always running.
+ */
+static inline unsigned long omap_32k_sync_timer_read(void)
+{
+	return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+	omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR);
+	omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR);
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+	omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR);
+}
+
+/*
+ * Rounds down to nearest usec
+ */
+static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
+{
+	return (ticks_32k * 5*5*5*5*5*5) >> 9;
+}
+
+static unsigned long omap_32k_last_tick = 0;
+
+/*
+ * Returns elapsed usecs since last 32k timer interrupt
+ */
+static unsigned long omap_32k_timer_gettimeoffset(void)
+{
+	unsigned long now = omap_32k_sync_timer_read();
+	return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
+}
+
+/*
+ * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
+ * function is also called from other interrupts to remove latency
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+					    struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned long now;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	now = omap_32k_sync_timer_read();
+
+	while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+		omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+		timer_tick(regs);
+	}
+
+	/* Restart timer so we don't drift off due to modulo or dynamic tick.
+	 * By default we program the next timer to be continuous to avoid
+	 * latencies during high system load. During dynamic tick operation the
+	 * continuous timer can be overridden from pm_idle to be longer.
+	 */
+	omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_32k_timer_irq = {
+	.name		= "32KHz timer",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap_32k_timer_interrupt
+};
+
+static __init void omap_init_32k_timer(void)
+{
+	setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+	omap_timer.offset  = omap_32k_timer_gettimeoffset;
+	omap_32k_last_tick = omap_32k_sync_timer_read();
+	omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+}
+#endif	/* CONFIG_OMAP_32K_TIMER */
+
+/*
  * ---------------------------------------------------------------------------
  * Timer initialization
  * ---------------------------------------------------------------------------
  */
 void __init omap_timer_init(void)
 {
+#if defined(CONFIG_OMAP_MPU_TIMER)
 	omap_init_mpu_timer();
+#elif defined(CONFIG_OMAP_32K_TIMER)
+	omap_init_32k_timer();
+#else
+#error No system timer selected in Kconfig!
+#endif
 }
 
 struct sys_timer omap_timer = {
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c
--- a/arch/arm/mach-omap/usb.c
+++ b/arch/arm/mach-omap/usb.c
@@ -49,10 +49,13 @@
 
 /* TESTED ON:
  *  - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ *  - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables
+ *  - 5912 OSK UDC, with *nonstandard* A-to-A cable
  *  - 1510 Innovator UDC with bundled usb0 cable
  *  - 1510 Innovator OHCI with bundled usb1/usb2 cable
  *  - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
  *  - 1710 custom development board using alternate pin group
+ *  - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables
  */
 
 /*-------------------------------------------------------------------------*/
@@ -101,50 +104,48 @@ static u32 __init omap_usb0_init(unsigne
 		return 0;
 	}
 
-	/*
-	 * VP and VM are needed for all active usb0 configurations.
-	 * USB0_VP and USB0_VM are always set on 1510, there's no muxing
-	 * available for them.
-	 */
-	if (nwires >= 2 && !cpu_is_omap15xx()) {
-		omap_cfg_reg(AA9_USB0_VP);
-		omap_cfg_reg(R9_USB0_VM);
-	}
 	if (is_device)
 		omap_cfg_reg(W4_USB_PUEN);
 
 	/* internal transceiver */
 	if (nwires == 2) {
+		// omap_cfg_reg(P9_USB_DP);
+		// omap_cfg_reg(R8_USB_DM);
+
 		if (cpu_is_omap15xx()) {
-			/* This works for OHCI on 1510-Innovator */
+			/* This works on 1510-Innovator */
 			return 0;
 		}
 
-		/* NOTE:  host OR device mode for now, no OTG */
+		/* NOTES:
+		 *  - peripheral should configure VBUS detection!
+		 *  - only peripherals may use the internal D+/D- pulldowns
+		 *  - OTG support on this port not yet written
+		 */
+
 		USB_TRANSCEIVER_CTRL_REG &= ~(7 << 4);
-		if (is_device) {
-			omap_cfg_reg(R18_1510_USB_GPIO0);
-			// omap_cfg_reg(USB0_VBUS);
-			// USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7
-		} else /* host mode needs D+ and D- pulldowns */
-			USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
+		if (!is_device)
+			USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
 
 		return 3 << 16;
 	}
 
 	/* alternate pin config, external transceiver */
+	if (cpu_is_omap15xx()) {
+		printk(KERN_ERR "no usb0 alt pin config on 15xx\n");
+		return 0;
+	}
+
 	omap_cfg_reg(V6_USB0_TXD);
 	omap_cfg_reg(W9_USB0_TXEN);
 	omap_cfg_reg(W5_USB0_SE0);
 
-#ifdef CONFIG_ARCH_OMAP_USB_SPEED
-	/* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */
-	omap_cfg_reg(V9_USB0_SPEED);
-	// omap_cfg_reg(V9_USB0_SUSP);
-#endif
+	/* NOTE:  SPEED and SUSP aren't configured here */
 
 	if (nwires != 3)
 		omap_cfg_reg(Y5_USB0_RCV);
+	if (nwires != 6)
+		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
 	switch (nwires) {
 	case 3:
@@ -155,7 +156,8 @@ static u32 __init omap_usb0_init(unsigne
 		break;
 	case 6:
 		syscon1 = 3;
-		/* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */
+		omap_cfg_reg(AA9_USB0_VP);
+		omap_cfg_reg(R9_USB0_VM);
 		USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
 		break;
 	default:
@@ -181,10 +183,13 @@ static u32 __init omap_usb1_init(unsigne
 		omap_cfg_reg(USB1_SEO);
 		omap_cfg_reg(USB1_SPEED);
 		// SUSP
-	} else if (cpu_is_omap16xx()) {
+	} else if (cpu_is_omap1610() || cpu_is_omap5912()) {
 		omap_cfg_reg(W13_1610_USB1_SE0);
 		omap_cfg_reg(R13_1610_USB1_SPEED);
 		// SUSP
+	} else if (cpu_is_omap1710()) {
+		omap_cfg_reg(R13_1710_USB1_SE0);
+		// SUSP
 	} else {
 		pr_debug("usb unrecognized\n");
 	}
@@ -216,12 +221,11 @@ static u32 __init omap_usb2_init(unsigne
 {
 	u32	syscon1 = 0;
 
+	/* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
 	if (alt_pingroup || nwires == 0)
 		return 0;
 	if (nwires != 6 && !cpu_is_omap15xx())
 		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
-	if (nwires == 0)
-		return 0;
 
 	/* external transceiver */
 	if (cpu_is_omap15xx()) {
@@ -322,8 +326,8 @@ static u64 ohci_dmamask = ~(u32)0;
 
 static struct resource ohci_resources[] = {
 	{
-		.start	= IO_ADDRESS(OMAP_OHCI_BASE),
-		.end	= IO_ADDRESS(OMAP_OHCI_BASE + 4096),
+		.start	= OMAP_OHCI_BASE,
+		.end	= OMAP_OHCI_BASE + 4096,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -374,6 +378,10 @@ static struct platform_device otg_device
 
 /*-------------------------------------------------------------------------*/
 
+#define ULPD_CLOCK_CTRL_REG	__REG16(ULPD_CLOCK_CTRL)
+#define ULPD_SOFT_REQ_REG	__REG16(ULPD_SOFT_REQ)
+
+
 // FIXME correct answer depends on hmc_mode,
 // as does any nonzero value for config->otg port number
 #ifdef	CONFIG_USB_GADGET_OMAP
@@ -412,12 +420,11 @@ omap_otg_init(struct omap_usb_config *co
 
 	syscon = config->hmc_mode;
 	syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
-	if (config->otg || config->register_host)
-		syscon |= UHOST_EN;
 #ifdef	CONFIG_USB_OTG
 	if (config->otg)
 		syscon |= OTG_EN;
 #endif
+	pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
 	pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
 	OTG_SYSCON_2_REG = syscon;
 
@@ -435,7 +442,10 @@ omap_otg_init(struct omap_usb_config *co
 		printk(", Mini-AB on usb%d", config->otg - 1);
 	printk("\n");
 
-	/* don't clock unused USB controllers  */
+	/* leave USB clocks/controllers off until needed */
+	ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+	ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+	ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
 	syscon = OTG_SYSCON_1_REG;
 	syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
 
@@ -443,6 +453,7 @@ omap_otg_init(struct omap_usb_config *co
 	if (config->otg || config->register_dev) {
 		syscon &= ~DEV_IDLE_EN;
 		udc_device.dev.platform_data = config;
+		/* FIXME patch IRQ numbers for omap730 */
 		status = platform_device_register(&udc_device);
 		if (status)
 			pr_debug("can't register UDC device, %d\n", status);
@@ -453,6 +464,8 @@ omap_otg_init(struct omap_usb_config *co
 	if (config->otg || config->register_host) {
 		syscon &= ~HST_IDLE_EN;
 		ohci_device.dev.platform_data = config;
+		if (cpu_is_omap730())
+			ohci_resources[1].start = INT_730_USB_HHC_1;
 		status = platform_device_register(&ohci_device);
 		if (status)
 			pr_debug("can't register OHCI device, %d\n", status);
@@ -462,10 +475,12 @@ omap_otg_init(struct omap_usb_config *co
 #ifdef	CONFIG_USB_OTG
 	if (config->otg) {
 		syscon &= ~OTG_IDLE_EN;
+		otg_device.dev.platform_data = config;
 		if (cpu_is_omap730())
 			otg_resources[1].start = INT_730_USB_OTG;
 		status = platform_device_register(&otg_device);
-		// ...
+		if (status)
+			pr_debug("can't register OTG device, %d\n", status);
 	}
 #endif
 	pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
@@ -482,10 +497,6 @@ static inline void omap_otg_init(struct 
 
 #ifdef	CONFIG_ARCH_OMAP1510
 
-#define ULPD_SOFT_REQ_REG	__REG16(ULPD_SOFT_REQ)
-#define SOFT_UDC_REQ		(1 << 4)
-#define SOFT_DPLL_REQ		(1 << 0)
-
 #define ULPD_DPLL_CTRL_REG	__REG16(ULPD_DPLL_CTRL)
 #define DPLL_IOB		(1 << 13)
 #define DPLL_PLL_ENABLE		(1 << 4)
@@ -546,7 +557,6 @@ static void __init omap_1510_usb_init(st
 		/* hcd explicitly gates 48MHz */
 	}
 #endif
-
 }
 
 #else
@@ -564,7 +574,8 @@ omap_usb_init(void)
 
 	config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config);
 	if (config == NULL) {
-		printk(KERN_ERR "USB: No board-specific platform config found\n");
+		printk(KERN_ERR "USB: No board-specific "
+				"platform config found\n");
 		return -ENODEV;
 	}
 	platform_data = *config;
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -8,6 +8,7 @@ choice
 config ARCH_LUBBOCK
 	bool "Intel DBPXA250 Development Platform"
 	select PXA25x
+	select SA1111
 
 config MACH_MAINSTONE
 	bool "Intel HCDDBBVA0 Development Platform"
@@ -19,28 +20,39 @@ config ARCH_PXA_IDP
 	select PXA25x
 
 config PXA_SHARPSL
-	bool "SHARP SL-C7xx Models (Corgi, Shepherd and Husky)"
+	bool "SHARP SL-5600 and SL-C7xx Models"
 	select PXA25x
+	select SHARP_SCOOP
+	select SHARP_PARAM
 	help
 	  Say Y here if you intend to run this kernel on a
-	  Sharp SL-C700 (Corgi), SL-C750 (Shepherd) or a
-	  Sharp SL-C760 (Husky) handheld computer.
+	  Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi),
+	  SL-C750 (Shepherd) or a Sharp SL-C760 (Husky)
+	  handheld computer.
 
 endchoice
 
 endmenu
 
+config MACH_POODLE
+	bool "Enable Sharp SL-5600 (Poodle) Support"
+	depends PXA_SHARPSL
+	select SHARP_LOCOMO
+
 config MACH_CORGI
 	bool "Enable Sharp SL-C700 (Corgi) Support"
 	depends PXA_SHARPSL
+	select PXA_SHARP_C7xx
 
 config MACH_SHEPHERD
 	bool "Enable Sharp SL-C750 (Shepherd) Support"
 	depends PXA_SHARPSL
+	select PXA_SHARP_C7xx
 
 config MACH_HUSKY
 	bool "Enable Sharp SL-C760 (Husky) Support"
 	depends PXA_SHARPSL
+	select PXA_SHARP_C7xx
 
 config PXA25x
 	bool
@@ -57,4 +69,9 @@ config IWMMXT
 	help
 	  Enable support for iWMMXt
 
+config PXA_SHARP_C7xx
+	bool
+	help
+	  Enable support for all Sharp C7xx models
+
 endif
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -11,7 +11,8 @@ obj-$(CONFIG_PXA27x) += pxa27x.o
 obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARPSL)	+= corgi.o corgi_ssp.o ssp.o
+obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o ssp.o
+obj-$(CONFIG_MACH_POODLE)	+= poodle.o
 
 # Support for blinky lights
 led-y := leds.o
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -37,6 +37,7 @@
 #include <asm/arch/udc.h>
 #include <asm/arch/corgi.h>
 
+#include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/scoop.h>
 #include <video/w100fb.h>
 
@@ -59,7 +60,7 @@ static struct scoop_config corgi_scoop_s
 	.io_out		= CORGI_SCOOP_IO_OUT,
 };
 
-static struct platform_device corgiscoop_device = {
+struct platform_device corgiscoop_device = {
 	.name		= "sharp-scoop",
 	.id		= -1,
 	.dev		= {
@@ -231,28 +232,10 @@ static struct platform_device *devices[]
 	&corgibl_device,
 };
 
-static struct sharpsl_flash_param_info sharpsl_flash_param;
-
-static void corgi_get_param(void)
-{
-	sharpsl_flash_param.comadj_keyword = readl(FLASH_MEM_BASE + FLASH_COMADJ_MAGIC_ADR);
-	sharpsl_flash_param.comadj = readl(FLASH_MEM_BASE + FLASH_COMADJ_DATA_ADR);
-
-	sharpsl_flash_param.phad_keyword = readl(FLASH_MEM_BASE + FLASH_PHAD_MAGIC_ADR);
-	sharpsl_flash_param.phadadj = readl(FLASH_MEM_BASE + FLASH_PHAD_DATA_ADR);
-}
-
 static void __init corgi_init(void)
 {
-	if (sharpsl_flash_param.comadj_keyword == FLASH_COMADJ_MAJIC)
-		corgi_fb_info.comadj=sharpsl_flash_param.comadj;
-	else
-		corgi_fb_info.comadj=-1;
-
-	if (sharpsl_flash_param.phad_keyword == FLASH_PHAD_MAJIC)
-		corgi_fb_info.phadadj=sharpsl_flash_param.phadadj;
-	else
-		corgi_fb_info.phadadj=-1;
+	corgi_fb_info.comadj=sharpsl_param.comadj;
+	corgi_fb_info.phadadj=sharpsl_param.phadadj;
 
 	pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
  	pxa_set_udc_info(&udc_info);
@@ -264,7 +247,7 @@ static void __init corgi_init(void)
 static void __init fixup_corgi(struct machine_desc *desc,
 		struct tag *tags, char **cmdline, struct meminfo *mi)
 {
-	corgi_get_param();
+	sharpsl_save_param();
 	mi->nr_banks=1;
 	mi->bank[0].start = 0xa0000000;
 	mi->bank[0].node = 0;
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
--- a/arch/arm/mach-pxa/corgi_ssp.c
+++ b/arch/arm/mach-pxa/corgi_ssp.c
@@ -210,7 +210,7 @@ static int corgi_ssp_remove(struct devic
 	return 0;
 }
 
-static int corgi_ssp_suspend(struct device *dev, u32 state, u32 level)
+static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_POWER_DOWN) {
 		ssp_flush(&corgi_ssp_dev);
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -220,6 +220,30 @@ static struct platform_device stuart_dev
 	.id		= 2,
 };
 
+static struct resource i2c_resources[] = {
+	{
+		.start	= 0x40301680,
+		.end	= 0x403016a3,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_I2C,
+		.end	= IRQ_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_device = {
+	.name		= "pxa2xx-i2c",
+	.id		= 0,
+	.resource	= i2c_resources,
+	.num_resources	= ARRAY_SIZE(i2c_resources),
+};
+
+void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
+{
+	i2c_device.dev.platform_data = info;
+}
+
 static struct platform_device *devices[] __initdata = {
 	&pxamci_device,
 	&udc_device,
@@ -227,6 +251,7 @@ static struct platform_device *devices[]
 	&ffuart_device,
 	&btuart_device,
 	&stuart_device,
+	&i2c_device,
 };
 
 static int __init pxa_init(void)
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -10,13 +10,16 @@
  *  2001-09-13: Cliff Brake <cbrake@accelent.com>
  *              Initial code
  *
- * Expected command line: mem=32M initrd=0xa1000000,4M root=/dev/ram ramdisk=8192
+ *  2005-02-15: Cliff Brake <cliff.brake@gmail.com>
+ *  		<http://www.vibren.com> <http://bec-systems.com>
+ *              Updated for 2.6 kernel
+ *
  */
-#include <linux/kernel.h>
+
 #include <linux/init.h>
-#include <linux/major.h>
-#include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/fb.h>
 
 #include <asm/setup.h>
 #include <asm/memory.h>
@@ -29,68 +32,133 @@
 
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/idp.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/mmc.h>
 
 #include "generic.h"
 
-#ifndef PXA_IDP_REV02
-/* shadow registers for write only registers */
-unsigned int idp_cpld_led_control_shadow = 0x1;
-unsigned int idp_cpld_periph_pwr_shadow = 0xd;
-unsigned int ipd_cpld_cir_shadow = 0;
-unsigned int idp_cpld_kb_col_high_shadow = 0;
-unsigned int idp_cpld_kb_col_low_shadow = 0;
-unsigned int idp_cpld_pccard_en_shadow = 0xC3;
-unsigned int idp_cpld_gpioh_dir_shadow = 0;
-unsigned int idp_cpld_gpioh_value_shadow = 0;
-unsigned int idp_cpld_gpiol_dir_shadow = 0;
-unsigned int idp_cpld_gpiol_value_shadow = 0;
-
-/*
- * enable all LCD signals -- they should still be on
- * write protect flash
- * enable all serial port transceivers
+/* TODO:
+ * - add pxa2xx_audio_ops_t device structure
+ * - Ethernet interrupt
  */
 
-unsigned int idp_control_port_shadow = ((0x7 << 21) | 		/* LCD power */
-					(0x1 << 19) |		/* disable flash write enable */
-					(0x7 << 9));		/* enable serial port transeivers */
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= (IDP_ETH_PHYS + 0x300),
+		.end	= (IDP_ETH_PHYS + 0xfffff),
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_GPIO(4),
+		.end	= IRQ_GPIO(4),
+		.flags	= IORESOURCE_IRQ,
+	}
+};
 
-#endif
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static void idp_backlight_power(int on)
+{
+	if (on) {
+		IDP_CPLD_LCD |= (1<<1);
+	} else {
+		IDP_CPLD_LCD &= ~(1<<1);
+	}
+}
+
+static void idp_vlcd(int on)
+{
+	if (on) {
+		IDP_CPLD_LCD |= (1<<2);
+	} else {
+		IDP_CPLD_LCD &= ~(1<<2);
+	}
+}
+
+static void idp_lcd_power(int on)
+{
+	if (on) {
+		IDP_CPLD_LCD |= (1<<0);
+	} else {
+		IDP_CPLD_LCD &= ~(1<<0);
+	}
+
+	/* call idp_vlcd for now as core driver does not support
+	 * both power and vlcd hooks.  Note, this is not technically
+	 * the correct sequence, but seems to work.  Disclaimer:
+	 * this may eventually damage the display.
+	 */
+
+	idp_vlcd(on);
+}
+
+static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+	.pixclock	= 270000,
+	.xres		= 640,
+	.yres		= 480,
+	.bpp		= 16,
+	.hsync_len	= 1,
+	.left_margin	= 3,
+	.right_margin	= 3,
+	.vsync_len	= 1,
+	.upper_margin	= 0,
+	.lower_margin	= 0,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 0,
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+	.lccr0		= LCCR0_SDS,
+	.lccr3		= LCCR3_PCP | LCCR3_Acb(255),
+	.pxafb_backlight_power = &idp_backlight_power,
+	.pxafb_lcd_power = &idp_lcd_power
+};
+
+static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+	/* setup GPIO for PXA25x MMC controller	*/
+	pxa_gpio_mode(GPIO6_MMCCLK_MD);
+	pxa_gpio_mode(GPIO8_MMCCS0_MD);
+
+	return 0;
+}
+
+static struct pxamci_platform_data idp_mci_platform_data = {
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.init 		= idp_mci_init,
+};
 
 static void __init idp_init(void)
 {
 	printk("idp_init()\n");
+
+	platform_device_register(&smc91x_device);
+	//platform_device_register(&mst_audio_device);
+	set_pxa_fb_info(&sharp_lm8v31);
+	pxa_set_mci_info(&idp_mci_platform_data);
 }
 
 static void __init idp_init_irq(void)
 {
+
 	pxa_init_irq();
+
+	set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
 }
 
 static struct map_desc idp_io_desc[] __initdata = {
  /* virtual     physical    length      type */
 
-
-#ifndef PXA_IDP_REV02
-  { IDP_CTRL_PORT_BASE,
-    IDP_CTRL_PORT_PHYS,
-    IDP_CTRL_PORT_SIZE,
-    MT_DEVICE },
-#endif
-
-  { IDP_IDE_BASE,
-    IDP_IDE_PHYS,
-    IDP_IDE_SIZE,
-    MT_DEVICE },
-  { IDP_ETH_BASE,
-    IDP_ETH_PHYS,
-    IDP_ETH_SIZE,
-    MT_DEVICE },
-  { IDP_COREVOLT_BASE,
+  { IDP_COREVOLT_VIRT,
     IDP_COREVOLT_PHYS,
     IDP_COREVOLT_SIZE,
     MT_DEVICE },
-  { IDP_CPLD_BASE,
+  { IDP_CPLD_VIRT,
     IDP_CPLD_PHYS,
     IDP_CPLD_SIZE,
     MT_DEVICE }
@@ -101,8 +169,6 @@ static void __init idp_map_io(void)
 	pxa_map_io();
 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 
-	set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
-
 	// serial ports 2 & 3
 	pxa_gpio_mode(GPIO42_BTRXD_MD);
 	pxa_gpio_mode(GPIO43_BTTXD_MD);
@@ -114,8 +180,8 @@ static void __init idp_map_io(void)
 }
 
 
-MACHINE_START(PXA_IDP, "Accelent Xscale IDP")
-	MAINTAINER("Accelent Systems Inc.")
+MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
+	MAINTAINER("Vibren Technologies")
 	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
 	MAPIO(idp_map_io)
 	INITIRQ(idp_init_irq)
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -97,23 +97,23 @@ static int pxa_gpio_irq_type(unsigned in
 		type = __IRQT_RISEDGE | __IRQT_FALEDGE;
 	}
 
-	printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio);
+	/* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */
 
 	pxa_gpio_mode(gpio | GPIO_IN);
 
 	if (type & __IRQT_RISEDGE) {
-		printk("rising ");
+		/* printk("rising "); */
 		__set_bit (gpio, GPIO_IRQ_rising_edge);
 	} else
 		__clear_bit (gpio, GPIO_IRQ_rising_edge);
 
 	if (type & __IRQT_FALEDGE) {
-		printk("falling ");
+		/* printk("falling "); */
 		__set_bit (gpio, GPIO_IRQ_falling_edge);
 	} else
 		__clear_bit (gpio, GPIO_IRQ_falling_edge);
 
-	printk("edges\n");
+	/* printk("edges\n"); */
 
 	GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
 	GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
--- a/arch/arm/mach-pxa/leds-idp.c
+++ b/arch/arm/mach-pxa/leds-idp.c
@@ -19,6 +19,7 @@
 #include <asm/leds.h>
 #include <asm/system.h>
 
+#include <asm/arch/pxa-regs.h>
 #include <asm/arch/idp.h>
 
 #include "leds.h"
@@ -65,12 +66,12 @@ void idp_leds_event(led_event_t evt)
 #ifdef CONFIG_LEDS_CPU
 	case led_idle_start:
 		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= IDP_BUSY_LED;
+			hw_led_state &= ~IDP_BUSY_LED;
 		break;
 
 	case led_idle_end:
 		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~IDP_BUSY_LED;
+			hw_led_state |= IDP_BUSY_LED;
 		break;
 #endif
 
@@ -79,12 +80,12 @@ void idp_leds_event(led_event_t evt)
 
 	case led_green_on:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_HB_LED;
+			hw_led_state |= IDP_HB_LED;
 		break;
 
 	case led_green_off:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_HB_LED;
+			hw_led_state &= ~IDP_HB_LED;
 		break;
 
 	case led_amber_on:
@@ -95,12 +96,12 @@ void idp_leds_event(led_event_t evt)
 
 	case led_red_on:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_BUSY_LED;
+			hw_led_state |= IDP_BUSY_LED;
 		break;
 
 	case led_red_off:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_BUSY_LED;
+			hw_led_state &= ~IDP_BUSY_LED;
 		break;
 
 	default:
@@ -108,7 +109,9 @@ void idp_leds_event(led_event_t evt)
 	}
 
 	if  (led_state & LED_STATE_ENABLED)
-		IDP_WRITE_LEDS(hw_led_state);
+		IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state);
+	else
+		IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK;
 
 	local_irq_restore(flags);
 }
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/major.h>
 #include <linux/fb.h>
 #include <linux/interrupt.h>
@@ -106,6 +107,35 @@ static void __init lubbock_init_irq(void
 	set_irq_type(IRQ_GPIO(0), IRQT_FALLING);
 }
 
+#ifdef CONFIG_PM
+
+static int lubbock_irq_resume(struct sys_device *dev)
+{
+	LUB_IRQ_MASK_EN = lubbock_irq_enabled;
+	return 0;
+}
+
+static struct sysdev_class lubbock_irq_sysclass = {
+	set_kset_name("cpld_irq"),
+	.resume = lubbock_irq_resume,
+};
+
+static struct sys_device lubbock_irq_device = {
+	.cls = &lubbock_irq_sysclass,
+};
+
+static int __init lubbock_irq_device_init(void)
+{
+	int ret = sysdev_class_register(&lubbock_irq_sysclass);
+	if (ret == 0)
+		ret = sysdev_register(&lubbock_irq_device);
+	return ret;
+}
+
+device_initcall(lubbock_irq_device_init);
+
+#endif
+
 static int lubbock_udc_is_connected(void)
 {
 	return (LUB_MISC_RD & (1 << 9)) == 0;
@@ -138,6 +168,7 @@ static struct platform_device sa1111_dev
 
 static struct resource smc91x_resources[] = {
 	[0] = {
+		.name	= "smc91x-regs",
 		.start	= 0x0c000000,
 		.end	= 0x0c0fffff,
 		.flags	= IORESOURCE_MEM,
@@ -148,6 +179,7 @@ static struct resource smc91x_resources[
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= "smc91x-attrib",
 		.start	= 0x0e000000,
 		.end	= 0x0e0fffff,
 		.flags	= IORESOURCE_MEM,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -15,6 +15,7 @@
 
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
@@ -62,7 +63,6 @@ static struct irqchip mainstone_irq_chip
 	.unmask		= mainstone_unmask_irq,
 };
 
-
 static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
 				  struct pt_regs *regs)
 {
@@ -100,6 +100,35 @@ static void __init mainstone_init_irq(vo
 	set_irq_type(IRQ_GPIO(0), IRQT_FALLING);
 }
 
+#ifdef CONFIG_PM
+
+static int mainstone_irq_resume(struct sys_device *dev)
+{
+	MST_INTMSKENA = mainstone_irq_enabled;
+	return 0;
+}
+
+static struct sysdev_class mainstone_irq_sysclass = {
+	set_kset_name("cpld_irq"),
+	.resume = mainstone_irq_resume,
+};
+
+static struct sys_device mainstone_irq_device = {
+	.cls = &mainstone_irq_sysclass,
+};
+
+static int __init mainstone_irq_device_init(void)
+{
+	int ret = sysdev_class_register(&mainstone_irq_sysclass);
+	if (ret == 0)
+		ret = sysdev_register(&mainstone_irq_device);
+	return ret;
+}
+
+device_initcall(mainstone_irq_device_init);
+
+#endif
+
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -295,6 +324,24 @@ static void __init mainstone_map_io(void
 {
 	pxa_map_io();
 	iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc));
+
+	/* initialize sleep mode regs (wake-up sources, etc) */
+	PGSR0 = 0x00008800;
+	PGSR1 = 0x00000002;
+	PGSR2 = 0x0001FC00;
+	PGSR3 = 0x00001F81;
+	PWER  = 0xC0000002;
+	PRER  = 0x00000002;
+	PFER  = 0x00000002;
+ 	/*	for use I SRAM as framebuffer.	*/
+ 	PSLR |= 0xF04;
+ 	PCFR = 0x66;
+ 	/*	For Keypad wakeup.	*/
+ 	KPC &=~KPC_ASACT;
+ 	KPC |=KPC_AS;
+ 	PKWR  = 0x000FD000;
+ 	/*	Need read PKWR back after set it.	*/
+ 	PKWR;
 }
 
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -29,9 +29,6 @@
  */
 #undef DEBUG
 
-extern void pxa_cpu_suspend(void);
-extern void pxa_cpu_resume(void);
-
 #define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
 
@@ -47,16 +44,28 @@ extern void pxa_cpu_resume(void);
  */
 enum {	SLEEP_SAVE_START = 0,
 
-	SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
-	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
-	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
-	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
-	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
-	SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
+	SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
+	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
+	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
+	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
+	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
+
+	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+	SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
+
+	SLEEP_SAVE_PSTR,
 
 	SLEEP_SAVE_ICMR,
 	SLEEP_SAVE_CKEN,
 
+#ifdef CONFIG_PXA27x
+ 	SLEEP_SAVE_MDREFR,
+ 	SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
+ 	SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
+#endif
+
 	SLEEP_SAVE_CKSUM,
 
 	SLEEP_SAVE_SIZE
@@ -69,9 +78,12 @@ static int pxa_pm_enter(suspend_state_t 
 	unsigned long checksum = 0;
 	struct timespec delta, rtc;
 	int i;
+	extern void pxa_cpu_pm_enter(suspend_state_t state);
 
-	if (state != PM_SUSPEND_MEM)
-		return -EINVAL;
+#ifdef CONFIG_IWMMXT
+	/* force any iWMMXt context to ram **/
+	iwmmxt_task_disable(NULL);
+#endif
 
 	/* preserve current time */
 	rtc.tv_sec = RCNR;
@@ -82,34 +94,44 @@ static int pxa_pm_enter(suspend_state_t 
 	SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
 	SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
 	SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
+	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
+
 	SAVE(GAFR0_L); SAVE(GAFR0_U);
 	SAVE(GAFR1_L); SAVE(GAFR1_U);
 	SAVE(GAFR2_L); SAVE(GAFR2_U);
 
+#ifdef CONFIG_PXA27x
+	SAVE(MDREFR);
+	SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3);
+	SAVE(GAFR3_L); SAVE(GAFR3_U);
+	SAVE(PWER); SAVE(PCFR); SAVE(PRER);
+	SAVE(PFER); SAVE(PKWR);
+#endif
+
 	SAVE(ICMR);
 	ICMR = 0;
 
 	SAVE(CKEN);
-	CKEN = 0;
+	SAVE(PSTR);
 
 	/* Note: wake up source are set up in each machine specific files */
 
 	/* clear GPIO transition detect  bits */
 	GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
+#ifdef CONFIG_PXA27x
+	GEDR3 = GEDR3;
+#endif
 
 	/* Clear sleep reset status */
 	RCSR = RCSR_SMR;
 
-	/* set resume return address */
-	PSPR = virt_to_phys(pxa_cpu_resume);
-
 	/* before sleeping, calculate and save a checksum */
 	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
 		checksum += sleep_save[i];
 	sleep_save[SLEEP_SAVE_CKSUM] = checksum;
 
 	/* *** go zzz *** */
-	pxa_cpu_suspend();
+	pxa_cpu_pm_enter(state);
 
 	/* after sleeping, validate the checksum */
 	checksum = 0;
@@ -121,7 +143,8 @@ static int pxa_pm_enter(suspend_state_t 
 #ifdef CONFIG_ARCH_LUBBOCK
 		LUB_HEXLED = 0xbadbadc5;
 #endif
-		while (1);
+		while (1)
+			pxa_cpu_pm_enter(state);
 	}
 
 	/* ensure not to come back here if it wasn't intended */
@@ -135,6 +158,15 @@ static int pxa_pm_enter(suspend_state_t 
 	RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
 	RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
 	RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
+	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
+
+#ifdef CONFIG_PXA27x
+	RESTORE(MDREFR);
+	RESTORE(GAFR3_L); RESTORE(GAFR3_U); RESTORE_GPLEVEL(3);
+	RESTORE(GPDR3); RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3);
+	RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
+	RESTORE(PFER); RESTORE(PKWR);
+#endif
 
 	PSSR = PSSR_RDH | PSSR_PH;
 
@@ -144,6 +176,8 @@ static int pxa_pm_enter(suspend_state_t 
 	ICCR = 1;
 	RESTORE(ICMR);
 
+	RESTORE(PSTR);
+
 	/* restore current time */
 	rtc.tv_sec = RCNR;
 	restore_time_delta(&delta, &rtc);
@@ -165,7 +199,9 @@ unsigned long sleep_phys_sp(void *sp)
  */
 static int pxa_pm_prepare(suspend_state_t state)
 {
-	return 0;
+	extern int pxa_cpu_pm_prepare(suspend_state_t state);
+
+	return pxa_cpu_pm_prepare(state);
 }
 
 /*
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-pxa/poodle.c
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-pxa/poodle.c
+ *
+ *  Support for the SHARP Poodle Board.
+ *
+ * Based on:
+ *  linux/arch/arm/mach-pxa/lubbock.c Author:	Nicolas Pitre
+ *
+ *  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.
+ *
+ * Change Log
+ *  12-Dec-2002 Sharp Corporation for Poodle
+ *  John Lenz <lenz@cs.wisc.edu> updates to 2.6
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/poodle.h>
+#include <asm/arch/pxafb.h>
+
+#include <asm/hardware/scoop.h>
+#include <asm/hardware/locomo.h>
+#include <asm/mach/sharpsl_param.h>
+
+#include "generic.h"
+
+static struct resource poodle_scoop_resources[] = {
+	[0] = {
+		.start		= 0x10800000,
+		.end		= 0x10800fff,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct scoop_config poodle_scoop_setup = {
+	.io_dir		= POODLE_SCOOP_IO_DIR,
+	.io_out		= POODLE_SCOOP_IO_OUT,
+};
+
+struct platform_device poodle_scoop_device = {
+	.name		= "sharp-scoop",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &poodle_scoop_setup,
+	},
+	.num_resources	= ARRAY_SIZE(poodle_scoop_resources),
+	.resource	= poodle_scoop_resources,
+};
+
+
+/* LoCoMo device */
+static struct resource locomo_resources[] = {
+	[0] = {
+		.start		= 0x10000000,
+		.end		= 0x10001fff,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= IRQ_GPIO(10),
+		.end		= IRQ_GPIO(10),
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device locomo_device = {
+	.name		= "locomo",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(locomo_resources),
+	.resource	= locomo_resources,
+};
+
+/* PXAFB device */
+static struct pxafb_mach_info poodle_fb_info __initdata = {
+	.pixclock	= 144700,
+
+	.xres		= 320,
+	.yres		= 240,
+	.bpp		= 16,
+
+	.hsync_len	= 7,
+	.left_margin	= 11,
+	.right_margin	= 30,
+
+	.vsync_len	= 2,
+	.upper_margin	= 2,
+	.lower_margin	= 0,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
+	.lccr3		= 0,
+
+	.pxafb_backlight_power	= NULL,
+	.pxafb_lcd_power	= NULL,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&locomo_device,
+	&poodle_scoop_device,
+};
+
+static void __init poodle_init(void)
+{
+	int ret = 0;
+
+	/* cpu initialize */
+	/* Pgsr Register */
+  	PGSR0 = 0x0146dd80;
+  	PGSR1 = 0x03bf0890;
+  	PGSR2 = 0x0001c000;
+
+	/* Alternate Register */
+  	GAFR0_L = 0x01001000;
+  	GAFR0_U = 0x591a8010;
+  	GAFR1_L = 0x900a8451;
+  	GAFR1_U = 0xaaa5aaaa;
+  	GAFR2_L = 0x8aaaaaaa;
+  	GAFR2_U = 0x00000002;
+
+	/* Direction Register */
+  	GPDR0 = 0xd3f0904c;
+  	GPDR1 = 0xfcffb7d3;
+  	GPDR2 = 0x0001ffff;
+
+	/* Output Register */
+  	GPCR0 = 0x00000000;
+  	GPCR1 = 0x00000000;
+  	GPCR2 = 0x00000000;
+
+  	GPSR0 = 0x00400000;
+  	GPSR1 = 0x00000000;
+        GPSR2 = 0x00000000;
+
+	set_pxa_fb_info(&poodle_fb_info);
+
+	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+	if (ret) {
+		printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n");
+	}
+}
+
+static void __init fixup_poodle(struct machine_desc *desc,
+		struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+	sharpsl_save_param();
+}
+
+static struct map_desc poodle_io_desc[] __initdata = {
+ /* virtual     physical    length                   */
+  { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */
+};
+
+static void __init poodle_map_io(void)
+{
+	pxa_map_io();
+	iotable_init(poodle_io_desc, ARRAY_SIZE(poodle_io_desc));
+
+	/* setup sleep mode values */
+	PWER  = 0x00000002;
+	PFER  = 0x00000000;
+	PRER  = 0x00000002;
+	PGSR0 = 0x00008000;
+	PGSR1 = 0x003F0202;
+	PGSR2 = 0x0001C000;
+	PCFR |= PCFR_OPDE;
+}
+
+MACHINE_START(POODLE, "SHARP Poodle")
+	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+	FIXUP(fixup_poodle)
+	MAPIO(poodle_map_io)
+	INITIRQ(pxa_init_irq)
+	.timer = &pxa_timer,
+	.init_machine = poodle_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -16,6 +16,7 @@
  * initialization stuff for PXA machines which can be overridden later if
  * need be.
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -102,3 +103,35 @@ unsigned int get_lcdclk_frequency_10khz(
 }
 
 EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
+
+#ifdef CONFIG_PM
+
+int pxa_cpu_pm_prepare(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void pxa_cpu_pm_enter(suspend_state_t state)
+{
+	extern void pxa_cpu_suspend(unsigned int);
+	extern void pxa_cpu_resume(void);
+
+	CKEN = 0;
+
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		/* set resume return address */
+		PSPR = virt_to_phys(pxa_cpu_resume);
+		pxa_cpu_suspend(3);
+		break;
+	}
+}
+
+#endif
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -120,6 +120,42 @@ EXPORT_SYMBOL(get_clk_frequency_khz);
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
 
+#ifdef CONFIG_PM
+
+int pxa_cpu_pm_prepare(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+void pxa_cpu_pm_enter(suspend_state_t state)
+{
+	extern void pxa_cpu_standby(void);
+	extern void pxa_cpu_suspend(unsigned int);
+	extern void pxa_cpu_resume(void);
+
+	CKEN = CKEN22_MEMC | CKEN9_OSTIMER;
+
+	/* ensure voltage-change sequencer not initiated, which hangs */
+	PCFR &= ~PCFR_FVC;
+
+	/* Clear edge-detect status register. */
+	PEDR = 0xDF12FE1B;
+
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		/* set resume return address */
+		PSPR = virt_to_phys(pxa_cpu_resume);
+		pxa_cpu_suspend(3);
+		break;
+	}
+}
+
+#endif
 
 /*
  * device registration specific to PXA27x.
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -18,6 +18,11 @@
 
 #include <asm/arch/pxa-regs.h>
 
+#ifdef CONFIG_PXA27x			// workaround for Errata 50
+#define MDREFR_KDIV	0x200a4000	// all banks
+#define CCCR_SLEEP	0x00000107	// L=7 2N=2 A=0 PPDIS=0 CPDIS=0
+#endif
+
 		.text
 
 /*
@@ -28,10 +33,13 @@
 
 ENTRY(pxa_cpu_suspend)
 
+#ifndef CONFIG_IWMMXT
 	mra	r2, r3, acc0
+#endif
 	stmfd	sp!, {r2 - r12, lr}		@ save registers on stack
 
 	@ get coprocessor registers
+	mrc	p14, 0, r3, c6, c0, 0		@ clock configuration, for turbo mode
 	mrc	p15, 0, r4, c15, c1, 0		@ CP access reg
 	mrc	p15, 0, r5, c13, c0, 0		@ PID
 	mrc 	p15, 0, r6, c3, c0, 0		@ domain ID
@@ -39,9 +47,11 @@ ENTRY(pxa_cpu_suspend)
 	mrc	p15, 0, r8, c1, c1, 0           @ auxiliary control reg
 	mrc 	p15, 0, r9, c1, c0, 0		@ control reg
 
+	bic	r3, r3, #2			@ clear frequency change bit
+
 	@ store them plus current virtual stack ptr on stack
 	mov	r10, sp
-	stmfd	sp!, {r4 - r10}
+	stmfd	sp!, {r3 - r10}
 
 	@ preserve phys address of stack
 	mov	r0, sp
@@ -58,14 +68,23 @@ ENTRY(pxa_cpu_suspend)
 	@ prepare value for sleep mode
 	mov	r1, #3				@ sleep mode
 
-	@ prepare to put SDRAM into self-refresh manually
+	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
+	mov	r2, #UNCACHED_PHYS_0
+
+	@ prepare SDRAM refresh settings
 	ldr	r4, =MDREFR
 	ldr	r5, [r4]
+
+	@ enable SDRAM self-refresh mode
 	orr	r5, r5, #MDREFR_SLFRSH
 
-	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
-	mov	r2, #UNCACHED_PHYS_0
+#ifdef CONFIG_PXA27x
+	@ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50)
+	ldr	r6, =MDREFR_KDIV
+	orr	r5, r5, r6
+#endif
 
+#ifdef CONFIG_PXA25x
 	@ Intel PXA255 Specification Update notes problems
 	@ about suspending with PXBus operating above 133MHz
 	@ (see Errata 31, GPIO output signals, ... unpredictable in sleep
@@ -90,12 +109,25 @@ ENTRY(pxa_cpu_suspend)
 	orrne	r7, r7, #1			@@ 99.53MHz
 
 	@ get ready for the change
-	@ note, since we are making turbo=run, do not remove the turbo
-	@ as this may cause non-turbo mode on resume
-	mrc	p14, 0, r0, c6, c0, 0
-	bic	r0, r0, #2			@ clear change bit
+
+	@ note, turbo is not preserved over sleep so there is no
+	@ point in preserving it here. we save it on the stack with the
+	@ other CP registers instead.
+	mov	r0, #0
 	mcr	p14, 0, r0, c6, c0, 0
 	orr	r0, r0, #2			@ initiate change bit
+#endif
+#ifdef CONFIG_PXA27x
+	@ Intel PXA270 Specification Update notes problems sleeping
+	@ with core operating above 91 MHz
+	@ (see Errata 50, ...processor does not exit from sleep...)
+
+	ldr	r6, =CCCR
+	ldr	r8, [r6]		@ keep original value for resume
+
+	ldr	r7, =CCCR_SLEEP		@ prepare CCCR sleep value
+	mov	r0, #0x2		@ prepare value for CLKCFG
+#endif
 
 	@ align execution to a cache line
 	b	1f
@@ -107,6 +139,7 @@ ENTRY(pxa_cpu_suspend)
 	@ All needed values are now in registers.
 	@ These last instructions should be in cache
 
+#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
 	@ initiate the frequency change...
 	str	r7, [r6]
 	mcr	p14, 0, r0, c6, c0, 0
@@ -114,14 +147,27 @@ ENTRY(pxa_cpu_suspend)
 	@ restore the original cpu speed value for resume
 	str	r8, [r6]
 
-	@ put SDRAM into self-refresh
-	str	r5, [r4]
+	@ need 6 13-MHz cycles before changing PWRMODE
+	@ just set frequency to 91-MHz... 6*91/13 = 42
+
+	mov	r0, #42
+10:	subs	r0, r0, #1
+	bne	10b
+#endif
+
+	@ Do not reorder...
+	@ Intel PXA270 Specification Update notes problems performing
+	@ external accesses after SDRAM is put in self-refresh mode
+	@ (see Errata 39 ...hangs when entering self-refresh mode)
 
 	@ force address lines low by reading at physical address 0
 	ldr	r3, [r2]
 
+	@ put SDRAM into self-refresh
+	str	r5, [r4]
+
 	@ enter sleep mode
-	mcr	p14, 0, r1, c7, c0, 0
+	mcr	p14, 0, r1, c7, c0, 0		@ PWRMODE
 
 20:	b	20b				@ loop waiting for sleep
 
@@ -145,7 +191,7 @@ ENTRY(pxa_cpu_resume)
 
 	ldr	r0, sleep_save_sp		@ stack phys addr
 	ldr	r2, =resume_after_mmu		@ its absolute virtual address
-	ldmfd	r0, {r4 - r9, sp}		@ CP regs + virt stack ptr
+	ldmfd	r0, {r3 - r9, sp}		@ CP regs + virt stack ptr
 
 	mov	r1, #0
 	mcr	p15, 0, r1, c8, c7, 0   	@ invalidate I & D TLBs
@@ -155,6 +201,7 @@ ENTRY(pxa_cpu_resume)
 	bic     r9, r9, #0x0004			@ see cpu_xscale_proc_init
 #endif
 
+	mcr	p14, 0, r3, c6, c0, 0		@ clock configuration, turbo mode.
 	mcr	p15, 0, r4, c15, c1, 0		@ CP access reg
 	mcr	p15, 0, r5, c13, c0, 0		@ PID
 	mcr 	p15, 0, r6, c3, c0, 0		@ domain ID
@@ -183,7 +230,9 @@ resume_after_mmu:
 	bl	cpu_xscale_proc_init
 #endif
 	ldmfd	sp!, {r2, r3}
+#ifndef CONFIG_IWMMXT
 	mar	acc0, r2, r3
+#endif
 	ldmfd	sp!, {r4 - r12, pc}		@ return to caller
 
 
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -254,7 +254,7 @@ static void floppy_enable_dma(dmach_t ch
 
 	regs.ARM_r9  = dma->buf.length;
 	regs.ARM_r10 = (unsigned long)dma->buf.__address;
-	regs.ARM_fp  = FLOPPYDMA_BASE;
+	regs.ARM_fp  = (unsigned long)FLOPPYDMA_BASE;
 
 	if (claim_fiq(&fh)) {
 		printk("floppydma: couldn't claim FIQ.\n");
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -67,7 +67,7 @@ __tagtable(ATAG_ACORN, parse_tag_acorn);
 
 static struct map_desc rpc_io_desc[] __initdata = {
  { SCREEN_BASE,	SCREEN_START,	2*1048576, MT_DEVICE }, /* VRAM		*/
- { IO_BASE,	IO_START,	IO_SIZE	 , MT_DEVICE }, /* IO space	*/
+ { (u32)IO_BASE, IO_START,	IO_SIZE	 , MT_DEVICE }, /* IO space	*/
  { EASI_BASE,	EASI_START,	EASI_SIZE, MT_DEVICE }  /* EASI space	*/
 };
 
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -19,6 +19,14 @@ config ARCH_H1940
 
 	  <http://www.handhelds.org/projects/h1940.html>.
 
+config MACH_N30
+	bool "Acer N30"
+	select CPU_S3C2410
+	help
+	  Say Y here if you are using the Acer N30
+
+	  <http://zoo.weinigel.se/n30>.
+
 config ARCH_SMDK2410
 	bool "SMDK2410/A9M2410"
 	select CPU_S3C2410
@@ -26,6 +34,12 @@ config ARCH_SMDK2410
 	   Say Y here if you are using the SMDK2410 or the derived module A9M2410
            <http://www.fsforth.de>
 
+config ARCH_S3C2440
+	bool "SMDK2440"
+	select CPU_S3C2440
+	help
+	  Say Y here if you are using the SMDK2440.
+
 config MACH_VR1000
 	bool "Thorcom VR1000"
 	select CPU_S3C2410
@@ -44,6 +58,18 @@ config MACH_RX3715
 	  See <http://www.handhelds.org/projects/rx3715.html> for more
 	  information on this project
 
+config MACH_OTOM
+ 	bool "NexVision OTOM Board"
+ 	select CPU_S3C2410
+	help
+ 	  Say Y here if you are using the Nex Vision OTOM board
+
+config MACH_NEXCODER_2440
+ 	bool "NexVision NEXCODER 2440 Light Board"
+ 	select CPU_S3C2440
+	help
+ 	  Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+
 endmenu
 
 config CPU_S3C2410
@@ -59,6 +85,26 @@ config CPU_S3C2440
 	help
 	  Support for S3C2440 Samsung Mobile CPU based systems.
 
+comment "S3C2410 Boot"
+
+config S3C2410_BOOT_WATCHDOG
+	bool "S3C2410 Initialisation watchdog"
+	depends on ARCH_S3C2410 && S3C2410_WATCHDOG
+	help
+	  Say y to enable the watchdog during the kernel decompression
+	  stage. If the kernel fails to uncompress, then the watchdog
+	  will trigger a reset and the system should restart.
+
+	  Although this uses the same hardware unit as the kernel watchdog
+	  driver, it is not a replacement for it. If you use this option,
+	  you will have to use the watchdg driver to either stop the timeout
+	  or restart it. If you do not, then your kernel will reboot after
+	  startup.
+
+	  The driver uses a fixed timeout value, so the exact time till the
+	  system resets depends on the value of PCLK. The timeout on an
+	  200MHz s3c2410 should be about 30 seconds.
+
 comment "S3C2410 Setup"
 
 config S3C2410_DMA
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -27,6 +27,10 @@ obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o 
 
 obj-$(CONFIG_ARCH_BAST)		+= mach-bast.o usb-simtec.o
 obj-$(CONFIG_ARCH_H1940)	+= mach-h1940.o
+obj-$(CONFIG_MACH_N30)		+= mach-n30.o
 obj-$(CONFIG_ARCH_SMDK2410)	+= mach-smdk2410.o
+obj-$(CONFIG_ARCH_S3C2440)	+= mach-smdk2440.o
 obj-$(CONFIG_MACH_VR1000)	+= mach-vr1000.o usb-simtec.o
 obj-$(CONFIG_MACH_RX3715)	+= mach-rx3715.o
+obj-$(CONFIG_MACH_OTOM)		+= mach-otom.o
+obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s3c2410/clock.c
  *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 Clock control support
  *
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
@@ -46,18 +47,13 @@
 #include <asm/arch/regs-clock.h>
 
 #include "clock.h"
+#include "cpu.h"
 
 /* clock information */
 
-unsigned long s3c24xx_xtal = 12*1000*1000;	/* default 12MHz */
-unsigned long s3c24xx_fclk;
-unsigned long s3c24xx_hclk;
-unsigned long s3c24xx_pclk;
-
 static LIST_HEAD(clocks);
 static DECLARE_MUTEX(clocks_sem);
 
-
 /* old functions */
 
 void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
@@ -206,6 +202,14 @@ EXPORT_SYMBOL(clk_get_parent);
 
 /* base clocks */
 
+static struct clk clk_xtal = {
+	.name		= "xtal",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= NULL,
+	.ctrlbit	= 0,
+};
+
 static struct clk clk_f = {
 	.name		= "fclk",
 	.id		= -1,
@@ -286,6 +290,7 @@ static struct clk init_clocks[] = {
 	  .ctrlbit = S3C2410_CLKCON_USBD
 	},
 	{ .name    = "timers",
+	  .id	   = -1,
 	  .parent  = &clk_p,
 	  .enable  = s3c24xx_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_PWMT
@@ -378,19 +383,24 @@ int s3c24xx_register_clock(struct clk *c
 
 /* initalise all the clocks */
 
-int __init s3c24xx_setup_clocks(void)
+int __init s3c24xx_setup_clocks(unsigned long xtal,
+				unsigned long fclk,
+				unsigned long hclk,
+				unsigned long pclk)
 {
 	struct clk *clkp = init_clocks;
 	int ptr;
 	int ret;
 
-	printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n");
+	printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n");
 
 	/* initialise the main system clocks */
 
-	clk_h.rate = s3c24xx_hclk;
-	clk_p.rate = s3c24xx_pclk;
-	clk_f.rate = s3c24xx_fclk;
+	clk_xtal.rate = xtal;
+
+	clk_h.rate = hclk;
+	clk_p.rate = pclk;
+	clk_f.rate = fclk;
 
 	/* it looks like just setting the register here is not good
 	 * enough, and causes the odd hang at initial boot time, so
@@ -414,6 +424,9 @@ int __init s3c24xx_setup_clocks(void)
 
 	/* register our clocks */
 
+	if (s3c24xx_register_clock(&clk_xtal) < 0)
+		printk(KERN_ERR "failed to register master xtal\n");
+
 	if (s3c24xx_register_clock(&clk_f) < 0)
 		printk(KERN_ERR "failed to register cpu fclk\n");
 
@@ -423,6 +436,8 @@ int __init s3c24xx_setup_clocks(void)
 	if (s3c24xx_register_clock(&clk_p) < 0)
 		printk(KERN_ERR "failed to register cpu pclk\n");
 
+	/* register clocks from clock array */
+
 	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
 		ret = s3c24xx_register_clock(clkp);
 		if (ret < 0) {
@@ -434,4 +449,59 @@ int __init s3c24xx_setup_clocks(void)
 	return 0;
 }
 
+/* S3C2440 extended clock support */
+
+#ifdef CONFIG_CPU_S3C2440
+
+static struct clk s3c2440_clk_upll = {
+	.name		= "upll",
+	.id		= -1,
+};
+
+static struct clk s3c2440_clk_cam = {
+	.name		= "camif",
+	.parent		= &clk_h,
+	.id		= -1,
+	.enable		= s3c24xx_clkcon_enable,
+	.ctrlbit	= S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2440_clk_ac97 = {
+	.name		= "ac97",
+	.parent		= &clk_p,
+	.id		= -1,
+	.enable		= s3c24xx_clkcon_enable,
+	.ctrlbit	= S3C2440_CLKCON_CAMERA,
+};
+
+static int s3c2440_clk_add(struct sys_device *sysdev)
+{
+	unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+
+	s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate);
+
+	printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
+	       print_mhz(s3c2440_clk_upll.rate));
+
+	s3c24xx_register_clock(&s3c2440_clk_ac97);
+	s3c24xx_register_clock(&s3c2440_clk_cam);
+	s3c24xx_register_clock(&s3c2440_clk_upll);
+
+	clk_disable(&s3c2440_clk_ac97);
+	clk_disable(&s3c2440_clk_cam);
+
+	return 0;
+}
+
+static struct sysdev_driver s3c2440_clk_driver = {
+	.add	= s3c2440_clk_add,
+};
+
+static int s3c24xx_clk_driver(void)
+{
+	return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
+}
+
+arch_initcall(s3c24xx_clk_driver);
 
+#endif /* CONFIG_CPU_S3C2440 */
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -1,7 +1,8 @@
 /*
  * linux/arch/arm/mach-s3c2410/clock.h
  *
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *	http://www.simtec.co.uk/products/SWLINUX/
  *	Written by Ben Dooks, <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,13 +30,6 @@ extern struct clk s3c24xx_clkout0;
 extern struct clk s3c24xx_clkout1;
 extern struct clk s3c24xx_uclk;
 
-/* processor clock settings, in Hz */
-
-extern unsigned long s3c24xx_xtal;
-extern unsigned long s3c24xx_pclk;
-extern unsigned long s3c24xx_hclk;
-extern unsigned long s3c24xx_fclk;
-
 /* exports for arch/arm/mach-s3c2410
  *
  * Please DO NOT use these outside of arch/arm/mach-s3c2410
@@ -44,4 +38,7 @@ extern unsigned long s3c24xx_fclk;
 extern int s3c24xx_clkcon_enable(struct clk *clk, int enable);
 extern int s3c24xx_register_clock(struct clk *clk);
 
-extern int s3c24xx_setup_clocks(void);
+extern int s3c24xx_setup_clocks(unsigned long xtal,
+				unsigned long fclk,
+				unsigned long hclk,
+				unsigned long pclk);
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -1,7 +1,8 @@
 /* linux/arch/arm/mach-s3c2410/cpu.c
  *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *	http://www.simtec.co.uk/products/SWLINUX/
+ *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C24XX CPU Support
  *
@@ -181,8 +182,8 @@ void __init s3c24xx_init_io(struct map_d
 
 void __init s3c24xx_init_clocks(int xtal)
 {
-	if (xtal != 0)
-		s3c24xx_xtal = xtal;
+	if (xtal == 0)
+		xtal = 12*1000*1000;
 
 	if (cpu == NULL)
 		panic("s3c24xx_init_clocks: no cpu setup?\n");
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -15,9 +15,13 @@
  *     04-Jan-2005 BJD  New uart initialisation
  *     10-Jan-2005 BJD  Moved generic init here, specific to cpu headers
  *     14-Jan-2005 BJD  Added s3c24xx_init_clocks() call
+ *     10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ} & IODESC_ENT
+ *     14-Mar-2005 BJD  Updated for __iomem
 */
 
-#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE }
+/* todo - fix when rmk changes iodescs to use `void __iomem *` */
+
+#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE }
 
 #ifndef MHZ
 #define MHZ (1000*1000)
@@ -27,6 +31,7 @@
 
 /* forward declaration */
 struct s3c2410_uartcfg;
+struct map_desc;
 
 /* core initialisation functions */
 
@@ -58,3 +63,7 @@ extern void s3c24xx_set_board(struct s3c
 
 struct sys_timer;
 extern struct sys_timer s3c24xx_timer;
+
+/* system device classes */
+
+extern struct sysdev_class s3c2440_sysclass;
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -10,6 +10,8 @@
  * published by the Free Software Foundation.
  *
  * Modifications:
+ *     10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ}
+ *     10-Feb-2005 BJD  Added camera from guillaume.gourat@nexvision.tv
  *     29-Aug-2004 BJD  Added timers 0 through 3
  *     29-Aug-2004 BJD  Changed index of devices we only have one of to -1
  *     21-Aug-2004 BJD  Added IRQ_TICK to RTC resources
@@ -45,7 +47,7 @@ struct platform_device *s3c24xx_uart_dev
 static struct resource s3c_usb_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_USBHOST,
-		.end   = S3C2410_PA_USBHOST + S3C2410_SZ_USBHOST,
+		.end   = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -75,7 +77,7 @@ EXPORT_SYMBOL(s3c_device_usb);
 static struct resource s3c_lcd_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_LCD,
-		.end   = S3C2410_PA_LCD + S3C2410_SZ_LCD,
+		.end   = S3C2410_PA_LCD + S3C24XX_SZ_LCD,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -106,7 +108,7 @@ EXPORT_SYMBOL(s3c_device_lcd);
 static struct resource s3c_nand_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_NAND,
-		.end   = S3C2410_PA_NAND + S3C2410_SZ_NAND,
+		.end   = S3C2410_PA_NAND + S3C24XX_SZ_NAND,
 		.flags = IORESOURCE_MEM,
 	}
 };
@@ -125,7 +127,7 @@ EXPORT_SYMBOL(s3c_device_nand);
 static struct resource s3c_usbgadget_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_USBDEV,
-		.end   = S3C2410_PA_USBDEV + S3C2410_SZ_USBDEV,
+		.end   = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -150,7 +152,7 @@ EXPORT_SYMBOL(s3c_device_usbgadget);
 static struct resource s3c_wdt_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_WATCHDOG,
-		.end   = S3C2410_PA_WATCHDOG + S3C2410_SZ_WATCHDOG,
+		.end   = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -175,7 +177,7 @@ EXPORT_SYMBOL(s3c_device_wdt);
 static struct resource s3c_i2c_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_IIC,
-		.end   = S3C2410_PA_IIC + S3C2410_SZ_IIC,
+		.end   = S3C2410_PA_IIC + S3C24XX_SZ_IIC,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -200,7 +202,7 @@ EXPORT_SYMBOL(s3c_device_i2c);
 static struct resource s3c_iis_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_IIS,
-		.end   = S3C2410_PA_IIS + S3C2410_SZ_IIS,
+		.end   = S3C2410_PA_IIS + S3C24XX_SZ_IIS,
 		.flags = IORESOURCE_MEM,
 	}
 };
@@ -254,7 +256,7 @@ EXPORT_SYMBOL(s3c_device_rtc);
 static struct resource s3c_adc_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_ADC,
-		.end   = S3C2410_PA_ADC + S3C2410_SZ_ADC,
+		.end   = S3C2410_PA_ADC + S3C24XX_SZ_ADC,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -277,7 +279,7 @@ struct platform_device s3c_device_adc = 
 static struct resource s3c_sdi_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_SDI,
-		.end   = S3C2410_PA_SDI + S3C2410_SZ_SDI,
+		.end   = S3C2410_PA_SDI + S3C24XX_SZ_SDI,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
@@ -446,3 +448,38 @@ struct platform_device s3c_device_timer3
 };
 
 EXPORT_SYMBOL(s3c_device_timer3);
+
+#ifdef CONFIG_CPU_S3C2440
+
+/* Camif Controller */
+
+static struct resource s3c_camif_resource[] = {
+	[0] = {
+		.start = S3C2440_PA_CAMIF,
+		.end   = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_CAM,
+		.end   = IRQ_CAM,
+		.flags = IORESOURCE_IRQ,
+	}
+
+};
+
+static u64 s3c_device_camif_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_camif = {
+	.name		  = "s3c2440-camif",
+	.id		  = -1,
+	.num_resources	  = ARRAY_SIZE(s3c_camif_resource),
+	.resource	  = s3c_camif_resource,
+	.dev              = {
+		.dma_mask = &s3c_device_camif_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c_device_camif);
+
+#endif // CONFIG_CPU_S32440
diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h
--- a/arch/arm/mach-s3c2410/devs.h
+++ b/arch/arm/mach-s3c2410/devs.h
@@ -12,7 +12,11 @@
  * Modifications:
  *      18-Aug-2004 BJD  Created initial version
  *	27-Aug-2004 BJD  Added timers 0 through 3
+ *	10-Feb-2005 BJD	 Added camera from guillaume.gourat@nexvision.tv
 */
+#include <linux/config.h>
+
+extern struct platform_device *s3c24xx_uart_devs[];
 
 extern struct platform_device s3c_device_usb;
 extern struct platform_device s3c_device_lcd;
@@ -34,3 +38,11 @@ extern struct platform_device s3c_device
 extern struct platform_device s3c_device_timer3;
 
 extern struct platform_device s3c_device_usbgadget;
+
+/* s3c2440 specific devices */
+
+#ifdef CONFIG_CPU_S3C2440
+
+extern struct platform_device s3c_device_camif;
+
+#endif
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-bast/dma.c
  *
- * (c) 2003,2004 Simtec Electronics
+ * (c) 2003-2005 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 DMA core
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  *
  * Changelog:
+ *  27-Feb-2005 BJD  Added kmem cache for dma descriptors
  *  18-Nov-2004 BJD  Removed error for loading onto stopped channel
  *  10-Nov-2004 BJD  Ensure all external symbols exported for modules
  *  10-Nov-2004 BJD  Use sys_device and sysdev_class for power management
@@ -57,6 +58,7 @@
 
 /* io map for dma */
 static void __iomem *dma_base;
+static kmem_cache_t *dma_kmem;
 
 /* dma channel state information */
 s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
@@ -432,7 +434,7 @@ int s3c2410_dma_enqueue(unsigned int cha
 	pr_debug("%s: id=%p, data=%08x, size=%d\n",
 		 __FUNCTION__, id, (unsigned int)data, size);
 
-	buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC);
+	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
 	if (buf == NULL) {
 		pr_debug("%s: out of memory (%d alloc)\n",
 			 __FUNCTION__, sizeof(*buf));
@@ -511,7 +513,7 @@ s3c2410_dma_freebuf(s3c2410_dma_buf_t *b
 	buf->magic = -1;
 
 	if (magicok) {
-		kfree(buf);
+		kmem_cache_free(dma_kmem, buf);
 	} else {
 		printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
 	}
@@ -783,6 +785,10 @@ int s3c2410_dma_free(dmach_t channel, s3
 	chan->client = NULL;
 	chan->in_use = 0;
 
+	if (chan->irq_claimed)
+		free_irq(chan->irq, (void *)chan);
+	chan->irq_claimed = 0;
+
 	local_irq_restore(flags);
 
 	return 0;
@@ -1090,7 +1096,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition);
 
 #ifdef CONFIG_PM
 
-static int s3c2410_dma_suspend(struct sys_device *dev, u32 state)
+static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
 {
 	s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
 
@@ -1128,6 +1134,14 @@ static struct sysdev_class dma_sysclass 
 	.resume		= s3c2410_dma_resume,
 };
 
+/* kmem cache implementation */
+
+static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
+{
+	memset(p, 0, sizeof(s3c2410_dma_buf_t));
+}
+
+
 /* initialisation code */
 
 static int __init s3c2410_init_dma(void)
@@ -1150,6 +1164,16 @@ static int __init s3c2410_init_dma(void)
 		goto err;
 	}
 
+	dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0,
+				     SLAB_HWCACHE_ALIGN,
+				     s3c2410_dma_cache_ctor, NULL);
+
+	if (dma_kmem == NULL) {
+		printk(KERN_ERR "dma failed to make kmem cache\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
 	for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
 		cp = &s3c2410_chans[channel];
 
@@ -1181,6 +1205,7 @@ static int __init s3c2410_init_dma(void)
 	return 0;
 
  err:
+	kmem_cache_destroy(dma_kmem);
 	iounmap(dma_base);
 	dma_base = NULL;
 	return ret;
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s3c2410/gpio.c
  *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 GPIO support
  *
@@ -29,9 +29,11 @@
  *	01-Oct-2004  BJD  Added getirq() to turn pin into irqno
  *	04-Oct-2004  BJD  Added irq filter controls for GPIO
  *	05-Nov-2004  BJD  EXPORT_SYMBOL() added for all code
+ *	13-Mar-2005  BJD  Updates for __iomem
  */
 
 
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -45,7 +47,7 @@
 
 void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
 {
-	unsigned long base = S3C2410_GPIO_BASE(pin);
+	void __iomem *base = S3C2410_GPIO_BASE(pin);
 	unsigned long mask;
 	unsigned long con;
 	unsigned long flags;
@@ -71,7 +73,7 @@ EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
 
 unsigned int s3c2410_gpio_getcfg(unsigned int pin)
 {
-	unsigned long base = S3C2410_GPIO_BASE(pin);
+	void __iomem *base = S3C2410_GPIO_BASE(pin);
 	unsigned long mask;
 
 	if (pin < S3C2410_GPIO_BANKB) {
@@ -87,7 +89,7 @@ EXPORT_SYMBOL(s3c2410_gpio_getcfg);
 
 void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
 {
-	unsigned long base = S3C2410_GPIO_BASE(pin);
+	void __iomem *base = S3C2410_GPIO_BASE(pin);
 	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
 	unsigned long flags;
 	unsigned long up;
@@ -109,7 +111,7 @@ EXPORT_SYMBOL(s3c2410_gpio_pullup);
 
 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
 {
-	unsigned long base = S3C2410_GPIO_BASE(pin);
+	void __iomem *base = S3C2410_GPIO_BASE(pin);
 	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
 	unsigned long flags;
 	unsigned long dat;
@@ -128,7 +130,7 @@ EXPORT_SYMBOL(s3c2410_gpio_setpin);
 
 unsigned int s3c2410_gpio_getpin(unsigned int pin)
 {
-	unsigned long base = S3C2410_GPIO_BASE(pin);
+	void __iomem *base = S3C2410_GPIO_BASE(pin);
 	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
 
 	return __raw_readl(base + 0x04) & (1<< offs);
@@ -175,7 +177,7 @@ EXPORT_SYMBOL(s3c2410_gpio_getirq);
 int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
 			   unsigned int config)
 {
-	unsigned long reg = S3C2410_EINFLT0;
+	void __iomem *reg = S3C2410_EINFLT0;
 	unsigned long flags;
 	unsigned long val;
 
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -39,6 +39,9 @@
  *
  *   04-Nov-2004  Ben Dooks
  *		  Fix standard IRQ wake for EINT0..4 and RTC
+ *
+ *   22-Feb-2004  Ben Dooks
+ *		  Fixed edge-triggering on ADC IRQ
 */
 
 #include <linux/init.h>
@@ -57,6 +60,7 @@
 #include <asm/arch/regs-irq.h>
 #include <asm/arch/regs-gpio.h>
 
+#include "cpu.h"
 #include "pm.h"
 
 #define irqdbf(x...)
@@ -261,8 +265,8 @@ s3c_irqext_unmask(unsigned int irqno)
 static int
 s3c_irqext_type(unsigned int irq, unsigned int type)
 {
-	unsigned long extint_reg;
-	unsigned long gpcon_reg;
+	void __iomem *extint_reg;
+	void __iomem *gpcon_reg;
 	unsigned long gpcon_offset, extint_offset;
 	unsigned long newvalue = 0, value;
 
@@ -425,6 +429,23 @@ s3c_irqsub_maskack(unsigned int irqno, u
 	}
 }
 
+static inline void
+s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
+{
+	unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
+
+	__raw_writel(bit, S3C2410_SUBSRCPND);
+
+	/* only ack parent if we've got all the irqs (seems we must
+	 * ack, all and hope that the irq system retriggers ok when
+	 * the interrupt goes off again)
+	 */
+
+	if (1) {
+		__raw_writel(parentmask, S3C2410_SRCPND);
+		__raw_writel(parentmask, S3C2410_INTPND);
+	}
+}
 
 /* UART0 */
 
@@ -521,7 +542,7 @@ s3c_irq_adc_unmask(unsigned int irqno)
 static void
 s3c_irq_adc_ack(unsigned int irqno)
 {
-	s3c_irqsub_maskack(irqno, INTMSK_ADCPARENT, 3 << 9);
+	s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
 }
 
 static struct irqchip s3c_irq_adc = {
@@ -628,6 +649,7 @@ s3c_irq_demux_uart2(unsigned int irq,
 	s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
 }
 
+
 /* s3c24xx_init_irq
  *
  * Initialise S3C2410 IRQ system
@@ -771,3 +793,174 @@ void __init s3c24xx_init_irq(void)
 
 	irqdbf("s3c2410: registered interrupt handlers\n");
 }
+
+/* s3c2440 irq code
+*/
+
+#ifdef CONFIG_CPU_S3C2440
+
+/* WDT/AC97 */
+
+static void s3c_irq_demux_wdtac97(unsigned int irq,
+				  struct irqdesc *desc,
+				  struct pt_regs *regs)
+{
+	unsigned int subsrc, submsk;
+	struct irqdesc *mydesc;
+
+	/* read the current pending interrupts, and the mask
+	 * for what it is available */
+
+	subsrc = __raw_readl(S3C2410_SUBSRCPND);
+	submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+	subsrc &= ~submsk;
+	subsrc >>= 13;
+	subsrc &= 3;
+
+	if (subsrc != 0) {
+		if (subsrc & 1) {
+			mydesc = irq_desc + IRQ_S3C2440_WDT;
+			mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+		}
+		if (subsrc & 2) {
+			mydesc = irq_desc + IRQ_S3C2440_AC97;
+			mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+		}
+	}
+}
+
+
+#define INTMSK_WDT	 (1UL << (IRQ_WDT - IRQ_EINT0))
+
+static void
+s3c_irq_wdtac97_mask(unsigned int irqno)
+{
+	s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
+}
+
+static void
+s3c_irq_wdtac97_unmask(unsigned int irqno)
+{
+	s3c_irqsub_unmask(irqno, INTMSK_WDT);
+}
+
+static void
+s3c_irq_wdtac97_ack(unsigned int irqno)
+{
+	s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
+}
+
+static struct irqchip s3c_irq_wdtac97 = {
+	.mask	    = s3c_irq_wdtac97_mask,
+	.unmask	    = s3c_irq_wdtac97_unmask,
+	.ack	    = s3c_irq_wdtac97_ack,
+};
+
+/* camera irq */
+
+static void s3c_irq_demux_cam(unsigned int irq,
+			      struct irqdesc *desc,
+			      struct pt_regs *regs)
+{
+	unsigned int subsrc, submsk;
+	struct irqdesc *mydesc;
+
+	/* read the current pending interrupts, and the mask
+	 * for what it is available */
+
+	subsrc = __raw_readl(S3C2410_SUBSRCPND);
+	submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+	subsrc &= ~submsk;
+	subsrc >>= 11;
+	subsrc &= 3;
+
+	if (subsrc != 0) {
+		if (subsrc & 1) {
+			mydesc = irq_desc + IRQ_S3C2440_CAM_C;
+			mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+		}
+		if (subsrc & 2) {
+			mydesc = irq_desc + IRQ_S3C2440_CAM_P;
+			mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+		}
+	}
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+
+static void
+s3c_irq_cam_mask(unsigned int irqno)
+{
+	s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
+}
+
+static void
+s3c_irq_cam_unmask(unsigned int irqno)
+{
+	s3c_irqsub_unmask(irqno, INTMSK_CAM);
+}
+
+static void
+s3c_irq_cam_ack(unsigned int irqno)
+{
+	s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
+}
+
+static struct irqchip s3c_irq_cam = {
+	.mask	    = s3c_irq_cam_mask,
+	.unmask	    = s3c_irq_cam_unmask,
+	.ack	    = s3c_irq_cam_ack,
+};
+
+static int s3c2440_irq_add(struct sys_device *sysdev)
+{
+	unsigned int irqno;
+
+	printk("S3C2440: IRQ Support\n");
+
+	set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
+	set_irq_handler(IRQ_NFCON, do_level_IRQ);
+	set_irq_flags(IRQ_NFCON, IRQF_VALID);
+
+	/* add new chained handler for wdt, ac7 */
+
+	set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
+	set_irq_handler(IRQ_WDT, do_level_IRQ);
+	set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
+
+	for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
+		set_irq_chip(irqno, &s3c_irq_wdtac97);
+		set_irq_handler(irqno, do_level_IRQ);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+
+	/* add chained handler for camera */
+
+	set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
+	set_irq_handler(IRQ_CAM, do_level_IRQ);
+	set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
+
+	for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
+		set_irq_chip(irqno, &s3c_irq_cam);
+		set_irq_handler(irqno, do_level_IRQ);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+
+	return 0;
+}
+
+static struct sysdev_driver s3c2440_irq_driver = {
+	.add	= s3c2440_irq_add,
+};
+
+static int s3c24xx_irq_driver(void)
+{
+	return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
+}
+
+arch_initcall(s3c24xx_irq_driver);
+
+#endif /* CONFIG_CPU_S3C2440 */
+
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -23,6 +23,9 @@
  *     04-Jan-2005 BJD  New uart init call
  *     10-Jan-2005 BJD  Removed include of s3c2410.h
  *     14-Jan-2005 BJD  Add support for muitlple NAND devices
+ *     03-Mar-2005 BJD  Ensured that bast-cpld.h is included
+ *     10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
+ *     14-Mar-2006 BJD  Updated for __iomem changes
 */
 
 #include <linux/kernel.h>
@@ -39,6 +42,7 @@
 
 #include <asm/arch/bast-map.h>
 #include <asm/arch/bast-irq.h>
+#include <asm/arch/bast-cpld.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -65,10 +69,10 @@
 #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
 
 /* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((item) + BAST_VAM_CS5)
-#define VA_C4(item) ((item) + BAST_VAM_CS4)
-#define VA_C3(item) ((item) + BAST_VAM_CS3)
-#define VA_C2(item) ((item) + BAST_VAM_CS2)
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
 
 /* macros to modify the physical addresses for io space */
 
@@ -80,8 +84,8 @@
 static struct map_desc bast_iodesc[] __initdata = {
   /* ISA IO areas */
 
-  { S3C2410_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
-  { S3C2410_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
+  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
+  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
 
   /* we could possibly compress the next set down into a set of smaller tables
    * pagetables, but that would mean using an L2 section, and it still means
@@ -89,26 +93,15 @@ static struct map_desc bast_iodesc[] __i
    */
 
   /* bast CPLD control registers, and external interrupt controls */
-  { BAST_VA_CTRL1, BAST_PA_CTRL1,		   SZ_1M, MT_DEVICE },
-  { BAST_VA_CTRL2, BAST_PA_CTRL2,		   SZ_1M, MT_DEVICE },
-  { BAST_VA_CTRL3, BAST_PA_CTRL3,		   SZ_1M, MT_DEVICE },
-  { BAST_VA_CTRL4, BAST_PA_CTRL4,		   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_CTRL1, BAST_PA_CTRL1,		   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_CTRL2, BAST_PA_CTRL2,		   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_CTRL3, BAST_PA_CTRL3,		   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_CTRL4, BAST_PA_CTRL4,		   SZ_1M, MT_DEVICE },
 
   /* PC104 IRQ mux */
-  { BAST_VA_PC104_IRQREQ,  BAST_PA_PC104_IRQREQ,   SZ_1M, MT_DEVICE },
-  { BAST_VA_PC104_IRQRAW,  BAST_PA_PC104_IRQRAW,   SZ_1M, MT_DEVICE },
-  { BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK,  SZ_1M, MT_DEVICE },
-
-  /* onboard 8bit lcd port */
-
-  { BAST_VA_LCD_RCMD1,  BAST_PA_LCD_RCMD1,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_WCMD1,  BAST_PA_LCD_WCMD1,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_RDATA1, BAST_PA_LCD_RDATA1,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_WDATA1, BAST_PA_LCD_WDATA1,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_RCMD2,  BAST_PA_LCD_RCMD2,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_WCMD2,  BAST_PA_LCD_WCMD2,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_RDATA2, BAST_PA_LCD_RDATA2,	   SZ_1M, MT_DEVICE },
-  { BAST_VA_LCD_WDATA2, BAST_PA_LCD_WDATA2,	   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_PC104_IRQREQ,  BAST_PA_PC104_IRQREQ,   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_PC104_IRQRAW,  BAST_PA_PC104_IRQRAW,   SZ_1M, MT_DEVICE },
+  { (u32)BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK,  SZ_1M, MT_DEVICE },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
@@ -407,7 +400,7 @@ static __init void bast_init_machine(voi
 
 MACHINE_START(BAST, "Simtec-BAST")
      MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
-     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(bast_map_io)
      INITIRQ(bast_init_irq)
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -23,6 +23,7 @@
  *     04-Jan-2005 BJD  Updated uart init call
  *     10-Jan-2005 BJD  Removed include of s3c2410.h
  *     14-Jan-2005 BJD  Added clock init
+ *     10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
 */
 
 #include <linux/kernel.h>
@@ -117,7 +118,7 @@ void __init h1940_init_irq(void)
 
 MACHINE_START(H1940, "IPAQ-H1940")
      MAINTAINER("Ben Dooks <ben@fluff.org>")
-     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(h1940_map_io)
      INITIRQ(h1940_init_irq)
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -0,0 +1,155 @@
+/* linux/arch/arm/mach-s3c2410/mach-n30.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright (c) 2005 Christer Weinigel <christer@weinigel.se>
+ *
+ * There is a wiki with more information about the n30 port at
+ * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/iic.h>
+
+#include <linux/serial_core.h>
+
+#include "s3c2410.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+static struct map_desc n30_iodesc[] __initdata = {
+	/* nothing here yet */
+};
+
+static struct s3c2410_uartcfg n30_uartcfgs[] = {
+	/* Normal serial port */
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = 0x2c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	/* IR port */
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.uart_flags  = UPF_CONS_FLOW,
+		.ucon	     = 0x2c5,
+		.ulcon	     = 0x43,
+		.ufcon	     = 0x51,
+	},
+	/* The BlueTooth controller is connected to port 2 */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = 0x2c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+};
+
+static struct platform_device *n30_devices[] __initdata = {
+	&s3c_device_usb,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c,
+	&s3c_device_iis,
+	&s3c_device_usbgadget,
+};
+
+static struct s3c2410_platform_i2c n30_i2ccfg = {
+	.flags		= 0,
+	.slave_addr	= 0x10,
+	.bus_freq	= 10*1000,
+	.max_freq	= 10*1000,
+};
+
+static struct s3c24xx_board n30_board __initdata = {
+	.devices       = n30_devices,
+	.devices_count = ARRAY_SIZE(n30_devices)
+};
+
+void __init n30_map_io(void)
+{
+	s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
+	s3c24xx_set_board(&n30_board);
+}
+
+void __init n30_init_irq(void)
+{
+	s3c24xx_init_irq();
+}
+
+
+static int n30_usbstart_thread(void *unused)
+{
+	/* Turn off suspend on both USB ports, and switch the
+	 * selectable USB port to USB device mode. */
+	writel(readl(S3C2410_MISCCR) & ~0x00003008, S3C2410_MISCCR);
+
+	/* Turn off the D+ pull up for 3 seconds so that the USB host
+	 * at the other end will do a rescan of the USB bus.  */
+	s3c2410_gpio_setpin(S3C2410_GPB3, 0);
+
+	msleep_interruptible(3*HZ);
+
+	s3c2410_gpio_setpin(S3C2410_GPB3, 1);
+
+	return 0;
+}
+
+
+void __init n30_init(void)
+{
+	s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
+	kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
+}
+
+MACHINE_START(N30, "Acer-N30")
+     MAINTAINER("Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org>")
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
+     BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+
+	.timer		= &s3c24xx_timer,
+	.init_machine	= n30_init,
+	.init_irq	= n30_init_irq,
+	.map_io		= n30_map_io,
+MACHINE_END
+
+/*
+    Local variables:
+        compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."
+        c-basic-offset: 8
+    End:
+*/
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-nexcoder.c
@@ -0,0 +1,156 @@
+/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c
+ *
+ * Copyright (c) 2004 Nex Vision
+ *   Guillaume GOURAT <guillaume.gourat@nexvision.tv>
+ *
+ * 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.
+ *
+ * Modifications:
+ *     15-10-2004 GG  Created initial version
+ *     12-03-2005 BJD Updated for release
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/mtd/map.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/setup.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-serial.h>
+
+#include "s3c2410.h"
+#include "s3c2440.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+static struct map_desc nexcoder_iodesc[] __initdata = {
+	/* nothing here yet */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg nexcoder_uartcfgs[] = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	}
+};
+
+/* NOR Flash on NexVision NexCoder 2440 board */
+
+static struct resource nexcoder_nor_resource[] = {
+	[0] = {
+		.start = S3C2410_CS0,
+		.end   = S3C2410_CS0 + (8*1024*1024) - 1,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct map_info nexcoder_nor_map = {
+	.bankwidth = 2,
+};
+
+static struct platform_device nexcoder_device_nor = {
+	.name		= "mtd-flash",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(nexcoder_nor_resource),
+	.resource	= nexcoder_nor_resource,
+	.dev =
+	{
+		.platform_data = &nexcoder_nor_map,
+	}
+};
+
+/* Standard Nexcoder devices */
+
+static struct platform_device *nexcoder_devices[] __initdata = {
+	&s3c_device_usb,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c,
+	&s3c_device_iis,
+ 	&s3c_device_rtc,
+	&s3c_device_camif,
+	&s3c_device_spi0,
+	&s3c_device_spi1,
+	&nexcoder_device_nor,
+};
+
+static struct s3c24xx_board nexcoder_board __initdata = {
+	.devices       = nexcoder_devices,
+	.devices_count = ARRAY_SIZE(nexcoder_devices),
+};
+
+
+static void __init nexcoder_sensorboard_init(void)
+{
+	// Initialize SCCB bus
+	s3c2410_gpio_setpin(S3C2410_GPE14, 1); // IICSCL
+	s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_OUTP);
+	s3c2410_gpio_setpin(S3C2410_GPE15, 1); // IICSDA
+	s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_OUTP);
+
+	// Power up the sensor board
+	s3c2410_gpio_setpin(S3C2410_GPF1, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_OUTP); // CAM_GPIO7 => nLDO_PWRDN
+	s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP); // CAM_GPIO6 => CAM_PWRDN
+}
+
+void __init nexcoder_map_io(void)
+{
+	s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
+	s3c24xx_set_board(&nexcoder_board);
+	nexcoder_sensorboard_init();
+}
+
+
+MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
+     MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
+     BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+	.map_io		= nexcoder_map_io,
+	.init_irq	= s3c24xx_init_irq,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -0,0 +1,124 @@
+/* linux/arch/arm/mach-s3c2410/mach-otom.c
+ *
+ * Copyright (c) 2004 Nex Vision
+ *   Guillaume GOURAT <guillaume.gourat@nexvision.fr>
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/otom-map.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "s3c2410.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+static struct map_desc otom11_iodesc[] __initdata = {
+  /* Device area */
+	{ (u32)OTOM_VA_CS8900A_BASE, OTOM_PA_CS8900A_BASE, SZ_16M, MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg otom11_uartcfgs[] = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	/* port 2 is not actually used */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	}
+};
+
+/* NOR Flash on NexVision OTOM board */
+
+static struct resource otom_nor_resource[] = {
+	[0] = {
+		.start = S3C2410_CS0,
+		.end   = S3C2410_CS0 + (4*1024*1024) - 1,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device otom_device_nor = {
+	.name		= "mtd-flash",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(otom_nor_resource),
+	.resource	= otom_nor_resource,
+};
+
+/* Standard OTOM devices */
+
+static struct platform_device *otom11_devices[] __initdata = {
+	&s3c_device_usb,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c,
+	&s3c_device_iis,
+ 	&s3c_device_rtc,
+	&otom_device_nor,
+};
+
+static struct s3c24xx_board otom11_board __initdata = {
+	.devices       = otom11_devices,
+	.devices_count = ARRAY_SIZE(otom11_devices)
+};
+
+
+void __init otom11_map_io(void)
+{
+	s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
+	s3c24xx_set_board(&otom11_board);
+}
+
+
+MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
+     MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
+     BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+	.map_io		= otom11_map_io,
+	.init_irq	= s3c24xx_init_irq,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -10,10 +10,12 @@
  * published by the Free Software Foundation.
  *
  * Modifications:
- *	16-Sep-2004 BJD Copied from mach-h1940.c
- *	25-Oct-2004 BJD Updates for 2.6.10-rc1
- *	10-Jan-2005 BJD Removed include of s3c2410.h s3c2440.h
- *	14-Jan-2005 BJD Added new clock init
+ *	16-Sep-2004 BJD  Copied from mach-h1940.c
+ *	25-Oct-2004 BJD  Updates for 2.6.10-rc1
+ *	10-Jan-2005 BJD  Removed include of s3c2410.h s3c2440.h
+ *	14-Jan-2005 BJD  Added new clock init
+ *	10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
+ *	14-Mar-2005 BJD  Fixed __iomem warnings
 */
 
 #include <linux/kernel.h>
@@ -48,8 +50,18 @@
 static struct map_desc rx3715_iodesc[] __initdata = {
 	/* dump ISA space somewhere unused */
 
-	{ S3C2410_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE },
-	{ S3C2410_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE },
+	{ (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE },
+	{ (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE },
+};
+
+
+static struct s3c24xx_uart_clksrc rx3715_serial_clocks[] = {
+	[0] = {
+		.name		= "fclk",
+		.divisor	= 0,
+		.min_baud	= 0,
+		.max_baud	= 0,
+	}
 };
 
 static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
@@ -59,6 +71,8 @@ static struct s3c2410_uartcfg rx3715_uar
 		.ucon	     = 0x3c5,
 		.ulcon	     = 0x03,
 		.ufcon	     = 0x51,
+		.clocks	     = rx3715_serial_clocks,
+		.clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
 	},
 	[1] = {
 		.hwport	     = 1,
@@ -66,6 +80,8 @@ static struct s3c2410_uartcfg rx3715_uar
 		.ucon	     = 0x3c5,
 		.ulcon	     = 0x03,
 		.ufcon	     = 0x00,
+		.clocks	     = rx3715_serial_clocks,
+		.clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
 	},
 	/* IR port */
 	[2] = {
@@ -74,6 +90,8 @@ static struct s3c2410_uartcfg rx3715_uar
 		.ucon	     = 0x3c5,
 		.ulcon	     = 0x43,
 		.ufcon	     = 0x51,
+		.clocks	     = rx3715_serial_clocks,
+		.clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
 	}
 };
 
@@ -114,7 +132,7 @@ static void __init rx3715_init_machine(v
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
      MAINTAINER("Ben Dooks <ben@fluff.org>")
-     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(rx3715_map_io)
      INITIRQ(rx3715_init_irq)
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -26,6 +26,9 @@
  * @History:
  * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
  * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 10-Mar-2005 LCVR  Changed S3C2410_VA to S3C24XX_VA
+ *
  ***********************************************************************/
 
 #include <linux/kernel.h>
@@ -110,7 +113,7 @@ void __init smdk2410_init_irq(void)
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
 				    * to SMDK2410 */
      MAINTAINER("Jonas Dietsche")
-     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(smdk2410_map_io)
      INITIRQ(smdk2410_init_irq)
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -0,0 +1,135 @@
+/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c
+ *
+ * Copyright (c) 2004,2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.fluff.org/ben/smdk2440/
+ *
+ * Thanks to Dimity Andric and TomTom for the loan of an SMDK2440.
+ *
+ * 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.
+ *
+ * Modifications:
+ *	01-Nov-2004 BJD   Initial version
+ *	12-Nov-2004 BJD   Updated for release
+ *	04-Jan-2005 BJD   Fixes for pre-release
+ *	22-Feb-2005 BJD   Updated for 2.6.11-rc5 relesa
+ *	10-Mar-2005 LCVR  Replaced S3C2410_VA by S3C24XX_VA
+ *	14-Mar-2005 BJD	  void __iomem fixes
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/idle.h>
+
+#include "s3c2410.h"
+#include "s3c2440.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct map_desc smdk2440_iodesc[] __initdata = {
+	/* ISA IO Space map (memory space selected by A24) */
+
+	{ (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE },
+	{ (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2440_uartcfgs[] = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	/* IR port */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x43,
+		.ufcon	     = 0x51,
+	}
+};
+
+static struct platform_device *smdk2440_devices[] __initdata = {
+	&s3c_device_usb,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c,
+	&s3c_device_iis,
+};
+
+static struct s3c24xx_board smdk2440_board __initdata = {
+	.devices       = smdk2440_devices,
+	.devices_count = ARRAY_SIZE(smdk2440_devices)
+};
+
+void __init smdk2440_map_io(void)
+{
+	s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
+	s3c24xx_init_clocks(16934400);
+	s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
+	s3c24xx_set_board(&smdk2440_board);
+}
+
+void __init smdk2440_machine_init(void)
+{
+	/* Configure the LEDs (even if we have no LED support)*/
+
+	s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
+	s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
+	s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
+	s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
+
+	s3c2410_gpio_setpin(S3C2410_GPF4, 0);
+	s3c2410_gpio_setpin(S3C2410_GPF5, 0);
+	s3c2410_gpio_setpin(S3C2410_GPF6, 0);
+	s3c2410_gpio_setpin(S3C2410_GPF7, 0);
+
+	s3c2410_pm_init();
+}
+
+MACHINE_START(S3C2440, "SMDK2440")
+	MAINTAINER("Ben Dooks <ben@fluff.org>")
+	BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
+	BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+
+	.init_irq	= s3c24xx_init_irq,
+	.map_io		= smdk2440_map_io,
+	.init_machine	= smdk2440_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -24,6 +24,9 @@
  *     14-Jan-2005 BJD  Added clock init
  *     15-Jan-2005 BJD  Add serial port device definition
  *     20-Jan-2005 BJD  Use UPF_IOREMAP for ports
+ *     10-Feb-2005 BJD  Added power-off capability
+ *     10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
+ *     14-Mar-2006 BJD  void __iomem fixes
 */
 
 #include <linux/kernel.h>
@@ -52,8 +55,8 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-//#include <asm/debug-ll.h>
 #include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
 
 #include "clock.h"
 #include "devs.h"
@@ -61,10 +64,10 @@
 #include "usb-simtec.h"
 
 /* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((item) + BAST_VAM_CS5)
-#define VA_C4(item) ((item) + BAST_VAM_CS4)
-#define VA_C3(item) ((item) + BAST_VAM_CS3)
-#define VA_C2(item) ((item) + BAST_VAM_CS2)
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
 
 /* macros to modify the physical addresses for io space */
 
@@ -76,8 +79,8 @@
 static struct map_desc vr1000_iodesc[] __initdata = {
   /* ISA IO areas */
 
-  { S3C2410_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
-  { S3C2410_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
+  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
+  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
 
   /* we could possibly compress the next set down into a set of smaller tables
    * pagetables, but that would mean using an L2 section, and it still means
@@ -85,10 +88,10 @@ static struct map_desc vr1000_iodesc[] _
    */
 
   /* bast CPLD control registers, and external interrupt controls */
-  { VR1000_VA_CTRL1, VR1000_PA_CTRL1,		       SZ_1M, MT_DEVICE },
-  { VR1000_VA_CTRL2, VR1000_PA_CTRL2,		       SZ_1M, MT_DEVICE },
-  { VR1000_VA_CTRL3, VR1000_PA_CTRL3,		       SZ_1M, MT_DEVICE },
-  { VR1000_VA_CTRL4, VR1000_PA_CTRL4,		       SZ_1M, MT_DEVICE },
+  { (u32)VR1000_VA_CTRL1, VR1000_PA_CTRL1,	       SZ_1M, MT_DEVICE },
+  { (u32)VR1000_VA_CTRL2, VR1000_PA_CTRL2,	       SZ_1M, MT_DEVICE },
+  { (u32)VR1000_VA_CTRL3, VR1000_PA_CTRL3,	       SZ_1M, MT_DEVICE },
+  { (u32)VR1000_VA_CTRL4, VR1000_PA_CTRL4,	       SZ_1M, MT_DEVICE },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
@@ -269,6 +272,11 @@ static struct s3c24xx_board vr1000_board
 	.clocks_count  = ARRAY_SIZE(vr1000_clocks),
 };
 
+static void vr1000_power_off(void)
+{
+	s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
+	s3c2410_gpio_setpin(S3C2410_GPB9, 1);
+}
 
 void __init vr1000_map_io(void)
 {
@@ -285,6 +293,8 @@ void __init vr1000_map_io(void)
 
 	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
 
+	pm_power_off = vr1000_power_off;
+
 	s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
@@ -299,7 +309,7 @@ void __init vr1000_init_irq(void)
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
      MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
-     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(vr1000_map_io)
      INITIRQ(vr1000_init_irq)
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -24,6 +24,9 @@
  * Parts based on arch/arm/mach-pxa/pm.c
  *
  * Thanks to Dimitry Andric for debugging
+ *
+ * Modifications:
+ *     10-Mar-2005 LCVR  Changed S3C2410_VA_UART to S3C24XX_VA_UART
 */
 
 #include <linux/config.h>
@@ -144,9 +147,11 @@ static struct sleep_save gpio_save[] = {
 	SAVE_ITEM((va) + S3C2410_UBRDIV)
 
 static struct sleep_save uart_save[] = {
-	SAVE_UART(S3C2410_VA_UART0),
-	SAVE_UART(S3C2410_VA_UART1),
-	SAVE_UART(S3C2410_VA_UART2),
+	SAVE_UART(S3C24XX_VA_UART0),
+	SAVE_UART(S3C24XX_VA_UART1),
+#ifndef CONFIG_CPU_S3C2400
+	SAVE_UART(S3C24XX_VA_UART2),
+#endif
 };
 
 /* debug
@@ -391,7 +396,7 @@ void s3c2410_pm_do_save(struct sleep_sav
 {
 	for (; count > 0; count--, ptr++) {
 		ptr->val = __raw_readl(ptr->reg);
-		DBG("saved %08lx value %08lx\n", ptr->reg, ptr->val);
+		DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
 	}
 }
 
@@ -406,7 +411,7 @@ void s3c2410_pm_do_save(struct sleep_sav
 void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
 {
 	for (; count > 0; count--, ptr++) {
-		printk(KERN_DEBUG "restore %08lx (restore %08lx, was %08x)\n",
+		printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
 		       ptr->reg, ptr->val, __raw_readl(ptr->reg));
 
 		__raw_writel(ptr->val, ptr->reg);
diff --git a/arch/arm/mach-s3c2410/pm.h b/arch/arm/mach-s3c2410/pm.h
--- a/arch/arm/mach-s3c2410/pm.h
+++ b/arch/arm/mach-s3c2410/pm.h
@@ -48,7 +48,7 @@ extern unsigned long s3c2410_sleep_save_
 /* sleep save info */
 
 struct sleep_save {
-	unsigned long	reg;
+	void __iomem	*reg;
 	unsigned long	val;
 };
 
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -17,7 +17,7 @@
  *     21-Aug-2004 BJD  Added new struct s3c2410_board handler
  *     28-Sep-2004 BJD  Updates for new serial port bits
  *     04-Nov-2004 BJD  Updated UART configuration process
- *     10-Jan-2004 BJD  Removed s3c2410_clock_tick_rate
+ *     10-Jan-2005 BJD  Removed s3c2410_clock_tick_rate
 */
 
 #include <linux/kernel.h>
@@ -164,31 +164,32 @@ void __init s3c2410_map_io(struct map_de
 void __init s3c2410_init_clocks(int xtal)
 {
 	unsigned long tmp;
+	unsigned long fclk;
+	unsigned long hclk;
+	unsigned long pclk;
 
 	/* now we've got our machine bits initialised, work out what
 	 * clocks we've got */
 
-	s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
-				       s3c24xx_xtal);
+	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
 
 	tmp = __raw_readl(S3C2410_CLKDIVN);
 
 	/* work out clock scalings */
 
-	s3c24xx_hclk = s3c24xx_fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
-	s3c24xx_pclk = s3c24xx_hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
+	hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
+	pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
 
 	/* print brieft summary of clocks, etc */
 
 	printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-	       print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
-	       print_mhz(s3c24xx_pclk));
+	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
 	/* initialise the clocks here, to allow other things like the
 	 * console to use them
 	 */
 
-	s3c24xx_setup_clocks();
+	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
 }
 
 int __init s3c2410_init(void)
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c
--- a/arch/arm/mach-s3c2410/s3c2440-dsc.c
+++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c
@@ -37,7 +37,7 @@
 
 int s3c2440_set_dsc(unsigned int pin, unsigned int value)
 {
-	unsigned long base;
+	void __iomem *base;
 	unsigned long val;
 	unsigned long flags;
 	unsigned long mask;
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2410/s3c2440.c
@@ -109,7 +109,6 @@ static struct platform_device s3c_uart0 
 	.resource	  = s3c_uart0_resource,
 };
 
-
 static struct platform_device s3c_uart1 = {
 	.name		  = "s3c2440-uart",
 	.id		  = 1,
@@ -149,19 +148,6 @@ void __init s3c2440_init_uarts(struct s3
 	s3c2440_uart_count = uart;
 }
 
-/* s3c2440 specific clock sources */
-
-static struct clk s3c2440_clk_cam = {
-	.name		= "camera",
-	.enable		= s3c24xx_clkcon_enable,
-	.ctrlbit	= S3C2440_CLKCON_CAMERA
-};
-
-static struct clk s3c2440_clk_ac97 = {
-	.name		= "ac97",
-	.enable		= s3c24xx_clkcon_enable,
-	.ctrlbit	= S3C2440_CLKCON_CAMERA
-};
 
 #ifdef CONFIG_PM
 
@@ -173,7 +159,7 @@ struct sleep_save s3c2440_sleep[] = {
 	SAVE_ITEM(S3C2440_GPJUP)
 };
 
-static int s3c2440_suspend(struct sys_device *dev, u32 state)
+static int s3c2440_suspend(struct sys_device *dev, pm_message_t state)
 {
 	s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
 	return 0;
@@ -190,7 +176,7 @@ static int s3c2440_resume(struct sys_dev
 #define s3c2440_resume  NULL
 #endif
 
-static struct sysdev_class s3c2440_sysclass = {
+struct sysdev_class s3c2440_sysclass = {
 	set_kset_name("s3c2440-core"),
 	.suspend	= s3c2440_suspend,
 	.resume		= s3c2440_resume
@@ -206,22 +192,29 @@ void __init s3c2440_map_io(struct map_de
 
 	iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
 	iotable_init(mach_desc, size);
+
 	/* rename any peripherals used differing from the s3c2410 */
 
-	s3c_device_i2c.name = "s3c2440-i2c";
+	s3c_device_i2c.name  = "s3c2440-i2c";
+	s3c_device_nand.name = "s3c2440-nand";
+
+	/* change irq for watchdog */
+
+	s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
+	s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT;
 }
 
 void __init s3c2440_init_clocks(int xtal)
 {
 	unsigned long clkdiv;
 	unsigned long camdiv;
-	int s3c2440_hdiv = 1;
+	unsigned long hclk, fclk, pclk;
+	int hdiv = 1;
 
 	/* now we've got our machine bits initialised, work out what
 	 * clocks we've got */
 
-	s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
-				       s3c24xx_xtal) * 2;
+	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
 
 	clkdiv = __raw_readl(S3C2410_CLKDIVN);
 	camdiv = __raw_readl(S3C2440_CAMDIVN);
@@ -230,63 +223,60 @@ void __init s3c2440_init_clocks(int xtal
 
 	switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
 	case S3C2440_CLKDIVN_HDIVN_1:
-		s3c2440_hdiv = 1;
+		hdiv = 1;
 		break;
 
 	case S3C2440_CLKDIVN_HDIVN_2:
-		s3c2440_hdiv = 1;
+		hdiv = 2;
 		break;
 
 	case S3C2440_CLKDIVN_HDIVN_4_8:
-		s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
 		break;
 
 	case S3C2440_CLKDIVN_HDIVN_3_6:
-		s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
+		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
 		break;
 	}
 
-	s3c24xx_hclk = s3c24xx_fclk / s3c2440_hdiv;
-	s3c24xx_pclk = s3c24xx_hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
+	hclk = fclk / hdiv;
+	pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
 
 	/* print brief summary of clocks, etc */
 
 	printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-	       print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
-	       print_mhz(s3c24xx_pclk));
+	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
 	/* initialise the clocks here, to allow other things like the
 	 * console to use them, and to add new ones after the initialisation
 	 */
 
-	s3c24xx_setup_clocks();
-
-	/* add s3c2440 specific clocks */
-
-	s3c2440_clk_cam.parent = clk_get(NULL, "hclk");
-	s3c2440_clk_ac97.parent = clk_get(NULL, "pclk");
+	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+}
 
-	s3c24xx_register_clock(&s3c2440_clk_ac97);
-	s3c24xx_register_clock(&s3c2440_clk_cam);
+/* need to register class before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
 
-	clk_disable(&s3c2440_clk_ac97);
-	clk_disable(&s3c2440_clk_cam);
+int __init s3c2440_core_init(void)
+{
+	return sysdev_class_register(&s3c2440_sysclass);
 }
 
+core_initcall(s3c2440_core_init);
+
 int __init s3c2440_init(void)
 {
 	int ret;
 
 	printk("S3C2440: Initialising architecture\n");
 
-	ret = sysdev_class_register(&s3c2440_sysclass);
-	if (ret == 0)
-		ret = sysdev_register(&s3c2440_sysdev);
-
+	ret = sysdev_register(&s3c2440_sysdev);
 	if (ret != 0)
 		printk(KERN_ERR "failed to register sysdev for s3c2440\n");
-
-	if (ret == 0)
+	else
 		ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count);
 
 	return ret;
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/mach-s3c2410/time.c
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/time.c
  *
- * Copyright (C) 2003,2004 Simtec Electronics
+ * Copyright (C) 2003-2005 Simtec Electronics
  *	Ben Dooks, <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,8 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/err.h>
+
 #include <asm/system.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
@@ -33,6 +35,7 @@
 #include <asm/arch/regs-timer.h>
 #include <asm/arch/regs-irq.h>
 #include <asm/mach/time.h>
+#include <asm/hardware/clock.h>
 
 #include "clock.h"
 
@@ -169,6 +172,9 @@ static void s3c2410_timer_setup (void)
 		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
 		tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
 	} else {
+		unsigned long pclk;
+		struct clk *clk;
+
 		/* for the h1940 (and others), we use the pclk from the core
 		 * to generate the timer values. since values around 50 to
 		 * 70MHz are not values we can directly generate the timer
@@ -180,7 +186,18 @@ static void s3c2410_timer_setup (void)
 
 		/* this is used as default if no other timer can be found */
 
-		timer_usec_ticks = timer_mask_usec_ticks(6, s3c24xx_pclk);
+		clk = clk_get(NULL, "timers");
+		if (IS_ERR(clk))
+			panic("failed to get clock for system timer");
+
+		clk_use(clk);
+		clk_enable(clk);
+
+		pclk = clk_get_rate(clk);
+
+		/* configure clock tick */
+
+		timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
 
 		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
 		tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
@@ -188,7 +205,7 @@ static void s3c2410_timer_setup (void)
 		tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
 		tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
 
-		tcnt = (s3c24xx_pclk / 6) / HZ;
+		tcnt = (pclk / 6) / HZ;
 	}
 
 	/* timers reload after counting zero, so reduce the count by 1 */
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
--- a/arch/arm/mach-sa1100/Kconfig
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -11,6 +11,7 @@ config SA1100_ASSABET
 config ASSABET_NEPONSET
 	bool "Include support for Neponset"
 	depends on SA1100_ASSABET
+	select SA1111
 	help
 	  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
 	  Microprocessor Development Board (Assabet)  with the SA-1111
@@ -44,7 +45,9 @@ endchoice
 
 config SA1100_COLLIE
 	bool "Sharp Zaurus SL5500"
-	depends on ARCH_SA1100
+	select SHARP_LOCOMO
+	select SHARP_SCOOP
+	select SHARP_PARAM
 	help
 	  Say Y here to support the Sharp Zaurus SL5500 PDAs.
 
@@ -85,12 +88,14 @@ config SA1100_H3XXX
 
 config SA1100_BADGE4
 	bool "HP Labs BadgePAD 4"
+	select SA1111
 	help
 	  Say Y here if you want to build a kernel for the HP Laboratories
 	  BadgePAD 4.
 
 config SA1100_JORNADA720
 	bool "HP Jornada 720"
+	select SA1111
 	help
 	  Say Y here if you want to build a kernel for the HP Jornada 720
 	  handheld computer.  See <http://www.hp.com/jornada/products/720>
@@ -145,7 +150,7 @@ config SA1100_SSP
 
 config H3600_SLEEVE
 	tristate "Compaq iPAQ Handheld sleeve support"
-	depends on SA1100_H3600
+	depends on SA1100_H3100 || SA1100_H3600
 	help
 	  Choose this option to enable support for extension packs (sleeves)
 	  for the Compaq iPAQ H3XXX series of handheld computers.  This option
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -259,9 +259,11 @@ static void __init map_sa1100_gpio_regs(
 	unsigned long phys = __PREG(GPLR) & PMD_MASK;
 	unsigned long virt = io_p2v(phys);
 	int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
-	pmd_t pmd;
-	pmd_val(pmd) = phys | prot;
-	set_pmd(pmd_offset(pgd_offset_k(virt), virt), pmd);
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pgd_offset_k(virt), virt);
+	*pmd = __pmd(phys | prot);
+	flush_pmd_entry(pmd);
 }
 
 /*
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -38,6 +38,7 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include <asm/hardware/scoop.h>
+#include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
 
 #include "generic.h"
@@ -55,7 +56,7 @@ static struct scoop_config collie_scoop_
 	.io_out		= COLLIE_SCOOP_IO_OUT,
 };
 
-static struct platform_device colliescoop_device = {
+struct platform_device colliescoop_device = {
 	.name		= "sharp-scoop",
 	.id		= -1,
 	.dev		= {
@@ -166,6 +167,8 @@ static void __init collie_init(void)
 
 	sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources,
 			      ARRAY_SIZE(collie_flash_resources));
+
+	sharpsl_save_param();
 }
 
 static struct map_desc collie_io_desc[] __initdata = {
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -130,7 +130,7 @@ static int h3600_irda_set_power(struct d
 	return 0;
 }
 
-static void h3600_irda_set_speed(struct device *dev, int speed)
+static void h3600_irda_set_speed(struct device *dev, unsigned int speed)
 {
 	if (speed < 4000000) {
 		clr_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -218,7 +218,7 @@ static struct sa1100irq_state {
 	unsigned int	iccr;
 } sa1100irq_state;
 
-static int sa1100irq_suspend(struct sys_device *dev, u32 state)
+static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
 {
 	struct sa1100irq_state *st = &sa1100irq_state;
 
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -178,7 +178,7 @@ static int neponset_probe(struct device 
 /*
  * LDM power management.
  */
-static int neponset_suspend(struct device *dev, u32 state, u32 level)
+static int neponset_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	/*
 	 * Save state.
@@ -266,6 +266,7 @@ static struct platform_device sa1111_dev
 
 static struct resource smc91x_resources[] = {
 	[0] = {
+		.name	= "smc91x-regs",
 		.start	= SA1100_CS3_PHYS,
 		.end	= SA1100_CS3_PHYS + 0x01ffffff,
 		.flags	= IORESOURCE_MEM,
@@ -276,6 +277,7 @@ static struct resource smc91x_resources[
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
+		.name	= "smc91x-attrib",
 		.start	= SA1100_CS3_PHYS + 0x02000000,
 		.end	= SA1100_CS3_PHYS + 0x03ffffff,
 		.flags	= IORESOURCE_MEM,
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -543,7 +543,7 @@ static void versatile_clcd_enable(struct
 		val |= SYS_CLCD_MODE_5551;
 		break;
 	case 6:
-		val |= SYS_CLCD_MODE_565_BLSB;
+		val |= SYS_CLCD_MODE_565_RLSB;
 		break;
 	case 8:
 		val |= SYS_CLCD_MODE_888;
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -228,7 +228,6 @@ config CPU_SA1100
 	select CPU_CACHE_V4WB
 	select CPU_CACHE_VIVT
 	select CPU_TLB_V4WB
-	select CPU_MINICACHE
 
 # XScale
 config CPU_XSCALE
@@ -239,7 +238,6 @@ config CPU_XSCALE
 	select CPU_ABRT_EV5T
 	select CPU_CACHE_VIVT
 	select CPU_TLB_V4WBI
-	select CPU_MINICACHE
 
 # ARMv6
 config CPU_V6
@@ -345,11 +343,6 @@ config CPU_TLB_V4WBI
 config CPU_TLB_V6
 	bool
 
-config CPU_MINICACHE
-	bool
-	help
-	  Processor has a minicache.
-
 comment "Processor Features"
 
 config ARM_THUMB
@@ -409,3 +402,31 @@ config CPU_BPREDICT_DISABLE
 	depends on CPU_ARM1020
 	help
 	  Say Y here to disable branch prediction.  If unsure, say N.
+
+config TLS_REG_EMUL
+	bool
+	default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3)
+	help
+	  An SMP system using a pre-ARMv6 processor (there are apparently
+	  a few prototypes like that in existence) and therefore access to
+	  that required register must be emulated.
+
+config HAS_TLS_REG
+	bool
+	depends on !TLS_REG_EMUL
+	default y if SMP || CPU_32v7
+	help
+	  This selects support for the CP15 thread register.
+	  It is defined to be available on some ARMv6 processors (including
+	  all SMP capable ARMv6's) or later processors.  User space may
+	  assume directly accessing that register and always obtain the
+	  expected value only on ARMv7 and above.
+
+config NEEDS_SYSCALL_FOR_CMPXCHG
+	bool
+	default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3)
+	help
+	  SMP on a pre-ARMv6 processor?  Well OK then.
+	  Forget about fast user space cmpxchg support.
+	  It is just not possible.
+
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -31,8 +31,6 @@ obj-$(CONFIG_CPU_COPY_V6)	+= copypage-v6
 obj-$(CONFIG_CPU_SA1100)	+= copypage-v4mc.o
 obj-$(CONFIG_CPU_XSCALE)	+= copypage-xscale.o
 
-obj-$(CONFIG_CPU_MINICACHE)	+= minicache.o
-
 obj-$(CONFIG_CPU_TLB_V3)	+= tlb-v3.o
 obj-$(CONFIG_CPU_TLB_V4WT)	+= tlb-v4.o
 obj-$(CONFIG_CPU_TLB_V4WB)	+= tlb-v4wb.o
diff --git a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S
--- a/arch/arm/mm/abort-ev4t.S
+++ b/arch/arm/mm/abort-ev4t.S
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "abort-macro.S"
 /*
  * Function: v4t_early_abort
  *
@@ -21,11 +22,9 @@
 ENTRY(v4t_early_abort)
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	tst	r3, #PSR_T_BIT
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	do_thumb_abort
 	ldreq	r3, [r2]			@ read aborted ARM instruction
 	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
 	tst	r3, #1 << 20			@ check write
 	orreq	r1, r1, #1 << 11
 	mov	pc, lr
diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S
--- a/arch/arm/mm/abort-ev5t.S
+++ b/arch/arm/mm/abort-ev5t.S
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "abort-macro.S"
 /*
  * Function: v5t_early_abort
  *
@@ -21,11 +22,10 @@
 ENTRY(v5t_early_abort)
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	tst	r3, #PSR_T_BIT
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	do_thumb_abort
 	ldreq	r3, [r2]			@ read aborted ARM instruction
 	bic	r1, r1, #1 << 11		@ clear bits 11 of FSR
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	do_ldrd_abort
 	tst	r3, #1 << 20			@ check write
 	orreq	r1, r1, #1 << 11
 	mov	pc, lr
diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S
--- a/arch/arm/mm/abort-ev5tj.S
+++ b/arch/arm/mm/abort-ev5tj.S
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "abort-macro.S"
 /*
  * Function: v5tj_early_abort
  *
@@ -24,10 +25,9 @@ ENTRY(v5tj_early_abort)
 	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
 	tst	r3, #PSR_J_BIT			@ Java?
 	movne	pc, lr
-	tst	r3, #PSR_T_BIT			@ Thumb?
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	do_thumb_abort
 	ldreq	r3, [r2]			@ read aborted ARM instruction
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	do_ldrd_abort
 	tst	r3, #1 << 20			@ L = 0 -> write
 	orreq	r1, r1, #1 << 11		@ yes.
 	mov	pc, lr
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
--- a/arch/arm/mm/abort-ev6.S
+++ b/arch/arm/mm/abort-ev6.S
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "abort-macro.S"
 /*
  * Function: v6_early_abort
  *
@@ -13,11 +14,26 @@
  *	   : sp = pointer to registers
  *
  * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  */
 	.align	5
 ENTRY(v6_early_abort)
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+/*
+ * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR.
+ * The test below covers all the write situations, including Java bytecodes
+ */
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
+	tst	r3, #PSR_J_BIT			@ Java?
+	movne	pc, lr
+	do_thumb_abort
+	ldreq	r3, [r2]			@ read aborted ARM instruction
+	do_ldrd_abort
+	tst	r3, #1 << 20			@ L = 0 -> write
+	orreq	r1, r1, #1 << 11		@ yes.
 	mov	pc, lr
 
 
diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S
new file mode 100644
--- /dev/null
+++ b/arch/arm/mm/abort-macro.S
@@ -0,0 +1,42 @@
+/*
+ * The ARM LDRD and Thumb LDRSB instructions use bit 20/11 (ARM/Thumb)
+ * differently than every other instruction, so it is set to 0 (write)
+ * even though the instructions are read instructions. This means that
+ * during an abort the instructions will be treated as a write and the
+ * handler will raise a signal from unwriteable locations if they
+ * fault. We have to specifically check for these instructions
+ * from the abort handlers to treat them properly.
+ *
+ */
+
+	.macro	do_thumb_abort
+	tst	r3, #PSR_T_BIT
+	beq	not_thumb
+	ldrh	r3, [r2]			@ Read aborted Thumb instruction
+	and	r3, r3, # 0xfe00		@ Mask opcode field
+	cmp	r3, # 0x5600			@ Is it ldrsb?
+	orreq	r3, r3, #1 << 11		@ Set L-bit if yes
+	tst	r3, #1 << 11			@ L = 0 -> write
+	orreq	r1, r1, #1 << 11		@ yes.
+	mov	pc, lr
+not_thumb:
+	.endm
+
+/*
+ * We check for the following insturction encoding for LDRD.
+ *
+ * [27:25] == 0
+ *   [7:4] == 1101
+ *    [20] == 0
+ */
+ 	.macro	do_ldrd_abort
+ 	tst	r3, #0x0e000000			@ [27:25] == 0
+	bne	not_ldrd
+	and	r2, r3, #0x000000f0		@ [7:4] == 1101
+	cmp	r2, #0x000000d0
+	bne	not_ldrd
+	tst	r3, #1 << 20			@ [20] == 0
+	moveq	pc, lr
+not_ldrd:
+	.endm
+
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -323,7 +323,7 @@ EXPORT_SYMBOL(dma_mmap_writecombine);
 void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
 {
 	struct vm_region *c;
-	unsigned long flags;
+	unsigned long flags, addr;
 	pte_t *ptep;
 
 	size = PAGE_ALIGN(size);
@@ -342,11 +342,13 @@ void dma_free_coherent(struct device *de
 	}
 
 	ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+	addr = c->vm_start;
 	do {
-		pte_t pte = ptep_get_and_clear(ptep);
+		pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
 		unsigned long pfn;
 
 		ptep++;
+		addr += PAGE_SIZE;
 
 		if (!pte_none(pte) && pte_present(pte)) {
 			pfn = pte_pfn(pte);
diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S
deleted file mode 100644
--- a/arch/arm/mm/copypage-v4mc.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/arch/arm/lib/copy_page-armv4mc.S
- *
- *  Copyright (C) 1995-2001 Russell King
- *
- * 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.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/constants.h>
-
-	.text
-	.align	5
-/*
- * ARMv4 mini-dcache optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(v4_mc_copy_user_page)
-	stmfd	sp!, {r4, lr}			@ 2
-	mov	r4, r0
-	mov	r0, r1
-	bl	map_page_minicache
-	mov	r1, #PAGE_SZ/64			@ 1
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-1:	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4+1
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmneia	r0!, {r2, r3, ip, lr}		@ 4
-	bne	1b				@ 1
-	ldmfd	sp!, {r4, pc}			@ 3
-
-	.align	5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(v4_mc_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/64			@ 1
-	mov	r2, #0				@ 1
-	mov	r3, #0				@ 1
-	mov	ip, #0				@ 1
-	mov	lr, #0				@ 1
-1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	bne	1b				@ 1
-	ldr	pc, [sp], #4
-
-	__INITDATA
-
-	.type	v4_mc_user_fns, #object
-ENTRY(v4_mc_user_fns)
-	.long	v4_mc_clear_user_page
-	.long	v4_mc_copy_user_page
-	.size	v4_mc_user_fns, . - v4_mc_user_fns
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -0,0 +1,111 @@
+/*
+ *  linux/arch/arm/lib/copypage-armv4mc.S
+ *
+ *  Copyright (C) 1995-2005 Russell King
+ *
+ * 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 handles the mini data cache, as found on SA11x0 and XScale
+ * processors.  When we copy a user page page, we map it in such a way
+ * that accesses to this page will not touch the main data cache, but
+ * will be cached in the mini data cache.  This prevents us thrashing
+ * the main data cache on page faults.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+ */
+#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+				  L_PTE_CACHEABLE)
+
+#define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
+
+static DEFINE_SPINLOCK(minicache_lock);
+
+/*
+ * ARMv4 mini-dcache optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_page that does the right thing.
+ */
+static void __attribute__((naked))
+mc_copy_user_page(void *from, void *to)
+{
+	asm volatile(
+	"stmfd	sp!, {r4, lr}			@ 2\n\
+	mov	r4, %2				@ 1\n\
+	ldmia	%0!, {r2, r3, ip, lr}		@ 4\n\
+1:	mcr	p15, 0, %1, c7, c6, 1		@ 1   invalidate D line\n\
+	stmia	%1!, {r2, r3, ip, lr}		@ 4\n\
+	ldmia	%0!, {r2, r3, ip, lr}		@ 4+1\n\
+	stmia	%1!, {r2, r3, ip, lr}		@ 4\n\
+	ldmia	%0!, {r2, r3, ip, lr}		@ 4\n\
+	mcr	p15, 0, %1, c7, c6, 1		@ 1   invalidate D line\n\
+	stmia	%1!, {r2, r3, ip, lr}		@ 4\n\
+	ldmia	%0!, {r2, r3, ip, lr}		@ 4\n\
+	subs	r4, r4, #1			@ 1\n\
+	stmia	%1!, {r2, r3, ip, lr}		@ 4\n\
+	ldmneia	%0!, {r2, r3, ip, lr}		@ 4\n\
+	bne	1b				@ 1\n\
+	ldmfd	sp!, {r4, pc}			@ 3"
+	:
+	: "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
+}
+
+void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+{
+	spin_lock(&minicache_lock);
+
+	set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+	flush_tlb_kernel_page(0xffff8000);
+
+	mc_copy_user_page((void *)0xffff8000, kto);
+
+	spin_unlock(&minicache_lock);
+}
+
+/*
+ * ARMv4 optimised clear_user_page
+ */
+void __attribute__((naked))
+v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+{
+	asm volatile(
+	"str	lr, [sp, #-4]!\n\
+	mov	r1, %0				@ 1\n\
+	mov	r2, #0				@ 1\n\
+	mov	r3, #0				@ 1\n\
+	mov	ip, #0				@ 1\n\
+	mov	lr, #0				@ 1\n\
+1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line\n\
+	stmia	r0!, {r2, r3, ip, lr}		@ 4\n\
+	stmia	r0!, {r2, r3, ip, lr}		@ 4\n\
+	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line\n\
+	stmia	r0!, {r2, r3, ip, lr}		@ 4\n\
+	stmia	r0!, {r2, r3, ip, lr}		@ 4\n\
+	subs	r1, r1, #1			@ 1\n\
+	bne	1b				@ 1\n\
+	ldr	pc, [sp], #4"
+	:
+	: "I" (PAGE_SIZE / 64));
+}
+
+struct cpu_user_fns v4_mc_user_fns __initdata = {
+	.cpu_clear_user_page	= v4_mc_clear_user_page, 
+	.cpu_copy_user_page	= v4_mc_copy_user_page,
+};
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -26,8 +26,8 @@
 #define to_address	(0xffffc000)
 #define to_pgprot	PAGE_KERNEL
 
-static pte_t *from_pte;
-static pte_t *to_pte;
+#define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
+
 static DEFINE_SPINLOCK(v6_lock);
 
 #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
@@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kt
 	 */
 	spin_lock(&v6_lock);
 
-	set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
-	set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
+	set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
+	set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
 
 	from = from_address + (offset << PAGE_SHIFT);
 	to   = to_address + (offset << PAGE_SHIFT);
@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *k
 	 */
 	spin_lock(&v6_lock);
 
-	set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
+	set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
 	flush_tlb_kernel_page(to);
 	clear_page((void *)to);
 
@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initda
 static int __init v6_userpage_init(void)
 {
 	if (cache_is_vipt_aliasing()) {
-		pgd_t *pgd;
-		pmd_t *pmd;
-
-		pgd = pgd_offset_k(from_address);
-		pmd = pmd_alloc(&init_mm, pgd, from_address);
-		if (!pmd)
-			BUG();
-		from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
-		if (!from_pte)
-			BUG();
-
-		to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
-		if (!to_pte)
-			BUG();
-
 		cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
 		cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
 	}
@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void)
 	return 0;
 }
 
-__initcall(v6_userpage_init);
-
+core_initcall(v6_userpage_init);
diff --git a/arch/arm/mm/copypage-xscale.S b/arch/arm/mm/copypage-xscale.S
deleted file mode 100644
--- a/arch/arm/mm/copypage-xscale.S
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-xscale.S
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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/linkage.h>
-#include <linux/init.h>
-#include <asm/constants.h>
-
-/*
- * General note:
- *  We don't really want write-allocate cache behaviour for these functions
- *  since that will just eat through 8K of the cache.
- */
-
-	.text
-	.align	5
-/*
- * XScale optimised copy_user_page
- *  r0 = destination
- *  r1 = source
- *  r2 = virtual user address of ultimate destination page
- *
- * The source page may have some clean entries in the cache already, but we
- * can safely ignore them - break_cow() will flush them out of the cache
- * if we eventually end up using our copied page.
- *
- * What we could do is use the mini-cache to buffer reads from the source
- * page.  We rely on the mini-cache being smaller than one page, so we'll
- * cycle through the complete cache anyway.
- */
-ENTRY(xscale_mc_copy_user_page)
-	stmfd	sp!, {r4, r5, lr}
-	mov	r5, r0
-	mov	r0, r1
-	bl	map_page_minicache
-	mov	r1, r5
-	mov	lr, #PAGE_SZ/64-1
-
-	/*
-	 * Strangely enough, best performance is achieved
-	 * when prefetching destination as well.  (NP)
-	 */
-	pld	[r0, #0]
-	pld	[r0, #32]
-	pld	[r1, #0]
-	pld	[r1, #32]
-
-1:	pld	[r0, #64]
-	pld	[r0, #96]
-	pld	[r1, #64]
-	pld	[r1, #96]
-
-2:	ldrd	r2, [r0], #8
-	ldrd	r4, [r0], #8
-	mov	ip, r1
-	strd	r2, [r1], #8
-	ldrd	r2, [r0], #8
-	strd	r4, [r1], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	strd	r4, [r1], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	ldrd	r2, [r0], #8
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	ldrd	r4, [r0], #8
-	mov	ip, r1
-	strd	r2, [r1], #8
-	ldrd	r2, [r0], #8
-	strd	r4, [r1], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	strd	r4, [r1], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	subs	lr, lr, #1
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	bgt	1b
-	beq	2b
-
-	ldmfd	sp!, {r4, r5, pc}
-
-	.align	5
-/*
- * XScale optimised clear_user_page
- *  r0 = destination
- *  r1 = virtual user address of ultimate destination page
- */
-ENTRY(xscale_mc_clear_user_page)
-	mov	r1, #PAGE_SZ/32
-	mov	r2, #0
-	mov	r3, #0
-1:	mov	ip, r0
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	subs	r1, r1, #1
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	bne	1b
-	mov	pc, lr
-
-	__INITDATA
-
-	.type	xscale_mc_user_fns, #object
-ENTRY(xscale_mc_user_fns)
-	.long	xscale_mc_clear_user_page
-	.long	xscale_mc_copy_user_page
-	.size	xscale_mc_user_fns, . - xscale_mc_user_fns
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
new file mode 100644
--- /dev/null
+++ b/arch/arm/mm/copypage-xscale.c
@@ -0,0 +1,131 @@
+/*
+ *  linux/arch/arm/lib/copypage-xscale.S
+ *
+ *  Copyright (C) 1995-2005 Russell King
+ *
+ * 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 handles the mini data cache, as found on SA11x0 and XScale
+ * processors.  When we copy a user page page, we map it in such a way
+ * that accesses to this page will not touch the main data cache, but
+ * will be cached in the mini data cache.  This prevents us thrashing
+ * the main data cache on page faults.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+ */
+#define COPYPAGE_MINICACHE	0xffff8000
+
+#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+				  L_PTE_CACHEABLE)
+
+#define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
+
+static DEFINE_SPINLOCK(minicache_lock);
+
+/*
+ * XScale mini-dcache optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ */
+static void __attribute__((naked))
+mc_copy_user_page(void *from, void *to)
+{
+	/*
+	 * Strangely enough, best performance is achieved
+	 * when prefetching destination as well.  (NP)
+	 */
+	asm volatile(
+	"stmfd	sp!, {r4, r5, lr}		\n\
+	mov	lr, %2				\n\
+	pld	[r0, #0]			\n\
+	pld	[r0, #32]			\n\
+	pld	[r1, #0]			\n\
+	pld	[r1, #32]			\n\
+1:	pld	[r0, #64]			\n\
+	pld	[r0, #96]			\n\
+	pld	[r1, #64]			\n\
+	pld	[r1, #96]			\n\
+2:	ldrd	r2, [r0], #8			\n\
+	ldrd	r4, [r0], #8			\n\
+	mov	ip, r1				\n\
+	strd	r2, [r1], #8			\n\
+	ldrd	r2, [r0], #8			\n\
+	strd	r4, [r1], #8			\n\
+	ldrd	r4, [r0], #8			\n\
+	strd	r2, [r1], #8			\n\
+	strd	r4, [r1], #8			\n\
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line\n\
+	ldrd	r2, [r0], #8			\n\
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line\n\
+	ldrd	r4, [r0], #8			\n\
+	mov	ip, r1				\n\
+	strd	r2, [r1], #8			\n\
+	ldrd	r2, [r0], #8			\n\
+	strd	r4, [r1], #8			\n\
+	ldrd	r4, [r0], #8			\n\
+	strd	r2, [r1], #8			\n\
+	strd	r4, [r1], #8			\n\
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line\n\
+	subs	lr, lr, #1			\n\
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line\n\
+	bgt	1b				\n\
+	beq	2b				\n\
+	ldmfd	sp!, {r4, r5, pc}		"
+	:
+	: "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1));
+}
+
+void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+{
+	spin_lock(&minicache_lock);
+
+	set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+	flush_tlb_kernel_page(COPYPAGE_MINICACHE);
+
+	mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
+
+	spin_unlock(&minicache_lock);
+}
+
+/*
+ * XScale optimised clear_user_page
+ */
+void __attribute__((naked))
+xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+{
+	asm volatile(
+	"mov	r1, %0				\n\
+	mov	r2, #0				\n\
+	mov	r3, #0				\n\
+1:	mov	ip, r0				\n\
+	strd	r2, [r0], #8			\n\
+	strd	r2, [r0], #8			\n\
+	strd	r2, [r0], #8			\n\
+	strd	r2, [r0], #8			\n\
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line\n\
+	subs	r1, r1, #1			\n\
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line\n\
+	bne	1b				\n\
+	mov	pc, lr"
+	:
+	: "I" (PAGE_SIZE / 32));
+}
+
+struct cpu_user_fns xscale_mc_user_fns __initdata = {
+	.cpu_clear_user_page	= xscale_mc_clear_user_page, 
+	.cpu_copy_user_page	= xscale_mc_copy_user_page,
+};
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -54,7 +54,7 @@ static int adjust_pte(struct vm_area_str
 	 * fault (ie, is old), we can safely ignore any issues.
 	 */
 	if (pte_present(entry) && pte_val(entry) & shared_pte_mask) {
-		flush_cache_page(vma, address);
+		flush_cache_page(vma, address, pte_pfn(entry));
 		pte_val(entry) &= ~shared_pte_mask;
 		set_pte(pte, entry);
 		flush_tlb_page(vma, address);
@@ -115,7 +115,7 @@ make_coherent(struct vm_area_struct *vma
 	if (aliases)
 		adjust_pte(vma, addr);
 	else
-		flush_cache_page(vma, addr);
+		flush_cache_page(vma, addr, page_to_pfn(page));
 }
 
 /*
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -108,14 +108,15 @@ __do_kernel_fault(struct mm_struct *mm, 
  */
 static void
 __do_user_fault(struct task_struct *tsk, unsigned long addr,
-		unsigned int fsr, int code, struct pt_regs *regs)
+		unsigned int fsr, unsigned int sig, int code,
+		struct pt_regs *regs)
 {
 	struct siginfo si;
 
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_SEGV) {
-		printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
-		       tsk->comm, addr, fsr);
+		printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
+		       tsk->comm, sig, addr, fsr);
 		show_pte(tsk->mm, addr);
 		show_regs(regs);
 	}
@@ -124,11 +125,11 @@ __do_user_fault(struct task_struct *tsk,
 	tsk->thread.address = addr;
 	tsk->thread.error_code = fsr;
 	tsk->thread.trap_no = 14;
-	si.si_signo = SIGSEGV;
+	si.si_signo = sig;
 	si.si_errno = 0;
 	si.si_code = code;
 	si.si_addr = (void __user *)addr;
-	force_sig_info(SIGSEGV, &si, tsk);
+	force_sig_info(sig, &si, tsk);
 }
 
 void
@@ -140,7 +141,7 @@ do_bad_area(struct task_struct *tsk, str
 	 * have no context to handle this fault with.
 	 */
 	if (user_mode(regs))
-		__do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs);
+		__do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
 	else
 		__do_kernel_fault(mm, addr, fsr, regs);
 }
@@ -201,10 +202,11 @@ survive:
 		goto out;
 
 	/*
-	 * If we are out of memory for pid1,
-	 * sleep for a while and retry
+	 * If we are out of memory for pid1, sleep for a while and retry
 	 */
+	up_read(&mm->mmap_sem);
 	yield();
+	down_read(&mm->mmap_sem);
 	goto survive;
 
 check_stack:
@@ -219,7 +221,7 @@ do_page_fault(unsigned long addr, unsign
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
-	int fault;
+	int fault, sig, code;
 
 	tsk = current;
 	mm  = tsk->mm;
@@ -242,55 +244,45 @@ do_page_fault(unsigned long addr, unsign
 		return 0;
 
 	/*
-	 * We had some memory, but were unable to
-	 * successfully fix up this page fault.
-	 */
-	if (fault == 0)
-		goto do_sigbus;
-
-	/*
 	 * If we are in kernel mode at this point, we
 	 * have no context to handle this fault with.
 	 */
 	if (!user_mode(regs))
 		goto no_context;
 
-	if (fault == VM_FAULT_OOM) {
+	switch (fault) {
+	case VM_FAULT_OOM:
 		/*
-		 * We ran out of memory, or some other thing happened to
-		 * us that made us unable to handle the page fault gracefully.
+		 * We ran out of memory, or some other thing
+		 * happened to us that made us unable to handle
+		 * the page fault gracefully.
 		 */
 		printk("VM: killing process %s\n", tsk->comm);
 		do_exit(SIGKILL);
-	} else
-		__do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ?
-				SEGV_ACCERR : SEGV_MAPERR, regs);
-	return 0;
+		return 0;
 
+	case 0:
+		/*
+		 * We had some memory, but were unable to
+		 * successfully fix up this page fault.
+		 */
+		sig = SIGBUS;
+		code = BUS_ADRERR;
+		break;
 
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-do_sigbus:
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
-	tsk->thread.address = addr;
-	tsk->thread.error_code = fsr;
-	tsk->thread.trap_no = 14;
-	force_sig(SIGBUS, tsk);
-#ifdef CONFIG_DEBUG_USER
-	if (user_debug & UDBG_BUS) {
-		printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
-			current->comm, addr, instruction_pointer(regs));
+	default:
+		/*
+		 * Something tried to access memory that
+		 * isn't in our memory map..
+		 */
+		sig = SIGSEGV;
+		code = fault == VM_FAULT_BADACCESS ?
+			SEGV_ACCERR : SEGV_MAPERR;
+		break;
 	}
-#endif
 
-	/* Kernel mode? Handle exceptions or die */
-	if (user_mode(regs))
-		return 0;
+	__do_user_fault(tsk, addr, fsr, sig, code, regs);
+	return 0;
 
 no_context:
 	__do_kernel_fault(mm, addr, fsr, regs);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -13,6 +13,29 @@
 
 #include <asm/cacheflush.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+#define ALIAS_FLUSH_START	0xffff4000
+
+#define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
+
+static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+{
+	unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+
+	set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
+	flush_tlb_kernel_page(to);
+
+	asm(	"mcrr	p15, 0, %1, %0, c14\n"
+	"	mcrr	p15, 0, %1, %0, c5\n"
+	    :
+	    : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES)
+	    : "cc");
+}
+#else
+#define flush_pfn_alias(pfn,vaddr)	do { } while (0)
+#endif
 
 static void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
@@ -37,6 +60,18 @@ static void __flush_dcache_page(struct a
 		return;
 
 	/*
+	 * This is a page cache page.  If we have a VIPT cache, we
+	 * only need to do one flush - which would be at the relevant
+	 * userspace colour, which is congruent with page->index.
+	 */
+	if (cache_is_vipt()) {
+		if (cache_is_vipt_aliasing())
+			flush_pfn_alias(page_to_pfn(page),
+					page->index << PAGE_CACHE_SHIFT);
+		return;
+	}
+
+	/*
 	 * There are possible user space mappings of this page:
 	 * - VIVT cache: we need to also write back and invalidate all user
 	 *   data in the current VM view associated with this page.
@@ -56,9 +91,7 @@ static void __flush_dcache_page(struct a
 		if (!(mpnt->vm_flags & VM_MAYSHARE))
 			continue;
 		offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
-		flush_cache_page(mpnt, mpnt->vm_start + offset);
-		if (cache_is_vipt())
-			break;
+		flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
 	}
 	flush_dcache_mmap_unlock(mapping);
 }
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -223,6 +223,9 @@ find_memend_and_nodes(struct meminfo *mi
 	 * This doesn't seem to be used by the Linux memory
 	 * manager any more.  If we can get rid of it, we
 	 * also get rid of some of the stuff above as well.
+	 *
+	 * Note: max_low_pfn and max_pfn reflect the number
+	 * of _pages_ in the system, not the maximum PFN.
 	 */
 	max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
 	max_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
@@ -501,10 +504,6 @@ void __init paging_init(struct meminfo *
 				bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
 	}
 
-#ifndef CONFIG_DISCONTIGMEM
-	mem_map = contig_page_data.node_mem_map;
-#endif
-
 	/*
 	 * finish off the bad pages once
 	 * the mem_map is initialised
diff --git a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c
deleted file mode 100644
--- a/arch/arm/mm/minicache.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  linux/arch/arm/mm/minicache.c
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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 handles the mini data cache, as found on SA11x0 and XScale
- * processors.  When we copy a user page page, we map it in such a way
- * that accesses to this page will not touch the main data cache, but
- * will be cached in the mini data cache.  This prevents us thrashing
- * the main data cache on page faults.
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-
-/*
- * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
- * specific hacks for copying pages efficiently.
- */
-#define minicache_address (0xffff8000)
-#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
-				  L_PTE_CACHEABLE)
-
-static pte_t *minicache_pte;
-
-/*
- * Note that this is intended to be called only from the copy_user_page
- * asm code; anything else will require special locking to prevent the
- * mini-cache space being re-used.  (Note: probably preempt unsafe).
- *
- * We rely on the fact that the minicache is 2K, and we'll be pushing
- * 4K of data through it, so we don't actually have to specifically
- * flush the minicache when we change the mapping.
- *
- * Note also: assert(PAGE_OFFSET <= virt < high_memory).
- * Unsafe: preempt, kmap.
- */
-unsigned long map_page_minicache(unsigned long virt)
-{
-	set_pte(minicache_pte, pfn_pte(__pa(virt) >> PAGE_SHIFT, minicache_pgprot));
-	flush_tlb_kernel_page(minicache_address);
-
-	return minicache_address;
-}
-
-static int __init minicache_init(void)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-
-	spin_lock(&init_mm.page_table_lock);
-
-	pgd = pgd_offset_k(minicache_address);
-	pmd = pmd_alloc(&init_mm, pgd, minicache_address);
-	if (!pmd)
-		BUG();
-	minicache_pte = pte_alloc_kernel(&init_mm, pmd, minicache_address);
-	if (!minicache_pte)
-		BUG();
-
-	spin_unlock(&init_mm.page_table_lock);
-
-	return 0;
-}
-
-core_initcall(minicache_init);
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel;
 
 EXPORT_SYMBOL(pgprot_kernel);
 
+pmd_t *top_pmd;
+
 struct cachepolicy {
 	const char	policy[16];
 	unsigned int	cr_mask;
@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup);
 
 #define FIRST_KERNEL_PGD_NR	(FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
 
+static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+{
+	return pmd_offset(pgd, virt);
+}
+
+static inline pmd_t *pmd_off_k(unsigned long virt)
+{
+	return pmd_off(pgd_offset_k(virt), virt);
+}
+
 /*
  * need to get a 16k page for level 1
  */
@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd)
 		return;
 
 	/* pgd is always present and good */
-	pmd = (pmd_t *)pgd;
+	pmd = pmd_off(pgd, 0);
 	if (pmd_none(*pmd))
 		goto free;
 	if (pmd_bad(*pmd)) {
@@ -246,13 +258,30 @@ free:
 static inline void
 alloc_init_section(unsigned long virt, unsigned long phys, int prot)
 {
-	pmd_t *pmdp;
+	pmd_t *pmdp = pmd_off_k(virt);
 
-	pmdp = pmd_offset(pgd_offset_k(virt), virt);
 	if (virt & (1 << 20))
 		pmdp++;
 
-	set_pmd(pmdp, __pmd(phys | prot));
+	*pmdp = __pmd(phys | prot);
+	flush_pmd_entry(pmdp);
+}
+
+/*
+ * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
+ */
+static inline void
+alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
+{
+	int i;
+
+	for (i = 0; i < 16; i += 1) {
+		alloc_init_section(virt, phys & SUPERSECTION_MASK,
+				   prot | PMD_SECT_SUPER);
+
+		virt += (PGDIR_SIZE / 2);
+		phys += (PGDIR_SIZE / 2);
+	}
 }
 
 /*
@@ -265,11 +294,9 @@ alloc_init_section(unsigned long virt, u
 static inline void
 alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
 {
-	pmd_t *pmdp;
+	pmd_t *pmdp = pmd_off_k(virt);
 	pte_t *ptep;
 
-	pmdp = pmd_offset(pgd_offset_k(virt), virt);
-
 	if (pmd_none(*pmdp)) {
 		unsigned long pmdval;
 		ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
@@ -292,7 +319,7 @@ alloc_init_page(unsigned long virt, unsi
  */
 static inline void clear_mapping(unsigned long virt)
 {
-	pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
+	pmd_clear(pmd_off_k(virt));
 }
 
 struct mem_types {
@@ -338,6 +365,15 @@ static struct mem_types mem_types[] __in
 	[MT_ROM] = {
 		.prot_sect = PMD_TYPE_SECT,
 		.domain    = DOMAIN_KERNEL,
+	},
+	[MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_WRITE,
+		.prot_l1   = PMD_TYPE_TABLE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
+				PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
+				PMD_SECT_TEX(1),
+		.domain    = DOMAIN_IO,
 	}
 };
 
@@ -384,9 +420,10 @@ static void __init build_mem_type_table(
 		mem_types[MT_MEMORY].prot_sect &= ~PMD_BIT4;
 		mem_types[MT_ROM].prot_sect &= ~PMD_BIT4;
 		/*
-		 * Mark cache clean areas read only from SVC mode
-		 * and no access from userspace.
+		 * Mark cache clean areas and XIP ROM read only
+		 * from SVC mode and no access from userspace.
 		 */
+		mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 	}
@@ -436,7 +473,8 @@ static void __init build_mem_type_table(
  * Create the page directory entries and any necessary
  * page tables for the mapping specified by `md'.  We
  * are able to cope here with varying sizes and address
- * offsets, and we take full advantage of sections.
+ * offsets, and we take full advantage of sections and
+ * supersections.
  */
 static void __init create_mapping(struct map_desc *md)
 {
@@ -483,6 +521,30 @@ static void __init create_mapping(struct
 		length -= PAGE_SIZE;
 	}
 
+	/* N.B.	ARMv6 supersections are only defined to work with domain 0.
+	 *	Since domain assignments can in fact be arbitrary, the
+	 *	'domain == 0' check below is required to insure that ARMv6
+	 *	supersections are only allocated for domain 0 regardless
+	 *	of the actual domain assignments in use.
+	 */
+	if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) {
+		/* Align to supersection boundary */
+		while ((virt & ~SUPERSECTION_MASK || (virt + off) &
+			~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) {
+			alloc_init_section(virt, virt + off, prot_sect);
+
+			virt   += (PGDIR_SIZE / 2);
+			length -= (PGDIR_SIZE / 2);
+		}
+
+		while (length >= SUPERSECTION_SIZE) {
+			alloc_init_supersection(virt, virt + off, prot_sect);
+
+			virt   += SUPERSECTION_SIZE;
+			length -= SUPERSECTION_SIZE;
+		}
+	}
+
 	/*
 	 * A section mapping covers half a "pgdir" entry.
 	 */
@@ -525,9 +587,10 @@ void setup_mm_for_reboot(char mode)
 			 PMD_TYPE_SECT;
 		if (cpu_arch <= CPU_ARCH_ARMv5)
 			pmdval |= PMD_BIT4;
-		pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
-		set_pmd(pmd, __pmd(pmdval));
-		set_pmd(pmd + 1, __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))));
+		pmd = pmd_off(pgd, i << PGDIR_SHIFT);
+		pmd[0] = __pmd(pmdval);
+		pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+		flush_pmd_entry(pmd);
 	}
 }
 
@@ -621,6 +684,8 @@ void __init memtable_init(struct meminfo
 
 	flush_cache_all();
 	flush_tlb_all();
+
+	top_pmd = pmd_off_k(0xffff0000);
 }
 
 /*
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -26,7 +26,7 @@ static void pmu_stop(void);
 static int pmu_create_files(struct super_block *, struct dentry *);
 
 #ifdef CONFIG_PM
-static int pmu_suspend(struct sys_device *dev, u32 state)
+static int pmu_suspend(struct sys_device *dev, pm_message_t state)
 {
 	if (pmu_enabled)
 		pmu_stop();
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Thu Jan 6 00:10:23 2005
+# Last update: Thu Mar 24 14:34:50 2005
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -226,7 +226,7 @@ dnp1110			SA1100_DNP1110		DNP1110			214
 pnp1110			SA1100_PNP1110		PNP1110			215
 csb226			ARCH_CSB226		CSB226			216
 arnold			SA1100_ARNOLD		ARNOLD			217
-voiceblue		SA1100_PSIBOARD		PSIBOARD		218
+voiceblue		MACH_VOICEBLUE		VOICEBLUE		218
 jz8028			ARCH_JZ8028		JZ8028			219
 h5400			ARCH_H5400		H5400			220
 forte			SA1100_FORTE		FORTE			221
@@ -381,7 +381,7 @@ s5c7375			ARCH_S5C7375		S5C7375			369
 spearhead		ARCH_SPEARHEAD		SPEARHEAD		370
 pantera			ARCH_PANTERA		PANTERA			371
 prayoglite		ARCH_PRAYOGLITE		PRAYOGLITE		372
-gumstik			ARCH_GUMSTIK		GUMSTIK			373
+gumstix			ARCH_GUMSTIK		GUMSTIK			373
 rcube			ARCH_RCUBE		RCUBE			374
 rea_olv			ARCH_REA_OLV		REA_OLV			375
 pxa_iphone		ARCH_PXA_IPHONE		PXA_IPHONE		376
@@ -649,7 +649,6 @@ zefeerdzg		MACH_ZEFEERDZG		ZEFEERDZG		63
 zefeerdzn		MACH_ZEFEERDZN		ZEFEERDZN		639
 zefeerdzq		MACH_ZEFEERDZQ		ZEFEERDZQ		640
 gtwx5715		MACH_GTWX5715		GTWX5715		641
-unknown			MACH_VL420		VL420			642
 astro_jack		MACH_ASTRO_JACK		ASTRO_JACK		643
 tip03			MACH_TIP03		TIP03			644
 a9200ec			MACH_A9200EC		A9200EC			645
@@ -667,3 +666,61 @@ n30			MACH_N30		N30			656
 manga_ks8695		MACH_MANGA_KS8695	MANGA_KS8695		657
 ajax			MACH_AJAX		AJAX			658
 nec_mp900		MACH_NEC_MP900		NEC_MP900		659
+vvtk1000		MACH_VVTK1000		VVTK1000		661
+kafa			MACH_KAFA		KAFA			662
+vvtk3000		MACH_VVTK3000		VVTK3000		663
+pimx1			MACH_PIMX1		PIMX1			664
+ollie			MACH_OLLIE		OLLIE			665
+skymax			MACH_SKYMAX		SKYMAX			666
+jazz			MACH_JAZZ		JAZZ			667
+tel_t3			MACH_TEL_T3		TEL_T3			668
+aisino_fcr255		MACH_AISINO_FCR255	AISINO_FCR255		669
+btweb			MACH_BTWEB		BTWEB			670
+dbg_lh79520		MACH_DBG_LH79520	DBG_LH79520		671
+cm41xx			MACH_CM41XX		CM41XX			672
+ts72xx			MACH_TS72XX		TS72XX			673
+nggpxa			MACH_NGGPXA		NGGPXA			674
+csb535			MACH_CSB535		CSB535			675
+csb536			MACH_CSB536		CSB536			676
+pxa_trakpod		MACH_PXA_TRAKPOD	PXA_TRAKPOD		677
+praxis			MACH_PRAXIS		PRAXIS			678
+lh75411			MACH_LH75411		LH75411			679
+otom			MACH_OTOM		OTOM			680
+nexcoder_2440		MACH_NEXCODER_2440	NEXCODER_2440		681
+loox410			MACH_LOOX410		LOOX410			682
+westlake		MACH_WESTLAKE		WESTLAKE		683
+nsb			MACH_NSB		NSB			684
+esl_sarva_stn		MACH_ESL_SARVA_STN	ESL_SARVA_STN		685
+esl_sarva_tft		MACH_ESL_SARVA_TFT	ESL_SARVA_TFT		686
+esl_sarva_iad		MACH_ESL_SARVA_IAD	ESL_SARVA_IAD		687
+esl_sarva_acc		MACH_ESL_SARVA_ACC	ESL_SARVA_ACC		688
+typhoon			MACH_TYPHOON		TYPHOON			689
+cnav			MACH_CNAV		CNAV			690
+a730			MACH_A730		A730			691
+netstar			MACH_NETSTAR		NETSTAR			692
+supercon		MACH_PHASEFALE_SUPERCON	PHASEFALE_SUPERCON	693
+shiva1100		MACH_SHIVA1100		SHIVA1100		694
+etexsc			MACH_ETEXSC		ETEXSC			695
+ixdpg465		MACH_IXDPG465		IXDPG465		696
+a9m2410			MACH_A9M2410		A9M2410			697
+a9m2440			MACH_A9M2440		A9M2440			698
+a9m9750			MACH_A9M9750		A9M9750			699
+a9m9360			MACH_A9M9360		A9M9360			700
+unc90			MACH_UNC90		UNC90			701
+eco920			MACH_ECO920		ECO920			702
+satview			MACH_SATVIEW		SATVIEW			703
+roadrunner		MACH_ROADRUNNER		ROADRUNNER		704
+at91rm9200ek		MACH_AT91RM9200EK	AT91RM9200EK		705
+gp32			MACH_GP32		GP32			706
+gem			MACH_GEM		GEM			707
+i858			MACH_I858		I858			708
+hx2750			MACH_HX2750		HX2750			709
+zeusevb			MACH_ZEUSEVB		ZEUSEVB			710
+p700			MACH_P700		P700			711
+cpe			MACH_CPE		CPE			712
+spitz			MACH_SPITZ		SPITZ			713
+nimbra340		MACH_NIMBRA340		NIMBRA340		714
+lpc22xx			MACH_LPC22XX		LPC22XX			715
+omap_comet3		MACH_COMET3		COMET3			716
+omap_comet4		MACH_COMET4		COMET4			717
+csb625			MACH_CSB625		CSB625			718
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -89,6 +89,10 @@ config PAGESIZE_16
           machine with 4MB of memory.
 endmenu
 
+config ISA_DMA_API
+	bool
+	default y
+
 menu "General setup"
 
 # Compressed boot loader in ROM.  Yes, we really want to ask about
diff --git a/arch/arm26/Kconfig.debug b/arch/arm26/Kconfig.debug
--- a/arch/arm26/Kconfig.debug
+++ b/arch/arm26/Kconfig.debug
@@ -38,16 +38,6 @@ config DEBUG_ERRORS
 	  you are concerned with the code size or don't want to see these
 	  messages.
 
-config DEBUG_INFO
-	bool "Include GDB debugging information in kernel binary"
-	help
-	  Say Y here to include source-level debugging information in the
-	  `vmlinux' binary image. This is handy if you want to use gdb or
-	  addr2line to debug the kernel. It has no impact on the in-memory
-	  footprint of the running kernel but it can increase the amount of
-	  time and disk space needed for compilation of the kernel. If in
-	  doubt say N.
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
 	bool "Kernel low-level debugging functions"
diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c
--- a/arch/arm26/kernel/ptrace.c
+++ b/arch/arm26/kernel/ptrace.c
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -591,7 +592,7 @@ static int do_ptrace(int request, struct
 		case PTRACE_SYSCALL:
 		case PTRACE_CONT:
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			if (request == PTRACE_SYSCALL)
 				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -626,7 +627,7 @@ static int do_ptrace(int request, struct
 		 */
 		case PTRACE_SINGLESTEP:
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			child->ptrace |= PT_SINGLESTEP;
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c
--- a/arch/arm26/kernel/setup.c
+++ b/arch/arm26/kernel/setup.c
@@ -74,7 +74,6 @@ unsigned int number_mfm_drives;
 
 struct processor processor;
 
-unsigned char aux_device_present;
 char elf_platform[ELF_PLATFORM_SIZE];
 
 unsigned long phys_initrd_start __initdata = 0;
diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c
--- a/arch/arm26/kernel/signal.c
+++ b/arch/arm26/kernel/signal.c
@@ -102,7 +102,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -114,7 +114,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -186,7 +186,7 @@ asmlinkage int sys_sigreturn(struct pt_r
 
 	frame = (struct sigframe *)regs->ARM_sp;
 
-	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_NSIG_WORDS > 1
@@ -231,7 +231,7 @@ asmlinkage int sys_rt_sigreturn(struct p
 
 	frame = (struct rt_sigframe *)regs->ARM_sp;
 
-	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
--- a/arch/arm26/kernel/sys_arm.c
+++ b/arch/arm26/kernel/sys_arm.c
@@ -64,10 +64,10 @@ inline long do_mmap2(
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
 	/*
-	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * If we are doing a fixed mapping, and address < FIRST_USER_ADDRESS,
 	 * then deny it.
 	 */
-	if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
+	if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS)
 		goto out;
 
 	error = -EBADF;
@@ -121,11 +121,10 @@ sys_arm_mremap(unsigned long addr, unsig
 	unsigned long ret = -EINVAL;
 
 	/*
-	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * If we are doing a fixed mapping, and address < FIRST_USER_ADDRESS,
 	 * then deny it.
 	 */
-	if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
-	    vectors_base() == 0)
+	if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS)
 		goto out;
 
 	down_write(&current->mm->mmap_sem);
diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c
--- a/arch/arm26/mm/init.c
+++ b/arch/arm26/mm/init.c
@@ -309,8 +309,6 @@ void __init paging_init(struct meminfo *
 	free_area_init_node(0, pgdat, zone_size,
 			bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
 
-	mem_map = NODE_DATA(0)->node_mem_map;
-
 	/*
 	 * finish off the bad pages once
 	 * the mem_map is initialised
diff --git a/arch/arm26/mm/small_page.c b/arch/arm26/mm/small_page.c
--- a/arch/arm26/mm/small_page.c
+++ b/arch/arm26/mm/small_page.c
@@ -92,8 +92,7 @@ static unsigned long __get_small_page(in
 		page = list_entry(order->queue.next, struct page, lru);
 again:
 #ifdef PEDANTIC
-		if (USED_MAP(page) & ~order->all_used)
-			PAGE_BUG(page);
+		BUG_ON(USED_MAP(page) & ~order->all_used);
 #endif
 		offset = ffz(USED_MAP(page));
 		SET_USED(page, offset);
@@ -141,8 +140,7 @@ static void __free_small_page(unsigned l
 			goto non_small;
 
 #ifdef PEDANTIC
-		if (USED_MAP(page) & ~order->all_used)
-			PAGE_BUG(page);
+		BUG_ON(USED_MAP(page) & ~order->all_used);
 #endif
 
 		spage = spage >> order->shift;
diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c
--- a/arch/cris/arch-v10/drivers/eeprom.c
+++ b/arch/cris/arch-v10/drivers/eeprom.c
@@ -599,7 +599,7 @@ static ssize_t eeprom_write(struct file 
   int i, written, restart=1;
   unsigned long p;
 
-  if (verify_area(VERIFY_READ, buf, count))
+  if (!access_ok(VERIFY_READ, buf, count))
   {
     return -EFAULT;
   }
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
--- a/arch/cris/arch-v10/drivers/gpio.c
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -355,7 +355,7 @@ static ssize_t gpio_write(struct file * 
 		return -EFAULT;
 	}
     
-	if (verify_area(VERIFY_READ, buf, count)) {
+	if (!access_ok(VERIFY_READ, buf, count)) {
 		return -EFAULT;
 	}
 	clk_mask = priv->clk_mask;
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -184,7 +185,7 @@ sys_ptrace(long request, long pid, long 
 		case PTRACE_CONT:
 			ret = -EIO;
 			
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
                         
 			if (request == PTRACE_SYSCALL) {
@@ -219,7 +220,7 @@ sys_ptrace(long request, long pid, long 
 		case PTRACE_SINGLESTEP:
 			ret = -EIO;
 			
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -125,7 +125,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -137,7 +137,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -231,7 +231,7 @@ asmlinkage int sys_sigreturn(long r10, l
         if (((long)frame) & 3)
                 goto badframe;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_NSIG_WORDS > 1
@@ -273,7 +273,7 @@ asmlinkage int sys_rt_sigreturn(long r10
         if (((long)frame) & 3)
                 goto badframe;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c
--- a/arch/cris/arch-v10/mm/init.c
+++ b/arch/cris/arch-v10/mm/init.c
@@ -184,7 +184,6 @@ paging_init(void)
 	 */
 
 	free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
-	mem_map = contig_page_data.node_mem_map;
 }
 
 /* Initialize remaps of some I/O-ports. It is important that this
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -26,8 +26,6 @@
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
 
-unsigned char aux_device_present;
-
 extern int root_mountflags;
 extern char _etext, _edata, _end;
 
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -348,151 +348,7 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-menu "Kernel hacking"
-
-config DEBUG_KERNEL
-	bool "Kernel debugging"
-	help
-	  Say Y here if you are developing drivers or trying to debug and
-	  identify kernel problems.
-
-config EARLY_PRINTK
-	bool "Early printk"
-	depends on EMBEDDED && DEBUG_KERNEL
-	default n
-	help
-	  Write kernel log output directly into the VGA buffer or to a serial
-	  port.
-
-	  This is useful for kernel debugging when your machine crashes very
-	  early before the console code is initialized. For normal operation
-	  it is not recommended because it looks ugly and doesn't cooperate
-	  with klogd/syslogd or the X server. You should normally N here,
-	  unless you want to debug such a crash.
-
-config DEBUG_STACKOVERFLOW
-	bool "Check for stack overflows"
-	depends on DEBUG_KERNEL
-
-config DEBUG_SLAB
-	bool "Debug memory allocations"
-	depends on DEBUG_KERNEL
-	help
-	  Say Y here to have the kernel do limited verification on memory
-	  allocation as well as poisoning memory on free to catch use of freed
-	  memory.
-
-config MAGIC_SYSRQ
-	bool "Magic SysRq key"
-	depends on DEBUG_KERNEL
-	help
-	  If you say Y here, you will have some control over the system even
-	  if the system crashes for example during kernel debugging (e.g., you
-	  will be able to flush the buffer cache to disk, reboot the system
-	  immediately or dump some status information). This is accomplished
-	  by pressing various keys while holding SysRq (Alt+PrintScreen). It
-	  also works on a serial console (on PC hardware at least), if you
-	  send a BREAK and then within 5 seconds a command keypress. The
-	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
-	  unless you really know what this hack does.
-
-config DEBUG_SPINLOCK
-	bool "Spinlock debugging"
-	depends on DEBUG_KERNEL
-	help
-	  Say Y here and build SMP to catch missing spinlock initialization
-	  and certain other kinds of spinlock errors commonly made.  This is
-	  best used in conjunction with the NMI watchdog so that spinlock
-	  deadlocks are also debuggable.
-
-config DEBUG_SPINLOCK_SLEEP
-	bool "Sleep-inside-spinlock checking"
-	depends on DEBUG_KERNEL
-	help
-	  If you say Y here, various routines which may sleep will become very
-	  noisy if they are called with a spinlock held.
-
-config DEBUG_PAGEALLOC
-	bool "Page alloc debugging"
-	depends on DEBUG_KERNEL
-	help
-	  Unmap pages from the kernel linear mapping after free_pages().
-	  This results in a large slowdown, but helps to find certain types
-	  of memory corruptions.
-
-config DEBUG_HIGHMEM
-	bool "Highmem debugging"
-	depends on DEBUG_KERNEL && HIGHMEM
-	help
-	  This options enables addition error checking for high memory systems.
-	  Disable for production systems.
-
-config DEBUG_INFO
-	bool "Compile the kernel with debug info"
-	depends on DEBUG_KERNEL
-	help
-          If you say Y here the resulting kernel image will include
-	  debugging info resulting in a larger kernel image.
-	  Say Y here only if you plan to use gdb to debug the kernel.
-	  If you don't debug the kernel, you can say N.
-
-config DEBUG_BUGVERBOSE
-	bool "Verbose BUG() reporting"
-	depends on DEBUG_KERNEL
-
-config FRAME_POINTER
-	bool "Compile the kernel with frame pointers"
-	depends on DEBUG_KERNEL
-	help
-	  If you say Y here the resulting kernel image will be slightly larger
-	  and slower, but it will give very useful debugging information.
-	  If you don't debug the kernel, you can say N, but we may not be able
-	  to solve problems without frame pointers.
-
-config GDBSTUB
-	bool "Remote GDB kernel debugging"
-	depends on DEBUG_KERNEL
-	select DEBUG_INFO
-	select FRAME_POINTER
-	help
-	  If you say Y here, it will be possible to remotely debug the kernel
-	  using gdb. This enlarges your kernel ELF image disk size by several
-	  megabytes and requires a machine with more than 16 MB, better 32 MB
-	  RAM to avoid excessive linking time. This is only useful for kernel
-	  hackers. If unsure, say N.
-
-choice
-	prompt "GDB stub port"
-	default GDBSTUB_UART1
-	depends on GDBSTUB
-	help
-	  Select the on-CPU port used for GDB-stub
-
-config GDBSTUB_UART0
-	bool "/dev/ttyS0"
-
-config GDBSTUB_UART1
-	bool "/dev/ttyS1"
-
-endchoice
-
-config GDBSTUB_IMMEDIATE
-	bool "Break into GDB stub immediately"
-	depends on GDBSTUB
-	help
-	  If you say Y here, GDB stub will break into the program as soon as
-	  possible, leaving the program counter at the beginning of
-	  start_kernel() in init/main.c.
-
-config GDB_CONSOLE
-	bool "Console output to GDB"
-	depends on KGDB
-	help
-	  If you are using GDB for remote debugging over a serial port and
-	  would like kernel messages to be formatted into GDB $O packets so
-	  that GDB prints them as program output, say 'Y'.
-
-endmenu
+source "arch/frv/Kconfig.debug"
 
 source "security/Kconfig"
 
diff --git a/arch/frv/Kconfig.debug b/arch/frv/Kconfig.debug
new file mode 100644
--- /dev/null
+++ b/arch/frv/Kconfig.debug
@@ -0,0 +1,74 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+	bool "Early printk"
+	depends on EMBEDDED && DEBUG_KERNEL
+	default n
+	help
+	  Write kernel log output directly into the VGA buffer or to a serial
+	  port.
+
+	  This is useful for kernel debugging when your machine crashes very
+	  early before the console code is initialized. For normal operation
+	  it is not recommended because it looks ugly and doesn't cooperate
+	  with klogd/syslogd or the X server. You should normally N here,
+	  unless you want to debug such a crash.
+
+config DEBUG_STACKOVERFLOW
+	bool "Check for stack overflows"
+	depends on DEBUG_KERNEL
+
+config DEBUG_PAGEALLOC
+	bool "Page alloc debugging"
+	depends on DEBUG_KERNEL
+	help
+	  Unmap pages from the kernel linear mapping after free_pages().
+	  This results in a large slowdown, but helps to find certain types
+	  of memory corruptions.
+
+config GDBSTUB
+	bool "Remote GDB kernel debugging"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	select FRAME_POINTER
+	help
+	  If you say Y here, it will be possible to remotely debug the kernel
+	  using gdb. This enlarges your kernel ELF image disk size by several
+	  megabytes and requires a machine with more than 16 MB, better 32 MB
+	  RAM to avoid excessive linking time. This is only useful for kernel
+	  hackers. If unsure, say N.
+
+choice
+	prompt "GDB stub port"
+	default GDBSTUB_UART1
+	depends on GDBSTUB
+	help
+	  Select the on-CPU port used for GDB-stub
+
+config GDBSTUB_UART0
+	bool "/dev/ttyS0"
+
+config GDBSTUB_UART1
+	bool "/dev/ttyS1"
+
+endchoice
+
+config GDBSTUB_IMMEDIATE
+	bool "Break into GDB stub immediately"
+	depends on GDBSTUB
+	help
+	  If you say Y here, GDB stub will break into the program as soon as
+	  possible, leaving the program counter at the beginning of
+	  start_kernel() in init/main.c.
+
+config GDB_CONSOLE
+	bool "Console output to GDB"
+	depends on GDBSTUB
+	help
+	  If you are using GDB for remote debugging over a serial port and
+	  would like kernel messages to be formatted into GDB $O packets so
+	  that GDB prints them as program output, say 'Y'.
+
+endmenu
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -20,6 +20,7 @@
 #include <linux/user.h>
 #include <linux/config.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -239,7 +240,7 @@ asmlinkage int sys_ptrace(long request, 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -267,7 +268,7 @@ asmlinkage int sys_ptrace(long request, 
 
 	case PTRACE_SINGLESTEP:  /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		ptrace_enable(child);
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -65,9 +65,6 @@ static void __init setup_uclinux_memory(
 
 #ifdef CONFIG_CONSOLE
 extern struct consw *conswitchp;
-#ifdef CONFIG_FRAMEBUFFER
-extern struct consw fb_con;
-#endif
 #endif
 
 #ifdef CONFIG_MB93090_MB00
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -114,7 +114,7 @@ asmlinkage int sys_sigaction(int sig,
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -126,7 +126,7 @@ asmlinkage int sys_sigaction(int sig,
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -197,7 +197,7 @@ asmlinkage int sys_sigreturn(void)
 	sigset_t set;
 	int gr8;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.sc_oldmask))
 		goto badframe;
@@ -225,10 +225,9 @@ asmlinkage int sys_rt_sigreturn(void)
 {
 	struct rt_sigframe __user *frame = (struct rt_sigframe __user *) __frame->sp;
 	sigset_t set;
-	stack_t st;
 	int gr8;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c
--- a/arch/frv/mb93090-mb00/pci-frv.c
+++ b/arch/frv/mb93090-mb00/pci-frv.c
@@ -31,7 +31,7 @@ pcibios_update_resource(struct pci_dev *
 	if (resource < 6) {
 		reg = PCI_BASE_ADDRESS_0 + 4*resource;
 	} else if (resource == PCI_ROM_RESOURCE) {
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 		new |= PCI_ROM_ADDRESS_ENABLE;
 		reg = dev->rom_base_reg;
 	} else {
@@ -43,7 +43,7 @@ pcibios_update_resource(struct pci_dev *
 	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,
+		       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
 		       new, check);
 	}
 }
@@ -128,7 +128,7 @@ static void __init pcibios_allocate_bus_
 					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);
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
 			}
 		}
 		pcibios_allocate_bus_resources(&bus->children);
@@ -170,11 +170,11 @@ static void __init pcibios_allocate_reso
 		}
 		if (!pass) {
 			r = &dev->resource[PCI_ROM_RESOURCE];
-			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+			if (r->flags & IORESOURCE_ROM_ENABLE) {
 				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
 				u32 reg;
 				DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
-				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				r->flags &= ~IORESOURCE_ROM_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);
 			}
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -294,7 +294,7 @@ static void __init pci_fixup_umc_ide(str
 	 */
 	int i;
 
-	printk("PCI: Fixing base address flags for device %s\n", d->slot_name);
+	printk("PCI: Fixing base address flags for device %s\n", pci_name(d));
 	for(i=0; i<4; i++)
 		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
@@ -308,7 +308,7 @@ static void __init pci_fixup_ide_bases(s
 	 */
 	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
 		return;
-	printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
 	for(i=0; i<4; i++) {
 		struct resource *r = &d->resource[i];
 		if ((r->start & ~0x80) == 0x374) {
@@ -326,7 +326,7 @@ static void __init pci_fixup_ide_trash(s
 	 * There exist PCI IDE controllers which have utter garbage
 	 * in first four base registers. Ignore that.
 	 */
-	printk("PCI: IDE base address trash cleared for %s\n", d->slot_name);
+	printk("PCI: IDE base address trash cleared for %s\n", pci_name(d));
 	for(i=0; i<4; i++)
 		d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
 }
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -54,7 +54,7 @@ asmlinkage void ret_from_fork(void);
 void default_idle(void)
 {
 	while(1) {
-		if (need_resched()) {
+		if (!need_resched()) {
 			local_irq_enable();
 			__asm__("sleep");
 			local_irq_disable();
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -24,6 +24,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/config.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -171,7 +172,7 @@ asmlinkage int sys_ptrace(long request, 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
 			ret = -EIO;
-			if ((unsigned long) data >= _NSIG)
+			if (!valid_signal(data))
 				break ;
 			if (request == PTRACE_SYSCALL)
 				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -202,7 +203,7 @@ asmlinkage int sys_ptrace(long request, 
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 			child->exit_code = data;
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -113,7 +113,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -125,7 +125,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -222,7 +222,7 @@ asmlinkage int do_sigreturn(unsigned lon
 	sigset_t set;
 	int er0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 	    (_NSIG_WORDS > 1 &&
@@ -253,7 +253,7 @@ asmlinkage int do_rt_sigreturn(unsigned 
 	sigset_t set;
 	int er0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -183,6 +183,7 @@ config M386
 	  - "Winchip-C6" for original IDT Winchip.
 	  - "Winchip-2" for IDT Winchip 2.
 	  - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+	  - "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
 	  - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
 	  - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above).
 
@@ -310,6 +311,11 @@ config MWINCHIP3D
 	  stores for this CPU, which can increase performance of some
 	  operations.
 
+config MGEODEGX1
+	bool "GeodeGX1"
+	help
+	  Select this for a Geode GX1 (Cyrix MediaGX) chip.
+
 config MCYRIXIII
 	bool "CyrixIII/VIA-C3"
 	help
@@ -360,7 +366,7 @@ config X86_L1_CACHE_SHIFT
 	int
 	default "7" if MPENTIUM4 || X86_GENERIC
 	default "4" if X86_ELAN || M486 || M386
-	default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2
+	default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODEGX1
 	default "6" if MK7 || MK8 || MPENTIUMM
 
 config RWSEM_GENERIC_SPINLOCK
@@ -379,7 +385,7 @@ config GENERIC_CALIBRATE_DELAY
 
 config X86_PPRO_FENCE
 	bool
-	depends on M686 || M586MMX || M586TSC || M586 || M486 || M386
+	depends on M686 || M586MMX || M586TSC || M586 || M486 || M386 || MGEODEGX1
 	default y
 
 config X86_F00F_BUG
@@ -409,7 +415,7 @@ config X86_POPAD_OK
 
 config X86_ALIGNMENT_16
 	bool
-	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2
+	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
 	default y
 
 config X86_GOOD_APIC
@@ -529,9 +535,9 @@ config PREEMPT_BKL
 	  Say N if you are unsure.
 
 config X86_UP_APIC
-	bool "Local APIC support on uniprocessors" if !SMP
-	depends on !(X86_VISWS || X86_VOYAGER)
-	---help---
+	bool "Local APIC support on uniprocessors"
+	depends on !SMP && !(X86_VISWS || X86_VOYAGER)
+	help
 	  A local APIC (Advanced Programmable Interrupt Controller) is an
 	  integrated interrupt controller in the CPU. If you have a single-CPU
 	  system which has a processor with a local APIC, you can say Y here to
@@ -541,36 +547,36 @@ config X86_UP_APIC
 	  performance counters), and the NMI watchdog which detects hard
 	  lockups.
 
-	  If you have a system with several CPUs, you do not need to say Y
-	  here: the local APIC will be used automatically.
-
 config X86_UP_IOAPIC
 	bool "IO-APIC support on uniprocessors"
-	depends on !SMP && X86_UP_APIC
+	depends on X86_UP_APIC
 	help
 	  An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
 	  SMP-capable replacement for PC-style interrupt controllers. Most
-	  SMP systems and a small number of uniprocessor systems have one.
+	  SMP systems and many recent uniprocessor systems have one.
+
 	  If you have a single-CPU system with an IO-APIC, you can say Y here
 	  to use it. If you say Y here even though your machine doesn't have
 	  an IO-APIC, then the kernel will still run with no slowdown at all.
 
-	  If you have a system with several CPUs, you do not need to say Y
-	  here: the IO-APIC will be used automatically.
-
 config X86_LOCAL_APIC
 	bool
-	depends on !SMP && X86_UP_APIC
+	depends on X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER)
 	default y
 
 config X86_IO_APIC
 	bool
-	depends on !SMP && X86_UP_IOAPIC
+	depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER))
+	default y
+
+config X86_VISWS_APIC
+	bool
+	depends on X86_VISWS
 	default y
 
 config X86_TSC
 	bool
-	depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ
+	depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1) && !X86_NUMAQ
 	default y
 
 config X86_MCE
@@ -645,6 +651,24 @@ config I8K
 	  Say Y if you intend to run this kernel on a Dell Inspiron 8000.
 	  Say N otherwise.
 
+config X86_REBOOTFIXUPS
+	bool "Enable X86 board specific fixups for reboot"
+	depends on X86
+	default n
+	---help---
+	  This enables chipset and/or board specific fixups to be done
+	  in order to get reboot to work correctly. This is only needed on
+	  some combinations of hardware and BIOS. The symptom, for which
+	  this config is intended, is when reboot ends with a stalled/hung
+	  system.
+
+	  Currently, the only fixup is for the Geode GX1/CS5530A/TROM2.1.
+	  combination.
+
+	  Say Y if you want to enable the fixup. Currently, it's safe to
+	  enable this option even if you don't need it.
+	  Say N otherwise.
+
 config MICROCODE
 	tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
 	---help---
@@ -769,6 +793,16 @@ config HAVE_ARCH_BOOTMEM_NODE
 	depends on NUMA
 	default y
 
+config HAVE_MEMORY_PRESENT
+	bool
+	depends on DISCONTIGMEM
+	default y
+
+config NEED_NODE_MEMMAP_SIZE
+	bool
+	depends on DISCONTIGMEM
+	default y
+
 config HIGHPTE
 	bool "Allocate 3rd-level pagetables from highmem"
 	depends on HIGHMEM4G || HIGHMEM64G
@@ -888,6 +922,23 @@ config REGPARM
 	generate incorrect output with certain kernel constructs when
 	-mregparm=3 is used.
 
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
 
@@ -1052,21 +1103,6 @@ endmenu
 
 menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
 
-config X86_VISWS_APIC
-	bool
-	depends on X86_VISWS
-	default y
-
-config X86_LOCAL_APIC
-	bool
-	depends on (X86_VISWS || SMP) && !X86_VOYAGER
-	default y
-
-config X86_IO_APIC
-	bool
-	depends on SMP && !(X86_VISWS || X86_VOYAGER)
-	default y
-
 config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
@@ -1127,7 +1163,7 @@ config PCI_DIRECT
 
 config PCI_MMCONFIG
 	bool
-	depends on PCI && (PCI_GOMMCONFIG || (PCI_GOANY && ACPI))
+	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 	select ACPI_BOOT
 	default y
 
@@ -1135,6 +1171,10 @@ source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
 
+config ISA_DMA_API
+	bool
+	default y
+
 config ISA
 	bool "ISA support"
 	depends on !(X86_VOYAGER || X86_VISWS)
@@ -1164,18 +1204,14 @@ config EISA
 source "drivers/eisa/Kconfig"
 
 config MCA
-	bool "MCA support"
-	depends on !(X86_VISWS || X86_VOYAGER)
+	bool "MCA support" if !(X86_VISWS || X86_VOYAGER)
+	default y if X86_VOYAGER
 	help
 	  MicroChannel Architecture is found in some IBM PS/2 machines and
 	  laptops.  It is a bus system similar to PCI or ISA. See
 	  <file:Documentation/mca.txt> (and especially the web page given
 	  there) before attempting to build an MCA bus kernel.
 
-config MCA
-	depends on X86_VOYAGER
-	default y if X86_VOYAGER
-
 source "drivers/mca/Kconfig"
 
 config SCx200
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug
--- a/arch/i386/Kconfig.debug
+++ b/arch/i386/Kconfig.debug
@@ -3,7 +3,7 @@ menu "Kernel hacking"
 source "lib/Kconfig.debug"
 
 config EARLY_PRINTK
-	bool "Early printk" if EMBEDDED
+	bool "Early printk" if EMBEDDED && DEBUG_KERNEL
 	default y
 	help
 	  Write kernel log output directly into the VGA buffer or to a serial
@@ -38,9 +38,12 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
+comment "Page alloc debug is incompatible with Software Suspend on i386"
+	depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
+
 config DEBUG_PAGEALLOC
 	bool "Page alloc debugging"
-	depends on DEBUG_KERNEL
+	depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
 	help
 	  Unmap pages from the kernel linear mapping after free_pages().
 	  This results in a large slowdown, but helps to find certain types
@@ -48,6 +51,7 @@ config DEBUG_PAGEALLOC
 
 config 4KSTACKS
 	bool "Use 4Kb for kernel stacks instead of 8Kb"
+	depends on DEBUG_KERNEL
 	help
 	  If you say Y here the kernel will use a 4Kb stacksize for the
 	  kernel stack attached to each process/thread. This facilitates
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -14,6 +14,8 @@
 # 19990713  Artur Skawina <skawina@geocities.com>
 #           Added '-march' and '-mpreferred-stack-boundary' support
 #
+# 20050320  Kianusch Sayah Karadji <kianusch@sk-tech.net>
+#           Added support for GEODE CPU
 
 LDFLAGS		:= -m elf_i386
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
@@ -52,6 +54,9 @@ cflags-$(CONFIG_MVIAC3_2)	+= $(call cc-o
 # AMD Elan support
 cflags-$(CONFIG_X86_ELAN)	+= -march=i486
 
+# Geode GX1 support
+cflags-$(CONFIG_MGEODEGX1)		+= $(call cc-option,-march=pentium-mmx,-march=i486)
+
 # -mregparm=3 works ok on gcc-3.0 and later
 #
 GCC_VERSION			:= $(call cc-version)
@@ -118,7 +123,7 @@ AFLAGS += $(mflags-y)
 boot := arch/i386/boot
 
 .PHONY: zImage bzImage compressed zlilo bzlilo \
-	zdisk bzdisk fdimage fdimage144 fdimage288 install
+	zdisk bzdisk fdimage fdimage144 fdimage288 install kernel_install
 
 all: bzImage
 
@@ -137,9 +142,13 @@ zlilo bzlilo: vmlinux
 zdisk bzdisk: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zdisk
 
-install fdimage fdimage144 fdimage288: vmlinux
+fdimage fdimage144 fdimage288: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
 
+install: vmlinux
+install kernel_install:
+	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
 prepare: include/asm-$(ARCH)/asm_offsets.h
 CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h
 
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
--- a/arch/i386/boot/bootsect.S
+++ b/arch/i386/boot/bootsect.S
@@ -83,7 +83,7 @@ bugger_off_msg:
 	.ascii	"\n"
 	.ascii	"Remove disk and press any key to reboot . . .\r\n"
 	.byte	0
-	
+
 
 	# Kernel attributes; used by setup
 
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -12,7 +12,6 @@
 #include <linux/linkage.h>
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
-#include <video/edid.h>
 #include <asm/io.h>
 
 /*
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -164,7 +164,7 @@ ramdisk_max:	.long (-__PAGE_OFFSET-(512 
 trampoline:	call	start_of_setup
 		.align 16
 					# The offset at this point is 0x240
-		.space	(0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
+		.space	(0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
 # End of setup header #####################################################
 
 start_of_setup:
@@ -333,9 +333,9 @@ jmpe820:
 	# sizeof(e820rec).
 	#
 good820:
-	movb	(E820NR), %al			# up to 32 entries
+	movb	(E820NR), %al			# up to 128 entries
 	cmpb	$E820MAX, %al
-	jnl	bail820
+	jae	bail820
 
 	incb	(E820NR)
 	movw	%di, %ax
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -1924,36 +1924,36 @@ skip10:	movb	%ah, %al
 	ret
 
 store_edid:
-	pushw	%es				# just save all registers 
-	pushw	%ax				
+	pushw	%es				# just save all registers
+	pushw	%ax
 	pushw	%bx
 	pushw   %cx
 	pushw	%dx
 	pushw   %di
 
-	pushw	%fs                             
+	pushw	%fs
 	popw    %es
 
 	movl	$0x13131313, %eax		# memset block with 0x13
 	movw    $32, %cx
 	movw	$0x140, %di
 	cld
-	rep 
-	stosl  
+	rep
+	stosl
 
-	movw	$0x4f15, %ax                    # do VBE/DDC 
+	movw	$0x4f15, %ax                    # do VBE/DDC
 	movw	$0x01, %bx
 	movw	$0x00, %cx
 	movw    $0x01, %dx
 	movw	$0x140, %di
-	int	$0x10	
+	int	$0x10
 
-	popw	%di				# restore all registers        
+	popw	%di				# restore all registers
 	popw	%dx
 	popw	%cx
 	popw	%bx
 	popw	%ax
-	popw	%es	
+	popw	%es
 	ret
 
 # VIDEO_SELECT-only variables
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -802,7 +802,6 @@ CONFIG_AGP=y
 # CONFIG_AGP_AMD is not set
 # CONFIG_AGP_AMD64 is not set
 CONFIG_AGP_INTEL=y
-CONFIG_AGP_INTEL_MCH=m
 # CONFIG_AGP_NVIDIA is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_SWORKS is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoli
 obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
+obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot_fixups.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
@@ -42,11 +43,11 @@ obj-$(CONFIG_SCx200)		+= scx200.o
 # Note: kbuild does not track this dependency due to usage of .incbin
 $(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so
 targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so)
-targets += vsyscall.lds
+targets += vsyscall-note.o vsyscall.lds
 
 # The DSO images are built using a special linker script.
 quiet_cmd_syscall = SYSCALL $@
-      cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
+      cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \
 		          -Wl,-T,$(filter-out FORCE,$^) -o $@
 
 export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH)
@@ -56,7 +57,8 @@ SYSCFLAGS_vsyscall-sysenter.so	= $(vsysc
 SYSCFLAGS_vsyscall-int80.so	= $(vsyscall-flags)
 
 $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
-$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds \
+		      $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE
 	$(call if_changed,syscall)
 
 # We also create a special relocatable object that should mirror the symbol
@@ -67,5 +69,6 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.
 $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
 
 SYSCFLAGS_vsyscall-syms.o = -r
-$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE
+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
+			$(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE
 	$(call if_changed,syscall)
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -608,6 +608,12 @@ static int __init acpi_parse_fadt(unsign
 	acpi_fadt.sci_int = fadt->sci_int;
 #endif
 
+#ifdef CONFIG_ACPI_BUS
+	/* initialize rev and apic_phys_dest_mode for x86_64 genapic */
+	acpi_fadt.revision = fadt->revision;
+	acpi_fadt.force_apic_physical_destination_mode = fadt->force_apic_physical_destination_mode;
+#endif
+
 #ifdef CONFIG_X86_PM_TIMER
 	/* detect the location of the ACPI PM Timer */
 	if (fadt->revision >= FADT2_REVISION_ID) {
@@ -644,7 +650,7 @@ acpi_find_rsdp (void)
 	 */
 	rsdp_phys = acpi_scan_rsdp (0, 0x400);
 	if (!rsdp_phys)
-		rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF);
+		rsdp_phys = acpi_scan_rsdp (0xE0000, 0x20000);
 
 	return rsdp_phys;
 }
diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
--- a/arch/i386/kernel/acpi/sleep.c
+++ b/arch/i386/kernel/acpi/sleep.c
@@ -8,7 +8,7 @@
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
 #include <asm/smp.h>
-
+#include <asm/tlbflush.h>
 
 /* address in low memory of the wakeup routine. */
 unsigned long acpi_wakeup_address = 0;
@@ -27,6 +27,7 @@ static void init_low_mapping(pgd_t *pgd,
 		set_pgd(pgd, *(pgd+USER_PTRS_PER_PGD));
 		pgd_ofs++, pgd++;
 	}
+	flush_tlb_all();
 }
 
 /**
@@ -46,15 +47,6 @@ int acpi_save_state_mem (void)
 	return 0;
 }
 
-/**
- * acpi_save_state_disk - save kernel state to disk
- *
- */
-int acpi_save_state_disk (void)
-{
-	return 1;
-}
-
 /*
  * acpi_restore_state - undo effects of acpi_save_state_mem
  */
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -548,7 +548,7 @@ static struct {
 	unsigned int apic_thmr;
 } apic_pm_state;
 
-static int lapic_suspend(struct sys_device *dev, u32 state)
+static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 {
 	unsigned long flags;
 
@@ -909,7 +909,7 @@ void (*wait_timer_tick)(void) __initdata
 
 #define APIC_DIVISOR 16
 
-void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks)
 {
 	unsigned int lvtt_value, tmp_value, ver;
 
@@ -959,7 +959,7 @@ static void __init setup_APIC_timer(unsi
  * APIC irq that way.
  */
 
-int __init calibrate_APIC_clock(void)
+static int __init calibrate_APIC_clock(void)
 {
 	unsigned long long t1 = 0, t2 = 0;
 	long tt1, tt2;
@@ -1165,7 +1165,7 @@ fastcall void smp_apic_timer_interrupt(s
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
-	irq_stat[cpu].apic_timer_irqs++;
+	per_cpu(irq_stat, cpu).apic_timer_irqs++;
 
 	/*
 	 * NOTE! We'd better ACK the irq immediately,
@@ -1265,8 +1265,6 @@ int __init APIC_init_uniprocessor (void)
 
 	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)
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -166,14 +166,14 @@
  *         If an APM idle fails log it and idle sensibly
  *   1.15: Don't queue events to clients who open the device O_WRONLY.
  *         Don't expect replies from clients who open the device O_RDONLY.
- *         (Idea from Thomas Hood <jdthood@mail.com>)
+ *         (Idea from Thomas Hood)
  *         Minor waitqueue cleanups. (John Fremlin <chief@bandits.org>)
  *   1.16: Fix idle calling. (Andreas Steinmetz <ast@domdv.de> et al.)
  *         Notify listeners of standby or suspend events before notifying
  *         drivers. Return EBUSY to ioctl() if suspend is rejected.
  *         (Russell King <rmk@arm.linux.org.uk> and Thomas Hood)
  *         Ignore first resume after we generate our own resume event
- *         after a suspend (Thomas Hood <jdthood@mail.com>)
+ *         after a suspend (Thomas Hood)
  *         Daemonize now gets rid of our controlling terminal (sfr).
  *         CONFIG_APM_CPU_IDLE now just affects the default value of
  *         idle_threshold (sfr).
@@ -1202,10 +1202,11 @@ static int suspend(int vetoable)
 	}
 
 	device_suspend(PMSG_SUSPEND);
+	local_irq_disable();
 	device_power_down(PMSG_SUSPEND);
 
 	/* serialize with the timer interrupt */
-	write_seqlock_irq(&xtime_lock);
+	write_seqlock(&xtime_lock);
 
 	/* protect against access to timer chip registers */
 	spin_lock(&i8253_lock);
@@ -1216,20 +1217,22 @@ static int suspend(int vetoable)
 	 * We'll undo any timer changes due to interrupts below.
 	 */
 	spin_unlock(&i8253_lock);
-	write_sequnlock_irq(&xtime_lock);
+	write_sequnlock(&xtime_lock);
+	local_irq_enable();
 
 	save_processor_state();
 	err = set_system_power_state(APM_STATE_SUSPEND);
+	ignore_normal_resume = 1;
 	restore_processor_state();
 
-	write_seqlock_irq(&xtime_lock);
+	local_irq_disable();
+	write_seqlock(&xtime_lock);
 	spin_lock(&i8253_lock);
 	reinit_timer();
 	set_time();
-	ignore_normal_resume = 1;
 
 	spin_unlock(&i8253_lock);
-	write_sequnlock_irq(&xtime_lock);
+	write_sequnlock(&xtime_lock);
 
 	if (err == APM_NO_ERROR)
 		err = APM_SUCCESS;
@@ -1237,6 +1240,7 @@ static int suspend(int vetoable)
 		apm_error("suspend", err);
 	err = (err == APM_SUCCESS) ? 0 : -EIO;
 	device_power_up();
+	local_irq_enable();
 	device_resume();
 	pm_send_all(PM_RESUME, (void *)0);
 	queue_event(APM_NORMAL_RESUME, NULL);
@@ -1255,17 +1259,22 @@ static void standby(void)
 {
 	int	err;
 
+	local_irq_disable();
 	device_power_down(PMSG_SUSPEND);
 	/* serialize with the timer interrupt */
-	write_seqlock_irq(&xtime_lock);
+	write_seqlock(&xtime_lock);
 	/* If needed, notify drivers here */
 	get_time_diff();
-	write_sequnlock_irq(&xtime_lock);
+	write_sequnlock(&xtime_lock);
+	local_irq_enable();
 
 	err = set_system_power_state(APM_STATE_STANDBY);
 	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
 		apm_error("standby", err);
+
+	local_irq_disable();
 	device_power_up();
+	local_irq_enable();
 }
 
 static apm_event_t get_event(void)
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include "sigframe.h"
 #include <asm/fixmap.h>
@@ -56,6 +57,11 @@ void foo(void)
 
 	OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
 	OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
+	BLANK();
+
+	OFFSET(pbe_address, pbe, address);
+	OFFSET(pbe_orig_address, pbe, orig_address);
+	OFFSET(pbe_next, pbe, next);
 
 	/* Offset from the sysenter stack to tss.esp0 */
 	DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) -
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -188,23 +188,30 @@ static void __init init_amd(struct cpuin
 	}
 
 	display_cacheinfo(c);
-	detect_ht(c);
-
-#ifdef CONFIG_X86_HT
-	/* AMD dual core looks like HT but isn't really. Hide it from the
-	   scheduler. This works around problems with the domain scheduler.
-	   Also probably gives slightly better scheduling and disables
-	   SMT nice which is harmful on dual core.
-	   TBD tune the domain scheduler for dual core. */
-	if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-		smp_num_siblings = 1;
-#endif
 
 	if (cpuid_eax(0x80000000) >= 0x80000008) {
 		c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
 		if (c->x86_num_cores & (c->x86_num_cores - 1))
 			c->x86_num_cores = 1;
 	}
+
+#ifdef CONFIG_X86_HT
+	/*
+	 * On a AMD dual core setup the lower bits of the APIC id
+	 * distingush the cores.  Assumes number of cores is a power
+	 * of two.
+	 */
+	if (c->x86_num_cores > 1) {
+		int cpu = smp_processor_id();
+		unsigned bits = 0;
+		while ((1 << bits) < c->x86_num_cores)
+			bits++;
+		cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
+		phys_proc_id[cpu] >>= bits;
+		printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
+		       cpu, c->x86_num_cores, cpu_core_id[cpu]);
+	}
+#endif
 }
 
 static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -21,6 +21,9 @@
 DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]);
 EXPORT_PER_CPU_SYMBOL(cpu_gdt_table);
 
+DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
+EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
+
 static int cachesize_override __initdata = -1;
 static int disable_x86_fxsr __initdata = 0;
 static int disable_x86_serial_nr __initdata = 1;
@@ -199,7 +202,7 @@ static inline int flag_is_changeable_p(u
 
 
 /* Probe for the CPUID instruction */
-int __init have_cpuid_p(void)
+static int __init have_cpuid_p(void)
 {
 	return flag_is_changeable_p(X86_EFLAGS_ID);
 }
@@ -207,7 +210,7 @@ int __init have_cpuid_p(void)
 /* Do minimum CPU detection early.
    Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
    The others are not touched to avoid unwanted side effects. */
-void __init early_cpu_detect(void)
+static void __init early_cpu_detect(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 
@@ -240,6 +243,10 @@ void __init early_cpu_detect(void)
 	}
 
 	early_intel_workaround(c);
+
+#ifdef CONFIG_X86_HT
+	phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
 }
 
 void __init generic_identify(struct cpuinfo_x86 * c)
@@ -426,25 +433,15 @@ void __init identify_cpu(struct cpuinfo_
 	mcheck_init(c);
 #endif
 }
-/*
- *	Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
- */
- 
-void __init dodgy_tsc(void)
-{
-	if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
-	    ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC   ))
-		cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
-}
 
 #ifdef CONFIG_X86_HT
 void __init detect_ht(struct cpuinfo_x86 *c)
 {
 	u32 	eax, ebx, ecx, edx;
-	int 	index_lsb, index_msb, tmp;
+	int 	index_msb, tmp;
 	int 	cpu = smp_processor_id();
 
-	if (!cpu_has(c, X86_FEATURE_HT))
+	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
 		return;
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
@@ -453,7 +450,6 @@ void __init detect_ht(struct cpuinfo_x86
 	if (smp_num_siblings == 1) {
 		printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
 	} else if (smp_num_siblings > 1 ) {
-		index_lsb = 0;
 		index_msb = 31;
 
 		if (smp_num_siblings > NR_CPUS) {
@@ -462,21 +458,34 @@ void __init detect_ht(struct cpuinfo_x86
 			return;
 		}
 		tmp = smp_num_siblings;
-		while ((tmp & 1) == 0) {
-			tmp >>=1 ;
-			index_lsb++;
-		}
-		tmp = smp_num_siblings;
 		while ((tmp & 0x80000000 ) == 0) {
 			tmp <<=1 ;
 			index_msb--;
 		}
-		if (index_lsb != index_msb )
+		if (smp_num_siblings & (smp_num_siblings - 1))
 			index_msb++;
 		phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
 
 		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
 		       phys_proc_id[cpu]);
+
+		smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+
+		tmp = smp_num_siblings;
+		index_msb = 31;
+		while ((tmp & 0x80000000) == 0) {
+			tmp <<=1 ;
+			index_msb--;
+		}
+
+		if (smp_num_siblings & (smp_num_siblings - 1))
+			index_msb++;
+
+		cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+
+		if (c->x86_num_cores > 1)
+			printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+			       cpu_core_id[cpu]);
 	}
 }
 #endif
@@ -523,7 +532,6 @@ extern int transmeta_init_cpu(void);
 extern int rise_init_cpu(void);
 extern int nexgen_init_cpu(void);
 extern int umc_init_cpu(void);
-void early_cpu_detect(void);
 
 void __init early_cpu_init(void)
 {
@@ -557,6 +565,7 @@ void __init cpu_init (void)
 	int cpu = smp_processor_id();
 	struct tss_struct * t = &per_cpu(init_tss, cpu);
 	struct thread_struct *thread = &current->thread;
+	__u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
 
 	if (cpu_test_and_set(cpu, cpu_initialized)) {
 		printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
@@ -579,6 +588,13 @@ void __init cpu_init (void)
 	 */
 	memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table,
 	       GDT_SIZE);
+
+	/* Set up GDT entry for 16bit stack */
+	*(__u64 *)&(per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_ESPFIX_SS]) |=
+		((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) |
+		((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
+		(CPU_16BIT_STACK_SIZE - 1);
+
 	cpu_gdt_descr[cpu].size = GDT_SIZE - 1;
 	cpu_gdt_descr[cpu].address =
 	    (unsigned long)&per_cpu(cpu_gdt_table, cpu);
diff --git a/arch/i386/kernel/cpu/cpu.h b/arch/i386/kernel/cpu/cpu.h
--- a/arch/i386/kernel/cpu/cpu.h
+++ b/arch/i386/kernel/cpu/cpu.h
@@ -25,7 +25,6 @@ extern int get_model_name(struct cpuinfo
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
 
 extern void generic_identify(struct cpuinfo_x86 * c);
-extern int have_cpuid_p(void);
 
 extern void early_intel_workaround(struct cpuinfo_x86 *c);
 
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -6,22 +6,14 @@ menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
 
-config CPU_FREQ_TABLE
-       tristate "CPU frequency table helpers"
-       depends on CPU_FREQ
-       default y
-       help
-         Many CPUFreq drivers use these helpers, so only say N here if
-	 the CPUFreq driver of your choice doesn't need these helpers.
-
-	 If in doubt, say Y.
+if CPU_FREQ
 
 comment "CPUFreq processor drivers"
-       depends on CPU_FREQ
 
 config X86_ACPI_CPUFREQ
 	tristate "ACPI Processor P-States driver"
-	depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
+	select CPU_FREQ_TABLE
+	depends on ACPI_PROCESSOR
 	help
 	  This driver adds a CPUFreq driver which utilizes the ACPI
 	  Processor Performance States.
@@ -31,8 +23,9 @@ config X86_ACPI_CPUFREQ
 	  If in doubt, say N.
 
 config ELAN_CPUFREQ
-	tristate "AMD Elan"
-	depends on CPU_FREQ_TABLE && X86_ELAN
+	tristate "AMD Elan SC400 and SC410"
+	select CPU_FREQ_TABLE
+	depends on X86_ELAN
 	---help---
 	  This adds the CPUFreq driver for AMD Elan SC400 and SC410
 	  processors.
@@ -45,9 +38,21 @@ config ELAN_CPUFREQ
 
 	  If in doubt, say N.
 
+config SC520_CPUFREQ
+	tristate "AMD Elan SC520"
+	select CPU_FREQ_TABLE
+	depends on X86_ELAN
+	---help---
+	  This adds the CPUFreq driver for AMD Elan SC520 processor.
+
+	  For details, take a look at <file:Documentation/cpu-freq/>.
+
+	  If in doubt, say N.
+
+
 config X86_POWERNOW_K6
 	tristate "AMD Mobile K6-2/K6-3 PowerNow!"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for mobile AMD K6-2+ and mobile
 	  AMD K6-3+ processors.
@@ -58,7 +63,7 @@ config X86_POWERNOW_K6
 
 config X86_POWERNOW_K7
 	tristate "AMD Mobile Athlon/Duron PowerNow!"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for mobile AMD K7 mobile processors.
 
@@ -68,12 +73,14 @@ config X86_POWERNOW_K7
 
 config X86_POWERNOW_K7_ACPI
 	bool
-	depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y"))
+	depends on X86_POWERNOW_K7 && ACPI_PROCESSOR
+	depends on !(X86_POWERNOW_K7 = y && ACPI_PROCESSOR = m)
 	default y
 
 config X86_POWERNOW_K8
 	tristate "AMD Opteron/Athlon64 PowerNow!"
-	depends on CPU_FREQ_TABLE && EXPERIMENTAL
+	select CPU_FREQ_TABLE
+	depends on EXPERIMENTAL
 	help
 	  This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
 
@@ -83,12 +90,12 @@ config X86_POWERNOW_K8
 
 config X86_POWERNOW_K8_ACPI
 	bool
-	depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+	depends on X86_POWERNOW_K8 && ACPI_PROCESSOR
+	depends on !(X86_POWERNOW_K8 = y && ACPI_PROCESSOR = m)
 	default y
 
 config X86_GX_SUSPMOD
 	tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
-	depends on CPU_FREQ
 	help
 	 This add the CPUFreq driver for NatSemi Geode processors which
 	 support suspend modulation.
@@ -99,7 +106,7 @@ config X86_GX_SUSPMOD
 
 config X86_SPEEDSTEP_CENTRINO
 	tristate "Intel Enhanced SpeedStep"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	select X86_SPEEDSTEP_CENTRINO_TABLE if (!X86_SPEEDSTEP_CENTRINO_ACPI)
 	help
 	  This adds the CPUFreq driver for Enhanced SpeedStep enabled
@@ -114,8 +121,8 @@ config X86_SPEEDSTEP_CENTRINO
 
 config X86_SPEEDSTEP_CENTRINO_ACPI
 	bool "Use ACPI tables to decode valid frequency/voltage pairs"
-	depends on X86_SPEEDSTEP_CENTRINO
-	depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
+	depends on X86_SPEEDSTEP_CENTRINO && ACPI_PROCESSOR
+	depends on !(X86_SPEEDSTEP_CENTRINO = y && ACPI_PROCESSOR = m)
 	default y
 	help
 	  Use primarily the information provided in the BIOS ACPI tables
@@ -136,7 +143,7 @@ config X86_SPEEDSTEP_CENTRINO_TABLE
 
 config X86_SPEEDSTEP_ICH
 	tristate "Intel Speedstep on ICH-M chipsets (ioport interface)"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for certain mobile Intel Pentium III
 	  (Coppermine), all mobile Intel Pentium III-M (Tualatin) and all
@@ -149,7 +156,8 @@ config X86_SPEEDSTEP_ICH
 
 config X86_SPEEDSTEP_SMI
 	tristate "Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)"
-	depends on CPU_FREQ_TABLE && EXPERIMENTAL
+	select CPU_FREQ_TABLE
+	depends on EXPERIMENTAL
 	help
 	  This adds the CPUFreq driver for certain mobile Intel Pentium III
 	  (Coppermine), all mobile Intel Pentium III-M (Tualatin)  
@@ -161,7 +169,7 @@ config X86_SPEEDSTEP_SMI
 
 config X86_P4_CLOCKMOD
 	tristate "Intel Pentium 4 clock modulation"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for Intel Pentium 4 / XEON
 	  processors.
@@ -172,7 +180,7 @@ config X86_P4_CLOCKMOD
 
 config X86_CPUFREQ_NFORCE2
 	tristate "nVidia nForce2 FSB changing"
-	depends on CPU_FREQ && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  This adds the CPUFreq driver for FSB changing on nVidia nForce2
 	  platforms.
@@ -183,7 +191,6 @@ config X86_CPUFREQ_NFORCE2
 
 config X86_LONGRUN
 	tristate "Transmeta LongRun"
-	depends on CPU_FREQ
 	help
 	  This adds the CPUFreq driver for Transmeta Crusoe and Efficeon processors
 	  which support LongRun.
@@ -194,7 +201,7 @@ config X86_LONGRUN
 
 config X86_LONGHAUL
 	tristate "VIA Cyrix III Longhaul"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for VIA Samuel/CyrixIII, 
 	  VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 
@@ -205,7 +212,6 @@ config X86_LONGHAUL
 	  If in doubt, say N.
 
 comment "shared options"
-	depends on CPU_FREQ
 
 config X86_ACPI_CPUFREQ_PROC_INTF
         bool "/proc/acpi/processor/../performance interface (deprecated)"
@@ -220,8 +226,7 @@ config X86_ACPI_CPUFREQ_PROC_INTF
 
 config X86_SPEEDSTEP_LIB
 	tristate
-	depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
-	default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
+	default X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD
 
 config X86_SPEEDSTEP_RELAXED_CAP_CHECK
 	bool "Relaxed speedstep capability checks"
@@ -233,5 +238,6 @@ config X86_SPEEDSTEP_RELAXED_CAP_CHECK
 	  option lets the probing code bypass some of those checks if the
 	  parameter "relaxed_check=1" is passed to the module.
 
+endif	# CPU_FREQ
 
 endmenu
diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile
--- a/arch/i386/kernel/cpu/cpufreq/Makefile
+++ b/arch/i386/kernel/cpu/cpufreq/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_X86_POWERNOW_K7)		+= powern
 obj-$(CONFIG_X86_POWERNOW_K8)		+= powernow-k8.o
 obj-$(CONFIG_X86_LONGHAUL)		+= longhaul.o
 obj-$(CONFIG_ELAN_CPUFREQ)		+= elanfreq.o
+obj-$(CONFIG_SC520_CPUFREQ)		+= sc520_freq.o
 obj-$(CONFIG_X86_LONGRUN)		+= longrun.o  
 obj-$(CONFIG_X86_GX_SUSPMOD)		+= gx-suspmod.o
 obj-$(CONFIG_X86_SPEEDSTEP_ICH)		+= speedstep-ich.o
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -29,6 +29,7 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/pci.h>
 
 #include <asm/msr.h>
 #include <asm/timex.h>
@@ -119,7 +120,13 @@ static int longhaul_get_cpu_mult(void)
 static void do_powersaver(union msr_longhaul *longhaul,
 			unsigned int clock_ratio_index)
 {
+	struct pci_dev *dev;
+	unsigned long flags;
+	unsigned int tmp_mask;
 	int version;
+	int i;
+	u16 pci_cmd;
+	u16 cmd_state[64];
 
 	switch (cpu_model) {
 	case CPU_EZRA_T:
@@ -137,17 +144,58 @@ static void do_powersaver(union msr_long
 	longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
 	longhaul->bits.EnableSoftBusRatio = 1;
 	longhaul->bits.RevisionKey = 0;
-	local_irq_disable();
-	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+
+	preempt_disable();
+	local_irq_save(flags);
+
+	/*
+	 * get current pci bus master state for all devices
+	 * and clear bus master bit
+	 */
+	dev = NULL;
+	i = 0;
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (dev != NULL) {
+			pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
+			cmd_state[i++] = pci_cmd;
+			pci_cmd &= ~PCI_COMMAND_MASTER;
+			pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
+		}
+	} while (dev != NULL);
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE,0x21);	/* TMR0 only */
+	outb(0xFF,0x80);	/* delay */
+
 	local_irq_enable();
+
+	__hlt();
+	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	__hlt();
 
+	local_irq_disable();
+
+	outb(tmp_mask,0x21);	/* restore mask */
+
+	/* restore pci bus master state for all devices */
+	dev = NULL;
+	i = 0;
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (dev != NULL) {
+			pci_cmd = cmd_state[i++];
+			pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
+		}
+	} while (dev != NULL);
+	local_irq_restore(flags);
+	preempt_enable();
+
+	/* disable bus ratio bit */
 	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	longhaul->bits.EnableSoftBusRatio = 0;
 	longhaul->bits.RevisionKey = version;
-	local_irq_disable();
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-	local_irq_enable();
 }
 
 /**
@@ -578,7 +626,7 @@ static int __init longhaul_cpu_init(stru
 		longhaul_setup_voltagescaling();
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cpuinfo.transition_latency = 200000;	/* nsec */
 	policy->cur = calc_speed(longhaul_get_cpu_mult());
 
 	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
@@ -23,6 +23,7 @@
 #include <linux/dmi.h>
 
 #include <asm/msr.h>
+#include <asm/timer.h>
 #include <asm/timex.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -586,13 +587,17 @@ static int __init powernow_cpu_init (str
 
 	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 
-	/* A K7 with powernow technology is set to max frequency by BIOS */
-	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID];
+	/* recalibrate cpu_khz */
+	result = recalibrate_cpu_khz();
+	if (result)
+		return result;
+
+	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
 	if (!fsb) {
 		printk(KERN_WARNING PFX "can not determine bus frequency\n");
 		return -EINVAL;
 	}
-	dprintk("FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000);
+	dprintk("FSB: %3dMHz\n", fsb/1000);
 
 	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
 		printk (KERN_INFO PFX "PSB/PST known to be broken.  Trying ACPI instead\n");
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -4,7 +4,7 @@
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
  *
- *  Support : paul.devriendt@amd.com
+ *  Support : mark.langsdorf@amd.com
  *
  *  Based on the powernow-k7.c module written by Dave Jones.
  *  (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs
@@ -15,12 +15,13 @@
  *
  *  Valuable input gratefully received from Dave Jones, Pavel Machek,
  *  Dominik Brodowski, and others.
+ *  Originally developed by Paul Devriendt.
  *  Processor information obtained from Chapter 9 (Power and Thermal Management)
  *  of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
  *  Opteron Processors" available for download from www.amd.com
  *
  *  Tables for specific CPUs can be infrerred from
- *	http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
+ *     http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
  */
 
 #include <linux/kernel.h>
@@ -30,6 +31,7 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/cpumask.h>
 
 #include <asm/msr.h>
 #include <asm/io.h>
@@ -42,7 +44,7 @@
 
 #define PFX "powernow-k8: "
 #define BFX PFX "BIOS error: "
-#define VERSION "version 1.00.09e"
+#define VERSION "version 1.40.2"
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
@@ -50,6 +52,10 @@ static DECLARE_MUTEX(fidvid_sem);
 
 static struct powernow_k8_data *powernow_data[NR_CPUS];
 
+#ifndef CONFIG_SMP
+static cpumask_t cpu_core_map[1];
+#endif
+
 /* Return a frequency in MHz, given an input fid */
 static u32 find_freq_from_fid(u32 fid)
 {
@@ -274,11 +280,18 @@ static int core_voltage_pre_transition(s
 {
 	u32 rvosteps = data->rvo;
 	u32 savefid = data->currfid;
+	u32 maxvid, lo;
 
 	dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
 		smp_processor_id(),
 		data->currfid, data->currvid, reqvid, data->rvo);
 
+	rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
+	maxvid = 0x1f & (maxvid >> 16);
+	dprintk("ph1 maxvid=0x%x\n", maxvid);
+	if (reqvid < maxvid) /* lower numbers are higher voltages */
+		reqvid = maxvid;
+
 	while (data->currvid > reqvid) {
 		dprintk("ph1: curr 0x%x, req vid 0x%x\n",
 			data->currvid, reqvid);
@@ -286,8 +299,8 @@ static int core_voltage_pre_transition(s
 			return 1;
 	}
 
-	while ((rvosteps > 0)  && ((data->rvo + data->currvid) > reqvid)) {
-		if (data->currvid == 0) {
+	while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
+		if (data->currvid == maxvid) {
 			rvosteps = 0;
 		} else {
 			dprintk("ph1: changing vid for rvo, req 0x%x\n",
@@ -671,7 +684,7 @@ static int find_psb_table(struct powerno
 	 * BIOS and Kernel Developer's Guide, which is available on
 	 * www.amd.com
 	 */
-	printk(KERN_ERR PFX "BIOS error - no PSB\n");
+	printk(KERN_INFO PFX "BIOS error - no PSB or ACPI _PSS objects\n");
 	return -ENODEV;
 }
 
@@ -695,7 +708,7 @@ static int powernow_k8_cpu_init_acpi(str
 	struct cpufreq_frequency_table *powernow_table;
 
 	if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
-		dprintk("register performance failed\n");
+		dprintk("register performance failed: bad ACPI data\n");
 		return -EIO;
 	}
 
@@ -746,22 +759,23 @@ static int powernow_k8_cpu_init_acpi(str
 			continue;
 		}
 
- 		if (fid < HI_FID_TABLE_BOTTOM) {
- 			if (cntlofreq) {
- 				/* if both entries are the same, ignore this
- 				 * one... 
- 				 */
- 				if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
- 				    (powernow_table[i].index != powernow_table[cntlofreq].index)) {
- 					printk(KERN_ERR PFX "Too many lo freq table entries\n");
- 					goto err_out_mem;
- 				}
-				
- 				dprintk("double low frequency table entry, ignoring it.\n");
- 				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
- 				continue;
- 			} else
- 				cntlofreq = i;
+		/* verify only 1 entry from the lo frequency table */
+		if (fid < HI_FID_TABLE_BOTTOM) {
+			if (cntlofreq) {
+				/* if both entries are the same, ignore this
+				 * one... 
+				 */
+				if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
+				    (powernow_table[i].index != powernow_table[cntlofreq].index)) {
+					printk(KERN_ERR PFX "Too many lo freq table entries\n");
+					goto err_out_mem;
+				}
+
+				dprintk("double low frequency table entry, ignoring it.\n");
+				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+				continue;
+			} else
+				cntlofreq = i;
 		}
 
 		if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
@@ -816,7 +830,7 @@ static int transition_frequency(struct p
 {
 	u32 fid;
 	u32 vid;
-	int res;
+	int res, i;
 	struct cpufreq_freqs freqs;
 
 	dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
@@ -841,7 +855,8 @@ static int transition_frequency(struct p
 	}
 
 	if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
-		printk("ignoring illegal change in lo freq table-%x to 0x%x\n",
+		printk(KERN_ERR PFX
+		       "ignoring illegal change in lo freq table-%x to 0x%x\n",
 		       data->currfid, fid);
 		return 1;
 	}
@@ -850,18 +865,20 @@ static int transition_frequency(struct p
 		smp_processor_id(), fid, vid);
 
 	freqs.cpu = data->cpu;
-
 	freqs.old = find_khz_freq_from_fid(data->currfid);
 	freqs.new = find_khz_freq_from_fid(fid);
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
+		freqs.cpu = i;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
 
-	down(&fidvid_sem);
 	res = transition_fid_vid(data, fid, vid);
-	up(&fidvid_sem);
 
 	freqs.new = find_khz_freq_from_fid(data->currfid);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
+	for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
+		freqs.cpu = i;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+        }
 	return res;
 }
 
@@ -874,6 +891,7 @@ static int powernowk8_target(struct cpuf
 	u32 checkvid = data->currvid;
 	unsigned int newstate;
 	int ret = -EIO;
+	int i;
 
 	/* only run on specific CPU from here on */
 	oldmask = current->cpus_allowed;
@@ -902,22 +920,41 @@ static int powernowk8_target(struct cpuf
 		data->currfid, data->currvid);
 
 	if ((checkvid != data->currvid) || (checkfid != data->currfid)) {
-		printk(KERN_ERR PFX
-		       "error - out of sync, fid 0x%x 0x%x, vid 0x%x 0x%x\n",
-		       checkfid, data->currfid, checkvid, data->currvid);
+		printk(KERN_INFO PFX
+			"error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
+			checkfid, data->currfid, checkvid, data->currvid);
 	}
 
 	if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
 		goto err_out;
 
+	down(&fidvid_sem);
+
+	for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
+		/* make sure the sibling is initialized */
+		if (!powernow_data[i]) {
+                        ret = 0;
+                        up(&fidvid_sem);
+                        goto err_out;
+                }
+	}
+
 	powernow_k8_acpi_pst_values(data, newstate);
 
 	if (transition_frequency(data, newstate)) {
 		printk(KERN_ERR PFX "transition frequency failed\n");
 		ret = 1;
+		up(&fidvid_sem);
 		goto err_out;
 	}
 
+	/* Update all the fid/vids of our siblings */
+	for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
+		powernow_data[i]->currvid = data->currvid;
+		powernow_data[i]->currfid = data->currfid;
+	}	
+	up(&fidvid_sem);
+
 	pol->cur = find_khz_freq_from_fid(data->currfid);
 	ret = 0;
 
@@ -962,7 +999,7 @@ static int __init powernowk8_cpu_init(st
 		 */
 
 		if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
-			printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n");
+			printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n");
 			kfree(data);
 			return -ENODEV;
 		}
@@ -1003,6 +1040,7 @@ static int __init powernowk8_cpu_init(st
 	schedule();
 
 	pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	pol->cpus = cpu_core_map[pol->cpu];
 
 	/* Take a crude guess here. 
 	 * That guess was in microseconds, so multiply with 1000 */
@@ -1069,7 +1107,7 @@ static unsigned int powernowk8_get (unsi
 		return 0;
 	}
 	preempt_disable();
-
+	
 	if (query_current_values_with_pending_wait(data))
 		goto out;
 
@@ -1127,9 +1165,10 @@ static void __exit powernowk8_exit(void)
 	cpufreq_unregister_driver(&cpufreq_amd64_driver);
 }
 
-MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
+MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com.");
 MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
 MODULE_LICENSE("GPL");
 
 late_initcall(powernowk8_init);
 module_exit(powernowk8_exit);
+
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -174,3 +174,18 @@ static int core_voltage_post_transition(
 static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
 
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
+
+#ifndef for_each_cpu_mask
+#define for_each_cpu_mask(i,mask) for (i=0;i<1;i++)
+#endif
+                                                                                
+#ifdef CONFIG_SMP
+static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
+{
+}
+#else
+static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
+{
+	cpu_set(0, cpu_sharedcore_mask[0]);
+}
+#endif
diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c
new file mode 100644
--- /dev/null
+++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c
@@ -0,0 +1,186 @@
+/*
+ *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
+ *
+ *	Copyright (C) 2005 Sean Young <sean@mess.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.
+ *
+ *	Based on elanfreq.c
+ *
+ *	2005-03-30: - initial revision
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+#define MMCR_BASE	0xfffef000	/* The default base address */
+#define OFFS_CPUCTL	0x2   /* CPU Control Register */
+
+static __u8 __iomem *cpuctl;
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg)
+
+static struct cpufreq_frequency_table sc520_freq_table[] = {
+	{0x01,	100000},
+	{0x02,	133000},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
+{
+	u8 clockspeed_reg = *cpuctl;
+
+	switch (clockspeed_reg & 0x03) {
+	default:
+		printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg);
+	case 0x01:
+		return 100000;
+	case 0x02:
+		return 133000;
+	}
+}
+
+static void sc520_freq_set_cpu_state (unsigned int state)
+{
+
+	struct cpufreq_freqs	freqs;
+	u8 clockspeed_reg;
+
+	freqs.old = sc520_freq_get_cpu_frequency(0);
+	freqs.new = sc520_freq_table[state].frequency;
+	freqs.cpu = 0; /* AMD Elan is UP */
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	dprintk("attempting to set frequency to %i kHz\n",
+			sc520_freq_table[state].frequency);
+
+	local_irq_disable();
+
+	clockspeed_reg = *cpuctl & ~0x03;
+	*cpuctl = clockspeed_reg | sc520_freq_table[state].index;
+
+	local_irq_enable();
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+static int sc520_freq_verify (struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
+}
+
+static int sc520_freq_target (struct cpufreq_policy *policy,
+			    unsigned int target_freq,
+			    unsigned int relation)
+{
+	unsigned int newstate = 0;
+
+	if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate))
+		return -EINVAL;
+
+	sc520_freq_set_cpu_state(newstate);
+
+	return 0;
+}
+
+
+/*
+ *	Module init and exit code
+ */
+
+static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	int result;
+
+	/* capability check */
+	if (c->x86_vendor != X86_VENDOR_AMD ||
+	    c->x86 != 4 || c->x86_model != 9)
+		return -ENODEV;
+
+	/* cpuinfo and default policy values */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
+	policy->cur = sc520_freq_get_cpu_frequency(0);
+
+	result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
+	if (result)
+		return (result);
+
+	cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
+
+	return 0;
+}
+
+
+static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+
+static struct freq_attr* sc520_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+
+static struct cpufreq_driver sc520_freq_driver = {
+	.get	= sc520_freq_get_cpu_frequency,
+	.verify	= sc520_freq_verify,
+	.target	= sc520_freq_target,
+	.init	= sc520_freq_cpu_init,
+	.exit	= sc520_freq_cpu_exit,
+	.name	= "sc520_freq",
+	.owner	= THIS_MODULE,
+	.attr	= sc520_freq_attr,
+};
+
+
+static int __init sc520_freq_init(void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+
+	/* Test if we have the right hardware */
+	if(c->x86_vendor != X86_VENDOR_AMD ||
+				c->x86 != 4 || c->x86_model != 9) {
+		dprintk("no Elan SC520 processor found!\n");
+		return -ENODEV;
+	}
+	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
+	if(!cpuctl) {
+		printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
+		return -ENOMEM;
+	}
+
+	return cpufreq_register_driver(&sc520_freq_driver);
+}
+
+
+static void __exit sc520_freq_exit(void)
+{
+	cpufreq_unregister_driver(&sc520_freq_driver);
+	iounmap(cpuctl);
+}
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
+
+module_init(sc520_freq_init);
+module_exit(sc520_freq_exit);
+
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -54,6 +54,8 @@ enum {
 	CPU_DOTHAN_A1,
 	CPU_DOTHAN_A2,
 	CPU_DOTHAN_B0,
+	CPU_MP4HT_D0,
+	CPU_MP4HT_E0,
 };
 
 static const struct cpu_id cpu_ids[] = {
@@ -61,6 +63,8 @@ static const struct cpu_id cpu_ids[] = {
 	[CPU_DOTHAN_A1]	= { 6, 13, 1 },
 	[CPU_DOTHAN_A2]	= { 6, 13, 2 },
 	[CPU_DOTHAN_B0]	= { 6, 13, 6 },
+	[CPU_MP4HT_D0]	= {15,  3, 4 },
+	[CPU_MP4HT_E0]	= {15,  4, 1 },
 };
 #define N_IDS	(sizeof(cpu_ids)/sizeof(cpu_ids[0]))
 
@@ -226,6 +230,8 @@ static struct cpu_model models[] =
 	{ &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL },
 	{ &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL },
 	{ &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL },
+	{ &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL },
+	{ &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL },
 
 	{ NULL, }
 };
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
@@ -336,7 +336,7 @@ unsigned int speedstep_get_freqs(unsigne
 	if (!prev_speed)
 		return -EIO;
 
-	dprintk("previous seped is %u\n", prev_speed);
+	dprintk("previous speed is %u\n", prev_speed);
 	
 	local_irq_save(flags);
 
@@ -348,7 +348,7 @@ unsigned int speedstep_get_freqs(unsigne
 		goto out;
 	}
 
-	dprintk("low seped is %u\n", *low_speed);
+	dprintk("low speed is %u\n", *low_speed);
 
 	/* switch to high state */
 	set_state(SPEEDSTEP_HIGH);
@@ -358,7 +358,7 @@ unsigned int speedstep_get_freqs(unsigne
 		goto out;
 	}
 
-	dprintk("high seped is %u\n", *high_speed);
+	dprintk("high speed is %u\n", *high_speed);
 
 	if (*low_speed == *high_speed) {
 		ret = -ENODEV;
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
@@ -357,6 +357,9 @@ static int __init speedstep_init(void)
 	case SPEEDSTEP_PROCESSOR_PIII_C:
 	case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
 		break;
+	case SPEEDSTEP_PROCESSOR_P4M:
+		printk(KERN_INFO "speedstep-smi: you're trying to use this cpufreq driver on a Pentium 4-based CPU. Most likely it will not work.\n");
+		break;
 	default:
 		speedstep_processor = 0;
 	}
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -12,7 +12,7 @@
 /*
  * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
-void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
 	unsigned char ccr2, ccr3;
 	unsigned long flags;
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -77,6 +77,27 @@ static void __init Intel_errata_workarou
 }
 
 
+/*
+ * find out the number of processor cores on the die
+ */
+static int __init num_cpu_cores(struct cpuinfo_x86 *c)
+{
+	unsigned int eax;
+
+	if (c->cpuid_level < 4)
+		return 1;
+
+	__asm__("cpuid"
+		: "=a" (eax)
+		: "0" (4), "c" (0)
+		: "bx", "dx");
+
+	if (eax & 0x1f)
+		return ((eax >> 26) + 1);
+	else
+		return 1;
+}
+
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
 	unsigned int l2 = 0;
@@ -139,6 +160,8 @@ static void __init init_intel(struct cpu
 	if ( p )
 		strcpy(c->x86_model_id, p);
 	
+	c->x86_num_cores = num_cpu_cores(c);
+
 	detect_ht(c);
 
 	/* Work around errata */
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -1,5 +1,18 @@
+/*
+ *      Routines to indentify caches on Intel CPU.
+ *
+ *      Changes:
+ *      Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
+ */
+
 #include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/compiler.h>
+#include <linux/cpu.h>
+
 #include <asm/processor.h>
+#include <asm/smp.h>
 
 #define LVL_1_INST	1
 #define LVL_1_DATA	2
@@ -58,10 +71,142 @@ static struct _cache_table cache_table[]
 	{ 0x00, 0, 0}
 };
 
+
+enum _cache_type
+{
+	CACHE_TYPE_NULL	= 0,
+	CACHE_TYPE_DATA = 1,
+	CACHE_TYPE_INST = 2,
+	CACHE_TYPE_UNIFIED = 3
+};
+
+union _cpuid4_leaf_eax {
+	struct {
+		enum _cache_type	type:5;
+		unsigned int		level:3;
+		unsigned int		is_self_initializing:1;
+		unsigned int		is_fully_associative:1;
+		unsigned int		reserved:4;
+		unsigned int		num_threads_sharing:12;
+		unsigned int		num_cores_on_die:6;
+	} split;
+	u32 full;
+};
+
+union _cpuid4_leaf_ebx {
+	struct {
+		unsigned int		coherency_line_size:12;
+		unsigned int		physical_line_partition:10;
+		unsigned int		ways_of_associativity:10;
+	} split;
+	u32 full;
+};
+
+union _cpuid4_leaf_ecx {
+	struct {
+		unsigned int		number_of_sets:32;
+	} split;
+	u32 full;
+};
+
+struct _cpuid4_info {
+	union _cpuid4_leaf_eax eax;
+	union _cpuid4_leaf_ebx ebx;
+	union _cpuid4_leaf_ecx ecx;
+	unsigned long size;
+	cpumask_t shared_cpu_map;
+};
+
+#define MAX_CACHE_LEAVES		4
+static unsigned short			num_cache_leaves;
+
+static int __devinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
+{
+	unsigned int		eax, ebx, ecx, edx;
+	union _cpuid4_leaf_eax	cache_eax;
+
+	cpuid_count(4, index, &eax, &ebx, &ecx, &edx);
+	cache_eax.full = eax;
+	if (cache_eax.split.type == CACHE_TYPE_NULL)
+		return -1;
+
+	this_leaf->eax.full = eax;
+	this_leaf->ebx.full = ebx;
+	this_leaf->ecx.full = ecx;
+	this_leaf->size = (this_leaf->ecx.split.number_of_sets + 1) *
+		(this_leaf->ebx.split.coherency_line_size + 1) *
+		(this_leaf->ebx.split.physical_line_partition + 1) *
+		(this_leaf->ebx.split.ways_of_associativity + 1);
+	return 0;
+}
+
+static int __init find_num_cache_leaves(void)
+{
+	unsigned int		eax, ebx, ecx, edx;
+	union _cpuid4_leaf_eax	cache_eax;
+	int 			i;
+	int 			retval;
+
+	retval = MAX_CACHE_LEAVES;
+	/* Do cpuid(4) loop to find out num_cache_leaves */
+	for (i = 0; i < MAX_CACHE_LEAVES; i++) {
+		cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
+		cache_eax.full = eax;
+		if (cache_eax.split.type == CACHE_TYPE_NULL) {
+			retval = i;
+			break;
+		}
+	}
+	return retval;
+}
+
 unsigned int __init init_intel_cacheinfo(struct cpuinfo_x86 *c)
 {
 	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
+	unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
+
+	if (c->cpuid_level > 4) {
+		static int is_initialized;
+
+		if (is_initialized == 0) {
+			/* Init num_cache_leaves from boot CPU */
+			num_cache_leaves = find_num_cache_leaves();
+			is_initialized++;
+		}
+
+		/*
+		 * Whenever possible use cpuid(4), deterministic cache
+		 * parameters cpuid leaf to find the cache details
+		 */
+		for (i = 0; i < num_cache_leaves; i++) {
+			struct _cpuid4_info this_leaf;
+
+			int retval;
 
+			retval = cpuid4_cache_lookup(i, &this_leaf);
+			if (retval >= 0) {
+				switch(this_leaf.eax.split.level) {
+				    case 1:
+					if (this_leaf.eax.split.type ==
+							CACHE_TYPE_DATA)
+						new_l1d = this_leaf.size/1024;
+					else if (this_leaf.eax.split.type ==
+							CACHE_TYPE_INST)
+						new_l1i = this_leaf.size/1024;
+					break;
+				    case 2:
+					new_l2 = this_leaf.size/1024;
+					break;
+				    case 3:
+					new_l3 = this_leaf.size/1024;
+					break;
+				    default:
+					break;
+				}
+			}
+		}
+	}
 	if (c->cpuid_level > 1) {
 		/* supports eax=2  call */
 		int i, j, n;
@@ -114,6 +259,18 @@ unsigned int __init init_intel_cacheinfo
 			}
 		}
 
+		if (new_l1d)
+			l1d = new_l1d;
+
+		if (new_l1i)
+			l1i = new_l1i;
+
+		if (new_l2)
+			l2 = new_l2;
+
+		if (new_l3)
+			l3 = new_l3;
+
 		if ( trace )
 			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
 		else if ( l1i )
@@ -138,3 +295,304 @@ unsigned int __init init_intel_cacheinfo
 
 	return l2;
 }
+
+/* pointer to _cpuid4_info array (for each cache leaf) */
+static struct _cpuid4_info *cpuid4_info[NR_CPUS];
+#define CPUID4_INFO_IDX(x,y)    (&((cpuid4_info[x])[y]))
+
+#ifdef CONFIG_SMP
+static void __devinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
+{
+	struct _cpuid4_info	*this_leaf;
+	unsigned long num_threads_sharing;
+
+	this_leaf = CPUID4_INFO_IDX(cpu, index);
+	num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
+
+	if (num_threads_sharing == 1)
+		cpu_set(cpu, this_leaf->shared_cpu_map);
+#ifdef CONFIG_X86_HT
+	else if (num_threads_sharing == smp_num_siblings)
+		this_leaf->shared_cpu_map = cpu_sibling_map[cpu];
+#endif
+	else
+		printk(KERN_INFO "Number of CPUs sharing cache didn't match "
+				"any known set of CPUs\n");
+}
+#else
+static void __init cache_shared_cpu_map_setup(unsigned int cpu, int index) {}
+#endif
+
+static void free_cache_attributes(unsigned int cpu)
+{
+	kfree(cpuid4_info[cpu]);
+	cpuid4_info[cpu] = NULL;
+}
+
+static int __devinit detect_cache_attributes(unsigned int cpu)
+{
+	struct _cpuid4_info	*this_leaf;
+	unsigned long 		j;
+	int 			retval;
+
+	if (num_cache_leaves == 0)
+		return -ENOENT;
+
+	cpuid4_info[cpu] = kmalloc(
+	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
+	if (unlikely(cpuid4_info[cpu] == NULL))
+		return -ENOMEM;
+	memset(cpuid4_info[cpu], 0,
+	    sizeof(struct _cpuid4_info) * num_cache_leaves);
+
+	/* Do cpuid and store the results */
+	for (j = 0; j < num_cache_leaves; j++) {
+		this_leaf = CPUID4_INFO_IDX(cpu, j);
+		retval = cpuid4_cache_lookup(j, this_leaf);
+		if (unlikely(retval < 0))
+			goto err_out;
+		cache_shared_cpu_map_setup(cpu, j);
+	}
+	return 0;
+
+err_out:
+	free_cache_attributes(cpu);
+	return -ENOMEM;
+}
+
+#ifdef CONFIG_SYSFS
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */
+
+/* pointer to kobject for cpuX/cache */
+static struct kobject * cache_kobject[NR_CPUS];
+
+struct _index_kobject {
+	struct kobject kobj;
+	unsigned int cpu;
+	unsigned short index;
+};
+
+/* pointer to array of kobjects for cpuX/cache/indexY */
+static struct _index_kobject *index_kobject[NR_CPUS];
+#define INDEX_KOBJECT_PTR(x,y)    (&((index_kobject[x])[y]))
+
+#define show_one_plus(file_name, object, val)				\
+static ssize_t show_##file_name						\
+			(struct _cpuid4_info *this_leaf, char *buf)	\
+{									\
+	return sprintf (buf, "%lu\n", (unsigned long)this_leaf->object + val); \
+}
+
+show_one_plus(level, eax.split.level, 0);
+show_one_plus(coherency_line_size, ebx.split.coherency_line_size, 1);
+show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);
+show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);
+show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);
+
+static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf)
+{
+	return sprintf (buf, "%luK\n", this_leaf->size / 1024);
+}
+
+static ssize_t show_shared_cpu_map(struct _cpuid4_info *this_leaf, char *buf)
+{
+	char mask_str[NR_CPUS];
+	cpumask_scnprintf(mask_str, NR_CPUS, this_leaf->shared_cpu_map);
+	return sprintf(buf, "%s\n", mask_str);
+}
+
+static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
+	switch(this_leaf->eax.split.type) {
+	    case CACHE_TYPE_DATA:
+		return sprintf(buf, "Data\n");
+		break;
+	    case CACHE_TYPE_INST:
+		return sprintf(buf, "Instruction\n");
+		break;
+	    case CACHE_TYPE_UNIFIED:
+		return sprintf(buf, "Unified\n");
+		break;
+	    default:
+		return sprintf(buf, "Unknown\n");
+		break;
+	}
+}
+
+struct _cache_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct _cpuid4_info *, char *);
+	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
+};
+
+#define define_one_ro(_name) \
+static struct _cache_attr _name = \
+	__ATTR(_name, 0444, show_##_name, NULL)
+
+define_one_ro(level);
+define_one_ro(type);
+define_one_ro(coherency_line_size);
+define_one_ro(physical_line_partition);
+define_one_ro(ways_of_associativity);
+define_one_ro(number_of_sets);
+define_one_ro(size);
+define_one_ro(shared_cpu_map);
+
+static struct attribute * default_attrs[] = {
+	&type.attr,
+	&level.attr,
+	&coherency_line_size.attr,
+	&physical_line_partition.attr,
+	&ways_of_associativity.attr,
+	&number_of_sets.attr,
+	&size.attr,
+	&shared_cpu_map.attr,
+	NULL
+};
+
+#define to_object(k) container_of(k, struct _index_kobject, kobj)
+#define to_attr(a) container_of(a, struct _cache_attr, attr)
+
+static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct _cache_attr *fattr = to_attr(attr);
+	struct _index_kobject *this_leaf = to_object(kobj);
+	ssize_t ret;
+
+	ret = fattr->show ?
+		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
+			buf) :
+	       	0;
+	return ret;
+}
+
+static ssize_t store(struct kobject * kobj, struct attribute * attr,
+		     const char * buf, size_t count)
+{
+	return 0;
+}
+
+static struct sysfs_ops sysfs_ops = {
+	.show   = show,
+	.store  = store,
+};
+
+static struct kobj_type ktype_cache = {
+	.sysfs_ops	= &sysfs_ops,
+	.default_attrs	= default_attrs,
+};
+
+static struct kobj_type ktype_percpu_entry = {
+	.sysfs_ops	= &sysfs_ops,
+};
+
+static void cpuid4_cache_sysfs_exit(unsigned int cpu)
+{
+	kfree(cache_kobject[cpu]);
+	kfree(index_kobject[cpu]);
+	cache_kobject[cpu] = NULL;
+	index_kobject[cpu] = NULL;
+	free_cache_attributes(cpu);
+}
+
+static int __devinit cpuid4_cache_sysfs_init(unsigned int cpu)
+{
+
+	if (num_cache_leaves == 0)
+		return -ENOENT;
+
+	detect_cache_attributes(cpu);
+	if (cpuid4_info[cpu] == NULL)
+		return -ENOENT;
+
+	/* Allocate all required memory */
+	cache_kobject[cpu] = kmalloc(sizeof(struct kobject), GFP_KERNEL);
+	if (unlikely(cache_kobject[cpu] == NULL))
+		goto err_out;
+	memset(cache_kobject[cpu], 0, sizeof(struct kobject));
+
+	index_kobject[cpu] = kmalloc(
+	    sizeof(struct _index_kobject ) * num_cache_leaves, GFP_KERNEL);
+	if (unlikely(index_kobject[cpu] == NULL))
+		goto err_out;
+	memset(index_kobject[cpu], 0,
+	    sizeof(struct _index_kobject) * num_cache_leaves);
+
+	return 0;
+
+err_out:
+	cpuid4_cache_sysfs_exit(cpu);
+	return -ENOMEM;
+}
+
+/* Add/Remove cache interface for CPU device */
+static int __devinit cache_add_dev(struct sys_device * sys_dev)
+{
+	unsigned int cpu = sys_dev->id;
+	unsigned long i, j;
+	struct _index_kobject *this_object;
+	int retval = 0;
+
+	retval = cpuid4_cache_sysfs_init(cpu);
+	if (unlikely(retval < 0))
+		return retval;
+
+	cache_kobject[cpu]->parent = &sys_dev->kobj;
+	kobject_set_name(cache_kobject[cpu], "%s", "cache");
+	cache_kobject[cpu]->ktype = &ktype_percpu_entry;
+	retval = kobject_register(cache_kobject[cpu]);
+
+	for (i = 0; i < num_cache_leaves; i++) {
+		this_object = INDEX_KOBJECT_PTR(cpu,i);
+		this_object->cpu = cpu;
+		this_object->index = i;
+		this_object->kobj.parent = cache_kobject[cpu];
+		kobject_set_name(&(this_object->kobj), "index%1lu", i);
+		this_object->kobj.ktype = &ktype_cache;
+		retval = kobject_register(&(this_object->kobj));
+		if (unlikely(retval)) {
+			for (j = 0; j < i; j++) {
+				kobject_unregister(
+					&(INDEX_KOBJECT_PTR(cpu,j)->kobj));
+			}
+			kobject_unregister(cache_kobject[cpu]);
+			cpuid4_cache_sysfs_exit(cpu);
+			break;
+		}
+	}
+	return retval;
+}
+
+static int __devexit cache_remove_dev(struct sys_device * sys_dev)
+{
+	unsigned int cpu = sys_dev->id;
+	unsigned long i;
+
+	for (i = 0; i < num_cache_leaves; i++)
+		kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
+	kobject_unregister(cache_kobject[cpu]);
+	cpuid4_cache_sysfs_exit(cpu);
+	return 0;
+}
+
+static struct sysdev_driver cache_sysdev_driver = {
+	.add = cache_add_dev,
+	.remove = __devexit_p(cache_remove_dev),
+};
+
+/* Register/Unregister the cpu_cache driver */
+static int __devinit cache_register_driver(void)
+{
+	if (num_cache_leaves == 0)
+		return 0;
+
+	return sysdev_driver_register(&cpu_sysdev_class,&cache_sysdev_driver);
+}
+
+device_initcall(cache_register_driver);
+
+#endif
+
diff --git a/arch/i386/kernel/cpu/mtrr/centaur.c b/arch/i386/kernel/cpu/mtrr/centaur.c
--- a/arch/i386/kernel/cpu/mtrr/centaur.c
+++ b/arch/i386/kernel/cpu/mtrr/centaur.c
@@ -86,6 +86,8 @@ static void centaur_set_mcr(unsigned int
 	centaur_mcr[reg].low = low;
 	wrmsr(MSR_IDT_MCR0 + reg, low, high);
 }
+
+#if 0
 /*
  *	Initialise the later (saner) Winchip MCR variant. In this version
  *	the BIOS can pass us the registers it has used (but not their values)
@@ -183,6 +185,7 @@ centaur_mcr_init(void)
 
 	set_mtrr_done(&ctxt);
 }
+#endif
 
 static int centaur_validate_add_page(unsigned long base, 
 				     unsigned long size, unsigned int type)
@@ -203,7 +206,7 @@ static int centaur_validate_add_page(uns
 
 static struct mtrr_ops centaur_mtrr_ops = {
 	.vendor            = X86_VENDOR_CENTAUR,
-	.init              = centaur_mcr_init,
+//	.init              = centaur_mcr_init,
 	.set               = centaur_set_mcr,
 	.get               = centaur_get_mcr,
 	.get_free_region   = centaur_get_free_region,
diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
--- a/arch/i386/kernel/cpu/mtrr/cyrix.c
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c
@@ -218,12 +218,12 @@ typedef struct {
 	mtrr_type type;
 } arr_state_t;
 
-arr_state_t arr_state[8] __initdata = {
+static arr_state_t arr_state[8] __devinitdata = {
 	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
 	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
 };
 
-unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+static unsigned char ccr_state[7] __devinitdata = { 0, 0, 0, 0, 0, 0, 0 };
 
 static void cyrix_set_all(void)
 {
@@ -243,6 +243,7 @@ static void cyrix_set_all(void)
 	post_set();
 }
 
+#if 0
 /*
  * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
  * with the SMM (System Management Mode) mode. So we need the following:
@@ -341,10 +342,11 @@ cyrix_arr_init(void)
 	if (ccrc[6])
 		printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
 }
+#endif
 
 static struct mtrr_ops cyrix_mtrr_ops = {
 	.vendor            = X86_VENDOR_CYRIX,
-	.init              = cyrix_arr_init,
+//	.init              = cyrix_arr_init,
 	.set_all	   = cyrix_set_all,
 	.set               = cyrix_set_arr,
 	.get               = cyrix_get_arr,
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -19,8 +19,7 @@ struct mtrr_state {
 };
 
 static unsigned long smp_changes_mask;
-struct mtrr_state mtrr_state = {};
-
+static struct mtrr_state mtrr_state = {};
 
 /*  Get the MSR pair relating to a var range  */
 static void __init
@@ -93,6 +92,16 @@ void __init mtrr_state_warn(void)
 	printk(KERN_INFO "mtrr: corrected configuration.\n");
 }
 
+/* Doesn't attempt to pass an error out to MTRR users
+   because it's quite complicated in some cases and probably not
+   worth it because the best error handling is to ignore it. */
+void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
+{
+	if (wrmsr_safe(msr, a, b) < 0)
+		printk(KERN_ERR
+			"MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
+			smp_processor_id(), msr, a, b);
+}
 
 int generic_get_free_region(unsigned long base, unsigned long size)
 /*  [SUMMARY] Get a free MTRR.
@@ -115,8 +124,8 @@ int generic_get_free_region(unsigned lon
 	return -ENOSPC;
 }
 
-void generic_get_mtrr(unsigned int reg, unsigned long *base,
-		      unsigned int *size, mtrr_type * type)
+static void generic_get_mtrr(unsigned int reg, unsigned long *base,
+			     unsigned int *size, mtrr_type * type)
 {
 	unsigned int mask_lo, mask_hi, base_lo, base_hi;
 
@@ -151,14 +160,14 @@ static int set_fixed_ranges(mtrr_type * 
 
 	rdmsr(MTRRfix64K_00000_MSR, lo, hi);
 	if (p[0] != lo || p[1] != hi) {
-		wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+		mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
 		changed = TRUE;
 	}
 
 	for (i = 0; i < 2; i++) {
 		rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
 		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
-			wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
+			mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
 			      p[3 + i * 2]);
 			changed = TRUE;
 		}
@@ -167,7 +176,7 @@ static int set_fixed_ranges(mtrr_type * 
 	for (i = 0; i < 8; i++) {
 		rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
 		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
-			wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
+			mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
 			      p[7 + i * 2]);
 			changed = TRUE;
 		}
@@ -184,16 +193,18 @@ static int set_mtrr_var_ranges(unsigned 
 
 	rdmsr(MTRRphysBase_MSR(index), lo, hi);
 	if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
-	    || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
-		wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+	    || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) !=
+		(hi & (size_and_mask >> (32 - PAGE_SHIFT)))) {
+		mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
 		changed = TRUE;
 	}
 
 	rdmsr(MTRRphysMask_MSR(index), lo, hi);
 
 	if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
-	    || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
-		wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+	    || (vr->mask_hi & (size_and_mask >> (32 - PAGE_SHIFT))) !=
+		(hi & (size_and_mask >> (32 - PAGE_SHIFT)))) {
+		mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
 		changed = TRUE;
 	}
 	return changed;
@@ -268,7 +279,7 @@ static void prepare_set(void)
 	rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
 
 	/*  Disable MTRRs, and set the default type to uncached  */
-	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+	mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
 }
 
 static void post_set(void)
@@ -277,7 +288,7 @@ static void post_set(void)
 	__flush_tlb();
 
 	/* Intel (P6) standard MTRRs */
-	wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+	mtrr_wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
 		
 	/*  Enable caches  */
 	write_cr0(read_cr0() & 0xbfffffff);
@@ -331,11 +342,11 @@ static void generic_set_mtrr(unsigned in
 	if (size == 0) {
 		/* The invalid bit is kept in the mask, so we simply clear the
 		   relevant mask register to disable a range. */
-		wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+		mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
 	} else {
-		wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
+		mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
 		      (base & size_and_mask) >> (32 - PAGE_SHIFT));
-		wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
+		mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
 		      (-size & size_and_mask) >> (32 - PAGE_SHIFT));
 	}
 
@@ -383,7 +394,7 @@ int generic_validate_add_page(unsigned l
 }
 
 
-int generic_have_wrcomb(void)
+static int generic_have_wrcomb(void)
 {
 	unsigned long config, dummy;
 	rdmsr(MTRRcap_MSR, config, dummy);
diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c
--- a/arch/i386/kernel/cpu/mtrr/if.c
+++ b/arch/i386/kernel/cpu/mtrr/if.c
@@ -98,16 +98,20 @@ mtrr_write(struct file *file, const char
 	unsigned long long base, size;
 	char *ptr;
 	char line[LINE_SIZE];
+	size_t linelen;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
+	if (!len)
+		return -EINVAL;
 	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')
+	linelen = strlen(line);
+	ptr = line + linelen - 1;
+	if (linelen && *ptr == '\n')
 		*ptr = '\0';
 	if (!strncmp(line, "disable=", 8)) {
 		reg = simple_strtoul(line + 8, &ptr, 0);
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -57,10 +57,6 @@ static struct mtrr_ops * mtrr_ops[X86_VE
 
 struct mtrr_ops * mtrr_if = NULL;
 
-__initdata char *mtrr_if_name[] = {
-    "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
-};
-
 static void set_mtrr(unsigned int reg, unsigned long base,
 		     unsigned long size, mtrr_type type);
 
@@ -76,17 +72,21 @@ void set_mtrr_ops(struct mtrr_ops * ops)
 static int have_wrcomb(void)
 {
 	struct pci_dev *dev;
+	u8 rev;
 	
 	if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
-		/* ServerWorks LE chipsets have problems with write-combining 
+		/* ServerWorks LE chipsets < rev 6 have problems with write-combining
 		   Don't allow it and leave room for other chipsets to be tagged */
 		if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
 		    dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) {
-			printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n");
-			pci_dev_put(dev);
-			return 0;
+			pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
+			if (rev <= 5) {
+				printk(KERN_INFO "mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n");
+				pci_dev_put(dev);
+				return 0;
+			}
 		}
-		/* Intel 450NX errata # 23. Non ascending cachline evictions to
+		/* Intel 450NX errata # 23. Non ascending cacheline evictions to
 		   write combining memory may resulting in data corruption */
 		if (dev->vendor == PCI_VENDOR_ID_INTEL &&
 		    dev->device == PCI_DEVICE_ID_INTEL_82451NX) {
@@ -100,7 +100,7 @@ static int have_wrcomb(void)
 }
 
 /*  This function returns the number of variable MTRRs  */
-void __init set_num_var_ranges(void)
+static void __init set_num_var_ranges(void)
 {
 	unsigned long config = 0, dummy;
 
@@ -618,40 +618,21 @@ static int __init mtrr_init(void)
 		mtrr_if = &generic_mtrr_ops;
 		size_or_mask = 0xff000000;	/* 36 bits */
 		size_and_mask = 0x00f00000;
-			
-		switch (boot_cpu_data.x86_vendor) {
-		case X86_VENDOR_AMD:
-			/* The original Athlon docs said that
-			   total addressable memory is 44 bits wide.
-			   It was not really clear whether its MTRRs
-			   follow this or not. (Read: 44 or 36 bits).
-			   However, "x86-64_overview.pdf" explicitly
-			   states that "previous implementations support
-			   36 bit MTRRs" and also provides a way to
-			   query the width (in bits) of the physical
-			   addressable memory on the Hammer family.
-			 */
-			if (boot_cpu_data.x86 == 15
-			    && (cpuid_eax(0x80000000) >= 0x80000008)) {
-				u32 phys_addr;
-				phys_addr = cpuid_eax(0x80000008) & 0xff;
-				size_or_mask =
-				    ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
-				size_and_mask = ~size_or_mask & 0xfff00000;
-			}
-			/* Athlon MTRRs use an Intel-compatible interface for 
-			 * getting and setting */
-			break;
-		case X86_VENDOR_CENTAUR:
-			if (boot_cpu_data.x86 == 6) {
-				/* VIA Cyrix family have Intel style MTRRs, but don't support PAE */
-				size_or_mask = 0xfff00000;	/* 32 bits */
-				size_and_mask = 0;
-			}
-			break;
-		
-		default:
-			break;
+
+		/* This is an AMD specific MSR, but we assume(hope?) that
+		   Intel will implement it to when they extend the address
+		   bus of the Xeon. */
+		if (cpuid_eax(0x80000000) >= 0x80000008) {
+			u32 phys_addr;
+			phys_addr = cpuid_eax(0x80000008) & 0xff;
+			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+			size_and_mask = ~size_or_mask & 0xfff00000;
+		} else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
+			   boot_cpu_data.x86 == 6) {
+			/* VIA C* family have Intel style MTRRs, but
+			   don't support PAE */
+			size_or_mask = 0xfff00000;	/* 32 bits */
+			size_and_mask = 0;
 		}
 	} else {
 		switch (boot_cpu_data.x86_vendor) {
diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h
@@ -37,7 +37,7 @@ typedef u8 mtrr_type;
 struct mtrr_ops {
 	u32	vendor;
 	u32	use_intel_if;
-	void	(*init)(void);
+//	void	(*init)(void);
 	void	(*set)(unsigned int reg, unsigned long base,
 		       unsigned long size, mtrr_type type);
 	void	(*set_all)(void);
@@ -57,7 +57,6 @@ extern int generic_validate_add_page(uns
 
 extern struct mtrr_ops generic_mtrr_ops;
 
-extern int generic_have_wrcomb(void);
 extern int positive_have_wrcomb(void);
 
 /* library functions for processor-specific routines */
@@ -95,5 +94,5 @@ extern unsigned int num_var_ranges;
 void finalize_mtrr_state(void);
 void mtrr_state_warn(void);
 char *mtrr_attrib_to_str(int x);
+void mtrr_wrmsr(unsigned, unsigned, unsigned);
 
-extern char * mtrr_if_name[];
diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
--- a/arch/i386/kernel/cpu/mtrr/state.c
+++ b/arch/i386/kernel/cpu/mtrr/state.c
@@ -42,7 +42,7 @@ void set_mtrr_cache_disable(struct set_m
 {
 	if (use_intel()) 
 		/*  Disable MTRRs, and set the default type to uncached  */
-		wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
+		mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
 		      ctxt->deftype_hi);
 	else if (is_cpu(CYRIX))
 		/* Cyrix ARRs - everything else were excluded at the top */
@@ -60,7 +60,7 @@ void set_mtrr_done(struct set_mtrr_conte
 		/*  Restore MTRRdefType  */
 		if (use_intel())
 			/* Intel (P6) standard MTRRs */
-			wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+			mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
 		else
 			/* Cyrix ARRs - everything else was excluded at the top */
 			setCx86(CX86_CCR3, ctxt->ccr3);
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -25,7 +25,7 @@ static int show_cpuinfo(struct seq_file 
 	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
 
 		/* AMD-defined */
-		"pni", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
 		NULL, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
@@ -94,8 +94,13 @@ static int show_cpuinfo(struct seq_file 
 	if (c->x86_cache_size >= 0)
 		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
 #ifdef CONFIG_X86_HT
-	seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
-	seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings);
+	if (c->x86_num_cores * smp_num_siblings > 1) {
+		seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
+		seq_printf(m, "siblings\t: %d\n",
+				c->x86_num_cores * smp_num_siblings);
+		seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]);
+		seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
+	}
 #endif
 	
 	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
@@ -126,6 +131,7 @@ static int show_cpuinfo(struct seq_file 
 	seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
 		     c->loops_per_jiffy/(500000/HZ),
 		     (c->loops_per_jiffy/(5000/HZ)) % 100);
+
 	return 0;
 }
 
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
--- a/arch/i386/kernel/cpuid.c
+++ b/arch/i386/kernel/cpuid.c
@@ -189,7 +189,7 @@ static struct notifier_block cpuid_class
 	.notifier_call = cpuid_class_cpu_callback,
 };
 
-int __init cpuid_init(void)
+static int __init cpuid_init(void)
 {
 	int i, err = 0;
 	i = 0;
@@ -227,7 +227,7 @@ out:
 	return err;
 }
 
-void __exit cpuid_exit(void)
+static void __exit cpuid_exit(void)
 {
 	int cpu = 0;
 
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -12,8 +12,6 @@
 #include <linux/bootmem.h>
 
 
-int es7000_plat = 0;
-
 struct dmi_header
 {
 	u8	type;
@@ -487,4 +485,3 @@ char * dmi_get_system_info(int field)
 	return dmi_ident[field];
 }
 
-EXPORT_SYMBOL(dmi_get_system_info);
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -46,8 +46,8 @@ extern efi_status_t asmlinkage efi_call_
 
 struct efi efi;
 EXPORT_SYMBOL(efi);
-struct efi efi_phys __initdata;
-struct efi_memory_map memmap __initdata;
+static struct efi efi_phys;
+struct efi_memory_map memmap;
 
 /*
  * We require an early boot_ioremap mapping mechanism initially
@@ -151,7 +151,7 @@ phys_efi_set_virtual_address_map(unsigne
 	return status;
 }
 
-efi_status_t
+static efi_status_t
 phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
 	efi_status_t status;
@@ -240,7 +240,8 @@ void __init efi_map_memmap(void)
 		printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
 }
 
-void __init print_efi_memmap(void)
+#if EFI_DEBUG
+static void __init print_efi_memmap(void)
 {
 	efi_memory_desc_t *md;
 	int i;
@@ -254,6 +255,7 @@ void __init print_efi_memmap(void)
 			(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
 	}
 }
+#endif  /*  EFI_DEBUG  */
 
 /*
  * Walks the EFI memory map and calls CALLBACK once for each EFI
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -47,6 +47,7 @@
 #include <asm/segment.h>
 #include <asm/smp.h>
 #include <asm/page.h>
+#include <asm/desc.h>
 #include "irq_vectors.h"
 
 #define nr_syscalls ((syscall_table_size)/4)
@@ -78,7 +79,7 @@ VM_MASK		= 0x00020000
 #define preempt_stop		cli
 #else
 #define preempt_stop
-#define resume_kernel		restore_all
+#define resume_kernel		restore_nocheck
 #endif
 
 #define SAVE_ALL \
@@ -122,24 +123,6 @@ VM_MASK		= 0x00020000
 .previous
 
 
-#define RESTORE_ALL	\
-	RESTORE_REGS	\
-	addl $4, %esp;	\
-1:	iret;		\
-.section .fixup,"ax";   \
-2:	sti;		\
-	movl $(__USER_DS), %edx; \
-	movl %edx, %ds; \
-	movl %edx, %es; \
-	movl $11,%eax;	\
-	call do_exit;	\
-.previous;		\
-.section __ex_table,"a";\
-	.align 4;	\
-	.long 1b,2b;	\
-.previous
-
-
 ENTRY(ret_from_fork)
 	pushl %eax
 	call schedule_tail
@@ -163,7 +146,7 @@ ret_from_intr:
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
 	testl $(VM_MASK | 3), %eax
-	jz resume_kernel		# returning to kernel or vm86-space
+	jz resume_kernel
 ENTRY(resume_userspace)
  	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
@@ -178,7 +161,7 @@ ENTRY(resume_userspace)
 ENTRY(resume_kernel)
 	cli
 	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
-	jnz restore_all
+	jnz restore_nocheck
 need_resched:
 	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
@@ -219,7 +202,8 @@ sysenter_past_esp:
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 
-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
 	jnz syscall_trace_entry
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
@@ -243,7 +227,8 @@ ENTRY(system_call)
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 					# system call tracing in operation
-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
 	jnz syscall_trace_entry
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
@@ -257,8 +242,57 @@ syscall_exit:
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
+
 restore_all:
-	RESTORE_ALL
+	movl EFLAGS(%esp), %eax		# mix EFLAGS, SS and CS
+	# Warning: OLDSS(%esp) contains the wrong/random values if we
+	# are returning to the kernel.
+	# See comments in process.c:copy_thread() for details.
+	movb OLDSS(%esp), %ah
+	movb CS(%esp), %al
+	andl $(VM_MASK | (4 << 8) | 3), %eax
+	cmpl $((4 << 8) | 3), %eax
+	je ldt_ss			# returning to user-space with LDT SS
+restore_nocheck:
+	RESTORE_REGS
+	addl $4, %esp
+1:	iret
+.section .fixup,"ax"
+iret_exc:
+	sti
+	pushl $0			# no error code
+	pushl $do_iret_error
+	jmp error_code
+.previous
+.section __ex_table,"a"
+	.align 4
+	.long 1b,iret_exc
+.previous
+
+ldt_ss:
+	larl OLDSS(%esp), %eax
+	jnz restore_nocheck
+	testl $0x00400000, %eax		# returning to 32bit stack?
+	jnz restore_nocheck		# allright, normal return
+	/* If returning to userspace with 16bit stack,
+	 * try to fix the higher word of ESP, as the CPU
+	 * won't restore it.
+	 * This is an "official" bug of all the x86-compatible
+	 * CPUs, which we can try to work around to make
+	 * dosemu and wine happy. */
+	subl $8, %esp		# reserve space for switch16 pointer
+	cli
+	movl %esp, %eax
+	/* Set up the 16bit stack frame with switch32 pointer on top,
+	 * and a switch16 pointer on top of the current frame. */
+	call setup_x86_bogus_stack
+	RESTORE_REGS
+	lss 20+4(%esp), %esp	# switch to 16bit stack
+1:	iret
+.section __ex_table,"a"
+	.align 4
+	.long 1b,iret_exc
+.previous
 
 	# perform work that needs to be done immediately before resumption
 	ALIGN
@@ -334,6 +368,27 @@ syscall_badsys:
 	movl $-ENOSYS,EAX(%esp)
 	jmp resume_userspace
 
+#define FIXUP_ESPFIX_STACK \
+	movl %esp, %eax; \
+	/* switch to 32bit stack using the pointer on top of 16bit stack */ \
+	lss %ss:CPU_16BIT_STACK_SIZE-8, %esp; \
+	/* copy data from 16bit stack to 32bit stack */ \
+	call fixup_x86_bogus_stack; \
+	/* put ESP to the proper location */ \
+	movl %eax, %esp;
+#define UNWIND_ESPFIX_STACK \
+	pushl %eax; \
+	movl %ss, %eax; \
+	/* see if on 16bit stack */ \
+	cmpw $__ESPFIX_SS, %ax; \
+	jne 28f; \
+	movl $__KERNEL_DS, %edx; \
+	movl %edx, %ds; \
+	movl %edx, %es; \
+	/* switch to 32bit stack */ \
+	FIXUP_ESPFIX_STACK \
+28:	popl %eax;
+
 /*
  * Build the entry stubs and pointer table with
  * some assembler magic.
@@ -388,7 +443,9 @@ error_code:
 	pushl %ecx
 	pushl %ebx
 	cld
-	movl %es, %ecx
+	pushl %es
+	UNWIND_ESPFIX_STACK
+	popl %ecx
 	movl ES(%esp), %edi		# get the function address
 	movl ORIG_EAX(%esp), %edx	# get the error code
 	movl %eax, ORIG_EAX(%esp)
@@ -457,8 +514,6 @@ debug_stack_correct:
 	xorl %edx,%edx			# error code 0
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
-	testl %eax,%eax
-	jnz restore_all
 	jmp ret_from_exception
 
 /*
@@ -470,6 +525,11 @@ debug_stack_correct:
  * fault happened on the sysenter path.
  */
 ENTRY(nmi)
+	pushl %eax
+	movl %ss, %eax
+	cmpw $__ESPFIX_SS, %ax
+	popl %eax
+	je nmi_16bit_stack
 	cmpl $sysenter_entry,(%esp)
 	je nmi_stack_fixup
 	pushl %eax
@@ -489,7 +549,7 @@ nmi_stack_correct:
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_nmi
-	RESTORE_ALL
+	jmp restore_all
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -505,14 +565,35 @@ nmi_debug_stack_fixup:
 	FIX_STACK(24,nmi_stack_correct, 1)
 	jmp nmi_stack_correct
 
+nmi_16bit_stack:
+	/* create the pointer to lss back */
+	pushl %ss
+	pushl %esp
+	movzwl %sp, %esp
+	addw $4, (%esp)
+	/* copy the iret frame of 12 bytes */
+	.rept 3
+	pushl 16(%esp)
+	.endr
+	pushl %eax
+	SAVE_ALL
+	FIXUP_ESPFIX_STACK		# %eax == %esp
+	xorl %edx,%edx			# zero error code
+	call do_nmi
+	RESTORE_REGS
+	lss 12+4(%esp), %esp		# back to 16bit stack
+1:	iret
+.section __ex_table,"a"
+	.align 4
+	.long 1b,iret_exc
+.previous
+
 ENTRY(int3)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
-	testl %eax,%eax
-	jnz restore_all
 	jmp ret_from_exception
 
 ENTRY(overflow)
@@ -571,296 +652,6 @@ ENTRY(spurious_interrupt_bug)
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
-.data
-ENTRY(sys_call_table)
-	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
-	.long sys_exit
-	.long sys_fork
-	.long sys_read
-	.long sys_write
-	.long sys_open		/* 5 */
-	.long sys_close
-	.long sys_waitpid
-	.long sys_creat
-	.long sys_link
-	.long sys_unlink	/* 10 */
-	.long sys_execve
-	.long sys_chdir
-	.long sys_time
-	.long sys_mknod
-	.long sys_chmod		/* 15 */
-	.long sys_lchown16
-	.long sys_ni_syscall	/* old break syscall holder */
-	.long sys_stat
-	.long sys_lseek
-	.long sys_getpid	/* 20 */
-	.long sys_mount
-	.long sys_oldumount
-	.long sys_setuid16
-	.long sys_getuid16
-	.long sys_stime		/* 25 */
-	.long sys_ptrace
-	.long sys_alarm
-	.long sys_fstat
-	.long sys_pause
-	.long sys_utime		/* 30 */
-	.long sys_ni_syscall	/* old stty syscall holder */
-	.long sys_ni_syscall	/* old gtty syscall holder */
-	.long sys_access
-	.long sys_nice
-	.long sys_ni_syscall	/* 35 - old ftime syscall holder */
-	.long sys_sync
-	.long sys_kill
-	.long sys_rename
-	.long sys_mkdir
-	.long sys_rmdir		/* 40 */
-	.long sys_dup
-	.long sys_pipe
-	.long sys_times
-	.long sys_ni_syscall	/* old prof syscall holder */
-	.long sys_brk		/* 45 */
-	.long sys_setgid16
-	.long sys_getgid16
-	.long sys_signal
-	.long sys_geteuid16
-	.long sys_getegid16	/* 50 */
-	.long sys_acct
-	.long sys_umount	/* recycled never used phys() */
-	.long sys_ni_syscall	/* old lock syscall holder */
-	.long sys_ioctl
-	.long sys_fcntl		/* 55 */
-	.long sys_ni_syscall	/* old mpx syscall holder */
-	.long sys_setpgid
-	.long sys_ni_syscall	/* old ulimit syscall holder */
-	.long sys_olduname
-	.long sys_umask		/* 60 */
-	.long sys_chroot
-	.long sys_ustat
-	.long sys_dup2
-	.long sys_getppid
-	.long sys_getpgrp	/* 65 */
-	.long sys_setsid
-	.long sys_sigaction
-	.long sys_sgetmask
-	.long sys_ssetmask
-	.long sys_setreuid16	/* 70 */
-	.long sys_setregid16
-	.long sys_sigsuspend
-	.long sys_sigpending
-	.long sys_sethostname
-	.long sys_setrlimit	/* 75 */
-	.long sys_old_getrlimit
-	.long sys_getrusage
-	.long sys_gettimeofday
-	.long sys_settimeofday
-	.long sys_getgroups16	/* 80 */
-	.long sys_setgroups16
-	.long old_select
-	.long sys_symlink
-	.long sys_lstat
-	.long sys_readlink	/* 85 */
-	.long sys_uselib
-	.long sys_swapon
-	.long sys_reboot
-	.long old_readdir
-	.long old_mmap		/* 90 */
-	.long sys_munmap
-	.long sys_truncate
-	.long sys_ftruncate
-	.long sys_fchmod
-	.long sys_fchown16	/* 95 */
-	.long sys_getpriority
-	.long sys_setpriority
-	.long sys_ni_syscall	/* old profil syscall holder */
-	.long sys_statfs
-	.long sys_fstatfs	/* 100 */
-	.long sys_ioperm
-	.long sys_socketcall
-	.long sys_syslog
-	.long sys_setitimer
-	.long sys_getitimer	/* 105 */
-	.long sys_newstat
-	.long sys_newlstat
-	.long sys_newfstat
-	.long sys_uname
-	.long sys_iopl		/* 110 */
-	.long sys_vhangup
-	.long sys_ni_syscall	/* old "idle" system call */
-	.long sys_vm86old
-	.long sys_wait4
-	.long sys_swapoff	/* 115 */
-	.long sys_sysinfo
-	.long sys_ipc
-	.long sys_fsync
-	.long sys_sigreturn
-	.long sys_clone		/* 120 */
-	.long sys_setdomainname
-	.long sys_newuname
-	.long sys_modify_ldt
-	.long sys_adjtimex
-	.long sys_mprotect	/* 125 */
-	.long sys_sigprocmask
-	.long sys_ni_syscall	/* old "create_module" */ 
-	.long sys_init_module
-	.long sys_delete_module
-	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
-	.long sys_quotactl
-	.long sys_getpgid
-	.long sys_fchdir
-	.long sys_bdflush
-	.long sys_sysfs		/* 135 */
-	.long sys_personality
-	.long sys_ni_syscall	/* reserved for afs_syscall */
-	.long sys_setfsuid16
-	.long sys_setfsgid16
-	.long sys_llseek	/* 140 */
-	.long sys_getdents
-	.long sys_select
-	.long sys_flock
-	.long sys_msync
-	.long sys_readv		/* 145 */
-	.long sys_writev
-	.long sys_getsid
-	.long sys_fdatasync
-	.long sys_sysctl
-	.long sys_mlock		/* 150 */
-	.long sys_munlock
-	.long sys_mlockall
-	.long sys_munlockall
-	.long sys_sched_setparam
-	.long sys_sched_getparam   /* 155 */
-	.long sys_sched_setscheduler
-	.long sys_sched_getscheduler
-	.long sys_sched_yield
-	.long sys_sched_get_priority_max
-	.long sys_sched_get_priority_min  /* 160 */
-	.long sys_sched_rr_get_interval
-	.long sys_nanosleep
-	.long sys_mremap
-	.long sys_setresuid16
-	.long sys_getresuid16	/* 165 */
-	.long sys_vm86
-	.long sys_ni_syscall	/* Old sys_query_module */
-	.long sys_poll
-	.long sys_nfsservctl
-	.long sys_setresgid16	/* 170 */
-	.long sys_getresgid16
-	.long sys_prctl
-	.long sys_rt_sigreturn
-	.long sys_rt_sigaction
-	.long sys_rt_sigprocmask	/* 175 */
-	.long sys_rt_sigpending
-	.long sys_rt_sigtimedwait
-	.long sys_rt_sigqueueinfo
-	.long sys_rt_sigsuspend
-	.long sys_pread64	/* 180 */
-	.long sys_pwrite64
-	.long sys_chown16
-	.long sys_getcwd
-	.long sys_capget
-	.long sys_capset	/* 185 */
-	.long sys_sigaltstack
-	.long sys_sendfile
-	.long sys_ni_syscall	/* reserved for streams1 */
-	.long sys_ni_syscall	/* reserved for streams2 */
-	.long sys_vfork		/* 190 */
-	.long sys_getrlimit
-	.long sys_mmap2
-	.long sys_truncate64
-	.long sys_ftruncate64
-	.long sys_stat64	/* 195 */
-	.long sys_lstat64
-	.long sys_fstat64
-	.long sys_lchown
-	.long sys_getuid
-	.long sys_getgid	/* 200 */
-	.long sys_geteuid
-	.long sys_getegid
-	.long sys_setreuid
-	.long sys_setregid
-	.long sys_getgroups	/* 205 */
-	.long sys_setgroups
-	.long sys_fchown
-	.long sys_setresuid
-	.long sys_getresuid
-	.long sys_setresgid	/* 210 */
-	.long sys_getresgid
-	.long sys_chown
-	.long sys_setuid
-	.long sys_setgid
-	.long sys_setfsuid	/* 215 */
-	.long sys_setfsgid
-	.long sys_pivot_root
-	.long sys_mincore
-	.long sys_madvise
-	.long sys_getdents64	/* 220 */
-	.long sys_fcntl64
-	.long sys_ni_syscall	/* reserved for TUX */
-	.long sys_ni_syscall
-	.long sys_gettid
-	.long sys_readahead	/* 225 */
-	.long sys_setxattr
-	.long sys_lsetxattr
-	.long sys_fsetxattr
-	.long sys_getxattr
-	.long sys_lgetxattr	/* 230 */
-	.long sys_fgetxattr
-	.long sys_listxattr
-	.long sys_llistxattr
-	.long sys_flistxattr
-	.long sys_removexattr	/* 235 */
-	.long sys_lremovexattr
-	.long sys_fremovexattr
-	.long sys_tkill
-	.long sys_sendfile64
-	.long sys_futex		/* 240 */
-	.long sys_sched_setaffinity
-	.long sys_sched_getaffinity
-	.long sys_set_thread_area
-	.long sys_get_thread_area
-	.long sys_io_setup	/* 245 */
-	.long sys_io_destroy
-	.long sys_io_getevents
-	.long sys_io_submit
-	.long sys_io_cancel
-	.long sys_fadvise64	/* 250 */
-	.long sys_ni_syscall
-	.long sys_exit_group
-	.long sys_lookup_dcookie
-	.long sys_epoll_create
-	.long sys_epoll_ctl	/* 255 */
-	.long sys_epoll_wait
- 	.long sys_remap_file_pages
- 	.long sys_set_tid_address
- 	.long sys_timer_create
- 	.long sys_timer_settime		/* 260 */
- 	.long sys_timer_gettime
- 	.long sys_timer_getoverrun
- 	.long sys_timer_delete
- 	.long sys_clock_settime
- 	.long sys_clock_gettime		/* 265 */
- 	.long sys_clock_getres
- 	.long sys_clock_nanosleep
-	.long sys_statfs64
-	.long sys_fstatfs64	
-	.long sys_tgkill	/* 270 */
-	.long sys_utimes
- 	.long sys_fadvise64_64
-	.long sys_ni_syscall	/* sys_vserver */
-	.long sys_mbind
-	.long sys_get_mempolicy
-	.long sys_set_mempolicy
-	.long sys_mq_open
-	.long sys_mq_unlink
-	.long sys_mq_timedsend
-	.long sys_mq_timedreceive	/* 280 */
-	.long sys_mq_notify
-	.long sys_mq_getsetattr
-	.long sys_ni_syscall		/* reserved for kexec */
-	.long sys_waitid
-	.long sys_ni_syscall		/* 285 */ /* available */
-	.long sys_add_key
-	.long sys_request_key
-	.long sys_keyctl
+#include "syscall_table.S"
 
 syscall_table_size=(.-sys_call_table)
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -380,6 +380,7 @@ rp_sidt:
 	ALIGN
 ignore_int:
 	cld
+#ifdef CONFIG_PRINTK
 	pushl %eax
 	pushl %ecx
 	pushl %edx
@@ -400,6 +401,7 @@ ignore_int:
 	popl %edx
 	popl %ecx
 	popl %eax
+#endif
 	iret
 
 /*
@@ -512,7 +514,7 @@ ENTRY(cpu_gdt_table)
 	.quad 0x00009a0000000000	/* 0xc0 APM CS 16 code (16 bit) */
 	.quad 0x0040920000000000	/* 0xc8 APM DS    data */
 
-	.quad 0x0000000000000000	/* 0xd0 - unused */
+	.quad 0x0000920000000000	/* 0xd0 - ESPFIX 16-bit SS */
 	.quad 0x0000000000000000	/* 0xd8 - unused */
 	.quad 0x0000000000000000	/* 0xe0 - unused */
 	.quad 0x0000000000000000	/* 0xe8 - unused */
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -97,6 +97,11 @@ EXPORT_SYMBOL(__get_user_1);
 EXPORT_SYMBOL(__get_user_2);
 EXPORT_SYMBOL(__get_user_4);
 
+EXPORT_SYMBOL(__put_user_1);
+EXPORT_SYMBOL(__put_user_2);
+EXPORT_SYMBOL(__put_user_4);
+EXPORT_SYMBOL(__put_user_8);
+
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
@@ -112,7 +117,6 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 EXPORT_SYMBOL(dma_free_coherent);
 
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(pcibios_penalize_isa_irq);
 EXPORT_SYMBOL(pci_mem_start);
 #endif
 
@@ -144,7 +148,6 @@ EXPORT_SYMBOL(smp_call_function);
 
 /* TLB flushing */
 EXPORT_SYMBOL(flush_tlb_page);
-EXPORT_SYMBOL_GPL(flush_tlb_all);
 #endif
 
 #ifdef CONFIG_X86_IO_APIC
@@ -166,10 +169,6 @@ EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL_GPL(set_nmi_callback);
 EXPORT_SYMBOL_GPL(unset_nmi_callback);
 
-#undef memcmp
-extern int memcmp(const void *,const void *,__kernel_size_t);
-EXPORT_SYMBOL(memcmp);
-
 EXPORT_SYMBOL(register_die_notifier);
 #ifdef CONFIG_HAVE_DEC_LOCK
 EXPORT_SYMBOL(_atomic_dec_and_lock);
diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
--- a/arch/i386/kernel/i387.c
+++ b/arch/i386/kernel/i387.c
@@ -24,7 +24,7 @@
 #define HAVE_HWFP 1
 #endif
 
-unsigned long mxcsr_feature_mask = 0xffffffff;
+static unsigned long mxcsr_feature_mask = 0xffffffff;
 
 void mxcsr_feature_mask_init(void)
 {
@@ -177,6 +177,7 @@ unsigned short get_fpu_swd( struct task_
 	}
 }
 
+#if 0
 unsigned short get_fpu_twd( struct task_struct *tsk )
 {
 	if ( cpu_has_fxsr ) {
@@ -185,6 +186,7 @@ unsigned short get_fpu_twd( struct task_
 		return (unsigned short)tsk->thread.i387.fsave.twd;
 	}
 }
+#endif  /*  0  */
 
 unsigned short get_fpu_mxcsr( struct task_struct *tsk )
 {
@@ -195,6 +197,8 @@ unsigned short get_fpu_mxcsr( struct tas
 	}
 }
 
+#if 0
+
 void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd )
 {
 	if ( cpu_has_fxsr ) {
@@ -222,6 +226,8 @@ void set_fpu_twd( struct task_struct *ts
 	}
 }
 
+#endif  /*  0  */
+
 /*
  * FXSR floating point environment conversions.
  */
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -49,7 +49,7 @@ static void end_8259A_irq (unsigned int 
 
 #define shutdown_8259A_irq	disable_8259A_irq
 
-void mask_and_ack_8259A(unsigned int);
+static void mask_and_ack_8259A(unsigned int);
 
 unsigned int startup_8259A_irq(unsigned int irq)
 { 
@@ -58,14 +58,13 @@ unsigned int startup_8259A_irq(unsigned 
 }
 
 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
+	.typename = "XT-PIC",
+	.startup = startup_8259A_irq,
+	.shutdown = shutdown_8259A_irq,
+	.enable = enable_8259A_irq,
+	.disable = disable_8259A_irq,
+	.ack = mask_and_ack_8259A,
+	.end = end_8259A_irq,
 };
 
 /*
@@ -169,7 +168,7 @@ static inline int i8259A_irq_real(unsign
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(unsigned int irq)
 {
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
@@ -263,7 +262,7 @@ static int i8259A_resume(struct sys_devi
 	return 0;
 }
 
-static int i8259A_suspend(struct sys_device *dev, u32 state)
+static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
 {
 	save_ELCR(irq_trigger);
 	return 0;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -188,7 +188,7 @@ static void unmask_IO_APIC_irq (unsigned
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
@@ -264,7 +264,7 @@ cpumask_t __cacheline_aligned pending_ir
 static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
 static int physical_balance = 0;
 
-struct irq_cpu_info {
+static struct irq_cpu_info {
 	unsigned long * last_irq;
 	unsigned long * irq_delta;
 	unsigned long irq;
@@ -275,7 +275,7 @@ struct irq_cpu_info {
 #define IRQ_DELTA(cpu,irq) 	(irq_cpu_data[cpu].irq_delta[irq])
 
 #define IDLE_ENOUGH(cpu,now) \
-		(idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
+	(idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1))
 
 #define IRQ_ALLOWED(cpu, allowed_mask)	cpu_isset(cpu, allowed_mask)
 
@@ -286,7 +286,7 @@ struct irq_cpu_info {
 #define BALANCED_IRQ_MORE_DELTA		(HZ/10)
 #define BALANCED_IRQ_LESS_DELTA		(HZ)
 
-long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL;
+static long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL;
 
 static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
 			unsigned long now, int direction)
@@ -685,8 +685,8 @@ void fastcall send_IPI_self(int vector)
  */
 
 #define MAX_PIRQS 8
-int pirq_entries [MAX_PIRQS];
-int pirqs_enabled;
+static int pirq_entries [MAX_PIRQS];
+static int pirqs_enabled;
 int skip_ioapic_setup;
 
 static int __init ioapic_setup(char *str)
@@ -1179,7 +1179,7 @@ static inline void ioapic_register_intr(
 	}
 }
 
-void __init setup_IO_APIC_irqs(void)
+static void __init setup_IO_APIC_irqs(void)
 {
 	struct IO_APIC_route_entry entry;
 	int apic, pin, idx, irq, first_notcon = 1, vector;
@@ -1258,7 +1258,7 @@ void __init setup_IO_APIC_irqs(void)
 /*
  * Set up the 8259A-master output pin:
  */
-void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
+static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
@@ -1452,6 +1452,8 @@ void __init print_IO_APIC(void)
 	return;
 }
 
+#if 0
+
 static void print_APIC_bitfield (int base)
 {
 	unsigned int v;
@@ -1594,6 +1596,8 @@ void /*__init*/ print_PIC(void)
 	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
+#endif  /*  0  */
+
 static void __init enable_IO_APIC(void)
 {
 	union IO_APIC_reg_01 reg_01;
@@ -2171,7 +2175,6 @@ static inline void check_timer(void)
 				disable_8259A_irq(0);
 				setup_nmi();
 				enable_8259A_irq(0);
-				check_nmi_watchdog();
 			}
 			return;
 		}
@@ -2194,7 +2197,6 @@ static inline void check_timer(void)
 				add_pin_to_irq(0, 0, pin2);
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
-				check_nmi_watchdog();
 			}
 			return;
 		}
@@ -2295,7 +2297,7 @@ struct sysfs_ioapic_data {
 };
 static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
 
-static int ioapic_suspend(struct sys_device *dev, u32 state)
+static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
 {
 	struct IO_APIC_route_entry *entry;
 	struct sysfs_ioapic_data *data;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -16,6 +16,9 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
+EXPORT_PER_CPU_SYMBOL(irq_stat);
+
 #ifndef CONFIG_X86_LOCAL_APIC
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
@@ -246,7 +249,7 @@ skip:
 		for (j = 0; j < NR_CPUS; j++)
 			if (cpu_online(j))
 				seq_printf(p, "%10u ",
-					irq_stat[j].apic_timer_irqs);
+					per_cpu(irq_stat,j).apic_timer_irqs);
 		seq_putc(p, '\n');
 #endif
 		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -84,7 +84,11 @@ static inline void prepare_singlestep(st
 {
 	regs->eflags |= TF_MASK;
 	regs->eflags &= ~IF_MASK;
-	regs->eip = (unsigned long)&p->ainsn.insn;
+	/*single step inline if the instruction is an int3*/
+	if (p->opcode == BREAKPOINT_INSTRUCTION)
+		regs->eip = (unsigned long)p->addr;
+	else
+		regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
 /*
@@ -117,6 +121,12 @@ static int kprobe_handler(struct pt_regs
 		   Disarm the probe we just hit, and ignore it. */
 		p = get_kprobe(addr);
 		if (p) {
+			if (kprobe_status == KPROBE_HIT_SS) {
+				regs->eflags &= ~TF_MASK;
+				regs->eflags |= kprobe_saved_eflags;
+				unlock_kprobes();
+				goto no_kprobe;
+			}
 			disarm_kprobe(p, regs);
 			ret = 1;
 		} else {
@@ -159,17 +169,16 @@ static int kprobe_handler(struct pt_regs
 	if (is_IF_modifier(p->opcode))
 		kprobe_saved_eflags &= ~IF_MASK;
 
-	if (p->pre_handler(p, regs)) {
+	if (p->pre_handler && p->pre_handler(p, regs))
 		/* handler has already set things up, so skip ss setup */
 		return 1;
-	}
 
-      ss_probe:
+ss_probe:
 	prepare_singlestep(p, regs);
 	kprobe_status = KPROBE_HIT_SS;
 	return 1;
 
-      no_kprobe:
+no_kprobe:
 	preempt_enable_no_resched();
 	return ret;
 }
@@ -208,6 +217,13 @@ static void resume_execution(struct kpro
 		*tos &= ~(TF_MASK | IF_MASK);
 		*tos |= kprobe_old_eflags;
 		break;
+	case 0xc3:		/* ret/lret */
+	case 0xcb:
+	case 0xc2:
+	case 0xca:
+		regs->eflags &= ~TF_MASK;
+		/* eip is already adjusted, no more changes required*/
+		return;
 	case 0xe8:		/* call relative - Fix return addr */
 		*tos = orig_eip + (*tos - copy_eip);
 		break;
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -49,7 +49,7 @@ int mp_bus_id_to_node [MAX_MP_BUSSES];
 int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
-int mp_current_pci_id;
+static int mp_current_pci_id;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
@@ -119,7 +119,7 @@ static int MP_valid_apicid(int apicid, i
 }
 #endif
 
-void __init MP_processor_info (struct mpc_config_processor *m)
+static void __init MP_processor_info (struct mpc_config_processor *m)
 {
  	int ver, apicid;
 	physid_mask_t tmp;
@@ -863,7 +863,7 @@ void __init mp_register_lapic (
 #define MP_ISA_BUS		0
 #define MP_MAX_IOAPIC_PIN	127
 
-struct mp_ioapic_routing {
+static struct mp_ioapic_routing {
 	int			apic_id;
 	int			gsi_base;
 	int			gsi_end;
@@ -982,6 +982,7 @@ void __init mp_override_legacy_irq (
 	return;
 }
 
+int es7000_plat;
 
 void __init mp_config_acpi_legacy_irqs (void)
 {
@@ -996,9 +997,9 @@ void __init mp_config_acpi_legacy_irqs (
 	Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
 
 	/*
-	 * ES7000 has no legacy identity mappings
+	 * Older generations of ES7000 have no legacy identity mappings
 	 */
-	if (es7000_plat)
+	if (es7000_plat == 1)
 		return;
 
 	/* 
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -291,7 +291,7 @@ static struct notifier_block msr_class_c
 	.notifier_call = msr_class_cpu_callback,
 };
 
-int __init msr_init(void)
+static int __init msr_init(void)
 {
 	int i, err = 0;
 	i = 0;
@@ -328,7 +328,7 @@ out:
 	return err;
 }
 
-void __exit msr_exit(void)
+static void __exit msr_exit(void)
 {
 	int cpu = 0;
 	for_each_online_cpu(cpu)
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -102,20 +102,21 @@ int nmi_active;
 	(P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
 	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
 
-int __init check_nmi_watchdog (void)
+static int __init check_nmi_watchdog(void)
 {
 	unsigned int prev_nmi_count[NR_CPUS];
 	int cpu;
 
-	printk(KERN_INFO "testing NMI watchdog ... ");
+	if (nmi_watchdog == NMI_NONE)
+		return 0;
+
+	printk(KERN_INFO "Testing NMI watchdog ... ");
 
 	for (cpu = 0; cpu < NR_CPUS; cpu++)
-		prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
+		prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count;
 	local_irq_enable();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
-	/* FIXME: Only boot CPU is online at this stage.  Check CPUs
-           as they come up. */
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 #ifdef CONFIG_SMP
 		/* Check cpu_callin_map here because that is set
@@ -139,6 +140,8 @@ int __init check_nmi_watchdog (void)
 
 	return 0;
 }
+/* This needs to happen later in boot so counters are working */
+late_initcall(check_nmi_watchdog);
 
 static int __init setup_nmi_watchdog(char *str)
 {
@@ -265,7 +268,7 @@ void enable_timer_nmi_watchdog(void)
 
 static int nmi_pm_active; /* nmi_active before suspend */
 
-static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
+static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
 {
 	nmi_pm_active = nmi_active;
 	disable_lapic_nmi_watchdog();
@@ -483,7 +486,7 @@ void nmi_watchdog_tick (struct pt_regs *
 	 */
 	int sum, cpu = smp_processor_id();
 
-	sum = irq_stat[cpu].apic_timer_irqs;
+	sum = per_cpu(irq_stat, cpu).apic_timer_irqs;
 
 	if (last_irq_sums[cpu] == sum) {
 		/*
diff --git a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c
--- a/arch/i386/kernel/numaq.c
+++ b/arch/i386/kernel/numaq.c
@@ -30,9 +30,7 @@
 #include <linux/module.h>
 #include <linux/nodemask.h>
 #include <asm/numaq.h>
-
-/* These are needed before the pgdat's are created */
-extern long node_start_pfn[], node_end_pfn[];
+#include <asm/topology.h>
 
 #define	MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
 
@@ -59,6 +57,12 @@ static void __init smp_dump_qct(void)
 				eq->hi_shrd_mem_start - eq->priv_mem_size);
 			node_end_pfn[node] = MB_TO_PAGES(
 				eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
+
+			memory_present(node,
+				node_start_pfn[node], node_end_pfn[node]);
+			node_remap_size[node] = node_memmap_size_bytes(node,
+							node_start_pfn[node],
+							node_end_pfn[node]);
 		}
 	}
 }
diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
--- a/arch/i386/kernel/pci-dma.c
+++ b/arch/i386/kernel/pci-dma.c
@@ -22,7 +22,7 @@ struct dma_coherent_mem {
 };
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, int gfp)
+			   dma_addr_t *dma_handle, unsigned int __nocast gfp)
 {
 	void *ret;
 	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
+#include <linux/random.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -55,7 +56,7 @@
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
-int hlt_counter;
+static int hlt_counter;
 
 unsigned long boot_option_idle_override = 0;
 EXPORT_SYMBOL(boot_option_idle_override);
@@ -72,7 +73,7 @@ unsigned long thread_saved_pc(struct tas
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void);
-static cpumask_t cpu_idle_map;
+static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
 void disable_hlt(void)
 {
@@ -145,22 +146,21 @@ static void poll_idle (void)
  */
 void cpu_idle (void)
 {
-	int cpu = _smp_processor_id();
-
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
 			void (*idle)(void);
 
-			if (cpu_isset(cpu, cpu_idle_map))
-				cpu_clear(cpu, cpu_idle_map);
+			if (__get_cpu_var(cpu_idle_state))
+				__get_cpu_var(cpu_idle_state) = 0;
+
 			rmb();
 			idle = pm_idle;
 
 			if (!idle)
 				idle = default_idle;
 
-			irq_stat[cpu].idle_timestamp = jiffies;
+			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
 			idle();
 		}
 		schedule();
@@ -169,16 +169,28 @@ void cpu_idle (void)
 
 void cpu_idle_wait(void)
 {
-	int cpu;
+	unsigned int cpu, this_cpu = get_cpu();
 	cpumask_t map;
 
-	for_each_online_cpu(cpu)
-		cpu_set(cpu, cpu_idle_map);
+	set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
+	put_cpu();
+
+	cpus_clear(map);
+	for_each_online_cpu(cpu) {
+		per_cpu(cpu_idle_state, cpu) = 1;
+		cpu_set(cpu, map);
+	}
+
+	__get_cpu_var(cpu_idle_state) = 0;
 
 	wmb();
 	do {
 		ssleep(1);
-		cpus_and(map, cpu_idle_map, cpu_online_map);
+		for_each_online_cpu(cpu) {
+			if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+				cpu_clear(cpu, map);
+		}
+		cpus_and(map, map, cpu_online_map);
 	} while (!cpus_empty(map));
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
@@ -388,6 +400,17 @@ int copy_thread(int nr, unsigned long cl
 	int err;
 
 	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
+	/*
+	 * The below -8 is to reserve 8 bytes on top of the ring0 stack.
+	 * This is necessary to guarantee that the entire "struct pt_regs"
+	 * is accessable even if the CPU haven't stored the SS/ESP registers
+	 * on the stack (interrupt gate does not save these registers
+	 * when switching to the same priv ring).
+	 * Therefore beware: accessing the xss/esp fields of the
+	 * "struct pt_regs" is possible, but they may contain the
+	 * completely wrong values.
+	 */
+	childregs = (struct pt_regs *) ((unsigned long) childregs - 8);
 	*childregs = *regs;
 	childregs->eax = 0;
 	childregs->esp = esp;
@@ -536,13 +559,6 @@ handle_io_bitmap(struct thread_struct *n
 	 */
 	tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 }
-/*
- * This special macro can be used to load a debugging register
- */
-#define loaddebug(thread,register) \
-		__asm__("movl %0,%%db" #register  \
-			: /* no output */ \
-			:"r" (thread->debugreg[register]))
 
 /*
  *	switch_to(x,yn) should switch tasks from x to y.
@@ -596,8 +612,8 @@ struct task_struct fastcall * __switch_t
 	 * Save away %fs and %gs. No need to save %es and %ds, as
 	 * those are always kernel segments while inside the kernel.
 	 */
-	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
-	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
+	asm volatile("mov %%fs,%0":"=m" (prev->fs));
+	asm volatile("mov %%gs,%0":"=m" (prev->gs));
 
 	/*
 	 * Restore %fs and %gs if needed.
@@ -828,3 +844,9 @@ asmlinkage int sys_get_thread_area(struc
 	return 0;
 }
 
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (randomize_va_space)
+		sp -= get_random_int() % 8192;
+	return sp & ~0xf;
+}
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -15,6 +15,8 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
+#include <linux/seccomp.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -510,7 +512,7 @@ asmlinkage int sys_ptrace(long request, 
 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
 	case PTRACE_CONT:	/* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -542,7 +544,7 @@ asmlinkage int sys_ptrace(long request, 
 
 	case PTRACE_SINGLESTEP:	/* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		set_singlestep(child);
@@ -678,24 +680,21 @@ void send_sigtrap(struct task_struct *ts
 __attribute__((regparm(3)))
 void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	if (unlikely(current->audit_context)) {
-		if (!entryexit)
-			audit_syscall_entry(current, regs->orig_eax,
-					    regs->ebx, regs->ecx,
-					    regs->edx, regs->esi);
-		else
-			audit_syscall_exit(current, regs->eax);
-	}
+	/* do the secure computing check first */
+	secure_computing(regs->orig_eax);
+
+	if (unlikely(current->audit_context) && entryexit)
+		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
 
 	if (!(current->ptrace & PT_PTRACED))
-		return;
+		goto out;
 
 	/* Fake a debug trap */
 	if (test_thread_flag(TIF_SINGLESTEP))
 		send_sigtrap(current, regs, 0);
 
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+		goto out;
 
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
@@ -710,4 +709,9 @@ void do_syscall_trace(struct pt_regs *re
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+ out:
+	if (unlikely(current->audit_context) && !entryexit)
+		audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+				    regs->ebx, regs->ecx, regs->edx, regs->esi);
+
 }
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
--- a/arch/i386/kernel/quirks.c
+++ b/arch/i386/kernel/quirks.c
@@ -7,7 +7,7 @@
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
-void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
+static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
 {
 	u8 config, rev;
 	u32 word;
@@ -37,7 +37,9 @@ void __devinit quirk_intel_irqbalance(st
 		irqbalance_disable("");
 #endif
 		noirqdebug_setup("");
+#ifdef CONFIG_PROC_FS
 		no_irq_affinity = 1;
+#endif
 	}
 
 	config &= ~0x2;
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -13,6 +13,7 @@
 #include <asm/uaccess.h>
 #include <asm/apic.h>
 #include "mach_reboot.h"
+#include <linux/reboot_fixups.h>
 
 /*
  * Power off function, if any
@@ -348,6 +349,7 @@ void machine_restart(char * __unused)
 		/* rebooting needs to touch the page at absolute addr 0 */
 		*((unsigned short *)__va(0x472)) = reboot_mode;
 		for (;;) {
+			mach_reboot_fixups(); /* for board specific fixups */
 			mach_reboot();
 			/* That didn't work - force a triple fault.. */
 			__asm__ __volatile__("lidt %0": :"m" (no_idt));
diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c
new file mode 100644
--- /dev/null
+++ b/arch/i386/kernel/reboot_fixups.c
@@ -0,0 +1,56 @@
+/*
+ * linux/arch/i386/kernel/reboot_fixups.c
+ *
+ * This is a good place to put board specific reboot fixups.
+ *
+ * List of supported fixups:
+ * geode-gx1/cs5530a - Jaya Kumar <jayalk@intworks.biz>
+ *
+ */
+
+#include <asm/delay.h>
+#include <linux/pci.h>
+
+static void cs5530a_warm_reset(struct pci_dev *dev)
+{
+	/* writing 1 to the reset control register, 0x44 causes the
+	cs5530a to perform a system warm reset */
+	pci_write_config_byte(dev, 0x44, 0x1);
+	udelay(50); /* shouldn't get here but be safe and spin-a-while */
+	return;
+}
+
+struct device_fixup {
+	unsigned int vendor;
+	unsigned int device;
+	void (*reboot_fixup)(struct pci_dev *);
+};
+
+static struct device_fixup fixups_table[] = {
+{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset },
+};
+
+/*
+ * we see if any fixup is available for our current hardware. if there
+ * is a fixup, we call it and we expect to never return from it. if we
+ * do return, we keep looking and then eventually fall back to the
+ * standard mach_reboot on return.
+ */
+void mach_reboot_fixups(void)
+{
+	struct device_fixup *cur;
+	struct pci_dev *dev;
+	int i;
+
+	for (i=0; i < (sizeof(fixups_table)/sizeof(fixups_table[0])); i++) {
+		cur = &(fixups_table[i]);
+		dev = pci_get_device(cur->vendor, cur->device, 0);
+		if (!dev)
+			continue;
+
+		cur->reboot_fixup(dev);
+	}
+
+	printk(KERN_WARNING "No reboot fixup found for your hardware\n");
+}
+
diff --git a/arch/i386/kernel/scx200.c b/arch/i386/kernel/scx200.c
--- a/arch/i386/kernel/scx200.c
+++ b/arch/i386/kernel/scx200.c
@@ -13,6 +13,9 @@
 
 #include <linux/scx200.h>
 
+/* Verify that the configuration block really is there */
+#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+
 #define NAME "scx200"
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
@@ -22,9 +25,13 @@ MODULE_LICENSE("GPL");
 unsigned scx200_gpio_base = 0;
 long scx200_gpio_shadow[2];
 
+unsigned scx200_cb_base = 0;
+
 static struct pci_device_id scx200_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS)   },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS)   },
 	{ },
 };
 MODULE_DEVICE_TABLE(pci,scx200_tbl);
@@ -37,7 +44,6 @@ static struct pci_driver scx200_pci_driv
 	.probe = scx200_probe,
 };
 
-DEFINE_SPINLOCK(scx200_gpio_lock);
 static DEFINE_SPINLOCK(scx200_gpio_config_lock);
 
 static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -45,22 +51,39 @@ static int __devinit scx200_probe(struct
 	int bank;
 	unsigned base;
 
-	base = pci_resource_start(pdev, 0);
-	printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
-
-	if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
-		printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
-		return -EBUSY;
+	if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
+	    pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) {
+		base = pci_resource_start(pdev, 0);
+		printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+		if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+			printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+			return -EBUSY;
+		}
+
+		scx200_gpio_base = base;
+
+		/* read the current values driven on the GPIO signals */
+		for (bank = 0; bank < 2; ++bank)
+			scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+
+	} else {
+		/* find the base of the Configuration Block */
+		if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) {
+			scx200_cb_base = SCx200_CB_BASE_FIXED;
+		} else {
+			pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base);
+			if (scx200_cb_probe(base)) {
+				scx200_cb_base = base;
+			} else {
+				printk(KERN_WARNING NAME ": Configuration Block not found\n");
+				return -ENODEV;
+			}
+		}
+		printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base);
 	}
 
-	scx200_gpio_base = base;
-
-	/* read the current values driven on the GPIO signals */
-	for (bank = 0; bank < 2; ++bank)
-		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
-
 	return 0;
-
 }
 
 u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
@@ -81,6 +104,7 @@ u32 scx200_gpio_configure(int index, u32
 	return config;
 }
 
+#if 0
 void scx200_gpio_dump(unsigned index)
 {
 	u32 config = scx200_gpio_configure(index, ~0, 0);
@@ -112,15 +136,16 @@ void scx200_gpio_dump(unsigned index)
 		printk(" DEBOUNCE"); /* debounce */
 	printk("\n");
 }
+#endif  /*  0  */
 
-int __init scx200_init(void)
+static int __init scx200_init(void)
 {
 	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
 
 	return pci_module_init(&scx200_pci_driver);
 }
 
-void __exit scx200_cleanup(void)
+static void __exit scx200_cleanup(void)
 {
 	pci_unregister_driver(&scx200_pci_driver);
 	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
@@ -131,9 +156,8 @@ module_exit(scx200_cleanup);
 
 EXPORT_SYMBOL(scx200_gpio_base);
 EXPORT_SYMBOL(scx200_gpio_shadow);
-EXPORT_SYMBOL(scx200_gpio_lock);
 EXPORT_SYMBOL(scx200_gpio_configure);
-EXPORT_SYMBOL(scx200_gpio_dump);
+EXPORT_SYMBOL(scx200_cb_base);
 
 /*
     Local variables:
diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c
--- a/arch/i386/kernel/semaphore.c
+++ b/arch/i386/kernel/semaphore.c
@@ -10,7 +10,7 @@
  *	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>
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -49,12 +49,12 @@
  *    we cannot lose wakeup events.
  */
 
-fastcall void __up(struct semaphore *sem)
+static fastcall void __attribute_used__  __up(struct semaphore *sem)
 {
 	wake_up(&sem->wait);
 }
 
-fastcall void __sched __down(struct semaphore * sem)
+static fastcall void __attribute_used__ __sched __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
@@ -91,7 +91,7 @@ fastcall void __sched __down(struct sema
 	tsk->state = TASK_RUNNING;
 }
 
-fastcall int __sched __down_interruptible(struct semaphore * sem)
+static fastcall int __attribute_used__ __sched __down_interruptible(struct semaphore * sem)
 {
 	int retval = 0;
 	struct task_struct *tsk = current;
@@ -154,7 +154,7 @@ fastcall int __sched __down_interruptibl
  * single "cmpxchg" without failure cases,
  * but then it wouldn't work on a 386.
  */
-fastcall int __down_trylock(struct semaphore * sem)
+static fastcall int __attribute_used__ __down_trylock(struct semaphore * sem)
 {
 	int sleepers;
 	unsigned long flags;
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -40,6 +40,7 @@
 #include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/edd.h>
+#include <linux/nodemask.h>
 #include <video/edid.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
@@ -74,7 +75,6 @@ struct cpuinfo_x86 new_cpu_data __initda
 struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 
 unsigned long mmu_cr4_features;
-EXPORT_SYMBOL_GPL(mmu_cr4_features);
 
 #ifdef	CONFIG_ACPI_INTERPRETER
 	int acpi_disabled = 0;
@@ -117,8 +117,6 @@ struct edid_info edid_info;
 struct ist_info ist_info;
 struct e820map e820;
 
-unsigned char aux_device_present;
-
 extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
 extern void generic_apic_probe(char *);
@@ -427,10 +425,10 @@ struct change_member {
 	struct e820entry *pbios; /* pointer to original bios entry */
 	unsigned long long addr; /* address for this change point */
 };
-struct change_member change_point_list[2*E820MAX] __initdata;
-struct change_member *change_point[2*E820MAX] __initdata;
-struct e820entry *overlap_list[E820MAX] __initdata;
-struct e820entry new_bios[E820MAX] __initdata;
+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;
 
 static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
 {
@@ -951,8 +949,6 @@ unsigned long __init find_max_low_pfn(vo
 	return max_low_pfn;
 }
 
-#ifndef CONFIG_DISCONTIGMEM
-
 /*
  * Free all available memory for boot time allocation.  Used
  * as a callback function by efi_memory_walk()
@@ -1026,15 +1022,15 @@ static void __init reserve_ebda_region(v
 		reserve_bootmem(addr, PAGE_SIZE);	
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+void __init setup_bootmem_allocator(void);
 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(init_pg_tables_end);
+	min_low_pfn = PFN_UP(init_pg_tables_end);
 
 	find_max_pfn();
 
@@ -1050,10 +1046,43 @@ static unsigned long __init setup_memory
 #endif
 	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
 			pages_to_mb(max_low_pfn));
+
+	setup_bootmem_allocator();
+
+	return max_low_pfn;
+}
+
+void __init zone_sizes_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	unsigned int max_dma, low;
+
+	max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	low = max_low_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] = highend_pfn - low;
+#endif
+	}
+	free_area_init(zones_size);
+}
+#else
+extern unsigned long setup_memory(void);
+extern void zone_sizes_init(void);
+#endif /* !CONFIG_DISCONTIGMEM */
+
+void __init setup_bootmem_allocator(void)
+{
+	unsigned long bootmap_size;
 	/*
 	 * Initialize the boot-time allocator (with low memory only):
 	 */
-	bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+	bootmap_size = init_bootmem(min_low_pfn, max_low_pfn);
 
 	register_bootmem_low_pages(max_low_pfn);
 
@@ -1063,7 +1092,7 @@ static unsigned long __init setup_memory
 	 * the (very unlikely) case of us accidentally initializing the
 	 * bootmem allocator with an invalid RAM area.
 	 */
-	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
+	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(min_low_pfn) +
 			 bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
 
 	/*
@@ -1120,11 +1149,25 @@ static unsigned long __init setup_memory
 		}
 	}
 #endif
-	return max_low_pfn;
 }
-#else
-extern unsigned long setup_memory(void);
-#endif /* !CONFIG_DISCONTIGMEM */
+
+/*
+ * The node 0 pgdat is initialized before all of these because
+ * it's needed for bootmem.  node>0 pgdats have their virtual
+ * space allocated before the pagetables are in place to access
+ * them, so they can't be cleared then.
+ *
+ * This should all compile down to nothing when NUMA is off.
+ */
+void __init remapped_pgdat_init(void)
+{
+	int nid;
+
+	for_each_online_node(nid) {
+		if (nid != 0)
+			memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
+	}
+}
 
 /*
  * Request address space for all standard RAM and ROM resources
@@ -1384,7 +1427,6 @@ void __init setup_arch(char **cmdline_p)
 		machine_submodel_id = SYS_DESC_TABLE.table[1];
 		BIOS_revision = SYS_DESC_TABLE.table[2];
 	}
-	aux_device_present = AUX_DEVICE_INFO;
 	bootloader_type = LOADER_TYPE;
 
 #ifdef CONFIG_BLK_DEV_RAM
@@ -1432,6 +1474,8 @@ void __init setup_arch(char **cmdline_p)
 	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
 #endif
 	paging_init();
+	remapped_pgdat_init();
+	zone_sizes_init();
 
 	/*
 	 * NOTE: at this point the bootmem allocator is fully available.
@@ -1458,11 +1502,13 @@ void __init setup_arch(char **cmdline_p)
 	if (efi_enabled)
 		efi_map_memmap();
 
+#ifdef CONFIG_ACPI_BOOT
 	/*
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
 	 */
 	acpi_boot_table_init();
 	acpi_boot_init();
+#endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (smp_found_config)
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -93,7 +93,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -105,7 +105,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -187,7 +187,7 @@ restore_sigcontext(struct pt_regs *regs,
 		struct _fpstate __user * buf;
 		err |= __get_user(buf, &sc->fpstate);
 		if (buf) {
-			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
 				goto badframe;
 			err |= restore_i387(buf);
 		} else {
@@ -213,7 +213,7 @@ asmlinkage int sys_sigreturn(unsigned lo
 	sigset_t set;
 	int eax;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_NSIG_WORDS > 1
@@ -243,7 +243,7 @@ asmlinkage int sys_rt_sigreturn(unsigned
 	sigset_t set;
 	int eax;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
@@ -557,6 +557,16 @@ handle_signal(unsigned long sig, siginfo
 		}
 	}
 
+	/*
+	 * If TF is set due to a debugger (PT_DTRACE), clear the TF flag so
+	 * that register information in the sigcontext is correct.
+	 */
+	if (unlikely(regs->eflags & TF_MASK)
+	    && likely(current->ptrace & PT_DTRACE)) {
+		current->ptrace &= ~PT_DTRACE;
+		regs->eflags &= ~TF_MASK;
+	}
+
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(sig, ka, info, oldset, regs);
@@ -608,7 +618,7 @@ int fastcall do_signal(struct pt_regs *r
 		 * inside the kernel.
 		 */
 		if (unlikely(current->thread.debugreg[7])) {
-			__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
+			loaddebug(&current->thread, 7);
 		}
 
 		/* Whee!  Actually deliver the signal.  */
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -188,7 +188,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	local_irq_restore(flags);
 }
 
-inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
+void send_IPI_mask_sequence(cpumask_t mask, int vector)
 {
 	unsigned long cfg, flags;
 	unsigned int query_cpu;
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -62,6 +62,8 @@ static int __initdata smp_b_stepping;
 int smp_num_siblings = 1;
 int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
 EXPORT_SYMBOL(phys_proc_id);
+int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
+EXPORT_SYMBOL(cpu_core_id);
 
 /* bitmap of online cpus */
 cpumask_t cpu_online_map;
@@ -77,9 +79,6 @@ u8 x86_cpu_to_apicid[NR_CPUS] =
 			{ [0 ... NR_CPUS-1] = 0xff };
 EXPORT_SYMBOL(x86_cpu_to_apicid);
 
-/* Set when the idlers are all forked */
-int smp_threads_ready;
-
 /*
  * Trampoline 80x86 program as an array.
  */
@@ -89,6 +88,8 @@ extern unsigned char trampoline_end  [];
 static unsigned char *trampoline_base;
 static int trampoline_exec;
 
+static void map_cpu_to_logical_apicid(void);
+
 /*
  * Currently trivial. Write the real->protected mode
  * bootstrap into the page concerned. The caller
@@ -319,7 +320,7 @@ extern void calibrate_delay(void);
 
 static atomic_t init_deasserted;
 
-void __init smp_callin(void)
+static void __init smp_callin(void)
 {
 	int cpuid, phys_id;
 	unsigned long timeout;
@@ -408,7 +409,7 @@ void __init smp_callin(void)
 		synchronize_tsc_ap();
 }
 
-int cpucount;
+static int cpucount;
 
 /*
  * Activate a secondary processor.
@@ -506,7 +507,7 @@ static inline void unmap_cpu_to_node(int
 
 u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
-void map_cpu_to_logical_apicid(void)
+static void map_cpu_to_logical_apicid(void)
 {
 	int cpu = smp_processor_id();
 	int apicid = logical_smp_processor_id();
@@ -515,7 +516,7 @@ void map_cpu_to_logical_apicid(void)
 	map_cpu_to_node(cpu, apicid_to_node(apicid));
 }
 
-void unmap_cpu_to_logical_apicid(int cpu)
+static void unmap_cpu_to_logical_apicid(int cpu)
 {
 	cpu_2_logical_apicid[cpu] = BAD_APICID;
 	unmap_cpu_to_node(cpu);
@@ -847,9 +848,6 @@ static int __init do_boot_cpu(int apicid
 	return boot_error;
 }
 
-cycles_t cacheflush_time;
-unsigned long cache_decay_ticks;
-
 static void smp_tune_scheduling (void)
 {
 	unsigned long cachesize;       /* kB   */
@@ -870,7 +868,6 @@ static void smp_tune_scheduling (void)
 		 * this basically disables processor-affinity
 		 * scheduling on SMP without a TSC.
 		 */
-		cacheflush_time = 0;
 		return;
 	} else {
 		cachesize = boot_cpu_data.x86_cache_size;
@@ -878,17 +875,7 @@ static void smp_tune_scheduling (void)
 			cachesize = 16; /* Pentiums, 2x8kB cache */
 			bandwidth = 100;
 		}
-
-		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
-
-	cache_decay_ticks = (long)cacheflush_time/cpu_khz + 1;
-
-	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
-		(long)cacheflush_time/(cpu_khz/1000),
-		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
-	printk("task migration cache decay timeout: %ld msecs.\n",
-		cache_decay_ticks);
 }
 
 /*
@@ -900,6 +887,8 @@ static int boot_cpu_logical_apicid;
 void *xquad_portio;
 
 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
 
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
@@ -922,6 +911,9 @@ static void __init smp_boot_cpus(unsigne
 	cpus_clear(cpu_sibling_map[0]);
 	cpu_set(0, cpu_sibling_map[0]);
 
+	cpus_clear(cpu_core_map[0]);
+	cpu_set(0, cpu_core_map[0]);
+
 	/*
 	 * If we couldn't find an SMP configuration at boot time,
 	 * get out of here now!
@@ -934,6 +926,8 @@ static void __init smp_boot_cpus(unsigne
 			printk(KERN_NOTICE "Local APIC not detected."
 					   " Using dummy APIC emulation.\n");
 		map_cpu_to_logical_apicid();
+		cpu_set(0, cpu_sibling_map[0]);
+		cpu_set(0, cpu_core_map[0]);
 		return;
 	}
 
@@ -957,6 +951,8 @@ static void __init smp_boot_cpus(unsigne
 		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
 		smpboot_clear_io_apic_irqs();
 		phys_cpu_present_map = physid_mask_of_physid(0);
+		cpu_set(0, cpu_sibling_map[0]);
+		cpu_set(0, cpu_core_map[0]);
 		return;
 	}
 
@@ -970,6 +966,8 @@ static void __init smp_boot_cpus(unsigne
 		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
 		smpboot_clear_io_apic_irqs();
 		phys_cpu_present_map = physid_mask_of_physid(0);
+		cpu_set(0, cpu_sibling_map[0]);
+		cpu_set(0, cpu_core_map[0]);
 		return;
 	}
 
@@ -1050,10 +1048,13 @@ static void __init smp_boot_cpus(unsigne
 	 * construct cpu_sibling_map[], so that we can tell sibling CPUs
 	 * efficiently.
 	 */
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		cpus_clear(cpu_sibling_map[cpu]);
+		cpus_clear(cpu_core_map[cpu]);
+	}
 
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		struct cpuinfo_x86 *c = cpu_data + cpu;
 		int siblings = 0;
 		int i;
 		if (!cpu_isset(cpu, cpu_callout_map))
@@ -1063,7 +1064,7 @@ static void __init smp_boot_cpus(unsigne
 			for (i = 0; i < NR_CPUS; i++) {
 				if (!cpu_isset(i, cpu_callout_map))
 					continue;
-				if (phys_proc_id[cpu] == phys_proc_id[i]) {
+				if (cpu_core_id[cpu] == cpu_core_id[i]) {
 					siblings++;
 					cpu_set(i, cpu_sibling_map[cpu]);
 				}
@@ -1073,12 +1074,23 @@ static void __init smp_boot_cpus(unsigne
 			cpu_set(cpu, cpu_sibling_map[cpu]);
 		}
 
-		if (siblings != smp_num_siblings)
+		if (siblings != smp_num_siblings) {
 			printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
-	}
+			smp_num_siblings = siblings;
+		}
 
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		check_nmi_watchdog();
+		if (c->x86_num_cores > 1) {
+			for (i = 0; i < NR_CPUS; i++) {
+				if (!cpu_isset(i, cpu_callout_map))
+					continue;
+				if (phys_proc_id[cpu] == phys_proc_id[i]) {
+					cpu_set(i, cpu_core_map[cpu]);
+				}
+			}
+		} else {
+			cpu_core_map[cpu] = cpu_sibling_map[cpu];
+		}
+	}
 
 	smpboot_setup_io_apic();
 
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -30,6 +30,7 @@
 #include <linux/acpi.h>
 #include <linux/nodemask.h>
 #include <asm/srat.h>
+#include <asm/topology.h>
 
 /*
  * proximity macros and definitions
@@ -58,8 +59,6 @@ static int num_memory_chunks;		/* total 
 static int zholes_size_init;
 static unsigned long zholes_size[MAX_NUMNODES * MAX_NR_ZONES];
 
-extern unsigned long node_start_pfn[], node_end_pfn[];
-
 extern void * boot_ioremap(unsigned long, unsigned long);
 
 /* Identify CPU proximity domains */
@@ -182,6 +181,38 @@ static __init void chunk_to_zones(unsign
 	}
 }
 
+/*
+ * The SRAT table always lists ascending addresses, so can always
+ * assume that the first "start" address that you see is the real
+ * start of the node, and that the current "end" address is after
+ * the previous one.
+ */
+static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_chunk)
+{
+	/*
+	 * Only add present memory as told by the e820.
+	 * There is no guarantee from the SRAT that the memory it
+	 * enumerates is present at boot time because it represents
+	 * *possible* memory hotplug areas the same as normal RAM.
+	 */
+	if (memory_chunk->start_pfn >= max_pfn) {
+		printk (KERN_INFO "Ignoring SRAT pfns: 0x%08lx -> %08lx\n",
+			memory_chunk->start_pfn, memory_chunk->end_pfn);
+		return;
+	}
+	if (memory_chunk->nid != nid)
+		return;
+
+	if (!node_has_online_mem(nid))
+		node_start_pfn[nid] = memory_chunk->start_pfn;
+
+	if (node_start_pfn[nid] > memory_chunk->start_pfn)
+		node_start_pfn[nid] = memory_chunk->start_pfn;
+
+	if (node_end_pfn[nid] < memory_chunk->end_pfn)
+		node_end_pfn[nid] = memory_chunk->end_pfn;
+}
+
 /* Parse the ACPI Static Resource Affinity Table */
 static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
 {
@@ -262,29 +293,18 @@ static int __init acpi20_parse_srat(stru
 	printk("Number of memory chunks in system = %d\n", num_memory_chunks);
 
 	for (j = 0; j < num_memory_chunks; j++){
+		struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
 		printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
-		       j, node_memory_chunk[j].nid,
-		       node_memory_chunk[j].start_pfn,
-		       node_memory_chunk[j].end_pfn);
+		       j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
+		node_read_chunk(chunk->nid, chunk);
 	}
  
-	/*calculate node_start_pfn/node_end_pfn arrays*/
 	for_each_online_node(nid) {
-		int been_here_before = 0;
+		unsigned long start = node_start_pfn[nid];
+		unsigned long end = node_end_pfn[nid];
 
-		for (j = 0; j < num_memory_chunks; j++){
-			if (node_memory_chunk[j].nid == nid) {
-				if (been_here_before == 0) {
-					node_start_pfn[nid] = node_memory_chunk[j].start_pfn;
-					node_end_pfn[nid] = node_memory_chunk[j].end_pfn;
-					been_here_before = 1;
-				} else { /* We've found another chunk of memory for the node */
-					if (node_start_pfn[nid] < node_memory_chunk[j].start_pfn) {
-						node_end_pfn[nid] = node_memory_chunk[j].end_pfn;
-					}
-				}
-			}
-		}
+		memory_present(nid, start, end);
+		node_remap_size[nid] = node_memmap_size_bytes(nid, start, end);
 	}
 	return 1;
 out_fail:
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
new file mode 100644
--- /dev/null
+++ b/arch/i386/kernel/syscall_table.S
@@ -0,0 +1,291 @@
+.data
+ENTRY(sys_call_table)
+	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open		/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink	/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod		/* 15 */
+	.long sys_lchown16
+	.long sys_ni_syscall	/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid	/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid16
+	.long sys_getuid16
+	.long sys_stime		/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime		/* 30 */
+	.long sys_ni_syscall	/* old stty syscall holder */
+	.long sys_ni_syscall	/* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall	/* 35 - old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir		/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall	/* old prof syscall holder */
+	.long sys_brk		/* 45 */
+	.long sys_setgid16
+	.long sys_getgid16
+	.long sys_signal
+	.long sys_geteuid16
+	.long sys_getegid16	/* 50 */
+	.long sys_acct
+	.long sys_umount	/* recycled never used phys() */
+	.long sys_ni_syscall	/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl		/* 55 */
+	.long sys_ni_syscall	/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall	/* old ulimit syscall holder */
+	.long sys_olduname
+	.long sys_umask		/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp	/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid16	/* 70 */
+	.long sys_setregid16
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit	/* 75 */
+	.long sys_old_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups16	/* 80 */
+	.long sys_setgroups16
+	.long old_select
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink	/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap		/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown16	/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall	/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs	/* 100 */
+	.long sys_ioperm
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer	/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_uname
+	.long sys_iopl		/* 110 */
+	.long sys_vhangup
+	.long sys_ni_syscall	/* old "idle" system call */
+	.long sys_vm86old
+	.long sys_wait4
+	.long sys_swapoff	/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone		/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_modify_ldt
+	.long sys_adjtimex
+	.long sys_mprotect	/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall	/* old "create_module" */
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs		/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall	/* reserved for afs_syscall */
+	.long sys_setfsuid16
+	.long sys_setfsgid16
+	.long sys_llseek	/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv		/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock		/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam   /* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min  /* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid16
+	.long sys_getresuid16	/* 165 */
+	.long sys_vm86
+	.long sys_ni_syscall	/* Old sys_query_module */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid16	/* 170 */
+	.long sys_getresgid16
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread64	/* 180 */
+	.long sys_pwrite64
+	.long sys_chown16
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset	/* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall	/* reserved for streams1 */
+	.long sys_ni_syscall	/* reserved for streams2 */
+	.long sys_vfork		/* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64	/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid	/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups	/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid	/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid	/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64	/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall	/* reserved for TUX */
+	.long sys_ni_syscall
+	.long sys_gettid
+	.long sys_readahead	/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr	/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr	/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex		/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_set_thread_area
+	.long sys_get_thread_area
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64	/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_wait
+ 	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64
+	.long sys_tgkill	/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64
+	.long sys_ni_syscall	/* sys_vserver */
+	.long sys_mbind
+	.long sys_get_mempolicy
+	.long sys_set_mempolicy
+	.long sys_mq_open
+	.long sys_mq_unlink
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive	/* 280 */
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_ni_syscall		/* reserved for kexec */
+	.long sys_waitid
+	.long sys_ni_syscall		/* 285 */ /* available */
+	.long sys_add_key
+	.long sys_request_key
+	.long sys_keyctl
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -89,6 +89,35 @@ EXPORT_SYMBOL(i8253_lock);
 struct timer_opts *cur_timer = &timer_none;
 
 /*
+ * This is a special lock that is owned by the CPU and holds the index
+ * register we are working with.  It is required for NMI access to the
+ * CMOS/RTC registers.  See include/asm-i386/mc146818rtc.h for details.
+ */
+volatile unsigned long cmos_lock = 0;
+EXPORT_SYMBOL(cmos_lock);
+
+/* Routines for accessing the CMOS RAM/RTC. */
+unsigned char rtc_cmos_read(unsigned char addr)
+{
+	unsigned char val;
+	lock_cmos_prefix(addr);
+	outb_p(addr, RTC_PORT(0));
+	val = inb_p(RTC_PORT(1));
+	lock_cmos_suffix(addr);
+	return val;
+}
+EXPORT_SYMBOL(rtc_cmos_read);
+
+void rtc_cmos_write(unsigned char val, unsigned char addr)
+{
+	lock_cmos_prefix(addr);
+	outb_p(addr, RTC_PORT(0));
+	outb_p(val, RTC_PORT(1));
+	lock_cmos_suffix(addr);
+}
+EXPORT_SYMBOL(rtc_cmos_write);
+
+/*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
  */
@@ -175,19 +204,19 @@ static int set_rtc_mmss(unsigned long no
 {
 	int retval;
 
+	WARN_ON(irqs_disabled());
+
 	/* gets recalled with irq locally disabled */
-	spin_lock(&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 	if (efi_enabled)
 		retval = efi_set_rtc_mmss(nowtime);
 	else
 		retval = mach_set_rtc_mmss(nowtime);
-	spin_unlock(&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
 	return retval;
 }
 
-/* last time the cmos clock got updated */
-static long last_rtc_update;
 
 int timer_ack;
 
@@ -239,28 +268,6 @@ static inline void do_timer_interrupt(in
 
 	do_timer_interrupt_hook(regs);
 
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * 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.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    (xtime.tv_nsec / 1000)
-			>= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
-	    (xtime.tv_nsec / 1000)
-			<= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
-		/* horrible...FIXME */
-		if (efi_enabled) {
-	 		if (efi_set_rtc_mmss(xtime.tv_sec) == 0)
-				last_rtc_update = xtime.tv_sec;
-			else
-				last_rtc_update = xtime.tv_sec - 600;
-		} else if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
 
 	if (MCA_bus) {
 		/* The PS/2 uses level-triggered interrupts.  You can't
@@ -317,10 +324,59 @@ unsigned long get_cmos_time(void)
 
 	return retval;
 }
+static void sync_cmos_clock(unsigned long dummy);
+
+static struct timer_list sync_cmos_timer =
+                                      TIMER_INITIALIZER(sync_cmos_clock, 0, 0);
+
+static void sync_cmos_clock(unsigned long dummy)
+{
+	struct timeval now, next;
+	int fail = 1;
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * 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.
+	 * This code is run on a timer.  If the clock is set, that timer
+	 * may not expire at the correct time.  Thus, we adjust...
+	 */
+	if ((time_status & STA_UNSYNC) != 0)
+		/*
+		 * Not synced, exit, do not restart a timer (if one is
+		 * running, let it run out).
+		 */
+		return;
+
+	do_gettimeofday(&now);
+	if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
+	    now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
+		fail = set_rtc_mmss(now.tv_sec);
+
+	next.tv_usec = USEC_AFTER - now.tv_usec;
+	if (next.tv_usec <= 0)
+		next.tv_usec += USEC_PER_SEC;
+
+	if (!fail)
+		next.tv_sec = 659;
+	else
+		next.tv_sec = 0;
+
+	if (next.tv_usec >= USEC_PER_SEC) {
+		next.tv_sec++;
+		next.tv_usec -= USEC_PER_SEC;
+	}
+	mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
+}
+
+void notify_arch_cmos_timer(void)
+{
+	mod_timer(&sync_cmos_timer, jiffies + 1);
+}
 
 static long clock_cmos_diff, sleep_start;
 
-static int timer_suspend(struct sys_device *dev, u32 state)
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
 	/*
 	 * Estimate time zone so that set_time can update the clock
@@ -378,14 +434,14 @@ device_initcall(time_init_device);
 #ifdef CONFIG_HPET_TIMER
 extern void (*late_time_init)(void);
 /* Duplicate of time_init() below, with hpet_enable part added */
-void __init hpet_time_init(void)
+static void __init hpet_time_init(void)
 {
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
 	set_normalized_timespec(&wall_to_monotonic,
 		-xtime.tv_sec, -xtime.tv_nsec);
 
-	if (hpet_enable() >= 0) {
+	if ((hpet_enable() >= 0) && hpet_use_timer) {
 		printk("Using HPET for base-timer\n");
 	}
 
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
--- a/arch/i386/kernel/time_hpet.c
+++ b/arch/i386/kernel/time_hpet.c
@@ -23,9 +23,10 @@
 #include <asm/hpet.h>
 #include <linux/hpet.h>
 
-unsigned long hpet_period;	/* fsecs / HPET clock */
-unsigned long hpet_tick;	/* hpet clks count per tick */
-unsigned long hpet_address;	/* hpet memory map physical address */
+static unsigned long hpet_period;	/* fsecs / HPET clock */
+unsigned long hpet_tick;		/* hpet clks count per tick */
+unsigned long hpet_address;		/* hpet memory map physical address */
+int hpet_use_timer;
 
 static int use_hpet; 		/* can be used for runtime check of hpet */
 static int boot_hpet_disable; 	/* boottime override for HPET timer */
@@ -38,7 +39,7 @@ int hpet_readl(unsigned long a)
 	return readl(hpet_virt_address + a);
 }
 
-void hpet_writel(unsigned long d, unsigned long a)
+static void hpet_writel(unsigned long d, unsigned long a)
 {
 	writel(d, hpet_virt_address + a);
 }
@@ -49,7 +50,7 @@ void hpet_writel(unsigned long d, unsign
  * comparator value and continue. Next tick can be caught by checking
  * for a change in the comparator value. Used in apic.c.
  */
-void __init wait_hpet_tick(void)
+static void __init wait_hpet_tick(void)
 {
 	unsigned int start_cmp_val, end_cmp_val;
 
@@ -73,26 +74,30 @@ static int hpet_timer_stop_set_go(unsign
 	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.
-	 */
-	cfg = hpet_readl(HPET_T0_CFG);
-	cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
-	       HPET_TN_SETVAL | HPET_TN_32BIT;
-	hpet_writel(cfg, HPET_T0_CFG);
-	/*
-	 * Some systems seems to need two writes to HPET_T0_CMP,
-	 * to get interrupts working
-	 */
-	hpet_writel(tick, HPET_T0_CMP);
-	hpet_writel(tick, HPET_T0_CMP);
+	if (hpet_use_timer) {
+		/*
+		 * Set up timer 0, as periodic with first interrupt to happen at
+		 * hpet_tick, and period also hpet_tick.
+		 */
+		cfg = hpet_readl(HPET_T0_CFG);
+		cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
+		       HPET_TN_SETVAL | HPET_TN_32BIT;
+		hpet_writel(cfg, HPET_T0_CFG);
 
+		/*
+		 * The first write after writing TN_SETVAL to the config register sets
+		 * the counter value, the second write sets the threshold.
+		 */
+		hpet_writel(tick, HPET_T0_CMP);
+		hpet_writel(tick, HPET_T0_CMP);
+	}
 	/*
  	 * Go!
  	 */
 	cfg = hpet_readl(HPET_CFG);
-	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
+	if (hpet_use_timer)
+		cfg |= HPET_CFG_LEGACY;
+	cfg |= HPET_CFG_ENABLE;
 	hpet_writel(cfg, HPET_CFG);
 
 	return 0;
@@ -121,13 +126,17 @@ int __init hpet_enable(void)
 	id = hpet_readl(HPET_ID);
 
 	/*
-	 * We are checking for value '1' or more in number field.
-	 * So, we are OK with HPET_EMULATE_RTC part too, where we need
-	 * to have atleast 2 timers.
+	 * We are checking for value '1' or more in number field if
+	 * CONFIG_HPET_EMULATE_RTC is set because we will need an
+	 * additional timer for RTC emulation.
+	 * However, we can do with one timer otherwise using the
+	 * the single HPET timer for system time.
 	 */
-	if (!(id & HPET_ID_NUMBER) ||
-	    !(id & HPET_ID_LEGSUP))
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (!(id & HPET_ID_NUMBER))
 		return -1;
+#endif
+
 
 	hpet_period = hpet_readl(HPET_PERIOD);
 	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD))
@@ -146,6 +155,8 @@ int __init hpet_enable(void)
 	if (hpet_tick_rem > (hpet_period >> 1))
 		hpet_tick++; /* rounding the result */
 
+	hpet_use_timer = id & HPET_ID_LEGSUP;
+
 	if (hpet_timer_stop_set_go(hpet_tick))
 		return -1;
 
@@ -196,7 +207,8 @@ int __init hpet_enable(void)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
-	wait_timer_tick = wait_hpet_tick;
+	if (hpet_use_timer)
+		wait_timer_tick = wait_hpet_tick;
 #endif
 	return 0;
 }
diff --git a/arch/i386/kernel/timers/common.c b/arch/i386/kernel/timers/common.c
--- a/arch/i386/kernel/timers/common.c
+++ b/arch/i386/kernel/timers/common.c
@@ -6,6 +6,7 @@
 #include <linux/timex.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/timer.h>
@@ -24,7 +25,7 @@
 
 #define CALIBRATE_TIME	(5 * 1000020/HZ)
 
-unsigned long __init calibrate_tsc(void)
+unsigned long calibrate_tsc(void)
 {
 	mach_prepare_counter();
 
@@ -139,7 +140,7 @@ bad_calibration:
 #endif
 
 /* calculate cpu_khz */
-void __init init_cpu_khz(void)
+void init_cpu_khz(void)
 {
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
@@ -158,3 +159,4 @@ void __init init_cpu_khz(void)
 		}
 	}
 }
+
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -79,7 +79,7 @@ static unsigned long get_offset_hpet(voi
 
 	eax = hpet_readl(HPET_COUNTER);
 	eax -= hpet_last;	/* hpet delta */
-
+	eax = min(hpet_tick, eax);
 	/*
          * Time offset = (hpet delta) * ( usecs per HPET clock )
 	 *             = (hpet delta) * ( usecs per tick / HPET clocks per tick)
@@ -105,9 +105,12 @@ static void mark_offset_hpet(void)
 	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
 	rdtsc(last_tsc_low, last_tsc_high);
 
-	offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
-	if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))) {
-		int lost_ticks = (offset - hpet_last) / hpet_tick;
+	if (hpet_use_timer)
+		offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
+	else
+		offset = hpet_readl(HPET_COUNTER);
+	if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {
+		int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;
 		jiffies_64 += lost_ticks;
 	}
 	hpet_last = offset;
@@ -118,7 +121,7 @@ static void mark_offset_hpet(void)
 	write_sequnlock(&monotonic_lock);
 }
 
-void delay_hpet(unsigned long loops)
+static void delay_hpet(unsigned long loops)
 {
 	unsigned long hpet_start, hpet_end;
 	unsigned long eax;
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -320,6 +320,26 @@ core_initcall(cpufreq_tsc);
 static inline void cpufreq_delayed_get(void) { return; }
 #endif 
 
+int recalibrate_cpu_khz(void)
+{
+#ifndef CONFIG_SMP
+	unsigned long cpu_khz_old = cpu_khz;
+
+	if (cpu_has_tsc) {
+		init_cpu_khz();
+		cpu_data[0].loops_per_jiffy =
+		    cpufreq_scale(cpu_data[0].loops_per_jiffy,
+			          cpu_khz_old,
+				  cpu_khz);
+		return 0;
+	} else
+		return -ENODEV;
+#else
+	return -ENODEV;
+#endif
+}
+EXPORT_SYMBOL(recalibrate_cpu_khz);
+
 static void mark_offset_tsc(void)
 {
 	unsigned long lost,delay;
@@ -477,7 +497,7 @@ static int __init init_tsc(char* overrid
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient;
 #ifdef CONFIG_HPET_TIMER
-		if (is_hpet_enabled()){
+		if (is_hpet_enabled() && hpet_use_timer) {
 			unsigned long result, remain;
 			printk("Using TSC for gettimeofday\n");
 			tsc_quotient = calibrate_tsc_hpet(NULL);
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -345,8 +345,7 @@ void die(const char * str, struct pt_reg
 
 	if (panic_on_oops) {
 		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(5 * HZ);
+		ssleep(5);
 		panic("Fatal exception");
 	}
 	do_exit(SIGSEGV);
@@ -452,6 +451,7 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", inv
 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, 0)
+DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
 
 fastcall void do_general_protection(struct pt_regs * regs, long error_code)
 {
@@ -643,16 +643,15 @@ void unset_nmi_callback(void)
 }
 
 #ifdef CONFIG_KPROBES
-fastcall int do_int3(struct pt_regs *regs, long error_code)
+fastcall void do_int3(struct pt_regs *regs, long error_code)
 {
 	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
 			== NOTIFY_STOP)
-		return 1;
+		return;
 	/* This is an interrupt gate, because kprobes wants interrupts
 	disabled.  Normal trap handlers don't. */
 	restore_interrupts(regs);
 	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
-	return 0;
 }
 #endif
 
@@ -707,8 +706,6 @@ fastcall void do_debug(struct pt_regs * 
 	/*
 	 * Single-stepping through TF: make sure we ignore any events in
 	 * kernel space (but re-enable TF when returning to user mode).
-	 * And if the event was due to a debugger (PT_DTRACE), clear the
-	 * TF flag so that register information is correct.
 	 */
 	if (condition & DR_STEP) {
 		/*
@@ -718,11 +715,6 @@ fastcall void do_debug(struct pt_regs * 
 		 */
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
-
-		if (likely(tsk->ptrace & PT_DTRACE)) {
-			tsk->ptrace &= ~PT_DTRACE;
-			regs->eflags &= ~TF_MASK;
-		}
 	}
 
 	/* Ok, finally something we can handle */
@@ -814,7 +806,7 @@ fastcall void do_coprocessor_error(struc
 	math_error((void __user *)regs->eip);
 }
 
-void simd_math_error(void __user *eip)
+static void simd_math_error(void __user *eip)
 {
 	struct task_struct * task;
 	siginfo_t info;
@@ -895,6 +887,51 @@ fastcall void do_spurious_interrupt_bug(
 #endif
 }
 
+fastcall void setup_x86_bogus_stack(unsigned char * stk)
+{
+	unsigned long *switch16_ptr, *switch32_ptr;
+	struct pt_regs *regs;
+	unsigned long stack_top, stack_bot;
+	unsigned short iret_frame16_off;
+	int cpu = smp_processor_id();
+	/* reserve the space on 32bit stack for the magic switch16 pointer */
+	memmove(stk, stk + 8, sizeof(struct pt_regs));
+	switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs));
+	regs = (struct pt_regs *)stk;
+	/* now the switch32 on 16bit stack */
+	stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
+	stack_top = stack_bot +	CPU_16BIT_STACK_SIZE;
+	switch32_ptr = (unsigned long *)(stack_top - 8);
+	iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20;
+	/* copy iret frame on 16bit stack */
+	memcpy((void *)(stack_bot + iret_frame16_off), &regs->eip, 20);
+	/* fill in the switch pointers */
+	switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off;
+	switch16_ptr[1] = __ESPFIX_SS;
+	switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) +
+		8 - CPU_16BIT_STACK_SIZE;
+	switch32_ptr[1] = __KERNEL_DS;
+}
+
+fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp)
+{
+	unsigned long *switch32_ptr;
+	unsigned char *stack16, *stack32;
+	unsigned long stack_top, stack_bot;
+	int len;
+	int cpu = smp_processor_id();
+	stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
+	stack_top = stack_bot +	CPU_16BIT_STACK_SIZE;
+	switch32_ptr = (unsigned long *)(stack_top - 8);
+	/* copy the data from 16bit stack to 32bit stack */
+	len = CPU_16BIT_STACK_SIZE - 8 - sp;
+	stack16 = (unsigned char *)(stack_bot + sp);
+	stack32 = (unsigned char *)
+		(switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len);
+	memcpy(stack32, stack16, len);
+	return stack32;
+}
+
 /*
  *  'math_state_restore()' saves the current math information in the
  * old math state array, and gets the new ones from the current task
@@ -1038,3 +1075,10 @@ void __init trap_init(void)
 
 	trap_init_hook();
 }
+
+static int __init kstack_setup(char *s)
+{
+	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+	return 0;
+}
+__setup("kstack=", kstack_setup);
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -145,29 +145,14 @@ static void mark_screen_rdonly(struct ta
 	preempt_disable();
 	spin_lock(&tsk->mm->page_table_lock);
 	pgd = pgd_offset(tsk->mm, 0xA0000);
-	if (pgd_none(*pgd))
+	if (pgd_none_or_clear_bad(pgd))
 		goto out;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		goto out;
-	}
 	pud = pud_offset(pgd, 0xA0000);
-	if (pud_none(*pud))
-		goto out;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
+	if (pud_none_or_clear_bad(pud))
 		goto out;
-	}
 	pmd = pmd_offset(pud, 0xA0000);
-	if (pmd_none(*pmd))
-		goto out;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
+	if (pmd_none_or_clear_bad(pmd))
 		goto out;
-	}
 	pte = mapped = pte_offset_map(pmd, 0xA0000);
 	for (i = 0; i < 32; i++) {
 		if (pte_present(*pte))
@@ -237,7 +222,7 @@ asmlinkage int sys_vm86(struct pt_regs r
 			goto out;
 		case VM86_PLUS_INSTALL_CHECK:
 			/* NOTE: on old vm86 stuff this will return the error
-			   from verify_area(), because the subfunction is
+			   from access_ok(), because the subfunction is
 			   interpreted as (invalid) address to vm86_struct.
 			   So the installation check works.
 			 */
@@ -309,8 +294,8 @@ static void do_sys_vm86(struct kernel_vm
  */
 	info->regs32->eax = 0;
 	tsk->thread.saved_esp0 = tsk->thread.esp0;
-	asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs));
-	asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs));
+	asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs));
+	asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs));
 
 	tss = &per_cpu(init_tss, get_cpu());
 	tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
@@ -732,12 +717,12 @@ static irqreturn_t irq_handler(int intno
 	irqbits |= irq_bit;
 	if (vm86_irqs[intno].sig)
 		send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1);
-	spin_unlock_irqrestore(&irqbits_lock, flags);
 	/*
 	 * IRQ will be re-enabled when user asks for the irq (whether
 	 * polling or as a result of the signal)
 	 */
-	disable_irq(intno);
+	disable_irq_nosync(intno);
+	spin_unlock_irqrestore(&irqbits_lock, flags);
 	return IRQ_HANDLED;
 
 out:
@@ -769,17 +754,20 @@ static inline int get_and_reset_irq(int 
 {
 	int bit;
 	unsigned long flags;
+	int ret = 0;
 	
 	if (invalid_vm86_irq(irqnumber)) return 0;
 	if (vm86_irqs[irqnumber].tsk != current) return 0;
 	spin_lock_irqsave(&irqbits_lock, flags);	
 	bit = irqbits & (1 << irqnumber);
 	irqbits &= ~bit;
+	if (bit) {
+		enable_irq(irqnumber);
+		ret = 1;
+	}
+
 	spin_unlock_irqrestore(&irqbits_lock, flags);	
-	if (!bit)
-		return 0;
-	enable_irq(irqnumber);
-	return 1;
+	return ret;
 }
 
 
diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S
new file mode 100644
--- /dev/null
+++ b/arch/i386/kernel/vsyscall-note.S
@@ -0,0 +1,25 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type)			      \
+	.section name, flags;						      \
+	.balign 4;							      \
+	.long 1f - 0f;		/* name length */			      \
+	.long 3f - 2f;		/* data length */			      \
+	.long type;		/* note type */				      \
+0:	.asciz vendor;		/* vendor name */			      \
+1:	.balign 4;							      \
+2:
+
+#define ASM_ELF_NOTE_END						      \
+3:	.balign 4;		/* pad out section */			      \
+	.previous
+
+	ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+	.long LINUX_VERSION_CODE
+	ASM_ELF_NOTE_END
diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S
--- a/arch/i386/kernel/vsyscall.lds.S
+++ b/arch/i386/kernel/vsyscall.lds.S
@@ -23,7 +23,7 @@ SECTIONS
   . = VSYSCALL_BASE + 0x400;
 
   .text           : { *(.text) }		:text =0x90909090
-
+  .note		  : { *(.note.*) }		:text :note
   .eh_frame_hdr   : { *(.eh_frame_hdr) }	:text :eh_frame_hdr
   .eh_frame       : { KEEP (*(.eh_frame)) }	:text
   .dynamic        : { *(.dynamic) }		:text :dynamic
@@ -43,6 +43,7 @@ PHDRS
 {
   text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
   dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  note PT_NOTE FLAGS(4); /* PF_R */
   eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
 }
 
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -3,7 +3,7 @@
 #
 
 
-lib-y = checksum.o delay.o usercopy.o getuser.o memcpy.o strstr.o \
+lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \
 	bitops.o
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S
new file mode 100644
--- /dev/null
+++ b/arch/i386/lib/putuser.S
@@ -0,0 +1,87 @@
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 2005 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.
+ */
+#include <asm/thread_info.h>
+
+
+/*
+ * __put_user_X
+ *
+ * Inputs:	%eax[:%edx] contains the data
+ *		%ecx contains the address
+ *
+ * Outputs:	%eax is error code (0 or -EFAULT)
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#define ENTER	pushl %ebx ; GET_THREAD_INFO(%ebx)
+#define EXIT	popl %ebx ; ret
+
+.text
+.align 4
+.globl __put_user_1
+__put_user_1:
+	ENTER
+	cmpl TI_addr_limit(%ebx),%ecx
+	jae bad_put_user
+1:	movb %al,(%ecx)
+	xorl %eax,%eax
+	EXIT
+
+.align 4
+.globl __put_user_2
+__put_user_2:
+	ENTER
+	movl TI_addr_limit(%ebx),%ebx
+	subl $1,%ebx
+	cmpl %ebx,%ecx
+	jae bad_put_user
+2:	movw %ax,(%ecx)
+	xorl %eax,%eax
+	EXIT
+
+.align 4
+.globl __put_user_4
+__put_user_4:
+	ENTER
+	movl TI_addr_limit(%ebx),%ebx
+	subl $3,%ebx
+	cmpl %ebx,%ecx
+	jae bad_put_user
+3:	movl %eax,(%ecx)
+	xorl %eax,%eax
+	EXIT
+
+.align 4
+.globl __put_user_8
+__put_user_8:
+	ENTER
+	movl TI_addr_limit(%ebx),%ebx
+	subl $7,%ebx
+	cmpl %ebx,%ecx
+	jae bad_put_user
+4:	movl %eax,(%ecx)
+5:	movl %edx,4(%ecx)
+	xorl %eax,%eax
+	EXIT
+
+bad_put_user:
+	movl $-14,%eax
+	EXIT
+
+.section __ex_table,"a"
+	.long 1b,bad_put_user
+	.long 2b,bad_put_user
+	.long 3b,bad_put_user
+	.long 4b,bad_put_user
+	.long 5b,bad_put_user
+.previous
diff --git a/arch/i386/mach-default/topology.c b/arch/i386/mach-default/topology.c
--- a/arch/i386/mach-default/topology.c
+++ b/arch/i386/mach-default/topology.c
@@ -30,7 +30,7 @@
 #include <linux/nodemask.h>
 #include <asm/cpu.h>
 
-struct i386_cpu cpu_devices[NR_CPUS];
+static struct i386_cpu cpu_devices[NR_CPUS];
 
 int arch_register_cpu(int num){
 	struct node *parent = NULL;
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -138,7 +138,19 @@ parse_unisys_oem (char *oemptr, int oem_
 		es7000_plat = 0;
 	} else {
 		printk("\nEnabling ES7000 specific features...\n");
-		es7000_plat = 1;
+		/*
+		 * Determine the generation of the ES7000 currently running.
+		 *
+		 * es7000_plat = 0 if the machine is NOT a Unisys ES7000 box
+		 * es7000_plat = 1 if the machine is a 5xx ES7000 box
+		 * es7000_plat = 2 if the machine is a x86_64 ES7000 box
+		 *
+		 */
+		if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
+			es7000_plat = 2;
+		else
+			es7000_plat = 1;
+
 		ioapic_renumber_irq = es7000_rename_gsi;
 	}
 	return es7000_plat;
diff --git a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c
--- a/arch/i386/mach-visws/mpparse.c
+++ b/arch/i386/mach-visws/mpparse.c
@@ -36,7 +36,7 @@ unsigned int __initdata maxcpus = NR_CPU
  * No problem for Linux.
  */
 
-void __init MP_processor_info (struct mpc_config_processor *m)
+static void __init MP_processor_info (struct mpc_config_processor *m)
 {
  	int ver, logical_apicid;
 	physid_mask_t apic_cpus;
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -37,10 +37,6 @@ DEFINE_PER_CPU(struct tlb_state, cpu_tlb
 /* CPU IRQ affinity -- set to all ones initially */
 static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1]  = ~0UL };
 
-/* Set when the idlers are all forked - Set in main.c but not actually
- * used by any other parts of the kernel */
-int smp_threads_ready = 0;
-
 /* per CPU data structure (for /proc/cpuinfo et al), visible externally
  * indexed physically */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
@@ -81,14 +77,6 @@ cpumask_t cpu_online_map = CPU_MASK_NONE
  * by scheduler but indexed physically */
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
 
-/* estimate of time used to flush the SMP-local cache - used in
- * processor affinity calculations */
-cycles_t cacheflush_time = 0;
-
-/* cache decay ticks for scheduler---a fairly useless quantity for the
-   voyager system with its odd affinity and huge L3 cache */
-unsigned long cache_decay_ticks = 20;
-
 
 /* The internal functions */
 static void send_CPI(__u32 cpuset, __u8 cpi);
@@ -109,7 +97,6 @@ static void ack_vic_irq(unsigned int irq
 static void vic_enable_cpi(void);
 static void do_boot_cpu(__u8 cpuid);
 static void do_quad_bootstrap(void);
-static inline void wrapper_smp_local_timer_interrupt(struct pt_regs *);
 
 int hard_smp_processor_id(void);
 
@@ -138,6 +125,14 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi)
 }
 
 static inline void
+wrapper_smp_local_timer_interrupt(struct pt_regs *regs)
+{
+	irq_enter();
+	smp_local_timer_interrupt(regs);
+	irq_exit();
+}
+
+static inline void
 send_one_CPI(__u8 cpu, __u8 cpi)
 {
 	if(voyager_quad_processors & (1<<cpu))
@@ -210,14 +205,14 @@ ack_CPI(__u8 cpi)
  * 8259 IRQs except that masks and things must be kept per processor
  */
 static struct hw_interrupt_type vic_irq_type = {
-	"VIC-level",
-	startup_vic_irq,	/* startup */
-	disable_vic_irq,	/* shutdown */
-	enable_vic_irq,		/* enable */
-	disable_vic_irq,	/* disable */
-	before_handle_vic_irq,	/* ack */
-	after_handle_vic_irq,	/* end */
-	set_vic_irq_affinity,	/* affinity */
+	.typename = "VIC-level",
+	.startup = startup_vic_irq,
+	.shutdown = disable_vic_irq,
+	.enable = enable_vic_irq,
+	.disable = disable_vic_irq,
+	.ack = before_handle_vic_irq,
+	.end = after_handle_vic_irq,
+	.set_affinity = set_vic_irq_affinity,
 };
 
 /* used to count up as CPUs are brought on line (starts at 0) */
@@ -1261,14 +1256,6 @@ smp_vic_timer_interrupt(struct pt_regs *
 	smp_local_timer_interrupt(regs);
 }
 
-static inline void
-wrapper_smp_local_timer_interrupt(struct pt_regs *regs)
-{
-	irq_enter();
-	smp_local_timer_interrupt(regs);
-	irq_exit();
-}
-
 /* local (per CPU) timer interrupt.  It does both profiling and
  * process statistics/rescheduling.
  *
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
--- a/arch/i386/mach-voyager/voyager_thread.c
+++ b/arch/i386/mach-voyager/voyager_thread.c
@@ -126,7 +126,6 @@ thread(void *unused)
 
 	kvoyagerd_running = 1;
 
-	reparent_to_init();
 	daemonize(THREAD_NAME);
 
 	set_timeout = 0;
diff --git a/arch/i386/math-emu/errors.c b/arch/i386/math-emu/errors.c
--- a/arch/i386/math-emu/errors.c
+++ b/arch/i386/math-emu/errors.c
@@ -34,13 +34,14 @@
 /* */
 
 
+#if 0
 void Un_impl(void)
 {
   u_char byte1, FPU_modrm;
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
-  /* No need to verify_area(), we have previously fetched these bytes. */
+  /* No need to check access_ok(), we have previously fetched these bytes. */
   printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *) address);
   if ( FPU_CS == __USER_CS )
     {
@@ -69,6 +70,7 @@ void Un_impl(void)
   EXCEPTION(EX_Invalid);
 
 }
+#endif  /*  0  */
 
 
 /*
@@ -91,7 +93,7 @@ void FPU_printall(void)
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
-  /* No need to verify_area(), we have previously fetched these bytes. */
+  /* No need to check access_ok(), we have previously fetched these bytes. */
   printk("At %p:", (void *) address);
   if ( FPU_CS == __USER_CS )
     {
diff --git a/arch/i386/math-emu/fpu_aux.c b/arch/i386/math-emu/fpu_aux.c
--- a/arch/i386/math-emu/fpu_aux.c
+++ b/arch/i386/math-emu/fpu_aux.c
@@ -21,7 +21,7 @@ static void fnop(void)
 {
 }
 
-void fclex(void)
+static void fclex(void)
 {
   partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
 		   SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
--- a/arch/i386/math-emu/fpu_entry.c
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -257,7 +257,7 @@ do_another_FPU_instruction:
     }
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_code_verify_area(1);
+  FPU_code_access_ok(1);
   FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
   RE_ENTRANT_CHECK_ON;
   FPU_EIP++;
@@ -589,7 +589,7 @@ static int valid_prefix(u_char *Byte, u_
   *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_code_verify_area(1);
+  FPU_code_access_ok(1);
   FPU_get_user(byte, ip);
   RE_ENTRANT_CHECK_ON;
 
@@ -635,7 +635,7 @@ static int valid_prefix(u_char *Byte, u_
 	do_next_byte:
 	  ip++;
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_code_verify_area(1);
+	  FPU_code_access_ok(1);
 	  FPU_get_user(byte, ip);
 	  RE_ENTRANT_CHECK_ON;
 	  break;
@@ -686,7 +686,7 @@ int restore_i387_soft(void *s387, struct
   int offset, other, i, tags, regnr, tag, newtop;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
+  FPU_access_ok(VERIFY_READ, d, 7*4 + 8*10);
   if (__copy_from_user(&S387->cwd, d, 7*4))
     return -1;
   RE_ENTRANT_CHECK_ON;
@@ -732,7 +732,7 @@ int save_i387_soft(void *s387, struct _f
   int offset = (S387->ftop & 7) * 10, other = 80 - offset;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
+  FPU_access_ok(VERIFY_WRITE, d, 7*4 + 8*10);
 #ifdef PECULIAR_486
   S387->cwd &= ~0xe080;
   /* An 80486 sets nearly all of the reserved bits to 1. */
diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h
--- a/arch/i386/math-emu/fpu_proto.h
+++ b/arch/i386/math-emu/fpu_proto.h
@@ -2,7 +2,6 @@
 #define _FPU_PROTO_H
 
 /* errors.c */
-extern void Un_impl(void);
 extern void FPU_illegal(void);
 extern void FPU_printall(void);
 asmlinkage void FPU_exception(int n);
@@ -41,7 +40,6 @@ extern void fsubp_(void);
 extern void fdivrp(void);
 extern void fdivp_(void);
 /* fpu_aux.c */
-extern void fclex(void);
 extern void finit(void);
 extern void finit_(void);
 extern void fstsw_(void);
diff --git a/arch/i386/math-emu/fpu_system.h b/arch/i386/math-emu/fpu_system.h
--- a/arch/i386/math-emu/fpu_system.h
+++ b/arch/i386/math-emu/fpu_system.h
@@ -66,21 +66,21 @@
 #define instruction_address	(*(struct address *)&I387.soft.fip)
 #define operand_address		(*(struct address *)&I387.soft.foo)
 
-#define FPU_verify_area(x,y,z)	if ( verify_area(x,y,z) ) \
+#define FPU_access_ok(x,y,z)	if ( !access_ok(x,y,z) ) \
 				math_abort(FPU_info,SIGSEGV)
 
 #undef FPU_IGNORE_CODE_SEGV
 #ifdef FPU_IGNORE_CODE_SEGV
-/* verify_area() is very expensive, and causes the emulator to run
+/* access_ok() is very expensive, and causes the emulator to run
    about 20% slower if applied to the code. Anyway, errors due to bad
    code addresses should be much rarer than errors due to bad data
    addresses. */
-#define	FPU_code_verify_area(z)
+#define	FPU_code_access_ok(z)
 #else
-/* A simpler test than verify_area() can probably be done for
-   FPU_code_verify_area() because the only possible error is to step
+/* A simpler test than access_ok() can probably be done for
+   FPU_code_access_ok() because the only possible error is to step
    past the upper boundary of a legal code area. */
-#define	FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void __user *)FPU_EIP,z)
+#define	FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
 #endif
 
 #define FPU_get_user(x,y)       get_user((x),(y))
diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c
--- a/arch/i386/math-emu/get_address.c
+++ b/arch/i386/math-emu/get_address.c
@@ -81,7 +81,7 @@ static int sib(int mod, unsigned long *f
   long offset;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_code_verify_area(1);
+  FPU_code_access_ok(1);
   FPU_get_user(base, (u_char __user *) (*fpu_eip));   /* The SIB byte */
   RE_ENTRANT_CHECK_ON;
   (*fpu_eip)++;
@@ -111,7 +111,7 @@ static int sib(int mod, unsigned long *f
       /* 8 bit signed displacement */
       long displacement;
       RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(1);
+      FPU_code_access_ok(1);
       FPU_get_user(displacement, (signed char __user *) (*fpu_eip));
       offset += displacement;
       RE_ENTRANT_CHECK_ON;
@@ -122,7 +122,7 @@ static int sib(int mod, unsigned long *f
       /* 32 bit displacement */
       long displacement;
       RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(4);
+      FPU_code_access_ok(4);
       FPU_get_user(displacement, (long __user *) (*fpu_eip));
       offset += displacement;
       RE_ENTRANT_CHECK_ON;
@@ -276,7 +276,7 @@ void __user *FPU_get_address(u_char FPU_
 	    {
 	      /* Special case: disp32 */
 	      RE_ENTRANT_CHECK_OFF;
-	      FPU_code_verify_area(4);
+	      FPU_code_access_ok(4);
 	      FPU_get_user(address, (unsigned long __user *) (*fpu_eip));
 	      (*fpu_eip) += 4;
 	      RE_ENTRANT_CHECK_ON;
@@ -293,7 +293,7 @@ void __user *FPU_get_address(u_char FPU_
 	case 1:
 	  /* 8 bit signed displacement */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_code_verify_area(1);
+	  FPU_code_access_ok(1);
 	  FPU_get_user(address, (signed char __user *) (*fpu_eip));
 	  RE_ENTRANT_CHECK_ON;
 	  (*fpu_eip)++;
@@ -301,7 +301,7 @@ void __user *FPU_get_address(u_char FPU_
 	case 2:
 	  /* 32 bit displacement */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_code_verify_area(4);
+	  FPU_code_access_ok(4);
 	  FPU_get_user(address, (long __user *) (*fpu_eip));
 	  (*fpu_eip) += 4;
 	  RE_ENTRANT_CHECK_ON;
@@ -362,7 +362,7 @@ void __user *FPU_get_address_16(u_char F
 	{
 	  /* Special case: disp16 */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_code_verify_area(2);
+	  FPU_code_access_ok(2);
 	  FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
 	  (*fpu_eip) += 2;
 	  RE_ENTRANT_CHECK_ON;
@@ -372,7 +372,7 @@ void __user *FPU_get_address_16(u_char F
     case 1:
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(1);
+      FPU_code_access_ok(1);
       FPU_get_user(address, (signed char __user *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip)++;
@@ -380,7 +380,7 @@ void __user *FPU_get_address_16(u_char F
     case 2:
       /* 16 bit displacement */
       RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(2);
+      FPU_code_access_ok(2);
       FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
       (*fpu_eip) += 2;
       RE_ENTRANT_CHECK_ON;
diff --git a/arch/i386/math-emu/load_store.c b/arch/i386/math-emu/load_store.c
--- a/arch/i386/math-emu/load_store.c
+++ b/arch/i386/math-emu/load_store.c
@@ -53,7 +53,7 @@ u_char const data_sizes_16[32] = {
   14, 0, 94, 10,  2, 10,  2,  8
 };
 
-u_char const data_sizes_32[32] = {
+static u_char const data_sizes_32[32] = {
   4,  4,  8,  2,  0,  0,  0,  0,
   4,  4,  8,  2,  4,  4,  8,  2,
   28, 0,108, 10,  2, 10,  0,  8,  
@@ -208,7 +208,7 @@ int FPU_load_store(u_char type, fpu_addr
       break;
     case 024:     /* fldcw */
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_READ, data_address, 2);
+      FPU_access_ok(VERIFY_READ, data_address, 2);
       FPU_get_user(control_word, (unsigned short __user *) data_address);
       RE_ENTRANT_CHECK_ON;
       if ( partial_status & ~control_word & CW_Exceptions )
@@ -243,7 +243,7 @@ int FPU_load_store(u_char type, fpu_addr
       break;
     case 034:      /* fstcw m16int */
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      FPU_access_ok(VERIFY_WRITE,data_address,2);
       FPU_put_user(control_word, (unsigned short __user *) data_address);
       RE_ENTRANT_CHECK_ON;
       return 1;
@@ -255,7 +255,7 @@ int FPU_load_store(u_char type, fpu_addr
       break;
     case 036:      /* fstsw m2byte */
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      FPU_access_ok(VERIFY_WRITE,data_address,2);
       FPU_put_user(status_word(),(unsigned short __user *) data_address);
       RE_ENTRANT_CHECK_ON;
       return 1;
diff --git a/arch/i386/math-emu/reg_constant.c b/arch/i386/math-emu/reg_constant.c
--- a/arch/i386/math-emu/reg_constant.c
+++ b/arch/i386/math-emu/reg_constant.c
@@ -21,15 +21,17 @@
                             ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
 
 FPU_REG const CONST_1    = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
+#if 0
 FPU_REG const CONST_2    = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
 FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
-FPU_REG const CONST_L2T  = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
-FPU_REG const CONST_L2E  = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
+#endif  /*  0  */
+static FPU_REG const CONST_L2T  = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
+static FPU_REG const CONST_L2E  = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
 FPU_REG const CONST_PI   = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
 FPU_REG const CONST_PI2  = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
 FPU_REG const CONST_PI4  = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
-FPU_REG const CONST_LG2  = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
-FPU_REG const CONST_LN2  = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
+static FPU_REG const CONST_LG2  = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
+static FPU_REG const CONST_LN2  = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
 
 /* Extra bits to take pi/2 to more than 128 bits precision. */
 FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
diff --git a/arch/i386/math-emu/reg_constant.h b/arch/i386/math-emu/reg_constant.h
--- a/arch/i386/math-emu/reg_constant.h
+++ b/arch/i386/math-emu/reg_constant.h
@@ -12,16 +12,10 @@
 #include "fpu_emu.h"
 
 extern FPU_REG const CONST_1;
-extern FPU_REG const CONST_2;
-extern FPU_REG const CONST_HALF;
-extern FPU_REG const CONST_L2T;
-extern FPU_REG const CONST_L2E;
 extern FPU_REG const CONST_PI;
 extern FPU_REG const CONST_PI2;
 extern FPU_REG const CONST_PI2extra;
 extern FPU_REG const CONST_PI4;
-extern FPU_REG const CONST_LG2;
-extern FPU_REG const CONST_LN2;
 extern FPU_REG const CONST_Z;
 extern FPU_REG const CONST_PINF;
 extern FPU_REG const CONST_INF;
diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c
--- a/arch/i386/math-emu/reg_ld_str.c
+++ b/arch/i386/math-emu/reg_ld_str.c
@@ -91,7 +91,7 @@ int FPU_load_extended(long double __user
   FPU_REG *sti_ptr = &st(stnr);
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, s, 10);
+  FPU_access_ok(VERIFY_READ, s, 10);
   __copy_from_user(sti_ptr, s, 10);
   RE_ENTRANT_CHECK_ON;
 
@@ -106,7 +106,7 @@ int FPU_load_double(double __user *dfloa
   unsigned m64, l64;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, dfloat, 8);
+  FPU_access_ok(VERIFY_READ, dfloat, 8);
   FPU_get_user(m64, 1 + (unsigned long __user *) dfloat);
   FPU_get_user(l64, (unsigned long __user *) dfloat);
   RE_ENTRANT_CHECK_ON;
@@ -178,7 +178,7 @@ int FPU_load_single(float __user *single
   int exp, tag, negative;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, single, 4);
+  FPU_access_ok(VERIFY_READ, single, 4);
   FPU_get_user(m32, (unsigned long __user *) single);
   RE_ENTRANT_CHECK_ON;
 
@@ -243,7 +243,7 @@ int FPU_load_int64(long long __user *_s)
   FPU_REG *st0_ptr = &st(0);
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, _s, 8);
+  FPU_access_ok(VERIFY_READ, _s, 8);
   copy_from_user(&s,_s,8);
   RE_ENTRANT_CHECK_ON;
 
@@ -274,7 +274,7 @@ int FPU_load_int32(long __user *_s, FPU_
   int negative;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, _s, 4);
+  FPU_access_ok(VERIFY_READ, _s, 4);
   FPU_get_user(s, _s);
   RE_ENTRANT_CHECK_ON;
 
@@ -302,7 +302,7 @@ int FPU_load_int16(short __user *_s, FPU
   int s, negative;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, _s, 2);
+  FPU_access_ok(VERIFY_READ, _s, 2);
   /* Cast as short to get the sign extended. */
   FPU_get_user(s, _s);
   RE_ENTRANT_CHECK_ON;
@@ -335,7 +335,7 @@ int FPU_load_bcd(u_char __user *s)
   int sign;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, s, 10);
+  FPU_access_ok(VERIFY_READ, s, 10);
   RE_ENTRANT_CHECK_ON;
   for ( pos = 8; pos >= 0; pos--)
     {
@@ -380,7 +380,7 @@ int FPU_store_extended(FPU_REG *st0_ptr,
   if ( st0_tag != TAG_Empty )
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE, d, 10);
+      FPU_access_ok(VERIFY_WRITE, d, 10);
 
       FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d);
       FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4));
@@ -397,7 +397,7 @@ int FPU_store_extended(FPU_REG *st0_ptr,
       /* The masked response */
       /* Put out the QNaN indefinite */
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE,d,10);
+      FPU_access_ok(VERIFY_WRITE,d,10);
       FPU_put_user(0, (unsigned long __user *) d);
       FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
       FPU_put_user(0xffff, 4 + (short __user *) d);
@@ -607,7 +607,7 @@ int FPU_store_double(FPU_REG *st0_ptr, u
 	  /* The masked response */
 	  /* Put out the QNaN indefinite */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_verify_area(VERIFY_WRITE,dfloat,8);
+	  FPU_access_ok(VERIFY_WRITE,dfloat,8);
 	  FPU_put_user(0, (unsigned long __user *) dfloat);
 	  FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat);
 	  RE_ENTRANT_CHECK_ON;
@@ -620,7 +620,7 @@ int FPU_store_double(FPU_REG *st0_ptr, u
     l[1] |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,dfloat,8);
+  FPU_access_ok(VERIFY_WRITE,dfloat,8);
   FPU_put_user(l[0], (unsigned long __user *)dfloat);
   FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
   RE_ENTRANT_CHECK_ON;
@@ -826,7 +826,7 @@ int FPU_store_single(FPU_REG *st0_ptr, u
 	  /* The masked response */
 	  /* Put out the QNaN indefinite */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_verify_area(VERIFY_WRITE,single,4);
+	  FPU_access_ok(VERIFY_WRITE,single,4);
 	  FPU_put_user(0xffc00000, (unsigned long __user *) single);
 	  RE_ENTRANT_CHECK_ON;
 	  return 1;
@@ -845,7 +845,7 @@ int FPU_store_single(FPU_REG *st0_ptr, u
     templ |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,single,4);
+  FPU_access_ok(VERIFY_WRITE,single,4);
   FPU_put_user(templ,(unsigned long __user *) single);
   RE_ENTRANT_CHECK_ON;
 
@@ -906,7 +906,7 @@ int FPU_store_int64(FPU_REG *st0_ptr, u_
     }
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,8);
+  FPU_access_ok(VERIFY_WRITE,d,8);
   copy_to_user(d, &tll, 8);
   RE_ENTRANT_CHECK_ON;
 
@@ -963,7 +963,7 @@ int FPU_store_int32(FPU_REG *st0_ptr, u_
     }
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,4);
+  FPU_access_ok(VERIFY_WRITE,d,4);
   FPU_put_user(t.sigl, (unsigned long __user *) d);
   RE_ENTRANT_CHECK_ON;
 
@@ -1020,7 +1020,7 @@ int FPU_store_int16(FPU_REG *st0_ptr, u_
     }
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,2);
+  FPU_access_ok(VERIFY_WRITE,d,2);
   FPU_put_user((short)t.sigl, d);
   RE_ENTRANT_CHECK_ON;
 
@@ -1069,7 +1069,7 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_ch
 	{
 	  /* Produce the QNaN "indefinite" */
 	  RE_ENTRANT_CHECK_OFF;
-	  FPU_verify_area(VERIFY_WRITE,d,10);
+	  FPU_access_ok(VERIFY_WRITE,d,10);
 	  for ( i = 0; i < 7; i++)
 	    FPU_put_user(0, d+i); /* These bytes "undefined" */
 	  FPU_put_user(0xc0, d+7); /* This byte "undefined" */
@@ -1088,7 +1088,7 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_ch
     }
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,10);
+  FPU_access_ok(VERIFY_WRITE,d,10);
   RE_ENTRANT_CHECK_ON;
   for ( i = 0; i < 9; i++)
     {
@@ -1186,7 +1186,7 @@ u_char __user *fldenv(fpu_addr_modes add
       ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_READ, s, 0x0e);
+      FPU_access_ok(VERIFY_READ, s, 0x0e);
       FPU_get_user(control_word, (unsigned short __user *) s);
       FPU_get_user(partial_status, (unsigned short __user *) (s+2));
       FPU_get_user(tag_word, (unsigned short __user *) (s+4));
@@ -1206,7 +1206,7 @@ u_char __user *fldenv(fpu_addr_modes add
   else
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_READ, s, 0x1c);
+      FPU_access_ok(VERIFY_READ, s, 0x1c);
       FPU_get_user(control_word, (unsigned short __user *) s);
       FPU_get_user(partial_status, (unsigned short __user *) (s+4));
       FPU_get_user(tag_word, (unsigned short __user *) (s+8));
@@ -1274,7 +1274,7 @@ void frstor(fpu_addr_modes addr_modes, u
 
   /* Copy all registers in stack order. */
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ,s,80);
+  FPU_access_ok(VERIFY_READ,s,80);
   __copy_from_user(register_base+offset, s, other);
   if ( offset )
     __copy_from_user(register_base, s+other, offset);
@@ -1298,7 +1298,7 @@ u_char __user *fstenv(fpu_addr_modes add
       ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE,d,14);
+      FPU_access_ok(VERIFY_WRITE,d,14);
 #ifdef PECULIAR_486
       FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);
 #else
@@ -1326,7 +1326,7 @@ u_char __user *fstenv(fpu_addr_modes add
   else
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE, d, 7*4);
+      FPU_access_ok(VERIFY_WRITE, d, 7*4);
 #ifdef PECULIAR_486
       control_word &= ~0xe080;
       /* An 80486 sets nearly all of the reserved bits to 1. */
@@ -1356,7 +1356,7 @@ void fsave(fpu_addr_modes addr_modes, u_
   d = fstenv(addr_modes, data_address);
 
   RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,80);
+  FPU_access_ok(VERIFY_WRITE,d,80);
 
   /* Copy all registers in stack order. */
   __copy_to_user(d, register_base+offset, other);
diff --git a/arch/i386/mm/boot_ioremap.c b/arch/i386/mm/boot_ioremap.c
--- a/arch/i386/mm/boot_ioremap.c
+++ b/arch/i386/mm/boot_ioremap.c
@@ -61,8 +61,8 @@ static void __boot_ioremap(unsigned long
 /* the virtual space we're going to remap comes from this array */
 #define BOOT_IOREMAP_PAGES 4
 #define BOOT_IOREMAP_SIZE (BOOT_IOREMAP_PAGES*PAGE_SIZE)
-__initdata char boot_ioremap_space[BOOT_IOREMAP_SIZE] 
-		__attribute__ ((aligned (PAGE_SIZE)));
+static __initdata char boot_ioremap_space[BOOT_IOREMAP_SIZE]
+		       __attribute__ ((aligned (PAGE_SIZE)));
 
 /*
  * This only applies to things which need to ioremap before paging_init()
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -60,6 +60,32 @@ bootmem_data_t node0_bdata;
  */
 s8 physnode_map[MAX_ELEMENTS] = { [0 ... (MAX_ELEMENTS - 1)] = -1};
 
+void memory_present(int nid, unsigned long start, unsigned long end)
+{
+	unsigned long pfn;
+
+	printk(KERN_INFO "Node: %d, start_pfn: %ld, end_pfn: %ld\n",
+			nid, start, end);
+	printk(KERN_DEBUG "  Setting physnode_map array to node %d for pfns:\n", nid);
+	printk(KERN_DEBUG "  ");
+	for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) {
+		physnode_map[pfn / PAGES_PER_ELEMENT] = nid;
+		printk("%ld ", pfn);
+	}
+	printk("\n");
+}
+
+unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
+					      unsigned long end_pfn)
+{
+	unsigned long nr_pages = end_pfn - start_pfn;
+
+	if (!nr_pages)
+		return 0;
+
+	return (nr_pages + 1) * sizeof(struct page);
+}
+
 unsigned long node_start_pfn[MAX_NUMNODES];
 unsigned long node_end_pfn[MAX_NUMNODES];
 
@@ -95,6 +121,7 @@ int __init get_memcfg_numa_flat(void)
 	find_max_pfn();
 	node_start_pfn[0] = 0;
 	node_end_pfn[0] = max_pfn;
+	memory_present(0, 0, max_pfn);
 
         /* Indicate there is one node available. */
 	nodes_clear(node_online_map);
@@ -128,52 +155,11 @@ static void __init find_max_pfn_node(int
  */
 static void __init allocate_pgdat(int nid)
 {
-	if (nid)
+	if (nid && node_has_online_mem(nid))
 		NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
 	else {
 		NODE_DATA(nid) = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
 		min_low_pfn += PFN_UP(sizeof(pg_data_t));
-		memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
-	}
-}
-
-/*
- * Register fully available low RAM pages with the bootmem allocator.
- */
-static void __init register_bootmem_low_pages(unsigned long system_max_low_pfn)
-{
-	int i;
-
-	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)
-			continue;
-		/*
-		 * We are rounding up the start address of usable memory:
-		 */
-		curr_pfn = PFN_UP(e820.map[i].addr);
-		if (curr_pfn >= system_max_low_pfn)
-			continue;
-		/*
-		 * ... and at the end of the usable range downwards:
-		 */
-		last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
-
-		if (last_pfn > system_max_low_pfn)
-			last_pfn = system_max_low_pfn;
-
-		/*
-		 * .. finally, did all the rounding and playing
-		 * around just make the area go away?
-		 */
-		if (last_pfn <= curr_pfn)
-			continue;
-
-		size = last_pfn - curr_pfn;
-		free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn), PFN_PHYS(size));
 	}
 }
 
@@ -203,9 +189,21 @@ static unsigned long calculate_numa_rema
 	for_each_online_node(nid) {
 		if (nid == 0)
 			continue;
-		/* calculate the size of the mem_map needed in bytes */
-		size = (node_end_pfn[nid] - node_start_pfn[nid] + 1) 
-			* sizeof(struct page) + sizeof(pg_data_t);
+		if (!node_remap_size[nid])
+			continue;
+
+		/*
+		 * The acpi/srat node info can show hot-add memroy zones
+		 * where memory could be added but not currently present.
+		 */
+		if (node_start_pfn[nid] > max_pfn)
+			continue;
+		if (node_end_pfn[nid] > max_pfn)
+			node_end_pfn[nid] = max_pfn;
+
+		/* ensure the remap includes space for the pgdat. */
+		size = node_remap_size[nid] + sizeof(pg_data_t);
+
 		/* convert size to large (pmd size) pages, rounding up */
 		size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
 		/* now the roundup is correct, convert to PAGE_SIZE pages */
@@ -225,22 +223,12 @@ static unsigned long calculate_numa_rema
 	return reserve_pages;
 }
 
-/*
- * workaround for Dell systems that neglect to reserve EBDA
- */
-static void __init reserve_ebda_region_node(void)
-{
-	unsigned int addr;
-	addr = get_bios_ebda();
-	if (addr)
-		reserve_bootmem_node(NODE_DATA(0), addr, PAGE_SIZE);
-}
-
+extern void setup_bootmem_allocator(void);
 unsigned long __init setup_memory(void)
 {
 	int nid;
-	unsigned long bootmap_size, system_start_pfn, system_max_low_pfn;
-	unsigned long reserve_pages, pfn;
+	unsigned long system_start_pfn, system_max_low_pfn;
+	unsigned long reserve_pages;
 
 	/*
 	 * When mapping a NUMA machine we allocate the node_mem_map arrays
@@ -249,28 +237,14 @@ unsigned long __init setup_memory(void)
 	 * this space and use it to adjust the boundry between ZONE_NORMAL
 	 * and ZONE_HIGHMEM.
 	 */
+	find_max_pfn();
 	get_memcfg_numa();
 
-	/* Fill in the physnode_map */
-	for_each_online_node(nid) {
-		printk("Node: %d, start_pfn: %ld, end_pfn: %ld\n",
-				nid, node_start_pfn[nid], node_end_pfn[nid]);
-		printk("  Setting physnode_map array to node %d for pfns:\n  ",
-				nid);
-		for (pfn = node_start_pfn[nid]; pfn < node_end_pfn[nid];
-	       				pfn += PAGES_PER_ELEMENT) {
-			physnode_map[pfn / PAGES_PER_ELEMENT] = nid;
-			printk("%ld ", pfn);
-		}
-		printk("\n");
-	}
-
 	reserve_pages = calculate_numa_remap_pages();
 
 	/* partially used pages are not usable - thus round upwards */
 	system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end);
 
-	find_max_pfn();
 	system_max_low_pfn = max_low_pfn = find_max_low_pfn() - reserve_pages;
 	printk("reserve_pages = %ld find_max_low_pfn() ~ %ld\n",
 			reserve_pages, max_low_pfn + reserve_pages);
@@ -304,70 +278,10 @@ unsigned long __init setup_memory(void)
 	for_each_online_node(nid)
 		find_max_pfn_node(nid);
 
+	memset(NODE_DATA(0), 0, sizeof(struct pglist_data));
 	NODE_DATA(0)->bdata = &node0_bdata;
-
-	/*
-	 * Initialize the boot-time allocator (with low memory only):
-	 */
-	bootmap_size = init_bootmem_node(NODE_DATA(0), min_low_pfn, 0, system_max_low_pfn);
-
-	register_bootmem_low_pages(system_max_low_pfn);
-
-	/*
-	 * Reserve the bootmem bitmap itself as well. We do this in two
-	 * steps (first step was init_bootmem()) because this catches
-	 * the (very unlikely) case of us accidentally initializing the
-	 * bootmem allocator with an invalid RAM area.
-	 */
-	reserve_bootmem_node(NODE_DATA(0), HIGH_MEMORY, (PFN_PHYS(min_low_pfn) +
-		 bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
-
-	/*
-	 * reserve physical page 0 - it's a special BIOS page on many boxes,
-	 * enabling clean reboots, SMP operation, laptop functions.
-	 */
-	reserve_bootmem_node(NODE_DATA(0), 0, PAGE_SIZE);
-
-	/*
-	 * 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_node(NODE_DATA(0), PAGE_SIZE, PAGE_SIZE);
-
-	/* reserve EBDA region, it's a 4K region */
-	reserve_ebda_region_node();
-
-#ifdef CONFIG_ACPI_SLEEP
-	/*
-	 * Reserve low memory region for sleep support.
-	 */
-	acpi_reserve_bootmem();
-#endif
-
-	/*
-	 * Find and reserve possible boot-time SMP configuration:
-	 */
-	find_smp_config();
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (LOADER_TYPE && INITRD_START) {
-		if (INITRD_START + INITRD_SIZE <= (system_max_low_pfn << PAGE_SHIFT)) {
-			reserve_bootmem_node(NODE_DATA(0), INITRD_START, INITRD_SIZE);
-			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",
-			    INITRD_START + INITRD_SIZE,
-			    system_max_low_pfn << PAGE_SHIFT);
-			initrd_start = 0;
-		}
-	}
-#endif
-	return system_max_low_pfn;
+	setup_bootmem_allocator();
+	return max_low_pfn;
 }
 
 void __init zone_sizes_init(void)
@@ -382,8 +296,6 @@ void __init zone_sizes_init(void)
 	for (nid = MAX_NUMNODES - 1; nid >= 0; nid--) {
 		if (!node_online(nid))
 			continue;
-		if (nid)
-			memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
 		NODE_DATA(nid)->pgdat_next = pgdat_list;
 		pgdat_list = NODE_DATA(nid);
 	}
@@ -399,24 +311,27 @@ void __init zone_sizes_init(void)
 
 		max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-		if (start > low) {
+		if (node_has_online_mem(nid)){
+			if (start > low) {
 #ifdef CONFIG_HIGHMEM
-			BUG_ON(start > high);
-			zones_size[ZONE_HIGHMEM] = high - start;
+				BUG_ON(start > high);
+				zones_size[ZONE_HIGHMEM] = high - start;
 #endif
-		} else {
-			if (low < max_dma)
-				zones_size[ZONE_DMA] = low;
-			else {
-				BUG_ON(max_dma > low);
-				BUG_ON(low > high);
-				zones_size[ZONE_DMA] = max_dma;
-				zones_size[ZONE_NORMAL] = low - max_dma;
+			} else {
+				if (low < max_dma)
+					zones_size[ZONE_DMA] = low;
+				else {
+					BUG_ON(max_dma > low);
+					BUG_ON(low > high);
+					zones_size[ZONE_DMA] = max_dma;
+					zones_size[ZONE_NORMAL] = low - max_dma;
 #ifdef CONFIG_HIGHMEM
-				zones_size[ZONE_HIGHMEM] = high - low;
+					zones_size[ZONE_HIGHMEM] = high - low;
 #endif
+				}
 			}
 		}
+
 		zholes_size = get_zholes_size(nid);
 		/*
 		 * We let the lmem_map for node 0 be allocated from the
@@ -466,12 +381,3 @@ void __init set_highmem_pages_init(int b
 	totalram_pages += totalhigh_pages;
 #endif
 }
-
-void __init set_max_mapnr_init(void)
-{
-#ifdef CONFIG_HIGHMEM
-	num_physpages = highend_pfn;
-#else
-	num_physpages = max_low_pfn;
-#endif
-}
diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
--- a/arch/i386/mm/highmem.c
+++ b/arch/i386/mm/highmem.c
@@ -66,7 +66,7 @@ void kunmap_atomic(void *kvaddr, enum km
 	 * force other mappings to Oops if they'll try to access
 	 * this pte without first remap it
 	 */
-	pte_clear(kmap_pte-idx);
+	pte_clear(&init_mm, vaddr, kmap_pte-idx);
 	__flush_tlb_one(vaddr);
 #endif
 
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -46,7 +46,7 @@ static void set_huge_pte(struct mm_struc
 {
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 	if (write_access) {
 		entry =
 		    pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -86,7 +86,7 @@ int copy_hugetlb_page_range(struct mm_st
 		ptepage = pte_page(entry);
 		get_page(ptepage);
 		set_pte(dst_pte, entry);
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -209,20 +209,23 @@ void unmap_hugepage_range(struct vm_area
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long address;
-	pte_t pte;
+	pte_t pte, *ptep;
 	struct page *page;
 
 	BUG_ON(start & (HPAGE_SIZE - 1));
 	BUG_ON(end & (HPAGE_SIZE - 1));
 
 	for (address = start; address < end; address += HPAGE_SIZE) {
-		pte = ptep_get_and_clear(huge_pte_offset(mm, address));
+		ptep = huge_pte_offset(mm, address);
+		if (!ptep)
+			continue;
+		pte = ptep_get_and_clear(mm, address, ptep);
 		if (pte_none(pte))
 			continue;
 		page = pte_page(pte);
 		put_page(page);
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm ,rss, -((end - start) >> PAGE_SHIFT));
 	flush_tlb_range(vma, start, end);
 }
 
@@ -246,15 +249,8 @@ int hugetlb_prefault(struct address_spac
 			goto out;
 		}
 
-		if (!pte_none(*pte)) {
-			pmd_t *pmd = (pmd_t *) pte;
-
-			page = pmd_page(*pmd);
-			pmd_clear(pmd);
-			mm->nr_ptes--;
-			dec_page_state(nr_page_table_pages);
-			page_cache_release(page);
-		}
+		if (!pte_none(*pte))
+			continue;
 
 		idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
 			+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -233,13 +233,10 @@ static inline int page_is_ram(unsigned l
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-
 #define kmap_get_fixmap_pte(vaddr)					\
 	pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr))
 
-void __init kmap_init(void)
+static void __init kmap_init(void)
 {
 	unsigned long kmap_vstart;
 
@@ -250,7 +247,7 @@ void __init kmap_init(void)
 	kmap_prot = PAGE_KERNEL;
 }
 
-void __init permanent_kmaps_init(pgd_t *pgd_base)
+static void __init permanent_kmaps_init(pgd_t *pgd_base)
 {
 	pgd_t *pgd;
 	pud_t *pud;
@@ -281,7 +278,7 @@ void __init one_highpage_init(struct pag
 }
 
 #ifndef CONFIG_DISCONTIGMEM
-void __init set_highmem_pages_init(int bad_ppro) 
+static void __init set_highmem_pages_init(int bad_ppro)
 {
 	int pfn;
 	for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
@@ -394,31 +391,6 @@ void zap_low_mappings (void)
 	flush_tlb_all();
 }
 
-#ifndef CONFIG_DISCONTIGMEM
-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);	
-}
-#else
-extern void zone_sizes_init(void);
-#endif /* !CONFIG_DISCONTIGMEM */
-
 static int disable_nx __initdata = 0;
 u64 __supported_pte_mask = ~_PAGE_NX;
 
@@ -519,7 +491,6 @@ void __init paging_init(void)
 	__flush_tlb_all();
 
 	kmap_init();
-	zone_sizes_init();
 }
 
 /*
@@ -529,7 +500,7 @@ void __init paging_init(void)
  * but fortunately the switch to using exceptions got rid of all that.
  */
 
-void __init test_wp_bit(void)
+static void __init test_wp_bit(void)
 {
 	printk("Checking if this processor honours the WP bit even in supervisor mode... ");
 
@@ -548,20 +519,17 @@ void __init test_wp_bit(void)
 	}
 }
 
-#ifndef CONFIG_DISCONTIGMEM
 static void __init set_max_mapnr_init(void)
 {
 #ifdef CONFIG_HIGHMEM
-	max_mapnr = num_physpages = highend_pfn;
+	num_physpages = highend_pfn;
 #else
-	max_mapnr = num_physpages = max_low_pfn;
+	num_physpages = max_low_pfn;
+#endif
+#ifndef CONFIG_DISCONTIGMEM
+	max_mapnr = num_physpages;
 #endif
 }
-#define __free_all_bootmem() free_all_bootmem()
-#else
-#define __free_all_bootmem() free_all_bootmem_node(NODE_DATA(0))
-extern void set_max_mapnr_init(void);
-#endif /* !CONFIG_DISCONTIGMEM */
 
 static struct kcore_list kcore_mem, kcore_vmalloc; 
 
@@ -592,13 +560,13 @@ void __init mem_init(void)
 	set_max_mapnr_init();
 
 #ifdef CONFIG_HIGHMEM
-	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE);
+	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
 	/* this will put all low memory onto the freelists */
-	totalram_pages += __free_all_bootmem();
+	totalram_pages += free_all_bootmem();
 
 	reservedpages = 0;
 	for (tmp = 0; tmp < max_low_pfn; tmp++)
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -17,89 +17,85 @@
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long phys_addr, unsigned long flags)
+#define ISA_START_ADDRESS	0xa0000
+#define ISA_END_ADDRESS		0x100000
+
+static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
+		unsigned long end, unsigned long phys_addr, unsigned long flags)
 {
-	unsigned long end;
+	pte_t *pte;
 	unsigned long pfn;
 
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	if (address >= end)
-		BUG();
 	pfn = phys_addr >> PAGE_SHIFT;
+	pte = pte_alloc_kernel(&init_mm, pmd, addr);
+	if (!pte)
+		return -ENOMEM;
 	do {
-		if (!pte_none(*pte)) {
-			printk("remap_area_pte: page already exists\n");
-			BUG();
-		}
+		BUG_ON(!pte_none(*pte));
 		set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW | 
 					_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
-		address += PAGE_SIZE;
 		pfn++;
-		pte++;
-	} while (address && (address < end));
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+	return 0;
+}
+
+static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
+		unsigned long end, unsigned long phys_addr, unsigned long flags)
+{
+	pmd_t *pmd;
+	unsigned long next;
+
+	phys_addr -= addr;
+	pmd = pmd_alloc(&init_mm, pud, addr);
+	if (!pmd)
+		return -ENOMEM;
+	do {
+		next = pmd_addr_end(addr, end);
+		if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, flags))
+			return -ENOMEM;
+	} while (pmd++, addr = next, addr != end);
+	return 0;
 }
 
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long phys_addr, unsigned long flags)
+static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
+		unsigned long end, unsigned long phys_addr, unsigned long flags)
 {
-	unsigned long end;
+	pud_t *pud;
+	unsigned long next;
 
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	phys_addr -= address;
-	if (address >= end)
-		BUG();
+	phys_addr -= addr;
+	pud = pud_alloc(&init_mm, pgd, addr);
+	if (!pud)
+		return -ENOMEM;
 	do {
-		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
-		if (!pte)
+		next = pud_addr_end(addr, end);
+		if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, flags))
 			return -ENOMEM;
-		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
+	} while (pud++, addr = next, addr != end);
 	return 0;
 }
 
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
-				 unsigned long size, unsigned long flags)
+static int ioremap_page_range(unsigned long addr,
+		unsigned long end, unsigned long phys_addr, unsigned long flags)
 {
-	int error;
-	pgd_t * dir;
-	unsigned long end = address + size;
+	pgd_t *pgd;
+	unsigned long next;
+	int err;
 
-	phys_addr -= address;
-	dir = pgd_offset(&init_mm, address);
+	BUG_ON(addr >= end);
 	flush_cache_all();
-	if (address >= end)
-		BUG();
+	phys_addr -= addr;
+	pgd = pgd_offset_k(addr);
 	spin_lock(&init_mm.page_table_lock);
 	do {
-		pud_t *pud;
-		pmd_t *pmd;
-		
-		error = -ENOMEM;
-		pud = pud_alloc(&init_mm, dir, address);
-		if (!pud)
+		next = pgd_addr_end(addr, end);
+		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, flags);
+		if (err)
 			break;
-		pmd = pmd_alloc(&init_mm, pud, address);
-		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));
+	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
-	return error;
+	return err;
 }
 
 /*
@@ -129,7 +125,7 @@ void __iomem * __ioremap(unsigned long p
 	/*
 	 * Don't remap the low PCI/ISA area, it's always mapped..
 	 */
-	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+	if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
 		return (void __iomem *) phys_to_virt(phys_addr);
 
 	/*
@@ -162,7 +158,8 @@ void __iomem * __ioremap(unsigned long p
 		return NULL;
 	area->phys_addr = phys_addr;
 	addr = (void __iomem *) area->addr;
-	if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+	if (ioremap_page_range((unsigned long) addr,
+			(unsigned long) addr + size, phys_addr, flags)) {
 		vunmap((void __force *) addr);
 		return NULL;
 	}
@@ -230,20 +227,32 @@ void iounmap(volatile void __iomem *addr
 {
 	struct vm_struct *p;
 	if ((void __force *) addr <= high_memory) 
-		return; 
-	p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
-	if (!p) { 
-		printk("__iounmap: bad address %p\n", addr);
 		return;
+
+	/*
+	 * __ioremap special-cases the PCI/ISA range by not instantiating a
+	 * vm_area and by simply returning an address into the kernel mapping
+	 * of ISA space.   So handle that here.
+	 */
+	if (addr >= phys_to_virt(ISA_START_ADDRESS) &&
+			addr < phys_to_virt(ISA_END_ADDRESS))
+		return;
+
+	write_lock(&vmlist_lock);
+	p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
+	if (!p) { 
+		printk("iounmap: bad address %p\n", addr);
+		goto out_unlock;
 	}
 
 	if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
-		/* p->size includes the guard page, but cpa doesn't like that */
 		change_page_attr(virt_to_page(__va(p->phys_addr)),
-				 (p->size - PAGE_SIZE) >> PAGE_SHIFT,
-				 PAGE_KERNEL); 				 
+				 p->size >> PAGE_SHIFT,
+				 PAGE_KERNEL);
 		global_flush_tlb();
 	} 
+out_unlock:
+	write_unlock(&vmlist_lock);
 	kfree(p); 
 }
 
@@ -261,7 +270,7 @@ void __init *bt_ioremap(unsigned long ph
 	/*
 	 * Don't remap the low PCI/ISA area, it's always mapped..
 	 */
-	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+	if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
 		return phys_to_virt(phys_addr);
 
 	/*
diff --git a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap.c
--- a/arch/i386/mm/mmap.c
+++ b/arch/i386/mm/mmap.c
@@ -26,6 +26,7 @@
 
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/random.h>
 
 /*
  * Top of mmap area (just below the process stack).
@@ -38,13 +39,17 @@
 static inline unsigned long mmap_base(struct mm_struct *mm)
 {
 	unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+	unsigned long random_factor = 0;
+
+	if (current->flags & PF_RANDOMIZE)
+		random_factor = get_random_int() % (1024*1024);
 
 	if (gap < MIN_GAP)
 		gap = MIN_GAP;
 	else if (gap > MAX_GAP)
 		gap = MAX_GAP;
 
-	return TASK_SIZE - (gap & PAGE_MASK);
+	return PAGE_ALIGN(TASK_SIZE - gap - random_factor);
 }
 
 /*
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -189,7 +189,7 @@ int change_page_attr(struct page *page, 
 void global_flush_tlb(void)
 { 
 	LIST_HEAD(l);
-	struct list_head* n;
+	struct page *pg, *next;
 
 	BUG_ON(irqs_disabled());
 
@@ -197,12 +197,8 @@ void global_flush_tlb(void)
 	list_splice_init(&df_list, &l);
 	spin_unlock_irq(&cpa_lock);
 	flush_map();
-	n = l.next;
-	while (n != &l) {
-		struct page *pg = list_entry(n, struct page, lru);
-		n = n->next;
+	list_for_each_entry_safe(pg, next, &l, lru)
 		__free_page(pg);
-	}
 } 
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -255,6 +255,6 @@ void pgd_free(pgd_t *pgd)
 	if (PTRS_PER_PMD > 1)
 		for (i = 0; i < USER_PTRS_PER_PGD; ++i)
 			kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
-	/* in the non-PAE case, clear_page_range() clears user pgd entries */
+	/* in the non-PAE case, free_pgtables() clears user pgd entries */
 	kmem_cache_free(pgd_cache, pgd);
 }
diff --git a/arch/i386/oprofile/backtrace.c b/arch/i386/oprofile/backtrace.c
--- a/arch/i386/oprofile/backtrace.c
+++ b/arch/i386/oprofile/backtrace.c
@@ -18,7 +18,6 @@ struct frame_head {
 	unsigned long ret;
 } __attribute__((packed));
 
-
 static struct frame_head *
 dump_backtrace(struct frame_head * head)
 {
@@ -27,21 +26,11 @@ dump_backtrace(struct frame_head * head)
 	/* frame pointers should strictly progress back up the stack
 	 * (towards higher addresses) */
 	if (head >= head->ebp)
-		return 0;
+		return NULL;
 
 	return head->ebp;
 }
 
-
-#ifdef CONFIG_X86_4G
-/* With a 4G kernel/user split, user pages are not directly
- * accessible from the kernel, so don't try
- */
-static int pages_present(struct frame_head * head)
-{
-	return 0;
-}
-#else
 /* check that the page(s) containing the frame head are present */
 static int pages_present(struct frame_head * head)
 {
@@ -53,8 +42,6 @@ static int pages_present(struct frame_he
 
 	return check_user_page_readable(mm, (unsigned long)(head + 1));
 }
-#endif /* CONFIG_X86_4G */
-
 
 /*
  * |             | /\ Higher addresses
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -32,7 +32,7 @@ static int nmi_enabled = 0;
 
 #ifdef CONFIG_PM
 
-static int nmi_suspend(struct sys_device *dev, u32 state)
+static int nmi_suspend(struct sys_device *dev, pm_message_t state)
 {
 	if (nmi_enabled == 1)
 		nmi_stop();
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -36,7 +36,7 @@ static void timer_stop(void)
 {
 	enable_timer_nmi_watchdog();
 	unset_nmi_callback();
-	synchronize_kernel();
+	synchronize_sched();  /* Allow already-started NMIs to complete. */
 }
 
 
diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
--- a/arch/i386/pci/acpi.c
+++ b/arch/i386/pci/acpi.c
@@ -37,21 +37,12 @@ static int __init pci_acpi_init(void)
 		 * also do it here in case there are still broken drivers that
 		 * don't use pci_enable_device().
 		 */
-		printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
-		printk(KERN_INFO "** was specified.  If this was required to make a driver work,\n");
-		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
-		printk(KERN_INFO "** so I can fix the driver.\n");
+		printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
 		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
 			acpi_pci_irq_enable(dev);
-	} else {
-		printk(KERN_INFO "** PCI interrupts are no longer routed automatically.  If this\n");
-		printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
-		printk(KERN_INFO "** driver failed to call pci_enable_device().  As a temporary\n");
-		printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
-		printk(KERN_INFO "** behavior.  If this argument makes the device work again,\n");
-		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
-		printk(KERN_INFO "** so I can fix the driver.\n");
-	}
+	} else
+		printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\".  If it helps, post a report\n");
+
 #ifdef CONFIG_X86_IO_APIC
 	if (acpi_ioapic)
 		print_IO_APIC();
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
--- a/arch/i386/pci/direct.c
+++ b/arch/i386/pci/direct.c
@@ -13,7 +13,8 @@
 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
 	(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
 
-static int pci_conf1_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_conf1_read(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long flags;
 
@@ -41,7 +42,8 @@ static int pci_conf1_read (int seg, int 
 	return 0;
 }
 
-static int pci_conf1_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_conf1_write(unsigned int seg, unsigned int bus,
+			   unsigned int devfn, int reg, int len, u32 value)
 {
 	unsigned long flags;
 
@@ -83,7 +85,8 @@ struct pci_raw_ops pci_direct_conf1 = {
 
 #define PCI_CONF2_ADDRESS(dev, reg)	(u16)(0xC000 | (dev << 8) | reg)
 
-static int pci_conf2_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_conf2_read(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long flags;
 	int dev, fn;
@@ -121,7 +124,8 @@ static int pci_conf2_read(int seg, int b
 	return 0;
 }
 
-static int pci_conf2_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_conf2_write(unsigned int seg, unsigned int bus,
+			   unsigned int devfn, int reg, int len, u32 value)
 {
 	unsigned long flags;
 	int dev, fn;
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_N
 #define MAX_PCIEROOT	6
 static int quirk_aspm_offset[MAX_PCIEROOT << 3];
 
-#define GET_INDEX(a, b) (((a - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + b)
+#define GET_INDEX(a, b) ((((a) - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + ((b) & 7))
 
 static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
 {
@@ -343,7 +343,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
 /*
  * Fixup to mark boot BIOS video selected by BIOS before it changes
  *
- * From information provided by "Jon Smirl" <jonsmirl@yahoo.com>
+ * From information provided by "Jon Smirl" <jonsmirl@gmail.com>
  *
  * The standard boot ROM sequence for an x86 machine uses the BIOS
  * to select an initial video card for boot display. This boot video 
@@ -354,12 +354,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
  * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
  * is marked here since the boot video device will be the only enabled
  * video device at this point.
- *
- */static void __devinit pci_fixup_video(struct pci_dev *pdev)
+ */
+
+static void __devinit pci_fixup_video(struct pci_dev *pdev)
 {
 	struct pci_dev *bridge;
 	struct pci_bus *bus;
-	u16 l;
+	u16 config;
 
 	if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
 		return;
@@ -369,12 +370,17 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
 	while (bus) {
 		bridge = bus->self;
 		if (bridge) {
-			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l);
-			if (!(l & PCI_BRIDGE_CTL_VGA))
+			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
+						&config);
+			if (!(config & PCI_BRIDGE_CTL_VGA))
 				return;
 		}
 		bus = bus->parent;
 	}
-	pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+	pci_read_config_word(pdev, PCI_COMMAND, &config);
+	if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+		pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+		printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
+	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -124,7 +124,7 @@ static void __init pcibios_allocate_reso
 	u16 command;
 	struct resource *r, *pr;
 
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+	for_each_pci_dev(dev) {
 		pci_read_config_word(dev, PCI_COMMAND, &command);
 		for(idx = 0; idx < 6; idx++) {
 			r = &dev->resource[idx];
@@ -150,11 +150,11 @@ static void __init pcibios_allocate_reso
 		}
 		if (!pass) {
 			r = &dev->resource[PCI_ROM_RESOURCE];
-			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+			if (r->flags & IORESOURCE_ROM_ENABLE) {
 				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
 				u32 reg;
 				DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
-				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				r->flags &= ~IORESOURCE_ROM_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);
 			}
@@ -168,7 +168,7 @@ static int __init pcibios_assign_resourc
 	int idx;
 	struct resource *r;
 
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+	for_each_pci_dev(dev) {
 		int class = dev->class >> 8;
 
 		/* Don't touch classless devices and host bridges */
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -495,6 +495,9 @@ static __init int intel_router_probe(str
 		case PCI_DEVICE_ID_INTEL_ICH6_1:
 		case PCI_DEVICE_ID_INTEL_ICH7_0:
 		case PCI_DEVICE_ID_INTEL_ICH7_1:
+		case PCI_DEVICE_ID_INTEL_ICH7_30:
+		case PCI_DEVICE_ID_INTEL_ICH7_31:
+		case PCI_DEVICE_ID_INTEL_ESB2_0:
 			r->name = "PIIX/ICH";
 			r->get = pirq_piix_get;
 			r->set = pirq_piix_set;
@@ -1026,66 +1029,60 @@ void pcibios_penalize_isa_irq(int irq)
 static int pirq_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
-	extern int via_interrupt_line_quirk;
 	struct pci_dev *temp_dev;
 
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
-		char *msg;
-		msg = "";
+		char *msg = "";
+
+		pin--;		/* interrupt pins are numbered starting from 1 */
+
 		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.
-				 */
-				temp_dev = dev;
-				while (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 %s[%c] to get irq %d\n",
-							pci_name(bridge), 'A' + pin, irq);
-					dev = bridge;
-				}
-				dev = temp_dev;
-				if (irq >= 0) {
+			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.
+			 */
+			temp_dev = dev;
+			while (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 %s[%c] to get irq %d\n",
+						pci_name(bridge), 'A' + pin, irq);
+				dev = bridge;
+			}
+			dev = temp_dev;
+			if (irq >= 0) {
 #ifdef CONFIG_PCI_MSI
-					if (!platform_legacy_irq(irq))
-						irq = IO_APIC_VECTOR(irq);
+				if (!platform_legacy_irq(irq))
+					irq = IO_APIC_VECTOR(irq);
 #endif
-					printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
-						pci_name(dev), 'A' + pin, irq);
-					dev->irq = irq;
-					return 0;
-				} else
-					msg = " Probably buggy MP table.";
-			}
+				printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
+					pci_name(dev), 'A' + pin, irq);
+				dev->irq = irq;
+				return 0;
+			} else
+				msg = " Probably buggy MP table.";
 		} else if (pci_probe & PCI_BIOS_IRQ_SCAN)
 			msg = "";
 		else
 			msg = " Please try using pci=biosirq.";
-			
+
 		/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
 		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
 			return 0;
-			
+
 		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
-		       'A' + pin - 1, pci_name(dev), msg);
+		       'A' + pin, pci_name(dev), msg);
 	}
-	/* VIA bridges use interrupt line for apic/pci steering across
-	   the V-Link */
-	else if (via_interrupt_line_quirk)
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15);
 	return 0;
 }
 
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -34,7 +34,8 @@ static inline void pci_exp_set_dev_base(
 	}
 }
 
-static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long flags;
 
@@ -62,7 +63,8 @@ static int pci_mmcfg_read(int seg, int b
 	return 0;
 }
 
-static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+			   unsigned int devfn, int reg, int len, u32 value)
 {
 	unsigned long flags;
 
diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c
--- a/arch/i386/pci/numa.c
+++ b/arch/i386/pci/numa.c
@@ -14,11 +14,12 @@
 #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
 	(0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
 
-static int pci_conf1_mq_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
+			     unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long flags;
 
-	if (!value || (bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
+	if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -42,11 +43,12 @@ static int pci_conf1_mq_read (int seg, i
 	return 0;
 }
 
-static int pci_conf1_mq_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
+			      unsigned int devfn, int reg, int len, u32 value)
 {
 	unsigned long flags;
 
-	if ((bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
+	if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
--- a/arch/i386/pci/pcbios.c
+++ b/arch/i386/pci/pcbios.c
@@ -172,7 +172,8 @@ static int __devinit pci_bios_find_devic
 	return (int) (ret & 0xff00) >> 8;
 }
 
-static int pci_bios_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_bios_read(unsigned int seg, unsigned int bus,
+			 unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long result = 0;
 	unsigned long flags;
@@ -227,7 +228,8 @@ static int pci_bios_read (int seg, int b
 	return (int)((result & 0xff00) >> 8);
 }
 
-static int pci_bios_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_bios_write(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 value)
 {
 	unsigned long result = 0;
 	unsigned long flags;
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -28,8 +28,7 @@
 
 static struct saved_context saved_context;
 
-unsigned long saved_context_eax, saved_context_ebx;
-unsigned long saved_context_ecx, saved_context_edx;
+unsigned long saved_context_ebx;
 unsigned long saved_context_esp, saved_context_ebp;
 unsigned long saved_context_esi, saved_context_edi;
 unsigned long saved_context_eflags;
diff --git a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S
--- a/arch/i386/power/swsusp.S
+++ b/arch/i386/power/swsusp.S
@@ -12,6 +12,7 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
+#include <asm/asm_offsets.h>
 
 	.text
 
@@ -28,28 +29,37 @@ ENTRY(swsusp_arch_suspend)
 	ret
 
 ENTRY(swsusp_arch_resume)
-	movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
-	movl %ecx,%cr3
+	movl	$swsusp_pg_dir-__PAGE_OFFSET, %ecx
+	movl	%ecx, %cr3
 
-	movl	pagedir_nosave, %ebx
-	xorl	%eax, %eax
-	xorl	%edx, %edx
+	movl	pagedir_nosave, %edx
 	.p2align 4,,7
 
 copy_loop:
-	movl	4(%ebx,%edx),%edi
-	movl	(%ebx,%edx),%esi
+	testl	%edx, %edx
+	jz	done
+
+	movl	pbe_address(%edx), %esi
+	movl	pbe_orig_address(%edx), %edi
 
 	movl	$1024, %ecx
 	rep
 	movsl
 
-	incl	%eax
-	addl	$16, %edx
-	cmpl	nr_copy_pages,%eax
-	jb copy_loop
+	movl	pbe_next(%edx), %edx
+	jmp	copy_loop
 	.p2align 4,,7
 
+done:
+	/* Flush TLB, including "global" things (vmalloc) */
+	movl	mmu_cr4_features, %eax
+	movl	%eax, %edx
+	andl	$~(1<<7), %edx;  # PGE
+	movl	%edx, %cr4;  # turn off PGE
+	movl	%cr3, %ecx;  # flush TLB
+	movl	%ecx, %cr3
+	movl	%eax, %cr4;  # turn PGE back on
+
 	movl saved_context_esp, %esp
 	movl saved_context_ebp, %ebp
 	movl saved_context_ebx, %ebx
@@ -57,5 +67,7 @@ copy_loop:
 	movl saved_context_edi, %edi
 
 	pushl saved_context_eflags ; popfl
-	call swsusp_restore
+
+	xorl	%eax, %eax
+
 	ret
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -46,6 +46,10 @@ config GENERIC_IOMAP
 	bool
 	default y
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+	bool
+	default y
+
 choice
 	prompt "System type"
 	default IA64_GENERIC
@@ -169,6 +173,7 @@ config NUMA
 	bool "NUMA support"
 	depends on !IA64_HP_SIM
 	default y if IA64_SGI_SN2
+	select ACPI_NUMA
 	help
 	  Say Y to compile the kernel to support NUMA (Non-Uniform Memory
 	  Access).  This option is for configuring high-end multiprocessor
@@ -216,6 +221,16 @@ config IA64_SGI_SN_SIM
 	  If you are compiling a kernel that will run under SGI's IA-64
 	  simulator (Medusa) then say Y, otherwise say N.
 
+config IA64_SGI_SN_XP
+	tristate "Support communication between SGI SSIs"
+	depends on MSPEC
+	help
+	  An SGI machine can be divided into multiple Single System
+	  Images which act independently of each other and have
+	  hardware based memory protection from the others.  Enabling
+	  this feature will allow for direct communication between SSIs
+	  based on a network adapter and DMA messaging.
+
 config FORCE_MAX_ZONEORDER
 	int
 	default "18"
@@ -260,6 +275,15 @@ config HOTPLUG_CPU
 	  can be controlled through /sys/devices/system/cpu/cpu#.
 	  Say N if you want to disable CPU hotplug.
 
+config SCHED_SMT
+	bool "SMT scheduler support"
+	depends on SMP
+	default off
+	help
+	  Improves the CPU scheduler's decision making when dealing with
+	  Intel IA64 chips with MultiThreading at a cost of slightly increased
+	  overhead in some places. If unsure say N here.
+
 config PREEMPT
 	bool "Preemptible Kernel"
         help
@@ -328,7 +352,7 @@ menu "Power management and ACPI"
 
 config PM
 	bool "Power Management support"
-	depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB
+	depends on !IA64_HP_SIM
 	default y
 	help
 	  "Power Management" means that parts of your computer are shut
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -31,6 +31,7 @@ CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
+CONFIG_CPUSETS=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
@@ -573,6 +574,8 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_N_HDLC is not set
 # CONFIG_STALDRV is not set
 CONFIG_SGI_SNSC=y
+CONFIG_SGI_TIOCX=y
+CONFIG_SGI_MBCS=m
 
 #
 # Serial drivers
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Sat Jan 22 11:17:02 2005
+# Linux kernel version: 2.6.12-rc3
+# Tue May  3 15:55:04 2005
 #
 
 #
@@ -10,6 +10,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -21,24 +22,27 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=20
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -85,6 +89,7 @@ CONFIG_FORCE_MAX_ZONEORDER=18
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
 CONFIG_HOTPLUG_CPU=y
+# CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
@@ -135,6 +140,7 @@ CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_MSI is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCI Hotplug Support
@@ -152,10 +158,6 @@ CONFIG_HOTPLUG_PCI_ACPI=m
 # CONFIG_PCCARD is not set
 
 #
-# PC-card bridges
-#
-
-#
 # Device Drivers
 #
 
@@ -195,9 +197,10 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -313,7 +316,6 @@ CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
@@ -325,7 +327,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 CONFIG_SCSI_QLOGIC_FC=y
 # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
 CONFIG_SCSI_QLOGIC_1280=y
@@ -336,6 +337,7 @@ CONFIG_SCSI_QLA22XX=m
 CONFIG_SCSI_QLA2300=m
 CONFIG_SCSI_QLA2322=m
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -358,6 +360,7 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+# CONFIG_DM_MULTIPATH is not set
 
 #
 # Fusion MPT device support
@@ -386,7 +389,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -446,7 +448,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # ARCnet devices
@@ -484,7 +485,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=m
 CONFIG_E100=m
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -566,25 +566,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-CONFIG_GAMEPORT=m
-CONFIG_SOUND_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_VORTEX is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461X is not set
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -602,6 +583,24 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+CONFIG_GAMEPORT=m
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_GAMEPORT_EMU10K1 is not set
+# CONFIG_GAMEPORT_VORTEX is not set
+# CONFIG_GAMEPORT_FM801 is not set
+# CONFIG_GAMEPORT_CS461X is not set
+CONFIG_SOUND_GAMEPORT=m
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -615,6 +614,8 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_SYNCLINK is not set
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
 # CONFIG_STALDRV is not set
 
 #
@@ -635,6 +636,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -670,6 +672,12 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -705,7 +713,6 @@ CONFIG_MAX_RAW_DEVS=256
 #
 CONFIG_VGA_CONSOLE=y
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -715,6 +722,8 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -726,8 +735,6 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -736,6 +743,8 @@ CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
 
@@ -751,12 +760,11 @@ CONFIG_USB_UHCI_HCD=y
 #
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT 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_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
@@ -800,6 +808,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
@@ -824,6 +833,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
 # CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -867,7 +877,12 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
 CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=y
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -945,7 +960,7 @@ CONFIG_NFSD_V4=y
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
+CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
 CONFIG_RPCSEC_GSS_KRB5=m
@@ -1042,8 +1057,10 @@ CONFIG_GENERIC_IRQ_PROBE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=20
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1077,6 +1094,7 @@ CONFIG_CRYPTO_MD5=m
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1,9 +1,9 @@
 /*
 **  IA64 System Bus Adapter (SBA) I/O MMU manager
 **
-**	(c) Copyright 2002-2004 Alex Williamson
+**	(c) Copyright 2002-2005 Alex Williamson
 **	(c) Copyright 2002-2003 Grant Grundler
-**	(c) Copyright 2002-2004 Hewlett-Packard Company
+**	(c) Copyright 2002-2005 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)
@@ -157,6 +157,7 @@
 #define DELAYED_RESOURCE_CNT	64
 
 #define ZX1_IOC_ID	((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
+#define ZX2_IOC_ID	((PCI_DEVICE_ID_HP_ZX2_IOC << 16) | PCI_VENDOR_ID_HP)
 #define REO_IOC_ID	((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
 #define SX1000_IOC_ID	((PCI_DEVICE_ID_HP_SX1000_IOC << 16) | PCI_VENDOR_ID_HP)
 
@@ -458,21 +459,32 @@ get_iovp_order (unsigned long size)
  * 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.
+ * @use_hint: use res_hint to indicate where to start looking
  *
  * 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)
+sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
 {
-	unsigned long *res_ptr = ioc->res_hint;
+	unsigned long *res_ptr;
 	unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
-	unsigned long pide = ~0UL;
+	unsigned long flags, pide = ~0UL;
 
 	ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
 	ASSERT(res_ptr < res_end);
 
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+	/* Allow caller to force a search through the entire resource space */
+	if (likely(use_hint)) {
+		res_ptr = ioc->res_hint;
+	} else {
+		res_ptr = (ulong *)ioc->res_map;
+		ioc->res_bitshift = 0;
+	}
+
 	/*
 	 * N.B.  REO/Grande defect AR2305 can cause TLB fetch timeouts
 	 * if a TLB entry is purged while in use.  sba_mark_invalid()
@@ -569,10 +581,12 @@ not_found:
 	prefetch(ioc->res_map);
 	ioc->res_hint = (unsigned long *) ioc->res_map;
 	ioc->res_bitshift = 0;
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 	return (pide);
 
 found_it:
 	ioc->res_hint = res_ptr;
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 	return (pide);
 }
 
@@ -593,36 +607,36 @@ sba_alloc_range(struct ioc *ioc, size_t 
 	unsigned long itc_start;
 #endif
 	unsigned long pide;
-	unsigned long flags;
 
 	ASSERT(pages_needed);
 	ASSERT(0 == (size & ~iovp_mask));
 
-	spin_lock_irqsave(&ioc->res_lock, flags);
-
 #ifdef PDIR_SEARCH_TIMING
 	itc_start = ia64_get_itc();
 #endif
 	/*
 	** "seek and ye shall find"...praying never hurts either...
 	*/
-	pide = sba_search_bitmap(ioc, pages_needed);
+	pide = sba_search_bitmap(ioc, pages_needed, 1);
 	if (unlikely(pide >= (ioc->res_size << 3))) {
-		pide = sba_search_bitmap(ioc, pages_needed);
+		pide = sba_search_bitmap(ioc, pages_needed, 0);
 		if (unlikely(pide >= (ioc->res_size << 3))) {
 #if DELAYED_RESOURCE_CNT > 0
+			unsigned long flags;
+
 			/*
 			** With delayed resource freeing, we can give this one more shot.  We're
 			** getting close to being in trouble here, so do what we can to make this
 			** one count.
 			*/
-			spin_lock(&ioc->saved_lock);
+			spin_lock_irqsave(&ioc->saved_lock, flags);
 			if (ioc->saved_cnt > 0) {
 				struct sba_dma_pair *d;
 				int cnt = ioc->saved_cnt;
 
-				d = &(ioc->saved[ioc->saved_cnt]);
+				d = &(ioc->saved[ioc->saved_cnt - 1]);
 
+				spin_lock(&ioc->res_lock);
 				while (cnt--) {
 					sba_mark_invalid(ioc, d->iova, d->size);
 					sba_free_range(ioc, d->iova, d->size);
@@ -630,10 +644,11 @@ sba_alloc_range(struct ioc *ioc, size_t 
 				}
 				ioc->saved_cnt = 0;
 				READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+				spin_unlock(&ioc->res_lock);
 			}
-			spin_unlock(&ioc->saved_lock);
+			spin_unlock_irqrestore(&ioc->saved_lock, flags);
 
-			pide = sba_search_bitmap(ioc, pages_needed);
+			pide = sba_search_bitmap(ioc, pages_needed, 0);
 			if (unlikely(pide >= (ioc->res_size << 3)))
 				panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
 				      ioc->ioc_hpa);
@@ -663,8 +678,6 @@ sba_alloc_range(struct ioc *ioc, size_t 
 		(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
 		ioc->res_bitshift );
 
-	spin_unlock_irqrestore(&ioc->res_lock, flags);
-
 	return (pide);
 }
 
@@ -761,7 +774,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, unsigne
 #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
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
  * flush them when they get mapped into an executable vm-area.
  */
 static void
@@ -949,6 +962,30 @@ sba_map_single(struct device *dev, void 
 	return SBA_IOVA(ioc, iovp, offset);
 }
 
+#ifdef ENABLE_MARK_CLEAN
+static SBA_INLINE void
+sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size)
+{
+	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 {
+		do {
+			addr = phys_to_virt(ioc->pdir_base[off] &
+			                    ~0xE000000000000FFFULL);
+			mark_clean(addr, min(size, iovp_size));
+			off++;
+			size -= iovp_size;
+		} while (size > 0);
+	}
+}
+#endif
+
 /**
  * sba_unmap_single - unmap one IOVA and free resources
  * @dev: instance of PCI owned by the driver that's asking.
@@ -994,6 +1031,10 @@ void sba_unmap_single(struct device *dev
 	size += offset;
 	size = ROUNDUP(size, iovp_size);
 
+#ifdef ENABLE_MARK_CLEAN
+	if (dir == DMA_FROM_DEVICE)
+		sba_mark_clean(ioc, iova, size);
+#endif
 
 #if DELAYED_RESOURCE_CNT > 0
 	spin_lock_irqsave(&ioc->saved_lock, flags);
@@ -1020,30 +1061,6 @@ void sba_unmap_single(struct device *dev
 	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif /* DELAYED_RESOURCE_CNT == 0 */
-#ifdef ENABLE_MARK_CLEAN
-	if (dir == DMA_FROM_DEVICE) {
-		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
 }
 
 
@@ -1707,6 +1724,7 @@ struct ioc_iommu {
 
 static struct ioc_iommu ioc_iommu_info[] __initdata = {
 	{ ZX1_IOC_ID, "zx1", ioc_zx1_init },
+	{ ZX2_IOC_ID, "zx2", NULL },
 	{ SX1000_IOC_ID, "sx1000", NULL },
 };
 
@@ -1926,43 +1944,17 @@ sba_connect_bus(struct pci_bus *bus)
 static void __init
 sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
 {
-	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-	union acpi_object *obj;
-	acpi_handle phandle;
 	unsigned int node;
+	int pxm;
 
 	ioc->node = MAX_NUMNODES;
 
-	/*
-	 * Check for a _PXM on this node first.  We don't typically see
-	 * one here, so we'll end up getting it from the parent.
-	 */
-	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) {
-		if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))
-			return;
-
-		/* Reset the acpi buffer */
-		buffer.length = ACPI_ALLOCATE_BUFFER;
-		buffer.pointer = NULL;
+	pxm = acpi_get_pxm(handle);
 
-		if (ACPI_FAILURE(acpi_evaluate_object(phandle, "_PXM", NULL,
-		                                      &buffer)))
-			return;
-	}
-
-	if (!buffer.length || !buffer.pointer)
+	if (pxm < 0)
 		return;
 
-	obj = buffer.pointer;
-
-	if (obj->type != ACPI_TYPE_INTEGER ||
-	    obj->integer.value >= MAX_PXM_DOMAINS) {
-		acpi_os_free(buffer.pointer);
-		return;
-	}
-
-	node = pxm_to_nid_map[obj->integer.value];
-	acpi_os_free(buffer.pointer);
+	node = pxm_to_nid_map[pxm];
 
 	if (node >= MAX_NUMNODES || !node_online(node))
 		return;
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -494,7 +494,7 @@ ia32_syscall_table:
   	data8 compat_sys_mq_notify
   	data8 compat_sys_mq_getsetattr
 	data8 sys_ni_syscall		/* reserved for kexec */
-	data8 sys32_waitid
+	data8 compat_sys_waitid
 
 	// guard against failures to increase IA32_NR_syscalls
 	.org ia32_syscall_table + 8*IA32_NR_syscalls
diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c
--- a/arch/ia64/ia32/ia32_ioctl.c
+++ b/arch/ia64/ia32/ia32_ioctl.c
@@ -13,7 +13,6 @@
   
 #define	INCLUDES
 #include "compat_ioctl.c"
-#include <asm/ioctl32.h>
 
 #define IOCTL_NR(a)	((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
 
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -460,10 +460,9 @@ __ia32_rt_sigsuspend (compat_sigset_t *s
 	sigset_t oldset, set;
 
 	scr->scratch_unat = 0;	/* avoid leaking kernel bits to user level */
-	memset(&set, 0, sizeof(&set));
+	memset(&set, 0, sizeof(set));
 
-	if (memcpy(&set.sig, &sset->sig, sigsetsize))
-		return -EFAULT;
+	memcpy(&set.sig, &sset->sig, sigsetsize);
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
 
@@ -778,7 +777,7 @@ restore_sigcontext_ia32 (struct pt_regs 
 		struct _fpstate * buf;
 		err |= __get_user(buf, &sc->fpstate);
 		if (buf) {
-			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
 				goto badframe;
 			err |= restore_i387(buf);
 		}
@@ -978,7 +977,7 @@ sys32_sigreturn (int arg0, int arg1, int
 	sigset_t set;
 	int eax;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -1010,7 +1009,7 @@ sys32_rt_sigreturn (int arg0, int arg1, 
 	sigset_t set;
 	int eax;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h
--- a/arch/ia64/ia32/ia32priv.h
+++ b/arch/ia64/ia32/ia32priv.h
@@ -225,13 +225,6 @@ struct stat64 {
 	unsigned int	st_ino_hi;
 };
 
-typedef union sigval32 {
-	int sival_int;
-	unsigned int sival_ptr;
-} sigval_t32;
-
-#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
 typedef struct compat_siginfo {
 	int si_signo;
 	int si_errno;
@@ -251,7 +244,7 @@ typedef struct compat_siginfo {
 			timer_t _tid;		/* timer id */
 			int _overrun;		/* overrun count */
 			char _pad[sizeof(unsigned int) - sizeof(int)];
-			sigval_t32 _sigval;	/* same as below */
+			compat_sigval_t _sigval;	/* same as below */
 			int _sys_private;       /* not to be passed to user */
 		} _timer;
 
@@ -259,7 +252,7 @@ typedef struct compat_siginfo {
 		struct {
 			unsigned int _pid;	/* sender's pid */
 			unsigned int _uid;	/* sender's uid */
-			sigval_t32 _sigval;
+			compat_sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -284,19 +277,6 @@ typedef struct compat_siginfo {
 	} _sifields;
 } compat_siginfo_t;
 
-typedef struct sigevent32 {
-	sigval_t32 sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE32];
-		struct {
-			u32 _function;
-			u32 _attribute; /* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t32;
-
 struct old_linux32_dirent {
 	u32	d_ino;
 	u32	d_offset;
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -2402,12 +2402,11 @@ sys32_epoll_ctl(int epfd, int op, int fd
 {
 	mm_segment_t old_fs = get_fs();
 	struct epoll_event event64;
-	int error = -EFAULT;
+	int error;
 	u32 data_halfword;
 
-	if ((error = verify_area(VERIFY_READ, event,
-				 sizeof(struct epoll_event32))))
-		return error;
+	if (!access_ok(VERIFY_READ, event, sizeof(struct epoll_event32)))
+		return -EFAULT;
 
 	__get_user(event64.events, &event->events);
 	__get_user(data_halfword, &event->data[0]);
@@ -2428,7 +2427,7 @@ sys32_epoll_wait(int epfd, struct epoll_
 {
 	struct epoll_event *events64 = NULL;
 	mm_segment_t old_fs = get_fs();
-	int error, numevents, size;
+	int numevents, size;
 	int evt_idx;
 	int do_free_pages = 0;
 
@@ -2437,9 +2436,8 @@ sys32_epoll_wait(int epfd, struct epoll_
 	}
 
 	/* Verify that the area passed by the user is writeable */
-	if ((error = verify_area(VERIFY_WRITE, events,
-				 maxevents * sizeof(struct epoll_event32))))
-		return error;
+	if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event32)))
+		return -EFAULT;
 
 	/*
  	 * Allocate space for the intermediate copy.  If the space needed
@@ -2592,7 +2590,7 @@ sys32_get_thread_area (struct ia32_user_
 }
 
 asmlinkage long
-sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id)
+sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id)
 {
 	struct sigevent se;
 	mm_segment_t oldfs;
@@ -2602,12 +2600,7 @@ sys32_timer_create(u32 clock, struct sig
 	if (se32 == NULL)
 		return sys_timer_create(clock, NULL, timer_id);
 
-	memset(&se, 0, sizeof(struct sigevent));
-	if (get_user(se.sigev_value.sival_int,	&se32->sigev_value.sival_int) ||
-	    __get_user(se.sigev_signo, &se32->sigev_signo) ||
-	    __get_user(se.sigev_notify, &se32->sigev_notify) ||
-	    __copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad,
-	    sizeof(se._sigev_un._pad)))
+	if (get_compat_sigevent(&se, se32))
 		return -EFAULT;
 
 	if (!access_ok(VERIFY_WRITE,timer_id,sizeof(timer_t)))
@@ -2633,32 +2626,6 @@ long sys32_fadvise64_64(int fd, __u32 of
 			       advice); 
 } 
 
-asmlinkage long sys32_waitid(int which, compat_pid_t pid,
-			     compat_siginfo_t __user *uinfo, int options,
-			     struct compat_rusage __user *uru)
-{
-	siginfo_t info;
-	struct rusage ru;
-	long ret;
-	mm_segment_t old_fs = get_fs();
-
-	info.si_signo = 0;
-	set_fs (KERNEL_DS);
-	ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
-			 uru ? (struct rusage __user *) &ru : NULL);
-	set_fs (old_fs);
-
-	if (ret < 0 || info.si_signo == 0)
-		return ret;
-
-	if (uru && (ret = put_compat_rusage(&ru, uru)))
-		return ret;
-
-	BUG_ON(info.si_code & __SI_MASK);
-	info.si_code |= __SI_CHLD;
-	return copy_siginfo_to_user32(uinfo, &info);
-}
-
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid)
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -771,7 +771,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
  
 
-#ifdef CONFIG_NUMA
+#ifdef CONFIG_ACPI_NUMA
 acpi_status __init
 acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
 {
@@ -779,7 +779,7 @@ acpi_map_iosapic (acpi_handle handle, u3
 	union acpi_object *obj;
 	struct acpi_table_iosapic *iosapic;
 	unsigned int gsi_base;
-	int node;
+	int pxm, node;
 
 	/* Only care about objects w/ a method that returns the MADT */
 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
@@ -805,29 +805,16 @@ acpi_map_iosapic (acpi_handle handle, u3
 	gsi_base = iosapic->global_irq_base;
 
 	acpi_os_free(buffer.pointer);
-	buffer.length = ACPI_ALLOCATE_BUFFER;
-	buffer.pointer = NULL;
 
 	/*
-	 * OK, it's an IOSAPIC MADT entry, look for a _PXM method to tell
+	 * OK, it's an IOSAPIC MADT entry, look for a _PXM value to tell
 	 * us which node to associate this with.
 	 */
-	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer)))
+	pxm = acpi_get_pxm(handle);
+	if (pxm < 0)
 		return AE_OK;
 
-	if (!buffer.length || !buffer.pointer)
-		return AE_OK;
-
-	obj = buffer.pointer;
-
-	if (obj->type != ACPI_TYPE_INTEGER ||
-	    obj->integer.value >= MAX_PXM_DOMAINS) {
-		acpi_os_free(buffer.pointer);
-		return AE_OK;
-	}
-
-	node = pxm_to_nid_map[obj->integer.value];
-	acpi_os_free(buffer.pointer);
+	node = pxm_to_nid_map[pxm];
 
 	if (node >= MAX_NUMNODES || !node_online(node) ||
 	    cpus_empty(node_to_cpumask(node)))
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -728,12 +728,8 @@ ENTRY(ia64_leave_syscall)
 	mov f8=f0		// clear f8
 	;;
 	ld8 r30=[r2],16		// M0|1 load cr.ifs
-	mov.m ar.ssd=r0		// M2 clear ar.ssd
-	cmp.eq p9,p0=r0,r0	// set p9 to indicate that we should restore cr.ifs
-	;;
 	ld8 r25=[r3],16		// M0|1 load ar.unat
-	mov.m ar.csd=r0		// M2 clear ar.csd
-	mov r22=r0		// clear r22
+	cmp.eq p9,p0=r0,r0	// set p9 to indicate that we should restore cr.ifs
 	;;
 	ld8 r26=[r2],PT(B0)-PT(AR_PFS)	// M0|1 load ar.pfs
 (pKStk)	mov r22=psr		// M2 read PSR now that interrupts are disabled
@@ -756,11 +752,15 @@ ENTRY(ia64_leave_syscall)
 	mov f7=f0		// clear f7
 	;;
 	ld8.fill r12=[r2]	// restore r12 (sp)
+	mov.m ar.ssd=r0		// M2 clear ar.ssd
+	mov r22=r0		// clear r22
+
 	ld8.fill r15=[r3]	// restore r15
+(pUStk) st1 [r14]=r17
 	addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0
 	;;
-(pUStk)	ld4 r3=[r3]		// r3 = cpu_data->phys_stacked_size_p8
-(pUStk) st1 [r14]=r17
+(pUStk)	ld4 r17=[r3]		// r17 = cpu_data->phys_stacked_size_p8
+	mov.m ar.csd=r0		// M2 clear ar.csd
 	mov b6=r18		// I0  restore b6
 	;;
 	mov r14=r0		// clear r14
@@ -782,7 +782,7 @@ GLOBAL_ENTRY(ia64_ret_from_ia32_execve)
 	st8.spill [r2]=r8	// store return value in slot for r8 and set unat bit
 	.mem.offset 8,0
 	st8.spill [r3]=r0	// clear error indication in slot for r10 and set unat bit
-END(ia64_ret_from_ia32_execve_syscall)
+END(ia64_ret_from_ia32_execve)
 	// fall through
 #endif /* CONFIG_IA32_SUPPORT */
 GLOBAL_ENTRY(ia64_leave_kernel)
@@ -1182,7 +1182,7 @@ ENTRY(notify_resume_user)
 	;;
 (pNonSys) mov out2=0				// out2==0 => not a syscall
 	.fframe 16
-	.spillpsp ar.unat, 16			// (note that offset is relative to psp+0x10!)
+	.spillsp ar.unat, 16
 	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
 	st8 [out1]=loc1,-8			// save ar.pfs, out1=&sigscratch
 	.body
@@ -1208,7 +1208,7 @@ GLOBAL_ENTRY(sys_rt_sigsuspend)
 	adds out2=8,sp				// out2=&sigscratch->ar_pfs
 	;;
 	.fframe 16
-	.spillpsp ar.unat, 16			// (note that offset is relative to psp+0x10!)
+	.spillsp ar.unat, 16
 	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
 	st8 [out2]=loc1,-8			// save ar.pfs, out2=&sigscratch
 	.body
@@ -1417,7 +1417,7 @@ sys_call_table:
 	data8 sys_msgrcv
 	data8 sys_msgctl
 	data8 sys_shmget
-	data8 ia64_shmat
+	data8 sys_shmat
 	data8 sys_shmdt				// 1115
 	data8 sys_shmctl
 	data8 sys_syslog
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -460,9 +460,9 @@ EX(.fail_efault, ld8 r14=[r33])			// r14
 	;;
 
 	st8 [r2]=r14				// update current->blocked with new mask
-	cmpxchg4.acq r14=[r9],r18,ar.ccv	// current->thread_info->flags <- r18
+	cmpxchg4.acq r8=[r9],r18,ar.ccv		// current->thread_info->flags <- r18
 	;;
-	cmp.ne p6,p0=r17,r14			// update failed?
+	cmp.ne p6,p0=r17,r8			// update failed?
 (p6)	br.cond.spnt.few 1b			// yes -> retry
 
 #ifdef CONFIG_SMP
@@ -611,8 +611,10 @@ GLOBAL_ENTRY(fsys_bubble_down)
 	movl r2=ia64_ret_from_syscall
 	;;
 	mov rp=r2				// set the real return addr
-	tbit.z p8,p0=r3,TIF_SYSCALL_TRACE
+	and r3=_TIF_SYSCALL_TRACEAUDIT,r3
 	;;
+	cmp.eq p8,p0=r3,r0
+
 (p10)	br.cond.spnt.many ia64_ret_from_syscall	// p10==true means out registers are more than 8
 (p8)	br.call.sptk.many b6=b6		// ignore this return addr
 	br.cond.sptk ia64_trace_syscall
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -15,6 +15,8 @@
  * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
  * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
  *   -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
+ * Copyright (C) 2004 Ashok Raj <ashok.raj@intel.com>
+ *   Support for CPU Hotplug
  */
 
 #include <linux/config.h>
@@ -29,6 +31,139 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
+#include <asm/mca_asm.h>
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define SAL_PSR_BITS_TO_SET				\
+	(IA64_PSR_AC | IA64_PSR_BN | IA64_PSR_MFH | IA64_PSR_MFL)
+
+#define SAVE_FROM_REG(src, ptr, dest)	\
+	mov dest=src;;						\
+	st8 [ptr]=dest,0x08
+
+#define RESTORE_REG(reg, ptr, _tmp)		\
+	ld8 _tmp=[ptr],0x08;;				\
+	mov reg=_tmp
+
+#define SAVE_BREAK_REGS(ptr, _idx, _breg, _dest)\
+	mov ar.lc=IA64_NUM_DBG_REGS-1;; 			\
+	mov _idx=0;; 								\
+1: 												\
+	SAVE_FROM_REG(_breg[_idx], ptr, _dest);;	\
+	add _idx=1,_idx;;							\
+	br.cloop.sptk.many 1b
+
+#define RESTORE_BREAK_REGS(ptr, _idx, _breg, _tmp, _lbl)\
+	mov ar.lc=IA64_NUM_DBG_REGS-1;;			\
+	mov _idx=0;;							\
+_lbl:  RESTORE_REG(_breg[_idx], ptr, _tmp);;	\
+	add _idx=1, _idx;;						\
+	br.cloop.sptk.many _lbl
+
+#define SAVE_ONE_RR(num, _reg, _tmp) \
+	movl _tmp=(num<<61);;	\
+	mov _reg=rr[_tmp]
+
+#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \
+	SAVE_ONE_RR(0,_r0, _tmp);; \
+	SAVE_ONE_RR(1,_r1, _tmp);; \
+	SAVE_ONE_RR(2,_r2, _tmp);; \
+	SAVE_ONE_RR(3,_r3, _tmp);; \
+	SAVE_ONE_RR(4,_r4, _tmp);; \
+	SAVE_ONE_RR(5,_r5, _tmp);; \
+	SAVE_ONE_RR(6,_r6, _tmp);; \
+	SAVE_ONE_RR(7,_r7, _tmp);;
+
+#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \
+	st8 [ptr]=_r0, 8;; \
+	st8 [ptr]=_r1, 8;; \
+	st8 [ptr]=_r2, 8;; \
+	st8 [ptr]=_r3, 8;; \
+	st8 [ptr]=_r4, 8;; \
+	st8 [ptr]=_r5, 8;; \
+	st8 [ptr]=_r6, 8;; \
+	st8 [ptr]=_r7, 8;;
+
+#define RESTORE_REGION_REGS(ptr, _idx1, _idx2, _tmp) \
+	mov		ar.lc=0x08-1;;						\
+	movl	_idx1=0x00;;						\
+RestRR:											\
+	dep.z	_idx2=_idx1,61,3;;					\
+	ld8		_tmp=[ptr],8;;						\
+	mov		rr[_idx2]=_tmp;;					\
+	srlz.d;;									\
+	add		_idx1=1,_idx1;;						\
+	br.cloop.sptk.few	RestRR
+
+#define SET_AREA_FOR_BOOTING_CPU(reg1, reg2) \
+	movl reg1=sal_state_for_booting_cpu;;	\
+	ld8 reg2=[reg1];;
+
+/*
+ * Adjust region registers saved before starting to save
+ * break regs and rest of the states that need to be preserved.
+ */
+#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(_reg1,_reg2,_pred)  \
+	SAVE_FROM_REG(b0,_reg1,_reg2);;						\
+	SAVE_FROM_REG(b1,_reg1,_reg2);;						\
+	SAVE_FROM_REG(b2,_reg1,_reg2);;						\
+	SAVE_FROM_REG(b3,_reg1,_reg2);;						\
+	SAVE_FROM_REG(b4,_reg1,_reg2);;						\
+	SAVE_FROM_REG(b5,_reg1,_reg2);;						\
+	st8 [_reg1]=r1,0x08;;								\
+	st8 [_reg1]=r12,0x08;;								\
+	st8 [_reg1]=r13,0x08;;								\
+	SAVE_FROM_REG(ar.fpsr,_reg1,_reg2);;				\
+	SAVE_FROM_REG(ar.pfs,_reg1,_reg2);;					\
+	SAVE_FROM_REG(ar.rnat,_reg1,_reg2);;				\
+	SAVE_FROM_REG(ar.unat,_reg1,_reg2);;				\
+	SAVE_FROM_REG(ar.bspstore,_reg1,_reg2);;			\
+	SAVE_FROM_REG(cr.dcr,_reg1,_reg2);;					\
+	SAVE_FROM_REG(cr.iva,_reg1,_reg2);;					\
+	SAVE_FROM_REG(cr.pta,_reg1,_reg2);;					\
+	SAVE_FROM_REG(cr.itv,_reg1,_reg2);;					\
+	SAVE_FROM_REG(cr.pmv,_reg1,_reg2);;					\
+	SAVE_FROM_REG(cr.cmcv,_reg1,_reg2);;				\
+	SAVE_FROM_REG(cr.lrr0,_reg1,_reg2);;				\
+	SAVE_FROM_REG(cr.lrr1,_reg1,_reg2);;				\
+	st8 [_reg1]=r4,0x08;;								\
+	st8 [_reg1]=r5,0x08;;								\
+	st8 [_reg1]=r6,0x08;;								\
+	st8 [_reg1]=r7,0x08;;								\
+	st8 [_reg1]=_pred,0x08;;							\
+	SAVE_FROM_REG(ar.lc, _reg1, _reg2);;				\
+	stf.spill.nta [_reg1]=f2,16;;						\
+	stf.spill.nta [_reg1]=f3,16;;						\
+	stf.spill.nta [_reg1]=f4,16;;						\
+	stf.spill.nta [_reg1]=f5,16;;						\
+	stf.spill.nta [_reg1]=f16,16;;						\
+	stf.spill.nta [_reg1]=f17,16;;						\
+	stf.spill.nta [_reg1]=f18,16;;						\
+	stf.spill.nta [_reg1]=f19,16;;						\
+	stf.spill.nta [_reg1]=f20,16;;						\
+	stf.spill.nta [_reg1]=f21,16;;						\
+	stf.spill.nta [_reg1]=f22,16;;						\
+	stf.spill.nta [_reg1]=f23,16;;						\
+	stf.spill.nta [_reg1]=f24,16;;						\
+	stf.spill.nta [_reg1]=f25,16;;						\
+	stf.spill.nta [_reg1]=f26,16;;						\
+	stf.spill.nta [_reg1]=f27,16;;						\
+	stf.spill.nta [_reg1]=f28,16;;						\
+	stf.spill.nta [_reg1]=f29,16;;						\
+	stf.spill.nta [_reg1]=f30,16;;						\
+	stf.spill.nta [_reg1]=f31,16;;
+
+#else
+#define SET_AREA_FOR_BOOTING_CPU(a1, a2)
+#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2, a3)
+#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)
+#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)
+#endif
+
+#define SET_ONE_RR(num, pgsize, _tmp1, _tmp2, vhpt) \
+	movl _tmp1=(num << 61);;	\
+	mov _tmp2=((ia64_rid(IA64_REGION_ID_KERNEL, (num<<61)) << 8) | (pgsize << 2) | vhpt);; \
+	mov rr[_tmp1]=_tmp2
 
 	.section __special_page_section,"ax"
 
@@ -64,6 +199,12 @@ start_ap:
 	srlz.i
 	;;
 	/*
+	 * Save the region registers, predicate before they get clobbered
+	 */
+	SAVE_REGION_REGS(r2, r8,r9,r10,r11,r12,r13,r14,r15);
+	mov r25=pr;;
+
+	/*
 	 * Initialize kernel region registers:
 	 *	rr[0]: VHPT enabled, page size = PAGE_SHIFT
 	 *	rr[1]: VHPT enabled, page size = PAGE_SHIFT
@@ -76,32 +217,14 @@ start_ap:
 	 * We initialize all of them to prevent inadvertently assuming
 	 * something about the state of address translation early in boot.
 	 */
-	mov r6=((ia64_rid(IA64_REGION_ID_KERNEL, (0<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r7=(0<<61)
-	mov r8=((ia64_rid(IA64_REGION_ID_KERNEL, (1<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r9=(1<<61)
-	mov r10=((ia64_rid(IA64_REGION_ID_KERNEL, (2<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r11=(2<<61)
-	mov r12=((ia64_rid(IA64_REGION_ID_KERNEL, (3<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r13=(3<<61)
-	mov r14=((ia64_rid(IA64_REGION_ID_KERNEL, (4<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r15=(4<<61)
-	mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
-	movl r17=(5<<61)
-	mov r18=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2))
-	movl r19=(6<<61)
-	mov r20=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2))
-	movl r21=(7<<61)
-	;;
-	mov rr[r7]=r6
-	mov rr[r9]=r8
-	mov rr[r11]=r10
-	mov rr[r13]=r12
-	mov rr[r15]=r14
-	mov rr[r17]=r16
-	mov rr[r19]=r18
-	mov rr[r21]=r20
-	;;
+	SET_ONE_RR(0, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(1, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(2, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(3, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(4, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(5, PAGE_SHIFT, r2, r16, 1);;
+	SET_ONE_RR(6, IA64_GRANULE_SHIFT, r2, r16, 0);;
+	SET_ONE_RR(7, IA64_GRANULE_SHIFT, r2, r16, 0);;
 	/*
 	 * Now pin mappings into the TLB for kernel text and data
 	 */
@@ -142,6 +265,12 @@ start_ap:
 	;;
 1:	// now we are in virtual mode
 
+	SET_AREA_FOR_BOOTING_CPU(r2, r16);
+
+	STORE_REGION_REGS(r16, r8,r9,r10,r11,r12,r13,r14,r15);
+	SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(r16,r17,r25)
+	;;
+
 	// set IVT entry point---can't access I/O ports without it
 	movl r3=ia64_ivt
 	;;
@@ -211,12 +340,13 @@ start_ap:
 	mov IA64_KR(CURRENT_STACK)=r16
 	mov r13=r2
 	/*
-	 * Reserve space at the top of the stack for "struct pt_regs".  Kernel threads
-	 * don't store interesting values in that structure, but the space still needs
-	 * to be there because time-critical stuff such as the context switching can
-	 * be implemented more efficiently (for example, __switch_to()
+	 * Reserve space at the top of the stack for "struct pt_regs".  Kernel
+	 * threads don't store interesting values in that structure, but the space
+	 * still needs to be there because time-critical stuff such as the context
+	 * switching can be implemented more efficiently (for example, __switch_to()
 	 * always sets the psr.dfh bit of the task it is switching to).
 	 */
+
 	addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2
 	addl r2=IA64_RBS_OFFSET,r2	// initialize the RSE
 	mov ar.rsc=0		// place RSE in enforced lazy mode
@@ -993,4 +1123,98 @@ END(ia64_spinlock_contention)
 
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+GLOBAL_ENTRY(ia64_jump_to_sal)
+	alloc r16=ar.pfs,1,0,0,0;;
+	rsm psr.i  | psr.ic
+{
+	flushrs
+	srlz.i
+}
+	tpa r25=in0
+	movl r18=tlb_purge_done;;
+	DATA_VA_TO_PA(r18);;
+	mov b1=r18 	// Return location
+	movl r18=ia64_do_tlb_purge;;
+	DATA_VA_TO_PA(r18);;
+	mov b2=r18 	// doing tlb_flush work
+	mov ar.rsc=0  // Put RSE  in enforced lazy, LE mode
+	movl r17=1f;;
+	DATA_VA_TO_PA(r17);;
+	mov cr.iip=r17
+	movl r16=SAL_PSR_BITS_TO_SET;;
+	mov cr.ipsr=r16
+	mov cr.ifs=r0;;
+	rfi;;
+1:
+	/*
+	 * Invalidate all TLB data/inst
+	 */
+	br.sptk.many b2;; // jump to tlb purge code
+
+tlb_purge_done:
+	RESTORE_REGION_REGS(r25, r17,r18,r19);;
+	RESTORE_REG(b0, r25, r17);;
+	RESTORE_REG(b1, r25, r17);;
+	RESTORE_REG(b2, r25, r17);;
+	RESTORE_REG(b3, r25, r17);;
+	RESTORE_REG(b4, r25, r17);;
+	RESTORE_REG(b5, r25, r17);;
+	ld8 r1=[r25],0x08;;
+	ld8 r12=[r25],0x08;;
+	ld8 r13=[r25],0x08;;
+	RESTORE_REG(ar.fpsr, r25, r17);;
+	RESTORE_REG(ar.pfs, r25, r17);;
+	RESTORE_REG(ar.rnat, r25, r17);;
+	RESTORE_REG(ar.unat, r25, r17);;
+	RESTORE_REG(ar.bspstore, r25, r17);;
+	RESTORE_REG(cr.dcr, r25, r17);;
+	RESTORE_REG(cr.iva, r25, r17);;
+	RESTORE_REG(cr.pta, r25, r17);;
+	RESTORE_REG(cr.itv, r25, r17);;
+	RESTORE_REG(cr.pmv, r25, r17);;
+	RESTORE_REG(cr.cmcv, r25, r17);;
+	RESTORE_REG(cr.lrr0, r25, r17);;
+	RESTORE_REG(cr.lrr1, r25, r17);;
+	ld8 r4=[r25],0x08;;
+	ld8 r5=[r25],0x08;;
+	ld8 r6=[r25],0x08;;
+	ld8 r7=[r25],0x08;;
+	ld8 r17=[r25],0x08;;
+	mov pr=r17,-1;;
+	RESTORE_REG(ar.lc, r25, r17);;
+	/*
+	 * Now Restore floating point regs
+	 */
+	ldf.fill.nta f2=[r25],16;;
+	ldf.fill.nta f3=[r25],16;;
+	ldf.fill.nta f4=[r25],16;;
+	ldf.fill.nta f5=[r25],16;;
+	ldf.fill.nta f16=[r25],16;;
+	ldf.fill.nta f17=[r25],16;;
+	ldf.fill.nta f18=[r25],16;;
+	ldf.fill.nta f19=[r25],16;;
+	ldf.fill.nta f20=[r25],16;;
+	ldf.fill.nta f21=[r25],16;;
+	ldf.fill.nta f22=[r25],16;;
+	ldf.fill.nta f23=[r25],16;;
+	ldf.fill.nta f24=[r25],16;;
+	ldf.fill.nta f25=[r25],16;;
+	ldf.fill.nta f26=[r25],16;;
+	ldf.fill.nta f27=[r25],16;;
+	ldf.fill.nta f28=[r25],16;;
+	ldf.fill.nta f29=[r25],16;;
+	ldf.fill.nta f30=[r25],16;;
+	ldf.fill.nta f31=[r25],16;;
+
+	/*
+	 * Now that we have done all the register restores
+	 * we are now ready for the big DIVE to SAL Land
+	 */
+	ssm psr.ic;;
+	srlz.d;;
+	br.ret.sptk.many b0;;
+END(ia64_jump_to_sal)
+#endif /* CONFIG_HOTPLUG_CPU */
+
 #endif /* CONFIG_SMP */
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -79,6 +79,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/string.h>
+#include <linux/bootmem.h>
 
 #include <asm/delay.h>
 #include <asm/hw_irq.h>
@@ -91,7 +92,6 @@
 
 
 #undef DEBUG_INTERRUPT_ROUTING
-#undef OVERRIDE_DEBUG
 
 #ifdef DEBUG_INTERRUPT_ROUTING
 #define DBG(fmt...)	printk(fmt)
@@ -99,19 +99,30 @@
 #define DBG(fmt...)
 #endif
 
+#define NR_PREALLOCATE_RTE_ENTRIES	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
+#define RTE_PREALLOCATED	(1)
+
 static DEFINE_SPINLOCK(iosapic_lock);
 
 /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
 
-static struct iosapic_intr_info {
+struct iosapic_rte_info {
+	struct list_head rte_list;	/* node in list of RTEs sharing the same vector */
 	char __iomem	*addr;		/* base address of IOSAPIC */
-	u32		low32;		/* current value of low word of Redirection table entry */
 	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
-	char		rte_index;	/* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */
+	char		rte_index;	/* IOSAPIC RTE index */
+	int		refcnt;		/* reference counter */
+	unsigned int	flags;		/* flags */
+} ____cacheline_aligned;
+
+static struct iosapic_intr_info {
+	struct list_head rtes;		/* RTEs using this vector (empty => not an IOSAPIC interrupt) */
+	int		count;		/* # of RTEs that shares this vector */
+	u32		low32;		/* current value of low word of Redirection table entry */
+	unsigned int	dest;		/* destination CPU physical ID */
 	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) */
-	int		refcnt;		/* reference counter */
 } iosapic_intr_info[IA64_NUM_VECTORS];
 
 static struct iosapic {
@@ -127,6 +138,8 @@ static int num_iosapic;
 
 static unsigned char pcat_compat __initdata;	/* 8259 compatibility flag */
 
+static int iosapic_kmalloc_ok;
+static LIST_HEAD(free_rte_list);
 
 /*
  * Find an IOSAPIC associated with a GSI
@@ -148,10 +161,12 @@ static inline int
 _gsi_to_vector (unsigned int gsi)
 {
 	struct iosapic_intr_info *info;
+	struct iosapic_rte_info *rte;
 
 	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
-		if (info->gsi_base + info->rte_index == gsi)
-			return info - iosapic_intr_info;
+		list_for_each_entry(rte, &info->rtes, rte_list)
+			if (rte->gsi_base + rte->rte_index == gsi)
+				return info - iosapic_intr_info;
 	return -1;
 }
 
@@ -168,33 +183,52 @@ gsi_to_vector (unsigned int gsi)
 int
 gsi_to_irq (unsigned int gsi)
 {
+	unsigned long flags;
+	int irq;
 	/*
 	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
 	 * numbers...
 	 */
-	return _gsi_to_vector(gsi);
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		irq = _gsi_to_vector(gsi);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+
+	return irq;
+}
+
+static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
+{
+	struct iosapic_rte_info *rte;
+
+	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
+		if (rte->gsi_base + rte->rte_index == gsi)
+			return rte;
+	return NULL;
 }
 
 static void
-set_rte (unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
 {
 	unsigned long pol, trigger, dmode;
 	u32 low32, high32;
 	char __iomem *addr;
 	int rte_index;
 	char redir;
+	struct iosapic_rte_info *rte;
 
 	DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
 
-	rte_index = iosapic_intr_info[vector].rte_index;
-	if (rte_index < 0)
+	rte = gsi_vector_to_rte(gsi, vector);
+	if (!rte)
 		return;		/* not an IOSAPIC interrupt */
 
-	addr    = iosapic_intr_info[vector].addr;
+	rte_index = rte->rte_index;
+	addr	= rte->addr;
 	pol     = iosapic_intr_info[vector].polarity;
 	trigger = iosapic_intr_info[vector].trigger;
 	dmode   = iosapic_intr_info[vector].dmode;
-	vector &= (~IA64_IRQ_REDIRECTED);
 
 	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
 
@@ -222,6 +256,7 @@ set_rte (unsigned int vector, unsigned i
 	iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
 	iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 	iosapic_intr_info[vector].low32 = low32;
+	iosapic_intr_info[vector].dest = dest;
 }
 
 static void
@@ -238,18 +273,20 @@ mask_irq (unsigned int irq)
 	u32 low32;
 	int rte_index;
 	ia64_vector vec = irq_to_vector(irq);
+	struct iosapic_rte_info *rte;
 
-	addr = iosapic_intr_info[vec].addr;
-	rte_index = iosapic_intr_info[vec].rte_index;
-
-	if (rte_index < 0)
+	if (list_empty(&iosapic_intr_info[vec].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 		/* set only the mask bit */
 		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-		iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+			addr = rte->addr;
+			rte_index = rte->rte_index;
+			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		}
 	}
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
@@ -262,16 +299,19 @@ unmask_irq (unsigned int irq)
 	u32 low32;
 	int rte_index;
 	ia64_vector vec = irq_to_vector(irq);
+	struct iosapic_rte_info *rte;
 
-	addr = iosapic_intr_info[vec].addr;
-	rte_index = iosapic_intr_info[vec].rte_index;
-	if (rte_index < 0)
+	if (list_empty(&iosapic_intr_info[vec].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-		iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+			addr = rte->addr;
+			rte_index = rte->rte_index;
+			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		}
 	}
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
@@ -287,6 +327,7 @@ iosapic_set_affinity (unsigned int irq, 
 	char __iomem *addr;
 	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
 	ia64_vector vec;
+	struct iosapic_rte_info *rte;
 
 	irq &= (~IA64_IRQ_REDIRECTED);
 	vec = irq_to_vector(irq);
@@ -296,10 +337,7 @@ iosapic_set_affinity (unsigned int irq, 
 
 	dest = cpu_physical_id(first_cpu(mask));
 
-	rte_index = iosapic_intr_info[vec].rte_index;
-	addr = iosapic_intr_info[vec].addr;
-
-	if (rte_index < 0)
+	if (list_empty(&iosapic_intr_info[vec].rtes))
 		return;			/* not an IOSAPIC interrupt */
 
 	set_irq_affinity_info(irq, dest, redir);
@@ -319,8 +357,13 @@ iosapic_set_affinity (unsigned int irq, 
 			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
 
 		iosapic_intr_info[vec].low32 = low32;
-		iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
-		iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		iosapic_intr_info[vec].dest = dest;
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+			addr = rte->addr;
+			rte_index = rte->rte_index;
+			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
+			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
+		}
 	}
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 #endif
@@ -341,9 +384,11 @@ static void
 iosapic_end_level_irq (unsigned int irq)
 {
 	ia64_vector vec = irq_to_vector(irq);
+	struct iosapic_rte_info *rte;
 
 	move_irq(irq);
-	iosapic_eoi(iosapic_intr_info[vec].addr, vec);
+	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
+		iosapic_eoi(rte->addr, vec);
 }
 
 #define iosapic_shutdown_level_irq	mask_irq
@@ -423,6 +468,34 @@ iosapic_version (char __iomem *addr)
 	return iosapic_read(addr, IOSAPIC_VERSION);
 }
 
+static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
+{
+	int i, vector = -1, min_count = -1;
+	struct iosapic_intr_info *info;
+
+	/*
+	 * shared vectors for edge-triggered interrupts are not
+	 * supported yet
+	 */
+	if (trigger == IOSAPIC_EDGE)
+		return -1;
+
+	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+		info = &iosapic_intr_info[i];
+		if (info->trigger == trigger && info->polarity == pol &&
+		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
+			if (min_count == -1 || info->count < min_count) {
+				vector = i;
+				min_count = info->count;
+			}
+		}
+	}
+	if (vector < 0)
+		panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+
+	return vector;
+}
+
 /*
  * if the given vector is already owned by other,
  *  assign a new vector for the other and make the vector available
@@ -432,19 +505,63 @@ iosapic_reassign_vector (int vector)
 {
 	int new_vector;
 
-	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)
-	{
+	if (!list_empty(&iosapic_intr_info[vector].rtes)) {
 		new_vector = assign_irq_vector(AUTO_ASSIGN);
 		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
 		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
 		       sizeof(struct iosapic_intr_info));
+		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
+		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
 		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
-		iosapic_intr_info[vector].rte_index = -1;
+		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 	}
 }
 
+static struct iosapic_rte_info *iosapic_alloc_rte (void)
+{
+	int i;
+	struct iosapic_rte_info *rte;
+	int preallocated = 0;
+
+	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
+		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
+		if (!rte)
+			return NULL;
+		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
+			list_add(&rte->rte_list, &free_rte_list);
+	}
+
+	if (!list_empty(&free_rte_list)) {
+		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
+		list_del(&rte->rte_list);
+		preallocated++;
+	} else {
+		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
+		if (!rte)
+			return NULL;
+	}
+
+	memset(rte, 0, sizeof(struct iosapic_rte_info));
+	if (preallocated)
+		rte->flags |= RTE_PREALLOCATED;
+
+	return rte;
+}
+
+static void iosapic_free_rte (struct iosapic_rte_info *rte)
+{
+	if (rte->flags & RTE_PREALLOCATED)
+		list_add_tail(&rte->rte_list, &free_rte_list);
+	else
+		kfree(rte);
+}
+
+static inline int vector_is_shared (int vector)
+{
+	return (iosapic_intr_info[vector].count > 1);
+}
+
 static void
 register_intr (unsigned int gsi, int vector, unsigned char delivery,
 	       unsigned long polarity, unsigned long trigger)
@@ -455,6 +572,7 @@ register_intr (unsigned int gsi, int vec
 	int index;
 	unsigned long gsi_base;
 	void __iomem *iosapic_address;
+	struct iosapic_rte_info *rte;
 
 	index = find_iosapic(gsi);
 	if (index < 0) {
@@ -465,14 +583,33 @@ register_intr (unsigned int gsi, int vec
 	iosapic_address = iosapic_lists[index].addr;
 	gsi_base = iosapic_lists[index].gsi_base;
 
-	rte_index = gsi - gsi_base;
-	iosapic_intr_info[vector].rte_index = rte_index;
+	rte = gsi_vector_to_rte(gsi, vector);
+	if (!rte) {
+		rte = iosapic_alloc_rte();
+		if (!rte) {
+			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+			return;
+		}
+
+		rte_index = gsi - gsi_base;
+		rte->rte_index	= rte_index;
+		rte->addr	= iosapic_address;
+		rte->gsi_base	= gsi_base;
+		rte->refcnt++;
+		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
+		iosapic_intr_info[vector].count++;
+	}
+	else if (vector_is_shared(vector)) {
+		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
+		if (info->trigger != trigger || info->polarity != polarity) {
+			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
+			return;
+		}
+	}
+
 	iosapic_intr_info[vector].polarity = polarity;
 	iosapic_intr_info[vector].dmode    = delivery;
-	iosapic_intr_info[vector].addr     = iosapic_address;
-	iosapic_intr_info[vector].gsi_base = gsi_base;
 	iosapic_intr_info[vector].trigger  = trigger;
-	iosapic_intr_info[vector].refcnt++;
 
 	if (trigger == IOSAPIC_EDGE)
 		irq_type = &irq_type_iosapic_edge;
@@ -495,18 +632,25 @@ get_target_cpu (unsigned int gsi, int ve
 	static int cpu = -1;
 
 	/*
+	 * In case of vector shared by multiple RTEs, all RTEs that
+	 * share the vector need to use the same destination CPU.
+	 */
+	if (!list_empty(&iosapic_intr_info[vector].rtes))
+		return iosapic_intr_info[vector].dest;
+
+	/*
 	 * If the platform supports redirection via XTP, let it
 	 * distribute interrupts.
 	 */
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
-		return hard_smp_processor_id();
+		return cpu_physical_id(smp_processor_id());
 
 	/*
 	 * Some interrupts (ACPI SCI, for instance) are registered
 	 * before the BSP is marked as online.
 	 */
 	if (!cpu_online(smp_processor_id()))
-		return hard_smp_processor_id();
+		return cpu_physical_id(smp_processor_id());
 
 #ifdef CONFIG_NUMA
 	{
@@ -553,7 +697,7 @@ skip_numa_setup:
 
 	return cpu_physical_id(cpu);
 #else
-	return hard_smp_processor_id();
+	return cpu_physical_id(smp_processor_id());
 #endif
 }
 
@@ -566,10 +710,12 @@ int
 iosapic_register_intr (unsigned int gsi,
 		       unsigned long polarity, unsigned long trigger)
 {
-	int vector;
+	int vector, mask = 1;
 	unsigned int dest;
 	unsigned long flags;
-
+	struct iosapic_rte_info *rte;
+	u32 low32;
+again:
 	/*
 	 * If this GSI has already been registered (i.e., it's a
 	 * shared interrupt, or we lost a race to register it),
@@ -579,19 +725,45 @@ iosapic_register_intr (unsigned int gsi,
 	{
 		vector = gsi_to_vector(gsi);
 		if (vector > 0) {
-			iosapic_intr_info[vector].refcnt++;
+			rte = gsi_vector_to_rte(gsi, vector);
+			rte->refcnt++;
 			spin_unlock_irqrestore(&iosapic_lock, flags);
 			return vector;
 		}
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+
+	/* If vector is running out, we try to find a sharable vector */
+	vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
+	if (vector < 0)
+		vector = iosapic_find_sharable_vector(trigger, polarity);
+
+	spin_lock_irqsave(&irq_descp(vector)->lock, flags);
+	spin_lock(&iosapic_lock);
+	{
+		if (gsi_to_vector(gsi) > 0) {
+			if (list_empty(&iosapic_intr_info[vector].rtes))
+				free_irq_vector(vector);
+			spin_unlock(&iosapic_lock);
+			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			goto again;
+		}
 
-		vector = assign_irq_vector(AUTO_ASSIGN);
 		dest = get_target_cpu(gsi, vector);
 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-			polarity, trigger);
+			      polarity, trigger);
 
-		set_rte(vector, dest, 1);
+		/*
+		 * If the vector is shared and already unmasked for
+		 * other interrupt sources, don't mask it.
+		 */
+		low32 = iosapic_intr_info[vector].low32;
+		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
+			mask = 0;
+		set_rte(gsi, vector, dest, mask);
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock(&iosapic_lock);
+	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
 
 	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
 	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -608,8 +780,10 @@ iosapic_unregister_intr (unsigned int gs
 	unsigned long flags;
 	int irq, vector;
 	irq_desc_t *idesc;
-	int rte_index;
+	u32 low32;
 	unsigned long trigger, polarity;
+	unsigned int dest;
+	struct iosapic_rte_info *rte;
 
 	/*
 	 * If the irq associated with the gsi is not found,
@@ -628,54 +802,56 @@ iosapic_unregister_intr (unsigned int gs
 	spin_lock_irqsave(&idesc->lock, flags);
 	spin_lock(&iosapic_lock);
 	{
-		rte_index = iosapic_intr_info[vector].rte_index;
-		if (rte_index < 0) {
-			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&idesc->lock, flags);
+		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
 			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
 			WARN_ON(1);
-			return;
+			goto out;
 		}
 
-		if (--iosapic_intr_info[vector].refcnt > 0) {
-			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&idesc->lock, flags);
-			return;
-		}
+		if (--rte->refcnt > 0)
+			goto out;
 
-		/*
-		 * If interrupt handlers still exist on the irq
-		 * associated with the gsi, don't unregister the
-		 * interrupt.
-		 */
-		if (idesc->action) {
-			iosapic_intr_info[vector].refcnt++;
-			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&idesc->lock, flags);
-			printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq);
-			return;
-		}
+		/* Mask the interrupt */
+		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
+		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
+
+		/* Remove the rte entry from the list */
+		list_del(&rte->rte_list);
+		iosapic_intr_info[vector].count--;
+		iosapic_free_rte(rte);
 
-		/* Clear the interrupt controller descriptor. */
-		idesc->handler = &no_irq_type;
-
-		trigger  = iosapic_intr_info[vector].trigger;
+		trigger	 = iosapic_intr_info[vector].trigger;
 		polarity = iosapic_intr_info[vector].polarity;
+		dest     = iosapic_intr_info[vector].dest;
+		printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+		       cpu_logical_id(dest), dest, vector);
+
+		if (list_empty(&iosapic_intr_info[vector].rtes)) {
+			/* Sanity check */
+			BUG_ON(iosapic_intr_info[vector].count);
+
+			/* Clear the interrupt controller descriptor */
+			idesc->handler = &no_irq_type;
+
+			/* Clear the interrupt information */
+			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
+			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+
+			if (idesc->action) {
+				printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
+				WARN_ON(1);
+			}
 
-		/* Clear the interrupt information. */
-		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
-		iosapic_intr_info[vector].rte_index = -1;	/* mark as unused */
+			/* Free the interrupt vector */
+			free_irq_vector(vector);
+		}
 	}
+ out:
 	spin_unlock(&iosapic_lock);
 	spin_unlock_irqrestore(&idesc->lock, flags);
-
-	/* Free the interrupt vector */
-	free_irq_vector(vector);
-
-	printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n",
-	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
-	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       vector);
 }
 #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
 
@@ -725,7 +901,7 @@ iosapic_register_platform_intr (u32 int_
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 	       cpu_logical_id(dest), dest, vector);
 
-	set_rte(vector, dest, mask);
+	set_rte(gsi, vector, dest, mask);
 	return vector;
 }
 
@@ -740,7 +916,7 @@ iosapic_override_isa_irq (unsigned int i
 			  unsigned long trigger)
 {
 	int vector;
-	unsigned int dest = hard_smp_processor_id();
+	unsigned int dest = cpu_physical_id(smp_processor_id());
 
 	vector = isa_irq_to_vector(isa_irq);
 
@@ -751,7 +927,7 @@ iosapic_override_isa_irq (unsigned int i
 	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
 	    cpu_logical_id(dest), dest, vector);
 
-	set_rte(vector, dest, 1);
+	set_rte(gsi, vector, dest, 1);
 }
 
 void __init
@@ -759,8 +935,10 @@ iosapic_system_init (int system_pcat_com
 {
 	int vector;
 
-	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
-		iosapic_intr_info[vector].rte_index = -1;	/* mark as unused */
+	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
+		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
+	}
 
 	pcat_compat = system_pcat_compat;
 	if (pcat_compat) {
@@ -826,3 +1004,10 @@ map_iosapic_to_node(unsigned int gsi_bas
 	return;
 }
 #endif
+
+static int __init iosapic_enable_kmalloc (void)
+{
+	iosapic_kmalloc_ok = 1;
+	return 0;
+}
+core_initcall (iosapic_enable_kmalloc);
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -94,12 +94,20 @@ skip:
 /*
  * This is updated when the user sets irq affinity via /proc
  */
-cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
+static cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
 static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)];
 
-static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
 static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
 
+/*
+ * Arch specific routine for deferred write to iosapic rte to reprogram
+ * intr destination.
+ */
+void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+{
+	pending_irq_cpumask[irq] = mask_val;
+}
+
 void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
 {
 	cpumask_t mask = CPU_MASK_NONE;
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -63,20 +63,30 @@ EXPORT_SYMBOL(isa_irq_to_vector_map);
 static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
 
 int
-assign_irq_vector (int irq)
+assign_irq_vector_nopanic (int irq)
 {
 	int pos, vector;
  again:
 	pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
 	vector = IA64_FIRST_DEVICE_VECTOR + pos;
 	if (vector > IA64_LAST_DEVICE_VECTOR)
-		/* XXX could look for sharable vectors instead of panic'ing... */
-		panic("assign_irq_vector: out of interrupt vectors!");
+		return -1;
 	if (test_and_set_bit(pos, ia64_vector_mask))
 		goto again;
 	return vector;
 }
 
+int
+assign_irq_vector (int irq)
+{
+	int vector = assign_irq_vector_nopanic(irq);
+
+	if (vector < 0)
+		panic("assign_irq_vector: out of interrupt vectors!");
+
+	return vector;
+}
+
 void
 free_irq_vector (int vector)
 {
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -957,6 +957,8 @@ END(ia64_syscall_setup)
 	 * element, followed by the arguments.
 	 */
 ENTRY(dispatch_illegal_op_fault)
+	.prologue
+	.body
 	SAVE_MIN_WITH_COVER
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
@@ -969,6 +971,7 @@ ENTRY(dispatch_illegal_op_fault)
 	mov out0=ar.ec
 	;;
 	SAVE_REST
+	PT_REGS_UNWIND_INFO(0)
 	;;
 	br.call.sptk.many rp=ia64_illegal_op_fault
 .ret0:	;;
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -1103,8 +1103,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi
 	return IRQ_HANDLED;
 }
 
-#endif /* CONFIG_ACPI */
-
 /*
  *  ia64_mca_cpe_poll
  *
@@ -1122,6 +1120,8 @@ ia64_mca_cpe_poll (unsigned long dummy)
 	platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
+#endif /* CONFIG_ACPI */
+
 /*
  * C portion of the OS INIT handler
  *
@@ -1390,8 +1390,7 @@ ia64_mca_init(void)
 	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
 
 #ifdef CONFIG_ACPI
-	/* Setup the CPEI/P vector and handler */
-	cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
+	/* Setup the CPEI/P handler */
 	register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
 #endif
 
@@ -1436,6 +1435,7 @@ ia64_mca_late_init(void)
 
 #ifdef CONFIG_ACPI
 	/* Setup the CPEI/P vector and handler */
+	cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
 	init_timer(&cpe_poll_timer);
 	cpe_poll_timer.function = ia64_mca_cpe_poll;
 
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -110,46 +110,19 @@
 	.global ia64_os_mca_dispatch_end
 	.global ia64_sal_to_os_handoff_state
 	.global	ia64_os_to_sal_handoff_state
+	.global ia64_do_tlb_purge
 
 	.text
 	.align 16
 
-ia64_os_mca_dispatch:
-
-	// Serialize all MCA processing
-	mov	r3=1;;
-	LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
-ia64_os_mca_spin:
-	xchg8	r4=[r2],r3;;
-	cmp.ne	p6,p0=r4,r0
-(p6)	br ia64_os_mca_spin
-
-	// Save the SAL to OS MCA handoff state as defined
-	// by SAL SPEC 3.0
-	// NOTE : The order in which the state gets saved
-	//	  is dependent on the way the C-structure
-	//	  for ia64_mca_sal_to_os_state_t has been
-	//	  defined in include/asm/mca.h
-	SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
-	;;
-
-	// LOG PROCESSOR STATE INFO FROM HERE ON..
-begin_os_mca_dump:
-	br	ia64_os_mca_proc_state_dump;;
-
-ia64_os_mca_done_dump:
-
-	LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56)
-	;;
-	ld8 r18=[r16]		// Get processor state parameter on existing PALE_CHECK.
-	;;
-	tbit.nz p6,p7=r18,60
-(p7)	br.spnt done_tlb_purge_and_reload
-
-	// The following code purges TC and TR entries. Then reload all TC entries.
-	// Purge percpu data TC entries.
-begin_tlb_purge_and_reload:
+/*
+ * Just the TLB purge part is moved to a separate function
+ * so we can re-use the code for cpu hotplug code as well
+ * Caller should now setup b1, so we can branch once the
+ * tlb flush is complete.
+ */
 
+ia64_do_tlb_purge:
 #define O(member)	IA64_CPUINFO_##member##_OFFSET
 
 	GET_THIS_PADDR(r2, cpu_info)	// load phys addr of cpu_info into r2
@@ -230,6 +203,51 @@ begin_tlb_purge_and_reload:
 	;;
 	srlz.i
 	;;
+	// Now branch away to caller.
+	br.sptk.many b1
+	;;
+
+ia64_os_mca_dispatch:
+
+	// Serialize all MCA processing
+	mov	r3=1;;
+	LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
+ia64_os_mca_spin:
+	xchg8	r4=[r2],r3;;
+	cmp.ne	p6,p0=r4,r0
+(p6)	br ia64_os_mca_spin
+
+	// Save the SAL to OS MCA handoff state as defined
+	// by SAL SPEC 3.0
+	// NOTE : The order in which the state gets saved
+	//	  is dependent on the way the C-structure
+	//	  for ia64_mca_sal_to_os_state_t has been
+	//	  defined in include/asm/mca.h
+	SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
+	;;
+
+	// LOG PROCESSOR STATE INFO FROM HERE ON..
+begin_os_mca_dump:
+	br	ia64_os_mca_proc_state_dump;;
+
+ia64_os_mca_done_dump:
+
+	LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56)
+	;;
+	ld8 r18=[r16]		// Get processor state parameter on existing PALE_CHECK.
+	;;
+	tbit.nz p6,p7=r18,60
+(p7)	br.spnt done_tlb_purge_and_reload
+
+	// The following code purges TC and TR entries. Then reload all TC entries.
+	// Purge percpu data TC entries.
+begin_tlb_purge_and_reload:
+	movl r18=ia64_reload_tr;;
+	LOAD_PHYSICAL(p0,r18,ia64_reload_tr);;
+	mov b1=r18;;
+	br.sptk.many ia64_do_tlb_purge;;
+
+ia64_reload_tr:
 	// Finally reload the TR registers.
 	// 1. Reload DTR/ITR registers for kernel.
 	mov r18=KERNEL_TR_PAGE_SHIFT<<2
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -132,8 +132,7 @@ mca_handler_bh(unsigned long paddr)
 	spin_unlock(&mca_bh_lock);
 
 	/* This process is about to be killed itself */
-	force_sig(SIGKILL, current);
-	schedule();
+	do_exit(SIGKILL);
 }
 
 /**
@@ -439,6 +438,7 @@ recover_from_read_error(slidx_table_t *s
 			psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
 			psr2->cpl = 0;
 			psr2->ri  = 0;
+			psr2->i  = 0;
 
 			return 1;
 		}
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S
--- a/arch/ia64/kernel/mca_drv_asm.S
+++ b/arch/ia64/kernel/mca_drv_asm.S
@@ -10,6 +10,7 @@
 
 #include <asm/asmmacro.h>
 #include <asm/processor.h>
+#include <asm/ptrace.h>
 
 GLOBAL_ENTRY(mca_handler_bhhook)
 	invala						// clear RSE ?
@@ -20,12 +21,21 @@ GLOBAL_ENTRY(mca_handler_bhhook)
 	;;						
 	alloc		r16=ar.pfs,0,2,1,0		// make a new frame
 	;;
+	mov		ar.rsc=0
+	;;
 	mov		r13=IA64_KR(CURRENT)		// current task pointer
 	;;
-	adds		r12=IA64_TASK_THREAD_KSP_OFFSET,r13
+	mov		r2=r13
+	;;
+	addl		r22=IA64_RBS_OFFSET,r2
+	;;
+	mov		ar.bspstore=r22
 	;;
-	ld8		r12=[r12]			// stack pointer
+	addl		sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2
 	;;
+	adds		r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
+	;;
+	st1		[r2]=r0				// clear current->thread.on_ustack flag
 	mov		loc0=r16
 	movl		loc1=mca_handler_bh		// recovery C function
 	;;
@@ -34,7 +44,9 @@ GLOBAL_ENTRY(mca_handler_bhhook)
 	;;
 	mov		loc1=rp
 	;;
-	br.call.sptk.many    rp=b6			// not return ...
+	ssm		psr.i
+	;;
+	br.call.sptk.many    rp=b6			// does not return ...
 	;;
 	mov		ar.pfs=loc0
 	mov 		rp=loc1
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -26,7 +26,7 @@
 (pKStk) addl r1=-IA64_PT_REGS_SIZE,r1;			/* if in kernel mode, use sp (r12) */	\
 	;;											\
 (pUStk)	mov r18=ar.bsp;										\
-(pUStk)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		\
+(pUStk)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */
 
 #define MINSTATE_END_SAVE_MIN_VIRT								\
 	bsw.1;			/* switch back to bank 1 (must be last in insn group) */	\
@@ -41,7 +41,7 @@
 (pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;;							\
 (pKStk) ld8 r3 = [r3];;										\
 (pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;;						\
-(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3;						\
+(pKStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3;						\
 (pUStk)	mov ar.rsc=0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
 (pUStk)	addl r22=IA64_RBS_OFFSET,r1;		/* compute base of register backing store */	\
 	;;											\
@@ -50,7 +50,6 @@
 (pUStk)	mov r23=ar.bspstore;				/* save ar.bspstore */			\
 (pUStk)	dep r22=-1,r22,61,3;			/* compute kernel virtual addr of RBS */	\
 	;;											\
-(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1;		/* if in kernel mode, use sp (r12) */		\
 (pUStk)	mov ar.bspstore=r22;			/* switch to kernel RBS */			\
 	;;											\
 (pUStk)	mov r18=ar.bsp;										\
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -825,14 +825,16 @@ apply_relocate_add (Elf64_Shdr *sechdrs,
 		 * XXX Should have an arch-hook for running this after final section
 		 *     addresses have been selected...
 		 */
-		/* See if gp can cover the entire core module:  */
-		uint64_t gp = (uint64_t) mod->module_core + MAX_LTOFF / 2;
-		if (mod->core_size >= MAX_LTOFF)
+		uint64_t gp;
+		if (mod->core_size > MAX_LTOFF)
 			/*
 			 * This takes advantage of fact that SHF_ARCH_SMALL gets allocated
 			 * at the end of the module.
 			 */
-			gp = (uint64_t) mod->module_core + mod->core_size - MAX_LTOFF / 2;
+			gp = mod->core_size - MAX_LTOFF / 2;
+		else
+			gp = mod->core_size / 2;
+		gp = (uint64_t) mod->module_core + ((gp + 7) & -8);
 		mod->arch.gp = gp;
 		DEBUGP("%s: placing gp at 0x%lx\n", __FUNCTION__, gp);
 	}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -11,7 +11,7 @@
  * Version Perfmon-2.x is a rewrite of perfmon-1.x
  * by Stephane Eranian, Hewlett Packard Co.
  *
- * Copyright (C) 1999-2003, 2005  Hewlett Packard Co
+ * Copyright (C) 1999-2005  Hewlett Packard Co
  *               Stephane Eranian <eranian@hpl.hp.com>
  *               David Mosberger-Tang <davidm@hpl.hp.com>
  *
@@ -480,14 +480,6 @@ typedef struct {
 #define PFM_CMD_ARG_MANY	-1 /* cannot be zero */
 
 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 */
-	int	expert_mode;	/* turn on/off value checking */
-	int 	debug_pfm_read;
-} pfm_sysctl_t;
-
-typedef struct {
 	unsigned long pfm_spurious_ovfl_intr_count;	/* keep track of spurious ovfl interrupts */
 	unsigned long pfm_replay_ovfl_intr_count;	/* keep track of replayed ovfl interrupts */
 	unsigned long pfm_ovfl_intr_count; 		/* keep track of ovfl interrupts */
@@ -505,6 +497,9 @@ typedef struct {
 static pfm_stats_t		pfm_stats[NR_CPUS];
 static pfm_session_t		pfm_sessions;	/* global sessions information */
 
+static spinlock_t pfm_alt_install_check = SPIN_LOCK_UNLOCKED;
+static pfm_intr_handler_desc_t  *pfm_alt_intr_handler;
+
 static struct proc_dir_entry 	*perfmon_dir;
 static pfm_uuid_t		pfm_null_uuid = {0,};
 
@@ -514,8 +509,8 @@ static LIST_HEAD(pfm_buffer_fmt_list);
 static pmu_config_t		*pmu_conf;
 
 /* sysctl() controls */
-static pfm_sysctl_t pfm_sysctl;
-int pfm_debug_var;
+pfm_sysctl_t pfm_sysctl;
+EXPORT_SYMBOL(pfm_sysctl);
 
 static ctl_table pfm_ctl_table[]={
 	{1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
@@ -614,6 +609,7 @@ DEFINE_PER_CPU(unsigned long, pfm_syst_i
 DEFINE_PER_CPU(struct task_struct *, pmu_owner);
 DEFINE_PER_CPU(pfm_context_t  *, pmu_ctx);
 DEFINE_PER_CPU(unsigned long, pmu_activation_number);
+EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info);
 
 
 /* forward declaration */
@@ -1273,6 +1269,8 @@ out:
 }
 EXPORT_SYMBOL(pfm_unregister_buffer_fmt);
 
+extern void update_pal_halt_status(int);
+
 static int
 pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
 {
@@ -1319,6 +1317,11 @@ pfm_reserve_session(struct task_struct *
 		is_syswide,
 		cpu));
 
+	/*
+	 * disable default_idle() to go to PAL_HALT
+	 */
+	update_pal_halt_status(0);
+
 	UNLOCK_PFS(flags);
 
 	return 0;
@@ -1326,7 +1329,7 @@ pfm_reserve_session(struct task_struct *
 error_conflict:
 	DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n",
   		pfm_sessions.pfs_sys_session[cpu]->pid,
-		smp_processor_id()));
+		cpu));
 abort:
 	UNLOCK_PFS(flags);
 
@@ -1374,6 +1377,12 @@ pfm_unreserve_session(pfm_context_t *ctx
 		is_syswide,
 		cpu));
 
+	/*
+	 * if possible, enable default_idle() to go into PAL_HALT
+	 */
+	if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0)
+		update_pal_halt_status(1);
+
 	UNLOCK_PFS(flags);
 
 	return 0;
@@ -1576,7 +1585,7 @@ pfm_read(struct file *filp, char __user 
 		goto abort_locked;
 	}
 
-	DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type));
+	DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type));
 
 	ret = -EFAULT;
   	if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t);
@@ -3695,8 +3704,6 @@ pfm_debug(pfm_context_t *ctx, void *arg,
 
 	pfm_sysctl.debug = m == 0 ? 0 : 1;
 
-	pfm_debug_var = pfm_sysctl.debug;
-
 	printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off");
 
 	if (m == 0) {
@@ -4212,7 +4219,7 @@ pfm_context_load(pfm_context_t *ctx, voi
 		DPRINT(("cannot load to [%d], invalid ctx_state=%d\n",
 			req->load_pid,
 			ctx->ctx_state));
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg));
@@ -4714,16 +4721,26 @@ recheck:
 	if (task == current || ctx->ctx_fl_system) return 0;
 
 	/*
-	 * if context is UNLOADED we are safe to go
-	 */
-	if (state == PFM_CTX_UNLOADED) return 0;
-
-	/*
-	 * no command can operate on a zombie context
+	 * we are monitoring another thread
 	 */
-	if (state == PFM_CTX_ZOMBIE) {
-		DPRINT(("cmd %d state zombie cannot operate on context\n", cmd));
-		return -EINVAL;
+	switch(state) {
+		case PFM_CTX_UNLOADED:
+			/*
+			 * if context is UNLOADED we are safe to go
+			 */
+			return 0;
+		case PFM_CTX_ZOMBIE:
+			/*
+			 * no command can operate on a zombie context
+			 */
+			DPRINT(("cmd %d state zombie cannot operate on context\n", cmd));
+			return -EINVAL;
+		case PFM_CTX_MASKED:
+			/*
+			 * PMU state has been saved to software even though
+			 * the thread may still be running.
+			 */
+			if (cmd != PFM_UNLOAD_CONTEXT) return 0;
 	}
 
 	/*
@@ -4996,13 +5013,21 @@ pfm_context_force_terminate(pfm_context_
 }
 
 static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds);
-
+ /*
+  * pfm_handle_work() can be called with interrupts enabled
+  * (TIF_NEED_RESCHED) or disabled. The down_interruptible
+  * call may sleep, therefore we must re-enable interrupts
+  * to avoid deadlocks. It is safe to do so because this function
+  * is called ONLY when returning to user level (PUStk=1), in which case
+  * there is no risk of kernel stack overflow due to deep
+  * interrupt nesting.
+  */
 void
 pfm_handle_work(void)
 {
 	pfm_context_t *ctx;
 	struct pt_regs *regs;
-	unsigned long flags;
+	unsigned long flags, dummy_flags;
 	unsigned long ovfl_regs;
 	unsigned int reason;
 	int ret;
@@ -5039,18 +5064,15 @@ pfm_handle_work(void)
 	//if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking;
 	if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking;
 
+	/*
+	 * restore interrupt mask to what it was on entry.
+	 * Could be enabled/diasbled.
+	 */
 	UNPROTECT_CTX(ctx, flags);
 
-	 /*
-	  * pfm_handle_work() is currently called with interrupts disabled.
-	  * The down_interruptible call may sleep, therefore we
-	  * must re-enable interrupts to avoid deadlocks. It is
-	  * safe to do so because this function is called ONLY
-	  * when returning to user level (PUStk=1), in which case
-	  * there is no risk of kernel stack overflow due to deep
-	  * interrupt nesting.
-	  */
-	BUG_ON(flags & IA64_PSR_I);
+	/*
+	 * force interrupt enable because of down_interruptible()
+	 */
 	local_irq_enable();
 
 	DPRINT(("before block sleeping\n"));
@@ -5064,12 +5086,12 @@ pfm_handle_work(void)
 	DPRINT(("after block sleeping ret=%d\n", ret));
 
 	/*
-	 * disable interrupts to restore state we had upon entering
-	 * this function
+	 * lock context and mask interrupts again
+	 * We save flags into a dummy because we may have
+	 * altered interrupts mask compared to entry in this
+	 * function.
 	 */
-	local_irq_disable();
-
-	PROTECT_CTX(ctx, flags);
+	PROTECT_CTX(ctx, dummy_flags);
 
 	/*
 	 * we need to read the ovfl_regs only after wake-up
@@ -5095,7 +5117,9 @@ skip_blocking:
 	ctx->ctx_ovfl_regs[0] = 0UL;
 
 nothing_to_do:
-
+	/*
+	 * restore flags as they were upon entry
+	 */
 	UNPROTECT_CTX(ctx, flags);
 }
 
@@ -5535,26 +5559,32 @@ pfm_interrupt_handler(int irq, void *arg
 	int ret;
 
 	this_cpu = get_cpu();
-	min      = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min;
-	max      = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max;
+	if (likely(!pfm_alt_intr_handler)) {
+		min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min;
+		max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max;
 
-	start_cycles = ia64_get_itc();
+		start_cycles = ia64_get_itc();
 
-	ret = pfm_do_interrupt_handler(irq, arg, regs);
+		ret = pfm_do_interrupt_handler(irq, arg, regs);
 
-	total_cycles = ia64_get_itc();
+		total_cycles = ia64_get_itc();
 
-	/*
-	 * don't measure spurious interrupts
-	 */
-	if (likely(ret == 0)) {
-		total_cycles -= start_cycles;
+		/*
+		 * don't measure spurious interrupts
+		 */
+		if (likely(ret == 0)) {
+			total_cycles -= start_cycles;
 
-		if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles;
-		if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles;
+			if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles;
+			if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles;
 
-		pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles;
+			pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles;
+		}
+	}
+	else {
+		(*pfm_alt_intr_handler->handler)(irq, arg, regs);
 	}
+
 	put_cpu_no_resched();
 	return IRQ_HANDLED;
 }
@@ -6405,6 +6435,141 @@ static struct irqaction perfmon_irqactio
 	.name    = "perfmon"
 };
 
+static void
+pfm_alt_save_pmu_state(void *data)
+{
+	struct pt_regs *regs;
+
+	regs = ia64_task_regs(current);
+
+	DPRINT(("called\n"));
+
+	/*
+	 * should not be necessary but
+	 * let's take not risk
+	 */
+	pfm_clear_psr_up();
+	pfm_clear_psr_pp();
+	ia64_psr(regs)->pp = 0;
+
+	/*
+	 * This call is required
+	 * May cause a spurious interrupt on some processors
+	 */
+	pfm_freeze_pmu();
+
+	ia64_srlz_d();
+}
+
+void
+pfm_alt_restore_pmu_state(void *data)
+{
+	struct pt_regs *regs;
+
+	regs = ia64_task_regs(current);
+
+	DPRINT(("called\n"));
+
+	/*
+	 * put PMU back in state expected
+	 * by perfmon
+	 */
+	pfm_clear_psr_up();
+	pfm_clear_psr_pp();
+	ia64_psr(regs)->pp = 0;
+
+	/*
+	 * perfmon runs with PMU unfrozen at all times
+	 */
+	pfm_unfreeze_pmu();
+
+	ia64_srlz_d();
+}
+
+int
+pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
+{
+	int ret, i;
+	int reserve_cpu;
+
+	/* some sanity checks */
+	if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
+
+	/* do the easy test first */
+	if (pfm_alt_intr_handler) return -EBUSY;
+
+	/* one at a time in the install or remove, just fail the others */
+	if (!spin_trylock(&pfm_alt_install_check)) {
+		return -EBUSY;
+	}
+
+	/* reserve our session */
+	for_each_online_cpu(reserve_cpu) {
+		ret = pfm_reserve_session(NULL, 1, reserve_cpu);
+		if (ret) goto cleanup_reserve;
+	}
+
+	/* save the current system wide pmu states */
+	ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1);
+	if (ret) {
+		DPRINT(("on_each_cpu() failed: %d\n", ret));
+		goto cleanup_reserve;
+	}
+
+	/* officially change to the alternate interrupt handler */
+	pfm_alt_intr_handler = hdl;
+
+	spin_unlock(&pfm_alt_install_check);
+
+	return 0;
+
+cleanup_reserve:
+	for_each_online_cpu(i) {
+		/* don't unreserve more than we reserved */
+		if (i >= reserve_cpu) break;
+
+		pfm_unreserve_session(NULL, 1, i);
+	}
+
+	spin_unlock(&pfm_alt_install_check);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt);
+
+int
+pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
+{
+	int i;
+	int ret;
+
+	if (hdl == NULL) return -EINVAL;
+
+	/* cannot remove someone else's handler! */
+	if (pfm_alt_intr_handler != hdl) return -EINVAL;
+
+	/* one at a time in the install or remove, just fail the others */
+	if (!spin_trylock(&pfm_alt_install_check)) {
+		return -EBUSY;
+	}
+
+	pfm_alt_intr_handler = NULL;
+
+	ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1);
+	if (ret) {
+		DPRINT(("on_each_cpu() failed: %d\n", ret));
+	}
+
+	for_each_online_cpu(i) {
+		pfm_unreserve_session(NULL, 1, i);
+	}
+
+	spin_unlock(&pfm_alt_install_check);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt);
+
 /*
  * perfmon initialization routine, called from the initcall() table
  */
diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c
--- a/arch/ia64/kernel/perfmon_default_smpl.c
+++ b/arch/ia64/kernel/perfmon_default_smpl.c
@@ -20,24 +20,17 @@ MODULE_AUTHOR("Stephane Eranian <eranian
 MODULE_DESCRIPTION("perfmon default sampling format");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "debug");
-
-MODULE_PARM(debug_ovfl, "i");
-MODULE_PARM_DESC(debug_ovfl, "debug ovfl");
-
-
 #define DEFAULT_DEBUG 1
 
 #ifdef DEFAULT_DEBUG
 #define DPRINT(a) \
 	do { \
-		if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+		if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
 	} while (0)
 
 #define DPRINT_ovfl(a) \
 	do { \
-		if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+		if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
 	} while (0)
 
 #else
@@ -45,8 +38,6 @@ MODULE_PARM_DESC(debug_ovfl, "debug ovfl
 #define DPRINT_ovfl(a)
 #endif
 
-static int debug, debug_ovfl;
-
 static int
 default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
 {
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * 04/11/17 Ashok Raj	<ashok.raj@intel.com> Added CPU Hotplug Support
  */
 #define __KERNEL_SYSCALLS__	/* see <asm/unistd.h> */
 #include <linux/config.h>
@@ -49,7 +50,7 @@
 #include "sigframe.h"
 
 void (*ia64_mark_idle)(int);
-static cpumask_t cpu_idle_map;
+static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
 unsigned long boot_option_idle_override = 0;
 EXPORT_SYMBOL(boot_option_idle_override);
@@ -172,7 +173,9 @@ do_notify_resume_user (sigset_t *oldset,
 		ia64_do_signal(oldset, scr, in_syscall);
 }
 
-static int pal_halt = 1;
+static int pal_halt        = 1;
+static int can_do_pal_halt = 1;
+
 static int __init nohalt_setup(char * str)
 {
 	pal_halt = 0;
@@ -180,16 +183,20 @@ static int __init nohalt_setup(char * st
 }
 __setup("nohalt", nohalt_setup);
 
+void
+update_pal_halt_status(int status)
+{
+	can_do_pal_halt = pal_halt && status;
+}
+
 /*
  * We use this if we don't have any better idle routine..
  */
 void
 default_idle (void)
 {
-	unsigned long pmu_active = ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_PP | IA64_PSR_UP);
-
 	while (!need_resched())
-		if (pal_halt && !pmu_active)
+		if (can_do_pal_halt)
 			safe_halt();
 		else
 			cpu_relax();
@@ -200,27 +207,20 @@ default_idle (void)
 static inline void play_dead(void)
 {
 	extern void ia64_cpu_local_tick (void);
+	unsigned int this_cpu = smp_processor_id();
+
 	/* Ack it */
 	__get_cpu_var(cpu_state) = CPU_DEAD;
 
-	/* We shouldn't have to disable interrupts while dead, but
-	 * some interrupts just don't seem to go away, and this makes
-	 * it "work" for testing purposes. */
 	max_xtp();
 	local_irq_disable();
-	/* Death loop */
-	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
-		cpu_relax();
-
+	idle_task_exit();
+	ia64_jump_to_sal(&sal_boot_rendez_state[this_cpu]);
 	/*
-	 * Enable timer interrupts from now on
-	 * Not required if we put processor in SAL_BOOT_RENDEZ mode.
+	 * The above is a point of no-return, the processor is
+	 * expected to be in SAL loop now.
 	 */
-	local_flush_tlb_all();
-	cpu_set(smp_processor_id(), cpu_online_map);
-	wmb();
-	ia64_cpu_local_tick ();
-	local_irq_enable();
+	BUG();
 }
 #else
 static inline void play_dead(void)
@@ -229,20 +229,31 @@ static inline void play_dead(void)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-
 void cpu_idle_wait(void)
 {
-        int cpu;
-        cpumask_t map;
+	unsigned int cpu, this_cpu = get_cpu();
+	cpumask_t map;
+
+	set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
+	put_cpu();
 
-        for_each_online_cpu(cpu)
-                cpu_set(cpu, cpu_idle_map);
+	cpus_clear(map);
+	for_each_online_cpu(cpu) {
+		per_cpu(cpu_idle_state, cpu) = 1;
+		cpu_set(cpu, map);
+	}
 
-        wmb();
-        do {
-                ssleep(1);
-                cpus_and(map, cpu_idle_map, cpu_online_map);
-        } while (!cpus_empty(map));
+	__get_cpu_var(cpu_idle_state) = 0;
+
+	wmb();
+	do {
+		ssleep(1);
+		for_each_online_cpu(cpu) {
+			if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+				cpu_clear(cpu, map);
+		}
+		cpus_and(map, map, cpu_online_map);
+	} while (!cpus_empty(map));
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
@@ -250,7 +261,6 @@ void __attribute__((noreturn))
 cpu_idle (void)
 {
 	void (*mark_idle)(int) = ia64_mark_idle;
-	int cpu = smp_processor_id();
 
 	/* endless idle loop with no priority at all */
 	while (1) {
@@ -261,12 +271,13 @@ cpu_idle (void)
 		while (!need_resched()) {
 			void (*idle)(void);
 
+			if (__get_cpu_var(cpu_idle_state))
+				__get_cpu_var(cpu_idle_state) = 0;
+
+			rmb();
 			if (mark_idle)
 				(*mark_idle)(1);
 
-			if (cpu_isset(cpu, cpu_idle_map))
-				cpu_clear(cpu, cpu_idle_map);
-			rmb();
 			idle = pm_idle;
 			if (!idle)
 				idle = default_idle;
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -17,6 +17,7 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
+#include <linux/signal.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -634,11 +635,17 @@ ia64_flush_fph (struct task_struct *task
 {
 	struct ia64_psr *psr = ia64_psr(ia64_task_regs(task));
 
+	/*
+	 * Prevent migrating this task while
+	 * we're fiddling with the FPU state
+	 */
+	preempt_disable();
 	if (ia64_is_local_fpu_owner(task) && psr->mfh) {
 		psr->mfh = 0;
 		task->thread.flags |= IA64_THREAD_FPH_VALID;
 		ia64_save_fpu(&task->thread.fph[0]);
 	}
+	preempt_enable();
 }
 
 /*
@@ -691,16 +698,30 @@ convert_to_non_syscall (struct task_stru
 			unsigned long cfm)
 {
 	struct unw_frame_info info, prev_info;
-	unsigned long ip, pr;
+	unsigned long ip, sp, pr;
 
 	unw_init_from_blocked_task(&info, child);
 	while (1) {
 		prev_info = info;
 		if (unw_unwind(&info) < 0)
 			return;
-		if (unw_get_rp(&info, &ip) < 0)
+
+		unw_get_sp(&info, &sp);
+		if ((long)((unsigned long)child + IA64_STK_OFFSET - sp)
+		    < IA64_PT_REGS_SIZE) {
+			dprintk("ptrace.%s: ran off the top of the kernel "
+				"stack\n", __FUNCTION__);
+			return;
+		}
+		if (unw_get_pr (&prev_info, &pr) < 0) {
+			unw_get_rp(&prev_info, &ip);
+			dprintk("ptrace.%s: failed to read "
+				"predicate register (ip=0x%lx)\n",
+				__FUNCTION__, ip);
 			return;
-		if (ip < FIXADDR_USER_END)
+		}
+		if (unw_is_intr_frame(&info)
+		    && (pr & (1UL << PRED_USER_STACK)))
 			break;
 	}
 
@@ -1074,15 +1095,12 @@ ptrace_getregs (struct task_struct *chil
 	struct ia64_fpreg fpval;
 	struct switch_stack *sw;
 	struct pt_regs *pt;
-	long ret, retval;
+	long ret, retval = 0;
 	char nat = 0;
 	int i;
 
-	retval = verify_area(VERIFY_WRITE, ppr,
-			     sizeof(struct pt_all_user_regs));
-	if (retval != 0) {
+	if (!access_ok(VERIFY_WRITE, ppr, sizeof(struct pt_all_user_regs)))
 		return -EIO;
-	}
 
 	pt = ia64_task_regs(child);
 	sw = (struct switch_stack *) (child->thread.ksp + 16);
@@ -1105,8 +1123,6 @@ ptrace_getregs (struct task_struct *chil
 	    || access_uarea(child, PT_NAT_BITS, &nat_bits, 0))
 		return -EIO;
 
-	retval = 0;
-
 	/* control regs */
 
 	retval |= __put_user(pt->cr_iip, &ppr->cr_iip);
@@ -1223,16 +1239,13 @@ ptrace_setregs (struct task_struct *chil
 	struct switch_stack *sw;
 	struct ia64_fpreg fpval;
 	struct pt_regs *pt;
-	long ret, retval;
+	long ret, retval = 0;
 	int i;
 
 	memset(&fpval, 0, sizeof(fpval));
 
-	retval = verify_area(VERIFY_READ, ppr,
-			     sizeof(struct pt_all_user_regs));
-	if (retval != 0) {
+	if (!access_ok(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs)))
 		return -EIO;
-	}
 
 	pt = ia64_task_regs(child);
 	sw = (struct switch_stack *) (child->thread.ksp + 16);
@@ -1246,8 +1259,6 @@ ptrace_setregs (struct task_struct *chil
 		return -EIO;
 	}
 
-	retval = 0;
-
 	/* control regs */
 
 	retval |= __get_user(pt->cr_iip, &ppr->cr_iip);
@@ -1491,7 +1502,7 @@ sys_ptrace (long request, pid_t pid, uns
 	      case PTRACE_CONT:
 		/* restart after signal. */
 		ret = -EIO;
-		if (data > _NSIG)
+		if (!valid_signal(data))
 			goto out_tsk;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -1530,7 +1541,7 @@ sys_ptrace (long request, pid_t pid, uns
 		/* let child execute for one instruction */
 	      case PTRACE_SINGLEBLOCK:
 		ret = -EIO;
-		if (data > _NSIG)
+		if (!valid_signal(data))
 			goto out_tsk;
 
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -1605,20 +1616,25 @@ syscall_trace_enter (long arg0, long arg
 		     long arg4, long arg5, long arg6, long arg7,
 		     struct pt_regs regs)
 {
-	long syscall;
+	if (test_thread_flag(TIF_SYSCALL_TRACE) 
+	    && (current->ptrace & PT_PTRACED))
+		syscall_trace();
 
 	if (unlikely(current->audit_context)) {
-		if (IS_IA32_PROCESS(&regs))
+		long syscall;
+		int arch;
+
+		if (IS_IA32_PROCESS(&regs)) {
 			syscall = regs.r1;
-		else
+			arch = AUDIT_ARCH_I386;
+		} else {
 			syscall = regs.r15;
+			arch = AUDIT_ARCH_IA64;
+		}
 
-		audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3);
+		audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3);
 	}
 
-	if (test_thread_flag(TIF_SYSCALL_TRACE)
-	    && (current->ptrace & PT_PTRACED))
-		syscall_trace();
 }
 
 /* "asmlinkage" so the input arguments are preserved... */
@@ -1629,7 +1645,7 @@ syscall_trace_leave (long arg0, long arg
 		     struct pt_regs regs)
 {
 	if (unlikely(current->audit_context))
-		audit_syscall_exit(current, regs.r8);
+		audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8);
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)
 	    && (current->ptrace & PT_PTRACED))
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -4,10 +4,15 @@
  * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *	Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
+ * Copyright (C) 2000, 2004 Intel Corp
+ * 	Rohit Seth <rohit.seth@intel.com>
+ * 	Suresh Siddha <suresh.b.siddha@intel.com>
+ * 	Gordon Jin <gordon.jin@intel.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  *
+ * 12/26/04 S.Siddha, G.Jin, R.Seth
+ *			Add multi-threading and multi-core detection
  * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo().
  * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map
  * 03/31/00 R.Seth	cpu_initialized and current->processor fixes
@@ -75,8 +80,6 @@ struct io_space io_space[MAX_IO_SPACES];
 EXPORT_SYMBOL(io_space);
 unsigned int num_io_spaces;
 
-unsigned char aux_device_present = 0xaa;        /* XXX remove this when legacy I/O is gone */
-
 /*
  * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1).  This
  * mask specifies a mask of address bits that must be 0 in order for two buffers to be
@@ -298,6 +301,34 @@ mark_bsp_online (void)
 #endif
 }
 
+#ifdef CONFIG_SMP
+static void
+check_for_logical_procs (void)
+{
+	pal_logical_to_physical_t info;
+	s64 status;
+
+	status = ia64_pal_logical_to_phys(0, &info);
+	if (status == -1) {
+		printk(KERN_INFO "No logical to physical processor mapping "
+		       "available\n");
+		return;
+	}
+	if (status) {
+		printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
+		       status);
+		return;
+	}
+	/*
+	 * Total number of siblings that BSP has.  Though not all of them 
+	 * may have booted successfully. The correct number of siblings 
+	 * booted is in info.overview_num_log.
+	 */
+	smp_num_siblings = info.overview_tpc;
+	smp_num_cpucores = info.overview_cpp;
+}
+#endif
+
 void __init
 setup_arch (char **cmdline_p)
 {
@@ -358,6 +389,19 @@ setup_arch (char **cmdline_p)
 
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
+
+	cpu_set(0, cpu_sibling_map[0]);
+	cpu_set(0, cpu_core_map[0]);
+
+	check_for_logical_procs();
+	if (smp_num_cpucores > 1)
+		printk(KERN_INFO
+		       "cpu package is Multi-Core capable: number of cores=%d\n",
+		       smp_num_cpucores);
+	if (smp_num_siblings > 1)
+		printk(KERN_INFO
+		       "cpu package is Multi-Threading capable: number of siblings=%d\n",
+		       smp_num_siblings);
 #endif
 
 	cpu_init();	/* initialize the bootstrap CPU */
@@ -461,12 +505,23 @@ show_cpuinfo (struct seq_file *m, void *
 		   "cpu regs   : %u\n"
 		   "cpu MHz    : %lu.%06lu\n"
 		   "itc MHz    : %lu.%06lu\n"
-		   "BogoMIPS   : %lu.%02lu\n\n",
+		   "BogoMIPS   : %lu.%02lu\n",
 		   cpunum, c->vendor, family, c->model, c->revision, c->archrev,
 		   features, c->ppn, c->number,
 		   c->proc_freq / 1000000, c->proc_freq % 1000000,
 		   c->itc_freq / 1000000, c->itc_freq % 1000000,
 		   lpj*HZ/500000, (lpj*HZ/5000) % 100);
+#ifdef CONFIG_SMP
+	seq_printf(m, "siblings   : %u\n", c->num_log);
+	if (c->threads_per_core > 1 || c->cores_per_socket > 1)
+		seq_printf(m,
+		   	   "physical id: %u\n"
+		   	   "core id    : %u\n"
+		   	   "thread id  : %u\n",
+		   	   c->socket_id, c->core_id, c->thread_id);
+#endif
+	seq_printf(m,"\n");
+
 	return 0;
 }
 
@@ -535,6 +590,14 @@ identify_cpu (struct cpuinfo_ia64 *c)
 	memcpy(c->vendor, cpuid.field.vendor, 16);
 #ifdef CONFIG_SMP
 	c->cpu = smp_processor_id();
+
+	/* below default values will be overwritten  by identify_siblings() 
+	 * for Multi-Threading/Multi-Core capable cpu's
+	 */
+	c->threads_per_core = c->cores_per_socket = c->num_log = 1;
+	c->socket_id = -1;
+
+	identify_siblings(c);
 #endif
 	c->ppn = cpuid.field.ppn;
 	c->number = cpuid.field.number;
@@ -648,7 +711,17 @@ cpu_init (void)
 	ia64_set_kr(IA64_KR_FPU_OWNER, 0);
 
 	/*
-	 * Initialize default control register to defer all speculative faults.  The
+	 * Initialize the page-table base register to a global
+	 * directory with all zeroes.  This ensure that we can handle
+	 * TLB-misses to user address-space even before we created the
+	 * first user address-space.  This may happen, e.g., due to
+	 * aggressive use of lfetch.fault.
+	 */
+	ia64_set_kr(IA64_KR_PT_BASE, __pa(ia64_imva(empty_zero_page)));
+
+	/*
+	 * Initialize default control register to defer speculative faults except
+	 * for those arising from TLB misses, which are not deferred.  The
 	 * kernel MUST NOT depend on a particular setting of these bits (in other words,
 	 * the kernel must have recovery code for all speculative accesses).  Turn on
 	 * dcr.lc as per recommendation by the architecture team.  Most IA-32 apps
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -224,7 +224,8 @@ ia64_rt_sigreturn (struct sigscratch *sc
 	 * could be corrupted.
 	 */
 	retval = (long) &ia64_leave_kernel;
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    || test_thread_flag(TIF_SYSCALL_AUDIT))
 		/*
 		 * strace expects to be notified after sigreturn returns even though the
 		 * context to which we return may not be in the middle of a syscall.
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -227,7 +227,6 @@ smp_flush_tlb_all (void)
 {
 	on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1);
 }
-EXPORT_SYMBOL(smp_flush_tlb_all);
 
 void
 smp_flush_tlb_mm (struct mm_struct *mm)
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -1,14 +1,25 @@
 /*
  * SMP boot-related support
  *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
+ * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001, 2004-2005 Intel Corp
+ * 	Rohit Seth <rohit.seth@intel.com>
+ * 	Suresh Siddha <suresh.b.siddha@intel.com>
+ * 	Gordon Jin <gordon.jin@intel.com>
+ *	Ashok Raj  <ashok.raj@intel.com>
  *
  * 01/05/16 Rohit Seth <rohit.seth@intel.com>	Moved SMP booting functions from smp.c to here.
  * 01/04/27 David Mosberger <davidm@hpl.hp.com>	Added ITC synching code.
  * 02/07/31 David Mosberger <davidm@hpl.hp.com>	Switch over to hotplug-CPU boot-sequence.
  *						smp_boot_cpus()/smp_commence() is replaced by
  *						smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
+ * 04/06/21 Ashok Raj		<ashok.raj@intel.com> Added CPU Hotplug Support
+ * 04/12/26 Jin Gordon <gordon.jin@intel.com>
+ * 04/12/26 Rohit Seth <rohit.seth@intel.com>
+ *						Add multi-threading and multi-core detection
+ * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com>
+ *						Setup cpu_sibling_map and cpu_core_map
  */
 #include <linux/config.h>
 
@@ -58,6 +69,37 @@
 #define Dprintk(x...)
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Store all idle threads, this can be reused instead of creating
+ * a new thread. Also avoids complicated thread destroy functionality
+ * for idle threads.
+ */
+struct task_struct *idle_thread_array[NR_CPUS];
+
+/*
+ * Global array allocated for NR_CPUS at boot time
+ */
+struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS];
+
+/*
+ * start_ap in head.S uses this to store current booting cpu
+ * info.
+ */
+struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0];
+
+#define set_brendez_area(x) (sal_state_for_booting_cpu = &sal_boot_rendez_state[(x)]);
+
+#define get_idle_for_cpu(x)		(idle_thread_array[(x)])
+#define set_idle_for_cpu(x,p)	(idle_thread_array[(x)] = (p))
+
+#else
+
+#define get_idle_for_cpu(x)		(NULL)
+#define set_idle_for_cpu(x,p)
+#define set_brendez_area(x)
+#endif
+
 
 /*
  * ITC synchronization related stuff:
@@ -90,6 +132,11 @@ EXPORT_SYMBOL(cpu_online_map);
 cpumask_t cpu_possible_map;
 EXPORT_SYMBOL(cpu_possible_map);
 
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+int smp_num_siblings = 1;
+int smp_num_cpucores = 1;
+
 /* which logical CPU number maps to which CPU (physical APIC ID) */
 volatile int ia64_cpu_to_sapicid[NR_CPUS];
 EXPORT_SYMBOL(ia64_cpu_to_sapicid);
@@ -124,7 +171,8 @@ sync_master (void *arg)
 	local_irq_save(flags);
 	{
 		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
-			while (!go[MASTER]);
+			while (!go[MASTER])
+				cpu_relax();
 			go[MASTER] = 0;
 			go[SLAVE] = ia64_get_itc();
 		}
@@ -147,7 +195,8 @@ get_delta (long *rt, long *master)
 	for (i = 0; i < NUM_ITERS; ++i) {
 		t0 = ia64_get_itc();
 		go[MASTER] = 1;
-		while (!(tm = go[SLAVE]));
+		while (!(tm = go[SLAVE]))
+			cpu_relax();
 		go[SLAVE] = 0;
 		t1 = ia64_get_itc();
 
@@ -226,7 +275,8 @@ ia64_sync_itc (unsigned int master)
 		return;
 	}
 
-	while (go[MASTER]);	/* wait for master to be ready */
+	while (go[MASTER])
+		cpu_relax();	/* wait for master to be ready */
 
 	spin_lock_irqsave(&itc_sync_lock, flags);
 	{
@@ -345,7 +395,6 @@ start_secondary (void *unused)
 {
 	/* Early console may use I/O ports */
 	ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
-
 	Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
 	efi_map_pal_code();
 	cpu_init();
@@ -384,6 +433,13 @@ do_boot_cpu (int sapicid, int cpu)
 		.done	= COMPLETION_INITIALIZER(c_idle.done),
 	};
 	DECLARE_WORK(work, do_fork_idle, &c_idle);
+
+ 	c_idle.idle = get_idle_for_cpu(cpu);
+ 	if (c_idle.idle) {
+		init_idle(c_idle.idle, cpu);
+ 		goto do_rest;
+	}
+
 	/*
 	 * We can't use kernel_thread since we must avoid to reschedule the child.
 	 */
@@ -396,10 +452,15 @@ do_boot_cpu (int sapicid, int cpu)
 
 	if (IS_ERR(c_idle.idle))
 		panic("failed fork for CPU %d", cpu);
+
+	set_idle_for_cpu(cpu, c_idle.idle);
+
+do_rest:
 	task_for_booting_cpu = c_idle.idle;
 
 	Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
 
+	set_brendez_area(cpu);
 	platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
 
 	/*
@@ -427,26 +488,12 @@ decay (char *str)
 {
 	int ticks;
 	get_option (&str, &ticks);
-	cache_decay_ticks = ticks;
 	return 1;
 }
 
 __setup("decay=", decay);
 
 /*
- * # of ticks an idle task is considered cache-hot.  Highly application-dependent.  There
- * are apps out there which are known to suffer significantly with values >= 4.
- */
-unsigned long cache_decay_ticks = 10;	/* equal to MIN_TIMESLICE */
-
-static void
-smp_tune_scheduling (void)
-{
-	printk(KERN_INFO "task migration cache decay timeout: %ld msecs.\n",
-	       (cache_decay_ticks + 1) * 1000 / HZ);
-}
-
-/*
  * Initialize the logical CPU number to SAPICID mapping
  */
 void __init
@@ -544,7 +591,6 @@ smp_prepare_cpus (unsigned int max_cpus)
 	printk(KERN_INFO "Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id);
 
 	current_thread_info()->cpu = 0;
-	smp_tune_scheduling();
 
 	/*
 	 * If SMP should be disabled, then really disable it!
@@ -567,19 +613,70 @@ void __devinit smp_prepare_boot_cpu(void
 	cpu_set(smp_processor_id(), cpu_callin_map);
 }
 
+/*
+ * mt_info[] is a temporary store for all info returned by
+ * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the
+ * specific cpu comes.
+ */
+static struct {
+	__u32   socket_id;
+	__u16   core_id;
+	__u16   thread_id;
+	__u16   proc_fixed_addr;
+	__u8    valid;
+} mt_info[NR_CPUS] __devinitdata;
+
 #ifdef CONFIG_HOTPLUG_CPU
-extern void fixup_irqs(void);
-/* must be called with cpucontrol mutex held */
-static int __devinit cpu_enable(unsigned int cpu)
+static inline void
+remove_from_mtinfo(int cpu)
 {
-	per_cpu(cpu_state,cpu) = CPU_UP_PREPARE;
-	wmb();
+	int i;
 
-	while (!cpu_online(cpu))
-		cpu_relax();
-	return 0;
+	for_each_cpu(i)
+		if (mt_info[i].valid &&  mt_info[i].socket_id ==
+		    				cpu_data(cpu)->socket_id)
+			mt_info[i].valid = 0;
+}
+
+static inline void
+clear_cpu_sibling_map(int cpu)
+{
+	int i;
+
+	for_each_cpu_mask(i, cpu_sibling_map[cpu])
+		cpu_clear(cpu, cpu_sibling_map[i]);
+	for_each_cpu_mask(i, cpu_core_map[cpu])
+		cpu_clear(cpu, cpu_core_map[i]);
+
+	cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
+}
+
+static void
+remove_siblinginfo(int cpu)
+{
+	int last = 0;
+
+	if (cpu_data(cpu)->threads_per_core == 1 &&
+	    cpu_data(cpu)->cores_per_socket == 1) {
+		cpu_clear(cpu, cpu_core_map[cpu]);
+		cpu_clear(cpu, cpu_sibling_map[cpu]);
+		return;
+	}
+
+	last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0);
+
+	/* remove it from all sibling map's */
+	clear_cpu_sibling_map(cpu);
+
+	/* if this cpu is the last in the core group, remove all its info 
+	 * from mt_info structure
+	 */
+	if (last)
+		remove_from_mtinfo(cpu);
 }
 
+extern void fixup_irqs(void);
+/* must be called with cpucontrol mutex held */
 int __cpu_disable(void)
 {
 	int cpu = smp_processor_id();
@@ -590,9 +687,10 @@ int __cpu_disable(void)
 	if (cpu == 0)
 		return -EBUSY;
 
+	remove_siblinginfo(cpu);
 	fixup_irqs();
 	local_flush_tlb_all();
-	printk ("Disabled cpu %u\n", smp_processor_id());
+	cpu_clear(cpu, cpu_callin_map);
 	return 0;
 }
 
@@ -604,12 +702,7 @@ void __cpu_die(unsigned int cpu)
 		/* They ack this in play_dead by setting CPU_DEAD */
 		if (per_cpu(cpu_state, cpu) == CPU_DEAD)
 		{
-			/*
-			 * TBD: Enable this when physical removal
-			 * or when we put the processor is put in
-			 * SAL_BOOT_RENDEZ mode
-			 * cpu_clear(cpu, cpu_callin_map);
-			 */
+			printk ("CPU %d is now offline\n", cpu);
 			return;
 		}
 		msleep(100);
@@ -617,11 +710,6 @@ void __cpu_die(unsigned int cpu)
  	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
 #else /* !CONFIG_HOTPLUG_CPU */
-static int __devinit cpu_enable(unsigned int cpu)
-{
-	return 0;
-}
-
 int __cpu_disable(void)
 {
 	return -ENOSYS;
@@ -652,6 +740,23 @@ smp_cpus_done (unsigned int dummy)
 	       (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
 }
 
+static inline void __devinit
+set_cpu_sibling_map(int cpu)
+{
+	int i;
+
+	for_each_online_cpu(i) {
+		if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) {
+			cpu_set(i, cpu_core_map[cpu]);
+			cpu_set(cpu, cpu_core_map[i]);
+			if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
+				cpu_set(i, cpu_sibling_map[cpu]);
+				cpu_set(cpu, cpu_sibling_map[i]);
+			}
+		}
+	}
+}
+
 int __devinit
 __cpu_up (unsigned int cpu)
 {
@@ -663,21 +768,26 @@ __cpu_up (unsigned int cpu)
 		return -EINVAL;
 
 	/*
-	 * Already booted.. just enable and get outa idle lool
+	 * Already booted cpu? not valid anymore since we dont
+	 * do idle loop tightspin anymore.
 	 */
 	if (cpu_isset(cpu, cpu_callin_map))
-	{
-		cpu_enable(cpu);
-		local_irq_enable();
-		while (!cpu_isset(cpu, cpu_online_map))
-			mb();
-		return 0;
-	}
+		return -EINVAL;
+
 	/* Processor goes to start_secondary(), sets online flag */
 	ret = do_boot_cpu(sapicid, cpu);
 	if (ret < 0)
 		return ret;
 
+	if (cpu_data(cpu)->threads_per_core == 1 &&
+	    cpu_data(cpu)->cores_per_socket == 1) {
+		cpu_set(cpu, cpu_sibling_map[cpu]);
+		cpu_set(cpu, cpu_core_map[cpu]);
+		return 0;
+	}
+
+	set_cpu_sibling_map(cpu);
+
 	return 0;
 }
 
@@ -705,3 +815,106 @@ init_smp_config(void)
 		       ia64_sal_strerror(sal_ret));
 }
 
+static inline int __devinit
+check_for_mtinfo_index(void)
+{
+	int i;
+	
+	for_each_cpu(i)
+		if (!mt_info[i].valid)
+			return i;
+
+	return -1;
+}
+
+/*
+ * Search the mt_info to find out if this socket's cid/tid information is
+ * cached or not. If the socket exists, fill in the core_id and thread_id 
+ * in cpuinfo
+ */
+static int __devinit
+check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c)
+{
+	int i;
+	__u32 sid = c->socket_id;
+
+	for_each_cpu(i) {
+		if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address
+		    && mt_info[i].socket_id == sid) {
+			c->core_id = mt_info[i].core_id;
+			c->thread_id = mt_info[i].thread_id;
+			return 1; /* not a new socket */
+		}
+	}
+	return 0;
+}
+
+/*
+ * identify_siblings(cpu) gets called from identify_cpu. This populates the 
+ * information related to logical execution units in per_cpu_data structure.
+ */
+void __devinit
+identify_siblings(struct cpuinfo_ia64 *c)
+{
+	s64 status;
+	u16 pltid;
+	u64 proc_fixed_addr;
+	int count, i;
+	pal_logical_to_physical_t info;
+
+	if (smp_num_cpucores == 1 && smp_num_siblings == 1)
+		return;
+
+	if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) {
+		printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
+		       status);
+		return;
+	}
+	if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
+		printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
+		return;
+	}
+	if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) {
+		printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status);
+		return;
+	}
+
+	c->socket_id =  (pltid << 8) | info.overview_ppid;
+	c->cores_per_socket = info.overview_cpp;
+	c->threads_per_core = info.overview_tpc;
+	count = c->num_log = info.overview_num_log;
+
+	/* If the thread and core id information is already cached, then
+	 * we will simply update cpu_info and return. Otherwise, we will
+	 * do the PAL calls and cache core and thread id's of all the siblings.
+	 */
+	if (check_for_new_socket(proc_fixed_addr, c))
+		return;
+
+	for (i = 0; i < count; i++) {
+		int index;
+
+		if (i && (status = ia64_pal_logical_to_phys(i, &info))
+			  != PAL_STATUS_SUCCESS) {
+                	printk(KERN_ERR "ia64_pal_logical_to_phys failed"
+					" with %ld\n", status);
+                	return;
+		}
+		if (info.log2_la == proc_fixed_addr) {
+			c->core_id = info.log1_cid;
+			c->thread_id = info.log1_tid;
+		}
+
+		index = check_for_mtinfo_index();
+		/* We will not do the mt_info caching optimization in this case.
+		 */
+		if (index < 0)
+			continue;
+
+		mt_info[index].valid = 1;
+		mt_info[index].socket_id = c->socket_id;
+		mt_info[index].core_id = info.log1_cid;
+		mt_info[index].thread_id = info.log1_tid;
+		mt_info[index].proc_fixed_addr = info.log2_la;
+	}
+}
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -93,20 +93,6 @@ sys_getpagesize (void)
 }
 
 asmlinkage unsigned long
-ia64_shmat (int shmid, void __user *shmaddr, int shmflg)
-{
-	unsigned long raddr;
-	int retval;
-
-	retval = do_shmat(shmid, shmaddr, shmflg, &raddr);
-	if (retval < 0)
-		return retval;
-
-	force_successful_syscall_return();
-	return raddr;
-}
-
-asmlinkage unsigned long
 ia64_brk (unsigned long brk)
 {
 	unsigned long rlim, retval, newbrk, oldbrk;
@@ -196,13 +182,6 @@ do_mmap2 (unsigned long addr, unsigned l
 		}
 	}
 
-	/*
-	 * A zero mmap always succeeds in Linux, independent of whether or not the
-	 * remaining arguments are valid.
-	 */
-	if (len == 0)
-		goto out;
-
 	/* Careful about overflows.. */
 	len = PAGE_ALIGN(len);
 	if (!len || len > TASK_SIZE) {
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -111,6 +111,24 @@ ia64_bad_break (unsigned long break_num,
 	siginfo_t siginfo;
 	int sig, code;
 
+	/* break.b always sets cr.iim to 0, which causes problems for
+	 * debuggers.  Get the real break number from the original instruction,
+	 * but only for kernel code.  User space break.b is left alone, to
+	 * preserve the existing behaviour.  All break codings have the same
+	 * format, so there is no need to check the slot type.
+	 */
+	if (break_num == 0 && !user_mode(regs)) {
+		struct ia64_psr *ipsr = ia64_psr(regs);
+		unsigned long *bundle = (unsigned long *)regs->cr_iip;
+		unsigned long slot;
+		switch (ipsr->ri) {
+		      case 0:  slot = (bundle[0] >>  5); break;
+		      case 1:  slot = (bundle[0] >> 46) | (bundle[1] << 18); break;
+		      default: slot = (bundle[1] >> 23); break;
+		}
+		break_num = ((slot >> 36 & 1) << 20) | (slot >> 6 & 0xfffff);
+	}
+
 	/* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
 	siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
 	siginfo.si_imm = break_num;
@@ -202,13 +220,21 @@ disabled_fph_fault (struct pt_regs *regs
 
 	/* first, grant user-level access to fph partition: */
 	psr->dfh = 0;
+
+	/*
+	 * Make sure that no other task gets in on this processor
+	 * while we're claiming the FPU
+	 */
+	preempt_disable();
 #ifndef CONFIG_SMP
 	{
 		struct task_struct *fpu_owner
 			= (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER);
 
-		if (ia64_is_local_fpu_owner(current))
+		if (ia64_is_local_fpu_owner(current)) {
+			preempt_enable_no_resched();
 			return;
+		}
 
 		if (fpu_owner)
 			ia64_flush_fph(fpu_owner);
@@ -226,6 +252,7 @@ disabled_fph_fault (struct pt_regs *regs
 		 */
 		psr->mfh = 1;
 	}
+	preempt_enable_no_resched();
 }
 
 static inline int
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -1380,6 +1380,10 @@ ia64_handle_unaligned (unsigned long ifa
 	 *		- ldX.spill
 	 *		- stX.spill
 	 *	Reason: RNATs are based on addresses
+	 *		- ld16
+	 *		- st16
+	 *	Reason: ld16 and st16 are supposed to occur in a single
+	 *		memory op
 	 *
 	 *	synchronization:
 	 *		- cmpxchg
@@ -1401,6 +1405,10 @@ ia64_handle_unaligned (unsigned long ifa
 	switch (opcode) {
 	      case LDS_OP:
 	      case LDSA_OP:
+		if (u.insn.x)
+			/* oops, really a semaphore op (cmpxchg, etc) */
+			goto failure;
+		/* no break */
 	      case LDS_IMM_OP:
 	      case LDSA_IMM_OP:
 	      case LDFS_OP:
@@ -1425,6 +1433,10 @@ ia64_handle_unaligned (unsigned long ifa
 	      case LDCCLR_OP:
 	      case LDCNC_OP:
 	      case LDCCLRACQ_OP:
+		if (u.insn.x)
+			/* oops, really a semaphore op (cmpxchg, etc) */
+			goto failure;
+		/* no break */
 	      case LD_IMM_OP:
 	      case LDA_IMM_OP:
 	      case LDBIAS_IMM_OP:
@@ -1437,6 +1449,10 @@ ia64_handle_unaligned (unsigned long ifa
 
 	      case ST_OP:
 	      case STREL_OP:
+		if (u.insn.x)
+			/* oops, really a semaphore op (cmpxchg, etc) */
+			goto failure;
+		/* no break */
 	      case ST_IMM_OP:
 	      case STREL_IMM_OP:
 		ret = emulate_store_int(ifa, u.insn, regs);
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -1943,23 +1943,30 @@ EXPORT_SYMBOL(unw_unwind);
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-	unsigned long ip, sp;
+	unsigned long ip, sp, pr = 0;
 
 	while (unw_unwind(info) >= 0) {
-		if (unw_get_rp(info, &ip) < 0) {
-			unw_get_ip(info, &ip);
-			UNW_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n",
-				   __FUNCTION__, ip);
-			return -1;
-		}
 		unw_get_sp(info, &sp);
-		if (sp >= (unsigned long)info->task + IA64_STK_OFFSET)
+		if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)
+		    < IA64_PT_REGS_SIZE) {
+			UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n",
+				   __FUNCTION__);
 			break;
-		if (ip < FIXADDR_USER_END)
+		}
+		if (unw_is_intr_frame(info) &&
+		    (pr & (1UL << PRED_USER_STACK)))
 			return 0;
+		if (unw_get_pr (info, &pr) < 0) {
+			unw_get_rp(info, &ip);
+			UNW_DPRINT(0, "unwind.%s: failed to read "
+				   "predicate register (ip=0x%lx)\n",
+				__FUNCTION__, ip);
+			return -1;
+		}
 	}
 	unw_get_ip(info, &ip);
-	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip);
+	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",
+		   __FUNCTION__, ip);
 	return -1;
 }
 EXPORT_SYMBOL(unw_unwind_to_user);
diff --git a/arch/ia64/lib/flush.S b/arch/ia64/lib/flush.S
--- a/arch/ia64/lib/flush.S
+++ b/arch/ia64/lib/flush.S
@@ -1,8 +1,8 @@
 /*
  * Cache flushing routines.
  *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001, 2005 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <asm/asmmacro.h>
 #include <asm/page.h>
@@ -26,7 +26,7 @@ GLOBAL_ENTRY(flush_icache_range)
 
 	mov ar.lc=r8
 	;;
-.Loop:	fc in0				// issuable on M0 only
+.Loop:	fc.i in0			// issuable on M2 only
 	add in0=32,in0
 	br.cloop.sptk.few .Loop
 	;;
diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S
--- a/arch/ia64/lib/memcpy_mck.S
+++ b/arch/ia64/lib/memcpy_mck.S
@@ -75,6 +75,7 @@ GLOBAL_ENTRY(memcpy)
 	mov	f6=f0
 	br.cond.sptk .common_code
 	;;
+END(memcpy)
 GLOBAL_ENTRY(__copy_user)
 	.prologue
 // check dest alignment
@@ -300,7 +301,7 @@ EK(.ex_handler,	(p[D])	st8 [dst1] = t15,
 	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
+(p7)	mov	ar.lc = cnt
 (p8)	mov	ar.lc = r0
 	;;
 	TEXT_ALIGN(32)
@@ -524,7 +525,6 @@ EK(.ex_handler,  (p17)	st8	[dst1]=r39,8)
 #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
diff --git a/arch/ia64/lib/memset.S b/arch/ia64/lib/memset.S
--- a/arch/ia64/lib/memset.S
+++ b/arch/ia64/lib/memset.S
@@ -57,10 +57,10 @@ GLOBAL_ENTRY(memset)
 { .mmi
 	.prologue
 	alloc	tmp = ar.pfs, 3, 0, 0, 0
-	.body
 	lfetch.nt1 [dest]			//
 	.save   ar.lc, save_lc
 	mov.i	save_lc = ar.lc
+	.body
 } { .mmi
 	mov	ret0 = dest			// return value
 	cmp.ne	p_nz, p_zr = value, r0		// use stf.spill if value is zero
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -444,7 +444,7 @@ swiotlb_map_single(struct device *hwdev,
 
 /*
  * 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
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
  * flush them when they get mapped into an executable vm-area.
  */
 static void
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -61,7 +61,8 @@ show_mem (void)
 	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", pgtable_cache_size);
+	printk("%ld pages in page table cache\n",
+		pgtable_quicklist_total_size());
 }
 
 /* physical address where the bootmem map is located */
@@ -280,7 +281,7 @@ paging_init (void)
 		vmem_map = (struct page *) vmalloc_end;
 		efi_memmap_walk(create_mem_map_page_table, NULL);
 
-		mem_map = contig_page_data.node_mem_map = vmem_map;
+		NODE_DATA(0)->node_mem_map = vmem_map;
 		free_area_init_node(0, &contig_page_data, zones_size,
 				    0, zholes_size);
 
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -582,7 +582,8 @@ void show_mem(void)
 	printk("%d reserved pages\n", total_reserved);
 	printk("%d pages shared\n", total_shared);
 	printk("%d pages swap cached\n", total_cached);
-	printk("Total of %ld pages in page table cache\n", pgtable_cache_size);
+	printk("Total of %ld pages in page table cache\n",
+		pgtable_quicklist_total_size());
 	printk("%d free buffer pages\n", nr_free_buffer_pages());
 }
 
diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c
--- a/arch/ia64/mm/extable.c
+++ b/arch/ia64/mm/extable.c
@@ -6,29 +6,29 @@
  */
 
 #include <linux/config.h>
+#include <linux/sort.h>
 
 #include <asm/uaccess.h>
 #include <asm/module.h>
 
-static inline int
-compare_entries (struct exception_table_entry *l, struct exception_table_entry *r)
+static int cmp_ex(const void *a, const void *b)
 {
+	const struct exception_table_entry *l = a, *r = b;
 	u64 lip = (u64) &l->addr + l->addr;
 	u64 rip = (u64) &r->addr + r->addr;
 
+	/* avoid overflow */
+	if (lip > rip)
+		return 1;
 	if (lip < rip)
 		return -1;
-	if (lip == rip)
-		return 0;
-	else
-		return 1;
+	return 0;
 }
 
-static inline void
-swap_entries (struct exception_table_entry *l, struct exception_table_entry *r)
+static void swap_ex(void *a, void *b, int size)
 {
+	struct exception_table_entry *l = a, *r = b, tmp;
 	u64 delta = (u64) r - (u64) l;
-	struct exception_table_entry tmp;
 
 	tmp = *l;
 	l->addr = r->addr + delta;
@@ -38,23 +38,20 @@ swap_entries (struct exception_table_ent
 }
 
 /*
- * Sort the exception table.  It's usually already sorted, but there may be unordered
- * entries due to multiple text sections (such as the .init text section).  Note that the
- * exception-table-entries contain location-relative addresses, which requires a bit of
- * care during sorting to avoid overflows in the offset members (e.g., it would not be
- * safe to make a temporary copy of an exception-table entry on the stack, because the
- * stack may be more than 2GB away from the exception-table).
+ * Sort the exception table. It's usually already sorted, but there
+ * may be unordered entries due to multiple text sections (such as the
+ * .init text section). Note that the exception-table-entries contain
+ * location-relative addresses, which requires a bit of care during
+ * sorting to avoid overflows in the offset members (e.g., it would
+ * not be safe to make a temporary copy of an exception-table entry on
+ * the stack, because the stack may be more than 2GB away from the
+ * exception-table).
  */
-void
-sort_extable (struct exception_table_entry *start, struct exception_table_entry *finish)
+void sort_extable (struct exception_table_entry *start,
+		   struct exception_table_entry *finish)
 {
-	struct exception_table_entry *p, *q;
-
- 	/* insertion sort */
-	for (p = start + 1; p < finish; ++p)
-		/* start .. p-1 is sorted; push p down to it's proper place */
-		for (q = p; q > start && compare_entries(&q[0], &q[-1]) < 0; --q)
-			swap_entries(&q[0], &q[-1]);
+	sort(start, finish - start, sizeof(struct exception_table_entry),
+	     cmp_ex, swap_ex);
 }
 
 const struct exception_table_entry *
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -209,10 +209,13 @@ ia64_do_page_fault (unsigned long addres
 	}
 
   no_context:
-	if (isr & IA64_ISR_SP) {
+	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;
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -73,7 +73,7 @@ set_huge_pte (struct mm_struct *mm, stru
 {
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 	if (write_access) {
 		entry =
 		    pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -116,7 +116,7 @@ int copy_hugetlb_page_range(struct mm_st
 		ptepage = pte_page(entry);
 		get_page(ptepage);
 		set_pte(dst_pte, entry);
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -186,46 +186,30 @@ follow_huge_pmd(struct mm_struct *mm, un
 	return NULL;
 }
 
-/*
- * Same as generic free_pgtables(), except constant PGDIR_* and pgd_offset
- * are hugetlb region specific.
- */
-void hugetlb_free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
-	unsigned long start, unsigned long end)
+void hugetlb_free_pgd_range(struct mmu_gather **tlb,
+			unsigned long addr, unsigned long end,
+			unsigned long floor, unsigned long ceiling)
 {
-	unsigned long first = start & HUGETLB_PGDIR_MASK;
-	unsigned long last = end + HUGETLB_PGDIR_SIZE - 1;
-	struct mm_struct *mm = tlb->mm;
-
-	if (!prev) {
-		prev = mm->mmap;
-		if (!prev)
-			goto no_mmaps;
-		if (prev->vm_end > start) {
-			if (last > prev->vm_start)
-				last = prev->vm_start;
-			goto no_mmaps;
-		}
-	}
-	for (;;) {
-		struct vm_area_struct *next = prev->vm_next;
+	/*
+	 * This is called only when is_hugepage_only_range(addr,),
+	 * and it follows that is_hugepage_only_range(end,) also.
+	 *
+	 * The offset of these addresses from the base of the hugetlb
+	 * region must be scaled down by HPAGE_SIZE/PAGE_SIZE so that
+	 * the standard free_pgd_range will free the right page tables.
+	 *
+	 * If floor and ceiling are also in the hugetlb region, they
+	 * must likewise be scaled down; but if outside, left unchanged.
+	 */
 
-		if (next) {
-			if (next->vm_start < start) {
-				prev = next;
-				continue;
-			}
-			if (last > next->vm_start)
-				last = next->vm_start;
-		}
-		if (prev->vm_end > first)
-			first = prev->vm_end;
-		break;
-	}
-no_mmaps:
-	if (last < first)	/* for arches with discontiguous pgd indices */
-		return;
-	clear_page_range(tlb, first, last);
+	addr = htlbpage_to_page(addr);
+	end  = htlbpage_to_page(end);
+	if (is_hugepage_only_range(tlb->mm, floor, HPAGE_SIZE))
+		floor = htlbpage_to_page(floor);
+	if (is_hugepage_only_range(tlb->mm, ceiling, HPAGE_SIZE))
+		ceiling = htlbpage_to_page(ceiling);
+
+	free_pgd_range(tlb, addr, end, floor, ceiling);
 }
 
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
@@ -244,9 +228,9 @@ void unmap_hugepage_range(struct vm_area
 			continue;
 		page = pte_page(*pte);
 		put_page(page);
-		pte_clear(pte);
+		pte_clear(mm, address, pte);
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm, rss, - ((end - start) >> PAGE_SHIFT));
 	flush_tlb_range(vma, start, end);
 }
 
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -39,6 +39,9 @@
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
+DEFINE_PER_CPU(unsigned long *, __pgtable_quicklist);
+DEFINE_PER_CPU(long, __pgtable_quicklist_size);
+
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
@@ -50,33 +53,59 @@ struct page *vmem_map;
 EXPORT_SYMBOL(vmem_map);
 #endif
 
-static int pgt_cache_water[2] = { 25, 50 };
-
-struct page *zero_page_memmap_ptr;		/* map entry for zero page */
+struct page *zero_page_memmap_ptr;	/* map entry for zero page */
 EXPORT_SYMBOL(zero_page_memmap_ptr);
 
+#define MIN_PGT_PAGES			25UL
+#define MAX_PGT_FREES_PER_PASS		16L
+#define PGT_FRACTION_OF_NODE_MEM	16
+
+static inline long
+max_pgt_pages(void)
+{
+	u64 node_free_pages, max_pgt_pages;
+
+#ifndef	CONFIG_NUMA
+	node_free_pages = nr_free_pages();
+#else
+	node_free_pages = nr_free_pages_pgdat(NODE_DATA(numa_node_id()));
+#endif
+	max_pgt_pages = node_free_pages / PGT_FRACTION_OF_NODE_MEM;
+	max_pgt_pages = max(max_pgt_pages, MIN_PGT_PAGES);
+	return max_pgt_pages;
+}
+
+static inline long
+min_pages_to_free(void)
+{
+	long pages_to_free;
+
+	pages_to_free = pgtable_quicklist_size - max_pgt_pages();
+	pages_to_free = min(pages_to_free, MAX_PGT_FREES_PER_PASS);
+	return pages_to_free;
+}
+
 void
-check_pgt_cache (void)
+check_pgt_cache(void)
 {
-	int low, high;
+	long pages_to_free;
 
-	low = pgt_cache_water[0];
-	high = pgt_cache_water[1];
+	if (unlikely(pgtable_quicklist_size <= MIN_PGT_PAGES))
+		return;
 
 	preempt_disable();
-	if (pgtable_cache_size > (u64) high) {
-		do {
-			if (pgd_quicklist)
-				free_page((unsigned long)pgd_alloc_one_fast(NULL));
-			if (pmd_quicklist)
-				free_page((unsigned long)pmd_alloc_one_fast(NULL, 0));
-		} while (pgtable_cache_size > (u64) low);
+	while (unlikely((pages_to_free = min_pages_to_free()) > 0)) {
+		while (pages_to_free--) {
+			free_page((unsigned long)pgtable_quicklist_alloc());
+		}
+		preempt_enable();
+		preempt_disable();
 	}
 	preempt_enable();
 }
 
 void
-update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte)
+lazy_mmu_prot_update (pte_t pte)
 {
 	unsigned long addr;
 	struct page *page;
@@ -85,7 +114,6 @@ update_mmu_cache (struct vm_area_struct 
 		return;				/* not an executable page... */
 
 	page = pte_page(pte);
-	/* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */
 	addr = (unsigned long) page_address(page);
 
 	if (test_bit(PG_arch_1, &page->flags))
@@ -277,8 +305,9 @@ setup_gate (void)
 	struct page *page;
 
 	/*
-	 * Map the gate page twice: once read-only to export the ELF headers etc. and once
-	 * execute-only page to enable privilege-promotion via "epc":
+	 * Map the gate page twice: once read-only to export the ELF
+	 * headers etc. and once execute-only page to enable
+	 * privilege-promotion via "epc":
 	 */
 	page = virt_to_page(ia64_imva(__start_gate_section));
 	put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
@@ -287,6 +316,20 @@ setup_gate (void)
 	put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
 #else
 	put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
+	/* Fill in the holes (if any) with read-only zero pages: */
+	{
+		unsigned long addr;
+
+		for (addr = GATE_ADDR + PAGE_SIZE;
+		     addr < GATE_ADDR + PERCPU_PAGE_SIZE;
+		     addr += PAGE_SIZE)
+		{
+			put_kernel_page(ZERO_PAGE(0), addr,
+					PAGE_READONLY);
+			put_kernel_page(ZERO_PAGE(0), addr + PERCPU_PAGE_SIZE,
+					PAGE_READONLY);
+		}
+	}
 #endif
 	ia64_patch_gate();
 }
@@ -524,11 +567,14 @@ void
 mem_init (void)
 {
 	long reserved_pages, codesize, datasize, initsize;
-	unsigned long num_pgt_pages;
 	pg_data_t *pgdat;
 	int i;
 	static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel;
 
+	BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE);
+	BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE);
+	BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE);
+
 #ifdef CONFIG_PCI
 	/*
 	 * This needs to be called _after_ the command line has been parsed but _before_
@@ -565,18 +611,6 @@ mem_init (void)
 	       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
-	 * at least once.  Each task also needs a couple of page tables pages, so add in a
-	 * fudge factor for that (don't use "threads-max" here; that would be wrong!).
-	 * Don't allow the cache to be more than 10% of total memory, though.
-	 */
-#	define NUM_TASKS	500	/* typical number of tasks */
-	num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS;
-	if (num_pgt_pages > nr_free_pages() / 10)
-		num_pgt_pages = nr_free_pages() / 10;
-	if (num_pgt_pages > (u64) pgt_cache_water[1])
-		pgt_cache_water[1] = num_pgt_pages;
 
 	/*
 	 * For fsyscall entrpoints with no light-weight handler, use the ordinary
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -127,7 +127,6 @@ local_flush_tlb_all (void)
 	local_irq_restore(flags);
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 }
-EXPORT_SYMBOL(local_flush_tlb_all);
 
 void
 flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -3,9 +3,9 @@
  *
  * Derived from bios32.c of i386 tree.
  *
- * Copyright (C) 2002 Hewlett-Packard Co
+ * (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
- *	Bjorn Helgaas <bjorn_helgaas@hp.com>
+ *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  * Copyright (C) 2004 Silicon Graphics, Inc.
  *
  * Note: Above list of copyright holders is incomplete...
@@ -27,26 +27,12 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
-
 #include <asm/sal.h>
-
-
-#ifdef CONFIG_SMP
-# include <asm/smp.h>
-#endif
+#include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 
 
-#undef DEBUG
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
 static int pci_routeirq;
 
 /*
@@ -55,23 +41,22 @@ static int pci_routeirq;
  * synchronization mechanism here.
  */
 
-#define PCI_SAL_ADDRESS(seg, bus, devfn, reg)	\
-	((u64)(seg << 24) | (u64)(bus << 16) |	\
-	 (u64)(devfn << 8) | (u64)(reg))
+#define PCI_SAL_ADDRESS(seg, bus, devfn, reg)		\
+	(((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg))
 
 /* SAL 3.2 adds support for extended config space. */
 
 #define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg)	\
-	((u64)(seg << 28) | (u64)(bus << 20) |		\
-	 (u64)(devfn << 12) | (u64)(reg))
+	(((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg))
 
 static int
-pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
+pci_sal_read (unsigned int seg, unsigned int bus, unsigned int devfn,
+	      int reg, int len, u32 *value)
 {
-	u64 addr, mode, data = 0;
-	int result = 0;
+	u64 addr, data = 0;
+	int mode, result;
 
-	if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
+	if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
 	if ((seg | reg) <= 255) {
@@ -82,16 +67,19 @@ pci_sal_read (int seg, int bus, int devf
 		mode = 1;
 	}
 	result = ia64_sal_pci_config_read(addr, mode, len, &data);
+	if (result != 0)
+		return -EINVAL;
 
 	*value = (u32) data;
-
-	return result;
+	return 0;
 }
 
 static int
-pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn,
+	       int reg, int len, u32 value)
 {
-	u64 addr, mode;
+	u64 addr;
+	int mode, result;
 
 	if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
@@ -103,7 +91,10 @@ pci_sal_write (int seg, int bus, int dev
 		addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
 		mode = 1;
 	}
-	return ia64_sal_pci_config_write(addr, mode, len, value);
+	result = ia64_sal_pci_config_write(addr, mode, len, value);
+	if (result != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct pci_raw_ops pci_sal_ops = {
@@ -160,21 +151,11 @@ pci_acpi_init (void)
 		 * also do it here in case there are still broken drivers that
 		 * don't use pci_enable_device().
 		 */
-		printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
-		printk(KERN_INFO "** was specified.  If this was required to make a driver work,\n");
-		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
-		printk(KERN_INFO "** so I can fix the driver.\n");
+		printk(KERN_INFO "PCI: Routing interrupts for all devices because \"pci=routeirq\" specified\n");
 		for_each_pci_dev(dev)
 			acpi_pci_irq_enable(dev);
-	} else {
-		printk(KERN_INFO "** PCI interrupts are no longer routed automatically.  If this\n");
-		printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
-		printk(KERN_INFO "** driver failed to call pci_enable_device().  As a temporary\n");
-		printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
-		printk(KERN_INFO "** behavior.  If this argument makes the device work again,\n");
-		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
-		printk(KERN_INFO "** so I can fix the driver.\n");
-	}
+	} else
+		printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\".  If it helps, post a report\n");
 
 	return 0;
 }
@@ -197,30 +178,6 @@ alloc_pci_controller (int seg)
 	return controller;
 }
 
-static int __devinit
-alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end,
-		unsigned long flags)
-{
-	struct resource *res;
-
-	res = kmalloc(sizeof(*res), GFP_KERNEL);
-	if (!res)
-		return -ENOMEM;
-
-	memset(res, 0, sizeof(*res));
-	res->name = name;
-	res->start = start;
-	res->end = end;
-	res->flags = flags;
-
-	if (insert_resource(root, res))	{
-		kfree(res);
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
 static u64 __devinit
 add_io_space (struct acpi_resource_address64 *addr)
 {
@@ -273,10 +230,9 @@ struct pci_root_info {
 	char *name;
 };
 
-static acpi_status __devinit
-add_window (struct acpi_resource *res, void *data)
+static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
 {
-	struct pci_root_info *info = (struct pci_root_info *) data;
+	struct pci_root_info *info = data;
 	struct pci_window *window;
 	struct acpi_resource_address64 addr;
 	acpi_status status;
@@ -284,45 +240,71 @@ add_window (struct acpi_resource *res, v
 	struct resource *root;
 
 	status = acpi_resource_to_address64(res, &addr);
-	if (ACPI_SUCCESS(status)) {
-		if (!addr.address_length)
-			return AE_OK;
+	if (!ACPI_SUCCESS(status))
+		return AE_OK;
+
+	if (!addr.address_length)
+		return AE_OK;
 
-		if (addr.resource_type == ACPI_MEMORY_RANGE) {
-			flags = IORESOURCE_MEM;
-			root = &iomem_resource;
-			offset = addr.address_translation_offset;
-		} else if (addr.resource_type == ACPI_IO_RANGE) {
-			flags = IORESOURCE_IO;
-			root = &ioport_resource;
-			offset = add_io_space(&addr);
-			if (offset == ~0)
-				return AE_OK;
-		} else
+	if (addr.resource_type == ACPI_MEMORY_RANGE) {
+		flags = IORESOURCE_MEM;
+		root = &iomem_resource;
+		offset = addr.address_translation_offset;
+	} else if (addr.resource_type == ACPI_IO_RANGE) {
+		flags = IORESOURCE_IO;
+		root = &ioport_resource;
+		offset = add_io_space(&addr);
+		if (offset == ~0)
 			return AE_OK;
+	} else
+		return AE_OK;
 
-		window = &info->controller->window[info->controller->windows++];
-		window->resource.flags	= flags;
-		window->resource.start  = addr.min_address_range;
-		window->resource.end    = addr.max_address_range;
-		window->offset		= offset;
-
-		if (alloc_resource(info->name, root, addr.min_address_range + offset,
-			addr.max_address_range + offset, flags))
-			printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n",
-				addr.min_address_range + offset, addr.max_address_range + offset,
-				root->name, info->name);
+	window = &info->controller->window[info->controller->windows++];
+	window->resource.name = info->name;
+	window->resource.flags = flags;
+	window->resource.start = addr.min_address_range + offset;
+	window->resource.end = addr.max_address_range + offset;
+	window->resource.child = NULL;
+	window->offset = offset;
+
+	if (insert_resource(root, &window->resource)) {
+		printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n",
+			window->resource.start, window->resource.end,
+			root->name, info->name);
 	}
 
 	return AE_OK;
 }
 
+static void __devinit
+pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
+{
+	int i, j;
+
+	j = 0;
+	for (i = 0; i < ctrl->windows; i++) {
+		struct resource *res = &ctrl->window[i].resource;
+		/* HP's firmware has a hack to work around a Windows bug.
+		 * Ignore these tiny memory ranges */
+		if ((res->flags & IORESOURCE_MEM) &&
+		    (res->end - res->start < 16))
+			continue;
+		if (j >= PCI_BUS_NUM_RESOURCES) {
+			printk("Ignoring range [%lx-%lx] (%lx)\n", res->start,
+					res->end, res->flags);
+			continue;
+		}
+		bus->resource[j++] = res;
+	}
+}
+
 struct pci_bus * __devinit
-pci_acpi_scan_root (struct acpi_device *device, int domain, int bus)
+pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
 {
 	struct pci_root_info info;
 	struct pci_controller *controller;
 	unsigned int windows = 0;
+	struct pci_bus *pbus;
 	char *name;
 
 	controller = alloc_pci_controller(domain);
@@ -331,8 +313,10 @@ pci_acpi_scan_root (struct acpi_device *
 
 	controller->acpi_handle = device->handle;
 
-	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, &windows);
-	controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL);
+	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
+			&windows);
+	controller->window = kmalloc(sizeof(*controller->window) * windows,
+			GFP_KERNEL);
 	if (!controller->window)
 		goto out2;
 
@@ -343,9 +327,14 @@ pci_acpi_scan_root (struct acpi_device *
 	sprintf(name, "PCI Bus %04x:%02x", domain, bus);
 	info.controller = controller;
 	info.name = name;
-	acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, &info);
+	acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
+			&info);
+
+	pbus = pci_scan_bus(bus, &pci_root_ops, controller);
+	if (pbus)
+		pcibios_setup_root_windows(pbus, controller);
 
-	return pci_scan_bus(bus, &pci_root_ops, controller);
+	return pbus;
 
 out3:
 	kfree(controller->window);
@@ -366,9 +355,9 @@ void pcibios_resource_to_bus(struct pci_
 		struct pci_window *window = &controller->window[i];
 		if (!(window->resource.flags & res->flags))
 			continue;
-		if (window->resource.start > res->start - window->offset)
+		if (window->resource.start > res->start)
 			continue;
-		if (window->resource.end < res->end - window->offset)
+		if (window->resource.end < res->end)
 			continue;
 		offset = window->offset;
 		break;
@@ -390,9 +379,9 @@ void pcibios_bus_to_resource(struct pci_
 		struct pci_window *window = &controller->window[i];
 		if (!(window->resource.flags & res->flags))
 			continue;
-		if (window->resource.start > region->start)
+		if (window->resource.start - window->offset > region->start)
 			continue;
-		if (window->resource.end < region->end)
+		if (window->resource.end - window->offset < region->end)
 			continue;
 		offset = window->offset;
 		break;
diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h
--- a/arch/ia64/sn/include/pci/pcibr_provider.h
+++ b/arch/ia64/sn/include/pci/pcibr_provider.h
@@ -123,9 +123,11 @@ pcibr_lock(struct pcibus_info *pcibus_in
 }
 #define pcibr_unlock(pcibus_info, flag)  spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag)
 
+extern int  pcibr_init_provider(void);
 extern void *pcibr_bus_fixup(struct pcibus_bussoft *);
-extern uint64_t pcibr_dma_map(struct pcidev_info *, unsigned long, size_t, unsigned int);
-extern void pcibr_dma_unmap(struct pcidev_info *, dma_addr_t, int);
+extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t);
+extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t);
+extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
 
 /*
  * prototypes for the bridge asic register access routines in pcibr_reg.c
diff --git a/arch/ia64/sn/include/pci/pcibus_provider_defs.h b/arch/ia64/sn/include/pci/pcibus_provider_defs.h
deleted file mode 100644
--- a/arch/ia64/sn/include/pci/pcibus_provider_defs.h
+++ /dev/null
@@ -1,43 +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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
-#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
-
-/*
- * SN pci asic types.  Do not ever renumber these or reuse values.  The
- * values must agree with what prom thinks they are.
- */
-
-#define PCIIO_ASIC_TYPE_UNKNOWN	0
-#define PCIIO_ASIC_TYPE_PPB	1
-#define PCIIO_ASIC_TYPE_PIC	2
-#define PCIIO_ASIC_TYPE_TIOCP	3
-
-/*
- * Common pciio bus provider data.  There should be one of these as the
- * first field in any pciio based provider soft structure (e.g. pcibr_soft
- * tioca_soft, etc).
- */
-
-struct pcibus_bussoft {
-	uint32_t		bs_asic_type;	/* chipset type */
-	uint32_t		bs_xid;		/* xwidget id */
-	uint64_t		bs_persist_busnum; /* Persistent Bus Number */
-	uint64_t		bs_legacy_io;	/* legacy io pio addr */
-	uint64_t		bs_legacy_mem;	/* legacy mem pio addr */
-	uint64_t		bs_base;	/* widget base */
-	struct xwidget_info	*bs_xwidget_info;
-};
-
-/*
- * DMA mapping flags
- */
-
-#define SN_PCIDMA_CONSISTENT    0x0001
-
-#endif				/* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
diff --git a/arch/ia64/sn/include/pci/pcidev.h b/arch/ia64/sn/include/pci/pcidev.h
deleted file mode 100644
--- a/arch/ia64/sn/include/pci/pcidev.h
+++ /dev/null
@@ -1,54 +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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PCIDEV_H
-#define _ASM_IA64_SN_PCI_PCIDEV_H
-
-#include <linux/pci.h>
-
-extern struct sn_irq_info **sn_irq;
-
-#define SN_PCIDEV_INFO(pci_dev) \
-        ((struct pcidev_info *)(pci_dev)->sysdata)
-
-/*
- * Given a pci_bus, return the sn pcibus_bussoft struct.  Note that
- * this only works for root busses, not for busses represented by PPB's.
- */
-
-#define SN_PCIBUS_BUSSOFT(pci_bus) \
-        ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
-
-/*
- * Given a struct pci_dev, return the sn pcibus_bussoft struct.  Note
- * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
- * due to possible PPB's in the path.
- */
-
-#define SN_PCIDEV_BUSSOFT(pci_dev) \
-	(SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info)
-
-#define PCIIO_BUS_NONE	255      /* bus 255 reserved */
-#define PCIIO_SLOT_NONE 255
-#define PCIIO_FUNC_NONE 255
-#define PCIIO_VENDOR_ID_NONE	(-1)
-
-struct pcidev_info {
-	uint64_t		pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */
-	uint64_t		pdi_slot_host_handle;	/* Bus and devfn Host pci_dev */
-
-	struct pcibus_bussoft	*pdi_pcibus_info;	/* Kernel common bus soft */
-	struct pcidev_info	*pdi_host_pcidev_info;	/* Kernel Host pci_dev */
-	struct pci_dev		*pdi_linux_pcidev;	/* Kernel pci_dev */
-
-	struct sn_irq_info	*pdi_sn_irq_info;
-};
-
-extern void sn_irq_fixup(struct pci_dev *pci_dev,
-			 struct sn_irq_info *sn_irq_info);
-
-#endif				/* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
--- a/arch/ia64/sn/kernel/Makefile
+++ b/arch/ia64/sn/kernel/Makefile
@@ -4,9 +4,15 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 1999,2001-2003 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 1999,2001-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 
 obj-y				+= setup.o bte.o bte_error.o irq.o mca.o idle.o \
 				   huberror.o io_init.o iomv.o klconflib.o sn2/
 obj-$(CONFIG_IA64_GENERIC)      += machvec.o
+obj-$(CONFIG_SGI_TIOCX)		+= tiocx.o
+obj-$(CONFIG_IA64_SGI_SN_XP)	+= xp.o
+xp-y				:= xp_main.o xp_nofault.o
+obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpc.o
+xpc-y				:= xpc_main.o xpc_channel.o xpc_partition.o
+obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpnet.o
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
--- a/arch/ia64/sn/kernel/bte.c
+++ b/arch/ia64/sn/kernel/bte.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 #include <linux/config.h>
@@ -170,10 +170,6 @@ retry_bteop:
 	/* Initialize the notification to a known value. */
 	*bte->most_rcnt_na = BTE_WORD_BUSY;
 
-	/* Set the status reg busy bit and transfer length */
-	BTE_PRINTKV(("IBLS = 0x%lx\n", IBLS_BUSY | transfer_size));
-	BTE_LNSTAT_STORE(bte, IBLS_BUSY | transfer_size);
-
 	/* Set the source and destination registers */
 	BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src))));
 	BTE_SRC_STORE(bte, TO_PHYS(src));
@@ -188,7 +184,7 @@ retry_bteop:
 
 	/* Initiate the transfer */
 	BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode)));
-	BTE_CTRL_STORE(bte, BTE_VALID_MODE(mode));
+	BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode));
 
 	itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec);
 
@@ -429,10 +425,16 @@ void bte_init_node(nodepda_t * mynodepda
 	mynodepda->bte_recovery_timer.data = (unsigned long)mynodepda;
 
 	for (i = 0; i < BTES_PER_NODE; i++) {
+		u64 *base_addr;
+
 		/* Which link status register should we use? */
-		unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1);
-		mynodepda->bte_if[i].bte_base_addr = (u64 *)
-		    REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status);
+		base_addr = (u64 *)
+		    REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), BTE_BASE_ADDR(i));
+		mynodepda->bte_if[i].bte_base_addr = base_addr;
+		mynodepda->bte_if[i].bte_source_addr = BTE_SOURCE_ADDR(base_addr);
+		mynodepda->bte_if[i].bte_destination_addr = BTE_DEST_ADDR(base_addr);
+		mynodepda->bte_if[i].bte_control_addr = BTE_CTRL_ADDR(base_addr);
+		mynodepda->bte_if[i].bte_notify_addr = BTE_NOTIF_ADDR(base_addr);
 
 		/*
 		 * Initialize the notification and spinlock
diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c
--- a/arch/ia64/sn/kernel/bte_error.c
+++ b/arch/ia64/sn/kernel/bte_error.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 #include <linux/types.h>
@@ -33,48 +33,28 @@ void bte_error_handler(unsigned long);
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-void bte_error_handler(unsigned long _nodepda)
+void shub1_bte_error_handler(unsigned long _nodepda)
 {
 	struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
-	spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
 	struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
 	nasid_t nasid;
 	int i;
 	int valid_crbs;
-	unsigned long irq_flags;
-	volatile u64 *notify;
-	bte_result_t bh_error;
 	ii_imem_u_t imem;	/* II IMEM Register */
 	ii_icrb0_d_u_t icrbd;	/* II CRB Register D */
 	ii_ibcr_u_t ibcr;
 	ii_icmr_u_t icmr;
 	ii_ieclr_u_t ieclr;
 
-	BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda,
+	BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda,
 		    smp_processor_id()));
 
-	spin_lock_irqsave(recovery_lock, irq_flags);
-
 	if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) &&
 	    (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
 		BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
 			    smp_processor_id()));
-		spin_unlock_irqrestore(recovery_lock, irq_flags);
 		return;
 	}
-	/*
-	 * Lock all interfaces on this node to prevent new transfers
-	 * from being queued.
-	 */
-	for (i = 0; i < BTES_PER_NODE; i++) {
-		if (err_nodepda->bte_if[i].cleanup_active) {
-			continue;
-		}
-		spin_lock(&err_nodepda->bte_if[i].spinlock);
-		BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda,
-			    smp_processor_id(), i));
-		err_nodepda->bte_if[i].cleanup_active = 1;
-	}
 
 	/* Determine information about our hub */
 	nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
@@ -101,7 +81,6 @@ void bte_error_handler(unsigned long _no
 		mod_timer(recovery_timer, HZ * 5);
 		BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
 			    smp_processor_id()));
-		spin_unlock_irqrestore(recovery_lock, irq_flags);
 		return;
 	}
 	if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
@@ -120,8 +99,6 @@ void bte_error_handler(unsigned long _no
 				BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
 					    err_nodepda, smp_processor_id(),
 					    i));
-				spin_unlock_irqrestore(recovery_lock,
-						       irq_flags);
 				return;
 			}
 		}
@@ -146,6 +123,51 @@ void bte_error_handler(unsigned long _no
 	ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
 	REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
 
+	del_timer(recovery_timer);
+}
+
+/*
+ * Wait until all BTE related CRBs are completed
+ * and then reset the interfaces.
+ */
+void bte_error_handler(unsigned long _nodepda)
+{
+	struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
+	spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
+	int i;
+	nasid_t nasid;
+	unsigned long irq_flags;
+	volatile u64 *notify;
+	bte_result_t bh_error;
+
+	BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda,
+		    smp_processor_id()));
+
+	spin_lock_irqsave(recovery_lock, irq_flags);
+
+	/*
+	 * Lock all interfaces on this node to prevent new transfers
+	 * from being queued.
+	 */
+	for (i = 0; i < BTES_PER_NODE; i++) {
+		if (err_nodepda->bte_if[i].cleanup_active) {
+			continue;
+		}
+		spin_lock(&err_nodepda->bte_if[i].spinlock);
+		BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda,
+			    smp_processor_id(), i));
+		err_nodepda->bte_if[i].cleanup_active = 1;
+	}
+
+	if (is_shub1()) {
+		shub1_bte_error_handler(_nodepda);
+	} else {
+		nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
+
+		if (ia64_sn_bte_recovery(nasid))
+			panic("bte_error_handler(): Fatal BTE Error");
+	}
+
 	for (i = 0; i < BTES_PER_NODE; i++) {
 		bh_error = err_nodepda->bte_if[i].bh_error;
 		if (bh_error != BTE_SUCCESS) {
@@ -165,8 +187,6 @@ void bte_error_handler(unsigned long _no
 		spin_unlock(&err_nodepda->bte_if[i].spinlock);
 	}
 
-	del_timer(recovery_timer);
-
 	spin_unlock_irqrestore(recovery_lock, irq_flags);
 }
 
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000,2002-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -38,8 +38,11 @@ static irqreturn_t hub_eint_handler(int 
 	if ((int)ret_stuff.v0)
 		panic("hubii_eint_handler(): Fatal TIO Error");
 
-	if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
-		(void)hubiio_crb_error_handler(hubdev_info);
+	if (is_shub1()) {
+		if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
+			(void)hubiio_crb_error_handler(hubdev_info);
+	} else 
+		bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -11,14 +11,15 @@
 #include <asm/sn/types.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/addrs.h>
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/pcibr_provider.h"
 #include "xtalk/xwidgetdev.h"
 #include <asm/sn/geo.h>
 #include "xtalk/hubdev.h"
 #include <asm/sn/io.h>
 #include <asm/sn/simulator.h>
+#include <asm/sn/tioca_provider.h>
 
 char master_baseio_wid;
 nasid_t master_nasid = INVALID_NASID;	/* Partition Master */
@@ -34,6 +35,37 @@ struct brick {
 
 int sn_ioif_inited = 0;		/* SN I/O infrastructure initialized? */
 
+struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];	/* indexed by asic type */
+
+/*
+ * Hooks and struct for unsupported pci providers
+ */
+
+static dma_addr_t
+sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
+{
+	return 0;
+}
+
+static void
+sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction)
+{
+	return;
+}
+
+static void *
+sn_default_pci_bus_fixup(struct pcibus_bussoft *soft)
+{
+	return NULL;
+}
+
+static struct sn_pcibus_provider sn_pci_default_provider = {
+	.dma_map = sn_default_pci_map,
+	.dma_map_consistent = sn_default_pci_map,
+	.dma_unmap = sn_default_pci_unmap,
+	.bus_fixup = sn_default_pci_bus_fixup,
+};
+
 /*
  * Retrieve the DMA Flush List given nasid.  This list is needed 
  * to implement the WAR - Flush DMA data on PIO Reads.
@@ -142,6 +174,12 @@ static void sn_fixup_ionodes(void)
 		if (status)
 			continue;
 
+		/* Attach the error interrupt handlers */
+		if (nasid & 1)
+			ice_error_init(hubdev);
+		else
+			hub_error_init(hubdev);
+
 		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
 			hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;
 
@@ -179,10 +217,6 @@ static void sn_fixup_ionodes(void)
 			    sn_flush_device_list;
 		}
 
-		if (!(i & 1))
-			hub_error_init(hubdev);
-		else
-			ice_error_init(hubdev);
 	}
 
 }
@@ -201,6 +235,7 @@ static void sn_pci_fixup_slot(struct pci
 	struct sn_irq_info *sn_irq_info;
 	struct pci_dev *host_pci_dev;
 	int status = 0;
+	struct pcibus_bussoft *bs;
 
 	dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
 	if (SN_PCIDEV_INFO(dev) <= 0)
@@ -241,6 +276,7 @@ static void sn_pci_fixup_slot(struct pci
 	}
 
 	/* set up host bus linkages */
+	bs = SN_PCIBUS_BUSSOFT(dev->bus);
 	host_pci_dev =
 	    pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
 			  SN_PCIDEV_INFO(dev)->
@@ -248,10 +284,16 @@ static void sn_pci_fixup_slot(struct pci
 	SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
 	    SN_PCIDEV_INFO(host_pci_dev);
 	SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
-	SN_PCIDEV_INFO(dev)->pdi_pcibus_info = SN_PCIBUS_BUSSOFT(dev->bus);
+	SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
+
+	if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
+		SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
+	} else {
+		SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider;
+	}
 
 	/* Only set up IRQ stuff if this device has a host bus context */
-	if (SN_PCIDEV_BUSSOFT(dev) && sn_irq_info->irq_irq) {
+	if (bs && sn_irq_info->irq_irq) {
 		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
 		dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
 		sn_irq_fixup(dev, sn_irq_info);
@@ -271,6 +313,7 @@ static void sn_pci_controller_fixup(int 
 	struct pcibus_bussoft *prom_bussoft_ptr;
 	struct hubdev_info *hubdev_info;
 	void *provider_soft;
+	struct sn_pcibus_provider *provider;
 
 	status =
 	    sal_get_pcibus_info((u64) segment, (u64) busnum,
@@ -291,16 +334,22 @@ static void sn_pci_controller_fixup(int 
 	/*
 	 * Per-provider fixup.  Copies the contents from prom to local
 	 * area and links SN_PCIBUS_BUSSOFT().
-	 *
-	 * Note:  Provider is responsible for ensuring that prom_bussoft_ptr
-	 * represents an asic-type that it can handle.
 	 */
 
-	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) {
-		return;		/* no further fixup necessary */
+	if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) {
+		return;		/* unsupported asic type */
+	}
+
+	provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
+	if (provider == NULL) {
+		return;		/* no provider registerd for this asic */
+	}
+
+	provider_soft = NULL;
+	if (provider->bus_fixup) {
+		provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr);
 	}
 
-	provider_soft = pcibr_bus_fixup(prom_bussoft_ptr);
 	if (provider_soft == NULL) {
 		return;		/* fixup failed or not applicable */
 	}
@@ -339,6 +388,17 @@ static int __init sn_pci_init(void)
 		return 0;
 
 	/*
+	 * prime sn_pci_provider[].  Individial provider init routines will
+	 * override their respective default entries.
+	 */
+
+	for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++)
+		sn_pci_provider[i] = &sn_pci_default_provider;
+
+	pcibr_init_provider();
+	tioca_init_provider();
+
+	/*
 	 * This is needed to avoid bounce limit checks in the blk layer
 	 */
 	ia64_max_iommu_merge_mask = ~PAGE_MASK;
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -13,8 +13,8 @@
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 #include "xtalk/xwidgetdev.h"
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/pcibr_provider.h"
 #include <asm/sn/shub_mmr.h>
 #include <asm/sn/sn_sal.h>
@@ -82,20 +82,9 @@ static void sn_ack_irq(unsigned int irq)
 	nasid = get_nasid();
 	event_occurred =
 	    HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED));
-	if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
-		mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT);
-	}
-	if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) {
-		mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT);
-	}
-	if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) {
-		mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT);
-	}
-	if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) {
-		mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT);
-	}
+	mask = event_occurred & SH_ALL_INT_MASK;
 	HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
-	      mask);
+		 mask);
 	__set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
 
 	move_irq(irq);
diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
--- a/arch/ia64/sn/kernel/mca.c
+++ b/arch/ia64/sn/kernel/mca.c
@@ -37,6 +37,11 @@ static u64 *sn_oemdata_size, sn_oemdata_
  * This function is the callback routine that SAL calls to log error
  * info for platform errors.  buf is appended to sn_oemdata, resizing as
  * required.
+ * Note: this is a SAL to OS callback, running under the same rules as the SAL
+ * code.  SAL calls are run with preempt disabled so this routine must not
+ * sleep.  vmalloc can sleep so print_hook cannot resize the output buffer
+ * itself, instead it must set the required size and return to let the caller
+ * resize the buffer then redrive the SAL call.
  */
 static int print_hook(const char *fmt, ...)
 {
@@ -47,18 +52,8 @@ static int print_hook(const char *fmt, .
 	vsnprintf(buf, sizeof(buf), fmt, args);
 	va_end(args);
 	len = strlen(buf);
-	while (*sn_oemdata_size + len + 1 > sn_oemdata_bufsize) {
-		u8 *newbuf = vmalloc(sn_oemdata_bufsize += 1000);
-		if (!newbuf) {
-			printk(KERN_ERR "%s: unable to extend sn_oemdata\n",
-			       __FUNCTION__);
-			return 0;
-		}
-		memcpy(newbuf, *sn_oemdata, *sn_oemdata_size);
-		vfree(*sn_oemdata);
-		*sn_oemdata = newbuf;
-	}
-	memcpy(*sn_oemdata + *sn_oemdata_size, buf, len + 1);
+	if (*sn_oemdata_size + len <= sn_oemdata_bufsize)
+		memcpy(*sn_oemdata + *sn_oemdata_size, buf, len);
 	*sn_oemdata_size += len;
 	return 0;
 }
@@ -98,7 +93,20 @@ sn_platform_plat_specific_err_print(cons
 	sn_oemdata = oemdata;
 	sn_oemdata_size = oemdata_size;
 	sn_oemdata_bufsize = 0;
-	ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header);
+	*sn_oemdata_size = PAGE_SIZE;	/* first guess at how much data will be generated */
+	while (*sn_oemdata_size > sn_oemdata_bufsize) {
+		u8 *newbuf = vmalloc(*sn_oemdata_size);
+		if (!newbuf) {
+			printk(KERN_ERR "%s: unable to extend sn_oemdata\n",
+			       __FUNCTION__);
+			return 1;
+		}
+		vfree(*sn_oemdata);
+		*sn_oemdata = newbuf;
+		sn_oemdata_bufsize = *sn_oemdata_size;
+		*sn_oemdata_size = 0;
+		ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header);
+	}
 	up(&sn_oemdata_mutex);
 	return 0;
 }
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999,2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1999,2001-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/root_dev.h>
 #include <linux/nodemask.h>
+#include <linux/pm.h>
 
 #include <asm/io.h>
 #include <asm/sal.h>
@@ -67,15 +68,33 @@ extern void snidle(int);
 extern unsigned char acpi_kbd_controller_present;
 
 unsigned long sn_rtc_cycles_per_second;
-
 EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 
+DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
+EXPORT_PER_CPU_SYMBOL(__sn_hub_info);
+
+DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_NUMNODES]);
+EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
+
+DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
+EXPORT_PER_CPU_SYMBOL(__sn_nodepda);
+
 partid_t sn_partid = -1;
 EXPORT_SYMBOL(sn_partid);
 char sn_system_serial_number_string[128];
 EXPORT_SYMBOL(sn_system_serial_number_string);
 u64 sn_partition_serial_number;
 EXPORT_SYMBOL(sn_partition_serial_number);
+u8 sn_partition_id;
+EXPORT_SYMBOL(sn_partition_id);
+u8 sn_system_size;
+EXPORT_SYMBOL(sn_system_size);
+u8 sn_sharing_domain_size;
+EXPORT_SYMBOL(sn_sharing_domain_size);
+u8 sn_coherency_id;
+EXPORT_SYMBOL(sn_coherency_id);
+u8 sn_region_size;
+EXPORT_SYMBOL(sn_region_size);
 
 short physical_node_map[MAX_PHYSNODE_ID];
 
@@ -203,7 +222,7 @@ void __init early_sn_setup(void)
 
 extern int platform_intr_list[];
 extern nasid_t master_nasid;
-static int shub_1_1_found __initdata;
+static int __initdata shub_1_1_found = 0;
 
 /*
  * sn_check_for_wars
@@ -252,6 +271,8 @@ void __init sn_setup(char **cmdline_p)
 	int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
 	extern void sn_cpu_init(void);
 
+	ia64_sn_plat_set_error_handling_features();
+
 	/*
 	 * If the generic code has enabled vga console support - lets
 	 * get rid of it again. This is a kludge for the fact that ACPI
@@ -341,6 +362,14 @@ void __init sn_setup(char **cmdline_p)
 	screen_info = sn_screen_info;
 
 	sn_timer_init();
+
+	/*
+	 * set pm_power_off to a SAL call to allow
+	 * sn machines to power off. The SAL call can be replaced
+	 * by an ACPI interface call when ACPI is fully implemented
+	 * for sn.
+	 */
+	pm_power_off = ia64_sn_power_down;
 }
 
 /**
@@ -352,11 +381,11 @@ static void __init sn_init_pdas(char **c
 {
 	cnodeid_t cnode;
 
-	memset(pda->cnodeid_to_nasid_table, -1,
-	       sizeof(pda->cnodeid_to_nasid_table));
+	memset(sn_cnodeid_to_nasid, -1,
+			sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid)));
 	for_each_online_node(cnode)
-		pda->cnodeid_to_nasid_table[cnode] =
-		    pxm_to_nasid(nid_to_pxm_map[cnode]);
+		sn_cnodeid_to_nasid[cnode] =
+				pxm_to_nasid(nid_to_pxm_map[cnode]);
 
 	numionodes = num_online_nodes();
 	scan_for_ionodes();
@@ -424,16 +453,14 @@ void __init sn_cpu_init(void)
 	int slice;
 	int cnode;
 	int i;
-	u64 shubtype, nasid_bitmask, nasid_shift;
 	static int wars_have_been_checked;
 
 	memset(pda, 0, sizeof(pda));
-	if (ia64_sn_get_hub_info(0, &shubtype, &nasid_bitmask, &nasid_shift))
+	if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2, &sn_hub_info->nasid_bitmask, &sn_hub_info->nasid_shift,
+				&sn_system_size, &sn_sharing_domain_size, &sn_partition_id,
+				&sn_coherency_id, &sn_region_size))
 		BUG();
-	pda->shub2 = (u8)shubtype;
-	pda->nasid_bitmask = (u16)nasid_bitmask;
-	pda->nasid_shift = (u8)nasid_shift;
-	pda->as_shift = pda->nasid_shift - 2;
+	sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2;
 
 	/*
 	 * The boot cpu makes this call again after platform initialization is
@@ -458,7 +485,8 @@ void __init sn_cpu_init(void)
 
 	cnode = nasid_to_cnodeid(nasid);
 
-	pda->p_nodepda = nodepdaindr[cnode];
+	sn_nodepda = nodepdaindr[cnode];
+
 	pda->led_address =
 	    (typeof(pda->led_address)) (LED0 + (slice << LED_CPU_SHIFT));
 	pda->led_state = LED_ALWAYS_SET;
@@ -467,22 +495,25 @@ void __init sn_cpu_init(void)
 	pda->idle_flag = 0;
 
 	if (cpuid != 0) {
-		memcpy(pda->cnodeid_to_nasid_table,
-		       pdacpu(0)->cnodeid_to_nasid_table,
-		       sizeof(pda->cnodeid_to_nasid_table));
+		/* copy cpu 0's sn_cnodeid_to_nasid table to this cpu's */
+		memcpy(sn_cnodeid_to_nasid,
+		       (&per_cpu(__sn_cnodeid_to_nasid, 0)),
+		       sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid)));
 	}
 
 	/*
 	 * Check for WARs.
 	 * Only needs to be done once, on BSP.
-	 * Has to be done after loop above, because it uses pda.cnodeid_to_nasid_table[i].
+	 * Has to be done after loop above, because it uses this cpu's
+	 * sn_cnodeid_to_nasid table which was just initialized if this
+	 * isn't cpu 0.
 	 * Has to be done before assignment below.
 	 */
 	if (!wars_have_been_checked) {
 		sn_check_for_wars();
 		wars_have_been_checked = 1;
 	}
-	pda->shub_1_1_found = shub_1_1_found;
+	sn_hub_info->shub_1_1_found = shub_1_1_found;
 
 	/*
 	 * Set up addresses of PIO/MEM write status registers.
@@ -561,8 +592,7 @@ static void __init scan_for_ionodes(void
 		brd = find_lboard_any(brd, KLTYPE_SNIA);
 
 		while (brd) {
-			pda->cnodeid_to_nasid_table[numionodes] =
-			    brd->brd_nasid;
+			sn_cnodeid_to_nasid[numionodes] = brd->brd_nasid;
 			physical_node_map[brd->brd_nasid] = numionodes;
 			root_lboard[numionodes] = brd;
 			numionodes++;
@@ -583,8 +613,7 @@ static void __init scan_for_ionodes(void
 				      root_lboard[nasid_to_cnodeid(nasid)],
 				      KLTYPE_TIO);
 		while (brd) {
-			pda->cnodeid_to_nasid_table[numionodes] =
-			    brd->brd_nasid;
+			sn_cnodeid_to_nasid[numionodes] = brd->brd_nasid;
 			physical_node_map[brd->brd_nasid] = numionodes;
 			root_lboard[numionodes] = brd;
 			numionodes++;
@@ -595,7 +624,6 @@ static void __init scan_for_ionodes(void
 			brd = find_lboard_any(brd, KLTYPE_TIO);
 		}
 	}
-
 }
 
 int
@@ -604,7 +632,8 @@ nasid_slice_to_cpuid(int nasid, int slic
 	long cpu;
 	
 	for (cpu=0; cpu < NR_CPUS; cpu++) 
-		if (nodepda->phys_cpuid[cpu].nasid == nasid && nodepda->phys_cpuid[cpu].slice == slice)
+		if (cpuid_to_nasid(cpu) == nasid &&
+					cpuid_to_slice(cpu) == slice)
 			return cpu;
 
 	return -1;
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -28,6 +28,7 @@
 #include <linux/vmalloc.h>
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
+#include <linux/utsname.h>
 #include <linux/cpumask.h>
 #include <linux/smp_lock.h>
 #include <linux/nodemask.h>
@@ -43,6 +44,7 @@
 #include <asm/sn/module.h>
 #include <asm/sn/geo.h>
 #include <asm/sn/sn2/sn_hwperf.h>
+#include <asm/sn/addrs.h>
 
 static void *sn_hwperf_salheap = NULL;
 static int sn_hwperf_obj_cnt = 0;
@@ -81,26 +83,45 @@ out:
 	return e;
 }
 
+static int sn_hwperf_location_to_bpos(char *location,
+	int *rack, int *bay, int *slot, int *slab)
+{
+	char type;
+
+	/* first scan for an old style geoid string */
+	if (sscanf(location, "%03d%c%02d#%d",
+		rack, &type, bay, slab) == 4)
+		*slot = 0; 
+	else /* scan for a new bladed geoid string */
+	if (sscanf(location, "%03d%c%02d^%02d#%d",
+		rack, &type, bay, slot, slab) != 5)
+		return -1; 
+	/* success */
+	return 0;
+}
+
 static int sn_hwperf_geoid_to_cnode(char *location)
 {
 	int cnode;
 	geoid_t geoid;
 	moduleid_t module_id;
-	char type;
-	int rack, slot, slab;
-	int this_rack, this_slot, this_slab;
+	int rack, bay, slot, slab;
+	int this_rack, this_bay, this_slot, this_slab;
 
-	if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4)
+	if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
 		return -1;
 
 	for (cnode = 0; cnode < numionodes; cnode++) {
 		geoid = cnodeid_get_geoid(cnode);
 		module_id = geo_module(geoid);
 		this_rack = MODULE_GET_RACK(module_id);
-		this_slot = MODULE_GET_BPOS(module_id);
+		this_bay = MODULE_GET_BPOS(module_id);
+		this_slot = geo_slot(geoid);
 		this_slab = geo_slab(geoid);
-		if (rack == this_rack && slot == this_slot && slab == this_slab)
+		if (rack == this_rack && bay == this_bay &&
+			slot == this_slot && slab == this_slab) {
 			break;
+		}
 	}
 
 	return cnode < numionodes ? cnode : -1;
@@ -153,11 +174,36 @@ static const char *sn_hwperf_get_slabnam
 	return slabname;
 }
 
+static void print_pci_topology(struct seq_file *s,
+	struct sn_hwperf_object_info *obj, int *ordinal,
+	u64 rack, u64 bay, u64 slot, u64 slab)
+{
+	char *p1;
+	char *p2;
+	char *pg;
+
+	if (!(pg = (char *)get_zeroed_page(GFP_KERNEL)))
+		return; /* ignore */
+	if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab,
+		__pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) {
+		for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) {
+			if (!(p2 = strchr(p1, '\n')))
+				break;
+			*p2 = '\0';
+			seq_printf(s, "pcibus %d %s-%s\n",
+				*ordinal, obj->location, p1);
+			(*ordinal)++;
+			p1 = p2 + 1;
+		}
+	}
+	free_page((unsigned long)pg);
+}
+
 static int sn_topology_show(struct seq_file *s, void *d)
 {
 	int sz;
 	int pt;
-	int e;
+	int e = 0;
 	int i;
 	int j;
 	const char *slabname;
@@ -169,11 +215,44 @@ static int sn_topology_show(struct seq_f
 	struct sn_hwperf_object_info *p;
 	struct sn_hwperf_object_info *obj = d;	/* this object */
 	struct sn_hwperf_object_info *objs = s->private; /* all objects */
+	int rack, bay, slot, slab;
+	u8 shubtype;
+	u8 system_size;
+	u8 sharing_size;
+	u8 partid;
+	u8 coher;
+	u8 nasid_shift;
+	u8 region_size;
+	u16 nasid_mask;
+	int nasid_msb;
+	int pci_bus_ordinal = 0;
 
 	if (obj == objs) {
-		seq_printf(s, "# sn_topology version 1\n");
+		seq_printf(s, "# sn_topology version 2\n");
 		seq_printf(s, "# objtype ordinal location partition"
 			" [attribute value [, ...]]\n");
+
+		if (ia64_sn_get_sn_info(0,
+			&shubtype, &nasid_mask, &nasid_shift, &system_size,
+			&sharing_size, &partid, &coher, &region_size))
+			BUG();
+		for (nasid_msb=63; nasid_msb > 0; nasid_msb--) {
+			if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb))
+				break;
+		}
+		seq_printf(s, "partition %u %s local "
+			"shubtype %s, "
+			"nasid_mask 0x%016lx, "
+			"nasid_bits %d:%d, "
+			"system_size %d, "
+			"sharing_size %d, "
+			"coherency_domain %d, "
+			"region_size %d\n",
+
+			partid, system_utsname.nodename,
+			shubtype ? "shub2" : "shub1", 
+			(u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
+			system_size, sharing_size, coher, region_size);
 	}
 
 	if (SN_HWPERF_FOREIGN(obj)) {
@@ -181,7 +260,7 @@ static int sn_topology_show(struct seq_f
 		return 0;
 	}
 
-	for (i = 0; obj->name[i]; i++) {
+	for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) {
 		if (obj->name[i] == ' ')
 			obj->name[i] = '_';
 	}
@@ -221,6 +300,17 @@ static int sn_topology_show(struct seq_f
 				seq_putc(s, '\n');
 			}
 		}
+
+		/*
+		 * PCI busses attached to this node, if any
+		 */
+		if (sn_hwperf_location_to_bpos(obj->location,
+			&rack, &bay, &slot, &slab)) {
+			/* export pci bus info */
+			print_pci_topology(s, obj, &pci_bus_ordinal,
+				rack, bay, slot, slab);
+
+		}
 	}
 
 	if (obj->ports) {
@@ -397,6 +487,9 @@ static int sn_hwperf_map_err(int hwperf_
 		break;
 
 	case SN_HWPERF_OP_BUSY:
+		e = -EBUSY;
+		break;
+
 	case SN_HWPERF_OP_RECONFIGURE:
 		e = -EAGAIN;
 		break;
@@ -549,6 +642,7 @@ sn_hwperf_ioctl(struct inode *in, struct
 		r = sn_hwperf_op_cpu(&op_info);
 		if (r) {
 			r = sn_hwperf_map_err(r);
+			a.v0 = v0;
 			goto error;
 		}
 		break;
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -0,0 +1,552 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/io.h>
+#include <asm/sn/types.h>
+#include <asm/sn/shubio.h>
+#include <asm/sn/tiocx.h>
+#include <asm/sn/l1.h>
+#include <asm/sn/module.h>
+#include "tio.h"
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
+
+#define CX_DEV_NONE 0
+#define DEVICE_NAME "tiocx"
+#define WIDGET_ID 0
+#define TIOCX_DEBUG 0
+
+#if TIOCX_DEBUG
+#define DBG(fmt...)    printk(KERN_ALERT fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+struct device_attribute dev_attr_cxdev_control;
+
+/**
+ * tiocx_match - Try to match driver id list with device.
+ * @dev: device pointer
+ * @drv: driver pointer
+ *
+ * Returns 1 if match, 0 otherwise.
+ */
+static int tiocx_match(struct device *dev, struct device_driver *drv)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct cx_drv *cx_drv = to_cx_driver(drv);
+	const struct cx_device_id *ids = cx_drv->id_table;
+
+	if (!ids)
+		return 0;
+
+	while (ids->part_num) {
+		if (ids->part_num == cx_dev->cx_id.part_num)
+			return 1;
+		ids++;
+	}
+	return 0;
+
+}
+
+static int tiocx_hotplug(struct device *dev, char **envp, int num_envp,
+			 char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+
+static void tiocx_bus_release(struct device *dev)
+{
+	kfree(to_cx_dev(dev));
+}
+
+struct bus_type tiocx_bus_type = {
+	.name = "tiocx",
+	.match = tiocx_match,
+	.hotplug = tiocx_hotplug,
+};
+
+/**
+ * cx_device_match - Find cx_device in the id table.
+ * @ids: id table from driver
+ * @cx_device: part/mfg id for the device
+ *
+ */
+static const struct cx_device_id *cx_device_match(const struct cx_device_id
+						  *ids,
+						  struct cx_dev *cx_device)
+{
+	/*
+	 * NOTES: We may want to check for CX_ANY_ID too.
+	 *        Do we want to match against nasid too?
+	 *        CX_DEV_NONE == 0, if the driver tries to register for
+	 *        part/mfg == 0 we should return no-match (NULL) here.
+	 */
+	while (ids->part_num && ids->mfg_num) {
+		if (ids->part_num == cx_device->cx_id.part_num &&
+		    ids->mfg_num == cx_device->cx_id.mfg_num)
+			return ids;
+		ids++;
+	}
+
+	return NULL;
+}
+
+/**
+ * cx_device_probe - Look for matching device.
+ *			Call driver probe routine if found.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ * @cx_device: part/mfg id for the device
+ */
+static int cx_device_probe(struct device *dev)
+{
+	const struct cx_device_id *id;
+	struct cx_drv *cx_drv = to_cx_driver(dev->driver);
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	int error = 0;
+
+	if (!cx_dev->driver && cx_drv->probe) {
+		id = cx_device_match(cx_drv->id_table, cx_dev);
+		if (id) {
+			if ((error = cx_drv->probe(cx_dev, id)) < 0)
+				return error;
+			else
+				cx_dev->driver = cx_drv;
+		}
+	}
+
+	return error;
+}
+
+/**
+ * cx_driver_remove - Remove driver from device struct.
+ * @dev: device
+ */
+static int cx_driver_remove(struct device *dev)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct cx_drv *cx_drv = cx_dev->driver;
+	if (cx_drv->remove)
+		cx_drv->remove(cx_dev);
+	cx_dev->driver = NULL;
+	return 0;
+}
+
+/**
+ * cx_driver_register - Register the driver.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ * 
+ * Called from the driver init routine to register a driver.
+ * The cx_drv struct contains the driver name, a pointer to
+ * a table of part/mfg numbers and a pointer to the driver's
+ * probe/attach routine.
+ */
+int cx_driver_register(struct cx_drv *cx_driver)
+{
+	cx_driver->driver.name = cx_driver->name;
+	cx_driver->driver.bus = &tiocx_bus_type;
+	cx_driver->driver.probe = cx_device_probe;
+	cx_driver->driver.remove = cx_driver_remove;
+
+	return driver_register(&cx_driver->driver);
+}
+
+/**
+ * cx_driver_unregister - Unregister the driver.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ */
+int cx_driver_unregister(struct cx_drv *cx_driver)
+{
+	driver_unregister(&cx_driver->driver);
+	return 0;
+}
+
+/**
+ * cx_device_register - Register a device.
+ * @nasid: device's nasid
+ * @part_num: device's part number
+ * @mfg_num: device's manufacturer number
+ * @hubdev: hub info associated with this device
+ *
+ */
+int
+cx_device_register(nasid_t nasid, int part_num, int mfg_num,
+		   struct hubdev_info *hubdev)
+{
+	struct cx_dev *cx_dev;
+
+	cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
+	DBG("cx_dev= 0x%p\n", cx_dev);
+	if (cx_dev == NULL)
+		return -ENOMEM;
+
+	cx_dev->cx_id.part_num = part_num;
+	cx_dev->cx_id.mfg_num = mfg_num;
+	cx_dev->cx_id.nasid = nasid;
+	cx_dev->hubdev = hubdev;
+
+	cx_dev->dev.parent = NULL;
+	cx_dev->dev.bus = &tiocx_bus_type;
+	cx_dev->dev.release = tiocx_bus_release;
+	snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x",
+		 cx_dev->cx_id.nasid, cx_dev->cx_id.part_num);
+	device_register(&cx_dev->dev);
+	get_device(&cx_dev->dev);
+
+	device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
+
+	return 0;
+}
+
+/**
+ * cx_device_unregister - Unregister a device.
+ * @cx_dev: part/mfg id for the device
+ */
+int cx_device_unregister(struct cx_dev *cx_dev)
+{
+	put_device(&cx_dev->dev);
+	device_unregister(&cx_dev->dev);
+	return 0;
+}
+
+/**
+ * cx_device_reload - Reload the device.
+ * @nasid: device's nasid
+ * @part_num: device's part number
+ * @mfg_num: device's manufacturer number
+ *
+ * Remove the device associated with 'nasid' from device list and then
+ * call device-register with the given part/mfg numbers.
+ */
+static int cx_device_reload(struct cx_dev *cx_dev)
+{
+	device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control);
+	cx_device_unregister(cx_dev);
+	return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
+				  cx_dev->cx_id.mfg_num, cx_dev->hubdev);
+}
+
+static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget,
+					u64 sn_irq_info,
+					int req_irq, nasid_t req_nasid,
+					int req_slice)
+{
+	struct ia64_sal_retval rv;
+	rv.status = 0;
+	rv.v0 = 0;
+
+	ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
+				SAL_INTR_ALLOC, nasid,
+				widget, sn_irq_info, req_irq,
+				req_nasid, req_slice);
+	return rv.status;
+}
+
+static inline void tiocx_intr_free(nasid_t nasid, int widget,
+				   struct sn_irq_info *sn_irq_info)
+{
+	struct ia64_sal_retval rv;
+	rv.status = 0;
+	rv.v0 = 0;
+
+	ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
+				SAL_INTR_FREE, nasid,
+				widget, sn_irq_info->irq_irq,
+				sn_irq_info->irq_cookie, 0, 0);
+}
+
+struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq,
+				    nasid_t req_nasid, int slice)
+{
+	struct sn_irq_info *sn_irq_info;
+	int status;
+	int sn_irq_size = sizeof(struct sn_irq_info);
+
+	if ((nasid & 1) == 0)
+		return NULL;
+
+	sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL);
+	if (sn_irq_info == NULL)
+		return NULL;
+
+	memset(sn_irq_info, 0x0, sn_irq_size);
+
+	status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq,
+				  req_nasid, slice);
+	if (status) {
+		kfree(sn_irq_info);
+		return NULL;
+	} else {
+		return sn_irq_info;
+	}
+}
+
+void tiocx_irq_free(struct sn_irq_info *sn_irq_info)
+{
+	uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
+	nasid_t nasid = NASID_GET(bridge);
+	int widget;
+
+	if (nasid & 1) {
+		widget = TIO_SWIN_WIDGETNUM(bridge);
+		tiocx_intr_free(nasid, widget, sn_irq_info);
+		kfree(sn_irq_info);
+	}
+}
+
+uint64_t tiocx_dma_addr(uint64_t addr)
+{
+	return PHYS_TO_TIODMA(addr);
+}
+
+uint64_t tiocx_swin_base(int nasid)
+{
+	return TIO_SWIN_BASE(nasid, TIOCX_CORELET);
+}
+
+EXPORT_SYMBOL(cx_driver_register);
+EXPORT_SYMBOL(cx_driver_unregister);
+EXPORT_SYMBOL(cx_device_register);
+EXPORT_SYMBOL(cx_device_unregister);
+EXPORT_SYMBOL(tiocx_irq_alloc);
+EXPORT_SYMBOL(tiocx_irq_free);
+EXPORT_SYMBOL(tiocx_bus_type);
+EXPORT_SYMBOL(tiocx_dma_addr);
+EXPORT_SYMBOL(tiocx_swin_base);
+
+static void tio_conveyor_set(nasid_t nasid, int enable_flag)
+{
+	uint64_t ice_frz;
+	uint64_t disable_cb = (1ull << 61);
+
+	if (!(nasid & 1))
+		return;
+
+	ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG);
+	if (enable_flag) {
+		if (!(ice_frz & disable_cb))	/* already enabled */
+			return;
+		ice_frz &= ~disable_cb;
+	} else {
+		if (ice_frz & disable_cb)	/* already disabled */
+			return;
+		ice_frz |= disable_cb;
+	}
+	DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz);
+	REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz);
+}
+
+#define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1)
+#define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0)
+
+static void tio_corelet_reset(nasid_t nasid, int corelet)
+{
+	if (!(nasid & 1))
+		return;
+
+	REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet);
+	udelay(2000);
+	REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0);
+	udelay(2000);
+}
+
+static int tiocx_btchar_get(int nasid)
+{
+	moduleid_t module_id;
+	geoid_t geoid;
+	int cnodeid;
+
+	cnodeid = nasid_to_cnodeid(nasid);
+	geoid = cnodeid_get_geoid(cnodeid);
+	module_id = geo_module(geoid);
+	return MODULE_GET_BTCHAR(module_id);
+}
+
+static int is_fpga_brick(int nasid)
+{
+	switch (tiocx_btchar_get(nasid)) {
+	case L1_BRICKTYPE_SA:
+	case L1_BRICKTYPE_ATHENA:
+		return 1;
+	}
+	return 0;
+}
+
+static int bitstream_loaded(nasid_t nasid)
+{
+	uint64_t cx_credits;
+
+	cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3);
+	cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK;
+	DBG("cx_credits= 0x%lx\n", cx_credits);
+
+	return (cx_credits == 0xf) ? 1 : 0;
+}
+
+static int tiocx_reload(struct cx_dev *cx_dev)
+{
+	int part_num = CX_DEV_NONE;
+	int mfg_num = CX_DEV_NONE;
+	nasid_t nasid = cx_dev->cx_id.nasid;
+
+	if (bitstream_loaded(nasid)) {
+		uint64_t cx_id;
+
+		cx_id =
+		    *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
+					  WIDGET_ID);
+		part_num = XWIDGET_PART_NUM(cx_id);
+		mfg_num = XWIDGET_MFG_NUM(cx_id);
+		DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num);
+		/* just ignore it if it's a CE */
+		if (part_num == TIO_CE_ASIC_PARTNUM)
+			return 0;
+	}
+
+	cx_dev->cx_id.part_num = part_num;
+	cx_dev->cx_id.mfg_num = mfg_num;
+
+	/*
+	 * Delete old device and register the new one.  It's ok if
+	 * part_num/mfg_num == CX_DEV_NONE.  We want to register
+	 * devices in the table even if a bitstream isn't loaded.
+	 * That allows use to see that a bitstream isn't loaded via
+	 * TIOCX_IOCTL_DEV_LIST.
+	 */
+	return cx_device_reload(cx_dev);
+}
+
+static ssize_t show_cxdev_control(struct device *dev, char *buf)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+
+	return sprintf(buf, "0x%x 0x%x 0x%x %d\n",
+		       cx_dev->cx_id.nasid,
+		       cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num,
+		       tiocx_btchar_get(cx_dev->cx_id.nasid));
+}
+
+static ssize_t store_cxdev_control(struct device *dev, const char *buf,
+				   size_t count)
+{
+	int n;
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (count <= 0)
+		return 0;
+
+	n = simple_strtoul(buf, NULL, 0);
+
+	switch (n) {
+	case 1:
+		tiocx_reload(cx_dev);
+		break;
+	case 3:
+		tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
+		break;
+	default:
+		break;
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
+
+static int __init tiocx_init(void)
+{
+	cnodeid_t cnodeid;
+	int found_tiocx_device = 0;
+
+	bus_register(&tiocx_bus_type);
+
+	for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
+		nasid_t nasid;
+
+		if ((nasid = cnodeid_to_nasid(cnodeid)) < 0)
+			break;	/* No more nasids .. bail out of loop */
+
+		if ((nasid & 0x1) && is_fpga_brick(nasid)) {
+			struct hubdev_info *hubdev;
+			struct xwidget_info *widgetp;
+
+			DBG("Found TIO at nasid 0x%x\n", nasid);
+
+			hubdev =
+			    (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
+
+			widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
+
+			/* The CE hangs off of the CX port but is not an FPGA */
+			if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM)
+				continue;
+
+			tio_corelet_reset(nasid, TIOCX_CORELET);
+			tio_conveyor_enable(nasid);
+
+			if (cx_device_register
+			    (nasid, widgetp->xwi_hwid.part_num,
+			     widgetp->xwi_hwid.mfg_num, hubdev) < 0)
+				return -ENXIO;
+			else
+				found_tiocx_device++;
+		}
+	}
+
+	/* It's ok if we find zero devices. */
+	DBG("found_tiocx_device= %d\n", found_tiocx_device);
+
+	return 0;
+}
+
+static void __exit tiocx_exit(void)
+{
+	struct device *dev;
+	struct device *tdev;
+
+	DBG("tiocx_exit\n");
+
+	/*
+	 * Unregister devices.
+	 */
+	list_for_each_entry_safe(dev, tdev, &tiocx_bus_type.devices.list,
+				 bus_list) {
+		if (dev) {
+			struct cx_dev *cx_dev = to_cx_dev(dev);
+			device_remove_file(dev, &dev_attr_cxdev_control);
+			cx_device_unregister(cx_dev);
+		}
+	}
+
+	bus_unregister(&tiocx_bus_type);
+}
+
+module_init(tiocx_init);
+module_exit(tiocx_exit);
+
+/************************************************************************
+ * Module licensing and description
+ ************************************************************************/
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
+MODULE_DESCRIPTION("TIOCX module");
+MODULE_SUPPORTED_DEVICE(DEVICE_NAME);
diff --git a/arch/ia64/sn/kernel/xp_main.c b/arch/ia64/sn/kernel/xp_main.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xp_main.c
@@ -0,0 +1,289 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition (XP) base.
+ *
+ *	XP provides a base from which its users can interact
+ *	with XPC, yet not be dependent on XPC.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/xp.h>
+
+
+/*
+ * Target of nofault PIO read.
+ */
+u64 xp_nofault_PIOR_target;
+
+
+/*
+ * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
+ * users of XPC.
+ */
+struct xpc_registration xpc_registrations[XPC_NCHANNELS];
+
+
+/*
+ * Initialize the XPC interface to indicate that XPC isn't loaded.
+ */
+static enum xpc_retval xpc_notloaded(void) { return xpcNotLoaded; }
+
+struct xpc_interface xpc_interface = {
+	(void (*)(int)) xpc_notloaded,
+	(void (*)(int)) xpc_notloaded,
+	(enum xpc_retval (*)(partid_t, int, u32, void **)) xpc_notloaded,
+	(enum xpc_retval (*)(partid_t, int, void *)) xpc_notloaded,
+	(enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, void *))
+							xpc_notloaded,
+	(void (*)(partid_t, int, void *)) xpc_notloaded,
+	(enum xpc_retval (*)(partid_t, void *)) xpc_notloaded
+};
+
+
+/*
+ * XPC calls this when it (the XPC module) has been loaded.
+ */
+void
+xpc_set_interface(void (*connect)(int),
+		void (*disconnect)(int),
+		enum xpc_retval (*allocate)(partid_t, int, u32, void **),
+		enum xpc_retval (*send)(partid_t, int, void *),
+		enum xpc_retval (*send_notify)(partid_t, int, void *,
+						xpc_notify_func, void *),
+		void (*received)(partid_t, int, void *),
+		enum xpc_retval (*partid_to_nasids)(partid_t, void *))
+{
+	xpc_interface.connect = connect;
+	xpc_interface.disconnect = disconnect;
+	xpc_interface.allocate = allocate;
+	xpc_interface.send = send;
+	xpc_interface.send_notify = send_notify;
+	xpc_interface.received = received;
+	xpc_interface.partid_to_nasids = partid_to_nasids;
+}
+
+
+/*
+ * XPC calls this when it (the XPC module) is being unloaded.
+ */
+void
+xpc_clear_interface(void)
+{
+	xpc_interface.connect = (void (*)(int)) xpc_notloaded;
+	xpc_interface.disconnect = (void (*)(int)) xpc_notloaded;
+	xpc_interface.allocate = (enum xpc_retval (*)(partid_t, int, u32,
+					void **)) xpc_notloaded;
+	xpc_interface.send = (enum xpc_retval (*)(partid_t, int, void *))
+					xpc_notloaded;
+	xpc_interface.send_notify = (enum xpc_retval (*)(partid_t, int, void *,
+				    xpc_notify_func, void *)) xpc_notloaded;
+	xpc_interface.received = (void (*)(partid_t, int, void *))
+					xpc_notloaded;
+	xpc_interface.partid_to_nasids = (enum xpc_retval (*)(partid_t, void *))
+					xpc_notloaded;
+}
+
+
+/*
+ * Register for automatic establishment of a channel connection whenever
+ * a partition comes up.
+ *
+ * Arguments:
+ *
+ *	ch_number - channel # to register for connection.
+ *	func - function to call for asynchronous notification of channel
+ *	       state changes (i.e., connection, disconnection, error) and
+ *	       the arrival of incoming messages.
+ *      key - pointer to optional user-defined value that gets passed back
+ *	      to the user on any callouts made to func.
+ *	payload_size - size in bytes of the XPC message's payload area which
+ *		       contains a user-defined message. The user should make
+ *		       this large enough to hold their largest message.
+ *	nentries - max #of XPC message entries a message queue can contain.
+ *		   The actual number, which is determined when a connection
+ * 		   is established and may be less then requested, will be
+ *		   passed to the user via the xpcConnected callout.
+ *	assigned_limit - max number of kthreads allowed to be processing
+ * 			 messages (per connection) at any given instant.
+ *	idle_limit - max number of kthreads allowed to be idle at any given
+ * 		     instant.
+ */
+enum xpc_retval
+xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
+		u16 nentries, u32 assigned_limit, u32 idle_limit)
+{
+	struct xpc_registration *registration;
+
+
+	DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+	DBUG_ON(payload_size == 0 || nentries == 0);
+	DBUG_ON(func == NULL);
+	DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit);
+
+	registration = &xpc_registrations[ch_number];
+
+	if (down_interruptible(&registration->sema) != 0) {
+		return xpcInterrupted;
+	}
+
+	/* if XPC_CHANNEL_REGISTERED(ch_number) */
+	if (registration->func != NULL) {
+		up(&registration->sema);
+		return xpcAlreadyRegistered;
+	}
+
+	/* register the channel for connection */
+	registration->msg_size = XPC_MSG_SIZE(payload_size);
+	registration->nentries = nentries;
+	registration->assigned_limit = assigned_limit;
+	registration->idle_limit = idle_limit;
+	registration->key = key;
+	registration->func = func;
+
+	up(&registration->sema);
+
+	xpc_interface.connect(ch_number);
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Remove the registration for automatic connection of the specified channel
+ * when a partition comes up.
+ *
+ * Before returning this xpc_disconnect() will wait for all connections on the
+ * specified channel have been closed/torndown. So the caller can be assured
+ * that they will not be receiving any more callouts from XPC to their
+ * function registered via xpc_connect().
+ *
+ * Arguments:
+ *
+ *	ch_number - channel # to unregister.
+ */
+void
+xpc_disconnect(int ch_number)
+{
+	struct xpc_registration *registration;
+
+
+	DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+
+	registration = &xpc_registrations[ch_number];
+
+	/*
+	 * We've decided not to make this a down_interruptible(), since we
+	 * figured XPC's users will just turn around and call xpc_disconnect()
+	 * again anyways, so we might as well wait, if need be.
+	 */
+	down(&registration->sema);
+
+	/* if !XPC_CHANNEL_REGISTERED(ch_number) */
+	if (registration->func == NULL) {
+		up(&registration->sema);
+		return;
+	}
+
+	/* remove the connection registration for the specified channel */
+	registration->func = NULL;
+	registration->key = NULL;
+	registration->nentries = 0;
+	registration->msg_size = 0;
+	registration->assigned_limit = 0;
+	registration->idle_limit = 0;
+
+	xpc_interface.disconnect(ch_number);
+
+	up(&registration->sema);
+
+	return;
+}
+
+
+int __init
+xp_init(void)
+{
+	int ret, ch_number;
+	u64 func_addr = *(u64 *) xp_nofault_PIOR;
+	u64 err_func_addr = *(u64 *) xp_error_PIOR;
+
+
+	if (!ia64_platform_is("sn2")) {
+		return -ENODEV;
+	}
+
+	/*
+	 * Register a nofault code region which performs a cross-partition
+	 * PIO read. If the PIO read times out, the MCA handler will consume
+	 * the error and return to a kernel-provided instruction to indicate
+	 * an error. This PIO read exists because it is guaranteed to timeout
+	 * if the destination is down (AMO operations do not timeout on at
+	 * least some CPUs on Shubs <= v1.2, which unfortunately we have to
+	 * work around).
+	 */
+	if ((ret = sn_register_nofault_code(func_addr, err_func_addr,
+						err_func_addr, 1, 1)) != 0) {
+		printk(KERN_ERR "XP: can't register nofault code, error=%d\n",
+			ret);
+	}
+	/*
+	 * Setup the nofault PIO read target. (There is no special reason why
+	 * SH_IPI_ACCESS was selected.)
+	 */
+	if (is_shub2()) {
+		xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
+	} else {
+		xp_nofault_PIOR_target = SH1_IPI_ACCESS;
+	}
+
+	/* initialize the connection registration semaphores */
+	for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) {
+		sema_init(&xpc_registrations[ch_number].sema, 1);  /* mutex */
+	}
+
+	return 0;
+}
+module_init(xp_init);
+
+
+void __exit
+xp_exit(void)
+{
+	u64 func_addr = *(u64 *) xp_nofault_PIOR;
+	u64 err_func_addr = *(u64 *) xp_error_PIOR;
+
+
+	/* unregister the PIO read nofault code region */
+	(void) sn_register_nofault_code(func_addr, err_func_addr,
+					err_func_addr, 1, 0);
+}
+module_exit(xp_exit);
+
+
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Cross Partition (XP) base");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(xp_nofault_PIOR);
+EXPORT_SYMBOL(xp_nofault_PIOR_target);
+EXPORT_SYMBOL(xpc_registrations);
+EXPORT_SYMBOL(xpc_interface);
+EXPORT_SYMBOL(xpc_clear_interface);
+EXPORT_SYMBOL(xpc_set_interface);
+EXPORT_SYMBOL(xpc_connect);
+EXPORT_SYMBOL(xpc_disconnect);
+
diff --git a/arch/ia64/sn/kernel/xp_nofault.S b/arch/ia64/sn/kernel/xp_nofault.S
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xp_nofault.S
@@ -0,0 +1,31 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * The xp_nofault_PIOR function takes a pointer to a remote PIO register
+ * and attempts to load and consume a value from it.  This function
+ * will be registered as a nofault code block.  In the event that the
+ * PIO read fails, the MCA handler will force the error to look
+ * corrected and vector to the xp_error_PIOR which will return an error.
+ *
+ *	extern int xp_nofault_PIOR(void *remote_register);
+ */
+
+	.global xp_nofault_PIOR
+xp_nofault_PIOR:
+	mov	r8=r0			// Stage a success return value
+	ld8.acq	r9=[r32];;		// PIO Read the specified register
+	adds	r9=1,r9			// Add to force a consume
+	br.ret.sptk.many b0;;		// Return success
+
+	.global xp_error_PIOR
+xp_error_PIOR:
+	mov	r8=1			// Return value of 1
+	br.ret.sptk.many b0;;		// Return failure
+
diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xpc.h
@@ -0,0 +1,991 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition Communication (XPC) structures and macros.
+ */
+
+#ifndef _IA64_SN_KERNEL_XPC_H
+#define _IA64_SN_KERNEL_XPC_H
+
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/mspec.h>
+#include <asm/sn/shub_mmr.h>
+#include <asm/sn/xp.h>
+
+
+/*
+ * XPC Version numbers consist of a major and minor number. XPC can always
+ * talk to versions with same major #, and never talk to versions with a
+ * different major #.
+ */
+#define _XPC_VERSION(_maj, _min)	(((_maj) << 4) | ((_min) & 0xf))
+#define XPC_VERSION_MAJOR(_v)		((_v) >> 4)
+#define XPC_VERSION_MINOR(_v)		((_v) & 0xf)
+
+
+/*
+ * The next macros define word or bit representations for given
+ * C-brick nasid in either the SAL provided bit array representing
+ * nasids in the partition/machine or the AMO_t array used for
+ * inter-partition initiation communications.
+ *
+ * For SN2 machines, C-Bricks are alway even numbered NASIDs.  As
+ * such, some space will be saved by insisting that nasid information
+ * passed from SAL always be packed for C-Bricks and the
+ * cross-partition interrupts use the same packing scheme.
+ */
+#define XPC_NASID_W_INDEX(_n)	(((_n) / 64) / 2)
+#define XPC_NASID_B_INDEX(_n)	(((_n) / 2) & (64 - 1))
+#define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \
+				    (1UL << XPC_NASID_B_INDEX(_n)))
+#define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2)
+
+#define XPC_HB_DEFAULT_INTERVAL		5	/* incr HB every x secs */
+#define XPC_HB_CHECK_DEFAULT_TIMEOUT	20	/* check HB every x secs */
+
+/* define the process name of HB checker and the CPU it is pinned to */
+#define XPC_HB_CHECK_THREAD_NAME	"xpc_hb"
+#define XPC_HB_CHECK_CPU		0
+
+/* define the process name of the discovery thread */
+#define XPC_DISCOVERY_THREAD_NAME	"xpc_discovery"
+
+
+#define XPC_HB_ALLOWED(_p, _v)	((_v)->heartbeating_to_mask & (1UL << (_p)))
+#define XPC_ALLOW_HB(_p, _v)	(_v)->heartbeating_to_mask |= (1UL << (_p))
+#define XPC_DISALLOW_HB(_p, _v)	(_v)->heartbeating_to_mask &= (~(1UL << (_p)))
+
+
+/*
+ * Reserved Page provided by SAL.
+ *
+ * SAL provides one page per partition of reserved memory.  When SAL
+ * initialization is complete, SAL_signature, SAL_version, partid,
+ * part_nasids, and mach_nasids are set.
+ *
+ * Note: Until vars_pa is set, the partition XPC code has not been initialized.
+ */
+struct xpc_rsvd_page {
+	u64 SAL_signature;	/* SAL unique signature */
+	u64 SAL_version;	/* SAL specified version */
+	u8 partid;		/* partition ID from SAL */
+	u8 version;
+	u8 pad[6];		/* pad to u64 align */
+	u64 vars_pa;
+	u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
+	u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
+};
+#define XPC_RP_VERSION _XPC_VERSION(1,0) /* version 1.0 of the reserved page */
+
+#define XPC_RSVD_PAGE_ALIGNED_SIZE \
+			(L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)))
+
+
+/*
+ * Define the structures by which XPC variables can be exported to other
+ * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
+ */
+
+/*
+ * The following structure describes the partition generic variables
+ * needed by other partitions in order to properly initialize.
+ *
+ * struct xpc_vars version number also applies to struct xpc_vars_part.
+ * Changes to either structure and/or related functionality should be
+ * reflected by incrementing either the major or minor version numbers
+ * of struct xpc_vars.
+ */
+struct xpc_vars {
+	u8 version;
+	u64 heartbeat;
+	u64 heartbeating_to_mask;
+	u64 kdb_status;		/* 0 = machine running */
+	int act_nasid;
+	int act_phys_cpuid;
+	u64 vars_part_pa;
+	u64 amos_page_pa;	/* paddr of page of AMOs from MSPEC driver */
+	AMO_t *amos_page;	/* vaddr of page of AMOs from MSPEC driver */
+	AMO_t *act_amos;	/* pointer to the first activation AMO */
+};
+#define XPC_V_VERSION _XPC_VERSION(3,0) /* version 3.0 of the cross vars */
+
+#define XPC_VARS_ALIGNED_SIZE  (L1_CACHE_ALIGN(sizeof(struct xpc_vars)))
+
+/*
+ * The following structure describes the per partition specific variables.
+ *
+ * An array of these structures, one per partition, will be defined. As a
+ * partition becomes active XPC will copy the array entry corresponding to
+ * itself from that partition. It is desirable that the size of this
+ * structure evenly divide into a cacheline, such that none of the entries
+ * in this array crosses a cacheline boundary. As it is now, each entry
+ * occupies half a cacheline.
+ */
+struct xpc_vars_part {
+	u64 magic;
+
+	u64 openclose_args_pa;	/* physical address of open and close args */
+	u64 GPs_pa;		/* physical address of Get/Put values */
+
+	u64 IPI_amo_pa;		/* physical address of IPI AMO_t structure */
+	int IPI_nasid;		/* nasid of where to send IPIs */
+	int IPI_phys_cpuid;	/* physical CPU ID of where to send IPIs */
+
+	u8 nchannels;		/* #of defined channels supported */
+
+	u8 reserved[23];	/* pad to a full 64 bytes */
+};
+
+/*
+ * The vars_part MAGIC numbers play a part in the first contact protocol.
+ *
+ * MAGIC1 indicates that the per partition specific variables for a remote
+ * partition have been initialized by this partition.
+ *
+ * MAGIC2 indicates that this partition has pulled the remote partititions
+ * per partition variables that pertain to this partition.
+ */
+#define XPC_VP_MAGIC1	0x0053524156435058L  /* 'XPCVARS\0'L (little endian) */
+#define XPC_VP_MAGIC2	0x0073726176435058L  /* 'XPCvars\0'L (little endian) */
+
+
+
+/*
+ * Functions registered by add_timer() or called by kernel_thread() only
+ * allow for a single 64-bit argument. The following macros can be used to
+ * pack and unpack two (32-bit, 16-bit or 8-bit) arguments into or out from
+ * the passed argument.
+ */
+#define XPC_PACK_ARGS(_arg1, _arg2) \
+			((((u64) _arg1) & 0xffffffff) | \
+			((((u64) _arg2) & 0xffffffff) << 32))
+
+#define XPC_UNPACK_ARG1(_args)	(((u64) _args) & 0xffffffff)
+#define XPC_UNPACK_ARG2(_args)	((((u64) _args) >> 32) & 0xffffffff)
+
+
+
+/*
+ * Define a Get/Put value pair (pointers) used with a message queue.
+ */
+struct xpc_gp {
+	s64 get;	/* Get value */
+	s64 put;	/* Put value */
+};
+
+#define XPC_GP_SIZE \
+		L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS)
+
+
+
+/*
+ * Define a structure that contains arguments associated with opening and
+ * closing a channel.
+ */
+struct xpc_openclose_args {
+	u16 reason;		/* reason why channel is closing */
+	u16 msg_size;		/* sizeof each message entry */
+	u16 remote_nentries;	/* #of message entries in remote msg queue */
+	u16 local_nentries;	/* #of message entries in local msg queue */
+	u64 local_msgqueue_pa;	/* physical address of local message queue */
+};
+
+#define XPC_OPENCLOSE_ARGS_SIZE \
+	      L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_NCHANNELS)
+
+
+
+/* struct xpc_msg flags */
+
+#define	XPC_M_DONE		0x01	/* msg has been received/consumed */
+#define	XPC_M_READY		0x02	/* msg is ready to be sent */
+#define	XPC_M_INTERRUPT		0x04	/* send interrupt when msg consumed */
+
+
+#define XPC_MSG_ADDRESS(_payload) \
+		((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET))
+
+
+
+/*
+ * Defines notify entry.
+ *
+ * This is used to notify a message's sender that their message was received
+ * and consumed by the intended recipient.
+ */
+struct xpc_notify {
+	struct semaphore sema;		/* notify semaphore */
+	u8 type;			/* type of notification */
+
+	/* the following two fields are only used if type == XPC_N_CALL */
+	xpc_notify_func func;		/* user's notify function */
+	void *key;			/* pointer to user's key */
+};
+
+/* struct xpc_notify type of notification */
+
+#define	XPC_N_CALL		0x01	/* notify function provided by user */
+
+
+
+/*
+ * Define the structure that manages all the stuff required by a channel. In
+ * particular, they are used to manage the messages sent across the channel.
+ *
+ * This structure is private to a partition, and is NOT shared across the
+ * partition boundary.
+ *
+ * There is an array of these structures for each remote partition. It is
+ * allocated at the time a partition becomes active. The array contains one
+ * of these structures for each potential channel connection to that partition.
+ *
+ * Each of these structures manages two message queues (circular buffers).
+ * They are allocated at the time a channel connection is made. One of
+ * these message queues (local_msgqueue) holds the locally created messages
+ * that are destined for the remote partition. The other of these message
+ * queues (remote_msgqueue) is a locally cached copy of the remote partition's
+ * own local_msgqueue.
+ *
+ * The following is a description of the Get/Put pointers used to manage these
+ * two message queues. Consider the local_msgqueue to be on one partition
+ * and the remote_msgqueue to be its cached copy on another partition. A
+ * description of what each of the lettered areas contains is included.
+ *
+ *
+ *                     local_msgqueue      remote_msgqueue
+ *
+ *                        |/////////|      |/////////|
+ *    w_remote_GP.get --> +---------+      |/////////|
+ *                        |    F    |      |/////////|
+ *     remote_GP.get  --> +---------+      +---------+ <-- local_GP->get
+ *                        |         |      |         |
+ *                        |         |      |    E    |
+ *                        |         |      |         |
+ *                        |         |      +---------+ <-- w_local_GP.get
+ *                        |    B    |      |/////////|
+ *                        |         |      |////D////|
+ *                        |         |      |/////////|
+ *                        |         |      +---------+ <-- w_remote_GP.put
+ *                        |         |      |////C////|
+ *      local_GP->put --> +---------+      +---------+ <-- remote_GP.put
+ *                        |         |      |/////////|
+ *                        |    A    |      |/////////|
+ *                        |         |      |/////////|
+ *     w_local_GP.put --> +---------+      |/////////|
+ *                        |/////////|      |/////////|
+ *
+ *
+ *	    ( remote_GP.[get|put] are cached copies of the remote
+ *	      partition's local_GP->[get|put], and thus their values can
+ *	      lag behind their counterparts on the remote partition. )
+ *
+ *
+ *  A - Messages that have been allocated, but have not yet been sent to the
+ *	remote partition.
+ *
+ *  B - Messages that have been sent, but have not yet been acknowledged by the
+ *      remote partition as having been received.
+ *
+ *  C - Area that needs to be prepared for the copying of sent messages, by
+ *	the clearing of the message flags of any previously received messages.
+ *
+ *  D - Area into which sent messages are to be copied from the remote
+ *	partition's local_msgqueue and then delivered to their intended
+ *	recipients. [ To allow for a multi-message copy, another pointer
+ *	(next_msg_to_pull) has been added to keep track of the next message
+ *	number needing to be copied (pulled). It chases after w_remote_GP.put.
+ *	Any messages lying between w_local_GP.get and next_msg_to_pull have
+ *	been copied and are ready to be delivered. ]
+ *
+ *  E - Messages that have been copied and delivered, but have not yet been
+ *	acknowledged by the recipient as having been received.
+ *
+ *  F - Messages that have been acknowledged, but XPC has not yet notified the
+ *	sender that the message was received by its intended recipient.
+ *	This is also an area that needs to be prepared for the allocating of
+ *	new messages, by the clearing of the message flags of the acknowledged
+ *	messages.
+ */
+struct xpc_channel {
+	partid_t partid;		/* ID of remote partition connected */
+	spinlock_t lock;		/* lock for updating this structure */
+	u32 flags;			/* general flags */
+
+	enum xpc_retval reason;		/* reason why channel is disconnect'g */
+	int reason_line;		/* line# disconnect initiated from */
+
+	u16 number;			/* channel # */
+
+	u16 msg_size;			/* sizeof each msg entry */
+	u16 local_nentries;		/* #of msg entries in local msg queue */
+	u16 remote_nentries;		/* #of msg entries in remote msg queue*/
+
+	void *local_msgqueue_base;	/* base address of kmalloc'd space */
+	struct xpc_msg *local_msgqueue;	/* local message queue */
+	void *remote_msgqueue_base;	/* base address of kmalloc'd space */
+	struct xpc_msg *remote_msgqueue;/* cached copy of remote partition's */
+					/* local message queue */
+	u64 remote_msgqueue_pa;		/* phys addr of remote partition's */
+					/* local message queue */
+
+	atomic_t references;		/* #of external references to queues */
+
+	atomic_t n_on_msg_allocate_wq;   /* #on msg allocation wait queue */
+	wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */
+
+	/* queue of msg senders who want to be notified when msg received */
+
+	atomic_t n_to_notify;		/* #of msg senders to notify */
+	struct xpc_notify *notify_queue;/* notify queue for messages sent */
+
+	xpc_channel_func func;		/* user's channel function */
+	void *key;			/* pointer to user's key */
+
+	struct semaphore msg_to_pull_sema; /* next msg to pull serialization */
+	struct semaphore teardown_sema;    /* wait for teardown completion */
+
+	struct xpc_openclose_args *local_openclose_args; /* args passed on */
+					/* opening or closing of channel */
+
+	/* various flavors of local and remote Get/Put values */
+
+	struct xpc_gp *local_GP;	/* local Get/Put values */
+	struct xpc_gp remote_GP;	/* remote Get/Put values */
+	struct xpc_gp w_local_GP;	/* working local Get/Put values */
+	struct xpc_gp w_remote_GP;	/* working remote Get/Put values */
+	s64 next_msg_to_pull;		/* Put value of next msg to pull */
+
+	/* kthread management related fields */
+
+// >>> rethink having kthreads_assigned_limit and kthreads_idle_limit; perhaps
+// >>> allow the assigned limit be unbounded and let the idle limit be dynamic
+// >>> dependent on activity over the last interval of time
+	atomic_t kthreads_assigned;	/* #of kthreads assigned to channel */
+	u32 kthreads_assigned_limit; 	/* limit on #of kthreads assigned */
+	atomic_t kthreads_idle;		/* #of kthreads idle waiting for work */
+	u32 kthreads_idle_limit;	/* limit on #of kthreads idle */
+	atomic_t kthreads_active;	/* #of kthreads actively working */
+	// >>> following field is temporary
+	u32 kthreads_created;		/* total #of kthreads created */
+
+	wait_queue_head_t idle_wq;	/* idle kthread wait queue */
+
+} ____cacheline_aligned;
+
+
+/* struct xpc_channel flags */
+
+#define	XPC_C_WASCONNECTED	0x00000001 /* channel was connected */
+
+#define	XPC_C_ROPENREPLY	0x00000002 /* remote open channel reply */
+#define	XPC_C_OPENREPLY		0x00000004 /* local open channel reply */
+#define	XPC_C_ROPENREQUEST	0x00000008 /* remote open channel request */
+#define	XPC_C_OPENREQUEST	0x00000010 /* local open channel request */
+
+#define	XPC_C_SETUP		0x00000020 /* channel's msgqueues are alloc'd */
+#define	XPC_C_CONNECTCALLOUT	0x00000040 /* channel connected callout made */
+#define	XPC_C_CONNECTED		0x00000080 /* local channel is connected */
+#define	XPC_C_CONNECTING	0x00000100 /* channel is being connected */
+
+#define	XPC_C_RCLOSEREPLY	0x00000200 /* remote close channel reply */
+#define	XPC_C_CLOSEREPLY	0x00000400 /* local close channel reply */
+#define	XPC_C_RCLOSEREQUEST	0x00000800 /* remote close channel request */
+#define	XPC_C_CLOSEREQUEST	0x00001000 /* local close channel request */
+
+#define	XPC_C_DISCONNECTED	0x00002000 /* channel is disconnected */
+#define	XPC_C_DISCONNECTING	0x00004000 /* channel is being disconnected */
+
+
+
+/*
+ * Manages channels on a partition basis. There is one of these structures
+ * for each partition (a partition will never utilize the structure that
+ * represents itself).
+ */
+struct xpc_partition {
+
+	/* XPC HB infrastructure */
+
+	u64 remote_rp_pa;		/* phys addr of partition's rsvd pg */
+	u64 remote_vars_pa;		/* phys addr of partition's vars */
+	u64 remote_vars_part_pa;	/* phys addr of partition's vars part */
+	u64 last_heartbeat;		/* HB at last read */
+	u64 remote_amos_page_pa;	/* phys addr of partition's amos page */
+	int remote_act_nasid;		/* active part's act/deact nasid */
+	int remote_act_phys_cpuid;	/* active part's act/deact phys cpuid */
+	u32 act_IRQ_rcvd;		/* IRQs since activation */
+	spinlock_t act_lock;		/* protect updating of act_state */
+	u8 act_state;			/* from XPC HB viewpoint */
+	enum xpc_retval reason;		/* reason partition is deactivating */
+	int reason_line;		/* line# deactivation initiated from */
+	int reactivate_nasid;		/* nasid in partition to reactivate */
+
+
+	/* XPC infrastructure referencing and teardown control */
+
+	u8 setup_state;			/* infrastructure setup state */
+	wait_queue_head_t teardown_wq;	/* kthread waiting to teardown infra */
+	atomic_t references;		/* #of references to infrastructure */
+
+
+	/*
+	 * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN
+	 * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION
+	 * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE
+	 * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.)
+	 */
+
+
+	u8 nchannels;		   /* #of defined channels supported */
+	atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */
+	struct xpc_channel *channels;/* array of channel structures */
+
+	void *local_GPs_base;	  /* base address of kmalloc'd space */
+	struct xpc_gp *local_GPs; /* local Get/Put values */
+	void *remote_GPs_base;    /* base address of kmalloc'd space */
+	struct xpc_gp *remote_GPs;/* copy of remote partition's local Get/Put */
+				  /* values */
+	u64 remote_GPs_pa;	  /* phys address of remote partition's local */
+				  /* Get/Put values */
+
+
+	/* fields used to pass args when opening or closing a channel */
+
+	void *local_openclose_args_base;  /* base address of kmalloc'd space */
+	struct xpc_openclose_args *local_openclose_args;  /* local's args */
+	void *remote_openclose_args_base; /* base address of kmalloc'd space */
+	struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */
+					  /* args */
+	u64 remote_openclose_args_pa;	  /* phys addr of remote's args */
+
+
+	/* IPI sending, receiving and handling related fields */
+
+	int remote_IPI_nasid;	    /* nasid of where to send IPIs */
+	int remote_IPI_phys_cpuid;  /* phys CPU ID of where to send IPIs */
+	AMO_t *remote_IPI_amo_va;   /* address of remote IPI AMO_t structure */
+
+	AMO_t *local_IPI_amo_va;    /* address of IPI AMO_t structure */
+	u64 local_IPI_amo;	    /* IPI amo flags yet to be handled */
+	char IPI_owner[8];	    /* IPI owner's name */
+	struct timer_list dropped_IPI_timer; /* dropped IPI timer */
+
+	spinlock_t IPI_lock;	    /* IPI handler lock */
+
+
+	/* channel manager related fields */
+
+	atomic_t channel_mgr_requests;	/* #of requests to activate chan mgr */
+	wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */
+
+} ____cacheline_aligned;
+
+
+/* struct xpc_partition act_state values (for XPC HB) */
+
+#define	XPC_P_INACTIVE		0x00	/* partition is not active */
+#define XPC_P_ACTIVATION_REQ	0x01	/* created thread to activate */
+#define XPC_P_ACTIVATING	0x02	/* activation thread started */
+#define XPC_P_ACTIVE		0x03	/* xpc_partition_up() was called */
+#define XPC_P_DEACTIVATING	0x04	/* partition deactivation initiated */
+
+
+#define XPC_DEACTIVATE_PARTITION(_p, _reason) \
+			xpc_deactivate_partition(__LINE__, (_p), (_reason))
+
+
+/* struct xpc_partition setup_state values */
+
+#define XPC_P_UNSET		0x00	/* infrastructure was never setup */
+#define XPC_P_SETUP		0x01	/* infrastructure is setup */
+#define XPC_P_WTEARDOWN		0x02	/* waiting to teardown infrastructure */
+#define XPC_P_TORNDOWN		0x03	/* infrastructure is torndown */
+
+
+/*
+ * struct xpc_partition IPI_timer #of seconds to wait before checking for
+ * dropped IPIs. These occur whenever an IPI amo write doesn't complete until
+ * after the IPI was received.
+ */
+#define XPC_P_DROPPED_IPI_WAIT	(0.25 * HZ)
+
+
+#define XPC_PARTID(_p)	((partid_t) ((_p) - &xpc_partitions[0]))
+
+
+
+/* found in xp_main.c */
+extern struct xpc_registration xpc_registrations[];
+
+
+/* >>> found in xpc_main.c only */
+extern struct device *xpc_part;
+extern struct device *xpc_chan;
+extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
+extern void xpc_dropped_IPI_check(struct xpc_partition *);
+extern void xpc_activate_kthreads(struct xpc_channel *, int);
+extern void xpc_create_kthreads(struct xpc_channel *, int);
+extern void xpc_disconnect_wait(int);
+
+
+/* found in xpc_main.c and efi-xpc.c */
+extern void xpc_activate_partition(struct xpc_partition *);
+
+
+/* found in xpc_partition.c */
+extern int xpc_exiting;
+extern int xpc_hb_interval;
+extern int xpc_hb_check_interval;
+extern struct xpc_vars *xpc_vars;
+extern struct xpc_rsvd_page *xpc_rsvd_page;
+extern struct xpc_vars_part *xpc_vars_part;
+extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1];
+extern char xpc_remote_copy_buffer[];
+extern struct xpc_rsvd_page *xpc_rsvd_page_init(void);
+extern void xpc_allow_IPI_ops(void);
+extern void xpc_restrict_IPI_ops(void);
+extern int xpc_identify_act_IRQ_sender(void);
+extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *);
+extern void xpc_mark_partition_inactive(struct xpc_partition *);
+extern void xpc_discovery(void);
+extern void xpc_check_remote_hb(void);
+extern void xpc_deactivate_partition(const int, struct xpc_partition *,
+						enum xpc_retval);
+extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *);
+
+
+/* found in xpc_channel.c */
+extern void xpc_initiate_connect(int);
+extern void xpc_initiate_disconnect(int);
+extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **);
+extern enum xpc_retval xpc_initiate_send(partid_t, int, void *);
+extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *,
+						xpc_notify_func, void *);
+extern void xpc_initiate_received(partid_t, int, void *);
+extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *);
+extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *);
+extern void xpc_process_channel_activity(struct xpc_partition *);
+extern void xpc_connected_callout(struct xpc_channel *);
+extern void xpc_deliver_msg(struct xpc_channel *);
+extern void xpc_disconnect_channel(const int, struct xpc_channel *,
+					enum xpc_retval, unsigned long *);
+extern void xpc_disconnected_callout(struct xpc_channel *);
+extern void xpc_partition_down(struct xpc_partition *, enum xpc_retval);
+extern void xpc_teardown_infrastructure(struct xpc_partition *);
+
+
+
+static inline void
+xpc_wakeup_channel_mgr(struct xpc_partition *part)
+{
+	if (atomic_inc_return(&part->channel_mgr_requests) == 1) {
+		wake_up(&part->channel_mgr_wq);
+	}
+}
+
+
+
+/*
+ * These next two inlines are used to keep us from tearing down a channel's
+ * msg queues while a thread may be referencing them.
+ */
+static inline void
+xpc_msgqueue_ref(struct xpc_channel *ch)
+{
+	atomic_inc(&ch->references);
+}
+
+static inline void
+xpc_msgqueue_deref(struct xpc_channel *ch)
+{
+	s32 refs = atomic_dec_return(&ch->references);
+
+	DBUG_ON(refs < 0);
+	if (refs == 0) {
+		xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]);
+	}
+}
+
+
+
+#define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \
+		xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs)
+
+
+/*
+ * These two inlines are used to keep us from tearing down a partition's
+ * setup infrastructure while a thread may be referencing it.
+ */
+static inline void
+xpc_part_deref(struct xpc_partition *part)
+{
+	s32 refs = atomic_dec_return(&part->references);
+
+
+	DBUG_ON(refs < 0);
+	if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) {
+		wake_up(&part->teardown_wq);
+	}
+}
+
+static inline int
+xpc_part_ref(struct xpc_partition *part)
+{
+	int setup;
+
+
+	atomic_inc(&part->references);
+	setup = (part->setup_state == XPC_P_SETUP);
+	if (!setup) {
+		xpc_part_deref(part);
+	}
+	return setup;
+}
+
+
+
+/*
+ * The following macro is to be used for the setting of the reason and
+ * reason_line fields in both the struct xpc_channel and struct xpc_partition
+ * structures.
+ */
+#define XPC_SET_REASON(_p, _reason, _line) \
+	{ \
+		(_p)->reason = _reason; \
+		(_p)->reason_line = _line; \
+	}
+
+
+
+/*
+ * The following set of macros and inlines are used for the sending and
+ * receiving of IPIs (also known as IRQs). There are two flavors of IPIs,
+ * one that is associated with partition activity (SGI_XPC_ACTIVATE) and
+ * the other that is associated with channel activity (SGI_XPC_NOTIFY).
+ */
+
+static inline u64
+xpc_IPI_receive(AMO_t *amo)
+{
+	return FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_CLEAR);
+}
+
+
+static inline enum xpc_retval
+xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
+{
+	int ret = 0;
+	unsigned long irq_flags;
+
+
+	local_irq_save(irq_flags);
+
+	FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, flag);
+	sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
+
+	/*
+	 * We must always use the nofault function regardless of whether we
+	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+	 * didn't, we'd never know that the other partition is down and would
+	 * keep sending IPIs and AMOs to it until the heartbeat times out.
+	 */
+	ret = xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
+				xp_nofault_PIOR_target));
+
+	local_irq_restore(irq_flags);
+
+	return ((ret == 0) ? xpcSuccess : xpcPioReadError);
+}
+
+
+/*
+ * IPIs associated with SGI_XPC_ACTIVATE IRQ.
+ */
+
+/*
+ * Flag the appropriate AMO variable and send an IPI to the specified node.
+ */
+static inline void
+xpc_activate_IRQ_send(u64 amos_page, int from_nasid, int to_nasid,
+			int to_phys_cpuid)
+{
+	int w_index = XPC_NASID_W_INDEX(from_nasid);
+	int b_index = XPC_NASID_B_INDEX(from_nasid);
+	AMO_t *amos = (AMO_t *) __va(amos_page +
+					(XP_MAX_PARTITIONS * sizeof(AMO_t)));
+
+
+	(void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid,
+				to_phys_cpuid, SGI_XPC_ACTIVATE);
+}
+
+static inline void
+xpc_IPI_send_activate(struct xpc_vars *vars)
+{
+	xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0),
+				vars->act_nasid, vars->act_phys_cpuid);
+}
+
+static inline void
+xpc_IPI_send_activated(struct xpc_partition *part)
+{
+	xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
+			part->remote_act_nasid, part->remote_act_phys_cpuid);
+}
+
+static inline void
+xpc_IPI_send_reactivate(struct xpc_partition *part)
+{
+	xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid,
+				xpc_vars->act_nasid, xpc_vars->act_phys_cpuid);
+}
+
+
+/*
+ * IPIs associated with SGI_XPC_NOTIFY IRQ.
+ */
+
+/*
+ * Send an IPI to the remote partition that is associated with the
+ * specified channel.
+ */
+#define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \
+		xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f)
+
+static inline void
+xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
+			unsigned long *irq_flags)
+{
+	struct xpc_partition *part = &xpc_partitions[ch->partid];
+	enum xpc_retval ret;
+
+
+	if (likely(part->act_state != XPC_P_DEACTIVATING)) {
+		ret = xpc_IPI_send(part->remote_IPI_amo_va,
+					(u64) ipi_flag << (ch->number * 8),
+					part->remote_IPI_nasid,
+					part->remote_IPI_phys_cpuid,
+					SGI_XPC_NOTIFY);
+		dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
+			ipi_flag_string, ch->partid, ch->number, ret);
+		if (unlikely(ret != xpcSuccess)) {
+			if (irq_flags != NULL) {
+				spin_unlock_irqrestore(&ch->lock, *irq_flags);
+			}
+			XPC_DEACTIVATE_PARTITION(part, ret);
+			if (irq_flags != NULL) {
+				spin_lock_irqsave(&ch->lock, *irq_flags);
+			}
+		}
+	}
+}
+
+
+/*
+ * Make it look like the remote partition, which is associated with the
+ * specified channel, sent us an IPI. This faked IPI will be handled
+ * by xpc_dropped_IPI_check().
+ */
+#define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \
+		xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f)
+
+static inline void
+xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag,
+				char *ipi_flag_string)
+{
+	struct xpc_partition *part = &xpc_partitions[ch->partid];
+
+
+	FETCHOP_STORE_OP(TO_AMO((u64) &part->local_IPI_amo_va->variable),
+			FETCHOP_OR, ((u64) ipi_flag << (ch->number * 8)));
+	dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
+		ipi_flag_string, ch->partid, ch->number);
+}
+
+
+/*
+ * The sending and receiving of IPIs includes the setting of an AMO variable
+ * to indicate the reason the IPI was sent. The 64-bit variable is divided
+ * up into eight bytes, ordered from right to left. Byte zero pertains to
+ * channel 0, byte one to channel 1, and so on. Each byte is described by
+ * the following IPI flags.
+ */
+
+#define	XPC_IPI_CLOSEREQUEST	0x01
+#define	XPC_IPI_CLOSEREPLY	0x02
+#define	XPC_IPI_OPENREQUEST	0x04
+#define	XPC_IPI_OPENREPLY	0x08
+#define	XPC_IPI_MSGREQUEST	0x10
+
+
+/* given an AMO variable and a channel#, get its associated IPI flags */
+#define XPC_GET_IPI_FLAGS(_amo, _c)	((u8) (((_amo) >> ((_c) * 8)) & 0xff))
+
+#define	XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0f)
+#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo)       ((_amo) & 0x1010101010101010)
+
+
+static inline void
+xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+	args->reason = ch->reason;
+
+	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+	args->msg_size = ch->msg_size;
+	args->local_nentries = ch->local_nentries;
+
+	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+	args->remote_nentries = ch->remote_nentries;
+	args->local_nentries = ch->local_nentries;
+	args->local_msgqueue_pa = __pa(ch->local_msgqueue);
+
+	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_msgrequest(struct xpc_channel *ch)
+{
+	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL);
+}
+
+static inline void
+xpc_IPI_send_local_msgrequest(struct xpc_channel *ch)
+{
+	XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST);
+}
+
+
+/*
+ * Memory for XPC's AMO variables is allocated by the MSPEC driver. These
+ * pages are located in the lowest granule. The lowest granule uses 4k pages
+ * for cached references and an alternate TLB handler to never provide a
+ * cacheable mapping for the entire region. This will prevent speculative
+ * reading of cached copies of our lines from being issued which will cause
+ * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
+ * (XP_MAX_PARTITIONS) AMO variables for message notification (xpc_main.c)
+ * and an additional 16 AMO variables for partition activation (xpc_hb.c).
+ */
+static inline AMO_t *
+xpc_IPI_init(partid_t partid)
+{
+	AMO_t *part_amo = xpc_vars->amos_page + partid;
+
+
+	xpc_IPI_receive(part_amo);
+	return part_amo;
+}
+
+
+
+static inline enum xpc_retval
+xpc_map_bte_errors(bte_result_t error)
+{
+	switch (error) {
+	case BTE_SUCCESS:	return xpcSuccess;
+	case BTEFAIL_DIR:	return xpcBteDirectoryError;
+	case BTEFAIL_POISON:	return xpcBtePoisonError;
+	case BTEFAIL_WERR:	return xpcBteWriteError;
+	case BTEFAIL_ACCESS:	return xpcBteAccessError;
+	case BTEFAIL_PWERR:	return xpcBtePWriteError;
+	case BTEFAIL_PRERR:	return xpcBtePReadError;
+	case BTEFAIL_TOUT:	return xpcBteTimeOutError;
+	case BTEFAIL_XTERR:	return xpcBteXtalkError;
+	case BTEFAIL_NOTAVAIL:	return xpcBteNotAvailable;
+	default:		return xpcBteUnmappedError;
+	}
+}
+
+
+
+static inline void *
+xpc_kmalloc_cacheline_aligned(size_t size, int flags, void **base)
+{
+	/* see if kmalloc will give us cachline aligned memory by default */
+	*base = kmalloc(size, flags);
+	if (*base == NULL) {
+		return NULL;
+	}
+	if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) {
+		return *base;
+	}
+	kfree(*base);
+
+	/* nope, we'll have to do it ourselves */
+	*base = kmalloc(size + L1_CACHE_BYTES, flags);
+	if (*base == NULL) {
+		return NULL;
+	}
+	return (void *) L1_CACHE_ALIGN((u64) *base);
+}
+
+
+/*
+ * Check to see if there is any channel activity to/from the specified
+ * partition.
+ */
+static inline void
+xpc_check_for_channel_activity(struct xpc_partition *part)
+{
+	u64 IPI_amo;
+	unsigned long irq_flags;
+
+
+	IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va);
+	if (IPI_amo == 0) {
+		return;
+	}
+
+	spin_lock_irqsave(&part->IPI_lock, irq_flags);
+	part->local_IPI_amo |= IPI_amo;
+	spin_unlock_irqrestore(&part->IPI_lock, irq_flags);
+
+	dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n",
+		XPC_PARTID(part), IPI_amo);
+
+	xpc_wakeup_channel_mgr(part);
+}
+
+
+#endif /* _IA64_SN_KERNEL_XPC_H */
+
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xpc_channel.c
@@ -0,0 +1,2297 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition Communication (XPC) channel support.
+ *
+ *	This is the part of XPC that manages the channels and
+ *	sends/receives messages across them to/from other partitions.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cache.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/sn_sal.h>
+#include "xpc.h"
+
+
+/*
+ * Set up the initial values for the XPartition Communication channels.
+ */
+static void
+xpc_initialize_channels(struct xpc_partition *part, partid_t partid)
+{
+	int ch_number;
+	struct xpc_channel *ch;
+
+
+	for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
+		ch = &part->channels[ch_number];
+
+		ch->partid = partid;
+		ch->number = ch_number;
+		ch->flags = XPC_C_DISCONNECTED;
+
+		ch->local_GP = &part->local_GPs[ch_number];
+		ch->local_openclose_args =
+					&part->local_openclose_args[ch_number];
+
+		atomic_set(&ch->kthreads_assigned, 0);
+		atomic_set(&ch->kthreads_idle, 0);
+		atomic_set(&ch->kthreads_active, 0);
+
+		atomic_set(&ch->references, 0);
+		atomic_set(&ch->n_to_notify, 0);
+
+		spin_lock_init(&ch->lock);
+		sema_init(&ch->msg_to_pull_sema, 1);	/* mutex */
+
+		atomic_set(&ch->n_on_msg_allocate_wq, 0);
+		init_waitqueue_head(&ch->msg_allocate_wq);
+		init_waitqueue_head(&ch->idle_wq);
+	}
+}
+
+
+/*
+ * Setup the infrastructure necessary to support XPartition Communication
+ * between the specified remote partition and the local one.
+ */
+enum xpc_retval
+xpc_setup_infrastructure(struct xpc_partition *part)
+{
+	int ret;
+	struct timer_list *timer;
+	partid_t partid = XPC_PARTID(part);
+
+
+	/*
+	 * Zero out MOST of the entry for this partition. Only the fields
+	 * starting with `nchannels' will be zeroed. The preceding fields must
+	 * remain `viable' across partition ups and downs, since they may be
+	 * referenced during this memset() operation.
+	 */
+	memset(&part->nchannels, 0, sizeof(struct xpc_partition) -
+				offsetof(struct xpc_partition, nchannels));
+
+	/*
+	 * Allocate all of the channel structures as a contiguous chunk of
+	 * memory.
+	 */
+	part->channels = kmalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS,
+								GFP_KERNEL);
+	if (part->channels == NULL) {
+		dev_err(xpc_chan, "can't get memory for channels\n");
+		return xpcNoMemory;
+	}
+	memset(part->channels, 0, sizeof(struct xpc_channel) * XPC_NCHANNELS);
+
+	part->nchannels = XPC_NCHANNELS;
+
+
+	/* allocate all the required GET/PUT values */
+
+	part->local_GPs = xpc_kmalloc_cacheline_aligned(XPC_GP_SIZE,
+					GFP_KERNEL, &part->local_GPs_base);
+	if (part->local_GPs == NULL) {
+		kfree(part->channels);
+		part->channels = NULL;
+		dev_err(xpc_chan, "can't get memory for local get/put "
+			"values\n");
+		return xpcNoMemory;
+	}
+	memset(part->local_GPs, 0, XPC_GP_SIZE);
+
+	part->remote_GPs = xpc_kmalloc_cacheline_aligned(XPC_GP_SIZE,
+					GFP_KERNEL, &part->remote_GPs_base);
+	if (part->remote_GPs == NULL) {
+		kfree(part->channels);
+		part->channels = NULL;
+		kfree(part->local_GPs_base);
+		part->local_GPs = NULL;
+		dev_err(xpc_chan, "can't get memory for remote get/put "
+			"values\n");
+		return xpcNoMemory;
+	}
+	memset(part->remote_GPs, 0, XPC_GP_SIZE);
+
+
+	/* allocate all the required open and close args */
+
+	part->local_openclose_args = xpc_kmalloc_cacheline_aligned(
+					XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL,
+					&part->local_openclose_args_base);
+	if (part->local_openclose_args == NULL) {
+		kfree(part->channels);
+		part->channels = NULL;
+		kfree(part->local_GPs_base);
+		part->local_GPs = NULL;
+		kfree(part->remote_GPs_base);
+		part->remote_GPs = NULL;
+		dev_err(xpc_chan, "can't get memory for local connect args\n");
+		return xpcNoMemory;
+	}
+	memset(part->local_openclose_args, 0, XPC_OPENCLOSE_ARGS_SIZE);
+
+	part->remote_openclose_args = xpc_kmalloc_cacheline_aligned(
+					XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL,
+					&part->remote_openclose_args_base);
+	if (part->remote_openclose_args == NULL) {
+		kfree(part->channels);
+		part->channels = NULL;
+		kfree(part->local_GPs_base);
+		part->local_GPs = NULL;
+		kfree(part->remote_GPs_base);
+		part->remote_GPs = NULL;
+		kfree(part->local_openclose_args_base);
+		part->local_openclose_args = NULL;
+		dev_err(xpc_chan, "can't get memory for remote connect args\n");
+		return xpcNoMemory;
+	}
+	memset(part->remote_openclose_args, 0, XPC_OPENCLOSE_ARGS_SIZE);
+
+
+	xpc_initialize_channels(part, partid);
+
+	atomic_set(&part->nchannels_active, 0);
+
+
+	/* local_IPI_amo were set to 0 by an earlier memset() */
+
+	/* Initialize this partitions AMO_t structure */
+	part->local_IPI_amo_va = xpc_IPI_init(partid);
+
+	spin_lock_init(&part->IPI_lock);
+
+	atomic_set(&part->channel_mgr_requests, 1);
+	init_waitqueue_head(&part->channel_mgr_wq);
+
+	sprintf(part->IPI_owner, "xpc%02d", partid);
+	ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, SA_SHIRQ,
+				part->IPI_owner, (void *) (u64) partid);
+	if (ret != 0) {
+		kfree(part->channels);
+		part->channels = NULL;
+		kfree(part->local_GPs_base);
+		part->local_GPs = NULL;
+		kfree(part->remote_GPs_base);
+		part->remote_GPs = NULL;
+		kfree(part->local_openclose_args_base);
+		part->local_openclose_args = NULL;
+		kfree(part->remote_openclose_args_base);
+		part->remote_openclose_args = NULL;
+		dev_err(xpc_chan, "can't register NOTIFY IRQ handler, "
+			"errno=%d\n", -ret);
+		return xpcLackOfResources;
+	}
+
+	/* Setup a timer to check for dropped IPIs */
+	timer = &part->dropped_IPI_timer;
+	init_timer(timer);
+	timer->function = (void (*)(unsigned long)) xpc_dropped_IPI_check;
+	timer->data = (unsigned long) part;
+	timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT;
+	add_timer(timer);
+
+	/*
+	 * With the setting of the partition setup_state to XPC_P_SETUP, we're
+	 * declaring that this partition is ready to go.
+	 */
+	(volatile u8) part->setup_state = XPC_P_SETUP;
+
+
+	/*
+	 * Setup the per partition specific variables required by the
+	 * remote partition to establish channel connections with us.
+	 *
+	 * The setting of the magic # indicates that these per partition
+	 * specific variables are ready to be used.
+	 */
+	xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs);
+	xpc_vars_part[partid].openclose_args_pa =
+					__pa(part->local_openclose_args);
+	xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va);
+	xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(smp_processor_id());
+	xpc_vars_part[partid].IPI_phys_cpuid =
+					cpu_physical_id(smp_processor_id());
+	xpc_vars_part[partid].nchannels = part->nchannels;
+	(volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Create a wrapper that hides the underlying mechanism for pulling a cacheline
+ * (or multiple cachelines) from a remote partition.
+ *
+ * src must be a cacheline aligned physical address on the remote partition.
+ * dst must be a cacheline aligned virtual address on this partition.
+ * cnt must be an cacheline sized
+ */
+static enum xpc_retval
+xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst,
+				const void *src, size_t cnt)
+{
+	bte_result_t bte_ret;
+
+
+	DBUG_ON((u64) src != L1_CACHE_ALIGN((u64) src));
+	DBUG_ON((u64) dst != L1_CACHE_ALIGN((u64) dst));
+	DBUG_ON(cnt != L1_CACHE_ALIGN(cnt));
+
+	if (part->act_state == XPC_P_DEACTIVATING) {
+		return part->reason;
+	}
+
+	bte_ret = xp_bte_copy((u64) src, (u64) ia64_tpa((u64) dst),
+				(u64) cnt, (BTE_NORMAL | BTE_WACQUIRE), NULL);
+	if (bte_ret == BTE_SUCCESS) {
+		return xpcSuccess;
+	}
+
+	dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n",
+		XPC_PARTID(part), bte_ret);
+
+	return xpc_map_bte_errors(bte_ret);
+}
+
+
+/*
+ * Pull the remote per partititon specific variables from the specified
+ * partition.
+ */
+enum xpc_retval
+xpc_pull_remote_vars_part(struct xpc_partition *part)
+{
+	u8 buffer[L1_CACHE_BYTES * 2];
+	struct xpc_vars_part *pulled_entry_cacheline =
+			(struct xpc_vars_part *) L1_CACHE_ALIGN((u64) buffer);
+	struct xpc_vars_part *pulled_entry;
+	u64 remote_entry_cacheline_pa, remote_entry_pa;
+	partid_t partid = XPC_PARTID(part);
+	enum xpc_retval ret;
+
+
+	/* pull the cacheline that contains the variables we're interested in */
+
+	DBUG_ON(part->remote_vars_part_pa !=
+				L1_CACHE_ALIGN(part->remote_vars_part_pa));
+	DBUG_ON(sizeof(struct xpc_vars_part) != L1_CACHE_BYTES / 2);
+
+	remote_entry_pa = part->remote_vars_part_pa +
+			sn_partition_id * sizeof(struct xpc_vars_part);
+
+	remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1));
+
+	pulled_entry = (struct xpc_vars_part *) ((u64) pulled_entry_cacheline +
+				(remote_entry_pa & (L1_CACHE_BYTES - 1)));
+
+	ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline,
+					(void *) remote_entry_cacheline_pa,
+					L1_CACHE_BYTES);
+	if (ret != xpcSuccess) {
+		dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
+			"partition %d, ret=%d\n", partid, ret);
+		return ret;
+	}
+
+
+	/* see if they've been set up yet */
+
+	if (pulled_entry->magic != XPC_VP_MAGIC1 &&
+				pulled_entry->magic != XPC_VP_MAGIC2) {
+
+		if (pulled_entry->magic != 0) {
+			dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
+				"partition %d has bad magic value (=0x%lx)\n",
+				partid, sn_partition_id, pulled_entry->magic);
+			return xpcBadMagic;
+		}
+
+		/* they've not been initialized yet */
+		return xpcRetry;
+	}
+
+	if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) {
+
+		/* validate the variables */
+
+		if (pulled_entry->GPs_pa == 0 ||
+				pulled_entry->openclose_args_pa == 0 ||
+					pulled_entry->IPI_amo_pa == 0) {
+
+			dev_err(xpc_chan, "partition %d's XPC vars_part for "
+				"partition %d are not valid\n", partid,
+				sn_partition_id);
+			return xpcInvalidAddress;
+		}
+
+		/* the variables we imported look to be valid */
+
+		part->remote_GPs_pa = pulled_entry->GPs_pa;
+		part->remote_openclose_args_pa =
+					pulled_entry->openclose_args_pa;
+		part->remote_IPI_amo_va =
+				      (AMO_t *) __va(pulled_entry->IPI_amo_pa);
+		part->remote_IPI_nasid = pulled_entry->IPI_nasid;
+		part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid;
+
+		if (part->nchannels > pulled_entry->nchannels) {
+			part->nchannels = pulled_entry->nchannels;
+		}
+
+		/* let the other side know that we've pulled their variables */
+
+		(volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC2;
+	}
+
+	if (pulled_entry->magic == XPC_VP_MAGIC1) {
+		return xpcRetry;
+	}
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Get the IPI flags and pull the openclose args and/or remote GPs as needed.
+ */
+static u64
+xpc_get_IPI_flags(struct xpc_partition *part)
+{
+	unsigned long irq_flags;
+	u64 IPI_amo;
+	enum xpc_retval ret;
+
+
+	/*
+	 * See if there are any IPI flags to be handled.
+	 */
+
+	spin_lock_irqsave(&part->IPI_lock, irq_flags);
+	if ((IPI_amo = part->local_IPI_amo) != 0) {
+		part->local_IPI_amo = 0;
+	}
+	spin_unlock_irqrestore(&part->IPI_lock, irq_flags);
+
+
+	if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) {
+		ret = xpc_pull_remote_cachelines(part,
+					part->remote_openclose_args,
+					(void *) part->remote_openclose_args_pa,
+					XPC_OPENCLOSE_ARGS_SIZE);
+		if (ret != xpcSuccess) {
+			XPC_DEACTIVATE_PARTITION(part, ret);
+
+			dev_dbg(xpc_chan, "failed to pull openclose args from "
+				"partition %d, ret=%d\n", XPC_PARTID(part),
+				ret);
+
+			/* don't bother processing IPIs anymore */
+			IPI_amo = 0;
+		}
+	}
+
+	if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) {
+		ret = xpc_pull_remote_cachelines(part, part->remote_GPs,
+						(void *) part->remote_GPs_pa,
+						XPC_GP_SIZE);
+		if (ret != xpcSuccess) {
+			XPC_DEACTIVATE_PARTITION(part, ret);
+
+			dev_dbg(xpc_chan, "failed to pull GPs from partition "
+				"%d, ret=%d\n", XPC_PARTID(part), ret);
+
+			/* don't bother processing IPIs anymore */
+			IPI_amo = 0;
+		}
+	}
+
+	return IPI_amo;
+}
+
+
+/*
+ * Allocate the local message queue and the notify queue.
+ */
+static enum xpc_retval
+xpc_allocate_local_msgqueue(struct xpc_channel *ch)
+{
+	unsigned long irq_flags;
+	int nentries;
+	size_t nbytes;
+
+
+	// >>> may want to check for ch->flags & XPC_C_DISCONNECTING between
+	// >>> iterations of the for-loop, bail if set?
+
+	// >>> should we impose a minumum #of entries? like 4 or 8?
+	for (nentries = ch->local_nentries; nentries > 0; nentries--) {
+
+		nbytes = nentries * ch->msg_size;
+		ch->local_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes,
+						(GFP_KERNEL | GFP_DMA),
+						&ch->local_msgqueue_base);
+		if (ch->local_msgqueue == NULL) {
+			continue;
+		}
+		memset(ch->local_msgqueue, 0, nbytes);
+
+		nbytes = nentries * sizeof(struct xpc_notify);
+		ch->notify_queue = kmalloc(nbytes, (GFP_KERNEL | GFP_DMA));
+		if (ch->notify_queue == NULL) {
+			kfree(ch->local_msgqueue_base);
+			ch->local_msgqueue = NULL;
+			continue;
+		}
+		memset(ch->notify_queue, 0, nbytes);
+
+		spin_lock_irqsave(&ch->lock, irq_flags);
+		if (nentries < ch->local_nentries) {
+			dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, "
+				"partid=%d, channel=%d\n", nentries,
+				ch->local_nentries, ch->partid, ch->number);
+
+			ch->local_nentries = nentries;
+		}
+		spin_unlock_irqrestore(&ch->lock, irq_flags);
+		return xpcSuccess;
+	}
+
+	dev_dbg(xpc_chan, "can't get memory for local message queue and notify "
+		"queue, partid=%d, channel=%d\n", ch->partid, ch->number);
+	return xpcNoMemory;
+}
+
+
+/*
+ * Allocate the cached remote message queue.
+ */
+static enum xpc_retval
+xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
+{
+	unsigned long irq_flags;
+	int nentries;
+	size_t nbytes;
+
+
+	DBUG_ON(ch->remote_nentries <= 0);
+
+	// >>> may want to check for ch->flags & XPC_C_DISCONNECTING between
+	// >>> iterations of the for-loop, bail if set?
+
+	// >>> should we impose a minumum #of entries? like 4 or 8?
+	for (nentries = ch->remote_nentries; nentries > 0; nentries--) {
+
+		nbytes = nentries * ch->msg_size;
+		ch->remote_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes,
+						(GFP_KERNEL | GFP_DMA),
+						&ch->remote_msgqueue_base);
+		if (ch->remote_msgqueue == NULL) {
+			continue;
+		}
+		memset(ch->remote_msgqueue, 0, nbytes);
+
+		spin_lock_irqsave(&ch->lock, irq_flags);
+		if (nentries < ch->remote_nentries) {
+			dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, "
+				"partid=%d, channel=%d\n", nentries,
+				ch->remote_nentries, ch->partid, ch->number);
+
+			ch->remote_nentries = nentries;
+		}
+		spin_unlock_irqrestore(&ch->lock, irq_flags);
+		return xpcSuccess;
+	}
+
+	dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "
+		"partid=%d, channel=%d\n", ch->partid, ch->number);
+	return xpcNoMemory;
+}
+
+
+/*
+ * Allocate message queues and other stuff associated with a channel.
+ *
+ * Note: Assumes all of the channel sizes are filled in.
+ */
+static enum xpc_retval
+xpc_allocate_msgqueues(struct xpc_channel *ch)
+{
+	unsigned long irq_flags;
+	int i;
+	enum xpc_retval ret;
+
+
+	DBUG_ON(ch->flags & XPC_C_SETUP);
+
+	if ((ret = xpc_allocate_local_msgqueue(ch)) != xpcSuccess) {
+		return ret;
+	}
+
+	if ((ret = xpc_allocate_remote_msgqueue(ch)) != xpcSuccess) {
+		kfree(ch->local_msgqueue_base);
+		ch->local_msgqueue = NULL;
+		kfree(ch->notify_queue);
+		ch->notify_queue = NULL;
+		return ret;
+	}
+
+	for (i = 0; i < ch->local_nentries; i++) {
+		/* use a semaphore as an event wait queue */
+		sema_init(&ch->notify_queue[i].sema, 0);
+	}
+
+	sema_init(&ch->teardown_sema, 0);	/* event wait */
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	ch->flags |= XPC_C_SETUP;
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Process a connect message from a remote partition.
+ *
+ * Note: xpc_process_connect() is expecting to be called with the
+ * spin_lock_irqsave held and will leave it locked upon return.
+ */
+static void
+xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	enum xpc_retval ret;
+
+
+	DBUG_ON(!spin_is_locked(&ch->lock));
+
+	if (!(ch->flags & XPC_C_OPENREQUEST) ||
+				!(ch->flags & XPC_C_ROPENREQUEST)) {
+		/* nothing more to do for now */
+		return;
+	}
+	DBUG_ON(!(ch->flags & XPC_C_CONNECTING));
+
+	if (!(ch->flags & XPC_C_SETUP)) {
+		spin_unlock_irqrestore(&ch->lock, *irq_flags);
+		ret = xpc_allocate_msgqueues(ch);
+		spin_lock_irqsave(&ch->lock, *irq_flags);
+
+		if (ret != xpcSuccess) {
+			XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags);
+		}
+		if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) {
+			return;
+		}
+
+		DBUG_ON(!(ch->flags & XPC_C_SETUP));
+		DBUG_ON(ch->local_msgqueue == NULL);
+		DBUG_ON(ch->remote_msgqueue == NULL);
+	}
+
+	if (!(ch->flags & XPC_C_OPENREPLY)) {
+		ch->flags |= XPC_C_OPENREPLY;
+		xpc_IPI_send_openreply(ch, irq_flags);
+	}
+
+	if (!(ch->flags & XPC_C_ROPENREPLY)) {
+		return;
+	}
+
+	DBUG_ON(ch->remote_msgqueue_pa == 0);
+
+	ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP);	/* clear all else */
+
+	dev_info(xpc_chan, "channel %d to partition %d connected\n",
+		ch->number, ch->partid);
+
+	spin_unlock_irqrestore(&ch->lock, *irq_flags);
+	xpc_create_kthreads(ch, 1);
+	spin_lock_irqsave(&ch->lock, *irq_flags);
+}
+
+
+/*
+ * Free up message queues and other stuff that were allocated for the specified
+ * channel.
+ *
+ * Note: ch->reason and ch->reason_line are left set for debugging purposes,
+ * they're cleared when XPC_C_DISCONNECTED is cleared.
+ */
+static void
+xpc_free_msgqueues(struct xpc_channel *ch)
+{
+	DBUG_ON(!spin_is_locked(&ch->lock));
+	DBUG_ON(atomic_read(&ch->n_to_notify) != 0);
+
+	ch->remote_msgqueue_pa = 0;
+	ch->func = NULL;
+	ch->key = NULL;
+	ch->msg_size = 0;
+	ch->local_nentries = 0;
+	ch->remote_nentries = 0;
+	ch->kthreads_assigned_limit = 0;
+	ch->kthreads_idle_limit = 0;
+
+	ch->local_GP->get = 0;
+	ch->local_GP->put = 0;
+	ch->remote_GP.get = 0;
+	ch->remote_GP.put = 0;
+	ch->w_local_GP.get = 0;
+	ch->w_local_GP.put = 0;
+	ch->w_remote_GP.get = 0;
+	ch->w_remote_GP.put = 0;
+	ch->next_msg_to_pull = 0;
+
+	if (ch->flags & XPC_C_SETUP) {
+		ch->flags &= ~XPC_C_SETUP;
+
+		dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n",
+			ch->flags, ch->partid, ch->number);
+
+		kfree(ch->local_msgqueue_base);
+		ch->local_msgqueue = NULL;
+		kfree(ch->remote_msgqueue_base);
+		ch->remote_msgqueue = NULL;
+		kfree(ch->notify_queue);
+		ch->notify_queue = NULL;
+
+		/* in case someone is waiting for the teardown to complete */
+		up(&ch->teardown_sema);
+	}
+}
+
+
+/*
+ * spin_lock_irqsave() is expected to be held on entry.
+ */
+static void
+xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+	struct xpc_partition *part = &xpc_partitions[ch->partid];
+	u32 ch_flags = ch->flags;
+
+
+	DBUG_ON(!spin_is_locked(&ch->lock));
+
+	if (!(ch->flags & XPC_C_DISCONNECTING)) {
+		return;
+	}
+
+	DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
+
+	/* make sure all activity has settled down first */
+
+	if (atomic_read(&ch->references) > 0) {
+		return;
+	}
+	DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);
+
+	/* it's now safe to free the channel's message queues */
+
+	xpc_free_msgqueues(ch);
+	DBUG_ON(ch->flags & XPC_C_SETUP);
+
+	if (part->act_state != XPC_P_DEACTIVATING) {
+
+		/* as long as the other side is up do the full protocol */
+
+		if (!(ch->flags & XPC_C_RCLOSEREQUEST)) {
+			return;
+		}
+
+		if (!(ch->flags & XPC_C_CLOSEREPLY)) {
+			ch->flags |= XPC_C_CLOSEREPLY;
+			xpc_IPI_send_closereply(ch, irq_flags);
+		}
+
+		if (!(ch->flags & XPC_C_RCLOSEREPLY)) {
+			return;
+		}
+	}
+
+	/* both sides are disconnected now */
+
+	ch->flags = XPC_C_DISCONNECTED;	/* clear all flags, but this one */
+
+	atomic_dec(&part->nchannels_active);
+
+	if (ch_flags & XPC_C_WASCONNECTED) {
+		dev_info(xpc_chan, "channel %d to partition %d disconnected, "
+			"reason=%d\n", ch->number, ch->partid, ch->reason);
+	}
+}
+
+
+/*
+ * Process a change in the channel's remote connection state.
+ */
+static void
+xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number,
+				u8 IPI_flags)
+{
+	unsigned long irq_flags;
+	struct xpc_openclose_args *args =
+				&part->remote_openclose_args[ch_number];
+	struct xpc_channel *ch = &part->channels[ch_number];
+	enum xpc_retval reason;
+
+
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+
+
+	if (IPI_flags & XPC_IPI_CLOSEREQUEST) {
+
+		dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received "
+			"from partid=%d, channel=%d\n", args->reason,
+			ch->partid, ch->number);
+
+		/*
+		 * If RCLOSEREQUEST is set, we're probably waiting for
+		 * RCLOSEREPLY. We should find it and a ROPENREQUEST packed
+		 * with this RCLOSEQREUQEST in the IPI_flags.
+		 */
+
+		if (ch->flags & XPC_C_RCLOSEREQUEST) {
+			DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING));
+			DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
+			DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY));
+			DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY);
+
+			DBUG_ON(!(IPI_flags & XPC_IPI_CLOSEREPLY));
+			IPI_flags &= ~XPC_IPI_CLOSEREPLY;
+			ch->flags |= XPC_C_RCLOSEREPLY;
+
+			/* both sides have finished disconnecting */
+			xpc_process_disconnect(ch, &irq_flags);
+		}
+
+		if (ch->flags & XPC_C_DISCONNECTED) {
+			// >>> explain this section
+
+			if (!(IPI_flags & XPC_IPI_OPENREQUEST)) {
+				DBUG_ON(part->act_state !=
+							XPC_P_DEACTIVATING);
+				spin_unlock_irqrestore(&ch->lock, irq_flags);
+				return;
+			}
+
+			XPC_SET_REASON(ch, 0, 0);
+			ch->flags &= ~XPC_C_DISCONNECTED;
+
+			atomic_inc(&part->nchannels_active);
+			ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST);
+		}
+
+		IPI_flags &= ~(XPC_IPI_OPENREQUEST | XPC_IPI_OPENREPLY);
+
+		/*
+		 * The meaningful CLOSEREQUEST connection state fields are:
+		 *      reason = reason connection is to be closed
+		 */
+
+		ch->flags |= XPC_C_RCLOSEREQUEST;
+
+		if (!(ch->flags & XPC_C_DISCONNECTING)) {
+			reason = args->reason;
+			if (reason <= xpcSuccess || reason > xpcUnknownReason) {
+				reason = xpcUnknownReason;
+			} else if (reason == xpcUnregistering) {
+				reason = xpcOtherUnregistering;
+			}
+
+			XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
+		} else {
+			xpc_process_disconnect(ch, &irq_flags);
+		}
+	}
+
+
+	if (IPI_flags & XPC_IPI_CLOSEREPLY) {
+
+		dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d,"
+			" channel=%d\n", ch->partid, ch->number);
+
+		if (ch->flags & XPC_C_DISCONNECTED) {
+			DBUG_ON(part->act_state != XPC_P_DEACTIVATING);
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			return;
+		}
+
+		DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
+		DBUG_ON(!(ch->flags & XPC_C_RCLOSEREQUEST));
+
+		ch->flags |= XPC_C_RCLOSEREPLY;
+
+		if (ch->flags & XPC_C_CLOSEREPLY) {
+			/* both sides have finished disconnecting */
+			xpc_process_disconnect(ch, &irq_flags);
+		}
+	}
+
+
+	if (IPI_flags & XPC_IPI_OPENREQUEST) {
+
+		dev_dbg(xpc_chan, "XPC_IPI_OPENREQUEST (msg_size=%d, "
+			"local_nentries=%d) received from partid=%d, "
+			"channel=%d\n", args->msg_size, args->local_nentries,
+			ch->partid, ch->number);
+
+		if ((ch->flags & XPC_C_DISCONNECTING) ||
+					part->act_state == XPC_P_DEACTIVATING) {
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			return;
+		}
+		DBUG_ON(!(ch->flags & (XPC_C_DISCONNECTED |
+							XPC_C_OPENREQUEST)));
+		DBUG_ON(ch->flags & (XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
+					XPC_C_OPENREPLY | XPC_C_CONNECTED));
+
+		/*
+		 * The meaningful OPENREQUEST connection state fields are:
+		 *      msg_size = size of channel's messages in bytes
+		 *      local_nentries = remote partition's local_nentries
+		 */
+		DBUG_ON(args->msg_size == 0);
+		DBUG_ON(args->local_nentries == 0);
+
+		ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING);
+		ch->remote_nentries = args->local_nentries;
+
+
+		if (ch->flags & XPC_C_OPENREQUEST) {
+			if (args->msg_size != ch->msg_size) {
+				XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+								&irq_flags);
+				spin_unlock_irqrestore(&ch->lock, irq_flags);
+				return;
+			}
+		} else {
+			ch->msg_size = args->msg_size;
+
+			XPC_SET_REASON(ch, 0, 0);
+			ch->flags &= ~XPC_C_DISCONNECTED;
+
+			atomic_inc(&part->nchannels_active);
+		}
+
+		xpc_process_connect(ch, &irq_flags);
+	}
+
+
+	if (IPI_flags & XPC_IPI_OPENREPLY) {
+
+		dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY (local_msgqueue_pa=0x%lx, "
+			"local_nentries=%d, remote_nentries=%d) received from "
+			"partid=%d, channel=%d\n", args->local_msgqueue_pa,
+			args->local_nentries, args->remote_nentries,
+			ch->partid, ch->number);
+
+		if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) {
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			return;
+		}
+		DBUG_ON(!(ch->flags & XPC_C_OPENREQUEST));
+		DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST));
+		DBUG_ON(ch->flags & XPC_C_CONNECTED);
+
+		/*
+		 * The meaningful OPENREPLY connection state fields are:
+		 *      local_msgqueue_pa = physical address of remote
+		 *			    partition's local_msgqueue
+		 *      local_nentries = remote partition's local_nentries
+		 *      remote_nentries = remote partition's remote_nentries
+		 */
+		DBUG_ON(args->local_msgqueue_pa == 0);
+		DBUG_ON(args->local_nentries == 0);
+		DBUG_ON(args->remote_nentries == 0);
+
+		ch->flags |= XPC_C_ROPENREPLY;
+		ch->remote_msgqueue_pa = args->local_msgqueue_pa;
+
+		if (args->local_nentries < ch->remote_nentries) {
+			dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new "
+				"remote_nentries=%d, old remote_nentries=%d, "
+				"partid=%d, channel=%d\n",
+				args->local_nentries, ch->remote_nentries,
+				ch->partid, ch->number);
+
+			ch->remote_nentries = args->local_nentries;
+		}
+		if (args->remote_nentries < ch->local_nentries) {
+			dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new "
+				"local_nentries=%d, old local_nentries=%d, "
+				"partid=%d, channel=%d\n",
+				args->remote_nentries, ch->local_nentries,
+				ch->partid, ch->number);
+
+			ch->local_nentries = args->remote_nentries;
+		}
+
+		xpc_process_connect(ch, &irq_flags);
+	}
+
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+}
+
+
+/*
+ * Attempt to establish a channel connection to a remote partition.
+ */
+static enum xpc_retval
+xpc_connect_channel(struct xpc_channel *ch)
+{
+	unsigned long irq_flags;
+	struct xpc_registration *registration = &xpc_registrations[ch->number];
+
+
+	if (down_interruptible(&registration->sema) != 0) {
+		return xpcInterrupted;
+	}
+
+	if (!XPC_CHANNEL_REGISTERED(ch->number)) {
+		up(&registration->sema);
+		return xpcUnregistered;
+	}
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+
+	DBUG_ON(ch->flags & XPC_C_CONNECTED);
+	DBUG_ON(ch->flags & XPC_C_OPENREQUEST);
+
+	if (ch->flags & XPC_C_DISCONNECTING) {
+		spin_unlock_irqrestore(&ch->lock, irq_flags);
+		up(&registration->sema);
+		return ch->reason;
+	}
+
+
+	/* add info from the channel connect registration to the channel */
+
+	ch->kthreads_assigned_limit = registration->assigned_limit;
+	ch->kthreads_idle_limit = registration->idle_limit;
+	DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);
+	DBUG_ON(atomic_read(&ch->kthreads_idle) != 0);
+	DBUG_ON(atomic_read(&ch->kthreads_active) != 0);
+
+	ch->func = registration->func;
+	DBUG_ON(registration->func == NULL);
+	ch->key = registration->key;
+
+	ch->local_nentries = registration->nentries;
+
+	if (ch->flags & XPC_C_ROPENREQUEST) {
+		if (registration->msg_size != ch->msg_size) {
+			/* the local and remote sides aren't the same */
+
+			/*
+			 * Because XPC_DISCONNECT_CHANNEL() can block we're
+			 * forced to up the registration sema before we unlock
+			 * the channel lock. But that's okay here because we're
+			 * done with the part that required the registration
+			 * sema. XPC_DISCONNECT_CHANNEL() requires that the
+			 * channel lock be locked and will unlock and relock
+			 * the channel lock as needed.
+			 */
+			up(&registration->sema);
+			XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+								&irq_flags);
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			return xpcUnequalMsgSizes;
+		}
+	} else {
+		ch->msg_size = registration->msg_size;
+
+		XPC_SET_REASON(ch, 0, 0);
+		ch->flags &= ~XPC_C_DISCONNECTED;
+
+		atomic_inc(&xpc_partitions[ch->partid].nchannels_active);
+	}
+
+	up(&registration->sema);
+
+
+	/* initiate the connection */
+
+	ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING);
+	xpc_IPI_send_openrequest(ch, &irq_flags);
+
+	xpc_process_connect(ch, &irq_flags);
+
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Notify those who wanted to be notified upon delivery of their message.
+ */
+static void
+xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put)
+{
+	struct xpc_notify *notify;
+	u8 notify_type;
+	s64 get = ch->w_remote_GP.get - 1;
+
+
+	while (++get < put && atomic_read(&ch->n_to_notify) > 0) {
+
+		notify = &ch->notify_queue[get % ch->local_nentries];
+
+		/*
+		 * See if the notify entry indicates it was associated with
+		 * a message who's sender wants to be notified. It is possible
+		 * that it is, but someone else is doing or has done the
+		 * notification.
+		 */
+		notify_type = notify->type;
+		if (notify_type == 0 ||
+				cmpxchg(&notify->type, notify_type, 0) !=
+								notify_type) {
+			continue;
+		}
+
+		DBUG_ON(notify_type != XPC_N_CALL);
+
+		atomic_dec(&ch->n_to_notify);
+
+		if (notify->func != NULL) {
+			dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, "
+				"msg_number=%ld, partid=%d, channel=%d\n",
+				(void *) notify, get, ch->partid, ch->number);
+
+			notify->func(reason, ch->partid, ch->number,
+								notify->key);
+
+			dev_dbg(xpc_chan, "notify->func() returned, "
+				"notify=0x%p, msg_number=%ld, partid=%d, "
+				"channel=%d\n", (void *) notify, get,
+				ch->partid, ch->number);
+		}
+	}
+}
+
+
+/*
+ * Clear some of the msg flags in the local message queue.
+ */
+static inline void
+xpc_clear_local_msgqueue_flags(struct xpc_channel *ch)
+{
+	struct xpc_msg *msg;
+	s64 get;
+
+
+	get = ch->w_remote_GP.get;
+	do {
+		msg = (struct xpc_msg *) ((u64) ch->local_msgqueue +
+				(get % ch->local_nentries) * ch->msg_size);
+		msg->flags = 0;
+	} while (++get < (volatile s64) ch->remote_GP.get);
+}
+
+
+/*
+ * Clear some of the msg flags in the remote message queue.
+ */
+static inline void
+xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch)
+{
+	struct xpc_msg *msg;
+	s64 put;
+
+
+	put = ch->w_remote_GP.put;
+	do {
+		msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue +
+				(put % ch->remote_nentries) * ch->msg_size);
+		msg->flags = 0;
+	} while (++put < (volatile s64) ch->remote_GP.put);
+}
+
+
+static void
+xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
+{
+	struct xpc_channel *ch = &part->channels[ch_number];
+	int nmsgs_sent;
+
+
+	ch->remote_GP = part->remote_GPs[ch_number];
+
+
+	/* See what, if anything, has changed for each connected channel */
+
+	xpc_msgqueue_ref(ch);
+
+	if (ch->w_remote_GP.get == ch->remote_GP.get &&
+				ch->w_remote_GP.put == ch->remote_GP.put) {
+		/* nothing changed since GPs were last pulled */
+		xpc_msgqueue_deref(ch);
+		return;
+	}
+
+	if (!(ch->flags & XPC_C_CONNECTED)){
+		xpc_msgqueue_deref(ch);
+		return;
+	}
+
+
+	/*
+	 * First check to see if messages recently sent by us have been
+	 * received by the other side. (The remote GET value will have
+	 * changed since we last looked at it.)
+	 */
+
+	if (ch->w_remote_GP.get != ch->remote_GP.get) {
+
+		/*
+		 * We need to notify any senders that want to be notified
+		 * that their sent messages have been received by their
+		 * intended recipients. We need to do this before updating
+		 * w_remote_GP.get so that we don't allocate the same message
+		 * queue entries prematurely (see xpc_allocate_msg()).
+		 */
+		if (atomic_read(&ch->n_to_notify) > 0) {
+			/*
+			 * Notify senders that messages sent have been
+			 * received and delivered by the other side.
+			 */
+			xpc_notify_senders(ch, xpcMsgDelivered,
+							ch->remote_GP.get);
+		}
+
+		/*
+		 * Clear msg->flags in previously sent messages, so that
+		 * they're ready for xpc_allocate_msg().
+		 */
+		xpc_clear_local_msgqueue_flags(ch);
+
+		(volatile s64) ch->w_remote_GP.get = ch->remote_GP.get;
+
+		dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, "
+			"channel=%d\n", ch->w_remote_GP.get, ch->partid,
+			ch->number);
+
+		/*
+		 * If anyone was waiting for message queue entries to become
+		 * available, wake them up.
+		 */
+		if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) {
+			wake_up(&ch->msg_allocate_wq);
+		}
+	}
+
+
+	/*
+	 * Now check for newly sent messages by the other side. (The remote
+	 * PUT value will have changed since we last looked at it.)
+	 */
+
+	if (ch->w_remote_GP.put != ch->remote_GP.put) {
+		/*
+		 * Clear msg->flags in previously received messages, so that
+		 * they're ready for xpc_get_deliverable_msg().
+		 */
+		xpc_clear_remote_msgqueue_flags(ch);
+
+		(volatile s64) ch->w_remote_GP.put = ch->remote_GP.put;
+
+		dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, "
+			"channel=%d\n", ch->w_remote_GP.put, ch->partid,
+			ch->number);
+
+		nmsgs_sent = ch->w_remote_GP.put - ch->w_local_GP.get;
+		if (nmsgs_sent > 0) {
+			dev_dbg(xpc_chan, "msgs waiting to be copied and "
+				"delivered=%d, partid=%d, channel=%d\n",
+				nmsgs_sent, ch->partid, ch->number);
+
+			if (ch->flags & XPC_C_CONNECTCALLOUT) {
+				xpc_activate_kthreads(ch, nmsgs_sent);
+			}
+		}
+	}
+
+	xpc_msgqueue_deref(ch);
+}
+
+
+void
+xpc_process_channel_activity(struct xpc_partition *part)
+{
+	unsigned long irq_flags;
+	u64 IPI_amo, IPI_flags;
+	struct xpc_channel *ch;
+	int ch_number;
+
+
+	IPI_amo = xpc_get_IPI_flags(part);
+
+	/*
+	 * Initiate channel connections for registered channels.
+	 *
+	 * For each connected channel that has pending messages activate idle
+	 * kthreads and/or create new kthreads as needed.
+	 */
+
+	for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
+		ch = &part->channels[ch_number];
+
+
+		/*
+		 * Process any open or close related IPI flags, and then deal
+		 * with connecting or disconnecting the channel as required.
+		 */
+
+		IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number);
+
+		if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) {
+			xpc_process_openclose_IPI(part, ch_number, IPI_flags);
+		}
+
+
+		if (ch->flags & XPC_C_DISCONNECTING) {
+			spin_lock_irqsave(&ch->lock, irq_flags);
+			xpc_process_disconnect(ch, &irq_flags);
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			continue;
+		}
+
+		if (part->act_state == XPC_P_DEACTIVATING) {
+			continue;
+		}
+
+		if (!(ch->flags & XPC_C_CONNECTED)) {
+			if (!(ch->flags & XPC_C_OPENREQUEST)) {
+				DBUG_ON(ch->flags & XPC_C_SETUP);
+				(void) xpc_connect_channel(ch);
+			} else {
+				spin_lock_irqsave(&ch->lock, irq_flags);
+				xpc_process_connect(ch, &irq_flags);
+				spin_unlock_irqrestore(&ch->lock, irq_flags);
+			}
+			continue;
+		}
+
+
+		/*
+		 * Process any message related IPI flags, this may involve the
+		 * activation of kthreads to deliver any pending messages sent
+		 * from the other partition.
+		 */
+
+		if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) {
+			xpc_process_msg_IPI(part, ch_number);
+		}
+	}
+}
+
+
+/*
+ * XPC's heartbeat code calls this function to inform XPC that a partition has
+ * gone down.  XPC responds by tearing down the XPartition Communication
+ * infrastructure used for the just downed partition.
+ *
+ * XPC's heartbeat code will never call this function and xpc_partition_up()
+ * at the same time. Nor will it ever make multiple calls to either function
+ * at the same time.
+ */
+void
+xpc_partition_down(struct xpc_partition *part, enum xpc_retval reason)
+{
+	unsigned long irq_flags;
+	int ch_number;
+	struct xpc_channel *ch;
+
+
+	dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n",
+		XPC_PARTID(part), reason);
+
+	if (!xpc_part_ref(part)) {
+		/* infrastructure for this partition isn't currently set up */
+		return;
+	}
+
+
+	/* disconnect all channels associated with the downed partition */
+
+	for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
+		ch = &part->channels[ch_number];
+
+
+		xpc_msgqueue_ref(ch);
+		spin_lock_irqsave(&ch->lock, irq_flags);
+
+		XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
+
+		spin_unlock_irqrestore(&ch->lock, irq_flags);
+		xpc_msgqueue_deref(ch);
+	}
+
+	xpc_wakeup_channel_mgr(part);
+
+	xpc_part_deref(part);
+}
+
+
+/*
+ * Teardown the infrastructure necessary to support XPartition Communication
+ * between the specified remote partition and the local one.
+ */
+void
+xpc_teardown_infrastructure(struct xpc_partition *part)
+{
+	partid_t partid = XPC_PARTID(part);
+
+
+	/*
+	 * We start off by making this partition inaccessible to local
+	 * processes by marking it as no longer setup. Then we make it
+	 * inaccessible to remote processes by clearing the XPC per partition
+	 * specific variable's magic # (which indicates that these variables
+	 * are no longer valid) and by ignoring all XPC notify IPIs sent to
+	 * this partition.
+	 */
+
+	DBUG_ON(atomic_read(&part->nchannels_active) != 0);
+	DBUG_ON(part->setup_state != XPC_P_SETUP);
+	part->setup_state = XPC_P_WTEARDOWN;
+
+	xpc_vars_part[partid].magic = 0;
+
+
+	free_irq(SGI_XPC_NOTIFY, (void *) (u64) partid);
+
+
+	/*
+	 * Before proceding with the teardown we have to wait until all
+	 * existing references cease.
+	 */
+	wait_event(part->teardown_wq, (atomic_read(&part->references) == 0));
+
+
+	/* now we can begin tearing down the infrastructure */
+
+	part->setup_state = XPC_P_TORNDOWN;
+
+	/* in case we've still got outstanding timers registered... */
+	del_timer_sync(&part->dropped_IPI_timer);
+
+	kfree(part->remote_openclose_args_base);
+	part->remote_openclose_args = NULL;
+	kfree(part->local_openclose_args_base);
+	part->local_openclose_args = NULL;
+	kfree(part->remote_GPs_base);
+	part->remote_GPs = NULL;
+	kfree(part->local_GPs_base);
+	part->local_GPs = NULL;
+	kfree(part->channels);
+	part->channels = NULL;
+	part->local_IPI_amo_va = NULL;
+}
+
+
+/*
+ * Called by XP at the time of channel connection registration to cause
+ * XPC to establish connections to all currently active partitions.
+ */
+void
+xpc_initiate_connect(int ch_number)
+{
+	partid_t partid;
+	struct xpc_partition *part;
+	struct xpc_channel *ch;
+
+
+	DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		if (xpc_part_ref(part)) {
+			ch = &part->channels[ch_number];
+
+			if (!(ch->flags & XPC_C_DISCONNECTING)) {
+				DBUG_ON(ch->flags & XPC_C_OPENREQUEST);
+				DBUG_ON(ch->flags & XPC_C_CONNECTED);
+				DBUG_ON(ch->flags & XPC_C_SETUP);
+
+				/*
+				 * Initiate the establishment of a connection
+				 * on the newly registered channel to the
+				 * remote partition.
+				 */
+				xpc_wakeup_channel_mgr(part);
+			}
+
+			xpc_part_deref(part);
+		}
+	}
+}
+
+
+void
+xpc_connected_callout(struct xpc_channel *ch)
+{
+	unsigned long irq_flags;
+
+
+	/* let the registerer know that a connection has been established */
+
+	if (ch->func != NULL) {
+		dev_dbg(xpc_chan, "ch->func() called, reason=xpcConnected, "
+			"partid=%d, channel=%d\n", ch->partid, ch->number);
+
+		ch->func(xpcConnected, ch->partid, ch->number,
+				(void *) (u64) ch->local_nentries, ch->key);
+
+		dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, "
+			"partid=%d, channel=%d\n", ch->partid, ch->number);
+	}
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	ch->flags |= XPC_C_CONNECTCALLOUT;
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+}
+
+
+/*
+ * Called by XP at the time of channel connection unregistration to cause
+ * XPC to teardown all current connections for the specified channel.
+ *
+ * Before returning xpc_initiate_disconnect() will wait until all connections
+ * on the specified channel have been closed/torndown. So the caller can be
+ * assured that they will not be receiving any more callouts from XPC to the
+ * function they registered via xpc_connect().
+ *
+ * Arguments:
+ *
+ *	ch_number - channel # to unregister.
+ */
+void
+xpc_initiate_disconnect(int ch_number)
+{
+	unsigned long irq_flags;
+	partid_t partid;
+	struct xpc_partition *part;
+	struct xpc_channel *ch;
+
+
+	DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+
+	/* initiate the channel disconnect for every active partition */
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		if (xpc_part_ref(part)) {
+			ch = &part->channels[ch_number];
+			xpc_msgqueue_ref(ch);
+
+			spin_lock_irqsave(&ch->lock, irq_flags);
+
+			XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering,
+								&irq_flags);
+
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+			xpc_msgqueue_deref(ch);
+			xpc_part_deref(part);
+		}
+	}
+
+	xpc_disconnect_wait(ch_number);
+}
+
+
+/*
+ * To disconnect a channel, and reflect it back to all who may be waiting.
+ *
+ * >>> An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by
+ * >>> xpc_free_msgqueues().
+ *
+ * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN.
+ */
+void
+xpc_disconnect_channel(const int line, struct xpc_channel *ch,
+			enum xpc_retval reason, unsigned long *irq_flags)
+{
+	u32 flags;
+
+
+	DBUG_ON(!spin_is_locked(&ch->lock));
+
+	if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) {
+		return;
+	}
+	DBUG_ON(!(ch->flags & (XPC_C_CONNECTING | XPC_C_CONNECTED)));
+
+	dev_dbg(xpc_chan, "reason=%d, line=%d, partid=%d, channel=%d\n",
+		reason, line, ch->partid, ch->number);
+
+	XPC_SET_REASON(ch, reason, line);
+
+	flags = ch->flags;
+	/* some of these may not have been set */
+	ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY |
+			XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
+			XPC_C_CONNECTING | XPC_C_CONNECTED);
+
+	ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING);
+	xpc_IPI_send_closerequest(ch, irq_flags);
+
+	if (flags & XPC_C_CONNECTED) {
+		ch->flags |= XPC_C_WASCONNECTED;
+	}
+
+	if (atomic_read(&ch->kthreads_idle) > 0) {
+		/* wake all idle kthreads so they can exit */
+		wake_up_all(&ch->idle_wq);
+	}
+
+	spin_unlock_irqrestore(&ch->lock, *irq_flags);
+
+
+	/* wake those waiting to allocate an entry from the local msg queue */
+
+	if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) {
+		wake_up(&ch->msg_allocate_wq);
+	}
+
+	/* wake those waiting for notify completion */
+
+	if (atomic_read(&ch->n_to_notify) > 0) {
+		xpc_notify_senders(ch, reason, ch->w_local_GP.put);
+	}
+
+	spin_lock_irqsave(&ch->lock, *irq_flags);
+}
+
+
+void
+xpc_disconnected_callout(struct xpc_channel *ch)
+{
+	/*
+	 * Let the channel's registerer know that the channel is now
+	 * disconnected. We don't want to do this if the registerer was never
+	 * informed of a connection being made, unless the disconnect was for
+	 * abnormal reasons.
+	 */
+
+	if (ch->func != NULL) {
+		dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, "
+			"channel=%d\n", ch->reason, ch->partid, ch->number);
+
+		ch->func(ch->reason, ch->partid, ch->number, NULL, ch->key);
+
+		dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, "
+			"channel=%d\n", ch->reason, ch->partid, ch->number);
+	}
+}
+
+
+/*
+ * Wait for a message entry to become available for the specified channel,
+ * but don't wait any longer than 1 jiffy.
+ */
+static enum xpc_retval
+xpc_allocate_msg_wait(struct xpc_channel *ch)
+{
+	enum xpc_retval ret;
+
+
+	if (ch->flags & XPC_C_DISCONNECTING) {
+		DBUG_ON(ch->reason == xpcInterrupted);  // >>> Is this true?
+		return ch->reason;
+	}
+
+	atomic_inc(&ch->n_on_msg_allocate_wq);
+	ret = interruptible_sleep_on_timeout(&ch->msg_allocate_wq, 1);
+	atomic_dec(&ch->n_on_msg_allocate_wq);
+
+	if (ch->flags & XPC_C_DISCONNECTING) {
+		ret = ch->reason;
+		DBUG_ON(ch->reason == xpcInterrupted);  // >>> Is this true?
+	} else if (ret == 0) {
+		ret = xpcTimeout;
+	} else {
+		ret = xpcInterrupted;
+	}
+
+	return ret;
+}
+
+
+/*
+ * Allocate an entry for a message from the message queue associated with the
+ * specified channel.
+ */
+static enum xpc_retval
+xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
+			struct xpc_msg **address_of_msg)
+{
+	struct xpc_msg *msg;
+	enum xpc_retval ret;
+	s64 put;
+
+
+	/* this reference will be dropped in xpc_send_msg() */
+	xpc_msgqueue_ref(ch);
+
+	if (ch->flags & XPC_C_DISCONNECTING) {
+		xpc_msgqueue_deref(ch);
+		return ch->reason;
+	}
+	if (!(ch->flags & XPC_C_CONNECTED)) {
+		xpc_msgqueue_deref(ch);
+		return xpcNotConnected;
+	}
+
+
+	/*
+	 * Get the next available message entry from the local message queue.
+	 * If none are available, we'll make sure that we grab the latest
+	 * GP values.
+	 */
+	ret = xpcTimeout;
+
+	while (1) {
+
+		put = (volatile s64) ch->w_local_GP.put;
+		if (put - (volatile s64) ch->w_remote_GP.get <
+							ch->local_nentries) {
+
+			/* There are available message entries. We need to try
+			 * to secure one for ourselves. We'll do this by trying
+			 * to increment w_local_GP.put as long as someone else
+			 * doesn't beat us to it. If they do, we'll have to
+			 * try again.
+		 	 */
+			if (cmpxchg(&ch->w_local_GP.put, put, put + 1) ==
+									put) {
+				/* we got the entry referenced by put */
+				break;
+			}
+			continue;	/* try again */
+		}
+
+
+		/*
+		 * There aren't any available msg entries at this time.
+		 *
+		 * In waiting for a message entry to become available,
+		 * we set a timeout in case the other side is not
+		 * sending completion IPIs. This lets us fake an IPI
+		 * that will cause the IPI handler to fetch the latest
+		 * GP values as if an IPI was sent by the other side.
+		 */
+		if (ret == xpcTimeout) {
+			xpc_IPI_send_local_msgrequest(ch);
+		}
+
+		if (flags & XPC_NOWAIT) {
+			xpc_msgqueue_deref(ch);
+			return xpcNoWait;
+		}
+
+		ret = xpc_allocate_msg_wait(ch);
+		if (ret != xpcInterrupted && ret != xpcTimeout) {
+			xpc_msgqueue_deref(ch);
+			return ret;
+		}
+	}
+
+
+	/* get the message's address and initialize it */
+	msg = (struct xpc_msg *) ((u64) ch->local_msgqueue +
+				(put % ch->local_nentries) * ch->msg_size);
+
+
+	DBUG_ON(msg->flags != 0);
+	msg->number = put;
+
+	dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, "
+		"msg_number=%ld, partid=%d, channel=%d\n", put + 1,
+		(void *) msg, msg->number, ch->partid, ch->number);
+
+	*address_of_msg = msg;
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Allocate an entry for a message from the message queue associated with the
+ * specified channel. NOTE that this routine can sleep waiting for a message
+ * entry to become available. To not sleep, pass in the XPC_NOWAIT flag.
+ *
+ * Arguments:
+ *
+ *	partid - ID of partition to which the channel is connected.
+ *	ch_number - channel #.
+ *	flags - see xpc.h for valid flags.
+ *	payload - address of the allocated payload area pointer (filled in on
+ * 	          return) in which the user-defined message is constructed.
+ */
+enum xpc_retval
+xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+{
+	struct xpc_partition *part = &xpc_partitions[partid];
+	enum xpc_retval ret = xpcUnknownReason;
+	struct xpc_msg *msg;
+
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
+
+	*payload = NULL;
+
+	if (xpc_part_ref(part)) {
+		ret = xpc_allocate_msg(&part->channels[ch_number], flags, &msg);
+		xpc_part_deref(part);
+
+		if (msg != NULL) {
+			*payload = &msg->payload;
+		}
+	}
+
+	return ret;
+}
+
+
+/*
+ * Now we actually send the messages that are ready to be sent by advancing
+ * the local message queue's Put value and then send an IPI to the recipient
+ * partition.
+ */
+static void
+xpc_send_msgs(struct xpc_channel *ch, s64 initial_put)
+{
+	struct xpc_msg *msg;
+	s64 put = initial_put + 1;
+	int send_IPI = 0;
+
+
+	while (1) {
+
+		while (1) {
+			if (put == (volatile s64) ch->w_local_GP.put) {
+				break;
+			}
+
+			msg = (struct xpc_msg *) ((u64) ch->local_msgqueue +
+			       (put % ch->local_nentries) * ch->msg_size);
+
+			if (!(msg->flags & XPC_M_READY)) {
+				break;
+			}
+
+			put++;
+		}
+
+		if (put == initial_put) {
+			/* nothing's changed */
+			break;
+		}
+
+		if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) !=
+								initial_put) {
+			/* someone else beat us to it */
+			DBUG_ON((volatile s64) ch->local_GP->put < initial_put);
+			break;
+		}
+
+		/* we just set the new value of local_GP->put */
+
+		dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, "
+			"channel=%d\n", put, ch->partid, ch->number);
+
+		send_IPI = 1;
+
+		/*
+		 * We need to ensure that the message referenced by
+		 * local_GP->put is not XPC_M_READY or that local_GP->put
+		 * equals w_local_GP.put, so we'll go have a look.
+		 */
+		initial_put = put;
+	}
+
+	if (send_IPI) {
+		xpc_IPI_send_msgrequest(ch);
+	}
+}
+
+
+/*
+ * Common code that does the actual sending of the message by advancing the
+ * local message queue's Put value and sends an IPI to the partition the
+ * message is being sent to.
+ */
+static enum xpc_retval
+xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
+			xpc_notify_func func, void *key)
+{
+	enum xpc_retval ret = xpcSuccess;
+	struct xpc_notify *notify = NULL;   // >>> to keep the compiler happy!!
+	s64 put, msg_number = msg->number;
+
+
+	DBUG_ON(notify_type == XPC_N_CALL && func == NULL);
+	DBUG_ON((((u64) msg - (u64) ch->local_msgqueue) / ch->msg_size) !=
+					msg_number % ch->local_nentries);
+	DBUG_ON(msg->flags & XPC_M_READY);
+
+	if (ch->flags & XPC_C_DISCONNECTING) {
+		/* drop the reference grabbed in xpc_allocate_msg() */
+		xpc_msgqueue_deref(ch);
+		return ch->reason;
+	}
+
+	if (notify_type != 0) {
+		/*
+		 * Tell the remote side to send an ACK interrupt when the
+		 * message has been delivered.
+		 */
+		msg->flags |= XPC_M_INTERRUPT;
+
+		atomic_inc(&ch->n_to_notify);
+
+		notify = &ch->notify_queue[msg_number % ch->local_nentries];
+		notify->func = func;
+		notify->key = key;
+		(volatile u8) notify->type = notify_type;
+
+		// >>> is a mb() needed here?
+
+		if (ch->flags & XPC_C_DISCONNECTING) {
+			/*
+			 * An error occurred between our last error check and
+			 * this one. We will try to clear the type field from
+			 * the notify entry. If we succeed then
+			 * xpc_disconnect_channel() didn't already process
+			 * the notify entry.
+			 */
+			if (cmpxchg(&notify->type, notify_type, 0) ==
+								notify_type) {
+				atomic_dec(&ch->n_to_notify);
+				ret = ch->reason;
+			}
+
+			/* drop the reference grabbed in xpc_allocate_msg() */
+			xpc_msgqueue_deref(ch);
+			return ret;
+		}
+	}
+
+	msg->flags |= XPC_M_READY;
+
+	/*
+	 * The preceding store of msg->flags must occur before the following
+	 * load of ch->local_GP->put.
+	 */
+	mb();
+
+	/* see if the message is next in line to be sent, if so send it */
+
+	put = ch->local_GP->put;
+	if (put == msg_number) {
+		xpc_send_msgs(ch, put);
+	}
+
+	/* drop the reference grabbed in xpc_allocate_msg() */
+	xpc_msgqueue_deref(ch);
+	return ret;
+}
+
+
+/*
+ * Send a message previously allocated using xpc_initiate_allocate() on the
+ * specified channel connected to the specified partition.
+ *
+ * This routine will not wait for the message to be received, nor will
+ * notification be given when it does happen. Once this routine has returned
+ * the message entry allocated via xpc_initiate_allocate() is no longer
+ * accessable to the caller.
+ *
+ * This routine, although called by users, does not call xpc_part_ref() to
+ * ensure that the partition infrastructure is in place. It relies on the
+ * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg().
+ *
+ * Arguments:
+ *
+ *	partid - ID of partition to which the channel is connected.
+ *	ch_number - channel # to send message on.
+ *	payload - pointer to the payload area allocated via
+ *			xpc_initiate_allocate().
+ */
+enum xpc_retval
+xpc_initiate_send(partid_t partid, int ch_number, void *payload)
+{
+	struct xpc_partition *part = &xpc_partitions[partid];
+	struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
+	enum xpc_retval ret;
+
+
+	dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg,
+		partid, ch_number);
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
+	DBUG_ON(msg == NULL);
+
+	ret = xpc_send_msg(&part->channels[ch_number], msg, 0, NULL, NULL);
+
+	return ret;
+}
+
+
+/*
+ * Send a message previously allocated using xpc_initiate_allocate on the
+ * specified channel connected to the specified partition.
+ *
+ * This routine will not wait for the message to be sent. Once this routine
+ * has returned the message entry allocated via xpc_initiate_allocate() is no
+ * longer accessable to the caller.
+ *
+ * Once the remote end of the channel has received the message, the function
+ * passed as an argument to xpc_initiate_send_notify() will be called. This
+ * allows the sender to free up or re-use any buffers referenced by the
+ * message, but does NOT mean the message has been processed at the remote
+ * end by a receiver.
+ *
+ * If this routine returns an error, the caller's function will NOT be called.
+ *
+ * This routine, although called by users, does not call xpc_part_ref() to
+ * ensure that the partition infrastructure is in place. It relies on the
+ * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg().
+ *
+ * Arguments:
+ *
+ *	partid - ID of partition to which the channel is connected.
+ *	ch_number - channel # to send message on.
+ *	payload - pointer to the payload area allocated via
+ *			xpc_initiate_allocate().
+ *	func - function to call with asynchronous notification of message
+ *		  receipt. THIS FUNCTION MUST BE NON-BLOCKING.
+ *	key - user-defined key to be passed to the function when it's called.
+ */
+enum xpc_retval
+xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload,
+				xpc_notify_func func, void *key)
+{
+	struct xpc_partition *part = &xpc_partitions[partid];
+	struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
+	enum xpc_retval ret;
+
+
+	dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg,
+		partid, ch_number);
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
+	DBUG_ON(msg == NULL);
+	DBUG_ON(func == NULL);
+
+	ret = xpc_send_msg(&part->channels[ch_number], msg, XPC_N_CALL,
+								func, key);
+	return ret;
+}
+
+
+static struct xpc_msg *
+xpc_pull_remote_msg(struct xpc_channel *ch, s64 get)
+{
+	struct xpc_partition *part = &xpc_partitions[ch->partid];
+	struct xpc_msg *remote_msg, *msg;
+	u32 msg_index, nmsgs;
+	u64 msg_offset;
+	enum xpc_retval ret;
+
+
+	if (down_interruptible(&ch->msg_to_pull_sema) != 0) {
+		/* we were interrupted by a signal */
+		return NULL;
+	}
+
+	while (get >= ch->next_msg_to_pull) {
+
+		/* pull as many messages as are ready and able to be pulled */
+
+		msg_index = ch->next_msg_to_pull % ch->remote_nentries;
+
+		DBUG_ON(ch->next_msg_to_pull >=
+					(volatile s64) ch->w_remote_GP.put);
+		nmsgs =  (volatile s64) ch->w_remote_GP.put -
+						ch->next_msg_to_pull;
+		if (msg_index + nmsgs > ch->remote_nentries) {
+			/* ignore the ones that wrap the msg queue for now */
+			nmsgs = ch->remote_nentries - msg_index;
+		}
+
+		msg_offset = msg_index * ch->msg_size;
+		msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue +
+								msg_offset);
+		remote_msg = (struct xpc_msg *) (ch->remote_msgqueue_pa +
+								msg_offset);
+
+		if ((ret = xpc_pull_remote_cachelines(part, msg, remote_msg,
+				nmsgs * ch->msg_size)) != xpcSuccess) {
+
+			dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
+				" msg %ld from partition %d, channel=%d, "
+				"ret=%d\n", nmsgs, ch->next_msg_to_pull,
+				ch->partid, ch->number, ret);
+
+			XPC_DEACTIVATE_PARTITION(part, ret);
+
+			up(&ch->msg_to_pull_sema);
+			return NULL;
+		}
+
+		mb();	/* >>> this may not be needed, we're not sure */
+
+		ch->next_msg_to_pull += nmsgs;
+	}
+
+	up(&ch->msg_to_pull_sema);
+
+	/* return the message we were looking for */
+	msg_offset = (get % ch->remote_nentries) * ch->msg_size;
+	msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue + msg_offset);
+
+	return msg;
+}
+
+
+/*
+ * Get a message to be delivered.
+ */
+static struct xpc_msg *
+xpc_get_deliverable_msg(struct xpc_channel *ch)
+{
+	struct xpc_msg *msg = NULL;
+	s64 get;
+
+
+	do {
+		if ((volatile u32) ch->flags & XPC_C_DISCONNECTING) {
+			break;
+		}
+
+		get = (volatile s64) ch->w_local_GP.get;
+		if (get == (volatile s64) ch->w_remote_GP.put) {
+			break;
+		}
+
+		/* There are messages waiting to be pulled and delivered.
+		 * We need to try to secure one for ourselves. We'll do this
+		 * by trying to increment w_local_GP.get and hope that no one
+		 * else beats us to it. If they do, we'll we'll simply have
+		 * to try again for the next one.
+	 	 */
+
+		if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) {
+			/* we got the entry referenced by get */
+
+			dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, "
+				"partid=%d, channel=%d\n", get + 1,
+				ch->partid, ch->number);
+
+			/* pull the message from the remote partition */
+
+			msg = xpc_pull_remote_msg(ch, get);
+
+			DBUG_ON(msg != NULL && msg->number != get);
+			DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE));
+			DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY));
+
+			break;
+		}
+
+	} while (1);
+
+	return msg;
+}
+
+
+/*
+ * Deliver a message to its intended recipient.
+ */
+void
+xpc_deliver_msg(struct xpc_channel *ch)
+{
+	struct xpc_msg *msg;
+
+
+	if ((msg = xpc_get_deliverable_msg(ch)) != NULL) {
+
+		/*
+		 * This ref is taken to protect the payload itself from being
+		 * freed before the user is finished with it, which the user
+		 * indicates by calling xpc_initiate_received().
+		 */
+		xpc_msgqueue_ref(ch);
+
+		atomic_inc(&ch->kthreads_active);
+
+		if (ch->func != NULL) {
+			dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, "
+				"msg_number=%ld, partid=%d, channel=%d\n",
+				(void *) msg, msg->number, ch->partid,
+				ch->number);
+
+			/* deliver the message to its intended recipient */
+			ch->func(xpcMsgReceived, ch->partid, ch->number,
+					&msg->payload, ch->key);
+
+			dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
+				"msg_number=%ld, partid=%d, channel=%d\n",
+				(void *) msg, msg->number, ch->partid,
+				ch->number);
+		}
+
+		atomic_dec(&ch->kthreads_active);
+	}
+}
+
+
+/*
+ * Now we actually acknowledge the messages that have been delivered and ack'd
+ * by advancing the cached remote message queue's Get value and if requested
+ * send an IPI to the message sender's partition.
+ */
+static void
+xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags)
+{
+	struct xpc_msg *msg;
+	s64 get = initial_get + 1;
+	int send_IPI = 0;
+
+
+	while (1) {
+
+		while (1) {
+			if (get == (volatile s64) ch->w_local_GP.get) {
+				break;
+			}
+
+			msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue +
+			       (get % ch->remote_nentries) * ch->msg_size);
+
+			if (!(msg->flags & XPC_M_DONE)) {
+				break;
+			}
+
+			msg_flags |= msg->flags;
+			get++;
+		}
+
+		if (get == initial_get) {
+			/* nothing's changed */
+			break;
+		}
+
+		if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) !=
+								initial_get) {
+			/* someone else beat us to it */
+			DBUG_ON((volatile s64) ch->local_GP->get <=
+								initial_get);
+			break;
+		}
+
+		/* we just set the new value of local_GP->get */
+
+		dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, "
+			"channel=%d\n", get, ch->partid, ch->number);
+
+		send_IPI = (msg_flags & XPC_M_INTERRUPT);
+
+		/*
+		 * We need to ensure that the message referenced by
+		 * local_GP->get is not XPC_M_DONE or that local_GP->get
+		 * equals w_local_GP.get, so we'll go have a look.
+		 */
+		initial_get = get;
+	}
+
+	if (send_IPI) {
+		xpc_IPI_send_msgrequest(ch);
+	}
+}
+
+
+/*
+ * Acknowledge receipt of a delivered message.
+ *
+ * If a message has XPC_M_INTERRUPT set, send an interrupt to the partition
+ * that sent the message.
+ *
+ * This function, although called by users, does not call xpc_part_ref() to
+ * ensure that the partition infrastructure is in place. It relies on the
+ * fact that we called xpc_msgqueue_ref() in xpc_deliver_msg().
+ *
+ * Arguments:
+ *
+ *	partid - ID of partition to which the channel is connected.
+ *	ch_number - channel # message received on.
+ *	payload - pointer to the payload area allocated via
+ *			xpc_initiate_allocate().
+ */
+void
+xpc_initiate_received(partid_t partid, int ch_number, void *payload)
+{
+	struct xpc_partition *part = &xpc_partitions[partid];
+	struct xpc_channel *ch;
+	struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
+	s64 get, msg_number = msg->number;
+
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
+
+	ch = &part->channels[ch_number];
+
+	dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n",
+		(void *) msg, msg_number, ch->partid, ch->number);
+
+	DBUG_ON((((u64) msg - (u64) ch->remote_msgqueue) / ch->msg_size) !=
+					msg_number % ch->remote_nentries);
+	DBUG_ON(msg->flags & XPC_M_DONE);
+
+	msg->flags |= XPC_M_DONE;
+
+	/*
+	 * The preceding store of msg->flags must occur before the following
+	 * load of ch->local_GP->get.
+	 */
+	mb();
+
+	/*
+	 * See if this message is next in line to be acknowledged as having
+	 * been delivered.
+	 */
+	get = ch->local_GP->get;
+	if (get == msg_number) {
+		xpc_acknowledge_msgs(ch, get, msg->flags);
+	}
+
+	/* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg()  */
+	xpc_msgqueue_deref(ch);
+}
+
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -0,0 +1,1064 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition Communication (XPC) support - standard version.
+ *
+ *	XPC provides a message passing capability that crosses partition
+ *	boundaries. This module is made up of two parts:
+ *
+ *	    partition	This part detects the presence/absence of other
+ *			partitions. It provides a heartbeat and monitors
+ *			the heartbeats of other partitions.
+ *
+ *	    channel	This part manages the channels and sends/receives
+ *			messages across them to/from other partitions.
+ *
+ *	There are a couple of additional functions residing in XP, which
+ *	provide an interface to XPC for its users.
+ *
+ *
+ *	Caveats:
+ *
+ *	  . We currently have no way to determine which nasid an IPI came
+ *	    from. Thus, xpc_IPI_send() does a remote AMO write followed by
+ *	    an IPI. The AMO indicates where data is to be pulled from, so
+ *	    after the IPI arrives, the remote partition checks the AMO word.
+ *	    The IPI can actually arrive before the AMO however, so other code
+ *	    must periodically check for this case. Also, remote AMO operations
+ *	    do not reliably time out. Thus we do a remote PIO read solely to
+ *	    know whether the remote partition is down and whether we should
+ *	    stop sending IPIs to it. This remote PIO read operation is set up
+ *	    in a special nofault region so SAL knows to ignore (and cleanup)
+ *	    any errors due to the remote AMO write, PIO read, and/or PIO
+ *	    write operations.
+ *
+ *	    If/when new hardware solves this IPI problem, we should abandon
+ *	    the current approach.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/cache.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/uaccess.h>
+#include "xpc.h"
+
+
+/* define two XPC debug device structures to be used with dev_dbg() et al */
+
+struct device_driver xpc_dbg_name = {
+	.name = "xpc"
+};
+
+struct device xpc_part_dbg_subname = {
+	.bus_id = {0},		/* set to "part" at xpc_init() time */
+	.driver = &xpc_dbg_name
+};
+
+struct device xpc_chan_dbg_subname = {
+	.bus_id = {0},		/* set to "chan" at xpc_init() time */
+	.driver = &xpc_dbg_name
+};
+
+struct device *xpc_part = &xpc_part_dbg_subname;
+struct device *xpc_chan = &xpc_chan_dbg_subname;
+
+
+/* systune related variables for /proc/sys directories */
+
+static int xpc_hb_min = 1;
+static int xpc_hb_max = 10;
+
+static int xpc_hb_check_min = 10;
+static int xpc_hb_check_max = 120;
+
+static ctl_table xpc_sys_xpc_hb_dir[] = {
+	{
+		1,
+		"hb_interval",
+		&xpc_hb_interval,
+		sizeof(int),
+		0644,
+		NULL,
+		&proc_dointvec_minmax,
+		&sysctl_intvec,
+		NULL,
+		&xpc_hb_min, &xpc_hb_max
+	},
+	{
+		2,
+		"hb_check_interval",
+		&xpc_hb_check_interval,
+		sizeof(int),
+		0644,
+		NULL,
+		&proc_dointvec_minmax,
+		&sysctl_intvec,
+		NULL,
+		&xpc_hb_check_min, &xpc_hb_check_max
+	},
+	{0}
+};
+static ctl_table xpc_sys_xpc_dir[] = {
+	{
+		1,
+		"hb",
+		NULL,
+		0,
+		0555,
+		xpc_sys_xpc_hb_dir
+	},
+	{0}
+};
+static ctl_table xpc_sys_dir[] = {
+	{
+		1,
+		"xpc",
+		NULL,
+		0,
+		0555,
+		xpc_sys_xpc_dir
+	},
+	{0}
+};
+static struct ctl_table_header *xpc_sysctl;
+
+
+/* #of IRQs received */
+static atomic_t xpc_act_IRQ_rcvd;
+
+/* IRQ handler notifies this wait queue on receipt of an IRQ */
+static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq);
+
+static unsigned long xpc_hb_check_timeout;
+
+/* xpc_hb_checker thread exited notification */
+static DECLARE_MUTEX_LOCKED(xpc_hb_checker_exited);
+
+/* xpc_discovery thread exited notification */
+static DECLARE_MUTEX_LOCKED(xpc_discovery_exited);
+
+
+static struct timer_list xpc_hb_timer;
+
+
+static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *);
+
+
+/*
+ * Notify the heartbeat check thread that an IRQ has been received.
+ */
+static irqreturn_t
+xpc_act_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	atomic_inc(&xpc_act_IRQ_rcvd);
+	wake_up_interruptible(&xpc_act_IRQ_wq);
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * Timer to produce the heartbeat.  The timer structures function is
+ * already set when this is initially called.  A tunable is used to
+ * specify when the next timeout should occur.
+ */
+static void
+xpc_hb_beater(unsigned long dummy)
+{
+	xpc_vars->heartbeat++;
+
+	if (jiffies >= xpc_hb_check_timeout) {
+		wake_up_interruptible(&xpc_act_IRQ_wq);
+	}
+
+	xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ);
+	add_timer(&xpc_hb_timer);
+}
+
+
+/*
+ * This thread is responsible for nearly all of the partition
+ * activation/deactivation.
+ */
+static int
+xpc_hb_checker(void *ignore)
+{
+	int last_IRQ_count = 0;
+	int new_IRQ_count;
+	int force_IRQ=0;
+
+
+	/* this thread was marked active by xpc_hb_init() */
+
+	daemonize(XPC_HB_CHECK_THREAD_NAME);
+
+	set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU));
+
+	xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
+
+	while (!(volatile int) xpc_exiting) {
+
+		/* wait for IRQ or timeout */
+		(void) wait_event_interruptible(xpc_act_IRQ_wq,
+			    (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) ||
+					jiffies >= xpc_hb_check_timeout ||
+						(volatile int) xpc_exiting));
+
+		dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have "
+			"been received\n",
+			(int) (xpc_hb_check_timeout - jiffies),
+			atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count);
+
+
+		/* checking of remote heartbeats is skewed by IRQ handling */
+		if (jiffies >= xpc_hb_check_timeout) {
+			dev_dbg(xpc_part, "checking remote heartbeats\n");
+			xpc_check_remote_hb();
+
+			/*
+			 * We need to periodically recheck to ensure no
+			 * IPI/AMO pairs have been missed.  That check
+			 * must always reset xpc_hb_check_timeout.
+			 */
+			force_IRQ = 1;
+		}
+
+
+		new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd);
+		if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) {
+			force_IRQ = 0;
+
+			dev_dbg(xpc_part, "found an IRQ to process; will be "
+				"resetting xpc_hb_check_timeout\n");
+
+			last_IRQ_count += xpc_identify_act_IRQ_sender();
+			if (last_IRQ_count < new_IRQ_count) {
+				/* retry once to help avoid missing AMO */
+				(void) xpc_identify_act_IRQ_sender();
+			}
+			last_IRQ_count = new_IRQ_count;
+
+			xpc_hb_check_timeout = jiffies +
+					   (xpc_hb_check_interval * HZ);
+		}
+	}
+
+	dev_dbg(xpc_part, "heartbeat checker is exiting\n");
+
+
+	/* mark this thread as inactive */
+	up(&xpc_hb_checker_exited);
+	return 0;
+}
+
+
+/*
+ * This thread will attempt to discover other partitions to activate
+ * based on info provided by SAL. This new thread is short lived and
+ * will exit once discovery is complete.
+ */
+static int
+xpc_initiate_discovery(void *ignore)
+{
+	daemonize(XPC_DISCOVERY_THREAD_NAME);
+
+	xpc_discovery();
+
+	dev_dbg(xpc_part, "discovery thread is exiting\n");
+
+	/* mark this thread as inactive */
+	up(&xpc_discovery_exited);
+	return 0;
+}
+
+
+/*
+ * Establish first contact with the remote partititon. This involves pulling
+ * the XPC per partition variables from the remote partition and waiting for
+ * the remote partition to pull ours.
+ */
+static enum xpc_retval
+xpc_make_first_contact(struct xpc_partition *part)
+{
+	enum xpc_retval ret;
+
+
+	while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) {
+		if (ret != xpcRetry) {
+			XPC_DEACTIVATE_PARTITION(part, ret);
+			return ret;
+		}
+
+		dev_dbg(xpc_chan, "waiting to make first contact with "
+			"partition %d\n", XPC_PARTID(part));
+
+		/* wait a 1/4 of a second or so */
+		set_current_state(TASK_INTERRUPTIBLE);
+		(void) schedule_timeout(0.25 * HZ);
+
+		if (part->act_state == XPC_P_DEACTIVATING) {
+			return part->reason;
+		}
+	}
+
+	return xpc_mark_partition_active(part);
+}
+
+
+/*
+ * The first kthread assigned to a newly activated partition is the one
+ * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to
+ * that kthread until the partition is brought down, at which time that kthread
+ * returns back to XPC HB. (The return of that kthread will signify to XPC HB
+ * that XPC has dismantled all communication infrastructure for the associated
+ * partition.) This kthread becomes the channel manager for that partition.
+ *
+ * Each active partition has a channel manager, who, besides connecting and
+ * disconnecting channels, will ensure that each of the partition's connected
+ * channels has the required number of assigned kthreads to get the work done.
+ */
+static void
+xpc_channel_mgr(struct xpc_partition *part)
+{
+	while (part->act_state != XPC_P_DEACTIVATING ||
+				atomic_read(&part->nchannels_active) > 0) {
+
+		xpc_process_channel_activity(part);
+
+
+		/*
+		 * Wait until we've been requested to activate kthreads or
+		 * all of the channel's message queues have been torn down or
+		 * a signal is pending.
+		 *
+		 * The channel_mgr_requests is set to 1 after being awakened,
+		 * This is done to prevent the channel mgr from making one pass
+		 * through the loop for each request, since he will
+		 * be servicing all the requests in one pass. The reason it's
+		 * set to 1 instead of 0 is so that other kthreads will know
+		 * that the channel mgr is running and won't bother trying to
+		 * wake him up.
+		 */
+		atomic_dec(&part->channel_mgr_requests);
+		(void) wait_event_interruptible(part->channel_mgr_wq,
+				(atomic_read(&part->channel_mgr_requests) > 0 ||
+				(volatile u64) part->local_IPI_amo != 0 ||
+				((volatile u8) part->act_state ==
+							XPC_P_DEACTIVATING &&
+				atomic_read(&part->nchannels_active) == 0)));
+		atomic_set(&part->channel_mgr_requests, 1);
+
+		// >>> Does it need to wakeup periodically as well? In case we
+		// >>> miscalculated the #of kthreads to wakeup or create?
+	}
+}
+
+
+/*
+ * When XPC HB determines that a partition has come up, it will create a new
+ * kthread and that kthread will call this function to attempt to set up the
+ * basic infrastructure used for Cross Partition Communication with the newly
+ * upped partition.
+ *
+ * The kthread that was created by XPC HB and which setup the XPC
+ * infrastructure will remain assigned to the partition until the partition
+ * goes down. At which time the kthread will teardown the XPC infrastructure
+ * and then exit.
+ *
+ * XPC HB will put the remote partition's XPC per partition specific variables
+ * physical address into xpc_partitions[partid].remote_vars_part_pa prior to
+ * calling xpc_partition_up().
+ */
+static void
+xpc_partition_up(struct xpc_partition *part)
+{
+	DBUG_ON(part->channels != NULL);
+
+	dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part));
+
+	if (xpc_setup_infrastructure(part) != xpcSuccess) {
+		return;
+	}
+
+	/*
+	 * The kthread that XPC HB called us with will become the
+	 * channel manager for this partition. It will not return
+	 * back to XPC HB until the partition's XPC infrastructure
+	 * has been dismantled.
+	 */
+
+	(void) xpc_part_ref(part);	/* this will always succeed */
+
+	if (xpc_make_first_contact(part) == xpcSuccess) {
+		xpc_channel_mgr(part);
+	}
+
+	xpc_part_deref(part);
+
+	xpc_teardown_infrastructure(part);
+}
+
+
+static int
+xpc_activating(void *__partid)
+{
+	partid_t partid = (u64) __partid;
+	struct xpc_partition *part = &xpc_partitions[partid];
+	unsigned long irq_flags;
+	struct sched_param param = { sched_priority: MAX_USER_RT_PRIO - 1 };
+	int ret;
+
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+
+	spin_lock_irqsave(&part->act_lock, irq_flags);
+
+	if (part->act_state == XPC_P_DEACTIVATING) {
+		part->act_state = XPC_P_INACTIVE;
+		spin_unlock_irqrestore(&part->act_lock, irq_flags);
+		part->remote_rp_pa = 0;
+		return 0;
+	}
+
+	/* indicate the thread is activating */
+	DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ);
+	part->act_state = XPC_P_ACTIVATING;
+
+	XPC_SET_REASON(part, 0, 0);
+	spin_unlock_irqrestore(&part->act_lock, irq_flags);
+
+	dev_dbg(xpc_part, "bringing partition %d up\n", partid);
+
+	daemonize("xpc%02d", partid);
+
+	/*
+	 * This thread needs to run at a realtime priority to prevent a
+	 * significant performance degradation.
+	 */
+	ret = sched_setscheduler(current, SCHED_FIFO, &param);
+	if (ret != 0) {
+		dev_warn(xpc_part, "unable to set pid %d to a realtime "
+			"priority, ret=%d\n", current->pid, ret);
+	}
+
+	/* allow this thread and its children to run on any CPU */
+	set_cpus_allowed(current, CPU_MASK_ALL);
+
+	/*
+	 * Register the remote partition's AMOs with SAL so it can handle
+	 * and cleanup errors within that address range should the remote
+	 * partition go down. We don't unregister this range because it is
+	 * difficult to tell when outstanding writes to the remote partition
+	 * are finished and thus when it is safe to unregister. This should
+	 * not result in wasted space in the SAL xp_addr_region table because
+	 * we should get the same page for remote_amos_page_pa after module
+	 * reloads and system reboots.
+	 */
+	if (sn_register_xp_addr_region(part->remote_amos_page_pa,
+							PAGE_SIZE, 1) < 0) {
+		dev_warn(xpc_part, "xpc_partition_up(%d) failed to register "
+			"xp_addr region\n", partid);
+
+		spin_lock_irqsave(&part->act_lock, irq_flags);
+		part->act_state = XPC_P_INACTIVE;
+		XPC_SET_REASON(part, xpcPhysAddrRegFailed, __LINE__);
+		spin_unlock_irqrestore(&part->act_lock, irq_flags);
+		part->remote_rp_pa = 0;
+		return 0;
+	}
+
+	XPC_ALLOW_HB(partid, xpc_vars);
+	xpc_IPI_send_activated(part);
+
+
+	/*
+	 * xpc_partition_up() holds this thread and marks this partition as
+	 * XPC_P_ACTIVE by calling xpc_hb_mark_active().
+	 */
+	(void) xpc_partition_up(part);
+
+	xpc_mark_partition_inactive(part);
+
+	if (part->reason == xpcReactivating) {
+		/* interrupting ourselves results in activating partition */
+		xpc_IPI_send_reactivate(part);
+	}
+
+	return 0;
+}
+
+
+void
+xpc_activate_partition(struct xpc_partition *part)
+{
+	partid_t partid = XPC_PARTID(part);
+	unsigned long irq_flags;
+	pid_t pid;
+
+
+	spin_lock_irqsave(&part->act_lock, irq_flags);
+
+	pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0);
+
+	DBUG_ON(part->act_state != XPC_P_INACTIVE);
+
+	if (pid > 0) {
+		part->act_state = XPC_P_ACTIVATION_REQ;
+		XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
+	} else {
+		XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
+	}
+
+	spin_unlock_irqrestore(&part->act_lock, irq_flags);
+}
+
+
+/*
+ * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified
+ * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more
+ * than one partition, we use an AMO_t structure per partition to indicate
+ * whether a partition has sent an IPI or not.  >>> If it has, then wake up the
+ * associated kthread to handle it.
+ *
+ * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC
+ * running on other partitions.
+ *
+ * Noteworthy Arguments:
+ *
+ *	irq - Interrupt ReQuest number. NOT USED.
+ *
+ *	dev_id - partid of IPI's potential sender.
+ *
+ *	regs - processor's context before the processor entered
+ *	       interrupt code. NOT USED.
+ */
+irqreturn_t
+xpc_notify_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	partid_t partid = (partid_t) (u64) dev_id;
+	struct xpc_partition *part = &xpc_partitions[partid];
+
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+
+	if (xpc_part_ref(part)) {
+		xpc_check_for_channel_activity(part);
+
+		xpc_part_deref(part);
+	}
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor
+ * because the write to their associated IPI amo completed after the IRQ/IPI
+ * was received.
+ */
+void
+xpc_dropped_IPI_check(struct xpc_partition *part)
+{
+	if (xpc_part_ref(part)) {
+		xpc_check_for_channel_activity(part);
+
+		part->dropped_IPI_timer.expires = jiffies +
+							XPC_P_DROPPED_IPI_WAIT;
+		add_timer(&part->dropped_IPI_timer);
+		xpc_part_deref(part);
+	}
+}
+
+
+void
+xpc_activate_kthreads(struct xpc_channel *ch, int needed)
+{
+	int idle = atomic_read(&ch->kthreads_idle);
+	int assigned = atomic_read(&ch->kthreads_assigned);
+	int wakeup;
+
+
+	DBUG_ON(needed <= 0);
+
+	if (idle > 0) {
+		wakeup = (needed > idle) ? idle : needed;
+		needed -= wakeup;
+
+		dev_dbg(xpc_chan, "wakeup %d idle kthreads, partid=%d, "
+			"channel=%d\n", wakeup, ch->partid, ch->number);
+
+		/* only wakeup the requested number of kthreads */
+		wake_up_nr(&ch->idle_wq, wakeup);
+	}
+
+	if (needed <= 0) {
+		return;
+	}
+
+	if (needed + assigned > ch->kthreads_assigned_limit) {
+		needed = ch->kthreads_assigned_limit - assigned;
+		// >>>should never be less than 0
+		if (needed <= 0) {
+			return;
+		}
+	}
+
+	dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
+		needed, ch->partid, ch->number);
+
+	xpc_create_kthreads(ch, needed);
+}
+
+
+/*
+ * This function is where XPC's kthreads wait for messages to deliver.
+ */
+static void
+xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch)
+{
+	do {
+		/* deliver messages to their intended recipients */
+
+		while ((volatile s64) ch->w_local_GP.get <
+				(volatile s64) ch->w_remote_GP.put &&
+					!((volatile u32) ch->flags &
+						XPC_C_DISCONNECTING)) {
+			xpc_deliver_msg(ch);
+		}
+
+		if (atomic_inc_return(&ch->kthreads_idle) >
+						ch->kthreads_idle_limit) {
+			/* too many idle kthreads on this channel */
+			atomic_dec(&ch->kthreads_idle);
+			break;
+		}
+
+		dev_dbg(xpc_chan, "idle kthread calling "
+			"wait_event_interruptible_exclusive()\n");
+
+		(void) wait_event_interruptible_exclusive(ch->idle_wq,
+				((volatile s64) ch->w_local_GP.get <
+					(volatile s64) ch->w_remote_GP.put ||
+				((volatile u32) ch->flags &
+						XPC_C_DISCONNECTING)));
+
+		atomic_dec(&ch->kthreads_idle);
+
+	} while (!((volatile u32) ch->flags & XPC_C_DISCONNECTING));
+}
+
+
+static int
+xpc_daemonize_kthread(void *args)
+{
+	partid_t partid = XPC_UNPACK_ARG1(args);
+	u16 ch_number = XPC_UNPACK_ARG2(args);
+	struct xpc_partition *part = &xpc_partitions[partid];
+	struct xpc_channel *ch;
+	int n_needed;
+
+
+	daemonize("xpc%02dc%d", partid, ch_number);
+
+	dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n",
+		partid, ch_number);
+
+	ch = &part->channels[ch_number];
+
+	if (!(ch->flags & XPC_C_DISCONNECTING)) {
+		DBUG_ON(!(ch->flags & XPC_C_CONNECTED));
+
+		/* let registerer know that connection has been established */
+
+		if (atomic_read(&ch->kthreads_assigned) == 1) {
+			xpc_connected_callout(ch);
+
+			/*
+			 * It is possible that while the callout was being
+			 * made that the remote partition sent some messages.
+			 * If that is the case, we may need to activate
+			 * additional kthreads to help deliver them. We only
+			 * need one less than total #of messages to deliver.
+			 */
+			n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1;
+			if (n_needed > 0 &&
+					!(ch->flags & XPC_C_DISCONNECTING)) {
+				xpc_activate_kthreads(ch, n_needed);
+			}
+		}
+
+		xpc_kthread_waitmsgs(part, ch);
+	}
+
+	if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
+			((ch->flags & XPC_C_CONNECTCALLOUT) ||
+				(ch->reason != xpcUnregistering &&
+					ch->reason != xpcOtherUnregistering))) {
+		xpc_disconnected_callout(ch);
+	}
+
+
+	xpc_msgqueue_deref(ch);
+
+	dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
+		partid, ch_number);
+
+	xpc_part_deref(part);
+	return 0;
+}
+
+
+/*
+ * For each partition that XPC has established communications with, there is
+ * a minimum of one kernel thread assigned to perform any operation that
+ * may potentially sleep or block (basically the callouts to the asynchronous
+ * functions registered via xpc_connect()).
+ *
+ * Additional kthreads are created and destroyed by XPC as the workload
+ * demands.
+ *
+ * A kthread is assigned to one of the active channels that exists for a given
+ * partition.
+ */
+void
+xpc_create_kthreads(struct xpc_channel *ch, int needed)
+{
+	unsigned long irq_flags;
+	pid_t pid;
+	u64 args = XPC_PACK_ARGS(ch->partid, ch->number);
+
+
+	while (needed-- > 0) {
+		pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
+		if (pid < 0) {
+			/* the fork failed */
+
+			if (atomic_read(&ch->kthreads_assigned) <
+						ch->kthreads_idle_limit) {
+				/*
+				 * Flag this as an error only if we have an
+				 * insufficient #of kthreads for the channel
+				 * to function.
+				 *
+				 * No xpc_msgqueue_ref() is needed here since
+				 * the channel mgr is doing this.
+				 */
+				spin_lock_irqsave(&ch->lock, irq_flags);
+				XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
+								&irq_flags);
+				spin_unlock_irqrestore(&ch->lock, irq_flags);
+			}
+			break;
+		}
+
+		/*
+		 * The following is done on behalf of the newly created
+		 * kthread. That kthread is responsible for doing the
+		 * counterpart to the following before it exits.
+		 */
+		(void) xpc_part_ref(&xpc_partitions[ch->partid]);
+		xpc_msgqueue_ref(ch);
+		atomic_inc(&ch->kthreads_assigned);
+		ch->kthreads_created++;	// >>> temporary debug only!!!
+	}
+}
+
+
+void
+xpc_disconnect_wait(int ch_number)
+{
+	partid_t partid;
+	struct xpc_partition *part;
+	struct xpc_channel *ch;
+
+
+	/* now wait for all callouts to the caller's function to cease */
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		if (xpc_part_ref(part)) {
+			ch = &part->channels[ch_number];
+
+// >>> how do we keep from falling into the window between our check and going
+// >>> down and coming back up where sema is re-inited?
+			if (ch->flags & XPC_C_SETUP) {
+				(void) down(&ch->teardown_sema);
+			}
+
+			xpc_part_deref(part);
+		}
+	}
+}
+
+
+static void
+xpc_do_exit(void)
+{
+	partid_t partid;
+	int active_part_count;
+	struct xpc_partition *part;
+
+
+	/* now it's time to eliminate our heartbeat */
+	del_timer_sync(&xpc_hb_timer);
+	xpc_vars->heartbeating_to_mask = 0;
+
+	/* indicate to others that our reserved page is uninitialized */
+	xpc_rsvd_page->vars_pa = 0;
+
+	/*
+	 * Ignore all incoming interrupts. Without interupts the heartbeat
+	 * checker won't activate any new partitions that may come up.
+	 */
+	free_irq(SGI_XPC_ACTIVATE, NULL);
+
+	/*
+	 * Cause the heartbeat checker and the discovery threads to exit.
+	 * We don't want them attempting to activate new partitions as we
+	 * try to deactivate the existing ones.
+	 */
+	xpc_exiting = 1;
+	wake_up_interruptible(&xpc_act_IRQ_wq);
+
+	/* wait for the heartbeat checker thread to mark itself inactive */
+	down(&xpc_hb_checker_exited);
+
+	/* wait for the discovery thread to mark itself inactive */
+	down(&xpc_discovery_exited);
+
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(0.3 * HZ);
+	set_current_state(TASK_RUNNING);
+
+
+	/* wait for all partitions to become inactive */
+
+	do {
+		active_part_count = 0;
+
+		for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+			part = &xpc_partitions[partid];
+			if (part->act_state != XPC_P_INACTIVE) {
+				active_part_count++;
+
+				XPC_DEACTIVATE_PARTITION(part, xpcUnloading);
+			}
+		}
+
+		if (active_part_count) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(0.3 * HZ);
+			set_current_state(TASK_RUNNING);
+		}
+
+	} while (active_part_count > 0);
+
+
+	/* close down protections for IPI operations */
+	xpc_restrict_IPI_ops();
+
+
+	/* clear the interface to XPC's functions */
+	xpc_clear_interface();
+
+	if (xpc_sysctl) {
+		unregister_sysctl_table(xpc_sysctl);
+	}
+}
+
+
+int __init
+xpc_init(void)
+{
+	int ret;
+	partid_t partid;
+	struct xpc_partition *part;
+	pid_t pid;
+
+
+	/*
+	 * xpc_remote_copy_buffer is used as a temporary buffer for bte_copy'ng
+	 * both a partition's reserved page and its XPC variables. Its size was
+	 * based on the size of a reserved page. So we need to ensure that the
+	 * XPC variables will fit as well.
+	 */
+	if (XPC_VARS_ALIGNED_SIZE > XPC_RSVD_PAGE_ALIGNED_SIZE) {
+		dev_err(xpc_part, "xpc_remote_copy_buffer is not big enough\n");
+		return -EPERM;
+	}
+	DBUG_ON((u64) xpc_remote_copy_buffer !=
+				L1_CACHE_ALIGN((u64) xpc_remote_copy_buffer));
+
+	snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
+	snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
+
+	xpc_sysctl = register_sysctl_table(xpc_sys_dir, 1);
+
+	/*
+	 * The first few fields of each entry of xpc_partitions[] need to
+	 * be initialized now so that calls to xpc_connect() and
+	 * xpc_disconnect() can be made prior to the activation of any remote
+	 * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
+	 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
+	 * PARTITION HAS BEEN ACTIVATED.
+	 */
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		DBUG_ON((u64) part != L1_CACHE_ALIGN((u64) part));
+
+		part->act_IRQ_rcvd = 0;
+		spin_lock_init(&part->act_lock);
+		part->act_state = XPC_P_INACTIVE;
+		XPC_SET_REASON(part, 0, 0);
+		part->setup_state = XPC_P_UNSET;
+		init_waitqueue_head(&part->teardown_wq);
+		atomic_set(&part->references, 0);
+	}
+
+	/*
+	 * Open up protections for IPI operations (and AMO operations on
+	 * Shub 1.1 systems).
+	 */
+	xpc_allow_IPI_ops();
+
+	/*
+	 * Interrupts being processed will increment this atomic variable and
+	 * awaken the heartbeat thread which will process the interrupts.
+	 */
+	atomic_set(&xpc_act_IRQ_rcvd, 0);
+
+	/*
+	 * This is safe to do before the xpc_hb_checker thread has started
+	 * because the handler releases a wait queue.  If an interrupt is
+	 * received before the thread is waiting, it will not go to sleep,
+	 * but rather immediately process the interrupt.
+	 */
+	ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0,
+							"xpc hb", NULL);
+	if (ret != 0) {
+		dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "
+			"errno=%d\n", -ret);
+
+		xpc_restrict_IPI_ops();
+
+		if (xpc_sysctl) {
+			unregister_sysctl_table(xpc_sysctl);
+		}
+		return -EBUSY;
+	}
+
+	/*
+	 * Fill the partition reserved page with the information needed by
+	 * other partitions to discover we are alive and establish initial
+	 * communications.
+	 */
+	xpc_rsvd_page = xpc_rsvd_page_init();
+	if (xpc_rsvd_page == NULL) {
+		dev_err(xpc_part, "could not setup our reserved page\n");
+
+		free_irq(SGI_XPC_ACTIVATE, NULL);
+		xpc_restrict_IPI_ops();
+
+		if (xpc_sysctl) {
+			unregister_sysctl_table(xpc_sysctl);
+		}
+		return -EBUSY;
+	}
+
+
+	/*
+	 * Set the beating to other partitions into motion.  This is
+	 * the last requirement for other partitions' discovery to
+	 * initiate communications with us.
+	 */
+	init_timer(&xpc_hb_timer);
+	xpc_hb_timer.function = xpc_hb_beater;
+	xpc_hb_beater(0);
+
+
+	/*
+	 * The real work-horse behind xpc.  This processes incoming
+	 * interrupts and monitors remote heartbeats.
+	 */
+	pid = kernel_thread(xpc_hb_checker, NULL, 0);
+	if (pid < 0) {
+		dev_err(xpc_part, "failed while forking hb check thread\n");
+
+		/* indicate to others that our reserved page is uninitialized */
+		xpc_rsvd_page->vars_pa = 0;
+
+		del_timer_sync(&xpc_hb_timer);
+		free_irq(SGI_XPC_ACTIVATE, NULL);
+		xpc_restrict_IPI_ops();
+
+		if (xpc_sysctl) {
+			unregister_sysctl_table(xpc_sysctl);
+		}
+		return -EBUSY;
+	}
+
+
+	/*
+	 * Startup a thread that will attempt to discover other partitions to
+	 * activate based on info provided by SAL. This new thread is short
+	 * lived and will exit once discovery is complete.
+	 */
+	pid = kernel_thread(xpc_initiate_discovery, NULL, 0);
+	if (pid < 0) {
+		dev_err(xpc_part, "failed while forking discovery thread\n");
+
+		/* mark this new thread as a non-starter */
+		up(&xpc_discovery_exited);
+
+		xpc_do_exit();
+		return -EBUSY;
+	}
+
+
+	/* set the interface to point at XPC's functions */
+	xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect,
+			  xpc_initiate_allocate, xpc_initiate_send,
+			  xpc_initiate_send_notify, xpc_initiate_received,
+			  xpc_initiate_partid_to_nasids);
+
+	return 0;
+}
+module_init(xpc_init);
+
+
+void __exit
+xpc_exit(void)
+{
+	xpc_do_exit();
+}
+module_exit(xpc_exit);
+
+
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Cross Partition Communication (XPC) support");
+MODULE_LICENSE("GPL");
+
+module_param(xpc_hb_interval, int, 0);
+MODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between "
+		"heartbeat increments.");
+
+module_param(xpc_hb_check_interval, int, 0);
+MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between "
+		"heartbeat checks.");
+
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xpc_partition.c
@@ -0,0 +1,984 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition Communication (XPC) partition support.
+ *
+ *	This is the part of XPC that detects the presence/absence of
+ *	other partitions. It provides a heartbeat and monitors the
+ *	heartbeats of other partitions.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
+#include <linux/cache.h>
+#include <linux/mmzone.h>
+#include <linux/nodemask.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/addrs.h>
+#include "xpc.h"
+
+
+/* XPC is exiting flag */
+int xpc_exiting;
+
+
+/* SH_IPI_ACCESS shub register value on startup */
+static u64 xpc_sh1_IPI_access;
+static u64 xpc_sh2_IPI_access0;
+static u64 xpc_sh2_IPI_access1;
+static u64 xpc_sh2_IPI_access2;
+static u64 xpc_sh2_IPI_access3;
+
+
+/* original protection values for each node */
+u64 xpc_prot_vec[MAX_COMPACT_NODES];
+
+
+/* this partition's reserved page */
+struct xpc_rsvd_page *xpc_rsvd_page;
+
+/* this partition's XPC variables (within the reserved page) */
+struct xpc_vars *xpc_vars;
+struct xpc_vars_part *xpc_vars_part;
+
+
+/*
+ * For performance reasons, each entry of xpc_partitions[] is cacheline
+ * aligned. And xpc_partitions[] is padded with an additional entry at the
+ * end so that the last legitimate entry doesn't share its cacheline with
+ * another variable.
+ */
+struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1];
+
+
+/*
+ * Generic buffer used to store a local copy of the remote partitions
+ * reserved page or XPC variables.
+ *
+ * xpc_discovery runs only once and is a seperate thread that is
+ * very likely going to be processing in parallel with receiving
+ * interrupts.
+ */
+char ____cacheline_aligned
+		xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE];
+
+
+/* systune related variables */
+int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
+int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_TIMEOUT;
+
+
+/*
+ * Given a nasid, get the physical address of the  partition's reserved page
+ * for that nasid. This function returns 0 on any error.
+ */
+static u64
+xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size)
+{
+	bte_result_t bte_res;
+	s64 status;
+	u64 cookie = 0;
+	u64 rp_pa = nasid;	/* seed with nasid */
+	u64 len = 0;
+
+
+	while (1) {
+
+		status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa,
+								&len);
+
+		dev_dbg(xpc_part, "SAL returned with status=%li, cookie="
+			"0x%016lx, address=0x%016lx, len=0x%016lx\n",
+			status, cookie, rp_pa, len);
+
+		if (status != SALRET_MORE_PASSES) {
+			break;
+		}
+
+		if (len > buf_size) {
+			dev_err(xpc_part, "len (=0x%016lx) > buf_size\n", len);
+			status = SALRET_ERROR;
+			break;
+		}
+
+		bte_res = xp_bte_copy(rp_pa, ia64_tpa(buf), buf_size,
+					(BTE_NOTIFY | BTE_WACQUIRE), NULL);
+		if (bte_res != BTE_SUCCESS) {
+			dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res);
+			status = SALRET_ERROR;
+			break;
+		}
+	}
+
+	if (status != SALRET_OK) {
+		rp_pa = 0;
+	}
+	dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa);
+	return rp_pa;
+}
+
+
+/*
+ * Fill the partition reserved page with the information needed by
+ * other partitions to discover we are alive and establish initial
+ * communications.
+ */
+struct xpc_rsvd_page *
+xpc_rsvd_page_init(void)
+{
+	struct xpc_rsvd_page *rp;
+	AMO_t *amos_page;
+	u64 rp_pa, next_cl, nasid_array = 0;
+	int i, ret;
+
+
+	/* get the local reserved page's address */
+
+	rp_pa = xpc_get_rsvd_page_pa(cnodeid_to_nasid(0),
+					(u64) xpc_remote_copy_buffer,
+						XPC_RSVD_PAGE_ALIGNED_SIZE);
+	if (rp_pa == 0) {
+		dev_err(xpc_part, "SAL failed to locate the reserved page\n");
+		return NULL;
+	}
+	rp = (struct xpc_rsvd_page *) __va(rp_pa);
+
+	if (rp->partid != sn_partition_id) {
+		dev_err(xpc_part, "the reserved page's partid of %d should be "
+			"%d\n", rp->partid, sn_partition_id);
+		return NULL;
+	}
+
+	rp->version = XPC_RP_VERSION;
+
+	/*
+	 * Place the XPC variables on the cache line following the
+	 * reserved page structure.
+	 */
+	next_cl = (u64) rp + XPC_RSVD_PAGE_ALIGNED_SIZE;
+	xpc_vars = (struct xpc_vars *) next_cl;
+
+	/*
+	 * Before clearing xpc_vars, see if a page of AMOs had been previously
+	 * allocated. If not we'll need to allocate one and set permissions
+	 * so that cross-partition AMOs are allowed.
+	 *
+	 * The allocated AMO page needs MCA reporting to remain disabled after
+	 * XPC has unloaded.  To make this work, we keep a copy of the pointer
+	 * to this page (i.e., amos_page) in the struct xpc_vars structure,
+	 * which is pointed to by the reserved page, and re-use that saved copy
+	 * on subsequent loads of XPC. This AMO page is never freed, and its
+	 * memory protections are never restricted.
+	 */
+	if ((amos_page = xpc_vars->amos_page) == NULL) {
+		amos_page = (AMO_t *) mspec_kalloc_page(0);
+		if (amos_page == NULL) {
+			dev_err(xpc_part, "can't allocate page of AMOs\n");
+			return NULL;
+		}
+
+		/*
+		 * Open up AMO-R/W to cpu.  This is done for Shub 1.1 systems
+		 * when xpc_allow_IPI_ops() is called via xpc_hb_init().
+		 */
+		if (!enable_shub_wars_1_1()) {
+			ret = sn_change_memprotect(ia64_tpa((u64) amos_page),
+					PAGE_SIZE, SN_MEMPROT_ACCESS_CLASS_1,
+					&nasid_array);
+			if (ret != 0) {
+				dev_err(xpc_part, "can't change memory "
+					"protections\n");
+				mspec_kfree_page((unsigned long) amos_page);
+				return NULL;
+			}
+		}
+	} else if (!IS_AMO_ADDRESS((u64) amos_page)) {
+		/*
+		 * EFI's XPBOOT can also set amos_page in the reserved page,
+		 * but it happens to leave it as an uncached physical address
+		 * and we need it to be an uncached virtual, so we'll have to
+		 * convert it.
+		 */
+		if (!IS_AMO_PHYS_ADDRESS((u64) amos_page)) {
+			dev_err(xpc_part, "previously used amos_page address "
+				"is bad = 0x%p\n", (void *) amos_page);
+			return NULL;
+		}
+		amos_page = (AMO_t *) TO_AMO((u64) amos_page);
+	}
+
+	memset(xpc_vars, 0, sizeof(struct xpc_vars));
+
+	/*
+	 * Place the XPC per partition specific variables on the cache line
+	 * following the XPC variables structure.
+	 */
+	next_cl += XPC_VARS_ALIGNED_SIZE;
+	memset((u64 *) next_cl, 0, sizeof(struct xpc_vars_part) *
+							XP_MAX_PARTITIONS);
+	xpc_vars_part = (struct xpc_vars_part *) next_cl;
+	xpc_vars->vars_part_pa = __pa(next_cl);
+
+	xpc_vars->version = XPC_V_VERSION;
+	xpc_vars->act_nasid = cpuid_to_nasid(0);
+	xpc_vars->act_phys_cpuid = cpu_physical_id(0);
+	xpc_vars->amos_page = amos_page;  /* save for next load of XPC */
+
+
+	/*
+	 * Initialize the activation related AMO variables.
+	 */
+	xpc_vars->act_amos = xpc_IPI_init(XP_MAX_PARTITIONS);
+	for (i = 1; i < XP_NASID_MASK_WORDS; i++) {
+		xpc_IPI_init(i + XP_MAX_PARTITIONS);
+	}
+	/* export AMO page's physical address to other partitions */
+	xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page);
+
+	/*
+	 * This signifies to the remote partition that our reserved
+	 * page is initialized.
+	 */
+	(volatile u64) rp->vars_pa = __pa(xpc_vars);
+
+	return rp;
+}
+
+
+/*
+ * Change protections to allow IPI operations (and AMO operations on
+ * Shub 1.1 systems).
+ */
+void
+xpc_allow_IPI_ops(void)
+{
+	int node;
+	int nasid;
+
+
+	// >>> Change SH_IPI_ACCESS code to use SAL call once it is available.
+
+	if (is_shub2()) {
+		xpc_sh2_IPI_access0 =
+			(u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS0));
+		xpc_sh2_IPI_access1 =
+			(u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS1));
+		xpc_sh2_IPI_access2 =
+			(u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS2));
+		xpc_sh2_IPI_access3 =
+			(u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS3));
+
+		for_each_online_node(node) {
+			nasid = cnodeid_to_nasid(node);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
+								-1UL);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
+								-1UL);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
+								-1UL);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
+								-1UL);
+		}
+
+	} else {
+		xpc_sh1_IPI_access =
+			(u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_IPI_ACCESS));
+
+		for_each_online_node(node) {
+			nasid = cnodeid_to_nasid(node);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
+								-1UL);
+
+			/*
+			 * Since the BIST collides with memory operations on
+			 * SHUB 1.1 sn_change_memprotect() cannot be used.
+			 */
+			if (enable_shub_wars_1_1()) {
+				/* open up everything */
+				xpc_prot_vec[node] = (u64) HUB_L((u64 *)
+						GLOBAL_MMR_ADDR(nasid,
+						SH1_MD_DQLP_MMR_DIR_PRIVEC0));
+				HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid,
+						SH1_MD_DQLP_MMR_DIR_PRIVEC0),
+								-1UL);
+				HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid,
+						SH1_MD_DQRP_MMR_DIR_PRIVEC0),
+								-1UL);
+			}
+		}
+	}
+}
+
+
+/*
+ * Restrict protections to disallow IPI operations (and AMO operations on
+ * Shub 1.1 systems).
+ */
+void
+xpc_restrict_IPI_ops(void)
+{
+	int node;
+	int nasid;
+
+
+	// >>> Change SH_IPI_ACCESS code to use SAL call once it is available.
+
+	if (is_shub2()) {
+
+		for_each_online_node(node) {
+			nasid = cnodeid_to_nasid(node);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
+							xpc_sh2_IPI_access0);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
+							xpc_sh2_IPI_access1);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
+							xpc_sh2_IPI_access2);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
+							xpc_sh2_IPI_access3);
+		}
+
+	} else {
+
+		for_each_online_node(node) {
+			nasid = cnodeid_to_nasid(node);
+			HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
+							xpc_sh1_IPI_access);
+
+			if (enable_shub_wars_1_1()) {
+				HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid,
+						SH1_MD_DQLP_MMR_DIR_PRIVEC0),
+							xpc_prot_vec[node]);
+				HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid,
+						SH1_MD_DQRP_MMR_DIR_PRIVEC0),
+							xpc_prot_vec[node]);
+			}
+		}
+	}
+}
+
+
+/*
+ * At periodic intervals, scan through all active partitions and ensure
+ * their heartbeat is still active.  If not, the partition is deactivated.
+ */
+void
+xpc_check_remote_hb(void)
+{
+	struct xpc_vars *remote_vars;
+	struct xpc_partition *part;
+	partid_t partid;
+	bte_result_t bres;
+
+
+	remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer;
+
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		if (partid == sn_partition_id) {
+			continue;
+		}
+
+		part = &xpc_partitions[partid];
+
+		if (part->act_state == XPC_P_INACTIVE ||
+				part->act_state == XPC_P_DEACTIVATING) {
+			continue;
+		}
+
+		/* pull the remote_hb cache line */
+		bres = xp_bte_copy(part->remote_vars_pa,
+					ia64_tpa((u64) remote_vars),
+					XPC_VARS_ALIGNED_SIZE,
+					(BTE_NOTIFY | BTE_WACQUIRE), NULL);
+		if (bres != BTE_SUCCESS) {
+			XPC_DEACTIVATE_PARTITION(part,
+						xpc_map_bte_errors(bres));
+			continue;
+		}
+
+		dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat"
+			" = %ld, kdb_status = %ld, HB_mask = 0x%lx\n", partid,
+			remote_vars->heartbeat, part->last_heartbeat,
+			remote_vars->kdb_status,
+			remote_vars->heartbeating_to_mask);
+
+		if (((remote_vars->heartbeat == part->last_heartbeat) &&
+			(remote_vars->kdb_status == 0)) ||
+			     !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) {
+
+			XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
+			continue;
+		}
+
+		part->last_heartbeat = remote_vars->heartbeat;
+	}
+}
+
+
+/*
+ * Get a copy of the remote partition's rsvd page.
+ *
+ * remote_rp points to a buffer that is cacheline aligned for BTE copies and
+ * assumed to be of size XPC_RSVD_PAGE_ALIGNED_SIZE.
+ */
+static enum xpc_retval
+xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
+		struct xpc_rsvd_page *remote_rp, u64 *remote_rsvd_page_pa)
+{
+	int bres, i;
+
+
+	/* get the reserved page's physical address */
+
+	*remote_rsvd_page_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp,
+						XPC_RSVD_PAGE_ALIGNED_SIZE);
+	if (*remote_rsvd_page_pa == 0) {
+		return xpcNoRsvdPageAddr;
+	}
+
+
+	/* pull over the reserved page structure */
+
+	bres = xp_bte_copy(*remote_rsvd_page_pa, ia64_tpa((u64) remote_rp),
+				XPC_RSVD_PAGE_ALIGNED_SIZE,
+				(BTE_NOTIFY | BTE_WACQUIRE), NULL);
+	if (bres != BTE_SUCCESS) {
+		return xpc_map_bte_errors(bres);
+	}
+
+
+	if (discovered_nasids != NULL) {
+		for (i = 0; i < XP_NASID_MASK_WORDS; i++) {
+			discovered_nasids[i] |= remote_rp->part_nasids[i];
+		}
+	}
+
+
+	/* check that the partid is for another partition */
+
+	if (remote_rp->partid < 1 ||
+				remote_rp->partid > (XP_MAX_PARTITIONS - 1)) {
+		return xpcInvalidPartid;
+	}
+
+	if (remote_rp->partid == sn_partition_id) {
+		return xpcLocalPartid;
+	}
+
+
+	if (XPC_VERSION_MAJOR(remote_rp->version) !=
+					XPC_VERSION_MAJOR(XPC_RP_VERSION)) {
+		return xpcBadVersion;
+	}
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Get a copy of the remote partition's XPC variables.
+ *
+ * remote_vars points to a buffer that is cacheline aligned for BTE copies and
+ * assumed to be of size XPC_VARS_ALIGNED_SIZE.
+ */
+static enum xpc_retval
+xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
+{
+	int bres;
+
+
+	if (remote_vars_pa == 0) {
+		return xpcVarsNotSet;
+	}
+
+
+	/* pull over the cross partition variables */
+
+	bres = xp_bte_copy(remote_vars_pa, ia64_tpa((u64) remote_vars),
+				XPC_VARS_ALIGNED_SIZE,
+				(BTE_NOTIFY | BTE_WACQUIRE), NULL);
+	if (bres != BTE_SUCCESS) {
+		return xpc_map_bte_errors(bres);
+	}
+
+	if (XPC_VERSION_MAJOR(remote_vars->version) !=
+					XPC_VERSION_MAJOR(XPC_V_VERSION)) {
+		return xpcBadVersion;
+	}
+
+	return xpcSuccess;
+}
+
+
+/*
+ * Prior code has determine the nasid which generated an IPI.  Inspect
+ * that nasid to determine if its partition needs to be activated or
+ * deactivated.
+ *
+ * A partition is consider "awaiting activation" if our partition
+ * flags indicate it is not active and it has a heartbeat.  A
+ * partition is considered "awaiting deactivation" if our partition
+ * flags indicate it is active but it has no heartbeat or it is not
+ * sending its heartbeat to us.
+ *
+ * To determine the heartbeat, the remote nasid must have a properly
+ * initialized reserved page.
+ */
+static void
+xpc_identify_act_IRQ_req(int nasid)
+{
+	struct xpc_rsvd_page *remote_rp;
+	struct xpc_vars *remote_vars;
+	u64 remote_rsvd_page_pa;
+	u64 remote_vars_pa;
+	partid_t partid;
+	struct xpc_partition *part;
+	enum xpc_retval ret;
+
+
+	/* pull over the reserved page structure */
+
+	remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer;
+
+	ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rsvd_page_pa);
+	if (ret != xpcSuccess) {
+		dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
+			"which sent interrupt, reason=%d\n", nasid, ret);
+		return;
+	}
+
+	remote_vars_pa = remote_rp->vars_pa;
+	partid = remote_rp->partid;
+	part = &xpc_partitions[partid];
+
+
+	/* pull over the cross partition variables */
+
+	remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer;
+
+	ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
+	if (ret != xpcSuccess) {
+
+		dev_warn(xpc_part, "unable to get XPC variables from nasid %d, "
+			"which sent interrupt, reason=%d\n", nasid, ret);
+
+		XPC_DEACTIVATE_PARTITION(part, ret);
+		return;
+	}
+
+
+	part->act_IRQ_rcvd++;
+
+	dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = "
+		"%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd,
+		remote_vars->heartbeat, remote_vars->heartbeating_to_mask);
+
+
+	if (part->act_state == XPC_P_INACTIVE) {
+
+		part->remote_rp_pa = remote_rsvd_page_pa;
+		dev_dbg(xpc_part, "  remote_rp_pa = 0x%016lx\n",
+			part->remote_rp_pa);
+
+		part->remote_vars_pa = remote_vars_pa;
+		dev_dbg(xpc_part, "  remote_vars_pa = 0x%016lx\n",
+			part->remote_vars_pa);
+
+		part->last_heartbeat = remote_vars->heartbeat;
+		dev_dbg(xpc_part, "  last_heartbeat = 0x%016lx\n",
+			part->last_heartbeat);
+
+		part->remote_vars_part_pa = remote_vars->vars_part_pa;
+		dev_dbg(xpc_part, "  remote_vars_part_pa = 0x%016lx\n",
+			part->remote_vars_part_pa);
+
+		part->remote_act_nasid = remote_vars->act_nasid;
+		dev_dbg(xpc_part, "  remote_act_nasid = 0x%x\n",
+			part->remote_act_nasid);
+
+		part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid;
+		dev_dbg(xpc_part, "  remote_act_phys_cpuid = 0x%x\n",
+			part->remote_act_phys_cpuid);
+
+		part->remote_amos_page_pa = remote_vars->amos_page_pa;
+		dev_dbg(xpc_part, "  remote_amos_page_pa = 0x%lx\n",
+			part->remote_amos_page_pa);
+
+		xpc_activate_partition(part);
+
+	} else if (part->remote_amos_page_pa != remote_vars->amos_page_pa ||
+			!XPC_HB_ALLOWED(sn_partition_id, remote_vars)) {
+
+		part->reactivate_nasid = nasid;
+		XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
+	}
+}
+
+
+/*
+ * Loop through the activation AMO variables and process any bits
+ * which are set.  Each bit indicates a nasid sending a partition
+ * activation or deactivation request.
+ *
+ * Return #of IRQs detected.
+ */
+int
+xpc_identify_act_IRQ_sender(void)
+{
+	int word, bit;
+	u64 nasid_mask;
+	u64 nasid;			/* remote nasid */
+	int n_IRQs_detected = 0;
+	AMO_t *act_amos;
+	struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page;
+
+
+	act_amos = xpc_vars->act_amos;
+
+
+	/* scan through act AMO variable looking for non-zero entries */
+	for (word = 0; word < XP_NASID_MASK_WORDS; word++) {
+
+		nasid_mask = xpc_IPI_receive(&act_amos[word]);
+		if (nasid_mask == 0) {
+			/* no IRQs from nasids in this variable */
+			continue;
+		}
+
+		dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word,
+			nasid_mask);
+
+
+		/*
+		 * If this nasid has been added to the machine since
+		 * our partition was reset, this will retain the
+		 * remote nasid in our reserved pages machine mask.
+		 * This is used in the event of module reload.
+		 */
+		rp->mach_nasids[word] |= nasid_mask;
+
+
+		/* locate the nasid(s) which sent interrupts */
+
+		for (bit = 0; bit < (8 * sizeof(u64)); bit++) {
+			if (nasid_mask & (1UL << bit)) {
+				n_IRQs_detected++;
+				nasid = XPC_NASID_FROM_W_B(word, bit);
+				dev_dbg(xpc_part, "interrupt from nasid %ld\n",
+					nasid);
+				xpc_identify_act_IRQ_req(nasid);
+			}
+		}
+	}
+	return n_IRQs_detected;
+}
+
+
+/*
+ * Mark specified partition as active.
+ */
+enum xpc_retval
+xpc_mark_partition_active(struct xpc_partition *part)
+{
+	unsigned long irq_flags;
+	enum xpc_retval ret;
+
+
+	dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part));
+
+	spin_lock_irqsave(&part->act_lock, irq_flags);
+	if (part->act_state == XPC_P_ACTIVATING) {
+		part->act_state = XPC_P_ACTIVE;
+		ret = xpcSuccess;
+	} else {
+		DBUG_ON(part->reason == xpcSuccess);
+		ret = part->reason;
+	}
+	spin_unlock_irqrestore(&part->act_lock, irq_flags);
+
+	return ret;
+}
+
+
+/*
+ * Notify XPC that the partition is down.
+ */
+void
+xpc_deactivate_partition(const int line, struct xpc_partition *part,
+				enum xpc_retval reason)
+{
+	unsigned long irq_flags;
+	partid_t partid = XPC_PARTID(part);
+
+
+	spin_lock_irqsave(&part->act_lock, irq_flags);
+
+	if (part->act_state == XPC_P_INACTIVE) {
+		XPC_SET_REASON(part, reason, line);
+		spin_unlock_irqrestore(&part->act_lock, irq_flags);
+		if (reason == xpcReactivating) {
+			/* we interrupt ourselves to reactivate partition */
+			xpc_IPI_send_reactivate(part);
+		}
+		return;
+	}
+	if (part->act_state == XPC_P_DEACTIVATING) {
+		if ((part->reason == xpcUnloading && reason != xpcUnloading) ||
+					reason == xpcReactivating) {
+			XPC_SET_REASON(part, reason, line);
+		}
+		spin_unlock_irqrestore(&part->act_lock, irq_flags);
+		return;
+	}
+
+	part->act_state = XPC_P_DEACTIVATING;
+	XPC_SET_REASON(part, reason, line);
+
+	spin_unlock_irqrestore(&part->act_lock, irq_flags);
+
+	XPC_DISALLOW_HB(partid, xpc_vars);
+
+	dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid,
+		reason);
+
+	xpc_partition_down(part, reason);
+}
+
+
+/*
+ * Mark specified partition as active.
+ */
+void
+xpc_mark_partition_inactive(struct xpc_partition *part)
+{
+	unsigned long irq_flags;
+
+
+	dev_dbg(xpc_part, "setting partition %d to INACTIVE\n",
+		XPC_PARTID(part));
+
+	spin_lock_irqsave(&part->act_lock, irq_flags);
+	part->act_state = XPC_P_INACTIVE;
+	spin_unlock_irqrestore(&part->act_lock, irq_flags);
+	part->remote_rp_pa = 0;
+}
+
+
+/*
+ * SAL has provided a partition and machine mask.  The partition mask
+ * contains a bit for each even nasid in our partition.  The machine
+ * mask contains a bit for each even nasid in the entire machine.
+ *
+ * Using those two bit arrays, we can determine which nasids are
+ * known in the machine.  Each should also have a reserved page
+ * initialized if they are available for partitioning.
+ */
+void
+xpc_discovery(void)
+{
+	void *remote_rp_base;
+	struct xpc_rsvd_page *remote_rp;
+	struct xpc_vars *remote_vars;
+	u64 remote_rsvd_page_pa;
+	u64 remote_vars_pa;
+	int region;
+	int max_regions;
+	int nasid;
+	struct xpc_rsvd_page *rp;
+	partid_t partid;
+	struct xpc_partition *part;
+	u64 *discovered_nasids;
+	enum xpc_retval ret;
+
+
+	remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RSVD_PAGE_ALIGNED_SIZE,
+						GFP_KERNEL, &remote_rp_base);
+	if (remote_rp == NULL) {
+		return;
+	}
+	remote_vars = (struct xpc_vars *) remote_rp;
+
+
+	discovered_nasids = kmalloc(sizeof(u64) * XP_NASID_MASK_WORDS,
+							GFP_KERNEL);
+	if (discovered_nasids == NULL) {
+		kfree(remote_rp_base);
+		return;
+	}
+	memset(discovered_nasids, 0, sizeof(u64) * XP_NASID_MASK_WORDS);
+
+	rp = (struct xpc_rsvd_page *) xpc_rsvd_page;
+
+	/*
+	 * The term 'region' in this context refers to the minimum number of
+	 * nodes that can comprise an access protection grouping. The access
+	 * protection is in regards to memory, IOI and IPI.
+	 */
+//>>> move the next two #defines into either include/asm-ia64/sn/arch.h or
+//>>> include/asm-ia64/sn/addrs.h
+#define SH1_MAX_REGIONS		64
+#define SH2_MAX_REGIONS		256
+	max_regions = is_shub2() ? SH2_MAX_REGIONS : SH1_MAX_REGIONS;
+
+	for (region = 0; region < max_regions; region++) {
+
+		if ((volatile int) xpc_exiting) {
+			break;
+		}
+
+		dev_dbg(xpc_part, "searching region %d\n", region);
+
+		for (nasid = (region * sn_region_size * 2);
+		     nasid < ((region + 1) * sn_region_size * 2);
+		     nasid += 2) {
+
+			if ((volatile int) xpc_exiting) {
+				break;
+			}
+
+			dev_dbg(xpc_part, "checking nasid %d\n", nasid);
+
+
+			if (XPC_NASID_IN_ARRAY(nasid, rp->part_nasids)) {
+				dev_dbg(xpc_part, "PROM indicates Nasid %d is "
+					"part of the local partition; skipping "
+					"region\n", nasid);
+				break;
+			}
+
+			if (!(XPC_NASID_IN_ARRAY(nasid, rp->mach_nasids))) {
+				dev_dbg(xpc_part, "PROM indicates Nasid %d was "
+					"not on Numa-Link network at reset\n",
+					nasid);
+				continue;
+			}
+
+			if (XPC_NASID_IN_ARRAY(nasid, discovered_nasids)) {
+				dev_dbg(xpc_part, "Nasid %d is part of a "
+					"partition which was previously "
+					"discovered\n", nasid);
+				continue;
+			}
+
+
+			/* pull over the reserved page structure */
+
+			ret = xpc_get_remote_rp(nasid, discovered_nasids,
+					      remote_rp, &remote_rsvd_page_pa);
+			if (ret != xpcSuccess) {
+				dev_dbg(xpc_part, "unable to get reserved page "
+					"from nasid %d, reason=%d\n", nasid,
+					ret);
+
+				if (ret == xpcLocalPartid) {
+					break;
+				}
+				continue;
+			}
+
+			remote_vars_pa = remote_rp->vars_pa;
+
+			partid = remote_rp->partid;
+			part = &xpc_partitions[partid];
+
+
+			/* pull over the cross partition variables */
+
+			ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
+			if (ret != xpcSuccess) {
+				dev_dbg(xpc_part, "unable to get XPC variables "
+					"from nasid %d, reason=%d\n", nasid,
+					ret);
+
+				XPC_DEACTIVATE_PARTITION(part, ret);
+				continue;
+			}
+
+			if (part->act_state != XPC_P_INACTIVE) {
+				dev_dbg(xpc_part, "partition %d on nasid %d is "
+					"already activating\n", partid, nasid);
+				break;
+			}
+
+			/*
+			 * Register the remote partition's AMOs with SAL so it
+			 * can handle and cleanup errors within that address
+			 * range should the remote partition go down. We don't
+			 * unregister this range because it is difficult to
+			 * tell when outstanding writes to the remote partition
+			 * are finished and thus when it is thus safe to
+			 * unregister. This should not result in wasted space
+			 * in the SAL xp_addr_region table because we should
+			 * get the same page for remote_act_amos_pa after
+			 * module reloads and system reboots.
+			 */
+			if (sn_register_xp_addr_region(
+					    remote_vars->amos_page_pa,
+							PAGE_SIZE, 1) < 0) {
+				dev_dbg(xpc_part, "partition %d failed to "
+					"register xp_addr region 0x%016lx\n",
+					partid, remote_vars->amos_page_pa);
+
+				XPC_SET_REASON(part, xpcPhysAddrRegFailed,
+						__LINE__);
+				break;
+			}
+
+			/*
+			 * The remote nasid is valid and available.
+			 * Send an interrupt to that nasid to notify
+			 * it that we are ready to begin activation.
+			 */
+			dev_dbg(xpc_part, "sending an interrupt to AMO 0x%lx, "
+				"nasid %d, phys_cpuid 0x%x\n",
+				remote_vars->amos_page_pa,
+				remote_vars->act_nasid,
+				remote_vars->act_phys_cpuid);
+
+			xpc_IPI_send_activate(remote_vars);
+		}
+	}
+
+	kfree(discovered_nasids);
+	kfree(remote_rp_base);
+}
+
+
+/*
+ * Given a partid, get the nasids owned by that partition from the
+ * remote partition's reserved page.
+ */
+enum xpc_retval
+xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask)
+{
+	struct xpc_partition *part;
+	u64 part_nasid_pa;
+	int bte_res;
+
+
+	part = &xpc_partitions[partid];
+	if (part->remote_rp_pa == 0) {
+		return xpcPartitionDown;
+	}
+
+	part_nasid_pa = part->remote_rp_pa +
+		(u64) &((struct xpc_rsvd_page *) 0)->part_nasids;
+
+	bte_res = xp_bte_copy(part_nasid_pa, ia64_tpa((u64) nasid_mask),
+				L1_CACHE_ALIGN(XP_NASID_MASK_BYTES),
+				(BTE_NOTIFY | BTE_WACQUIRE), NULL);
+
+	return xpc_map_bte_errors(bte_res);
+}
+
diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/kernel/xpnet.c
@@ -0,0 +1,715 @@
+/*
+ * 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,2001-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+/*
+ * Cross Partition Network Interface (XPNET) support
+ *
+ *	XPNET provides a virtual network layered on top of the Cross
+ *	Partition communication layer.
+ *
+ *	XPNET provides direct point-to-point and broadcast-like support
+ *	for an ethernet-like device.  The ethernet broadcast medium is
+ *	replaced with a point-to-point message structure which passes
+ *	pointers to a DMA-capable block that a remote partition should
+ *	retrieve and pass to the upper level networking layer.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/smp.h>
+#include <linux/string.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/types.h>
+#include <asm/atomic.h>
+#include <asm/sn/xp.h>
+
+
+/*
+ * The message payload transferred by XPC.
+ *
+ * buf_pa is the physical address where the DMA should pull from.
+ *
+ * NOTE: for performance reasons, buf_pa should _ALWAYS_ begin on a
+ * cacheline boundary.  To accomplish this, we record the number of
+ * bytes from the beginning of the first cacheline to the first useful
+ * byte of the skb (leadin_ignore) and the number of bytes from the
+ * last useful byte of the skb to the end of the last cacheline
+ * (tailout_ignore).
+ *
+ * size is the number of bytes to transfer which includes the skb->len
+ * (useful bytes of the senders skb) plus the leadin and tailout
+ */
+struct xpnet_message {
+	u16 version;		/* Version for this message */
+	u16 embedded_bytes;	/* #of bytes embedded in XPC message */
+	u32 magic;		/* Special number indicating this is xpnet */
+	u64 buf_pa;		/* phys address of buffer to retrieve */
+	u32 size;		/* #of bytes in buffer */
+	u8 leadin_ignore;	/* #of bytes to ignore at the beginning */
+	u8 tailout_ignore;	/* #of bytes to ignore at the end */
+	unsigned char data;	/* body of small packets */
+};
+
+/*
+ * Determine the size of our message, the cacheline aligned size,
+ * and then the number of message will request from XPC.
+ *
+ * XPC expects each message to exist in an individual cacheline.
+ */
+#define XPNET_MSG_SIZE		(L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET)
+#define XPNET_MSG_DATA_MAX	\
+		(XPNET_MSG_SIZE - (u64)(&((struct xpnet_message *)0)->data))
+#define XPNET_MSG_ALIGNED_SIZE	(L1_CACHE_ALIGN(XPNET_MSG_SIZE))
+#define XPNET_MSG_NENTRIES	(PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE)
+
+
+#define XPNET_MAX_KTHREADS	(XPNET_MSG_NENTRIES + 1)
+#define XPNET_MAX_IDLE_KTHREADS	(XPNET_MSG_NENTRIES + 1)
+
+/*
+ * Version number of XPNET implementation. XPNET can always talk to versions
+ * with same major #, and never talk to versions with a different version.
+ */
+#define _XPNET_VERSION(_major, _minor)	(((_major) << 4) | (_minor))
+#define XPNET_VERSION_MAJOR(_v)		((_v) >> 4)
+#define XPNET_VERSION_MINOR(_v)		((_v) & 0xf)
+
+#define	XPNET_VERSION _XPNET_VERSION(1,0)		/* version 1.0 */
+#define	XPNET_VERSION_EMBED _XPNET_VERSION(1,1)		/* version 1.1 */
+#define XPNET_MAGIC	0x88786984 /* "XNET" */
+
+#define XPNET_VALID_MSG(_m)						     \
+   ((XPNET_VERSION_MAJOR(_m->version) == XPNET_VERSION_MAJOR(XPNET_VERSION)) \
+    && (msg->magic == XPNET_MAGIC))
+
+#define XPNET_DEVICE_NAME		"xp0"
+
+
+/*
+ * When messages are queued with xpc_send_notify, a kmalloc'd buffer
+ * of the following type is passed as a notification cookie.  When the
+ * notification function is called, we use the cookie to decide
+ * whether all outstanding message sends have completed.  The skb can
+ * then be released.
+ */
+struct xpnet_pending_msg {
+	struct list_head free_list;
+	struct sk_buff *skb;
+	atomic_t use_count;
+};
+
+/* driver specific structure pointed to by the device structure */
+struct xpnet_dev_private {
+	struct net_device_stats stats;
+};
+
+struct net_device *xpnet_device;
+
+/*
+ * When we are notified of other partitions activating, we add them to
+ * our bitmask of partitions to which we broadcast.
+ */
+static u64 xpnet_broadcast_partitions;
+/* protect above */
+static spinlock_t xpnet_broadcast_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Since the Block Transfer Engine (BTE) is being used for the transfer
+ * and it relies upon cache-line size transfers, we need to reserve at
+ * least one cache-line for head and tail alignment.  The BTE is
+ * limited to 8MB transfers.
+ *
+ * Testing has shown that changing MTU to greater than 64KB has no effect
+ * on TCP as the two sides negotiate a Max Segment Size that is limited
+ * to 64K.  Other protocols May use packets greater than this, but for
+ * now, the default is 64KB.
+ */
+#define XPNET_MAX_MTU (0x800000UL - L1_CACHE_BYTES)
+/* 32KB has been determined to be the ideal */
+#define XPNET_DEF_MTU (0x8000UL)
+
+
+/*
+ * The partition id is encapsulated in the MAC address.  The following
+ * define locates the octet the partid is in.
+ */
+#define XPNET_PARTID_OCTET	1
+#define XPNET_LICENSE_OCTET	2
+
+
+/*
+ * Define the XPNET debug device structure that is to be used with dev_dbg(),
+ * dev_err(), dev_warn(), and dev_info().
+ */
+struct device_driver xpnet_dbg_name = {
+	.name = "xpnet"
+};
+
+struct device xpnet_dbg_subname = {
+	.bus_id = {0},			/* set to "" */
+	.driver = &xpnet_dbg_name
+};
+
+struct device *xpnet = &xpnet_dbg_subname;
+
+/*
+ * Packet was recevied by XPC and forwarded to us.
+ */
+static void
+xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg)
+{
+	struct sk_buff *skb;
+	bte_result_t bret;
+	struct xpnet_dev_private *priv =
+		(struct xpnet_dev_private *) xpnet_device->priv;
+
+
+	if (!XPNET_VALID_MSG(msg)) {
+		/*
+		 * Packet with a different XPC version.  Ignore.
+		 */
+		xpc_received(partid, channel, (void *) msg);
+
+		priv->stats.rx_errors++;
+
+		return;
+	}
+	dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size,
+		msg->leadin_ignore, msg->tailout_ignore);
+
+
+	/* reserve an extra cache line */
+	skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES);
+	if (!skb) {
+		dev_err(xpnet, "failed on dev_alloc_skb(%d)\n",
+			msg->size + L1_CACHE_BYTES);
+
+		xpc_received(partid, channel, (void *) msg);
+
+		priv->stats.rx_errors++;
+
+		return;
+	}
+
+	/*
+	 * The allocated skb has some reserved space.
+	 * In order to use bte_copy, we need to get the
+	 * skb->data pointer moved forward.
+	 */
+	skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data &
+					    (L1_CACHE_BYTES - 1)) +
+			  msg->leadin_ignore));
+
+	/*
+	 * Update the tail pointer to indicate data actually
+	 * transferred.
+	 */
+	skb_put(skb, (msg->size - msg->leadin_ignore - msg->tailout_ignore));
+
+	/*
+	 * Move the data over from the the other side.
+	 */
+	if ((XPNET_VERSION_MINOR(msg->version) == 1) &&
+						(msg->embedded_bytes != 0)) {
+		dev_dbg(xpnet, "copying embedded message. memcpy(0x%p, 0x%p, "
+			"%lu)\n", skb->data, &msg->data,
+			(size_t) msg->embedded_bytes);
+
+		memcpy(skb->data, &msg->data, (size_t) msg->embedded_bytes);
+	} else {
+		dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t"
+			"bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa,
+			(void *)__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)),
+			msg->size);
+
+		bret = bte_copy(msg->buf_pa,
+				__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)),
+				msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
+
+		if (bret != BTE_SUCCESS) {
+			// >>> Need better way of cleaning skb.  Currently skb
+			// >>> appears in_use and we can't just call
+			// >>> dev_kfree_skb.
+			dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned "
+				"error=0x%x\n", (void *)msg->buf_pa,
+				(void *)__pa((u64)skb->data &
+							~(L1_CACHE_BYTES - 1)),
+				msg->size, bret);
+
+			xpc_received(partid, channel, (void *) msg);
+
+			priv->stats.rx_errors++;
+
+			return;
+		}
+	}
+
+	dev_dbg(xpnet, "<skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
+		"skb->end=0x%p skb->len=%d\n", (void *) skb->head,
+		(void *) skb->data, (void *) skb->tail, (void *) skb->end,
+		skb->len);
+
+	skb->dev = xpnet_device;
+	skb->protocol = eth_type_trans(skb, xpnet_device);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	dev_dbg(xpnet, "passing skb to network layer; \n\tskb->head=0x%p "
+		"skb->data=0x%p skb->tail=0x%p skb->end=0x%p skb->len=%d\n",
+		(void *) skb->head, (void *) skb->data, (void *) skb->tail,
+		(void *) skb->end, skb->len);
+
+
+	xpnet_device->last_rx = jiffies;
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += skb->len + ETH_HLEN;
+
+	netif_rx_ni(skb);
+	xpc_received(partid, channel, (void *) msg);
+}
+
+
+/*
+ * This is the handler which XPC calls during any sort of change in
+ * state or message reception on a connection.
+ */
+static void
+xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel,
+			  void *data, void *key)
+{
+	long bp;
+
+
+	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(channel != XPC_NET_CHANNEL);
+
+	switch(reason) {
+	case xpcMsgReceived:	/* message received */
+		DBUG_ON(data == NULL);
+
+		xpnet_receive(partid, channel, (struct xpnet_message *) data);
+		break;
+
+	case xpcConnected:	/* connection completed to a partition */
+		spin_lock_bh(&xpnet_broadcast_lock);
+		xpnet_broadcast_partitions |= 1UL << (partid -1 );
+		bp = xpnet_broadcast_partitions;
+		spin_unlock_bh(&xpnet_broadcast_lock);
+
+		netif_carrier_on(xpnet_device);
+
+		dev_dbg(xpnet, "%s connection created to partition %d; "
+			"xpnet_broadcast_partitions=0x%lx\n",
+			xpnet_device->name, partid, bp);
+		break;
+
+	default:
+		spin_lock_bh(&xpnet_broadcast_lock);
+		xpnet_broadcast_partitions &= ~(1UL << (partid -1 ));
+		bp = xpnet_broadcast_partitions;
+		spin_unlock_bh(&xpnet_broadcast_lock);
+
+		if (bp == 0) {
+			netif_carrier_off(xpnet_device);
+		}
+
+		dev_dbg(xpnet, "%s disconnected from partition %d; "
+			"xpnet_broadcast_partitions=0x%lx\n",
+			xpnet_device->name, partid, bp);
+		break;
+
+	}
+}
+
+
+static int
+xpnet_dev_open(struct net_device *dev)
+{
+	enum xpc_retval ret;
+
+
+	dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %d, "
+		"%d)\n", XPC_NET_CHANNEL, xpnet_connection_activity,
+		XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, XPNET_MAX_KTHREADS,
+		XPNET_MAX_IDLE_KTHREADS);
+
+	ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL,
+			  XPNET_MSG_SIZE, XPNET_MSG_NENTRIES,
+			  XPNET_MAX_KTHREADS, XPNET_MAX_IDLE_KTHREADS);
+	if (ret != xpcSuccess) {
+		dev_err(xpnet, "ifconfig up of %s failed on XPC connect, "
+			"ret=%d\n", dev->name, ret);
+
+		return -ENOMEM;
+	}
+
+	dev_dbg(xpnet, "ifconfig up of %s; XPC connected\n", dev->name);
+
+	return 0;
+}
+
+
+static int
+xpnet_dev_stop(struct net_device *dev)
+{
+	xpc_disconnect(XPC_NET_CHANNEL);
+
+	dev_dbg(xpnet, "ifconfig down of %s; XPC disconnected\n", dev->name);
+
+	return 0;
+}
+
+
+static int
+xpnet_dev_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* 68 comes from min TCP+IP+MAC header */
+	if ((new_mtu < 68) || (new_mtu > XPNET_MAX_MTU)) {
+		dev_err(xpnet, "ifconfig %s mtu %d failed; value must be "
+			"between 68 and %ld\n", dev->name, new_mtu,
+			XPNET_MAX_MTU);
+		return -EINVAL;
+	}
+
+	dev->mtu = new_mtu;
+	dev_dbg(xpnet, "ifconfig %s mtu set to %d\n", dev->name, new_mtu);
+	return 0;
+}
+
+
+/*
+ * Required for the net_device structure.
+ */
+static int
+xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map)
+{
+	return 0;
+}
+
+
+/*
+ * Return statistics to the caller.
+ */
+static struct net_device_stats *
+xpnet_dev_get_stats(struct net_device *dev)
+{
+	struct xpnet_dev_private *priv;
+
+
+	priv = (struct xpnet_dev_private *) dev->priv;
+
+	return &priv->stats;
+}
+
+
+/*
+ * Notification that the other end has received the message and
+ * DMA'd the skb information.  At this point, they are done with
+ * our side.  When all recipients are done processing, we
+ * release the skb and then release our pending message structure.
+ */
+static void
+xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel,
+			void *__qm)
+{
+	struct xpnet_pending_msg *queued_msg =
+		(struct xpnet_pending_msg *) __qm;
+
+
+	DBUG_ON(queued_msg == NULL);
+
+	dev_dbg(xpnet, "message to %d notified with reason %d\n",
+		partid, reason);
+
+	if (atomic_dec_return(&queued_msg->use_count) == 0) {
+		dev_dbg(xpnet, "all acks for skb->head=-x%p\n",
+			(void *) queued_msg->skb->head);
+
+		dev_kfree_skb_any(queued_msg->skb);
+		kfree(queued_msg);
+	}
+}
+
+
+/*
+ * Network layer has formatted a packet (skb) and is ready to place it
+ * "on the wire".  Prepare and send an xpnet_message to all partitions
+ * which have connected with us and are targets of this packet.
+ *
+ * MAC-NOTE:  For the XPNET driver, the MAC address contains the
+ * destination partition_id.  If the destination partition id word
+ * is 0xff, this packet is to broadcast to all partitions.
+ */
+static int
+xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct xpnet_pending_msg *queued_msg;
+	enum xpc_retval ret;
+	struct xpnet_message *msg;
+	u64 start_addr, end_addr;
+	long dp;
+	u8 second_mac_octet;
+	partid_t dest_partid;
+	struct xpnet_dev_private *priv;
+	u16 embedded_bytes;
+
+
+	priv = (struct xpnet_dev_private *) dev->priv;
+
+
+	dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
+		"skb->end=0x%p skb->len=%d\n", (void *) skb->head,
+		(void *) skb->data, (void *) skb->tail, (void *) skb->end,
+		skb->len);
+
+
+	/*
+	 * The xpnet_pending_msg tracks how many outstanding
+	 * xpc_send_notifies are relying on this skb.  When none
+	 * remain, release the skb.
+	 */
+	queued_msg = kmalloc(sizeof(struct xpnet_pending_msg), GFP_ATOMIC);
+	if (queued_msg == NULL) {
+		dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping "
+			"packet\n", sizeof(struct xpnet_pending_msg));
+
+		priv->stats.tx_errors++;
+
+		return -ENOMEM;
+	}
+
+
+	/* get the beginning of the first cacheline and end of last */
+	start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1));
+	end_addr = L1_CACHE_ALIGN((u64) skb->tail);
+
+	/* calculate how many bytes to embed in the XPC message */
+	embedded_bytes = 0;
+	if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) {
+		/* skb->data does fit so embed */
+		embedded_bytes = skb->len;
+	}
+
+
+	/*
+	 * Since the send occurs asynchronously, we set the count to one
+	 * and begin sending.  Any sends that happen to complete before
+	 * we are done sending will not free the skb.  We will be left
+	 * with that task during exit.  This also handles the case of
+	 * a packet destined for a partition which is no longer up.
+	 */
+	atomic_set(&queued_msg->use_count, 1);
+	queued_msg->skb = skb;
+
+
+	second_mac_octet = skb->data[XPNET_PARTID_OCTET];
+	if (second_mac_octet == 0xff) {
+		/* we are being asked to broadcast to all partitions */
+		dp = xpnet_broadcast_partitions;
+	} else if (second_mac_octet != 0) {
+		dp = xpnet_broadcast_partitions &
+					(1UL << (second_mac_octet - 1));
+	} else {
+		/* 0 is an invalid partid.  Ignore */
+		dp = 0;
+	}
+	dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp);
+
+	/*
+	 * If we wanted to allow promiscous mode to work like an
+	 * unswitched network, this would be a good point to OR in a
+	 * mask of partitions which should be receiving all packets.
+	 */
+
+	/*
+	 * Main send loop.
+	 */
+	for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS;
+	     dest_partid++) {
+
+
+		if (!(dp & (1UL << (dest_partid - 1)))) {
+			/* not destined for this partition */
+			continue;
+		}
+
+		/* remove this partition from the destinations mask */
+		dp &= ~(1UL << (dest_partid - 1));
+
+
+		/* found a partition to send to */
+
+		ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL,
+				   XPC_NOWAIT, (void **)&msg);
+		if (unlikely(ret != xpcSuccess)) {
+			continue;
+		}
+
+		msg->embedded_bytes = embedded_bytes;
+		if (unlikely(embedded_bytes != 0)) {
+			msg->version = XPNET_VERSION_EMBED;
+			dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n",
+				&msg->data, skb->data, (size_t) embedded_bytes);
+			memcpy(&msg->data, skb->data, (size_t) embedded_bytes);
+		} else {
+			msg->version = XPNET_VERSION;
+		}
+		msg->magic = XPNET_MAGIC;
+		msg->size = end_addr - start_addr;
+		msg->leadin_ignore = (u64) skb->data - start_addr;
+		msg->tailout_ignore = end_addr - (u64) skb->tail;
+		msg->buf_pa = __pa(start_addr);
+
+		dev_dbg(xpnet, "sending XPC message to %d:%d\nmsg->buf_pa="
+			"0x%lx, msg->size=%u, msg->leadin_ignore=%u, "
+			"msg->tailout_ignore=%u\n", dest_partid,
+			XPC_NET_CHANNEL, msg->buf_pa, msg->size,
+			msg->leadin_ignore, msg->tailout_ignore);
+
+
+		atomic_inc(&queued_msg->use_count);
+
+		ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg,
+				      xpnet_send_completed, queued_msg);
+		if (unlikely(ret != xpcSuccess)) {
+			atomic_dec(&queued_msg->use_count);
+			continue;
+		}
+
+	}
+
+	if (atomic_dec_return(&queued_msg->use_count) == 0) {
+		dev_dbg(xpnet, "no partitions to receive packet destined for "
+			"%d\n", dest_partid);
+
+
+		dev_kfree_skb(skb);
+		kfree(queued_msg);
+	}
+
+	priv->stats.tx_packets++;
+	priv->stats.tx_bytes += skb->len;
+
+	return 0;
+}
+
+
+/*
+ * Deal with transmit timeouts coming from the network layer.
+ */
+static void
+xpnet_dev_tx_timeout (struct net_device *dev)
+{
+	struct xpnet_dev_private *priv;
+
+
+	priv = (struct xpnet_dev_private *) dev->priv;
+
+	priv->stats.tx_errors++;
+	return;
+}
+
+
+static int __init
+xpnet_init(void)
+{
+	int i;
+	u32 license_num;
+	int result = -ENOMEM;
+
+
+	dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);
+
+	/*
+	 * use ether_setup() to init the majority of our device
+	 * structure and then override the necessary pieces.
+	 */
+	xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private),
+				    XPNET_DEVICE_NAME, ether_setup);
+	if (xpnet_device == NULL) {
+		return -ENOMEM;
+	}
+
+	netif_carrier_off(xpnet_device);
+
+	xpnet_device->mtu = XPNET_DEF_MTU;
+	xpnet_device->change_mtu = xpnet_dev_change_mtu;
+	xpnet_device->open = xpnet_dev_open;
+	xpnet_device->get_stats = xpnet_dev_get_stats;
+	xpnet_device->stop = xpnet_dev_stop;
+	xpnet_device->hard_start_xmit = xpnet_dev_hard_start_xmit;
+	xpnet_device->tx_timeout = xpnet_dev_tx_timeout;
+	xpnet_device->set_config = xpnet_dev_set_config;
+
+	/*
+	 * Multicast assumes the LSB of the first octet is set for multicast
+	 * MAC addresses.  We chose the first octet of the MAC to be unlikely
+	 * to collide with any vendor's officially issued MAC.
+	 */
+	xpnet_device->dev_addr[0] = 0xfe;
+	xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id;
+	license_num = sn_partition_serial_number_val();
+	for (i = 3; i >= 0; i--) {
+		xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] =
+							license_num & 0xff;
+		license_num = license_num >> 8;
+	}
+
+	/*
+	 * ether_setup() sets this to a multicast device.  We are
+	 * really not supporting multicast at this time.
+	 */
+	xpnet_device->flags &= ~IFF_MULTICAST;
+
+	/*
+	 * No need to checksum as it is a DMA transfer.  The BTE will
+	 * report an error if the data is not retrievable and the
+	 * packet will be dropped.
+	 */
+	xpnet_device->features = NETIF_F_NO_CSUM;
+
+	result = register_netdev(xpnet_device);
+	if (result != 0) {
+		free_netdev(xpnet_device);
+	}
+
+	return result;
+}
+module_init(xpnet_init);
+
+
+static void __exit
+xpnet_exit(void)
+{
+	dev_info(xpnet, "unregistering network device %s\n",
+		xpnet_device[0].name);
+
+	unregister_netdev(xpnet_device);
+
+	free_netdev(xpnet_device);
+}
+module_exit(xpnet_exit);
+
+
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Cross Partition Network adapter (XPNET)");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile
--- a/arch/ia64/sn/pci/Makefile
+++ b/arch/ia64/sn/pci/Makefile
@@ -7,4 +7,4 @@
 #
 # Makefile for the sn pci general routines.
 
-obj-y := pci_dma.o pcibr/ 
+obj-y := pci_dma.o tioca_provider.o pcibr/ 
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -12,9 +12,8 @@
 #include <linux/module.h>
 #include <asm/dma.h>
 #include <asm/sn/sn_sal.h>
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
-#include "pci/pcibr_provider.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 
 #define SG_ENT_VIRT_ADDRESS(sg)	(page_address((sg)->page) + (sg)->offset)
 #define SG_ENT_PHYS_ADDRESS(SG)	virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
@@ -79,7 +78,8 @@ void *sn_dma_alloc_coherent(struct devic
 {
 	void *cpuaddr;
 	unsigned long phys_addr;
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	BUG_ON(dev->bus != &pci_bus_type);
 
@@ -102,8 +102,7 @@ void *sn_dma_alloc_coherent(struct devic
 	 * resources.
 	 */
 
-	*dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size,
-				    SN_PCIDMA_CONSISTENT);
+	*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
 	if (!*dma_handle) {
 		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
 		free_pages((unsigned long)cpuaddr, get_order(size));
@@ -127,11 +126,12 @@ EXPORT_SYMBOL(sn_dma_alloc_coherent);
 void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
 			  dma_addr_t dma_handle)
 {
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	BUG_ON(dev->bus != &pci_bus_type);
 
-	pcibr_dma_unmap(pcidev_info, dma_handle, 0);
+	provider->dma_unmap(pdev, dma_handle, 0);
 	free_pages((unsigned long)cpu_addr, get_order(size));
 }
 EXPORT_SYMBOL(sn_dma_free_coherent);
@@ -159,12 +159,13 @@ dma_addr_t sn_dma_map_single(struct devi
 {
 	dma_addr_t dma_addr;
 	unsigned long phys_addr;
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	BUG_ON(dev->bus != &pci_bus_type);
 
 	phys_addr = __pa(cpu_addr);
-	dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0);
+	dma_addr = provider->dma_map(pdev, phys_addr, size);
 	if (!dma_addr) {
 		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
 		return 0;
@@ -187,10 +188,12 @@ EXPORT_SYMBOL(sn_dma_map_single);
 void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
 			 int direction)
 {
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	BUG_ON(dev->bus != &pci_bus_type);
-	pcibr_dma_unmap(pcidev_info, dma_addr, direction);
+
+	provider->dma_unmap(pdev, dma_addr, direction);
 }
 EXPORT_SYMBOL(sn_dma_unmap_single);
 
@@ -207,12 +210,13 @@ void sn_dma_unmap_sg(struct device *dev,
 		     int nhwentries, int direction)
 {
 	int i;
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	BUG_ON(dev->bus != &pci_bus_type);
 
 	for (i = 0; i < nhwentries; i++, sg++) {
-		pcibr_dma_unmap(pcidev_info, sg->dma_address, direction);
+		provider->dma_unmap(pdev, sg->dma_address, direction);
 		sg->dma_address = (dma_addr_t) NULL;
 		sg->dma_length = 0;
 	}
@@ -233,7 +237,8 @@ int sn_dma_map_sg(struct device *dev, st
 {
 	unsigned long phys_addr;
 	struct scatterlist *saved_sg = sg;
-	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev));
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 	int i;
 
 	BUG_ON(dev->bus != &pci_bus_type);
@@ -243,8 +248,8 @@ int sn_dma_map_sg(struct device *dev, st
 	 */
 	for (i = 0; i < nhwentries; i++, sg++) {
 		phys_addr = SG_ENT_PHYS_ADDRESS(sg);
-		sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr,
-						sg->length, 0);
+		sg->dma_address = provider->dma_map(pdev,
+						    phys_addr, sg->length);
 
 		if (!sg->dma_address) {
 			printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
--- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
@@ -8,8 +8,8 @@
 
 #include <linux/types.h>
 #include <asm/sn/sn_sal.h>
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/pcibr_provider.h"
 
 int pcibr_invalidate_ate = 0;	/* by default don't invalidate ATE on free */
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -12,8 +12,8 @@
 #include <asm/sn/geo.h>
 #include "xtalk/xwidgetdev.h"
 #include "xtalk/hubdev.h"
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/tiocp.h"
 #include "pci/pic.h"
 #include "pci/pcibr_provider.h"
@@ -40,7 +40,7 @@ extern int sn_ioif_inited;
  *      we do not have to allocate entries in the PMU.
  */
 
-static uint64_t
+static dma_addr_t
 pcibr_dmamap_ate32(struct pcidev_info *info,
 		   uint64_t paddr, size_t req_size, uint64_t flags)
 {
@@ -109,7 +109,7 @@ pcibr_dmamap_ate32(struct pcidev_info *i
 	return pci_addr;
 }
 
-static uint64_t
+static dma_addr_t
 pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr,
 			uint64_t dma_attributes)
 {
@@ -141,7 +141,7 @@ pcibr_dmatrans_direct64(struct pcidev_in
 
 }
 
-static uint64_t
+static dma_addr_t
 pcibr_dmatrans_direct32(struct pcidev_info * info,
 			uint64_t paddr, size_t req_size, uint64_t flags)
 {
@@ -180,11 +180,11 @@ pcibr_dmatrans_direct32(struct pcidev_in
  * DMA mappings for Direct 64 and 32 do not have any DMA maps.
  */
 void
-pcibr_dma_unmap(struct pcidev_info *pcidev_info, dma_addr_t dma_handle,
-		int direction)
+pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction)
 {
-	struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
-	    pdi_pcibus_info;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+	struct pcibus_info *pcibus_info =
+	    (struct pcibus_info *)pcidev_info->pdi_pcibus_info;
 
 	if (IS_PCI32_MAPPED(dma_handle)) {
 		int ate_index;
@@ -301,7 +301,7 @@ void sn_dma_flush(uint64_t addr)
 		spin_lock_irqsave(&((struct sn_flush_device_list *)p)->
 				  sfdl_flush_lock, flags);
 
-		p->sfdl_flush_value = 0;
+		*p->sfdl_flush_addr = 0;
 
 		/* force an interrupt. */
 		*(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
@@ -316,64 +316,63 @@ void sn_dma_flush(uint64_t addr)
 }
 
 /*
- * Wrapper DMA interface.  Called from pci_dma.c routines.
+ * DMA interfaces.  Called from pci_dma.c routines.
  */
 
-uint64_t
-pcibr_dma_map(struct pcidev_info * pcidev_info, unsigned long phys_addr,
-	      size_t size, unsigned int flags)
+dma_addr_t
+pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
 {
 	dma_addr_t dma_handle;
-	struct pci_dev *pcidev = pcidev_info->pdi_linux_pcidev;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
 
-	if (flags & SN_PCIDMA_CONSISTENT) {
-		/* sn_pci_alloc_consistent interfaces */
-		if (pcidev->dev.coherent_dma_mask == ~0UL) {
-			dma_handle =
-			    pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-						    PCI64_ATTR_BAR);
-		} else {
-			dma_handle =
-			    (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
-							    phys_addr, size,
-							    PCI32_ATE_BAR);
-		}
-	} else {
-		/* map_sg/map_single interfaces */
+	/* SN cannot support DMA addresses smaller than 32 bits. */
+	if (hwdev->dma_mask < 0x7fffffff) {
+		return 0;
+	}
 
-		/* SN cannot support DMA addresses smaller than 32 bits. */
-		if (pcidev->dma_mask < 0x7fffffff) {
-			return 0;
-		}
+	if (hwdev->dma_mask == ~0UL) {
+		/*
+		 * Handle the most common case: 64 bit cards.  This
+		 * call should always succeed.
+		 */
 
-		if (pcidev->dma_mask == ~0UL) {
+		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+						     PCI64_ATTR_PREF);
+	} else {
+		/* Handle 32-63 bit cards via direct mapping */
+		dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
+						     size, 0);
+		if (!dma_handle) {
 			/*
-			 * Handle the most common case: 64 bit cards.  This
-			 * call should always succeed.
+			 * It is a 32 bit card and we cannot do direct mapping,
+			 * so we use an ATE.
 			 */
 
-			dma_handle =
-			    pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-						    PCI64_ATTR_PREF);
-		} else {
-			/* Handle 32-63 bit cards via direct mapping */
-			dma_handle =
-			    pcibr_dmatrans_direct32(pcidev_info, phys_addr,
-						    size, 0);
-			if (!dma_handle) {
-				/*
-				 * It is a 32 bit card and we cannot do direct mapping,
-				 * so we use an ATE.
-				 */
-
-				dma_handle =
-				    pcibr_dmamap_ate32(pcidev_info, phys_addr,
-						       size, PCI32_ATE_PREF);
-			}
+			dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
+							size, PCI32_ATE_PREF);
 		}
 	}
 
 	return dma_handle;
 }
 
+dma_addr_t
+pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
+			 size_t size)
+{
+	dma_addr_t dma_handle;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+
+	if (hwdev->dev.coherent_dma_mask == ~0UL) {
+		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+					    PCI64_ATTR_BAR);
+	} else {
+		dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
+						    phys_addr, size,
+						    PCI32_ATE_BAR);
+	}
+
+	return dma_handle;
+}
+
 EXPORT_SYMBOL(sn_dma_flush);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -13,8 +13,8 @@
 #include "xtalk/xwidgetdev.h"
 #include <asm/sn/geo.h>
 #include "xtalk/hubdev.h"
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/pcibr_provider.h"
 #include <asm/sn/addrs.h>
 
@@ -168,3 +168,23 @@ void pcibr_change_devices_irq(struct sn_
 		pcibr_force_interrupt(sn_irq_info);
 	}
 }
+
+/*
+ * Provider entries for PIC/CP
+ */
+
+struct sn_pcibus_provider pcibr_provider = {
+	.dma_map = pcibr_dma_map,
+	.dma_map_consistent = pcibr_dma_map_consistent,
+	.dma_unmap = pcibr_dma_unmap,
+	.bus_fixup = pcibr_bus_fixup,
+};
+
+int
+pcibr_init_provider(void)
+{
+	sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider;
+	sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider;
+
+	return 0;
+}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
--- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
@@ -8,8 +8,8 @@
 
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include "pci/pcibus_provider_defs.h"
-#include "pci/pcidev.h"
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
 #include "pci/tiocp.h"
 #include "pci/pic.h"
 #include "pci/pcibr_provider.h"
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
new file mode 100644
--- /dev/null
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -0,0 +1,668 @@
+/*
+ * 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) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioca_provider.h>
+
+uint32_t tioca_gart_found;
+EXPORT_SYMBOL(tioca_gart_found);	/* used by agp-sgi */
+
+LIST_HEAD(tioca_list);
+EXPORT_SYMBOL(tioca_list);	/* used by agp-sgi */
+
+static int tioca_gart_init(struct tioca_kernel *);
+
+/**
+ * tioca_gart_init - Initialize SGI TIOCA GART
+ * @tioca_common: ptr to common prom/kernel struct identifying the 
+ *
+ * If the indicated tioca has devices present, initialize its associated
+ * GART MMR's and kernel memory.
+ */
+static int
+tioca_gart_init(struct tioca_kernel *tioca_kern)
+{
+	uint64_t ap_reg;
+	uint64_t offset;
+	struct page *tmp;
+	struct tioca_common *tioca_common;
+	volatile struct tioca *ca_base;
+
+	tioca_common = tioca_kern->ca_common;
+	ca_base = (struct tioca *)tioca_common->ca_common.bs_base;
+
+	if (list_empty(tioca_kern->ca_devices))
+		return 0;
+
+	ap_reg = 0;
+
+	/*
+	 * Validate aperature size
+	 */
+
+	switch (CA_APERATURE_SIZE >> 20) {
+	case 4:
+		ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT);	/* 4MB */
+		break;
+	case 8:
+		ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT);	/* 8MB */
+		break;
+	case 16:
+		ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT);	/* 16MB */
+		break;
+	case 32:
+		ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT);	/* 32 MB */
+		break;
+	case 64:
+		ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT);	/* 64 MB */
+		break;
+	case 128:
+		ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT);	/* 128 MB */
+		break;
+	case 256:
+		ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT);	/* 256 MB */
+		break;
+	case 512:
+		ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT);	/* 512 MB */
+		break;
+	case 1024:
+		ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT);	/* 1GB */
+		break;
+	case 2048:
+		ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT);	/* 2GB */
+		break;
+	case 4096:
+		ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT);	/* 4 GB */
+		break;
+	default:
+		printk(KERN_ERR "%s:  Invalid CA_APERATURE_SIZE "
+		       "0x%lx\n", __FUNCTION__, (ulong) CA_APERATURE_SIZE);
+		return -1;
+	}
+
+	/*
+	 * Set up other aperature parameters
+	 */
+
+	if (PAGE_SIZE >= 16384) {
+		tioca_kern->ca_ap_pagesize = 16384;
+		ap_reg |= CA_GART_PAGE_SIZE;
+	} else {
+		tioca_kern->ca_ap_pagesize = 4096;
+	}
+
+	tioca_kern->ca_ap_size = CA_APERATURE_SIZE;
+	tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE;
+	tioca_kern->ca_gart_entries =
+	    tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize;
+
+	ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI);
+	ap_reg |= tioca_kern->ca_ap_bus_base;
+
+	/*
+	 * Allocate and set up the GART
+	 */
+
+	tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64);
+	tmp =
+	    alloc_pages_node(tioca_kern->ca_closest_node,
+			     GFP_KERNEL | __GFP_ZERO,
+			     get_order(tioca_kern->ca_gart_size));
+
+	if (!tmp) {
+		printk(KERN_ERR "%s:  Could not allocate "
+		       "%lu bytes (order %d) for GART\n",
+		       __FUNCTION__,
+		       tioca_kern->ca_gart_size,
+		       get_order(tioca_kern->ca_gart_size));
+		return -ENOMEM;
+	}
+
+	tioca_kern->ca_gart = page_address(tmp);
+	tioca_kern->ca_gart_coretalk_addr =
+	    PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart));
+
+	/*
+	 * Compute PCI/AGP convenience fields 
+	 */
+
+	offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE;
+	tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE;
+	tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE;
+	tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize;
+	tioca_kern->ca_pcigart_base =
+	    tioca_kern->ca_gart_coretalk_addr + offset;
+	tioca_kern->ca_pcigart =
+	    &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start];
+	tioca_kern->ca_pcigart_entries =
+	    tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize;
+	tioca_kern->ca_pcigart_pagemap =
+	    kcalloc(1, tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
+	if (!tioca_kern->ca_pcigart_pagemap) {
+		free_pages((unsigned long)tioca_kern->ca_gart,
+			   get_order(tioca_kern->ca_gart_size));
+		return -1;
+	}
+
+	offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE;
+	tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE;
+	tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE;
+	tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize;
+	tioca_kern->ca_gfxgart_base =
+	    tioca_kern->ca_gart_coretalk_addr + offset;
+	tioca_kern->ca_gfxgart =
+	    &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start];
+	tioca_kern->ca_gfxgart_entries =
+	    tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize;
+
+	/*
+	 * various control settings:
+	 *      use agp op-combining
+	 *      use GET semantics to fetch memory
+	 *      participate in coherency domain
+	 * 	DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029
+	 */
+
+	ca_base->ca_control1 |= CA_AGPDMA_OP_ENB_COMBDELAY;	/* PV895469 ? */
+	ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM);
+	ca_base->ca_control2 |= (0x2ull << CA_GART_MEM_PARAM_SHFT);
+	tioca_kern->ca_gart_iscoherent = 1;
+	ca_base->ca_control2 &=
+	    ~(CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB);
+
+	/*
+	 * Unmask GART fetch error interrupts.  Clear residual errors first.
+	 */
+
+	ca_base->ca_int_status_alias = CA_GART_FETCH_ERR;
+	ca_base->ca_mult_error_alias = CA_GART_FETCH_ERR;
+	ca_base->ca_int_mask &= ~CA_GART_FETCH_ERR;
+
+	/*
+	 * Program the aperature and gart registers in TIOCA
+	 */
+
+	ca_base->ca_gart_aperature = ap_reg;
+	ca_base->ca_gart_ptr_table = tioca_kern->ca_gart_coretalk_addr | 1;
+
+	return 0;
+}
+
+/**
+ * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions
+ * @tioca_kernel: structure representing the CA
+ *
+ * Given a CA, scan all attached functions making sure they all support
+ * FastWrite.  If so, enable FastWrite for all functions and the CA itself.
+ */
+
+void
+tioca_fastwrite_enable(struct tioca_kernel *tioca_kern)
+{
+	int cap_ptr;
+	uint64_t ca_control1;
+	uint32_t reg;
+	struct tioca *tioca_base;
+	struct pci_dev *pdev;
+	struct tioca_common *common;
+
+	common = tioca_kern->ca_common;
+
+	/*
+	 * Scan all vga controllers on this bus making sure they all
+	 * suport FW.  If not, return.
+	 */
+
+	list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) {
+		if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
+			continue;
+
+		cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+		if (!cap_ptr)
+			return;	/* no AGP CAP means no FW */
+
+		pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, &reg);
+		if (!(reg & PCI_AGP_STATUS_FW))
+			return;	/* function doesn't support FW */
+	}
+
+	/*
+	 * Set fw for all vga fn's
+	 */
+
+	list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) {
+		if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
+			continue;
+
+		cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+		pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, &reg);
+		reg |= PCI_AGP_COMMAND_FW;
+		pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg);
+	}
+
+	/*
+	 * Set ca's fw to match
+	 */
+
+	tioca_base = (struct tioca *)common->ca_common.bs_base;
+	ca_control1 = tioca_base->ca_control1;
+	ca_control1 |= CA_AGP_FW_ENABLE;
+	tioca_base->ca_control1 = ca_control1;
+}
+
+EXPORT_SYMBOL(tioca_fastwrite_enable);	/* used by agp-sgi */
+
+/**
+ * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode
+ * @paddr: system physical address
+ *
+ * Map @paddr into 64-bit CA bus space.  No device context is necessary.
+ * Bits 53:0 come from the coretalk address.  We just need to mask in the
+ * following optional bits of the 64-bit pci address:
+ *
+ * 63:60 - Coretalk Packet Type -  0x1 for Mem Get/Put (coherent)
+ *                                 0x2 for PIO (non-coherent)
+ *                                 We will always use 0x1
+ * 55:55 - Swap bytes		   Currently unused
+ */
+static uint64_t
+tioca_dma_d64(unsigned long paddr)
+{
+	dma_addr_t bus_addr;
+
+	bus_addr = PHYS_TO_TIODMA(paddr);
+
+	BUG_ON(!bus_addr);
+	BUG_ON(bus_addr >> 54);
+
+	/* Set upper nibble to Cache Coherent Memory op */
+	bus_addr |= (1UL << 60);
+
+	return bus_addr;
+}
+
+/**
+ * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode
+ * @pdev: linux pci_dev representing the function
+ * @paddr: system physical address
+ *
+ * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info.
+ *
+ * The CA agp 48 bit direct address falls out as follows:
+ *
+ * When direct mapping AGP addresses, the 48 bit AGP address is
+ * constructed as follows:
+ *
+ * [47:40] - Low 8 bits of the page Node ID extracted from coretalk
+ *              address [47:40].  The upper 8 node bits are fixed
+ *              and come from the xxx register bits [5:0]
+ * [39:38] - Chiplet ID extracted from coretalk address [39:38]
+ * [37:00] - node offset extracted from coretalk address [37:00]
+ * 
+ * Since the node id in general will be non-zero, and the chiplet id
+ * will always be non-zero, it follows that the device must support
+ * a dma mask of at least 0xffffffffff (40 bits) to target node 0
+ * and in general should be 0xffffffffffff (48 bits) to target nodes
+ * up to 255.  Nodes above 255 need the support of the xxx register,
+ * and so a given CA can only directly target nodes in the range
+ * xxx - xxx+255.
+ */
+static uint64_t
+tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr)
+{
+	struct tioca_common *tioca_common;
+	struct tioca *ca_base;
+	uint64_t ct_addr;
+	dma_addr_t bus_addr;
+	uint32_t node_upper;
+	uint64_t agp_dma_extn;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);
+
+	tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
+	ca_base = (struct tioca *)tioca_common->ca_common.bs_base;
+
+	ct_addr = PHYS_TO_TIODMA(paddr);
+	if (!ct_addr)
+		return 0;
+
+	bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffff);
+	node_upper = ct_addr >> 48;
+
+	if (node_upper > 64) {
+		printk(KERN_ERR "%s:  coretalk addr 0x%p node id out "
+		       "of range\n", __FUNCTION__, (void *)ct_addr);
+		return 0;
+	}
+
+	agp_dma_extn = ca_base->ca_agp_dma_addr_extn;
+	if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) {
+		printk(KERN_ERR "%s:  coretalk upper node (%u) "
+		       "mismatch with ca_agp_dma_addr_extn (%lu)\n",
+		       __FUNCTION__,
+		       node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT));
+		return 0;
+	}
+
+	return bus_addr;
+}
+
+/**
+ * tioca_dma_mapped - create a DMA mapping using a CA GART 
+ * @pdev: linux pci_dev representing the function
+ * @paddr: host physical address to map
+ * @req_size: len (bytes) to map
+ *
+ * Map @paddr into CA address space using the GART mechanism.  The mapped
+ * dma_addr_t is guarenteed to be contiguous in CA bus space.
+ */
+static dma_addr_t
+tioca_dma_mapped(struct pci_dev *pdev, uint64_t paddr, size_t req_size)
+{
+	int i, ps, ps_shift, entry, entries, mapsize, last_entry;
+	uint64_t xio_addr, end_xio_addr;
+	struct tioca_common *tioca_common;
+	struct tioca_kernel *tioca_kern;
+	dma_addr_t bus_addr = 0;
+	struct tioca_dmamap *ca_dmamap;
+	void *map;
+	unsigned long flags;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);;
+
+	tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
+	tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;
+
+	xio_addr = PHYS_TO_TIODMA(paddr);
+	if (!xio_addr)
+		return 0;
+
+	spin_lock_irqsave(&tioca_kern->ca_lock, flags);
+
+	/*
+	 * allocate a map struct
+	 */
+
+	ca_dmamap = kcalloc(1, sizeof(struct tioca_dmamap), GFP_ATOMIC);
+	if (!ca_dmamap)
+		goto map_return;
+
+	/*
+	 * Locate free entries that can hold req_size.  Account for
+	 * unaligned start/length when allocating.
+	 */
+
+	ps = tioca_kern->ca_ap_pagesize;	/* will be power of 2 */
+	ps_shift = ffs(ps) - 1;
+	end_xio_addr = xio_addr + req_size - 1;
+
+	entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1;
+
+	map = tioca_kern->ca_pcigart_pagemap;
+	mapsize = tioca_kern->ca_pcigart_entries;
+
+	entry = find_first_zero_bit(map, mapsize);
+	while (entry < mapsize) {
+		last_entry = find_next_bit(map, mapsize, entry);
+
+		if (last_entry - entry >= entries)
+			break;
+
+		entry = find_next_zero_bit(map, mapsize, last_entry);
+	}
+
+	if (entry > mapsize)
+		goto map_return;
+
+	for (i = 0; i < entries; i++)
+		set_bit(entry + i, map);
+
+	bus_addr = tioca_kern->ca_pciap_base + (entry * ps);
+
+	ca_dmamap->cad_dma_addr = bus_addr;
+	ca_dmamap->cad_gart_size = entries;
+	ca_dmamap->cad_gart_entry = entry;
+	list_add(&ca_dmamap->cad_list, &tioca_kern->ca_dmamaps);
+
+	if (xio_addr % ps) {
+		tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);
+		bus_addr += xio_addr & (ps - 1);
+		xio_addr &= ~(ps - 1);
+		xio_addr += ps;
+		entry++;
+	}
+
+	while (xio_addr < end_xio_addr) {
+		tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);
+		xio_addr += ps;
+		entry++;
+	}
+
+	tioca_tlbflush(tioca_kern);
+
+map_return:
+	spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);
+	return bus_addr;
+}
+
+/**
+ * tioca_dma_unmap - release CA mapping resources
+ * @pdev: linux pci_dev representing the function
+ * @bus_addr: bus address returned by an earlier tioca_dma_map
+ * @dir: mapping direction (unused)
+ *
+ * Locate mapping resources associated with @bus_addr and release them.
+ * For mappings created using the direct modes (64 or 48) there are no
+ * resources to release.
+ */
+void
+tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
+{
+	int i, entry;
+	struct tioca_common *tioca_common;
+	struct tioca_kernel *tioca_kern;
+	struct tioca_dmamap *map;
+	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);
+	unsigned long flags;
+
+	tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
+	tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;
+
+	/* return straight away if this isn't be a mapped address */
+
+	if (bus_addr < tioca_kern->ca_pciap_base ||
+	    bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size))
+		return;
+
+	spin_lock_irqsave(&tioca_kern->ca_lock, flags);
+
+	list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list)
+	    if (map->cad_dma_addr == bus_addr)
+		break;
+
+	BUG_ON(map == NULL);
+
+	entry = map->cad_gart_entry;
+
+	for (i = 0; i < map->cad_gart_size; i++, entry++) {
+		clear_bit(entry, tioca_kern->ca_pcigart_pagemap);
+		tioca_kern->ca_pcigart[entry] = 0;
+	}
+	tioca_tlbflush(tioca_kern);
+
+	list_del(&map->cad_list);
+	spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);
+	kfree(map);
+}
+
+/**
+ * tioca_dma_map - map pages for PCI DMA
+ * @pdev: linux pci_dev representing the function
+ * @paddr: host physical address to map
+ * @byte_count: bytes to map
+ *
+ * This is the main wrapper for mapping host physical pages to CA PCI space.
+ * The mapping mode used is based on the devices dma_mask.  As a last resort
+ * use the GART mapped mode.
+ */
+uint64_t
+tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+	uint64_t mapaddr;
+
+	/*
+	 * If card is 64 or 48 bit addresable, use a direct mapping.  32
+	 * bit direct is so restrictive w.r.t. where the memory resides that
+	 * we don't use it even though CA has some support.
+	 */
+
+	if (pdev->dma_mask == ~0UL)
+		mapaddr = tioca_dma_d64(paddr);
+	else if (pdev->dma_mask == 0xffffffffffffUL)
+		mapaddr = tioca_dma_d48(pdev, paddr);
+	else
+		mapaddr = 0;
+
+	/* Last resort ... use PCI portion of CA GART */
+
+	if (mapaddr == 0)
+		mapaddr = tioca_dma_mapped(pdev, paddr, byte_count);
+
+	return mapaddr;
+}
+
+/**
+ * tioca_error_intr_handler - SGI TIO CA error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioca_common struct for the given CA
+ * @pt: unused
+ *
+ * Handle a CA error interrupt.  Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */
+static irqreturn_t
+tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+{
+	struct tioca_common *soft = arg;
+	struct ia64_sal_retval ret_stuff;
+	uint64_t segment;
+	uint64_t busnum;
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	segment = 0;
+	busnum = soft->ca_common.bs_persist_busnum;
+
+	SAL_CALL_NOLOCK(ret_stuff,
+			(u64) SN_SAL_IOIF_ERROR_INTERRUPT,
+			segment, busnum, 0, 0, 0, 0, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus
+ * @prom_bussoft: Common prom/kernel struct representing the bus
+ *
+ * Replicates the tioca_common pointed to by @prom_bussoft in kernel
+ * space.  Allocates and initializes a kernel-only area for a given CA,
+ * and sets up an irq for handling CA error interrupts.
+ *
+ * On successful setup, returns the kernel version of tioca_common back to
+ * the caller.
+ */
+void *
+tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft)
+{
+	struct tioca_common *tioca_common;
+	struct tioca_kernel *tioca_kern;
+	struct pci_bus *bus;
+
+	/* sanity check prom rev */
+
+	if (sn_sal_rev_major() < 4 ||
+	    (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) {
+		printk
+		    (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "
+		     "for tioca support\n", __FUNCTION__);
+		return NULL;
+	}
+
+	/*
+	 * Allocate kernel bus soft and copy from prom.
+	 */
+
+	tioca_common = kcalloc(1, sizeof(struct tioca_common), GFP_KERNEL);
+	if (!tioca_common)
+		return NULL;
+
+	memcpy(tioca_common, prom_bussoft, sizeof(struct tioca_common));
+	tioca_common->ca_common.bs_base |= __IA64_UNCACHED_OFFSET;
+
+	/* init kernel-private area */
+
+	tioca_kern = kcalloc(1, sizeof(struct tioca_kernel), GFP_KERNEL);
+	if (!tioca_kern) {
+		kfree(tioca_common);
+		return NULL;
+	}
+
+	tioca_kern->ca_common = tioca_common;
+	spin_lock_init(&tioca_kern->ca_lock);
+	INIT_LIST_HEAD(&tioca_kern->ca_dmamaps);
+	tioca_kern->ca_closest_node =
+	    nasid_to_cnodeid(tioca_common->ca_closest_nasid);
+	tioca_common->ca_kernel_private = (uint64_t) tioca_kern;
+
+	bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum);
+	BUG_ON(!bus);
+	tioca_kern->ca_devices = &bus->devices;
+
+	/* init GART */
+
+	if (tioca_gart_init(tioca_kern) < 0) {
+		kfree(tioca_kern);
+		kfree(tioca_common);
+		return NULL;
+	}
+
+	tioca_gart_found++;
+	list_add(&tioca_kern->ca_list, &tioca_list);
+
+	if (request_irq(SGI_TIOCA_ERROR,
+			tioca_error_intr_handler,
+			SA_SHIRQ, "TIOCA error", (void *)tioca_common))
+		printk(KERN_WARNING
+		       "%s:  Unable to get irq %d.  "
+		       "Error interrupts won't be routed for TIOCA bus %d\n",
+		       __FUNCTION__, SGI_TIOCA_ERROR,
+		       (int)tioca_common->ca_common.bs_persist_busnum);
+
+	return tioca_common;
+}
+
+static struct sn_pcibus_provider tioca_pci_interfaces = {
+	.dma_map = tioca_dma_map,
+	.dma_map_consistent = tioca_dma_map,
+	.dma_unmap = tioca_dma_unmap,
+	.bus_fixup = tioca_bus_fixup,
+};
+
+/**
+ * tioca_init_provider - init SN PCI provider ops for TIO CA
+ */
+int
+tioca_init_provider(void)
+{
+	sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces;
+	return 0;
+}
diff --git a/arch/m32r/boot/compressed/Makefile b/arch/m32r/boot/compressed/Makefile
--- a/arch/m32r/boot/compressed/Makefile
+++ b/arch/m32r/boot/compressed/Makefile
@@ -30,7 +30,12 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bi
 
 CFLAGS_misc.o += -fpic
 
+ifdef CONFIG_MMU
 LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T
+else
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r -T
+endif
+
 OBJCOPYFLAGS += -R .empty_zero_page
 
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
diff --git a/arch/m32r/boot/compressed/head.S b/arch/m32r/boot/compressed/head.S
--- a/arch/m32r/boot/compressed/head.S
+++ b/arch/m32r/boot/compressed/head.S
@@ -138,6 +138,11 @@ startup:
 	ldi	r0, -1
 	ldi	r1, 0xd0	; invalidate i-cache, copy back d-cache
 	stb	r1, @r0
+#elif defined(CONFIG_CHIP_M32102)
+	/* Cache flush */
+	ldi	r0, -2
+	ldi	r1, 0x0100	; invalidate
+	stb	r1, @r0
 #else
 #error "put your cache flush function, please"
 #endif
diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c
--- a/arch/m32r/boot/compressed/m32r_sio.c
+++ b/arch/m32r/boot/compressed/m32r_sio.c
@@ -46,9 +46,14 @@ static void putc(char c)
 	}
 	*BOOT_SIO0TXB = c;
 }
-#else
+#else /* defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) */
+#ifdef CONFIG_MMU
 #define SIO0STS	(volatile unsigned short *)(0xa0efd000 + 14)
 #define SIO0TXB	(volatile unsigned short *)(0xa0efd000 + 30)
+#else
+#define SIO0STS	(volatile unsigned short *)(0x00efd000 + 14)
+#define SIO0TXB	(volatile unsigned short *)(0x00efd000 + 30)
+#endif
 
 static void putc(char c)
 {
diff --git a/arch/m32r/boot/setup.S b/arch/m32r/boot/setup.S
--- a/arch/m32r/boot/setup.S
+++ b/arch/m32r/boot/setup.S
@@ -75,6 +75,11 @@ ENTRY(boot)
 	ldi	r1, #0x73		; cache on (with invalidation)
 ;	ldi	r1, #0x00		; cache off
 	st	r1, @r0
+#elif defined(CONFIG_CHIP_M32102)
+	ldi	r0, #-4              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x101		; cache on (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	st	r1, @r0
 #else
 #error unknown chip configuration
 #endif
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
--- a/arch/m32r/kernel/entry.S
+++ b/arch/m32r/kernel/entry.S
@@ -69,16 +69,17 @@
 #include <asm/mmu_context.h>
 
 #if !defined(CONFIG_MMU)
-#define sys_madvise             sys_ni_syscall
-#define sys_readahead           sys_ni_syscall
-#define sys_mprotect            sys_ni_syscall
-#define sys_msync               sys_ni_syscall
-#define sys_mlock               sys_ni_syscall
-#define sys_munlock             sys_ni_syscall
-#define sys_mlockall            sys_ni_syscall
-#define sys_munlockall          sys_ni_syscall
-#define sys_mremap              sys_ni_syscall
-#define sys_mincore             sys_ni_syscall
+#define sys_madvise		sys_ni_syscall
+#define sys_readahead		sys_ni_syscall
+#define sys_mprotect		sys_ni_syscall
+#define sys_msync		sys_ni_syscall
+#define sys_mlock		sys_ni_syscall
+#define sys_munlock		sys_ni_syscall
+#define sys_mlockall		sys_ni_syscall
+#define sys_munlockall		sys_ni_syscall
+#define sys_mremap		sys_ni_syscall
+#define sys_mincore		sys_ni_syscall
+#define sys_remap_file_pages	sys_ni_syscall
 #endif /* CONFIG_MMU */
 
 #define R4(reg)			@reg
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
--- a/arch/m32r/kernel/m32r_ksyms.c
+++ b/arch/m32r/kernel/m32r_ksyms.c
@@ -76,7 +76,6 @@ EXPORT_SYMBOL(smp_call_function);
 
 /* TLB flushing */
 EXPORT_SYMBOL(smp_flush_tlb_page);
-EXPORT_SYMBOL_GPL(smp_flush_tlb_all);
 #endif
 
 /* compiler generated symbol */
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c
--- a/arch/m32r/kernel/module.c
+++ b/arch/m32r/kernel/module.c
@@ -14,6 +14,8 @@
     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/moduleloader.h>
 #include <linux/elf.h>
 #include <linux/vmalloc.h>
@@ -31,7 +33,11 @@ void *module_alloc(unsigned long size)
 {
 	if (size == 0)
 		return NULL;
+#ifdef CONFIG_MMU
 	return vmalloc_exec(size);
+#else
+	return vmalloc(size);
+#endif
 }
 
 
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -24,6 +24,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/string.h>
+#include <linux/signal.h>
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
@@ -665,7 +666,7 @@ do_ptrace(long request, struct task_stru
 	case PTRACE_SYSCALL:
 	case PTRACE_CONT:
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -700,7 +701,7 @@ do_ptrace(long request, struct task_stru
 		unsigned long pc, insn;
 
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		if ((child->ptrace & PT_DTRACE) == 0) {
diff --git a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c
--- a/arch/m32r/kernel/semaphore.c
+++ b/arch/m32r/kernel/semaphore.c
@@ -19,7 +19,7 @@
  *	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>
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 #include <linux/config.h>
 #include <linux/sched.h>
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
--- a/arch/m32r/kernel/setup.c
+++ b/arch/m32r/kernel/setup.c
@@ -7,8 +7,6 @@
  *                            Hitoshi Yamamoto
  */
 
-/* $Id$ */
-
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/stddef.h>
@@ -24,6 +22,9 @@
 #include <linux/seq_file.h>
 #include <linux/timex.h>
 #include <linux/tty.h>
+#include <linux/cpu.h>
+#include <linux/nodemask.h>
+
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -52,7 +53,7 @@ struct cpuinfo_m32r boot_cpu_data;
 #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 */
-extern int rd_image_start;  /* starting block # of image */
+extern int rd_image_start;	/* starting block # of image */
 #endif
 
 #if defined(CONFIG_VGA_CONSOLE)
@@ -273,6 +274,21 @@ void __init setup_arch(char **cmdline_p)
 	paging_init();
 }
 
+static struct cpu cpu[NR_CPUS];
+
+static int __init topology_init(void)
+{
+	int cpu_id;
+
+	for (cpu_id = 0; cpu_id < NR_CPUS; cpu_id++)
+		if (cpu_possible(cpu_id))
+			register_cpu(&cpu[cpu_id], cpu_id, NULL);
+
+	return 0;
+}
+
+subsys_initcall(topology_init);
+
 #ifdef CONFIG_PROC_FS
 /*
  *	Get CPU information for use by the procfs.
@@ -285,7 +301,7 @@ static int show_cpuinfo(struct seq_file 
 #ifdef CONFIG_SMP
 	if (!cpu_online(cpu))
 		return 0;
-#endif  /* CONFIG_SMP */
+#endif	/* CONFIG_SMP */
 
 	seq_printf(m, "processor\t: %ld\n", cpu);
 
@@ -359,7 +375,7 @@ struct seq_operations cpuinfo_op = {
 	stop:	c_stop,
 	show:	show_cpuinfo,
 };
-#endif  /* CONFIG_PROC_FS */
+#endif	/* CONFIG_PROC_FS */
 
 unsigned long cpu_initialized __initdata = 0;
 
@@ -399,7 +415,6 @@ void __init cpu_init (void)
 #endif
 
 	/* Set up ICUIMASK */
-	outl(0x00070000, M32R_ICU_IMASK_PORTL);   /* imask=111 */
+	outl(0x00070000, M32R_ICU_IMASK_PORTL);		/* imask=111 */
 }
-#endif  /* defined(CONFIG_CHIP_VDEC2) ... */
-
+#endif	/* defined(CONFIG_CHIP_VDEC2) ... */
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -147,7 +147,7 @@ sys_rt_sigreturn(unsigned long r0, unsig
 	stack_t st;
 	int result;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -81,9 +81,6 @@ static cpumask_t cpu_callin_map;
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned;
 
-/* Set when the idlers are all forked */
-int smp_threads_ready;
-
 static int cpucount;
 static cpumask_t smp_commenced_mask;
 
@@ -106,8 +103,6 @@ spinlock_t ipi_lock[NR_IPIS];
 
 static unsigned int calibration_result;
 
-unsigned long cache_decay_ticks = HZ / 100;
-
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 /* Function Prototypes                                                       */
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
--- a/arch/m32r/kernel/sys_m32r.c
+++ b/arch/m32r/kernel/sys_m32r.c
@@ -171,9 +171,9 @@ asmlinkage int sys_ipc(uint call, int fi
 	case SHMAT: {
 		ulong raddr;
 
-		if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third,
-				      sizeof(ulong))))
-			return ret;
+		if (!access_ok(VERIFY_WRITE, (ulong __user *) third,
+				      sizeof(ulong)))
+			return -EFAULT;
 		ret = do_shmat (first, (char __user *) ptr, second, &raddr);
 		if (ret)
 			return ret;
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -95,8 +95,10 @@ void	set_eit_vector_entries(void)
 	eit_vector[31] = 0xff000000UL;
 	eit_vector[32] = BRA_INSN(ei_handler, 32);
 	eit_vector[64] = BRA_INSN(pie_handler, 64);
+#ifdef CONFIG_MMU
 	eit_vector[68] = BRA_INSN(ace_handler, 68);
 	eit_vector[72] = BRA_INSN(tme_handler, 72);
+#endif /* CONFIG_MMU */
 #ifdef CONFIG_SMP
 	eit_vector[184] = (unsigned long)smp_reschedule_interrupt;
 	eit_vector[185] = (unsigned long)smp_invalidate_interrupt;
diff --git a/arch/m32r/mm/cache.c b/arch/m32r/mm/cache.c
--- a/arch/m32r/mm/cache.c
+++ b/arch/m32r/mm/cache.c
@@ -4,8 +4,6 @@
  *  Copyright (C) 2002  Hirokazu Takata
  */
 
-/* $Id$ */
-
 #include <linux/config.h>
 #include <asm/pgtable.h>
 
@@ -25,8 +23,8 @@
 #define MCCR_DCACHE_CBINV	(MCCR_CC|MCCR_DIV|MCCR_DCB)
 #define CHECK_MCCR(mccr)	(mccr = *MCCR)
 #elif defined(CONFIG_CHIP_M32102)
-#define MCCR		((volatile unsigned long*)0xfffffffc)
-#define MCCR_IIV	(1UL << 8)	/* I-cache invalidate */
+#define MCCR		((volatile unsigned char*)0xfffffffe)
+#define MCCR_IIV	(1UL << 0)	/* I-cache invalidate */
 #define MCCR_ICACHE_INV		MCCR_IIV
 #endif /* CONFIG_CHIP_XNUX2 || CONFIG_CHIP_M32700 */
 
@@ -65,4 +63,3 @@ void _flush_cache_copyback_all(void)
 
 #endif
 }
-
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
--- a/arch/m32r/mm/discontig.c
+++ b/arch/m32r/mm/discontig.c
@@ -11,6 +11,7 @@
 #include <linux/bootmem.h>
 #include <linux/mmzone.h>
 #include <linux/initrd.h>
+#include <linux/nodemask.h>
 
 #include <asm/setup.h>
 
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
--- a/arch/m32r/mm/fault-nommu.c
+++ b/arch/m32r/mm/fault-nommu.c
@@ -23,6 +23,7 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/vt_kern.h>              /* For unblank_screen() */
 
 #include <asm/m32r.h>
 #include <asm/system.h>
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
--- a/arch/m32r/mm/init.c
+++ b/arch/m32r/mm/init.c
@@ -121,8 +121,6 @@ unsigned long __init zone_sizes_init(voi
 
 	free_area_init_node(0, NODE_DATA(0), zones_size, start_pfn, 0);
 
-	mem_map = contig_page_data.node_mem_map;
-
 	return 0;
 }
 #else	/* CONFIG_DISCONTIGMEM */
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -34,6 +34,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/wait.h>
 
 #include <asm/atari_stdma.h>
 #include <asm/atariints.h>
@@ -81,11 +82,10 @@ void stdma_lock(irqreturn_t (*handler)(i
 
 	local_irq_save(flags);		/* protect lock */
 
-	while(stdma_locked)
-		/* Since the DMA is used for file system purposes, we
-		 have to sleep uninterruptible (there may be locked
-		 buffers) */
-		sleep_on(&stdma_wait);
+	/* Since the DMA is used for file system purposes, we
+	 have to sleep uninterruptible (there may be locked
+	 buffers) */
+	wait_event(stdma_wait, !stdma_locked);
 
 	stdma_locked   = 1;
 	stdma_isr      = handler;
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -635,7 +635,7 @@ static inline void unswap_pte(struct vm_
 	set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	swap_free(entry);
 	get_page(page);
-	++vma->vm_mm->rss;
+	inc_mm_counter(vma->vm_mm, rss);
 }
 
 static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir,
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:22:54 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:23 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -104,6 +108,7 @@ CONFIG_ZORRO_NAMES=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -116,9 +121,10 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 CONFIG_PARPORT=m
 # CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_AMIGA=m
 CONFIG_PARPORT_MFC3=m
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 CONFIG_PARPORT_1284=y
 
 #
@@ -131,8 +137,8 @@ CONFIG_PARPORT_1284=y
 #
 CONFIG_AMIGA_FLOPPY=y
 CONFIG_AMIGA_Z2RAM=y
-# CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -152,6 +158,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -212,22 +219,17 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA 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_GENERIC_NCR5380_MMIO is not set
 # CONFIG_SCSI_PPA is not set
@@ -238,7 +240,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_A3000_SCSI=y
 CONFIG_A2091_SCSI=y
@@ -273,6 +274,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -296,7 +299,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -394,11 +396,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -470,7 +470,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # ARCnet devices
@@ -488,7 +487,6 @@ CONFIG_HYDRA=m
 CONFIG_ZORRO8390=m
 CONFIG_APNE=m
 # 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_AT1700 is not set
@@ -564,17 +562,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -593,21 +580,42 @@ CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_AMIGA=y
 # CONFIG_MOUSE_VSXXXAA is not set
 CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
 # CONFIG_JOYSTICK_IFORCE is not set
 # CONFIG_JOYSTICK_WARRIOR is not set
 # CONFIG_JOYSTICK_MAGELLAN is not set
 # CONFIG_JOYSTICK_SPACEORB is not set
 # CONFIG_JOYSTICK_SPACEBALL is not set
 # CONFIG_JOYSTICK_STINGER is not set
-# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
 # CONFIG_JOYSTICK_DB9 is not set
 # CONFIG_JOYSTICK_GAMECON is not set
 # CONFIG_JOYSTICK_TURBOGRAFX is not set
 CONFIG_JOYSTICK_AMIGA=m
+# CONFIG_JOYSTICK_JOYDUMP is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -653,6 +661,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -680,6 +692,11 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 CONFIG_FB_CIRRUS=m
@@ -688,6 +705,7 @@ CONFIG_FB_AMIGA_OCS=y
 CONFIG_FB_AMIGA_ECS=y
 CONFIG_FB_AMIGA_AGA=y
 CONFIG_FB_FM2=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -707,6 +725,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -722,10 +741,6 @@ CONFIG_DMASOUND=m
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -736,6 +751,11 @@ CONFIG_DMASOUND=m
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_AMIGA_BUILTIN_SERIAL=y
@@ -758,10 +778,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -916,13 +942,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -941,7 +973,8 @@ CONFIG_CRYPTO_MD5=m
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -959,6 +992,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:22:58 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:27 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -99,6 +103,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -118,6 +123,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -137,6 +143,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -171,6 +178,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -196,6 +204,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -219,7 +229,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -320,11 +329,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -396,7 +403,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -469,16 +475,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -496,6 +492,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -536,6 +541,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -581,10 +590,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -595,6 +600,11 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_DN_SERIAL=y
@@ -615,10 +625,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -773,13 +789,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -798,7 +820,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -816,6 +839,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:11 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:32 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -100,6 +104,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -112,8 +117,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 CONFIG_PARPORT=m
 # CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_ATARI=m
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 CONFIG_PARPORT_1284=y
 
 #
@@ -125,6 +131,7 @@ CONFIG_PARPORT_1284=y
 #
 CONFIG_ATARI_FLOPPY=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -144,6 +151,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -201,6 +209,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -228,6 +237,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -251,7 +262,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -349,11 +359,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -425,7 +433,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -499,17 +506,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -529,6 +525,16 @@ CONFIG_INPUT_M68K_BEEP=m
 CONFIG_INPUT_UINPUT=m
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -574,6 +580,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -601,9 +611,15 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -619,6 +635,7 @@ CONFIG_FONT_8x16=y
 # Logo configuration
 #
 # CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -634,10 +651,6 @@ CONFIG_DMASOUND=m
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -648,6 +661,11 @@ CONFIG_DMASOUND=m
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_ATARI_MFPSER=m
@@ -672,9 +690,15 @@ CONFIG_REISERFS_PROC_INFO=y
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -828,13 +852,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -853,7 +883,8 @@ CONFIG_CRYPTO_MD5=m
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -871,6 +902,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:15 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:37 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -99,6 +103,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -118,6 +123,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -137,6 +143,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -171,6 +178,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -196,6 +204,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -219,7 +229,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -320,11 +329,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -395,7 +402,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -468,16 +474,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -495,6 +491,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -535,6 +540,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -580,10 +589,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -594,6 +599,11 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_BVME6000_SCC=y
@@ -614,10 +624,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -772,13 +788,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -797,7 +819,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -815,6 +838,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:40 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:41 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -100,6 +104,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -119,6 +124,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -138,6 +144,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -172,6 +179,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -197,6 +205,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -220,7 +230,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -321,11 +330,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -397,7 +404,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -470,16 +476,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -497,6 +493,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -537,6 +542,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -582,10 +591,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -596,6 +601,11 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 
@@ -614,10 +624,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -772,13 +788,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -797,7 +819,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -815,6 +838,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:44 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:45 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -101,6 +105,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -120,6 +125,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -139,6 +145,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -196,6 +203,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -223,6 +231,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -258,7 +268,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -356,11 +365,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -435,7 +442,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -512,16 +518,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -539,6 +535,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -579,6 +584,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -606,10 +615,16 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+CONFIG_FB_MACMODES=y
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 CONFIG_FB_VALKYRIE=y
 CONFIG_FB_MAC=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -630,6 +645,7 @@ CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_LOGO_MAC_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -643,10 +659,6 @@ CONFIG_LOGO_MAC_CLUT224=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -657,6 +669,11 @@ CONFIG_LOGO_MAC_CLUT224=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_MAC_SCC=y
@@ -679,10 +696,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -846,18 +869,24 @@ CONFIG_NLS_ISO8859_14=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=m
+CONFIG_NLS_UTF8=y
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -876,7 +905,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -894,6 +924,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:49 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:50 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -99,6 +103,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -118,6 +123,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -137,6 +143,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -171,6 +178,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -197,6 +205,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -220,7 +230,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -321,11 +330,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -397,7 +404,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -470,16 +476,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -497,6 +493,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -537,6 +542,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -564,8 +573,14 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -584,6 +599,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -597,10 +613,6 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -611,6 +623,11 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_MVME147_SCC=y
@@ -631,10 +648,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -791,13 +814,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -816,7 +845,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -834,6 +864,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:53 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:53 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -99,6 +103,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -118,6 +123,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -137,6 +143,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -171,6 +178,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -196,6 +204,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -219,7 +229,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -320,11 +329,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -396,7 +403,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -469,16 +475,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -496,6 +492,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -536,6 +541,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -563,8 +572,14 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -583,6 +598,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -596,10 +612,6 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -610,6 +622,11 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_MVME162_SCC=y
@@ -630,10 +647,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -790,13 +813,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -815,7 +844,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -833,6 +863,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:57 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:58 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -101,6 +105,7 @@ CONFIG_GENERIC_ISA_DMA=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -122,7 +127,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -142,6 +147,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -200,22 +206,17 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA 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_GENERIC_NCR5380_MMIO is not set
 # CONFIG_SCSI_NCR53C406A is not set
@@ -224,7 +225,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -250,6 +250,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -273,7 +275,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -374,11 +375,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -450,7 +449,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # ARCnet devices
@@ -463,7 +461,6 @@ CONFIG_EQUALIZER=m
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # 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_AT1700 is not set
@@ -539,17 +536,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_Q40KBD=m
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -570,6 +556,16 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_Q40KBD=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -610,6 +606,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -637,9 +637,15 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 CONFIG_FB_Q40=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -658,6 +664,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -673,10 +680,6 @@ CONFIG_DMASOUND=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -687,6 +690,11 @@ CONFIG_DMASOUND=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 
@@ -705,10 +713,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -863,13 +877,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -888,7 +908,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -906,6 +927,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:24:01 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:35:02 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -87,6 +91,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -106,6 +111,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -125,6 +131,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -159,13 +166,13 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_DEBUG is not set
-CONFIG_SUN3_SCSI=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -185,6 +192,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -208,7 +217,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -309,11 +317,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -385,7 +391,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -459,16 +464,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -486,6 +481,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -526,6 +530,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -553,8 +561,14 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -573,6 +587,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -586,10 +601,6 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -600,6 +611,11 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 
@@ -618,10 +634,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -730,6 +752,7 @@ CONFIG_CODA_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
+CONFIG_SUN_PARTITION=y
 
 #
 # Native Language Support
@@ -778,13 +801,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -803,7 +832,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -821,6 +851,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:24:05 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:35:06 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,23 +28,25 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -98,6 +102,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -117,6 +122,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Block devices
 #
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -136,6 +142,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -170,6 +177,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -196,6 +204,8 @@ CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -219,7 +229,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -320,11 +329,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 
 #
-# IPv6: Netfilter Configuration
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -396,7 +403,6 @@ CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 CONFIG_EQUALIZER=m
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -469,16 +475,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -496,6 +492,15 @@ CONFIG_MOUSE_SERIAL=m
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -536,6 +541,10 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -563,8 +572,14 @@ CONFIG_GEN_RTC_X=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -583,6 +598,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -596,10 +612,6 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -610,6 +622,11 @@ CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 
@@ -628,10 +645,16 @@ CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_FS_XATTR is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -740,6 +763,7 @@ CONFIG_CODA_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
+CONFIG_SUN_PARTITION=y
 
 #
 # Native Language Support
@@ -788,13 +812,19 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
@@ -813,7 +843,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -831,6 +862,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-m68k
-# Sun Dec 26 11:23:36 2004
+# Linux kernel version: 2.6.12-rc6-m68k
+# Tue Jun  7 20:34:17 2005
 #
 CONFIG_M68K=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -14,6 +15,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -25,22 +27,24 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -92,6 +96,7 @@ CONFIG_PROC_HARDWARE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -112,6 +117,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 CONFIG_AMIGA_FLOPPY=y
 # CONFIG_AMIGA_Z2RAM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -130,6 +136,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -164,6 +171,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -207,7 +215,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -324,16 +331,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -353,6 +350,15 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -393,6 +399,10 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -420,6 +430,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_CIRRUS is not set
@@ -428,6 +443,7 @@ CONFIG_FB_AMIGA_OCS=y
 CONFIG_FB_AMIGA_ECS=y
 CONFIG_FB_AMIGA_AGA=y
 # CONFIG_FB_FM2 is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -440,6 +456,7 @@ CONFIG_DUMMY_CONSOLE=y
 # Logo configuration
 #
 # CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -453,10 +470,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -467,6 +480,11 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # Character devices
 #
 CONFIG_AMIGA_BUILTIN_SERIAL=y
@@ -483,6 +501,10 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
@@ -544,7 +566,6 @@ CONFIG_NFS_FS=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -608,7 +629,10 @@ CONFIG_NLS_CODEPAGE_437=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 
 #
 # Security options
@@ -622,6 +646,10 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/config.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -251,7 +252,7 @@ asmlinkage int sys_ptrace(long request, 
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			if (request == PTRACE_SYSCALL) {
 					child->thread.work.syscall_trace = ~0;
@@ -292,7 +293,7 @@ asmlinkage int sys_ptrace(long request, 
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			child->thread.work.syscall_trace = 0;
 			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -130,7 +130,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -142,7 +142,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -510,7 +510,7 @@ asmlinkage int do_sigreturn(unsigned lon
 	sigset_t set;
 	int d0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 	    (_NSIG_WORDS > 1 &&
@@ -540,7 +540,7 @@ asmlinkage int do_rt_sigreturn(unsigned 
 	sigset_t set;
 	int d0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
@@ -951,6 +951,21 @@ handle_restart(struct pt_regs *regs, str
 	}
 }
 
+void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
+{
+	if (regs->orig_d0 < 0)
+		return;
+	switch (regs->d0) {
+	case -ERESTARTNOHAND:
+	case -ERESTARTSYS:
+	case -ERESTARTNOINTR:
+		regs->d0 = regs->orig_d0;
+		regs->orig_d0 = -1;
+		regs->pc -= 2;
+		break;
+	}
+}
+
 /*
  * OK, we're invoking a handler
  */
@@ -982,133 +997,22 @@ handle_signal(int sig, struct k_sigactio
  * 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.
- *
- * Note that we go through the signals twice: once to check the signals
- * that the kernel can handle, and then we build all the user-level signal
- * handling stack-frames in one go after that.
  */
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	struct k_sigaction ka;
+	int signr;
 
 	current->thread.esp0 = (unsigned long) regs;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		int signr;
-
-		signr = dequeue_signal(current, &current->blocked, &info);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			regs->sr &= ~PS_T;
-
-			/* Did we come from a system call? */
-			if (regs->orig_d0 >= 0) {
-				/* Restart the system call the same way as
-				   if the process were not traced.  */
-				struct k_sigaction *ka =
-					&current->sighand->action[signr-1];
-				int has_handler =
-					(ka->sa.sa_handler != SIG_IGN &&
-					 ka->sa.sa_handler != SIG_DFL);
-				handle_restart(regs, ka, has_handler);
-			}
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code)) {
-			discard_frame:
-			    /* Make sure that a faulted bus cycle isn't
-			       restarted (only needed on the 680[23]0).  */
-			    if (regs->format == 10 || regs->format == 11)
-				regs->stkadj = frame_extra_sizes[regs->format];
-			    continue;
-			}
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				goto discard_frame;
-
-			/* 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->parent->pid;
-				info.si_uid = current->parent->uid;
-				info.si_uid16 = high2lowuid(current->parent->uid);
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sighand->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;
-
-			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(process_group(current)))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP: {
-				struct sighand_struct *sighand;
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				sighand = current->parent->sighand;
-				if (sighand && !(sighand->action[SIGCHLD-1].sa.sa_flags
-					     & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-			}
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGIOT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, exit_code, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				do_group_exit(signr);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &ka, &info, oldset, regs);
 		return 1;
 	}
 
@@ -1117,18 +1021,5 @@ asmlinkage int do_signal(sigset_t *oldse
 		/* Restart the system call - no handlers present */
 		handle_restart(regs, NULL, 0);
 
-	/* If we are about to discard some frame stuff we must copy
-	   over the remaining frame. */
-	if (regs->stkadj) {
-		struct pt_regs *tregs =
-		  (struct pt_regs *) ((ulong) regs + regs->stkadj);
-
-		/* This must be copied with decreasing addresses to
-		   handle overlaps.  */
-		tregs->vector = 0;
-		tregs->format = 0;
-		tregs->pc = regs->pc;
-		tregs->sr = regs->sr;
-	}
 	return 0;
 }
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -534,6 +534,11 @@ endchoice
 
 endmenu
 
+config ISA_DMA_API
+	bool
+	depends on !M5272
+	default y
+
 menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
 
 config PCI
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -43,7 +43,6 @@ BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)	:= ram
 model-$(CONFIG_ROMKERNEL)	:= rom
-model-$(CONFIG_HIMEMKERNEL)	:= himem
 MODEL := $(model-y)
 
 #
@@ -58,12 +57,15 @@ cpuclass-$(CONFIG_M5249)	:= 5307
 cpuclass-$(CONFIG_M527x)	:= 5307
 cpuclass-$(CONFIG_M5272)	:= 5307
 cpuclass-$(CONFIG_M528x)	:= 5307
+cpuclass-$(CONFIG_M5307)	:= 5307
 cpuclass-$(CONFIG_M5407)	:= 5307
+cpuclass-$(CONFIG_M68328)	:= 68328
 cpuclass-$(CONFIG_M68EZ328)	:= 68328
 cpuclass-$(CONFIG_M68VZ328)	:= 68328
+cpuclass-$(CONFIG_M68360)	:= 68360
 CPUCLASS := $(cpuclass-y)
 
-ifneq ($(CPUCLASS),)
+ifneq ($(CPUCLASS),$(PLATFORM))
 CLASSDIR := arch/m68knommu/platform/$(cpuclass-y)/
 endif
 
@@ -93,7 +95,7 @@ CFLAGS += -O1 -g
 CFLAGS += -D__linux__
 CFLAGS += -DUTS_SYSNAME=\"uClinux\"
 
-head-y := arch/m68knommu/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o
+head-y := arch/m68knommu/platform/$(cpuclass-y)/head.o
 
 CLEAN_FILES := include/asm-$(ARCH)/asm-offsets.h \
 	       arch/$(ARCH)/kernel/asm-offsets.s
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -15,6 +15,7 @@
 #include <linux/hardirq.h>
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
+#include <asm/thread_info.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -63,10 +64,13 @@ int main(void)
 	DEFINE(PT_A2, offsetof(struct pt_regs, a2));
 	DEFINE(PT_PC, offsetof(struct pt_regs, pc));
 	DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+
+#ifdef CONFIG_COLDFIRE
+	/* bitfields are a bit difficult */
+	DEFINE(PT_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
+#else
 	/* bitfields are a bit difficult */
 	DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
-
-#ifndef CONFIG_COLDFIRE
 	/* offsets into the irq_handler struct */
 	DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
 	DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
@@ -85,5 +89,13 @@ int main(void)
 	DEFINE(PT_PTRACED, PT_PTRACED);
 	DEFINE(PT_DTRACE, PT_DTRACE);
 
+	DEFINE(THREAD_SIZE, THREAD_SIZE);
+
+	/* Offsets in thread_info structure */
+	DEFINE(TI_TASK, offsetof(struct thread_info, task));
+	DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
+	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+
 	return 0;
 }
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S
--- a/arch/m68knommu/kernel/entry.S
+++ b/arch/m68knommu/kernel/entry.S
@@ -47,7 +47,7 @@
 ENTRY(buserr)
 	SAVE_ALL
 	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)
+	movel	%d0,%sp@(PT_ORIG_D0)
 	movel	%sp,%sp@- 		/* stack frame pointer argument */
 	jsr	buserr_c
 	addql	#4,%sp
@@ -56,7 +56,7 @@ ENTRY(buserr)
 ENTRY(trap)
 	SAVE_ALL
 	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)
+	movel	%d0,%sp@(PT_ORIG_D0)
 	movel	%sp,%sp@- 		/* stack frame pointer argument */
 	jsr	trap_c
 	addql	#4,%sp
@@ -68,7 +68,7 @@ ENTRY(trap)
 ENTRY(dbginterrupt)
 	SAVE_ALL
 	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)
+	movel	%d0,%sp@(PT_ORIG_D0)
 	movel	%sp,%sp@- 		/* stack frame pointer argument */
 	jsr	dbginterrupt_c
 	addql	#4,%sp
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void);
  */
 void default_idle(void)
 {
-	while(1) {
-		if (need_resched())
-			__asm__("stop #0x2000" : : : "cc");
-		schedule();
+	local_irq_disable();
+ 	while (!need_resched()) {
+		/* This stop will re-enable interrupts */
+ 		__asm__("stop #0x2000" : : : "cc");
+		local_irq_disable();
 	}
+	local_irq_enable();
 }
 
 void (*idle)(void) = default_idle;
@@ -63,7 +65,12 @@ void (*idle)(void) = default_idle;
 void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
-	idle();
+	while (1) {
+		idle();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
 }
 
 void machine_restart(char * __unused)
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/config.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -240,7 +241,7 @@ asmlinkage int sys_ptrace(long request, 
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			if (request == PTRACE_SYSCALL)
 				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -278,7 +279,7 @@ asmlinkage int sys_ptrace(long request, 
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
+			if (!valid_signal(data))
 				break;
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -116,7 +116,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -360,7 +360,7 @@ asmlinkage int do_sigreturn(unsigned lon
 	sigset_t set;
 	int d0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 	    (_NSIG_WORDS > 1 &&
@@ -392,7 +392,7 @@ asmlinkage int do_rt_sigreturn(unsigned 
 	sigset_t set;
 	int d0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S
+++ /dev/null
@@ -1,213 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5206 ColdFire Arnewsh board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Arnewsh m5206 ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*
- *	The following define the limits within which to search for
- *	available RAM.
- */
-#define	MEM_MIN		0x00100000	/* Search from 1Mb */
-#define	MEM_MAX		0x02000000	/* Max DRAM 32Mb! */
-#define	MEM_LUMP	0x00010000	/* 64 Kb chunks */
-
-#define MEM_TMPSTACK	0x00010000	/* At 64k - for exceptions */
-
-/*
- *	Chip Select setup.
- */
-#define	CS0_ADDR	0x0000f000	/* CS0 connected to Flash ROM */
-#define	CS0_MASK	0xf0000000	/*   is 1Mbyte */
-#define	CS0_CTRL	0x00000000	/*   read-only */
-#define	CS1_ADDR	0x00000000	/* CS1 not connected */
-#define	CS1_MASK	0x00000000
-#define	CS1_CTRL	0x00000000
-#define	CS2_ADDR	0x00003000	/* CS2 connected to SRAM */
-#define	CS2_MASK	0x0000f000	/*   is 1Mbyte */
-#define	CS2_CTRL	0x00001903	/*   read-write */
-#define	CS3_ADDR	0x00004000	/* CS3 connected to LED, par port */
-#define	CS3_MASK	0x0000f000	/*   is 1Mbyte */
-#define	CS3_CTRL	0x00000083	/*   read-write */
-#define	CS4_ADDR	0x00000000	/* CS4 not connected */
-#define	CS4_MASK	0x00000000
-#define	CS4_CTRL	0x00000123
-#define	CS5_ADDR	0x00000000	/* CS5 not connected */
-#define	CS5_MASK	0x00000000
-#define	CS5_CTRL	0x00000000
-#define	CS6_ADDR	0x00000000	/* CS6 not connected */
-#define	CS6_MASK	0x00000000
-#define	CS6_CTRL	0x00000000
-#define	CS7_ADDR	0x00000000	/* CS7 not connected */
-#define	CS7_MASK	0x00000000
-#define	CS7_CTRL	0x00000000
-#define	DMC_CTRL	0x00000000	/* default memory control */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 *
-	 *	On the Arnewsh 5206 board we can probe for the amount
-	 *	of DRAM present...
-	 */
-	move.l	#MEM_MIN, %a0			/* Start at bottom */
-	move.l	#MEM_MAX, %a1			/* Set stop point */
-	lea.l	MEM_TMPSTACK, %sp		/* Set up tmp stack ptr */
-
-	move.l	#VBR_BASE+8, %a2		/* Address of bus trap */
-	lea.l	_ram_buserr, %a3		/* Get RAM trap address */
-	move.l	%a3, (%a2)			/* Set trap to local ptr */
-
-_find_ram:
-	move.l	(%a0), %d0			/* Attempt read */
-	add.l	#MEM_LUMP, %a0			/* Try next bank */
-	cmp.l	%a1, %a0			/* Check more? */
-	bne	_find_ram
-
-	/*
-	 *	BUS error trap handler - used for RAM probing.
-	 */
-_ram_buserr:
-	bra	_found_ram
-
-_found_ram:					/* Vectored here on bus err */
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current task pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile
--- a/arch/m68knommu/platform/5206/Makefile
+++ b/arch/m68knommu/platform/5206/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S
+++ /dev/null
@@ -1,178 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5206e ColdFire based CADRE3 boards.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Cadre-III M5206e ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	SDRAM size for the Cadre III board (m5206e).
-	 */
-#if defined(CONFIG_RAMAUTO)
-	movea.l	#0x00000000,%a0
-	move.l	MCF_MBAR+MCFSIM_DCMR0,%d0
-	and.l	#0x00fe0000, %d0
-	beq	noaddr1
-	add.l	#0x00020000,%d0
-	move.l	%d0,%a0
-noaddr1:
-	move.l	MCF_MBAR+MCFSIM_DCMR1,%d0
-	and.l	#0x00fe0000, %d0
-	beq	noaddr2
-	add.l	#0x00020000,%d0
-	add.l	%d0,%a0
-noaddr2:
-
-#else
-
-#if defined(CONFIG_RAM32MB)
-#define MEM_SIZE	0x02000000	/* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-	move.l	#MEM_SIZE, %a0
-#endif
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current task pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile
--- a/arch/m68knommu/platform/5206e/Makefile
+++ b/arch/m68knommu/platform/5206e/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S b/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S
+++ /dev/null
@@ -1,346 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5206e ColdFire based eLITE boards.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	Copyright (C) 1999 Rob Scott (rscott@mtrob.fdns.net)
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	M5206eLITE ColdFire eval board, chip select and memory setup.
- */
-
-#ifdef CONFIG_SMALL
-#define	MEM_BASE	0x30000000      /* Base memory for M5206eLITE */
-#define	MEM_RESERVED	0x00020000      /* Don't use memory reserved by dBUG */
-#define	MEM_SIZE	0x00100000      /* 1 MB of SRAM on M5206eLITE */
-#else
-#define	MEM_BASE	0x00000000      /* Base memory for M5206eLITE */
-#define	MEM_RESERVED	0x00010000      /* Skip first MEM_LUMP for colilo */
-#define	MEM_SIZE	0x02000000      /* Max DRAM 32Mb */
-#endif
-#define	MEM_MIN		MEM_BASE+MEM_RESERVED
-/* Define end of probeable memory space */
-#define	MEM_MAX		MEM_BASE+MEM_SIZE
-#define	MEM_BUILTIN	0x20000000      /* Put built in SRAM at dBUG loc */
-#define	MEM_TMPSTACK	MEM_BUILTIN+0x800 /* Use built in SRAM for tmp stack */
-#define	MEM_LUMP	0x00010000	/* 64 Kb chunks */
-#define	VBR_BASE	MEM_BUILTIN     /* Use built in SRAM for vectors */
-
-#define	CS0_ADDR	0x0000ffe0	/* CS0 connected to Flash ROM */
-#define	CS0_MASK	0x000f0000	/*   is 1Mbyte */
-#define	CS0_CTRL	0x00001da3	/*   read-write (for flash) */
-#define	CS1_ADDR	0x00000000	/* CS1 not connected */
-#define	CS1_MASK	0x00000000
-#define	CS1_CTRL	0x00000000
-#define	CS2_ADDR	0x00003000	/* CS2 connected to SRAM */
-#define	CS2_MASK	0x000f0000	/*   is 1Mbyte */
-#define	CS2_CTRL	0x00001903	/*   read-write */
-#define	CS3_ADDR	0x00004000	/* CS3 connected to LED, par port */
-#define	CS3_MASK	0x000f0000	/*   is 1Mbyte */
-#define	CS3_CTRL	0x00000183	/*   read-write */
-#define	CS4_ADDR	0x00000000	/* CS4 not connected */
-#define	CS4_MASK	0x00000000
-#define	CS4_CTRL	0x00000000
-#define	CS5_ADDR	0x00000000	/* CS5 not connected */
-#define	CS5_MASK	0x00000000
-#define	CS5_CTRL	0x00000000
-#define	CS6_ADDR	0x00000000	/* CS6 not connected */
-#define	CS6_MASK	0x00000000
-#define	CS6_CTRL	0x00000000
-#define	CS7_ADDR	0x00000000	/* CS7 not connected */
-#define	CS7_MASK	0x00000000
-#define	CS7_CTRL	0x00000000
-#define	DMC_CTRL	0x00000000	/* default memory control */
-
-#define	DCRR		0x00000034	/* Refresh period  */
-/* DCTR definition:
-     <15>: DAEM, 1 = Drive Multiplexed Address During External Master DRAM xfer
-     <14>: EDO,  1 = EDO, 0 = Normal
-     <12>: RCD,  1 = 2 clk RAS-to-CAS, 0 = 1.0 clk RAS-to-CAS
-  <10:09>: RSH,  10 = 3.5 clk RAS low, 01 = 2.5 clk, 00 = 1.5 clk
-  <06:05>: RP,   10 = 3.5 clk RAS Precharge, 01 = 2.5 clk, 00 = 1.5 clk
-     <03>: CAS,  1 = 2.5 clk CAS assertion, 0 = 1.5 clk
-     <01>: CP,   1 = 1.5 CAS clk precharge, 0 = .5 clk
-     <00>: CSR,  1 = 2.0 clk CAS before RAS setup, 0 = 1.0 clk
-*/
-#define	DCTR		0x0000144B	/* Slow DRAM */
-#define	DCAR0		0x00000000	/* DRAM0 address, 0 base addr */
-#define	DCMR0		0x003e0000	/* DRAM0 mask, 4Mb DRAM */
-#define	DCCR0		0x00000007	/* DRAM0 control, R/W, burst pg mde */
-#define	DCAR1		0x00000000	/* DRAM1 address, 0 base addr */
-#define	DCMR1		0x00000000	/* DRAM1 mask, no DRAM */
-#define	DCCR1		0x00000000	/* DRAM1 control, off */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	move.l	#MCF_MBAR+1, %a0		/* Set I/O base addr */
-	movec	%a0, %MBAR			/* Note: bit 0 is Validate */
-	move.l	#MEM_BUILTIN+1,%a0		/* Set SRAM base addr */
-	movec	%a0, %RAMBAR0			/* Note: bit 0 is Validate */
-
-	move.l	#MCF_MBAR, %a0			/* Get I/O base addr */
-
-	/* ----------------------- CS1 ----------------------- */
-	move.w	#CS1_ADDR, %d0			/* CS1 address */
-	move.w	%d0, MCFSIM_CSAR1(%a0)		/* CS1 address */
-	move.l	#CS1_MASK, %d0			/* CS1 mask */
-	move.l	%d0, MCFSIM_CSMR1(%a0)		/* CS1 mask */
-	move.w	#CS1_CTRL, %d0			/* CS1 control */
-	move.w	%d0, MCFSIM_CSCR1(%a0)		/* CS1 control */
-
-	/* ----------------------- CS2 ----------------------- */
-	move.w	#CS2_ADDR, %d0			/* CS2 address */
-	move.w	%d0, MCFSIM_CSAR2(%a0)		/* CS2 address */
-	move.l	#CS2_MASK, %d0			/* CS2 mask */
-	move.l	%d0, MCFSIM_CSMR2(%a0)		/* CS2 mask */
-	move.w	#CS2_CTRL, %d0			/* CS2 control */
-	move.w	%d0, MCFSIM_CSCR2(%a0)		/* CS2 control */
-
-	/* ----------------------- CS3 ----------------------- */
-	move.w	#CS3_ADDR, %d0			/* CS3 address */
-	move.w	%d0, MCFSIM_CSAR3(%a0)		/* CS3 address */
-	move.l	#CS3_MASK, %d0			/* CS3 mask */
-	move.l	%d0, MCFSIM_CSMR3(%a0)		/* CS3 mask */
-	move.w	#CS3_CTRL, %d0			/* CS3 control */
-	move.w	%d0, MCFSIM_CSCR3(%a0)		/* CS3 control */
-
-	/* ----------------------- CS4 ----------------------- */
-	move.w	#CS4_ADDR, %d0			/* CS4 address */
-	move.w	%d0, MCFSIM_CSAR4(%a0)		/* CS4 address */
-	move.l	#CS4_MASK, %d0			/* CS4 mask */
-	move.l	%d0, MCFSIM_CSMR4(%a0)		/* CS4 mask */
-	move.w	#CS4_CTRL, %d0			/* CS4 control */
-	move.w	%d0, MCFSIM_CSCR4(%a0)		/* CS4 control */
-
-	/* ----------------------- CS5 ----------------------- */
-	move.w	#CS5_ADDR, %d0			/* CS5 address */
-	move.w	%d0, MCFSIM_CSAR5(%a0)		/* CS5 address */
-	move.l	#CS5_MASK, %d0			/* CS5 mask */
-	move.l	%d0, MCFSIM_CSMR5(%a0)		/* CS5 mask */
-	move.w	#CS5_CTRL, %d0			/* CS5 control */
-	move.w	%d0, MCFSIM_CSCR5(%a0)		/* CS5 control */
-
-	/* ----------------------- CS6 ----------------------- */
-	move.w	#CS6_ADDR, %d0			/* CS6 address */
-	move.w	%d0, MCFSIM_CSAR6(%a0)		/* CS6 address */
-	move.l	#CS6_MASK, %d0			/* CS6 mask */
-	move.l	%d0, MCFSIM_CSMR6(%a0)		/* CS6 mask */
-	move.w	#CS6_CTRL, %d0			/* CS6 control */
-	move.w	%d0, MCFSIM_CSCR6(%a0)		/* CS6 control */
-
-	/* ----------------------- CS7 ----------------------- */
-	move.w	#CS7_ADDR, %d0			/* CS7 address */
-	move.w	%d0, MCFSIM_CSAR7(%a0)		/* CS7 address */
-	move.l	#CS7_MASK, %d0			/* CS7 mask */
-	move.l	%d0, MCFSIM_CSMR7(%a0)		/* CS7 mask */
-	move.w	#CS7_CTRL, %d0			/* CS7 control */
-	move.w	%d0, MCFSIM_CSCR7(%a0)		/* CS7 control */
-
-	/* --------------------- Default --------------------- */
-	move.w	#DMC_CTRL, %d0			/* Default control */
-	move.w	%d0, MCFSIM_DMCR(%a0)		/* Default control */
-
-	/* ----------------------- DRAM ------------------------ */
-	move.w	#DCRR, %d0			/* Refresh period */
-	move.w	%d0, MCFSIM_DCRR(%a0)		/* Refresh period */
-	move.w	#DCTR, %d0			/* Timing address */
-	move.w	%d0, MCFSIM_DCTR(%a0)		/* Timing address */
-	move.w	#DCAR0, %d0			/* DRAM0 base address */
-	move.w	%d0, MCFSIM_DCAR0(%a0)		/* DRAM0 base address */
-	move.l	#DCMR0, %d0			/* DRAM0 mask */
-	move.l	%d0, MCFSIM_DCMR0(%a0)		/* DRAM0 mask */
-	move.b	#DCCR0, %d0			/* DRAM0 control */
-	move.b	%d0, MCFSIM_DCCR0(%a0)		/* DRAM0 control */
-	move.w	#DCAR1, %d0			/* DRAM1 base address */
-	move.w	%d0, MCFSIM_DCAR1(%a0)		/* DRAM1 base address */
-	move.l	#DCMR1, %d0			/* DRAM1 mask */
-	move.l	%d0, MCFSIM_DCMR1(%a0)		/* DRAM1 mask */
-	move.b	#DCCR1, %d0			/* DRAM1 control */
-	move.b	%d0, MCFSIM_DCCR1(%a0)		/* DRAM1 control */
-
-	/*
-	 * ChipSelect 0 - ROM cs
-	 *
-	 * ChipSelect 0 is the global chip select coming out of system reset.
-	 * CS0 is asserted for every access until CSMR0 is written.  Therefore,
-	 * the entire ChipSelect must be properly set prior to asserting
-	 * CSCR0_V.
-	 */
-	move.w	#CS0_ADDR, %d0			/* CS0 address */
-	move.w	%d0, MCFSIM_CSAR0(%a0)		/* CS0 address */
-	move.l	#CS0_MASK, %d0			/* CS0 mask */
-	move.l	%d0, MCFSIM_CSMR0(%a0)		/* CS0 mask */
-	move.w	#CS0_CTRL, %d0			/* CS0 control */
-	move.w	%d0, MCFSIM_CSCR0(%a0)		/* CS0 control */
-
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack
-	 *	Done differently for different eval boards and cpus.
-	 */
-
-#if defined(CONFIG_SMALL)
-	/*
-	 *	Set to SRAM size when configuring a minimal system
-	 */
-	move.l	#MEM_MAX, %a0
-
-#else
-	/*
-	 *	On the Arnewsh 5206 board and the Motorola m5206eLITE board
-	 *	we can probe for the amount of DRAM present...
-	 */
-	move.l	#MEM_MIN, %a0			/* Start at bottom */
-	move.l	#MEM_MAX, %a1			/* Set stop point */
-	lea.l	MEM_TMPSTACK, %sp		/* Set up tmp stack ptr */
-
-	move.l	#VBR_BASE+8, %a2		/* Address of bus trap */
-	lea.l	_ram_buserr, %a3		/* Get RAM trap address */
-	move.l	%a3, (%a2)			/* Set trap to local ptr */
-
-_find_ram:
-	move.l	(%a0), %d0			/* Attempt read */
-	add.l	#MEM_LUMP, %a0			/* Try next bank */
-	cmp.l	%a1, %a0			/* Check more? */
-	bne	_find_ram
-
-	/*
-	 *	BUS error trap handler - used for RAM probing.
-	 */
-_ram_buserr:
-	bra	_found_ram
-
-_found_ram:					/* Vectored here on bus err */
-#endif
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *      Load the current task pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S
+++ /dev/null
@@ -1,230 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Motorola M5249C3 eval board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Motorola M5249C3 ColdFire eval board, chip select and memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	MEM_SIZE	0x00800000	/* Memory size 8MB */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 *	Set MBAR1 and MBAR2, just incase they are not set.
-	 */
-	move.l  #0x10000001, %a0
-	movec   %a0, %MBAR			/* Map MBAR region */
-	subq.l  #1, %a0				/* Get MBAR address in a0 */
-
-	move.l  #0x80000001, %a1
-	movec   %a1, #3086			/* Map MBAR2 region */
-	subq.l  #1, %a1				/* Get MBAR2 address in a1 */
-
-	/*
-	 *      Move secondary interrupts to base at 128.
-	 */
-	move.b  #0x80, %d0
-	move.b  %d0, 0x16b(%a1)			/* Interrupt base register */
-
-#if 1
-	/*
-	 *      Work around broken CSMR0/DRAM vector problem.
-	 */
-	move.l  #0x001F0021, %d0		/* Disable C/I bit */
-	move.l  %d0, 0x84(%a0)			/* Set CSMR0 */
-#endif
-
-	/*
-	 *	Disable the PLL firstly. (Who knows what state it is
-	 *	in here!).
-	 */
-	move.l  0x180(%a1), %d0			/* Get current PLL value */
-	and.l   #0xfffffffe, %d0		/* PLL bypass first */
-	move.l  %d0, 0x180(%a1)			/* Set PLL register */
-	nop
-
-#ifdef CONFIG_CLOCK_140MHz
-	/*
-	 *	Set initial clock frequency. This assumes M5249C3 board
-	 *	is fitted with 11.2896MHz crystal. It will program the
-	 *	PLL for 140MHz. Lets go fast :-)
-	 */
-	move.l  #0x125a40f0, %d0		/* Set for 140MHz */
-	move.l  %d0, 0x180(%a1)			/* Set PLL register */
-	or.l    #0x1, %d0
-	move.l  %d0, 0x180(%a1)			/* Set PLL register */
-#endif
-
-	/*
-	 *	Setup CS1 for ethernet controller.
-	 *	(Setup as per M5249C3 doco).
-	 */
-	move.l  #0xe0000000, %d0		/* CS1 mapped at 0xe0000000 */
-	move.l  %d0, 0x8c(%a0)
-	move.l  #0x001f0021, %d0		/* CS1 size of 1Mb */
-	move.l  %d0, 0x90(%a0)
-	move.w  #0x0080, %d0			/* CS1 = 16bit port, AA */
-	move.w  %d0, 0x96(%a0)
-
-	/*
-	 *	Setup CS2 for IDE interface.
-	 */
-	move.l	#0x50000000, %d0		/* CS2 mapped at 0x50000000 */
-	move.l	%d0, 0x98(%a0)
-	move.l	#0x001f0001, %d0		/* CS2 size of 1MB */
-	move.l	%d0, 0x9c(%a0)
-	move.w	#0x0080, %d0			/* CS2 = 16bit, TA */
-	move.w	%d0, 0xa2(%a0)
-
-	move.l	#0x00107000, %d0		/* IDEconfig1 */
-	move.l	%d0, 0x18c(%a1)
-	move.l	#0x000c0400, %d0		/* IDEconfig2 */
-	move.l	%d0, 0x190(%a1)
-
-	move.l	#0x00080000, %d0		/* GPIO19, IDE reset bit */
-	or.l	%d0, 0xc(%a1)			/* Function GPIO19 */
-	or.l	%d0, 0x8(%a1)			/* Enable GPIO19 as output */
-        or.l	%d0, 0x4(%a1)			/* De-assert IDE reset */
-
-
-	/*
-	 *	Setup VBR as per eval board (really dBUG does this).
-	 *	These settings must match it.
-	 */
-	move.l	#VBR_BASE, %a0			/* Note VBR can't be read */
-	movec   %a0, %VBR
-	move.l	%a0, _ramvec			/* Set up vector addr */
-	move.l	%a0, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set the memory size, and then set a temporary stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l  #0x01000000, %d0		/* Invalidate whole cache */
-	movec   %d0, %CACR
-	nop
-
-	move.l  #0x0000c000, %d0		/* Set SDRAM cached only */
-	movec   %d0, %ACR0
-	move.l  #0x00000000, %d0		/* No other regions cached */
-	movec   %d0, %ACR1
-
-	move.l  #0xa0000200, %d0		/* Enable cache... */
-	movec   %d0, %CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile
--- a/arch/m68knommu/platform/5249/Makefile
+++ b/arch/m68knommu/platform/5249/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/5272/CANCam/crt0_ram.S b/arch/m68knommu/platform/5272/CANCam/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5272/CANCam/crt0_ram.S
+++ /dev/null
@@ -1,154 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Feith CANCan board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	(C) Copyright 2000, Lineo (www.lineo.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Feith ColdFire CANCam, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-#define MEM_SIZE  0x04000000      /* Memory size 64Mb */
-
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S
+++ /dev/null
@@ -1,165 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5272 ColdFire based MOTOROLA boards.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	(C) Copyright 2000, Lineo (www.lineo.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Motorola M5272C3 ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec	%a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-#if defined(CONFIG_RAMAUTO)
-	move.l	MCF_MBAR+0x7c,%d0	/* get SDRAM address mask */
-	andi.l	#0xfffff000,%d0		/* mask out chip select options */
-	neg.l	%d0			/* negate bits */
-#else
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %d0
-#endif
-
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile
--- a/arch/m68knommu/platform/5272/Makefile
+++ b/arch/m68knommu/platform/5272/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/5272/NETtel/crt0_ram.S b/arch/m68knommu/platform/5272/NETtel/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5272/NETtel/crt0_ram.S
+++ /dev/null
@@ -1,196 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5307 ColdFire based NETtel.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- * 	Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-#include "asm/nettel.h"
-
-/*****************************************************************************/
-
-/*
- *	Lineo NETtel board memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-/*
- *	The NETtel platform has some funky LEDs!
- */
-.global ppdata
-ppdata:
-.short	0x0000
-
-.global ledbank
-ledbank:
-.byte	0xff
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-#ifdef CONFIG_ROMFS_FROM_ROM
-	/*
-	 *	check for an in RAM romfs
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	mov.l	(%a0), %d0
-	cmp.l	#0x2d726f6d, %d0	/* check for "-rom" */
-	bne		use_xip_romfs
-	add.l	#4, %a0
-	mov.l	(%a0), %d0
-	cmp.l	#0x3166732d, %d0	/* check for "1fs-" */
-	bne		use_xip_romfs
-#endif
-
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#ifdef CONFIG_ROMFS_FROM_ROM
-	bra		done_romfs
-  use_xip_romfs:
-	lea.l	_ebss, %a1			/* Set up destination  */
-	mov.l	#0, (%a1)			/* make sure we don't use an old RAM version */
-	move.l	%a1, _ramstart		/* Set start of ram */
-  done_romfs:
-#endif
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5272/SCALES/crt0_ram.S b/arch/m68knommu/platform/5272/SCALES/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5272/SCALES/crt0_ram.S
+++ /dev/null
@@ -1,154 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Feith SCALES board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	(C) Copyright 2000, Lineo (www.lineo.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Feith ColdFire SCALES, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-#define MEM_SIZE  0x02000000      /* Memory size 32Mb */
-
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -39,6 +39,14 @@ extern unsigned int mcf_timerlevel;
 /***************************************************************************/
 
 /*
+ *	Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+/*
  *	DMA channel base address table.
  */
 unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
diff --git a/arch/m68knommu/platform/5272/senTec/crt0_ram.S b/arch/m68knommu/platform/5272/senTec/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5272/senTec/crt0_ram.S
+++ /dev/null
@@ -1,159 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5272 ColdFire based boards.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	(C) Copyright 2000, Lineo (www.lineo.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	senTec COBRA5272 board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* Invalidate cache cmd */
-	movec	%d0, %CACR			/* Invalidate cache */
-	move.l	#0x80000100, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S b/arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S
+++ /dev/null
@@ -1,166 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF527x ColdFire based Freescale boards.
- *
- *	(C) Copyright 2003-2004, Greg Ungerer (gerg@snapgear.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Freescale M5271EVB ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM4MB)
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01400000, %d0
-	movec	%d0, %CACR			/* Invalidate cache */
-	nop
-
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	move.l	#0x80400100, %d0		/* Configure cache */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S b/arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S
+++ /dev/null
@@ -1,166 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF527x ColdFire based Freescale boards.
- *
- *	(C) Copyright 2003-2004, Greg Ungerer (gerg@snapgear.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Freescale M5275EVB ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM4MB)
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01400000, %d0
-	movec	%d0, %CACR			/* Invalidate cache */
-	nop
-
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	move.l	#0x80400100, %d0		/* Configure cache */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
--- a/arch/m68knommu/platform/527x/Makefile
+++ b/arch/m68knommu/platform/527x/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S b/arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S
+++ /dev/null
@@ -1,171 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for M5282EVB ColdFire based MOTOROLA boards.
- *
- *	(C) Copyright 2003, Greg Ungerer (gerg@snapgear.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	Motorola M5282EVB ColdFire eval board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 *
-	 *	Cache is totally broken in first 5282 silicon.
-	 *	No point enabling it for now.
-	 */
-#if 0
-	move.l	#0x01000000, %d0
-	movec	%d0, %CACR			/* Invalidate cache */
-	nop
-
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	move.l	#0x00000000, %d0		/* Setup cache mask */
-	movec	%d0, %CACR			/* Enable cache */
-	nop
-#endif
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
--- a/arch/m68knommu/platform/528x/Makefile
+++ b/arch/m68knommu/platform/528x/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/528x/senTec/crt0_ram.S b/arch/m68knommu/platform/528x/senTec/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/528x/senTec/crt0_ram.S
+++ /dev/null
@@ -1,180 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for senTec COBRA5282 ColdFire based boards.
- *
- *	(C) Copyright 2003, Greg Ungerer (gerg@snapgear.com).
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*****************************************************************************/
-
-/*
- *	senTec COBRA5282 board, chip select and memory setup.
- */
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-
-#define IPSBAR 0x40000000
-#define GPACR0 0x30
-/*****************************************************************************/
-
-.global	_start
-.global	_rambase
-.global	_ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop								/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Set memory size.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend		/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 *
-	 *	Cache is totally broken in first 5282 silicon.
-	 *	No point enabling it for now.
-	 */
-#if 0
-	move.l	#0x01000000, %d0
-	movec	%d0, %CACR				/* Invalidate cache */
-	nop
-
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	move.l	#0x00000000, %d0		/* Setup cache mask */
-	movec	%d0, %CACR				/* Enable cache */
-	nop
-#endif
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0	/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart		/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0					/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current thread pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-   /*
-    * User mode port access
-    */
-   move.l   #0x0000000c, %d0
-   move.b   %d0, (IPSBAR+GPACR0)
-
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S
+++ /dev/null
@@ -1,167 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5307 ColdFire Arnewsh board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- * 	Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-#include "asm/nettel.h"
-
-/*****************************************************************************/
-
-/*
- *	SnapGear/NETtel board memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/* make region ROM cachable (turn off for flash programming?) */
-	/* 0xff000000 - 0xffffffff */
-#ifdef DEBUGGER_COMPATIBLE_CACHE
-	movl #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WTHRU+ACR_WPROTECT,%d0
-#else
-	movl #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK+ACR_WPROTECT,%d0
-#endif
-	movc  %d0,%ACR0
-
-	/* make region RAM cachable *
-	/* 0x00000000 - 0x00ffffffff */
-#ifdef DEBUGGER_COMPATIBLE_CACHE
-	movl #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WTHRU,%d0
-#else
-	movl #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK,%d0
-#endif
-	movc  %d0,%ACR1
-
-	/* make the default cache mode precise */
-	movl  #CACR_EC+CACR_ESB+CACR_DCM_OFF_PRE,%d0 /* enable cache */
-	movc  %d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S
+++ /dev/null
@@ -1,183 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Feith CLEOPATRA board.
- *
- *	(C) Copyright 2001, Roman Wagner.
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Feith CLEOPATRA board, chip select and memory setup.
-*/
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#else
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-/*
- * The current version of the 5307 processor
- * SWT does not work. Probing invalid addresses
- * will hang the system.
- *
- * For now, set the memory size to 8 meg
- */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/* now fire off the cache, remember to invalidate it first */
-	movl  #0,%d0
-	movc  %d0,%CACR
-	nop
-	movc  %d0,%CACR				/* cache is off */
-
-	movl  #CACR_CINVA,%d0			/* invalidate whole cache */
-	movc  %d0,%CACR
-	nop
-	movc  %d0,%CACR
-	nop                                    
-
-	/* make region ROM cachable (turn off for flash programming?) */
-	/* 0xff000000 - 0xffffffff */
-	movl #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK+ACR_WPROTECT,%d0
-	movc  %d0,%ACR0
-
-	/* make region RAM cachable *
-	/* 0x00000000 - 0x00ffffffff */
-	movl #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK,%d0
-	movc  %d0,%ACR1
-
-	/* make the default cache mode precise */
-	movl  #CACR_EC+CACR_ESB+CACR_DCM_OFF_PRE,%d0 /* enable cache */
-	movc  %d0,%CACR
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S
+++ /dev/null
@@ -1,167 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5307C3 Cadre-III ColdFire board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- * 	Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-#include "asm/nettel.h"
-
-/*****************************************************************************/
-
-/*
- *	SnapGear/NETtel board memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/* make region ROM cachable (turn off for flash programming?) */
-	/* 0xff000000 - 0xffffffff */
-#ifdef DEBUGGER_COMPATIBLE_CACHE
-	movl #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WTHRU+ACR_WPROTECT,%d0
-#else
-	movl #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK+ACR_WPROTECT,%d0
-#endif
-	movc  %d0,%ACR0
-
-	/* make region RAM cachable *
-	/* 0x00000000 - 0x00ffffffff */
-#ifdef DEBUGGER_COMPATIBLE_CACHE
-	movl #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WTHRU,%d0
-#else
-	movl #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_WBACK,%d0
-#endif
-	movc  %d0,%ACR1
-
-	/* make the default cache mode precise */
-	movl  #CACR_EC+CACR_ESB+CACR_DCM_OFF_PRE,%d0 /* enable cache */
-	movc  %d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/MP3/crt0_ram.S b/arch/m68knommu/platform/5307/MP3/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5307/MP3/crt0_ram.S
+++ /dev/null
@@ -1,181 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5307 ColdFire based MP3.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- * 	Copyright (C) 2000-2001  Lineo Inc. (www.lineo.com) 
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-#include "asm/nettel.h"
-
-/*****************************************************************************/
-
-/*
- *	SnapGear/NETtel board memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#else
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 *	Disable watchdog timer.
-	 */
-	move.l	#MCF_MBAR, %a0			/* Get MBAR address */
-	clr.l	%d0				/* Disable SWT */
-	move.b	%d0, MCFSIM_SYPCR(%a0)
-	move.b	#0x55, %d0			/* Clear SWT as well */
-	move.b	%d0, MCFSIM_SWSR(%a0)
-	move.b	#0xaa, %d0
-	move.b	%d0, MCFSIM_SWSR(%a0)
-	move.l	#0xffffffff, %d0		/* Mask out all interrupts */
-	move.l	%d0, MCFSIM_IMR(%a0)
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* invalidate whole cache */
-	movec	%d0,%CACR
-	nop
-
-	/* MUST be write-through for DMA to work... */
-	/* This also makes this debugger safe */
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	/* Enable cache */
-	move.l	#0xa0000200, %d0
-	movec	%d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -26,6 +26,4 @@ obj-$(CONFIG_M5307)	+= config.o timers.o
 obj-$(CONFIG_M528x)     += pit.o
 obj-$(CONFIG_M5407)	+= timers.o
 
-ifeq ($(CONFIG_M5307),y)
-extra-y := $(BOARD)/crt0_$(MODEL).o
-endif
+extra-y := head.o
diff --git a/arch/m68knommu/platform/5307/NETtel/crt0_ram.S b/arch/m68knommu/platform/5307/NETtel/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5307/NETtel/crt0_ram.S
+++ /dev/null
@@ -1,204 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for MCF5307 ColdFire based NETtel.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- * 	Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-#include "asm/nettel.h"
-
-/*****************************************************************************/
-
-/*
- *	SnapGear/NETtel board memory setup.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#if defined(CONFIG_RAM16MB)
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define	MEM_SIZE	0x00800000	/* Memory size 8Mb */
-#else
-#define	MEM_SIZE	0x00400000	/* Memory size 4Mb */
-#endif
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-/*
- *	The NETtel platform has some funky LEDs!
- */
-.global ppdata
-ppdata:
-.short	0x0000
-
-.global ledbank
-ledbank:
-.byte	0xff
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 *	Set LEDs to known startup state.
-	 */
-	move.l	#NETtel_LEDADDR, %a5		/* Addr of LED bank */
-	move.b	#0xff, (%a5)			/* Turn them all off */
-
-
-	/*
-	 *	Disable watchdog timer.
-	 */
-	move.l	#MCF_MBAR, %a0			/* Get MBAR address */
-	clr.l	%d0				/* Disable SWT */
-	move.b	%d0, MCFSIM_SYPCR(%a0)
-	move.b	#0x55, %d0			/* Clear SWT as well */
-	move.b	%d0, MCFSIM_SWSR(%a0)
-	move.b	#0xaa, %d0
-	move.b	%d0, MCFSIM_SWSR(%a0)
-	move.l	#0xffffffff, %d0		/* Mask out all interrupts */
-	move.l	%d0, MCFSIM_IMR(%a0)
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01000000, %d0		/* invalidate whole cache */
-	movec	%d0,%CACR
-	nop
-#ifdef DEBUGGER_COMPATIBLE_CACHE
-	move.l	#0x0000c000, %d0		/* Set SDRAM cached only */
-#else
-	move.l	#0x0000c020, %d0		/* Set SDRAM cached only (copyback) */
-#endif
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-
-	/* Enable cache */
-	move.l	#0xa0000200, %d0
-	movec	%d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 * load the current task pointer and stack
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -40,6 +40,14 @@ extern unsigned int mcf_timerlevel;
 /***************************************************************************/
 
 /*
+ *	Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+/*
  *	DMA channel base address table.
  */
 unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
diff --git a/arch/m68knommu/platform/5307/entry.S b/arch/m68knommu/platform/5307/entry.S
--- a/arch/m68knommu/platform/5307/entry.S
+++ b/arch/m68knommu/platform/5307/entry.S
@@ -5,6 +5,7 @@
  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
  *                      Kenneth Albanowski <kjahds@kjahds.com>,
  *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
+ *  Copyright (C) 2004  Macq Electronique SA. (www.macqel.com)
  *
  * Based on:
  *
@@ -22,6 +23,7 @@
  * ColdFire support by Greg Ungerer (gerg@snapgear.com)
  * 5307 fixes by David W. Miller
  * linux 2.4 support David McCullough <davidm@snapgear.com>
+ * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
  */
 
 #include <linux/config.h>
@@ -35,7 +37,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/entry.h>
 
-.data
+.bss
 
 sw_ksp:
 .long	0
@@ -59,7 +61,7 @@ ENTRY(system_call)
 	move	#0x2000,%sr		/* enable intrs again */
 
 	movel	#-LENOSYS,%d2
-	movel	%d2,LD0(%sp)		/* default return value in d0 */
+	movel	%d2,PT_D0(%sp)		/* default return value in d0 */
 					/* original D0 is in orig_d0 */
 	movel	%d0,%d2
 
@@ -77,14 +79,14 @@ ENTRY(system_call)
 	lsrl	#2,%d2
 
 	movel	%sp,%d2			/* get thread_info pointer */
-	andl	#0xffffe000,%d2		/* at start of 8k kernel stack */
+	andl	#-THREAD_SIZE,%d2	/* at start of kernel stack */
 	movel	%d2,%a0
 	btst	#TIF_SYSCALL_TRACE,%a0@(TI_FLAGS)
 	bnes	1f
 
 	movel	%d3,%a0
 	jbsr	%a0@
-	movel	%d0,%sp@(LD0)		/* save the return value */
+	movel	%d0,%sp@(PT_D0)		/* save the return value */
 	jra	ret_from_exception
 1:
 	subql	#4,%sp
@@ -94,7 +96,7 @@ ENTRY(system_call)
 	addql	#4,%sp
 	movel	%d3,%a0
 	jbsr	%a0@
-	movel	%d0,%sp@(LD0)		/* save the return value */
+	movel	%d0,%sp@(PT_D0)		/* save the return value */
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
 	jbsr	syscall_trace
@@ -104,20 +106,20 @@ ret_from_signal:
 	addql	#4,%sp
 
 ret_from_exception:
-	btst	#5,%sp@(LSR)		/* check if returning to kernel */
+	btst	#5,%sp@(PT_SR)		/* check if returning to kernel */
 	jeq	Luser_return		/* if so, skip resched, signals */
 
 Lkernel_return:
-	moveml  %sp@,%d1-%d5/%a0-%a2
-	addl    #32,%sp			/* space for 8 regs */
-	movel   %sp@+,%d0
-	addql   #4,%sp			/* orig d0 */
-	addl    %sp@+,%sp		/* stk adj */
+	moveml	%sp@,%d1-%d5/%a0-%a2
+	lea	%sp@(32),%sp		/* space for 8 regs */
+	movel	%sp@+,%d0
+	addql	#4,%sp			/* orig d0 */
+	addl	%sp@+,%sp		/* stk adj */
 	rte
 
 Luser_return:
 	movel	%sp,%d1			/* get thread_info pointer */
-	andl	#0xffffe000,%d1		/* at base of 8k kernel stack */
+	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
 	movel	%d1,%a0
 	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
 	andl	#_TIF_WORK_MASK,%d1
@@ -126,27 +128,17 @@ Luser_return:
 Lreturn:
 	move    #0x2700,%sr		/* disable intrs */
 	movel   sw_usp,%a0		/* get usp */
-	moveml  %sp@(LFORMATVEC),%d1-%d2 /* copy exception */
-	moveml  %d1-%d2,%a0@(-8)
-	bclr    #5,%a0@(-8)		/* clear format byte, bit 5 to make
-					 * stack appear modulo 4 which it WILL
-					 * be when we do the rte because it was
-					 * generated in setup_frame
-					 */
-	bclr    #4,%a0@(-8)		/* clear format byte, bit 4 to make 
-					 * stack appear modulo 4 which it WILL
-					 * be when we do the rte because it was
-					 * generated in setup_frame
-					 */
-	moveml  %sp@,%d1-%d5/%a0-%a2
-	addl    #32,%sp			/* space for 8 regs */
-	movel   %sp@+,%d0                  
-	addql   #4,%sp			/* orig d0 */
-	addl    %sp@+,%sp		/* stk adj */
-	addql   #8,%sp			/* remove exception */
-	movel   %sp,sw_ksp		/* save ksp */
-	movel   sw_usp,%sp		/* restore usp */
-	subql   #8,%sp			/* set exception */
+	movel	%sp@(PT_PC),%a0@-	/* copy exception program counter */
+	movel	%sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */
+	moveml	%sp@,%d1-%d5/%a0-%a2
+	lea	%sp@(32),%sp		/* space for 8 regs */
+	movel	%sp@+,%d0
+	addql	#4,%sp			/* orig d0 */
+	addl	%sp@+,%sp		/* stk adj */
+	addql	#8,%sp			/* remove exception */
+	movel	%sp,sw_ksp		/* save ksp */
+	subql	#8,sw_usp		/* set exception */
+	movel	sw_usp,%sp		/* restore usp */
 	rte
 
 Lwork_to_do:
@@ -160,8 +152,7 @@ Lsignal_return:
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	clr	%d1
-	movel	%d1,%sp@-
+	clrl	%sp@-
 	jsr	do_signal
 	addql	#8,%sp
 	RESTORE_SWITCH_STACK
@@ -176,10 +167,10 @@ Lsignal_return:
 ENTRY(inthandler)
 	SAVE_ALL
 	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)
+	movel	%d0,%sp@(PT_ORIG_D0)
 	addql	#1,local_irq_count
 
-	movew   %sp@(LFORMATVEC),%d0	/* put exception # in d0 */
+	movew   %sp@(PT_FORMATVEC),%d0	/* put exception # in d0 */
 	andl	#0x03fc,%d0		/* mask out vector only */
 
 	leal	per_cpu__kstat+STAT_IRQ,%a0
@@ -197,7 +188,7 @@ ENTRY(inthandler)
 
 	movel	%a0@,%a0		/* get function to call */
 	jbsr	%a0@			/* call vector handler */
-	addl	#12,%sp			/* pop parameters off stack */
+	lea	%sp@(12),%sp		/* pop parameters off stack */
 
 	bra	ret_from_interrupt	/* this was fallthrough */
 
@@ -210,15 +201,14 @@ ENTRY(inthandler)
 ENTRY(fasthandler)
 	SAVE_LOCAL
 
-	movew   %sp@(LFORMATVEC),%d0
+	movew   %sp@(PT_FORMATVEC),%d0
 	andl	#0x03fc,%d0		/* mask out vector only */
 
 	leal	per_cpu__kstat+STAT_IRQ,%a0
 	addql	#1,%a0@(%d0)
 
 	movel	%sp,%sp@-		/* push regs arg onto stack */
-	clrl	%d1
-	movel	%d1,%sp@- 		/* push devid arg */
+	clrl	%sp@-			/* push devid arg */
 	lsrl	#2,%d0			/* calculate real vector # */
 	movel	%d0,%sp@- 		/* push vector # on stack */
 
@@ -226,7 +216,7 @@ ENTRY(fasthandler)
 	lea	irq_list,%a0
 	movel	%a0@(%d0),%a0		/* get function to call */
 	jbsr	%a0@			/* call vector handler */
-	addl	#12,%sp			/* pop parameters off stack */
+	lea	%sp@(12),%sp		/* pop parameters off stack */
 
 	RESTORE_LOCAL
 
@@ -236,7 +226,7 @@ ENTRY(ret_from_interrupt)
 1:
 	RESTORE_ALL
 2:
-	moveb	%sp@(LSR),%d0
+	moveb	%sp@(PT_SR),%d0
 	andl	#0x7,%d0
 	jhi	1b
 
diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S
--- a/arch/m68knommu/platform/5307/head.S
+++ b/arch/m68knommu/platform/5307/head.S
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/sys.h>
 #include <linux/linkage.h>
-#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
 #include <asm/coldfire.h>
 #include <asm/mcfcache.h>
 #include <asm/mcfsim.h>
@@ -87,7 +87,7 @@
 .endm
 
 #elif defined(CONFIG_M5272)
-.macro GET_MEMORY_SIZE
+.macro GET_MEM_SIZE
 	movel	MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */
 	andil	#0xfffff000,%d0		/* mask out chip select options */
 	negl	%d0			/* negate bits */
diff --git a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S
+++ /dev/null
@@ -1,180 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Feith Cleopatra 2 board.
- *
- *	(C) Copyright 2001, Roman Wagner.
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Feith CLEOPATRA board, chip select and memory setup.
-*/
-
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#define	MEM_SIZE	0x01000000	/* Memory size 16Mb */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-
-	/*
-	 * Setup VBR here, otherwise buserror remap will not work.
-	 * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
-	 *
-	 * bkr@cut.de 19990306
-	 *
-	 * Note: this is because dBUG points VBR to ROM, making vectors read
-	 * only, so the bus trap can't be changed. (RS)
-	 */
-	move.l	#VBR_BASE, %a7			/* Note VBR can't be read */
-	movec   %a7, %VBR
-	move.l	%a7, _ramvec			/* Set up vector addr */
-	move.l	%a7, _rambase			/* Set up base RAM addr */
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-/*
- * The current version of the 5307 processor
- * SWT does not work. Probing invalid addresses
- * will hang the system.
- *
- * For now, set the memory size to 8 meg
- */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01040100, %d0		/* Invalidate whole cache */
-	movec	%d0,%CACR
-	nop
-
-	/* make region ROM cachable (turn off for flash programming?) */
-	/* 0xff000000 - 0xffffffff */
-	move.l #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP+ACR_WPROTECT,%d0
-	movec  %d0,%ACR0
-
-	/* make region RAM cachable */
-	/* 0x00000000 - 0x00ffffffff */
-	move.l #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP,%d0
-   movec  %d0,%ACR1
-
-	move.l #(0xff<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP+ACR_WPROTECT,%d0
-	movec  %d0,%ACR2
-
-	move.l #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP,%d0
-   movec  %d0,%ACR3
- 
-	/* Enable cache */
-	move.l	#0xa4098400, %d0		/* Write buffer, dflt precise */
-	movec	%d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current task pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S
+++ /dev/null
@@ -1,160 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	crt0_ram.S -- startup code for Motorola 5407 eval board.
- *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
- *	(C) Copyright 2000, Lineo (www.lineo.com).
- *
- * 	1999/02/24 Modified for the 5307 processor David W. Miller
- */
-
-/*****************************************************************************/
-
-#include "linux/autoconf.h"
-#include "asm/coldfire.h"
-#include "asm/mcfsim.h"
-
-/*****************************************************************************/
-
-/*
- *	Board setup info.
- */
-#define	MEM_BASE	0x00000000	/* Memory base at address 0 */
-#define	VBR_BASE	MEM_BASE	/* Vector address */
-
-#define	MEM_SIZE	0x02000000	/* Memory size 32 */
-
-/*****************************************************************************/
-
-.global	_start
-.global _rambase
-.global _ramvec
-.global	_ramstart
-.global	_ramend
-
-/*****************************************************************************/
-
-.data
-
-/*
- *	Set up the usable of RAM stuff. Size of RAM is determined then
- *	an initial stack set up at the end.
- */
-_rambase:
-.long	0
-_ramvec:
-.long	0
-_ramstart:
-.long	0
-_ramend:
-.long	0
-
-/*****************************************************************************/
-
-.text
-
-/*
- *	This is the codes first entry point. This is where it all
- *	begins...
- */
-
-_start:
-	nop					/* Filler */
-	move.w	#0x2700, %sr			/* No interrupts */
-
-	/*
-	 *	Setup VBR as per eval board (really dBUG does this).
-	 *	These settings must match it.
-	 */
-	move.l	#VBR_BASE, %a0			/* Note VBR can't be read */
-	movec   %a0, %VBR
-	move.l	%a0, _ramvec			/* Set up vector addr */
-	move.l	%a0, _rambase			/* Set up base RAM addr */
-
-
-	/*
-	 *	Determine size of RAM, then set up initial stack.
-	 */
-	move.l	#MEM_SIZE, %a0
-
-	move.l	%a0, %d0			/* Mem end addr is in a0 */
-	move.l	%d0, %sp			/* Set up initial stack ptr */
-	move.l	%d0, _ramend			/* Set end ram addr */
-
-
-	/*
-	 *	Enable CPU internal cache.
-	 */
-	move.l	#0x01040100, %d0		/* Invalidate whole cache */
-	movec	%d0,%CACR
-	nop
-	move.l	#0x000fc000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR0
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR1
-	move.l	#0x000fc000, %d0		/* Set SDRAM cached only */
-	movec	%d0, %ACR2
-	move.l	#0x00000000, %d0		/* No other regions cached */
-	movec	%d0, %ACR3
-
-	/* Enable cache */
-	move.l	#0xb6088400, %d0		/* Enable caches */
-	movec	%d0,%CACR
-	nop
-
-
-#ifdef CONFIG_ROMFS_FS
-	/*
-	 *	Move ROM filesystem above bss :-)
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Set up destination  */
-	move.l	%a0, %a2			/* Copy of bss start */
-
-	move.l	8(%a0), %d0			/* Get size of ROMFS */
-	addq.l	#8, %d0				/* Allow for rounding */
-	and.l	#0xfffffffc, %d0		/* Whole words */
-
-	add.l	%d0, %a0			/* Copy from end */
-	add.l	%d0, %a1			/* Copy from end */
-	move.l	%a1, _ramstart			/* Set start of ram */
-
-_copy_romfs:
-	move.l	-(%a0), %d0			/* Copy dword */
-	move.l	%d0, -(%a1)
-	cmp.l	%a0, %a2			/* Check if at end */
-	bne	_copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-	lea.l	_ebss, %a1
-	move.l	%a1, _ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-	/*
-	 *	Zero out the bss region.
-	 */
-	lea.l	_sbss, %a0			/* Get start of bss */
-	lea.l	_ebss, %a1			/* Get end of bss */
-	clr.l	%d0				/* Set value */
-_clear_bss:
-	move.l	%d0, (%a0)+			/* Clear each word */
-	cmp.l	%a0, %a1			/* Check if at end */
-	bne	_clear_bss
-
-	/*
-	 *	Load the current task pointer and stack.
-	 */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	/*
-	 *	Assember start up done, start code proper.
-	 */
-	jsr	start_kernel			/* Start Linux kernel */
-
-_exit:
-	jmp	_exit				/* Should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile
--- a/arch/m68knommu/platform/5407/Makefile
+++ b/arch/m68knommu/platform/5407/Makefile
@@ -18,4 +18,3 @@ endif
 
 obj-y := config.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/68328/Makefile b/arch/m68knommu/platform/68328/Makefile
--- a/arch/m68knommu/platform/68328/Makefile
+++ b/arch/m68knommu/platform/68328/Makefile
@@ -2,14 +2,20 @@
 # Makefile for arch/m68knommu/platform/68328.
 #
 
-obj-$(CONFIG_M68328)	+= entry.o ints.o config.o
-obj-$(CONFIG_M68EZ328)	+= entry.o ints.o
-obj-$(CONFIG_M68VZ328)	+= entry.o ints.o
-
-ifeq ($(CONFIG_M68328),y)
-extra-y := $(BOARD)/bootlogo.rh $(BOARD)/crt0_$(MODEL).o
-endif
+head-y			= head-$(MODEL).o
+head-$(CONFIG_PILOT)	= head-pilot.o
+head-$(CONFIG_DRAGEN2)	= head-de2.o
 
-$(obj)/$(BOARD)/bootlogo.rh: $(src)/bootlogo.h
-	perl $(src)/bootlogo.pl < $(src)/bootlogo.h > $(obj)/$(BOARD)/bootlogo.rh
+obj-y			+= entry.o ints.o timers.o
+obj-$(CONFIG_M68328)	+= config.o
 
+extra-y			:= head.o
+extra-$(CONFIG_M68328)	+= bootlogo.rh head.o
+
+$(obj)/bootlogo.rh: $(src)/bootlogo.h
+	perl $(src)/bootlogo.pl < $(src)/bootlogo.h > $(obj)/bootlogo.rh
+
+$(obj)/head.o: $(obj)/$(head-y)
+	ln -sf $(head-y) $(obj)/head.o
+
+clean-files := $(obj)/bootlogo.rh $(obj)/head.o $(head-y)
diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S
new file mode 100644
--- /dev/null
+++ b/arch/m68knommu/platform/68328/head-pilot.S
@@ -0,0 +1,224 @@
+/*
+ * linux/arch/m68knommu/platform/68328/head-rom.S
+ * - A startup file for the MC68328
+ *
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
+ *                     Kenneth Albanowski <kjahds@kjahds.com>,
+ *                     The Silver Hammer Group, Ltd.
+ *
+ * (c) 1995, Dionne & Associates
+ * (c) 1995, DKG Display Tech.
+ */
+
+#define ASSEMBLY
+
+#define IMMED #
+#define	DBG_PUTC(x)	moveb IMMED x, 0xfffff907
+
+#include <linux/config.h>
+
+.global _stext
+.global _start
+
+.global _rambase
+.global __ramvec
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global penguin_bits
+
+#ifdef CONFIG_PILOT
+
+#define IMR 0xFFFFF304
+
+	.data
+	.align 16
+
+penguin_bits:	
+#include "bootlogo.rh"
+
+#endif
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+.text
+	
+_start:
+_stext:
+
+
+#ifdef CONFIG_M68328
+
+#ifdef CONFIG_PILOT
+	.byte 0x4e, 0xfa, 0x00, 0x0a /* Jmp +X bytes */
+	.byte 'b', 'o', 'o', 't'
+	.word 10000
+
+	nop
+#endif
+
+	moveq	#0, %d0
+	movew   %d0, 0xfffff618 /* Watchdog off */
+	movel	#0x00011f07, 0xfffff114 /* CS A1 Mask */
+
+	movew	#0x0800, 0xfffff906 /* Ignore CTS */
+	movew	#0x010b, 0xfffff902 /* BAUD to 9600 */
+
+	movew	#0x2410, 0xfffff200 /* PLLCR */
+	movew	#0x123, 0xfffff202 /* PLLFSR */
+
+#ifdef CONFIG_PILOT
+	moveb	#0, 0xfffffA27 /* LCKCON */
+	movel   #_start, 0xfffffA00 /* LSSA */
+	moveb   #0xa, 0xfffffA05 /* LVPW */
+	movew	#0x9f, 0xFFFFFa08 /* LXMAX */
+	movew	#0x9f, 0xFFFFFa0a /* LYMAX */
+	moveb   #9, 0xfffffa29 /* LBAR */
+	moveb   #0, 0xfffffa25 /* LPXCD */
+	moveb	#0x04, 0xFFFFFa20 /* LPICF */
+	moveb	#0x58, 0xfffffA27 /* LCKCON */
+	moveb	#0x85, 0xfffff429 /* PFDATA */
+	moveb	#0xd8, 0xfffffA27 /* LCKCON */
+	moveb	#0xc5, 0xfffff429 /* PFDATA */
+	moveb	#0xd5, 0xfffff429 /* PFDATA */
+
+	moveal	#0x00100000, %a3
+	moveal	#0x100ffc00, %a4
+#endif /* CONFIG_PILOT */
+
+#endif /* CONFIG_M68328 */
+
+	movew   #0x2700, %sr
+	lea	%a4@(-4), %sp
+
+	DBG_PUTC('\r')
+	DBG_PUTC('\n')
+	DBG_PUTC('A')
+
+   	moveq   #0,%d0
+	movew	#16384, %d0  /* PLL settle wait loop */
+L0:
+	subw	#1, %d0
+	bne	L0
+
+	DBG_PUTC('B')
+
+	/* Copy command line from beginning of RAM (+16) to end of bss */
+	movel	#__ramvec, %d7
+	addl	#16, %d7
+	moveal	%d7, %a0
+	moveal	#_ebss, %a1
+	lea	%a1@(512), %a2
+
+	DBG_PUTC('C')
+
+	/* Copy %a0 to %a1 until %a1 == %a2 */
+L2:
+	movel	%a0@+, %d0
+	movel	%d0, %a1@+
+	cmpal	%a1, %a2
+	bhi	L2
+
+	/* Copy data+init segment from ROM to RAM */
+	moveal	#_etext, %a0
+	moveal	#_sdata, %a1
+	moveal	#__init_end, %a2
+
+	DBG_PUTC('D')
+
+	/* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+	movel	%a0@+, %d0
+	movel	%d0, %a1@+
+	cmpal	%a1, %a2
+	bhi	LD1
+
+	DBG_PUTC('E')
+
+	moveal	#_sbss, %a0
+	moveal	#_ebss, %a1
+
+	/* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+	movel	#0, %a0@+
+	cmpal	%a0, %a1
+	bhi	L1
+
+	DBG_PUTC('F')
+
+	/* Copy command line from end of bss to command line */
+	moveal	#_ebss, %a0
+	moveal	#command_line, %a1
+	lea	%a1@(512), %a2
+
+	DBG_PUTC('G')
+
+	/* Copy %a0 to %a1 until %a1 == %a2 */
+L3:
+	movel	%a0@+, %d0
+	movel	%d0, %a1@+
+	cmpal	%a1, %a2
+	bhi	L3
+
+	movel	#_sdata, %d0	
+	movel	%d0, _rambase	
+	movel	#_ebss,	%d0
+	movel	%d0, _ramstart
+
+	movel	%a4, %d0
+	subl	#4096, %d0	/* Reserve 4K of stack */
+	moveq	#79, %d7
+	movel	%d0, _ramend
+
+	movel	%a3, %d0
+	movel	%d0, rom_length
+
+	pea	0
+	pea	env
+	pea	%sp@(4)
+	pea	0
+
+	DBG_PUTC('H')
+
+#ifdef CONFIG_PILOT
+	movel	#penguin_bits, 0xFFFFFA00
+	moveb	#10, 0xFFFFFA05
+	movew	#160, 0xFFFFFA08
+	movew	#160, 0xFFFFFA0A
+#endif /* CONFIG_PILOT */
+
+	DBG_PUTC('I')
+
+	lea	init_thread_union, %a0
+	lea	0x2000(%a0), %sp
+
+	DBG_PUTC('J')
+	DBG_PUTC('\r')
+	DBG_PUTC('\n')
+
+	jsr	start_kernel
+_exit:
+
+	jmp	_exit
+
+
+	.data
+env:
+	.long	0
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68knommu/platform/68328/head-ram.S
new file mode 100644
--- /dev/null
+++ b/arch/m68knommu/platform/68328/head-ram.S
@@ -0,0 +1,171 @@
+#include <linux/config.h>
+
+	.global __main
+	.global __ram_start
+	.global __ram_end
+	.global __rom_start
+	.global __rom_end
+
+        .global _rambase
+        .global _ramstart
+	
+	.global splash_bits
+	.global _start
+	.global _stext
+
+#define DEBUG
+#define ROM_OFFSET 0x10C00000
+#define STACK_GAURD 0x10
+
+	.text
+	
+_start:
+_stext:
+	movew	#0x2700, %sr            /* Exceptions off! */
+
+#if 0
+	/* Init chip registers.  uCsimm specific */
+	moveb	#0x00,   0xfffffb0b	/* Watchdog off */
+	moveb	#0x10,   0xfffff000	/* SCR */
+
+	movew   #0x2400, 0xfffff200	/* PLLCR */
+	movew   #0x0123, 0xfffff202	/* PLLFSR */
+
+	moveb	#0x00,   0xfffff40b	/* enable chip select */
+	moveb	#0x00,   0xfffff423	/* enable /DWE */
+	moveb	#0x08,   0xfffffd0d	/* disable hardmap */
+	moveb	#0x07,   0xfffffd0e	/* level 7 interrupt clear */
+
+	movew	#0x8600, 0xfffff100	/* FLASH at 0x10c00000 */
+	movew	#0x018b, 0xfffff110	/* 2Meg, enable, 0ws */
+
+	movew	#0x8f00, 0xfffffc00	/* DRAM configuration */
+	movew	#0x9667, 0xfffffc02	/* DRAM control */
+	movew	#0x0000, 0xfffff106	/* DRAM at 0x00000000 */
+	movew	#0x068f, 0xfffff116	/* 8Meg, enable, 0ws */
+
+	moveb	#0x40,   0xfffff300	/* IVR */
+	movel	#0x007FFFFF, %d0	/* IMR */
+	movel	%d0,     0xfffff304
+
+	moveb	0xfffff42b, %d0
+	andb	#0xe0,	 %d0
+	moveb	%d0,	 0xfffff42b
+
+	moveb	#0x08,   0xfffff907	/* Ignore CTS */
+	movew	#0x010b, 0xfffff902	/* BAUD to 9600 */
+	movew	#0xe100, 0xfffff900	/* enable */
+#endif
+
+	movew	#16384, %d0  /* PLL settle wait loop */
+L0:
+	subw	#1, %d0
+	bne	L0
+#ifdef DEBUG
+	moveq	#70, %d7		/* 'F' */
+	moveb	%d7,0xfffff907          /* No absolute addresses */
+pclp1:
+	movew	0xfffff906, %d7
+	andw	#0x2000, %d7
+	beq	pclp1
+#endif /* DEBUG */
+
+#ifdef CONFIG_RELOCATE
+	/* Copy me to RAM */
+	moveal	#__rom_start, %a0
+	moveal	#__ram_start, %a1
+	moveal	#_edata, %a2
+
+	/* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+	movel	%a0@+, %d0
+	movel	%d0, %a1@+
+	cmpal	%a1, %a2
+	bhi	LD1
+	
+#ifdef DEBUG
+	moveq	#74, %d7		/* 'J' */
+	moveb	%d7,0xfffff907          /* No absolute addresses */
+pclp2:
+	movew	0xfffff906, %d7
+	andw	#0x2000, %d7
+	beq	pclp2
+#endif /* DEBUG */
+	/* jump into the RAM copy */
+	jmp     ram_jump
+ram_jump:
+
+#endif /* CONFIG_RELOCATE */
+
+#ifdef DEBUG
+	moveq	#82, %d7		/* 'R' */
+	moveb	%d7,0xfffff907          /* No absolute addresses */
+pclp3:
+	movew	0xfffff906, %d7
+	andw	#0x2000, %d7
+	beq	pclp3
+#endif /* DEBUG */
+	moveal	#0x007ffff0, %ssp
+	moveal	#_sbss, %a0
+	moveal	#_ebss, %a1
+
+	/* Copy 0 to %a0 until %a0 >= %a1 */
+L1:
+	movel	#0, %a0@+
+	cmpal	%a0, %a1
+	bhi	L1
+
+#ifdef DEBUG
+	moveq	#67, %d7                /* 'C' */
+	jsr	putc
+#endif /* DEBUG */
+
+	pea	0
+	pea	env
+	pea	%sp@(4)
+	pea	0
+
+#ifdef DEBUG
+	moveq	#70, %d7		/* 'F' */
+	jsr	putc
+#endif /* DEBUG */
+
+lp:
+	jsr	start_kernel
+        jmp lp
+_exit:
+
+	jmp	_exit
+
+__main:
+	/* nothing */
+	rts
+
+#ifdef DEBUG
+putc:
+	moveb	%d7,0xfffff907
+pclp:
+	movew	0xfffff906, %d7
+	andw	#0x2000, %d7
+	beq	pclp
+	rts
+#endif /* DEBUG */
+
+	.data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+env:
+	.long	0
diff --git a/arch/m68knommu/platform/68328/head-rom.S b/arch/m68knommu/platform/68328/head-rom.S
new file mode 100644
--- /dev/null
+++ b/arch/m68knommu/platform/68328/head-rom.S
@@ -0,0 +1,109 @@
+#include <linux/config.h>
+	
+	.global _start
+	.global _stext
+
+	.global _rambase
+	.global _ramvec
+	.global _ramstart
+	.global _ramend
+
+#ifdef CONFIG_INIT_LCD
+	.global splash_bits
+#endif
+
+	.data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+#ifdef CONFIG_INIT_LCD
+splash_bits:
+#include "bootlogo.rh"
+#endif
+	
+	.text
+_start:
+_stext:	movew	#0x2700,%sr
+#ifdef CONFIG_INIT_LCD
+	movel	#splash_bits, 0xfffffA00 /* LSSA */
+	moveb	#0x28,   0xfffffA05	/* LVPW */
+	movew	#0x280,  0xFFFFFa08	/* LXMAX */
+	movew	#0x1df,  0xFFFFFa0a	/* LYMAX */
+	moveb	#0,      0xfffffa29	/* LBAR */
+	moveb	#0,      0xfffffa25	/* LPXCD */
+	moveb	#0x08,   0xFFFFFa20	/* LPICF */
+	moveb	#0x01,   0xFFFFFA21	/* -ve pol */
+	moveb	#0x81,   0xfffffA27	/* LCKCON */
+	movew	#0xff00, 0xfffff412	/* LCD pins */
+#endif
+	moveal  #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
+	movew	#32767, %d0  /* PLL settle wait loop */
+1:	subq	#1, %d0
+	bne	1b
+
+	/* Copy data segment from ROM to RAM */
+	moveal	#_etext, %a0
+	moveal	#_sdata, %a1
+	moveal	#_edata, %a2
+
+	/* Copy %a0 to %a1 until %a1 == %a2 */
+1:	movel	%a0@+, %a1@+
+	cmpal	%a1, %a2
+	bhi	1b
+
+	moveal	#_sbss, %a0
+	moveal	#_ebss, %a1
+	/* Copy 0 to %a0 until %a0 == %a1 */
+	
+1:
+	clrl	%a0@+
+	cmpal	%a0, %a1
+	bhi	1b
+
+        movel   #_sdata, %d0    
+        movel   %d0,    _rambase        
+        movel   #_ebss,  %d0
+        movel   %d0,    _ramstart
+	movel	#__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0
+	movel	%d0,	_ramend
+	movel	#__ramvec,	%d0
+	movel	%d0,	_ramvec
+	
+/*
+ * load the current task pointer and stack
+ */
+	lea	init_thread_union, %a0
+	lea	0x2000(%a0), %sp
+
+1:	jsr	start_kernel
+        bra 1b
+_exit:
+
+	jmp	_exit
+
+
+putc:
+	moveb	%d7,0xfffff907
+1:
+	movew	0xfffff906, %d7
+	andw	#0x2000, %d7
+	beq	1b
+	rts
+
+	.data
+env:
+	.long	0
+	.text
+
diff --git a/arch/m68knommu/platform/68328/pilot/crt0_rom.S b/arch/m68knommu/platform/68328/pilot/crt0_rom.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68328/pilot/crt0_rom.S
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * linux/arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * - A startup file for the MC68332 
- *
- * Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
- *                     Kenneth Albanowski <kjahds@kjahds.com>,
- *                     The Silver Hammer Group, Ltd.
- *
- * (c) 1995, Dionne & Associates
- * (c) 1995, DKG Display Tech.
- */
-
-#define ASSEMBLY
-
-#define IMMED #
-#define	DBG_PUTC(x)	moveb IMMED x, 0xfffff907
-
-#include <linux/config.h>
-
-.global _stext
-.global _start
-
-.global _rambase
-.global __ramvec
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global penguin_bits
-
-#ifdef CONFIG_PILOT
-
-#define IMR 0xFFFFF304
-
-	.data
-	.align 16
-
-penguin_bits:	
-#include "bootlogo.rh"
-
-#endif
-
-/*****************************************************************************/
-
-.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-.text
-	
-_start:
-_stext:
-
-
-#ifdef CONFIG_M68328
-
-#ifdef CONFIG_PILOT
-	.byte 0x4e, 0xfa, 0x00, 0x0a /* Jmp +X bytes */
-	.byte 'b', 'o', 'o', 't'
-	.word 10000
-
-	nop
-#endif
-
-	moveq	#0, %d0
-	movew   %d0, 0xfffff618 /* Watchdog off */
-	movel	#0x00011f07, 0xfffff114 /* CS A1 Mask */
-
-	movew	#0x0800, 0xfffff906 /* Ignore CTS */
-	movew	#0x010b, 0xfffff902 /* BAUD to 9600 */
-
-	movew	#0x2410, 0xfffff200 /* PLLCR */
-	movew	#0x123, 0xfffff202 /* PLLFSR */
-
-#ifdef CONFIG_PILOT
-	moveb	#0, 0xfffffA27 /* LCKCON */
-	movel   #_start, 0xfffffA00 /* LSSA */
-	moveb   #0xa, 0xfffffA05 /* LVPW */
-	movew	#0x9f, 0xFFFFFa08 /* LXMAX */
-	movew	#0x9f, 0xFFFFFa0a /* LYMAX */
-	moveb   #9, 0xfffffa29 /* LBAR */
-	moveb   #0, 0xfffffa25 /* LPXCD */
-	moveb	#0x04, 0xFFFFFa20 /* LPICF */
-	moveb	#0x58, 0xfffffA27 /* LCKCON */
-	moveb	#0x85, 0xfffff429 /* PFDATA */
-	moveb	#0xd8, 0xfffffA27 /* LCKCON */
-	moveb	#0xc5, 0xfffff429 /* PFDATA */
-	moveb	#0xd5, 0xfffff429 /* PFDATA */
-
-	moveal	#0x00100000, %a3
-	moveal	#0x100ffc00, %a4
-#endif /* CONFIG_PILOT */
-
-#endif /* CONFIG_M68328 */
-
-	movew   #0x2700, %sr
-	lea	%a4@(-4), %sp
-
-	DBG_PUTC('\r')
-	DBG_PUTC('\n')
-	DBG_PUTC('A')
-
-   	moveq   #0,%d0
-	movew	#16384, %d0  /* PLL settle wait loop */
-L0:
-	subw	#1, %d0
-	bne	L0
-
-	DBG_PUTC('B')
-
-	/* Copy command line from beginning of RAM (+16) to end of bss */
-	movel	#__ramvec, %d7
-	addl	#16, %d7
-	moveal	%d7, %a0
-	moveal	#_ebss, %a1
-	lea	%a1@(512), %a2
-
-	DBG_PUTC('C')
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-L2:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	L2
-
-	/* Copy data+init segment from ROM to RAM */
-	moveal	#_etext, %a0
-	moveal	#_sdata, %a1
-	moveal	#__init_end, %a2
-
-	DBG_PUTC('D')
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	LD1
-
-	DBG_PUTC('E')
-
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	L1
-
-	DBG_PUTC('F')
-
-	/* Copy command line from end of bss to command line */
-	moveal	#_ebss, %a0
-	moveal	#command_line, %a1
-	lea	%a1@(512), %a2
-
-	DBG_PUTC('G')
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-L3:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	L3
-
-	movel	#_sdata, %d0	
-	movel	%d0, _rambase	
-	movel	#_ebss,	%d0
-	movel	%d0, _ramstart
-
-	movel	%a4, %d0
-	subl	#4096, %d0	/* Reserve 4K of stack */
-	moveq	#79, %d7
-	movel	%d0, _ramend
-
-	movel	%a3, %d0
-	movel	%d0, rom_length
-
-	pea	0
-	pea	env
-	pea	%sp@(4)
-	pea	0
-
-	DBG_PUTC('H')
-
-#ifdef CONFIG_PILOT
-	movel	#penguin_bits, 0xFFFFFA00
-	moveb	#10, 0xFFFFFA05
-	movew	#160, 0xFFFFFA08
-	movew	#160, 0xFFFFFA0A
-#endif /* CONFIG_PILOT */
-
-	DBG_PUTC('I')
-
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	DBG_PUTC('J')
-	DBG_PUTC('\r')
-	DBG_PUTC('\n')
-
-	jsr	start_kernel
-_exit:
-
-	jmp	_exit
-
-
-	.data
-env:
-	.long	0
diff --git a/arch/m68knommu/platform/68360/Makefile b/arch/m68knommu/platform/68360/Makefile
--- a/arch/m68knommu/platform/68360/Makefile
+++ b/arch/m68knommu/platform/68360/Makefile
@@ -4,4 +4,7 @@
 
 obj-y := config.o commproc.o entry.o ints.o
 
-extra-y := $(BOARD)/crt0_$(MODEL).o
+extra-y := head.o
+
+$(obj)/head.o: $(obj)/head-$(MODEL).o
+	ln -sf head-$(MODEL).o $(obj)/head.o
diff --git a/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S b/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S
+++ /dev/null
@@ -1,408 +0,0 @@
-/* arch/m68knommu/platform/68360/uCquicc/crt0_rom.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-#define ASSEMBLY
-#include <linux/config.h>
-
-.global _stext
-.global _start
-
-.global _rambase
-.global __ramvec
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000002
-#define SIM_BR0_MASK                0x00000001
-
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-	
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-	.text
-_start:
-_stext:
-	nop
-	ori.w	#MCU_DISABLE_INTRPTS, %sr	/* disable interrupts: */
-	/* We should not need to setup the boot stack the reset should do it. */
-	movea.l	#__ramend, %sp			/*set up stack at the end of DRAM:*/
-
-set_mbar_register:
-	moveq.l	#0x07, %d1			/* Setup MBAR */
-	movec	%d1, %dfc
-
-	lea.l	MCU_SIM_MBAR_ADRS, %a0
-	move.l	#_dprbase, %d0
-	andi.l	#MCU_SIM_MBAR_BA_MASK, %d0
-	ori.l	#MCU_SIM_MBAR_AS_MASK, %d0
-	moves.l	%d0, %a0@
-
-	moveq.l	#0x05, %d1
-	movec.l	%d1, %dfc
-
-	/* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-	/* Set Module Configuration Register */
-	move.l	#MCU_SIM_MCR, MCR
-
-	/* to do:	Determine cause of reset */
-
-	/*
-	 *       configure system clock MC68360 p. 6-40
-	 *       (value +1)*osc/128 = system clock
-	 */
-set_sim_clock:
-	move.w	#MCU_SIM_PLLCR, PLLCR
-	move.b	#MCU_SIM_CLKOCR, CLKOCR
-	move.w	#MCU_SIM_CDVCR, CDVCR
-
-	/* Wait for the PLL to settle */
-	move.w	#16384, %d0
-pll_settle_wait:
-	subi.w	#1, %d0
-	bne	pll_settle_wait
-
-	/* Setup the system protection register, and watchdog timer register */
-	move.b	#MCU_SIM_SWIV, SWIV
-	move.w	#MCU_SIM_PICR, PICR
-	move.w	#MCU_SIM_PITR, PITR
-	move.w	#MCU_SIM_SYPCR, SYPCR
-
-	/* Clear DPRAM - system + parameter */
-	movea.l	#_dprbase, %a0
-	movea.l	#_dprbase+0x2000, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	clear_dpram
-
-configure_memory_controller:    
-	/* Set up Global Memory Register (GMR) */
-	move.l	#MCU_SIM_GMR, %d0
-	move.l	%d0, GMR
-
-configure_chip_select_0:
-	move.l	#__ramend, %d0
-	subi.l	#__ramstart, %d0
-	subq.l	#0x01, %d0
-	eori.l	#SIM_OR_MASK, %d0
-	ori.l	#SIM_OR0_MASK, %d0
-	move.l	%d0, OR0
-
-	move.l	#__ramstart, %d0
-	ori.l	#SIM_BR0_MASK, %d0
-	move.l	%d0, BR0
-
-configure_chip_select_1:
-	move.l	#__rom_end, %d0
-	subi.l	#__rom_start, %d0
-	subq.l	#0x01, %d0
-	eori.l	#SIM_OR_MASK, %d0
-	ori.l	#SIM_OR1_MASK, %d0
-	move.l	%d0, OR1
-
-	move.l	#__rom_start, %d0
-	ori.l	#SIM_BR1_MASK, %d0
-	move.l	%d0, BR1
-
-	move.w	#MCU_SIM_PEPAR, PEPAR 
-
-	/* point to vector table: */
-	move.l	#_romvec, %a0
-	move.l	#_ramvec, %a1
-copy_vectors:
-	move.l	%a0@, %d0
-	move.l	%d0, %a1@
-	move.l	%a0@, %a1@
-	addq.l	#0x04, %a0
-	addq.l	#0x04, %a1
-	cmp.l	#_start, %a0
-	blt	copy_vectors
-
-	move.l	#_ramvec, %a1
-	movec	%a1, %vbr
-
-
-	/* Copy data segment from ROM to RAM */
-	moveal	#_stext, %a0
-	moveal	#_sdata, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	move.l	%a0@, %d0
-	addq.l	#0x04, %a0
-	move.l	%d0, %a1@
-	addq.l	#0x04, %a1
-	cmp.l	#_edata, %a1
-	blt     LD1
-
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	L1
-
-load_quicc:
-	move.l	#_dprbase, _quicc_base
-
-store_ram_size:
-	/* Set ram size information */
-	move.l	#_sdata, _rambase
-	move.l	#_ebss, _ramstart
-	move.l	#__ramend, %d0
-	sub.l	#0x1000, %d0			/* Reserve 4K for stack space.*/
-	move.l	%d0, _ramend			/* Different from __ramend.*/
-
-store_flash_size:
-	/* Set rom size information */
-	move.l	#__rom_end, %d0
-	sub.l	#__rom_start, %d0
-	move.l	%d0, rom_length
-    
-	pea	0
-	pea	env
-	pea	%sp@(4)
-	pea	0
-
-	lea	init_thread_union, %a2
-	lea	0x2000(%a2), %sp
-
-lp:
-	jsr	start_kernel
-
-_exit:
-	jmp	_exit
-
-
-	.data
-	.align 4
-env:
-	.long	0
-_quicc_base:
-	.long	0
-_periph_base:
-	.long	0
-_ramvec:
-	.long   0
-_rambase:
-	.long   0
-_ramstart:
-	.long   0
-_ramend:
-	.long   0
-_dprbase:
-	.long	0xffffe000
-
-	.text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
- 
-.section ".data.initvect","awx"
-    .long   __ramend	/* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S b/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S
+++ /dev/null
@@ -1,420 +0,0 @@
-/* arch/m68knommu/platform/68360/uCquicc/crt0_rom.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-#include <linux/config.h>
-
-.global _stext
-.global _sbss
-.global _start
-
-.global _rambase
-.global __ramvec
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-
-#define OR2                         (_dprbase + REGB + 0x0074)
-#define BR2                         (_dprbase + REGB + 0x0070)
-
-#define OR3                         (_dprbase + REGB + 0x0084)
-#define BR3                         (_dprbase + REGB + 0x0080)
-
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-
-#define OR5                         (_dprbase + REGB + 0x00A4)
-#define BR5                         (_dprbase + REGB + 0x00A0)
-
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000000
-#define SIM_BR0_MASK                0x00000001
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-	
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-	.text
-_start:
-_stext:
-	nop
-	ori.w	#MCU_DISABLE_INTRPTS, %sr	/* disable interrupts: */
-	/* We should not need to setup the boot stack the reset should do it. */
-	movea.l	#__ramend, %sp		/* set up stack at the end of DRAM:*/
-
-
-set_mbar_register:
-	moveq.l	#0x07, %d1			/* Setup MBAR */
-	movec	%d1, %dfc
-
-	lea.l	MCU_SIM_MBAR_ADRS, %a0
-	move.l	#_dprbase, %d0
-	andi.l	#MCU_SIM_MBAR_BA_MASK, %d0
-	ori.l	#MCU_SIM_MBAR_AS_MASK, %d0
-	moves.l	%d0, %a0@
-
-	moveq.l	#0x05, %d1
-	movec.l	%d1, %dfc
-
-	/* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-	/* Set Module Configuration Register */
-	move.l	#MCU_SIM_MCR, MCR
-
-	/* to do:	Determine cause of reset */
-
-	/*
-	 *	configure system clock MC68360 p. 6-40
-	 *	(value +1)*osc/128 = system clock
-	 *                    or
-	 *	(value + 1)*osc = system clock
-	 *	You do not need to divide the oscillator by 128 unless you want to.
-	 */
-set_sim_clock:
-	move.w	#MCU_SIM_PLLCR, PLLCR
-	move.b	#MCU_SIM_CLKOCR, CLKOCR
-	move.w	#MCU_SIM_CDVCR, CDVCR
-
-	/* Wait for the PLL to settle */
-	move.w	#16384, %d0
-pll_settle_wait:
-	subi.w	#1, %d0
-	bne	pll_settle_wait
-
-	/* Setup the system protection register, and watchdog timer register */
-	move.b	#MCU_SIM_SWIV, SWIV
-	move.w	#MCU_SIM_PICR, PICR
-	move.w	#MCU_SIM_PITR, PITR
-	move.w	#MCU_SIM_SYPCR, SYPCR
-
-	/* Clear DPRAM - system + parameter */
-	movea.l	#_dprbase, %a0
-	movea.l	#_dprbase+0x2000, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	clear_dpram
-
-configure_memory_controller:    
-	/* Set up Global Memory Register (GMR) */
-	move.l	#MCU_SIM_GMR, %d0
-	move.l	%d0, GMR
-
-configure_chip_select_0:
-	move.l	#0x00400000, %d0
-	subq.l	#0x01, %d0
-	eori.l	#SIM_OR_MASK, %d0
-	ori.l	#SIM_OR0_MASK, %d0
-	move.l	%d0, OR0
-
-	move.l	#__rom_start, %d0
-	ori.l	#SIM_BR0_MASK, %d0
-	move.l	%d0, BR0
-
-	move.l	#0x0, BR1
-	move.l	#0x0, BR2
-	move.l	#0x0, BR3
-	move.l	#0x0, BR4
-	move.l	#0x0, BR5
-	move.l	#0x0, BR6
-	move.l	#0x0, BR7
-
-	move.w	#MCU_SIM_PEPAR, PEPAR 
-
-	/* point to vector table: */
-	move.l	#_romvec, %a0
-	move.l	#_ramvec, %a1
-copy_vectors:
-	move.l	%a0@, %d0
-	move.l	%d0, %a1@
-	move.l	%a0@, %a1@
-	addq.l	#0x04, %a0
-	addq.l	#0x04, %a1
-	cmp.l	#_start, %a0
-	blt	copy_vectors
-
-	move.l	#_ramvec, %a1
-	movec	%a1, %vbr
-
-
-	/* Copy data segment from ROM to RAM */
-	moveal	#_etext, %a0
-	moveal	#_sdata, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	move.l	%a0@, %d0
-	addq.l	#0x04, %a0
-	move.l	%d0, %a1@
-	addq.l	#0x04, %a1
-	cmp.l	#_edata, %a1
-	blt	LD1
-
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	L1
-
-load_quicc:
-	move.l	#_dprbase, _quicc_base
-
-store_ram_size:
-	/* Set ram size information */
-	move.l	#_sdata, _rambase
-	move.l	#_ebss, _ramstart
-	move.l	#__ramend, %d0
-	sub.l	#0x1000, %d0			/* Reserve 4K for stack space.*/
-	move.l	%d0, _ramend			/* Different from __ramend.*/
-
-store_flash_size:
-	/* Set rom size information */
-	move.l	#__rom_end, %d0
-	sub.l	#__rom_start, %d0
-	move.l	%d0, rom_length
-    
-	pea	0
-	pea	env
-	pea	%sp@(4)
-	pea	0
-
-	lea	init_thread_union, %a2
-	lea	0x2000(%a2), %sp
-
-lp:
-	jsr	start_kernel
-
-_exit:
-	jmp	_exit
-
-
-	.data
-	.align 4
-env:
-	.long	0
-_quicc_base:
-	.long	0
-_periph_base:
-	.long	0
-_ramvec:
-	.long   0
-_rambase:
-	.long   0
-_ramstart:
-	.long   0
-_ramend:
-	.long   0
-_dprbase:
-	.long	0xffffe000
-
-
-	.text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
- 
-.section ".data.initvect","awx"
-    .long   __ramend	/* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68knommu/platform/68EZ328/Makefile b/arch/m68knommu/platform/68EZ328/Makefile
--- a/arch/m68knommu/platform/68EZ328/Makefile
+++ b/arch/m68knommu/platform/68EZ328/Makefile
@@ -4,9 +4,8 @@
 
 obj-y := config.o
 
-extra-y := $(BOARD)/bootlogo.rh $(BOARD)/crt0_$(MODEL).o
+extra-y := bootlogo.rh
 
-$(obj)/$(BOARD)/bootlogo.rh: $(src)/bootlogo.h
+$(obj)/bootlogo.rh: $(src)/bootlogo.h
 	perl $(src)/../68328/bootlogo.pl < $(src)/bootlogo.h \
-		> $(obj)/$(BOARD)/bootlogo.rh
-
+		> $(obj)/bootlogo.rh
diff --git a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <linux/config.h>
-	
-	.global _start
-	.global _stext
-
-	.global _rambase
-	.global _ramvec
-	.global _ramstart
-	.global _ramend
-
-#ifdef CONFIG_INIT_LCD
-	.global splash_bits
-#endif
-
-	.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-#ifdef CONFIG_INIT_LCD
-splash_bits:
-#include "bootlogo.rh"
-#endif
-	
-	.text
-_start:
-_stext:	movew	#0x2700,%sr
-#ifdef CONFIG_INIT_LCD
-	movel	#splash_bits, 0xfffffA00 /* LSSA */
-	moveb	#0x28,   0xfffffA05	/* LVPW */
-	movew	#0x280,  0xFFFFFa08	/* LXMAX */
-	movew	#0x1df,  0xFFFFFa0a	/* LYMAX */
-	moveb	#0,      0xfffffa29	/* LBAR */
-	moveb	#0,      0xfffffa25	/* LPXCD */
-	moveb	#0x08,   0xFFFFFa20	/* LPICF */
-	moveb	#0x01,   0xFFFFFA21	/* -ve pol */
-	moveb	#0x81,   0xfffffA27	/* LCKCON */
-	movew	#0xff00, 0xfffff412	/* LCD pins */
-#endif
-	moveal  #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
-	movew	#32767, %d0  /* PLL settle wait loop */
-1:	subq	#1, %d0
-	bne	1b
-
-	/* Copy data segment from ROM to RAM */
-	moveal	#_etext, %a0
-	moveal	#_sdata, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-1:	movel	%a0@+, %a1@+
-	cmpal	%a1, %a2
-	bhi	1b
-
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-	/* Copy 0 to %a0 until %a0 == %a1 */
-	
-1:
-	clrl	%a0@+
-	cmpal	%a0, %a1
-	bhi	1b
-
-        movel   #_sdata, %d0    
-        movel   %d0,    _rambase        
-        movel   #_ebss,  %d0
-        movel   %d0,    _ramstart
-	movel	#__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0
-	movel	%d0,	_ramend
-	movel	#__ramvec,	%d0
-	movel	%d0,	_ramvec
-	
-/*
- * load the current task pointer and stack
- */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-1:	jsr	start_kernel
-        bra 1b
-_exit:
-
-	jmp	_exit
-
-
-putc:
-	moveb	%d7,0xfffff907
-1:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	1b
-	rts
-
-	.data
-env:
-	.long	0
-	.text
-
diff --git a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "crt0_fixed.S"
diff --git a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S
+++ /dev/null
@@ -1,167 +0,0 @@
-	.global __main
-	.global __ram_start
-	.global __ram_end
-	.global __rom_start
-	.global __rom_end
-
-        .global _rambase
-        .global _ramstart
-	
-	.global splash_bits
-	.global _start
-	.global _stext
-
-#define DEBUG
-#define ROM_OFFSET 0x10C00000
-#define STACK_GAURD 0x10
-
-	.text
-	
-_start:
-_stext:
-	movew	#0x2700, %sr            /* Exceptions off! */
-
-	/* Init chip registers.  uCsimm specific */
-	moveb	#0x00,   0xfffffb0b	/* Watchdog off */
-	moveb	#0x10,   0xfffff000	/* SCR */
-
-	movew   #0x2400, 0xfffff200	/* PLLCR */
-	movew   #0x0123, 0xfffff202	/* PLLFSR */
-
-	moveb	#0x00,   0xfffff40b	/* enable chip select */
-	moveb	#0x00,   0xfffff423	/* enable /DWE */
-	moveb	#0x08,   0xfffffd0d	/* disable hardmap */
-	moveb	#0x07,   0xfffffd0e	/* level 7 interrupt clear */
-
-	movew	#0x8600, 0xfffff100	/* FLASH at 0x10c00000 */
-	movew	#0x018b, 0xfffff110	/* 2Meg, enable, 0ws */
-
-	movew	#0x8f00, 0xfffffc00	/* DRAM configuration */
-	movew	#0x9667, 0xfffffc02	/* DRAM control */
-	movew	#0x0000, 0xfffff106	/* DRAM at 0x00000000 */
-	movew	#0x068f, 0xfffff116	/* 8Meg, enable, 0ws */
-
-	moveb	#0x40,   0xfffff300	/* IVR */
-	movel	#0x007FFFFF, %d0	/* IMR */
-	movel	%d0,     0xfffff304
-
-	moveb	0xfffff42b, %d0
-	andb	#0xe0,	 %d0
-	moveb	%d0,	 0xfffff42b
-
-	moveb	#0x08,   0xfffff907	/* Ignore CTS */
-	movew	#0x010b, 0xfffff902	/* BAUD to 9600 */
-	movew	#0xe100, 0xfffff900	/* enable */
-
-	movew	#16384, %d0  /* PLL settle wait loop */
-L0:
-	subw	#1, %d0
-	bne	L0
-#ifdef DEBUG
-	moveq	#70, %d7		/* 'F' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp1:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp1
-#endif /* DEBUG */
-
-#ifdef CONFIG_RELOCATE
-	/* Copy me to RAM */
-	moveal	#__rom_start, %a0
-	moveal	#__ram_start, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	LD1
-	
-#ifdef DEBUG
-	moveq	#74, %d7		/* 'J' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp2:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp2
-#endif /* DEBUG */
-	/* jump into the RAM copy */
-	jmp     ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
-#ifdef DEBUG
-	moveq	#82, %d7		/* 'R' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp3:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp3
-#endif /* DEBUG */
-	moveal	#0x007ffff0, %ssp
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 >= %a1 */
-L1:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	L1
-
-#ifdef DEBUG
-	moveq	#67, %d7                /* 'C' */
-	jsr	putc
-#endif /* DEBUG */
-
-	pea	0
-	pea	env
-	pea	%sp@(4)
-	pea	0
-
-#ifdef DEBUG
-	moveq	#70, %d7		/* 'F' */
-	jsr	putc
-#endif /* DEBUG */
-
-lp:
-	jsr	start_kernel
-        jmp lp
-_exit:
-
-	jmp	_exit
-
-__main:
-	/* nothing */
-	rts
-
-#ifdef DEBUG
-putc:
-	moveb	%d7,0xfffff907
-pclp:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp
-	rts
-#endif /* DEBUG */
-
-	.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-env:
-	.long	0
diff --git a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "crt0_fixed.S"
diff --git a/arch/m68knommu/platform/68VZ328/Makefile b/arch/m68knommu/platform/68VZ328/Makefile
--- a/arch/m68knommu/platform/68VZ328/Makefile
+++ b/arch/m68knommu/platform/68VZ328/Makefile
@@ -2,5 +2,15 @@
 # Makefile for arch/m68knommu/platform/68VZ328.
 #
 
-obj-y := $(BOARD)/
+obj-y		:= config.o
+logo-$(UCDIMM)	:= bootlogo.rh
+logo-$(DRAGEN2)	:= screen.h
+extra-y		:= $(logo-y)
 
+$(obj)/bootlogo.rh: $(src)/../68EZ328/bootlogo.h
+	perl $(src)/bootlogo.pl < $(src)/../68328/bootlogo.h > $(obj)/bootlogo.rh
+
+$(obj)/screen.h: $(src)/screen.xbm $(src)/xbm2lcd.pl
+	perl $(src)/xbm2lcd.pl < $(src)/screen.xbm > $(obj)/screen.h
+
+clean-files := $(obj)/screen.h $(obj)/bootlogo.rh
diff --git a/arch/m68knommu/platform/68VZ328/de2/Makefile b/arch/m68knommu/platform/68VZ328/de2/Makefile
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/de2/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68VZ328/de2.
-#
-
-obj-y := config.o
-
-EXTRA_TARGETS := bootlogo.rh crt0_$(MODEL).o
-
-$(obj)/bootlogo.rh: $(src)/../../68EZ328/bootlogo.h
-	perl $(src)/../../68328/bootlogo.pl < $(src)/../../68EZ328/bootlogo.h \
-		> $(obj)/bootlogo.rh
-
diff --git a/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S b/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S
+++ /dev/null
@@ -1,135 +0,0 @@
-#include <linux/config.h>
-
-#if defined(CONFIG_RAM32MB)
-#define	MEM_END	0x02000000	/* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define	MEM_END	0x01000000	/* Memory size 16Mb */
-#else
-#define	MEM_END	0x00800000	/* Memory size 8Mb */
-#endif
-
-#undef CRT_DEBUG
-
-.macro	PUTC CHAR
-#ifdef CRT_DEBUG
-	moveq	#\CHAR, %d7
-	jsr	putc
-#endif
-.endm
-
-	.global	_start
-	.global _rambase
-	.global _ramvec
-	.global	_ramstart
-	.global	_ramend
-	
-	.data
-
-/*
- *	Set up the usable of RAM stuff
- */
-_rambase:
-	.long	0
-_ramvec:
-	.long	0
-_ramstart:
-	.long	0
-_ramend:
-	.long	0
-
-	.text
-
-_start:
-
-/*
- * Setup initial stack
- */
-	/* disable all interrupts */
-	movew	#0x2700, %sr
-	movel	#-1, 0xfffff304
-	movel	#MEM_END-4, %sp
-
-	PUTC	'\r'
-	PUTC	'\n'
-	PUTC	'A'
-	PUTC	'B'
-
-/*
- *	Determine end of RAM
- */
-
-	movel	#MEM_END, %a0
-	movel	%a0, _ramend
-
-	PUTC	'C'
-
-/*
- *	Move ROM filesystem above bss :-)
- */
-
-	moveal	#_sbss, %a0			/* romfs at the start of bss */
-	moveal	#_ebss, %a1			/* Set up destination  */
-	movel	%a0, %a2			/* Copy of bss start */
-
-	movel	8(%a0), %d1			/* Get size of ROMFS */
-	addql	#8, %d1				/* Allow for rounding */
-	andl	#0xfffffffc, %d1	/* Whole words */
-
-	addl	%d1, %a0			/* Copy from end */
-	addl	%d1, %a1			/* Copy from end */
-	movel	%a1, _ramstart		/* Set start of ram */
-
-1:
-	movel	-(%a0), %d0			/* Copy dword */
-	movel	%d0, -(%a1)
-	cmpl	%a0, %a2			/* Check if at end */
-	bne	1b
-
-	PUTC	'D'
-
-/*
- * Initialize BSS segment to 0
- */
-
-	lea	_sbss, %a0
-	lea	_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 == %a1 */
-2:	cmpal	%a0, %a1
-	beq	1f
-	clrl	(%a0)+
-	bra	2b
-1:
-
-	PUTC	'E'
-
-/*
- * Load the current task pointer and stack
- */
-
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-	PUTC	'F'
-	PUTC	'\r'
-	PUTC	'\n'
-
-/*
- * Go
- */
-
-	jmp	start_kernel
-
-/*
- * Local functions
- */
- 
-#ifdef CRT_DEBUG
-putc:
-	moveb	%d7, 0xfffff907
-1:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	1b
-	rts
-#endif
diff --git a/arch/m68knommu/platform/68VZ328/ucdimm/Makefile b/arch/m68knommu/platform/68VZ328/ucdimm/Makefile
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/ucdimm/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68VZ328/ucdimm.
-#
-
-obj-y := config.o
-
-EXTRA_TARGETS := bootlogo.rh crt0_$(MODEL).o
-
-$(obj)/bootlogo.rh: $(src)/../../68EZ328/bootlogo.h
-	perl $(src)/../../68328/bootlogo.pl < $(src)/../../68EZ328/bootlogo.h \
-		> $(obj)/bootlogo.rh
-
diff --git a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <linux/config.h>
-	
-	.global _start
-	.global _stext
-
-	.global _rambase
-	.global _ramvec
-	.global _ramstart
-	.global _ramend
-
-#ifdef CONFIG_INIT_LCD
-	.global splash_bits
-#endif
-
-	.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-#ifdef CONFIG_INIT_LCD
-splash_bits:
-#include "bootlogo.rh"
-#endif
-	
-	.text
-_start:
-_stext:	movew	#0x2700,%sr
-#ifdef CONFIG_INIT_LCD
-	movel	#splash_bits, 0xfffffA00 /* LSSA */
-	moveb	#0x28,   0xfffffA05	/* LVPW */
-	movew	#0x280,  0xFFFFFa08	/* LXMAX */
-	movew	#0x1df,  0xFFFFFa0a	/* LYMAX */
-	moveb	#0,      0xfffffa29	/* LBAR */
-	moveb	#0,      0xfffffa25	/* LPXCD */
-	moveb	#0x08,   0xFFFFFa20	/* LPICF */
-	moveb	#0x01,   0xFFFFFA21	/* -ve pol */
-	moveb	#0x81,   0xfffffA27	/* LCKCON */
-	movew	#0xff00, 0xfffff412	/* LCD pins */
-#endif
-	moveal  #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
-	movew	#32767, %d0  /* PLL settle wait loop */
-1:	subq	#1, %d0
-	bne	1b
-
-	/* Copy data segment from ROM to RAM */
-	moveal	#_etext, %a0
-	moveal	#_sdata, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-1:	movel	%a0@+, %a1@+
-	cmpal	%a1, %a2
-	bhi	1b
-
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-	/* Copy 0 to %a0 until %a0 == %a1 */
-	
-1:
-	clrl	%a0@+
-	cmpal	%a0, %a1
-	bhi	1b
-
-        movel   #_sdata, %d0    
-        movel   %d0,    _rambase        
-        movel   #_ebss,  %d0
-        movel   %d0,    _ramstart
-	movel	#__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0
-	movel	%d0,	_ramend
-	movel	#__ramvec,	%d0
-	movel	%d0,	_ramvec
-	
-/*
- * load the current task pointer and stack
- */
-	lea	init_thread_union, %a0
-	lea	0x2000(%a0), %sp
-
-1:	jsr	start_kernel
-        bra 1b
-_exit:
-
-	jmp	_exit
-
-
-putc:
-	moveb	%d7,0xfffff907
-1:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	1b
-	rts
-
-	.data
-env:
-	.long	0
-	.text
-
diff --git a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "crt0_fixed.S"
diff --git a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S
+++ /dev/null
@@ -1,171 +0,0 @@
-#include <linux/config.h>
-
-	.global __main
-	.global __ram_start
-	.global __ram_end
-	.global __rom_start
-	.global __rom_end
-
-        .global _rambase
-        .global _ramstart
-	
-	.global splash_bits
-	.global _start
-	.global _stext
-
-#define DEBUG
-#define ROM_OFFSET 0x10C00000
-#define STACK_GAURD 0x10
-
-	.text
-	
-_start:
-_stext:
-	movew	#0x2700, %sr            /* Exceptions off! */
-
-#if 0
-	/* Init chip registers.  uCsimm specific */
-	moveb	#0x00,   0xfffffb0b	/* Watchdog off */
-	moveb	#0x10,   0xfffff000	/* SCR */
-
-	movew   #0x2400, 0xfffff200	/* PLLCR */
-	movew   #0x0123, 0xfffff202	/* PLLFSR */
-
-	moveb	#0x00,   0xfffff40b	/* enable chip select */
-	moveb	#0x00,   0xfffff423	/* enable /DWE */
-	moveb	#0x08,   0xfffffd0d	/* disable hardmap */
-	moveb	#0x07,   0xfffffd0e	/* level 7 interrupt clear */
-
-	movew	#0x8600, 0xfffff100	/* FLASH at 0x10c00000 */
-	movew	#0x018b, 0xfffff110	/* 2Meg, enable, 0ws */
-
-	movew	#0x8f00, 0xfffffc00	/* DRAM configuration */
-	movew	#0x9667, 0xfffffc02	/* DRAM control */
-	movew	#0x0000, 0xfffff106	/* DRAM at 0x00000000 */
-	movew	#0x068f, 0xfffff116	/* 8Meg, enable, 0ws */
-
-	moveb	#0x40,   0xfffff300	/* IVR */
-	movel	#0x007FFFFF, %d0	/* IMR */
-	movel	%d0,     0xfffff304
-
-	moveb	0xfffff42b, %d0
-	andb	#0xe0,	 %d0
-	moveb	%d0,	 0xfffff42b
-
-	moveb	#0x08,   0xfffff907	/* Ignore CTS */
-	movew	#0x010b, 0xfffff902	/* BAUD to 9600 */
-	movew	#0xe100, 0xfffff900	/* enable */
-#endif
-
-	movew	#16384, %d0  /* PLL settle wait loop */
-L0:
-	subw	#1, %d0
-	bne	L0
-#ifdef DEBUG
-	moveq	#70, %d7		/* 'F' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp1:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp1
-#endif /* DEBUG */
-
-#ifdef CONFIG_RELOCATE
-	/* Copy me to RAM */
-	moveal	#__rom_start, %a0
-	moveal	#__ram_start, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	LD1
-	
-#ifdef DEBUG
-	moveq	#74, %d7		/* 'J' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp2:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp2
-#endif /* DEBUG */
-	/* jump into the RAM copy */
-	jmp     ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
-#ifdef DEBUG
-	moveq	#82, %d7		/* 'R' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp3:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp3
-#endif /* DEBUG */
-	moveal	#0x007ffff0, %ssp
-	moveal	#_sbss, %a0
-	moveal	#_ebss, %a1
-
-	/* Copy 0 to %a0 until %a0 >= %a1 */
-L1:
-	movel	#0, %a0@+
-	cmpal	%a0, %a1
-	bhi	L1
-
-#ifdef DEBUG
-	moveq	#67, %d7                /* 'C' */
-	jsr	putc
-#endif /* DEBUG */
-
-	pea	0
-	pea	env
-	pea	%sp@(4)
-	pea	0
-
-#ifdef DEBUG
-	moveq	#70, %d7		/* 'F' */
-	jsr	putc
-#endif /* DEBUG */
-
-lp:
-	jsr	start_kernel
-        jmp lp
-_exit:
-
-	jmp	_exit
-
-__main:
-	/* nothing */
-	rts
-
-#ifdef DEBUG
-putc:
-	moveb	%d7,0xfffff907
-pclp:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp
-	rts
-#endif /* DEBUG */
-
-	.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-env:
-	.long	0
diff --git a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S
deleted file mode 100644
--- a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "crt0_fixed.S"
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -122,10 +122,6 @@ config TANBAC_TB0229
 	  The TANBAC TB0229 (VR4131DIMM) is a MIPS-based platform manufactured by TANBAC.
 	  Please refer to <http://www.tanbac.co.jp/> about VR4131DIMM.
 
-config TANBAC_TB0219
-	bool "Added TANBAC TB0219 Base board support"
-	depends on TANBAC_TB0229
-
 config VICTOR_MPC30X
 	bool "Support for Victor MP-C303/304"
 	select DMA_NONCOHERENT
@@ -1660,3 +1656,7 @@ config GENERIC_HARDIRQS
 config GENERIC_IRQ_PROBE
 	bool
 	default y
+
+config ISA_DMA_API
+	bool
+	default y
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -692,7 +692,7 @@ static int load_irix_binary(struct linux
 	/* Do this so that we can load the interpreter, if need be.  We will
 	 * change some of these later.
 	 */
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 	setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
 	current->mm->start_stack = bprm->p;
 
@@ -887,12 +887,11 @@ unsigned long irix_mapelf(int fd, struct
 
 	/* First get the verification out of the way. */
 	hp = user_phdrp;
-	retval = verify_area(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt));
-	if(retval) {
+	if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) {
 #ifdef DEBUG_ELF
-		printk("irix_mapelf: verify_area fails!\n");
+		printk("irix_mapelf: access_ok fails!\n");
 #endif
-		return retval;
+		return -EFAULT;
 	}
 
 #ifdef DEBUG_ELF
diff --git a/arch/mips/kernel/irixinv.c b/arch/mips/kernel/irixinv.c
--- a/arch/mips/kernel/irixinv.c
+++ b/arch/mips/kernel/irixinv.c
@@ -36,8 +36,8 @@ int dump_inventory_to_user (void *userbu
 	inventory_t *user = userbuf;
 	int v;
 
-	if ((v = verify_area (VERIFY_WRITE, userbuf, size)))
-		return v;
+	if (!access_ok(VERIFY_WRITE, userbuf, size))
+		return -EFAULT;
 
 	for (v = 0; v < inventory_items; v++){
 		inv = &inventory [v];
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -312,7 +312,7 @@ irix_sigaction(int sig, const struct sig
 #endif
 	if (act) {
 		sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags))
 			return -EFAULT;
@@ -331,7 +331,7 @@ irix_sigaction(int sig, const struct sig
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
 			return -EFAULT;
@@ -350,12 +350,10 @@ asmlinkage int irix_sigpending(irix_sigs
 asmlinkage int irix_sigprocmask(int how, irix_sigset_t *new, irix_sigset_t *old)
 {
 	sigset_t oldbits, newbits;
-	int error;
 
 	if (new) {
-		error = verify_area(VERIFY_READ, new, sizeof(*new));
-		if (error)
-			return error;
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
+			return -EFAULT;
 		__copy_from_user(&newbits, new, sizeof(unsigned long)*4);
 		sigdelsetmask(&newbits, ~_BLOCKABLE);
 
@@ -385,9 +383,8 @@ asmlinkage int irix_sigprocmask(int how,
 		spin_unlock_irq(&current->sighand->siglock);
 	}
 	if(old) {
-		error = verify_area(VERIFY_WRITE, old, sizeof(*old));
-		if(error)
-			return error;
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
+			return -EFAULT;
 		__copy_to_user(old, &current->blocked, sizeof(unsigned long)*4);
 	}
 
@@ -469,12 +466,13 @@ asmlinkage int irix_sigpoll_sys(unsigned
 #endif
 
 	/* Must always specify the signal set. */
-	if(!set)
+	if (!set)
 		return -EINVAL;
 
-	error = verify_area(VERIFY_READ, set, sizeof(kset));
-	if (error)
+	if (!access_ok(VERIFY_READ, set, sizeof(kset))) {
+		error = -EFAULT;
 		goto out;
+	}
 
 	__copy_from_user(&kset, set, sizeof(set));
 	if (error)
@@ -485,11 +483,10 @@ asmlinkage int irix_sigpoll_sys(unsigned
 		goto out;
 	}
 
-	if(tp) {
-		error = verify_area(VERIFY_READ, tp, sizeof(*tp));
-		if(error)
-			return error;
-		if(!tp->tv_sec && !tp->tv_nsec) {
+	if (tp) {
+		if (!access_ok(VERIFY_READ, tp, sizeof(*tp)))
+			return -EFAULT;
+		if (!tp->tv_sec && !tp->tv_nsec) {
 			error = -EINVAL;
 			goto out;
 		}
@@ -564,13 +561,15 @@ asmlinkage int irix_waitsys(int type, in
 		retval = -EINVAL;
 		goto out;
 	}
-	retval = verify_area(VERIFY_WRITE, info, sizeof(*info));
-	if(retval)
+	if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) {
+		retval = -EFAULT;
 		goto out;
+	}
 	if (ru) {
-		retval = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
-		if(retval)
+		if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) {
+			retval = -EFAULT;
 			goto out;
+		}
 	}
 	if (options & ~(W_MASK)) {
 		retval = -EINVAL;
@@ -690,7 +689,7 @@ struct irix5_context {
 
 asmlinkage int irix_getcontext(struct pt_regs *regs)
 {
-	int error, i, base = 0;
+	int i, base = 0;
 	struct irix5_context *ctx;
 	unsigned long flags;
 
@@ -703,9 +702,9 @@ asmlinkage int irix_getcontext(struct pt
 	       current->comm, current->pid, ctx);
 #endif
 
-	error = verify_area(VERIFY_WRITE, ctx, sizeof(*ctx));
-	if(error)
-		goto out;
+	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)))
+		return -EFAULT;
+
 	__put_user(current->thread.irix_oldctx, &ctx->link);
 
 	__copy_to_user(&ctx->sigmask, &current->blocked, sizeof(irix_sigset_t));
@@ -725,17 +724,15 @@ asmlinkage int irix_getcontext(struct pt
 	__put_user(regs->cp0_epc, &ctx->regs[35]);
 
 	flags = 0x0f;
-	if(!used_math()) {
+	if (!used_math()) {
 		flags &= ~(0x08);
 	} else {
 		/* XXX wheee... */
 		printk("Wheee, no code for saving IRIX FPU context yet.\n");
 	}
 	__put_user(flags, &ctx->flags);
-	error = 0;
 
-out:
-	return error;
+	return 0;
 }
 
 asmlinkage unsigned long irix_setcontext(struct pt_regs *regs)
@@ -752,9 +749,10 @@ asmlinkage unsigned long irix_setcontext
 	       current->comm, current->pid, ctx);
 #endif
 
-	error = verify_area(VERIFY_READ, ctx, sizeof(*ctx));
-	if (error)
+	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))) {
+		error = -EFAULT;
 		goto out;
+	}
 
 	if (ctx->flags & 0x02) {
 		/* XXX sigstack garbage, todo... */
@@ -787,21 +785,19 @@ struct irix_sigstack { unsigned long sp;
 
 asmlinkage int irix_sigstack(struct irix_sigstack *new, struct irix_sigstack *old)
 {
-	int error;
+	int error = -EFAULT;
 
 #ifdef DEBUG_SIG
 	printk("[%s:%d] irix_sigstack(%p,%p)\n",
 	       current->comm, current->pid, new, old);
 #endif
 	if(new) {
-		error = verify_area(VERIFY_READ, new, sizeof(*new));
-		if(error)
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
 			goto out;
 	}
 
 	if(old) {
-		error = verify_area(VERIFY_WRITE, old, sizeof(*old));
-		if(error)
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
 			goto out;
 	}
 	error = 0;
@@ -815,21 +811,19 @@ struct irix_sigaltstack { unsigned long 
 asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new,
 				struct irix_sigaltstack *old)
 {
-	int error;
+	int error = -EFAULT;
 
 #ifdef DEBUG_SIG
 	printk("[%s:%d] irix_sigaltstack(%p,%p)\n",
 	       current->comm, current->pid, new, old);
 #endif
 	if (new) {
-		error = verify_area(VERIFY_READ, new, sizeof(*new));
-		if(error)
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
 			goto out;
 	}
 
 	if (old) {
-		error = verify_area(VERIFY_WRITE, old, sizeof(*old));
-		if(error)
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
 			goto out;
 	}
 	error = 0;
@@ -846,19 +840,14 @@ struct irix_procset {
 
 asmlinkage int irix_sigsendset(struct irix_procset *pset, int sig)
 {
-	int error;
+	if (!access_ok(VERIFY_READ, pset, sizeof(*pset)))
+		return -EFAULT;
 
-	error = verify_area(VERIFY_READ, pset, sizeof(*pset));
-	if(error)
-		goto out;
 #ifdef DEBUG_SIG
 	printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n",
 	       current->comm, current->pid,
 	       pset->cmd, pset->ltype, pset->lid, pset->rtype, pset->rid,
 	       sig);
 #endif
-	error = -EINVAL;
-
-out:
-	return error;
+	return -EINVAL;
 }
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -239,7 +239,7 @@ put_rusage (struct rusage32 *ru, struct 
 {
 	int err;
 
-	if (verify_area(VERIFY_WRITE, ru, sizeof *ru))
+	if (!access_ok(VERIFY_WRITE, ru, sizeof *ru))
 		return -EFAULT;
 
 	err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -21,10 +21,12 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/audit.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/cpu.h>
 #include <asm/fpu.h>
@@ -256,7 +258,7 @@ asmlinkage int sys_ptrace(long request, 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -299,25 +301,38 @@ out:
 	return ret;
 }
 
+static inline int audit_arch(void)
+{
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#ifdef CONFIG_MIPS64
+	if (!(current->thread.mflags & MF_32BIT_REGS))
+		return AUDIT_ARCH_MIPSEL64;
+#endif /* MIPS64 */
+	return AUDIT_ARCH_MIPSEL;
+
+#else /* big endian... */
+#ifdef CONFIG_MIPS64
+	if (!(current->thread.mflags & MF_32BIT_REGS))
+		return AUDIT_ARCH_MIPS64;
+#endif /* MIPS64 */
+	return AUDIT_ARCH_MIPS;
+
+#endif /* endian */
+}
+
 /*
  * Notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	if (unlikely(current->audit_context)) {
-		if (!entryexit)
-			audit_syscall_entry(current, regs->orig_eax,
-			                    regs->regs[4], regs->regs[5],
-			                    regs->regs[6], regs->regs[7]);
-		else
-			audit_syscall_exit(current, regs->regs[2]);
-	}
+	if (unlikely(current->audit_context) && entryexit)
+		audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), regs->regs[2]);
 
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+		goto out;
 	if (!(current->ptrace & PT_PTRACED))
-		return;
+		goto out;
 
 	/* The 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
@@ -333,4 +348,9 @@ asmlinkage void do_syscall_trace(struct 
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+ out:
+	if (unlikely(current->audit_context) && !entryexit)
+		audit_syscall_entry(current, audit_arch(), regs->regs[2],
+				    regs->regs[4], regs->regs[5],
+				    regs->regs[6], regs->regs[7]);
 }
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -24,6 +24,7 @@
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/cpu.h>
 #include <asm/fpu.h>
@@ -241,7 +242,7 @@ asmlinkage int sys32_ptrace(int request,
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned int) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -86,8 +86,8 @@ EXPORT_SYMBOL(mips_io_port_base);
 unsigned long isa_slot_offset;
 EXPORT_SYMBOL(isa_slot_offset);
 
-static struct resource code_resource = { "Kernel code" };
-static struct resource data_resource = { "Kernel data" };
+static struct resource code_resource = { .name = "Kernel code", };
+static struct resource data_resource = { .name = "Kernel data", };
 
 void __init add_memory_region(phys_t start, phys_t size, long type)
 {
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -32,11 +32,6 @@
 
 #define SI_PAD_SIZE32   ((SI_MAX_SIZE/sizeof(int)) - 3)
 
-typedef union sigval32 {
-	int sival_int;
-	s32 sival_ptr;
-} sigval_t32;
-
 typedef struct compat_siginfo {
 	int si_signo;
 	int si_code;
@@ -89,7 +84,7 @@ typedef struct compat_siginfo {
 		struct {
 			compat_pid_t _pid;	/* sender's pid */
 			compat_uid_t _uid;	/* sender's uid */
-			sigval_t32 _sigval;
+			compat_sigval_t _sigval;
 		} _rt;
 
 	} _sifields;
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -46,9 +46,6 @@ int __cpu_logical_map[NR_CPUS];		/* Map 
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(cpu_online_map);
 
-cycles_t cacheflush_time;
-unsigned long cache_decay_ticks;
-
 static void smp_tune_scheduling (void)
 {
 	struct cache_desc *cd = &current_cpu_data.scache;
@@ -71,25 +68,10 @@ static void smp_tune_scheduling (void)
 	 *  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 cycle counter.  Currently all SMP capable MIPS
-		 * processors have a cycle counter.
-		 */
-		cacheflush_time = 0;
+	if (!cpu_khz)
 		return;
-	}
 
 	cachesize = cd->linesz * cd->sets * cd->ways;
-	cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
-	cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
-
-	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
-		(long)cacheflush_time/(cpu_khz/1000),
-		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
-	printk("task migration cache decay timeout: %ld msecs.\n",
-		(cache_decay_ticks + 1) * 1000 / HZ);
 }
 
 extern void __init calibrate_delay(void);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -374,22 +374,6 @@ asmlinkage int sys_ipc (uint call, int f
 }
 
 /*
- * Native ABI that is O32 or N64 version
- */
-asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
-                          int shmflg, unsigned long *addr)
-{
-	unsigned long raddr;
-	int err;
-
-	err = do_shmat(shmid, shmaddr, shmflg, &raddr);
-	if (err)
-		return err;
-
-	return put_user(raddr, addr);
-}
-
-/*
  * No implemented yet ...
  */
 asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -289,9 +289,10 @@ asmlinkage int irix_syssgi(struct pt_reg
 		struct task_struct *p;
 		char tcomm[sizeof(current->comm)];
 
-		retval = verify_area(VERIFY_WRITE, buf, sizeof(tcomm));
-		if (retval)
+		if (!access_ok(VERIFY_WRITE, buf, sizeof(tcomm))) {
+			retval = -EFAULT;
 			break;
+		}
 		read_lock(&tasklist_lock);
 		p = find_task_by_pid(pid);
 		if (!p) {
@@ -313,9 +314,10 @@ asmlinkage int irix_syssgi(struct pt_reg
 		char *buf = (char *) regs->regs[base+6];
 		char *value;
 		return -EINVAL;	/* til I fix it */
-		retval = verify_area(VERIFY_WRITE, buf, 128);
-		if (retval)
+		if (!access_ok(VERIFY_WRITE, buf, 128)) {
+			retval = -EFAULT;
 			break;
+		}
 		value = prom_getenv(name);	/* PROM lock?  */
 		if (!value) {
 			retval = -EINVAL;
@@ -472,9 +474,8 @@ asmlinkage int irix_syssgi(struct pt_reg
 		pmd_t *pmdp;
 		pte_t *ptep;
 
-		retval = verify_area(VERIFY_WRITE, pageno, sizeof(int));
-		if (retval)
-			return retval;
+		if (!access_ok(VERIFY_WRITE, pageno, sizeof(int)))
+			return -EFAULT;
 
 		down_read(&mm->mmap_sem);
 		pgdp = pgd_offset(mm, addr);
@@ -727,9 +728,10 @@ asmlinkage int irix_statfs(const char *p
 		error = -EINVAL;
 		goto out;
 	}
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statfs))) {
+		error = -EFAULT;
 		goto out;
+	}
 	error = user_path_walk(path, &nd);
 	if (error)
 		goto out;
@@ -763,9 +765,10 @@ asmlinkage int irix_fstatfs(unsigned int
 	struct file *file;
 	int error, i;
 
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statfs))) {
+		error = -EFAULT;
 		goto out;
+	}
 	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
@@ -816,9 +819,8 @@ asmlinkage int irix_times(struct tms * t
 	int err = 0;
 
 	if (tbuf) {
-		err = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
-		if (err)
-			return err;
+		if (!access_ok(VERIFY_WRITE,tbuf,sizeof *tbuf))
+			return -EFAULT;
 		err |= __put_user(current->utime, &tbuf->tms_utime);
 		err |= __put_user(current->stime, &tbuf->tms_stime);
 		err |= __put_user(current->signal->cutime, &tbuf->tms_cutime);
@@ -919,9 +921,8 @@ asmlinkage int irix_getdomainname(char *
 {
 	int error;
 
-	error = verify_area(VERIFY_WRITE, name, len);
-	if (error)
-		return error;
+	if (!access_ok(VERIFY_WRITE, name, len))
+		return -EFAULT;
 
 	down_read(&uts_sem);
 	if (len > __NEW_UTS_LEN)
@@ -1050,7 +1051,7 @@ asmlinkage int irix_gettimeofday(struct 
 	long nsec, seq;
 	int err;
 
-	if (verify_area(VERIFY_WRITE, tv, sizeof(struct timeval)))
+	if (!access_ok(VERIFY_WRITE, tv, sizeof(struct timeval)))
 		return -EFAULT;
 
 	do {
@@ -1396,9 +1397,10 @@ asmlinkage int irix_statvfs(char *fname,
 
 	printk("[%s:%d] Wheee.. irix_statvfs(%s,%p)\n",
 	       current->comm, current->pid, fname, buf);
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
 		goto out;
+	}
 	error = user_path_walk(fname, &nd);
 	if (error)
 		goto out;
@@ -1443,9 +1445,10 @@ asmlinkage int irix_fstatvfs(int fd, str
 	printk("[%s:%d] Wheee.. irix_fstatvfs(%d,%p)\n",
 	       current->comm, current->pid, fd, buf);
 
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
 		goto out;
+	}
 	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
@@ -1537,16 +1540,18 @@ asmlinkage int irix_mmap64(struct pt_reg
 	prot = regs->regs[base + 6];
 	if (!base) {
 		flags = regs->regs[base + 7];
-		error = verify_area(VERIFY_READ, sp, (4 * sizeof(unsigned long)));
-		if(error)
+		if (!access_ok(VERIFY_READ, sp, (4 * sizeof(unsigned long)))) {
+			error = -EFAULT;
 			goto out;
+		}
 		fd = sp[0];
 		__get_user(off1, &sp[1]);
 		__get_user(off2, &sp[2]);
 	} else {
-		error = verify_area(VERIFY_READ, sp, (5 * sizeof(unsigned long)));
-		if(error)
+		if (!access_ok(VERIFY_READ, sp, (5 * sizeof(unsigned long)))) {
+			error = -EFAULT;
 			goto out;
+		}
 		__get_user(flags, &sp[0]);
 		__get_user(fd, &sp[1]);
 		__get_user(off1, &sp[2]);
@@ -1650,9 +1655,10 @@ asmlinkage int irix_statvfs64(char *fnam
 
 	printk("[%s:%d] Wheee.. irix_statvfs64(%s,%p)\n",
 	       current->comm, current->pid, fname, buf);
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs64));
-	if(error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs64))) {
+		error = -EFAULT;
 		goto out;
+	}
 	error = user_path_walk(fname, &nd);
 	if (error)
 		goto out;
@@ -1697,9 +1703,10 @@ asmlinkage int irix_fstatvfs64(int fd, s
 	printk("[%s:%d] Wheee.. irix_fstatvfs64(%d,%p)\n",
 	       current->comm, current->pid, fd, buf);
 
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
 		goto out;
+	}
 	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
@@ -1735,13 +1742,12 @@ out:
 
 asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf)
 {
-	int err;
+	int err = 0;
 
 	printk("[%s:%d] irix_getmountid(%s, %p)\n",
 	       current->comm, current->pid, fname, midbuf);
-	err = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4));
-	if (err)
-		return err;
+	if (!access_ok(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4)))
+		return -EFAULT;
 
 	/*
 	 * The idea with this system call is that when trying to determine
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -143,7 +143,7 @@ static inline int emulate_load_store_ins
 	 * The remaining opcodes are the ones that are really of interest.
 	 */
 	case lh_op:
-		if (verify_area(VERIFY_READ, addr, 2))
+		if (!access_ok(VERIFY_READ, addr, 2))
 			goto sigbus;
 
 		__asm__ __volatile__ (".set\tnoat\n"
@@ -176,7 +176,7 @@ static inline int emulate_load_store_ins
 		break;
 
 	case lw_op:
-		if (verify_area(VERIFY_READ, addr, 4))
+		if (!access_ok(VERIFY_READ, addr, 4))
 			goto sigbus;
 
 		__asm__ __volatile__ (
@@ -206,7 +206,7 @@ static inline int emulate_load_store_ins
 		break;
 
 	case lhu_op:
-		if (verify_area(VERIFY_READ, addr, 2))
+		if (!access_ok(VERIFY_READ, addr, 2))
 			goto sigbus;
 
 		__asm__ __volatile__ (
@@ -248,7 +248,7 @@ static inline int emulate_load_store_ins
 		 * would blow up, so for now we don't handle unaligned 64-bit
 		 * instructions on 32-bit kernels.
 		 */
-		if (verify_area(VERIFY_READ, addr, 4))
+		if (!access_ok(VERIFY_READ, addr, 4))
 			goto sigbus;
 
 		__asm__ __volatile__ (
@@ -292,7 +292,7 @@ static inline int emulate_load_store_ins
 		 * would blow up, so for now we don't handle unaligned 64-bit
 		 * instructions on 32-bit kernels.
 		 */
-		if (verify_area(VERIFY_READ, addr, 8))
+		if (!access_ok(VERIFY_READ, addr, 8))
 			goto sigbus;
 
 		__asm__ __volatile__ (
@@ -326,7 +326,7 @@ static inline int emulate_load_store_ins
 		goto sigill;
 
 	case sh_op:
-		if (verify_area(VERIFY_WRITE, addr, 2))
+		if (!access_ok(VERIFY_WRITE, addr, 2))
 			goto sigbus;
 
 		value = regs->regs[insn.i_format.rt];
@@ -362,7 +362,7 @@ static inline int emulate_load_store_ins
 		break;
 
 	case sw_op:
-		if (verify_area(VERIFY_WRITE, addr, 4))
+		if (!access_ok(VERIFY_WRITE, addr, 4))
 			goto sigbus;
 
 		value = regs->regs[insn.i_format.rt];
@@ -400,7 +400,7 @@ static inline int emulate_load_store_ins
 		 * would blow up, so for now we don't handle unaligned 64-bit
 		 * instructions on 32-bit kernels.
 		 */
-		if (verify_area(VERIFY_WRITE, addr, 8))
+		if (!access_ok(VERIFY_WRITE, addr, 8))
 			goto sigbus;
 
 		value = regs->regs[insn.i_format.rt];
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,7 +2,9 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y	+= csum_partial_copy.o dec_and_lock.o iomap.o memcpy.o promlib.o \
+lib-y	+= csum_partial_copy.o dec_and_lock.o memcpy.o promlib.o \
 	   strlen_user.o strncpy_user.o strnlen_user.o
 
+obj-y	+= iomap.o
+
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -95,7 +95,7 @@ int mips_dsemul(struct pt_regs *regs, mi
 	fr = (struct emuframe *) dsemul_insns;
 
 	/* Verify that the stack pointer is not competely insane */
-	if (unlikely(verify_area(VERIFY_WRITE, fr, sizeof(struct emuframe))))
+	if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
 		return SIGBUS;
 
 	err = __put_user(ir, &fr->emul);
@@ -128,7 +128,7 @@ int do_dsemulret(struct pt_regs *xcp)
 	 * 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)))
+	if (!access_ok(VERIFY_READ, fr, sizeof(struct emuframe)))
 		return 0;
 
 	/*
@@ -142,7 +142,6 @@ int do_dsemulret(struct pt_regs *xcp)
 
 	if (unlikely(err || (insn != BADINST) || (cookie != BD_COOKIE))) {
 		fpuemuprivate.stats.errors++;
-
 		return 0;
 	}
 
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -254,8 +254,7 @@ static void r3k_flush_cache_range(struct
 {
 }
 
-static void r3k_flush_cache_page(struct vm_area_struct *vma,
-	unsigned long page)
+static void r3k_flush_cache_page(struct vm_area_struct *vma, unsigned long page, unsigned long pfn)
 {
 }
 
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -426,8 +426,7 @@ static inline void local_r4k_flush_cache
 	}
 }
 
-static void r4k_flush_cache_page(struct vm_area_struct *vma,
-	unsigned long page)
+static void r4k_flush_cache_page(struct vm_area_struct *vma, unsigned long page, unsigned long pfn)
 {
 	struct flush_cache_page_args args;
 
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
--- a/arch/mips/mm/c-sb1.c
+++ b/arch/mips/mm/c-sb1.c
@@ -160,8 +160,7 @@ static inline void __sb1_flush_icache_al
  * dcache first, then invalidate the icache.  If the page isn't
  * executable, nothing is required.
  */
-static void local_sb1_flush_cache_page(struct vm_area_struct *vma,
-	unsigned long addr)
+static void local_sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
 {
 	int cpu = smp_processor_id();
 
@@ -183,17 +182,18 @@ static void local_sb1_flush_cache_page(s
 struct flush_cache_page_args {
 	struct vm_area_struct *vma;
 	unsigned long addr;
+	unsigned long pfn;
 };
 
 static void sb1_flush_cache_page_ipi(void *info)
 {
 	struct flush_cache_page_args *args = info;
 
-	local_sb1_flush_cache_page(args->vma, args->addr);
+	local_sb1_flush_cache_page(args->vma, args->addr, args->pfn);
 }
 
 /* Dirty dcache could be on another CPU, so do the IPIs */
-static void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+static void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
 {
 	struct flush_cache_page_args args;
 
@@ -203,10 +203,11 @@ static void sb1_flush_cache_page(struct 
 	addr &= PAGE_MASK;
 	args.vma = vma;
 	args.addr = addr;
+	args.pfn = pfn;
 	on_each_cpu(sb1_flush_cache_page_ipi, (void *) &args, 1, 1);
 }
 #else
-void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
 	__attribute__((alias("local_sb1_flush_cache_page")));
 #endif
 
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -178,8 +178,7 @@ static void tx39_flush_cache_range(struc
 	}
 }
 
-static void tx39_flush_cache_page(struct vm_area_struct *vma,
-				   unsigned long page)
+static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page, unsigned long pfn)
 {
 	int exec = vma->vm_flags & VM_EXEC;
 	struct mm_struct *mm = vma->vm_mm;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -23,7 +23,7 @@ void (*__flush_cache_all)(void);
 void (*flush_cache_mm)(struct mm_struct *mm);
 void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 	unsigned long end);
-void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
+void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 void (*flush_icache_range)(unsigned long start, unsigned long end);
 void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page);
 
@@ -52,7 +52,7 @@ EXPORT_SYMBOL(_dma_cache_inv);
 asmlinkage int sys_cacheflush(unsigned long addr, unsigned long int bytes,
 	unsigned int cache)
 {
-	if (verify_area(VERIFY_WRITE, (void *) addr, bytes))
+	if (!access_ok(VERIFY_WRITE, (void *) addr, bytes))
 		return -EFAULT;
 
 	flush_icache_range(addr, addr + bytes);
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -75,7 +75,7 @@ void __kunmap_atomic(void *kvaddr, enum 
 	 * force other mappings to Oops if they'll try to access
 	 * this pte without first remap it
 	 */
-	pte_clear(kmap_pte-idx);
+	pte_clear(&init_mm, vaddr, kmap_pte-idx);
 	local_flush_tlb_one(vaddr);
 #endif
 
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -82,9 +82,6 @@ unsigned long setup_zero_pages(void)
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-
 #define kmap_get_fixmap_pte(vaddr)					\
 	pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
 
diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c
--- a/arch/mips/pci/fixup-mpc30x.c
+++ b/arch/mips/pci/fixup-mpc30x.c
@@ -29,7 +29,7 @@ static const int internal_func_irqs[] __
 	VRC4173_USB_IRQ,
 };
 
-static char irq_tab_mpc30x[] __initdata = {
+static const int irq_tab_mpc30x[] __initdata = {
  [12] = VRC4173_PCMCIA1_IRQ,
  [13] = VRC4173_PCMCIA2_IRQ,
  [29] = MQ200_IRQ,
diff --git a/arch/mips/pci/ops-vr41xx.c b/arch/mips/pci/ops-vr41xx.c
--- a/arch/mips/pci/ops-vr41xx.c
+++ b/arch/mips/pci/ops-vr41xx.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2004-2005  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
@@ -29,8 +29,8 @@
 
 #include <asm/io.h>
 
-#define PCICONFDREG	KSEG1ADDR(0x0f000c14)
-#define PCICONFAREG	KSEG1ADDR(0x0f000c18)
+#define PCICONFDREG	(void __iomem *)KSEG1ADDR(0x0f000c14)
+#define PCICONFAREG	(void __iomem *)KSEG1ADDR(0x0f000c18)
 
 static inline int set_pci_configuration_address(unsigned char number,
                                                 unsigned int devfn, int where)
diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c
--- a/arch/mips/pci/pci-vr41xx.c
+++ b/arch/mips/pci/pci-vr41xx.c
@@ -3,8 +3,8 @@
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.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
@@ -31,12 +31,18 @@
 
 #include <asm/cpu.h>
 #include <asm/io.h>
+#include <asm/vr41xx/pci.h>
 #include <asm/vr41xx/vr41xx.h>
 
 #include "pci-vr41xx.h"
 
 extern struct pci_ops vr41xx_pci_ops;
 
+static void __iomem *pciu_base;
+
+#define pciu_read(offset)		readl(pciu_base + (offset))
+#define pciu_write(offset, value)	writel((value), pciu_base + (offset))
+
 static struct pci_master_address_conversion pci_master_memory1 = {
 	.bus_base_address	= PCI_MASTER_MEM1_BUS_BASE_ADDRESS,
 	.address_mask		= PCI_MASTER_MEM1_ADDRESS_MASK,
@@ -113,6 +119,15 @@ static int __init vr41xx_pciu_init(void)
 
 	setup = &vr41xx_pci_controller_unit_setup;
 
+	if (request_mem_region(PCIU_BASE, PCIU_SIZE, "PCIU") == NULL)
+		return -EBUSY;
+
+	pciu_base = ioremap(PCIU_BASE, PCIU_SIZE);
+	if (pciu_base == NULL) {
+		release_mem_region(PCIU_BASE, PCIU_SIZE);
+		return -EBUSY;
+	}
+
 	/* Disable PCI interrupt */
 	vr41xx_disable_pciint();
 
@@ -129,14 +144,14 @@ static int __init vr41xx_pciu_init(void)
 		pci_clock_max = PCI_CLOCK_MAX;
 	vtclock = vr41xx_get_vtclock_frequency();
 	if (vtclock < pci_clock_max)
-		writel(EQUAL_VTCLOCK, PCICLKSELREG);
+		pciu_write(PCICLKSELREG, EQUAL_VTCLOCK);
 	else if ((vtclock / 2) < pci_clock_max)
-		writel(HALF_VTCLOCK, PCICLKSELREG);
+		pciu_write(PCICLKSELREG, HALF_VTCLOCK);
 	else if (current_cpu_data.processor_id >= PRID_VR4131_REV2_1 &&
 	         (vtclock / 3) < pci_clock_max)
-		writel(ONE_THIRD_VTCLOCK, PCICLKSELREG);
+		pciu_write(PCICLKSELREG, ONE_THIRD_VTCLOCK);
 	else if ((vtclock / 4) < pci_clock_max)
-		writel(QUARTER_VTCLOCK, PCICLKSELREG);
+		pciu_write(PCICLKSELREG, QUARTER_VTCLOCK);
 	else {
 		printk(KERN_ERR "PCI Clock is over 33MHz.\n");
 		return -EINVAL;
@@ -151,11 +166,11 @@ static int __init vr41xx_pciu_init(void)
 		      MASTER_MSK(master->address_mask) |
 		      WINEN |
 		      PCIA(master->pci_base_address);
-		writel(val, PCIMMAW1REG);
+		pciu_write(PCIMMAW1REG, val);
 	} else {
-		val = readl(PCIMMAW1REG);
+		val = pciu_read(PCIMMAW1REG);
 		val &= ~WINEN;
-		writel(val, PCIMMAW1REG);
+		pciu_write(PCIMMAW1REG, val);
 	}
 
 	if (setup->master_memory2 != NULL) {
@@ -164,11 +179,11 @@ static int __init vr41xx_pciu_init(void)
 		      MASTER_MSK(master->address_mask) |
 		      WINEN |
 		      PCIA(master->pci_base_address);
-		writel(val, PCIMMAW2REG);
+		pciu_write(PCIMMAW2REG, val);
 	} else {
-		val = readl(PCIMMAW2REG);
+		val = pciu_read(PCIMMAW2REG);
 		val &= ~WINEN;
-		writel(val, PCIMMAW2REG);
+		pciu_write(PCIMMAW2REG, val);
 	}
 
 	if (setup->target_memory1 != NULL) {
@@ -176,11 +191,11 @@ static int __init vr41xx_pciu_init(void)
 		val = TARGET_MSK(target->address_mask) |
 		      WINEN |
 		      ITA(target->bus_base_address);
-		writel(val, PCITAW1REG);
+		pciu_write(PCITAW1REG, val);
 	} else {
-		val = readl(PCITAW1REG);
+		val = pciu_read(PCITAW1REG);
 		val &= ~WINEN;
-		writel(val, PCITAW1REG);
+		pciu_write(PCITAW1REG, val);
 	}
 
 	if (setup->target_memory2 != NULL) {
@@ -188,11 +203,11 @@ static int __init vr41xx_pciu_init(void)
 		val = TARGET_MSK(target->address_mask) |
 		      WINEN |
 		      ITA(target->bus_base_address);
-		writel(val, PCITAW2REG);
+		pciu_write(PCITAW2REG, val);
 	} else {
-		val = readl(PCITAW2REG);
+		val = pciu_read(PCITAW2REG);
 		val &= ~WINEN;
-		writel(val, PCITAW2REG);
+		pciu_write(PCITAW2REG, val);
 	}
 
 	if (setup->master_io != NULL) {
@@ -201,50 +216,50 @@ static int __init vr41xx_pciu_init(void)
 		      MASTER_MSK(master->address_mask) |
 		      WINEN |
 		      PCIIA(master->pci_base_address);
-		writel(val, PCIMIOAWREG);
+		pciu_write(PCIMIOAWREG, val);
 	} else {
-		val = readl(PCIMIOAWREG);
+		val = pciu_read(PCIMIOAWREG);
 		val &= ~WINEN;
-		writel(val, PCIMIOAWREG);
+		pciu_write(PCIMIOAWREG, val);
 	}
 
 	if (setup->exclusive_access == CANNOT_LOCK_FROM_DEVICE)
-		writel(UNLOCK, PCIEXACCREG);
+		pciu_write(PCIEXACCREG, UNLOCK);
 	else
-		writel(0, PCIEXACCREG);
+		pciu_write(PCIEXACCREG, 0);
 
 	if (current_cpu_data.cputype == CPU_VR4122)
-		writel(TRDYV(setup->wait_time_limit_from_irdy_to_trdy), PCITRDYVREG);
+		pciu_write(PCITRDYVREG, TRDYV(setup->wait_time_limit_from_irdy_to_trdy));
 
-	writel(MLTIM(setup->master_latency_timer), LATTIMEREG);
+	pciu_write(LATTIMEREG, MLTIM(setup->master_latency_timer));
 
 	if (setup->mailbox != NULL) {
 		mailbox = setup->mailbox;
 		val = MBADD(mailbox->base_address) | TYPE_32BITSPACE |
 		      MSI_MEMORY | PREF_APPROVAL;
-		writel(val, MAILBAREG);
+		pciu_write(MAILBAREG, val);
 	}
 
 	if (setup->target_window1) {
 		window = setup->target_window1;
 		val = PMBA(window->base_address) | TYPE_32BITSPACE |
 		      MSI_MEMORY | PREF_APPROVAL;
-		writel(val, PCIMBA1REG);
+		pciu_write(PCIMBA1REG, val);
 	}
 
 	if (setup->target_window2) {
 		window = setup->target_window2;
 		val = PMBA(window->base_address) | TYPE_32BITSPACE |
 		      MSI_MEMORY | PREF_APPROVAL;
-		writel(val, PCIMBA2REG);
+		pciu_write(PCIMBA2REG, val);
 	}
 
-	val = readl(RETVALREG);
+	val = pciu_read(RETVALREG);
 	val &= ~RTYVAL_MASK;
 	val |= RTYVAL(setup->retry_limit);
-	writel(val, RETVALREG);
+	pciu_write(RETVALREG, val);
 
-	val = readl(PCIAPCNTREG);
+	val = pciu_read(PCIAPCNTREG);
 	val &= ~(TKYGNT | PAPC);
 
 	switch (setup->arbiter_priority_control) {
@@ -262,15 +277,16 @@ static int __init vr41xx_pciu_init(void)
 	if (setup->take_away_gnt_mode == PCI_TAKE_AWAY_GNT_ENABLE)
 		val |= TKYGNT_ENABLE;
 
-	writel(val, PCIAPCNTREG);
+	pciu_write(PCIAPCNTREG, val);
 
-	writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
-	       PCI_COMMAND_PARITY | PCI_COMMAND_SERR, COMMANDREG);
+	pciu_write(COMMANDREG, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+	                       PCI_COMMAND_MASTER | PCI_COMMAND_PARITY |
+			       PCI_COMMAND_SERR);
 
 	/* Clear bus error */
-	readl(BUSERRADREG);
+	pciu_read(BUSERRADREG);
 
-	writel(BLOODY_CONFIG_DONE, PCIENREG);
+	pciu_write(PCIENREG, PCIU_CONFIG_DONE);
 
 	if (setup->mem_resource != NULL)
 		vr41xx_pci_controller.mem_resource = setup->mem_resource;
@@ -288,4 +304,4 @@ static int __init vr41xx_pciu_init(void)
 	return 0;
 }
 
-early_initcall(vr41xx_pciu_init);
+arch_initcall(vr41xx_pciu_init);
diff --git a/arch/mips/pci/pci-vr41xx.h b/arch/mips/pci/pci-vr41xx.h
--- a/arch/mips/pci/pci-vr41xx.h
+++ b/arch/mips/pci/pci-vr41xx.h
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2004-2005  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
@@ -22,11 +22,14 @@
 #ifndef __PCI_VR41XX_H
 #define __PCI_VR41XX_H
 
-#define PCIMMAW1REG		KSEG1ADDR(0x0f000c00)
-#define PCIMMAW2REG		KSEG1ADDR(0x0f000c04)
-#define PCITAW1REG		KSEG1ADDR(0x0f000c08)
-#define PCITAW2REG		KSEG1ADDR(0x0f000c0c)
-#define PCIMIOAWREG		KSEG1ADDR(0x0f000c10)
+#define PCIU_BASE		0x0f000c00UL
+#define PCIU_SIZE		0x200UL
+
+#define PCIMMAW1REG		0x00
+#define PCIMMAW2REG		0x04
+#define PCITAW1REG		0x08
+#define PCITAW2REG		0x0c
+#define PCIMIOAWREG		0x10
  #define IBA(addr)		((addr) & 0xff000000U)
  #define MASTER_MSK(mask)	(((mask) >> 11) & 0x000fe000U)
  #define PCIA(addr)		(((addr) >> 24) & 0x000000ffU)
@@ -34,13 +37,13 @@
  #define ITA(addr)		(((addr) >> 24) & 0x000000ffU)
  #define PCIIA(addr)		(((addr) >> 24) & 0x000000ffU)
  #define WINEN			0x1000U
-#define PCICONFDREG		KSEG1ADDR(0x0f000c14)
-#define PCICONFAREG		KSEG1ADDR(0x0f000c18)
-#define PCIMAILREG		KSEG1ADDR(0x0f000c1c)
-#define BUSERRADREG		KSEG1ADDR(0x0f000c24)
+#define PCICONFDREG		0x14
+#define PCICONFAREG		0x18
+#define PCIMAILREG		0x1c
+#define BUSERRADREG		0x24
  #define EA(reg)		((reg) &0xfffffffc)
 
-#define INTCNTSTAREG		KSEG1ADDR(0x0f000c28)
+#define INTCNTSTAREG		0x28
  #define MABTCLR		0x80000000U
  #define TRDYCLR		0x40000000U
  #define PARCLR			0x20000000U
@@ -67,34 +70,34 @@
  #define MABORT			0x00000002U
  #define TABORT			0x00000001U
 
-#define PCIEXACCREG		KSEG1ADDR(0x0f000c2c)
+#define PCIEXACCREG		0x2c
  #define UNLOCK			0x2U
  #define EAREQ			0x1U
-#define PCIRECONTREG		KSEG1ADDR(0x0f000c30)
+#define PCIRECONTREG		0x30
  #define RTRYCNT(reg)		((reg) & 0x000000ffU)
-#define PCIENREG		KSEG1ADDR(0x0f000c34)
- #define BLOODY_CONFIG_DONE	0x4U
-#define PCICLKSELREG		KSEG1ADDR(0x0f000c38)
+#define PCIENREG		0x34
+ #define PCIU_CONFIG_DONE	0x4U
+#define PCICLKSELREG		0x38
  #define EQUAL_VTCLOCK		0x2U
  #define HALF_VTCLOCK		0x0U
  #define ONE_THIRD_VTCLOCK	0x3U
  #define QUARTER_VTCLOCK	0x1U
-#define PCITRDYVREG		KSEG1ADDR(0x0f000c3c)
+#define PCITRDYVREG		0x3c
  #define TRDYV(val)		((uint32_t)(val) & 0xffU)
-#define PCICLKRUNREG		KSEG1ADDR(0x0f000c60)
+#define PCICLKRUNREG		0x60
 
-#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 VENDORIDREG		0x100
+#define DEVICEIDREG		0x100
+#define COMMANDREG		0x104
+#define STATUSREG		0x104
+#define REVIDREG		0x108
+#define CLASSREG		0x108
+#define CACHELSREG		0x10c
+#define LATTIMEREG		0x10c
  #define MLTIM(val)		(((uint32_t)(val) << 7) & 0xff00U)
-#define MAILBAREG		KSEG1ADDR(0x0f000d10)
-#define PCIMBA1REG		KSEG1ADDR(0x0f000d14)
-#define PCIMBA2REG		KSEG1ADDR(0x0f000d18)
+#define MAILBAREG		0x110
+#define PCIMBA1REG		0x114
+#define PCIMBA2REG		0x118
  #define MBADD(base)		((base) & 0xfffff800U)
  #define PMBA(base)		((base) & 0xffe00000U)
  #define PREF			0x8U
@@ -104,10 +107,10 @@
  #define TYPE_32BITSPACE	0x0U
  #define MSI			0x1U
  #define MSI_MEMORY		0x0U
-#define INTLINEREG		KSEG1ADDR(0x0f000d3c)
-#define INTPINREG		KSEG1ADDR(0x0f000d3c)
-#define RETVALREG		KSEG1ADDR(0x0f000d40)
-#define PCIAPCNTREG		KSEG1ADDR(0x0f000d40)
+#define INTLINEREG		0x13c
+#define INTPINREG		0x13c
+#define RETVALREG		0x140
+#define PCIAPCNTREG		0x140
  #define TKYGNT			0x04000000U
  #define TKYGNT_ENABLE		0x04000000U
  #define TKYGNT_DISABLE		0x00000000U
diff --git a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c
--- a/arch/mips/pmc-sierra/yosemite/ht.c
+++ b/arch/mips/pmc-sierra/yosemite/ht.c
@@ -303,7 +303,7 @@ int pcibios_enable_resources(struct pci_
                 if (!r->start && r->end) {
                         printk(KERN_ERR
                                "PCI: Device %s not available because of "
-                               "resource collisions\n", dev->slot_name);
+                               "resource collisions\n", pci_name(dev));
                         return -EINVAL;
                 }
                 if (r->flags & IORESOURCE_IO)
@@ -361,7 +361,7 @@ void pcibios_update_resource(struct pci_
         if (resource < 6) {
                 reg = PCI_BASE_ADDRESS_0 + 4 * resource;
         } else if (resource == PCI_ROM_RESOURCE) {
-                res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
                 reg = dev->rom_base_reg;
         } else {
                 /*
@@ -377,7 +377,7 @@ void pcibios_update_resource(struct pci_
             ((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,
+                       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
                        new, check);
         }
 }
@@ -396,7 +396,7 @@ void pcibios_align_resource(void *data, 
                    addresses kilobyte aligned.  */
                 if (size > 0x100) {
                         printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                               " (%ld bytes)\n", dev->slot_name,
+                               " (%ld bytes)\n", pci_name(dev),
                                 dev->resource - res, size);
                 }
 
diff --git a/arch/mips/vr41xx/casio-e55/setup.c b/arch/mips/vr41xx/casio-e55/setup.c
--- a/arch/mips/vr41xx/casio-e55/setup.c
+++ b/arch/mips/vr41xx/casio-e55/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the CASIO CASSIOPEIA E-11/15/55/65.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  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
@@ -17,7 +17,7 @@
  *  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/ioport.h>
 
 #include <asm/io.h>
@@ -28,18 +28,13 @@ const char *get_system_type(void)
 	return "CASIO CASSIOPEIA E-11/15/55/65";
 }
 
-static int casio_e55_setup(void)
+static int __init casio_e55_setup(void)
 {
 	set_io_port_base(IO_PORT_BASE);
 	ioport_resource.start = IO_PORT_RESOURCE_START;
 	ioport_resource.end = IO_PORT_RESOURCE_END;
 
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-#endif
-
 	return 0;
 }
 
-early_initcall(casio_e55_setup);
+arch_initcall(casio_e55_setup);
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,9 +2,7 @@
 # Makefile for common code of the NEC VR4100 series.
 #
 
-obj-y				+= bcu.o cmu.o giu.o icu.o init.o int-handler.o ksyms.o pmu.o rtc.o
-obj-$(CONFIG_SERIAL_8250)	+= serial.o
-obj-$(CONFIG_VRC4171)		+= vrc4171.o
+obj-y				+= bcu.o cmu.o giu.o icu.o init.o int-handler.o pmu.o
 obj-$(CONFIG_VRC4173)		+= vrc4173.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c
--- a/arch/mips/vr41xx/common/bcu.c
+++ b/arch/mips/vr41xx/common/bcu.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
- *  Copyright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2003-2005  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
@@ -28,20 +28,16 @@
  *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *  - Added support for NEC VR4133.
  */
-#include <linux/init.h>
-#include <linux/ioport.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 
 #include <asm/cpu.h>
 #include <asm/io.h>
 
-#define IO_MEM_RESOURCE_START	0UL
-#define IO_MEM_RESOURCE_END	0x1fffffffUL
-
-#define CLKSPEEDREG_TYPE1	KSEG1ADDR(0x0b000014)
-#define CLKSPEEDREG_TYPE2	KSEG1ADDR(0x0f000014)
+#define CLKSPEEDREG_TYPE1	(void __iomem *)KSEG1ADDR(0x0b000014)
+#define CLKSPEEDREG_TYPE2	(void __iomem *)KSEG1ADDR(0x0f000014)
  #define CLKSP(x)		((x) & 0x001f)
  #define CLKSP_VR4133(x)	((x) & 0x0007)
 
@@ -63,11 +59,15 @@ unsigned long vr41xx_get_vtclock_frequen
 	return vr41xx_vtclock;
 }
 
+EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency);
+
 unsigned long vr41xx_get_tclock_frequency(void)
 {
 	return vr41xx_tclock;
 }
 
+EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency);
+
 static inline uint16_t read_clkspeed(void)
 {
 	switch (current_cpu_data.cputype) {
@@ -207,7 +207,7 @@ static inline unsigned long calculate_tc
 	return tclock;
 }
 
-static int __init vr41xx_bcu_init(void)
+void vr41xx_calculate_clock_frequency(void)
 {
 	unsigned long pclock;
 	uint16_t clkspeed;
@@ -217,11 +217,6 @@ static int __init vr41xx_bcu_init(void)
 	pclock = calculate_pclock(clkspeed);
 	vr41xx_vtclock = calculate_vtclock(clkspeed, pclock);
 	vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock);
-
-	iomem_resource.start = IO_MEM_RESOURCE_START;
-	iomem_resource.end = IO_MEM_RESOURCE_END;
-
-	return 0;
 }
 
-early_initcall(vr41xx_bcu_init);
+EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency);
diff --git a/arch/mips/vr41xx/common/cmu.c b/arch/mips/vr41xx/common/cmu.c
--- a/arch/mips/vr41xx/common/cmu.c
+++ b/arch/mips/vr41xx/common/cmu.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copuright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copuright (C) 2003-2005  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
@@ -29,6 +29,8 @@
  *  - Added support for NEC VR4133.
  */
 #include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -37,8 +39,16 @@
 #include <asm/io.h>
 #include <asm/vr41xx/vr41xx.h>
 
-#define CMUCLKMSK_TYPE1	KSEG1ADDR(0x0b000060)
-#define CMUCLKMSK_TYPE2	KSEG1ADDR(0x0f000060)
+#define CMU_TYPE1_BASE	0x0b000060UL
+#define CMU_TYPE1_SIZE	0x4
+
+#define CMU_TYPE2_BASE	0x0f000060UL
+#define CMU_TYPE2_SIZE	0x4
+
+#define CMU_TYPE3_BASE	0x0f000060UL
+#define CMU_TYPE3_SIZE	0x8
+
+#define CMUCLKMSK	0x0
  #define MSKPIU		0x0001
  #define MSKSIU		0x0002
  #define MSKAIU		0x0004
@@ -52,19 +62,17 @@
  #define MSKFFIR	0x0400
  #define MSKSCSI	0x1000
  #define MSKPPCIU	0x2000
-#define CMUCLKMSK2	KSEG1ADDR(0x0f000064)
+#define CMUCLKMSK2	0x4
  #define MSKCEU		0x0001
  #define MSKMAC0	0x0002
  #define MSKMAC1	0x0004
 
-static uint32_t cmu_base;
+static void __iomem *cmu_base;
 static uint16_t cmuclkmsk, cmuclkmsk2;
 static spinlock_t cmu_lock;
 
-#define read_cmuclkmsk()	readw(cmu_base)
-#define read_cmuclkmsk2()	readw(CMUCLKMSK2)
-#define write_cmuclkmsk()	writew(cmuclkmsk, cmu_base)
-#define write_cmuclkmsk2()	writew(cmuclkmsk2, CMUCLKMSK2)
+#define cmu_read(offset)		readw(cmu_base + (offset))
+#define cmu_write(offset, value)	writew((value), cmu_base + (offset))
 
 void vr41xx_supply_clock(vr41xx_clock_t clock)
 {
@@ -120,13 +128,15 @@ void vr41xx_supply_clock(vr41xx_clock_t 
 
 	if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
 	    clock == ETHER1_CLOCK)
-		write_cmuclkmsk2();
+		cmu_write(CMUCLKMSK2, cmuclkmsk2);
 	else
-		write_cmuclkmsk();
+		cmu_write(CMUCLKMSK, cmuclkmsk);
 
 	spin_unlock_irq(&cmu_lock);
 }
 
+EXPORT_SYMBOL_GPL(vr41xx_supply_clock);
+
 void vr41xx_mask_clock(vr41xx_clock_t clock)
 {
 	spin_lock_irq(&cmu_lock);
@@ -160,7 +170,7 @@ void vr41xx_mask_clock(vr41xx_clock_t cl
 		    current_cpu_data.cputype == CPU_VR4121) {
 			cmuclkmsk &= ~MSKDSIU;
 		} else {
-			if (cmuclkmsk & MSKSIU)
+			if (cmuclkmsk & MSKSSIU)
 				cmuclkmsk &= ~MSKDSIU;
 			else
 				cmuclkmsk &= ~(MSKSIU | MSKDSIU);
@@ -193,38 +203,55 @@ void vr41xx_mask_clock(vr41xx_clock_t cl
 
 	if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
 	    clock == ETHER1_CLOCK)
-		write_cmuclkmsk2();
+		cmu_write(CMUCLKMSK2, cmuclkmsk2);
 	else
-		write_cmuclkmsk();
+		cmu_write(CMUCLKMSK, cmuclkmsk);
 
 	spin_unlock_irq(&cmu_lock);
 }
 
+EXPORT_SYMBOL_GPL(vr41xx_mask_clock);
+
 static int __init vr41xx_cmu_init(void)
 {
+	unsigned long start, size;
+
 	switch (current_cpu_data.cputype) {
         case CPU_VR4111:
         case CPU_VR4121:
-                cmu_base = CMUCLKMSK_TYPE1;
+		start = CMU_TYPE1_BASE;
+		size = CMU_TYPE1_SIZE;
                 break;
         case CPU_VR4122:
         case CPU_VR4131:
-                cmu_base = CMUCLKMSK_TYPE2;
-                break;
+		start = CMU_TYPE2_BASE;
+		size = CMU_TYPE2_SIZE;
+		break;
         case CPU_VR4133:
-                cmu_base = CMUCLKMSK_TYPE2;
-		cmuclkmsk2 = read_cmuclkmsk2();
+		start = CMU_TYPE3_BASE;
+		size = CMU_TYPE3_SIZE;
                 break;
 	default:
 		panic("Unexpected CPU of NEC VR4100 series");
 		break;
         }
 
-	cmuclkmsk = read_cmuclkmsk();
+	if (request_mem_region(start, size, "CMU") == NULL)
+		return -EBUSY;
+
+	cmu_base = ioremap(start, size);
+	if (cmu_base == NULL) {
+		release_mem_region(start, size);
+		return -EBUSY;
+	}
+
+	cmuclkmsk = cmu_read(CMUCLKMSK);
+	if (current_cpu_data.cputype == CPU_VR4133)
+		cmuclkmsk2 = cmu_read(CMUCLKMSK2);
 
 	spin_lock_init(&cmu_lock);
 
 	return 0;
 }
 
-early_initcall(vr41xx_cmu_init);
+core_initcall(vr41xx_cmu_init);
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -1,7 +1,7 @@
 /*
  *  init.c, Common initialization routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2003-2005  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
@@ -18,9 +18,45 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
 #include <linux/string.h>
 
 #include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define IO_MEM_RESOURCE_START	0UL
+#define IO_MEM_RESOURCE_END	0x1fffffffUL
+
+static void __init iomem_resource_init(void)
+{
+	iomem_resource.start = IO_MEM_RESOURCE_START;
+	iomem_resource.end = IO_MEM_RESOURCE_END;
+}
+
+static void __init setup_timer_frequency(void)
+{
+	unsigned long tclock;
+
+	tclock = vr41xx_get_tclock_frequency();
+	if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 ||
+	    current_cpu_data.processor_id == PRID_VR4131_REV2_1)
+		mips_hpt_frequency = tclock / 2;
+	else
+		mips_hpt_frequency = tclock / 4;
+}
+
+static void __init setup_timer_irq(struct irqaction *irq)
+{
+	setup_irq(TIMER_IRQ, irq);
+}
+
+static void __init timer_init(void)
+{
+	board_time_init = setup_timer_frequency;
+	board_timer_setup = setup_timer_irq;
+}
 
 void __init prom_init(void)
 {
@@ -35,6 +71,12 @@ void __init prom_init(void)
 		if (i < (argc - 1))
 			strcat(arcs_cmdline, " ");
 	}
+
+	vr41xx_calculate_clock_frequency();
+
+	timer_init();
+
+	iomem_resource_init();
 }
 
 unsigned long __init prom_free_prom_memory (void)
diff --git a/arch/mips/vr41xx/common/ksyms.c b/arch/mips/vr41xx/common/ksyms.c
deleted file mode 100644
--- a/arch/mips/vr41xx/common/ksyms.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *   ksyms.c, Export NEC VR4100 series specific functions needed for loadable modules.
- *
- *  Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *  Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.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 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/module.h>
-
-#include <asm/vr41xx/vr41xx.h>
-
-EXPORT_SYMBOL(vr41xx_get_vtclock_frequency);
-EXPORT_SYMBOL(vr41xx_get_tclock_frequency);
-
-EXPORT_SYMBOL(vr41xx_set_rtclong1_cycle);
-EXPORT_SYMBOL(vr41xx_read_rtclong1_counter);
-EXPORT_SYMBOL(vr41xx_set_rtclong2_cycle);
-EXPORT_SYMBOL(vr41xx_read_rtclong2_counter);
-EXPORT_SYMBOL(vr41xx_set_tclock_cycle);
-EXPORT_SYMBOL(vr41xx_read_tclock_counter);
diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c
--- a/arch/mips/vr41xx/common/pmu.c
+++ b/arch/mips/vr41xx/common/pmu.c
@@ -1,7 +1,7 @@
 /*
  *  pmu.c, Power Management Unit routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2003-2005  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
@@ -17,7 +17,9 @@
  *  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/errno.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/types.h>
@@ -27,20 +29,31 @@
 #include <asm/reboot.h>
 #include <asm/system.h>
 
-#define PMUCNT2REG	KSEG1ADDR(0x0f0000c6)
+#define PMU_TYPE1_BASE	0x0b0000a0UL
+#define PMU_TYPE1_SIZE	0x0eUL
+
+#define PMU_TYPE2_BASE	0x0f0000c0UL
+#define PMU_TYPE2_SIZE	0x10UL
+
+#define PMUCNT2REG	0x06
  #define SOFTRST	0x0010
 
+static void __iomem *pmu_base;
+
+#define pmu_read(offset)		readw(pmu_base + (offset))
+#define pmu_write(offset, value)	writew((value), pmu_base + (offset))
+
 static inline void software_reset(void)
 {
-	uint16_t val;
+	uint16_t pmucnt2;
 
 	switch (current_cpu_data.cputype) {
 	case CPU_VR4122:
 	case CPU_VR4131:
 	case CPU_VR4133:
-		val = readw(PMUCNT2REG);
-		val |= SOFTRST;
-		writew(val, PMUCNT2REG);
+		pmucnt2 = pmu_read(PMUCNT2REG);
+		pmucnt2 |= SOFTRST;
+		pmu_write(PMUCNT2REG, pmucnt2);
 		break;
 	default:
 		break;
@@ -71,6 +84,34 @@ static void vr41xx_power_off(void)
 
 static int __init vr41xx_pmu_init(void)
 {
+	unsigned long start, size;
+
+	switch (current_cpu_data.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		start = PMU_TYPE1_BASE;
+		size = PMU_TYPE1_SIZE;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+	case CPU_VR4133:
+		start = PMU_TYPE2_BASE;
+		size = PMU_TYPE2_SIZE;
+		break;
+	default:
+		printk("Unexpected CPU of NEC VR4100 series\n");
+		return -ENODEV;
+	}
+
+	if (request_mem_region(start, size, "PMU") == NULL)
+		return -EBUSY;
+
+	pmu_base = ioremap(start, size);
+	if (pmu_base == NULL) {
+		release_mem_region(start, size);
+		return -EBUSY;
+	}
+
 	_machine_restart = vr41xx_restart;
 	_machine_halt = vr41xx_halt;
 	_machine_power_off = vr41xx_power_off;
@@ -78,4 +119,4 @@ static int __init vr41xx_pmu_init(void)
 	return 0;
 }
 
-early_initcall(vr41xx_pmu_init);
+core_initcall(vr41xx_pmu_init);
diff --git a/arch/mips/vr41xx/common/rtc.c b/arch/mips/vr41xx/common/rtc.c
deleted file mode 100644
--- a/arch/mips/vr41xx/common/rtc.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- *  rtc.c, RTC(has only timer function) routines for NEC VR4100 series.
- *
- *  Copyright (C) 2003-2004  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.
- *
- *  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/irq.h>
-#include <linux/smp.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/time.h>
-#include <asm/vr41xx/vr41xx.h>
-
-static uint32_t rtc1_base;
-static uint32_t rtc2_base;
-
-static uint64_t previous_elapsedtime;
-static unsigned int remainder_per_sec;
-static unsigned int cycles_per_sec;
-static unsigned int cycles_per_jiffy;
-static unsigned long epoch_time;
-
-#define CYCLES_PER_JIFFY	(CLOCK_TICK_RATE / HZ)
-#define REMAINDER_PER_SEC	(CLOCK_TICK_RATE - (CYCLES_PER_JIFFY * HZ))
-#define CYCLES_PER_100USEC	((CLOCK_TICK_RATE + (10000 / 2)) / 10000)
-
-#define ETIMELREG_TYPE1		KSEG1ADDR(0x0b0000c0)
-#define TCLKLREG_TYPE1		KSEG1ADDR(0x0b0001c0)
-
-#define ETIMELREG_TYPE2		KSEG1ADDR(0x0f000100)
-#define TCLKLREG_TYPE2		KSEG1ADDR(0x0f000120)
-
-/* RTC 1 registers */
-#define ETIMELREG		0x00
-#define ETIMEMREG		0x02
-#define ETIMEHREG		0x04
-/* RFU */
-#define ECMPLREG		0x08
-#define ECMPMREG		0x0a
-#define ECMPHREG		0x0c
-/* RFU */
-#define RTCL1LREG		0x10
-#define RTCL1HREG		0x12
-#define RTCL1CNTLREG		0x14
-#define RTCL1CNTHREG		0x16
-#define RTCL2LREG		0x18
-#define RTCL2HREG		0x1a
-#define RTCL2CNTLREG		0x1c
-#define RTCL2CNTHREG		0x1e
-
-/* RTC 2 registers */
-#define TCLKLREG		0x00
-#define TCLKHREG		0x02
-#define TCLKCNTLREG		0x04
-#define TCLKCNTHREG		0x06
-/* RFU */
-#define RTCINTREG		0x1e
- #define TCLOCK_INT		0x08
- #define RTCLONG2_INT		0x04
- #define RTCLONG1_INT		0x02
- #define ELAPSEDTIME_INT	0x01
-
-#define read_rtc1(offset)	readw(rtc1_base + (offset))
-#define write_rtc1(val, offset)	writew((val), rtc1_base + (offset))
-
-#define read_rtc2(offset)	readw(rtc2_base + (offset))
-#define write_rtc2(val, offset)	writew((val), rtc2_base + (offset))
-
-static inline uint64_t read_elapsedtime_counter(void)
-{
-	uint64_t first, second;
-	uint32_t first_mid, first_low;
-	uint32_t second_mid, second_low;
-
-	do {
-		first_low = (uint32_t)read_rtc1(ETIMELREG);
-		first_mid = (uint32_t)read_rtc1(ETIMEMREG);
-		first = (uint64_t)read_rtc1(ETIMEHREG);
-		second_low = (uint32_t)read_rtc1(ETIMELREG);
-		second_mid = (uint32_t)read_rtc1(ETIMEMREG);
-		second = (uint64_t)read_rtc1(ETIMEHREG);
-	} while (first_low != second_low || first_mid != second_mid ||
-	         first != second);
-
-	return (first << 32) | (uint64_t)((first_mid << 16) | first_low);
-}
-
-static inline void write_elapsedtime_counter(uint64_t time)
-{
-	write_rtc1((uint16_t)time, ETIMELREG);
-	write_rtc1((uint16_t)(time >> 16), ETIMEMREG);
-	write_rtc1((uint16_t)(time >> 32), ETIMEHREG);
-}
-
-static inline void write_elapsedtime_compare(uint64_t time)
-{
-	write_rtc1((uint16_t)time, ECMPLREG);
-	write_rtc1((uint16_t)(time >> 16), ECMPMREG);
-	write_rtc1((uint16_t)(time >> 32), ECMPHREG);
-}
-
-void vr41xx_set_rtclong1_cycle(uint32_t cycles)
-{
-	write_rtc1((uint16_t)cycles, RTCL1LREG);
-	write_rtc1((uint16_t)(cycles >> 16), RTCL1HREG);
-}
-
-uint32_t vr41xx_read_rtclong1_counter(void)
-{
-	uint32_t first_high, first_low;
-	uint32_t second_high, second_low;
-
-	do {
-		first_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
-		first_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
-		second_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
-		second_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
-	} while (first_low != second_low || first_high != second_high);
-
-	return (first_high << 16) | first_low;
-}
-
-void vr41xx_set_rtclong2_cycle(uint32_t cycles)
-{
-	write_rtc1((uint16_t)cycles, RTCL2LREG);
-	write_rtc1((uint16_t)(cycles >> 16), RTCL2HREG);
-}
-
-uint32_t vr41xx_read_rtclong2_counter(void)
-{
-	uint32_t first_high, first_low;
-	uint32_t second_high, second_low;
-
-	do {
-		first_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
-		first_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
-		second_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
-		second_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
-	} while (first_low != second_low || first_high != second_high);
-
-	return (first_high << 16) | first_low;
-}
-
-void vr41xx_set_tclock_cycle(uint32_t cycles)
-{
-	write_rtc2((uint16_t)cycles, TCLKLREG);
-	write_rtc2((uint16_t)(cycles >> 16), TCLKHREG);
-}
-
-uint32_t vr41xx_read_tclock_counter(void)
-{
-	uint32_t first_high, first_low;
-	uint32_t second_high, second_low;
-
-	do {
-		first_low = (uint32_t)read_rtc2(TCLKCNTLREG);
-		first_high = (uint32_t)read_rtc2(TCLKCNTHREG);
-		second_low = (uint32_t)read_rtc2(TCLKCNTLREG);
-		second_high = (uint32_t)read_rtc2(TCLKCNTHREG);
-	} while (first_low != second_low || first_high != second_high);
-
-	return (first_high << 16) | first_low;
-}
-
-static void vr41xx_timer_ack(void)
-{
-	uint64_t cur;
-
-	write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
-
-	previous_elapsedtime += (uint64_t)cycles_per_jiffy;
-	cycles_per_sec += cycles_per_jiffy;
-
-	if (cycles_per_sec >= CLOCK_TICK_RATE) {
-		cycles_per_sec = 0;
-		remainder_per_sec = REMAINDER_PER_SEC;
-	}
-
-	cycles_per_jiffy = 0;
-
-	do {
-		cycles_per_jiffy += CYCLES_PER_JIFFY;
-		if (remainder_per_sec > 0) {
-			cycles_per_jiffy++;
-			remainder_per_sec--;
-		}
-
-		cur = read_elapsedtime_counter();
-	} while (cur >= previous_elapsedtime + (uint64_t)cycles_per_jiffy);
-
-	write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
-}
-
-static void vr41xx_hpt_init(unsigned int count)
-{
-}
-
-static unsigned int vr41xx_hpt_read(void)
-{
-	uint64_t cur;
-
-	cur = read_elapsedtime_counter();
-
-	return (unsigned int)cur;
-}
-
-static unsigned long vr41xx_gettimeoffset(void)
-{
-	uint64_t cur;
-	unsigned long gap;
-
-	cur = read_elapsedtime_counter();
-	gap = (unsigned long)(cur - previous_elapsedtime);
-	gap = gap / CYCLES_PER_100USEC * 100;	/* usec */
-
-	return gap;
-}
-
-static unsigned long vr41xx_get_time(void)
-{
-	uint64_t counts;
-
-	counts = read_elapsedtime_counter();
-	counts >>= 15;
-
-	return epoch_time + (unsigned long)counts;
-
-}
-
-static int vr41xx_set_time(unsigned long sec)
-{
-	if (sec < epoch_time)
-		return -EINVAL;
-
-	sec -= epoch_time;
-
-	write_elapsedtime_counter((uint64_t)sec << 15);
-
-	return 0;
-}
-
-void vr41xx_set_epoch_time(unsigned long time)
-{
-	epoch_time = time;
-}
-
-static void __init vr41xx_time_init(void)
-{
-	switch (current_cpu_data.cputype) {
-	case CPU_VR4111:
-	case CPU_VR4121:
-		rtc1_base = ETIMELREG_TYPE1;
-		rtc2_base = TCLKLREG_TYPE1;
-		break;
-	case CPU_VR4122:
-	case CPU_VR4131:
-	case CPU_VR4133:
-		rtc1_base = ETIMELREG_TYPE2;
-		rtc2_base = TCLKLREG_TYPE2;
-		break;
-	default:
-		panic("Unexpected CPU of NEC VR4100 series");
-		break;
-	}
-
-	mips_timer_ack = vr41xx_timer_ack;
-
-	mips_hpt_init = vr41xx_hpt_init;
-	mips_hpt_read = vr41xx_hpt_read;
-	mips_hpt_frequency = CLOCK_TICK_RATE;
-
-	if (epoch_time == 0)
-		epoch_time = mktime(1970, 1, 1, 0, 0, 0);
-
-	rtc_get_time = vr41xx_get_time;
-	rtc_set_time = vr41xx_set_time;
-}
-
-static void __init vr41xx_timer_setup(struct irqaction *irq)
-{
-	do_gettimeoffset = vr41xx_gettimeoffset;
-
-	remainder_per_sec = REMAINDER_PER_SEC;
-	cycles_per_jiffy = CYCLES_PER_JIFFY;
-
-	if (remainder_per_sec > 0) {
-		cycles_per_jiffy++;
-		remainder_per_sec--;
-	}
-
-	previous_elapsedtime = read_elapsedtime_counter();
-	write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
-	write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
-
-	setup_irq(ELAPSEDTIME_IRQ, irq);
-}
-
-static int __init vr41xx_rtc_init(void)
-{
-	board_time_init = vr41xx_time_init;
-	board_timer_setup = vr41xx_timer_setup;
-
-	return 0;
-}
-
-early_initcall(vr41xx_rtc_init);
diff --git a/arch/mips/vr41xx/common/serial.c b/arch/mips/vr41xx/common/serial.c
deleted file mode 100644
--- a/arch/mips/vr41xx/common/serial.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  serial.c, Serial Interface Unit routines for NEC VR4100 series.
- *
- *  Copyright (C) 2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2004  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.
- *
- *  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
- */
-/*
- * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
- *  - New creation, NEC VR4122 and VR4131 are supported.
- *  - Added support for NEC VR4111 and VR4121.
- *
- *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *  - Added support for NEC VR4133.
- */
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/smp.h>
-
-#include <asm/addrspace.h>
-#include <asm/cpu.h>
-#include <asm/io.h>
-#include <asm/vr41xx/vr41xx.h>
-
-#define SIUIRSEL_TYPE1		KSEG1ADDR(0x0c000008)
-#define SIUIRSEL_TYPE2		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_TYPE1		0x0c000000UL	/* VR4111 and VR4121 */
-#define SIU_BASE_TYPE2		0x0f000800UL	/* VR4122, VR4131 and VR4133 */
-#define SIU_SIZE		0x8UL
-
-#define SIU_BASE_BAUD		1152000
-
-/* VR4122, VR4131 and VR4133 DSIU Registers */
-#define DSIU_BASE		0x0f000820UL
-#define DSIU_SIZE		0x8UL
-
-#define DSIU_BASE_BAUD		1152000
-
-int vr41xx_serial_ports = 0;
-
-void vr41xx_select_siu_interface(siu_interface_t interface,
-                                 irda_module_t module)
-{
-	uint16_t 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;
-		default:
-			printk(KERN_ERR "SIU: unknown IrDA module\n");
-			return;
-		}
-		val |= USE_IRDA | SIU_USES_IRDA;
-	}
-
-	switch (current_cpu_data.cputype) {
-	case CPU_VR4111:
-	case CPU_VR4121:
-		writew(val, SIUIRSEL_TYPE1);
-		break;
-	case CPU_VR4122:
-	case CPU_VR4131:
-	case CPU_VR4133:
-		writew(val, SIUIRSEL_TYPE2);
-		break;
-	default:
-		printk(KERN_ERR "SIU: unsupported CPU of NEC VR4100 series\n");
-		break;
-	}
-}
-
-void __init vr41xx_siu_init(void)
-{
-	struct uart_port port;
-
-	memset(&port, 0, sizeof(port));
-
-	port.line = vr41xx_serial_ports;
-	port.uartclk = SIU_BASE_BAUD * 16;
-	port.irq = SIU_IRQ;
-	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
-	switch (current_cpu_data.cputype) {
-	case CPU_VR4111:
-	case CPU_VR4121:
-		port.mapbase = SIU_BASE_TYPE1;
-		break;
-	case CPU_VR4122:
-	case CPU_VR4131:
-	case CPU_VR4133:
-		port.mapbase = SIU_BASE_TYPE2;
-		break;
-	default:
-		printk(KERN_ERR "SIU: unsupported CPU of NEC VR4100 series\n");
-		return;
-	}
-	port.regshift = 0;
-	port.iotype = UPIO_MEM;
-	port.membase = ioremap(port.mapbase, SIU_SIZE);
-	if (port.membase != NULL) {
-		if (early_serial_setup(&port) == 0) {
-			vr41xx_supply_clock(SIU_CLOCK);
-			vr41xx_serial_ports++;
-			return;
-		}
-	}
-
-	printk(KERN_ERR "SIU: setup failed!\n");
-}
-
-void __init vr41xx_dsiu_init(void)
-{
-	struct uart_port port;
-
-	if (current_cpu_data.cputype != CPU_VR4122 &&
-	    current_cpu_data.cputype != CPU_VR4131 &&
-	    current_cpu_data.cputype != CPU_VR4133) {
-		printk(KERN_ERR "DSIU: unsupported CPU of NEC VR4100 series\n");
-		return;
-	}
-
-	memset(&port, 0, sizeof(port));
-
-	port.line = vr41xx_serial_ports;
-	port.uartclk = DSIU_BASE_BAUD * 16;
-	port.irq = DSIU_IRQ;
-	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
-	port.mapbase = DSIU_BASE;
-	port.regshift = 0;
-	port.iotype = UPIO_MEM;
-	port.membase = ioremap(port.mapbase, DSIU_SIZE);
-	if (port.membase != NULL) {
-		if (early_serial_setup(&port) == 0) {
-			vr41xx_supply_clock(DSIU_CLOCK);
-			vr41xx_enable_dsiuint(DSIUINT_ALL);
-			vr41xx_serial_ports++;
-			return;
-		}
-	}
-
-	printk(KERN_ERR "DSIU: setup failed!\n");
-}
diff --git a/arch/mips/vr41xx/common/vrc4171.c b/arch/mips/vr41xx/common/vrc4171.c
deleted file mode 100644
--- a/arch/mips/vr41xx/common/vrc4171.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *  vrc4171.c, NEC VRC4171 base driver.
- *
- *  Copyright (C) 2003  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.
- *
- *  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/ioport.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/vrc4171.h>
-
-MODULE_DESCRIPTION("NEC VRC4171 base driver");
-MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(vrc4171_get_irq_status);
-EXPORT_SYMBOL_GPL(vrc4171_set_multifunction_pin);
-
-#define CONFIGURATION1		0x05fe
- #define SLOTB_CONFIG		0xc000
- #define SLOTB_NONE		0x0000
- #define SLOTB_PCCARD		0x4000
- #define SLOTB_CF		0x8000
- #define SLOTB_FLASHROM		0xc000
-
-#define CONFIGURATION2		0x05fc
-#define INTERRUPT_STATUS	0x05fa
-#define PCS_CONTROL		0x05ee
-#define GPIO_DATA		PCS_CONTROL
-#define PCS0_UPPER_START	0x05ec
-#define PCS0_LOWER_START	0x05ea
-#define PCS0_UPPER_STOP		0x05e8
-#define PCS0_LOWER_STOP		0x05e6
-#define PCS1_UPPER_START	0x05e4
-#define PCS1_LOWER_START	0x05e2
-#define PCS1_UPPER_STOP		0x05de
-#define PCS1_LOWER_STOP		0x05dc
-
-#define VRC4171_REGS_BASE	PCS1_LOWER_STOP
-#define VRC4171_REGS_SIZE	0x24
-
-uint16_t vrc4171_get_irq_status(void)
-{
-	return inw(INTERRUPT_STATUS);
-}
-
-void vrc4171_set_multifunction_pin(int config)
-{
-	uint16_t config1;
-
-	config1 = inw(CONFIGURATION1);
-	config1 &= ~SLOTB_CONFIG;
-
-	switch (config) {
-	case SLOTB_IS_NONE:
-		config1 |= SLOTB_NONE;
-		break;
-	case SLOTB_IS_PCCARD:
-		config1 |= SLOTB_PCCARD;
-		break;
-	case SLOTB_IS_CF:
-		config1 |= SLOTB_CF;
-		break;
-	case SLOTB_IS_FLASHROM:
-		config1 |= SLOTB_FLASHROM;
-		break;
-	default:
-		break;
-	}
-
-	outw(config1, CONFIGURATION1);
-}
-
-static int __devinit vrc4171_init(void)
-{
-	if (request_region(VRC4171_REGS_BASE, VRC4171_REGS_SIZE, "NEC VRC4171") == NULL)
-		return -EBUSY;
-
-	printk(KERN_INFO "NEC VRC4171 base driver\n");
-
-	return 0;
-}
-
-static void __devexit vrc4171_exit(void)
-{
-	release_region(VRC4171_REGS_BASE, VRC4171_REGS_SIZE);
-}
-
-module_init(vrc4171_init);
-module_exit(vrc4171_exit);
diff --git a/arch/mips/vr41xx/ibm-workpad/setup.c b/arch/mips/vr41xx/ibm-workpad/setup.c
--- a/arch/mips/vr41xx/ibm-workpad/setup.c
+++ b/arch/mips/vr41xx/ibm-workpad/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the IBM WorkPad z50.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  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
@@ -17,7 +17,7 @@
  *  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/ioport.h>
 
 #include <asm/io.h>
@@ -28,18 +28,13 @@ const char *get_system_type(void)
 	return "IBM WorkPad z50";
 }
 
-static int ibm_workpad_setup(void)
+static int __init ibm_workpad_setup(void)
 {
 	set_io_port_base(IO_PORT_BASE);
 	ioport_resource.start = IO_PORT_RESOURCE_START;
 	ioport_resource.end = IO_PORT_RESOURCE_END;
 
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-#endif
-
 	return 0;
 }
 
-early_initcall(ibm_workpad_setup);
+arch_initcall(ibm_workpad_setup);
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/setup.c b/arch/mips/vr41xx/nec-cmbvr4133/setup.c
--- a/arch/mips/vr41xx/nec-cmbvr4133/setup.c
+++ b/arch/mips/vr41xx/nec-cmbvr4133/setup.c
@@ -16,7 +16,6 @@
  */
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/console.h>
 #include <linux/ide.h>
 #include <linux/ioport.h>
 
@@ -55,15 +54,6 @@ static struct mtd_partition cmbvr4133_mt
 #define number_partitions (sizeof(cmbvr4133_mtd_parts)/sizeof(struct mtd_partition))
 #endif
 
-extern void (*late_time_init)(void);
-
-static void __init vr4133_serial_init(void)
-{
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-	vr41xx_dsiu_init();
-}
-
 extern void i8259_init(void);
 
 static int __init nec_cmbvr4133_setup(void)
@@ -78,8 +68,6 @@ static int __init nec_cmbvr4133_setup(vo
 	mips_machgroup = MACH_GROUP_NEC_VR41XX;
 	mips_machtype = MACH_NEC_CMBVR4133;
 
-	late_time_init = vr4133_serial_init;
-
 #ifdef CONFIG_PCI
 #ifdef CONFIG_ROCKHOPPER
 	ali_m5229_preinit();
diff --git a/arch/mips/vr41xx/tanbac-tb0226/setup.c b/arch/mips/vr41xx/tanbac-tb0226/setup.c
--- a/arch/mips/vr41xx/tanbac-tb0226/setup.c
+++ b/arch/mips/vr41xx/tanbac-tb0226/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the TANBAC TB0226.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  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
@@ -17,23 +17,8 @@
  *  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/vr41xx/vr41xx.h>
 
 const char *get_system_type(void)
 {
 	return "TANBAC TB0226";
 }
-
-static int tanbac_tb0226_setup(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-#endif
-
-	return 0;
-}
-
-early_initcall(tanbac_tb0226_setup);
diff --git a/arch/mips/vr41xx/tanbac-tb0229/Makefile b/arch/mips/vr41xx/tanbac-tb0229/Makefile
--- a/arch/mips/vr41xx/tanbac-tb0229/Makefile
+++ b/arch/mips/vr41xx/tanbac-tb0229/Makefile
@@ -3,5 +3,3 @@
 #
 
 obj-y				:= setup.o
-
-obj-$(CONFIG_TANBAC_TB0219)	+= tb0219.o
diff --git a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c
--- a/arch/mips/vr41xx/tanbac-tb0229/setup.c
+++ b/arch/mips/vr41xx/tanbac-tb0229/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the TANBAC TB0229 (VR4131DIMM)
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  *  Modified for TANBAC TB0229:
  *  Copyright (C) 2003  Megasolution Inc.  <matsu@megasolution.jp>
@@ -20,24 +20,8 @@
  *  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/vr41xx/vr41xx.h>
 
 const char *get_system_type(void)
 {
 	return "TANBAC TB0229";
 }
-
-static int tanbac_tb0229_setup(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-	vr41xx_dsiu_init();
-#endif
-
-	return 0;
-}
-
-early_initcall(tanbac_tb0229_setup);
diff --git a/arch/mips/vr41xx/tanbac-tb0229/tb0219.c b/arch/mips/vr41xx/tanbac-tb0229/tb0219.c
deleted file mode 100644
--- a/arch/mips/vr41xx/tanbac-tb0229/tb0219.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  tb0219.c, Setup for the TANBAC TB0219
- *
- *  Copyright (C) 2003  Megasolution Inc. <matsu@megasolution.jp>
- *  Copyright (C) 2004  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.
- *
- *  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 <asm/io.h>
-#include <asm/reboot.h>
-
-#define TB0219_RESET_REGS	KSEG1ADDR(0x0a00000e)
-
-#define tb0219_hard_reset()	writew(0, TB0219_RESET_REGS)
-
-static void tanbac_tb0219_restart(char *command)
-{
-	local_irq_disable();
-	tb0219_hard_reset();
-	while (1);
-}
-
-static int __init tanbac_tb0219_setup(void)
-{
-	_machine_restart = tanbac_tb0219_restart;
-
-	return 0;
-}
-
-early_initcall(tanbac_tb0219_setup);
diff --git a/arch/mips/vr41xx/victor-mpc30x/setup.c b/arch/mips/vr41xx/victor-mpc30x/setup.c
--- a/arch/mips/vr41xx/victor-mpc30x/setup.c
+++ b/arch/mips/vr41xx/victor-mpc30x/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the Victor MP-C303/304.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  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
@@ -17,23 +17,8 @@
  *  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/vr41xx/vr41xx.h>
 
 const char *get_system_type(void)
 {
 	return "Victor MP-C303/304";
 }
-
-static int victor_mpc30x_setup(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-#endif
-
-	return 0;
-}
-
-early_initcall(victor_mpc30x_setup);
diff --git a/arch/mips/vr41xx/zao-capcella/setup.c b/arch/mips/vr41xx/zao-capcella/setup.c
--- a/arch/mips/vr41xx/zao-capcella/setup.c
+++ b/arch/mips/vr41xx/zao-capcella/setup.c
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the ZAO Networks Capcella.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2002-2005  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
@@ -17,24 +17,8 @@
  *  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/vr41xx/vr41xx.h>
 
 const char *get_system_type(void)
 {
 	return "ZAO Networks Capcella";
 }
-
-static int zao_capcella_setup(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	vr41xx_select_siu_interface(SIU_RS232C, IRDA_NONE);
-	vr41xx_siu_init();
-	vr41xx_dsiu_init();
-#endif
-
-	return 0;
-}
-
-early_initcall(zao_capcella_setup);
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -6,8 +6,7 @@
 mainmenu "Linux/PA-RISC Kernel Configuration"
 
 config PARISC
-	bool
-	default y
+	def_bool y
 	help
 	  The PA-RISC microprocessor is designed by Hewlett-Packard and used
 	  in many of their workstations & servers (HP9000 700 and 800 series,
@@ -15,19 +14,16 @@ config PARISC
 	  at <http://www.parisc-linux.org/>.
 
 config MMU
-	bool
-	default y
+	def_bool y
 
 config STACK_GROWSUP
-	bool
-	default y
+	def_bool y
 
 config UID16
 	bool
 
 config RWSEM_GENERIC_SPINLOCK
-	bool
-	default y
+	def_bool y
 
 config RWSEM_XCHGADD_ALGORITHM
 	bool
@@ -49,6 +45,10 @@ config GENERIC_IRQ_PROBE
 config PM
 	bool
 
+config ISA_DMA_API
+	bool
+	default y
+
 source "init/Kconfig"
 
 
@@ -111,7 +111,7 @@ config PREFETCH
 	def_bool y
 	depends on PA8X00
 
-config PARISC64
+config 64BIT
 	bool "64-bit kernel"
 	depends on PA8X00
 	help
@@ -124,9 +124,6 @@ config PARISC64
 	  enable this option otherwise. The 64bit kernel is significantly bigger
 	  and slower than the 32bit one.
 
-config 64BIT
-	def_bool PARISC64
-
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
@@ -166,13 +163,12 @@ config PREEMPT
 	default n
 
 config COMPAT
-	bool
-	depends on PARISC64
-	default y
+	def_bool y
+	depends on 64BIT
 
 config HPUX
 	bool "Support for HP-UX binaries"
-	depends on !PARISC64
+	depends on !64BIT
 
 config NR_CPUS
 	int "Maximum number of CPUs (2-32)"
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -17,9 +17,12 @@
 # Mike Shaver, Helge Deller and Martin K. Petersen
 #
 NM		= sh $(srctree)/arch/parisc/nm
-ifdef CONFIG_PARISC64
+CHECKFLAGS	+= -D__hppa__=1
+
+ifdef CONFIG_64BIT
 CROSS_COMPILE	:= hppa64-linux-
 UTS_MACHINE	:= parisc64
+CHECKFLAGS	+= -D__LP64__=1 -m64
 else
 MACHINE := $(subst 64,,$(shell uname -m))
 ifneq ($(MACHINE),parisc)
@@ -65,8 +68,12 @@ libs-y	+= arch/parisc/lib/ `$(CC) -print
 
 drivers-$(CONFIG_OPROFILE)		+= arch/parisc/oprofile/
 
+PALO := $(shell if which palo; then : ; \
+	elif [ -x /sbin/palo ]; then echo /sbin/palo; \
+	fi)
+
 palo: vmlinux
-	@if [ $$(palo -f /dev/null >/dev/null 2>&1 ; echo $$?) != 2 ]; then \
+	@if [ -x $PALO ]; then \
 		echo 'ERROR: Please install palo first (apt-get install palo)';\
 		echo 'or build it from source and install it somewhere in your $$PATH';\
 		false; \
@@ -78,7 +85,7 @@ palo: vmlinux
 		echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
 		false; \
 	fi
-	palo -f ./palo.conf
+	$(PALO) -f ./palo.conf
 
 oldpalo: vmlinux
 	export TOPDIR=`pwd`; \
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -1,12 +1,15 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-pa5
-# Wed Jan  5 13:22:34 2005
+# Linux kernel version: 2.6.11-rc4-pa1
+# Wed Feb 16 11:32:49 2005
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
 
 #
 # Code maturity level options
@@ -68,7 +71,6 @@ CONFIG_STOP_MACHINE=y
 CONFIG_PA8X00=y
 CONFIG_PA20=y
 CONFIG_PREFETCH=y
-CONFIG_PARISC64=y
 CONFIG_64BIT=y
 CONFIG_SMP=y
 CONFIG_HOTPLUG_CPU=y
@@ -87,16 +89,12 @@ CONFIG_PCI_NAMES=y
 CONFIG_PCI_LBA=y
 CONFIG_IOSAPIC=y
 CONFIG_IOMMU_SBA=y
-# CONFIG_SUPERIO is not set
-# CONFIG_CHASSIS_LCD_LED is not set
-CONFIG_PDC_CHASSIS=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
 
@@ -107,6 +105,7 @@ CONFIG_YENTA=m
 CONFIG_PD6729=m
 CONFIG_I82092=m
 CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
 
 #
 # PCI Hotplug Support
@@ -114,6 +113,14 @@ CONFIG_TCIC=m
 # CONFIG_HOTPLUG_PCI is not set
 
 #
+# PA-RISC specific drivers
+#
+# CONFIG_SUPERIO is not set
+# CONFIG_CHASSIS_LCD_LED is not set
+CONFIG_PDC_CHASSIS=y
+CONFIG_PDC_STABLE=y
+
+#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
@@ -153,6 +160,7 @@ CONFIG_FW_LOADER=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_UMEM=m
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -171,6 +179,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -205,6 +214,7 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
 
 #
 # SCSI low-level drivers
@@ -231,10 +241,10 @@ CONFIG_SCSI_FC_ATTRS=m
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_IOMAPPED=y
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -249,7 +259,6 @@ CONFIG_SCSI_QLA2XXX=y
 CONFIG_SCSI_QLA2300=m
 CONFIG_SCSI_QLA2322=m
 CONFIG_SCSI_QLA6312=m
-CONFIG_SCSI_QLA6322=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 CONFIG_SCSI_DEBUG=m
@@ -399,8 +408,6 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -465,7 +472,7 @@ CONFIG_TYPHOON=m
 #
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
-CONFIG_TULIP=m
+CONFIG_TULIP=y
 # CONFIG_TULIP_MWI is not set
 CONFIG_TULIP_MMIO=y
 # CONFIG_TULIP_NAPI is not set
@@ -483,7 +490,6 @@ CONFIG_PCNET32=m
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=m
-# CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
 CONFIG_E100_NAPI=y
 # CONFIG_FEALNX is not set
@@ -524,6 +530,7 @@ CONFIG_IXGB=m
 CONFIG_IXGB_NAPI=y
 CONFIG_S2IO=m
 CONFIG_S2IO_NAPI=y
+# CONFIG_2BUFF_MODE is not set
 
 #
 # Token Ring devices
@@ -691,7 +698,6 @@ CONFIG_GEN_RTC_X=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -733,9 +739,9 @@ CONFIG_MAX_RAW_DEVS=256
 #
 # Console display driver support
 #
+CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
-CONFIG_DUMMY_CONSOLE=y
 
 #
 # Sound
@@ -764,6 +770,15 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_MMC is not set
 
 #
+# InfiniBand support
+#
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -775,10 +790,16 @@ CONFIG_JBD=y
 # CONFIG_REISERFS_FS is not set
 CONFIG_JFS_FS=m
 # CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
@@ -786,7 +807,7 @@ CONFIG_XFS_FS=m
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 
@@ -817,7 +838,8 @@ CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -935,6 +957,8 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_IOREMAP is not set
+# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_RWLOCK is not set
 
 #
@@ -973,6 +997,10 @@ CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/parisc/configs/n4000_defconfig b/arch/parisc/configs/n4000_defconfig
deleted file mode 100644
--- a/arch/parisc/configs/n4000_defconfig
+++ /dev/null
@@ -1,927 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-pa5
-# Wed Jan  5 13:40:36 2005
-#
-CONFIG_PARISC=y
-CONFIG_MMU=y
-CONFIG_STACK_GROWSUP=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# Processor type and features
-#
-# CONFIG_PA7000 is not set
-# CONFIG_PA7100LC is not set
-# CONFIG_PA7200 is not set
-# CONFIG_PA7300LC is not set
-CONFIG_PA8X00=y
-CONFIG_PA20=y
-CONFIG_PREFETCH=y
-CONFIG_PARISC64=y
-CONFIG_64BIT=y
-# CONFIG_SMP is not set
-CONFIG_DISCONTIGMEM=y
-# CONFIG_PREEMPT is not set
-CONFIG_COMPAT=y
-
-#
-# Bus options (PCI, PCMCIA, EISA, GSC, ISA)
-#
-# CONFIG_GSC is not set
-CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-CONFIG_PCI_LBA=y
-CONFIG_IOSAPIC=y
-CONFIG_IOMMU_SBA=y
-# CONFIG_SUPERIO is not set
-CONFIG_CHASSIS_LCD_LED=y
-# CONFIG_PDC_CHASSIS is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_FW_LOADER=y
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# 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_UMEM=m
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=6144
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-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_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=m
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA 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_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_IOMAPPED=y
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=m
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-CONFIG_SCSI_QLOGIC_1280=m
-# CONFIG_SCSI_QLOGIC_1280_1040 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-CONFIG_SCSI_QLA2300=m
-CONFIG_SCSI_QLA2322=m
-CONFIG_SCSI_QLA6312=m
-CONFIG_SCSI_QLA6322=m
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-CONFIG_SCSI_DEBUG=m
-
-#
-# 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_RAID10 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_RAID6 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_MD_FAULTY is not set
-# CONFIG_BLK_DEV_DM is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=m
-CONFIG_FUSION_MAX_SGE=40
-CONFIG_FUSION_CTL=m
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK_DEV=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=m
-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=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_SYN_COOKIES is not set
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=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_RECENT=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_OWNER=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=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_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=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_CLASSIFY=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-CONFIG_LLC=m
-CONFIG_LLC2=m
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-CONFIG_NET_CLS_ROUTE=y
-
-#
-# Network testing
-#
-CONFIG_NET_PKTGEN=m
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_ETHERTAP is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=m
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-CONFIG_NET_VENDOR_3COM=y
-CONFIG_VORTEX=m
-CONFIG_TYPHOON=m
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-CONFIG_DE2104X=y
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-CONFIG_TULIP_MMIO=y
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-CONFIG_HP100=m
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=m
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=m
-# CONFIG_EEPRO100_PIO is not set
-CONFIG_E100=m
-CONFIG_E100_NAPI=y
-# CONFIG_FEALNX is not set
-CONFIG_NATSEMI=m
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-CONFIG_8139TOO=m
-# 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=m
-# CONFIG_SUNDANCE is not set
-CONFIG_VIA_RHINE=m
-CONFIG_VIA_RHINE_MMIO=y
-
-#
-# Ethernet (1000 Mbit)
-#
-CONFIG_ACENIC=m
-CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_DL2K=m
-CONFIG_E1000=m
-CONFIG_E1000_NAPI=y
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_VIA_VELOCITY is not set
-CONFIG_TIGON3=m
-
-#
-# Ethernet (10000 Mbit)
-#
-CONFIG_IXGB=m
-CONFIG_IXGB_NAPI=y
-CONFIG_S2IO=m
-CONFIG_S2IO_NAPI=y
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-CONFIG_HERMES=m
-CONFIG_PLX_HERMES=m
-CONFIG_TMD_HERMES=m
-CONFIG_PCI_HERMES=m
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# 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 is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=8
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_MUX is not set
-CONFIG_PDC_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_GEN_RTC=y
-CONFIG_GEN_RTC_X=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-CONFIG_DUMMY_CONSOLE_COLUMNS=160
-CONFIG_DUMMY_CONSOLE_ROWS=64
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_REISERFS_FS is not set
-CONFIG_JFS_FS=m
-# CONFIG_JFS_POSIX_ACL is not set
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_STATISTICS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_XFS_FS=m
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-CONFIG_UFS_FS=m
-# CONFIG_UFS_FS_WRITE is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-CONFIG_NFSD_V4=y
-CONFIG_NFSD_TCP=y
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=m
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-# 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=m
-# CONFIG_NLS_CODEPAGE_864 is not set
-CONFIG_NLS_CODEPAGE_865=m
-# 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_ASCII is not set
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-# 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=m
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-# CONFIG_CRYPTO_ARC4 is not set
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_DEFLATE=m
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-CONFIG_CRYPTO_CRC32C=m
-CONFIG_CRYPTO_TEST=m
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=m
-CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile
--- a/arch/parisc/kernel/Makefile
+++ b/arch/parisc/kernel/Makefile
@@ -19,6 +19,6 @@ obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_PA11)	+= pci-dma.o
 obj-$(CONFIG_PCI)	+= pci.o
 obj-$(CONFIG_MODULES)	+= module.o
-obj-$(CONFIG_PARISC64)	+= binfmt_elf32.o sys_parisc32.o ioctl32.o signal32.o
+obj-$(CONFIG_64BIT)	+= 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
+obj-$(CONFIG_64BIT)	+= perf.o perf_asm.o
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
--- a/arch/parisc/kernel/binfmt_elf32.c
+++ b/arch/parisc/kernel/binfmt_elf32.c
@@ -37,7 +37,6 @@ 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 <linux/compat.h>		/* struct compat_timeval */
 
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -10,7 +10,7 @@
  * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
  * Copyright (c) 2001 Helge Deller <deller@gmx.de>
  * Copyright (c) 2001,2002 Ryan Bradetich 
- * Copyright (c) 2004 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright (c) 2004-2005 Thibaut VARENE <varenet@parisc-linux.org>
  * 
  * The file handles registering devices and drivers, then matching them.
  * It's the closest we get to a dating agency.
@@ -611,6 +611,24 @@ struct device *hwpath_to_device(struct h
 }
 EXPORT_SYMBOL(hwpath_to_device);
 
+/**
+ * device_to_hwpath - Populates the hwpath corresponding to the given device.
+ * @param dev the target device
+ * @param path pointer to a previously allocated hwpath struct to be filled in
+ */
+void device_to_hwpath(struct device *dev, struct hardware_path *path)
+{
+	struct parisc_device *padev;
+	if (dev->bus == &parisc_bus_type) {
+		padev = to_parisc_device(dev);
+		get_node_path(dev->parent, path);
+		path->mod = padev->hw_path;
+	} else if (is_pci_dev(dev)) {
+		get_node_path(dev, path);
+	}
+}
+EXPORT_SYMBOL(device_to_hwpath);
+
 #define BC_PORT_MASK 0x8
 #define BC_LOWER_PORT 0x8
 
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -76,13 +76,11 @@
 	mtsp	%r0, %sr5
 	mtsp	%r0, %sr6
 	mtsp	%r0, %sr7
-	ldil	L%KERNEL_PSW, %r1
-	ldo	R%KERNEL_PSW(%r1), %r1
+	load32	KERNEL_PSW, %r1
 	mtctl	%r1, %cr22
 	mtctl	%r0, %cr17	/* Clear IIASQ tail */
 	mtctl	%r0, %cr17	/* Clear IIASQ head */
-	ldil	L%4f, %r1
-	ldo	R%4f(%r1), %r1
+	load32	4f, %r1
 	mtctl	%r1, %cr18	/* Set IIAOQ tail */
 	ldo	4(%r1), %r1
 	mtctl	%r1, %cr18	/* Set IIAOQ head */
@@ -197,8 +195,7 @@
 	/* HPMC handler */
 	.macro	hpmc code
 	nop			/* must be a NOP, will be patched later */
-	ldil	L%PA(os_hpmc), %r3
-	ldo	R%PA(os_hpmc)(%r3), %r3
+	load32	PA(os_hpmc), %r3
 	bv,n	0(%r3)
 	nop
 	.word	0		/* checksum (will be patched) */
@@ -860,8 +857,7 @@ _switch_to:
 
 	callee_save
 
-	ldil	L%_switch_to_ret, %r2
-	ldo	R%_switch_to_ret(%r2), %r2
+	load32	_switch_to_ret, %r2
 
 	STREG	%r2, TASK_PT_KPC(%r26)
 	LDREG	TASK_PT_KPC(%r25), %r2
@@ -914,16 +910,13 @@ syscall_exit_rfi:
 	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
+	load32	USER_PSW_MASK,%r1
 #ifdef __LP64__
-	ldil    L%USER_PSW_HI_MASK,%r20
-	ldo     R%USER_PSW_HI_MASK(%r20),%r20
+	load32	USER_PSW_HI_MASK,%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
+	load32	USER_PSW,%r1
 	or      %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
 	STREG   %r19,PT_PSW(%r16)
 
@@ -955,8 +948,7 @@ intr_return:
 
 	.import irq_stat,data
 
-	ldil	L%irq_stat,%r19
-	ldo	R%irq_stat(%r19),%r19
+	load32	irq_stat,%r19
 #ifdef CONFIG_SMP
 	mfctl   %cr30,%r1
 	ldw	TI_CPU(%r1),%r1 /* get cpu # - int */
@@ -1079,7 +1071,7 @@ intr_do_signal:
 	BL	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
-	b	intr_restore
+	b	intr_check_sig
 	nop
 
 	/*
@@ -1607,8 +1599,7 @@ dbit_trap_20w:
 
 #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
+	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_20w:
 	ldcw            0(t0),t1
@@ -1644,8 +1635,7 @@ dbit_trap_11:
 
 #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
+	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_11:
 	ldcw            0(t0),t1
@@ -1685,8 +1675,7 @@ dbit_trap_20:
 
 #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
+	load32		PA(pa_dbit_lock),t0
 
 dbit_spin_20:
 	ldcw            0(t0),t1
@@ -2082,8 +2071,7 @@ syscall_check_bh:
 
 	.import irq_stat,data
 
-	ldil    L%irq_stat,%r19
-	ldo     R%irq_stat(%r19),%r19
+	load32	irq_stat,%r19
 
 #ifdef CONFIG_SMP
 	/* sched.h: int processor */
@@ -2282,7 +2270,7 @@ syscall_do_signal:
 	ldo	TASK_REGS(%r1), %r20		/* reload pt_regs */
 	reg_restore %r20
 
-	b,n     syscall_restore
+	b,n     syscall_check_sig
 
 	/*
 	 * get_register is used by the non access tlb miss handlers to
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -120,10 +120,10 @@ static unsigned long f_extend(unsigned l
 #ifdef __LP64__
 	if(unlikely(parisc_narrow_firmware)) {
 		if((address & 0xff000000) == 0xf0000000)
-			return 0xf0f0f0f000000000 | (u32)address;
+			return 0xf0f0f0f000000000UL | (u32)address;
 
 		if((address & 0xf0000000) == 0xf0000000)
-			return 0xffffffff00000000 | (u32)address;
+			return 0xffffffff00000000UL | (u32)address;
 	}
 #endif
 	return address;
@@ -782,6 +782,8 @@ int pdc_pci_irt(unsigned long num_entrie
 {
 	int retval;
 
+	BUG_ON((unsigned long)tbl & 0x7);
+
 	spin_lock_irq(&pdc_lock);
 	pdc_result[0] = num_entries;
 	retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, 
@@ -912,7 +914,7 @@ int pdc_do_firm_test_reset(unsigned long
  *
  * Reset the system.
  */
-int pdc_do_reset()
+int pdc_do_reset(void)
 {
         int retval;
 
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -1296,18 +1296,18 @@ static struct hp_cpu_type_mask {
 };
 
 char *cpu_name_version[][2] = {
-	[pcx]	{ "PA7000 (PCX)",	"1.0" },
-	[pcxs]	{ "PA7000 (PCX-S)",	"1.1a" },
-	[pcxt]	{ "PA7100 (PCX-T)",	"1.1b" },
-	[pcxt_]	{ "PA7200 (PCX-T')",	"1.1c" },
-	[pcxl]	{ "PA7100LC (PCX-L)",	"1.1d" },
-	[pcxl2]	{ "PA7300LC (PCX-L2)",	"1.1e" },
-	[pcxu]	{ "PA8000 (PCX-U)",	"2.0" },
-	[pcxu_]	{ "PA8200 (PCX-U+)",	"2.0" },
-	[pcxw]	{ "PA8500 (PCX-W)",	"2.0" },
-	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" },
-	[pcxw2]	{ "PA8700 (PCX-W2)",	"2.0" },
-	[mako]	{ "PA8800 (Mako)",	"2.0" }
+	[pcx]	= { "PA7000 (PCX)",	"1.0" },
+	[pcxs]	= { "PA7000 (PCX-S)",	"1.1a" },
+	[pcxt]	= { "PA7100 (PCX-T)",	"1.1b" },
+	[pcxt_]	= { "PA7200 (PCX-T')",	"1.1c" },
+	[pcxl]	= { "PA7100LC (PCX-L)",	"1.1d" },
+	[pcxl2]	= { "PA7300LC (PCX-L2)",	"1.1e" },
+	[pcxu]	= { "PA8000 (PCX-U)",	"2.0" },
+	[pcxu_]	= { "PA8200 (PCX-U+)",	"2.0" },
+	[pcxw]	= { "PA8500 (PCX-W)",	"2.0" },
+	[pcxw_]	= { "PA8600 (PCX-W+)",	"2.0" },
+	[pcxw2]	= { "PA8700 (PCX-W2)",	"2.0" },
+	[mako]	= { "PA8800 (Mako)",	"2.0" }
 };
 
 const char * __init
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -71,47 +71,42 @@ $bss_loop:
 	stw,ma          %arg2,4(%r1)
 	stw,ma          %arg3,4(%r1)
 
-	/* Initialize startup VM. Just map first 8 MB of memory */
-	load32		PA(pg0),%r1
-
-#ifdef __LP64__
-	load32		PA(pmd0),%r5
-	shrd            %r5,PxD_VALUE_SHIFT,%r3	
-#else
-	shr		%r1,PxD_VALUE_SHIFT,%r3
-#endif
-        ldo             (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3	
-	
+	/* Initialize startup VM. Just map first 8/16 MB of memory */
 	load32		PA(swapper_pg_dir),%r4
 	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
 	mtctl		%r4,%cr25	/* Initialize user root pointer */
 
 #ifdef __LP64__
+	/* Set pmd in pgd */
+	load32		PA(pmd0),%r5
+	shrd            %r5,PxD_VALUE_SHIFT,%r3	
+        ldo             (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3	
 	stw		%r3,ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4)
-	shrd		%r1,PxD_VALUE_SHIFT,%r3
-	ldo		(PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
-	ldo		ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r5
+	ldo		ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r4
 #else
+	/* 2-level page table, so pmd == pgd */
         ldo             ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4),%r4
 #endif
+
+	/* Fill in pmd with enough pte directories */
+	load32		PA(pg0),%r1
+	SHRREG		%r1,PxD_VALUE_SHIFT,%r3
+	ldo		(PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
+
 	ldi		ASM_PT_INITIAL,%r1
 
 1:
-#ifdef __LP64__
-	stw             %r3,0(%r5)
-#else
-	stw             %r3,0(%r4)
-#endif
-	
+	stw		%r3,0(%r4)
 	ldo		(ASM_PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3
 	addib,>		-1,%r1,1b
-
 #ifdef __LP64__
-	ldo		ASM_PMD_ENTRY_SIZE(%r5),%r5
+	ldo             ASM_PMD_ENTRY_SIZE(%r4),%r4
 #else
-	ldo		ASM_PGD_ENTRY_SIZE(%r4),%r4
+	ldo             ASM_PGD_ENTRY_SIZE(%r4),%r4
 #endif
 
+
+	/* Now initialize the PTEs themselves */
 	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
 	load32		PA(pg0),%r1
 
@@ -306,7 +301,7 @@ $rfi:	
 	mtctl		%r11,%cr18	/* IIAOQ head */
 	ldo		4(%r11),%r11
 	mtctl		%r11,%cr18	/* IIAOQ tail */
-
+	
 	/* Jump to hyperspace */
 	rfi
 	nop
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
--- a/arch/parisc/kernel/hpmc.S
+++ b/arch/parisc/kernel/hpmc.S
@@ -121,8 +121,7 @@ os_hpmc:
 
 	/* Setup stack pointer. */
 
-	ldil    L%PA(hpmc_stack),sp
-	ldo     R%PA(hpmc_stack)(sp),sp
+	load32	PA(hpmc_stack),sp
 	
 	ldo     128(sp),sp /* leave room for arguments */
 
@@ -135,8 +134,7 @@ os_hpmc:
 	mtctl   %r4,ipsw
 	mtctl   %r0,pcsq
 	mtctl   %r0,pcsq
-	ldil    L%PA(os_hpmc_1),%r4
-	ldo     R%PA(os_hpmc_1)(%r4),%r4
+	load32	PA(os_hpmc_1),%r4
 	mtctl   %r4,pcoq
 	ldo     4(%r4),%r4
 	mtctl   %r4,pcoq
@@ -155,12 +153,9 @@ os_hpmc_1:
 
 	ldo     PDC_PIM(%r0), arg0
 	ldo     PDC_PIM_HPMC(%r0),arg1          /* Transfer HPMC data */
-	ldil    L%PA(hpmc_raddr),arg2
-	ldo     R%PA(hpmc_raddr)(arg2),arg2
-	ldil    L%PA(hpmc_pim_data),arg3
-	ldo     R%PA(hpmc_pim_data)(arg3),arg3
-	ldil    L%HPMC_PIM_DATA_SIZE,%r4
-	ldo     R%HPMC_PIM_DATA_SIZE(%r4),%r4
+	load32	PA(hpmc_raddr),arg2
+	load32	PA(hpmc_pim_data),arg3
+	load32	HPMC_PIM_DATA_SIZE,%r4
 	stw     %r4,-52(sp)
 
 	ldil    L%PA(os_hpmc_2), rp
@@ -199,16 +194,13 @@ os_hpmc_3:
 
 	ldo     PDC_IODC(%r0),arg0
 	ldo     PDC_IODC_READ(%r0),arg1
-	ldil    L%PA(hpmc_raddr),arg2
-	ldo     R%PA(hpmc_raddr)(arg2),arg2
+	load32	PA(hpmc_raddr),arg2
 	ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
 	ldo     PDC_IODC_RI_INIT(%r0),%r4
 	stw     %r4,-52(sp)
-	ldil    L%PA(hpmc_iodc_buf),%r4
-	ldo     R%PA(hpmc_iodc_buf)(%r4),%r4
+	load32	PA(hpmc_iodc_buf),%r4
 	stw     %r4,-56(sp)
-	ldil    L%HPMC_IODC_BUF_SIZE,%r4
-	ldo     R%HPMC_IODC_BUF_SIZE(%r4),%r4
+	load32	HPMC_IODC_BUF_SIZE,%r4
 	stw     %r4,-60(sp)
 
 	ldil    L%PA(os_hpmc_4),rp
@@ -225,16 +217,14 @@ os_hpmc_4:
 	ldw     BOOT_CONSOLE_SPA_OFFSET(%r0),arg2  /* console spa */
 	depi    0,31,11,arg2                       /* clear bits 21-31    */
 	ldo     BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
-	ldil    L%PA(hpmc_raddr),%r4
-	ldo     R%PA(hpmc_raddr)(%r4),%r4
+	load32	PA(hpmc_raddr),%r4
 	stw     %r4, -52(sp)
 	stw     %r0, -56(sp)                    /* HV                  */
 	stw     %r0, -60(sp)                    /* HV                  */
 	stw     %r0, -64(sp)                    /* HV                  */
 	stw     %r0, -68(sp)                    /* lang, must be zero  */
 
-	ldil    L%PA(hpmc_iodc_buf),%r5
-	ldo     R%PA(hpmc_iodc_buf)(%r5),%r5
+	load32	PA(hpmc_iodc_buf),%r5
 	ldil    L%PA(os_hpmc_5),rp
 	bv      (%r5)
 	ldo     R%PA(os_hpmc_5)(rp),rp
@@ -249,8 +239,7 @@ os_hpmc_5:
 	 * we don't intend to ever return to user land anyway)
 	 */
 
-	ldil		L%PA(swapper_pg_dir),%r4
-	ldo		R%PA(swapper_pg_dir)(%r4),%r4
+	load32		PA(swapper_pg_dir),%r4
 	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
 	mtctl		%r4,%cr25	/* Initialize user root pointer */
 
@@ -265,8 +254,7 @@ os_hpmc_5:
 
 	rsm 8,%r0           /* Clear Q bit */
 	ldi     1,%r8       /* Set trap code to "1" for HPMC */
-	ldil    L%PA(intr_save), %r1
-	ldo     R%PA(intr_save)(%r1), %r1
+	load32	PA(intr_save),%r1
 	be      0(%sr7,%r1)
 	nop
 
diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c
--- a/arch/parisc/kernel/init_task.c
+++ b/arch/parisc/kernel/init_task.c
@@ -55,11 +55,15 @@ union thread_union init_thread_union
 
 #ifdef __LP64__
 /* NOTE: This layout exactly conforms to the hybrid L2/L3 page table layout
- * with the first pmd adjacent to the pgd and below it */
-pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
+ * with the first pmd adjacent to the pgd and below it. gcc doesn't actually
+ * guarantee that global objects will be laid out in memory in the same order 
+ * as the order of declaration, so put these in different sections and use
+ * the linker script to order them. */
+pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((aligned(PAGE_SIZE))) __attribute__ ((__section__ (".data.vm0.pmd"))) = { {0}, };
+
 #endif
-pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
-pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(PAGE_SIZE))) __attribute__ ((__section__ (".data.vm0.pgd"))) = { {0}, };
+pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(PAGE_SIZE))) __attribute__ ((__section__ (".data.vm0.pte")))  = { {0}, };
 
 /*
  * Initial task structure.
diff --git a/arch/parisc/kernel/ioctl32.c b/arch/parisc/kernel/ioctl32.c
--- a/arch/parisc/kernel/ioctl32.c
+++ b/arch/parisc/kernel/ioctl32.c
@@ -563,7 +563,7 @@ static int drm32_res_ctx(unsigned int fd
 
 #endif
 
-#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
+#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, NULL },
 #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd, sys_ioctl) 
 
 #define IOCTL_TABLE_START  struct ioctl_trans ioctl_start[] = {
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -5,6 +5,7 @@
  * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
  * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
  * Copyright (C) 1999-2000 Grant Grundler
+ * Copyright (c) 2005 Matthew Wilcox
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -22,38 +23,19 @@
  */
 #include <linux/bitops.h>
 #include <linux/config.h>
-#include <linux/eisa.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/module.h>
-#include <linux/signal.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/seq_file.h>
 #include <linux/spinlock.h>
+#include <linux/types.h>
 
-#include <asm/cache.h>
-#include <asm/pdc.h>
-
-#undef DEBUG_IRQ
 #undef PARISC_IRQ_CR16_COUNTS
 
 extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
 extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
 
-#ifdef DEBUG_IRQ
-#define DBG_IRQ(irq, x)	if ((irq) != TIMER_IRQ) printk x
-#else /* DEBUG_IRQ */
-#define DBG_IRQ(irq, x)	do { } while (0)
-#endif /* DEBUG_IRQ */
-
 #define EIEM_MASK(irq)       (1UL<<(CPU_IRQ_MAX - irq))
 
 /* Bits in EIEM correlate with cpu_irq_action[].
@@ -120,8 +102,10 @@ int show_interrupts(struct seq_file *p, 
 	}
 
 	if (i < NR_IRQS) {
+		struct irqaction *action;
+
 		spin_lock_irqsave(&irq_desc[i].lock, flags);
-		struct irqaction *action = irq_desc[i].action;
+		action = irq_desc[i].action;
 		if (!action)
 			goto skip;
 		seq_printf(p, "%3d: ", i);
@@ -200,7 +184,25 @@ int txn_claim_irq(int irq)
 	return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq;
 }
 
-int txn_alloc_irq(void)
+/*
+ * The bits_wide parameter accommodates the limitations of the HW/SW which
+ * use these bits:
+ * Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
+ * V-class (EPIC):          6 bits
+ * N/L/A-class (iosapic):   8 bits
+ * PCI 2.2 MSI:            16 bits
+ * Some PCI devices:       32 bits (Symbios SCSI/ATM/HyperFabric)
+ *
+ * On the service provider side:
+ * o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
+ * o PA 2.0 wide mode                   6-bits (per processor)
+ * o IA64                               8-bits (0-256 total)
+ *
+ * So a Legacy PA I/O device on a PA 2.0 box can't use all the bits supported
+ * by the processor...and the N/L-class I/O subsystem supports more bits than
+ * PA2.0 has. The first case is the problem.
+ */
+int txn_alloc_irq(unsigned int bits_wide)
 {
 	int irq;
 
@@ -208,6 +210,8 @@ int txn_alloc_irq(void)
 	for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) {
 		if (cpu_claim_irq(irq, NULL, NULL) < 0)
 			continue;
+		if ((irq - CPU_IRQ_BASE) >= (1 << bits_wide))
+			continue;
 		return irq;
 	}
 
@@ -215,7 +219,7 @@ int txn_alloc_irq(void)
 	return -1;
 }
 
-unsigned long txn_alloc_addr(int virt_irq)
+unsigned long txn_alloc_addr(unsigned int virt_irq)
 {
 	static int next_cpu = -1;
 
@@ -233,36 +237,8 @@ unsigned long txn_alloc_addr(int virt_ir
 }
 
 
-/*
-** The alloc process needs to accept a parameter to accommodate limitations
-** of the HW/SW which use these bits:
-** Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
-** 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 (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)
-** o PA 2.0 wide mode                   6-bits (per processor)
-** o IA64                               8-bits (0-256 total)
-**
-** So a Legacy PA I/O device on a PA 2.0 box can't use all
-** the bits supported by the processor...and the N/L-class
-** I/O subsystem supports more bits than PA2.0 has. The first
-** case is the problem.
-*/
-unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide)
+unsigned int txn_alloc_data(unsigned int virt_irq)
 {
-	/* XXX FIXME : bits_wide indicates how wide the transaction
-	** data is allowed to be...we may need a different virt_irq
-	** if this one won't work. Another reason to index virtual
-	** irq's into a table which can manage CPU/IRQ bit separately.
-	*/
-	if ((virt_irq - CPU_IRQ_BASE) > (1 << (bits_wide - 1))) {
-		panic("Sorry -- didn't allocate valid IRQ for this device\n");
-	}
-
 	return virt_irq - CPU_IRQ_BASE;
 }
 
@@ -270,42 +246,35 @@ unsigned int txn_alloc_data(int virt_irq
 void do_cpu_irq_mask(struct pt_regs *regs)
 {
 	unsigned long eirr_val;
-	unsigned int i=3;	/* limit time in interrupt context */
+
+	irq_enter();
 
 	/*
-	 * 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.
+	 * Only allow interrupt processing to be interrupted by the
+	 * timer tick
 	 */
-	set_eiem(0UL);	/* disable all extr interrupt for now */
+	set_eiem(EIEM_MASK(TIMER_IRQ));
 
 	/* 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 interrupt
 	 *    when we could have just handled it right away.
-	 * 3) Limit the number of times we loop to make sure other
-	 *    processing can occur.
 	 */
 	for (;;) {
 		unsigned long bit = (1UL << (BITS_PER_LONG - 1));
 		unsigned int irq;
 		eirr_val = mfctl(23) & cpu_eiem;
-		if (!eirr_val || !i--)
+		if (!eirr_val)
 			break;
 
-		mtctl(eirr_val, 23); /* reset bits we are going to process */
+		if (eirr_val & EIEM_MASK(TIMER_IRQ))
+			set_eiem(0);
 
-#ifdef DEBUG_IRQ
-		if (eirr_val != (1UL << MAX_CPU_IRQ))
-			printk(KERN_DEBUG "do_cpu_irq_mask  0x%x & 0x%x\n", eirr_val, cpu_eiem);
-#endif
+		mtctl(eirr_val, 23); /* reset bits we are going to process */
 
 		/* Work our way from MSb to LSb...same order we alloc EIRs */
 		for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
-			if (!(bit & eirr_val & cpu_eiem))
+			if (!(bit & eirr_val))
 				continue;
 
 			/* clear bit in mask - can exit loop sooner */
@@ -315,6 +284,7 @@ void do_cpu_irq_mask(struct pt_regs *reg
 		}
 	}
 	set_eiem(cpu_eiem);
+	irq_exit();
 }
 
 
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -2,7 +2,7 @@
  *
  *    The best reference for this stuff is probably the Processor-
  *    Specific ELF Supplement for PA-RISC:
- *        http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf
+ *        http://ftp.parisc-linux.org/docs/arch/elf-pa-hp.pdf
  *
  *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *    Copyright (C) 2003 Randolph Chung <tausq at debian . org>
@@ -21,6 +21,23 @@
  *    You 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
+ *
+ *
+ *    Notes:
+ *    - SEGREL32 handling
+ *      We are not doing SEGREL32 handling correctly. According to the ABI, we
+ *      should do a value offset, like this:
+ *			if (is_init(me, (void *)val))
+ *				val -= (uint32_t)me->module_init;
+ *			else
+ *				val -= (uint32_t)me->module_core;
+ *	However, SEGREL32 is used only for PARISC unwind entries, and we want
+ *	those entries to have an absolute address, and not just an offset.
+ *
+ *	The unwind table mechanism has the ability to specify an offset for 
+ *	the unwind table; however, because we split off the init functions into
+ *	a different piece of memory, it is not possible to do this using a 
+ *	single offset. Instead, we use the above hack for now.
  */
 
 #include <linux/moduleloader.h>
@@ -30,6 +47,8 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 
+#include <asm/unwind.h>
+
 #if 0
 #define DEBUGP printk
 #else
@@ -248,6 +267,10 @@ int module_frob_arch_sections(CONST Elf_
 		const Elf_Rela *rels = (void *)hdr + sechdrs[i].sh_offset;
 		unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels);
 
+		if (strncmp(secstrings + sechdrs[i].sh_name,
+			    ".PARISC.unwind", 14) == 0)
+			me->arch.unwind_section = i;
+
 		if (sechdrs[i].sh_type != SHT_RELA)
 			continue;
 
@@ -499,7 +522,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs
 			break;
 		case R_PARISC_SEGREL32:
 			/* 32-bit segment relative address */
-			val -= (uint32_t)me->module_core;
+			/* See note about special handling of SEGREL32 at
+			 * the beginning of this file.
+			 */
 			*loc = fsel(val, addend); 
 			break;
 		case R_PARISC_DPREL21L:
@@ -651,7 +676,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs
 			break;
 		case R_PARISC_SEGREL32:
 			/* 32-bit segment relative address */
-			val -= (uint64_t)me->module_core;
+			/* See note about special handling of SEGREL32 at
+			 * the beginning of this file.
+			 */
 			*loc = fsel(val, addend); 
 			break;
 		case R_PARISC_FPTR64:
@@ -682,6 +709,32 @@ int apply_relocate_add(Elf_Shdr *sechdrs
 }
 #endif
 
+static void
+register_unwind_table(struct module *me,
+		      const Elf_Shdr *sechdrs)
+{
+	unsigned char *table, *end;
+	unsigned long gp;
+
+	if (!me->arch.unwind_section)
+		return;
+
+	table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
+	end = table + sechdrs[me->arch.unwind_section].sh_size;
+	gp = (Elf_Addr)me->module_core + me->arch.got_offset;
+
+	DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
+	       me->arch.unwind_section, table, end, gp);
+	me->arch.unwind = unwind_table_add(me->name, 0, gp, table, end);
+}
+
+static void
+deregister_unwind_table(struct module *me)
+{
+	if (me->arch.unwind)
+		unwind_table_remove(me->arch.unwind);
+}
+
 int module_finalize(const Elf_Ehdr *hdr,
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
@@ -711,6 +764,8 @@ int module_finalize(const Elf_Ehdr *hdr,
 	       me->arch.fdesc_count, me->arch.fdesc_max);
 #endif
 
+	register_unwind_table(me, sechdrs);
+
 	/* haven't filled in me->symtab yet, so have to find it
 	 * ourselves */
 	for (i = 1; i < hdr->e_shnum; i++) {
@@ -763,4 +818,5 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
+	deregister_unwind_table(mod);
 }
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -27,17 +27,17 @@
  */
 
 #ifdef __LP64__
-#define ADDIB   addib,*
-#define CMPB    cmpb,*
-#define ANDCM   andcm,*
+#define ADDIB	addib,*
+#define CMPB	cmpb,*
+#define ANDCM	andcm,*
 
-	.level 2.0w
+	.level	2.0w
 #else
-#define ADDIB   addib,
-#define CMPB    cmpb,
-#define ANDCM   andcm
+#define ADDIB	addib,
+#define CMPB	cmpb,
+#define ANDCM	andcm
 
-	.level 2.0
+	.level	2.0
 #endif
 
 #include <asm/assembly.h>
@@ -46,7 +46,7 @@
 #include <asm/cache.h>
 
 	.text
-	.align 128
+	.align	128
 
 	.export flush_tlb_all_local,code
 
@@ -68,7 +68,7 @@ flush_tlb_all_local:
 	 * consolidated.
 	 */
 
-	rsm     PSW_SM_I,%r19	/* relied upon translation! PA 2.0 Arch. F-5 */
+	rsm		PSW_SM_I, %r19		/* relied upon translation! PA 2.0 Arch. F-5 */
 	nop
 	nop
 	nop
@@ -77,127 +77,127 @@ flush_tlb_all_local:
 	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	/* Clear IIASQ tail */
-	mtctl	%r0, %cr17	/* Clear IIASQ head */
-	ldil    L%PA(1f),%r1
-	ldo     R%PA(1f)(%r1),%r1
-	mtctl	%r1, %cr18	/* IIAOQ head */
-	ldo	4(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ tail */
+	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		/* Clear IIASQ tail */
+	mtctl		%r0, %cr17		/* Clear IIASQ head */
+	ldil		L%PA(1f), %r1
+	ldo		R%PA(1f)(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ head */
+	ldo		4(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ tail */
 	rfi
 	nop
 
-1:      ldil            L%PA(cache_info),%r1
-	ldo             R%PA(cache_info)(%r1),%r1
+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 */
+	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 */
+	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 */
+	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 */
+	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	/* Clear IIASQ tail */
-	mtctl	%r0, %cr17	/* Clear IIASQ head */
-	ldil    L%(2f), %r1
-	ldo     R%(2f)(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ head */
-	ldo	4(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ tail */
+	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		/* Clear IIASQ tail */
+	mtctl		%r0, %cr17		/* Clear IIASQ head */
+	ldil		L%(2f), %r1
+	ldo		R%(2f)(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ head */
+	ldo		4(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ tail */
 	rfi
 	nop
 
-2:      bv      %r0(%r2)
+2:      bv		%r0(%r2)
 	nop
 	.exit
 
@@ -211,140 +211,198 @@ flush_instruction_cache_local:
 	.callinfo NO_CALLS
 	.entry
 
-	mtsp            %r0,%sr1
-	ldil            L%cache_info,%r1
-	ldo             R%cache_info(%r1),%r1
+	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
-	rsm             PSW_SM_I,%r22		/* No mmgt ops during loop*/
-	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 */
+	LDREG		ICACHE_BASE(%r1), %arg0
+	LDREG		ICACHE_STRIDE(%r1), %arg1
+	LDREG		ICACHE_COUNT(%r1), %arg2
+	LDREG		ICACHE_LOOP(%r1), %arg3
+	rsm             PSW_SM_I, %r22		/* No mmgt ops during loop*/
+	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
-	mtsm	%r22
-	bv      %r0(%r2)
+	mtsm		%r22
+	bv		%r0(%r2)
 	nop
 	.exit
 
 	.procend
 
-	.export flush_data_cache_local,code
-	.import cache_info,data
+	.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
+	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 */
+	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)
+	mtsm		%r22
+	bv		%r0(%r2)
 	nop
 	.exit
 
 	.procend
 
 	.export copy_user_page_asm,code
+	.align	16
 
 copy_user_page_asm:
 	.proc
 	.callinfo NO_CALLS
 	.entry
 
-	ldi 64,%r1
+#ifdef __LP64__
+	/* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+	 * Unroll the loop by hand and arrange insn appropriately.
+	 * GCC probably can do this just as well.
+	 */
+
+	ldd		0(%r25), %r19
+	ldi		32, %r1                 /* PAGE_SIZE/128 == 32 */
+	ldw		64(%r25), %r0		/* prefetch 1 cacheline ahead */
+	ldw		128(%r25), %r0		/* prefetch 2 */
+
+1:	ldd		8(%r25), %r20
+	ldw		192(%r25), %r0		/* prefetch 3 */
+	ldw		256(%r25), %r0		/* prefetch 4 */
+
+	ldd		16(%r25), %r21
+	ldd		24(%r25), %r22
+	std		%r19, 0(%r26)
+	std		%r20, 8(%r26)
+
+	ldd		32(%r25), %r19
+	ldd		40(%r25), %r20
+	std		%r21, 16(%r26)
+	std		%r22, 24(%r26)
+
+	ldd		48(%r25), %r21
+	ldd		56(%r25), %r22
+	std		%r19, 32(%r26)
+	std		%r20, 40(%r26)
+
+	ldd		64(%r25), %r19
+	ldd		72(%r25), %r20
+	std		%r21, 48(%r26)
+	std		%r22, 56(%r26)
+
+	ldd		80(%r25), %r21
+	ldd		88(%r25), %r22
+	std		%r19, 64(%r26)
+	std		%r20, 72(%r26)
+
+	ldd		 96(%r25), %r19
+	ldd		104(%r25), %r20
+	std		%r21, 80(%r26)
+	std		%r22, 88(%r26)
+
+	ldd		112(%r25), %r21
+	ldd		120(%r25), %r22
+	std		%r19, 96(%r26)
+	std		%r20, 104(%r26)
+
+	ldo		128(%r25), %r25
+	std		%r21, 112(%r26)
+	std		%r22, 120(%r26)
+	ldo		128(%r26), %r26
+
+	ADDIB>		-1, %r1, 1b		/* bundle 10 */
+	ldd		0(%r25), %r19		/* start next loads */
+
+#else
 
 	/*
 	 * 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
+	 * bundles (very restricted rules for bundling).
+	 * 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.
 	 */
-
+	ldi		64, %r1		/* PAGE_SIZE/64 == 64 */
 
 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)
+	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
+#endif
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -393,33 +451,33 @@ copy_user_page_asm:
 	.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' */
+	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)
+	pdtlb		0(%r28)
+	pdtlb		0(%r29)
 
-	ldi 64,%r1
+	ldi		64, %r1
 
 	/*
 	 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
@@ -432,43 +490,43 @@ copy_user_page_asm:
 
 
 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
+	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)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -482,49 +540,77 @@ __clear_user_page_asm:
 	.callinfo NO_CALLS
 	.entry
 
-	tophys_r1 %r26
+	tophys_r1	%r26
 
-	ldil    L%(TMPALIAS_MAP_START),%r28
+	ldil		L%(TMPALIAS_MAP_START), %r28
 #ifdef __LP64__
 #if (TMPALIAS_MAP_START >= 0x80000000)
-	depdi	0,31,32,%r28	/* clear any sign extension */
+	depdi		0, 31,32, %r28		/* clear any sign extension */
 #endif
-	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 */
+	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)
+	pdtlb		0(%r28)
 
-	ldi 64,%r1
+#ifdef __LP64__
+	ldi		32, %r1			/* PAGE_SIZE/128 == 32 */
+
+	/* PREFETCH (Write) has not (yet) been proven to help here */
+/* #define	PREFETCHW_OP	ldd		256(%0), %r0 */
+
+1:	std		%r0, 0(%r28)
+	std		%r0, 8(%r28)
+	std		%r0, 16(%r28)
+	std		%r0, 24(%r28)
+	std		%r0, 32(%r28)
+	std		%r0, 40(%r28)
+	std		%r0, 48(%r28)
+	std		%r0, 56(%r28)
+	std		%r0, 64(%r28)
+	std		%r0, 72(%r28)
+	std		%r0, 80(%r28)
+	std		%r0, 88(%r28)
+	std		%r0, 96(%r28)
+	std		%r0, 104(%r28)
+	std		%r0, 112(%r28)
+	std		%r0, 120(%r28)
+	ADDIB>		-1, %r1, 1b
+	ldo		128(%r28), %r28
+
+#else	/* ! __LP64 */
+
+	ldi		64, %r1			/* PAGE_SIZE/64 == 64 */
 
 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
+	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
+#endif	/* __LP64 */
 
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -537,38 +623,38 @@ flush_kernel_dcache_page:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r25
+	depdi,z		1, 63-PAGE_SHIFT,1, %r25
 #else
-	depwi,z 1,31-PAGE_SHIFT,1,%r25
+	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)
+	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)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -581,38 +667,38 @@ flush_user_dcache_page:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r25
+	depdi,z		1,63-PAGE_SHIFT,1, %r25
 #else
-	depwi,z 1,31-PAGE_SHIFT,1,%r25
+	depwi,z		1,31-PAGE_SHIFT,1, %r25
 #endif
-	add     %r26,%r25,%r25
-	sub     %r25,%r23,%r25
-
-
-1:      fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	fdc,m   %r23(%sr3,%r26)
-	CMPB<<  %r26,%r25,1b
-	fdc,m   %r23(%sr3,%r26)
+	add		%r26, %r25, %r25
+	sub		%r25, %r23, %r25
+
+
+1:      fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	fdc,m		%r23(%sr3, %r26)
+	CMPB<<		%r26, %r25,1b
+	fdc,m		%r23(%sr3, %r26)
 
 	sync
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -625,38 +711,38 @@ flush_user_icache_page:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r25
+	depdi,z		1, 63-PAGE_SHIFT,1, %r25
 #else
-	depwi,z 1,31-PAGE_SHIFT,1,%r25
+	depwi,z		1, 31-PAGE_SHIFT,1, %r25
 #endif
-	add     %r26,%r25,%r25
-	sub     %r25,%r23,%r25
-
-
-1:      fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	fic,m   %r23(%sr3,%r26)
-	CMPB<<  %r26,%r25,1b
-	fic,m   %r23(%sr3,%r26)
+	add		%r26, %r25, %r25
+	sub		%r25, %r23, %r25
+
+
+1:      fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	fic,m		%r23(%sr3, %r26)
+	CMPB<<		%r26, %r25,1b
+	fic,m		%r23(%sr3, %r26)
 
 	sync
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -670,37 +756,37 @@ purge_kernel_dcache_page:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r25
+	depdi,z		1, 63-PAGE_SHIFT,1, %r25
 #else
-	depwi,z 1,31-PAGE_SHIFT,1,%r25
+	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)
+	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)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -718,54 +804,54 @@ flush_alias_page:
 	.callinfo NO_CALLS
 	.entry
 
-	tophys_r1 %r26
+	tophys_r1		%r26
 
-	ldil    L%(TMPALIAS_MAP_START),%r28
+	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 */
+	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 */
+	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)
+	pdtlb		0(%r28)
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r29
+	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)
+	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)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -779,16 +865,16 @@ flush_user_dcache_range_asm:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
-	ldo     -1(%r23),%r21
-	ANDCM   %r26,%r21,%r26
+	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)
+1:      CMPB<<,n	%r26, %r25, 1b
+	fdc,m		%r23(%sr3, %r26)
 
 	sync
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -801,17 +887,17 @@ flush_kernel_dcache_range_asm:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%dcache_stride,%r1
-	ldw     R%dcache_stride(%r1),%r23
-	ldo     -1(%r23),%r21
-	ANDCM   %r26,%r21,%r26
+	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)
+1:      CMPB<<,n	%r26, %r25,1b
+	fdc,m		%r23(%r26)
 
 	sync
 	syncdma
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -824,16 +910,16 @@ flush_user_icache_range_asm:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%icache_stride,%r1
-	ldw     R%icache_stride(%r1),%r23
-	ldo     -1(%r23),%r21
-	ANDCM   %r26,%r21,%r26
+	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)
+1:      CMPB<<,n	%r26, %r25,1b
+	fic,m		%r23(%sr3, %r26)
 
 	sync
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -846,38 +932,38 @@ flush_kernel_icache_page:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%icache_stride,%r1
-	ldw     R%icache_stride(%r1),%r23
+	ldil		L%icache_stride, %r1
+	ldw		R%icache_stride(%r1), %r23
 
 #ifdef __LP64__
-	depdi,z 1,63-PAGE_SHIFT,1,%r25
+	depdi,z		1, 63-PAGE_SHIFT,1, %r25
 #else
-	depwi,z 1,31-PAGE_SHIFT,1,%r25
+	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)
+	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)
+	bv		%r0(%r2)
 	nop
 	.exit
 
@@ -890,22 +976,22 @@ flush_kernel_icache_range_asm:
 	.callinfo NO_CALLS
 	.entry
 
-	ldil    L%icache_stride,%r1
-	ldw     R%icache_stride(%r1),%r23
-	ldo     -1(%r23),%r21
-	ANDCM   %r26,%r21,%r26
+	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)
+1:      CMPB<<,n	%r26, %r25, 1b
+	fic,m		%r23(%r26)
 
 	sync
-	bv      %r0(%r2)
+	bv		%r0(%r2)
 	nop
 	.exit
 
 	.procend
 
-	.align 128
+	.align	128
 
 	.export disable_sr_hashing_asm,code
 
@@ -916,7 +1002,7 @@ disable_sr_hashing_asm:
 
 	/* Switch to real mode */
 
-	ssm     0,%r0           /* relied upon translation! */
+	ssm		0, %r0			/* relied upon translation! */
 	nop
 	nop
 	nop
@@ -925,73 +1011,73 @@ disable_sr_hashing_asm:
 	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	/* Clear IIASQ tail */
-	mtctl	%r0, %cr17	/* Clear IIASQ head */
-	ldil    L%PA(1f),%r1
-	ldo     R%PA(1f)(%r1),%r1
-	mtctl	%r1, %cr18	/* IIAOQ head */
-	ldo	4(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ tail */
+	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		/* Clear IIASQ tail */
+	mtctl		%r0, %cr17		/* Clear IIASQ head */
+	ldil		L%PA(1f), %r1
+	ldo		R%PA(1f)(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ head */
+	ldo		4(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ tail */
 	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
+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
+	.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
+	.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 */
+	.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	/* Clear IIASQ tail */
-	mtctl	%r0, %cr17	/* Clear IIASQ head */
-	ldil    L%(2f), %r1
-	ldo     R%(2f)(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ head */
-	ldo	4(%r1), %r1
-	mtctl	%r1, %cr18	/* IIAOQ tail */
+	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		/* Clear IIASQ tail */
+	mtctl		%r0, %cr17		/* Clear IIASQ head */
+	ldil 	   	L%(2f), %r1
+	ldo     	R%(2f)(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ head */
+	ldo		4(%r1), %r1
+	mtctl		%r1, %cr18		/* IIAOQ tail */
 	rfi
 	nop
 
-2:      bv      %r0(%r2)
+2:      bv		%r0(%r2)
 	nop
 	.exit
 
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -32,18 +32,6 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 
-#ifdef DEBUG_PCI
-#undef ASSERT
-#define ASSERT(expr) \
-	if(!(expr)) { \
-		printk("\n%s:%d: Assertion " #expr " failed!\n", \
-				__FILE__, __LINE__); \
-		panic(#expr); \
-	}
-#else
-#define ASSERT(expr)
-#endif
-
 
 static struct proc_dir_entry * proc_gsc_root = NULL;
 static int pcxl_proc_info(char *buffer, char **start, off_t offset, int length);
@@ -180,7 +168,7 @@ static inline void unmap_uncached_pte(pm
 		end = PMD_SIZE;
 	do {
 		pte_t page = *pte;
-		pte_clear(pte);
+		pte_clear(&init_mm, vaddr, pte);
 		purge_tlb_start();
 		pdtlb_kernel(orig_vaddr);
 		purge_tlb_end();
@@ -259,10 +247,6 @@ pcxl_alloc_range(size_t size)
 	u_long mask, flags;
 	unsigned int pages_needed = size >> PAGE_SHIFT;
 
-	ASSERT(pages_needed);
-	ASSERT((pages_needed * PAGE_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < (BITS_PER_LONG - PAGE_SHIFT));
-
 	mask = (u_long) -1L;
  	mask >>= BITS_PER_LONG - pages_needed;
 
@@ -306,7 +290,7 @@ resource_found:
 
 #define PCXL_FREE_MAPPINGS(idx, m, size) \
 		u##size *res_ptr = (u##size *)&(pcxl_res_map[(idx) + (((size >> 3) - 1) & (~((size >> 3) - 1)))]); \
-		ASSERT((*res_ptr & m) == m); \
+		/* BUG_ON((*res_ptr & m) != m); */ \
 		*res_ptr &= ~m;
 
 /*
@@ -319,10 +303,6 @@ pcxl_free_range(unsigned long vaddr, siz
 	unsigned int res_idx = (vaddr - pcxl_dma_start) >> (PAGE_SHIFT + 3);
 	unsigned int pages_mapped = size >> PAGE_SHIFT;
 
-	ASSERT(pages_mapped);
-	ASSERT((pages_mapped * PAGE_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_mapped < (BITS_PER_LONG - PAGE_SHIFT));
-
 	mask = (u_long) -1L;
  	mask >>= BITS_PER_LONG - pages_mapped;
 
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
--- a/arch/parisc/kernel/pdc_chassis.c
+++ b/arch/parisc/kernel/pdc_chassis.c
@@ -2,7 +2,7 @@
  *    interfaces to log Chassis Codes via PDC (firmware)
  *
  *    Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
- *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@esiee.fr>
+ *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.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
@@ -182,7 +182,7 @@ int pdc_chassis_send_status(int message)
 
 		DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 		if (is_pdc_pat()) {
 			switch(message) {
 				case PDC_CHASSIS_DIRECT_BSTART:
@@ -238,7 +238,7 @@ int pdc_chassis_send_status(int message)
 					retval = -1;
 			}
 		} else retval = -1;
-#endif /* CONFIG_PARISC64 */
+#endif /* CONFIG_64BIT */
 	}	/* if (pdc_chassis_enabled) */
 #endif /* CONFIG_PDC_CHASSIS */
 	return retval;
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -42,7 +42,6 @@
  *  on every box. 
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/miscdevice.h>
@@ -157,16 +156,16 @@ static struct rdr_tbl_ent perf_rdr_tbl_U
  * 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
+	0x0000000000000000ul,     /* first dbl word must be zero */
+	0xfdffe00000000000ul,     /* RDR0 bitmask */
+	0x003f000000000000ul,     /* RDR1 bitmask */
+	0x00fffffffffffffful,     /* RDR20-RDR21 bitmask (152 bits) */
+	0xfffffffffffffffful,
+	0xfffffffc00000000ul,
+	0xfffffffffffffffful,     /* RDR22-RDR23 bitmask (233 bits) */
+	0xfffffffffffffffful,
+	0xfffffffffffffffcul,
+	0xff00000000000000ul
 };
 
 /*
@@ -174,16 +173,16 @@ static uint64_t perf_bitmasks[] = {
  * 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
+	0x0000000000000000ul,     /* first dbl word must be zero */
+	0xfdffe00000000000ul,     /* RDR0 bitmask */
+	0x003f000000000000ul,     /* RDR1 bitmask */
+	0x00fffffffffffffful,     /* RDR20-RDR21 bitmask (158 bits) */
+	0xfffffffffffffffful,
+	0xfffffffc00000000ul,
+	0xfffffffffffffffful,     /* RDR22-RDR23 bitmask (210 bits) */
+	0xfffffffffffffffful,
+	0xfffffffffffffffful,
+	0xfffc000000000000ul
 };
 
 static uint64_t *bitmask_array;   /* array of bitmasks to use */
@@ -194,8 +193,8 @@ static uint64_t *bitmask_array;   /* arr
 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, 
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 
 	loff_t *ppos);
 static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	unsigned long arg);
@@ -287,7 +286,7 @@ static int perf_release(struct inode *in
 /*
  * Read does nothing for this driver
  */
-static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
 {
 	return 0;
 }
@@ -299,7 +298,7 @@ static ssize_t perf_read(struct file *fi
  * called on the processor that the download should happen
  * on.
  */
-static ssize_t perf_write(struct file *file, const char *buf, size_t count, 
+static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 
 	loff_t *ppos)
 {
 	int err;
@@ -460,7 +459,7 @@ static int perf_ioctl(struct inode *inod
 			}
 
 			/* copy out the Counters */
-			if (copy_to_user((void *)arg, raddr, 
+			if (copy_to_user((void __user *)arg, raddr, 
 					sizeof (raddr)) != 0) {
 				return -EFAULT;
 			}
@@ -607,7 +606,7 @@ static int perf_stop_counters(uint32_t *
 		 * 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[21] &= 0xfffffffffffffc00ul;	/* 0 to last 10 bits */
 		userbuf[22] = 0;
 		userbuf[23] = 0;
 
@@ -802,8 +801,8 @@ static int perf_write_image(uint64_t *me
 	proc_hpa = cpu_device->hpa;
 
 	/* Merge intrigue bits into Runway STATUS 0 */
-	tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecffffffffffff;
-	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000), proc_hpa + RUNWAY_STATUS);
+	tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecfffffffffffful;
+	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), proc_hpa + RUNWAY_STATUS);
 	
 	/* Write RUNWAY DEBUG registers */
 	for (i = 0; i < 8; i++) {
diff --git a/arch/parisc/kernel/perf_asm.S b/arch/parisc/kernel/perf_asm.S
--- a/arch/parisc/kernel/perf_asm.S
+++ b/arch/parisc/kernel/perf_asm.S
@@ -22,9 +22,9 @@
 #include <linux/config.h>
 #include <asm/assembly.h>
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 	.level		2.0w
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 #define MTDIAG_1(gr)    .word 0x14201840 + gr*0x10000
 #define MTDIAG_2(gr)    .word 0x14401840 + gr*0x10000
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -54,7 +54,7 @@
 #include <asm/uaccess.h>
 #include <asm/unwind.h>
 
-int hlt_counter;
+static int hlt_counter;
 
 /*
  * Power off function, if any
@@ -251,7 +251,7 @@ int
 sys_clone(unsigned long clone_flags, unsigned long usp,
 	  struct pt_regs *regs)
 {
-	int *user_tid = (int *)regs->gr[26];
+	int __user *user_tid = (int __user *)regs->gr[26];
 
 	/* usp must be word aligned.  This also prevents users from
 	 * passing in the value 1 (which is the signal for a special
@@ -357,12 +357,12 @@ asmlinkage int sys_execve(struct pt_regs
 	int error;
 	char *filename;
 
-	filename = getname((char *) regs->gr[26]);
+	filename = getname((const char __user *) regs->gr[26]);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
-	error = do_execve(filename, (char **) regs->gr[25],
-		(char **) regs->gr[24], regs);
+	error = do_execve(filename, (char __user **) regs->gr[25],
+		(char __user **) regs->gr[24], regs);
 	if (error == 0) {
 		task_lock(current);
 		current->ptrace &= ~PT_DTRACE;
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -17,6 +17,7 @@
 #include <linux/personality.h>
 #include <linux/security.h>
 #include <linux/compat.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -285,7 +286,7 @@ long sys_ptrace(long request, pid_t pid,
 		ret = -EIO;
 		DBG("sys_ptrace(%s)\n",
 			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT");
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			goto out_tsk;
 		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
 		if (request == PTRACE_SYSCALL) {
@@ -311,7 +312,7 @@ long sys_ptrace(long request, pid_t pid,
 	case PTRACE_SINGLEBLOCK:
 		DBG("sys_ptrace(SINGLEBLOCK)\n");
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			goto out_tsk;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->ptrace &= ~PT_SINGLESTEP;
@@ -328,7 +329,7 @@ long sys_ptrace(long request, pid_t pid,
 	case PTRACE_SINGLESTEP:
 		DBG("sys_ptrace(SINGLESTEP)\n");
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			goto out_tsk;
 
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
--- a/arch/parisc/kernel/real2.S
+++ b/arch/parisc/kernel/real2.S
@@ -81,8 +81,7 @@ real32_call_asm:
 	rsm	PSW_SM_W, %r0		/* go narrow */
 #endif
 
-	ldil	L%PA(ric_ret), %r2
-	ldo	R%PA(ric_ret)(%r2), %r2
+	load32	PA(ric_ret), %r2
 	bv	0(%r31)
 	nop
 ric_ret:
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -53,6 +53,15 @@ struct proc_dir_entry * proc_runway_root
 struct proc_dir_entry * proc_gsc_root = NULL;
 struct proc_dir_entry * proc_mckinley_root = NULL;
 
+#if !defined(CONFIG_PA20) && (defined(CONFIG_IOMMU_CCIO) || defined(CONFIG_IOMMU_SBA))
+int parisc_bus_is_phys = 1;	/* Assume no IOMMU is present */
+EXPORT_SYMBOL(parisc_bus_is_phys);
+#endif
+
+/* This sets the vmerge boundary and size, it's here because it has to
+ * be available on all platforms (zero means no-virtual merging) */
+unsigned long parisc_vmerge_boundary = 0;
+unsigned long parisc_vmerge_max_size = 0;
 
 void __init setup_cmdline(char **cmdline_p)
 {
@@ -112,6 +121,10 @@ extern void collect_boot_cpu_data(void);
 
 void __init setup_arch(char **cmdline_p)
 {
+#ifdef __LP64__
+	extern int parisc_narrow_firmware;
+#endif
+
 	init_per_cpu(smp_processor_id());	/* Set Modes & Enable FP */
 
 #ifdef __LP64__
@@ -123,7 +136,6 @@ void __init setup_arch(char **cmdline_p)
 	pdc_console_init();
 
 #ifdef __LP64__
-	extern int parisc_narrow_firmware;
 	if(parisc_narrow_firmware) {
 		printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
 	}
@@ -199,7 +211,7 @@ static void __init parisc_proc_mkdir(voi
 	case pcxl2:
 		if (NULL == proc_gsc_root)
 		{
-			proc_gsc_root = proc_mkdir("bus/gsc", 0);
+			proc_gsc_root = proc_mkdir("bus/gsc", NULL);
 		}
 		break;
         case pcxt_:
@@ -210,13 +222,13 @@ static void __init parisc_proc_mkdir(voi
         case pcxw2:
                 if (NULL == proc_runway_root)
                 {
-                        proc_runway_root = proc_mkdir("bus/runway", 0);
+                        proc_runway_root = proc_mkdir("bus/runway", NULL);
                 }
                 break;
 	case mako:
                 if (NULL == proc_mckinley_root)
                 {
-                        proc_mckinley_root = proc_mkdir("bus/mckinley", 0);
+                        proc_mckinley_root = proc_mkdir("bus/mckinley", NULL);
                 }
                 break;
 	default:
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -32,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
+#include <asm/offsets.h>
 
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
@@ -69,7 +70,7 @@ int do_signal(sigset_t *oldset, struct p
 #endif
 
 asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
 {
 	sigset_t saveset, newset;
 #ifdef __LP64__
@@ -79,7 +80,7 @@ sys_rt_sigsuspend(sigset_t *unewset, siz
 		/* XXX: Don't preclude handling different sized sigset_t's.  */
 		if (sigsetsize != sizeof(compat_sigset_t))
 			return -EINVAL;
-		if (copy_from_user(&newset32, (compat_sigset_t *)unewset, sizeof(newset32)))
+		if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32)))
 			return -EFAULT;
 		sigset_32to64(&newset,&newset32);
 		
@@ -125,7 +126,7 @@ sys_rt_sigsuspend(sigset_t *unewset, siz
 #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
 
 static long
-restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
+restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
 {
 	long err = 0;
 
@@ -143,14 +144,14 @@ restore_sigcontext(struct sigcontext *sc
 void
 sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 {
-	struct rt_sigframe *frame;
+	struct rt_sigframe __user *frame;
 	struct siginfo si;
 	sigset_t set;
 	unsigned long usp = (regs->gr[30] & ~(0x01UL));
 	unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
 #ifdef __LP64__
 	compat_sigset_t compat_set;
-	struct compat_rt_sigframe * compat_frame;
+	struct compat_rt_sigframe __user * compat_frame;
 	
 	if(personality(current->personality) == PER_LINUX32)
 		sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
@@ -158,12 +159,12 @@ sys_rt_sigreturn(struct pt_regs *regs, i
 
 
 	/* Unwind the user stack to get the rt_sigframe structure. */
-	frame = (struct rt_sigframe *)
+	frame = (struct rt_sigframe __user *)
 		(usp - sigframe_size);
 	DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
 
 #ifdef __LP64__
-	compat_frame = (struct compat_rt_sigframe *)frame;
+	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
 	if(personality(current->personality) == PER_LINUX32){
 		DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
@@ -238,7 +239,7 @@ give_sigsegv:
  * Set up a signal frame.
  */
 
-static inline void *
+static inline void __user *
 get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
 {
 	/*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
@@ -251,11 +252,11 @@ get_sigframe(struct k_sigaction *ka, uns
 		sp = current->sas_ss_sp; /* Stacks grow up! */
 
 	DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp);
-	return (void *) sp; /* Stacks grow up.  Fun. */
+	return (void __user *) sp; /* Stacks grow up.  Fun. */
 }
 
 static long
-setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall)
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall)
 		 
 {
 	unsigned long flags = 0;
@@ -292,14 +293,14 @@ static long
 setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	       sigset_t *set, struct pt_regs *regs, int in_syscall)
 {
-	struct rt_sigframe *frame;
+	struct rt_sigframe __user *frame;
 	unsigned long rp, usp;
 	unsigned long haddr, sigframe_size;
 	struct siginfo si;
 	int err = 0;
 #ifdef __LP64__
 	compat_int_t compat_val;
-	struct compat_rt_sigframe * compat_frame;
+	struct compat_rt_sigframe __user * compat_frame;
 	compat_sigset_t compat_set;
 #endif
 	
@@ -313,7 +314,7 @@ setup_rt_frame(int sig, struct k_sigacti
 	
 #ifdef __LP64__
 
-	compat_frame = (struct compat_rt_sigframe *)frame;
+	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
 	if(personality(current->personality) == PER_LINUX32) {
 		DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
@@ -396,7 +397,7 @@ setup_rt_frame(int sig, struct k_sigacti
 #endif
 		if (haddr & PA_PLABEL_FDESC) {
 			Elf32_Fdesc fdesc;
-			Elf32_Fdesc *ufdesc = (Elf32_Fdesc *)A(haddr & ~3);
+			Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3);
 
 			err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
 
@@ -409,7 +410,7 @@ setup_rt_frame(int sig, struct k_sigacti
 #ifdef __LP64__
 	} else {
 		Elf64_Fdesc fdesc;
-		Elf64_Fdesc *ufdesc = (Elf64_Fdesc *)A(haddr & ~3);
+		Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
 		
 		err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
 		
@@ -443,6 +444,18 @@ setup_rt_frame(int sig, struct k_sigacti
 			psw |= PSW_W;
 #endif
 
+		/* If we are singlestepping, arrange a trap to be delivered
+		   when we return to userspace. Note the semantics -- we
+		   should trap before the first insn in the handler is
+		   executed. Ref:
+			http://sources.redhat.com/ml/gdb/2004-11/msg00245.html
+		 */
+		if (pa_psw(current)->r) {
+			pa_psw(current)->r = 0;
+			psw |= PSW_R;
+			mtctl(-1, 0);
+		}
+
 		regs->gr[0] = psw;
 		regs->iaoq[0] = haddr | 3;
 		regs->iaoq[1] = regs->iaoq[0] + 4;
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -20,7 +20,6 @@
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/compat.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -65,7 +64,7 @@ sigset_64to32(compat_sigset_t *s32, sigs
 }
 
 static int
-put_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
+put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
 {
 	compat_sigset_t s;
 
@@ -76,7 +75,7 @@ put_sigset32(compat_sigset_t *up, sigset
 }
 
 static int
-get_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
+get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
 {
 	compat_sigset_t s;
 	int r;
@@ -90,7 +89,7 @@ get_sigset32(compat_sigset_t *up, sigset
 	return r;
 }
 
-int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
+int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset,
 				    unsigned int sigsetsize)
 {
 	sigset_t old_set, new_set;
@@ -99,8 +98,8 @@ int sys32_rt_sigprocmask(int how, compat
 	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);
+	KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL,
+				 oset ? (sigset_t __user *)&old_set : NULL, sigsetsize);
 
 	if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize))
 		return -EFAULT;
@@ -109,12 +108,12 @@ int sys32_rt_sigprocmask(int how, compat
 }
 
 
-int sys32_rt_sigpending(compat_sigset_t *uset, unsigned int sigsetsize)
+int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize)
 {
 	int ret;
 	sigset_t set;
 
-	KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize);
+	KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize);
 
 	if (!ret && put_sigset32(uset, &set, sigsetsize))
 		return -EFAULT;
@@ -123,7 +122,7 @@ int sys32_rt_sigpending(compat_sigset_t 
 }
 
 long
-sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact,
+sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact,
                  size_t sigsetsize)
 {
 	struct k_sigaction32 new_sa32, old_sa32;
@@ -151,7 +150,7 @@ sys32_rt_sigaction(int sig, const struct
 }
 
 int 
-do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned long sp)
+do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp)
 {
 	compat_stack_t ss32, oss32;
 	stack_t ss, oss;
@@ -162,7 +161,7 @@ do_sigaltstack32 (const compat_stack_t *
 		if (copy_from_user(&ss32, uss32, sizeof ss32))
 			return -EFAULT;
 
-		ss.ss_sp = (void *)(unsigned long)ss32.ss_sp;
+		ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp;
 		ss.ss_flags = ss32.ss_flags;
 		ss.ss_size = ss32.ss_size;
 
@@ -172,7 +171,7 @@ do_sigaltstack32 (const compat_stack_t *
 	if (uoss32)
 		ossp = &oss;
 
-	KERNEL_SYSCALL(ret, do_sigaltstack, ssp, ossp, sp);
+	KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp);
 
 	if (!ret && uoss32) {
 		oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp;
@@ -186,7 +185,7 @@ do_sigaltstack32 (const compat_stack_t *
 }
 
 long
-restore_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf,
+restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
 		struct pt_regs *regs)
 {
 	long err = 0;
@@ -265,7 +264,7 @@ restore_sigcontext32(struct compat_sigco
  * truncate for a 32-bit userspace.
  */
 long
-setup_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf, 
+setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, 
 		struct pt_regs *regs, int in_syscall)		 
 {
 	compat_int_t flags = 0;
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -31,13 +31,13 @@ struct k_sigaction32 {
 
 void sigset_32to64(sigset_t *s64, compat_sigset_t *s32);
 void sigset_64to32(compat_sigset_t *s32, sigset_t *s64);
-int do_sigaltstack32 (const compat_stack_t *uss32, 
-		compat_stack_t *uoss32, unsigned long sp);
-long restore_sigcontext32(struct compat_sigcontext *sc, 
-		struct compat_regfile *rf,
+int do_sigaltstack32 (const compat_stack_t __user *uss32, 
+		compat_stack_t __user *uoss32, unsigned long sp);
+long restore_sigcontext32(struct compat_sigcontext __user *sc, 
+		struct compat_regfile __user *rf,
 		struct pt_regs *regs);
-long setup_sigcontext32(struct compat_sigcontext *sc, 
-		struct compat_regfile *rf,
+long setup_sigcontext32(struct compat_sigcontext __user *sc, 
+		struct compat_regfile __user *rf,
 		struct pt_regs *regs, int in_syscall);
 
 #endif
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -60,8 +60,6 @@ volatile struct task_struct *smp_init_cu
 
 static volatile int cpu_now_booting = 0;	/* track which CPU is booting */
 
-unsigned long cache_decay_ticks;	/* declared by include/linux/sched.h */
-
 static int parisc_max_cpus = 1;
 
 /* online cpus are ones that we've managed to bring up completely
@@ -583,8 +581,6 @@ void __devinit smp_prepare_boot_cpu(void
 
 	cpu_set(bootstrap_processor, cpu_online_map);
 	cpu_set(bootstrap_processor, cpu_present_map);
-
-	cache_decay_ticks = HZ/100;	/* FIXME very rough.  */
 }
 
 
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -32,7 +32,7 @@
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 
-int sys_pipe(int *fildes)
+int sys_pipe(int __user *fildes)
 {
 	int fd[2];
 	int error;
@@ -161,21 +161,10 @@ asmlinkage unsigned long sys_mmap(unsign
 	}
 }
 
-long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
-{
-	unsigned long raddr;
-	int r;
-
-	r = do_shmat(shmid, shmaddr, shmflag, &raddr);
-	if (r < 0)
-		return r;
-	return raddr;
-}
-
 /* Fucking broken ABI */
 
-#ifdef CONFIG_PARISC64
-asmlinkage long parisc_truncate64(const char * path,
+#ifdef CONFIG_64BIT
+asmlinkage long parisc_truncate64(const char __user * path,
 					unsigned int high, unsigned int low)
 {
 	return sys_truncate(path, (long)high << 32 | low);
@@ -189,7 +178,7 @@ asmlinkage long parisc_ftruncate64(unsig
 
 /* stubs for the benefit of the syscall_table since truncate64 and truncate 
  * are identical on LP64 */
-asmlinkage long sys_truncate64(const char * path, unsigned long length)
+asmlinkage long sys_truncate64(const char __user * path, unsigned long length)
 {
 	return sys_truncate(path, length);
 }
@@ -203,7 +192,7 @@ asmlinkage long sys_fcntl64(unsigned int
 }
 #else
 
-asmlinkage long parisc_truncate64(const char * path,
+asmlinkage long parisc_truncate64(const char __user * path,
 					unsigned int high, unsigned int low)
 {
 	return sys_truncate64(path, (loff_t)high << 32 | low);
@@ -216,13 +205,13 @@ asmlinkage long parisc_ftruncate64(unsig
 }
 #endif
 
-asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
+asmlinkage ssize_t parisc_pread64(unsigned int fd, char __user *buf, size_t count,
 					unsigned int high, unsigned int low)
 {
 	return sys_pread64(fd, buf, count, (loff_t)high << 32 | low);
 }
 
-asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf,
+asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char __user *buf,
 			size_t count, unsigned int high, unsigned int low)
 {
 	return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -74,7 +74,7 @@ asmlinkage int sys32_execve(struct pt_re
 	char *filename;
 
 	DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
-	filename = getname((char *) regs->gr[26]);
+	filename = getname((const char __user *) regs->gr[26]);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
@@ -111,13 +111,13 @@ struct __sysctl_args32 {
 	u32 __unused[4];
 };
 
-asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
 {
 	struct __sysctl_args32 tmp;
 	int error;
 	unsigned int oldlen32;
 	size_t oldlen, *oldlenp = NULL;
-	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+	unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
 	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
 	       void *newval, size_t newlen);
 
@@ -159,7 +159,7 @@ asmlinkage long sys32_sysctl(struct __sy
 					error = -EFAULT;
 			}
 		}
-		if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
+		if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused)))
 			error = -EFAULT;
 	}
 	return error;
@@ -168,19 +168,19 @@ asmlinkage long sys32_sysctl(struct __sy
 #endif /* CONFIG_SYSCTL */
 
 asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
-	struct compat_timespec *interval)
+	struct compat_timespec __user *interval)
 {
 	struct timespec t;
 	int ret;
-	
-	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t);
+
+	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t);
 	if (put_compat_timespec(&t, interval))
 		return -EFAULT;
 	return ret;
 }
 
 static int
-put_compat_timeval(struct compat_timeval *u, struct timeval *t)
+put_compat_timeval(struct compat_timeval __user *u, struct timeval *t)
 {
 	struct compat_timeval t32;
 	t32.tv_sec = t->tv_sec;
@@ -188,7 +188,7 @@ put_compat_timeval(struct compat_timeval
 	return copy_to_user(u, &t32, sizeof t32);
 }
 
-static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
 {
 	long usec;
 
@@ -201,7 +201,7 @@ static inline long get_ts32(struct times
 }
 
 asmlinkage int
-sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
     extern void do_gettimeofday(struct timeval *tv);
 
@@ -220,7 +220,7 @@ sys32_gettimeofday(struct compat_timeval
 }
 
 asmlinkage 
-int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
 	struct timespec kts;
 	struct timezone ktz;
@@ -237,7 +237,7 @@ int sys32_settimeofday(struct compat_tim
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
 {
 	int err;
 
@@ -294,24 +294,24 @@ struct old_linux32_dirent {
 };
 
 struct getdents32_callback {
-	struct linux32_dirent * current_dir;
-	struct linux32_dirent * previous;
+	struct linux32_dirent __user * current_dir;
+	struct linux32_dirent __user * previous;
 	int count;
 	int error;
 };
 
 struct readdir32_callback {
-	struct old_linux32_dirent * dirent;
+	struct old_linux32_dirent __user * 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)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (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 linux32_dirent __user * dirent;
 	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
 	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
 
@@ -327,17 +327,17 @@ filldir32 (void *__buf, const char *name
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	dirent = (struct linux32_dirent *)((char *)dirent + reclen);
+	dirent = ((void __user *)dirent) + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
 }
 
 asmlinkage long
-sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
+sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count)
 {
 	struct file * file;
-	struct linux32_dirent * lastdirent;
+	struct linux32_dirent __user * lastdirent;
 	struct getdents32_callback buf;
 	int error;
 
@@ -346,7 +346,7 @@ sys32_getdents (unsigned int fd, void * 
 	if (!file)
 		goto out;
 
-	buf.current_dir = (struct linux32_dirent *) dirent;
+	buf.current_dir = (struct linux32_dirent __user *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
@@ -372,7 +372,7 @@ fillonedir32 (void * __buf, const char *
 	      unsigned int d_type)
 {
 	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
-	struct old_linux32_dirent * dirent;
+	struct old_linux32_dirent __user * dirent;
 
 	if (buf->count)
 		return -EINVAL;
@@ -387,7 +387,7 @@ fillonedir32 (void * __buf, const char *
 }
 
 asmlinkage long
-sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
+sys32_readdir (unsigned int fd, void __user * dirent, unsigned int count)
 {
 	int error;
 	struct file * file;
@@ -422,7 +422,7 @@ get_fd_set32(unsigned long n, u32 *ufdse
 	if (ufdset) {
 		unsigned long odd;
 
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
+		if (!access_ok(VERIFY_WRITE, ufdset, n*sizeof(u32)))
 			return -EFAULT;
 
 		odd = n & 1UL;
@@ -477,7 +477,7 @@ struct msgbuf32 {
 };
 
 asmlinkage long sys32_msgsnd(int msqid,
-				struct msgbuf32 *umsgp32,
+				struct msgbuf32 __user *umsgp32,
 				size_t msgsz, int msgflg)
 {
 	struct msgbuf *mb;
@@ -494,14 +494,14 @@ asmlinkage long sys32_msgsnd(int msqid,
 	if (err)
 		err = -EFAULT;
 	else
-		KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg);
+		KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
 
 	kfree(mb);
 	return err;
 }
 
 asmlinkage long sys32_msgrcv(int msqid,
-				struct msgbuf32 *umsgp32,
+				struct msgbuf32 __user *umsgp32,
 				size_t msgsz, long msgtyp, int msgflg)
 {
 	struct msgbuf *mb;
@@ -511,7 +511,7 @@ asmlinkage long sys32_msgrcv(int msqid,
 	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-	KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg);
+	KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
 
 	if (err >= 0) {
 		len = err;
@@ -528,7 +528,7 @@ asmlinkage long sys32_msgrcv(int msqid,
 	return err;
 }
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
 {
         mm_segment_t old_fs = get_fs();
         int ret;
@@ -538,7 +538,7 @@ asmlinkage int sys32_sendfile(int out_fd
                 return -EFAULT;
 
         set_fs(KERNEL_DS);
-        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
         set_fs(old_fs);
 
         if (offset && put_user(of, offset))
@@ -547,9 +547,7 @@ asmlinkage int sys32_sendfile(int out_fd
         return ret;
 }
 
-typedef long __kernel_loff_t32;		/* move this to asm/posix_types.h? */
-
-asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count)
+asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
 	int ret;
@@ -559,7 +557,7 @@ asmlinkage int sys32_sendfile64(int out_
 		return -EFAULT;
 		
 	set_fs(KERNEL_DS);
-	ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
+	ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
 	set_fs(old_fs);
 	
 	if (offset && put_user(lof, offset))
@@ -598,7 +596,7 @@ struct timex32 {
 	int  :32; int  :32; int  :32; int  :32;
 };
 
-asmlinkage long sys32_adjtimex(struct timex32 *txc_p32)
+asmlinkage long sys32_adjtimex(struct timex32 __user *txc_p32)
 {
 	struct timex txc;
 	struct timex32 t32;
@@ -647,7 +645,7 @@ struct sysinfo32 {
  * damage, I decided to just duplicate the code from sys_sysinfo here.
  */
 
-asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
 {
 	struct sysinfo val;
 	int err;
@@ -714,7 +712,7 @@ asmlinkage long sys32_semctl(int semid, 
 	return sys_semctl (semid, semnum, cmd, arg);
 }
 
-long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf,
+long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
 			  size_t len)
 {
 	return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -297,7 +297,7 @@
 	ENTRY_DIFF(msgrcv)
 	ENTRY_SAME(msgget)		/* 190 */
 	ENTRY_SAME(msgctl)
-	ENTRY_SAME(shmat_wrapper)
+	ENTRY_SAME(shmat)
 	ENTRY_SAME(shmdt)
 	ENTRY_SAME(shmget)
 	ENTRY_SAME(shmctl)		/* 195 */
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -163,13 +163,20 @@ void show_stack(struct task_struct *task
 	struct unwind_frame_info info;
 
 	if (!task) {
-		unsigned long sp, ip, rp;
+		unsigned long sp;
+		struct pt_regs *r;
 
 HERE:
 		asm volatile ("copy %%r30, %0" : "=r"(sp));
-		ip = (unsigned long)&&HERE;
-		rp = (unsigned long)__builtin_return_address(0);
-		unwind_frame_init(&info, current, sp, ip, rp);
+		r = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
+		if (!r)
+			return;
+		memset(r, 0, sizeof(struct pt_regs));
+		r->iaoq[0] = (unsigned long)&&HERE;
+		r->gr[2] = (unsigned long)__builtin_return_address(0);
+		r->gr[30] = sp;
+		unwind_frame_init(&info, current, r);
+		kfree(r);
 	} else {
 		unwind_frame_init_from_blocked_task(&info, task);
 	}
@@ -242,7 +249,7 @@ void handle_gdb_break(struct pt_regs *re
 	struct siginfo si;
 
 	si.si_code = wot;
-	si.si_addr = (void *) (regs->iaoq[0] & ~3);
+	si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
 	si.si_signo = SIGTRAP;
 	si.si_errno = 0;
 	force_sig_info(SIGTRAP, &si, current);
@@ -263,7 +270,7 @@ void handle_break(unsigned iir, struct p
 		show_regs(regs);
 #endif
 		si.si_code = TRAP_BRKPT;
-		si.si_addr = (void *) (regs->iaoq[0] & ~3);
+		si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
 		si.si_signo = SIGTRAP;
 		force_sig_info(SIGTRAP, &si, current);
 		break;
@@ -281,7 +288,7 @@ void handle_break(unsigned iir, struct p
 #endif
 		si.si_signo = SIGTRAP;
 		si.si_code = TRAP_BRKPT;
-		si.si_addr = (void *) (regs->iaoq[0] & ~3);
+		si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
 		force_sig_info(SIGTRAP, &si, current);
 		return;
 	}
@@ -416,7 +423,7 @@ void parisc_terminate(char *msg, struct 
 	{
 		/* show_stack(NULL, (unsigned long *)regs->gr[30]); */
 		struct unwind_frame_info info;
-		unwind_frame_init(&info, current, regs->gr[30], regs->iaoq[0], regs->gr[2]);
+		unwind_frame_init(&info, current, regs);
 		do_show_stack(&info);
 	}
 
@@ -569,7 +576,7 @@ void handle_interruption(int code, struc
 	give_sigill:
 		si.si_signo = SIGILL;
 		si.si_errno = 0;
-		si.si_addr = (void *) regs->iaoq[0];
+		si.si_addr = (void __user *) regs->iaoq[0];
 		force_sig_info(SIGILL, &si, current);
 		return;
 
@@ -577,7 +584,7 @@ void handle_interruption(int code, struc
 		/* Overflow Trap, let the userland signal handler do the cleanup */
 		si.si_signo = SIGFPE;
 		si.si_code = FPE_INTOVF;
-		si.si_addr = (void *) regs->iaoq[0];
+		si.si_addr = (void __user *) regs->iaoq[0];
 		force_sig_info(SIGFPE, &si, current);
 		return;
 		
@@ -699,9 +706,9 @@ void handle_interruption(int code, struc
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
 		if (code == 7)
-		    si.si_addr = (void *) regs->iaoq[0];
+		    si.si_addr = (void __user *) regs->iaoq[0];
 		else
-		    si.si_addr = (void *) regs->ior;
+		    si.si_addr = (void __user *) regs->ior;
 		force_sig_info(SIGSEGV, &si, current);
 		return;
 
@@ -721,7 +728,7 @@ void handle_interruption(int code, struc
 			si.si_signo = SIGBUS;
 			si.si_code = BUS_OBJERR;
 			si.si_errno = 0;
-			si.si_addr = (void *) regs->ior;
+			si.si_addr = (void __user *) regs->ior;
 			force_sig_info(SIGBUS, &si, current);
 			return;
 		}
@@ -732,7 +739,7 @@ void handle_interruption(int code, struc
 	}
 
 	if (user_mode(regs)) {
-	    if ((fault_space>>SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
+	    if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
 #ifdef PRINT_USER_FAULTS
 		if (fault_space == 0)
 			printk(KERN_DEBUG "User Fault on Kernel Space ");
@@ -745,7 +752,7 @@ void handle_interruption(int code, struc
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
 		si.si_code = SEGV_MAPERR;
-		si.si_addr = (void *) regs->ior;
+		si.si_addr = (void __user *) regs->ior;
 		force_sig_info(SIGSEGV, &si, current);
 		return;
 	    }
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
--- a/arch/parisc/kernel/unaligned.c
+++ b/arch/parisc/kernel/unaligned.c
@@ -744,7 +744,7 @@ void handle_unaligned(struct pt_regs *re
 			si.si_signo = SIGSEGV;
 			si.si_errno = 0;
 			si.si_code = SEGV_MAPERR;
-			si.si_addr = (void *)regs->ior;
+			si.si_addr = (void __user *)regs->ior;
 			force_sig_info(SIGSEGV, &si, current);
 		}
 		else
@@ -754,7 +754,7 @@ force_sigbus:
 			si.si_signo = SIGBUS;
 			si.si_errno = 0;
 			si.si_code = BUS_ADRALN;
-			si.si_addr = (void *)regs->ior;
+			si.si_addr = (void __user *)regs->ior;
 			force_sig_info(SIGBUS, &si, current);
 		}
 		
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -36,8 +36,7 @@ static spinlock_t unwind_lock;
  * possible (before the slab allocator is initialized)
  */
 static struct unwind_table kernel_unwind_table;
-static struct unwind_table *unwind_tables, *unwind_tables_end;
-
+static LIST_HEAD(unwind_tables);
 
 static inline const struct unwind_table_entry *
 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
@@ -65,14 +64,14 @@ find_unwind_entry_in_table(const struct 
 static const struct unwind_table_entry *
 find_unwind_entry(unsigned long addr)
 {
-	struct unwind_table *table = unwind_tables;
+	struct unwind_table *table;
 	const struct unwind_table_entry *e = NULL;
 
 	if (addr >= kernel_unwind_table.start && 
 	    addr <= kernel_unwind_table.end)
 		e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
-	else
-		for (; table; table = table->next) {
+	else 
+		list_for_each_entry(table, &unwind_tables, list) {
 			if (addr >= table->start && 
 			    addr <= table->end)
 				e = find_unwind_entry_in_table(table, addr);
@@ -99,7 +98,7 @@ unwind_table_init(struct unwind_table *t
 	table->end = base_addr + end->region_end;
 	table->table = (struct unwind_table_entry *)table_start;
 	table->length = end - start + 1;
-	table->next = NULL;
+	INIT_LIST_HEAD(&table->list);
 
 	for (; start <= end; start++) {
 		if (start < end && 
@@ -112,33 +111,60 @@ unwind_table_init(struct unwind_table *t
 	}
 }
 
-void *
+static void
+unwind_table_sort(struct unwind_table_entry *start,
+		  struct unwind_table_entry *finish)
+{
+	struct unwind_table_entry el, *p, *q;
+
+	for (p = start + 1; p < finish; ++p) {
+		if (p[0].region_start < p[-1].region_start) {
+			el = *p;
+			q = p;
+			do {
+				q[0] = q[-1];
+				--q;
+			} while (q > start && 
+				 el.region_start < q[-1].region_start);
+			*q = el;
+		}
+	}
+}
+
+struct unwind_table *
 unwind_table_add(const char *name, unsigned long base_addr, 
 		 unsigned long gp,
                  void *start, void *end)
 {
 	struct unwind_table *table;
 	unsigned long flags;
+	struct unwind_table_entry *s = (struct unwind_table_entry *)start;
+	struct unwind_table_entry *e = (struct unwind_table_entry *)end;
+
+	unwind_table_sort(s, e);
 
 	table = kmalloc(sizeof(struct unwind_table), GFP_USER);
 	if (table == NULL)
 		return NULL;
 	unwind_table_init(table, name, base_addr, gp, start, end);
 	spin_lock_irqsave(&unwind_lock, flags);
-	if (unwind_tables)
-	{
-		unwind_tables_end->next = table;
-		unwind_tables_end = table;
-	}
-	else
-	{
-		unwind_tables = unwind_tables_end = table;
-	}
+	list_add_tail(&table->list, &unwind_tables);
 	spin_unlock_irqrestore(&unwind_lock, flags);
 
 	return table;
 }
 
+void unwind_table_remove(struct unwind_table *table)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&unwind_lock, flags);
+	list_del(&table->list);
+	spin_unlock_irqrestore(&unwind_lock, flags);
+
+	kfree(table);
+}
+
 /* Called from setup_arch to import the kernel unwind info */
 static int unwind_init(void)
 {
@@ -148,6 +174,8 @@ static int unwind_init(void)
 	start = (long)&__start___unwind[0];
 	stop = (long)&__stop___unwind[0];
 
+	spin_lock_init(&unwind_lock);
+
 	printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
 	    start, stop,
 	    (stop - start) / sizeof(struct unwind_table_entry));
@@ -239,9 +267,9 @@ static void unwind_frame_regs(struct unw
 		    info->prev_sp, info->prev_ip);
 	} else {
 		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
-		    "Save_RP = %d size = %u\n", e->region_start, 
-		    e->region_end, e->Save_SP, e->Save_RP, 
-		    e->Total_frame_size);
+		    "Save_RP = %d, Millicode = %d size = %u\n", 
+		    e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
+		    e->Millicode, e->Total_frame_size);
 
 		looking_for_rp = e->Save_RP;
 
@@ -284,7 +312,9 @@ static void unwind_frame_regs(struct unw
 		}
 
 		info->prev_sp = info->sp - frame_size;
-		if (rpoffset)
+		if (e->Millicode)
+			info->rp = info->r31;
+		else if (rpoffset)
 			info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
 		info->prev_ip = info->rp;
 		info->rp = 0;
@@ -296,13 +326,14 @@ static void unwind_frame_regs(struct unw
 }
 
 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
-		       unsigned long sp, unsigned long ip, unsigned long rp)
+		       struct pt_regs *regs)
 {
 	memset(info, 0, sizeof(struct unwind_frame_info));
 	info->t = t;
-	info->sp = sp;
-	info->ip = ip;
-	info->rp = rp;
+	info->sp = regs->gr[30];
+	info->ip = regs->iaoq[0];
+	info->rp = regs->gr[2];
+	info->r31 = regs->gr[31];
 
 	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
 	    t ? (int)t->pid : -1, info->sp, info->ip);
@@ -310,14 +341,22 @@ void unwind_frame_init(struct unwind_fra
 
 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
 {
-	struct pt_regs *regs = &t->thread.regs;
-	unwind_frame_init(info, t, regs->ksp, regs->kpc, 0);
+	struct pt_regs *r = &t->thread.regs;
+	struct pt_regs *r2;
+
+	r2 = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
+	if (!r2)
+		return;
+	*r2 = *r;
+	r2->gr[30] = r->ksp;
+	r2->iaoq[0] = r->kpc;
+	unwind_frame_init(info, t, r2);
+	kfree(r2);
 }
 
 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
 {
-	unwind_frame_init(info, current, regs->gr[30], regs->iaoq[0],
-			  regs->gr[2]);
+	unwind_frame_init(info, current, regs);
 }
 
 int unwind_once(struct unwind_frame_info *next_frame)
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -29,7 +29,7 @@
 #include <asm/page.h>
 	
 /* ld script to make hppa Linux kernel */
-#ifndef CONFIG_PARISC64
+#ifndef CONFIG_64BIT
 OUTPUT_FORMAT("elf32-hppa-linux")
 OUTPUT_ARCH(hppa)
 #else
@@ -38,7 +38,7 @@ OUTPUT_ARCH(hppa:hppa2.0w)
 #endif
 
 ENTRY(_stext)
-#ifndef CONFIG_PARISC64
+#ifndef CONFIG_64BIT
 jiffies = jiffies_64 + 4;
 #else
 jiffies = jiffies_64;
@@ -84,6 +84,9 @@ SECTIONS
  
   .data : {			/* Data */
 	*(.data)
+	*(.data.vm0.pmd)
+	*(.data.vm0.pgd)
+	*(.data.vm0.pte)
 	CONSTRUCTORS
 	}
 
@@ -112,7 +115,7 @@ SECTIONS
   . = ALIGN(16384);	
   init_istack : { *(init_istack) }
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
   . = ALIGN(16);               /* Linkage tables */
   .opd : { *(.opd) } PROVIDE (__gp = .); 
   .plt : { *(.plt) } 
@@ -180,7 +183,7 @@ SECTIONS
   /* Sections to be discarded */
   /DISCARD/ : {
 	*(.exitcall.exit)
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 	/* temporary hack until binutils is fixed to not emit these
 	 for static binaries */
 	*(.interp)
diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c
--- a/arch/parisc/lib/checksum.c
+++ b/arch/parisc/lib/checksum.c
@@ -131,9 +131,9 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck)
  * 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 unsigned char *src, unsigned char *dst,
-                                          int len, unsigned int sum,
-                                          int *err_ptr)
+unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+					unsigned char *dst, int len,
+					unsigned int sum, int *err_ptr)
 {
 	int missing;
 
diff --git a/arch/parisc/lib/debuglocks.c b/arch/parisc/lib/debuglocks.c
--- a/arch/parisc/lib/debuglocks.c
+++ b/arch/parisc/lib/debuglocks.c
@@ -1,7 +1,7 @@
 /* 
  *    Debugging versions of SMP locking primitives.
  *
- *    Copyright (C) 2004 Thibaut VARENE <varenet@esiee.fr>
+ *    Copyright (C) 2004 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *    Some code stollen from alpha & sparc64 ;)
  *
@@ -239,8 +239,6 @@ int _dbg_write_trylock(rwlock_t *rw, con
 	if(rw->counter != 0) {
 		/* this basically never happens */
 		_raw_spin_unlock(&rw->lock);
-		
-		
 		return 0;
 	}
 
@@ -250,6 +248,7 @@ int _dbg_write_trylock(rwlock_t *rw, con
 	pdc_printf("%s:%d: try write_lock grabbed in %s at %p(%d)\n",
 		   bfile, bline, current->comm, inline_pc, cpu);
 #endif
+	return 1;
 }
 
 void _dbg_read_lock(rwlock_t * rw, const char *bfile, int bline)
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c
--- a/arch/parisc/lib/iomap.c
+++ b/arch/parisc/lib/iomap.c
@@ -43,10 +43,14 @@
 struct iomap_ops {
 	unsigned int (*read8)(void __iomem *);
 	unsigned int (*read16)(void __iomem *);
+	unsigned int (*read16be)(void __iomem *);
 	unsigned int (*read32)(void __iomem *);
+	unsigned int (*read32be)(void __iomem *);
 	void (*write8)(u8, void __iomem *);
 	void (*write16)(u16, void __iomem *);
+	void (*write16be)(u16, void __iomem *);
 	void (*write32)(u32, void __iomem *);
+	void (*write32be)(u32, void __iomem *);
 	void (*read8r)(void __iomem *, void *, unsigned long);
 	void (*read16r)(void __iomem *, void *, unsigned long);
 	void (*read32r)(void __iomem *, void *, unsigned long);
@@ -122,9 +126,13 @@ static void ioport_write32r(void __iomem
 static const struct iomap_ops ioport_ops = {
 	ioport_read8,
 	ioport_read16,
+	ioport_read16,
+	ioport_read32,
 	ioport_read32,
 	ioport_write8,
 	ioport_write16,
+	ioport_write16,
+	ioport_write32,
 	ioport_write32,
 	ioport_read8r,
 	ioport_read16r,
@@ -146,11 +154,21 @@ static unsigned int iomem_read16(void __
 	return readw(addr);
 }
 
+static unsigned int iomem_read16be(void __iomem *addr)
+{
+	return __raw_readw(addr);
+}
+
 static unsigned int iomem_read32(void __iomem *addr)
 {
 	return readl(addr);
 }
 
+static unsigned int iomem_read32be(void __iomem *addr)
+{
+	return __raw_readl(addr);
+}
+
 static void iomem_write8(u8 datum, void __iomem *addr)
 {
 	writeb(datum, addr);
@@ -161,11 +179,21 @@ static void iomem_write16(u16 datum, voi
 	writew(datum, addr);
 }
 
+static void iomem_write16be(u16 datum, void __iomem *addr)
+{
+	__raw_writew(datum, addr);
+}
+
 static void iomem_write32(u32 datum, void __iomem *addr)
 {
 	writel(datum, addr);
 }
 
+static void iomem_write32be(u32 datum, void __iomem *addr)
+{
+	__raw_writel(datum, addr);
+}
+
 static void iomem_read8r(void __iomem *addr, void *dst, unsigned long count)
 {
 	while (count--) {
@@ -217,10 +245,14 @@ static void iomem_write32r(void __iomem 
 static const struct iomap_ops iomem_ops = {
 	iomem_read8,
 	iomem_read16,
+	iomem_read16be,
 	iomem_read32,
+	iomem_read32be,
 	iomem_write8,
 	iomem_write16,
+	iomem_write16be,
 	iomem_write32,
+	iomem_write32be,
 	iomem_read8r,
 	iomem_read16r,
 	iomem_read32r,
@@ -253,6 +285,13 @@ unsigned int ioread16(void __iomem *addr
 	return le16_to_cpup((u16 *)addr);
 }
 
+unsigned int ioread16be(void __iomem *addr)
+{
+	if (unlikely(INDIRECT_ADDR(addr)))
+		return iomap_ops[ADDR_TO_REGION(addr)]->read16be(addr);
+	return *((u16 *)addr);
+}
+
 unsigned int ioread32(void __iomem *addr)
 {
 	if (unlikely(INDIRECT_ADDR(addr)))
@@ -260,6 +299,13 @@ unsigned int ioread32(void __iomem *addr
 	return le32_to_cpup((u32 *)addr);
 }
 
+unsigned int ioread32be(void __iomem *addr)
+{
+	if (unlikely(INDIRECT_ADDR(addr)))
+		return iomap_ops[ADDR_TO_REGION(addr)]->read32be(addr);
+	return *((u32 *)addr);
+}
+
 void iowrite8(u8 datum, void __iomem *addr)
 {
 	if (unlikely(INDIRECT_ADDR(addr))) {
@@ -278,6 +324,15 @@ void iowrite16(u16 datum, void __iomem *
 	}
 }
 
+void iowrite16be(u16 datum, void __iomem *addr)
+{
+	if (unlikely(INDIRECT_ADDR(addr))) {
+		iomap_ops[ADDR_TO_REGION(addr)]->write16be(datum, addr);
+	} else {
+		*((u16 *)addr) = datum;
+	}
+}
+
 void iowrite32(u32 datum, void __iomem *addr)
 {
 	if (unlikely(INDIRECT_ADDR(addr))) {
@@ -287,6 +342,15 @@ void iowrite32(u32 datum, void __iomem *
 	}
 }
 
+void iowrite32be(u32 datum, void __iomem *addr)
+{
+	if (unlikely(INDIRECT_ADDR(addr))) {
+		iomap_ops[ADDR_TO_REGION(addr)]->write32be(datum, addr);
+	} else {
+		*((u32 *)addr) = datum;
+	}
+}
+
 /* Repeating interfaces */
 
 void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
@@ -406,10 +470,14 @@ void pci_iounmap(struct pci_dev *dev, vo
 
 EXPORT_SYMBOL(ioread8);
 EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread16be);
 EXPORT_SYMBOL(ioread32);
+EXPORT_SYMBOL(ioread32be);
 EXPORT_SYMBOL(iowrite8);
 EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite16be);
 EXPORT_SYMBOL(iowrite32);
+EXPORT_SYMBOL(iowrite32be);
 EXPORT_SYMBOL(ioread8_rep);
 EXPORT_SYMBOL(ioread16_rep);
 EXPORT_SYMBOL(ioread32_rep);
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
--- a/arch/parisc/lib/memcpy.c
+++ b/arch/parisc/lib/memcpy.c
@@ -111,7 +111,7 @@ DECLARE_PER_CPU(struct exception_data, e
 	"\t" EXC_WORD "\t" #_e "\n"			\
 	"\t.previous\n"					\
 	: _tt(_t), "+r"(_a)				\
-	: "1"(_a)					\
+	: 						\
 	: "r8")
 
 #define def_store_ai_insn(_insn,_sz,_tt,_s,_a,_t,_e) 	\
@@ -122,7 +122,7 @@ DECLARE_PER_CPU(struct exception_data, e
 	"\t" EXC_WORD "\t" #_e "\n"			\
 	"\t.previous\n"					\
 	: "+r"(_a) 					\
-	: _tt(_t), "0"(_a)				\
+	: _tt(_t)					\
 	: "r8")
 
 #define ldbma(_s, _a, _t, _e) def_load_ai_insn(ldbs,1,"=r",_s,_a,_t,_e)
@@ -297,7 +297,7 @@ handle_store_error:
 unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
 {
 	register unsigned long src, dst, t1, t2, t3;
-	register char *pcs, *pcd;
+	register unsigned char *pcs, *pcd;
 	register unsigned int *pws, *pwd;
 	register double *pds, *pdd;
 	unsigned long ret = 0;
diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
--- a/arch/parisc/math-emu/driver.c
+++ b/arch/parisc/math-emu/driver.c
@@ -27,7 +27,6 @@
  *  Copyright (C) 2001	      Hewlett-Packard <bame@debian.org>
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include "float.h"
 #include "math-emu.h"
@@ -120,7 +119,7 @@ handle_fpe(struct pt_regs *regs)
 	    si.si_signo = signalcode >> 24;
 	    si.si_errno = 0;
 	    si.si_code = signalcode & 0xffffff;
-	    si.si_addr = (void *) regs->iaoq[0];
+	    si.si_addr = (void __user *) regs->iaoq[0];
 	    force_sig_info(si.si_signo, &si, current);
 	    return -1;
 	}
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -225,7 +225,7 @@ bad_area:
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
 		si.si_code = SEGV_MAPERR;
-		si.si_addr = (void *) address;
+		si.si_addr = (void __user *) address;
 		force_sig_info(SIGSEGV, &si, current);
 		return;
 	}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -21,6 +21,7 @@
 #include <linux/swap.h>
 #include <linux/unistd.h>
 #include <linux/nodemask.h>	/* for node_online_map */
+#include <linux/pagemap.h>	/* for release_pages and page_cache_release */
 
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
@@ -59,8 +60,6 @@ static struct resource pdcdata_resource 
 
 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.
  */
@@ -180,7 +179,7 @@ static void __init setup_bootmem(void)
 
 			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",
+			printk(KERN_INFO "%2d) Start 0x%016lx End 0x%016lx Size %6ld MB\n",
 				i,start, start + (size - 1), size >> 20);
 		}
 	}
@@ -213,7 +212,7 @@ static void __init setup_bootmem(void)
 
 		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);
+			printk(KERN_WARNING "Memory truncated to %ld MB\n", mem_limit >> 20);
 			if (mem_max == mem_limit)
 				npmem_ranges = i;
 			else {
@@ -229,7 +228,7 @@ static void __init setup_bootmem(void)
 		mem_max += rsize;
 	}
 
-	printk(KERN_INFO "Total Memory: %ld Mb\n",mem_max >> 20);
+	printk(KERN_INFO "Total Memory: %ld MB\n",mem_max >> 20);
 
 #ifndef CONFIG_DISCONTIGMEM
 	/* Merge the ranges, keeping track of the holes */
@@ -445,7 +444,6 @@ void __init mem_init(void)
 
 #ifndef CONFIG_DISCONTIGMEM
 	max_mapnr = page_to_pfn(virt_to_page(high_memory - 1)) + 1;
-	mem_map = zone_table[ZONE_DMA]->zone_mem_map;
 	totalram_pages += free_all_bootmem();
 #else
 	{
diff --git a/arch/parisc/mm/kmap.c b/arch/parisc/mm/kmap.c
--- a/arch/parisc/mm/kmap.c
+++ b/arch/parisc/mm/kmap.c
@@ -49,10 +49,10 @@ typedef void (*pte_iterator_t) (pte_t * 
  * 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)
+static void unmap_cached_pte(pte_t * pte, unsigned long addr, unsigned long arg)
 {
 	pte_t page = *pte;
-	pte_clear(pte);
+	pte_clear(&init_mm, addr, pte);
 	if (!pte_none(page)) {
 		if (pte_present(page)) {
 			unsigned long map_nr = pte_pagenr(page);
diff --git a/arch/ppc/8260_io/Kconfig b/arch/ppc/8260_io/Kconfig
--- a/arch/ppc/8260_io/Kconfig
+++ b/arch/ppc/8260_io/Kconfig
@@ -42,7 +42,7 @@ config USE_MDIO
 choice
 	prompt "Type of PHY"
 	depends on 8260 && USE_MDIO
-	default FCC_LXT971
+	default FCC_GENERIC_PHY
 
 config FCC_LXT970
 	bool "LXT970"
@@ -53,6 +53,13 @@ config FCC_LXT971
 config FCC_QS6612
 	bool "QS6612"
 
+config FCC_DM9131
+	bool "DM9131"
+
+config FCC_DM9161
+	bool "DM9161"
+
+config FCC_GENERIC_PHY
+	bool "Generic"
 endchoice
 endmenu
-
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -16,6 +16,9 @@
  * small packets.  Since this is a cache coherent processor and CPM,
  * I could also preallocate SKB's and use them directly on the interface.
  *
+ * 2004-12	Leo Li (leoli@freescale.com)
+ * - Rework the FCC clock configuration part, make it easier to configure.
+ *
  */
 
 #include <linux/config.h>
@@ -34,6 +37,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/workqueue.h>
 #include <linux/bitops.h>
 
 #include <asm/immap_cpm2.h>
@@ -41,6 +46,26 @@
 #include <asm/mpc8260.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
+#include <asm/signal.h>
+
+/* We can't use the PHY interrupt if we aren't using MDIO. */
+#if !defined(CONFIG_USE_MDIO)
+#undef PHY_INTERRUPT
+#endif
+
+/* If we have a PHY interrupt, we will advertise both full-duplex and half-
+ * duplex capabilities.  If we don't have a PHY interrupt, then we will only
+ * advertise half-duplex capabilities.
+ */
+#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \
+				 ADVERTISE_CSMA)
+#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \
+				 MII_ADVERTISE_HALF)
+#ifdef PHY_INTERRUPT
+#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_ALL
+#else
+#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_HALF
+#endif
 #include <asm/cpm2.h>
 
 /* The transmitter timeout
@@ -65,18 +90,6 @@ typedef struct {
 	const phy_cmd_t *shutdown;
 } phy_info_t;
 
-/* Register definitions for the PHY. */
-
-#define MII_REG_CR          0  /* Control Register                         */
-#define MII_REG_SR          1  /* Status Register                          */
-#define MII_REG_PHYIR1      2  /* PHY Identification Register 1            */
-#define MII_REG_PHYIR2      3  /* PHY Identification Register 2            */
-#define MII_REG_ANAR        4  /* A-N Advertisement Register               */
-#define MII_REG_ANLPAR      5  /* A-N Link Partner Ability Register        */
-#define MII_REG_ANER        6  /* A-N Expansion Register                   */
-#define MII_REG_ANNPTR      7  /* A-N Next Page Transmit Register          */
-#define MII_REG_ANLPRNPR    8  /* A-N Link Partner Received Next Page Reg. */
-
 /* values for phy_status */
 
 #define PHY_CONF_ANE	0x0001  /* 1 auto-negotiation enabled */
@@ -111,13 +124,15 @@ typedef struct {
 #define TX_RING_MOD_MASK	15	/*   for this to work */
 
 /* The FCC stores dest/src/type, data, and checksum for receive packets.
+ * size includes support for VLAN
  */
-#define PKT_MAXBUF_SIZE		1518
+#define PKT_MAXBUF_SIZE		1522
 #define PKT_MINBUF_SIZE		64
 
 /* Maximum input DMA size.  Must be a should(?) be a multiple of 4.
-*/
-#define PKT_MAXDMA_SIZE		1520
+ * size includes support for VLAN
+ */
+#define PKT_MAXDMA_SIZE		1524
 
 /* Maximum input buffer size.  Must be a multiple of 32.
 */
@@ -129,8 +144,9 @@ static int fcc_enet_rx(struct net_device
 static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);
 static int fcc_enet_close(struct net_device *dev);
 static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
+/* static void set_multicast_list(struct net_device *dev); */
 static void fcc_restart(struct net_device *dev, int duplex);
+static void fcc_stop(struct net_device *dev);
 static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
 
 /* These will be configurable for the FCC choice.
@@ -141,6 +157,65 @@ static int fcc_enet_set_mac_address(stru
  * help show what pins are used for each device.
  */
 
+/* Since the CLK setting changes greatly from board to board, I changed
+ * it to a easy way.  You just need to specify which CLK number to use.
+ * Note that only limited choices can be make on each port.
+ */
+
+/* FCC1 Clock Source Configuration.  There are board specific.
+   Can only choose from CLK9-12 */
+#ifdef CONFIG_SBC82xx
+#define F1_RXCLK	9
+#define F1_TXCLK	10
+#elif defined(CONFIG_ADS8272)
+#define F1_RXCLK	11
+#define F1_TXCLK	10
+#else
+#define F1_RXCLK	12
+#define F1_TXCLK	11
+#endif
+
+/* FCC2 Clock Source Configuration.  There are board specific.
+   Can only choose from CLK13-16 */
+#ifdef CONFIG_ADS8272
+#define F2_RXCLK	15
+#define F2_TXCLK	16
+#else
+#define F2_RXCLK	13
+#define F2_TXCLK	14
+#endif
+
+/* FCC3 Clock Source Configuration.  There are board specific.
+   Can only choose from CLK13-16 */
+#define F3_RXCLK	15
+#define F3_TXCLK	16
+
+/* Automatically generates register configurations */
+#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */
+
+#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */
+#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */
+#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */
+#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */
+#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */
+#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */
+
+#define PC_F1RXCLK	PC_CLK(F1_RXCLK)
+#define PC_F1TXCLK	PC_CLK(F1_TXCLK)
+#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))
+#define CMX1_CLK_MASK	((uint)0xff000000)
+
+#define PC_F2RXCLK	PC_CLK(F2_RXCLK)
+#define PC_F2TXCLK	PC_CLK(F2_TXCLK)
+#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))
+#define CMX2_CLK_MASK	((uint)0x00ff0000)
+
+#define PC_F3RXCLK	PC_CLK(F3_RXCLK)
+#define PC_F3TXCLK	PC_CLK(F3_TXCLK)
+#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))
+#define CMX3_CLK_MASK	((uint)0x0000ff00)
+
+
 /* I/O Pin assignment for FCC1.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
  */
@@ -152,30 +227,12 @@ static int fcc_enet_set_mac_address(stru
 #define PA1_RXER	((uint)0x00000020)
 #define PA1_TXDAT	((uint)0x00003c00)
 #define PA1_RXDAT	((uint)0x0003c000)
-#define PA1_PSORA0	(PA1_RXDAT | PA1_TXDAT)
-#define PA1_PSORA1	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
+#define PA1_PSORA_BOUT	(PA1_RXDAT | PA1_TXDAT)
+#define PA1_PSORA_BIN	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
 				PA1_RXDV | PA1_RXER)
-#define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
-#define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
+#define PA1_DIRA_BOUT	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
+#define PA1_DIRA_BIN	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
 
-#ifdef CONFIG_SBC82xx
-/* rx is clk9, tx is clk10 */
-#define PC_F1RXCLK     ((uint)0x00000100)
-#define PC_F1TXCLK     ((uint)0x00000200)
-#define CMX1_CLK_ROUTE ((uint)0x25000000)
-#define CMX1_CLK_MASK  ((uint)0xff000000)
-#elif defined(CONFIG_ADS8272)
-#define PC_F1RXCLK	((uint)0x00000400)
-#define PC_F1TXCLK	((uint)0x00000200)
-#define CMX1_CLK_ROUTE	((uint)0x36000000)
-#define CMX1_CLK_MASK	((uint)0xff000000)
-#else /* other boards */
-/* CLK12 is receive, CLK11 is transmit.  These are board specific. */
-#define PC_F1RXCLK	((uint)0x00000800)
-#define PC_F1TXCLK	((uint)0x00000400)
-#define CMX1_CLK_ROUTE	((uint)0x3e000000)
-#define CMX1_CLK_MASK	((uint)0xff000000)
-#endif
 
 /* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
@@ -188,25 +245,12 @@ static int fcc_enet_set_mac_address(stru
 #define PB2_CRS		((uint)0x00000020)
 #define PB2_TXDAT	((uint)0x000003c0)
 #define PB2_RXDAT	((uint)0x00003c00)
-#define PB2_PSORB0	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
+#define PB2_PSORB_BOUT	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
 				PB2_RXER | PB2_RXDV | PB2_TXER)
-#define PB2_PSORB1	(PB2_TXEN)
-#define PB2_DIRB0	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
-#define PB2_DIRB1	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
+#define PB2_PSORB_BIN	(PB2_TXEN)
+#define PB2_DIRB_BOUT	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
+#define PB2_DIRB_BIN	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
 
-/* CLK13 is receive, CLK14 is transmit.  These are board dependent.
-*/
-#ifdef CONFIG_ADS8272
-#define PC_F2RXCLK	((uint)0x00004000)
-#define PC_F2TXCLK	((uint)0x00008000)
-#define CMX2_CLK_ROUTE	((uint)0x00370000)
-#define CMX2_CLK_MASK	((uint)0x00ff0000)
-#else
-#define PC_F2RXCLK	((uint)0x00001000)
-#define PC_F2TXCLK	((uint)0x00002000)
-#define CMX2_CLK_ROUTE	((uint)0x00250000)
-#define CMX2_CLK_MASK	((uint)0x00ff0000)
-#endif
 
 /* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
@@ -217,35 +261,61 @@ static int fcc_enet_set_mac_address(stru
 #define PB3_TXEN	((uint)0x00020000)
 #define PB3_COL		((uint)0x00040000)
 #define PB3_CRS		((uint)0x00080000)
+#ifndef CONFIG_RPX8260
 #define PB3_TXDAT	((uint)0x0f000000)
+#define PC3_TXDAT	((uint)0x00000000)
+#else
+#define PB3_TXDAT	((uint)0x0f000000)
+#define PC3_TXDAT	0
+#endif
 #define PB3_RXDAT	((uint)0x00f00000)
-#define PB3_PSORB0	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
+#define PB3_PSORB_BOUT	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
 				PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
-#define PB3_PSORB1	(0)
-#define PB3_DIRB0	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
-#define PB3_DIRB1	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
+#define PB3_PSORB_BIN	(0)
+#define PB3_DIRB_BOUT	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
+#define PB3_DIRB_BIN	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
+
+#define PC3_PSORC_BOUT	(PC3_TXDAT)
+#define PC3_PSORC_BIN	(0)
+#define PC3_DIRC_BOUT	(0)
+#define PC3_DIRC_BIN	(PC3_TXDAT)
 
-/* CLK15 is receive, CLK16 is transmit.  These are board dependent.
-*/
-#define PC_F3RXCLK	((uint)0x00004000)
-#define PC_F3TXCLK	((uint)0x00008000)
-#define CMX3_CLK_ROUTE	((uint)0x00003700)
-#define CMX3_CLK_MASK	((uint)0x0000ff00)
 
 /* MII status/control serial interface.
 */
-#ifdef	CONFIG_TQM8260
+#if defined(CONFIG_RPX8260)
+/* The EP8260 doesn't use Port C for MDIO */
+#define PC_MDIO		((uint)0x00000000)
+#define PC_MDCK		((uint)0x00000000)
+#elif defined(CONFIG_TQM8260)
 /* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */
 #define PC_MDIO		((uint)0x00000002)
 #define PC_MDCK		((uint)0x00000001)
 #elif defined(CONFIG_ADS8272)
 #define PC_MDIO		((uint)0x00002000)
 #define PC_MDCK		((uint)0x00001000)
+#elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260) || defined(CONFIG_PQ2FADS)
+#define PC_MDIO		((uint)0x00400000)
+#define PC_MDCK		((uint)0x00200000)
 #else
 #define PC_MDIO		((uint)0x00000004)
 #define PC_MDCK		((uint)0x00000020)
 #endif
 
+#if defined(CONFIG_USE_MDIO) && (!defined(PC_MDIO) || !defined(PC_MDCK))
+#error "Must define PC_MDIO and PC_MDCK if using MDIO"
+#endif
+
+/* PHY addresses */
+/* default to dynamic config of phy addresses */
+#define FCC1_PHY_ADDR 0
+#ifdef CONFIG_PQ2FADS
+#define FCC2_PHY_ADDR 0
+#else
+#define FCC2_PHY_ADDR 2
+#endif
+#define FCC3_PHY_ADDR 3
+
 /* A table of information for supporting FCCs.  This does two things.
  * First, we know how many FCCs we have and they are always externally
  * numbered from zero.  Second, it holds control register and I/O
@@ -253,6 +323,7 @@ static int fcc_enet_set_mac_address(stru
  */
 typedef struct fcc_info {
 	uint	fc_fccnum;
+	uint	fc_phyaddr;
 	uint	fc_cpmblock;
 	uint	fc_cpmpage;
 	uint	fc_proff;
@@ -266,33 +337,19 @@ typedef struct fcc_info {
 
 static fcc_info_t fcc_ports[] = {
 #ifdef CONFIG_FCC1_ENET
-	{ 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,
+	{ 0, FCC1_PHY_ADDR, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,
 		(PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK,
-# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
 		PC_MDIO, PC_MDCK },
-# else
-		0x00000004, 0x00000100 },
-# endif
 #endif
 #ifdef CONFIG_FCC2_ENET
-	{ 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,
+	{ 1, FCC2_PHY_ADDR, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,
 		(PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK,
-# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
 		PC_MDIO, PC_MDCK },
-# elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260)
-		0x00400000, 0x00200000 },
-# else
-		0x00000002, 0x00000080 },
-# endif
 #endif
 #ifdef CONFIG_FCC3_ENET
-	{ 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,
+	{ 2, FCC3_PHY_ADDR, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,
 		(PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK,
-# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
 		PC_MDIO, PC_MDCK },
-# else
-		0x00000001, 0x00000040 },
-# endif
 #endif
 };
 
@@ -310,8 +367,6 @@ struct fcc_enet_private {
 	ushort	skb_cur;
 	ushort	skb_dirty;
 
-	atomic_t n_pkts;  /* Number of packets in tx ring */
-
 	/* CPM dual port RAM relative addresses.
 	*/
 	cbd_t	*rx_bd_base;		/* Address of Rx and Tx buffers. */
@@ -321,7 +376,7 @@ struct fcc_enet_private {
 	volatile fcc_t	*fccp;
 	volatile fcc_enet_t	*ep;
 	struct	net_device_stats stats;
-	uint	tx_full;
+	uint	tx_free;
 	spinlock_t lock;
 
 #ifdef	CONFIG_USE_MDIO
@@ -329,7 +384,8 @@ struct fcc_enet_private {
 	uint	phy_id_done;
 	uint	phy_status;
 	phy_info_t	*phy;
-	struct tq_struct phy_task;
+	struct work_struct phy_relink;
+	struct work_struct phy_display_config;
 
 	uint	sequence_done;
 
@@ -354,14 +410,13 @@ static void init_fcc_param(fcc_info_t *f
 #ifdef	CONFIG_USE_MDIO
 static int	mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *));
 static uint	mii_send_receive(fcc_info_t *fip, uint cmd);
-
-static void	fcc_stop(struct net_device *dev);
+static void	mii_do_cmd(struct net_device *dev, const phy_cmd_t *c);
 
 /* Make MII read/write commands for the FCC.
 */
-#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
-#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
-						(VAL & 0xffff))
+#define mk_mii_read(REG)	(0x60020000 | (((REG) & 0x1f) << 18))
+#define mk_mii_write(REG, VAL)	(0x50020000 | (((REG) & 0x1f) << 18) | \
+						((VAL) & 0xffff))
 #define mk_mii_end	0
 #endif	/* CONFIG_USE_MDIO */
 
@@ -371,20 +426,14 @@ fcc_enet_start_xmit(struct sk_buff *skb,
 {
 	struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
 	volatile cbd_t	*bdp;
-	int idx;
-
-	if (!cep->link) {
-		/* Link is down or autonegotiation is in progress. */
-		return 1;
-	}
 
 	/* Fill in a Tx ring entry */
 	bdp = cep->cur_tx;
 
 #ifndef final_version
-	if (bdp->cbd_sc & BD_ENET_TX_READY) {
+	if (!cep->tx_free || (bdp->cbd_sc & BD_ENET_TX_READY)) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
-		 * This should not happen, since cep->tx_full should be set.
+		 * This should not happen, since the tx queue should be stopped.
 		 */
 		printk("%s: tx queue full!.\n", dev->name);
 		return 1;
@@ -407,21 +456,10 @@ fcc_enet_start_xmit(struct sk_buff *skb,
 	spin_lock_irq(&cep->lock);
 
 	/* Save skb pointer. */
-	idx = cep->skb_cur & TX_RING_MOD_MASK;
-	if (cep->tx_skbuff[idx]) {
-		/* This should never happen (any more).
-		   Leave the sanity check in for now... */
-		printk(KERN_ERR "EEP. cep->tx_skbuff[%d] is %p not NULL in %s\n", 
-		       idx, cep->tx_skbuff[idx], __func__);
-		printk(KERN_ERR "Expect to lose %d bytes of sock space", 
-		       cep->tx_skbuff[idx]->truesize);
-	}
-	cep->tx_skbuff[idx] = skb;
+	cep->tx_skbuff[cep->skb_cur] = skb;
 
 	cep->stats.tx_bytes += skb->len;
-	cep->skb_cur++;
-
-	atomic_inc(&cep->n_pkts);
+	cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
 
 	/* Send it on its way.  Tell CPM its ready, interrupt when done,
 	 * its the last BD of the frame, and to put the CRC on the end.
@@ -440,14 +478,8 @@ fcc_enet_start_xmit(struct sk_buff *skb,
 	else
 		bdp++;
 
-
-	/* If the tx_ring is full, stop the queue */
-	if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) {
-	  if (!netif_queue_stopped(dev)) {
-		netif_stop_queue(dev);	  
-		cep->tx_full = 1;
-	  }
-	}
+	if (!--cep->tx_free)
+		netif_stop_queue(dev);
 
 	cep->cur_tx = (cbd_t *)bdp;
 
@@ -468,8 +500,8 @@ fcc_enet_timeout(struct net_device *dev)
 	{
 		int	i;
 		cbd_t	*bdp;
-		printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
-		       cep->cur_tx, cep->tx_full ? " (full)" : "",
+		printk(" Ring data dump: cur_tx %p tx_free %d cur_rx %p.\n",
+		       cep->cur_tx, cep->tx_free,
 		       cep->cur_rx);
 		bdp = cep->tx_bd_base;
 		printk(" Tx @base %p :\n", bdp);
@@ -487,7 +519,7 @@ fcc_enet_timeout(struct net_device *dev)
 			       bdp->cbd_bufaddr);
 	}
 #endif
-	if (!cep->tx_full)
+	if (cep->tx_free)
 		netif_wake_queue(dev);
 }
 
@@ -500,16 +532,22 @@ fcc_enet_interrupt(int irq, void * dev_i
 	volatile cbd_t	*bdp;
 	ushort	int_events;
 	int	must_restart;
-	int idx;
 
 	cep = (struct fcc_enet_private *)dev->priv;
 
 	/* Get the interrupt events that caused us to be here.
 	*/
 	int_events = cep->fccp->fcc_fcce;
-	cep->fccp->fcc_fcce = int_events;
+	cep->fccp->fcc_fcce = (int_events & cep->fccp->fcc_fccm);
 	must_restart = 0;
 
+#ifdef PHY_INTERRUPT
+	/* We have to be careful here to make sure that we aren't
+	 * interrupted by a PHY interrupt.
+	 */
+	disable_irq_nosync(PHY_INTERRUPT);
+#endif
+
 	/* Handle receive event in its own function.
 	*/
 	if (int_events & FCC_ENET_RXF)
@@ -530,7 +568,7 @@ fcc_enet_interrupt(int irq, void * dev_i
 	    spin_lock(&cep->lock);
 	    bdp = cep->dirty_tx;
 	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
-		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+		if (cep->tx_free == TX_RING_SIZE)
 		    break;
 
 		if (bdp->cbd_sc & BD_ENET_TX_HB)	/* No heartbeat */
@@ -563,12 +601,9 @@ fcc_enet_interrupt(int irq, void * dev_i
 			cep->stats.collisions++;
 
 		/* Free the sk buffer associated with this last transmit. */
-		idx = cep->skb_dirty & TX_RING_MOD_MASK;
-		dev_kfree_skb_irq(cep->tx_skbuff[idx]);
-		cep->tx_skbuff[idx] = NULL;
-		cep->skb_dirty++;
-
-		atomic_dec(&cep->n_pkts);
+		dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
+		cep->tx_skbuff[cep->skb_dirty] = NULL;
+		cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
 
 		/* Update pointer to next buffer descriptor to be transmitted. */
 		if (bdp->cbd_sc & BD_ENET_TX_WRAP)
@@ -588,8 +623,7 @@ fcc_enet_interrupt(int irq, void * dev_i
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
-		if (cep->tx_full) {
-			cep->tx_full = 0;
+		if (!cep->tx_free++) {
 			if (netif_queue_stopped(dev)) {
 				netif_wake_queue(dev);
 			}
@@ -626,8 +660,13 @@ fcc_enet_interrupt(int irq, void * dev_i
 	 * put them.
 	 */
 	if (int_events & FCC_ENET_BSY) {
+		cep->fccp->fcc_fcce = FCC_ENET_BSY;
 		cep->stats.rx_dropped++;
 	}
+
+#ifdef PHY_INTERRUPT
+	enable_irq(PHY_INTERRUPT);
+#endif
 	return IRQ_HANDLED;
 }
 
@@ -726,8 +765,16 @@ for (;;) {
 static int
 fcc_enet_close(struct net_device *dev)
 {
-	/* Don't know what to do yet. */
+#ifdef	CONFIG_USE_MDIO
+	struct fcc_enet_private *fep = dev->priv;
+#endif
+
 	netif_stop_queue(dev);
+	fcc_stop(dev);
+#ifdef	CONFIG_USE_MDIO
+	if (fep->phy)
+		mii_do_cmd(dev, fep->phy->shutdown);
+#endif
 
 	return 0;
 }
@@ -784,15 +831,14 @@ static void mii_parse_sr(uint mii_reg, s
 
 	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
 
-	if (mii_reg & 0x0004)
+	if (mii_reg & BMSR_LSTATUS)
 		s |= PHY_STAT_LINK;
-	if (mii_reg & 0x0010)
+	if (mii_reg & BMSR_RFAULT)
 		s |= PHY_STAT_FAULT;
-	if (mii_reg & 0x0020)
+	if (mii_reg & BMSR_ANEGCOMPLETE)
 		s |= PHY_STAT_ANC;
 
 	fep->phy_status = s;
-	fep->link = (s & PHY_STAT_LINK) ? 1 : 0;
 }
 
 static void mii_parse_cr(uint mii_reg, struct net_device *dev)
@@ -802,9 +848,9 @@ static void mii_parse_cr(uint mii_reg, s
 
 	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
 
-	if (mii_reg & 0x1000)
+	if (mii_reg & BMCR_ANENABLE)
 		s |= PHY_CONF_ANE;
-	if (mii_reg & 0x4000)
+	if (mii_reg & BMCR_LOOPBACK)
 		s |= PHY_CONF_LOOP;
 
 	fep->phy_status = s;
@@ -817,17 +863,59 @@ static void mii_parse_anar(uint mii_reg,
 
 	s &= ~(PHY_CONF_SPMASK);
 
-	if (mii_reg & 0x0020)
+	if (mii_reg & ADVERTISE_10HALF)
 		s |= PHY_CONF_10HDX;
-	if (mii_reg & 0x0040)
+	if (mii_reg & ADVERTISE_10FULL)
 		s |= PHY_CONF_10FDX;
-	if (mii_reg & 0x0080)
+	if (mii_reg & ADVERTISE_100HALF)
 		s |= PHY_CONF_100HDX;
-	if (mii_reg & 0x00100)
+	if (mii_reg & ADVERTISE_100FULL)
 		s |= PHY_CONF_100FDX;
 
 	fep->phy_status = s;
 }
+
+/* ------------------------------------------------------------------------- */
+/* Generic PHY support.  Should work for all PHYs, but does not support link
+ * change interrupts.
+ */
+#ifdef CONFIG_FCC_GENERIC_PHY
+
+static phy_info_t phy_info_generic = {
+	0x00000000, /* 0-->match any PHY */
+	"GENERIC",
+
+	(const phy_cmd_t []) {  /* config */
+		/* advertise only half-duplex capabilities */
+		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_HALF),
+			mii_parse_anar },
+
+		/* enable auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* startup */
+		/* restart auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART),
+			NULL },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		/* We don't actually use the ack_int table with a generic
+		 * PHY, but putting a reference to mii_parse_sr here keeps
+		 * us from getting a compiler warning about unused static
+		 * functions in the case where we only compile in generic
+		 * PHY support.
+		 */
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* shutdown */
+		{ mk_mii_end, }
+	},
+};
+#endif	/* ifdef CONFIG_FCC_GENERIC_PHY */
+
 /* ------------------------------------------------------------------------- */
 /* The Level one LXT970 is used by many boards				     */
 
@@ -867,26 +955,26 @@ static phy_info_t phy_info_lxt970 = {
 
 	(const phy_cmd_t []) {  /* config */
 #if 0
-//		{ mk_mii_write(MII_REG_ANAR, 0x0021), NULL },
+//		{ mk_mii_write(MII_ADVERTISE, 0x0021), NULL },
 
 		/* Set default operation of 100-TX....for some reason
 		 * some of these bits are set on power up, which is wrong.
 		 */
 		{ mk_mii_write(MII_LXT970_CONFIG, 0), NULL },
 #endif
-		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
-		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_read(MII_BMCR), mii_parse_cr },
+		{ mk_mii_read(MII_ADVERTISE), mii_parse_anar },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_LXT970_IER, 0x0002), NULL },
-		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+		{ mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
 		/* read SR and ISR to acknowledge */
 
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
 		{ mk_mii_read(MII_LXT970_ISR), NULL },
 
 		/* find out the current status */
@@ -951,30 +1039,29 @@ static phy_info_t phy_info_lxt971 = {
 	"LXT971",
 
 	(const phy_cmd_t []) {  /* config */
-//		{ mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10  Mbps, HD */
-		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
-		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		/* configure link capabilities to advertise */
+		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_DEFAULT),
+			mii_parse_anar },
+
+		/* enable auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
-		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-
-		/* Somehow does the 971 tell me that the link is down
-		 * the first read after power-up.
-		 * read here to get a valid value in ack_int */
 
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		/* restart auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART),
+			NULL },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
 		/* find out the current status */
-
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_BMSR), NULL },
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
 		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
 
 		/* we only need to read ISR to acknowledge */
-
 		{ mk_mii_read(MII_LXT971_ISR), NULL },
 		{ mk_mii_end, }
 	},
@@ -984,8 +1071,7 @@ static phy_info_t phy_info_lxt971 = {
 	},
 };
 
-#endif /* CONFIG_FEC_LXT970 */
-
+#endif /* CONFIG_FCC_LXT971 */
 
 /* ------------------------------------------------------------------------- */
 /* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
@@ -1023,7 +1109,7 @@ static phy_info_t phy_info_qs6612 = {
 	"QS6612",
 
 	(const phy_cmd_t []) {  /* config */
-//	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10  Mbps */
+//	{ mk_mii_write(MII_ADVERTISE, 0x061), NULL }, /* 10  Mbps */
 
 		/* The PHY powers up isolated on the RPX,
 		 * so send a command to allow operation.
@@ -1033,13 +1119,13 @@ static phy_info_t phy_info_qs6612 = {
 
 		/* parse cr and anar to get some info */
 
-		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
-		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_read(MII_BMCR), mii_parse_cr },
+		{ mk_mii_read(MII_ADVERTISE), mii_parse_anar },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
-		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+		{ mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
@@ -1047,8 +1133,8 @@ static phy_info_t phy_info_qs6612 = {
 		/* we need to read ISR, SR and ANER to acknowledge */
 
 		{ mk_mii_read(MII_QS6612_ISR), NULL },
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
-		{ mk_mii_read(MII_REG_ANER), NULL },
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
+		{ mk_mii_read(MII_EXPANSION), NULL },
 
 		/* read pcr to get info */
 
@@ -1102,13 +1188,13 @@ static phy_info_t phy_info_dm9131 = {
 
 	(const phy_cmd_t []) {  /* config */
 		/* parse cr and anar to get some info */
-		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
-		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_read(MII_BMCR), mii_parse_cr },
+		{ mk_mii_read(MII_ADVERTISE), mii_parse_anar },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_DM9131_INTR, 0x0002), NULL },
-		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+		{ mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
@@ -1116,8 +1202,8 @@ static phy_info_t phy_info_dm9131 = {
 		/* we need to read INTR, SR and ANER to acknowledge */
 
 		{ mk_mii_read(MII_DM9131_INTR), NULL },
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
-		{ mk_mii_read(MII_REG_ANER), NULL },
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
+		{ mk_mii_read(MII_EXPANSION), NULL },
 
 		/* read acsr to get info */
 
@@ -1132,7 +1218,147 @@ static phy_info_t phy_info_dm9131 = {
 
 
 #endif /* CONFIG_FEC_DM9131 */
+#ifdef CONFIG_FCC_DM9161
+/* ------------------------------------------------------------------------- */
+/* DM9161 Control register values */
+#define MIIM_DM9161_CR_STOP     0x0400
+#define MIIM_DM9161_CR_RSTAN    0x1200
+
+#define MIIM_DM9161_SCR         0x10
+#define MIIM_DM9161_SCR_INIT    0x0610
+
+/* DM9161 Specified Configuration and Status Register */
+#define MIIM_DM9161_SCSR        0x11
+#define MIIM_DM9161_SCSR_100F   0x8000
+#define MIIM_DM9161_SCSR_100H   0x4000
+#define MIIM_DM9161_SCSR_10F    0x2000
+#define MIIM_DM9161_SCSR_10H    0x1000
+/* DM9161 10BT register */
+#define MIIM_DM9161_10BTCSR 	0x12
+#define MIIM_DM9161_10BTCSR_INIT 0x7800
+/* DM9161 Interrupt Register */
+#define MIIM_DM9161_INTR        0x15
+#define MIIM_DM9161_INTR_PEND           0x8000
+#define MIIM_DM9161_INTR_DPLX_MASK      0x0800
+#define MIIM_DM9161_INTR_SPD_MASK       0x0400
+#define MIIM_DM9161_INTR_LINK_MASK      0x0200
+#define MIIM_DM9161_INTR_MASK           0x0100
+#define MIIM_DM9161_INTR_DPLX_CHANGE    0x0010
+#define MIIM_DM9161_INTR_SPD_CHANGE     0x0008
+#define MIIM_DM9161_INTR_LINK_CHANGE    0x0004
+#define MIIM_DM9161_INTR_INIT           0x0000
+#define MIIM_DM9161_INTR_STOP   \
+(MIIM_DM9161_INTR_DPLX_MASK | MIIM_DM9161_INTR_SPD_MASK \
+  | MIIM_DM9161_INTR_LINK_MASK | MIIM_DM9161_INTR_MASK)
+
+static void mii_parse_dm9161_sr(uint mii_reg, struct net_device * dev)
+{
+	volatile struct fcc_enet_private *fep = dev->priv;
+	uint regstat,  timeout=0xffff;
+
+	while(!(mii_reg & 0x0020) && timeout--)
+	{
+		regstat=mk_mii_read(MII_BMSR);
+	        regstat |= fep->phy_addr <<23;
+	        mii_reg = mii_send_receive(fep->fip,regstat);
+	}
+
+	mii_parse_sr(mii_reg, dev);
+}
+
+static void mii_parse_dm9161_scsr(uint mii_reg, struct net_device * dev)
+{
+	volatile struct fcc_enet_private *fep = dev->priv;
+	uint s = fep->phy_status;
+
+	s &= ~(PHY_STAT_SPMASK);
+	switch((mii_reg >>12) & 0xf) {
+		case 1:
+		{
+			s |= PHY_STAT_10HDX;
+			printk("10BaseT Half Duplex\n");
+			break;
+		}
+		case 2:
+		{
+			s |= PHY_STAT_10FDX;
+		        printk("10BaseT Full Duplex\n");
+			break;
+		}
+		case 4:
+	        {
+			s |= PHY_STAT_100HDX;
+		        printk("100BaseT Half Duplex\n");
+			break;
+		}
+		case 8:
+		{
+			s |= PHY_STAT_100FDX;
+			printk("100BaseT Full Duplex\n");
+			break;
+		}
+	}
 
+	fep->phy_status = s;
+
+}
+
+static void mii_dm9161_wait(uint mii_reg, struct net_device *dev)
+{
+	int timeout = HZ;
+
+	/* Davicom takes a bit to come up after a reset,
+	 * so wait here for a bit */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(timeout);
+}
+
+static phy_info_t phy_info_dm9161 = {
+        0x00181b88,
+        "Davicom DM9161E",
+        (const phy_cmd_t[]) { /* config */
+                { mk_mii_write(MII_BMCR, MIIM_DM9161_CR_STOP), NULL},
+                /* Do not bypass the scrambler/descrambler */
+                { mk_mii_write(MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT), NULL},
+		/* Configure 10BTCSR register */
+		{ mk_mii_write(MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT),NULL},
+                /* Configure some basic stuff */
+                { mk_mii_write(MII_BMCR, 0x1000), NULL},
+		{ mk_mii_read(MII_BMCR), mii_parse_cr },
+		{ mk_mii_read(MII_ADVERTISE), mii_parse_anar },
+		{ mk_mii_end,}
+        },
+       (const phy_cmd_t[]) { /* startup */
+                /* Restart Auto Negotiation */
+                { mk_mii_write(MII_BMCR, MIIM_DM9161_CR_RSTAN), NULL},
+                /* Status is read once to clear old link state */
+                { mk_mii_read(MII_BMSR), mii_dm9161_wait},
+                /* Auto-negotiate */
+                { mk_mii_read(MII_BMSR), mii_parse_dm9161_sr},
+                /* Read the status */
+                { mk_mii_read(MIIM_DM9161_SCSR), mii_parse_dm9161_scsr},
+                /* Clear any pending interrupts */
+                { mk_mii_read(MIIM_DM9161_INTR), NULL},
+                /* Enable Interrupts */
+                { mk_mii_write(MIIM_DM9161_INTR, MIIM_DM9161_INTR_INIT), NULL},
+                { mk_mii_end,}
+        },
+       (const phy_cmd_t[]) { /* ack_int */
+                { mk_mii_read(MIIM_DM9161_INTR), NULL},
+#if 0
+		{ mk_mii_read(MII_BMSR), NULL},
+		{ mk_mii_read(MII_BMSR), mii_parse_dm9161_sr},
+		{ mk_mii_read(MIIM_DM9161_SCSR), mii_parse_dm9161_scsr},
+#endif
+                { mk_mii_end,}
+        },
+        (const phy_cmd_t[]) { /* shutdown */
+	        { mk_mii_read(MIIM_DM9161_INTR),NULL},
+                { mk_mii_write(MIIM_DM9161_INTR, MIIM_DM9161_INTR_STOP), NULL},
+	        { mk_mii_end,}
+	},
+};
+#endif /* CONFIG_FCC_DM9161 */
 
 static phy_info_t *phy_info[] = {
 
@@ -1152,11 +1378,24 @@ static phy_info_t *phy_info[] = {
 	&phy_info_dm9131,
 #endif /* CONFIG_FEC_DM9131 */
 
+#ifdef CONFIG_FCC_DM9161
+	&phy_info_dm9161,
+#endif /* CONFIG_FCC_DM9161 */
+
+#ifdef CONFIG_FCC_GENERIC_PHY
+	/* Generic PHY support.  This must be the last PHY in the table.
+	 * It will be used to support any PHY that doesn't match a previous
+	 * entry in the table.
+	 */
+	&phy_info_generic,
+#endif /* CONFIG_FCC_GENERIC_PHY */
+
 	NULL
 };
 
-static void mii_display_status(struct net_device *dev)
+static void mii_display_status(void *data)
 {
+	struct net_device *dev = data;
 	volatile struct fcc_enet_private *fep = dev->priv;
 	uint s = fep->phy_status;
 
@@ -1191,8 +1430,9 @@ static void mii_display_status(struct ne
 	printk(".\n");
 }
 
-static void mii_display_config(struct net_device *dev)
+static void mii_display_config(void *data)
 {
+	struct net_device *dev = data;
 	volatile struct fcc_enet_private *fep = dev->priv;
 	uint s = fep->phy_status;
 
@@ -1225,20 +1465,23 @@ static void mii_display_config(struct ne
 static void mii_relink(struct net_device *dev)
 {
 	struct fcc_enet_private *fep = dev->priv;
-	int duplex;
+	int duplex = 0;
 
-	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
-	mii_display_status(dev);
 	fep->old_link = fep->link;
+	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
+
+#ifdef MDIO_DEBUG
+	printk("  mii_relink:  link=%d\n", fep->link);
+#endif
 
 	if (fep->link) {
-		duplex = 0;
 		if (fep->phy_status
 		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))
 			duplex = 1;
 		fcc_restart(dev, duplex);
-	} else {
-		fcc_stop(dev);
+#ifdef MDIO_DEBUG
+		printk("  mii_relink:  duplex=%d\n", duplex);
+#endif
 	}
 }
 
@@ -1246,25 +1489,21 @@ static void mii_queue_relink(uint mii_re
 {
 	struct fcc_enet_private *fep = dev->priv;
 
-	fep->phy_task.routine = (void *)mii_relink;
-	fep->phy_task.data = dev;
-	schedule_task(&fep->phy_task);
+	mii_relink(dev);
+
+	schedule_work(&fep->phy_relink);
 }
 
 static void mii_queue_config(uint mii_reg, struct net_device *dev)
 {
 	struct fcc_enet_private *fep = dev->priv;
 
-	fep->phy_task.routine = (void *)mii_display_config;
-	fep->phy_task.data = dev;
-	schedule_task(&fep->phy_task);
+	schedule_work(&fep->phy_display_config);
 }
 
-
-
-phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink },
+phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_BMCR), mii_queue_relink },
 			       { mk_mii_end, } };
-phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config },
+phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_BMCR), mii_queue_config },
 			       { mk_mii_end, } };
 
 
@@ -1277,10 +1516,11 @@ mii_discover_phy3(uint mii_reg, struct n
 	int	i;
 
 	fep = dev->priv;
+	printk("mii_reg: %08x\n", mii_reg);
 	fep->phy_id |= (mii_reg & 0xffff);
 
 	for(i = 0; phy_info[i]; i++)
-		if(phy_info[i]->id == (fep->phy_id >> 4))
+		if((phy_info[i]->id == (fep->phy_id >> 4)) || !phy_info[i]->id)
 			break;
 
 	if(!phy_info[i])
@@ -1288,6 +1528,7 @@ mii_discover_phy3(uint mii_reg, struct n
 		      dev->name, fep->phy_id);
 
 	fep->phy = phy_info[i];
+	fep->phy_id_done = 1;
 
 	printk("%s: Phy @ 0x%x, type %s (0x%08x)\n",
 		dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);
@@ -1304,36 +1545,49 @@ mii_discover_phy(uint mii_reg, struct ne
 
 	fep = dev->priv;
 
-	if ((phytype = (mii_reg & 0xfff)) != 0xfff) {
+	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
 
 		/* 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_PHYSID2), mii_discover_phy3);
 	} else {
 		fep->phy_addr++;
 		if (fep->phy_addr < 32) {
-			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
+			mii_queue(dev, mk_mii_read(MII_PHYSID1),
 							mii_discover_phy);
 		} else {
 			printk("fec: No PHY device found.\n");
 		}
 	}
 }
+#endif	/* CONFIG_USE_MDIO */
 
+#ifdef PHY_INTERRUPT
 /* This interrupt occurs when the PHY detects a link change. */
 static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 {
 	struct	net_device *dev = dev_id;
 	struct fcc_enet_private *fep = dev->priv;
+	fcc_info_t *fip = fep->fip;
 
-	mii_do_cmd(dev, fep->phy->ack_int);
-	mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
+	if (fep->phy) {
+		/* We don't want to be interrupted by an FCC
+		 * interrupt here.
+		 */
+		disable_irq_nosync(fip->fc_interrupt);
+
+		mii_do_cmd(dev, fep->phy->ack_int);
+		/* restart and display status */
+		mii_do_cmd(dev, phy_cmd_relink);
+
+		enable_irq(fip->fc_interrupt);
+	}
 	return IRQ_HANDLED;
 }
+#endif	/* ifdef PHY_INTERRUPT */
 
-#endif	/* CONFIG_USE_MDIO */
-
+#if 0 /* This should be fixed someday */
 /* Set or clear the multicast filter for this adaptor.
  * Skeleton taken from sunlance driver.
  * The CPM Ethernet implementation allows Multicast as well as individual
@@ -1383,8 +1637,8 @@ return;
 
 			dmi = dev->mc_list;
 
-			for (i=0; i<dev->mc_count; i++) {
-		
+			for (i=0; i<dev->mc_count; i++, dmi = dmi->next) {
+
 				/* Only support group multicast for now.
 				*/
 				if (!(dmi->dmi_addr[0] & 1))
@@ -1411,6 +1665,7 @@ return;
 		}
 	}
 }
+#endif /* if 0 */
 
 
 /* Set the individual MAC address.
@@ -1482,7 +1737,7 @@ static int __init fec_enet_init(void)
 		dev->watchdog_timeo = TX_TIMEOUT;
 		dev->stop = fcc_enet_close;
 		dev->get_stats = fcc_enet_get_stats;
-		dev->set_multicast_list = set_multicast_list;
+		/* dev->set_multicast_list = set_multicast_list; */
 		dev->set_mac_address = fcc_enet_set_mac_address;
 
 		init_fcc_startup(fip, dev);
@@ -1502,8 +1757,11 @@ static int __init fec_enet_init(void)
 		/* Queue up command to detect the PHY and initialize the
 	 	* remainder of the interface.
 	 	*/
-		cep->phy_addr = 0;
-		mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+		cep->phy_id_done = 0;
+		cep->phy_addr = fip->fc_phyaddr;
+		mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy);
+		INIT_WORK(&cep->phy_relink, mii_display_status, dev);
+		INIT_WORK(&cep->phy_display_config, mii_display_config, dev);
 #endif	/* CONFIG_USE_MDIO */
 
 		fip++;
@@ -1549,29 +1807,36 @@ init_fcc_ioports(fcc_info_t *fip, volati
 	if (fip->fc_proff == PROFF_FCC1) {
 		/* Configure port A and C pins for FCC1 Ethernet.
 		 */
-		io->iop_pdira &= ~PA1_DIRA0;
-		io->iop_pdira |= PA1_DIRA1;
-		io->iop_psora &= ~PA1_PSORA0;
-		io->iop_psora |= PA1_PSORA1;
-		io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1);
+		io->iop_pdira &= ~PA1_DIRA_BOUT;
+		io->iop_pdira |= PA1_DIRA_BIN;
+		io->iop_psora &= ~PA1_PSORA_BOUT;
+		io->iop_psora |= PA1_PSORA_BIN;
+		io->iop_ppara |= (PA1_DIRA_BOUT | PA1_DIRA_BIN);
 	}
 	if (fip->fc_proff == PROFF_FCC2) {
 		/* Configure port B and C pins for FCC Ethernet.
 		 */
-		io->iop_pdirb &= ~PB2_DIRB0;
-		io->iop_pdirb |= PB2_DIRB1;
-		io->iop_psorb &= ~PB2_PSORB0;
-		io->iop_psorb |= PB2_PSORB1;
-		io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1);
+		io->iop_pdirb &= ~PB2_DIRB_BOUT;
+		io->iop_pdirb |= PB2_DIRB_BIN;
+		io->iop_psorb &= ~PB2_PSORB_BOUT;
+		io->iop_psorb |= PB2_PSORB_BIN;
+		io->iop_pparb |= (PB2_DIRB_BOUT | PB2_DIRB_BIN);
 	}
 	if (fip->fc_proff == PROFF_FCC3) {
 		/* Configure port B and C pins for FCC Ethernet.
 		 */
-		io->iop_pdirb &= ~PB3_DIRB0;
-		io->iop_pdirb |= PB3_DIRB1;
-		io->iop_psorb &= ~PB3_PSORB0;
-		io->iop_psorb |= PB3_PSORB1;
-		io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1);
+		io->iop_pdirb &= ~PB3_DIRB_BOUT;
+		io->iop_pdirb |= PB3_DIRB_BIN;
+		io->iop_psorb &= ~PB3_PSORB_BOUT;
+		io->iop_psorb |= PB3_PSORB_BIN;
+		io->iop_pparb |= (PB3_DIRB_BOUT | PB3_DIRB_BIN);
+
+		io->iop_pdirc &= ~PC3_DIRC_BOUT;
+		io->iop_pdirc |= PC3_DIRC_BIN;
+		io->iop_psorc &= ~PC3_PSORC_BOUT;
+		io->iop_psorc |= PC3_PSORC_BIN;
+		io->iop_pparc |= (PC3_DIRC_BOUT | PC3_DIRC_BIN);
+
 	}
 
 	/* Port C has clocks......
@@ -1699,6 +1964,11 @@ init_fcc_param(fcc_info_t *fip, struct n
 	 */
 	eap = (unsigned char *)&(ep->fen_paddrh);
 	for (i=5; i>=0; i--) {
+
+/*
+ * The EP8260 only uses FCC3, so we can safely give it the real
+ * MAC address.
+ */
 #ifdef CONFIG_SBC82xx
 		if (i == 5) {
 			/* bd->bi_enetaddr holds the SCC0 address; the FCC
@@ -1708,15 +1978,17 @@ init_fcc_param(fcc_info_t *fip, struct n
 			*eap++ = dev->dev_addr[i];
 		}
 #else
+#ifndef CONFIG_RPX8260
 		if (i == 3) {
 			dev->dev_addr[i] = bd->bi_enetaddr[i];
 			dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum));
 			*eap++ = dev->dev_addr[i];
-		}
+		} else
 #endif
-		else {
+		{
 			*eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
 		}
+#endif
 	}
 
 	ep->fen_taddrh = 0;
@@ -1798,7 +2070,6 @@ init_fcc_param(fcc_info_t *fip, struct n
 	while (cp->cp_cpcr & CPM_CR_FLG);
 
 	cep->skb_cur = cep->skb_dirty = 0;
-	atomic_set(&cep->n_pkts, 0);
 }
 
 /* Let 'er rip.
@@ -1812,25 +2083,56 @@ init_fcc_startup(fcc_info_t *fip, struct
 	cep = (struct fcc_enet_private *)(dev->priv);
 	fccp = cep->fccp;
 
+#ifdef CONFIG_RPX8260
+#ifdef PHY_INTERRUPT
+	/* Route PHY interrupt to IRQ.  The following code only works for
+	 * IRQ1 - IRQ7.  It does not work for Port C interrupts.
+	 */
+	*((volatile u_char *) (RPX_CSR_ADDR + 13)) &= ~BCSR13_FETH_IRQMASK;
+	*((volatile u_char *) (RPX_CSR_ADDR + 13)) |=
+		((PHY_INTERRUPT - SIU_INT_IRQ1 + 1) << 4);
+#endif
+	/* Initialize MDIO pins. */
+	*((volatile u_char *) (RPX_CSR_ADDR + 4)) &= ~BCSR4_MII_MDC;
+	*((volatile u_char *) (RPX_CSR_ADDR + 4)) |=
+		BCSR4_MII_READ | BCSR4_MII_MDIO;
+	/* Enable external LXT971 PHY. */
+	*((volatile u_char *) (RPX_CSR_ADDR + 4)) |= BCSR4_EN_PHY;
+	udelay(1000);
+	*((volatile u_char *) (RPX_CSR_ADDR+ 4)) |= BCSR4_EN_MII;
+	udelay(1000);
+#endif	/* ifdef CONFIG_RPX8260 */
+
 	fccp->fcc_fcce = 0xffff;	/* Clear any pending events */
 
-	/* Enable interrupts for transmit error, complete frame
-	 * received, and any transmit buffer we have also set the
-	 * interrupt flag.
+	/* Leave FCC interrupts masked for now.  Will be unmasked by
+	 * fcc_restart().
 	 */
-	fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);
+	fccp->fcc_fccm = 0;
 
 	/* Install our interrupt handler.
 	*/
-	if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0,
-							"fenet", dev) < 0)
+	if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet",
+				dev) < 0)
 		printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);
 
-#ifdef	CONFIG_USE_MDIO
+#ifdef	PHY_INTERRUPT
+#ifdef CONFIG_ADS8272
+	if (request_irq(PHY_INTERRUPT, mii_link_interrupt, SA_SHIRQ,
+				"mii", dev) < 0)
+		printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);
+#else
+	/* Make IRQn edge triggered.  This does not work if PHY_INTERRUPT is
+	 * on Port C.
+	 */
+	((volatile cpm2_map_t *) CPM_MAP_ADDR)->im_intctl.ic_siexr |=
+		(1 << (14 - (PHY_INTERRUPT - SIU_INT_IRQ1)));
+
 	if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0,
 							"mii", dev) < 0)
-		printk("Can't get MII IRQ %d\n", fip->fc_interrupt);
-#endif	/* CONFIG_USE_MDIO */
+		printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);
+#endif
+#endif	/* PHY_INTERRUPT */
 
 	/* Set GFMR to enable Ethernet operating mode.
 	 */
@@ -1847,10 +2149,14 @@ init_fcc_startup(fcc_info_t *fip, struct
 	fccp->fcc_fpsmr = FCC_PSMR_ENCRC;
 
 #ifdef CONFIG_PQ2ADS
-	/* Enable the PHY.
-	*/
-        *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN;
-        *(volatile uint *)(BCSR_ADDR + 4) |=  BCSR1_FETH_RST;
+	/* Enable the PHY. */
+	*(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN;
+	*(volatile uint *)(BCSR_ADDR + 4) |=  BCSR1_FETH_RST;
+#endif
+#if defined(CONFIG_PQ2ADS) || defined(CONFIG_PQ2FADS)
+	/* Enable the 2nd PHY. */
+	*(volatile uint *)(BCSR_ADDR + 12) &= ~BCSR3_FETHIEN2;
+	*(volatile uint *)(BCSR_ADDR + 12) |=  BCSR3_FETH2_RST;
 #endif
 
 #if defined(CONFIG_USE_MDIO) || defined(CONFIG_TQM8260)
@@ -1872,54 +2178,74 @@ init_fcc_startup(fcc_info_t *fip, struct
  * I wonder what "they" were thinking (maybe weren't) when they leave
  * the I2C in the CPM but I have to toggle these bits......
  */
-
-#define FCC_PDATC_MDIO(bit)					\
-	if (bit)						\
-		io->iop_pdatc |= fip->fc_mdio;			\
-	else							\
-		io->iop_pdatc &= ~fip->fc_mdio;
-
-#define FCC_PDATC_MDC(bit)					\
-	if (bit)						\
-		io->iop_pdatc |= fip->fc_mdck;			\
-	else							\
-		io->iop_pdatc &= ~fip->fc_mdck;
+#ifdef CONFIG_RPX8260
+	/* The EP8260 has the MDIO pins in a BCSR instead of on Port C
+	 * like most other boards.
+	 */
+#define MDIO_ADDR ((volatile u_char *)(RPX_CSR_ADDR + 4))
+#define MAKE_MDIO_OUTPUT *MDIO_ADDR &= ~BCSR4_MII_READ
+#define MAKE_MDIO_INPUT  *MDIO_ADDR |=  BCSR4_MII_READ | BCSR4_MII_MDIO
+#define OUT_MDIO(bit)				\
+	if (bit)				\
+		*MDIO_ADDR |=  BCSR4_MII_MDIO;	\
+	else					\
+		*MDIO_ADDR &= ~BCSR4_MII_MDIO;
+#define IN_MDIO (*MDIO_ADDR & BCSR4_MII_MDIO)
+#define OUT_MDC(bit)				\
+	if (bit)				\
+		*MDIO_ADDR |=  BCSR4_MII_MDC;	\
+	else					\
+		*MDIO_ADDR &= ~BCSR4_MII_MDC;
+#else	/* ifdef CONFIG_RPX8260 */
+	/* This is for the usual case where the MDIO pins are on Port C.
+	 */
+#define MDIO_ADDR (((volatile cpm2_map_t *)CPM_MAP_ADDR)->im_ioport)
+#define MAKE_MDIO_OUTPUT MDIO_ADDR.iop_pdirc |= fip->fc_mdio
+#define MAKE_MDIO_INPUT MDIO_ADDR.iop_pdirc &= ~fip->fc_mdio
+#define OUT_MDIO(bit)				\
+	if (bit)				\
+		MDIO_ADDR.iop_pdatc |= fip->fc_mdio;	\
+	else					\
+		MDIO_ADDR.iop_pdatc &= ~fip->fc_mdio;
+#define IN_MDIO ((MDIO_ADDR.iop_pdatc) & fip->fc_mdio)
+#define OUT_MDC(bit)				\
+	if (bit)				\
+		MDIO_ADDR.iop_pdatc |= fip->fc_mdck;	\
+	else					\
+		MDIO_ADDR.iop_pdatc &= ~fip->fc_mdck;
+#endif	/* ifdef CONFIG_RPX8260 */
 
 static uint
 mii_send_receive(fcc_info_t *fip, uint cmd)
 {
 	uint		retval;
 	int		read_op, i, off;
-	volatile	cpm2_map_t		*immap;
-	volatile	iop_cpm2_t	*io;
-
-	immap = (cpm2_map_t *)CPM_MAP_ADDR;
-	io = &immap->im_ioport;
-
-	io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);
+	const int	us = 1;
 
 	read_op = ((cmd & 0xf0000000) == 0x60000000);
 
 	/* Write preamble
 	 */
+	OUT_MDIO(1);
+	MAKE_MDIO_OUTPUT;
+	OUT_MDIO(1);
 	for (i = 0; i < 32; i++)
 	{
-		FCC_PDATC_MDC(0);
-		FCC_PDATC_MDIO(1);
-		udelay(1);
-		FCC_PDATC_MDC(1);
-		udelay(1);
+		udelay(us);
+		OUT_MDC(1);
+		udelay(us);
+		OUT_MDC(0);
 	}
 
 	/* Write data
 	 */
 	for (i = 0, off = 31; i < (read_op ? 14 : 32); i++, --off)
 	{
-		FCC_PDATC_MDC(0);
-		FCC_PDATC_MDIO((cmd >> off) & 0x00000001);
-		udelay(1);
-		FCC_PDATC_MDC(1);
-		udelay(1);
+		OUT_MDIO((cmd >> off) & 0x00000001);
+		udelay(us);
+		OUT_MDC(1);
+		udelay(us);
+		OUT_MDC(0);
 	}
 
 	retval = cmd;
@@ -1928,68 +2254,111 @@ mii_send_receive(fcc_info_t *fip, uint c
 	{
 		retval >>= 16;
 
-		FCC_PDATC_MDC(0);
-		io->iop_pdirc &= ~fip->fc_mdio;
-		udelay(1);
-		FCC_PDATC_MDC(1);
-		udelay(1);
-		FCC_PDATC_MDC(0);
-		udelay(1);
+		MAKE_MDIO_INPUT;
+		udelay(us);
+		OUT_MDC(1);
+		udelay(us);
+		OUT_MDC(0);
 
-		for (i = 0, off = 15; i < 16; i++, off--)
+		for (i = 0; i < 16; i++)
 		{
-			FCC_PDATC_MDC(1);
+			udelay(us);
+			OUT_MDC(1);
+			udelay(us);
 			retval <<= 1;
-			if (io->iop_pdatc & fip->fc_mdio)
+			if (IN_MDIO)
 				retval++;
-			udelay(1);
-			FCC_PDATC_MDC(0);
-			udelay(1);
+			OUT_MDC(0);
 		}
 	}
 
-	io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);
-
-	for (i = 0; i < 32; i++)
-	{
-		FCC_PDATC_MDC(0);
-		FCC_PDATC_MDIO(1);
-		udelay(1);
-		FCC_PDATC_MDC(1);
-		udelay(1);
-	}
+	MAKE_MDIO_INPUT;
+	udelay(us);
+	OUT_MDC(1);
+	udelay(us);
+	OUT_MDC(0);
 
 	return retval;
 }
+#endif	/* CONFIG_USE_MDIO */
 
 static void
 fcc_stop(struct net_device *dev)
 {
-	volatile fcc_t	*fccp;
-	struct fcc_enet_private	*fcp;
+	struct fcc_enet_private	*fep= (struct fcc_enet_private *)(dev->priv);
+	volatile fcc_t	*fccp = fep->fccp;
+	fcc_info_t *fip = fep->fip;
+	volatile fcc_enet_t *ep = fep->ep;
+	volatile cpm_cpm2_t *cp = cpmp;
+	volatile cbd_t *bdp;
+	int i;
+
+	if ((fccp->fcc_gfmr & (FCC_GFMR_ENR | FCC_GFMR_ENT)) == 0)
+		return;	/* already down */
 
-	fcp = (struct fcc_enet_private *)(dev->priv);
-	fccp = fcp->fccp;
+	fccp->fcc_fccm = 0;
+
+	/* issue the graceful stop tx command */
+	while (cp->cp_cpcr & CPM_CR_FLG);
+	cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock,
+				0x0c, CPM_CR_GRA_STOP_TX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
 
 	/* Disable transmit/receive */
 	fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT);
+
+	/* issue the restart tx command */
+	fccp->fcc_fcce = FCC_ENET_GRA;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+	cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock,
+				0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* free tx buffers */
+	fep->skb_cur = fep->skb_dirty = 0;
+	for (i=0; i<=TX_RING_MOD_MASK; i++) {
+		if (fep->tx_skbuff[i] != NULL) {
+			dev_kfree_skb(fep->tx_skbuff[i]);
+			fep->tx_skbuff[i] = NULL;
+		}
+	}
+	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
+	fep->tx_free = TX_RING_SIZE;
+	ep->fen_genfcc.fcc_tbptr = ep->fen_genfcc.fcc_tbase;
+
+	/* Initialize the tx buffer descriptors. */
+	bdp = fep->tx_bd_base;
+	for (i=0; i<TX_RING_SIZE; i++) {
+		bdp->cbd_sc = 0;
+		bdp->cbd_datlen = 0;
+		bdp->cbd_bufaddr = 0;
+		bdp++;
+	}
+	/* Set the last buffer to wrap. */
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
 }
-#endif	/* CONFIG_USE_MDIO */
 
 static void
 fcc_restart(struct net_device *dev, int duplex)
 {
-	volatile fcc_t	*fccp;
-	struct fcc_enet_private	*fcp;
+	struct fcc_enet_private	*fep = (struct fcc_enet_private *)(dev->priv);
+	volatile fcc_t	*fccp = fep->fccp;
 
-	fcp = (struct fcc_enet_private *)(dev->priv);
-	fccp = fcp->fccp;
+	/* stop any transmissions in progress */
+	fcc_stop(dev);
 
 	if (duplex)
 		fccp->fcc_fpsmr |= FCC_PSMR_FDE | FCC_PSMR_LPB;
 	else
 		fccp->fcc_fpsmr &= ~(FCC_PSMR_FDE | FCC_PSMR_LPB);
 
+	/* Enable interrupts for transmit error, complete frame
+	 * received, and any transmit buffer we have also set the
+	 * interrupt flag.
+	 */
+	fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);
+
 	/* Enable transmit/receive */
 	fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT;
 }
@@ -2004,6 +2373,7 @@ fcc_enet_open(struct net_device *dev)
 	fep->link = 0;
 
 	if (fep->phy) {
+		fcc_restart(dev, 0);	/* always start in half-duplex */
 		mii_do_cmd(dev, fep->phy->ack_int);
 		mii_do_cmd(dev, fep->phy->config);
 		mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
@@ -2017,6 +2387,7 @@ fcc_enet_open(struct net_device *dev)
 	return -ENODEV;		/* No PHY we understand */
 #else
 	fep->link = 1;
+	fcc_restart(dev, 0);	/* always start in half-duplex */
 	netif_start_queue(dev);
 	return 0;					/* Always succeed */
 #endif	/* CONFIG_USE_MDIO */
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -55,7 +55,7 @@ static int irq_installed = 0;
 static char **sound_buffers = NULL;
 static char **sound_read_buffers = NULL;
 
-static spinlock_t cs4218_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(cs4218_lock);
 
 /* Local copies of things we put in the control register.  Output
  * volume, like most codecs is really attenuation.
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -657,7 +657,7 @@ static int __init scc_enet_init(void)
 
 	cp = cpmp;	/* Get pointer to Communication Processor */
 
-	immap = (immap_t *)(mfspr(IMMR) & 0xFFFF0000);	/* and to internal registers */
+	immap = (immap_t *)(mfspr(SPRN_IMMR) & 0xFFFF0000);	/* and to internal registers */
 
 	bd = (bd_t *)__res;
 
diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
--- a/arch/ppc/8xx_io/fec.c
+++ b/arch/ppc/8xx_io/fec.c
@@ -1735,7 +1735,7 @@ static int __init fec_enet_init(void)
 
 	/* Bits moved from Rev. D onward.
 	*/
-	if ((mfspr(IMMR) & 0xffff) < 0x0501)
+	if ((mfspr(SPRN_IMMR) & 0xffff) < 0x0501)
 		immap->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
 	else
 		immap->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -43,6 +43,10 @@ config GENERIC_NVRAM
 	bool
 	default y
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+	bool
+	default y
+
 source "init/Kconfig"
 
 menu "Processor"
@@ -52,17 +56,18 @@ choice
 	default 6xx
 
 config 6xx
-	bool "6xx/7xx/74xx/52xx/8260"
+	bool "6xx/7xx/74xx/52xx/82xx/83xx"
+	select PPC_FPU
 	help
 	  There are four types of PowerPC chips supported.  The more common
 	  types (601, 603, 604, 740, 750, 7400), the Motorola embedded
-	  versions (821, 823, 850, 855, 860, 52xx, 8260), the IBM embedded
+	  versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM embedded
 	  versions (403 and 405) and the high end 64 bit Power processors
 	  (POWER 3, POWER4, and IBM 970 also known as G5)
 	  Unless you are building a kernel for one of the embedded processor
 	  systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx.
 	  Note that the kernel runs in 32-bit mode even on 64-bit chips.
-	  Also note that because the 52xx & 82xx family has a 603e core,
+	  Also note that because the 52xx, 82xx, & 83xx family has a 603e core,
 	  specific support for that chipset is asked later on.
 
 config 40x
@@ -72,9 +77,11 @@ config 44x
 	bool "44x"
 
 config POWER3
+	select PPC_FPU
 	bool "POWER3"
 
 config POWER4
+	select PPC_FPU
 	bool "POWER4 and 970 (G5)"
 
 config 8xx
@@ -86,6 +93,9 @@ config E500
 
 endchoice
 
+config PPC_FPU
+	bool
+
 config BOOKE
 	bool
 	depends on E500
@@ -98,18 +108,24 @@ config FSL_BOOKE
 
 config PTE_64BIT
 	bool
-	depends on 44x
-	default y
+	depends on 44x || E500
+	default y if 44x
+	default y if E500 && PHYS_64BIT
 
 config PHYS_64BIT
-	bool
-	depends on 44x
-	default y
+	bool 'Large physical address support' if E500
+	depends on 44x || E500
+	default y if 44x
+	---help---
+	  This option enables kernel support for larger than 32-bit physical
+	  addresses.  This features is not be available on all e500 cores.
+
+	  If in doubt, say N here.
 
 config ALTIVEC
 	bool "AltiVec Support"
 	depends on 6xx || POWER4
-	depends on !8260
+	depends on !8260 && !83xx
 	---help---
 	  This option enables kernel support for the Altivec extensions to the
 	  PowerPC processor. The kernel currently supports saving and restoring
@@ -140,7 +156,7 @@ config SPE
 
 config TAU
 	bool "Thermal Management Support"
-	depends on 6xx && !8260
+	depends on 6xx && !8260 && !83xx
 	help
 	  G3 and G4 processors have an on-chip temperature sensor called the
 	  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
@@ -203,16 +219,12 @@ source "drivers/cpufreq/Kconfig"
 config CPU_FREQ_PMAC
 	bool "Support for Apple PowerBooks"
 	depends on CPU_FREQ && ADB_PMU
+	select CPU_FREQ_TABLE
 	help
 	  This adds support for frequency switching on Apple PowerBooks,
 	  this currently includes some models of iBook & Titanium
 	  PowerBook.
 
-config CPU_FREQ_TABLE
-	bool
-	depends on CPU_FREQ_PMAC
-	default y
-
 config PPC601_SYNC_FIX
 	bool "Workarounds for PPC601 bugs"
 	depends on 6xx && (PPC_PREP || PPC_PMAC)
@@ -538,6 +550,17 @@ config CHESTNUT
 config SPRUCE
 	bool "IBM-Spruce"
 
+config HDPU
+	bool "Sky-HDPU"
+	help
+	  Select HDPU if configuring a Sky Computers Compute Blade.
+
+config HDPU_FEATURES
+	depends HDPU
+	tristate "HDPU-Features"
+	help
+	  Select to enable HDPU enhanced features.
+
 config EV64260
 	bool "Marvell-EV64260BP"
 	help
@@ -568,6 +591,9 @@ config SANDPOINT
 	  Select SANDPOINT if configuring for a Motorola Sandpoint X3
 	  (any flavor).
 
+config RADSTONE_PPC7D
+	bool "Radstone Technology PPC7D board"
+
 config ADIR
 	bool "SBS-Adirondack"
 
@@ -638,6 +664,11 @@ config LITE5200
 	  much but it's only been tested on this board version. I think this
 	  board is also known as IceCube.
 
+config MPC834x_SYS
+	bool "Freescale MPC834x SYS"
+	help
+	  This option enables support for the MPC 834x SYS evaluation board.
+
 endchoice
 
 config PQ2ADS
@@ -676,6 +707,14 @@ config 8272
 	  The MPC8272 CPM has a different internal dpram setup than other CPM2
 	  devices
 
+config 83xx
+	bool
+	default y if MPC834x_SYS
+
+config MPC834x
+	bool
+	default y if MPC834x_SYS
+
 config CPM2
 	bool
 	depends on 8260 || MPC8560 || MPC8555
@@ -715,7 +754,8 @@ config PPC_GEN550
 	bool
 	depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \
 		PRPMC750 || K2 || PRPMC800 || LOPEC || \
-		(EV64260 && !SERIAL_MPSC) || CHESTNUT
+		(EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
+		83xx
 	default y
 
 config FORCE
@@ -728,16 +768,11 @@ config GT64260
 	depends on EV64260 || CPCI690
 	default y
 
-config MV64360
+config MV64360		# Really MV64360 & MV64460
 	bool
-	depends on KATANA
+	depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU
 	default y
 
-config MV64360
-	bool
-	depends on CHESTNUT
-  	default y
-
 config MV64X60
 	bool
 	depends on (GT64260 || MV64360)
@@ -793,7 +828,7 @@ config MPC10X_BRIDGE
 
 config FSL_OCP
 	bool
-	depends on MPC10X_BRIDGE || PPC_MPC52xx
+	depends on MPC10X_BRIDGE
 	default y
 
 config MPC10X_OPENPIC
@@ -1046,8 +1081,14 @@ config PROC_HARDWARE
 
 source "drivers/zorro/Kconfig"
 
+source kernel/power/Kconfig
+
 endmenu
 
+config ISA_DMA_API
+	bool
+	default y
+
 menu "Bus options"
 
 config ISA
@@ -1079,8 +1120,8 @@ config MCA
 	bool
 
 config PCI
-	bool "PCI support" if 40x || CPM2 || 85xx
-	default y if !40x && !CPM2 && !8xx && !APUS && !85xx
+	bool "PCI support" if 40x || CPM2 || 83xx || 85xx || PPC_MPC52xx
+	default y if !40x && !CPM2 && !8xx && !APUS && !83xx && !85xx
 	default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
 	default PCI_QSPAN if !4xx && !CPM2 && 8xx
 	help
@@ -1102,12 +1143,12 @@ config PCI_QSPAN
 
 config PCI_8260
 	bool
-	depends on PCI && 8260 && !8272
+	depends on PCI && 8260
 	default y
 
 config 8260_PCI9
 	bool "  Enable workaround for MPC826x erratum PCI 9"
-	depends on PCI_8260
+	depends on PCI_8260 && !ADS8272
 	default y
 
 choice
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -49,14 +49,16 @@ head-y				:= arch/ppc/kernel/head.o
 head-$(CONFIG_8xx)		:= arch/ppc/kernel/head_8xx.o
 head-$(CONFIG_4xx)		:= arch/ppc/kernel/head_4xx.o
 head-$(CONFIG_44x)		:= arch/ppc/kernel/head_44x.o
-head-$(CONFIG_E500)		:= arch/ppc/kernel/head_e500.o
+head-$(CONFIG_FSL_BOOKE)	:= arch/ppc/kernel/head_fsl_booke.o
 
 head-$(CONFIG_6xx)		+= arch/ppc/kernel/idle_6xx.o
 head-$(CONFIG_POWER4)		+= arch/ppc/kernel/idle_power4.o
+head-$(CONFIG_PPC_FPU)		+= arch/ppc/kernel/fpu.o
 
 core-y				+= arch/ppc/kernel/ arch/ppc/platforms/ \
 				   arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/
 core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
+core-$(CONFIG_83xx)		+= arch/ppc/platforms/83xx/
 core-$(CONFIG_85xx)		+= arch/ppc/platforms/85xx/
 core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
@@ -112,26 +114,24 @@ include/asm-$(ARCH)/offsets.h: arch/$(AR
 TOUT	:= .tmp_gas_check
 # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec
 # instructions.
-AS_ALTIVEC	:= $(shell echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; echo $$?)
 # gcc-3.4 and binutils-2.14 are a fatal combination.
 GCC_VERSION	:= $(call cc-version)
-BAD_GCC_AS	:= $(shell echo mftb 5 | $(AS) -mppc -many -o $(TOUT) >/dev/null 2>&1 && echo 0 || echo 1)
 
 checkbin:
-ifeq ($(GCC_VERSION)$(BAD_GCC_AS),03041)
-	@echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '
-	@echo 'correctly with gcc-3.4 and your version of binutils.'
-	@echo '*** Please upgrade your binutils or downgrade your gcc'
-	@false
-endif
-ifneq ($(AS_ALTIVEC),0)
-	echo $(AS_ALTIVEC)
-	@echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '
-	@echo 'correctly with old versions of binutils.'
-	@echo '*** Please upgrade your binutils to 2.12.1 or newer'
-	@false
-endif
-	@true
+	@if test "$(GCC_VERSION)" = "0304" ; then \
+		if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \
+			echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \
+			echo 'correctly with gcc-3.4 and your version of binutils.'; \
+			echo '*** Please upgrade your binutils or downgrade your gcc'; \
+			false; \
+		fi ; \
+	fi
+	@if ! /bin/echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; then \
+		echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' ; \
+		echo 'correctly with old versions of binutils.' ; \
+		echo '*** Please upgrade your binutils to 2.12.1 or newer' ; \
+		false ; \
+	fi
 
 CLEAN_FILES +=	include/asm-$(ARCH)/offsets.h \
 		arch/$(ARCH)/kernel/asm-offsets.s \
diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S
--- a/arch/ppc/boot/common/util.S
+++ b/arch/ppc/boot/common/util.S
@@ -47,23 +47,23 @@ disable_6xx_mmu:
 
 	/* Clear BATs */
 	li	r8,0
-	mtspr	DBAT0U,r8
-	mtspr	DBAT0L,r8
-	mtspr	DBAT1U,r8
-	mtspr	DBAT1L,r8
-	mtspr	DBAT2U,r8
-	mtspr	DBAT2L,r8
-	mtspr	DBAT3U,r8
-	mtspr	DBAT3L,r8
+	mtspr	SPRN_DBAT0U,r8
+	mtspr	SPRN_DBAT0L,r8
+	mtspr	SPRN_DBAT1U,r8
+	mtspr	SPRN_DBAT1L,r8
+	mtspr	SPRN_DBAT2U,r8
+	mtspr	SPRN_DBAT2L,r8
+	mtspr	SPRN_DBAT3U,r8
+	mtspr	SPRN_DBAT3L,r8
 .clearbats_601:
-	mtspr	IBAT0U,r8
-	mtspr	IBAT0L,r8
-	mtspr	IBAT1U,r8
-	mtspr	IBAT1L,r8
-	mtspr	IBAT2U,r8
-	mtspr	IBAT2L,r8
-	mtspr	IBAT3U,r8
-	mtspr	IBAT3L,r8
+	mtspr	SPRN_IBAT0U,r8
+	mtspr	SPRN_IBAT0L,r8
+	mtspr	SPRN_IBAT1U,r8
+	mtspr	SPRN_IBAT1L,r8
+	mtspr	SPRN_IBAT2U,r8
+	mtspr	SPRN_IBAT2L,r8
+	mtspr	SPRN_IBAT3U,r8
+	mtspr	SPRN_IBAT3L,r8
 	isync
 	sync
 	sync
@@ -84,14 +84,14 @@ disable_6xx_l1cache:
 	/* Enable, invalidate and then disable the L1 icache/dcache. */
 	li	r8,0
 	ori	r8,r8,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
-	mfspr	r11,HID0
+	mfspr	r11,SPRN_HID0
 	or	r11,r11,r8
 	andc	r10,r11,r8
 	isync
-	mtspr	HID0,r8
+	mtspr	SPRN_HID0,r8
 	sync
 	isync
-	mtspr	HID0,r10
+	mtspr	SPRN_HID0,r10
 	sync
 	isync
 	blr
@@ -107,17 +107,17 @@ _setup_L2CR:
 	/* Invalidate/disable L2 cache */
 	sync
 	isync
-	mfspr	r8,L2CR
+	mfspr	r8,SPRN_L2CR
 	rlwinm	r8,r8,0,1,31
 	oris	r8,r8,L2CR_L2I@h
 	sync
 	isync
-	mtspr	L2CR,r8
+	mtspr	SPRN_L2CR,r8
 	sync
 	isync
 
 	/* Wait for the invalidation to complete */
-	mfspr   r8,PVR
+	mfspr   r8,SPRN_PVR
 	srwi    r8,r8,16
 	cmplwi	cr0,r8,0x8000			/* 7450 */
 	cmplwi	cr1,r8,0x8001			/* 7455 */
@@ -126,19 +126,19 @@ _setup_L2CR:
 	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
 	bne     2f
 
-1:	mfspr	r8,L2CR		/* On 745x, poll L2I bit (bit 10) */
+1:	mfspr	r8,SPRN_L2CR	/* On 745x, poll L2I bit (bit 10) */
 	rlwinm.	r9,r8,0,10,10
 	bne	1b
 	b	3f
 
-2:      mfspr   r8,L2CR		/* On 75x & 74[01]0, poll L2IP bit (bit 31) */
+2:      mfspr   r8,SPRN_L2CR	/* On 75x & 74[01]0, poll L2IP bit (bit 31) */
 	rlwinm. r9,r8,0,31,31
 	bne     2b
 
 3:	rlwinm	r8,r8,0,11,9	/* Turn off L2I bit */
 	sync
 	isync
-	mtspr	L2CR,r8
+	mtspr	SPRN_L2CR,r8
 	sync
 	isync
 	blr
@@ -148,24 +148,24 @@ _setup_L3CR:
 	/* Invalidate/disable L3 cache */
 	sync
 	isync
-	mfspr	r8,L3CR
+	mfspr	r8,SPRN_L3CR
 	rlwinm	r8,r8,0,1,31
 	ori	r8,r8,L3CR_L3I@l
 	sync
 	isync
-	mtspr	L3CR,r8
+	mtspr	SPRN_L3CR,r8
 	sync
 	isync
 
 	/* Wait for the invalidation to complete */
-1:	mfspr	r8,L3CR
+1:	mfspr	r8,SPRN_L3CR
 	rlwinm.	r9,r8,0,21,21
 	bne	1b
 
 	rlwinm	r8,r8,0,22,20		/* Turn off L3I bit */
 	sync
 	isync
-	mtspr	L3CR,r8
+	mtspr	SPRN_L3CR,r8
 	sync
 	isync
 	blr
@@ -190,7 +190,7 @@ timebase_period_ns:
  */
 	.globl	udelay
 udelay:
-	mfspr	r4,PVR
+	mfspr	r4,SPRN_PVR
 	srwi	r4,r4,16
 	cmpwi	0,r4,1		/* 601 ? */
 	bne	.udelay_not_601
@@ -240,11 +240,11 @@ _GLOBAL(flush_instruction_cache)
 
 #ifdef CONFIG_8xx
 	lis	r3, IDC_INVALL@h
-	mtspr	IC_CST, r3
+	mtspr	SPRN_IC_CST, r3
 	lis	r3, IDC_ENABLE@h
-	mtspr	IC_CST, r3
+	mtspr	SPRN_IC_CST, r3
 	lis	r3, IDC_DISABLE@h
-	mtspr	DC_CST, r3
+	mtspr	SPRN_DC_CST, r3
 #elif CONFIG_4xx
 	lis	r3,start@h		# r9 = &_start
 	lis	r4,_etext@ha
@@ -258,14 +258,14 @@ _GLOBAL(flush_instruction_cache)
 	/* Enable, invalidate and then disable the L1 icache/dcache. */
 	li	r3,0
 	ori	r3,r3,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
-	mfspr	r4,HID0
+	mfspr	r4,SPRN_HID0
 	or	r5,r4,r3
 	isync
-	mtspr	HID0,r5
+	mtspr	SPRN_HID0,r5
 	sync
 	isync
 	ori	r5,r4,HID0_ICE	/* Enable cache */
-	mtspr	HID0,r5
+	mtspr	SPRN_HID0,r5
 	sync
 	isync
 #endif
diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile
--- a/arch/ppc/boot/images/Makefile
+++ b/arch/ppc/boot/images/Makefile
@@ -20,8 +20,10 @@ quiet_cmd_uimage = UIMAGE  $@
 
 targets += uImage
 $(obj)/uImage: $(obj)/vmlinux.gz
+	$(Q)rm -f $@
 	$(call if_changed,uimage)
-	@echo '  Image $@ is ready'
+	@echo -n '  Image: $@ '
+	@if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
 
 # Files generated that shall be removed upon make clean
 clean-files	:= sImage vmapus vmlinux* miboot* zImage* uImage
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -49,7 +49,7 @@ clear_L2_L3	:= $(srctree)/$(boot)/simple
 #----------------------------------------------------------------------------
       zimage-$(CONFIG_CPCI690)		:= zImage-STRIPELF
 zimageinitrd-$(CONFIG_CPCI690)		:= zImage.initrd-STRIPELF
-     extra.o-$(CONFIG_CPCI690)		:= misc-cpci690.o mv64x60_stub.o
+     extra.o-$(CONFIG_CPCI690)		:= misc-cpci690.o
          end-$(CONFIG_CPCI690)		:= cpci690
    cacheflag-$(CONFIG_CPCI690)		:= -include $(clear_L2_L3)
 
@@ -65,6 +65,7 @@ zimageinitrd-$(CONFIG_IBM_OPENBIOS)	:= z
 zimageinitrd-$(CONFIG_EBONY)		:= zImage.initrd-TREE
          end-$(CONFIG_EBONY)		:= ebony
   entrypoint-$(CONFIG_EBONY)		:= 0x01000000
+     extra.o-$(CONFIG_EBONY)		:= openbios.o
 
       zimage-$(CONFIG_LUAN)		:= zImage-TREE
 zimageinitrd-$(CONFIG_LUAN)		:= zImage.initrd-TREE
@@ -93,10 +94,14 @@ zimageinitrd-$(CONFIG_GEMINI)		:= zImage
          end-$(CONFIG_K2)		:= k2
    cacheflag-$(CONFIG_K2)		:= -include $(clear_L2_L3)
 
-     extra.o-$(CONFIG_KATANA)		:= misc-katana.o mv64x60_stub.o
+     extra.o-$(CONFIG_KATANA)		:= misc-katana.o
          end-$(CONFIG_KATANA)		:= katana
    cacheflag-$(CONFIG_KATANA)		:= -include $(clear_L2_L3)
 
+     extra.o-$(CONFIG_RADSTONE_PPC7D)	:= misc-radstone_ppc7d.o
+         end-$(CONFIG_RADSTONE_PPC7D)	:= radstone_ppc7d
+   cacheflag-$(CONFIG_RADSTONE_PPC7D)	:= -include $(clear_L2_L3)
+
 # kconfig 'feature', only one of these will ever be 'y' at a time.
 # The rest will be unset.
 motorola := $(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750) \
@@ -118,10 +123,13 @@ zimageinitrd-$(pcore)			:= zImage.initrd
          end-$(pcore)			:= pcore
    cacheflag-$(pcore)			:= -include $(clear_L2_L3)
 
+# Really only valid if CONFIG_6xx=y
       zimage-$(CONFIG_PPC_PREP)		:= zImage-PPLUS
 zimageinitrd-$(CONFIG_PPC_PREP)		:= zImage.initrd-PPLUS
+ifeq ($(CONFIG_6xx),y)
      extra.o-$(CONFIG_PPC_PREP)		:= prepmap.o
         misc-$(CONFIG_PPC_PREP)		+= misc-prep.o mpc10x_memory.o
+endif
          end-$(CONFIG_PPC_PREP)		:= prep
 
          end-$(CONFIG_SANDPOINT)	:= sandpoint
diff --git a/arch/ppc/boot/simple/clear.S b/arch/ppc/boot/simple/clear.S
--- a/arch/ppc/boot/simple/clear.S
+++ b/arch/ppc/boot/simple/clear.S
@@ -7,7 +7,7 @@
 	bl	_setup_L2CR;					\
 								\
 	/* If 745x, turn off L3CR as well */			\
-	mfspr	r8,PVR;						\
+	mfspr	r8,SPRN_PVR;					\
 	srwi	r8,r8,16;					\
 								\
 	cmpli	cr0,r8,0x8000;			/* 7450 */	\
diff --git a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
--- a/arch/ppc/boot/simple/embed_config.c
+++ b/arch/ppc/boot/simple/embed_config.c
@@ -506,7 +506,7 @@ embed_config(bd_t **bdp)
 	memcpy(bd->bi_enetaddr, cp, 6);
 
 	/* can busfreq be calculated? */
-	pvr = mfspr(PVR);
+	pvr = mfspr(SPRN_PVR);
 	if ((pvr & 0xffff0000) == 0x80820000) {
 		bd->bi_busfreq = 100000000;
 		clk_8280(bd);
diff --git a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S
--- a/arch/ppc/boot/simple/head.S
+++ b/arch/ppc/boot/simple/head.S
@@ -52,7 +52,7 @@ start_:
 	 */
 	li	r4,0x0000
 	isync
-	mtspr	HID0,r4
+	mtspr	SPRN_HID0,r4
 	sync
 	isync
 #endif
@@ -135,11 +135,6 @@ haveOF:
 			 */
 #endif
 
-#ifdef	CONFIG_MV64X60
-	/* mv64x60 specific hook to do things like moving register base, etc. */
-	bl	mv64x60_init
-#endif
-
 	/* Get the load address.
 	*/
 	subi	r3, r3, 4	/* Get the actual IP, not NIP */
diff --git a/arch/ppc/boot/simple/m8260_tty.c b/arch/ppc/boot/simple/m8260_tty.c
--- a/arch/ppc/boot/simple/m8260_tty.c
+++ b/arch/ppc/boot/simple/m8260_tty.c
@@ -159,7 +159,7 @@ serial_init(int ignored, bd_t *bd)
 	sccp->scc_sccm = 0;
 	sccp->scc_scce = 0xffff;
 	sccp->scc_dsr = 0x7e7e;
-	sccp->scc_pmsr = 0x3000;
+	sccp->scc_psmr = 0x3000;
 
 	/* Wire BRG1 to SCC1.  The console driver will take care of
 	 * others.
diff --git a/arch/ppc/boot/simple/misc-chestnut.S b/arch/ppc/boot/simple/misc-chestnut.S
deleted file mode 100644
--- a/arch/ppc/boot/simple/misc-chestnut.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/ppc/boot/simple/misc-chestnut.S
- *
- * Setup for the IBM Chestnut (ibm-750fxgx_eval)
- *
- * Author: <source@mvista.com>
- *
- * <2004> (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-
-#include <asm/ppc_asm.h>
-#include <asm/mv64x60_defs.h>
-#include <platforms/chestnut.h>
-
-	.globl	mv64x60_board_init
-mv64x60_board_init:
-	/*
-	 * move UART to 0xffc00000
-	 */
-
-	li      r23,16
-
-	addis	r25,0,CONFIG_MV64X60_BASE@h
-	ori     r25,r25,MV64x60_CPU2DEV_2_BASE
-	addis   r26,0,CHESTNUT_UART_BASE@h
-	srw     r26,r26,r23
-	stwbrx  r26,0,(r25)
-	sync
-
-	addis	r25,0,CONFIG_MV64X60_BASE@h
-	ori     r25,r25,MV64x60_CPU2DEV_2_SIZE
-	addis   r26,0,0x00100000@h
-	srw     r26,r26,r23
-	stwbrx  r26,0,(r25)
-	sync
-
-	blr
diff --git a/arch/ppc/boot/simple/misc-chestnut.c b/arch/ppc/boot/simple/misc-chestnut.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/boot/simple/misc-chestnut.c
@@ -0,0 +1,35 @@
+/*
+ * arch/ppc/boot/simple/misc-chestnut.c
+ *
+ * Setup for the IBM Chestnut (ibm-750fxgx_eval)
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+#include <platforms/chestnut.h>
+
+/* Not in the kernel so won't include kernel.h to get its 'max' definition */
+#define max(a,b)	(((a) > (b)) ? (a) : (b))
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+	/*
+	 * Change device bus 2 window so that bootoader can do I/O thru
+	 * 8250/16550 UART that's mapped in that window.
+	 */
+	out_le32(new_base + MV64x60_CPU2DEV_2_BASE, CHESTNUT_UART_BASE >> 16);
+	out_le32(new_base + MV64x60_CPU2DEV_2_SIZE, CHESTNUT_UART_SIZE >> 16);
+	__asm__ __volatile__("sync");
+#endif
+}
diff --git a/arch/ppc/boot/simple/misc-cpci690.c b/arch/ppc/boot/simple/misc-cpci690.c
--- a/arch/ppc/boot/simple/misc-cpci690.c
+++ b/arch/ppc/boot/simple/misc-cpci690.c
@@ -12,4 +12,16 @@
  */
 
 #include <linux/types.h>
-long	mv64x60_mpsc_clk_freq = 133000000;
+#include <platforms/cpci690.h>
+
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+	mv64x60_console_baud = CPCI690_MPSC_BAUD;
+	mv64x60_mpsc_clk_src = CPCI690_MPSC_CLK_SRC;
+	mv64x60_mpsc_clk_freq = CPCI690_BUS_FREQ;
+}
diff --git a/arch/ppc/boot/simple/misc-ev64260.S b/arch/ppc/boot/simple/misc-ev64260.S
deleted file mode 100644
--- a/arch/ppc/boot/simple/misc-ev64260.S
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/ppc/boot/simple/misc-ev64260.S
- *
- * Host bridge init code for the Marvell/Galileo EV-64260-BP evaluation board
- * with a GT64260 onboard.
- *
- * Author: Mark Greer <mgreer@mvista.com>
- *
- * 2001 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <asm/ppc_asm.h>
-#include <asm/processor.h>
-#include <asm/cache.h>
-#include <asm/mv64x60_defs.h>
-#include <platforms/ev64260.h>
-
-	.globl	mv64x60_board_init
-mv64x60_board_init:
-	/* DINK doesn't enable 745x timebase, so enable here (Adrian Cox) */
-	mfspr	r25,PVR
-	srwi	r25,r25,16
-	cmplwi	r25,(PVR_7450 >> 16)
-	bne	1f
-	mfspr	r25,HID0
-	oris	r25,r25,(HID0_TBEN >> 16)
-	mtspr	HID0,r25
-1:
-#if (CONFIG_MV64X60_NEW_BASE != CONFIG_MV64X60_BASE)
-	li	r23,20
-
-	/*
-	 * Change the CS2 window for the UART so that the bootloader
-	 * can do I/O thru the UARTs.
-	 */
-	addis	r25,0,CONFIG_MV64X60_NEW_BASE@h
-	ori	r25,r25,MV64x60_CPU2DEV_2_BASE
-	addis	r26,0,EV64260_UART_BASE@h
-	srw	r26,r26,r23
-	stwbrx	r26,0,(r25)
-	sync
-
-	addis	r25,0,CONFIG_MV64X60_NEW_BASE@h
-	ori	r25,r25,MV64x60_CPU2DEV_2_SIZE
-	addis	r26,0,EV64260_UART_END@h
-	srw	r26,r26,r23
-	stwbrx	r26,0,(r25)
-	sync
-#endif
-	blr
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
-.data
-	.globl	mv64x60_console_baud
-mv64x60_console_baud:
-.long	EV64260_DEFAULT_BAUD
-
-	.globl	mv64x60_mpsc_clk_src
-mv64x60_mpsc_clk_src:
-.long	EV64260_MPSC_CLK_SRC
-
-	.globl	mv64x60_mpsc_clk_freq
-mv64x60_mpsc_clk_freq:
-.long	EV64260_MPSC_CLK_FREQ
-#endif
diff --git a/arch/ppc/boot/simple/misc-ev64260.c b/arch/ppc/boot/simple/misc-ev64260.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/boot/simple/misc-ev64260.c
@@ -0,0 +1,57 @@
+/*
+ * arch/ppc/boot/simple/misc-ev64260.c
+ *
+ * Host bridge init code for the Marvell/Galileo EV-64260-BP evaluation board
+ * with a GT64260 onboard.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+#include <platforms/ev64260.h>
+
+#ifdef CONFIG_SERIAL_MPSC_CONSOLE
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+#endif
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+	u32	p, v;
+
+	/* DINK doesn't enable 745x timebase, so enable here (Adrian Cox) */
+	p = mfspr(SPRN_PVR);
+	p >>= 16;
+
+	/* Reasonable SWAG at a 745x PVR value */
+	if (((p & 0xfff0) == 0x8000) && (p != 0x800c)) {
+		v = mfspr(SPRN_HID0);
+		v |= HID0_TBEN;
+		mtspr(SPRN_HID0, v);
+	}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+	/*
+	 * Change device bus 2 window so that bootoader can do I/O thru
+	 * 8250/16550 UART that's mapped in that window.
+	 */
+	out_le32(new_base + MV64x60_CPU2DEV_2_BASE, EV64260_UART_BASE >> 20);
+	out_le32(new_base + MV64x60_CPU2DEV_2_SIZE, EV64260_UART_END >> 20);
+	__asm__ __volatile__("sync");
+#elif defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	mv64x60_console_baud = EV64260_DEFAULT_BAUD;
+	mv64x60_mpsc_clk_src = EV64260_MPSC_CLK_SRC;
+	mv64x60_mpsc_clk_freq = EV64260_MPSC_CLK_FREQ;
+#endif
+}
diff --git a/arch/ppc/boot/simple/misc-katana.c b/arch/ppc/boot/simple/misc-katana.c
--- a/arch/ppc/boot/simple/misc-katana.c
+++ b/arch/ppc/boot/simple/misc-katana.c
@@ -1,7 +1,7 @@
 /*
  * arch/ppc/boot/simple/misc-katana.c
  *
- * Add birec data for Artesyn KATANA board.
+ * Set up MPSC values to bootwrapper can prompt user.
  *
  * Author: Mark A. Greer <source@mvista.com>
  *
@@ -11,5 +11,27 @@
  * or implied.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
-long	mv64x60_mpsc_clk_freq = 133333333;
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+#include <platforms/katana.h>
+
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+
+/* Not in the kernel so won't include kernel.h to get its 'min' definition */
+#ifndef min
+#define	min(a,b)	(((a) < (b)) ? (a) : (b))
+#endif
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+	mv64x60_console_baud = KATANA_DEFAULT_BAUD;
+	mv64x60_mpsc_clk_src = KATANA_MPSC_CLK_SRC;
+	mv64x60_mpsc_clk_freq =
+		min(katana_bus_freq((void __iomem *)KATANA_CPLD_BASE),
+			MV64x60_TCLK_FREQ_MAX);
+}
diff --git a/arch/ppc/boot/simple/misc-mv64x60.S b/arch/ppc/boot/simple/misc-mv64x60.S
deleted file mode 100644
--- a/arch/ppc/boot/simple/misc-mv64x60.S
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * arch/ppc/boot/simple/misc-mv64x60.S
- *
- * Code to change the base address of the host bridges and call board specific
- * init routine.
- *
- * Author: Mark Greer <mgreer@mvista.com>
- *
- * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
- * of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#include <linux/config.h>
-#include <asm/ppc_asm.h>
-#include <asm/processor.h>
-#include <asm/cache.h>
-#include <asm/mv64x60_defs.h>
-
-	.globl	mv64x60_init
-mv64x60_init:
-	mflr	r27
-
-#if (CONFIG_MV64X60_NEW_BASE != CONFIG_MV64X60_BASE)
-	bl	move_base
-#endif
-	bl	mv64x60_board_init
-
-	mtlr	r27
-	blr
-
-#if (CONFIG_MV64X60_NEW_BASE != CONFIG_MV64X60_BASE)
-move_base:
-	li	r20,0
-	li	r23,20
-
-	/* Relocate bridge's regs */
-	addis	r25,0,CONFIG_MV64X60_BASE@h
-	ori	r25,r25,MV64x60_INTERNAL_SPACE_DECODE
-	lwbrx	r26,0,(r25)
-	lis	r24,0xffff
-	and	r26,r26,r24
-	addis	r24,0,CONFIG_MV64X60_NEW_BASE@h
-	srw	r24,r24,r23
-	or	r26,r26,r24
-	stwbrx	r26,0,(r25)
-	sync
-
-	/* Wait for write to take effect */
-	addis	r25,0,CONFIG_MV64X60_NEW_BASE@h
-	ori	r25,r25,MV64x60_INTERNAL_SPACE_DECODE
-1:	lwbrx	r24,0,(r25)
-	cmpw	r24,r26
-	bne	1b
-
-	blr
-#endif
diff --git a/arch/ppc/boot/simple/misc-mv64x60.c b/arch/ppc/boot/simple/misc-mv64x60.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/boot/simple/misc-mv64x60.c
@@ -0,0 +1,61 @@
+/*
+ * arch/ppc/boot/simple/misc-mv64x60.c
+ *
+ * Relocate bridge's register base and call board specific routine.
+ *
+ * Author: Mark A. Greer <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+
+extern struct bi_record *decompress_kernel(unsigned long load_addr,
+	int num_words, unsigned long cksum);
+
+void
+mv64x60_move_base(void __iomem *old_base, void __iomem *new_base)
+{
+	u32	bits, mask, b;
+
+	if (old_base != new_base) {
+#ifdef CONFIG_GT64260
+		bits = 12;
+		mask = 0x07000000;
+#else /* Must be mv64[34]60 */
+		bits = 16;
+		mask = 0x03000000;
+#endif
+		b = in_le32(old_base + MV64x60_INTERNAL_SPACE_DECODE);
+		b &= mask;
+		b |= ((u32)new_base >> (32 - bits));
+		out_le32(old_base + MV64x60_INTERNAL_SPACE_DECODE, b);
+
+		__asm__ __volatile__("sync");
+
+		/* Wait for change to happen (in accordance with the manual) */
+		while (in_le32(new_base + MV64x60_INTERNAL_SPACE_DECODE) != b);
+	}
+}
+
+void __attribute__ ((weak))
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+}
+
+void *
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *ign1, void *ign2)
+{
+	mv64x60_move_base((void __iomem *)CONFIG_MV64X60_BASE,
+		(void __iomem *)CONFIG_MV64X60_NEW_BASE);
+	mv64x60_board_init((void __iomem *)CONFIG_MV64X60_BASE,
+		(void __iomem *)CONFIG_MV64X60_NEW_BASE);
+	return decompress_kernel(load_addr, num_words, cksum);
+}
diff --git a/arch/ppc/boot/simple/misc-radstone_ppc7d.c b/arch/ppc/boot/simple/misc-radstone_ppc7d.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/boot/simple/misc-radstone_ppc7d.c
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/boot/simple/misc-radstone_ppc7d.c
+ *
+ * Misc data for Radstone PPC7D board.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ */
+
+#include <linux/types.h>
+#include <platforms/radstone_ppc7d.h>
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+#endif
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	mv64x60_console_baud = PPC7D_DEFAULT_BAUD;
+	mv64x60_mpsc_clk_src = PPC7D_MPSC_CLK_SRC;
+	mv64x60_mpsc_clk_freq = PPC7D_MPSC_CLK_FREQ;
+#endif
+}
diff --git a/arch/ppc/boot/simple/mpc52xx_tty.c b/arch/ppc/boot/simple/mpc52xx_tty.c
--- a/arch/ppc/boot/simple/mpc52xx_tty.c
+++ b/arch/ppc/boot/simple/mpc52xx_tty.c
@@ -20,31 +20,31 @@
 #include <asm/io.h>
 #include <asm/time.h>
 
-#if MPC52xx_PF_CONSOLE_PORT == 0
-#define MPC52xx_CONSOLE		MPC52xx_PSC1
-#define MPC52xx_PSC_CONFIG_SHIFT	0
-#elif MPC52xx_PF_CONSOLE_PORT == 1
-#define MPC52xx_CONSOLE		MPC52xx_PSC2
-#define MPC52xx_PSC_CONFIG_SHIFT	4
-#elif MPC52xx_PF_CONSOLE_PORT == 2
-#define MPC52xx_CONSOLE		MPC52xx_PSC3
-#define MPC52xx_PSC_CONFIG_SHIFT	8
+
+#ifdef MPC52xx_PF_CONSOLE_PORT
+#define MPC52xx_CONSOLE MPC52xx_PSCx_OFFSET(MPC52xx_PF_CONSOLE_PORT)
+#define MPC52xx_PSC_CONFIG_SHIFT ((MPC52xx_PF_CONSOLE_PORT-1)<<2)
 #else
 #error "MPC52xx_PF_CONSOLE_PORT not defined"
 #endif
 
-static struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE;
+static struct mpc52xx_psc __iomem *psc =
+	(struct mpc52xx_psc __iomem *) MPC52xx_PA(MPC52xx_CONSOLE);
 
 /* The decrementer counts at the system bus clock frequency
  * divided by four.  The most accurate time base is connected to the
- * rtc.  We read the decrementer change during one rtc tick (one second)
- * and multiply by 4 to get the system bus clock frequency.
+ * rtc.  We read the decrementer change during one rtc tick
+ * and multiply by 4 to get the system bus clock frequency. Since a
+ * rtc tick is one seconds, and that's pretty long, we change the rtc
+ * dividers temporarly to set them 64x faster ;)
  */
-int
+static int
 mpc52xx_ipbfreq(void)
 {
-	struct mpc52xx_rtc *rtc = (struct mpc52xx_rtc*)MPC52xx_RTC;
-	struct mpc52xx_cdm *cdm = (struct mpc52xx_cdm*)MPC52xx_CDM;
+	struct mpc52xx_rtc __iomem *rtc =
+		(struct mpc52xx_rtc __iomem *) MPC52xx_PA(MPC52xx_RTC_OFFSET);
+	struct mpc52xx_cdm __iomem *cdm =
+		(struct mpc52xx_cdm __iomem *) MPC52xx_PA(MPC52xx_CDM_OFFSET);
 	int current_time, previous_time;
 	int tbl_start, tbl_end;
 	int xlbfreq, ipbfreq;
@@ -67,7 +67,8 @@ mpc52xx_ipbfreq(void)
 unsigned long
 serial_init(int ignored, void *ignored2)
 {
-	struct mpc52xx_gpio *gpio = (struct mpc52xx_gpio *)MPC52xx_GPIO;
+	struct mpc52xx_gpio __iomem *gpio =
+		(struct mpc52xx_gpio __iomem *) MPC52xx_PA(MPC52xx_GPIO_OFFSET);
 	int divisor;
 	int mode1;
 	int mode2;
@@ -117,7 +118,7 @@ serial_init(int ignored, void *ignored2)
 void
 serial_putc(void *ignored, const char c)
 {
-	serial_init(0, 0);
+	serial_init(0, NULL);
 
 	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
 	out_8(&psc->mpc52xx_psc_buffer_8, c);
diff --git a/arch/ppc/boot/simple/mv64x60_stub.c b/arch/ppc/boot/simple/mv64x60_stub.c
deleted file mode 100644
--- a/arch/ppc/boot/simple/mv64x60_stub.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/ppc/boot/simple/mv64x60_stub.c
- *
- * Stub for board_init() routine called from mv64x60_init().
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
- * of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#include <linux/config.h>
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
-long __attribute__ ((weak))	mv64x60_console_baud = 9600;
-long __attribute__ ((weak))	mv64x60_mpsc_clk_src = 8; /* TCLK */
-long __attribute__ ((weak))	mv64x60_mpsc_clk_freq = 100000000;
-#endif
-
-void __attribute__ ((weak))
-mv64x60_board_init(void)
-{
-}
diff --git a/arch/ppc/boot/simple/mv64x60_tty.c b/arch/ppc/boot/simple/mv64x60_tty.c
--- a/arch/ppc/boot/simple/mv64x60_tty.c
+++ b/arch/ppc/boot/simple/mv64x60_tty.c
@@ -18,36 +18,18 @@
 #include <linux/types.h>
 #include <linux/serial_reg.h>
 #include <asm/serial.h>
+#include <asm/io.h>
 #include <asm/mv64x60_defs.h>
 #include <mpsc_defs.h>
 
+u32	mv64x60_console_baud = 9600;
+u32	mv64x60_mpsc_clk_src = 8; /* TCLK */
+u32	mv64x60_mpsc_clk_freq = 100000000;
+
 extern void udelay(long);
 static void stop_dma(int chan);
 
-static u32	mv64x60_base = CONFIG_MV64X60_NEW_BASE;
-
-inline unsigned
-mv64x60_in_le32(volatile unsigned *addr)
-{
-	unsigned ret;
-
-	__asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
-				"r" (addr), "m" (*addr));
-	return ret;
-}
-
-inline void
-mv64x60_out_le32(volatile unsigned *addr, int val)
-{
-	__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
-				"r" (val), "r" (addr));
-}
-
-#define MV64x60_REG_READ(offs)						\
-	(mv64x60_in_le32((volatile uint *)(mv64x60_base + (offs))))
-#define MV64x60_REG_WRITE(offs, d)					\
-	(mv64x60_out_le32((volatile uint *)(mv64x60_base + (offs)), (int)(d)))
-
+static void __iomem *mv64x60_base = (void __iomem *)CONFIG_MV64X60_NEW_BASE;
 
 struct sdma_regs {
 	u32	sdc;
@@ -142,9 +124,6 @@ serial_init(int chan, void *ignored)
 {
 	u32		mpsc_routing_base, sdma_base, brg_bcr, cdv;
 	int		i;
-	extern long	mv64x60_console_baud;
-	extern long	mv64x60_mpsc_clk_src;
-	extern long	mv64x60_mpsc_clk_freq;
 
 	chan = (chan == 1); /* default to chan 0 if anything but 1 */
 
@@ -157,8 +136,7 @@ serial_init(int chan, void *ignored)
 		sdma_base = MV64x60_SDMA_0_OFFSET;
 		brg_bcr = MV64x60_BRG_0_OFFSET + BRG_BCR;
 		SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_0_OFFSET);
-	}
-	else {
+	} else {
 		sdma_base = MV64x60_SDMA_1_OFFSET;
 		brg_bcr = MV64x60_BRG_1_OFFSET + BRG_BCR;
 		SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_1_OFFSET);
@@ -186,10 +164,10 @@ serial_init(int chan, void *ignored)
 	td[chan][TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[chan][0];
 
 	/* Set MPSC Routing */
-	MV64x60_REG_WRITE(mpsc_routing_base + MPSC_MRR, 0x3ffffe38);
+	out_le32(mv64x60_base + mpsc_routing_base + MPSC_MRR, 0x3ffffe38);
 
 #ifdef CONFIG_GT64260
-	MV64x60_REG_WRITE(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
+	out_le32(mv64x60_base + GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
 #else /* Must be MV64360 or MV64460 */
 	{
 	u32	enables, prot_bits, v;
@@ -197,68 +175,70 @@ serial_init(int chan, void *ignored)
 	/* Set up comm unit to memory mapping windows */
 	/* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
 
-	enables = MV64x60_REG_READ(MV64360_CPU_BAR_ENABLE) & 0xf;
+	enables = in_le32(mv64x60_base + MV64360_CPU_BAR_ENABLE) & 0xf;
 	prot_bits = 0;
 
 	for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
 		if (!(enables & (1 << i))) {
-			v = MV64x60_REG_READ(cpu2mem_tab[i][0]);
+			v = in_le32(mv64x60_base + cpu2mem_tab[i][0]);
 			v = ((v & 0xffff) << 16) | (dram_selects[i] << 8);
-			MV64x60_REG_WRITE(com2mem_tab[i][0], v);
+			out_le32(mv64x60_base + com2mem_tab[i][0], v);
 
-			v = MV64x60_REG_READ(cpu2mem_tab[i][1]);
+			v = in_le32(mv64x60_base + cpu2mem_tab[i][1]);
 			v = (v & 0xffff) << 16;
-			MV64x60_REG_WRITE(com2mem_tab[i][1], v);
+			out_le32(mv64x60_base + com2mem_tab[i][1], v);
 
 			prot_bits |= (0x3 << (i << 1)); /* r/w access */
 		}
 	}
 
-	MV64x60_REG_WRITE(MV64360_MPSC_0_REMAP, 0);
-	MV64x60_REG_WRITE(MV64360_MPSC_1_REMAP, 0);
-	MV64x60_REG_WRITE(MV64360_MPSC2MEM_ACC_PROT_0, prot_bits);
-	MV64x60_REG_WRITE(MV64360_MPSC2MEM_ACC_PROT_1, prot_bits);
-	MV64x60_REG_WRITE(MV64360_MPSC2MEM_BAR_ENABLE, enables);
+	out_le32(mv64x60_base + MV64360_MPSC_0_REMAP, 0);
+	out_le32(mv64x60_base + MV64360_MPSC_1_REMAP, 0);
+	out_le32(mv64x60_base + MV64360_MPSC2MEM_ACC_PROT_0, prot_bits);
+	out_le32(mv64x60_base + MV64360_MPSC2MEM_ACC_PROT_1, prot_bits);
+	out_le32(mv64x60_base + MV64360_MPSC2MEM_BAR_ENABLE, enables);
 	}
 #endif
 
 	/* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
-	MV64x60_REG_WRITE(mpsc_routing_base + MPSC_RCRR, 0x00000100);
-	MV64x60_REG_WRITE(mpsc_routing_base + MPSC_TCRR, 0x00000100);
+	out_le32(mv64x60_base + mpsc_routing_base + MPSC_RCRR, 0x00000100);
+	out_le32(mv64x60_base + mpsc_routing_base + MPSC_TCRR, 0x00000100);
 
 	/* clear pending interrupts */
-	MV64x60_REG_WRITE(MV64x60_SDMA_INTR_OFFSET + SDMA_INTR_MASK, 0);
+	out_le32(mv64x60_base + MV64x60_SDMA_INTR_OFFSET + SDMA_INTR_MASK, 0);
 
-	MV64x60_REG_WRITE(SDMA_SCRDP + sdma_base, &rd[chan][0]);
-	MV64x60_REG_WRITE(SDMA_SCTDP + sdma_base, &td[chan][TX_NUM_DESC - 1]);
-	MV64x60_REG_WRITE(SDMA_SFTDP + sdma_base, &td[chan][TX_NUM_DESC - 1]);
+	out_le32(mv64x60_base + SDMA_SCRDP + sdma_base, (int)&rd[chan][0]);
+	out_le32(mv64x60_base + SDMA_SCTDP + sdma_base,
+		(int)&td[chan][TX_NUM_DESC - 1]);
+	out_le32(mv64x60_base + SDMA_SFTDP + sdma_base,
+		(int)&td[chan][TX_NUM_DESC - 1]);
 
-	MV64x60_REG_WRITE(SDMA_SDC + sdma_base,
+	out_le32(mv64x60_base + SDMA_SDC + sdma_base,
 		SDMA_SDC_RFT | SDMA_SDC_SFM | SDMA_SDC_BLMR | SDMA_SDC_BLMT |
 		(3 << 12));
 
 	cdv = ((mv64x60_mpsc_clk_freq/(32*mv64x60_console_baud))-1);
-	MV64x60_REG_WRITE(brg_bcr,
+	out_le32(mv64x60_base + brg_bcr,
 		((mv64x60_mpsc_clk_src << 18) | (1 << 16) | cdv));
 
 	/* Put MPSC into UART mode, no null modem, 16x clock mode */
-	MV64x60_REG_WRITE(MPSC_MMCRL + mpsc_base[chan], 0x000004c4);
-	MV64x60_REG_WRITE(MPSC_MMCRH + mpsc_base[chan], 0x04400400);
+	out_le32(mv64x60_base + MPSC_MMCRL + mpsc_base[chan], 0x000004c4);
+	out_le32(mv64x60_base + MPSC_MMCRH + mpsc_base[chan], 0x04400400);
 
-	MV64x60_REG_WRITE(MPSC_CHR_1 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_9 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_10 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_3 + mpsc_base[chan], 4);
-	MV64x60_REG_WRITE(MPSC_CHR_4 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_5 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_6 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_7 + mpsc_base[chan], 0);
-	MV64x60_REG_WRITE(MPSC_CHR_8 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_1 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_9 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_10 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_3 + mpsc_base[chan], 4);
+	out_le32(mv64x60_base + MPSC_CHR_4 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_5 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_6 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_7 + mpsc_base[chan], 0);
+	out_le32(mv64x60_base + MPSC_CHR_8 + mpsc_base[chan], 0);
 
 	/* 8 data bits, 1 stop bit */
-	MV64x60_REG_WRITE(MPSC_MPCR + mpsc_base[chan], (3 << 12));
-	MV64x60_REG_WRITE(SDMA_SDCM + sdma_base, SDMA_SDCM_ERD);
-	MV64x60_REG_WRITE(MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_EH);
+	out_le32(mv64x60_base + MPSC_MPCR + mpsc_base[chan], (3 << 12));
+	out_le32(mv64x60_base + SDMA_SDCM + sdma_base, SDMA_SDCM_ERD);
+	out_le32(mv64x60_base + MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_EH);
 
 	udelay(100);
 
@@ -271,20 +251,19 @@ stop_dma(int chan)
 	int	i;
 
 	/* Abort MPSC Rx (aborting Tx messes things up) */
-	MV64x60_REG_WRITE(MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_RA);
+	out_le32(mv64x60_base + MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_RA);
 
 	/* Abort SDMA Rx, Tx */
-	MV64x60_REG_WRITE(sdma_regs[chan].sdcm, SDMA_SDCM_AR | SDMA_SDCM_STD);
+	out_le32(mv64x60_base + sdma_regs[chan].sdcm,
+		SDMA_SDCM_AR | SDMA_SDCM_STD);
 
 	for (i=0; i<MAX_RESET_WAIT; i++) {
-		if ((MV64x60_REG_READ(sdma_regs[chan].sdcm) &
+		if ((in_le32(mv64x60_base + sdma_regs[chan].sdcm) &
 				(SDMA_SDCM_AR | SDMA_SDCM_AT)) == 0)
 			break;
 
 		udelay(100);
 	}
-
-	return;
 }
 
 static int
@@ -293,7 +272,7 @@ wait_for_ownership(int chan)
 	int	i;
 
 	for (i=0; i<MAX_TX_WAIT; i++) {
-		if ((MV64x60_REG_READ(sdma_regs[chan].sdcm) &
+		if ((in_le32(mv64x60_base + sdma_regs[chan].sdcm) &
 				SDMA_SDCM_TXD) == 0)
 			break;
 
@@ -321,12 +300,11 @@ serial_putc(unsigned long com_port, unsi
 	tdp->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |
 		SDMA_DESC_CMDSTAT_O;
 
-	MV64x60_REG_WRITE(sdma_regs[com_port].sctdp, tdp);
-	MV64x60_REG_WRITE(sdma_regs[com_port].sftdp, tdp);
-	MV64x60_REG_WRITE(sdma_regs[com_port].sdcm,
-		MV64x60_REG_READ(sdma_regs[com_port].sdcm) | SDMA_SDCM_TXD);
-
-	return;
+	out_le32(mv64x60_base + sdma_regs[com_port].sctdp, (int)tdp);
+	out_le32(mv64x60_base + sdma_regs[com_port].sftdp, (int)tdp);
+	out_le32(mv64x60_base + sdma_regs[com_port].sdcm,
+		in_le32(mv64x60_base + sdma_regs[com_port].sdcm) |
+			SDMA_SDCM_TXD);
 }
 
 unsigned char
@@ -366,8 +344,7 @@ serial_tstc(unsigned long com_port)
 			if (++cur_rd[com_port] >= RX_NUM_DESC)
 				cur_rd[com_port] = 0;
 			rdp = (struct mv64x60_rx_desc *)rdp->next_desc_ptr;
-		}
-		else {
+		} else {
 			rc = 1;
 			break;
 		}
@@ -380,5 +357,4 @@ void
 serial_close(unsigned long com_port)
 {
 	stop_dma(com_port);
-	return;
 }
diff --git a/arch/ppc/boot/simple/openbios.c b/arch/ppc/boot/simple/openbios.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/boot/simple/openbios.c
@@ -0,0 +1,37 @@
+/*
+ * arch/ppc/boot/simple/openbios.c
+ *
+ * 2005 (c) SYSGO AG - g.jaeger@sysgo.com
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ *
+ * Derived from arch/ppc/boot/simple/pibs.c (from MontaVista)
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <asm/ppcboot.h>
+#include <platforms/4xx/ebony.h>
+
+extern unsigned long decompress_kernel(unsigned long load_addr, int num_words,
+				       unsigned long cksum);
+
+/* We need to make sure that this is before the images to ensure
+ * that it's in a mapped location. */
+bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
+bd_t *hold_residual = &hold_resid_buf;
+
+void *
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *ign1, void *ign2)
+{
+	decompress_kernel(load_addr, num_words, cksum);
+
+	/* simply copy the MAC addresses */
+	memcpy(hold_residual->bi_enetaddr,  (char *)EBONY_OPENBIOS_MAC_BASE, 6);
+	memcpy(hold_residual->bi_enet1addr, (char *)(EBONY_OPENBIOS_MAC_BASE+EBONY_OPENBIOS_MAC_OFFSET), 6);
+
+	return (void *)hold_residual;
+}
diff --git a/arch/ppc/configs/chestnut_defconfig b/arch/ppc/configs/chestnut_defconfig
--- a/arch/ppc/configs/chestnut_defconfig
+++ b/arch/ppc/configs/chestnut_defconfig
@@ -1,11 +1,12 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Tue Dec  7 16:02:09 2004
+# Linux kernel version: 2.6.11
+# Fri Mar 11 14:32:49 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
@@ -35,6 +36,7 @@ CONFIG_KOBJECT_UEVENT=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +46,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -78,7 +81,9 @@ CONFIG_NOT_COHERENT_CACHE=y
 #
 # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_APUS is not set
+# CONFIG_KATANA is not set
 # CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
 # CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
 CONFIG_CHESTNUT=y
@@ -91,6 +96,7 @@ CONFIG_CHESTNUT=y
 # CONFIG_PRPMC750 is not set
 # CONFIG_PRPMC800 is not set
 # CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
 # CONFIG_ADIR is not set
 # CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
@@ -101,7 +107,9 @@ CONFIG_CHESTNUT=y
 # CONFIG_RPX8260 is not set
 # CONFIG_TQM8260 is not set
 # CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
 # CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
 CONFIG_MV64360=y
 CONFIG_MV64X60=y
 
@@ -128,6 +136,15 @@ CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
 # Advanced setup
 #
 CONFIG_ADVANCED_OPTIONS=y
@@ -154,6 +171,7 @@ CONFIG_BOOT_LOAD=0x00800000
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -181,6 +199,9 @@ 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_NOSWAP is not set
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -198,13 +219,16 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_CHESTNUT=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xfc000000
+CONFIG_MTD_PHYSMAP_LEN=0x02000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 
 #
 # Self-contained MTD device drivers
@@ -214,6 +238,7 @@ CONFIG_MTD_CHESTNUT=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -244,11 +269,13 @@ CONFIG_MTD_CHESTNUT=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
@@ -262,6 +289,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -404,7 +432,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -429,6 +456,10 @@ CONFIG_E100=y
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+CONFIG_MV643XX_ETH_1=y
+# CONFIG_MV643XX_ETH_2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -485,14 +516,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -502,6 +525,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -520,6 +550,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MPSC is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -550,6 +581,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 # CONFIG_I2C is not set
@@ -606,6 +642,16 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -614,6 +660,10 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -664,6 +714,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -686,7 +737,6 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -725,6 +775,7 @@ CONFIG_ZLIB_DEFLATE=y
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
@@ -737,3 +788,7 @@ CONFIG_ZLIB_DEFLATE=y
 # Cryptographic options
 #
 # CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/hdpu_defconfig b/arch/ppc/configs/hdpu_defconfig
new file mode 100644
--- /dev/null
+++ b/arch/ppc/configs/hdpu_defconfig
@@ -0,0 +1,890 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Wed Mar 16 12:43:19 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_NOT_COHERENT_CACHE is not set
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+CONFIG_HDPU=y
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xf1000000
+# CONFIG_SMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_NR_CPUS is not set
+CONFIG_PREEMPT=y
+CONFIG_HIGHMEM=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/nfs ip=auto"
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xfc000000
+CONFIG_MTD_PHYSMAP_LEN=0x04000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+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_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA 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_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR 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_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+# CONFIG_MV643XX_ETH_1 is not set
+# CONFIG_MV643XX_ETH_2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_MPSC=y
+CONFIG_SERIAL_MPSC_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+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_ASCII 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
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/katana_defconfig b/arch/ppc/configs/katana_defconfig
--- a/arch/ppc/configs/katana_defconfig
+++ b/arch/ppc/configs/katana_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Tue Jan 25 16:31:13 2005
+# Linux kernel version: 2.6.11
+# Tue Mar  8 17:31:00 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -36,6 +36,7 @@ CONFIG_KOBJECT_UEVENT=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -45,6 +46,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -70,6 +72,7 @@ CONFIG_6xx=y
 CONFIG_ALTIVEC=y
 # CONFIG_TAU is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_83xx is not set
 CONFIG_PPC_STD_MMU=y
 CONFIG_NOT_COHERENT_CACHE=y
 
@@ -93,6 +96,7 @@ CONFIG_KATANA=y
 # CONFIG_PRPMC750 is not set
 # CONFIG_PRPMC800 is not set
 # CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
 # CONFIG_ADIR is not set
 # CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
@@ -152,8 +156,8 @@ CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
 CONFIG_CONSISTENT_START_BOOL=y
 CONFIG_CONSISTENT_START=0xf0000000
-# CONFIG_CONSISTENT_SIZE_BOOL is not set
-CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_CONSISTENT_SIZE_BOOL=y
+CONFIG_CONSISTENT_SIZE=0x00400000
 # CONFIG_BOOT_LOAD_BOOL is not set
 CONFIG_BOOT_LOAD=0x00800000
 
@@ -171,7 +175,82 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_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
+# CONFIG_INFTL 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=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xe0000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+CONFIG_MTD_PHRAM=y
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
 
 #
 # Parallel port support
@@ -353,7 +432,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -378,6 +456,10 @@ CONFIG_E100=y
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+CONFIG_MV643XX_ETH_1=y
+CONFIG_MV643XX_ETH_2=y
 
 #
 # Ethernet (10000 Mbit)
@@ -500,7 +582,90 @@ CONFIG_GEN_RTC=y
 #
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_MV64XXX=y
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_M41T00=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # Dallas's 1-wire bus
@@ -531,7 +696,6 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -573,6 +737,10 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -619,6 +787,8 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_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_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -637,7 +807,6 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -674,6 +843,7 @@ CONFIG_CRC32=y
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+# CONFIG_PRINTK_TIME is not set
 
 #
 # Security options
diff --git a/arch/ppc/configs/mpc834x_sys_defconfig b/arch/ppc/configs/mpc834x_sys_defconfig
new file mode 100644
--- /dev/null
+++ b/arch/ppc/configs/mpc834x_sys_defconfig
@@ -0,0 +1,644 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc4
+# Thu Feb 17 16:12:23 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_GEN550=y
+CONFIG_83xx=y
+
+#
+# Freescale 83xx options
+#
+CONFIG_MPC834x_SYS=y
+CONFIG_MPC834x=y
+CONFIG_PPC_STD_MMU=y
+
+#
+# Platform options
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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=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_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ISA is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_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 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 is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/mpc8555_cds_defconfig b/arch/ppc/configs/mpc8555_cds_defconfig
--- a/arch/ppc/configs/mpc8555_cds_defconfig
+++ b/arch/ppc/configs/mpc8555_cds_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc1
-# Thu Jan 20 01:25:35 2005
+# Linux kernel version: 2.6.12-rc4
+# Tue May 17 11:56:01 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
@@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -29,12 +31,14 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +48,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -62,10 +67,12 @@ CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_E500=y
 CONFIG_BOOKE=y
 CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
 CONFIG_SPE=y
 CONFIG_MATH_EMULATION=y
 # CONFIG_CPU_FREQ is not set
 CONFIG_PPC_GEN550=y
+# CONFIG_PM is not set
 CONFIG_85xx=y
 CONFIG_PPC_INDIRECT_PCI_BE=y
 
@@ -76,6 +83,7 @@ CONFIG_PPC_INDIRECT_PCI_BE=y
 CONFIG_MPC8555_CDS=y
 # CONFIG_MPC8560_ADS is not set
 # CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
 CONFIG_MPC8555=y
 CONFIG_85xx_PCI2=y
 
@@ -90,6 +98,7 @@ CONFIG_CPM2=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -105,10 +114,6 @@ CONFIG_PCI_NAMES=y
 # CONFIG_PCCARD is not set
 
 #
-# PC-card bridges
-#
-
-#
 # Advanced setup
 #
 # CONFIG_ADVANCED_OPTIONS is not set
@@ -180,7 +185,59 @@ CONFIG_IOSCHED_CFQ=y
 #
 # ATA/ATAPI/MFM/RLL support
 #
-# CONFIG_IDE is not set
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI device support
@@ -220,7 +277,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -370,14 +426,6 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -387,6 +435,13 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -406,6 +461,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -434,6 +490,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -456,11 +517,11 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -483,7 +544,9 @@ CONFIG_I2C_MPC=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -494,9 +557,11 @@ CONFIG_I2C_MPC=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -506,10 +571,12 @@ CONFIG_I2C_MPC=y
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -538,7 +605,6 @@ CONFIG_I2C_MPC=y
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -548,13 +614,9 @@ CONFIG_I2C_MPC=y
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
 
 #
 # USB Gadget Support
@@ -585,6 +647,10 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -646,7 +712,6 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -698,7 +763,9 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_KGDB_CONSOLE is not set
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
diff --git a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig
--- a/arch/ppc/configs/pmac_defconfig
+++ b/arch/ppc/configs/pmac_defconfig
@@ -1,8 +1,12 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc4
+# Sun Feb 13 14:56:58 2005
 #
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
@@ -13,40 +17,45 @@ CONFIG_GENERIC_NVRAM=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=16
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 
 #
@@ -58,17 +67,21 @@ CONFIG_6xx=y
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E500 is not set
 CONFIG_ALTIVEC=y
 CONFIG_TAU=y
 # CONFIG_TAU_INT is not set
 # CONFIG_TAU_AVERAGE is not set
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_PROC_INTF=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
 CONFIG_CPU_FREQ_PMAC=y
 CONFIG_CPU_FREQ_TABLE=y
 CONFIG_PPC601_SYNC_FIX=y
@@ -80,11 +93,14 @@ CONFIG_PPC_STD_MMU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_APUS is not set
+# CONFIG_KATANA is not set
 # CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
 # CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
+# CONFIG_CHESTNUT is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_EV64260 is not set
 # CONFIG_LOPEC is not set
 # CONFIG_MCPN765 is not set
 # CONFIG_MVME5100 is not set
@@ -97,9 +113,13 @@ CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
 # CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
+# CONFIG_RPX8260 is not set
 # CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
 CONFIG_PPC_CHRP=y
 CONFIG_PPC_PMAC=y
 CONFIG_PPC_PREP=y
@@ -108,11 +128,9 @@ CONFIG_PPCBUG_NVRAM=y
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PROC_DEVICETREE=y
-CONFIG_PPC_RTAS=y
 # CONFIG_PREP_RESIDUAL is not set
 # CONFIG_CMDLINE_BOOL is not set
 
@@ -127,14 +145,21 @@ CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=m
+CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-CONFIG_YENTA=m
+CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
-CONFIG_I82092=m
-CONFIG_TCIC=m
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCCARD_NONSTATIC=m
 
 #
 # Advanced setup
@@ -156,7 +181,10 @@ CONFIG_BOOT_LOAD=0x00800000
 #
 # Generic Driver Options
 #
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -176,18 +204,35 @@ CONFIG_BOOT_LOAD=0x00800000
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+CONFIG_MAC_FLOPPY=m
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 CONFIG_LBD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -198,16 +243,15 @@ CONFIG_BLK_DEV_IDE=y
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-CONFIG_BLK_DEV_IDECS=m
+# 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
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -218,12 +262,11 @@ CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
@@ -249,7 +292,7 @@ CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDE_PMAC_BLINK=y
-CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
+# CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -275,7 +318,6 @@ CONFIG_CHR_DEV_SG=y
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 # CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -284,33 +326,35 @@ CONFIG_SCSI_CONSTANTS=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD 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_BUILD_FIRMWARE is not set
 CONFIG_AIC7XXX_DEBUG_ENABLE=y
 CONFIG_AIC7XXX_DEBUG_MASK=0
 CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_SCSI_AIC79XX is not set
-CONFIG_SCSI_ADVANSYS=m
-# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
@@ -327,7 +371,6 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
@@ -384,7 +427,8 @@ CONFIG_IEEE1394_SBP2=m
 CONFIG_IEEE1394_ETH1394=m
 CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
-# CONFIG_IEEE1394_CMP is not set
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
 
 #
 # I2O device support
@@ -400,8 +444,6 @@ CONFIG_ADB_PMU=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_PMAC_APM_EMU=y
 CONFIG_PMAC_BACKLIGHT=y
-# CONFIG_MAC_FLOPPY is not set
-CONFIG_MAC_SERIAL=y
 CONFIG_ADB_MACIO=y
 CONFIG_INPUT_ADBHID=y
 CONFIG_MAC_EMUMOUSEBTN=y
@@ -434,6 +476,9 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -447,11 +492,14 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CT_PROTO_SCTP=m
 CONFIG_IP_NF_FTP=m
 CONFIG_IP_NF_IRC=m
 CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
@@ -471,8 +519,17 @@ CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
 CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_MATCH_COMMENT=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -484,17 +541,19 @@ CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
 CONFIG_IP_NF_NAT_TFTP=m
 CONFIG_IP_NF_NAT_AMANDA=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_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_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -512,12 +571,12 @@ CONFIG_IP_NF_RAW=m
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -593,7 +652,6 @@ CONFIG_MII=y
 CONFIG_MACE=y
 # CONFIG_MACE_AAUI_PORT is not set
 CONFIG_BMAC=y
-# CONFIG_OAKNET is not set
 # CONFIG_HAPPYMEAL is not set
 CONFIG_SUNGEM=y
 # CONFIG_NET_VENDOR_3COM is not set
@@ -634,6 +692,7 @@ CONFIG_PCNET32=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -667,7 +726,6 @@ CONFIG_NET_RADIO=y
 #
 # Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_AIRO is not set
 CONFIG_HERMES=m
 CONFIG_APPLE_AIRPORT=m
 # CONFIG_PLX_HERMES is not set
@@ -691,15 +749,7 @@ CONFIG_NET_WIRELESS=y
 #
 # PCMCIA network device support
 #
-CONFIG_NET_PCMCIA=y
-# CONFIG_PCMCIA_3C589 is not set
-# CONFIG_PCMCIA_3C574 is not set
-# CONFIG_PCMCIA_FMVJ18X is not set
-# CONFIG_PCMCIA_PCNET is not set
-# CONFIG_PCMCIA_NMCLAN is not set
-# CONFIG_PCMCIA_SMC91C92 is not set
-# CONFIG_PCMCIA_XIRC2PS is not set
-# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_NET_PCMCIA is not set
 
 #
 # Wan interfaces
@@ -714,10 +764,9 @@ CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=y
 CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
+CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 # CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 
@@ -740,7 +789,7 @@ CONFIG_INPUT=y
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
@@ -753,11 +802,8 @@ CONFIG_INPUT_EVDEV=y
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
+# CONFIG_SERIO is not set
 # CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
 
 #
 # Input Device Drivers
@@ -796,12 +842,12 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_PMACZILOG=y
-# CONFIG_SERIAL_PMACZILOG_CONSOLE is not set
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -822,9 +868,14 @@ CONFIG_GEN_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+CONFIG_AGP=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_DRM=m
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
 
 #
 # PCMCIA character devices
@@ -843,6 +894,7 @@ CONFIG_I2C_CHARDEV=m
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -857,6 +909,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_ISA is not set
 CONFIG_I2C_KEYWEST=m
+# CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PIIX4 is not set
@@ -866,26 +919,38 @@ CONFIG_I2C_KEYWEST=m
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
 #
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -897,12 +962,18 @@ CONFIG_I2C_KEYWEST=m
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -920,6 +991,9 @@ CONFIG_I2C_KEYWEST=m
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
@@ -927,16 +1001,14 @@ CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
 CONFIG_FB_CT65550=y
+# CONFIG_FB_ASILIANT is not set
 CONFIG_FB_IMSTT=y
-# CONFIG_FB_S3TRIO is not set
 # CONFIG_FB_VGA16 is not set
 # CONFIG_FB_RIVA is not set
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G450 is not set
-CONFIG_FB_MATROX_G100A=y
-CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_G=y
 # CONFIG_FB_MATROX_I2C is not set
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_RADEON_OLD is not set
@@ -946,12 +1018,15 @@ CONFIG_FB_RADEON_I2C=y
 CONFIG_FB_ATY128=y
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_CT=y
-CONFIG_FB_ATY_GX=y
+CONFIG_FB_ATY_GENERIC_LCD=y
 # CONFIG_FB_ATY_XL_INIT is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 CONFIG_FB_3DFX=y
+CONFIG_FB_3DFX_ACCEL=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
@@ -960,10 +1035,8 @@ CONFIG_FB_3DFX=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
@@ -975,6 +1048,11 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
 
 #
 # Sound
@@ -989,6 +1067,7 @@ CONFIG_DMASOUND=m
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
 CONFIG_SND_RAWMIDI=m
 CONFIG_SND_SEQUENCER=m
 CONFIG_SND_SEQ_DUMMY=m
@@ -1013,6 +1092,7 @@ CONFIG_SND_DUMMY=m
 #
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_AU8810 is not set
 # CONFIG_SND_AU8820 is not set
 # CONFIG_SND_AU8830 is not set
@@ -1021,6 +1101,8 @@ CONFIG_SND_DUMMY=m
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
@@ -1044,6 +1126,7 @@ CONFIG_SND_DUMMY=m
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 
 #
@@ -1052,9 +1135,10 @@ CONFIG_SND_DUMMY=m
 CONFIG_SND_POWERMAC=m
 
 #
-# ALSA USB devices
+# USB devices
 #
 CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_USX2Y=m
 
 #
 # PCMCIA devices
@@ -1077,6 +1161,10 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -1084,6 +1172,7 @@ CONFIG_USB_DYNAMIC_MINORS=y
 # CONFIG_USB_EHCI_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1093,20 +1182,25 @@ CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_MIDI is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 # CONFIG_USB_STORAGE is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 # CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
 
@@ -1115,7 +1209,6 @@ CONFIG_USB_HIDINPUT=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -1127,11 +1220,11 @@ CONFIG_USB_HIDINPUT=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_PEGASUS=m
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
 
@@ -1147,6 +1240,7 @@ CONFIG_USB_SERIAL=m
 # 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_CYPRESS_M8 is not set
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 CONFIG_USB_SERIAL_VISOR=m
@@ -1154,41 +1248,75 @@ CONFIG_USB_SERIAL_VISOR=m
 # 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_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
 # CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI 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_EZUSB=y
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB ATM/DSL drivers
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -1198,10 +1326,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -1211,7 +1344,8 @@ CONFIG_FS_MBCACHE=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
@@ -1219,6 +1353,8 @@ CONFIG_ISO9660_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1227,11 +1363,12 @@ CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -1245,7 +1382,7 @@ CONFIG_HFSPLUS_FS=m
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
+CONFIG_CRAMFS=m
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -1256,16 +1393,19 @@ CONFIG_HFSPLUS_FS=m
 # Network File Systems
 #
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 # CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_CIFS is not set
@@ -1288,7 +1428,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -1320,8 +1459,9 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -1332,31 +1472,52 @@ CONFIG_NLS_ISO8859_1=m
 # 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_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 
 #
 # Library routines
 #
+CONFIG_CRC_CCITT=y
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
 CONFIG_BOOTX_TEXT=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
 #
 # CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/radstone_ppc7d_defconfig b/arch/ppc/configs/radstone_ppc7d_defconfig
new file mode 100644
--- /dev/null
+++ b/arch/ppc/configs/radstone_ppc7d_defconfig
@@ -0,0 +1,956 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Tue Mar 15 14:31:19 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_GEN550=y
+# CONFIG_PM is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_NOT_COHERENT_CACHE is not set
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+CONFIG_RADSTONE_PPC7D=y
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xfef00000
+CONFIG_MV64X60_NEW_BASE=0xfef00000
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600"
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_FTL=y
+# CONFIG_NFTL is not set
+# CONFIG_INFTL 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA 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_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 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_IPR 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_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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=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_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO 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
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+CONFIG_R8169_NAPI=y
+CONFIG_SK98LIN=y
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=y
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+CONFIG_MV643XX_ETH_1=y
+# CONFIG_MV643XX_ETH_2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_XTKBD=y
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_MPSC=y
+# CONFIG_SERIAL_MPSC_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_MV64XXX=y
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -5,10 +5,11 @@
 extra-$(CONFIG_PPC_STD_MMU)	:= head.o
 extra-$(CONFIG_40x)		:= head_4xx.o
 extra-$(CONFIG_44x)		:= head_44x.o
-extra-$(CONFIG_E500)		:= head_e500.o
+extra-$(CONFIG_FSL_BOOKE)	:= head_fsl_booke.o
 extra-$(CONFIG_8xx)		:= head_8xx.o
 extra-$(CONFIG_6xx)		+= idle_6xx.o
 extra-$(CONFIG_POWER4)		+= idle_power4.o
+extra-$(CONFIG_PPC_FPU)		+= fpu.o
 extra-y				+= vmlinux.lds
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
@@ -16,6 +17,7 @@ obj-y				:= entry.o traps.o irq.o idle.o
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o perfmon.o
 obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
 obj-$(CONFIG_POWER4)		+= cpu_setup_power4.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
--- a/arch/ppc/kernel/align.c
+++ b/arch/ppc/kernel/align.c
@@ -248,7 +248,7 @@ fix_alignment(struct pt_regs *regs)
 		 */
 		p = (long __user *) (regs->dar & -L1_CACHE_BYTES);
 		if (user_mode(regs)
-		    && verify_area(VERIFY_WRITE, p, L1_CACHE_BYTES))
+		    && !access_ok(VERIFY_WRITE, p, L1_CACHE_BYTES))
 			return -EFAULT;
 		for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
 			if (__put_user(0, p+i))
@@ -290,6 +290,10 @@ fix_alignment(struct pt_regs *regs)
 			/* lwm, stmw */
 			nb = (32 - reg) * 4;
 		}
+
+		if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb+nb0))
+			return -EFAULT;	/* bad address */
+
 		rptr = (unsigned char *) &regs->gpr[reg];
 		if (flags & LD) {
 			for (i = 0; i < nb; ++i)
@@ -328,7 +332,7 @@ fix_alignment(struct pt_regs *regs)
 
 	/* Verify the address of the operand */
 	if (user_mode(regs)) {
-		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+		if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
 			return -EFAULT;	/* bad address */
 	}
 
@@ -368,16 +372,24 @@ fix_alignment(struct pt_regs *regs)
 
 	/* Single-precision FP load and store require conversions... */
 	case LD+F+S:
+#ifdef CONFIG_PPC_FPU
 		preempt_disable();
 		enable_kernel_fp();
 		cvt_fd(&data.f, &data.d, &current->thread.fpscr);
 		preempt_enable();
+#else
+		return 0;
+#endif
 		break;
 	case ST+F+S:
+#ifdef CONFIG_PPC_FPU
 		preempt_disable();
 		enable_kernel_fp();
 		cvt_df(&data.d, &data.f, &current->thread.fpscr);
 		preempt_enable();
+#else
+		return 0;
+#endif
 		break;
 	}
 
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
+#include <linux/suspend.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <asm/io.h>
@@ -136,6 +137,10 @@ main(void)
 	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 	DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
 
+	DEFINE(pbe_address, offsetof(struct pbe, address));
+	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+	DEFINE(pbe_next, offsetof(struct pbe, next));
+
 	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
 	return 0;
 }
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
--- a/arch/ppc/kernel/cpu_setup_6xx.S
+++ b/arch/ppc/kernel/cpu_setup_6xx.S
@@ -30,12 +30,14 @@ _GLOBAL(__setup_cpu_604)
 	blr
 _GLOBAL(__setup_cpu_750)
 	mflr	r4
+	bl	__init_fpu_registers
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
 	mtlr	r4
 	blr
 _GLOBAL(__setup_cpu_750cx)
 	mflr	r4
+	bl	__init_fpu_registers
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
 	bl	setup_750cx
@@ -43,6 +45,7 @@ _GLOBAL(__setup_cpu_750cx)
 	blr
 _GLOBAL(__setup_cpu_750fx)
 	mflr	r4
+	bl	__init_fpu_registers
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
 	bl	setup_750fx
@@ -50,6 +53,7 @@ _GLOBAL(__setup_cpu_750fx)
 	blr
 _GLOBAL(__setup_cpu_7400)
 	mflr	r4
+	bl	__init_fpu_registers
 	bl	setup_7400_workarounds
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
@@ -57,6 +61,7 @@ _GLOBAL(__setup_cpu_7400)
 	blr
 _GLOBAL(__setup_cpu_7410)
 	mflr	r4
+	bl	__init_fpu_registers
 	bl	setup_7410_workarounds
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
@@ -73,16 +78,16 @@ _GLOBAL(__setup_cpu_745x)
 
 /* Enable caches for 603's, 604, 750 & 7400 */
 setup_common_caches:
-	mfspr	r11,HID0
+	mfspr	r11,SPRN_HID0
 	andi.	r0,r11,HID0_DCE
 	ori	r11,r11,HID0_ICE|HID0_DCE
 	ori	r8,r11,HID0_ICFI
 	bne	1f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
 1:	sync
-	mtspr	HID0,r8			/* enable and invalidate caches */
+	mtspr	SPRN_HID0,r8		/* enable and invalidate caches */
 	sync
-	mtspr	HID0,r11		/* enable caches */
+	mtspr	SPRN_HID0,r11		/* enable caches */
 	sync
 	isync
 	blr
@@ -91,13 +96,13 @@ setup_common_caches:
  * Enable superscalar execution & branch history table
  */
 setup_604_hid0:
-	mfspr	r11,HID0
+	mfspr	r11,SPRN_HID0
 	ori	r11,r11,HID0_SIED|HID0_BHTE
 	ori	r8,r11,HID0_BTCD
 	sync
-	mtspr	HID0,r8		/* flush branch target address cache */
+	mtspr	SPRN_HID0,r8	/* flush branch target address cache */
 	sync			/* on 604e/604r */
-	mtspr	HID0,r11
+	mtspr	SPRN_HID0,r11
 	sync
 	isync
 	blr
@@ -150,17 +155,21 @@ setup_7410_workarounds:
  * Clear Instruction cache throttling (ICTC)
  */
 setup_750_7400_hid0:
-	mfspr	r11,HID0
+	mfspr	r11,SPRN_HID0
 	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
+	oris	r11,r11,HID0_DPM@h
 BEGIN_FTR_SECTION
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+	xori	r11,r11,HID0_BTIC
+END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC)
+BEGIN_FTR_SECTION
+	xoris	r11,r11,HID0_DPM@h	/* disable dynamic power mgmt */
+END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
 	li	r3,HID0_SPD
 	andc	r11,r11,r3		/* clear SPD: enable speculative */
  	li	r3,0
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+ 	mtspr	SPRN_ICTC,r3		/* Instruction Cache Throttling off */
 	isync
-	mtspr	HID0,r11
+	mtspr	SPRN_HID0,r11
 	sync
 	isync
 	blr
@@ -214,17 +223,19 @@ setup_745x_specifics:
 	andc	r6,r6,r7
 	stw	r6,CPU_SPEC_FEATURES(r5)
 1:
-	mfspr	r11,HID0
+	mfspr	r11,SPRN_HID0
 
 	/* All of the bits we have to set.....
 	 */
-	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK | HID0_BTIC
+	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE
+	ori	r11,r11,HID0_LRSTK | HID0_BTIC
+	oris	r11,r11,HID0_DPM@h
 BEGIN_FTR_SECTION
 	xori	r11,r11,HID0_BTIC
 END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC)
 BEGIN_FTR_SECTION
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+	xoris	r11,r11,HID0_DPM@h	/* disable dynamic power mgmt */
+END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
 
 	/* All of the bits we have to clear....
 	 */
@@ -232,9 +243,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	andc	r11,r11,r3		/* clear SPD: enable speculative */
  	li	r3,0
 
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+ 	mtspr	SPRN_ICTC,r3		/* Instruction Cache Throttling off */
 	isync
-	mtspr	HID0,r11
+	mtspr	SPRN_HID0,r11
 	sync
 	isync
 
@@ -248,6 +259,25 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	isync
 	blr
 
+/*
+ * Initialize the FPU registers. This is needed to work around an errata
+ * in some 750 cpus where using a not yet initialized FPU register after
+ * power on reset may hang the CPU
+ */
+_GLOBAL(__init_fpu_registers)
+	mfmsr	r10
+	ori	r11,r10,MSR_FP
+	mtmsr	r11
+	isync
+	addis	r9,r3,empty_zero_page@ha
+	addi	r9,r9,empty_zero_page@l
+	REST_32FPRS(0,r9)
+	sync
+	mtmsr	r10
+	isync
+	blr
+
+
 /* Definitions for the table use to save CPU states */
 #define CS_HID0		0
 #define CS_HID1		4
@@ -285,7 +315,7 @@ _GLOBAL(__save_cpu_setup)
 	stw	r3,CS_HID0(r5)
 
 	/* Now deal with CPU type dependent registers */
-	mfspr	r3,PVR
+	mfspr	r3,SPRN_PVR
 	srwi	r3,r3,16
 	cmplwi	cr0,r3,0x8000	/* 7450 */
 	cmplwi	cr1,r3,0x000c	/* 7400 */
@@ -323,7 +353,7 @@ _GLOBAL(__save_cpu_setup)
 	mfspr	r4,SPRN_HID1
 	stw	r4,CS_HID1(r5)
 	/* If rev 2.x, backup HID2 */
-	mfspr	r3,PVR
+	mfspr	r3,SPRN_PVR
 	andi.	r3,r3,0xff00
 	cmpwi	cr0,r3,0x0200
 	bne	1f
@@ -354,7 +384,7 @@ _GLOBAL(__restore_cpu_setup)
 	isync
 
 	/* Now deal with CPU type dependent registers */
-	mfspr	r3,PVR
+	mfspr	r3,SPRN_PVR
 	srwi	r3,r3,16
 	cmplwi	cr0,r3,0x8000	/* 7450 */
 	cmplwi	cr1,r3,0x000c	/* 7400 */
@@ -414,7 +444,7 @@ _GLOBAL(__restore_cpu_setup)
 	 * to PLL 0 on all
 	 */
 	/* If rev 2.x, restore HID2 with low voltage bit cleared */
-	mfspr	r3,PVR
+	mfspr	r3,SPRN_PVR
 	andi.	r3,r3,0xff00
 	cmpwi	cr0,r3,0x0200
 	bne	4f
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -560,6 +560,18 @@ struct cpu_spec	cpu_specs[] = {
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603
 	},
+	{	/* e300 (a 603e core, plus some) on 83xx */
+		.pvr_mask		= 0x7fff0000,
+		.pvr_value		= 0x00830000,
+		.cpu_name		= "e300",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB |
+			CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS,
+		.cpu_user_features	= COMMON_PPC,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+		.cpu_setup		= __setup_cpu_603
+	},
 	{	/* default match, we assume split I/D cache & TB (non-601)... */
 		.pvr_mask		= 0x00000000,
 		.pvr_value		= 0x00000000,
@@ -826,6 +838,17 @@ struct cpu_spec	cpu_specs[] = {
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 	},
+	{	/* 405EP */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x51210000,
+		.cpu_name		= "405EP",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB,
+		.cpu_user_features	= PPC_FEATURE_32 |
+			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+	},
 
 #endif /* CONFIG_40x */
 #ifdef CONFIG_44x
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c
--- a/arch/ppc/kernel/dma-mapping.c
+++ b/arch/ppc/kernel/dma-mapping.c
@@ -219,7 +219,8 @@ __dma_alloc_coherent(size_t size, dma_ad
 	c = vm_region_alloc(&consistent_head, size,
 			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
 	if (c) {
-		pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+		unsigned long vaddr = c->vm_start;
+		pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr);
 		struct page *end = page + (1 << order);
 
 		/*
@@ -232,9 +233,11 @@ __dma_alloc_coherent(size_t size, dma_ad
 
 			set_page_count(page, 1);
 			SetPageReserved(page);
-			set_pte(pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
+			set_pte_at(&init_mm, vaddr,
+				   pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
 			page++;
 			pte++;
+			vaddr += PAGE_SIZE;
 		} while (size -= PAGE_SIZE);
 
 		/*
@@ -262,7 +265,7 @@ EXPORT_SYMBOL(__dma_alloc_coherent);
 void __dma_free_coherent(size_t size, void *vaddr)
 {
 	struct vm_region *c;
-	unsigned long flags;
+	unsigned long flags, addr;
 	pte_t *ptep;
 
 	size = PAGE_ALIGN(size);
@@ -281,11 +284,13 @@ void __dma_free_coherent(size_t size, vo
 	}
 
 	ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+	addr = c->vm_start;
 	do {
-		pte_t pte = ptep_get_and_clear(ptep);
+		pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
 		unsigned long pfn;
 
 		ptep++;
+		addr += PAGE_SIZE;
 
 		if (!pte_none(pte) && pte_present(pte)) {
 			pfn = pte_pfn(pte);
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -45,40 +45,37 @@
 #endif
 
 #ifdef CONFIG_BOOKE
-#define	COR	r8	/* Critical Offset Register (COR) */
-#define BOOKE_LOAD_COR	lis COR,crit_save@ha
-#define BOOKE_REST_COR	mfspr COR,SPRG2
-#define BOOKE_SAVE_COR	mtspr SPRG2,COR
-#else
-#define COR	0
-#define BOOKE_LOAD_COR
-#define BOOKE_REST_COR
-#define BOOKE_SAVE_COR
-#endif
-
-#ifdef CONFIG_BOOKE
+#include "head_booke.h"
 	.globl	mcheck_transfer_to_handler
 mcheck_transfer_to_handler:
-	mtspr	SPRG6W,r8
-	lis	r8,mcheck_save@ha
-	lwz	r0,mcheck_r10@l(r8)
+	mtspr	MCHECK_SPRG,r8
+	BOOKE_LOAD_MCHECK_STACK
+	lwz	r0,GPR10-INT_FRAME_SIZE(r8)
 	stw	r0,GPR10(r11)
-	lwz	r0,mcheck_r11@l(r8)
+	lwz	r0,GPR11-INT_FRAME_SIZE(r8)
 	stw	r0,GPR11(r11)
-	mfspr	r8,SPRG6R
+	mfspr	r8,MCHECK_SPRG
 	b	transfer_to_handler_full
+
+	.globl	crit_transfer_to_handler
+crit_transfer_to_handler:
+	mtspr	CRIT_SPRG,r8
+	BOOKE_LOAD_CRIT_STACK
+	lwz	r0,GPR10-INT_FRAME_SIZE(r8)
+	stw	r0,GPR10(r11)
+	lwz	r0,GPR11-INT_FRAME_SIZE(r8)
+	stw	r0,GPR11(r11)
+	mfspr	r8,CRIT_SPRG
+	/* fall through */
 #endif
 
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_40x
 	.globl	crit_transfer_to_handler
 crit_transfer_to_handler:
-	BOOKE_SAVE_COR
-	BOOKE_LOAD_COR
-	lwz	r0,crit_r10@l(COR)
+	lwz	r0,crit_r10@l(0)
 	stw	r0,GPR10(r11)
-	lwz	r0,crit_r11@l(COR)
+	lwz	r0,crit_r11@l(0)
 	stw	r0,GPR11(r11)
-	BOOKE_REST_COR
 	/* fall through */
 #endif
 
@@ -101,10 +98,10 @@ transfer_to_handler:
 	stw	r9,_MSR(r11)
 	andi.	r2,r9,MSR_PR
 	mfctr	r12
-	mfspr	r2,XER
+	mfspr	r2,SPRN_XER
 	stw	r12,_CTR(r11)
 	stw	r2,_XER(r11)
-	mfspr	r12,SPRG3
+	mfspr	r12,SPRN_SPRG3
 	addi	r2,r12,-THREAD
 	tovirt(r2,r2)			/* set r2 to current */
 	beq	2f			/* if from user, fix up THREAD.regs */
@@ -152,8 +149,8 @@ transfer_to_handler_cont:
 	lwz	r11,0(r9)		/* virtual address of handler */
 	lwz	r9,4(r9)		/* where to go when done */
 	FIX_SRR1(r10,r12)
-	mtspr	SRR0,r11
-	mtspr	SRR1,r10
+	mtspr	SPRN_SRR0,r11
+	mtspr	SPRN_SRR1,r10
 	mtlr	r9
 	SYNC
 	RFI				/* jump to handler, enable MMU */
@@ -177,8 +174,8 @@ stack_ovf:
 	addi	r9,r9,StackOverflow@l
 	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
 	FIX_SRR1(r10,r12)
-	mtspr	SRR0,r9
-	mtspr	SRR1,r10
+	mtspr	SPRN_SRR0,r9
+	mtspr	SPRN_SRR1,r10
 	SYNC
 	RFI
 
@@ -260,8 +257,8 @@ syscall_exit_cont:
 	FIX_SRR1(r8, r0)
 	lwz	r2,GPR2(r1)
 	lwz	r1,GPR1(r1)
-	mtspr	SRR0,r7
-	mtspr	SRR1,r8
+	mtspr	SPRN_SRR0,r7
+	mtspr	SPRN_SRR1,r8
 	SYNC
 	RFI
 
@@ -538,7 +535,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
 	tophys(r0,r4)
 	CLR_TOP32(r0)
-	mtspr	SPRG3,r0	/* Update current THREAD phys addr */
+	mtspr	SPRN_SPRG3,r0	/* Update current THREAD phys addr */
 	lwz	r1,KSP(r4)	/* Load new stack pointer */
 
 	/* save the old current 'last' for return value */
@@ -566,6 +563,65 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	addi	r1,r1,INT_FRAME_SIZE
 	blr
 
+	.globl	fast_exception_return
+fast_exception_return:
+#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
+	andi.	r10,r9,MSR_RI		/* check for recoverable interrupt */
+	beq	1f			/* if not, we've got problems */
+#endif
+
+2:	REST_4GPRS(3, r11)
+	lwz	r10,_CCR(r11)
+	REST_GPR(1, r11)
+	mtcr	r10
+	lwz	r10,_LINK(r11)
+	mtlr	r10
+	REST_GPR(10, r11)
+	mtspr	SPRN_SRR1,r9
+	mtspr	SPRN_SRR0,r12
+	REST_GPR(9, r11)
+	REST_GPR(12, r11)
+	lwz	r11,GPR11(r11)
+	SYNC
+	RFI
+
+#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
+/* check if the exception happened in a restartable section */
+1:	lis	r3,exc_exit_restart_end@ha
+	addi	r3,r3,exc_exit_restart_end@l
+	cmplw	r12,r3
+	bge	3f
+	lis	r4,exc_exit_restart@ha
+	addi	r4,r4,exc_exit_restart@l
+	cmplw	r12,r4
+	blt	3f
+	lis	r3,fee_restarts@ha
+	tophys(r3,r3)
+	lwz	r5,fee_restarts@l(r3)
+	addi	r5,r5,1
+	stw	r5,fee_restarts@l(r3)
+	mr	r12,r4		/* restart at exc_exit_restart */
+	b	2b
+
+	.comm	fee_restarts,4
+
+/* aargh, a nonrecoverable interrupt, panic */
+/* aargh, we don't know which trap this is */
+/* but the 601 doesn't implement the RI bit, so assume it's OK */
+3:
+BEGIN_FTR_SECTION
+	b	2b
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+	li	r10,-1
+	stw	r10,TRAP(r11)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	lis	r10,MSR_KERNEL@h
+	ori	r10,r10,MSR_KERNEL@l
+	bl	transfer_to_handler_full
+	.long	nonrecoverable_exception
+	.long	ret_from_except
+#endif
+
 	.globl	sigreturn_exit
 sigreturn_exit:
 	subi	r1,r3,STACK_FRAME_OVERHEAD
@@ -642,7 +698,7 @@ restore:
 
 	lwz	r10,_XER(r1)
 	lwz	r11,_CTR(r1)
-	mtspr	XER,r10
+	mtspr	SPRN_XER,r10
 	mtctr	r11
 
 	PPC405_ERR77(0,r1)
@@ -675,8 +731,8 @@ exc_exit_restart:
 	lwz	r9,_MSR(r1)
 	lwz	r12,_NIP(r1)
 	FIX_SRR1(r9,r10)
-	mtspr	SRR0,r12
-	mtspr	SRR1,r9
+	mtspr	SPRN_SRR0,r12
+	mtspr	SPRN_SRR1,r9
 	REST_4GPRS(9, r1)
 	lwz	r1,GPR1(r1)
 	.globl exc_exit_restart_end
@@ -702,8 +758,8 @@ exc_exit_restart:
 	lwz	r11,_NIP(r1)
 	lwz	r12,_MSR(r1)
 exc_exit_start:
-	mtspr	SRR0,r11
-	mtspr	SRR1,r12
+	mtspr	SPRN_SRR0,r11
+	mtspr	SPRN_SRR1,r12
 	REST_2GPRS(11, r1)
 	lwz	r1,GPR1(r1)
 	.globl exc_exit_restart_end
@@ -724,8 +780,6 @@ exc_exit_restart_end:
  * We have to restore various SPRs that may have been in use at the
  * time of the critical interrupt.
  *
- * Note that SPRG6 is used for machine check on CONFIG_BOOKE parts and
- * thus not saved in the critical handler
  */
 	.globl	ret_from_crit_exc
 ret_from_crit_exc:
@@ -742,7 +796,7 @@ ret_from_crit_exc:
 
 	lwz	r10,_XER(r1)
 	lwz	r11,_CTR(r1)
-	mtspr	XER,r10
+	mtspr	SPRN_XER,r10
 	mtctr	r11
 
 	PPC405_ERR77(0,r1)
@@ -766,36 +820,13 @@ ret_from_crit_exc:
 	mtspr	SPRN_ESR,r10
 	lwz	r11,_NIP(r1)
 	lwz	r12,_MSR(r1)
-	mtspr	CSRR0,r11
-	mtspr	CSRR1,r12
+	mtspr	SPRN_CSRR0,r11
+	mtspr	SPRN_CSRR1,r12
 	lwz	r9,GPR9(r1)
 	lwz	r12,GPR12(r1)
-	BOOKE_SAVE_COR
-	BOOKE_LOAD_COR
-	lwz	r10,crit_sprg0@l(COR)
-	mtspr	SPRN_SPRG0,r10
-	lwz	r10,crit_sprg1@l(COR)
-	mtspr	SPRN_SPRG1,r10
-	lwz	r10,crit_sprg4@l(COR)
-	mtspr	SPRN_SPRG4,r10
-	lwz	r10,crit_sprg5@l(COR)
-	mtspr	SPRN_SPRG5,r10
-#ifdef CONFIG_40x
-	lwz	r10,crit_sprg6@l(COR)
-	mtspr	SPRN_SPRG6,r10
-#endif
-	lwz	r10,crit_sprg7@l(COR)
-	mtspr	SPRN_SPRG7,r10
-	lwz	r10,crit_srr0@l(COR)
-	mtspr	SRR0,r10
-	lwz	r10,crit_srr1@l(COR)
-	mtspr	SRR1,r10
-	lwz	r10,crit_pid@l(COR)
-	mtspr	SPRN_PID,r10
 	lwz	r10,GPR10(r1)
 	lwz	r11,GPR11(r1)
 	lwz	r1,GPR1(r1)
-	BOOKE_REST_COR
 	PPC405_ERR77_SYNC
 	rfci
 	b	.		/* prevent prefetch past rfci */
@@ -820,7 +851,7 @@ ret_from_mcheck_exc:
 
 	lwz	r10,_XER(r1)
 	lwz	r11,_CTR(r1)
-	mtspr	XER,r10
+	mtspr	SPRN_XER,r10
 	mtctr	r11
 
 	stwcx.	r0,0,r1			/* to clear the reservation */
@@ -835,36 +866,13 @@ ret_from_mcheck_exc:
 	mtspr	SPRN_ESR,r10
 	lwz	r11,_NIP(r1)
 	lwz	r12,_MSR(r1)
-	mtspr	MCSRR0,r11
-	mtspr	MCSRR1,r12
+	mtspr	SPRN_MCSRR0,r11
+	mtspr	SPRN_MCSRR1,r12
 	lwz	r9,GPR9(r1)
 	lwz	r12,GPR12(r1)
-	mtspr	SPRG6W,r8
-	lis	r8,mcheck_save@ha
-	lwz	r10,mcheck_sprg0@l(r8)
-	mtspr	SPRN_SPRG0,r10
-	lwz	r10,mcheck_sprg1@l(r8)
-	mtspr	SPRN_SPRG1,r10
-	lwz	r10,mcheck_sprg4@l(r8)
-	mtspr	SPRN_SPRG4,r10
-	lwz	r10,mcheck_sprg5@l(r8)
-	mtspr	SPRN_SPRG5,r10
-	lwz	r10,mcheck_sprg7@l(r8)
-	mtspr	SPRN_SPRG7,r10
-	lwz	r10,mcheck_srr0@l(r8)
-	mtspr	SRR0,r10
-	lwz	r10,mcheck_srr1@l(r8)
-	mtspr	SRR1,r10
-	lwz	r10,mcheck_csrr0@l(r8)
-	mtspr	CSRR0,r10
-	lwz	r10,mcheck_csrr1@l(r8)
-	mtspr	CSRR1,r10
-	lwz	r10,mcheck_pid@l(r8)
-	mtspr	SPRN_PID,r10
 	lwz	r10,GPR10(r1)
 	lwz	r11,GPR11(r1)
 	lwz	r1,GPR1(r1)
-	mfspr	r8,SPRG6R
 	RFMCI
 #endif /* CONFIG_BOOKE */
 
@@ -997,9 +1005,9 @@ _GLOBAL(enter_rtas)
 	li	r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
 	mtlr	r6
 	CLR_TOP32(r7)
-	mtspr	SPRG2,r7
-	mtspr	SRR0,r8
-	mtspr	SRR1,r9
+	mtspr	SPRN_SPRG2,r7
+	mtspr	SPRN_SRR0,r8
+	mtspr	SPRN_SRR1,r9
 	RFI
 1:	tophys(r9,r1)
 	lwz	r8,INT_FRAME_SIZE+4(r9)	/* get return address */
@@ -1007,9 +1015,9 @@ _GLOBAL(enter_rtas)
 	FIX_SRR1(r9,r0)
 	addi	r1,r1,INT_FRAME_SIZE
 	li	r0,0
-	mtspr	SPRG2,r0
-	mtspr	SRR0,r8
-	mtspr	SRR1,r9
+	mtspr	SPRN_SPRG2,r0
+	mtspr	SPRN_SRR0,r8
+	mtspr	SPRN_SRR1,r9
 	RFI			/* return to caller */
 
 	.globl	machine_check_in_rtas
diff --git a/arch/ppc/kernel/fpu.S b/arch/ppc/kernel/fpu.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc/kernel/fpu.S
@@ -0,0 +1,133 @@
+/*
+ *  FPU support code, moved here from head.S so that it can be used
+ *  by chips which use other head-whatever.S files.
+ *
+ *  This program is free software; you can redistribute it 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/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+/*
+ * This task wants to use the FPU now.
+ * On UP, disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Load up this task's FP registers from its thread_struct,
+ * enable the FPU for the current task and return to the task.
+ */
+	.globl	load_up_fpu
+load_up_fpu:
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+#ifdef CONFIG_PPC64BRIDGE
+	clrldi	r5,r5,1			/* turn off 64-bit mode */
+#endif /* CONFIG_PPC64BRIDGE */
+	SYNC
+	MTMSRD(r5)			/* enable use of fpu now */
+	isync
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_fpu in switch_to.
+ */
+#ifndef CONFIG_SMP
+	tophys(r6,0)			/* get __pa constant */
+	addis	r3,r6,last_task_used_math@ha
+	lwz	r4,last_task_used_math@l(r3)
+	cmpwi	0,r4,0
+	beq	1f
+	add	r4,r4,r6
+	addi	r4,r4,THREAD		/* want last_task_used_math->thread */
+	SAVE_32FPRS(0, r4)
+	mffs	fr0
+	stfd	fr0,THREAD_FPSCR-4(r4)
+	lwz	r5,PT_REGS(r4)
+	add	r5,r5,r6
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r10,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r10		/* disable FP for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+	/* enable use of FP after return */
+	mfspr	r5,SPRN_SPRG3		/* current task's THREAD (phys) */
+	lwz	r4,THREAD_FPEXC_MODE(r5)
+	ori	r9,r9,MSR_FP		/* enable FP for current */
+	or	r9,r9,r4
+	lfd	fr0,THREAD_FPSCR-4(r5)
+	mtfsf	0xff,fr0
+	REST_32FPRS(0, r5)
+#ifndef CONFIG_SMP
+	subi	r4,r5,THREAD
+	sub	r4,r4,r6
+	stw	r4,last_task_used_math@l(r3)
+#endif /* CONFIG_SMP */
+	/* restore registers and return */
+	/* we haven't used ctr or xer or lr */
+	b	fast_exception_return
+
+/*
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
+ */
+ 	.globl	KernelFP
+KernelFP:
+	lwz	r3,_MSR(r1)
+	ori	r3,r3,MSR_FP
+	stw	r3,_MSR(r1)		/* enable use of FP after return */
+	lis	r3,86f@h
+	ori	r3,r3,86f@l
+	mr	r4,r2			/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	ret_from_except
+86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
+	.align	4,0
+
+/*
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ */
+	.globl	giveup_fpu
+giveup_fpu:
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+	SYNC_601
+	ISYNC_601
+	MTMSRD(r5)			/* enable use of fpu now */
+	SYNC_601
+	isync
+	cmpwi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,THREAD	        /* want THREAD of task */
+	lwz	r5,PT_REGS(r3)
+	cmpwi	0,r5,0
+	SAVE_32FPRS(0, r3)
+	mffs	fr0
+	stfd	fr0,THREAD_FPSCR-4(r3)
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r3,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r3		/* disable FP for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+	li	r5,0
+	lis	r4,last_task_used_math@ha
+	stw	r5,last_task_used_math@l(r4)
+#endif /* CONFIG_SMP */
+	blr
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -41,12 +41,12 @@
 #define LOAD_BAT(n, reg, RA, RB)	\
 	ld	RA,(n*32)+0(reg);	\
 	ld	RB,(n*32)+8(reg);	\
-	mtspr	IBAT##n##U,RA;		\
-	mtspr	IBAT##n##L,RB;		\
+	mtspr	SPRN_IBAT##n##U,RA;	\
+	mtspr	SPRN_IBAT##n##L,RB;	\
 	ld	RA,(n*32)+16(reg);	\
 	ld	RB,(n*32)+24(reg);	\
-	mtspr	DBAT##n##U,RA;		\
-	mtspr	DBAT##n##L,RB;		\
+	mtspr	SPRN_DBAT##n##U,RA;	\
+	mtspr	SPRN_DBAT##n##L,RB;	\
 
 #else /* CONFIG_PPC64BRIDGE */
 
@@ -54,17 +54,17 @@
 #define LOAD_BAT(n, reg, RA, RB)	\
 	/* see the comment for clear_bats() -- Cort */ \
 	li	RA,0;			\
-	mtspr	IBAT##n##U,RA;		\
-	mtspr	DBAT##n##U,RA;		\
+	mtspr	SPRN_IBAT##n##U,RA;	\
+	mtspr	SPRN_DBAT##n##U,RA;	\
 	lwz	RA,(n*16)+0(reg);	\
 	lwz	RB,(n*16)+4(reg);	\
-	mtspr	IBAT##n##U,RA;		\
-	mtspr	IBAT##n##L,RB;		\
+	mtspr	SPRN_IBAT##n##U,RA;	\
+	mtspr	SPRN_IBAT##n##L,RB;	\
 	beq	1f;			\
 	lwz	RA,(n*16)+8(reg);	\
 	lwz	RB,(n*16)+12(reg);	\
-	mtspr	DBAT##n##U,RA;		\
-	mtspr	DBAT##n##L,RB;		\
+	mtspr	SPRN_DBAT##n##U,RA;	\
+	mtspr	SPRN_DBAT##n##L,RB;	\
 1:
 #endif /* CONFIG_PPC64BRIDGE */
 
@@ -224,10 +224,10 @@ __after_mmu_off:
 turn_on_mmu:
 	mfmsr	r0
 	ori	r0,r0,MSR_DR|MSR_IR
-	mtspr	SRR1,r0
+	mtspr	SPRN_SRR1,r0
 	lis	r0,start_here@h
 	ori	r0,r0,start_here@l
-	mtspr	SRR0,r0
+	mtspr	SPRN_SRR0,r0
 	SYNC
 	RFI				/* enables MMU */
 
@@ -260,18 +260,18 @@ __secondary_hold:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG	\
-	mtspr	SPRG0,r10;	\
-	mtspr	SPRG1,r11;	\
+	mtspr	SPRN_SPRG0,r10;	\
+	mtspr	SPRN_SPRG1,r11;	\
 	mfcr	r10;		\
 	EXCEPTION_PROLOG_1;	\
 	EXCEPTION_PROLOG_2
 
 #define EXCEPTION_PROLOG_1	\
-	mfspr	r11,SRR1;		/* check whether user or kernel */ \
+	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel */ \
 	andi.	r11,r11,MSR_PR;	\
 	tophys(r11,r1);			/* use tophys(r1) if kernel */ \
 	beq	1f;		\
-	mfspr	r11,SPRG3;	\
+	mfspr	r11,SPRN_SPRG3;	\
 	lwz	r11,THREAD_INFO-THREAD(r11);	\
 	addi	r11,r11,THREAD_SIZE;	\
 	tophys(r11,r11);	\
@@ -283,14 +283,14 @@ __secondary_hold:
 	stw	r10,_CCR(r11);		/* save registers */ \
 	stw	r12,GPR12(r11);	\
 	stw	r9,GPR9(r11);	\
-	mfspr	r10,SPRG0;	\
+	mfspr	r10,SPRN_SPRG0;	\
 	stw	r10,GPR10(r11);	\
-	mfspr	r12,SPRG1;	\
+	mfspr	r12,SPRN_SPRG1;	\
 	stw	r12,GPR11(r11);	\
 	mflr	r10;		\
 	stw	r10,_LINK(r11);	\
-	mfspr	r12,SRR0;	\
-	mfspr	r9,SRR1;	\
+	mfspr	r12,SPRN_SRR0;	\
+	mfspr	r9,SPRN_SRR1;	\
 	stw	r1,GPR1(r11);	\
 	stw	r1,0(r11);	\
 	tovirt(r1,r11);			/* set new kernel sp */	\
@@ -373,11 +373,11 @@ i##n:								\
  *	-- paulus.
  */
 	. = 0x200
-	mtspr	SPRG0,r10
-	mtspr	SPRG1,r11
+	mtspr	SPRN_SPRG0,r10
+	mtspr	SPRN_SPRG1,r11
 	mfcr	r10
 #ifdef CONFIG_PPC_CHRP
-	mfspr	r11,SPRG2
+	mfspr	r11,SPRN_SPRG2
 	cmpwi	0,r11,0
 	bne	7f
 #endif /* CONFIG_PPC_CHRP */
@@ -385,7 +385,7 @@ i##n:								\
 7:	EXCEPTION_PROLOG_2
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 #ifdef CONFIG_PPC_CHRP
-	mfspr	r4,SPRG2
+	mfspr	r4,SPRN_SPRG2
 	cmpwi	cr1,r4,0
 	bne	cr1,1f
 #endif
@@ -403,15 +403,15 @@ DataAccessCont:
 DataAccess:
 	EXCEPTION_PROLOG
 #endif /* CONFIG_PPC64BRIDGE */
-	mfspr	r10,DSISR
+	mfspr	r10,SPRN_DSISR
 	andis.	r0,r10,0xa470		/* weird error? */
 	bne	1f			/* if not, try to put a PTE */
-	mfspr	r4,DAR			/* into the hash table */
+	mfspr	r4,SPRN_DAR		/* into the hash table */
 	rlwinm	r3,r10,32-15,21,21	/* DSISR_STORE -> _PAGE_RW */
 	bl	hash_page
 1:	stw	r10,_DSISR(r11)
 	mr	r5,r10
-	mfspr	r4,DAR
+	mfspr	r4,SPRN_DAR
 	EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
 #ifdef CONFIG_PPC64BRIDGE
@@ -451,9 +451,9 @@ InstructionAccess:
 	. = 0x600
 Alignment:
 	EXCEPTION_PROLOG
-	mfspr	r4,DAR
+	mfspr	r4,SPRN_DAR
 	stw	r4,_DAR(r11)
-	mfspr	r5,DSISR
+	mfspr	r5,SPRN_DSISR
 	stw	r5,_DSISR(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	EXC_XFER_EE(0x600, AlignmentException)
@@ -518,16 +518,16 @@ InstructionTLBMiss:
  */
 	mfctr	r0
 	/* Get PTE (linux-style) and check access */
-	mfspr	r3,IMISS
+	mfspr	r3,SPRN_IMISS
 	lis	r1,KERNELBASE@h		/* check if kernel address */
 	cmplw	0,r3,r1
-	mfspr	r2,SPRG3
+	mfspr	r2,SPRN_SPRG3
 	li	r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
 	lwz	r2,PGDIR(r2)
 	blt+	112f
 	lis	r2,swapper_pg_dir@ha	/* if kernel address, use */
 	addi	r2,r2,swapper_pg_dir@l	/* kernel page table */
-	mfspr	r1,SRR1			/* and MSR_PR bit from SRR1 */
+	mfspr	r1,SPRN_SRR1		/* and MSR_PR bit from SRR1 */
 	rlwinm	r1,r1,32-12,29,29	/* shift MSR_PR to _PAGE_USER posn */
 112:	tophys(r2,r2)
 	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
@@ -553,26 +553,26 @@ InstructionTLBMiss:
 	ori	r1,r1,0xe14		/* clear out reserved bits and M */
 	andc	r1,r3,r1		/* PP = user? (rw&dirty? 2: 3): 0 */
 	mtspr	SPRN_RPA,r1
-	mfspr	r3,IMISS
+	mfspr	r3,SPRN_IMISS
 	tlbli	r3
-	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mfspr	r3,SPRN_SRR1		/* Need to restore CR0 */
 	mtcrf	0x80,r3
 	rfi
 InstructionAddressInvalid:
-	mfspr	r3,SRR1
+	mfspr	r3,SPRN_SRR1
 	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
 
 	addis	r1,r1,0x2000
-	mtspr	DSISR,r1	/* (shouldn't be needed) */
+	mtspr	SPRN_DSISR,r1	/* (shouldn't be needed) */
 	mtctr	r0		/* Restore CTR */
 	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
 	or	r2,r2,r1
-	mtspr	SRR1,r2
-	mfspr	r1,IMISS	/* Get failing address */
+	mtspr	SPRN_SRR1,r2
+	mfspr	r1,SPRN_IMISS	/* Get failing address */
 	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
 	rlwimi	r2,r2,1,30,30	/* change 1 -> 3 */
 	xor	r1,r1,r2
-	mtspr	DAR,r1		/* Set fault address */
+	mtspr	SPRN_DAR,r1	/* Set fault address */
 	mfmsr	r0		/* Restore "normal" registers */
 	xoris	r0,r0,MSR_TGPR>>16
 	mtcrf	0x80,r3		/* Restore CR0 */
@@ -592,16 +592,16 @@ DataLoadTLBMiss:
  */
 	mfctr	r0
 	/* Get PTE (linux-style) and check access */
-	mfspr	r3,DMISS
+	mfspr	r3,SPRN_DMISS
 	lis	r1,KERNELBASE@h		/* check if kernel address */
 	cmplw	0,r3,r1
-	mfspr	r2,SPRG3
+	mfspr	r2,SPRN_SPRG3
 	li	r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
 	lwz	r2,PGDIR(r2)
 	blt+	112f
 	lis	r2,swapper_pg_dir@ha	/* if kernel address, use */
 	addi	r2,r2,swapper_pg_dir@l	/* kernel page table */
-	mfspr	r1,SRR1			/* and MSR_PR bit from SRR1 */
+	mfspr	r1,SPRN_SRR1		/* and MSR_PR bit from SRR1 */
 	rlwinm	r1,r1,32-12,29,29	/* shift MSR_PR to _PAGE_USER posn */
 112:	tophys(r2,r2)
 	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
@@ -627,24 +627,24 @@ DataLoadTLBMiss:
 	ori	r1,r1,0xe14		/* clear out reserved bits and M */
 	andc	r1,r3,r1		/* PP = user? (rw&dirty? 2: 3): 0 */
 	mtspr	SPRN_RPA,r1
-	mfspr	r3,DMISS
+	mfspr	r3,SPRN_DMISS
 	tlbld	r3
-	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mfspr	r3,SPRN_SRR1		/* Need to restore CR0 */
 	mtcrf	0x80,r3
 	rfi
 DataAddressInvalid:
-	mfspr	r3,SRR1
+	mfspr	r3,SPRN_SRR1
 	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
 	addis	r1,r1,0x2000
-	mtspr	DSISR,r1
+	mtspr	SPRN_DSISR,r1
 	mtctr	r0		/* Restore CTR */
 	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
-	mtspr	SRR1,r2
-	mfspr	r1,DMISS	/* Get failing address */
+	mtspr	SPRN_SRR1,r2
+	mfspr	r1,SPRN_DMISS	/* Get failing address */
 	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
 	beq	20f		/* Jump if big endian */
 	xori	r1,r1,3
-20:	mtspr	DAR,r1		/* Set fault address */
+20:	mtspr	SPRN_DAR,r1	/* Set fault address */
 	mfmsr	r0		/* Restore "normal" registers */
 	xoris	r0,r0,MSR_TGPR>>16
 	mtcrf	0x80,r3		/* Restore CR0 */
@@ -664,16 +664,16 @@ DataStoreTLBMiss:
  */
 	mfctr	r0
 	/* Get PTE (linux-style) and check access */
-	mfspr	r3,DMISS
+	mfspr	r3,SPRN_DMISS
 	lis	r1,KERNELBASE@h		/* check if kernel address */
 	cmplw	0,r3,r1
-	mfspr	r2,SPRG3
+	mfspr	r2,SPRN_SPRG3
 	li	r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
 	lwz	r2,PGDIR(r2)
 	blt+	112f
 	lis	r2,swapper_pg_dir@ha	/* if kernel address, use */
 	addi	r2,r2,swapper_pg_dir@l	/* kernel page table */
-	mfspr	r1,SRR1			/* and MSR_PR bit from SRR1 */
+	mfspr	r1,SPRN_SRR1		/* and MSR_PR bit from SRR1 */
 	rlwinm	r1,r1,32-12,29,29	/* shift MSR_PR to _PAGE_USER posn */
 112:	tophys(r2,r2)
 	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
@@ -695,9 +695,9 @@ DataStoreTLBMiss:
 	li	r1,0xe15		/* clear out reserved bits and M */
 	andc	r1,r3,r1		/* PP = user? 2: 0 */
 	mtspr	SPRN_RPA,r1
-	mfspr	r3,DMISS
+	mfspr	r3,SPRN_DMISS
 	tlbld	r3
-	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mfspr	r3,SPRN_SRR1		/* Need to restore CR0 */
 	mtcrf	0x80,r3
 	rfi
 
@@ -765,7 +765,7 @@ InstructionAccess:
 DataSegment:
 	EXCEPTION_PROLOG
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	mfspr	r4,DAR
+	mfspr	r4,SPRN_DAR
 	stw	r4,_DAR(r11)
 	EXC_XFER_STD(0x380, UnknownException)
 
@@ -775,133 +775,6 @@ InstructionSegment:
 	EXC_XFER_STD(0x480, UnknownException)
 #endif /* CONFIG_PPC64BRIDGE */
 
-/*
- * This task wants to use the FPU now.
- * On UP, disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
- * Load up this task's FP registers from its thread_struct,
- * enable the FPU for the current task and return to the task.
- */
-load_up_fpu:
-	mfmsr	r5
-	ori	r5,r5,MSR_FP
-#ifdef CONFIG_PPC64BRIDGE
-	clrldi	r5,r5,1			/* turn off 64-bit mode */
-#endif /* CONFIG_PPC64BRIDGE */
-	SYNC
-	MTMSRD(r5)			/* enable use of fpu now */
-	isync
-/*
- * For SMP, we don't do lazy FPU switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another.  Instead we call giveup_fpu in switch_to.
- */
-#ifndef CONFIG_SMP
-	tophys(r6,0)			/* get __pa constant */
-	addis	r3,r6,last_task_used_math@ha
-	lwz	r4,last_task_used_math@l(r3)
-	cmpwi	0,r4,0
-	beq	1f
-	add	r4,r4,r6
-	addi	r4,r4,THREAD		/* want last_task_used_math->thread */
-	SAVE_32FPRS(0, r4)
-	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r4)
-	lwz	r5,PT_REGS(r4)
-	add	r5,r5,r6
-	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	li	r10,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r10		/* disable FP for previous task */
-	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-	/* enable use of FP after return */
-	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
-	lwz	r4,THREAD_FPEXC_MODE(r5)
-	ori	r9,r9,MSR_FP		/* enable FP for current */
-	or	r9,r9,r4
-	lfd	fr0,THREAD_FPSCR-4(r5)
-	mtfsf	0xff,fr0
-	REST_32FPRS(0, r5)
-#ifndef CONFIG_SMP
-	subi	r4,r5,THREAD
-	sub	r4,r4,r6
-	stw	r4,last_task_used_math@l(r3)
-#endif /* CONFIG_SMP */
-	/* restore registers and return */
-	/* we haven't used ctr or xer or lr */
-	/* fall through to fast_exception_return */
-
-	.globl	fast_exception_return
-fast_exception_return:
-	andi.	r10,r9,MSR_RI		/* check for recoverable interrupt */
-	beq	1f			/* if not, we've got problems */
-2:	REST_4GPRS(3, r11)
-	lwz	r10,_CCR(r11)
-	REST_GPR(1, r11)
-	mtcr	r10
-	lwz	r10,_LINK(r11)
-	mtlr	r10
-	REST_GPR(10, r11)
-	mtspr	SRR1,r9
-	mtspr	SRR0,r12
-	REST_GPR(9, r11)
-	REST_GPR(12, r11)
-	lwz	r11,GPR11(r11)
-	SYNC
-	RFI
-
-/* check if the exception happened in a restartable section */
-1:	lis	r3,exc_exit_restart_end@ha
-	addi	r3,r3,exc_exit_restart_end@l
-	cmplw	r12,r3
-	bge	3f
-	lis	r4,exc_exit_restart@ha
-	addi	r4,r4,exc_exit_restart@l
-	cmplw	r12,r4
-	blt	3f
-	lis	r3,fee_restarts@ha
-	tophys(r3,r3)
-	lwz	r5,fee_restarts@l(r3)
-	addi	r5,r5,1
-	stw	r5,fee_restarts@l(r3)
-	mr	r12,r4		/* restart at exc_exit_restart */
-	b	2b
-
-	.comm	fee_restarts,4
-
-/* aargh, a nonrecoverable interrupt, panic */
-/* aargh, we don't know which trap this is */
-/* but the 601 doesn't implement the RI bit, so assume it's OK */
-3:
-BEGIN_FTR_SECTION
-	b	2b
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-	li	r10,-1
-	stw	r10,TRAP(r11)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r10,MSR_KERNEL
-	bl	transfer_to_handler_full
-	.long	nonrecoverable_exception
-	.long	ret_from_except
-
-/*
- * FP unavailable trap from kernel - print a message, but let
- * the task use FP in the kernel until it returns to user mode.
- */
-KernelFP:
-	lwz	r3,_MSR(r1)
-	ori	r3,r3,MSR_FP
-	stw	r3,_MSR(r1)		/* enable use of FP after return */
-	lis	r3,86f@h
-	ori	r3,r3,86f@l
-	mr	r4,r2			/* current */
-	lwz	r5,_NIP(r1)
-	bl	printk
-	b	ret_from_except
-86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
-	.align	4,0
-
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
  * support.  Changes to one are likely to be applicable to the
@@ -945,7 +818,7 @@ load_up_altivec:
 #endif /* CONFIG_SMP */
 	/* enable use of AltiVec after return */
 	oris	r9,r9,MSR_VEC@h
-	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	mfspr	r5,SPRN_SPRG3		/* current task's THREAD (phys) */
 	li	r4,1
 	li	r10,THREAD_VSCR
 	stw	r4,THREAD_USED_VR(r5)
@@ -1016,42 +889,6 @@ giveup_altivec:
 #endif /* CONFIG_ALTIVEC */
 
 /*
- * giveup_fpu(tsk)
- * Disable FP for the task given as the argument,
- * and save the floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- */
-	.globl	giveup_fpu
-giveup_fpu:
-	mfmsr	r5
-	ori	r5,r5,MSR_FP
-	SYNC_601
-	ISYNC_601
-	MTMSRD(r5)			/* enable use of fpu now */
-	SYNC_601
-	isync
-	cmpwi	0,r3,0
-	beqlr-				/* if no previous owner, done */
-	addi	r3,r3,THREAD	        /* want THREAD of task */
-	lwz	r5,PT_REGS(r3)
-	cmpwi	0,r5,0
-	SAVE_32FPRS(0, r3)
-	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r3)
-	beq	1f
-	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	li	r3,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r3		/* disable FP for previous task */
-	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
-	li	r5,0
-	lis	r4,last_task_used_math@ha
-	stw	r5,last_task_used_math@l(r4)
-#endif /* CONFIG_SMP */
-	blr
-
-/*
  * This code is jumped to from the startup code to copy
  * the kernel image to physical address 0.
  */
@@ -1142,8 +979,8 @@ fix_mem_constants:
 	lis	r8,0
 #endif
 	ori	r8,r8,0x2		/* 128KB, supervisor */
-	mtspr	DBAT3U,r8
-	mtspr	DBAT3L,r8
+	mtspr	SPRN_DBAT3U,r8
+	mtspr	SPRN_DBAT3L,r8
 
 	lis	r12,__ptov_table_begin@h
 	ori	r12,r12,__ptov_table_begin@l
@@ -1179,12 +1016,12 @@ fix_mem_constants:
 #ifdef CONFIG_GEMINI
 	.globl	__secondary_start_gemini
 __secondary_start_gemini:
-        mfspr   r4,HID0
+        mfspr   r4,SPRN_HID0
         ori     r4,r4,HID0_ICFI
         li      r3,0
         ori     r3,r3,HID0_ICE
         andc    r4,r4,r3
-        mtspr   HID0,r4
+        mtspr   SPRN_HID0,r4
         sync
         bl      gemini_prom_init
         b       __secondary_start
@@ -1255,17 +1092,17 @@ __secondary_start:
 	tophys(r4,r2)
 	addi	r4,r4,THREAD	/* phys address of our thread_struct */
 	CLR_TOP32(r4)
-	mtspr	SPRG3,r4
+	mtspr	SPRN_SPRG3,r4
 	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => not in RTAS */
+	mtspr	SPRN_SPRG2,r3	/* 0 => not in RTAS */
 
 	/* enable MMU and jump to start_secondary */
 	li	r4,MSR_KERNEL
 	FIX_SRR1(r4,r5)
 	lis	r3,start_secondary@h
 	ori	r3,r3,start_secondary@l
-	mtspr	SRR0,r3
-	mtspr	SRR1,r4
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r4
 	SYNC
 	RFI
 #endif /* CONFIG_SMP */
@@ -1301,7 +1138,7 @@ load_up_mmu:
 	lis	r6,_SDR1@ha
 	tophys(r6,r6)
 	lwz	r6,_SDR1@l(r6)
-	mtspr	SDR1,r6
+	mtspr	SPRN_SDR1,r6
 #ifdef CONFIG_PPC64BRIDGE
 	/* clear the ASR so we only use the pseudo-segment registers. */
 	li	r6,0
@@ -1343,9 +1180,9 @@ start_here:
 	tophys(r4,r2)
 	addi	r4,r4,THREAD	/* init task's THREAD */
 	CLR_TOP32(r4)
-	mtspr	SPRG3,r4
+	mtspr	SPRN_SPRG3,r4
 	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => not in RTAS */
+	mtspr	SPRN_SPRG2,r3	/* 0 => not in RTAS */
 
 	/* stack */
 	lis	r1,init_thread_union@ha
@@ -1387,8 +1224,8 @@ start_here:
 	tophys(r4,r4)
 	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
 	FIX_SRR1(r3,r5)
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
 	SYNC
 	RFI
 /* Load up the kernel context */
@@ -1413,8 +1250,8 @@ start_here:
 	FIX_SRR1(r4,r5)
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-	mtspr	SRR0,r3
-	mtspr	SRR1,r4
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r4
 	SYNC
 	RFI
 
@@ -1461,28 +1298,28 @@ _GLOBAL(set_context)
  */
 clear_bats:
 	li	r10,0
-	mfspr	r9,PVR
+	mfspr	r9,SPRN_PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	r9, 1
 	beq	1f
 
-	mtspr	DBAT0U,r10
-	mtspr	DBAT0L,r10
-	mtspr	DBAT1U,r10
-	mtspr	DBAT1L,r10
-	mtspr	DBAT2U,r10
-	mtspr	DBAT2L,r10
-	mtspr	DBAT3U,r10
-	mtspr	DBAT3L,r10
+	mtspr	SPRN_DBAT0U,r10
+	mtspr	SPRN_DBAT0L,r10
+	mtspr	SPRN_DBAT1U,r10
+	mtspr	SPRN_DBAT1L,r10
+	mtspr	SPRN_DBAT2U,r10
+	mtspr	SPRN_DBAT2L,r10
+	mtspr	SPRN_DBAT3U,r10
+	mtspr	SPRN_DBAT3L,r10
 1:
-	mtspr	IBAT0U,r10
-	mtspr	IBAT0L,r10
-	mtspr	IBAT1U,r10
-	mtspr	IBAT1L,r10
-	mtspr	IBAT2U,r10
-	mtspr	IBAT2L,r10
-	mtspr	IBAT3U,r10
-	mtspr	IBAT3L,r10
+	mtspr	SPRN_IBAT0U,r10
+	mtspr	SPRN_IBAT0L,r10
+	mtspr	SPRN_IBAT1U,r10
+	mtspr	SPRN_IBAT1L,r10
+	mtspr	SPRN_IBAT2U,r10
+	mtspr	SPRN_IBAT2L,r10
+	mtspr	SPRN_IBAT3U,r10
+	mtspr	SPRN_IBAT3L,r10
 BEGIN_FTR_SECTION
 	/* Here's a tweak: at this point, CPU setup have
 	 * not been called yet, so HIGH_BAT_EN may not be
@@ -1523,8 +1360,8 @@ mmu_off:
 	andi.	r0,r3,MSR_DR|MSR_IR		/* MMU enabled? */
 	beqlr
 	andc	r3,r3,r0
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
 	sync
 	RFI
 
@@ -1537,7 +1374,7 @@ mmu_off:
 initial_bats:
 	lis	r11,KERNELBASE@h
 #ifndef CONFIG_PPC64BRIDGE
-	mfspr	r9,PVR
+	mfspr	r9,SPRN_PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	0,r9,1
 	bne	4f
@@ -1545,10 +1382,10 @@ initial_bats:
 	li	r8,0x7f			/* valid, block length = 8MB */
 	oris	r9,r11,0x800000@h	/* set up BAT reg for 2nd 8M */
 	oris	r10,r8,0x800000@h	/* set up BAT reg for 2nd 8M */
-	mtspr	IBAT0U,r11		/* N.B. 601 has valid bit in */
-	mtspr	IBAT0L,r8		/* lower BAT register */
-	mtspr	IBAT1U,r9
-	mtspr	IBAT1L,r10
+	mtspr	SPRN_IBAT0U,r11		/* N.B. 601 has valid bit in */
+	mtspr	SPRN_IBAT0L,r8		/* lower BAT register */
+	mtspr	SPRN_IBAT1U,r9
+	mtspr	SPRN_IBAT1L,r10
 	isync
 	blr
 #endif /* CONFIG_PPC64BRIDGE */
@@ -1570,10 +1407,10 @@ initial_bats:
 	clrldi	r11,r11,32
 	clrldi	r8,r8,32
 #endif /* CONFIG_PPC64BRIDGE */
-	mtspr	DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
-	mtspr	DBAT0U,r11		/* bit in upper BAT register */
-	mtspr	IBAT0L,r8
-	mtspr	IBAT0U,r11
+	mtspr	SPRN_DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
+	mtspr	SPRN_DBAT0U,r11		/* bit in upper BAT register */
+	mtspr	SPRN_IBAT0L,r8
+	mtspr	SPRN_IBAT0U,r11
 	isync
 	blr
 
@@ -1589,15 +1426,15 @@ setup_disp_bat:
 	addi	r8,r8,disp_BAT@l
 	lwz	r11,0(r8)
 	lwz	r8,4(r8)
-	mfspr	r9,PVR
+	mfspr	r9,SPRN_PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	0,r9,1
 	beq	1f
-	mtspr	DBAT3L,r8
-	mtspr	DBAT3U,r11
+	mtspr	SPRN_DBAT3L,r8
+	mtspr	SPRN_DBAT3U,r11
 	blr
-1:	mtspr	IBAT3L,r8
-	mtspr	IBAT3U,r11
+1:	mtspr	SPRN_IBAT3L,r8
+	mtspr	SPRN_IBAT3U,r11
 	blr
 
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
@@ -1612,7 +1449,7 @@ setup_disp_bat:
 initial_mm_power4:
 	addis	r14,r3,_SDR1@ha		/* get the value from _SDR1 */
 	lwz	r14,_SDR1@l(r14)	/* assume hash table below 4GB */
-	mtspr	SDR1,r14
+	mtspr	SPRN_SDR1,r14
 	slbia
 	lis	r4,0x2000		/* set pseudo-segment reg 12 */
 	ori	r5,r4,0x0ccc
@@ -1649,18 +1486,18 @@ m8260_gorom:
 	sync
 	mtmsr	r0
 	sync
-	mfspr	r11, HID0
+	mfspr	r11, SPRN_HID0
 	lis	r10, 0
 	ori	r10,r10,HID0_ICE|HID0_DCE
 	andc	r11, r11, r10
-	mtspr	HID0, r11
+	mtspr	SPRN_HID0, r11
 	isync
 	li	r5, MSR_ME|MSR_RI
 	lis	r6,2f@h
 	addis	r6,r6,-KERNELBASE@h
 	ori	r6,r6,2f@l
-	mtspr	SRR0,r6
-	mtspr	SRR1,r5
+	mtspr	SPRN_SRR0,r6
+	mtspr	SPRN_SRR1,r5
 	isync
 	sync
 	rfi
diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
--- a/arch/ppc/kernel/head_44x.S
+++ b/arch/ppc/kernel/head_44x.S
@@ -162,10 +162,10 @@ skpinv:	addi	r4,r4,1				/* Increment */
 
 	/* Force context change */
 	mfmsr	r0
-	mtspr	SRR1, r0
+	mtspr	SPRN_SRR1, r0
 	lis	r0,3f@h
 	ori	r0,r0,3f@l
-	mtspr	SRR0,r0
+	mtspr	SPRN_SRR0,r0
 	sync
 	rfi
 
@@ -238,7 +238,7 @@ skpinv:	addi	r4,r4,1				/* Increment */
 
 	/* ptr to current thread */
 	addi	r4,r2,THREAD	/* init task's THREAD */
-	mtspr	SPRG3,r4
+	mtspr	SPRN_SPRG3,r4
 
 	/* stack */
 	lis	r1,init_thread_union@h
@@ -274,8 +274,8 @@ skpinv:	addi	r4,r4,1				/* Increment */
 	ori	r4,r4,start_kernel@l
 	lis	r3,MSR_KERNEL@h
 	ori	r3,r3,MSR_KERNEL@l
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
 	rfi			/* change context and jump to start_kernel */
 
 /*
@@ -308,12 +308,12 @@ interrupt_base:
 
 	/* Data Storage Interrupt */
 	START_EXCEPTION(DataStorage)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
 	mfcr	r11
-	mtspr	SPRG7W, r11
+	mtspr	SPRN_SPRG7W, r11
 
 	/*
 	 * Check if it was a store fault, if not then bail
@@ -330,8 +330,9 @@ interrupt_base:
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r11, r10, 0x8000
-	beq	3f
+	lis	r11, TASK_SIZE@h
+	cmplw	r10, r11
+	blt+	3f
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 
@@ -342,7 +343,7 @@ interrupt_base:
 
 	/* Get the PGD for the current thread */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 
 	/* Load PID into MMUCR TID */
@@ -390,13 +391,13 @@ interrupt_base:
 
 	/* Done...restore registers and get out of here.
 	*/
-	mfspr	r11, SPRG7R
+	mfspr	r11, SPRN_SPRG7R
 	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
 
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	rfi			/* Force context change */
 
 2:
@@ -404,13 +405,13 @@ interrupt_base:
 	 * The bailout.  Restore registers to pre-exception conditions
 	 * and call the heavyweights to help us out.
 	 */
-	mfspr	r11, SPRG7R
+	mfspr	r11, SPRN_SPRG7R
 	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
 
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	data_access
 
 	/* Instruction Storage Interrupt */
@@ -426,7 +427,11 @@ interrupt_base:
 	PROGRAM_EXCEPTION
 
 	/* Floating Point Unavailable Interrupt */
+#ifdef CONFIG_PPC_FPU
+	FP_UNAVAILABLE_EXCEPTION
+#else
 	EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
+#endif
 
 	/* System Call Interrupt */
 	START_EXCEPTION(SystemCall)
@@ -449,19 +454,20 @@ interrupt_base:
 
 	/* Data TLB Error Interrupt */
 	START_EXCEPTION(DataTLBError)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
 	mfcr	r11
-	mtspr	SPRG7W, r11
+	mtspr	SPRN_SPRG7W, r11
 	mfspr	r10, SPRN_DEAR		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r11, r10, 0x8000
-	beq	3f
+	lis	r11, TASK_SIZE@h
+	cmplw	r10, r11
+	blt+	3f
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 
@@ -472,7 +478,7 @@ interrupt_base:
 
 	/* Get the PGD for the current thread */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 
 	/* Load PID into MMUCR TID */
@@ -503,12 +509,12 @@ interrupt_base:
 	/* The bailout.  Restore registers to pre-exception conditions
 	 * and call the heavyweights to help us out.
 	 */
-	mfspr	r11, SPRG7R
+	mfspr	r11, SPRN_SPRG7R
 	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	data_access
 
 	/* Instruction TLB Error Interrupt */
@@ -518,19 +524,20 @@ interrupt_base:
 	 * to a different point.
 	 */
 	START_EXCEPTION(InstructionTLBError)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
 	mfcr	r11
-	mtspr	SPRG7W, r11
-	mfspr	r10, SRR0		/* Get faulting address */
+	mtspr	SPRN_SPRG7W, r11
+	mfspr	r10, SPRN_SRR0		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r11, r10, 0x8000
-	beq	3f
+	lis	r11, TASK_SIZE@h
+	cmplw	r10, r11
+	blt+	3f
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 
@@ -541,7 +548,7 @@ interrupt_base:
 
 	/* Get the PGD for the current thread */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 
 	/* Load PID into MMUCR TID */
@@ -572,12 +579,12 @@ interrupt_base:
 	/* The bailout.  Restore registers to pre-exception conditions
 	 * and call the heavyweights to help us out.
 	 */
-	mfspr	r11, SPRG7R
+	mfspr	r11, SPRN_SPRG7R
 	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	InstructionStorage
 
 	/* Debug Interrupt */
@@ -661,12 +668,12 @@ finish_tlb_load:
 
 	/* Done...restore registers and get out of here.
 	*/
-	mfspr	r11, SPRG7R
+	mfspr	r11, SPRN_SPRG7R
 	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	rfi					/* Force context change */
 
 /*
@@ -686,8 +693,10 @@ _GLOBAL(giveup_altivec)
  *
  * The 44x core does not have an FPU.
  */
+#ifndef CONFIG_PPC_FPU
 _GLOBAL(giveup_fpu)
 	blr
+#endif
 
 /*
  * extern void abort(void)
@@ -728,78 +737,13 @@ _GLOBAL(empty_zero_page)
 _GLOBAL(swapper_pg_dir)
 	.space	8192
 
+/* Reserved 4k for the critical exception stack & 4k for the machine
+ * check stack per CPU for kernel mode exceptions */
 	.section .bss
-/* Stack for handling critical exceptions from kernel mode */
-critical_stack_bottom:
-	.space 4096
-critical_stack_top:
-	.previous
-
-/* Stack for handling machine check exceptions from kernel mode */
-mcheck_stack_bottom:
-	.space 4096
-mcheck_stack_top:
-	.previous
-
-/*
- * This area is used for temporarily saving registers during the
- * critical and machine check exception prologs. It must always
- * follow the page aligned allocations, so it starts on a page
- * boundary, ensuring that all crit_save areas are in a single
- * page.
- */
-
-/* crit_save */
-_GLOBAL(crit_save)
-	.space  4
-_GLOBAL(crit_r10)
-	.space	4
-_GLOBAL(crit_r11)
-	.space	4
-_GLOBAL(crit_sprg0)
-	.space	4
-_GLOBAL(crit_sprg1)
-	.space	4
-_GLOBAL(crit_sprg4)
-	.space	4
-_GLOBAL(crit_sprg5)
-	.space	4
-_GLOBAL(crit_sprg7)
-	.space	4
-_GLOBAL(crit_pid)
-	.space	4
-_GLOBAL(crit_srr0)
-	.space	4
-_GLOBAL(crit_srr1)
-	.space	4
-
-/* mcheck_save */
-_GLOBAL(mcheck_save)
-	.space  4
-_GLOBAL(mcheck_r10)
-	.space	4
-_GLOBAL(mcheck_r11)
-	.space	4
-_GLOBAL(mcheck_sprg0)
-	.space	4
-_GLOBAL(mcheck_sprg1)
-	.space	4
-_GLOBAL(mcheck_sprg4)
-	.space	4
-_GLOBAL(mcheck_sprg5)
-	.space	4
-_GLOBAL(mcheck_sprg7)
-	.space	4
-_GLOBAL(mcheck_pid)
-	.space	4
-_GLOBAL(mcheck_srr0)
-	.space	4
-_GLOBAL(mcheck_srr1)
-	.space	4
-_GLOBAL(mcheck_csrr0)
-	.space	4
-_GLOBAL(mcheck_csrr1)
-	.space	4
+        .align 12
+exception_stack_bottom:
+	.space	BOOKE_EXCEPTION_STACK_SIZE
+_GLOBAL(exception_stack_top)
 
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -77,10 +77,10 @@ _GLOBAL(_start)
 turn_on_mmu:
 	lis	r0,MSR_KERNEL@h
 	ori	r0,r0,MSR_KERNEL@l
-	mtspr	SRR1,r0
+	mtspr	SPRN_SRR1,r0
 	lis	r0,start_here@h
 	ori	r0,r0,start_here@l
-	mtspr	SRR0,r0
+	mtspr	SPRN_SRR0,r0
 	SYNC
 	rfi				/* enables MMU */
 	b	.			/* prevent prefetch past rfi */
@@ -95,24 +95,6 @@ _GLOBAL(crit_r10)
 	.space	4
 _GLOBAL(crit_r11)
 	.space	4
-_GLOBAL(crit_sprg0)
-	.space	4
-_GLOBAL(crit_sprg1)
-	.space	4
-_GLOBAL(crit_sprg4)
-	.space	4
-_GLOBAL(crit_sprg5)
-	.space	4
-_GLOBAL(crit_sprg6)
-	.space	4
-_GLOBAL(crit_sprg7)
-	.space	4
-_GLOBAL(crit_pid)
-	.space	4
-_GLOBAL(crit_srr0)
-	.space	4
-_GLOBAL(crit_srr1)
-	.space	4
 
 /*
  * Exception vector entry code. This code runs with address translation
@@ -130,7 +112,7 @@ _GLOBAL(crit_srr1)
 	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\
 	andi.	r11,r11,MSR_PR;						     \
 	beq	1f;							     \
-	mfspr	r1,SPRG3;		/* if from user, start at top of   */\
+	mfspr	r1,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
 	addi	r1,r1,THREAD_SIZE;					     \
 1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
@@ -138,16 +120,16 @@ _GLOBAL(crit_srr1)
 	stw	r10,_CCR(r11);          /* save various registers	   */\
 	stw	r12,GPR12(r11);						     \
 	stw	r9,GPR9(r11);						     \
-	mfspr	r10,SPRG0;						     \
+	mfspr	r10,SPRN_SPRG0;						     \
 	stw	r10,GPR10(r11);						     \
-	mfspr	r12,SPRG1;						     \
+	mfspr	r12,SPRN_SPRG1;						     \
 	stw	r12,GPR11(r11);						     \
 	mflr	r10;							     \
 	stw	r10,_LINK(r11);						     \
-	mfspr	r10,SPRG2;						     \
-	mfspr	r12,SRR0;						     \
+	mfspr	r10,SPRN_SPRG2;						     \
+	mfspr	r12,SPRN_SRR0;						     \
 	stw	r10,GPR1(r11);						     \
-	mfspr	r9,SRR1;						     \
+	mfspr	r9,SPRN_SRR1;						     \
 	stw	r10,0(r11);						     \
 	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
 	stw	r0,GPR0(r11);						     \
@@ -165,24 +147,6 @@ _GLOBAL(crit_srr1)
 #define CRITICAL_EXCEPTION_PROLOG					     \
 	stw	r10,crit_r10@l(0);	/* save two registers to work with */\
 	stw	r11,crit_r11@l(0);					     \
-	mfspr	r10,SPRG0;						     \
-	stw	r10,crit_sprg0@l(0);					     \
-	mfspr	r10,SPRG1;						     \
-	stw	r10,crit_sprg1@l(0);					     \
-	mfspr	r10,SPRG4;						     \
-	stw	r10,crit_sprg4@l(0);					     \
-	mfspr	r10,SPRG5;						     \
-	stw	r10,crit_sprg5@l(0);					     \
-	mfspr	r10,SPRG6;						     \
-	stw	r10,crit_sprg6@l(0);					     \
-	mfspr	r10,SPRG7;						     \
-	stw	r10,crit_sprg7@l(0);					     \
-	mfspr	r10,SPRN_PID;						     \
-	stw	r10,crit_pid@l(0);					     \
-	mfspr	r10,SRR0;						     \
-	stw	r10,crit_srr0@l(0);					     \
-	mfspr	r10,SRR1;						     \
-	stw	r10,crit_srr1@l(0);					     \
 	mfcr	r10;			/* save CR in r10 for now	   */\
 	mfspr	r11,SPRN_SRR3;		/* check whether user or kernel    */\
 	andi.	r11,r11,MSR_PR;						     \
@@ -190,7 +154,7 @@ _GLOBAL(crit_srr1)
 	ori	r11,r11,critical_stack_top@l;				     \
 	beq	1f;							     \
 	/* COMING FROM USER MODE */					     \
-	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	mfspr	r11,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
 	addi	r11,r11,THREAD_SIZE;					     \
 1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
@@ -204,9 +168,9 @@ _GLOBAL(crit_srr1)
 	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
 	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
 	stw	r9,_ESR(r11);		/* exception was taken		   */\
-	mfspr	r12,SRR2;						     \
+	mfspr	r12,SPRN_SRR2;						     \
 	stw	r1,GPR1(r11);						     \
-	mfspr	r9,SRR3;						     \
+	mfspr	r9,SPRN_SRR3;						     \
 	stw	r1,0(r11);						     \
 	tovirt(r1,r11);							     \
 	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
@@ -221,9 +185,6 @@ _GLOBAL(crit_srr1)
 	 * r11 saved in crit_r11 and in stack frame,
 	 *	now phys stack/exception frame pointer
 	 * r12 saved in stack frame, now saved SRR2
-	 * SPRG0,1,4,5,6,7 saved in crit_sprg0,1,4,5,6,7
-	 * PID saved in crit_pid
-	 * SRR0,1 saved in crit_srr0,1
 	 * CR saved in stack frame, CR0.EQ = !SRR3.PR
 	 * LR, DEAR, ESR in stack frame
 	 * r1 saved in stack frame, now virt stack/excframe pointer
@@ -299,8 +260,8 @@ label:
  * and exit.  Otherwise, we call heavywight functions to do the work.
  */
 	START_EXCEPTION(0x0300,	DataStorage)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
 #ifdef CONFIG_403GCX
 	stw     r12, 0(r0)
 	stw     r9, 4(r0)
@@ -309,12 +270,12 @@ label:
 	stw     r11, 8(r0)
 	stw     r12, 12(r0)
 #else
-	mtspr	SPRG4, r12
-	mtspr	SPRG5, r9
+	mtspr	SPRN_SPRG4, r12
+	mtspr	SPRN_SPRG5, r9
 	mfcr	r11
 	mfspr	r12, SPRN_PID
-	mtspr	SPRG7, r11
-	mtspr	SPRG6, r12
+	mtspr	SPRN_SPRG7, r11
+	mtspr	SPRN_SPRG6, r12
 #endif
 
 	/* First, check if it was a zone fault (which means a user
@@ -341,7 +302,7 @@ label:
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 4:
 	tophys(r11, r11)
@@ -388,15 +349,15 @@ label:
 	lwz     r9, 4(r0)
 	lwz     r12, 0(r0)
 #else
-	mfspr	r12, SPRG6
-	mfspr	r11, SPRG7
+	mfspr	r12, SPRN_SPRG6
+	mfspr	r11, SPRN_SPRG7
 	mtspr	SPRN_PID, r12
 	mtcr	r11
-	mfspr	r9, SPRG5
-	mfspr	r12, SPRG4
+	mfspr	r9, SPRN_SPRG5
+	mfspr	r12, SPRN_SPRG4
 #endif
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
 	b	.		/* prevent prefetch past rfi */
@@ -413,15 +374,15 @@ label:
 	lwz     r9, 4(r0)
 	lwz     r12, 0(r0)
 #else
-	mfspr	r12, SPRG6
-	mfspr	r11, SPRG7
+	mfspr	r12, SPRN_SPRG6
+	mfspr	r11, SPRN_SPRG7
 	mtspr	SPRN_PID, r12
 	mtcr	r11
-	mfspr	r9, SPRG5
-	mfspr	r12, SPRG4
+	mfspr	r9, SPRN_SPRG5
+	mfspr	r12, SPRN_SPRG4
 #endif
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	DataAccess
 
 /*
@@ -496,8 +457,8 @@ label:
  * load TLB entries from the page table if they exist.
  */
 	START_EXCEPTION(0x1100,	DTLBMiss)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
 #ifdef CONFIG_403GCX
 	stw     r12, 0(r0)
 	stw     r9, 4(r0)
@@ -506,12 +467,12 @@ label:
 	stw     r11, 8(r0)
 	stw     r12, 12(r0)
 #else
-	mtspr	SPRG4, r12
-	mtspr	SPRG5, r9
+	mtspr	SPRN_SPRG4, r12
+	mtspr	SPRN_SPRG5, r9
 	mfcr	r11
 	mfspr	r12, SPRN_PID
-	mtspr	SPRG7, r11
-	mtspr	SPRG6, r12
+	mtspr	SPRN_SPRG7, r11
+	mtspr	SPRN_SPRG6, r12
 #endif
 	mfspr	r10, SPRN_DEAR		/* Get faulting address */
 
@@ -529,7 +490,7 @@ label:
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 4:
 	tophys(r11, r11)
@@ -579,15 +540,15 @@ label:
 	lwz     r9, 4(r0)
 	lwz     r12, 0(r0)
 #else
-	mfspr	r12, SPRG6
-	mfspr	r11, SPRG7
+	mfspr	r12, SPRN_SPRG6
+	mfspr	r11, SPRN_SPRG7
 	mtspr	SPRN_PID, r12
 	mtcr	r11
-	mfspr	r9, SPRG5
-	mfspr	r12, SPRG4
+	mfspr	r9, SPRN_SPRG5
+	mfspr	r12, SPRN_SPRG4
 #endif
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	DataAccess
 
 /* 0x1200 - Instruction TLB Miss Exception
@@ -595,8 +556,8 @@ label:
  * registers and bailout to a different point.
  */
 	START_EXCEPTION(0x1200,	ITLBMiss)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
 #ifdef CONFIG_403GCX
 	stw     r12, 0(r0)
 	stw     r9, 4(r0)
@@ -605,14 +566,14 @@ label:
 	stw     r11, 8(r0)
 	stw     r12, 12(r0)
 #else
-	mtspr	SPRG4, r12
-	mtspr	SPRG5, r9
+	mtspr	SPRN_SPRG4, r12
+	mtspr	SPRN_SPRG5, r9
 	mfcr	r11
 	mfspr	r12, SPRN_PID
-	mtspr	SPRG7, r11
-	mtspr	SPRG6, r12
+	mtspr	SPRN_SPRG7, r11
+	mtspr	SPRN_SPRG6, r12
 #endif
-	mfspr	r10, SRR0		/* Get faulting address */
+	mfspr	r10, SPRN_SRR0		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
@@ -628,7 +589,7 @@ label:
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r11,SPRG3
+	mfspr	r11,SPRN_SPRG3
 	lwz	r11,PGDIR(r11)
 4:
 	tophys(r11, r11)
@@ -678,15 +639,15 @@ label:
 	lwz     r9, 4(r0)
 	lwz     r12, 0(r0)
 #else
-	mfspr	r12, SPRG6
-	mfspr	r11, SPRG7
+	mfspr	r12, SPRN_SPRG6
+	mfspr	r11, SPRN_SPRG7
 	mtspr	SPRN_PID, r12
 	mtcr	r11
-	mfspr	r9, SPRG5
-	mfspr	r12, SPRG4
+	mfspr	r9, SPRN_SPRG5
+	mfspr	r12, SPRN_SPRG4
 #endif
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	b	InstructionAccess
 
 	EXCEPTION(0x1300, Trap_13, UnknownException, EXC_XFER_EE)
@@ -754,8 +715,8 @@ label:
 	lwz	r0,GPR0(r11)
 	lwz	r1,GPR1(r11)
 	mtcrf	0x80,r10
-	mtspr	SRR2,r12
-	mtspr	SRR3,r9
+	mtspr	SPRN_SRR2,r12
+	mtspr	SPRN_SRR3,r9
 	lwz	r9,GPR9(r11)
 	lwz	r12,GPR12(r11)
 	lwz	r10,crit_r10@l(0)
@@ -831,15 +792,15 @@ finish_tlb_load:
 	lwz     r9, 4(r0)
 	lwz     r12, 0(r0)
 #else
-	mfspr	r12, SPRG6
-	mfspr	r11, SPRG7
+	mfspr	r12, SPRN_SPRG6
+	mfspr	r11, SPRN_SPRG7
 	mtspr	SPRN_PID, r12
 	mtcr	r11
-	mfspr	r9, SPRG5
-	mfspr	r12, SPRG4
+	mfspr	r9, SPRN_SPRG5
+	mfspr	r12, SPRN_SPRG4
 #endif
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
 	b	.		/* prevent prefetch past rfi */
@@ -863,7 +824,7 @@ start_here:
 	/* ptr to phys current thread */
 	tophys(r4,r2)
 	addi	r4,r4,THREAD	/* init task's THREAD */
-	mtspr	SPRG3,r4
+	mtspr	SPRN_SPRG3,r4
 
 	/* stack */
 	lis	r1,init_thread_union@ha
@@ -894,8 +855,8 @@ start_here:
 	tophys(r4,r4)
 	lis	r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@h
 	ori	r3,r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@l
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
 	rfi
 	b	.		/* prevent prefetch past rfi */
 
@@ -920,8 +881,8 @@ start_here:
 	ori	r4,r4,MSR_KERNEL@l
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-	mtspr	SRR0,r3
-	mtspr	SRR1,r4
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
 	b	.		/* prevent prefetch past rfi */
 
@@ -1030,10 +991,11 @@ _GLOBAL(swapper_pg_dir)
 
 /* Stack for handling critical exceptions from kernel mode */
 	.section .bss
-critical_stack_bottom:
+        .align 12
+exception_stack_bottom:
 	.space	4096
 critical_stack_top:
-	.previous
+_GLOBAL(exception_stack_top)
 
 /* This space gets a copy of optional info passed to us by the bootstrap
  * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -101,10 +101,10 @@ __start:
 turn_on_mmu:
 	mfmsr	r0
 	ori	r0,r0,MSR_DR|MSR_IR
-	mtspr	SRR1,r0
+	mtspr	SPRN_SRR1,r0
 	lis	r0,start_here@h
 	ori	r0,r0,start_here@l
-	mtspr	SRR0,r0
+	mtspr	SPRN_SRR0,r0
 	SYNC
 	rfi				/* enables MMU */
 
@@ -115,18 +115,18 @@ turn_on_mmu:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG	\
-	mtspr	SPRG0,r10;	\
-	mtspr	SPRG1,r11;	\
+	mtspr	SPRN_SPRG0,r10;	\
+	mtspr	SPRN_SPRG1,r11;	\
 	mfcr	r10;		\
 	EXCEPTION_PROLOG_1;	\
 	EXCEPTION_PROLOG_2
 
 #define EXCEPTION_PROLOG_1	\
-	mfspr	r11,SRR1;		/* check whether user or kernel */ \
+	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel */ \
 	andi.	r11,r11,MSR_PR;	\
 	tophys(r11,r1);			/* use tophys(r1) if kernel */ \
 	beq	1f;		\
-	mfspr	r11,SPRG3;	\
+	mfspr	r11,SPRN_SPRG3;	\
 	lwz	r11,THREAD_INFO-THREAD(r11);	\
 	addi	r11,r11,THREAD_SIZE;	\
 	tophys(r11,r11);	\
@@ -138,14 +138,14 @@ turn_on_mmu:
 	stw	r10,_CCR(r11);		/* save registers */ \
 	stw	r12,GPR12(r11);	\
 	stw	r9,GPR9(r11);	\
-	mfspr	r10,SPRG0;	\
+	mfspr	r10,SPRN_SPRG0;	\
 	stw	r10,GPR10(r11);	\
-	mfspr	r12,SPRG1;	\
+	mfspr	r12,SPRN_SPRG1;	\
 	stw	r12,GPR11(r11);	\
 	mflr	r10;		\
 	stw	r10,_LINK(r11);	\
-	mfspr	r12,SRR0;	\
-	mfspr	r9,SRR1;	\
+	mfspr	r12,SPRN_SRR0;	\
+	mfspr	r9,SPRN_SRR1;	\
 	stw	r1,GPR1(r11);	\
 	stw	r1,0(r11);	\
 	tovirt(r1,r11);			/* set new kernel sp */	\
@@ -209,9 +209,9 @@ i##n:								\
 	. = 0x200
 MachineCheck:
 	EXCEPTION_PROLOG
-	mfspr r4,DAR
+	mfspr r4,SPRN_DAR
 	stw r4,_DAR(r11)
-	mfspr r5,DSISR
+	mfspr r5,SPRN_DSISR
 	stw r5,_DSISR(r11)
 	addi r3,r1,STACK_FRAME_OVERHEAD
 	EXC_XFER_STD(0x200, MachineCheckException)
@@ -223,10 +223,10 @@ MachineCheck:
 	. = 0x300
 DataAccess:
 	EXCEPTION_PROLOG
-	mfspr	r10,DSISR
+	mfspr	r10,SPRN_DSISR
 	stw	r10,_DSISR(r11)
 	mr	r5,r10
-	mfspr	r4,DAR
+	mfspr	r4,SPRN_DAR
 	EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
 /* Instruction access exception.
@@ -247,9 +247,9 @@ InstructionAccess:
 	. = 0x600
 Alignment:
 	EXCEPTION_PROLOG
-	mfspr	r4,DAR
+	mfspr	r4,SPRN_DAR
 	stw	r4,_DAR(r11)
-	mfspr	r5,DSISR
+	mfspr	r5,SPRN_DSISR
 	stw	r5,_DSISR(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	EXC_XFER_EE(0x600, AlignmentException)
@@ -301,14 +301,14 @@ InstructionTLBMiss:
 	stw	r3, 8(r0)
 #endif
 	DO_8xx_CPU6(0x3f80, r3)
-	mtspr	M_TW, r10	/* Save a couple of working registers */
+	mtspr	SPRN_M_TW, r10	/* Save a couple of working registers */
 	mfcr	r10
 	stw	r10, 0(r0)
 	stw	r11, 4(r0)
-	mfspr	r10, SRR0	/* Get effective address of fault */
+	mfspr	r10, SPRN_SRR0	/* Get effective address of fault */
 	DO_8xx_CPU6(0x3780, r3)
-	mtspr	MD_EPN, r10	/* Have to use MD_EPN for walk, MI_EPN can't */
-	mfspr	r10, M_TWB	/* Get level 1 table entry address */
+	mtspr	SPRN_MD_EPN, r10	/* Have to use MD_EPN for walk, MI_EPN can't */
+	mfspr	r10, SPRN_M_TWB	/* Get level 1 table entry address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
@@ -328,10 +328,10 @@ InstructionTLBMiss:
 	 */
 	ori	r11,r11,1		/* Set valid bit */
 	DO_8xx_CPU6(0x2b80, r3)
-	mtspr	MI_TWC, r11	/* Set segment attributes */
+	mtspr	SPRN_MI_TWC, r11	/* Set segment attributes */
 	DO_8xx_CPU6(0x3b80, r3)
-	mtspr	MD_TWC, r11	/* Load pte table base address */
-	mfspr	r11, MD_TWC	/* ....and get the pte address */
+	mtspr	SPRN_MD_TWC, r11	/* Load pte table base address */
+	mfspr	r11, SPRN_MD_TWC	/* ....and get the pte address */
 	lwz	r10, 0(r11)	/* Get the pte */
 
 	ori	r10, r10, _PAGE_ACCESSED
@@ -346,9 +346,9 @@ InstructionTLBMiss:
 2:	li	r11, 0x00f0
 	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
 	DO_8xx_CPU6(0x2d80, r3)
-	mtspr	MI_RPN, r10	/* Update TLB entry */
+	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */
 
-	mfspr	r10, M_TW	/* Restore registers */
+	mfspr	r10, SPRN_M_TW	/* Restore registers */
 	lwz	r11, 0(r0)
 	mtcr	r11
 	lwz	r11, 4(r0)
@@ -363,11 +363,11 @@ DataStoreTLBMiss:
 	stw	r3, 8(r0)
 #endif
 	DO_8xx_CPU6(0x3f80, r3)
-	mtspr	M_TW, r10	/* Save a couple of working registers */
+	mtspr	SPRN_M_TW, r10	/* Save a couple of working registers */
 	mfcr	r10
 	stw	r10, 0(r0)
 	stw	r11, 4(r0)
-	mfspr	r10, M_TWB	/* Get level 1 table entry address */
+	mfspr	r10, SPRN_M_TWB	/* Get level 1 table entry address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
@@ -386,8 +386,8 @@ DataStoreTLBMiss:
 	 */
 	ori	r11, r11, 1	/* Set valid bit in physical L2 page */
 	DO_8xx_CPU6(0x3b80, r3)
-	mtspr	MD_TWC, r11	/* Load pte table base address */
-	mfspr	r10, MD_TWC	/* ....and get the pte address */
+	mtspr	SPRN_MD_TWC, r11	/* Load pte table base address */
+	mfspr	r10, SPRN_MD_TWC	/* ....and get the pte address */
 	lwz	r10, 0(r10)	/* Get the pte */
 
 	/* Insert the Guarded flag into the TWC from the Linux PTE.
@@ -398,9 +398,9 @@ DataStoreTLBMiss:
 	 */
 	rlwimi	r11, r10, 0, 27, 27
 	DO_8xx_CPU6(0x3b80, r3)
-	mtspr	MD_TWC, r11
+	mtspr	SPRN_MD_TWC, r11
 
-	mfspr	r11, MD_TWC	/* get the pte address again */
+	mfspr	r11, SPRN_MD_TWC	/* get the pte address again */
 	ori	r10, r10, _PAGE_ACCESSED
 	stw	r10, 0(r11)
 
@@ -413,9 +413,9 @@ DataStoreTLBMiss:
 2:	li	r11, 0x00f0
 	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
 	DO_8xx_CPU6(0x3d80, r3)
-	mtspr	MD_RPN, r10	/* Update TLB entry */
+	mtspr	SPRN_MD_RPN, r10	/* Update TLB entry */
 
-	mfspr	r10, M_TW	/* Restore registers */
+	mfspr	r10, SPRN_M_TW	/* Restore registers */
 	lwz	r11, 0(r0)
 	mtcr	r11
 	lwz	r11, 4(r0)
@@ -446,14 +446,14 @@ DataTLBError:
 	stw	r3, 8(r0)
 #endif
 	DO_8xx_CPU6(0x3f80, r3)
-	mtspr	M_TW, r10	/* Save a couple of working registers */
+	mtspr	SPRN_M_TW, r10	/* Save a couple of working registers */
 	mfcr	r10
 	stw	r10, 0(r0)
 	stw	r11, 4(r0)
 
 	/* First, make sure this was a store operation.
 	*/
-	mfspr	r10, DSISR
+	mfspr	r10, SPRN_DSISR
 	andis.	r11, r10, 0x0200	/* If set, indicates store op */
 	beq	2f
 
@@ -473,15 +473,15 @@ DataTLBError:
 	 * are initialized in mapin_ram().  This will avoid the problem,
 	 * assuming we only use the dcbi instruction on kernel addresses.
 	 */
-	mfspr	r10, DAR
+	mfspr	r10, SPRN_DAR
 	rlwinm	r11, r10, 0, 0, 19
 	ori	r11, r11, MD_EVALID
-	mfspr	r10, M_CASID
+	mfspr	r10, SPRN_M_CASID
 	rlwimi	r11, r10, 0, 28, 31
 	DO_8xx_CPU6(0x3780, r3)
-	mtspr	MD_EPN, r11
+	mtspr	SPRN_MD_EPN, r11
 
-	mfspr	r10, M_TWB	/* Get level 1 table entry address */
+	mfspr	r10, SPRN_M_TWB	/* Get level 1 table entry address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
@@ -500,8 +500,8 @@ DataTLBError:
 	 */
 	ori	r11, r11, 1		/* Set valid bit in physical L2 page */
 	DO_8xx_CPU6(0x3b80, r3)
-	mtspr	MD_TWC, r11		/* Load pte table base address */
-	mfspr	r11, MD_TWC		/* ....and get the pte address */
+	mtspr	SPRN_MD_TWC, r11		/* Load pte table base address */
+	mfspr	r11, SPRN_MD_TWC		/* ....and get the pte address */
 	lwz	r10, 0(r11)		/* Get the pte */
 
 	andi.	r11, r10, _PAGE_RW	/* Is it writeable? */
@@ -510,7 +510,7 @@ DataTLBError:
 	/* Update 'changed', among others.
 	*/
 	ori	r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
-	mfspr	r11, MD_TWC		/* Get pte address again */
+	mfspr	r11, SPRN_MD_TWC		/* Get pte address again */
 	stw	r10, 0(r11)		/* and update pte in table */
 
 	/* The Linux PTE won't go exactly into the MMU TLB.
@@ -522,9 +522,9 @@ DataTLBError:
 	li	r11, 0x00f0
 	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
 	DO_8xx_CPU6(0x3d80, r3)
-	mtspr	MD_RPN, r10	/* Update TLB entry */
+	mtspr	SPRN_MD_RPN, r10	/* Update TLB entry */
 
-	mfspr	r10, M_TW	/* Restore registers */
+	mfspr	r10, SPRN_M_TW	/* Restore registers */
 	lwz	r11, 0(r0)
 	mtcr	r11
 	lwz	r11, 4(r0)
@@ -533,7 +533,7 @@ DataTLBError:
 #endif
 	rfi
 2:
-	mfspr	r10, M_TW	/* Restore registers */
+	mfspr	r10, SPRN_M_TW	/* Restore registers */
 	lwz	r11, 0(r0)
 	mtcr	r11
 	lwz	r11, 4(r0)
@@ -576,9 +576,9 @@ start_here:
 	/* ptr to phys current thread */
 	tophys(r4,r2)
 	addi	r4,r4,THREAD	/* init task's THREAD */
-	mtspr	SPRG3,r4
+	mtspr	SPRN_SPRG3,r4
 	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+	mtspr	SPRN_SPRG2,r3	/* 0 => r1 has kernel sp */
 
 	/* stack */
 	lis	r1,init_thread_union@ha
@@ -619,13 +619,13 @@ start_here:
 	stw	r3, 12(r4)
 	lwz	r3, 12(r4)
 #endif
-	mtspr	M_TWB, r6
+	mtspr	SPRN_M_TWB, r6
 	lis	r4,2f@h
 	ori	r4,r4,2f@l
 	tophys(r4,r4)
 	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
 	rfi
 /* Load up the kernel context */
 2:
@@ -647,8 +647,8 @@ start_here:
 	li	r4,MSR_KERNEL
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-	mtspr	SRR0,r3
-	mtspr	SRR1,r4
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
 
 /* Set up the initial MMU state so we can do the first level of
@@ -667,7 +667,7 @@ initial_mmu:
 #else
 	li	r8, 0
 #endif
-	mtspr	MI_CTR, r8	/* Set instruction MMU control */
+	mtspr	SPRN_MI_CTR, r8	/* Set instruction MMU control */
 
 #ifdef CONFIG_PIN_TLB
 	lis	r10, (MD_RSV4I | MD_RESETVAL)@h
@@ -679,7 +679,7 @@ initial_mmu:
 #ifndef CONFIG_8xx_COPYBACK
 	oris	r10, r10, MD_WTDEF@h
 #endif
-	mtspr	MD_CTR, r10	/* Set data TLB control */
+	mtspr	SPRN_MD_CTR, r10	/* Set data TLB control */
 
 	/* Now map the lower 8 Meg into the TLBs.  For this quick hack,
 	 * we can load the instruction and data TLB registers with the
@@ -687,61 +687,61 @@ initial_mmu:
 	 */
 	lis	r8, KERNELBASE@h	/* Create vaddr for TLB */
 	ori	r8, r8, MI_EVALID	/* Mark it valid */
-	mtspr	MI_EPN, r8
-	mtspr	MD_EPN, r8
+	mtspr	SPRN_MI_EPN, r8
+	mtspr	SPRN_MD_EPN, r8
 	li	r8, MI_PS8MEG		/* Set 8M byte page */
 	ori	r8, r8, MI_SVALID	/* Make it valid */
-	mtspr	MI_TWC, r8
-	mtspr	MD_TWC, r8
+	mtspr	SPRN_MI_TWC, r8
+	mtspr	SPRN_MD_TWC, r8
 	li	r8, MI_BOOTINIT		/* Create RPN for address 0 */
-	mtspr	MI_RPN, r8		/* Store TLB entry */
-	mtspr	MD_RPN, r8
+	mtspr	SPRN_MI_RPN, r8		/* Store TLB entry */
+	mtspr	SPRN_MD_RPN, r8
 	lis	r8, MI_Kp@h		/* Set the protection mode */
-	mtspr	MI_AP, r8
-	mtspr	MD_AP, r8
+	mtspr	SPRN_MI_AP, r8
+	mtspr	SPRN_MD_AP, r8
 
 	/* Map another 8 MByte at the IMMR to get the processor
 	 * internal registers (among other things).
 	 */
 #ifdef CONFIG_PIN_TLB
 	addi	r10, r10, 0x0100
-	mtspr	MD_CTR, r10
+	mtspr	SPRN_MD_CTR, r10
 #endif
 	mfspr	r9, 638			/* Get current IMMR */
 	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */
 
 	mr	r8, r9			/* Create vaddr for TLB */
 	ori	r8, r8, MD_EVALID	/* Mark it valid */
-	mtspr	MD_EPN, r8
+	mtspr	SPRN_MD_EPN, r8
 	li	r8, MD_PS8MEG		/* Set 8M byte page */
 	ori	r8, r8, MD_SVALID	/* Make it valid */
-	mtspr	MD_TWC, r8
+	mtspr	SPRN_MD_TWC, r8
 	mr	r8, r9			/* Create paddr for TLB */
 	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
-	mtspr	MD_RPN, r8
+	mtspr	SPRN_MD_RPN, r8
 
 #ifdef CONFIG_PIN_TLB
 	/* Map two more 8M kernel data pages.
 	*/
 	addi	r10, r10, 0x0100
-	mtspr	MD_CTR, r10
+	mtspr	SPRN_MD_CTR, r10
 
 	lis	r8, KERNELBASE@h	/* Create vaddr for TLB */
 	addis	r8, r8, 0x0080		/* Add 8M */
 	ori	r8, r8, MI_EVALID	/* Mark it valid */
-	mtspr	MD_EPN, r8
+	mtspr	SPRN_MD_EPN, r8
 	li	r9, MI_PS8MEG		/* Set 8M byte page */
 	ori	r9, r9, MI_SVALID	/* Make it valid */
-	mtspr	MD_TWC, r9
+	mtspr	SPRN_MD_TWC, r9
 	li	r11, MI_BOOTINIT	/* Create RPN for address 0 */
 	addis	r11, r11, 0x0080	/* Add 8M */
-	mtspr	MD_RPN, r8
+	mtspr	SPRN_MD_RPN, r8
 
 	addis	r8, r8, 0x0080		/* Add 8M */
-	mtspr	MD_EPN, r8
-	mtspr	MD_TWC, r9
+	mtspr	SPRN_MD_EPN, r8
+	mtspr	SPRN_MD_TWC, r9
 	addis	r11, r11, 0x0080	/* Add 8M */
-	mtspr	MD_RPN, r8
+	mtspr	SPRN_MD_RPN, r8
 #endif
 
 	/* Since the cache is enabled according to the information we
@@ -749,20 +749,20 @@ initial_mmu:
 	 * We should probably check/set other modes....later.
 	 */
 	lis	r8, IDC_INVALL@h
-	mtspr	IC_CST, r8
-	mtspr	DC_CST, r8
+	mtspr	SPRN_IC_CST, r8
+	mtspr	SPRN_DC_CST, r8
 	lis	r8, IDC_ENABLE@h
-	mtspr	IC_CST, r8
+	mtspr	SPRN_IC_CST, r8
 #ifdef CONFIG_8xx_COPYBACK
-	mtspr	DC_CST, r8
+	mtspr	SPRN_DC_CST, r8
 #else
 	/* For a debug option, I left this here to easily enable
 	 * the write through cache mode
 	 */
 	lis	r8, DC_SFWT@h
-	mtspr	DC_CST, r8
+	mtspr	SPRN_DC_CST, r8
 	lis	r8, IDC_ENABLE@h
-	mtspr	DC_CST, r8
+	mtspr	SPRN_DC_CST, r8
 #endif
 	blr
 
@@ -793,15 +793,15 @@ _GLOBAL(set_context)
 	li	r7, 0x3980
 	stw	r7, 12(r6)
 	lwz	r7, 12(r6)
-        mtspr   M_TWB, r4               /* Update MMU base address */
+        mtspr   SPRN_M_TWB, r4               /* Update MMU base address */
 	li	r7, 0x3380
 	stw	r7, 12(r6)
 	lwz	r7, 12(r6)
-        mtspr   M_CASID, r3             /* Update context */
+        mtspr   SPRN_M_CASID, r3             /* Update context */
 #else
-        mtspr   M_CASID,r3		/* Update context */
+        mtspr   SPRN_M_CASID,r3		/* Update context */
 	tophys	(r4, r4)
-	mtspr	M_TWB, r4		/* and pgd */
+	mtspr	SPRN_M_TWB, r4		/* and pgd */
 #endif
 	SYNC
 	blr
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
--- a/arch/ppc/kernel/head_booke.h
+++ b/arch/ppc/kernel/head_booke.h
@@ -18,72 +18,98 @@
 	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\
 	andi.	r11,r11,MSR_PR;						     \
 	beq	1f;							     \
-	mfspr	r1,SPRG3;		/* if from user, start at top of   */\
+	mfspr	r1,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
 	addi	r1,r1,THREAD_SIZE;					     \
 1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
-	tophys(r11,r1);							     \
+	mr	r11,r1;							     \
 	stw	r10,_CCR(r11);          /* save various registers	   */\
 	stw	r12,GPR12(r11);						     \
 	stw	r9,GPR9(r11);						     \
-	mfspr	r10,SPRG0;						     \
+	mfspr	r10,SPRN_SPRG0;						     \
 	stw	r10,GPR10(r11);						     \
-	mfspr	r12,SPRG1;						     \
+	mfspr	r12,SPRN_SPRG1;						     \
 	stw	r12,GPR11(r11);						     \
 	mflr	r10;							     \
 	stw	r10,_LINK(r11);						     \
-	mfspr	r10,SPRG4R;						     \
-	mfspr	r12,SRR0;						     \
+	mfspr	r10,SPRN_SPRG4R;					     \
+	mfspr	r12,SPRN_SRR0;						     \
 	stw	r10,GPR1(r11);						     \
-	mfspr	r9,SRR1;						     \
+	mfspr	r9,SPRN_SRR1;						     \
 	stw	r10,0(r11);						     \
 	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
 	stw	r0,GPR0(r11);						     \
 	SAVE_4GPRS(3, r11);						     \
 	SAVE_2GPRS(7, r11)
 
+/* To handle the additional exception priority levels on 40x and Book-E
+ * processors we allocate a 4k stack per additional priority level. The various
+ * head_xxx.S files allocate space (exception_stack_top) for each priority's
+ * stack times the number of CPUs
+ *
+ * On 40x critical is the only additional level
+ * On 44x/e500 we have critical and machine check
+ *
+ * Additionally we reserve a SPRG for each priority level so we can free up a
+ * GPR to use as the base for indirect access to the exception stacks.  This
+ * is necessary since the MMU is always on, for Book-E parts, and the stacks
+ * are offset from KERNELBASE.
+ *
+ */
+#define BOOKE_EXCEPTION_STACK_SIZE	(8192)
+
+/* CRIT_SPRG only used in critical exception handling */
+#define CRIT_SPRG	SPRN_SPRG2
+/* MCHECK_SPRG only used in critical exception handling */
+#define MCHECK_SPRG	SPRN_SPRG6W
+
+#define MCHECK_STACK_TOP	(exception_stack_top - 4096)
+#define CRIT_STACK_TOP		(exception_stack_top)
+
+#ifdef CONFIG_SMP
+#define BOOKE_LOAD_CRIT_STACK				\
+	mfspr	r8,SPRN_PIR;				\
+	mulli	r8,r8,BOOKE_EXCEPTION_STACK_SIZE;	\
+	neg	r8,r8;					\
+	addis	r8,r8,CRIT_STACK_TOP@ha;		\
+	addi	r8,r8,CRIT_STACK_TOP@l
+#define BOOKE_LOAD_MCHECK_STACK				\
+	mfspr	r8,SPRN_PIR;				\
+	mulli	r8,r8,BOOKE_EXCEPTION_STACK_SIZE;	\
+	neg	r8,r8;					\
+	addis	r8,r8,MCHECK_STACK_TOP@ha;		\
+	addi	r8,r8,MCHECK_STACK_TOP@l
+#else
+#define BOOKE_LOAD_CRIT_STACK				\
+	lis	r8,CRIT_STACK_TOP@h;			\
+	ori	r8,r8,CRIT_STACK_TOP@l
+#define BOOKE_LOAD_MCHECK_STACK				\
+	lis	r8,MCHECK_STACK_TOP@h;			\
+	ori	r8,r8,MCHECK_STACK_TOP@l
+#endif
+
 /*
  * Exception prolog for critical exceptions.  This is a little different
  * from the normal exception prolog above since a critical exception
  * can potentially occur at any point during normal exception processing.
  * Thus we cannot use the same SPRG registers as the normal prolog above.
- * Instead we use a couple of words of memory at low physical addresses.
- * This is OK since we don't support SMP on these processors. For Book E
- * processors, we also have a reserved register (SPRG2) that is only used
- * in critical exceptions so we can free up a GPR to use as the base for
- * indirect access to the critical exception save area.  This is necessary
- * since the MMU is always on and the save area is offset from KERNELBASE.
+ * Instead we use a portion of the critical exception stack at low physical
+ * addresses.
  */
+
 #define CRITICAL_EXCEPTION_PROLOG					     \
-	mtspr	SPRG2,r8;		/* SPRG2 only used in criticals */   \
-	lis	r8,crit_save@ha;					     \
-	stw	r10,crit_r10@l(r8);					     \
-	stw	r11,crit_r11@l(r8);					     \
-	mfspr	r10,SPRG0;						     \
-	stw	r10,crit_sprg0@l(r8);					     \
-	mfspr	r10,SPRG1;						     \
-	stw	r10,crit_sprg1@l(r8);					     \
-	mfspr	r10,SPRG4R;						     \
-	stw	r10,crit_sprg4@l(r8);					     \
-	mfspr	r10,SPRG5R;						     \
-	stw	r10,crit_sprg5@l(r8);					     \
-	mfspr	r10,SPRG7R;						     \
-	stw	r10,crit_sprg7@l(r8);					     \
-	mfspr	r10,SPRN_PID;						     \
-	stw	r10,crit_pid@l(r8);					     \
-	mfspr	r10,SRR0;						     \
-	stw	r10,crit_srr0@l(r8);					     \
-	mfspr	r10,SRR1;						     \
-	stw	r10,crit_srr1@l(r8);					     \
-	mfspr	r8,SPRG2;		/* SPRG2 only used in criticals */   \
+	mtspr	CRIT_SPRG,r8;						     \
+	BOOKE_LOAD_CRIT_STACK;		/* r8 points to the crit stack */    \
+	stw	r10,GPR10-INT_FRAME_SIZE(r8);				     \
+	stw	r11,GPR11-INT_FRAME_SIZE(r8);				     \
 	mfcr	r10;			/* save CR in r10 for now	   */\
 	mfspr	r11,SPRN_CSRR1;		/* check whether user or kernel    */\
 	andi.	r11,r11,MSR_PR;						     \
-	lis	r11,critical_stack_top@h;				     \
-	ori	r11,r11,critical_stack_top@l;				     \
+	mr	r11,r8;							     \
+	mfspr	r8,CRIT_SPRG;						     \
 	beq	1f;							     \
 	/* COMING FROM USER MODE */					     \
-	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	mfspr	r11,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
 	addi	r11,r11,THREAD_SIZE;					     \
 1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
@@ -96,11 +122,11 @@
 	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
 	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
 	stw	r9,_ESR(r11);		/* exception was taken		   */\
-	mfspr	r12,CSRR0;						     \
+	mfspr	r12,SPRN_CSRR0;						     \
 	stw	r1,GPR1(r11);						     \
-	mfspr	r9,CSRR1;						     \
+	mfspr	r9,SPRN_CSRR1;						     \
 	stw	r1,0(r11);						     \
-	tovirt(r1,r11);							     \
+	mr	r1,r11;							     \
 	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
 	stw	r0,GPR0(r11);						     \
 	SAVE_4GPRS(3, r11);						     \
@@ -109,46 +135,21 @@
 /*
  * Exception prolog for machine check exceptions.  This is similar to
  * the critical exception prolog, except that machine check exceptions
- * have their own save area.  For Book E processors, we also have a
- * reserved register (SPRG6) that is only used in machine check exceptions
- * so we can free up a GPR to use as the base for indirect access to the
- * machine check exception save area.  This is necessary since the MMU
- * is always on and the save area is offset from KERNELBASE.
+ * have their stack.
  */
 #define MCHECK_EXCEPTION_PROLOG					     \
-	mtspr	SPRG6W,r8;		/* SPRG6 used in machine checks */   \
-	lis	r8,mcheck_save@ha;					     \
-	stw	r10,mcheck_r10@l(r8);					     \
-	stw	r11,mcheck_r11@l(r8);					     \
-	mfspr	r10,SPRG0;						     \
-	stw	r10,mcheck_sprg0@l(r8);					     \
-	mfspr	r10,SPRG1;						     \
-	stw	r10,mcheck_sprg1@l(r8);					     \
-	mfspr	r10,SPRG4R;						     \
-	stw	r10,mcheck_sprg4@l(r8);					     \
-	mfspr	r10,SPRG5R;						     \
-	stw	r10,mcheck_sprg5@l(r8);					     \
-	mfspr	r10,SPRG7R;						     \
-	stw	r10,mcheck_sprg7@l(r8);					     \
-	mfspr	r10,SPRN_PID;						     \
-	stw	r10,mcheck_pid@l(r8);					     \
-	mfspr	r10,SRR0;						     \
-	stw	r10,mcheck_srr0@l(r8);					     \
-	mfspr	r10,SRR1;						     \
-	stw	r10,mcheck_srr1@l(r8);					     \
-	mfspr	r10,CSRR0;						     \
-	stw	r10,mcheck_csrr0@l(r8);					     \
-	mfspr	r10,CSRR1;						     \
-	stw	r10,mcheck_csrr1@l(r8);					     \
-	mfspr	r8,SPRG6R;		/* SPRG6 used in machine checks */   \
+	mtspr	MCHECK_SPRG,r8;						     \
+	BOOKE_LOAD_MCHECK_STACK;	/* r8 points to the mcheck stack   */\
+	stw	r10,GPR10-INT_FRAME_SIZE(r8);				     \
+	stw	r11,GPR11-INT_FRAME_SIZE(r8);				     \
 	mfcr	r10;			/* save CR in r10 for now	   */\
 	mfspr	r11,SPRN_MCSRR1;	/* check whether user or kernel    */\
 	andi.	r11,r11,MSR_PR;						     \
-	lis	r11,mcheck_stack_top@h;					     \
-	ori	r11,r11,mcheck_stack_top@l;				     \
+	mr	r11,r8;							     \
+	mfspr	r8,MCHECK_SPRG;						     \
 	beq	1f;							     \
 	/* COMING FROM USER MODE */					     \
-	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	mfspr	r11,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
 	addi	r11,r11,THREAD_SIZE;					     \
 1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
@@ -161,11 +162,11 @@
 	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
 	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
 	stw	r9,_ESR(r11);		/* exception was taken		   */\
-	mfspr	r12,MCSRR0;						     \
+	mfspr	r12,SPRN_MCSRR0;					     \
 	stw	r1,GPR1(r11);						     \
-	mfspr	r9,MCSRR1;						     \
+	mfspr	r9,SPRN_MCSRR1;						     \
 	stw	r1,0(r11);						     \
-	tovirt(r1,r11);							     \
+	mr	r1,r11;							     \
 	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
 	stw	r0,GPR0(r11);						     \
 	SAVE_4GPRS(3, r11);						     \
@@ -194,8 +195,8 @@ label:
 	CRITICAL_EXCEPTION_PROLOG;				\
 	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
 	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
-			  NOCOPY, transfer_to_handler_full, \
-			  ret_from_except_full)
+			  NOCOPY, crit_transfer_to_handler, \
+			  ret_from_crit_exc)
 
 #define MCHECK_EXCEPTION(n, label, hdlr)			\
 	START_EXCEPTION(label);					\
@@ -285,15 +286,15 @@ label:
 	lwz	r0,GPR0(r11);						      \
 	lwz	r1,GPR1(r11);						      \
 	mtcrf	0x80,r10;						      \
-	mtspr	CSRR0,r12;						      \
-	mtspr	CSRR1,r9;						      \
+	mtspr	SPRN_CSRR0,r12;						      \
+	mtspr	SPRN_CSRR1,r9;						      \
 	lwz	r9,GPR9(r11);						      \
 	lwz	r12,GPR12(r11);						      \
-	mtspr	SPRG2,r8;		/* SPRG2 only used in criticals */    \
-	lis	r8,crit_save@ha;					      \
-	lwz	r10,crit_r10@l(r8);					      \
-	lwz	r11,crit_r11@l(r8);					      \
-	mfspr	r8,SPRG2;						      \
+	mtspr	CRIT_SPRG,r8;						      \
+	BOOKE_LOAD_CRIT_STACK;		/* r8 points to the crit stack */     \
+	lwz	r10,GPR10-INT_FRAME_SIZE(r8);				      \
+	lwz	r11,GPR11-INT_FRAME_SIZE(r8);				      \
+	mfspr	r8,CRIT_SPRG;						      \
 									      \
 	rfci;								      \
 	b	.;							      \
@@ -336,4 +337,11 @@ label:
 	addi    r3,r1,STACK_FRAME_OVERHEAD;				      \
 	EXC_XFER_LITE(0x0900, timer_interrupt)
 
+#define FP_UNAVAILABLE_EXCEPTION					      \
+	START_EXCEPTION(FloatingPointUnavailable)			      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	bne	load_up_fpu;		/* if from user, just load it up */   \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_EE_LITE(0x800, KernelFP)
+
 #endif /* __HEAD_BOOKE_H__ */
diff --git a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S
deleted file mode 100644
--- a/arch/ppc/kernel/head_e500.S
+++ /dev/null
@@ -1,1019 +0,0 @@
-/*
- * arch/ppc/kernel/head_e500.S
- *
- * Kernel execution entry point code.
- *
- *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
- *      Initial PowerPC version.
- *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
- *      Rewritten for PReP
- *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
- *      Low-level exception handers, MMU support, and rewrite.
- *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *      PowerPC 8xx modifications.
- *    Copyright (c) 1998-1999 TiVo, Inc.
- *      PowerPC 403GCX modifications.
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *      PowerPC 403GCX/405GP modifications.
- *    Copyright 2000 MontaVista Software Inc.
- *	PPC405 modifications
- *      PowerPC 403GCX/405GP modifications.
- * 	Author: MontaVista Software, Inc.
- *         	frank_rowand@mvista.com or source@mvista.com
- * 	   	debbie_chu@mvista.com
- *    Copyright 2002-2004 MontaVista Software, Inc.
- *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
- *    Copyright 2004 Freescale Semiconductor, Inc
- *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.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 <asm/processor.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/cputable.h>
-#include <asm/thread_info.h>
-#include <asm/ppc_asm.h>
-#include <asm/offsets.h>
-#include "head_booke.h"
-
-/* As with the other PowerPC ports, it is expected that when code
- * execution begins here, the following registers contain valid, yet
- * optional, information:
- *
- *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
- *   r4 - Starting address of the init RAM disk
- *   r5 - Ending address of the init RAM disk
- *   r6 - Start of kernel command line string (e.g. "mem=128")
- *   r7 - End of kernel command line string
- *
- */
-	.text
-_GLOBAL(_stext)
-_GLOBAL(_start)
-	/*
-	 * Reserve a word at a fixed location to store the address
-	 * of abatron_pteptrs
-	 */
-	nop
-/*
- * Save parameters we are passed
- */
-	mr	r31,r3
-	mr	r30,r4
-	mr	r29,r5
-	mr	r28,r6
-	mr	r27,r7
-	li	r24,0		/* CPU number */
-
-/* We try to not make any assumptions about how the boot loader
- * setup or used the TLBs.  We invalidate all mappings from the
- * boot loader and load a single entry in TLB1[0] to map the
- * first 16M of kernel memory.  Any boot info passed from the
- * bootloader needs to live in this first 16M.
- *
- * Requirement on bootloader:
- *  - The page we're executing in needs to reside in TLB1 and
- *    have IPROT=1.  If not an invalidate broadcast could
- *    evict the entry we're currently executing in.
- *
- *  r3 = Index of TLB1 were executing in
- *  r4 = Current MSR[IS]
- *  r5 = Index of TLB1 temp mapping
- *
- * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0]
- * if needed
- */
-
-/* 1. Find the index of the entry we're executing in */
-	bl	invstr				/* Find our address */
-invstr:	mflr	r6				/* Make it accessible */
-	mfmsr	r7
-	rlwinm	r4,r7,27,31,31			/* extract MSR[IS] */
-	mfspr	r7, SPRN_PID0
-	slwi	r7,r7,16
-	or	r7,r7,r4
-	mtspr	SPRN_MAS6,r7
-	tlbsx	0,r6				/* search MSR[IS], SPID=PID0 */
-	mfspr	r7,SPRN_MAS1
-	andis.	r7,r7,MAS1_VALID@h
-	bne	match_TLB
-	mfspr	r7,SPRN_PID1
-	slwi	r7,r7,16
-	or	r7,r7,r4
-	mtspr	SPRN_MAS6,r7
-	tlbsx	0,r6				/* search MSR[IS], SPID=PID1 */
-	mfspr	r7,SPRN_MAS1
-	andis.	r7,r7,MAS1_VALID@h
-	bne	match_TLB
-	mfspr	r7, SPRN_PID2
-	slwi	r7,r7,16
-	or	r7,r7,r4
-	mtspr	SPRN_MAS6,r7
-	tlbsx	0,r6				/* Fall through, we had to match */
-match_TLB:
-	mfspr	r7,SPRN_MAS0
-	rlwinm	r3,r7,16,20,31			/* Extract MAS0(Entry) */
-
-	mfspr	r7,SPRN_MAS1			/* Insure IPROT set */
-	oris	r7,r7,MAS1_IPROT@h
-	mtspr	SPRN_MAS1,r7
-	tlbwe
-
-/* 2. Invalidate all entries except the entry we're executing in */
-	mfspr	r9,SPRN_TLB1CFG
-	andi.	r9,r9,0xfff
-	li	r6,0				/* Set Entry counter to 0 */
-1:	lis	r7,0x1000			/* Set MAS0(TLBSEL) = 1 */
-	rlwimi	r7,r6,16,4,15			/* Setup MAS0 = TLBSEL | ESEL(r6) */
-	mtspr	SPRN_MAS0,r7
-	tlbre
-	mfspr	r7,SPRN_MAS1
-	rlwinm	r7,r7,0,2,31			/* Clear MAS1 Valid and IPROT */
-	cmpw	r3,r6
-	beq	skpinv				/* Dont update the current execution TLB */
-	mtspr	SPRN_MAS1,r7
-	tlbwe
-	isync
-skpinv:	addi	r6,r6,1				/* Increment */
-	cmpw	r6,r9				/* Are we done? */
-	bne	1b				/* If not, repeat */
-
-	/* Invalidate TLB0 */
-	li      r6,0x04
-	tlbivax 0,r6
-#ifdef CONFIG_SMP
-	tlbsync
-#endif
-	/* Invalidate TLB1 */
-	li      r6,0x0c
-	tlbivax 0,r6
-#ifdef CONFIG_SMP
-	tlbsync
-#endif
-	msync
-
-/* 3. Setup a temp mapping and jump to it */
-	andi.	r5, r3, 0x1	/* Find an entry not used and is non-zero */
-	addi	r5, r5, 0x1
-	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
-	rlwimi	r7,r3,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
-	mtspr	SPRN_MAS0,r7
-	tlbre
-
-	/* Just modify the entry ID and EPN for the temp mapping */
-	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
-	rlwimi	r7,r5,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
-	mtspr	SPRN_MAS0,r7
-	xori	r6,r4,1		/* Setup TMP mapping in the other Address space */
-	slwi	r6,r6,12
-	oris	r6,r6,(MAS1_VALID|MAS1_IPROT)@h
-	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
-	mtspr	SPRN_MAS1,r6
-	mfspr	r6,SPRN_MAS2
-	li	r7,0		/* temp EPN = 0 */
-	rlwimi	r7,r6,0,20,31
-	mtspr	SPRN_MAS2,r7
-	tlbwe
-
-	xori	r6,r4,1
-	slwi	r6,r6,5		/* setup new context with other address space */
-	bl	1f		/* Find our address */
-1:	mflr	r9
-	rlwimi	r7,r9,0,20,31
-	addi	r7,r7,24
-	mtspr	SRR0,r7
-	mtspr	SRR1,r6
-	rfi
-
-/* 4. Clear out PIDs & Search info */
-	li	r6,0
-	mtspr	SPRN_PID0,r6
-	mtspr	SPRN_PID1,r6
-	mtspr	SPRN_PID2,r6
-	mtspr	SPRN_MAS6,r6
-
-/* 5. Invalidate mapping we started in */
-	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
-	rlwimi	r7,r3,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
-	mtspr	SPRN_MAS0,r7
-	tlbre
-	li	r6,0
-	mtspr	SPRN_MAS1,r6
-	tlbwe
-	/* Invalidate TLB1 */
-	li      r9,0x0c
-	tlbivax 0,r9
-#ifdef CONFIG_SMP
-	tlbsync
-#endif
-	msync
-
-/* 6. Setup KERNELBASE mapping in TLB1[0] */
-	lis	r6,0x1000		/* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
-	mtspr	SPRN_MAS0,r6
-	lis	r6,(MAS1_VALID|MAS1_IPROT)@h
-	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l
-	mtspr	SPRN_MAS1,r6
-	li	r7,0
-	lis	r6,KERNELBASE@h
-	ori	r6,r6,KERNELBASE@l
-	rlwimi	r6,r7,0,20,31
-	mtspr	SPRN_MAS2,r6
-	li	r7,(MAS3_SX|MAS3_SW|MAS3_SR)
-	mtspr	SPRN_MAS3,r7
-	tlbwe
-
-/* 7. Jump to KERNELBASE mapping */
-	li	r7,0
-	bl	1f			/* Find our address */
-1:	mflr	r9
-	rlwimi	r6,r9,0,20,31
-	addi	r6,r6,24
-	mtspr	SRR0,r6
-	mtspr	SRR1,r7
-	rfi				/* start execution out of TLB1[0] entry */
-
-/* 8. Clear out the temp mapping */
-	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
-	rlwimi	r7,r5,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
-	mtspr	SPRN_MAS0,r7
-	tlbre
-	mtspr	SPRN_MAS1,r8
-	tlbwe
-	/* Invalidate TLB1 */
-	li      r9,0x0c
-	tlbivax 0,r9
-#ifdef CONFIG_SMP
-	tlbsync
-#endif
-	msync
-
-	/* Establish the interrupt vector offsets */
-	SET_IVOR(0,  CriticalInput);
-	SET_IVOR(1,  MachineCheck);
-	SET_IVOR(2,  DataStorage);
-	SET_IVOR(3,  InstructionStorage);
-	SET_IVOR(4,  ExternalInput);
-	SET_IVOR(5,  Alignment);
-	SET_IVOR(6,  Program);
-	SET_IVOR(7,  FloatingPointUnavailable);
-	SET_IVOR(8,  SystemCall);
-	SET_IVOR(9,  AuxillaryProcessorUnavailable);
-	SET_IVOR(10, Decrementer);
-	SET_IVOR(11, FixedIntervalTimer);
-	SET_IVOR(12, WatchdogTimer);
-	SET_IVOR(13, DataTLBError);
-	SET_IVOR(14, InstructionTLBError);
-	SET_IVOR(15, Debug);
-	SET_IVOR(32, SPEUnavailable);
-	SET_IVOR(33, SPEFloatingPointData);
-	SET_IVOR(34, SPEFloatingPointRound);
-	SET_IVOR(35, PerformanceMonitor);
-
-	/* Establish the interrupt vector base */
-	lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */
-	mtspr	SPRN_IVPR,r4
-
-	/* Setup the defaults for TLB entries */
-	li	r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
-   	mtspr	SPRN_MAS4, r2
-
-#if 0
-	/* Enable DOZE */
-	mfspr	r2,SPRN_HID0
-	oris	r2,r2,HID0_DOZE@h
-	mtspr	SPRN_HID0, r2
-#endif
-
-	/*
-	 * This is where the main kernel code starts.
-	 */
-
-	/* ptr to current */
-	lis	r2,init_task@h
-	ori	r2,r2,init_task@l
-
-	/* ptr to current thread */
-	addi	r4,r2,THREAD	/* init task's THREAD */
-	mtspr	SPRG3,r4
-
-	/* stack */
-	lis	r1,init_thread_union@h
-	ori	r1,r1,init_thread_union@l
-	li	r0,0
-	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
-
-	bl	early_init
-
-	mfspr	r3,SPRN_TLB1CFG
-	andi.	r3,r3,0xfff
-	lis	r4,num_tlbcam_entries@ha
-	stw	r3,num_tlbcam_entries@l(r4)
-/*
- * Decide what sort of machine this is and initialize the MMU.
- */
-	mr	r3,r31
-	mr	r4,r30
-	mr	r5,r29
-	mr	r6,r28
-	mr	r7,r27
-	bl	machine_init
-	bl	MMU_init
-
-	/* Setup PTE pointers for the Abatron bdiGDB */
-	lis	r6, swapper_pg_dir@h
-	ori	r6, r6, swapper_pg_dir@l
-	lis	r5, abatron_pteptrs@h
-	ori	r5, r5, abatron_pteptrs@l
-	lis	r4, KERNELBASE@h
-	ori	r4, r4, KERNELBASE@l
-	stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */
-	stw	r6, 0(r5)
-
-	/* Let's move on */
-	lis	r4,start_kernel@h
-	ori	r4,r4,start_kernel@l
-	lis	r3,MSR_KERNEL@h
-	ori	r3,r3,MSR_KERNEL@l
-	mtspr	SRR0,r4
-	mtspr	SRR1,r3
-	rfi			/* change context and jump to start_kernel */
-
-/*
- * Interrupt vector entry code
- *
- * The Book E MMUs are always on so we don't need to handle
- * interrupts in real mode as with previous PPC processors. In
- * this case we handle interrupts in the kernel virtual address
- * space.
- *
- * Interrupt vectors are dynamically placed relative to the
- * interrupt prefix as determined by the address of interrupt_base.
- * The interrupt vectors offsets are programmed using the labels
- * for each interrupt vector entry.
- *
- * Interrupt vectors must be aligned on a 16 byte boundary.
- * We align on a 32 byte cache line boundary for good measure.
- */
-
-interrupt_base:
-	/* Critical Input Interrupt */
-	CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
-
-	/* Machine Check Interrupt */
-	MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
-
-	/* Data Storage Interrupt */
-	START_EXCEPTION(DataStorage)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
-	mfcr	r11
-	mtspr	SPRG7W, r11
-
-	/*
-	 * Check if it was a store fault, if not then bail
-	 * because a user tried to access a kernel or
-	 * read-protected page.  Otherwise, get the
-	 * offending address and handle it.
-	 */
-	mfspr	r10, SPRN_ESR
-	andis.	r10, r10, ESR_ST@h
-	beq	2f
-
-	mfspr	r10, SPRN_DEAR		/* Get faulting address */
-
-	/* If we are faulting a kernel address, we have to use the
-	 * kernel page tables.
-	 */
-	lis	r11, TASK_SIZE@h
-	ori	r11, r11, TASK_SIZE@l
-	cmplw	0, r10, r11
-	bge	2f
-
-	/* Get the PGD for the current thread */
-3:
-	mfspr	r11,SPRG3
-	lwz	r11,PGDIR(r11)
-4:
-	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r11, 0(r11)		/* Get L1 entry */
-	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
-	beq	2f			/* Bail if no table */
-
-	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
-	lwz	r11, 0(r12)		/* Get Linux PTE */
-
-	/* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */
-	andi.	r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE
-	cmpwi	0, r13, _PAGE_RW|_PAGE_USER
-	bne	2f			/* Bail if not */
-
-	/* Update 'changed'. */
-	ori	r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
-	stw	r11, 0(r12)		/* Update Linux page table */
-
-	/* MAS2 not updated as the entry does exist in the tlb, this
-	   fault taken to detect state transition (eg: COW -> DIRTY)
-	 */
-	lis	r12, MAS3_RPN@h
-	ori	r12, r12, _PAGE_HWEXEC | MAS3_RPN@l
-	and	r11, r11, r12
-	rlwimi	r11, r11, 31, 27, 27	/* SX <- _PAGE_HWEXEC */
-	ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
-
-	/* update search PID in MAS6, AS = 0 */
-	mfspr	r12, SPRN_PID0
-	slwi	r12, r12, 16
-	mtspr	SPRN_MAS6, r12
-
-	/* find the TLB index that caused the fault.  It has to be here. */
-	tlbsx	0, r10
-
-	mtspr	SPRN_MAS3,r11
-	tlbwe
-
-	/* Done...restore registers and get out of here.  */
-	mfspr	r11, SPRG7R
-	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
-	rfi			/* Force context change */
-
-2:
-	/*
-	 * The bailout.  Restore registers to pre-exception conditions
-	 * and call the heavyweights to help us out.
-	 */
-	mfspr	r11, SPRG7R
-	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
-	b	data_access
-
-	/* Instruction Storage Interrupt */
-	INSTRUCTION_STORAGE_EXCEPTION
-
-	/* External Input Interrupt */
-	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
-
-	/* Alignment Interrupt */
-	ALIGNMENT_EXCEPTION
-
-	/* Program Interrupt */
-	PROGRAM_EXCEPTION
-
-	/* Floating Point Unavailable Interrupt */
-	EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
-
-	/* System Call Interrupt */
-	START_EXCEPTION(SystemCall)
-	NORMAL_EXCEPTION_PROLOG
-	EXC_XFER_EE_LITE(0x0c00, DoSyscall)
-
-	/* Auxillary Processor Unavailable Interrupt */
-	EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE)
-
-	/* Decrementer Interrupt */
-	DECREMENTER_EXCEPTION
-
-	/* Fixed Internal Timer Interrupt */
-	/* TODO: Add FIT support */
-	EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
-
-	/* Watchdog Timer Interrupt */
-	/* TODO: Add watchdog support */
-	CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
-
-	/* Data TLB Error Interrupt */
-	START_EXCEPTION(DataTLBError)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
-	mfcr	r11
-	mtspr	SPRG7W, r11
-	mfspr	r10, SPRN_DEAR		/* Get faulting address */
-
-	/* If we are faulting a kernel address, we have to use the
-	 * kernel page tables.
-	 */
-	lis	r11, TASK_SIZE@h
-	ori	r11, r11, TASK_SIZE@l
-	cmplw	5, r10, r11
-	blt	5, 3f
-	lis	r11, swapper_pg_dir@h
-	ori	r11, r11, swapper_pg_dir@l
-
-	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
-	rlwinm	r12,r12,0,16,1
-	mtspr	SPRN_MAS1,r12
-
-	b	4f
-
-	/* Get the PGD for the current thread */
-3:
-	mfspr	r11,SPRG3
-	lwz	r11,PGDIR(r11)
-
-4:
-	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r11, 0(r11)		/* Get L1 entry */
-	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
-	beq	2f			/* Bail if no table */
-
-	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
-	lwz	r11, 0(r12)		/* Get Linux PTE */
-	andi.	r13, r11, _PAGE_PRESENT
-	beq	2f
-
-	ori	r11, r11, _PAGE_ACCESSED
-	stw	r11, 0(r12)
-
-	 /* Jump to common tlb load */
-	b	finish_tlb_load
-2:
-	/* The bailout.  Restore registers to pre-exception conditions
-	 * and call the heavyweights to help us out.
-	 */
-	mfspr	r11, SPRG7R
-	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
-	b	data_access
-
-	/* Instruction TLB Error Interrupt */
-	/*
-	 * Nearly the same as above, except we get our
-	 * information from different registers and bailout
-	 * to a different point.
-	 */
-	START_EXCEPTION(InstructionTLBError)
-	mtspr	SPRG0, r10		/* Save some working registers */
-	mtspr	SPRG1, r11
-	mtspr	SPRG4W, r12
-	mtspr	SPRG5W, r13
-	mfcr	r11
-	mtspr	SPRG7W, r11
-	mfspr	r10, SRR0		/* Get faulting address */
-
-	/* If we are faulting a kernel address, we have to use the
-	 * kernel page tables.
-	 */
-	lis	r11, TASK_SIZE@h
-	ori	r11, r11, TASK_SIZE@l
-	cmplw	5, r10, r11
-	blt	5, 3f
-	lis	r11, swapper_pg_dir@h
-	ori	r11, r11, swapper_pg_dir@l
-
-	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
-	rlwinm	r12,r12,0,16,1
-	mtspr	SPRN_MAS1,r12
-
-	b	4f
-
-	/* Get the PGD for the current thread */
-3:
-	mfspr	r11,SPRG3
-	lwz	r11,PGDIR(r11)
-
-4:
-	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r11, 0(r11)		/* Get L1 entry */
-	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
-	beq	2f			/* Bail if no table */
-
-	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
-	lwz	r11, 0(r12)		/* Get Linux PTE */
-	andi.	r13, r11, _PAGE_PRESENT
-	beq	2f
-
-	ori	r11, r11, _PAGE_ACCESSED
-	stw	r11, 0(r12)
-
-	/* Jump to common TLB load point */
-	b	finish_tlb_load
-
-2:
-	/* The bailout.  Restore registers to pre-exception conditions
-	 * and call the heavyweights to help us out.
-	 */
-	mfspr	r11, SPRG7R
-	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
-	b	InstructionStorage
-
-#ifdef CONFIG_SPE
-	/* SPE Unavailable */
-	START_EXCEPTION(SPEUnavailable)
-	NORMAL_EXCEPTION_PROLOG
-	bne	load_up_spe
-	addi    r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_EE_LITE(0x2010, KernelSPE)
-#else
-	EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE)
-#endif /* CONFIG_SPE */
-
-	/* SPE Floating Point Data */
-#ifdef CONFIG_SPE
-	EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
-#else
-	EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE)
-#endif /* CONFIG_SPE */
-
-	/* SPE Floating Point Round */
-	EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE)
-
-	/* Performance Monitor */
-	EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD)
-
-
-	/* Debug Interrupt */
-	DEBUG_EXCEPTION
-
-/*
- * Local functions
- */
-	/*
-	 * Data TLB exceptions will bail out to this point
-	 * if they can't resolve the lightweight TLB fault.
-	 */
-data_access:
-	NORMAL_EXCEPTION_PROLOG
-	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
-	stw	r5,_ESR(r11)
-	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
-	andis.	r10,r5,(ESR_ILK|ESR_DLK)@h
-	bne	1f
-	EXC_XFER_EE_LITE(0x0300, handle_page_fault)
-1:
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_EE_LITE(0x0300, CacheLockingException)
-
-/*
-
- * Both the instruction and data TLB miss get to this
- * point to load the TLB.
- * 	r10 - EA of fault
- * 	r11 - TLB (info from Linux PTE)
- * 	r12, r13 - available to use
- * 	CR5 - results of addr < TASK_SIZE
- *	MAS0, MAS1 - loaded with proper value when we get here
- *	MAS2, MAS3 - will need additional info from Linux PTE
- *	Upon exit, we reload everything and RFI.
- */
-finish_tlb_load:
-	/*
-	 * We set execute, because we don't have the granularity to
-	 * properly set this at the page level (Linux problem).
-	 * Many of these bits are software only.  Bits we don't set
-	 * here we (properly should) assume have the appropriate value.
-	 */
-
-	mfspr	r12, SPRN_MAS2
-	rlwimi	r12, r11, 26, 27, 31	/* extract WIMGE from pte */
-	mtspr	SPRN_MAS2, r12
-
-	bge	5, 1f
-
-	/* addr > TASK_SIZE */
-	li	r10, (MAS3_UX | MAS3_UW | MAS3_UR)
-	andi.	r13, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC)
-	andi.	r12, r11, _PAGE_USER	/* Test for _PAGE_USER */
-	iseleq	r12, 0, r10
-	and	r10, r12, r13
-	srwi	r12, r10, 1
-	or	r12, r12, r10	/* Copy user perms into supervisor */
-	b	2f
-
-	/* addr <= TASK_SIZE */
-1:	rlwinm	r12, r11, 31, 29, 29	/* Extract _PAGE_HWWRITE into SW */
-	ori	r12, r12, (MAS3_SX | MAS3_SR)
-
-2:	rlwimi	r11, r12, 0, 20, 31	/* Extract RPN from PTE and merge with perms */
-	mtspr	SPRN_MAS3, r11
-	tlbwe
-
-	/* Done...restore registers and get out of here.  */
-	mfspr	r11, SPRG7R
-	mtcr	r11
-	mfspr	r13, SPRG5R
-	mfspr	r12, SPRG4R
-	mfspr	r11, SPRG1
-	mfspr	r10, SPRG0
-	rfi					/* Force context change */
-
-#ifdef CONFIG_SPE
-/* Note that the SPE support is closely modeled after the AltiVec
- * support.  Changes to one are likely to be applicable to the
- * other!  */
-load_up_spe:
-/*
- * Disable SPE for the task which had SPE previously,
- * and save its SPE registers in its thread_struct.
- * Enables SPE for use in the kernel on return.
- * On SMP we know the SPE units are free, since we give it up every
- * switch.  -- Kumar
- */
-	mfmsr	r5
-	oris	r5,r5,MSR_SPE@h
-	mtmsr	r5			/* enable use of SPE now */
-	isync
-/*
- * For SMP, we don't do lazy SPE switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another.  Instead we call giveup_spe in switch_to.
- */
-#ifndef CONFIG_SMP
-	lis	r3,last_task_used_spe@ha
-	lwz	r4,last_task_used_spe@l(r3)
-	cmpi	0,r4,0
-	beq	1f
-	addi	r4,r4,THREAD	/* want THREAD of last_task_used_spe */
-	SAVE_32EVR(0,r10,r4)
-   	evxor	evr10, evr10, evr10	/* clear out evr10 */
-	evmwumiaa evr10, evr10, evr10	/* evr10 <- ACC = 0 * 0 + ACC */
-	li	r5,THREAD_ACC
-   	evstddx	evr10, r4, r5		/* save off accumulator */
-	lwz	r5,PT_REGS(r4)
-	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	lis	r10,MSR_SPE@h
-	andc	r4,r4,r10	/* disable SPE for previous task */
-	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-	/* enable use of SPE after return */
-	oris	r9,r9,MSR_SPE@h
-	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
-	li	r4,1
-	li	r10,THREAD_ACC
-	stw	r4,THREAD_USED_SPE(r5)
-	evlddx	evr4,r10,r5
-	evmra	evr4,evr4
-	REST_32EVR(0,r10,r5)
-#ifndef CONFIG_SMP
-	subi	r4,r5,THREAD
-	stw	r4,last_task_used_spe@l(r3)
-#endif /* CONFIG_SMP */
-	/* restore registers and return */
-2:	REST_4GPRS(3, r11)
-	lwz	r10,_CCR(r11)
-	REST_GPR(1, r11)
-	mtcr	r10
-	lwz	r10,_LINK(r11)
-	mtlr	r10
-	REST_GPR(10, r11)
-	mtspr	SRR1,r9
-	mtspr	SRR0,r12
-	REST_GPR(9, r11)
-	REST_GPR(12, r11)
-	lwz	r11,GPR11(r11)
-	SYNC
-	rfi
-
-
-
-/*
- * SPE unavailable trap from kernel - print a message, but let
- * the task use SPE in the kernel until it returns to user mode.
- */
-KernelSPE:
-	lwz	r3,_MSR(r1)
-	oris	r3,r3,MSR_SPE@h
-	stw	r3,_MSR(r1)	/* enable use of SPE after return */
-	lis	r3,87f@h
-	ori	r3,r3,87f@l
-	mr	r4,r2		/* current */
-	lwz	r5,_NIP(r1)
-	bl	printk
-	b	ret_from_except
-87:	.string	"SPE used in kernel  (task=%p, pc=%x)  \n"
-	.align	4,0
-
-#endif /* CONFIG_SPE */
-
-/*
- * Global functions
- */
-
-/*
- * extern void loadcam_entry(unsigned int index)
- *
- * Load TLBCAM[index] entry in to the L2 CAM MMU
- */
-_GLOBAL(loadcam_entry)
-	lis	r4,TLBCAM@ha
-	addi	r4,r4,TLBCAM@l
-	mulli	r5,r3,20
-	add	r3,r5,r4
-	lwz	r4,0(r3)
-	mtspr	SPRN_MAS0,r4
-	lwz	r4,4(r3)
-	mtspr	SPRN_MAS1,r4
-	lwz	r4,8(r3)
-	mtspr	SPRN_MAS2,r4
-	lwz	r4,12(r3)
-	mtspr	SPRN_MAS3,r4
-	tlbwe
-	isync
-	blr
-
-/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The e500 core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
-	blr
-
-#ifdef CONFIG_SPE
-/*
- * extern void giveup_spe(struct task_struct *prev)
- *
- */
-_GLOBAL(giveup_spe)
-	mfmsr	r5
-	oris	r5,r5,MSR_SPE@h
-	SYNC
-	mtmsr	r5			/* enable use of SPE now */
-	isync
-	cmpi	0,r3,0
-	beqlr-				/* if no previous owner, done */
-	addi	r3,r3,THREAD		/* want THREAD of task */
-	lwz	r5,PT_REGS(r3)
-	cmpi	0,r5,0
-	SAVE_32EVR(0, r4, r3)
-   	evxor	evr6, evr6, evr6	/* clear out evr6 */
-	evmwumiaa evr6, evr6, evr6	/* evr6 <- ACC = 0 * 0 + ACC */
-	li	r4,THREAD_ACC
-   	evstddx	evr6, r4, r3		/* save off accumulator */
-	mfspr	r6,SPRN_SPEFSCR
-	stw	r6,THREAD_SPEFSCR(r3)	/* save spefscr register value */
-	beq	1f
-	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	lis	r3,MSR_SPE@h
-	andc	r4,r4,r3		/* disable SPE for previous task */
-	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
-	li	r5,0
-	lis	r4,last_task_used_spe@ha
-	stw	r5,last_task_used_spe@l(r4)
-#endif /* CONFIG_SMP */
-	blr
-#endif /* CONFIG_SPE */
-
-/*
- * extern void giveup_fpu(struct task_struct *prev)
- *
- * The e500 core does not have an FPU.
- */
-_GLOBAL(giveup_fpu)
-	blr
-
-/*
- * extern void abort(void)
- *
- * At present, this routine just applies a system reset.
- */
-_GLOBAL(abort)
-	li	r13,0
-        mtspr   SPRN_DBCR0,r13		/* disable all debug events */
-	mfmsr	r13
-	ori	r13,r13,MSR_DE@l	/* Enable Debug Events */
-	mtmsr	r13
-        mfspr   r13,SPRN_DBCR0
-        lis	r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
-        mtspr   SPRN_DBCR0,r13
-
-_GLOBAL(set_context)
-
-#ifdef CONFIG_BDI_SWITCH
-	/* Context switch the PTE pointer for the Abatron BDI2000.
-	 * The PGDIR is the second parameter.
-	 */
-	lis	r5, abatron_pteptrs@h
-	ori	r5, r5, abatron_pteptrs@l
-	stw	r4, 0x4(r5)
-#endif
-	mtspr	SPRN_PID,r3
-	isync			/* Force context change */
-	blr
-
-/*
- * We put a few things here that have to be page-aligned. This stuff
- * goes at the beginning of the data segment, which is page-aligned.
- */
-	.data
-_GLOBAL(sdata)
-_GLOBAL(empty_zero_page)
-	.space	4096
-_GLOBAL(swapper_pg_dir)
-	.space	4096
-
-	.section .bss
-/* Stack for handling critical exceptions from kernel mode */
-critical_stack_bottom:
-	.space 4096
-critical_stack_top:
-	.previous
-
-/* Stack for handling machine check exceptions from kernel mode */
-mcheck_stack_bottom:
-	.space 4096
-mcheck_stack_top:
-	.previous
-
-/*
- * This area is used for temporarily saving registers during the
- * critical and machine check exception prologs. It must always
- * follow the page aligned allocations, so it starts on a page
- * boundary, ensuring that all crit_save areas are in a single
- * page.
- */
-
-/* crit_save */
-_GLOBAL(crit_save)
-	.space  4
-_GLOBAL(crit_r10)
-	.space	4
-_GLOBAL(crit_r11)
-	.space	4
-_GLOBAL(crit_sprg0)
-	.space	4
-_GLOBAL(crit_sprg1)
-	.space	4
-_GLOBAL(crit_sprg4)
-	.space	4
-_GLOBAL(crit_sprg5)
-	.space	4
-_GLOBAL(crit_sprg7)
-	.space	4
-_GLOBAL(crit_pid)
-	.space	4
-_GLOBAL(crit_srr0)
-	.space	4
-_GLOBAL(crit_srr1)
-	.space	4
-
-/* mcheck_save */
-_GLOBAL(mcheck_save)
-	.space  4
-_GLOBAL(mcheck_r10)
-	.space	4
-_GLOBAL(mcheck_r11)
-	.space	4
-_GLOBAL(mcheck_sprg0)
-	.space	4
-_GLOBAL(mcheck_sprg1)
-	.space	4
-_GLOBAL(mcheck_sprg4)
-	.space	4
-_GLOBAL(mcheck_sprg5)
-	.space	4
-_GLOBAL(mcheck_sprg7)
-	.space	4
-_GLOBAL(mcheck_pid)
-	.space	4
-_GLOBAL(mcheck_srr0)
-	.space	4
-_GLOBAL(mcheck_srr1)
-	.space	4
-_GLOBAL(mcheck_csrr0)
-	.space	4
-_GLOBAL(mcheck_csrr1)
-	.space	4
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
-_GLOBAL(cmd_line)
-	.space	512
-
-/*
- * Room for two PTE pointers, usually the kernel and current user pointers
- * to their respective root page table.
- */
-abatron_pteptrs:
-	.space	8
-
-
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -0,0 +1,1004 @@
+/*
+ * arch/ppc/kernel/head_fsl_booke.S
+ *
+ * Kernel execution entry point code.
+ *
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *    Copyright 2002-2004 MontaVista Software, Inc.
+ *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
+ *    Copyright 2004 Freescale Semiconductor, Inc
+ *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.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/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include "head_booke.h"
+
+/* As with the other PowerPC ports, it is expected that when code
+ * execution begins here, the following registers contain valid, yet
+ * optional, information:
+ *
+ *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
+ *   r4 - Starting address of the init RAM disk
+ *   r5 - Ending address of the init RAM disk
+ *   r6 - Start of kernel command line string (e.g. "mem=128")
+ *   r7 - End of kernel command line string
+ *
+ */
+	.text
+_GLOBAL(_stext)
+_GLOBAL(_start)
+	/*
+	 * Reserve a word at a fixed location to store the address
+	 * of abatron_pteptrs
+	 */
+	nop
+/*
+ * Save parameters we are passed
+ */
+	mr	r31,r3
+	mr	r30,r4
+	mr	r29,r5
+	mr	r28,r6
+	mr	r27,r7
+	li	r24,0		/* CPU number */
+
+/* We try to not make any assumptions about how the boot loader
+ * setup or used the TLBs.  We invalidate all mappings from the
+ * boot loader and load a single entry in TLB1[0] to map the
+ * first 16M of kernel memory.  Any boot info passed from the
+ * bootloader needs to live in this first 16M.
+ *
+ * Requirement on bootloader:
+ *  - The page we're executing in needs to reside in TLB1 and
+ *    have IPROT=1.  If not an invalidate broadcast could
+ *    evict the entry we're currently executing in.
+ *
+ *  r3 = Index of TLB1 were executing in
+ *  r4 = Current MSR[IS]
+ *  r5 = Index of TLB1 temp mapping
+ *
+ * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0]
+ * if needed
+ */
+
+/* 1. Find the index of the entry we're executing in */
+	bl	invstr				/* Find our address */
+invstr:	mflr	r6				/* Make it accessible */
+	mfmsr	r7
+	rlwinm	r4,r7,27,31,31			/* extract MSR[IS] */
+	mfspr	r7, SPRN_PID0
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* search MSR[IS], SPID=PID0 */
+	mfspr	r7,SPRN_MAS1
+	andis.	r7,r7,MAS1_VALID@h
+	bne	match_TLB
+	mfspr	r7,SPRN_PID1
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* search MSR[IS], SPID=PID1 */
+	mfspr	r7,SPRN_MAS1
+	andis.	r7,r7,MAS1_VALID@h
+	bne	match_TLB
+	mfspr	r7, SPRN_PID2
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* Fall through, we had to match */
+match_TLB:
+	mfspr	r7,SPRN_MAS0
+	rlwinm	r3,r7,16,20,31			/* Extract MAS0(Entry) */
+
+	mfspr	r7,SPRN_MAS1			/* Insure IPROT set */
+	oris	r7,r7,MAS1_IPROT@h
+	mtspr	SPRN_MAS1,r7
+	tlbwe
+
+/* 2. Invalidate all entries except the entry we're executing in */
+	mfspr	r9,SPRN_TLB1CFG
+	andi.	r9,r9,0xfff
+	li	r6,0				/* Set Entry counter to 0 */
+1:	lis	r7,0x1000			/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r6,16,4,15			/* Setup MAS0 = TLBSEL | ESEL(r6) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	mfspr	r7,SPRN_MAS1
+	rlwinm	r7,r7,0,2,31			/* Clear MAS1 Valid and IPROT */
+	cmpw	r3,r6
+	beq	skpinv				/* Dont update the current execution TLB */
+	mtspr	SPRN_MAS1,r7
+	tlbwe
+	isync
+skpinv:	addi	r6,r6,1				/* Increment */
+	cmpw	r6,r9				/* Are we done? */
+	bne	1b				/* If not, repeat */
+
+	/* Invalidate TLB0 */
+	li      r6,0x04
+	tlbivax 0,r6
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	/* Invalidate TLB1 */
+	li      r6,0x0c
+	tlbivax 0,r6
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+/* 3. Setup a temp mapping and jump to it */
+	andi.	r5, r3, 0x1	/* Find an entry not used and is non-zero */
+	addi	r5, r5, 0x1
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r3,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+
+	/* Just modify the entry ID and EPN for the temp mapping */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r5,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
+	mtspr	SPRN_MAS0,r7
+	xori	r6,r4,1		/* Setup TMP mapping in the other Address space */
+	slwi	r6,r6,12
+	oris	r6,r6,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+	mtspr	SPRN_MAS1,r6
+	mfspr	r6,SPRN_MAS2
+	li	r7,0		/* temp EPN = 0 */
+	rlwimi	r7,r6,0,20,31
+	mtspr	SPRN_MAS2,r7
+	tlbwe
+
+	xori	r6,r4,1
+	slwi	r6,r6,5		/* setup new context with other address space */
+	bl	1f		/* Find our address */
+1:	mflr	r9
+	rlwimi	r7,r9,0,20,31
+	addi	r7,r7,24
+	mtspr	SPRN_SRR0,r7
+	mtspr	SPRN_SRR1,r6
+	rfi
+
+/* 4. Clear out PIDs & Search info */
+	li	r6,0
+	mtspr	SPRN_PID0,r6
+	mtspr	SPRN_PID1,r6
+	mtspr	SPRN_PID2,r6
+	mtspr	SPRN_MAS6,r6
+
+/* 5. Invalidate mapping we started in */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r3,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	li	r6,0
+	mtspr	SPRN_MAS1,r6
+	tlbwe
+	/* Invalidate TLB1 */
+	li      r9,0x0c
+	tlbivax 0,r9
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+/* 6. Setup KERNELBASE mapping in TLB1[0] */
+	lis	r6,0x1000		/* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
+	mtspr	SPRN_MAS0,r6
+	lis	r6,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l
+	mtspr	SPRN_MAS1,r6
+	li	r7,0
+	lis	r6,KERNELBASE@h
+	ori	r6,r6,KERNELBASE@l
+	rlwimi	r6,r7,0,20,31
+	mtspr	SPRN_MAS2,r6
+	li	r7,(MAS3_SX|MAS3_SW|MAS3_SR)
+	mtspr	SPRN_MAS3,r7
+	tlbwe
+
+/* 7. Jump to KERNELBASE mapping */
+	lis	r7,MSR_KERNEL@h
+	ori	r7,r7,MSR_KERNEL@l
+	bl	1f			/* Find our address */
+1:	mflr	r9
+	rlwimi	r6,r9,0,20,31
+	addi	r6,r6,24
+	mtspr	SPRN_SRR0,r6
+	mtspr	SPRN_SRR1,r7
+	rfi				/* start execution out of TLB1[0] entry */
+
+/* 8. Clear out the temp mapping */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r5,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	mtspr	SPRN_MAS1,r8
+	tlbwe
+	/* Invalidate TLB1 */
+	li      r9,0x0c
+	tlbivax 0,r9
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+	/* Establish the interrupt vector offsets */
+	SET_IVOR(0,  CriticalInput);
+	SET_IVOR(1,  MachineCheck);
+	SET_IVOR(2,  DataStorage);
+	SET_IVOR(3,  InstructionStorage);
+	SET_IVOR(4,  ExternalInput);
+	SET_IVOR(5,  Alignment);
+	SET_IVOR(6,  Program);
+	SET_IVOR(7,  FloatingPointUnavailable);
+	SET_IVOR(8,  SystemCall);
+	SET_IVOR(9,  AuxillaryProcessorUnavailable);
+	SET_IVOR(10, Decrementer);
+	SET_IVOR(11, FixedIntervalTimer);
+	SET_IVOR(12, WatchdogTimer);
+	SET_IVOR(13, DataTLBError);
+	SET_IVOR(14, InstructionTLBError);
+	SET_IVOR(15, Debug);
+	SET_IVOR(32, SPEUnavailable);
+	SET_IVOR(33, SPEFloatingPointData);
+	SET_IVOR(34, SPEFloatingPointRound);
+	SET_IVOR(35, PerformanceMonitor);
+
+	/* Establish the interrupt vector base */
+	lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */
+	mtspr	SPRN_IVPR,r4
+
+	/* Setup the defaults for TLB entries */
+	li	r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+   	mtspr	SPRN_MAS4, r2
+
+#if 0
+	/* Enable DOZE */
+	mfspr	r2,SPRN_HID0
+	oris	r2,r2,HID0_DOZE@h
+	mtspr	SPRN_HID0, r2
+#endif
+
+#if !defined(CONFIG_BDI_SWITCH)
+	/*
+	 * The Abatron BDI JTAG debugger does not tolerate others
+	 * mucking with the debug registers.
+	 */
+	lis	r2,DBCR0_IDM@h
+	mtspr	SPRN_DBCR0,r2
+	/* clear any residual debug events */
+	li	r2,-1
+	mtspr	SPRN_DBSR,r2
+#endif
+
+	/*
+	 * This is where the main kernel code starts.
+	 */
+
+	/* ptr to current */
+	lis	r2,init_task@h
+	ori	r2,r2,init_task@l
+
+	/* ptr to current thread */
+	addi	r4,r2,THREAD	/* init task's THREAD */
+	mtspr	SPRN_SPRG3,r4
+
+	/* stack */
+	lis	r1,init_thread_union@h
+	ori	r1,r1,init_thread_union@l
+	li	r0,0
+	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+
+	bl	early_init
+
+	mfspr	r3,SPRN_TLB1CFG
+	andi.	r3,r3,0xfff
+	lis	r4,num_tlbcam_entries@ha
+	stw	r3,num_tlbcam_entries@l(r4)
+/*
+ * Decide what sort of machine this is and initialize the MMU.
+ */
+	mr	r3,r31
+	mr	r4,r30
+	mr	r5,r29
+	mr	r6,r28
+	mr	r7,r27
+	bl	machine_init
+	bl	MMU_init
+
+	/* Setup PTE pointers for the Abatron bdiGDB */
+	lis	r6, swapper_pg_dir@h
+	ori	r6, r6, swapper_pg_dir@l
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	lis	r4, KERNELBASE@h
+	ori	r4, r4, KERNELBASE@l
+	stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */
+	stw	r6, 0(r5)
+
+	/* Let's move on */
+	lis	r4,start_kernel@h
+	ori	r4,r4,start_kernel@l
+	lis	r3,MSR_KERNEL@h
+	ori	r3,r3,MSR_KERNEL@l
+	mtspr	SPRN_SRR0,r4
+	mtspr	SPRN_SRR1,r3
+	rfi			/* change context and jump to start_kernel */
+
+/* Macros to hide the PTE size differences
+ *
+ * FIND_PTE -- walks the page tables given EA & pgdir pointer
+ *   r10 -- EA of fault
+ *   r11 -- PGDIR pointer
+ *   r12 -- free
+ *   label 2: is the bailout case
+ *
+ * if we find the pte (fall through):
+ *   r11 is low pte word
+ *   r12 is pointer to the pte
+ */
+#ifdef CONFIG_PTE_64BIT
+#define PTE_FLAGS_OFFSET	4
+#define FIND_PTE	\
+	rlwinm 	r12, r10, 13, 19, 29;	/* Compute pgdir/pmd offset */	\
+	lwzx	r11, r12, r11;		/* Get pgd/pmd entry */		\
+	rlwinm.	r12, r11, 0, 0, 20;	/* Extract pt base address */	\
+	beq	2f;			/* Bail if no table */		\
+	rlwimi	r12, r10, 23, 20, 28;	/* Compute pte address */	\
+	lwz	r11, 4(r12);		/* Get pte entry */
+#else
+#define PTE_FLAGS_OFFSET	0
+#define FIND_PTE	\
+	rlwimi	r11, r10, 12, 20, 29;	/* Create L1 (pgdir/pmd) address */	\
+	lwz	r11, 0(r11);		/* Get L1 entry */			\
+	rlwinm.	r12, r11, 0, 0, 19;	/* Extract L2 (pte) base address */	\
+	beq	2f;			/* Bail if no table */			\
+	rlwimi	r12, r10, 22, 20, 29;	/* Compute PTE address */		\
+	lwz	r11, 0(r12);		/* Get Linux PTE */
+#endif
+
+/*
+ * Interrupt vector entry code
+ *
+ * The Book E MMUs are always on so we don't need to handle
+ * interrupts in real mode as with previous PPC processors. In
+ * this case we handle interrupts in the kernel virtual address
+ * space.
+ *
+ * Interrupt vectors are dynamically placed relative to the
+ * interrupt prefix as determined by the address of interrupt_base.
+ * The interrupt vectors offsets are programmed using the labels
+ * for each interrupt vector entry.
+ *
+ * Interrupt vectors must be aligned on a 16 byte boundary.
+ * We align on a 32 byte cache line boundary for good measure.
+ */
+
+interrupt_base:
+	/* Critical Input Interrupt */
+	CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
+
+	/* Machine Check Interrupt */
+	MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+
+	/* Data Storage Interrupt */
+	START_EXCEPTION(DataStorage)
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRN_SPRG7W, r11
+
+	/*
+	 * Check if it was a store fault, if not then bail
+	 * because a user tried to access a kernel or
+	 * read-protected page.  Otherwise, get the
+	 * offending address and handle it.
+	 */
+	mfspr	r10, SPRN_ESR
+	andis.	r10, r10, ESR_ST@h
+	beq	2f
+
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	0, r10, r11
+	bge	2f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRN_SPRG3
+	lwz	r11,PGDIR(r11)
+4:
+	FIND_PTE
+
+	/* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */
+	andi.	r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE
+	cmpwi	0, r13, _PAGE_RW|_PAGE_USER
+	bne	2f			/* Bail if not */
+
+	/* Update 'changed'. */
+	ori	r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+	stw	r11, PTE_FLAGS_OFFSET(r12) /* Update Linux page table */
+
+	/* MAS2 not updated as the entry does exist in the tlb, this
+	   fault taken to detect state transition (eg: COW -> DIRTY)
+	 */
+	andi.	r11, r11, _PAGE_HWEXEC
+	rlwimi	r11, r11, 31, 27, 27	/* SX <- _PAGE_HWEXEC */
+	ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
+
+	/* update search PID in MAS6, AS = 0 */
+	mfspr	r12, SPRN_PID0
+	slwi	r12, r12, 16
+	mtspr	SPRN_MAS6, r12
+
+	/* find the TLB index that caused the fault.  It has to be here. */
+	tlbsx	0, r10
+
+	/* only update the perm bits, assume the RPN is fine */
+	mfspr	r12, SPRN_MAS3
+	rlwimi	r12, r11, 0, 20, 31
+	mtspr	SPRN_MAS3,r12
+	tlbwe
+
+	/* Done...restore registers and get out of here.  */
+	mfspr	r11, SPRN_SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
+	rfi			/* Force context change */
+
+2:
+	/*
+	 * The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRN_SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
+	b	data_access
+
+	/* Instruction Storage Interrupt */
+	INSTRUCTION_STORAGE_EXCEPTION
+
+	/* External Input Interrupt */
+	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+
+	/* Alignment Interrupt */
+	ALIGNMENT_EXCEPTION
+
+	/* Program Interrupt */
+	PROGRAM_EXCEPTION
+
+	/* Floating Point Unavailable Interrupt */
+#ifdef CONFIG_PPC_FPU
+	FP_UNAVAILABLE_EXCEPTION
+#else
+	EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
+#endif
+
+	/* System Call Interrupt */
+	START_EXCEPTION(SystemCall)
+	NORMAL_EXCEPTION_PROLOG
+	EXC_XFER_EE_LITE(0x0c00, DoSyscall)
+
+	/* Auxillary Processor Unavailable Interrupt */
+	EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE)
+
+	/* Decrementer Interrupt */
+	DECREMENTER_EXCEPTION
+
+	/* Fixed Internal Timer Interrupt */
+	/* TODO: Add FIT support */
+	EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
+
+	/* Watchdog Timer Interrupt */
+	/* TODO: Add watchdog support */
+	CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
+
+	/* Data TLB Error Interrupt */
+	START_EXCEPTION(DataTLBError)
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRN_SPRG7W, r11
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	5, r10, r11
+	blt	5, 3f
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+
+	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
+	rlwinm	r12,r12,0,16,1
+	mtspr	SPRN_MAS1,r12
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRN_SPRG3
+	lwz	r11,PGDIR(r11)
+
+4:
+	FIND_PTE
+	andi.	r13, r11, _PAGE_PRESENT	/* Is the page present? */
+	beq	2f			/* Bail if not present */
+
+#ifdef CONFIG_PTE_64BIT
+	lwz	r13, 0(r12)
+#endif
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, PTE_FLAGS_OFFSET(r12)
+
+	 /* Jump to common tlb load */
+	b	finish_tlb_load
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRN_SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
+	b	data_access
+
+	/* Instruction TLB Error Interrupt */
+	/*
+	 * Nearly the same as above, except we get our
+	 * information from different registers and bailout
+	 * to a different point.
+	 */
+	START_EXCEPTION(InstructionTLBError)
+	mtspr	SPRN_SPRG0, r10		/* Save some working registers */
+	mtspr	SPRN_SPRG1, r11
+	mtspr	SPRN_SPRG4W, r12
+	mtspr	SPRN_SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRN_SPRG7W, r11
+	mfspr	r10, SPRN_SRR0		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	5, r10, r11
+	blt	5, 3f
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+
+	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
+	rlwinm	r12,r12,0,16,1
+	mtspr	SPRN_MAS1,r12
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRN_SPRG3
+	lwz	r11,PGDIR(r11)
+
+4:
+	FIND_PTE
+	andi.	r13, r11, _PAGE_PRESENT	/* Is the page present? */
+	beq	2f			/* Bail if not present */
+
+#ifdef CONFIG_PTE_64BIT
+	lwz	r13, 0(r12)
+#endif
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, PTE_FLAGS_OFFSET(r12)
+
+	/* Jump to common TLB load point */
+	b	finish_tlb_load
+
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRN_SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
+	b	InstructionStorage
+
+#ifdef CONFIG_SPE
+	/* SPE Unavailable */
+	START_EXCEPTION(SPEUnavailable)
+	NORMAL_EXCEPTION_PROLOG
+	bne	load_up_spe
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE_LITE(0x2010, KernelSPE)
+#else
+	EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+	/* SPE Floating Point Data */
+#ifdef CONFIG_SPE
+	EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
+#else
+	EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+	/* SPE Floating Point Round */
+	EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE)
+
+	/* Performance Monitor */
+	EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD)
+
+
+	/* Debug Interrupt */
+	DEBUG_EXCEPTION
+
+/*
+ * Local functions
+ */
+	/*
+	 * Data TLB exceptions will bail out to this point
+	 * if they can't resolve the lightweight TLB fault.
+	 */
+data_access:
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
+	stw	r5,_ESR(r11)
+	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
+	andis.	r10,r5,(ESR_ILK|ESR_DLK)@h
+	bne	1f
+	EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+1:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE_LITE(0x0300, CacheLockingException)
+
+/*
+
+ * Both the instruction and data TLB miss get to this
+ * point to load the TLB.
+ * 	r10 - EA of fault
+ * 	r11 - TLB (info from Linux PTE)
+ * 	r12, r13 - available to use
+ * 	CR5 - results of addr < TASK_SIZE
+ *	MAS0, MAS1 - loaded with proper value when we get here
+ *	MAS2, MAS3 - will need additional info from Linux PTE
+ *	Upon exit, we reload everything and RFI.
+ */
+finish_tlb_load:
+	/*
+	 * We set execute, because we don't have the granularity to
+	 * properly set this at the page level (Linux problem).
+	 * Many of these bits are software only.  Bits we don't set
+	 * here we (properly should) assume have the appropriate value.
+	 */
+
+	mfspr	r12, SPRN_MAS2
+#ifdef CONFIG_PTE_64BIT
+	rlwimi	r12, r11, 26, 24, 31	/* extract ...WIMGE from pte */
+#else
+	rlwimi	r12, r11, 26, 27, 31	/* extract WIMGE from pte */
+#endif
+	mtspr	SPRN_MAS2, r12
+
+	bge	5, 1f
+
+	/* is user addr */
+	andi.	r12, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC)
+	andi.	r10, r11, _PAGE_USER	/* Test for _PAGE_USER */
+	srwi	r10, r12, 1
+	or	r12, r12, r10	/* Copy user perms into supervisor */
+	iseleq	r12, 0, r12
+	b	2f
+
+	/* is kernel addr */
+1:	rlwinm	r12, r11, 31, 29, 29	/* Extract _PAGE_HWWRITE into SW */
+	ori	r12, r12, (MAS3_SX | MAS3_SR)
+
+#ifdef CONFIG_PTE_64BIT
+2:	rlwimi	r12, r13, 24, 0, 7	/* grab RPN[32:39] */
+	rlwimi	r12, r11, 24, 8, 19	/* grab RPN[40:51] */
+	mtspr	SPRN_MAS3, r12
+BEGIN_FTR_SECTION
+	srwi	r10, r13, 8		/* grab RPN[8:31] */
+	mtspr	SPRN_MAS7, r10
+END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
+#else
+2:	rlwimi	r11, r12, 0, 20, 31	/* Extract RPN from PTE and merge with perms */
+	mtspr	SPRN_MAS3, r11
+#endif
+	tlbwe
+
+	/* Done...restore registers and get out of here.  */
+	mfspr	r11, SPRN_SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRN_SPRG5R
+	mfspr	r12, SPRN_SPRG4R
+	mfspr	r11, SPRN_SPRG1
+	mfspr	r10, SPRN_SPRG0
+	rfi					/* Force context change */
+
+#ifdef CONFIG_SPE
+/* Note that the SPE support is closely modeled after the AltiVec
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_spe:
+/*
+ * Disable SPE for the task which had SPE previously,
+ * and save its SPE registers in its thread_struct.
+ * Enables SPE for use in the kernel on return.
+ * On SMP we know the SPE units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+	mfmsr	r5
+	oris	r5,r5,MSR_SPE@h
+	mtmsr	r5			/* enable use of SPE now */
+	isync
+/*
+ * For SMP, we don't do lazy SPE switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_spe in switch_to.
+ */
+#ifndef CONFIG_SMP
+	lis	r3,last_task_used_spe@ha
+	lwz	r4,last_task_used_spe@l(r3)
+	cmpi	0,r4,0
+	beq	1f
+	addi	r4,r4,THREAD	/* want THREAD of last_task_used_spe */
+	SAVE_32EVR(0,r10,r4)
+   	evxor	evr10, evr10, evr10	/* clear out evr10 */
+	evmwumiaa evr10, evr10, evr10	/* evr10 <- ACC = 0 * 0 + ACC */
+	li	r5,THREAD_ACC
+   	evstddx	evr10, r4, r5		/* save off accumulator */
+	lwz	r5,PT_REGS(r4)
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r10,MSR_SPE@h
+	andc	r4,r4,r10	/* disable SPE for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+	/* enable use of SPE after return */
+	oris	r9,r9,MSR_SPE@h
+	mfspr	r5,SPRN_SPRG3		/* current task's THREAD (phys) */
+	li	r4,1
+	li	r10,THREAD_ACC
+	stw	r4,THREAD_USED_SPE(r5)
+	evlddx	evr4,r10,r5
+	evmra	evr4,evr4
+	REST_32EVR(0,r10,r5)
+#ifndef CONFIG_SMP
+	subi	r4,r5,THREAD
+	stw	r4,last_task_used_spe@l(r3)
+#endif /* CONFIG_SMP */
+	/* restore registers and return */
+2:	REST_4GPRS(3, r11)
+	lwz	r10,_CCR(r11)
+	REST_GPR(1, r11)
+	mtcr	r10
+	lwz	r10,_LINK(r11)
+	mtlr	r10
+	REST_GPR(10, r11)
+	mtspr	SPRN_SRR1,r9
+	mtspr	SPRN_SRR0,r12
+	REST_GPR(9, r11)
+	REST_GPR(12, r11)
+	lwz	r11,GPR11(r11)
+	SYNC
+	rfi
+
+/*
+ * SPE unavailable trap from kernel - print a message, but let
+ * the task use SPE in the kernel until it returns to user mode.
+ */
+KernelSPE:
+	lwz	r3,_MSR(r1)
+	oris	r3,r3,MSR_SPE@h
+	stw	r3,_MSR(r1)	/* enable use of SPE after return */
+	lis	r3,87f@h
+	ori	r3,r3,87f@l
+	mr	r4,r2		/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	ret_from_except
+87:	.string	"SPE used in kernel  (task=%p, pc=%x)  \n"
+	.align	4,0
+
+#endif /* CONFIG_SPE */
+
+/*
+ * Global functions
+ */
+
+/*
+ * extern void loadcam_entry(unsigned int index)
+ *
+ * Load TLBCAM[index] entry in to the L2 CAM MMU
+ */
+_GLOBAL(loadcam_entry)
+	lis	r4,TLBCAM@ha
+	addi	r4,r4,TLBCAM@l
+	mulli	r5,r3,20
+	add	r3,r5,r4
+	lwz	r4,0(r3)
+	mtspr	SPRN_MAS0,r4
+	lwz	r4,4(r3)
+	mtspr	SPRN_MAS1,r4
+	lwz	r4,8(r3)
+	mtspr	SPRN_MAS2,r4
+	lwz	r4,12(r3)
+	mtspr	SPRN_MAS3,r4
+	tlbwe
+	isync
+	blr
+
+/*
+ * extern void giveup_altivec(struct task_struct *prev)
+ *
+ * The e500 core does not have an AltiVec unit.
+ */
+_GLOBAL(giveup_altivec)
+	blr
+
+#ifdef CONFIG_SPE
+/*
+ * extern void giveup_spe(struct task_struct *prev)
+ *
+ */
+_GLOBAL(giveup_spe)
+	mfmsr	r5
+	oris	r5,r5,MSR_SPE@h
+	SYNC
+	mtmsr	r5			/* enable use of SPE now */
+	isync
+	cmpi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,THREAD		/* want THREAD of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32EVR(0, r4, r3)
+   	evxor	evr6, evr6, evr6	/* clear out evr6 */
+	evmwumiaa evr6, evr6, evr6	/* evr6 <- ACC = 0 * 0 + ACC */
+	li	r4,THREAD_ACC
+   	evstddx	evr6, r4, r3		/* save off accumulator */
+	mfspr	r6,SPRN_SPEFSCR
+	stw	r6,THREAD_SPEFSCR(r3)	/* save spefscr register value */
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r3,MSR_SPE@h
+	andc	r4,r4,r3		/* disable SPE for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+	li	r5,0
+	lis	r4,last_task_used_spe@ha
+	stw	r5,last_task_used_spe@l(r4)
+#endif /* CONFIG_SMP */
+	blr
+#endif /* CONFIG_SPE */
+
+/*
+ * extern void giveup_fpu(struct task_struct *prev)
+ *
+ * Not all FSL Book-E cores have an FPU
+ */
+#ifndef CONFIG_PPC_FPU
+_GLOBAL(giveup_fpu)
+	blr
+#endif
+
+/*
+ * extern void abort(void)
+ *
+ * At present, this routine just applies a system reset.
+ */
+_GLOBAL(abort)
+	li	r13,0
+        mtspr   SPRN_DBCR0,r13		/* disable all debug events */
+	mfmsr	r13
+	ori	r13,r13,MSR_DE@l	/* Enable Debug Events */
+	mtmsr	r13
+        mfspr   r13,SPRN_DBCR0
+        lis	r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
+        mtspr   SPRN_DBCR0,r13
+
+_GLOBAL(set_context)
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is the second parameter.
+	 */
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r4, 0x4(r5)
+#endif
+	mtspr	SPRN_PID,r3
+	isync			/* Force context change */
+	blr
+
+/*
+ * We put a few things here that have to be page-aligned. This stuff
+ * goes at the beginning of the data segment, which is page-aligned.
+ */
+	.data
+_GLOBAL(sdata)
+_GLOBAL(empty_zero_page)
+	.space	4096
+_GLOBAL(swapper_pg_dir)
+	.space	4096
+
+/* Reserved 4k for the critical exception stack & 4k for the machine
+ * check stack per CPU for kernel mode exceptions */
+	.section .bss
+        .align 12
+exception_stack_bottom:
+	.space	BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS
+_GLOBAL(exception_stack_top)
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+_GLOBAL(cmd_line)
+	.space	512
+
+/*
+ * Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+	.space	8
+
diff --git a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S
--- a/arch/ppc/kernel/l2cr.S
+++ b/arch/ppc/kernel/l2cr.S
@@ -125,14 +125,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	 * DPM can possibly interfere with the state machine in the processor
 	 * that invalidates the L2 cache tags.
 	 */
-	mfspr	r8,HID0			/* Save HID0 in r8 */
+	mfspr	r8,SPRN_HID0		/* Save HID0 in r8 */
 	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
 	sync
-	mtspr	HID0,r4			/* Disable DPM */
+	mtspr	SPRN_HID0,r4		/* Disable DPM */
 	sync
 
 	/* Get the current enable bit of the L2CR into r4 */
-	mfspr	r4,L2CR
+	mfspr	r4,SPRN_L2CR
 
 	/* Tweak some bits */
 	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
@@ -186,7 +186,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	.balign	L1_CACHE_LINE_SIZE
 22:
 	sync
-	mtspr	L2CR,r3
+	mtspr	SPRN_L2CR,r3
 	sync
 	b	23f
 20:
@@ -199,27 +199,27 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	/* Perform a global invalidation */
 	oris	r3,r3,0x0020
 	sync
-	mtspr	L2CR,r3
+	mtspr	SPRN_L2CR,r3
 	sync
 	isync				/* For errata */
 
 BEGIN_FTR_SECTION
 	/* On the 7450, we wait for the L2I bit to clear......
 	*/
-10:	mfspr	r3,L2CR
+10:	mfspr	r3,SPRN_L2CR
 	andis.	r4,r3,0x0020
 	bne	10b
 	b	11f
 END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
 
 	/* Wait for the invalidation to complete */
-3:	mfspr	r3,L2CR
+3:	mfspr	r3,SPRN_L2CR
 	rlwinm.	r4,r3,0,31,31
 	bne	3b
 
 11:	rlwinm	r3,r3,0,11,9		/* Turn off the L2I bit */
 	sync
-	mtspr	L2CR,r3
+	mtspr	SPRN_L2CR,r3
 	sync
 
 	/* See if we need to enable the cache */
@@ -228,7 +228,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
 
 	/* Enable the cache */
 	oris	r3,r3,0x8000
-	mtspr	L2CR,r3
+	mtspr	SPRN_L2CR,r3
 	sync
 
 4:
@@ -250,7 +250,7 @@ _GLOBAL(_get_L2CR)
 	/* Return the L2CR contents */
 	li	r3,0
 BEGIN_FTR_SECTION
-	mfspr	r3,L2CR
+	mfspr	r3,SPRN_L2CR
 END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
 	blr
 
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -216,10 +216,10 @@ _GLOBAL(low_choose_750fx_pll)
 	/* If switching to PLL1, disable HID0:BTIC */
 	cmplwi	cr0,r3,0
 	beq	1f
-	mfspr	r5,HID0
+	mfspr	r5,SPRN_HID0
 	rlwinm	r5,r5,0,27,25
 	sync
-	mtspr	HID0,r5
+	mtspr	SPRN_HID0,r5
 	isync
 	sync
 
@@ -241,10 +241,10 @@ _GLOBAL(low_choose_750fx_pll)
 	/* If switching to PLL0, enable HID0:BTIC */
 	cmplwi	cr0,r3,0
 	bne	1f
-	mfspr	r5,HID0
+	mfspr	r5,SPRN_HID0
 	ori	r5,r5,HID0_BTIC
 	sync
-	mtspr	HID0,r5
+	mtspr	SPRN_HID0,r5
 	isync
 	sync
 
@@ -579,7 +579,7 @@ _GLOBAL(flush_instruction_cache)
 #if defined(CONFIG_8xx)
 	isync
 	lis	r5, IDC_INVALL@h
-	mtspr	IC_CST, r5
+	mtspr	SPRN_IC_CST, r5
 #elif defined(CONFIG_4xx)
 #ifdef CONFIG_403GCX
 	li      r3, 512
@@ -597,14 +597,14 @@ _GLOBAL(flush_instruction_cache)
 	ori	r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
 	mtspr	SPRN_L1CSR1,r3
 #else
-	mfspr	r3,PVR
+	mfspr	r3,SPRN_PVR
 	rlwinm	r3,r3,16,16,31
 	cmpwi	0,r3,1
 	beqlr			/* for 601, do nothing */
 	/* 603/604 processor - use invalidate-all bit in HID0 */
-	mfspr	r3,HID0
+	mfspr	r3,SPRN_HID0
 	ori	r3,r3,HID0_ICFI
-	mtspr	HID0,r3
+	mtspr	SPRN_HID0,r3
 #endif /* CONFIG_8xx/4xx */
 	isync
 	blr
@@ -619,7 +619,7 @@ _GLOBAL(flush_instruction_cache)
 _GLOBAL(flush_icache_range)
 BEGIN_FTR_SECTION
 	blr				/* for 601, do nothing */
-END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
 	li	r5,L1_CACHE_LINE_SIZE-1
 	andc	r3,r3,r5
 	subf	r4,r3,r4
@@ -736,7 +736,7 @@ _GLOBAL(flush_dcache_all)
 _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
 	blr					/* for 601, do nothing */
-END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
 	rlwinm	r3,r3,0,0,19			/* Get page base address */
 	li	r4,4096/L1_CACHE_LINE_SIZE	/* Number of lines in a page */
 	mtctr	r4
@@ -764,7 +764,7 @@ END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIE
 _GLOBAL(__flush_dcache_icache_phys)
 BEGIN_FTR_SECTION
 	blr					/* for 601, do nothing */
-END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
 	mfmsr	r10
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
@@ -1096,17 +1096,7 @@ _GLOBAL(_get_SP)
  * and exceptions as if the cpu had performed the load or store.
  */
 
-#if defined(CONFIG_4xx) || defined(CONFIG_E500)
-_GLOBAL(cvt_fd)
-	lfs	0,0(r3)
-	stfd	0,0(r4)
-	blr
-
-_GLOBAL(cvt_df)
-	lfd	0,0(r3)
-	stfs	0,0(r4)
-	blr
-#else
+#ifdef CONFIG_PPC_FPU
 _GLOBAL(cvt_fd)
 	lfd	0,-4(r5)	/* load up fpscr value */
 	mtfsf	0xff,0
@@ -1450,3 +1440,4 @@ _GLOBAL(sys_call_table)
 	.long sys_add_key
 	.long sys_request_key		/* 270 */
 	.long sys_keyctl
+	.long sys_waitid
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -521,11 +521,11 @@ pcibios_allocate_resources(int pass)
 		if (pass)
 			continue;
 		r = &dev->resource[PCI_ROM_RESOURCE];
-		if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+		if (r->flags & IORESOURCE_ROM_ENABLE) {
 			/* Turn the ROM off, leave the resource region, but keep it unregistered. */
 			u32 reg;
 			DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
-			r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+			r->flags &= ~IORESOURCE_ROM_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);
@@ -1058,7 +1058,7 @@ do_update_p2p_io_resource(struct pci_bus
 		return;
  	res = *(bus->resource[0]);
 
-	DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name);
+	DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
 	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);
@@ -1432,7 +1432,7 @@ pci_bus_to_hose(int bus)
 	return NULL;
 }
 
-void*
+void __iomem *
 pci_bus_io_base(unsigned int bus)
 {
 	struct pci_controller *hose;
@@ -1478,97 +1478,145 @@ pci_resource_to_bus(struct pci_dev *pdev
 	return res->start;
 }
 
-/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
- *  -- paulus.
- */
 
-/*
- * Adjust vm_pgoff of VMA such that it is the physical page offset
- * corresponding to the 32-bit pci bus offset for DEV requested by the user.
- *
- * Basically, the user finds the base address for his device which he wishes
- * to mmap.  They read the 32-bit value from the config space base register,
- * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
- * offset parameter of mmap on /proc/bus/pci/XXX for that device.
- *
- * Returns negative error code on failure, zero on success.
- */
-static __inline__ int
-__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
-		       enum pci_mmap_state mmap_state)
-{
-	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	unsigned long size = vma->vm_end - vma->vm_start;
-	unsigned long base;
-	struct resource *res;
-	int i;
-	int ret = -EINVAL;
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+					       unsigned long *offset,
+					       enum pci_mmap_state mmap_state)
+{
+	struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+	unsigned long io_offset = 0;
+	int i, res_bit;
 
 	if (hose == 0)
-		return -EINVAL;		/* should never happen */
-	if (offset + size <= offset)
-		return -EINVAL;
+		return NULL;		/* should never happen */
 
+	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
-		/* PCI memory space */
-		base = hose->pci_mem_offset;
-		for (i = 0; i < 3; ++i) {
-			res = &hose->mem_resources[i];
-			if (res->flags == 0)
-				continue;
-			if (offset >= res->start - base
-			    && offset + size - 1 <= res->end - base) {
-				ret = 0;
-				break;
-			}
-		}
-		offset += hose->pci_mem_offset;
+		*offset += hose->pci_mem_offset;
+		res_bit = IORESOURCE_MEM;
 	} else {
-		/* PCI I/O space */
-		base = (unsigned long)hose->io_base_virt - isa_io_base;
-		res = &hose->io_resource;
-		if (offset >= res->start - base
-		    && offset + size - 1 <= res->end - base)
-			ret = 0;
-		offset += hose->io_base_phys;
+		io_offset = (unsigned long)hose->io_base_virt;
+		*offset += io_offset;
+		res_bit = IORESOURCE_IO;
 	}
 
-	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	return ret;
-}
+	/*
+	 * Check that the offset requested corresponds to one of the
+	 * resources of the device.
+	 */
+	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+		struct resource *rp = &dev->resource[i];
+		int flags = rp->flags;
+
+		/* treat ROM as memory (should be already) */
+		if (i == PCI_ROM_RESOURCE)
+			flags |= IORESOURCE_MEM;
 
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
-		     enum pci_mmap_state mmap_state)
-{
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+		/* Active and same type? */
+		if ((flags & res_bit) == 0)
+			continue;
+
+		/* In the range of this resource? */
+		if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+			continue;
+
+		/* found it! construct the final physical address */
+		if (mmap_state == pci_mmap_io)
+			*offset += hose->io_base_phys - _IO_BASE;
+		return rp;
+	}
+
+	return NULL;
 }
 
 /*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
  */
-static __inline__ void
-__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
-		      enum pci_mmap_state mmap_state, int write_combine)
-{
-	int prot = pgprot_val(vma->vm_page_prot);
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+				      pgprot_t protection,
+				      enum pci_mmap_state mmap_state,
+				      int write_combine)
+{
+	unsigned long prot = pgprot_val(protection);
+
+	/* Write combine is always 0 on non-memory space mappings. On
+	 * memory space, if the user didn't pass 1, we check for a
+	 * "prefetchable" resource. This is a bit hackish, but we use
+	 * this to workaround the inability of /sysfs to provide a write
+	 * combine bit
+	 */
+	if (mmap_state != pci_mmap_mem)
+		write_combine = 0;
+	else if (write_combine == 0) {
+		if (rp->flags & IORESOURCE_PREFETCH)
+			write_combine = 1;
+	}
 
 	/* XXX would be nice to have a way to ask for write-through */
 	prot |= _PAGE_NO_CACHE;
-	if (!write_combine)
+	if (write_combine)
+		prot &= ~_PAGE_GUARDED;
+	else
 		prot |= _PAGE_GUARDED;
-	vma->vm_page_prot = __pgprot(prot);
+
+	printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+	       prot);
+
+	return __pgprot(prot);
 }
 
 /*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+				  unsigned long offset,
+				  unsigned long size,
+				  pgprot_t protection)
+{
+	struct pci_dev *pdev = NULL;
+	struct resource *found = NULL;
+	unsigned long prot = pgprot_val(protection);
+	int i;
+
+	if (page_is_ram(offset >> PAGE_SHIFT))
+		return prot;
+
+	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+	for_each_pci_dev(pdev) {
+		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+			struct resource *rp = &pdev->resource[i];
+			int flags = rp->flags;
+
+			/* Active and same type? */
+			if ((flags & IORESOURCE_MEM) == 0)
+				continue;
+			/* In the range of this resource? */
+			if (offset < (rp->start & PAGE_MASK) ||
+			    offset > rp->end)
+				continue;
+			found = rp;
+			break;
+		}
+		if (found)
+			break;
+	}
+	if (found) {
+		if (found->flags & IORESOURCE_PREFETCH)
+			prot &= ~_PAGE_GUARDED;
+		pci_dev_put(pdev);
+	}
+
+	DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+	return __pgprot(prot);
+}
+
+
+/*
  * Perform the actual remap of the pages for a PCI device mapping, as
  * appropriate for this architecture.  The region in the process to map
  * is described by vm_start and vm_end members of VMA, the base physical
@@ -1582,14 +1630,19 @@ int pci_mmap_page_range(struct pci_dev *
 			enum pci_mmap_state mmap_state,
 			int write_combine)
 {
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct resource *rp;
 	int ret;
 
-	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
-	if (ret < 0)
-		return ret;
+	rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+	if (rp == NULL)
+		return -EINVAL;
 
-	__pci_mmap_set_flags(dev, vma, mmap_state);
-	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+						  vma->vm_page_prot,
+						  mmap_state, write_combine);
 
 	ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -108,7 +108,7 @@ static int ppc_htab_show(struct seq_file
 	PTE *ptr;
 #endif /* CONFIG_PPC_STD_MMU */
 
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
+	if (cpu_has_feature(CPU_FTR_604_PERF_MON)) {
 		mmcr0 = mfspr(SPRN_MMCR0);
 		pmc1 = mfspr(SPRN_PMC1);
 		pmc2 = mfspr(SPRN_PMC2);
@@ -209,7 +209,7 @@ static ssize_t ppc_htab_write(struct fil
 
 	if ( !strncmp( buffer, "reset", 5) )
 	{
-		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
+		if (cpu_has_feature(CPU_FTR_604_PERF_MON)) {
 			/* reset PMC1 and PMC2 */
 			mtspr(SPRN_PMC1, 0);
 			mtspr(SPRN_PMC2, 0);
@@ -221,7 +221,7 @@ static ssize_t ppc_htab_write(struct fil
 	}
 
 	/* Everything below here requires the performance monitor feature. */
-	if ( !cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON )
+	if (!cpu_has_feature(CPU_FTR_604_PERF_MON))
 		return count;
 
 	/* turn off performance monitoring */
@@ -339,7 +339,7 @@ int proc_dol2crvec(ctl_table *table, int
 		"0.5", "1.0", "(reserved2)", "(reserved3)"
 	};
 
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+	if (!cpu_has_feature(CPU_FTR_L2CR))
 		return -EFAULT;
 
 	if ( /*!table->maxlen ||*/ (*ppos && !write)) {
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -319,7 +319,8 @@ EXPORT_SYMBOL(debugger_fault_handler);
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
 #endif /* CONFIG_8xx */
-#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx)
+#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) ||\
+	defined(CONFIG_83xx)
 EXPORT_SYMBOL(__res);
 #endif
 
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -26,6 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -356,7 +357,7 @@ int sys_ptrace(long request, long pid, l
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -389,7 +390,7 @@ int sys_ptrace(long request, long pid, l
 
 	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		set_single_step(child);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -41,6 +41,10 @@
 #include <asm/xmon.h>
 #include <asm/ocp.h>
 
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+#include <asm/ppc_sys.h>
+#endif
+
 #if defined CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -56,7 +60,6 @@ extern void ppc6xx_idle(void);
 extern void power4_idle(void);
 
 extern boot_infos_t *boot_infos;
-unsigned char aux_device_present;
 struct ide_machdep_calls ppc_ide_md;
 char *sysmap;
 unsigned long sysmap_size;
@@ -179,7 +182,7 @@ int show_cpuinfo(struct seq_file *m, voi
 	pvr = cpu_data[i].pvr;
 	lpj = cpu_data[i].loops_per_jiffy;
 #else
-	pvr = mfspr(PVR);
+	pvr = mfspr(SPRN_PVR);
 	lpj = loops_per_jiffy;
 #endif
 
@@ -218,23 +221,26 @@ int show_cpuinfo(struct seq_file *m, voi
 			return err;
 	}
 
-	switch (PVR_VER(pvr)) {
-	case 0x0020:	/* 403 family */
-		maj = PVR_MAJ(pvr) + 1;
-		min = PVR_MIN(pvr);
-		break;
-	case 0x1008:	/* 740P/750P ?? */
-		maj = ((pvr >> 8) & 0xFF) - 1;
-		min = pvr & 0xFF;
-		break;
-	case 0x8020:	/* e500 */
+	/* If we are a Freescale core do a simple check so
+	 * we dont have to keep adding cases in the future */
+	if ((PVR_VER(pvr) & 0x8000) == 0x8000) {
 		maj = PVR_MAJ(pvr);
 		min = PVR_MIN(pvr);
-		break;
-	default:
-		maj = (pvr >> 8) & 0xFF;
-		min = pvr & 0xFF;
-		break;
+	} else {
+		switch (PVR_VER(pvr)) {
+			case 0x0020:	/* 403 family */
+				maj = PVR_MAJ(pvr) + 1;
+				min = PVR_MIN(pvr);
+				break;
+			case 0x1008:	/* 740P/750P ?? */
+				maj = ((pvr >> 8) & 0xFF) - 1;
+				min = pvr & 0xFF;
+				break;
+			default:
+				maj = (pvr >> 8) & 0xFF;
+				min = pvr & 0xFF;
+				break;
+		}
 	}
 
 	seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n",
@@ -243,6 +249,12 @@ int show_cpuinfo(struct seq_file *m, voi
 	seq_printf(m, "bogomips\t: %lu.%02lu\n",
 		   lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
 
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+	if (cur_ppc_sys_spec->ppc_sys_name)
+		seq_printf(m, "chipset\t\t: %s\n",
+			cur_ppc_sys_spec->ppc_sys_name);
+#endif
+
 #ifdef CONFIG_SMP
 	seq_printf(m, "\n");
 #endif
@@ -335,14 +347,15 @@ int __openfirmware
 of_show_percpuinfo(struct seq_file *m, int i)
 {
 	struct device_node *cpu_node;
-	int *fp, s;
+	u32 *fp;
+	int 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);
+	fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
 	if (fp)
 		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
 	return 0;
@@ -486,7 +499,7 @@ static int __init set_preferred_console(
 {
 	struct device_node *prom_stdout;
 	char *name;
-	int offset;
+	int offset = 0;
 
 	if (of_stdout_device == NULL)
 		return -ENODEV;
@@ -619,7 +632,7 @@ machine_init(unsigned long r3, unsigned 
 /* Checks "l2cr=xxxx" command-line option */
 int __init ppc_setup_l2cr(char *str)
 {
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
+	if (cpu_has_feature(CPU_FTR_L2CR)) {
 		unsigned long val = simple_strtoul(str, NULL, 0);
 		printk(KERN_INFO "l2cr set to %lx\n", val);
 		_set_L2CR(0);		/* force invalidate by disable cache */
@@ -720,7 +733,7 @@ void __init setup_arch(char **cmdline_p)
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPLIT_ID_CACHE) {
+	if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
 		dcache_bsize = cur_cpu_spec[0]->dcache_bsize;
 		icache_bsize = cur_cpu_spec[0]->icache_bsize;
 		ucache_bsize = 0;
@@ -740,6 +753,8 @@ void __init setup_arch(char **cmdline_p)
 	strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
 	*cmdline_p = cmd_line;
 
+	parse_early_param();
+
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -28,6 +28,7 @@
 #include <linux/elf.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -118,7 +119,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -130,7 +131,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, (act? &new_ka: NULL), (oact? &old_ka: NULL));
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -376,7 +377,7 @@ handle_rt_signal(unsigned long sig, stru
 	/* create a stack frame for the caller of the handler */
 	newsp -= __SIGNAL_FRAMESIZE + 16;
 
-	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+	if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
 		goto badframe;
 
 	/* Put the siginfo & fill in most of the ucontext */
@@ -445,7 +446,7 @@ int sys_swapcontext(struct ucontext __us
 		return -EINVAL;
 
 	if (old_ctx != NULL) {
-		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
+		if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
 		    || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
 		    || __copy_to_user(&old_ctx->uc_sigmask,
 				      &current->blocked, sizeof(sigset_t))
@@ -454,7 +455,7 @@ int sys_swapcontext(struct ucontext __us
 	}
 	if (new_ctx == NULL)
 		return 0;
-	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))
+	if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx))
 	    || __get_user(tmp, (u8 __user *) new_ctx)
 	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))
 		return -EFAULT;
@@ -464,7 +465,7 @@ int sys_swapcontext(struct ucontext __us
 	 * image of the user's registers, we can't just return -EFAULT
 	 * because the user's registers will be corrupted.  For instance
 	 * the NIP value may have been updated but not some of the
-	 * other registers.  Given that we have done the verify_area
+	 * other registers.  Given that we have done the access_ok
 	 * and successfully read the first and last bytes of the region
 	 * above, this should only happen in an out-of-memory situation
 	 * or if another thread unmaps the region containing the context.
@@ -487,7 +488,7 @@ int sys_rt_sigreturn(int r3, int r4, int
 
 	rt_sf = (struct rt_sigframe __user *)
 		(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
-	if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe)))
+	if (!access_ok(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe)))
 		goto bad;
 	if (do_setcontext(&rt_sf->uc, regs, 1))
 		goto bad;
@@ -510,7 +511,7 @@ int sys_rt_sigreturn(int r3, int r4, int
 }
 
 int sys_debug_setcontext(struct ucontext __user *ctx,
-			 int ndbg, struct sig_dbg_op *dbg,
+			 int ndbg, struct sig_dbg_op __user *dbg,
 			 int r6, int r7, int r8,
 			 struct pt_regs *regs)
 {
@@ -572,7 +573,7 @@ int sys_debug_setcontext(struct ucontext
 	 * image of the user's registers, we can't just return -EFAULT
 	 * because the user's registers will be corrupted.  For instance
 	 * the NIP value may have been updated but not some of the
-	 * other registers.  Given that we have done the verify_area
+	 * other registers.  Given that we have done the access_ok
 	 * and successfully read the first and last bytes of the region
 	 * above, this should only happen in an out-of-memory situation
 	 * or if another thread unmaps the region containing the context.
@@ -622,7 +623,7 @@ handle_signal(unsigned long sig, struct 
 	/* create a stack frame for the caller of the handler */
 	newsp -= __SIGNAL_FRAMESIZE;
 
-	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+	if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
 		goto badframe;
 
 #if _NSIG != 64
@@ -631,7 +632,7 @@ handle_signal(unsigned long sig, struct 
 	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
 	    || __put_user(oldset->sig[0], &sc->oldmask)
 	    || __put_user(oldset->sig[1], &sc->_unused[3])
-	    || __put_user((struct pt_regs *)frame, &sc->regs)
+	    || __put_user((struct pt_regs __user *)frame, &sc->regs)
 	    || __put_user(sig, &sc->signal))
 		goto badframe;
 
@@ -680,7 +681,7 @@ int sys_sigreturn(int r3, int r4, int r5
 	restore_sigmask(&set);
 
 	sr = (struct mcontext __user *) sigctx.regs;
-	if (verify_area(VERIFY_READ, sr, sizeof(*sr))
+	if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
 	    || restore_user_regs(regs, sr, 1))
 		goto badframe;
 
@@ -704,13 +705,20 @@ int do_signal(sigset_t *oldset, struct p
 	unsigned long frame, newsp;
 	int signr, ret;
 
+	if (current->flags & PF_FREEZE) {
+		refrigerator(PF_FREEZE);
+		signr = 0;
+		if (!signal_pending(current))
+			goto no_signal;
+	}
+
 	if (!oldset)
 		oldset = &current->blocked;
 
 	newsp = frame = 0;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-
+ no_signal:
 	if (TRAP(regs) == 0x0C00		/* System Call! */
 	    && regs->ccr & 0x10000000		/* error signalled */
 	    && ((ret = regs->gpr[3]) == ERESTARTSYS
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -35,14 +35,12 @@
 #include <asm/tlbflush.h>
 #include <asm/xmon.h>
 
-int smp_threads_ready;
 volatile int smp_commenced;
 int smp_tb_synchronized;
 struct cpuinfo_PPC cpu_data[NR_CPUS];
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-unsigned long cache_decay_ticks = HZ/100;
 cpumask_t cpu_online_map;
 cpumask_t cpu_possible_map;
 int smp_hw_index[NR_CPUS];
@@ -119,7 +117,7 @@ void smp_message_recv(int msg, struct pt
  */
 void smp_send_tlb_invalidate(int cpu)
 {
-	if ( PVR_VER(mfspr(PVR)) == 8 )
+	if ( PVR_VER(mfspr(SPRN_PVR)) == 8 )
 		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0);
 }
 
@@ -283,7 +281,7 @@ static void __devinit smp_store_cpu_info
 
 	/* assume bogomips are same for everything */
         c->loops_per_jiffy = loops_per_jiffy;
-        c->pvr = mfspr(PVR);
+        c->pvr = mfspr(SPRN_PVR);
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/ppc/kernel/swsusp.S b/arch/ppc/kernel/swsusp.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc/kernel/swsusp.S
@@ -0,0 +1,349 @@
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#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_R2		0x68
+#define SL_CR		0x6c
+#define SL_LR		0x70
+#define SL_R12		0x74	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.section .data
+	.align	5
+
+_GLOBAL(swsusp_save_area)
+	.space	SL_SIZE
+
+
+	.section .text
+	.align	5
+
+_GLOBAL(swsusp_arch_suspend)
+
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+
+	mflr	r0
+	stw	r0,SL_LR(r11)
+	mfcr	r0
+	stw	r0,SL_CR(r11)
+	stw	r1,SL_SP(r11)
+	stw	r2,SL_R2(r11)
+	stmw	r12,SL_R12(r11)
+
+	/* Save MSR & SDR1 */
+	mfmsr	r4
+	stw	r4,SL_MSR(r11)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r11)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TB(r11)
+	mftb	r5
+	stw	r5,SL_TB+4(r11)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r11)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r11)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r11)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r11)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r11)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r11)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r11)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r11)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r11)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r11)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r11)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r11)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r11)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r11)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r11)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r11)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r11)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r11)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r11)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r11)
+
+#if  0
+	/* Backup various CPU config stuffs */
+	bl	__save_cpu_setup
+#endif
+	/* Call the low level suspend stuff (we should probably have made
+	 * a stackframe...
+	 */
+	bl	swsusp_save
+
+	/* Restore LR from the save area */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	blr
+
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ 	sync
+
+	/* Disable MSR:DR to make sure we don't take a TLB or
+	 * hash miss during the copy, as our hash table will
+	 * for a while be unuseable. For .text, we assume we are
+	 * covered by a BAT. This works only for non-G5 at this
+	 * point. G5 will need a better approach, possibly using
+	 * a small temporary hash table filled with large mappings,
+	 * disabling the MMU completely isn't a good option for
+	 * performance reasons.
+	 * (Note that 750's may have the same performance issue as
+	 * the G5 in this case, we should investigate using moving
+	 * BATs for these CPUs)
+	 */
+	mfmsr	r0
+	sync
+	rlwinm	r0,r0,0,28,26		/* clear MSR_DR */
+	mtmsr	r0
+	sync
+	isync
+
+	/* Load ptr the list of pages to copy in r3 */
+	lis	r11,(pagedir_nosave - KERNELBASE)@h
+	ori	r11,r11,pagedir_nosave@l
+	lwz	r10,0(r11)
+
+	/* Copy the pages. This is a very basic implementation, to
+	 * be replaced by something more cache efficient */
+1:
+	tophys(r3,r10)
+	li	r0,256
+	mtctr	r0
+	lwz	r11,pbe_address(r3)	/* source */
+	tophys(r5,r11)
+	lwz	r10,pbe_orig_address(r3)	/* destination */
+	tophys(r6,r10)
+2:
+	lwz	r8,0(r5)
+	lwz	r9,4(r5)
+	lwz	r10,8(r5)
+	lwz	r11,12(r5)
+	addi	r5,r5,16
+	stw	r8,0(r6)
+	stw	r9,4(r6)
+	stw	r10,8(r6)
+	stw	r11,12(r6)
+	addi	r6,r6,16
+	bdnz	2b
+	lwz		r10,pbe_next(r3)
+	cmpwi	0,r10,0
+	bne	1b
+
+	/* Do a very simple cache flush/inval of the L1 to ensure
+	 * coherency of the icache
+	 */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	lwz	r0,0(r3)
+	addi	r3,r3,0x0020
+	bdnz	1b
+	isync
+	sync
+
+	/* Now flush those cache lines */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	dcbf	0,r3
+	addi	r3,r3,0x0020
+	bdnz	1b
+	sync
+
+	/* Ok, we are now running with the kernel data of the old
+	 * kernel fully restored. We can get to the save area
+	 * easily now. As for the rest of the code, it assumes the
+	 * loader kernel and the booted one are exactly identical
+	 */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	tophys(r11,r11)
+
+#if 0
+	/* Restore various CPU config stuffs */
+	bl	__restore_cpu_setup
+#endif
+	/* Restore the BATs, and SDR1.  Then we can turn on the MMU.
+	 * This is a bit hairy as we are running out of those BATs,
+	 * but first, our code is probably in the icache, and we are
+	 * writing the same value to the BAT, so that should be fine,
+	 * though a better solution will have to be found long-term
+	 */
+	lwz	r4,SL_SDR1(r11)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r11)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r11)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r11)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r11)
+	mtsprg	3,r4
+
+#if 0
+	lwz	r4,SL_DBAT0(r11)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r11)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r11)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r11)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r11)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r11)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r11)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r11)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r11)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r11)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r11)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r11)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r11)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r11)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r11)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r11)
+	mtibatl	3,r4
+#endif
+
+BEGIN_FTR_SECTION
+	li	r4,0
+	mtspr	SPRN_DBAT4U,r4
+	mtspr	SPRN_DBAT4L,r4
+	mtspr	SPRN_DBAT5U,r4
+	mtspr	SPRN_DBAT5L,r4
+	mtspr	SPRN_DBAT6U,r4
+	mtspr	SPRN_DBAT6L,r4
+	mtspr	SPRN_DBAT7U,r4
+	mtspr	SPRN_DBAT7L,r4
+	mtspr	SPRN_IBAT4U,r4
+	mtspr	SPRN_IBAT4L,r4
+	mtspr	SPRN_IBAT5U,r4
+	mtspr	SPRN_IBAT5L,r4
+	mtspr	SPRN_IBAT6U,r4
+	mtspr	SPRN_IBAT6L,r4
+	mtspr	SPRN_IBAT7U,r4
+	mtspr	SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
+	/* 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(r11)
+	bl	turn_on_mmu
+	tovirt(r11,r11)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TB(r11)
+	lwz	r4,SL_TB+4(r11)
+	mttbu	r3
+	mttbl	r4
+
+	/* Kick decrementer */
+	li	r0,1
+	mtdec	r0
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r11)
+	mtcr	r0
+	lwz	r2,SL_R2(r11)
+	lmw	r12,SL_R12(r11)
+	lwz	r1,SL_SP(r11)
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	// XXX Note: we don't really need to call swsusp_resume
+
+	li	r3,0
+	blr
+
+/* FIXME:This construct is actually not useful since we don't shut
+ * down the instruction MMU, we could just flip back MSR-DR on.
+ */
+turn_on_mmu:
+	mflr	r4
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	isync
+	rfi
+
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -77,7 +77,7 @@ sys_ipc (uint call, int first, int secon
 
 		if (!ptr)
 			break;
-		if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+		if ((ret = access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
 		    || (ret = get_user(fourth.__pad, (void __user *__user *)ptr)))
 			break;
 		ret = sys_semctl (first, second, third, fourth);
@@ -93,7 +93,7 @@ sys_ipc (uint call, int first, int secon
 
 			if (!ptr)
 				break;
-			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+			if ((ret = access_ok(VERIFY_READ, ptr, sizeof(tmp)) ? 0 : -EFAULT)
 			    || (ret = copy_from_user(&tmp,
 					(struct ipc_kludge __user *) ptr,
 					sizeof (tmp)) ? -EFAULT : 0))
@@ -117,8 +117,8 @@ sys_ipc (uint call, int first, int secon
 	case SHMAT: {
 		ulong raddr;
 
-		if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third,
-				       sizeof(ulong))))
+		if ((ret = access_ok(VERIFY_WRITE, (ulong __user *) third,
+				       sizeof(ulong)) ? 0 : -EFAULT))
 			break;
 		ret = do_shmat (first, (char __user *) ptr, second, &raddr);
 		if (ret)
@@ -213,7 +213,7 @@ ppc_select(int n, fd_set __user *inp, fd
 	if ( (unsigned long)n >= 4096 )
 	{
 		unsigned long __user *buffer = (unsigned long __user *)n;
-		if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+		if (!access_ok(VERIFY_READ, buffer, 5*sizeof(unsigned long))
 		    || __get_user(n, buffer)
 		    || __get_user(inp, ((fd_set __user * __user *)(buffer+1)))
 		    || __get_user(outp, ((fd_set  __user * __user *)(buffer+2)))
diff --git a/arch/ppc/kernel/temp.c b/arch/ppc/kernel/temp.c
--- a/arch/ppc/kernel/temp.c
+++ b/arch/ppc/kernel/temp.c
@@ -223,7 +223,7 @@ int __init TAU_init(void)
 	/* We assume in SMP that if one CPU has TAU support, they
 	 * all have it --BenH
 	 */
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_TAU)) {
+	if (!cpu_has_feature(CPU_FTR_TAU)) {
 		printk("Thermal assist unit not available\n");
 		tau_initialized = 0;
 		return 1;
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -89,8 +89,6 @@ unsigned long tb_to_ns_scale;
 
 extern unsigned long wall_jiffies;
 
-static long time_offset;
-
 DEFINE_SPINLOCK(rtc_lock);
 
 EXPORT_SYMBOL(rtc_lock);
@@ -272,7 +270,6 @@ int do_settimeofday(struct timespec *tv)
 
 	time_adjust = 0;                /* stop active adjtime() */
 	time_status |= STA_UNSYNC;
-	time_state = TIME_ERROR;        /* p. 24, (a) */
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irqrestore(&xtime_lock, flags);
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -176,7 +176,7 @@ static inline int check_io_access(struct
 #else
 #define get_mc_reason(regs)	(mfspr(SPRN_MCSR))
 #endif
-#define REASON_FP		0
+#define REASON_FP		ESR_FP
 #define REASON_ILLEGAL		ESR_PIL
 #define REASON_PRIVILEGED	ESR_PPR
 #define REASON_TRAP		ESR_PTR
@@ -389,6 +389,82 @@ void RunModeException(struct pt_regs *re
 #define INST_MCRXR		0x7c000400
 #define INST_MCRXR_MASK		0x7c0007fe
 
+#define INST_STRING		0x7c00042a
+#define INST_STRING_MASK	0x7c0007fe
+#define INST_STRING_GEN_MASK	0x7c00067e
+#define INST_LSWI		0x7c0004aa
+#define INST_LSWX		0x7c00042a
+#define INST_STSWI		0x7c0005aa
+#define INST_STSWX		0x7c00052a
+
+static int emulate_string_inst(struct pt_regs *regs, u32 instword)
+{
+	u8 rT = (instword >> 21) & 0x1f;
+	u8 rA = (instword >> 16) & 0x1f;
+	u8 NB_RB = (instword >> 11) & 0x1f;
+	u32 num_bytes;
+	unsigned long EA;
+	int pos = 0;
+
+	/* Early out if we are an invalid form of lswx */
+	if ((instword & INST_STRING_MASK) == INST_LSWX)
+		if ((rT == rA) || (rT == NB_RB))
+			return -EINVAL;
+
+	EA = (rA == 0) ? 0 : regs->gpr[rA];
+
+	switch (instword & INST_STRING_MASK) {
+		case INST_LSWX:
+		case INST_STSWX:
+			EA += NB_RB;
+			num_bytes = regs->xer & 0x7f;
+			break;
+		case INST_LSWI:
+		case INST_STSWI:
+			num_bytes = (NB_RB == 0) ? 32 : NB_RB;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	while (num_bytes != 0)
+	{
+		u8 val;
+		u32 shift = 8 * (3 - (pos & 0x3));
+
+		switch ((instword & INST_STRING_MASK)) {
+			case INST_LSWX:
+			case INST_LSWI:
+				if (get_user(val, (u8 __user *)EA))
+					return -EFAULT;
+				/* first time updating this reg,
+				 * zero it out */
+				if (pos == 0)
+					regs->gpr[rT] = 0;
+				regs->gpr[rT] |= val << shift;
+				break;
+			case INST_STSWI:
+			case INST_STSWX:
+				val = regs->gpr[rT] >> shift;
+				if (put_user(val, (u8 __user *)EA))
+					return -EFAULT;
+				break;
+		}
+		/* move EA to next address */
+		EA += 1;
+		num_bytes--;
+
+		/* manage our position within the register */
+		if (++pos == 4) {
+			pos = 0;
+			if (++rT == 32)
+				rT = 0;
+		}
+	}
+
+	return 0;
+}
+
 static int emulate_instruction(struct pt_regs *regs)
 {
 	u32 instword;
@@ -405,7 +481,7 @@ static int emulate_instruction(struct pt
 	 */
 	if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
 		rd = (instword >> 21) & 0x1f;
-		regs->gpr[rd] = mfspr(PVR);
+		regs->gpr[rd] = mfspr(SPRN_PVR);
 		return 0;
 	}
 
@@ -423,6 +499,10 @@ static int emulate_instruction(struct pt
 		return 0;
 	}
 
+	/* Emulate load/store string insn. */
+	if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
+		return emulate_string_inst(regs, instword);
+
 	return -EINVAL;
 }
 
@@ -594,6 +674,7 @@ void AlignmentException(struct pt_regs *
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
 		regs->nip += 4;	/* skip over emulated instruction */
+		emulate_single_step(regs);
 		return;
 	}
 	if (fixed == -EFAULT) {
@@ -720,6 +801,13 @@ void AltivecAssistException(struct pt_re
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
 	preempt_enable();
+	if (!user_mode(regs)) {
+		printk(KERN_ERR "altivec assist exception in kernel mode"
+		       " at %lx\n", regs->nip);
+		debugger(regs);
+		die("altivec assist exception", regs, SIGFPE);
+		return;
+	}
 
 	err = emulate_altivec(regs);
 	if (err == 0) {
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -74,6 +74,12 @@ SECTIONS
     CONSTRUCTORS
   }
 
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
@@ -139,6 +145,7 @@ SECTIONS
   __init_end = .;
 
   . = ALIGN(4096);
+  _sextratext = .;
   __pmac_begin = .;
   .pmac.text : { *(.pmac.text) }
   .pmac.data : { *(.pmac.data) }
@@ -165,6 +172,7 @@ SECTIONS
   .openfirmware.data : { *(.openfirmware.data) }
   . = ALIGN(4096);
   __openfirmware_end = .;
+  _eextratext = .;
 
   __bss_start = .;
   .bss       :
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
--- a/arch/ppc/lib/string.S
+++ b/arch/ppc/lib/string.S
@@ -446,6 +446,7 @@ _GLOBAL(__copy_tofrom_user)
 #ifdef CONFIG_8xx
 	/* Don't use prefetch on 8xx */
 	mtctr	r0
+	li	r0,0
 53:	COPY_16_BYTES_WITHEX(0)
 	bdnz	53b
 
@@ -564,7 +565,9 @@ _GLOBAL(__copy_tofrom_user)
 /* or write fault in cacheline loop */
 105:	li	r9,1
 92:	li	r3,LG_CACHELINE_BYTES
-	b	99f
+	mfctr	r8
+	add	r0,r0,r8
+	b	106f
 /* read fault in final word loop */
 108:	li	r9,0
 	b	93f
@@ -585,7 +588,7 @@ _GLOBAL(__copy_tofrom_user)
  * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
  */
 99:	mfctr	r0
-	slw	r3,r0,r3
+106:	slw	r3,r0,r3
 	add.	r3,r3,r5
 	beq	120f			/* shouldn't happen */
 	cmpwi	0,r9,0
diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
--- a/arch/ppc/mm/hashtable.S
+++ b/arch/ppc/mm/hashtable.S
@@ -101,7 +101,7 @@ _GLOBAL(hash_page)
 	/* Get PTE (linux-style) and check access */
 	lis	r0,KERNELBASE@h		/* check if kernel address */
 	cmplw	0,r4,r0
-	mfspr	r8,SPRG3		/* current task's THREAD (phys) */
+	mfspr	r8,SPRN_SPRG3		/* current task's THREAD (phys) */
 	ori	r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
 	lwz	r5,PGDIR(r8)		/* virt page-table root */
 	blt+	112f			/* assume user more likely */
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -179,6 +179,7 @@ void free_initmem(void)
 	if (!have_of)
 		FREESEC(openfirmware);
  	printk("\n");
+	ppc_md.progress = NULL;
 #undef FREESEC
 }
 
@@ -490,18 +491,6 @@ void __init mem_init(void)
 		printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page);
 #endif
 
-	/* Make sure all our pagetable pages have page->mapping
-	   and page->index set correctly. */
-	for (addr = KERNELBASE; addr != 0; addr += PGDIR_SIZE) {
-		struct page *pg;
-		pmd_t *pmd = pmd_offset(pgd_offset_k(addr), addr);
-		if (pmd_present(*pmd)) {
-			pg = pmd_page(*pmd);
-			pg->mapping = (void *) &init_mm;
-			pg->index = addr;
-		}
-	}
-
 	mem_init_done = 1;
 }
 
@@ -653,3 +642,27 @@ void update_mmu_cache(struct vm_area_str
 	}
 #endif
 }
+
+/*
+ * This is called by /dev/mem to know if a given address has to
+ * be mapped non-cacheable or not
+ */
+int page_is_ram(unsigned long pfn)
+{
+	unsigned long paddr = (pfn << PAGE_SHIFT);
+
+	return paddr < __pa(high_memory);
+}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+			      unsigned long size, pgprot_t vma_prot)
+{
+	if (ppc_md.phys_mem_access_prot)
+		return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+
+	if (!page_is_ram(addr >> PAGE_SHIFT))
+		vma_prot = __pgprot(pgprot_val(vma_prot)
+				    | _PAGE_GUARDED | _PAGE_NO_CACHE);
+	return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h
--- a/arch/ppc/mm/mmu_decl.h
+++ b/arch/ppc/mm/mmu_decl.h
@@ -75,7 +75,7 @@ static inline void flush_HPTE(unsigned c
 			      unsigned long pdval)
 {
 	if ((Hash != 0) &&
-	    (cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE))
+	    cpu_has_feature(CPU_FTR_HPTE_TABLE))
 		flush_hash_pages(0, va, pdval, 1);
 	else
 		_tlbie(va);
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -74,7 +74,7 @@ extern unsigned long p_mapped_by_tlbcam(
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_44x
+#ifdef CONFIG_PTE_64BIT
 /* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
 #define PGDIR_ORDER	1
 #else
@@ -102,11 +102,6 @@ pte_t *pte_alloc_one_kernel(struct mm_st
 
 	if (mem_init_done) {
 		pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
-		if (pte) {
-			struct page *ptepage = virt_to_page(pte);
-			ptepage->mapping = (void *) mm;
-			ptepage->index = address & PMD_MASK;
-		}
 	} else {
 		pte = (pte_t *)early_get_page();
 		if (pte)
@@ -126,11 +121,8 @@ struct page *pte_alloc_one(struct mm_str
 #endif
 
 	ptepage = alloc_pages(flags, 0);
-	if (ptepage) {
-		ptepage->mapping = (void *) mm;
-		ptepage->index = address & PMD_MASK;
+	if (ptepage)
 		clear_highpage(ptepage);
-	}
 	return ptepage;
 }
 
@@ -139,7 +131,6 @@ void pte_free_kernel(pte_t *pte)
 #ifdef CONFIG_SMP
 	hash_page_sync();
 #endif
-	virt_to_page(pte)->mapping = NULL;
 	free_page((unsigned long)pte);
 }
 
@@ -148,17 +139,16 @@ void pte_free(struct page *ptepage)
 #ifdef CONFIG_SMP
 	hash_page_sync();
 #endif
-	ptepage->mapping = NULL;
 	__free_page(ptepage);
 }
 
-#ifndef CONFIG_44x
+#ifndef CONFIG_PHYS_64BIT
 void __iomem *
 ioremap(phys_addr_t addr, unsigned long size)
 {
 	return __ioremap(addr, size, _PAGE_NO_CACHE);
 }
-#else /* CONFIG_44x */
+#else /* CONFIG_PHYS_64BIT */
 void __iomem *
 ioremap64(unsigned long long addr, unsigned long size)
 {
@@ -172,7 +162,7 @@ ioremap(phys_addr_t addr, unsigned long 
 
 	return ioremap64(addr64, size);
 }
-#endif /* CONFIG_44x */
+#endif /* CONFIG_PHYS_64BIT */
 
 void __iomem *
 __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
@@ -203,7 +193,7 @@ __ioremap(phys_addr_t addr, unsigned lon
 	 */
 	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
 	{
-		printk("__ioremap(): phys addr "PTE_FMT" is RAM lr %p\n", p,
+		printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
 		       __builtin_return_address(0));
 		return NULL;
 	}
@@ -298,7 +288,7 @@ map_page(unsigned long va, phys_addr_t p
 	pg = pte_alloc_kernel(&init_mm, pd, va);
 	if (pg != 0) {
 		err = 0;
-		set_pte(pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
+		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
 		if (mem_init_done)
 			flush_HPTE(0, va, pmd_val(*pd));
 	}
diff --git a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c
+++ b/arch/ppc/mm/ppc_mmu.c
@@ -138,11 +138,11 @@ void __init setbat(int index, unsigned l
 	union ubat *bat = BATS[index];
 
 	if (((flags & _PAGE_NO_CACHE) == 0) &&
-	    (cur_cpu_spec[0]->cpu_features & CPU_FTR_NEED_COHERENT))
+	    cpu_has_feature(CPU_FTR_NEED_COHERENT))
 		flags |= _PAGE_COHERENT;
 
 	bl = (size >> 17) - 1;
-	if (PVR_VER(mfspr(PVR)) != 1) {
+	if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
 		/* 603, 604, etc. */
 		/* Do DBAT first */
 		wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
@@ -191,7 +191,7 @@ void __init MMU_init_hw(void)
 	extern unsigned int hash_page[];
 	extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
 
-	if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE) == 0) {
+	if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) {
 		/*
 		 * Put a blr (procedure return) instruction at the
 		 * start of hash_page, since we can still get DSI
diff --git a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c
--- a/arch/ppc/mm/tlb.c
+++ b/arch/ppc/mm/tlb.c
@@ -47,26 +47,6 @@ void flush_hash_entry(struct mm_struct *
 }
 
 /*
- * Called by ptep_test_and_clear_young()
- */
-void flush_hash_one_pte(pte_t *ptep)
-{
-	struct page *ptepage;
-	struct mm_struct *mm;
-	unsigned long ptephys;
-	unsigned long addr;
-
-	if (Hash == 0)
-		return;
-	
-	ptepage = virt_to_page(ptep);
-	mm = (struct mm_struct *) ptepage->mapping;
-	ptephys = __pa(ptep) & PAGE_MASK;
-	addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 10);
-	flush_hash_pages(mm->context, addr, ptephys, 1);
-}
-
-/*
  * Called by ptep_set_access_flags, must flush on CPUs for which the
  * DSI handler can't just "fixup" the TLB on a write fault
  */
diff --git a/arch/ppc/oprofile/op_model_fsl_booke.c b/arch/ppc/oprofile/op_model_fsl_booke.c
--- a/arch/ppc/oprofile/op_model_fsl_booke.c
+++ b/arch/ppc/oprofile/op_model_fsl_booke.c
@@ -150,7 +150,6 @@ static void fsl_booke_handle_interrupt(s
 	int is_kernel;
 	int val;
 	int i;
-	unsigned int cpu = smp_processor_id();
 
 	/* set the PMM bit (see comment below) */
 	mtmsr(mfmsr() | MSR_PMM);
@@ -162,7 +161,7 @@ static void fsl_booke_handle_interrupt(s
 		val = ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
-				oprofile_add_sample(pc, is_kernel, i, cpu);
+				oprofile_add_pc(pc, is_kernel, i);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
--- a/arch/ppc/platforms/4xx/ebony.c
+++ b/arch/ppc/platforms/4xx/ebony.c
@@ -49,8 +49,19 @@
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
 #include <asm/ppc4xx_pic.h>
+#include <asm/ppcboot.h>
 
 #include <syslib/gen550.h>
+#include <syslib/ibm440gp_common.h>
+
+/*
+ * This is a horrible kludge, we eventually need to abstract this
+ * generic PHY stuff, so the  standard phy mode defines can be
+ * easily used from arch code.
+ */
+#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
+
+bd_t __res;
 
 static struct ibm44x_clocks clocks __initdata;
 
@@ -86,7 +97,7 @@ ebony_calibrate_decr(void)
 	 * on Rev. C silicon then errata forces us to
 	 * use the internal clock.
 	 */
-	switch (PVR_REV(mfspr(PVR))) {
+	switch (PVR_REV(mfspr(SPRN_PVR))) {
 		case PVR_REV(PVR_440GP_RB):
 			freq = EBONY_440GP_RB_SYSCLK;
 			break;
@@ -138,7 +149,7 @@ ebony_map_irq(struct pci_dev *dev, unsig
 static void __init
 ebony_setup_pcix(void)
 {
-	void *pcix_reg_base;
+	void __iomem *pcix_reg_base;
 
 	pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE);
 
@@ -199,9 +210,8 @@ ebony_setup_hose(void)
 	hose->io_space.end = EBONY_PCI_UPPER_IO;
 	hose->mem_space.start = EBONY_PCI_LOWER_MEM;
 	hose->mem_space.end = EBONY_PCI_UPPER_MEM;
-	isa_io_base =
-		(unsigned long)ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE);
-	hose->io_base_virt = (void *)isa_io_base;
+	hose->io_base_virt = ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE);
+	isa_io_base = (unsigned long)hose->io_base_virt;
 
 	setup_indirect_pci(hose,
 			EBONY_PCI_CFGA_PLB32,
@@ -258,19 +268,21 @@ ebony_early_serial_map(void)
 static void __init
 ebony_setup_arch(void)
 {
-	unsigned char * vpd_base;
 	struct ocp_def *def;
 	struct ocp_func_emac_data *emacdata;
 
 	/* Set mac_addr for each EMAC */
-	vpd_base = ioremap64(EBONY_VPD_BASE, EBONY_VPD_SIZE);
 	def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
 	emacdata = def->additions;
-	memcpy(emacdata->mac_addr, EBONY_NA0_ADDR(vpd_base), 6);
+	emacdata->phy_map = 0x00000001;	/* Skip 0x00 */
+	emacdata->phy_mode = PHY_MODE_RMII;
+	memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
+
 	def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1);
 	emacdata = def->additions;
-	memcpy(emacdata->mac_addr, EBONY_NA1_ADDR(vpd_base), 6);
-	iounmap(vpd_base);
+	emacdata->phy_map = 0x00000001;	/* Skip 0x00 */
+	emacdata->phy_mode = PHY_MODE_RMII;
+	memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
 
 	/*
 	 * Determine various clocks.
@@ -314,7 +326,14 @@ ebony_setup_arch(void)
 void __init platform_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7)
 {
-	parse_bootinfo((struct bi_record *) (r3 + KERNELBASE));
+	parse_bootinfo(find_bootinfo());
+
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3)
+		__res = *(bd_t *)(r3 + KERNELBASE);
 
 	ibm44x_platform_init();
 
diff --git a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h
--- a/arch/ppc/platforms/4xx/ebony.h
+++ b/arch/ppc/platforms/4xx/ebony.h
@@ -23,13 +23,9 @@
 /* F/W TLB mapping used in bootloader glue to reset EMAC */
 #define PPC44x_EMAC0_MR0	0xE0000800
 
-/* Macros to get at Ebony VPD info */
-#define EBONY_VPD_BASE		0x00000001fffffe00ULL
-#define EBONY_VPD_SIZE		0x24
-#define EBONY_NA0_OFFSET	0x0c
-#define EBONY_NA1_OFFSET	0x18
-#define EBONY_NA0_ADDR(base)	(base + EBONY_NA0_OFFSET)
-#define EBONY_NA1_ADDR(base)	(base + EBONY_NA1_OFFSET)
+/* Where to find the MAC info */
+#define EBONY_OPENBIOS_MAC_BASE   0xfffffe0c
+#define EBONY_OPENBIOS_MAC_OFFSET 0x0c
 
 /* Default clock rates for Rev. B and Rev. C silicon */
 #define EBONY_440GP_RB_SYSCLK	33000000
@@ -61,8 +57,8 @@
  */
 
 /* OpenBIOS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE	(u8 *) 0xE0000200
-#define UART1_IO_BASE	(u8 *) 0xE0000300
+#define UART0_IO_BASE	0xE0000200
+#define UART1_IO_BASE	0xE0000300
 
 /* external Epson SG-615P */
 #define BASE_BAUD	691200
diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
--- a/arch/ppc/platforms/4xx/luan.c
+++ b/arch/ppc/platforms/4xx/luan.c
@@ -223,9 +223,8 @@ luan_setup_hose(struct pci_controller *h
 	hose->io_space.end = LUAN_PCIX_UPPER_IO;
 	hose->mem_space.start = lower_mem;
 	hose->mem_space.end = upper_mem;
-	isa_io_base =
-		(unsigned long)ioremap64(pcix_io_base, PCIX_IO_SIZE);
-	hose->io_base_virt = (void *)isa_io_base;
+	hose->io_base_virt = ioremap64(pcix_io_base, PCIX_IO_SIZE);
+	isa_io_base = (unsigned long) hose->io_base_virt;
 
 	setup_indirect_pci(hose, cfga, cfgd);
 	hose->set_cfg_type = 1;
diff --git a/arch/ppc/platforms/4xx/luan.h b/arch/ppc/platforms/4xx/luan.h
--- a/arch/ppc/platforms/4xx/luan.h
+++ b/arch/ppc/platforms/4xx/luan.h
@@ -47,9 +47,9 @@
 #define RS_TABLE_SIZE	3
 
 /* PIBS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE	(u8 *) 0xa0000200
-#define UART1_IO_BASE	(u8 *) 0xa0000300
-#define UART2_IO_BASE	(u8 *) 0xa0000600
+#define UART0_IO_BASE	0xa0000200
+#define UART1_IO_BASE	0xa0000300
+#define UART2_IO_BASE	0xa0000600
 
 #define BASE_BAUD	11059200
 #define STD_UART_OP(num)					\
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -227,9 +227,8 @@ ocotea_setup_hose(void)
 	hose->io_space.end = OCOTEA_PCI_UPPER_IO;
 	hose->mem_space.start = OCOTEA_PCI_LOWER_MEM;
 	hose->mem_space.end = OCOTEA_PCI_UPPER_MEM;
-	isa_io_base =
-		(unsigned long)ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE);
-	hose->io_base_virt = (void *)isa_io_base;
+	hose->io_base_virt = ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE);
+	isa_io_base = (unsigned long) hose->io_base_virt;
 
 	setup_indirect_pci(hose,
 			OCOTEA_PCI_CFGA_PLB32,
diff --git a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h
--- a/arch/ppc/platforms/4xx/ocotea.h
+++ b/arch/ppc/platforms/4xx/ocotea.h
@@ -56,8 +56,8 @@
 #define RS_TABLE_SIZE	2
 
 /* OpenBIOS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE	(u8 *) 0xE0000200
-#define UART1_IO_BASE	(u8 *) 0xE0000300
+#define UART0_IO_BASE	0xE0000200
+#define UART1_IO_BASE	0xE0000300
 
 #define BASE_BAUD	11059200/16
 #define STD_UART_OP(num)					\
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
--- a/arch/ppc/platforms/4xx/xilinx_ml300.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -122,25 +122,7 @@ ml300_setup_arch(void)
 void __init
 ml300_init_irq(void)
 {
-	unsigned int i;
-
 	ppc4xx_init_IRQ();
-
-	/*
-	 * For PowerPC 405 cores the default value for NR_IRQS is 32.
-	 * See include/asm-ppc/irq.h for details.
-	 * This is just fine for ML300.
-	 */
-#if (NR_IRQS != 32)
-#error NR_IRQS must be 32 for ML300
-#endif
-
-	for (i = 0; i < NR_IRQS; i++) {
-		if (XPAR_INTC_0_KIND_OF_INTR & (0x80000000 >> i))
-			irq_desc[i].status &= ~IRQ_LEVEL;
-		else
-			irq_desc[i].status |= IRQ_LEVEL;
-	}
 }
 
 void __init
diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/83xx/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the PowerPC 83xx linux kernel.
+#
+obj-$(CONFIG_MPC834x_SYS)	+= mpc834x_sys.o
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -0,0 +1,288 @@
+/*
+ * arch/ppc/platforms/83xx/mpc834x_sys.c
+ *
+ * MPC834x SYS board specific routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#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/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>	/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc83xx.h>
+#include <asm/irq.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc83xx_setup.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory;	/* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+#ifdef CONFIG_PCI
+#error "PCI is not supported"
+/* NEED mpc83xx_map_irq & mpc83xx_exclude_device
+   see platforms/85xx/mpc85xx_ads_common.c */
+#endif /* CONFIG_PCI */
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc834x_sys_setup_arch(void)
+{
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+	struct gianfar_platform_data *pdata;
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+	/* setup PCI host bridges */
+	mpc83xx_sys_setup_hose();
+#endif
+	mpc83xx_early_serial_map();
+
+	/* setup the board related information for the enet controllers */
+	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
+	pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+	pdata->interruptPHY = MPC83xx_IRQ_EXT1;
+	pdata->phyid = 0;
+	/* fixup phy address */
+	pdata->phy_reg_addr += binfo->bi_immr_base;
+	memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
+	pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+	pdata->interruptPHY = MPC83xx_IRQ_EXT2;
+	pdata->phyid = 1;
+	/* fixup phy address */
+	pdata->phy_reg_addr += binfo->bi_immr_base;
+	memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_HDA1;
+#endif
+}
+
+static void __init
+mpc834x_sys_map_io(void)
+{
+	/* we steal the lowest ioremap addr for virt space */
+	io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO);
+}
+
+int
+mpc834x_sys_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+
+	seq_printf(m, "Vendor\t\t: Freescale Inc.\n");
+	seq_printf(m, "Machine\t\t: mpc%s sys\n", cur_ppc_sys_spec->ppc_sys_name);
+	seq_printf(m, "core clock\t: %d MHz\n"
+			"bus  clock\t: %d MHz\n",
+			(int)(binfo->bi_intfreq / 1000000),
+			(int)(binfo->bi_busfreq / 1000000));
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", (int)(binfo->bi_memsize / (1024 * 1024)));
+
+	return 0;
+}
+
+
+void __init
+mpc834x_sys_init_IRQ(void)
+{
+	bd_t *binfo = (bd_t *) __res;
+
+	u8 senses[8] = {
+		0,			/* EXT 0 */
+		IRQ_SENSE_LEVEL,	/* EXT 1 */
+		IRQ_SENSE_LEVEL,	/* EXT 2 */
+		0,			/* EXT 3 */
+		0,			/* EXT 4 */
+		0,			/* EXT 5 */
+		0,			/* EXT 6 */
+		0,			/* EXT 7 */
+	};
+
+	ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8);
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	ipic_set_default_priority();
+}
+
+static __inline__ void
+mpc834x_sys_set_bat(void)
+{
+	/* we steal the lowest ioremap addr for virt space */
+	mb();
+	mtspr(SPRN_DBAT1U, VIRT_IMMRBAR | 0x1e);
+	mtspr(SPRN_DBAT1L, immrbar | 0x2a);
+	mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	bd_t *binfo = (bd_t *) __res;
+
+	/* parse_bootinfo must always be called first */
+	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));
+	}
+
+	immrbar = binfo->bi_immr_base;
+
+	mpc834x_sys_set_bat();
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+	{
+		struct uart_port p;
+
+		memset(&p, 0, sizeof (p));
+		p.iotype = SERIAL_IO_MEM;
+		p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4500);
+		p.uartclk = binfo->bi_busfreq;
+
+		gen550_init(0, &p);
+
+		memset(&p, 0, sizeof (p));
+		p.iotype = SERIAL_IO_MEM;
+		p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4600);
+		p.uartclk = binfo->bi_busfreq;
+
+		gen550_init(1, &p);
+	}
+#endif
+
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+	/* setup the PowerPC module struct */
+	ppc_md.setup_arch = mpc834x_sys_setup_arch;
+	ppc_md.show_cpuinfo = mpc834x_sys_show_cpuinfo;
+
+	ppc_md.init_IRQ = mpc834x_sys_init_IRQ;
+	ppc_md.get_irq = ipic_get_irq;
+
+	ppc_md.restart = mpc83xx_restart;
+	ppc_md.power_off = mpc83xx_power_off;
+	ppc_md.halt = mpc83xx_halt;
+
+	ppc_md.find_end_of_memory = mpc83xx_find_end_of_memory;
+	ppc_md.setup_io_mappings  = mpc834x_sys_map_io;
+
+	ppc_md.time_init = mpc83xx_time_init;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = mpc83xx_calibrate_decr;
+
+	ppc_md.early_serial_map = mpc83xx_early_serial_map;
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+	ppc_md.progress = gen550_progress;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc834x_sys_init(): exit", 0);
+
+	return;
+}
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -0,0 +1,56 @@
+/*
+ * arch/ppc/platforms/83xx/mpc834x_sys.h
+ *
+ * MPC834X SYS common board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ *
+ */
+
+#ifndef __MACH_MPC83XX_SYS_H__
+#define __MACH_MPC83XX_SYS_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <syslib/ppc83xx_setup.h>
+#include <asm/ppcboot.h>
+
+#define VIRT_IMMRBAR		((uint)0xfe000000)
+
+#define BCSR_PHYS_ADDR		((uint)0xf8000000)
+#define BCSR_SIZE		((uint)(32 * 1024))
+
+#define BCSR_MISC_REG2_OFF	0x07
+#define BCSR_MISC_REG2_PORESET	0x01
+
+#define BCSR_MISC_REG3_OFF	0x08
+#define BCSR_MISC_REG3_CNFLOCK	0x80
+
+#ifdef CONFIG_PCI
+/* PCI interrupt controller */
+#define PIRQA        MPC83xx_IRQ_IRQ4
+#define PIRQB        MPC83xx_IRQ_IRQ5
+#define PIRQC        MPC83xx_IRQ_IRQ6
+#define PIRQD        MPC83xx_IRQ_IRQ7
+
+#define MPC834x_SYS_PCI1_LOWER_IO        0x00000000
+#define MPC834x_SYS_PCI1_UPPER_IO        0x00ffffff
+
+#define MPC834x_SYS_PCI1_LOWER_MEM       0x80000000
+#define MPC834x_SYS_PCI1_UPPER_MEM       0x9fffffff
+
+#define MPC834x_SYS_PCI1_IO_BASE         0xe2000000
+#define MPC834x_SYS_PCI1_MEM_OFFSET      0x00000000
+
+#define MPC834x_SYS_PCI1_IO_SIZE         0x01000000
+#endif /* CONFIG_PCI */
+
+#endif                /* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
--- a/arch/ppc/platforms/85xx/Makefile
+++ b/arch/ppc/platforms/85xx/Makefile
@@ -1,8 +1,6 @@
 #
 # Makefile for the PowerPC 85xx linux kernel.
 #
-obj-$(CONFIG_85xx)		+= mpc85xx_sys.o mpc85xx_devices.o
-
 obj-$(CONFIG_MPC8540_ADS)	+= mpc85xx_ads_common.o mpc8540_ads.o
 obj-$(CONFIG_MPC8555_CDS)	+= mpc85xx_cds_common.o
 obj-$(CONFIG_MPC8560_ADS)	+= mpc85xx_ads_common.o mpc8560_ads.o
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -109,7 +109,7 @@ mpc8540ads_setup_arch(void)
 	memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
-	pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+	pdata->board_flags = 0;
 	pdata->interruptPHY = MPC85xx_IRQ_EXT5;
 	pdata->phyid = 3;
 	/* fixup phy address */
@@ -187,7 +187,7 @@ platform_init(unsigned long r3, unsigned
 		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
 	}
 
-	identify_ppc_sys_by_id(mfspr(SVR));
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
 
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = mpc8540ads_setup_arch;
@@ -210,6 +210,9 @@ platform_init(unsigned long r3, unsigned
 #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
 	ppc_md.progress = gen550_progress;
 #endif	/* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+	ppc_md.early_serial_map = mpc85xx_early_serial_map;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_KGDB */
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc8540ads_init(): exit", 0);
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -135,25 +135,11 @@ static struct irqaction cpm2_irqaction =
 static void __init
 mpc8560_ads_init_IRQ(void)
 {
-	int i;
-	volatile cpm2_map_t *immap = cpm2_immr;
-
 	/* Setup OpenPIC */
 	mpc85xx_ads_init_IRQ();
 
-	/* disable all CPM interupts */
-	immap->im_intctl.ic_simrh = 0x0;
-	immap->im_intctl.ic_simrl = 0x0;
-
-	for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
-		irq_desc[i].handler = &cpm2_pic;
-
-	/* Initialize the default interrupt mapping priorities,
-	 * in case the boot rom changed something on us.
-	 */
-	immap->im_intctl.ic_sicr = 0;
-	immap->im_intctl.ic_scprrh = 0x05309770;
-	immap->im_intctl.ic_scprrl = 0x05309770;
+	/* Setup CPM2 PIC */
+        cpm2_init_IRQ();
 
 	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
 
@@ -197,7 +183,7 @@ platform_init(unsigned long r3, unsigned
 		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
 	}
 
-	identify_ppc_sys_by_id(mfspr(SVR));
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
 
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = mpc8560ads_setup_arch;
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -43,6 +43,7 @@
 #include <asm/mpc85xx.h>
 #include <asm/irq.h>
 #include <asm/immap_85xx.h>
+#include <asm/ppc_sys.h>
 
 #include <mm/mmu_decl.h>
 
@@ -125,28 +126,17 @@ mpc85xx_ads_show_cpuinfo(struct seq_file
 	/* get the core frequency */
 	freq = binfo->bi_intfreq;
 
-	pvid = mfspr(PVR);
-	svid = mfspr(SVR);
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
 
 	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
-
-	switch (svid & 0xffff0000) {
-	case SVR_8540:
-		seq_printf(m, "Machine\t\t: mpc8540ads\n");
-		break;
-	case SVR_8560:
-		seq_printf(m, "Machine\t\t: mpc8560ads\n");
-		break;
-	default:
-		seq_printf(m, "Machine\t\t: unknown\n");
-		break;
-	}
+	seq_printf(m, "Machine\t\t: mpc%sads\n", cur_ppc_sys_spec->ppc_sys_name);
 	seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
 	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
 	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
 	/* Display cpu Pll setting */
-	phid1 = mfspr(HID1);
+	phid1 = mfspr(SPRN_HID1);
 	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 
 	/* Display the amount of memory */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -39,10 +39,12 @@
 #include <asm/page.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
+#include <asm/todc.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/open_pic.h>
+#include <asm/i8259.h>
 #include <asm/bootinfo.h>
 #include <asm/pci-bridge.h>
 #include <asm/mpc85xx.h>
@@ -73,60 +75,60 @@ static volatile u8 * cadmus;
 /* Internal interrupts are all Level Sensitive, and Positive Polarity */
 
 static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  0: L2 Cache */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  1: ECM */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  2: DDR DRAM */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  3: LBIU */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  4: DMA 0 */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  5: DMA 1 */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  6: DMA 2 */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  7: DMA 3 */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  8: PCI/PCI-X */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  9: RIO Inbound Port Write Error */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 10: RIO Doorbell Inbound */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 11: RIO Outbound Message */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 12: RIO Inbound Message */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 13: TSEC 0 Transmit */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 14: TSEC 0 Receive */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 15: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 16: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 17: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 18: TSEC 0 Receive/Transmit Error */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 19: TSEC 1 Transmit */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 20: TSEC 1 Receive */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 21: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 22: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 23: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 24: TSEC 1 Receive/Transmit Error */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 25: Fast Ethernet */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 26: DUART */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 27: I2C */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 28: Performance Monitor */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 29: Unused */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 30: CPM */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 31: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  0: L2 Cache */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  1: ECM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  2: DDR DRAM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  3: LBIU */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  4: DMA 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  5: DMA 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  6: DMA 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  7: DMA 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  8: PCI/PCI-X */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  9: RIO Inbound Port Write Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 10: RIO Doorbell Inbound */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 11: RIO Outbound Message */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 12: RIO Inbound Message */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 13: TSEC 0 Transmit */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 14: TSEC 0 Receive */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 15: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 16: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 17: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 18: TSEC 0 Receive/Transmit Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 19: TSEC 1 Transmit */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 20: TSEC 1 Receive */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 21: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 22: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 23: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 24: TSEC 1 Receive/Transmit Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 25: Fast Ethernet */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 26: DUART */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 27: I2C */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 28: Performance Monitor */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 29: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 30: CPM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 31: Unused */
 #if defined(CONFIG_PCI)
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 0: PCI1 slot */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 1: PCI1 slot */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 2: PCI1 slot */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 3: PCI1 slot */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 0: PCI1 slot */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 1: PCI1 slot */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 2: PCI1 slot */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 3: PCI1 slot */
 #else
-        0x0,                            /* External  0: */
-        0x0,                            /* External  1: */
-        0x0,                            /* External  2: */
-        0x0,                            /* External  3: */
-#endif
-        0x0,                            /* External  4: */
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 5: PHY */
-        0x0,                            /* External  6: */
-        0x0,                            /* External  7: */
-        0x0,                            /* External  8: */
-        0x0,                            /* External  9: */
-        0x0,                            /* External 10: */
+	0x0,						/* External  0: */
+	0x0,						/* External  1: */
+	0x0,						/* External  2: */
+	0x0,						/* External  3: */
+#endif
+	0x0,						/* External  4: */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External  5: PHY */
+	0x0,						/* External  6: */
+	0x0,						/* External  7: */
+	0x0,						/* External  8: */
+	0x0,						/* External  9: */
+	0x0,						/* External 10: */
 #if defined(CONFIG_85xx_PCI2) && defined(CONFIG_PCI)
-        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 11: PCI2 slot 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 11: PCI2 slot 0 */
 #else
-        0x0,                            /* External 11: */
+	0x0,						/* External 11: */
 #endif
 };
 
@@ -134,31 +136,31 @@ static u_char mpc85xx_cds_openpic_initse
 int
 mpc85xx_cds_show_cpuinfo(struct seq_file *m)
 {
-        uint pvid, svid, phid1;
-        uint memsize = total_memory;
-        bd_t *binfo = (bd_t *) __res;
-        unsigned int freq;
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
 
-        /* get the core frequency */
-        freq = binfo->bi_intfreq;
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
 
-        pvid = mfspr(PVR);
-        svid = mfspr(SVR);
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
 
-        seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
-	seq_printf(m, "Machine\t\t: CDS (%x)\n", cadmus[CM_VER]);
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+	seq_printf(m, "Machine\t\t: CDS - MPC%s (%x)\n", cur_ppc_sys_spec->ppc_sys_name, cadmus[CM_VER]);
 	seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
-        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
-        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
-        /* Display cpu Pll setting */
-        phid1 = mfspr(HID1);
-        seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 
-        /* Display the amount of memory */
-        seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
 
-        return 0;
+	return 0;
 }
 
 #ifdef CONFIG_CPM2
@@ -180,46 +182,41 @@ void __init
 mpc85xx_cds_init_IRQ(void)
 {
 	bd_t *binfo = (bd_t *) __res;
-#ifdef CONFIG_CPM2
-	volatile cpm2_map_t *immap = cpm2_immr;
 	int i;
-#endif
 
-        /* Determine the Physical Address of the OpenPIC regs */
-        phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
-        OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
-        OpenPIC_InitSenses = mpc85xx_cds_openpic_initsenses;
-        OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses);
-
-        /* Skip reserved space and internal sources */
-        openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
-        /* Map PIC IRQs 0-11 */
-        openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
-
-        /* we let openpic interrupts starting from an offset, to
-         * leave space for cascading interrupts underneath.
-         */
-        openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+	/* Determine the Physical Address of the OpenPIC regs */
+	phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+	OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+	OpenPIC_InitSenses = mpc85xx_cds_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses);
+
+	/* Skip reserved space and internal sources */
+	openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+	/* Map PIC IRQs 0-11 */
+	openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
 
-#ifdef CONFIG_CPM2
-	/* disable all CPM interupts */
-	immap->im_intctl.ic_simrh = 0x0;
-	immap->im_intctl.ic_simrl = 0x0;
+	/* we let openpic interrupts starting from an offset, to
+	 * leave space for cascading interrupts underneath.
+	 */
+	openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
 
-	for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
-		irq_desc[i].handler = &cpm2_pic;
+#ifdef CONFIG_PCI
+	openpic_hookup_cascade(PIRQ0A, "82c59 cascade", i8259_irq);
 
-	/* Initialize the default interrupt mapping priorities,
-	 * in case the boot rom changed something on us.
-	 */
-	immap->im_intctl.ic_sicr = 0;
-	immap->im_intctl.ic_scprrh = 0x05309770;
-	immap->im_intctl.ic_scprrl = 0x05309770;
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_init(0);
+#endif
+
+#ifdef CONFIG_CPM2
+	/* Setup CPM2 PIC */
+        cpm2_init_IRQ();
 
 	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
 #endif
 
-        return;
+	return;
 }
 
 #ifdef CONFIG_PCI
@@ -245,7 +242,7 @@ mpc85xx_map_irq(struct pci_dev *dev, uns
 			 * interrupt on slot */
 		{
 			{ 0, 1, 2, 3 }, /* 16 - PMC */
-			{ 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */
+			{ 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */
 			{ 0, 1, 2, 3 }, /* 18 - Slot 1 */
 			{ 1, 2, 3, 0 }, /* 19 - Slot 2 */
 			{ 2, 3, 0, 1 }, /* 20 - Slot 3 */
@@ -278,8 +275,8 @@ mpc85xx_map_irq(struct pci_dev *dev, uns
 	}
 }
 
-#define ARCADIA_HOST_BRIDGE_IDSEL     17
-#define ARCADIA_2ND_BRIDGE_IDSEL     3
+#define ARCADIA_HOST_BRIDGE_IDSEL	17
+#define ARCADIA_2ND_BRIDGE_IDSEL	3
 
 extern int mpc85xx_pci1_last_busno;
 
@@ -289,20 +286,144 @@ mpc85xx_exclude_device(u_char bus, u_cha
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 #ifdef CONFIG_85xx_PCI2
-	if (mpc85xx_pci1_last_busno) 
+	if (mpc85xx_pci1_last_busno)
 		if (bus == (mpc85xx_pci1_last_busno + 1) && PCI_SLOT(devfn) == 0)
 			return PCIBIOS_DEVICE_NOT_FOUND;
 #endif
 	/* We explicitly do not go past the Tundra 320 Bridge */
-	if (bus == 1)
+	if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	else
 		return PCIBIOS_SUCCESSFUL;
 }
+
+void __init
+mpc85xx_cds_enable_via(struct pci_controller *hose)
+{
+	u32 pci_class;
+	u16 vid, did;
+
+	early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class);
+	if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI)
+		return;
+
+	/* Configure P2P so that we can reach bus 1 */
+	early_write_config_byte(hose, 0, 0x88, PCI_PRIMARY_BUS, 0);
+	early_write_config_byte(hose, 0, 0x88, PCI_SECONDARY_BUS, 1);
+	early_write_config_byte(hose, 0, 0x88, PCI_SUBORDINATE_BUS, 0xff);
+
+	early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid);
+	early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did);
+
+	if ((vid != PCI_VENDOR_ID_VIA) ||
+			(did != PCI_DEVICE_ID_VIA_82C686))
+		return;
+
+	/* Enable USB and IDE functions */
+	early_write_config_byte(hose, 1, 0x10, 0x48, 0x08);
+}
+
+void __init
+mpc85xx_cds_fixup_via(struct pci_controller *hose)
+{
+	u32 pci_class;
+	u16 vid, did;
+
+	early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class);
+	if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI)
+		return;
+
+	/*
+	 * Force the backplane P2P bridge to have a window
+	 * open from 0x00000000-0x00001fff in PCI I/O space.
+	 * This allows legacy I/O (i8259, etc) on the VIA
+	 * southbridge to be accessed.
+	 */
+	early_write_config_byte(hose, 0, 0x88, PCI_IO_BASE, 0x00);
+	early_write_config_word(hose, 0, 0x88, PCI_IO_BASE_UPPER16, 0x0000);
+	early_write_config_byte(hose, 0, 0x88, PCI_IO_LIMIT, 0x10);
+	early_write_config_word(hose, 0, 0x88, PCI_IO_LIMIT_UPPER16, 0x0000);
+
+	early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid);
+	early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did);
+	if ((vid != PCI_VENDOR_ID_VIA) ||
+			(did != PCI_DEVICE_ID_VIA_82C686))
+		return;
+
+	/*
+	 * Since the P2P window was forced to cover the fixed
+	 * legacy I/O addresses, it is necessary to manually
+	 * place the base addresses for the IDE and USB functions
+	 * within this window.
+	 */
+	/* Function 1, IDE */
+	early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_0, 0x1ff8);
+	early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_1, 0x1ff4);
+	early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_2, 0x1fe8);
+	early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_3, 0x1fe4);
+	early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_4, 0x1fd0);
+
+	/* Function 2, USB ports 0-1 */
+	early_write_config_dword(hose, 1, 0x12, PCI_BASE_ADDRESS_4, 0x1fa0);
+
+	/* Function 3, USB ports 2-3 */
+	early_write_config_dword(hose, 1, 0x13, PCI_BASE_ADDRESS_4, 0x1f80);
+
+	/* Function 5, Power Management */
+	early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_0, 0x1e00);
+	early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_1, 0x1dfc);
+	early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_2, 0x1df8);
+
+	/* Function 6, AC97 Interface */
+	early_write_config_dword(hose, 1, 0x16, PCI_BASE_ADDRESS_0, 0x1c00);
+}
+
+void __init
+mpc85xx_cds_pcibios_fixup(void)
+{
+        struct pci_dev *dev = NULL;
+	u_char		c;
+
+        if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+                                        PCI_DEVICE_ID_VIA_82C586_1, NULL))) {
+                /*
+                 * U-Boot does not set the enable bits
+                 * for the IDE device. Force them on here.
+                 */
+                pci_read_config_byte(dev, 0x40, &c);
+                c |= 0x03; /* IDE: Chip Enable Bits */
+                pci_write_config_byte(dev, 0x40, c);
+
+		/*
+		 * Since only primary interface works, force the
+		 * IDE function to standard primary IDE interrupt
+		 * w/ 8259 offset
+		 */
+                dev->irq = 14;
+                pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+        }
+
+	/*
+	 * Force legacy USB interrupt routing
+	 */
+        if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+                                        PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
+                dev->irq = 10;
+                pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
+        }
+
+        if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+                                        PCI_DEVICE_ID_VIA_82C586_2, dev))) {
+                dev->irq = 11;
+                pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+        }
+}
 #endif /* CONFIG_PCI */
 
+TODC_ALLOC();
+
 /* ************************************************************************
  *
  * Setup the architecture
@@ -311,14 +432,14 @@ mpc85xx_exclude_device(u_char bus, u_cha
 static void __init
 mpc85xx_cds_setup_arch(void)
 {
-        bd_t *binfo = (bd_t *) __res;
-        unsigned int freq;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
 	struct gianfar_platform_data *pdata;
 
-        /* get the core frequency */
-        freq = binfo->bi_intfreq;
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
 
-        printk("mpc85xx_cds_setup_arch\n");
+	printk("mpc85xx_cds_setup_arch\n");
 
 #ifdef CONFIG_CPM2
 	cpm2_reset();
@@ -328,17 +449,27 @@ mpc85xx_cds_setup_arch(void)
 	cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
 	printk("CDS Version = %x in PCI slot %d\n", cadmus[CM_VER], cds_pci_slot);
 
-        /* Set loops_per_jiffy to a half-way reasonable value,
-           for use until calibrate_delay gets called. */
-        loops_per_jiffy = freq / HZ;
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1743,
+			0,
+			0,
+			ioremap(CDS_RTC_ADDR, CDS_RTC_SIZE),
+			8);
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	loops_per_jiffy = freq / HZ;
 
 #ifdef CONFIG_PCI
-        /* setup PCI host bridges */
-        mpc85xx_setup_hose();
+	/* VIA IDE configuration */
+        ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup;
+
+	/* setup PCI host bridges */
+	mpc85xx_setup_hose();
 #endif
 
 #ifdef CONFIG_SERIAL_8250
-        mpc85xx_early_serial_map();
+	mpc85xx_early_serial_map();
 #endif
 
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
@@ -366,14 +497,14 @@ mpc85xx_cds_setup_arch(void)
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
-        if (initrd_start)
-                ROOT_DEV = Root_RAM0;
-        else
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
 #endif
 #ifdef  CONFIG_ROOT_NFS
-                ROOT_DEV = Root_NFS;
+		ROOT_DEV = Root_NFS;
 #else
-                ROOT_DEV = Root_HDA1;
+	ROOT_DEV = Root_HDA1;
 #endif
 }
 
@@ -382,18 +513,18 @@ void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
               unsigned long r6, unsigned long r7)
 {
-        /* parse_bootinfo must always be called first */
-        parse_bootinfo(find_bootinfo());
+	/* parse_bootinfo must always be called first */
+	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 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));
 
-        }
+	}
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	{
 		bd_t *binfo = (bd_t *) __res;
@@ -401,7 +532,7 @@ platform_init(unsigned long r3, unsigned
 
 		/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
 		settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
-			  binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+				binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
 
 		memset(&p, 0, sizeof (p));
 		p.iotype = SERIAL_IO_MEM;
@@ -420,49 +551,56 @@ platform_init(unsigned long r3, unsigned
 #endif
 
 #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 */
+	/*
+	 * 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. */
+	/* Copy the kernel command line arguments to a safe place. */
 
-        if (r6) {
-                *(char *) (r7 + KERNELBASE) = 0;
-                strcpy(cmd_line, (char *) (r6 + KERNELBASE));
-        }
+	if (r6) {
+		*(char *) (r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+	}
+
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+	/* setup the PowerPC module struct */
+	ppc_md.setup_arch = mpc85xx_cds_setup_arch;
+	ppc_md.show_cpuinfo = mpc85xx_cds_show_cpuinfo;
 
-	identify_ppc_sys_by_id(mfspr(SVR));
+	ppc_md.init_IRQ = mpc85xx_cds_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
 
-        /* setup the PowerPC module struct */
-        ppc_md.setup_arch = mpc85xx_cds_setup_arch;
-        ppc_md.show_cpuinfo = mpc85xx_cds_show_cpuinfo;
+	ppc_md.restart = mpc85xx_restart;
+	ppc_md.power_off = mpc85xx_power_off;
+	ppc_md.halt = mpc85xx_halt;
 
-        ppc_md.init_IRQ = mpc85xx_cds_init_IRQ;
-        ppc_md.get_irq = openpic_get_irq;
+	ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
 
-        ppc_md.restart = mpc85xx_restart;
-        ppc_md.power_off = mpc85xx_power_off;
-        ppc_md.halt = mpc85xx_halt;
+	ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
 
-        ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+	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.time_init = NULL;
-        ppc_md.set_rtc_time = NULL;
-        ppc_md.get_rtc_time = NULL;
-        ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
 
 #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
-        ppc_md.progress = gen550_progress;
+	ppc_md.progress = gen550_progress;
 #endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+	ppc_md.early_serial_map = mpc85xx_early_serial_map;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_KGDB */
 
-        if (ppc_md.progress)
-                ppc_md.progress("mpc85xx_cds_init(): exit", 0);
+	if (ppc_md.progress)
+		ppc_md.progress("mpc85xx_cds_init(): exit", 0);
 
-        return;
+	return;
 }
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -33,6 +33,10 @@
 #define CM_CSR	(1)
 #define CM_RST	(2)
 
+/* CDS NVRAM/RTC */
+#define CDS_RTC_ADDR	(0xf8000000)
+#define CDS_RTC_SIZE	(8 * 1024)
+
 /* PCI config */
 #define PCI1_CFG_ADDR_OFFSET	(0x8000)
 #define PCI1_CFG_DATA_OFFSET	(0x8004)
@@ -73,4 +77,7 @@
 
 #define MPC85XX_PCI2_IO_SIZE         0x01000000
 
+#define NR_8259_INTS		     16
+#define CPM_IRQ_OFFSET		     NR_8259_INTS
+
 #endif /* __MACH_MPC85XX_CDS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_devices.c b/arch/ppc/platforms/85xx/mpc85xx_devices.c
deleted file mode 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_devices.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * arch/ppc/platforms/85xx/mpc85xx_devices.c
- *
- * MPC85xx Device descriptions
- *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
- *
- * Copyright 2005 Freescale 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <linux/fsl_devices.h>
-#include <asm/mpc85xx.h>
-#include <asm/irq.h>
-#include <asm/ppc_sys.h>
-
-/* We use offsets for IORESOURCE_MEM since we do not know at compile time
- * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
- */
-
-static struct gianfar_platform_data mpc85xx_tsec1_pdata = {
-	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
-	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
-	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
-};
-
-static struct gianfar_platform_data mpc85xx_tsec2_pdata = {
-	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
-	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
-	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
-};
-
-static struct gianfar_platform_data mpc85xx_fec_pdata = {
-	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
-};
-
-static struct fsl_i2c_platform_data mpc85xx_fsl_i2c_pdata = {
-	.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
-};
-
-static struct plat_serial8250_port serial_platform_data[] = {
-	[0] = {
-		.mapbase	= 0x4500,
-		.irq		= MPC85xx_IRQ_DUART,
-		.iotype		= UPIO_MEM,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
-	},
-	[1] = {
-		.mapbase	= 0x4600,
-		.irq		= MPC85xx_IRQ_DUART,
-		.iotype		= UPIO_MEM,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
-	},
-};
-
-struct platform_device ppc_sys_platform_devices[] = {
-	[MPC85xx_TSEC1] = {
-		.name = "fsl-gianfar",
-		.id	= 1,
-		.dev.platform_data = &mpc85xx_tsec1_pdata,
-		.num_resources	 = 4,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_ENET1_OFFSET,
-				.end	= MPC85xx_ENET1_OFFSET +
-						MPC85xx_ENET1_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.name	= "tx",
-				.start	= MPC85xx_IRQ_TSEC1_TX,
-				.end	= MPC85xx_IRQ_TSEC1_TX,
-				.flags	= IORESOURCE_IRQ,
-			},
-			{
-				.name	= "rx",
-				.start	= MPC85xx_IRQ_TSEC1_RX,
-				.end	= MPC85xx_IRQ_TSEC1_RX,
-				.flags	= IORESOURCE_IRQ,
-			},
-			{
-				.name	= "error",
-				.start	= MPC85xx_IRQ_TSEC1_ERROR,
-				.end	= MPC85xx_IRQ_TSEC1_ERROR,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_TSEC2] = {
-		.name = "fsl-gianfar",
-		.id	= 2,
-		.dev.platform_data = &mpc85xx_tsec2_pdata,
-		.num_resources	 = 4,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_ENET2_OFFSET,
-				.end	= MPC85xx_ENET2_OFFSET +
-						MPC85xx_ENET2_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.name	= "tx",
-				.start	= MPC85xx_IRQ_TSEC2_TX,
-				.end	= MPC85xx_IRQ_TSEC2_TX,
-				.flags	= IORESOURCE_IRQ,
-			},
-			{
-				.name	= "rx",
-				.start	= MPC85xx_IRQ_TSEC2_RX,
-				.end	= MPC85xx_IRQ_TSEC2_RX,
-				.flags	= IORESOURCE_IRQ,
-			},
-			{
-				.name	= "error",
-				.start	= MPC85xx_IRQ_TSEC2_ERROR,
-				.end	= MPC85xx_IRQ_TSEC2_ERROR,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_FEC] =	{
-		.name = "fsl-gianfar",
-		.id	= 3,
-		.dev.platform_data = &mpc85xx_fec_pdata,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_ENET3_OFFSET,
-				.end	= MPC85xx_ENET3_OFFSET +
-						MPC85xx_ENET3_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-
-			},
-			{
-				.start	= MPC85xx_IRQ_FEC,
-				.end	= MPC85xx_IRQ_FEC,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_IIC1] = {
-		.name = "fsl-i2c",
-		.id	= 1,
-		.dev.platform_data = &mpc85xx_fsl_i2c_pdata,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_IIC1_OFFSET,
-				.end	= MPC85xx_IIC1_OFFSET +
-						MPC85xx_IIC1_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_IIC1,
-				.end	= MPC85xx_IRQ_IIC1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_DMA0] = {
-		.name = "fsl-dma",
-		.id	= 0,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_DMA0_OFFSET,
-				.end	= MPC85xx_DMA0_OFFSET +
-						MPC85xx_DMA0_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_DMA0,
-				.end	= MPC85xx_IRQ_DMA0,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_DMA1] = {
-		.name = "fsl-dma",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_DMA1_OFFSET,
-				.end	= MPC85xx_DMA1_OFFSET +
-						MPC85xx_DMA1_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_DMA1,
-				.end	= MPC85xx_IRQ_DMA1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_DMA2] = {
-		.name = "fsl-dma",
-		.id	= 2,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_DMA2_OFFSET,
-				.end	= MPC85xx_DMA2_OFFSET +
-						MPC85xx_DMA2_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_DMA2,
-				.end	= MPC85xx_IRQ_DMA2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_DMA3] = {
-		.name = "fsl-dma",
-		.id	= 3,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_DMA3_OFFSET,
-				.end	= MPC85xx_DMA3_OFFSET +
-						MPC85xx_DMA3_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_DMA3,
-				.end	= MPC85xx_IRQ_DMA3,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_DUART] = {
-		.name = "serial8250",
-		.id	= 0,
-		.dev.platform_data = serial_platform_data,
-	},
-	[MPC85xx_PERFMON] = {
-		.name = "fsl-perfmon",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_PERFMON_OFFSET,
-				.end	= MPC85xx_PERFMON_OFFSET +
-						MPC85xx_PERFMON_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_PERFMON,
-				.end	= MPC85xx_IRQ_PERFMON,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_SEC2] = {
-		.name = "fsl-sec2",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= MPC85xx_SEC2_OFFSET,
-				.end	= MPC85xx_SEC2_OFFSET +
-						MPC85xx_SEC2_SIZE - 1,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= MPC85xx_IRQ_SEC2,
-				.end	= MPC85xx_IRQ_SEC2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-#ifdef CONFIG_CPM2
-	[MPC85xx_CPM_FCC1] = {
-		.name = "fsl-cpm-fcc",
-		.id	= 1,
-		.num_resources	 = 3,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91300,
-				.end	= 0x9131F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= 0x91380,
-				.end	= 0x9139F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_FCC1,
-				.end	= SIU_INT_FCC1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_FCC2] = {
-		.name = "fsl-cpm-fcc",
-		.id	= 2,
-		.num_resources	 = 3,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91320,
-				.end	= 0x9133F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= 0x913A0,
-				.end	= 0x913CF,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_FCC2,
-				.end	= SIU_INT_FCC2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_FCC3] = {
-		.name = "fsl-cpm-fcc",
-		.id	= 3,
-		.num_resources	 = 3,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91340,
-				.end	= 0x9135F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= 0x913D0,
-				.end	= 0x913FF,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_FCC3,
-				.end	= SIU_INT_FCC3,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_I2C] = {
-		.name = "fsl-cpm-i2c",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91860,
-				.end	= 0x918BF,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_I2C,
-				.end	= SIU_INT_I2C,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SCC1] = {
-		.name = "fsl-cpm-scc",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A00,
-				.end	= 0x91A1F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SCC1,
-				.end	= SIU_INT_SCC1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SCC2] = {
-		.name = "fsl-cpm-scc",
-		.id	= 2,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A20,
-				.end	= 0x91A3F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SCC2,
-				.end	= SIU_INT_SCC2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SCC3] = {
-		.name = "fsl-cpm-scc",
-		.id	= 3,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A40,
-				.end	= 0x91A5F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SCC3,
-				.end	= SIU_INT_SCC3,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SCC4] = {
-		.name = "fsl-cpm-scc",
-		.id	= 4,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A60,
-				.end	= 0x91A7F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SCC4,
-				.end	= SIU_INT_SCC4,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SPI] = {
-		.name = "fsl-cpm-spi",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91AA0,
-				.end	= 0x91AFF,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SPI,
-				.end	= SIU_INT_SPI,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_MCC1] = {
-		.name = "fsl-cpm-mcc",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91B30,
-				.end	= 0x91B3F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_MCC1,
-				.end	= SIU_INT_MCC1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_MCC2] = {
-		.name = "fsl-cpm-mcc",
-		.id	= 2,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91B50,
-				.end	= 0x91B5F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_MCC2,
-				.end	= SIU_INT_MCC2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SMC1] = {
-		.name = "fsl-cpm-smc",
-		.id	= 1,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A80,
-				.end	= 0x91A8F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SMC1,
-				.end	= SIU_INT_SMC1,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_SMC2] = {
-		.name = "fsl-cpm-smc",
-		.id	= 2,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91A90,
-				.end	= 0x91A9F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_SMC2,
-				.end	= SIU_INT_SMC2,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-	[MPC85xx_CPM_USB] = {
-		.name = "fsl-cpm-usb",
-		.id	= 2,
-		.num_resources	 = 2,
-		.resource = (struct resource[]) {
-			{
-				.start	= 0x91B60,
-				.end	= 0x91B7F,
-				.flags	= IORESOURCE_MEM,
-			},
-			{
-				.start	= SIU_INT_USB,
-				.end	= SIU_INT_USB,
-				.flags	= IORESOURCE_IRQ,
-			},
-		},
-	},
-#endif /* CONFIG_CPM2 */
-};
-
-static int __init mach_mpc85xx_fixup(struct platform_device *pdev)
-{
-	ppc_sys_fixup_mem_resource(pdev, CCSRBAR);
-	return 0;
-}
-
-static int __init mach_mpc85xx_init(void)
-{
-	ppc_sys_device_fixup = mach_mpc85xx_fixup;
-	return 0;
-}
-
-postcore_initcall(mach_mpc85xx_init);
diff --git a/arch/ppc/platforms/85xx/mpc85xx_sys.c b/arch/ppc/platforms/85xx/mpc85xx_sys.c
deleted file mode 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_sys.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * arch/ppc/platforms/85xx/mpc85xx_sys.c
- *
- * MPC85xx System descriptions
- *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
- *
- * Copyright 2005 Freescale 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <asm/ppc_sys.h>
-
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
-	{
-		.ppc_sys_name	= "MPC8540",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x80300000,
-		.num_devices	= 10,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_FEC, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON, MPC85xx_DUART,
-		},
-	},
-	{
-		.ppc_sys_name	= "MPC8560",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x80700000,
-		.num_devices	= 19,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON,
-			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
-			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3, MPC85xx_CPM_SCC4,
-			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
-			MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2,
-		},
-	},
-	{
-		.ppc_sys_name	= "MPC8541",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x80720000,
-		.num_devices	= 13,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON, MPC85xx_DUART,
-			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
-			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
-		},
-	},
-	{
-		.ppc_sys_name	= "MPC8541E",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x807A0000,
-		.num_devices	= 14,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
-			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
-			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
-		},
-	},
-	{
-		.ppc_sys_name	= "MPC8555",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x80710000,
-		.num_devices	= 20,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON, MPC85xx_DUART,
-			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
-			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
-			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
-			MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
-			MPC85xx_CPM_USB,
-		},
-	},
-	{
-		.ppc_sys_name	= "MPC8555E",
-		.mask 		= 0xFFFF0000,
-		.value 		= 0x80790000,
-		.num_devices	= 21,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
-			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
-			MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
-			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
-			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
-			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
-			MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
-			MPC85xx_CPM_USB,
-		},
-	},
-	{	/* default match */
-		.ppc_sys_name	= "",
-		.mask 		= 0x00000000,
-		.value 		= 0x00000000,
-	},
-};
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -198,7 +198,7 @@ platform_init(unsigned long r3, unsigned
 		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
 	}
 
-	identify_ppc_sys_by_id(mfspr(SVR));
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
 
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = sbc8560_setup_arch;
@@ -221,6 +221,9 @@ platform_init(unsigned long r3, unsigned
 #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
 	ppc_md.progress = gen550_progress;
 #endif	/* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+	ppc_md.early_serial_map = sbc8560_early_serial_map;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_KGDB */
 
 	if (ppc_md.progress)
 		ppc_md.progress("sbc8560_init(): exit", 0);
diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c
--- a/arch/ppc/platforms/85xx/sbc85xx.c
+++ b/arch/ppc/platforms/85xx/sbc85xx.c
@@ -42,6 +42,7 @@
 #include <asm/mpc85xx.h>
 #include <asm/irq.h>
 #include <asm/immap_85xx.h>
+#include <asm/ppc_sys.h>
 
 #include <mm/mmu_decl.h>
 
@@ -125,28 +126,17 @@ sbc8560_show_cpuinfo(struct seq_file *m)
 	/* get the core frequency */
 	freq = binfo->bi_intfreq;
 
-	pvid = mfspr(PVR);
-	svid = mfspr(SVR);
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
 
 	seq_printf(m, "Vendor\t\t: Wind River\n");
-
-	switch (svid & 0xffff0000) {
-	case SVR_8540:
-		seq_printf(m, "Machine\t\t: hhmmm, this board isn't made yet!\n");
-		break;
-	case SVR_8560:
-		seq_printf(m, "Machine\t\t: SBC8560\n");
-		break;
-	default:
-		seq_printf(m, "Machine\t\t: unknown\n");
-		break;
-	}
+	seq_printf(m, "Machine\t\t: SBC%s\n", cur_ppc_sys_spec->ppc_sys_name);
 	seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
 	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
 	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
 	/* Display cpu Pll setting */
-	phid1 = mfspr(HID1);
+	phid1 = mfspr(SPRN_HID1);
 	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 
 	/* Display the amount of memory */
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -34,8 +34,10 @@
 #include <linux/root_dev.h>
 #include <linux/seq_file.h>
 #include <linux/serial.h>
+#include <linux/initrd.h>
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -199,7 +201,6 @@ static void __init
 gp3_init_IRQ(void)
 {
 	int i;
-	volatile cpm2_map_t *immap = cpm2_immr;
 	bd_t *binfo = (bd_t *) __res;
 
 	/*
@@ -225,24 +226,8 @@ gp3_init_IRQ(void)
 	 */
 	openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
 
-	/*
-	 * Setup CPM2 PIC
-	 */
-
-	/* disable all CPM interupts */
-	immap->im_intctl.ic_simrh = 0x0;
-	immap->im_intctl.ic_simrl = 0x0;
-
-	for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
-		irq_desc[i].handler = &cpm2_pic;
-
-	/*
-	 * Initialize the default interrupt mapping priorities,
-	 * in case the boot rom changed something on us.
-	 */
-	immap->im_intctl.ic_sicr = 0;
-	immap->im_intctl.ic_scprrh = 0x05309770;
-	immap->im_intctl.ic_scprrl = 0x05309770;
+	/* Setup CPM2 PIC */
+        cpm2_init_IRQ();
 
 	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
 
@@ -261,31 +246,20 @@ gp3_show_cpuinfo(struct seq_file *m)
 	/* get the core frequency */
 	freq = binfo->bi_intfreq;
 
-	pvid = mfspr(PVR);
-	svid = mfspr(SVR);
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
 
 	memsize = total_memory;
 
 	seq_printf(m, "Vendor\t\t: RPC Electronics STx \n");
-
-	switch (svid & 0xffff0000) {
-	case SVR_8540:
-		seq_printf(m, "Machine\t\t: GP3 - MPC8540\n");
-		break;
-	case SVR_8560:
-		seq_printf(m, "Machine\t\t: GP3 - MPC8560\n");
-		break;
-	default:
-		seq_printf(m, "Machine\t\t: unknown\n");
-		break;
-	}
+	seq_printf(m, "Machine\t\t: GP3 - MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
 	seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
 		   freq % 1000000);
 	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
 	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
 	/* Display cpu Pll setting */
-	phid1 = mfspr(HID1);
+	phid1 = mfspr(SPRN_HID1);
 	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 
 	/* Display the amount of memory */
@@ -357,7 +331,7 @@ platform_init(unsigned long r3, unsigned
 		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
 	}
 
-	identify_ppc_sys_by_id(mfspr(SVR));
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
 
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = gp3_setup_arch;
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -12,7 +12,8 @@ endif
 obj-$(CONFIG_PPC_PMAC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
 					pmac_feature.o pmac_pci.o pmac_sleep.o \
 					pmac_low_i2c.o pmac_cache.o
-obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o
+obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o \
+					chrp_pegasos_eth.o
 obj-$(CONFIG_PPC_PREP)		+= prep_pci.o prep_setup.o
 ifeq ($(CONFIG_PPC_PMAC),y)
 obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
@@ -30,6 +31,7 @@ obj-$(CONFIG_GEMINI)		+= gemini_pci.o ge
 obj-$(CONFIG_K2)		+= k2.o
 obj-$(CONFIG_LOPEC)		+= lopec.o
 obj-$(CONFIG_KATANA)		+= katana.o
+obj-$(CONFIG_HDPU)		+= hdpu.o
 obj-$(CONFIG_MCPN765)		+= mcpn765.o
 obj-$(CONFIG_MENF1)		+= menf1_setup.o menf1_pci.o
 obj-$(CONFIG_MVME5100)		+= mvme5100.o
@@ -39,10 +41,11 @@ obj-$(CONFIG_POWERPMC250)	+= powerpmc250
 obj-$(CONFIG_PPLUS)		+= pplus.o
 obj-$(CONFIG_PRPMC750)		+= prpmc750.o
 obj-$(CONFIG_PRPMC800)		+= prpmc800.o
+obj-$(CONFIG_RADSTONE_PPC7D)	+= radstone_ppc7d.o
 obj-$(CONFIG_SANDPOINT)		+= sandpoint.o
 obj-$(CONFIG_SBC82xx)		+= sbc82xx.o
 obj-$(CONFIG_SPRUCE)		+= spruce.o
-obj-$(CONFIG_LITE5200)		+= lite5200.o mpc5200.o
+obj-$(CONFIG_LITE5200)		+= lite5200.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_PMAC)		+= pmac_smp.o
diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c
--- a/arch/ppc/platforms/adir_setup.c
+++ b/arch/ppc/platforms/adir_setup.c
@@ -60,7 +60,7 @@ adir_get_cpu_speed(void)
 	unsigned long hid1;
 	int cpu_speed;
 
-	hid1 = mfspr(HID1) >> 28;
+	hid1 = mfspr(SPRN_HID1) >> 28;
 
 	hid1 = cpu_750cx[hid1];
 
@@ -126,7 +126,7 @@ adir_setup_arch(void)
 	printk("SBS Adirondack port (C) 2001 SBS Technologies, Inc.\n");
 
 	/* Identify the CPU manufacturer */
-	cpu = mfspr(PVR);
+	cpu = mfspr(SPRN_PVR);
 	printk("CPU manufacturer: IBM [rev=%04x]\n", (cpu & 0xffff));
 }
 
diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c
--- a/arch/ppc/platforms/chestnut.c
+++ b/arch/ppc/platforms/chestnut.c
@@ -28,6 +28,7 @@
 #include <linux/ide.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/mtd/physmap.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -42,8 +43,8 @@
 #include <asm/mv64x60.h>
 #include <platforms/chestnut.h>
 
-static u32 boot_base; /* Virtual addr of 8bit boot */
-static u32 cpld_base; /* Virtual addr of CPLD Regs */
+static void __iomem *sram_base; /* Virtual addr of Internal SRAM */
+static void __iomem *cpld_base; /* Virtual addr of CPLD Regs */
 
 static mv64x60_handle_t	bh;
 
@@ -65,7 +66,8 @@ extern void mv64360_pcibios_fixup(mv64x6
  *
  ****/
 static void __init
-chestnut_calibrate_decr(void){
+chestnut_calibrate_decr(void)
+{
 	ulong freq;
 
 	freq = CHESTNUT_BUS_SPEED / 4;
@@ -75,8 +77,6 @@ chestnut_calibrate_decr(void){
 
 	tb_ticks_per_jiffy = freq / HZ;
 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-	return;
 }
 
 static int
@@ -103,7 +103,7 @@ chestnut_find_end_of_memory(void)
       		mem_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
 				MV64x60_TYPE_MV64460);
    	}
-   	return(mem_size);
+   	return mem_size;
 }
 
 #if defined(CONFIG_SERIAL_8250)
@@ -155,7 +155,7 @@ chestnut_map_irq(struct pci_dev *dev, un
 	};
 	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
 
-	return (PCI_IRQ_TABLE_LOOKUP);
+	return PCI_IRQ_TABLE_LOOKUP;
 }
 
 
@@ -193,24 +193,30 @@ chestnut_setup_bridge(void)
 	si.pci_0.pci_cmd_bits = 0;
 	si.pci_0.latency_timer = 0x80;
 
-	si.window_preserve_mask_32_lo = CHESTNUT_PRESERVE_MASK;
-
 	for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
 		si.cpu_prot_options[i] = 0;
-#ifdef CONFIG_NOT_CACHE_COHERENT
-		si.cpu_snoop_options[i] = MV64360_CPU_SNOOP_NONE;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
 #else
-		si.cpu_snoop_options[i] = MV64360_CPU_SNOOP_WB; /* risky */
-#endif
-		si.pci_0.acc_cntl_options[i] =
-#ifdef CONFIG_NOT_CACHE_COHERENT
-			MV64360_PCI_ACC_CNTL_SNOOP_NONE |
-#else
-			MV64360_PCI_ACC_CNTL_SNOOP_WB | /* risky */
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
 #endif
-			MV64360_PCI_ACC_CNTL_SWAP_NONE |
-			MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
-			MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
 	}
 
    	/* Lookup host bridge - on CPU 0 - no SMP support */
@@ -227,55 +233,44 @@ chestnut_setup_bridge(void)
 	bh.hose_a->first_busno = 0;
 	bh.hose_a->last_busno = 0xff;
 	bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
-
 }
 
 void __init
 chestnut_setup_peripherals(void)
 {
-
    	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
 			CHESTNUT_BOOT_8BIT_BASE, CHESTNUT_BOOT_8BIT_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
 
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
 			CHESTNUT_32BIT_BASE, CHESTNUT_32BIT_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
 			CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+	cpld_base = ioremap(CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE);
 
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
 			CHESTNUT_UART_BASE, CHESTNUT_UART_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
 			CHESTNUT_FRAM_BASE, CHESTNUT_FRAM_SIZE, 0);
-   	/* Set up window for internal sram (256KByte insize) */
-   	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
-			CHESTNUT_INTERNAL_SRAM_BASE,
-			CHESTNUT_INTERNAL_SRAM_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
 
-	boot_base = (u32)ioremap(CHESTNUT_BOOT_8BIT_BASE,
-				CHESTNUT_BOOT_8BIT_SIZE);
-	cpld_base = (u32)ioremap(CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE);
+   	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+			CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
 
-   	/*
-    	 * Configure internal SRAM -
-    	 * Cache coherent write back, incase
-	 *      CONFIG_MV64360_SRAM_CACHE_COHERENT set
-    	 * Parity enabled.
-    	 * Parity error propagation
-    	 * Arbitration not parked for CPU only
-    	 * Other bits are reserved.
-    	 */
-#ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT
-   	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
-#else
+#ifdef CONFIG_NOT_COHERENT_CACHE
    	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0);
+#else
+   	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
 #endif
+	sram_base = ioremap(CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+   	memset(sram_base, 0, MV64360_SRAM_SIZE);
 
-   	/*
-    	 * Setting the SRAM to 0. Note that this generates parity errors on
-	 * internal data path in SRAM since it's first time accessing it
-	 * while after reset it's not configured
-    	*/
-   	memset((void *)CHESTNUT_INTERNAL_SRAM_BASE, 0, CHESTNUT_INTERNAL_SRAM_SIZE);
 	/*
 	 * Configure MPP pins for PCI DMA
 	 *
@@ -312,9 +307,9 @@ chestnut_setup_peripherals(void)
 			(0xf << 20) |	/* MPPSel13 GPIO[13] */
 			(0xf << 24) |	/* MPPSel14 GPIO[14] */
 			(0xf << 28));	/* MPPSel15 GPIO[15] */
-	mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL,
+	mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, /* Output */
 			BIT(1)  | BIT(2)  | BIT(4)  | BIT(5)  | BIT(6)  |
-			BIT(9)  | BIT(10) | BIT(13) | BIT(14) | BIT(15)); /* Output */
+			BIT(9)  | BIT(10) | BIT(13) | BIT(14) | BIT(15));
 
    	/*
     	 * Configure the following MPP pins to indicate a level
@@ -364,7 +359,7 @@ chestnut_setup_peripherals(void)
    	/*
     	 * Dismiss and then enable interrupt on CPU #0 high cause register
     	 * BIT27 summarizes GPP interrupts 24-31
-    	*/
+    	 */
    	mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, BIT(27));
 
    	if (ppc_md.progress)
@@ -423,14 +418,32 @@ chestnut_setup_arch(void)
 
 	/* Identify the system */
 	printk(KERN_INFO "System Identification: IBM 750FX/GX Eval Board\n");
-	printk(KERN_INFO "IBM 750FX/GX port (C) 2004 MontaVista Software, Inc. (source@mvista.com)\n");
+	printk(KERN_INFO "IBM 750FX/GX port (C) 2004 MontaVista Software, Inc."
+		" (source@mvista.com)\n");
 
 	if (ppc_md.progress)
       		ppc_md.progress("chestnut_setup_arch: exit", 0);
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+static struct mtd_partition ptbl;
+
+static int __init
+chestnut_setup_mtd(void)
+{
+	memset(&ptbl, 0, sizeof(ptbl));
 
-	return;
+	ptbl.name = "User FS";
+	ptbl.size = CHESTNUT_32BIT_SIZE;
+
+	physmap_map.size = CHESTNUT_32BIT_SIZE;
+	physmap_set_partitions(&ptbl, 1);
+	return 0;
 }
 
+arch_initcall(chestnut_setup_mtd);
+#endif
+
 /**************************************************************************
  * FUNCTION: chestnut_restart
  *
@@ -450,7 +463,7 @@ chestnut_restart(char *cmd)
          *
          * MPP24 - board reset
          */
-   	writeb(0x1, (void __iomem *)(cpld_base+3));
+   	writeb(0x1, cpld_base + 3);
 
 	/* GPP pin tied to MPP earlier */
         mv64x60_set_bits(&bh, MV64x60_GPP_VALUE_SET, BIT(24));
@@ -474,37 +487,6 @@ chestnut_power_off(void)
 	/* NOTREACHED */
 }
 
-#define SET_PCI_COMMAND_INVALIDATE
-#ifdef SET_PCI_COMMAND_INVALIDATE
-/*
- * Dave Wilhardt found that PCI_COMMAND_INVALIDATE must
- * be set for each device if you are using cache coherency.
- */
-static void __init
-set_pci_command_invalidate(void)
-{
-	struct pci_dev *dev = NULL;
-	u16 val;
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		pci_read_config_word(dev, PCI_COMMAND, &val);
-		val |= PCI_COMMAND_INVALIDATE;
-		pci_write_config_word(dev, PCI_COMMAND, val);
-
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-				      L1_CACHE_LINE_SIZE >> 2);
-	}
-}
-#endif
-
-static void __init
-chestnut_pci_fixups(void)
-{
-#ifdef SET_PCI_COMMAND_INVALIDATE
-	set_pci_command_invalidate();
-#endif
-}
-
 /**************************************************************************
  * FUNCTION: chestnut_map_io
  *
@@ -514,27 +496,9 @@ chestnut_pci_fixups(void)
 static void __init
 chestnut_map_io(void)
 {
-#ifdef CONFIG_MV64360_SRAM_CACHEABLE
-   	io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_SIZE,
-       			_PAGE_KERNEL | _PAGE_GUARDED);
-#else
-#ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT
-   	io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_SIZE,
-       			_PAGE_KERNEL | _PAGE_GUARDED | _PAGE_COHERENT);
-#else
-   	io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_BASE,
-       			CHESTNUT_INTERNAL_SRAM_SIZE,
-       			_PAGE_IO);
-#endif /* !CONFIG_MV64360_SRAM_CACHE_COHERENT */
-#endif /* !CONFIG_MV64360_SRAM_CACHEABLE */
-
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-	io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, _PAGE_IO);
+	io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000,
+		_PAGE_IO);
 #endif
 }
 
@@ -549,11 +513,9 @@ static __inline__ void
 chestnut_set_bat(void)
 {
         mb();
-        mtspr(DBAT3U, 0xf0001ffe);
-        mtspr(DBAT3L, 0xf000002a);
+        mtspr(SPRN_DBAT3U, 0xf0001ffe);
+        mtspr(SPRN_DBAT3L, 0xf000002a);
         mb();
-
-	return;
 }
 
 /**************************************************************************
@@ -587,7 +549,6 @@ platform_init(unsigned long r3, unsigned
 
 	ppc_md.find_end_of_memory = chestnut_find_end_of_memory;
 	ppc_md.setup_io_mappings  = chestnut_map_io;
-	ppc_md.pcibios_fixup = chestnut_pci_fixups;
 
 	ppc_md.restart = chestnut_restart;
    	ppc_md.power_off = chestnut_power_off;
@@ -603,8 +564,6 @@ platform_init(unsigned long r3, unsigned
 
 	ppc_md.heartbeat = NULL;
 
-	ppc_md.pcibios_fixup = chestnut_pci_fixups;
-
 	bh.p_base = CONFIG_MV64X60_NEW_BASE;
 
 	chestnut_set_bat();
@@ -618,6 +577,4 @@ platform_init(unsigned long r3, unsigned
 
 	if (ppc_md.progress)
                 ppc_md.progress("chestnut_init(): exit", 0);
-
-        return;
 }
diff --git a/arch/ppc/platforms/chestnut.h b/arch/ppc/platforms/chestnut.h
--- a/arch/ppc/platforms/chestnut.h
+++ b/arch/ppc/platforms/chestnut.h
@@ -24,11 +24,12 @@
  * implement at 0xf1000000 only at this time
  *
  *    0xfff00000-0xffffffff      - 8 Flash
+ *    0xffe00000-0xffefffff      - BOOT SRAM
  *    0xffd00000-0xffd00004      - CPLD
  *    0xffc00000-0xffc0000f      - UART
  *    0xffb00000-0xffb07fff      - FRAM
- *    0xffa00000-0xffafffff      - *** HOLE ***
- *    0xff900000-0xff9fffff      - MV64460 Integrated SRAM
+ *    0xff840000-0xffafffff      - *** HOLE ***
+ *    0xff800000-0xff83ffff      - MV64460 Integrated SRAM
  *    0xfe000000-0xff8fffff      - *** HOLE ***
  *    0xfc000000-0xfdffffff      - 32bit Flash
  *    0xf1010000-0xfbffffff      - *** HOLE ***
@@ -49,9 +50,7 @@
 #define CHESTNUT_UART_SIZE_ACTUAL		16
 #define CHESTNUT_FRAM_BASE			0xffb00000
 #define CHESTNUT_FRAM_SIZE_ACTUAL		(32*1024)
-#define CHESTNUT_BRIDGE_REG_BASE		0xf1000000
-#define CHESTNUT_INTERNAL_SRAM_BASE		0xff900000
-#define CHESTNUT_INTERNAL_SRAM_SIZE_ACTUAL	(256*1024)
+#define CHESTNUT_INTERNAL_SRAM_BASE		0xff800000
 #define CHESTNUT_32BIT_BASE			0xfc000000
 #define CHESTNUT_32BIT_SIZE			(32*1024*1024)
 
@@ -65,14 +64,16 @@
 					CHESTNUT_UART_SIZE_ACTUAL)
 #define CHESTNUT_FRAM_SIZE		max(MV64360_WINDOW_SIZE_MIN, \
 					CHESTNUT_FRAM_SIZE_ACTUAL)
-#define CHESTNUT_INTERNAL_SRAM_SIZE	max(MV64360_WINDOW_SIZE_MIN, \
-					CHESTNUT_INTERNAL_SRAM_SIZE_ACTUAL)
 
 #define CHESTNUT_BUS_SPEED		200000000
 #define CHESTNUT_PIBS_DATABASE		0xf0000 /* from PIBS src code */
 
-#define MV64360_ETH_PORT_SERIAL_CONTROL_REG_PORT0 	0x243c
-#define MV64360_ETH_PORT_SERIAL_CONTROL_REG_PORT1 	0x283c
+#define	KATANA_ETH0_PHY_ADDR			12
+#define	KATANA_ETH1_PHY_ADDR			11
+#define	KATANA_ETH2_PHY_ADDR			4
+
+#define CHESTNUT_ETH_TX_QUEUE_SIZE		800
+#define CHESTNUT_ETH_RX_QUEUE_SIZE		400
 
 /*
  * PCI windows
@@ -89,17 +90,17 @@
 /*
  * Board-specific IRQ info
  */
-#define CHESTNUT_PCI_SLOT0_IRQ	64+31
-#define CHESTNUT_PCI_SLOT1_IRQ	64+30
-#define CHESTNUT_PCI_SLOT2_IRQ	64+29
-#define CHESTNUT_PCI_SLOT3_IRQ	64+28
+#define CHESTNUT_PCI_SLOT0_IRQ	(64 + 31)
+#define CHESTNUT_PCI_SLOT1_IRQ	(64 + 30)
+#define CHESTNUT_PCI_SLOT2_IRQ	(64 + 29)
+#define CHESTNUT_PCI_SLOT3_IRQ	(64 + 28)
 
 /* serial port definitions */
-#define CHESTNUT_UART0_IO_BASE  CHESTNUT_UART_BASE+8
+#define CHESTNUT_UART0_IO_BASE  (CHESTNUT_UART_BASE + 8)
 #define CHESTNUT_UART1_IO_BASE  CHESTNUT_UART_BASE
 
-#define UART0_INT           	64+25
-#define UART1_INT        	64+26
+#define UART0_INT           	(64 + 25)
+#define UART1_INT        	(64 + 26)
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define RS_TABLE_SIZE  64
@@ -108,7 +109,7 @@
 #endif
 
 /* Rate for the 3.6864 Mhz clock for the onboard serial chip */
-#define BASE_BAUD 		( 3686400 / 16 )
+#define BASE_BAUD 		(3686400 / 16)
 
 #ifdef CONFIG_SERIAL_DETECT_IRQ
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c
--- a/arch/ppc/platforms/chrp_pci.c
+++ b/arch/ppc/platforms/chrp_pci.c
@@ -129,7 +129,7 @@ static struct pci_ops rtas_pci_ops =
 	rtas_write_config
 };
 
-volatile struct Hydra *Hydra = NULL;
+volatile struct Hydra __iomem *Hydra = NULL;
 
 int __init
 hydra_init(void)
@@ -175,13 +175,14 @@ chrp_pcibios_fixup(void)
 static void __init
 setup_python(struct pci_controller *hose, struct device_node *dev)
 {
-	u32 *reg, val;
+	u32 __iomem *reg;
+	u32 val;
 	unsigned long addr = dev->addrs[0].address;
 
 	setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
 
 	/* Clear the magic go-slow bit */
-	reg = (u32 *) ioremap(dev->addrs[0].address + 0xf6000, 0x40);
+	reg = 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);
diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/chrp_pegasos_eth.c
@@ -0,0 +1,101 @@
+/*
+ *  arch/ppc/platforms/chrp_pegasos_eth.c
+ *
+ *  Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
+ *  Thanks to :
+ *	Dale Farnsworth <dale@farnsworth.org>
+ *	Mark A. Greer <mgreer@mvista.com>
+ *	Nicolas DET <nd@bplan-gmbh.de>
+ *	Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *  And anyone else who helped me on this.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/mv643xx.h>
+#include <linux/pci.h>
+
+/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */
+static struct resource mv643xx_eth_shared_resources[] = {
+	[0] = {
+		.name	= "ethernet shared base",
+		.start	= 0xf1000000 + MV643XX_ETH_SHARED_REGS,
+		.end	= 0xf1000000 + MV643XX_ETH_SHARED_REGS +
+					MV643XX_ETH_SHARED_REGS_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device mv643xx_eth_shared_device = {
+	.name		= MV643XX_ETH_SHARED_NAME,
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(mv643xx_eth_shared_resources),
+	.resource	= mv643xx_eth_shared_resources,
+};
+
+static struct resource mv643xx_eth0_resources[] = {
+	[0] = {
+		.name	= "eth0 irq",
+		.start	= 9,
+		.end	= 9,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mv643xx_eth_platform_data eth0_pd;
+
+static struct platform_device eth0_device = {
+	.name		= MV643XX_ETH_NAME,
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(mv643xx_eth0_resources),
+	.resource	= mv643xx_eth0_resources,
+	.dev = {
+		.platform_data = &eth0_pd,
+	},
+};
+
+static struct resource mv643xx_eth1_resources[] = {
+	[0] = {
+		.name	= "eth1 irq",
+		.start	= 9,
+		.end	= 9,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mv643xx_eth_platform_data eth1_pd;
+
+static struct platform_device eth1_device = {
+	.name		= MV643XX_ETH_NAME,
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(mv643xx_eth1_resources),
+	.resource	= mv643xx_eth1_resources,
+	.dev = {
+		.platform_data = &eth1_pd,
+	},
+};
+
+static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
+	&mv643xx_eth_shared_device,
+	&eth0_device,
+	&eth1_device,
+};
+
+
+int
+mv643xx_eth_add_pds(void)
+{
+	int ret = 0;
+	static struct pci_device_id pci_marvell_mv64360[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) },
+		{ }
+	};
+
+	if (pci_dev_present(pci_marvell_mv64360)) {
+		ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs));
+	}
+	return ret;
+}
+device_initcall(mv643xx_eth_add_pds);
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -356,7 +356,7 @@ static void __init chrp_find_openpic(voi
 	struct device_node *np;
 	int len, i;
 	unsigned int *iranges;
-	void *isu;
+	void __iomem *isu;
 
 	np = find_type_devices("open-pic");
 	if (np == NULL || np->n_addrs == 0)
@@ -527,6 +527,8 @@ chrp_init(unsigned long r3, unsigned lon
 
 	ppc_md.init           = chrp_init2;
 
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 	ppc_md.restart        = chrp_restart;
 	ppc_md.power_off      = chrp_power_off;
 	ppc_md.halt           = chrp_halt;
diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c
--- a/arch/ppc/platforms/chrp_time.c
+++ b/arch/ppc/platforms/chrp_time.c
@@ -115,8 +115,6 @@ int __chrp chrp_set_rtc_time(unsigned lo
 	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;
 }
diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c
--- a/arch/ppc/platforms/cpci690.c
+++ b/arch/ppc/platforms/cpci690.c
@@ -60,8 +60,7 @@ cpci690_map_irq(struct pci_dev *dev, uns
 
 		const long min_idsel = 20, max_idsel = 20, irqs_per_slot = 4;
 		return PCI_IRQ_TABLE_LOOKUP;
-	}
-	else {
+	} else {
 		static char pci_irq_table[][4] =
 		/*
 		 *	PCI IDSEL/INTPIN->INTLINE
@@ -79,18 +78,12 @@ cpci690_map_irq(struct pci_dev *dev, uns
 }
 
 static int
-cpci690_get_bus_speed(void)
-{
-	return 133333333;
-}
-
-static int
 cpci690_get_cpu_speed(void)
 {
 	unsigned long	hid1;
 
-	hid1 = mfspr(HID1) >> 28;
-	return cpci690_get_bus_speed() * cpu_7xx[hid1]/2;
+	hid1 = mfspr(SPRN_HID1) >> 28;
+	return CPCI690_BUS_FREQ * cpu_7xx[hid1]/2;
 }
 
 #define	KB	(1024UL)
@@ -226,8 +219,6 @@ cpci690_setup_bridge(void)
 	bh.hose_b->last_busno = 0xff;
 	bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
 		bh.hose_b->first_busno);
-
-	return;
 }
 
 static void __init
@@ -285,8 +276,6 @@ cpci690_setup_peripherals(void)
 	/* Route MPP interrupt inputs to GPP */
 	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, 0x00000000);
 	mv64x60_write(&bh, MV64x60_MPP_CNTL_3, 0x00000000);
-
-	return;
 }
 
 static void __init
@@ -326,8 +315,6 @@ cpci690_setup_arch(void)
 
 	if (ppc_md.progress)
 		ppc_md.progress("cpci690_setup_arch: exit", 0);
-
-	return;
 }
 
 /* Platform device data fixup routines. */
@@ -340,11 +327,9 @@ cpci690_fixup_mpsc_pdata(struct platform
 	pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
 
 	pdata->max_idle = 40;
-	pdata->default_baud = 9600;
-	pdata->brg_clk_src = 8;
-	pdata->brg_clk_freq = 133000000;
-
-	return;
+	pdata->default_baud = CPCI690_MPSC_BAUD;
+	pdata->brg_clk_src = CPCI690_MPSC_CLK_SRC;
+	pdata->brg_clk_freq = CPCI690_BUS_FREQ;
 }
 
 static int __init
@@ -354,8 +339,8 @@ cpci690_platform_notify(struct device *d
 		char	*bus_id;
 		void	((*rtn)(struct platform_device *pdev));
 	} dev_map[] = {
-		{ MPSC_CTLR_NAME "0", cpci690_fixup_mpsc_pdata },
-		{ MPSC_CTLR_NAME "1", cpci690_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".0", cpci690_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".1", cpci690_fixup_mpsc_pdata },
 	};
 	struct platform_device	*pdev;
 	int	i;
@@ -412,7 +397,7 @@ cpci690_show_cpuinfo(struct seq_file *m)
 	seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
 	seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
 	seq_printf(m, "cpu MHz\t\t: %d\n", cpci690_get_cpu_speed()/1000/1000);
-	seq_printf(m, "bus MHz\t\t: %d\n", cpci690_get_bus_speed()/1000/1000);
+	seq_printf(m, "bus MHz\t\t: %d\n", CPCI690_BUS_FREQ/1000/1000);
 
 	return 0;
 }
@@ -422,15 +407,13 @@ cpci690_calibrate_decr(void)
 {
 	ulong freq;
 
-	freq = cpci690_get_bus_speed()/4;
+	freq = CPCI690_BUS_FREQ / 4;
 
 	printk(KERN_INFO "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;
 }
 
 static __inline__ void
@@ -441,11 +424,9 @@ cpci690_set_bat(u32 addr, u32 size)
 	size = ((size >> 17) - 1) << 2;
 
 	mb();
-	mtspr(DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */
-	mtspr(DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */
+	mtspr(SPRN_DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */
+	mtspr(SPRN_DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */
 	mb();
-
-	return;
 }
 
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
@@ -507,6 +488,4 @@ platform_init(unsigned long r3, unsigned
 #if defined(CONFIG_SERIAL_MPSC)
 	platform_notify = cpci690_platform_notify;
 #endif
-
-	return;
 }
diff --git a/arch/ppc/platforms/cpci690.h b/arch/ppc/platforms/cpci690.h
--- a/arch/ppc/platforms/cpci690.h
+++ b/arch/ppc/platforms/cpci690.h
@@ -70,4 +70,9 @@ typedef struct board_info {
 #define	CPCI690_IPMI_SIZE		max(GT64260_WINDOW_SIZE_MIN,	\
 						CPCI690_IPMI_SIZE_ACTUAL)
 
+#define	CPCI690_MPSC_BAUD			9600
+#define	CPCI690_MPSC_CLK_SRC			8 /* TCLK */
+
+#define	CPCI690_BUS_FREQ			133333333
+
 #endif /* __PPC_PLATFORMS_CPCI690_H */
diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c
--- a/arch/ppc/platforms/ev64260.c
+++ b/arch/ppc/platforms/ev64260.c
@@ -80,14 +80,14 @@ ev64260_get_cpu_speed(void)
 {
 	unsigned long	pvr, hid1, pll_ext;
 
-	pvr = PVR_VER(mfspr(PVR));
+	pvr = PVR_VER(mfspr(SPRN_PVR));
 
 	if (pvr != PVR_VER(PVR_7450)) {
-		hid1 = mfspr(HID1) >> 28;
+		hid1 = mfspr(SPRN_HID1) >> 28;
 		return ev64260_get_bus_speed() * cpu_7xx[hid1]/2;
 	}
 	else {
-		hid1 = (mfspr(HID1) & 0x0001e000) >> 13;
+		hid1 = (mfspr(SPRN_HID1) & 0x0001e000) >> 13;
 		pll_ext = 0; /* No way to read; must get from schematic */
 		return ev64260_get_bus_speed() * cpu_745x[pll_ext][hid1]/2;
 	}
@@ -422,8 +422,8 @@ ev64260_platform_notify(struct device *d
 		char	*bus_id;
 		void	((*rtn)(struct platform_device *pdev));
 	} dev_map[] = {
-		{ MPSC_CTLR_NAME "0", ev64260_fixup_mpsc_pdata },
-		{ MPSC_CTLR_NAME "1", ev64260_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".0", ev64260_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".1", ev64260_fixup_mpsc_pdata },
 	};
 	struct platform_device	*pdev;
 	int	i;
@@ -530,7 +530,7 @@ ev64260_show_cpuinfo(struct seq_file *m)
 {
 	uint pvid;
 
-	pvid = mfspr(PVR);
+	pvid = mfspr(SPRN_PVR);
 	seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
 	seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
 	seq_printf(m, "cpu MHz\t\t: %d\n", ev64260_get_cpu_speed()/1000/1000);
@@ -563,8 +563,8 @@ static __inline__ void
 ev64260_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xfb0001fe);
-	mtspr(DBAT1L, 0xfb00002a);
+	mtspr(SPRN_DBAT1U, 0xfb0001fe);
+	mtspr(SPRN_DBAT1L, 0xfb00002a);
 	mb();
 
 	return;
diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S
--- a/arch/ppc/platforms/gemini_prom.S
+++ b/arch/ppc/platforms/gemini_prom.S
@@ -40,29 +40,29 @@ _GLOBAL(gemini_prom_init)
 	/* 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   SPRN_IBAT0U,r3
+        mtspr   SPRN_IBAT0L,r3
+        mtspr   SPRN_IBAT1U,r3
+        mtspr   SPRN_IBAT1L,r3
+        mtspr   SPRN_IBAT2U,r3
+        mtspr   SPRN_IBAT2L,r3
+        mtspr   SPRN_IBAT3U,r3
+        mtspr   SPRN_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
+        mtspr   SPRN_DBAT0U,r3
+        mtspr   SPRN_DBAT0L,r3
+        mtspr   SPRN_DBAT1U,r3
+        mtspr   SPRN_DBAT1L,r3
+        mtspr   SPRN_DBAT2U,r3
+	mtspr   SPRN_DBAT2L,r3
+        mtspr   SPRN_DBAT3U,r3
+        mtspr   SPRN_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
+	mtspr	SPRN_SDR1,r4
 
 	li	r4,16
 	mtctr	r4
@@ -75,9 +75,9 @@ prom_no_mmu:	
 #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
+	mfspr	r4,SPRN_HID0
 	ori	r4,r4,HID0_ABE
-	mtspr	HID0,r4
+	mtspr	SPRN_HID0,r4
 	sync
 #endif /* CONFIG_SMP */
 	blr
@@ -88,6 +88,6 @@ _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
+	mtspr	SPRN_SRR0,r5
+	mtspr	SPRN_SRR1,r6
 	rfi
diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
--- a/arch/ppc/platforms/gemini_setup.c
+++ b/arch/ppc/platforms/gemini_setup.c
@@ -202,8 +202,8 @@ gemini_get_clock_speed(void)
 	unsigned long hid1, pvr;
 	int clock;
 
-	pvr = mfspr(PVR);
-	hid1 = (mfspr(HID1) >> 28) & 0xf;
+	pvr = mfspr(SPRN_PVR);
+	hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf;
 	if (PVR_VER(pvr) == 8 ||
 	    PVR_VER(pvr) == 12)
 		hid1 = cpu_7xx[hid1];
@@ -238,7 +238,7 @@ void __init gemini_init_l2(void)
         reg = readb(GEMINI_L2CFG);
         brev = readb(GEMINI_BREV);
         fam = readb(GEMINI_FEAT);
-        pvr = mfspr(PVR);
+        pvr = mfspr(SPRN_PVR);
 
         switch(PVR_VER(pvr)) {
 
@@ -433,9 +433,6 @@ gemini_set_rtc_time( unsigned long now )
 	/* done writing */
 	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
 
-	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
-		time_state = TIME_OK;
-
 	return 0;
 }
 
@@ -537,8 +534,8 @@ void __init platform_init(unsigned long 
 	int i;
 
 	/* Restore BATs for now */
-	mtspr(DBAT3U, 0xf0001fff);
-	mtspr(DBAT3L, 0xf000002a);
+	mtspr(SPRN_DBAT3U, 0xf0001fff);
+	mtspr(SPRN_DBAT3L, 0xf000002a);
 
 	parse_bootinfo(find_bootinfo());
 
diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/hdpu.c
@@ -0,0 +1,1062 @@
+
+/*
+ * arch/ppc/platforms/hdpu_setup.c
+ *
+ * Board setup routines for the Sky Computers HDPU Compute Blade.
+ *
+ * Written by Brian Waite <waite@skycomputers.com>
+ *
+ * Based on code done by - Mark A. Greer <mgreer@mvista.com>
+ *                         Rabeeh Khoury - rabeeh@galileo.co.il
+ *
+ * This program is free software; you can redistribute  it 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/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/smp.h>
+
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <asm/mv64x60.h>
+#include <asm/ppcboot.h>
+#include <platforms/hdpu.h>
+#include <linux/mv643xx.h>
+#include <linux/hdpu_features.h>
+#include <linux/device.h>
+#include <linux/mtd/physmap.h>
+
+#define BOARD_VENDOR	"Sky Computers"
+#define BOARD_MACHINE	"HDPU-CB-A"
+
+bd_t ppcboot_bd;
+int ppcboot_bd_valid = 0;
+
+static mv64x60_handle_t bh;
+
+extern char cmd_line[];
+
+unsigned long hdpu_find_end_of_memory(void);
+void hdpu_mpsc_progress(char *s, unsigned short hex);
+void hdpu_heartbeat(void);
+
+static void parse_bootinfo(unsigned long r3,
+			   unsigned long r4, unsigned long r5,
+			   unsigned long r6, unsigned long r7);
+static void hdpu_set_l1pe(void);
+static void hdpu_cpustate_set(unsigned char new_state);
+#ifdef CONFIG_SMP
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int timebase_upper = 0, timebase_lower = 0;
+extern int smp_tb_synchronized;
+
+void __devinit hdpu_tben_give(void);
+void __devinit hdpu_tben_take(void);
+#endif
+
+static int __init
+hdpu_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+	if (hose->index == 0) {
+		static char pci_irq_table[][4] = {
+			{HDPU_PCI_0_IRQ, 0, 0, 0},
+			{HDPU_PCI_0_IRQ, 0, 0, 0},
+		};
+
+		const long min_idsel = 1, max_idsel = 2, irqs_per_slot = 4;
+		return PCI_IRQ_TABLE_LOOKUP;
+	} else {
+		static char pci_irq_table[][4] = {
+			{HDPU_PCI_1_IRQ, 0, 0, 0},
+		};
+
+		const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4;
+		return PCI_IRQ_TABLE_LOOKUP;
+	}
+}
+
+static void __init hdpu_intr_setup(void)
+{
+	mv64x60_write(&bh, MV64x60_GPP_IO_CNTL,
+		      (1 | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) |
+		       (1 << 6) | (1 << 7) | (1 << 12) | (1 << 16) |
+		       (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) |
+		       (1 << 22) | (1 << 23) | (1 << 24) | (1 << 25) |
+		       (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29)));
+
+	/* XXXX Erranum FEr PCI-#8 */
+	mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1 << 5) | (1 << 9));
+	mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1 << 5) | (1 << 9));
+
+	/*
+	 * Dismiss and then enable interrupt on GPP interrupt cause
+	 * for CPU #0
+	 */
+	mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~((1 << 8) | (1 << 13)));
+	mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, (1 << 8) | (1 << 13));
+
+	/*
+	 * Dismiss and then enable interrupt on CPU #0 high cause reg
+	 * BIT25 summarizes GPP interrupts 8-15
+	 */
+	mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1 << 25));
+}
+
+static void __init hdpu_setup_peripherals(void)
+{
+	unsigned int val;
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+				 HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
+				 HDPU_TBEN_BASE, HDPU_TBEN_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+				 HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+				 HDPU_INTERNAL_SRAM_BASE,
+				 HDPU_INTERNAL_SRAM_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+	bh.ci->disable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+	mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, 0, 0, 0);
+
+	mv64x60_clr_bits(&bh, MV64x60_PCI0_PCI_DECODE_CNTL, (1 << 3));
+	mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3));
+	mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+			 ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)));
+
+	/* Enable pipelining */
+	mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1 << 13));
+	/* Enable Snoop Pipelineing */
+	mv64x60_set_bits(&bh, MV64360_D_UNIT_CONTROL_HIGH, (1 << 24));
+
+	/*
+	 * Change DRAM read buffer assignment.
+	 * Assign read buffer 0 dedicated only for CPU,
+	 * and the rest read buffer 1.
+	 */
+	val = mv64x60_read(&bh, MV64360_SDRAM_CONFIG);
+	val = val & 0x03ffffff;
+	val = val | 0xf8000000;
+	mv64x60_write(&bh, MV64360_SDRAM_CONFIG, val);
+
+	/*
+	 * Configure internal SRAM -
+	 * Cache coherent write back, if CONFIG_MV64360_SRAM_CACHE_COHERENT set
+	 * Parity enabled.
+	 * Parity error propagation
+	 * Arbitration not parked for CPU only
+	 * Other bits are reserved.
+	 */
+#ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT
+	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#else
+	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0);
+#endif
+
+	hdpu_intr_setup();
+}
+
+static void __init hdpu_setup_bridge(void)
+{
+	struct mv64x60_setup_info si;
+	int i;
+
+	memset(&si, 0, sizeof(si));
+
+	si.phys_reg_base = HDPU_BRIDGE_REG_BASE;
+	si.pci_0.enable_bus = 1;
+	si.pci_0.pci_io.cpu_base = HDPU_PCI0_IO_START_PROC_ADDR;
+	si.pci_0.pci_io.pci_base_hi = 0;
+	si.pci_0.pci_io.pci_base_lo = HDPU_PCI0_IO_START_PCI_ADDR;
+	si.pci_0.pci_io.size = HDPU_PCI0_IO_SIZE;
+	si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_0.pci_mem[0].cpu_base = HDPU_PCI0_MEM_START_PROC_ADDR;
+	si.pci_0.pci_mem[0].pci_base_hi = HDPU_PCI0_MEM_START_PCI_HI_ADDR;
+	si.pci_0.pci_mem[0].pci_base_lo = HDPU_PCI0_MEM_START_PCI_LO_ADDR;
+	si.pci_0.pci_mem[0].size = HDPU_PCI0_MEM_SIZE;
+	si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_0.pci_cmd_bits = 0;
+	si.pci_0.latency_timer = 0x80;
+
+	si.pci_1.enable_bus = 1;
+	si.pci_1.pci_io.cpu_base = HDPU_PCI1_IO_START_PROC_ADDR;
+	si.pci_1.pci_io.pci_base_hi = 0;
+	si.pci_1.pci_io.pci_base_lo = HDPU_PCI1_IO_START_PCI_ADDR;
+	si.pci_1.pci_io.size = HDPU_PCI1_IO_SIZE;
+	si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_mem[0].cpu_base = HDPU_PCI1_MEM_START_PROC_ADDR;
+	si.pci_1.pci_mem[0].pci_base_hi = HDPU_PCI1_MEM_START_PCI_HI_ADDR;
+	si.pci_1.pci_mem[0].pci_base_lo = HDPU_PCI1_MEM_START_PCI_LO_ADDR;
+	si.pci_1.pci_mem[0].size = HDPU_PCI1_MEM_SIZE;
+	si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_cmd_bits = 0;
+	si.pci_1.latency_timer = 0x80;
+
+	for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+		si.pci_0.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+#else
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB;	/* errata */
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB;	/* errata */
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB;	/* errata */
+
+		si.pci_0.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#endif
+	}
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_PCI);
+
+	/* Lookup PCI host bridges */
+	mv64x60_init(&bh, &si);
+	pci_dram_offset = 0;	/* System mem at same addr on PCI & cpu bus */
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = hdpu_map_irq;
+
+	mv64x60_set_bus(&bh, 0, 0);
+	bh.hose_a->first_busno = 0;
+	bh.hose_a->last_busno = 0xff;
+	bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+
+	bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+	mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+	bh.hose_b->last_busno = 0xff;
+	bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+		bh.hose_b->first_busno);
+
+	ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_REG);
+	/*
+	 * Enabling of PCI internal-vs-external arbitration
+	 * is a platform- and errata-dependent decision.
+	 */
+	return;
+}
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init hdpu_early_serial_map(void)
+{
+#ifdef	CONFIG_KGDB
+	static char first_time = 1;
+
+#if defined(CONFIG_KGDB_TTYS0)
+#define KGDB_PORT 0
+#elif defined(CONFIG_KGDB_TTYS1)
+#define KGDB_PORT 1
+#else
+#error "Invalid kgdb_tty port"
+#endif
+
+	if (first_time) {
+		gt_early_mpsc_init(KGDB_PORT,
+				   B9600 | CS8 | CREAD | HUPCL | CLOCAL);
+		first_time = 0;
+	}
+
+	return;
+#endif
+}
+#endif
+
+static void hdpu_init2(void)
+{
+	return;
+}
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init hdpu_fixup_eth_pdata(struct platform_device *pd)
+{
+
+	struct mv643xx_eth_platform_data *eth_pd;
+	eth_pd = pd->dev.platform_data;
+
+	eth_pd->port_serial_control =
+	    mv64x60_read(&bh, MV643XX_ETH_PORT_SERIAL_CONTROL_REG(pd->id) & ~1);
+
+	eth_pd->force_phy_addr = 1;
+	eth_pd->phy_addr = pd->id;
+	eth_pd->tx_queue_size = 400;
+	eth_pd->rx_queue_size = 800;
+}
+#endif
+
+static void __init hdpu_fixup_mpsc_pdata(struct platform_device *pd)
+{
+
+	struct mpsc_pdata *pdata;
+
+	pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+
+	pdata->max_idle = 40;
+	if (ppcboot_bd_valid)
+		pdata->default_baud = ppcboot_bd.bi_baudrate;
+	else
+		pdata->default_baud = HDPU_DEFAULT_BAUD;
+	pdata->brg_clk_src = HDPU_MPSC_CLK_SRC;
+	pdata->brg_clk_freq = HDPU_MPSC_CLK_FREQ;
+}
+
+#if defined(CONFIG_HDPU_FEATURES)
+static void __init hdpu_fixup_cpustate_pdata(struct platform_device *pd)
+{
+	struct platform_device *pds[1];
+	pds[0] = pd;
+	mv64x60_pd_fixup(&bh, pds, 1);
+}
+#endif
+
+static int __init hdpu_platform_notify(struct device *dev)
+{
+	static struct {
+		char *bus_id;
+		void ((*rtn) (struct platform_device * pdev));
+	} dev_map[] = {
+		{
+		MPSC_CTLR_NAME ".0", hdpu_fixup_mpsc_pdata},
+#if defined(CONFIG_MV643XX_ETH)
+		{
+		MV643XX_ETH_NAME ".0", hdpu_fixup_eth_pdata},
+#endif
+#if defined(CONFIG_HDPU_FEATURES)
+		{
+		HDPU_CPUSTATE_NAME ".0", hdpu_fixup_cpustate_pdata},
+#endif
+	};
+	struct platform_device *pdev;
+	int i;
+
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++)
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+				     BUS_ID_SIZE)) {
+
+				pdev = container_of(dev,
+						    struct platform_device,
+						    dev);
+				dev_map[i].rtn(pdev);
+			}
+
+	return 0;
+}
+
+static void __init hdpu_setup_arch(void)
+{
+	if (ppc_md.progress)
+		ppc_md.progress("hdpu_setup_arch: enter", 0);
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef	CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_SDA2;
+#endif
+
+	ppc_md.heartbeat = hdpu_heartbeat;
+
+	ppc_md.heartbeat_reset = HZ;
+	ppc_md.heartbeat_count = 1;
+
+	if (ppc_md.progress)
+		ppc_md.progress("hdpu_setup_arch: Enabling L2 cache", 0);
+
+	/* Enable L1 Parity Bits */
+	hdpu_set_l1pe();
+
+	/* Enable L2 and L3 caches (if 745x) */
+	_set_L2CR(0x80080000);
+
+	if (ppc_md.progress)
+		ppc_md.progress("hdpu_setup_arch: enter", 0);
+
+	hdpu_setup_bridge();
+
+	hdpu_setup_peripherals();
+
+#ifdef CONFIG_SERIAL_MPSC_CONSOLE
+	hdpu_early_serial_map();
+#endif
+
+	printk("SKY HDPU Compute Blade \n");
+
+	if (ppc_md.progress)
+		ppc_md.progress("hdpu_setup_arch: exit", 0);
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_OK);
+	return;
+}
+static void __init hdpu_init_irq(void)
+{
+	mv64360_init_irq();
+}
+
+static void __init hdpu_set_l1pe()
+{
+	unsigned long ictrl;
+	asm volatile ("mfspr %0, 1011":"=r" (ictrl):);
+	ictrl |= ICTRL_EICE | ICTRL_EDC | ICTRL_EICP;
+	asm volatile ("mtspr 1011, %0"::"r" (ictrl));
+}
+
+/*
+ * Set BAT 1 to map 0xf1000000 to end of physical memory space.
+ */
+static __inline__ void hdpu_set_bat(void)
+{
+	mb();
+	mtspr(SPRN_DBAT1U, 0xf10001fe);
+	mtspr(SPRN_DBAT1L, 0xf100002a);
+	mb();
+
+	return;
+}
+
+unsigned long __init hdpu_find_end_of_memory(void)
+{
+	return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+				    MV64x60_TYPE_MV64360);
+}
+
+static void hdpu_reset_board(void)
+{
+	volatile int infinite = 1;
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_RESET);
+
+	local_irq_disable();
+
+	/* Clear all the LEDs */
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) |
+						   (1 << 5) | (1 << 6)));
+
+	/* disable and invalidate the L2 cache */
+	_set_L2CR(0);
+	_set_L2CR(0x200000);
+
+	/* flush and disable L1 I/D cache */
+	__asm__ __volatile__
+	    ("\n"
+	     "mfspr   3,1008\n"
+	     "ori	5,5,0xcc00\n"
+	     "ori	4,3,0xc00\n"
+	     "andc	5,3,5\n"
+	     "sync\n"
+	     "mtspr	1008,4\n"
+	     "isync\n" "sync\n" "mtspr	1008,5\n" "isync\n" "sync\n");
+
+	/* Hit the reset bit */
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 3));
+
+	while (infinite)
+		infinite = infinite;
+
+	return;
+}
+
+static void hdpu_restart(char *cmd)
+{
+	volatile ulong i = 10000000;
+
+	hdpu_reset_board();
+
+	while (i-- > 0) ;
+	panic("restart failed\n");
+}
+
+static void hdpu_halt(void)
+{
+	local_irq_disable();
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_HALT);
+
+	/* Clear all the LEDs */
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) | (1 << 5) |
+						   (1 << 6)));
+	while (1) ;
+	/* NOTREACHED */
+}
+
+static void hdpu_power_off(void)
+{
+	hdpu_halt();
+	/* NOTREACHED */
+}
+
+static int hdpu_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid;
+
+	pvid = mfspr(SPRN_PVR);
+	seq_printf(m, "vendor\t\t: Sky Computers\n");
+	seq_printf(m, "machine\t\t: HDPU Compute Blade\n");
+	seq_printf(m, "PVID\t\t: 0x%x, vendor: %s\n",
+		   pvid, (pvid & (1 << 15) ? "IBM" : "Motorola"));
+
+	return 0;
+}
+
+static void __init hdpu_calibrate_decr(void)
+{
+	ulong freq;
+
+	if (ppcboot_bd_valid)
+		freq = ppcboot_bd.bi_busfreq / 4;
+	else
+		freq = 133000000;
+
+	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;
+}
+
+static void parse_bootinfo(unsigned long r3,
+			   unsigned long r4, unsigned long r5,
+			   unsigned long r6, unsigned long r7)
+{
+	bd_t *bd = NULL;
+	char *cmdline_start = NULL;
+	int cmdline_len = 0;
+
+	if (r3) {
+		if ((r3 & 0xf0000000) == 0)
+			r3 += KERNELBASE;
+		if ((r3 & 0xf0000000) == KERNELBASE) {
+			bd = (void *)r3;
+
+			memcpy(&ppcboot_bd, bd, sizeof(ppcboot_bd));
+			ppcboot_bd_valid = 1;
+		}
+	}
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (r4 && r5 && r5 > r4) {
+		if ((r4 & 0xf0000000) == 0)
+			r4 += KERNELBASE;
+		if ((r5 & 0xf0000000) == 0)
+			r5 += KERNELBASE;
+		if ((r4 & 0xf0000000) == KERNELBASE) {
+			initrd_start = r4;
+			initrd_end = r5;
+			initrd_below_start_ok = 1;
+		}
+	}
+#endif				/* CONFIG_BLK_DEV_INITRD */
+
+	if (r6 && r7 && r7 > r6) {
+		if ((r6 & 0xf0000000) == 0)
+			r6 += KERNELBASE;
+		if ((r7 & 0xf0000000) == 0)
+			r7 += KERNELBASE;
+		if ((r6 & 0xf0000000) == KERNELBASE) {
+			cmdline_start = (void *)r6;
+			cmdline_len = (r7 - r6);
+			strncpy(cmd_line, cmdline_start, cmdline_len);
+		}
+	}
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+static int hdpu_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static void
+hdpu_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name)
+{
+	request_region(from, extent, name);
+	return;
+}
+
+static void hdpu_ide_release_region(ide_ioreg_t from, unsigned int extent)
+{
+	release_region(from, extent);
+	return;
+}
+
+static void __init
+hdpu_ide_pci_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
+			     ide_ioreg_t ctrl_port, int *irq)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) ||
+		    ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID)) {
+			hw->irq = dev->irq;
+
+			if (irq != NULL) {
+				*irq = dev->irq;
+			}
+		}
+	}
+
+	return;
+}
+#endif
+
+void hdpu_heartbeat(void)
+{
+	if (mv64x60_read(&bh, MV64x60_GPP_VALUE) & (1 << 5))
+		mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 5));
+	else
+		mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, (1 << 5));
+
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+
+}
+
+static void __init hdpu_map_io(void)
+{
+	io_block_mapping(0xf1000000, 0xf1000000, 0x20000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+char hdpu_smp0[] = "SMP Cpu #0";
+char hdpu_smp1[] = "SMP Cpu #1";
+
+static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id,
+					     struct pt_regs *regs)
+{
+	volatile unsigned int doorbell;
+
+	doorbell = mv64x60_read(&bh, MV64360_CPU0_DOORBELL);
+
+	/* Ack the doorbell interrupts */
+	mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell);
+
+	if (doorbell & 1) {
+		smp_message_recv(0, regs);
+	}
+	if (doorbell & 2) {
+		smp_message_recv(1, regs);
+	}
+	if (doorbell & 4) {
+		smp_message_recv(2, regs);
+	}
+	if (doorbell & 8) {
+		smp_message_recv(3, regs);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id,
+					     struct pt_regs *regs)
+{
+	volatile unsigned int doorbell;
+
+	doorbell = mv64x60_read(&bh, MV64360_CPU1_DOORBELL);
+
+	/* Ack the doorbell interrupts */
+	mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell);
+
+	if (doorbell & 1) {
+		smp_message_recv(0, regs);
+	}
+	if (doorbell & 2) {
+		smp_message_recv(1, regs);
+	}
+	if (doorbell & 4) {
+		smp_message_recv(2, regs);
+	}
+	if (doorbell & 8) {
+		smp_message_recv(3, regs);
+	}
+	return IRQ_HANDLED;
+}
+
+static void smp_hdpu_CPU_two(void)
+{
+	__asm__ __volatile__
+	    ("\n"
+	     "lis     3,0x0000\n"
+	     "ori     3,3,0x00c0\n"
+	     "mtspr   26, 3\n" "li      4,0\n" "mtspr   27,4\n" "rfi");
+
+}
+
+static int smp_hdpu_probe(void)
+{
+	int *cpu_count_reg;
+	int num_cpus = 0;
+
+	cpu_count_reg = ioremap(HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE);
+	if (cpu_count_reg) {
+		num_cpus = (*cpu_count_reg >> 20) & 0x3;
+		iounmap(cpu_count_reg);
+	}
+
+	/* Validate the bits in the CPLD. If we could not map the reg, return 2.
+	 * If the register reported 0 or 3, return 2.
+	 * Older CPLD revisions set these bits to all ones (val = 3).
+	 */
+	if ((num_cpus < 1) || (num_cpus > 2)) {
+		printk
+		    ("Unable to determine the number of processors %d . deafulting to 2.\n",
+		     num_cpus);
+		num_cpus = 2;
+	}
+	return num_cpus;
+}
+
+static void
+smp_hdpu_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	if (msg > 0x3) {
+		printk("SMP %d: smp_message_pass: unknown msg %d\n",
+		       smp_processor_id(), msg);
+		return;
+	}
+	switch (target) {
+	case MSG_ALL:
+		mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+		mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+		break;
+	case MSG_ALL_BUT_SELF:
+		if (smp_processor_id())
+			mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+		else
+			mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+		break;
+	default:
+		if (target == 0)
+			mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+		else
+			mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+		break;
+	}
+}
+
+static void smp_hdpu_kick_cpu(int nr)
+{
+	volatile unsigned int *bootaddr;
+
+	if (ppc_md.progress)
+		ppc_md.progress("smp_hdpu_kick_cpu", 0);
+
+	hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_CPU1_KICK);
+
+       /* Disable BootCS. Must also reduce the windows size to zero. */
+	bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, 0, 0, 0);
+
+	bootaddr = ioremap(HDPU_INTERNAL_SRAM_BASE, HDPU_INTERNAL_SRAM_SIZE);
+	if (!bootaddr) {
+		if (ppc_md.progress)
+			ppc_md.progress("smp_hdpu_kick_cpu: ioremap failed", 0);
+		return;
+	}
+
+	memcpy((void *)(bootaddr + 0x40), (void *)&smp_hdpu_CPU_two, 0x20);
+
+	/* map SRAM to 0xfff00000 */
+	bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+				 0xfff00000, HDPU_INTERNAL_SRAM_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+	/* Enable CPU1 arbitration */
+	mv64x60_clr_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1 << 9));
+
+	/*
+	 * Wait 100mSecond until other CPU has reached __secondary_start.
+	 * When it reaches, it is permittable to rever the SRAM mapping etc...
+	 */
+	mdelay(100);
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory");
+
+	iounmap(bootaddr);
+
+	/* Set up window for internal sram (256KByte insize) */
+	bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+				 HDPU_INTERNAL_SRAM_BASE,
+				 HDPU_INTERNAL_SRAM_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+	/*
+	 * Set up windows for embedded FLASH (using boot CS window).
+	 */
+
+	bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+				 HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+}
+
+static void smp_hdpu_setup_cpu(int cpu_nr)
+{
+	if (cpu_nr == 0) {
+		if (ppc_md.progress)
+			ppc_md.progress("smp_hdpu_setup_cpu 0", 0);
+		mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, 0xff);
+		mv64x60_write(&bh, MV64360_CPU0_DOORBELL_MASK, 0xff);
+		request_irq(60, hdpu_smp_cpu0_int_handler,
+			    SA_INTERRUPT, hdpu_smp0, 0);
+	}
+
+	if (cpu_nr == 1) {
+		if (ppc_md.progress)
+			ppc_md.progress("smp_hdpu_setup_cpu 1", 0);
+
+		hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR |
+				  CPUSTATE_KERNEL_CPU1_OK);
+
+		/* Enable L1 Parity Bits */
+		hdpu_set_l1pe();
+
+		/* Enable L2 cache */
+		_set_L2CR(0);
+		_set_L2CR(0x80080000);
+
+		mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, 0x0);
+		mv64x60_write(&bh, MV64360_CPU1_DOORBELL_MASK, 0xff);
+		request_irq(28, hdpu_smp_cpu1_int_handler,
+			    SA_INTERRUPT, hdpu_smp1, 0);
+	}
+
+}
+
+void __devinit hdpu_tben_give()
+{
+	volatile unsigned long *val = 0;
+
+	/* By writing 0 to the TBEN_BASE, the timebases is frozen */
+	val = ioremap(HDPU_TBEN_BASE, 4);
+	*val = 0;
+	mb();
+
+	spin_lock(&timebase_lock);
+	timebase_upper = get_tbu();
+	timebase_lower = get_tbl();
+	spin_unlock(&timebase_lock);
+
+	while (timebase_upper || timebase_lower)
+		barrier();
+
+	/* By writing 1 to the TBEN_BASE, the timebases is thawed */
+	*val = 1;
+	mb();
+
+	iounmap(val);
+
+}
+
+void __devinit hdpu_tben_take()
+{
+	while (!(timebase_upper || timebase_lower))
+		barrier();
+
+	spin_lock(&timebase_lock);
+	set_tb(timebase_upper, timebase_lower);
+	timebase_upper = 0;
+	timebase_lower = 0;
+	spin_unlock(&timebase_lock);
+}
+
+static struct smp_ops_t hdpu_smp_ops = {
+	.message_pass = smp_hdpu_message_pass,
+	.probe = smp_hdpu_probe,
+	.kick_cpu = smp_hdpu_kick_cpu,
+	.setup_cpu = smp_hdpu_setup_cpu,
+	.give_timebase = hdpu_tben_give,
+	.take_timebase = hdpu_tben_take,
+};
+#endif				/* CONFIG_SMP */
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(r3, r4, r5, r6, r7);
+
+	isa_mem_base = 0;
+
+	ppc_md.setup_arch = hdpu_setup_arch;
+	ppc_md.init = hdpu_init2;
+	ppc_md.show_cpuinfo = hdpu_show_cpuinfo;
+	ppc_md.init_IRQ = hdpu_init_irq;
+	ppc_md.get_irq = mv64360_get_irq;
+	ppc_md.restart = hdpu_restart;
+	ppc_md.power_off = hdpu_power_off;
+	ppc_md.halt = hdpu_halt;
+	ppc_md.find_end_of_memory = hdpu_find_end_of_memory;
+	ppc_md.calibrate_decr = hdpu_calibrate_decr;
+	ppc_md.setup_io_mappings = hdpu_map_io;
+
+	bh.p_base = CONFIG_MV64X60_NEW_BASE;
+	bh.v_base = (unsigned long *)bh.p_base;
+
+	hdpu_set_bat();
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG)
+	ppc_md.progress = hdpu_mpsc_progress;	/* embedded UART */
+	mv64x60_progress_init(bh.p_base);
+#endif				/* CONFIG_SERIAL_TEXT_DEBUG */
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &hdpu_smp_ops;
+#endif				/* CONFIG_SMP */
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
+	platform_notify = hdpu_platform_notify;
+#endif
+	return;
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+/* SMP safe version of the serial text debug routine. Uses Semaphore 0 */
+void hdpu_mpsc_progress(char *s, unsigned short hex)
+{
+	while (mv64x60_read(&bh, MV64360_WHO_AM_I) !=
+	       mv64x60_read(&bh, MV64360_SEMAPHORE_0)) {
+	}
+	mv64x60_mpsc_progress(s, hex);
+	mv64x60_write(&bh, MV64360_SEMAPHORE_0, 0xff);
+}
+#endif
+
+static void hdpu_cpustate_set(unsigned char new_state)
+{
+	unsigned int state = (new_state << 21);
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (0xff << 21));
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, state);
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+static struct mtd_partition hdpu_partitions[] = {
+	{
+	 .name = "Root FS",
+	 .size = 0x03400000,
+	 .offset = 0,
+	 .mask_flags = 0,
+	 },{
+	 .name = "User FS",
+	 .size = 0x00800000,
+	 .offset = 0x03400000,
+	 .mask_flags = 0,
+	 },{
+	 .name = "Kernel Image",
+	 .size = 0x002C0000,
+	 .offset = 0x03C00000,
+	 .mask_flags = 0,
+	 },{
+	 .name = "bootEnv",
+	 .size = 0x00040000,
+	 .offset = 0x03EC0000,
+	 .mask_flags = 0,
+	 },{
+	 .name = "bootROM",
+	 .size = 0x00100000,
+	 .offset = 0x03F00000,
+	 .mask_flags = 0,
+	 }
+};
+
+static int __init hdpu_setup_mtd(void)
+{
+
+	physmap_set_partitions(hdpu_partitions, 5);
+	return 0;
+}
+
+arch_initcall(hdpu_setup_mtd);
+#endif
+
+#ifdef CONFIG_HDPU_FEATURES
+
+static struct resource hdpu_cpustate_resources[] = {
+	[0] = {
+	       .name = "addr base",
+	       .start = MV64x60_GPP_VALUE_SET,
+	       .end = MV64x60_GPP_VALUE_CLR + 1,
+	       .flags = IORESOURCE_MEM,
+	       },
+};
+
+static struct resource hdpu_nexus_resources[] = {
+	[0] = {
+	       .name = "nexus register",
+	       .start = HDPU_NEXUS_ID_BASE,
+	       .end = HDPU_NEXUS_ID_BASE + HDPU_NEXUS_ID_SIZE,
+	       .flags = IORESOURCE_MEM,
+	       },
+};
+
+static struct platform_device hdpu_cpustate_device = {
+	.name = HDPU_CPUSTATE_NAME,
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdpu_cpustate_resources),
+	.resource = hdpu_cpustate_resources,
+};
+
+static struct platform_device hdpu_nexus_device = {
+	.name = HDPU_NEXUS_NAME,
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdpu_nexus_resources),
+	.resource = hdpu_nexus_resources,
+};
+
+static int __init hdpu_add_pds(void)
+{
+	platform_device_register(&hdpu_cpustate_device);
+	platform_device_register(&hdpu_nexus_device);
+	return 0;
+}
+
+arch_initcall(hdpu_add_pds);
+#endif
diff --git a/arch/ppc/platforms/hdpu.h b/arch/ppc/platforms/hdpu.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/hdpu.h
@@ -0,0 +1,82 @@
+/*
+ * arch/ppc/platforms/hdpu.h
+ *
+ * Definitions for Sky Computers HDPU board.
+ *
+ * Brian Waite <waite@skycomputers.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@mvista.com>
+ * Based on code done by  Tim Montgomery <timm@artesyncp.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 MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 64K and start
+ * on a boundary that is a multiple of the window size):
+ *
+ *    0x80000000-0x8fffffff	 - PCI 0 MEM
+ *    0xa0000000-0xafffffff	 - PCI 1 MEM
+ *    0xc0000000-0xc0ffffff	 - PCI 0 I/O
+ *    0xc1000000-0xc1ffffff	 - PCI 1 I/O
+
+ *    0xf1000000-0xf100ffff      - MV64360 Registers
+ *    0xf1010000-0xfb9fffff      - HOLE
+ *    0xfbfa0000-0xfbfaffff      - TBEN
+ *    0xfbf00000-0xfbfbffff      - NEXUS
+ *    0xfbfc0000-0xfbffffff      - Internal SRAM
+ *    0xfc000000-0xffffffff      - Boot window
+ */
+
+#ifndef __PPC_PLATFORMS_HDPU_H
+#define __PPC_PLATFORMS_HDPU_H
+
+/* CPU Physical Memory Map setup. */
+#define	HDPU_BRIDGE_REG_BASE		     0xf1000000
+
+#define HDPU_TBEN_BASE                        0xfbfa0000
+#define HDPU_TBEN_SIZE                        0x00010000
+#define HDPU_NEXUS_ID_BASE                    0xfbfb0000
+#define HDPU_NEXUS_ID_SIZE                    0x00010000
+#define HDPU_INTERNAL_SRAM_BASE               0xfbfc0000
+#define HDPU_INTERNAL_SRAM_SIZE               0x00040000
+#define	HDPU_EMB_FLASH_BASE		      0xfc000000
+#define	HDPU_EMB_FLASH_SIZE      	      0x04000000
+
+/* PCI Mappings */
+
+#define HDPU_PCI0_MEM_START_PROC_ADDR         0x80000000
+#define HDPU_PCI0_MEM_START_PCI_HI_ADDR       0x00000000
+#define HDPU_PCI0_MEM_START_PCI_LO_ADDR       HDPU_PCI0_MEM_START_PROC_ADDR
+#define HDPU_PCI0_MEM_SIZE                    0x10000000
+
+#define HDPU_PCI1_MEM_START_PROC_ADDR         0xc0000000
+#define HDPU_PCI1_MEM_START_PCI_HI_ADDR       0x00000000
+#define HDPU_PCI1_MEM_START_PCI_LO_ADDR       HDPU_PCI1_MEM_START_PROC_ADDR
+#define HDPU_PCI1_MEM_SIZE                    0x20000000
+
+#define HDPU_PCI0_IO_START_PROC_ADDR          0xc0000000
+#define HDPU_PCI0_IO_START_PCI_ADDR           0x00000000
+#define HDPU_PCI0_IO_SIZE                     0x01000000
+
+#define HDPU_PCI1_IO_START_PROC_ADDR          0xc1000000
+#define HDPU_PCI1_IO_START_PCI_ADDR           0x01000000
+#define HDPU_PCI1_IO_SIZE                     0x01000000
+
+#define HDPU_DEFAULT_BAUD 115200
+#define HDPU_MPSC_CLK_SRC 8	/* TCLK */
+#define HDPU_MPSC_CLK_FREQ 133000000	/* 133 Mhz */
+
+#define	HDPU_PCI_0_IRQ		(8+64)
+#define	HDPU_PCI_1_IRQ		(13+64)
+
+#endif				/* __PPC_PLATFORMS_HDPU_H */
diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c
--- a/arch/ppc/platforms/k2.c
+++ b/arch/ppc/platforms/k2.c
@@ -392,9 +392,9 @@ static int k2_get_cpu_speed(void)
 	unsigned long hid1;
 	int cpu_speed;
 
-	hid1 = mfspr(HID1) >> 28;
+	hid1 = mfspr(SPRN_HID1) >> 28;
 
-	if ((mfspr(PVR) >> 16) == 8)
+	if ((mfspr(SPRN_PVR) >> 16) == 8)
 		hid1 = cpu_7xx[hid1];
 	else
 		hid1 = cpu_6xx[hid1];
@@ -472,7 +472,7 @@ static void __init k2_setup_arch(void)
 			"(source@mvista.com)\n");
 
 	/* Identify the CPU manufacturer */
-	cpu = PVR_REV(mfspr(PVR));
+	cpu = PVR_REV(mfspr(SPRN_PVR));
 	printk(KERN_INFO "CPU manufacturer: %s [rev=%04x]\n",
 			(cpu & (1 << 15)) ? "IBM" : "Motorola", cpu);
 }
@@ -486,8 +486,8 @@ static void k2_restart(char *cmd)
 
 	/* SRR0 has system reset vector, SRR1 has default MSR value */
 	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-	mtspr(SRR0, 0xfff00100);
-	mtspr(SRR1, 0);
+	mtspr(SPRN_SRR0, 0xfff00100);
+	mtspr(SPRN_SRR1, 0);
 	__asm__ __volatile__("rfi\n\t");
 
 	/* not reached */
@@ -513,10 +513,10 @@ static __inline__ void k2_set_bat(void)
 	mb();
 
 	/* setup DBATs */
-	mtspr(DBAT2U, 0x80001ffe);
-	mtspr(DBAT2L, 0x8000002a);
-	mtspr(DBAT3U, 0xf0001ffe);
-	mtspr(DBAT3L, 0xf000002a);
+	mtspr(SPRN_DBAT2U, 0x80001ffe);
+	mtspr(SPRN_DBAT2L, 0x8000002a);
+	mtspr(SPRN_DBAT3U, 0xf0001ffe);
+	mtspr(SPRN_DBAT3L, 0xf000002a);
 
 	/* wait for updates */
 	mb();
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
--- a/arch/ppc/platforms/katana.c
+++ b/arch/ppc/platforms/katana.c
@@ -1,9 +1,10 @@
 /*
  * arch/ppc/platforms/katana.c
  *
- * Board setup routines for the Artesyn Katana 750 based boards.
+ * Board setup routines for the Artesyn Katana cPCI boards.
  *
- * Tim Montgomery <timm@artesyncp.com>
+ * Author: Tim Montgomery <timm@artesyncp.com>
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
  *
  * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
  * Based on code done by - Mark A. Greer <mgreer@mvista.com>
@@ -26,7 +27,8 @@
 #include <linux/root_dev.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
-#include <linux/smp.h>
+#include <linux/bootmem.h>
+#include <linux/mtd/physmap.h>
 #include <linux/mv643xx.h>
 #ifdef CONFIG_BOOTIMG
 #include <linux/bootimg.h>
@@ -36,13 +38,21 @@
 #include <asm/smp.h>
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
+#include <asm/ppcboot.h>
 #include <asm/mv64x60.h>
 #include <platforms/katana.h>
 
 static struct		mv64x60_handle bh;
 static katana_id_t	katana_id;
-static u32		cpld_base;
-static u32		sram_base;
+static void __iomem	*cpld_base;
+static void __iomem	*sram_base;
+
+static u32		katana_flash_size_0;
+static u32		katana_flash_size_1;
+
+static u32		katana_bus_frequency;
+
+unsigned char	__res[sizeof(bd_t)];
 
 /* PCI Interrupt routing */
 static int __init
@@ -105,7 +115,7 @@ katana_map_irq(struct pci_dev *dev, unsi
 void __init
 katana_get_board_id(void)
 {
-	switch (in_8((volatile char *)(cpld_base + KATANA_CPLD_PRODUCT_ID))) {
+	switch (in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)) {
 	case KATANA_PRODUCT_ID_3750:
 		katana_id = KATANA_ID_3750;
 		break;
@@ -170,50 +180,107 @@ katana_get_proc_num(void)
 static inline int
 katana_is_monarch(void)
 {
-	return in_8((volatile char *)(cpld_base + KATANA_CPLD_BD_CFG_3)) &
+	return in_8(cpld_base + KATANA_CPLD_BD_CFG_3) &
 		KATANA_CPLD_BD_CFG_3_MONARCH;
 }
 
 static void __init
-katana_enable_ipmi(void)
+katana_setup_bridge(void)
 {
-	u8 reset_out;
+	struct pci_controller hose;
+	struct mv64x60_setup_info si;
+	void __iomem *vaddr;
+	int i;
+	u16 val;
+	u8 save_exclude;
 
-	/* Enable access to IPMI ctlr by clearing IPMI PORTSEL bit in CPLD */
-	reset_out = in_8((volatile char *)(cpld_base + KATANA_CPLD_RESET_OUT));
-	reset_out &= ~KATANA_CPLD_RESET_OUT_PORTSEL;
-	out_8((volatile void *)(cpld_base + KATANA_CPLD_RESET_OUT), reset_out);
-	return;
-}
+	/*
+	 * Some versions of the Katana firmware mistakenly change the vendor
+	 * & device id fields in the bridge's pci device (visible via pci
+	 * config accesses).  This breaks mv64x60_init() because those values
+	 * are used to identify the type of bridge that's there.  Artesyn
+	 * claims that the subsystem vendor/device id's will have the correct
+	 * Marvell values so this code puts back the correct values from there.
+	 */
+	memset(&hose, 0, sizeof(hose));
+	vaddr = ioremap(CONFIG_MV64X60_NEW_BASE, MV64x60_INTERNAL_SPACE_SIZE);
+	setup_indirect_pci_nomap(&hose, vaddr + MV64x60_PCI0_CONFIG_ADDR,
+		vaddr + MV64x60_PCI0_CONFIG_DATA);
+	save_exclude = mv64x60_pci_exclude_bridge;
+	mv64x60_pci_exclude_bridge = 0;
+
+	early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID, &val);
+
+	if (val != PCI_VENDOR_ID_MARVELL) {
+		early_read_config_word(&hose, 0, PCI_DEVFN(0, 0),
+			PCI_SUBSYSTEM_VENDOR_ID, &val);
+		early_write_config_word(&hose, 0, PCI_DEVFN(0, 0),
+			PCI_VENDOR_ID, val);
+		early_read_config_word(&hose, 0, PCI_DEVFN(0, 0),
+			PCI_SUBSYSTEM_ID, &val);
+		early_write_config_word(&hose, 0, PCI_DEVFN(0, 0),
+			PCI_DEVICE_ID, val);
+	}
 
-static unsigned long
-katana_bus_freq(void)
-{
-	u8 bd_cfg_0;
+	mv64x60_pci_exclude_bridge = save_exclude;
+	iounmap(vaddr);
 
-	bd_cfg_0 = in_8((volatile char *)(cpld_base + KATANA_CPLD_BD_CFG_0));
+	memset(&si, 0, sizeof(si));
 
-	switch (bd_cfg_0 & KATANA_CPLD_BD_CFG_0_SYSCLK_MASK) {
-	case KATANA_CPLD_BD_CFG_0_SYSCLK_200:
-		return 200000000;
-		break;
+	si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
 
-	case KATANA_CPLD_BD_CFG_0_SYSCLK_166:
-		return 166666666;
-		break;
+	si.pci_1.enable_bus = 1;
+	si.pci_1.pci_io.cpu_base = KATANA_PCI1_IO_START_PROC_ADDR;
+	si.pci_1.pci_io.pci_base_hi = 0;
+	si.pci_1.pci_io.pci_base_lo = KATANA_PCI1_IO_START_PCI_ADDR;
+	si.pci_1.pci_io.size = KATANA_PCI1_IO_SIZE;
+	si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_mem[0].cpu_base = KATANA_PCI1_MEM_START_PROC_ADDR;
+	si.pci_1.pci_mem[0].pci_base_hi = KATANA_PCI1_MEM_START_PCI_HI_ADDR;
+	si.pci_1.pci_mem[0].pci_base_lo = KATANA_PCI1_MEM_START_PCI_LO_ADDR;
+	si.pci_1.pci_mem[0].size = KATANA_PCI1_MEM_SIZE;
+	si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_cmd_bits = 0;
+	si.pci_1.latency_timer = 0x80;
 
-	case KATANA_CPLD_BD_CFG_0_SYSCLK_133:
-		return 133333333;
-		break;
+	for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
 
-	case KATANA_CPLD_BD_CFG_0_SYSCLK_100:
-		return 100000000;
-		break;
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
 
-	default:
-		return 133333333;
-		break;
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
 	}
+
+	/* Lookup PCI host bridges */
+	if (mv64x60_init(&bh, &si))
+		printk(KERN_WARNING "Bridge initialization failed.\n");
+
+	pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = katana_map_irq;
+	ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+	mv64x60_set_bus(&bh, 1, 0);
+	bh.hose_b->first_busno = 0;
+	bh.hose_b->last_busno = 0xff;
 }
 
 /* Bridge & platform setup routines */
@@ -263,13 +330,12 @@ katana_intr_setup(void)
 	 * BIT25 summarizes GPP interrupts 8-15
 	 */
 	mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25));
-	return;
 }
 
 void __init
 katana_setup_peripherals(void)
 {
-	u32 base, size_0, size_1;
+	u32 base;
 
 	/* Set up windows for boot CS, soldered & socketed flash, and CPLD */
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
@@ -277,19 +343,22 @@ katana_setup_peripherals(void)
 	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
 
 	/* Assume firmware set up window sizes correctly for dev 0 & 1 */
-	mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base, &size_0);
+	mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base,
+		&katana_flash_size_0);
 
-	if (size_0 > 0) {
+	if (katana_flash_size_0 > 0) {
 		mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
-			 KATANA_SOLDERED_FLASH_BASE, size_0, 0);
+			 KATANA_SOLDERED_FLASH_BASE, katana_flash_size_0, 0);
 		bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
 	}
 
-	mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base, &size_1);
+	mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base,
+		&katana_flash_size_1);
 
-	if (size_1 > 0) {
+	if (katana_flash_size_1 > 0) {
 		mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
-			 (KATANA_SOLDERED_FLASH_BASE + size_0), size_1, 0);
+			 (KATANA_SOLDERED_FLASH_BASE + katana_flash_size_0),
+			 katana_flash_size_1, 0);
 		bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
 	}
 
@@ -300,12 +369,12 @@ katana_setup_peripherals(void)
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
 		 KATANA_CPLD_BASE, KATANA_CPLD_SIZE, 0);
 	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
-	cpld_base = (u32)ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE);
+	cpld_base = ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE);
 
 	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
 		 KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
 	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
-	sram_base = (u32)ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+	sram_base = ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
 
 	/* Set up Enet->SRAM window */
 	mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
@@ -339,79 +408,22 @@ katana_setup_peripherals(void)
 	 * internal data path in SRAM since it's first time accessing it
 	 * while after reset it's not configured.
 	 */
-	memset((void *)sram_base, 0, MV64360_SRAM_SIZE);
+	memset(sram_base, 0, MV64360_SRAM_SIZE);
 
 	/* Only processor zero [on 3750] is an PCI interrupt controller */
 	if (katana_get_proc_num() == 0)
 		katana_intr_setup();
-
-	return;
 }
 
 static void __init
-katana_setup_bridge(void)
+katana_enable_ipmi(void)
 {
-	struct mv64x60_setup_info si;
-	int i;
-
-	memset(&si, 0, sizeof(si));
-
-	si.phys_reg_base = KATANA_BRIDGE_REG_BASE;
-
-	si.pci_1.enable_bus = 1;
-	si.pci_1.pci_io.cpu_base = KATANA_PCI1_IO_START_PROC_ADDR;
-	si.pci_1.pci_io.pci_base_hi = 0;
-	si.pci_1.pci_io.pci_base_lo = KATANA_PCI1_IO_START_PCI_ADDR;
-	si.pci_1.pci_io.size = KATANA_PCI1_IO_SIZE;
-	si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
-	si.pci_1.pci_mem[0].cpu_base = KATANA_PCI1_MEM_START_PROC_ADDR;
-	si.pci_1.pci_mem[0].pci_base_hi = KATANA_PCI1_MEM_START_PCI_HI_ADDR;
-	si.pci_1.pci_mem[0].pci_base_lo = KATANA_PCI1_MEM_START_PCI_LO_ADDR;
-	si.pci_1.pci_mem[0].size = KATANA_PCI1_MEM_SIZE;
-	si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
-	si.pci_1.pci_cmd_bits = 0;
-	si.pci_1.latency_timer = 0x80;
-
-	for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
-#if defined(CONFIG_NOT_COHERENT_CACHE)
-		si.cpu_prot_options[i] = 0;
-		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
-		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
-		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
-
-		si.pci_1.acc_cntl_options[i] =
-		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
-		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
-		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
-		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
-#else
-		si.cpu_prot_options[i] = 0;
-		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
-		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
-		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
-
-		si.pci_1.acc_cntl_options[i] =
-		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
-		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
-		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
-		    MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
-#endif
-	}
-
-	/* Lookup PCI host bridges */
-	if (mv64x60_init(&bh, &si))
-		printk(KERN_WARNING "Bridge initialization failed.\n");
-
-	pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
-	ppc_md.pci_swizzle = common_swizzle;
-	ppc_md.pci_map_irq = katana_map_irq;
-	ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
-
-	mv64x60_set_bus(&bh, 1, 0);
-	bh.hose_b->first_busno = 0;
-	bh.hose_b->last_busno = 0xff;
+	u8 reset_out;
 
-	return;
+	/* Enable access to IPMI ctlr by clearing IPMI PORTSEL bit in CPLD */
+	reset_out = in_8(cpld_base + KATANA_CPLD_RESET_OUT);
+	reset_out &= ~KATANA_CPLD_RESET_OUT_PORTSEL;
+	out_8(cpld_base + KATANA_CPLD_RESET_OUT, reset_out);
 }
 
 static void __init
@@ -440,12 +452,11 @@ katana_setup_arch(void)
 	 * DD2.0 has bug that requires the L2 to be in WRT mode
 	 * avoid dirty data in cache
 	 */
-	if (PVR_REV(mfspr(PVR)) == 0x0200) {
+	if (PVR_REV(mfspr(SPRN_PVR)) == 0x0200) {
 		printk(KERN_INFO "DD2.0 detected. Setting L2 cache"
 			"to Writethrough mode\n");
 		_set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2WT);
-	}
-	else
+	} else
 		_set_L2CR(L2CR_L2E | L2CR_L2PE);
 
 	if (ppc_md.progress)
@@ -455,10 +466,11 @@ katana_setup_arch(void)
 	katana_setup_peripherals();
 	katana_enable_ipmi();
 
+	katana_bus_frequency = katana_bus_freq(cpld_base);
+
 	printk(KERN_INFO "Artesyn Communication Products, LLC - Katana(TM)\n");
 	if (ppc_md.progress)
 		ppc_md.progress("katana_setup_arch: exit", 0);
-	return;
 }
 
 /* Platform device data fixup routines. */
@@ -473,9 +485,12 @@ katana_fixup_mpsc_pdata(struct platform_
 	pdata->max_idle = 40;
 	pdata->default_baud = KATANA_DEFAULT_BAUD;
 	pdata->brg_clk_src = KATANA_MPSC_CLK_SRC;
-	pdata->brg_clk_freq = KATANA_MPSC_CLK_FREQ;
-
-	return;
+	/*
+	 * TCLK (not SysCLk) is routed to BRG, then to the MPSC.  On most parts,
+	 * TCLK == SysCLK but on 64460, they are separate pins.
+	 * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz.
+	 */
+	pdata->brg_clk_freq = min(katana_bus_frequency, MV64x60_TCLK_FREQ_MAX);
 }
 #endif
 
@@ -483,32 +498,18 @@ katana_fixup_mpsc_pdata(struct platform_
 static void __init
 katana_fixup_eth_pdata(struct platform_device *pdev)
 {
-	struct mv64xxx_eth_platform_data *eth_pd;
+	struct mv643xx_eth_platform_data *eth_pd;
 	static u16 phy_addr[] = {
 		KATANA_ETH0_PHY_ADDR,
 		KATANA_ETH1_PHY_ADDR,
 		KATANA_ETH2_PHY_ADDR,
 	};
-	int	rx_size = KATANA_ETH_RX_QUEUE_SIZE * MV64340_ETH_DESC_SIZE;
-	int	tx_size = KATANA_ETH_TX_QUEUE_SIZE * MV64340_ETH_DESC_SIZE;
 
 	eth_pd = pdev->dev.platform_data;
 	eth_pd->force_phy_addr = 1;
 	eth_pd->phy_addr = phy_addr[pdev->id];
 	eth_pd->tx_queue_size = KATANA_ETH_TX_QUEUE_SIZE;
 	eth_pd->rx_queue_size = KATANA_ETH_RX_QUEUE_SIZE;
-	eth_pd->tx_sram_addr = mv643xx_sram_alloc(tx_size);
-
-	if (eth_pd->tx_sram_addr)
-		eth_pd->tx_sram_size = tx_size;
-	else
-		printk(KERN_ERR "mv643xx_sram_alloc failed\n");
-
-	eth_pd->rx_sram_addr = mv643xx_sram_alloc(rx_size);
-	if (eth_pd->rx_sram_addr)
-		eth_pd->rx_sram_size = rx_size;
-	else
-		printk(KERN_ERR "mv643xx_sram_alloc failed\n");
 }
 #endif
 
@@ -520,13 +521,13 @@ katana_platform_notify(struct device *de
 		void	((*rtn)(struct platform_device *pdev));
 	} dev_map[] = {
 #if defined(CONFIG_SERIAL_MPSC)
-		{ MPSC_CTLR_NAME "0", katana_fixup_mpsc_pdata },
-		{ MPSC_CTLR_NAME "1", katana_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".0", katana_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".1", katana_fixup_mpsc_pdata },
 #endif
 #if defined(CONFIG_MV643XX_ETH)
-		{ MV64XXX_ETH_NAME "0", katana_fixup_eth_pdata },
-		{ MV64XXX_ETH_NAME "1", katana_fixup_eth_pdata },
-		{ MV64XXX_ETH_NAME "2", katana_fixup_eth_pdata },
+		{ MV643XX_ETH_NAME ".0", katana_fixup_eth_pdata },
+		{ MV643XX_ETH_NAME ".1", katana_fixup_eth_pdata },
+		{ MV643XX_ETH_NAME ".2", katana_fixup_eth_pdata },
 #endif
 	};
 	struct platform_device	*pdev;
@@ -545,14 +546,82 @@ katana_platform_notify(struct device *de
 	return 0;
 }
 
+#ifdef CONFIG_MTD_PHYSMAP
+
+#ifndef MB
+#define MB	(1 << 20)
+#endif
+
+/*
+ * MTD Layout depends on amount of soldered FLASH in system. Sizes in MB.
+ *
+ * FLASH Amount:	128	64	32	16
+ * -------------	---	--	--	--
+ * Monitor:		1	1	1	1
+ * Primary Kernel:	1.5	1.5	1.5	1.5
+ * Primary fs:		30	30	<end>	<end>
+ * Secondary Kernel:	1.5	1.5	N/A	N/A
+ * Secondary fs:	<end>	<end>	N/A	N/A
+ * User: 		<overlays entire FLASH except for "Monitor" section>
+ */
+static int __init
+katana_setup_mtd(void)
+{
+	u32	size;
+	int	ptbl_entries;
+	static struct mtd_partition	*ptbl;
+
+	size = katana_flash_size_0 + katana_flash_size_1;
+	if (!size)
+		return -ENOMEM;
+
+	ptbl_entries = (size >= (64*MB)) ? 6 : 4;
+
+	if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
+		GFP_KERNEL)) == NULL) {
+
+		printk(KERN_WARNING "Can't alloc MTD partition table\n");
+		return -ENOMEM;
+	}
+	memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
+
+	ptbl[0].name = "Monitor";
+	ptbl[0].size = KATANA_MTD_MONITOR_SIZE;
+	ptbl[1].name = "Primary Kernel";
+	ptbl[1].offset = MTDPART_OFS_NXTBLK;
+	ptbl[1].size = 0x00180000; /* 1.5 MB */
+	ptbl[2].name = "Primary Filesystem";
+	ptbl[2].offset = MTDPART_OFS_APPEND;
+	ptbl[2].size = MTDPART_SIZ_FULL; /* Correct for 16 & 32 MB */
+	ptbl[ptbl_entries-1].name = "User FLASH";
+	ptbl[ptbl_entries-1].offset = KATANA_MTD_MONITOR_SIZE;
+	ptbl[ptbl_entries-1].size = MTDPART_SIZ_FULL;
+
+	if (size >= (64*MB)) {
+		ptbl[2].size = 30*MB;
+		ptbl[3].name = "Secondary Kernel";
+		ptbl[3].offset = MTDPART_OFS_NXTBLK;
+		ptbl[3].size = 0x00180000; /* 1.5 MB */
+		ptbl[4].name = "Secondary Filesystem";
+		ptbl[4].offset = MTDPART_OFS_APPEND;
+		ptbl[4].size = MTDPART_SIZ_FULL;
+	}
+
+	physmap_map.size = size;
+	physmap_set_partitions(ptbl, ptbl_entries);
+	return 0;
+}
+
+arch_initcall(katana_setup_mtd);
+#endif
+
 static void
 katana_restart(char *cmd)
 {
-	volatile ulong i = 10000000;
+	ulong	i = 10000000;
 
 	/* issue hard reset to the reset command register */
-	out_8((volatile char *)(cpld_base + KATANA_CPLD_RST_CMD),
-		KATANA_CPLD_RST_CMD_HR);
+	out_8(cpld_base + KATANA_CPLD_RST_CMD, KATANA_CPLD_RST_CMD_HR);
 
 	while (i-- > 0) ;
 	panic("restart failed\n");
@@ -561,6 +630,14 @@ katana_restart(char *cmd)
 static void
 katana_halt(void)
 {
+	u8	v;
+
+	if (katana_id == KATANA_ID_752I) {
+		   v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF);
+		   v |= HSL_PLD_HOT_SWAP_LED_BIT;
+		   out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v);
+	}
+
 	while (1) ;
 	/* NOTREACHED */
 }
@@ -598,12 +675,13 @@ katana_show_cpuinfo(struct seq_file *m)
 	}
 
 	seq_printf(m, "product ID\t: 0x%x\n",
-		   in_8((volatile char *)(cpld_base + KATANA_CPLD_PRODUCT_ID)));
+		   in_8(cpld_base + KATANA_CPLD_PRODUCT_ID));
 	seq_printf(m, "hardware rev\t: 0x%x\n",
-		   in_8((volatile char *)(cpld_base+KATANA_CPLD_HARDWARE_VER)));
+		   in_8(cpld_base+KATANA_CPLD_HARDWARE_VER));
 	seq_printf(m, "PLD rev\t\t: 0x%x\n",
-		   in_8((volatile char *)(cpld_base + KATANA_CPLD_PLD_VER)));
-	seq_printf(m, "PLB freq\t: %ldMhz\n", katana_bus_freq() / 1000000);
+		   in_8(cpld_base + KATANA_CPLD_PLD_VER));
+	seq_printf(m, "PLB freq\t: %ldMhz\n",
+		(long)katana_bus_frequency / 1000000);
 	seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-");
 
 	return 0;
@@ -612,35 +690,52 @@ katana_show_cpuinfo(struct seq_file *m)
 static void __init
 katana_calibrate_decr(void)
 {
-	ulong freq;
+	u32 freq;
 
-	freq = katana_bus_freq() / 4;
+	freq = katana_bus_frequency / 4;
 
 	printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
-	       freq / 1000000, freq % 1000000);
+	       (long)freq / 1000000, (long)freq % 1000000);
 
 	tb_ticks_per_jiffy = freq / HZ;
 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-	return;
 }
 
 unsigned long __init
 katana_find_end_of_memory(void)
 {
-	return mv64x60_get_mem_size(KATANA_BRIDGE_REG_BASE,
+	return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
 		MV64x60_TYPE_MV64360);
 }
 
+#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
+extern ulong	m41t00_get_rtc_time(void);
+extern int	m41t00_set_rtc_time(ulong);
+
+static int __init
+katana_rtc_hookup(void)
+{
+	struct timespec	tv;
+
+	ppc_md.get_rtc_time = m41t00_get_rtc_time;
+	ppc_md.set_rtc_time = m41t00_set_rtc_time;
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = (ppc_md.get_rtc_time)();
+	do_settimeofday(&tv);
+
+	return 0;
+}
+late_initcall(katana_rtc_hookup);
+#endif
+
 static inline void
 katana_set_bat(void)
 {
 	mb();
-	mtspr(DBAT2U, 0xf0001ffe);
-	mtspr(DBAT2L, 0xf000002a);
+	mtspr(SPRN_DBAT2U, 0xf0001ffe);
+	mtspr(SPRN_DBAT2L, 0xf000002a);
 	mb();
-
-	return;
 }
 
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
@@ -657,6 +752,23 @@ platform_init(unsigned long r3, unsigned
 {
 	parse_bootinfo(find_bootinfo());
 
+	/* ASSUMPTION:  If both r3 (bd_t pointer) and r6 (cmdline pointer)
+	 * are non-zero, then we should use the board info from the bd_t
+	 * structure and the cmdline pointed to by r6 instead of the
+	 * information from birecs, if any.  Otherwise, use the information
+	 * from birecs as discovered by the preceeding call to
+	 * parse_bootinfo().  This rule should work with both PPCBoot, which
+	 * uses a bd_t board info structure, and the kernel boot wrapper,
+	 * which uses birecs.
+	 */
+	if (r3 && r6) {
+		/* copy board info structure */
+		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+		/* copy command line */
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
 	isa_mem_base = 0;
 
 	ppc_md.setup_arch = katana_setup_arch;
@@ -672,7 +784,7 @@ platform_init(unsigned long r3, unsigned
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
 	ppc_md.setup_io_mappings = katana_map_io;
 	ppc_md.progress = mv64x60_mpsc_progress;
-	mv64x60_progress_init(KATANA_BRIDGE_REG_BASE);
+	mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
 #endif
 
 #if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
@@ -680,5 +792,4 @@ platform_init(unsigned long r3, unsigned
 #endif
 
 	katana_set_bat(); /* Need for katana_find_end_of_memory and progress */
-	return;
 }
diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h
--- a/arch/ppc/platforms/katana.h
+++ b/arch/ppc/platforms/katana.h
@@ -3,7 +3,8 @@
  *
  * Definitions for Artesyn Katana750i/3750 board.
  *
- * Tim Montgomery <timm@artesyncp.com>
+ * Author: Tim Montgomery <timm@artesyncp.com>
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
  *
  * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
  * Based on code done by Mark A. Greer <mgreer@mvista.com>
@@ -19,18 +20,17 @@
  * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
  * We'll only use one PCI MEM window on each PCI bus.
  *
- * This is the CPU physical memory map (windows must be at least 1MB and start
+ * This is the CPU physical memory map (windows must be at least 64 KB and start
  * on a boundary that is a multiple of the window size):
  *
  *    0xff800000-0xffffffff      - Boot window
- *    0xf8400000-0xf85fffff      - Internal SRAM
- *    0xf8200000-0xf823ffff      - CPLD
- *    0xf8100000-0xf810ffff      - MV64360 Registers
- *    0xf8000000-0xf80fffff      - PLCC socket
- *    0xf0000000-0xf01fffff	 - Consistent memory pool
- *    0xe8000000-0xefffffff      - soldered flash
- *    0xc0000000-0xc0ffffff      - PCI I/O
- *    0x80000000-0xbfffffff      - PCI MEM
+ *    0xf8400000-0xf843ffff      - Internal SRAM
+ *    0xf8200000-0xf83fffff      - CPLD
+ *    0xf8100000-0xf810ffff      - MV64360 Registers (CONFIG_MV64X60_NEW_BASE)
+ *    0xf8000000-0xf80fffff      - Socketed FLASH
+ *    0xe0000000-0xefffffff      - Soldered FLASH
+ *    0xc0000000-0xc3ffffff      - PCI I/O (second hose)
+ *    0x80000000-0xbfffffff      - PCI MEM (second hose)
  */
 
 #ifndef __PPC_PLATFORMS_KATANA_H
@@ -38,33 +38,22 @@
 
 /* CPU Physical Memory Map setup. */
 #define KATANA_BOOT_WINDOW_BASE			0xff800000
+#define KATANA_BOOT_WINDOW_SIZE			0x00800000 /* 8 MB */
 #define KATANA_INTERNAL_SRAM_BASE		0xf8400000
 #define KATANA_CPLD_BASE			0xf8200000
-#define KATANA_BRIDGE_REG_BASE			0xf8100000
+#define KATANA_CPLD_SIZE			0x00200000 /* 2 MB */
 #define KATANA_SOCKET_BASE			0xf8000000
-#define KATANA_SOLDERED_FLASH_BASE		0xe8000000
-
-#define KATANA_BOOT_WINDOW_SIZE_ACTUAL		0x00800000 /* 8MB */
-#define KATANA_CPLD_SIZE_ACTUAL			0x00020000 /* 128KB */
-#define KATANA_SOCKETED_FLASH_SIZE_ACTUAL	0x00080000 /* 512KB */
-#define KATANA_SOLDERED_FLASH_SIZE_ACTUAL	0x02000000 /* 32MB */
-
-#define KATANA_BOOT_WINDOW_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
-		KATANA_BOOT_WINDOW_SIZE_ACTUAL)
-#define KATANA_CPLD_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
-		KATANA_CPLD_SIZE_ACTUAL)
-#define KATANA_SOCKETED_FLASH_SIZE	max(MV64360_WINDOW_SIZE_MIN,	\
-		KATANA_SOCKETED_FLASH_SIZE_ACTUAL)
-#define KATANA_SOLDERED_FLASH_SIZE	max(MV64360_WINDOW_SIZE_MIN,	\
-		KATANA_SOLDERED_FLASH_SIZE_ACTUAL)
+#define KATANA_SOCKETED_FLASH_SIZE		0x00100000 /* 1 MB */
+#define KATANA_SOLDERED_FLASH_BASE		0xe0000000
+#define KATANA_SOLDERED_FLASH_SIZE		0x10000000 /* 256 MB */
 
 #define KATANA_PCI1_MEM_START_PROC_ADDR         0x80000000
 #define KATANA_PCI1_MEM_START_PCI_HI_ADDR       0x00000000
 #define KATANA_PCI1_MEM_START_PCI_LO_ADDR       0x80000000
-#define KATANA_PCI1_MEM_SIZE                    0x40000000
+#define KATANA_PCI1_MEM_SIZE                    0x40000000 /* 1 GB */
 #define KATANA_PCI1_IO_START_PROC_ADDR          0xc0000000
 #define KATANA_PCI1_IO_START_PCI_ADDR           0x00000000
-#define KATANA_PCI1_IO_SIZE                     0x01000000
+#define KATANA_PCI1_IO_SIZE                     0x04000000 /* 64 MB */
 
 /* Board-specific IRQ info */
 #define  KATANA_PCI_INTA_IRQ_3750		64+8
@@ -138,6 +127,8 @@
 #define HSL_PLD_J4SGA_REG_OFF			0
 #define HSL_PLD_J4GA_REG_OFF			1
 #define HSL_PLD_J2GA_REG_OFF			2
+#define HSL_PLD_HOT_SWAP_OFF			6
+#define HSL_PLD_HOT_SWAP_LED_BIT		0x1
 #define GA_MASK					0x1f
 #define HSL_PLD_SIZE				0x1000
 #define K3750_GPP_GEO_ADDR_PINS			0xf8000000
@@ -162,7 +153,8 @@
 
 #define	KATANA_DEFAULT_BAUD			9600
 #define	KATANA_MPSC_CLK_SRC			8	  /* TCLK */
-#define	KATANA_MPSC_CLK_FREQ			133333333 /* 133.3333... MHz */
+
+#define	KATANA_MTD_MONITOR_SIZE			(1 << 20) /* 1 MB */
 
 #define	KATANA_ETH0_PHY_ADDR			12
 #define	KATANA_ETH1_PHY_ADDR			11
@@ -230,4 +222,34 @@ typedef enum {
 
 #endif
 
-#endif				/* __PPC_PLATFORMS_KATANA_H */
+static inline u32
+katana_bus_freq(void __iomem *cpld_base)
+{
+	u8 bd_cfg_0;
+
+	bd_cfg_0 = in_8(cpld_base + KATANA_CPLD_BD_CFG_0);
+
+	switch (bd_cfg_0 & KATANA_CPLD_BD_CFG_0_SYSCLK_MASK) {
+	case KATANA_CPLD_BD_CFG_0_SYSCLK_200:
+		return 200000000;
+		break;
+
+	case KATANA_CPLD_BD_CFG_0_SYSCLK_166:
+		return 166666666;
+		break;
+
+	case KATANA_CPLD_BD_CFG_0_SYSCLK_133:
+		return 133333333;
+		break;
+
+	case KATANA_CPLD_BD_CFG_0_SYSCLK_100:
+		return 100000000;
+		break;
+
+	default:
+		return 133333333;
+		break;
+	}
+}
+
+#endif	/* __PPC_PLATFORMS_KATANA_H */
diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c
--- a/arch/ppc/platforms/lite5200.c
+++ b/arch/ppc/platforms/lite5200.c
@@ -13,7 +13,7 @@
  * Dale Farnsworth <dale.farnsworth@mvista.com> and
  * Wolfgang Denk <wd@denx.de>
  * 
- * Copyright 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright 2004-2005 Sylvain Munaut <tnt@246tNt.com>
  * Copyright 2003 Motorola Inc.
  * Copyright 2003 MontaVista Software Inc.
  * Copyright 2003 DENX Software Engineering (wd@denx.de)
@@ -29,11 +29,14 @@
 #include <linux/kdev_t.h>
 #include <linux/root_dev.h>
 #include <linux/console.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/io.h>
-#include <asm/ocp.h>
 #include <asm/mpc52xx.h>
+#include <asm/ppc_sys.h>
+
+#include <syslib/mpc52xx_pci.h>
 
 
 extern int powersave_nap;
@@ -44,33 +47,19 @@ EXPORT_SYMBOL(__res);	/* For modules */
 
 
 /* ======================================================================== */
-/* OCP device definition                                                    */
-/* For board/shared resources like PSCs                                     */
+/* Platform specific code                                                   */
 /* ======================================================================== */
-/* Be sure not to load conficting devices : e.g. loading the UART drivers for
- * PSC1 and then also loading a AC97 for this same PSC.
- * For details about how to create an entry, look in the doc of the concerned
- * driver ( eg drivers/serial/mpc52xx_uart.c for the PSC in uart mode )
- */
-
-struct ocp_def board_ocp[] = {
-	{
-		.vendor		= OCP_VENDOR_FREESCALE,
-		.function	= OCP_FUNC_PSC_UART,
-		.index		= 0,
-		.paddr		= MPC52xx_PSC1,
-		.irq		= MPC52xx_PSC1_IRQ,
-		.pm		= OCP_CPM_NA,
-	},
-	{	/* Terminating entry */
-		.vendor		= OCP_VENDOR_INVALID
-	}
-};
 
+/* Supported PSC function in "preference" order */
+struct mpc52xx_psc_func mpc52xx_psc_functions[] = {
+		{       .id     = 0,
+			.func   = "uart",
+		},
+		{       .id     = -1,   /* End entry */
+			.func   = NULL,
+		}
+	};
 
-/* ======================================================================== */
-/* Platform specific code                                                   */
-/* ======================================================================== */
 
 static int
 lite5200_show_cpuinfo(struct seq_file *m)
@@ -79,22 +68,66 @@ lite5200_show_cpuinfo(struct seq_file *m
 	return 0;
 }
 
+#ifdef CONFIG_PCI
+static int
+lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	return (pin == 1) && (idsel==24) ? MPC52xx_IRQ0 : -1;
+}
+#endif
+
 static void __init
 lite5200_setup_cpu(void)
 {
-	struct mpc52xx_intr *intr;
+	struct mpc52xx_cdm  __iomem *cdm;
+	struct mpc52xx_gpio __iomem *gpio;
+	struct mpc52xx_intr __iomem *intr;
+	struct mpc52xx_xlb  __iomem *xlb;
 
+	u32 port_config;
 	u32 intr_ctrl;
 
 	/* Map zones */
-	intr = (struct mpc52xx_intr *)
-		ioremap(MPC52xx_INTR,sizeof(struct mpc52xx_intr));
-
-	if (!intr) {
-		printk("lite5200.c: Error while mapping INTR during lite5200_setup_cpu\n");
+	cdm  = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+	xlb  = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE);
+	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
+
+	if (!cdm || !gpio || !xlb || !intr) {
+		printk("lite5200.c: Error while mapping CDM/GPIO/XLB/INTR during"
+				"lite5200_setup_cpu\n");
 		goto unmap_regs;
 	}
 
+	/* Use internal 48 Mhz */
+	out_8(&cdm->ext_48mhz_en, 0x00);
+	out_8(&cdm->fd_enable, 0x01);
+	if (in_be32(&cdm->rstcfg) & 0x40)	/* Assumes 33Mhz clock */
+		out_be16(&cdm->fd_counters, 0x0001);
+	else
+		out_be16(&cdm->fd_counters, 0x5555);
+
+	/* Get port mux config */
+	port_config = in_be32(&gpio->port_config);
+
+	/* 48Mhz internal, pin is GPIO */
+	port_config &= ~0x00800000;
+
+	/* USB port */
+	port_config &= ~0x00007000;	/* Differential mode - USB1 only */
+	port_config |=  0x00001000;
+
+	/* Commit port config */
+	out_be32(&gpio->port_config, port_config);
+
+	/* Configure the XLB Arbiter */
+	out_be32(&xlb->master_pri_enable, 0xff);
+	out_be32(&xlb->master_priority, 0x11111111);
+
+	/* Enable ram snooping for 1GB window */
+	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
+	out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d);
+
 	/* IRQ[0-3] setup : IRQ0     - Level Active Low  */
 	/*                  IRQ[1-3] - Level Active High */
 	intr_ctrl = in_be32(&intr->ctrl);
@@ -104,17 +137,22 @@ lite5200_setup_cpu(void)
 
 	/* Unmap reg zone */
 unmap_regs:
+	if (cdm)  iounmap(cdm);
+	if (gpio) iounmap(gpio);
+	if (xlb)  iounmap(xlb);
 	if (intr) iounmap(intr);
 }
 
 static void __init
 lite5200_setup_arch(void)
 {
-	/* Add board OCP definitions */
-	mpc52xx_add_board_devices(board_ocp);
-
 	/* CPU & Port mux setup */
 	lite5200_setup_cpu();
+
+#ifdef CONFIG_PCI
+	/* PCI Bridge setup */
+	mpc52xx_find_bridges();
+#endif
 }
 
 void __init
@@ -150,15 +188,22 @@ platform_init(unsigned long r3, unsigned
 		}
 	}
 
+	/* PPC Sys identification */
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
 	/* BAT setup */
 	mpc52xx_set_bat();
 
-	/* No ISA bus AFAIK */
+	/* No ISA bus by default */
 	isa_io_base		= 0;
 	isa_mem_base		= 0;
 
 	/* Powersave */
-	powersave_nap = 1;	/* We allow this platform to NAP */
+	/* This is provided as an example on how to do it. But you
+	   need to be aware that NAP disable bus snoop and that may
+	   be required for some devices to work properly, like USB ... */
+	/* powersave_nap = 1; */
+
 
 	/* Setup the ppc_md struct */
 	ppc_md.setup_arch	= lite5200_setup_arch;
@@ -167,6 +212,10 @@ platform_init(unsigned long r3, unsigned
 	ppc_md.init_IRQ		= mpc52xx_init_irq;
 	ppc_md.get_irq		= mpc52xx_get_irq;
 
+#ifdef CONFIG_PCI
+	ppc_md.pci_map_irq	= lite5200_map_irq;
+#endif
+
 	ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory;
 	ppc_md.setup_io_mappings  = mpc52xx_map_io;
 
diff --git a/arch/ppc/platforms/lite5200.h b/arch/ppc/platforms/lite5200.h
--- a/arch/ppc/platforms/lite5200.h
+++ b/arch/ppc/platforms/lite5200.h
@@ -17,7 +17,7 @@
 #define __PLATFORMS_LITE5200_H__
 
 /* Serial port used for low-level debug */
-#define MPC52xx_PF_CONSOLE_PORT 0	/* PSC1 */
+#define MPC52xx_PF_CONSOLE_PORT 1	/* PSC1 */
 
 
 #endif /* __PLATFORMS_LITE5200_H__ */
diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c
--- a/arch/ppc/platforms/lopec.c
+++ b/arch/ppc/platforms/lopec.c
@@ -319,8 +319,8 @@ static __inline__ void
 lopec_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xf8000ffe);
-	mtspr(DBAT1L, 0xf800002a);
+	mtspr(SPRN_DBAT1U, 0xf8000ffe);
+	mtspr(SPRN_DBAT1L, 0xf800002a);
 	mb();
 }
 
diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c
--- a/arch/ppc/platforms/mcpn765.c
+++ b/arch/ppc/platforms/mcpn765.c
@@ -470,8 +470,8 @@ static __inline__ void
 mcpn765_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xfe8000fe);
-	mtspr(DBAT1L, 0xfe80002a);
+	mtspr(SPRN_DBAT1U, 0xfe8000fe);
+	mtspr(SPRN_DBAT1L, 0xfe80002a);
 	mb();
 }
 
diff --git a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c
--- a/arch/ppc/platforms/mpc5200.c
+++ b/arch/ppc/platforms/mpc5200.c
@@ -17,7 +17,7 @@
 #include <asm/mpc52xx.h>
 
 
-struct ocp_fs_i2c_data mpc5200_i2c_def = {
+static struct ocp_fs_i2c_data mpc5200_i2c_def = {
         .flags  = FS_I2C_CLOCK_5200,
 };
 
diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c
--- a/arch/ppc/platforms/mvme5100.c
+++ b/arch/ppc/platforms/mvme5100.c
@@ -246,8 +246,8 @@ static __inline__ void
 mvme5100_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xf0001ffe);
-	mtspr(DBAT1L, 0xf000002a);
+	mtspr(SPRN_DBAT1U, 0xf0001ffe);
+	mtspr(SPRN_DBAT1L, 0xf000002a);
 	mb();
 }
 
diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c
--- a/arch/ppc/platforms/pcore.c
+++ b/arch/ppc/platforms/pcore.c
@@ -282,8 +282,8 @@ static __inline__ void
 pcore_set_bat(void)
 {
 	mb();
-	mtspr(DBAT3U, 0xf0001ffe);
-	mtspr(DBAT3L, 0xfe80002a);
+	mtspr(SPRN_DBAT3U, 0xf0001ffe);
+	mtspr(SPRN_DBAT3L, 0xfe80002a);
 	mb();
 
 }
diff --git a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c
--- a/arch/ppc/platforms/pmac_backlight.c
+++ b/arch/ppc/platforms/pmac_backlight.c
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>
 #include <linux/reboot.h>
 #include <linux/nvram.h>
+#include <linux/console.h>
 #include <asm/sections.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
@@ -25,14 +26,19 @@
 #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 struct backlight_controller *backlighter;
+static void* backlighter_data;
+static int backlight_autosave;
 static int backlight_level = BACKLIGHT_MAX;
 static int backlight_enabled = 1;
+static int backlight_req_level = -1;
+static int backlight_req_enable = -1;
 
-void __pmac
-register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+static void backlight_callback(void *);
+static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+
+void __pmac register_backlight_controller(struct backlight_controller *ctrler,
+					  void *data, char *type)
 {
 	struct device_node* bk_node;
 	char *prop;
@@ -83,16 +89,18 @@ register_backlight_controller(struct bac
 		backlight_level = req.reply[0] >> 4;
 	}
 #endif
+	acquire_console_sem();
 	if (!backlighter->set_enable(1, backlight_level, data))
 		backlight_enabled = 1;
+	release_console_sem();
 
-	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
-		type, backlight_level);
+	printk(KERN_INFO "Registered \"%s\" backlight controller,"
+	       "level: %d/15\n", type, backlight_level);
 }
 EXPORT_SYMBOL(register_backlight_controller);
 
-void __pmac
-unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+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)
@@ -100,22 +108,32 @@ unregister_backlight_controller(struct b
 }
 EXPORT_SYMBOL(unregister_backlight_controller);
 
-int __pmac
-set_backlight_enable(int enable)
+static int __pmac __set_backlight_enable(int enable)
 {
 	int rc;
 
 	if (!backlighter)
 		return -ENODEV;
-	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+	acquire_console_sem();
+	rc = backlighter->set_enable(enable, backlight_level,
+				     backlighter_data);
 	if (!rc)
 		backlight_enabled = enable;
+	release_console_sem();
 	return rc;
 }
+int __pmac set_backlight_enable(int enable)
+{
+	if (!backlighter)
+		return -ENODEV;
+	backlight_req_enable = enable;
+	schedule_work(&backlight_work);
+	return 0;
+}
+
 EXPORT_SYMBOL(set_backlight_enable);
 
-int __pmac
-get_backlight_enable(void)
+int __pmac get_backlight_enable(void)
 {
 	if (!backlighter)
 		return -ENODEV;
@@ -123,8 +141,7 @@ get_backlight_enable(void)
 }
 EXPORT_SYMBOL(get_backlight_enable);
 
-int __pmac
-set_backlight_level(int level)
+static int __pmac __set_backlight_level(int level)
 {
 	int rc = 0;
 
@@ -134,10 +151,12 @@ set_backlight_level(int level)
 		level = BACKLIGHT_OFF;
 	if (level > BACKLIGHT_MAX)
 		level = BACKLIGHT_MAX;
+	acquire_console_sem();
 	if (backlight_enabled)
 		rc = backlighter->set_level(level, backlighter_data);
 	if (!rc)
 		backlight_level = level;
+	release_console_sem();
 	if (!rc && !backlight_autosave) {
 		level <<=1;
 		if (level & 0x10)
@@ -146,13 +165,38 @@ set_backlight_level(int level)
 	}
 	return rc;
 }
+int __pmac set_backlight_level(int level)
+{
+	if (!backlighter)
+		return -ENODEV;
+	backlight_req_level = level;
+	schedule_work(&backlight_work);
+	return 0;
+}
+
 EXPORT_SYMBOL(set_backlight_level);
 
-int __pmac
-get_backlight_level(void)
+int __pmac get_backlight_level(void)
 {
 	if (!backlighter)
 		return -ENODEV;
 	return backlight_level;
 }
 EXPORT_SYMBOL(get_backlight_level);
+
+static void backlight_callback(void *dummy)
+{
+	int level, enable;
+
+	do {
+		level = backlight_req_level;
+		enable = backlight_req_enable;
+		mb();
+
+		if (level >= 0)
+			__set_backlight_level(level);
+		if (enable >= 0)
+			__set_backlight_enable(enable);
+	} while(cmpxchg(&backlight_req_level, level, -1) != level ||
+		cmpxchg(&backlight_req_enable, enable, -1) != enable);
+}
diff --git a/arch/ppc/platforms/pmac_cache.S b/arch/ppc/platforms/pmac_cache.S
--- a/arch/ppc/platforms/pmac_cache.S
+++ b/arch/ppc/platforms/pmac_cache.S
@@ -28,6 +28,9 @@
  */
 
 _GLOBAL(flush_disable_caches)
+#ifndef CONFIG_6xx
+	blr
+#else
 BEGIN_FTR_SECTION
 	b	flush_disable_745x
 END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
@@ -55,44 +58,56 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
 	/* Stop DPM */
-	mfspr	r8,SPRN_HID0		/* Save HID0 in r8 */
+	mfspr	r8,SPRN_HID0		/* Save SPRN_HID0 in r8 */
 	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
 	sync
 	mtspr	SPRN_HID0,r4		/* Disable DPM */
 	sync
 
-	/* disp-flush L1 */
-	li	r4,0x4000
-	mtctr	r4
+	/* Disp-flush L1. We have a weird problem here that I never
+	 * totally figured out. On 750FX, using the ROM for the flush
+	 * results in a non-working flush. We use that workaround for
+	 * now until I finally understand what's going on. --BenH
+	 */
+
+	/* ROM base by default */
 	lis	r4,0xfff0
-1:	lwzx	r0,r0,r4
+	mfpvr	r3
+	srwi	r3,r3,16
+	cmplwi	cr0,r3,0x7000
+	bne+	1f
+	/* RAM base on 750FX */
+	li	r4,0
+1:	li	r4,0x4000
+	mtctr	r4
+1:	lwz	r0,0(r4)
 	addi	r4,r4,32
 	bdnz	1b
 	sync
 	isync
 
-	/* disable / invalidate / enable L1 data */
+	/* Disable / invalidate / enable L1 data */
 	mfspr	r3,SPRN_HID0
-	rlwinm	r0,r0,0,~HID0_DCE
+	rlwinm	r3,r3,0,~(HID0_DCE | HID0_ICE)
 	mtspr	SPRN_HID0,r3
 	sync
 	isync
-	ori	r3,r3,HID0_DCE|HID0_DCI
+	ori	r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
 	sync
 	isync
 	mtspr	SPRN_HID0,r3
-	xori	r3,r3,HID0_DCI
+	xori	r3,r3,(HID0_DCI|HID0_ICFI)
 	mtspr	SPRN_HID0,r3
 	sync
 
 	/* Get the current enable bit of the L2CR into r4 */
-	mfspr	r5,L2CR
+	mfspr	r5,SPRN_L2CR
 	/* Set to data-only (pre-745x bit) */
 	oris	r3,r5,L2CR_L2DO@h
 	b	2f
 	/* When disabling L2, code must be in L1 */
 	.balign 32
-1:	mtspr	L2CR,r3
+1:	mtspr	SPRN_L2CR,r3
 3:	sync
 	isync
 	b	1f
@@ -107,17 +122,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	lis	r4,2
 	mtctr	r4
 	lis	r4,0xfff0
-1:	lwzx	r0,r0,r4
+1:	lwz	r0,0(r4)
 	addi	r4,r4,32
 	bdnz	1b
 	sync
 	isync
+	lis	r4,2
+	mtctr	r4
+	lis	r4,0xfff0
+1:	dcbf	0,r4
+	addi	r4,r4,32
+	bdnz	1b
+	sync
+	isync
+
 	/* now disable L2 */
 	rlwinm	r5,r5,0,~L2CR_L2E
 	b	2f
 	/* When disabling L2, code must be in L1 */
 	.balign 32
-1:	mtspr	L2CR,r5
+1:	mtspr	SPRN_L2CR,r5
 3:	sync
 	isync
 	b	1f
@@ -129,24 +153,33 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	isync
 	/* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
 	oris	r4,r5,L2CR_L2I@h
-	mtspr	L2CR,r4
+	mtspr	SPRN_L2CR,r4
 	sync
 	isync
+
+	/* Wait for the invalidation to complete */
+1:	mfspr	r3,SPRN_L2CR
+	rlwinm.	r0,r3,0,31,31
+	bne	1b
+
+	/* Clear L2I */
 	xoris	r4,r4,L2CR_L2I@h
 	sync
-	mtspr	L2CR,r4
+	mtspr	SPRN_L2CR,r4
 	sync
 
 	/* now disable the L1 data cache */
-	mfspr	r0,HID0
-	rlwinm	r0,r0,0,~HID0_DCE
-	mtspr	HID0,r0
+	mfspr	r0,SPRN_HID0
+	rlwinm	r0,r0,0,~(HID0_DCE|HID0_ICE)
+	mtspr	SPRN_HID0,r0
 	sync
 	isync
 
 	/* Restore HID0[DPM] to whatever it was before */
 	sync
-	mtspr	SPRN_HID0,r8
+	mfspr	r0,SPRN_HID0
+	rlwimi	r0,r8,0,11,11		/* Turn back HID0[DPM] */
+	mtspr	SPRN_HID0,r0
 	sync
 
 	/* restore DR and EE */
@@ -198,7 +231,7 @@ flush_disable_745x:
         mtctr   r4
  	li      r4,0
 1:
-        lwzx    r0,r0,r4
+        lwz     r0,0(r4)
         addi    r4,r4,32                /* Go to start of next cache line */
         bdnz    1b
         isync
@@ -239,14 +272,14 @@ flush_disable_745x:
 	isync
 
 	/* Flush the L2 cache using the hardware assist */
-	mfspr	r3,L2CR
+	mfspr	r3,SPRN_L2CR
 	cmpwi	r3,0		/* check if it is enabled first */
 	bge	4f
 	oris	r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
 	b	2f
 	/* When disabling/locking L2, code must be in L1 */
 	.balign 32
-1:	mtspr	L2CR,r0		/* lock the L2 cache */
+1:	mtspr	SPRN_L2CR,r0	/* lock the L2 cache */
 3:	sync
 	isync
 	b	1f
@@ -258,8 +291,8 @@ flush_disable_745x:
 	isync
 	ori	r0,r3,L2CR_L2HWF_745x
 	sync
-	mtspr	L2CR,r0		/* set the hardware flush bit */
-3:	mfspr	r0,L2CR		/* wait for it to go to 0 */
+	mtspr	SPRN_L2CR,r0	/* set the hardware flush bit */
+3:	mfspr	r0,SPRN_L2CR	/* wait for it to go to 0 */
 	andi.	r0,r0,L2CR_L2HWF_745x
 	bne	3b
 	sync
@@ -267,7 +300,7 @@ flush_disable_745x:
 	b	2f
 	/* When disabling L2, code must be in L1 */
 	.balign 32
-1:	mtspr	L2CR,r3		/* disable the L2 cache */
+1:	mtspr	SPRN_L2CR,r3	/* disable the L2 cache */
 3:	sync
 	isync
 	b	1f
@@ -278,34 +311,34 @@ flush_disable_745x:
 1:	sync
 	isync
 	oris	r4,r3,L2CR_L2I@h
-	mtspr	L2CR,r4
+	mtspr	SPRN_L2CR,r4
 	sync
 	isync
-1:	mfspr	r4,L2CR
+1:	mfspr	r4,SPRN_L2CR
 	andis.	r0,r4,L2CR_L2I@h
 	bne	1b
 	sync
 
 BEGIN_FTR_SECTION
 	/* Flush the L3 cache using the hardware assist */
-4:	mfspr	r3,L3CR
+4:	mfspr	r3,SPRN_L3CR
 	cmpwi	r3,0		/* check if it is enabled */
 	bge	6f
 	oris	r0,r3,L3CR_L3IO@h
 	ori	r0,r0,L3CR_L3DO
 	sync
-	mtspr	L3CR,r0		/* lock the L3 cache */
+	mtspr	SPRN_L3CR,r0	/* lock the L3 cache */
 	sync
 	isync
 	ori	r0,r0,L3CR_L3HWF
 	sync
-	mtspr	L3CR,r0		/* set the hardware flush bit */
-5:	mfspr	r0,L3CR		/* wait for it to go to zero */
+	mtspr	SPRN_L3CR,r0	/* set the hardware flush bit */
+5:	mfspr	r0,SPRN_L3CR	/* wait for it to go to zero */
 	andi.	r0,r0,L3CR_L3HWF
 	bne	5b
 	rlwinm	r3,r3,0,~L3CR_L3E
 	sync
-	mtspr	L3CR,r3		/* disable the L3 cache */
+	mtspr	SPRN_L3CR,r3	/* disable the L3 cache */
 	sync
 	ori	r4,r3,L3CR_L3I
 	mtspr	SPRN_L3CR,r4
@@ -315,11 +348,12 @@ BEGIN_FTR_SECTION
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
 
-6:	mfspr	r0,HID0		/* now disable the L1 data cache */
+6:	mfspr	r0,SPRN_HID0	/* now disable the L1 data cache */
 	rlwinm	r0,r0,0,~HID0_DCE
-	mtspr	HID0,r0
+	mtspr	SPRN_HID0,r0
 	sync
 	isync
 	mtmsr	r11		/* restore DR and EE */
 	isync
 	blr
+#endif	/* CONFIG_6xx */
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
--- a/arch/ppc/platforms/pmac_cpufreq.c
+++ b/arch/ppc/platforms/pmac_cpufreq.c
@@ -1,13 +1,18 @@
 /*
  *  arch/ppc/platforms/pmac_cpufreq.c
  *
- *  Copyright (C) 2002 - 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
  *  Copyright (C) 2004        John Steele Scott <toojays@toojays.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.
  *
+ * TODO: Need a big cleanup here. Basically, we need to have different
+ * cpufreq_driver structures for the different type of HW instead of the
+ * current mess. We also need to better deal with the detection of the
+ * type of machine.
+ *
  */
 
 #include <linux/config.h>
@@ -35,6 +40,7 @@
 #include <asm/time.h>
 #include <asm/system.h>
 #include <asm/open_pic.h>
+#include <asm/keylargo.h>
 
 /* WARNING !!! This will cause calibrate_delay() to be called,
  * but this is an __init function ! So you MUST go edit
@@ -61,11 +67,13 @@ extern void low_sleep_handler(void);
 static unsigned int low_freq;
 static unsigned int hi_freq;
 static unsigned int cur_freq;
+static unsigned int sleep_freq;
 
 /*
  * Different models uses different mecanisms to switch the frequency
  */
 static int (*set_speed_proc)(int low_speed);
+static unsigned int (*get_speed_proc)(void);
 
 /*
  * Some definitions used by the various speedprocs
@@ -73,16 +81,15 @@ static int (*set_speed_proc)(int low_spe
 static u32 voltage_gpio;
 static u32 frequency_gpio;
 static u32 slew_done_gpio;
-
-
-#define PMAC_CPU_LOW_SPEED	1
-#define PMAC_CPU_HIGH_SPEED	0
+static int no_schedule;
+static int has_cpu_l2lve;
+static int is_pmu_based;
 
 /* There are only two frequency states for each processor. Values
  * are in kHz for the time being.
  */
-#define CPUFREQ_HIGH                  PMAC_CPU_HIGH_SPEED
-#define CPUFREQ_LOW                   PMAC_CPU_LOW_SPEED
+#define CPUFREQ_HIGH                  0
+#define CPUFREQ_LOW                   1
 
 static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
 	{CPUFREQ_HIGH, 		0},
@@ -90,6 +97,19 @@ static struct cpufreq_frequency_table pm
 	{0,			CPUFREQ_TABLE_END},
 };
 
+static struct freq_attr* pmac_cpu_freqs_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static inline void local_delay(unsigned long ms)
+{
+	if (no_schedule)
+		mdelay(ms);
+	else
+		msleep(ms);
+}
+
 static inline void wakeup_decrementer(void)
 {
 	set_dec(tb_ticks_per_jiffy);
@@ -118,20 +138,48 @@ static inline void debug_calc_bogomips(v
  */
 static int __pmac cpu_750fx_cpu_speed(int low_speed)
 {
-#ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
-#endif
+	u32 hid2;
+
+	if (low_speed == 0) {
+		/* ramping up, set voltage first */
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+		/* Make sure we sleep for at least 1ms */
+		local_delay(10);
+
+		/* tweak L2 for high voltage */
+		if (has_cpu_l2lve) {
+			hid2 = mfspr(SPRN_HID2);
+			hid2 &= ~0x2000;
+			mtspr(SPRN_HID2, hid2);
+		}
+	}
 #ifdef CONFIG_6xx
 	low_choose_750fx_pll(low_speed);
 #endif
-#ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
-	debug_calc_bogomips();
-#endif
+	if (low_speed == 1) {
+		/* tweak L2 for low voltage */
+		if (has_cpu_l2lve) {
+			hid2 = mfspr(SPRN_HID2);
+			hid2 |= 0x2000;
+			mtspr(SPRN_HID2, hid2);
+		}
+
+		/* ramping down, set voltage last */
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+		local_delay(10);
+	}
 
 	return 0;
 }
 
+static unsigned int __pmac cpu_750fx_get_cpu_speed(void)
+{
+	if (mfspr(SPRN_HID1) & HID1_PS)
+		return low_freq;
+	else
+		return hi_freq;
+}
+
 /* Switch CPU speed using DFS */
 static int __pmac dfs_set_cpu_speed(int low_speed)
 {
@@ -139,24 +187,27 @@ static int __pmac dfs_set_cpu_speed(int 
 		/* ramping up, set voltage first */
 		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
 		/* Make sure we sleep for at least 1ms */
-		msleep(1);
+		local_delay(1);
 	}
 
 	/* set frequency */
+#ifdef CONFIG_6xx
 	low_choose_7447a_dfs(low_speed);
+#endif
+	udelay(100);
 
 	if (low_speed == 1) {
 		/* ramping down, set voltage last */
 		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-		msleep(1);
+		local_delay(1);
 	}
 
 	return 0;
 }
 
-static unsigned int __pmac dfs_get_cpu_speed(unsigned int cpu)
+static unsigned int __pmac dfs_get_cpu_speed(void)
 {
-	if (mfspr(HID1) & HID1_DFS)
+	if (mfspr(SPRN_HID1) & HID1_DFS)
 		return low_freq;
 	else
 		return hi_freq;
@@ -167,30 +218,35 @@ static unsigned int __pmac dfs_get_cpu_s
  */
 static int __pmac gpios_set_cpu_speed(int low_speed)
 {
-	int gpio;
+	int gpio, timeout = 0;
 
 	/* If ramping up, set voltage first */
 	if (low_speed == 0) {
 		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
 		/* Delay is way too big but it's ok, we schedule */
-		msleep(10);
+		local_delay(10);
 	}
 
 	/* Set frequency */
+	gpio = 	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+	if (low_speed == ((gpio & 0x01) == 0))
+		goto skip;
+
 	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,
 			  low_speed ? 0x04 : 0x05);
 	udelay(200);
 	do {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
+		if (++timeout > 100)
+			break;
+		local_delay(1);
 		gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
 	} while((gpio & 0x02) == 0);
-
+ skip:
 	/* If ramping down, set voltage last */
 	if (low_speed == 1) {
 		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
 		/* Delay is way too big but it's ok, we schedule */
-		msleep(10);
+		local_delay(10);
 	}
 
 #ifdef DEBUG_FREQ
@@ -207,14 +263,19 @@ static int __pmac pmu_set_cpu_speed(int 
 	struct adb_request req;
 	unsigned long save_l2cr;
 	unsigned long save_l3cr;
+	unsigned int pic_prio;
+	unsigned long flags;
 
 	preempt_disable();
 
 #ifdef DEBUG_FREQ
 	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
 #endif
+	pmu_suspend();
+
 	/* Disable all interrupt sources on openpic */
- 	openpic_set_priority(0xf);
+ 	pic_prio = openpic_get_priority();
+	openpic_set_priority(0xf);
 
 	/* Make sure the decrementer won't interrupt us */
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
@@ -224,13 +285,13 @@ static int __pmac pmu_set_cpu_speed(int 
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 
 	/* We can now disable MSR_EE */
-	local_irq_disable();
+	local_irq_save(flags);
 
 	/* Giveup the FPU & vec */
 	enable_kernel_fp();
 
 #ifdef CONFIG_ALTIVEC
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		enable_kernel_altivec();
 #endif /* CONFIG_ALTIVEC */
 
@@ -277,39 +338,64 @@ static int __pmac pmu_set_cpu_speed(int 
 	wakeup_decrementer();
 
 	/* Restore interrupts */
- 	openpic_set_priority(0);
+ 	openpic_set_priority(pic_prio);
 
 	/* Let interrupts flow again ... */
-	local_irq_enable();
+	local_irq_restore(flags);
 
 #ifdef DEBUG_FREQ
 	debug_calc_bogomips();
 #endif
 
+	pmu_resume();
+
 	preempt_enable();
 
 	return 0;
 }
 
-static int __pmac do_set_cpu_speed(int speed_mode)
+static int __pmac do_set_cpu_speed(int speed_mode, int notify)
 {
 	struct cpufreq_freqs freqs;
+	unsigned long l3cr;
+	static unsigned long prev_l3cr;
 
 	freqs.old = cur_freq;
-	freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
+	freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
 	freqs.cpu = smp_processor_id();
 
 	if (freqs.old == freqs.new)
 		return 0;
 
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-	cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	if (speed_mode == CPUFREQ_LOW &&
+	    cpu_has_feature(CPU_FTR_L3CR)) {
+		l3cr = _get_L3CR();
+		if (l3cr & L3CR_L3E) {
+			prev_l3cr = l3cr;
+			_set_L3CR(0);
+		}
+	}
+	set_speed_proc(speed_mode == CPUFREQ_LOW);
+	if (speed_mode == CPUFREQ_HIGH &&
+	    cpu_has_feature(CPU_FTR_L3CR)) {
+		l3cr = _get_L3CR();
+		if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
+			_set_L3CR(prev_l3cr);
+	}
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
 
 	return 0;
 }
 
+static unsigned int __pmac pmac_cpufreq_get_speed(unsigned int cpu)
+{
+	return cur_freq;
+}
+
 static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy)
 {
 	return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
@@ -325,7 +411,7 @@ static int __pmac pmac_cpufreq_target(	s
 			target_freq, relation, &newstate))
 		return -EINVAL;
 
-	return do_set_cpu_speed(newstate);
+	return do_set_cpu_speed(newstate, 1);
 }
 
 unsigned int __pmac pmac_get_one_cpufreq(int i)
@@ -343,25 +429,73 @@ static int __pmac pmac_cpufreq_cpu_init(
 	policy->cpuinfo.transition_latency	= CPUFREQ_ETERNAL;
 	policy->cur = cur_freq;
 
-	return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]);
+	cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
+	return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
 }
 
 static u32 __pmac read_gpio(struct device_node *np)
 {
 	u32 *reg = (u32 *)get_property(np, "reg", NULL);
+	u32 offset;
 
 	if (reg == NULL)
 		return 0;
 	/* That works for all keylargos but shall be fixed properly
-	 * some day...
+	 * some day... The problem is that it seems we can't rely
+	 * on the "reg" property of the GPIO nodes, they are either
+	 * relative to the base of KeyLargo or to the base of the
+	 * GPIO space, and the device-tree doesn't help.
+	 */
+	offset = *reg;
+	if (offset < KEYLARGO_GPIO_LEVELS0)
+		offset += KEYLARGO_GPIO_LEVELS0;
+	return offset;
+}
+
+static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state)
+{
+	/* Ok, this could be made a bit smarter, but let's be robust for now. We
+	 * always force a speed change to high speed before sleep, to make sure
+	 * we have appropriate voltage and/or bus speed for the wakeup process,
+	 * and to make sure our loops_per_jiffies are "good enough", that is will
+	 * not cause too short delays if we sleep in low speed and wake in high
+	 * speed..
 	 */
-	return 0x50 + (*reg);
+	no_schedule = 1;
+	sleep_freq = cur_freq;
+	if (cur_freq == low_freq && !is_pmu_based)
+		do_set_cpu_speed(CPUFREQ_HIGH, 0);
+	return 0;
+}
+
+static int __pmac pmac_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	/* If we resume, first check if we have a get() function */
+	if (get_speed_proc)
+		cur_freq = get_speed_proc();
+	else
+		cur_freq = 0;
+
+	/* We don't, hrm... we don't really know our speed here, best
+	 * is that we force a switch to whatever it was, which is
+	 * probably high speed due to our suspend() routine
+	 */
+	do_set_cpu_speed(sleep_freq == low_freq ?
+			 CPUFREQ_LOW : CPUFREQ_HIGH, 0);
+
+	no_schedule = 0;
+	return 0;
 }
 
 static struct cpufreq_driver pmac_cpufreq_driver = {
 	.verify 	= pmac_cpufreq_verify,
 	.target 	= pmac_cpufreq_target,
+	.get		= pmac_cpufreq_get_speed,
 	.init		= pmac_cpufreq_cpu_init,
+	.suspend	= pmac_cpufreq_suspend,
+	.resume		= pmac_cpufreq_resume,
+	.flags		= CPUFREQ_PM_NO_WARN,
+	.attr		= pmac_cpu_freqs_attr,
 	.name		= "powermac",
 	.owner		= THIS_MODULE,
 };
@@ -454,6 +588,7 @@ static int __pmac pmac_cpufreq_init_MacR
 		return 1;
 	hi_freq = (*value) / 1000;
 	set_speed_proc = pmu_set_cpu_speed;
+	is_pmu_based = 1;
 
 	return 0;
 }
@@ -461,24 +596,54 @@ static int __pmac pmac_cpufreq_init_MacR
 static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode)
 {
 	struct device_node *volt_gpio_np;
-	u32 *reg;
-	struct cpufreq_driver *driver = &pmac_cpufreq_driver;
 
-	/* OF only reports the high frequency */
-	hi_freq = cur_freq;
-	low_freq = cur_freq/2;
-	driver->get = dfs_get_cpu_speed;
-	cur_freq = driver->get(0);
+	if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+		return 1;
 
 	volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-	if (!volt_gpio_np){
+	if (volt_gpio_np)
+		voltage_gpio = read_gpio(volt_gpio_np);
+	if (!voltage_gpio){
 		printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
 		return 1;
 	}
 
-	reg = (u32 *)get_property(volt_gpio_np, "reg", NULL);
-	voltage_gpio = *reg;
+	/* OF only reports the high frequency */
+	hi_freq = cur_freq;
+	low_freq = cur_freq/2;
+
+	/* Read actual frequency from CPU */
+	cur_freq = dfs_get_cpu_speed();
 	set_speed_proc = dfs_set_cpu_speed;
+	get_speed_proc = dfs_get_cpu_speed;
+
+	return 0;
+}
+
+static int __pmac pmac_cpufreq_init_750FX(struct device_node *cpunode)
+{
+	struct device_node *volt_gpio_np;
+	u32 pvr, *value;
+
+	if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+		return 1;
+
+	hi_freq = cur_freq;
+	value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
+	if (!value)
+		return 1;
+	low_freq = (*value) / 1000;
+
+	volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
+	if (volt_gpio_np)
+		voltage_gpio = read_gpio(volt_gpio_np);
+
+	pvr = mfspr(SPRN_PVR);
+	has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
+
+	set_speed_proc = cpu_750fx_cpu_speed;
+	get_speed_proc = cpu_750fx_get_cpu_speed;
+	cur_freq = cpu_750fx_get_cpu_speed();
 
 	return 0;
 }
@@ -492,7 +657,7 @@ static int __pmac pmac_cpufreq_init_7447
  *  - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz)
  *  - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
  *  - Recent MacRISC3 laptops
- *  - iBook G4s and PowerBook G4s with 7447A CPUs
+ *  - All new machines with 7447A CPUs
  */
 static int __init pmac_cpufreq_setup(void)
 {
@@ -513,11 +678,10 @@ static int __init pmac_cpufreq_setup(voi
 		goto out;
 	cur_freq = (*value) / 1000;
 
-	/*  Check for 7447A based iBook G4 or PowerBook */
-	if (machine_is_compatible("PowerBook6,5") ||
-	    machine_is_compatible("PowerBook6,4") ||
-	    machine_is_compatible("PowerBook5,5") ||
-	    machine_is_compatible("PowerBook5,4")) {
+	/*  Check for 7447A based MacRISC3 */
+	if (machine_is_compatible("MacRISC3") &&
+	    get_property(cpunode, "dynamic-power-step", NULL) &&
+	    PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
 		pmac_cpufreq_init_7447A(cpunode);
 	/* Check for other MacRISC3 machines */
 	} else if (machine_is_compatible("PowerBook3,4") ||
@@ -529,6 +693,7 @@ static int __init pmac_cpufreq_setup(voi
 		hi_freq = cur_freq;
 		low_freq = 400000;
 		set_speed_proc = pmu_set_cpu_speed;
+		is_pmu_based = 1;
 	}
 	/* Else check for TiPb 400 & 500 */
 	else if (machine_is_compatible("PowerBook3,2")) {
@@ -540,18 +705,11 @@ static int __init pmac_cpufreq_setup(voi
 		hi_freq = cur_freq;
 		low_freq = 300000;
 		set_speed_proc = pmu_set_cpu_speed;
+		is_pmu_based = 1;
 	}
 	/* Else check for 750FX */
-	else if (PVR_VER(mfspr(PVR)) == 0x7000) {
-		if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
-			goto out;
-		hi_freq = cur_freq;
-		value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
-		if (!value)
-			goto out;
-		low_freq = (*value) / 1000;		
-		set_speed_proc = cpu_750fx_cpu_speed;
-	}
+	else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
+		pmac_cpufreq_init_750FX(cpunode);
 out:
 	if (set_speed_proc == NULL)
 		return -ENODEV;
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
--- a/arch/ppc/platforms/pmac_feature.c
+++ b/arch/ppc/platforms/pmac_feature.c
@@ -74,8 +74,7 @@ static DEFINE_SPINLOCK(feature_lock  __p
  */
 struct macio_chip macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
 
-struct macio_chip* __pmac
-macio_find(struct device_node* child, int type)
+struct macio_chip* __pmac macio_find(struct device_node* child, int type)
 {
 	while(child) {
 		int	i;
@@ -88,6 +87,7 @@ macio_find(struct device_node* child, in
 	}
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(macio_find);
 
 static const char* macio_names[] __pmacdata =
 {
@@ -1590,6 +1590,114 @@ intrepid_shutdown(struct macio_chip* mac
 	mdelay(10);
 }
 
+
+void __pmac pmac_tweak_clock_spreading(int enable)
+{
+	struct macio_chip* macio = &macio_chips[0];
+
+	/* Hack for doing clock spreading on some machines PowerBooks and
+	 * iBooks. This implements the "platform-do-clockspreading" OF
+	 * property as decoded manually on various models. For safety, we also
+	 * check the product ID in the device-tree in cases we'll whack the i2c
+	 * chip to make reasonably sure we won't set wrong values in there
+	 *
+	 * Of course, ultimately, we have to implement a real parser for
+	 * the platform-do-* stuff...
+	 */
+
+	if (macio->type == macio_intrepid) {
+		if (enable)
+			UN_OUT(UNI_N_CLOCK_SPREADING, 2);
+		else
+			UN_OUT(UNI_N_CLOCK_SPREADING, 0);
+		mdelay(40);
+	}
+
+	while (machine_is_compatible("PowerBook5,2") ||
+	       machine_is_compatible("PowerBook5,3") ||
+	       machine_is_compatible("PowerBook6,2") ||
+	       machine_is_compatible("PowerBook6,3")) {
+		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
+		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
+		u8 buffer[9];
+		u32 *productID;
+		int i, rc, changed = 0;
+
+		if (dt == NULL)
+			break;
+		productID = (u32 *)get_property(dt, "pid#", NULL);
+		if (productID == NULL)
+			break;
+		while(ui2c) {
+			struct device_node *p = of_get_parent(ui2c);
+			if (p && !strcmp(p->name, "uni-n"))
+				break;
+			ui2c = of_find_node_by_type(ui2c, "i2c");
+		}
+		if (ui2c == NULL)
+			break;
+		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
+		rc = pmac_low_i2c_open(ui2c, 1);
+		if (rc != 0)
+			break;
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+		DBG("read result: %d,", rc);
+		if (rc != 0) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		for (i=0; i<9; i++)
+			DBG(" %02x", buffer[i]);
+		DBG("\n");
+
+		switch(*productID) {
+		case 0x1182:	/* AlBook 12" rev 2 */
+		case 0x1183:	/* iBook G4 12" */
+			buffer[0] = (buffer[0] & 0x8f) | 0x70;
+			buffer[2] = (buffer[2] & 0x7f) | 0x00;
+			buffer[5] = (buffer[5] & 0x80) | 0x31;
+			buffer[6] = (buffer[6] & 0x40) | 0xb0;
+			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
+			buffer[8] = (buffer[8] & 0x00) | 0x30;
+			changed = 1;
+			break;
+		case 0x3142:	/* AlBook 15" (ATI M10) */
+		case 0x3143:	/* AlBook 17" (ATI M10) */
+			buffer[0] = (buffer[0] & 0xaf) | 0x50;
+			buffer[2] = (buffer[2] & 0x7f) | 0x00;
+			buffer[5] = (buffer[5] & 0x80) | 0x31;
+			buffer[6] = (buffer[6] & 0x40) | 0xb0;
+			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
+			buffer[8] = (buffer[8] & 0x00) | 0x30;
+			changed = 1;
+			break;
+		default:
+			DBG("i2c-hwclock: Machine model not handled\n");
+			break;
+		}
+		if (!changed) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
+		DBG("write result: %d,", rc);
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+		DBG("read result: %d,", rc);
+		if (rc != 0) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		for (i=0; i<9; i++)
+			DBG(" %02x", buffer[i]);
+		pmac_low_i2c_close(ui2c);
+		break;
+	}
+}
+
+
 static int __pmac
 core99_sleep(void)
 {
@@ -1601,12 +1709,6 @@ core99_sleep(void)
 	    macio->type != macio_intrepid)
 		return -ENODEV;
 
-	/* The device-tree contains that in the hwclock node */
-	if (macio->type == macio_intrepid) {
-		UN_OUT(UNI_N_CLOCK_SPREADING, 0);
-		mdelay(40);
-	}
-
 	/* We power off the wireless slot in case it was not done
 	 * by the driver. We don't power it on automatically however
 	 */
@@ -1749,12 +1851,6 @@ core99_wake_up(void)
 	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
 	udelay(100);
 
-	/* Restore clock spreading */
-	if (macio->type == macio_intrepid) {
-		UN_OUT(UNI_N_CLOCK_SPREADING, 2);
-		mdelay(40);
-	}
-
 	return 0;
 }
 
@@ -1779,32 +1875,6 @@ core99_sleep_state(struct device_node* n
 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
 		return -EPERM;
 
-#ifdef CONFIG_CPU_FREQ_PMAC
-	/* XXX should be elsewhere */
-	if (machine_is_compatible("PowerBook6,5") ||
-	    machine_is_compatible("PowerBook6,4") ||
-	    machine_is_compatible("PowerBook5,5") ||
-	    machine_is_compatible("PowerBook5,4")) {
-		struct device_node *volt_gpio_np;
-		u32 *reg = NULL;
-
-		volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-		if (volt_gpio_np != NULL)
-			reg = (u32 *)get_property(volt_gpio_np, "reg", NULL);
-		if (reg != NULL) {
-			/* Set the CPU voltage high if sleeping */
-			if (value == 1) {
-				pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
-						  *reg, 0x05);
-			} else if (value == 0 && (mfspr(HID1) & HID1_DFS)) {
-				pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
-						  *reg, 0x04);
-			}
-			mdelay(2);
-		}
-	}
-#endif /* CONFIG_CPU_FREQ_PMAC */
-
 	if (value == 1)
 		return core99_sleep();
 	else if (value == 0)
@@ -2022,10 +2092,11 @@ static struct feature_table_entry g5_fea
 #endif /* CONFIG_POWER4 */
 
 static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
-	/* Warning: ordering is important as some models may claim
-	 * beeing compatible with several types
-	 */
 #ifndef CONFIG_POWER4
+	/*
+	 * Desktops
+	 */
+
 	{	"AAPL,8500",			"PowerMac 8500/8600",
 		PMAC_TYPE_PSURGE,		NULL,
 		0
@@ -2058,14 +2129,6 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_GAZELLE,		NULL,
 		0
 	},
-	{	"AAPL,3400/2400",		"PowerBook 3400",
-		PMAC_TYPE_HOOPER,		ohare_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-	},
-	{	"AAPL,3500",			"PowerBook 3500",
-		PMAC_TYPE_KANGA,		ohare_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-	},
 	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
 		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
 		0
@@ -2074,42 +2137,6 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_SILK,			heathrow_desktop_features,
 		0
 	},
-	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
-		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-	},
-	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
-		PMAC_TYPE_101_PBOOK,		paddington_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE
-	},
-	{	"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_MAY_SLEEP
-	},
-	{	"PowerBook4,3",			"iBook 2 rev. 2",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-	},
-	{	"PowerBook4,2",			"iBook 2",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-	},
-	{	"PowerBook4,1",			"iBook 2",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-	},
-	{	"PowerMac4,4",			"eMac",
-		PMAC_TYPE_EMAC,			core99_features,
-		PMAC_MB_MAY_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
@@ -2118,9 +2145,13 @@ static struct pmac_mb_def pmac_mb_defs[]
 		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 | PMAC_MB_MOBILE
+	{	"PowerMac2,1",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac2,2",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
 	},
 	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
 		PMAC_TYPE_SAWTOOTH,		core99_features,
@@ -2134,30 +2165,96 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_SAWTOOTH,		core99_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
 	},
-	{	"PowerMac2,1",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+	{	"PowerMac3,4",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		PMAC_MB_MAY_SLEEP
 	},
-	{	"PowerMac2,2",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+	{	"PowerMac3,5",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		PMAC_MB_MAY_SLEEP
 	},
-	{	"PowerBook2,2",			"iBook FireWire",
-		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
-		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+	{	"PowerMac3,6",			"PowerMac G4 Windtunnel",
+		PMAC_TYPE_WINDTUNNEL,		core99_features,
+		PMAC_MB_MAY_SLEEP,
+	},
+	{	"PowerMac4,1",			"iMac \"Flower Power\"",
+		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
+		PMAC_MB_MAY_SLEEP
+	},
+	{	"PowerMac4,2",			"Flat panel iMac",
+		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac4,4",			"eMac",
+		PMAC_TYPE_EMAC,			core99_features,
+		PMAC_MB_MAY_SLEEP
 	},
 	{	"PowerMac5,1",			"PowerMac G4 Cube",
 		PMAC_TYPE_CUBE,			core99_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
 	},
-	{	"PowerMac3,4",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		PMAC_MB_MAY_SLEEP
+	{	"PowerMac6,1",			"Flat panel iMac",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP,
 	},
-	{	"PowerMac3,5",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		PMAC_MB_MAY_SLEEP
+	{	"PowerMac6,3",			"Flat panel iMac",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP,
+	},
+	{	"PowerMac6,4",			"eMac",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP,
+	},
+	{	"PowerMac10,1",			"Mac mini",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
+	},
+	{	"iMac,1",			"iMac (first generation)",
+		PMAC_TYPE_ORIG_IMAC,		paddington_features,
+		0
+	},
+
+	/*
+	 * Xserve's
+	 */
+
+	{	"RackMac1,1",			"XServe",
+		PMAC_TYPE_RACKMAC,		rackmac_features,
+		0,
+	},
+	{	"RackMac1,2",			"XServe rev. 2",
+		PMAC_TYPE_RACKMAC,		rackmac_features,
+		0,
+	},
+
+	/*
+	 * Laptops
+	 */
+
+	{	"AAPL,3400/2400",		"PowerBook 3400",
+		PMAC_TYPE_HOOPER,		ohare_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+	},
+	{	"AAPL,3500",			"PowerBook 3500",
+		PMAC_TYPE_KANGA,		ohare_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+	},
+	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
+		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+	},
+	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
+		PMAC_TYPE_101_PBOOK,		paddington_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+	},
+	{	"PowerBook2,1",			"iBook (first generation)",
+		PMAC_TYPE_ORIG_IBOOK,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+	},
+	{	"PowerBook2,2",			"iBook FireWire",
+		PMAC_TYPE_FW_IBOOK,		core99_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
+		PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,1",			"PowerBook Pismo",
 		PMAC_TYPE_PISMO,		core99_features,
@@ -2180,17 +2277,17 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_TITANIUM4,		core99_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
-	{	"RackMac1,1",			"XServe",
-		PMAC_TYPE_RACKMAC,		rackmac_features,
-		0,
+	{	"PowerBook4,1",			"iBook 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
-	{	"RackMac1,2",			"XServe rev. 2",
-		PMAC_TYPE_RACKMAC,		rackmac_features,
-		0,
+	{	"PowerBook4,2",			"iBook 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
-	{	"PowerMac3,6",			"PowerMac G4 Windtunnel",
-		PMAC_TYPE_WINDTUNNEL,		core99_features,
-		PMAC_MB_MAY_SLEEP,
+	{	"PowerBook4,3",			"iBook 2 rev. 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook5,1",			"PowerBook G4 17\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
@@ -2212,6 +2309,14 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
 	},
+	{	"PowerBook5,6",			"PowerBook G4 15\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
+	{	"PowerBook5,7",			"PowerBook G4 17\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
 	{	"PowerBook6,1",			"PowerBook G4 12\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
@@ -2232,6 +2337,10 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
 	},
+	{	"PowerBook6,8",			"PowerBook G4 12\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
 #else /* CONFIG_POWER4 */
 	{	"PowerMac7,2",			"PowerMac G5",
 		PMAC_TYPE_POWERMAC_G5,		g5_features,
@@ -2705,97 +2814,11 @@ set_initial_features(void)
 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
 	}
 
-	/* Hack for bumping clock speed on the new PowerBooks and the
-	 * iBook G4. This implements the "platform-do-clockspreading" OF
-	 * property. For safety, we also check the product ID in the
-	 * device-tree to make reasonably sure we won't set wrong values
-	 * in the clock chip.
-	 *
-	 * Of course, ultimately, we have to implement a real parser for
-	 * the platform-do-* stuff...
+	/* Some machine models need the clock chip to be properly setup for
+	 * clock spreading now. This should be a platform function but we
+	 * don't do these at the moment
 	 */
-	while (machine_is_compatible("PowerBook5,2") ||
-	       machine_is_compatible("PowerBook5,3") ||
-	       machine_is_compatible("PowerBook6,2") ||
-	       machine_is_compatible("PowerBook6,3")) {
-		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
-		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
-		u8 buffer[9];
-		u32 *productID;
-		int i, rc, changed = 0;
-		
-		if (dt == NULL)
-			break;
-		productID = (u32 *)get_property(dt, "pid#", NULL);
-		if (productID == NULL)
-			break;
-		while(ui2c) {
-			struct device_node *p = of_get_parent(ui2c);
-			if (p && !strcmp(p->name, "uni-n"))
-				break;
-			ui2c = of_find_node_by_type(ui2c, "i2c");
-		}
-		if (ui2c == NULL)
-			break;
-		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
-		rc = pmac_low_i2c_open(ui2c, 1);
-		if (rc != 0)
-			break;
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-		DBG("read result: %d,", rc);
-		if (rc != 0) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		for (i=0; i<9; i++)
-			DBG(" %02x", buffer[i]);
-		DBG("\n");
-		
-		switch(*productID) {
-		case 0x1182:	/* AlBook 12" rev 2 */
-		case 0x1183:	/* iBook G4 12" */
-			buffer[0] = (buffer[0] & 0x8f) | 0x70;
-			buffer[2] = (buffer[2] & 0x7f) | 0x00;
-			buffer[5] = (buffer[5] & 0x80) | 0x31;
-			buffer[6] = (buffer[6] & 0x40) | 0xb0;
-			buffer[7] = (buffer[7] & 0x00) | 0xc0;
-			buffer[8] = (buffer[8] & 0x00) | 0x30;
-			changed = 1;
-			break;
-		case 0x3142:	/* AlBook 15" (ATI M10) */
-		case 0x3143:	/* AlBook 17" (ATI M10) */
-			buffer[0] = (buffer[0] & 0xaf) | 0x50;
-			buffer[2] = (buffer[2] & 0x7f) | 0x00;
-			buffer[5] = (buffer[5] & 0x80) | 0x31;
-			buffer[6] = (buffer[6] & 0x40) | 0xb0;
-			buffer[7] = (buffer[7] & 0x00) | 0xd0;
-			buffer[8] = (buffer[8] & 0x00) | 0x30;
-			changed = 1;
-			break;
-		default:
-			DBG("i2c-hwclock: Machine model not handled\n");
-			break;
-		}
-		if (!changed) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
-		DBG("write result: %d,", rc);
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-		DBG("read result: %d,", rc);
-		if (rc != 0) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		for (i=0; i<9; i++)
-			DBG(" %02x", buffer[i]);
-		pmac_low_i2c_close(ui2c);
-		break;
-	}
+	pmac_tweak_clock_spreading(1);
 
 #endif /* CONFIG_POWER4 */
 
@@ -2931,3 +2954,48 @@ void __pmac pmac_call_early_video_resume
 	if (pmac_early_vresume_proc)
 		pmac_early_vresume_proc(pmac_early_vresume_data);
 }
+
+/*
+ * AGP related suspend/resume code
+ */
+
+static struct pci_dev *pmac_agp_bridge __pmacdata;
+static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata;
+static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata;
+
+void __pmac pmac_register_agp_pm(struct pci_dev *bridge,
+				 int (*suspend)(struct pci_dev *bridge),
+				 int (*resume)(struct pci_dev *bridge))
+{
+	if (suspend || resume) {
+		pmac_agp_bridge = bridge;
+		pmac_agp_suspend = suspend;
+		pmac_agp_resume = resume;
+		return;
+	}
+	if (bridge != pmac_agp_bridge)
+		return;
+	pmac_agp_suspend = pmac_agp_resume = NULL;
+	return;
+}
+EXPORT_SYMBOL(pmac_register_agp_pm);
+
+void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev)
+{
+	if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
+		return;
+	if (pmac_agp_bridge->bus != dev->bus)
+		return;
+	pmac_agp_suspend(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_suspend_agp_for_card);
+
+void __pmac pmac_resume_agp_for_card(struct pci_dev *dev)
+{
+	if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
+		return;
+	if (pmac_agp_bridge->bus != dev->bus)
+		return;
+	pmac_agp_resume(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/ppc/platforms/pmac_low_i2c.c b/arch/ppc/platforms/pmac_low_i2c.c
--- a/arch/ppc/platforms/pmac_low_i2c.c
+++ b/arch/ppc/platforms/pmac_low_i2c.c
@@ -54,7 +54,7 @@ struct low_i2c_host
 	int			mode;		/* Current mode */
 	int			channel;	/* Current channel */
 	int			num_channels;	/* Number of channels */
-	unsigned long		base;		/* For keywest-i2c, base address */
+	void __iomem *		base;		/* For keywest-i2c, base address */
 	int			bsteps;		/* And register stepping */
 	int			speed;		/* And speed */
 };
@@ -154,14 +154,12 @@ static const char *__kw_state_names[] = 
 
 static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
 {
-	return in_8(((volatile u8 *)host->base)
-		+ (((unsigned)reg) << host->bsteps));
+	return in_8(host->base + (((unsigned)reg) << host->bsteps));
 }
 
 static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
 {
-	out_8(((volatile u8 *)host->base)
-		+ (((unsigned)reg) << host->bsteps), val);
+	out_8(host->base + (((unsigned)reg) << host->bsteps), val);
 	(void)__kw_read_reg(host, reg_subaddr);
 }
 
@@ -370,7 +368,7 @@ static void keywest_low_i2c_add(struct d
 		break;
 	}	
 	host->mode = pmac_low_i2c_mode_std;
-	host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset,
+	host->base = ioremap(np->addrs[0].address + aoffset,
 						np->addrs[0].size);
 	host->func = keywest_low_i2c_func;
 }
diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c
+++ b/arch/ppc/platforms/pmac_setup.c
@@ -52,6 +52,7 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/bitops.h>
+#include <linux/suspend.h>
 
 #include <asm/reg.h>
 #include <asm/sections.h>
@@ -70,6 +71,8 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
 #include "pmac_pic.h"
 #include "mem_pieces.h"
 
@@ -247,7 +250,7 @@ pmac_setup_arch(void)
 	int *fp;
 	unsigned long pvr;
 
-	pvr = PVR_VER(mfspr(PVR));
+	pvr = PVR_VER(mfspr(SPRN_PVR));
 
 	/* Set loops_per_jiffy to a half-way reasonable value,
 	   for use until calibrate_delay gets called. */
@@ -274,7 +277,7 @@ pmac_setup_arch(void)
 	pmac_find_bridges();
 
 	/* Checks "l2cr-value" property in the registry */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
+	if (cpu_has_feature(CPU_FTR_L2CR)) {
 		struct device_node *np = find_devices("cpus");
 		if (np == 0)
 			np = find_type_devices("cpu");
@@ -421,10 +424,62 @@ find_boot_device(void)
 }
 
 static int initializing = 1;
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+
+static int pmac_pm_prepare(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	return 0;
+}
+
+static int pmac_pm_enter(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Giveup the lazy FPU & vec so we don't have to back them
+	 * up from the low level code
+	 */
+	enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+		enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+	return 0;
+}
+
+static int pmac_pm_finish(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Restore userland MMU context */
+	set_context(current->active_mm->context, current->active_mm->pgd);
+
+	return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+	.pm_disk_mode	= PM_DISK_SHUTDOWN,
+	.prepare	= pmac_pm_prepare,
+	.enter		= pmac_pm_enter,
+	.finish		= pmac_pm_finish,
+};
+
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 
 static int pmac_late_init(void)
 {
 	initializing = 0;
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 	return 0;
 }
 
@@ -614,6 +669,7 @@ pmac_init(unsigned long r3, unsigned lon
 	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.phys_mem_access_prot = pci_phys_mem_access_prot;
 
 	ppc_md.restart        = pmac_restart;
 	ppc_md.power_off      = pmac_power_off;
diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S
--- a/arch/ppc/platforms/pmac_sleep.S
+++ b/arch/ppc/platforms/pmac_sleep.S
@@ -182,12 +182,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
 /*
  * Set the HID0 and MSR for sleep.
  */
-	mfspr	r2,HID0
+	mfspr	r2,SPRN_HID0
 	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
 	oris	r2,r2,HID0_SLEEP@h
 	sync
 	isync
-	mtspr	HID0,r2
+	mtspr	SPRN_HID0,r2
 	sync
 
 /* This loop puts us back to sleep in case we have a spurrious
@@ -216,10 +216,10 @@ _GLOBAL(core99_wake_up)
 	/* Make sure HID0 no longer contains any sleep bit and that data cache
 	 * is disabled
 	 */
-	mfspr	r3,HID0
+	mfspr	r3,SPRN_HID0
 	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
 	rlwinm	3,r3,0,18,15		/* clear DCE, ICE */
-	mtspr	HID0,r3
+	mtspr	SPRN_HID0,r3
 	sync
 	isync
 
@@ -267,6 +267,10 @@ grackle_wake_up:
 	/* Restore various CPU config stuffs */
 	bl	__restore_cpu_setup
 
+	/* Make sure all FPRs have been initialized */
+	bl	reloc_offset
+	bl	__init_fpu_registers
+
 	/* Invalidate & enable L1 cache, we don't care about
 	 * whatever the ROM may have tried to write to memory
 	 */
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
--- a/arch/ppc/platforms/pmac_smp.c
+++ b/arch/ppc/platforms/pmac_smp.c
@@ -91,11 +91,11 @@ extern void __secondary_start_psurge3(vo
 #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;
+static volatile u8 __iomem *hhead_base;
+static volatile u8 __iomem *quad_base;
+static volatile u32 __iomem *psurge_pri_intr;
+static volatile u8 __iomem *psurge_sec_intr;
+static volatile u32 __iomem *psurge_start;
 
 /* values for psurge_type */
 #define PSURGE_NONE		-1
@@ -116,10 +116,12 @@ static unsigned int core99_tb_gpio;
 
 /* Sync flag for HW tb sync */
 static volatile int sec_tb_reset = 0;
+static unsigned int pri_tb_hi, pri_tb_lo;
+static unsigned int pri_tb_stamp;
 
 static void __init core99_init_caches(int cpu)
 {
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+	if (!cpu_has_feature(CPU_FTR_L2CR))
 		return;
 
 	if (cpu == 0) {
@@ -132,7 +134,7 @@ static void __init core99_init_caches(in
 		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
 	}
 
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+	if (!cpu_has_feature(CPU_FTR_L3CR))
 		return;
 
 	if (cpu == 0){
@@ -294,7 +296,7 @@ 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)
+	if (PVR_VER(mfspr(SPRN_PVR)) == 1)
 		return 1;
 
 	/*
@@ -320,10 +322,10 @@ static int __init smp_psurge_probe(void)
 		/* All released cards using this HW design have 4 CPUs */
 		ncpus = 4;
 	} else {
-		iounmap((void *) quad_base);
+		iounmap(quad_base);
 		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
 			/* not a dual-cpu card */
-			iounmap((void *) hhead_base);
+			iounmap(hhead_base);
 			psurge_type = PSURGE_NONE;
 			return 1;
 		}
@@ -453,7 +455,7 @@ static int __init smp_core99_probe(void)
 #endif
 	struct device_node *cpus, *firstcpu;
 	int i, ncpus = 0, boot_cpu = -1;
-	u32 *tbprop;
+	u32 *tbprop = NULL;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
 	cpus = firstcpu = find_type_devices("cpu");
@@ -576,46 +578,74 @@ static void __init smp_core99_setup_cpu(
 	}
 }
 
-void __init smp_core99_take_timebase(void)
+/* not __init, called in sleep/wakeup code */
+void smp_core99_take_timebase(void)
 {
-	/* Secondary processor "takes" the timebase by freezing
-	 * it, resetting its local TB and telling CPU 0 to go on
-	 */
-	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
-	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+	unsigned long flags;
+
+	/* tell the primary we're here */
+	sec_tb_reset = 1;
 	mb();
 
-	set_dec(tb_ticks_per_jiffy);
-	set_tb(0, 0);
-	last_jiffy_stamp(smp_processor_id()) = 0;
+	/* wait for the primary to set pri_tb_hi/lo */
+	while (sec_tb_reset < 2)
+		mb();
 
+	/* set our stuff the same as the primary */
+	local_irq_save(flags);
+	set_dec(1);
+	set_tb(pri_tb_hi, pri_tb_lo);
+	last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
+	mb();
+
+	/* tell the primary we're done */
+       	sec_tb_reset = 0;
 	mb();
-       	sec_tb_reset = 1;
+	local_irq_restore(flags);
 }
 
-void __init smp_core99_give_timebase(void)
+/* not __init, called in sleep/wakeup code */
+void smp_core99_give_timebase(void)
 {
+	unsigned long flags;
 	unsigned int t;
 
-	/* Primary processor waits for secondary to have frozen
-	 * the timebase, resets local TB, and kick timebase again
-	 */
-	/* wait for the secondary to have reset its TB before proceeding */
-	for (t = 1000; t > 0 && !sec_tb_reset; --t)
-		udelay(1000);
-	if (t == 0)
+	/* wait for the secondary to be in take_timebase */
+	for (t = 100000; t > 0 && !sec_tb_reset; --t)
+		udelay(10);
+	if (!sec_tb_reset) {
 		printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
+		return;
+	}
 
-       	set_dec(tb_ticks_per_jiffy);
-	set_tb(0, 0);
-	last_jiffy_stamp(smp_processor_id()) = 0;
+	/* freeze the timebase and read it */
+	/* disable interrupts so the timebase is disabled for the
+	   shortest possible time */
+	local_irq_save(flags);
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+	mb();
+	pri_tb_hi = get_tbu();
+	pri_tb_lo = get_tbl();
+	pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
 	mb();
 
+	/* tell the secondary we're ready */
+	sec_tb_reset = 2;
+	mb();
+
+	/* wait for the secondary to have taken it */
+	for (t = 100000; t > 0 && sec_tb_reset; --t)
+		udelay(10);
+	if (sec_tb_reset)
+		printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
+	else
+		smp_tb_synchronized = 1;
+
 	/* Now, restart the timebase by leaving the GPIO to an open collector */
        	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
         pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-
-	smp_tb_synchronized = 1;
+	local_irq_restore(flags);
 }
 
 
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
--- a/arch/ppc/platforms/pmac_time.c
+++ b/arch/ppc/platforms/pmac_time.c
@@ -165,7 +165,7 @@ int __init
 via_calibrate_decr(void)
 {
 	struct device_node *vias;
-	volatile unsigned char *via;
+	volatile unsigned char __iomem *via;
 	int count = VIA_TIMER_FREQ_6 / 100;
 	unsigned int dstart, dend;
 
@@ -176,8 +176,7 @@ via_calibrate_decr(void)
 		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);
+	via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
 
 	/* set timer 1 for continuous interrupts */
 	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
@@ -202,7 +201,7 @@ via_calibrate_decr(void)
 	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
 	       tb_ticks_per_jiffy, dstart - dend);
 
-	iounmap((void*)via);
+	iounmap(via);
 	
 	return 1;
 }
diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c
--- a/arch/ppc/platforms/pplus.c
+++ b/arch/ppc/platforms/pplus.c
@@ -849,10 +849,10 @@ static __inline__ void pplus_set_bat(voi
 	mb();
 
 	/* setup DBATs */
-	mtspr(DBAT2U, 0x80001ffe);
-	mtspr(DBAT2L, 0x8000002a);
-	mtspr(DBAT3U, 0xf0001ffe);
-	mtspr(DBAT3L, 0xf000002a);
+	mtspr(SPRN_DBAT2U, 0x80001ffe);
+	mtspr(SPRN_DBAT2L, 0x8000002a);
+	mtspr(SPRN_DBAT3U, 0xf0001ffe);
+	mtspr(SPRN_DBAT3L, 0xf000002a);
 
 	/* wait for updates */
 	mb();
diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h
--- a/arch/ppc/platforms/pq2ads.h
+++ b/arch/ppc/platforms/pq2ads.h
@@ -49,10 +49,10 @@
 /* PCI interrupt controller */
 #define PCI_INT_STAT_REG	0xF8200000
 #define PCI_INT_MASK_REG	0xF8200004
-#define PIRQA			(NR_SIU_INTS + 0)
-#define PIRQB			(NR_SIU_INTS + 1)
-#define PIRQC			(NR_SIU_INTS + 2)
-#define PIRQD			(NR_SIU_INTS + 3)
+#define PIRQA			(NR_CPM_INTS + 0)
+#define PIRQB			(NR_CPM_INTS + 1)
+#define PIRQC			(NR_CPM_INTS + 2)
+#define PIRQD			(NR_CPM_INTS + 3)
 
 /*
  * PCI memory map definitions for MPC8266ADS-PCI.
@@ -68,28 +68,23 @@
  *	0x00000000-0x1FFFFFFF	0x00000000-0x1FFFFFFF	MPC8266 local memory
  */
 
-/* window for a PCI master to access MPC8266 memory */
-#define PCI_SLV_MEM_LOCAL	0x00000000	/* Local base */
-#define PCI_SLV_MEM_BUS		0x00000000	/* PCI base */
-
-/* window for the processor to access PCI memory with prefetching */
-#define PCI_MSTR_MEM_LOCAL	0x80000000	/* Local base */
-#define PCI_MSTR_MEM_BUS	0x80000000	/* PCI base   */
-#define PCI_MSTR_MEM_SIZE	0x20000000	/* 512MB */
-
-/* window for the processor to access PCI memory without prefetching */
-#define PCI_MSTR_MEMIO_LOCAL	0xA0000000	/* Local base */
-#define PCI_MSTR_MEMIO_BUS	0xA0000000	/* PCI base   */
-#define PCI_MSTR_MEMIO_SIZE	0x20000000	/* 512MB */
-
-/* window for the processor to access PCI I/O */
-#define PCI_MSTR_IO_LOCAL	0xF4000000	/* Local base */
-#define PCI_MSTR_IO_BUS         0x00000000	/* PCI base   */
-#define PCI_MSTR_IO_SIZE        0x04000000	/* 64MB */
-
-#define _IO_BASE		PCI_MSTR_IO_LOCAL
-#define _ISA_MEM_BASE		PCI_MSTR_MEMIO_LOCAL
-#define PCI_DRAM_OFFSET		PCI_SLV_MEM_BUS
+/* All the other PCI memory map definitions reside at syslib/m82xx_pci.h
+   Here we should redefine what is unique for this board */
+#define M82xx_PCI_SLAVE_MEM_LOCAL	0x00000000	/* Local base */
+#define M82xx_PCI_SLAVE_MEM_BUS		0x00000000	/* PCI base */
+#define M82xx_PCI_SLAVE_MEM_SIZE	0x10000000	/* 256 Mb */
+
+#define M82xx_PCI_SLAVE_SEC_WND_SIZE	~(0x40000000 - 1U)	/* 2 x 512Mb  */
+#define M82xx_PCI_SLAVE_SEC_WND_BASE	0x80000000		/* PCI Memory base */
+
+#if defined(CONFIG_ADS8272)
+#define PCI_INT_TO_SIU 	SIU_INT_IRQ2
+#elif defined(CONFIG_PQ2FADS)
+#define PCI_INT_TO_SIU 	SIU_INT_IRQ6
+#else
+#warning PCI Bridge will be without interrupts support
+#endif
+
 #endif /* CONFIG_PCI */
 
 #endif /* __MACH_ADS8260_DEFS */
diff --git a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c
+++ b/arch/ppc/platforms/prep_pci.c
@@ -1245,8 +1245,13 @@ prep_pcibios_fixup(void)
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 	}
 
-	/* Setup the Winbond or Via PIB */
-	prep_pib_init();
+	/* Setup the Winbond or Via PIB - prep_pib_init() is coded for
+	 * the non-openpic case, but it breaks (at least) the Utah
+	 * (Powerstack II Pro4000), so only call it if we have an
+	 * openpic.
+	 */
+	if (have_openpic)
+		prep_pib_init();
 }
 
 static void __init
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -690,8 +690,8 @@ prep_set_bat(void)
 	mb();
 
 	/* setup DBATs */
-	mtspr(DBAT2U, 0x80001ffe);
-	mtspr(DBAT2L, 0x8000002a);
+	mtspr(SPRN_DBAT2U, 0x80001ffe);
+	mtspr(SPRN_DBAT2L, 0x8000002a);
 
 	/* wait for updates */
 	mb();
@@ -1144,6 +1144,8 @@ prep_init(unsigned long r3, unsigned lon
 	/* this gets changed later on if we have an OpenPIC -- Cort */
 	ppc_md.get_irq        = i8259_irq;
 
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 	ppc_md.restart        = prep_restart;
 	ppc_md.power_off      = NULL; /* set in prep_setup_arch() */
 	ppc_md.halt           = prep_halt;
diff --git a/arch/ppc/platforms/prpmc750.c b/arch/ppc/platforms/prpmc750.c
--- a/arch/ppc/platforms/prpmc750.c
+++ b/arch/ppc/platforms/prpmc750.c
@@ -302,8 +302,8 @@ static void __init prpmc750_init_IRQ(voi
 static __inline__ void prpmc750_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xf0001ffe);
-	mtspr(DBAT1L, 0xf000002a);
+	mtspr(SPRN_DBAT1U, 0xf0001ffe);
+	mtspr(SPRN_DBAT1L, 0xf000002a);
 	mb();
 }
 
diff --git a/arch/ppc/platforms/prpmc800.c b/arch/ppc/platforms/prpmc800.c
--- a/arch/ppc/platforms/prpmc800.c
+++ b/arch/ppc/platforms/prpmc800.c
@@ -419,8 +419,8 @@ static void __init prpmc800_init_IRQ(voi
 static __inline__ void prpmc800_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xf0001ffe);
-	mtspr(DBAT1L, 0xf000002a);
+	mtspr(SPRN_DBAT1U, 0xf0001ffe);
+	mtspr(SPRN_DBAT1L, 0xf000002a);
 	mb();
 }
 
diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/radstone_ppc7d.c
@@ -0,0 +1,1500 @@
+/*
+ * arch/ppc/platforms/radstone_ppc7d.c
+ *
+ * Board setup routines for the Radstone PPC7D boards.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@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.
+ */
+
+/* Radstone PPC7D boards are rugged VME boards with PPC 7447A CPUs,
+ * Discovery-II, dual gigabit ethernet, dual PMC, USB, keyboard/mouse,
+ * 4 serial ports, 2 high speed serial ports (MPSCs) and optional
+ * SCSI / VGA.
+ */
+
+#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/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>		/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/mv643xx.h>
+#include <linux/netdevice.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/vga.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/pci-bridge.h>
+#include <asm/mv64x60.h>
+#include <asm/i8259.h>
+
+#include "radstone_ppc7d.h"
+
+#undef DEBUG
+
+#define PPC7D_RST_PIN			17 	/* GPP17 */
+
+extern u32 mv64360_irq_base;
+extern spinlock_t rtc_lock;
+
+static struct mv64x60_handle bh;
+static int ppc7d_has_alma;
+
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+
+/* FIXME - move to h file */
+extern int ds1337_do_command(int id, int cmd, void *arg);
+#define DS1337_GET_DATE         0
+#define DS1337_SET_DATE         1
+
+/* residual data */
+unsigned char __res[sizeof(bd_t)];
+
+/*****************************************************************************
+ * Serial port code
+ *****************************************************************************/
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+static void __init ppc7d_early_serial_map(void)
+{
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#elif defined(CONFIG_SERIAL_8250)
+	struct uart_port serial_req;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.uartclk = UART_CLK;
+	serial_req.irq = 4;
+	serial_req.flags = STD_COM_FLAGS;
+	serial_req.iotype = SERIAL_IO_MEM;
+	serial_req.membase = (u_char *) PPC7D_SERIAL_0;
+
+	gen550_init(0, &serial_req);
+	if (early_serial_setup(&serial_req) != 0)
+		printk(KERN_ERR "Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.irq = 3;
+	serial_req.membase = (u_char *) PPC7D_SERIAL_1;
+
+	gen550_init(1, &serial_req);
+	if (early_serial_setup(&serial_req) != 0)
+		printk(KERN_ERR "Early serial init of port 1 failed\n");
+#else
+#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX
+#endif
+}
+#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */
+
+/*****************************************************************************
+ * Low-level board support code
+ *****************************************************************************/
+
+static unsigned long __init ppc7d_find_end_of_memory(void)
+{
+	bd_t *bp = (bd_t *) __res;
+
+	if (bp->bi_memsize)
+		return bp->bi_memsize;
+
+	return (256 * 1024 * 1024);
+}
+
+static void __init ppc7d_map_io(void)
+{
+	/* remove temporary mapping */
+	mtspr(SPRN_DBAT3U, 0x00000000);
+	mtspr(SPRN_DBAT3L, 0x00000000);
+
+	io_block_mapping(0xe8000000, 0xe8000000, 0x08000000, _PAGE_IO);
+	io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+}
+
+static void ppc7d_restart(char *cmd)
+{
+	u32 data;
+
+	/* Disable GPP17 interrupt */
+	data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
+	data &= ~(1 << PPC7D_RST_PIN);
+	mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data);
+
+	/* Configure MPP17 as GPP */
+	data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+	data &= ~(0x0000000f << 4);
+	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+
+	/* Enable pin GPP17 for output */
+	data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL);
+	data |= (1 << PPC7D_RST_PIN);
+	mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data);
+
+	/* Toggle GPP9 pin to reset the board */
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, 1 << PPC7D_RST_PIN);
+	mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, 1 << PPC7D_RST_PIN);
+
+	for (;;) ;		/* Spin until reset happens */
+	/* NOTREACHED */
+}
+
+static void ppc7d_power_off(void)
+{
+	u32 data;
+
+	local_irq_disable();
+
+	/* Ensure that internal MV643XX watchdog is disabled.
+	 * The Disco watchdog uses MPP17 on this hardware.
+	 */
+	data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+	data &= ~(0x0000000f << 4);
+	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+
+	data = mv64x60_read(&bh, MV64x60_WDT_WDC);
+	if (data & 0x80000000) {
+		mv64x60_write(&bh, MV64x60_WDT_WDC, 1 << 24);
+		mv64x60_write(&bh, MV64x60_WDT_WDC, 2 << 24);
+	}
+
+	for (;;) ;		/* No way to shut power off with software */
+	/* NOTREACHED */
+}
+
+static void ppc7d_halt(void)
+{
+	ppc7d_power_off();
+	/* NOTREACHED */
+}
+
+static unsigned long ppc7d_led_no_pulse;
+
+static int __init ppc7d_led_pulse_disable(char *str)
+{
+	ppc7d_led_no_pulse = 1;
+	return 1;
+}
+
+/* This kernel option disables the heartbeat pulsing of a board LED */
+__setup("ledoff", ppc7d_led_pulse_disable);
+
+static void ppc7d_heartbeat(void)
+{
+	u32 data32;
+	u8 data8;
+	static int max706_wdog = 0;
+
+	/* Unfortunately we can't access the LED control registers
+	 * during early init because they're on the CPLD which is the
+	 * other side of a PCI bridge which goes unreachable during
+	 * PCI scan. So write the LEDs only if the MV64360 watchdog is
+	 * enabled (i.e. userspace apps are running so kernel is up)..
+	 */
+	data32 = mv64x60_read(&bh, MV64x60_WDT_WDC);
+	if (data32 & 0x80000000) {
+		/* Enable MAX706 watchdog if not done already */
+		if (!max706_wdog) {
+			outb(3, PPC7D_CPLD_RESET);
+			max706_wdog = 1;
+		}
+
+		/* Hit the MAX706 watchdog */
+		outb(0, PPC7D_CPLD_WATCHDOG_TRIG);
+
+		/* Pulse LED DS219 if not disabled */
+		if (!ppc7d_led_no_pulse) {
+			static int led_on = 0;
+
+			data8 = inb(PPC7D_CPLD_LEDS);
+			if (led_on)
+				data8 &= ~PPC7D_CPLD_LEDS_DS219_MASK;
+			else
+				data8 |= PPC7D_CPLD_LEDS_DS219_MASK;
+
+			outb(data8, PPC7D_CPLD_LEDS);
+			led_on = !led_on;
+		}
+	}
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+
+static int ppc7d_show_cpuinfo(struct seq_file *m)
+{
+	u8 val;
+	u8 val1, val2;
+	static int flash_sizes[4] = { 64, 32, 0, 16 };
+	static int flash_banks[4] = { 4, 3, 2, 1 };
+	static int sdram_bank_sizes[4] = { 128, 256, 512, 1 };
+	int sdram_num_banks = 2;
+	static char *pci_modes[] = { "PCI33", "PCI66",
+		"Unknown", "Unknown",
+		"PCIX33", "PCIX66",
+		"PCIX100", "PCIX133"
+	};
+
+	seq_printf(m, "vendor\t\t: Radstone Technology\n");
+	seq_printf(m, "machine\t\t: PPC7D\n");
+
+	val = inb(PPC7D_CPLD_BOARD_REVISION);
+	val1 = (val & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5;
+	val2 = (val & PPC7D_CPLD_BOARD_REVISION_LETTER_MASK);
+	seq_printf(m, "revision\t: %hd%c%c\n",
+		   val1,
+		   (val2 <= 0x18) ? 'A' + val2 : 'Y',
+		   (val2 > 0x18) ? 'A' + (val2 - 0x19) : ' ');
+
+	val = inb(PPC7D_CPLD_MOTHERBOARD_TYPE);
+	val1 = val & PPC7D_CPLD_MB_TYPE_PLL_MASK;
+	val2 = val & (PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK |
+		      PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK);
+	seq_printf(m, "bus speed\t: %dMHz\n",
+		   (val1 == PPC7D_CPLD_MB_TYPE_PLL_133) ? 133 :
+		   (val1 == PPC7D_CPLD_MB_TYPE_PLL_100) ? 100 :
+		   (val1 == PPC7D_CPLD_MB_TYPE_PLL_64) ? 64 : 0);
+
+	val = inb(PPC7D_CPLD_MEM_CONFIG);
+	if (val & PPC7D_CPLD_SDRAM_BANK_NUM_MASK) sdram_num_banks--;
+
+	val = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND);
+	val1 = (val & PPC7D_CPLD_SDRAM_BANK_SIZE_MASK) >> 6;
+	seq_printf(m, "SDRAM\t\t: %d banks of %d%c, total %d%c",
+		   sdram_num_banks,
+		   sdram_bank_sizes[val1],
+		   (sdram_bank_sizes[val1] < 128) ? 'G' : 'M',
+		   sdram_num_banks * sdram_bank_sizes[val1],
+		   (sdram_bank_sizes[val1] < 128) ? 'G' : 'M');
+	if (val2 & PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK) {
+		seq_printf(m, " [ECC %sabled]",
+			   (val2 & PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK) ? "en" :
+			   "dis");
+	}
+	seq_printf(m, "\n");
+
+	val1 = (val & PPC7D_CPLD_FLASH_DEV_SIZE_MASK);
+	val2 = (val & PPC7D_CPLD_FLASH_BANK_NUM_MASK) >> 2;
+	seq_printf(m, "FLASH\t\t: %d banks of %dM, total %dM\n",
+		   flash_banks[val2], flash_sizes[val1],
+		   flash_banks[val2] * flash_sizes[val1]);
+
+	val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL);
+	val1 = inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+	seq_printf(m, "  write links\t: %s%s%s%s\n",
+		   (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "WRITE " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "BOOT " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "USER " : "",
+		   (val & (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK |
+			   PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK |
+			   PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK)) ==
+		   0 ? "NONE" : "");
+	seq_printf(m, "  write sector h/w enables: %s%s%s%s%s\n",
+		   (val & PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK) ? "RECOVERY " :
+		   "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK) ? "BOOT " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK) ? "USER " : "",
+		   (val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) ? "NVRAM " :
+		   "",
+		   (((val &
+		      (PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK |
+		       PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK |
+		       PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK)) == 0)
+		    && ((val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) ==
+			0)) ? "NONE" : "");
+	val1 =
+	    inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT) &
+	    (PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK |
+	     PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK);
+	seq_printf(m, "  software sector enables: %s%s%s\n",
+		   (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK) ? "SYSBOOT "
+		   : "",
+		   (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK) ? "USER " : "",
+		   (val1 == 0) ? "NONE " : "");
+
+	seq_printf(m, "Boot options\t: %s%s%s%s\n",
+		   (val & PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK) ?
+		   "ALTERNATE " : "",
+		   (val & PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK) ? "VME " :
+		   "",
+		   (val & PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK) ? "RECOVERY "
+		   : "",
+		   ((val &
+		     (PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK |
+		      PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK |
+		      PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK)) ==
+		    0) ? "NONE" : "");
+
+	val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_1);
+	seq_printf(m, "Fitted modules\t: %s%s%s%s\n",
+		   (val & PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK) ? "" : "PMC1 ",
+		   (val & PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK) ? "" : "PMC2 ",
+		   (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) ? "AFIX " : "",
+		   ((val & (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK |
+			    PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK |
+			    PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK)) ==
+		    (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK |
+		     PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK)) ? "NONE" : "");
+
+	if (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) {
+		static const char *ids[] = {
+			"unknown",
+			"1553 (Dual Channel)",
+			"1553 (Single Channel)",
+			"8-bit SCSI + VGA",
+			"16-bit SCSI + VGA",
+			"1553 (Single Channel with sideband)",
+			"1553 (Dual Channel with sideband)",
+			NULL
+		};
+		u8 id = __raw_readb((void *)PPC7D_AFIX_REG_BASE + 0x03);
+		seq_printf(m, "AFIX module\t: 0x%hx [%s]\n", id,
+			   id < 7 ? ids[id] : "unknown");
+	}
+
+	val = inb(PPC7D_CPLD_PCI_CONFIG);
+	val1 = (val & PPC7D_CPLD_PCI_CONFIG_PCI0_MASK) >> 4;
+	val2 = (val & PPC7D_CPLD_PCI_CONFIG_PCI1_MASK);
+	seq_printf(m, "PCI#0\t\t: %s\nPCI#1\t\t: %s\n",
+		   pci_modes[val1], pci_modes[val2]);
+
+	val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2);
+	seq_printf(m, "PMC1\t\t: %s\nPMC2\t\t: %s\n",
+		   (val & PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK) ? "3.3v" : "5v",
+		   (val & PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK) ? "3.3v" : "5v");
+	seq_printf(m, "PMC power source: %s\n",
+		   (val & PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK) ? "VME" :
+		   "internal");
+
+	val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_4);
+	val2 = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2);
+	seq_printf(m, "Fit options\t: %s%s%s%s%s%s%s\n",
+		   (val & PPC7D_CPLD_EQPT_PRES_4_LPT_MASK) ? "LPT " : "",
+		   (val & PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED) ? "PS2 " : "",
+		   (val & PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED) ? "USB2 " : "",
+		   (val2 & PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK) ? "VME " : "",
+		   (val2 & PPC7D_CPLD_EQPT_PRES_2_COM36_MASK) ? "COM3-6 " : "",
+		   (val2 & PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK) ? "eth0 " : "",
+		   (val2 & PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK) ? "eth1 " :
+		   "");
+
+	val = inb(PPC7D_CPLD_ID_LINK);
+	val1 = val & (PPC7D_CPLD_ID_LINK_E6_MASK |
+		      PPC7D_CPLD_ID_LINK_E7_MASK |
+		      PPC7D_CPLD_ID_LINK_E12_MASK |
+		      PPC7D_CPLD_ID_LINK_E13_MASK);
+
+	val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL) &
+	    (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK |
+	     PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK |
+	     PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK);
+
+	seq_printf(m, "Board links present: %s%s%s%s%s%s%s%s\n",
+		   (val1 & PPC7D_CPLD_ID_LINK_E6_MASK) ? "E6 " : "",
+		   (val1 & PPC7D_CPLD_ID_LINK_E7_MASK) ? "E7 " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "E9 " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "E10 " : "",
+		   (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "E11 " : "",
+		   (val1 & PPC7D_CPLD_ID_LINK_E12_MASK) ? "E12 " : "",
+		   (val1 & PPC7D_CPLD_ID_LINK_E13_MASK) ? "E13 " : "",
+		   ((val == 0) && (val1 == 0)) ? "NONE" : "");
+
+	val = inb(PPC7D_CPLD_WDOG_RESETSW_MASK);
+	seq_printf(m, "Front panel reset switch: %sabled\n",
+		   (val & PPC7D_CPLD_WDOG_RESETSW_MASK) ? "dis" : "en");
+
+	return 0;
+}
+
+static void __init ppc7d_calibrate_decr(void)
+{
+	ulong freq;
+
+	freq = 100000000 / 4;
+
+	pr_debug("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);
+}
+
+/*****************************************************************************
+ * Interrupt stuff
+ *****************************************************************************/
+
+static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
+	if (temp & (1 << 28)) {
+		i8259_irq(regs);
+		mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28)));
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+/*
+ * Each interrupt cause is assigned an IRQ number.
+ * Southbridge has 16*2 (two 8259's) interrupts.
+ * Discovery-II has 96 interrupts (cause-hi, cause-lo, gpp x 32).
+ * If multiple interrupts are pending, get_irq() returns the
+ * lowest pending irq number first.
+ *
+ *
+ * IRQ #   Source                              Trig   Active
+ * =============================================================
+ *
+ * Southbridge
+ * -----------
+ * IRQ #   Source                              Trig
+ * =============================================================
+ * 0       ISA High Resolution Counter         Edge
+ * 1       Keyboard                            Edge
+ * 2       Cascade From (IRQ 8-15)             Edge
+ * 3       Com 2 (Uart 2)                      Edge
+ * 4       Com 1 (Uart 1)                      Edge
+ * 5       PCI Int D/AFIX IRQZ ID4 (2,7)       Level
+ * 6       GPIO                                Level
+ * 7       LPT                                 Edge
+ * 8       RTC Alarm                           Edge
+ * 9       PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level
+ * 10      PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level
+ * 11      USB2                                Level
+ * 12      Mouse                               Edge
+ * 13      Reserved internally by Ali M1535+
+ * 14      PCI Int C/VME/AFIX IRQY ID3 (2,6)   Level
+ * 15      COM 5/6                             Level
+ *
+ * 16..112 Discovery-II...
+ *
+ * MPP28   Southbridge                         Edge   High
+ *
+ *
+ * Interrupts are cascaded through to the Discovery-II.
+ *
+ *  PCI ---
+ *         \
+ * CPLD --> ALI1535 -------> DISCOVERY-II
+ *        INTF           MPP28
+ */
+static void __init ppc7d_init_irq(void)
+{
+	int irq;
+
+	pr_debug("%s\n", __FUNCTION__);
+	i8259_init(0);
+	mv64360_init_irq();
+
+	/* IRQ 0..15 are handled by the cascaded 8259's of the Ali1535 */
+	for (irq = 0; irq < 16; irq++) {
+		irq_desc[irq].handler = &i8259_pic;
+	}
+	/* IRQs 5,6,9,10,11,14,15 are level sensitive */
+	irq_desc[5].status |= IRQ_LEVEL;
+	irq_desc[6].status |= IRQ_LEVEL;
+	irq_desc[9].status |= IRQ_LEVEL;
+	irq_desc[10].status |= IRQ_LEVEL;
+	irq_desc[11].status |= IRQ_LEVEL;
+	irq_desc[14].status |= IRQ_LEVEL;
+	irq_desc[15].status |= IRQ_LEVEL;
+
+	/* GPP28 is edge triggered */
+	irq_desc[mv64360_irq_base + MV64x60_IRQ_GPP28].status &= ~IRQ_LEVEL;
+}
+
+static u32 ppc7d_irq_canonicalize(u32 irq)
+{
+	if ((irq >= 16) && (irq < (16 + 96)))
+		irq -= 16;
+
+	return irq;
+}
+
+static int ppc7d_get_irq(struct pt_regs *regs)
+{
+	int irq;
+
+	irq = mv64360_get_irq(regs);
+	if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28))
+		irq = i8259_irq(regs);
+	return irq;
+}
+
+/*
+ * 9       PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level
+ * 10      PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level
+ * 14      PCI Int C/VME/AFIX IRQY ID3 (2,6)   Level
+ * 5       PCI Int D/AFIX IRQZ ID4 (2,7)       Level
+ */
+static int __init ppc7d_map_irq(struct pci_dev *dev, unsigned char idsel,
+				unsigned char pin)
+{
+	static const char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{10, 14, 5, 9},	/* IDSEL 10 - PMC2 / AFIX IRQW */
+		{9, 10, 14, 5},	/* IDSEL 11 - PMC1 / AFIX IRQX */
+		{5, 9, 10, 14},	/* IDSEL 12 - AFIX IRQY */
+		{14, 5, 9, 10},	/* IDSEL 13 - AFIX IRQZ */
+	};
+	const long min_idsel = 10, max_idsel = 14, irqs_per_slot = 4;
+
+	pr_debug("%s: %04x/%04x/%x: idsel=%hx pin=%hu\n", __FUNCTION__,
+		 dev->vendor, dev->device, PCI_FUNC(dev->devfn), idsel, pin);
+
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init ppc7d_intr_setup(void)
+{
+	u32 data;
+
+	/*
+	 * Define GPP 28 interrupt polarity as active high
+	 * input signal and level triggered
+	 */
+	data = mv64x60_read(&bh, MV64x60_GPP_LEVEL_CNTL);
+	data &= ~(1 << 28);
+	mv64x60_write(&bh, MV64x60_GPP_LEVEL_CNTL, data);
+	data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL);
+	data &= ~(1 << 28);
+	mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data);
+
+	/* Config GPP intr ctlr to respond to level trigger */
+	data = mv64x60_read(&bh, MV64x60_COMM_ARBITER_CNTL);
+	data |= (1 << 10);
+	mv64x60_write(&bh, MV64x60_COMM_ARBITER_CNTL, data);
+
+	/* XXXX Erranum FEr PCI-#8 */
+	data = mv64x60_read(&bh, MV64x60_PCI0_CMD);
+	data &= ~((1 << 5) | (1 << 9));
+	mv64x60_write(&bh, MV64x60_PCI0_CMD, data);
+	data = mv64x60_read(&bh, MV64x60_PCI1_CMD);
+	data &= ~((1 << 5) | (1 << 9));
+	mv64x60_write(&bh, MV64x60_PCI1_CMD, data);
+
+	/*
+	 * Dismiss and then enable interrupt on GPP interrupt cause
+	 * for CPU #0
+	 */
+	mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(1 << 28));
+	data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
+	data |= (1 << 28);
+	mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data);
+
+	/*
+	 * Dismiss and then enable interrupt on CPU #0 high cause reg
+	 * BIT27 summarizes GPP interrupts 23-31
+	 */
+	mv64x60_write(&bh, MV64360_IC_MAIN_CAUSE_HI, ~(1 << 27));
+	data = mv64x60_read(&bh, MV64360_IC_CPU0_INTR_MASK_HI);
+	data |= (1 << 27);
+	mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI, data);
+}
+
+/*****************************************************************************
+ * Platform device data fixup routines.
+ *****************************************************************************/
+
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init ppc7d_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+	struct mpsc_pdata *pdata;
+
+	pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+	pdata->max_idle = 40;
+	pdata->default_baud = PPC7D_DEFAULT_BAUD;
+	pdata->brg_clk_src = PPC7D_MPSC_CLK_SRC;
+	pdata->brg_clk_freq = PPC7D_MPSC_CLK_FREQ;
+
+	return;
+}
+#endif
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init ppc7d_fixup_eth_pdata(struct platform_device *pdev)
+{
+	struct mv643xx_eth_platform_data *eth_pd;
+	static u16 phy_addr[] = {
+		PPC7D_ETH0_PHY_ADDR,
+		PPC7D_ETH1_PHY_ADDR,
+		PPC7D_ETH2_PHY_ADDR,
+	};
+	int i;
+
+	eth_pd = pdev->dev.platform_data;
+	eth_pd->force_phy_addr = 1;
+	eth_pd->phy_addr = phy_addr[pdev->id];
+	eth_pd->tx_queue_size = PPC7D_ETH_TX_QUEUE_SIZE;
+	eth_pd->rx_queue_size = PPC7D_ETH_RX_QUEUE_SIZE;
+
+	/* Adjust IRQ by mv64360_irq_base */
+	for (i = 0; i < pdev->num_resources; i++) {
+		struct resource *r = &pdev->resource[i];
+
+		if (r->flags & IORESOURCE_IRQ) {
+			r->start += mv64360_irq_base;
+			r->end += mv64360_irq_base;
+			pr_debug("%s, uses IRQ %d\n", pdev->name,
+				 (int)r->start);
+		}
+	}
+
+}
+#endif
+
+#if defined(CONFIG_I2C_MV64XXX)
+static void __init
+ppc7d_fixup_i2c_pdata(struct platform_device *pdev)
+{
+	struct mv64xxx_i2c_pdata *pdata;
+	int i;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata == NULL) {
+		pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+		if (pdata == NULL)
+			return;
+
+		memset(pdata, 0, sizeof(*pdata));
+		pdev->dev.platform_data = pdata;
+	}
+
+	/* divisors M=8, N=3 for 100kHz I2C from 133MHz system clock */
+	pdata->freq_m = 8;
+	pdata->freq_n = 3;
+	pdata->timeout = 500;
+	pdata->retries = 3;
+
+	/* Adjust IRQ by mv64360_irq_base */
+	for (i = 0; i < pdev->num_resources; i++) {
+		struct resource *r = &pdev->resource[i];
+
+		if (r->flags & IORESOURCE_IRQ) {
+			r->start += mv64360_irq_base;
+			r->end += mv64360_irq_base;
+			pr_debug("%s, uses IRQ %d\n", pdev->name, (int) r->start);
+		}
+	}
+}
+#endif
+
+static int __init ppc7d_platform_notify(struct device *dev)
+{
+	static struct {
+		char *bus_id;
+		void ((*rtn) (struct platform_device * pdev));
+	} dev_map[] = {
+#if defined(CONFIG_SERIAL_MPSC)
+		{ MPSC_CTLR_NAME ".0", ppc7d_fixup_mpsc_pdata },
+		{ MPSC_CTLR_NAME ".1", ppc7d_fixup_mpsc_pdata },
+#endif
+#if defined(CONFIG_MV643XX_ETH)
+		{ MV643XX_ETH_NAME ".0", ppc7d_fixup_eth_pdata },
+		{ MV643XX_ETH_NAME ".1", ppc7d_fixup_eth_pdata },
+		{ MV643XX_ETH_NAME ".2", ppc7d_fixup_eth_pdata },
+#endif
+#if defined(CONFIG_I2C_MV64XXX)
+		{ MV64XXX_I2C_CTLR_NAME ".0", ppc7d_fixup_i2c_pdata },
+#endif
+	};
+	struct platform_device *pdev;
+	int i;
+
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++)
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+				     BUS_ID_SIZE)) {
+
+				pdev = container_of(dev,
+						    struct platform_device,
+						    dev);
+				dev_map[i].rtn(pdev);
+			}
+
+	return 0;
+}
+
+/*****************************************************************************
+ * PCI device fixups.
+ * These aren't really fixups per se. They are used to init devices as they
+ * are found during PCI scan.
+ *
+ * The PPC7D has an HB8 PCI-X bridge which must be set up during a PCI
+ * scan in order to find other devices on its secondary side.
+ *****************************************************************************/
+
+static void __init ppc7d_fixup_hb8(struct pci_dev *dev)
+{
+	u16 val16;
+
+	if (dev->bus->number == 0) {
+		pr_debug("PCI: HB8 init\n");
+
+		pci_write_config_byte(dev, 0x1c,
+				      ((PPC7D_PCI0_IO_START_PCI_ADDR & 0xf000)
+				       >> 8) | 0x01);
+		pci_write_config_byte(dev, 0x1d,
+				      (((PPC7D_PCI0_IO_START_PCI_ADDR +
+					 PPC7D_PCI0_IO_SIZE -
+					 1) & 0xf000) >> 8) | 0x01);
+		pci_write_config_word(dev, 0x30,
+				      PPC7D_PCI0_IO_START_PCI_ADDR >> 16);
+		pci_write_config_word(dev, 0x32,
+				      ((PPC7D_PCI0_IO_START_PCI_ADDR +
+					PPC7D_PCI0_IO_SIZE -
+					1) >> 16) & 0xffff);
+
+		pci_write_config_word(dev, 0x20,
+				      PPC7D_PCI0_MEM0_START_PCI_LO_ADDR >> 16);
+		pci_write_config_word(dev, 0x22,
+				      ((PPC7D_PCI0_MEM0_START_PCI_LO_ADDR +
+					PPC7D_PCI0_MEM0_SIZE -
+					1) >> 16) & 0xffff);
+		pci_write_config_word(dev, 0x24, 0);
+		pci_write_config_word(dev, 0x26, 0);
+		pci_write_config_dword(dev, 0x28, 0);
+		pci_write_config_dword(dev, 0x2c, 0);
+
+		pci_read_config_word(dev, 0x3e, &val16);
+		val16 |= ((1 << 5) | (1 << 1));	/* signal master aborts and
+						 * SERR to primary
+						 */
+		val16 &= ~(1 << 2);		/* ISA disable, so all ISA
+						 * ports forwarded to secondary
+						 */
+		pci_write_config_word(dev, 0x3e, val16);
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0028, ppc7d_fixup_hb8);
+
+/* This should perhaps be a separate driver as we're actually initializing
+ * the chip for this board here. It's hardly a fixup...
+ */
+static void __init ppc7d_fixup_ali1535(struct pci_dev *dev)
+{
+	pr_debug("PCI: ALI1535 init\n");
+
+	if (dev->bus->number == 1) {
+		/* Configure the ISA Port Settings */
+		pci_write_config_byte(dev, 0x43, 0x00);
+
+		/* Disable PCI Interrupt polling mode */
+		pci_write_config_byte(dev, 0x45, 0x00);
+
+		/* Multifunction pin select INTFJ -> INTF */
+		pci_write_config_byte(dev, 0x78, 0x00);
+
+		/* Set PCI INT -> IRQ Routing control in for external
+		 * pins south bridge.
+		 */
+		pci_write_config_byte(dev, 0x48, 0x31);	/* [7-4] INT B -> IRQ10
+							 * [3-0] INT A -> IRQ9
+							 */
+		pci_write_config_byte(dev, 0x49, 0x5D);	/* [7-4] INT D -> IRQ5
+							 * [3-0] INT C -> IRQ14
+							 */
+
+		/* PPC7D setup */
+		/* NEC USB device on IRQ 11 (INTE) - INTF disabled */
+		pci_write_config_byte(dev, 0x4A, 0x09);
+
+		/* GPIO on IRQ 6 */
+		pci_write_config_byte(dev, 0x76, 0x07);
+
+		/* SIRQ I (COMS 5/6) use IRQ line 15.
+		 * Positive (not subtractive) address decode.
+		 */
+		pci_write_config_byte(dev, 0x44, 0x0f);
+
+		/* SIRQ II disabled */
+		pci_write_config_byte(dev, 0x75, 0x0);
+
+		/* On board USB and RTC disabled */
+		pci_write_config_word(dev, 0x52, (1 << 14));
+		pci_write_config_byte(dev, 0x74, 0x00);
+
+		/* On board IDE disabled */
+		pci_write_config_byte(dev, 0x58, 0x00);
+
+		/* Decode 32-bit addresses */
+		pci_write_config_byte(dev, 0x5b, 0);
+
+		/* Disable docking IO */
+		pci_write_config_word(dev, 0x5c, 0x0000);
+
+		/* Disable modem, enable sound */
+		pci_write_config_byte(dev, 0x77, (1 << 6));
+
+		/* Disable hot-docking mode */
+		pci_write_config_byte(dev, 0x7d, 0x00);
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1533, ppc7d_fixup_ali1535);
+
+static int ppc7d_pci_exclude_device(u8 bus, u8 devfn)
+{
+	/* Early versions of this board were fitted with IBM ALMA
+	 * PCI-VME bridge chips. The PCI config space of these devices
+	 * was not set up correctly and causes PCI scan problems.
+	 */
+	if ((bus == 1) && (PCI_SLOT(devfn) == 4) && ppc7d_has_alma)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return mv64x60_pci_exclude_device(bus, devfn);
+}
+
+/* This hook is called when each PCI bus is probed.
+ */
+static void ppc7d_pci_fixup_bus(struct pci_bus *bus)
+{
+	pr_debug("PCI BUS %hu: %lx/%lx %lx/%lx %lx/%lx %lx/%lx\n",
+		 bus->number,
+		 bus->resource[0] ? bus->resource[0]->start : 0,
+		 bus->resource[0] ? bus->resource[0]->end : 0,
+		 bus->resource[1] ? bus->resource[1]->start : 0,
+		 bus->resource[1] ? bus->resource[1]->end : 0,
+		 bus->resource[2] ? bus->resource[2]->start : 0,
+		 bus->resource[2] ? bus->resource[2]->end : 0,
+		 bus->resource[3] ? bus->resource[3]->start : 0,
+		 bus->resource[3] ? bus->resource[3]->end : 0);
+
+	if ((bus->number == 1) && (bus->resource[2] != NULL)) {
+		/* Hide PCI window 2 of Bus 1 which is used only to
+		 * map legacy ISA memory space.
+		 */
+		bus->resource[2]->start = 0;
+		bus->resource[2]->end = 0;
+		bus->resource[2]->flags = 0;
+	}
+}
+
+/*****************************************************************************
+ * Board device setup code
+ *****************************************************************************/
+
+void __init ppc7d_setup_peripherals(void)
+{
+	u32 val32;
+
+	/* Set up windows for boot CS */
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+				 PPC7D_BOOT_WINDOW_BASE, PPC7D_BOOT_WINDOW_SIZE,
+				 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+	/* Boot firmware configures the following DevCS addresses.
+	 * DevCS0 - board control/status
+	 * DevCS1 - test registers
+	 * DevCS2 - AFIX port/address registers (for identifying)
+	 * DevCS3 - FLASH
+	 *
+	 * We don't use DevCS0, DevCS1.
+	 */
+	val32 = mv64x60_read(&bh, MV64360_CPU_BAR_ENABLE);
+	val32 |= ((1 << 4) | (1 << 5));
+	mv64x60_write(&bh, MV64360_CPU_BAR_ENABLE, val32);
+	mv64x60_write(&bh, MV64x60_CPU2DEV_0_BASE, 0);
+	mv64x60_write(&bh, MV64x60_CPU2DEV_0_SIZE, 0);
+	mv64x60_write(&bh, MV64x60_CPU2DEV_1_BASE, 0);
+	mv64x60_write(&bh, MV64x60_CPU2DEV_1_SIZE, 0);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
+				 PPC7D_AFIX_REG_BASE, PPC7D_AFIX_REG_SIZE, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
+				 PPC7D_FLASH_BASE, PPC7D_FLASH_SIZE_ACTUAL, 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+
+	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+				 PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE,
+				 0);
+	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+	/* Set up Enet->SRAM window */
+	mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
+				 PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE,
+				 0x2);
+	bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+
+	/* Give enet r/w access to memory region */
+	val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_0);
+	val32 |= (0x3 << (4 << 1));
+	mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_0, val32);
+	val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_1);
+	val32 |= (0x3 << (4 << 1));
+	mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_1, val32);
+	val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_2);
+	val32 |= (0x3 << (4 << 1));
+	mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_2, val32);
+
+	val32 = mv64x60_read(&bh, MV64x60_TIMR_CNTR_0_3_CNTL);
+	val32 &= ~((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24));
+	mv64x60_write(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, val32);
+
+	/* Enumerate pci bus.
+	 *
+	 * We scan PCI#0 first (the bus with the HB8 and other
+	 * on-board peripherals). We must configure the 64360 before
+	 * each scan, according to the bus number assignments.  Busses
+	 * are assigned incrementally, starting at 0.  PCI#0 is
+	 * usually assigned bus#0, the secondary side of the HB8 gets
+	 * bus#1 and PCI#1 (second PMC site) gets bus#2.  However, if
+	 * any PMC card has a PCI bridge, these bus assignments will
+	 * change.
+	 */
+
+	/* Turn off PCI retries */
+	val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+	val32 |= (1 << 17);
+	mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32);
+
+	/* Scan PCI#0 */
+	mv64x60_set_bus(&bh, 0, 0);
+	bh.hose_a->first_busno = 0;
+	bh.hose_a->last_busno = 0xff;
+	bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+	printk(KERN_INFO "PCI#0: first=%d last=%d\n",
+	       bh.hose_a->first_busno, bh.hose_a->last_busno);
+
+	/* Scan PCI#1 */
+	bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+	mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+	bh.hose_b->last_busno = 0xff;
+	bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+		bh.hose_b->first_busno);
+	printk(KERN_INFO "PCI#1: first=%d last=%d\n",
+	       bh.hose_b->first_busno, bh.hose_b->last_busno);
+
+	/* Turn on PCI retries */
+	val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+	val32 &= ~(1 << 17);
+	mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32);
+
+	/* Setup interrupts */
+	ppc7d_intr_setup();
+}
+
+static void __init ppc7d_setup_bridge(void)
+{
+	struct mv64x60_setup_info si;
+	int i;
+	u32 temp;
+
+	mv64360_irq_base = 16;	/* first 16 intrs are 2 x 8259's */
+
+	memset(&si, 0, sizeof(si));
+
+	si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+	si.pci_0.enable_bus = 1;
+	si.pci_0.pci_io.cpu_base = PPC7D_PCI0_IO_START_PROC_ADDR;
+	si.pci_0.pci_io.pci_base_hi = 0;
+	si.pci_0.pci_io.pci_base_lo = PPC7D_PCI0_IO_START_PCI_ADDR;
+	si.pci_0.pci_io.size = PPC7D_PCI0_IO_SIZE;
+	si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_0.pci_mem[0].cpu_base = PPC7D_PCI0_MEM0_START_PROC_ADDR;
+	si.pci_0.pci_mem[0].pci_base_hi = PPC7D_PCI0_MEM0_START_PCI_HI_ADDR;
+	si.pci_0.pci_mem[0].pci_base_lo = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR;
+	si.pci_0.pci_mem[0].size = PPC7D_PCI0_MEM0_SIZE;
+	si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_0.pci_mem[1].cpu_base = PPC7D_PCI0_MEM1_START_PROC_ADDR;
+	si.pci_0.pci_mem[1].pci_base_hi = PPC7D_PCI0_MEM1_START_PCI_HI_ADDR;
+	si.pci_0.pci_mem[1].pci_base_lo = PPC7D_PCI0_MEM1_START_PCI_LO_ADDR;
+	si.pci_0.pci_mem[1].size = PPC7D_PCI0_MEM1_SIZE;
+	si.pci_0.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_0.pci_cmd_bits = 0;
+	si.pci_0.latency_timer = 0x80;
+
+	si.pci_1.enable_bus = 1;
+	si.pci_1.pci_io.cpu_base = PPC7D_PCI1_IO_START_PROC_ADDR;
+	si.pci_1.pci_io.pci_base_hi = 0;
+	si.pci_1.pci_io.pci_base_lo = PPC7D_PCI1_IO_START_PCI_ADDR;
+	si.pci_1.pci_io.size = PPC7D_PCI1_IO_SIZE;
+	si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_mem[0].cpu_base = PPC7D_PCI1_MEM0_START_PROC_ADDR;
+	si.pci_1.pci_mem[0].pci_base_hi = PPC7D_PCI1_MEM0_START_PCI_HI_ADDR;
+	si.pci_1.pci_mem[0].pci_base_lo = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR;
+	si.pci_1.pci_mem[0].size = PPC7D_PCI1_MEM0_SIZE;
+	si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_mem[1].cpu_base = PPC7D_PCI1_MEM1_START_PROC_ADDR;
+	si.pci_1.pci_mem[1].pci_base_hi = PPC7D_PCI1_MEM1_START_PCI_HI_ADDR;
+	si.pci_1.pci_mem[1].pci_base_lo = PPC7D_PCI1_MEM1_START_PCI_LO_ADDR;
+	si.pci_1.pci_mem[1].size = PPC7D_PCI1_MEM1_SIZE;
+	si.pci_1.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE;
+	si.pci_1.pci_cmd_bits = 0;
+	si.pci_1.latency_timer = 0x80;
+
+	/* Don't clear the SRAM window since we use it for debug */
+	si.window_preserve_mask_32_lo = (1 << MV64x60_CPU2SRAM_WIN);
+
+	printk(KERN_INFO "PCI: MV64360 PCI#0 IO at %x, size %x\n",
+	       si.pci_0.pci_io.cpu_base, si.pci_0.pci_io.size);
+	printk(KERN_INFO "PCI: MV64360 PCI#1 IO at %x, size %x\n",
+	       si.pci_1.pci_io.cpu_base, si.pci_1.pci_io.size);
+
+	for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+		si.cpu_prot_options[i] = 0;
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+		si.pci_0.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+		si.cpu_prot_options[i] = 0;
+		/* All PPC7D hardware uses B0 or newer MV64360 silicon which
+		 * does not have snoop bugs.
+		 */
+		si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB;
+		si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB;
+		si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB;
+
+		si.pci_0.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+
+		si.pci_1.acc_cntl_options[i] =
+		    MV64360_PCI_ACC_CNTL_SNOOP_WB |
+		    MV64360_PCI_ACC_CNTL_SWAP_NONE |
+		    MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+		    MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+	}
+
+	/* Lookup PCI host bridges */
+	if (mv64x60_init(&bh, &si))
+		printk(KERN_ERR "MV64360 initialization failed.\n");
+
+	pr_debug("MV64360 regs @ %lx/%p\n", bh.p_base, bh.v_base);
+
+	/* Enable WB Cache coherency on SRAM */
+	temp = mv64x60_read(&bh, MV64360_SRAM_CONFIG);
+	pr_debug("SRAM_CONFIG: %x\n", temp);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+	mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp & ~0x2);
+#else
+	mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp | 0x2);
+#endif
+	/* If system operates with internal bus arbiter (CPU master
+	 * control bit8) clear AACK Delay bit [25] in CPU
+	 * configuration register.
+	 */
+	temp = mv64x60_read(&bh, MV64x60_CPU_MASTER_CNTL);
+	if (temp & (1 << 8)) {
+		temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+		mv64x60_write(&bh, MV64x60_CPU_CONFIG, (temp & ~(1 << 25)));
+	}
+
+	/* Data and address parity is enabled */
+	temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+	mv64x60_write(&bh, MV64x60_CPU_CONFIG,
+		      (temp | (1 << 26) | (1 << 19)));
+
+	pci_dram_offset = 0;	/* sys mem at same addr on PCI & cpu bus */
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = ppc7d_map_irq;
+	ppc_md.pci_exclude_device = ppc7d_pci_exclude_device;
+
+	mv64x60_set_bus(&bh, 0, 0);
+	bh.hose_a->first_busno = 0;
+	bh.hose_a->last_busno = 0xff;
+	bh.hose_a->mem_space.start = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR;
+	bh.hose_a->mem_space.end =
+	    PPC7D_PCI0_MEM0_START_PCI_LO_ADDR + PPC7D_PCI0_MEM0_SIZE;
+
+	/* These will be set later, as a result of PCI0 scan */
+	bh.hose_b->first_busno = 0;
+	bh.hose_b->last_busno = 0xff;
+	bh.hose_b->mem_space.start = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR;
+	bh.hose_b->mem_space.end =
+	    PPC7D_PCI1_MEM0_START_PCI_LO_ADDR + PPC7D_PCI1_MEM0_SIZE;
+
+	pr_debug("MV64360: PCI#0 IO decode %08x/%08x IO remap %08x\n",
+		 mv64x60_read(&bh, 0x48), mv64x60_read(&bh, 0x50),
+		 mv64x60_read(&bh, 0xf0));
+}
+
+static void __init ppc7d_setup_arch(void)
+{
+	int port;
+
+	loops_per_jiffy = 100000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef	CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_HDA1;
+#endif
+
+	if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) ||
+	    (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+		/* 745x is different.  We only want to pass along enable. */
+		_set_L2CR(L2CR_L2E);
+	else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)
+		/* All modules have 1MB of L2.  We also assume that an
+		 * L2 divisor of 3 will work.
+		 */
+		_set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3
+			  | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF);
+
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)
+		/* No L3 cache */
+		_set_L3CR(0);
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	/* Lookup PCI host bridges */
+	if (ppc_md.progress)
+		ppc_md.progress("ppc7d_setup_arch: calling setup_bridge", 0);
+
+	ppc7d_setup_bridge();
+	ppc7d_setup_peripherals();
+
+	/* Disable ethernet. It might have been setup by the bootrom */
+	for (port = 0; port < 3; port++)
+		mv64x60_write(&bh, MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port),
+			      0x0000ff00);
+
+	/* Clear queue pointers to ensure they are all initialized,
+	 * otherwise since queues 1-7 are unused, they have random
+	 * pointers which look strange in register dumps. Don't bother
+	 * with queue 0 since it will be initialized later.
+	 */
+	for (port = 0; port < 3; port++) {
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port),
+			      0x00000000);
+		mv64x60_write(&bh,
+			      MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port),
+			      0x00000000);
+	}
+
+	printk(KERN_INFO "Radstone Technology PPC7D\n");
+	if (ppc_md.progress)
+		ppc_md.progress("ppc7d_setup_arch: exit", 0);
+
+}
+
+/* Real Time Clock support.
+ * PPC7D has a DS1337 accessed by I2C.
+ */
+static ulong ppc7d_get_rtc_time(void)
+{
+        struct rtc_time tm;
+        int result;
+
+        spin_lock(&rtc_lock);
+        result = ds1337_do_command(0, DS1337_GET_DATE, &tm);
+        spin_unlock(&rtc_lock);
+
+        if (result == 0)
+                result = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+        return result;
+}
+
+static int ppc7d_set_rtc_time(unsigned long nowtime)
+{
+        struct rtc_time tm;
+        int result;
+
+        spin_lock(&rtc_lock);
+        to_tm(nowtime, &tm);
+        result = ds1337_do_command(0, DS1337_SET_DATE, &tm);
+        spin_unlock(&rtc_lock);
+
+        return result;
+}
+
+/* This kernel command line parameter can be used to have the target
+ * wait for a JTAG debugger to attach. Of course, a JTAG debugger
+ * with hardware breakpoint support can have the target stop at any
+ * location during init, but this is a convenience feature that makes
+ * it easier in the common case of loading the code using the ppcboot
+ * bootloader..
+ */
+static unsigned long ppc7d_wait_debugger;
+
+static int __init ppc7d_waitdbg(char *str)
+{
+	ppc7d_wait_debugger = 1;
+	return 1;
+}
+
+__setup("waitdbg", ppc7d_waitdbg);
+
+/* Second phase board init, called after other (architecture common)
+ * low-level services have been initialized.
+ */
+static void ppc7d_init2(void)
+{
+	unsigned long flags;
+	u32 data;
+	u8 data8;
+
+	pr_debug("%s: enter\n", __FUNCTION__);
+
+	/* Wait for debugger? */
+	if (ppc7d_wait_debugger) {
+		printk("Waiting for debugger...\n");
+
+		while (readl(&ppc7d_wait_debugger)) ;
+	}
+
+	/* Hook up i8259 interrupt which is connected to GPP28 */
+	request_irq(mv64360_irq_base + MV64x60_IRQ_GPP28, ppc7d_i8259_intr,
+		    SA_INTERRUPT, "I8259 (GPP28) interrupt", (void *)0);
+
+	/* Configure MPP16 as watchdog NMI, MPP17 as watchdog WDE */
+	spin_lock_irqsave(&mv64x60_lock, flags);
+	data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+	data &= ~(0x0000000f << 0);
+	data |= (0x00000004 << 0);
+	data &= ~(0x0000000f << 4);
+	data |= (0x00000004 << 4);
+	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+	spin_unlock_irqrestore(&mv64x60_lock, flags);
+
+	/* All LEDs off */
+	data8 = inb(PPC7D_CPLD_LEDS);
+	data8 &= ~0x08;
+	data8 |= 0x07;
+	outb(data8, PPC7D_CPLD_LEDS);
+
+        /* Hook up RTC. We couldn't do this earlier because we need the I2C subsystem */
+        ppc_md.set_rtc_time = ppc7d_set_rtc_time;
+        ppc_md.get_rtc_time = ppc7d_get_rtc_time;
+
+	pr_debug("%s: exit\n", __FUNCTION__);
+}
+
+/* Called from machine_init(), early, before any of the __init functions
+ * have run. We must init software-configurable pins before other functions
+ * such as interrupt controllers are initialised.
+ */
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+			  unsigned long r6, unsigned long r7)
+{
+	u8 val8;
+	u8 rev_num;
+
+	/* Map 0xe0000000-0xffffffff early because we need access to SRAM
+	 * and the ISA memory space (for serial port) here. This mapping
+	 * is redone properly in ppc7d_map_io() later.
+	 */
+	mtspr(SPRN_DBAT3U, 0xe0003fff);
+	mtspr(SPRN_DBAT3L, 0xe000002a);
+
+	/*
+	 * Zero SRAM. Note that this generates parity errors on
+	 * internal data path in SRAM if it's first time accessing it
+	 * after reset.
+	 *
+	 * We do this ASAP to avoid parity errors when reading
+	 * uninitialized SRAM.
+	 */
+	memset((void *)PPC7D_INTERNAL_SRAM_BASE, 0, MV64360_SRAM_SIZE);
+
+	pr_debug("platform_init: r3-r7: %lx %lx %lx %lx %lx\n",
+		 r3, r4, r5, r6, r7);
+
+	parse_bootinfo(find_bootinfo());
+
+	/* ASSUMPTION:  If both r3 (bd_t pointer) and r6 (cmdline pointer)
+	 * are non-zero, then we should use the board info from the bd_t
+	 * structure and the cmdline pointed to by r6 instead of the
+	 * information from birecs, if any.  Otherwise, use the information
+	 * from birecs as discovered by the preceeding call to
+	 * parse_bootinfo().  This rule should work with both PPCBoot, which
+	 * uses a bd_t board info structure, and the kernel boot wrapper,
+	 * which uses birecs.
+	 */
+	if (r3 && r6) {
+		bd_t *bp = (bd_t *) __res;
+
+		/* copy board info structure */
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+		/* copy command line */
+		*(char *)(r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+
+		printk(KERN_INFO "Board info data:-\n");
+		printk(KERN_INFO "  Internal freq: %lu MHz, bus freq: %lu MHz\n",
+		       bp->bi_intfreq, bp->bi_busfreq);
+		printk(KERN_INFO "  Memory: %lx, size %lx\n", bp->bi_memstart,
+		       bp->bi_memsize);
+		printk(KERN_INFO "  Console baudrate: %lu\n", bp->bi_baudrate);
+		printk(KERN_INFO "  Ethernet address: "
+		       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		       bp->bi_enetaddr[0], bp->bi_enetaddr[1],
+		       bp->bi_enetaddr[2], bp->bi_enetaddr[3],
+		       bp->bi_enetaddr[4], bp->bi_enetaddr[5]);
+	}
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+		printk(KERN_INFO "INITRD @ %lx/%lx\n", initrd_start, initrd_end);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Map in board regs, etc. */
+	isa_io_base = 0xe8000000;
+	isa_mem_base = 0xe8000000;
+	pci_dram_offset = 0x00000000;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch = ppc7d_setup_arch;
+	ppc_md.init = ppc7d_init2;
+	ppc_md.show_cpuinfo = ppc7d_show_cpuinfo;
+	ppc_md.irq_canonicalize = ppc7d_irq_canonicalize;
+	ppc_md.init_IRQ = ppc7d_init_irq;
+	ppc_md.get_irq = ppc7d_get_irq;
+
+	ppc_md.restart = ppc7d_restart;
+	ppc_md.power_off = ppc7d_power_off;
+	ppc_md.halt = ppc7d_halt;
+
+	ppc_md.find_end_of_memory = ppc7d_find_end_of_memory;
+	ppc_md.setup_io_mappings = ppc7d_map_io;
+
+	ppc_md.time_init = NULL;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = ppc7d_calibrate_decr;
+	ppc_md.nvram_read_val = NULL;
+	ppc_md.nvram_write_val = NULL;
+
+	ppc_md.heartbeat = ppc7d_heartbeat;
+	ppc_md.heartbeat_reset = HZ;
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+
+	ppc_md.pcibios_fixup_bus = ppc7d_pci_fixup_bus;
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) || \
+    defined(CONFIG_I2C_MV64XXX)
+	platform_notify = ppc7d_platform_notify;
+#endif
+
+#ifdef CONFIG_SERIAL_MPSC
+	/* On PPC7D, we must configure MPSC support via CPLD control
+	 * registers.
+	 */
+	outb(PPC7D_CPLD_RTS_COM4_SCLK |
+	     PPC7D_CPLD_RTS_COM56_ENABLED, PPC7D_CPLD_RTS);
+	outb(PPC7D_CPLD_COMS_COM3_TCLKEN |
+	     PPC7D_CPLD_COMS_COM3_TXEN |
+	     PPC7D_CPLD_COMS_COM4_TCLKEN |
+	     PPC7D_CPLD_COMS_COM4_TXEN, PPC7D_CPLD_COMS);
+#endif /* CONFIG_SERIAL_MPSC */
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+	ppc7d_early_serial_map();
+#ifdef  CONFIG_SERIAL_TEXT_DEBUG
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	ppc_md.progress = mv64x60_mpsc_progress;
+#elif defined(CONFIG_SERIAL_8250)
+	ppc_md.progress = gen550_progress;
+#else
+#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX
+#endif /* CONFIG_SERIAL_8250 */
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */
+
+	/* Enable write access to user flash.  This is necessary for
+	 * flash probe.
+	 */
+	val8 = readb((void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+	writeb(val8 | (PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED &
+		       PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK),
+	       (void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+
+	/* Determine if this board has IBM ALMA VME devices */
+	val8 = readb((void *)isa_io_base + PPC7D_CPLD_BOARD_REVISION);
+	rev_num = (val8 & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5;
+	if (rev_num <= 1)
+		ppc7d_has_alma = 1;
+
+#ifdef DEBUG
+	console_printk[0] = 8;
+#endif
+}
diff --git a/arch/ppc/platforms/radstone_ppc7d.h b/arch/ppc/platforms/radstone_ppc7d.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/radstone_ppc7d.h
@@ -0,0 +1,435 @@
+/*
+ * arch/ppc/platforms/radstone_ppc7d.h
+ *
+ * Board definitions for the Radstone PPC7D boards.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@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.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 1MB
+ * and start on a boundary that is a multiple of the window size):
+ *
+ *    0xff800000-0xffffffff      - Boot window
+ *    0xff000000-0xff000fff	 - AFIX registers (DevCS2)
+ *    0xfef00000-0xfef0ffff      - Internal MV64x60 registers
+ *    0xfef40000-0xfef7ffff      - Internal SRAM
+ *    0xfef00000-0xfef0ffff      - MV64360 Registers
+ *    0x70000000-0x7fffffff      - soldered flash (DevCS3)
+ *    0xe8000000-0xe9ffffff      - PCI I/O
+ *    0x80000000-0xbfffffff      - PCI MEM
+ */
+
+#ifndef __PPC_PLATFORMS_PPC7D_H
+#define __PPC_PLATFORMS_PPC7D_H
+
+#include <asm/ppcboot.h>
+
+/*****************************************************************************
+ * CPU Physical Memory Map setup.
+ *****************************************************************************/
+
+#define PPC7D_BOOT_WINDOW_BASE			0xff800000
+#define PPC7D_AFIX_REG_BASE			0xff000000
+#define PPC7D_INTERNAL_SRAM_BASE		0xfef40000
+#define PPC7D_FLASH_BASE			0x70000000
+
+#define PPC7D_BOOT_WINDOW_SIZE_ACTUAL		0x00800000 /* 8MB */
+#define PPC7D_FLASH_SIZE_ACTUAL			0x10000000 /* 256MB */
+
+#define PPC7D_BOOT_WINDOW_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
+		PPC7D_BOOT_WINDOW_SIZE_ACTUAL)
+#define PPC7D_FLASH_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
+		PPC7D_FLASH_SIZE_ACTUAL)
+#define PPC7D_AFIX_REG_SIZE		max(MV64360_WINDOW_SIZE_MIN, 0xff)
+
+
+#define PPC7D_PCI0_MEM0_START_PROC_ADDR        0x80000000UL
+#define PPC7D_PCI0_MEM0_START_PCI_HI_ADDR      0x00000000UL
+#define PPC7D_PCI0_MEM0_START_PCI_LO_ADDR      0x80000000UL
+#define PPC7D_PCI0_MEM0_SIZE                   0x20000000UL
+#define PPC7D_PCI0_MEM1_START_PROC_ADDR        0xe8010000UL
+#define PPC7D_PCI0_MEM1_START_PCI_HI_ADDR      0x00000000UL
+#define PPC7D_PCI0_MEM1_START_PCI_LO_ADDR      0x00000000UL
+#define PPC7D_PCI0_MEM1_SIZE                   0x000f0000UL
+#define PPC7D_PCI0_IO_START_PROC_ADDR          0xe8000000UL
+#define PPC7D_PCI0_IO_START_PCI_ADDR           0x00000000UL
+#define PPC7D_PCI0_IO_SIZE                     0x00010000UL
+
+#define PPC7D_PCI1_MEM0_START_PROC_ADDR        0xa0000000UL
+#define PPC7D_PCI1_MEM0_START_PCI_HI_ADDR      0x00000000UL
+#define PPC7D_PCI1_MEM0_START_PCI_LO_ADDR      0xa0000000UL
+#define PPC7D_PCI1_MEM0_SIZE                   0x20000000UL
+#define PPC7D_PCI1_MEM1_START_PROC_ADDR        0xe9800000UL
+#define PPC7D_PCI1_MEM1_START_PCI_HI_ADDR      0x00000000UL
+#define PPC7D_PCI1_MEM1_START_PCI_LO_ADDR      0x00000000UL
+#define PPC7D_PCI1_MEM1_SIZE                   0x00800000UL
+#define PPC7D_PCI1_IO_START_PROC_ADDR          0xe9000000UL
+#define PPC7D_PCI1_IO_START_PCI_ADDR           0x00000000UL
+#define PPC7D_PCI1_IO_SIZE                     0x00010000UL
+
+#define	PPC7D_DEFAULT_BAUD			9600
+#define	PPC7D_MPSC_CLK_SRC			8	  /* TCLK */
+#define	PPC7D_MPSC_CLK_FREQ			133333333 /* 133.3333... MHz */
+
+#define	PPC7D_ETH0_PHY_ADDR			8
+#define	PPC7D_ETH1_PHY_ADDR			9
+#define	PPC7D_ETH2_PHY_ADDR			0
+
+#define PPC7D_ETH_TX_QUEUE_SIZE			400
+#define PPC7D_ETH_RX_QUEUE_SIZE			400
+
+#define	PPC7D_ETH_PORT_CONFIG_VALUE			\
+	MV64340_ETH_UNICAST_NORMAL_MODE			|	\
+	MV64340_ETH_DEFAULT_RX_QUEUE_0			|	\
+	MV64340_ETH_DEFAULT_RX_ARP_QUEUE_0		|	\
+	MV64340_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP		|	\
+	MV64340_ETH_RECEIVE_BC_IF_IP			|	\
+	MV64340_ETH_RECEIVE_BC_IF_ARP			|	\
+	MV64340_ETH_CAPTURE_TCP_FRAMES_DIS		|	\
+	MV64340_ETH_CAPTURE_UDP_FRAMES_DIS		|	\
+	MV64340_ETH_DEFAULT_RX_TCP_QUEUE_0		|	\
+	MV64340_ETH_DEFAULT_RX_UDP_QUEUE_0		|	\
+	MV64340_ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+#define	PPC7D_ETH_PORT_CONFIG_EXTEND_VALUE		\
+	MV64340_ETH_SPAN_BPDU_PACKETS_AS_NORMAL		|	\
+	MV64340_ETH_PARTITION_DISABLE
+
+#define	GT_ETH_IPG_INT_RX(value)			\
+	((value & 0x3fff) << 8)
+
+#define	PPC7D_ETH_PORT_SDMA_CONFIG_VALUE		\
+	MV64340_ETH_RX_BURST_SIZE_4_64BIT		|	\
+	GT_ETH_IPG_INT_RX(0)			|	\
+	MV64340_ETH_TX_BURST_SIZE_4_64BIT
+
+#define	PPC7D_ETH_PORT_SERIAL_CONTROL_VALUE		\
+	MV64340_ETH_ENABLE_AUTO_NEG_FOR_DUPLX		|	\
+	MV64340_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL	|	\
+	MV64340_ETH_ADV_SYMMETRIC_FLOW_CTRL		|	\
+	MV64340_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX	|	\
+	MV64340_ETH_FORCE_BP_MODE_NO_JAM		|	\
+	(1 << 9)					|	\
+	MV64340_ETH_DO_NOT_FORCE_LINK_FAIL		|	\
+	MV64340_ETH_RETRANSMIT_16_ATTEMPTS		|	\
+	MV64340_ETH_ENABLE_AUTO_NEG_SPEED_GMII		|	\
+	MV64340_ETH_DTE_ADV_0				|	\
+	MV64340_ETH_DISABLE_AUTO_NEG_BYPASS		|	\
+	MV64340_ETH_AUTO_NEG_NO_CHANGE			|	\
+	MV64340_ETH_MAX_RX_PACKET_9700BYTE		|	\
+	MV64340_ETH_CLR_EXT_LOOPBACK			|	\
+	MV64340_ETH_SET_FULL_DUPLEX_MODE		|	\
+	MV64340_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+/*****************************************************************************
+ * Serial defines.
+ *****************************************************************************/
+
+#define PPC7D_SERIAL_0		0xe80003f8
+#define PPC7D_SERIAL_1		0xe80002f8
+
+#define RS_TABLE_SIZE  2
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define UART_CLK			1843200
+#define BASE_BAUD			( UART_CLK / 16 )
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DFNS \
+        { 0, BASE_BAUD, PPC7D_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \
+		iomem_base: (u8 *)PPC7D_SERIAL_0,			  \
+		io_type: SERIAL_IO_MEM, },				  \
+        { 0, BASE_BAUD, PPC7D_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \
+		iomem_base: (u8 *)PPC7D_SERIAL_1,			  \
+		io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DFNS
+
+/*****************************************************************************
+ * CPLD defines.
+ *
+ * Register map:-
+ *
+ * 0000 to 000F 	South Bridge DMA 1 Control
+ * 0020 and 0021 	South Bridge Interrupt 1 Control
+ * 0040 to 0043 	South Bridge Counter Control
+ * 0060 		Keyboard
+ * 0061 		South Bridge NMI Status and Control
+ * 0064 		Keyboard
+ * 0071 and 0072 	RTC R/W
+ * 0078 to 007B 	South Bridge BIOS Timer
+ * 0080 to 0090 	South Bridge DMA Pages
+ * 00A0 and 00A1 	South Bridge Interrupt 2 Control
+ * 00C0 to 00DE 	South Bridge DMA 2 Control
+ * 02E8 to 02EF 	COM6 R/W
+ * 02F8 to 02FF 	South Bridge COM2 R/W
+ * 03E8 to 03EF 	COM5 R/W
+ * 03F8 to 03FF 	South Bridge COM1 R/W
+ * 040A 		South Bridge DMA Scatter/Gather RO
+ * 040B 		DMA 1 Extended Mode WO
+ * 0410 to 043F 	South Bridge DMA Scatter/Gather
+ * 0481 to 048B 	South Bridge DMA High Pages
+ * 04D0 and 04D1 	South Bridge Edge/Level Control
+ * 04D6 		DMA 2 Extended Mode WO
+ * 0804 		Memory Configuration RO
+ * 0806 		Memory Configuration Extend RO
+ * 0808 		SCSI Activity LED R/W
+ * 080C 		Equipment Present 1 RO
+ * 080E 		Equipment Present 2 RO
+ * 0810 		Equipment Present 3 RO
+ * 0812 		Equipment Present 4 RO
+ * 0818 		Key Lock RO
+ * 0820 		LEDS R/W
+ * 0824 		COMs R/W
+ * 0826 		RTS R/W
+ * 0828 		Reset R/W
+ * 082C 		Watchdog Trig R/W
+ * 082E 		Interrupt R/W
+ * 0830 		Interrupt Status RO
+ * 0832 		PCI configuration RO
+ * 0854 		Board Revision RO
+ * 0858 		Extended ID RO
+ * 0864 		ID Link RO
+ * 0866 		Motherboard Type RO
+ * 0868 		FLASH Write control RO
+ * 086A 		Software FLASH write protect R/W
+ * 086E 		FLASH Control R/W
+ *****************************************************************************/
+
+#define PPC7D_CPLD_MEM_CONFIG			0x0804
+#define PPC7D_CPLD_MEM_CONFIG_EXTEND		0x0806
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED		0x0808
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_1		0x080C
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_2		0x080E
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_3		0x0810
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_4		0x0812
+#define PPC7D_CPLD_KEY_LOCK			0x0818
+#define PPC7D_CPLD_LEDS				0x0820
+#define PPC7D_CPLD_COMS				0x0824
+#define PPC7D_CPLD_RTS				0x0826
+#define PPC7D_CPLD_RESET			0x0828
+#define PPC7D_CPLD_WATCHDOG_TRIG		0x082C
+#define PPC7D_CPLD_INTR				0x082E
+#define PPC7D_CPLD_INTR_STATUS			0x0830
+#define PPC7D_CPLD_PCI_CONFIG			0x0832
+#define PPC7D_CPLD_BOARD_REVISION		0x0854
+#define PPC7D_CPLD_EXTENDED_ID			0x0858
+#define PPC7D_CPLD_ID_LINK			0x0864
+#define PPC7D_CPLD_MOTHERBOARD_TYPE		0x0866
+#define PPC7D_CPLD_FLASH_WRITE_CNTL		0x0868
+#define PPC7D_CPLD_SW_FLASH_WRITE_PROTECT	0x086A
+#define PPC7D_CPLD_FLASH_CNTL			0x086E
+
+/* MEMORY_CONFIG_EXTEND */
+#define PPC7D_CPLD_SDRAM_BANK_NUM_MASK		0x02
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_MASK		0xc0
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_128M		0
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_256M		0x40
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_512M		0x80
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_1G		0xc0
+#define PPC7D_CPLD_FLASH_DEV_SIZE_MASK		0x03
+#define PPC7D_CPLD_FLASH_BANK_NUM_MASK		0x0c
+#define PPC7D_CPLD_FLASH_DEV_SIZE_64M		0
+#define PPC7D_CPLD_FLASH_DEV_SIZE_32M		1
+#define PPC7D_CPLD_FLASH_DEV_SIZE_16M		3
+#define PPC7D_CPLD_FLASH_BANK_NUM_4		0x00
+#define PPC7D_CPLD_FLASH_BANK_NUM_3		0x04
+#define PPC7D_CPLD_FLASH_BANK_NUM_2		0x08
+#define PPC7D_CPLD_FLASH_BANK_NUM_1		0x0c
+
+/* SCSI_LED */
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED_OFF	0
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED_ON		1
+
+/* EQUIPMENT_PRESENT_1 */
+#define PPC7D_CPLD_EQPT_PRES_1_FITTED		0
+#define PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK	(0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK	(0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK	(0x80 >> 4)
+
+/* EQUIPMENT_PRESENT_2 */
+#define PPC7D_CPLD_EQPT_PRES_2_FITTED		!0
+#define PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK	(0x80 >> 0)
+#define PPC7D_CPLD_EQPT_PRES_2_COM36_MASK	(0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK	(0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK	(0x80 >> 4)
+
+/* EQUIPMENT_PRESENT_3 */
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK	(0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_5V		(0 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_3V		(0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK	(0x80 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_5V		(0 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_3V		(0x80 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK	(0x80 >> 5)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_INTER	(0 >> 5)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_VME	(0x80 >> 5)
+
+/* EQUIPMENT_PRESENT_4 */
+#define PPC7D_CPLD_EQPT_PRES_4_LPT_MASK		(0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_4_LPT_FITTED	(0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_4_PS2_USB2_MASK	(0xc0 >> 6)
+#define PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED	(0x40 >> 6)
+#define PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED	(0x80 >> 6)
+
+/* CPLD_LEDS */
+#define PPC7D_CPLD_LEDS_ON			(!0)
+#define PPC7D_CPLD_LEDS_OFF			(0)
+#define PPC7D_CPLD_LEDS_NVRAM_PAGE_MASK		(0xc0 >> 2)
+#define PPC7D_CPLD_LEDS_DS201_MASK		(0x80 >> 4)
+#define PPC7D_CPLD_LEDS_DS219_MASK		(0x80 >> 5)
+#define PPC7D_CPLD_LEDS_DS220_MASK		(0x80 >> 6)
+#define PPC7D_CPLD_LEDS_DS221_MASK		(0x80 >> 7)
+
+/* CPLD_COMS */
+#define PPC7D_CPLD_COMS_COM3_TCLKEN		(0x80 >> 0)
+#define PPC7D_CPLD_COMS_COM3_RTCLKEN		(0x80 >> 1)
+#define PPC7D_CPLD_COMS_COM3_MODE_MASK		(0x80 >> 2)
+#define PPC7D_CPLD_COMS_COM3_MODE_RS232		(0)
+#define PPC7D_CPLD_COMS_COM3_MODE_RS422		(0x80 >> 2)
+#define PPC7D_CPLD_COMS_COM3_TXEN		(0x80 >> 3)
+#define PPC7D_CPLD_COMS_COM4_TCLKEN		(0x80 >> 4)
+#define PPC7D_CPLD_COMS_COM4_RTCLKEN		(0x80 >> 5)
+#define PPC7D_CPLD_COMS_COM4_MODE_MASK		(0x80 >> 6)
+#define PPC7D_CPLD_COMS_COM4_MODE_RS232		(0)
+#define PPC7D_CPLD_COMS_COM4_MODE_RS422		(0x80 >> 6)
+#define PPC7D_CPLD_COMS_COM4_TXEN		(0x80 >> 7)
+
+/* CPLD_RTS */
+#define PPC7D_CPLD_RTS_COM36_LOOPBACK		(0x80 >> 0)
+#define PPC7D_CPLD_RTS_COM4_SCLK		(0x80 >> 1)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_MASK		(0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_DISABLED	(0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED	(0x80 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3	(0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3S (0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM56_MODE_MASK		(0x80 >> 4)
+#define PPC7D_CPLD_RTS_COM56_MODE_RS232		(0)
+#define PPC7D_CPLD_RTS_COM56_MODE_RS422		(0x80 >> 4)
+#define PPC7D_CPLD_RTS_COM56_ENABLE_MASK	(0x80 >> 5)
+#define PPC7D_CPLD_RTS_COM56_DISABLED		(0)
+#define PPC7D_CPLD_RTS_COM56_ENABLED		(0x80 >> 5)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_MASK		(0xc0 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_DISABLED	(0 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED	(0x80 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3	(0x40 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3S (0x40 >> 6)
+
+/* WATCHDOG_TRIG */
+#define PPC7D_CPLD_WDOG_CAUSE_MASK		(0x80 >> 0)
+#define PPC7D_CPLD_WDOG_CAUSE_NORMAL_RESET	(0 >> 0)
+#define PPC7D_CPLD_WDOG_CAUSE_WATCHDOG		(0x80 >> 0)
+#define PPC7D_CPLD_WDOG_ENABLE_MASK		(0x80 >> 6)
+#define PPC7D_CPLD_WDOG_ENABLE_OFF		(0 >> 6)
+#define PPC7D_CPLD_WDOG_ENABLE_ON		(0x80 >> 6)
+#define PPC7D_CPLD_WDOG_RESETSW_MASK		(0x80 >> 7)
+#define PPC7D_CPLD_WDOG_RESETSW_OFF		(0 >> 7)
+#define PPC7D_CPLD_WDOG_RESETSW_ON		(0x80 >> 7)
+
+/* Interrupt mask and status bits */
+#define PPC7D_CPLD_INTR_TEMP_MASK		(0x80 >> 0)
+#define PPC7D_CPLD_INTR_HB8_MASK		(0x80 >> 1)
+#define PPC7D_CPLD_INTR_PHY1_MASK		(0x80 >> 2)
+#define PPC7D_CPLD_INTR_PHY0_MASK		(0x80 >> 3)
+#define PPC7D_CPLD_INTR_ISANMI_MASK		(0x80 >> 5)
+#define PPC7D_CPLD_INTR_CRITTEMP_MASK		(0x80 >> 6)
+
+/* CPLD_INTR */
+#define PPC7D_CPLD_INTR_ENABLE_OFF		(0)
+#define PPC7D_CPLD_INTR_ENABLE_ON		(!0)
+
+/* CPLD_INTR_STATUS */
+#define PPC7D_CPLD_INTR_STATUS_OFF		(0)
+#define PPC7D_CPLD_INTR_STATUS_ON		(!0)
+
+/* CPLD_PCI_CONFIG */
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_MASK		0x70
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI33	0x00
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI66	0x10
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX33	0x40
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX66	0x50
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX100      0x60
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX133	0x70
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_MASK		0x07
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI33	0x00
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI66	0x01
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX33	0x04
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX66	0x05
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX100	0x06
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX133	0x07
+
+/* CPLD_BOARD_REVISION */
+#define PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK	0xe0
+#define PPC7D_CPLD_BOARD_REVISION_LETTER_MASK	0x1f
+
+/* CPLD_EXTENDED_ID */
+#define PPC7D_CPLD_EXTENDED_ID_PPC7D		0x18
+
+/* CPLD_ID_LINK */
+#define PPC7D_CPLD_ID_LINK_VME64_GAP_MASK	(0x80 >> 2)
+#define PPC7D_CPLD_ID_LINK_VME64_GA4_MASK	(0x80 >> 3)
+#define PPC7D_CPLD_ID_LINK_E13_MASK		(0x80 >> 4)
+#define PPC7D_CPLD_ID_LINK_E12_MASK		(0x80 >> 5)
+#define PPC7D_CPLD_ID_LINK_E7_MASK		(0x80 >> 6)
+#define PPC7D_CPLD_ID_LINK_E6_MASK		(0x80 >> 7)
+
+/* CPLD_MOTHERBOARD_TYPE */
+#define PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK	(0x80 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_ENABLED		(0x80 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_DISABLED		(0 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK	(0x80 >> 3)
+#define PPC7D_CPLD_MB_TYPE_PLL_MASK		0x0c
+#define PPC7D_CPLD_MB_TYPE_PLL_133		0x00
+#define PPC7D_CPLD_MB_TYPE_PLL_100		0x08
+#define PPC7D_CPLD_MB_TYPE_PLL_64		0x04
+#define PPC7D_CPLD_MB_TYPE_HW_ID_MASK		0x03
+
+/* CPLD_FLASH_WRITE_CNTL */
+#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK	(0x80 >> 0)
+#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_FITTED	(0x80 >> 0)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK	(0x80 >> 2)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_FITTED	(0x80 >> 2)
+#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK	(0x80 >> 3)
+#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_FITTED	(0x80 >> 3)
+#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK	(0x80 >> 5)
+#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_ENABLED	(0x80 >> 5)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK	(0x80 >> 6)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_ENABLED	(0x80 >> 6)
+#define PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK	(0x80 >> 7)
+#define PPD7D_CPLD_FLASH_CNTL_USER_WR_ENABLED	(0x80 >> 7)
+
+/* CPLD_SW_FLASH_WRITE_PROTECT */
+#define PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED	(!0)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_DISABLED	(0)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK	(0x80 >> 6)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK	(0x80 >> 7)
+
+/* CPLD_FLASH_WRITE_CNTL */
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK	(0x80 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_DISABLED	(0 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_ENABLED	(0x80 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK	(0x80 >> 1)
+#define PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK	(0x80 >> 2)
+#define PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK	(0x80 >> 3)
+
+
+#endif /* __PPC_PLATFORMS_PPC7D_H */
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
--- a/arch/ppc/platforms/sandpoint.c
+++ b/arch/ppc/platforms/sandpoint.c
@@ -202,13 +202,6 @@ sandpoint_setup_winbond_83553(struct pci
 				0x48, /* ISA-to-PCI Addr Decoder Control */
 				0xf0);
 
-	/* Enable RTC and Keyboard address locations.  */
-	early_write_config_byte(hose,
-				0,
-				devfn,
-				0x4d,	/* Chip Select Control Register */
-				0x00);
-
 	/* Enable Port 92.  */
 	early_write_config_byte(hose,
 				0,
@@ -319,10 +312,10 @@ sandpoint_setup_arch(void)
 	 * We will do this now with good known values.  Future versions
 	 * of DINK32 are supposed to get this correct.
 	 */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450)
+	if (cpu_has_feature(CPU_FTR_SPEC7450))
 		/* 745x is different.  We only want to pass along enable. */
 		_set_L2CR(L2CR_L2E);
-	else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)
+	else if (cpu_has_feature(CPU_FTR_L2CR))
 		/* All modules have 1MB of L2.  We also assume that an
 		 * L2 divisor of 3 will work.
 		 */
@@ -330,7 +323,7 @@ sandpoint_setup_arch(void)
 				| L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF);
 #if 0
 	/* Untested right now. */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) {
+	if (cpu_has_feature(CPU_FTR_L3CR)) {
 		/* Magic value. */
 		_set_L3CR(0x8f032000);
 	}
diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
--- a/arch/ppc/platforms/spruce.c
+++ b/arch/ppc/platforms/spruce.c
@@ -278,8 +278,8 @@ static __inline__ void
 spruce_set_bat(void)
 {
 	mb();
-	mtspr(DBAT1U, 0xf8000ffe);
-	mtspr(DBAT1L, 0xf800002a);
+	mtspr(SPRN_DBAT1U, 0xf8000ffe);
+	mtspr(SPRN_DBAT1L, 0xf800002a);
 	mb();
 }
 
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_GT64260)		+= gt64260_pic.o
 obj-$(CONFIG_K2)		+= i8259.o indirect_pci.o todc_time.o \
 					pci_auto.o
 obj-$(CONFIG_LOPEC)		+= i8259.o pci_auto.o todc_time.o
+obj-$(CONFIG_HDPU)		+= pci_auto.o
 obj-$(CONFIG_LUAN)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_KATANA)		+= pci_auto.o
 obj-$(CONFIG_MCPN765)		+= todc_time.o indirect_pci.o pci_auto.o \
@@ -74,12 +75,13 @@ obj-$(CONFIG_PRPMC750)		+= open_pic.o in
 					hawk_common.o
 obj-$(CONFIG_HARRIER)		+= harrier.o
 obj-$(CONFIG_PRPMC800)		+= open_pic.o indirect_pci.o pci_auto.o
+obj-$(CONFIG_RADSTONE_PPC7D)	+= i8259.o pci_auto.o
 obj-$(CONFIG_SANDPOINT)		+= i8259.o pci_auto.o todc_time.o
 obj-$(CONFIG_SBC82xx)		+= todc_time.o
 obj-$(CONFIG_SPRUCE)		+= cpc700_pic.o indirect_pci.o pci_auto.o \
 				   todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o
-obj-$(CONFIG_PCI_8260)		+= m8260_pci.o indirect_pci.o
+obj-$(CONFIG_PCI_8260)		+= m82xx_pci.o indirect_pci.o pci_auto.o
 obj-$(CONFIG_8260_PCI9)		+= m8260_pci_erratum9.o
 obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
 ifeq ($(CONFIG_PPC_GEN550),y)
@@ -95,8 +97,19 @@ obj-$(CONFIG_MPC10X_OPENPIC)	+= open_pic
 obj-$(CONFIG_40x)		+= dcr.o
 obj-$(CONFIG_BOOKE)		+= dcr.o
 obj-$(CONFIG_85xx)		+= open_pic.o ppc85xx_common.o ppc85xx_setup.o \
-					ppc_sys.o
+					ppc_sys.o i8259.o mpc85xx_sys.o \
+					mpc85xx_devices.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
 endif
-obj-$(CONFIG_PPC_MPC52xx)	+= mpc52xx_setup.o mpc52xx_pic.o
+obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
+					mpc83xx_sys.o mpc83xx_devices.o
+ifeq ($(CONFIG_83xx),y)
+obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+endif
+obj-$(CONFIG_MPC8555_CDS)	+= todc_time.o
+obj-$(CONFIG_PPC_MPC52xx)	+= mpc52xx_setup.o mpc52xx_pic.o \
+					mpc52xx_sys.o mpc52xx_devices.o ppc_sys.o
+ifeq ($(CONFIG_PPC_MPC52xx),y)
+obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
+endif
diff --git a/arch/ppc/syslib/btext.c b/arch/ppc/syslib/btext.c
--- a/arch/ppc/syslib/btext.c
+++ b/arch/ppc/syslib/btext.c
@@ -137,7 +137,7 @@ btext_prepare_BAT(void)
 		boot_text_mapped = 0;
 		return;
 	}
-	if (PVR_VER(mfspr(PVR)) != 1) {
+	if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
 		/* 603, 604, G3, G4, ... */
 		lowbits = addr & ~0xFF000000UL;
 		addr &= 0xFF000000UL;
diff --git a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h
--- a/arch/ppc/syslib/cpc700.h
+++ b/arch/ppc/syslib/cpc700.h
@@ -17,13 +17,14 @@
  * memory controller, PIC, UARTs, IIC, and Timers.
  */
 
-#ifndef	_ASMPPC_CPC700_H
-#define	_ASMPPC_CPC700_H
+#ifndef	__PPC_SYSLIB_CPC700_H__
+#define	__PPC_SYSLIB_CPC700_H__
 
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/init.h>
 
+/* XXX no barriers? not even any volatiles?  -- paulus */
 #define CPC700_OUT_32(a,d)  (*(u_int *)a = d)
 #define CPC700_IN_32(a)     (*(u_int *)a)
 
@@ -33,21 +34,26 @@
 #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
+/* CPU -> PCI memory window 0 */
+#define CPC700_PMM0_LOCAL		0xff400000	/* CPU physical addr */
+#define CPC700_PMM0_MASK_ATTR		0xff400004	/* size and attrs */
+#define CPC700_PMM0_PCI_LOW		0xff400008	/* PCI addr, low word */
+#define CPC700_PMM0_PCI_HIGH		0xff40000c	/* PCI addr, high wd */
+/* CPU -> PCI memory window 1 */
 #define CPC700_PMM1_LOCAL		0xff400010
 #define CPC700_PMM1_MASK_ATTR		0xff400014
 #define CPC700_PMM1_PCI_LOW		0xff400018
 #define CPC700_PMM1_PCI_HIGH		0xff40001c
+/* CPU -> PCI memory window 2 */
 #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
+/* PCI memory -> CPU window 1 */
+#define CPC700_PTM1_MEMSIZE		0xff400030	/* window size */
+#define CPC700_PTM1_LOCAL		0xff400034	/* CPU phys addr */
+/* PCI memory -> CPU window 2 */
+#define CPC700_PTM2_MEMSIZE		0xff400038	/* size and enable */
 #define CPC700_PTM2_LOCAL		0xff40003c
 
 /*
@@ -89,4 +95,4 @@ extern unsigned int cpc700_irq_assigns[3
 extern void __init cpc700_init_IRQ(void);
 extern int cpc700_get_irq(struct pt_regs *);
 
-#endif	/* _ASMPPC_CPC700_H */
+#endif	/* __PPC_SYSLIB_CPC700_H__ */
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
--- a/arch/ppc/syslib/cpm2_pic.c
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -32,15 +32,17 @@ static	u_char	irq_to_siureg[] = {
 	0, 0, 0, 0, 0, 0, 0, 0
 };
 
+/* bit numbers do not match the docs, these are precomputed so the bit for
+ * a given irq is (1 << irq_to_siubit[irq]) */
 static	u_char	irq_to_siubit[] = {
-	31, 16, 17, 18, 19, 20, 21, 22,
-	23, 24, 25, 26, 27, 28, 29, 30,
-	29, 30, 16, 17, 18, 19, 20, 21,
-	22, 23, 24, 25, 26, 27, 28, 31,
-	 0,  1,  2,  3,  4,  5,  6,  7,
-	 8,  9, 10, 11, 12, 13, 14, 15,
-	15, 14, 13, 12, 11, 10,  9,  8,
-	 7,  6,  5,  4,  3,  2,  1,  0
+	 0, 15, 14, 13, 12, 11, 10,  9,
+	 8,  7,  6,  5,  4,  3,  2,  1,
+	 2,  1, 15, 14, 13, 12, 11, 10,
+	 9,  8,  7,  6,  5,  4,  3,  0,
+	31, 30, 29, 28, 27, 26, 25, 24,
+	23, 22, 21, 20, 19, 18, 17, 16,
+	16, 17, 18, 19, 20, 21, 22, 23,
+	24, 25, 26, 27, 28, 29, 30, 31,
 };
 
 static void cpm2_mask_irq(unsigned int irq_nr)
@@ -48,11 +50,13 @@ static void cpm2_mask_irq(unsigned int i
 	int	bit, word;
 	volatile uint	*simr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	ppc_cached_irq_mask[word] &= ~(1 << bit);
 	simr[word] = ppc_cached_irq_mask[word];
 }
 
@@ -61,11 +65,13 @@ static void cpm2_unmask_irq(unsigned int
 	int	bit, word;
 	volatile uint	*simr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
-	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	ppc_cached_irq_mask[word] |= 1 << bit;
 	simr[word] = ppc_cached_irq_mask[word];
 }
 
@@ -74,14 +80,16 @@ static void cpm2_mask_and_ack(unsigned i
 	int	bit, word;
 	volatile uint	*simr, *sipnr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
 	sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	ppc_cached_irq_mask[word] &= ~(1 << bit);
 	simr[word] = ppc_cached_irq_mask[word];
-	sipnr[word] = 1 << (31 - bit);
+	sipnr[word] = 1 << bit;
 }
 
 static void cpm2_end_irq(unsigned int irq_nr)
@@ -92,29 +100,30 @@ static void cpm2_end_irq(unsigned int ir
 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
 			&& irq_desc[irq_nr].action) {
 
+		irq_nr -= CPM_IRQ_OFFSET;
 		bit = irq_to_siubit[irq_nr];
 		word = irq_to_siureg[irq_nr];
 
 		simr = &(cpm2_immr->im_intctl.ic_simrh);
-		ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+		ppc_cached_irq_mask[word] |= 1 << bit;
 		simr[word] = ppc_cached_irq_mask[word];
+		/*
+		 * Work around large numbers of spurious IRQs on PowerPC 82xx
+		 * systems.
+		 */
+		mb();
 	}
 }
 
-struct hw_interrupt_type cpm2_pic = {
-	" CPM2 SIU  ",
-	NULL,
-	NULL,
-	cpm2_unmask_irq,
-	cpm2_mask_irq,
-	cpm2_mask_and_ack,
-	cpm2_end_irq,
-	0
+static struct hw_interrupt_type cpm2_pic = {
+	.typename = " CPM2 SIU ",
+	.enable = cpm2_unmask_irq,
+	.disable = cpm2_mask_irq,
+	.ack = cpm2_mask_and_ack,
+	.end = cpm2_end_irq,
 };
 
-
-int
-cpm2_get_irq(struct pt_regs *regs)
+int cpm2_get_irq(struct pt_regs *regs)
 {
 	int irq;
         unsigned long bits;
@@ -126,5 +135,43 @@ cpm2_get_irq(struct pt_regs *regs)
 
 	if (irq == 0)
 		return(-1);
-	return irq;
+	return irq+CPM_IRQ_OFFSET;
+}
+
+void cpm2_init_IRQ(void)
+{
+	int i;
+
+	/* Clear the CPM IRQ controller, in case it has any bits set
+	 * from the bootloader
+	 */
+
+	/* Mask out everything */
+	cpm2_immr->im_intctl.ic_simrh = 0x00000000;
+	cpm2_immr->im_intctl.ic_simrl = 0x00000000;
+	wmb();
+
+	/* Ack everything */
+	cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
+	cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
+	wmb();
+
+	/* Dummy read of the vector */
+	i = cpm2_immr->im_intctl.ic_sivec;
+	rmb();
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	cpm2_immr->im_intctl.ic_sicr = 0;
+	cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
+	cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
+
+
+	/* Enable chaining to OpenPIC, and make everything level
+	 */
+	for (i = 0; i < NR_CPM_INTS; i++) {
+		irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
+	}
 }
diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h
--- a/arch/ppc/syslib/cpm2_pic.h
+++ b/arch/ppc/syslib/cpm2_pic.h
@@ -1,7 +1,8 @@
 #ifndef _PPC_KERNEL_CPM2_H
 #define _PPC_KERNEL_CPM2_H
 
-extern struct hw_interrupt_type cpm2_pic;
 extern int cpm2_get_irq(struct pt_regs *regs);
 
+extern void cpm2_init_IRQ(void);
+
 #endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c
--- a/arch/ppc/syslib/ibm440gx_common.c
+++ b/arch/ppc/syslib/ibm440gx_common.c
@@ -221,7 +221,7 @@ void __init ibm440gx_l2c_setup(struct ib
 	/* Disable L2C on rev.A, rev.B and 800MHz version of rev.C,
 	   enable it on all other revisions
 	 */
-	u32 pvr = mfspr(PVR);
+	u32 pvr = mfspr(SPRN_PVR);
 	if (pvr == PVR_440GX_RA || pvr == PVR_440GX_RB ||
 	    (pvr == PVR_440GX_RC && p->cpu > 667000000))
 		ibm440gx_l2c_disable();
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ipic.c
@@ -0,0 +1,646 @@
+/*
+ * include/asm-ppc/ipic.c
+ *
+ * IPIC routines implementations.
+ *
+ * Copyright 2005 Freescale 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/ipic.h>
+#include <asm/mpc83xx.h>
+
+#include "ipic.h"
+
+static struct ipic p_ipic;
+static struct ipic * primary_ipic;
+
+static struct ipic_info ipic_info[] = {
+	[9] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 24,
+		.prio_mask = 0,
+	},
+	[10] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 25,
+		.prio_mask = 1,
+	},
+	[11] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 26,
+		.prio_mask = 2,
+	},
+	[14] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 29,
+		.prio_mask = 5,
+	},
+	[15] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 30,
+		.prio_mask = 6,
+	},
+	[16] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_D,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 31,
+		.prio_mask = 7,
+	},
+	[17] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SEFCR,
+		.bit	= 1,
+		.prio_mask = 5,
+	},
+	[18] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SEFCR,
+		.bit	= 2,
+		.prio_mask = 6,
+	},
+	[19] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SEFCR,
+		.bit	= 3,
+		.prio_mask = 7,
+	},
+	[20] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SEFCR,
+		.bit	= 4,
+		.prio_mask = 4,
+	},
+	[21] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SEFCR,
+		.bit	= 5,
+		.prio_mask = 5,
+	},
+	[22] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SEFCR,
+		.bit	= 6,
+		.prio_mask = 6,
+	},
+	[23] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SEFCR,
+		.bit	= 7,
+		.prio_mask = 7,
+	},
+	[32] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 0,
+		.prio_mask = 0,
+	},
+	[33] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 1,
+		.prio_mask = 1,
+	},
+	[34] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 2,
+		.prio_mask = 2,
+	},
+	[35] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 3,
+		.prio_mask = 3,
+	},
+	[36] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 4,
+		.prio_mask = 4,
+	},
+	[37] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 5,
+		.prio_mask = 5,
+	},
+	[38] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 6,
+		.prio_mask = 6,
+	},
+	[39] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_H,
+		.prio	= IPIC_SIPRR_A,
+		.force	= IPIC_SIFCR_H,
+		.bit	= 7,
+		.prio_mask = 7,
+	},
+	[48] = {
+		.pend	= IPIC_SEPNR,
+		.mask	= IPIC_SEMSR,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SEFCR,
+		.bit	= 0,
+		.prio_mask = 4,
+	},
+	[64] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 0,
+		.prio_mask = 0,
+	},
+	[65] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 1,
+		.prio_mask = 1,
+	},
+	[66] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 2,
+		.prio_mask = 2,
+	},
+	[67] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_A,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 3,
+		.prio_mask = 3,
+	},
+	[68] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 4,
+		.prio_mask = 0,
+	},
+	[69] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 5,
+		.prio_mask = 1,
+	},
+	[70] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 6,
+		.prio_mask = 2,
+	},
+	[71] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= IPIC_SMPRR_B,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 7,
+		.prio_mask = 3,
+	},
+	[72] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 8,
+	},
+	[73] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 9,
+	},
+	[74] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 10,
+	},
+	[75] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 11,
+	},
+	[76] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 12,
+	},
+	[77] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 13,
+	},
+	[78] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 14,
+	},
+	[79] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 15,
+	},
+	[80] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 16,
+	},
+	[84] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 20,
+	},
+	[85] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 21,
+	},
+	[90] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 26,
+	},
+	[91] = {
+		.pend	= IPIC_SIPNR_H,
+		.mask	= IPIC_SIMSR_L,
+		.prio	= 0,
+		.force	= IPIC_SIFCR_L,
+		.bit	= 27,
+	},
+};
+
+static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
+{
+	return in_be32(base + (reg >> 2));
+}
+
+static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
+{
+	out_be32(base + (reg >> 2), value);
+}
+
+static inline struct ipic * ipic_from_irq(unsigned int irq)
+{
+	return primary_ipic;
+}
+
+static void ipic_enable_irq(unsigned int irq)
+{
+	struct ipic *ipic = ipic_from_irq(irq);
+	unsigned int src = irq - ipic->irq_offset;
+	u32 temp;
+
+	temp = ipic_read(ipic->regs, ipic_info[src].mask);
+	temp |= (1 << (31 - ipic_info[src].bit));
+	ipic_write(ipic->regs, ipic_info[src].mask, temp);
+}
+
+static void ipic_disable_irq(unsigned int irq)
+{
+	struct ipic *ipic = ipic_from_irq(irq);
+	unsigned int src = irq - ipic->irq_offset;
+	u32 temp;
+
+	temp = ipic_read(ipic->regs, ipic_info[src].mask);
+	temp &= ~(1 << (31 - ipic_info[src].bit));
+	ipic_write(ipic->regs, ipic_info[src].mask, temp);
+}
+
+static void ipic_disable_irq_and_ack(unsigned int irq)
+{
+	struct ipic *ipic = ipic_from_irq(irq);
+	unsigned int src = irq - ipic->irq_offset;
+	u32 temp;
+
+	ipic_disable_irq(irq);
+
+	temp = ipic_read(ipic->regs, ipic_info[src].pend);
+	temp |= (1 << (31 - ipic_info[src].bit));
+	ipic_write(ipic->regs, ipic_info[src].pend, temp);
+}
+
+static void ipic_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		ipic_enable_irq(irq);
+}
+
+struct hw_interrupt_type ipic = {
+	.typename = " IPIC  ",
+	.enable = ipic_enable_irq,
+	.disable = ipic_disable_irq,
+	.ack = ipic_disable_irq_and_ack,
+	.end = ipic_end_irq,
+};
+
+void __init ipic_init(phys_addr_t phys_addr,
+		unsigned int flags,
+		unsigned int irq_offset,
+		unsigned char *senses,
+		unsigned int senses_count)
+{
+	u32 i, temp = 0;
+
+	primary_ipic = &p_ipic;
+	primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE);
+
+	primary_ipic->irq_offset = irq_offset;
+
+	ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0);
+
+	/* default priority scheme is grouped. If spread mode is required
+	 * configure SICFR accordingly */
+	if (flags & IPIC_SPREADMODE_GRP_A)
+		temp |= SICFR_IPSA;
+	if (flags & IPIC_SPREADMODE_GRP_D)
+		temp |= SICFR_IPSD;
+	if (flags & IPIC_SPREADMODE_MIX_A)
+		temp |= SICFR_MPSA;
+	if (flags & IPIC_SPREADMODE_MIX_B)
+		temp |= SICFR_MPSB;
+
+	ipic_write(primary_ipic->regs, IPIC_SICNR, temp);
+
+	/* handle MCP route */
+	temp = 0;
+	if (flags & IPIC_DISABLE_MCP_OUT)
+		temp = SERCR_MCPR;
+	ipic_write(primary_ipic->regs, IPIC_SERCR, temp);
+
+	/* handle routing of IRQ0 to MCP */
+	temp = ipic_read(primary_ipic->regs, IPIC_SEMSR);
+
+	if (flags & IPIC_IRQ0_MCP)
+		temp |= SEMSR_SIRQ0;
+	else
+		temp &= ~SEMSR_SIRQ0;
+
+	ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
+
+	for (i = 0 ; i < NR_IPIC_INTS ; i++) {
+		irq_desc[i+irq_offset].handler = &ipic;
+		irq_desc[i+irq_offset].status = IRQ_LEVEL;
+	}
+
+	temp = 0;
+	for (i = 0 ; i < senses_count ; i++) {
+		if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) {
+			temp |= 1 << (15 - i);
+			if (i != 0)
+				irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0;
+			else
+				irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0;
+		}
+	}
+	ipic_write(primary_ipic->regs, IPIC_SECNR, temp);
+
+	printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS,
+			senses_count, primary_ipic->regs);
+}
+
+int ipic_set_priority(unsigned int irq, unsigned int priority)
+{
+	struct ipic *ipic = ipic_from_irq(irq);
+	unsigned int src = irq - ipic->irq_offset;
+	u32 temp;
+
+	if (priority > 7)
+		return -EINVAL;
+	if (src > 127)
+		return -EINVAL;
+	if (ipic_info[src].prio == 0)
+		return -EINVAL;
+
+	temp = ipic_read(ipic->regs, ipic_info[src].prio);
+
+	if (priority < 4) {
+		temp &= ~(0x7 << (20 + (3 - priority) * 3));
+		temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
+	} else {
+		temp &= ~(0x7 << (4 + (7 - priority) * 3));
+		temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
+	}
+
+	ipic_write(ipic->regs, ipic_info[src].prio, temp);
+
+	return 0;
+}
+
+void ipic_set_highest_priority(unsigned int irq)
+{
+	struct ipic *ipic = ipic_from_irq(irq);
+	unsigned int src = irq - ipic->irq_offset;
+	u32 temp;
+
+	temp = ipic_read(ipic->regs, IPIC_SICFR);
+
+	/* clear and set HPI */
+	temp &= 0x7f000000;
+	temp |= (src & 0x7f) << 24;
+
+	ipic_write(ipic->regs, IPIC_SICFR, temp);
+}
+
+void ipic_set_default_priority(void)
+{
+	ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
+	ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
+	ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
+	ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
+	ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
+	ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
+	ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
+	ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
+
+	ipic_set_priority(MPC83xx_IRQ_UART1, 0);
+	ipic_set_priority(MPC83xx_IRQ_UART2, 1);
+	ipic_set_priority(MPC83xx_IRQ_SEC2, 2);
+	ipic_set_priority(MPC83xx_IRQ_IIC1, 5);
+	ipic_set_priority(MPC83xx_IRQ_IIC2, 6);
+	ipic_set_priority(MPC83xx_IRQ_SPI, 7);
+	ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0);
+	ipic_set_priority(MPC83xx_IRQ_PIT, 1);
+	ipic_set_priority(MPC83xx_IRQ_PCI1, 2);
+	ipic_set_priority(MPC83xx_IRQ_PCI2, 3);
+	ipic_set_priority(MPC83xx_IRQ_EXT0, 4);
+	ipic_set_priority(MPC83xx_IRQ_EXT1, 5);
+	ipic_set_priority(MPC83xx_IRQ_EXT2, 6);
+	ipic_set_priority(MPC83xx_IRQ_EXT3, 7);
+	ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0);
+	ipic_set_priority(MPC83xx_IRQ_MU, 1);
+	ipic_set_priority(MPC83xx_IRQ_SBA, 2);
+	ipic_set_priority(MPC83xx_IRQ_DMA, 3);
+	ipic_set_priority(MPC83xx_IRQ_EXT4, 4);
+	ipic_set_priority(MPC83xx_IRQ_EXT5, 5);
+	ipic_set_priority(MPC83xx_IRQ_EXT6, 6);
+	ipic_set_priority(MPC83xx_IRQ_EXT7, 7);
+}
+
+void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
+{
+	struct ipic *ipic = primary_ipic;
+	u32 temp;
+
+	temp = ipic_read(ipic->regs, IPIC_SERMR);
+	temp |= (1 << (31 - mcp_irq));
+	ipic_write(ipic->regs, IPIC_SERMR, temp);
+}
+
+void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
+{
+	struct ipic *ipic = primary_ipic;
+	u32 temp;
+
+	temp = ipic_read(ipic->regs, IPIC_SERMR);
+	temp &= (1 << (31 - mcp_irq));
+	ipic_write(ipic->regs, IPIC_SERMR, temp);
+}
+
+u32 ipic_get_mcp_status(void)
+{
+	return ipic_read(primary_ipic->regs, IPIC_SERMR);
+}
+
+void ipic_clear_mcp_status(u32 mask)
+{
+	ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
+}
+
+/* Return an interrupt vector or -1 if no interrupt is pending. */
+int ipic_get_irq(struct pt_regs *regs)
+{
+	int irq;
+
+	irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f;
+
+	if (irq == 0)    /* 0 --> no irq is pending */
+		irq = -1;
+
+	return irq;
+}
+
+static struct sysdev_class ipic_sysclass = {
+	set_kset_name("ipic"),
+};
+
+static struct sys_device device_ipic = {
+	.id		= 0,
+	.cls		= &ipic_sysclass,
+};
+
+static int __init init_ipic_sysfs(void)
+{
+	int rc;
+
+	if (!primary_ipic->regs)
+		return -ENODEV;
+	printk(KERN_DEBUG "Registering ipic with sysfs...\n");
+
+	rc = sysdev_class_register(&ipic_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering ipic sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&device_ipic);
+	if (rc) {
+		printk(KERN_ERR "Failed registering ipic sys device\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_ipic_sysfs);
diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ipic.h
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/kernel/ipic.h
+ *
+ * IPIC private definitions and structure.
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+#ifndef __IPIC_H__
+#define __IPIC_H__
+
+#include <asm/ipic.h>
+
+#define MPC83xx_IPIC_SIZE	(0x00100)
+
+/* System Global Interrupt Configuration Register */
+#define	SICFR_IPSA	0x00010000
+#define	SICFR_IPSD	0x00080000
+#define	SICFR_MPSA	0x00200000
+#define	SICFR_MPSB	0x00400000
+
+/* System External Interrupt Mask Register */
+#define	SEMSR_SIRQ0	0x00008000
+
+/* System Error Control Register */
+#define SERCR_MCPR	0x00000001
+
+struct ipic {
+	volatile u32 __iomem	*regs;
+	unsigned int		irq_offset;
+};
+
+struct ipic_info {
+	u8	pend;		/* pending register offset from base */
+	u8	mask;		/* mask register offset from base */
+	u8	prio;		/* priority register offset from base */
+	u8	force;		/* force register offset from base */
+	u8	bit;		/* register bit position (as per doc)
+				   bit mask = 1 << (31 - bit) */
+	u8	prio_mask;	/* priority mask value */
+};
+
+#endif /* __IPIC_H__ */
diff --git a/arch/ppc/syslib/m8260_pci.c b/arch/ppc/syslib/m8260_pci.c
deleted file mode 100644
--- a/arch/ppc/syslib/m8260_pci.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * (C) Copyright 2003
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * (C) Copyright 2004 Red Hat, Inc.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it 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/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/immap_cpm2.h>
-#include <asm/mpc8260.h>
-
-#include "m8260_pci.h"
-
-
-/* PCI bus configuration registers.
- */
-
-static void __init m8260_setup_pci(struct pci_controller *hose)
-{
-	volatile cpm2_map_t *immap = cpm2_immr;
-	unsigned long pocmr;
-	u16 tempShort;
-
-#ifndef CONFIG_ATC 	/* already done in U-Boot */
-	/* 
-	 * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]), 
-	 * and local bus for PCI (SIUMCR [LBPC]).
-	 */
-	immap->im_siu_conf.siu_82xx.sc_siumcr = 0x00640000;
-#endif
-
-	/* Make PCI lowest priority */
-	/* Each 4 bits is a device bus request  and the MS 4bits 
-	   is highest priority */
-	/* Bus               4bit value 
-	   ---               ----------
-	   CPM high          0b0000
-	   CPM middle        0b0001
-	   CPM low           0b0010
-	   PCI reguest       0b0011
-	   Reserved          0b0100
-	   Reserved          0b0101
-	   Internal Core     0b0110
-	   External Master 1 0b0111
-	   External Master 2 0b1000
-	   External Master 3 0b1001
-	   The rest are reserved */
-	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
-
-	/* Park bus on core while modifying PCI Bus accesses */
-	immap->im_siu_conf.siu_82xx.sc_ppc_acr = 0x6;
-
-	/* 
-	 * Set up master window that allows the CPU to access PCI space. This 
-	 * window is set up using the first SIU PCIBR registers.
-	 */
-	immap->im_memctl.memc_pcimsk0 = MPC826x_PCI_MASK;
-	immap->im_memctl.memc_pcibr0 =	MPC826x_PCI_BASE | PCIBR_ENABLE;
-
-	/* Disable machine check on no response or target abort */
-	immap->im_pci.pci_emr = cpu_to_le32(0x1fe7);
-	/* Release PCI RST (by default the PCI RST signal is held low)  */
-	immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
-
-	/* give it some time */
-	mdelay(1);
-
-	/* 
-	 * Set up master window that allows the CPU to access PCI Memory (prefetch) 
-	 * space. This window is set up using the first set of Outbound ATU registers.
-	 */
-	immap->im_pci.pci_potar0 = cpu_to_le32(MPC826x_PCI_LOWER_MEM >> 12);
-	immap->im_pci.pci_pobar0 = cpu_to_le32((MPC826x_PCI_LOWER_MEM - MPC826x_PCI_MEM_OFFSET) >> 12);
-	pocmr = ((MPC826x_PCI_UPPER_MEM - MPC826x_PCI_LOWER_MEM) >> 12) ^ 0xfffff;
-	immap->im_pci.pci_pocmr0 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PREFETCH_EN);
-
-	/* 
-	 * Set up master window that allows the CPU to access PCI Memory (non-prefetch) 
-	 * space. This window is set up using the second set of Outbound ATU registers.
-	 */
-	immap->im_pci.pci_potar1 = cpu_to_le32(MPC826x_PCI_LOWER_MMIO >> 12);
-	immap->im_pci.pci_pobar1 = cpu_to_le32((MPC826x_PCI_LOWER_MMIO - MPC826x_PCI_MMIO_OFFSET) >> 12);
-	pocmr = ((MPC826x_PCI_UPPER_MMIO - MPC826x_PCI_LOWER_MMIO) >> 12) ^ 0xfffff;
-	immap->im_pci.pci_pocmr1 = cpu_to_le32(pocmr | POCMR_ENABLE);
-
-	/* 
-	 * Set up master window that allows the CPU to access PCI IO space. This window
-	 * is set up using the third set of Outbound ATU registers.
-	 */
-	immap->im_pci.pci_potar2 = cpu_to_le32(MPC826x_PCI_IO_BASE >> 12);
-	immap->im_pci.pci_pobar2 = cpu_to_le32(MPC826x_PCI_LOWER_IO >> 12);
-	pocmr = ((MPC826x_PCI_UPPER_IO - MPC826x_PCI_LOWER_IO) >> 12) ^ 0xfffff;
-	immap->im_pci.pci_pocmr2 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PCI_IO);
-
-	/* 
-	 * Set up slave window that allows PCI masters to access MPC826x local memory. 
-	 * This window is set up using the first set of Inbound ATU registers
-	 */
-
-	immap->im_pci.pci_pitar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_LOCAL >> 12);
-	immap->im_pci.pci_pibar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_BUS >> 12);
-	pocmr = ((MPC826x_PCI_SLAVE_MEM_SIZE-1) >> 12) ^ 0xfffff;
-	immap->im_pci.pci_picmr0 = cpu_to_le32(pocmr | PICMR_ENABLE | PICMR_PREFETCH_EN);
-
-	/* See above for description - puts PCI request as highest priority */
-	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
-
-	/* Park the bus on the PCI */
-	immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
-
-	/* Host mode - specify the bridge as a host-PCI bridge */
-	early_write_config_word(hose, 0, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_HOST);
-
-	/* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
-	early_read_config_word(hose, 0, 0, PCI_COMMAND, &tempShort);
-	early_write_config_word(hose, 0, 0, PCI_COMMAND,
-				tempShort | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-}
-
-void __init m8260_find_bridges(void)
-{
-	extern int pci_assign_all_busses;
-	struct pci_controller * hose;
-
-	pci_assign_all_busses = 1;
-
-	hose = pcibios_alloc_controller();
-
-	if (!hose)
-		return;
-
-	ppc_md.pci_swizzle = common_swizzle;
-
-	hose->first_busno = 0;
-	hose->bus_offset = 0;
-	hose->last_busno = 0xff;
-
-	setup_m8260_indirect_pci(hose, 
-				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
-				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
-
-	m8260_setup_pci(hose);
-        hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET;
-
-        isa_io_base =
-                (unsigned long) ioremap(MPC826x_PCI_IO_BASE,
-                                        MPC826x_PCI_IO_SIZE);
-        hose->io_base_virt = (void *) isa_io_base;
- 
-        /* setup resources */
-        pci_init_resource(&hose->mem_resources[0],
-			  MPC826x_PCI_LOWER_MEM,
-			  MPC826x_PCI_UPPER_MEM,
-			  IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
-
-        pci_init_resource(&hose->mem_resources[1],
-			  MPC826x_PCI_LOWER_MMIO,
-			  MPC826x_PCI_UPPER_MMIO,
-			  IORESOURCE_MEM, "PCI memory");
-
-        pci_init_resource(&hose->io_resource,
-			  MPC826x_PCI_LOWER_IO,
-			  MPC826x_PCI_UPPER_IO,
-			  IORESOURCE_IO, "PCI I/O");
-}
diff --git a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h
deleted file mode 100644
--- a/arch/ppc/syslib/m8260_pci.h
+++ /dev/null
@@ -1,76 +0,0 @@
-
-#ifndef _PPC_KERNEL_M8260_PCI_H
-#define _PPC_KERNEL_M8260_PCI_H
-
-#include <asm/m8260_pci.h>
-
-/*
- *   Local->PCI map (from CPU)                             controlled by
- *   MPC826x master window
- *
- *   0x80000000 - 0xBFFFFFFF    Total CPU2PCI space        PCIBR0
- *                       
- *   0x80000000 - 0x9FFFFFFF    PCI Mem with prefetch      (Outbound ATU #1)
- *   0xA0000000 - 0xAFFFFFFF    PCI Mem w/o  prefetch      (Outbound ATU #2)
- *   0xB0000000 - 0xB0FFFFFF    32-bit PCI IO              (Outbound ATU #3)
- *                      
- *   PCI->Local map (from PCI)
- *   MPC826x slave window                                  controlled by
- *
- *   0x00000000 - 0x07FFFFFF    MPC826x local memory       (Inbound ATU #1)
- */
-
-/* 
- * Slave window that allows PCI masters to access MPC826x local memory. 
- * This window is set up using the first set of Inbound ATU registers
- */
-
-#ifndef MPC826x_PCI_SLAVE_MEM_LOCAL
-#define MPC826x_PCI_SLAVE_MEM_LOCAL	(((struct bd_info *)__res)->bi_memstart)
-#define MPC826x_PCI_SLAVE_MEM_BUS	(((struct bd_info *)__res)->bi_memstart)
-#define MPC826x_PCI_SLAVE_MEM_SIZE	(((struct bd_info *)__res)->bi_memsize)
-#endif
-
-/* 
- * This is the window that allows the CPU to access PCI address space.
- * It will be setup with the SIU PCIBR0 register. All three PCI master
- * windows, which allow the CPU to access PCI prefetch, non prefetch,
- * and IO space (see below), must all fit within this window. 
- */
-#ifndef MPC826x_PCI_BASE
-#define MPC826x_PCI_BASE	0x80000000
-#define MPC826x_PCI_MASK	0xc0000000
-#endif
-
-#ifndef MPC826x_PCI_LOWER_MEM
-#define MPC826x_PCI_LOWER_MEM  0x80000000
-#define MPC826x_PCI_UPPER_MEM  0x9fffffff
-#define MPC826x_PCI_MEM_OFFSET 0x00000000
-#endif
-
-#ifndef MPC826x_PCI_LOWER_MMIO
-#define MPC826x_PCI_LOWER_MMIO  0xa0000000
-#define MPC826x_PCI_UPPER_MMIO  0xafffffff
-#define MPC826x_PCI_MMIO_OFFSET 0x00000000
-#endif
-
-#ifndef MPC826x_PCI_LOWER_IO
-#define MPC826x_PCI_LOWER_IO   0x00000000
-#define MPC826x_PCI_UPPER_IO   0x00ffffff
-#define MPC826x_PCI_IO_BASE    0xb0000000
-#define MPC826x_PCI_IO_SIZE    0x01000000
-#endif
-
-#ifndef _IO_BASE
-#define _IO_BASE isa_io_base
-#endif
-
-#ifdef CONFIG_8260_PCI9
-struct pci_controller;
-extern void setup_m8260_indirect_pci(struct pci_controller* hose,
-				     u32 cfg_addr, u32 cfg_data);
-#else
-#define setup_m8260_indirect_pci setup_indirect_pci
-#endif
-
-#endif /* _PPC_KERNEL_M8260_PCI_H */
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
--- a/arch/ppc/syslib/m8260_pci_erratum9.c
+++ b/arch/ppc/syslib/m8260_pci_erratum9.c
@@ -31,7 +31,7 @@
 #include <asm/immap_cpm2.h>
 #include <asm/cpm2.h>
 
-#include "m8260_pci.h"
+#include "m82xx_pci.h"
 
 #ifdef CONFIG_8260_PCI9
 /*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
@@ -248,11 +248,11 @@ EXPORT_SYMBOL(idma_pci9_read_le);
 
 static inline int is_pci_mem(unsigned long addr)
 {
-	if (addr >= MPC826x_PCI_LOWER_MMIO &&
-	    addr <= MPC826x_PCI_UPPER_MMIO)
+	if (addr >= M82xx_PCI_LOWER_MMIO &&
+		addr <= M82xx_PCI_UPPER_MMIO)
 		return 1;
-	if (addr >= MPC826x_PCI_LOWER_MEM &&
-	    addr <= MPC826x_PCI_UPPER_MEM)
+	if (addr >= M82xx_PCI_LOWER_MEM &&
+		addr <= M82xx_PCI_UPPER_MEM)
 		return 1;
 	return 0;
 }
diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
--- a/arch/ppc/syslib/m8260_setup.c
+++ b/arch/ppc/syslib/m8260_setup.c
@@ -34,7 +34,8 @@
 unsigned char __res[sizeof(bd_t)];
 
 extern void cpm2_reset(void);
-extern void m8260_find_bridges(void);
+extern void pq2_find_bridges(void);
+extern void pq2pci_init_irq(void);
 extern void idma_pci9_init(void);
 
 /* Place-holder for board-specific init */
@@ -56,7 +57,7 @@ m8260_setup_arch(void)
 	idma_pci9_init();
 #endif
 #ifdef CONFIG_PCI_8260
-	m8260_find_bridges();
+	pq2_find_bridges();
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start)
@@ -167,18 +168,18 @@ m8260_show_cpuinfo(struct seq_file *m)
 static void __init
 m8260_init_IRQ(void)
 {
-	int i;
-
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &cpm2_pic;
+	cpm2_init_IRQ();
 
 	/* Initialize the default interrupt mapping priorities,
 	 * in case the boot rom changed something on us.
 	 */
-	cpm2_immr->im_intctl.ic_sicr = 0;
 	cpm2_immr->im_intctl.ic_siprr = 0x05309770;
-	cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
-	cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
+
+#if defined(CONFIG_PCI) && (defined(CONFIG_ADS8272) || defined(CONFIG_PQ2FADS))
+ 	/* Initialize stuff for the 82xx CPLD IC and install demux  */
+ 	pq2pci_init_irq();
+#endif
+
 }
 
 /*
diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/m82xx_pci.c
@@ -0,0 +1,383 @@
+/*
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2004 Red Hat, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it 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/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm2.h>
+
+#include "m82xx_pci.h"
+
+/*
+ * Interrupt routing
+ */
+
+static inline int
+pq2pci_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
+	 */
+	{
+		{ PIRQA, PIRQB, PIRQC, PIRQD },	/* IDSEL 22 - PCI slot 0 */
+		{ PIRQD, PIRQA, PIRQB, PIRQC },	/* IDSEL 23 - PCI slot 1 */
+		{ PIRQC, PIRQD, PIRQA, PIRQB },	/* IDSEL 24 - PCI slot 2 */
+	};
+
+	const long min_idsel = 22, max_idsel = 24, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void
+pq2pci_mask_irq(unsigned int irq)
+{
+	int bit = irq - NR_CPM_INTS;
+
+	*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));
+	return;
+}
+
+static void
+pq2pci_unmask_irq(unsigned int irq)
+{
+	int bit = irq - NR_CPM_INTS;
+
+	*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));
+	return;
+}
+
+static void
+pq2pci_mask_and_ack(unsigned int irq)
+{
+	int bit = irq - NR_CPM_INTS;
+
+	*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));
+	return;
+}
+
+static void
+pq2pci_end_irq(unsigned int irq)
+{
+	int bit = irq - NR_CPM_INTS;
+
+	*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));
+	return;
+}
+
+struct hw_interrupt_type pq2pci_ic = {
+	"PQ2 PCI",
+	NULL,
+	NULL,
+	pq2pci_unmask_irq,
+	pq2pci_mask_irq,
+	pq2pci_mask_and_ack,
+	pq2pci_end_irq,
+	0
+};
+
+static irqreturn_t
+pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long stat, mask, pend;
+	int bit;
+
+	for(;;) {
+		stat = *(volatile unsigned long *) PCI_INT_STAT_REG;
+		mask = *(volatile unsigned long *) PCI_INT_MASK_REG;
+		pend = stat & ~mask & 0xf0000000;
+		if (!pend)
+			break;
+		for (bit = 0; pend != 0; ++bit, pend <<= 1) {
+			if (pend & 0x80000000)
+				__do_IRQ(NR_CPM_INTS + bit, regs);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction pq2pci_irqaction = {
+	.handler = pq2pci_irq_demux,
+	.flags 	 = SA_INTERRUPT,
+	.mask	 = CPU_MASK_NONE,
+	.name	 = "PQ2 PCI cascade",
+};
+
+
+void
+pq2pci_init_irq(void)
+{
+	int irq;
+	volatile cpm2_map_t *immap = cpm2_immr;
+#if defined CONFIG_ADS8272
+	/* configure chip select for PCI interrupt controller */
+	immap->im_memctl.memc_br3 = PCI_INT_STAT_REG | 0x00001801;
+	immap->im_memctl.memc_or3 = 0xffff8010;
+#elif defined CONFIG_PQ2FADS
+	immap->im_memctl.memc_br8 = PCI_INT_STAT_REG | 0x00001801;
+	immap->im_memctl.memc_or8 = 0xffff8010;
+#endif
+	for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)
+		irq_desc[irq].handler = &pq2pci_ic;
+
+	/* make PCI IRQ level sensitive */
+	immap->im_intctl.ic_siexr &=
+		~(1 << (14 - (PCI_INT_TO_SIU - SIU_INT_IRQ1)));
+
+	/* mask all PCI interrupts */
+	*(volatile unsigned long *) PCI_INT_MASK_REG |= 0xfff00000;
+
+	/* install the demultiplexer for the PCI cascade interrupt */
+	setup_irq(PCI_INT_TO_SIU, &pq2pci_irqaction);
+	return;
+}
+
+static int
+pq2pci_exclude_device(u_char bus, u_char devfn)
+{
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* PCI bus configuration registers.
+ */
+static void
+pq2ads_setup_pci(struct pci_controller *hose)
+{
+	__u32 val;
+	volatile cpm2_map_t *immap = cpm2_immr;
+	bd_t* binfo = (bd_t*) __res;
+	u32 sccr = immap->im_clkrst.car_sccr;
+	uint pci_div,freq,time;
+		/* PCI int lowest prio */
+	/* Each 4 bits is a device bus request	and the MS 4bits
+	 is highest priority */
+	/* Bus                4bit value
+	   ---                ----------
+	   CPM high      	0b0000
+	   CPM middle           0b0001
+	   CPM low       	0b0010
+	   PCI reguest          0b0011
+	   Reserved      	0b0100
+	   Reserved      	0b0101
+	   Internal Core     	0b0110
+	   External Master 1 	0b0111
+	   External Master 2 	0b1000
+	   External Master 3 	0b1001
+	   The rest are reserved
+	 */
+	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
+	/* park bus on core */
+	immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_CORE;
+	/*
+	 * Set up master windows that allow the CPU to access PCI space. These
+	 * windows are set up using the two SIU PCIBR registers.
+	 */
+
+	immap->im_memctl.memc_pcimsk0 = M82xx_PCI_PRIM_WND_SIZE;
+	immap->im_memctl.memc_pcibr0  = M82xx_PCI_PRIM_WND_BASE | PCIBR_ENABLE;
+
+#ifdef M82xx_PCI_SEC_WND_SIZE
+	immap->im_memctl.memc_pcimsk1 = M82xx_PCI_SEC_WND_SIZE;
+	immap->im_memctl.memc_pcibr1  = M82xx_PCI_SEC_WND_BASE | PCIBR_ENABLE;
+#endif
+
+#if defined CONFIG_ADS8272
+	immap->im_siu_conf.siu_82xx.sc_siumcr =
+		(immap->im_siu_conf.siu_82xx.sc_siumcr &
+		~(SIUMCR_BBD | SIUMCR_ESE | SIUMCR_PBSE |
+		SIUMCR_CDIS | SIUMCR_DPPC11 | SIUMCR_L2CPC11 |
+		SIUMCR_LBPC11 | SIUMCR_APPC11 |
+		SIUMCR_CS10PC11 | SIUMCR_BCTLC11 | SIUMCR_MMR11)) |
+		SIUMCR_DPPC11 | SIUMCR_L2CPC01 | SIUMCR_LBPC00 |
+		SIUMCR_APPC10 | SIUMCR_CS10PC00 |
+		SIUMCR_BCTLC00 | SIUMCR_MMR11 ;
+
+#elif defined CONFIG_PQ2FADS
+	/*
+	 * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
+	 * and local bus for PCI (SIUMCR [LBPC]).
+	 */
+	immap->im_siu_conf.siu_82xx.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
+				~(SIUMCR_L2PC11 | SIUMCR_LBPC11 | SIUMCR_CS10PC11 | SIUMCR_APPC11) |
+				SIUMCR_BBD | SIUMCR_LBPC01 | SIUMCR_DPPC11 | SIUMCR_APPC10;
+#endif
+	/* Enable PCI  */
+	immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
+
+	pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) *
+			( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1);
+	freq = (uint)((2*binfo->bi_cpmfreq)/(pci_div));
+	time = (int)666666/freq;
+	/* due to PCI Local Bus spec, some devices needs to wait such a long
+	time after RST 	deassertion. More specifically, 0.508s for 66MHz & twice more for 33 */
+	printk("%s: The PCI bus is %d Mhz.\nWaiting %s after deasserting RST...\n",__FILE__,freq,
+	(time==1) ? "0.5 seconds":"1 second" );
+
+	{
+		int i;
+		for(i=0;i<(500*time);i++)
+			udelay(1000);
+	}
+
+	/* setup ATU registers */
+	immap->im_pci.pci_pocmr0 = cpu_to_le32(POCMR_ENABLE | POCMR_PCI_IO |
+				((~(M82xx_PCI_IO_SIZE - 1U)) >> POTA_ADDR_SHIFT));
+	immap->im_pci.pci_potar0 = cpu_to_le32(M82xx_PCI_LOWER_IO >> POTA_ADDR_SHIFT);
+	immap->im_pci.pci_pobar0 = cpu_to_le32(M82xx_PCI_IO_BASE >> POTA_ADDR_SHIFT);
+
+	/* Set-up non-prefetchable window */
+	immap->im_pci.pci_pocmr1 = cpu_to_le32(POCMR_ENABLE | ((~(M82xx_PCI_MMIO_SIZE-1U)) >> POTA_ADDR_SHIFT));
+	immap->im_pci.pci_potar1 = cpu_to_le32(M82xx_PCI_LOWER_MMIO >> POTA_ADDR_SHIFT);
+	immap->im_pci.pci_pobar1 = cpu_to_le32((M82xx_PCI_LOWER_MMIO - M82xx_PCI_MMIO_OFFSET) >> POTA_ADDR_SHIFT);
+
+	/* Set-up prefetchable window */
+	immap->im_pci.pci_pocmr2 = cpu_to_le32(POCMR_ENABLE |POCMR_PREFETCH_EN |
+		(~(M82xx_PCI_MEM_SIZE-1U) >> POTA_ADDR_SHIFT));
+	immap->im_pci.pci_potar2 = cpu_to_le32(M82xx_PCI_LOWER_MEM >> POTA_ADDR_SHIFT);
+	immap->im_pci.pci_pobar2 = cpu_to_le32((M82xx_PCI_LOWER_MEM - M82xx_PCI_MEM_OFFSET) >> POTA_ADDR_SHIFT);
+
+ 	/* Inbound transactions from PCI memory space */
+	immap->im_pci.pci_picmr0 = cpu_to_le32(PICMR_ENABLE | PICMR_PREFETCH_EN |
+					((~(M82xx_PCI_SLAVE_MEM_SIZE-1U)) >> PITA_ADDR_SHIFT));
+	immap->im_pci.pci_pibar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_BUS  >> PITA_ADDR_SHIFT);
+	immap->im_pci.pci_pitar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_LOCAL>> PITA_ADDR_SHIFT);
+
+#if defined CONFIG_ADS8272
+	/* PCI int highest prio */
+	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x01236745;
+#elif defined CONFIG_PQ2FADS
+	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
+#endif
+	/* park bus on PCI */
+	immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
+
+	/* Enable bus mastering and inbound memory transactions */
+	early_read_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, &val);
+	val &= 0xffff0000;
+	val |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER;
+	early_write_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, val);
+
+}
+
+void __init pq2_find_bridges(void)
+{
+	extern int pci_assign_all_busses;
+	struct pci_controller * hose;
+	int host_bridge;
+
+	pci_assign_all_busses = 1;
+
+	hose = pcibios_alloc_controller();
+
+	if (!hose)
+		return;
+
+	ppc_md.pci_swizzle = common_swizzle;
+
+	hose->first_busno = 0;
+	hose->bus_offset = 0;
+	hose->last_busno = 0xff;
+
+#ifdef CONFIG_ADS8272
+	hose->set_cfg_type = 1;
+#endif
+
+	setup_m8260_indirect_pci(hose,
+				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
+				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
+
+	/* Make sure it is a supported bridge */
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				PCI_VENDOR_ID,
+				&host_bridge);
+	switch (host_bridge) {
+		case PCI_DEVICE_ID_MPC8265:
+			break;
+		case PCI_DEVICE_ID_MPC8272:
+			break;
+		default:
+			printk("Attempting to use unrecognized host bridge ID"
+				" 0x%08x.\n", host_bridge);
+			break;
+	}
+
+	pq2ads_setup_pci(hose);
+
+	hose->io_space.start =	M82xx_PCI_LOWER_IO;
+	hose->io_space.end = M82xx_PCI_UPPER_IO;
+	hose->mem_space.start = M82xx_PCI_LOWER_MEM;
+	hose->mem_space.end = M82xx_PCI_UPPER_MMIO;
+	hose->pci_mem_offset = M82xx_PCI_MEM_OFFSET;
+
+	isa_io_base =
+	(unsigned long) ioremap(M82xx_PCI_IO_BASE,
+					M82xx_PCI_IO_SIZE);
+	hose->io_base_virt = (void *) isa_io_base;
+
+	/* setup resources */
+	pci_init_resource(&hose->mem_resources[0],
+			M82xx_PCI_LOWER_MEM,
+			M82xx_PCI_UPPER_MEM,
+			IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
+
+	pci_init_resource(&hose->mem_resources[1],
+			M82xx_PCI_LOWER_MMIO,
+			M82xx_PCI_UPPER_MMIO,
+			IORESOURCE_MEM, "PCI memory");
+
+	pci_init_resource(&hose->io_resource,
+			M82xx_PCI_LOWER_IO,
+			M82xx_PCI_UPPER_IO,
+			IORESOURCE_IO | 1, "PCI I/O");
+
+	ppc_md.pci_exclude_device = pq2pci_exclude_device;
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_map_irq = pq2pci_map_irq;
+	ppc_md.pcibios_fixup = NULL;
+	ppc_md.pcibios_fixup_bus = NULL;
+
+}
diff --git a/arch/ppc/syslib/m82xx_pci.h b/arch/ppc/syslib/m82xx_pci.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/m82xx_pci.h
@@ -0,0 +1,92 @@
+
+#ifndef _PPC_KERNEL_M82XX_PCI_H
+#define _PPC_KERNEL_M82XX_PCI_H
+
+#include <asm/m8260_pci.h>
+/*
+ *   Local->PCI map (from CPU)                             controlled by
+ *   MPC826x master window
+ *
+ *   0xF6000000 - 0xF7FFFFFF    IO space
+ *   0x80000000 - 0xBFFFFFFF    CPU2PCI memory space       PCIBR0
+ *
+ *   0x80000000 - 0x9FFFFFFF    PCI Mem with prefetch      (Outbound ATU #1)
+ *   0xA0000000 - 0xBFFFFFFF    PCI Mem w/o  prefetch      (Outbound ATU #2)
+ *   0xF6000000 - 0xF7FFFFFF    32-bit PCI IO              (Outbound ATU #3)
+ *
+ *   PCI->Local map (from PCI)
+ *   MPC826x slave window                                  controlled by
+ *
+ *   0x00000000 - 0x07FFFFFF    MPC826x local memory       (Inbound ATU #1)
+ */
+
+/*
+ * Slave window that allows PCI masters to access MPC826x local memory.
+ * This window is set up using the first set of Inbound ATU registers
+ */
+
+#ifndef M82xx_PCI_SLAVE_MEM_LOCAL
+#define M82xx_PCI_SLAVE_MEM_LOCAL	(((struct bd_info *)__res)->bi_memstart)
+#define M82xx_PCI_SLAVE_MEM_BUS		(((struct bd_info *)__res)->bi_memstart)
+#define M82xx_PCI_SLAVE_MEM_SIZE	(((struct bd_info *)__res)->bi_memsize)
+#endif
+
+/*
+ * This is the window that allows the CPU to access PCI address space.
+ * It will be setup with the SIU PCIBR0 register. All three PCI master
+ * windows, which allow the CPU to access PCI prefetch, non prefetch,
+ * and IO space (see below), must all fit within this window.
+ */
+
+#ifndef M82xx_PCI_LOWER_MEM
+#define M82xx_PCI_LOWER_MEM		0x80000000
+#define M82xx_PCI_UPPER_MEM		0x9fffffff
+#define M82xx_PCI_MEM_OFFSET		0x00000000
+#define M82xx_PCI_MEM_SIZE		0x20000000
+#endif
+
+#ifndef M82xx_PCI_LOWER_MMIO
+#define M82xx_PCI_LOWER_MMIO		0xa0000000
+#define M82xx_PCI_UPPER_MMIO		0xafffffff
+#define M82xx_PCI_MMIO_OFFSET		0x00000000
+#define M82xx_PCI_MMIO_SIZE		0x20000000
+#endif
+
+#ifndef M82xx_PCI_LOWER_IO
+#define M82xx_PCI_LOWER_IO		0x00000000
+#define M82xx_PCI_UPPER_IO		0x01ffffff
+#define M82xx_PCI_IO_BASE		0xf6000000
+#define M82xx_PCI_IO_SIZE		0x02000000
+#endif
+
+#ifndef M82xx_PCI_PRIM_WND_SIZE
+#define M82xx_PCI_PRIM_WND_SIZE 	~(M82xx_PCI_IO_SIZE - 1U)
+#define M82xx_PCI_PRIM_WND_BASE		(M82xx_PCI_IO_BASE)
+#endif
+
+#ifndef M82xx_PCI_SEC_WND_SIZE
+#define M82xx_PCI_SEC_WND_SIZE 		~(M82xx_PCI_MEM_SIZE + M82xx_PCI_MMIO_SIZE - 1U)
+#define M82xx_PCI_SEC_WND_BASE 		(M82xx_PCI_LOWER_MEM)
+#endif
+
+#ifndef POTA_ADDR_SHIFT
+#define POTA_ADDR_SHIFT		12
+#endif
+
+#ifndef PITA_ADDR_SHIFT
+#define PITA_ADDR_SHIFT		12
+#endif
+
+#ifndef _IO_BASE
+#define _IO_BASE isa_io_base
+#endif
+
+#ifdef CONFIG_8260_PCI9
+struct pci_controller;
+extern void setup_m8260_indirect_pci(struct pci_controller* hose,
+					u32 cfg_addr, u32 cfg_data);
+#else
+#define setup_m8260_indirect_pci setup_indirect_pci
+#endif
+
+#endif /* _PPC_KERNEL_M8260_PCI_H */
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -11,6 +11,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/8xx_immap.h>
@@ -18,6 +19,12 @@
 
 static int wdt_timeout;
 
+static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
+static struct irqaction m8xx_wdt_irqaction = {
+	.handler = m8xx_wdt_interrupt,
+	.name = "watchdog",
+};
+
 void m8xx_wdt_reset(void)
 {
 	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
@@ -84,8 +91,8 @@ void __init m8xx_wdt_handler_install(bd_
 	imap->im_sit.sit_piscr =
 	    (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE;
 
-	if (request_irq(PIT_INTERRUPT, m8xx_wdt_interrupt, 0, "watchdog", NULL))
-		panic("m8xx_wdt: could not allocate watchdog irq!");
+	if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction))
+		panic("m8xx_wdt: error setting up the watchdog irq!");
 
 	printk(KERN_NOTICE
 	       "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_devices.c
@@ -0,0 +1,318 @@
+/*
+ * arch/ppc/syslib/mpc52xx_devices.c
+ *
+ * Freescale MPC52xx device descriptions
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/fsl_devices.h>
+#include <linux/resource.h>
+#include <asm/mpc52xx.h>
+#include <asm/ppc_sys.h>
+
+
+static u64 mpc52xx_dma_mask = 0xffffffffULL;
+
+static struct fsl_i2c_platform_data mpc52xx_fsl_i2c_pdata = {
+	.device_flags = FSL_I2C_DEV_CLOCK_5200,
+};
+
+
+/* We use relative offsets for IORESOURCE_MEM to be independent from the
+ * MBAR location at compile time
+ */
+
+/* TODO Add the BestComm initiator channel to the device definitions,
+   possibly using IORESOURCE_DMA. But that's when BestComm is ready ... */
+
+struct platform_device ppc_sys_platform_devices[] = {
+	[MPC52xx_MSCAN1] = {
+		.name		= "mpc52xx-mscan",
+		.id		= 0,
+		.num_resources	= 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x0900,
+				.end	= 0x097f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_MSCAN1_IRQ,
+				.end	= MPC52xx_MSCAN1_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_MSCAN2] = {
+		.name		= "mpc52xx-mscan",
+		.id		= 1,
+		.num_resources	= 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x0980,
+				.end	= 0x09ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_MSCAN2_IRQ,
+				.end	= MPC52xx_MSCAN2_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_SPI] = {
+		.name		= "mpc52xx-spi",
+		.id		= -1,
+		.num_resources	= 3,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x0f00,
+				.end	= 0x0f1f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "modf",
+				.start	= MPC52xx_SPI_MODF_IRQ,
+				.end	= MPC52xx_SPI_MODF_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "spif",
+				.start	= MPC52xx_SPI_SPIF_IRQ,
+				.end	= MPC52xx_SPI_SPIF_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_USB] = {
+		.name		= "ppc-soc-ohci",
+		.id		= -1,
+		.num_resources	= 2,
+		.dev.dma_mask	= &mpc52xx_dma_mask,
+		.dev.coherent_dma_mask = 0xffffffffULL,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x1000,
+				.end	= 0x10ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_USB_IRQ,
+				.end	= MPC52xx_USB_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_BDLC] = {
+		.name		= "mpc52xx-bdlc",
+		.id		= -1,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x1300,
+				.end	= 0x130f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_BDLC_IRQ,
+				.end	= MPC52xx_BDLC_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC1] = {
+		.name		= "mpc52xx-psc",
+		.id		= 0,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2000,
+				.end	= 0x209f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC1_IRQ,
+				.end	= MPC52xx_PSC1_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC2] = {
+		.name		= "mpc52xx-psc",
+		.id		= 1,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2200,
+				.end	= 0x229f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC2_IRQ,
+				.end	= MPC52xx_PSC2_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC3] = {
+		.name		= "mpc52xx-psc",
+		.id		= 2,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2400,
+				.end	= 0x249f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC3_IRQ,
+				.end	= MPC52xx_PSC3_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC4] = {
+		.name		= "mpc52xx-psc",
+		.id		= 3,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2600,
+				.end	= 0x269f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC4_IRQ,
+				.end	= MPC52xx_PSC4_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC5] = {
+		.name		= "mpc52xx-psc",
+		.id		= 4,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2800,
+				.end	= 0x289f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC5_IRQ,
+				.end	= MPC52xx_PSC5_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_PSC6] = {
+		.name		= "mpc52xx-psc",
+		.id		= 5,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x2c00,
+				.end	= 0x2c9f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_PSC6_IRQ,
+				.end	= MPC52xx_PSC6_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_FEC] = {
+		.name		= "mpc52xx-fec",
+		.id		= -1,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x3000,
+				.end	= 0x33ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_FEC_IRQ,
+				.end	= MPC52xx_FEC_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_ATA] = {
+		.name		= "mpc52xx-ata",
+		.id		= -1,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x3a00,
+				.end	= 0x3aff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_ATA_IRQ,
+				.end	= MPC52xx_ATA_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_I2C1] = {
+		.name		= "fsl-i2c",
+		.id		= 0,
+		.dev.platform_data = &mpc52xx_fsl_i2c_pdata,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x3d00,
+				.end	= 0x3d1f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_I2C1_IRQ,
+				.end	= MPC52xx_I2C1_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC52xx_I2C2] = {
+		.name		= "fsl-i2c",
+		.id		= 1,
+		.dev.platform_data = &mpc52xx_fsl_i2c_pdata,
+		.num_resources	= 2,
+		.resource	= (struct resource[]) {
+			{
+				.start	= 0x3d40,
+				.end	= 0x3d5f,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC52xx_I2C2_IRQ,
+				.end	= MPC52xx_I2C2_IRQ,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+};
+
+
+static int __init mach_mpc52xx_fixup(struct platform_device *pdev)
+{
+	ppc_sys_fixup_mem_resource(pdev, MPC52xx_MBAR);
+	return 0;
+}
+
+static int __init mach_mpc52xx_init(void)
+{
+	ppc_sys_device_fixup = mach_mpc52xx_fixup;
+	return 0;
+}
+
+postcore_initcall(mach_mpc52xx_init);
diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_pci.c
@@ -0,0 +1,233 @@
+/*
+ * arch/ppc/syslib/mpc52xx_pci.c
+ *
+ * PCI code for the Freescale MPC52xx embedded CPU.
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+
+#include <asm/pci.h>
+
+#include <asm/mpc52xx.h>
+#include "mpc52xx_pci.h"
+
+#include <asm/delay.h>
+
+
+static int
+mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+				int offset, int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	u32 value;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	out_be32(hose->cfg_addr,
+		(1 << 31) |
+		((bus->number - hose->bus_offset) << 16) |
+		(devfn << 8) |
+		(offset & 0xfc));
+
+	value = in_le32(hose->cfg_data);
+
+	if (len != 4) {
+		value >>= ((offset & 0x3) << 3);
+		value &= 0xffffffff >> (32 - (len << 3));
+	}
+
+	*val = value;
+
+	out_be32(hose->cfg_addr, 0);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+				int offset, int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	u32 value, mask;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	out_be32(hose->cfg_addr,
+		(1 << 31) |
+		((bus->number - hose->bus_offset) << 16) |
+		(devfn << 8) |
+		(offset & 0xfc));
+
+	if (len != 4) {
+		value = in_le32(hose->cfg_data);
+
+		offset = (offset & 0x3) << 3;
+		mask = (0xffffffff >> (32 - (len << 3)));
+		mask <<= offset;
+
+		value &= ~mask;
+		val = value | ((val << offset) & mask);
+	}
+
+	out_le32(hose->cfg_data, val);
+
+	out_be32(hose->cfg_addr, 0);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mpc52xx_pci_ops = {
+	.read  = mpc52xx_pci_read_config,
+	.write = mpc52xx_pci_write_config
+};
+
+
+static void __init
+mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
+{
+
+	/* Setup control regs */
+		/* Nothing to do afaik */
+
+	/* Setup windows */
+	out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
+		MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
+		MPC52xx_PCI_MEM_START,
+		MPC52xx_PCI_MEM_SIZE ));
+
+	out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
+		MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
+		MPC52xx_PCI_MMIO_START,
+		MPC52xx_PCI_MMIO_SIZE ));
+
+	out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
+		MPC52xx_PCI_IO_BASE,
+		MPC52xx_PCI_IO_START,
+		MPC52xx_PCI_IO_SIZE ));
+
+	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
+		( MPC52xx_PCI_IWCR_ENABLE |		/* iw0btar */
+		  MPC52xx_PCI_IWCR_READ_MULTI |
+		  MPC52xx_PCI_IWCR_MEM ),
+		( MPC52xx_PCI_IWCR_ENABLE |		/* iw1btar */
+		  MPC52xx_PCI_IWCR_READ |
+		  MPC52xx_PCI_IWCR_MEM ),
+		( MPC52xx_PCI_IWCR_ENABLE |		/* iw2btar */
+		  MPC52xx_PCI_IWCR_IO )
+	));
+
+
+	out_be32(&pci_regs->tbatr0,
+		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
+	out_be32(&pci_regs->tbatr1,
+		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
+
+	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
+
+	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
+	/* Not necessary and can be a bad thing if for example the bootloader
+	   is displaying a splash screen or ... Just left here for
+	   documentation purpose if anyone need it */
+#if 0
+	u32 tmp;
+	tmp = in_be32(&pci_regs->gscr);
+	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
+	udelay(50);
+	out_be32(&pci_regs->gscr, tmp);
+#endif
+}
+
+static void __init
+mpc52xx_pci_fixup_resources(struct pci_dev *dev)
+{
+	int i;
+
+	/* We don't rely on boot loader for PCI and resets all
+	   devices */
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		struct resource *res = &dev->resource[i];
+		if (res->end > res->start) {	/* Only valid resources */
+			res->end -= res->start;
+			res->start = 0;
+			res->flags |= IORESOURCE_UNSET;
+		}
+	}
+
+	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
+	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
+	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+	     (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200) ) {
+		struct resource *res = &dev->resource[1];
+		res->start = res->end = res->flags = 0;
+	}
+}
+
+void __init
+mpc52xx_find_bridges(void)
+{
+	struct mpc52xx_pci __iomem *pci_regs;
+	struct pci_controller *hose;
+
+	pci_assign_all_busses = 1;
+
+	pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
+	if (!pci_regs)
+		return;
+
+	hose = pcibios_alloc_controller();
+	if (!hose) {
+		iounmap(pci_regs);
+		return;
+	}
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+	hose->bus_offset = 0;
+	hose->ops = &mpc52xx_pci_ops;
+
+	mpc52xx_pci_setup(pci_regs);
+
+	hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
+
+	hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
+	isa_io_base = (unsigned long) hose->io_base_virt;
+
+	hose->cfg_addr = &pci_regs->car;
+	hose->cfg_data = hose->io_base_virt;
+
+	/* Setup resources */
+	pci_init_resource(&hose->mem_resources[0],
+			MPC52xx_PCI_MEM_START,
+			MPC52xx_PCI_MEM_STOP,
+			IORESOURCE_MEM|IORESOURCE_PREFETCH,
+			"PCI prefetchable memory");
+
+	pci_init_resource(&hose->mem_resources[1],
+			MPC52xx_PCI_MMIO_START,
+			MPC52xx_PCI_MMIO_STOP,
+			IORESOURCE_MEM,
+			"PCI memory");
+
+	pci_init_resource(&hose->io_resource,
+			MPC52xx_PCI_IO_START,
+			MPC52xx_PCI_IO_STOP,
+			IORESOURCE_IO,
+			"PCI I/O");
+
+}
diff --git a/arch/ppc/syslib/mpc52xx_pci.h b/arch/ppc/syslib/mpc52xx_pci.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_pci.h
@@ -0,0 +1,139 @@
+/*
+ * arch/ppc/syslib/mpc52xx_pci.h
+ *
+ * PCI Include file the Freescale MPC52xx embedded cpu chips
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Inspired from code written by Dale Farnsworth <dfarnsworth@mvista.com>
+ * for the 2.4 kernel.
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __SYSLIB_MPC52xx_PCI_H__
+#define __SYSLIB_MPC52xx_PCI_H__
+
+/* ======================================================================== */
+/* PCI windows config                                                       */
+/* ======================================================================== */
+
+/*
+ * Master windows : MPC52xx -> PCI
+ *
+ *  0x80000000 -> 0x9FFFFFFF       PCI Mem prefetchable          IW0BTAR
+ *  0xA0000000 -> 0xAFFFFFFF       PCI Mem                       IW1BTAR
+ *  0xB0000000 -> 0xB0FFFFFF       PCI IO                        IW2BTAR
+ *
+ * Slave windows  : PCI -> MPC52xx
+ *
+ *  0xF0000000 -> 0xF003FFFF       MPC52xx MBAR                  TBATR0
+ *  0x00000000 -> 0x3FFFFFFF       MPC52xx local memory          TBATR1
+ */
+
+#define MPC52xx_PCI_MEM_OFFSET 	0x00000000	/* Offset for MEM MMIO */
+
+#define MPC52xx_PCI_MEM_START	0x80000000
+#define MPC52xx_PCI_MEM_SIZE	0x20000000
+#define MPC52xx_PCI_MEM_STOP	(MPC52xx_PCI_MEM_START+MPC52xx_PCI_MEM_SIZE-1)
+
+#define MPC52xx_PCI_MMIO_START	0xa0000000
+#define MPC52xx_PCI_MMIO_SIZE	0x10000000
+#define MPC52xx_PCI_MMIO_STOP	(MPC52xx_PCI_MMIO_START+MPC52xx_PCI_MMIO_SIZE-1)
+
+#define MPC52xx_PCI_IO_BASE	0xb0000000
+
+#define MPC52xx_PCI_IO_START	0x00000000
+#define MPC52xx_PCI_IO_SIZE	0x01000000
+#define MPC52xx_PCI_IO_STOP	(MPC52xx_PCI_IO_START+MPC52xx_PCI_IO_SIZE-1)
+
+
+#define MPC52xx_PCI_TARGET_IO	MPC52xx_MBAR
+#define MPC52xx_PCI_TARGET_MEM	0x00000000
+
+
+/* ======================================================================== */
+/* Structures mapping & Defines for PCI Unit                                */
+/* ======================================================================== */
+
+#define MPC52xx_PCI_GSCR_BM		0x40000000
+#define MPC52xx_PCI_GSCR_PE		0x20000000
+#define MPC52xx_PCI_GSCR_SE		0x10000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
+#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
+#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
+#define MPC52xx_PCI_GSCR_BME		0x00004000
+#define MPC52xx_PCI_GSCR_PEE		0x00002000
+#define MPC52xx_PCI_GSCR_SEE		0x00001000
+#define MPC52xx_PCI_GSCR_PR		0x00000001
+
+
+#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
+		( ( (proc_ad) & 0xff000000 )			| \
+		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
+		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
+
+#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
+						 ((win1) << 16) | \
+						 ((win2) <<  8))
+
+#define MPC52xx_PCI_IWCR_DISABLE	0x0
+#define MPC52xx_PCI_IWCR_ENABLE		0x1
+#define MPC52xx_PCI_IWCR_READ		0x0
+#define MPC52xx_PCI_IWCR_READ_LINE	0x2
+#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
+#define MPC52xx_PCI_IWCR_MEM		0x0
+#define MPC52xx_PCI_IWCR_IO		0x8
+
+#define MPC52xx_PCI_TCR_P		0x01000000
+#define MPC52xx_PCI_TCR_LD		0x00010000
+
+#define MPC52xx_PCI_TBATR_DISABLE	0x0
+#define MPC52xx_PCI_TBATR_ENABLE	0x1
+
+
+#ifndef __ASSEMBLY__
+
+struct mpc52xx_pci {
+	u32	idr;		/* PCI + 0x00 */
+	u32	scr;		/* PCI + 0x04 */
+	u32	ccrir;		/* PCI + 0x08 */
+	u32	cr1;		/* PCI + 0x0C */
+	u32	bar0;		/* PCI + 0x10 */
+	u32	bar1;		/* PCI + 0x14 */
+	u8	reserved1[16];	/* PCI + 0x18 */
+	u32	ccpr;		/* PCI + 0x28 */
+	u32	sid;		/* PCI + 0x2C */
+	u32	erbar;		/* PCI + 0x30 */
+	u32	cpr;		/* PCI + 0x34 */
+	u8	reserved2[4];	/* PCI + 0x38 */
+	u32	cr2;		/* PCI + 0x3C */
+	u8	reserved3[32];	/* PCI + 0x40 */
+	u32	gscr;		/* PCI + 0x60 */
+	u32	tbatr0;		/* PCI + 0x64 */
+	u32	tbatr1;		/* PCI + 0x68 */
+	u32	tcr;		/* PCI + 0x6C */
+	u32	iw0btar;	/* PCI + 0x70 */
+	u32	iw1btar;	/* PCI + 0x74 */
+	u32	iw2btar;	/* PCI + 0x78 */
+	u8	reserved4[4];	/* PCI + 0x7C */
+	u32	iwcr;		/* PCI + 0x80 */
+	u32	icr;		/* PCI + 0x84 */
+	u32	isr;		/* PCI + 0x88 */
+	u32	arb;		/* PCI + 0x8C */
+	u8	reserved5[104];	/* PCI + 0x90 */
+	u32	car;		/* PCI + 0xF8 */
+	u8	reserved6[4];	/* PCI + 0xFC */
+};
+
+#endif  /* __ASSEMBLY__ */
+
+
+#endif  /* __SYSLIB_MPC52xx_PCI_H__ */
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
--- a/arch/ppc/syslib/mpc52xx_pic.c
+++ b/arch/ppc/syslib/mpc52xx_pic.c
@@ -33,8 +33,8 @@
 #include <asm/mpc52xx.h>
 
 
-static struct mpc52xx_intr *intr;
-static struct mpc52xx_sdma *sdma;
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_sdma __iomem *sdma;
 
 static void
 mpc52xx_ic_disable(unsigned int irq)
@@ -166,14 +166,11 @@ mpc52xx_ic_end(unsigned int irq)
 }
 
 static struct hw_interrupt_type mpc52xx_ic = {
-	"MPC52xx",
-	NULL,				/* startup(irq) */
-	NULL,				/* shutdown(irq) */
-	mpc52xx_ic_enable,		/* enable(irq) */
-	mpc52xx_ic_disable,		/* disable(irq) */
-	mpc52xx_ic_disable_and_ack,	/* disable_and_ack(irq) */
-	mpc52xx_ic_end,			/* end(irq) */
-	0				/* set_affinity(irq, cpumask) SMP. */
+	.typename	= " MPC52xx  ",
+	.enable		= mpc52xx_ic_enable,
+	.disable	= mpc52xx_ic_disable,
+	.ack		= mpc52xx_ic_disable_and_ack,
+	.end		= mpc52xx_ic_end,
 };
 
 void __init
@@ -183,10 +180,8 @@ mpc52xx_init_irq(void)
 	u32 intr_ctrl;
 
 	/* Remap the necessary zones */
-	intr = (struct mpc52xx_intr *)
-		ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr));
-	sdma = (struct mpc52xx_sdma *)
-		ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma));
+	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
+	sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
 
 	if ((intr==NULL) || (sdma==NULL))
 		panic("Can't ioremap PIC/SDMA register for init_irq !");
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
--- a/arch/ppc/syslib/mpc52xx_setup.c
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -23,7 +23,6 @@
 #include <asm/time.h>
 #include <asm/mpc52xx.h>
 #include <asm/mpc52xx_psc.h>
-#include <asm/ocp.h>
 #include <asm/pgtable.h>
 #include <asm/ppcboot.h>
 
@@ -39,17 +38,14 @@ static int core_mult[] = {		/* CPU Frequ
 void
 mpc52xx_restart(char *cmd)
 {
-	struct mpc52xx_gpt* gpt0 = (struct mpc52xx_gpt*) MPC52xx_GPTx(0);
+	struct mpc52xx_gpt __iomem *gpt0 = MPC52xx_VA(MPC52xx_GPTx_OFFSET(0));
 
 	local_irq_disable();
 
 	/* Turn on the watchdog and wait for it to expire. It effectively
 	  does a reset */
-	if (gpt0 != NULL) {
-		out_be32(&gpt0->count, 0x000000ff);
-		out_be32(&gpt0->mode, 0x00009004);
-	} else
-		printk(KERN_ERR "mpc52xx_restart: Unable to ioremap GPT0 registers, -> looping ...");
+	out_be32(&gpt0->count, 0x000000ff);
+	out_be32(&gpt0->mode, 0x00009004);
 
 	while (1);
 }
@@ -80,8 +76,8 @@ mpc52xx_set_bat(void)
 	 * mpc52xx_find_end_of_memory, and UARTs/GPIO access for debug
 	 */
 	mb();
-	mtspr(DBAT2U, 0xf0001ffe);
-	mtspr(DBAT2L, 0xf000002a);
+	mtspr(SPRN_DBAT2U, 0xf0001ffe);
+	mtspr(SPRN_DBAT2L, 0xf000002a);
 	mb();
 }
 
@@ -95,14 +91,12 @@ mpc52xx_map_io(void)
 
 
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
-#ifdef MPC52xx_PF_CONSOLE_PORT
-#define MPC52xx_CONSOLE MPC52xx_PSCx(MPC52xx_PF_CONSOLE_PORT)
-#else
+#ifndef MPC52xx_PF_CONSOLE_PORT
 #error "mpc52xx PSC for console not selected"
 #endif
 
 static void
-mpc52xx_psc_putc(struct mpc52xx_psc * psc, unsigned char c)
+mpc52xx_psc_putc(struct mpc52xx_psc __iomem *psc, unsigned char c)
 {
 	while (!(in_be16(&psc->mpc52xx_psc_status) &
 	         MPC52xx_PSC_SR_TXRDY));
@@ -112,8 +106,10 @@ mpc52xx_psc_putc(struct mpc52xx_psc * ps
 void
 mpc52xx_progress(char *s, unsigned short hex)
 {
-	struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE;
 	char c;
+	struct mpc52xx_psc __iomem *psc;
+
+	psc = MPC52xx_VA(MPC52xx_PSCx_OFFSET(MPC52xx_PF_CONSOLE_PORT));
 
 	while ((c = *s++) != 0) {
 		if (c == '\n')
@@ -138,11 +134,11 @@ mpc52xx_find_end_of_memory(void)
 	 * else get size from sdram config registers
 	 */
 	if (ramsize == 0) {
-		struct mpc52xx_mmap_ctl *mmap_ctl;
+		struct mpc52xx_mmap_ctl __iomem *mmap_ctl;
 		u32 sdram_config_0, sdram_config_1;
 
 		/* Temp BAT2 mapping active when this is called ! */
-		mmap_ctl = (struct mpc52xx_mmap_ctl*) MPC52xx_MMAP_CTL;
+		mmap_ctl = MPC52xx_VA(MPC52xx_MMAP_CTL_OFFSET);
 
 		sdram_config_0 = in_be32(&mmap_ctl->sdram0);
 		sdram_config_1 = in_be32(&mmap_ctl->sdram1);
@@ -169,13 +165,11 @@ mpc52xx_calibrate_decr(void)
 	/* if bootloader didn't pass bus frequencies, calculate them */
 	if (xlbfreq == 0) {
 		/* Get RTC & Clock manager modules */
-		struct mpc52xx_rtc *rtc;
-		struct mpc52xx_cdm *cdm;
+		struct mpc52xx_rtc __iomem *rtc;
+		struct mpc52xx_cdm __iomem *cdm;
 
-		rtc = (struct mpc52xx_rtc*)
-			ioremap(MPC52xx_RTC, sizeof(struct mpc52xx_rtc));
-		cdm = (struct mpc52xx_cdm*)
-			ioremap(MPC52xx_CDM, sizeof(struct mpc52xx_cdm));
+		rtc = ioremap(MPC52xx_PA(MPC52xx_RTC_OFFSET), MPC52xx_RTC_SIZE);
+		cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
 
 		if ((rtc==NULL) || (cdm==NULL))
 			panic("Can't ioremap RTC/CDM while computing bus freq");
@@ -212,8 +206,8 @@ mpc52xx_calibrate_decr(void)
 		__res.bi_pcifreq = pcifreq;
 
 		/* Release mapping */
-		iounmap((void*)rtc);
-		iounmap((void*)cdm);
+		iounmap(rtc);
+		iounmap(cdm);
 	}
 
 	divisor = 4;
@@ -222,11 +216,15 @@ mpc52xx_calibrate_decr(void)
 	tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
 }
 
+int mpc52xx_match_psc_function(int psc_idx, const char *func)
+{
+	struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
 
-void __init
-mpc52xx_add_board_devices(struct ocp_def board_ocp[]) {
-	while (board_ocp->vendor != OCP_VENDOR_INVALID)
-		if(ocp_add_one_device(board_ocp++))
-			printk("mpc5200-ocp: Failed to add board device !\n");
-}
+	while ((cf->id != -1) && (cf->func != NULL)) {
+		if ((cf->id == psc_idx) && !strcmp(cf->func,func))
+			return 1;
+		cf++;
+	}
 
+	return 0;
+}
diff --git a/arch/ppc/syslib/mpc52xx_sys.c b/arch/ppc/syslib/mpc52xx_sys.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_sys.c
@@ -0,0 +1,38 @@
+/*
+ * arch/ppc/syslib/mpc52xx_sys.c
+ *
+ * Freescale MPC52xx system descriptions
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		.ppc_sys_name	= "5200",
+		.mask		= 0xffff0000,
+		.value		= 0x80110000,
+		.num_devices	= 15,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI,
+			MPC52xx_USB, MPC52xx_BDLC, MPC52xx_PSC1, MPC52xx_PSC2,
+			MPC52xx_PSC3, MPC52xx_PSC4, MPC52xx_PSC5, MPC52xx_PSC6,
+			MPC52xx_FEC, MPC52xx_ATA, MPC52xx_I2C1, MPC52xx_I2C2,
+		},
+	},
+	{	/* default match */
+		.ppc_sys_name	= "",
+		.mask		= 0x00000000,
+		.value		= 0x00000000,
+	},
+};
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -0,0 +1,238 @@
+/*
+ * arch/ppc/platforms/83xx/mpc83xx_devices.c
+ *
+ * MPC83xx Device descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/fsl_devices.h>
+#include <asm/mpc83xx.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+
+/* We use offsets for IORESOURCE_MEM since we do not know at compile time
+ * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup
+ */
+
+static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
+	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
+	.phy_reg_addr = 0x24000,
+};
+
+static struct gianfar_platform_data mpc83xx_tsec2_pdata = {
+	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
+	.phy_reg_addr = 0x24000,
+};
+
+static struct fsl_i2c_platform_data mpc83xx_fsl_i2c1_pdata = {
+	.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
+};
+
+static struct fsl_i2c_platform_data mpc83xx_fsl_i2c2_pdata = {
+	.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	[0] = {
+		.mapbase	= 0x4500,
+		.irq		= MPC83xx_IRQ_UART1,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+	},
+	[1] = {
+		.mapbase	= 0x4600,
+		.irq		= MPC83xx_IRQ_UART2,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+	},
+	{ },
+};
+
+struct platform_device ppc_sys_platform_devices[] = {
+	[MPC83xx_TSEC1] = {
+		.name = "fsl-gianfar",
+		.id	= 1,
+		.dev.platform_data = &mpc83xx_tsec1_pdata,
+		.num_resources	 = 4,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x24000,
+				.end	= 0x24fff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "tx",
+				.start	= MPC83xx_IRQ_TSEC1_TX,
+				.end	= MPC83xx_IRQ_TSEC1_TX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "rx",
+				.start	= MPC83xx_IRQ_TSEC1_RX,
+				.end	= MPC83xx_IRQ_TSEC1_RX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "error",
+				.start	= MPC83xx_IRQ_TSEC1_ERROR,
+				.end	= MPC83xx_IRQ_TSEC1_ERROR,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_TSEC2] = {
+		.name = "fsl-gianfar",
+		.id	= 2,
+		.dev.platform_data = &mpc83xx_tsec2_pdata,
+		.num_resources	 = 4,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x25000,
+				.end	= 0x25fff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "tx",
+				.start	= MPC83xx_IRQ_TSEC2_TX,
+				.end	= MPC83xx_IRQ_TSEC2_TX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "rx",
+				.start	= MPC83xx_IRQ_TSEC2_RX,
+				.end	= MPC83xx_IRQ_TSEC2_RX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "error",
+				.start	= MPC83xx_IRQ_TSEC2_ERROR,
+				.end	= MPC83xx_IRQ_TSEC2_ERROR,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_IIC1] = {
+		.name = "fsl-i2c",
+		.id	= 1,
+		.dev.platform_data = &mpc83xx_fsl_i2c1_pdata,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x3000,
+				.end	= 0x30ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC83xx_IRQ_IIC1,
+				.end	= MPC83xx_IRQ_IIC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_IIC2] = {
+		.name = "fsl-i2c",
+		.id	= 2,
+		.dev.platform_data = &mpc83xx_fsl_i2c2_pdata,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x3100,
+				.end	= 0x31ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC83xx_IRQ_IIC2,
+				.end	= MPC83xx_IRQ_IIC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_DUART] = {
+		.name = "serial8250",
+		.id	= 0,
+		.dev.platform_data = serial_platform_data,
+	},
+	[MPC83xx_SEC2] = {
+		.name = "fsl-sec2",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x30000,
+				.end	= 0x3ffff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC83xx_IRQ_SEC2,
+				.end	= MPC83xx_IRQ_SEC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_USB2_DR] = {
+		.name = "fsl-usb2-dr",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x22000,
+				.end	= 0x22fff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC83xx_IRQ_USB2_DR,
+				.end	= MPC83xx_IRQ_USB2_DR,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC83xx_USB2_MPH] = {
+		.name = "fsl-usb2-mph",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x23000,
+				.end	= 0x23fff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC83xx_IRQ_USB2_MPH,
+				.end	= MPC83xx_IRQ_USB2_MPH,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+};
+
+static int __init mach_mpc83xx_fixup(struct platform_device *pdev)
+{
+	ppc_sys_fixup_mem_resource(pdev, immrbar);
+	return 0;
+}
+
+static int __init mach_mpc83xx_init(void)
+{
+	if (ppc_md.progress)
+		ppc_md.progress("mach_mpc83xx_init:enter", 0);
+	ppc_sys_device_fixup = mach_mpc83xx_fixup;
+	return 0;
+}
+
+postcore_initcall(mach_mpc83xx_init);
diff --git a/arch/ppc/syslib/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc83xx_sys.c
@@ -0,0 +1,100 @@
+/*
+ * arch/ppc/platforms/83xx/mpc83xx_sys.c
+ *
+ * MPC83xx System descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		.ppc_sys_name	= "8349E",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80500000,
+		.num_devices	= 8,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+		},
+	},
+	{
+		.ppc_sys_name	= "8349",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80510000,
+		.num_devices	= 7,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART,
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+		},
+	},
+	{
+		.ppc_sys_name	= "8347E",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80520000,
+		.num_devices	= 8,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+		},
+	},
+	{
+		.ppc_sys_name	= "8347",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80530000,
+		.num_devices	= 7,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART,
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+		},
+	},
+	{
+		.ppc_sys_name	= "8343E",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80540000,
+		.num_devices	= 7,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
+			MPC83xx_USB2_DR,
+		},
+	},
+	{
+		.ppc_sys_name	= "8343",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80550000,
+		.num_devices	= 6,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
+			MPC83xx_IIC2, MPC83xx_DUART,
+			MPC83xx_USB2_DR,
+		},
+	},
+	{	/* default match */
+		.ppc_sys_name	= "",
+		.mask 		= 0x00000000,
+		.value 		= 0x00000000,
+	},
+};
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -0,0 +1,553 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_devices.c
+ *
+ * MPC85xx Device descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/fsl_devices.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+
+/* We use offsets for IORESOURCE_MEM since we do not know at compile time
+ * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
+ */
+
+static struct gianfar_platform_data mpc85xx_tsec1_pdata = {
+	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
+	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct gianfar_platform_data mpc85xx_tsec2_pdata = {
+	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
+	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct gianfar_platform_data mpc85xx_fec_pdata = {
+	.phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct fsl_i2c_platform_data mpc85xx_fsl_i2c_pdata = {
+	.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	[0] = {
+		.mapbase	= 0x4500,
+		.irq		= MPC85xx_IRQ_DUART,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
+	},
+	[1] = {
+		.mapbase	= 0x4600,
+		.irq		= MPC85xx_IRQ_DUART,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
+	},
+	{ },
+};
+
+struct platform_device ppc_sys_platform_devices[] = {
+	[MPC85xx_TSEC1] = {
+		.name = "fsl-gianfar",
+		.id	= 1,
+		.dev.platform_data = &mpc85xx_tsec1_pdata,
+		.num_resources	 = 4,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_ENET1_OFFSET,
+				.end	= MPC85xx_ENET1_OFFSET +
+						MPC85xx_ENET1_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "tx",
+				.start	= MPC85xx_IRQ_TSEC1_TX,
+				.end	= MPC85xx_IRQ_TSEC1_TX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "rx",
+				.start	= MPC85xx_IRQ_TSEC1_RX,
+				.end	= MPC85xx_IRQ_TSEC1_RX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "error",
+				.start	= MPC85xx_IRQ_TSEC1_ERROR,
+				.end	= MPC85xx_IRQ_TSEC1_ERROR,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_TSEC2] = {
+		.name = "fsl-gianfar",
+		.id	= 2,
+		.dev.platform_data = &mpc85xx_tsec2_pdata,
+		.num_resources	 = 4,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_ENET2_OFFSET,
+				.end	= MPC85xx_ENET2_OFFSET +
+						MPC85xx_ENET2_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "tx",
+				.start	= MPC85xx_IRQ_TSEC2_TX,
+				.end	= MPC85xx_IRQ_TSEC2_TX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "rx",
+				.start	= MPC85xx_IRQ_TSEC2_RX,
+				.end	= MPC85xx_IRQ_TSEC2_RX,
+				.flags	= IORESOURCE_IRQ,
+			},
+			{
+				.name	= "error",
+				.start	= MPC85xx_IRQ_TSEC2_ERROR,
+				.end	= MPC85xx_IRQ_TSEC2_ERROR,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_FEC] =	{
+		.name = "fsl-gianfar",
+		.id	= 3,
+		.dev.platform_data = &mpc85xx_fec_pdata,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_ENET3_OFFSET,
+				.end	= MPC85xx_ENET3_OFFSET +
+						MPC85xx_ENET3_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+
+			},
+			{
+				.start	= MPC85xx_IRQ_FEC,
+				.end	= MPC85xx_IRQ_FEC,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_IIC1] = {
+		.name = "fsl-i2c",
+		.id	= 1,
+		.dev.platform_data = &mpc85xx_fsl_i2c_pdata,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_IIC1_OFFSET,
+				.end	= MPC85xx_IIC1_OFFSET +
+						MPC85xx_IIC1_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_IIC1,
+				.end	= MPC85xx_IRQ_IIC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_DMA0] = {
+		.name = "fsl-dma",
+		.id	= 0,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_DMA0_OFFSET,
+				.end	= MPC85xx_DMA0_OFFSET +
+						MPC85xx_DMA0_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_DMA0,
+				.end	= MPC85xx_IRQ_DMA0,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_DMA1] = {
+		.name = "fsl-dma",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_DMA1_OFFSET,
+				.end	= MPC85xx_DMA1_OFFSET +
+						MPC85xx_DMA1_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_DMA1,
+				.end	= MPC85xx_IRQ_DMA1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_DMA2] = {
+		.name = "fsl-dma",
+		.id	= 2,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_DMA2_OFFSET,
+				.end	= MPC85xx_DMA2_OFFSET +
+						MPC85xx_DMA2_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_DMA2,
+				.end	= MPC85xx_IRQ_DMA2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_DMA3] = {
+		.name = "fsl-dma",
+		.id	= 3,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_DMA3_OFFSET,
+				.end	= MPC85xx_DMA3_OFFSET +
+						MPC85xx_DMA3_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_DMA3,
+				.end	= MPC85xx_IRQ_DMA3,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_DUART] = {
+		.name = "serial8250",
+		.id	= 0,
+		.dev.platform_data = serial_platform_data,
+	},
+	[MPC85xx_PERFMON] = {
+		.name = "fsl-perfmon",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_PERFMON_OFFSET,
+				.end	= MPC85xx_PERFMON_OFFSET +
+						MPC85xx_PERFMON_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_PERFMON,
+				.end	= MPC85xx_IRQ_PERFMON,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_SEC2] = {
+		.name = "fsl-sec2",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= MPC85xx_SEC2_OFFSET,
+				.end	= MPC85xx_SEC2_OFFSET +
+						MPC85xx_SEC2_SIZE - 1,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= MPC85xx_IRQ_SEC2,
+				.end	= MPC85xx_IRQ_SEC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+#ifdef CONFIG_CPM2
+	[MPC85xx_CPM_FCC1] = {
+		.name = "fsl-cpm-fcc",
+		.id	= 1,
+		.num_resources	 = 3,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91300,
+				.end	= 0x9131F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= 0x91380,
+				.end	= 0x9139F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_FCC1,
+				.end	= SIU_INT_FCC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_FCC2] = {
+		.name = "fsl-cpm-fcc",
+		.id	= 2,
+		.num_resources	 = 3,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91320,
+				.end	= 0x9133F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= 0x913A0,
+				.end	= 0x913CF,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_FCC2,
+				.end	= SIU_INT_FCC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_FCC3] = {
+		.name = "fsl-cpm-fcc",
+		.id	= 3,
+		.num_resources	 = 3,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91340,
+				.end	= 0x9135F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= 0x913D0,
+				.end	= 0x913FF,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_FCC3,
+				.end	= SIU_INT_FCC3,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_I2C] = {
+		.name = "fsl-cpm-i2c",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91860,
+				.end	= 0x918BF,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_I2C,
+				.end	= SIU_INT_I2C,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SCC1] = {
+		.name = "fsl-cpm-scc",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A00,
+				.end	= 0x91A1F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SCC1,
+				.end	= SIU_INT_SCC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SCC2] = {
+		.name = "fsl-cpm-scc",
+		.id	= 2,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A20,
+				.end	= 0x91A3F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SCC2,
+				.end	= SIU_INT_SCC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SCC3] = {
+		.name = "fsl-cpm-scc",
+		.id	= 3,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A40,
+				.end	= 0x91A5F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SCC3,
+				.end	= SIU_INT_SCC3,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SCC4] = {
+		.name = "fsl-cpm-scc",
+		.id	= 4,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A60,
+				.end	= 0x91A7F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SCC4,
+				.end	= SIU_INT_SCC4,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SPI] = {
+		.name = "fsl-cpm-spi",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91AA0,
+				.end	= 0x91AFF,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SPI,
+				.end	= SIU_INT_SPI,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_MCC1] = {
+		.name = "fsl-cpm-mcc",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91B30,
+				.end	= 0x91B3F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_MCC1,
+				.end	= SIU_INT_MCC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_MCC2] = {
+		.name = "fsl-cpm-mcc",
+		.id	= 2,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91B50,
+				.end	= 0x91B5F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_MCC2,
+				.end	= SIU_INT_MCC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SMC1] = {
+		.name = "fsl-cpm-smc",
+		.id	= 1,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A80,
+				.end	= 0x91A8F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SMC1,
+				.end	= SIU_INT_SMC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_SMC2] = {
+		.name = "fsl-cpm-smc",
+		.id	= 2,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91A90,
+				.end	= 0x91A9F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_SMC2,
+				.end	= SIU_INT_SMC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC85xx_CPM_USB] = {
+		.name = "fsl-cpm-usb",
+		.id	= 2,
+		.num_resources	 = 2,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x91B60,
+				.end	= 0x91B7F,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.start	= SIU_INT_USB,
+				.end	= SIU_INT_USB,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+#endif /* CONFIG_CPM2 */
+};
+
+static int __init mach_mpc85xx_fixup(struct platform_device *pdev)
+{
+	ppc_sys_fixup_mem_resource(pdev, CCSRBAR);
+	return 0;
+}
+
+static int __init mach_mpc85xx_init(void)
+{
+	ppc_sys_device_fixup = mach_mpc85xx_fixup;
+	return 0;
+}
+
+postcore_initcall(mach_mpc85xx_init);
diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc85xx_sys.c
@@ -0,0 +1,118 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_sys.c
+ *
+ * MPC85xx System descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		.ppc_sys_name	= "8540",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80300000,
+		.num_devices	= 10,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_FEC, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON, MPC85xx_DUART,
+		},
+	},
+	{
+		.ppc_sys_name	= "8560",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80700000,
+		.num_devices	= 19,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON,
+			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
+			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3, MPC85xx_CPM_SCC4,
+			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
+			MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2,
+		},
+	},
+	{
+		.ppc_sys_name	= "8541",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80720000,
+		.num_devices	= 13,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON, MPC85xx_DUART,
+			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
+			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+		},
+	},
+	{
+		.ppc_sys_name	= "8541E",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x807A0000,
+		.num_devices	= 14,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
+			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+		},
+	},
+	{
+		.ppc_sys_name	= "8555",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80710000,
+		.num_devices	= 19,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON, MPC85xx_DUART,
+			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
+			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
+			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+			MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
+			MPC85xx_CPM_USB,
+		},
+	},
+	{
+		.ppc_sys_name	= "8555E",
+		.mask 		= 0xFFFF0000,
+		.value 		= 0x80790000,
+		.num_devices	= 20,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
+			MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+			MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+			MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
+			MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
+			MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+			MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
+			MPC85xx_CPM_USB,
+		},
+	},
+	{	/* default match */
+		.ppc_sys_name	= "",
+		.mask 		= 0x00000000,
+		.value 		= 0x00000000,
+	},
+};
diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c
--- a/arch/ppc/syslib/mv64360_pic.c
+++ b/arch/ppc/syslib/mv64360_pic.c
@@ -64,7 +64,7 @@ static irqreturn_t mv64360_pci_error_int
 /* ========================== local declarations =========================== */
 
 struct hw_interrupt_type mv64360_pic = {
-	.typename = " mv64360_pic ",
+	.typename = " mv64360  ",
 	.enable   = mv64360_unmask_irq,
 	.disable  = mv64360_mask_irq,
 	.ack      = mv64360_mask_irq,
@@ -155,9 +155,10 @@ mv64360_get_irq(struct pt_regs *regs)
 	 */
 	int cpu_nr = smp_processor_id();
 	if (cpu_nr == 1) {
-		if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) & (1 << 28)))
+		if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) &
+		      (1 << MV64x60_IRQ_DOORBELL)))
 			return -1;
-		return 28;
+		return mv64360_irq_base + MV64x60_IRQ_DOORBELL;
 	}
 #endif
 
@@ -171,7 +172,7 @@ mv64360_get_irq(struct pt_regs *regs)
 		if (irq == -1)
 			irq = -2; /* bogus interrupt, should never happen */
 		else {
-			if ((irq >= 24) && (irq < 28)) {
+			if ((irq >= 24) && (irq < MV64x60_IRQ_DOORBELL)) {
 				irq_gpp = mv64x60_read(&bh,
 					MV64x60_GPP_INTR_CAUSE);
 				irq_gpp = __ilog2(irq_gpp &
@@ -217,8 +218,9 @@ mv64360_unmask_irq(unsigned int irq)
 {
 #ifdef CONFIG_SMP
 	/* second CPU gets only doorbell interrupts */
-	if ((irq - mv64360_irq_base) == 28) {
-		mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, (1 << 28));
+	if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) {
+		mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO,
+				 (1 << MV64x60_IRQ_DOORBELL));
 		return;
 	}
 #endif
@@ -257,8 +259,9 @@ static void
 mv64360_mask_irq(unsigned int irq)
 {
 #ifdef CONFIG_SMP
-	if ((irq - mv64360_irq_base) == 28) {
-		mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, (1 << 28));
+	if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) {
+		mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO,
+				 (1 << MV64x60_IRQ_DOORBELL));
 		return;
 	}
 #endif
@@ -371,7 +374,7 @@ mv64360_register_hdlrs(void)
 
 	/* Clear old errors and register CPU interface error intr handler */
 	mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
-	if ((rc = request_irq(MV64x60_IRQ_CPU_ERR,
+	if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base,
 		mv64360_cpu_error_int_handler, SA_INTERRUPT, CPU_INTR_STR, 0)))
 		printk(KERN_WARNING "Can't register cpu error handler: %d", rc);
 
@@ -380,7 +383,7 @@ mv64360_register_hdlrs(void)
 
 	/* Clear old errors and register internal SRAM error intr handler */
 	mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0);
-	if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR,
+	if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base,
 		mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0)))
 		printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
 
@@ -397,7 +400,8 @@ mv64360_register_hdlrs(void)
 
 	/* Clear old errors and register PCI 0 error intr handler */
 	mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0);
-	if ((rc = request_irq(MV64360_IRQ_PCI0, mv64360_pci_error_int_handler,
+	if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base,
+			mv64360_pci_error_int_handler,
 			SA_INTERRUPT, PCI0_INTR_STR, (void *)0)))
 		printk(KERN_WARNING "Can't register pci 0 error handler: %d",
 			rc);
@@ -407,7 +411,8 @@ mv64360_register_hdlrs(void)
 
 	/* Clear old errors and register PCI 1 error intr handler */
 	mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0);
-	if ((rc = request_irq(MV64360_IRQ_PCI1, mv64360_pci_error_int_handler,
+	if ((rc = request_irq(MV64360_IRQ_PCI1 + mv64360_irq_base,
+			mv64360_pci_error_int_handler,
 			SA_INTERRUPT, PCI1_INTR_STR, (void *)1)))
 		printk(KERN_WARNING "Can't register pci 1 error handler: %d",
 			rc);
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -314,15 +314,15 @@ static struct platform_device mpsc1_devi
 static struct resource mv64x60_eth_shared_resources[] = {
 	[0] = {
 		.name	= "ethernet shared base",
-		.start	= MV64340_ETH_SHARED_REGS,
-		.end	= MV64340_ETH_SHARED_REGS +
-					MV64340_ETH_SHARED_REGS_SIZE - 1,
+		.start	= MV643XX_ETH_SHARED_REGS,
+		.end	= MV643XX_ETH_SHARED_REGS +
+					MV643XX_ETH_SHARED_REGS_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 };
 
 static struct platform_device mv64x60_eth_shared_device = {
-	.name		= MV64XXX_ETH_SHARED_NAME,
+	.name		= MV643XX_ETH_SHARED_NAME,
 	.id		= 0,
 	.num_resources	= ARRAY_SIZE(mv64x60_eth_shared_resources),
 	.resource	= mv64x60_eth_shared_resources,
@@ -338,10 +338,10 @@ static struct resource mv64x60_eth0_reso
 	},
 };
 
-static struct mv64xxx_eth_platform_data eth0_pd;
+static struct mv643xx_eth_platform_data eth0_pd;
 
 static struct platform_device eth0_device = {
-	.name		= MV64XXX_ETH_NAME,
+	.name		= MV643XX_ETH_NAME,
 	.id		= 0,
 	.num_resources	= ARRAY_SIZE(mv64x60_eth0_resources),
 	.resource	= mv64x60_eth0_resources,
@@ -361,10 +361,10 @@ static struct resource mv64x60_eth1_reso
 	},
 };
 
-static struct mv64xxx_eth_platform_data eth1_pd;
+static struct mv643xx_eth_platform_data eth1_pd;
 
 static struct platform_device eth1_device = {
-	.name		= MV64XXX_ETH_NAME,
+	.name		= MV643XX_ETH_NAME,
 	.id		= 1,
 	.num_resources	= ARRAY_SIZE(mv64x60_eth1_resources),
 	.resource	= mv64x60_eth1_resources,
@@ -384,10 +384,10 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static struct mv64xxx_eth_platform_data eth2_pd;
+static struct mv643xx_eth_platform_data eth2_pd;
 
 static struct platform_device eth2_device = {
-	.name		= MV64XXX_ETH_NAME,
+	.name		= MV643XX_ETH_NAME,
 	.id		= 2,
 	.num_resources	= ARRAY_SIZE(mv64x60_eth2_resources),
 	.resource	= mv64x60_eth2_resources,
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -78,7 +78,6 @@ static void openpic_mapirq(u_int irq, cp
  */
 #ifdef notused
 static void openpic_enable_8259_pass_through(void);
-static u_int openpic_get_priority(void);
 static u_int openpic_get_spurious(void);
 static void openpic_set_sense(u_int irq, int sense);
 #endif /* notused */
@@ -276,7 +275,7 @@ static void __init openpic_enable_sie(vo
 }
 #endif
 
-#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM)
+#if defined(CONFIG_EPIC_SERIAL_MODE)
 static void openpic_reset(void)
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
@@ -465,8 +464,7 @@ void openpic_eoi(void)
 	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
 }
 
-#ifdef notused
-static u_int openpic_get_priority(void)
+u_int openpic_get_priority(void)
 {
 	DECL_THIS_CPU;
 
@@ -474,7 +472,6 @@ static u_int openpic_get_priority(void)
 	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
 				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
 }
-#endif /* notused */
 
 void openpic_set_priority(u_int pri)
 {
@@ -560,12 +557,10 @@ static void __init openpic_initipi(u_int
  */
 void openpic_cause_IPI(u_int ipi, cpumask_t cpumask)
 {
-	cpumask_t phys;
 	DECL_THIS_CPU;
 
 	CHECK_THIS_CPU;
 	check_arg_ipi(ipi);
-	phys = physmask(cpumask);
 	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
 		      cpus_addr(physmask(cpumask))[0]);
 }
@@ -998,8 +993,6 @@ int openpic_resume(struct sys_device *sy
 		return 0;
 	}
 
-	openpic_reset();
-
 	/* OpenPIC sometimes seem to need some time to be fully back up... */
 	do {
 		openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
diff --git a/arch/ppc/syslib/open_pic_defs.h b/arch/ppc/syslib/open_pic_defs.h
--- a/arch/ppc/syslib/open_pic_defs.h
+++ b/arch/ppc/syslib/open_pic_defs.h
@@ -172,9 +172,6 @@ struct OpenPIC {
     OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
 };
 
-extern volatile struct OpenPIC __iomem *OpenPIC;
-
-
     /*
      *  Current Task Priority Register
      */
diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
--- a/arch/ppc/syslib/ppc4xx_pic.c
+++ b/arch/ppc/syslib/ppc4xx_pic.c
@@ -4,7 +4,7 @@
  * Interrupt controller driver for PowerPC 4xx-based processors.
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2004 Zultys Technologies
+ * Copyright (c) 2004, 2005 Zultys Technologies
  *
  * Based on original code by
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
@@ -29,8 +29,9 @@
 /* See comment in include/arch-ppc/ppc4xx_pic.h
  * for more info about these two variables
  */
-extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] __attribute__((weak));
-extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__((weak));
+extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS]
+    __attribute__ ((weak));
+extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
 
 #define IRQ_MASK_UIC0(irq)		(1 << (31 - (irq)))
 #define IRQ_MASK_UICx(irq)		(1 << (31 - ((irq) & 0x1f)))
@@ -40,7 +41,10 @@ extern unsigned char ppc4xx_uic_ext_irq_
 #define UIC_HANDLERS(n)							\
 static void ppc4xx_uic##n##_enable(unsigned int irq)			\
 {									\
-	ppc_cached_irq_mask[n] |= IRQ_MASK_UIC##n(irq);			\
+	u32 mask = IRQ_MASK_UIC##n(irq);				\
+	if (irq_desc[irq].status & IRQ_LEVEL)				\
+		mtdcr(DCRN_UIC_SR(UIC##n), mask);			\
+	ppc_cached_irq_mask[n] |= mask;					\
 	mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);		\
 }									\
 									\
@@ -48,6 +52,7 @@ static void ppc4xx_uic##n##_disable(unsi
 {									\
 	ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq);		\
 	mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);		\
+	ACK_UIC##n##_PARENT						\
 }									\
 									\
 static void ppc4xx_uic##n##_ack(unsigned int irq)			\
@@ -63,11 +68,11 @@ static void ppc4xx_uic##n##_end(unsigned
 {									\
 	unsigned int status = irq_desc[irq].status;			\
 	u32 mask = IRQ_MASK_UIC##n(irq);				\
-	if (status & IRQ_LEVEL){					\
+	if (status & IRQ_LEVEL) {					\
 		mtdcr(DCRN_UIC_SR(UIC##n), mask);			\
 		ACK_UIC##n##_PARENT					\
 	}								\
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))){		\
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		\
 		ppc_cached_irq_mask[n] |= mask;				\
 		mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);	\
 	}								\
@@ -86,7 +91,9 @@ static void ppc4xx_uic##n##_end(unsigned
 #define ACK_UIC0_PARENT	mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
 #define ACK_UIC1_PARENT	mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
 #define ACK_UIC2_PARENT	mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
-UIC_HANDLERS(0); UIC_HANDLERS(1); UIC_HANDLERS(2);
+UIC_HANDLERS(0);
+UIC_HANDLERS(1);
+UIC_HANDLERS(2);
 
 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
 {
@@ -114,7 +121,8 @@ static void __init ppc4xx_pic_impl_init(
 #elif NR_UICS == 2
 #define ACK_UIC0_PARENT
 #define ACK_UIC1_PARENT	mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
-UIC_HANDLERS(0); UIC_HANDLERS(1);
+UIC_HANDLERS(0);
+UIC_HANDLERS(1);
 
 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
 {
@@ -143,18 +151,20 @@ static int ppc4xx_pic_get_irq(struct pt_
 	return uic0 ? 32 - ffs(uic0) : -1;
 }
 
-static inline void ppc4xx_pic_impl_init(void){}
+static inline void ppc4xx_pic_impl_init(void)
+{
+}
 #endif
 
 static struct ppc4xx_uic_impl {
 	struct hw_interrupt_type decl;
-	int			 base;		/* Base DCR number */
+	int base;			/* Base DCR number */
 } __uic[] = {
-    { .decl = DECLARE_UIC(0), .base = UIC0 },
+	{ .decl = DECLARE_UIC(0), .base = UIC0 },
 #if NR_UICS > 1
-    { .decl = DECLARE_UIC(1), .base = UIC1 },
+	{ .decl = DECLARE_UIC(1), .base = UIC1 },
 #if NR_UICS > 2
-    { .decl = DECLARE_UIC(2), .base = UIC2 },
+	{ .decl = DECLARE_UIC(2), .base = UIC2 },
 #endif
 #endif
 };
@@ -168,9 +178,9 @@ static inline int is_level_sensitive(int
 void __init ppc4xx_pic_init(void)
 {
 	int i;
-	unsigned char* eirqs = ppc4xx_uic_ext_irq_cfg;
+	unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg;
 
-	for (i = 0; i < NR_UICS; ++i){
+	for (i = 0; i < NR_UICS; ++i) {
 		int base = __uic[i].base;
 
 		/* Disable everything by default */
@@ -181,23 +191,23 @@ void __init ppc4xx_pic_init(void)
 		mtdcr(DCRN_UIC_CR(base), 0);
 
 		/* Configure polarity and triggering */
-		if (ppc4xx_core_uic_cfg){
-			struct ppc4xx_uic_settings* p = ppc4xx_core_uic_cfg + i;
+		if (ppc4xx_core_uic_cfg) {
+			struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i;
 			u32 mask = p->ext_irq_mask;
 			u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
 			u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
 
 			/* "Fixed" interrupts (on-chip devices) */
-			pr |= p->polarity   & ~mask;
+			pr |= p->polarity & ~mask;
 			tr |= p->triggering & ~mask;
 
 			/* Merge external IRQs settings if board port
 			 * provided them
 			 */
-			if (eirqs && mask){
+			if (eirqs && mask) {
 				pr &= ~mask;
 				tr &= ~mask;
-				while (mask){
+				while (mask) {
 					/* Extract current external IRQ mask */
 					u32 eirq_mask = 1 << __ilog2(mask);
 
@@ -227,8 +237,8 @@ void __init ppc4xx_pic_init(void)
 	ppc4xx_pic_impl_init();
 
 	/* Attach low-level handlers */
-	for (i = 0; i < (NR_UICS << 5); ++i){
-    		irq_desc[i].handler = &__uic[i >> 5].decl;
+	for (i = 0; i < (NR_UICS << 5); ++i) {
+		irq_desc[i].handler = &__uic[i >> 5].decl;
 		if (is_level_sensitive(i))
 			irq_desc[i].status |= IRQ_LEVEL;
 	}
diff --git a/arch/ppc/syslib/ppc4xx_serial.c b/arch/ppc/syslib/ppc4xx_serial.c
deleted file mode 100644
--- a/arch/ppc/syslib/ppc4xx_serial.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * arch/ppc/syslib/ppc405_serial.c
- *
- * Author: MontaVista Software, Inc.
- *         	frank_rowand@mvista.com or source@mvista.com
- * 	   	debbie_chu@mvista.com
- *
- * This is a fairly standard 165xx type device that will eventually
- * be merged with other similar processor/boards.	-- Dan
- *
- * 2000 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Console I/O support for Early kernel bringup.
- */
-
-#include <linux/config.h>
-
-#if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR)
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#include <linux/init.h>
-#endif
-
-#ifdef CONFIG_DEBUG_BRINGUP
-
-#include <linux/console.h>
-
-extern void ftr_reset_preferred_console(void);
-
-
-static int ppc405_sercons_setup(struct console *co, char *options)
-{
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_dll  = (char *)0xef600300;
-    volatile unsigned char *uart_fcr  = (char *)0xef600302;
-    volatile unsigned char *uart_lcr  = (char *)0xef600303;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_dll  = (char *)0xef600400;
-    volatile unsigned char *uart_fcr  = (char *)0xef600402;
-    volatile unsigned char *uart_lcr  = (char *)0xef600403;
-#endif
-
-    *uart_lcr = *uart_lcr | 0x80;   /* DLAB on  */
-
-/* ftr revisit - there is no config option for this
-**  also see include/asm-ppc/ppc405_serial.h
-**
-** #define CONFIG_IBM405GP_INTERNAL_CLOCK
-*/
-
-
-#ifdef  CONFIG_IBM405GP_INTERNAL_CLOCK
-    /* ftr revisit
-    ** why is bit 19 of chcr0 (0x1000) being set?
-    */
-    /* 0x2a results in data corruption, kgdb works with 0x28 */
-    *uart_dll = 0x28;		    /* 9600 baud */
-    _put_CHCR0((_get_CHCR0() & 0xffffe000) | 0x103e);
-#else
-    *uart_dll = 0x48;		    /* 9600 baud */
-#endif
-    *uart_lcr = *uart_lcr & 0x7f;   /* DLAB off */
-
-    return 0;
-}
-
-
-/*
- * This is a bringup hack, writing directly to uart0 or uart1
- */
-
-static void
-ppc405_sercons_write(struct console *co, const char *ptr,
-            unsigned nb)
-{
-    int i;
-
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_xmit = (char *)0xef600300;
-    volatile unsigned char *uart_lsr  = (char *)0xef600305;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_xmit = (char *)0xef600400;
-    volatile unsigned char *uart_lsr  = (char *)0xef600405;
-#endif
-
-    for (i = 0; i < nb; ++i) {
-
-	/* wait for transmit reg (possibly fifo) to empty */
-	while ((*uart_lsr & 0x40) == 0)
-	    ;
-
-	*uart_xmit = (ptr[i] & 0xff);
-
-	if (ptr[i] == '\n') {
-
-	    /* add a carriage return */
-
-	    /* wait for transmit reg (possibly fifo) to empty */
-	    while ((*uart_lsr & 0x40) == 0)
-		;
-
-	    *uart_xmit = '\r';
-	}
-    }
-
-    return;
-}
-
-
-static int
-ppc405_sercons_read(struct console *co, char *ptr, unsigned nb)
-{
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_rcv  = (char *)0xef600300;
-    volatile unsigned char *uart_lsr  = (char *)0xef600305;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_rcv  = (char *)0xef600400;
-    volatile unsigned char *uart_lsr  = (char *)0xef600405;
-#endif
-
-
-    /* ftr revisit: not tested */
-
-    if (nb == 0)
-	return(0);
-
-    if (!ptr)
-	return(-1);
-
-    /* wait for receive reg (possibly fifo) to contain data */
-    while ((*uart_lsr & 0x01) == 0)
-	;
-
-    *ptr = *uart_rcv;
-
-    return(1);
-}
-
-static struct console ppc405_sercons = {
-	.name =		"dbg_cons",
-	.write =	ppc405_console_write,
-	.setup =	ppc405_console_setup,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
-};
-
-void
-register_debug_console(void)
-{
-	register_console(&ppc405_sercons);
-}
-
-void
-unregister_debug_console(void)
-{
-	unregister_console(&ppc405_sercons);
-}
-
-#endif	/* CONFIG_DEBUG_BRINGUP */
-
-#endif	/* #if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR) */
diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc83xx_setup.c
@@ -0,0 +1,166 @@
+/*
+ * arch/ppc/syslib/ppc83xx_setup.c
+ *
+ * MPC83XX common board code
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/serial.h>
+#include <linux/tty.h>	/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/mpc83xx.h>
+#include <asm/mmu.h>
+#include <asm/ppc_sys.h>
+#include <asm/kgdb.h>
+#include <asm/delay.h>
+
+#include <syslib/ppc83xx_setup.h>
+
+phys_addr_t immrbar;
+
+/* Return the amount of memory */
+unsigned long __init
+mpc83xx_find_end_of_memory(void)
+{
+        bd_t *binfo;
+
+        binfo = (bd_t *) __res;
+
+        return binfo->bi_memsize;
+}
+
+long __init
+mpc83xx_time_init(void)
+{
+#define SPCR_OFFS   0x00000110
+#define SPCR_TBEN   0x00400000
+
+	bd_t *binfo = (bd_t *)__res;
+	u32 *spcr = ioremap(binfo->bi_immr_base + SPCR_OFFS, 4);
+
+	*spcr |= SPCR_TBEN;
+
+	iounmap(spcr);
+
+	return 0;
+}
+
+/* The decrementer counts at the system (internal) clock freq divided by 4 */
+void __init
+mpc83xx_calibrate_decr(void)
+{
+        bd_t *binfo = (bd_t *) __res;
+        unsigned int freq, divisor;
+
+	freq = binfo->bi_busfreq;
+	divisor = 4;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+}
+
+#ifdef CONFIG_SERIAL_8250
+void __init
+mpc83xx_early_serial_map(void)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	struct uart_port serial_req;
+#endif
+	struct plat_serial8250_port *pdata;
+	bd_t *binfo = (bd_t *) __res;
+	pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC83xx_DUART);
+
+	/* Setup serial port access */
+	pdata[0].uartclk = binfo->bi_busfreq;
+	pdata[0].mapbase += binfo->bi_immr_base;
+	pdata[0].membase = ioremap(pdata[0].mapbase, 0x100);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	memset(&serial_req, 0, sizeof (serial_req));
+	serial_req.iotype = SERIAL_IO_MEM;
+	serial_req.mapbase = pdata[0].mapbase;
+	serial_req.membase = pdata[0].membase;
+	serial_req.regshift = 0;
+
+	gen550_init(0, &serial_req);
+#endif
+
+	pdata[1].uartclk = binfo->bi_busfreq;
+	pdata[1].mapbase += binfo->bi_immr_base;
+	pdata[1].membase = ioremap(pdata[1].mapbase, 0x100);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Assume gen550_init() doesn't modify serial_req */
+	serial_req.mapbase = pdata[1].mapbase;
+	serial_req.membase = pdata[1].membase;
+
+	gen550_init(1, &serial_req);
+#endif
+}
+#endif
+
+void
+mpc83xx_restart(char *cmd)
+{
+	volatile unsigned char __iomem *reg;
+	unsigned char tmp;
+
+	reg = ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+
+	local_irq_disable();
+
+	/*
+	 * Unlock the BCSR bits so a PRST will update the contents.
+	 * Otherwise the reset asserts but doesn't clear.
+	 */
+	tmp = in_8(reg + BCSR_MISC_REG3_OFF);
+	tmp |= BCSR_MISC_REG3_CNFLOCK; /* low true, high false */
+	out_8(reg + BCSR_MISC_REG3_OFF, tmp);
+
+	/*
+	 * Trigger a reset via a low->high transition of the
+	 * PORESET bit.
+	 */
+	tmp = in_8(reg + BCSR_MISC_REG2_OFF);
+	tmp &= ~BCSR_MISC_REG2_PORESET;
+	out_8(reg + BCSR_MISC_REG2_OFF, tmp);
+
+	udelay(1);
+
+	tmp |= BCSR_MISC_REG2_PORESET;
+	out_8(reg + BCSR_MISC_REG2_OFF, tmp);
+
+	for(;;);
+}
+
+void
+mpc83xx_power_off(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+void
+mpc83xx_halt(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+/* PCI SUPPORT DOES NOT EXIT, MODEL after ppc85xx_setup.c */
diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc83xx_setup.h
@@ -0,0 +1,53 @@
+/*
+ * arch/ppc/syslib/ppc83xx_setup.h
+ *
+ * MPC83XX common board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ *
+ */
+
+#ifndef __PPC_SYSLIB_PPC83XX_SETUP_H
+#define __PPC_SYSLIB_PPC83XX_SETUP_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+extern unsigned long mpc83xx_find_end_of_memory(void) __init;
+extern long mpc83xx_time_init(void) __init;
+extern void mpc83xx_calibrate_decr(void) __init;
+extern void mpc83xx_early_serial_map(void) __init;
+extern void mpc83xx_restart(char *cmd);
+extern void mpc83xx_power_off(void);
+extern void mpc83xx_halt(void);
+extern void mpc83xx_setup_hose(void) __init;
+
+/* PCI config */
+#if 0
+#define PCI1_CFG_ADDR_OFFSET	(FIXME)
+#define PCI1_CFG_DATA_OFFSET	(FIXME)
+
+#define PCI2_CFG_ADDR_OFFSET	(FIXME)
+#define PCI2_CFG_DATA_OFFSET	(FIXME)
+#endif
+
+/* Serial Config */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  2
+#endif
+
+#ifndef BASE_BAUD
+#define BASE_BAUD 115200
+#endif
+
+#endif /* __PPC_SYSLIB_PPC83XX_SETUP_H */
diff --git a/arch/ppc/syslib/ppc85xx_common.c b/arch/ppc/syslib/ppc85xx_common.c
--- a/arch/ppc/syslib/ppc85xx_common.c
+++ b/arch/ppc/syslib/ppc85xx_common.c
@@ -31,3 +31,11 @@ get_ccsrbar(void)
 }
 
 EXPORT_SYMBOL(get_ccsrbar);
+
+/* For now this is a pass through */
+phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
+{
+	return addr;
+};
+EXPORT_SYMBOL(fixup_bigphys_addr);
+
diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c
--- a/arch/ppc/syslib/ppc85xx_setup.c
+++ b/arch/ppc/syslib/ppc85xx_setup.c
@@ -132,6 +132,12 @@ mpc85xx_halt(void)
 }
 
 #ifdef CONFIG_PCI
+
+#if defined(CONFIG_MPC8555_CDS)
+extern void mpc85xx_cds_enable_via(struct pci_controller *hose);
+extern void mpc85xx_cds_fixup_via(struct pci_controller *hose);
+#endif
+
 static void __init
 mpc85xx_setup_pci1(struct pci_controller *hose)
 {
@@ -280,16 +286,14 @@ mpc85xx_setup_hose(void)
 	hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;
 	hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE;
 #ifdef CONFIG_85xx_PCI2
-	isa_io_base =
-		(unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+	hose_a->io_base_virt =  ioremap(MPC85XX_PCI1_IO_BASE,
 					MPC85XX_PCI1_IO_SIZE +
 					MPC85XX_PCI2_IO_SIZE);
 #else
-	isa_io_base =
-		(unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+	hose_a->io_base_virt =  ioremap(MPC85XX_PCI1_IO_BASE,
 					MPC85XX_PCI1_IO_SIZE);
 #endif
-	hose_a->io_base_virt = (void *) isa_io_base;
+	isa_io_base = (unsigned long)hose_a->io_base_virt;
 
 	/* setup resources */
 	pci_init_resource(&hose_a->mem_resources[0],
@@ -304,8 +308,18 @@ mpc85xx_setup_hose(void)
 
 	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
 
+#if defined(CONFIG_MPC8555_CDS)
+	/* Pre pciauto_bus_scan VIA init */
+	mpc85xx_cds_enable_via(hose_a);
+#endif
+
 	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
 
+#if defined(CONFIG_MPC8555_CDS)
+	/* Post pciauto_bus_scan VIA fixup */
+	mpc85xx_cds_fixup_via(hose_a);
+#endif
+
 #ifdef CONFIG_85xx_PCI2
 	hose_b = pcibios_alloc_controller();
 
@@ -329,8 +343,8 @@ mpc85xx_setup_hose(void)
 	hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO;
 	hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO;
 	hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE;
-	hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE;
-
+	hose_b->io_base_virt = hose_a->io_base_virt + MPC85XX_PCI1_IO_SIZE;
+	
 	/* setup resources */
 	pci_init_resource(&hose_b->mem_resources[0],
 			MPC85XX_PCI2_LOWER_MEM,
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
--- a/arch/ppc/syslib/prom.c
+++ b/arch/ppc/syslib/prom.c
@@ -308,7 +308,7 @@ map_interrupt(unsigned int **irq, struct
 	struct device_node *p, *ipar;
 	unsigned int *imap, *imask, *ip;
 	int i, imaplen, match;
-	int newintrc, newaddrc;
+	int newintrc = 1, newaddrc = 1;
 	unsigned int *reg;
 	int naddrc;
 
diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c
--- a/arch/ppc/syslib/prom_init.c
+++ b/arch/ppc/syslib/prom_init.c
@@ -53,11 +53,13 @@ extern const struct linux_logo logo_linu
 
 #define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
 
+typedef u32 prom_arg_t;
+
 struct prom_args {
 	const char *service;
 	int nargs;
 	int nret;
-	void *args[10];
+	prom_arg_t args[10];
 };
 
 struct pci_address {
@@ -93,9 +95,9 @@ struct pci_intr_map {
 };
 
 static void prom_exit(void);
-static void *call_prom(const char *service, int nargs, int nret, ...);
-static void *call_prom_ret(const char *service, int nargs, int nret,
-			   void **rets, ...);
+static int  call_prom(const char *service, int nargs, int nret, ...);
+static int  call_prom_ret(const char *service, int nargs, int nret,
+			  prom_arg_t *rets, ...);
 static void prom_print_hex(unsigned int v);
 static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
 static int  prom_next_node(phandle *nodep);
@@ -146,7 +148,7 @@ prom_exit(void)
 		;
 }
 
-static void * __init
+static int __init
 call_prom(const char *service, int nargs, int nret, ...)
 {
 	va_list list;
@@ -158,16 +160,16 @@ call_prom(const char *service, int nargs
 	prom_args.nret = nret;
 	va_start(list, nret);
 	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, void *);
+		prom_args.args[i] = va_arg(list, prom_arg_t);
 	va_end(list);
 	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = NULL;
+		prom_args.args[i + nargs] = 0;
 	prom(&prom_args);
 	return prom_args.args[nargs];
 }
 
-static void * __init
-call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
+static int __init
+call_prom_ret(const char *service, int nargs, int nret, prom_arg_t *rets, ...)
 {
 	va_list list;
 	int i;
@@ -178,10 +180,10 @@ call_prom_ret(const char *service, int n
 	prom_args.nret = nret;
 	va_start(list, rets);
 	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, void *);
+		prom_args.args[i] = va_arg(list, int);
 	va_end(list);
 	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = NULL;
+		prom_args.args[i + nargs] = 0;
 	prom(&prom_args);
 	for (i = 1; i < nret; ++i)
 		rets[i-1] = prom_args.args[nargs + i];
@@ -227,19 +229,7 @@ prom_print_hex(unsigned int v)
 static int __init
 prom_set_color(ihandle ih, int i, int r, int g, int b)
 {
-	struct prom_args prom_args;
-
-	prom_args.service = "call-method";
-	prom_args.nargs = 6;
-	prom_args.nret = 1;
-	prom_args.args[0] = "color!";
-	prom_args.args[1] = ih;
-	prom_args.args[2] = (void *) i;
-	prom_args.args[3] = (void *) b;
-	prom_args.args[4] = (void *) g;
-	prom_args.args[5] = (void *) r;
-	prom(&prom_args);
-	return (int) prom_args.args[6];
+	return call_prom("call-method", 6, 1, "color!", ih, i, b, g, r);
 }
 
 static int __init
@@ -363,9 +353,9 @@ check_display(unsigned long mem)
 	};
 	const unsigned char *clut;
 
-	prom_disp_node = NULL;
+	prom_disp_node = 0;
 
-	for (node = NULL; prom_next_node(&node); ) {
+	for (node = 0; prom_next_node(&node); ) {
 		type[0] = 0;
 		call_prom("getprop", 4, 1, node, "device_type",
 			  type, sizeof(type));
@@ -374,8 +364,7 @@ check_display(unsigned long mem)
 		/* It seems OF doesn't null-terminate the path :-( */
 		path = (char *) mem;
 		memset(path, 0, 256);
-		if ((int) call_prom("package-to-path", 3, 1,
-				    node, path, 255) < 0)
+		if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
 			continue;
 
 		/*
@@ -417,11 +406,11 @@ check_display(unsigned long mem)
 				prom_disp_node = prom_display_nodes[j];
 				j--;
 			} else
-				prom_disp_node = NULL;
+				prom_disp_node = 0;
 			continue;
 		} else {
 			prom_print("... ok\n");
-			call_prom("setprop", 4, 1, node, "linux,opened", 0, NULL);
+			call_prom("setprop", 4, 1, node, "linux,opened", 0, 0);
 
 			/*
 			 * Setup a usable color table when the appropriate
@@ -448,13 +437,13 @@ check_display(unsigned long mem)
 	if (prom_stdout) {
 		phandle p;
 		p = call_prom("instance-to-package", 1, 1, prom_stdout);
-		if (p && (int)p != -1) {
+		if (p && p != -1) {
 			type[0] = 0;
 			call_prom("getprop", 4, 1, p, "device_type",
 				  type, sizeof(type));
 			if (strcmp(type, "display") == 0)
 				call_prom("setprop", 4, 1, p, "linux,boot-display",
-					  0, NULL);
+					  0, 0);
 		}
 	}
 
@@ -495,9 +484,8 @@ setup_disp_fake_bi(ihandle dp)
 		  &address, sizeof(address));
 	if (address == 0) {
 		/* look for an assigned address with a size of >= 1MB */
-		naddrs = (int) call_prom(getprop, 4, 1, dp,
-				"assigned-addresses",
-				addrs, sizeof(addrs));
+		naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses",
+				   addrs, sizeof(addrs));
 		naddrs /= sizeof(struct pci_reg_property);
 		for (i = 0; i < naddrs; ++i) {
 			if (addrs[i].size_lo >= (1 << 20)) {
@@ -602,16 +590,14 @@ inspect_node(phandle node, struct device
 		pp = (struct property *) mem_start;
 		namep = (char *) (pp + 1);
 		pp->name = PTRUNRELOC(namep);
-		if ((int) call_prom("nextprop", 3, 1, node, prev_name,
-				    namep) <= 0)
+		if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0)
 			break;
 		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
 		prev_name = namep;
 		valp = (unsigned char *) mem_start;
 		pp->value = PTRUNRELOC(valp);
-		pp->length = (int)
-			call_prom("getprop", 4, 1, node, namep,
-				  valp, mem_end - mem_start);
+		pp->length = call_prom("getprop", 4, 1, node, namep,
+				       valp, mem_end - mem_start);
 		if (pp->length < 0)
 			continue;
 #ifdef MAX_PROPERTY_LENGTH
@@ -622,7 +608,7 @@ inspect_node(phandle node, struct device
 		*prev_propp = PTRUNRELOC(pp);
 		prev_propp = &pp->next;
 	}
-	if (np->node != NULL) {
+	if (np->node != 0) {
 		/* Add a "linux,phandle" property" */
 		pp = (struct property *) mem_start;
 		*prev_propp = PTRUNRELOC(pp);
@@ -637,17 +623,27 @@ inspect_node(phandle node, struct device
 	*prev_propp = NULL;
 
 	/* get the node's full name */
-	l = (int) call_prom("package-to-path", 3, 1, node,
-			    (char *) mem_start, mem_end - mem_start);
+	l = call_prom("package-to-path", 3, 1, node,
+		      mem_start, mem_end - mem_start);
 	if (l >= 0) {
+		char *p, *ep;
+
 		np->full_name = PTRUNRELOC((char *) mem_start);
 		*(char *)(mem_start + l) = 0;
+		/* Fixup an Apple bug where they have bogus \0 chars in the
+		 * middle of the path in some properties
+		 */
+		for (p = (char *)mem_start, ep = p + l; p < ep; p++)
+			if ((*p) == '\0') {
+				memmove(p, p+1, ep - p);
+				ep--;
+			}
 		mem_start = ALIGNUL(mem_start + l + 1);
 	}
 
 	/* do all our children */
 	child = call_prom("child", 1, 1, node);
-	while (child != (void *)0) {
+	while (child != 0) {
 		mem_start = inspect_node(child, np, mem_start, mem_end,
 					 allnextpp);
 		child = call_prom("peer", 1, 1, child);
@@ -698,8 +694,8 @@ prom_hold_cpus(unsigned long mem)
 	 *      chrp we have a device_type property -- Cort
 	 */
 	node = call_prom("finddevice", 1, 1, "/");
-	if ((int)call_prom("getprop", 4, 1, node,
-			   "device_type",type, sizeof(type)) <= 0)
+	if (call_prom("getprop", 4, 1, node,
+		      "device_type", type, sizeof(type)) <= 0)
 		return;
 
 	/* copy the holding pattern code to someplace safe (0) */
@@ -711,7 +707,7 @@ prom_hold_cpus(unsigned long mem)
 	/* look for cpus */
 	*(unsigned long *)(0x0) = 0;
 	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
-	for (node = NULL; prom_next_node(&node); ) {
+	for (node = 0; prom_next_node(&node); ) {
 		type[0] = 0;
 		call_prom("getprop", 4, 1, node, "device_type",
 			  type, sizeof(type));
@@ -719,8 +715,7 @@ prom_hold_cpus(unsigned long mem)
 			continue;
 		path = (char *) mem;
 		memset(path, 0, 256);
-		if ((int) call_prom("package-to-path", 3, 1,
-				    node, path, 255) < 0)
+		if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
 			continue;
 		reg = -1;
 		call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
@@ -753,11 +748,10 @@ static void __init
 prom_instantiate_rtas(void)
 {
 	ihandle prom_rtas;
-	unsigned int i;
-	struct prom_args prom_args;
+	prom_arg_t result;
 
 	prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
-	if (prom_rtas == (void *) -1)
+	if (prom_rtas == -1)
 		return;
 
 	rtas_size = 0;
@@ -779,17 +773,10 @@ prom_instantiate_rtas(void)
 
 	prom_rtas = call_prom("open", 1, 1, "/rtas");
 	prom_print("...");
-	prom_args.service = "call-method";
-	prom_args.nargs = 3;
-	prom_args.nret = 2;
-	prom_args.args[0] = "instantiate-rtas";
-	prom_args.args[1] = prom_rtas;
-	prom_args.args[2] = (void *) rtas_data;
-	prom(&prom_args);
-	i = 0;
-	if (prom_args.args[3] == 0)
-		i = (unsigned int)prom_args.args[4];
-	rtas_entry = i;
+	rtas_entry = 0;
+	if (call_prom_ret("call-method", 3, 2, &result,
+			  "instantiate-rtas", prom_rtas, rtas_data) == 0)
+		rtas_entry = result;
 	if ((rtas_entry == -1) || (rtas_entry == 0))
 		prom_print(" failed\n");
 	else
@@ -809,7 +796,7 @@ prom_init(int r3, int r4, prom_entry pp)
 	int i, l;
 	char *p, *d;
  	unsigned long phys;
-	void *result[3];
+	prom_arg_t result[3];
 	char model[32];
 	phandle node;
 	int rc;
@@ -820,11 +807,10 @@ prom_init(int r3, int r4, prom_entry pp)
 	/* First get a handle for the stdout device */
 	prom = pp;
 	prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
-	if (prom_chosen == (void *)-1)
+	if (prom_chosen == -1)
 		prom_exit();
-	if ((int) call_prom("getprop", 4, 1, prom_chosen,
-			    "stdout", &prom_stdout,
-			    sizeof(prom_stdout)) <= 0)
+	if (call_prom("getprop", 4, 1, prom_chosen, "stdout",
+		      &prom_stdout, sizeof(prom_stdout)) <= 0)
 		prom_exit();
 
 	/* Get the full OF pathname of the stdout device */
@@ -837,8 +823,7 @@ prom_init(int r3, int r4, prom_entry pp)
 
 	/* Get the boot device and translate it to a full OF pathname. */
 	p = (char *) mem;
-	l = (int) call_prom("getprop", 4, 1, prom_chosen,
-			    "bootpath", p, 1<<20);
+	l = call_prom("getprop", 4, 1, prom_chosen, "bootpath", p, 1<<20);
 	if (l > 0) {
 		p[l] = 0;	/* should already be null-terminated */
 		bootpath = PTRUNRELOC(p);
@@ -885,15 +870,15 @@ prom_init(int r3, int r4, prom_entry pp)
 	 	 */
 		prom_print("(already at 0xc0000000) phys=0\n");
 		phys = 0;
-	} else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
-				 &prom_mmu, sizeof(prom_mmu)) <= 0) {
+	} else if (call_prom("getprop", 4, 1, prom_chosen, "mmu",
+			     &prom_mmu, sizeof(prom_mmu)) <= 0) {
 		prom_print(" no MMU found\n");
-	} else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
-				      prom_mmu, &_stext, 1) != 0) {
+	} else if (call_prom_ret("call-method", 4, 4, result, "translate",
+				 prom_mmu, &_stext, 1) != 0) {
 		prom_print(" (translate failed)\n");
 	} else {
 		/* We assume the phys. address size is 3 cells */
-		phys = (unsigned long)result[2];
+		phys = result[2];
 	}
 
 	if (prom_disp_node != 0)
@@ -916,7 +901,7 @@ prom_init(int r3, int r4, prom_entry pp)
 	prom_print("returning 0x");
 	prom_print_hex(phys);
 	prom_print("from prom_init\n");
-	prom_stdout = NULL;
+	prom_stdout = 0;
 
 	return phys;
 }
diff --git a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c
--- a/arch/ppc/syslib/todc_time.c
+++ b/arch/ppc/syslib/todc_time.c
@@ -287,6 +287,7 @@ todc_get_rtc_time(void)
 		limit = 1;
 
 		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1553:
 			case TODC_TYPE_DS1557:
 			case TODC_TYPE_DS1743:
 			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
@@ -322,6 +323,7 @@ todc_get_rtc_time(void)
 
 	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
 		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1553:
 			case TODC_TYPE_DS1557:
 			case TODC_TYPE_DS1743:
 			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
@@ -418,6 +420,7 @@ static unsigned char __init todc_read_ti
 	unsigned char save_control = 0, val;
 
 	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1553:
 		case TODC_TYPE_DS1557:
 		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 		case TODC_TYPE_DS1747:
@@ -432,6 +435,7 @@ static unsigned char __init todc_read_ti
 	val = todc_read_val(addr);
 
 	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1553:
 		case TODC_TYPE_DS1557:
 		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 		case TODC_TYPE_DS1747:
diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c
--- a/arch/ppc/syslib/xilinx_pic.c
+++ b/arch/ppc/syslib/xilinx_pic.c
@@ -114,6 +114,14 @@ ppc4xx_pic_init(void)
 {
 	int i;
 
+	/*
+	 * NOTE: The assumption here is that NR_IRQS is 32 or less
+	 * (NR_IRQS is 32 for PowerPC 405 cores by default).
+	 */
+#if (NR_IRQS > 32)
+#error NR_IRQS > 32 not supported
+#endif
+
 #if XPAR_XINTC_USE_DCR == 0
 	intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
 
@@ -138,6 +146,12 @@ ppc4xx_pic_init(void)
 
 	ppc_md.get_irq = xilinx_pic_get_irq;
 
-	for (i = 0; i < NR_IRQS; ++i)
+	for (i = 0; i < NR_IRQS; ++i) {
 		irq_desc[i].handler = &xilinx_intc;
+
+		if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
+			irq_desc[i].status &= ~IRQ_LEVEL;
+		else
+			irq_desc[i].status |= IRQ_LEVEL;
+	}
 }
diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
--- a/arch/ppc/xmon/start.c
+++ b/arch/ppc/xmon/start.c
@@ -215,9 +215,7 @@ xmon_map_scc(void)
 	DLAB = 0x80;
 #endif /* platform */
 
-#ifdef CONFIG_MAGIC_SYSRQ
-	__sysrq_put_key_op('x', &sysrq_xmon_op);
-#endif
+	register_sysrq_key('x', &sysrq_xmon_op);
 }
 
 static int scc_initialized = 0;
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
--- a/arch/ppc/xmon/xmon.c
+++ b/arch/ppc/xmon/xmon.c
@@ -1033,9 +1033,9 @@ dump_hash_table_seg(unsigned seg, unsign
 	extern unsigned long Hash_size;
 	unsigned *htab = Hash;
 	unsigned hsize = Hash_size;
-	unsigned v, hmask, va, last_va;
+	unsigned v, hmask, va, last_va = 0;
 	int found, last_found, i;
-	unsigned *hg, w1, last_w2, last_va0;
+	unsigned *hg, w1, last_w2 = 0, last_va0 = 0;
 
 	last_found = 0;
 	hmask = hsize / 64 - 1;
@@ -1492,7 +1492,7 @@ ppc_inst_dump(unsigned adr, int count)
 {
 	int nr, dotted;
 	unsigned first_adr;
-	unsigned long inst, last_inst;
+	unsigned long inst, last_inst = 0;
 	unsigned char val[4];
 
 	dotted = 0;
@@ -1959,7 +1959,7 @@ unsigned long
 xmon_symbol_to_addr(char* symbol)
 {
 	char *p, *cur;
-	char *match;
+	char *match = NULL;
 	int goodness = 0;
 	int result = 0;
 	
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -40,7 +40,7 @@ config COMPAT
 	bool
 	default y
 
-config FRAME_POINTER
+config SCHED_NO_NO_OMIT_FRAME_POINTER
 	bool
 	default y
 
@@ -81,7 +81,6 @@ config PPC_PMAC
 	depends on PPC_MULTIPLATFORM
 	bool "  Apple G5 based machines"
 	default y
-	select ADB_PMU
 	select U3_DART
 
 config PPC_MAPLE
@@ -194,7 +193,10 @@ config NR_CPUS
 
 config HMT
 	bool "Hardware multithreading"
-	depends on SMP && PPC_PSERIES
+	depends on SMP && PPC_PSERIES && BROKEN
+	help
+	  This option enables hardware multithreading on RS64 cpus.
+	  pSeries systems p620 and p660 have such a cpu type.
 
 config DISCONTIGMEM
 	bool "Discontiguous Memory Support"
@@ -253,16 +255,22 @@ config MSCHUNKS
 
 
 config PPC_RTAS
-	bool "Proc interface to RTAS"
+	bool
 	depends on PPC_PSERIES
+	default y
+
+config RTAS_PROC
+	bool "Proc interface to RTAS"
+	depends on PPC_RTAS
+	default y
 
 config RTAS_FLASH
 	tristate "Firmware flash interface"
-	depends on PPC_RTAS
+	depends on RTAS_PROC
 
 config SCANLOG
 	tristate "Scanlog dump interface"
-	depends on PPC_RTAS
+	depends on RTAS_PROC && PPC_PSERIES
 
 config LPARCFG
 	tristate "LPAR Configuration Data"
@@ -271,8 +279,28 @@ config LPARCFG
 	Provide system capacity information via human readable
 	<key word>=<value> pairs through a /proc/ppc64/lparcfg interface.
 
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
+config ISA_DMA_API
+	bool
+	default y
 
 menu "General setup"
 
@@ -313,7 +341,7 @@ source "drivers/pci/Kconfig"
 
 config HOTPLUG_CPU
 	bool "Support for hot-pluggable CPUs"
-	depends on SMP && EXPERIMENTAL && PPC_PSERIES
+	depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
 	select HOTPLUG
 	---help---
 	  Say Y here to be able to turn CPUs off and on.
diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug
--- a/arch/ppc64/Kconfig.debug
+++ b/arch/ppc64/Kconfig.debug
@@ -5,6 +5,9 @@ source "lib/Kconfig.debug"
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
+	help
+	  This option will cause messages to be printed if free stack space
+	  drops below a certain limit.
 
 config KPROBES
 	bool "Kprobes"
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile
+++ b/arch/ppc64/Makefile
@@ -15,17 +15,38 @@
 
 KERNELLOAD	:= 0xc000000000000000
 
+# Set default 32 bits cross compilers for vdso and boot wrapper
+CROSS32_COMPILE ?=
+
+CROSS32CC		:= $(CROSS32_COMPILE)gcc
+CROSS32AS		:= $(CROSS32_COMPILE)as
+CROSS32LD		:= $(CROSS32_COMPILE)ld
+CROSS32OBJCOPY		:= $(CROSS32_COMPILE)objcopy
+
+# If we have a biarch compiler, use it for 32 bits cross compile if
+# CROSS32_COMPILE wasn't explicitely defined, and add proper explicit
+# target type to target compilers
+
 HAS_BIARCH      := $(call cc-option-yn, -m64)
 ifeq ($(HAS_BIARCH),y)
+ifeq ($(CROSS32_COMPILE),)
+CROSS32CC	:= $(CC) -m32
+CROSS32AS	:= $(AS) -a32
+CROSS32LD	:= $(LD) -m elf32ppc
+CROSS32OBJCOPY	:= $(OBJCOPY)
+endif
 AS              := $(AS) -a64
 LD              := $(LD) -m elf64ppc
 CC		:= $(CC) -m64
 endif
 
+export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
+
 new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi)
 
 ifeq ($(new_nm),y)
 NM		:= $(NM) --synthetic
+
 endif
 
 CHECKFLAGS	+= -m64 -D__powerpc__
@@ -35,13 +56,20 @@ LDFLAGS_vmlinux	:= -Bstatic -e $(KERNELL
 CFLAGS		+= -msoft-float -pipe -mminimal-toc -mtraceback=none \
 		   -mcall-aixdesc
 
+GCC_VERSION     := $(call cc-version)
+GCC_BROKEN_VEC	:= $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;)
+
 ifeq ($(CONFIG_POWER4_ONLY),y)
 ifeq ($(CONFIG_ALTIVEC),y)
+ifeq ($(GCC_BROKEN_VEC),y)
 	CFLAGS += $(call cc-option,-mcpu=970)
 else
 	CFLAGS += $(call cc-option,-mcpu=power4)
 endif
 else
+	CFLAGS += $(call cc-option,-mcpu=power4)
+endif
+else
 	CFLAGS += $(call cc-option,-mtune=power4)
 endif
 
@@ -65,14 +93,20 @@ boottarget-$(CONFIG_PPC_ISERIES) := vmli
 $(boottarget-y): vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
-bootimage-$(CONFIG_PPC_PSERIES) := zImage
-bootimage-$(CONFIG_PPC_MAPLE) := zImage
+bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage
+bootimage-$(CONFIG_PPC_PMAC) := vmlinux
+bootimage-$(CONFIG_PPC_MAPLE) := $(boot)/zImage
 bootimage-$(CONFIG_PPC_ISERIES) := vmlinux
 BOOTIMAGE := $(bootimage-y)
 install: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
 
-all: $(BOOTIMAGE)
+defaultimage-$(CONFIG_PPC_PSERIES) := zImage
+defaultimage-$(CONFIG_PPC_PMAC) := vmlinux
+defaultimage-$(CONFIG_PPC_MAPLE) := zImage
+defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux
+KBUILD_IMAGE := $(defaultimage-y)
+all: $(KBUILD_IMAGE)
 
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
--- a/arch/ppc64/boot/Makefile
+++ b/arch/ppc64/boot/Makefile
@@ -20,17 +20,11 @@
 #	CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
 #	in the toplevel makefile.
 
-CROSS32_COMPILE ?=
-#CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux-
 
-BOOTCC		:= $(CROSS32_COMPILE)gcc
 HOSTCC		:= gcc
 BOOTCFLAGS	:= $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin 
-BOOTAS		:= $(CROSS32_COMPILE)as
 BOOTAFLAGS	:= -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional
-BOOTLD		:= $(CROSS32_COMPILE)ld
 BOOTLFLAGS	:= -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds
-BOOTOBJCOPY	:= $(CROSS32_COMPILE)objcopy
 OBJCOPYFLAGS    := contents,alloc,load,readonly,data
 
 src-boot := crt0.S string.S prom.c main.c zlib.c imagesize.c div64.S
@@ -38,10 +32,10 @@ src-boot := $(addprefix $(obj)/, $(src-b
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
 
 quiet_cmd_bootcc = BOOTCC  $@
-      cmd_bootcc = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
+      cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
 
 quiet_cmd_bootas = BOOTAS  $@
-      cmd_bootas = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
+      cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
 	$(call if_changed_dep,bootcc)
@@ -77,15 +71,15 @@ vmlinux.strip: vmlinux FORCE
 $(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE
 	$(call if_changed,ramdisk)
 
-addsection = $(BOOTOBJCOPY) $(1) \
+addsection = $(CROSS32OBJCOPY) $(1) \
 		--add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \
 		--set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(OBJCOPYFLAGS)
 
 quiet_cmd_addnote = ADDNOTE $@ 
-      cmd_addnote = $(BOOTLD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@
+      cmd_addnote = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@
 
 quiet_cmd_piggy = PIGGY   $@
-      cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(BOOTAS) -o $@
+      cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(CROSS32AS) -o $@
 
 $(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE
 	$(call if_changed,gzip)
@@ -117,7 +111,7 @@ $(obj)/imagesize.c: vmlinux.strip
 	awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' \
 		>> $(obj)/imagesize.c
 
-install: $(CONFIGURE) $(obj)/$(BOOTIMAGE)
-	sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(INSTALL_PATH)"
+install: $(CONFIGURE) $(BOOTIMAGE)
+	sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
 
 clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
diff --git a/arch/ppc64/boot/addnote.c b/arch/ppc64/boot/addnote.c
--- a/arch/ppc64/boot/addnote.c
+++ b/arch/ppc64/boot/addnote.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 
+/* CHRP note section */
 char arch[] = "PowerPC";
 
 #define N_DESCR	6
@@ -31,6 +32,29 @@ unsigned int descr[N_DESCR] = {
 	0x4000,			/* load-base */
 };
 
+/* RPA note section */
+char rpaname[] = "IBM,RPA-Client-Config";
+
+/*
+ * Note: setting ignore_my_client_config *should* mean that OF ignores
+ * all the other fields, but there is a firmware bug which means that
+ * it looks at the splpar field at least.  So these values need to be
+ * reasonable.
+ */
+#define N_RPA_DESCR	8
+unsigned int rpanote[N_RPA_DESCR] = {
+	0,			/* lparaffinity */
+	64,			/* min_rmo_size */
+	0,			/* min_rmo_percent */
+	40,			/* max_pft_size */
+	1,			/* splpar */
+	-1,			/* min_load */
+	0,			/* new_mem_def */
+	1,			/* ignore_my_client_config */
+};
+
+#define ROUNDUP(len)	(((len) + 3) & ~3)
+
 unsigned char buf[512];
 
 #define GET_16BE(off)	((buf[off] << 8) + (buf[(off)+1]))
@@ -69,7 +93,7 @@ main(int ac, char **av)
 {
 	int fd, n, i;
 	int ph, ps, np;
-	int nnote, ns;
+	int nnote, nnote2, ns;
 
 	if (ac != 2) {
 		fprintf(stderr, "Usage: %s elf-file\n", av[0]);
@@ -81,7 +105,8 @@ main(int ac, char **av)
 		exit(1);
 	}
 
-	nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4;
+	nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
+	nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
 
 	n = read(fd, buf, sizeof(buf));
 	if (n < 0) {
@@ -104,7 +129,7 @@ main(int ac, char **av)
 	np = GET_16BE(E_PHNUM);
 	if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
 		goto notelf;
-	if (ph + (np + 1) * ps + nnote > n)
+	if (ph + (np + 2) * ps + nnote + nnote2 > n)
 		goto nospace;
 
 	for (i = 0; i < np; ++i) {
@@ -117,12 +142,12 @@ main(int ac, char **av)
 	}
 
 	/* XXX check that the area we want to use is all zeroes */
-	for (i = 0; i < ps + nnote; ++i)
+	for (i = 0; i < 2 * ps + nnote + nnote2; ++i)
 		if (buf[ph + i] != 0)
 			goto nospace;
 
 	/* fill in the program header entry */
-	ns = ph + ps;
+	ns = ph + 2 * ps;
 	PUT_32BE(ph + PH_TYPE, PT_NOTE);
 	PUT_32BE(ph + PH_OFFSET, ns);
 	PUT_32BE(ph + PH_FILESZ, nnote);
@@ -134,11 +159,26 @@ main(int ac, char **av)
 	PUT_32BE(ns + 8, 0x1275);
 	strcpy(&buf[ns + 12], arch);
 	ns += 12 + strlen(arch) + 1;
-	for (i = 0; i < N_DESCR; ++i)
-		PUT_32BE(ns + i * 4, descr[i]);
+	for (i = 0; i < N_DESCR; ++i, ns += 4)
+		PUT_32BE(ns, descr[i]);
+
+	/* fill in the second program header entry and the RPA note area */
+	ph += ps;
+	PUT_32BE(ph + PH_TYPE, PT_NOTE);
+	PUT_32BE(ph + PH_OFFSET, ns);
+	PUT_32BE(ph + PH_FILESZ, nnote2);
+
+	/* fill in the note area we point to */
+	PUT_32BE(ns, strlen(rpaname) + 1);
+	PUT_32BE(ns + 4, sizeof(rpanote));
+	PUT_32BE(ns + 8, 0x12759999);
+	strcpy(&buf[ns + 12], rpaname);
+	ns += 12 + ROUNDUP(strlen(rpaname) + 1);
+	for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
+		PUT_32BE(ns, rpanote[i]);
 
 	/* Update the number of program headers */
-	PUT_16BE(E_PHNUM, np + 1);
+	PUT_16BE(E_PHNUM, np + 2);
 
 	/* write back */
 	lseek(fd, (long) 0, SEEK_SET);
@@ -155,11 +195,11 @@ main(int ac, char **av)
 	exit(0);
 
  notelf:
-	fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]);
+	fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]);
 	exit(1);
 
  nospace:
 	fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
-		av[0]);
+		av[1]);
 	exit(1);
 }
diff --git a/arch/ppc64/boot/install.sh b/arch/ppc64/boot/install.sh
--- a/arch/ppc64/boot/install.sh
+++ b/arch/ppc64/boot/install.sh
@@ -17,6 +17,7 @@
 #   $2 - kernel image file
 #   $3 - kernel map file
 #   $4 - default install path (blank if root directory)
+#   $5 - kernel boot file, the zImage
 #
 
 # User may have a custom install script
@@ -27,7 +28,7 @@ if [ -x /sbin/installkernel ]; then exec
 # Default install
 
 # this should work for both the pSeries zImage and the iSeries vmlinux.sm
-image_name=`basename $2`
+image_name=`basename $5`
 
 if [ -f $4/$image_name ]; then
 	mv $4/$image_name $4/$image_name.old
diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c
--- a/arch/ppc64/boot/main.c
+++ b/arch/ppc64/boot/main.c
@@ -14,7 +14,6 @@
 #include <linux/string.h>
 #include <asm/processor.h>
 #include <asm/page.h>
-#include <asm/bootinfo.h>
 
 extern void *finddevice(const char *);
 extern int getprop(void *, const char *, void *, int);
@@ -112,7 +111,7 @@ void start(unsigned long a1, unsigned lo
 	if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
 		exit();
 
-	printf("zImage starting: loaded at 0x%x\n\r", (unsigned)_start);
+	printf("\n\rzImage starting: loaded at 0x%x\n\r", (unsigned)_start);
 
 	/*
 	 * Now we try to claim some memory for the kernel itself
@@ -151,7 +150,7 @@ void start(unsigned long a1, unsigned lo
 		printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
 		       initrd.addr, (unsigned long)_initrd_start, initrd.size);
 		memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
-		printf("initrd head: 0x%lx\n", *((u32 *)initrd.addr));
+		printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
 	}
 
 	/* Eventually gunzip the kernel */
@@ -200,7 +199,7 @@ void start(unsigned long a1, unsigned lo
 	vmlinux.addr += (unsigned long)elf64ph->p_offset;
 	vmlinux.size -= (unsigned long)elf64ph->p_offset;
 
-	flush_cache((void *)vmlinux.addr, vmlinux.memsize);
+	flush_cache((void *)vmlinux.addr, vmlinux.size);
 
 	if (a1)
 		printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
diff --git a/arch/ppc64/boot/no_initrd.c b/arch/ppc64/boot/no_initrd.c
deleted file mode 100644
--- a/arch/ppc64/boot/no_initrd.c
+++ /dev/null
@@ -1,2 +0,0 @@
-char initrd_data[1];
-int initrd_len = 0;
diff --git a/arch/ppc64/boot/prom.c b/arch/ppc64/boot/prom.c
--- a/arch/ppc64/boot/prom.c
+++ b/arch/ppc64/boot/prom.c
@@ -11,6 +11,23 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+extern __u32 __div64_32(unsigned long long *dividend, __u32 divisor);
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({				\
+	__u32 __base = (base);			\
+	__u32 __rem;					\
+	(void)(((typeof((n)) *)0) == ((unsigned long long *)0));	\
+	if (((n) >> 32) == 0) {			\
+		__rem = (__u32)(n) % __base;		\
+		(n) = (__u32)(n) / __base;		\
+	} else 						\
+		__rem = __div64_32(&(n), __base);	\
+	__rem;						\
+ })
+
 int (*prom)(void *);
 
 void *chosen_handle;
@@ -352,7 +369,7 @@ static int skip_atoi(const char **s)
 #define SPECIAL	32		/* 0x */
 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
 
-static char * number(char * str, long num, int base, int size, int precision, int type)
+static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
 {
 	char c,sign,tmp[66];
 	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
@@ -367,9 +384,9 @@ static char * number(char * str, long nu
 	c = (type & ZEROPAD) ? '0' : ' ';
 	sign = 0;
 	if (type & SIGN) {
-		if (num < 0) {
+		if ((signed long long)num < 0) {
 			sign = '-';
-			num = -num;
+			num = - (signed long long)num;
 			size--;
 		} else if (type & PLUS) {
 			sign = '+';
@@ -389,8 +406,7 @@ static char * number(char * str, long nu
 	if (num == 0)
 		tmp[i++]='0';
 	else while (num != 0) {
-		tmp[i++] = digits[num % base];
-		num /= base;
+		tmp[i++] = digits[do_div(num, base)];
 	}
 	if (i > precision)
 		precision = i;
@@ -426,7 +442,7 @@ int sprintf(char * buf, const char *fmt,
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
 	int len;
-	unsigned long num;
+	unsigned long long num;
 	int i, base;
 	char * str;
 	const char *s;
diff --git a/arch/ppc64/boot/start.c b/arch/ppc64/boot/start.c
deleted file mode 100644
--- a/arch/ppc64/boot/start.c
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it 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 <stdarg.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-#include <asm/div64.h>
-
-int (*prom)(void *);
-
-void *chosen_handle;
-void *stdin;
-void *stdout;
-void *stderr;
-
-void exit(void);
-void *finddevice(const char *name);
-int getprop(void *phandle, const char *name, void *buf, int buflen);
-void chrpboot(int a1, int a2, void *prom);	/* in main.c */
-
-void printk(char *fmt, ...);
-
-void
-start(int a1, int a2, void *promptr)
-{
-	prom = (int (*)(void *)) promptr;
-	chosen_handle = finddevice("/chosen");
-	if (chosen_handle == (void *) -1)
-		exit();
-	if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
-		exit();
-	stderr = stdout;
-	if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-	exit();
-
-	chrpboot(a1, a2, promptr);
-	for (;;)
-		exit();
-}
-
-int
-write(void *handle, void *ptr, int nb)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		void *ihandle;
-		void *addr;
-		int len;
-		int actual;
-	} args;
-
-	args.service = "write";
-	args.nargs = 3;
-	args.nret = 1;
-	args.ihandle = handle;
-	args.addr = ptr;
-	args.len = nb;
-	args.actual = -1;
-	(*prom)(&args);
-	return args.actual;
-}
-
-int
-read(void *handle, void *ptr, int nb)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		void *ihandle;
-		void *addr;
-		int len;
-		int actual;
-	} args;
-
-	args.service = "read";
-	args.nargs = 3;
-	args.nret = 1;
-	args.ihandle = handle;
-	args.addr = ptr;
-	args.len = nb;
-	args.actual = -1;
-	(*prom)(&args);
-	return args.actual;
-}
-
-void
-exit()
-{
-	struct prom_args {
-		char *service;
-	} args;
-
-	for (;;) {
-		args.service = "exit";
-		(*prom)(&args);
-	}
-}
-
-void
-pause(void)
-{
-	struct prom_args {
-		char *service;
-	} args;
-
-	args.service = "enter";
-	(*prom)(&args);
-}
-
-void *
-finddevice(const char *name)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		const char *devspec;
-		void *phandle;
-	} args;
-
-	args.service = "finddevice";
-	args.nargs = 1;
-	args.nret = 1;
-	args.devspec = name;
-	args.phandle = (void *) -1;
-	(*prom)(&args);
-	return args.phandle;
-}
-
-void *
-claim(unsigned long virt, unsigned long size, unsigned long align)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		unsigned int virt;
-		unsigned int size;
-		unsigned int align;
-		void *ret;
-	} args;
-
-	args.service = "claim";
-	args.nargs = 3;
-	args.nret = 1;
-	args.virt = virt;
-	args.size = size;
-	args.align = align;
-	(*prom)(&args);
-	return args.ret;
-}
-
-int
-getprop(void *phandle, const char *name, void *buf, int buflen)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		void *phandle;
-		const char *name;
-		void *buf;
-		int buflen;
-		int size;
-	} args;
-
-	args.service = "getprop";
-	args.nargs = 4;
-	args.nret = 1;
-	args.phandle = phandle;
-	args.name = name;
-	args.buf = buf;
-	args.buflen = buflen;
-	args.size = -1;
-	(*prom)(&args);
-	return args.size;
-}
-
-int
-putc(int c, void *f)
-{
-	char ch = c;
-
-	if (c == '\n')
-		putc('\r', f);
-	return write(f, &ch, 1) == 1? c: -1;
-}
-
-int
-putchar(int c)
-{
-	return putc(c, stdout);
-}
-
-int
-fputs(char *str, void *f)
-{
-	int n = strlen(str);
-
-	return write(f, str, n) == n? 0: -1;
-}
-
-int
-readchar(void)
-{
-	char ch;
-
-	for (;;) {
-		switch (read(stdin, &ch, 1)) {
-		case 1:
-			return ch;
-		case -1:
-			printk("read(stdin) returned -1\r\n");
-			return -1;
-		}
-	}
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
-	int c;
-
-	if (lineleft == 0) {
-		lineptr = line;
-		for (;;) {
-			c = readchar();
-			if (c == -1 || c == 4)
-				break;
-			if (c == '\r' || c == '\n') {
-				*lineptr++ = '\n';
-				putchar('\n');
-				break;
-			}
-			switch (c) {
-			case 0177:
-			case '\b':
-				if (lineptr > line) {
-					putchar('\b');
-					putchar(' ');
-					putchar('\b');
-					--lineptr;
-				}
-				break;
-			case 'U' & 0x1F:
-				while (lineptr > line) {
-					putchar('\b');
-					putchar(' ');
-					putchar('\b');
-					--lineptr;
-				}
-				break;
-			default:
-				if (lineptr >= &line[sizeof(line) - 1])
-					putchar('\a');
-				else {
-					putchar(c);
-					*lineptr++ = c;
-				}
-			}
-		}
-		lineleft = lineptr - line;
-		lineptr = line;
-	}
-	if (lineleft == 0)
-		return -1;
-	--lineleft;
-	return *lineptr++;
-}
-
-
-
-/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
-unsigned char _ctype[] = {
-_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
-_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
-_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
-_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
-_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
-_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
-_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
-_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
-_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
-_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
-_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
-_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
-_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
-_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
-_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
-_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
-_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
-_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
-_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
-_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
-
-size_t strnlen(const char * s, size_t count)
-{
-	const char *sc;
-
-	for (sc = s; count-- && *sc != '\0'; ++sc)
-		/* nothing */;
-	return sc - s;
-}
-
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
-	unsigned long result = 0,value;
-
-	if (!base) {
-		base = 10;
-		if (*cp == '0') {
-			base = 8;
-			cp++;
-			if ((*cp == 'x') && isxdigit(cp[1])) {
-				cp++;
-				base = 16;
-			}
-		}
-	}
-	while (isxdigit(*cp) &&
-	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
-		result = result*base + value;
-		cp++;
-	}
-	if (endp)
-		*endp = (char *)cp;
-	return result;
-}
-
-long simple_strtol(const char *cp,char **endp,unsigned int base)
-{
-	if(*cp=='-')
-		return -simple_strtoul(cp+1,endp,base);
-	return simple_strtoul(cp,endp,base);
-}
-
-static int skip_atoi(const char **s)
-{
-	int i=0;
-
-	while (isdigit(**s))
-		i = i*10 + *((*s)++) - '0';
-	return i;
-}
-
-#define ZEROPAD	1		/* pad with zero */
-#define SIGN	2		/* unsigned/signed long */
-#define PLUS	4		/* show plus */
-#define SPACE	8		/* space if plus */
-#define LEFT	16		/* left justified */
-#define SPECIAL	32		/* 0x */
-#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
-
-static char * number(char * str, long long num, int base, int size, int precision, int type)
-{
-	char c,sign,tmp[66];
-	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
-	int i;
-
-	if (type & LARGE)
-		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	if (type & LEFT)
-		type &= ~ZEROPAD;
-	if (base < 2 || base > 36)
-		return 0;
-	c = (type & ZEROPAD) ? '0' : ' ';
-	sign = 0;
-	if (type & SIGN) {
-		if (num < 0) {
-			sign = '-';
-			num = -num;
-			size--;
-		} else if (type & PLUS) {
-			sign = '+';
-			size--;
-		} else if (type & SPACE) {
-			sign = ' ';
-			size--;
-		}
-	}
-	if (type & SPECIAL) {
-		if (base == 16)
-			size -= 2;
-		else if (base == 8)
-			size--;
-	}
-	i = 0;
-	if (num == 0)
-		tmp[i++]='0';
-	else while (num != 0)
-		tmp[i++] = digits[do_div(num,base)];
-	if (i > precision)
-		precision = i;
-	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
-	if (sign)
-		*str++ = sign;
-	if (type & SPECIAL) {
-		if (base==8)
-			*str++ = '0';
-		else if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
-		}
-	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
-}
-
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
-
-int vsprintf(char *buf, const char *fmt, va_list args)
-{
-	int len;
-	unsigned long long num;
-	int i, base;
-	char * str;
-	const char *s;
-
-	int flags;		/* flags to number() */
-
-	int field_width;	/* width of output field */
-	int precision;		/* min. # of digits for integers; max
-				   number of chars for from string */
-	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
-	                        /* 'z' support added 23/7/1999 S.H.    */
-				/* 'z' changed to 'Z' --davidm 1/25/99 */
-
-	
-	for (str=buf ; *fmt ; ++fmt) {
-		if (*fmt != '%') {
-			*str++ = *fmt;
-			continue;
-		}
-			
-		/* process flags */
-		flags = 0;
-		repeat:
-			++fmt;		/* this also skips first '%' */
-			switch (*fmt) {
-				case '-': flags |= LEFT; goto repeat;
-				case '+': flags |= PLUS; goto repeat;
-				case ' ': flags |= SPACE; goto repeat;
-				case '#': flags |= SPECIAL; goto repeat;
-				case '0': flags |= ZEROPAD; goto repeat;
-				}
-		
-		/* get field width */
-		field_width = -1;
-		if (isdigit(*fmt))
-			field_width = skip_atoi(&fmt);
-		else if (*fmt == '*') {
-			++fmt;
-			/* it's the next argument */
-			field_width = va_arg(args, int);
-			if (field_width < 0) {
-				field_width = -field_width;
-				flags |= LEFT;
-			}
-		}
-
-		/* get the precision */
-		precision = -1;
-		if (*fmt == '.') {
-			++fmt;	
-			if (isdigit(*fmt))
-				precision = skip_atoi(&fmt);
-			else if (*fmt == '*') {
-				++fmt;
-				/* it's the next argument */
-				precision = va_arg(args, int);
-			}
-			if (precision < 0)
-				precision = 0;
-		}
-
-		/* get the conversion qualifier */
-		qualifier = -1;
-		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
-			qualifier = *fmt;
-			++fmt;
-		}
-
-		/* default base */
-		base = 10;
-
-		switch (*fmt) {
-		case 'c':
-			if (!(flags & LEFT))
-				while (--field_width > 0)
-					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
-				*str++ = ' ';
-			continue;
-
-		case 's':
-			s = va_arg(args, char *);
-			if (!s)
-				s = "<NULL>";
-
-			len = strnlen(s, precision);
-
-			if (!(flags & LEFT))
-				while (len < field_width--)
-					*str++ = ' ';
-			for (i = 0; i < len; ++i)
-				*str++ = *s++;
-			while (len < field_width--)
-				*str++ = ' ';
-			continue;
-
-		case 'p':
-			if (field_width == -1) {
-				field_width = 2*sizeof(void *);
-				flags |= ZEROPAD;
-			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
-			continue;
-
-
-		case 'n':
-			if (qualifier == 'l') {
-				long * ip = va_arg(args, long *);
-				*ip = (str - buf);
-			} else if (qualifier == 'Z') {
-				size_t * ip = va_arg(args, size_t *);
-				*ip = (str - buf);
-			} else {
-				int * ip = va_arg(args, int *);
-				*ip = (str - buf);
-			}
-			continue;
-
-		case '%':
-			*str++ = '%';
-			continue;
-
-		/* integer number formats - set up the flags and "break" */
-		case 'o':
-			base = 8;
-			break;
-
-		case 'X':
-			flags |= LARGE;
-		case 'x':
-			base = 16;
-			break;
-
-		case 'd':
-		case 'i':
-			flags |= SIGN;
-		case 'u':
-			break;
-
-		default:
-			*str++ = '%';
-			if (*fmt)
-				*str++ = *fmt;
-			else
-				--fmt;
-			continue;
-		}
-		if (qualifier == 'L')
-			num = va_arg(args, long long);
-		else if (qualifier == 'l') {
-			num = va_arg(args, unsigned long);
-			if (flags & SIGN)
-				num = (signed long) num;
-		} else if (qualifier == 'Z') {
-			num = va_arg(args, size_t);
-		} else if (qualifier == 'h') {
-			num = (unsigned short) va_arg(args, int);
-			if (flags & SIGN)
-				num = (signed short) num;
-		} else {
-			num = va_arg(args, unsigned int);
-			if (flags & SIGN)
-				num = (signed int) num;
-		}
-		str = number(str, num, base, field_width, precision, flags);
-	}
-	*str = '\0';
-	return str-buf;
-}
-
-int sprintf(char * buf, const char *fmt, ...)
-{
-	va_list args;
-	int i;
-
-	va_start(args, fmt);
-	i=vsprintf(buf,fmt,args);
-	va_end(args);
-	return i;
-}
-
-static char sprint_buf[1024];
-
-void
-printk(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	write(stdout, sprint_buf, n);
-}
-
-int
-printf(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	write(stdout, sprint_buf, n);
-	return n;
-}
diff --git a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds
--- a/arch/ppc64/boot/zImage.lds
+++ b/arch/ppc64/boot/zImage.lds
@@ -1,4 +1,4 @@
-OUTPUT_ARCH(powerpc)
+OUTPUT_ARCH(powerpc:common)
 SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
 /* Do we need any of these for elf?
    __DYNAMIC = 0;    */
diff --git a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig
--- a/arch/ppc64/configs/g5_defconfig
+++ b/arch/ppc64/configs/g5_defconfig
@@ -1,16 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc3
-# Thu Oct  7 15:18:38 2004
+# Linux kernel version: 2.6.12-rc6
+# Tue Jun 14 16:59:20 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
-CONFIG_FRAME_POINTER=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_FORCE_MAX_ZONEORDER=13
 
 #
@@ -18,6 +19,8 @@ CONFIG_FORCE_MAX_ZONEORDER=13
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -25,36 +28,42 @@ CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=17
 CONFIG_HOTPLUG=y
-# CONFIG_IKCONFIG is not set
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
 CONFIG_SYSVIPC_COMPAT=y
 
@@ -65,6 +74,7 @@ CONFIG_SYSVIPC_COMPAT=y
 CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_PPC_PSERIES is not set
 CONFIG_PPC_PMAC=y
+# CONFIG_PPC_MAPLE is not set
 CONFIG_PPC=y
 CONFIG_PPC64=y
 CONFIG_PPC_OF=y
@@ -75,12 +85,12 @@ CONFIG_BOOTX_TEXT=y
 CONFIG_POWER4_ONLY=y
 CONFIG_IOMMU_VMERGE=y
 CONFIG_SMP=y
-CONFIG_IRQ_ALL_CPUS=y
 CONFIG_NR_CPUS=2
 # CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_PPC_RTAS is not set
-# CONFIG_LPARCFG is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # General setup
@@ -91,12 +101,13 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 # CONFIG_HOTPLUG_CPU is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -139,14 +150,29 @@ CONFIG_FW_LOADER=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -161,11 +187,10 @@ CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDETAPE=y
-CONFIG_BLK_DEV_IDEFLOPPY=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
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -205,7 +230,6 @@ CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 # CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set
-CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
@@ -240,6 +264,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -254,30 +279,28 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 CONFIG_SCSI_SATA=y
+# CONFIG_SCSI_SATA_AHCI is not set
 CONFIG_SCSI_SATA_SVW=y
 # CONFIG_SCSI_ATA_PIIX is not set
 # CONFIG_SCSI_SATA_NV is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
 # CONFIG_SCSI_SATA_SX4 is not set
 # CONFIG_SCSI_SATA_SIL is not set
 # CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
 # CONFIG_SCSI_SATA_VIA is not set
 # CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR 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_QLA2XXX=y
@@ -286,11 +309,10 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -300,15 +322,17 @@ CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
-# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID10=m
 CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID6 is not set
-# CONFIG_MD_MULTIPATH is not set
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=y
-# CONFIG_DM_CRYPT is not set
-# CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+# CONFIG_DM_MULTIPATH is not set
 
 #
 # Fusion MPT device support
@@ -355,6 +379,7 @@ CONFIG_IEEE1394_RAWIO=y
 #
 CONFIG_ADB=y
 CONFIG_ADB_PMU=y
+CONFIG_PMAC_SMU=y
 # CONFIG_PMAC_PBOOK is not set
 # CONFIG_PMAC_BACKLIGHT is not set
 # CONFIG_INPUT_ADBHID is not set
@@ -370,7 +395,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -386,6 +410,8 @@ CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 CONFIG_INET_TUNNEL=y
+CONFIG_IP_TCPDIAG=m
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -398,61 +424,71 @@ CONFIG_NETFILTER=y
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=y
-# CONFIG_IP_NF_CT_ACCT is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-# CONFIG_IP_NF_FTP is not set
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-CONFIG_IP_NF_QUEUE=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_LIMIT=y
-CONFIG_IP_NF_MATCH_IPRANGE=y
-CONFIG_IP_NF_MATCH_MAC=y
-CONFIG_IP_NF_MATCH_PKTTYPE=y
-CONFIG_IP_NF_MATCH_MARK=y
-CONFIG_IP_NF_MATCH_MULTIPORT=y
-CONFIG_IP_NF_MATCH_TOS=y
-CONFIG_IP_NF_MATCH_RECENT=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_DSCP=y
-CONFIG_IP_NF_MATCH_AH_ESP=y
-CONFIG_IP_NF_MATCH_LENGTH=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_MATCH_TCPMSS=y
-CONFIG_IP_NF_MATCH_HELPER=y
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
-CONFIG_IP_NF_MATCH_OWNER=y
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_IP_NF_TARGET_TCPMSS=y
-CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=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_RECENT=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_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_MATCH_COMMENT=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_SAME=y
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_TOS=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_DSCP=y
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_CLASSIFY=y
-# CONFIG_IP_NF_RAW is not set
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=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_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -471,13 +507,12 @@ CONFIG_LLC=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -529,6 +564,8 @@ CONFIG_E1000=y
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=m
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -587,7 +624,7 @@ CONFIG_INPUT=y
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 CONFIG_INPUT_JOYDEV=m
@@ -596,18 +633,6 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -625,6 +650,16 @@ CONFIG_INPUT_MOUSE=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -641,6 +676,7 @@ CONFIG_HW_CONSOLE=y
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_PMACZILOG is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -663,10 +699,17 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
+CONFIG_AGP=m
+CONFIG_AGP_UNINORTH=m
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -691,6 +734,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 CONFIG_I2C_KEYWEST=y
 # CONFIG_I2C_NFORCE2 is not set
@@ -701,6 +745,7 @@ CONFIG_I2C_KEYWEST=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -712,20 +757,29 @@ CONFIG_I2C_KEYWEST=y
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -735,6 +789,7 @@ CONFIG_I2C_KEYWEST=y
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
@@ -767,7 +822,13 @@ CONFIG_I2C_KEYWEST=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+CONFIG_FB_MACMODES=y
 CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
@@ -779,6 +840,7 @@ CONFIG_FB_OF=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_VGA16 is not set
+# CONFIG_FB_NVIDIA is not set
 CONFIG_FB_RIVA=y
 # CONFIG_FB_RIVA_I2C is not set
 # CONFIG_FB_RIVA_DEBUG is not set
@@ -789,12 +851,14 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_FB_RADEON_DEBUG is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -814,6 +878,11 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
 
 #
 # Sound
@@ -823,6 +892,8 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -841,7 +912,10 @@ CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -849,20 +923,23 @@ CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_BLUETOOTH_TTY is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT is not set
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
 CONFIG_USB_STORAGE_ISD200=y
 CONFIG_USB_STORAGE_DPCM=y
-CONFIG_USB_STORAGE_HP8200e=y
+# CONFIG_USB_STORAGE_USBAT is not set
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
@@ -885,7 +962,6 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -897,12 +973,12 @@ CONFIG_USB_HIDDEV=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
 CONFIG_USB_USBNET=m
 
 #
@@ -914,6 +990,7 @@ CONFIG_USB_BELKIN=y
 CONFIG_USB_GENESYS=y
 CONFIG_USB_NET1080=y
 CONFIG_USB_PL2301=y
+CONFIG_USB_KC2190=y
 
 #
 # Intelligent USB Devices/Gadgets
@@ -927,6 +1004,7 @@ CONFIG_USB_CDCETHER=y
 # USB Network Adapters
 #
 CONFIG_USB_AX8817X=y
+CONFIG_USB_MON=y
 
 #
 # USB port drivers
@@ -937,8 +1015,11 @@ CONFIG_USB_AX8817X=y
 #
 CONFIG_USB_SERIAL=m
 CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRPRIME is not set
 CONFIG_USB_SERIAL_BELKIN=m
 CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP2101 is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
 CONFIG_USB_SERIAL_EMPEG=m
 CONFIG_USB_SERIAL_FTDI_SIO=m
 CONFIG_USB_SERIAL_VISOR=m
@@ -946,6 +1027,8 @@ CONFIG_USB_SERIAL_IPAQ=m
 CONFIG_USB_SERIAL_IR=m
 CONFIG_USB_SERIAL_EDGEPORT=m
 CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
 CONFIG_USB_SERIAL_KEYSPAN=m
 CONFIG_USB_SERIAL_KEYSPAN_MPR=y
@@ -964,8 +1047,10 @@ CONFIG_USB_SERIAL_KLSI=m
 CONFIG_USB_SERIAL_KOBIL_SCT=m
 CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
 CONFIG_USB_SERIAL_SAFE=m
 CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_TI=m
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
 CONFIG_USB_SERIAL_OMNINET=m
@@ -976,42 +1061,73 @@ CONFIG_USB_EZUSB=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB ATM/DSL drivers
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
+
+#
+# XFS support
+#
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=m
 # CONFIG_AUTOFS4_FS is not set
 
@@ -1019,8 +1135,9 @@ CONFIG_AUTOFS_FS=m
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
 CONFIG_UDF_FS=m
 CONFIG_UDF_NLS=y
 
@@ -1044,6 +1161,8 @@ CONFIG_SYSFS=y
 CONFIG_DEVPTS_FS_XATTR=y
 # CONFIG_DEVPTS_FS_SECURITY is not set
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1053,8 +1172,8 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -1087,7 +1206,7 @@ CONFIG_RPCSEC_GSS_KRB5=y
 CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
 # CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_POSIX is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
@@ -1117,7 +1236,7 @@ CONFIG_MSDOS_PARTITION=y
 #
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1138,10 +1257,10 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1151,10 +1270,10 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=y
 
 #
 # Profiling support
@@ -1165,21 +1284,28 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_KPROBES is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUGGER is not set
 # CONFIG_PPCDBG is not set
 CONFIG_IRQSTACKS=y
-# CONFIG_SCHEDSTATS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1193,7 +1319,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_WP512=m
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -1201,19 +1328,24 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
-# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
-# CONFIG_CRYPTO_KHAZAD is not set
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
-# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
 CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
+CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/ppc64/configs/iSeries_defconfig b/arch/ppc64/configs/iSeries_defconfig
--- a/arch/ppc64/configs/iSeries_defconfig
+++ b/arch/ppc64/configs/iSeries_defconfig
@@ -1,14 +1,17 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc6
+# Tue Jun 14 17:01:28 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
-CONFIG_FRAME_POINTER=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_FORCE_MAX_ZONEORDER=13
 
 #
@@ -16,10 +19,13 @@ CONFIG_FORCE_MAX_ZONEORDER=13
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -27,23 +33,27 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
 CONFIG_AUDITSYSCALL=y
-CONFIG_LOG_BUF_SHIFT=17
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -52,8 +62,9 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
 CONFIG_SYSVIPC_COMPAT=y
 
@@ -61,17 +72,21 @@ CONFIG_SYSVIPC_COMPAT=y
 # Platform support
 #
 CONFIG_PPC_ISERIES=y
-# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_MULTIPLATFORM is not set
 CONFIG_PPC=y
 CONFIG_PPC64=y
+CONFIG_IBMVIO=y
 # CONFIG_POWER4_ONLY is not set
 CONFIG_IOMMU_VMERGE=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
 # CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_MSCHUNKS=y
 CONFIG_LPARCFG=y
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # General setup
@@ -82,12 +97,12 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_PCI_DEBUG is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -128,13 +143,26 @@ CONFIG_FW_LOADER=m
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -169,6 +197,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
@@ -186,15 +215,14 @@ CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
 CONFIG_SCSI_IBMVSCSI=m
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR 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_QLA2XXX=y
@@ -203,7 +231,7 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -220,11 +248,13 @@ CONFIG_MD_RAID10=m
 CONFIG_MD_RAID5=y
 CONFIG_MD_RAID6=m
 CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+# CONFIG_DM_MULTIPATH is not set
 
 #
 # Fusion MPT device support
@@ -255,7 +285,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -271,6 +300,8 @@ CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 CONFIG_INET_TUNNEL=y
+CONFIG_IP_TCPDIAG=m
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -284,6 +315,9 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CT_PROTO_SCTP=m
 CONFIG_IP_NF_FTP=m
 CONFIG_IP_NF_IRC=m
 CONFIG_IP_NF_TFTP=m
@@ -308,8 +342,17 @@ CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
 CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_MATCH_COMMENT=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -327,21 +370,13 @@ CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
 CONFIG_IP_NF_TARGET_MARK=m
 CONFIG_IP_NF_TARGET_CLASSIFY=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-# CONFIG_IP_NF_CT_ACCT is not set
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_CT_PROTO_SCTP=m
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -362,7 +397,6 @@ CONFIG_LLC=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -415,7 +449,6 @@ CONFIG_PCNET32=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -425,20 +458,23 @@ CONFIG_E100=y
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -498,7 +534,7 @@ CONFIG_INPUT=y
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
@@ -507,17 +543,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -527,6 +552,12 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 # CONFIG_SERIAL_NONSTANDARD is not set
@@ -541,6 +572,7 @@ CONFIG_SERIO_SERPORT=y
 #
 CONFIG_SERIAL_CORE=m
 CONFIG_SERIAL_ICOM=m
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -567,6 +599,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -605,6 +643,8 @@ CONFIG_MAX_RAW_DEVS=256
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB is not set
 
 #
@@ -613,16 +653,26 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -631,20 +681,27 @@ CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_PROC_INFO is not set
 CONFIG_REISERFS_FS_XATTR=y
 CONFIG_REISERFS_FS_POSIX_ACL=y
-# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_REISERFS_FS_SECURITY=y
 CONFIG_JFS_FS=m
 CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=m
 # CONFIG_AUTOFS4_FS is not set
 
@@ -652,8 +709,9 @@ CONFIG_AUTOFS_FS=m
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
 CONFIG_UDF_FS=m
 CONFIG_UDF_NLS=y
 
@@ -675,8 +733,10 @@ CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 CONFIG_DEVPTS_FS_XATTR=y
-# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_DEVPTS_FS_SECURITY=y
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -721,6 +781,7 @@ CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
 CONFIG_CIFS_XATTR=y
 CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
@@ -793,21 +854,28 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_KPROBES is not set
 CONFIG_DEBUG_STACK_USAGE=y
 # CONFIG_DEBUGGER is not set
 # CONFIG_PPCDBG is not set
-# CONFIG_IRQSTACKS is not set
-# CONFIG_SCHEDSTATS is not set
+CONFIG_IRQSTACKS=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -821,7 +889,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WHIRLPOOL=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -832,12 +901,17 @@ CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/ppc64/configs/maple_defconfig b/arch/ppc64/configs/maple_defconfig
--- a/arch/ppc64/configs/maple_defconfig
+++ b/arch/ppc64/configs/maple_defconfig
@@ -1,16 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9
-# Wed Oct 20 15:39:14 2004
+# Linux kernel version: 2.6.12-rc6
+# Tue Jun 14 17:12:48 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
-CONFIG_FRAME_POINTER=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_FORCE_MAX_ZONEORDER=13
 
 #
@@ -18,6 +19,8 @@ CONFIG_FORCE_MAX_ZONEORDER=13
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -25,36 +28,41 @@ CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
 CONFIG_SYSVIPC_COMPAT=y
@@ -77,10 +85,12 @@ CONFIG_BOOTX_TEXT=y
 CONFIG_POWER4_ONLY=y
 CONFIG_IOMMU_VMERGE=y
 CONFIG_SMP=y
-# CONFIG_IRQ_ALL_CPUS is not set
 CONFIG_NR_CPUS=2
 # CONFIG_SCHED_SMT is not set
 # CONFIG_PREEMPT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # General setup
@@ -91,6 +101,17 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 
@@ -103,6 +124,7 @@ CONFIG_PROC_DEVICETREE=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -127,13 +149,26 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -151,7 +186,6 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 CONFIG_IDE_TASK_IOCTL=y
-CONFIG_IDE_TASKFILE_IO=y
 
 #
 # IDE chipset support/bugfixes
@@ -231,7 +265,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -250,6 +283,8 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -269,7 +304,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -330,7 +364,6 @@ CONFIG_AMD8111_ETH=y
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -344,7 +377,10 @@ CONFIG_E1000=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -401,14 +437,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1200
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -418,6 +446,12 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -438,7 +472,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_PMACZILOG is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -464,6 +498,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -488,6 +528,7 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_AMD8111=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
@@ -497,6 +538,7 @@ CONFIG_I2C_AMD8111=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -508,20 +550,29 @@ CONFIG_I2C_AMD8111=y
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -531,6 +582,7 @@ CONFIG_I2C_AMD8111=y
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
@@ -578,6 +630,8 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -596,7 +650,10 @@ CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_SPLIT_ISO=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -604,10 +661,14 @@ CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 # CONFIG_USB_STORAGE is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
@@ -637,13 +698,14 @@ CONFIG_USB_HIDINPUT=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
 CONFIG_USB_PEGASUS=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
 
 #
 # USB port drivers
@@ -655,8 +717,11 @@ CONFIG_USB_PEGASUS=y
 CONFIG_USB_SERIAL=y
 # CONFIG_USB_SERIAL_CONSOLE is not set
 CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRPRIME is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
 # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
@@ -664,6 +729,8 @@ CONFIG_USB_SERIAL_GENERIC=y
 # 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_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 CONFIG_USB_SERIAL_KEYSPAN=y
 CONFIG_USB_SERIAL_KEYSPAN_MPR=y
@@ -682,7 +749,9 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
 # CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
 # CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_TI=m
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
@@ -693,22 +762,38 @@ CONFIG_USB_EZUSB=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB ATM/DSL drivers
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -719,10 +804,15 @@ CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -752,8 +842,10 @@ CONFIG_SYSFS=y
 CONFIG_DEVPTS_FS_XATTR=y
 # CONFIG_DEVPTS_FS_SECURITY is not set
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
 
 #
@@ -766,7 +858,7 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
+CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -784,7 +876,6 @@ CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -867,23 +958,30 @@ CONFIG_NLS_UTF8=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_SCHEDSTATS is not set
 CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SPINLOCK is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_KPROBES is not set
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
 # CONFIG_PPCDBG is not set
 # CONFIG_IRQSTACKS is not set
-# CONFIG_SCHEDSTATS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -898,6 +996,7 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -908,14 +1007,20 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=y
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
diff --git a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig
--- a/arch/ppc64/configs/pSeries_defconfig
+++ b/arch/ppc64/configs/pSeries_defconfig
@@ -1,16 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc2
-# Thu Sep 23 16:45:05 2004
+# Linux kernel version: 2.6.12-rc6
+# Tue Jun 14 17:13:47 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
-CONFIG_FRAME_POINTER=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_FORCE_MAX_ZONEORDER=13
 
 #
@@ -18,6 +19,8 @@ CONFIG_FORCE_MAX_ZONEORDER=13
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -30,23 +33,27 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_SYSCTL=y
 CONFIG_AUDIT=y
 CONFIG_AUDITSYSCALL=y
-CONFIG_LOG_BUF_SHIFT=17
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_CPUSETS=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -55,8 +62,9 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
 CONFIG_SYSVIPC_COMPAT=y
 
@@ -67,26 +75,32 @@ CONFIG_SYSVIPC_COMPAT=y
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_PPC_PSERIES=y
 # CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_MAPLE is not set
 CONFIG_PPC=y
 CONFIG_PPC64=y
 CONFIG_PPC_OF=y
 CONFIG_ALTIVEC=y
 CONFIG_PPC_SPLPAR=y
+CONFIG_IBMVIO=y
+# CONFIG_U3_DART is not set
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_POWER4_ONLY is not set
 CONFIG_IOMMU_VMERGE=y
 CONFIG_SMP=y
-CONFIG_IRQ_ALL_CPUS=y
 CONFIG_NR_CPUS=128
-# CONFIG_HMT is not set
 CONFIG_DISCONTIGMEM=y
 CONFIG_NUMA=y
 CONFIG_SCHED_SMT=y
 # CONFIG_PREEMPT is not set
+CONFIG_EEH=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_PPC_RTAS=y
+CONFIG_RTAS_PROC=y
 CONFIG_RTAS_FLASH=m
 CONFIG_SCANLOG=m
 CONFIG_LPARCFG=y
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # General setup
@@ -97,12 +111,13 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
 CONFIG_HOTPLUG_CPU=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -110,7 +125,6 @@ CONFIG_HOTPLUG_CPU=y
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
@@ -137,7 +151,13 @@ CONFIG_FW_LOADER=y
 #
 # Parallel port support
 #
-# CONFIG_PARPORT is not set
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_1284 is not set
 
 #
 # Plug and Play support
@@ -147,18 +167,32 @@ CONFIG_FW_LOADER=y
 # Block devices
 #
 CONFIG_BLK_DEV_FD=m
+# CONFIG_PARIDE is not set
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -177,7 +211,6 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -247,6 +280,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=m
 
 #
 # SCSI low-level drivers
@@ -264,21 +298,22 @@ CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
 CONFIG_SCSI_IBMVSCSI=y
+# 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_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 CONFIG_SCSI_IPR=y
-# CONFIG_SCSI_IPR_TRACE is not set
-# CONFIG_SCSI_IPR_DUMP is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
+CONFIG_SCSI_IPR_TRACE=y
+CONFIG_SCSI_IPR_DUMP=y
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=y
@@ -287,7 +322,7 @@ CONFIG_SCSI_QLA22XX=m
 CONFIG_SCSI_QLA2300=m
 CONFIG_SCSI_QLA2322=m
 CONFIG_SCSI_QLA6312=m
-CONFIG_SCSI_QLA6322=m
+CONFIG_SCSI_LPFC=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -304,11 +339,14 @@ CONFIG_MD_RAID10=m
 CONFIG_MD_RAID5=y
 CONFIG_MD_RAID6=m
 CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -339,7 +377,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -355,6 +392,8 @@ CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 CONFIG_INET_TUNNEL=y
+CONFIG_IP_TCPDIAG=m
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -368,7 +407,8 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
 CONFIG_IP_NF_CT_PROTO_SCTP=m
 CONFIG_IP_NF_FTP=m
 CONFIG_IP_NF_IRC=m
@@ -397,6 +437,9 @@ CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_REALM=m
 CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_MATCH_COMMENT=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
@@ -419,13 +462,13 @@ CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
 CONFIG_IP_NF_TARGET_MARK=m
 CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -446,7 +489,6 @@ CONFIG_LLC=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -502,7 +544,6 @@ CONFIG_PCNET32=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -512,7 +553,6 @@ CONFIG_E100=y
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -527,7 +567,10 @@ CONFIG_E1000=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -536,6 +579,7 @@ CONFIG_IXGB=m
 # CONFIG_IXGB_NAPI is not set
 CONFIG_S2IO=m
 # CONFIG_S2IO_NAPI is not set
+# CONFIG_2BUFF_MODE is not set
 
 #
 # Token Ring devices
@@ -556,6 +600,7 @@ CONFIG_IBMOL=y
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
 CONFIG_PPP=m
 # CONFIG_PPP_MULTILINK is not set
 # CONFIG_PPP_FILTER is not set
@@ -588,7 +633,7 @@ CONFIG_INPUT=y
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
@@ -597,18 +642,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -624,10 +657,22 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_PCSPKR=m
 # CONFIG_INPUT_UINPUT is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -648,11 +693,14 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_PMACZILOG is not set
 CONFIG_SERIAL_ICOM=m
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 CONFIG_HVC_CONSOLE=y
 CONFIG_HVCS=m
 
@@ -678,6 +726,12 @@ CONFIG_HVCS=m
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=1024
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -702,8 +756,10 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
@@ -711,6 +767,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -722,20 +779,29 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -745,6 +811,7 @@ CONFIG_I2C_ALGOBIT=y
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
@@ -777,7 +844,13 @@ CONFIG_I2C_ALGOBIT=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+CONFIG_FB_MACMODES=y
 CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
@@ -786,12 +859,12 @@ CONFIG_FB_OF=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_VGA16 is not set
+# CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G450=y
-CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_G=y
 # CONFIG_FB_MATROX_I2C is not set
 CONFIG_FB_MATROX_MULTIHEAD=y
 # CONFIG_FB_RADEON_OLD is not set
@@ -800,12 +873,14 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_FB_RADEON_DEBUG is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -825,6 +900,11 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
 
 #
 # Sound
@@ -834,6 +914,8 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -852,7 +934,10 @@ CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -860,20 +945,23 @@ CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT 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_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
@@ -893,7 +981,6 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -905,17 +992,19 @@ CONFIG_USB_HIDDEV=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
 
 #
 # USB port drivers
 #
+# CONFIG_USB_USS720 is not set
 
 #
 # USB Serial Converter support
@@ -927,32 +1016,52 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB ATM/DSL drivers
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -961,20 +1070,27 @@ CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_PROC_INFO is not set
 CONFIG_REISERFS_FS_XATTR=y
 CONFIG_REISERFS_FS_POSIX_ACL=y
-# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_REISERFS_FS_SECURITY=y
 CONFIG_JFS_FS=m
 CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=m
 # CONFIG_AUTOFS4_FS is not set
 
@@ -982,8 +1098,9 @@ CONFIG_AUTOFS_FS=m
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
 CONFIG_UDF_FS=m
 CONFIG_UDF_NLS=y
 
@@ -1005,8 +1122,10 @@ CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 CONFIG_DEVPTS_FS_XATTR=y
-# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_DEVPTS_FS_SECURITY=y
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1035,13 +1154,13 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=m
+CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V4=y
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
+CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -1051,6 +1170,7 @@ CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
 CONFIG_CIFS_XATTR=y
 CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
@@ -1114,23 +1234,30 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_KPROBES is not set
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
 # CONFIG_PPCDBG is not set
 CONFIG_IRQSTACKS=y
-# CONFIG_SCHEDSTATS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1144,7 +1271,8 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WHIRLPOOL=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -1155,12 +1283,17 @@ CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff --git a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig
+++ b/arch/ppc64/defconfig
@@ -1,14 +1,17 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc5-git9
+# Sun Jun  5 09:26:47 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
-CONFIG_FRAME_POINTER=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_FORCE_MAX_ZONEORDER=13
 
 #
@@ -16,27 +19,40 @@ CONFIG_FORCE_MAX_ZONEORDER=13
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_AUDIT is not set
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_CPUSETS=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -45,32 +61,47 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
+CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Platform support
 #
 # CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_PPC_PSERIES=y
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_MAPLE=y
 CONFIG_PPC=y
 CONFIG_PPC64=y
 CONFIG_PPC_OF=y
 CONFIG_ALTIVEC=y
-# CONFIG_PPC_PMAC is not set
-# CONFIG_BOOTX_TEXT is not set
+CONFIG_PPC_SPLPAR=y
+CONFIG_IBMVIO=y
+CONFIG_U3_DART=y
+CONFIG_MPIC_BROKEN_U3=y
+CONFIG_PPC_PMAC64=y
+CONFIG_BOOTX_TEXT=y
 # CONFIG_POWER4_ONLY is not set
-# CONFIG_IOMMU_VMERGE is not set
+CONFIG_IOMMU_VMERGE=y
 CONFIG_SMP=y
-CONFIG_IRQ_ALL_CPUS=y
 CONFIG_NR_CPUS=32
-# CONFIG_HMT is not set
-# CONFIG_DISCONTIGMEM is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_NUMA is not set
+# CONFIG_SCHED_SMT is not set
+# CONFIG_PREEMPT is not set
+CONFIG_EEH=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_PPC_RTAS=y
+CONFIG_RTAS_PROC=y
 CONFIG_RTAS_FLASH=m
 CONFIG_SCANLOG=m
 CONFIG_LPARCFG=y
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # General setup
@@ -78,14 +109,16 @@ CONFIG_LPARCFG=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_HOTPLUG_CPU=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -93,7 +126,6 @@ CONFIG_PCI_NAMES=y
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
@@ -107,7 +139,9 @@ CONFIG_PROC_DEVICETREE=y
 #
 # Generic Driver Options
 #
-CONFIG_FW_LOADER=m
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -118,7 +152,13 @@ CONFIG_FW_LOADER=m
 #
 # Parallel port support
 #
-# CONFIG_PARPORT is not set
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_1284 is not set
 
 #
 # Plug and Play support
@@ -128,17 +168,32 @@ CONFIG_FW_LOADER=m
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
+# CONFIG_PARIDE is not set
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -149,15 +204,14 @@ CONFIG_BLK_DEV_IDE=y
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -173,7 +227,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=y
@@ -194,6 +247,11 @@ CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+# CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set
+# CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -219,7 +277,6 @@ CONFIG_CHR_DEV_SG=y
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_REPORT_LUNS=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -228,34 +285,52 @@ CONFIG_SCSI_CONSTANTS=y
 #
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=m
 
 #
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+CONFIG_SCSI_SATA=y
+# CONFIG_SCSI_SATA_AHCI is not set
+CONFIG_SCSI_SATA_SVW=y
+# CONFIG_SCSI_ATA_PIIX is not set
+# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_SX4 is not set
+# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
+CONFIG_SCSI_IBMVSCSI=y
+# 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_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
+CONFIG_SCSI_IPR=y
+CONFIG_SCSI_IPR_TRACE=y
+CONFIG_SCSI_IPR_DUMP=y
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=y
@@ -264,10 +339,10 @@ CONFIG_SCSI_QLA22XX=m
 CONFIG_SCSI_QLA2300=m
 CONFIG_SCSI_QLA2322=m
 CONFIG_SCSI_QLA6312=m
-CONFIG_SCSI_QLA6322=m
+CONFIG_SCSI_LPFC=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_DEBUG=m
 
 #
 # Multi-device support (RAID and LVM)
@@ -277,11 +352,18 @@ CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
+CONFIG_MD_RAID10=y
 CONFIG_MD_RAID5=y
-CONFIG_MD_RAID6=y
-# CONFIG_MD_MULTIPATH is not set
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
 
 #
 # Fusion MPT device support
@@ -291,15 +373,49 @@ CONFIG_DM_CRYPT=m
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
+CONFIG_IEEE1394=y
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=y
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=y
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
 
 #
 # I2O device support
 #
+# CONFIG_I2O is not set
 
 #
 # Macintosh device drivers
 #
+CONFIG_ADB=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_SMU=y
+# CONFIG_PMAC_PBOOK is not set
+# CONFIG_PMAC_BACKLIGHT is not set
+# CONFIG_INPUT_ADBHID is not set
+CONFIG_THERM_PM72=y
 
 #
 # Networking support
@@ -311,7 +427,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -322,19 +437,19 @@ CONFIG_NET_IPIP=y
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
-CONFIG_INET_ECN=y
 CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=y
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
 #
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 
@@ -342,6 +457,9 @@ CONFIG_NETFILTER=y
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CT_PROTO_SCTP=m
 CONFIG_IP_NF_FTP=m
 CONFIG_IP_NF_IRC=m
 CONFIG_IP_NF_TFTP=m
@@ -366,8 +484,17 @@ CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
 CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_MATCH_COMMENT=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -385,24 +512,24 @@ CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
 CONFIG_IP_NF_TARGET_MARK=m
 CONFIG_IP_NF_TARGET_CLASSIFY=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_COMPAT_IPFWADM=m
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 CONFIG_LLC=y
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
@@ -412,36 +539,42 @@ CONFIG_LLC=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
 
 #
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_OAKNET is not set
 # CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
+CONFIG_SUNGEM=y
 CONFIG_NET_VENDOR_3COM=y
 CONFIG_VORTEX=y
 # CONFIG_TYPHOON is not set
@@ -451,6 +584,7 @@ CONFIG_VORTEX=y
 #
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
+CONFIG_IBMVETH=m
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
 # CONFIG_AMD8111_ETH is not set
@@ -460,7 +594,6 @@ CONFIG_PCNET32=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -483,68 +616,51 @@ CONFIG_E1000=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 CONFIG_IXGB=m
 # CONFIG_IXGB_NAPI is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_IBMVETH=m
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# 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
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
 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_SHAPER is not set
-CONFIG_NETCONSOLE=y
 
 #
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_IRDA is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# Bluetooth support
+# Wan interfaces
 #
-# CONFIG_BT is not set
-CONFIG_NETPOLL=y
-CONFIG_NETPOLL_RX=y
-CONFIG_NETPOLL_TRAP=y
-CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# 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
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # ISDN subsystem
@@ -565,43 +681,46 @@ CONFIG_INPUT=y
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
-CONFIG_INPUT_PCSPKR=y
+CONFIG_INPUT_PCSPKR=m
 # CONFIG_INPUT_UINPUT is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -623,16 +742,17 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_PMACZILOG is not set
+CONFIG_SERIAL_ICOM=m
+CONFIG_SERIAL_JSM=m
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 CONFIG_HVC_CONSOLE=y
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+CONFIG_HVCS=m
 
 #
 # IPMI
@@ -656,30 +776,41 @@ CONFIG_HVC_CONSOLE=y
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
 #
 CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_CHARDEV=y
 
 #
 # I2C Algorithms
 #
 CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
 #
 # CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
 # CONFIG_I2C_ALI15X3 is not set
 # CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_AMD8111=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
+CONFIG_I2C_KEYWEST=y
 # CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
@@ -687,33 +818,66 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
-# I2C Hardware Sensors Chip support
+# Hardware Sensors Chip support
 #
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 # CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -731,20 +895,32 @@ CONFIG_I2C_ALGOBIT=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
 # CONFIG_FB_CT65550 is not set
+# CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S3TRIO is not set
 # CONFIG_FB_VGA16 is not set
+# CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G450=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_I2C is not set
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
 CONFIG_FB_MATROX_MULTIHEAD=y
 # CONFIG_FB_RADEON_OLD is not set
 CONFIG_FB_RADEON=y
@@ -752,22 +928,22 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_FB_RADEON_DEBUG is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
@@ -779,6 +955,11 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
 
 #
 # Sound
@@ -788,6 +969,8 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -797,13 +980,19 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -811,19 +1000,23 @@ CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
 # 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_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
@@ -833,14 +1026,16 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
 
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -852,17 +1047,19 @@ CONFIG_USB_HIDDEV=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_PEGASUS=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
 #
+# CONFIG_USB_USS720 is not set
 
 #
 # USB Serial Converter support
@@ -874,50 +1071,82 @@ CONFIG_USB_HIDDEV=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB ATM/DSL drivers
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
 CONFIG_JFS_FS=y
 CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
 # CONFIG_JFS_DEBUG is not set
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=m
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
 # CONFIG_AUTOFS4_FS is not set
 
 #
@@ -927,6 +1156,7 @@ CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
 CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
@@ -934,6 +1164,8 @@ CONFIG_UDF_FS=m
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -941,10 +1173,13 @@ CONFIG_VFAT_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 CONFIG_DEVPTS_FS_XATTR=y
-# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_DEVPTS_FS_SECURITY=y
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -954,8 +1189,8 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -973,18 +1208,23 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
+CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V4=y
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
+CONFIG_EXPORTFS=m
 CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_RPCSEC_GSS_SPKM3=m
 # CONFIG_SMB_FS is not set
 CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
@@ -992,51 +1232,66 @@ CONFIG_CIFS=m
 #
 # 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=y
 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 is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
 #
 CONFIG_NLS=y
 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
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
 
 #
 # Profiling support
@@ -1047,20 +1302,30 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_KPROBES is not set
 CONFIG_DEBUG_STACK_USAGE=y
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
-CONFIG_XMON_DEFAULT=y
+# CONFIG_XMON_DEFAULT is not set
 # CONFIG_PPCDBG is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_IRQSTACKS=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1070,24 +1335,37 @@ CONFIG_CRYPTO=y
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_TEST=m
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+CONFIG_CRC_CCITT=m
 CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c
--- a/arch/ppc64/kernel/HvLpEvent.c
+++ b/arch/ppc64/kernel/HvLpEvent.c
@@ -45,7 +45,7 @@ int HvLpEvent_unregisterHandler( HvLpEve
 			/* We now sleep until all other CPUs have scheduled. This ensures that
 			 * the deletion is seen by all other CPUs, and that the deleted handler
 			 * isn't still running on another CPU when we return. */
-			synchronize_kernel();
+			synchronize_rcu();
 		}
 	}
 	return rc;
diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
--- a/arch/ppc64/kernel/LparData.c
+++ b/arch/ppc64/kernel/LparData.c
@@ -45,7 +45,7 @@ struct HvReleaseData hvReleaseData = {
 	.xSize = sizeof(struct HvReleaseData),
 	.xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
 	.xSlicNacaAddr = &naca,		/* 64-bit Naca address */
-	.xMsNucDataOffset = 0x6000,	/* offset of LparMap within loadarea (see head.S) */
+	.xMsNucDataOffset = 0x4800,	/* offset of LparMap within loadarea (see head.S) */
 	.xTagsMode = 1,			/* tags inactive       */
 	.xAddressSize = 0,		/* 64 bit              */
 	.xNoSharedProcs = 0,		/* shared processors   */
@@ -224,6 +224,7 @@ struct ItVpdAreas itVpdAreas = {
 };
 
 struct msChunks msChunks;
+EXPORT_SYMBOL(msChunks);
 
 /* Depending on whether this is called from iSeries or pSeries setup
  * code, the location of the msChunks struct may or may not have
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -11,7 +11,8 @@ obj-y               :=	setup.o entry.o t
 			udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
 			ptrace32.o signal32.o rtc.o init_task.o \
 			lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
-			iommu.o sysfs.o
+			iommu.o sysfs.o vdso.o pmc.o
+obj-y += vdso32/ vdso64/
 
 obj-$(CONFIG_PPC_OF) +=	of_device.o
 
@@ -30,7 +31,7 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq
 obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o mpic.o
 
 obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
-			     pSeries_nvram.o rtasd.o ras.o \
+			     pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \
 			     xics.o rtas.o pSeries_setup.o pSeries_iommu.o
 
 obj-$(CONFIG_EEH)		+= eeh.o
@@ -38,7 +39,7 @@ obj-$(CONFIG_PROC_FS)		+= proc_ppc64.o
 obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
-obj-$(CONFIG_PPC_RTAS)		+= rtas-proc.o
+obj-$(CONFIG_RTAS_PROC)		+= rtas-proc.o
 obj-$(CONFIG_SCANLOG)		+= scanlog.o
 obj-$(CONFIG_VIOPATH)		+= viopath.o
 obj-$(CONFIG_LPARCFG)		+= lparcfg.o
diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c
--- a/arch/ppc64/kernel/align.c
+++ b/arch/ppc64/kernel/align.c
@@ -238,7 +238,7 @@ fix_alignment(struct pt_regs *regs)
 
 	dsisr = regs->dsisr;
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_NODSISRALIGN) {
+	if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) {
 	    unsigned int real_instr;
 	    if (__get_user(real_instr, (unsigned int __user *)regs->nip))
 		return 0;
@@ -273,7 +273,7 @@ fix_alignment(struct pt_regs *regs)
 
 	/* Verify the address of the operand */
 	if (user_mode(regs)) {
-		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+		if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
 			return -EFAULT;	/* bad address */
 	}
 
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
--- a/arch/ppc64/kernel/asm-offsets.c
+++ b/arch/ppc64/kernel/asm-offsets.c
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/time.h>
 #include <linux/hardirq.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -35,6 +36,8 @@
 #include <asm/rtas.h>
 #include <asm/cputable.h>
 #include <asm/cache.h>
+#include <asm/systemcfg.h>
+#include <asm/compat.h>
 
 #define DEFINE(sym, val) \
 	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -167,5 +170,24 @@ int main(void)
 	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
 	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
 
+	/* systemcfg offsets for use by vdso */
+	DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp));
+	DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec));
+	DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs));
+	DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec));
+	DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count));
+	DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest));
+	DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime));
+	DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32));
+	DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64));
+
+	/* timeval/timezone offsets for use by vdso */
+	DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec));
+	DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec));
+	DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec));
+	DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec));
+	DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
+	DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
+
 	return 0;
 }
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -17,9 +17,12 @@
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/init.h>
+#include <linux/module.h>
+
 #include <asm/cputable.h>
 
 struct cpu_spec* cur_cpu_spec = NULL;
+EXPORT_SYMBOL(cur_cpu_spec);
 
 /* NOTE:
  * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's
diff --git a/arch/ppc64/kernel/dma.c b/arch/ppc64/kernel/dma.c
--- a/arch/ppc64/kernel/dma.c
+++ b/arch/ppc64/kernel/dma.c
@@ -13,14 +13,23 @@
 #include <asm/scatterlist.h>
 #include <asm/bug.h>
 
-int dma_supported(struct device *dev, u64 mask)
+static struct dma_mapping_ops *get_dma_ops(struct device *dev)
 {
 	if (dev->bus == &pci_bus_type)
-		return pci_dma_supported(to_pci_dev(dev), mask);
+		return &pci_dma_ops;
 #ifdef CONFIG_IBMVIO
 	if (dev->bus == &vio_bus_type)
-		return vio_dma_supported(to_vio_dev(dev), mask);
-#endif /* CONFIG_IBMVIO */
+		return &vio_dma_ops;
+#endif
+	return NULL;
+}
+
+int dma_supported(struct device *dev, u64 mask)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		return dma_ops->dma_supported(dev, mask);
 	BUG();
 	return 0;
 }
@@ -32,7 +41,7 @@ int dma_set_mask(struct device *dev, u64
 		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
 #ifdef CONFIG_IBMVIO
 	if (dev->bus == &vio_bus_type)
-		return vio_set_dma_mask(to_vio_dev(dev), dma_mask);
+		return -EIO;
 #endif /* CONFIG_IBMVIO */
 	BUG();
 	return 0;
@@ -40,14 +49,12 @@ int dma_set_mask(struct device *dev, u64
 EXPORT_SYMBOL(dma_set_mask);
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
-		dma_addr_t *dma_handle, int flag)
+		dma_addr_t *dma_handle, unsigned int __nocast flag)
 {
-	if (dev->bus == &pci_bus_type)
-		return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
-#ifdef CONFIG_IBMVIO
-	if (dev->bus == &vio_bus_type)
-		return vio_alloc_consistent(to_vio_dev(dev), size, dma_handle);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
 	BUG();
 	return NULL;
 }
@@ -56,12 +63,10 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
 		dma_addr_t dma_handle)
 {
-	if (dev->bus == &pci_bus_type)
-		pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
-#ifdef CONFIG_IBMVIO
-	else if (dev->bus == &vio_bus_type)
-		vio_free_consistent(to_vio_dev(dev), size, cpu_addr, dma_handle);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
 	else
 		BUG();
 }
@@ -70,12 +75,10 @@ EXPORT_SYMBOL(dma_free_coherent);
 dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
-#ifdef CONFIG_IBMVIO
-	if (dev->bus == &vio_bus_type)
-		return vio_map_single(to_vio_dev(dev), cpu_addr, size, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		return dma_ops->map_single(dev, cpu_addr, size, direction);
 	BUG();
 	return (dma_addr_t)0;
 }
@@ -84,12 +87,10 @@ EXPORT_SYMBOL(dma_map_single);
 void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
-#ifdef CONFIG_IBMVIO
-	else if (dev->bus == &vio_bus_type)
-		vio_unmap_single(to_vio_dev(dev), dma_addr, size, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		dma_ops->unmap_single(dev, dma_addr, size, direction);
 	else
 		BUG();
 }
@@ -99,12 +100,11 @@ dma_addr_t dma_map_page(struct device *d
 		unsigned long offset, size_t size,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
-#ifdef CONFIG_IBMVIO
-	if (dev->bus == &vio_bus_type)
-		return vio_map_page(to_vio_dev(dev), page, offset, size, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		return dma_ops->map_single(dev,
+				(page_address(page) + offset), size, direction);
 	BUG();
 	return (dma_addr_t)0;
 }
@@ -113,12 +113,10 @@ EXPORT_SYMBOL(dma_map_page);
 void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
-#ifdef CONFIG_IBMVIO
-	else if (dev->bus == &vio_bus_type)
-		vio_unmap_page(to_vio_dev(dev), dma_address, size, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		dma_ops->unmap_single(dev, dma_address, size, direction);
 	else
 		BUG();
 }
@@ -127,12 +125,10 @@ EXPORT_SYMBOL(dma_unmap_page);
 int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
-#ifdef CONFIG_IBMVIO
-	if (dev->bus == &vio_bus_type)
-		return vio_map_sg(to_vio_dev(dev), sg, nents, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		return dma_ops->map_sg(dev, sg, nents, direction);
 	BUG();
 	return 0;
 }
@@ -141,12 +137,10 @@ EXPORT_SYMBOL(dma_map_sg);
 void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
 		enum dma_data_direction direction)
 {
-	if (dev->bus == &pci_bus_type)
-		pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
-#ifdef CONFIG_IBMVIO
-	else if (dev->bus == &vio_bus_type)
-		vio_unmap_sg(to_vio_dev(dev), sg, nhwentries, direction);
-#endif /* CONFIG_IBMVIO */
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (dma_ops)
+		dma_ops->unmap_sg(dev, sg, nhwentries, direction);
 	else
 		BUG();
 }
diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c
--- a/arch/ppc64/kernel/eeh.c
+++ b/arch/ppc64/kernel/eeh.c
@@ -824,7 +824,7 @@ void eeh_add_device_early(struct device_
 	struct pci_controller *phb;
 	struct eeh_early_enable_info info;
 
-	if (!dn || !eeh_subsystem_enabled)
+	if (!dn)
 		return;
 	phb = dn->phb;
 	if (NULL == phb || 0 == phb->buid) {
diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S
+++ b/arch/ppc64/kernel/entry.S
@@ -436,15 +436,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	REST_8GPRS(14, r1)
 	REST_10GPRS(22, r1)
 
-#ifdef CONFIG_PPC_ISERIES
-	clrrdi	r7,r1,THREAD_SHIFT	/* get current_thread_info() */
-	ld	r7,TI_FLAGS(r7)		/* Get run light flag */
-	mfspr	r9,CTRLF
-	srdi	r7,r7,TIF_RUN_LIGHT
-	insrdi	r9,r7,1,63		/* Insert run light into CTRL */
-	mtspr	CTRLT,r9
-#endif
-
 	/* convert old thread to its task_struct for return value */
 	addi	r3,r3,-THREAD
 	ld	r7,_NIP(r1)	/* Return to _switch caller in new task */
@@ -616,7 +607,7 @@ unrecov_restore:
 	bl	.unrecoverable_exception
 	b	unrecov_restore
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC_RTAS
 /*
  * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
  * called with the MMU off.
@@ -753,7 +744,7 @@ _STATIC(rtas_restore_regs)
 	mtlr    r0
         blr				/* return to caller */
 
-#endif /* CONFIG_PPC_PSERIES */
+#endif /* CONFIG_PPC_RTAS */
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
 
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -37,6 +37,7 @@
 #include <asm/bug.h>
 #include <asm/cputable.h>
 #include <asm/setup.h>
+#include <asm/hvcall.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -45,7 +46,6 @@
 /*
  * hcall interface to pSeries LPAR
  */
-#define HVSC		.long 0x44000022
 #define H_SET_ASR	0x30
 
 /*
@@ -54,7 +54,6 @@
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
  * 0x3000 - 0x3fff : Interrupt support
  * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : SystemCfg
  * 0x6000	   : iSeries and common interrupt prologs
  * 0x9000 - 0x9fff : Initial segment table
  */
@@ -517,16 +516,7 @@ __end_interrupts:
 	.globl naca
 naca:
 	.llong itVpdAreas
-#endif
-
-	. = SYSTEMCFG_PHYS_ADDR
-	.globl __start_systemcfg
-__start_systemcfg:
-	. = (SYSTEMCFG_PHYS_ADDR + PAGE_SIZE)
-	.globl __end_systemcfg
-__end_systemcfg:
 
-#ifdef CONFIG_PPC_ISERIES
 	/*
 	 * The iSeries LPAR map is at this fixed address
 	 * so that the HvReleaseData structure can address
@@ -536,6 +526,8 @@ __end_systemcfg:
 	 * VSID generation algorithm.  See include/asm/mmu_context.h.
 	 */
 
+	. = 0x4800
+
 	.llong	2		/* # ESIDs to be mapped by hypervisor	 */
 	.llong	1		/* # memory ranges to be mapped by hypervisor */
 	.llong	STAB0_PAGE	/* Page # of segment table within load area	*/
@@ -634,10 +626,10 @@ system_reset_iSeries:
 	lhz	r24,PACAPACAINDEX(r13)	/* Get processor # */
 	cmpwi	0,r24,0			/* Are we processor 0? */
 	beq	.__start_initialization_iSeries	/* Start up the first processor */
-	mfspr	r4,CTRLF
-	li	r5,RUNLATCH		/* Turn off the run light */
+	mfspr	r4,SPRN_CTRLF
+	li	r5,CTRL_RUNLATCH	/* Turn off the run light */
 	andc	r4,r4,r5
-	mtspr	CTRLT,r4
+	mtspr	SPRN_CTRLT,r4
 
 1:
 	HMT_LOW
@@ -930,7 +922,9 @@ fp_unavailable_common:
 altivec_unavailable_common:
 	EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
 #ifdef CONFIG_ALTIVEC
+BEGIN_FTR_SECTION
 	bne	.load_up_altivec	/* if from user, just load it up */
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
 	bl	.save_nvgprs
 	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -958,11 +952,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
 	 * accessing a userspace segment (even from the kernel). We assume
 	 * kernel addresses always have the high bit set.
 	 */
-	rlwinm	r4,r4,32-23,29,29	/* DSISR_STORE -> _PAGE_RW */
+	rlwinm	r4,r4,32-25+9,31-9,31-9	/* DSISR_STORE -> _PAGE_RW */
 	rotldi	r0,r3,15		/* Move high bit into MSR_PR posn */
 	orc	r0,r12,r0		/* MSR_PR | ~high_bit */
 	rlwimi	r4,r0,32-13,30,30	/* becomes _PAGE_USER access bit */
 	ori	r4,r4,1			/* add _PAGE_PRESENT */
+	rlwimi	r4,r5,22+2,31-2,31-2	/* Set _PAGE_EXEC if trap is 0x400 */
 
 	/*
 	 * On iSeries, we soft-disable interrupts here, then
@@ -1264,10 +1259,6 @@ _STATIC(__start_initialization_iSeries)
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
-	LOADADDR(r9,systemcfg)
-	SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR)
-	std	r4,0(r9)		/* set the systemcfg pointer */
-
 	bl	.iSeries_early_setup
 
 	/* relocation is on at this point */
@@ -1772,7 +1763,7 @@ _GLOBAL(__secondary_start)
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg	 */
+	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg	 */
 	lwz	r3,PLATFORM(r3)		/* r3 = platform flags		 */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne	98f
@@ -1861,12 +1852,6 @@ _STATIC(start_here_multiplatform)
 	ori	r6,r6,MSR_RI
 	mtmsrd	r6			/* RI on */
 
-	/* setup the systemcfg pointer which is needed by *tab_initialize	*/
-	LOADADDR(r6,systemcfg)
-	sub	r6,r6,r26		/* addr of the variable systemcfg */
-	li	r27,SYSTEMCFG_PHYS_ADDR
-	std	r27,0(r6)	 	/* set the value of systemcfg	*/
-
 #ifdef CONFIG_HMT
 	/* Start up the second thread on cpu 0 */
 	mfspr	r3,PVR
@@ -1941,7 +1926,7 @@ _STATIC(start_here_multiplatform)
 	/* set the ASR */
 	ld	r3,PACASTABREAL(r13)
 	ori	r4,r3,1			/* turn on valid bit		 */
-	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg */
+	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
 	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne	98f
@@ -1960,7 +1945,7 @@ _STATIC(start_here_multiplatform)
 	mtasr	r4			/* set the stab location	*/
 99:
 	/* Set SDR1 (hash table pointer) */
-	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg */
+	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
 	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
 	/* Test if bit 0 is set (LPAR bit) */
 	andi.	r3,r3,0x1
@@ -1998,11 +1983,6 @@ _STATIC(start_here_common)
 	li	r3,0
 	bl	.do_cpu_ftr_fixups
 
-	/* setup the systemcfg pointer */
-	LOADADDR(r9,systemcfg)
-	SET_REG_TO_CONST(r8, SYSTEMCFG_VIRT_ADDR)
-	std	r8,0(r9)
-
 	LOADADDR(r26, boot_cpuid)
 	lwz	r26,0(r26)
 
@@ -2102,9 +2082,9 @@ _GLOBAL(hmt_start_secondary)
 	mfspr	r4, HID0
 	ori	r4, r4, 0x1
 	mtspr	HID0, r4
-	mfspr	r4, CTRLF
+	mfspr	r4, SPRN_CTRLF
 	oris	r4, r4, 0x40
-	mtspr	CTRLT, r4
+	mtspr	SPRN_CTRLT, r4
 	blr
 #endif
 
diff --git a/arch/ppc64/kernel/i8259.c b/arch/ppc64/kernel/i8259.c
--- a/arch/ppc64/kernel/i8259.c
+++ b/arch/ppc64/kernel/i8259.c
@@ -131,14 +131,11 @@ static void i8259_end_irq(unsigned int i
 }
 
 struct hw_interrupt_type i8259_pic = {
-        " i8259    ",
-        NULL,
-        NULL,
-        i8259_unmask_irq,
-        i8259_mask_irq,
-        i8259_mask_and_ack_irq,
-        i8259_end_irq,
-        NULL
+	.typename = " i8259    ",
+	.enable = i8259_unmask_irq,
+	.disable = i8259_mask_irq,
+	.ack = i8259_mask_and_ack_irq,
+	.end = i8259_end_irq,
 };
 
 void __init i8259_init(int offset)
diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c
--- a/arch/ppc64/kernel/iSeries_htab.c
+++ b/arch/ppc64/kernel/iSeries_htab.c
@@ -144,6 +144,10 @@ static long iSeries_hpte_updatepp(unsign
 
 	HvCallHpt_get(&hpte, slot);
 	if ((hpte.dw0.dw0.avpn == avpn) && (hpte.dw0.dw0.v)) {
+		/*
+		 * Hypervisor expects bits as NPPP, which is
+		 * different from how they are mapped in our PP.
+		 */
 		HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));
 		iSeries_hunlock(slot);
 		return 0;
diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c
+++ b/arch/ppc64/kernel/iSeries_pci.c
@@ -610,6 +610,10 @@ static int iSeries_pci_read_config(struc
 
 	if (node == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (offset > 255) {
+		*val = ~0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
 
 	fn = hv_cfg_read_func[(size - 1) & 3];
 	HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0);
@@ -636,6 +640,8 @@ static int iSeries_pci_write_config(stru
 
 	if (node == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (offset > 255)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
 
 	fn = hv_cfg_write_func[(size - 1) & 3];
 	ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0);
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -15,7 +15,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
- 
+
 #undef DEBUG
 
 #include <linux/config.h>
@@ -39,6 +39,7 @@
 #include <asm/mmu_context.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/iommu.h>
 
 #include <asm/time.h>
 #include "iSeries_setup.h"
@@ -57,6 +58,7 @@
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/iSeries/mf.h>
 #include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/iSeries_irq.h>
 
 extern void hvlog(char *fmt, ...);
 
@@ -72,7 +74,6 @@ extern void ppcdbg_initialize(void);
 static void build_iSeries_Memory_Map(void);
 static void setup_iSeries_cache_sizes(void);
 static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
-extern void iSeries_setup_arch(void);
 extern void iSeries_pci_final_fixup(void);
 
 /* Global Variables */
@@ -108,8 +109,8 @@ struct MemoryBlock {
  * and return the number of physical blocks and fill in the array of
  * block data.
  */
-unsigned long iSeries_process_Condor_mainstore_vpd(struct MemoryBlock *mb_array,
-		unsigned long max_entries)
+static unsigned long iSeries_process_Condor_mainstore_vpd(
+		struct MemoryBlock *mb_array, unsigned long max_entries)
 {
 	unsigned long holeFirstChunk, holeSizeChunks;
 	unsigned long numMemoryBlocks = 1;
@@ -154,7 +155,7 @@ unsigned long iSeries_process_Condor_mai
 #define MaxSegmentAdrRangeBlocks	128
 #define MaxAreaRangeBlocks		4
 
-unsigned long iSeries_process_Regatta_mainstore_vpd(
+static unsigned long iSeries_process_Regatta_mainstore_vpd(
 		struct MemoryBlock *mb_array, unsigned long max_entries)
 {
 	struct IoHriMainStoreSegment5 *msVpdP =
@@ -246,7 +247,7 @@ unsigned long iSeries_process_Regatta_ma
 		printk("          Bitmap range: %016lx - %016lx\n"
 				"        Absolute range: %016lx - %016lx\n",
 				mb_array[i].logicalStart,
-				mb_array[i].logicalEnd, 
+				mb_array[i].logicalEnd,
 				mb_array[i].absStart, mb_array[i].absEnd);
 		mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
 				0x000fffffffffffff);
@@ -261,13 +262,13 @@ unsigned long iSeries_process_Regatta_ma
 	return numSegmentBlocks;
 }
 
-unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
+static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
 		unsigned long max_entries)
 {
 	unsigned long i;
 	unsigned long mem_blocks = 0;
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
+	if (cpu_has_feature(CPU_FTR_SLB))
 		mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
 				max_entries);
 	else
@@ -284,7 +285,7 @@ unsigned long iSeries_process_mainstore_
 	return mem_blocks;
 }
 
-static void __init iSeries_parse_cmdline(void)
+static void __init iSeries_get_cmdline(void)
 {
 	char *p, *q;
 
@@ -302,8 +303,10 @@ static void __init iSeries_parse_cmdline
 	*p = 0;
 }
 
-/*static*/ void __init iSeries_init_early(void)
+static void __init iSeries_init_early(void)
 {
+	extern unsigned long memory_limit;
+
 	DBG(" -> iSeries_init_early()\n");
 
 	ppcdbg_initialize();
@@ -351,11 +354,36 @@ static void __init iSeries_parse_cmdline
 	 */
 	build_iSeries_Memory_Map();
 
+	iSeries_get_cmdline();
+
+	/* Save unparsed command line copy for /proc/cmdline */
+	strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
+
+	/* Parse early parameters, in particular mem=x */
+	parse_early_param();
+
+	if (memory_limit) {
+		if (memory_limit < systemcfg->physicalMemorySize)
+			systemcfg->physicalMemorySize = memory_limit;
+		else {
+			printk("Ignoring mem=%lu >= ram_top.\n", memory_limit);
+			memory_limit = 0;
+		}
+	}
+
+	/* Bolt kernel mappings for all of memory (or just a bit if we've got a limit) */
+	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
+
+	lmb_init();
+	lmb_add(0, systemcfg->physicalMemorySize);
+	lmb_analyze();
+	lmb_reserve(0, __pa(klimit));
+
 	/* Initialize machine-dependency vectors */
 #ifdef CONFIG_SMP
 	smp_init_iSeries();
 #endif
-	if (itLpNaca.xPirEnvironMode == 0) 
+	if (itLpNaca.xPirEnvironMode == 0)
 		piranha_simulator = 1;
 
 	/* Associate Lp Event Queue 0 with processor 0 */
@@ -376,30 +404,27 @@ static void __init iSeries_parse_cmdline
 		initrd_start = initrd_end = 0;
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-
-	iSeries_parse_cmdline();
-
 	DBG(" <- iSeries_init_early()\n");
 }
 
 /*
  * The iSeries may have very large memories ( > 128 GB ) and a partition
  * may get memory in "chunks" that may be anywhere in the 2**52 real
- * address space.  The chunks are 256K in size.  To map this to the 
- * memory model Linux expects, the AS/400 specific code builds a 
+ * address space.  The chunks are 256K in size.  To map this to the
+ * memory model Linux expects, the AS/400 specific code builds a
  * translation table to translate what Linux thinks are "physical"
- * addresses to the actual real addresses.  This allows us to make 
+ * addresses to the actual real addresses.  This allows us to make
  * it appear to Linux that we have contiguous memory starting at
  * physical address zero while in fact this could be far from the truth.
- * To avoid confusion, I'll let the words physical and/or real address 
- * apply to the Linux addresses while I'll use "absolute address" to 
+ * To avoid confusion, I'll let the words physical and/or real address
+ * apply to the Linux addresses while I'll use "absolute address" to
  * refer to the actual hardware real address.
  *
- * build_iSeries_Memory_Map gets information from the Hypervisor and 
+ * build_iSeries_Memory_Map gets information from the Hypervisor and
  * looks at the Main Store VPD to determine the absolute addresses
  * of the memory that has been assigned to our partition and builds
  * a table used to translate Linux's physical addresses to these
- * absolute addresses.  Absolute addresses are needed when 
+ * absolute addresses.  Absolute addresses are needed when
  * communicating with the hypervisor (e.g. to build HPT entries)
  */
 
@@ -428,13 +453,13 @@ static void __init build_iSeries_Memory_
 	 * otherwise, it might not be returned by PLIC as the first
 	 * chunks
 	 */
-	
+
 	loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
 	loadAreaSize =  itLpNaca.xLoadAreaChunks;
 
 	/*
-	 * Only add the pages already mapped here.  
-	 * Otherwise we might add the hpt pages 
+	 * Only add the pages already mapped here.
+	 * Otherwise we might add the hpt pages
 	 * The rest of the pages of the load area
 	 * aren't in the HPT yet and can still
 	 * be assigned an arbitrary physical address
@@ -446,7 +471,7 @@ static void __init build_iSeries_Memory_
 
 	/*
 	 * TODO Do we need to do something if the HPT is in the 64MB load area?
-	 * This would be required if the itLpNaca.xLoadAreaChunks includes 
+	 * This would be required if the itLpNaca.xLoadAreaChunks includes
 	 * the HPT size
 	 */
 
@@ -454,11 +479,11 @@ static void __init build_iSeries_Memory_
 		"                    absolute addr = %016lx\n",
 		chunk_to_addr(loadAreaFirstChunk));
 	printk("Load area size %dK\n", loadAreaSize * 256);
-	
+
 	for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
 		msChunks.abs[nextPhysChunk] =
 			loadAreaFirstChunk + nextPhysChunk;
-	
+
 	/*
 	 * Get absolute address of our HPT and remember it so
 	 * we won't map it to any physical address
@@ -475,7 +500,7 @@ static void __init build_iSeries_Memory_
 	num_ptegs = hptSizePages *
 		(PAGE_SIZE / (sizeof(HPTE) * HPTES_PER_GROUP));
 	htab_hash_mask = num_ptegs - 1;
-	
+
 	/*
 	 * The actual hashed page table is in the hypervisor,
 	 * we have no direct access
@@ -533,20 +558,12 @@ static void __init build_iSeries_Memory_
 	}
 
 	/*
-	 * main store size (in chunks) is 
+	 * main store size (in chunks) is
 	 *   totalChunks - hptSizeChunks
-	 * which should be equal to 
+	 * which should be equal to
 	 *   nextPhysChunk
 	 */
 	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
-
-	/* Bolt kernel mappings for all of memory */
-	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
-
-	lmb_init();
-	lmb_add(0, systemcfg->physicalMemorySize);
-	lmb_analyze();	/* ?? */
-	lmb_reserve(0, __pa(klimit));
 }
 
 /*
@@ -633,6 +650,10 @@ static void __init iSeries_bolt_kernel(u
 		unsigned long vpn = va >> PAGE_SHIFT;
 		unsigned long slot = HvCallHpt_findValid(&hpte, vpn);
 
+		/* Make non-kernel text non-executable */
+		if (!in_kernel_text(ea))
+			mode_rw |= HW_NO_EXEC;
+
 		if (hpte.dw0.dw0.v) {
 			/* HPTE exists, so just bolt it */
 			HvCallHpt_setSwBits(slot, 0x10, 0);
@@ -650,7 +671,7 @@ extern unsigned long ppc_tb_freq;
 /*
  * Document me.
  */
-void __init iSeries_setup_arch(void)
+static void __init iSeries_setup_arch(void)
 {
 	void *eventStack;
 	unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index;
@@ -669,14 +690,14 @@ void __init iSeries_setup_arch(void)
 	 */
 	eventStack = alloc_bootmem_pages(LpEventStackSize);
 	memset(eventStack, 0, LpEventStackSize);
-	
+
 	/* Invoke the hypervisor to initialize the event stack */
 	HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
 
 	/* Initialize fields in our Lp Event Queue */
 	xItLpQueue.xSlicEventStackPtr = (char *)eventStack;
 	xItLpQueue.xSlicCurEventPtr = (char *)eventStack;
-	xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack + 
+	xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack +
 					(LpEventStackSize - LpEventMaxSize);
 	xItLpQueue.xIndex = 0;
 
@@ -694,7 +715,7 @@ void __init iSeries_setup_arch(void)
 	tbFreqMhzHundreths = (tbFreqHz / 10000) - (tbFreqMhz * 100);
 	ppc_tb_freq = tbFreqHz;
 
-	printk("Max  logical processors = %d\n", 
+	printk("Max  logical processors = %d\n",
 			itVpdAreas.xSlicMaxLogicalProcs);
 	printk("Max physical processors = %d\n",
 			itVpdAreas.xSlicMaxPhysicalProcs);
@@ -706,7 +727,7 @@ void __init iSeries_setup_arch(void)
 	printk("Processor version = %x\n", systemcfg->processor);
 }
 
-void iSeries_get_cpuinfo(struct seq_file *m)
+static void iSeries_get_cpuinfo(struct seq_file *m)
 {
 	seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
 }
@@ -715,7 +736,7 @@ void iSeries_get_cpuinfo(struct seq_file
  * Document me.
  * and Implement me.
  */
-int iSeries_get_irq(struct pt_regs *regs)
+static int iSeries_get_irq(struct pt_regs *regs)
 {
 	/* -2 means ignore this interrupt */
 	return -2;
@@ -724,7 +745,7 @@ int iSeries_get_irq(struct pt_regs *regs
 /*
  * Document me.
  */
-void iSeries_restart(char *cmd)
+static void iSeries_restart(char *cmd)
 {
 	mf_reboot();
 }
@@ -732,7 +753,7 @@ void iSeries_restart(char *cmd)
 /*
  * Document me.
  */
-void iSeries_power_off(void)
+static void iSeries_power_off(void)
 {
 	mf_power_off();
 }
@@ -740,14 +761,11 @@ void iSeries_power_off(void)
 /*
  * Document me.
  */
-void iSeries_halt(void)
+static void iSeries_halt(void)
 {
 	mf_power_off();
 }
 
-/* JDH Hack */
-unsigned long jdh_time = 0;
-
 extern void setup_default_decr(void);
 
 /*
@@ -758,17 +776,17 @@ extern void setup_default_decr(void);
  *   and sets up the kernel timer decrementer based on that value.
  *
  */
-void __init iSeries_calibrate_decr(void)
+static void __init iSeries_calibrate_decr(void)
 {
 	unsigned long	cyclesPerUsec;
 	struct div_result divres;
-	
+
 	/* Compute decrementer (and TB) frequency in cycles/sec */
 	cyclesPerUsec = ppc_tb_freq / 1000000;
 
 	/*
 	 * Set the amount to refresh the decrementer by.  This
-	 * is the number of decrementer ticks it takes for 
+	 * is the number of decrementer ticks it takes for
 	 * 1/HZ seconds.
 	 */
 	tb_ticks_per_jiffy = ppc_tb_freq / HZ;
@@ -793,7 +811,7 @@ void __init iSeries_calibrate_decr(void)
 	setup_default_decr();
 }
 
-void __init iSeries_progress(char * st, unsigned short code)
+static void __init iSeries_progress(char * st, unsigned short code)
 {
 	printk("Progress: [%04x] - %s\n", (unsigned)code, st);
 	if (!piranha_simulator && mf_initialized) {
@@ -825,7 +843,7 @@ static void __init iSeries_fixup_klimit(
 	}
 }
 
-int __init iSeries_src_init(void)
+static int __init iSeries_src_init(void)
 {
         /* clear the progress line */
         ppc_md.progress(" ", 0xffff);
@@ -834,6 +852,28 @@ int __init iSeries_src_init(void)
 
 late_initcall(iSeries_src_init);
 
+static int set_spread_lpevents(char *str)
+{
+	unsigned long i;
+	unsigned long val = simple_strtoul(str, NULL, 0);
+
+	/*
+	 * The parameter is the number of processors to share in processing
+	 * lp events.
+	 */
+	if (( val > 0) && (val <= NR_CPUS)) {
+		for (i = 1; i < val; ++i)
+			paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
+
+		printk("lpevent processing spread over %ld processors\n", val);
+	} else {
+		printk("invalid spread_lpevents %ld\n", val);
+	}
+
+	return 1;
+}
+__setup("spread_lpevents=", set_spread_lpevents);
+
 void __init iSeries_early_setup(void)
 {
 	iSeries_fixup_klimit();
diff --git a/arch/ppc64/kernel/iSeries_setup.h b/arch/ppc64/kernel/iSeries_setup.h
--- a/arch/ppc64/kernel/iSeries_setup.h
+++ b/arch/ppc64/kernel/iSeries_setup.h
@@ -19,19 +19,8 @@
 #ifndef	__ISERIES_SETUP_H__
 #define	__ISERIES_SETUP_H__
 
-extern void iSeries_setup_arch(void);
-extern void iSeries_setup_residual(struct seq_file *m, int cpu_id);
-extern void iSeries_get_cpuinfo(struct seq_file *m);
-extern void iSeries_init_IRQ(void);
-extern int iSeries_get_irq(struct pt_regs *regs);
-extern void iSeries_restart(char *cmd);
-extern void iSeries_power_off(void);
-extern void iSeries_halt(void);
-extern void iSeries_time_init(void);
 extern void iSeries_get_boot_time(struct rtc_time *tm);
 extern int iSeries_set_rtc_time(struct rtc_time *tm);
 extern void iSeries_get_rtc_time(struct rtc_time *tm);
-extern void iSeries_calibrate_decr(void);
-extern void iSeries_progress( char *, unsigned short );
 
 #endif /* __ISERIES_SETUP_H__ */
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -75,13 +75,9 @@ static int iSeries_idle(void)
 {
 	struct paca_struct *lpaca;
 	long oldval;
-	unsigned long CTRL;
 
 	/* ensure iSeries run light will be out when idle */
-	clear_thread_flag(TIF_RUN_LIGHT);
-	CTRL = mfspr(CTRLF);
-	CTRL &= ~RUNLATCH;
-	mtspr(CTRLT, CTRL);
+	ppc64_runlatch_off();
 
 	lpaca = get_paca();
 
@@ -111,7 +107,9 @@ static int iSeries_idle(void)
 			}
 		}
 
+		ppc64_runlatch_on();
 		schedule();
+		ppc64_runlatch_off();
 	}
 
 	return 0;
@@ -293,6 +291,10 @@ static int native_idle(void)
 			power4_idle();
 		if (need_resched())
 			schedule();
+
+		if (cpu_is_offline(_smp_processor_id()) &&
+		    system_state == SYSTEM_RUNNING)
+			cpu_die();
 	}
 	return 0;
 }
diff --git a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c
+++ b/arch/ppc64/kernel/ioctl32.c
@@ -39,7 +39,6 @@ IOCTL_TABLE_START
 #include <linux/compat_ioctl.h>
 #define DECLARES
 #include "compat_ioctl.c"
-COMPATIBLE_IOCTL(TCSBRKP)
 COMPATIBLE_IOCTL(TIOCSTART)
 COMPATIBLE_IOCTL(TIOCSTOP)
 COMPATIBLE_IOCTL(TIOCSLTC)
diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c
--- a/arch/ppc64/kernel/iommu.c
+++ b/arch/ppc64/kernel/iommu.c
@@ -513,8 +513,8 @@ void iommu_unmap_single(struct iommu_tab
  * Returns the virtual address of the buffer and sets dma_handle
  * to the dma address (mapping) of the first page.
  */
-void *iommu_alloc_consistent(struct iommu_table *tbl, size_t size,
-		dma_addr_t *dma_handle)
+void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
+		dma_addr_t *dma_handle, unsigned int __nocast flag)
 {
 	void *ret = NULL;
 	dma_addr_t mapping;
@@ -538,7 +538,7 @@ void *iommu_alloc_consistent(struct iomm
 		return NULL;
 
 	/* Alloc enough pages (and possibly more) */
-	ret = (void *)__get_free_pages(GFP_ATOMIC, order);
+	ret = (void *)__get_free_pages(flag, order);
 	if (!ret)
 		return NULL;
 	memset(ret, 0, size);
@@ -553,7 +553,7 @@ void *iommu_alloc_consistent(struct iomm
 	return ret;
 }
 
-void iommu_free_consistent(struct iommu_table *tbl, size_t size,
+void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
 	unsigned int npages;
diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c
+++ b/arch/ppc64/kernel/irq.c
@@ -61,6 +61,7 @@ extern void iSeries_smp_message_recv( st
 #endif
 
 extern irq_desc_t irq_desc[NR_IRQS];
+EXPORT_SYMBOL(irq_desc);
 
 int distribute_irqs = 1;
 int __irq_offset_value;
@@ -115,6 +116,35 @@ skip:
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+void fixup_irqs(cpumask_t map)
+{
+	unsigned int irq;
+	static int warned;
+
+	for_each_irq(irq) {
+		cpumask_t mask;
+
+		if (irq_desc[irq].status & IRQ_PER_CPU)
+			continue;
+
+		cpus_and(mask, irq_affinity[irq], map);
+		if (any_online_cpu(mask) == NR_CPUS) {
+			printk("Breaking affinity for irq %i\n", irq);
+			mask = map;
+		}
+		if (irq_desc[irq].handler->set_affinity)
+			irq_desc[irq].handler->set_affinity(irq, mask);
+		else if (irq_desc[irq].action && !(warned++))
+			printk("Cannot set affinity for irq %i\n", irq);
+	}
+
+	local_irq_enable();
+	mdelay(1);
+	local_irq_disable();
+}
+#endif
+
 extern int noirqdebug;
 
 /*
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -45,12 +45,17 @@ static struct pt_regs jprobe_saved_regs;
 
 int arch_prepare_kprobe(struct kprobe *p)
 {
+	int ret = 0;
 	kprobe_opcode_t insn = *p->addr;
 
-	if (IS_MTMSRD(insn) || IS_RFID(insn))
-		/* cannot put bp on RFID/MTMSRD */
-		return 1;
-	return 0;
+	if ((unsigned long)p->addr & 0x03) {
+		printk("Attempt to register kprobe at an unaligned address\n");
+		ret = -EINVAL;
+	} else if (IS_MTMSRD(insn) || IS_RFID(insn)) {
+		printk("Cannot register a kprobe on rfid or mtmsrd\n");
+		ret = -EINVAL;
+	}
+	return ret;
 }
 
 void arch_copy_kprobe(struct kprobe *p)
@@ -71,7 +76,11 @@ static inline void disarm_kprobe(struct 
 static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
 	regs->msr |= MSR_SE;
-	regs->nip = (unsigned long)&p->ainsn.insn;
+	/*single step inline if it a breakpoint instruction*/
+	if (p->opcode == BREAKPOINT_INSTRUCTION)
+		regs->nip = (unsigned long)p->addr;
+	else
+		regs->nip = (unsigned long)&p->ainsn.insn;
 }
 
 static inline int kprobe_handler(struct pt_regs *regs)
@@ -80,15 +89,18 @@ static inline int kprobe_handler(struct 
 	int ret = 0;
 	unsigned int *addr = (unsigned int *)regs->nip;
 
-	/* We're in an interrupt, but this is clear and BUG()-safe. */
-	preempt_disable();
-
 	/* Check we're not actually recursing */
 	if (kprobe_running()) {
 		/* We *are* holding lock here, so this is safe.
 		   Disarm the probe we just hit, and ignore it. */
 		p = get_kprobe(addr);
 		if (p) {
+			if (kprobe_status == KPROBE_HIT_SS) {
+				regs->msr &= ~MSR_SE;
+				regs->msr |= kprobe_saved_msr;
+				unlock_kprobes();
+				goto no_kprobe;
+			}
 			disarm_kprobe(p, regs);
 			ret = 1;
 		} else {
@@ -105,9 +117,17 @@ static inline int kprobe_handler(struct 
 	p = get_kprobe(addr);
 	if (!p) {
 		unlock_kprobes();
-#if 0
 		if (*addr != BREAKPOINT_INSTRUCTION) {
 			/*
+			 * PowerPC has multiple variants of the "trap"
+			 * instruction. If the current instruction is a
+			 * trap variant, it could belong to someone else
+			 */
+			kprobe_opcode_t cur_insn = *addr;
+			if (IS_TW(cur_insn) || IS_TD(cur_insn) ||
+					IS_TWI(cur_insn) || IS_TDI(cur_insn))
+		       		goto no_kprobe;
+			/*
 			 * The breakpoint instruction was removed right
 			 * after we hit it.  Another cpu has removed
 			 * either a probepoint or a debugger breakpoint
@@ -116,7 +136,6 @@ static inline int kprobe_handler(struct 
 			 */
 			ret = 1;
 		}
-#endif
 		/* Not one of ours: let kernel handle it */
 		goto no_kprobe;
 	}
@@ -124,18 +143,21 @@ static inline int kprobe_handler(struct 
 	kprobe_status = KPROBE_HIT_ACTIVE;
 	current_kprobe = p;
 	kprobe_saved_msr = regs->msr;
-	if (p->pre_handler(p, regs)) {
+	if (p->pre_handler && p->pre_handler(p, regs))
 		/* handler has already set things up, so skip ss setup */
 		return 1;
-	}
 
 ss_probe:
 	prepare_singlestep(p, regs);
 	kprobe_status = KPROBE_HIT_SS;
+	/*
+	 * This preempt_disable() matches the preempt_enable_no_resched()
+	 * in post_kprobe_handler().
+	 */
+	preempt_disable();
 	return 1;
 
 no_kprobe:
-	preempt_enable_no_resched();
 	return ret;
 }
 
@@ -155,8 +177,6 @@ static void resume_execution(struct kpro
 	ret = emulate_step(regs, p->ainsn.insn[0]);
 	if (ret == 0)
 		regs->nip = (unsigned long)p->addr + 4;
-
-	regs->msr &= ~MSR_SE;
 }
 
 static inline int post_kprobe_handler(struct pt_regs *regs)
@@ -193,6 +213,7 @@ static inline int kprobe_fault_handler(s
 
 	if (kprobe_status & KPROBE_HIT_SS) {
 		resume_execution(current_kprobe, regs);
+		regs->msr &= ~MSR_SE;
 		regs->msr |= kprobe_saved_msr;
 
 		unlock_kprobes();
@@ -208,27 +229,33 @@ int kprobe_exceptions_notify(struct noti
 			     void *data)
 {
 	struct die_args *args = (struct die_args *)data;
+	int ret = NOTIFY_DONE;
+
+	/*
+	 * Interrupts are not disabled here.  We need to disable
+	 * preemption, because kprobe_running() uses smp_processor_id().
+	 */
+	preempt_disable();
 	switch (val) {
-	case DIE_IABR_MATCH:
-	case DIE_DABR_MATCH:
 	case DIE_BPT:
 		if (kprobe_handler(args->regs))
-			return NOTIFY_STOP;
+			ret = NOTIFY_STOP;
 		break;
 	case DIE_SSTEP:
 		if (post_kprobe_handler(args->regs))
-			return NOTIFY_STOP;
+			ret = NOTIFY_STOP;
 		break;
 	case DIE_GPF:
 	case DIE_PAGE_FAULT:
 		if (kprobe_running() &&
 		    kprobe_fault_handler(args->regs, args->trapnr))
-			return NOTIFY_STOP;
+			ret = NOTIFY_STOP;
 		break;
 	default:
 		break;
 	}
-	return NOTIFY_DONE;
+	preempt_enable();
+	return ret;
 }
 
 int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
@@ -246,7 +273,6 @@ int setjmp_pre_handler(struct kprobe *p,
 
 void jprobe_return(void)
 {
-	preempt_enable_no_resched();
 	asm volatile("trap" ::: "memory");
 }
 
diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c
--- a/arch/ppc64/kernel/lmb.c
+++ b/arch/ppc64/kernel/lmb.c
@@ -344,3 +344,29 @@ lmb_abs_to_phys(unsigned long aa)
 
 	return pa;
 }
+
+/*
+ * Truncate the lmb list to memory_limit if it's set
+ * You must call lmb_analyze() after this.
+ */
+void __init lmb_enforce_memory_limit(void)
+{
+	extern unsigned long memory_limit;
+	unsigned long i, limit;
+	struct lmb_region *mem = &(lmb.memory);
+
+	if (! memory_limit)
+		return;
+
+	limit = memory_limit;
+	for (i = 0; i < mem->cnt; i++) {
+		if (limit > mem->region[i].size) {
+			limit -= mem->region[i].size;
+			continue;
+		}
+
+		mem->region[i].size = limit;
+		mem->cnt = i + 1;
+		break;
+	}
+}
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/ppc64/kernel/lparcfg.c
@@ -33,8 +33,9 @@
 #include <asm/cputable.h>
 #include <asm/rtas.h>
 #include <asm/system.h>
+#include <asm/time.h>
 
-#define MODULE_VERS "1.5"
+#define MODULE_VERS "1.6"
 #define MODULE_NAME "lparcfg"
 
 /* #define LPARCFG_DEBUG */
@@ -214,13 +215,20 @@ static void h_pic(unsigned long *pool_id
 }
 
 static unsigned long get_purr(void);
-/* ToDo:  get sum of purr across all processors.  The purr collection code
- * is coming, but at this time is still problematic, so for now this
- * function will return 0.
- */
+
+/* Track sum of all purrs across all processors. This is used to further */
+/* calculate usage values by different applications                       */
+
 static unsigned long get_purr(void)
 {
 	unsigned long sum_purr = 0;
+	int cpu;
+	struct cpu_usage *cu;
+
+	for_each_cpu(cpu) {
+		cu = &per_cpu(cpu_usage_array, cpu);
+		sum_purr += cu->current_tb;
+	}
 	return sum_purr;
 }
 
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
--- a/arch/ppc64/kernel/maple_setup.c
+++ b/arch/ppc64/kernel/maple_setup.c
@@ -142,7 +142,7 @@ static void __init maple_init_early(void
 	if (physport) {
 		void *comport;
 		/* Map the uart for udbg. */
-		comport = (void *)__ioremap(physport, 16, _PAGE_NO_CACHE);
+		comport = (void *)ioremap(physport, 16);
 		udbg_init_uart(comport, default_speed);
 
 		ppc_md.udbg_putc = udbg_putc;
diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c
--- a/arch/ppc64/kernel/mf.c
+++ b/arch/ppc64/kernel/mf.c
@@ -1,7 +1,7 @@
 /*
   * mf.c
   * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
-  * Copyright (C) 2004 Stephen Rothwell  IBM Corporation
+  * Copyright (C) 2004-2005 Stephen Rothwell  IBM Corporation
   *
   * This modules exists as an interface between a Linux secondary partition
   * running on an iSeries and the primary partition's Virtual Service
@@ -36,10 +36,12 @@
 
 #include <asm/time.h>
 #include <asm/uaccess.h>
+#include <asm/paca.h>
 #include <asm/iSeries/vio.h>
 #include <asm/iSeries/mf.h>
 #include <asm/iSeries/HvLpConfig.h>
 #include <asm/iSeries/ItSpCommArea.h>
+#include <asm/iSeries/ItLpQueue.h>
 
 /*
  * This is the structure layout for the Machine Facilites LPAR event
@@ -696,36 +698,23 @@ static void get_rtc_time_complete(void *
 	complete(&rtc->com);
 }
 
-int mf_get_rtc(struct rtc_time *tm)
+static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
 {
-	struct ce_msg_comp_data ce_complete;
-	struct rtc_time_data rtc_data;
-	int rc;
-
-	memset(&ce_complete, 0, sizeof(ce_complete));
-	memset(&rtc_data, 0, sizeof(rtc_data));
-	init_completion(&rtc_data.com);
-	ce_complete.handler = &get_rtc_time_complete;
-	ce_complete.token = &rtc_data;
-	rc = signal_ce_msg_simple(0x40, &ce_complete);
-	if (rc)
-		return rc;
-	wait_for_completion(&rtc_data.com);
 	tm->tm_wday = 0;
 	tm->tm_yday = 0;
 	tm->tm_isdst = 0;
-	if (rtc_data.rc) {
+	if (rc) {
 		tm->tm_sec = 0;
 		tm->tm_min = 0;
 		tm->tm_hour = 0;
 		tm->tm_mday = 15;
 		tm->tm_mon = 5;
 		tm->tm_year = 52;
-		return rtc_data.rc;
+		return rc;
 	}
 
-	if ((rtc_data.ce_msg.ce_msg[2] == 0xa9) ||
-	    (rtc_data.ce_msg.ce_msg[2] == 0xaf)) {
+	if ((ce_msg[2] == 0xa9) ||
+	    (ce_msg[2] == 0xaf)) {
 		/* TOD clock is not set */
 		tm->tm_sec = 1;
 		tm->tm_min = 1;
@@ -736,7 +725,6 @@ int mf_get_rtc(struct rtc_time *tm)
 		mf_set_rtc(tm);
 	}
 	{
-		u8 *ce_msg = rtc_data.ce_msg.ce_msg;
 		u8 year = ce_msg[5];
 		u8 sec = ce_msg[6];
 		u8 min = ce_msg[7];
@@ -765,6 +753,63 @@ int mf_get_rtc(struct rtc_time *tm)
 	return 0;
 }
 
+int mf_get_rtc(struct rtc_time *tm)
+{
+	struct ce_msg_comp_data ce_complete;
+	struct rtc_time_data rtc_data;
+	int rc;
+
+	memset(&ce_complete, 0, sizeof(ce_complete));
+	memset(&rtc_data, 0, sizeof(rtc_data));
+	init_completion(&rtc_data.com);
+	ce_complete.handler = &get_rtc_time_complete;
+	ce_complete.token = &rtc_data;
+	rc = signal_ce_msg_simple(0x40, &ce_complete);
+	if (rc)
+		return rc;
+	wait_for_completion(&rtc_data.com);
+	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
+}
+
+struct boot_rtc_time_data {
+	int busy;
+	struct ce_msg_data ce_msg;
+	int rc;
+};
+
+static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
+{
+	struct boot_rtc_time_data *rtc = token;
+
+	memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
+	rtc->rc = 0;
+	rtc->busy = 0;
+}
+
+int mf_get_boot_rtc(struct rtc_time *tm)
+{
+	struct ce_msg_comp_data ce_complete;
+	struct boot_rtc_time_data rtc_data;
+	int rc;
+
+	memset(&ce_complete, 0, sizeof(ce_complete));
+	memset(&rtc_data, 0, sizeof(rtc_data));
+	rtc_data.busy = 1;
+	ce_complete.handler = &get_boot_rtc_time_complete;
+	ce_complete.token = &rtc_data;
+	rc = signal_ce_msg_simple(0x40, &ce_complete);
+	if (rc)
+		return rc;
+	/* We need to poll here as we are not yet taking interrupts */
+	while (rtc_data.busy) {
+		extern unsigned long lpevent_count;
+		struct ItLpQueue *lpq = get_paca()->lpqueue_ptr;
+		if (lpq && ItLpQueue_isLpIntPending(lpq))
+			lpevent_count += ItLpQueue_process(lpq, NULL);
+	}
+	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
+}
+
 int mf_set_rtc(struct rtc_time *tm)
 {
 	char ce_time[12];
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -32,7 +32,7 @@
 	.text
 
 /*
- * Returns (address we're running at) - (address we were linked at)
+ * Returns (address we were linked at) - (address we are running at)
  * for use before the text and data are mapped to KERNELBASE.
  */
 
@@ -292,6 +292,26 @@ _GLOBAL(flush_dcache_phys_range)
 	isync
 	blr
 
+_GLOBAL(flush_inval_dcache_range)
+ 	ld	r10,PPC64_CACHES@toc(r2)
+	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	addi	r5,r7,-1
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5		/* ensure we get enough */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
+	srw.	r8,r8,r9		/* compute line count */
+	beqlr				/* nothing to do? */
+	sync
+	isync
+	mtctr	r8
+0:	dcbf	0,r6
+	add	r6,r6,r7
+	bdnz	0b
+	sync
+	isync
+	blr
+
 
 /*
  * Flush a particular page from the data cache to RAM.
@@ -660,10 +680,6 @@ _GLOBAL(kernel_thread)
 	ld	r30,-16(r1)
 	blr
 
-#ifndef CONFIG_PPC_PSERIES	/* hack hack hack */
-#define ppc_rtas	sys_ni_syscall
-#endif
-
 /* Why isn't this a) automatic, b) written in 'C'? */	
 	.balign 8
 _GLOBAL(sys_call_table32)
@@ -776,7 +792,7 @@ _GLOBAL(sys_call_table32)
 	.llong .compat_sys_newstat
 	.llong .compat_sys_newlstat
 	.llong .compat_sys_newfstat
-	.llong .sys_uname
+	.llong .sys32_uname
 	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall		/* old idle syscall */
@@ -939,6 +955,7 @@ _GLOBAL(sys_call_table32)
 	.llong .sys32_add_key
 	.llong .sys32_request_key
 	.llong .compat_sys_keyctl
+	.llong .compat_sys_waitid
 
 	.balign 8
 _GLOBAL(sys_call_table)
@@ -1214,3 +1231,4 @@ _GLOBAL(sys_call_table)
 	.llong .sys_add_key
 	.llong .sys_request_key		/* 270 */
 	.llong .sys_keyctl
+	.llong .sys_waitid
diff --git a/arch/ppc64/kernel/module.c b/arch/ppc64/kernel/module.c
--- a/arch/ppc64/kernel/module.c
+++ b/arch/ppc64/kernel/module.c
@@ -102,7 +102,8 @@ void *module_alloc(unsigned long size)
 {
 	if (size == 0)
 		return NULL;
-	return vmalloc(size);
+
+	return vmalloc_exec(size);
 }
 
 /* Free memory returned from module_alloc */
diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
--- a/arch/ppc64/kernel/nvram.c
+++ b/arch/ppc64/kernel/nvram.c
@@ -89,7 +89,7 @@ static ssize_t dev_nvram_read(struct fil
 		return -ENODEV;
 	size = ppc_md.nvram_size();
 
-	if (verify_area(VERIFY_WRITE, buf, count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 	if (*ppos >= size)
 		return 0;
@@ -129,7 +129,7 @@ static ssize_t dev_nvram_write(struct fi
 		return -ENODEV;
 	size = ppc_md.nvram_size();
 
-	if (verify_area(VERIFY_READ, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 	if (*ppos >= size)
 		return 0;
@@ -339,9 +339,9 @@ static int nvram_remove_os_partition(voi
 static int nvram_create_os_partition(void)
 {
 	struct list_head * p;
-	struct nvram_partition * part;
-	struct nvram_partition * new_part = NULL;
-	struct nvram_partition * free_part = NULL;
+	struct nvram_partition *part = NULL;
+	struct nvram_partition *new_part = NULL;
+	struct nvram_partition *free_part = NULL;
 	int seq_init[2] = { 0, 0 };
 	loff_t tmp_index;
 	long size = 0;
@@ -364,13 +364,11 @@ static int nvram_create_os_partition(voi
 			free_part = part;
 		}
 	}
-	if (!size) {
+	if (!size)
 		return -ENOSPC;
-	}
 	
 	/* Create our OS partition */
-	new_part = (struct nvram_partition *)
-		kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+	new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
 	if (!new_part) {
 		printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n");
 		return -ENOMEM;
@@ -379,7 +377,7 @@ static int nvram_create_os_partition(voi
 	new_part->index = free_part->index;
 	new_part->header.signature = NVRAM_SIG_OS;
 	new_part->header.length = size;
-	sprintf(new_part->header.name, "ppc64,linux");
+	strcpy(new_part->header.name, "ppc64,linux");
 	new_part->header.checksum = nvram_checksum(&new_part->header);
 
 	rc = nvram_write_header(new_part);
@@ -394,7 +392,8 @@ static int nvram_create_os_partition(voi
 	tmp_index = new_part->index + NVRAM_HEADER_LEN;
 	rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index);
 	if (rc <= 0) {
-		printk(KERN_ERR "nvram_create_os_partition: nvram_write failed (%d)\n", rc);
+		printk(KERN_ERR "nvram_create_os_partition: nvram_write "
+				"failed (%d)\n", rc);
 		return rc;
 	}
 	
@@ -507,8 +506,8 @@ static int nvram_scan_partitions(void)
 	struct nvram_partition * tmp_part;
 	unsigned char c_sum;
 	char * header;
-	long size;
 	int total_size;
+	int err;
 
 	if (ppc_md.nvram_size == NULL)
 		return -ENODEV;
@@ -522,29 +521,37 @@ static int nvram_scan_partitions(void)
 
 	while (cur_index < total_size) {
 
-		size = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
-		if (size != NVRAM_HEADER_LEN) {
+		err = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
+		if (err != NVRAM_HEADER_LEN) {
 			printk(KERN_ERR "nvram_scan_partitions: Error parsing "
 			       "nvram partitions\n");
-			kfree(header);
-			return size;
+			goto out;
 		}
 
 		cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
 
 		memcpy(&phead, header, NVRAM_HEADER_LEN);
 
+		err = 0;
 		c_sum = nvram_checksum(&phead);
-		if (c_sum != phead.checksum)
-			printk(KERN_WARNING "WARNING: nvram partition checksum "
-			       "was %02x, should be %02x!\n", phead.checksum, c_sum);
-		
+		if (c_sum != phead.checksum) {
+			printk(KERN_WARNING "WARNING: nvram partition checksum"
+			       " was %02x, should be %02x!\n",
+			       phead.checksum, c_sum);
+			printk(KERN_WARNING "Terminating nvram partition scan\n");
+			goto out;
+		}
+		if (!phead.length) {
+			printk(KERN_WARNING "WARNING: nvram corruption "
+			       "detected: 0-length partition\n");
+			goto out;
+		}
 		tmp_part = (struct nvram_partition *)
 			kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+		err = -ENOMEM;
 		if (!tmp_part) {
 			printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
-			kfree(header);
-			return -ENOMEM;
+			goto out;
 		}
 		
 		memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
@@ -553,9 +560,11 @@ static int nvram_scan_partitions(void)
 		
 		cur_index += phead.length * NVRAM_BLOCK_LEN;
 	}
+	err = 0;
 
+ out:
 	kfree(header);
-	return 0;
+	return err;
 }
 
 static int __init nvram_init(void)
diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c
--- a/arch/ppc64/kernel/of_device.c
+++ b/arch/ppc64/kernel/of_device.c
@@ -104,7 +104,7 @@ static int of_device_remove(struct devic
 	return 0;
 }
 
-static int of_device_suspend(struct device *dev, u32 state)
+static int of_device_suspend(struct device *dev, pm_message_t state)
 {
 	struct of_device * of_dev = to_of_device(dev);
 	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
diff --git a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S
--- a/arch/ppc64/kernel/pSeries_hvCall.S
+++ b/arch/ppc64/kernel/pSeries_hvCall.S
@@ -1,7 +1,6 @@
 /*
  * arch/ppc64/kernel/pSeries_hvCall.S
  *
- *
  * This file contains the generic code to perform a call to the
  * pSeries LPAR hypervisor.
  * NOTE: this file will go away when we move to inline this work.
@@ -11,133 +10,122 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include <linux/sys.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
+#include <asm/hvcall.h>
 #include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cache.h>
 #include <asm/ppc_asm.h>
 	
-/*
- * hcall interface to pSeries LPAR
- */
-#define HVSC .long 0x44000022
-
-/* long plpar_hcall(unsigned long opcode,	 R3 
-		 unsigned long arg1,		 R4 
-		 unsigned long arg2,		 R5 
-		 unsigned long arg3,		 R6 
-		 unsigned long arg4,		 R7 
-		 unsigned long *out1,		 R8 
-		 unsigned long *out2,		 R9
-		 unsigned long *out3);		 R10
- */
+#define STK_PARM(i)     (48 + ((i)-3)*8)
 
 	.text
+
+/* long plpar_hcall(unsigned long opcode,		R3
+			unsigned long arg1,		R4
+			unsigned long arg2,		R5
+			unsigned long arg3,		R6
+			unsigned long arg4,		R7
+			unsigned long *out1,		R8
+			unsigned long *out2,		R9
+			unsigned long *out3);		R10
+ */
 _GLOBAL(plpar_hcall)
-	mfcr	r0
-	std	r0,-8(r1)
-	stdu	r1,-32(r1)
+	HMT_MEDIUM
 
-        std     r8,-8(r1)       /* Save out ptrs. */
-        std     r9,-16(r1)
-        std     r10,-24(r1)
-	
-	HVSC                    /* invoke the hypervisor */
+	mfcr	r0
 
-        ld      r10,-8(r1)      /* Fetch r4-r7 ret args. */
-        std     r4,0(r10)
-        ld      r10,-16(r1)
-        std     r5,0(r10)
-        ld      r10,-24(r1)
-        std     r6,0(r10)
+	std	r8,STK_PARM(r8)(r1)	/* Save out ptrs */
+	std	r9,STK_PARM(r9)(r1)
+	std	r10,STK_PARM(r10)(r1)
+
+	stw	r0,8(r1)
+
+	HVSC				/* invoke the hypervisor */
+
+	lwz	r0,8(r1)
+
+	ld	r8,STK_PARM(r8)(r1)	/* Fetch r4-r6 ret args */
+	ld	r9,STK_PARM(r9)(r1)
+	ld	r10,STK_PARM(r10)(r1)
+	std	r4,0(r8)
+	std	r5,0(r9)
+	std	r6,0(r10)
 
-	ld	r1,0(r1)
-	ld	r0,-8(r1)
 	mtcrf	0xff,r0
-	blr                     /* return r3 = status */
+	blr				/* return r3 = status */
 
 
 /* Simple interface with no output values (other than status) */
 _GLOBAL(plpar_hcall_norets)
+	HMT_MEDIUM
+
 	mfcr	r0
-	std	r0,-8(r1)
-	HVSC                    /* invoke the hypervisor */
-	ld	r0,-8(r1)
-	mtcrf	0xff,r0
-	blr                     /* return r3 = status */
+	stw	r0,8(r1)
 
+	HVSC				/* invoke the hypervisor */
 
-/* long plpar_hcall_8arg_2ret(unsigned long opcode,		 R3 
-			     unsigned long arg1,		 R4 
-		 	     unsigned long arg2,		 R5 
-			     unsigned long arg3,		 R6 
-	 		     unsigned long arg4,		 R7 
-	 		     unsigned long arg5,		 R8 
-			     unsigned long arg6,		 R9 
-	 		     unsigned long arg7,		 R10 
-	 		     unsigned long arg8,		 112(R1)
-	 		     unsigned long *out1);		 120(R1)
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+	blr				/* return r3 = status */
 
- */
 
-	.text
+/* long plpar_hcall_8arg_2ret(unsigned long opcode,	R3
+			unsigned long arg1,		R4
+			unsigned long arg2,		R5
+			unsigned long arg3,		R6
+			unsigned long arg4,		R7
+			unsigned long arg5,		R8
+			unsigned long arg6,		R9
+			unsigned long arg7,		R10
+			unsigned long arg8,		112(R1)
+			unsigned long *out1);		120(R1)
+ */
 _GLOBAL(plpar_hcall_8arg_2ret)
-	mfcr	r0
-
-	ld              r11, 112(r1) /* put arg8 and out1 in R11 and R12 */
-	ld              r12, 120(r1)
+	HMT_MEDIUM
 
-	std	r0,-8(r1)
-	stdu	r1,-32(r1)
-
-        std     r12,-8(r1)      /* Save out ptr */
-	
-	HVSC                    /* invoke the hypervisor */
+	mfcr	r0
+	ld	r11,STK_PARM(r11)(r1)	/* put arg8 in R11 */
+	stw	r0,8(r1)
 
-        ld      r10,-8(r1)      /* Fetch r4 ret arg */
-        std     r4,0(r10)
+	HVSC				/* invoke the hypervisor */
 
-	ld	r1,0(r1)
-	ld	r0,-8(r1)
+	lwz	r0,8(r1)
+	ld	r10,STK_PARM(r12)(r1)	/* Fetch r4 ret arg */
+	std	r4,0(r10)
 	mtcrf	0xff,r0
-	blr                     /* return r3 = status */
+	blr				/* return r3 = status */
 
 
-/* long plpar_hcall_4out(unsigned long opcode,	 R3 
-		 unsigned long arg1,		 R4 
-		 unsigned long arg2,		 R5 
-		 unsigned long arg3,		 R6 
-		 unsigned long arg4,		 R7 
-		 unsigned long *out1,	(r4)	 R8 
-		 unsigned long *out2,	(r5)	 R9
-		 unsigned long *out3,   (r6)     R10
-		 unsigned long *out4);	(r7)	 112(R1). From Parameter save area. 
+/* long plpar_hcall_4out(unsigned long opcode,		R3
+		 	unsigned long arg1,		R4
+		 	unsigned long arg2,		R5
+		 	unsigned long arg3,		R6
+		 	unsigned long arg4,		R7
+		 	unsigned long *out1,		R8
+		 	unsigned long *out2,		R9
+		 	unsigned long *out3,		R10
+		 	unsigned long *out4);		112(R1)
  */
 _GLOBAL(plpar_hcall_4out)
+	HMT_MEDIUM
+
 	mfcr	r0
-	std	r0,-8(r1)
-	ld      r14,112(r1)
-	stdu	r1,-48(r1) 
-
-	std     r8,32(r1)       /* Save out ptrs. */
-	std     r9,24(r1)
-	std     r10,16(r1)
-	std     r14,8(r1)
-	
-	HVSC                    /* invoke the hypervisor */
+	stw	r0,8(r1)
 
-	ld      r14,32(r1)      /* Fetch r4-r7 ret args. */
-	std     r4,0(r14)
-	ld      r14,24(r1)
-	std     r5,0(r14)
-	ld      r14,16(r1)
-	std     r6,0(r14)
-	ld      r14,8(r1)
-	std     r7,0(r14)
+	std	r8,STK_PARM(r8)(r1)	/* Save out ptrs */
+	std	r9,STK_PARM(r9)(r1)
+	std	r10,STK_PARM(r10)(r1)
+
+	HVSC				/* invoke the hypervisor */
+
+	lwz	r0,8(r1)
+
+	ld	r8,STK_PARM(r8)(r1)	/* Fetch r4-r7 ret args */
+	ld	r9,STK_PARM(r9)(r1)
+	ld	r10,STK_PARM(r10)(r1)
+	ld	r11,STK_PARM(r11)(r1)
+	std	r4,0(r8)
+	std	r5,0(r9)
+	std	r6,0(r10)
+	std	r7,0(r11)
 
-	ld	r1,0(r1) 
-	ld	r0,-8(r1)
 	mtcrf	0xff,r0
-	blr                     /* return r3 = status */
+	blr				/* return r3 = status */
diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c
--- a/arch/ppc64/kernel/pSeries_iommu.c
+++ b/arch/ppc64/kernel/pSeries_iommu.c
@@ -43,6 +43,7 @@
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/pSeries_reconfig.h>
 #include <asm/systemcfg.h>
 #include "pci.h"
 
@@ -401,6 +402,8 @@ static void iommu_bus_setup_pSeriesLP(st
 	struct device_node *dn, *pdn;
 	unsigned int *dma_window = NULL;
 
+	DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
+
 	dn = pci_bus_to_OF_node(bus);
 
 	/* Find nearest ibm,dma-window, walking up the device tree */
@@ -455,6 +458,78 @@ static void iommu_dev_setup_pSeries(stru
 	}
 }
 
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+	int err = NOTIFY_OK;
+	struct device_node *np = node;
+
+	switch (action) {
+	case PSERIES_RECONFIG_REMOVE:
+		if (np->iommu_table &&
+		    get_property(np, "ibm,dma-window", NULL))
+			iommu_free_table(np);
+		break;
+	default:
+		err = NOTIFY_DONE;
+		break;
+	}
+	return err;
+}
+
+static struct notifier_block iommu_reconfig_nb = {
+	.notifier_call = iommu_reconfig_notifier,
+};
+
+static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
+{
+	struct device_node *pdn, *dn;
+	struct iommu_table *tbl;
+	int *dma_window = NULL;
+
+	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);
+
+	/* dev setup for LPAR is a little tricky, since the device tree might
+	 * contain the dma-window properties per-device and not neccesarily
+	 * for the bus. So we need to search upwards in the tree until we
+	 * either hit a dma-window property, OR find a parent with a table
+	 * already allocated.
+	 */
+	dn = pci_device_to_OF_node(dev);
+
+	for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) {
+		dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
+		if (dma_window)
+			break;
+	}
+
+	/* Check for parent == NULL so we don't try to setup the empty EADS
+	 * slots on POWER4 machines.
+	 */
+	if (dma_window == NULL || pdn->parent == NULL) {
+		/* Fall back to regular (non-LPAR) dev setup */
+		DBG("No dma window for device, falling back to regular setup\n");
+		iommu_dev_setup_pSeries(dev);
+		return;
+	} else {
+		DBG("Found DMA window, allocating table\n");
+	}
+
+	if (!pdn->iommu_table) {
+		/* iommu_table_setparms_lpar needs bussubno. */
+		pdn->bussubno = pdn->phb->bus->number;
+
+		tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
+						    GFP_KERNEL);
+
+		iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
+
+		pdn->iommu_table = iommu_init_table(tbl);
+	}
+
+	if (pdn != dn)
+		dn->iommu_table = pdn->iommu_table;
+}
+
 static void iommu_bus_setup_null(struct pci_bus *b) { }
 static void iommu_dev_setup_null(struct pci_dev *d) { }
 
@@ -479,13 +554,16 @@ void iommu_init_early_pSeries(void)
 			ppc_md.tce_free	 = tce_free_pSeriesLP;
 		}
 		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
+		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
 	} else {
 		ppc_md.tce_build = tce_build_pSeries;
 		ppc_md.tce_free  = tce_free_pSeries;
 		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
+		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
 	}
 
-	ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
+
+	pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
 
 	pci_iommu_init();
 }
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c
+++ b/arch/ppc64/kernel/pSeries_lpar.c
@@ -470,7 +470,7 @@ static void pSeries_lpar_hpte_updatebolt
 	slot = pSeries_lpar_hpte_find(vpn);
 	BUG_ON(slot == -1);
 
-	flags = newpp & 3;
+	flags = newpp & 7;
 	lpar_rc = plpar_pte_protect(flags, slot, 0);
 
 	BUG_ON(lpar_rc != H_Success);
@@ -505,7 +505,7 @@ void pSeries_lpar_flush_hash_range(unsig
 	int i;
 	unsigned long flags = 0;
 	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
-	int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+	int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
 	if (lock_tlbie)
 		spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
diff --git a/arch/ppc64/kernel/pSeries_nvram.c b/arch/ppc64/kernel/pSeries_nvram.c
--- a/arch/ppc64/kernel/pSeries_nvram.c
+++ b/arch/ppc64/kernel/pSeries_nvram.c
@@ -11,14 +11,9 @@
  * This perhaps should live in drivers/char
  */
 
-#include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/fcntl.h>
-#include <linux/nvram.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c
+++ b/arch/ppc64/kernel/pSeries_pci.c
@@ -52,6 +52,16 @@ static int s7a_workaround;
 
 extern struct mpic *pSeries_mpic;
 
+static int config_access_valid(struct device_node *dn, int where)
+{
+	if (where < 256)
+		return 1;
+	if (where < 4096 && dn->pci_ext_config_space)
+		return 1;
+
+	return 0;
+}
+
 static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
 {
 	int returnval = -1;
@@ -60,10 +70,11 @@ static int rtas_read_config(struct devic
 
 	if (!dn)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (where & (size - 1))
+	if (!config_access_valid(dn, where))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
-	addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+	addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
+		(dn->devfn << 8) | (where & 0xff);
 	buid = dn->phb->buid;
 	if (buid) {
 		ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
@@ -108,10 +119,11 @@ static int rtas_write_config(struct devi
 
 	if (!dn)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (where & (size - 1))
+	if (!config_access_valid(dn, where))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
-	addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+	addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
+		(dn->devfn << 8) | (where & 0xff);
 	buid = dn->phb->buid;
 	if (buid) {
 		ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
@@ -412,16 +424,18 @@ struct pci_controller * __devinit init_p
 	unsigned int root_size_cells = 0;
 	struct pci_controller *phb;
 	struct pci_bus *bus;
+	int primary;
 
 	root_size_cells = prom_n_size_cells(root);
 
+	primary = list_empty(&hose_list);
 	phb = alloc_phb_dynamic(dn, root_size_cells);
 	if (!phb)
 		return NULL;
 
 	pci_process_bridge_OF_ranges(phb, dn);
 
-	pci_setup_phb_io_dynamic(phb);
+	pci_setup_phb_io_dynamic(phb, primary);
 	of_node_put(root);
 
 	pci_devs_phb_init_dynamic(phb);
@@ -526,6 +540,9 @@ EXPORT_SYMBOL(pcibios_remove_root_bus);
 
 static void __init pSeries_request_regions(void)
 {
+	if (!isa_io_base)
+		return;
+
 	request_region(0x20,0x20,"pic1");
 	request_region(0xa0,0x20,"pic2");
 	request_region(0x00,0x20,"dma1");
diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/pSeries_reconfig.c
@@ -0,0 +1,426 @@
+/*
+ * pSeries_reconfig.c - support for dynamic reconfiguration (including PCI
+ * Hotplug and Dynamic Logical Partitioning on RPA platforms).
+ *
+ * Copyright (C) 2005 Nathan Lynch
+ * Copyright (C) 2005 IBM Corporation
+ *
+ *
+ *	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/kernel.h>
+#include <linux/kref.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+
+#include <asm/prom.h>
+#include <asm/pSeries_reconfig.h>
+#include <asm/uaccess.h>
+
+
+
+/*
+ * Routines for "runtime" addition and removal of device tree nodes.
+ */
+#ifdef CONFIG_PROC_DEVICETREE
+/*
+ * Add a node to /proc/device-tree.
+ */
+static void add_node_proc_entries(struct device_node *np)
+{
+	struct proc_dir_entry *ent;
+
+	ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);
+	if (ent)
+		proc_device_tree_add_node(np, ent);
+}
+
+static void remove_node_proc_entries(struct device_node *np)
+{
+	struct property *pp = np->properties;
+	struct device_node *parent = np->parent;
+
+	while (pp) {
+		remove_proc_entry(pp->name, np->pde);
+		pp = pp->next;
+	}
+	if (np->pde)
+		remove_proc_entry(np->pde->name, parent->pde);
+}
+#else /* !CONFIG_PROC_DEVICETREE */
+static void add_node_proc_entries(struct device_node *np)
+{
+	return;
+}
+
+static void remove_node_proc_entries(struct device_node *np)
+{
+	return;
+}
+#endif /* CONFIG_PROC_DEVICETREE */
+
+/**
+ *	derive_parent - basically like dirname(1)
+ *	@path:  the full_name of a node to be added to the tree
+ *
+ *	Returns the node which should be the parent of the node
+ *	described by path.  E.g., for path = "/foo/bar", returns
+ *	the node with full_name = "/foo".
+ */
+static struct device_node *derive_parent(const char *path)
+{
+	struct device_node *parent = NULL;
+	char *parent_path = "/";
+	size_t parent_path_len = strrchr(path, '/') - path + 1;
+
+	/* reject if path is "/" */
+	if (!strcmp(path, "/"))
+		return ERR_PTR(-EINVAL);
+
+	if (strrchr(path, '/') != path) {
+		parent_path = kmalloc(parent_path_len, GFP_KERNEL);
+		if (!parent_path)
+			return ERR_PTR(-ENOMEM);
+		strlcpy(parent_path, path, parent_path_len);
+	}
+	parent = of_find_node_by_path(parent_path);
+	if (!parent)
+		return ERR_PTR(-EINVAL);
+	if (strcmp(parent_path, "/"))
+		kfree(parent_path);
+	return parent;
+}
+
+static struct notifier_block *pSeries_reconfig_chain;
+
+int pSeries_reconfig_notifier_register(struct notifier_block *nb)
+{
+	return notifier_chain_register(&pSeries_reconfig_chain, nb);
+}
+
+void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
+{
+	notifier_chain_unregister(&pSeries_reconfig_chain, nb);
+}
+
+static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
+{
+	struct device_node *np;
+	int err = -ENOMEM;
+
+	np = kcalloc(1, sizeof(*np), GFP_KERNEL);
+	if (!np)
+		goto out_err;
+
+	np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
+	if (!np->full_name)
+		goto out_err;
+
+	strcpy(np->full_name, path);
+
+	np->properties = proplist;
+	OF_MARK_DYNAMIC(np);
+	kref_init(&np->kref);
+
+	np->parent = derive_parent(path);
+	if (IS_ERR(np->parent)) {
+		err = PTR_ERR(np->parent);
+		goto out_err;
+	}
+
+	err = notifier_call_chain(&pSeries_reconfig_chain,
+				  PSERIES_RECONFIG_ADD, np);
+	if (err == NOTIFY_BAD) {
+		printk(KERN_ERR "Failed to add device node %s\n", path);
+		err = -ENOMEM; /* For now, safe to assume kmalloc failure */
+		goto out_err;
+	}
+
+	of_attach_node(np);
+
+	add_node_proc_entries(np);
+
+	of_node_put(np->parent);
+
+	return 0;
+
+out_err:
+	if (np) {
+		of_node_put(np->parent);
+		kfree(np->full_name);
+		kfree(np);
+	}
+	return err;
+}
+
+static int pSeries_reconfig_remove_node(struct device_node *np)
+{
+	struct device_node *parent, *child;
+
+	parent = of_get_parent(np);
+	if (!parent)
+		return -EINVAL;
+
+	if ((child = of_get_next_child(np, NULL))) {
+		of_node_put(child);
+		return -EBUSY;
+	}
+
+	remove_node_proc_entries(np);
+
+	notifier_call_chain(&pSeries_reconfig_chain,
+			    PSERIES_RECONFIG_REMOVE, np);
+	of_detach_node(np);
+
+	of_node_put(parent);
+	of_node_put(np); /* Must decrement the refcount */
+	return 0;
+}
+
+/*
+ * /proc/ppc64/ofdt - yucky binary interface for adding and removing
+ * OF device nodes.  Should be deprecated as soon as we get an
+ * in-kernel wrapper for the RTAS ibm,configure-connector call.
+ */
+
+static void release_prop_list(const struct property *prop)
+{
+	struct property *next;
+	for (; prop; prop = next) {
+		next = prop->next;
+		kfree(prop->name);
+		kfree(prop->value);
+		kfree(prop);
+	}
+
+}
+
+/**
+ * parse_next_property - process the next property from raw input buffer
+ * @buf: input buffer, must be nul-terminated
+ * @end: end of the input buffer + 1, for validation
+ * @name: return value; set to property name in buf
+ * @length: return value; set to length of value
+ * @value: return value; set to the property value in buf
+ *
+ * Note that the caller must make copies of the name and value returned,
+ * this function does no allocation or copying of the data.  Return value
+ * is set to the next name in buf, or NULL on error.
+ */
+static char * parse_next_property(char *buf, char *end, char **name, int *length,
+				  unsigned char **value)
+{
+	char *tmp;
+
+	*name = buf;
+
+	tmp = strchr(buf, ' ');
+	if (!tmp) {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+	*tmp = '\0';
+
+	if (++tmp >= end) {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+
+	/* now we're on the length */
+	*length = -1;
+	*length = simple_strtoul(tmp, &tmp, 10);
+	if (*length == -1) {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+	if (*tmp != ' ' || ++tmp >= end) {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+
+	/* now we're on the value */
+	*value = tmp;
+	tmp += *length;
+	if (tmp > end) {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+	else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
+		printk(KERN_ERR "property parse failed in %s at line %d\n",
+		       __FUNCTION__, __LINE__);
+		return NULL;
+	}
+	tmp++;
+
+	/* and now we should be on the next name, or the end */
+	return tmp;
+}
+
+static struct property *new_property(const char *name, const int length,
+				     const unsigned char *value, struct property *last)
+{
+	struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
+
+	if (!new)
+		return NULL;
+	memset(new, 0, sizeof(*new));
+
+	if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL)))
+		goto cleanup;
+	if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
+		goto cleanup;
+
+	strcpy(new->name, name);
+	memcpy(new->value, value, length);
+	*(((char *)new->value) + length) = 0;
+	new->length = length;
+	new->next = last;
+	return new;
+
+cleanup:
+	if (new->name)
+		kfree(new->name);
+	if (new->value)
+		kfree(new->value);
+	kfree(new);
+	return NULL;
+}
+
+static int do_add_node(char *buf, size_t bufsize)
+{
+	char *path, *end, *name;
+	struct device_node *np;
+	struct property *prop = NULL;
+	unsigned char* value;
+	int length, rv = 0;
+
+	end = buf + bufsize;
+	path = buf;
+	buf = strchr(buf, ' ');
+	if (!buf)
+		return -EINVAL;
+	*buf = '\0';
+	buf++;
+
+	if ((np = of_find_node_by_path(path))) {
+		of_node_put(np);
+		return -EINVAL;
+	}
+
+	/* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
+	while (buf < end &&
+	       (buf = parse_next_property(buf, end, &name, &length, &value))) {
+		struct property *last = prop;
+
+		prop = new_property(name, length, value, last);
+		if (!prop) {
+			rv = -ENOMEM;
+			prop = last;
+			goto out;
+		}
+	}
+	if (!buf) {
+		rv = -EINVAL;
+		goto out;
+	}
+
+	rv = pSeries_reconfig_add_node(path, prop);
+
+out:
+	if (rv)
+		release_prop_list(prop);
+	return rv;
+}
+
+static int do_remove_node(char *buf)
+{
+	struct device_node *node;
+	int rv = -ENODEV;
+
+	if ((node = of_find_node_by_path(buf)))
+		rv = pSeries_reconfig_remove_node(node);
+
+	of_node_put(node);
+	return rv;
+}
+
+/**
+ * ofdt_write - perform operations on the Open Firmware device tree
+ *
+ * @file: not used
+ * @buf: command and arguments
+ * @count: size of the command buffer
+ * @off: not used
+ *
+ * Operations supported at this time are addition and removal of
+ * whole nodes along with their properties.  Operations on individual
+ * properties are not implemented (yet).
+ */
+static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count,
+			  loff_t *off)
+{
+	int rv = 0;
+	char *kbuf;
+	char *tmp;
+
+	if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) {
+		rv = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(kbuf, buf, count)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	kbuf[count] = '\0';
+
+	tmp = strchr(kbuf, ' ');
+	if (!tmp) {
+		rv = -EINVAL;
+		goto out;
+	}
+	*tmp = '\0';
+	tmp++;
+
+	if (!strcmp(kbuf, "add_node"))
+		rv = do_add_node(tmp, count - (tmp - kbuf));
+	else if (!strcmp(kbuf, "remove_node"))
+		rv = do_remove_node(tmp);
+	else
+		rv = -EINVAL;
+out:
+	kfree(kbuf);
+	return rv ? rv : count;
+}
+
+static struct file_operations ofdt_fops = {
+	.write = ofdt_write
+};
+
+/* create /proc/ppc64/ofdt write-only by root */
+static int proc_ppc64_create_ofdt(void)
+{
+	struct proc_dir_entry *ent;
+
+	if (!(systemcfg->platform & PLATFORM_PSERIES))
+		return 0;
+
+	ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
+	if (ent) {
+		ent->nlink = 1;
+		ent->data = NULL;
+		ent->size = 0;
+		ent->proc_fops = &ofdt_fops;
+	}
+
+	return 0;
+}
+__initcall(proc_ppc64_create_ofdt);
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -320,9 +320,10 @@ static  void __init pSeries_discover_pic
 	}
 }
 
-static void pSeries_cpu_die(void)
+static void pSeries_mach_cpu_die(void)
 {
 	local_irq_disable();
+	idle_task_exit();
 	/* Some hardware requires clearing the CPPR, while other hardware does not
 	 * it is safe either way
 	 */
@@ -362,7 +363,7 @@ static void __init pSeries_init_early(vo
 		find_udbg_vterm();
 	else if (physport) {
 		/* Map the uart for udbg. */
-		comport = (void *)__ioremap(physport, 16, _PAGE_NO_CACHE);
+		comport = (void *)ioremap(physport, 16);
 		udbg_init_uart(comport, default_speed);
 
 		ppc_md.udbg_putc = udbg_putc;
@@ -599,7 +600,7 @@ struct machdep_calls __initdata pSeries_
 	.power_off		= rtas_power_off,
 	.halt			= rtas_halt,
 	.panic			= rtas_os_term,
-	.cpu_die		= pSeries_cpu_die,
+	.cpu_die		= pSeries_mach_cpu_die,
 	.get_boot_time		= pSeries_get_boot_time,
 	.get_rtc_time		= pSeries_get_rtc_time,
 	.set_rtc_time		= pSeries_set_rtc_time,
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c
--- a/arch/ppc64/kernel/pSeries_smp.c
+++ b/arch/ppc64/kernel/pSeries_smp.c
@@ -44,6 +44,7 @@
 #include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/pSeries_reconfig.h>
 
 #include "mpic.h"
 
@@ -53,8 +54,16 @@
 #define DBG(fmt...)
 #endif
 
+/*
+ * The primary thread of each non-boot processor is recorded here before
+ * smp init.
+ */
+static cpumask_t of_spin_map;
+
 extern void pSeries_secondary_smp_init(unsigned long);
 
+#ifdef CONFIG_HOTPLUG_CPU
+
 /* Get state of physical CPU.
  * Return codes:
  *	0	- The processor is in the RTAS stopped state
@@ -81,9 +90,6 @@ static int query_cpu_stopped(unsigned in
 	return cpu_status;
 }
 
-
-#ifdef CONFIG_HOTPLUG_CPU
-
 int pSeries_cpu_disable(void)
 {
 	systemcfg->processorCount--;
@@ -122,60 +128,134 @@ void pSeries_cpu_die(unsigned int cpu)
 	paca[cpu].cpu_start = 0;
 }
 
-/* Search all cpu device nodes for an offline logical cpu.  If a
- * device node has a "ibm,my-drc-index" property (meaning this is an
- * LPAR), paranoid-check whether we own the cpu.  For each "thread"
- * of a cpu, if it is offline and has the same hw index as before,
- * grab that in preference.
+/*
+ * Update cpu_present_map and paca(s) for a new cpu node.  The wrinkle
+ * here is that a cpu device node may represent up to two logical cpus
+ * in the SMT case.  We must honor the assumption in other code that
+ * the logical ids for sibling SMT threads x and y are adjacent, such
+ * that x^1 == y and y^1 == x.
  */
-static unsigned int find_physical_cpu_to_start(unsigned int old_hwindex)
+static int pSeries_add_processor(struct device_node *np)
 {
-	struct device_node *np = NULL;
-	unsigned int best = -1U;
+	unsigned int cpu;
+	cpumask_t candidate_map, tmp = CPU_MASK_NONE;
+	int err = -ENOSPC, len, nthreads, i;
+	u32 *intserv;
 
-	while ((np = of_find_node_by_type(np, "cpu"))) {
-		int nr_threads, len;
-		u32 *index = (u32 *)get_property(np, "ibm,my-drc-index", NULL);
-		u32 *tid = (u32 *)
-			get_property(np, "ibm,ppc-interrupt-server#s", &len);
+	intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return 0;
 
-		if (!tid)
-			tid = (u32 *)get_property(np, "reg", &len);
+	nthreads = len / sizeof(u32);
+	for (i = 0; i < nthreads; i++)
+		cpu_set(i, tmp);
+
+	lock_cpu_hotplug();
+
+	BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
+
+	/* Get a bitmap of unoccupied slots. */
+	cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
+	if (cpus_empty(candidate_map)) {
+		/* If we get here, it most likely means that NR_CPUS is
+		 * less than the partition's max processors setting.
+		 */
+		printk(KERN_ERR "Cannot add cpu %s; this system configuration"
+		       " supports %d logical cpus.\n", np->full_name,
+		       cpus_weight(cpu_possible_map));
+		goto out_unlock;
+	}
 
-		if (!tid)
-			continue;
+	while (!cpus_empty(tmp))
+		if (cpus_subset(tmp, candidate_map))
+			/* Found a range where we can insert the new cpu(s) */
+			break;
+		else
+			cpus_shift_left(tmp, tmp, nthreads);
 
-		/* If there is a drc-index, make sure that we own
-		 * the cpu.
-		 */
-		if (index) {
-			int state;
-			int rc = rtas_get_sensor(9003, *index, &state);
-			if (rc != 0 || state != 1)
+	if (cpus_empty(tmp)) {
+		printk(KERN_ERR "Unable to find space in cpu_present_map for"
+		       " processor %s with %d thread(s)\n", np->name,
+		       nthreads);
+		goto out_unlock;
+	}
+
+	for_each_cpu_mask(cpu, tmp) {
+		BUG_ON(cpu_isset(cpu, cpu_present_map));
+		cpu_set(cpu, cpu_present_map);
+		set_hard_smp_processor_id(cpu, *intserv++);
+	}
+	err = 0;
+out_unlock:
+	unlock_cpu_hotplug();
+	return err;
+}
+
+/*
+ * Update the present map for a cpu node which is going away, and set
+ * the hard id in the paca(s) to -1 to be consistent with boot time
+ * convention for non-present cpus.
+ */
+static void pSeries_remove_processor(struct device_node *np)
+{
+	unsigned int cpu;
+	int len, nthreads, i;
+	u32 *intserv;
+
+	intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return;
+
+	nthreads = len / sizeof(u32);
+
+	lock_cpu_hotplug();
+	for (i = 0; i < nthreads; i++) {
+		for_each_present_cpu(cpu) {
+			if (get_hard_smp_processor_id(cpu) != intserv[i])
 				continue;
+			BUG_ON(cpu_online(cpu));
+			cpu_clear(cpu, cpu_present_map);
+			set_hard_smp_processor_id(cpu, -1);
+			break;
 		}
+		if (cpu == NR_CPUS)
+			printk(KERN_WARNING "Could not find cpu to remove "
+			       "with physical id 0x%x\n", intserv[i]);
+	}
+	unlock_cpu_hotplug();
+}
 
-		nr_threads = len / sizeof(u32);
+static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+	int err = NOTIFY_OK;
 
-		while (nr_threads--) {
-			if (0 == query_cpu_stopped(tid[nr_threads])) {
-				best = tid[nr_threads];
-				if (best == old_hwindex)
-					goto out;
-			}
-		}
+	switch (action) {
+	case PSERIES_RECONFIG_ADD:
+		if (pSeries_add_processor(node))
+			err = NOTIFY_BAD;
+		break;
+	case PSERIES_RECONFIG_REMOVE:
+		pSeries_remove_processor(node);
+		break;
+	default:
+		err = NOTIFY_DONE;
+		break;
 	}
-out:
-	of_node_put(np);
-	return best;
+	return err;
 }
 
+static struct notifier_block pSeries_smp_nb = {
+	.notifier_call = pSeries_smp_notifier,
+};
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /**
  * smp_startup_cpu() - start the given cpu
  *
- * At boot time, there is nothing to do.  At run-time, call RTAS with
- * the appropriate start location, if the cpu is in the RTAS stopped
- * state.
+ * At boot time, there is nothing to do for primary threads which were
+ * started from Open Firmware.  For anything else, call RTAS with the
+ * appropriate start location.
  *
  * Returns:
  *	0	- failure
@@ -188,23 +268,15 @@ static inline int __devinit smp_startup_
 					       pSeries_secondary_smp_init));
 	unsigned int pcpu;
 
-	/* At boot time the cpus are already spinning in hold
-	 * loops, so nothing to do. */
- 	if (system_state < SYSTEM_RUNNING)
+	if (cpu_isset(lcpu, of_spin_map))
+		/* Already started by OF and sitting in spin loop */
 		return 1;
 
-	pcpu = find_physical_cpu_to_start(get_hard_smp_processor_id(lcpu));
-	if (pcpu == -1U) {
-		printk(KERN_INFO "No more cpus available, failing\n");
-		return 0;
-	}
+	pcpu = get_hard_smp_processor_id(lcpu);
 
 	/* Fixup atomic count: it exited inside IRQ handler. */
 	paca[lcpu].__current->thread_info->preempt_count	= 0;
 
-	/* At boot this is done in prom.c. */
-	paca[lcpu].hw_cpu_id = pcpu;
-
 	status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL,
 			   pcpu, start_here, lcpu);
 	if (status != 0) {
@@ -213,12 +285,6 @@ static inline int __devinit smp_startup_
 	}
 	return 1;
 }
-#else /* ... CONFIG_HOTPLUG_CPU */
-static inline int __devinit smp_startup_cpu(unsigned int lcpu)
-{
-	return 1;
-}
-#endif /* CONFIG_HOTPLUG_CPU */
 
 static inline void smp_xics_do_message(int cpu, int msg)
 {
@@ -258,13 +324,8 @@ static void __devinit smp_xics_setup_cpu
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
 		vpa_init(cpu);
 
-	/*
-	 * Put the calling processor into the GIQ.  This is really only
-	 * necessary from a secondary thread as the OF start-cpu interface
-	 * performs this function for us on primary threads.
-	 */
-	rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
-		(1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
+	cpu_clear(cpu, of_spin_map);
+
 }
 
 static DEFINE_SPINLOCK(timebase_lock);
@@ -307,6 +368,20 @@ static void __devinit smp_pSeries_kick_c
 	paca[nr].cpu_start = 1;
 }
 
+static int smp_pSeries_cpu_bootable(unsigned int nr)
+{
+	/* Special case - we inhibit secondary thread startup
+	 * during boot if the user requests it.  Odd-numbered
+	 * cpus are assumed to be secondary threads.
+	 */
+	if (system_state < SYSTEM_RUNNING &&
+	    cur_cpu_spec->cpu_features & CPU_FTR_SMT &&
+	    !smt_enabled_at_boot && nr % 2 != 0)
+		return 0;
+
+	return 1;
+}
+
 static struct smp_ops_t pSeries_mpic_smp_ops = {
 	.message_pass	= smp_mpic_message_pass,
 	.probe		= smp_mpic_probe,
@@ -319,12 +394,13 @@ static struct smp_ops_t pSeries_xics_smp
 	.probe		= smp_xics_probe,
 	.kick_cpu	= smp_pSeries_kick_cpu,
 	.setup_cpu	= smp_xics_setup_cpu,
+	.cpu_bootable	= smp_pSeries_cpu_bootable,
 };
 
 /* This is called very early */
 void __init smp_init_pSeries(void)
 {
-	int ret, i;
+	int i;
 
 	DBG(" -> smp_init_pSeries()\n");
 
@@ -336,22 +412,26 @@ void __init smp_init_pSeries(void)
 #ifdef CONFIG_HOTPLUG_CPU
 	smp_ops->cpu_disable = pSeries_cpu_disable;
 	smp_ops->cpu_die = pSeries_cpu_die;
+
+	/* Processors can be added/removed only on LPAR */
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR)
+		pSeries_reconfig_notifier_register(&pSeries_smp_nb);
 #endif
 
-	/* Start secondary threads on SMT systems; primary threads
-	 * are already in the running state.
-	 */
-	for_each_present_cpu(i) {
-		if (query_cpu_stopped(get_hard_smp_processor_id(i)) == 0) {
-			printk("%16.16x : starting thread\n", i);
-			DBG("%16.16x : starting thread\n", i);
-			rtas_call(rtas_token("start-cpu"), 3, 1, &ret,
-				  get_hard_smp_processor_id(i),
-				  __pa((u32)*((unsigned long *)
-					      pSeries_secondary_smp_init)),
-				  i);
+	/* Mark threads which are still spinning in hold loops. */
+	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+		for_each_present_cpu(i) {
+			if (i % 2 == 0)
+				/*
+				 * Even-numbered logical cpus correspond to
+				 * primary threads.
+				 */
+				cpu_set(i, of_spin_map);
 		}
-	}
+	else
+		of_spin_map = cpu_present_map;
+
+	cpu_clear(boot_cpuid, of_spin_map);
 
 	/* Non-lpar has additional take/give timebase */
 	if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -20,9 +20,14 @@
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/paca.h>
 
-struct systemcfg *systemcfg;
+static union {
+	struct systemcfg	data;
+	u8			page[PAGE_SIZE];
+} systemcfg_store __page_aligned;
+struct systemcfg *systemcfg = &systemcfg_store.data;
 EXPORT_SYMBOL(systemcfg);
 
+
 /* This symbol is provided by the linker - let it fill in the paca
  * field correctly */
 extern unsigned long __toc_start;
@@ -216,3 +221,4 @@ struct paca_struct paca[] = {
 #endif
 #endif
 };
+EXPORT_SYMBOL(paca);
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -63,13 +63,15 @@ unsigned int pcibios_assign_all_busses(v
  * page is mapped and isa_io_limit prevents access to it.
  */
 unsigned long isa_io_base;	/* NULL if no ISA bus */
+EXPORT_SYMBOL(isa_io_base);
 unsigned long pci_io_base;
+EXPORT_SYMBOL(pci_io_base);
 
 void iSeries_pcibios_init(void);
 
 LIST_HEAD(hose_list);
 
-struct pci_dma_ops pci_dma_ops;
+struct dma_mapping_ops pci_dma_ops;
 EXPORT_SYMBOL(pci_dma_ops);
 
 int global_phb_number;		/* Global phb counter */
@@ -208,6 +210,11 @@ static int __init pcibios_init(void)
 	struct pci_controller *hose, *tmp;
 	struct pci_bus *bus;
 
+	/* For now, override phys_mem_access_prot. If we need it,
+	 * later, we may move that initialization to each ppc_md
+	 */
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 #ifdef CONFIG_PPC_ISERIES
 	iSeries_pcibios_init(); 
 #endif
@@ -300,19 +307,15 @@ int pci_domain_nr(struct pci_bus *bus)
 
 EXPORT_SYMBOL(pci_domain_nr);
 
-/* Set the name of the bus as it appears in /proc/bus/pci */
-int pci_name_bus(char *name, struct pci_bus *bus)
+/* Decide whether to display the domain number in /proc */
+int pci_proc_domain(struct pci_bus *bus)
 {
-#ifndef CONFIG_PPC_ISERIES
+#ifdef CONFIG_PPC_ISERIES
+	return 0;
+#else
 	struct pci_controller *hose = pci_bus_to_host(bus);
-
-	if (hose->buid)
-		sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
-	else
+	return hose->buid;
 #endif
-		sprintf(name, "%02x", bus->number);
-
-	return 0;
 }
 
 /*
@@ -332,25 +335,24 @@ int pci_name_bus(char *name, struct pci_
  *
  * Returns negative error code on failure, zero on success.
  */
-static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev,
-					     struct vm_area_struct *vma,
-					     enum pci_mmap_state mmap_state)
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+					       unsigned long *offset,
+					       enum pci_mmap_state mmap_state)
 {
 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long io_offset = 0;
 	int i, res_bit;
 
 	if (hose == 0)
-		return -EINVAL;		/* should never happen */
+		return NULL;		/* should never happen */
 
 	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
-		offset += hose->pci_mem_offset;
+		*offset += hose->pci_mem_offset;
 		res_bit = IORESOURCE_MEM;
 	} else {
 		io_offset = (unsigned long)hose->io_base_virt;
-		offset += io_offset;
+		*offset += io_offset;
 		res_bit = IORESOURCE_IO;
 	}
 
@@ -371,50 +373,106 @@ static __inline__ int __pci_mmap_make_of
 			continue;
 
 		/* In the range of this resource? */
-		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+		if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
 			continue;
 
 		/* found it! construct the final physical address */
 		if (mmap_state == pci_mmap_io)
-			offset += hose->io_base_phys - io_offset;
-
-		vma->vm_pgoff = offset >> PAGE_SHIFT;
-		return 0;
+			*offset += hose->io_base_phys - io_offset;
+		return rp;
 	}
 
-	return -EINVAL;
-}
-
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void __pci_mmap_set_flags(struct pci_dev *dev,
-					    struct vm_area_struct *vma,
-					    enum pci_mmap_state mmap_state)
-{
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	return NULL;
 }
 
 /*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
  */
-static __inline__ void __pci_mmap_set_pgprot(struct pci_dev *dev,
-					     struct vm_area_struct *vma,
-					     enum pci_mmap_state mmap_state,
-					     int write_combine)
-{
-	long prot = pgprot_val(vma->vm_page_prot);
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+				      pgprot_t protection,
+				      enum pci_mmap_state mmap_state,
+				      int write_combine)
+{
+	unsigned long prot = pgprot_val(protection);
+
+	/* Write combine is always 0 on non-memory space mappings. On
+	 * memory space, if the user didn't pass 1, we check for a
+	 * "prefetchable" resource. This is a bit hackish, but we use
+	 * this to workaround the inability of /sysfs to provide a write
+	 * combine bit
+	 */
+	if (mmap_state != pci_mmap_mem)
+		write_combine = 0;
+	else if (write_combine == 0) {
+		if (rp->flags & IORESOURCE_PREFETCH)
+			write_combine = 1;
+	}
 
 	/* XXX would be nice to have a way to ask for write-through */
 	prot |= _PAGE_NO_CACHE;
-	if (!write_combine)
+	if (write_combine)
+		prot &= ~_PAGE_GUARDED;
+	else
 		prot |= _PAGE_GUARDED;
-	vma->vm_page_prot = __pgprot(prot);
+
+	printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+	       prot);
+
+	return __pgprot(prot);
 }
 
 /*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+				  unsigned long offset,
+				  unsigned long size,
+				  pgprot_t protection)
+{
+	struct pci_dev *pdev = NULL;
+	struct resource *found = NULL;
+	unsigned long prot = pgprot_val(protection);
+	int i;
+
+	if (page_is_ram(offset >> PAGE_SHIFT))
+		return __pgprot(prot);
+
+	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+	for_each_pci_dev(pdev) {
+		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+			struct resource *rp = &pdev->resource[i];
+			int flags = rp->flags;
+
+			/* Active and same type? */
+			if ((flags & IORESOURCE_MEM) == 0)
+				continue;
+			/* In the range of this resource? */
+			if (offset < (rp->start & PAGE_MASK) ||
+			    offset > rp->end)
+				continue;
+			found = rp;
+			break;
+		}
+		if (found)
+			break;
+	}
+	if (found) {
+		if (found->flags & IORESOURCE_PREFETCH)
+			prot &= ~_PAGE_GUARDED;
+		pci_dev_put(pdev);
+	}
+
+	DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+	return __pgprot(prot);
+}
+
+
+/*
  * Perform the actual remap of the pages for a PCI device mapping, as
  * appropriate for this architecture.  The region in the process to map
  * is described by vm_start and vm_end members of VMA, the base physical
@@ -428,14 +486,19 @@ int pci_mmap_page_range(struct pci_dev *
 			enum pci_mmap_state mmap_state,
 			int write_combine)
 {
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct resource *rp;
 	int ret;
 
-	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
-	if (ret < 0)
-		return ret;
+	rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+	if (rp == NULL)
+		return -EINVAL;
 
-	__pci_mmap_set_flags(dev, vma, mmap_state);
-	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+						  vma->vm_page_prot,
+						  mmap_state, write_combine);
 
 	ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
@@ -484,8 +547,9 @@ static void __devinit pci_process_ISA_OF
 	if (range == NULL || (rlen < sizeof(struct isa_range))) {
 		printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
 		       "mapping 64k\n");
-		__ioremap_explicit(phb_io_base_phys, (unsigned long)phb_io_base_virt, 
-				   0x10000, _PAGE_NO_CACHE);
+		__ioremap_explicit(phb_io_base_phys,
+				   (unsigned long)phb_io_base_virt,
+				   0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED);
 		return;	
 	}
 	
@@ -513,7 +577,7 @@ static void __devinit pci_process_ISA_OF
 
 		__ioremap_explicit(phb_io_base_phys, 
 				   (unsigned long) phb_io_base_virt, 
-				   size, _PAGE_NO_CACHE);
+				   size, _PAGE_NO_CACHE | _PAGE_GUARDED);
 	}
 }
 
@@ -621,18 +685,22 @@ void __init pci_setup_phb_io(struct pci_
 	res->end += io_virt_offset;
 }
 
-void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose)
+void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose,
+					int primary)
 {
 	unsigned long size = hose->pci_io_size;
 	unsigned long io_virt_offset;
 	struct resource *res;
 
 	hose->io_base_virt = __ioremap(hose->io_base_phys, size,
-					_PAGE_NO_CACHE);
+					_PAGE_NO_CACHE | _PAGE_GUARDED);
 	DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
 		hose->global_number, hose->io_base_phys,
 		(unsigned long) hose->io_base_virt);
 
+	if (primary)
+		pci_io_base = (unsigned long)hose->io_base_virt;
+
 	io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
 	res = &hose->io_resource;
 	res->start += io_virt_offset;
@@ -713,7 +781,8 @@ int remap_bus_range(struct pci_bus *bus)
 	if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
 		return 1;
 	printk("mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
-	if (__ioremap_explicit(start_phys, start_virt, size, _PAGE_NO_CACHE))
+	if (__ioremap_explicit(start_phys, start_virt, size,
+			       _PAGE_NO_CACHE | _PAGE_GUARDED))
 		return 1;
 
 	return 0;
diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h
--- a/arch/ppc64/kernel/pci.h
+++ b/arch/ppc64/kernel/pci.h
@@ -16,8 +16,7 @@ extern unsigned long isa_io_base;
 
 extern void pci_setup_pci_controller(struct pci_controller *hose);
 extern void pci_setup_phb_io(struct pci_controller *hose, int primary);
-
-extern void pci_setup_phb_io_dynamic(struct pci_controller *hose);
+extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary);
 
 
 extern struct list_head hose_list;
diff --git a/arch/ppc64/kernel/pci_direct_iommu.c b/arch/ppc64/kernel/pci_direct_iommu.c
--- a/arch/ppc64/kernel/pci_direct_iommu.c
+++ b/arch/ppc64/kernel/pci_direct_iommu.c
@@ -30,12 +30,12 @@
 
 #include "pci.h"
 
-static void *pci_direct_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				   dma_addr_t *dma_handle)
+static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size,
+				   dma_addr_t *dma_handle, unsigned int __nocast flag)
 {
 	void *ret;
 
-	ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+	ret = (void *)__get_free_pages(flag, get_order(size));
 	if (ret != NULL) {
 		memset(ret, 0, size);
 		*dma_handle = virt_to_abs(ret);
@@ -43,24 +43,24 @@ static void *pci_direct_alloc_consistent
 	return ret;
 }
 
-static void pci_direct_free_consistent(struct pci_dev *hwdev, size_t size,
+static void pci_direct_free_coherent(struct device *hwdev, size_t size,
 				 void *vaddr, dma_addr_t dma_handle)
 {
 	free_pages((unsigned long)vaddr, get_order(size));
 }
 
-static dma_addr_t pci_direct_map_single(struct pci_dev *hwdev, void *ptr,
+static dma_addr_t pci_direct_map_single(struct device *hwdev, void *ptr,
 		size_t size, enum dma_data_direction direction)
 {
 	return virt_to_abs(ptr);
 }
 
-static void pci_direct_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+static void pci_direct_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
 		size_t size, enum dma_data_direction direction)
 {
 }
 
-static int pci_direct_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static int pci_direct_map_sg(struct device *hwdev, struct scatterlist *sg,
 		int nents, enum dma_data_direction direction)
 {
 	int i;
@@ -73,17 +73,23 @@ static int pci_direct_map_sg(struct pci_
 	return nents;
 }
 
-static void pci_direct_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static void pci_direct_unmap_sg(struct device *hwdev, struct scatterlist *sg,
 		int nents, enum dma_data_direction direction)
 {
 }
 
+static int pci_direct_dma_supported(struct device *dev, u64 mask)
+{
+	return mask < 0x100000000ull;
+}
+
 void __init pci_direct_iommu_init(void)
 {
-	pci_dma_ops.pci_alloc_consistent = pci_direct_alloc_consistent;
-	pci_dma_ops.pci_free_consistent = pci_direct_free_consistent;
-	pci_dma_ops.pci_map_single = pci_direct_map_single;
-	pci_dma_ops.pci_unmap_single = pci_direct_unmap_single;
-	pci_dma_ops.pci_map_sg = pci_direct_map_sg;
-	pci_dma_ops.pci_unmap_sg = pci_direct_unmap_sg;
+	pci_dma_ops.alloc_coherent = pci_direct_alloc_coherent;
+	pci_dma_ops.free_coherent = pci_direct_free_coherent;
+	pci_dma_ops.map_single = pci_direct_map_single;
+	pci_dma_ops.unmap_single = pci_direct_unmap_single;
+	pci_dma_ops.map_sg = pci_direct_map_sg;
+	pci_dma_ops.unmap_sg = pci_direct_unmap_sg;
+	pci_dma_ops.dma_supported = pci_direct_dma_supported;
 }
diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
--- a/arch/ppc64/kernel/pci_dn.c
+++ b/arch/ppc64/kernel/pci_dn.c
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#include <asm/pSeries_reconfig.h>
 
 #include "pci.h"
 
@@ -37,6 +38,7 @@
 static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
 {
 	struct pci_controller *phb = data;
+	int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
 	u32 *regs;
 
 	dn->phb = phb;
@@ -46,6 +48,8 @@ static void * __devinit update_dn_pci_in
 		dn->busno = (regs[0] >> 16) & 0xff;
 		dn->devfn = (regs[0] >> 8) & 0xff;
 	}
+
+	dn->pci_ext_config_space = (type && *type == 1);
 	return NULL;
 }
 
@@ -158,6 +162,25 @@ struct device_node *fetch_dev_dn(struct 
 }
 EXPORT_SYMBOL(fetch_dev_dn);
 
+static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+	struct device_node *np = node;
+	int err = NOTIFY_OK;
+
+	switch (action) {
+	case PSERIES_RECONFIG_ADD:
+		update_dn_pci_info(np, np->parent->phb);
+		break;
+	default:
+		err = NOTIFY_DONE;
+		break;
+	}
+	return err;
+}
+
+static struct notifier_block pci_dn_reconfig_nb = {
+	.notifier_call = pci_dn_reconfig_notifier,
+};
 
 /*
  * Actually initialize the phbs.
@@ -170,4 +193,6 @@ void __init pci_devs_phb_init(void)
 	/* This must be done first so the device nodes have valid pci info! */
 	list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
 		pci_devs_phb_init_dynamic(phb);
+
+	pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
 }
diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c
--- a/arch/ppc64/kernel/pci_iommu.c
+++ b/arch/ppc64/kernel/pci_iommu.c
@@ -50,19 +50,23 @@
  */
 #define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
 
-static inline struct iommu_table *devnode_table(struct pci_dev *dev)
+static inline struct iommu_table *devnode_table(struct device *dev)
 {
-	if (!dev)
-		dev = ppc64_isabridge_dev;
-	if (!dev)
-		return NULL;
+	struct pci_dev *pdev;
+
+	if (!dev) {
+		pdev = ppc64_isabridge_dev;
+		if (!pdev)
+			return NULL;
+	} else
+		pdev = to_pci_dev(dev);
 
 #ifdef CONFIG_PPC_ISERIES
-	return ISERIES_DEVNODE(dev)->iommu_table;
+	return ISERIES_DEVNODE(pdev)->iommu_table;
 #endif /* CONFIG_PPC_ISERIES */
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
-	return PCI_GET_DN(dev)->iommu_table;
+	return PCI_GET_DN(pdev)->iommu_table;
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 }
 
@@ -71,16 +75,17 @@ static inline struct iommu_table *devnod
  * Returns the virtual address of the buffer and sets dma_handle
  * to the dma address (mapping) of the first page.
  */
-static void *pci_iommu_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t *dma_handle)
+static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size,
+			   dma_addr_t *dma_handle, unsigned int __nocast flag)
 {
-	return iommu_alloc_consistent(devnode_table(hwdev), size, dma_handle);
+	return iommu_alloc_coherent(devnode_table(hwdev), size, dma_handle,
+			flag);
 }
 
-static void pci_iommu_free_consistent(struct pci_dev *hwdev, size_t size,
+static void pci_iommu_free_coherent(struct device *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
-	iommu_free_consistent(devnode_table(hwdev), size, vaddr, dma_handle);
+	iommu_free_coherent(devnode_table(hwdev), size, vaddr, dma_handle);
 }
 
 /* Creates TCEs for a user provided buffer.  The user buffer must be 
@@ -89,46 +94,46 @@ static void pci_iommu_free_consistent(st
  * need not be page aligned, the dma_addr_t returned will point to the same
  * byte within the page as vaddr.
  */
-static dma_addr_t pci_iommu_map_single(struct pci_dev *hwdev, void *vaddr,
+static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr,
 		size_t size, enum dma_data_direction direction)
 {
 	return iommu_map_single(devnode_table(hwdev), vaddr, size, direction);
 }
 
 
-static void pci_iommu_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
+static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle,
 		size_t size, enum dma_data_direction direction)
 {
 	iommu_unmap_single(devnode_table(hwdev), dma_handle, size, direction);
 }
 
 
-static int pci_iommu_map_sg(struct pci_dev *pdev, struct scatterlist *sglist,
+static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist,
 		int nelems, enum dma_data_direction direction)
 {
-	return iommu_map_sg(&pdev->dev, devnode_table(pdev), sglist,
+	return iommu_map_sg(pdev, devnode_table(pdev), sglist,
 			nelems, direction);
 }
 
-static void pci_iommu_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist,
+static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist,
 		int nelems, enum dma_data_direction direction)
 {
 	iommu_unmap_sg(devnode_table(pdev), sglist, nelems, direction);
 }
 
 /* We support DMA to/from any memory page via the iommu */
-static int pci_iommu_dma_supported(struct pci_dev *pdev, u64 mask)
+static int pci_iommu_dma_supported(struct device *dev, u64 mask)
 {
 	return 1;
 }
 
 void pci_iommu_init(void)
 {
-	pci_dma_ops.pci_alloc_consistent = pci_iommu_alloc_consistent;
-	pci_dma_ops.pci_free_consistent = pci_iommu_free_consistent;
-	pci_dma_ops.pci_map_single = pci_iommu_map_single;
-	pci_dma_ops.pci_unmap_single = pci_iommu_unmap_single;
-	pci_dma_ops.pci_map_sg = pci_iommu_map_sg;
-	pci_dma_ops.pci_unmap_sg = pci_iommu_unmap_sg;
-	pci_dma_ops.pci_dma_supported = pci_iommu_dma_supported;
+	pci_dma_ops.alloc_coherent = pci_iommu_alloc_coherent;
+	pci_dma_ops.free_coherent = pci_iommu_free_coherent;
+	pci_dma_ops.map_single = pci_iommu_map_single;
+	pci_dma_ops.unmap_single = pci_iommu_unmap_single;
+	pci_dma_ops.map_sg = pci_iommu_map_sg;
+	pci_dma_ops.unmap_sg = pci_iommu_unmap_sg;
+	pci_dma_ops.dma_supported = pci_iommu_dma_supported;
 }
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c
--- a/arch/ppc64/kernel/pmac_feature.c
+++ b/arch/ppc64/kernel/pmac_feature.c
@@ -64,8 +64,7 @@ static DEFINE_SPINLOCK(feature_lock  __p
  */
 struct macio_chip macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
 
-struct macio_chip* __pmac
-macio_find(struct device_node* child, int type)
+struct macio_chip* __pmac macio_find(struct device_node* child, int type)
 {
 	while(child) {
 		int	i;
@@ -78,6 +77,7 @@ macio_find(struct device_node* child, in
 	}
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(macio_find);
 
 static const char* macio_names[] __pmacdata =
 {
@@ -220,6 +220,60 @@ static long __pmac g5_mpic_enable(struct
 	return 0;
 }
 
+static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+	struct device_node *phy;
+	int need_reset;
+
+	/*
+	 * We must not reset the combo PHYs, only the BCM5221 found in
+	 * the iMac G5.
+	 */
+	phy = of_get_next_child(node, NULL);
+	if (!phy)
+		return -ENODEV;
+	need_reset = device_is_compatible(phy, "B5221");
+	of_node_put(phy);
+	if (!need_reset)
+		return 0;
+
+	/* PHY reset is GPIO 29, not in device-tree unfortunately */
+	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
+		   KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+	/* Thankfully, this is now always called at a time when we can
+	 * schedule by sungem.
+	 */
+	msleep(10);
+	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
+
+	return 0;
+}
+
+static long __pmac g5_i2s_enable(struct device_node *node, long param, long value)
+{
+	/* Very crude implementation for now */
+	struct macio_chip* macio = &macio_chips[0];
+	unsigned long flags;
+
+	if (value == 0)
+		return 0; /* don't disable yet */
+
+	LOCK(flags);
+	MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
+		  KL3_I2S0_CLK18_ENABLE);
+	udelay(10);
+	MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
+		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
+	udelay(10);
+	MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
+	UNLOCK(flags);
+	udelay(10);
+
+	return 0;
+}
+
+
 #ifdef CONFIG_SMP
 static long __pmac g5_reset_cpu(struct device_node* node, long param, long value)
 {
@@ -306,6 +360,8 @@ static struct feature_table_entry g5_fea
 	{ PMAC_FTR_ENABLE_MPIC,		g5_mpic_enable },
 	{ PMAC_FTR_READ_GPIO,		g5_read_gpio },
 	{ PMAC_FTR_WRITE_GPIO,		g5_write_gpio },
+	{ PMAC_FTR_GMAC_PHY_RESET,	g5_eth_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	g5_i2s_enable },
 #ifdef CONFIG_SMP
 	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },
 #endif /* CONFIG_SMP */
@@ -321,8 +377,16 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_POWERMAC_G5,		g5_features,
 		0,
 	},
+	{	"PowerMac8,1",			"iMac G5",
+		PMAC_TYPE_IMAC_G5,		g5_features,
+		0,
+	},
+	{	"PowerMac9,1",			"PowerMac G5",
+		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
+		0,
+	},
 	{       "RackMac3,1",                   "XServe G5",
-		PMAC_TYPE_POWERMAC_G5,          g5_features,
+		PMAC_TYPE_XSERVE_G5,		g5_features,
 		0,
 	},
 };
@@ -635,3 +699,67 @@ void __init pmac_check_ht_link(void)
 	dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
 #endif
 }
+
+/*
+ * Early video resume hook
+ */
+
+static void (*pmac_early_vresume_proc)(void *data) __pmacdata;
+static void *pmac_early_vresume_data __pmacdata;
+
+void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
+{
+	if (_machine != _MACH_Pmac)
+		return;
+	preempt_disable();
+	pmac_early_vresume_proc = proc;
+	pmac_early_vresume_data = data;
+	preempt_enable();
+}
+EXPORT_SYMBOL(pmac_set_early_video_resume);
+
+
+/*
+ * AGP related suspend/resume code
+ */
+
+static struct pci_dev *pmac_agp_bridge __pmacdata;
+static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata;
+static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata;
+
+void __pmac pmac_register_agp_pm(struct pci_dev *bridge,
+				 int (*suspend)(struct pci_dev *bridge),
+				 int (*resume)(struct pci_dev *bridge))
+{
+	if (suspend || resume) {
+		pmac_agp_bridge = bridge;
+		pmac_agp_suspend = suspend;
+		pmac_agp_resume = resume;
+		return;
+	}
+	if (bridge != pmac_agp_bridge)
+		return;
+	pmac_agp_suspend = pmac_agp_resume = NULL;
+	return;
+}
+EXPORT_SYMBOL(pmac_register_agp_pm);
+
+void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev)
+{
+	if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
+		return;
+	if (pmac_agp_bridge->bus != dev->bus)
+		return;
+	pmac_agp_suspend(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_suspend_agp_for_card);
+
+void __pmac pmac_resume_agp_for_card(struct pci_dev *dev)
+{
+	if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
+		return;
+	if (pmac_agp_bridge->bus != dev->bus)
+		return;
+	pmac_agp_resume(pmac_agp_bridge);
+}
+EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c
--- a/arch/ppc64/kernel/pmac_pci.c
+++ b/arch/ppc64/kernel/pmac_pci.c
@@ -656,13 +656,32 @@ static int __init add_bridge(struct devi
 	return 0;
 }
 
+/*
+ * We use our own read_irq_line here because PCI_INTERRUPT_PIN is
+ * crap on some of Apple ASICs. We unconditionally use the Open Firmware
+ * interrupt number as this is always right.
+ */
+static int pmac_pci_read_irq_line(struct pci_dev *pci_dev)
+{
+	struct device_node *node;
+
+	node = pci_device_to_OF_node(pci_dev);
+	if (node == NULL)
+		return -1;
+	if (node->n_intrs == 0)
+		return -1;
+	pci_dev->irq = node->intrs[0].line;
+	pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq);
+
+	return 0;
+}
 
 void __init pmac_pcibios_fixup(void)
 {
 	struct pci_dev *dev = NULL;
 
 	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
+		pmac_pci_read_irq_line(dev);
 }
 
 static void __init pmac_fixup_phb_resources(void)
@@ -771,3 +790,4 @@ static void fixup_k2_sata(struct pci_dev
 	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
+
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -70,6 +70,7 @@
 #include <asm/time.h>
 #include <asm/of_device.h>
 #include <asm/lmb.h>
+#include <asm/smu.h>
 
 #include "pmac.h"
 #include "mpic.h"
@@ -80,13 +81,20 @@
 #define DBG(fmt...)
 #endif
 
-
 static int current_root_goodness = -1;
 #define DEFAULT_ROOT_DEVICE Root_SDA1	/* sda1 - slightly silly choice */
 
 extern  int powersave_nap;
 int sccdbg;
 
+sys_ctrler_t sys_ctrler;
+EXPORT_SYMBOL(sys_ctrler);
+
+#ifdef CONFIG_PMAC_SMU
+unsigned long smu_cmdbuf_abs;
+EXPORT_SYMBOL(smu_cmdbuf_abs);
+#endif
+
 extern void udbg_init_scc(struct device_node *np);
 
 void __pmac pmac_show_cpuinfo(struct seq_file *m)
@@ -155,8 +163,14 @@ void __init pmac_setup_arch(void)
 	/* We can NAP */
 	powersave_nap = 1;
 
-	/* Initialize the PMU */
+#ifdef CONFIG_ADB_PMU
+	/* Initialize the PMU if any */
 	find_via_pmu();
+#endif
+#ifdef CONFIG_PMAC_SMU
+	/* Initialize the SMU if any */
+	smu_init();
+#endif
 
 	/* Init NVRAM access */
 	pmac_nvram_init();
@@ -216,12 +230,39 @@ void __pmac note_bootable_part(dev_t dev
 
 void __pmac pmac_restart(char *cmd)
 {
-	pmu_restart();
+	switch(sys_ctrler) {
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		pmu_restart();
+		break;
+#endif
+
+#ifdef CONFIG_PMAC_SMU
+	case SYS_CTRLER_SMU:
+		smu_restart();
+		break;
+#endif
+	default:
+		;
+	}
 }
 
 void __pmac pmac_power_off(void)
 {
-	pmu_shutdown();
+	switch(sys_ctrler) {
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		pmu_shutdown();
+		break;
+#endif
+#ifdef CONFIG_PMAC_SMU
+	case SYS_CTRLER_SMU:
+		smu_shutdown();
+		break;
+#endif
+	default:
+		;
+	}
 }
 
 void __pmac pmac_halt(void)
@@ -244,7 +285,6 @@ static void btext_putc(unsigned char c)
 {
 	btext_drawchar(c);
 }
-#endif /* CONFIG_BOOTX_TEXT */
 
 static void __init init_boot_display(void)
 {
@@ -280,6 +320,7 @@ static void __init init_boot_display(voi
 			return;
 	}
 }
+#endif /* CONFIG_BOOTX_TEXT */
 
 /* 
  * Early initialization.
@@ -426,7 +467,6 @@ static int __init pmac_probe(int platfor
 {
 	if (platform != PLATFORM_POWERMAC)
 		return 0;
-
 	/*
 	 * On U3, the DART (iommu) must be allocated now since it
 	 * has an impact on htab_initialize (due to the large page it
@@ -435,10 +475,22 @@ static int __init pmac_probe(int platfor
 	 */
 	alloc_u3_dart_table();
 
+#ifdef CONFIG_PMAC_SMU
+	/*
+	 * SMU based G5s need some memory below 2Gb, at least the current
+	 * driver needs that. We have to allocate it now. We allocate 4k
+	 * (1 small page) for now.
+	 */
+	smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL);
+#endif /* CONFIG_PMAC_SMU */
+
 	return 1;
 }
 
 struct machdep_calls __initdata pmac_md = {
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_die		= generic_mach_cpu_die,
+#endif
 	.probe			= pmac_probe,
 	.setup_arch		= pmac_setup_arch,
 	.init_early		= pmac_init_early,
diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c
--- a/arch/ppc64/kernel/pmac_smp.c
+++ b/arch/ppc64/kernel/pmac_smp.c
@@ -68,6 +68,7 @@ extern struct smp_ops_t *smp_ops;
 
 static void (*pmac_tb_freeze)(int freeze);
 static struct device_node *pmac_tb_clock_chip_host;
+static u8 pmac_tb_pulsar_addr;
 static DEFINE_SPINLOCK(timebase_lock);
 static unsigned long timebase;
 
@@ -106,12 +107,9 @@ static void smp_core99_pulsar_tb_freeze(
 	u8 data;
 	int rc;
 
-	/* Strangely, the device-tree says address is 0xd2, but darwin
-	 * accesses 0xd0 ...
-	 */
 	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
 	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       0xd4 | pmac_low_i2c_read,
+			       pmac_tb_pulsar_addr | pmac_low_i2c_read,
 			       0x2e, &data, 1);
 	if (rc != 0)
 		goto bail;
@@ -120,7 +118,7 @@ static void smp_core99_pulsar_tb_freeze(
 
 	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
 	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       0xd4 | pmac_low_i2c_write,
+			       pmac_tb_pulsar_addr | pmac_low_i2c_write,
 			       0x2e, &data, 1);
  bail:
 	if (rc != 0) {
@@ -185,6 +183,12 @@ static int __init smp_core99_probe(void)
 	if (ncpus <= 1)
 		return 1;
 
+	/* HW sync only on these platforms */
+	if (!machine_is_compatible("PowerMac7,2") &&
+	    !machine_is_compatible("PowerMac7,3") &&
+	    !machine_is_compatible("RackMac3,1"))
+		goto nohwsync;
+
 	/* Look for the clock chip */
 	for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) {
 		struct device_node *p = of_get_parent(cc);
@@ -198,11 +202,18 @@ static int __init smp_core99_probe(void)
 			goto next;
 		switch (*reg) {
 		case 0xd2:
-			pmac_tb_freeze = smp_core99_cypress_tb_freeze;
-			printk(KERN_INFO "Timebase clock is Cypress chip\n");
+			if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
+				pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
+				pmac_tb_pulsar_addr = 0xd2;
+				printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+			} else if (device_is_compatible(cc, "cy28508")) {
+				pmac_tb_freeze = smp_core99_cypress_tb_freeze;
+				printk(KERN_INFO "Timebase clock is Cypress chip\n");
+			}
 			break;
 		case 0xd4:
 			pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
+			pmac_tb_pulsar_addr = 0xd4;
 			printk(KERN_INFO "Timebase clock is Pulsar chip\n");
 			break;
 		}
@@ -210,12 +221,15 @@ static int __init smp_core99_probe(void)
 			pmac_tb_clock_chip_host = p;
 			smp_ops->give_timebase = smp_core99_give_timebase;
 			smp_ops->take_timebase = smp_core99_take_timebase;
+			of_node_put(cc);
+			of_node_put(p);
 			break;
 		}
 	next:
 		of_node_put(p);
 	}
 
+ nohwsync:
 	mpic_request_ipis();
 
 	return ncpus;
@@ -308,4 +322,9 @@ struct smp_ops_t core99_smp_ops __pmacda
 void __init pmac_setup_smp(void)
 {
 	smp_ops = &core99_smp_ops;
+#ifdef CONFIG_HOTPLUG_CPU
+	smp_ops->cpu_enable = generic_cpu_enable;
+	smp_ops->cpu_disable = generic_cpu_disable;
+	smp_ops->cpu_die = generic_cpu_die;
+#endif
 }
diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c
--- a/arch/ppc64/kernel/pmac_time.c
+++ b/arch/ppc64/kernel/pmac_time.c
@@ -6,6 +6,8 @@
  *
  * Paul Mackerras	August 1996.
  * Copyright (C) 1996 Paul Mackerras.
+ * Copyright (C) 2003-2005 Benjamin Herrenschmidt.
+ *
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -28,6 +30,7 @@
 #include <asm/machdep.h>
 #include <asm/time.h>
 #include <asm/nvram.h>
+#include <asm/smu.h>
 
 #undef DEBUG
 
@@ -55,54 +58,86 @@ extern void to_tm(int tim, struct rtc_ti
 
 void __pmac pmac_get_rtc_time(struct rtc_time *tm)
 {
-	struct adb_request req;
-	unsigned int now;
-
-	/* Get the time from the RTC */
-	if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-		return;
-	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];
-	DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET));
-	now -= RTC_OFFSET;
-
-	to_tm(now, tm);
-	tm->tm_year -= 1900;
-	tm->tm_mon -= 1;
+	switch(sys_ctrler) {
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU: {
+		/* TODO: Move that to a function in the PMU driver */
+		struct adb_request req;
+		unsigned int now;
+
+		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+			return;
+		pmu_wait_complete(&req);
+		if (req.reply_len != 4)
+			printk(KERN_ERR "pmac_get_rtc_time: PMU returned a %d"
+			       " bytes reply\n", req.reply_len);
+		now = (req.reply[0] << 24) + (req.reply[1] << 16)
+			+ (req.reply[2] << 8) + req.reply[3];
+		DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET));
+		now -= RTC_OFFSET;
+
+		to_tm(now, tm);
+		tm->tm_year -= 1900;
+		tm->tm_mon -= 1;
 	
-	DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
-	       tm->tm_mday, tm->tm_mon, tm->tm_year,
-	       tm->tm_hour, tm->tm_min, tm->tm_sec);
+		DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
+		    tm->tm_mday, tm->tm_mon, tm->tm_year,
+		    tm->tm_hour, tm->tm_min, tm->tm_sec);
+		break;
+	}
+#endif /* CONFIG_ADB_PMU */
+
+#ifdef CONFIG_PMAC_SMU
+	case SYS_CTRLER_SMU:
+		smu_get_rtc_time(tm);
+		break;
+#endif /* CONFIG_PMAC_SMU */
+	default:
+		;
+	}
 }
 
 int __pmac pmac_set_rtc_time(struct rtc_time *tm)
 {
-	struct adb_request req;
-	unsigned int nowtime;
-
-	DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
-	       tm->tm_mday, tm->tm_mon, tm->tm_year,
-	       tm->tm_hour, tm->tm_min, tm->tm_sec);
-
-	nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-			 tm->tm_hour, tm->tm_min, tm->tm_sec);
-	DBG("-> %u -> %u\n", (int)nowtime, (int)(nowtime + RTC_OFFSET));
-	nowtime += RTC_OFFSET;
-
-	if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-			nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+	switch(sys_ctrler) {
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU: {
+		/* TODO: Move that to a function in the PMU driver */
+		struct adb_request req;
+		unsigned int nowtime;
+
+		DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d,"
+		    " %d:%02d:%02d\n",
+		    tm->tm_mday, tm->tm_mon, tm->tm_year,
+		    tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+		nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1,
+				 tm->tm_mday, tm->tm_hour, tm->tm_min,
+				 tm->tm_sec);
+
+		DBG("-> %u -> %u\n", (int)nowtime,
+		    (int)(nowtime + RTC_OFFSET));
+		nowtime += RTC_OFFSET;
+
+		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+				nowtime >> 24, nowtime >> 16,
+				nowtime >> 8, nowtime) < 0)
+			return -ENXIO;
+		pmu_wait_complete(&req);
+		if (req.reply_len != 0)
+			printk(KERN_ERR "pmac_set_rtc_time: PMU returned a %d"
+			       " bytes reply\n", req.reply_len);
 		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 */
+
+#ifdef CONFIG_PMAC_SMU
+	case SYS_CTRLER_SMU:
+		return smu_set_rtc_time(tm);
+#endif /* CONFIG_PMAC_SMU */
+	default:
+		return -ENODEV;
+	}
 }
 
 void __init pmac_get_boot_time(struct rtc_time *tm)
diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/pmc.c
@@ -0,0 +1,67 @@
+/*
+ *  linux/arch/ppc64/kernel/pmc.c
+ *
+ *  Copyright (C) 2004 David Gibson, 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/errno.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/processor.h>
+#include <asm/pmc.h>
+
+/* Ensure exceptions are disabled */
+static void dummy_perf(struct pt_regs *regs)
+{
+	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
+
+	mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO);
+	mtspr(SPRN_MMCR0, mmcr0);
+}
+
+static spinlock_t pmc_owner_lock = SPIN_LOCK_UNLOCKED;
+static void *pmc_owner_caller; /* mostly for debugging */
+perf_irq_t perf_irq = dummy_perf;
+
+int reserve_pmc_hardware(perf_irq_t new_perf_irq)
+{
+	int err = 0;
+
+	spin_lock(&pmc_owner_lock);
+
+	if (pmc_owner_caller) {
+		printk(KERN_WARNING "reserve_pmc_hardware: "
+		       "PMC hardware busy (reserved by caller %p)\n",
+		       pmc_owner_caller);
+		err = -EBUSY;
+		goto out;
+	}
+
+	pmc_owner_caller = __builtin_return_address(0);
+	perf_irq = new_perf_irq ? : dummy_perf;
+
+ out:
+	spin_unlock(&pmc_owner_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(reserve_pmc_hardware);
+
+void release_pmc_hardware(void)
+{
+	spin_lock(&pmc_owner_lock);
+
+	WARN_ON(! pmc_owner_caller);
+
+	pmc_owner_caller = NULL;
+	perf_irq = dummy_perf;
+
+	spin_unlock(&pmc_owner_lock);
+}
+EXPORT_SYMBOL_GPL(release_pmc_hardware);
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
--- a/arch/ppc64/kernel/ppc_ksyms.c
+++ b/arch/ppc64/kernel/ppc_ksyms.c
@@ -8,49 +8,18 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
 #include <linux/console.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/smp_lock.h>
-#include <linux/syscalls.h>
-#include <linux/bitops.h>
+#include <net/checksum.h>
 
-#include <asm/page.h>
-#include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/checksum.h>
-#include <asm/pgtable.h>
-#include <asm/prom.h>
 #include <asm/system.h>
-#include <asm/pci-bridge.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
 #include <asm/cacheflush.h>
-#ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/HvCallSc.h>
-#include <asm/iSeries/LparData.h>
-#endif
-
-extern int do_signal(sigset_t *, struct pt_regs *);
-
-EXPORT_SYMBOL(do_signal);
-
-EXPORT_SYMBOL(isa_io_base);
-EXPORT_SYMBOL(pci_io_base);
 
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -65,10 +34,6 @@ EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
 
-EXPORT_SYMBOL(__down_interruptible);
-EXPORT_SYMBOL(__up);
-EXPORT_SYMBOL(__down);
-
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 EXPORT_SYMBOL(ip_fast_csum);
@@ -79,11 +44,6 @@ EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(__strncpy_from_user);
 EXPORT_SYMBOL(__strnlen_user);
 
-EXPORT_SYMBOL(clear_user_page);
-
-#ifdef CONFIG_MSCHUNKS
-EXPORT_SYMBOL(msChunks);
-#endif
 EXPORT_SYMBOL(reloc_offset);
 
 #ifdef CONFIG_PPC_ISERIES
@@ -107,20 +67,15 @@ EXPORT_SYMBOL(_insw_ns);
 EXPORT_SYMBOL(_outsw_ns);
 EXPORT_SYMBOL(_insl_ns);
 EXPORT_SYMBOL(_outsl_ns);
-EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
 
-EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(giveup_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(giveup_altivec);
 #endif
-EXPORT_SYMBOL(flush_icache_range);
-EXPORT_SYMBOL(flush_icache_user_range);
-EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_icache_range);
+
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC_ISERIES
 EXPORT_SYMBOL(local_get_flags);
@@ -129,19 +84,6 @@ EXPORT_SYMBOL(local_irq_restore);
 #endif
 #endif
 
-EXPORT_SYMBOL(ppc_md);
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-EXPORT_SYMBOL(find_devices);
-EXPORT_SYMBOL(find_type_devices);
-EXPORT_SYMBOL(find_compatible_devices);
-EXPORT_SYMBOL(find_path_device);
-EXPORT_SYMBOL(device_is_compatible);
-EXPORT_SYMBOL(machine_is_compatible);
-EXPORT_SYMBOL(find_all_nodes);
-EXPORT_SYMBOL(get_property);
-#endif
-
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
@@ -150,10 +92,4 @@ EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memchr);
 
 EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(irq_desc);
-EXPORT_SYMBOL(get_wchan);
 EXPORT_SYMBOL(console_drivers);
-
-EXPORT_SYMBOL(tb_ticks_per_usec);
-EXPORT_SYMBOL(paca);
-EXPORT_SYMBOL(cur_cpu_spec);
diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c
--- a/arch/ppc64/kernel/proc_ppc64.c
+++ b/arch/ppc64/kernel/proc_ppc64.c
@@ -41,20 +41,6 @@ static struct file_operations page_map_f
 	.mmap	= page_map_mmap
 };
 
-#ifdef CONFIG_PPC_PSERIES
-/* routines for /proc/ppc64/ofdt */
-static ssize_t ofdt_write(struct file *, const char __user *, size_t, loff_t *);
-static void proc_ppc64_create_ofdt(void);
-static int do_remove_node(char *);
-static int do_add_node(char *, size_t);
-static void release_prop_list(const struct property *);
-static struct property *new_property(const char *, const int, const unsigned char *, struct property *);
-static char * parse_next_property(char *, char *, char **, int *, unsigned char**);
-static struct file_operations ofdt_fops = {
-	.write = ofdt_write
-};
-#endif
-
 /*
  * Create the ppc64 and ppc64/rtas directories early. This allows us to
  * assume that they have been previously created in drivers.
@@ -89,14 +75,9 @@ static int __init proc_ppc64_init(void)
 		return 1;
 	pde->nlink = 1;
 	pde->data = systemcfg;
-	pde->size = 4096;
+	pde->size = PAGE_SIZE;
 	pde->proc_fops = &page_map_fops;
 
-#ifdef CONFIG_PPC_PSERIES
-	if ((systemcfg->platform & PLATFORM_PSERIES))
-		proc_ppc64_create_ofdt();
-#endif
-
 	return 0;
 }
 __initcall(proc_ppc64_init);
@@ -145,233 +126,3 @@ static int page_map_mmap( struct file *f
 	return 0;
 }
 
-#ifdef CONFIG_PPC_PSERIES
-/* create /proc/ppc64/ofdt write-only by root */
-static void proc_ppc64_create_ofdt(void)
-{
-	struct proc_dir_entry *ent;
-
-	ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
-	if (ent) {
-		ent->nlink = 1;
-		ent->data = NULL;
-		ent->size = 0;
-		ent->proc_fops = &ofdt_fops;
-	}
-}
-
-/**
- * ofdt_write - perform operations on the Open Firmware device tree
- *
- * @file: not used
- * @buf: command and arguments
- * @count: size of the command buffer
- * @off: not used
- *
- * Operations supported at this time are addition and removal of
- * whole nodes along with their properties.  Operations on individual
- * properties are not implemented (yet).
- */
-static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count,
-			  loff_t *off)
-{
-	int rv = 0;
-	char *kbuf;
-	char *tmp;
-
-	if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) {
-		rv = -ENOMEM;
-		goto out;
-	}
-	if (copy_from_user(kbuf, buf, count)) {
-		rv = -EFAULT;
-		goto out;
-	}
-
-	kbuf[count] = '\0';
-
-	tmp = strchr(kbuf, ' ');
-	if (!tmp) {
-		rv = -EINVAL;
-		goto out;
-	}
-	*tmp = '\0';
-	tmp++;
-
-	if (!strcmp(kbuf, "add_node"))
-		rv = do_add_node(tmp, count - (tmp - kbuf));
-	else if (!strcmp(kbuf, "remove_node"))
-		rv = do_remove_node(tmp);
-	else
-		rv = -EINVAL;
-out:
-	kfree(kbuf);
-	return rv ? rv : count;
-}
-
-static int do_remove_node(char *buf)
-{
-	struct device_node *node;
-	int rv = -ENODEV;
-
-	if ((node = of_find_node_by_path(buf)))
-		rv = of_remove_node(node);
-
-	of_node_put(node);
-	return rv;
-}
-
-static int do_add_node(char *buf, size_t bufsize)
-{
-	char *path, *end, *name;
-	struct device_node *np;
-	struct property *prop = NULL;
-	unsigned char* value;
-	int length, rv = 0;
-
-	end = buf + bufsize;
-	path = buf;
-	buf = strchr(buf, ' ');
-	if (!buf)
-		return -EINVAL;
-	*buf = '\0';
-	buf++;
-
-	if ((np = of_find_node_by_path(path))) {
-		of_node_put(np);
-		return -EINVAL;
-	}
-
-	/* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
-	while (buf < end &&
-	       (buf = parse_next_property(buf, end, &name, &length, &value))) {
-		struct property *last = prop;
-
-		prop = new_property(name, length, value, last);
-		if (!prop) {
-			rv = -ENOMEM;
-			prop = last;
-			goto out;
-		}
-	}
-	if (!buf) {
-		rv = -EINVAL;
-		goto out;
-	}
-
-	rv = of_add_node(path, prop);
-
-out:
-	if (rv)
-		release_prop_list(prop);
-	return rv;
-}
-
-static struct property *new_property(const char *name, const int length,
-				     const unsigned char *value, struct property *last)
-{
-	struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
-
-	if (!new)
-		return NULL;
-	memset(new, 0, sizeof(*new));
-
-	if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL)))
-		goto cleanup;
-	if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
-		goto cleanup;
-
-	strcpy(new->name, name);
-	memcpy(new->value, value, length);
-	*(((char *)new->value) + length) = 0;
-	new->length = length;
-	new->next = last;
-	return new;
-
-cleanup:
-	if (new->name)
-		kfree(new->name);
-	if (new->value)
-		kfree(new->value);
-	kfree(new);
-	return NULL;
-}
-
-/**
- * parse_next_property - process the next property from raw input buffer
- * @buf: input buffer, must be nul-terminated
- * @end: end of the input buffer + 1, for validation
- * @name: return value; set to property name in buf
- * @length: return value; set to length of value
- * @value: return value; set to the property value in buf
- *
- * Note that the caller must make copies of the name and value returned,
- * this function does no allocation or copying of the data.  Return value
- * is set to the next name in buf, or NULL on error.
- */
-static char * parse_next_property(char *buf, char *end, char **name, int *length,
-				  unsigned char **value)
-{
-	char *tmp;
-
-	*name = buf;
-
-	tmp = strchr(buf, ' ');
-	if (!tmp) {
-		printk(KERN_ERR "property parse failed in %s at line %d\n",
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-	*tmp = '\0';
-
-	if (++tmp >= end) {
-		printk(KERN_ERR "property parse failed in %s at line %d\n",
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-
-	/* now we're on the length */
-	*length = -1;
-	*length = simple_strtoul(tmp, &tmp, 10);
-	if (*length == -1) {
-		printk(KERN_ERR "property parse failed in %s at line %d\n", 
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-	if (*tmp != ' ' || ++tmp >= end) {
-		printk(KERN_ERR "property parse failed in %s at line %d\n",
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-
-	/* now we're on the value */
-	*value = tmp;
-	tmp += *length;
-	if (tmp > end) {
-		printk(KERN_ERR "property parse failed in %s at line %d\n",
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-	else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
-		printk(KERN_ERR "property parse failed in %s at line %d\n",
-		       __FUNCTION__, __LINE__);
-		return NULL;
-	}
-	tmp++;
-
-	/* and now we should be on the next name, or the end */
-	return tmp;
-}
-
-static void release_prop_list(const struct property *prop)
-{
-	struct property *next;
-	for (; prop; prop = next) {
-		next = prop->next;
-		kfree(prop->name);
-		kfree(prop->value);
-		kfree(prop);
-	}
-
-}
-#endif	/* defined(CONFIG_PPC_PSERIES) */
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c
+++ b/arch/ppc64/kernel/process.c
@@ -51,6 +51,7 @@
 #include <asm/cputable.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
+#include <asm/time.h>
 
 #ifndef CONFIG_SMP
 struct task_struct *last_task_used_math = NULL;
@@ -168,6 +169,8 @@ int dump_task_altivec(struct pt_regs *re
 
 #endif /* CONFIG_ALTIVEC */
 
+DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
+
 struct task_struct *__switch_to(struct task_struct *prev,
 				struct task_struct *new)
 {
@@ -206,6 +209,21 @@ struct task_struct *__switch_to(struct t
 	new_thread = &new->thread;
 	old_thread = &current->thread;
 
+/* Collect purr utilization data per process and per processor wise */
+/* purr is nothing but processor time base                          */
+
+#if defined(CONFIG_PPC_PSERIES)
+	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+		struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
+		long unsigned start_tb, current_tb;
+		start_tb = old_thread->start_tb;
+		cu->current_tb = current_tb = mfspr(SPRN_PURR);
+		old_thread->accum_tb += (current_tb - start_tb);
+		new_thread->start_tb = current_tb;
+	}
+#endif
+
+
 	local_irq_save(flags);
 	last = _switch(old_thread, new_thread);
 
@@ -360,9 +378,6 @@ copy_thread(int nr, unsigned long clone_
 		childregs->gpr[1] = sp + sizeof(struct pt_regs);
 		p->thread.regs = NULL;	/* no user register state */
 		clear_ti_thread_flag(p->thread_info, TIF_32BIT);
-#ifdef CONFIG_PPC_ISERIES
-		set_ti_thread_flag(p->thread_info, TIF_RUN_LIGHT);
-#endif
 	} else {
 		childregs->gpr[1] = usp;
 		p->thread.regs = childregs;
@@ -388,12 +403,12 @@ copy_thread(int nr, unsigned long clone_
 	kregs = (struct pt_regs *) sp;
 	sp -= STACK_FRAME_OVERHEAD;
 	p->thread.ksp = sp;
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
+	if (cpu_has_feature(CPU_FTR_SLB)) {
 		unsigned long sp_vsid = get_kernel_vsid(sp);
 
 		sp_vsid <<= SLB_VSID_SHIFT;
 		sp_vsid |= SLB_VSID_KERNEL;
-		if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+		if (cpu_has_feature(CPU_FTR_16M_PAGE))
 			sp_vsid |= SLB_VSID_L;
 
 		p->thread.ksp_vsid = sp_vsid;
@@ -469,6 +484,7 @@ void start_thread(struct pt_regs *regs, 
 	current->thread.used_vr = 0;
 #endif /* CONFIG_ALTIVEC */
 }
+EXPORT_SYMBOL(start_thread);
 
 int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
 {
@@ -607,6 +623,7 @@ unsigned long get_wchan(struct task_stru
 	} while (count++ < 16);
 	return 0;
 }
+EXPORT_SYMBOL(get_wchan);
 
 void show_stack(struct task_struct *p, unsigned long *_sp)
 {
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -27,11 +27,12 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
 #include <linux/bitops.h>
+#include <linux/module.h>
+
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/lmb.h>
@@ -51,6 +52,7 @@
 #include <asm/btext.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
+#include <asm/pSeries_reconfig.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -71,8 +73,8 @@ struct isa_reg_property {
 };
 
 
-typedef unsigned long interpret_func(struct device_node *, unsigned long,
-				     int, int, int);
+typedef int interpret_func(struct device_node *, unsigned long *,
+			   int, int, int);
 
 extern struct rtas_t rtas;
 extern struct lmb lmb;
@@ -101,6 +103,25 @@ static DEFINE_RWLOCK(devtree_lock);
 struct device_node *of_chosen;
 
 /*
+ * Wrapper for allocating memory for various data that needs to be
+ * attached to device nodes as they are processed at boot or when
+ * added to the device tree later (e.g. DLPAR).  At boot there is
+ * already a region reserved so we just increment *mem_start by size;
+ * otherwise we call kmalloc.
+ */
+static void * prom_alloc(unsigned long size, unsigned long *mem_start)
+{
+	unsigned long tmp;
+
+	if (!mem_start)
+		return kmalloc(size, GFP_KERNEL);
+
+	tmp = *mem_start;
+	*mem_start += size;
+	return (void *)tmp;
+}
+
+/*
  * Find the device_node with a given phandle.
  */
 static struct device_node * find_phandle(phandle ph)
@@ -253,9 +274,9 @@ static int __devinit map_interrupt(unsig
 	return nintrc;
 }
 
-static unsigned long __init finish_node_interrupts(struct device_node *np,
-						   unsigned long mem_start,
-						   int measure_only)
+static int __devinit finish_node_interrupts(struct device_node *np,
+					    unsigned long *mem_start,
+					    int measure_only)
 {
 	unsigned int *ints;
 	int intlen, intrcells, intrcount;
@@ -265,14 +286,16 @@ static unsigned long __init finish_node_
 
 	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
 	if (ints == NULL)
-		return mem_start;
+		return 0;
 	intrcells = prom_n_intr_cells(np);
 	intlen /= intrcells * sizeof(unsigned int);
-	np->intrs = (struct interrupt_info *) mem_start;
-	mem_start += intlen * sizeof(struct interrupt_info);
+
+	np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
+	if (!np->intrs)
+		return -ENOMEM;
 
 	if (measure_only)
-		return mem_start;
+		return 0;
 
 	intrcount = 0;
 	for (i = 0; i < intlen; ++i, ints += intrcells) {
@@ -298,6 +321,10 @@ static unsigned long __init finish_node_
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
 				np->intrs[intrcount].line += 128;
+			else if (!(name && !strcmp(name, "mac-io")))
+				/* ignore other cascaded controllers, such as
+				   the k2-sata-root */
+				break;
 		}
 		np->intrs[intrcount].sense = 1;
 		if (n > 1)
@@ -313,42 +340,49 @@ static unsigned long __init finish_node_
 	}
 	np->n_intrs = intrcount;
 
-	return mem_start;
+	return 0;
 }
 
-static unsigned long __init interpret_pci_props(struct device_node *np,
-						unsigned long mem_start,
-						int naddrc, int nsizec,
-						int measure_only)
+static int __devinit interpret_pci_props(struct device_node *np,
+					 unsigned long *mem_start,
+					 int naddrc, int nsizec,
+					 int measure_only)
 {
 	struct address_range *adr;
 	struct pci_reg_property *pci_addrs;
-	int i, l;
+	int i, l, n_addrs;
 
 	pci_addrs = (struct pci_reg_property *)
 		get_property(np, "assigned-addresses", &l);
-	if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			if (!measure_only) {
-				adr[i].space = pci_addrs[i].addr.a_hi;
-				adr[i].address = pci_addrs[i].addr.a_lo;
-				adr[i].size = pci_addrs[i].size_lo;
-			}
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
+	if (!pci_addrs)
+		return 0;
+
+	n_addrs = l / sizeof(*pci_addrs);
+
+	adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
+	if (!adr)
+		return -ENOMEM;
+
+ 	if (measure_only)
+ 		return 0;
+
+ 	np->addrs = adr;
+ 	np->n_addrs = n_addrs;
+
+ 	for (i = 0; i < n_addrs; i++) {
+ 		adr[i].space = pci_addrs[i].addr.a_hi;
+ 		adr[i].address = pci_addrs[i].addr.a_lo |
+			((u64)pci_addrs[i].addr.a_mid << 32);
+ 		adr[i].size = pci_addrs[i].size_lo;
 	}
-	return mem_start;
+
+	return 0;
 }
 
-static unsigned long __init interpret_dbdma_props(struct device_node *np,
-						  unsigned long mem_start,
-						  int naddrc, int nsizec,
-						  int measure_only)
+static int __init interpret_dbdma_props(struct device_node *np,
+					unsigned long *mem_start,
+					int naddrc, int nsizec,
+					int measure_only)
 {
 	struct reg_property32 *rp;
 	struct address_range *adr;
@@ -369,7 +403,7 @@ static unsigned long __init interpret_db
 	rp = (struct reg_property32 *) get_property(np, "reg", &l);
 	if (rp != 0 && l >= sizeof(struct reg_property32)) {
 		i = 0;
-		adr = (struct address_range *) mem_start;
+		adr = (struct address_range *) (*mem_start);
 		while ((l -= sizeof(struct reg_property32)) >= 0) {
 			if (!measure_only) {
 				adr[i].space = 2;
@@ -380,16 +414,16 @@ static unsigned long __init interpret_db
 		}
 		np->addrs = adr;
 		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
+		(*mem_start) += i * sizeof(struct address_range);
 	}
 
-	return mem_start;
+	return 0;
 }
 
-static unsigned long __init interpret_macio_props(struct device_node *np,
-						  unsigned long mem_start,
-						  int naddrc, int nsizec,
-						  int measure_only)
+static int __init interpret_macio_props(struct device_node *np,
+					unsigned long *mem_start,
+					int naddrc, int nsizec,
+					int measure_only)
 {
 	struct reg_property32 *rp;
 	struct address_range *adr;
@@ -410,7 +444,7 @@ static unsigned long __init interpret_ma
 	rp = (struct reg_property32 *) get_property(np, "reg", &l);
 	if (rp != 0 && l >= sizeof(struct reg_property32)) {
 		i = 0;
-		adr = (struct address_range *) mem_start;
+		adr = (struct address_range *) (*mem_start);
 		while ((l -= sizeof(struct reg_property32)) >= 0) {
 			if (!measure_only) {
 				adr[i].space = 2;
@@ -421,16 +455,16 @@ static unsigned long __init interpret_ma
 		}
 		np->addrs = adr;
 		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
+		(*mem_start) += i * sizeof(struct address_range);
 	}
 
-	return mem_start;
+	return 0;
 }
 
-static unsigned long __init interpret_isa_props(struct device_node *np,
-						unsigned long mem_start,
-						int naddrc, int nsizec,
-						int measure_only)
+static int __init interpret_isa_props(struct device_node *np,
+				      unsigned long *mem_start,
+				      int naddrc, int nsizec,
+				      int measure_only)
 {
 	struct isa_reg_property *rp;
 	struct address_range *adr;
@@ -439,7 +473,7 @@ static unsigned long __init interpret_is
 	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
 	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
 		i = 0;
-		adr = (struct address_range *) mem_start;
+		adr = (struct address_range *) (*mem_start);
 		while ((l -= sizeof(struct isa_reg_property)) >= 0) {
 			if (!measure_only) {
 				adr[i].space = rp[i].space;
@@ -450,16 +484,16 @@ static unsigned long __init interpret_is
 		}
 		np->addrs = adr;
 		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
+		(*mem_start) += i * sizeof(struct address_range);
 	}
 
-	return mem_start;
+	return 0;
 }
 
-static unsigned long __init interpret_root_props(struct device_node *np,
-						 unsigned long mem_start,
-						 int naddrc, int nsizec,
-						 int measure_only)
+static int __init interpret_root_props(struct device_node *np,
+				       unsigned long *mem_start,
+				       int naddrc, int nsizec,
+				       int measure_only)
 {
 	struct address_range *adr;
 	int i, l;
@@ -469,7 +503,7 @@ static unsigned long __init interpret_ro
 	rp = (unsigned int *) get_property(np, "reg", &l);
 	if (rp != 0 && l >= rpsize) {
 		i = 0;
-		adr = (struct address_range *) mem_start;
+		adr = (struct address_range *) (*mem_start);
 		while ((l -= rpsize) >= 0) {
 			if (!measure_only) {
 				adr[i].space = 0;
@@ -481,26 +515,30 @@ static unsigned long __init interpret_ro
 		}
 		np->addrs = adr;
 		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
+		(*mem_start) += i * sizeof(struct address_range);
 	}
 
-	return mem_start;
+	return 0;
 }
 
-static unsigned long __init finish_node(struct device_node *np,
-					unsigned long mem_start,
-					interpret_func *ifunc,
-					int naddrc, int nsizec,
-					int measure_only)
+static int __devinit finish_node(struct device_node *np,
+				 unsigned long *mem_start,
+				 interpret_func *ifunc,
+				 int naddrc, int nsizec,
+				 int measure_only)
 {
 	struct device_node *child;
-	int *ip;
+	int *ip, rc = 0;
 
 	/* get the device addresses and interrupts */
 	if (ifunc != NULL)
-		mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only);
+		rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
+	if (rc)
+		goto out;
 
-	mem_start = finish_node_interrupts(np, mem_start, measure_only);
+	rc = finish_node_interrupts(np, mem_start, measure_only);
+	if (rc)
+		goto out;
 
 	/* Look for #address-cells and #size-cells properties. */
 	ip = (int *) get_property(np, "#address-cells", NULL);
@@ -510,12 +548,6 @@ static unsigned long __init finish_node(
 	if (ip != NULL)
 		nsizec = *ip;
 
-	/* the f50 sets the name to 'display' and 'compatible' to what we
-	 * expect for the name -- Cort
-	 */
-	if (!strcmp(np->name, "display"))
-		np->name = get_property(np, "compatible", NULL);
-
 	if (!strcmp(np->name, "device-tree") || np->parent == NULL)
 		ifunc = interpret_root_props;
 	else if (np->type == 0)
@@ -536,11 +568,14 @@ static unsigned long __init finish_node(
 		       || !strcmp(np->type, "media-bay"))))
 		ifunc = NULL;
 
-	for (child = np->child; child != NULL; child = child->sibling)
-		mem_start = finish_node(child, mem_start, ifunc,
-					naddrc, nsizec, measure_only);
-
-	return mem_start;
+	for (child = np->child; child != NULL; child = child->sibling) {
+		rc = finish_node(child, mem_start, ifunc,
+				 naddrc, nsizec, measure_only);
+		if (rc)
+			goto out;
+	}
+out:
+	return rc;
 }
 
 /**
@@ -552,7 +587,7 @@ static unsigned long __init finish_node(
  */
 void __init finish_device_tree(void)
 {
-	unsigned long mem, size;
+	unsigned long start, end, size = 0;
 
 	DBG(" -> finish_device_tree\n");
 
@@ -564,11 +599,22 @@ void __init finish_device_tree(void)
 	/* Initialize virtual IRQ map */
 	virt_irq_init();
 
-	/* Finish device-tree (pre-parsing some properties etc...) */
-	size = finish_node(allnodes, 0, NULL, 0, 0, 1);
-	mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128));
-	if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size)
-		BUG();
+	/*
+	 * Finish device-tree (pre-parsing some properties etc...)
+	 * We do this in 2 passes. One with "measure_only" set, which
+	 * will only measure the amount of memory needed, then we can
+	 * allocate that memory, and call finish_node again. However,
+	 * we must be careful as most routines will fail nowadays when
+	 * prom_alloc() returns 0, so we must make sure our first pass
+	 * doesn't start at 0. We pre-initialize size to 16 for that
+	 * reason and then remove those additional 16 bytes
+	 */
+	size = 16;
+	finish_node(allnodes, &size, NULL, 0, 0, 1);
+	size -= 16;
+	end = start = (unsigned long)abs_to_virt(lmb_alloc(size, 128));
+	finish_node(allnodes, &end, NULL, 0, 0, 0);
+	BUG_ON(end != start + size);
 
 	DBG(" <- finish_device_tree\n");
 }
@@ -788,7 +834,7 @@ void __init unflatten_device_tree(void)
 {
 	unsigned long start, mem, size;
 	struct device_node **allnextp = &allnodes;
-	char *p;
+	char *p = NULL;
 	int l = 0;
 
 	DBG(" -> unflatten_device_tree()\n");
@@ -837,6 +883,7 @@ static int __init early_init_dt_scan_cpu
 					  const char *full_path, void *data)
 {
 	char *type = get_flat_dt_prop(node, "device_type", NULL);
+	u32 *prop;
 
 	/* We are scanning "cpu" nodes only */
 	if (type == NULL || strcmp(type, "cpu") != 0)
@@ -868,6 +915,20 @@ static int __init early_init_dt_scan_cpu
 		}
 	}
 
+	/* Check if we have a VMX and eventually update CPU features */
+	prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL);
+	if (prop && (*prop) > 0) {
+		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+	}
+
+	/* Same goes for Apple's "altivec" property */
+	prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL);
+	if (prop) {
+		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+	}
+
 	return 0;
 }
 
@@ -875,6 +936,8 @@ static int __init early_init_dt_scan_cho
 					    const char *full_path, void *data)
 {
 	u32 *prop;
+	u64 *prop64;
+	extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
 
 	if (strcmp(full_path, "/chosen") != 0)
 		return 0;
@@ -891,7 +954,19 @@ static int __init early_init_dt_scan_cho
 	if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)
 		iommu_force_on = 1;
 
-#ifdef CONFIG_PPC_PSERIES
+ 	prop64 = (u64*)get_flat_dt_prop(node, "linux,memory-limit", NULL);
+ 	if (prop64)
+ 		memory_limit = *prop64;
+
+ 	prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-start", NULL);
+ 	if (prop64)
+ 		tce_alloc_start = *prop64;
+
+ 	prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
+ 	if (prop64)
+ 		tce_alloc_end = *prop64;
+
+#ifdef CONFIG_PPC_RTAS
 	/* To help early debugging via the front panel, we retreive a minimal
 	 * set of RTAS infos now if available
 	 */
@@ -907,7 +982,7 @@ static int __init early_init_dt_scan_cho
 			rtas.size = *prop;
 		}
 	}
-#endif /* CONFIG_PPC_PSERIES */
+#endif /* CONFIG_PPC_RTAS */
 
 	/* break now */
 	return 1;
@@ -1030,6 +1105,7 @@ void __init early_init_devtree(void *par
 	lmb_init();
 	scan_flat_dt(early_init_dt_scan_root, NULL);
 	scan_flat_dt(early_init_dt_scan_memory, NULL);
+	lmb_enforce_memory_limit();
 	lmb_analyze();
 	systemcfg->physicalMemorySize = lmb_phys_mem_size();
 	lmb_reserve(0, __pa(klimit));
@@ -1041,7 +1117,9 @@ void __init early_init_devtree(void *par
 
 	DBG("Scanning CPUs ...\n");
 
-	/* Retreive hash table size from flattened tree */
+	/* Retreive hash table size from flattened tree plus other
+	 * CPU related informations (altivec support, boot CPU ID, ...)
+	 */
 	scan_flat_dt(early_init_dt_scan_cpus, NULL);
 
 	/* If hash size wasn't obtained above, we calculate it now based on
@@ -1138,6 +1216,7 @@ find_devices(const char *name)
 	*prevp = NULL;
 	return head;
 }
+EXPORT_SYMBOL(find_devices);
 
 /**
  * Construct and return a list of the device_nodes with a given type.
@@ -1157,6 +1236,7 @@ find_type_devices(const char *type)
 	*prevp = NULL;
 	return head;
 }
+EXPORT_SYMBOL(find_type_devices);
 
 /**
  * Returns all nodes linked together
@@ -1174,6 +1254,7 @@ find_all_nodes(void)
 	*prevp = NULL;
 	return head;
 }
+EXPORT_SYMBOL(find_all_nodes);
 
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
@@ -1197,6 +1278,7 @@ device_is_compatible(struct device_node 
 
 	return 0;
 }
+EXPORT_SYMBOL(device_is_compatible);
 
 
 /**
@@ -1216,6 +1298,7 @@ machine_is_compatible(const char *compat
 	}
 	return rc;
 }
+EXPORT_SYMBOL(machine_is_compatible);
 
 /**
  * Construct and return a list of the device_nodes with a given type
@@ -1239,6 +1322,7 @@ find_compatible_devices(const char *type
 	*prevp = NULL;
 	return head;
 }
+EXPORT_SYMBOL(find_compatible_devices);
 
 /**
  * Find the device_node with a given full_name.
@@ -1253,6 +1337,7 @@ find_path_device(const char *path)
 			return np;
 	return NULL;
 }
+EXPORT_SYMBOL(find_path_device);
 
 /*******
  *
@@ -1531,132 +1616,6 @@ void of_node_put(struct device_node *nod
 }
 EXPORT_SYMBOL(of_node_put);
 
-/**
- *	derive_parent - basically like dirname(1)
- *	@path:  the full_name of a node to be added to the tree
- *
- *	Returns the node which should be the parent of the node
- *	described by path.  E.g., for path = "/foo/bar", returns
- *	the node with full_name = "/foo".
- */
-static struct device_node *derive_parent(const char *path)
-{
-	struct device_node *parent = NULL;
-	char *parent_path = "/";
-	size_t parent_path_len = strrchr(path, '/') - path + 1;
-
-	/* reject if path is "/" */
-	if (!strcmp(path, "/"))
-		return NULL;
-
-	if (strrchr(path, '/') != path) {
-		parent_path = kmalloc(parent_path_len, GFP_KERNEL);
-		if (!parent_path)
-			return NULL;
-		strlcpy(parent_path, path, parent_path_len);
-	}
-	parent = of_find_node_by_path(parent_path);
-	if (strcmp(parent_path, "/"))
-		kfree(parent_path);
-	return parent;
-}
-
-/*
- * Routines for "runtime" addition and removal of device tree nodes.
- */
-#ifdef CONFIG_PROC_DEVICETREE
-/*
- * Add a node to /proc/device-tree.
- */
-static void add_node_proc_entries(struct device_node *np)
-{
-	struct proc_dir_entry *ent;
-
-	ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);
-	if (ent)
-		proc_device_tree_add_node(np, ent);
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
-	struct property *pp = np->properties;
-	struct device_node *parent = np->parent;
-
-	while (pp) {
-		remove_proc_entry(pp->name, np->pde);
-		pp = pp->next;
-	}
-
-	/* Assuming that symlinks have the same parent directory as
-	 * np->pde.
-	 */
-	if (np->name_link)
-		remove_proc_entry(np->name_link->name, parent->pde);
-	if (np->addr_link)
-		remove_proc_entry(np->addr_link->name, parent->pde);
-	if (np->pde)
-		remove_proc_entry(np->pde->name, parent->pde);
-}
-#else /* !CONFIG_PROC_DEVICETREE */
-static void add_node_proc_entries(struct device_node *np)
-{
-	return;
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
-	return;
-}
-#endif /* CONFIG_PROC_DEVICETREE */
-
-/*
- * Fix up n_intrs and intrs fields in a new device node
- *
- */
-static int of_finish_dynamic_node_interrupts(struct device_node *node)
-{
-	int intrcells, intlen, i;
-	unsigned *irq, *ints, virq;
-	struct device_node *ic;
-
-	ints = (unsigned int *)get_property(node, "interrupts", &intlen);
-	intrcells = prom_n_intr_cells(node);
-	intlen /= intrcells * sizeof(unsigned int);
-	node->n_intrs = intlen;
-	node->intrs = kmalloc(sizeof(struct interrupt_info) * intlen,
-			      GFP_KERNEL);
-	if (!node->intrs)
-		return -ENOMEM;
-
-	for (i = 0; i < intlen; ++i) {
-		int n, j;
-		node->intrs[i].line = 0;
-		node->intrs[i].sense = 1;
-		n = map_interrupt(&irq, &ic, node, ints, intrcells);
-		if (n <= 0)
-			continue;
-		virq = virt_irq_create_mapping(irq[0]);
-		if (virq == NO_IRQ) {
-			printk(KERN_CRIT "Could not allocate interrupt "
-			       "number for %s\n", node->full_name);
-			return -ENOMEM;
-		}
-		node->intrs[i].line = irq_offset_up(virq);
-		if (n > 1)
-			node->intrs[i].sense = irq[1];
-		if (n > 2) {
-			printk(KERN_DEBUG "hmmm, got %d intr cells for %s:", n,
-			       node->full_name);
-			for (j = 0; j < n; ++j)
-				printk(" %d", irq[j]);
-			printk("\n");
-		}
-		ints += intrcells;
-	}
-	return 0;
-}
-
-
 /*
  * Fix up the uninitialized fields in a new device node:
  * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
@@ -1668,10 +1627,11 @@ static int of_finish_dynamic_node_interr
  * This should probably be split up into smaller chunks.
  */
 
-static int of_finish_dynamic_node(struct device_node *node)
+static int of_finish_dynamic_node(struct device_node *node,
+				  unsigned long *unused1, int unused2,
+				  int unused3, int unused4)
 {
 	struct device_node *parent = of_get_parent(node);
-	u32 *regs;
 	int err = 0;
 	phandle *ibm_phandle;
 
@@ -1693,117 +1653,22 @@ static int of_finish_dynamic_node(struct
 	if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
 		node->linux_phandle = *ibm_phandle;
 
-	/* do the work of interpret_pci_props */
-	if (parent->type && !strcmp(parent->type, "pci")) {
-		struct address_range *adr;
-		struct pci_reg_property *pci_addrs;
-		int i, l;
-
-		pci_addrs = (struct pci_reg_property *)
-			get_property(node, "assigned-addresses", &l);
-		if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
-			i = 0;
-			adr = kmalloc(sizeof(struct address_range) * 
-				      (l / sizeof(struct pci_reg_property)),
-				      GFP_KERNEL);
-			if (!adr) {
-				err = -ENOMEM;
-				goto out;
-			}
-			while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-				adr[i].space = pci_addrs[i].addr.a_hi;
-				adr[i].address = pci_addrs[i].addr.a_lo;
-				adr[i].size = pci_addrs[i].size_lo;
-				++i;
-			}
-			node->addrs = adr;
-			node->n_addrs = i;
-		}
-	}
-
-	/* now do the work of finish_node_interrupts */
-	if (get_property(node, "interrupts", NULL)) {
-		err = of_finish_dynamic_node_interrupts(node);
-		if (err) goto out;
-	}
-
-	/* now do the rough equivalent of update_dn_pci_info, this
-	 * probably is not correct for phb's, but should work for
-	 * IOAs and slots.
-	 */
-
-	node->phb = parent->phb;
-
-	regs = (u32 *)get_property(node, "reg", NULL);
-	if (regs) {
-		node->busno = (regs[0] >> 16) & 0xff;
-		node->devfn = (regs[0] >> 8) & 0xff;
-	}
-
 out:
 	of_node_put(parent);
 	return err;
 }
 
 /*
- * Given a path and a property list, construct an OF device node, add
- * it to the device tree and global list, and place it in
- * /proc/device-tree.  This function may sleep.
+ * Plug a device node into the tree and global list.
  */
-int of_add_node(const char *path, struct property *proplist)
+void of_attach_node(struct device_node *np)
 {
-	struct device_node *np;
-	int err = 0;
-
-	np = kmalloc(sizeof(struct device_node), GFP_KERNEL);
-	if (!np)
-		return -ENOMEM;
-
-	memset(np, 0, sizeof(*np));
-
-	np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
-	if (!np->full_name) {
-		kfree(np);
-		return -ENOMEM;
-	}
-	strcpy(np->full_name, path);
-
-	np->properties = proplist;
-	OF_MARK_DYNAMIC(np);
-	kref_init(&np->kref);
-	of_node_get(np);
-	np->parent = derive_parent(path);
-	if (!np->parent) {
-		kfree(np);
-		return -EINVAL; /* could also be ENOMEM, though */
-	}
-
-	if (0 != (err = of_finish_dynamic_node(np))) {
-		kfree(np);
-		return err;
-	}
-
 	write_lock(&devtree_lock);
 	np->sibling = np->parent->child;
 	np->allnext = allnodes;
 	np->parent->child = np;
 	allnodes = np;
 	write_unlock(&devtree_lock);
-
-	add_node_proc_entries(np);
-
-	of_node_put(np->parent);
-	of_node_put(np);
-	return 0;
-}
-
-/*
- * Prepare an OF node for removal from system
- */
-static void of_cleanup_node(struct device_node *np)
-{
-	if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
-		iommu_free_table(np);
 }
 
 /*
@@ -1811,23 +1676,14 @@ static void of_cleanup_node(struct devic
  * a reference to the node.  The memory associated with the node
  * is not freed until its refcount goes to zero.
  */
-int of_remove_node(struct device_node *np)
+void of_detach_node(const struct device_node *np)
 {
-	struct device_node *parent, *child;
-
-	parent = of_get_parent(np);
-	if (!parent)
-		return -EINVAL;
+	struct device_node *parent;
 
-	if ((child = of_get_next_child(np, NULL))) {
-		of_node_put(child);
-		return -EBUSY;
-	}
+	write_lock(&devtree_lock);
 
-	of_cleanup_node(np);
+	parent = np->parent;
 
-	write_lock(&devtree_lock);
-	remove_node_proc_entries(np);
 	if (allnodes == np)
 		allnodes = np->allnext;
 	else {
@@ -1849,12 +1705,40 @@ int of_remove_node(struct device_node *n
 			;
 		prevsib->sibling = np->sibling;
 	}
+
 	write_unlock(&devtree_lock);
-	of_node_put(parent);
-	of_node_put(np); /* Must decrement the refcount */
-	return 0;
 }
 
+static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+	int err;
+
+	switch (action) {
+	case PSERIES_RECONFIG_ADD:
+		err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
+		if (err < 0) {
+			printk(KERN_ERR "finish_node returned %d\n", err);
+			err = NOTIFY_BAD;
+		}
+		break;
+	default:
+		err = NOTIFY_DONE;
+		break;
+	}
+	return err;
+}
+
+static struct notifier_block prom_reconfig_nb = {
+	.notifier_call = prom_reconfig_notifier,
+	.priority = 10, /* This one needs to run first */
+};
+
+static int __init prom_reconfig_setup(void)
+{
+	return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
+}
+__initcall(prom_reconfig_setup);
+
 /*
  * Find a property with a given name for a given node
  * and return the value.
@@ -1872,6 +1756,7 @@ get_property(struct device_node *np, con
 		}
 	return NULL;
 }
+EXPORT_SYMBOL(get_property);
 
 /*
  * Add a property to a node
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -151,7 +151,6 @@ typedef u32 cell_t;
 
 extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
 
-extern unsigned long reloc_offset(void);
 extern void enter_prom(struct prom_args *args, unsigned long entry);
 extern void copy_and_flush(unsigned long dest, unsigned long src,
 			   unsigned long size, unsigned long offset);
@@ -178,6 +177,10 @@ static int __initdata of_platform;
 
 static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
 
+static unsigned long __initdata prom_memory_limit;
+static unsigned long __initdata prom_tce_alloc_start;
+static unsigned long __initdata prom_tce_alloc_end;
+
 static unsigned long __initdata alloc_top;
 static unsigned long __initdata alloc_top_high;
 static unsigned long __initdata alloc_bottom;
@@ -208,13 +211,23 @@ struct {
  */
 #define ADDR(x)		(u32) ((unsigned long)(x) - offset)
 
+/*
+ * Error results ... some OF calls will return "-1" on error, some
+ * will return 0, some will return either. To simplify, here are
+ * macros to use with any ihandle or phandle return value to check if
+ * it is valid
+ */
+
+#define PROM_ERROR		(-1u)
+#define PHANDLE_VALID(p)	((p) != 0 && (p) != PROM_ERROR)
+#define IHANDLE_VALID(i)	((i) != 0 && (i) != PROM_ERROR)
+
+
 /* This is the one and *ONLY* place where we actually call open
  * firmware from, since we need to make sure we're running in 32b
  * mode when we do.  We switch back to 64b mode upon return.
  */
 
-#define PROM_ERROR	(-1)
-
 static int __init call_prom(const char *service, int nargs, int nret, ...)
 {
 	int i;
@@ -385,10 +398,70 @@ static int __init prom_setprop(phandle n
 			 (u32)(unsigned long) value, (u32) valuelen);
 }
 
+/* We can't use the standard versions because of RELOC headaches. */
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
+
+#define isdigit(c)	('0' <= (c) && (c) <= '9')
+#define islower(c)	('a' <= (c) && (c) <= 'z')
+#define toupper(c)	(islower(c) ? ((c) - 'a' + 'A') : (c))
+
+unsigned long prom_strtoul(const char *cp, const char **endp)
+{
+	unsigned long result = 0, base = 10, value;
+
+	if (*cp == '0') {
+		base = 8;
+		cp++;
+		if (toupper(*cp) == 'X') {
+			cp++;
+			base = 16;
+		}
+	}
+
+	while (isxdigit(*cp) &&
+	       (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
+		result = result * base + value;
+		cp++;
+	}
+
+	if (endp)
+		*endp = cp;
+
+	return result;
+}
+
+unsigned long prom_memparse(const char *ptr, const char **retptr)
+{
+	unsigned long ret = prom_strtoul(ptr, retptr);
+	int shift = 0;
+
+	/*
+	 * We can't use a switch here because GCC *may* generate a
+	 * jump table which won't work, because we're not running at
+	 * the address we're linked at.
+	 */
+	if ('G' == **retptr || 'g' == **retptr)
+		shift = 30;
+
+	if ('M' == **retptr || 'm' == **retptr)
+		shift = 20;
+
+	if ('K' == **retptr || 'k' == **retptr)
+		shift = 10;
+
+	if (shift) {
+		ret <<= shift;
+		(*retptr)++;
+	}
+
+	return ret;
+}
 
 /*
  * Early parsing of the command line passed to the kernel, used for
- * the options that affect the iommu
+ * "mem=x" and the options that affect the iommu
  */
 static void __init early_cmdline_parse(void)
 {
@@ -419,6 +492,120 @@ static void __init early_cmdline_parse(v
 		else if (!strncmp(opt, RELOC("force"), 5))
 			RELOC(iommu_force_on) = 1;
 	}
+
+	opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
+	if (opt) {
+		opt += 4;
+		RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
+		/* Align to 16 MB == size of large page */
+		RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
+	}
+}
+
+/*
+ * To tell the firmware what our capabilities are, we have to pass
+ * it a fake 32-bit ELF header containing a couple of PT_NOTE sections
+ * that contain structures that contain the actual values.
+ */
+static struct fake_elf {
+	Elf32_Ehdr	elfhdr;
+	Elf32_Phdr	phdr[2];
+	struct chrpnote {
+		u32	namesz;
+		u32	descsz;
+		u32	type;
+		char	name[8];	/* "PowerPC" */
+		struct chrpdesc {
+			u32	real_mode;
+			u32	real_base;
+			u32	real_size;
+			u32	virt_base;
+			u32	virt_size;
+			u32	load_base;
+		} chrpdesc;
+	} chrpnote;
+	struct rpanote {
+		u32	namesz;
+		u32	descsz;
+		u32	type;
+		char	name[24];	/* "IBM,RPA-Client-Config" */
+		struct rpadesc {
+			u32	lpar_affinity;
+			u32	min_rmo_size;
+			u32	min_rmo_percent;
+			u32	max_pft_size;
+			u32	splpar;
+			u32	min_load;
+			u32	new_mem_def;
+			u32	ignore_me;
+		} rpadesc;
+	} rpanote;
+} fake_elf = {
+	.elfhdr = {
+		.e_ident = { 0x7f, 'E', 'L', 'F',
+			     ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
+		.e_type = ET_EXEC,	/* yeah right */
+		.e_machine = EM_PPC,
+		.e_version = EV_CURRENT,
+		.e_phoff = offsetof(struct fake_elf, phdr),
+		.e_phentsize = sizeof(Elf32_Phdr),
+		.e_phnum = 2
+	},
+	.phdr = {
+		[0] = {
+			.p_type = PT_NOTE,
+			.p_offset = offsetof(struct fake_elf, chrpnote),
+			.p_filesz = sizeof(struct chrpnote)
+		}, [1] = {
+			.p_type = PT_NOTE,
+			.p_offset = offsetof(struct fake_elf, rpanote),
+			.p_filesz = sizeof(struct rpanote)
+		}
+	},
+	.chrpnote = {
+		.namesz = sizeof("PowerPC"),
+		.descsz = sizeof(struct chrpdesc),
+		.type = 0x1275,
+		.name = "PowerPC",
+		.chrpdesc = {
+			.real_mode = ~0U,	/* ~0 means "don't care" */
+			.real_base = ~0U,
+			.real_size = ~0U,
+			.virt_base = ~0U,
+			.virt_size = ~0U,
+			.load_base = ~0U
+		},
+	},
+	.rpanote = {
+		.namesz = sizeof("IBM,RPA-Client-Config"),
+		.descsz = sizeof(struct rpadesc),
+		.type = 0x12759999,
+		.name = "IBM,RPA-Client-Config",
+		.rpadesc = {
+			.lpar_affinity = 0,
+			.min_rmo_size = 64,	/* in megabytes */
+			.min_rmo_percent = 0,
+			.max_pft_size = 48,	/* 2^48 bytes max PFT size */
+			.splpar = 1,
+			.min_load = ~0U,
+			.new_mem_def = 0
+		}
+	}
+};
+
+static void __init prom_send_capabilities(void)
+{
+	unsigned long offset = reloc_offset();
+	ihandle elfloader;
+
+	elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
+	if (elfloader == 0) {
+		prom_printf("couldn't open /packages/elf-loader\n");
+		return;
+	}
+	call_prom("call-method", 3, 1, ADDR("process-elf-header"),
+			elfloader, ADDR(&fake_elf));
+	call_prom("close", 1, 0, elfloader);
 }
 
 /*
@@ -468,7 +655,7 @@ static unsigned long __init alloc_up(uns
 	    base = _ALIGN_UP(base + 0x100000, align)) {
 		prom_debug("    trying: 0x%x\n\r", base);
 		addr = (unsigned long)prom_claim(base, size, 0);
-		if ((int)addr != PROM_ERROR)
+		if (addr != PROM_ERROR)
 			break;
 		addr = 0;
 		if (align == 0)
@@ -530,7 +717,7 @@ static unsigned long __init alloc_down(u
 	for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align))  {
 		prom_debug("    trying: 0x%x\n\r", base);
 		addr = (unsigned long)prom_claim(base, size, 0);
-		if ((int)addr != PROM_ERROR)
+		if (addr != PROM_ERROR)
 			break;
 		addr = 0;
 	}
@@ -665,26 +852,50 @@ static void __init prom_init_mem(void)
 		}
 	}
 
-	/* Setup our top/bottom alloc points, that is top of RMO or top of
-	 * segment 0 when running non-LPAR
-	 */
-	if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
-		RELOC(alloc_top) = RELOC(rmo_top);
-	else
-		RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top));
 	RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000);
-	RELOC(alloc_top_high) = RELOC(ram_top);
 
 	/* Check if we have an initrd after the kernel, if we do move our bottom
 	 * point to after it
 	 */
 	if (RELOC(prom_initrd_start)) {
-		if ((RELOC(prom_initrd_start) + RELOC(prom_initrd_end))
-		    > RELOC(alloc_bottom))
+		if (RELOC(prom_initrd_end) > RELOC(alloc_bottom))
 			RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
 	}
 
+	/*
+	 * If prom_memory_limit is set we reduce the upper limits *except* for
+	 * alloc_top_high. This must be the real top of RAM so we can put
+	 * TCE's up there.
+	 */
+
+	RELOC(alloc_top_high) = RELOC(ram_top);
+
+	if (RELOC(prom_memory_limit)) {
+		if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
+			prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
+				RELOC(prom_memory_limit));
+			RELOC(prom_memory_limit) = 0;
+		} else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
+			prom_printf("Ignoring mem=%x >= ram_top.\n",
+				RELOC(prom_memory_limit));
+			RELOC(prom_memory_limit) = 0;
+		} else {
+			RELOC(ram_top) = RELOC(prom_memory_limit);
+			RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
+		}
+	}
+
+	/*
+	 * Setup our top alloc point, that is top of RMO or top of
+	 * segment 0 when running non-LPAR.
+	 */
+	if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
+		RELOC(alloc_top) = RELOC(rmo_top);
+	else
+		RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top));
+
 	prom_printf("memory layout at init:\n");
+	prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
 	prom_printf("  alloc_bottom : %x\n", RELOC(alloc_bottom));
 	prom_printf("  alloc_top    : %x\n", RELOC(alloc_top));
 	prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
@@ -700,18 +911,19 @@ static void __init prom_instantiate_rtas
 {
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
-	phandle prom_rtas, rtas_node;
+	phandle rtas_node;
+	ihandle rtas_inst;
 	u32 base, entry = 0;
 	u32 size = 0;
 
 	prom_debug("prom_instantiate_rtas: start...\n");
 
-	prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
-	prom_debug("prom_rtas: %x\n", prom_rtas);
-	if (prom_rtas == (phandle) -1)
+	rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+	prom_debug("rtas_node: %x\n", rtas_node);
+	if (!PHANDLE_VALID(rtas_node))
 		return;
 
-	prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size));
+	prom_getprop(rtas_node, "rtas-size", &size, sizeof(size));
 	if (size == 0)
 		return;
 
@@ -720,14 +932,18 @@ static void __init prom_instantiate_rtas
 		prom_printf("RTAS allocation failed !\n");
 		return;
 	}
-	prom_printf("instantiating rtas at 0x%x", base);
 
-	rtas_node = call_prom("open", 1, 1, ADDR("/rtas"));
-	prom_printf("...");
+	rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
+	if (!IHANDLE_VALID(rtas_inst)) {
+		prom_printf("opening rtas package failed");
+		return;
+	}
+
+	prom_printf("instantiating rtas at 0x%x ...", base);
 
 	if (call_prom("call-method", 3, 2,
 		      ADDR("instantiate-rtas"),
-		      rtas_node, base) != PROM_ERROR) {
+		      rtas_inst, base) != PROM_ERROR) {
 		entry = (long)_prom->args.rets[1];
 	}
 	if (entry == 0) {
@@ -738,8 +954,8 @@ static void __init prom_instantiate_rtas
 
 	reserve_mem(base, size);
 
-	prom_setprop(prom_rtas, "linux,rtas-base", &base, sizeof(base));
-	prom_setprop(prom_rtas, "linux,rtas-entry", &entry, sizeof(entry));
+	prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
+	prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
 
 	prom_debug("rtas base     = 0x%x\n", base);
 	prom_debug("rtas entry    = 0x%x\n", entry);
@@ -860,7 +1076,7 @@ static void __init prom_initialize_tce_t
 
 		prom_printf("opening PHB %s", path);
 		phb_node = call_prom("open", 1, 1, path);
-		if ( (long)phb_node <= 0)
+		if (phb_node == 0)
 			prom_printf("... failed\n");
 		else
 			prom_printf("... done\n");
@@ -873,6 +1089,16 @@ static void __init prom_initialize_tce_t
 
 	reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
 
+	if (RELOC(prom_memory_limit)) {
+		/*
+		 * We align the start to a 16MB boundary so we can map the TCE area
+		 * using large pages if possible. The end should be the top of RAM
+		 * so no need to align it.
+		 */
+		RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, 0x1000000);
+		RELOC(prom_tce_alloc_end) = local_alloc_top;
+	}
+
 	/* Flag the first invalid entry */
 	prom_debug("ending prom_initialize_tce_table\n");
 }
@@ -1067,12 +1293,12 @@ static void __init prom_init_client_serv
 
 	/* get a handle for the stdout device */
 	_prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
-	if ((long)_prom->chosen <= 0)
+	if (!PHANDLE_VALID(_prom->chosen))
 		prom_panic("cannot find chosen"); /* msg won't be printed :( */
 
 	/* get device tree root */
 	_prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
-	if ((long)_prom->root <= 0)
+	if (!PHANDLE_VALID(_prom->root))
 		prom_panic("cannot find device tree root"); /* msg won't be printed :( */
 }
 
@@ -1144,9 +1370,8 @@ static int __init prom_find_machine_type
 	}
 	/* Default to pSeries. We need to know if we are running LPAR */
 	rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
-	if (rtas != (phandle) -1) {
-		unsigned long x;
-		x = prom_getproplen(rtas, "ibm,hypertas-functions");
+	if (PHANDLE_VALID(rtas)) {
+		int x = prom_getproplen(rtas, "ibm,hypertas-functions");
 		if (x != PROM_ERROR) {
 			prom_printf("Hypertas detected, assuming LPAR !\n");
 			return PLATFORM_PSERIES_LPAR;
@@ -1214,12 +1439,13 @@ static void __init prom_check_displays(v
 		 * leave some room at the end of the path for appending extra
 		 * arguments
 		 */
-		if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0)
+		if (call_prom("package-to-path", 3, 1, node, path,
+			      PROM_SCRATCH_SIZE-10) == PROM_ERROR)
 			continue;
 		prom_printf("found display   : %s, opening ... ", path);
 		
 		ih = call_prom("open", 1, 1, path);
-		if (ih == (ihandle)0 || ih == (ihandle)-1) {
+		if (ih == 0) {
 			prom_printf("failed\n");
 			continue;
 		}
@@ -1302,6 +1528,12 @@ static unsigned long __init dt_find_stri
 	return 0;
 }
 
+/*
+ * The Open Firmware 1275 specification states properties must be 31 bytes or
+ * less, however not all firmwares obey this. Make it 64 bytes to be safe.
+ */
+#define MAX_PROPERTY_NAME 64
+
 static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
 					 unsigned long *mem_end)
 {
@@ -1315,10 +1547,12 @@ static void __init scan_dt_build_strings
 	/* get and store all property names */
 	prev_name = RELOC("");
 	for (;;) {
-		
-		/* 32 is max len of name including nul. */
-		namep = make_room(mem_start, mem_end, 32, 1);
-		if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) {
+		int rc;
+
+		/* 64 is max len of name including nul. */
+		namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
+		rc = call_prom("nextprop", 3, 1, node, prev_name, namep);
+		if (rc != 1) {
 			/* No more nodes: unwind alloc */
 			*mem_start = (unsigned long)namep;
 			break;
@@ -1348,11 +1582,11 @@ static void __init scan_dt_build_struct(
 {
 	int l, align;
 	phandle child;
-	char *namep, *prev_name, *sstart;
+	char *namep, *prev_name, *sstart, *p, *ep;
 	unsigned long soff;
 	unsigned char *valp;
 	unsigned long offset = reloc_offset();
-	char pname[32];
+	char pname[MAX_PROPERTY_NAME];
 	char *path;
 
 	path = RELOC(prom_scratch);
@@ -1370,6 +1604,14 @@ static void __init scan_dt_build_struct(
 			call_prom("package-to-path", 3, 1, node, namep, l);
 		}
 		namep[l] = '\0';
+		/* Fixup an Apple bug where they have bogus \0 chars in the
+		 * middle of the path in some properties
+		 */
+		for (p = namep, ep = namep + l; p < ep; p++)
+			if (*p == '\0') {
+				memmove(p, p+1, ep - p);
+				ep--; l--;
+			}
 		*mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
 	}
 
@@ -1381,7 +1623,10 @@ static void __init scan_dt_build_struct(
 	prev_name = RELOC("");
 	sstart = (char *)RELOC(dt_string_start);
 	for (;;) {
-		if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0)
+		int rc;
+
+		rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
+		if (rc != 1)
 			break;
 
 		/* find string offset */
@@ -1397,7 +1642,7 @@ static void __init scan_dt_build_struct(
 		l = call_prom("getproplen", 2, 1, node, pname);
 
 		/* sanity checks */
-		if (l < 0)
+		if (l == PROM_ERROR)
 			continue;
 		if (l > MAX_PROPERTY_LENGTH) {
 			prom_printf("WARNING: ignoring large property ");
@@ -1532,7 +1777,45 @@ static void __init flatten_device_tree(v
 	prom_printf("Device tree struct  0x%x -> 0x%x\n",
 		    RELOC(dt_struct_start), RELOC(dt_struct_end));
 
- }
+}
+
+
+static void __init fixup_device_tree(void)
+{
+	unsigned long offset = reloc_offset();
+	phandle u3, i2c, mpic;
+	u32 u3_rev;
+	u32 interrupts[2];
+	u32 parent;
+
+	/* Some G5s have a missing interrupt definition, fix it up here */
+	u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
+	if (!PHANDLE_VALID(u3))
+		return;
+	i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
+	if (!PHANDLE_VALID(i2c))
+		return;
+	mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
+	if (!PHANDLE_VALID(mpic))
+		return;
+
+	/* check if proper rev of u3 */
+	if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
+	    == PROM_ERROR)
+		return;
+	if (u3_rev != 0x35)
+		return;
+	/* does it need fixup ? */
+	if (prom_getproplen(i2c, "interrupts") > 0)
+		return;
+	/* interrupt on this revision of u3 is number 0 and level */
+	interrupts[0] = 0;
+	interrupts[1] = 1;
+	prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
+	parent = (u32)mpic;
+	prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
+}
+
 
 static void __init prom_find_boot_cpu(void)
 {
@@ -1626,6 +1909,12 @@ unsigned long __init prom_init(unsigned 
 		     &getprop_rval, sizeof(getprop_rval));
 
 	/*
+	 * On pSeries, inform the firmware about our capabilities
+	 */
+	if (RELOC(of_platform) & PLATFORM_PSERIES)
+		prom_send_capabilities();
+
+	/*
 	 * On pSeries, copy the CPU hold code
 	 */
        	if (RELOC(of_platform) & PLATFORM_PSERIES)
@@ -1686,9 +1975,26 @@ unsigned long __init prom_init(unsigned 
 	 */
 	if (RELOC(ppc64_iommu_off))
 		prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
+
 	if (RELOC(iommu_force_on))
 		prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
 
+	if (RELOC(prom_memory_limit))
+		prom_setprop(_prom->chosen, "linux,memory-limit",
+			PTRRELOC(&prom_memory_limit), sizeof(RELOC(prom_memory_limit)));
+
+	if (RELOC(prom_tce_alloc_start)) {
+		prom_setprop(_prom->chosen, "linux,tce-alloc-start",
+			PTRRELOC(&prom_tce_alloc_start), sizeof(RELOC(prom_tce_alloc_start)));
+		prom_setprop(_prom->chosen, "linux,tce-alloc-end",
+			PTRRELOC(&prom_tce_alloc_end), sizeof(RELOC(prom_tce_alloc_end)));
+	}
+
+	/*
+	 * Fixup any known bugs in the device-tree
+	 */
+	fixup_device_tree();
+
 	/*
 	 * Now finally create the flattened device-tree
 	 */
diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c
--- a/arch/ppc64/kernel/ptrace.c
+++ b/arch/ppc64/kernel/ptrace.c
@@ -27,6 +27,8 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
+#include <linux/seccomp.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -161,7 +163,7 @@ int sys_ptrace(long request, long pid, l
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -193,7 +195,7 @@ int sys_ptrace(long request, long pid, l
 
 	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		set_single_step(child);
@@ -303,20 +305,27 @@ static void do_syscall_trace(void)
 
 void do_syscall_trace_enter(struct pt_regs *regs)
 {
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		do_syscall_trace();
+
 	if (unlikely(current->audit_context))
-		audit_syscall_entry(current, regs->gpr[0],
+		audit_syscall_entry(current,
+				    test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
+				    regs->gpr[0],
 				    regs->gpr[3], regs->gpr[4],
 				    regs->gpr[5], regs->gpr[6]);
 
-	if (test_thread_flag(TIF_SYSCALL_TRACE)
-	    && (current->ptrace & PT_PTRACED))
-		do_syscall_trace();
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)
 {
+	secure_computing(regs->gpr[0]);
+
 	if (unlikely(current->audit_context))
-		audit_syscall_exit(current, regs->result);
+		audit_syscall_exit(current, 
+				   (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
+				   regs->result);
 
 	if ((test_thread_flag(TIF_SYSCALL_TRACE)
 	     || test_thread_flag(TIF_SINGLESTEP))
diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c
--- a/arch/ppc64/kernel/ptrace32.c
+++ b/arch/ppc64/kernel/ptrace32.c
@@ -26,6 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -293,7 +294,7 @@ int sys32_ptrace(long request, long pid,
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -325,7 +326,7 @@ int sys32_ptrace(long request, long pid,
 
 	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		set_single_step(child);
diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c
+++ b/arch/ppc64/kernel/rtas.c
@@ -255,29 +255,59 @@ rtas_extended_busy_delay_time(int status
 	return ms; 
 }
 
-int
-rtas_get_power_level(int powerdomain, int *level)
+int rtas_error_rc(int rtas_rc)
+{
+	int rc;
+
+	switch (rtas_rc) {
+		case -1: 		/* Hardware Error */
+			rc = -EIO;
+			break;
+		case -3:		/* Bad indicator/domain/etc */
+			rc = -EINVAL;
+			break;
+		case -9000:		/* Isolation error */
+			rc = -EFAULT;
+			break;
+		case -9001:		/* Outstanding TCE/PTE */
+			rc = -EEXIST;
+			break;
+		case -9002:		/* No usable slot */
+			rc = -ENODEV;
+			break;
+		default:
+			printk(KERN_ERR "%s: unexpected RTAS error %d\n",
+					__FUNCTION__, rtas_rc);
+			rc = -ERANGE;
+			break;
+	}
+	return rc;
+}
+
+int rtas_get_power_level(int powerdomain, int *level)
 {
 	int token = rtas_token("get-power-level");
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
-		return RTAS_UNKNOWN_OP;
+		return -ENOENT;
 
 	while ((rc = rtas_call(token, 1, 2, level, powerdomain)) == RTAS_BUSY)
 		udelay(1);
+
+	if (rc < 0)
+		return rtas_error_rc(rc);
 	return rc;
 }
 
-int
-rtas_set_power_level(int powerdomain, int level, int *setlevel)
+int rtas_set_power_level(int powerdomain, int level, int *setlevel)
 {
 	int token = rtas_token("set-power-level");
 	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
-		return RTAS_UNKNOWN_OP;
+		return -ENOENT;
 
 	while (1) {
 		rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
@@ -289,18 +319,20 @@ rtas_set_power_level(int powerdomain, in
 		} else
 			break;
 	}
+
+	if (rc < 0)
+		return rtas_error_rc(rc);
 	return rc;
 }
 
-int
-rtas_get_sensor(int sensor, int index, int *state)
+int rtas_get_sensor(int sensor, int index, int *state)
 {
 	int token = rtas_token("get-sensor-state");
 	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
-		return RTAS_UNKNOWN_OP;
+		return -ENOENT;
 
 	while (1) {
 		rc = rtas_call(token, 2, 2, state, sensor, index);
@@ -312,18 +344,20 @@ rtas_get_sensor(int sensor, int index, i
 		} else
 			break;
 	}
+
+	if (rc < 0)
+		return rtas_error_rc(rc);
 	return rc;
 }
 
-int
-rtas_set_indicator(int indicator, int index, int new_value)
+int rtas_set_indicator(int indicator, int index, int new_value)
 {
 	int token = rtas_token("set-indicator");
 	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
-		return RTAS_UNKNOWN_OP;
+		return -ENOENT;
 
 	while (1) {
 		rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
@@ -337,6 +371,8 @@ rtas_set_indicator(int indicator, int in
 			break;
 	}
 
+	if (rc < 0)
+		return rtas_error_rc(rc);
 	return rc;
 }
 
diff --git a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c
--- a/arch/ppc64/kernel/rtas_flash.c
+++ b/arch/ppc64/kernel/rtas_flash.c
@@ -218,13 +218,12 @@ static void get_flash_status_msg(int sta
 }
 
 /* Reading the proc file will show status (not the firmware contents) */
-static ssize_t rtas_flash_read(struct file *file, char *buf,
+static ssize_t rtas_flash_read(struct file *file, char __user *buf,
 			       size_t count, loff_t *ppos)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 	struct rtas_update_flash_t *uf;
 	char msg[RTAS_MSG_MAXLEN];
-	int error;
 	int msglen;
 
 	uf = (struct rtas_update_flash_t *) dp->data;
@@ -241,8 +240,7 @@ static ssize_t rtas_flash_read(struct fi
 	if (ppos && *ppos != 0)
 		return 0;	/* be cheap */
 
-	error = verify_area(VERIFY_WRITE, buf, msglen);
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, msglen))
 		return -EINVAL;
 
 	if (copy_to_user(buf, msg, msglen))
@@ -258,7 +256,7 @@ static ssize_t rtas_flash_read(struct fi
  * 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,
+static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
 				size_t count, loff_t *off)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
@@ -358,14 +356,13 @@ static void manage_flash(struct rtas_man
 	args_buf->status = rc;
 }
 
-static ssize_t manage_flash_read(struct file *file, char *buf,
+static ssize_t manage_flash_read(struct file *file, char __user *buf,
 			       size_t count, loff_t *ppos)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 	struct rtas_manage_flash_t *args_buf;
 	char msg[RTAS_MSG_MAXLEN];
 	int msglen;
-	int error;
 
 	args_buf = (struct rtas_manage_flash_t *) dp->data;
 	if (args_buf == NULL)
@@ -378,8 +375,7 @@ static ssize_t manage_flash_read(struct 
 	if (ppos && *ppos != 0)
 		return 0;	/* be cheap */
 
-	error = verify_area(VERIFY_WRITE, buf, msglen);
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, msglen))
 		return -EINVAL;
 
 	if (copy_to_user(buf, msg, msglen))
@@ -390,7 +386,7 @@ static ssize_t manage_flash_read(struct 
 	return msglen;
 }
 
-static ssize_t manage_flash_write(struct file *file, const char *buf,
+static ssize_t manage_flash_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *off)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
@@ -470,14 +466,13 @@ static int get_validate_flash_msg(struct
 	return n;
 }
 
-static ssize_t validate_flash_read(struct file *file, char *buf,
+static ssize_t validate_flash_read(struct file *file, char __user *buf,
 			       size_t count, loff_t *ppos)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 	struct rtas_validate_flash_t *args_buf;
 	char msg[RTAS_MSG_MAXLEN];
 	int msglen;
-	int error;
 
 	args_buf = (struct rtas_validate_flash_t *) dp->data;
 
@@ -488,8 +483,7 @@ static ssize_t validate_flash_read(struc
 	if (msglen > count)
 		msglen = count;
 
-	error = verify_area(VERIFY_WRITE, buf, msglen);
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, msglen))
 		return -EINVAL;
 
 	if (copy_to_user(buf, msg, msglen))
@@ -500,7 +494,7 @@ static ssize_t validate_flash_read(struc
 	return msglen;
 }
 
-static ssize_t validate_flash_write(struct file *file, const char *buf,
+static ssize_t validate_flash_write(struct file *file, const char __user *buf,
 				    size_t count, loff_t *off)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
@@ -531,7 +525,7 @@ static ssize_t validate_flash_write(stru
 		args_buf->status = VALIDATE_INCOMPLETE;
 	}
 
-	if (verify_area(VERIFY_READ, buf, count)) {
+	if (!access_ok(VERIFY_READ, buf, count)) {
 		rc = -EFAULT;
 		goto done;
 	}
diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
--- a/arch/ppc64/kernel/rtasd.c
+++ b/arch/ppc64/kernel/rtasd.c
@@ -289,8 +289,7 @@ static ssize_t rtas_log_read(struct file
 
 	count = rtas_error_log_buffer_max;
 
-	error = verify_area(VERIFY_WRITE, buf, count);
-	if (error)
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 
 	tmp = kmalloc(count, GFP_KERNEL);
@@ -347,7 +346,7 @@ static int enable_surveillance(int timeo
 	if (error == 0)
 		return 0;
 
-	if (error == RTAS_NO_SUCH_INDICATOR) {
+	if (error == -EINVAL) {
 		printk(KERN_INFO "rtasd: surveillance not supported\n");
 		return 0;
 	}
@@ -400,10 +399,33 @@ static void do_event_scan(int event_scan
 	} while(error == 0);
 }
 
+static void do_event_scan_all_cpus(long delay)
+{
+	int cpu;
+
+	lock_cpu_hotplug();
+	cpu = first_cpu(cpu_online_map);
+	for (;;) {
+		set_cpus_allowed(current, cpumask_of_cpu(cpu));
+		do_event_scan(rtas_token("event-scan"));
+		set_cpus_allowed(current, CPU_MASK_ALL);
+
+		/* Drop hotplug lock, and sleep for the specified delay */
+		unlock_cpu_hotplug();
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(delay);
+		lock_cpu_hotplug();
+
+		cpu = next_cpu(cpu, cpu_online_map);
+		if (cpu == NR_CPUS)
+			break;
+	}
+	unlock_cpu_hotplug();
+}
+
 static int rtasd(void *unused)
 {
 	unsigned int err_type;
-	int cpu = 0;
 	int event_scan = rtas_token("event-scan");
 	int rc;
 
@@ -437,17 +459,7 @@ static int rtasd(void *unused)
 	}
 
 	/* First pass. */
-	lock_cpu_hotplug();
-	for_each_online_cpu(cpu) {
-		DEBUG("scheduling on %d\n", cpu);
-		set_cpus_allowed(current, cpumask_of_cpu(cpu));
-		DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id());
-
-		do_event_scan(event_scan);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ);
-	}
-	unlock_cpu_hotplug();
+	do_event_scan_all_cpus(HZ);
 
 	if (surveillance_timeout != -1) {
 		DEBUG("enabling surveillance\n");
@@ -455,25 +467,11 @@ static int rtasd(void *unused)
 		DEBUG("surveillance enabled\n");
 	}
 
-	lock_cpu_hotplug();
-	cpu = first_cpu(cpu_online_map);
-	for (;;) {
-		set_cpus_allowed(current, cpumask_of_cpu(cpu));
-		do_event_scan(event_scan);
-		set_cpus_allowed(current, CPU_MASK_ALL);
-
-		/* Drop hotplug lock, and sleep for a bit (at least
-		 * one second since some machines have problems if we
-		 * call event-scan too quickly). */
-		unlock_cpu_hotplug();
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout((HZ*60/rtas_event_scan_rate) / 2);
-		lock_cpu_hotplug();
-
-		cpu = next_cpu(cpu, cpu_online_map);
-		if (cpu == NR_CPUS)
-			cpu = first_cpu(cpu_online_map);
-	}
+	/* Delay should be at least one second since some
+	 * machines have problems if we call event-scan too
+	 * quickly. */
+	for (;;)
+		do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2);
 
 error:
 	/* Should delete proc entries */
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c
--- a/arch/ppc64/kernel/rtc.c
+++ b/arch/ppc64/kernel/rtc.c
@@ -292,52 +292,15 @@ int iSeries_set_rtc_time(struct rtc_time
 
 void iSeries_get_boot_time(struct rtc_time *tm)
 {
-	unsigned long time;
-	static unsigned long lastsec = 1;
-
-	u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
-	u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
-	int year = 1970;
-	int year1 = ( dataWord1 >> 24 ) & 0x000000FF;
-	int year2 = ( dataWord1 >> 16 ) & 0x000000FF;
-	int sec = ( dataWord1 >> 8 ) & 0x000000FF;
-	int min = dataWord1 & 0x000000FF;
-	int hour = ( dataWord2 >> 24 ) & 0x000000FF;
-	int day = ( dataWord2 >> 8 ) & 0x000000FF;
-	int mon = dataWord2 & 0x000000FF;
-
 	if ( piranha_simulator )
 		return;
 
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year1);
-	BCD_TO_BIN(year2);
-	year = year1 * 100 + year2;
-
-	time = mktime(year, mon, day, hour, min, sec);
-	time += ( jiffies / HZ );
-
-	/* Now THIS is a nasty hack!
-	* It ensures that the first two calls get different answers.  
-	* That way the loop in init_time (time.c) will not think
-	* the clock is stuck.
-	*/
-	if ( lastsec ) {
-		time -= lastsec;
-		--lastsec;
-	}
-
-	to_tm(time, tm); 
-	tm->tm_year -= 1900;
+	mf_get_boot_rtc(tm);
 	tm->tm_mon  -= 1;
 }
 #endif
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC_RTAS
 #define MAX_RTC_WAIT 5000	/* 5 sec */
 #define RTAS_CLOCK_BUSY (-2)
 void pSeries_get_boot_time(struct rtc_time *rtc_tm)
diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c
--- a/arch/ppc64/kernel/scanlog.c
+++ b/arch/ppc64/kernel/scanlog.c
@@ -43,7 +43,7 @@ static int scanlog_debug;
 static unsigned int ibm_scan_log_dump;			/* RTAS token */
 static struct proc_dir_entry *proc_ppc64_scan_log_dump;	/* The proc file */
 
-static ssize_t scanlog_read(struct file *file, char *buf,
+static ssize_t scanlog_read(struct file *file, char __user *buf,
 			    size_t count, loff_t *ppos)
 {
         struct inode * inode = file->f_dentry->d_inode;
@@ -73,7 +73,7 @@ static ssize_t scanlog_read(struct file 
 		return -EINVAL;
 	}
 
-	if (verify_area(VERIFY_WRITE, buf, count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 
 	for (;;) {
@@ -129,7 +129,7 @@ static ssize_t scanlog_read(struct file 
 	/*NOTREACHED*/
 }
 
-static ssize_t scanlog_write(struct file * file, const char * buf,
+static ssize_t scanlog_write(struct file * file, const char __user * buf,
 			     size_t count, loff_t *ppos)
 {
 	char stkbuf[20];
diff --git a/arch/ppc64/kernel/semaphore.c b/arch/ppc64/kernel/semaphore.c
--- a/arch/ppc64/kernel/semaphore.c
+++ b/arch/ppc64/kernel/semaphore.c
@@ -18,6 +18,8 @@
 
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/module.h>
+
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <asm/errno.h>
@@ -62,6 +64,7 @@ void __up(struct semaphore *sem)
 	__sem_update_count(sem, 1);
 	wake_up(&sem->wait);
 }
+EXPORT_SYMBOL(__up);
 
 /*
  * Note that when we come in to __down or __down_interruptible,
@@ -99,6 +102,7 @@ void __sched __down(struct semaphore *se
 	 */
 	wake_up(&sem->wait);
 }
+EXPORT_SYMBOL(__down);
 
 int __sched __down_interruptible(struct semaphore * sem)
 {
@@ -129,3 +133,4 @@ int __sched __down_interruptible(struct 
 	wake_up(&sem->wait);
 	return retval;
 }
+EXPORT_SYMBOL(__down_interruptible);
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -103,11 +103,6 @@ extern void unflatten_device_tree(void);
 
 extern void smp_release_cpus(void);
 
-unsigned long decr_overclock = 1;
-unsigned long decr_overclock_proc0 = 1;
-unsigned long decr_overclock_set = 0;
-unsigned long decr_overclock_proc0_set = 0;
-
 int have_of = 1;
 int boot_cpuid = 0;
 int boot_cpuid_phys = 0;
@@ -129,6 +124,7 @@ int ucache_bsize;
 /* The main machine-dep calls structure
  */
 struct machdep_calls ppc_md;
+EXPORT_SYMBOL(ppc_md);
 
 #ifdef CONFIG_MAGIC_SYSRQ
 unsigned long SYSRQ_KEY;
@@ -268,15 +264,9 @@ static void __init setup_cpu_maps(void)
 		nthreads = len / sizeof(u32);
 
 		for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
-			/*
-			 * Only spin up secondary threads if SMT is enabled.
-			 * We must leave space in the logical map for the
-			 * threads.
-			 */
-			if (j == 0 || smt_enabled_at_boot) {
-				cpu_set(cpu, cpu_present_map);
-				set_hard_smp_processor_id(cpu, intserv[j]);
-			}
+			cpu_set(cpu, cpu_present_map);
+			set_hard_smp_processor_id(cpu, intserv[j]);
+
 			if (intserv[j] == boot_cpuid_phys)
 				swap_cpuid = cpu;
 			cpu_set(cpu, cpu_possible_map);
@@ -315,7 +305,7 @@ static void __init setup_cpu_maps(void)
 		maxcpus = ireg[num_addr_cell + num_size_cell];
 
 		/* Double maxcpus for processors which have SMT capability */
-		if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+		if (cpu_has_feature(CPU_FTR_SMT))
 			maxcpus *= 2;
 
 		if (maxcpus > NR_CPUS) {
@@ -339,7 +329,7 @@ static void __init setup_cpu_maps(void)
 	 */
 	for_each_cpu(cpu) {
 		cpu_set(cpu, cpu_sibling_map[cpu]);
-		if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+		if (cpu_has_feature(CPU_FTR_SMT))
 			cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]);
 	}
 
@@ -604,12 +594,12 @@ void __init setup_system(void)
 	 */
 	initialize_cache_info();
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC_RTAS
 	/*
 	 * Initialize RTAS if available
 	 */
 	rtas_initialize();
-#endif /* CONFIG_PPC_PSERIES */
+#endif /* CONFIG_PPC_RTAS */
 
 	/*
 	 * Check if we have an initrd provided via the device-tree
@@ -641,12 +631,11 @@ void __init setup_system(void)
 	early_console_initialized = 1;
 	register_console(&udbg_console);
 
-#endif /* !CONFIG_PPC_ISERIES */
-
 	/* Save unparsed command line copy for /proc/cmdline */
 	strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
 
 	parse_early_param();
+#endif /* !CONFIG_PPC_ISERIES */
 
 #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)
 	/*
@@ -767,7 +756,7 @@ static int show_cpuinfo(struct seq_file 
 		seq_printf(m, "unknown (%08x)", pvr);
 
 #ifdef CONFIG_ALTIVEC
-	if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		seq_printf(m, ", altivec supported");
 #endif /* CONFIG_ALTIVEC */
 
@@ -805,20 +794,31 @@ struct seq_operations cpuinfo_op = {
 	.show =	show_cpuinfo,
 };
 
-#if 0 /* XXX not currently used */
+/*
+ * These three variables are used to save values passed to us by prom_init()
+ * via the device tree. The TCE variables are needed because with a memory_limit
+ * in force we may need to explicitly map the TCE are at the top of RAM.
+ */
 unsigned long memory_limit;
+unsigned long tce_alloc_start;
+unsigned long tce_alloc_end;
 
+#ifdef CONFIG_PPC_ISERIES
+/*
+ * On iSeries we just parse the mem=X option from the command line.
+ * On pSeries it's a bit more complicated, see prom_init_mem()
+ */
 static int __init early_parsemem(char *p)
 {
 	if (!p)
 		return 0;
 
-	memory_limit = memparse(p, &p);
+	memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE);
 
 	return 0;
 }
 early_param("mem", early_parsemem);
-#endif
+#endif /* CONFIG_PPC_ISERIES */
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
 static int __init set_preferred_console(void)
@@ -990,6 +990,34 @@ static void __init emergency_stack_init(
 }
 
 /*
+ * Called from setup_arch to initialize the bitmap of available
+ * syscalls in the systemcfg page
+ */
+void __init setup_syscall_map(void)
+{
+	unsigned int i, count64 = 0, count32 = 0;
+	extern unsigned long *sys_call_table;
+	extern unsigned long *sys_call_table32;
+	extern unsigned long sys_ni_syscall;
+
+
+	for (i = 0; i < __NR_syscalls; i++) {
+		if (sys_call_table[i] == sys_ni_syscall)
+			continue;
+		count64++;
+		systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f);
+	}
+	for (i = 0; i < __NR_syscalls; i++) {
+		if (sys_call_table32[i] == sys_ni_syscall)
+			continue;
+		count32++;
+		systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f);
+	}
+	printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n",
+	       count32, count64);
+}
+
+/*
  * Called into from start_kernel, after lock_kernel has been called.
  * Initializes bootmem, which is unsed to manage page allocation until
  * mem_init is called.
@@ -1027,6 +1055,9 @@ void __init setup_arch(char **cmdline_p)
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
 
+	/* initialize the syscall map in systemcfg */
+	setup_syscall_map();
+
 	ppc_md.setup_arch();
 
 	/* Select the correct idle loop for the platform. */
@@ -1084,64 +1115,15 @@ void ppc64_dump_msg(unsigned int src, co
 	printk("[dump]%04x %s\n", src, msg);
 }
 
-int set_spread_lpevents( char * str )
-{
-	/* The parameter is the number of processors to share in processing lp events */
-	unsigned long i;
-	unsigned long val = simple_strtoul( str, NULL, 0 );
-	if ( ( val > 0 ) && ( val <= NR_CPUS ) ) {
-		for ( i=1; i<val; ++i )
-			paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
-		printk("lpevent processing spread over %ld processors\n", val);
-	}
-	else
-		printk("invalid spreaqd_lpevents %ld\n", val);
-	return 1;
-}	
-
 /* This should only be called on processor 0 during calibrate decr */
 void setup_default_decr(void)
 {
 	struct paca_struct *lpaca = get_paca();
 
-	if ( decr_overclock_set && !decr_overclock_proc0_set )
-		decr_overclock_proc0 = decr_overclock;
-
-	lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;	
+	lpaca->default_decr = tb_ticks_per_jiffy;
 	lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
 }
 
-int set_decr_overclock_proc0( char * str )
-{
-	unsigned long val = simple_strtoul( str, NULL, 0 );
-	if ( ( val >= 1 ) && ( val <= 48 ) ) {
-		decr_overclock_proc0_set = 1;
-		decr_overclock_proc0 = val;
-		printk("proc 0 decrementer overclock factor of %ld\n", val);
-	}
-	else
-		printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
-	return 1;
-}
-
-int set_decr_overclock( char * str )
-{
-	unsigned long val = simple_strtoul( str, NULL, 0 );
-	if ( ( val >= 1 ) && ( val <= 48 ) ) {
-		decr_overclock_set = 1;
-		decr_overclock = val;
-		printk("decrementer overclock factor of %ld\n", val);
-	}
-	else
-		printk("invalid decrementer overclock factor of %ld\n", val);
-	return 1;
-
-}
-
-__setup("spread_lpevents=", set_spread_lpevents );
-__setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
-__setup("decr_overclock=", set_decr_overclock );
-
 #ifndef CONFIG_PPC_ISERIES
 /*
  * This function can be used by platforms to "find" legacy serial ports.
@@ -1335,6 +1317,12 @@ EXPORT_SYMBOL(check_legacy_ioport);
 static int __init early_xmon(char *p)
 {
 	/* ensure xmon is enabled */
+	if (p) {
+		if (strncmp(p, "on", 2) == 0)
+			xmon_init();
+		if (strncmp(p, "early", 5) != 0)
+			return 0;
+	}
 	xmon_init();
 	debugger(NULL);
 
@@ -1345,9 +1333,6 @@ early_param("xmon", early_xmon);
 
 void cpu_die(void)
 {
-	idle_task_exit();
 	if (ppc_md.cpu_die)
 		ppc_md.cpu_die();
-	local_irq_disable();
-	for (;;);
 }
diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c
+++ b/arch/ppc64/kernel/signal.c
@@ -27,6 +27,8 @@
 #include <linux/stddef.h>
 #include <linux/elf.h>
 #include <linux/ptrace.h>
+#include <linux/module.h>
+
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -34,16 +36,13 @@
 #include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
+#include <asm/vdso.h>
 
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define GP_REGS_SIZE	min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 #define FP_REGS_SIZE	sizeof(elf_fpregset_t)
 
 #define TRAMP_TRACEBACK	3
@@ -313,7 +312,7 @@ int sys_swapcontext(struct ucontext __us
 		return -EINVAL;
 
 	if (old_ctx != NULL) {
-		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
+		if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
 		    || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0)
 		    || __copy_to_user(&old_ctx->uc_sigmask,
 				      &current->blocked, sizeof(sigset_t)))
@@ -321,7 +320,7 @@ int sys_swapcontext(struct ucontext __us
 	}
 	if (new_ctx == NULL)
 		return 0;
-	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))
+	if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx))
 	    || __get_user(tmp, (u8 __user *) new_ctx)
 	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))
 		return -EFAULT;
@@ -331,7 +330,7 @@ int sys_swapcontext(struct ucontext __us
 	 * image of the user's registers, we can't just return -EFAULT
 	 * because the user's registers will be corrupted.  For instance
 	 * the NIP value may have been updated but not some of the
-	 * other registers.  Given that we have done the verify_area
+	 * other registers.  Given that we have done the access_ok
 	 * and successfully read the first and last bytes of the region
 	 * above, this should only happen in an out-of-memory situation
 	 * or if another thread unmaps the region containing the context.
@@ -363,7 +362,7 @@ int sys_rt_sigreturn(unsigned long r3, u
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-	if (verify_area(VERIFY_READ, uc, sizeof(*uc)))
+	if (!access_ok(VERIFY_READ, uc, sizeof(*uc)))
 		goto badframe;
 
 	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
@@ -403,7 +402,7 @@ static int setup_rt_frame(int signr, str
 
 	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 
 	err |= __put_user(&frame->info, &frame->pinfo);
@@ -426,10 +425,14 @@ static int setup_rt_frame(int signr, str
 		goto badframe;
 
 	/* Set up to return from userspace. */
-	err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
-	if (err)
-		goto badframe;
-
+	if (vdso64_rt_sigtramp && current->thread.vdso_base) {
+		regs->link = current->thread.vdso_base + vdso64_rt_sigtramp;
+	} else {
+		err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
+		if (err)
+			goto badframe;
+		regs->link = (unsigned long) &frame->tramp[0];
+	}
 	funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;
 
 	/* Allocate a dummy caller frame for the signal handler. */
@@ -438,7 +441,6 @@ static int setup_rt_frame(int signr, str
 
 	/* Set up "regs" so we "return" to the signal handler. */
 	err |= get_user(regs->nip, &funct_desc_ptr->entry);
-	regs->link = (unsigned long) &frame->tramp[0];
 	regs->gpr[1] = newsp;
 	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
 	regs->gpr[3] = signr;
@@ -566,6 +568,4 @@ int do_signal(sigset_t *oldset, struct p
 
 	return 0;
 }
-
-
-
+EXPORT_SYMBOL(do_signal);
diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c
+++ b/arch/ppc64/kernel/signal32.c
@@ -31,6 +31,7 @@
 #include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
+#include <asm/vdso.h>
 
 #define DEBUG_SIG 0
 
@@ -637,7 +638,7 @@ static int handle_rt_signal32(unsigned l
 	/* create a stack frame for the caller of the handler */
 	newsp -= __SIGNAL_FRAMESIZE32 + 16;
 
-	if (verify_area(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
+	if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
 		goto badframe;
 
 	compat_from_sigset(&c_oldset, oldset);
@@ -656,18 +657,24 @@ static int handle_rt_signal32(unsigned l
 
 	/* Save user registers on the stack */
 	frame = &rt_sf->uc.uc_mcontext;
-	if (save_user_regs(regs, frame, __NR_rt_sigreturn))
+	if (put_user(regs->gpr[1], (u32 __user *)newsp))
 		goto badframe;
 
-	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))
-		goto badframe;
+	if (vdso32_rt_sigtramp && current->thread.vdso_base) {
+		if (save_user_regs(regs, frame, 0))
+			goto badframe;
+		regs->link = current->thread.vdso_base + vdso32_rt_sigtramp;
+	} else {
+		if (save_user_regs(regs, frame, __NR_rt_sigreturn))
+			goto badframe;
+		regs->link = (unsigned long) frame->tramp;
+	}
 	regs->gpr[1] = (unsigned long) newsp;
 	regs->gpr[3] = sig;
 	regs->gpr[4] = (unsigned long) &rt_sf->info;
 	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
 	regs->nip = (unsigned long) ka->sa.sa_handler;
-	regs->link = (unsigned long) frame->tramp;
 	regs->trap = 0;
 	regs->result = 0;
 
@@ -721,7 +728,7 @@ long sys32_swapcontext(struct ucontext32
 
 	if (old_ctx != NULL) {
 		compat_from_sigset(&c_set, &current->blocked);
-		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
+		if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
 		    || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
 		    || __copy_to_user(&old_ctx->uc_sigmask, &c_set, sizeof(c_set))
 		    || __put_user((u32)(u64)&old_ctx->uc_mcontext, &old_ctx->uc_regs))
@@ -729,7 +736,7 @@ long sys32_swapcontext(struct ucontext32
 	}
 	if (new_ctx == NULL)
 		return 0;
-	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))
+	if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx))
 	    || __get_user(tmp, (u8 __user *) new_ctx)
 	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))
 		return -EFAULT;
@@ -739,7 +746,7 @@ long sys32_swapcontext(struct ucontext32
 	 * image of the user's registers, we can't just return -EFAULT
 	 * because the user's registers will be corrupted.  For instance
 	 * the NIP value may have been updated but not some of the
-	 * other registers.  Given that we have done the verify_area
+	 * other registers.  Given that we have done the access_ok
 	 * and successfully read the first and last bytes of the region
 	 * above, this should only happen in an out-of-memory situation
 	 * or if another thread unmaps the region containing the context.
@@ -763,7 +770,7 @@ long sys32_rt_sigreturn(int r3, int r4, 
 
 	rt_sf = (struct rt_sigframe32 __user *)
 		(regs->gpr[1] + __SIGNAL_FRAMESIZE32 + 16);
-	if (verify_area(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
+	if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
 		goto bad;
 	if (do_setcontext32(&rt_sf->uc, regs, 1))
 		goto bad;
@@ -812,7 +819,7 @@ static int handle_signal32(unsigned long
 	/* create a stack frame for the caller of the handler */
 	newsp -= __SIGNAL_FRAMESIZE32;
 
-	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+	if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
 		goto badframe;
 
 #if _NSIG != 64
@@ -825,16 +832,22 @@ static int handle_signal32(unsigned long
 	    || __put_user(sig, &sc->signal))
 		goto badframe;
 
-	if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
-		goto badframe;
+	if (vdso32_sigtramp && current->thread.vdso_base) {
+		if (save_user_regs(regs, &frame->mctx, 0))
+			goto badframe;
+		regs->link = current->thread.vdso_base + vdso32_sigtramp;
+	} else {
+		if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
+			goto badframe;
+		regs->link = (unsigned long) frame->mctx.tramp;
+	}
 
-	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))
+	if (put_user(regs->gpr[1], (u32 __user *)newsp))
 		goto badframe;
 	regs->gpr[1] = (unsigned long) newsp;
 	regs->gpr[3] = sig;
 	regs->gpr[4] = (unsigned long) sc;
 	regs->nip = (unsigned long) ka->sa.sa_handler;
-	regs->link = (unsigned long) frame->mctx.tramp;
 	regs->trap = 0;
 	regs->result = 0;
 
@@ -879,7 +892,7 @@ long sys32_sigreturn(int r3, int r4, int
 	restore_sigmask(&set);
 
 	sr = (struct mcontext32 __user *)(u64)sigctx.regs;
-	if (verify_area(VERIFY_READ, sr, sizeof(*sr))
+	if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
 	    || restore_user_regs(regs, sr, 1))
 		goto badframe;
 
diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c
+++ b/arch/ppc64/kernel/smp.c
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -53,8 +54,6 @@
 #define DBG(fmt...)
 #endif
 
-int smp_threads_ready;
-
 cpumask_t cpu_possible_map = CPU_MASK_NONE;
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
@@ -126,7 +125,7 @@ void __devinit smp_generic_kick_cpu(int 
 	 * the processor will continue on to secondary_start
 	 */
 	paca[nr].cpu_start = 1;
-	mb();
+	smp_mb();
 }
 
 #endif /* CONFIG_PPC_MULTIPLATFORM */
@@ -257,7 +256,7 @@ int smp_call_function (void (*func) (voi
 	}
 
 	call_data = &data;
-	wmb();
+	smp_wmb();
 	/* Send a message to all other CPUs and wait for them to respond */
 	smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION);
 
@@ -335,7 +334,6 @@ void smp_call_function_interrupt(void)
 	}
 }
 
-extern unsigned long decr_overclock;
 extern struct gettimeofday_struct do_gtod;
 
 struct thread_info *current_set[NR_CPUS];
@@ -383,7 +381,7 @@ void __init smp_prepare_cpus(unsigned in
 	 * For now we leave it which means the time can be some
 	 * number of msecs off until someone does a settimeofday()
 	 */
-	do_gtod.tb_orig_stamp = tb_last_stamp;
+	do_gtod.varp->tb_orig_stamp = tb_last_stamp;
 	systemcfg->tb_orig_stamp = tb_last_stamp;
 #endif
 
@@ -406,17 +404,95 @@ void __devinit smp_prepare_boot_cpu(void
 	current_set[boot_cpuid] = current->thread_info;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* State of each CPU during hotplug phases */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
+int generic_cpu_disable(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	if (cpu == boot_cpuid)
+		return -EBUSY;
+
+	systemcfg->processorCount--;
+	cpu_clear(cpu, cpu_online_map);
+	fixup_irqs(cpu_online_map);
+	return 0;
+}
+
+int generic_cpu_enable(unsigned int cpu)
+{
+	/* Do the normal bootup if we haven't
+	 * already bootstrapped. */
+	if (system_state != SYSTEM_RUNNING)
+		return -ENOSYS;
+
+	/* get the target out of it's holding state */
+	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+	smp_wmb();
+
+	while (!cpu_online(cpu))
+		cpu_relax();
+
+	fixup_irqs(cpu_online_map);
+	/* counter the irq disable in fixup_irqs */
+	local_irq_enable();
+	return 0;
+}
+
+void generic_cpu_die(unsigned int cpu)
+{
+	int i;
+
+	for (i = 0; i < 100; i++) {
+		smp_rmb();
+		if (per_cpu(cpu_state, cpu) == CPU_DEAD)
+			return;
+		msleep(100);
+	}
+	printk(KERN_ERR "CPU%d didn't die...\n", cpu);
+}
+
+void generic_mach_cpu_die(void)
+{
+	unsigned int cpu;
+
+	local_irq_disable();
+	cpu = smp_processor_id();
+	printk(KERN_DEBUG "CPU%d offline\n", cpu);
+	__get_cpu_var(cpu_state) = CPU_DEAD;
+	smp_wmb();
+	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
+		cpu_relax();
+
+	flush_tlb_pending();
+	cpu_set(cpu, cpu_online_map);
+	local_irq_enable();
+}
+#endif
+
+static int __devinit cpu_enable(unsigned int cpu)
+{
+	if (smp_ops->cpu_enable)
+		return smp_ops->cpu_enable(cpu);
+
+	return -ENOSYS;
+}
+
 int __devinit __cpu_up(unsigned int cpu)
 {
 	int c;
 
-	/* At boot, don't bother with non-present cpus -JSCHOPP */
-	if (system_state < SYSTEM_RUNNING && !cpu_present(cpu))
-		return -ENOENT;
+	if (!cpu_enable(cpu))
+		return 0;
+
+	if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
+		return -EINVAL;
 
-	paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock;
+	paca[cpu].default_decr = tb_ticks_per_jiffy;
 
-	if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) {
+	if (!cpu_has_feature(CPU_FTR_SLB)) {
 		void *tmp;
 
 		/* maximum of 48 CPUs on machines with a segment table */
@@ -438,7 +514,7 @@ int __devinit __cpu_up(unsigned int cpu)
 	 * be written out to main store before we release
 	 * the processor.
 	 */
-	mb();
+	smp_mb();
 
 	/* wake up cpus */
 	DBG("smp: kicking cpu %d\n", cpu);
@@ -526,14 +602,6 @@ void __init smp_cpus_done(unsigned int m
 	smp_ops->setup_cpu(boot_cpuid);
 
 	set_cpus_allowed(current, old_mask);
-
-	/*
-	 * We know at boot the maximum number of cpus we can add to
-	 * a partition and set cpu_possible_map accordingly. cpu_present_map
-	 * needs to match for the hotplug code to allow us to hot add
-	 * any offline cpus.
-	 */
-	cpu_present_map = cpu_possible_map;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -241,7 +241,7 @@ int cp_compat_stat(struct kstat *stat, s
 	    !new_valid_dev(stat->rdev))
 		return -EOVERFLOW;
 
-	err  = verify_area(VERIFY_WRITE, statbuf, sizeof(*statbuf));
+	err  = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
 	err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
 	err |= __put_user(stat->ino, &statbuf->st_ino);
 	err |= __put_user(stat->mode, &statbuf->st_mode);
@@ -504,11 +504,11 @@ long sys32_ipc(u32 call, u32 first, u32 
 	switch (call) {
 
 	case SEMTIMEDOP:
-		if (third)
+		if (fifth)
 			/* sign extend semid */
 			return compat_sys_semtimedop((int)first,
 						     compat_ptr(ptr), second,
-						     compat_ptr(third));
+						     compat_ptr(fifth));
 		/* else fall through for normal semop() */
 	case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
@@ -791,31 +791,6 @@ asmlinkage int sys32_pciconfig_iobase(u3
 }
 
 
-asmlinkage int ppc64_newuname(struct new_utsname __user * name)
-{
-	int errno = sys_newuname(name);
-
-	if (current->personality == PER_LINUX32 && !errno) {
-		if(copy_to_user(name->machine, "ppc\0\0", 8)) {
-			errno = -EFAULT;
-		}
-	}
-	return errno;
-}
-
-asmlinkage int ppc64_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;
-}
-
-
-
 /* Note: it is necessary to treat mode 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)
@@ -1158,26 +1133,47 @@ asmlinkage long sys32_sysctl(struct __sy
 }
 #endif
 
+asmlinkage int sys32_uname(struct old_utsname __user * name)
+{
+	int err = 0;
+	
+	down_read(&uts_sem);
+	if (copy_to_user(name, &system_utsname, sizeof(*name)))
+		err = -EFAULT;
+	up_read(&uts_sem);
+	if (!err && personality(current->personality) == PER_LINUX32) {
+		/* change "ppc64" to "ppc" */
+		if (__put_user(0, name->machine + 3)
+		    || __put_user(0, name->machine + 4))
+			err = -EFAULT;
+	}
+	return err;
+}
+
 asmlinkage int sys32_olduname(struct oldold_utsname __user * 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);
-	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	error -= __put_user(0,name->release+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	error -= __put_user(0,name->version+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	error = __put_user(0,name->machine+__OLD_UTS_LEN);
+	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error |= __put_user(0,name->release+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error |= __put_user(0,name->version+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+	if (personality(current->personality) == PER_LINUX32) {
+		/* change "ppc64" to "ppc" */
+		error |= __put_user(0, name->machine + 3);
+		error |= __put_user(0, name->machine + 4);
+	}
+	
 	up_read(&uts_sem);
 
 	error = error ? -EFAULT : 0;
@@ -1195,7 +1191,7 @@ unsigned long sys32_mmap2(unsigned long 
 
 int get_compat_timeval(struct timeval *tv, struct compat_timeval __user *ctv)
 {
-	return (verify_area(VERIFY_READ, ctv, sizeof(*ctv)) ||
+	return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
 		__get_user(tv->tv_sec, &ctv->tv_sec) ||
 		__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
 }
@@ -1290,14 +1286,7 @@ long ppc32_timer_create(clockid_t clock,
 	if (ev32 == NULL)
 		return sys_timer_create(clock, NULL, timer_id);
 
-	memset(&event, 0, sizeof(event));
-	if (!access_ok(VERIFY_READ, ev32, sizeof(struct compat_sigevent))
-	    || __get_user(event.sigev_value.sival_int,
-			  &ev32->sigev_value.sival_int)
-	    || __get_user(event.sigev_signo, &ev32->sigev_signo)
-	    || __get_user(event.sigev_notify, &ev32->sigev_notify)
-	    || __get_user(event.sigev_notify_thread_id,
-			  &ev32->sigev_notify_thread_id))
+	if (get_compat_sigevent(&event, ev32))
 		return -EFAULT;
 
 	if (!access_ok(VERIFY_WRITE, timer_id, sizeof(timer_t)))
diff --git a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c
+++ b/arch/ppc64/kernel/syscalls.c
@@ -199,24 +199,33 @@ out:
 	return ret;
 }
 
-static int __init set_fakeppc(char *str)
+long ppc64_personality(unsigned long personality)
 {
-	if (*str)
-		return 0;
-	init_task.personality = PER_LINUX32;
-	return 1;
+	long 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;
 }
-__setup("fakeppc", set_fakeppc);
 
-asmlinkage int sys_uname(struct old_utsname __user * name)
+long ppc64_newuname(struct new_utsname __user * name)
 {
-	int err = -EFAULT;
-	
+	int err = 0;
+
 	down_read(&uts_sem);
-	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
-		err = 0;
+	if (copy_to_user(name, &system_utsname, sizeof(*name)))
+		err = -EFAULT;
 	up_read(&uts_sem);
-	
+	if (!err && personality(current->personality) == PER_LINUX32) {
+		/* change ppc64 to ppc */
+		if (__put_user(0, name->machine + 3)
+		    || __put_user(0, name->machine + 4))
+			err = -EFAULT;
+	}
 	return err;
 }
 
@@ -256,6 +265,3 @@ void do_show_syscall_exit(unsigned long 
 {
 	printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id());
 }
-
-/* Only exists on P-series. */
-cond_syscall(ppc_rtas);
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -18,7 +18,7 @@
 #include <asm/systemcfg.h>
 #include <asm/paca.h>
 #include <asm/lppaca.h>
-
+#include <asm/machdep.h>
 
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
@@ -63,7 +63,7 @@ static int __init smt_setup(void)
 	unsigned int *val;
 	unsigned int cpu;
 
-	if (!cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (!cpu_has_feature(CPU_FTR_SMT))
 		return 1;
 
 	options = find_path_device("/options");
@@ -86,7 +86,7 @@ static int __init setup_smt_snooze_delay
 	unsigned int cpu;
 	int snooze;
 
-	if (!cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (!cpu_has_feature(CPU_FTR_SMT))
 		return 1;
 
 	smt_snooze_cmdline = 1;
@@ -113,7 +113,6 @@ void ppc64_enable_pmcs(void)
 #ifdef CONFIG_PPC_PSERIES
 	unsigned long set, reset;
 	int ret;
-	unsigned int ctrl;
 #endif /* CONFIG_PPC_PSERIES */
 
 	/* Only need to enable them once */
@@ -167,11 +166,8 @@ void ppc64_enable_pmcs(void)
 	 * On SMT machines we have to set the run latch in the ctrl register
 	 * in order to make PMC6 spin.
 	 */
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) {
-		ctrl = mfspr(CTRLF);
-		ctrl |= RUNLATCH;
-		mtspr(CTRLT, ctrl);
-	}
+	if (cpu_has_feature(CPU_FTR_SMT))
+		ppc64_runlatch_on();
 #endif /* CONFIG_PPC_PSERIES */
 }
 
@@ -266,7 +262,7 @@ static void register_cpu_online(unsigned
 	struct sys_device *s = &c->sysdev;
 
 #ifndef CONFIG_PPC_ISERIES
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (cpu_has_feature(CPU_FTR_SMT))
 		sysdev_create_file(s, &attr_smt_snooze_delay);
 #endif
 
@@ -275,7 +271,7 @@ static void register_cpu_online(unsigned
 	sysdev_create_file(s, &attr_mmcr0);
 	sysdev_create_file(s, &attr_mmcr1);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA)
+	if (cpu_has_feature(CPU_FTR_MMCRA))
 		sysdev_create_file(s, &attr_mmcra);
 
 	sysdev_create_file(s, &attr_pmc1);
@@ -285,12 +281,12 @@ static void register_cpu_online(unsigned
 	sysdev_create_file(s, &attr_pmc5);
 	sysdev_create_file(s, &attr_pmc6);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_PMC8) {
+	if (cpu_has_feature(CPU_FTR_PMC8)) {
 		sysdev_create_file(s, &attr_pmc7);
 		sysdev_create_file(s, &attr_pmc8);
 	}
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (cpu_has_feature(CPU_FTR_SMT))
 		sysdev_create_file(s, &attr_purr);
 }
 
@@ -303,7 +299,7 @@ static void unregister_cpu_online(unsign
 	BUG_ON(c->no_control);
 
 #ifndef CONFIG_PPC_ISERIES
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (cpu_has_feature(CPU_FTR_SMT))
 		sysdev_remove_file(s, &attr_smt_snooze_delay);
 #endif
 
@@ -312,7 +308,7 @@ static void unregister_cpu_online(unsign
 	sysdev_remove_file(s, &attr_mmcr0);
 	sysdev_remove_file(s, &attr_mmcr1);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA)
+	if (cpu_has_feature(CPU_FTR_MMCRA))
 		sysdev_remove_file(s, &attr_mmcra);
 
 	sysdev_remove_file(s, &attr_pmc1);
@@ -322,12 +318,12 @@ static void unregister_cpu_online(unsign
 	sysdev_remove_file(s, &attr_pmc5);
 	sysdev_remove_file(s, &attr_pmc6);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_PMC8) {
+	if (cpu_has_feature(CPU_FTR_PMC8)) {
 		sysdev_remove_file(s, &attr_pmc7);
 		sysdev_remove_file(s, &attr_pmc8);
 	}
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+	if (cpu_has_feature(CPU_FTR_SMT))
 		sysdev_remove_file(s, &attr_purr);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -413,9 +409,7 @@ static int __init topology_init(void)
 		 * CPU.  For instance, the boot cpu might never be valid
 		 * for hotplugging.
 		 */
-#ifdef CONFIG_HOTPLUG_CPU
-		if (systemcfg->platform != PLATFORM_PSERIES_LPAR)
-#endif
+		if (!ppc_md.cpu_die)
 			c->no_control = 1;
 
 		if (cpu_online(cpu) || (c->no_control == 0)) {
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -85,9 +85,8 @@ static unsigned long first_settimeofday 
 
 unsigned long tb_ticks_per_jiffy;
 unsigned long tb_ticks_per_usec = 100; /* sane default */
+EXPORT_SYMBOL(tb_ticks_per_usec);
 unsigned long tb_ticks_per_sec;
-unsigned long next_xtime_sync_tb;
-unsigned long xtime_sync_interval;
 unsigned long tb_to_xs;
 unsigned      tb_to_us;
 unsigned long processor_freq;
@@ -158,8 +157,8 @@ static inline void __do_gettimeofday(str
 	 * The conversion to microseconds at the end is done
 	 * without a divide (and in fact, without a multiply)
 	 */
-	tb_ticks = tb_val - do_gtod.tb_orig_stamp;
 	temp_varp = do_gtod.varp;
+	tb_ticks = tb_val - temp_varp->tb_orig_stamp;
 	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 );
@@ -185,17 +184,55 @@ static inline void timer_sync_xtime(unsi
 {
 	struct timeval my_tv;
 
-	if (cur_tb > next_xtime_sync_tb) {
-		next_xtime_sync_tb = cur_tb + xtime_sync_interval;
-		__do_gettimeofday(&my_tv, cur_tb);
-
-		if (xtime.tv_sec <= my_tv.tv_sec) {
-			xtime.tv_sec = my_tv.tv_sec;
-			xtime.tv_nsec = my_tv.tv_usec * 1000;
-		}
+	__do_gettimeofday(&my_tv, cur_tb);
+
+	if (xtime.tv_sec <= my_tv.tv_sec) {
+		xtime.tv_sec = my_tv.tv_sec;
+		xtime.tv_nsec = my_tv.tv_usec * 1000;
 	}
 }
 
+/*
+ * When the timebase - tb_orig_stamp gets too big, we do a manipulation
+ * between tb_orig_stamp and stamp_xsec. The goal here is to keep the
+ * difference tb - tb_orig_stamp small enough to always fit inside a
+ * 32 bits number. This is a requirement of our fast 32 bits userland
+ * implementation in the vdso. If we "miss" a call to this function
+ * (interrupt latency, CPU locked in a spinlock, ...) and we end up
+ * with a too big difference, then the vdso will fallback to calling
+ * the syscall
+ */
+static __inline__ void timer_recalc_offset(unsigned long cur_tb)
+{
+	struct gettimeofday_vars * temp_varp;
+	unsigned temp_idx;
+	unsigned long offset, new_stamp_xsec, new_tb_orig_stamp;
+
+	if (((cur_tb - do_gtod.varp->tb_orig_stamp) & 0x80000000u) == 0)
+		return;
+
+	temp_idx = (do_gtod.var_idx == 0);
+	temp_varp = &do_gtod.vars[temp_idx];
+
+	new_tb_orig_stamp = cur_tb;
+	offset = new_tb_orig_stamp - do_gtod.varp->tb_orig_stamp;
+	new_stamp_xsec = do_gtod.varp->stamp_xsec + mulhdu(offset, do_gtod.varp->tb_to_xs);
+
+	temp_varp->tb_to_xs = do_gtod.varp->tb_to_xs;
+	temp_varp->tb_orig_stamp = new_tb_orig_stamp;
+	temp_varp->stamp_xsec = new_stamp_xsec;
+	smp_mb();
+	do_gtod.varp = temp_varp;
+	do_gtod.var_idx = temp_idx;
+
+	++(systemcfg->tb_update_count);
+	smp_wmb();
+	systemcfg->tb_orig_stamp = new_tb_orig_stamp;
+	systemcfg->stamp_xsec = new_stamp_xsec;
+	smp_wmb();
+	++(systemcfg->tb_update_count);
+}
+
 #ifdef CONFIG_SMP
 unsigned long profile_pc(struct pt_regs *regs)
 {
@@ -288,9 +325,7 @@ int timer_interrupt(struct pt_regs * reg
 
 	irq_enter();
 
-#ifndef CONFIG_PPC_ISERIES
 	profile_tick(CPU_PROFILING, regs);
-#endif
 
 	lpaca->lppaca.int_dword.fields.decr_int = 0;
 
@@ -311,6 +346,7 @@ int timer_interrupt(struct pt_regs * reg
 		if (cpu == boot_cpuid) {
 			write_seqlock(&xtime_lock);
 			tb_last_stamp = lpaca->next_jiffy_update_tb;
+			timer_recalc_offset(lpaca->next_jiffy_update_tb);
 			do_timer(regs);
 			timer_sync_xtime(lpaca->next_jiffy_update_tb);
 			timer_check_rtc();
@@ -334,6 +370,14 @@ int timer_interrupt(struct pt_regs * reg
 	}
 #endif
 
+/* collect purr register values often, for accurate calculations */
+#if defined(CONFIG_PPC_PSERIES)
+	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+		struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
+		cu->current_tb = mfspr(SPRN_PURR);
+	}
+#endif
+
 	irq_exit();
 
 	return 1;
@@ -398,7 +442,9 @@ int do_settimeofday(struct timespec *tv)
 	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-do_gtod.varp->tb_orig_stamp),
+			     do_gtod.varp->tb_to_xs );
+
 	new_xsec = (new_nsec * XSEC_PER_SEC) / NSEC_PER_SEC;
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
@@ -411,7 +457,7 @@ int do_settimeofday(struct timespec *tv)
 		 * 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;
+		do_gtod.varp->tb_orig_stamp = tb_last_stamp;
 		systemcfg->stamp_xsec = new_xsec;
 		systemcfg->tb_orig_stamp = tb_last_stamp;
 	}
@@ -464,9 +510,10 @@ void __init time_init(void)
 	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->tb_orig_stamp = tb_last_stamp;
+	get_paca()->next_jiffy_update_tb = tb_last_stamp + tb_ticks_per_jiffy;
 	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;
@@ -477,9 +524,6 @@ void __init time_init(void)
 	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
 	systemcfg->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;
-
 	time_freq = 0;
 
 	xtime.tv_nsec = 0;
@@ -584,12 +628,12 @@ void ppc_adjtimex(void)
 	   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;
+	write_seqlock_irqsave( &xtime_lock, flags );
+	tb_ticks = get_tb() - do_gtod.varp->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_seqlock_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;
 
@@ -597,17 +641,13 @@ void ppc_adjtimex(void)
 	   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_idx = (do_gtod.var_idx == 0);
+	temp_varp = &do_gtod.vars[temp_idx];
+
 	temp_varp->tb_to_xs = new_tb_to_xs;
 	temp_varp->stamp_xsec = new_stamp_xsec;
-	mb();
+	temp_varp->tb_orig_stamp = do_gtod.varp->tb_orig_stamp;
+	smp_mb();
 	do_gtod.varp = temp_varp;
 	do_gtod.var_idx = temp_idx;
 
@@ -621,10 +661,10 @@ void ppc_adjtimex(void)
 	 * loops back and reads them again until this criteria is met.
 	 */
 	++(systemcfg->tb_update_count);
-	wmb();
+	smp_wmb();
 	systemcfg->tb_to_xs = new_tb_to_xs;
 	systemcfg->stamp_xsec = new_stamp_xsec;
-	wmb();
+	smp_wmb();
 	++(systemcfg->tb_update_count);
 
 	write_sequnlock_irqrestore( &xtime_lock, flags );
diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c
+++ b/arch/ppc64/kernel/traps.c
@@ -41,6 +41,7 @@
 #include <asm/rtas.h>
 #include <asm/systemcfg.h>
 #include <asm/machdep.h>
+#include <asm/pmc.h>
 
 #ifdef CONFIG_DEBUGGER
 int (*__debugger)(struct pt_regs *regs);
@@ -278,6 +279,9 @@ static void parse_fpe(struct pt_regs *re
  * fault.  Return zero on success.
  */
 
+#define INST_MFSPR_PVR		0x7c1f42a6
+#define INST_MFSPR_PVR_MASK	0xfc1fffff
+
 #define INST_DCBA		0x7c0005ec
 #define INST_DCBA_MASK		0x7c0007fe
 
@@ -296,6 +300,15 @@ static int emulate_instruction(struct pt
 	if (get_user(instword, (unsigned int __user *)(regs->nip)))
 		return -EFAULT;
 
+	/* Emulate the mfspr rD, PVR. */
+	if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
+		unsigned int rd;
+
+		rd = (instword >> 21) & 0x1f;
+		regs->gpr[rd] = mfspr(SPRN_PVR);
+		return 0;
+	}
+
 	/* Emulating the dcba insn is just a no-op.  */
 	if ((instword & INST_DCBA_MASK) == INST_DCBA) {
 		static int warned;
@@ -389,11 +402,6 @@ void program_check_exception(struct pt_r
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */
 		parse_fpe(regs);
-
-	} else if (regs->msr & 0x40000) {
-		/* Privileged instruction */
-		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
-
 	} else if (regs->msr & 0x20000) {
 		/* trap exception */
 
@@ -410,7 +418,7 @@ void program_check_exception(struct pt_r
 		_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
 
 	} else {
-		/* Illegal instruction; try to emulate it.  */
+		/* Privileged or illegal instruction; try to emulate it. */
 		switch (emulate_instruction(regs)) {
 		case 0:
 			regs->nip += 4;
@@ -422,7 +430,12 @@ void program_check_exception(struct pt_r
 			break;
 
 		default:
-			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+			if (regs->msr & 0x40000)
+				/* priveleged */
+				_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+			else
+				/* illegal */
+				_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 			break;
 		}
 	}
@@ -437,31 +450,18 @@ void kernel_fp_unavailable_exception(str
 
 void altivec_unavailable_exception(struct pt_regs *regs)
 {
-#ifndef CONFIG_ALTIVEC
 	if (user_mode(regs)) {
 		/* A user program has executed an altivec instruction,
 		   but this kernel doesn't support altivec. */
 		_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 		return;
 	}
-#endif
 	printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
 			  "%lx at %lx\n", regs->trap, regs->nip);
 	die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
-/* Ensure exceptions are disabled */
-static void dummy_perf(struct pt_regs *regs)
-{
-	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-
-	mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO);
-	mtspr(SPRN_MMCR0, mmcr0);
-}
-
-void (*perf_irq)(struct pt_regs *) = dummy_perf;
-
-EXPORT_SYMBOL(perf_irq);
+extern perf_irq_t perf_irq;
 
 void performance_monitor_exception(struct pt_regs *regs)
 {
diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso.c
@@ -0,0 +1,619 @@
+/*
+ *  linux/arch/ppc64/kernel/vdso.c
+ *
+ *    Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
+ *			 <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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/slab.h>
+#include <linux/user.h>
+#include <linux/elf.h>
+#include <linux/security.h>
+#include <linux/bootmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/sections.h>
+#include <asm/vdso.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+
+/*
+ * The vDSOs themselves are here
+ */
+extern char vdso64_start, vdso64_end;
+extern char vdso32_start, vdso32_end;
+
+static void *vdso64_kbase = &vdso64_start;
+static void *vdso32_kbase = &vdso32_start;
+
+unsigned int vdso64_pages;
+unsigned int vdso32_pages;
+
+/* Signal trampolines user addresses */
+
+unsigned long vdso64_rt_sigtramp;
+unsigned long vdso32_sigtramp;
+unsigned long vdso32_rt_sigtramp;
+
+/* Format of the patch table */
+struct vdso_patch_def
+{
+	u32		pvr_mask, pvr_value;
+	const char	*gen_name;
+	const char	*fix_name;
+};
+
+/* Table of functions to patch based on the CPU type/revision
+ *
+ * TODO: Improve by adding whole lists for each entry
+ */
+static struct vdso_patch_def vdso_patches[] = {
+	{
+		0xffff0000, 0x003a0000,		/* POWER5 */
+		"__kernel_sync_dicache", "__kernel_sync_dicache_p5"
+	},
+	{
+		0xffff0000, 0x003b0000,		/* POWER5 */
+		"__kernel_sync_dicache", "__kernel_sync_dicache_p5"
+	},
+};
+
+/*
+ * Some infos carried around for each of them during parsing at
+ * boot time.
+ */
+struct lib32_elfinfo
+{
+	Elf32_Ehdr	*hdr;		/* ptr to ELF */
+	Elf32_Sym	*dynsym;	/* ptr to .dynsym section */
+	unsigned long	dynsymsize;	/* size of .dynsym section */
+	char		*dynstr;	/* ptr to .dynstr section */
+	unsigned long	text;		/* offset of .text section in .so */
+};
+
+struct lib64_elfinfo
+{
+	Elf64_Ehdr	*hdr;
+	Elf64_Sym	*dynsym;
+	unsigned long	dynsymsize;
+	char		*dynstr;
+	unsigned long	text;
+};
+
+
+#ifdef __DEBUG
+static void dump_one_vdso_page(struct page *pg, struct page *upg)
+{
+	printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
+	       page_count(pg),
+	       pg->flags);
+	if (upg/* && pg != upg*/) {
+		printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) << PAGE_SHIFT),
+		       page_count(upg),
+		       upg->flags);
+	}
+	printk("\n");
+}
+
+static void dump_vdso_pages(struct vm_area_struct * vma)
+{
+	int i;
+
+	if (!vma || test_thread_flag(TIF_32BIT)) {
+		printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
+		for (i=0; i<vdso32_pages; i++) {
+			struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
+			struct page *upg = (vma && vma->vm_mm) ?
+				follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0)
+				: NULL;
+			dump_one_vdso_page(pg, upg);
+		}
+	}
+	if (!vma || !test_thread_flag(TIF_32BIT)) {
+		printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
+		for (i=0; i<vdso64_pages; i++) {
+			struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
+			struct page *upg = (vma && vma->vm_mm) ?
+				follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0)
+				: NULL;
+			dump_one_vdso_page(pg, upg);
+		}
+	}
+}
+#endif /* DEBUG */
+
+/*
+ * Keep a dummy vma_close for now, it will prevent VMA merging.
+ */
+static void vdso_vma_close(struct vm_area_struct * vma)
+{
+}
+
+/*
+ * Our nopage() function, maps in the actual vDSO kernel pages, they will
+ * be mapped read-only by do_no_page(), and eventually COW'ed, either
+ * right away for an initial write access, or by do_wp_page().
+ */
+static struct page * vdso_vma_nopage(struct vm_area_struct * vma,
+				     unsigned long address, int *type)
+{
+	unsigned long offset = address - vma->vm_start;
+	struct page *pg;
+	void *vbase = test_thread_flag(TIF_32BIT) ? vdso32_kbase : vdso64_kbase;
+
+	DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n",
+	    current->comm, address, offset);
+
+	if (address < vma->vm_start || address > vma->vm_end)
+		return NOPAGE_SIGBUS;
+
+	/*
+	 * Last page is systemcfg, special handling here, no get_page() a
+	 * this is a reserved page
+	 */
+	if ((vma->vm_end - address) <= PAGE_SIZE)
+		return virt_to_page(systemcfg);
+
+	pg = virt_to_page(vbase + offset);
+	get_page(pg);
+	DBG(" ->page count: %d\n", page_count(pg));
+
+	return pg;
+}
+
+static struct vm_operations_struct vdso_vmops = {
+	.close	= vdso_vma_close,
+	.nopage	= vdso_vma_nopage,
+};
+
+/*
+ * This is called from binfmt_elf, we create the special vma for the
+ * vDSO and insert it into the mm struct tree
+ */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long vdso_pages;
+	unsigned long vdso_base;
+
+	if (test_thread_flag(TIF_32BIT)) {
+		vdso_pages = vdso32_pages;
+		vdso_base = VDSO32_MBASE;
+	} else {
+		vdso_pages = vdso64_pages;
+		vdso_base = VDSO64_MBASE;
+	}
+
+	current->thread.vdso_base = 0;
+
+	/* vDSO has a problem and was disabled, just don't "enable" it for the
+	 * process
+	 */
+	if (vdso_pages == 0)
+		return 0;
+
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma == NULL)
+		return -ENOMEM;
+	if (security_vm_enough_memory(vdso_pages)) {
+		kmem_cache_free(vm_area_cachep, vma);
+		return -ENOMEM;
+	}
+	memset(vma, 0, sizeof(*vma));
+
+	/*
+	 * pick a base address for the vDSO in process space. We try to put it
+	 * at vdso_base which is the "natural" base for it, but we might fail
+	 * and end up putting it elsewhere.
+	 */
+	vdso_base = get_unmapped_area(NULL, vdso_base,
+				      vdso_pages << PAGE_SHIFT, 0, 0);
+	if (vdso_base & ~PAGE_MASK)
+		return (int)vdso_base;
+
+	current->thread.vdso_base = vdso_base;
+
+	vma->vm_mm = mm;
+	vma->vm_start = current->thread.vdso_base;
+
+	/*
+	 * the VMA size is one page more than the vDSO since systemcfg
+	 * is mapped in the last one
+	 */
+	vma->vm_end = vma->vm_start + ((vdso_pages + 1) << PAGE_SHIFT);
+
+	/*
+	 * our vma flags don't have VM_WRITE so by default, the process isn't allowed
+	 * to write those pages.
+	 * gdb can break that with ptrace interface, and thus trigger COW on those
+	 * pages but it's then your responsibility to never do that on the "data" page
+	 * of the vDSO or you'll stop getting kernel updates and your nice userland
+	 * gettimeofday will be totally dead. It's fine to use that for setting
+	 * breakpoints in the vDSO code pages though
+	 */
+	vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+	vma->vm_flags |= mm->def_flags;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+	vma->vm_ops = &vdso_vmops;
+
+	down_write(&mm->mmap_sem);
+	insert_vm_struct(mm, vma);
+	mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	up_write(&mm->mmap_sem);
+
+	return 0;
+}
+
+static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
+				  unsigned long *size)
+{
+	Elf32_Shdr *sechdrs;
+	unsigned int i;
+	char *secnames;
+
+	/* Grab section headers and strings so we can tell who is who */
+	sechdrs = (void *)ehdr + ehdr->e_shoff;
+	secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
+
+	/* Find the section they want */
+	for (i = 1; i < ehdr->e_shnum; i++) {
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
+			if (size)
+				*size = sechdrs[i].sh_size;
+			return (void *)ehdr + sechdrs[i].sh_offset;
+		}
+	}
+	*size = 0;
+	return NULL;
+}
+
+static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname,
+				  unsigned long *size)
+{
+	Elf64_Shdr *sechdrs;
+	unsigned int i;
+	char *secnames;
+
+	/* Grab section headers and strings so we can tell who is who */
+	sechdrs = (void *)ehdr + ehdr->e_shoff;
+	secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
+
+	/* Find the section they want */
+	for (i = 1; i < ehdr->e_shnum; i++) {
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
+			if (size)
+				*size = sechdrs[i].sh_size;
+			return (void *)ehdr + sechdrs[i].sh_offset;
+		}
+	}
+	if (size)
+		*size = 0;
+	return NULL;
+}
+
+static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib, const char *symname)
+{
+	unsigned int i;
+	char name[32], *c;
+
+	for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
+		if (lib->dynsym[i].st_name == 0)
+			continue;
+		strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32);
+		c = strchr(name, '@');
+		if (c)
+			*c = 0;
+		if (strcmp(symname, name) == 0)
+			return &lib->dynsym[i];
+	}
+	return NULL;
+}
+
+static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib, const char *symname)
+{
+	unsigned int i;
+	char name[32], *c;
+
+	for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) {
+		if (lib->dynsym[i].st_name == 0)
+			continue;
+		strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32);
+		c = strchr(name, '@');
+		if (c)
+			*c = 0;
+		if (strcmp(symname, name) == 0)
+			return &lib->dynsym[i];
+	}
+	return NULL;
+}
+
+/* Note that we assume the section is .text and the symbol is relative to
+ * the library base
+ */
+static unsigned long __init find_function32(struct lib32_elfinfo *lib, const char *symname)
+{
+	Elf32_Sym *sym = find_symbol32(lib, symname);
+
+	if (sym == NULL) {
+		printk(KERN_WARNING "vDSO32: function %s not found !\n", symname);
+		return 0;
+	}
+	return sym->st_value - VDSO32_LBASE;
+}
+
+/* Note that we assume the section is .text and the symbol is relative to
+ * the library base
+ */
+static unsigned long __init find_function64(struct lib64_elfinfo *lib, const char *symname)
+{
+	Elf64_Sym *sym = find_symbol64(lib, symname);
+
+	if (sym == NULL) {
+		printk(KERN_WARNING "vDSO64: function %s not found !\n", symname);
+		return 0;
+	}
+#ifdef VDS64_HAS_DESCRIPTORS
+	return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) - VDSO64_LBASE;
+#else
+	return sym->st_value - VDSO64_LBASE;
+#endif
+}
+
+
+static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
+					struct lib64_elfinfo *v64)
+{
+	void *sect;
+
+	/*
+	 * Locate symbol tables & text section
+	 */
+
+	v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize);
+	v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL);
+	if (v32->dynsym == NULL || v32->dynstr == NULL) {
+		printk(KERN_ERR "vDSO32: a required symbol section was not found\n");
+		return -1;
+	}
+	sect = find_section32(v32->hdr, ".text", NULL);
+	if (sect == NULL) {
+		printk(KERN_ERR "vDSO32: the .text section was not found\n");
+		return -1;
+	}
+	v32->text = sect - vdso32_kbase;
+
+	v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize);
+	v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL);
+	if (v64->dynsym == NULL || v64->dynstr == NULL) {
+		printk(KERN_ERR "vDSO64: a required symbol section was not found\n");
+		return -1;
+	}
+	sect = find_section64(v64->hdr, ".text", NULL);
+	if (sect == NULL) {
+		printk(KERN_ERR "vDSO64: the .text section was not found\n");
+		return -1;
+	}
+	v64->text = sect - vdso64_kbase;
+
+	return 0;
+}
+
+static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32,
+					  struct lib64_elfinfo *v64)
+{
+	/*
+	 * Find signal trampolines
+	 */
+
+	vdso64_rt_sigtramp	= find_function64(v64, "__kernel_sigtramp_rt64");
+	vdso32_sigtramp		= find_function32(v32, "__kernel_sigtramp32");
+	vdso32_rt_sigtramp	= find_function32(v32, "__kernel_sigtramp_rt32");
+}
+
+static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
+				       struct lib64_elfinfo *v64)
+{
+	Elf32_Sym *sym32;
+	Elf64_Sym *sym64;
+
+	sym32 = find_symbol32(v32, "__kernel_datapage_offset");
+	if (sym32 == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol __kernel_datapage_offset !\n");
+		return -1;
+	}
+	*((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) =
+		(vdso32_pages << PAGE_SHIFT) - (sym32->st_value - VDSO32_LBASE);
+
+       	sym64 = find_symbol64(v64, "__kernel_datapage_offset");
+	if (sym64 == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol __kernel_datapage_offset !\n");
+		return -1;
+	}
+	*((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) =
+		(vdso64_pages << PAGE_SHIFT) - (sym64->st_value - VDSO64_LBASE);
+
+	return 0;
+}
+
+static int vdso_do_func_patch32(struct lib32_elfinfo *v32,
+				struct lib64_elfinfo *v64,
+				const char *orig, const char *fix)
+{
+	Elf32_Sym *sym32_gen, *sym32_fix;
+
+	sym32_gen = find_symbol32(v32, orig);
+	if (sym32_gen == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig);
+		return -1;
+	}
+	sym32_fix = find_symbol32(v32, fix);
+	if (sym32_fix == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix);
+		return -1;
+	}
+	sym32_gen->st_value = sym32_fix->st_value;
+	sym32_gen->st_size = sym32_fix->st_size;
+	sym32_gen->st_info = sym32_fix->st_info;
+	sym32_gen->st_other = sym32_fix->st_other;
+	sym32_gen->st_shndx = sym32_fix->st_shndx;
+
+	return 0;
+}
+
+static int vdso_do_func_patch64(struct lib32_elfinfo *v32,
+				struct lib64_elfinfo *v64,
+				const char *orig, const char *fix)
+{
+	Elf64_Sym *sym64_gen, *sym64_fix;
+
+	sym64_gen = find_symbol64(v64, orig);
+	if (sym64_gen == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig);
+		return -1;
+	}
+	sym64_fix = find_symbol64(v64, fix);
+	if (sym64_fix == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix);
+		return -1;
+	}
+	sym64_gen->st_value = sym64_fix->st_value;
+	sym64_gen->st_size = sym64_fix->st_size;
+	sym64_gen->st_info = sym64_fix->st_info;
+	sym64_gen->st_other = sym64_fix->st_other;
+	sym64_gen->st_shndx = sym64_fix->st_shndx;
+
+	return 0;
+}
+
+static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
+				       struct lib64_elfinfo *v64)
+{
+	u32 pvr;
+	int i;
+
+	pvr = mfspr(SPRN_PVR);
+	for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) {
+		struct vdso_patch_def *patch = &vdso_patches[i];
+		int match = (pvr & patch->pvr_mask) == patch->pvr_value;
+
+		DBG("patch %d (mask: %x, pvr: %x) : %s\n",
+		    i, patch->pvr_mask, patch->pvr_value, match ? "match" : "skip");
+
+		if (!match)
+			continue;
+
+		DBG("replacing %s with %s...\n", patch->gen_name, patch->fix_name);
+
+		/*
+		 * Patch the 32 bits and 64 bits symbols. Note that we do not patch
+		 * the "." symbol on 64 bits. It would be easy to do, but doesn't
+		 * seem to be necessary, patching the OPD symbol is enough.
+		 */
+		vdso_do_func_patch32(v32, v64, patch->gen_name, patch->fix_name);
+		vdso_do_func_patch64(v32, v64, patch->gen_name, patch->fix_name);
+	}
+
+	return 0;
+}
+
+
+static __init int vdso_setup(void)
+{
+	struct lib32_elfinfo	v32;
+	struct lib64_elfinfo	v64;
+
+	v32.hdr = vdso32_kbase;
+	v64.hdr = vdso64_kbase;
+
+	if (vdso_do_find_sections(&v32, &v64))
+		return -1;
+
+	if (vdso_fixup_datapage(&v32, &v64))
+		return -1;
+
+	if (vdso_fixup_alt_funcs(&v32, &v64))
+		return -1;
+
+	vdso_setup_trampolines(&v32, &v64);
+
+	return 0;
+}
+
+void __init vdso_init(void)
+{
+	int i;
+
+	vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
+	vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT;
+
+	DBG("vdso64_kbase: %p, 0x%x pages, vdso32_kbase: %p, 0x%x pages\n",
+	       vdso64_kbase, vdso64_pages, vdso32_kbase, vdso32_pages);
+
+	/*
+	 * Initialize the vDSO images in memory, that is do necessary
+	 * fixups of vDSO symbols, locate trampolines, etc...
+	 */
+	if (vdso_setup()) {
+		printk(KERN_ERR "vDSO setup failure, not enabled !\n");
+		/* XXX should free pages here ? */
+		vdso64_pages = vdso32_pages = 0;
+		return;
+	}
+
+	/* Make sure pages are in the correct state */
+	for (i = 0; i < vdso64_pages; i++) {
+		struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+	}
+	for (i = 0; i < vdso32_pages; i++) {
+		struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+	}
+}
+
+int in_gate_area_no_task(unsigned long addr)
+{
+	return 0;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+	return 0;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+	return NULL;
+}
+
diff --git a/arch/ppc64/kernel/vdso32/Makefile b/arch/ppc64/kernel/vdso32/Makefile
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/Makefile
@@ -0,0 +1,36 @@
+
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
+
+# Build rules
+
+targets := $(obj-vdso32) vdso32.so
+obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
+
+
+EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
+EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1
+EXTRA_AFLAGS := -D__VDSO32__ -s
+
+obj-y += vdso32_wrapper.o
+extra-y += vdso32.lds
+CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
+
+# Force dependency (incbin is bad)
+$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
+
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32)
+	$(call if_changed,vdso32ld)
+
+# assembly rules for the .S files
+$(obj-vdso32): %.o: %.S
+	$(call if_changed_dep,vdso32as)
+
+# actual build commands
+quiet_cmd_vdso32ld = VDSO32L $@
+      cmd_vdso32ld = $(CROSS32CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdso32as = VDSO32A $@
+      cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $<
+
diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/cacheflush.S
@@ -0,0 +1,67 @@
+/*
+ * vDSO provided cache flush routines
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *                    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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/offsets.h>
+
+	.text
+
+/*
+ * Default "generic" version of __kernel_sync_dicache.
+ *
+ * void __kernel_sync_dicache(unsigned long start, unsigned long end)
+ *
+ * Flushes the data cache & invalidate the instruction cache for the
+ * provided range [start, end[
+ *
+ * Note: all CPUs supported by this kernel have a 128 bytes cache
+ * line size so we don't have to peek that info from the datapage
+ */
+V_FUNCTION_BEGIN(__kernel_sync_dicache)
+  .cfi_startproc
+	li	r5,127
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5		/* ensure we get enough */
+	srwi.	r8,r8,7			/* compute line count */
+	beqlr				/* nothing to do? */
+	mtctr	r8
+	mr	r3,r6
+1:	dcbst	0,r3
+	addi	r3,r3,128
+	bdnz	1b
+	sync
+	mtctr	r8
+1:	icbi	0,r6
+	addi	r6,r6,128
+	bdnz	1b
+	isync
+	li	r3,0
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_sync_dicache)
+
+
+/*
+ * POWER5 version of __kernel_sync_dicache
+ */
+V_FUNCTION_BEGIN(__kernel_sync_dicache_p5)
+  .cfi_startproc
+	sync
+	isync
+	li	r3,0
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_sync_dicache_p5)
+
diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/ppc64/kernel/vdso32/datapage.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/datapage.S
@@ -0,0 +1,68 @@
+/*
+ * Access to the shared data page by the vDSO & syscall map
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), 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.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+	.text
+V_FUNCTION_BEGIN(__get_datapage)
+  .cfi_startproc
+	/* We don't want that exposed or overridable as we want other objects
+	 * to be able to bl directly to here
+	 */
+	.protected __get_datapage
+	.hidden __get_datapage
+
+	mflr	r0
+  .cfi_register lr,r0
+
+	bcl	20,31,1f
+	.global	__kernel_datapage_offset;
+__kernel_datapage_offset:
+	.long	0
+1:
+	mflr	r3
+	mtlr	r0
+	lwz	r0,0(r3)
+	add	r3,r0,r3
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__get_datapage)
+
+/*
+ * void *__kernel_get_syscall_map(unsigned int *syscall_count) ;
+ *
+ * returns a pointer to the syscall map. the map is agnostic to the
+ * size of "long", unlike kernel bitops, it stores bits from top to
+ * bottom so that memory actually contains a linear bitmap
+ * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of
+ * 32 bits int at N >> 5.
+ */
+V_FUNCTION_BEGIN(__kernel_get_syscall_map)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r4,r3
+	bl	__get_datapage@local
+	mtlr	r12
+	addi	r3,r3,CFG_SYSCALL_MAP32
+	cmpli	cr0,r4,0
+	beqlr
+	li	r0,__NR_syscalls
+	stw	r0,0(r4)
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_get_syscall_map)
diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/gettimeofday.S
@@ -0,0 +1,140 @@
+/*
+ * Userland implementation of gettimeofday() for 32 bits processes in a
+ * ppc64 kernel for use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), 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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/offsets.h>
+#include <asm/unistd.h>
+
+	.text
+/*
+ * Exact prototype of gettimeofday
+ *
+ * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_gettimeofday)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r10,r3			/* r10 saves tv */
+	mr	r11,r4			/* r11 saves tz */
+	bl	__get_datapage@local	/* get data page */
+	mr	r9, r3			/* datapage ptr in r9 */
+	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
+	bne-	2f			/* out of line -> do syscall */
+
+	/* seconds are xsec >> 20 */
+	rlwinm	r5,r4,12,20,31
+	rlwimi	r5,r3,12,0,19
+	stw	r5,TVAL32_TV_SEC(r10)
+
+	/* get remaining xsec and convert to usec. we scale
+	 * up remaining xsec by 12 bits and get the top 32 bits
+	 * of the multiplication
+	 */
+	rlwinm	r5,r4,12,0,19
+	lis	r6,1000000@h
+	ori	r6,r6,1000000@l
+	mulhwu	r5,r5,r6
+	stw	r5,TVAL32_TV_USEC(r10)
+
+	cmpli	cr0,r11,0		/* check if tz is NULL */
+	beq	1f
+	lwz	r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
+	lwz	r5,CFG_TZ_DSTTIME(r9)
+	stw	r4,TZONE_TZ_MINWEST(r11)
+	stw	r5,TZONE_TZ_DSTTIME(r11)
+
+1:	mtlr	r12
+	li	r3,0
+	blr
+
+2:	mr	r3,r10
+	mr	r4,r11
+	li	r0,__NR_gettimeofday
+	sc
+	b	1b
+  .cfi_endproc
+V_FUNCTION_END(__kernel_gettimeofday)
+
+/*
+ * This is the core of gettimeofday(), it returns the xsec
+ * value in r3 & r4 and expects the datapage ptr (non clobbered)
+ * in r9. clobbers r0,r4,r5,r6,r7,r8
+*/
+__do_get_xsec:
+  .cfi_startproc
+	/* Check for update count & load values. We use the low
+	 * order 32 bits of the update count
+	 */
+1:	lwz	r8,(CFG_TB_UPDATE_COUNT+4)(r9)
+	andi.	r0,r8,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r8,r8		/* create dependency */
+	add	r9,r9,r0
+
+	/* Load orig stamp (offset to TB) */
+	lwz	r5,CFG_TB_ORIG_STAMP(r9)
+	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
+
+	/* Get a stable TB value */
+2:	mftbu	r3
+	mftbl	r4
+	mftbu	r0
+	cmpl	cr0,r3,r0
+	bne-	2b
+
+	/* Substract tb orig stamp. If the high part is non-zero, we jump to the
+	 * slow path which call the syscall. If it's ok, then we have our 32 bits
+	 * tb_ticks value in r7
+	 */
+	subfc	r7,r6,r4
+	subfe.	r0,r5,r3
+	bne-	3f
+
+	/* Load scale factor & do multiplication */
+	lwz	r5,CFG_TB_TO_XS(r9)	/* load values */
+	lwz	r6,(CFG_TB_TO_XS+4)(r9)
+	mulhwu	r4,r7,r5
+	mulhwu	r6,r7,r6
+	mullw	r6,r7,r5
+	addc	r6,r6,r0
+
+	/* At this point, we have the scaled xsec value in r4 + XER:CA
+	 * we load & add the stamp since epoch
+	 */
+	lwz	r5,CFG_STAMP_XSEC(r9)
+	lwz	r6,(CFG_STAMP_XSEC+4)(r9)
+	adde	r4,r4,r6
+	addze	r3,r5
+
+	/* We now have our result in r3,r4. We create a fake dependency
+	 * on that result and re-check the counter
+	 */
+	xor	r0,r4,r4
+	add	r9,r9,r0
+	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
+        cmpl    cr0,r8,r0		/* check if updated */
+	bne-	1b
+
+	/* Warning ! The caller expects CR:EQ to be set to indicate a
+	 * successful calculation (so it won't fallback to the syscall
+	 * method). We have overriden that CR bit in the counter check,
+	 * but fortunately, the loop exit condition _is_ CR:EQ set, so
+	 * we can exit safely here. If you change this code, be careful
+	 * of that side effect.
+	 */
+3:	blr
+  .cfi_endproc
diff --git a/arch/ppc64/kernel/vdso32/note.S b/arch/ppc64/kernel/vdso32/note.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/note.S
@@ -0,0 +1,25 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type)			      \
+	.section name, flags;						      \
+	.balign 4;							      \
+	.long 1f - 0f;		/* name length */			      \
+	.long 3f - 2f;		/* data length */			      \
+	.long type;		/* note type */				      \
+0:	.asciz vendor;		/* vendor name */			      \
+1:	.balign 4;							      \
+2:
+
+#define ASM_ELF_NOTE_END						      \
+3:	.balign 4;		/* pad out section */			      \
+	.previous
+
+	ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+	.long LINUX_VERSION_CODE
+	ASM_ELF_NOTE_END
diff --git a/arch/ppc64/kernel/vdso32/sigtramp.S b/arch/ppc64/kernel/vdso32/sigtramp.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/sigtramp.S
@@ -0,0 +1,300 @@
+/*
+ * Signal trampolines for 32 bits processes in a ppc64 kernel for
+ * use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp.
+ * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), 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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+	.text
+
+/* The nop here is a hack.  The dwarf2 unwind routines subtract 1 from
+   the return address to get an address in the middle of the presumed
+   call instruction.  Since we don't have a call here, we artifically
+   extend the range covered by the unwind info by adding a nop before
+   the real start.  */
+	nop
+V_FUNCTION_BEGIN(__kernel_sigtramp32)
+.Lsig_start = . - 4
+	li	r0,__NR_sigreturn
+	sc
+.Lsig_end:
+V_FUNCTION_END(__kernel_sigtramp32)
+
+.Lsigrt_start:
+	nop
+V_FUNCTION_BEGIN(__kernel_sigtramp_rt32)
+	li	r0,__NR_rt_sigreturn
+	sc
+.Lsigrt_end:
+V_FUNCTION_END(__kernel_sigtramp_rt32)
+
+	.section .eh_frame,"a",@progbits
+
+/* Register r1 can be found at offset 4 of a pt_regs structure.
+   A pointer to the pt_regs is stored in memory at the old sp plus PTREGS.  */
+#define cfa_save \
+  .byte 0x0f;			/* DW_CFA_def_cfa_expression */		\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x23; .uleb128 RSIZE;	/*     DW_OP_plus_uconst */		\
+  .byte 0x06;			/*     DW_OP_deref */			\
+9:
+
+/* Register REGNO can be found at offset OFS of a pt_regs structure.
+   A pointer to the pt_regs is stored in memory at the old sp plus PTREGS.  */
+#define rsave(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .ifne ofs;								\
+    .byte 0x23; .uleb128 ofs;	/*     DW_OP_plus_uconst */		\
+  .endif;								\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
+   of the VMX reg struct.  The VMX reg struct is at offset VREGS of
+   the pt_regs struct.  This macro is for REGNO == 0, and contains
+   'subroutines' that the other macros jump to.  */
+#define vsave_msr0(regno) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x30 + regno;		/*     DW_OP_lit0 */			\
+2:									\
+  .byte 0x40;			/*     DW_OP_lit16 */			\
+  .byte 0x1e;			/*     DW_OP_mul */			\
+3:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x12;			/*     DW_OP_dup */			\
+  .byte 0x23;			/*     DW_OP_plus_uconst */		\
+    .uleb128 33*RSIZE;		/*       msr offset */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x0c; .long 1 << 25;	/*     DW_OP_const4u */			\
+  .byte 0x1a;			/*     DW_OP_and */			\
+  .byte 0x12;			/*     DW_OP_dup, ret 0 if bra taken */	\
+  .byte 0x30;			/*     DW_OP_lit0 */			\
+  .byte 0x29;			/*     DW_OP_eq */			\
+  .byte 0x28; .short 0x7fff;	/*     DW_OP_bra to end */		\
+  .byte 0x13;			/*     DW_OP_drop, pop the 0 */		\
+  .byte 0x23; .uleb128 VREGS;	/*     DW_OP_plus_uconst */		\
+  .byte 0x22;			/*     DW_OP_plus */			\
+  .byte 0x2f; .short 0x7fff;	/*     DW_OP_skip to end */		\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
+   of the VMX reg struct.  REGNO is 1 thru 31.  */
+#define vsave_msr1(regno) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x30 + regno;		/*     DW_OP_lit n */			\
+  .byte 0x2f; .short 2b - 9f;	/*     DW_OP_skip */			\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of
+   the VMX save block.  */
+#define vsave_msr2(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x0a; .short ofs;	/*     DW_OP_const2u */			\
+  .byte 0x2f; .short 3b - 9f;	/*     DW_OP_skip */			\
+9:
+
+/* VMX register REGNO is at offset OFS of the VMX save area.  */
+#define vsave(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x23; .uleb128 VREGS;	/*     DW_OP_plus_uconst */		\
+  .byte 0x23; .uleb128 ofs;	/*     DW_OP_plus_uconst */		\
+9:
+
+/* This is where the pt_regs pointer can be found on the stack.  */
+#define PTREGS 64+28
+
+/* Size of regs.  */
+#define RSIZE 4
+
+/* This is the offset of the VMX regs.  */
+#define VREGS 48*RSIZE+34*8
+
+/* Describe where general purpose regs are saved.  */
+#define EH_FRAME_GEN \
+  cfa_save;								\
+  rsave ( 0,  0*RSIZE);							\
+  rsave ( 2,  2*RSIZE);							\
+  rsave ( 3,  3*RSIZE);							\
+  rsave ( 4,  4*RSIZE);							\
+  rsave ( 5,  5*RSIZE);							\
+  rsave ( 6,  6*RSIZE);							\
+  rsave ( 7,  7*RSIZE);							\
+  rsave ( 8,  8*RSIZE);							\
+  rsave ( 9,  9*RSIZE);							\
+  rsave (10, 10*RSIZE);							\
+  rsave (11, 11*RSIZE);							\
+  rsave (12, 12*RSIZE);							\
+  rsave (13, 13*RSIZE);							\
+  rsave (14, 14*RSIZE);							\
+  rsave (15, 15*RSIZE);							\
+  rsave (16, 16*RSIZE);							\
+  rsave (17, 17*RSIZE);							\
+  rsave (18, 18*RSIZE);							\
+  rsave (19, 19*RSIZE);							\
+  rsave (20, 20*RSIZE);							\
+  rsave (21, 21*RSIZE);							\
+  rsave (22, 22*RSIZE);							\
+  rsave (23, 23*RSIZE);							\
+  rsave (24, 24*RSIZE);							\
+  rsave (25, 25*RSIZE);							\
+  rsave (26, 26*RSIZE);							\
+  rsave (27, 27*RSIZE);							\
+  rsave (28, 28*RSIZE);							\
+  rsave (29, 29*RSIZE);							\
+  rsave (30, 30*RSIZE);							\
+  rsave (31, 31*RSIZE);							\
+  rsave (67, 32*RSIZE);		/* ap, used as temp for nip */		\
+  rsave (65, 36*RSIZE);		/* lr */				\
+  rsave (70, 38*RSIZE)		/* cr */
+
+/* Describe where the FP regs are saved.  */
+#define EH_FRAME_FP \
+  rsave (32, 48*RSIZE +  0*8);						\
+  rsave (33, 48*RSIZE +  1*8);						\
+  rsave (34, 48*RSIZE +  2*8);						\
+  rsave (35, 48*RSIZE +  3*8);						\
+  rsave (36, 48*RSIZE +  4*8);						\
+  rsave (37, 48*RSIZE +  5*8);						\
+  rsave (38, 48*RSIZE +  6*8);						\
+  rsave (39, 48*RSIZE +  7*8);						\
+  rsave (40, 48*RSIZE +  8*8);						\
+  rsave (41, 48*RSIZE +  9*8);						\
+  rsave (42, 48*RSIZE + 10*8);						\
+  rsave (43, 48*RSIZE + 11*8);						\
+  rsave (44, 48*RSIZE + 12*8);						\
+  rsave (45, 48*RSIZE + 13*8);						\
+  rsave (46, 48*RSIZE + 14*8);						\
+  rsave (47, 48*RSIZE + 15*8);						\
+  rsave (48, 48*RSIZE + 16*8);						\
+  rsave (49, 48*RSIZE + 17*8);						\
+  rsave (50, 48*RSIZE + 18*8);						\
+  rsave (51, 48*RSIZE + 19*8);						\
+  rsave (52, 48*RSIZE + 20*8);						\
+  rsave (53, 48*RSIZE + 21*8);						\
+  rsave (54, 48*RSIZE + 22*8);						\
+  rsave (55, 48*RSIZE + 23*8);						\
+  rsave (56, 48*RSIZE + 24*8);						\
+  rsave (57, 48*RSIZE + 25*8);						\
+  rsave (58, 48*RSIZE + 26*8);						\
+  rsave (59, 48*RSIZE + 27*8);						\
+  rsave (60, 48*RSIZE + 28*8);						\
+  rsave (61, 48*RSIZE + 29*8);						\
+  rsave (62, 48*RSIZE + 30*8);						\
+  rsave (63, 48*RSIZE + 31*8)
+
+/* Describe where the VMX regs are saved.  */
+#ifdef CONFIG_ALTIVEC
+#define EH_FRAME_VMX \
+  vsave_msr0 ( 0);							\
+  vsave_msr1 ( 1);							\
+  vsave_msr1 ( 2);							\
+  vsave_msr1 ( 3);							\
+  vsave_msr1 ( 4);							\
+  vsave_msr1 ( 5);							\
+  vsave_msr1 ( 6);							\
+  vsave_msr1 ( 7);							\
+  vsave_msr1 ( 8);							\
+  vsave_msr1 ( 9);							\
+  vsave_msr1 (10);							\
+  vsave_msr1 (11);							\
+  vsave_msr1 (12);							\
+  vsave_msr1 (13);							\
+  vsave_msr1 (14);							\
+  vsave_msr1 (15);							\
+  vsave_msr1 (16);							\
+  vsave_msr1 (17);							\
+  vsave_msr1 (18);							\
+  vsave_msr1 (19);							\
+  vsave_msr1 (20);							\
+  vsave_msr1 (21);							\
+  vsave_msr1 (22);							\
+  vsave_msr1 (23);							\
+  vsave_msr1 (24);							\
+  vsave_msr1 (25);							\
+  vsave_msr1 (26);							\
+  vsave_msr1 (27);							\
+  vsave_msr1 (28);							\
+  vsave_msr1 (29);							\
+  vsave_msr1 (30);							\
+  vsave_msr1 (31);							\
+  vsave_msr2 (33, 32*16+12);						\
+  vsave      (32, 32*16)
+#else
+#define EH_FRAME_VMX
+#endif
+
+.Lcie:
+	.long .Lcie_end - .Lcie_start
+.Lcie_start:
+	.long 0			/* CIE ID */
+	.byte 1			/* Version number */
+	.string "zR"		/* NUL-terminated augmentation string */
+	.uleb128 4		/* Code alignment factor */
+	.sleb128 -4		/* Data alignment factor */
+	.byte 67		/* Return address register column, ap */
+	.uleb128 1		/* Augmentation value length */
+	.byte 0x1b		/* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */
+	.byte 0x0c,1,0		/* DW_CFA_def_cfa: r1 ofs 0 */
+	.balign 4
+.Lcie_end:
+
+	.long .Lfde0_end - .Lfde0_start
+.Lfde0_start:
+	.long .Lfde0_start - .Lcie	/* CIE pointer. */
+	.long .Lsig_start - .		/* PC start, length */
+	.long .Lsig_end - .Lsig_start
+	.uleb128 0			/* Augmentation */
+	EH_FRAME_GEN
+	EH_FRAME_FP
+	EH_FRAME_VMX
+	.balign 4
+.Lfde0_end:
+
+/* We have a different stack layout for rt_sigreturn.  */
+#undef PTREGS
+#define PTREGS 64+16+128+20+28
+
+	.long .Lfde1_end - .Lfde1_start
+.Lfde1_start:
+	.long .Lfde1_start - .Lcie	/* CIE pointer. */
+	.long .Lsigrt_start - .		/* PC start, length */
+	.long .Lsigrt_end - .Lsigrt_start
+	.uleb128 0			/* Augmentation */
+	EH_FRAME_GEN
+	EH_FRAME_FP
+	EH_FRAME_VMX
+	.balign 4
+.Lfde1_end:
diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S
@@ -0,0 +1,114 @@
+
+/*
+ * This is the infamous ld script for the 32 bits vdso
+ * library
+ */
+#include <asm/vdso.h>
+
+/* Default link addresses for the vDSOs */
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_start)
+
+SECTIONS
+{
+  . = VDSO32_LBASE + SIZEOF_HEADERS;
+  .hash           : { *(.hash) }			:text
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+
+  .note		  : { *(.note.*) } 			:text	:note
+
+  . = ALIGN (16);
+  .text :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+  }
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+
+  /* Other stuff is appended to the text segment: */
+  .rodata		: { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1		: { *(.rodata1) }
+
+  .eh_frame_hdr		: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+  .eh_frame		: { KEEP (*(.eh_frame)) }	:text
+  .gcc_except_table	: { *(.gcc_except_table) }
+  .fixup		: { *(.fixup) }
+
+  .got ALIGN(4)		: { *(.got.plt) *(.got) }
+
+  .dynamic		: { *(.dynamic) }		:text	:dynamic
+
+  _end = .;
+  __end = .;
+  PROVIDE (end = .);
+
+
+  /* Stabs debugging sections are here too
+   */
+  .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) }
+  .debug 0 : { *(.debug) }
+  .line 0 : { *(.line) }
+
+  .debug_srcinfo 0 : { *(.debug_srcinfo) }
+  .debug_sfnames 0 : { *(.debug_sfnames) }
+
+  .debug_aranges 0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+
+  .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .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) }
+
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames 0 : { *(.debug_varnames) }
+
+  /DISCARD/ : { *(.note.GNU-stack) }
+  /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) }
+  /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) }
+}
+
+
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+  note PT_NOTE FLAGS(4); /* PF_R */
+  dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+  VDSO_VERSION_STRING {
+    global:
+	__kernel_datapage_offset; /* Has to be there for the kernel to find it */
+	__kernel_get_syscall_map;
+	__kernel_gettimeofday;
+	__kernel_sync_dicache;
+	__kernel_sync_dicache_p5;
+	__kernel_sigtramp32;
+	__kernel_sigtramp_rt32;
+    local: *;
+  };
+}
diff --git a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S b/arch/ppc64/kernel/vdso32/vdso32_wrapper.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso32/vdso32_wrapper.S
@@ -0,0 +1,13 @@
+#include <linux/init.h>
+#include <asm/page.h>
+
+	.section ".data.page_aligned"
+
+	.globl vdso32_start, vdso32_end
+	.balign PAGE_SIZE
+vdso32_start:
+	.incbin "arch/ppc64/kernel/vdso32/vdso32.so"
+	.balign PAGE_SIZE
+vdso32_end:
+
+	.previous
diff --git a/arch/ppc64/kernel/vdso64/Makefile b/arch/ppc64/kernel/vdso64/Makefile
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/Makefile
@@ -0,0 +1,35 @@
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
+
+# Build rules
+
+targets := $(obj-vdso64) vdso64.so
+obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
+
+EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
+EXTRA_CFLAGS +=  -nostdlib -Wl,-soname=linux-vdso64.so.1
+EXTRA_AFLAGS := -D__VDSO64__ -s
+
+obj-y += vdso64_wrapper.o
+extra-y += vdso64.lds
+CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
+
+# Force dependency (incbin is bad)
+$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
+
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso64.so: $(src)/vdso64.lds $(obj-vdso64)
+	$(call if_changed,vdso64ld)
+
+# assembly rules for the .S files
+$(obj-vdso64): %.o: %.S
+	$(call if_changed_dep,vdso64as)
+
+# actual build commands
+quiet_cmd_vdso64ld = VDSO64L $@
+      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdso64as = VDSO64A $@
+      cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
+
+
diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/cacheflush.S
@@ -0,0 +1,66 @@
+/*
+ * vDSO provided cache flush routines
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *                    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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/offsets.h>
+
+	.text
+
+/*
+ * Default "generic" version of __kernel_sync_dicache.
+ *
+ * void __kernel_sync_dicache(unsigned long start, unsigned long end)
+ *
+ * Flushes the data cache & invalidate the instruction cache for the
+ * provided range [start, end[
+ *
+ * Note: all CPUs supported by this kernel have a 128 bytes cache
+ * line size so we don't have to peek that info from the datapage
+ */
+V_FUNCTION_BEGIN(__kernel_sync_dicache)
+  .cfi_startproc
+	li	r5,127
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5		/* ensure we get enough */
+	srwi.	r8,r8,7			/* compute line count */
+	beqlr				/* nothing to do? */
+	mtctr	r8
+	mr	r3,r6
+1:	dcbst	0,r3
+	addi	r3,r3,128
+	bdnz	1b
+	sync
+	mtctr	r8
+1:	icbi	0,r6
+	addi	r6,r6,128
+	bdnz	1b
+	isync
+	li	r3,0
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_sync_dicache)
+
+
+/*
+ * POWER5 version of __kernel_sync_dicache
+ */
+V_FUNCTION_BEGIN(__kernel_sync_dicache_p5)
+  .cfi_startproc
+	sync
+	isync
+	li	r3,0
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_sync_dicache_p5)
diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/ppc64/kernel/vdso64/datapage.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/datapage.S
@@ -0,0 +1,68 @@
+/*
+ * Access to the shared data page by the vDSO & syscall map
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), 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.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+	.text
+V_FUNCTION_BEGIN(__get_datapage)
+  .cfi_startproc
+	/* We don't want that exposed or overridable as we want other objects
+	 * to be able to bl directly to here
+	 */
+	.protected __get_datapage
+	.hidden __get_datapage
+
+	mflr	r0
+  .cfi_register lr,r0
+
+	bcl	20,31,1f
+	.global	__kernel_datapage_offset;
+__kernel_datapage_offset:
+	.long	0
+1:
+	mflr	r3
+	mtlr	r0
+	lwz	r0,0(r3)
+	add	r3,r0,r3
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__get_datapage)
+
+/*
+ * void *__kernel_get_syscall_map(unsigned int *syscall_count) ;
+ *
+ * returns a pointer to the syscall map. the map is agnostic to the
+ * size of "long", unlike kernel bitops, it stores bits from top to
+ * bottom so that memory actually contains a linear bitmap
+ * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of
+ * 32 bits int at N >> 5.
+ */
+V_FUNCTION_BEGIN(__kernel_get_syscall_map)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r4,r3
+	bl	V_LOCAL_FUNC(__get_datapage)
+	mtlr	r12
+	addi	r3,r3,CFG_SYSCALL_MAP64
+	cmpli	cr0,r4,0
+	beqlr
+	li	r0,__NR_syscalls
+	stw	r0,0(r4)
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_get_syscall_map)
diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/gettimeofday.S
@@ -0,0 +1,91 @@
+/*
+ * Userland implementation of gettimeofday() for 64 bits processes in a
+ * ppc64 kernel for use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *                    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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/offsets.h>
+
+	.text
+/*
+ * Exact prototype of gettimeofday
+ *
+ * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_gettimeofday)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r11,r3			/* r11 holds tv */
+	mr	r10,r4			/* r10 holds tz */
+	bl	V_LOCAL_FUNC(__get_datapage)		/* get data page */
+	bl	V_LOCAL_FUNC(__do_get_xsec)		/* get xsec from tb & kernel */
+	lis     r7,15			/* r7 = 1000000 = USEC_PER_SEC */
+	ori     r7,r7,16960
+	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
+	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
+	std	r5,TVAL64_TV_SEC(r11)	/* store sec in tv */
+	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
+	mulld   r0,r0,r7		/* usec = (xsec * USEC_PER_SEC) / XSEC_PER_SEC */
+	rldicl  r0,r0,44,20
+	cmpldi	cr0,r10,0		/* check if tz is NULL */
+	std	r0,TVAL64_TV_USEC(r11)	/* store usec in tv */
+	beq	1f
+	lwz	r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
+	lwz	r5,CFG_TZ_DSTTIME(r3)
+	stw	r4,TZONE_TZ_MINWEST(r10)
+	stw	r5,TZONE_TZ_DSTTIME(r10)
+1:	mtlr	r12
+	li	r3,0			/* always success */
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_gettimeofday)
+
+
+/*
+ * This is the core of gettimeofday(), it returns the xsec
+ * value in r4 and expects the datapage ptr (non clobbered)
+ * in r3. clobbers r0,r4,r5,r6,r7,r8
+*/
+V_FUNCTION_BEGIN(__do_get_xsec)
+  .cfi_startproc
+	/* check for update count & load values */
+1:	ld	r7,CFG_TB_UPDATE_COUNT(r3)
+	andi.	r0,r4,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r4,r4		/* create dependency */
+	add	r3,r3,r0
+
+	/* Get TB & offset it */
+	mftb	r8
+	ld	r9,CFG_TB_ORIG_STAMP(r3)
+	subf	r8,r9,r8
+
+	/* Scale result */
+	ld	r5,CFG_TB_TO_XS(r3)
+	mulhdu	r8,r8,r5
+
+	/* Add stamp since epoch */
+	ld	r6,CFG_STAMP_XSEC(r3)
+	add	r4,r6,r8
+
+	xor	r0,r4,r4
+	add	r3,r3,r0
+	ld	r0,CFG_TB_UPDATE_COUNT(r3)
+        cmpld   cr0,r0,r7		/* check if updated */
+	bne-	1b
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__do_get_xsec)
diff --git a/arch/ppc64/kernel/vdso64/note.S b/arch/ppc64/kernel/vdso64/note.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/note.S
@@ -0,0 +1 @@
+#include "../vdso32/note.S"
diff --git a/arch/ppc64/kernel/vdso64/sigtramp.S b/arch/ppc64/kernel/vdso64/sigtramp.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/sigtramp.S
@@ -0,0 +1,294 @@
+/*
+ * Signal trampoline for 64 bits processes in a ppc64 kernel for
+ * use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp.
+ * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), 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.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+	.text
+
+/* The nop here is a hack.  The dwarf2 unwind routines subtract 1 from
+   the return address to get an address in the middle of the presumed
+   call instruction.  Since we don't have a call here, we artifically
+   extend the range covered by the unwind info by padding before the
+   real start.  */
+	nop
+	.balign 8
+V_FUNCTION_BEGIN(__kernel_sigtramp_rt64)
+.Lsigrt_start = . - 4
+	addi	r1, r1, __SIGNAL_FRAMESIZE
+	li	r0,__NR_rt_sigreturn
+	sc
+.Lsigrt_end:
+V_FUNCTION_END(__kernel_sigtramp_rt64)
+/* The ".balign 8" above and the following zeros mimic the old stack
+   trampoline layout.  The last magic value is the ucontext pointer,
+   chosen in such a way that older libgcc unwind code returns a zero
+   for a sigcontext pointer.  */
+	.long 0,0,0
+	.quad 0,-21*8
+
+/* Register r1 can be found at offset 8 of a pt_regs structure.
+   A pointer to the pt_regs is stored in memory at the old sp plus PTREGS.  */
+#define cfa_save \
+  .byte 0x0f;			/* DW_CFA_def_cfa_expression */		\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x23; .uleb128 RSIZE;	/*     DW_OP_plus_uconst */		\
+  .byte 0x06;			/*     DW_OP_deref */			\
+9:
+
+/* Register REGNO can be found at offset OFS of a pt_regs structure.
+   A pointer to the pt_regs is stored in memory at the old sp plus PTREGS.  */
+#define rsave(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .ifne ofs;								\
+    .byte 0x23; .uleb128 ofs;	/*     DW_OP_plus_uconst */		\
+  .endif;								\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
+   of the VMX reg struct.  A pointer to the VMX reg struct is at VREGS in
+   the pt_regs struct.  This macro is for REGNO == 0, and contains
+   'subroutines' that the other macros jump to.  */
+#define vsave_msr0(regno) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x30 + regno;		/*     DW_OP_lit0 */			\
+2:									\
+  .byte 0x40;			/*     DW_OP_lit16 */			\
+  .byte 0x1e;			/*     DW_OP_mul */			\
+3:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x12;			/*     DW_OP_dup */			\
+  .byte 0x23;			/*     DW_OP_plus_uconst */		\
+    .uleb128 33*RSIZE;		/*       msr offset */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x0c; .long 1 << 25;	/*     DW_OP_const4u */			\
+  .byte 0x1a;			/*     DW_OP_and */			\
+  .byte 0x12;			/*     DW_OP_dup, ret 0 if bra taken */	\
+  .byte 0x30;			/*     DW_OP_lit0 */			\
+  .byte 0x29;			/*     DW_OP_eq */			\
+  .byte 0x28; .short 0x7fff;	/*     DW_OP_bra to end */		\
+  .byte 0x13;			/*     DW_OP_drop, pop the 0 */		\
+  .byte 0x23; .uleb128 VREGS;	/*     DW_OP_plus_uconst */		\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x22;			/*     DW_OP_plus */			\
+  .byte 0x2f; .short 0x7fff;	/*     DW_OP_skip to end */		\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
+   of the VMX reg struct.  REGNO is 1 thru 31.  */
+#define vsave_msr1(regno) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x30 + regno;		/*     DW_OP_lit n */			\
+  .byte 0x2f; .short 2b - 9f;	/*     DW_OP_skip */			\
+9:
+
+/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of
+   the VMX save block.  */
+#define vsave_msr2(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x0a; .short ofs;	/*     DW_OP_const2u */			\
+  .byte 0x2f; .short 3b - 9f;	/*     DW_OP_skip */			\
+9:
+
+/* VMX register REGNO is at offset OFS of the VMX save area.  */
+#define vsave(regno, ofs) \
+  .byte 0x10;			/* DW_CFA_expression */			\
+  .uleb128 regno + 77;		/*   regno */				\
+  .uleb128 9f - 1f;		/*   length */				\
+1:									\
+  .byte 0x71; .sleb128 PTREGS;	/*     DW_OP_breg1 */			\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x23; .uleb128 VREGS;	/*     DW_OP_plus_uconst */		\
+  .byte 0x06;			/*     DW_OP_deref */			\
+  .byte 0x23; .uleb128 ofs;	/*     DW_OP_plus_uconst */		\
+9:
+
+/* This is where the pt_regs pointer can be found on the stack.  */
+#define PTREGS 128+168+56
+
+/* Size of regs.  */
+#define RSIZE 8
+
+/* This is the offset of the VMX reg pointer.  */
+#define VREGS 48*RSIZE+33*8
+
+/* Describe where general purpose regs are saved.  */
+#define EH_FRAME_GEN \
+  cfa_save;								\
+  rsave ( 0,  0*RSIZE);							\
+  rsave ( 2,  2*RSIZE);							\
+  rsave ( 3,  3*RSIZE);							\
+  rsave ( 4,  4*RSIZE);							\
+  rsave ( 5,  5*RSIZE);							\
+  rsave ( 6,  6*RSIZE);							\
+  rsave ( 7,  7*RSIZE);							\
+  rsave ( 8,  8*RSIZE);							\
+  rsave ( 9,  9*RSIZE);							\
+  rsave (10, 10*RSIZE);							\
+  rsave (11, 11*RSIZE);							\
+  rsave (12, 12*RSIZE);							\
+  rsave (13, 13*RSIZE);							\
+  rsave (14, 14*RSIZE);							\
+  rsave (15, 15*RSIZE);							\
+  rsave (16, 16*RSIZE);							\
+  rsave (17, 17*RSIZE);							\
+  rsave (18, 18*RSIZE);							\
+  rsave (19, 19*RSIZE);							\
+  rsave (20, 20*RSIZE);							\
+  rsave (21, 21*RSIZE);							\
+  rsave (22, 22*RSIZE);							\
+  rsave (23, 23*RSIZE);							\
+  rsave (24, 24*RSIZE);							\
+  rsave (25, 25*RSIZE);							\
+  rsave (26, 26*RSIZE);							\
+  rsave (27, 27*RSIZE);							\
+  rsave (28, 28*RSIZE);							\
+  rsave (29, 29*RSIZE);							\
+  rsave (30, 30*RSIZE);							\
+  rsave (31, 31*RSIZE);							\
+  rsave (67, 32*RSIZE);		/* ap, used as temp for nip */		\
+  rsave (65, 36*RSIZE);		/* lr */				\
+  rsave (70, 38*RSIZE)		/* cr */
+
+/* Describe where the FP regs are saved.  */
+#define EH_FRAME_FP \
+  rsave (32, 48*RSIZE +  0*8);						\
+  rsave (33, 48*RSIZE +  1*8);						\
+  rsave (34, 48*RSIZE +  2*8);						\
+  rsave (35, 48*RSIZE +  3*8);						\
+  rsave (36, 48*RSIZE +  4*8);						\
+  rsave (37, 48*RSIZE +  5*8);						\
+  rsave (38, 48*RSIZE +  6*8);						\
+  rsave (39, 48*RSIZE +  7*8);						\
+  rsave (40, 48*RSIZE +  8*8);						\
+  rsave (41, 48*RSIZE +  9*8);						\
+  rsave (42, 48*RSIZE + 10*8);						\
+  rsave (43, 48*RSIZE + 11*8);						\
+  rsave (44, 48*RSIZE + 12*8);						\
+  rsave (45, 48*RSIZE + 13*8);						\
+  rsave (46, 48*RSIZE + 14*8);						\
+  rsave (47, 48*RSIZE + 15*8);						\
+  rsave (48, 48*RSIZE + 16*8);						\
+  rsave (49, 48*RSIZE + 17*8);						\
+  rsave (50, 48*RSIZE + 18*8);						\
+  rsave (51, 48*RSIZE + 19*8);						\
+  rsave (52, 48*RSIZE + 20*8);						\
+  rsave (53, 48*RSIZE + 21*8);						\
+  rsave (54, 48*RSIZE + 22*8);						\
+  rsave (55, 48*RSIZE + 23*8);						\
+  rsave (56, 48*RSIZE + 24*8);						\
+  rsave (57, 48*RSIZE + 25*8);						\
+  rsave (58, 48*RSIZE + 26*8);						\
+  rsave (59, 48*RSIZE + 27*8);						\
+  rsave (60, 48*RSIZE + 28*8);						\
+  rsave (61, 48*RSIZE + 29*8);						\
+  rsave (62, 48*RSIZE + 30*8);						\
+  rsave (63, 48*RSIZE + 31*8)
+
+/* Describe where the VMX regs are saved.  */
+#ifdef CONFIG_ALTIVEC
+#define EH_FRAME_VMX \
+  vsave_msr0 ( 0);							\
+  vsave_msr1 ( 1);							\
+  vsave_msr1 ( 2);							\
+  vsave_msr1 ( 3);							\
+  vsave_msr1 ( 4);							\
+  vsave_msr1 ( 5);							\
+  vsave_msr1 ( 6);							\
+  vsave_msr1 ( 7);							\
+  vsave_msr1 ( 8);							\
+  vsave_msr1 ( 9);							\
+  vsave_msr1 (10);							\
+  vsave_msr1 (11);							\
+  vsave_msr1 (12);							\
+  vsave_msr1 (13);							\
+  vsave_msr1 (14);							\
+  vsave_msr1 (15);							\
+  vsave_msr1 (16);							\
+  vsave_msr1 (17);							\
+  vsave_msr1 (18);							\
+  vsave_msr1 (19);							\
+  vsave_msr1 (20);							\
+  vsave_msr1 (21);							\
+  vsave_msr1 (22);							\
+  vsave_msr1 (23);							\
+  vsave_msr1 (24);							\
+  vsave_msr1 (25);							\
+  vsave_msr1 (26);							\
+  vsave_msr1 (27);							\
+  vsave_msr1 (28);							\
+  vsave_msr1 (29);							\
+  vsave_msr1 (30);							\
+  vsave_msr1 (31);							\
+  vsave_msr2 (33, 32*16+12);						\
+  vsave      (32, 33*16)
+#else
+#define EH_FRAME_VMX
+#endif
+
+	.section .eh_frame,"a",@progbits
+.Lcie:
+	.long .Lcie_end - .Lcie_start
+.Lcie_start:
+	.long 0			/* CIE ID */
+	.byte 1			/* Version number */
+	.string "zR"		/* NUL-terminated augmentation string */
+	.uleb128 4		/* Code alignment factor */
+	.sleb128 -8		/* Data alignment factor */
+	.byte 67		/* Return address register column, ap */
+	.uleb128 1		/* Augmentation value length */
+	.byte 0x14		/* DW_EH_PE_pcrel | DW_EH_PE_udata8. */
+	.byte 0x0c,1,0		/* DW_CFA_def_cfa: r1 ofs 0 */
+	.balign 8
+.Lcie_end:
+
+	.long .Lfde0_end - .Lfde0_start
+.Lfde0_start:
+	.long .Lfde0_start - .Lcie	/* CIE pointer. */
+	.quad .Lsigrt_start - .		/* PC start, length */
+	.quad .Lsigrt_end - .Lsigrt_start
+	.uleb128 0			/* Augmentation */
+	EH_FRAME_GEN
+	EH_FRAME_FP
+	EH_FRAME_VMX
+# Do we really need to describe the frame at this point?  ie. will
+# we ever have some call chain that returns somewhere past the addi?
+# I don't think so, since gcc doesn't support async signals.
+#	.byte 0x41		/* DW_CFA_advance_loc 1*4 */
+#undef PTREGS
+#define PTREGS 168+56
+#	EH_FRAME_GEN
+#	EH_FRAME_FP
+#	EH_FRAME_VMX
+	.balign 8
+.Lfde0_end:
diff --git a/arch/ppc64/kernel/vdso64/vdso64.lds.S b/arch/ppc64/kernel/vdso64/vdso64.lds.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/vdso64.lds.S
@@ -0,0 +1,113 @@
+/*
+ * This is the infamous ld script for the 64 bits vdso
+ * library
+ */
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_start)
+
+SECTIONS
+{
+  . = VDSO64_LBASE + SIZEOF_HEADERS;
+  .hash           : { *(.hash) }		:text
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+
+  .note		  : { *(.note.*) }		:text	:note
+
+  . = ALIGN (16);
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    *(.sfpr .glink)
+  }						:text
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+
+  /* Other stuff is appended to the text segment: */
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr   : { *(.eh_frame_hdr) }	:text	:eh_frame_hdr
+  .eh_frame       : { KEEP (*(.eh_frame)) }	:text
+  .gcc_except_table   : { *(.gcc_except_table) }
+
+  .opd           ALIGN(8) : { KEEP (*(.opd)) }
+  .got		 ALIGN(8) : { *(.got .toc) }
+  .rela.dyn	 ALIGN(8) : { *(.rela.dyn) }
+
+  .dynamic        : { *(.dynamic) }		:text	:dynamic
+
+  _end = .;
+  PROVIDE (end = .);
+
+  /* Stabs debugging sections are here too
+   */
+  .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) }
+  /* DWARF debug sectio/ns.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .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) }
+
+  /DISCARD/ : { *(.note.GNU-stack) }
+  /DISCARD/ : { *(.branch_lt) }
+  /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.*) }
+  /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) }
+}
+
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+  note PT_NOTE FLAGS(4); /* PF_R */
+  dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+  VDSO_VERSION_STRING {
+    global:
+	__kernel_datapage_offset; /* Has to be there for the kernel to find it */
+	__kernel_get_syscall_map;
+    	__kernel_gettimeofday;
+	__kernel_sync_dicache;
+	__kernel_sync_dicache_p5;
+	__kernel_sigtramp_rt64;
+    local: *;
+  };
+}
diff --git a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S b/arch/ppc64/kernel/vdso64/vdso64_wrapper.S
new file mode 100644
--- /dev/null
+++ b/arch/ppc64/kernel/vdso64/vdso64_wrapper.S
@@ -0,0 +1,13 @@
+#include <linux/init.h>
+#include <asm/page.h>
+
+	.section ".data.page_aligned"
+
+	.globl vdso64_start, vdso64_end
+	.balign PAGE_SIZE
+vdso64_start:
+	.incbin "arch/ppc64/kernel/vdso64/vdso64.so"
+	.balign PAGE_SIZE
+vdso64_end:
+
+	.previous
diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c
--- a/arch/ppc64/kernel/vio.c
+++ b/arch/ppc64/kernel/vio.c
@@ -557,48 +557,61 @@ int vio_disable_interrupts(struct vio_de
 EXPORT_SYMBOL(vio_disable_interrupts);
 #endif
 
-dma_addr_t vio_map_single(struct vio_dev *dev, void *vaddr,
+static dma_addr_t vio_map_single(struct device *dev, void *vaddr,
 			  size_t size, enum dma_data_direction direction)
 {
-	return iommu_map_single(dev->iommu_table, vaddr, size, direction);
+	return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size,
+			direction);
 }
-EXPORT_SYMBOL(vio_map_single);
 
-void vio_unmap_single(struct vio_dev *dev, dma_addr_t dma_handle,
+static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle,
 		      size_t size, enum dma_data_direction direction)
 {
-	iommu_unmap_single(dev->iommu_table, dma_handle, size, direction);
+	iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size,
+			direction);
 }
-EXPORT_SYMBOL(vio_unmap_single);
 
-int vio_map_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
-	       enum dma_data_direction direction)
+static int vio_map_sg(struct device *dev, struct scatterlist *sglist,
+		int nelems, enum dma_data_direction direction)
 {
-	return iommu_map_sg(&vdev->dev, vdev->iommu_table, sglist,
+	return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist,
 			nelems, direction);
 }
-EXPORT_SYMBOL(vio_map_sg);
 
-void vio_unmap_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
-		  enum dma_data_direction direction)
+static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist,
+		int nelems, enum dma_data_direction direction)
 {
-	iommu_unmap_sg(vdev->iommu_table, sglist, nelems, direction);
+	iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction);
 }
-EXPORT_SYMBOL(vio_unmap_sg);
 
-void *vio_alloc_consistent(struct vio_dev *dev, size_t size,
-			   dma_addr_t *dma_handle)
+static void *vio_alloc_coherent(struct device *dev, size_t size,
+			   dma_addr_t *dma_handle, unsigned int __nocast flag)
 {
-	return iommu_alloc_consistent(dev->iommu_table, size, dma_handle);
+	return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size,
+			dma_handle, flag);
 }
-EXPORT_SYMBOL(vio_alloc_consistent);
 
-void vio_free_consistent(struct vio_dev *dev, size_t size,
+static void vio_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
-	iommu_free_consistent(dev->iommu_table, size, vaddr, dma_handle);
+	iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr,
+			dma_handle);
 }
-EXPORT_SYMBOL(vio_free_consistent);
+
+static int vio_dma_supported(struct device *dev, u64 mask)
+{
+	return 1;
+}
+
+struct dma_mapping_ops vio_dma_ops = {
+	.alloc_coherent = vio_alloc_coherent,
+	.free_coherent = vio_free_coherent,
+	.map_single = vio_map_single,
+	.unmap_single = vio_unmap_single,
+	.map_sg = vio_map_sg,
+	.unmap_sg = vio_unmap_sg,
+	.dma_supported = vio_dma_supported,
+};
 
 static int vio_bus_match(struct device *dev, struct device_driver *drv)
 {
diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c
--- a/arch/ppc64/kernel/viopath.c
+++ b/arch/ppc64/kernel/viopath.c
@@ -42,6 +42,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/iSeries/HvTypes.h>
 #include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvLpConfig.h>
@@ -56,8 +57,8 @@
  * But this allows for other support in the future.
  */
 static struct viopathStatus {
-	int isOpen:1;		/* Did we open the path?            */
-	int isActive:1;		/* Do we have a mon msg outstanding */
+	int isOpen;		/* Did we open the path?            */
+	int isActive;		/* Do we have a mon msg outstanding */
 	int users[VIO_MAX_SUBTYPES];
 	HvLpInstanceId mSourceInst;
 	HvLpInstanceId mTargetInst;
@@ -79,12 +80,12 @@ static void handleMonitorEvent(struct Hv
 /*
  * We use this structure to handle asynchronous responses.  The caller
  * blocks on the semaphore and the handler posts the semaphore.  However,
- * if in_atomic() is true in the caller, then wait_atomic is used ...
+ * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...
  */
-struct doneAllocParms_t {
-	struct semaphore *sem;
+struct alloc_parms {
+	struct semaphore sem;
 	int number;
-	atomic_t *wait_atomic;
+	atomic_t wait_atomic;
 	int used_wait_atomic;
 };
 
@@ -97,9 +98,9 @@ static u8 viomonseq = 22;
 /* Our hosting logical partition.  We get this at startup
  * time, and different modules access this variable directly.
  */
-HvLpIndex viopath_hostLp = 0xff;	/* HvLpIndexInvalid */
+HvLpIndex viopath_hostLp = HvLpIndexInvalid;
 EXPORT_SYMBOL(viopath_hostLp);
-HvLpIndex viopath_ourLp = 0xff;
+HvLpIndex viopath_ourLp = HvLpIndexInvalid;
 EXPORT_SYMBOL(viopath_ourLp);
 
 /* For each kind of incoming event we set a pointer to a
@@ -200,7 +201,7 @@ EXPORT_SYMBOL(viopath_isactive);
 
 /*
  * We cache the source and target instance ids for each
- * partition.  
+ * partition.
  */
 HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
 {
@@ -450,36 +451,33 @@ static void vio_handleEvent(struct HvLpE
 
 static void viopath_donealloc(void *parm, int number)
 {
-	struct doneAllocParms_t *parmsp = (struct doneAllocParms_t *)parm;
+	struct alloc_parms *parmsp = parm;
 
 	parmsp->number = number;
 	if (parmsp->used_wait_atomic)
-		atomic_set(parmsp->wait_atomic, 0);
+		atomic_set(&parmsp->wait_atomic, 0);
 	else
-		up(parmsp->sem);
+		up(&parmsp->sem);
 }
 
 static int allocateEvents(HvLpIndex remoteLp, int numEvents)
 {
-	struct doneAllocParms_t parms;
-	DECLARE_MUTEX_LOCKED(Semaphore);
-	atomic_t wait_atomic;
+	struct alloc_parms parms;
 
-	if (in_atomic()) {
+	if (system_state != SYSTEM_RUNNING) {
 		parms.used_wait_atomic = 1;
-		atomic_set(&wait_atomic, 1);
-		parms.wait_atomic = &wait_atomic;
+		atomic_set(&parms.wait_atomic, 1);
 	} else {
 		parms.used_wait_atomic = 0;
-		parms.sem = &Semaphore;
+		init_MUTEX_LOCKED(&parms.sem);
 	}
 	mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250,	/* It would be nice to put a real number here! */
 			    numEvents, &viopath_donealloc, &parms);
-	if (in_atomic()) {
-		while (atomic_read(&wait_atomic))
+	if (system_state != SYSTEM_RUNNING) {
+		while (atomic_read(&parms.wait_atomic))
 			mb();
 	} else
-		down(&Semaphore);
+		down(&parms.sem);
 	return parms.number;
 }
 
@@ -558,8 +556,7 @@ int viopath_close(HvLpIndex remoteLp, in
 	unsigned long flags;
 	int i;
 	int numOpen;
-	struct doneAllocParms_t doneAllocParms;
-	DECLARE_MUTEX_LOCKED(Semaphore);
+	struct alloc_parms parms;
 
 	if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid))
 		return -EINVAL;
@@ -580,11 +577,11 @@ int viopath_close(HvLpIndex remoteLp, in
 
 	spin_unlock_irqrestore(&statuslock, flags);
 
-	doneAllocParms.used_wait_atomic = 0;
-	doneAllocParms.sem = &Semaphore;
+	parms.used_wait_atomic = 0;
+	init_MUTEX_LOCKED(&parms.sem);
 	mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,
-			      numReq, &viopath_donealloc, &doneAllocParms);
-	down(&Semaphore);
+			      numReq, &viopath_donealloc, &parms);
+	down(&parms.sem);
 
 	spin_lock_irqsave(&statuslock, flags);
 	for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)
diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c
+++ b/arch/ppc64/kernel/xics.c
@@ -432,6 +432,7 @@ void xics_cause_IPI(int cpu)
 {
 	ops->qirr_info(cpu, IPI_PRIORITY);
 }
+#endif /* CONFIG_SMP */
 
 void xics_setup_cpu(void)
 {
@@ -439,9 +440,17 @@ void xics_setup_cpu(void)
 
 	ops->cppr_info(cpu, 0xff);
 	iosync();
-}
 
-#endif /* CONFIG_SMP */
+	/*
+	 * Put the calling processor into the GIQ.  This is really only
+	 * necessary from a secondary thread as the OF start-cpu interface
+	 * performs this function for us on primary threads.
+	 *
+	 * XXX: undo of teardown on kexec needs this too, as may hotplug
+	 */
+	rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
+		(1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
+}
 
 void xics_init_IRQ(void)
 {
@@ -563,8 +572,7 @@ nextnode:
 	for (; i < NR_IRQS; ++i)
 		get_irq_desc(i)->handler = &xics_pic;
 
-	ops->cppr_info(boot_cpuid, 0xff);
-	iosync();
+	xics_setup_cpu();
 
 	ppc64_boot_msg(0x21, "XICS Done");
 }
@@ -654,7 +662,7 @@ void xics_migrate_irqs_away(void)
 	/* remove ourselves from the global interrupt queue */
 	status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
 		(1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
-	WARN_ON(status != 0);
+	WARN_ON(status < 0);
 
 	/* Allow IPIs again... */
 	ops->cppr_info(cpu, DEFAULT_PRIORITY);
@@ -704,15 +712,8 @@ void xics_migrate_irqs_away(void)
 		       virq, cpu);
 
 		/* Reset affinity to all cpus */
-		xics_status[0] = default_distrib_server;
-
-		status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
-				xics_status[0], xics_status[1]);
-		if (status)
-			printk(KERN_ERR "migrate_irqs_away: irq=%d "
-					"ibm,set-xive returns %d\n",
-					virq, status);
-
+		desc->handler->set_affinity(virq, CPU_MASK_ALL);
+		irq_affinity[virq] = CPU_MASK_ALL;
 unlock:
 		spin_unlock_irqrestore(&desc->lock, flags);
 	}
diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c
--- a/arch/ppc64/mm/fault.c
+++ b/arch/ppc64/mm/fault.c
@@ -91,8 +91,9 @@ int do_page_fault(struct pt_regs *regs, 
 	struct mm_struct *mm = current->mm;
 	siginfo_t info;
 	unsigned long code = SEGV_MAPERR;
-	unsigned long is_write = error_code & 0x02000000;
+	unsigned long is_write = error_code & DSISR_ISSTORE;
 	unsigned long trap = TRAP(regs);
+ 	unsigned long is_exec = trap == 0x400;
 
 	BUG_ON((trap == 0x380) || (trap == 0x480));
 
@@ -109,7 +110,7 @@ int do_page_fault(struct pt_regs *regs, 
 	if (!user_mode(regs) && (address >= TASK_SIZE))
 		return SIGSEGV;
 
-	if (error_code & 0x00400000) {
+	if (error_code & DSISR_DABRMATCH) {
 		if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
 					11, SIGSEGV) == NOTIFY_STOP)
 			return 0;
@@ -199,16 +200,19 @@ int do_page_fault(struct pt_regs *regs, 
 good_area:
 	code = SEGV_ACCERR;
 
+	if (is_exec) {
+		/* protection fault */
+		if (error_code & DSISR_PROTFAULT)
+			goto bad_area;
+		if (!(vma->vm_flags & VM_EXEC))
+			goto bad_area;
 	/* a write */
-	if (is_write) {
+	} else if (is_write) {
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	/* a read */
 	} else {
-		/* protection fault */
-		if (error_code & 0x08000000)
-			goto bad_area;
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+		if (!(vma->vm_flags & VM_READ))
 			goto bad_area;
 	}
 
@@ -251,6 +255,12 @@ bad_area_nosemaphore:
 		return 0;
 	}
 
+	if (trap == 0x400 && (error_code & DSISR_PROTFAULT)
+	    && printk_ratelimit())
+		printk(KERN_CRIT "kernel tried to execute NX-protected"
+		       " page (%lx) - exploit attempt? (uid: %d)\n",
+		       address, current->uid);
+
 	return SIGSEGV;
 
 /*
diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S
--- a/arch/ppc64/mm/hash_low.S
+++ b/arch/ppc64/mm/hash_low.S
@@ -85,11 +85,14 @@ _GLOBAL(__hash_page)
 	bne-	htab_wrong_access
 	/* Check if PTE is busy */
 	andi.	r0,r31,_PAGE_BUSY
-	bne-	1b
+	/* If so, just bail out and refault if needed. Someone else
+	 * is changing this PTE anyway and might hash it.
+	 */
+	bne-	bail_ok
 	/* Prepare new PTE value (turn access RW into DIRTY, then
 	 * add BUSY,HASHPTE and ACCESSED)
 	 */
-	rlwinm	r30,r4,5,24,24	/* _PAGE_RW -> _PAGE_DIRTY */
+	rlwinm	r30,r4,32-9+7,31-7,31-7	/* _PAGE_RW -> _PAGE_DIRTY */
 	or	r30,r30,r31
 	ori	r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
 	/* Write the linux PTE atomically (setting busy) */
@@ -112,11 +115,11 @@ _GLOBAL(__hash_page)
 	rldicl	r5,r5,0,25		/* vsid & 0x0000007fffffffff */
 	rldicl	r0,r3,64-12,48		/* (ea >> 12) & 0xffff */
 	xor	r28,r5,r0
-	
-	/* Convert linux PTE bits into HW equivalents
-	 */
-	andi.	r3,r30,0x1fa		/* Get basic set of flags */
-	rlwinm	r0,r30,32-2+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
+
+	/* Convert linux PTE bits into HW equivalents */
+	andi.	r3,r30,0x1fe		/* Get basic set of flags */
+	xori	r3,r3,HW_NO_EXEC	/* _PAGE_EXEC -> NOEXEC */
+	rlwinm	r0,r30,32-9+1,30,30	/* _PAGE_RW -> _PAGE_USER (r0) */
 	rlwinm	r4,r30,32-7+1,30,30	/* _PAGE_DIRTY -> _PAGE_USER (r4) */
 	and	r0,r0,r4		/* _PAGE_RW & _PAGE_DIRTY -> r0 bit 30 */
 	andc	r0,r30,r0		/* r0 = pte & ~r0 */
@@ -215,6 +218,10 @@ _GLOBAL(htab_call_hpte_remove)
 	/* Try all again */
 	b	htab_insert_pte	
 
+bail_ok:
+	li	r3,0
+	b	bail
+
 htab_pte_insert_ok:
 	/* Insert slot number & secondary bit in PTE */
 	rldimi	r30,r3,12,63-15
diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c
--- a/arch/ppc64/mm/hash_native.c
+++ b/arch/ppc64/mm/hash_native.c
@@ -217,10 +217,10 @@ static long native_hpte_updatepp(unsigne
 	}
 
 	/* Ensure it is out of the tlb too */
-	if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+	if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) {
 		tlbiel(va);
 	} else {
-		int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+		int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
 		if (lock_tlbie)
 			spin_lock(&native_tlbie_lock);
@@ -245,7 +245,7 @@ static void native_hpte_updateboltedpp(u
 	unsigned long vsid, va, vpn, flags = 0;
 	long slot;
 	HPTE *hptep;
-	int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+	int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
 	vsid = get_kernel_vsid(ea);
 	va = (vsid << 28) | (ea & 0x0fffffff);
@@ -273,7 +273,7 @@ static void native_hpte_invalidate(unsig
 	Hpte_dword0 dw0;
 	unsigned long avpn = va >> 23;
 	unsigned long flags;
-	int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+	int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
 	if (large)
 		avpn &= ~0x1UL;
@@ -292,7 +292,7 @@ static void native_hpte_invalidate(unsig
 	}
 
 	/* Invalidate the tlb */
-	if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+	if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) {
 		tlbiel(va);
 	} else {
 		if (lock_tlbie)
@@ -320,8 +320,7 @@ static void native_flush_hash_range(unsi
 
 	j = 0;
 	for (i = 0; i < number; i++) {
-		if ((batch->addr[i] >= USER_START) &&
-		    (batch->addr[i] <= USER_END))
+		if (batch->addr[i] < KERNELBASE)
 			vsid = get_vsid(context, batch->addr[i]);
 		else
 			vsid = get_kernel_vsid(batch->addr[i]);
@@ -360,7 +359,7 @@ static void native_flush_hash_range(unsi
 		j++;
 	}
 
-	if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+	if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) {
 		asm volatile("ptesync":::"memory");
 
 		for (i = 0; i < j; i++)
@@ -368,7 +367,7 @@ static void native_flush_hash_range(unsi
 
 		asm volatile("ptesync":::"memory");
 	} else {
-		int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+		int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
 		if (lock_tlbie)
 			spin_lock(&native_tlbie_lock);
diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
--- a/arch/ppc64/mm/hash_utils.c
+++ b/arch/ppc64/mm/hash_utils.c
@@ -51,6 +51,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
+#include <asm/sections.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -95,6 +96,7 @@ static inline void create_pte_mapping(un
 {
 	unsigned long addr;
 	unsigned int step;
+	unsigned long tmp_mode;
 
 	if (large)
 		step = 16*MB;
@@ -112,6 +114,13 @@ static inline void create_pte_mapping(un
 		else
 			vpn = va >> PAGE_SHIFT;
 
+
+		tmp_mode = mode;
+		
+		/* Make non-kernel text non-executable */
+		if (!in_kernel_text(addr))
+			tmp_mode = mode | HW_NO_EXEC;
+
 		hash = hpt_hash(vpn, large);
 
 		hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
@@ -120,12 +129,12 @@ static inline void create_pte_mapping(un
 		if (systemcfg->platform & PLATFORM_LPAR)
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
 				virt_to_abs(addr) >> PAGE_SHIFT,
-				0, mode, 1, large);
+				0, tmp_mode, 1, large);
 		else
 #endif /* CONFIG_PPC_PSERIES */
 			ret = native_hpte_insert(hpteg, va,
 				virt_to_abs(addr) >> PAGE_SHIFT,
-				0, mode, 1, large);
+				0, tmp_mode, 1, large);
 
 		if (ret == -1) {
 			ppc64_terminate_msg(0x20, "create_pte_mapping");
@@ -140,6 +149,8 @@ void __init htab_initialize(void)
 	unsigned long pteg_count;
 	unsigned long mode_rw;
 	int i, use_largepages = 0;
+	unsigned long base = 0, size = 0;
+	extern unsigned long tce_alloc_start, tce_alloc_end;
 
 	DBG(" -> htab_initialize()\n");
 
@@ -190,13 +201,11 @@ void __init htab_initialize(void)
 	 * _NOT_ map it to avoid cache paradoxes as it's remapped non
 	 * cacheable later on
 	 */
-	if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+	if (cpu_has_feature(CPU_FTR_16M_PAGE))
 		use_largepages = 1;
 
 	/* create bolted the linear mapping in the hash table */
 	for (i=0; i < lmb.memory.cnt; i++) {
-		unsigned long base, size;
-
 		base = lmb.memory.region[i].physbase + KERNELBASE;
 		size = lmb.memory.region[i].size;
 
@@ -225,6 +234,25 @@ void __init htab_initialize(void)
 #endif /* CONFIG_U3_DART */
 		create_pte_mapping(base, base + size, mode_rw, use_largepages);
 	}
+
+	/*
+	 * If we have a memory_limit and we've allocated TCEs then we need to
+	 * explicitly map the TCE area at the top of RAM. We also cope with the
+	 * case that the TCEs start below memory_limit.
+	 * tce_alloc_start/end are 16MB aligned so the mapping should work
+	 * for either 4K or 16MB pages.
+	 */
+	if (tce_alloc_start) {
+		tce_alloc_start += KERNELBASE;
+		tce_alloc_end += KERNELBASE;
+
+		if (base + size >= tce_alloc_start)
+			tce_alloc_start = base + size + 1;
+
+		create_pte_mapping(tce_alloc_start, tce_alloc_end,
+			mode_rw, use_largepages);
+	}
+
 	DBG(" <- htab_initialize()\n");
 }
 #undef KB
@@ -238,8 +266,6 @@ unsigned int hash_page_do_lazy_icache(un
 {
 	struct page *page;
 
-#define PPC64_HWNOEXEC (1 << 2)
-
 	if (!pfn_valid(pte_pfn(pte)))
 		return pp;
 
@@ -251,7 +277,7 @@ unsigned int hash_page_do_lazy_icache(un
 			__flush_dcache_icache(page_address(page));
 			set_bit(PG_arch_1, &page->flags);
 		} else
-			pp |= PPC64_HWNOEXEC;
+			pp |= HW_NO_EXEC;
 	}
 	return pp;
 }
@@ -272,24 +298,23 @@ int hash_page(unsigned long ea, unsigned
 	int local = 0;
 	cpumask_t tmp;
 
+	if ((ea & ~REGION_MASK) > EADDR_MASK)
+		return 1;
+
  	switch (REGION_ID(ea)) {
 	case USER_REGION_ID:
 		user_region = 1;
 		mm = current->mm;
-		if ((ea > USER_END) || (! mm))
+		if (! mm)
 			return 1;
 
 		vsid = get_vsid(mm->context.id, ea);
 		break;
 	case IO_REGION_ID:
-		if (ea > IMALLOC_END)
-			return 1;
 		mm = &ioremap_mm;
 		vsid = get_kernel_vsid(ea);
 		break;
 	case VMALLOC_REGION_ID:
-		if (ea > VMALLOC_END)
-			return 1;
 		mm = &init_mm;
 		vsid = get_kernel_vsid(ea);
 		break;
@@ -336,7 +361,7 @@ void flush_hash_page(unsigned long conte
 	unsigned long vsid, vpn, va, hash, secondary, slot;
 	unsigned long huge = pte_huge(pte);
 
-	if ((ea >= USER_START) && (ea <= USER_END))
+	if (ea < KERNELBASE)
 		vsid = get_vsid(context, ea);
 	else
 		vsid = get_kernel_vsid(ea);
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -42,7 +42,7 @@ static inline int hugepgd_index(unsigned
 	return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT;
 }
 
-static pgd_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr)
+static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr)
 {
 	int index;
 
@@ -52,21 +52,21 @@ static pgd_t *hugepgd_offset(struct mm_s
 
 	index = hugepgd_index(addr);
 	BUG_ON(index >= PTRS_PER_HUGEPGD);
-	return mm->context.huge_pgdir + index;
+	return (pud_t *)(mm->context.huge_pgdir + index);
 }
 
-static inline pte_t *hugepte_offset(pgd_t *dir, unsigned long addr)
+static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr)
 {
 	int index;
 
-	if (pgd_none(*dir))
+	if (pud_none(*dir))
 		return NULL;
 
 	index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE;
-	return (pte_t *)pgd_page(*dir) + index;
+	return (pte_t *)pud_page(*dir) + index;
 }
 
-static pgd_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr)
+static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr)
 {
 	BUG_ON(! in_hugepage_area(mm->context, addr));
 
@@ -90,10 +90,9 @@ static pgd_t *hugepgd_alloc(struct mm_st
 	return hugepgd_offset(mm, addr);
 }
 
-static pte_t *hugepte_alloc(struct mm_struct *mm, pgd_t *dir,
-			    unsigned long addr)
+static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr)
 {
-	if (! pgd_present(*dir)) {
+	if (! pud_present(*dir)) {
 		pte_t *new;
 
 		spin_unlock(&mm->page_table_lock);
@@ -104,7 +103,7 @@ static pte_t *hugepte_alloc(struct mm_st
 		 * Because we dropped the lock, we should re-check the
 		 * entry, as somebody else could have populated it..
 		 */
-		if (pgd_present(*dir)) {
+		if (pud_present(*dir)) {
 			if (new)
 				kmem_cache_free(zero_cache, new);
 		} else {
@@ -115,7 +114,7 @@ static pte_t *hugepte_alloc(struct mm_st
 			ptepage = virt_to_page(new);
 			ptepage->mapping = (void *) mm;
 			ptepage->index = addr & HUGEPGDIR_MASK;
-			pgd_populate(mm, dir, new);
+			pud_populate(mm, dir, new);
 		}
 	}
 
@@ -124,36 +123,37 @@ static pte_t *hugepte_alloc(struct mm_st
 
 static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
-	pgd_t *pgd;
+	pud_t *pud;
 
 	BUG_ON(! in_hugepage_area(mm->context, addr));
 
-	pgd = hugepgd_offset(mm, addr);
-	if (! pgd)
+	pud = hugepgd_offset(mm, addr);
+	if (! pud)
 		return NULL;
 
-	return hugepte_offset(pgd, addr);
+	return hugepte_offset(pud, addr);
 }
 
 static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
 {
-	pgd_t *pgd;
+	pud_t *pud;
 
 	BUG_ON(! in_hugepage_area(mm->context, addr));
 
-	pgd = hugepgd_alloc(mm, addr);
-	if (! pgd)
+	pud = hugepgd_alloc(mm, addr);
+	if (! pud)
 		return NULL;
 
-	return hugepte_alloc(mm, pgd, addr);
+	return hugepte_alloc(mm, pud, addr);
 }
 
 static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
-			 struct page *page, pte_t *ptep, int write_access)
+			 unsigned long addr, struct page *page,
+			 pte_t *ptep, int write_access)
 {
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 	if (write_access) {
 		entry =
 		    pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -163,7 +163,7 @@ static void set_huge_pte(struct mm_struc
 	entry = pte_mkyoung(entry);
 	entry = pte_mkhuge(entry);
 
-	set_pte(ptep, entry);
+	set_pte_at(mm, addr, ptep, entry);
 }
 
 /*
@@ -202,8 +202,6 @@ static int prepare_low_seg_for_htlb(stru
 	unsigned long start = seg << SID_SHIFT;
 	unsigned long end = (seg+1) << SID_SHIFT;
 	struct vm_area_struct *vma;
-	unsigned long addr;
-	struct mmu_gather *tlb;
 
 	BUG_ON(seg >= 16);
 
@@ -212,41 +210,6 @@ static int prepare_low_seg_for_htlb(stru
 	if (vma && (vma->vm_start < end))
 		return -EBUSY;
 
-	/* Clean up any leftover PTE pages in the region */
-	spin_lock(&mm->page_table_lock);
-	tlb = tlb_gather_mmu(mm, 0);
-	for (addr = start; addr < end; addr += PMD_SIZE) {
-		pgd_t *pgd = pgd_offset(mm, addr);
-		pmd_t *pmd;
-		struct page *page;
-		pte_t *pte;
-		int i;
-
-		if (pgd_none(*pgd))
-			continue;
-		pmd = pmd_offset(pgd, addr);
-		if (!pmd || pmd_none(*pmd))
-			continue;
-		if (pmd_bad(*pmd)) {
-			pmd_ERROR(*pmd);
-			pmd_clear(pmd);
-			continue;
-		}
-		pte = (pte_t *)pmd_page_kernel(*pmd);
-		/* No VMAs, so there should be no PTEs, check just in case. */
-		for (i = 0; i < PTRS_PER_PTE; i++) {
-			BUG_ON(!pte_none(*pte));
-			pte++;
-		}
-		page = pmd_page(*pmd);
-		pmd_clear(pmd);
-		mm->nr_ptes--;
-		dec_page_state(nr_page_table_pages);
-		pte_free_tlb(tlb, page);
-	}
-	tlb_finish_mmu(tlb, start, end);
-	spin_unlock(&mm->page_table_lock);
-
 	return 0;
 }
 
@@ -315,8 +278,8 @@ int copy_hugetlb_page_range(struct mm_st
 		
 		ptepage = pte_page(entry);
 		get_page(ptepage);
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
-		set_pte(dst_pte, entry);
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
+		set_pte_at(dst, addr, dst_pte, entry);
 
 		addr += HPAGE_SIZE;
 	}
@@ -421,24 +384,14 @@ void unmap_hugepage_range(struct vm_area
 
 		pte = *ptep;
 		page = pte_page(pte);
-		pte_clear(ptep);
+		pte_clear(mm, addr, ptep);
 
 		put_page(page);
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
 	flush_tlb_pending();
 }
 
-void hugetlb_free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
-			   unsigned long start, unsigned long end)
-{
-	/* Because the huge pgtables are only 2 level, they can take
-	 * at most around 4M, much less than one hugepage which the
-	 * process is presumably entitled to use.  So we don't bother
-	 * freeing up the pagetables on unmap, and wait until
-	 * destroy_context() to clean up the lot. */
-}
-
 int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
 {
 	struct mm_struct *mm = current->mm;
@@ -486,7 +439,7 @@ int hugetlb_prefault(struct address_spac
 				goto out;
 			}
 		}
-		set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
+		set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE);
 	}
 out:
 	spin_unlock(&mm->page_table_lock);
@@ -512,7 +465,7 @@ unsigned long arch_get_unmapped_area(str
 		vma = find_vma(mm, addr);
 		if (((TASK_SIZE - len) >= addr)
 		    && (!vma || (addr+len) <= vma->vm_start)
-		    && !is_hugepage_only_range(addr,len))
+		    && !is_hugepage_only_range(mm, addr,len))
 			return addr;
 	}
 	start_addr = addr = mm->free_area_cache;
@@ -522,7 +475,7 @@ full_search:
 	while (TASK_SIZE - len >= addr) {
 		BUG_ON(vma && (addr >= vma->vm_end));
 
-		if (touches_hugepage_low_range(addr, len)) {
+		if (touches_hugepage_low_range(mm, addr, len)) {
 			addr = ALIGN(addr+1, 1<<SID_SHIFT);
 			vma = find_vma(mm, addr);
 			continue;
@@ -583,7 +536,7 @@ arch_get_unmapped_area_topdown(struct fi
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
 				(!vma || addr + len <= vma->vm_start)
-				&& !is_hugepage_only_range(addr,len))
+				&& !is_hugepage_only_range(mm, addr,len))
 			return addr;
 	}
 
@@ -596,7 +549,7 @@ try_again:
 	addr = (mm->free_area_cache - len) & PAGE_MASK;
 	do {
 hugepage_recheck:
-		if (touches_hugepage_low_range(addr, len)) {
+		if (touches_hugepage_low_range(mm, addr, len)) {
 			addr = (addr & ((~0) << SID_SHIFT)) - len;
 			goto hugepage_recheck;
 		} else if (touches_hugepage_high_range(addr, len)) {
@@ -709,7 +662,7 @@ unsigned long hugetlb_get_unmapped_area(
 	if (len & ~HPAGE_MASK)
 		return -EINVAL;
 
-	if (!(cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE))
+	if (!cpu_has_feature(CPU_FTR_16M_PAGE))
 		return -EINVAL;
 
 	if (test_thread_flag(TIF_32BIT)) {
@@ -755,10 +708,10 @@ void hugetlb_mm_free_pgd(struct mm_struc
 
 	/* cleanup any hugepte pages leftover */
 	for (i = 0; i < PTRS_PER_HUGEPGD; i++) {
-		pgd_t *pgd = pgdir + i;
+		pud_t *pud = (pud_t *)(pgdir + i);
 
-		if (! pgd_none(*pgd)) {
-			pte_t *pte = (pte_t *)pgd_page(*pgd);
+		if (! pud_none(*pud)) {
+			pte_t *pte = (pte_t *)pud_page(*pud);
 			struct page *ptepage = virt_to_page(pte);
 
 			ptepage->mapping = NULL;
@@ -766,7 +719,7 @@ void hugetlb_mm_free_pgd(struct mm_struc
 			BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE));
 			kmem_cache_free(zero_cache, pte);
 		}
-		pgd_clear(pgd);
+		pud_clear(pud);
 	}
 
 	BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE));
@@ -781,7 +734,6 @@ int hash_huge_page(struct mm_struct *mm,
 {
 	pte_t *ptep;
 	unsigned long va, vpn;
-	int is_write;
 	pte_t old_pte, new_pte;
 	unsigned long hpteflags, prpn;
 	long slot;
@@ -808,8 +760,7 @@ int hash_huge_page(struct mm_struct *mm,
 	 * Check the user's access rights to the page.  If access should be
 	 * prevented then send the problem up to do_page_fault.
 	 */
-	is_write = access & _PAGE_RW;
-	if (unlikely(is_write && !(pte_val(*ptep) & _PAGE_RW)))
+	if (unlikely(access & ~pte_val(*ptep)))
 		goto out;
 	/*
 	 * At this point, we have a pte (old_pte) which can be used to build
@@ -828,6 +779,8 @@ int hash_huge_page(struct mm_struct *mm,
 	new_pte = old_pte;
 
 	hpteflags = 0x2 | (! (pte_val(new_pte) & _PAGE_RW));
+ 	/* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */
+	hpteflags |= ((pte_val(new_pte) & _PAGE_EXEC) ? 0 : HW_NO_EXEC);
 
 	/* Check if pte already has an hpte (case 2) */
 	if (unlikely(pte_val(old_pte) & _PAGE_HASHPTE)) {
diff --git a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c
--- a/arch/ppc64/mm/imalloc.c
+++ b/arch/ppc64/mm/imalloc.c
@@ -14,6 +14,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/semaphore.h>
+#include <asm/imalloc.h>
 
 static DECLARE_MUTEX(imlist_sem);
 struct vm_struct * imlist = NULL;
@@ -23,11 +24,11 @@ static int get_free_im_addr(unsigned lon
 	unsigned long addr;
 	struct vm_struct **p, *tmp;
 
-	addr = IMALLOC_START;
+	addr = ioremap_bot;
 	for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
 		if (size + addr < (unsigned long) tmp->addr)
 			break;
-		if ((unsigned long)tmp->addr >= IMALLOC_START) 
+		if ((unsigned long)tmp->addr >= ioremap_bot)
 			addr = tmp->size + (unsigned long) tmp->addr;
 		if (addr > IMALLOC_END-size) 
 			return 1;
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -38,6 +38,7 @@
 #include <linux/highmem.h>
 #include <linux/idr.h>
 #include <linux/nodemask.h>
+#include <linux/module.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
@@ -62,6 +63,8 @@
 #include <asm/system.h>
 #include <asm/iommu.h>
 #include <asm/abs_addr.h>
+#include <asm/vdso.h>
+#include <asm/imalloc.h>
 
 int mem_init_done;
 unsigned long ioremap_bot = IMALLOC_BASE;
@@ -134,14 +137,78 @@ void iounmap(volatile void __iomem *addr
 
 #else
 
+static void unmap_im_area_pte(pmd_t *pmd, unsigned long addr,
+				  unsigned long end)
+{
+	pte_t *pte;
+
+	pte = pte_offset_kernel(pmd, addr);
+	do {
+		pte_t ptent = ptep_get_and_clear(&ioremap_mm, addr, pte);
+		WARN_ON(!pte_none(ptent) && !pte_present(ptent));
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+}
+
+static inline void unmap_im_area_pmd(pud_t *pud, unsigned long addr,
+				     unsigned long end)
+{
+	pmd_t *pmd;
+	unsigned long next;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		unmap_im_area_pte(pmd, addr, next);
+	} while (pmd++, addr = next, addr != end);
+}
+
+static inline void unmap_im_area_pud(pgd_t *pgd, unsigned long addr,
+				     unsigned long end)
+{
+	pud_t *pud;
+	unsigned long next;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		unmap_im_area_pmd(pud, addr, next);
+	} while (pud++, addr = next, addr != end);
+}
+
+static void unmap_im_area(unsigned long addr, unsigned long end)
+{
+	struct mm_struct *mm = &ioremap_mm;
+	unsigned long next;
+	pgd_t *pgd;
+
+	spin_lock(&mm->page_table_lock);
+
+	pgd = pgd_offset_i(addr);
+	flush_cache_vunmap(addr, end);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		unmap_im_area_pud(pgd, addr, next);
+	} while (pgd++, addr = next, addr != end);
+	flush_tlb_kernel_range(start, end);
+
+	spin_unlock(&mm->page_table_lock);
+}
+
 /*
  * map_io_page currently only called by __ioremap
  * map_io_page adds an entry to the ioremap page table
  * and adds an entry to the HPT, possibly bolting it
  */
-static void map_io_page(unsigned long ea, unsigned long pa, int flags)
+static int map_io_page(unsigned long ea, unsigned long pa, int flags)
 {
 	pgd_t *pgdp;
+	pud_t *pudp;
 	pmd_t *pmdp;
 	pte_t *ptep;
 	unsigned long vsid;
@@ -149,11 +216,18 @@ static void map_io_page(unsigned long ea
 	if (mem_init_done) {
 		spin_lock(&ioremap_mm.page_table_lock);
 		pgdp = pgd_offset_i(ea);
-		pmdp = pmd_alloc(&ioremap_mm, pgdp, ea);
+		pudp = pud_alloc(&ioremap_mm, pgdp, ea);
+		if (!pudp)
+			return -ENOMEM;
+		pmdp = pmd_alloc(&ioremap_mm, pudp, ea);
+		if (!pmdp)
+			return -ENOMEM;
 		ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea);
-
+		if (!ptep)
+			return -ENOMEM;
 		pa = abs_to_phys(pa);
-		set_pte(ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
+		set_pte_at(&ioremap_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
+							  __pgprot(flags)));
 		spin_unlock(&ioremap_mm.page_table_lock);
 	} else {
 		unsigned long va, vpn, hash, hpteg;
@@ -178,6 +252,7 @@ static void map_io_page(unsigned long ea
 			panic("map_io_page: could not insert mapping");
 		}
 	}
+	return 0;
 }
 
 
@@ -189,27 +264,30 @@ static void __iomem * __ioremap_com(unsi
 
 	if ((flags & _PAGE_PRESENT) == 0)
 		flags |= pgprot_val(PAGE_KERNEL);
-	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
-		flags |= _PAGE_GUARDED;
 
-	for (i = 0; i < size; i += PAGE_SIZE) {
-		map_io_page(ea+i, pa+i, flags);
-	}
+	for (i = 0; i < size; i += PAGE_SIZE)
+		if (map_io_page(ea+i, pa+i, flags))
+			goto failure;
 
 	return (void __iomem *) (ea + (addr & ~PAGE_MASK));
+ failure:
+	if (mem_init_done)
+		unmap_im_area(ea, ea + size);
+	return NULL;
 }
 
 
 void __iomem *
 ioremap(unsigned long addr, unsigned long size)
 {
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
+	return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED);
 }
 
-void __iomem *
-__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+void __iomem * __ioremap(unsigned long addr, unsigned long size,
+			 unsigned long flags)
 {
 	unsigned long pa, ea;
+	void __iomem *ret;
 
 	/*
 	 * Choose an address to map it to.
@@ -232,12 +310,16 @@ __ioremap(unsigned long addr, unsigned l
 		if (area == NULL)
 			return NULL;
 		ea = (unsigned long)(area->addr);
+		ret = __ioremap_com(addr, pa, ea, size, flags);
+		if (!ret)
+			im_free(area->addr);
 	} else {
 		ea = ioremap_bot;
-		ioremap_bot += size;
+		ret = __ioremap_com(addr, pa, ea, size, flags);
+		if (ret)
+			ioremap_bot += size;
 	}
-
-	return __ioremap_com(addr, pa, ea, size, flags);
+	return ret;
 }
 
 #define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
@@ -246,6 +328,7 @@ int __ioremap_explicit(unsigned long pa,
 		       unsigned long size, unsigned long flags)
 {
 	struct vm_struct *area;
+	void __iomem *ret;
 	
 	/* For now, require page-aligned values for pa, ea, and size */
 	if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
@@ -270,12 +353,18 @@ int __ioremap_explicit(unsigned long pa,
 			return 1;
 		}
 		if (ea != (unsigned long) area->addr) {
-			printk(KERN_ERR "unexpected addr return from im_get_area\n");
+			printk(KERN_ERR "unexpected addr return from "
+			       "im_get_area\n");
 			return 1;
 		}
 	}
 	
-	if (__ioremap_com(pa, pa, ea, size, flags) != (void *) ea) {
+	ret = __ioremap_com(pa, pa, ea, size, flags);
+	if (ret == NULL) {
+		printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
+		return 1;
+	}
+	if (ret != (void *) ea) {
 		printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
 		return 1;
 	}
@@ -283,108 +372,28 @@ int __ioremap_explicit(unsigned long pa,
 	return 0;
 }
 
-static void unmap_im_area_pte(pmd_t *pmd, unsigned long address,
-				  unsigned long size)
-{
-	unsigned long end;
-	pte_t *pte;
-
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-
-	pte = pte_offset_kernel(pmd, address);
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-
-	do {
-		pte_t page;
-		page = ptep_get_and_clear(pte);
-		address += PAGE_SIZE;
-		pte++;
-		if (pte_none(page))
-			continue;
-		if (pte_present(page))
-			continue;
-		printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
-	} while (address < end);
-}
-
-static void unmap_im_area_pmd(pgd_t *dir, unsigned long address,
-				  unsigned long size)
-{
-	unsigned long end;
-	pmd_t *pmd;
-
-	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 {
-		unmap_im_area_pte(pmd, address, end - address);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-}
-
 /*  
  * Unmap an IO region and remove it from imalloc'd list.
  * Access to IO memory should be serialized by driver.
  * This code is modeled after vmalloc code - unmap_vm_area()
  *
- * XXX	what about calls before mem_init_done (ie python_countermeasures())	
+ * XXX	what about calls before mem_init_done (ie python_countermeasures())
  */
 void iounmap(volatile void __iomem *token)
 {
-	unsigned long address, start, end, size;
-	struct mm_struct *mm;
-	pgd_t *dir;
+	unsigned long address, size;
 	void *addr;
 
-	if (!mem_init_done) {
+	if (!mem_init_done)
 		return;
-	}
 	
 	addr = (void *) ((unsigned long __force) token & PAGE_MASK);
 	
-	if ((size = im_free(addr)) == 0) {
+	if ((size = im_free(addr)) == 0)
 		return;
-	}
 
 	address = (unsigned long)addr; 
-	start = address;
-	end = address + size;
-
-	mm = &ioremap_mm;
-	spin_lock(&mm->page_table_lock);
-
-	dir = pgd_offset_i(address);
-	flush_cache_vunmap(address, end);
-	do {
-		unmap_im_area_pmd(dir, address, end - address);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	flush_tlb_kernel_range(start, end);
-
-	spin_unlock(&mm->page_table_lock);
-	return;
+	unmap_im_area(address, address + size);
 }
 
 static int iounmap_subset_regions(unsigned long addr, unsigned long size)
@@ -441,6 +450,10 @@ int iounmap_explicit(volatile void __iom
 
 #endif
 
+EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+
 void free_initmem(void)
 {
 	unsigned long addr;
@@ -656,9 +669,8 @@ void __init paging_init(void)
 	zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
 	zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
 
-	free_area_init_node(0, &contig_page_data, zones_size,
+	free_area_init_node(0, NODE_DATA(0), zones_size,
 			    __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
-	mem_map = contig_page_data.node_mem_map;
 }
 #endif /* CONFIG_DISCONTIGMEM */
 
@@ -743,6 +755,8 @@ void __init mem_init(void)
 #ifdef CONFIG_PPC_ISERIES
 	iommu_vio_init();
 #endif
+	/* Initialize the vDSO */
+	vdso_init();
 }
 
 /*
@@ -752,18 +766,19 @@ void __init mem_init(void)
  */
 void flush_dcache_page(struct page *page)
 {
-	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
 		return;
 	/* avoid an atomic op if possible */
 	if (test_bit(PG_arch_1, &page->flags))
 		clear_bit(PG_arch_1, &page->flags);
 }
+EXPORT_SYMBOL(flush_dcache_page);
 
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
 	clear_page(page);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
 		return;
 	/*
 	 * We shouldnt have to do this, but some versions of glibc
@@ -775,6 +790,7 @@ void clear_user_page(void *page, unsigne
 	if (test_bit(PG_arch_1, &pg->flags))
 		clear_bit(PG_arch_1, &pg->flags);
 }
+EXPORT_SYMBOL(clear_user_page);
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
 		    struct page *pg)
@@ -796,7 +812,7 @@ void copy_user_page(void *vto, void *vfr
 		return;
 #endif
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
 		return;
 
 	/* avoid an atomic op if possible */
@@ -812,6 +828,7 @@ void flush_icache_user_range(struct vm_a
 	maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK);
 	flush_icache_range(maddr, maddr + len);
 }
+EXPORT_SYMBOL(flush_icache_user_range);
 
 /*
  * This is called at the end of handling a user page fault, when the
@@ -832,8 +849,8 @@ void update_mmu_cache(struct vm_area_str
 	unsigned long flags;
 
 	/* handle i-cache coherency */
-	if (!(cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) &&
-	    !(cur_cpu_spec->cpu_features & CPU_FTR_NOEXECUTE)) {
+	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) &&
+	    !cpu_has_feature(CPU_FTR_NOEXECUTE)) {
 		unsigned long pfn = pte_pfn(pte);
 		if (pfn_valid(pfn)) {
 			struct page *page = pfn_to_page(pfn);
@@ -900,3 +917,16 @@ void pgtable_cache_init(void)
 	if (!zero_cache)
 		panic("pgtable_cache_init(): could not create zero_cache!\n");
 }
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+			      unsigned long size, pgprot_t vma_prot)
+{
+	if (ppc_md.phys_mem_access_prot)
+		return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+
+	if (!page_is_ram(addr >> PAGE_SHIFT))
+		vma_prot = __pgprot(pgprot_val(vma_prot)
+				    | _PAGE_GUARDED | _PAGE_NO_CACHE);
+	return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -40,7 +40,6 @@ int nr_cpus_in_node[MAX_NUMNODES] = { [0
 
 struct pglist_data *node_data[MAX_NUMNODES];
 bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
-static unsigned long node0_io_hole_size;
 static int min_common_depth;
 
 /*
@@ -49,7 +48,8 @@ static int min_common_depth;
  */
 static struct {
 	unsigned long node_start_pfn;
-	unsigned long node_spanned_pages;
+	unsigned long node_end_pfn;
+	unsigned long node_present_pages;
 } init_node_data[MAX_NUMNODES] __initdata;
 
 EXPORT_SYMBOL(node_data);
@@ -186,14 +186,36 @@ static int __init find_min_common_depth(
 	return depth;
 }
 
-static unsigned long read_cell_ul(struct device_node *device, unsigned int **buf)
+static int __init get_mem_addr_cells(void)
+{
+	struct device_node *memory = NULL;
+	int rc;
+
+	memory = of_find_node_by_type(memory, "memory");
+	if (!memory)
+		return 0; /* it won't matter */
+
+	rc = prom_n_addr_cells(memory);
+	return rc;
+}
+
+static int __init get_mem_size_cells(void)
+{
+	struct device_node *memory = NULL;
+	int rc;
+
+	memory = of_find_node_by_type(memory, "memory");
+	if (!memory)
+		return 0; /* it won't matter */
+	rc = prom_n_size_cells(memory);
+	return rc;
+}
+
+static unsigned long read_n_cells(int n, unsigned int **buf)
 {
-	int i;
 	unsigned long result = 0;
 
-	i = prom_n_size_cells(device);
-	/* bug on i>2 ?? */
-	while (i--) {
+	while (n--) {
 		result = (result << 32) | **buf;
 		(*buf)++;
 	}
@@ -263,10 +285,40 @@ static int cpu_numa_callback(struct noti
 	return ret;
 }
 
+/*
+ * Check and possibly modify a memory region to enforce the memory limit.
+ *
+ * Returns the size the region should have to enforce the memory limit.
+ * This will either be the original value of size, a truncated value,
+ * or zero. If the returned value of size is 0 the region should be
+ * discarded as it lies wholy above the memory limit.
+ */
+static unsigned long __init numa_enforce_memory_limit(unsigned long start, unsigned long size)
+{
+	/*
+	 * We use lmb_end_of_DRAM() in here instead of memory_limit because
+	 * we've already adjusted it for the limit and it takes care of
+	 * having memory holes below the limit.
+	 */
+	extern unsigned long memory_limit;
+
+	if (! memory_limit)
+		return size;
+
+	if (start + size <= lmb_end_of_DRAM())
+		return size;
+
+	if (start >= lmb_end_of_DRAM())
+		return 0;
+
+	return lmb_end_of_DRAM() - start;
+}
+
 static int __init parse_numa_properties(void)
 {
 	struct device_node *cpu = NULL;
 	struct device_node *memory = NULL;
+	int addr_cells, size_cells;
 	int max_domain = 0;
 	long entries = lmb_end_of_DRAM() >> MEMORY_INCREMENT_SHIFT;
 	unsigned long i;
@@ -313,6 +365,8 @@ static int __init parse_numa_properties(
 		}
 	}
 
+	addr_cells = get_mem_addr_cells();
+	size_cells = get_mem_size_cells();
 	memory = NULL;
 	while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
 		unsigned long start;
@@ -329,8 +383,8 @@ static int __init parse_numa_properties(
 		ranges = memory->n_addrs;
 new_range:
 		/* these are order-sensitive, and modify the buffer pointer */
-		start = read_cell_ul(memory, &memcell_buf);
-		size = read_cell_ul(memory, &memcell_buf);
+		start = read_n_cells(addr_cells, &memcell_buf);
+		size = read_n_cells(size_cells, &memcell_buf);
 
 		start = _ALIGN_DOWN(start, MEMORY_INCREMENT);
 		size = _ALIGN_UP(size, MEMORY_INCREMENT);
@@ -348,33 +402,38 @@ new_range:
 		if (max_domain < numa_domain)
 			max_domain = numa_domain;
 
-		/* 
-		 * For backwards compatibility, OF splits the first node
-		 * into two regions (the first being 0-4GB). Check for
-		 * this simple case and complain if there is a gap in
-		 * memory
+		if (! (size = numa_enforce_memory_limit(start, size))) {
+			if (--ranges)
+				goto new_range;
+			else
+				continue;
+		}
+
+		/*
+		 * Initialize new node struct, or add to an existing one.
 		 */
-		if (init_node_data[numa_domain].node_spanned_pages) {
-			unsigned long shouldstart =
-				init_node_data[numa_domain].node_start_pfn +
-				init_node_data[numa_domain].node_spanned_pages;
-			if (shouldstart != (start / PAGE_SIZE)) {
-				/* Revert to non-numa for now */
-				printk(KERN_ERR
-				       "WARNING: Unexpected node layout: "
-				       "region start %lx length %lx\n",
-				       start, size);
-				printk(KERN_ERR "NUMA is disabled\n");
-				goto err;
-			}
-			init_node_data[numa_domain].node_spanned_pages +=
+		if (init_node_data[numa_domain].node_end_pfn) {
+			if ((start / PAGE_SIZE) <
+			    init_node_data[numa_domain].node_start_pfn)
+				init_node_data[numa_domain].node_start_pfn =
+					start / PAGE_SIZE;
+			if (((start / PAGE_SIZE) + (size / PAGE_SIZE)) >
+			    init_node_data[numa_domain].node_end_pfn)
+				init_node_data[numa_domain].node_end_pfn =
+					(start / PAGE_SIZE) +
+					(size / PAGE_SIZE);
+
+			init_node_data[numa_domain].node_present_pages +=
 				size / PAGE_SIZE;
 		} else {
 			node_set_online(numa_domain);
 
 			init_node_data[numa_domain].node_start_pfn =
 				start / PAGE_SIZE;
-			init_node_data[numa_domain].node_spanned_pages =
+			init_node_data[numa_domain].node_end_pfn =
+				init_node_data[numa_domain].node_start_pfn +
+				size / PAGE_SIZE;
+			init_node_data[numa_domain].node_present_pages =
 				size / PAGE_SIZE;
 		}
 
@@ -382,8 +441,7 @@ new_range:
 			numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
 				numa_domain;
 
-		ranges--;
-		if (ranges)
+		if (--ranges)
 			goto new_range;
 	}
 
@@ -391,14 +449,6 @@ new_range:
 		node_set_online(i);
 
 	return 0;
-err:
-	/* Something has gone wrong; revert any setup we've done */
-	for_each_node(i) {
-		node_set_offline(i);
-		init_node_data[i].node_start_pfn = 0;
-		init_node_data[i].node_spanned_pages = 0;
-	}
-	return -1;
 }
 
 static void __init setup_nonnuma(void)
@@ -426,12 +476,11 @@ static void __init setup_nonnuma(void)
 	node_set_online(0);
 
 	init_node_data[0].node_start_pfn = 0;
-	init_node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE;
+	init_node_data[0].node_end_pfn = lmb_end_of_DRAM() / PAGE_SIZE;
+	init_node_data[0].node_present_pages = total_ram / PAGE_SIZE;
 
 	for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT)
 		numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0;
-
-	node0_io_hole_size = top_of_ram - total_ram;
 }
 
 static void __init dump_numa_topology(void)
@@ -512,6 +561,8 @@ static unsigned long careful_allocation(
 void __init do_init_bootmem(void)
 {
 	int nid;
+	int addr_cells, size_cells;
+	struct device_node *memory = NULL;
 	static struct notifier_block ppc64_numa_nb = {
 		.notifier_call = cpu_numa_callback,
 		.priority = 1 /* Must run before sched domains notifier. */
@@ -535,7 +586,7 @@ void __init do_init_bootmem(void)
 		unsigned long bootmap_pages;
 
 		start_paddr = init_node_data[nid].node_start_pfn * PAGE_SIZE;
-		end_paddr = start_paddr + (init_node_data[nid].node_spanned_pages * PAGE_SIZE);
+		end_paddr = init_node_data[nid].node_end_pfn * PAGE_SIZE;
 
 		/* Allocate the node structure node local if possible */
 		NODE_DATA(nid) = (struct pglist_data *)careful_allocation(nid,
@@ -551,9 +602,9 @@ void __init do_init_bootmem(void)
 		NODE_DATA(nid)->node_start_pfn =
 			init_node_data[nid].node_start_pfn;
 		NODE_DATA(nid)->node_spanned_pages =
-			init_node_data[nid].node_spanned_pages;
+			end_paddr - start_paddr;
 
-		if (init_node_data[nid].node_spanned_pages == 0)
+		if (NODE_DATA(nid)->node_spanned_pages == 0)
   			continue;
 
   		dbg("start_paddr = %lx\n", start_paddr);
@@ -572,33 +623,53 @@ void __init do_init_bootmem(void)
 				  start_paddr >> PAGE_SHIFT,
 				  end_paddr >> PAGE_SHIFT);
 
-		for (i = 0; i < lmb.memory.cnt; i++) {
-			unsigned long physbase, size;
-
-			physbase = lmb.memory.region[i].physbase;
-			size = lmb.memory.region[i].size;
-
-			if (physbase < end_paddr &&
-			    (physbase+size) > start_paddr) {
-				/* overlaps */
-				if (physbase < start_paddr) {
-					size -= start_paddr - physbase;
-					physbase = start_paddr;
-				}
-
-				if (size > end_paddr - physbase)
-					size = end_paddr - physbase;
+		/*
+		 * We need to do another scan of all memory sections to
+		 * associate memory with the correct node.
+		 */
+		addr_cells = get_mem_addr_cells();
+		size_cells = get_mem_size_cells();
+		memory = NULL;
+		while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+			unsigned long mem_start, mem_size;
+			int numa_domain, ranges;
+			unsigned int *memcell_buf;
+			unsigned int len;
+
+			memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+			if (!memcell_buf || len <= 0)
+				continue;
 
-				dbg("free_bootmem %lx %lx\n", physbase, size);
-				free_bootmem_node(NODE_DATA(nid), physbase,
-						  size);
+			ranges = memory->n_addrs;	/* ranges in cell */
+new_range:
+			mem_start = read_n_cells(addr_cells, &memcell_buf);
+			mem_size = read_n_cells(size_cells, &memcell_buf);
+			numa_domain = numa_enabled ? of_node_numa_domain(memory) : 0;
+
+			if (numa_domain != nid)
+				continue;
+
+			mem_size = numa_enforce_memory_limit(mem_start, mem_size);
+  			if (mem_size) {
+  				dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
+  				free_bootmem_node(NODE_DATA(nid), mem_start, mem_size);
 			}
+
+			if (--ranges)		/* process all ranges in cell */
+				goto new_range;
 		}
 
+		/*
+		 * Mark reserved regions on this node
+		 */
 		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 (pa_to_nid(physbase) != nid &&
+			    pa_to_nid(physbase+size-1) != nid)
+				continue;
+
 			if (physbase < end_paddr &&
 			    (physbase+size) > start_paddr) {
 				/* overlaps */
@@ -632,13 +703,12 @@ void __init paging_init(void)
 		unsigned long start_pfn;
 		unsigned long end_pfn;
 
-		start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
-		end_pfn = plat_node_bdata[nid].node_low_pfn;
+		start_pfn = init_node_data[nid].node_start_pfn;
+		end_pfn = init_node_data[nid].node_end_pfn;
 
 		zones_size[ZONE_DMA] = end_pfn - start_pfn;
-		zholes_size[ZONE_DMA] = 0;
-		if (nid == 0)
-			zholes_size[ZONE_DMA] = node0_io_hole_size >> PAGE_SHIFT;
+		zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
+			init_node_data[nid].node_present_pages;
 
 		dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid,
 		    zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]);
diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c
--- a/arch/ppc64/mm/slb.c
+++ b/arch/ppc64/mm/slb.c
@@ -33,8 +33,8 @@ static inline unsigned long mk_vsid_data
 	return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags;
 }
 
-static inline void create_slbe(unsigned long ea, unsigned long vsid,
-			       unsigned long flags, unsigned long entry)
+static inline void create_slbe(unsigned long ea, unsigned long flags,
+			       unsigned long entry)
 {
 	asm volatile("slbmte  %0,%1" :
 		     : "r" (mk_vsid_data(ea, flags)),
@@ -51,7 +51,7 @@ static void slb_flush_and_rebolt(void)
 
 	WARN_ON(!irqs_disabled());
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+	if (cpu_has_feature(CPU_FTR_16M_PAGE))
 		ksp_flags |= SLB_VSID_L;
 
 	ksp_esid_data = mk_esid_data(get_paca()->kstack, 2);
@@ -139,15 +139,14 @@ void slb_initialize(void)
 	unsigned long flags = SLB_VSID_KERNEL;
 
  	/* Invalidate the entire SLB (even slot 0) & all the ERATS */
- 	if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+ 	if (cpu_has_feature(CPU_FTR_16M_PAGE))
  		flags |= SLB_VSID_L;
 
  	asm volatile("isync":::"memory");
  	asm volatile("slbmte  %0,%0"::"r" (0) : "memory");
 	asm volatile("isync; slbia; isync":::"memory");
-	create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), flags, 0);
-	create_slbe(VMALLOCBASE, get_kernel_vsid(KERNELBASE),
-		    SLB_VSID_KERNEL, 1);
+	create_slbe(KERNELBASE, flags, 0);
+	create_slbe(VMALLOCBASE, SLB_VSID_KERNEL, 1);
 	/* We don't bolt the stack for the time being - we're in boot,
 	 * so the stack is in the bolted segment.  By the time it goes
 	 * elsewhere, we'll call _switch() which will bolt in the new
diff --git a/arch/ppc64/mm/stab.c b/arch/ppc64/mm/stab.c
--- a/arch/ppc64/mm/stab.c
+++ b/arch/ppc64/mm/stab.c
@@ -19,6 +19,11 @@
 #include <asm/paca.h>
 #include <asm/cputable.h>
 
+struct stab_entry {
+	unsigned long esid_data;
+	unsigned long vsid_data;
+};
+
 /* Both the segment table and SLB code uses the following cache */
 #define NR_STAB_CACHE_ENTRIES 8
 DEFINE_PER_CPU(long, stab_cache_ptr);
@@ -227,7 +232,7 @@ void stab_initialize(unsigned long stab)
 {
 	unsigned long vsid = get_kernel_vsid(KERNELBASE);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
+	if (cpu_has_feature(CPU_FTR_SLB)) {
 		slb_initialize();
 	} else {
 		asm volatile("isync; slbia; isync":::"memory");
diff --git a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c
--- a/arch/ppc64/mm/tlb.c
+++ b/arch/ppc64/mm/tlb.c
@@ -74,24 +74,13 @@ void __pte_free_tlb(struct mmu_gather *t
  * change the existing HPTE to read-only rather than removing it
  * (if we remove it we should clear the _PTE_HPTEFLAGS bits).
  */
-void hpte_update(pte_t *ptep, unsigned long pte, int wrprot)
+void hpte_update(struct mm_struct *mm, unsigned long addr,
+		 unsigned long pte, int wrprot)
 {
-	struct page *ptepage;
-	struct mm_struct *mm;
-	unsigned long addr;
 	int i;
 	unsigned long context = 0;
 	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
-	ptepage = virt_to_page(ptep);
-	mm = (struct mm_struct *) ptepage->mapping;
-	addr = ptepage->index;
-	if (pte_huge(pte))
-		addr +=  ((unsigned long)ptep & ~PAGE_MASK)
-			/ sizeof(*ptep) * HPAGE_SIZE;
-	else
-		addr += ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE;
-
 	if (REGION_ID(addr) == USER_REGION_ID)
 		context = mm->context.id;
 	i = batch->index;
diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c
--- a/arch/ppc64/oprofile/common.c
+++ b/arch/ppc64/oprofile/common.c
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
+#include <asm/pmc.h>
 
 #include "op_impl.h"
 
@@ -22,9 +23,6 @@ extern struct op_ppc64_model op_model_rs
 extern struct op_ppc64_model op_model_power4;
 static struct op_ppc64_model *model;
 
-extern void (*perf_irq)(struct pt_regs *);
-static void (*save_perf_irq)(struct pt_regs *);
-
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
@@ -35,11 +33,12 @@ static void op_handle_interrupt(struct p
 
 static int op_ppc64_setup(void)
 {
-	/* Install our interrupt handler into the existing hook.  */
-	save_perf_irq = perf_irq;
-	perf_irq = op_handle_interrupt;
+	int err;
 
-	mb();
+	/* Grab the hardware */
+	err = reserve_pmc_hardware(op_handle_interrupt);
+	if (err)
+		return err;
 
 	/* Pre-compute the values to stuff in the hardware registers.  */
 	model->reg_setup(ctr, &sys, model->num_counters);
@@ -52,10 +51,7 @@ static int op_ppc64_setup(void)
 
 static void op_ppc64_shutdown(void)
 {
-	mb();
-
-	/* Remove our interrupt handler. We may be removing this module. */
-	perf_irq = save_perf_irq;
+	release_pmc_hardware();
 }
 
 static void op_ppc64_cpu_start(void *dummy)
diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c
--- a/arch/ppc64/oprofile/op_model_power4.c
+++ b/arch/ppc64/oprofile/op_model_power4.c
@@ -54,7 +54,7 @@ static void power4_reg_setup(struct op_c
 	 *
 	 * It has been verified to work on POWER5 so we enable it there.
 	 */
-	if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA_SIHV)
+	if (cpu_has_feature(CPU_FTR_MMCRA_SIHV))
 		mmcra_has_sihv = 1;
 
 	/*
@@ -224,7 +224,7 @@ static unsigned long get_pc(struct pt_re
 	if (mmcra & MMCRA_SIPR)
 		return pc;
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC_RTAS
 	/* Were we in RTAS? */
 	if (pc >= rtas.base && pc < (rtas.base + rtas.size))
 		/* function descriptor madness */
diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c
--- a/arch/ppc64/oprofile/op_model_rs64.c
+++ b/arch/ppc64/oprofile/op_model_rs64.c
@@ -114,7 +114,7 @@ static void rs64_cpu_setup(void *unused)
 	/* reset MMCR1, MMCRA */
 	mtspr(SPRN_MMCR1, 0);
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA)
+	if (cpu_has_feature(CPU_FTR_MMCRA))
 		mtspr(SPRN_MMCRA, 0);
 
 	mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
diff --git a/arch/ppc64/xmon/ppc-opc.c b/arch/ppc64/xmon/ppc-opc.c
--- a/arch/ppc64/xmon/ppc-opc.c
+++ b/arch/ppc64/xmon/ppc-opc.c
@@ -20,6 +20,7 @@
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
+#include <linux/stddef.h>
 #include "nonstdio.h"
 #include "ppc.h"
 
@@ -110,12 +111,12 @@ const struct powerpc_operand powerpc_ope
   /* The zero index is used to indicate the end of the list of
      operands.  */
 #define UNUSED 0
-  { 0, 0, 0, 0, 0 },
+  { 0, 0, NULL, NULL, 0 },
 
   /* The BA field in an XL form instruction.  */
 #define BA UNUSED + 1
 #define BA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_CR },
+  { 5, 16, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BA field in an XL form instruction when it must be the same
      as the BT field in the same instruction.  */
@@ -125,7 +126,7 @@ const struct powerpc_operand powerpc_ope
   /* The BB field in an XL form instruction.  */
 #define BB BAT + 1
 #define BB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_CR },
+  { 5, 11, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BB field in an XL form instruction when it must be the same
      as the BA field in the same instruction.  */
@@ -168,21 +169,21 @@ const struct powerpc_operand powerpc_ope
 
   /* The BF field in an X or XL form instruction.  */
 #define BF BDPA + 1
-  { 3, 23, 0, 0, PPC_OPERAND_CR },
+  { 3, 23, NULL, NULL, PPC_OPERAND_CR },
 
   /* An optional BF field.  This is used for comparison instructions,
      in which an omitted BF field is taken as zero.  */
 #define OBF BF + 1
-  { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+  { 3, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
 
   /* The BFA field in an X or XL form instruction.  */
 #define BFA OBF + 1
-  { 3, 18, 0, 0, PPC_OPERAND_CR },
+  { 3, 18, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BI field in a B form or XL form instruction.  */
 #define BI BFA + 1
 #define BI_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_CR },
+  { 5, 16, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BO field in a B form instruction.  Certain values are
      illegal.  */
@@ -197,36 +198,36 @@ const struct powerpc_operand powerpc_ope
 
   /* The BT field in an X or XL form instruction.  */
 #define BT BOE + 1
-  { 5, 21, 0, 0, PPC_OPERAND_CR },
+  { 5, 21, NULL, NULL, PPC_OPERAND_CR },
 
   /* The condition register number portion of the BI field in a B form
      or XL form instruction.  This is used for the extended
      conditional branch mnemonics, which set the lower two bits of the
      BI field.  This field is optional.  */
 #define CR BT + 1
-  { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+  { 3, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
 
   /* The CRB field in an X form instruction.  */
 #define CRB CR + 1
-  { 5, 6, 0, 0, 0 },
+  { 5, 6, NULL, NULL, 0 },
 
   /* The CRFD field in an X form instruction.  */
 #define CRFD CRB + 1
-  { 3, 23, 0, 0, PPC_OPERAND_CR },
+  { 3, 23, NULL, NULL, PPC_OPERAND_CR },
 
   /* The CRFS field in an X form instruction.  */
 #define CRFS CRFD + 1
-  { 3, 0, 0, 0, PPC_OPERAND_CR },
+  { 3, 0, NULL, NULL, PPC_OPERAND_CR },
 
   /* The CT field in an X form instruction.  */
 #define CT CRFS + 1
-  { 5, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+  { 5, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The D field in a D form instruction.  This is a displacement off
      a register, and implies that the next operand is a register in
      parentheses.  */
 #define D CT + 1
-  { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+  { 16, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
 
   /* The DE field in a DE form instruction.  This is like D, but is 12
      bits only.  */
@@ -252,40 +253,40 @@ const struct powerpc_operand powerpc_ope
 
   /* The E field in a wrteei instruction.  */
 #define E DS + 1
-  { 1, 15, 0, 0, 0 },
+  { 1, 15, NULL, NULL, 0 },
 
   /* The FL1 field in a POWER SC form instruction.  */
 #define FL1 E + 1
-  { 4, 12, 0, 0, 0 },
+  { 4, 12, NULL, NULL, 0 },
 
   /* The FL2 field in a POWER SC form instruction.  */
 #define FL2 FL1 + 1
-  { 3, 2, 0, 0, 0 },
+  { 3, 2, NULL, NULL, 0 },
 
   /* The FLM field in an XFL form instruction.  */
 #define FLM FL2 + 1
-  { 8, 17, 0, 0, 0 },
+  { 8, 17, NULL, NULL, 0 },
 
   /* The FRA field in an X or A form instruction.  */
 #define FRA FLM + 1
 #define FRA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_FPR },
+  { 5, 16, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRB field in an X or A form instruction.  */
 #define FRB FRA + 1
 #define FRB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_FPR },
+  { 5, 11, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRC field in an A form instruction.  */
 #define FRC FRB + 1
 #define FRC_MASK (0x1f << 6)
-  { 5, 6, 0, 0, PPC_OPERAND_FPR },
+  { 5, 6, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRS field in an X form instruction or the FRT field in a D, X
      or A form instruction.  */
 #define FRS FRC + 1
 #define FRT FRS
-  { 5, 21, 0, 0, PPC_OPERAND_FPR },
+  { 5, 21, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FXM field in an XFX instruction.  */
 #define FXM FRS + 1
@@ -298,11 +299,11 @@ const struct powerpc_operand powerpc_ope
 
   /* The L field in a D or X form instruction.  */
 #define L FXM4 + 1
-  { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+  { 1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The LEV field in a POWER SC form instruction.  */
 #define LEV L + 1
-  { 7, 5, 0, 0, 0 },
+  { 7, 5, NULL, NULL, 0 },
 
   /* The LI field in an I form instruction.  The lower two bits are
      forced to zero.  */
@@ -316,24 +317,24 @@ const struct powerpc_operand powerpc_ope
 
   /* The LS field in an X (sync) form instruction.  */
 #define LS LIA + 1
-  { 2, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+  { 2, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The MB field in an M form instruction.  */
 #define MB LS + 1
 #define MB_MASK (0x1f << 6)
-  { 5, 6, 0, 0, 0 },
+  { 5, 6, NULL, NULL, 0 },
 
   /* The ME field in an M form instruction.  */
 #define ME MB + 1
 #define ME_MASK (0x1f << 1)
-  { 5, 1, 0, 0, 0 },
+  { 5, 1, NULL, NULL, 0 },
 
   /* The MB and ME fields in an M form instruction expressed a single
      operand which is a bitmask indicating which bits to select.  This
      is a two operand form using PPC_OPERAND_NEXT.  See the
      description in opcode/ppc.h for what this means.  */
 #define MBE ME + 1
-  { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { 5, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
   { 32, 0, insert_mbe, extract_mbe, 0 },
 
   /* The MB or ME field in an MD or MDS form instruction.  The high
@@ -345,7 +346,7 @@ const struct powerpc_operand powerpc_ope
 
   /* The MO field in an mbar instruction.  */
 #define MO MB6 + 1
-  { 5, 21, 0, 0, 0 },
+  { 5, 21, NULL, NULL, 0 },
 
   /* The NB field in an X form instruction.  The value 32 is stored as
      0.  */
@@ -361,34 +362,34 @@ const struct powerpc_operand powerpc_ope
   /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction.  */
 #define RA NSI + 1
 #define RA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_GPR },
+  { 5, 16, NULL, NULL, PPC_OPERAND_GPR },
 
   /* The RA field in the DQ form lq instruction, which has special
      value restrictions.  */
 #define RAQ RA + 1
-  { 5, 16, insert_raq, 0, PPC_OPERAND_GPR },
+  { 5, 16, insert_raq, NULL, PPC_OPERAND_GPR },
 
   /* The RA field in a D or X form instruction which is an updating
      load, which means that the RA field may not be zero and may not
      equal the RT field.  */
 #define RAL RAQ + 1
-  { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
+  { 5, 16, insert_ral, NULL, PPC_OPERAND_GPR },
 
   /* The RA field in an lmw instruction, which has special value
      restrictions.  */
 #define RAM RAL + 1
-  { 5, 16, insert_ram, 0, PPC_OPERAND_GPR },
+  { 5, 16, insert_ram, NULL, PPC_OPERAND_GPR },
 
   /* The RA field in a D or X form instruction which is an updating
      store or an updating floating point load, which means that the RA
      field may not be zero.  */
 #define RAS RAM + 1
-  { 5, 16, insert_ras, 0, PPC_OPERAND_GPR },
+  { 5, 16, insert_ras, NULL, PPC_OPERAND_GPR },
 
   /* The RB field in an X, XO, M, or MDS form instruction.  */
 #define RB RAS + 1
 #define RB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_GPR },
+  { 5, 11, NULL, NULL, PPC_OPERAND_GPR },
 
   /* The RB field in an X form instruction when it must be the same as
      the RS field in the instruction.  This is used for extended
@@ -402,22 +403,22 @@ const struct powerpc_operand powerpc_ope
 #define RS RBS + 1
 #define RT RS
 #define RT_MASK (0x1f << 21)
-  { 5, 21, 0, 0, PPC_OPERAND_GPR },
+  { 5, 21, NULL, NULL, PPC_OPERAND_GPR },
 
   /* The RS field of the DS form stq instruction, which has special
      value restrictions.  */
 #define RSQ RS + 1
-  { 5, 21, insert_rsq, 0, PPC_OPERAND_GPR },
+  { 5, 21, insert_rsq, NULL, PPC_OPERAND_GPR },
 
   /* The RT field of the DQ form lq instruction, which has special
      value restrictions.  */
 #define RTQ RSQ + 1
-  { 5, 21, insert_rtq, 0, PPC_OPERAND_GPR },
+  { 5, 21, insert_rtq, NULL, PPC_OPERAND_GPR },
 
   /* The SH field in an X or M form instruction.  */
 #define SH RTQ + 1
 #define SH_MASK (0x1f << 11)
-  { 5, 11, 0, 0, 0 },
+  { 5, 11, NULL, NULL, 0 },
 
   /* The SH field in an MD form instruction.  This is split.  */
 #define SH6 SH + 1
@@ -426,12 +427,12 @@ const struct powerpc_operand powerpc_ope
 
   /* The SI field in a D form instruction.  */
 #define SI SH6 + 1
-  { 16, 0, 0, 0, PPC_OPERAND_SIGNED },
+  { 16, 0, NULL, NULL, PPC_OPERAND_SIGNED },
 
   /* The SI field in a D form instruction when we accept a wide range
      of positive values.  */
 #define SISIGNOPT SI + 1
-  { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+  { 16, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
 
   /* The SPR field in an XFX form instruction.  This is flipped--the
      lower 5 bits are stored in the upper 5 and vice- versa.  */
@@ -443,25 +444,25 @@ const struct powerpc_operand powerpc_ope
   /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
 #define SPRBAT SPR + 1
 #define SPRBAT_MASK (0x3 << 17)
-  { 2, 17, 0, 0, 0 },
+  { 2, 17, NULL, NULL, 0 },
 
   /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
 #define SPRG SPRBAT + 1
 #define SPRG_MASK (0x3 << 16)
-  { 2, 16, 0, 0, 0 },
+  { 2, 16, NULL, NULL, 0 },
 
   /* The SR field in an X form instruction.  */
 #define SR SPRG + 1
-  { 4, 16, 0, 0, 0 },
+  { 4, 16, NULL, NULL, 0 },
 
   /* The STRM field in an X AltiVec form instruction.  */
 #define STRM SR + 1
 #define STRM_MASK (0x3 << 21)
-  { 2, 21, 0, 0, 0 },
+  { 2, 21, NULL, NULL, 0 },
 
   /* The SV field in a POWER SC form instruction.  */
 #define SV STRM + 1
-  { 14, 2, 0, 0, 0 },
+  { 14, 2, NULL, NULL, 0 },
 
   /* The TBR field in an XFX form instruction.  This is like the SPR
      field, but it is optional.  */
@@ -471,52 +472,52 @@ const struct powerpc_operand powerpc_ope
   /* The TO field in a D or X form instruction.  */
 #define TO TBR + 1
 #define TO_MASK (0x1f << 21)
-  { 5, 21, 0, 0, 0 },
+  { 5, 21, NULL, NULL, 0 },
 
   /* The U field in an X form instruction.  */
 #define U TO + 1
-  { 4, 12, 0, 0, 0 },
+  { 4, 12, NULL, NULL, 0 },
 
   /* The UI field in a D form instruction.  */
 #define UI U + 1
-  { 16, 0, 0, 0, 0 },
+  { 16, 0, NULL, NULL, 0 },
 
   /* The VA field in a VA, VX or VXR form instruction.  */
 #define VA UI + 1
 #define VA_MASK	(0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_VR },
+  { 5, 16, NULL, NULL, PPC_OPERAND_VR },
 
   /* The VB field in a VA, VX or VXR form instruction.  */
 #define VB VA + 1
 #define VB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_VR },
+  { 5, 11, NULL, NULL, PPC_OPERAND_VR },
 
   /* The VC field in a VA form instruction.  */
 #define VC VB + 1
 #define VC_MASK (0x1f << 6)
-  { 5, 6, 0, 0, PPC_OPERAND_VR },
+  { 5, 6, NULL, NULL, PPC_OPERAND_VR },
 
   /* The VD or VS field in a VA, VX, VXR or X form instruction.  */
 #define VD VC + 1
 #define VS VD
 #define VD_MASK (0x1f << 21)
-  { 5, 21, 0, 0, PPC_OPERAND_VR },
+  { 5, 21, NULL, NULL, PPC_OPERAND_VR },
 
   /* The SIMM field in a VX form instruction.  */
 #define SIMM VD + 1
-  { 5, 16, 0, 0, PPC_OPERAND_SIGNED},
+  { 5, 16, NULL, NULL, PPC_OPERAND_SIGNED},
 
   /* The UIMM field in a VX form instruction.  */
 #define UIMM SIMM + 1
-  { 5, 16, 0, 0, 0 },
+  { 5, 16, NULL, NULL, 0 },
 
   /* The SHB field in a VA form instruction.  */
 #define SHB UIMM + 1
-  { 4, 6, 0, 0, 0 },
+  { 4, 6, NULL, NULL, 0 },
 
   /* The other UIMM field in a EVX form instruction.  */
 #define EVUIMM SHB + 1
-  { 5, 11, 0, 0, 0 },
+  { 5, 11, NULL, NULL, 0 },
 
   /* The other UIMM field in a half word EVX form instruction.  */
 #define EVUIMM_2 EVUIMM + 1
@@ -533,11 +534,11 @@ const struct powerpc_operand powerpc_ope
   /* The WS field.  */
 #define WS EVUIMM_8 + 1
 #define WS_MASK (0x7 << 11)
-  { 3, 11, 0, 0, 0 },
+  { 3, 11, NULL, NULL, 0 },
 
   /* The L field in an mtmsrd instruction */
 #define MTMSRD_L WS + 1
-  { 1, 16, 0, 0, PPC_OPERAND_OPTIONAL },
+  { 1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
 };
 
diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c
+++ b/arch/ppc64/xmon/xmon.c
@@ -32,6 +32,7 @@
 #include <asm/rtas.h>
 #include <asm/sstep.h>
 #include <asm/bug.h>
+#include <asm/hvcall.h>
 
 #include "nonstdio.h"
 #include "privinst.h"
@@ -725,7 +726,7 @@ static void insert_cpu_bpts(void)
 {
 	if (dabr.enabled)
 		set_controlled_dabr(dabr.address | (dabr.enabled & 7));
-	if (iabr && (cur_cpu_spec->cpu_features & CPU_FTR_IABR))
+	if (iabr && cpu_has_feature(CPU_FTR_IABR))
 		set_iabr(iabr->address
 			 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
 }
@@ -753,7 +754,7 @@ static void remove_bpts(void)
 static void remove_cpu_bpts(void)
 {
 	set_controlled_dabr(0);
-	if ((cur_cpu_spec->cpu_features & CPU_FTR_IABR))
+	if (cpu_has_feature(CPU_FTR_IABR))
 		set_iabr(0);
 }
 
@@ -1100,7 +1101,7 @@ bpt_cmds(void)
 		break;
 
 	case 'i':	/* bi - hardware instr breakpoint */
-		if (!(cur_cpu_spec->cpu_features & CPU_FTR_IABR)) {
+		if (!cpu_has_feature(CPU_FTR_IABR)) {
 			printf("Hardware instruction breakpoint "
 			       "not supported on this cpu\n");
 			break;
@@ -2498,7 +2499,7 @@ void xmon_init(void)
 
 void dump_segments(void)
 {
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
+	if (cpu_has_feature(CPU_FTR_SLB))
 		dump_slb();
 	else
 		dump_stab();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -84,12 +84,12 @@ config NR_CPUS
 	  approximately sixteen kilobytes to the kernel image.
 
 config HOTPLUG_CPU
-	bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
-	depends on SMP && EXPERIMENTAL
+	bool "Support for hot-pluggable CPUs"
+	depends on SMP
 	select HOTPLUG
 	default n
 	help
-	  Say Y here to experiment with turning CPUs off and on.  CPUs
+	  Say Y here to be able to turn CPUs off and on. CPUs
 	  can be controlled through /sys/devices/system/cpu/cpu#.
 	  Say N if you want to disable CPU hotplug.
 
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -66,7 +66,7 @@ cflags-$(CONFIG_WARN_STACK) += -mwarn-dy
 cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE)
 endif
 
-CFLAGS		+= -mbackchain $(cflags-y)
+CFLAGS		+= -mbackchain -msoft-float $(cflags-y)
 CFLAGS		+= $(call cc-option,-finline-limit=10000)
 CFLAGS 		+= -pipe -fno-strength-reduce -Wno-sign-compare 
 AFLAGS		+= $(aflags-y)
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -28,6 +28,7 @@
 //#include <linux/kernel_stat.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
+#include <linux/workqueue.h>
 
 #include "appldata.h"
 
@@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_
 static int appldata_timer_active;
 
 /*
- * Tasklet
+ * Work queue
  */
-static struct tasklet_struct appldata_tasklet_struct;
+static struct workqueue_struct *appldata_wq;
+static void appldata_work_fn(void *data);
+static DECLARE_WORK(appldata_work, appldata_work_fn, NULL);
+
 
 /*
  * Ops list
@@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock
 static LIST_HEAD(appldata_ops_list);
 
 
-/************************* timer, tasklet, DIAG ******************************/
+/*************************** timer, work, DIAG *******************************/
 /*
  * appldata_timer_function()
  *
- * schedule tasklet and reschedule timer
+ * schedule work and reschedule timer
  */
 static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
 {
@@ -157,22 +161,22 @@ static void appldata_timer_function(unsi
 		atomic_read(&appldata_expire_count));
 	if (atomic_dec_and_test(&appldata_expire_count)) {
 		atomic_set(&appldata_expire_count, num_online_cpus());
-		tasklet_schedule((struct tasklet_struct *) data);
+		queue_work(appldata_wq, (struct work_struct *) data);
 	}
 }
 
 /*
- * appldata_tasklet_function()
+ * appldata_work_fn()
  *
  * call data gathering function for each (active) module
  */
-static void appldata_tasklet_function(unsigned long data)
+static void appldata_work_fn(void *data)
 {
 	struct list_head *lh;
 	struct appldata_ops *ops;
 	int i;
 
-	P_DEBUG("  -= Tasklet =-\n");
+	P_DEBUG("  -= Work Queue =-\n");
 	i = 0;
 	spin_lock(&appldata_ops_lock);
 	list_for_each(lh, &appldata_ops_list) {
@@ -231,7 +235,7 @@ static int appldata_diag(char record_nr,
 			: "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
 	return (int) ry;
 }
-/********************** timer, tasklet, DIAG <END> ***************************/
+/************************ timer, work, DIAG <END> ****************************/
 
 
 /****************************** /proc stuff **********************************/
@@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl,
 	struct list_head *lh;
 
 	found = 0;
-	spin_lock_bh(&appldata_ops_lock);
+	spin_lock(&appldata_ops_lock);
 	list_for_each(lh, &appldata_ops_list) {
 		tmp_ops = list_entry(lh, struct appldata_ops, list);
 		if (&tmp_ops->ctl_table[2] == ctl) {
@@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl,
 		}
 	}
 	if (!found) {
-		spin_unlock_bh(&appldata_ops_lock);
+		spin_unlock(&appldata_ops_lock);
 		return -ENODEV;
 	}
 	ops = ctl->data;
 	if (!try_module_get(ops->owner)) {	// protect this function
-		spin_unlock_bh(&appldata_ops_lock);
+		spin_unlock(&appldata_ops_lock);
 		return -ENODEV;
 	}
-	spin_unlock_bh(&appldata_ops_lock);
+	spin_unlock(&appldata_ops_lock);
 
 	if (!*lenp || *ppos) {
 		*lenp = 0;
@@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl,
 		return -EFAULT;
 	}
 
-	spin_lock_bh(&appldata_ops_lock);
+	spin_lock(&appldata_ops_lock);
 	if ((buf[0] == '1') && (ops->active == 0)) {
-		if (!try_module_get(ops->owner)) {	// protect tasklet
-			spin_unlock_bh(&appldata_ops_lock);
+		// protect work queue callback
+		if (!try_module_get(ops->owner)) {
+			spin_unlock(&appldata_ops_lock);
 			module_put(ops->owner);
 			return -ENODEV;
 		}
@@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl,
 		}
 		module_put(ops->owner);
 	}
-	spin_unlock_bh(&appldata_ops_lock);
+	spin_unlock(&appldata_ops_lock);
 out:
 	*lenp = len;
 	*ppos += len;
@@ -529,7 +534,7 @@ int appldata_register_ops(struct appldat
 	}
 	memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
 
-	spin_lock_bh(&appldata_ops_lock);
+	spin_lock(&appldata_ops_lock);
 	list_for_each(lh, &appldata_ops_list) {
 		tmp_ops = list_entry(lh, struct appldata_ops, list);
 		P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
@@ -541,18 +546,18 @@ int appldata_register_ops(struct appldat
 				APPLDATA_PROC_NAME_LENGTH) == 0) {
 			P_ERROR("Name \"%s\" already registered!\n", ops->name);
 			kfree(ops->ctl_table);
-			spin_unlock_bh(&appldata_ops_lock);
+			spin_unlock(&appldata_ops_lock);
 			return -EBUSY;
 		}
 		if (tmp_ops->ctl_nr == ops->ctl_nr) {
 			P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
 			kfree(ops->ctl_table);
-			spin_unlock_bh(&appldata_ops_lock);
+			spin_unlock(&appldata_ops_lock);
 			return -EBUSY;
 		}
 	}
 	list_add(&ops->list, &appldata_ops_list);
-	spin_unlock_bh(&appldata_ops_lock);
+	spin_unlock(&appldata_ops_lock);
 
 	ops->ctl_table[0].ctl_name = CTL_APPLDATA;
 	ops->ctl_table[0].procname = appldata_proc_name;
@@ -583,12 +588,12 @@ int appldata_register_ops(struct appldat
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
-	spin_lock_bh(&appldata_ops_lock);
+	spin_lock(&appldata_ops_lock);
 	unregister_sysctl_table(ops->sysctl_header);
 	list_del(&ops->list);
 	kfree(ops->ctl_table);
 	ops->ctl_table = NULL;
-	spin_unlock_bh(&appldata_ops_lock);
+	spin_unlock(&appldata_ops_lock);
 	P_INFO("%s-ops unregistered!\n", ops->name);
 }
 /********************** module-ops management <END> **************************/
@@ -602,7 +607,7 @@ appldata_online_cpu(int cpu)
 	init_virt_timer(&per_cpu(appldata_timer, cpu));
 	per_cpu(appldata_timer, cpu).function = appldata_timer_function;
 	per_cpu(appldata_timer, cpu).data = (unsigned long)
-		&appldata_tasklet_struct;
+		&appldata_work;
 	atomic_inc(&appldata_expire_count);
 	spin_lock(&appldata_timer_lock);
 	__appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu)
 	del_virt_timer(&per_cpu(appldata_timer, cpu));
 	if (atomic_dec_and_test(&appldata_expire_count)) {
 		atomic_set(&appldata_expire_count, num_online_cpus());
-		tasklet_schedule(&appldata_tasklet_struct);
+		queue_work(appldata_wq, &appldata_work);
 	}
 	spin_lock(&appldata_timer_lock);
 	__appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@@ -648,7 +653,7 @@ static struct notifier_block __devinitda
 /*
  * appldata_init()
  *
- * init timer and tasklet, register /proc entries
+ * init timer, register /proc entries
  */
 static int __init appldata_init(void)
 {
@@ -657,6 +662,12 @@ static int __init appldata_init(void)
 	P_DEBUG("sizeof(parameter_list) = %lu\n",
 		sizeof(struct appldata_parameter_list));
 
+	appldata_wq = create_singlethread_workqueue("appldata");
+	if (!appldata_wq) {
+		P_ERROR("Could not create work queue\n");
+		return -ENOMEM;
+	}
+
 	for_each_online_cpu(i)
 		appldata_online_cpu(i);
 
@@ -670,7 +681,6 @@ static int __init appldata_init(void)
 	appldata_table[1].de->owner = THIS_MODULE;
 #endif
 
-	tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
 	P_DEBUG("Base interface initialized.\n");
 	return 0;
 }
@@ -678,7 +688,7 @@ static int __init appldata_init(void)
 /*
  * appldata_exit()
  *
- * stop timer and tasklet, unregister /proc entries
+ * stop timer, unregister /proc entries
  */
 static void __exit appldata_exit(void)
 {
@@ -690,7 +700,7 @@ static void __exit appldata_exit(void)
 	/*
 	 * ops list should be empty, but just in case something went wrong...
 	 */
-	spin_lock_bh(&appldata_ops_lock);
+	spin_lock(&appldata_ops_lock);
 	list_for_each(lh, &appldata_ops_list) {
 		ops = list_entry(lh, struct appldata_ops, list);
 		rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
@@ -700,7 +710,7 @@ static void __exit appldata_exit(void)
 				"return code: %d\n", ops->name, rc);
 		}
 	}
-	spin_unlock_bh(&appldata_ops_lock);
+	spin_unlock(&appldata_ops_lock);
 
 	for_each_online_cpu(i)
 		appldata_offline_cpu(i);
@@ -709,7 +719,7 @@ static void __exit appldata_exit(void)
 
 	unregister_sysctl_table(appldata_sysctl_header);
 
-	tasklet_kill(&appldata_tasklet_struct);
+	destroy_workqueue(appldata_wq);
 	P_DEBUG("... module unloaded!\n");
 }
 /**************************** init / exit <END> ******************************/
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -68,7 +68,7 @@ struct appldata_mem_data {
 	u64 pgmajfault;		/* page faults (major only) */
 // <-- New in 2.6
 
-} appldata_mem_data;
+} __attribute__((packed)) appldata_mem_data;
 
 
 static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -57,7 +57,7 @@ struct appldata_net_sum_data {
 	u64 rx_dropped;		/* no space in linux buffers     */
 	u64 tx_dropped;		/* no space available in linux   */
 	u64 collisions;		/* collisions while transmitting */
-} appldata_net_sum_data;
+} __attribute__((packed)) appldata_net_sum_data;
 
 
 static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -49,7 +49,7 @@ struct appldata_os_per_cpu {
 	u32 per_cpu_softirq;	/* ... spent in softirqs            */
 	u32 per_cpu_iowait;	/* ... spent while waiting for I/O  */
 // <-- New in 2.6
-};
+} __attribute__((packed));
 
 struct appldata_os_data {
 	u64 timestamp;
@@ -75,7 +75,7 @@ struct appldata_os_data {
 
 	/* per cpu data */
 	struct appldata_os_per_cpu os_cpu[0];
-};
+} __attribute__((packed));
 
 static struct appldata_os_data *appldata_os_data;
 
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Mon Jan 31 16:27:12 2005
+# Linux kernel version: 2.6.12-rc3
+# Fri Apr 22 15:30:58 2005
 #
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -15,6 +15,7 @@ CONFIG_UID16=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -26,24 +27,25 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=17
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -54,6 +56,7 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 
 #
 # Base setup
@@ -67,7 +70,7 @@ CONFIG_KMOD=y
 CONFIG_ARCH_S390_31=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
-# CONFIG_HOTPLUG_CPU is not set
+CONFIG_HOTPLUG_CPU=y
 CONFIG_MATHEMU=y
 
 #
@@ -260,7 +263,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
@@ -328,6 +330,7 @@ CONFIG_NET_SCH_DSMARK=m
 CONFIG_NET_QOS=y
 CONFIG_NET_ESTIMATOR=y
 CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
 CONFIG_NET_CLS_TCINDEX=m
 CONFIG_NET_CLS_ROUTE4=m
 CONFIG_NET_CLS_ROUTE=y
@@ -337,6 +340,7 @@ CONFIG_NET_CLS_U32=m
 # CONFIG_NET_CLS_IND is not set
 CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
 # CONFIG_NET_CLS_ACT is not set
 CONFIG_NET_CLS_POLICE=y
 
@@ -392,6 +396,8 @@ CONFIG_CTC=m
 CONFIG_IUCV=m
 # CONFIG_NETIUCV is not set
 # CONFIG_SMSGIUCV is not set
+# CONFIG_CLAW is not set
+# CONFIG_MPC is not set
 CONFIG_QETH=y
 
 #
@@ -419,6 +425,10 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -527,10 +537,13 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
@@ -555,6 +568,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 # CONFIG_CRYPTO_DES is not set
 # CONFIG_CRYPTO_DES_Z990 is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
diff --git a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c
--- a/arch/s390/kernel/compat_ioctl.c
+++ b/arch/s390/kernel/compat_ioctl.c
@@ -16,6 +16,7 @@
 #define CODE
 #include "../../../fs/compat_ioctl.c"
 #include <asm/dasd.h>
+#include <asm/cmb.h>
 #include <asm/tape390.h>
 
 static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
@@ -58,16 +59,17 @@ COMPATIBLE_IOCTL(BIODASDPRRD)
 COMPATIBLE_IOCTL(BIODASDPSRD)
 COMPATIBLE_IOCTL(BIODASDGATTR)
 COMPATIBLE_IOCTL(BIODASDSATTR)
-
+#if defined(CONFIG_DASD_CMB) || defined(CONFIG_DASD_CMB_MODULE)
+COMPATIBLE_IOCTL(BIODASDCMFENABLE)
+COMPATIBLE_IOCTL(BIODASDCMFDISABLE)
+COMPATIBLE_IOCTL(BIODASDREADALLCMB)
+#endif
 #endif
 
 #if defined(CONFIG_S390_TAPE) || defined(CONFIG_S390_TAPE_MODULE)
 COMPATIBLE_IOCTL(TAPE390_DISPLAY)
 #endif
 
-/* This one should be architecture independent */
-COMPATIBLE_IOCTL(TCSBRKP)
-
 /* s390 doesn't need handlers here */
 COMPATIBLE_IOCTL(TIOCGSERIAL)
 COMPATIBLE_IOCTL(TIOCSSERIAL)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -1019,7 +1019,7 @@ extern asmlinkage long
 sys_timer_create(clockid_t, struct sigevent *, timer_t *);
 
 asmlinkage long
-sys32_timer_create(clockid_t which_clock, struct sigevent32 *se32,
+sys32_timer_create(clockid_t which_clock, struct compat_sigevent *se32,
 		timer_t *timer_id)
 {
 	struct sigevent se;
@@ -1030,16 +1030,7 @@ sys32_timer_create(clockid_t which_clock
 	if (se32 == NULL)
 		return sys_timer_create(which_clock, NULL, timer_id);
 
-	/* XXX: converting se32 to se is filthy because of the
-	 * two union members. For now it is ok, because the pointers
-	 * are not touched in kernel.
-	 */
-	memset(&se, 0, sizeof(se));
-	if (get_user(se.sigev_value.sival_int,  &se32->sigev_value.sival_int) ||
-	    get_user(se.sigev_signo, &se32->sigev_signo) ||
-	    get_user(se.sigev_notify, &se32->sigev_notify) ||
-	    copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad,
-	    sizeof(se._sigev_un._pad)))
+	if (get_compat_sigevent(&se, se32))
 		return -EFAULT;
 
 	old_fs = get_fs();
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -29,11 +29,6 @@ struct old_sigaction32 {
        __u32			sa_restorer;	/* Another 32 bit pointer */
 };
  
-typedef union sigval32 {
-        int     sival_int;
-        __u32   sival_ptr;
-} sigval_t32;
-                 
 typedef struct compat_siginfo {
 	int	si_signo;
 	int	si_errno;
@@ -52,7 +47,7 @@ typedef struct compat_siginfo {
 		struct {
 			timer_t _tid;		/* timer id */
 			int _overrun;		/* overrun count */
-			sigval_t _sigval;	/* same as below */
+			compat_sigval_t _sigval;	/* same as below */
 			int _sys_private;       /* not to be passed to user */
 		} _timer;
 
@@ -60,7 +55,7 @@ typedef struct compat_siginfo {
 		struct {
 			pid_t			_pid;	/* sender's pid */
 			uid_t			_uid;	/* sender's uid */
-			sigval_t32		_sigval;
+			compat_sigval_t		_sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -199,22 +194,4 @@ struct ucontext32 {
 	compat_sigset_t		uc_sigmask;	/* mask last for extensibility */
 };
 
-#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-struct sigevent32 {
-	union {
-		int sival_int;
-		u32 sival_ptr;
-	} sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE32];
-		int _tid;
-		struct {
-			u32 *_function;
-			u32 *_attribute;
-		} _sigev_thread;
-	} _sigev_un;
-};
-
 #endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -231,7 +231,7 @@ sys32_sigaction(int sig, const struct ol
 
         if (act) {
 		compat_old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(sa_handler, &act->sa_handler) ||
 		    __get_user(sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -247,7 +247,7 @@ sys32_sigaction(int sig, const struct ol
 	if (!ret && oact) {
 		sa_handler = (unsigned long) old_ka.sa.sa_handler;
 		sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(sa_handler, &oact->sa_handler) ||
 		    __put_user(sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -416,7 +416,7 @@ asmlinkage long sys32_sigreturn(struct p
 	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
 	sigset_t set;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
 		goto badframe;
@@ -446,7 +446,7 @@ asmlinkage long sys32_rt_sigreturn(struc
 	int err;
 	mm_segment_t old_fs = get_fs();
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1406,3 +1406,38 @@ compat_sys_mq_getsetattr_wrapper:
 	llgtr	%r3,%r3			# struct compat_mq_attr *
 	llgtr	%r4,%r4			# struct compat_mq_attr *
 	jg	compat_sys_mq_getsetattr
+
+	.globl	compat_sys_add_key_wrapper
+compat_sys_add_key_wrapper:
+	llgtr	%r2,%r2			# const char *
+	llgtr	%r3,%r3			# const char *
+	llgtr	%r4,%r4			# const void *
+	llgfr	%r5,%r5			# size_t
+	llgfr	%r6,%r6			# (key_serial_t) u32
+	jg	sys_add_key
+
+	.globl	compat_sys_request_key_wrapper
+compat_sys_request_key_wrapper:
+	llgtr	%r2,%r2			# const char *
+	llgtr	%r3,%r3			# const char *
+	llgtr	%r4,%r4			# const void *
+	llgfr	%r5,%r5			# (key_serial_t) u32
+	jg	sys_request_key
+
+	.globl	sys32_remap_file_pages_wrapper
+sys32_remap_file_pages_wrapper:
+	llgfr	%r2,%r2			# unsigned long
+	llgfr	%r3,%r3			# unsigned long
+	llgfr	%r4,%r4			# unsigned long
+	llgfr	%r5,%r5			# unsigned long
+	llgfr	%r6,%r6			# unsigned long
+	jg	sys_remap_file_pages
+
+	.globl	compat_sys_waitid_wrapper
+compat_sys_waitid_wrapper:
+	lgfr	%r2,%r2			# int
+	lgfr	%r3,%r3			# pid_t
+	llgtr	%r4,%r4			# siginfo_emu31_t *
+	lgfr	%r5,%r5			# int
+	llgtr	%r6,%r6			# struct rusage_emu31 *
+	jg	compat_sys_waitid
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -931,11 +931,15 @@ int debug_register_view(debug_info_t * i
 	int rc = 0;
 	int i;
 	unsigned long flags;
-	mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+	mode_t mode = S_IFREG;
 	struct proc_dir_entry *pde;
 
 	if (!id)
 		goto out;
+	if (view->prolog_proc || view->format_proc || view->header_proc)
+		mode |= S_IRUSR;
+	if (view->input_proc)
+		mode |= S_IWUSR;
 	pde = create_proc_entry(view->name, mode, id->proc_root_entry);
 	if (!pde){
 		printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name);
@@ -958,10 +962,6 @@ int debug_register_view(debug_info_t * i
 	}
 	else {
 		id->views[i] = view;
-		if (view->prolog_proc || view->format_proc || view->header_proc)
-			mode |= S_IRUSR;
-		if (view->input_proc)
-			mode |= S_IWUSR;
 		pde->proc_fops = &debug_file_ops;
 		id->proc_entries[i] = pde;
 	}
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -25,9 +25,8 @@ int show_interrupts(struct seq_file *p, 
 
 	if (i == 0) {
 		seq_puts(p, "           ");
-		for (j=0; j<NR_CPUS; j++)
-			if (cpu_online(j))
-				seq_printf(p, "CPU%d       ",j);
+		for_each_online_cpu(j)
+			seq_printf(p, "CPU%d       ",j);
 		seq_putc(p, '\n');
 	}
 
@@ -36,9 +35,8 @@ int show_interrupts(struct seq_file *p, 
 #ifndef CONFIG_SMP
 		seq_printf(p, "%10u ", kstat_irqs(i));
 #else
-		for (j = 0; j < NR_CPUS; j++)
-			if (cpu_online(j))
-				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+		for_each_online_cpu(j)
+			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
                 seq_putc(p, '\n');
 
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -31,6 +31,8 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
+#include <linux/signal.h>
 
 #include <asm/segment.h>
 #include <asm/page.h>
@@ -38,6 +40,7 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #ifdef CONFIG_S390_SUPPORT
 #include "compat_ptrace.h"
@@ -128,13 +131,19 @@ static int
 peek_user(struct task_struct *child, addr_t addr, addr_t data)
 {
 	struct user *dummy = NULL;
-	addr_t offset, tmp;
+	addr_t offset, tmp, mask;
 
 	/*
 	 * Stupid gdb peeks/pokes the access registers in 64 bit with
 	 * an alignment of 4. Programmers from hell...
 	 */
-	if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+	mask = __ADDR_MASK;
+#ifdef CONFIG_ARCH_S390X
+	if (addr >= (addr_t) &dummy->regs.acrs &&
+	    addr < (addr_t) &dummy->regs.orig_gpr2)
+		mask = 3;
+#endif
+	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
 		return -EIO;
 
 	if (addr < (addr_t) &dummy->regs.acrs) {
@@ -151,6 +160,16 @@ peek_user(struct task_struct *child, add
 		 * access registers are stored in the thread structure
 		 */
 		offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_ARCH_S390X
+		/*
+		 * Very special case: old & broken 64 bit gdb reading
+		 * from acrs[15]. Result is a 64 bit value. Read the
+		 * 32 bit acrs[15] value and shift it by 32. Sick...
+		 */
+		if (addr == (addr_t) &dummy->regs.acrs[15])
+			tmp = ((unsigned long) child->thread.acrs[15]) << 32;
+		else
+#endif
 		tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
 
 	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
@@ -165,6 +184,9 @@ peek_user(struct task_struct *child, add
 		 */
 		offset = addr - (addr_t) &dummy->regs.fp_regs;
 		tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
+		if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
+			tmp &= (unsigned long) FPC_VALID_MASK
+				<< (BITS_PER_LONG - 32);
 
 	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
 		/*
@@ -189,13 +211,19 @@ static int
 poke_user(struct task_struct *child, addr_t addr, addr_t data)
 {
 	struct user *dummy = NULL;
-	addr_t offset;
+	addr_t offset, mask;
 
 	/*
 	 * Stupid gdb peeks/pokes the access registers in 64 bit with
 	 * an alignment of 4. Programmers from hell indeed...
 	 */
-	if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+	mask = __ADDR_MASK;
+#ifdef CONFIG_ARCH_S390X
+	if (addr >= (addr_t) &dummy->regs.acrs &&
+	    addr < (addr_t) &dummy->regs.orig_gpr2)
+		mask = 3;
+#endif
+	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
 		return -EIO;
 
 	if (addr < (addr_t) &dummy->regs.acrs) {
@@ -222,6 +250,17 @@ poke_user(struct task_struct *child, add
 		 * access registers are stored in the thread structure
 		 */
 		offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_ARCH_S390X
+		/*
+		 * Very special case: old & broken 64 bit gdb writing
+		 * to acrs[15] with a 64 bit value. Ignore the lower
+		 * half of the value and write the upper 32 bit to
+		 * acrs[15]. Sick...
+		 */
+		if (addr == (addr_t) &dummy->regs.acrs[15])
+			child->thread.acrs[15] = (unsigned int) (data >> 32);
+		else
+#endif
 		*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
 
 	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
@@ -235,7 +274,8 @@ poke_user(struct task_struct *child, add
 		 * floating point regs. are stored in the thread structure
 		 */
 		if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
-		    (data & ~FPC_VALID_MASK) != 0)
+		    (data & ~((unsigned long) FPC_VALID_MASK
+			      << (BITS_PER_LONG - 32))) != 0)
 			return -EINVAL;
 		offset = addr - (addr_t) &dummy->regs.fp_regs;
 		*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
@@ -608,7 +648,7 @@ do_ptrace(struct task_struct *child, lon
 		/* continue and stop at next (return from) syscall */
 	case PTRACE_CONT:
 		/* restart after signal. */
-		if ((unsigned long) data >= _NSIG)
+		if (!valid_signal(data))
 			return -EIO;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -636,7 +676,7 @@ do_ptrace(struct task_struct *child, lon
 
 	case PTRACE_SINGLESTEP:
 		/* set the trap flag. */
-		if ((unsigned long) data >= _NSIG)
+		if (!valid_signal(data))
 			return -EIO;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
@@ -710,22 +750,24 @@ out:
 asmlinkage void
 syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	if (unlikely(current->audit_context)) {
-		if (!entryexit)
-			audit_syscall_entry(current, regs->gprs[2],
-					    regs->orig_gpr2, regs->gprs[3],
-					    regs->gprs[4], regs->gprs[5]);
-		else
-			audit_syscall_exit(current, regs->gprs[2]);
-	}
+	if (unlikely(current->audit_context) && entryexit)
+		audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+		goto out;
 	if (!(current->ptrace & PT_PTRACED))
-		return;
+		goto out;
 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 				 ? 0x80 : 0));
 
 	/*
+	 * If the debuffer has set an invalid system call number,
+	 * we prepare to skip the system call restart handling.
+	 */
+	if (!entryexit && regs->gprs[2] >= NR_syscalls)
+		regs->trap = -1;
+
+	/*
 	 * 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
@@ -734,4 +776,10 @@ syscall_trace(struct pt_regs *regs, int 
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+ out:
+	if (unlikely(current->audit_context) && !entryexit)
+		audit_syscall_entry(current, 
+				    test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
+				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
+				    regs->gprs[4], regs->gprs[5]);
 }
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -114,6 +114,10 @@ void do_extint(struct pt_regs *regs, uns
 	irq_enter();
 	asm volatile ("mc 0,0");
 	if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+		/**
+		 * Make sure that the i/o interrupt did not "overtake"
+		 * the last HZ timer interrupt.
+		 */
 		account_ticks(regs);
 	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
         index = code & 0xff;
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -34,7 +34,6 @@ EXPORT_SYMBOL(__clear_user_asm);
 EXPORT_SYMBOL(__strncpy_from_user_asm);
 EXPORT_SYMBOL(__strnlen_user_asm);
 EXPORT_SYMBOL(diag10);
-EXPORT_SYMBOL(default_storage_key);
 
 /*
  * semaphore ops
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -44,6 +44,8 @@
 #include <asm/cpcmd.h>
 #include <asm/lowcore.h>
 #include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
 
 /*
  * Machine setup..
@@ -53,13 +55,14 @@ unsigned int console_devno = -1;
 unsigned int console_irq = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
-unsigned int default_storage_key = 0;
 struct {
 	unsigned long addr, size, type;
 } memory_chunk[MEMORY_CHUNKS] = { { 0 } };
 #define CHUNK_READ_WRITE 0
 #define CHUNK_READ_ONLY 1
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
+unsigned long __initdata zholes_size[MAX_NR_ZONES];
+static unsigned long __initdata memory_end;
 
 /*
  * Setup options
@@ -78,11 +81,15 @@ static char command_line[COMMAND_LINE_SI
 
 static struct resource code_resource = {
 	.name  = "Kernel code",
+	.start = (unsigned long) &_text,
+	.end = (unsigned long) &_etext - 1,
 	.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
 static struct resource data_resource = {
 	.name = "Kernel data",
+	.start = (unsigned long) &_etext,
+	.end = (unsigned long) &_edata - 1,
 	.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
@@ -310,90 +317,50 @@ void machine_power_off(void)
 
 EXPORT_SYMBOL(machine_power_off);
 
-/*
- * Setup function called from init/main.c just after the banner
- * was printed.
- */
-extern char _pstart, _pend, _stext;
-
-void __init setup_arch(char **cmdline_p)
+static void __init
+add_memory_hole(unsigned long start, unsigned long end)
 {
-        unsigned long bootmap_size;
-        unsigned long memory_start, memory_end;
-        char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
-	unsigned long start_pfn, end_pfn;
-        static unsigned int smptrap=0;
-        unsigned long delay = 0;
-	struct _lowcore *lc;
-	int i;
+	unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
 
-        if (smptrap)
-                return;
-        smptrap=1;
+	if (end <= dma_pfn)
+		zholes_size[ZONE_DMA] += end - start + 1;
+	else if (start > dma_pfn)
+		zholes_size[ZONE_NORMAL] += end - start + 1;
+	else {
+		zholes_size[ZONE_DMA] += dma_pfn - start + 1;
+		zholes_size[ZONE_NORMAL] += end - dma_pfn;
+	}
+}
 
-        /*
-         * print what head.S has found out about the machine 
-         */
-#ifndef CONFIG_ARCH_S390X
-	printk((MACHINE_IS_VM) ?
-	       "We are running under VM (31 bit mode)\n" :
-	       "We are running native (31 bit mode)\n");
-	printk((MACHINE_HAS_IEEE) ?
-	       "This machine has an IEEE fpu\n" :
-	       "This machine has no IEEE fpu\n");
-#else /* CONFIG_ARCH_S390X */
-	printk((MACHINE_IS_VM) ?
-	       "We are running under VM (64 bit mode)\n" :
-	       "We are running native (64 bit mode)\n");
-#endif /* CONFIG_ARCH_S390X */
+static void __init
+parse_cmdline_early(char **cmdline_p)
+{
+	char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
+	unsigned long delay = 0;
 
-        ROOT_DEV = Root_RAM0;
-        memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-#ifndef CONFIG_ARCH_S390X
-	memory_end = memory_size & ~0x400000UL;  /* align memory end to 4MB */
-        /*
-         * We need some free virtual space to be able to do vmalloc.
-         * On a machine with 2GB memory we make sure that we have at
-         * least 128 MB free space for vmalloc.
-         */
-        if (memory_end > 1920*1024*1024)
-                memory_end = 1920*1024*1024;
-#else /* CONFIG_ARCH_S390X */
-	memory_end = memory_size & ~0x200000UL;  /* detected in head.s */
-#endif /* CONFIG_ARCH_S390X */
-        init_mm.start_code = PAGE_OFFSET;
-        init_mm.end_code = (unsigned long) &_etext;
-        init_mm.end_data = (unsigned long) &_edata;
-        init_mm.brk = (unsigned long) &_end;
-
-	code_resource.start = (unsigned long) &_text;
-	code_resource.end = (unsigned long) &_etext - 1;
-	data_resource.start = (unsigned long) &_etext;
-	data_resource.end = (unsigned long) &_edata - 1;
-
-        /* 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 (;;) {
-                /*
-                 * "mem=XXX[kKmM]" sets memsize 
-                 */
-                if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
-                        memory_end = simple_strtoul(from+4, &from, 0);
-                        if ( *from == 'K' || *from == 'k' ) {
-                                memory_end = memory_end << 10;
-                                from++;
-                        } else if ( *from == 'M' || *from == 'm' ) {
-                                memory_end = memory_end << 20;
-                                from++;
-                        }
-                }
-                /*
-                 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
-                 */
-                if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
-                        delay = simple_strtoul(from+9, &from, 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 (;;) {
+		/*
+		 * "mem=XXX[kKmM]" sets memsize
+		 */
+		if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
+			memory_end = simple_strtoul(from+4, &from, 0);
+			if ( *from == 'K' || *from == 'k' ) {
+				memory_end = memory_end << 10;
+				from++;
+			} else if ( *from == 'M' || *from == 'm' ) {
+				memory_end = memory_end << 20;
+				from++;
+			}
+		}
+		/*
+		 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
+		 */
+		if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
+			delay = simple_strtoul(from+9, &from, 0);
 			if (*from == 's' || *from == 'S') {
 				delay = delay*1000000;
 				from++;
@@ -403,24 +370,110 @@ void __init setup_arch(char **cmdline_p)
 			}
 			/* now wait for the requested amount of time */
 			udelay(delay);
-                }
-                cn = *(from++);
-                if (!cn)
-                        break;
-                if (cn == '\n')
-                        cn = ' ';  /* replace newlines with space */
+		}
+		cn = *(from++);
+		if (!cn)
+			break;
+		if (cn == '\n')
+			cn = ' ';  /* replace newlines with space */
 		if (cn == 0x0d)
 			cn = ' ';  /* replace 0x0d with space */
-                if (cn == ' ' && c == ' ')
-                        continue;  /* remove additional spaces */
-                c = cn;
-                if (to - command_line >= COMMAND_LINE_SIZE)
-                        break;
-                *(to++) = c;
-        }
-        if (c == ' ' && to > command_line) to--;
-        *to = '\0';
-        *cmdline_p = command_line;
+		if (cn == ' ' && c == ' ')
+			continue;  /* remove additional spaces */
+		c = cn;
+		if (to - command_line >= COMMAND_LINE_SIZE)
+			break;
+		*(to++) = c;
+	}
+	if (c == ' ' && to > command_line) to--;
+	*to = '\0';
+	*cmdline_p = command_line;
+}
+
+static void __init
+setup_lowcore(void)
+{
+	struct _lowcore *lc;
+	int lc_pages;
+
+	/*
+	 * Setup lowcore for boot cpu
+	 */
+	lc_pages = sizeof(void *) == 8 ? 2 : 1;
+	lc = (struct _lowcore *)
+		__alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0);
+	memset(lc, 0, lc_pages * PAGE_SIZE);
+	lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+	lc->restart_psw.addr =
+		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
+	lc->external_new_psw.mask = PSW_KERNEL_BITS;
+	lc->external_new_psw.addr =
+		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
+	lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
+	lc->program_new_psw.mask = PSW_KERNEL_BITS;
+	lc->program_new_psw.addr =
+		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
+	lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+	lc->mcck_new_psw.addr =
+		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
+	lc->io_new_psw.mask = PSW_KERNEL_BITS;
+	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
+	lc->ipl_device = S390_lowcore.ipl_device;
+	lc->jiffy_timer = -1LL;
+	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
+	lc->async_stack = (unsigned long)
+		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
+#ifdef CONFIG_CHECK_STACK
+	lc->panic_stack = (unsigned long)
+		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
+#endif
+	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
+	lc->thread_info = (unsigned long) &init_thread_union;
+#ifdef CONFIG_ARCH_S390X
+	if (MACHINE_HAS_DIAG44)
+		lc->diag44_opcode = 0x83000044;
+	else
+		lc->diag44_opcode = 0x07000700;
+#endif /* CONFIG_ARCH_S390X */
+	set_prefix((u32)(unsigned long) lc);
+}
+
+static void __init
+setup_resources(void)
+{
+	struct resource *res;
+	int i;
+
+	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+		res = alloc_bootmem_low(sizeof(struct resource));
+		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+		switch (memory_chunk[i].type) {
+		case CHUNK_READ_WRITE:
+			res->name = "System RAM";
+			break;
+		case CHUNK_READ_ONLY:
+			res->name = "System ROM";
+			res->flags |= IORESOURCE_READONLY;
+			break;
+		default:
+			res->name = "reserved";
+		}
+		res->start = memory_chunk[i].addr;
+		res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
+		request_resource(&iomem_resource, res);
+		request_resource(res, &code_resource);
+		request_resource(res, &data_resource);
+	}
+}
+
+static void __init
+setup_memory(void)
+{
+        unsigned long bootmap_size;
+	unsigned long start_pfn, end_pfn, init_pfn;
+	unsigned long last_rw_end;
+	int i;
 
 	/*
 	 * partially used pages are not usable - thus
@@ -429,6 +482,10 @@ void __init setup_arch(char **cmdline_p)
 	start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	end_pfn = max_pfn = memory_end >> PAGE_SHIFT;
 
+	/* Initialize storage key for kernel pages */
+	for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
+		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+
 	/*
 	 * Initialize the boot-time allocator (with low memory only):
 	 */
@@ -437,7 +494,9 @@ void __init setup_arch(char **cmdline_p)
 	/*
 	 * Register RAM areas with the bootmem allocator.
 	 */
-	for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
+	last_rw_end = start_pfn;
+
+	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
 		unsigned long start_chunk, end_chunk;
 
 		if (memory_chunk[i].type != CHUNK_READ_WRITE)
@@ -450,102 +509,98 @@ void __init setup_arch(char **cmdline_p)
 			start_chunk = start_pfn;
 		if (end_chunk > end_pfn)
 			end_chunk = end_pfn;
-		if (start_chunk < end_chunk)
+		if (start_chunk < end_chunk) {
+			/* Initialize storage key for RAM pages */
+			for (init_pfn = start_chunk ; init_pfn < end_chunk;
+			     init_pfn++)
+				page_set_storage_key(init_pfn << PAGE_SHIFT,
+						     PAGE_DEFAULT_KEY);
 			free_bootmem(start_chunk << PAGE_SHIFT,
 				     (end_chunk - start_chunk) << PAGE_SHIFT);
+			if (last_rw_end < start_chunk)
+				add_memory_hole(last_rw_end, start_chunk - 1);
+			last_rw_end = end_chunk;
+		}
 	}
 
-        /*
-         * Reserve the bootmem bitmap itself as well. We do this in two
-         * steps (first step was init_bootmem()) because this catches
-         * the (very unlikely) case of us accidentally initializing the
-         * bootmem allocator with an invalid RAM area.
-         */
-        reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
+	psw_set_key(PAGE_DEFAULT_KEY);
+
+	if (last_rw_end < end_pfn - 1)
+		add_memory_hole(last_rw_end, end_pfn - 1);
+
+	/*
+	 * Reserve the bootmem bitmap itself as well. We do this in two
+	 * steps (first step was init_bootmem()) because this catches
+	 * the (very unlikely) case of us accidentally initializing the
+	 * bootmem allocator with an invalid RAM area.
+	 */
+	reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-        if (INITRD_START) {
+	if (INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= memory_end) {
 			reserve_bootmem(INITRD_START, INITRD_SIZE);
 			initrd_start = INITRD_START;
 			initrd_end = initrd_start + INITRD_SIZE;
 		} else {
-                        printk("initrd extends beyond end of memory "
-                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-                               initrd_start + INITRD_SIZE, memory_end);
-                        initrd_start = initrd_end = 0;
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_start + INITRD_SIZE, memory_end);
+			initrd_start = initrd_end = 0;
 		}
-        }
+	}
 #endif
+}
 
-	for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
-		struct resource *res;
-
-		res = alloc_bootmem_low(sizeof(struct resource));
-		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
-
-		switch (memory_chunk[i].type) {
-		case CHUNK_READ_WRITE:
-			res->name = "System RAM";
-			break;
-		case CHUNK_READ_ONLY:
-			res->name = "System ROM";
-			res->flags |= IORESOURCE_READONLY;
-			break;
-		default:
-			res->name = "reserved";
-		}
-		res->start = memory_chunk[i].addr;
-		res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
-		request_resource(&iomem_resource, res);
-		request_resource(res, &code_resource);
-		request_resource(res, &data_resource);
-	}
+/*
+ * Setup function called from init/main.c just after the banner
+ * was printed.
+ */
 
+void __init
+setup_arch(char **cmdline_p)
+{
         /*
-         * Setup lowcore for boot cpu
+         * print what head.S has found out about the machine
          */
 #ifndef CONFIG_ARCH_S390X
-	lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
-	memset(lc, 0, PAGE_SIZE);
+	printk((MACHINE_IS_VM) ?
+	       "We are running under VM (31 bit mode)\n" :
+	       "We are running native (31 bit mode)\n");
+	printk((MACHINE_HAS_IEEE) ?
+	       "This machine has an IEEE fpu\n" :
+	       "This machine has no IEEE fpu\n");
 #else /* CONFIG_ARCH_S390X */
-	lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
-	memset(lc, 0, 2*PAGE_SIZE);
+	printk((MACHINE_IS_VM) ?
+	       "We are running under VM (64 bit mode)\n" :
+	       "We are running native (64 bit mode)\n");
 #endif /* CONFIG_ARCH_S390X */
-	lc->restart_psw.mask = PSW_BASE_BITS;
-	lc->restart_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-	lc->external_new_psw.mask = PSW_KERNEL_BITS;
-	lc->external_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
-	lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
-	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
-	lc->program_new_psw.mask = PSW_KERNEL_BITS;
-	lc->program_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
-	lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
-	lc->mcck_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
-	lc->io_new_psw.mask = PSW_KERNEL_BITS;
-	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
-	lc->ipl_device = S390_lowcore.ipl_device;
-	lc->jiffy_timer = -1LL;
-	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
-	lc->async_stack = (unsigned long)
-		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
-#ifdef CONFIG_CHECK_STACK
-	lc->panic_stack = (unsigned long)
-		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
-#endif
-	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
-	lc->thread_info = (unsigned long) &init_thread_union;
-#ifdef CONFIG_ARCH_S390X
-	if (MACHINE_HAS_DIAG44)
-		lc->diag44_opcode = 0x83000044;
-	else
-		lc->diag44_opcode = 0x07000700;
+
+        ROOT_DEV = Root_RAM0;
+#ifndef CONFIG_ARCH_S390X
+	memory_end = memory_size & ~0x400000UL;  /* align memory end to 4MB */
+        /*
+         * We need some free virtual space to be able to do vmalloc.
+         * On a machine with 2GB memory we make sure that we have at
+         * least 128 MB free space for vmalloc.
+         */
+        if (memory_end > 1920*1024*1024)
+                memory_end = 1920*1024*1024;
+#else /* CONFIG_ARCH_S390X */
+	memory_end = memory_size & ~0x200000UL;  /* detected in head.s */
 #endif /* CONFIG_ARCH_S390X */
-	set_prefix((u32)(unsigned long) lc);
+
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
+
+	parse_cmdline_early(cmdline_p);
+
+	setup_memory();
+	setup_resources();
+	setup_lowcore();
+
         cpu_init();
         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
 
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -116,7 +116,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -214,7 +214,7 @@ asmlinkage long sys_sigreturn(struct pt_
 	sigframe __user *frame = (sigframe __user *)regs->gprs[15];
 	sigset_t set;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
 		goto badframe;
@@ -240,7 +240,7 @@ asmlinkage long sys_rt_sigreturn(struct 
 	rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
 	sigset_t set;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
@@ -282,7 +282,7 @@ get_sigframe(struct k_sigaction *ka, str
 
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (! on_sig_stack(sp))
+		if (! sas_ss_flags(sp))
 			sp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -50,12 +50,9 @@ extern volatile int __cpu_logical_map[];
  */
 
 struct _lowcore *lowcore_ptr[NR_CPUS];
-cycles_t         cacheflush_time=0;
-int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 
 cpumask_t cpu_online_map;
 cpumask_t cpu_possible_map;
-unsigned long    cache_decay_ticks = 0;
 
 static struct task_struct *current_set[NR_CPUS];
 
@@ -212,29 +209,29 @@ EXPORT_SYMBOL(smp_call_function_on);
 
 static inline void do_send_stop(void)
 {
-        int i, rc;
+        int cpu, rc;
 
         /* stop all processors */
-        for (i =  0; i < NR_CPUS; i++) {
-                if (!cpu_online(i) || smp_processor_id() == i)
+	for_each_online_cpu(cpu) {
+		if (cpu == smp_processor_id())
 			continue;
 		do {
-			rc = signal_processor(i, sigp_stop);
+			rc = signal_processor(cpu, sigp_stop);
 		} while (rc == sigp_busy);
 	}
 }
 
 static inline void do_store_status(void)
 {
-        int i, rc;
+        int cpu, rc;
 
         /* store status of all processors in their lowcores (real 0) */
-        for (i =  0; i < NR_CPUS; i++) {
-                if (!cpu_online(i) || smp_processor_id() == i) 
+	for_each_online_cpu(cpu) {
+		if (cpu == smp_processor_id())
 			continue;
 		do {
 			rc = signal_processor_p(
-				(__u32)(unsigned long) lowcore_ptr[i], i,
+				(__u32)(unsigned long) lowcore_ptr[cpu], cpu,
 				sigp_store_status_at_address);
 		} while(rc == sigp_busy);
         }
@@ -259,37 +256,41 @@ void smp_send_stop(void)
 /*
  * Reboot, halt and power_off routines for SMP.
  */
-static cpumask_t cpu_restart_map;
 
 static void do_machine_restart(void * __unused)
 {
+	int cpu;
 	static atomic_t cpuid = ATOMIC_INIT(-1);
 
-	cpu_clear(smp_processor_id(), cpu_restart_map);
-	if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
-		/* Wait for all other cpus to enter do_machine_restart. */
-		while (!cpus_empty(cpu_restart_map))
+	if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
+		signal_processor(smp_processor_id(), sigp_stop);
+
+	/* Wait for all other cpus to enter stopped state */
+	for_each_online_cpu(cpu) {
+		if (cpu == smp_processor_id())
+			continue;
+		while(!smp_cpu_not_running(cpu))
 			cpu_relax();
-		/* 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).
-		 */
-		if (MACHINE_IS_VM)
-			cpcmd ("IPL", NULL, 0);
-		else
-			reipl (0x10000 | S390_lowcore.ipl_device);
 	}
-	signal_processor(smp_processor_id(), sigp_stop);
+
+	/* 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).
+	 */
+	if (MACHINE_IS_VM)
+		cpcmd ("IPL", NULL, 0);
+	else
+		reipl (0x10000 | S390_lowcore.ipl_device);
 }
 
 void machine_restart_smp(char * __unused) 
 {
-	cpu_restart_map = cpu_online_map;
         on_each_cpu(do_machine_restart, NULL, 0, 0);
 }
 
@@ -384,16 +385,16 @@ static void smp_ext_bitcall(int cpu, ec_
  */
 static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
-        int i;
+        int cpu;
 
-        for (i = 0; i < NR_CPUS; i++) {
-                if (!cpu_online(i) || smp_processor_id() == i)
+	for_each_online_cpu(cpu) {
+		if (cpu == smp_processor_id())
                         continue;
                 /*
                  * Set signaling bit in lowcore of target cpu and kick it
                  */
-		set_bit(sig, (unsigned long *) &lowcore_ptr[i]->ext_call_fast);
-                while (signal_processor(i, sigp_external_call) == sigp_busy)
+		set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
+		while (signal_processor(cpu, sigp_external_call) == sigp_busy)
 			udelay(10);
         }
 }
@@ -497,7 +498,6 @@ __init smp_check_cpus(unsigned int max_c
 	 */
 
 	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
-	__cpu_logical_map[0] = boot_cpu_addr;
 	current_thread_info()->cpu = 0;
 	num_cpus = 1;
 	for (cpu = 0; cpu <= 65535 && num_cpus < max_cpus; cpu++) {
@@ -725,7 +725,7 @@ void
 __cpu_die(unsigned int cpu)
 {
 	/* Wait until target cpu is down */
-	while (!cpu_stopped(cpu))
+	while (!smp_cpu_not_running(cpu))
 		cpu_relax();
 	printk("Processor %d spun down\n", cpu);
 }
@@ -790,6 +790,7 @@ void __devinit smp_prepare_boot_cpu(void
 	BUG_ON(smp_processor_id() != 0);
 
 	cpu_set(0, cpu_online_map);
+	cpu_set(0, cpu_present_map);
 	cpu_set(0, cpu_possible_map);
 	S390_lowcore.percpu_offset = __per_cpu_offset[0];
 	current_set[0] = current;
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -275,7 +275,7 @@ NI_SYSCALL							/* reserved for vserver
 SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
 SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
 SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
-NI_SYSCALL							/* 267 new sys_remap_file_pages */
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
 NI_SYSCALL							/* 268 sys_mbind */
 NI_SYSCALL							/* 269 sys_get_mempolicy */
 NI_SYSCALL							/* 270 sys_set_mempolicy */
@@ -286,3 +286,7 @@ SYSCALL(sys_mq_timedreceive,sys_mq_timed
 SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
 SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
 NI_SYSCALL							/* reserved for kexec */
+SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
+SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
+SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl)		/* 280 */
+SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid_wrapper)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -168,8 +168,17 @@ void account_ticks(struct pt_regs *regs)
 	__u32 ticks, xticks;
 
 	/* Calculate how many ticks have passed. */
-	if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer)
+	if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
+		/*
+		 * We have to program the clock comparator even if
+		 * no tick has passed. That happens if e.g. an i/o
+		 * interrupt wakes up an idle processor that has
+		 * switched off its hz timer.
+		 */
+		tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
+		asm volatile ("SCKC %0" : : "m" (tmp));
 		return;
+	}
 	tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
 	if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
 		ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
@@ -235,7 +244,7 @@ int sysctl_hz_timer = 1;
  */
 static inline void stop_hz_timer(void)
 {
-	__u64 timer;
+	__u64 timer, todval;
 
 	if (sysctl_hz_timer != 0)
 		return;
@@ -256,8 +265,14 @@ static inline void stop_hz_timer(void)
 	 * for the next event.
 	 */
 	timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64;
-	timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
-	asm volatile ("SCKC %0" : : "m" (timer));
+	todval = -1ULL;
+	/* Be careful about overflows. */
+	if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) {
+		timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
+		if (timer >= jiffies_timer_cc)
+			todval = timer;
+	}
+	asm volatile ("SCKC %0" : : "m" (todval));
 }
 
 /*
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -19,6 +19,7 @@
 #include <linux/notifier.h>
 #include <linux/kernel_stat.h>
 #include <linux/rcupdate.h>
+#include <linux/posix-timers.h>
 
 #include <asm/s390_ext.h>
 #include <asm/timer.h>
@@ -69,6 +70,7 @@ void account_user_vtime(struct task_stru
 	if (rcu_pending(smp_processor_id()))
 		rcu_check_callbacks(smp_processor_id(), rcu_user_flag);
 	scheduler_tick();
+ 	run_posix_cpu_timers(tsk);
 }
 
 /*
@@ -120,12 +122,17 @@ static void start_cpu_timer(void)
 	struct vtimer_queue *vt_list;
 
 	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
-	set_vtimer(vt_list->idle);
+
+	/* CPU timer interrupt is pending, don't reprogramm it */
+	if (vt_list->idle & 1LL<<63)
+		return;
+
+	if (!list_empty(&vt_list->list))
+		set_vtimer(vt_list->idle);
 }
 
 static void stop_cpu_timer(void)
 {
-	__u64 done;
 	struct vtimer_queue *vt_list;
 
 	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
@@ -136,21 +143,17 @@ static void stop_cpu_timer(void)
 		goto fire;
 	}
 
-	/* store progress */
-	asm volatile ("STPT %0" : "=m" (done));
+	/* store the actual expire value */
+	asm volatile ("STPT %0" : "=m" (vt_list->idle));
 
 	/*
-	 * If done is negative we do not stop the CPU timer
-	 * because we will get instantly an interrupt that
-	 * will start the CPU timer again.
+	 * If the CPU timer is negative we don't reprogramm
+	 * it because we will get instantly an interrupt.
 	 */
-	if (done & 1LL<<63)
+	if (vt_list->idle & 1LL<<63)
 		return;
-	else
-		vt_list->offset += vt_list->to_expire - done;
 
-	/* save the actual expire value */
-	vt_list->idle = done;
+	vt_list->offset += vt_list->to_expire - vt_list->idle;
 
 	/*
 	 * We cannot halt the CPU timer, we just write a value that
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -20,6 +20,11 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 
+static char *sender = "VMRMSVM";
+module_param(sender, charp, 0);
+MODULE_PARM_DESC(sender,
+		 "Guest name that may send SMSG messages (default VMRMSVM)");
+
 #include "../../../drivers/s390/net/smsgiucv.h"
 
 #define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2)
@@ -367,10 +372,12 @@ static struct ctl_table cmm_dir_table[] 
 #ifdef CONFIG_CMM_IUCV
 #define SMSG_PREFIX "CMM"
 static void
-cmm_smsg_target(char *msg)
+cmm_smsg_target(char *from, char *msg)
 {
 	long pages, seconds;
 
+	if (strlen(sender) > 0 && strcmp(from, sender) != 0)
+		return;
 	if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg))
 		return;
 	if (strncmp(msg, "SHRINK", 6) == 0) {
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -62,8 +62,8 @@ void bust_spinlocks(int yes)
 		oops_in_progress = 1;
 	} else {
 		int loglevel_save = console_loglevel;
-		oops_in_progress = 0;
 		console_unblank();
+		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
@@ -87,6 +87,7 @@ static int __check_access_register(struc
 	if (areg == 0)
 		/* Access via access register 0 -> kernel address */
 		return 0;
+	save_access_regs(current->thread.acrs);
 	if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1)
 		/*
 		 * access register contains 0 -> kernel address,
@@ -115,11 +116,11 @@ static inline int check_user_space(struc
 	 *   3: Home Segment Table Descriptor
 	 */
 	int descriptor = S390_lowcore.trans_exc_code & 3;
-	if (descriptor == 1) {
-		save_access_regs(current->thread.acrs);
+	if (unlikely(descriptor == 1))
 		return __check_access_register(regs, error_code);
-	}
-	return descriptor >> 1;
+	if (descriptor == 2)
+		return current->thread.mm_segment.ar4;
+	return descriptor != 0;
 }
 
 /*
@@ -206,7 +207,7 @@ do_exception(struct pt_regs *regs, unsig
 	 * we are not in an interrupt and that there is a 
 	 * user context.
 	 */
-        if (user_address == 0 || in_interrupt() || !mm)
+        if (user_address == 0 || in_atomic() || !mm)
                 goto no_context;
 
 	/*
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -101,6 +101,7 @@ extern unsigned long _end;
 extern unsigned long __init_begin;
 extern unsigned long __init_end;
 
+extern unsigned long __initdata zholes_size[];
 /*
  * paging_init() sets up the page tables
  */
@@ -145,7 +146,7 @@ void __init paging_init(void)
                 for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
                         pte = pfn_pte(pfn, PAGE_KERNEL);
                         if (pfn >= max_low_pfn)
-                                pte_clear(&pte);
+                                pte_clear(&init_mm, 0, &pte);
                         set_pte(pg_table, pte);
                         pfn++;
                 }
@@ -163,10 +164,13 @@ void __init paging_init(void)
         local_flush_tlb();
 
 	{
-		unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0};
+		unsigned long zones_size[MAX_NR_ZONES];
 
+		memset(zones_size, 0, sizeof(zones_size));
 		zones_size[ZONE_DMA] = max_low_pfn;
-		free_area_init(zones_size);
+		free_area_init_node(0, &contig_page_data, zones_size,
+				    __pa(PAGE_OFFSET) >> PAGE_SHIFT,
+				    zholes_size);
 	}
         return;
 }
@@ -184,9 +188,10 @@ void __init paging_init(void)
           _KERN_REGION_TABLE;
 	static const int ssm_mask = 0x04000000L;
 
-	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	unsigned long zones_size[MAX_NR_ZONES];
 	unsigned long dma_pfn, high_pfn;
 
+	memset(zones_size, 0, sizeof(zones_size));
 	dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
 	high_pfn = max_low_pfn;
 
@@ -198,8 +203,8 @@ void __init paging_init(void)
 	}
 
 	/* Initialize mem_map[].  */
-	free_area_init(zones_size);
-
+	free_area_init_node(0, &contig_page_data, zones_size,
+			    __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
 
 	/*
 	 * map whole physical memory to virtual memory (identity mapping) 
@@ -229,7 +234,7 @@ void __init paging_init(void)
                         for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
                                 pte = pfn_pte(pfn, PAGE_KERNEL);
                                 if (pfn >= max_low_pfn) {
-                                        pte_clear(&pte); 
+                                        pte_clear(&init_mm, 0, &pte); 
                                         continue;
                                 }
                                 set_pte(pt_dir, pte);
diff --git a/arch/s390/oprofile/Kconfig b/arch/s390/oprofile/Kconfig
--- a/arch/s390/oprofile/Kconfig
+++ b/arch/s390/oprofile/Kconfig
@@ -1,16 +1,15 @@
 
 menu "Profiling support"
-	depends on EXPERIMENTAL
 
 config PROFILING
-	bool "Profiling support (EXPERIMENTAL)"
+	bool "Profiling support"
 	help
 	  Say Y here to enable profiling support mechanisms used by
 	  profilers such as readprofile or OProfile.
 
 
 config OPROFILE
-	tristate "OProfile system profiling (EXPERIMENTAL)"
+	tristate "OProfile system profiling"
 	depends on PROFILING
 	help
 	  OProfile is a profiling system capable of profiling the
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -25,6 +25,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_HARDIRQS
+	bool
+	default y
+
+config GENERIC_IRQ_PROBE
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -651,19 +659,10 @@ menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
 
-config CPU_FREQ_TABLE
-	tristate "CPU frequency table helpers"
-	depends on CPU_FREQ
-	default y
-	help
-	  Many cpufreq drivers use these helpers, so only say N here if
-	  the cpufreq driver of your choice doesn't need these helpers.
-
-	  If unsure, say Y.
-
 config SH_CPU_FREQ
 	tristate "SuperH CPU Frequency driver"
 	depends on CPU_FREQ
+	select CPU_FREQ_TABLE
 	help
 	  This adds the cpufreq driver for SuperH. At present, only
 	  the SH-4 is supported.
@@ -694,6 +693,10 @@ config RTC_9701JE
 
 endmenu
 
+config ISA_DMA_API
+	bool
+	depends on MPC1211
+	default y
 
 menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
 
@@ -755,7 +758,6 @@ source "drivers/pci/hotplug/Kconfig"
 
 endmenu
 
-
 menu "Executable file formats"
 
 source "fs/Kconfig.binfmt"
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -31,6 +31,13 @@ cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+=
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -R .stab -R .stabstr -S
 
 #
+# arch/sh/defconfig doesn't reflect any real hardware, and as such should
+# never be used by anyone. Use a board-specific defconfig that has a
+# reasonable chance of being current instead.
+#
+KBUILD_DEFCONFIG := rts7751r2d_defconfig
+
+#
 # Choosing incompatible machines durings configuration will result in
 # error messages during linking.
 #
diff --git a/arch/sh/boards/hp6xx/hp620/Makefile b/arch/sh/boards/hp6xx/hp620/Makefile
--- a/arch/sh/boards/hp6xx/hp620/Makefile
+++ b/arch/sh/boards/hp6xx/hp620/Makefile
@@ -2,5 +2,5 @@
 # Makefile for the HP620 specific parts of the kernel
 #
 
-obj-y	 := mach.o
+obj-y	 := mach.o setup.o
 
diff --git a/arch/sh/boards/hp6xx/hp620/setup.c b/arch/sh/boards/hp6xx/hp620/setup.c
new file mode 100644
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp620/setup.c
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp620/setup.c
+ *
+ * Copyright (C) 2002 Andriy Skulysh, 2005 Kristoffer Ericson
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See Linux/COPYING for more information.
+ *
+ * Setup code for an HP620.
+ * Due to similiarity with hp680/hp690 same inits are done (for now)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/io.h>
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/cpu/dac.h>
+
+const char *get_system_type(void)
+{
+	return "HP620";
+}
+
+int __init platform_setup(void)
+{
+	u16 v;
+
+	v  = inw(HD64461_STBCR);
+	v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST  |
+	     HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+	     HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
+	     HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
+	     HD64461_STBCR_SAFECKE_IST;
+	outw(v, HD64461_STBCR);
+
+	v  = inw(HD64461_GPADR);
+	v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0;
+	outw(v, HD64461_GPADR);
+
+	sh_dac_disable(DAC_SPEAKER_VOLUME);
+
+	return 0;
+}
+
diff --git a/arch/sh/boards/se/7300/io.c b/arch/sh/boards/se/7300/io.c
--- a/arch/sh/boards/se/7300/io.c
+++ b/arch/sh/boards/se/7300/io.c
@@ -1,12 +1,16 @@
 /*
- * linux/arch/sh/boards/se/7300/io.c
+ * arch/sh/boards/se/7300/io.c
  *
  * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/kernel/io_shmse.c
+ *
+ * I/O routine for SH-Mobile3 73180 SolutionEngine.
+ *
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <asm/se7300/se7300.h>
+#include <asm/mach/se7300.h>
 #include <asm/io.h>
 
 #define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
--- a/arch/sh/boards/sh03/rtc.c
+++ b/arch/sh/boards/sh03/rtc.c
@@ -115,8 +115,6 @@ static int set_rtc_mmss(unsigned long no
 	real_minutes %= 60;
 
 	if (abs(real_minutes - cmos_minutes) < 30) {
-		BIN_TO_BCD(real_seconds);
-		BIN_TO_BCD(real_minutes);
 		ctrl_outb(real_seconds % 10, RTC_SEC1);
 		ctrl_outb(real_seconds / 10, RTC_SEC10);
 		ctrl_outb(real_minutes % 10, RTC_MIN1);
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
--- a/arch/sh/boards/snapgear/setup.c
+++ b/arch/sh/boards/snapgear/setup.c
@@ -27,6 +27,7 @@
 #include <asm/mach/io.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/cpu/timer.h>
 
 extern void (*board_time_init)(void);
 extern void secureedge5410_rtc_init(void);
@@ -111,11 +112,6 @@ static void __init init_snapgear_IRQ(voi
 #endif
 #define TMU_TSTR_INIT	1
 #define TMU1_TCR_CALIB	0x0000
-#define TMU_TOCR	0xffd80000	/* Byte access */
-#define TMU_TSTR	0xffd80004	/* Byte access */
-#define TMU1_TCOR	0xffd80014	/* Long access */
-#define TMU1_TCNT	0xffd80018	/* Long access */
-#define TMU1_TCR	0xffd8001c	/* Word access */
 
 
 #ifdef FAST_POLL_INTR
diff --git a/arch/sh/configs/adx_defconfig b/arch/sh/configs/adx_defconfig
--- a/arch/sh/configs/adx_defconfig
+++ b/arch/sh/configs/adx_defconfig
@@ -1,15 +1,46 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:26 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -17,10 +48,13 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_MODULES is not set
 
 #
-# Processor type and features
+# System type
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
 # CONFIG_SH_HP620 is not set
@@ -29,57 +63,115 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SH_CQREEK is not set
 # CONFIG_SH_DMIDA is not set
 # CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
 # CONFIG_SH_DREAMCAST is not set
 # CONFIG_SH_CAT68701 is not set
 # CONFIG_SH_BIGSUR is not set
 # CONFIG_SH_SH2000 is not set
 CONFIG_SH_ADX=y
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
-CONFIG_SH_RTC=y
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 CONFIG_CPU_SUBTYPE_SH7750=y
 # CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
 CONFIG_MEMORY_START=0x08000000
 CONFIG_MEMORY_SIZE=0x00400000
 CONFIG_MEMORY_SET=y
-# CONFIG_DISCONTIGMEM is not set
-
-#
-# General setup
-#
-CONFIG_ISA=y
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-# CONFIG_NET is not set
+# CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_CF_ENABLER=y
 # CONFIG_CF_AREA5 is not set
 CONFIG_CF_AREA6=y
 CONFIG_CF_BASE_ADDR=0xb8000000
-# CONFIG_HD64461 is not set
-# CONFIG_HD64465 is not set
+CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=50000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 # CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
 # CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
-# Parallel port support
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -87,190 +179,361 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
 # 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_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# 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
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
 
 #
-# IDE, ATA and ATAPI Block devices
+# Please see Documentation/ide.txt for help/info on IDE drives
 #
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # 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 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_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE_SH=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI 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
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 # CONFIG_SCSI is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
 #
-# CONFIG_CD_NO_IDESCSI is not set
 
 #
-# Input core support
+# IEEE 1394 (FireWire) support
+#
+
 #
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+# I2O device support
+#
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Joysticks
+# IPMI
 #
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_PSMOUSE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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
-# CONFIG_REISERFS_PROC_INFO is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS 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
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
 
 #
-# Multimedia devices
+# Native Language Support
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_NLS is not set
 
 #
-# Sound
+# Profiling support
 #
-# CONFIG_SOUND is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 CONFIG_SH_STANDARD_BIOS=y
-CONFIG_SH_EARLY_PRINTK=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
 
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/cqreek_defconfig b/arch/sh/configs/cqreek_defconfig
--- a/arch/sh/configs/cqreek_defconfig
+++ b/arch/sh/configs/cqreek_defconfig
@@ -1,15 +1,46 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:38 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -17,10 +48,13 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_MODULES is not set
 
 #
-# Processor type and features
+# System type
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
 # CONFIG_SH_HP620 is not set
@@ -29,55 +63,110 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SH_CQREEK=y
 # CONFIG_SH_DMIDA is not set
 # CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
 # CONFIG_SH_DREAMCAST is not set
 # CONFIG_SH_CAT68701 is not set
 # CONFIG_SH_BIGSUR is not set
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
-CONFIG_SH_RTC=y
+# CONFIG_CPU_SH2 is not set
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SH4 is not set
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 CONFIG_CPU_SUBTYPE_SH7708=y
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_DISCONTIGMEM is not set
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_SH_DSP=y
+CONFIG_SH_ADC=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=1193182
 
 #
-# General setup
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
 #
-CONFIG_ISA=y
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-# CONFIG_NET is not set
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
-# CONFIG_HD64461 is not set
-# CONFIG_HD64465 is not set
 # CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
 # CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
 CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
-# Parallel port support
+# SH initrd options
 #
-# CONFIG_PARPORT is not set
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -85,190 +174,360 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
 # 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_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# 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
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
 
 #
-# IDE, ATA and ATAPI Block devices
+# Please see Documentation/ide.txt for help/info on IDE drives
 #
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # 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 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_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE_SH=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI 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
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 # CONFIG_SCSI is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_INPUT=y
 
 #
-# Input core support
+# Userland interfaces
 #
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Joysticks
+# Non-8250 serial port support
 #
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_PSMOUSE is not set
+# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=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
-# CONFIG_REISERFS_PROC_INFO is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS 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
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
 
 #
-# Multimedia devices
+# Native Language Support
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_NLS is not set
 
 #
-# Sound
+# Profiling support
 #
-# CONFIG_SOUND is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 CONFIG_SH_STANDARD_BIOS=y
-CONFIG_SH_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
 
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -1,36 +1,50 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:40 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -40,6 +54,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -47,6 +62,8 @@ CONFIG_KMOD=y
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -63,20 +80,29 @@ CONFIG_SH_DREAMCAST=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
 CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 CONFIG_CPU_SUBTYPE_SH7750=y
 # CONFIG_CPU_SUBTYPE_SH7751 is not set
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 CONFIG_HUGETLB_PAGE_SIZE_64K=y
 # CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
@@ -85,6 +111,7 @@ CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x01000000
 CONFIG_MEMORY_SET=y
 # CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_FPU=y
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_CPU_LITTLE_ENDIAN=y
@@ -94,25 +121,36 @@ CONFIG_PREEMPT=y
 CONFIG_SH_OCRAM=y
 CONFIG_SH_STORE_QUEUES=y
 # CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=49876504
 
 #
 # CPU Frequency scaling
 #
 CONFIG_CPU_FREQ=y
-# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_24_API is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
 CONFIG_CPU_FREQ_TABLE=y
 CONFIG_SH_CPU_FREQ=y
+
+#
+# DMA support
+#
 CONFIG_SH_DMA=y
 CONFIG_NR_ONCHIP_DMA_CHANNELS=4
 CONFIG_NR_DMA_CHANNELS_BOOL=y
 CONFIG_NR_DMA_CHANNELS=9
+
+#
+# Companion Chips
+#
 # CONFIG_HD6446X_SERIES is not set
 
 #
@@ -126,9 +164,13 @@ CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-# CONFIG_PCMCIA is not set
 
 #
 # PCI Hotplug Support
@@ -143,12 +185,19 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
 # Device Drivers
 #
 
 #
 # Generic Driver Options
 #
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 
 #
@@ -173,12 +222,26 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=1024
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -210,10 +273,6 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_I2O is not set
 
 #
-# Macintosh device drivers
-#
-
-#
 # Networking support
 #
 CONFIG_NET=y
@@ -236,23 +295,24 @@ CONFIG_IP_PNP_DHCP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -261,27 +321,32 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
 
 #
 # Ethernet (10 or 100Mbit)
@@ -292,6 +357,7 @@ CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
 
 #
 # Tulip family network device support
@@ -316,7 +382,6 @@ CONFIG_8139TOO=y
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
-CONFIG_8139_RXBUF_IDX=1
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -333,50 +398,36 @@ CONFIG_8139_RXBUF_IDX=1
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR 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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_IRDA is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# Bluetooth support
+# Wan interfaces
 #
-# CONFIG_BT is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
@@ -415,6 +466,8 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -422,6 +475,7 @@ CONFIG_SERIO=y
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_MAPLE is not set
@@ -429,6 +483,7 @@ CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_MAPLE is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -458,12 +513,6 @@ CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
 # IPMI
 #
 # CONFIG_IPMI_HANDLER is not set
@@ -485,7 +534,6 @@ CONFIG_SH_WDT=y
 #
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
-# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
@@ -495,8 +543,6 @@ CONFIG_SH_WDT=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -506,6 +552,11 @@ CONFIG_SH_WDT=y
 # CONFIG_I2C is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -523,18 +574,22 @@ CONFIG_SH_WDT=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_PVR2=y
-# CONFIG_FB_E1355 is not set
+# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
@@ -547,10 +602,8 @@ CONFIG_FB_PVR2=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
@@ -571,6 +624,7 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_SUPERH_MONO is not set
 # CONFIG_LOGO_SUPERH_VGA16 is not set
 CONFIG_LOGO_SUPERH_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -581,6 +635,12 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -588,10 +648,14 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # CONFIG_USB_GADGET is not set
 
 #
-# Maple Bus input peripherals
+# MMC/SD Card support
 #
-# CONFIG_MAPLE_KEYBOARD is not set
-# CONFIG_MAPLE_MOUSE is not set
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
@@ -601,10 +665,15 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -617,7 +686,8 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -625,11 +695,13 @@ CONFIG_ROMFS_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -662,9 +734,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -691,15 +763,17 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -708,7 +782,13 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/sh/configs/hp680_defconfig b/arch/sh/configs/hp680_defconfig
--- a/arch/sh/configs/hp680_defconfig
+++ b/arch/sh/configs/hp680_defconfig
@@ -1,36 +1,47 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:41 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
 CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -42,6 +53,8 @@ CONFIG_IOSCHED_DEADLINE=y
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -58,20 +71,29 @@ CONFIG_SH_HP680=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 CONFIG_CPU_SH3=y
 # CONFIG_CPU_SH4 is not set
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7751 is not set
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 # CONFIG_CMDLINE_BOOL is not set
 CONFIG_MEMORY_START=0x0c000000
@@ -80,6 +102,7 @@ CONFIG_MEMORY_SET=y
 # CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_SH_RTC=y
 # CONFIG_SH_DSP is not set
+CONFIG_SH_ADC=y
 CONFIG_SH_HP600=y
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
@@ -89,9 +112,22 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_SH_WRITETHROUGH is not set
 # CONFIG_SH_OCRAM is not set
 # CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=1193182
+
+#
+# CPU Frequency scaling
+#
 # CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 # CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
 CONFIG_HD6446X_SERIES=y
 CONFIG_HD64461=y
 # CONFIG_HD64465 is not set
@@ -102,7 +138,19 @@ CONFIG_HD64461_IRQ=36
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
 # CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
 
 #
 # Executable file formats
@@ -112,8 +160,20 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -126,40 +186,57 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_PARPORT is not set
 
 #
+# Plug and Play support
+#
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
 
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+CONFIG_IDE_SH=y
+# CONFIG_IDE_ARM is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -173,19 +250,24 @@ CONFIG_IDE_GENERIC=y
 # CONFIG_MD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
-# Networking support
+# I2O device support
 #
-# CONFIG_NET is not set
 
 #
-# Amateur Radio support
+# Networking support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -222,6 +304,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -238,33 +321,125 @@ CONFIG_SERIO=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Unix98 PTY support
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
 #
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PSMOUSE is not set
+# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
 
 #
-# Serial drivers
+# Ftape, the floppy tape device driver
 #
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Non-8250 serial port support
+# I2C support
 #
-# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_I2C is not set
 
 #
-# I2C support
+# Dallas's 1-wire bus
 #
-# CONFIG_I2C is not set
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_EPSON1355 is not set
+CONFIG_FB_HIT=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+CONFIG_FONT_PEARL_8x8=y
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
@@ -275,10 +450,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -291,7 +471,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -299,9 +480,11 @@ CONFIG_EXT2_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
@@ -313,6 +496,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -335,60 +519,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_NLS is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_E1355 is not set
-CONFIG_FB_HIT=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-CONFIG_FONT_PEARL_8x8=y
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
 # Profiling support
 #
 # CONFIG_PROFILING is not set
@@ -396,15 +526,15 @@ CONFIG_FONT_PEARL_8x8=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -413,6 +543,12 @@ CONFIG_FONT_PEARL_8x8=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
--- a/arch/sh/configs/microdev_defconfig
+++ b/arch/sh/configs/microdev_defconfig
@@ -1,9 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:41 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -11,10 +16,12 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
@@ -24,17 +31,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -133,9 +143,13 @@ CONFIG_ISA=y
 # CONFIG_PCI is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-# CONFIG_PCMCIA is not set
 CONFIG_PCMCIA_PROBE=y
 
 #
@@ -185,12 +199,25 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -209,7 +236,6 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -275,6 +301,9 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -294,7 +323,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -419,7 +447,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -437,7 +464,6 @@ CONFIG_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -478,6 +504,12 @@ CONFIG_RTC=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -485,6 +517,16 @@ CONFIG_RTC=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -498,10 +540,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -533,6 +580,7 @@ CONFIG_DEVFS_MOUNT=y
 CONFIG_DEVPTS_FS_XATTR=y
 # CONFIG_DEVPTS_FS_SECURITY is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -565,10 +613,10 @@ CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -633,17 +681,17 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Kernel hacking
 #
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -657,6 +705,7 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -667,12 +716,17 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
--- a/arch/sh/configs/rts7751r2d_defconfig
+++ b/arch/sh/configs/rts7751r2d_defconfig
@@ -1,21 +1,26 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:42 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -24,16 +29,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -42,6 +51,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
@@ -50,6 +60,7 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
 # CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -66,9 +77,12 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
 # CONFIG_SH_HS7751RVOIP is not set
 CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
@@ -82,8 +96,10 @@ CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
 # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
@@ -92,6 +108,7 @@ CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_MEMORY_SET=y
 # CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
 CONFIG_ZERO_PAGE_OFFSET=0x00010000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_CPU_LITTLE_ENDIAN=y
@@ -128,7 +145,6 @@ CONFIG_RTC_9701JE=y
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
-CONFIG_ISA=y
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_AUTO=y
@@ -137,16 +153,13 @@ CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 CONFIG_PCI_NAMES=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-CONFIG_PCMCIA=m
-# CONFIG_PCMCIA_DEBUG is not set
-CONFIG_YENTA=m
-CONFIG_CARDBUS=y
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_PROBE=y
 
 #
 # PCI Hotplug Support
@@ -154,7 +167,6 @@ CONFIG_PCMCIA_PROBE=y
 CONFIG_HOTPLUG_PCI=y
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 
 #
@@ -171,6 +183,8 @@ CONFIG_BINFMT_ELF=y
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 
 #
@@ -186,24 +200,35 @@ CONFIG_BINFMT_ELF=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -215,14 +240,13 @@ CONFIG_BLK_DEV_IDE=y
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE 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_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -231,7 +255,6 @@ CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEPCI is not set
 CONFIG_IDE_SH=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -242,11 +265,6 @@ CONFIG_IDE_SH=y
 # CONFIG_SCSI is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
@@ -289,6 +307,9 @@ CONFIG_INET=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -308,13 +329,12 @@ CONFIG_INET=y
 # 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
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -345,38 +365,19 @@ CONFIG_MII=y
 # CONFIG_HAPPYMEAL 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_SMC91X is not set
 
 #
 # Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
-CONFIG_NET_ISA=y
-# CONFIG_E2100 is not set
-# CONFIG_EWRK3 is not set
-# CONFIG_EEXPRESS is not set
-# CONFIG_EEXPRESS_PRO is not set
-# CONFIG_HPLAN_PLUS is not set
-# CONFIG_HPLAN is not set
-# CONFIG_LP486E is not set
-# CONFIG_ETH16I is not set
-CONFIG_NE2000=m
-# CONFIG_ZNET is not set
-# CONFIG_SEEQ8005 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
@@ -394,7 +395,6 @@ CONFIG_8139TOO=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -407,6 +407,7 @@ CONFIG_8139TOO=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -429,20 +430,10 @@ CONFIG_NET_RADIO=y
 # Obsolete Wireless cards support (pre-802.11)
 #
 # CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-# CONFIG_WAVELAN is not set
-# CONFIG_PCMCIA_WAVELAN is not set
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
 
 #
 # Wireless 802.11b ISA/PCI cards support
 #
-# CONFIG_AIRO is not set
 CONFIG_HERMES=m
 # CONFIG_PLX_HERMES is not set
 # CONFIG_TMD_HERMES is not set
@@ -450,24 +441,12 @@ CONFIG_HERMES=m
 # CONFIG_ATMEL is not set
 
 #
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-CONFIG_PCMCIA_HERMES=m
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_WL3501 is not set
-
-#
 # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
 #
 # CONFIG_PRISM54 is not set
 CONFIG_NET_WIRELESS=y
 
 #
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
 # Wan interfaces
 #
 # CONFIG_WAN is not set
@@ -527,7 +506,6 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -547,14 +525,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # 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_SYNCLINK_CS is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -563,6 +534,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -611,37 +587,12 @@ CONFIG_SND_OPL3_LIB=m
 # CONFIG_SND_MPU401 is not set
 
 #
-# ISA devices
-#
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_CS4231 is not set
-# CONFIG_SND_CS4232 is not set
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_WAVEFRONT is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_SGALAXY is not set
-# CONFIG_SND_SSCAPE is not set
-
-#
 # PCI devices
 #
 CONFIG_SND_AC97_CODEC=m
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_AU8810 is not set
 # CONFIG_SND_AU8820 is not set
 # CONFIG_SND_AU8830 is not set
@@ -650,6 +601,8 @@ CONFIG_SND_AC97_CODEC=m
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
@@ -673,16 +626,10 @@ CONFIG_SND_YMFPCI=m
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 
 #
-# PCMCIA devices
-#
-# CONFIG_SND_VXPOCKET is not set
-# CONFIG_SND_VXP440 is not set
-# CONFIG_SND_PDAUDIOCF is not set
-
-#
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=m
@@ -713,6 +660,12 @@ CONFIG_SOUND_VOYAGERGX=m
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -720,6 +673,16 @@ CONFIG_SOUND_VOYAGERGX=m
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -728,10 +691,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -747,6 +715,8 @@ CONFIG_MINIX_FS=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -783,7 +753,6 @@ CONFIG_RAMFS=y
 #
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -824,6 +793,7 @@ CONFIG_NLS_CODEPAGE_932=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -848,17 +818,16 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -867,7 +836,12 @@ CONFIG_OPROFILE=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se7300_defconfig b/arch/sh/configs/se7300_defconfig
--- a/arch/sh/configs/se7300_defconfig
+++ b/arch/sh/configs/se7300_defconfig
@@ -1,24 +1,28 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:43 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
-# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
@@ -29,11 +33,13 @@ CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -46,6 +52,7 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
 CONFIG_SH_7300_SOLUTION_ENGINE=y
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -62,23 +69,29 @@ CONFIG_SH_7300_SOLUTION_ENGINE=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
 # CONFIG_SH_HS7751RVOIP is not set
 # CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 CONFIG_CPU_SH3=y
 # CONFIG_CPU_SH4 is not set
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 CONFIG_CPU_SUBTYPE_SH7300=y
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7751 is not set
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
 # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram0"
@@ -120,6 +133,19 @@ CONFIG_HEARTBEAT=y
 # CONFIG_PCI is not set
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
@@ -139,6 +165,9 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -158,11 +187,23 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -186,7 +227,6 @@ CONFIG_BLK_DEV_INITRD=y
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -234,6 +274,8 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -264,7 +306,6 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -274,6 +315,7 @@ CONFIG_IPMI_HANDLER=y
 CONFIG_IPMI_DEVICE_INTERFACE=y
 # CONFIG_IPMI_SI is not set
 CONFIG_IPMI_WATCHDOG=y
+# CONFIG_IPMI_POWEROFF is not set
 
 #
 # Watchdog Cards
@@ -290,13 +332,10 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
@@ -306,6 +345,11 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_I2C is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -331,6 +375,12 @@ CONFIG_SOFT_WATCHDOG=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -338,6 +388,16 @@ CONFIG_SOFT_WATCHDOG=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -346,10 +406,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -362,7 +427,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -415,9 +481,8 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 CONFIG_SH_STANDARD_BIOS=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_KGDB=y
@@ -442,11 +507,11 @@ CONFIG_KGDB_DEFPARITY_N=y
 # CONFIG_KGDB_DEFPARITY_O is not set
 CONFIG_KGDB_DEFBITS_8=y
 # CONFIG_KGDB_DEFBITS_7 is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -455,7 +520,12 @@ CONFIG_KGDB_DEFBITS_8=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se73180_defconfig b/arch/sh/configs/se73180_defconfig
--- a/arch/sh/configs/se73180_defconfig
+++ b/arch/sh/configs/se73180_defconfig
@@ -1,24 +1,28 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:44 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
-# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
 # CONFIG_AUDIT is not set
@@ -29,11 +33,13 @@ CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -42,6 +48,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
@@ -67,9 +74,12 @@ CONFIG_SH_73180_SOLUTION_ENGINE=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
 # CONFIG_SH_HS7751RVOIP is not set
 # CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
@@ -86,6 +96,7 @@ CONFIG_CPU_SH4=y
 CONFIG_CPU_SUBTYPE_SH73180=y
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
 # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
@@ -127,6 +138,19 @@ CONFIG_HEARTBEAT=y
 # CONFIG_PCI is not set
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
@@ -146,6 +170,9 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -165,12 +192,24 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -194,7 +233,6 @@ CONFIG_BLK_DEV_INITRD=y
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -257,7 +295,6 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -279,13 +316,10 @@ CONFIG_WATCHDOG=y
 # CONFIG_GEN_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
 # CONFIG_RAW_DRIVER is not set
 
@@ -295,6 +329,11 @@ CONFIG_WATCHDOG=y
 # CONFIG_I2C is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -320,6 +359,12 @@ CONFIG_WATCHDOG=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -327,6 +372,16 @@ CONFIG_WATCHDOG=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -335,10 +390,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -351,7 +411,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -364,6 +425,7 @@ CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -404,18 +466,17 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -424,7 +485,12 @@ CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
--- a/arch/sh/configs/se7705_defconfig
+++ b/arch/sh/configs/se7705_defconfig
@@ -1,9 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:45 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -11,10 +16,12 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,16 +30,19 @@ CONFIG_BROKEN_ON_SMP=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_IOSCHED_NOOP is not set
-CONFIG_IOSCHED_AS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -41,6 +51,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -66,6 +77,7 @@ CONFIG_SH_SOLUTION_ENGINE=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
 # CONFIG_SH_HS7751RVOIP is not set
 # CONFIG_SH_RTS7751R2D is not set
@@ -132,6 +144,19 @@ CONFIG_HEARTBEAT=y
 # CONFIG_PCI is not set
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
@@ -152,6 +177,7 @@ CONFIG_BINFMT_ELF=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -215,6 +241,7 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -241,12 +268,25 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -302,6 +342,9 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -321,7 +364,6 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -350,6 +392,7 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 CONFIG_STNIC=y
+# CONFIG_SMC91X is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -417,6 +460,8 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -447,7 +492,6 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -466,7 +510,6 @@ CONFIG_UNIX98_PTYS=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -507,6 +550,12 @@ CONFIG_UNIX98_PTYS=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -514,6 +563,16 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -522,10 +581,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -569,6 +633,7 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -590,9 +655,9 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -618,16 +683,16 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -636,6 +701,10 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
new file mode 100644
--- /dev/null
+++ b/arch/sh/configs/se7750_defconfig
@@ -0,0 +1,713 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:46 2005
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System type
+#
+CONFIG_SH_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+CONFIG_CPU_SUBTYPE_SH7750=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp"
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=49876504
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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
+# CONFIG_MTD_CMDLINE_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
+# CONFIG_INFTL 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_SOLUTIONENGINE=y
+CONFIG_MTD_SUPERH_RESERVE=0x00010000
+# CONFIG_MTD_MPC1211 is not set
+# CONFIG_MTD_RTS7751R2D is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_STNIC=y
+# CONFIG_SMC91X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SH_WDT=y
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_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 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 is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
--- a/arch/sh/configs/se7751_defconfig
+++ b/arch/sh/configs/se7751_defconfig
@@ -1,34 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:48 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -37,6 +52,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
@@ -44,6 +60,8 @@ CONFIG_OBSOLETE_MODPARM=y
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 CONFIG_SH_7751_SOLUTION_ENGINE=y
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -60,20 +78,29 @@ CONFIG_SH_7751_SOLUTION_ENGINE=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
 CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttySC1,38400"
@@ -82,6 +109,7 @@ CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_MEMORY_SET=y
 # CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
 CONFIG_ZERO_PAGE_OFFSET=0x00010000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_CPU_LITTLE_ENDIAN=y
@@ -91,21 +119,48 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_SH_OCRAM is not set
 # CONFIG_SH_STORE_QUEUES is not set
 # CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=60013568
+
+#
+# CPU Frequency scaling
+#
 # CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 # CONFIG_SH_DMA is not set
 
 #
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
 CONFIG_PCI=y
 # CONFIG_SH_PCIDMA_NONCOHERENT is not set
 CONFIG_PCI_AUTO=y
 CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
 
 #
 # Executable file formats
@@ -115,8 +170,20 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -144,28 +211,43 @@ 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_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
 CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_SOLUTIONENGINE is not set
 # CONFIG_MTD_MPC1211 is not set
+# CONFIG_MTD_RTS7751R2D is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -185,6 +267,10 @@ CONFIG_MTD_RAM=y
 # CONFIG_PARPORT is not set
 
 #
+# Plug and Play support
+#
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
@@ -192,12 +278,26 @@ CONFIG_MTD_RAM=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -215,11 +315,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -243,19 +352,19 @@ CONFIG_IP_PNP_RARP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
 #
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_DEBUG=y
 
@@ -263,19 +372,19 @@ CONFIG_NETFILTER_DEBUG=y
 # IP: Netfilter Configuration
 #
 # CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
 CONFIG_IP_NF_QUEUE=y
 # 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
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -284,24 +393,23 @@ CONFIG_IPV6_SCTP__=y
 # 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
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 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
@@ -309,6 +417,11 @@ CONFIG_NETDEVICES=y
 # CONFIG_ETHERTAP is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
@@ -317,6 +430,7 @@ CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
 
 #
 # Tulip family network device support
@@ -328,6 +442,7 @@ CONFIG_PCNET32=y
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
@@ -352,55 +467,41 @@ CONFIG_PCNET32=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR 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
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_IRDA is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# Bluetooth support
+# Wan interfaces
 #
-# CONFIG_BT is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -432,35 +533,54 @@ CONFIG_SOUND_GAMEPORT=y
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Unix 98 PTY support
+# Non-8250 serial port support
 #
+# CONFIG_SERIAL_SH_SCI is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_HEARTBEAT=y
-# CONFIG_PSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
 # CONFIG_SH_WDT is not set
-# CONFIG_RTC is not set
 
 #
-# Serial drivers
+# PCI-based Watchdog Cards
 #
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
-# Non-8250 serial port support
+# Ftape, the floppy tape device driver
 #
-# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
 # I2C support
@@ -468,17 +588,59 @@ CONFIG_WATCHDOG=y
 # CONFIG_I2C is not set
 
 #
-# I2C Algorithms
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
 #
 
 #
-# I2C Hardware Bus support
+# USB Gadget Support
 #
+# CONFIG_USB_GADGET is not set
 
 #
-# I2C Hardware Sensors Chip support
+# MMC/SD Card support
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
@@ -489,10 +651,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -505,7 +672,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -513,10 +681,12 @@ CONFIG_EXT2_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -526,6 +696,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -533,6 +704,11 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -545,12 +721,10 @@ CONFIG_JFFS2_FS_DEBUG=0
 #
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -560,30 +734,9 @@ CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Multimedia devices
+# Native Language Support
 #
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_NLS is not set
 
 #
 # Profiling support
@@ -593,15 +746,16 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -610,8 +764,14 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
--- a/arch/sh/configs/sh03_defconfig
+++ b/arch/sh/configs/sh03_defconfig
@@ -1,9 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:49 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
@@ -12,10 +17,12 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
 CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -25,17 +32,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -45,6 +55,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -137,7 +148,6 @@ CONFIG_HEARTBEAT=y
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
-CONFIG_ISA=y
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_AUTO=y
@@ -146,16 +156,13 @@ CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-CONFIG_PCMCIA=m
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_YENTA is not set
-# CONFIG_PD6729 is not set
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_PROBE=y
 
 #
 # PCI Hotplug Support
@@ -163,7 +170,6 @@ CONFIG_PCMCIA_PROBE=y
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 
 #
@@ -202,25 +208,36 @@ CONFIG_BINFMT_MISC=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=y
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -235,13 +252,11 @@ CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
-CONFIG_BLK_DEV_IDECS=m
 CONFIG_BLK_DEV_IDECD=m
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -250,7 +265,6 @@ CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEPCI is not set
 CONFIG_IDE_SH=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -283,46 +297,37 @@ CONFIG_CHR_DEV_SG=m
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX 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_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_SCSI_SATA 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_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_GENERIC_NCR5380_MMIO 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_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR 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
@@ -332,30 +337,12 @@ CONFIG_SCSI_QLA2XXX=m
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
-# PCMCIA SCSI adapter support
-#
-# CONFIG_PCMCIA_AHA152X is not set
-# CONFIG_PCMCIA_FDOMAIN is not set
-# CONFIG_PCMCIA_NINJA_SCSI is not set
-# CONFIG_PCMCIA_QLOGIC is not set
-# CONFIG_PCMCIA_SYM53C500 is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
@@ -403,6 +390,9 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 CONFIG_XFRM=y
@@ -424,7 +414,6 @@ CONFIG_XFRM=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -461,27 +450,19 @@ CONFIG_MII=y
 # CONFIG_HAPPYMEAL 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_SMC91X is not set
 
 #
 # Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
@@ -495,8 +476,6 @@ CONFIG_8139CP=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -509,6 +488,7 @@ CONFIG_8139CP=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -528,11 +508,6 @@ CONFIG_8139CP=y
 # CONFIG_NET_RADIO is not set
 
 #
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
 # Wan interfaces
 #
 # CONFIG_WAN is not set
@@ -600,7 +575,6 @@ CONFIG_HW_CONSOLE=y
 # Serial drivers
 #
 CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
@@ -614,7 +588,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -634,13 +607,6 @@ CONFIG_WATCHDOG=y
 CONFIG_SH_WDT=m
 
 #
-# ISA-based Watchdog Cards
-#
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_WDT is not set
-
-#
 # PCI-based Watchdog Cards
 #
 # CONFIG_PCIPCWATCHDOG is not set
@@ -655,13 +621,7 @@ CONFIG_SH03_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -697,7 +657,6 @@ CONFIG_SH03_RTC=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -709,6 +668,12 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -716,6 +681,16 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -732,10 +707,15 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 
@@ -768,6 +748,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -807,6 +788,7 @@ CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -886,18 +868,18 @@ CONFIG_OPROFILE=m
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_FRAME_POINTER is not set
 CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -911,6 +893,7 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -921,12 +904,17 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=y
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
--- a/arch/sh/configs/snapgear_defconfig
+++ b/arch/sh/configs/snapgear_defconfig
@@ -1,34 +1,48 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:51 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -40,6 +54,9 @@ CONFIG_IOSCHED_DEADLINE=y
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
 # CONFIG_SH_HP620 is not set
@@ -55,19 +72,29 @@ CONFIG_IOSCHED_DEADLINE=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 CONFIG_SH_SECUREEDGE5410=y
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
 CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 # CONFIG_CMDLINE_BOOL is not set
 CONFIG_MEMORY_START=0x08000000
@@ -75,6 +102,7 @@ CONFIG_MEMORY_SIZE=0x01000000
 CONFIG_MEMORY_SET=y
 # CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_CPU_LITTLE_ENDIAN=y
@@ -84,11 +112,25 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_SH_OCRAM is not set
 # CONFIG_SH_STORE_QUEUES is not set
 # CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=60013568
+
+#
+# CPU Frequency scaling
+#
 # CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 CONFIG_SH_DMA=y
-CONFIG_NR_DMA_CHANNELS=8
-# CONFIG_DMA_PAGE_OPS is not set
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -97,10 +139,22 @@ CONFIG_PCI=y
 # CONFIG_SH_PCIDMA_NONCOHERENT is not set
 CONFIG_PCI_AUTO=y
 CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
 
 #
 # Executable file formats
@@ -110,8 +164,20 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -124,6 +190,10 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_PARPORT is not set
 
 #
+# Plug and Play support
+#
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
@@ -131,12 +201,26 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -154,11 +238,20 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -180,60 +273,69 @@ CONFIG_IP_PNP_DHCP=y
 # 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_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # 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
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
 # CONFIG_STNIC is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
 
 #
 # Tulip family network device support
@@ -245,6 +347,7 @@ CONFIG_NET_PCI=y
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
@@ -273,49 +376,41 @@ CONFIG_8139TOO=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_S2IO is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO 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
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -344,7 +439,12 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -358,47 +458,110 @@ CONFIG_SOUND_GAMEPORT=y
 #
 # Character devices
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Unix 98 PTY support
+# Serial drivers
 #
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
-# Serial drivers
+# Ftape, the floppy tape device driver
 #
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Non-8250 serial port support
+# I2C support
 #
-# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_I2C is not set
 
 #
-# I2C support
+# Dallas's 1-wire bus
 #
-# CONFIG_I2C is not set
+# CONFIG_W1 is not set
 
 #
-# I2C Hardware Sensors Mainboard support
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
-# I2C Hardware Sensors Chip support
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
 #
-# CONFIG_I2C_SENSOR is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
@@ -409,10 +572,15 @@ CONFIG_EXT2_FS=y
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -425,19 +593,24 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -446,6 +619,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -462,18 +636,18 @@ CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -483,48 +657,28 @@ CONFIG_SUNRPC=y
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
+# Native Language Support
 #
-# CONFIG_FB is not set
+# CONFIG_NLS is not set
 
 #
-# Sound
+# Profiling support
 #
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -533,7 +687,13 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
--- a/arch/sh/configs/systemh_defconfig
+++ b/arch/sh/configs/systemh_defconfig
@@ -1,35 +1,48 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-sh
+# Wed Mar  2 15:09:53 2005
 #
 CONFIG_SUPERH=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
 CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -39,6 +52,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 
 #
@@ -46,6 +60,8 @@ CONFIG_OBSOLETE_MODPARM=y
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
 CONFIG_SH_7751_SYSTEMH=y
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -62,25 +78,36 @@ CONFIG_SH_7751_SYSTEMH=y
 # CONFIG_SH_SH2000 is not set
 # CONFIG_SH_ADX is not set
 # CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
 # CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
 # CONFIG_CPU_SH3 is not set
 CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_MMU=y
 # CONFIG_CMDLINE_BOOL is not set
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x00400000
 # CONFIG_MEMORY_OVERRIDE is not set
 CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_CPU_LITTLE_ENDIAN=y
@@ -90,21 +117,47 @@ CONFIG_PREEMPT=y
 # CONFIG_SH_OCRAM is not set
 # CONFIG_SH_STORE_QUEUES is not set
 # CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=49876504
+
+#
+# CPU Frequency scaling
+#
 # CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 # CONFIG_SH_DMA is not set
 
 #
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
 CONFIG_PCI=y
 # CONFIG_SH_PCIDMA_NONCOHERENT is not set
 CONFIG_PCI_AUTO=y
 CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
 
 #
 # Executable file formats
@@ -114,8 +167,20 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -128,17 +193,35 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_PARPORT is not set
 
 #
+# Plug and Play support
+#
+
+#
 # Block devices
 #
+# CONFIG_BLK_DEV_FD is not set
 # 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_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=1024
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -156,19 +239,25 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_MD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
-# Networking support
+# I2O device support
 #
-# CONFIG_NET is not set
+# CONFIG_I2O is not set
 
 #
-# Amateur Radio support
+# Networking support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -198,6 +287,8 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -207,50 +298,100 @@ CONFIG_SERIO=y
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
-# Unix 98 PTY support
+# Serial drivers
 #
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
-# Serial drivers
+# Ftape, the floppy tape device driver
 #
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Non-8250 serial port support
+# I2C support
 #
-# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_I2C is not set
 
 #
-# I2C support
+# Dallas's 1-wire bus
 #
-# CONFIG_I2C is not set
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
 
 #
-# I2C Algorithms
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
 #
 
 #
-# I2C Hardware Bus support
+# USB Gadget Support
 #
+# CONFIG_USB_GADGET is not set
 
 #
-# I2C Hardware Sensors Chip support
+# MMC/SD Card support
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
 
 #
 # File systems
@@ -260,10 +401,15 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -276,7 +422,8 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -284,12 +431,13 @@ CONFIG_ROMFS_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -300,6 +448,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -317,29 +466,9 @@ CONFIG_CRAMFS=y
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
+# Native Language Support
 #
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_NLS is not set
 
 #
 # Profiling support
@@ -349,15 +478,17 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_FRAME_POINTER is not set
 # CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -366,7 +497,13 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/sh/defconfig b/arch/sh/defconfig
deleted file mode 100644
--- a/arch/sh/defconfig
+++ /dev/null
@@ -1,372 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-CONFIG_SH_UNKNOWN=y
-# CONFIG_CPU_SH2 is not set
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-CONFIG_CPU_SUBTYPE_SH7708=y
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_CF_ENABLER=y
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
-CONFIG_SH_RTC=y
-CONFIG_SH_DSP=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=1193182
-# CONFIG_CPU_FREQ is not set
-# CONFIG_SH_DMA is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-
-#
-# Unix98 PTY support
-#
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-CONFIG_SH_STANDARD_BIOS=y
-CONFIG_EARLY_PRINTK=y
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -46,11 +46,11 @@ static int sh03_pci_lookup_irq(struct pc
 	/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
 	irq = pcibios_map_platform_irq(slot, pin, dev);
 	if( irq < 0 ) {
-		pr_debug("PCI: Error mapping IRQ on device %s\n", dev->slot_name);
+		pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
 		return irq;
 	}
 
-	pr_debug("Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+	pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
 
 	return irq;
 }
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -169,7 +169,7 @@ static void __init pci_fixup_ide_bases(s
 	 */
 	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
 		return;
-	pr_debug("PCI: IDE base address fixup for %s\n", d->slot_name);
+	pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
 	for(i=0; i<4; i++) {
 		struct resource *r = &d->resource[i];
 		if ((r->start & ~0x80) == 0x374) {
@@ -178,8 +178,8 @@ static void __init pci_fixup_ide_bases(s
 		}
 	}
 }
+
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-#endif
 
 /*
  *  Called after each bus is probed, but before its children
@@ -401,11 +401,11 @@ static int sh7751_pci_lookup_irq(struct 
 	/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
 	irq = pcibios_map_platform_irq(slot,pin);
 	if( irq < 0 ) {
-		pr_debug("PCI: Error mapping IRQ on device %s\n", dev->slot_name);
+		pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
 		return irq;
 	}
-	
-	pr_debug("Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+
+	pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
 
 	return irq;
 }
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -246,7 +246,7 @@ static void __init pci_fixup_ide_bases(s
 	 */
 	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
 		return;
-	printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
 	for(i=0; i<4; i++) {
 		struct resource *r = &d->resource[i];
 		if ((r->start & ~0x80) == 0x374) {
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -57,7 +57,7 @@ pcibios_update_resource(struct pci_dev *
 	if (resource < 6) {
 		reg = PCI_BASE_ADDRESS_0 + 4*resource;
 	} else if (resource == PCI_ROM_RESOURCE) {
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 		new |= PCI_ROM_ADDRESS_ENABLE;
 		reg = dev->rom_base_reg;
 	} else {
diff --git a/arch/sh/kernel/cpu/bus.c b/arch/sh/kernel/cpu/bus.c
--- a/arch/sh/kernel/cpu/bus.c
+++ b/arch/sh/kernel/cpu/bus.c
@@ -31,7 +31,7 @@ static int sh_bus_match(struct device *d
 	return shdev->dev_id == shdrv->dev_id;
 }
 
-static int sh_bus_suspend(struct device *dev, u32 state)
+static int sh_bus_suspend(struct device *dev, pm_message_t state)
 {
 	struct sh_dev *shdev = to_sh_dev(dev);
 	struct sh_driver *shdrv = to_sh_driver(dev->driver);
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -379,7 +379,7 @@ static int sq_mmap(struct file *file, st
 
 	map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace");
 
-	if (io_remap_page_range(vma, map->sq_addr, map->addr,
+	if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT,
 				size, vma->vm_page_prot))
 		return -EAGAIN;
 
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -3,7 +3,7 @@
  *
  * cpufreq driver for the SuperH processors.
  *
- * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
  * Copyright (C) 2002 M. R. Brown
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/cpumask.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -46,9 +47,8 @@ struct clock_set {
 #endif
 };
 
-#define NR_CLOCK_SETS	(sizeof(clock_sets) / sizeof(struct clock_set))
 #define MIN_CLOCK_SET	0
-#define MAX_CLOCK_SET	(NR_CLOCK_SETS - 1)
+#define MAX_CLOCK_SET	(ARRAY_SIZE(clock_sets) - 1)
 
 /*
  * For the time being, we only support two frequencies, which in turn are
@@ -83,18 +83,16 @@ static void sh_cpufreq_update_clocks(uns
 static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
 {
 	unsigned short frqcr = ctrl_inw(FRQCR);
-	unsigned long cpus_allowed;
+	cpumask_t cpus_allowed;
 	struct cpufreq_freqs freqs;
-	int allowable_cpu_map;
 
 	if (!cpu_online(cpu))
 		return -ENODEV;
 
 	cpus_allowed = current->cpus_allowed;
-	allowable_cpu_map = 1 << cpu;
-	set_cpus_allowed(current, allowable_cpu_map);
-	
-	BUG_ON(!(allowable_cpu_map & (1 << smp_processor_id())));
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+	BUG_ON(smp_processor_id() != cpu);
 
 	freqs.cpu = cpu;
 	freqs.old = current_cpu_data.cpu_clock / 1000;
@@ -134,7 +132,7 @@ static int sh_cpufreq_setstate(unsigned 
 
 	set_cpus_allowed(current, cpus_allowed);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-	
+
 	return 0;
 }
 
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -40,58 +40,17 @@
 #include <asm/irq.h>
 #include <linux/irq.h>
 
-/*
- * Controller mappings for all interrupt sources:
- */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
-	[0 ... NR_IRQS-1] = {
-		.handler = &no_irq_type,
-		.lock = SPIN_LOCK_UNLOCKED
-	}
-};
-
-/*
- * Special irq handlers.
- */
 
-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{ return IRQ_NONE; }
-
-/*
- * 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 doesn't deserve
  * a generic callback i think.
  */
+void ack_bad_irq(unsigned int irq)
+{
 	printk("unexpected IRQ trap at vector %02x\n", irq);
 }
 
-/* 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
-};
-
-/*
- * Generic, controller-independent functions:
- */
-
 #if defined(CONFIG_PROC_FS)
 int show_interrupts(struct seq_file *p, void *v)
 {
@@ -127,210 +86,13 @@ unlock:
 }
 #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 = 1;	/* Force the "do bottom halves" bit */
-	int ret, retval = 0;
-
-	if (!(action->flags & SA_INTERRUPT))
-		local_irq_enable();
-
-	do {
-		ret = action->handler(irq, action->dev_id, regs);
-		if (ret == IRQ_HANDLED)
-			status |= action->flags;
-		retval |= ret;
-		action = action->next;
-	} while (action);
-
-	if (status & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-
-	local_irq_disable();
-	return retval;
-}
-
-static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
-	struct irqaction *action;
-
-	if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
-		printk(KERN_ERR "irq event %d: bogus return value %x\n",
-				irq, action_ret);
-	} else {
-		printk(KERN_ERR "irq %d: nobody cared!\n", irq);
-	}
-	dump_stack();
-	printk(KERN_ERR "handlers:\n");
-	action = desc->action;
-	do {
-		printk(KERN_ERR "[<%p>]", action->handler);
-		print_symbol(" (%s)",
-			(unsigned long)action->handler);
-		printk("\n");
-		action = action->next;
-	} while (action);
-}
-
-static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
-	static int count = 100;
-
-	if (count) {
-		count--;
-		__report_bad_irq(irq, desc, action_ret);
-	}
-}
-
-static int noirqdebug;
-
-static int __init noirqdebug_setup(char *str)
-{
-	noirqdebug = 1;
-	printk("IRQ lockup detection disabled\n");
-	return 1;
-}
-
-__setup("noirqdebug", noirqdebug_setup);
-
-/*
- * If 99,900 of the previous 100,000 interrupts have not been handled then
- * assume that the IRQ is stuck in some manner.  Drop a diagnostic and try to
- * turn the IRQ off.
- *
- * (The other 100-of-100,000 interrupts may have been a correctly-functioning
- *  device sharing an IRQ with the failing one)
- *
- * Called under desc->lock
- */
-static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
-	if (action_ret != IRQ_HANDLED) {
-		desc->irqs_unhandled++;
-		if (action_ret != IRQ_NONE)
-			report_bad_irq(irq, desc, action_ret);
-	}
-
-	desc->irq_count++;
-	if (desc->irq_count < 100000)
-		return;
-
-	desc->irq_count = 0;
-	if (desc->irqs_unhandled > 99900) {
-		/*
-		 * The interrupt is stuck
-		 */
-		__report_bad_irq(irq, desc, action_ret);
-		/*
-		 * Now kill the IRQ
-		 */
-		printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
-		desc->status |= IRQ_DISABLED;
-		desc->handler->disable(irq);
-	}
-	desc->irqs_unhandled = 0;
-}
-
-/*
- * 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. 
- */
-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);
-}
-
-/*
- * Synchronous version of the above, making sure the IRQ is
- * no longer running on any other IRQ..
- */
-void disable_irq(unsigned int irq)
-{
-	irq_desc_t *desc = irq_desc + irq;
-	disable_irq_nosync(irq);
-	if (desc->action)
-		synchronize_irq(irq);
-}
-
-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 | IRQ_INPROGRESS);
-		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() unbalanced from %p\n",
-		       __builtin_return_address(0));
-	}
-	spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/*
- * do_IRQ handles all normal device IRQ's.
- */
 asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
 		      unsigned long r6, unsigned long r7,
 		      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;
-	irq_desc_t *desc;
-	struct irqaction * action;
-	unsigned int status;
 
 	irq_enter();
-
-#ifdef CONFIG_PREEMPT
-	/*
-	 * At this point we're now about to actually call handlers,
-	 * and interrupts might get reenabled during them... bump
-	 * preempt_count to prevent any preemption while the handler
-	 * called here is pending...
-	 */
-	preempt_disable();
-#endif
-
-	/* Get IRQ number */
 	asm volatile("stc	r2_bank, %0\n\t"
 		     "shlr2	%0\n\t"
 		     "shlr2	%0\n\t"
@@ -338,394 +100,7 @@ asmlinkage int do_IRQ(unsigned long r4, 
 		     "add	#-16, %0\n\t"
 		     :"=z" (irq));
 	irq = irq_demux(irq);
-
-	kstat_this_cpu.irqs[irq]++;
-	desc = irq_desc + 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 (likely(!(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 (unlikely(!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 (;;) {
-		irqreturn_t action_ret;
-
-		spin_unlock(&desc->lock);
-		action_ret = handle_IRQ_event(irq, &regs, action);
-		spin_lock(&desc->lock);
-		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret);
-		if (likely(!(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);
-
+	__do_IRQ(irq, &regs);
 	irq_exit();
-
-#ifdef CONFIG_PREEMPT
-	/*
-	 * We're done with the handlers, interrupts should be
-	 * currently disabled; decrement preempt_count now so
-	 * as we return preemption may be allowed...
-	 */
-	preempt_enable_no_resched();
-#endif
-
 	return 1;
 }
-
-int request_irq(unsigned int irq, 
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
-		const char * devname,
-		void *dev_id)
-{
-	int retval;
-	struct irqaction * action;
-
-	if (irq >= ACTUAL_NR_IRQS)
-		return -EINVAL;
-	if (!handler)
-		return -EINVAL;
-
-	action = (struct irqaction *)
-			kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
-	if (!action)
-		return -ENOMEM;
-
-	action->handler = handler;
-	action->flags = irqflags;
-	cpus_clear(action->mask);
-	action->name = devname;
-	action->next = NULL;
-	action->dev_id = dev_id;
-
-	retval = setup_irq(irq, action);
-	if (retval)
-		kfree(action);
-	return retval;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	irq_desc_t *desc;
-	struct irqaction **p;
-	unsigned long flags;
-
-	if (irq >= ACTUAL_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);
-			synchronize_irq(irq);
-			kfree(action);
-			return;
-		}
-		printk("Trying to free free IRQ%d\n",irq);
-		spin_unlock_irqrestore(&desc->lock,flags);
-		return;
-	}
-}
-
-EXPORT_SYMBOL(free_irq);
-
-static DECLARE_MUTEX(probe_sem);
-
-/*
- * 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.
- */
-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 (!desc->action)
-			desc->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 */ barrier();
-
-	/*
-	 * 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 */ barrier();
-
-	/*
-	 * Now filter out any obviously spurious interrupts
-	 */
-	val = 0;
-	for (i=0; i<NR_IRQS; i++) {
-		unsigned int status;
-
-		desc = irq_desc + i;
-
-		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;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-/* 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;
-}
-
-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;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
-	int shared = 0;
-	struct irqaction *old, **p;
-	unsigned long flags;
-	irq_desc_t *desc = irq_desc + irq;
-
-	if (desc->handler == &no_irq_type)
-		return -ENOSYS;
- 	/*
-	 * 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 | IRQ_INPROGRESS);
-		desc->handler->startup(irq);
-	}
-	spin_unlock_irqrestore(&desc->lock,flags);
-	return 0;
-}
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-
-void init_irq_proc(void)
-{
-}
-#endif
-
-/* Taken from the 2.5 alpha port */
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
-	/* is there anything to synchronize with? */
-	if (!irq_desc[irq].action)
-		return;
-
-	while (irq_desc[irq].status & IRQ_INPROGRESS)
-		barrier();
-}
-#endif
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -1,5 +1,4 @@
-/* $Id: ptrace.c,v 1.15 2004/05/07 05:32:05 sugioka Exp $
- *
+/*
  * linux/arch/sh/kernel/ptrace.c
  *
  * Original x86 implementation:
@@ -21,6 +20,7 @@
 #include <linux/user.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -198,7 +198,7 @@ asmlinkage int sys_ptrace(long request, 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -229,7 +229,7 @@ asmlinkage int sys_ptrace(long request, 
 		struct pt_regs *dummy = NULL;
 
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		if ((child->ptrace & PT_DTRACE) == 0) {
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -43,7 +43,6 @@ extern void * __rd_start, * __rd_end;
  */
 struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 10000000, };
 struct screen_info screen_info;
-unsigned char aux_device_present = 0xaa;
 
 #if defined(CONFIG_SH_UNKNOWN)
 struct sh_machine_vector sh_mv;
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -51,7 +51,6 @@ EXPORT_SYMBOL(strncat);
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
-EXPORT_SYMBOL(pcibios_penalize_isa_irq);
 #endif
 
 /* mem exports */
@@ -65,13 +64,6 @@ EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(__copy_user);
-
-#ifdef CONFIG_VT
-/* XXX: MRB-remove - what was screen_info changed to?
-EXPORT_SYMBOL(screen_info);
-*/
-#endif
-
 EXPORT_SYMBOL(boot_cpu_data);
 
 #ifdef CONFIG_MMU
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -1,5 +1,4 @@
-/* $Id: signal.c,v 1.21 2004/06/28 13:18:44 doyu Exp $
- *
+/*
  *  linux/arch/sh/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -100,7 +99,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -112,7 +111,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -239,7 +238,7 @@ asmlinkage int sys_sigreturn(unsigned lo
 	sigset_t set;
 	int r0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -273,7 +272,7 @@ asmlinkage int sys_rt_sigreturn(unsigned
 	stack_t st;
 	int r0;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -341,8 +340,10 @@ setup_sigcontext(struct sigcontext __use
 static inline void __user *
 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;
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (sas_ss_flags(sp) == 0)
+			sp = current->sas_ss_sp + current->sas_ss_size;
+	}
 
 	return (void __user *)((sp - frame_size) & -8ul);
 }
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -34,14 +34,12 @@
  * but is designed to be usable regardless if there's an MMU
  * present or not.
  */
-int smp_threads_ready = 0;
 struct sh_cpuinfo cpu_data[NR_CPUS];
 
 extern void per_cpu_trap_init(void);
 
 cpumask_t cpu_possible_map;
 cpumask_t cpu_online_map;
-unsigned long cache_decay_ticks = HZ / 100;
 static atomic_t cpus_booted = ATOMIC_INIT(0);
 
 /* These are defined by the board-specific code. */
@@ -129,7 +127,6 @@ int start_secondary(void *unused)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
-	smp_threads_ready = 1;
 	smp_mb();
 }
 
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -33,6 +33,7 @@
 #include <asm/machvec.h>
 #include <asm/rtc.h>
 #include <asm/freq.h>
+#include <asm/cpu/timer.h>
 #ifdef CONFIG_SH_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -46,40 +47,10 @@
 
 #define TMU0_TCR_CALIB	0x0000
 
-#if defined(CONFIG_CPU_SH3)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
-#define TMU_TSTR        0xA412FE92      /* Byte access */
-
-#define TMU0_TCOR       0xA412FE94      /* Long access */
-#define TMU0_TCNT       0xA412FE98      /* Long access */
-#define TMU0_TCR        0xA412FE9C      /* Word access */
-
-#define TMU1_TCOR	0xA412FEA0	/* Long access */
-#define TMU1_TCNT	0xA412FEA4	/* Long access */
-#define TMU1_TCR	0xA412FEA8	/* Word access */
-
-#define FRQCR           0xA415FF80
-#else
-#define TMU_TOCR	0xfffffe90	/* Byte access */
-#define TMU_TSTR	0xfffffe92	/* Byte access */
-
-#define TMU0_TCOR	0xfffffe94	/* Long access */
-#define TMU0_TCNT	0xfffffe98	/* Long access */
-#define TMU0_TCR	0xfffffe9c	/* Word access */
-#endif
-#elif defined(CONFIG_CPU_SH4)
-#define TMU_TOCR	0xffd80000	/* Byte access */
-#define TMU_TSTR	0xffd80004	/* Byte access */
-
-#define TMU0_TCOR	0xffd80008	/* Long access */
-#define TMU0_TCNT	0xffd8000c	/* Long access */
-#define TMU0_TCR	0xffd80010	/* Word access */
-
 #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
 #define CLOCKGEN_MEMCLKCR 0xbb040038
 #define MEMCLKCR_RATIO_MASK 0x7
 #endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */
-#endif /* CONFIG_CPU_SH3 or CONFIG_CPU_SH4 */
 
 extern unsigned long wall_jiffies;
 #define TICK_SIZE (tick_nsec / 1000)
@@ -272,7 +243,7 @@ static inline void do_timer_interrupt(in
 	profile_tick(CPU_PROFILING, regs);
 
 #ifdef CONFIG_HEARTBEAT
-	if (sh_mv.mv_heartbeat != NULL) 
+	if (sh_mv.mv_heartbeat != NULL)
 		sh_mv.mv_heartbeat();
 #endif
 
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -258,10 +258,16 @@ void flush_cache_mm(struct mm_struct *mm
 	flush_cache_all();
 }
 
-static void __flush_cache_page(struct vm_area_struct *vma,
-			       unsigned long address,
-			       unsigned long phys)
+/*
+ * Write back and invalidate I/D-caches for the page.
+ *
+ * ADDR: Virtual Address (U0 address)
+ * PFN: Physical page number
+ */
+void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
 {
+	unsigned long phys = pfn << PAGE_SHIFT;
+
 	/* We only need to flush D-cache when we have alias */
 	if ((address^phys) & CACHE_ALIAS) {
 		/* Loop 4K of the D-cache */
@@ -342,32 +348,6 @@ void flush_cache_range(struct vm_area_st
 }
 
 /*
- * Write back and invalidate I/D-caches for the page.
- *
- * ADDR: Virtual Address (U0 address)
- */
-void flush_cache_page(struct vm_area_struct *vma, unsigned long address)
-{
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-	unsigned long phys;
-
-	dir = pgd_offset(vma->vm_mm, address);
-	pmd = pmd_offset(dir, address);
-	if (pmd_none(*pmd) || pmd_bad(*pmd))
-		return;
-	pte = pte_offset_kernel(pmd, address);
-	entry = *pte;
-	if (!(pte_val(entry) & _PAGE_PRESENT))
-		return;
-
-	phys = pte_val(entry)&PTE_PHYS_MASK;
-	__flush_cache_page(vma, address, phys);
-}
-
-/*
  * flush_icache_user_range
  * @vma: VMA of the process
  * @page: page
@@ -377,6 +357,6 @@ void flush_cache_page(struct vm_area_str
 void flush_icache_user_range(struct vm_area_struct *vma,
 			     struct page *page, unsigned long addr, int len)
 {
-	__flush_cache_page(vma, addr, PHYSADDR(page_address(page)));
+	flush_cache_page(vma, addr, page_to_pfn(page));
 }
 
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -186,25 +186,9 @@ void flush_cache_range(struct vm_area_st
  *
  * ADDRESS: Virtual Address (U0 address)
  */
-void flush_cache_page(struct vm_area_struct *vma, unsigned long address)
+void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
 {
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-	unsigned long phys;
-
-	dir = pgd_offset(vma->vm_mm, address);
-	pmd = pmd_offset(dir, address);
-	if (pmd_none(*pmd) || pmd_bad(*pmd))
-		return;
-	pte = pte_offset(pmd, address);
-	entry = *pte;
-	if (pte_none(entry) || !pte_present(entry))
-		return;
-
-	phys = pte_val(entry)&PTE_PHYS_MASK;
-	__flush_dcache_page(phys);
+	__flush_dcache_page(pfn << PAGE_SHIFT);
 }
 
 /*
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -62,7 +62,7 @@ static void set_huge_pte(struct mm_struc
 	unsigned long i;
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 
 	if (write_access)
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -115,7 +115,7 @@ int copy_hugetlb_page_range(struct mm_st
 			pte_val(entry) += PAGE_SIZE;
 			dst_pte++;
 		}
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -202,11 +202,11 @@ void unmap_hugepage_range(struct vm_area
 		page = pte_page(*pte);
 		put_page(page);
 		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-			pte_clear(pte);
+			pte_clear(mm, address+(i*PAGE_SIZE), pte);
 			pte++;
 		}
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
 	flush_tlb_range(vma, start, end);
 }
 
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -216,8 +216,6 @@ void __init paging_init(void)
 #endif
 	NODE_DATA(0)->node_mem_map = NULL;
 	free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
-	/* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/
-	mem_map = NODE_DATA(0)->node_mem_map;
 
 #ifdef CONFIG_DISCONTIGMEM
 	/*
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c
--- a/arch/sh/mm/pg-sh4.c
+++ b/arch/sh/mm/pg-sh4.c
@@ -56,7 +56,7 @@ void clear_user_page(void *to, unsigned 
 		local_irq_restore(flags);
 		update_mmu_cache(NULL, p3_addr, entry);
 		__clear_user_page((void *)p3_addr, to);
-		pte_clear(pte);
+		pte_clear(&init_mm, p3_addr, pte);
 		up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
 	}
 }
@@ -95,7 +95,7 @@ void copy_user_page(void *to, void *from
 		local_irq_restore(flags);
 		update_mmu_cache(NULL, p3_addr, entry);
 		__copy_user_page((void *)p3_addr, from, to);
-		pte_clear(pte);
+		pte_clear(&init_mm, p3_addr, pte);
 		up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
 	}
 }
@@ -103,11 +103,11 @@ void copy_user_page(void *to, void *from
 /*
  * For SH-4, we have our own implementation for ptep_get_and_clear
  */
-inline pte_t ptep_get_and_clear(pte_t *ptep)
+inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t pte = *ptep;
 
-	pte_clear(ptep);
+	pte_clear(mm, addr, ptep);
 	if (!pte_not_present(pte)) {
 		unsigned long pfn = pte_pfn(pte);
 		if (pfn_valid(pfn)) {
diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c
--- a/arch/sh/mm/pg-sh7705.c
+++ b/arch/sh/mm/pg-sh7705.c
@@ -117,11 +117,11 @@ void copy_user_page(void *to, void *from
  * For SH7705, we have our own implementation for ptep_get_and_clear
  * Copied from pg-sh4.c
  */
-inline pte_t ptep_get_and_clear(pte_t *ptep)
+inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t pte = *ptep;
 
-	pte_clear(ptep);
+	pte_clear(mm, addr, ptep);
 	if (!pte_not_present(pte)) {
 		unsigned long pfn = pte_pfn(pte);
 		if (pfn_valid(pfn)) {
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -98,7 +98,12 @@ config BIG_ENDIAN
 
 endchoice
 
+config SH_FPU
+	bool "FPU support"
+	default y
+
 config SH64_FPU_DENORM_FLUSH
+	depends on SH_FPU
 	bool "Flush floating point denorms to zero"
 
 choice
@@ -274,3 +279,15 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+#
+# Use the generic interrupt handling code in kernel/irq/:
+#
+config GENERIC_HARDIRQS
+	bool
+	default y
+
+config GENERIC_IRQ_PROBE
+	bool
+	default y
+
diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug
--- a/arch/sh64/Kconfig.debug
+++ b/arch/sh64/Kconfig.debug
@@ -19,6 +19,13 @@ config SH64_PROC_ASIDS
 config SH64_SR_WATCH
 	bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
 
+config POOR_MANS_STRACE
+	bool "Debug: enable rudimentary strace facility"
+	help
+	  This option allows system calls to be traced to the console.  It also
+	  aids in detecting kernel stack underflow.  It is useful for debugging
+	  early-userland problems (e.g. init incurring fatal exceptions.)
+
 config SH_ALPHANUMERIC
 	bool "Enable debug outputs to on-board alphanumeric display"
 
diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile
--- a/arch/sh64/Makefile
+++ b/arch/sh64/Makefile
@@ -11,13 +11,6 @@
 # for "archclean" and "archdep" for cleaning up and making dependencies for
 # this architecture
 #
-# Note that top level Makefile automagically builds dependencies for SUBDIRS
-# but does not automagically clean SUBDIRS. Therefore "archclean" should clean
-# up all, "archdep" does nothing on added SUBDIRS.
-#
-ifndef include_config
--include .config
-endif
 
 cpu-y				:= -mb
 cpu-$(CONFIG_LITTLE_ENDIAN)	:= -ml
@@ -37,10 +30,17 @@ AFLAGS		+= -m5 -isa=sh64 -traditional
 CFLAGS		+= $(cpu-y)
 
 LDFLAGS_vmlinux	+= --defsym phys_stext=_stext-$(CONFIG_CACHED_MEMORY_OFFSET) \
-		   -e phys_stext
+		  --defsym phys_stext_shmedia=phys_stext+1 \
+		  -e phys_stext_shmedia
 
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -R .stab -R .stabstr -S
 
+#
+# arch/sh64/defconfig never had any hope of being
+# frequently updated, so use one that does
+#
+KBUILD_DEFCONFIG	:= cayman_defconfig
+
 ifdef LOADADDR
 LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
 endif
@@ -52,7 +52,11 @@ machine-$(CONFIG_SH_ROMRAM)	:= romram
 
 head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
 
-core-y += $(addprefix arch/$(ARCH)/, kernel/ mm/ mach-$(machine-y)/)
+core-y	+= arch/sh64/kernel/ arch/sh64/mm/
+
+ifneq ($(machine-y),)
+core-y	+= arch/sh64/mach-$(machine-y)/
+endif
 
 LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
 libs-y	+= arch/$(ARCH)/lib/ $(LIBGCC)
@@ -92,7 +96,7 @@ define filechk_gen-syscalltab
 	echo "struct syscall_info {"; \
 	echo "	const char *name;"; \
 	echo "} syscall_info_table[] = {"; \
-	sed -e '/^.*\.long /!d;s//\t{ "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
+	sed -e '/^.*\.long /!d;s//    { "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
 		s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \
 	echo "};"; \
 	echo ""; \
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
--- a/arch/sh64/configs/cayman_defconfig
+++ b/arch/sh64/configs/cayman_defconfig
@@ -1,11 +1,14 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Fri Feb 25 18:14:31 2005
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH64=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_LOG_BUF_SHIFT=14
 
 #
@@ -13,12 +16,12 @@ CONFIG_LOG_BUF_SHIFT=14
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
 CONFIG_POSIX_MQUEUE=y
@@ -26,16 +29,21 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -50,15 +58,12 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_SH_CAYMAN=y
 # CONFIG_SH_ROMRAM is not set
 # CONFIG_SH_HARP is not set
-
-#
-# Processor type and features
-#
 CONFIG_CPU_SH5=y
 CONFIG_CPU_SUBTYPE_SH5_101=y
 # CONFIG_CPU_SUBTYPE_SH5_103 is not set
 CONFIG_LITTLE_ENDIAN=y
 # CONFIG_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
 # CONFIG_SH64_FPU_DENORM_FLUSH is not set
 CONFIG_SH64_PGTABLE_2_LEVEL=y
 # CONFIG_SH64_PGTABLE_3_LEVEL is not set
@@ -102,12 +107,27 @@ CONFIG_PREEMPT=y
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
+CONFIG_SUPERHYWAY=y
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
@@ -121,6 +141,10 @@ CONFIG_BINFMT_ELF=y
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -144,14 +168,27 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -161,7 +198,74 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 #
 # SCSI device support
 #
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# 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 is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA 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_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR 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_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -171,6 +275,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -209,6 +314,9 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -228,12 +336,12 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -309,6 +417,7 @@ CONFIG_NET_PCI=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 
 #
@@ -335,6 +444,7 @@ CONFIG_NET_PCI=y
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 
@@ -375,6 +485,8 @@ CONFIG_SERIO_I8042=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -416,7 +528,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -449,8 +560,6 @@ CONFIG_WATCHDOG=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -460,6 +569,11 @@ CONFIG_WATCHDOG=y
 # CONFIG_I2C is not set
 
 #
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
 # Misc devices
 #
 
@@ -477,17 +591,21 @@ CONFIG_WATCHDOG=y
 # Graphics support
 #
 CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_E1355 is not set
+# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_KYRO=y
@@ -500,10 +618,8 @@ CONFIG_FB_KYRO=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
 CONFIG_FONT_8x16=y
@@ -524,6 +640,7 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_SUPERH_MONO is not set
 # CONFIG_LOGO_SUPERH_VGA16 is not set
 CONFIG_LOGO_SUPERH_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -534,6 +651,12 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
@@ -541,18 +664,38 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 CONFIG_MINIX_FS=y
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -565,7 +708,8 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -577,6 +721,7 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -609,9 +754,9 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -621,8 +766,22 @@ CONFIG_SUNRPC=y
 #
 # 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 is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
@@ -630,21 +789,33 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_NLS is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_FS=y
+CONFIG_FRAME_POINTER=y
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
-# CONFIG_SH64_PROC_TLB is not set
-# CONFIG_SH64_PROC_ASIDS is not set
+CONFIG_SH64_PROC_TLB=y
+CONFIG_SH64_PROC_ASIDS=y
 CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
 # CONFIG_SH_ALPHANUMERIC is not set
 # CONFIG_SH_NO_BSS_INIT is not set
-CONFIG_FRAME_POINTER=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -653,7 +824,14 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/sh64/defconfig b/arch/sh64/defconfig
deleted file mode 100644
--- a/arch/sh64/defconfig
+++ /dev/null
@@ -1,667 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_SUPERH64=y
-CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_LOG_BUF_SHIFT=14
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# System type
-#
-# CONFIG_SH_GENERIC is not set
-# CONFIG_SH_SIMULATOR is not set
-CONFIG_SH_CAYMAN=y
-# CONFIG_SH_ROMRAM is not set
-# CONFIG_SH_HARP is not set
-CONFIG_CPU_SH5=y
-CONFIG_CPU_SUBTYPE_SH5_101=y
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
-CONFIG_LITTLE_ENDIAN=y
-# CONFIG_BIG_ENDIAN is not set
-# CONFIG_SH64_FPU_DENORM_FLUSH is not set
-CONFIG_SH64_PGTABLE_2_LEVEL=y
-# CONFIG_SH64_PGTABLE_3_LEVEL is not set
-CONFIG_HUGETLB_PAGE_SIZE_64K=y
-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
-# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
-CONFIG_SH64_USER_MISALIGNED_FIXUP=y
-
-#
-# Memory options
-#
-CONFIG_CACHED_MEMORY_OFFSET=0x20000000
-CONFIG_MEMORY_START=0x80000000
-CONFIG_MEMORY_SIZE_IN_MB=128
-
-#
-# Cache options
-#
-# CONFIG_DCACHE_DISABLED is not set
-CONFIG_DCACHE_WRITE_BACK=y
-# CONFIG_DCACHE_WRITE_THROUGH is not set
-# CONFIG_ICACHE_DISABLED is not set
-CONFIG_PCIDEVICE_MEMORY_START=C0000000
-CONFIG_DEVICE_MEMORY_START=E0000000
-CONFIG_FLASH_MEMORY_START=0x00000000
-CONFIG_PCI_BLOCK_START=0x40000000
-
-#
-# CPU Subtype specific options
-#
-CONFIG_SH64_ID2815_WORKAROUND=y
-
-#
-# Misc options
-#
-CONFIG_HEARTBEAT=y
-CONFIG_HDSP253_LED=y
-CONFIG_SH_DMA=y
-CONFIG_PREEMPT=y
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-CONFIG_PCI=y
-CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# 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_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-# 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_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_STNIC is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO 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_VELOCITY is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_SH_WDT is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_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
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_E1355 is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-CONFIG_FB_KYRO=y
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-# CONFIG_LOGO_LINUX_CLUT224 is not set
-# CONFIG_LOGO_SUPERH_MONO is not set
-# CONFIG_LOGO_SUPERH_VGA16 is not set
-CONFIG_LOGO_SUPERH_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-CONFIG_MINIX_FS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-# CONFIG_OPROFILE is not set
-
-#
-# Kernel hacking
-#
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_EARLY_PRINTK is not set
-# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
-# CONFIG_SH64_PROC_TLB is not set
-# CONFIG_SH64_PROC_ASIDS is not set
-CONFIG_SH64_SR_WATCH=y
-# CONFIG_SH_ALPHANUMERIC is not set
-# CONFIG_SH_NO_BSS_INIT is not set
-CONFIG_FRAME_POINTER=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh64/kernel/Makefile b/arch/sh64/kernel/Makefile
--- a/arch/sh64/kernel/Makefile
+++ b/arch/sh64/kernel/Makefile
@@ -13,7 +13,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-extra-y	:= head.o init_task.o vmlinux.lds.s
+extra-y	:= head.o init_task.o vmlinux.lds
 
 obj-y	:= process.o signal.o entry.o traps.o irq.o irq_intc.o \
 	   ptrace.o setup.o time.o sys_sh64.o semaphore.o sh_ksyms.o \
@@ -22,17 +22,15 @@ obj-y	:= process.o signal.o entry.o trap
 obj-$(CONFIG_HEARTBEAT)		+= led.o
 obj-$(CONFIG_SH_ALPHANUMERIC)	+= alphanum.o
 obj-$(CONFIG_SH_DMA)		+= dma.o
+obj-$(CONFIG_SH_FPU)		+= fpu.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KALLSYMS)		+= unwind.o
 obj-$(CONFIG_PCI)		+= pci-dma.o pcibios.o
+obj-$(CONFIG_MODULES)		+= module.o
 
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_CPU_SH5)		+= pci_sh5.o
 endif
 
-ifndef CONFIG_NOFPU_SUPPORT
-obj-y				+= fpu.o
-endif
-
 USE_STANDARD_AS_RULE := true
 
diff --git a/arch/sh64/kernel/dma.c b/arch/sh64/kernel/dma.c
--- a/arch/sh64/kernel/dma.c
+++ b/arch/sh64/kernel/dma.c
@@ -31,7 +31,7 @@ typedef struct {
 } dma_info_t;
 
 static dma_info_t dma_info[MAX_DMA_CHANNELS];
-extern spinlock_t dma_spin_lock;
+static DEFINE_SPINLOCK(dma_spin_lock);
 
 /* arch/sh64/kernel/irq_intc.c */
 extern void make_intc_irq(unsigned int irq);
diff --git a/arch/sh64/kernel/early_printk.c b/arch/sh64/kernel/early_printk.c
--- a/arch/sh64/kernel/early_printk.c
+++ b/arch/sh64/kernel/early_printk.c
@@ -16,8 +16,6 @@
 #include <asm/io.h>
 #include <asm/hardware.h>
 
-extern void cpu_relax(void);
-
 #define SCIF_BASE_ADDR	0x01030000
 #define SCIF_ADDR_SH5	PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
 
diff --git a/arch/sh64/kernel/entry.S b/arch/sh64/kernel/entry.S
--- a/arch/sh64/kernel/entry.S
+++ b/arch/sh64/kernel/entry.S
@@ -6,7 +6,7 @@
  * arch/sh64/kernel/entry.S
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2004  Paul Mundt
+ * Copyright (C) 2004, 2005  Paul Mundt
  * Copyright (C) 2003, 2004 Richard Curnow
  *
  */
@@ -155,7 +155,7 @@ trap_jtable:
 	.long	tlb_miss_store				/* 0x0C0 */
 	.long	do_address_error_load	/* 0x0E0 */
 	.long	do_address_error_store	/* 0x100 */
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	.long	do_fpu_error		/* 0x120 */
 #else
 	.long	do_exception_error		/* 0x120 */
@@ -237,6 +237,7 @@ LVBR_block:
 	.space	256, 0			/* Power-on class handler, */
 					/* not required here       */
 not_a_tlb_miss:
+	synco	/* TAKum03020 (but probably a good idea anyway.) */
 	/* Save original stack pointer into KCR1 */
 	putcon	SP, KCR1
 
@@ -278,6 +279,7 @@ not_a_tlb_miss:
 	 * block making sure the final alignment is correct.
 	 */
 tlb_miss:
+	synco	/* TAKum03020 (but probably a good idea anyway.) */
 	putcon	SP, KCR1
 	movi	reg_save_area, SP
 	/* SP is guaranteed 32-byte aligned. */
@@ -393,6 +395,7 @@ fixup_to_invoke_general_handler:
 	/* VBR + 0x600 */
 
 interrupt:
+	synco	/* TAKum03020 (but probably a good idea anyway.) */
 	/* Save original stack pointer into KCR1 */
 	putcon	SP, KCR1
 
@@ -429,6 +432,7 @@ LRESVEC_block:
 	 *			(this may need to be extended...)
 	 */
 reset_or_panic:
+	synco	/* TAKum03020 (but probably a good idea anyway.) */
 	putcon	SP, DCR
 	/* First save r0-1 and tr0, as we need to use these */
 	movi	resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP
@@ -481,6 +485,7 @@ single_step_panic:
 
 	.balign	256
 debug_exception:
+	synco	/* TAKum03020 (but probably a good idea anyway.) */
 	/*
 	 * Single step/software_break_point first level handler.
 	 * Called with MMU off, so the first thing we do is enable it
@@ -788,9 +793,7 @@ no_underflow:
 	! exceptions
 	add	SP, ZERO, r14
 
-#define POOR_MANS_STRACE 0
-
-#if POOR_MANS_STRACE
+#ifdef CONFIG_POOR_MANS_STRACE
 	/* We've pushed all the registers now, so only r2-r4 hold anything
 	 * useful. Move them into callee save registers */
 	or	r2, ZERO, r28
@@ -811,7 +814,6 @@ no_underflow:
 	or	r30, ZERO, r4
 #endif
 
-
 	/* For syscall and debug race condition, get TRA now */
 	getcon	TRA, r5
 
@@ -866,7 +868,7 @@ no_underflow:
  */
 	.global ret_from_irq
 ret_from_irq:
-#if POOR_MANS_STRACE
+#ifdef CONFIG_POOR_MANS_STRACE
 	pta	evt_debug_ret_from_irq, tr0
 	ori	SP, 0, r2
 	blink	tr0, LINK
@@ -884,7 +886,7 @@ ret_from_irq:
 ret_from_exception:
 	preempt_stop()
 
-#if POOR_MANS_STRACE
+#ifdef CONFIG_POOR_MANS_STRACE
 	pta	evt_debug_ret_from_exc, tr0
 	ori	SP, 0, r2
 	blink	tr0, LINK
@@ -1141,7 +1143,7 @@ call_do_page_fault:
 fpu_error_or_IRQA:
 	pta	its_IRQ, tr0
 	beqi/l	r4, EVENT_INTERRUPT, tr0
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	movi	do_fpu_state_restore, r6
 #else
 	movi	do_exception_error, r6
@@ -1152,7 +1154,7 @@ fpu_error_or_IRQA:
 fpu_error_or_IRQB:
 	pta	its_IRQ, tr0
 	beqi/l	r4, EVENT_INTERRUPT, tr0
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	movi	do_fpu_state_restore, r6
 #else
 	movi	do_exception_error, r6
@@ -1223,7 +1225,7 @@ syscall_bad:
 syscall_ret:
 	st.q	SP, FRAME_R(9), r2	/* Expecting SP back to BASIC frame */
 
-#if POOR_MANS_STRACE
+#ifdef CONFIG_POOR_MANS_STRACE
 	/* nothing useful in registers at this point */
 
 	movi	evt_debug2, r5
@@ -1254,7 +1256,7 @@ ret_from_fork:
 	ptabs	r5, tr0
 	blink	tr0, LINK
 
-#if POOR_MANS_STRACE
+#ifdef CONFIG_POOR_MANS_STRACE
 	/* nothing useful in registers at this point */
 
 	movi	evt_debug2, r5
diff --git a/arch/sh64/kernel/head.S b/arch/sh64/kernel/head.S
--- a/arch/sh64/kernel/head.S
+++ b/arch/sh64/kernel/head.S
@@ -96,8 +96,8 @@ empty_zero_page:
 	.long	0		/* RAMDISK_FLAGS */
 	.long	0x0200		/* ORIG_ROOT_DEV */
 	.long	1		/* LOADER_TYPE */
-	.long	0x00360000	/* INITRD_START */
-	.long	0x000a0000	/* INITRD_SIZE */
+	.long	0x00800000	/* INITRD_START */
+	.long	0x00800000	/* INITRD_SIZE */
 	.long	0
 
 	.text
@@ -310,7 +310,7 @@ hyperspace:			    /* ... that's the next
 	 */
 	movi fpu_in_use, r31	/* Temporary */
 
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	getcon	SR, r21
 	movi	SR_ENABLE_FPU, r22
 	and	r21, r22, r22
diff --git a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c
--- a/arch/sh64/kernel/irq.c
+++ b/arch/sh64/kernel/irq.c
@@ -39,57 +39,11 @@
 #include <asm/irq.h>
 #include <linux/irq.h>
 
-/*
- * Controller mappings for all interrupt sources:
- */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
-	[0 ... NR_IRQS-1] = {
-		.handler = &no_irq_type,
-		.lock = SPIN_LOCK_UNLOCKED
-	}
-};
-
-
-/*
- * Special irq handlers.
- */
-
-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+void ack_bad_irq(unsigned int irq)
 {
-	return IRQ_NONE;
-}
-
-/*
- * 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.
- */
 	printk("unexpected IRQ trap at irq %02x\n", irq);
 }
 
-/* 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
-};
-
 #if defined(CONFIG_PROC_FS)
 int show_interrupts(struct seq_file *p, void *v)
 {
@@ -139,584 +93,24 @@ asmlinkage void do_NMI(unsigned long vec
 }
 
 /*
- * 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 ret;
-
-	status = 1;	/* Force the "do bottom halves" bit */
-
-        if (!(action->flags & SA_INTERRUPT))
-                local_irq_enable();
-
-	do {
-		ret = action->handler(irq, action->dev_id, regs);
-		if (ret == IRQ_HANDLED)
-			status |= action->flags;
-		action = action->next;
-	} while (action);
-	if (status & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-
-	local_irq_disable();
-
-	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 of an interrupt
- *	stack. 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.
- */
-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. Disables of an interrupt
- *	stack. That is for two disables you need two enables. 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);
-	synchronize_irq(irq);
-}
-
-/**
- *	enable_irq - enable interrupt handling on an irq
- *	@irq: Interrupt to enable
- *
- *	Re-enables the processing of interrupts on this IRQ line
- *	providing no disable_irq calls are now in effect.
- *
- *	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() unbalanced from %p\n",
-		       __builtin_return_address(0));
-	}
-	spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/*
  * do_IRQ handles all normal device IRQ's.
  */
 asmlinkage int do_IRQ(unsigned long vector_num, 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;
-	int cpu = smp_processor_id();
-	irq_desc_t *desc = NULL;
-	struct irqaction * action;
-	unsigned int status;
 
 	irq_enter();
 
-#ifdef CONFIG_PREEMPT
-	/*
-	 * At this point we're now about to actually call handlers,
-	 * and interrupts might get reenabled during them... bump
-	 * preempt_count to prevent any preemption while the handler
-	 * called here is pending...
-	 */
-	preempt_disable();
-#endif
-
 	irq = irq_demux(vector_num);
 
-	/*
-	 * Should never happen, if it does check
-	 * vectorN_to_IRQ[] against trap_jtable[].
-	 */
-	if (irq == -1) {
+	if (irq >= 0) {
+		__do_IRQ(irq, regs);
+	} else {
 		printk("unexpected IRQ trap at vector %03lx\n", vector_num);
-		goto out;
-	}
-
-	desc = irq_desc + irq;
-
-	kstat_cpu(cpu).irqs[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 | IRQ_INPROGRESS);
-	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.
-	 */
-	if (desc) {
-		desc->handler->end(irq);
-		spin_unlock(&desc->lock);
 	}
 
 	irq_exit();
 
-#ifdef CONFIG_PREEMPT
-	/*
-	 * We're done with the handlers, interrupts should be
-	 * currently disabled; decrement preempt_count now so
-	 * as we return preemption may be allowed...
-	 */
-	preempt_enable_no_resched();
-#endif
-
 	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,
-		irqreturn_t (*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;
-	cpus_clear(action->mask);
-	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);
-			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.
- */
-
-/**
- *	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;
-
-	/*
-	 * 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 + 1;
-
-		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 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))
-			continue;
-
-		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);
-	}
-
-	if (nr_irqs > 1)
-		irq_found = -irq_found;
-	return irq_found;
-}
-
-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;
-		desc->handler->startup(irq);
-	}
-	spin_unlock_irqrestore(&desc->lock,flags);
-
-	/*
-	 * No PROC FS support for interrupts.
-	 * For improvements in this area please check
-	 * the i386 branch.
-	 */
-	return 0;
-}
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-
-void init_irq_proc(void)
-{
-	/*
-	 * No PROC FS support for interrupts.
-	 * For improvements in this area please check
-	 * the i386 branch.
-	 */
-}
-#endif
diff --git a/arch/sh64/kernel/module.c b/arch/sh64/kernel/module.c
new file mode 100644
--- /dev/null
+++ b/arch/sh64/kernel/module.c
@@ -0,0 +1,161 @@
+/*  Kernel module help for sh64.
+
+    This program is free software; you can redistribute it 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 2004 SuperH (UK) Ltd
+    Author: Richard Curnow
+
+    Based on the sh version, and on code from the sh64-specific parts of
+    modutils, originally written by Richard Curnow and Ben Gaster.
+
+*/
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	unsigned int i;
+	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	Elf32_Addr relocation;
+	uint32_t *location;
+	int align;
+	int is_shmedia;
+
+	DEBUGP("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+		/* This is the symbol it is referring to.  Note that all
+		   undefined symbols have been resolved.  */
+		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+			+ ELF32_R_SYM(rel[i].r_info);
+		relocation = sym->st_value + rel[i].r_addend;
+		align = (int)location & 3;
+
+		/* For text addresses, bit2 of the st_other field indicates
+		 * whether the symbol is SHmedia (1) or SHcompact (0).  If
+		 * SHmedia, the LSB of the symbol needs to be asserted
+		 * for the CPU to be in SHmedia mode when it starts executing
+		 * the branch target. */
+		is_shmedia = (sym->st_other & 4) ? 1 : 0;
+		if (is_shmedia) {
+			relocation |= 1;
+		}
+
+		switch (ELF32_R_TYPE(rel[i].r_info)) {
+		case R_SH_DIR32:
+			DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			*location += relocation;
+			break;
+		case R_SH_REL32:
+			DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			relocation -= (Elf32_Addr) location;
+			*location += relocation;
+			break;
+		case R_SH_IMM_LOW16:
+			DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			*location = (*location & ~0x3fffc00) |
+				((relocation & 0xffff) << 10);
+			break;
+		case R_SH_IMM_MEDLOW16:
+			DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			*location = (*location & ~0x3fffc00) |
+				(((relocation >> 16) & 0xffff) << 10);
+			break;
+		case R_SH_IMM_LOW16_PCREL:
+			DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			relocation -= (Elf32_Addr) location;
+			*location = (*location & ~0x3fffc00) |
+				((relocation & 0xffff) << 10);
+			break;
+		case R_SH_IMM_MEDLOW16_PCREL:
+			DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+			relocation -= (Elf32_Addr) location;
+			*location = (*location & ~0x3fffc00) |
+				(((relocation >> 16) & 0xffff) << 10);
+			break;
+		default:
+			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+			       me->name, ELF32_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+	return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+	       me->name);
+	return -ENOEXEC;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
+
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
--- a/arch/sh64/kernel/pci_sh5.c
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -39,7 +39,7 @@ static void __init pci_fixup_ide_bases(s
 	 */
 	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
 		return;
-	printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
 	for(i=0; i<4; i++) {
 		struct resource *r = &d->resource[i];
 		if ((r->start & ~0x80) == 0x374) {
diff --git a/arch/sh64/kernel/pcibios.c b/arch/sh64/kernel/pcibios.c
--- a/arch/sh64/kernel/pcibios.c
+++ b/arch/sh64/kernel/pcibios.c
@@ -45,7 +45,7 @@ pcibios_update_resource(struct pci_dev *
 	if (resource < 6) {
 		reg = PCI_BASE_ADDRESS_0 + 4*resource;
 	} else if (resource == PCI_ROM_RESOURCE) {
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 		new |= PCI_ROM_ADDRESS_ENABLE;
 		reg = dev->rom_base_reg;
 	} else {
@@ -57,7 +57,7 @@ pcibios_update_resource(struct pci_dev *
 	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,
+		       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
 		       new, check);
 	}
 }
@@ -125,7 +125,7 @@ int pcibios_enable_device(struct pci_dev
 			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);
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
 			return -EINVAL;
 		}
 		if (r->flags & IORESOURCE_IO)
diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
--- a/arch/sh64/kernel/process.c
+++ b/arch/sh64/kernel/process.c
@@ -638,7 +638,6 @@ void free_task_struct(struct task_struct
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	/* A bit less processor dependent than older sh ... */
-
 	unsigned int reply;
 
 static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp)
@@ -671,7 +670,7 @@ void exit_thread(void)
 	   null it here, there is no other path through which it would get safely
 	   nulled. */
 
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	if (last_task_used_math == current) {
 		last_task_used_math = NULL;
 	}
@@ -683,7 +682,7 @@ void flush_thread(void)
 
 	/* Called by fs/exec.c (flush_old_exec) to remove traces of a
 	 * previously running executable. */
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	if (last_task_used_math == current) {
 		last_task_used_math = NULL;
 	}
@@ -709,7 +708,7 @@ void release_thread(struct task_struct *
 /* Fill in the fpu structure for a core dump.. */
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 {
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	int fpvalid;
 	struct task_struct *tsk = current;
 
@@ -741,7 +740,7 @@ int copy_thread(int nr, unsigned long cl
 	struct pt_regs *childregs;
 	unsigned long long se;			/* Sign extension */
 
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 	if(last_task_used_math == current) {
 		grab_fpu();
 		fpsave(&current->thread.fpu.hard);
@@ -933,7 +932,7 @@ asids_proc_info(char *buf, char **start,
 	int len=0;
 	struct task_struct *p;
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
 		int pid = p->pid;
 		struct mm_struct *mm;
 		if (!pid) continue;
@@ -942,7 +941,7 @@ asids_proc_info(char *buf, char **start,
 			unsigned long asid, context;
 			context = mm->context;
 			asid = (context & 0xff);
-			len += sprintf(buf+len, "%5d : %02x\n", pid, asid);
+			len += sprintf(buf+len, "%5d : %02lx\n", pid, asid);
 		} else {
 			len += sprintf(buf+len, "%5d : (none)\n", pid);
 		}
diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c
--- a/arch/sh64/kernel/ptrace.c
+++ b/arch/sh64/kernel/ptrace.c
@@ -27,6 +27,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/signal.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -123,9 +124,26 @@ put_fpu_long(struct task_struct *task, u
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
+	extern void poke_real_address_q(unsigned long long addr, unsigned long long data);
+#define WPC_DBRMODE 0x0d104008
+	static int first_call = 1;
 	int ret;
 
 	lock_kernel();
+
+	if (first_call) {
+		/* Set WPC.DBRMODE to 0.  This makes all debug events get
+		 * delivered through RESVEC, i.e. into the handlers in entry.S.
+		 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
+		 * would normally be left set to 1, which makes debug events get
+		 * delivered through DBRVEC, i.e. into the remote gdb's
+		 * handlers.  This prevents ptrace getting them, and confuses
+		 * the remote gdb.) */
+		printk("DBRMODE set to 0 to permit native debugging\n");
+		poke_real_address_q(WPC_DBRMODE, 0);
+		first_call = 0;
+	}
+
 	ret = -EPERM;
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
@@ -238,7 +256,7 @@ asmlinkage int sys_ptrace(long request, 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT: { /* restart after signal. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -268,7 +286,7 @@ asmlinkage int sys_ptrace(long request, 
 		struct pt_regs *regs;
 
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		if ((child->ptrace & PT_DTRACE) == 0) {
diff --git a/arch/sh64/kernel/setup.c b/arch/sh64/kernel/setup.c
--- a/arch/sh64/kernel/setup.c
+++ b/arch/sh64/kernel/setup.c
@@ -65,10 +65,6 @@
 
 struct screen_info screen_info;
 
-/* On a PC this would be initialised as a result of the BIOS detecting the
- * mouse. */
-unsigned char aux_device_present = 0xaa;
-
 #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 */
diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
--- a/arch/sh64/kernel/sh_ksyms.c
+++ b/arch/sh64/kernel/sh_ksyms.c
@@ -19,6 +19,7 @@
 #include <linux/in6.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
+#include <linux/tty.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -50,7 +51,6 @@ EXPORT_SYMBOL(kernel_thread);
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
 
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
@@ -72,12 +72,18 @@ EXPORT_SYMBOL(strlen);
 
 EXPORT_SYMBOL(flush_dcache_page);
 
+/* For ext3 */
+EXPORT_SYMBOL(sh64_page_clear);
+
 /* Ugh.  These come in from libgcc.a at link time. */
 
 extern void __sdivsi3(void);
 extern void __muldi3(void);
 extern void __udivsi3(void);
+extern char __div_table;
 EXPORT_SYMBOL(__sdivsi3);
 EXPORT_SYMBOL(__muldi3);
 EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__div_table);
+
 
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -125,7 +125,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -137,7 +137,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -178,7 +178,7 @@ struct rt_sigframe
 	long long retcode[2];
 };
 
-#ifndef CONFIG_NOFPU_SUPPORT
+#ifdef CONFIG_SH_FPU
 static inline int
 restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
 {
@@ -293,7 +293,7 @@ asmlinkage int sys_sigreturn(unsigned lo
 	sigset_t set;
 	long long ret;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -330,7 +330,7 @@ asmlinkage int sys_rt_sigreturn(unsigned
 	stack_t __user st;
 	long long ret;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -634,11 +634,9 @@ give_sigsegv:
  */
 
 static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
-	      struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+		sigset_t *oldset, struct pt_regs * regs)
 {
-	struct k_sigaction *ka = &current->sighand->action[sig-1];
-
 	/* Are we from a system call? */
 	if (regs->syscall_nr >= 0) {
 		/* If so, check system call restarting.. */
@@ -666,9 +664,6 @@ handle_signal(unsigned long sig, siginfo
 	else
 		setup_frame(sig, ka, 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->sighand->siglock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -691,6 +686,7 @@ int do_signal(struct pt_regs *regs, sigs
 {
 	siginfo_t info;
 	int signr;
+	struct k_sigaction ka;
 
 	/*
 	 * We want the common case to go fast, which
@@ -707,11 +703,11 @@ int do_signal(struct pt_regs *regs, sigs
 	if (!oldset)
 		oldset = &current->blocked;
 
-	signr = get_signal_to_deliver(&info, regs, 0);
+	signr = get_signal_to_deliver(&info, &ka, regs, 0);
 
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, &info, oldset, regs);
+		handle_signal(signr, &info, &ka, oldset, regs);
 		return 1;
 	}
 
diff --git a/arch/sh64/kernel/switchto.S b/arch/sh64/kernel/switchto.S
--- a/arch/sh64/kernel/switchto.S
+++ b/arch/sh64/kernel/switchto.S
@@ -27,7 +27,7 @@ sh64_switch_to:
    r5 - &next->thread
 
    Outgoing results
-   r2 - last (=prev)
+   r2 - last (=prev) : this just stays in r2 throughout
 
    Want to create a full (struct pt_regs) on the stack to allow backtracing
    functions to work.  However, we only need to populate the callee-save
@@ -188,7 +188,6 @@ sh64_switch_to:
 	! epilogue
 	ld.l	r15, 0, r18
 	ld.l	r15, 4, r14
-	ori	r4, 0, r2	! last = prev
 	ptabs	r18, tr0
 	movi	FRAME_SIZE, r0
 	add	r15, r0, r15
diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
--- a/arch/sh64/kernel/sys_sh64.c
+++ b/arch/sh64/kernel/sys_sh64.c
@@ -283,4 +283,3 @@ asmlinkage int sys_uname(struct old_utsn
 	up_read(&uts_sem);
 	return err?-EFAULT:0;
 }
-
diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S
--- a/arch/sh64/kernel/syscalls.S
+++ b/arch/sh64/kernel/syscalls.S
@@ -268,7 +268,7 @@ sys_call_table:
 	.long sys_msgrcv
 	.long sys_msgget
 	.long sys_msgctl
-	.long sys_ni_syscall /* sys_shmatcall */
+	.long sys_shmat
 	.long sys_shmdt			/* 245 */
 	.long sys_shmget
 	.long sys_shmctl
@@ -337,4 +337,9 @@ sys_call_table:
 	.long sys_mq_timedreceive
 	.long sys_mq_notify
 	.long sys_mq_getsetattr		/* 310 */
+	.long sys_ni_syscall	/* Reserved for kexec */
+	.long sys_waitid
+	.long sys_add_key
+	.long sys_request_key
+	.long sys_keyctl		/* 315 */
 
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -45,6 +45,7 @@
 #define TMU_TOCR_INIT	0x00
 #define TMU0_TCR_INIT	0x0020
 #define TMU_TSTR_INIT	1
+#define TMU_TSTR_OFF	0
 
 /* RCR1 Bits */
 #define RCR1_CF		0x80	/* Carry Flag             */
@@ -424,7 +425,7 @@ static __init unsigned int get_cpu_hz(vo
 	*/
 	register unsigned long long  __rtc_irq_flag __asm__ ("r3");
 
-	sti();
+	local_irq_enable();
 	do {} while (ctrl_inb(R64CNT) != 0);
 	ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */
 
@@ -443,7 +444,7 @@ static __init unsigned int get_cpu_hz(vo
 		     "getcon	" __CTC ", %0\n\t"
 		: "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
 		: "0" (0));
-	cli();
+	local_irq_disable();
 	/*
 	 * SH-3:
 	 * CPU clock = 4 stages * loop
@@ -561,6 +562,7 @@ void __init time_init(void)
 	current_cpu_data.module_clock = module_clock;
 
 	/* Start TMU0 */
+	ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
 	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
 	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
 	ctrl_outl(interval, TMU0_TCOR);
diff --git a/arch/sh64/kernel/traps.c b/arch/sh64/kernel/traps.c
--- a/arch/sh64/kernel/traps.c
+++ b/arch/sh64/kernel/traps.c
@@ -30,6 +30,7 @@
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -286,6 +287,8 @@ void dump_stack(void)
 {
 	show_task(NULL);
 }
+/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
+EXPORT_SYMBOL(dump_stack);
 
 static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
 		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
diff --git a/arch/sh64/lib/Makefile b/arch/sh64/lib/Makefile
--- a/arch/sh64/lib/Makefile
+++ b/arch/sh64/lib/Makefile
@@ -15,5 +15,5 @@
 
 # Panic should really be compiled as PIC
 lib-y  := udelay.o c-checksum.o dbg.o io.o panic.o memcpy.o copy_user_memcpy.o \
-		page_copy.o page_clear.o
+		page_copy.o page_clear.o iomap.o
 
diff --git a/arch/sh64/lib/copy_user_memcpy.S b/arch/sh64/lib/copy_user_memcpy.S
--- a/arch/sh64/lib/copy_user_memcpy.S
+++ b/arch/sh64/lib/copy_user_memcpy.S
@@ -46,6 +46,11 @@
 
 */
 
+/* NOTE : Prefetches removed and allocos guarded by synco to avoid TAKum03020
+ * erratum.  The first two prefetches are nop-ed out to avoid upsetting the
+ * instruction counts used in the jump address calculation.
+ * */
+
 	.section .text..SHmedia32,"ax"
 	.little
 	.balign 32
@@ -58,7 +63,7 @@ copy_user_memcpy:
 #define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1
 #define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1
 
-	ld.b r3,0,r63
+	nop ! ld.b r3,0,r63 ! TAKum03020
 	pta/l Large,tr0
 	movi 25,r0
 	bgeu/u r4,r0,tr0
@@ -108,7 +113,7 @@ L8_15:	/* 8..15 byte memcpy cntd. */
 
 	/* 2 or 3 byte memcpy */
 	ld.b r3,0,r0
-	ld.b r2,0,r63
+	nop ! ld.b r2,0,r63 ! TAKum03020
 	ld.b r3,1,r1
 	st.b r2,0,r0
 	pta/l L2_3,tr0
@@ -151,7 +156,7 @@ L8_15:	/* 8..15 byte memcpy cntd. */
 	blink tr1,r63
 
 Large:
-	ld.b r2, 0, r63
+	! ld.b r2, 0, r63 ! TAKum03020
 	pta/l  Loop_ua, tr1
 	ori r3, -8, r7
 	sub r2, r7, r22
@@ -173,8 +178,7 @@ Large:
 	addi r6, -8, r21
 
 Loop_line:
-	ldx.q r22, r36, r63
-	synco
+	! ldx.q r22, r36, r63 ! TAKum03020
 	alloco r22, 32
 	synco
 	addi r22, 32, r22
diff --git a/arch/sh64/lib/dbg.c b/arch/sh64/lib/dbg.c
--- a/arch/sh64/lib/dbg.c
+++ b/arch/sh64/lib/dbg.c
@@ -8,6 +8,7 @@
 -- Copyright 2004 Richard Curnow (evt_debug etc)
 --
 --------------------------------------------------------------------------*/
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -136,6 +137,8 @@ void print_itlb(void)
 
 /* ======================================================================= */
 
+#ifdef CONFIG_POOR_MANS_STRACE
+
 #include "syscalltab.h"
 
 struct ring_node {
@@ -151,6 +154,17 @@ struct ring_node {
 static struct ring_node event_ring[16];
 static int event_ptr = 0;
 
+struct stored_syscall_data {
+	int pid;
+	int syscall_number;
+};
+
+#define N_STORED_SYSCALLS 16
+
+static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS];
+static int syscall_next=0;
+static int syscall_next_print=0;
+
 void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs)
 {
 	int syscallno = tra & 0xff;
@@ -187,15 +201,35 @@ void evt_debug(int evt, int ret_addr, in
 	event_ptr = (event_ptr + 1) & 15;
 
 	if ((event == 2) && (evt == 0x160)) {
-		if (syscallno < NUM_SYSCALL_INFO_ENTRIES)
-			printk("Task %d: %s()\n",
-			       current->pid,
-			       syscall_info_table[syscallno].name);
+		if (syscallno < NUM_SYSCALL_INFO_ENTRIES) {
+			/* Store the syscall information to print later.  We
+			 * can't print this now - currently we're running with
+			 * SR.BL=1, so we can't take a tlbmiss (which could occur
+			 * in the console drivers under printk).
+			 *
+			 * Just overwrite old entries on ring overflow - this
+			 * is only for last-hope debugging. */
+			stored_syscalls[syscall_next].pid = current->pid;
+			stored_syscalls[syscall_next].syscall_number = syscallno;
+			syscall_next++;
+			syscall_next &= (N_STORED_SYSCALLS - 1);
+		}
+	}
+}
+
+static void drain_syscalls(void) {
+	while (syscall_next_print != syscall_next) {
+		printk("Task %d: %s()\n",
+			stored_syscalls[syscall_next_print].pid,
+			syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name);
+			syscall_next_print++;
+			syscall_next_print &= (N_STORED_SYSCALLS - 1);
 	}
 }
 
 void evt_debug2(unsigned int ret)
 {
+	drain_syscalls();
 	printk("Task %d: syscall returns %08x\n", current->pid, ret);
 }
 
@@ -231,6 +265,8 @@ void evt_debug_ret_from_exc(struct pt_re
 	event_ptr = (event_ptr + 1) & 15;
 }
 
+#endif /* CONFIG_POOR_MANS_STRACE */
+
 /* ======================================================================= */
 
 void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
diff --git a/arch/sh64/lib/io.c b/arch/sh64/lib/io.c
--- a/arch/sh64/lib/io.c
+++ b/arch/sh64/lib/io.c
@@ -9,14 +9,12 @@
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/io.h>
-#ifdef CONFIG_SH_CAYMAN
-#include <asm/cayman.h>
-#endif
 
 /*
  * readX/writeX() are used to access memory mapped devices. On some
@@ -25,71 +23,6 @@
  * memory location directly.
  */
 
-#define dprintk(x...)
-
-static int io_addr(int x) {
-	if (x < 0x400) {
-#ifdef CONFIG_SH_CAYMAN
-		return (x << 2) | smsc_superio_virt;
-#else
-		panic ("Illegal access to I/O port 0x%04x\n", x);
-		return 0;
-#endif
-	} else {
-#ifdef CONFIG_PCI
-		return (x + pciio_virt);
-#else
-		panic ("Illegal access to I/O port 0x%04x\n", x);
-		return 0;
-#endif
-	}
-}
-
-unsigned long inb(unsigned long port)
-{
-	unsigned long r;
-
-	r = ctrl_inb(io_addr(port));
-	dprintk("inb(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port));
-	return r;
-}
-
-unsigned long inw(unsigned long port)
-{
-	unsigned long r;
-
-	r = ctrl_inw(io_addr(port));
-	dprintk("inw(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port));
-	return r;
-}
-
-unsigned long inl(unsigned long port)
-{
-	unsigned long r;
-
-	r = ctrl_inl(io_addr(port));
-	dprintk("inl(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port));
-	return r;
-}
-
-void outb(unsigned long value, unsigned long port)
-{
-	dprintk("outb(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port));
-	ctrl_outb(value, io_addr(port));
-}
-
-void outw(unsigned long value, unsigned long port)
-{
-	dprintk("outw(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port));
-	ctrl_outw(value, io_addr(port));
-}
-
-void outl(unsigned long value, unsigned long port)
-{
-	dprintk("outw(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port));
-	ctrl_outl(value, io_addr(port));
-}
-
 /* This is horrible at the moment - needs more work to do something sensible */
 #define IO_DELAY()
 
@@ -185,7 +118,7 @@ void insl(unsigned long port, void *addr
 	}
 }
 
-void memcpy_toio(unsigned long to, const void *from, long count)
+void memcpy_toio(void __iomem *to, const void *from, long count)
 {
 	unsigned char *p = (unsigned char *) from;
 
@@ -195,7 +128,7 @@ void memcpy_toio(unsigned long to, const
 	}
 }
 
-void memcpy_fromio(void *to, unsigned long from, long count)
+void memcpy_fromio(void *to, void __iomem *from, long count)
 {
 	int i;
 	unsigned char *p = (unsigned char *) to;
diff --git a/arch/sh64/lib/iomap.c b/arch/sh64/lib/iomap.c
new file mode 100644
--- /dev/null
+++ b/arch/sh64/lib/iomap.c
@@ -0,0 +1,55 @@
+/*
+ * arch/sh64/lib/iomap.c
+ *
+ * Generic sh64 iomap interface
+ *
+ * Copyright (C) 2004  Paul Mundt
+ *
+ * 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/config.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void __iomem *__attribute__ ((weak))
+ioport_map(unsigned long port, unsigned int len)
+{
+	return (void __iomem *)port;
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+	/* Nothing .. */
+}
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+	unsigned long start = pci_resource_start(dev, bar);
+	unsigned long len = pci_resource_len(dev, bar);
+	unsigned long flags = pci_resource_flags(dev, bar);
+
+	if (!len)
+		return NULL;
+	if (max && len > max)
+		len = max;
+	if (flags & IORESOURCE_IO)
+		return ioport_map(start + pciio_virt, len);
+	if (flags & IORESOURCE_MEM)
+		return (void __iomem *)start;
+
+	/* What? */
+	return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+	/* Nothing .. */
+}
+
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
+
diff --git a/arch/sh64/lib/old-checksum.c b/arch/sh64/lib/old-checksum.c
deleted file mode 100644
--- a/arch/sh64/lib/old-checksum.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * FIXME: old compatibility stuff, will be removed soon.
- */
-
-#include <net/checksum.h>
-
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
-{
-	int src_err=0, dst_err=0;
-
-	sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
-
-	if (src_err || dst_err)
-		printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
-
-	return sum;
-}
diff --git a/arch/sh64/lib/page_clear.S b/arch/sh64/lib/page_clear.S
--- a/arch/sh64/lib/page_clear.S
+++ b/arch/sh64/lib/page_clear.S
@@ -17,6 +17,8 @@
 
    Always clears 4096 bytes.
 
+   Note : alloco guarded by synco to avoid TAKum03020 erratum
+
 */
 
 	.section .text..SHmedia32,"ax"
@@ -34,6 +36,7 @@ sh64_page_clear:
 	add  r2, r63, r6
 1:
 	alloco r6, 0
+	synco	! TAKum03020
 	addi	r6, 32, r6
 	bgt/l	r7, r6, tr1
 
diff --git a/arch/sh64/lib/page_copy.S b/arch/sh64/lib/page_copy.S
--- a/arch/sh64/lib/page_copy.S
+++ b/arch/sh64/lib/page_copy.S
@@ -39,12 +39,17 @@ sh64_page_copy:
 	pta 3f, tr3
 	ptabs r18, tr0
 
+#if 0
+	/* TAKum03020 */
 	ld.q r2, 0x00, r63
 	ld.q r2, 0x20, r63
 	ld.q r2, 0x40, r63
 	ld.q r2, 0x60, r63
+#endif
 	alloco r3, 0x00
+	synco		! TAKum03020
 	alloco r3, 0x20
+	synco		! TAKum03020
 
 	movi 3968, r6
 	add  r3, r6, r6
@@ -60,11 +65,15 @@ sh64_page_copy:
    because they overlap with the time spent waiting for prefetches to
    complete. */
 1:
+#if 0
+	/* TAKum03020 */
 	bge/u r3, r6, tr2  ! skip prefetch for last 4 lines
 	ldx.q r3, r22, r63 ! prefetch 4 lines hence
+#endif
 2:
 	bge/u r3, r7, tr3  ! skip alloco for last 2 lines
 	alloco r3, 0x40    ! alloc destination line 2 lines ahead
+	synco		! TAKum03020
 3:
 	ldx.q r3, r60, r36
 	ldx.q r3, r61, r37
diff --git a/arch/sh64/mach-cayman/Makefile b/arch/sh64/mach-cayman/Makefile
--- a/arch/sh64/mach-cayman/Makefile
+++ b/arch/sh64/mach-cayman/Makefile
@@ -6,6 +6,6 @@
 # unless it's something special (ie not a .c file).
 #
 
-obj-y := setup.o irq.o
+obj-y := setup.o irq.o iomap.o
 obj-$(CONFIG_HEARTBEAT)	+= led.o
 
diff --git a/arch/sh64/mach-cayman/iomap.c b/arch/sh64/mach-cayman/iomap.c
new file mode 100644
--- /dev/null
+++ b/arch/sh64/mach-cayman/iomap.c
@@ -0,0 +1,24 @@
+/*
+ * arch/sh64/mach-cayman/iomap.c
+ *
+ * Cayman iomap interface
+ *
+ * Copyright (C) 2004  Paul Mundt
+ *
+ * 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/config.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/cayman.h>
+
+void __iomem *ioport_map(unsigned long port, unsigned int len)
+{
+	if (port < 0x400)
+		return (void __iomem *)((port << 2) | smsc_superio_virt);
+
+	return (void __iomem *)port;
+}
+
diff --git a/arch/sh64/mach-cayman/irq.c b/arch/sh64/mach-cayman/irq.c
--- a/arch/sh64/mach-cayman/irq.c
+++ b/arch/sh64/mach-cayman/irq.c
@@ -64,11 +64,11 @@ static void enable_cayman_irq(unsigned i
 	irq -= START_EXT_IRQS;
 	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
 	bit = 1<<(irq % 8);
-	save_and_cli(flags);
+	local_irq_save(flags);
 	mask = ctrl_inl(reg);
 	mask |= bit;
 	ctrl_outl(mask, reg);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 void disable_cayman_irq(unsigned int irq)
@@ -81,11 +81,11 @@ void disable_cayman_irq(unsigned int irq
 	irq -= START_EXT_IRQS;
 	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
 	bit = 1<<(irq % 8);
-	save_and_cli(flags);
+	local_irq_save(flags);
 	mask = ctrl_inl(reg);
 	mask &= ~bit;
 	ctrl_outl(mask, reg);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 static void ack_cayman_irq(unsigned int irq)
diff --git a/arch/sh64/mach-cayman/setup.c b/arch/sh64/mach-cayman/setup.c
--- a/arch/sh64/mach-cayman/setup.c
+++ b/arch/sh64/mach-cayman/setup.c
@@ -33,8 +33,6 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
-
 /*
  * Platform Dependent Interrupt Priorities.
  */
@@ -86,10 +84,14 @@
 #define SMSC_DEVICE_ID_INDEX	0x20
 #define SMSC_DEVICE_REV_INDEX	0x21
 #define SMSC_ACTIVATE_INDEX	0x30
+#define SMSC_PRIMARY_BASE_INDEX  0x60
+#define SMSC_SECONDARY_BASE_INDEX 0x62
 #define SMSC_PRIMARY_INT_INDEX	0x70
 #define SMSC_SECONDARY_INT_INDEX 0x72
 
-#define SMSC_KEYBOARD_DEVICE 7
+#define SMSC_IDE1_DEVICE	1
+#define SMSC_KEYBOARD_DEVICE	7
+#define SMSC_CONFIG_REGISTERS	8
 
 #define SMSC_SUPERIO_READ_INDEXED(index) ({ \
 	outb((index), SMSC_INDEX_PORT_ADDR); \
@@ -98,6 +100,9 @@
 	outb((index), SMSC_INDEX_PORT_ADDR); \
 	outb((val),   SMSC_DATA_PORT_ADDR); })
 
+#define IDE1_PRIMARY_BASE	0x01f0
+#define IDE1_SECONDARY_BASE	0x03f6
+
 unsigned long smsc_superio_virt;
 
 /*
@@ -125,13 +130,13 @@ struct sh64_platform platform_parms = {
 	.initial_root_dev =	0x0100,
 	.loader_type =		1,
 	.io_res_p =		io_resources,
-	.io_res_count =		RES_COUNT(io_resources),
+	.io_res_count =		ARRAY_SIZE(io_resources),
 	.kram_res_p =		kram_resources,
-	.kram_res_count =	RES_COUNT(kram_resources),
+	.kram_res_count =	ARRAY_SIZE(kram_resources),
 	.xram_res_p =		xram_resources,
-	.xram_res_count =	RES_COUNT(xram_resources),
+	.xram_res_count =	ARRAY_SIZE(xram_resources),
 	.rom_res_p =		rom_resources,
-	.rom_res_count =	RES_COUNT(rom_resources),
+	.rom_res_count =	ARRAY_SIZE(rom_resources),
 };
 
 int platform_int_priority[NR_INTC_IRQS] = {
@@ -175,6 +180,38 @@ static int __init smsc_superio_setup(voi
 	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
 	SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
 
+#ifdef CONFIG_IDE
+	/*
+	 * Only IDE1 exists on the Cayman
+	 */
+
+	/* Power it on */
+	SMSC_SUPERIO_WRITE_INDEXED(1 << SMSC_IDE1_DEVICE, 0x22);
+
+	SMSC_SUPERIO_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+
+	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE >> 8,
+				   SMSC_PRIMARY_BASE_INDEX + 0);
+	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE & 0xff,
+				   SMSC_PRIMARY_BASE_INDEX + 1);
+
+	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE >> 8,
+				   SMSC_SECONDARY_BASE_INDEX + 0);
+	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE & 0xff,
+				   SMSC_SECONDARY_BASE_INDEX + 1);
+
+	SMSC_SUPERIO_WRITE_INDEXED(14, SMSC_PRIMARY_INT_INDEX);
+
+	SMSC_SUPERIO_WRITE_INDEXED(SMSC_CONFIG_REGISTERS,
+				   SMCS_LOGICAL_DEV_INDEX);
+
+	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
+	SMSC_SUPERIO_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
+	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
+	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
+#endif
+
 	/* Exit the configuraton state */
 	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
 
diff --git a/arch/sh64/mm/cache.c b/arch/sh64/mm/cache.c
--- a/arch/sh64/mm/cache.c
+++ b/arch/sh64/mm/cache.c
@@ -114,6 +114,16 @@ int __init sh64_cache_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_DCACHE_DISABLED
+#define sh64_dcache_purge_all()					do { } while (0)
+#define sh64_dcache_purge_coloured_phy_page(paddr, eaddr)	do { } while (0)
+#define sh64_dcache_purge_user_range(mm, start, end)		do { } while (0)
+#define sh64_dcache_purge_phy_page(paddr)			do { } while (0)
+#define sh64_dcache_purge_virt_page(mm, eaddr)			do { } while (0)
+#define sh64_dcache_purge_kernel_range(start, end)		do { } while (0)
+#define sh64_dcache_wback_current_user_range(start, end)	do { } while (0)
+#endif
+
 /*##########################################################################*/
 
 /* From here onwards, a rewrite of the implementation,
@@ -436,6 +446,7 @@ static void __inline__ sh64_dcache_purge
 		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
 		for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
 			asm __volatile__ ("alloco %0, 0" : : "r" (eaddr));
+			asm __volatile__ ("synco"); /* TAKum03020 */
 		}
 
 		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
@@ -573,31 +584,6 @@ static void sh64_dcache_purge_phy_page(u
 	}
 }
 
-static void sh64_dcache_purge_virt_page(struct mm_struct *mm, unsigned long eaddr)
-{
-	unsigned long phys;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	pte_t entry;
-
-	pgd = pgd_offset(mm, eaddr);
-	pmd = pmd_offset(pgd, eaddr);
-
-	if (pmd_none(*pmd) || pmd_bad(*pmd))
-		return;
-
-	pte = pte_offset_kernel(pmd, eaddr);
-	entry = *pte;
-
-	if (pte_none(entry) || !pte_present(entry))
-		return;
-
-	phys = pte_val(entry) & PAGE_MASK;
-
-	sh64_dcache_purge_phy_page(phys);
-}
-
 static void sh64_dcache_purge_user_page(struct mm_struct *mm, unsigned long eaddr)
 {
 	pgd_t *pgd;
@@ -766,8 +752,6 @@ static void sh64_dcache_wback_current_us
 	}
 }
 
-#endif /* !CONFIG_DCACHE_DISABLED */
-
 /****************************************************************************/
 
 /* These *MUST* lie in an area of virtual address space that's otherwise unused. */
@@ -830,6 +814,8 @@ static void sh64_clear_user_page_coloure
 	sh64_teardown_dtlb_cache_slot();
 }
 
+#endif /* !CONFIG_DCACHE_DISABLED */
+
 /****************************************************************************/
 
 /*##########################################################################
@@ -904,7 +890,7 @@ void flush_cache_range(struct vm_area_st
 
 /****************************************************************************/
 
-void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr)
+void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, unsigned long pfn)
 {
 	/* Invalidate any entries in either cache for the vma within the user
 	   address space vma->vm_mm for the page starting at virtual address
@@ -915,7 +901,7 @@ void flush_cache_page(struct vm_area_str
 	   Note(1), this is called with mm->page_table_lock held.
 	   */
 
-	sh64_dcache_purge_virt_page(vma->vm_mm, eaddr);
+	sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT);
 
 	if (vma->vm_flags & VM_EXEC) {
 		sh64_icache_inv_user_page(vma, eaddr);
diff --git a/arch/sh64/mm/extable.c b/arch/sh64/mm/extable.c
--- a/arch/sh64/mm/extable.c
+++ b/arch/sh64/mm/extable.c
@@ -15,7 +15,8 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-extern unsigned long copy_user_memcpy, copy_user_memcpy_end, __copy_user_fixup;
+extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
+extern void __copy_user_fixup(void);
 
 static const struct exception_table_entry __copy_user_fixup_ex = {
 	.fixup = (unsigned long)&__copy_user_fixup,
diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
--- a/arch/sh64/mm/fault.c
+++ b/arch/sh64/mm/fault.c
@@ -148,7 +148,7 @@ asmlinkage void do_page_fault(struct pt_
 	mm = tsk->mm;
 
 	/* Not an IO address, so reenable interrupts */
-	sti();
+	local_irq_enable();
 
 	/*
 	 * If we're in an interrupt or have no user
@@ -203,17 +203,17 @@ asmlinkage void do_page_fault(struct pt_
  * we can handle it..
  */
 good_area:
-	if (writeaccess) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-			goto bad_area;
-	}
-
 	if (textaccess) {
 		if (!(vma->vm_flags & VM_EXEC))
 			goto bad_area;
+	} else {
+		if (writeaccess) {
+			if (!(vma->vm_flags & VM_WRITE))
+				goto bad_area;
+		} else {
+			if (!(vma->vm_flags & VM_READ))
+				goto bad_area;
+		}
 	}
 
 	/*
@@ -264,17 +264,28 @@ bad_area:
 	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
-		printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx opcode=%08lx\n",
-			address, current->pid, current->comm,
-			(unsigned long) regs->pc,
-			*(unsigned long *)(u32)(regs->pc & ~3));
-		show_regs(regs);
+		static int count=0;
+		siginfo_t info;
+		if (count < 4) {
+			/* This is really to help debug faults when starting
+			 * usermode, so only need a few */
+			count++;
+			printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
+				address, current->pid, current->comm,
+				(unsigned long) regs->pc);
+#if 0
+			show_regs(regs);
+#endif
+		}
 		if (tsk->pid == 1) {
 			panic("INIT had user mode bad_area\n");
 		}
 		tsk->thread.address = address;
 		tsk->thread.error_code = writeaccess;
-		force_sig(SIGSEGV, tsk);
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		info.si_addr = (void *) address;
+		force_sig_info(SIGSEGV, &info, tsk);
 		return;
 	}
 
diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c
--- a/arch/sh64/mm/hugetlbpage.c
+++ b/arch/sh64/mm/hugetlbpage.c
@@ -62,7 +62,7 @@ static void set_huge_pte(struct mm_struc
 	unsigned long i;
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 
 	if (write_access)
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -115,7 +115,7 @@ int copy_hugetlb_page_range(struct mm_st
 			pte_val(entry) += PAGE_SIZE;
 			dst_pte++;
 		}
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -202,11 +202,11 @@ void unmap_hugepage_range(struct vm_area
 		page = pte_page(*pte);
 		put_page(page);
 		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-			pte_clear(pte);
+			pte_clear(mm, address+(i*PAGE_SIZE), pte);
 			pte++;
 		}
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
 	flush_tlb_range(vma, start, end);
 }
 
diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c
--- a/arch/sh64/mm/init.c
+++ b/arch/sh64/mm/init.c
@@ -124,9 +124,6 @@ void __init paging_init(void)
 	zones_size[ZONE_DMA] = MAX_LOW_PFN - START_PFN;
 	NODE_DATA(0)->node_mem_map = NULL;
 	free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
-
-	/* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/
-	mem_map = NODE_DATA(0)->node_mem_map;
 }
 
 void __init mem_init(void)
diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
--- a/arch/sh64/mm/ioremap.c
+++ b/arch/sh64/mm/ioremap.c
@@ -182,8 +182,8 @@ void iounmap(void *addr)
 }
 
 static struct resource shmedia_iomap = {
-        .name	= "shmedia_iomap",
-	.start	= IOBASE_VADDR,
+	.name	= "shmedia_iomap",
+	.start	= IOBASE_VADDR + PAGE_SIZE,
 	.end	= IOBASE_END - 1,
 };
 
@@ -400,7 +400,7 @@ static void shmedia_unmapioaddr(unsigned
 		return;
 
 	clear_page((void *)ptep);
-	pte_clear(ptep);
+	pte_clear(&init_mm, vaddr, ptep);
 }
 
 unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name)
diff --git a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c
--- a/arch/sh64/mm/tlbmiss.c
+++ b/arch/sh64/mm/tlbmiss.c
@@ -75,7 +75,6 @@ inline void __do_tlb_refill(unsigned lon
 
 	/* Set PTEL register, set_pte has performed the sign extension */
 	ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-	ptel |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */
 
 	tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
 	next = tlbp->next;
diff --git a/arch/sh64/oprofile/op_model_null.c b/arch/sh64/oprofile/op_model_null.c
--- a/arch/sh64/oprofile/op_model_null.c
+++ b/arch/sh64/oprofile/op_model_null.c
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 
-int __init oprofile_arch_init(struct oprofile_operations **ops)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
 	return -ENODEV;
 }
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -54,11 +54,11 @@ static void _sparc_free_io(struct resour
 
 /* This points to the next to use virtual memory for DVMA mappings */
 static struct resource _sparc_dvma = {
-	"sparc_dvma", DVMA_VADDR, DVMA_END - 1
+	.name = "sparc_dvma", .start = DVMA_VADDR, .end = DVMA_END - 1
 };
 /* This points to the start of I/O mappings, cluable from outside. */
 /*ext*/ struct resource sparc_iomap = {
-	"sparc_iomap", IOBASE_VADDR, IOBASE_END - 1
+	.name = "sparc_iomap", .start = IOBASE_VADDR, .end = IOBASE_END - 1
 };
 
 /*
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -83,9 +83,6 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
-	if (current->pid != 0)
-		goto out;
-
 	/* endless idle loop with no priority at all */
 	for (;;) {
 		if (ARCH_SUN4C_SUN4) {
@@ -126,8 +123,6 @@ void cpu_idle(void)
 		schedule();
 		check_pgt_cache();
 	}
-out:
-	return;
 }
 
 #else
@@ -333,6 +328,17 @@ void show_stack(struct task_struct *tsk,
 	printk("\n");
 }
 
+void dump_stack(void)
+{
+	unsigned long *ksp;
+
+	__asm__ __volatile__("mov	%%fp, %0"
+			     : "=r" (ksp));
+	show_stack(current, ksp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
 /*
  * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
  */
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -285,17 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs
 			       s, (int) request, (int) pid, addr, data, addr2);
 	}
 #endif
-	if(request == PTRACE_TRACEME) {
-		int ret;
+	if (request == PTRACE_TRACEME) {
+		int my_ret;
 
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED) {
 			pt_error_return(regs, EPERM);
 			goto out;
 		}
-		ret = security_ptrace(current->parent, current);
-		if (ret) {
-			pt_error_return(regs, -ret);
+		my_ret = security_ptrace(current->parent, current);
+		if (my_ret) {
+			pt_error_return(regs, -my_ret);
 			goto out;
 		}
 
@@ -305,7 +306,7 @@ asmlinkage void do_ptrace(struct pt_regs
 		goto out;
 	}
 #ifndef ALLOW_INIT_TRACING
-	if(pid == 1) {
+	if (pid == 1) {
 		/* Can't dork with init. */
 		pt_error_return(regs, EPERM);
 		goto out;
@@ -374,8 +375,8 @@ asmlinkage void do_ptrace(struct pt_regs
 		struct pt_regs *cregs = child->thread.kregs;
 		int rval;
 
-		rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
-		if(rval) {
+		if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
+			rval = -EFAULT;
 			pt_error_return(regs, -rval);
 			goto out_tsk;
 		}
@@ -401,9 +402,8 @@ asmlinkage void do_ptrace(struct pt_regs
 		/* Must be careful, tracing process can only set certain
 		 * bits in the psr.
 		 */
-		i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
-		if(i) {
-			pt_error_return(regs, -i);
+		if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
+			pt_error_return(regs, EFAULT);
 			goto out_tsk;
 		}
 		__get_user(psr, (&pregs->psr));
@@ -413,7 +413,7 @@ asmlinkage void do_ptrace(struct pt_regs
 		psr &= PSR_ICC;
 		cregs->psr &= ~PSR_ICC;
 		cregs->psr |= psr;
-		if(!((pc | npc) & 3)) {
+		if (!((pc | npc) & 3)) {
 			cregs->pc = pc;
 			cregs->npc =npc;
 		}
@@ -439,8 +439,8 @@ asmlinkage void do_ptrace(struct pt_regs
 		struct fps __user *fps = (struct fps __user *) addr;
 		int i;
 
-		i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
-		if(i) {
+		if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
+			i = -EFAULT;
 			pt_error_return(regs, -i);
 			goto out_tsk;
 		}
@@ -474,8 +474,8 @@ asmlinkage void do_ptrace(struct pt_regs
 		struct fps __user *fps = (struct fps __user *) addr;
 		int i;
 
-		i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
-		if(i) {
+		if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
+			i = -EFAULT;
 			pt_error_return(regs, -i);
 			goto out_tsk;
 		}
@@ -527,22 +527,10 @@ asmlinkage void do_ptrace(struct pt_regs
 		addr = 1;
 
 	case PTRACE_CONT: { /* restart after signal. */
-		if (data > _NSIG) {
+		if (!valid_signal(data)) {
 			pt_error_return(regs, EIO);
 			goto out_tsk;
 		}
-		if (addr != 1) {
-			if (addr & 3) {
-				pt_error_return(regs, EINVAL);
-				goto out_tsk;
-			}
-#ifdef DEBUG_PTRACE
-			printk ("Original: %08lx %08lx\n", child->thread.kregs->pc, child->thread.kregs->npc);
-			printk ("Continuing with %08lx %08lx\n", addr, addr+4);
-#endif
-			child->thread.kregs->pc = addr;
-			child->thread.kregs->npc = addr + 4;
-		}
 
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -205,7 +205,7 @@ restore_fpu_state(struct pt_regs *regs, 
 	set_used_math();
 	clear_tsk_thread_flag(current, TIF_USEDFPU);
 
-	if (verify_area(VERIFY_READ, fpu, sizeof(*fpu)))
+	if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
 		return -EFAULT;
 
 	err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
@@ -231,7 +231,7 @@ static inline void do_new_sigreturn (str
 	sf = (struct new_signal_frame __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (verify_area(VERIFY_READ, sf, sizeof(*sf)))
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
 		goto segv_and_exit;
 
 	if (((unsigned long) sf) & 3)
@@ -297,7 +297,7 @@ asmlinkage void do_sigreturn(struct pt_r
 	scptr = (struct sigcontext __user *) regs->u_regs[UREG_I0];
 
 	/* Check sanity of the user arg. */
-	if (verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
+	if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
 	    (((unsigned long) scptr) & 3))
 		goto segv_and_exit;
 
@@ -356,7 +356,7 @@ asmlinkage void do_rt_sigreturn(struct p
 
 	synchronize_user_stack();
 	sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
-	if (verify_area(VERIFY_READ, sf, sizeof(*sf)) ||
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
 	    (((unsigned long) sf) & 0x03))
 		goto segv;
 
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -36,15 +36,12 @@
 
 volatile int smp_processors_ready = 0;
 int smp_num_cpus = 1;
-int smp_threads_ready=0;
 volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
 unsigned char boot_cpu_id = 0;
 unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
 int smp_activated = 0;
 volatile int __cpu_number_map[NR_CPUS];
 volatile int __cpu_logical_map[NR_CPUS];
-cycles_t cacheflush_time = 0; /* XXX */
-unsigned long cache_decay_ticks = 100;
 
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -20,6 +20,7 @@
 #include <linux/in6.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/syscalls.h>
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
@@ -89,6 +90,9 @@ extern void ___atomic24_sub(void);
 extern void ___set_bit(void);
 extern void ___clear_bit(void);
 extern void ___change_bit(void);
+extern void ___rw_read_enter(void);
+extern void ___rw_read_exit(void);
+extern void ___rw_write_enter(void);
 
 /* Alias functions whose names begin with "." and export the aliases.
  * The module references will be fixed up by module_frob_arch_sections.
@@ -121,9 +125,9 @@ EXPORT_SYMBOL(_do_write_unlock);
 #endif
 #else
 // XXX find what uses (or used) these.
-// EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
-// EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
-// EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
+EXPORT_SYMBOL(___rw_read_enter);
+EXPORT_SYMBOL(___rw_read_exit);
+EXPORT_SYMBOL(___rw_write_enter);
 #endif
 /* semaphores */
 EXPORT_SYMBOL(__up);
@@ -144,6 +148,9 @@ EXPORT_SYMBOL(___set_bit);
 EXPORT_SYMBOL(___clear_bit);
 EXPORT_SYMBOL(___change_bit);
 
+/* Per-CPU information table */
+EXPORT_PER_CPU_SYMBOL(__cpu_data);
+
 #ifdef CONFIG_SMP
 /* IRQ implementation. */
 EXPORT_SYMBOL(synchronize_irq);
@@ -151,6 +158,10 @@ EXPORT_SYMBOL(synchronize_irq);
 /* Misc SMP information */
 EXPORT_SYMBOL(__cpu_number_map);
 EXPORT_SYMBOL(__cpu_logical_map);
+
+/* CPU online map and active count. */
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(phys_cpu_present_map);
 #endif
 
 EXPORT_SYMBOL(__udelay);
@@ -164,6 +175,7 @@ EXPORT_SYMBOL(get_auxio);
 #endif
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(io_remap_pfn_range);
   /* P3: iounit_xxx may be needed, sun4d users */
 /* EXPORT_SYMBOL(iounit_map_dma_init); */
 /* EXPORT_SYMBOL(iounit_map_dma_page); */
@@ -331,3 +343,6 @@ EXPORT_SYMBOL(do_BUG);
 
 /* Sun Power Management Idle Handler */
 EXPORT_SYMBOL(pm_idle);
+
+/* Binfmt_misc needs this */
+EXPORT_SYMBOL(sys_close);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -45,7 +45,6 @@ extern void calibrate_delay(void);
 extern volatile int smp_processors_ready;
 extern int smp_num_cpus;
 static int smp_highest_cpu;
-extern int smp_threads_ready;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
 extern unsigned char boot_cpu_id;
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -41,7 +41,6 @@ extern void calibrate_delay(void);
 
 extern volatile int smp_processors_ready;
 extern int smp_num_cpus;
-extern int smp_threads_ready;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern int smp_activated;
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -399,7 +399,7 @@ sparc_sigaction (int sig, const struct o
 	if (act) {
 		unsigned long mask;
 
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -417,7 +417,7 @@ sparc_sigaction (int sig, const struct o
 		 * deadlock us if we held the signal lock on SMP.  So for
 		 * now I take the easy way out and do no locking.
 		 */
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1131,7 +1131,7 @@ sunos_sigaction(int sig, const struct ol
 	if (act) {
 		old_sigset_t mask;
 
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags))
 			return -EFAULT;
@@ -1152,7 +1152,7 @@ sunos_sigaction(int sig, const struct ol
 		 * But then again we don't support SunOS lwp's anyways ;-)
 		 */
 		old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
 			 return -EFAULT;
diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
--- a/arch/sparc/kernel/unaligned.c
+++ b/arch/sparc/kernel/unaligned.c
@@ -428,40 +428,35 @@ static inline int ok_for_user(struct pt_
 			      enum direction dir)
 {
 	unsigned int reg;
-	int retval, check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
+	int check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
 	int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
 
 	if ((regs->pc | regs->npc) & 3)
 		return 0;
 
-	/* Must verify_area() in all the necessary places. */
+	/* Must access_ok() in all the necessary places. */
 #define WINREG_ADDR(regnum) \
 	((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
 
-	retval = 0;
 	reg = (insn >> 25) & 0x1f;
 	if (reg >= 16) {
-		retval = verify_area(check, WINREG_ADDR(reg - 16), size);
-		if (retval)
-			return retval;
+		if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+			return -EFAULT;
 	}
 	reg = (insn >> 14) & 0x1f;
 	if (reg >= 16) {
-		retval = verify_area(check, WINREG_ADDR(reg - 16), size);
-		if (retval)
-			return retval;
+		if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+			return -EFAULT;
 	}
 	if (!(insn & 0x2000)) {
 		reg = (insn & 0x1f);
 		if (reg >= 16) {
-			retval = verify_area(check, WINREG_ADDR(reg - 16),
-					     size);
-			if (retval)
-				return retval;
+			if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+				return -EFAULT;
 		}
 	}
-	return retval;
 #undef WINREG_ADDR
+	return 0;
 }
 
 void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault");
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
--- a/arch/sparc/mm/generic.c
+++ b/arch/sparc/mm/generic.c
@@ -47,7 +47,7 @@ static inline void forget_pte(pte_t page
  * They use a pgprot that sets PAGE_IO and does not check the
  * mem_map table as this is independent of normal memory.
  */
-static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
+static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long offset, pgprot_t prot, int space)
 {
 	unsigned long end;
@@ -58,7 +58,7 @@ static inline void io_remap_pte_range(pt
 		end = PMD_SIZE;
 	do {
 		pte_t oldpage = *pte;
-		pte_clear(pte);
+		pte_clear(mm, address, pte);
 		set_pte(pte, mk_pte_io(offset, prot, space));
 		forget_pte(oldpage);
 		address += PAGE_SIZE;
@@ -67,7 +67,7 @@ static inline void io_remap_pte_range(pt
 	} while (address < end);
 }
 
-static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
+static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
 	unsigned long offset, pgprot_t prot, int space)
 {
 	unsigned long end;
@@ -78,10 +78,10 @@ static inline int io_remap_pmd_range(pmd
 		end = PGDIR_SIZE;
 	offset -= address;
 	do {
-		pte_t * pte = pte_alloc_map(current->mm, pmd, address);
+		pte_t * pte = pte_alloc_map(mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		io_remap_pte_range(pte, address, end - address, address + offset, prot, space);
+		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
@@ -107,7 +107,41 @@ int io_remap_page_range(struct vm_area_s
 		error = -ENOMEM;
 		if (!pmd)
 			break;
-		error = io_remap_pmd_range(pmd, from, end - from, offset + from, prot, space);
+		error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
+		if (error)
+			break;
+		from = (from + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	flush_tlb_range(vma, beg, end);
+	return error;
+}
+
+int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+			unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+	int error = 0;
+	pgd_t * dir;
+	unsigned long beg = from;
+	unsigned long end = from + size;
+	struct mm_struct *mm = vma->vm_mm;
+	int space = GET_IOSPACE(pfn);
+	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+
+	prot = __pgprot(pg_iobits);
+	offset -= from;
+	dir = pgd_offset(mm, from);
+	flush_cache_range(vma, beg, end);
+
+	spin_lock(&mm->page_table_lock);
+	while (from < end) {
+		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
 		if (error)
 			break;
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c
--- a/arch/sparc/mm/highmem.c
+++ b/arch/sparc/mm/highmem.c
@@ -88,7 +88,7 @@ void kunmap_atomic(void *kvaddr, enum km
 	 * force other mappings to Oops if they'll try to access
 	 * this pte without first remap it
 	 */
-	pte_clear(kmap_pte-idx);
+	pte_clear(&init_mm, vaddr, kmap_pte-idx);
 /* XXX Fix - Anton */
 #if 0
 	__flush_tlb_one(vaddr);
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -59,9 +59,6 @@ unsigned long highstart_pfn, highend_pfn
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-
 #define kmap_get_fixmap_pte(vaddr) \
 	pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
 
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -161,6 +161,9 @@ static inline int srmmu_pte_none(pte_t p
 static inline int srmmu_pte_present(pte_t pte)
 { return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
 
+static inline int srmmu_pte_read(pte_t pte)
+{ return !(pte_val(pte) & SRMMU_NOREAD); }
+
 static inline void srmmu_pte_clear(pte_t *ptep)
 { srmmu_set_pte(ptep, __pte(0)); }
 
@@ -1003,8 +1006,7 @@ extern void viking_flush_cache_all(void)
 extern void viking_flush_cache_mm(struct mm_struct *mm);
 extern void viking_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 				     unsigned long end);
-extern void viking_flush_cache_page(struct vm_area_struct *vma,
-				    unsigned long page);
+extern void viking_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void viking_flush_page_to_ram(unsigned long page);
 extern void viking_flush_page_for_dma(unsigned long page);
 extern void viking_flush_sig_insns(struct mm_struct *mm, unsigned long addr);
@@ -1344,7 +1346,6 @@ void __init srmmu_paging_init(void)
 
 		free_area_init_node(0, &contig_page_data, zones_size,
 				    pfn_base, zholes_size);
-		mem_map = contig_page_data.node_mem_map;
 	}
 }
 
@@ -2168,6 +2169,7 @@ void __init ld_mmu_srmmu(void)
 
 	BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
+	BTFIXUPSET_CALL(pte_read, srmmu_pte_read, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(pmd_bad, srmmu_pmd_bad, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pmd_present, srmmu_pmd_present, BTFIXUPCALL_NORM);
@@ -2198,7 +2200,6 @@ void __init ld_mmu_srmmu(void)
 	BTFIXUPSET_CALL(free_pgd_fast, srmmu_free_pgd_fast, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_HALF(pte_readi, SRMMU_NOREAD);
 	BTFIXUPSET_HALF(pte_writei, SRMMU_WRITE);
 	BTFIXUPSET_HALF(pte_dirtyi, SRMMU_DIRTY);
 	BTFIXUPSET_HALF(pte_youngi, SRMMU_REF);
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1746,6 +1746,11 @@ static int sun4c_pte_present(pte_t pte)
 }
 static void sun4c_pte_clear(pte_t *ptep)	{ *ptep = __pte(0); }
 
+static int sun4c_pte_read(pte_t pte)
+{
+	return (pte_val(pte) & _SUN4C_PAGE_READ);
+}
+
 static int sun4c_pmd_bad(pmd_t pmd)
 {
 	return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) ||
@@ -2117,7 +2122,6 @@ void __init sun4c_paging_init(void)
 
 		free_area_init_node(0, &contig_page_data, zones_size,
 				    pfn_base, zholes_size);
-		mem_map = contig_page_data.node_mem_map;
 	}
 
 	cnt = 0;
@@ -2200,6 +2204,7 @@ void __init ld_mmu_sun4c(void)
 
 	BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
+	BTFIXUPSET_CALL(pte_read, sun4c_pte_read, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM);
@@ -2226,7 +2231,6 @@ void __init ld_mmu_sun4c(void)
 	BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_HALF(pte_readi, _SUN4C_PAGE_READ);
 	BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE);
 	BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED);
 	BTFIXUPSET_HALF(pte_youngi, _SUN4C_PAGE_ACCESSED);
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -47,9 +47,9 @@ prom_sortmemlist(struct linux_mlist_v0 *
 	char *tmpaddr;
 	char *lowest;
 
-	for(i=0; thislist[i].theres_more != 0; i++) {
+	for(i=0; thislist[i].theres_more; i++) {
 		lowest = thislist[i].start_adr;
-		for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+		for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
 			if(thislist[mitr].start_adr < lowest) {
 				lowest = thislist[mitr].start_adr;
 				swapi = mitr;
@@ -85,7 +85,7 @@ void __init prom_meminit(void)
 			prom_phys_total[iter].num_bytes = mptr->num_bytes;
 			prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
 		}
-		prom_phys_total[iter-1].theres_more = 0x0;
+		prom_phys_total[iter-1].theres_more = NULL;
 		/* Second, the total prom taken descriptors. */
 		for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
 		    mptr; mptr=mptr->theres_more, iter++) {
@@ -93,7 +93,7 @@ void __init prom_meminit(void)
 			prom_prom_taken[iter].num_bytes = mptr->num_bytes;
 			prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
 		}
-		prom_prom_taken[iter-1].theres_more = 0x0;
+		prom_prom_taken[iter-1].theres_more = NULL;
 		/* Last, the available physical descriptors. */
 		for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
 		    mptr; mptr=mptr->theres_more, iter++) {
@@ -101,7 +101,7 @@ void __init prom_meminit(void)
 			prom_phys_avail[iter].num_bytes = mptr->num_bytes;
 			prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
 		}
-		prom_phys_avail[iter-1].theres_more = 0x0;
+		prom_phys_avail[iter-1].theres_more = NULL;
 		/* Sort all the lists. */
 		prom_sortmemlist(prom_phys_total);
 		prom_sortmemlist(prom_prom_taken);
@@ -124,7 +124,7 @@ void __init prom_meminit(void)
 			prom_phys_avail[iter].theres_more =
 				&prom_phys_avail[iter+1];
 		}
-		prom_phys_avail[iter-1].theres_more = 0x0;
+		prom_phys_avail[iter-1].theres_more = NULL;
 
 		num_regs = prom_getproperty(node, "reg",
 					    (char *) prom_reg_memlist,
@@ -138,7 +138,7 @@ void __init prom_meminit(void)
 			prom_phys_total[iter].theres_more =
 				&prom_phys_total[iter+1];
 		}
-		prom_phys_total[iter-1].theres_more = 0x0;
+		prom_phys_total[iter-1].theres_more = NULL;
 
 		node = prom_getchild(prom_root_node);
 		node = prom_searchsiblings(node, "virtual-memory");
@@ -158,7 +158,7 @@ void __init prom_meminit(void)
 			prom_prom_taken[iter].theres_more =
 				&prom_prom_taken[iter+1];
 		}
-		prom_prom_taken[iter-1].theres_more = 0x0;
+		prom_prom_taken[iter-1].theres_more = NULL;
 
 		prom_sortmemlist(prom_prom_taken);
 
@@ -182,15 +182,15 @@ void __init prom_meminit(void)
 	case PROM_SUN4:
 #ifdef CONFIG_SUN4	
 		/* how simple :) */
-		prom_phys_total[0].start_adr = 0x0;
+		prom_phys_total[0].start_adr = NULL;
 		prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize);
-		prom_phys_total[0].theres_more = 0x0;
-		prom_prom_taken[0].start_adr = 0x0; 
+		prom_phys_total[0].theres_more = NULL;
+		prom_prom_taken[0].start_adr = NULL; 
 		prom_prom_taken[0].num_bytes = 0x0;
-		prom_prom_taken[0].theres_more = 0x0;
-		prom_phys_avail[0].start_adr = 0x0;
+		prom_prom_taken[0].theres_more = NULL;
+		prom_phys_avail[0].start_adr = NULL;
 		prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail);
-		prom_phys_avail[0].theres_more = 0x0;
+		prom_phys_avail[0].theres_more = NULL;
 #endif
 		break;
 
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
--- a/arch/sparc/prom/sun4prom.c
+++ b/arch/sparc/prom/sun4prom.c
@@ -151,7 +151,7 @@ struct linux_romvec * __init sun4_prom_i
 	 * have more time, we can teach the penguin to say "By your
 	 * command" or "Activating turbo boost, Michael". :-)
 	 */
-	sun4_romvec->setLEDs(0x0);
+	sun4_romvec->setLEDs(NULL);
 	
 	printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
 		sun4_romvec->monid,
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -16,6 +16,33 @@ config TIME_INTERPOLATION
 	bool
 	default y
 
+choice
+	prompt "Kernel page size"
+	default SPARC64_PAGE_SIZE_8KB
+
+config SPARC64_PAGE_SIZE_8KB
+	bool "8KB"
+	help
+	  This lets you select the page size of the kernel.
+
+	  8KB and 64KB work quite well, since Sparc ELF sections
+	  provide for up to 64KB alignment.
+
+	  Therefore, 512KB and 4MB are for expert hackers only.
+
+	  If you don't know what to do, choose 8KB.
+
+config SPARC64_PAGE_SIZE_64KB
+	bool "64KB"
+
+config SPARC64_PAGE_SIZE_512KB
+	bool "512KB"
+
+config SPARC64_PAGE_SIZE_4MB
+	bool "4MB"
+
+endchoice
+
 source "init/Kconfig"
 
 config SYSVIPC_COMPAT
@@ -91,6 +118,7 @@ config VT_CONSOLE
 
 config HW_CONSOLE
 	bool
+	depends on VT
 	default y
 
 config SMP
@@ -136,19 +164,10 @@ config NR_CPUS
 
 source "drivers/cpufreq/Kconfig"
 
-config CPU_FREQ_TABLE
-       tristate "CPU frequency table helpers"
-       depends on CPU_FREQ
-       default y
-       help
-         Many CPUFreq drivers use these helpers, so only say N here if
-	 the CPUFreq driver of your choice doesn't need these helpers.
-
-	 If in doubt, say Y.
-
 config US3_FREQ
 	tristate "UltraSPARC-III CPU Frequency driver"
-	depends on CPU_FREQ_TABLE
+	depends on CPU_FREQ
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for UltraSPARC-III processors.
 
@@ -158,7 +177,8 @@ config US3_FREQ
 
 config US2E_FREQ
 	tristate "UltraSPARC-IIe CPU Frequency driver"
-	depends on CPU_FREQ_TABLE
+	depends on CPU_FREQ
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for UltraSPARC-IIe processors.
 
@@ -198,9 +218,11 @@ config HUGETLB_PAGE_SIZE_4MB
 	bool "4MB"
 
 config HUGETLB_PAGE_SIZE_512K
+	depends on !SPARC64_PAGE_SIZE_4MB
 	bool "512K"
 
 config HUGETLB_PAGE_SIZE_64K
+	depends on !SPARC64_PAGE_SIZE_4MB && !SPARC64_PAGE_SIZE_512K
 	bool "64K"
 
 endchoice
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -41,10 +41,10 @@ endif
 
 ifneq ($(NEW_GCC),y)
   CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
-	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+	    -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare
 else
   CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
-	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \
+	    -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
 	    $(CC_UNDECL)
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
 endif
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Thu Feb 17 15:32:19 2005
+# Linux kernel version: 2.6.11
+# Sun Mar  6 20:47:29 2005
 #
 CONFIG_64BIT=y
 CONFIG_MMU=y
@@ -368,6 +368,7 @@ CONFIG_SCSI_SATA_SVW=m
 CONFIG_SCSI_ATA_PIIX=m
 CONFIG_SCSI_SATA_NV=m
 CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_QSTOR=m
 CONFIG_SCSI_SATA_SX4=m
 CONFIG_SCSI_SATA_SIL=m
 CONFIG_SCSI_SATA_SIS=m
@@ -737,6 +738,7 @@ CONFIG_NET_SCH_INGRESS=m
 CONFIG_NET_QOS=y
 CONFIG_NET_ESTIMATOR=y
 CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
 CONFIG_NET_CLS_TCINDEX=m
 CONFIG_NET_CLS_ROUTE4=m
 CONFIG_NET_CLS_ROUTE=y
@@ -747,6 +749,12 @@ CONFIG_NET_CLS_IND=y
 CONFIG_CLS_U32_MARK=y
 CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
@@ -899,7 +907,6 @@ CONFIG_FORCEDETH=m
 CONFIG_DGRS=m
 CONFIG_EEPRO100=m
 CONFIG_E100=m
-CONFIG_E100_NAPI=y
 CONFIG_FEALNX=m
 CONFIG_NATSEMI=m
 CONFIG_NE2K_PCI=m
@@ -1171,6 +1178,7 @@ CONFIG_I2C_ISA=m
 CONFIG_I2C_NFORCE2=m
 CONFIG_I2C_PARPORT=m
 CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PIIX4=m
 CONFIG_I2C_PROSAVAGE=m
 CONFIG_I2C_SAVAGE4=m
 CONFIG_SCx200_ACB=m
@@ -1194,7 +1202,9 @@ CONFIG_SENSORS_ADM1031=m
 CONFIG_SENSORS_ASB100=m
 CONFIG_SENSORS_DS1621=m
 CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
 CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
 CONFIG_SENSORS_IT87=m
 CONFIG_SENSORS_LM63=m
 CONFIG_SENSORS_LM75=m
@@ -1208,6 +1218,7 @@ CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_MAX1619=m
 CONFIG_SENSORS_PC87360=m
 CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
 CONFIG_SENSORS_SMSC47M1=m
 CONFIG_SENSORS_VIA686A=m
 CONFIG_SENSORS_W83781D=m
@@ -1909,6 +1920,7 @@ CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -114,9 +114,9 @@ static int aout32_core_dump(long signr, 
 
 /* make sure we actually have a data and stack area to dump */
 	set_fs(USER_DS);
-	if (verify_area(VERIFY_READ, (void __user *) START_DATA(dump), dump.u_dsize))
+	if (!access_ok(VERIFY_READ, (void __user *) START_DATA(dump), dump.u_dsize))
 		dump.u_dsize = 0;
-	if (verify_area(VERIFY_READ, (void __user *) START_STACK(dump), dump.u_ssize))
+	if (!access_ok(VERIFY_READ, (void __user *) START_STACK(dump), dump.u_ssize))
 		dump.u_ssize = 0;
 
 	set_fs(KERNEL_DS);
@@ -241,7 +241,7 @@ static int load_aout32_binary(struct lin
 	current->mm->brk = ex.a_bss +
 		(current->mm->start_brk = N_BSSADDR(ex));
 
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -22,10 +22,11 @@ struct linux_fhc *fhc_list = NULL;
 
 #define IS_CENTRAL_FHC(__fhc)	((__fhc) == central_bus->child)
 
-static inline unsigned long long_align(unsigned long addr)
+static void central_probe_failure(int line)
 {
-	return ((addr + (sizeof(unsigned long) - 1)) &
-		~(sizeof(unsigned long) - 1));
+	prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
+		    line);
+	prom_halt();
 }
 
 static void central_ranges_init(int cnode, struct linux_central *central)
@@ -65,7 +66,7 @@ static void adjust_regs(struct linux_pro
 			if (regp[regc].which_io == rangep[rngc].ot_child_space)
 				break; /* Fount it */
 		if (rngc == nranges) /* oops */
-			prom_printf("adjust_regs: Could not find range with matching bus type...\n");
+			central_probe_failure(__LINE__);
 		regp[regc].which_io = rangep[rngc].ot_parent_space;
 		regp[regc].phys_addr -= rangep[rngc].ot_child_base;
 		regp[regc].phys_addr += rangep[rngc].ot_parent_base;
@@ -102,6 +103,13 @@ void * __init central_alloc_bootmem(unsi
 	return ret;
 }
 
+static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
+{
+	unsigned long ret = ((unsigned long) r->which_io) << 32;
+
+	return ret | (unsigned long) r->phys_addr;
+}
+
 static void probe_other_fhcs(void)
 {
 	struct linux_prom64_registers fpregs[6];
@@ -110,10 +118,8 @@ static void probe_other_fhcs(void)
 
 	node = prom_getchild(prom_root_node);
 	node = prom_searchsiblings(node, "fhc");
-	if (node == 0) {
-		prom_printf("FHC: Cannot find any toplevel firehose controllers.\n");
-		prom_halt();
-	}
+	if (node == 0)
+		central_probe_failure(__LINE__);
 	while (node) {
 		struct linux_fhc *fhc;
 		int board;
@@ -121,10 +127,8 @@ static void probe_other_fhcs(void)
 
 		fhc = (struct linux_fhc *)
 			central_alloc_bootmem(sizeof(struct linux_fhc));
-		if (fhc == NULL) {
-			prom_printf("probe_other_fhcs: Cannot alloc fhc.\n");
-			prom_halt();
-		}
+		if (fhc == NULL)
+			central_probe_failure(__LINE__);
 
 		/* Link it into the FHC chain. */
 		fhc->next = fhc_list;
@@ -140,10 +144,8 @@ static void probe_other_fhcs(void)
 
 		/* Non-central FHC's have 64-bit OBP format registers. */
 		if (prom_getproperty(node, "reg",
-				    (char *)&fpregs[0], sizeof(fpregs)) == -1) {
-			prom_printf("FHC: Fatal error, cannot get fhc regs.\n");
-			prom_halt();
-		}
+				    (char *)&fpregs[0], sizeof(fpregs)) == -1)
+			central_probe_failure(__LINE__);
 
 		/* Only central FHC needs special ranges applied. */
 		fhc->fhc_regs.pregs = fpregs[0].phys_addr;
@@ -196,28 +198,23 @@ static void probe_clock_board(struct lin
 	int clknode, nslots, tmp, nregs;
 
 	clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
-	if (clknode == 0 || clknode == -1) {
-		prom_printf("Critical error, central lacks clock-board.\n");
-		prom_halt();
-	}
+	if (clknode == 0 || clknode == -1)
+		central_probe_failure(__LINE__);
+
 	nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
-	if (nregs == -1) {
-		prom_printf("CENTRAL: Fatal error, cannot map clock-board regs.\n");
-		prom_halt();
-	}
+	if (nregs == -1)
+		central_probe_failure(__LINE__);
+
 	nregs /= sizeof(struct linux_prom_registers);
 	apply_fhc_ranges(fhc, &cregs[0], nregs);
 	apply_central_ranges(central, &cregs[0], nregs);
-	central->cfreg = ((((unsigned long)cregs[0].which_io) << 32UL) |
-			  ((unsigned long)cregs[0].phys_addr));
-	central->clkregs = ((((unsigned long)cregs[1].which_io) << 32UL) |
-			    ((unsigned long)cregs[1].phys_addr));
+	central->cfreg = prom_reg_to_paddr(&cregs[0]);
+	central->clkregs = prom_reg_to_paddr(&cregs[1]);
 
 	if (nregs == 2)
 		central->clkver = 0UL;
 	else
-		central->clkver = ((((unsigned long)cregs[2].which_io) << 32UL) |
-				   ((unsigned long)cregs[2].phys_addr));
+		central->clkver = prom_reg_to_paddr(&cregs[2]);
 
 	tmp = upa_readb(central->clkregs + CLOCK_STAT1);
 	tmp &= 0xc0;
@@ -247,6 +244,18 @@ static void probe_clock_board(struct lin
 	       (central->clkver ? upa_readb(central->clkver) : 0x00));
 }
 
+static void ZAP(unsigned long iclr, unsigned long imap)
+{
+	u32 imap_tmp;
+
+	upa_writel(0, iclr);
+	upa_readl(iclr);
+	imap_tmp = upa_readl(imap);
+	imap_tmp &= ~(0x80000000);
+	upa_writel(imap_tmp, imap);
+	upa_readl(imap);
+}
+
 static void init_all_fhc_hw(void)
 {
 	struct linux_fhc *fhc;
@@ -257,16 +266,6 @@ static void init_all_fhc_hw(void)
 		/* Clear all of the interrupt mapping registers
 		 * just in case OBP left them in a foul state.
 		 */
-#define ZAP(ICLR, IMAP) \
-do {	u32 imap_tmp; \
-	upa_writel(0, (ICLR)); \
-	upa_readl(ICLR); \
-	imap_tmp = upa_readl(IMAP); \
-	imap_tmp &= ~(0x80000000); \
-	upa_writel(imap_tmp, (IMAP)); \
-	upa_readl(IMAP); \
-} while (0)
-
 		ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
 		    fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
 		ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
@@ -276,8 +275,6 @@ do {	u32 imap_tmp; \
 		ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
 		    fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
 
-#undef ZAP
-
 		/* Setup FHC control register. */
 		tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
 
@@ -288,7 +285,8 @@ do {	u32 imap_tmp; \
 		/* For all FHCs, clear the firmware synchronization
 		 * line and both low power mode enables.
 		 */
-		tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+		tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF |
+			 FHC_CONTROL_SLINE);
 
 		upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
 		upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
@@ -313,17 +311,13 @@ void central_probe(void)
 	/* Ok we got one, grab some memory for software state. */
 	central_bus = (struct linux_central *)
 		central_alloc_bootmem(sizeof(struct linux_central));
-	if (central_bus == NULL) {
-		prom_printf("central_probe: Cannot alloc central_bus.\n");
-		prom_halt();
-	}
+	if (central_bus == NULL)
+		central_probe_failure(__LINE__);
 
 	fhc = (struct linux_fhc *)
 		central_alloc_bootmem(sizeof(struct linux_fhc));
-	if (fhc == NULL) {
-		prom_printf("central_probe: Cannot alloc central fhc.\n");
-		prom_halt();
-	}
+	if (fhc == NULL)
+		central_probe_failure(__LINE__);
 
 	/* First init central. */
 	central_bus->child = fhc;
@@ -340,10 +334,9 @@ void central_probe(void)
 
 	fhc->parent = central_bus;
 	fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
-	if (fnode == 0 || fnode == -1) {
-		prom_printf("Critical error, central board lacks fhc.\n");
-		prom_halt();
-	}
+	if (fnode == 0 || fnode == -1)
+		central_probe_failure(__LINE__);
+
 	fhc->prom_node = fnode;
 	prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
 	strcpy(fhc->prom_name, namebuf);
@@ -351,24 +344,17 @@ void central_probe(void)
 	fhc_ranges_init(fnode, fhc);
 
 	/* Now, map in FHC register set. */
-	if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) {
-		prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n");
-		prom_halt();
-	}
+	if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1)
+		central_probe_failure(__LINE__);
+
 	apply_central_ranges(central_bus, &fpregs[0], 6);
 	
-	fhc->fhc_regs.pregs = ((((unsigned long)fpregs[0].which_io)<<32UL) |
-			       ((unsigned long)fpregs[0].phys_addr));
-	fhc->fhc_regs.ireg = ((((unsigned long)fpregs[1].which_io)<<32UL) |
-			      ((unsigned long)fpregs[1].phys_addr));
-	fhc->fhc_regs.ffregs = ((((unsigned long)fpregs[2].which_io)<<32UL) |
-				((unsigned long)fpregs[2].phys_addr));
-	fhc->fhc_regs.sregs = ((((unsigned long)fpregs[3].which_io)<<32UL) |
-			       ((unsigned long)fpregs[3].phys_addr));
-	fhc->fhc_regs.uregs = ((((unsigned long)fpregs[4].which_io)<<32UL) |
-			       ((unsigned long)fpregs[4].phys_addr));
-	fhc->fhc_regs.tregs = ((((unsigned long)fpregs[5].which_io)<<32UL) |
-			       ((unsigned long)fpregs[5].phys_addr));
+	fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]);
+	fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]);
+	fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]);
+	fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]);
+	fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]);
+	fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]);
 
 	/* Obtain board number from board status register, Central's
 	 * FHC lacks "board#" property.
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -38,6 +38,7 @@ struct cpu_fp_info linux_sparc_fpu[] = {
   { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
   { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
   { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
+  { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -51,6 +52,7 @@ struct cpu_iu_info linux_sparc_chips[] =
   { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
   { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
   { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
+  { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
--- a/arch/sparc64/kernel/dtlb_backend.S
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -7,60 +7,143 @@
  */
 
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
+#include <asm/mmu.h>
 
 #if PAGE_SHIFT == 13
-#define FILL_VALID_SZ_BITS1(r1) \
-	 sllx		%g2, 62, r1
-#define FILL_VALID_SZ_BITS2(r1)
-#define FILL_VALID_SZ_BITS_NOP nop
+#define SZ_BITS		_PAGE_SZ8K
 #elif PAGE_SHIFT == 16
-#define FILL_VALID_SZ_BITS1(r1) \
-	or		%g0, 5, r1
-#define FILL_VALID_SZ_BITS2(r1) \
-	sllx		r1, 61, r1
-#define FILL_VALID_SZ_BITS_NOP
-#else
-#error unsupported PAGE_SIZE
-#endif /* PAGE_SHIFT */
+#define SZ_BITS		_PAGE_SZ64K
+#elif PAGE_SHIFT == 19
+#define SZ_BITS		_PAGE_SZ512K
+#elif PAGE_SHIFT == 22
+#define SZ_BITS		_PAGE_SZ4M
+#endif
+
+#define VALID_SZ_BITS	(_PAGE_VALID | SZ_BITS)
 
 #define VPTE_BITS		(_PAGE_CP | _PAGE_CV | _PAGE_P )
 #define VPTE_SHIFT		(PAGE_SHIFT - 3)
-#define TLB_PMD_SHIFT		(PAGE_SHIFT - 3 + 3)
-#define TLB_PGD_SHIFT		(PMD_BITS + PAGE_SHIFT - 3 + 3)
-#define TLB_PMD_MASK		(((1 << PMD_BITS) - 1) << 1)
-#define TLB_PGD_MASK		(((1 << (VA_BITS - PAGE_SHIFT - (PAGE_SHIFT - 3) - PMD_BITS)) - 1) << 2)
 
 /* Ways we can get here:
  *
  * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1.
  * 2) Nucleus loads and stores to/from user/kernel window save areas.
  * 3) VPTE misses from dtlb_base and itlb_base.
+ *
+ * We need to extract out the PMD and PGDIR indexes from the
+ * linear virtual page table access address.  The PTE index
+ * is at the bottom, but we are not concerned with it.  Bits
+ * 0 to 2 are clear since each PTE is 8 bytes in size.  Each
+ * PMD and PGDIR entry are 4 bytes in size.   Thus, this
+ * address looks something like:
+ *
+ * |---------------------------------------------------------------|
+ * |  ...   |    PGDIR index    |    PMD index    | PTE index  |   |
+ * |---------------------------------------------------------------|
+ *   63   F   E               D   C             B   A         3 2 0  <- bit nr
+ *
+ *  The variable bits above are defined as:
+ *  A --> 3 + (PAGE_SHIFT - log2(8))
+ *    --> 3 + (PAGE_SHIFT - 3) - 1
+ *        (ie. this is "bit 3" + PAGE_SIZE - size of PTE entry in bits - 1)
+ *  B --> A + 1
+ *  C --> B + (PAGE_SHIFT - log2(4))
+ *    -->  B + (PAGE_SHIFT - 2) - 1
+ *        (ie. this is "bit B" + PAGE_SIZE - size of PMD entry in bits - 1)
+ *  D --> C + 1
+ *  E --> D + (PAGE_SHIFT - log2(4))
+ *    --> D + (PAGE_SHIFT - 2) - 1
+ *        (ie. this is "bit D" + PAGE_SIZE - size of PGDIR entry in bits - 1)
+ *  F --> E + 1
+ *
+ * (Note how "B" always evalutes to PAGE_SHIFT, all the other constants
+ *  cancel out.)
+ *
+ * For 8K PAGE_SIZE (thus, PAGE_SHIFT of 13) the bit numbers are:
+ * A --> 12
+ * B --> 13
+ * C --> 23
+ * D --> 24
+ * E --> 34
+ * F --> 35
+ *
+ * For 64K PAGE_SIZE (thus, PAGE_SHIFT of 16) the bit numbers are:
+ * A --> 15
+ * B --> 16
+ * C --> 29
+ * D --> 30
+ * E --> 43
+ * F --> 44
+ *
+ * Because bits both above and below each PGDIR and PMD index need to
+ * be masked out, and the index can be as long as 14 bits (when using a
+ * 64K PAGE_SIZE, and thus a PAGE_SHIFT of 16), we need 3 instructions
+ * to extract each index out.
+ *
+ * Shifts do not pair very well on UltraSPARC-I, II, IIi, and IIe, so
+ * we try to avoid using them for the entire operation.  We could setup
+ * a mask anywhere from bit 31 down to bit 10 using the sethi instruction.
+ *
+ * We need a mask covering bits B --> C and one covering D --> E.
+ * For 8K PAGE_SIZE these masks are 0x00ffe000 and 0x7ff000000.
+ * For 64K PAGE_SIZE these masks are 0x3fff0000 and 0xfffc0000000.
+ * The second in each set cannot be loaded with a single sethi
+ * instruction, because the upper bits are past bit 32.  We would
+ * need to use a sethi + a shift.
+ *
+ * For the time being, we use 2 shifts and a simple "and" mask.
+ * We shift left to clear the bits above the index, we shift down
+ * to clear the bits below the index (sans the log2(4 or 8) bits)
+ * and a mask to clear the log2(4 or 8) bits.  We need therefore
+ * define 4 shift counts, all of which are relative to PAGE_SHIFT.
+ *
+ * Although unsupportable for other reasons, this does mean that
+ * 512K and 4MB page sizes would be generaally supported by the
+ * kernel.  (ELF binaries would break with > 64K PAGE_SIZE since
+ * the sections are only aligned that strongly).
+ *
+ * The operations performed for extraction are thus:
+ *
+ *      ((X << FOO_SHIFT_LEFT) >> FOO_SHIFT_RIGHT) & ~0x3
+ *
  */
 
+#define A (3 + (PAGE_SHIFT - 3) - 1)
+#define B (A + 1)
+#define C (B + (PAGE_SHIFT - 2) - 1)
+#define D (C + 1)
+#define E (D + (PAGE_SHIFT - 2) - 1)
+#define F (E + 1)
+
+#define PMD_SHIFT_LEFT		(64 - D)
+#define PMD_SHIFT_RIGHT		(64 - (D - B) - 2)
+#define PGDIR_SHIFT_LEFT 	(64 - F)
+#define PGDIR_SHIFT_RIGHT	(64 - (F - D) - 2)
+#define LOW_MASK_BITS		0x3
+
 /* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss	*/
 	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
 	add		%g3, %g3, %g5			! Compute VPTE base
 	cmp		%g4, %g5			! VPTE miss?
 	bgeu,pt		%xcc, 1f			! Continue here
-	 andcc		%g4, TAG_CONTEXT_BITS, %g5	! From Nucleus? (for tl0 miss)
-	ba,pt		%xcc, from_tl1_trap		! Fall to tl0 miss
-	 rdpr		%tl, %g5			! For tl0 miss TL==3 test
+	 andcc		%g4, TAG_CONTEXT_BITS, %g5	! tl0 miss Nucleus test
+	ba,a,pt		%xcc, from_tl1_trap		! Fall to tl0 miss
 1:	sllx		%g6, VPTE_SHIFT, %g4		! Position TAG_ACCESS
+	or		%g4, %g5, %g4			! Prepare TAG_ACCESS
 
 /* TLB1 ** ICACHE line 2: Quick VPTE miss	  	*/
-	or		%g4, %g5, %g4			! Prepare TAG_ACCESS
 	mov		TSB_REG, %g1			! Grab TSB reg
 	ldxa		[%g1] ASI_DMMU, %g5		! Doing PGD caching?
-	srlx		%g6, (TLB_PMD_SHIFT - 1), %g1	! Position PMD offset
+	sllx		%g6, PMD_SHIFT_LEFT, %g1	! Position PMD offset
 	be,pn		%xcc, sparc64_vpte_nucleus	! Is it from Nucleus?
-	 and		%g1, TLB_PMD_MASK, %g1		! Mask PMD offset bits
+	 srlx		%g1, PMD_SHIFT_RIGHT, %g1	! Mask PMD offset bits
 	brnz,pt		%g5, sparc64_vpte_continue	! Yep, go like smoke
-	 add		%g1, %g1, %g1			! Position PMD offset some more
+	 andn		%g1, LOW_MASK_BITS, %g1		! Final PMD mask
+	sllx		%g6, PGDIR_SHIFT_LEFT, %g5	! Position PGD offset
 
 /* TLB1 ** ICACHE line 3: Quick VPTE miss	  	*/
-	srlx		%g6, (TLB_PGD_SHIFT - 2), %g5	! Position PGD offset
-	and		%g5, TLB_PGD_MASK, %g5		! Mask PGD offset
+	srlx		%g5, PGDIR_SHIFT_RIGHT, %g5	! Mask PGD offset bits
+	andn		%g5, LOW_MASK_BITS, %g5		! Final PGD mask
 	lduwa		[%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
 	brz,pn		%g5, vpte_noent			! Valid?
 sparc64_kpte_continue:
@@ -71,23 +154,28 @@ sparc64_vpte_continue:
 	brz,pn		%g5, vpte_noent			! Valid?
 
 /* TLB1 ** ICACHE line 4: Quick VPTE miss	  	*/
-	 FILL_VALID_SZ_BITS1(%g1)			! Put _PAGE_VALID into %g1
-	FILL_VALID_SZ_BITS2(%g1)			! Put _PAGE_VALID into %g1
+	 mov		(VALID_SZ_BITS >> 61), %g1	! upper vpte into %g1
+	sllx		%g1, 61, %g1			! finish calc
 	or		%g5, VPTE_BITS, %g5		! Prepare VPTE data
 	or		%g5, %g1, %g5			! ...
 	mov		TLB_SFSR, %g1			! Restore %g1 value
 	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Load VPTE into TLB
 	stxa		%g4, [%g1 + %g1] ASI_DMMU	! Restore previous TAG_ACCESS
 	retry						! Load PTE once again
-	FILL_VALID_SZ_BITS_NOP
 
+#undef SZ_BITS
+#undef VALID_SZ_BITS
 #undef VPTE_SHIFT
-#undef TLB_PMD_SHIFT
-#undef TLB_PGD_SHIFT
 #undef VPTE_BITS
-#undef TLB_PMD_MASK
-#undef TLB_PGD_MASK
-#undef FILL_VALID_SZ_BITS1
-#undef FILL_VALID_SZ_BITS2
-#undef FILL_VALID_SZ_BITS_NOP
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef PMD_SHIFT_LEFT
+#undef PMD_SHIFT_RIGHT
+#undef PGDIR_SHIFT_LEFT
+#undef PGDIR_SHIFT_RIGHT
+#undef LOW_MASK_BITS
 
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
--- a/arch/sparc64/kernel/dtlb_base.S
+++ b/arch/sparc64/kernel/dtlb_base.S
@@ -7,7 +7,7 @@
  */
 
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
+#include <asm/mmu.h>
 
 /* %g1	TLB_SFSR	(%g1 + %g1 == TLB_TAG_ACCESS)
  * %g2	(KERN_HIGHBITS | KERN_LOWBITS)
@@ -68,8 +68,8 @@
 /* DTLB ** ICACHE line 1: Quick user TLB misses		*/
 	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
 	andcc		%g4, TAG_CONTEXT_BITS, %g0	! From Nucleus?
-	mov		1, %g5				! For TL==3 test
 from_tl1_trap:
+	rdpr		%tl, %g5			! For TL==3 test
 	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -38,97 +38,150 @@
  * range (note that this is only possible for instruction miss, data misses to
  * obp range do not use vpte). If so, go back directly to the faulting address.
  * This is because we want to read the tpc, otherwise we have no way of knowing
- * the 8k aligned faulting address if we are using >8k kernel pagesize. This also
- * ensures no vpte range addresses are dropped into tlb while obp is executing
- * (see inherit_locked_prom_mappings() rant).
+ * the 8k aligned faulting address if we are using >8k kernel pagesize. This
+ * also ensures no vpte range addresses are dropped into tlb while obp is
+ * executing (see inherit_locked_prom_mappings() rant).
  */
 sparc64_vpte_nucleus:
+	/* Load 0xf0000000, which is LOW_OBP_ADDRESS.  */
 	mov		0xf, %g5
-	sllx		%g5, 28, %g5			! Load 0xf0000000
-	cmp		%g4, %g5			! Is addr >= LOW_OBP_ADDRESS?
+	sllx		%g5, 28, %g5
+
+	/* Is addr >= LOW_OBP_ADDRESS?  */
+	cmp		%g4, %g5
 	blu,pn		%xcc, sparc64_vpte_patchme1
 	 mov		0x1, %g5
-	sllx		%g5, 32, %g5			! Load 0x100000000
-	cmp		%g4, %g5			! Is addr < HI_OBP_ADDRESS?
+
+	/* Load 0x100000000, which is HI_OBP_ADDRESS.  */
+	sllx		%g5, 32, %g5
+
+	/* Is addr < HI_OBP_ADDRESS?  */
+	cmp		%g4, %g5
 	blu,pn		%xcc, obp_iaddr_patch
 	 nop
+
+	/* These two instructions are patched by paginig_init().  */
 sparc64_vpte_patchme1:
-	sethi		%hi(0), %g5			! This has to be patched
+	sethi		%hi(0), %g5
 sparc64_vpte_patchme2:
-	or		%g5, %lo(0), %g5		! This is patched too
-	ba,pt		%xcc, sparc64_kpte_continue	! Part of dtlb_backend
-	 add		%g1, %g1, %g1			! Finish PMD offset adjustment
+	or		%g5, %lo(0), %g5
+
+	/* With kernel PGD in %g5, branch back into dtlb_backend.  */
+	ba,pt		%xcc, sparc64_kpte_continue
+	 andn		%g1, 0x3, %g1	/* Finish PMD offset adjustment.  */
 
 vpte_noent:
-	mov		TLB_SFSR, %g1			! Restore %g1 value
-	stxa		%g4, [%g1 + %g1] ASI_DMMU	! Restore previous TAG_ACCESS
-	done						! Slick trick
+	/* Restore previous TAG_ACCESS, %g5 is zero, and we will
+	 * skip over the trap instruction so that the top level
+	 * TLB miss handler will thing this %g5 value is just an
+	 * invalid PTE, thus branching to full fault processing.
+	 */
+	mov		TLB_SFSR, %g1
+	stxa		%g4, [%g1 + %g1] ASI_DMMU
+	done
 
 	.globl		obp_iaddr_patch
-	.globl		obp_daddr_patch
-
 obp_iaddr_patch:
-	sethi		%hi(0), %g5			! This and following is patched
-	or		%g5, %lo(0), %g5		! g5 now holds obp pmd base physaddr
-	wrpr		%g0, 1, %tl			! Behave as if we are at TL0
-	rdpr		%tpc, %g4			! Find original faulting iaddr
-	srlx		%g4, 13, %g4			! Throw out context bits
-	sllx		%g4, 13, %g4			! g4 has vpn + ctx0 now
-	mov		TLB_SFSR, %g1			! Restore %g1 value
-	stxa		%g4, [%g1 + %g1] ASI_IMMU	! Restore previous TAG_ACCESS
-	srlx		%g4, 23, %g6			! Find pmd number
-	and		%g6, 0x7ff, %g6			! Find pmd number
-	sllx		%g6, 2, %g6			! Find pmd offset
-	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pmd, ie pagetable physaddr
-	brz,pn		%g5, longpath			! Kill the PROM ? :-)
-	 sllx		%g5, 11, %g5			! Shift into place
-	srlx		%g4, 13, %g6			! find pte number in pagetable
-	and		%g6, 0x3ff, %g6			! find pte number in pagetable
-	sllx		%g6, 3, %g6			! find pte offset in pagetable
-	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pte
-	brgez,pn	%g5, longpath			! Kill the PROM ? :-)
+	/* These two instructions patched by inherit_prom_mappings().  */
+	sethi		%hi(0), %g5
+	or		%g5, %lo(0), %g5
+
+	/* Behave as if we are at TL0.  */
+	wrpr		%g0, 1, %tl
+	rdpr		%tpc, %g4	/* Find original faulting iaddr */
+	srlx		%g4, 13, %g4	/* Throw out context bits */
+	sllx		%g4, 13, %g4	/* g4 has vpn + ctx0 now */
+
+	/* Restore previous TAG_ACCESS.  */
+	mov		TLB_SFSR, %g1
+	stxa		%g4, [%g1 + %g1] ASI_IMMU
+
+	/* Get PMD offset.  */
+	srlx		%g4, 23, %g6
+	and		%g6, 0x7ff, %g6
+	sllx		%g6, 2, %g6
+
+	/* Load PMD, is it valid?  */
+	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
+	brz,pn		%g5, longpath
+	 sllx		%g5, 11, %g5
+
+	/* Get PTE offset.  */
+	srlx		%g4, 13, %g6
+	and		%g6, 0x3ff, %g6
+	sllx		%g6, 3, %g6
+
+	/* Load PTE.  */
+	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
+	brgez,pn	%g5, longpath
 	 nop
-	stxa		%g5, [%g0] ASI_ITLB_DATA_IN	! put into tlb
-	retry						! go back to original fault
 
+	/* TLB load and return from trap.  */
+	stxa		%g5, [%g0] ASI_ITLB_DATA_IN
+	retry
+
+	.globl		obp_daddr_patch
 obp_daddr_patch:
-	sethi		%hi(0), %g5			! This and following is patched
-	or		%g5, %lo(0), %g5		! g5 now holds obp pmd base physaddr
-	srlx		%g4, 23, %g6			! Find pmd number
-	and		%g6, 0x7ff, %g6			! Find pmd number
-	sllx		%g6, 2, %g6			! Find pmd offset
-	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pmd, ie pagetable physaddr
+	/* These two instructions patched by inherit_prom_mappings().  */
+	sethi		%hi(0), %g5
+	or		%g5, %lo(0), %g5
+
+	/* Get PMD offset.  */
+	srlx		%g4, 23, %g6
+	and		%g6, 0x7ff, %g6
+	sllx		%g6, 2, %g6
+
+	/* Load PMD, is it valid?  */
+	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
 	brz,pn		%g5, longpath
-	 sllx		%g5, 11, %g5			! Shift into place
-	srlx		%g4, 13, %g6			! find pte number in pagetable
-	and		%g6, 0x3ff, %g6			! find pte number in pagetable
-	sllx		%g6, 3, %g6			! find pte offset in pagetable
-	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pte
+	 sllx		%g5, 11, %g5
+
+	/* Get PTE offset.  */
+	srlx		%g4, 13, %g6
+	and		%g6, 0x3ff, %g6
+	sllx		%g6, 3, %g6
+
+	/* Load PTE.  */
+	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
 	brgez,pn	%g5, longpath
 	 nop
-	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! put into tlb
+
+	/* TLB load and return from trap.  */
+	stxa		%g5, [%g0] ASI_DTLB_DATA_IN
 	retry
 
 /*
- * On a first level data miss, check whether this is to the OBP range (note that
- * such accesses can be made by prom, as well as by kernel using prom_getproperty
- * on "address"), and if so, do not use vpte access ... rather, use information
- * saved during inherit_prom_mappings() using 8k pagesize.
+ * On a first level data miss, check whether this is to the OBP range (note
+ * that such accesses can be made by prom, as well as by kernel using
+ * prom_getproperty on "address"), and if so, do not use vpte access ...
+ * rather, use information saved during inherit_prom_mappings() using 8k
+ * pagesize.
  */
 kvmap:
+	/* Load 0xf0000000, which is LOW_OBP_ADDRESS.  */
 	mov		0xf, %g5
-	sllx		%g5, 28, %g5			! Load 0xf0000000
-	cmp		%g4, %g5			! Is addr >= LOW_OBP_ADDRESS?
+	sllx		%g5, 28, %g5
+
+	/* Is addr >= LOW_OBP_ADDRESS?  */
+	cmp		%g4, %g5
 	blu,pn		%xcc, vmalloc_addr
 	 mov		0x1, %g5
-	sllx		%g5, 32, %g5			! Load 0x100000000
-	cmp		%g4, %g5			! Is addr < HI_OBP_ADDRESS?
+
+	/* Load 0x100000000, which is HI_OBP_ADDRESS.  */
+	sllx		%g5, 32, %g5
+
+	/* Is addr < HI_OBP_ADDRESS?  */
+	cmp		%g4, %g5
 	blu,pn		%xcc, obp_daddr_patch
 	 nop
-vmalloc_addr:						! vmalloc addr accessed
-	ldxa		[%g3 + %g6] ASI_N, %g5		! Yep, load k-vpte
-	brgez,pn	%g5, longpath			! Valid, load into TLB
+
+vmalloc_addr:
+	/* If we get here, a vmalloc addr accessed, load kernel VPTE.  */
+	ldxa		[%g3 + %g6] ASI_N, %g5
+	brgez,pn	%g5, longpath
 	 nop
+
+	/* PTE is valid, load into TLB and return from trap.  */
 	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
 	retry
 
@@ -199,9 +252,11 @@ do_fpdis:
 	faddd		%f0, %f2, %f4
 	fmuld		%f0, %f2, %f6
 	ldxa		[%g3] ASI_DMMU, %g5
-	add		%g6, TI_FPREGS + 0xc0, %g2
-	stxa		%g0, [%g3] ASI_DMMU
+cplus_fptrap_insn_1:
+	sethi		%hi(0), %g2
+	stxa		%g2, [%g3] ASI_DMMU
 	membar		#Sync
+	add		%g6, TI_FPREGS + 0xc0, %g2
 	faddd		%f0, %f2, %f8
 	fmuld		%f0, %f2, %f10
 	ldda		[%g1] ASI_BLK_S, %f32	! grrr, where is ASI_BLK_NUCLEUS 8-(
@@ -225,7 +280,9 @@ do_fpdis:
 	fzero		%f34
 	ldxa		[%g3] ASI_DMMU, %g5
 	add		%g6, TI_FPREGS, %g1
-	stxa		%g0, [%g3] ASI_DMMU
+cplus_fptrap_insn_2:
+	sethi		%hi(0), %g2
+	stxa		%g2, [%g3] ASI_DMMU
 	membar		#Sync
 	add		%g6, TI_FPREGS + 0x40, %g2
 	faddd		%f32, %f34, %f36
@@ -249,9 +306,11 @@ do_fpdis:
 3:	mov		SECONDARY_CONTEXT, %g3
 	add		%g6, TI_FPREGS, %g1
 	ldxa		[%g3] ASI_DMMU, %g5
-	mov		0x40, %g2
-	stxa		%g0, [%g3] ASI_DMMU
+cplus_fptrap_insn_3:
+	sethi		%hi(0), %g2
+	stxa		%g2, [%g3] ASI_DMMU
 	membar		#Sync
+	mov		0x40, %g2
 	ldda		[%g1] ASI_BLK_S, %f0		! grrr, where is ASI_BLK_NUCLEUS 8-(
 	ldda		[%g1 + %g2] ASI_BLK_S, %f16
 	add		%g1, 0x80, %g1
@@ -412,10 +471,12 @@ do_fptrap_after_fsr:
 	rd		%gsr, %g3
 	stx		%g3, [%g6 + TI_GSR]
 	mov		SECONDARY_CONTEXT, %g3
-	add		%g6, TI_FPREGS, %g2
 	ldxa		[%g3] ASI_DMMU, %g5
-	stxa		%g0, [%g3] ASI_DMMU
+cplus_fptrap_insn_4:
+	sethi		%hi(0), %g2
+	stxa		%g2, [%g3] ASI_DMMU
 	membar		#Sync
+	add		%g6, TI_FPREGS, %g2
 	andcc		%g1, FPRS_DL, %g0
 	be,pn		%icc, 4f
 	 mov		0x40, %g3
@@ -433,6 +494,33 @@ do_fptrap_after_fsr:
 	ba,pt		%xcc, etrap
 	 wr		%g0, 0, %fprs
 
+cplus_fptrap_1:
+	sethi		%hi(CTX_CHEETAH_PLUS_CTX0), %g2
+
+	.globl		cheetah_plus_patch_fpdis
+cheetah_plus_patch_fpdis:
+	/* We configure the dTLB512_0 for 4MB pages and the
+	 * dTLB512_1 for 8K pages when in context zero.
+	 */
+	sethi			%hi(cplus_fptrap_1), %o0
+	lduw			[%o0 + %lo(cplus_fptrap_1)], %o1
+
+	set			cplus_fptrap_insn_1, %o2
+	stw			%o1, [%o2]
+	flush			%o2
+	set			cplus_fptrap_insn_2, %o2
+	stw			%o1, [%o2]
+	flush			%o2
+	set			cplus_fptrap_insn_3, %o2
+	stw			%o1, [%o2]
+	flush			%o2
+	set			cplus_fptrap_insn_4, %o2
+	stw			%o1, [%o2]
+	flush			%o2
+
+	retl
+	 nop
+
 	/* The registers for cross calls will be:
 	 *
 	 * DATA 0: [low 32-bits]  Address of function to call, jmp to this
@@ -1642,7 +1730,7 @@ ret_from_syscall:
 		andn		%o7, _TIF_NEWCHILD, %l0
 		stx		%l0, [%g6 + TI_FLAGS]
 		call		schedule_tail
-		 mov		%g5, %o0
+		 mov		%g7, %o0
 		andcc		%l0, _TIF_PERFCTR, %g0
 		be,pt		%icc, 1f
 		 nop
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -14,6 +14,7 @@
 #include <asm/spitfire.h>
 #include <asm/head.h>
 #include <asm/processor.h>
+#include <asm/mmu.h>
 
 #define		TASK_REGOFF		(THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ)
 #define		ETRAP_PSTATE1		(PSTATE_RMO | PSTATE_PRIV)
@@ -67,7 +68,13 @@ etrap_irq:
 
 		wrpr	%g3, 0, %otherwin
 		wrpr	%g2, 0, %wstate
-		stxa	%g0, [%l4] ASI_DMMU
+cplus_etrap_insn_1:
+		sethi	%hi(0), %g3
+		sllx	%g3, 32, %g3
+cplus_etrap_insn_2:
+		sethi	%hi(0), %g2
+		or	%g3, %g2, %g3
+		stxa	%g3, [%l4] ASI_DMMU
 		flush	%l6
 		wr	%g0, ASI_AIUS, %asi
 2:		wrpr	%g0, 0x0, %tl
@@ -95,11 +102,12 @@ etrap_irq:
 		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]
 		wrpr	%g0, ETRAP_PSTATE2, %pstate
 		mov	%l6, %g6
+#ifdef CONFIG_SMP
+		mov	TSB_REG, %g3
+		ldxa	[%g3] ASI_IMMU, %g5
+#endif
 		jmpl	%l2 + 0x4, %g0
 		 ldx	[%g6 + TI_TASK], %g4
-		nop
-		nop
-		nop
 
 3:		ldub	[%l6 + TI_FPDEPTH], %l5
 		add	%l6, TI_FPSAVED + 1, %l4
@@ -207,7 +215,13 @@ scetrap:	rdpr	%pil, %g2
 		mov	PRIMARY_CONTEXT, %l4
 		wrpr	%g3, 0, %otherwin
 		wrpr	%g2, 0, %wstate
-		stxa	%g0, [%l4] ASI_DMMU
+cplus_etrap_insn_3:
+		sethi	%hi(0), %g3
+		sllx	%g3, 32, %g3
+cplus_etrap_insn_4:
+		sethi	%hi(0), %g2
+		or	%g3, %g2, %g3
+		stxa	%g3, [%l4] ASI_DMMU
 		flush	%l6
 
 		mov	ASI_AIUS, %l7
@@ -241,11 +255,47 @@ scetrap:	rdpr	%pil, %g2
 		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]
 		mov	%l6, %g6
 		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]
+#ifdef CONFIG_SMP
+		mov	TSB_REG, %g3
+		ldxa	[%g3] ASI_IMMU, %g5
+#endif
 		ldx	[%g6 + TI_TASK], %g4
 		done
-		nop
-		nop
 
 #undef TASK_REGOFF
 #undef ETRAP_PSTATE1
-#undef ETRAP_PSTATE2
+
+cplus_einsn_1:
+		sethi			%uhi(CTX_CHEETAH_PLUS_NUC), %g3
+cplus_einsn_2:
+		sethi			%hi(CTX_CHEETAH_PLUS_CTX0), %g2
+
+		.globl			cheetah_plus_patch_etrap
+cheetah_plus_patch_etrap:
+		/* We configure the dTLB512_0 for 4MB pages and the
+		 * dTLB512_1 for 8K pages when in context zero.
+		 */
+		sethi			%hi(cplus_einsn_1), %o0
+		sethi			%hi(cplus_etrap_insn_1), %o2
+		lduw			[%o0 + %lo(cplus_einsn_1)], %o1
+		or			%o2, %lo(cplus_etrap_insn_1), %o2
+		stw			%o1, [%o2]
+		flush			%o2
+		sethi			%hi(cplus_etrap_insn_3), %o2
+		or			%o2, %lo(cplus_etrap_insn_3), %o2
+		stw			%o1, [%o2]
+		flush			%o2
+
+		sethi			%hi(cplus_einsn_2), %o0
+		sethi			%hi(cplus_etrap_insn_2), %o2
+		lduw			[%o0 + %lo(cplus_einsn_2)], %o1
+		or			%o2, %lo(cplus_etrap_insn_2), %o2
+		stw			%o1, [%o2]
+		flush			%o2
+		sethi			%hi(cplus_etrap_insn_4), %o2
+		or			%o2, %lo(cplus_etrap_insn_4), %o2
+		stw			%o1, [%o2]
+		flush			%o2
+
+		retl
+		 nop
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -25,6 +25,7 @@
 #include <asm/dcu.h>
 #include <asm/head.h>
 #include <asm/ttable.h>
+#include <asm/mmu.h>
 	
 /* This section from from _start to sparc64_boot_end should fit into
  * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
@@ -88,8 +89,8 @@ sparc_ramdisk_image64:
 	 * PROM entry point is on %o4
 	 */
 sparc64_boot:
-	BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_boot)
-	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_boot)
+	BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
 	ba,pt	%xcc, spitfire_boot
 	 nop
 
@@ -102,11 +103,11 @@ cheetah_boot:
 	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr	%g1, %asr18
 
-	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
+	sethi	%uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g7
+	or	%g7, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g7
+	sllx	%g7, 32, %g7
+	or	%g7, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g7
+	stxa	%g7, [%g0] ASI_DCU_CONTROL_REG
 	membar	#Sync
 
 cheetah_generic_boot:
@@ -491,7 +492,7 @@ sun4u_init:
 	stxa	%g3, [%g2] ASI_DMMU
 	membar	#Sync
 
-	BRANCH_IF_ANY_CHEETAH(g1,g5,cheetah_tlb_fixup)
+	BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup)
 
 	ba,pt	%xcc, spitfire_tlb_fixup
 	 nop
@@ -515,14 +516,31 @@ cheetah_tlb_fixup:
 	membar	#Sync
 
 	mov	2, %g2		/* Set TLB type to cheetah+. */
-	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g5,g7,1f)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
 
 	mov	1, %g2		/* Set TLB type to cheetah. */
 
-1:	sethi	%hi(tlb_type), %g5
-	stw	%g2, [%g5 + %lo(tlb_type)]
+1:	sethi	%hi(tlb_type), %g1
+	stw	%g2, [%g1 + %lo(tlb_type)]
 
-	/* Patch copy/page operations to cheetah optimized versions. */
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
+	ba,pt	%xcc, 2f
+	 nop
+
+1:	/* Patch context register writes to support nucleus page
+	 * size correctly.
+	 */
+	call	cheetah_plus_patch_etrap
+	 nop
+	call	cheetah_plus_patch_rtrap
+	 nop
+	call	cheetah_plus_patch_fpdis
+	 nop
+	call	cheetah_plus_patch_winfixup
+	 nop
+	
+
+2:	/* Patch copy/page operations to cheetah optimized versions. */
 	call	cheetah_patch_copyops
 	 nop
 	call	cheetah_patch_cachetlbops
@@ -549,8 +567,8 @@ spitfire_tlb_fixup:
 
 	/* Set TLB type to spitfire. */
 	mov	0, %g2
-	sethi	%hi(tlb_type), %g5
-	stw	%g2, [%g5 + %lo(tlb_type)]
+	sethi	%hi(tlb_type), %g1
+	stw	%g2, [%g1 + %lo(tlb_type)]
 
 tlb_fixup_done:
 	sethi	%hi(init_thread_union), %g6
@@ -578,12 +596,18 @@ tlb_fixup_done:
 #endif
 
 	wr	%g0, ASI_P, %asi
-	mov	1, %g5
-	sllx	%g5, THREAD_SHIFT, %g5
-	sub	%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
-	add	%g6, %g5, %sp
+	mov	1, %g1
+	sllx	%g1, THREAD_SHIFT, %g1
+	sub	%g1, (STACKFRAME_SZ + STACK_BIAS), %g1
+	add	%g6, %g1, %sp
 	mov	0, %fp
 
+	/* Set per-cpu pointer initially to zero, this makes
+	 * the boot-cpu use the in-kernel-image per-cpu areas
+	 * before setup_per_cpu_area() is invoked.
+	 */
+	clr	%g5
+
 	wrpr	%g0, 0, %wstate
 	wrpr	%g0, 0x0, %tl
 
@@ -619,8 +643,8 @@ setup_tba:	/* i0 = is_starfire */
 	rdpr	%pstate, %o1
 	mov	%g6, %o2
 	wrpr	%o1, (PSTATE_AG|PSTATE_IE), %pstate
-	sethi	%hi(sparc64_ttable_tl0), %g5
-	wrpr	%g5, %tba
+	sethi	%hi(sparc64_ttable_tl0), %g1
+	wrpr	%g1, %tba
 	mov	%o2, %g6
 
 	/* Set up MMU globals */
@@ -633,6 +657,8 @@ setup_tba:	/* i0 = is_starfire */
 	mov	TSB_REG, %g1
 	stxa	%g0, [%g1] ASI_DMMU
 	membar	#Sync
+	stxa	%g0, [%g1] ASI_IMMU
+	membar	#Sync
 	mov	TLB_SFSR, %g1
 	sethi	%uhi(KERN_HIGHBITS), %g2
 	or	%g2, %ulo(KERN_HIGHBITS), %g2
@@ -685,10 +711,23 @@ spitfire_vpte_base:
 	call	init_irqwork_curcpu
 	 nop
 
-	sethi	%hi(sparc64_ttable_tl0), %g5
 	call	prom_set_trap_table
-	 mov	%g5, %o0
+	 sethi	%hi(sparc64_ttable_tl0), %o0
+
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g2,g3,1f)
+	ba,pt	%xcc, 2f
+	 nop
 
+1:	/* Start using proper page size encodings in ctx register.  */
+	sethi	%uhi(CTX_CHEETAH_PLUS_NUC), %g3
+	mov	PRIMARY_CONTEXT, %g1
+	sllx	%g3, 32, %g3
+	sethi	%hi(CTX_CHEETAH_PLUS_CTX0), %g2
+	or	%g3, %g2, %g3
+	stxa	%g3, [%g1] ASI_DMMU
+	membar	#Sync
+
+2:
 	rdpr	%pstate, %o1
 	or	%o1, PSTATE_IE, %o1
 	wrpr	%o1, 0, %pstate
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -475,7 +475,6 @@ IOCTL_TABLE_START
 #include <linux/compat_ioctl.h>
 #define DECLARES
 #include "compat_ioctl.c"
-COMPATIBLE_IOCTL(TCSBRKP)
 COMPATIBLE_IOCTL(TIOCSTART)
 COMPATIBLE_IOCTL(TIOCSTOP)
 COMPATIBLE_IOCTL(TIOCSLTC)
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -756,7 +756,7 @@ void handler_irq(int irq, struct pt_regs
 		clear_softint(clr_mask);
 	}
 #else
-	int should_forward = 1;
+	int should_forward = 0;
 
 	clear_softint(1 << irq);
 #endif
@@ -1007,10 +1007,10 @@ static int retarget_one_irq(struct irqac
 	}
 	upa_writel(tid | IMAP_VALID, imap);
 
-	while (!cpu_online(goal_cpu)) {
+	do {
 		if (++goal_cpu >= NR_CPUS)
 			goal_cpu = 0;
-	}
+	} while (!cpu_online(goal_cpu));
 
 	return goal_cpu;
 }
@@ -1112,7 +1112,7 @@ void enable_prom_timer(void)
 void init_irqwork_curcpu(void)
 {
 	register struct irq_work_struct *workp asm("o2");
-	unsigned long tmp;
+	register unsigned long tmp asm("o3");
 	int cpu = hard_smp_processor_id();
 
 	memset(__irq_work + cpu, 0, sizeof(*workp));
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -68,8 +68,14 @@ static inline void prepare_singlestep(st
 	current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
 	regs->tstate |= TSTATE_PIL;
 
-	regs->tpc = (unsigned long) &p->ainsn.insn[0];
-	regs->tnpc = (unsigned long) &p->ainsn.insn[1];
+	/*single step inline, if it a breakpoint instruction*/
+	if (p->opcode == BREAKPOINT_INSTRUCTION) {
+		regs->tpc = (unsigned long) p->addr;
+		regs->tnpc = current_kprobe_orig_tnpc;
+	} else {
+		regs->tpc = (unsigned long) &p->ainsn.insn[0];
+		regs->tnpc = (unsigned long) &p->ainsn.insn[1];
+	}
 }
 
 static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
@@ -97,6 +103,12 @@ static int kprobe_handler(struct pt_regs
 		 */
 		p = get_kprobe(addr);
 		if (p) {
+			if (kprobe_status == KPROBE_HIT_SS) {
+				regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+					current_kprobe_orig_tstate_pil);
+				unlock_kprobes();
+				goto no_kprobe;
+			}
 			disarm_kprobe(p, regs);
 			ret = 1;
 		} else {
@@ -128,7 +140,7 @@ static int kprobe_handler(struct pt_regs
 
 	kprobe_status = KPROBE_HIT_ACTIVE;
 	current_kprobe = p;
-	if (p->pre_handler(p, regs))
+	if (p->pre_handler && p->pre_handler(p, regs))
 		return 1;
 
 ss_probe:
diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c
--- a/arch/sparc64/kernel/module.c
+++ b/arch/sparc64/kernel/module.c
@@ -17,108 +17,19 @@
 #include <asm/processor.h>
 #include <asm/spitfire.h>
 
-static struct vm_struct * modvmlist = NULL;
-
-static void module_unmap(void * addr)
-{
-	struct vm_struct **p, *tmp;
-	int i;
-
-	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) != NULL; p = &tmp->next) {
-		if (tmp->addr == addr) {
-			*p = tmp->next;
-			goto found;
-		}
-	}
-	printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
-	return;
-
-found:
-	unmap_vm_area(tmp);
-	
-	for (i = 0; i < tmp->nr_pages; i++) {
-		if (unlikely(!tmp->pages[i]))
-			BUG();
-		__free_page(tmp->pages[i]);
-	}
-
-	kfree(tmp->pages);
-	kfree(tmp);
-}
-
-
 static void *module_map(unsigned long size)
 {
-	struct vm_struct **p, *tmp, *area;
-	struct page **pages;
-	void * addr;
-	unsigned int nr_pages, array_size, i;
+	struct vm_struct *area;
 
 	size = PAGE_ALIGN(size);
 	if (!size || size > MODULES_LEN)
 		return NULL;
-		
-	addr = (void *) MODULES_VADDR;
-	for (p = &modvmlist; (tmp = *p) != NULL; 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);
+
+	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
 	if (!area)
 		return NULL;
-	area->size = size + PAGE_SIZE;
-	area->addr = addr;
-	area->next = *p;
-	area->pages = NULL;
-	area->nr_pages = 0;
-	area->phys_addr = 0;
-	*p = area;
-
-	nr_pages = size >> PAGE_SHIFT;
-	array_size = (nr_pages * sizeof(struct page *));
-
-	area->nr_pages = nr_pages;
-	area->pages = pages = kmalloc(array_size, GFP_KERNEL);
-	if (!area->pages)
-		goto fail;
-
-	memset(area->pages, 0, array_size);
-
-	for (i = 0; i < area->nr_pages; i++) {
-		area->pages[i] = alloc_page(GFP_KERNEL);
-		if (unlikely(!area->pages[i]))
-			goto fail;
-	}
-	
-	if (map_vm_area(area, PAGE_KERNEL, &pages)) {
-		unmap_vm_area(area);
-		goto fail;
-	}
-
-	return area->addr;
-
-fail:
-	if (area->pages) {
-		for (i = 0; i < area->nr_pages; i++) {
-			if (area->pages[i])
-				__free_page(area->pages[i]);
-		}
-		kfree(area->pages);
-	}
-	kfree(area);
 
-	return NULL;
+	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
 }
 
 void *module_alloc(unsigned long size)
@@ -141,9 +52,7 @@ void *module_alloc(unsigned long size)
 /* Free memory returned from module_core_alloc/module_init_alloc */
 void module_free(struct module *mod, void *module_region)
 {
-	write_lock(&vmlist_lock);
-	module_unmap(module_region);
-	write_unlock(&vmlist_lock);
+	vfree(module_region);
 	/* FIXME: If module_region == mod->init_region, trim exception
            table entries. */
 }
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -18,6 +18,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/pbm.h>
+#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/ebus.h>
 #include <asm/isa.h>
@@ -734,12 +735,10 @@ static void __pci_mmap_set_flags(struct 
 static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
 					     enum pci_mmap_state mmap_state)
 {
-	/* Our io_remap_page_range takes care of this, do nothing. */
+	/* Our io_remap_page_range/io_remap_pfn_range takes care of this,
+	   do nothing. */
 }
 
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
-			       unsigned long size, pgprot_t prot, int space);
-
 /* Perform the actual remap of the pages for a PCI device mapping, as appropriate
  * for this architecture.  The region in the process to map is described by vm_start
  * and vm_end members of VMA, the base physical address is found in vm_pgoff.
@@ -761,10 +760,10 @@ int pci_mmap_page_range(struct pci_dev *
 	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state);
 
-	ret = io_remap_page_range(vma, vma->vm_start,
-				  (vma->vm_pgoff << PAGE_SHIFT |
-				   (write_combine ? 0x1UL : 0x0UL)),
-				  vma->vm_end - vma->vm_start, vma->vm_page_prot, 0);
+	ret = io_remap_pfn_range(vma, vma->vm_start,
+				 vma->vm_pgoff,
+				 vma->vm_end - vma->vm_start,
+				 vma->vm_page_prot);
 	if (ret)
 		return ret;
 
@@ -794,12 +793,6 @@ int pci_domain_nr(struct pci_bus *pbus)
 }
 EXPORT_SYMBOL(pci_domain_nr);
 
-int pci_name_bus(char *name, struct pci_bus *bus)
-{
-	sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
-	return 0;
-}
-
 int pcibios_prep_mwi(struct pci_dev *dev)
 {
 	/* We set correct PCI_CACHE_LINE_SIZE register values for every
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/pbm.h>
 
@@ -195,6 +196,34 @@ static iopte_t *alloc_consistent_cluster
 	return NULL;
 }
 
+static int iommu_alloc_ctx(struct pci_iommu *iommu)
+{
+	int lowest = iommu->ctx_lowest_free;
+	int sz = IOMMU_NUM_CTXS - lowest;
+	int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
+
+	if (unlikely(n == sz)) {
+		n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
+		if (unlikely(n == lowest)) {
+			printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
+			n = 0;
+		}
+	}
+	if (n)
+		__set_bit(n, iommu->ctx_bitmap);
+
+	return n;
+}
+
+static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
+{
+	if (likely(ctx)) {
+		__clear_bit(ctx, iommu->ctx_bitmap);
+		if (ctx < iommu->ctx_lowest_free)
+			iommu->ctx_lowest_free = ctx;
+	}
+}
+
 /* Allocate and map kernel buffer of size SIZE using consistent mode
  * DMA for PCI device PDEV.  Return non-NULL cpu-side address if
  * successful and set *DMA_ADDRP to the PCI side dma address.
@@ -235,7 +264,7 @@ void *pci_alloc_consistent(struct pci_de
 	npages = size >> IO_PAGE_SHIFT;
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
-		ctx = iommu->iommu_cur_ctx++;
+		ctx = iommu_alloc_ctx(iommu);
 	first_page = __pa(first_page);
 	while (npages--) {
 		iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) |
@@ -316,6 +345,8 @@ void pci_free_consistent(struct pci_dev 
 		}
 	}
 
+	iommu_free_ctx(iommu, ctx);
+
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
 	order = get_order(size);
@@ -359,7 +390,7 @@ dma_addr_t pci_map_single(struct pci_dev
 	base_paddr = __pa(oaddr & IO_PAGE_MASK);
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
-		ctx = iommu->iommu_cur_ctx++;
+		ctx = iommu_alloc_ctx(iommu);
 	if (strbuf->strbuf_enabled)
 		iopte_protection = IOPTE_STREAMING(ctx);
 	else
@@ -379,6 +410,70 @@ bad:
 	return PCI_DMA_ERROR_CODE;
 }
 
+static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
+{
+	int limit;
+
+	if (strbuf->strbuf_ctxflush &&
+	    iommu->iommu_ctxflush) {
+		unsigned long matchreg, flushreg;
+		u64 val;
+
+		flushreg = strbuf->strbuf_ctxflush;
+		matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+
+		pci_iommu_write(flushreg, ctx);
+		val = pci_iommu_read(matchreg);
+		val &= 0xffff;
+		if (!val)
+			goto do_flush_sync;
+
+		while (val) {
+			if (val & 0x1)
+				pci_iommu_write(flushreg, ctx);
+			val >>= 1;
+		}
+		val = pci_iommu_read(matchreg);
+		if (unlikely(val)) {
+			printk(KERN_WARNING "pci_strbuf_flush: ctx flush "
+			       "timeout matchreg[%lx] ctx[%lx]\n",
+			       val, ctx);
+			goto do_page_flush;
+		}
+	} else {
+		unsigned long i;
+
+	do_page_flush:
+		for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
+			pci_iommu_write(strbuf->strbuf_pflush, vaddr);
+	}
+
+do_flush_sync:
+	/* If the device could not have possibly put dirty data into
+	 * the streaming cache, no flush-flag synchronization needs
+	 * to be performed.
+	 */
+	if (direction == PCI_DMA_TODEVICE)
+		return;
+
+	PCI_STC_FLUSHFLAG_INIT(strbuf);
+	pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+	(void) pci_iommu_read(iommu->write_complete_reg);
+
+	limit = 100000;
+	while (!PCI_STC_FLUSHFLAG_SET(strbuf)) {
+		limit--;
+		if (!limit)
+			break;
+		udelay(1);
+		membar("#LoadLoad");
+	}
+	if (!limit)
+		printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout "
+		       "vaddr[%08x] ctx[%lx] npages[%ld]\n",
+		       vaddr, ctx, npages);
+}
+
 /* Unmap a single streaming mode DMA translation. */
 void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
@@ -386,7 +481,7 @@ void pci_unmap_single(struct pci_dev *pd
 	struct pci_iommu *iommu;
 	struct pci_strbuf *strbuf;
 	iopte_t *base;
-	unsigned long flags, npages, i, ctx;
+	unsigned long flags, npages, ctx;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
@@ -414,29 +509,8 @@ void pci_unmap_single(struct pci_dev *pd
 		ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
 
 	/* Step 1: Kick data out of streaming buffers if necessary. */
-	if (strbuf->strbuf_enabled) {
-		u32 vaddr = bus_addr;
-
-		PCI_STC_FLUSHFLAG_INIT(strbuf);
-		if (strbuf->strbuf_ctxflush &&
-		    iommu->iommu_ctxflush) {
-			unsigned long matchreg, flushreg;
-
-			flushreg = strbuf->strbuf_ctxflush;
-			matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
-			do {
-				pci_iommu_write(flushreg, ctx);
-			} while(((long)pci_iommu_read(matchreg)) < 0L);
-		} else {
-			for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
-				pci_iommu_write(strbuf->strbuf_pflush, vaddr);
-		}
-
-		pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
-		(void) pci_iommu_read(iommu->write_complete_reg);
-		while (!PCI_STC_FLUSHFLAG_SET(strbuf))
-			membar("#LoadLoad");
-	}
+	if (strbuf->strbuf_enabled)
+		pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
 
 	/* Step 2: Clear out first TSB entry. */
 	iopte_make_dummy(iommu, base);
@@ -444,6 +518,8 @@ void pci_unmap_single(struct pci_dev *pd
 	free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
 			       npages, ctx);
 
+	iommu_free_ctx(iommu, ctx);
+
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -583,7 +659,7 @@ int pci_map_sg(struct pci_dev *pdev, str
 	/* Step 4: Choose a context if necessary. */
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
-		ctx = iommu->iommu_cur_ctx++;
+		ctx = iommu_alloc_ctx(iommu);
 
 	/* Step 5: Create the mappings. */
 	if (strbuf->strbuf_enabled)
@@ -647,29 +723,8 @@ void pci_unmap_sg(struct pci_dev *pdev, 
 		ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
 
 	/* Step 1: Kick data out of streaming buffers if necessary. */
-	if (strbuf->strbuf_enabled) {
-		u32 vaddr = (u32) bus_addr;
-
-		PCI_STC_FLUSHFLAG_INIT(strbuf);
-		if (strbuf->strbuf_ctxflush &&
-		    iommu->iommu_ctxflush) {
-			unsigned long matchreg, flushreg;
-
-			flushreg = strbuf->strbuf_ctxflush;
-			matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
-			do {
-				pci_iommu_write(flushreg, ctx);
-			} while(((long)pci_iommu_read(matchreg)) < 0L);
-		} else {
-			for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
-				pci_iommu_write(strbuf->strbuf_pflush, vaddr);
-		}
-
-		pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
-		(void) pci_iommu_read(iommu->write_complete_reg);
-		while (!PCI_STC_FLUSHFLAG_SET(strbuf))
-			membar("#LoadLoad");
-	}
+	if (strbuf->strbuf_enabled)
+		pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
 
 	/* Step 2: Clear out first TSB entry. */
 	iopte_make_dummy(iommu, base);
@@ -677,6 +732,8 @@ void pci_unmap_sg(struct pci_dev *pdev, 
 	free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
 			       npages, ctx);
 
+	iommu_free_ctx(iommu, ctx);
+
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -715,28 +772,7 @@ void pci_dma_sync_single_for_cpu(struct 
 	}
 
 	/* Step 2: Kick data out of streaming buffers. */
-	PCI_STC_FLUSHFLAG_INIT(strbuf);
-	if (iommu->iommu_ctxflush &&
-	    strbuf->strbuf_ctxflush) {
-		unsigned long matchreg, flushreg;
-
-		flushreg = strbuf->strbuf_ctxflush;
-		matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
-		do {
-			pci_iommu_write(flushreg, ctx);
-		} while(((long)pci_iommu_read(matchreg)) < 0L);
-	} else {
-		unsigned long i;
-
-		for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE)
-			pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
-	}
-
-	/* Step 3: Perform flush synchronization sequence. */
-	pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
-	(void) pci_iommu_read(iommu->write_complete_reg);
-	while (!PCI_STC_FLUSHFLAG_SET(strbuf))
-		membar("#LoadLoad");
+	pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
 
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
@@ -749,7 +785,8 @@ void pci_dma_sync_sg_for_cpu(struct pci_
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
 	struct pci_strbuf *strbuf;
-	unsigned long flags, ctx;
+	unsigned long flags, ctx, npages, i;
+	u32 bus_addr;
 
 	pcp = pdev->sysdata;
 	iommu = pcp->pbm->iommu;
@@ -772,36 +809,14 @@ void pci_dma_sync_sg_for_cpu(struct pci_
 	}
 
 	/* Step 2: Kick data out of streaming buffers. */
-	PCI_STC_FLUSHFLAG_INIT(strbuf);
-	if (iommu->iommu_ctxflush &&
-	    strbuf->strbuf_ctxflush) {
-		unsigned long matchreg, flushreg;
-
-		flushreg = strbuf->strbuf_ctxflush;
-		matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
-		do {
-			pci_iommu_write(flushreg, ctx);
-		} while (((long)pci_iommu_read(matchreg)) < 0L);
-	} else {
-		unsigned long i, npages;
-		u32 bus_addr;
-
-		bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
-
-		for(i = 1; i < nelems; i++)
-			if (!sglist[i].dma_length)
-				break;
-		i--;
-		npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT;
-		for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE)
-			pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
-	}
-
-	/* Step 3: Perform flush synchronization sequence. */
-	pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
-	(void) pci_iommu_read(iommu->write_complete_reg);
-	while (!PCI_STC_FLUSHFLAG_SET(strbuf))
-		membar("#LoadLoad");
+	bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
+	for(i = 1; i < nelems; i++)
+		if (!sglist[i].dma_length)
+			break;
+	i--;
+	npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
+		  - bus_addr) >> IO_PAGE_SHIFT;
+	pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
 
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1133,7 +1133,7 @@ static void __init psycho_base_address_u
 	       (((u32)(res->start - root->start)) & ~size));
 	if (resource == PCI_ROM_RESOURCE) {
 		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 	}
 	pci_write_config_dword(pdev, where, reg);
 
@@ -1212,7 +1212,7 @@ static void __init psycho_iommu_init(str
 
 	/* Setup initial software IOMMU state. */
 	spin_lock_init(&iommu->lock);
-	iommu->iommu_cur_ctx = 0;
+	iommu->ctx_lowest_free = 1;
 
 	/* Register addresses. */
 	iommu->iommu_control  = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1100,7 +1100,7 @@ static void __init sabre_base_address_up
 	       (((u32)(res->start - base)) & ~size));
 	if (resource == PCI_ROM_RESOURCE) {
 		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 	}
 	pci_write_config_dword(pdev, where, reg);
 
@@ -1265,7 +1265,7 @@ static void __init sabre_iommu_init(stru
 
 	/* Setup initial software IOMMU state. */
 	spin_lock_init(&iommu->lock);
-	iommu->iommu_cur_ctx = 0;
+	iommu->ctx_lowest_free = 1;
 
 	/* Register addresses. */
 	iommu->iommu_control  = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -326,9 +326,9 @@ static int __init schizo_ino_to_pil(stru
 	return ret;
 }
 
-static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
-					    struct pci_dev *pdev,
-					    unsigned int ino)
+static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
+				     struct pci_dev *pdev,
+				     unsigned int ino)
 {
 	struct ino_bucket *bucket;
 	unsigned long imap, iclr;
@@ -382,19 +382,57 @@ static unsigned long stc_error_buf[128];
 static unsigned long stc_tag_buf[16];
 static unsigned long stc_line_buf[16];
 
-/* These offsets look weird because I keep in pbm->controller_regs
- * the second PROM register property minus 0x10000 which is the
- * base of the Safari and UPA64S registers of SCHIZO.
- */
-#define SCHIZO_PBM_A_REGS_OFF	(0x600000UL - 0x400000UL)
-#define SCHIZO_PBM_B_REGS_OFF	(0x700000UL - 0x400000UL)
+#define SCHIZO_UE_INO		0x30 /* Uncorrectable ECC error */
+#define SCHIZO_CE_INO		0x31 /* Correctable ECC error */
+#define SCHIZO_PCIERR_A_INO	0x32 /* PBM A PCI bus error */
+#define SCHIZO_PCIERR_B_INO	0x33 /* PBM B PCI bus error */
+#define SCHIZO_SERR_INO		0x34 /* Safari interface error */
+
+struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
+{
+	ino &= IMAP_INO;
+	if (p->pbm_A.ino_bitmap & (1UL << ino))
+		return &p->pbm_A;
+	if (p->pbm_B.ino_bitmap & (1UL << ino))
+		return &p->pbm_B;
+
+	printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
+	       "PBM_A[%016lx] PBM_B[%016lx]",
+	       p->index, ino,
+	       p->pbm_A.ino_bitmap,
+	       p->pbm_B.ino_bitmap);
+	printk("PCI%d: Using PBM_A, report this problem immediately.\n",
+	       p->index);
+
+	return &p->pbm_A;
+}
 
-static void schizo_clear_other_err_intr(int irq)
+static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
 {
-	struct ino_bucket *bucket = __bucket(irq);
-	unsigned long iclr = bucket->iclr;
+	struct pci_pbm_info *pbm;
+	struct ino_bucket *bucket;
+	unsigned long iclr;
+
+	/* Do not clear the interrupt for the other PCI bus.
+	 *
+	 * This "ACK both PBM IRQs" only needs to be performed
+	 * for chip-wide error interrupts.
+	 */
+	if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO ||
+	    (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO)
+		return;
+
+	pbm = pbm_for_ino(p, irq);
+	if (pbm == &p->pbm_A)
+		pbm = &p->pbm_B;
+	else
+		pbm = &p->pbm_A;
+
+	irq = schizo_irq_build(pbm, NULL,
+			       (pbm->portid << 6) | (irq & IMAP_INO));
+	bucket = __bucket(irq);
+	iclr = bucket->iclr;
 
-	iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF);
 	upa_writel(ICLR_IDLE, iclr);
 }
 
@@ -728,7 +766,7 @@ static irqreturn_t schizo_ue_intr(int ir
 	/* Interrogate IOMMU for error status. */
 	schizo_check_iommu_error(p, UE_ERR);
 
-	schizo_clear_other_err_intr(irq);
+	schizo_clear_other_err_intr(p, irq);
 
 	return IRQ_HANDLED;
 }
@@ -819,7 +857,7 @@ static irqreturn_t schizo_ce_intr(int ir
 		printk("(none)");
 	printk("]\n");
 
-	schizo_clear_other_err_intr(irq);
+	schizo_clear_other_err_intr(p, irq);
 
 	return IRQ_HANDLED;
 }
@@ -856,9 +894,9 @@ static irqreturn_t schizo_ce_intr(int ir
 #define SCHIZO_PCICTRL_SBH_ERR	(1UL << 35UL) /* Safari */
 #define SCHIZO_PCICTRL_SERR	(1UL << 34UL) /* Safari/Tomatillo */
 #define SCHIZO_PCICTRL_PCISPD	(1UL << 33UL) /* Safari */
-#define SCHIZO_PCICTRL_MRM_PREF	(1UL << 28UL) /* Tomatillo */
-#define SCHIZO_PCICTRL_RDO_PREF	(1UL << 27UL) /* Tomatillo */
-#define SCHIZO_PCICTRL_RDL_PREF	(1UL << 26UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_MRM_PREF	(1UL << 30UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDO_PREF	(1UL << 29UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDL_PREF	(1UL << 28UL) /* Tomatillo */
 #define SCHIZO_PCICTRL_PTO	(3UL << 24UL) /* Safari/Tomatillo */
 #define SCHIZO_PCICTRL_PTO_SHIFT 24UL
 #define SCHIZO_PCICTRL_TRWSW	(7UL << 21UL) /* Tomatillo */
@@ -1040,7 +1078,7 @@ static irqreturn_t schizo_pcierr_intr(in
 	if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
 		pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
 
-	schizo_clear_other_err_intr(irq);
+	schizo_clear_other_err_intr(p, irq);
 
 	return IRQ_HANDLED;
 }
@@ -1097,7 +1135,7 @@ static irqreturn_t schizo_safarierr_intr
 		printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
 		       p->index, errlog);
 
-		schizo_clear_other_err_intr(irq);
+		schizo_clear_other_err_intr(p, irq);
 		return IRQ_HANDLED;
 	}
 
@@ -1105,7 +1143,7 @@ static irqreturn_t schizo_safarierr_intr
 	       p->index);
 	schizo_check_iommu_error(p, SAFARI_ERR);
 
-	schizo_clear_other_err_intr(irq);
+	schizo_clear_other_err_intr(p, irq);
 	return IRQ_HANDLED;
 }
 
@@ -1120,26 +1158,6 @@ static irqreturn_t schizo_safarierr_intr
 #define SCHIZO_SAFARI_IRQCTRL	0x10010UL
 #define  SCHIZO_SAFIRQCTRL_EN	 0x8000000000000000UL
 
-#define SCHIZO_UE_INO		0x30 /* Uncorrectable ECC error */
-#define SCHIZO_CE_INO		0x31 /* Correctable ECC error */
-#define SCHIZO_PCIERR_A_INO	0x32 /* PBM A PCI bus error */
-#define SCHIZO_PCIERR_B_INO	0x33 /* PBM B PCI bus error */
-#define SCHIZO_SERR_INO		0x34 /* Safari interface error */
-
-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
-{
-	ino &= IMAP_INO;
-	if (p->pbm_A.ino_bitmap & (1UL << ino))
-		return &p->pbm_A;
-	if (p->pbm_B.ino_bitmap & (1UL << ino))
-		return &p->pbm_B;
-	prom_printf("TOMATILLO%d: No entry in ino bitmap for %d\n",
-		    p->index, ino);
-	prom_halt();
-	/* NOTREACHED */
-	return NULL;
-}
-
 /* How the Tomatillo IRQs are routed around is pure guesswork here.
  *
  * All the Tomatillo devices I see in prtconf dumps seem to have only
@@ -1554,7 +1572,7 @@ static void __init schizo_base_address_u
 	       (((u32)(res->start - root->start)) & ~size));
 	if (resource == PCI_ROM_RESOURCE) {
 		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
 	}
 	pci_write_config_dword(pdev, where, reg);
 
@@ -1735,7 +1753,7 @@ static void schizo_pbm_iommu_init(struct
 
 	/* Setup initial software IOMMU state. */
 	spin_lock_init(&iommu->lock);
-	iommu->iommu_cur_ctx = 0;
+	iommu->ctx_lowest_free = 1;
 
 	/* Register addresses, SCHIZO has iommu ctx flushing. */
 	iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1887,7 +1905,7 @@ static void __init schizo_pbm_hw_init(st
 
 	tmp &= ~SCHIZO_PCICTRL_PTO;
 	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
-	    pbm->chip_version == 0x2)
+	    pbm->chip_version >= 0x2)
 		tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 	else
 		tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
@@ -1895,8 +1913,16 @@ static void __init schizo_pbm_hw_init(st
 	if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
 		tmp |= SCHIZO_PCICTRL_PARK;
 
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
+	    pbm->chip_version <= 0x1)
+		tmp |= (1UL << 61);
+	else
+		tmp &= ~(1UL << 61);
+
 	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
-		tmp |= SCHIZO_PCICTRL_MRM_PREF;
+		tmp |= (SCHIZO_PCICTRL_MRM_PREF |
+			SCHIZO_PCICTRL_RDO_PREF |
+			SCHIZO_PCICTRL_RDL_PREF);
 
 	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -62,9 +62,6 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
-	if (current->pid != 0)
-		return;
-
 	/* endless idle loop with no priority at all */
 	for (;;) {
 		/* If current->work.need_resched is zero we should really
@@ -80,7 +77,6 @@ void cpu_idle(void)
 		schedule();
 		check_pgt_cache();
 	}
-	return;
 }
 
 #else
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -19,6 +19,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
@@ -103,6 +104,55 @@ void ptrace_disable(struct task_struct *
 	/* nothing to do */
 }
 
+/* To get the necessary page struct, access_process_vm() first calls
+ * get_user_pages().  This has done a flush_dcache_page() on the
+ * accessed page.  Then our caller (copy_{to,from}_user_page()) did
+ * to memcpy to read/write the data from that page.
+ *
+ * Now, the only thing we have to do is:
+ * 1) flush the D-cache if it's possible than an illegal alias
+ *    has been created
+ * 2) flush the I-cache if this is pre-cheetah and we did a write
+ */
+void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
+			 unsigned long uaddr, void *kaddr,
+			 unsigned long len, int write)
+{
+	BUG_ON(len > PAGE_SIZE);
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+	/* If bit 13 of the kernel address we used to access the
+	 * user page is the same as the virtual address that page
+	 * is mapped to in the user's address space, we can skip the
+	 * D-cache flush.
+	 */
+	if ((uaddr ^ kaddr) & (1UL << 13)) {
+		unsigned long start = __pa(kaddr);
+		unsigned long end = start + len;
+
+		if (tlb_type == spitfire) {
+			for (; start < end; start += 32)
+				spitfire_put_dcache_tag(va & 0x3fe0, 0x0);
+		} else {
+			for (; start < end; start += 32)
+				__asm__ __volatile__(
+					"stxa %%g0, [%0] %1\n\t"
+					"membar #Sync"
+					: /* no outputs */
+					: "r" (va),
+					"i" (ASI_DCACHE_INVALIDATE));
+		}
+	}
+#endif
+	if (write && tlb_type == spitfire) {
+		unsigned long start = (unsigned long) kaddr;
+		unsigned long end = start + len;
+
+		for (; start < end; start += 32)
+			flushi(start);
+	}
+}
+
 asmlinkage void do_ptrace(struct pt_regs *regs)
 {
 	int request = regs->u_regs[UREG_I0];
@@ -227,7 +277,7 @@ asmlinkage void do_ptrace(struct pt_regs
 			pt_error_return(regs, -res);
 		else
 			pt_os_succ_return(regs, tmp64, (void __user *) data);
-		goto flush_and_out;
+		goto out_tsk;
 	}
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
@@ -253,7 +303,7 @@ asmlinkage void do_ptrace(struct pt_regs
 			pt_error_return(regs, -res);
 		else
 			pt_succ_return(regs, res);
-		goto flush_and_out;
+		goto out_tsk;
 	}
 
 	case PTRACE_GETREGS: {
@@ -485,12 +535,12 @@ asmlinkage void do_ptrace(struct pt_regs
 					  (char __user *)addr2, data);
 		if (res == data) {
 			pt_succ_return(regs, 0);
-			goto flush_and_out;
+			goto out_tsk;
 		}
 		if (res >= 0)
 			res = -EIO;
 		pt_error_return(regs, -res);
-		goto flush_and_out;
+		goto out_tsk;
 	}
 
 	case PTRACE_WRITETEXT:
@@ -499,40 +549,21 @@ asmlinkage void do_ptrace(struct pt_regs
 					   addr, data);
 		if (res == data) {
 			pt_succ_return(regs, 0);
-			goto flush_and_out;
+			goto out_tsk;
 		}
 		if (res >= 0)
 			res = -EIO;
 		pt_error_return(regs, -res);
-		goto flush_and_out;
+		goto out_tsk;
 	}
 	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
 		addr = 1;
 
 	case PTRACE_CONT: { /* restart after signal. */
-		if (data > _NSIG) {
+		if (!valid_signal(data)) {
 			pt_error_return(regs, EIO);
 			goto out_tsk;
 		}
-		if (addr != 1) {
-			unsigned long pc_mask = ~0UL;
-
-			if ((child->thread_info->flags & _TIF_32BIT) != 0)
-				pc_mask = 0xffffffff;
-
-			if (addr & 3) {
-				pt_error_return(regs, EINVAL);
-				goto out_tsk;
-			}
-#ifdef DEBUG_PTRACE
-			printk ("Original: %016lx %016lx\n",
-				child->thread_info->kregs->tpc,
-				child->thread_info->kregs->tnpc);
-			printk ("Continuing with %016lx %016lx\n", addr, addr+4);
-#endif
-			child->thread_info->kregs->tpc = (addr & pc_mask);
-			child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask);
-		}
 
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -590,27 +621,6 @@ asmlinkage void do_ptrace(struct pt_regs
 		goto out_tsk;
 	}
 	}
-flush_and_out:
-	{
-		unsigned long va;
-
-		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. */
-		} else {
-			for (va =  0; va < L1DCACHE_SIZE; va += 32)
-				spitfire_put_dcache_tag(va, 0x0);
-			if (request == PTRACE_PEEKTEXT ||
-			    request == PTRACE_POKETEXT ||
-			    request == PTRACE_READTEXT ||
-			    request == PTRACE_WRITETEXT) {
-				for (va =  0; va < (PAGE_SIZE << 1); va += 32)
-					spitfire_put_icache_tag(va, 0x0);
-				__asm__ __volatile__("flush %g6");
-			}
-		}
-	}
 out_tsk:
 	if (child)
 		put_task_struct(child);
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -223,7 +223,10 @@ rt_continue:	ldx			[%sp + PTREGS_OFF + P
 		ldx			[%sp + PTREGS_OFF + PT_V9_G3], %g3
 		ldx			[%sp + PTREGS_OFF + PT_V9_G4], %g4
 		ldx			[%sp + PTREGS_OFF + PT_V9_G5], %g5
-		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
+		mov			TSB_REG, %g6
+		brnz,a,pn		%l3, 1f
+		 ldxa			[%g6] ASI_IMMU, %g5
+1:		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G7], %g7
 		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
 		ldx			[%sp + PTREGS_OFF + PT_V9_I0], %i0
@@ -250,6 +253,10 @@ rt_continue:	ldx			[%sp + PTREGS_OFF + P
 		brnz,pn			%l3, kern_rtt
 		 mov			PRIMARY_CONTEXT, %l7
 		ldxa			[%l7 + %l7] ASI_DMMU, %l0
+cplus_rtrap_insn_1:
+		sethi			%hi(0), %l1
+		sllx			%l1, 32, %l1
+		or			%l0, %l1, %l0
 		stxa			%l0, [%l7] ASI_DMMU
 		flush			%g6
 		rdpr			%wstate, %l1
@@ -298,10 +305,10 @@ kern_fpucheck:	ldub			[%g6 + TI_FPDEPTH]
 		andcc			%l2, FPRS_FEF, %g0
 		be,pn			%icc, 5f
 		 sll			%o0, 3, %o5
-		rd			%fprs, %g5
+		rd			%fprs, %g1
 
-		wr			%g5, FPRS_FEF, %fprs
-		ldx			[%o1 + %o5], %g5
+		wr			%g1, FPRS_FEF, %fprs
+		ldx			[%o1 + %o5], %g1
 		add			%g6, TI_XFSR, %o1
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
@@ -313,7 +320,7 @@ kern_fpucheck:	ldub			[%g6 + TI_FPDEPTH]
 		ldda			[%o4 + %o2] ASI_BLK_P, %f16
 1:		andcc			%l2, FPRS_DU, %g0
 		be,pn			%icc, 1f
-		 wr			%g5, 0, %gsr
+		 wr			%g1, 0, %gsr
 		add			%o2, 0x80, %o2
 		ldda			[%o3 + %o2] ASI_BLK_P, %f32
 		ldda			[%o4 + %o2] ASI_BLK_P, %f48
@@ -335,3 +342,21 @@ kern_fpucheck:	ldub			[%g6 + TI_FPDEPTH]
 		wr			%g0, FPRS_DU, %fprs
 		ba,pt			%xcc, rt_continue
 		 stb			%l5, [%g6 + TI_FPDEPTH]
+
+cplus_rinsn_1:
+		sethi			%uhi(CTX_CHEETAH_PLUS_NUC), %l1
+
+		.globl			cheetah_plus_patch_rtrap
+cheetah_plus_patch_rtrap:
+		/* We configure the dTLB512_0 for 4MB pages and the
+		 * dTLB512_1 for 8K pages when in context zero.
+		 */
+		sethi			%hi(cplus_rinsn_1), %o0
+		sethi			%hi(cplus_rtrap_insn_1), %o2
+		lduw			[%o0 + %lo(cplus_rinsn_1)], %o1
+		or			%o2, %lo(cplus_rtrap_insn_1), %o2
+		stw			%o1, [%o2]
+		flush			%o2
+
+		retl
+		 nop
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -117,19 +117,42 @@ static void iommu_flush(struct sbus_iomm
 
 #define STRBUF_TAG_VALID	0x02UL
 
-static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction)
 {
-	iommu->strbuf_flushflag = 0UL;
-	while (npages--)
-		upa_writeq(base + (npages << IO_PAGE_SHIFT),
+	unsigned long n;
+	int limit;
+
+	n = npages;
+	while (n--)
+		upa_writeq(base + (n << IO_PAGE_SHIFT),
 			   iommu->strbuf_regs + STRBUF_PFLUSH);
 
+	/* If the device could not have possibly put dirty data into
+	 * the streaming cache, no flush-flag synchronization needs
+	 * to be performed.
+	 */
+	if (direction == SBUS_DMA_TODEVICE)
+		return;
+
+	iommu->strbuf_flushflag = 0UL;
+
 	/* Whoopee cushion! */
 	upa_writeq(__pa(&iommu->strbuf_flushflag),
 		   iommu->strbuf_regs + STRBUF_FSYNC);
 	upa_readq(iommu->sbus_control_reg);
-	while (iommu->strbuf_flushflag == 0UL)
+
+	limit = 100000;
+	while (iommu->strbuf_flushflag == 0UL) {
+		limit--;
+		if (!limit)
+			break;
+		udelay(1);
 		membar("#LoadLoad");
+	}
+	if (!limit)
+		printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout "
+		       "vaddr[%08x] npages[%ld]\n",
+		       base, npages);
 }
 
 static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
@@ -406,7 +429,7 @@ void sbus_unmap_single(struct sbus_dev *
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);
-	strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT);
+	sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -569,7 +592,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev
 	iommu = sdev->bus->iommu;
 	spin_lock_irqsave(&iommu->lock, flags);
 	free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);
-	strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT);
+	sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -581,7 +604,7 @@ void sbus_dma_sync_single_for_cpu(struct
 	size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT);
+	sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -605,7 +628,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbu
 	size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT);
+	sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
--- a/arch/sparc64/kernel/semaphore.c
+++ b/arch/sparc64/kernel/semaphore.c
@@ -65,30 +65,25 @@ void up(struct semaphore *sem)
 	__asm__ __volatile__("\n"
 "	! up sem(%0)\n"
 "	membar	#StoreLoad | #LoadLoad\n"
-"1:	lduw	[%0], %%g5\n"
-"	add	%%g5, 1, %%g7\n"
-"	cas	[%0], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
+"1:	lduw	[%0], %%g1\n"
+"	add	%%g1, 1, %%g7\n"
+"	cas	[%0], %%g1, %%g7\n"
+"	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 addcc	%%g7, 1, %%g0\n"
 "	ble,pn	%%icc, 3f\n"
 "	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
-"3:	mov	%0, %%g5\n"
+"3:	mov	%0, %%g1\n"
 "	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
 "	call	%1\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
+"	 mov	%%g1, %%o0\n"
 "	ba,pt	%%xcc, 2b\n"
-"	 restore %%l3, %%g0, %%g3\n"
+"	 restore\n"
 "	.previous\n"
 	: : "r" (sem), "i" (__up)
-	: "g5", "g7", "memory", "cc");
+	: "g1", "g2", "g3", "g7", "memory", "cc");
 }
 
 static void __sched __down(struct semaphore * sem)
@@ -127,30 +122,25 @@ void __sched down(struct semaphore *sem)
 
 	__asm__ __volatile__("\n"
 "	! down sem(%0)\n"
-"1:	lduw	[%0], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cas	[%0], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
+"1:	lduw	[%0], %%g1\n"
+"	sub	%%g1, 1, %%g7\n"
+"	cas	[%0], %%g1, %%g7\n"
+"	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
 "	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
-"3:	mov	%0, %%g5\n"
+"3:	mov	%0, %%g1\n"
 "	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
 "	call	%1\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
+"	 mov	%%g1, %%o0\n"
 "	ba,pt	%%xcc, 2b\n"
-"	 restore %%l3, %%g0, %%g3\n"
+"	 restore\n"
 "	.previous\n"
 	: : "r" (sem), "i" (__down)
-	: "g5", "g7", "memory", "cc");
+	: "g1", "g2", "g3", "g7", "memory", "cc");
 }
 
 int down_trylock(struct semaphore *sem)
@@ -175,20 +165,20 @@ int down_trylock(struct semaphore *sem)
 
 	__asm__ __volatile__("\n"
 "	! down_trylock sem(%1) ret(%0)\n"
-"1:	lduw	[%1], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cmp	%%g5, 1\n"
+"1:	lduw	[%1], %%g1\n"
+"	sub	%%g1, 1, %%g7\n"
+"	cmp	%%g1, 1\n"
 "	bl,pn	%%icc, 2f\n"
 "	 mov	1, %0\n"
-"	cas	[%1], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
+"	cas	[%1], %%g1, %%g7\n"
+"	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 mov	0, %0\n"
 "	membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 	: "=&r" (ret)
 	: "r" (sem)
-	: "g5", "g7", "memory", "cc");
+	: "g1", "g7", "memory", "cc");
 
 	return ret;
 }
@@ -237,31 +227,25 @@ int __sched down_interruptible(struct se
 
 	__asm__ __volatile__("\n"
 "	! down_interruptible sem(%2) ret(%0)\n"
-"1:	lduw	[%2], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cas	[%2], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
+"1:	lduw	[%2], %%g1\n"
+"	sub	%%g1, 1, %%g7\n"
+"	cas	[%2], %%g1, %%g7\n"
+"	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
 "	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
-"3:	mov	%2, %%g5\n"
+"3:	mov	%2, %%g1\n"
 "	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
 "	call	%3\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
-"	mov	%%l3, %%g3\n"
+"	 mov	%%g1, %%o0\n"
 "	ba,pt	%%xcc, 2b\n"
-"	 restore %%o0, %%g0, %0\n"
+"	 restore\n"
 "	.previous\n"
 	: "=r" (ret)
 	: "0" (ret), "r" (sem), "i" (__down_interruptible)
-	: "g5", "g7", "memory", "cc");
+	: "g1", "g2", "g3", "g7", "memory", "cc");
 	return ret;
 }
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -47,6 +47,7 @@
 #include <asm/timer.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
+#include <asm/mmu.h>
 
 #ifdef CONFIG_IP_PNP
 #include <net/ipconfig.h>
@@ -157,11 +158,11 @@ int prom_callback(long *args)
 
 			for_each_process(p) {
 				mm = p->mm;
-				if (CTX_HWBITS(mm->context) == ctx)
+				if (CTX_NRBITS(mm->context) == ctx)
 					break;
 			}
 			if (!mm ||
-			    CTX_HWBITS(mm->context) != ctx)
+			    CTX_NRBITS(mm->context) != ctx)
 				goto done;
 
 			pgdp = pgd_offset(mm, va);
@@ -187,12 +188,19 @@ int prom_callback(long *args)
 		}
 
 		if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+			unsigned long kernel_pctx = 0;
+
+			if (tlb_type == cheetah_plus)
+				kernel_pctx |= (CTX_CHEETAH_PLUS_NUC |
+						CTX_CHEETAH_PLUS_CTX0);
+
 			/* Spitfire Errata #32 workaround */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+					     : "r" (kernel_pctx),
+					       "r" (PRIMARY_CONTEXT),
+					       "i" (ASI_DMMU));
 
 			/*
 			 * Locked down tlb entry.
@@ -375,6 +383,17 @@ static void __init process_switch(char c
 		/* Use PROM debug console. */
 		register_console(&prom_debug_console);
 		break;
+	case 'P':
+		/* Force UltraSPARC-III P-Cache on. */
+		if (tlb_type != cheetah) {
+			printk("BOOT: Ignoring P-Cache force option.\n");
+			break;
+		}
+		cheetah_pcache_forced_on = 1;
+		add_taint(TAINT_MACHINE_CHECK);
+		cheetah_enable_pcache();
+		break;
+
 	default:
 		printk("Unknown boot switch (-%c)\n", c);
 		break;
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -53,7 +53,7 @@ asmlinkage void sparc64_set_context(stru
 	flush_user_windows();
 	if (get_thread_wsaved()					||
 	    (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
-	    (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
+	    (!__access_ok(ucp, sizeof(*ucp))))
 		goto do_sigsegv;
 	grp  = &ucp->uc_mcontext.mc_gregs;
 	err  = __get_user(pc, &((*grp)[MC_PC]));
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -104,7 +104,7 @@ typedef struct compat_siginfo{
 		struct {
 			timer_t _tid;			/* timer id */
 			int _overrun;			/* overrun count */
-			sigval_t32 _sigval;		/* same as below */
+			compat_sigval_t _sigval;		/* same as below */
 			int _sys_private;		/* not to be passed to user */
 		} _timer;
 
@@ -112,7 +112,7 @@ typedef struct compat_siginfo{
 		struct {
 			compat_pid_t _pid;		/* sender's pid */
 			unsigned int _uid;		/* sender's uid */
-			sigval_t32 _sigval;
+			compat_sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -192,10 +192,13 @@ int copy_siginfo_to_user32(compat_siginf
 			err |= __put_user(from->si_uid, &to->si_uid);
 			break;
 		case __SI_FAULT >> 16:
-		case __SI_POLL >> 16:
 			err |= __put_user(from->si_trapno, &to->si_trapno);
 			err |= __put_user((unsigned 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 >> 16: /* This is not generated by the kernel as of now.  */
 		case __SI_MESGQ >> 16:
 			err |= __put_user(from->si_pid, &to->si_pid);
@@ -351,7 +354,7 @@ void do_new_sigreturn32(struct pt_regs *
 	sf = (struct new_signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (verify_area(VERIFY_READ, sf, sizeof(*sf))	||
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
 	    (((unsigned long) sf) & 3))
 		goto segv;
 
@@ -436,7 +439,7 @@ asmlinkage void do_sigreturn32(struct pt
 	scptr = (struct sigcontext32 __user *)
 		(regs->u_regs[UREG_I0] & 0x00000000ffffffffUL);
 	/* Check sanity of the user arg. */
-	if (verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
+	if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
 	    (((unsigned long) scptr) & 3))
 		goto segv;
 
@@ -504,7 +507,7 @@ asmlinkage void do_rt_sigreturn32(struct
 	sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (verify_area(VERIFY_READ, sf, sizeof(*sf))	||
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
 	    (((unsigned long) sf) & 3))
 		goto segv;
 
@@ -1102,7 +1105,7 @@ asmlinkage int svr4_setcontext(svr4_ucon
 		goto sigsegv;
 	}
 
-	if (!__access_ok((unsigned long)c, sizeof(*c))) {
+	if (!__access_ok(c, sizeof(*c))) {
 		/* Miguel, add nice debugging msg _here_. ;-) */
 		goto sigsegv;
 	}
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -3,6 +3,7 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -20,6 +21,7 @@
 #include <linux/cache.h>
 #include <linux/jiffies.h>
 #include <linux/profile.h>
+#include <linux/bootmem.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -89,7 +91,6 @@ void __init smp_store_cpu_info(int id)
 	cpu_data(id).pgcache_size		= 0;
 	cpu_data(id).pte_cache[0]		= NULL;
 	cpu_data(id).pte_cache[1]		= NULL;
-	cpu_data(id).pgdcache_size		= 0;
 	cpu_data(id).pgd_cache			= NULL;
 	cpu_data(id).idle_volume		= 1;
 }
@@ -100,6 +101,16 @@ static volatile unsigned long callin_fla
 
 extern void inherit_locked_prom_mappings(int save_p);
 
+static inline void cpu_setup_percpu_base(unsigned long cpu_id)
+{
+	__asm__ __volatile__("mov	%0, %%g5\n\t"
+			     "stxa	%0, [%1] %2\n\t"
+			     "membar	#Sync"
+			     : /* no outputs */
+			     : "r" (__per_cpu_offset(cpu_id)),
+			       "r" (TSB_REG), "i" (ASI_IMMU));
+}
+
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
@@ -108,8 +119,13 @@ void __init smp_callin(void)
 
 	__flush_tlb_all();
 
+	cpu_setup_percpu_base(cpuid);
+
 	smp_setup_percpu_timer();
 
+	if (cheetah_pcache_forced_on)
+		cheetah_enable_pcache();
+
 	local_irq_enable();
 
 	calibrate_delay();
@@ -627,7 +643,10 @@ extern unsigned long xcall_flush_tlb_all
 extern unsigned long xcall_flush_tlb_all_cheetah;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
+
+#ifdef DCACHE_ALIASING_POSSIBLE
 extern unsigned long xcall_flush_dcache_page_cheetah;
+#endif
 extern unsigned long xcall_flush_dcache_page_spitfire;
 
 #ifdef CONFIG_DEBUG_DCFLUSH
@@ -637,7 +656,7 @@ extern atomic_t dcpage_flushes_xcall;
 
 static __inline__ void __local_flush_dcache_page(struct page *page)
 {
-#if (L1DCACHE_SIZE > PAGE_SIZE)
+#ifdef DCACHE_ALIASING_POSSIBLE
 	__flush_dcache_page(page_address(page),
 			    ((tlb_type == spitfire) &&
 			     page_mapping(page) != NULL));
@@ -672,11 +691,13 @@ void smp_flush_dcache_page_impl(struct p
 					       (u64) pg_addr,
 					       mask);
 		} else {
+#ifdef DCACHE_ALIASING_POSSIBLE
 			data0 =
 				((u64)&xcall_flush_dcache_page_cheetah);
 			cheetah_xcall_deliver(data0,
 					      __pa(pg_addr),
 					      0, mask);
+#endif
 		}
 #ifdef CONFIG_DEBUG_DCFLUSH
 		atomic_inc(&dcpage_flushes_xcall);
@@ -709,10 +730,12 @@ void flush_dcache_page_all(struct mm_str
 				       (u64) pg_addr,
 				       mask);
 	} else {
+#ifdef DCACHE_ALIASING_POSSIBLE
 		data0 = ((u64)&xcall_flush_dcache_page_cheetah);
 		cheetah_xcall_deliver(data0,
 				      __pa(pg_addr),
 				      0, mask);
+#endif
 	}
 #ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes_xcall);
@@ -1055,95 +1078,6 @@ void __init smp_tick_init(void)
 	prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
 }
 
-cycles_t cacheflush_time;
-unsigned long cache_decay_ticks;
-
-extern unsigned long cheetah_tune_scheduling(void);
-
-static void __init smp_tune_scheduling(void)
-{
-	unsigned long orig_flush_base, flush_base, flags, *p;
-	unsigned int ecache_size, order;
-	cycles_t tick1, tick2, raw;
-	int cpu_node;
-
-	/* Approximate heuristic for SMP scheduling.  It is an
-	 * estimation of the time it takes to flush the L2 cache
-	 * on the local processor.
-	 *
-	 * The ia32 chooses to use the L1 cache flush time instead,
-	 * and I consider this complete nonsense.  The Ultra can service
-	 * a miss to the L1 with a hit to the L2 in 7 or 8 cycles, and
-	 * L2 misses are what create extra bus traffic (ie. the "cost"
-	 * of moving a process from one cpu to another).
-	 */
-	printk("SMP: Calibrating ecache flush... ");
-	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		cacheflush_time = cheetah_tune_scheduling();
-		goto report;
-	}
-
-	cpu_find_by_instance(0, &cpu_node, NULL);
-	ecache_size = prom_getintdefault(cpu_node,
-					 "ecache-size", (512 * 1024));
-	if (ecache_size > (4 * 1024 * 1024))
-		ecache_size = (4 * 1024 * 1024);
-	orig_flush_base = flush_base =
-		__get_free_pages(GFP_KERNEL, order = get_order(ecache_size));
-
-	if (flush_base != 0UL) {
-		local_irq_save(flags);
-
-		/* Scan twice the size once just to get the TLB entries
-		 * loaded and make sure the second scan measures pure misses.
-		 */
-		for (p = (unsigned long *)flush_base;
-		     ((unsigned long)p) < (flush_base + (ecache_size<<1));
-		     p += (64 / sizeof(unsigned long)))
-			*((volatile unsigned long *)p);
-
-		tick1 = tick_ops->get_tick();
-
-		__asm__ __volatile__("1:\n\t"
-				     "ldx	[%0 + 0x000], %%g1\n\t"
-				     "ldx	[%0 + 0x040], %%g2\n\t"
-				     "ldx	[%0 + 0x080], %%g3\n\t"
-				     "ldx	[%0 + 0x0c0], %%g5\n\t"
-				     "add	%0, 0x100, %0\n\t"
-				     "cmp	%0, %2\n\t"
-				     "bne,pt	%%xcc, 1b\n\t"
-				     " nop"
-				     : "=&r" (flush_base)
-				     : "0" (flush_base),
-				       "r" (flush_base + ecache_size)
-				     : "g1", "g2", "g3", "g5");
-
-		tick2 = tick_ops->get_tick();
-
-		local_irq_restore(flags);
-
-		raw = (tick2 - tick1);
-
-		/* Dampen it a little, considering two processes
-		 * sharing the cache and fitting.
-		 */
-		cacheflush_time = (raw - (raw >> 2));
-
-		free_pages(orig_flush_base, order);
-	} else {
-		cacheflush_time = ((ecache_size << 2) +
-				   (ecache_size << 1));
-	}
-report:
-	/* Convert ticks/sticks to jiffies. */
-	cache_decay_ticks = cacheflush_time / timer_tick_offset;
-	if (cache_decay_ticks < 1)
-		cache_decay_ticks = 1;
-
-	printk("Using heuristic of %ld cycles, %ld ticks.\n",
-	       cacheflush_time, cache_decay_ticks);
-}
-
 /* /proc/profile writes can call this, don't __init it please. */
 static DEFINE_SPINLOCK(prof_setup_lock);
 
@@ -1198,6 +1132,7 @@ void __devinit smp_prepare_boot_cpu(void
 	}
 
 	current_thread_info()->cpu = hard_smp_processor_id();
+
 	cpu_set(smp_processor_id(), cpu_online_map);
 	cpu_set(smp_processor_id(), phys_cpu_present_map);
 }
@@ -1233,11 +1168,6 @@ void __init smp_cpus_done(unsigned int m
 	       (long) num_online_cpus(),
 	       bogosum/(500000/HZ),
 	       (bogosum/(5000/HZ))%100);
-
-	/* We want to run this with all the other cpus spinning
-	 * in the kernel.
-	 */
-	smp_tune_scheduling();
 }
 
 /* This needn't do anything as we do not sleep the cpu
@@ -1263,3 +1193,55 @@ void smp_send_stop(void)
 {
 }
 
+unsigned long __per_cpu_base;
+unsigned long __per_cpu_shift;
+
+EXPORT_SYMBOL(__per_cpu_base);
+EXPORT_SYMBOL(__per_cpu_shift);
+
+void __init setup_per_cpu_areas(void)
+{
+	unsigned long goal, size, i;
+	char *ptr;
+	/* Created by linker magic */
+	extern char __per_cpu_start[], __per_cpu_end[];
+
+	/* Copy section for each CPU (we discard the original) */
+	goal = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
+
+#ifdef CONFIG_MODULES
+	if (goal < PERCPU_ENOUGH_ROOM)
+		goal = PERCPU_ENOUGH_ROOM;
+#endif
+	__per_cpu_shift = 0;
+	for (size = 1UL; size < goal; size <<= 1UL)
+		__per_cpu_shift++;
+
+	/* Make sure the resulting __per_cpu_base value
+	 * will fit in the 43-bit sign extended IMMU
+	 * TSB register.
+	 */
+	ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE,
+			      (unsigned long) __per_cpu_start);
+
+	__per_cpu_base = ptr - __per_cpu_start;
+
+	if ((__per_cpu_shift < PAGE_SHIFT) ||
+	    (__per_cpu_base & ~PAGE_MASK) ||
+	    (__per_cpu_base != (((long) __per_cpu_base << 20) >> 20))) {
+		prom_printf("PER_CPU: Invalid layout, "
+			    "ptr[%p] shift[%lx] base[%lx]\n",
+			    ptr, __per_cpu_shift, __per_cpu_base);
+		prom_halt();
+	}
+
+	for (i = 0; i < NR_CPUS; i++, ptr += size)
+		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+
+	/* Finally, load in the boot cpu's base value.
+	 * We abuse the IMMU TSB register for trap handler
+	 * entry and exit loading of %g5.  That is why it
+	 * has to be page aligned.
+	 */
+	cpu_setup_percpu_base(hard_smp_processor_id());
+}
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -59,6 +59,7 @@
 #include <asm/ns87303.h>
 #include <asm/timer.h>
 #include <asm/cpudata.h>
+#include <asm/rwsem.h>
 
 struct poll {
 	int fd;
@@ -87,7 +88,10 @@ extern int svr4_setcontext(svr4_ucontext
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char __user * filename, int flags, int mode);
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
+	unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+	unsigned long pfn, unsigned long size, pgprot_t prot);
 extern void (*prom_palette)(int);
 
 extern int __ashrdi3(int, int);
@@ -171,6 +175,15 @@ EXPORT_SYMBOL(down_trylock);
 EXPORT_SYMBOL(down_interruptible);
 EXPORT_SYMBOL(up);
 
+/* RW semaphores */
+EXPORT_SYMBOL(__down_read);
+EXPORT_SYMBOL(__down_read_trylock);
+EXPORT_SYMBOL(__down_write);
+EXPORT_SYMBOL(__down_write_trylock);
+EXPORT_SYMBOL(__up_read);
+EXPORT_SYMBOL(__up_write);
+EXPORT_SYMBOL(__downgrade_write);
+
 /* Atomic counter implementation. */
 EXPORT_SYMBOL(atomic_add);
 EXPORT_SYMBOL(atomic_add_ret);
@@ -206,8 +219,11 @@ EXPORT_SYMBOL(__flushw_user);
 EXPORT_SYMBOL(tlb_type);
 EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
+
 EXPORT_SYMBOL(flush_dcache_page);
+#ifdef DCACHE_ALIASING_POSSIBLE
 EXPORT_SYMBOL(__flush_dcache_range);
+#endif
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
@@ -254,6 +270,7 @@ EXPORT_SYMBOL(pci_dma_supported);
 
 /* I/O device mmaping on Sparc64. */
 EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(io_remap_pfn_range);
 
 /* Solaris/SunOS binary compatibility */
 EXPORT_SYMBOL(_sigpause_common);
@@ -261,7 +278,7 @@ EXPORT_SYMBOL(verify_compat_iovec);
 
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(__pte_alloc_one_kernel);
+EXPORT_SYMBOL(pte_alloc_one_kernel);
 #ifndef CONFIG_SMP
 EXPORT_SYMBOL(pgt_quicklists);
 #endif
@@ -346,7 +363,9 @@ EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(memchr);
 
 EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_sparc64);
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(__csum_partial_copy_from_user);
+EXPORT_SYMBOL(__csum_partial_copy_to_user);
 EXPORT_SYMBOL(ip_fast_csum);
 
 /* Moving data to/from/in userspace. */
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -264,11 +264,11 @@ asmlinkage long compat_sys_ipc(u32 call,
 
 	switch (call) {
 	case SEMTIMEDOP:
-		if (third)
+		if (fifth)
 			/* sign extend semid */
 			return compat_sys_semtimedop((int)first,
 						     compat_ptr(ptr), second,
-						     compat_ptr(third));
+						     compat_ptr(fifth));
 		/* else fall through for normal semop() */
 	case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
@@ -352,11 +352,11 @@ int cp_compat_stat(struct kstat *stat, s
 	err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
 	err |= put_user(stat->size, &statbuf->st_size);
 	err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
-	err |= put_user(0, &statbuf->__unused1);
+	err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
 	err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
-	err |= put_user(0, &statbuf->__unused2);
+	err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
 	err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
-	err |= put_user(0, &statbuf->__unused3);
+	err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
 	err |= put_user(stat->blksize, &statbuf->st_blksize);
 	err |= put_user(stat->blocks, &statbuf->st_blocks);
 	err |= put_user(0, &statbuf->__unused4[0]);
@@ -365,6 +365,68 @@ int cp_compat_stat(struct kstat *stat, s
 	return err;
 }
 
+int cp_compat_stat64(struct kstat *stat, struct compat_stat64 __user *statbuf)
+{
+	int err;
+
+	err  = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
+	err |= put_user(stat->ino, &statbuf->st_ino);
+	err |= put_user(stat->mode, &statbuf->st_mode);
+	err |= put_user(stat->nlink, &statbuf->st_nlink);
+	err |= put_user(stat->uid, &statbuf->st_uid);
+	err |= put_user(stat->gid, &statbuf->st_gid);
+	err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
+	err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
+	err |= put_user(stat->size, &statbuf->st_size);
+	err |= put_user(stat->blksize, &statbuf->st_blksize);
+	err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
+	err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
+	err |= put_user(stat->blocks, &statbuf->st_blocks);
+	err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
+	err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
+	err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
+	err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
+	err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
+	err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
+	err |= put_user(0, &statbuf->__unused4);
+	err |= put_user(0, &statbuf->__unused5);
+
+	return err;
+}
+
+asmlinkage long compat_sys_stat64(char __user * filename,
+		struct compat_stat64 __user *statbuf)
+{
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_compat_stat64(&stat, statbuf);
+	return error;
+}
+
+asmlinkage long compat_sys_lstat64(char __user * filename,
+		struct compat_stat64 __user *statbuf)
+{
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+
+	if (!error)
+		error = cp_compat_stat64(&stat, statbuf);
+	return error;
+}
+
+asmlinkage long compat_sys_fstat64(unsigned int fd,
+		struct compat_stat64 __user * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
+
+	if (!error)
+		error = cp_compat_stat64(&stat, statbuf);
+	return error;
+}
+
 asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
 {
 	return sys_sysfs(option, arg1, arg2);
@@ -1087,7 +1149,7 @@ sys_timer_create(clockid_t which_clock,
 		 timer_t __user *created_timer_id);
 
 long
-sys32_timer_create(u32 clock, struct sigevent32 __user *se32,
+sys32_timer_create(u32 clock, struct compat_sigevent __user *se32,
 		   timer_t __user *timer_id)
 {
 	struct sigevent se;
@@ -1098,12 +1160,7 @@ sys32_timer_create(u32 clock, struct sig
 	if (se32 == NULL)
 		return sys_timer_create(clock, NULL, timer_id);
 
-	memset(&se, 0, sizeof(struct sigevent));
-	if (get_user(se.sigev_value.sival_int,  &se32->sigev_value.sival_int) ||
-	    __get_user(se.sigev_signo, &se32->sigev_signo) ||
-	    __get_user(se.sigev_notify, &se32->sigev_notify) ||
-	    __copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad,
-	    sizeof(se._sigev_un._pad)))
+	if (get_compat_sigevent(&se, se32))
 		return -EFAULT;
 
 	if (!access_ok(VERIFY_WRITE,timer_id,sizeof(timer_t)))
@@ -1121,34 +1178,3 @@ sys32_timer_create(u32 clock, struct sig
 
 	return err;
 }
-
-asmlinkage long compat_sys_waitid(u32 which, u32 pid,
-				  struct compat_siginfo __user *uinfo,
-				  u32 options, struct compat_rusage __user *uru)
-{
-	siginfo_t info;
-	struct rusage ru;
-	long ret;
-	mm_segment_t old_fs = get_fs();
-
-	memset(&info, 0, sizeof(info));
-
-	set_fs (KERNEL_DS);
-	ret = sys_waitid(which, pid, (siginfo_t __user *) &info,
-			 options,
-			 uru ? (struct rusage __user *) &ru : NULL);
-	set_fs (old_fs);
-
-	if (ret < 0 || info.si_signo == 0)
-		return ret;
-
-	if (uru) {
-		ret = put_compat_rusage(&ru, uru);
-		if (ret)
-			return ret;
-	}
-
-	BUG_ON(info.si_code & __SI_MASK);
-	info.si_code |= __SI_CHLD;
-	return copy_siginfo_to_user32(uinfo, &info);
-}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -32,7 +32,7 @@ sys_call_table32:
 	.word sys32_umount, sys32_setgid16, sys32_getgid16, sys32_signal, sys32_geteuid16
 /*50*/	.word sys32_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl
 	.word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve
-/*60*/	.word sys32_umask, sys_chroot, compat_sys_newfstat, sys_fstat64, sys_getpagesize
+/*60*/	.word sys32_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize
 	.word sys32_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid
 /*70*/	.word sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect
 	.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16
@@ -46,8 +46,8 @@ sys_call_table32:
 	.word sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
-/*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-	.word sys_nis_syscall, sys32_mkdir, sys_rmdir, sys32_utimes, sys_stat64
+/*130*/	.word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys32_mkdir, sys_rmdir, sys32_utimes, compat_sys_stat64
 /*140*/	.word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
 	.word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
@@ -75,7 +75,7 @@ sys_call_table32:
 /*260*/	.word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
 	.word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
 /*270*/	.word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink
-	.word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid
+	.word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid
 /*280*/	.word sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl
 
 #endif /* CONFIG_COMPAT */
@@ -98,7 +98,7 @@ sys_call_table:
 	.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/	.word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
 	.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/	.word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+/*60*/	.word sys_umask, sys_chroot, sys_newfstat, sys_stat64, sys_getpagesize
 	.word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall
 /*70*/	.word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect
 	.word sys_madvise, sys_vhangup, sys_nis_syscall, sys_mincore, sys_getgroups
@@ -112,8 +112,8 @@ sys_call_table:
 	.word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
 /*120*/	.word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
 	.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/	.word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
-	.word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
+/*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_sendto, sys_shutdown
+	.word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
 /*140*/	.word sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
 	.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -48,7 +48,7 @@
 
 DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
-unsigned long mstk48t02_regs = 0UL;
+void __iomem *mstk48t02_regs = NULL;
 #ifdef CONFIG_PCI
 unsigned long ds1287_regs = 0UL;
 #endif
@@ -59,8 +59,8 @@ u64 jiffies_64 = INITIAL_JIFFIES;
 
 EXPORT_SYMBOL(jiffies_64);
 
-static unsigned long mstk48t08_regs = 0UL;
-static unsigned long mstk48t59_regs = 0UL;
+static void __iomem *mstk48t08_regs;
+static void __iomem *mstk48t59_regs;
 
 static int set_rtc_mmss(unsigned long);
 
@@ -520,7 +520,7 @@ void timer_tick_interrupt(struct pt_regs
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
 static void __init kick_start_clock(void)
 {
-	unsigned long regs = mstk48t02_regs;
+	void __iomem *regs = mstk48t02_regs;
 	u8 sec, tmp;
 	int i, count;
 
@@ -604,7 +604,7 @@ static void __init kick_start_clock(void
 /* Return nonzero if the clock chip battery is low. */
 static int __init has_low_battery(void)
 {
-	unsigned long regs = mstk48t02_regs;
+	void __iomem *regs = mstk48t02_regs;
 	u8 data1, data2;
 
 	spin_lock_irq(&mostek_lock);
@@ -623,7 +623,7 @@ static int __init has_low_battery(void)
 static void __init set_system_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	unsigned long mregs = mstk48t02_regs;
+	void __iomem *mregs = mstk48t02_regs;
 #ifdef CONFIG_PCI
 	unsigned long dregs = ds1287_regs;
 #else
@@ -779,6 +779,7 @@ void __init clock_probe(void)
 		    strcmp(model, "mk48t59") &&
 		    strcmp(model, "m5819") &&
 		    strcmp(model, "m5819p") &&
+		    strcmp(model, "m5823") &&
 		    strcmp(model, "ds1287")) {
 			if (cbus != NULL) {
 				prom_printf("clock_probe: Central bus lacks timer chip.\n");
@@ -838,10 +839,12 @@ void __init clock_probe(void)
 
 			if (!strcmp(model, "ds1287") ||
 			    !strcmp(model, "m5819") ||
-			    !strcmp(model, "m5819p")) {
+			    !strcmp(model, "m5819p") ||
+			    !strcmp(model, "m5823")) {
 				ds1287_regs = edev->resource[0].start;
 			} else {
-				mstk48t59_regs = edev->resource[0].start;
+				mstk48t59_regs = (void __iomem *)
+					edev->resource[0].start;
 				mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
 			}
 			break;
@@ -859,10 +862,12 @@ try_isa_clock:
 			}
 			if (!strcmp(model, "ds1287") ||
 			    !strcmp(model, "m5819") ||
-			    !strcmp(model, "m5819p")) {
+			    !strcmp(model, "m5819p") ||
+			    !strcmp(model, "m5823")) {
 				ds1287_regs = isadev->resource.start;
 			} else {
-				mstk48t59_regs = isadev->resource.start;
+				mstk48t59_regs = (void __iomem *)
+					isadev->resource.start;
 				mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
 			}
 			break;
@@ -890,21 +895,24 @@ try_isa_clock:
 		}
 
 		if(model[5] == '0' && model[6] == '2') {
-			mstk48t02_regs = (((u64)clk_reg[0].phys_addr) |
-					  (((u64)clk_reg[0].which_io)<<32UL));
+			mstk48t02_regs = (void __iomem *)
+				(((u64)clk_reg[0].phys_addr) |
+				 (((u64)clk_reg[0].which_io)<<32UL));
 		} else if(model[5] == '0' && model[6] == '8') {
-			mstk48t08_regs = (((u64)clk_reg[0].phys_addr) |
-					  (((u64)clk_reg[0].which_io)<<32UL));
+			mstk48t08_regs = (void __iomem *)
+				(((u64)clk_reg[0].phys_addr) |
+				 (((u64)clk_reg[0].which_io)<<32UL));
 			mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
 		} else {
-			mstk48t59_regs = (((u64)clk_reg[0].phys_addr) |
-					  (((u64)clk_reg[0].which_io)<<32UL));
+			mstk48t59_regs = (void __iomem *)
+				(((u64)clk_reg[0].phys_addr) |
+				 (((u64)clk_reg[0].which_io)<<32UL));
 			mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
 		}
 		break;
 	}
 
-	if (mstk48t02_regs != 0UL) {
+	if (mstk48t02_regs != NULL) {
 		/* Report a low battery voltage condition. */
 		if (has_low_battery())
 			prom_printf("NVRAM: Low battery voltage!\n");
@@ -1084,7 +1092,7 @@ unsigned long long sched_clock(void)
 static int set_rtc_mmss(unsigned long nowtime)
 {
 	int real_seconds, real_minutes, chip_minutes;
-	unsigned long mregs = mstk48t02_regs;
+	void __iomem *mregs = mstk48t02_regs;
 #ifdef CONFIG_PCI
 	unsigned long dregs = ds1287_regs;
 #else
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -15,6 +15,7 @@
 #include <asm/spitfire.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/mmu.h>
 
 	.data
 	.align	8
@@ -334,6 +335,20 @@ do_unlock:
 	call		init_irqwork_curcpu
 	 nop
 
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g2,g3,1f)
+	ba,pt	%xcc, 2f
+	 nop
+
+1:	/* Start using proper page size encodings in ctx register.  */
+	sethi	%uhi(CTX_CHEETAH_PLUS_NUC), %g3
+	mov	PRIMARY_CONTEXT, %g1
+	sllx	%g3, 32, %g3
+	sethi	%hi(CTX_CHEETAH_PLUS_CTX0), %g2
+	or	%g3, %g2, %g3
+	stxa	%g3, [%g1] ASI_DMMU
+	membar	#Sync
+
+2:
 	rdpr		%pstate, %o1
 	or		%o1, PSTATE_IE, %o1
 	wrpr		%o1, 0, %pstate
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -421,6 +421,25 @@ asmlinkage void cee_log(unsigned long ce
 	}
 }
 
+int cheetah_pcache_forced_on;
+
+void cheetah_enable_pcache(void)
+{
+	unsigned long dcr;
+
+	printk("CHEETAH: Enabling P-Cache on cpu %d.\n",
+	       smp_processor_id());
+
+	__asm__ __volatile__("ldxa [%%g0] %1, %0"
+			     : "=r" (dcr)
+			     : "i" (ASI_DCU_CONTROL_REG));
+	dcr |= (DCU_PE | DCU_HPE | DCU_SPE | DCU_SL);
+	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (dcr), "i" (ASI_DCU_CONTROL_REG));
+}
+
 /* Cheetah error trap handling. */
 static unsigned long ecache_flush_physbase;
 static unsigned long ecache_flush_linesize;
@@ -806,48 +825,6 @@ static void cheetah_flush_ecache_line(un
 			       "i" (ASI_PHYS_USE_EC));
 }
 
-#ifdef CONFIG_SMP
-unsigned long __init cheetah_tune_scheduling(void)
-{
-	unsigned long tick1, tick2, raw;
-	unsigned long flush_base = ecache_flush_physbase;
-	unsigned long flush_linesize = ecache_flush_linesize;
-	unsigned long flush_size = ecache_flush_size;
-
-	/* Run through the whole cache to guarantee the timed loop
-	 * is really displacing cache lines.
-	 */
-	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
-			     "   bne,pt	%%xcc, 1b\n\t"
-			     "    ldxa	[%2 + %0] %3, %%g0\n\t"
-			     : "=&r" (flush_size)
-			     : "0" (flush_size), "r" (flush_base),
-			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
-
-	/* The flush area is 2 X Ecache-size, so cut this in half for
-	 * the timed loop.
-	 */
-	flush_base = ecache_flush_physbase;
-	flush_linesize = ecache_flush_linesize;
-	flush_size = ecache_flush_size >> 1;
-
-	tick1 = tick_ops->get_tick();
-
-	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
-			     "   bne,pt	%%xcc, 1b\n\t"
-			     "    ldxa	[%2 + %0] %3, %%g0\n\t"
-			     : "=&r" (flush_size)
-			     : "0" (flush_size), "r" (flush_base),
-			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
-
-	tick2 = tick_ops->get_tick();
-
-	raw = (tick2 - tick1);
-
-	return (raw - (raw >> 2));
-}
-#endif
-
 /* Unfortunately, the diagnostic access to the I-cache tags we need to
  * use to clear the thing interferes with I-cache coherency transactions.
  *
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -379,8 +379,8 @@ void kernel_mna_trap_fault(struct pt_reg
                 	printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
 	        printk(KERN_ALERT " at virtual address %016lx\n",address);
 		printk(KERN_ALERT "current->{mm,active_mm}->context = %016lx\n",
-			(current->mm ? current->mm->context :
-			current->active_mm->context));
+			(current->mm ? CTX_HWBITS(current->mm->context) :
+			CTX_HWBITS(current->active_mm->context)));
 		printk(KERN_ALERT "current->{mm,active_mm}->pgd = %016lx\n",
 			(current->mm ? (unsigned long) current->mm->pgd :
 			(unsigned long) current->active_mm->pgd));
@@ -413,7 +413,7 @@ asmlinkage void kernel_unaligned_trap(st
 		:
 		: "r" (regs), "r" (insn)
 		: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
-		  "g1", "g2", "g3", "g4", "g5", "g7", "cc");
+		  "g1", "g2", "g3", "g4", "g7", "cc");
 	} else {
 		unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
 
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -72,7 +72,7 @@ SECTIONS
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
-  . = ALIGN(32);
+  . = ALIGN(8192);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -14,6 +14,25 @@
 #include <asm/thread_info.h>
 
 	.text
+
+set_pcontext:
+cplus_winfixup_insn_1:
+	sethi	%hi(0), %l1
+	mov	PRIMARY_CONTEXT, %g1
+	sllx	%l1, 32, %l1
+cplus_winfixup_insn_2:
+	sethi	%hi(0), %g2
+	or	%l1, %g2, %l1
+	stxa	%l1, [%g1] ASI_DMMU
+	flush	%g6
+	retl
+	 nop
+
+cplus_wfinsn_1:
+	sethi	%uhi(CTX_CHEETAH_PLUS_NUC), %l1
+cplus_wfinsn_2:
+	sethi	%hi(CTX_CHEETAH_PLUS_CTX0), %g2
+
 	.align	32
 
 	/* Here are the rules, pay attention.
@@ -62,9 +81,8 @@ fill_fixup:
 	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
 	wrpr		%g2, 0x0, %wstate		! This must be consistent.
 	wrpr		%g0, 0x0, %otherwin		! We know this.
-	mov		PRIMARY_CONTEXT, %g1		! Change contexts...
-	stxa		%g0, [%g1] ASI_DMMU		! Back into the nucleus.
-	flush		%g6				! Flush instruction buffers
+	call		set_pcontext			! Change contexts...
+	 nop
 	rdpr		%pstate, %l1			! Prepare to change globals.
 	mov		%g6, %o7			! Get current.
 
@@ -75,6 +93,10 @@ fill_fixup:
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	mov		%o7, %g6
 	ldx		[%g6 + TI_TASK], %g4
+#ifdef CONFIG_SMP
+	mov		TSB_REG, %g1
+	ldxa		[%g1] ASI_IMMU, %g5
+#endif
 
 	/* This is the same as below, except we handle this a bit special
 	 * since we must preserve %l5 and %l6, see comment above.
@@ -183,9 +205,8 @@ fill_fixup_mna:
 
 	wrpr		%g2, 0x0, %wstate		! This must be consistent.
 	wrpr		%g0, 0x0, %otherwin		! We know this.
-	mov		PRIMARY_CONTEXT, %g1		! Change contexts...
-	stxa		%g0, [%g1] ASI_DMMU		! Back into the nucleus.
-	flush		%g6				! Flush instruction buffers
+	call		set_pcontext			! Change contexts...
+	 nop
 	rdpr		%pstate, %l1			! Prepare to change globals.
 	mov		%g4, %o2			! Setup args for
 	mov		%g5, %o1			! final call to mem_address_unaligned.
@@ -196,6 +217,10 @@ fill_fixup_mna:
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	mov		%o7, %g6			! Get current back.
 	ldx		[%g6 + TI_TASK], %g4		! Finish it.
+#ifdef CONFIG_SMP
+	mov		TSB_REG, %g1
+	ldxa		[%g1] ASI_IMMU, %g5
+#endif
 	call		mem_address_unaligned
 	 add		%sp, PTREGS_OFF, %o0
 
@@ -289,9 +314,8 @@ fill_fixup_dax:
 
 	wrpr		%g2, 0x0, %wstate		! This must be consistent.
 	wrpr		%g0, 0x0, %otherwin		! We know this.
-	mov		PRIMARY_CONTEXT, %g1		! Change contexts...
-	stxa		%g0, [%g1] ASI_DMMU		! Back into the nucleus.
-	flush		%g6				! Flush instruction buffers
+	call		set_pcontext			! Change contexts...
+	 nop
 	rdpr		%pstate, %l1			! Prepare to change globals.
 	mov		%g4, %o1			! Setup args for
 	mov		%g5, %o2			! final call to data_access_exception.
@@ -302,6 +326,10 @@ fill_fixup_dax:
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	mov		%o7, %g6			! Get current back.
 	ldx		[%g6 + TI_TASK], %g4		! Finish it.
+#ifdef CONFIG_SMP
+	mov		TSB_REG, %g1
+	ldxa		[%g1] ASI_IMMU, %g5
+#endif
 	call		data_access_exception
 	 add		%sp, PTREGS_OFF, %o0
 
@@ -368,3 +396,22 @@ window_dax_from_user_common:
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
+
+	.globl		cheetah_plus_patch_winfixup
+cheetah_plus_patch_winfixup:
+	sethi			%hi(cplus_wfinsn_1), %o0
+	sethi			%hi(cplus_winfixup_insn_1), %o2
+	lduw			[%o0 + %lo(cplus_wfinsn_1)], %o1
+	or			%o2, %lo(cplus_winfixup_insn_1), %o2
+	stw			%o1, [%o2]
+	flush			%o2
+
+	sethi			%hi(cplus_wfinsn_2), %o0
+	sethi			%hi(cplus_winfixup_insn_2), %o2
+	lduw			[%o0 + %lo(cplus_wfinsn_2)], %o1
+	or			%o2, %lo(cplus_winfixup_insn_2), %o2
+	stw			%o1, [%o2]
+	flush			%o2
+
+	retl
+	 nop
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -7,8 +7,8 @@ EXTRA_CFLAGS := -Werror
 
 lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
 	 memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-	 VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
-	 VIScsumcopyusr.o VISsave.o atomic.o bitops.o \
+	 bzero.o csum_copy.o csum_copy_from_user.o csum_copy_to_user.o \
+	 VISsave.o atomic.o bitops.o \
 	 U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
 	 U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
 	 copy_in_user.o user_fixup.o memmove.o \
diff --git a/arch/sparc64/lib/U1memcpy.S b/arch/sparc64/lib/U1memcpy.S
--- a/arch/sparc64/lib/U1memcpy.S
+++ b/arch/sparc64/lib/U1memcpy.S
@@ -7,7 +7,9 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#define GLOBAL_SPARE	g7
 #else
+#define GLOBAL_SPARE	g5
 #define ASI_BLK_P 0xf0
 #define FPRS_FEF  0x04
 #ifdef MEMCPY_DEBUG
@@ -123,7 +125,7 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	cmp		%g2, 0
 	tne		%xcc, 5
 	PREAMBLE
-	mov		%o0, %g5
+	mov		%o0, %o4
 	cmp		%o2, 0
 	be,pn		%XCC, 85f
 	 or		%o0, %o1, %o3
@@ -146,7 +148,7 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
 	 * subtract this from 'len'.
 	 */
-	 sub		%o0, %o1, %o4
+	 sub		%o0, %o1, %GLOBAL_SPARE
 	sub		%g2, 0x40, %g2
 	sub		%g0, %g2, %g2
 	sub		%o2, %g2, %o2
@@ -156,11 +158,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 
 1:	subcc		%g1, 0x1, %g1
 	EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
-	EX_ST(STORE(stb, %o3, %o1 + %o4))
+	EX_ST(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x1, %o1
 
-	add		%o1, %o4, %o0
+	add		%o1, %GLOBAL_SPARE, %o0
 
 2:	cmp		%g2, 0x0
 	and		%o1, 0x7, %g1
@@ -188,19 +190,19 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 3:	
 	membar		  #LoadStore | #StoreStore | #StoreLoad
 
-	subcc		%o2, 0x40, %o4
+	subcc		%o2, 0x40, %GLOBAL_SPARE
 	add		%o1, %g1, %g1
-	andncc		%o4, (0x40 - 1), %o4
+	andncc		%GLOBAL_SPARE, (0x40 - 1), %GLOBAL_SPARE
 	srl		%g1, 3, %g2
-	sub		%o2, %o4, %g3
+	sub		%o2, %GLOBAL_SPARE, %g3
 	andn		%o1, (0x40 - 1), %o1
 	and		%g2, 7, %g2
 	andncc		%g3, 0x7, %g3
 	fmovd		%f0, %f2
 	sub		%g3, 0x8, %g3
-	sub		%o2, %o4, %o2
+	sub		%o2, %GLOBAL_SPARE, %o2
 
-	add		%g1, %o4, %g1
+	add		%g1, %GLOBAL_SPARE, %g1
 	subcc		%o2, %g3, %o2
 
 	EX_LD(LOAD_BLK(%o1, %f0))
@@ -208,7 +210,7 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	add		%g1, %g3, %g1
 	EX_LD(LOAD_BLK(%o1, %f16))
 	add		%o1, 0x40, %o1
-	sub		%o4, 0x80, %o4
+	sub		%GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
 	EX_LD(LOAD_BLK(%o1, %f32))
 	add		%o1, 0x40, %o1
 
@@ -229,11 +231,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 
 	.align		64
 1:	FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f0, %f2, %f48
 1:	FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
@@ -250,11 +252,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 56f) membar #Sync
 
 1:	FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f2, %f4, %f48
 1:	FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
@@ -271,11 +273,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 57f) membar #Sync
 
 1:	FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f4, %f6, %f48
 1:	FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
@@ -292,11 +294,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 58f) membar #Sync
 
 1:	FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) 
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f6, %f8, %f48
 1:	FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
@@ -313,11 +315,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 59f) membar #Sync
 
 1:	FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f8, %f10, %f48
 1:	FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
@@ -334,11 +336,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 60f) membar #Sync
 
 1:	FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f10, %f12, %f48
 1:	FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
@@ -355,11 +357,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 61f) membar #Sync
 
 1:	FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f12, %f14, %f48
 1:	FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
@@ -376,11 +378,11 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	STORE_JUMP(o0, f48, 62f) membar #Sync
 
 1:	FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-	LOOP_CHUNK1(o1, o0, o4, 1f)
+	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-	LOOP_CHUNK2(o1, o0, o4, 2f)
+	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
 	FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-	LOOP_CHUNK3(o1, o0, o4, 3f)
+	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f14, %f16, %f48
 1:	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
@@ -449,18 +451,18 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 2:	membar		#StoreLoad | #StoreStore
 	VISExit
 	retl
-	 mov		EX_RETVAL(%g5), %o0
+	 mov		EX_RETVAL(%o4), %o0
 
 	.align		64
 70:	/* 16 < len <= (5 * 64) */
 	bne,pn		%XCC, 75f
 	 sub		%o0, %o1, %o3
 
-72:	andn		%o2, 0xf, %o4
+72:	andn		%o2, 0xf, %GLOBAL_SPARE
 	and		%o2, 0xf, %o2
 1:	EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
 	EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
-	subcc		%o4, 0x10, %o4
+	subcc		%GLOBAL_SPARE, 0x10, %GLOBAL_SPARE
 	EX_ST(STORE(stx, %o5, %o1 + %o3))
 	add		%o1, 0x8, %o1
 	EX_ST(STORE(stx, %g1, %o1 + %o3))
@@ -512,10 +514,10 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	andn		%o1, 0x7, %o1
 	EX_LD(LOAD(ldx, %o1, %g2))
 	sub		%o3, %g1, %o3
-	andn		%o2, 0x7, %o4
+	andn		%o2, 0x7, %GLOBAL_SPARE
 	sllx		%g2, %g1, %g2
 1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
-	subcc		%o4, 0x8, %o4
+	subcc		%GLOBAL_SPARE, 0x8, %GLOBAL_SPARE
 	add		%o1, 0x8, %o1
 	srlx		%g3, %o3, %o5
 	or		%o5, %g2, %o5
@@ -544,7 +546,7 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	 add		%o1, 4, %o1
 
 85:	retl
-	 mov		EX_RETVAL(%g5), %o0
+	 mov		EX_RETVAL(%o4), %o0
 
 	.align		32
 90:	EX_LD(LOAD(ldub, %o1, %g1))
@@ -553,6 +555,6 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
-	 mov		EX_RETVAL(%g5), %o0
+	 mov		EX_RETVAL(%o4), %o0
 
 	.size		FUNC_NAME, .-FUNC_NAME
diff --git a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S
--- a/arch/sparc64/lib/U3memcpy.S
+++ b/arch/sparc64/lib/U3memcpy.S
@@ -6,6 +6,7 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#define GLOBAL_SPARE	%g7
 #else
 #define ASI_BLK_P 0xf0
 #define FPRS_FEF  0x04
@@ -17,6 +18,7 @@
 #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
 #endif
+#define GLOBAL_SPARE	%g5
 #endif
 
 #ifndef EX_LD
@@ -84,7 +86,7 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	cmp		%g2, 0
 	tne		%xcc, 5
 	PREAMBLE
-	mov		%o0, %g5
+	mov		%o0, %o4
 	cmp		%o2, 0
 	be,pn		%XCC, 85f
 	 or		%o0, %o1, %o3
@@ -109,7 +111,7 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
 	 * subtract this from 'len'.
 	 */
-	 sub		%o0, %o1, %o4
+	 sub		%o0, %o1, GLOBAL_SPARE
 	sub		%g2, 0x40, %g2
 	sub		%g0, %g2, %g2
 	sub		%o2, %g2, %o2
@@ -119,11 +121,11 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 
 1:	subcc		%g1, 0x1, %g1
 	EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
-	EX_ST(STORE(stb, %o3, %o1 + %o4))
+	EX_ST(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x1, %o1
 
-	add		%o1, %o4, %o0
+	add		%o1, GLOBAL_SPARE, %o0
 
 2:	cmp		%g2, 0x0
 	and		%o1, 0x7, %g1
@@ -149,7 +151,7 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 
 3:	LOAD(prefetch, %o1 + 0x000, #one_read)
 	LOAD(prefetch, %o1 + 0x040, #one_read)
-	andn		%o2, (0x40 - 1), %o4
+	andn		%o2, (0x40 - 1), GLOBAL_SPARE
 	LOAD(prefetch, %o1 + 0x080, #one_read)
 	LOAD(prefetch, %o1 + 0x0c0, #one_read)
 	LOAD(prefetch, %o1 + 0x100, #one_read)
@@ -173,10 +175,10 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	faligndata	%f10, %f12, %f26
 	EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
 
-	subcc		%o4, 0x80, %o4
+	subcc		GLOBAL_SPARE, 0x80, GLOBAL_SPARE
 	add		%o1, 0x40, %o1
 	bgu,pt		%XCC, 1f
-	 srl		%o4, 6, %o3
+	 srl		GLOBAL_SPARE, 6, %o3
 	ba,pt		%xcc, 2f
 	 nop
 
@@ -315,9 +317,9 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	 sub		%o0, %o1, %o3
 
 72:
-	andn		%o2, 0xf, %o4
+	andn		%o2, 0xf, GLOBAL_SPARE
 	and		%o2, 0xf, %o2
-1:	subcc		%o4, 0x10, %o4
+1:	subcc		GLOBAL_SPARE, 0x10, GLOBAL_SPARE
 	EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
 	EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
 	EX_ST(STORE(stx, %o5, %o1 + %o3))
@@ -372,10 +374,10 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	andn		%o1, 0x7, %o1
 	EX_LD(LOAD(ldx, %o1, %g2))
 	sub		%o3, %g1, %o3
-	andn		%o2, 0x7, %o4
+	andn		%o2, 0x7, GLOBAL_SPARE
 	sllx		%g2, %g1, %g2
 1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
-	subcc		%o4, 0x8, %o4
+	subcc		GLOBAL_SPARE, 0x8, GLOBAL_SPARE
 	add		%o1, 0x8, %o1
 	srlx		%g3, %o3, %o5
 	or		%o5, %g2, %o5
@@ -405,7 +407,7 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	 add		%o1, 4, %o1
 
 85:	retl
-	 mov		EX_RETVAL(%g5), %o0
+	 mov		EX_RETVAL(%o4), %o0
 
 	.align		32
 90:
@@ -415,6 +417,6 @@ FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len 
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
-	 mov		EX_RETVAL(%g5), %o0
+	 mov		EX_RETVAL(%o4), %o0
 
 	.size		FUNC_NAME, .-FUNC_NAME
diff --git a/arch/sparc64/lib/VIS.h b/arch/sparc64/lib/VIS.h
deleted file mode 100644
--- a/arch/sparc64/lib/VIS.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* $Id: VIS.h,v 1.4 1999/05/25 16:52:50 jj Exp $
- * VIS.h: High speed copy/clear operations utilizing the UltraSparc
- *        Visual Instruction Set.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-	/* VIS code can be used for numerous copy/set operation variants.
-	 * It can be made to work in the kernel, one single instance,
-	 * for all of memcpy, copy_to_user, and copy_from_user by setting
-	 * the ASI src/dest globals correctly.  Furthermore it can
-	 * be used for kernel-->kernel page copies as well, a hook label
-	 * is put in here just for this purpose.
-	 *
-	 * For userland, compiling this without __KERNEL__ defined makes
-	 * it work just fine as a generic libc bcopy and memcpy.
-	 * If for userland it is compiled with a 32bit gcc (but you need
-	 * -Wa,-Av9a), the code will just rely on lower 32bits of
-	 * IEU registers, if you compile it with 64bit gcc (ie. define
-	 * __sparc_v9__), the code will use full 64bit.
-	 */
-
-#ifndef __VIS_H
-#define __VIS_H
-	 
-#ifdef __KERNEL__
-#include <asm/head.h>
-#include <asm/asi.h>
-#else
-#define ASI_AIUS		0x11 /* Secondary, user				*/
-#define ASI_BLK_AIUS		0x71 /* Secondary, user, blk ld/st		*/
-#define ASI_P			0x80 /* Primary, implicit			*/
-#define ASI_S			0x81 /* Secondary, implicit			*/
-#define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit		*/
-#define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit		*/
-#define ASI_BLK_P		0xf0 /* Primary, blk ld/st			*/
-#define ASI_BLK_S		0xf1 /* Secondary, blk ld/st			*/
-#define FPRS_FEF		0x04
-#endif
-
-	/* I'm telling you, they really did this chip right.
-	 * Perhaps the SunSoft folks should visit some of the
-	 * people in Sun Microelectronics and start some brain
-	 * cell exchange program...
-	 */
-#define ASI_BLK_XOR		(ASI_P ^ ASI_BLK_P)
-	/* Well, things get more hairy if we use ASI_AIUS as
-	 * USER_DS and ASI_P as KERNEL_DS, we'd reach
-	 * commit block stores this way which is not what we want...
-	 */
-	/* ASI_P->ASI_BLK_P && ASI_AIUS->ASI_BLK_AIUS transitions can be done
-	 * as blkasi = asi | ASI_BLK_OR
-	 */
-#define ASI_BLK_OR		(ASI_BLK_P & ~ASI_P)
-	/* Transition back from ASI_BLK_P->ASI_P && ASI_BLK_AIUS->ASI_AIUS is
-	 * more complicated:
-	 * asi = blkasi ^ (blkasi >> 3) ^ ASI_BLK_XOR1
-	 */
-#define ASI_BLK_XOR1		(ASI_BLK_P ^ (ASI_BLK_P >> 3) ^ ASI_P)
-
-#define	asi_src			%o3
-#define asi_dest		%o4
-
-#ifdef __KERNEL__
-#define ASI_SETSRC_BLK		wr	asi_src, 0, %asi;
-#define ASI_SETSRC_NOBLK	wr	asi_src, 0, %asi;
-#define ASI_SETDST_BLK		wr	asi_dest, 0, %asi;
-#define ASI_SETDST_NOBLK	wr	asi_dest, 0, %asi;
-#define ASIBLK			%asi
-#define ASINORMAL		%asi
-#define LDUB			lduba
-#define LDUH			lduha
-#define LDUW			lduwa
-#define LDX			ldxa
-#define LDD			ldda
-#define LDDF			ldda
-#define LDBLK			ldda
-#define STB			stba
-#define STH			stha
-#define STW			stwa
-#define STD			stda
-#define STX			stxa
-#define STDF			stda
-#define STBLK			stda
-#else
-#define ASI_SETSRC_BLK
-#define ASI_SETSRC_NOBLK
-#define ASI_SETDST_BLK
-#define ASI_SETDST_NOBLK
-#define ASI_SETDST_SPECIAL
-#define ASIBLK			%asi
-#define ASINORMAL
-#define LDUB			ldub
-#define LDUH			lduh
-#define LDUW			lduw
-#define LDD			ldd
-#define LDX			ldx
-#define LDDF			ldd
-#define LDBLK			ldda
-#define STB			stb
-#define STH			sth
-#define STW			stw
-#define STD			std
-#define STX			stx
-#define STDF			std
-#define STBLK			stda
-#endif
-
-#ifdef __KERNEL__
-
-#define REGS_64BIT
-
-#else
-
-#ifndef REGS_64BIT
-#ifdef __sparc_v9__
-#define REGS_64BIT
-#endif
-#endif
-
-#endif
-
-#ifndef REGS_64BIT
-#define	xcc	icc
-#endif
-
-#endif
diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S
deleted file mode 100644
--- a/arch/sparc64/lib/VISbzero.S
+++ /dev/null
@@ -1,274 +0,0 @@
-/* $Id: VISbzero.S,v 1.11 2001/03/15 08:51:24 anton Exp $
- * VISbzero.S: High speed clear operations utilizing the UltraSparc
- *        Visual Instruction Set.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#include "VIS.h"
-
-#ifdef __KERNEL__
-#include <asm/visasm.h>
-
-#define EXN(x,y,a,b,z) 				\
-98: 	x,y;					\
-	.section .fixup;			\
-	.align	4;				\
-99:	ba	VISbzerofixup_ret##z;		\
-	 a, b, %o0;				\
-	.section __ex_table;			\
-	.align	4;				\
-	.word	98b, 99b;			\
-	.text;					\
-	.align	4;
-#define EXC(x,y,a,b,c...) 			\
-98: 	x,y;					\
-	.section .fixup;			\
-	.align	4;				\
-99:	c;					\
-	ba	VISbzerofixup_ret0;		\
-	 a, b, %o0;				\
-	.section __ex_table;			\
-	.align	4;				\
-	.word	98b, 99b;			\
-	.text;					\
-	.align	4;
-#define EXO1(x,y) 				\
-98: 	x,y;					\
-	.section __ex_table;			\
-	.align	4;				\
-	.word	98b, VISbzerofixup_reto1;	\
-	.text;					\
-	.align	4;
-#define EX(x,y,a,b) EXN(x,y,a,b,0)
-#define EX1(x,y,a,b) EXN(x,y,a,b,1)
-#define EX2(x,y,a,b) EXN(x,y,a,b,2)
-#define EXT(start,end,handler) 			\
-	.section __ex_table;			\
-	.align	4;				\
-	.word	start, 0, end, handler;		\
-	.text;					\
-	.align	4
-#else
-#define EX(x,y,a,b)		x,y
-#define EX1(x,y,a,b)		x,y
-#define EX2(x,y,a,b)		x,y
-#define EXC(x,y,a,b,c...)	x,y
-#define EXO1(x,y)		x,y
-#define EXT(a,b,c)
-#endif
-
-#define ZERO_BLOCKS(base, offset, source)			\
-	STX	source, [base - offset - 0x38] ASINORMAL;	\
-	STX	source, [base - offset - 0x30] ASINORMAL;	\
-	STX	source, [base - offset - 0x28] ASINORMAL;	\
-	STX	source, [base - offset - 0x20] ASINORMAL;	\
-	STX	source, [base - offset - 0x18] ASINORMAL;	\
-	STX	source, [base - offset - 0x10] ASINORMAL;	\
-	STX	source, [base - offset - 0x08] ASINORMAL;	\
-	STX	source, [base - offset - 0x00] ASINORMAL;
-
-#ifdef __KERNEL__
-#define RETL	clr %o0
-#else
-#define RETL	mov %g3, %o0
-#endif
-
-	/* Well, bzero is a lot easier to get right than bcopy... */
-#ifdef __KERNEL__
-	.section	__ex_table,#alloc
-	.section	.fixup,#alloc,#execinstr
-#endif
-	.text
-	.align		32
-#ifdef __KERNEL__
-	.globl		__bzero, __bzero_noasi
-__bzero_noasi:
-	rd		%asi, %g5
-	ba,pt		%xcc, __bzero+12
-	 mov		%g5, %o4
-__bzero:
-	rd		%asi, %g5
-	wr		%g0, ASI_P, %asi		! LSU	Group
-	mov		ASI_P, %o4
-#else
-	.globl		bzero
-bzero_private:
-bzero:
-#ifndef REGS_64BIT
-	srl		%o1, 0, %o1
-#endif
-	mov		%o0, %g3
-#endif
-	cmp		%o1, 7
-	bleu,pn		%xcc, 17f
-	 andcc		%o0, 3, %o2
-	be,a,pt		%xcc, 4f
-	 andcc		%o0, 4, %g0
-	cmp		%o2, 3
-	be,pn		%xcc, 2f
-	 EXO1(STB	%g0, [%o0 + 0x00] ASINORMAL)
-	cmp		%o2, 2
-	be,pt		%xcc, 2f
-	 EX(STB		%g0, [%o0 + 0x01] ASINORMAL, sub %o1, 1)
-	EX(STB		%g0, [%o0 + 0x02] ASINORMAL, sub %o1, 2)
-2:	sub		%o2, 4, %o2
-	sub		%o0, %o2, %o0
-	add		%o1, %o2, %o1
-	andcc		%o0, 4, %g0
-4:	be,pt		%xcc, 2f
-	 cmp		%o1, 128
-	EXO1(STW	%g0, [%o0] ASINORMAL)
-	sub		%o1, 4, %o1
-	add		%o0, 4, %o0
-2:	blu,pn		%xcc, 9f
-	 andcc		%o0, 0x38, %o2
-	be,pn		%icc, 6f
-	 mov		64, %o5
-	andcc		%o0, 8, %g0
-	be,pn		%icc, 1f
-	 sub		%o5, %o2, %o5
-	EX(STX		%g0, [%o0] ASINORMAL, sub %o1, 0)
-	add		%o0, 8, %o0
-1:	andcc		%o5, 16, %g0
-	be,pn		%icc, 1f
-	 sub		%o1, %o5, %o1
-	EX1(STX		%g0, [%o0] ASINORMAL, add %g0, 0)
-	EX1(STX		%g0, [%o0 + 8] ASINORMAL, sub %g0, 8)
-	add		%o0, 16, %o0
-1:	andcc		%o5, 32, %g0
-	be,pn		%icc, 7f
-	 andncc		%o1, 0x3f, %o3
-	EX(STX		%g0, [%o0] ASINORMAL, add %o1, 32)
-	EX(STX		%g0, [%o0 + 8] ASINORMAL, add %o1, 24)
-	EX(STX		%g0, [%o0 + 16] ASINORMAL, add %o1, 16)
-	EX(STX		%g0, [%o0 + 24] ASINORMAL, add %o1, 8)
-	add		%o0, 32, %o0
-6:	andncc		%o1, 0x3f, %o3
-7:	be,pn		%xcc, 9f
-#ifdef __KERNEL__
-	 or		%o4, ASI_BLK_OR, %g7 
-	wr		%g7, %g0, %asi
-	VISEntryHalf
-#else
-	 wr		%g0, ASI_BLK_P, %asi
-#endif
-	membar		#StoreLoad | #StoreStore | #LoadStore
-	fzero		%f0
-	andcc		%o3, 0xc0, %o2
-	and		%o1, 0x3f, %o1
-	fzero		%f2
-	andn		%o3, 0xff, %o3
-	faddd		%f0, %f2, %f4
-	fmuld		%f0, %f2, %f6
-	cmp		%o2, 64
-	faddd		%f0, %f2, %f8
-	fmuld		%f0, %f2, %f10
-	faddd		%f0, %f2, %f12
-	brz,pn		%o2, 10f
-	 fmuld		%f0, %f2, %f14
-	be,pn		%icc, 2f
-	 EXC(STBLK	%f0, [%o0 + 0x00] ASIBLK, add %o3, %o2, add %o2, %o1, %o2)
-	cmp		%o2, 128
-	be,pn		%icc, 2f
-	 EXC(STBLK	%f0, [%o0 + 0x40] ASIBLK, add %o3, %o2, add %o2, %o1, %o2; sub %o2, 64, %o2)
-	EXC(STBLK	%f0, [%o0 + 0x80] ASIBLK, add %o3, %o2, add %o2, %o1, %o2; sub %o2, 128, %o2)
-2:	brz,pn		%o3, 12f
-	 add		%o0, %o2, %o0
-10:	EX(STBLK	%f0, [%o0 + 0x00] ASIBLK, add %o3, %o1)
-	EXC(STBLK	%f0, [%o0 + 0x40] ASIBLK, add %o3, %o1, sub %o1, 64, %o1)
-	EXC(STBLK	%f0, [%o0 + 0x80] ASIBLK, add %o3, %o1, sub %o1, 128, %o1)
-	EXC(STBLK	%f0, [%o0 + 0xc0] ASIBLK, add %o3, %o1, sub %o1, 192, %o1)
-11:	subcc		%o3, 256, %o3
-	bne,pt		%xcc, 10b
-	 add		%o0, 256, %o0
-12:
-#ifdef __KERNEL__
-	VISExitHalf
-	wr		%o4, 0x0, %asi
-#else
-#ifndef REGS_64BIT
-	wr		%g0, FPRS_FEF, %fprs
-#endif
-#endif
-	membar		#StoreLoad | #StoreStore
-9:	andcc		%o1, 0xf8, %o2
-	be,pn		%xcc, 13f
-	 andcc		%o1, 7, %o1
-#ifdef __KERNEL__
-14:	sethi		%hi(13f), %o4
-	srl		%o2, 1, %o3
-	sub		%o4, %o3, %o4
-	jmpl		%o4 + %lo(13f), %g0
-	 add		%o0, %o2, %o0
-#else
-14:	rd		%pc, %o4
-	srl		%o2, 1, %o3
-	sub		%o4, %o3, %o4
-	jmpl		%o4 + (13f - 14b), %g0
-	 add		%o0, %o2, %o0
-#endif
-12:	ZERO_BLOCKS(%o0, 0xc8, %g0)
-	ZERO_BLOCKS(%o0, 0x88, %g0)
-	ZERO_BLOCKS(%o0, 0x48, %g0)
-	ZERO_BLOCKS(%o0, 0x08, %g0)
-	EXT(12b,13f,VISbzerofixup_zb)
-13:	be,pn		%xcc, 8f
-	 andcc		%o1, 4, %g0
-	be,pn		%xcc, 1f
-	 andcc		%o1, 2, %g0
-	EX(STW		%g0, [%o0] ASINORMAL, and %o1, 7)
-	add		%o0, 4, %o0
-1:	be,pn		%xcc, 1f
-	 andcc		%o1, 1, %g0
-	EX(STH		%g0, [%o0] ASINORMAL, and %o1, 3)
-	add		%o0, 2, %o0
-1:	bne,a,pn	%xcc, 8f
-	 EX(STB		%g0, [%o0] ASINORMAL, add %g0, 1)
-8:
-#ifdef __KERNEL__
-	wr		%g5, %g0, %asi
-#endif
-	retl
-	 RETL
-17:	be,pn		%xcc, 13b
-	 orcc		%o1, 0, %g0
-	be,pn		%xcc, 0f
-8:	 add		%o0, 1, %o0
-	subcc		%o1, 1, %o1
-	bne,pt		%xcc, 8b
-	 EX(STB		%g0, [%o0 - 1] ASINORMAL, add %o1, 1)
-0:
-#ifdef __KERNEL__
-	wr		%g5, %g0, %asi
-#endif
-	retl
-	 RETL
-
-#ifdef __KERNEL__
-	.section	.fixup
-	.align		4
-VISbzerofixup_reto1:
-	mov		%o1, %o0
-VISbzerofixup_ret0:
-	wr		%g5, %g0, %asi
-	retl
-	 wr		%g0, 0, %fprs
-VISbzerofixup_ret1:
-	and		%o5, 0x30, %o5
-	add		%o5, %o1, %o5
-	ba,pt		%xcc, VISbzerofixup_ret0
-	 add		%o0, %o5, %o0
-VISbzerofixup_ret2:
-	and		%o5, 0x20, %o5
-	add		%o5, %o1, %o5
-	ba,pt		%xcc, VISbzerofixup_ret0
-	 add		%o0, %o5, %o0
-VISbzerofixup_zb:
-	andcc		%o1, 7, %o1
-	sll		%g2, 3, %g2
-	add		%o1, 256, %o1
-	ba,pt		%xcc, VISbzerofixup_ret0
-	 sub		%o1, %g2, %o0
-#endif
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
deleted file mode 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ /dev/null
@@ -1,546 +0,0 @@
-/* $Id: VIScsum.S,v 1.7 2002/02/09 19:49:30 davem Exp $
- * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
- *            Visual Instruction Set.
- *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 2000 David S. Miller (davem@redhat.com)
- *
- * Based on older sparc32/sparc64 checksum.S, which is:
- *
- *      Copyright(C) 1995 Linus Torvalds
- *      Copyright(C) 1995 Miguel de Icaza
- *      Copyright(C) 1996, 1997 David S. Miller
- *    derived from:
- *	  Linux/Alpha checksum c-code
- *        Linux/ix86 inline checksum assembly
- *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
- *	  David Mosberger-Tang for optimized reference c-code
- *	  BSD4.4 portable checksum routine
- */
-
-#ifdef __sparc_v9__
-#define STACKOFF	2175
-#else
-#define STACKOFF	64
-#endif
-
-#ifdef __KERNEL__
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/visasm.h>
-#include <asm/thread_info.h>
-#else
-#define ASI_BLK_P	0xf0
-#define FRPS_FEF	0x04
-#endif
-
-/* Dobrou noc, SunSoft engineers. Spete sladce.
- * This has a couple of tricks in and those
- * tricks are UltraLinux trade secrets :))
- */
-
-#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10)						\
-	fcmpgt32	%fz, %f0, %g1		/*  FPM		Group	*/;		\
-	fcmpgt32	%fz, %f2, %g2		/*  FPM		Group	*/;		\
-	fcmpgt32	%fz, %f4, %g3		/*  FPM		Group	*/;		\
-	inc		%g1			/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f6, %g5		/*  FPM			*/;		\
-	srl		%g1, 1, %g1		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f8, %g7		/*  FPM			*/;		\
-	inc		%g2			/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f10, %o3		/*  FPM			*/;		\
-	srl		%g2, 1, %g2		/*  IEU0	Group	*/;		\
-	inc		%g3			/*  IEU1		*/;		\
-	srl		%g3, 1, %g3		/*  IEU0	Group	*/;		\
-	add		%o2, %g1, %o2		/*  IEU1		*/;		\
-	add		%o2, %g2, %o2		/*  IEU0	Group	*/;		\
-	inc		%g5			/*  IEU1		*/;		\
-	add		%o2, %g3, %o2		/*  IEU0	Group	*/;
-
-#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14)	\
-	srl		%g5, 1, %g5		/*  IEU0	Group	*/;		\
-	fpadd32		%F0, %f0, %F0		/*  FPA			*/;		\
-	fcmpgt32	%O12, %f12, %o4		/*  FPM			*/;		\
-	inc		%g7			/*  IEU0	Group	*/;		\
-	fpadd32		%F2, %f2, %F2		/*  FPA			*/;		\
-	fcmpgt32	%O14, %f14, %o5		/*  FPM			*/;		\
-	add		%o2, %g5, %o2		/*  IEU1	Group	*/;		\
-	fpadd32		%F4, %f4, %F4		/*  FPA			*/;		\
-	fcmpgt32	%f0, %F0, %g1		/*  FPM			*/;		\
-	srl		%g7, 1, %g7		/*  IEU0	Group	*/;		\
-	fpadd32		%F6, %f6, %F6		/*  FPA			*/;		\
-	fcmpgt32	%f2, %F2, %g2		/*  FPM			*/;		\
-	add		%o2, %g7, %o2		/*  IEU0	Group	*/;		\
-	fpadd32		%F8, %f8, %F8		/*  FPA			*/;		\
-	fcmpgt32	%f4, %F4, %g3		/*  FPM			*/;		\
-	inc		%o3			/*  IEU0	Group	*/;		\
-	fpadd32		%F10, %f10, %F10	/*  FPA			*/;		\
-	fcmpgt32	%f6, %F6, %g5		/*  FPM			*/;		\
-	srl		%o3, 1, %o3		/*  IEU0	Group	*/;		\
-	fpadd32		%F12, %f12, %F12	/*  FPA			*/;		\
-	fcmpgt32	%f8, %F8, %g7		/*  FPM			*/;		\
-	add		%o2, %o3, %o2		/*  IEU0	Group	*/;		\
-	fpadd32		%F14, %f14, %F14	/*  FPA			*/;		\
-	fcmpgt32	%f10, %F10, %o3		/*  FPM			*/;		\
-	inc		%o4			/*  IEU0	Group	*/;		\
-	inc		%o5			/*  IEU1		*/;		\
-	srl		%o4, 1, %o4		/*  IEU0	Group	*/;		\
-	inc		%g1			/*  IEU1		*/;		\
-	srl		%o5, 1, %o5		/*  IEU0	Group	*/;		\
-	add		%o2, %o4, %o2		/*  IEU1		*/;		\
-	srl		%g1, 1, %g1		/*  IEU0	Group	*/;		\
-	add		%o2, %o5, %o2		/*  IEU1		*/;		\
-	inc		%g2			/*  IEU0	Group	*/;		\
-	add		%o2, %g1, %o2		/*  IEU1		*/;		\
-	srl		%g2, 1, %g2		/*  IEU0	Group	*/;		\
-	inc		%g3			/*  IEU1		*/;		\
-	srl		%g3, 1, %g3		/*  IEU0	Group	*/;		\
-	add		%o2, %g2, %o2		/*  IEU1		*/;		\
-	inc		%g5			/*  IEU0	Group	*/;		\
-	add		%o2, %g3, %o2		/*  IEU0		*/;
-
-#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz)	\
-	srl		%g5, 1, %g5		/*  IEU0	Group	*/;		\
-	fpadd32		%f2, %f0, %S0		/*  FPA			*/;		\
-	fcmpgt32	%O12, %f12, %o4		/*  FPM			*/;		\
-	inc		%g7			/*  IEU0	Group	*/;		\
-	fpadd32		%f6, %f4, %S1		/*  FPA			*/;		\
-	fcmpgt32	%O14, %f14, %o5		/*  FPM			*/;		\
-	srl		%g7, 1, %g7		/*  IEU0	Group	*/;		\
-	fpadd32		%f10, %f8, %S2		/*  FPA			*/;		\
-	fcmpgt32	%f0, %S0, %g1		/*  FPM			*/;		\
-	inc		%o3			/*  IEU0	Group	*/;		\
-	fpadd32		%f14, %f12, %S3		/*  FPA			*/;		\
-	fcmpgt32	%f4, %S1, %g2		/*  FPM			*/;		\
-	add		%o2, %g5, %o2		/*  IEU0	Group	*/;		\
-	fpadd32		%S0, %S1, %T0		/*  FPA			*/;		\
-	fcmpgt32	%f8, %S2, %g3		/*  FPM			*/;		\
-	add		%o2, %g7, %o2		/*  IEU0	Group	*/;		\
-	fzero		%fz			/*  FPA			*/;		\
-	fcmpgt32	%f12, %S3, %g5		/*  FPM			*/;		\
-	srl		%o3, 1, %o3		/*  IEU0	Group	*/;		\
-	fpadd32		%S2, %S3, %T1		/*  FPA			*/;		\
-	fcmpgt32	%S0, %T0, %g7		/*  FPM			*/;		\
-	add		%o2, %o3, %o2		/*  IEU0	Group	*/;		\
-	fpadd32		%T0, %T1, %U0		/*  FPA			*/;		\
-	fcmpgt32	%S2, %T1, %o3		/*  FPM			*/;		\
-	inc		%o4			/*  IEU0	Group	*/;		\
-	inc		%o5			/*  IEU1		*/;		\
-	srl		%o4, 1, %o4		/*  IEU0	Group	*/;		\
-	inc		%g1			/*  IEU1		*/;		\
-	add		%o2, %o4, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f2, %o4		/*  FPM			*/;		\
-	srl		%o5, 1, %o5		/*  IEU0	Group	*/;		\
-	inc		%g2			/*  IEU1		*/;		\
-	add		%o2, %o5, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f6, %o5		/*  FPM			*/;		\
-	srl		%g1, 1, %g1		/*  IEU0	Group	*/;		\
-	inc		%g3			/*  IEU1		*/;		\
-	add		%o2, %g1, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f10, %g1		/*  FPM			*/;		\
-	srl		%g2, 1, %g2		/*  IEU0	Group	*/;		\
-	inc		%g5			/*  IEU1		*/;		\
-	add		%o2, %g2, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %f14, %g2		/*  FPM			*/;		\
-	srl		%g3, 1, %g3		/*  IEU0	Group	*/;		\
-	inc		%g7			/*  IEU1		*/;		\
-	add		%o2, %g3, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %S1, %g3		/*  FPM			*/;		\
-	srl		%g5, 1, %g5		/*  IEU0	Group	*/;		\
-	inc		%o3			/*  IEU1		*/;		\
-	add		%o2, %g5, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %S3, %g5		/*  FPM			*/;		\
-	srl		%g7, 1, %g7		/*  IEU0	Group	*/;		\
-	inc		%o4			/*  IEU1		*/;		\
-	add		%o2, %g7, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %T1, %g7		/*  FPM			*/;		\
-	srl		%o3, 1, %o3		/*  IEU0	Group	*/;		\
-	inc		%o5			/*  IEU1		*/;		\
-	add		%o2, %o3, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%T0, %U0, %o3		/*  FPM			*/;		\
-	srl		%o4, 1, %o4		/*  IEU0	Group	*/;		\
-	inc		%g1			/*  IEU1		*/;		\
-	sub		%o2, %o4, %o2		/*  IEU0	Group	*/;		\
-	fcmpgt32	%fz, %U0, %o4		/*  FPM			*/;		\
-	srl		%o5, 1, %o5		/*  IEU0	Group	*/;		\
-	inc		%g2			/*  IEU1		*/;		\
-	srl		%g1, 1, %g1		/*  IEU0	Group	*/;		\
-	sub		%o2, %o5, %o2		/*  IEU1		*/;		\
-	std		%U0, [%sp + STACKOFF]	/*  Store		*/;		\
-	srl		%g2, 1, %g2		/*  IEU0	Group	*/;		\
-	sub		%o2, %g1, %o2		/*  IEU1		*/;		\
-	inc		%g3			/*  IEU0	Group	*/;		\
-	sub		%o2, %g2, %o2		/*  IEU1		*/;		\
-	srl		%g3, 1, %g3		/*  IEU0	Group	*/;		\
-	inc		%g5			/*  IEU1		*/;		\
-	srl		%g5, 1, %g5		/*  IEU0	Group	*/;		\
-	sub		%o2, %g3, %o2		/*  IEU1		*/;		\
-	ldx		[%sp + STACKOFF], %o5	/*  Load	Group	*/;		\
-	inc		%g7			/*  IEU0		*/;		\
-	sub		%o2, %g5, %o2		/*  IEU1		*/;		\
-	srl		%g7, 1, %g7		/*  IEU0	Group	*/;		\
-	inc		%o3			/*  IEU1		*/;		\
-	srl		%o3, 1, %o3		/*  IEU0	Group	*/;		\
-	sub		%o2, %g7, %o2		/*  IEU1		*/;		\
-	inc		%o4			/*  IEU0	Group	*/;		\
-	add		%o2, %o3, %o2		/*  IEU1		*/;		\
-	srl		%o4, 1, %o4		/*  IEU0	Group	*/;		\
-	sub		%o2, %o4, %o2		/*  IEU0	Group	*/;		\
-	addcc		%o2, %o5, %o2		/*  IEU1	Group	*/;		\
-	bcs,a,pn	%xcc, 33f		/*  CTI			*/;		\
-	 add		%o2, 1, %o2		/*  IEU0		*/;		\
-33:						/*  That's it		*/;
-
-#define CSUM_LASTCHUNK(offset)								\
-        ldx             [%o0 - offset - 0x10], %g2;					\
-        ldx             [%o0 - offset - 0x08], %g3;					\
-        addcc           %g2, %o2, %o2;							\
-        bcs,a,pn        %xcc, 31f;							\
-         add            %o2, 1, %o2;							\
-31:     addcc           %g3, %o2, %o2;							\
-        bcs,a,pn        %xcc, 32f;							\
-         add            %o2, 1, %o2;							\
-32:
-
-	.text
-	.globl		csum_partial
-	.align		32
-csum_partial:
-	andcc		%o0, 7, %g0		/*  IEU1	Group		*/
-	be,pt		%icc, 4f		/*  CTI				*/
-	 andcc		%o0, 0x38, %g3		/*  IEU1			*/
-	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			*/
-	lduh		[%o0], %g2		/*  Load			*/
-	sub		%o1, 2, %o1		/*  IEU0	Group		*/
-	add		%o0, 2, %o0		/*  IEU1			*/
-	andcc		%o0, 4, %g7		/*  IEU1	Group		*/
-	sll		%g5, 16, %g5		/*  IEU0			*/
-	sll		%g2, 16, %g2		/*  IEU0	Group 		*/
-	addcc		%g2, %o2, %o2		/*  IEU1	Group (regdep)	*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%o2, %g5, %o2		/*  IEU0			*/
-1:	ld		[%o0], %g2		/*  Load			*/
-	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group		*/
-	 and		%o0, 0x38, %g3		/*  IEU0			*/
-	add		%o0, 4, %o0		/*  IEU0	Group		*/
-	sub		%o1, 4, %o1		/*  IEU1			*/
-	addcc		%g2, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	and		%o0, 0x38, %g3		/*  IEU1	Group		*/
-4:	srl		%o2, 0, %o2		/*  IEU0	Group		*/
-	mov		0x40, %g1		/*  IEU1			*/
-	brz,pn		%g3, 3f			/*  CTI+IEU1	Group		*/
-	 sub		%g1, %g3, %g1		/*  IEU0			*/
-	cmp		%o1, 56			/*  IEU1	Group		*/
-	blu,pn		%icc, 20f		/*  CTI				*/
-	 andcc		%o0, 8, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 ldx		[%o0], %g2		/*  Load			*/
-	add		%o0, 8, %o0		/*  IEU0	Group		*/
-	sub		%o1, 8, %o1		/*  IEU1			*/
-	addcc		%g2, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 2f		/*  CTI				*/
-	 and		%g1, 0x20, %g1		/*  IEU0			*/
-	ldx		[%o0], %g2		/*  Load			*/
-	ldx		[%o0+8], %g3		/*  Load	Group		*/
-	add		%o0, 16, %o0		/*  IEU0			*/
-	sub		%o1, 16, %o1		/*  IEU1			*/
-	addcc		%g2, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	addcc		%g3, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 2f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-2:	brz,pn		%g1, 3f			/*  CTI+IEU1	Group		*/
-	 ldx		[%o0], %g2		/*  Load			*/
-	ldx		[%o0+8], %g3		/*  Load	Group		*/
-	ldx		[%o0+16], %g5		/*  Load	Group		*/
-	ldx		[%o0+24], %g7		/*  Load	Group		*/
-	add		%o0, 32, %o0		/*  IEU0			*/
-	sub		%o1, 32, %o1		/*  IEU1			*/
-	addcc		%g2, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	addcc		%g3, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	addcc		%g5, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	addcc		%g7, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 3f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-3:	cmp		%o1, 0xc0		/*  IEU1	Group		*/
-	blu,pn		%icc, 20f		/*  CTI				*/
-	 sllx		%o2, 32, %g5		/*  IEU0			*/
-#ifdef __KERNEL__
-	VISEntry
-#endif
-	addcc		%o2, %g5, %o2		/*  IEU1	Group		*/
-	sub		%o1, 0xc0, %o1		/*  IEU0			*/
-	wr		%g0, ASI_BLK_P, %asi	/*  LSU		Group		*/
-	membar		#StoreLoad		/*  LSU		Group		*/
-	srlx		%o2, 32, %o2		/*  IEU0	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU1			*/
-1:	andcc		%o1, 0x80, %g0		/*  IEU1	Group		*/
-	bne,pn		%icc, 7f		/*  CTI				*/
-	 andcc		%o1, 0x40, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 6f		/*  CTI				*/
-	 fzero		%f12			/*  FPA				*/
-	fzero		%f14			/*  FPA		Group		*/
-	ldda		[%o0 + 0x000] %asi, %f16
-	ldda		[%o0 + 0x040] %asi, %f32
-	ldda		[%o0 + 0x080] %asi, %f48
-	START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
-	ba,a,pt		%xcc, 3f
-6:	sub		%o0, 0x40, %o0		/*  IEU0	Group		*/
-	fzero		%f28			/*  FPA				*/
-	fzero		%f30			/*  FPA		Group		*/
-	ldda		[%o0 + 0x040] %asi, %f32
-	ldda		[%o0 + 0x080] %asi, %f48
-	ldda		[%o0 + 0x0c0] %asi, %f0
-	START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
-	ba,a,pt		%xcc, 4f
-7:	bne,pt		%icc, 8f		/*  CTI				*/
-	 fzero		%f44			/*  FPA				*/
-	add		%o0, 0x40, %o0		/*  IEU0	Group		*/
-	fzero		%f60			/*  FPA				*/
-	fzero		%f62			/*  FPA		Group		*/
-	ldda		[%o0 - 0x040] %asi, %f0
-	ldda		[%o0 + 0x000] %asi, %f16
-	ldda		[%o0 + 0x040] %asi, %f32
-	START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
-	ba,a,pt		%xcc, 2f
-8:	add		%o0, 0x80, %o0		/*  IEU0	Group		*/
-	fzero		%f46			/*  FPA				*/
-	ldda		[%o0 - 0x080] %asi, %f48
-	ldda		[%o0 - 0x040] %asi, %f0
-	ldda		[%o0 + 0x000] %asi, %f16
-	START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58)
-1:	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
-	ldda		[%o0 + 0x040] %asi, %f32
-2:	DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
-	ldda		[%o0 + 0x080] %asi, %f48
-3:	DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
-	ldda		[%o0 + 0x0c0] %asi, %f0
-4:	DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
-	add		%o0, 0x100, %o0		/*  IEU0	Group		*/
-	subcc		%o1, 0x100, %o1		/*  IEU1			*/
-	bgeu,a,pt	%icc, 1b		/*  CTI				*/
-	 ldda		[%o0 + 0x000] %asi, %f16
-	membar		#Sync			/*  LSU		Group		*/
-	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
-	END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
-#ifdef __KERNEL__
-	ldub		[%g6 + TI_CURRENT_DS], %g7
-#endif
-	and		%o1, 0x3f, %o1		/*  IEU0	Group		*/
-#ifdef __KERNEL__
-	VISExit
-	wr		%g7, %g0, %asi
-#endif
-20:	andcc		%o1, 0xf0, %g1		/*  IEU1	Group		*/
-	be,pn		%icc, 23f		/*  CTI				*/
-	 and		%o1, 0xf, %o3		/*  IEU0			*/
-#ifdef __KERNEL__
-22:	sll		%g1, 1, %o4		/*  IEU0	Group		*/
-	sethi		%hi(23f), %g7		/*  IEU1			*/
-	sub		%g7, %o4, %g7		/*  IEU0	Group		*/
-	jmpl		%g7 + %lo(23f), %g0	/*  CTI		Group brk forced*/
-	 add		%o0, %g1, %o0		/*  IEU0			*/
-#else
-22:	rd		%pc, %g7		/*  LSU		Group+4bubbles	*/
-	sll		%g1, 1, %o4		/*  IEU0	Group		*/
-	sub		%g7, %o4, %g7		/*  IEU0	Group (regdep)	*/
-	jmpl		%g7 + (23f - 22b), %g0	/*  CTI		Group brk forced*/
-	 add		%o0, %g1, %o0		/*  IEU0			*/
-#endif
-	CSUM_LASTCHUNK(0xe0)
-	CSUM_LASTCHUNK(0xd0)
-	CSUM_LASTCHUNK(0xc0)
-	CSUM_LASTCHUNK(0xb0)
-	CSUM_LASTCHUNK(0xa0)
-	CSUM_LASTCHUNK(0x90)
-	CSUM_LASTCHUNK(0x80)
-	CSUM_LASTCHUNK(0x70)
-	CSUM_LASTCHUNK(0x60)
-	CSUM_LASTCHUNK(0x50)
-	CSUM_LASTCHUNK(0x40)
-	CSUM_LASTCHUNK(0x30)
-	CSUM_LASTCHUNK(0x20)
-	CSUM_LASTCHUNK(0x10)
-	CSUM_LASTCHUNK(0x00)
-23:	brnz,pn		%o3, 26f		/*  CTI+IEU1	Group		*/
-24:	 sllx		%o2, 32, %g1		/*  IEU0			*/
-25:	addcc		%o2, %g1, %o0		/*  IEU1	Group		*/
-	srlx		%o0, 32, %o0		/*  IEU0	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o0, 1, %o0		/*  IEU1			*/
-1:	retl					/*  CTI		Group brk forced*/
-	 srl		%o0, 0, %o0		/*  IEU0			*/
-26:	andcc		%o1, 8, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 ldx		[%o0], %g3		/*  Load			*/
-	add		%o0, 8, %o0		/*  IEU0	Group		*/
-	addcc		%g3, %o2, %o2		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	andcc		%o1, 4, %g0		/*  IEU1	Group		*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g2			/*  IEU0			*/
-	ld		[%o0], %g2		/*  Load			*/
-	add		%o0, 4, %o0		/*  IEU0	Group		*/
-	sllx		%g2, 32, %g2		/*  IEU0	Group		*/
-1:	andcc		%o1, 2, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o4			/*  IEU0	Group		*/
-	lduh		[%o0], %o4		/*  Load			*/
-	add		%o0, 2, %o0		/*  IEU1			*/
-	sll		%o4, 16, %o4		/*  IEU0	Group		*/
-1:	andcc		%o1, 1, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o5			/*  IEU0	Group		*/
-	ldub		[%o0], %o5		/*  Load			*/
-	sll		%o5, 8, %o5		/*  IEU0	Group		*/
-1:	or		%g2, %o4, %o4		/*  IEU1			*/
-	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)	*/
-	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%o2, 1, %o2		/*  IEU0			*/
-1:	ba,pt		%xcc, 25b		/*  CTI		Group		*/
-	 sllx		%o2, 32, %g1		/*  IEU0			*/
-21:	srl		%o2, 0, %o2		/*  IEU0	Group		*/
-	cmp		%o1, 0			/*  IEU1			*/
-	be,pn		%icc, 24b		/*  CTI				*/
-	 andcc		%o1, 4, %g0		/*  IEU1	Group		*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g2			/*  IEU0			*/
-	lduh		[%o0], %g3		/*  Load			*/
-	lduh		[%o0+2], %g2		/*  Load	Group		*/
-	add		%o0, 4, %o0		/*  IEU0	Group		*/
-	sllx		%g3, 48, %g3		/*  IEU0	Group		*/
-	sllx		%g2, 32, %g2		/*  IEU0	Group		*/
-	or		%g3, %g2, %g2		/*  IEU0	Group		*/
-1:	andcc		%o1, 2, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o4			/*  IEU0	Group		*/
-	lduh		[%o0], %o4		/*  Load			*/
-	add		%o0, 2, %o0		/*  IEU1			*/
-	sll		%o4, 16, %o4		/*  IEU0	Group		*/
-1:	andcc		%o1, 1, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o5			/*  IEU0	Group		*/
-	ldub		[%o0], %o5		/*  Load			*/
-	sll		%o5, 8, %o5		/*  IEU0	Group		*/
-1:	or		%g2, %o4, %o4		/*  IEU1			*/
-	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)	*/
-	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 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 --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
deleted file mode 100644
--- a/arch/sparc64/lib/VIScsumcopy.S
+++ /dev/null
@@ -1,897 +0,0 @@
-/* $Id: VIScsumcopy.S,v 1.8 2000/02/20 23:21:39 davem Exp $
- * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
- *            copying utilizing the UltraSparc Visual Instruction Set.
- *
- * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- * Based on older sparc32/sparc64 checksum.S, which is:
- *
- *      Copyright(C) 1995 Linus Torvalds
- *      Copyright(C) 1995 Miguel de Icaza
- *      Copyright(C) 1996,1997 David S. Miller
- *    derived from:
- *	  Linux/Alpha checksum c-code
- *        Linux/ix86 inline checksum assembly
- *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
- *	  David Mosberger-Tang for optimized reference c-code
- *	  BSD4.4 portable checksum routine
- */
-
-#ifdef __sparc_v9__
-#define STACKOFF	0x7ff+128
-#else
-#define STACKOFF	64
-#endif
-
-#ifdef __KERNEL__
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/visasm.h>
-#include <asm/thread_info.h>
-#define ASI_BLK_XOR	0
-#define ASI_BLK_XOR1	(ASI_BLK_P ^ (ASI_BLK_P >> 3) ^ ASI_P)
-#define ASI_BLK_OR	(ASI_BLK_P & ~ASI_P)
-#else
-#define ASI_P		0x80
-#define ASI_BLK_P	0xf0
-#define FRPS_FEF	0x04
-#define FPRS_DU		0x02
-#define FPRS_DL		0x01
-#define ASI_BLK_XOR	(ASI_BLK_P ^ ASI_P)
-#endif
-
-#define src		o0
-#define dst		o1
-#define	len		o2
-#define sum		o3
-#define x1		g1
-#define x2		g2
-#define x3		o4
-#define x4		g4
-#define x5		g5
-#define x6		g7
-#define x7		g3
-#define x8		o5
-
-/* Dobrou noc, SunSoft engineers. Spete sladce.
- * This has a couple of tricks in and those
- * tricks are UltraLinux trade secrets :))
- * Once AGAIN, the SunSoft engineers are caught
- * asleep at the keyboard :)).
- * The main loop does about 20 superscalar cycles
- * per 64bytes checksummed/copied.
- */
-
-#define LDBLK(O0)									\
-	ldda		[%src] %asi, %O0 	/*  Load	Group		*/
-
-#define STBLK										\
-	stda		%f48, [%dst] ASI_BLK_P	/*  Store			*/
-
-#define ST(fx,off)									\
-	std		%fx, [%dst + off]	/*  Store			*/
-
-#define SYNC										\
-	membar		#Sync
-
-
-#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...)	\
-	LOAD					/*  Load	(Group)		*/;	\
-	faligndata	%A14, %F0, %A14		/*  FPA		Group		*/;	\
-	inc		%x5			/*  IEU0			*/;	\
-	STORE1					/*  Store (optional)		*/;	\
-	faligndata	%F0, %F2, %A0		/*  FPA		Group		*/;	\
-	srl		%x5, 1, %x5		/*  IEU0			*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	fpadd32		%F0, %f0, %F0		/*  FPA		Group		*/;	\
-	inc		%x6			/*  IEU0			*/;	\
-	STORE2					/*  Store (optional)		*/;	\
-	faligndata	%F2, %F4, %A2		/*  FPA		Group		*/;	\
-	srl		%x6, 1, %x6		/*  IEU0			*/;	\
-	add		%sum, %x5, %sum		/*  IEU1			*/;	\
-	fpadd32		%F2, %f2, %F2		/*  FPA		Group		*/;	\
-	add		%src, 64, %src		/*  IEU0			*/;	\
-	fcmpgt32	%f0, %F0, %x1		/*  FPM				*/;	\
-	add		%dst, 64, %dst		/*  IEU1	Group		*/;	\
-	inc		%x7			/*  IEU0			*/;	\
-	STORE3					/*  Store (optional)		*/;	\
-	faligndata	%F4, %F6, %A4		/*  FPA				*/;	\
-	fpadd32		%F4, %f4, %F4		/*  FPA		Group		*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	fcmpgt32	%f2, %F2, %x2		/*  FPM				*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	inc		%x8			/*  IEU1			*/;	\
-	STORE4					/*  Store (optional)		*/;	\
-	faligndata	%F6, %F8, %A6		/*  FPA				*/;	\
-	fpadd32		%F6, %f6, %F6		/*  FPA		Group		*/;	\
-	srl		%x8, 1, %x8		/*  IEU0			*/;	\
-	fcmpgt32	%f4, %F4, %x3		/*  FPM				*/;	\
-	add		%sum, %x7, %sum		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	STORE5					/*  Store (optional)		*/;	\
-	faligndata	%F8, %F10, %A8		/*  FPA				*/;	\
-	fpadd32		%F8, %f8, %F8		/*  FPA		Group		*/;	\
-	srl		%x1, 1, %x1		/*  IEU0			*/;	\
-	fcmpgt32	%f6, %F6, %x4		/*  FPM				*/;	\
-	add		%sum, %x8, %sum		/*  IEU0	Group		*/;	\
-	inc		%x2			/*  IEU1			*/;	\
-	STORE6					/*  Store (optional)		*/;	\
-	faligndata	%F10, %F12, %A10	/*  FPA				*/;	\
-	fpadd32		%F10, %f10, %F10	/*  FPA		Group		*/;	\
-	srl		%x2, 1, %x2		/*  IEU0			*/;	\
-	fcmpgt32	%f8, %F8, %x5		/*  FPM				*/;	\
-	add		%sum, %x1, %sum		/*  IEU0	Group		*/;	\
-	inc		%x3			/*  IEU1			*/;	\
-	STORE7					/*  Store (optional)		*/;	\
-	faligndata	%F12, %F14, %A12	/*  FPA				*/;	\
-	fpadd32		%F12, %f12, %F12	/*  FPA		Group		*/;	\
-	srl		%x3, 1, %x3		/*  IEU0			*/;	\
-	fcmpgt32	%f10, %F10, %x6		/*  FPM				*/;	\
-	add		%sum, %x2, %sum		/*  IEU0	Group		*/;	\
-	inc		%x4			/*  IEU1			*/;	\
-	STORE8					/*  Store (optional)		*/;	\
-	fmovd		%F14, %B14		/*  FPA				*/;	\
-	fpadd32		%F14, %f14, %F14	/*  FPA		Group		*/;	\
-	srl		%x4, 1, %x4		/*  IEU0			*/;	\
-	fcmpgt32	%f12, %F12, %x7		/*  FPM				*/;	\
-	add		%sum, %x3, %sum		/*  IEU0	Group		*/;	\
-	subcc		%len, 64, %len		/*  IEU1			*/;	\
-	BRANCH					/*  CTI				*/;	\
-	fcmpgt32	%f14, %F14, %x8		/*  FPM		Group		*/;
-
-#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
-	inc		%x5			/*  IEU0	Group		*/;	\
-	fpadd32		%f2, %f0, %S0		/*  FPA				*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	fpadd32		%f6, %f4, %S1		/*  FPA				*/;	\
-	inc		%x6			/*  IEU1			*/;	\
-	fpadd32		%f10, %f8, %S2		/*  FPA		Group		*/;	\
-	add		%sum, %x5, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%f0, %S0, %x1		/*  FPM				*/;	\
-	fpadd32		%f14, %f12, %S3		/*  FPA		Group		*/;	\
-	srl		%x6, 1, %x6		/*  IEU0			*/;	\
-	fcmpgt32	%f4, %S1, %x2		/*  FPM				*/;	\
-	add		%sum, %x6, %sum		/*  IEU0	Group		*/;	\
-	fzero		%fz			/*  FPA				*/;	\
-	fcmpgt32	%f8, %S2, %x3		/*  FPM				*/;	\
-	inc		%x7			/*  IEU0	Group		*/;	\
-	inc		%x8			/*  IEU1			*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	fpadd32		%S0, %S1, %T0		/*  FPA				*/;	\
-	fpadd32		%S2, %S3, %T1		/*  FPA		Group		*/;	\
-	add		%sum, %x7, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%f12, %S3, %x4		/*  FPM				*/;	\
-	srl		%x8, 1, %x8		/*  IEU0	Group		*/;	\
-	inc		%x2			/*  IEU1			*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	add		%sum, %x8, %sum		/*  IEU1			*/;	\
-	add		%sum, %x1, %sum		/*  IEU0	Group		*/;	\
-	fcmpgt32	%S0, %T0, %x5		/*  FPM				*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	fcmpgt32	%S2, %T1, %x6		/*  FPM				*/;	\
-	inc		%x3			/*  IEU0	Group		*/;	\
-	add		%sum, %x2, %sum		/*  IEU1			*/;	\
-	srl		%x3, 1, %x3		/*  IEU0	Group		*/;	\
-	inc		%x4			/*  IEU1			*/;	\
-	fpadd32		%T0, %T1, %U0		/*  FPA		Group		*/;	\
-	add		%sum, %x3, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%fz, %f2, %x7		/*  FPM				*/;	\
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %f6, %x8		/*  FPM				*/;	\
-	inc		%x5			/*  IEU0	Group		*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %f10, %x1		/*  FPM				*/;	\
-	inc		%x6			/*  IEU0	Group		*/;	\
-	add		%sum, %x5, %sum		/*  IEU1			*/;	\
-	fmovd		%FA, %FB		/*  FPA		Group		*/;	\
-	fcmpgt32	%fz, %f14, %x2		/*  FPM				*/;	\
-	srl		%x6, 1, %x6		/*  IEU0	Group		*/;	\
-	ba,pt		%xcc, ett		/*  CTI				*/;	\
-	 inc		%x7			/*  IEU1			*/;
-
-#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) 				\
-	END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
-
-#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) 					\
-	fpadd32		%U0, %U1, %V0		/*  FPA		Group		*/;	\
-	srl		%x7, 1, %x7		/*  IEU0			*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	std		%V0, [%sp + STACKOFF]	/*  Store	Group		*/;	\
-	inc		%x8			/*  IEU0			*/;	\
-	sub		%sum, %x7, %sum		/*  IEU1			*/;	\
-	srl		%x8, 1, %x8		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %S1, %x3		/*  FPM				*/;	\
-	inc		%x1			/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %S3, %x4		/*  FPM				*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	sub		%sum, %x8, %sum		/*  IEU1			*/;	\
-	ldx		[%sp + STACKOFF], %x8	/*  Load	Group		*/;	\
-	inc		%x2			/*  IEU0			*/;	\
-	sub		%sum, %x1, %sum		/*  IEU1			*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %T1, %x5		/*  FPM				*/;	\
-	inc		%x3			/*  IEU0	Group		*/;	\
-	fcmpgt32	%T0, %U0, %x6		/*  FPM				*/;	\
-	srl		%x3, 1, %x3		/*  IEU0	Group		*/;	\
-	sub		%sum, %x2, %sum		/*  IEU1			*/;	\
-	inc		%x4			/*  IEU0	Group		*/;	\
-	sub		%sum, %x3, %sum		/*  IEU1			*/;	\
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %U1, %x7		/*  FPM				*/;	\
-	inc		%x5			/*  IEU0	Group		*/;	\
-	fcmpgt32	%U0, %V0, %x1		/*  FPM				*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	sub		%sum, %x4, %sum		/*  IEU1			*/;	\
-	sub		%sum, %x5, %sum		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %V0, %x2		/*  FPM				*/;	\
-	inc		%x6			/*  IEU0	Group		*/;	\
-	inc		%x7			/*  IEU1			*/;	\
-	srl		%x6, 1, %x6		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	sub		%sum, %x7, %sum		/*  IEU1			*/;	\
-	inc		%x2			/*  IEU0	Group		*/;	\
-	add		%sum, %x1, %sum		/*  IEU1			*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	sub		%sum, %x2, %sum		/*  IEU0	Group		*/;	\
-	addcc		%sum, %x8, %sum		/*  IEU1	Group		*/;	\
-	bcs,a,pn	%xcc, 33f		/*  CTI				*/;	\
-	 add		%sum, 1, %sum		/*  IEU0	(Group)		*/;	\
-33:						/*  That's it			*/;
-
-	.text
-	.globl		csum_partial_copy_vis
-	.align		32
-/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp.
- * csum_partial_copy_from_user
- * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256
- */
-csum_partial_copy_vis:
-	andcc		%dst, 7, %g0		/*  IEU1	Group		*/
-	be,pt		%icc, 4f		/*  CTI				*/
-	 and		%dst, 0x38, %o4		/*  IEU0			*/
-	mov		1, %g5			/*  IEU0	Group		*/
-	andcc		%dst, 2, %g0		/*  IEU1			*/
-	be,pt		%icc, 1f		/*  CTI				*/
-	 and		%dst, 4, %g7		/*  IEU0	Group		*/
-	lduha		[%src] %asi, %g2	/*  Load			*/
-	sub		%len, 2, %len		/*  IEU0	Group		*/
-	add		%dst, 2, %dst		/*  IEU1			*/
-	andcc		%dst, 4, %g7		/*  IEU1	Group		*/
-	sll		%g5, 16, %g5		/*  IEU0			*/
-	sth		%g2, [%dst - 2]		/*  Store	Group		*/
-	sll		%g2, 16, %g2		/*  IEU0	 		*/
-	add		%src, 2, %src		/*  IEU1			*/
-	addcc		%g2, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%sum, %g5, %sum		/*  IEU0			*/
-1:	lduwa		[%src] %asi, %g2	/*  Load			*/
-	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group		*/
-	 and		%dst, 0x38, %o4		/*  IEU0			*/
-	add		%dst, 4, %dst		/*  IEU0	Group		*/
-	sub		%len, 4, %len		/*  IEU1			*/
-	addcc		%g2, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	and		%dst, 0x38, %o4		/*  IEU0	Group		*/
-	stw		%g2, [%dst - 4]		/*  Store			*/
-	add		%src, 4, %src		/*  IEU1			*/
-4:
-#ifdef __KERNEL__
-	VISEntry
-#endif
-	mov		%src, %g7		/*  IEU1	Group		*/
-	fzero		%f48			/*  FPA				*/
-	alignaddr	%src, %g0, %src		/*  Single	Group		*/
-	subcc		%g7, %src, %g7		/*  IEU1	Group		*/
-	be,pt		%xcc, 1f		/*  CTI				*/
-	 mov		0x40, %g1		/*  IEU0			*/
-	lduwa		[%src] %asi, %g2	/*  Load	Group		*/
-	subcc		%sum, %g2, %sum		/*  IEU1	Group+load stall*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 sub		%sum, 1, %sum		/*  IEU0			*/
-1:	srl		%sum, 0, %sum		/*  IEU0	Group		*/
-	clr		%g5			/*  IEU1			*/
-	brz,pn		%o4, 3f			/*  CTI+IEU1	Group		*/
-	 sub		%g1, %o4, %g1		/*  IEU0			*/
-	ldda		[%src] %asi, %f0	/*  Load			*/
-	clr		%o4			/*  IEU0	Group		*/
-	andcc		%dst, 8, %g0		/*  IEU1			*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 ldda		[%src + 8] %asi, %f2	/*  Load	Group		*/
-	add		%src, 8, %src		/*  IEU0			*/
-	sub		%len, 8, %len		/*  IEU1			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	addcc		%dst, 8, %dst		/*  IEU1	Group		*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %o4		/*  FPM		Group		*/
-	fmovd		%f2, %f0		/*  FPA		Group		*/
-	ldda		[%src + 8] %asi, %f2	/*  Load			*/
-	std		%f16, [%dst - 8]	/*  Store			*/
-	fmovd		%f50, %f48		/*  FPA				*/
-1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 and		%g1, 0x20, %g1		/*  IEU0			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	ldda		[%src + 16] %asi, %f4	/*  Load	Group		*/
-	add		%src, 16, %src		/*  IEU0			*/
-	add		%dst, 16, %dst		/*  IEU1			*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group		*/
-	sub		%len, 16, %len		/*  IEU0			*/
-	inc		%o4			/*  IEU1			*/
-	std		%f16, [%dst - 16]	/*  Store	Group		*/
-	fpadd32		%f2, %f50, %f48		/*  FPA				*/
-	srl		%o4, 1, %o5		/*  IEU0			*/
-	faligndata	%f2, %f4, %f18		/*  FPA		Group		*/
-	std		%f18, [%dst - 8]	/*  Store			*/
-	fcmpgt32	%f50, %f48, %o4		/*  FPM		Group		*/
-	add		%o5, %sum, %sum		/*  IEU0			*/
-	ldda		[%src + 8] %asi, %f2	/*  Load			*/
-	fmovd		%f4, %f0		/*  FPA				*/
-1:	brz,a,pn	%g1, 4f			/*  CTI+IEU1	Group		*/
-	 rd		%asi, %g2		/*  LSU		Group + 4 bubbles*/
-	inc		%g5			/*  IEU0			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	ldda		[%src + 16] %asi, %f4	/*  Load	Group		*/
-	srl		%g5, 1, %g5		/*  IEU0			*/
-	add		%dst, 32, %dst		/*  IEU1			*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %o5		/*  FPM		Group		*/
-	inc		%o4			/*  IEU0			*/
-	ldda		[%src + 24] %asi, %f6	/*  Load			*/
-	srl		%o4, 1, %o4		/*  IEU0	Group		*/
-	add		%g5, %sum, %sum		/*  IEU1			*/
-	ldda		[%src + 32] %asi, %f8	/*  Load			*/
-	fpadd32		%f2, %f50, %f48		/*  FPA				*/
-	faligndata	%f2, %f4, %f18		/*  FPA		Group		*/
-	sub		%len, 32, %len		/*  IEU0			*/
-	std		%f16, [%dst - 32]	/*  Store			*/
-	fcmpgt32	%f50, %f48, %g3		/*  FPM		Group		*/
-	inc		%o5			/*  IEU0			*/
-	add		%o4, %sum, %sum		/*  IEU1			*/
-	fpadd32		%f4, %f48, %f50		/*  FPA				*/
-	faligndata	%f4, %f6, %f20		/*  FPA		Group		*/
-	srl		%o5, 1, %o5		/*  IEU0			*/
-	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group		*/
-	add		%o5, %sum, %sum		/*  IEU0			*/
-	std		%f18, [%dst - 24]	/*  Store			*/
-	fpadd32		%f6, %f50, %f48		/*  FPA				*/
-	inc		%g3			/*  IEU0	Group		*/
-	std		%f20, [%dst - 16]	/*  Store			*/
-	add		%src, 32, %src		/*  IEU1			*/
-	faligndata	%f6, %f8, %f22		/*  FPA				*/
-	fcmpgt32	%f50, %f48, %o4		/*  FPM		Group		*/
-	srl		%g3, 1, %g3		/*  IEU0			*/
-	std		%f22, [%dst - 8]	/*  Store			*/	
-	add		%g3, %sum, %sum		/*  IEU0	Group		*/
-3:	rd		%asi, %g2		/*  LSU		Group + 4 bubbles*/
-#ifdef __KERNEL__
-4:	sethi		%hi(vis0s), %g7		/*  IEU0	Group		*/
-	or		%g2, ASI_BLK_OR, %g2	/*  IEU1			*/
-#else
-4:	rd		%pc, %g7		/*  LSU		Group + 4 bubbles*/
-#endif
-	inc		%g5			/*  IEU0	Group		*/
-	and		%src, 0x38, %g3		/*  IEU1			*/	
-	membar		#StoreLoad		/*  LSU		Group		*/
-	srl		%g5, 1, %g5		/*  IEU0			*/
-	inc		%o4			/*  IEU1			*/
-	sll		%g3, 8, %g3		/*  IEU0	Group		*/
-	sub		%len, 0xc0, %len	/*  IEU1			*/
-	addcc		%g5, %sum, %sum		/*  IEU1	Group		*/
-	srl		%o4, 1, %o4		/*  IEU0			*/
-	add		%g7, %g3, %g7		/*  IEU0	Group		*/
-	add		%o4, %sum, %sum		/*  IEU1			*/
-#ifdef __KERNEL__
-	jmpl		%g7 + %lo(vis0s), %g0	/*  CTI+IEU1	Group		*/
-#else
-	jmpl		%g7 + (vis0s - 4b), %g0	/*  CTI+IEU1	Group		*/
-#endif
-	 fzero		%f32			/*  FPA				*/
-
-	.align		2048
-vis0s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	add		%src, 128, %src		/*  IEU0	Group		*/
-	ldda		[%src-128] %asi, %f0	/*  Load	Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f48, %f62		/*  FPA		Group	f0 available*/
-	faligndata	%f0, %f2, %f48		/*  FPA		Group	f2 available*/
-	fcmpgt32	%f32, %f2, %x1		/*  FPM		Group	f4 available*/
-	fpadd32		%f0, %f62, %f0		/*  FPA				*/
-	fcmpgt32	%f32, %f4, %x2		/*  FPM		Group	f6 available*/
-	faligndata	%f2, %f4, %f50		/*  FPA				*/
-	fcmpgt32	%f62, %f0, %x3		/*  FPM		Group	f8 available*/
-	faligndata	%f4, %f6, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group	f10 available*/
-	inc		%x1			/*  IEU0			*/
-	faligndata	%f6, %f8, %f54		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group	f12 available*/
-	srl		%x1, 1, %x1		/*  IEU0			*/
-	inc		%x2			/*  IEU1			*/
-	faligndata	%f8, %f10, %f56		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group	f14 available*/
-	srl		%x2, 1, %x2		/*  IEU0			*/
-	add		%sum, %x1, %sum		/*  IEU1			*/
-	faligndata	%f10, %f12, %f58	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	add		%sum, %x2, %sum		/*  IEU1			*/
-	faligndata	%f12, %f14, %f60	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f62		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis0:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,
-			,LDBLK(f32),	STBLK,,,,,,,,
-			,bcs,pn %icc, vis0e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,
-			,LDBLK(f0),	STBLK,,,,,,,,
-			,bcs,pn %icc, vis0e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,
-			,LDBLK(f16),	STBLK,,,,,,,,
-			,bcc,pt %icc, vis0)
-vis0e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f32,
-			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
-vis0e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f0,
-			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
-vis0e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f16,
-			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis1s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	add		%src, 128 - 8, %src	/*  IEU0	Group		*/
-	ldda		[%src-128] %asi, %f0	/*  Load	Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f0, %f58		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f2, %x2		/*  FPM		Group		*/
-	faligndata	%f2, %f4, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group		*/
-	faligndata	%f4, %f6, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	inc		%x2			/*  IEU1			*/
-	faligndata	%f8, %f10, %f54		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	srl		%x2, 1, %x2		/*  IEU0			*/
-	faligndata	%f10, %f12, %f56	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	add		%sum, %x2, %sum		/*  IEU1			*/
-	faligndata	%f12, %f14, %f58	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f60		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis1:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f32),	,STBLK,,,,,,,
-			,bcs,pn %icc, vis1e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f0),	,STBLK,,,,,,,
-			,bcs,pn %icc, vis1e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f16),	,STBLK,,,,,,,
-			,bcc,pt %icc, vis1)
-vis1e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f32,
-			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
-vis1e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f62,f48,f50,f52,f54,f56,f58,f60,f0,
-			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
-vis1e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f16,
-			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis2s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	add		%src, 128 - 16, %src	/*  IEU0	Group		*/
-	ldda		[%src-128] %asi, %f0	/*  Load	Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f0, %f56		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/	
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group		*/
-	faligndata	%f4, %f6, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f54	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	faligndata	%f12, %f14, %f56	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f58		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis2:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f32),	,,STBLK,,,,,,
-			,bcs,pn %icc, vis2e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f0),	,,STBLK,,,,,,
-			,bcs,pn %icc, vis2e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f16),	,,STBLK,,,,,,
-			,bcc,pt %icc, vis2)
-vis2e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f32,
-			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
-vis2e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f60,f62,f48,f50,f52,f54,f56,f58,f0,
-			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
-vis2e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f16,
-			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis3s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	add		%src, 128 - 24, %src	/*  IEU0	Group		*/
-	ldda		[%src-128] %asi, %f0	/*  Load	Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f0, %f54		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fpsub32		%f4, %f4, %f4		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f52	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f54	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f56		/*  FPA				*/
-	inc		%x4			/*  IEU0			*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-vis3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f32),	,,,STBLK,,,,,
-			,bcs,pn %icc, vis3e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f0),	,,,STBLK,,,,,
-			,bcs,pn %icc, vis3e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f16),	,,,STBLK,,,,,
-			,bcc,pt %icc, vis3)
-vis3e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f32,
-			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
-vis3e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f58,f60,f62,f48,f50,f52,f54,f56,f0,
-			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
-vis3e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f16,
-			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis4s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	add		%src, 128 - 32, %src	/*  IEU0	Group		*/
-	ldda		[%src-128] %asi, %f0	/*  Load	Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f0, %f52		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fpsub32		%f4, %f4, %f4		/*  FPA		Group		*/
-	fpsub32		%f6, %f6, %f6		/*  FPA		Group		*/
-	clr		%x4			/*  IEU0			*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f50	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f52	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f54		/*  FPA				*/
-vis4:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f32),	,,,,STBLK,,,,
-			,bcs,pn %icc, vis4e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f0),	,,,,STBLK,,,,
-			,bcs,pn %icc, vis4e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f16),	,,,,STBLK,,,,
-			,bcc,pt %icc, vis4)
-vis4e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f32,
-			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
-vis4e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f56,f58,f60,f62,f48,f50,f52,f54,f0,
-			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
-vis4e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f16,
-			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis5s:	add		%src, 128 - 40, %src	/*  IEU0	Group		*/
-	ldda		[%src-88] %asi, %f10	/*  Load	Group		*/
-	ldda		[%src-80] %asi, %f12	/*  Load	Group		*/
-	ldda		[%src-72] %asi, %f14	/*  Load	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	faligndata	%f10, %f12, %f48	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f50	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f52		/*  FPA				*/
-vis5:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f32),	,,,,,STBLK,,,
-			,bcs,pn %icc, vis5e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f0),	,,,,,STBLK,,,
-			,bcs,pn %icc, vis5e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f16),	,,,,,STBLK,,,
-			,bcc,pt %icc, vis5)
-vis5e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f32,
-			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
-vis5e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f54,f56,f58,f60,f62,f48,f50,f52,f0,
-			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
-vis5e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f16,
-			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis6s:	add		%src, 128 - 48, %src	/*  IEU0	Group		*/
-	ldda		[%src-80] %asi, %f12	/*  Load	Group		*/
-	ldda		[%src-72] %asi, %f14	/*  Load	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f10	/*  FPM				*/
-	clr		%x6			/*  IEU0			*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f48	/*  FPA				*/
-	fmovd		%f14, %f50		/*  FPA		Group		*/
-vis6:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f32),	,,,,,,STBLK,,
-			,bcs,pn %icc, vis6e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f0),	,,,,,,STBLK,,
-			,bcs,pn %icc, vis6e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f16),	,,,,,,STBLK,,
-			,bcc,pt %icc, vis6)
-vis6e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f32,
-			,SYNC,		,,,,,,STBLK,ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
-vis6e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f52,f54,f56,f58,f60,f62,f48,f50,f0,
-			,SYNC,		,,,,,,STBLK,ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
-vis6e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f16,
-			,SYNC,		,,,,,,STBLK,ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis7s:	add		%src, 128 - 56, %src	/*  IEU0	Group		*/
-	ldda		[%src-72] %asi, %f14	/*  Load	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src-64] %asi, %f16	/*  Load	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f10	/*  FPM				*/
-	clr		%x6			/*  IEU0			*/
-	faddd		%f32, %f32, %f12	/*  FPA		Group		*/
-	clr		%x7			/*  IEU0			*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fmovd		%f14, %f48		/*  FPA				*/
-vis7:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f32),	,,,,,,,STBLK,
-			,bcs,pn %icc, vis7e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f0),	,,,,,,,STBLK,
-			,bcs,pn %icc, vis7e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f16),	,,,,,,,STBLK,
-			,bcc,pt %icc, vis7)
-vis7e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f32,
-			,SYNC,		,,,,,,,STBLK,
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
-vis7e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f50,f52,f54,f56,f58,f60,f62,f48,f0,
-			,SYNC,		,,,,,,,STBLK,
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
-vis7e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f16,
-			,SYNC,		,,,,,,,STBLK,
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
-e1:	END_THE_TRICK1(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
-e2:	END_THE_TRICK1(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
-e3:	END_THE_TRICK1(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
-ett:	rd		%asi, %x4		/*  LSU		Group+4bubbles	*/
-	rd		%gsr, %x3		/*  LSU		Group+4bubbles	*/
-#ifdef __KERNEL__
-	srl		%x4, 3, %x5		/*  IEU0	Group		*/
-	xor		%x4, ASI_BLK_XOR1, %x4	/*  IEU1			*/
-	wr		%x4, %x5, %asi		/*  LSU		Group+4bubbles	*/
-#else
-	wr		%x4, ASI_BLK_XOR, %asi	/*  LSU		Group+4bubbles	*/
-#endif
-	andcc		%x3, 7, %x3		/*  IEU1	Group		*/
-	add		%dst, 8, %dst		/*  IEU0			*/
-	bne,pn		%icc, 1f		/*  CTI				*/
-	 fzero		%f10			/*  FPA				*/
-	brz,a,pn	%len, 2f		/*  CTI+IEU1	Group		*/
-	 std		%f6, [%dst - 8]		/*  Store			*/
-1:	cmp		%len, 8			/*  IEU1			*/
-	blu,pn		%icc, 3f		/*  CTI				*/
-	 sub		%src, 64, %src		/*  IEU0	Group		*/
-1:	ldda		[%src] %asi, %f2	/*  Load	Group		*/
-	fpadd32		%f10, %f2, %f12		/*  FPA		Group+load stall*/
-	add		%src, 8, %src		/*  IEU0			*/
-	add		%dst, 8, %dst		/*  IEU1			*/
-	faligndata	%f6, %f2, %f14		/*  FPA		Group		*/
-	fcmpgt32	%f10, %f12, %x5		/*  FPM		Group		*/
-	std		%f14, [%dst - 16]	/*  Store			*/
-	fmovd		%f2, %f6		/*  FPA				*/
-	fmovd		%f12, %f10		/*  FPA		Group		*/
-	sub		%len, 8, %len		/*  IEU1			*/
-	fzero		%f16			/*  FPA		Group - FPU nop	*/
-	fzero		%f18			/*  FPA		Group - FPU nop	*/
-	inc		%x5			/*  IEU0			*/
-	srl		%x5, 1, %x5		/*  IEU0	Group (regdep)	*/
-	cmp		%len, 8			/*  IEU1			*/
-	bgeu,pt		%icc, 1b		/*  CTI				*/
-	 add		%x5, %sum, %sum		/*  IEU0	Group		*/
-3:	brz,a,pt	%x3, 2f			/*  CTI+IEU1			*/
-	 std		%f6, [%dst - 8]		/*  Store	Group		*/
-	st		%f7, [%dst - 8]		/*  Store	Group		*/
-	sub		%dst, 4, %dst		/*  IEU0			*/
-	add		%len, 4, %len		/*  IEU1			*/
-2:
-#ifdef __KERNEL__
-	sub		%sp, 8, %sp		/*  IEU0	Group		*/
-#endif
-	END_THE_TRICK2(	f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
-	membar		#Sync			/*  LSU		Group		*/
-#ifdef __KERNEL__
-	VISExit
-	add		%sp, 8, %sp		/*  IEU0	Group		*/
-#endif
-23:	brnz,pn		%len, 26f		/*  CTI+IEU1	Group		*/
-24:	 sllx		%sum, 32, %g1		/*  IEU0			*/
-25:	addcc		%sum, %g1, %src		/*  IEU1	Group		*/
-	srlx		%src, 32, %src		/*  IEU0	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%src, 1, %src		/*  IEU1			*/
-#ifndef __KERNEL__
-1:	retl					/*  CTI		Group brk forced*/
-	 srl		%src, 0, %src		/*  IEU0			*/
-#else
-1:	retl					/*  CTI		Group brk forced*/
-	 ldx		[%g6 + TI_TASK], %g4	/*  Load			*/
-#endif
-26:	andcc		%len, 8, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 lduwa		[%src] %asi, %o4	/*  Load			*/
-	lduwa		[%src+4] %asi, %g2	/*  Load	Group		*/
-	add		%src, 8, %src		/*  IEU0			*/
-	add		%dst, 8, %dst		/*  IEU1			*/
-	sllx		%o4, 32, %g5		/*  IEU0	Group		*/
-	stw		%o4, [%dst - 8]		/*  Store			*/
-	or		%g5, %g2, %g5		/*  IEU0	Group		*/
-	stw		%g2, [%dst - 4]		/*  Store			*/
-	addcc		%g5, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	andcc		%len, 4, %g0		/*  IEU1	Group		*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g2			/*  IEU0			*/
-	lduwa		[%src] %asi, %g7	/*  Load			*/
-	add		%src, 4, %src		/*  IEU0	Group		*/
-	add		%dst, 4, %dst		/*  IEU1			*/
-	sllx		%g7, 32, %g2		/*  IEU0	Group		*/
-	stw		%g7, [%dst - 4]		/*  Store			*/
-1:	andcc		%len, 2, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g3			/*  IEU0	Group		*/
-	lduha		[%src] %asi, %g7	/*  Load			*/
-	add		%src, 2, %src		/*  IEU1			*/
-	add		%dst, 2, %dst		/*  IEU0	Group		*/
-	sll		%g7, 16, %g3		/*  IEU0	Group		*/
-	sth		%g7, [%dst - 2]		/*  Store			*/
-1:	andcc		%len, 1, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o5			/*  IEU0	Group		*/
-	lduba		[%src] %asi, %g7	/*  Load			*/
-	sll		%g7, 8, %o5		/*  IEU0	Group		*/
-	stb		%g7, [%dst]		/*  Store			*/
-1:	or		%g2, %g3, %g3		/*  IEU1			*/
-	or		%o5, %g3, %g3		/*  IEU0	Group (regdep)	*/
-	addcc		%g3, %sum, %sum		/*  IEU1	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	ba,pt		%xcc, 25b		/*  CTI		Group		*/
-	 sllx		%sum, 32, %g1		/*  IEU0			*/
-
-#ifdef __KERNEL__
-end:
-
-	.section	__ex_table
-	.align		4
-	.word		csum_partial_copy_vis, 0, end, cpc_handler
-#endif
diff --git a/arch/sparc64/lib/VIScsumcopyusr.S b/arch/sparc64/lib/VIScsumcopyusr.S
deleted file mode 100644
--- a/arch/sparc64/lib/VIScsumcopyusr.S
+++ /dev/null
@@ -1,916 +0,0 @@
-/* $Id: VIScsumcopyusr.S,v 1.2 2000/02/20 23:21:40 davem Exp $
- * VIScsumcopyusr.S: High bandwidth IP checksumming with simultaneous
- *                   copying utilizing the UltraSparc Visual Instruction Set.
- *
- * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 2000 David S. Miller (davem@redhat.com)
- *
- * Based on older sparc32/sparc64 checksum.S, which is:
- *
- *      Copyright(C) 1995 Linus Torvalds
- *      Copyright(C) 1995 Miguel de Icaza
- *      Copyright(C) 1996,1997 David S. Miller
- *    derived from:
- *	  Linux/Alpha checksum c-code
- *        Linux/ix86 inline checksum assembly
- *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
- *	  David Mosberger-Tang for optimized reference c-code
- *	  BSD4.4 portable checksum routine
- */
-
-#ifdef __sparc_v9__
-#define STACKOFF	0x7ff+128
-#else
-#define STACKOFF	64
-#endif
-
-#ifdef __KERNEL__
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/visasm.h>
-#include <asm/thread_info.h>
-#define ASI_BLK_XOR	0
-#define ASI_BLK_XOR1	(ASI_BLK_P ^ (ASI_BLK_P >> 3) ^ ASI_P)
-#define ASI_BLK_OR	(ASI_BLK_P & ~ASI_P)
-#else
-#define ASI_P		0x80
-#define ASI_BLK_P	0xf0
-#define FRPS_FEF	0x04
-#define FPRS_DU		0x02
-#define FPRS_DL		0x01
-#define ASI_BLK_XOR	(ASI_BLK_P ^ ASI_P)
-#endif
-
-#define src		o0
-#define dst		o1
-#define	len		o2
-#define sum		o3
-#define x1		g1
-#define x2		g2
-#define x3		o4
-#define x4		g4
-#define x5		g5
-#define x6		g7
-#define x7		g3
-#define x8		o5
-
-/* Dobrou noc, SunSoft engineers. Spete sladce.
- * This has a couple of tricks in and those
- * tricks are UltraLinux trade secrets :))
- * Once AGAIN, the SunSoft engineers are caught
- * asleep at the keyboard :)).
- * The main loop does about 20 superscalar cycles
- * per 64bytes checksummed/copied.
- */
-
-#define LDBLK(O0)										\
-	ldda		[%src] ASI_BLK_P, %O0 	/*  Load	Group			*/
-
-#define STBLK											\
-	stda		%f48, [%dst] %asi	/*  Store				*/
-
-#ifdef __KERNEL__
-#define STBLK_XORASI(tmpreg1,tmpreg2)								\
-	stda		%f48, [%dst] %asi	/*  Store				*/;	\
-	rd		%asi, %tmpreg1;								\
-	srl		%tmpreg1, 3, %tmpreg2;							\
-	xor		%tmpreg1, ASI_BLK_XOR1, %tmpreg1;					\
-	wr		%tmpreg1, %tmpreg2, %asi;
-#else
-#define STBLK_XORASI(tmpreg1,tmpreg2)								\
-	stda		%f48, [%dst] %asi	/*  Store				*/;	\
-	rd		%asi, %tmpreg1;								\
-	wr		%tmpreg1, ASI_BLK_XOR, %asi;
-#endif
-
-#define ST(fx,off)										\
-	stda		%fx, [%dst + off] %asi	/*  Store				*/
-
-#define SYNC											\
-	membar		#Sync
-
-
-#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...)	\
-	LOAD					/*  Load	(Group)		*/;	\
-	faligndata	%A14, %F0, %A14		/*  FPA		Group		*/;	\
-	inc		%x5			/*  IEU0			*/;	\
-	STORE1					/*  Store (optional)		*/;	\
-	faligndata	%F0, %F2, %A0		/*  FPA		Group		*/;	\
-	srl		%x5, 1, %x5		/*  IEU0			*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	fpadd32		%F0, %f0, %F0		/*  FPA		Group		*/;	\
-	inc		%x6			/*  IEU0			*/;	\
-	STORE2					/*  Store (optional)		*/;	\
-	faligndata	%F2, %F4, %A2		/*  FPA		Group		*/;	\
-	srl		%x6, 1, %x6		/*  IEU0			*/;	\
-	add		%sum, %x5, %sum		/*  IEU1			*/;	\
-	fpadd32		%F2, %f2, %F2		/*  FPA		Group		*/;	\
-	add		%src, 64, %src		/*  IEU0			*/;	\
-	fcmpgt32	%f0, %F0, %x1		/*  FPM				*/;	\
-	add		%dst, 64, %dst		/*  IEU1	Group		*/;	\
-	inc		%x7			/*  IEU0			*/;	\
-	STORE3					/*  Store (optional)		*/;	\
-	faligndata	%F4, %F6, %A4		/*  FPA				*/;	\
-	fpadd32		%F4, %f4, %F4		/*  FPA		Group		*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	fcmpgt32	%f2, %F2, %x2		/*  FPM				*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	inc		%x8			/*  IEU1			*/;	\
-	STORE4					/*  Store (optional)		*/;	\
-	faligndata	%F6, %F8, %A6		/*  FPA				*/;	\
-	fpadd32		%F6, %f6, %F6		/*  FPA		Group		*/;	\
-	srl		%x8, 1, %x8		/*  IEU0			*/;	\
-	fcmpgt32	%f4, %F4, %x3		/*  FPM				*/;	\
-	add		%sum, %x7, %sum		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	STORE5					/*  Store (optional)		*/;	\
-	faligndata	%F8, %F10, %A8		/*  FPA				*/;	\
-	fpadd32		%F8, %f8, %F8		/*  FPA		Group		*/;	\
-	srl		%x1, 1, %x1		/*  IEU0			*/;	\
-	fcmpgt32	%f6, %F6, %x4		/*  FPM				*/;	\
-	add		%sum, %x8, %sum		/*  IEU0	Group		*/;	\
-	inc		%x2			/*  IEU1			*/;	\
-	STORE6					/*  Store (optional)		*/;	\
-	faligndata	%F10, %F12, %A10	/*  FPA				*/;	\
-	fpadd32		%F10, %f10, %F10	/*  FPA		Group		*/;	\
-	srl		%x2, 1, %x2		/*  IEU0			*/;	\
-	fcmpgt32	%f8, %F8, %x5		/*  FPM				*/;	\
-	add		%sum, %x1, %sum		/*  IEU0	Group		*/;	\
-	inc		%x3			/*  IEU1			*/;	\
-	STORE7					/*  Store (optional)		*/;	\
-	faligndata	%F12, %F14, %A12	/*  FPA				*/;	\
-	fpadd32		%F12, %f12, %F12	/*  FPA		Group		*/;	\
-	srl		%x3, 1, %x3		/*  IEU0			*/;	\
-	fcmpgt32	%f10, %F10, %x6		/*  FPM				*/;	\
-	add		%sum, %x2, %sum		/*  IEU0	Group		*/;	\
-	inc		%x4			/*  IEU1			*/;	\
-	STORE8					/*  Store (optional)		*/;	\
-	fmovd		%F14, %B14		/*  FPA				*/;	\
-	fpadd32		%F14, %f14, %F14	/*  FPA		Group		*/;	\
-	srl		%x4, 1, %x4		/*  IEU0			*/;	\
-	fcmpgt32	%f12, %F12, %x7		/*  FPM				*/;	\
-	add		%sum, %x3, %sum		/*  IEU0	Group		*/;	\
-	subcc		%len, 64, %len		/*  IEU1			*/;	\
-	BRANCH					/*  CTI				*/;	\
-	fcmpgt32	%f14, %F14, %x8		/*  FPM		Group		*/;
-
-#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
-	inc		%x5			/*  IEU0	Group		*/;	\
-	fpadd32		%f2, %f0, %S0		/*  FPA				*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	fpadd32		%f6, %f4, %S1		/*  FPA				*/;	\
-	inc		%x6			/*  IEU1			*/;	\
-	fpadd32		%f10, %f8, %S2		/*  FPA		Group		*/;	\
-	add		%sum, %x5, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%f0, %S0, %x1		/*  FPM				*/;	\
-	fpadd32		%f14, %f12, %S3		/*  FPA		Group		*/;	\
-	srl		%x6, 1, %x6		/*  IEU0			*/;	\
-	fcmpgt32	%f4, %S1, %x2		/*  FPM				*/;	\
-	add		%sum, %x6, %sum		/*  IEU0	Group		*/;	\
-	fzero		%fz			/*  FPA				*/;	\
-	fcmpgt32	%f8, %S2, %x3		/*  FPM				*/;	\
-	inc		%x7			/*  IEU0	Group		*/;	\
-	inc		%x8			/*  IEU1			*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	fpadd32		%S0, %S1, %T0		/*  FPA				*/;	\
-	fpadd32		%S2, %S3, %T1		/*  FPA		Group		*/;	\
-	add		%sum, %x7, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%f12, %S3, %x4		/*  FPM				*/;	\
-	srl		%x8, 1, %x8		/*  IEU0	Group		*/;	\
-	inc		%x2			/*  IEU1			*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	add		%sum, %x8, %sum		/*  IEU1			*/;	\
-	add		%sum, %x1, %sum		/*  IEU0	Group		*/;	\
-	fcmpgt32	%S0, %T0, %x5		/*  FPM				*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	fcmpgt32	%S2, %T1, %x6		/*  FPM				*/;	\
-	inc		%x3			/*  IEU0	Group		*/;	\
-	add		%sum, %x2, %sum		/*  IEU1			*/;	\
-	srl		%x3, 1, %x3		/*  IEU0	Group		*/;	\
-	inc		%x4			/*  IEU1			*/;	\
-	fpadd32		%T0, %T1, %U0		/*  FPA		Group		*/;	\
-	add		%sum, %x3, %sum		/*  IEU0			*/;	\
-	fcmpgt32	%fz, %f2, %x7		/*  FPM				*/;	\
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %f6, %x8		/*  FPM				*/;	\
-	inc		%x5			/*  IEU0	Group		*/;	\
-	add		%sum, %x4, %sum		/*  IEU1			*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %f10, %x1		/*  FPM				*/;	\
-	inc		%x6			/*  IEU0	Group		*/;	\
-	add		%sum, %x5, %sum		/*  IEU1			*/;	\
-	fmovd		%FA, %FB		/*  FPA		Group		*/;	\
-	fcmpgt32	%fz, %f14, %x2		/*  FPM				*/;	\
-	srl		%x6, 1, %x6		/*  IEU0	Group		*/;	\
-	ba,pt		%xcc, ett		/*  CTI				*/;	\
-	 inc		%x7			/*  IEU1			*/;
-
-#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) 				\
-	END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
-
-#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) 					\
-	fpadd32		%U0, %U1, %V0		/*  FPA		Group		*/;	\
-	srl		%x7, 1, %x7		/*  IEU0			*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	std		%V0, [%sp + STACKOFF]	/*  Store	Group		*/;	\
-	inc		%x8			/*  IEU0			*/;	\
-	sub		%sum, %x7, %sum		/*  IEU1			*/;	\
-	srl		%x8, 1, %x8		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %S1, %x3		/*  FPM				*/;	\
-	inc		%x1			/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %S3, %x4		/*  FPM				*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	sub		%sum, %x8, %sum		/*  IEU1			*/;	\
-	ldx		[%sp + STACKOFF], %x8	/*  Load	Group		*/;	\
-	inc		%x2			/*  IEU0			*/;	\
-	sub		%sum, %x1, %sum		/*  IEU1			*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %T1, %x5		/*  FPM				*/;	\
-	inc		%x3			/*  IEU0	Group		*/;	\
-	fcmpgt32	%T0, %U0, %x6		/*  FPM				*/;	\
-	srl		%x3, 1, %x3		/*  IEU0	Group		*/;	\
-	sub		%sum, %x2, %sum		/*  IEU1			*/;	\
-	inc		%x4			/*  IEU0	Group		*/;	\
-	sub		%sum, %x3, %sum		/*  IEU1			*/;	\
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %U1, %x7		/*  FPM				*/;	\
-	inc		%x5			/*  IEU0	Group		*/;	\
-	fcmpgt32	%U0, %V0, %x1		/*  FPM				*/;	\
-	srl		%x5, 1, %x5		/*  IEU0	Group		*/;	\
-	sub		%sum, %x4, %sum		/*  IEU1			*/;	\
-	sub		%sum, %x5, %sum		/*  IEU0	Group		*/;	\
-	fcmpgt32	%fz, %V0, %x2		/*  FPM				*/;	\
-	inc		%x6			/*  IEU0	Group		*/;	\
-	inc		%x7			/*  IEU1			*/;	\
-	srl		%x6, 1, %x6		/*  IEU0	Group		*/;	\
-	inc		%x1			/*  IEU1			*/;	\
-	srl		%x7, 1, %x7		/*  IEU0	Group		*/;	\
-	add		%sum, %x6, %sum		/*  IEU1			*/;	\
-	srl		%x1, 1, %x1		/*  IEU0	Group		*/;	\
-	sub		%sum, %x7, %sum		/*  IEU1			*/;	\
-	inc		%x2			/*  IEU0	Group		*/;	\
-	add		%sum, %x1, %sum		/*  IEU1			*/;	\
-	srl		%x2, 1, %x2		/*  IEU0	Group		*/;	\
-	sub		%sum, %x2, %sum		/*  IEU0	Group		*/;	\
-	addcc		%sum, %x8, %sum		/*  IEU1	Group		*/;	\
-	bcs,a,pn	%xcc, 33f		/*  CTI				*/;	\
-	 add		%sum, 1, %sum		/*  IEU0	(Group)		*/;	\
-33:						/*  That's it			*/;
-
-	.text
-	.globl		csum_partial_copy_user_vis
-	.align		32
-/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp.
- * csum_partial_copy_from_user
- * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256
- */
-csum_partial_copy_user_vis:
-	andcc		%dst, 7, %g0		/*  IEU1	Group		*/
-	be,pt		%icc, 4f		/*  CTI				*/
-	 and		%dst, 0x38, %o4		/*  IEU0			*/
-	mov		1, %g5			/*  IEU0	Group		*/
-	andcc		%dst, 2, %g0		/*  IEU1			*/
-	be,pt		%icc, 1f		/*  CTI				*/
-	 and		%dst, 4, %g7		/*  IEU0	Group		*/
-	lduh		[%src], %g2		/*  Load			*/
-	sub		%len, 2, %len		/*  IEU0	Group		*/
-	add		%dst, 2, %dst		/*  IEU1			*/
-	andcc		%dst, 4, %g7		/*  IEU1	Group		*/
-	sll		%g5, 16, %g5		/*  IEU0			*/
-	stha		%g2, [%dst - 2]	%asi	/*  Store	Group		*/
-	sll		%g2, 16, %g2		/*  IEU0	 		*/
-	add		%src, 2, %src		/*  IEU1			*/
-	addcc		%g2, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%sum, %g5, %sum		/*  IEU0			*/
-1:	lduw		[%src], %g2		/*  Load			*/
-	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group		*/
-	 and		%dst, 0x38, %o4		/*  IEU0			*/
-	add		%dst, 4, %dst		/*  IEU0	Group		*/
-	sub		%len, 4, %len		/*  IEU1			*/
-	addcc		%g2, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	and		%dst, 0x38, %o4		/*  IEU0	Group		*/
-	stwa		%g2, [%dst - 4] %asi	/*  Store			*/
-	add		%src, 4, %src		/*  IEU1			*/
-4:
-#ifdef __KERNEL__
-	VISEntry
-#endif
-	mov		%src, %g7		/*  IEU1	Group		*/
-	fzero		%f48			/*  FPA				*/
-	alignaddr	%src, %g0, %src		/*  Single	Group		*/
-	subcc		%g7, %src, %g7		/*  IEU1	Group		*/
-	be,pt		%xcc, 1f		/*  CTI				*/
-	 mov		0x40, %g1		/*  IEU0			*/
-	lduw		[%src], %g2		/*  Load	Group		*/
-	subcc		%sum, %g2, %sum		/*  IEU1	Group+load stall*/
-	bcs,a,pn	%icc, 1f		/*  CTI				*/
-	 sub		%sum, 1, %sum		/*  IEU0			*/
-1:	srl		%sum, 0, %sum		/*  IEU0	Group		*/
-	clr		%g5			/*  IEU1			*/
-	brz,pn		%o4, 3f			/*  CTI+IEU1	Group		*/
-	 sub		%g1, %o4, %g1		/*  IEU0			*/
-	ldd		[%src], %f0		/*  Load			*/
-	clr		%o4			/*  IEU0	Group		*/
-	andcc		%dst, 8, %g0		/*  IEU1			*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 ldd		[%src + 8], %f2		/*  Load	Group		*/
-	add		%src, 8, %src		/*  IEU0			*/
-	sub		%len, 8, %len		/*  IEU1			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	addcc		%dst, 8, %dst		/*  IEU1	Group		*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %o4		/*  FPM		Group		*/
-	fmovd		%f2, %f0		/*  FPA		Group		*/
-	ldd		[%src + 8], %f2		/*  Load			*/
-	stda		%f16, [%dst - 8] %asi	/*  Store			*/
-	fmovd		%f50, %f48		/*  FPA				*/
-1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 and		%g1, 0x20, %g1		/*  IEU0			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	ldd		[%src + 16], %f4	/*  Load	Group		*/
-	add		%src, 16, %src		/*  IEU0			*/
-	add		%dst, 16, %dst		/*  IEU1			*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group		*/
-	sub		%len, 16, %len		/*  IEU0			*/
-	inc		%o4			/*  IEU1			*/
-	stda		%f16, [%dst - 16] %asi	/*  Store	Group		*/
-	fpadd32		%f2, %f50, %f48		/*  FPA				*/
-	srl		%o4, 1, %o5		/*  IEU0			*/
-	faligndata	%f2, %f4, %f18		/*  FPA		Group		*/
-	stda		%f18, [%dst - 8] %asi	/*  Store			*/
-	fcmpgt32	%f50, %f48, %o4		/*  FPM		Group		*/
-	add		%o5, %sum, %sum		/*  IEU0			*/
-	ldd		[%src + 8], %f2		/*  Load			*/
-	fmovd		%f4, %f0		/*  FPA				*/
-1:	brz,a,pn	%g1, 4f			/*  CTI+IEU1	Group		*/
-	 rd		%asi, %g2		/*  LSU		Group + 4 bubbles*/
-	inc		%g5			/*  IEU0			*/
-	fpadd32		%f0, %f48, %f50		/*  FPA				*/
-	ldd		[%src + 16], %f4	/*  Load	Group		*/
-	srl		%g5, 1, %g5		/*  IEU0			*/
-	add		%dst, 32, %dst		/*  IEU1			*/
-	faligndata	%f0, %f2, %f16		/*  FPA				*/
-	fcmpgt32	%f48, %f50, %o5		/*  FPM		Group		*/
-	inc		%o4			/*  IEU0			*/
-	ldd		[%src + 24], %f6	/*  Load			*/
-	srl		%o4, 1, %o4		/*  IEU0	Group		*/
-	add		%g5, %sum, %sum		/*  IEU1			*/
-	ldd		[%src + 32], %f8	/*  Load			*/
-	fpadd32		%f2, %f50, %f48		/*  FPA				*/
-	faligndata	%f2, %f4, %f18		/*  FPA		Group		*/
-	sub		%len, 32, %len		/*  IEU0			*/
-	stda		%f16, [%dst - 32] %asi	/*  Store			*/
-	fcmpgt32	%f50, %f48, %g3		/*  FPM		Group		*/
-	inc		%o5			/*  IEU0			*/
-	add		%o4, %sum, %sum		/*  IEU1			*/
-	fpadd32		%f4, %f48, %f50		/*  FPA				*/
-	faligndata	%f4, %f6, %f20		/*  FPA		Group		*/
-	srl		%o5, 1, %o5		/*  IEU0			*/
-	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group		*/
-	add		%o5, %sum, %sum		/*  IEU0			*/
-	stda		%f18, [%dst - 24] %asi	/*  Store			*/
-	fpadd32		%f6, %f50, %f48		/*  FPA				*/
-	inc		%g3			/*  IEU0	Group		*/
-	stda		%f20, [%dst - 16] %asi	/*  Store			*/
-	add		%src, 32, %src		/*  IEU1			*/
-	faligndata	%f6, %f8, %f22		/*  FPA				*/
-	fcmpgt32	%f50, %f48, %o4		/*  FPM		Group		*/
-	srl		%g3, 1, %g3		/*  IEU0			*/
-	stda		%f22, [%dst - 8] %asi	/*  Store			*/	
-	add		%g3, %sum, %sum		/*  IEU0	Group		*/
-3:	rd		%asi, %g2		/*  LSU		Group + 4 bubbles*/
-#ifdef __KERNEL__
-4:	sethi		%hi(vis0s), %g7		/*  IEU0	Group		*/
-	or		%g2, ASI_BLK_OR, %g2	/*  IEU1			*/
-#else
-4:	rd		%pc, %g7		/*  LSU		Group + 4 bubbles*/
-#endif
-	inc		%g5			/*  IEU0	Group		*/
-	and		%src, 0x38, %g3		/*  IEU1			*/	
-	membar		#StoreLoad		/*  LSU		Group		*/
-	srl		%g5, 1, %g5		/*  IEU0			*/
-	inc		%o4			/*  IEU1			*/
-	sll		%g3, 8, %g3		/*  IEU0	Group		*/
-	sub		%len, 0xc0, %len	/*  IEU1			*/
-	addcc		%g5, %sum, %sum		/*  IEU1	Group		*/
-	srl		%o4, 1, %o4		/*  IEU0			*/
-	add		%g7, %g3, %g7		/*  IEU0	Group		*/
-	add		%o4, %sum, %sum		/*  IEU1			*/
-#ifdef __KERNEL__
-	jmpl		%g7 + %lo(vis0s), %g0	/*  CTI+IEU1	Group		*/
-#else
-	jmpl		%g7 + (vis0s - 4b), %g0	/*  CTI+IEU1	Group		*/
-#endif
-	 fzero		%f32			/*  FPA				*/
-
-	.align		2048
-vis0s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src] ASI_BLK_P, %f0	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f48, %f62		/*  FPA		Group	f0 available*/
-	faligndata	%f0, %f2, %f48		/*  FPA		Group	f2 available*/
-	fcmpgt32	%f32, %f2, %x1		/*  FPM		Group	f4 available*/
-	fpadd32		%f0, %f62, %f0		/*  FPA				*/
-	fcmpgt32	%f32, %f4, %x2		/*  FPM		Group	f6 available*/
-	faligndata	%f2, %f4, %f50		/*  FPA				*/
-	fcmpgt32	%f62, %f0, %x3		/*  FPM		Group	f8 available*/
-	faligndata	%f4, %f6, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group	f10 available*/
-	inc		%x1			/*  IEU0			*/
-	faligndata	%f6, %f8, %f54		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group	f12 available*/
-	srl		%x1, 1, %x1		/*  IEU0			*/
-	inc		%x2			/*  IEU1			*/
-	faligndata	%f8, %f10, %f56		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group	f14 available*/
-	srl		%x2, 1, %x2		/*  IEU0			*/
-	add		%sum, %x1, %sum		/*  IEU1			*/
-	faligndata	%f10, %f12, %f58	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	add		%sum, %x2, %sum		/*  IEU1			*/
-	faligndata	%f12, %f14, %f60	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f62		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis0:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,								
-			,LDBLK(f32),	STBLK,,,,,,,,									
-			,bcs,pn %icc, vis0e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,								
-			,LDBLK(f0),	STBLK,,,,,,,,									
-			,bcs,pn %icc, vis0e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f48,f50,f52,f54,f56,f58,f60,f62,f62,
-			,LDBLK(f16),	STBLK,,,,,,,,
-			,bcc,pt %icc, vis0)
-vis0e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f48,f50,f52,f54,f56,f58,f60,f62,f32,
-			,SYNC,		STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
-vis0e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f48,f50,f52,f54,f56,f58,f60,f62,f0,
-			,SYNC,		STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
-vis0e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f48,f50,f52,f54,f56,f58,f60,f62,f16,
-			,SYNC,		STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
-			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis1s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	sub		%src, 8, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f0	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f0, %f58		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f2, %x2		/*  FPM		Group		*/
-	faligndata	%f2, %f4, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group		*/
-	faligndata	%f4, %f6, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	inc		%x2			/*  IEU1			*/
-	faligndata	%f8, %f10, %f54		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	srl		%x2, 1, %x2		/*  IEU0			*/
-	faligndata	%f10, %f12, %f56	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	add		%sum, %x2, %sum		/*  IEU1			*/
-	faligndata	%f12, %f14, %f58	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f60		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis1:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f32),	,STBLK,,,,,,,
-			,bcs,pn %icc, vis1e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f0),	,STBLK,,,,,,,
-			,bcs,pn %icc, vis1e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
-			,LDBLK(f16),	,STBLK,,,,,,,
-			,bcc,pt %icc, vis1)
-vis1e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f32,
-			,SYNC,		,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
-vis1e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f62,f48,f50,f52,f54,f56,f58,f60,f0,
-			,SYNC,		,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
-vis1e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f62,f48,f50,f52,f54,f56,f58,f60,f16,
-			,SYNC,		,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
-			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis2s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	sub		%src, 16, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f0	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f0, %f56		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/	
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group		*/
-	faligndata	%f4, %f6, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f52		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f54	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	inc		%x3			/*  IEU0			*/
-	faligndata	%f12, %f14, %f56	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	srl		%x3, 1, %x3		/*  IEU0			*/
-	inc		%x4			/*  IEU1			*/
-	fmovd		%f14, %f58		/*  FPA				*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-	add		%sum, %x3, %sum		/*  IEU1			*/
-vis2:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f32),	,,STBLK,,,,,,
-			,bcs,pn %icc, vis2e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f0),	,,STBLK,,,,,,
-			,bcs,pn %icc, vis2e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
-			,LDBLK(f16),	,,STBLK,,,,,,
-			,bcc,pt %icc, vis2)
-vis2e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f32,
-			,SYNC,		,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
-vis2e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f60,f62,f48,f50,f52,f54,f56,f58,f0,
-			,SYNC,		,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
-vis2e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f60,f62,f48,f50,f52,f54,f56,f58,f16,
-			,SYNC,		,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
-			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis3s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	sub		%src, 24, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f0	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f0, %f54		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fpsub32		%f4, %f4, %f4		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group		*/
-	faligndata	%f6, %f8, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f50		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f52	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f54	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f56		/*  FPA				*/
-	inc		%x4			/*  IEU0			*/
-	srl		%x4, 1, %x4		/*  IEU0	Group		*/
-vis3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f32),	,,,STBLK,,,,,
-			,bcs,pn %icc, vis3e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f0),	,,,STBLK,,,,,
-			,bcs,pn %icc, vis3e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
-			,LDBLK(f16),	,,,STBLK,,,,,
-			,bcc,pt %icc, vis3)
-vis3e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f32,
-			,SYNC,		,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
-vis3e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f58,f60,f62,f48,f50,f52,f54,f56,f0,
-			,SYNC,		,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
-vis3e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f58,f60,f62,f48,f50,f52,f54,f56,f16,
-			,SYNC,		,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
-			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis4s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	sub		%src, 32, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f0	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f0, %f52		/*  FPA		Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fpsub32		%f2, %f2, %f2		/*  FPA		Group		*/
-	fpsub32		%f4, %f4, %f4		/*  FPA		Group		*/
-	fpsub32		%f6, %f6, %f6		/*  FPA		Group		*/
-	clr		%x4			/*  IEU0			*/
-	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group		*/
-	faligndata	%f8, %f10, %f48		/*  FPA				*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	faligndata	%f10, %f12, %f50	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f52	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f54		/*  FPA				*/
-vis4:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f32),	,,,,STBLK,,,,
-			,bcs,pn %icc, vis4e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f0),	,,,,STBLK,,,,
-			,bcs,pn %icc, vis4e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
-			,LDBLK(f16),	,,,,STBLK,,,,
-			,bcc,pt %icc, vis4)
-vis4e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f32,
-			,SYNC,		,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
-vis4e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f56,f58,f60,f62,f48,f50,f52,f54,f0,
-			,SYNC,		,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
-vis4e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f56,f58,f60,f62,f48,f50,f52,f54,f16,
-			,SYNC,		,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80),
-			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis5s:	ldd		[%src+0], %f10		/*  Load	Group		*/
-	ldd		[%src+8], %f12		/*  Load	Group		*/
-	ldd		[%src+16], %f14		/*  Load	Group		*/
-	add		%src, 24, %src		/*  IEU0	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	faligndata	%f10, %f12, %f48	/*  FPA				*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f50	/*  FPA				*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	fmovd		%f14, %f52		/*  FPA				*/
-vis5:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f32),	,,,,,STBLK,,,
-			,bcs,pn %icc, vis5e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f0),	,,,,,STBLK,,,
-			,bcs,pn %icc, vis5e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
-			,LDBLK(f16),	,,,,,STBLK,,,
-			,bcc,pt %icc, vis5)
-vis5e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f32,
-			,SYNC,		,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
-vis5e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f54,f56,f58,f60,f62,f48,f50,f52,f0,
-			,SYNC,		,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
-vis5e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f54,f56,f58,f60,f62,f48,f50,f52,f16,
-			,SYNC,		,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72),
-			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis6s:	ldd		[%src+0], %f12		/*  Load	Group		*/
-	ldd		[%src+8], %f14		/*  Load	Group		*/
-	add		%src, 16, %src		/*  IEU0	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f10	/*  FPM				*/
-	clr		%x6			/*  IEU0			*/
-	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	faligndata	%f12, %f14, %f48	/*  FPA				*/
-	fmovd		%f14, %f50		/*  FPA		Group		*/
-vis6:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f32),	,,,,,,STBLK,,
-			,bcs,pn %icc, vis6e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f0),	,,,,,,STBLK,,
-			,bcs,pn %icc, vis6e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
-			,LDBLK(f16),	,,,,,,STBLK,,
-			,bcc,pt %icc, vis6)
-vis6e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f32,
-			,SYNC,		,,,,,,STBLK_XORASI(x6,x7),ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
-vis6e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f52,f54,f56,f58,f60,f62,f48,f50,f0,
-			,SYNC,		,,,,,,STBLK_XORASI(x6,x7),ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
-vis6e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f52,f54,f56,f58,f60,f62,f48,f50,f16,
-			,SYNC,		,,,,,,STBLK_XORASI(x6,x7),ST(f48,64),
-			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
-	.align		2048
-vis7s:	ldd		[%src+0], %f14		/*  Load	Group		*/
-	add		%src, 8, %src		/*  IEU0	Group		*/
-	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group		*/
-	ldda		[%src] ASI_BLK_P, %f16	/*  Load	Group		*/
-	add		%src, 64, %src		/*  IEU0	Group		*/
-	fmovd		%f48, %f0		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f2		/*  FPM				*/
-	clr		%x4			/*  IEU0			*/
-	faddd		%f32, %f32, %f4		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f6		/*  FPM				*/
-	clr		%x5			/*  IEU0			*/
-	faddd		%f32, %f32, %f8		/*  FPA		Group		*/
-	fmuld		%f32, %f32, %f10	/*  FPM				*/
-	clr		%x6			/*  IEU0			*/
-	faddd		%f32, %f32, %f12	/*  FPA		Group		*/
-	clr		%x7			/*  IEU0			*/
-	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group		*/
-	sub		%dst, 64, %dst		/*  IEU0			*/
-	fmovd		%f14, %f48		/*  FPA				*/
-vis7:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f32),	,,,,,,,STBLK,
-			,bcs,pn %icc, vis7e1)
-	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f0),	,,,,,,,STBLK,
-			,bcs,pn %icc, vis7e2)
-	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
-			,LDBLK(f16),	,,,,,,,STBLK,
-			,bcc,pt %icc, vis7)
-vis7e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f32,
-			,SYNC,		,,,,,,,STBLK_XORASI(x7,x8),
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
-vis7e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
-			,f50,f52,f54,f56,f58,f60,f62,f48,f0,
-			,SYNC,		,,,,,,,STBLK_XORASI(x7,x8),
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
-vis7e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
-			,f50,f52,f54,f56,f58,f60,f62,f48,f16,
-			,SYNC,		,,,,,,,STBLK_XORASI(x7,x8),
-			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
-e1:	END_THE_TRICK1(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
-e2:	END_THE_TRICK1(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
-e3:	END_THE_TRICK1(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
-ett:	rd		%gsr, %x3		/*  LSU		Group+4bubbles	*/
-	andcc		%x3, 7, %x3		/*  IEU1	Group		*/
-	add		%dst, 8, %dst		/*  IEU0			*/
-	bne,pn		%icc, 1f		/*  CTI				*/
-	 fzero		%f10			/*  FPA				*/
-	brz,a,pn	%len, 2f		/*  CTI+IEU1	Group		*/
-	 stda		%f6, [%dst - 8] %asi	/*  Store			*/
-1:	cmp		%len, 8			/*  IEU1			*/
-	blu,pn		%icc, 3f		/*  CTI				*/
-	 sub		%src, 64, %src		/*  IEU0	Group		*/
-1:	ldd		[%src], %f2		/*  Load	Group		*/
-	fpadd32		%f10, %f2, %f12		/*  FPA		Group+load stall*/
-	add		%src, 8, %src		/*  IEU0			*/
-	add		%dst, 8, %dst		/*  IEU1			*/
-	faligndata	%f6, %f2, %f14		/*  FPA		Group		*/
-	fcmpgt32	%f10, %f12, %x5		/*  FPM		Group		*/
-	stda		%f14, [%dst - 16] %asi	/*  Store			*/
-	fmovd		%f2, %f6		/*  FPA				*/
-	fmovd		%f12, %f10		/*  FPA		Group		*/
-	sub		%len, 8, %len		/*  IEU1			*/
-	fzero		%f16			/*  FPA		Group - FPU nop	*/
-	fzero		%f18			/*  FPA		Group - FPU nop	*/
-	inc		%x5			/*  IEU0			*/
-	srl		%x5, 1, %x5		/*  IEU0	Group (regdep)	*/
-	cmp		%len, 8			/*  IEU1			*/
-	bgeu,pt		%icc, 1b		/*  CTI				*/
-	 add		%x5, %sum, %sum		/*  IEU0	Group		*/
-3:	brz,a,pt	%x3, 2f			/*  CTI+IEU1			*/
-	 stda		%f6, [%dst - 8] %asi	/*  Store	Group		*/
-	sta		%f7, [%dst - 8]	%asi	/*  Store	Group		*/
-	sub		%dst, 4, %dst		/*  IEU0			*/
-	add		%len, 4, %len		/*  IEU1			*/
-2:
-#ifdef __KERNEL__
-	sub		%sp, 8, %sp		/*  IEU0	Group		*/
-#endif
-	END_THE_TRICK2(	f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
-	membar		#Sync			/*  LSU		Group		*/
-#ifdef __KERNEL__
-	VISExit
-	add		%sp, 8, %sp		/*  IEU0	Group		*/
-#endif
-23:	brnz,pn		%len, 26f		/*  CTI+IEU1	Group		*/
-24:	 sllx		%sum, 32, %g1		/*  IEU0			*/
-25:	addcc		%sum, %g1, %src		/*  IEU1	Group		*/
-	srlx		%src, 32, %src		/*  IEU0	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%src, 1, %src		/*  IEU1			*/
-#ifndef __KERNEL__
-1:	retl					/*  CTI		Group brk forced*/
-	 srl		%src, 0, %src		/*  IEU0			*/
-#else
-1:	retl					/*  CTI		Group brk forced*/
-	 ldx		[%g6 + TI_TASK], %g4	/*  Load			*/
-#endif
-26:	andcc		%len, 8, %g0		/*  IEU1	Group		*/
-	be,pn		%icc, 1f		/*  CTI				*/
-	 lduw		[%src], %o4		/*  Load			*/
-	lduw		[%src+4], %g2		/*  Load	Group		*/
-	add		%src, 8, %src		/*  IEU0			*/
-	add		%dst, 8, %dst		/*  IEU1			*/
-	sllx		%o4, 32, %g5		/*  IEU0	Group		*/
-	stwa		%o4, [%dst - 8] %asi	/*  Store			*/
-	or		%g5, %g2, %g5		/*  IEU0	Group		*/
-	stwa		%g2, [%dst - 4]	%asi	/*  Store			*/
-	addcc		%g5, %sum, %sum		/*  IEU1	Group		*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	andcc		%len, 4, %g0		/*  IEU1	Group		*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g2			/*  IEU0			*/
-	lduw		[%src], %g7		/*  Load			*/
-	add		%src, 4, %src		/*  IEU0	Group		*/
-	add		%dst, 4, %dst		/*  IEU1			*/
-	sllx		%g7, 32, %g2		/*  IEU0	Group		*/
-	stwa		%g7, [%dst - 4] %asi	/*  Store			*/
-1:	andcc		%len, 2, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%g3			/*  IEU0	Group		*/
-	lduh		[%src], %g7		/*  Load			*/
-	add		%src, 2, %src		/*  IEU1			*/
-	add		%dst, 2, %dst		/*  IEU0	Group		*/
-	sll		%g7, 16, %g3		/*  IEU0	Group		*/
-	stha		%g7, [%dst - 2] %asi	/*  Store			*/
-1:	andcc		%len, 1, %g0		/*  IEU1			*/
-	be,a,pn		%icc, 1f		/*  CTI				*/
-	 clr		%o5			/*  IEU0	Group		*/
-	ldub		[%src], %g7		/*  Load			*/
-	sll		%g7, 8, %o5		/*  IEU0	Group		*/
-	stba		%g7, [%dst] %asi	/*  Store			*/
-1:	or		%g2, %g3, %g3		/*  IEU1			*/
-	or		%o5, %g3, %g3		/*  IEU0	Group (regdep)	*/
-	addcc		%g3, %sum, %sum		/*  IEU1	Group (regdep)	*/
-	bcs,a,pn	%xcc, 1f		/*  CTI				*/
-	 add		%sum, 1, %sum		/*  IEU0			*/
-1:	ba,pt		%xcc, 25b		/*  CTI		Group		*/
-	 sllx		%sum, 32, %g1		/*  IEU0			*/
-
-#ifdef __KERNEL__
-end:
-
-	.section	__ex_table
-	.align		4
-	.word		csum_partial_copy_user_vis, 0, end, cpc_handler
-#endif
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
deleted file mode 100644
--- a/arch/sparc64/lib/VISmemset.S
+++ /dev/null
@@ -1,240 +0,0 @@
-/* $Id: VISmemset.S,v 1.10 1999/12/23 17:02:16 jj Exp $
- * VISmemset.S: High speed memset operations utilizing the UltraSparc
- *        Visual Instruction Set.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jakub@redhat.com)
- */
-
-#include "VIS.h"
-
-#ifdef REGS_64BIT
-#define SET_BLOCKS(base, offset, source)	\
-	stx	source, [base - offset - 0x18];	\
-	stx	source, [base - offset - 0x10];	\
-	stx	source, [base - offset - 0x08];	\
-	stx	source, [base - offset - 0x00];
-#else
-#define SET_BLOCKS(base, offset, source)	\
-	stw	source, [base - offset - 0x18];	\
-	stw	source, [base - offset - 0x14];	\
-	stw	source, [base - offset - 0x10];	\
-	stw	source, [base - offset - 0x0c];	\
-	stw	source, [base - offset - 0x08];	\
-	stw	source, [base - offset - 0x04];	\
-	stw	source, [base - offset - 0x00];	\
-	stw	source, [base - offset + 0x04];
-#endif
-
-#ifndef __KERNEL__
-/* So that the brz,a,pt in memset doesn't have to get through PLT, here we go... */
-#include "VISbzero.S"
-#endif
-
-#ifdef __KERNEL__
-#include <asm/visasm.h>
-#endif
-
-	/* Well, memset is a lot easier to get right than bcopy... */
-	.text
-	.align		32
-#ifdef __KERNEL__
-	.globl		__memset
-__memset:
-#endif
-	.globl		memset
-memset:
-#ifndef __KERNEL__
-	brz,a,pt	%o1, bzero_private
-	 mov		%o2, %o1
-#ifndef REGS_64BIT
-	srl		%o2, 0, %o2
-#endif
-#endif
-	mov		%o0, %o4
-	cmp		%o2, 7
-	bleu,pn		%xcc, 17f
-	 andcc		%o0, 3, %g5
-	be,pt		%xcc, 4f
-	 and		%o1, 0xff, %o1
-	cmp		%g5, 3
-	be,pn		%xcc, 2f
-	 stb		%o1, [%o0 + 0x00]
-	cmp		%g5, 2
-	be,pt		%xcc, 2f
-	 stb		%o1, [%o0 + 0x01]
-	stb		%o1, [%o0 + 0x02]
-2:	sub		%g5, 4, %g5
-	sub		%o0, %g5, %o0
-	add		%o2, %g5, %o2
-4:	sllx		%o1, 8, %g1
-	andcc		%o0, 4, %g0
-	or		%o1, %g1, %o1
-	sllx		%o1, 16, %g1
-	or		%o1, %g1, %o1
-	be,pt		%xcc, 2f
-#ifdef REGS_64BIT
-	 sllx		%o1, 32, %g1
-#else
-	 cmp		%o2, 128
-#endif
-	stw		%o1, [%o0]
-	sub		%o2, 4, %o2
-	add		%o0, 4, %o0
-2:
-#ifdef REGS_64BIT
-	cmp		%o2, 128
-	or		%o1, %g1, %o1
-#endif
-	blu,pn		%xcc, 9f
-	 andcc		%o0, 0x38, %g5
-	be,pn		%icc, 6f
-	 mov		64, %o5
-	andcc		%o0, 8, %g0
-	be,pn		%icc, 1f
-	 sub		%o5, %g5, %o5
-#ifdef REGS_64BIT
-	stx		%o1, [%o0]
-#else
-	stw		%o1, [%o0]
-	stw		%o1, [%o0 + 4]
-#endif
-	add		%o0, 8, %o0
-1:	andcc		%o5, 16, %g0
-	be,pn		%icc, 1f
-	 sub		%o2, %o5, %o2
-#ifdef REGS_64BIT
-	stx		%o1, [%o0]
-	stx		%o1, [%o0 + 8]
-#else
-	stw		%o1, [%o0]
-	stw		%o1, [%o0 + 4]
-	stw		%o1, [%o0 + 8]
-	stw		%o1, [%o0 + 12]
-#endif
-	add		%o0, 16, %o0
-1:	andcc		%o5, 32, %g0
-	be,pn		%icc, 7f
-	 andncc		%o2, 0x3f, %o3
-#ifdef REGS_64BIT
-	stx		%o1, [%o0]
-	stx		%o1, [%o0 + 8]
-	stx		%o1, [%o0 + 16]
-	stx		%o1, [%o0 + 24]
-#else
-	stw		%o1, [%o0]
-	stw		%o1, [%o0 + 4]
-	stw		%o1, [%o0 + 8]
-	stw		%o1, [%o0 + 12]
-	stw		%o1, [%o0 + 16]
-	stw		%o1, [%o0 + 20]
-	stw		%o1, [%o0 + 24]
-	stw		%o1, [%o0 + 28]
-#endif
-	add		%o0, 32, %o0
-7:	be,pn		%xcc, 9f
-	 nop
-#ifdef __KERNEL__
-	VISEntryHalf
-#endif
-	ldd		[%o0 - 8], %f0
-18:	rd		%asi, %g2
-	wr		%g0, ASI_BLK_P, %asi
-	membar		#StoreStore | #LoadStore
-	andcc		%o3, 0xc0, %g5
-	and		%o2, 0x3f, %o2
-	fmovd		%f0, %f2
-	fmovd		%f0, %f4
-	andn		%o3, 0xff, %o3
-	fmovd		%f0, %f6
-	cmp		%g5, 64
-	fmovd		%f0, %f8
-	fmovd		%f0, %f10
-	fmovd		%f0, %f12
-	brz,pn		%g5, 10f
-	 fmovd		%f0, %f14
-	be,pn		%icc, 2f
-	 stda		%f0, [%o0 + 0x00] %asi
-	cmp		%g5, 128
-	be,pn		%icc, 2f
-	 stda		%f0, [%o0 + 0x40] %asi
-	stda		%f0, [%o0 + 0x80] %asi
-2:	brz,pn		%o3, 12f
-	 add		%o0, %g5, %o0
-10:	stda		%f0, [%o0 + 0x00] %asi
-	stda		%f0, [%o0 + 0x40] %asi
-	stda		%f0, [%o0 + 0x80] %asi
-	stda		%f0, [%o0 + 0xc0] %asi
-11:	subcc		%o3, 256, %o3
-	bne,pt		%xcc, 10b
-	 add		%o0, 256, %o0
-12:
-#ifdef __KERNEL__
-	wr		%g2, %g0, %asi
-	VISExitHalf
-#else
-#ifndef REGS_64BIT
-	wr		%g0, FPRS_FEF, %fprs
-#endif
-#endif
-	membar		#StoreLoad | #StoreStore
-9:	andcc		%o2, 0x78, %g5
-	be,pn		%xcc, 13f
-	 andcc		%o2, 7, %o2
-#ifdef __KERNEL__
-14:	srl		%g5, 1, %o3
-	sethi		%hi(13f), %g3
-	sub		%g3, %o3, %g3
-	jmpl		%g3 + %lo(13f), %g0
-	 add		%o0, %g5, %o0
-#else
-14:	rd		%pc, %g3
-#ifdef REGS_64BIT
-	srl		%g5, 1, %o3
-	sub		%g3, %o3, %g3
-#else
-	sub		%g3, %g5, %g3
-#endif
-	jmpl		%g3 + (13f - 14b), %g0
-	 add		%o0, %g5, %o0
-#endif
-12:	SET_BLOCKS(%o0, 0x68, %o1)
-	SET_BLOCKS(%o0, 0x48, %o1)
-	SET_BLOCKS(%o0, 0x28, %o1)
-	SET_BLOCKS(%o0, 0x08, %o1)
-13:	be,pn		%xcc, 8f
-	 andcc		%o2, 4, %g0
-	be,pn		%xcc, 1f
-	 andcc		%o2, 2, %g0
-	stw		%o1, [%o0]
-	add		%o0, 4, %o0
-1:	be,pn		%xcc, 1f
-	 andcc		%o2, 1, %g0
-	sth		%o1, [%o0]
-	add		%o0, 2, %o0
-1:	bne,a,pn	%xcc, 8f
-	 stb		%o1, [%o0]
-8:	retl
-	 mov		%o4, %o0
-17:	brz,pn		%o2, 0f
-8:	 add		%o0, 1, %o0
-	subcc		%o2, 1, %o2
-	bne,pt		%xcc, 8b
-	 stb		%o1, [%o0 - 1]
-0:	retl
-	 mov		%o4, %o0
-6:
-#ifdef REGS_64BIT
-	stx		%o1, [%o0]
-#else
-	stw		%o1, [%o0]
-	stw		%o1, [%o0 + 4]
-#endif
-	andncc		%o2, 0x3f, %o3
-	be,pn		%xcc, 9b
-	 nop
-#ifdef __KERNEL__
-	VISEntryHalf
-#endif
-	ba,pt		%xcc, 18b
-	 ldd		[%o0], %f0
diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S
--- a/arch/sparc64/lib/atomic.S
+++ b/arch/sparc64/lib/atomic.S
@@ -29,10 +29,10 @@
 	.globl	atomic_add
 	.type	atomic_add,#function
 atomic_add: /* %o0 = increment, %o1 = atomic_ptr */
-1:	lduw	[%o1], %g5
-	add	%g5, %o0, %g7
-	cas	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	lduw	[%o1], %g1
+	add	%g1, %o0, %g7
+	cas	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	 nop
 	retl
@@ -42,10 +42,10 @@ atomic_add: /* %o0 = increment, %o1 = at
 	.globl	atomic_sub
 	.type	atomic_sub,#function
 atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
-1:	lduw	[%o1], %g5
-	sub	%g5, %o0, %g7
-	cas	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	lduw	[%o1], %g1
+	sub	%g1, %o0, %g7
+	cas	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	 nop
 	retl
@@ -56,10 +56,10 @@ atomic_sub: /* %o0 = decrement, %o1 = at
 	.type	atomic_add_ret,#function
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
 	ATOMIC_PRE_BARRIER
-1:	lduw	[%o1], %g5
-	add	%g5, %o0, %g7
-	cas	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	lduw	[%o1], %g1
+	add	%g1, %o0, %g7
+	cas	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	 add	%g7, %o0, %g7
 	ATOMIC_POST_BARRIER
@@ -71,10 +71,10 @@ atomic_add_ret: /* %o0 = increment, %o1 
 	.type	atomic_sub_ret,#function
 atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
 	ATOMIC_PRE_BARRIER
-1:	lduw	[%o1], %g5
-	sub	%g5, %o0, %g7
-	cas	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	lduw	[%o1], %g1
+	sub	%g1, %o0, %g7
+	cas	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	 sub	%g7, %o0, %g7
 	ATOMIC_POST_BARRIER
@@ -85,10 +85,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 
 	.globl	atomic64_add
 	.type	atomic64_add,#function
 atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */
-1:	ldx	[%o1], %g5
-	add	%g5, %o0, %g7
-	casx	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	ldx	[%o1], %g1
+	add	%g1, %o0, %g7
+	casx	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	 nop
 	retl
@@ -98,10 +98,10 @@ atomic64_add: /* %o0 = increment, %o1 = 
 	.globl	atomic64_sub
 	.type	atomic64_sub,#function
 atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */
-1:	ldx	[%o1], %g5
-	sub	%g5, %o0, %g7
-	casx	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	ldx	[%o1], %g1
+	sub	%g1, %o0, %g7
+	casx	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	 nop
 	retl
@@ -112,10 +112,10 @@ atomic64_sub: /* %o0 = decrement, %o1 = 
 	.type	atomic64_add_ret,#function
 atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
 	ATOMIC_PRE_BARRIER
-1:	ldx	[%o1], %g5
-	add	%g5, %o0, %g7
-	casx	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	ldx	[%o1], %g1
+	add	%g1, %o0, %g7
+	casx	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	 add	%g7, %o0, %g7
 	ATOMIC_POST_BARRIER
@@ -127,10 +127,10 @@ atomic64_add_ret: /* %o0 = increment, %o
 	.type	atomic64_sub_ret,#function
 atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
 	ATOMIC_PRE_BARRIER
-1:	ldx	[%o1], %g5
-	sub	%g5, %o0, %g7
-	casx	[%o1], %g5, %g7
-	cmp	%g5, %g7
+1:	ldx	[%o1], %g1
+	sub	%g1, %o0, %g7
+	casx	[%o1], %g1, %g7
+	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	 sub	%g7, %o0, %g7
 	ATOMIC_POST_BARRIER
diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S
--- a/arch/sparc64/lib/bitops.S
+++ b/arch/sparc64/lib/bitops.S
@@ -26,17 +26,17 @@
 test_and_set_bit:	/* %o0=nr, %o1=addr */
 	BITOP_PRE_BARRIER
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	or	%g7, %g5, %g1
+	or	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
-	 and	%g7, %g5, %g2
+	 and	%g7, %o2, %g2
 	BITOP_POST_BARRIER
 	clr	%o0
 	retl
@@ -48,17 +48,17 @@ test_and_set_bit:	/* %o0=nr, %o1=addr */
 test_and_clear_bit:	/* %o0=nr, %o1=addr */
 	BITOP_PRE_BARRIER
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	andn	%g7, %g5, %g1
+	andn	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
-	 and	%g7, %g5, %g2
+	 and	%g7, %o2, %g2
 	BITOP_POST_BARRIER
 	clr	%o0
 	retl
@@ -70,17 +70,17 @@ test_and_clear_bit:	/* %o0=nr, %o1=addr 
 test_and_change_bit:	/* %o0=nr, %o1=addr */
 	BITOP_PRE_BARRIER
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	xor	%g7, %g5, %g1
+	xor	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
-	 and	%g7, %g5, %g2
+	 and	%g7, %o2, %g2
 	BITOP_POST_BARRIER
 	clr	%o0
 	retl
@@ -91,13 +91,13 @@ test_and_change_bit:	/* %o0=nr, %o1=addr
 	.type	set_bit,#function
 set_bit:		/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	or	%g7, %g5, %g1
+	or	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
@@ -110,13 +110,13 @@ set_bit:		/* %o0=nr, %o1=addr */
 	.type	clear_bit,#function
 clear_bit:		/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	andn	%g7, %g5, %g1
+	andn	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
@@ -129,13 +129,13 @@ clear_bit:		/* %o0=nr, %o1=addr */
 	.type	change_bit,#function
 change_bit:		/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
-	mov	1, %g5
+	mov	1, %o2
 	sllx	%g1, 3, %g3
 	and	%o0, 63, %g2
-	sllx	%g5, %g2, %g5
+	sllx	%o2, %g2, %o2
 	add	%o1, %g3, %o1
 1:	ldx	[%o1], %g7
-	xor	%g7, %g5, %g1
+	xor	%g7, %o2, %g1
 	casx	[%o1], %g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
diff --git a/arch/sparc64/lib/bzero.S b/arch/sparc64/lib/bzero.S
new file mode 100644
--- /dev/null
+++ b/arch/sparc64/lib/bzero.S
@@ -0,0 +1,158 @@
+/* bzero.S: Simple prefetching memset, bzero, and clear_user
+ *          implementations.
+ *
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+	.text
+
+	.globl	__memset
+	.type	__memset, #function
+__memset:		/* %o0=buf, %o1=pat, %o2=len */
+
+	.globl	memset
+	.type	memset, #function
+memset:			/* %o0=buf, %o1=pat, %o2=len */
+	and		%o1, 0xff, %o3
+	mov		%o2, %o1
+	sllx		%o3, 8, %g1
+	or		%g1, %o3, %o2
+	sllx		%o2, 16, %g1
+	or		%g1, %o2, %o2
+	sllx		%o2, 32, %g1
+	ba,pt		%xcc, 1f
+	 or		%g1, %o2, %o2
+
+	.globl	__bzero
+	.type	__bzero, #function
+__bzero:		/* %o0=buf, %o1=len */
+	clr		%o2
+1:	mov		%o0, %o3
+	brz,pn		%o1, __bzero_done
+	 cmp		%o1, 16
+	bl,pn		%icc, __bzero_tiny
+	 prefetch	[%o0 + 0x000], #n_writes
+	andcc		%o0, 0x3, %g0
+	be,pt		%icc, 2f
+1:	 stb		%o2, [%o0 + 0x00]
+	add		%o0, 1, %o0
+	andcc		%o0, 0x3, %g0
+	bne,pn		%icc, 1b
+	 sub		%o1, 1, %o1
+2:	andcc		%o0, 0x7, %g0
+	be,pt		%icc, 3f
+	 stw		%o2, [%o0 + 0x00]
+	sub		%o1, 4, %o1
+	add		%o0, 4, %o0
+3:	and		%o1, 0x38, %g1
+	cmp		%o1, 0x40
+	andn		%o1, 0x3f, %o4
+	bl,pn		%icc, 5f
+	 and		%o1, 0x7, %o1
+	prefetch	[%o0 + 0x040], #n_writes
+	prefetch	[%o0 + 0x080], #n_writes
+	prefetch	[%o0 + 0x0c0], #n_writes
+	prefetch	[%o0 + 0x100], #n_writes
+	prefetch	[%o0 + 0x140], #n_writes
+4:	prefetch	[%o0 + 0x180], #n_writes
+	stx		%o2, [%o0 + 0x00]
+	stx		%o2, [%o0 + 0x08]
+	stx		%o2, [%o0 + 0x10]
+	stx		%o2, [%o0 + 0x18]
+	stx		%o2, [%o0 + 0x20]
+	stx		%o2, [%o0 + 0x28]
+	stx		%o2, [%o0 + 0x30]
+	stx		%o2, [%o0 + 0x38]
+	subcc		%o4, 0x40, %o4
+	bne,pt		%icc, 4b
+	 add		%o0, 0x40, %o0
+	brz,pn		%g1, 6f
+	 nop
+5:	stx		%o2, [%o0 + 0x00]
+	subcc		%g1, 8, %g1
+	bne,pt		%icc, 5b
+	 add		%o0, 0x8, %o0
+6:	brz,pt		%o1, __bzero_done
+	 nop
+__bzero_tiny:
+1:	stb		%o2, [%o0 + 0x00]
+	subcc		%o1, 1, %o1
+	bne,pt		%icc, 1b
+	 add		%o0, 1, %o0
+__bzero_done:
+	retl
+	 mov		%o3, %o0
+	.size		__bzero, .-__bzero
+	.size		__memset, .-__memset
+	.size		memset, .-memset
+
+#define EX_ST(x,y)		\
+98:	x,y;			\
+	.section .fixup;	\
+	.align 4;		\
+99:	retl;			\
+	 mov	%o1, %o0;	\
+	.section __ex_table;	\
+	.align 4;		\
+	.word 98b, 99b;		\
+	.text;			\
+	.align 4;
+
+	.globl	__bzero_noasi
+	.type	__bzero_noasi, #function
+__bzero_noasi:		/* %o0=buf, %o1=len */
+	brz,pn		%o1, __bzero_noasi_done
+	 cmp		%o1, 16
+	bl,pn		%icc, __bzero_noasi_tiny
+	 EX_ST(prefetcha [%o0 + 0x00] %asi, #n_writes)
+	andcc		%o0, 0x3, %g0
+	be,pt		%icc, 2f
+1:	 EX_ST(stba	%g0, [%o0 + 0x00] %asi)
+	add		%o0, 1, %o0
+	andcc		%o0, 0x3, %g0
+	bne,pn		%icc, 1b
+	 sub		%o1, 1, %o1
+2:	andcc		%o0, 0x7, %g0
+	be,pt		%icc, 3f
+	 EX_ST(stwa	%g0, [%o0 + 0x00] %asi)
+	sub		%o1, 4, %o1
+	add		%o0, 4, %o0
+3:	and		%o1, 0x38, %g1
+	cmp		%o1, 0x40
+	andn		%o1, 0x3f, %o4
+	bl,pn		%icc, 5f
+	 and		%o1, 0x7, %o1
+	EX_ST(prefetcha	[%o0 + 0x040] %asi, #n_writes)
+	EX_ST(prefetcha	[%o0 + 0x080] %asi, #n_writes)
+	EX_ST(prefetcha	[%o0 + 0x0c0] %asi, #n_writes)
+	EX_ST(prefetcha	[%o0 + 0x100] %asi, #n_writes)
+	EX_ST(prefetcha	[%o0 + 0x140] %asi, #n_writes)
+4:	EX_ST(prefetcha	[%o0 + 0x180] %asi, #n_writes)
+	EX_ST(stxa	%g0, [%o0 + 0x00] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x08] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x10] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x18] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x20] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x28] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x30] %asi)
+	EX_ST(stxa	%g0, [%o0 + 0x38] %asi)
+	subcc		%o4, 0x40, %o4
+	bne,pt		%icc, 4b
+	 add		%o0, 0x40, %o0
+	brz,pn		%g1, 6f
+	 nop
+5:	EX_ST(stxa	%g0, [%o0 + 0x00] %asi)
+	subcc		%g1, 8, %g1
+	bne,pt		%icc, 5b
+	 add		%o0, 0x8, %o0
+6:	brz,pt		%o1, __bzero_noasi_done
+	 nop
+__bzero_noasi_tiny:
+1:	EX_ST(stba	%g0, [%o0 + 0x00] %asi)
+	subcc		%o1, 1, %o1
+	bne,pt		%icc, 1b
+	 add		%o0, 1, %o0
+__bzero_noasi_done:
+	retl
+	 clr		%o0
+	.size		__bzero_noasi, .-__bzero_noasi
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -13,500 +13,160 @@
  *	BSD4.4 portable checksum routine
  */
 
-#include <asm/errno.h>
-#include <asm/head.h>
-#include <asm/ptrace.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/thread_info.h>
-
-	/* The problem with the "add with carry" instructions on Ultra
-	 * are two fold.  Firstly, they cannot pair with jack shit,
-	 * and also they only add in the 32-bit carry condition bit
-	 * into the accumulated sum.  The following is much better.
-	 * For larger chunks we use VIS code, which is faster ;)
-	 */
-
-#define src o0
-#define dst o1
-#define len o2
-#define sum o3
-
 	.text
-	/* I think I have an erection...  Once _AGAIN_ the SunSoft
-	 * engineers are caught asleep at the keyboard, tsk tsk...
-	 */
 
-#define CSUMCOPY_LASTCHUNK(off, t0, t1)							\
-	ldxa		[%src - off - 0x08] %asi, t0;					\
-	ldxa		[%src - off - 0x00] %asi, t1;					\
-	nop; nop;									\
-	addcc		t0, %sum, %sum;							\
-	stw		t0, [%dst - off - 0x04];					\
-	srlx		t0, 32, t0;							\
-	bcc,pt		%xcc, 51f;							\
-	 stw		t0, [%dst - off - 0x08];					\
-	add		%sum, 1, %sum;							\
-51:	addcc		t1, %sum, %sum;							\
-	stw		t1, [%dst - off + 0x04];					\
-	srlx		t1, 32, t1;							\
-	bcc,pt		%xcc, 52f;							\
-	 stw		t1, [%dst - off - 0x00];					\
-	add		%sum, 1, %sum;							\
-52:
-
-cpc_start:
-cc_end_cruft:
-	andcc		%g7, 8, %g0		! IEU1	Group
-	be,pn		%icc, 1f		! CTI
-	 and		%g7, 4, %g5		! IEU0
-	ldxa		[%src + 0x00] %asi, %g2	! Load	Group
-	add		%dst, 8, %dst		! IEU0
-	add		%src, 8, %src		! IEU1
-	addcc		%g2, %sum, %sum		! IEU1	Group + 2 bubbles
-	stw		%g2, [%dst - 0x04]	! Store
-	srlx		%g2, 32, %g2		! IEU0
-	bcc,pt		%xcc, 1f		! CTI	Group
-	 stw		%g2, [%dst - 0x08]	! Store
-	add		%sum, 1, %sum		! IEU0
-1:	brz,pt		%g5, 1f			! CTI	Group
-	 clr		%g2			! IEU0
-	lduwa		[%src + 0x00] %asi, %g2	! Load
-	add		%dst, 4, %dst		! IEU0	Group
-	add		%src, 4, %src		! IEU1
-	stw		%g2, [%dst - 0x04]	! Store	Group + 2 bubbles
-	sllx		%g2, 32, %g2		! IEU0
-1:	andcc		%g7, 2, %g0		! IEU1
-	be,pn		%icc, 1f		! CTI	Group
-	 clr		%o4			! IEU1
-	lduha		[%src + 0x00] %asi, %o4	! Load
-	add		%src, 2, %src		! IEU0	Group
-	add		%dst, 2, %dst		! IEU1
-	sth		%o4, [%dst - 0x2]	! Store Group + 2 bubbles
-	sll		%o4, 16, %o4		! IEU0
-1:	andcc		%g7, 1, %g0		! IEU1
-	be,pn		%icc, 1f		! CTI	Group
-	 clr		%o5			! IEU0
-	lduba		[%src + 0x00] %asi, %o5	! Load
-	stb		%o5, [%dst + 0x00]	! Store	Group + 2 bubbles
-	sll		%o5, 8, %o5		! IEU0
-1:	or		%g2, %o4, %o4		! IEU1
-	or		%o5, %o4, %o4		! IEU0	Group
-	addcc		%o4, %sum, %sum		! IEU1
-	bcc,pt		%xcc, ccfold		! CTI
-	 nop					! IEU0	Group
-	b,pt		%xcc, ccfold		! CTI
-	 add		%sum, 1, %sum		! IEU1
-
-cc_fixit:
-	cmp		%len, 6			! IEU1	Group
-	bl,a,pn		%icc, ccte		! CTI
-	 andcc		%len, 0xf, %g7		! IEU1	Group
-	andcc		%src, 2, %g0		! IEU1	Group
-	be,pn		%icc, 1f		! CTI
-	 andcc		%src, 0x4, %g0		! IEU1	Group
-	lduha		[%src + 0x00] %asi, %g4	! Load
-	sub		%len, 2, %len		! IEU0
-	add		%src, 2, %src		! IEU0	Group
-	add		%dst, 2, %dst		! IEU1
-	sll		%g4, 16, %g3		! IEU0	Group + 1 bubble
-	addcc		%g3, %sum, %sum		! IEU1
-	bcc,pt		%xcc, 0f		! CTI
-	 srl		%sum, 16, %g3		! IEU0	Group
-	add		%g3, 1, %g3		! IEU0	4 clocks (mispredict)
-0:	andcc		%src, 0x4, %g0		! IEU1	Group
-	sth		%g4, [%dst - 0x2]	! Store
-	sll		%sum, 16, %sum		! IEU0
-	sll		%g3, 16, %g3		! IEU0	Group
-	srl		%sum, 16, %sum		! IEU0	Group
-	or		%g3, %sum, %sum		! IEU0	Group (regdep)
-1:	be,pt		%icc, ccmerge		! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1
-	lduwa		[%src + 0x00] %asi, %g4	! Load	Group
-	sub		%len, 4, %len		! IEU0
-	add		%src, 4, %src		! IEU1
-	add		%dst, 4, %dst		! IEU0	Group
-	addcc		%g4, %sum, %sum		! IEU1	Group + 1 bubble
-	stw		%g4, [%dst - 0x4]	! Store
-	bcc,pt		%xcc, ccmerge		! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1	Group
-	b,pt		%xcc, ccmerge		! CTI	4 clocks (mispredict)
-	 add		%sum, 1, %sum		! IEU0
+csum_partial_fix_alignment:
+	/* We checked for zero length already, so there must be
+	 * at least one byte.
+	 */
+	be,pt		%icc, 1f
+	 nop
+	ldub		[%o0 + 0x00], %o4
+	add		%o0, 1, %o0
+	sub		%o1, 1, %o1
+1:	andcc		%o0, 0x2, %g0
+	be,pn		%icc, csum_partial_post_align
+	 cmp		%o1, 2
+	blu,pn		%icc, csum_partial_end_cruft
+	 nop
+	lduh		[%o0 + 0x00], %o5
+	add		%o0, 2, %o0
+	sub		%o1, 2, %o1
+	ba,pt		%xcc, csum_partial_post_align
+	 add		%o5, %o4, %o4
 
 	.align		32
-	.globl		csum_partial_copy_sparc64
-csum_partial_copy_sparc64:			/* %o0=src, %o1=dest, %o2=len, %o3=sum */
-	xorcc		%src, %dst, %o4		! IEU1	Group
-	srl		%sum, 0, %sum		! IEU0
-	andcc		%o4, 3, %g0		! IEU1	Group
-	srl		%len, 0, %len		! IEU0
-	bne,pn		%icc, ccslow		! CTI
-	 andcc		%src, 1, %g0		! IEU1	Group
-	bne,pn		%icc, ccslow		! CTI
-	 cmp		%len, 256		! IEU1	Group
-	bgeu,pt		%icc, csum_partial_copy_vis ! CTI
-	 andcc		%src, 7, %g0		! IEU1	Group
-	bne,pn		%icc, cc_fixit		! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1	Group
-ccmerge:be,pn		%icc, ccte		! CTI
-	 andcc		%len, 0xf, %g7		! IEU1	Group
-	sll		%g1, 2, %o4		! IEU0
-13:	sethi		%hi(12f), %o5		! IEU0	Group
-	add		%src, %g1, %src		! IEU1	
-	sub		%o5, %o4, %o5		! IEU0	Group
-	jmpl		%o5 + %lo(12f), %g0	! CTI	Group brk forced
-	 add		%dst, %g1, %dst		! IEU0	Group
-cctbl:	CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
-12:
-	andcc		%len, 0xf, %g7		! IEU1	Group
-ccte:	bne,pn		%icc, cc_end_cruft	! CTI
-	 nop					! IEU0
-ccfold:	sllx		%sum, 32, %o0		! IEU0	Group
-	addcc		%sum, %o0, %o0		! IEU1	Group (regdep)
-	srlx		%o0, 32, %o0		! IEU0	Group (regdep)
-	bcs,a,pn	%xcc, 1f		! CTI
-	 add		%o0, 1, %o0		! IEU1	4 clocks (mispredict)
-1:	retl					! CTI	Group brk forced
-	 ldx		[%g6 + TI_TASK], %g4	! Load
-
-ccslow:	mov	0, %g5
-	brlez,pn %len, 4f
-	 andcc	%src, 1, %o5		
-	be,a,pt	%icc, 1f
-	 srl	%len, 1, %g7		
-	sub	%len, 1, %len	
-	lduba [%src] %asi, %g5
-	add	%src, 1, %src	
-	stb	%g5, [%dst]
-	srl	%len, 1, %g7
-	add	%dst, 1, %dst
-1:	brz,a,pn %g7, 3f
-	 andcc	%len, 1, %g0
-	andcc	%src, 2, %g0	
-	be,a,pt	%icc, 1f
-	 srl	%g7, 1, %g7
-	lduha [%src] %asi, %o4
-	sub	%len, 2, %len	
-	srl	%o4, 8, %g2
-	sub	%g7, 1, %g7	
-	stb	%g2, [%dst]
-	add	%o4, %g5, %g5
-	stb	%o4, [%dst + 1]
-	add	%src, 2, %src	
-	srl	%g7, 1, %g7
-	add	%dst, 2, %dst
-1:	brz,a,pn %g7, 2f		
-	 andcc	%len, 2, %g0
-	lduwa	[%src] %asi, %o4
-5:	srl	%o4, 24, %g2
-	srl	%o4, 16, %g3
-	stb	%g2, [%dst]
-	srl	%o4, 8, %g2
-	stb	%g3, [%dst + 1]
-	add	%src, 4, %src
-	stb	%g2, [%dst + 2]
-	addcc	%o4, %g5, %g5
-	stb	%o4, [%dst + 3]
-	addc	%g5, %g0, %g5
-	add	%dst, 4, %dst
-	subcc	%g7, 1, %g7
-	bne,a,pt %icc, 5b
-	 lduwa [%src] %asi, %o4
-	sll	%g5, 16, %g2
-	srl	%g5, 16, %g5
-	srl	%g2, 16, %g2
-	andcc	%len, 2, %g0
-	add	%g2, %g5, %g5 
-2:	be,a,pt	%icc, 3f		
-	 andcc	%len, 1, %g0
-	lduha [%src] %asi, %o4
-	andcc	%len, 1, %g0
-	srl	%o4, 8, %g2
-	add	%src, 2, %src	
-	stb	%g2, [%dst]
-	add	%g5, %o4, %g5
-	stb	%o4, [%dst + 1]
-	add	%dst, 2, %dst
-3:	be,a,pt	%icc, 1f		
-	 sll	%g5, 16, %o4
-	lduba [%src] %asi, %g2
-	sll	%g2, 8, %o4	
-	stb	%g2, [%dst]
-	add	%g5, %o4, %g5
-	sll	%g5, 16, %o4
-1:	addcc	%o4, %g5, %g5
-	srl	%g5, 16, %o4
-	addc	%g0, %o4, %g5
-	brz,pt	%o5, 4f
-	 srl	%g5, 8, %o4
-	and	%g5, 0xff, %g2
-	and	%o4, 0xff, %o4
-	sll	%g2, 8, %g2
-	or	%g2, %o4, %g5
-4:	addcc	%sum, %g5, %sum
-	addc	%g0, %sum, %o0
-	retl	
-	 srl	%o0, 0, %o0
-cpc_end:
-
-	/* Now the version with userspace as the destination */
-#define CSUMCOPY_LASTCHUNK_USER(off, t0, t1)						\
-	ldx		[%src - off - 0x08], t0;					\
-	ldx		[%src - off - 0x00], t1;					\
-	nop; nop;									\
-	addcc		t0, %sum, %sum;							\
-	stwa		t0, [%dst - off - 0x04] %asi;					\
-	srlx		t0, 32, t0;							\
-	bcc,pt		%xcc, 51f;							\
-	 stwa		t0, [%dst - off - 0x08] %asi;					\
-	add		%sum, 1, %sum;							\
-51:	addcc		t1, %sum, %sum;							\
-	stwa		t1, [%dst - off + 0x04] %asi;					\
-	srlx		t1, 32, t1;							\
-	bcc,pt		%xcc, 52f;							\
-	 stwa		t1, [%dst - off - 0x00] %asi;					\
-	add		%sum, 1, %sum;							\
-52:
-
-cpc_user_start:
-cc_user_end_cruft:
-	andcc		%g7, 8, %g0		! IEU1	Group
-	be,pn		%icc, 1f		! CTI
-	 and		%g7, 4, %g5		! IEU0
-	ldx		[%src + 0x00], %g2	! Load	Group
-	add		%dst, 8, %dst		! IEU0
-	add		%src, 8, %src		! IEU1
-	addcc		%g2, %sum, %sum		! IEU1	Group + 2 bubbles
-	stwa		%g2, [%dst - 0x04] %asi	! Store
-	srlx		%g2, 32, %g2		! IEU0
-	bcc,pt		%xcc, 1f		! CTI	Group
-	 stwa		%g2, [%dst - 0x08] %asi	! Store
-	add		%sum, 1, %sum		! IEU0
-1:	brz,pt		%g5, 1f			! CTI	Group
-	 clr		%g2			! IEU0
-	lduw		[%src + 0x00], %g2	! Load
-	add		%dst, 4, %dst		! IEU0	Group
-	add		%src, 4, %src		! IEU1
-	stwa		%g2, [%dst - 0x04] %asi	! Store	Group + 2 bubbles
-	sllx		%g2, 32, %g2		! IEU0
-1:	andcc		%g7, 2, %g0		! IEU1
-	be,pn		%icc, 1f		! CTI	Group
-	 clr		%o4			! IEU1
-	lduh		[%src + 0x00], %o4	! Load
-	add		%src, 2, %src		! IEU0	Group
-	add		%dst, 2, %dst		! IEU1
-	stha		%o4, [%dst - 0x2] %asi	! Store Group + 2 bubbles
-	sll		%o4, 16, %o4		! IEU0
-1:	andcc		%g7, 1, %g0		! IEU1
-	be,pn		%icc, 1f		! CTI	Group
-	 clr		%o5			! IEU0
-	ldub		[%src + 0x00], %o5	! Load
-	stba		%o5, [%dst + 0x00] %asi	! Store	Group + 2 bubbles
-	sll		%o5, 8, %o5		! IEU0
-1:	or		%g2, %o4, %o4		! IEU1
-	or		%o5, %o4, %o4		! IEU0	Group
-	addcc		%o4, %sum, %sum		! IEU1
-	bcc,pt		%xcc, ccuserfold	! CTI
-	 nop					! IEU0	Group
-	b,pt		%xcc, ccuserfold	! CTI
-	 add		%sum, 1, %sum		! IEU1
-
-cc_user_fixit:
-	cmp		%len, 6			! IEU1	Group
-	bl,a,pn		%icc, ccuserte		! CTI
-	 andcc		%len, 0xf, %g7		! IEU1	Group
-	andcc		%src, 2, %g0		! IEU1	Group
-	be,pn		%icc, 1f		! CTI
-	 andcc		%src, 0x4, %g0		! IEU1	Group
-	lduh		[%src + 0x00], %g4	! Load
-	sub		%len, 2, %len		! IEU0
-	add		%src, 2, %src		! IEU0	Group
-	add		%dst, 2, %dst		! IEU1
-	sll		%g4, 16, %g3		! IEU0	Group + 1 bubble
-	addcc		%g3, %sum, %sum		! IEU1
-	bcc,pt		%xcc, 0f		! CTI
-	 srl		%sum, 16, %g3		! IEU0	Group
-	add		%g3, 1, %g3		! IEU0	4 clocks (mispredict)
-0:	andcc		%src, 0x4, %g0		! IEU1	Group
-	stha		%g4, [%dst - 0x2] %asi	! Store
-	sll		%sum, 16, %sum		! IEU0
-	sll		%g3, 16, %g3		! IEU0	Group
-	srl		%sum, 16, %sum		! IEU0	Group
-	or		%g3, %sum, %sum		! IEU0	Group (regdep)
-1:	be,pt		%icc, ccusermerge	! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1
-	lduw		[%src + 0x00], %g4	! Load	Group
-	sub		%len, 4, %len		! IEU0
-	add		%src, 4, %src		! IEU1
-	add		%dst, 4, %dst		! IEU0	Group
-	addcc		%g4, %sum, %sum		! IEU1	Group + 1 bubble
-	stwa		%g4, [%dst - 0x4] %asi	! Store
-	bcc,pt		%xcc, ccusermerge	! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1	Group
-	b,pt		%xcc, ccusermerge	! CTI	4 clocks (mispredict)
-	 add		%sum, 1, %sum		! IEU0
+	.globl		csum_partial
+csum_partial:		/* %o0=buff, %o1=len, %o2=sum */
+	prefetch	[%o0 + 0x000], #n_reads
+	clr		%o4
+	prefetch	[%o0 + 0x040], #n_reads
+	brz,pn		%o1, csum_partial_finish
+	 andcc		%o0, 0x3, %g0
+
+	/* We "remember" whether the lowest bit in the address
+	 * was set in %g7.  Because if it is, we have to swap
+	 * upper and lower 8 bit fields of the sum we calculate.
+	*/
+	bne,pn		%icc, csum_partial_fix_alignment
+	 andcc		%o0, 0x1, %g7
+
+csum_partial_post_align:
+	prefetch	[%o0 + 0x080], #n_reads
+	andncc		%o1, 0x3f, %o3
+
+	prefetch	[%o0 + 0x0c0], #n_reads
+	sub		%o1, %o3, %o1
+	brz,pn		%o3, 2f
+	 prefetch	[%o0 + 0x100], #n_reads
+
+	/* So that we don't need to use the non-pairing
+	 * add-with-carry instructions we accumulate 32-bit
+	 * values into a 64-bit register.  At the end of the
+	 * loop we fold it down to 32-bits and so on.
+	 */
+	prefetch	[%o0 + 0x140], #n_reads
+1:	lduw		[%o0 + 0x00], %o5
+	lduw		[%o0 + 0x04], %g1
+	lduw		[%o0 + 0x08], %g2
+	add		%o4, %o5, %o4
+	lduw		[%o0 + 0x0c], %g3
+	add		%o4, %g1, %o4
+	lduw		[%o0 + 0x10], %o5
+	add		%o4, %g2, %o4
+	lduw		[%o0 + 0x14], %g1
+	add		%o4, %g3, %o4
+	lduw		[%o0 + 0x18], %g2
+	add		%o4, %o5, %o4
+	lduw		[%o0 + 0x1c], %g3
+	add		%o4, %g1, %o4
+	lduw		[%o0 + 0x20], %o5
+	add		%o4, %g2, %o4
+	lduw		[%o0 + 0x24], %g1
+	add		%o4, %g3, %o4
+	lduw		[%o0 + 0x28], %g2
+	add		%o4, %o5, %o4
+	lduw		[%o0 + 0x2c], %g3
+	add		%o4, %g1, %o4
+	lduw		[%o0 + 0x30], %o5
+	add		%o4, %g2, %o4
+	lduw		[%o0 + 0x34], %g1
+	add		%o4, %g3, %o4
+	lduw		[%o0 + 0x38], %g2
+	add		%o4, %o5, %o4
+	lduw		[%o0 + 0x3c], %g3
+	add		%o4, %g1, %o4
+	prefetch	[%o0 + 0x180], #n_reads
+	add		%o4, %g2, %o4
+	subcc		%o3, 0x40, %o3
+	add		%o0, 0x40, %o0
+	bne,pt		%icc, 1b
+	 add		%o4, %g3, %o4
+
+2:	and		%o1, 0x3c, %o3
+	brz,pn		%o3, 2f
+	 sub		%o1, %o3, %o1
+1:	lduw		[%o0 + 0x00], %o5
+	subcc		%o3, 0x4, %o3
+	add		%o0, 0x4, %o0
+	bne,pt		%icc, 1b
+	 add		%o4, %o5, %o4
+
+2:
+	/* fold 64-->32 */
+	srlx		%o4, 32, %o5
+	srl		%o4, 0, %o4
+	add		%o4, %o5, %o4
+	srlx		%o4, 32, %o5
+	srl		%o4, 0, %o4
+	add		%o4, %o5, %o4
+
+	/* fold 32-->16 */
+	sethi		%hi(0xffff0000), %g1
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+
+csum_partial_end_cruft:
+	/* %o4 has the 16-bit sum we have calculated so-far.  */
+	cmp		%o1, 2
+	blu,pt		%icc, 1f
+	 nop
+	lduh		[%o0 + 0x00], %o5
+	sub		%o1, 2, %o1
+	add		%o0, 2, %o0
+	add		%o4, %o5, %o4
+1:	brz,pt		%o1, 1f
+	 nop
+	ldub		[%o0 + 0x00], %o5
+	sub		%o1, 1, %o1
+	add		%o0, 1, %o0
+	sllx		%o5, 8, %o5
+	add		%o4, %o5, %o4
+1:
+	/* fold 32-->16 */
+	sethi		%hi(0xffff0000), %g1
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+
+1:	brz,pt		%g7, 1f
+	 nop
+
+	/* We started with an odd byte, byte-swap the result.  */
+	srl		%o4, 8, %o5
+	and		%o4, 0xff, %g1
+	sll		%g1, 8, %g1
+	or		%o5, %g1, %o4
 
-	.align		32
-	.globl		csum_partial_copy_user_sparc64
-csum_partial_copy_user_sparc64:			/* %o0=src, %o1=dest, %o2=len, %o3=sum */
-	xorcc		%src, %dst, %o4		! IEU1	Group
-	srl		%sum, 0, %sum		! IEU0
-	andcc		%o4, 3, %g0		! IEU1	Group
-	srl		%len, 0, %len		! IEU0
-	bne,pn		%icc, ccuserslow	! CTI
-	 andcc		%src, 1, %g0		! IEU1	Group
-	bne,pn		%icc, ccuserslow	! CTI
-	 cmp		%len, 256		! IEU1	Group
-	bgeu,pt		%icc, csum_partial_copy_user_vis ! CTI
-	 andcc		%src, 7, %g0		! IEU1	Group
-	bne,pn		%icc, cc_user_fixit	! CTI
-	 andcc		%len, 0xf0, %g1		! IEU1	Group
-ccusermerge:
-	be,pn		%icc, ccuserte		! CTI
-	 andcc		%len, 0xf, %g7		! IEU1	Group
-	sll		%g1, 2, %o4		! IEU0
-13:	sethi		%hi(12f), %o5		! IEU0	Group
-	add		%src, %g1, %src		! IEU1	
-	sub		%o5, %o4, %o5		! IEU0	Group
-	jmpl		%o5 + %lo(12f), %g0	! CTI	Group brk forced
-	 add		%dst, %g1, %dst		! IEU0	Group
-ccusertbl:
-	CSUMCOPY_LASTCHUNK_USER(0xe8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0xd8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0xc8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0xb8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0xa8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x98,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x88,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x78,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x68,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x58,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x48,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x38,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x28,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x18,%g2,%g3)
-	CSUMCOPY_LASTCHUNK_USER(0x08,%g2,%g3)
-12:
-	andcc		%len, 0xf, %g7		! IEU1	Group
-ccuserte:
-	bne,pn		%icc, cc_user_end_cruft	! CTI
-	 nop					! IEU0
-ccuserfold:
-	sllx		%sum, 32, %o0		! IEU0	Group
-	addcc		%sum, %o0, %o0		! IEU1	Group (regdep)
-	srlx		%o0, 32, %o0		! IEU0	Group (regdep)
-	bcs,a,pn	%xcc, 1f		! CTI
-	 add		%o0, 1, %o0		! IEU1	4 clocks (mispredict)
-1:	retl					! CTI	Group brk forced
-	 ldx		[%g6 + TI_TASK], %g4	! IEU0	Group
-
-ccuserslow:
-	mov	0, %g5
-	brlez,pn %len, 4f
-	 andcc	%src, 1, %o5		
-	be,a,pt	%icc, 1f
-	 srl	%len, 1, %g7		
-	sub	%len, 1, %len	
-	ldub [%src], %g5
-	add	%src, 1, %src	
-	stba	%g5, [%dst] %asi
-	srl	%len, 1, %g7
-	add	%dst, 1, %dst
-1:	brz,a,pn %g7, 3f
-	 andcc	%len, 1, %g0
-	andcc	%src, 2, %g0	
-	be,a,pt	%icc, 1f
-	 srl	%g7, 1, %g7
-	lduh [%src], %o4
-	sub	%len, 2, %len	
-	srl	%o4, 8, %g2
-	sub	%g7, 1, %g7	
-	stba	%g2, [%dst] %asi
-	add	%o4, %g5, %g5
-	stba	%o4, [%dst + 1] %asi
-	add	%src, 2, %src	
-	srl	%g7, 1, %g7
-	add	%dst, 2, %dst
-1:	brz,a,pn %g7, 2f		
-	 andcc	%len, 2, %g0
-	lduw	[%src], %o4
-5:	srl	%o4, 24, %g2
-	srl	%o4, 16, %g3
-	stba	%g2, [%dst] %asi
-	srl	%o4, 8, %g2
-	stba	%g3, [%dst + 1] %asi
-	add	%src, 4, %src
-	stba	%g2, [%dst + 2] %asi
-	addcc	%o4, %g5, %g5
-	stba	%o4, [%dst + 3] %asi
-	addc	%g5, %g0, %g5
-	add	%dst, 4, %dst
-	subcc	%g7, 1, %g7
-	bne,a,pt %icc, 5b
-	 lduw [%src], %o4
-	sll	%g5, 16, %g2
-	srl	%g5, 16, %g5
-	srl	%g2, 16, %g2
-	andcc	%len, 2, %g0
-	add	%g2, %g5, %g5 
-2:	be,a,pt	%icc, 3f		
-	 andcc	%len, 1, %g0
-	lduh [%src], %o4
-	andcc	%len, 1, %g0
-	srl	%o4, 8, %g2
-	add	%src, 2, %src	
-	stba	%g2, [%dst] %asi
-	add	%g5, %o4, %g5
-	stba	%o4, [%dst + 1] %asi
-	add	%dst, 2, %dst
-3:	be,a,pt	%icc, 1f		
-	 sll	%g5, 16, %o4
-	ldub [%src], %g2
-	sll	%g2, 8, %o4	
-	stba 	%g2, [%dst] %asi
-	add	%g5, %o4, %g5
-	sll	%g5, 16, %o4
-1:	addcc	%o4, %g5, %g5
-	srl	%g5, 16, %o4
-	addc	%g0, %o4, %g5
-	brz,pt	%o5, 4f
-	 srl	%g5, 8, %o4
-	and	%g5, 0xff, %g2
-	and	%o4, 0xff, %o4
-	sll	%g2, 8, %g2
-	or	%g2, %o4, %g5
-4:	addcc	%sum, %g5, %sum
-	addc	%g0, %sum, %o0
-	retl	
-	 srl	%o0, 0, %o0
-cpc_user_end:
-
-	.globl	cpc_handler
-cpc_handler:
-	ldx	[%sp + 0x7ff + 128], %g1
-	ldub	[%g6 + TI_CURRENT_DS], %g3
-	sub	%g0, EFAULT, %g2
-	brnz,a,pt %g1, 1f
-	 st	%g2, [%g1]
-1:	wr	%g3, %g0, %asi
-	retl
-	 ldx	[%g6 + TI_TASK], %g4
+1:	add		%o2, %o4, %o2
 
-	.section __ex_table
-	.align  4
-	.word	cpc_start, 0, cpc_end, cpc_handler
-	.word	cpc_user_start, 0, cpc_user_end, cpc_handler
+csum_partial_finish:
+	retl
+	 mov		%o2, %o0
diff --git a/arch/sparc64/lib/csum_copy.S b/arch/sparc64/lib/csum_copy.S
new file mode 100644
--- /dev/null
+++ b/arch/sparc64/lib/csum_copy.S
@@ -0,0 +1,308 @@
+/* csum_copy.S: Checksum+copy code for sparc64
+ *
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifdef __KERNEL__
+#define GLOBAL_SPARE	%g7
+#else
+#define GLOBAL_SPARE	%g5
+#endif
+
+#ifndef EX_LD
+#define EX_LD(x)	x
+#endif
+
+#ifndef EX_ST
+#define EX_ST(x)	x
+#endif
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+#endif
+
+#ifndef LOAD
+#define LOAD(type,addr,dest)	type [addr], dest
+#endif
+
+#ifndef STORE
+#define STORE(type,src,addr)	type src, [addr]
+#endif
+
+#ifndef FUNC_NAME
+#define FUNC_NAME	csum_partial_copy_nocheck
+#endif
+
+	.register	%g2, #scratch
+	.register	%g3, #scratch
+
+	.text
+
+90:
+	/* We checked for zero length already, so there must be
+	 * at least one byte.
+	 */
+	be,pt		%icc, 1f
+	 nop
+	EX_LD(LOAD(ldub, %o0 + 0x00, %o4))
+	add		%o0, 1, %o0
+	sub		%o2, 1, %o2
+	EX_ST(STORE(stb, %o4, %o1 + 0x00))
+	add		%o1, 1, %o1
+1:	andcc		%o0, 0x2, %g0
+	be,pn		%icc, 80f
+	 cmp		%o2, 2
+	blu,pn		%icc, 60f
+	 nop
+	EX_LD(LOAD(lduh, %o0 + 0x00, %o5))
+	add		%o0, 2, %o0
+	sub		%o2, 2, %o2
+	EX_ST(STORE(sth, %o5, %o1 + 0x00))
+	add		%o1, 2, %o1
+	ba,pt		%xcc, 80f
+	 add		%o5, %o4, %o4
+
+	.globl		FUNC_NAME
+FUNC_NAME:		/* %o0=src, %o1=dst, %o2=len, %o3=sum */
+	LOAD(prefetch, %o0 + 0x000, #n_reads)
+	xor		%o0, %o1, %g1
+	clr		%o4
+	andcc		%g1, 0x3, %g0
+	bne,pn		%icc, 95f
+	 LOAD(prefetch, %o0 + 0x040, #n_reads)
+	
+	brz,pn		%o2, 70f
+	 andcc		%o0, 0x3, %g0
+
+	/* We "remember" whether the lowest bit in the address
+	 * was set in GLOBAL_SPARE.  Because if it is, we have to swap
+	 * upper and lower 8 bit fields of the sum we calculate.
+	*/
+	bne,pn		%icc, 90b
+	 andcc		%o0, 0x1, GLOBAL_SPARE
+
+80:
+	LOAD(prefetch, %o0 + 0x080, #n_reads)
+	andncc		%o2, 0x3f, %g3
+
+	LOAD(prefetch, %o0 + 0x0c0, #n_reads)
+	sub		%o2, %g3, %o2
+	brz,pn		%g3, 2f
+	 LOAD(prefetch, %o0 + 0x100, #n_reads)
+
+	/* So that we don't need to use the non-pairing
+	 * add-with-carry instructions we accumulate 32-bit
+	 * values into a 64-bit register.  At the end of the
+	 * loop we fold it down to 32-bits and so on.
+	 */
+	ba,pt		%xcc, 1f
+	LOAD(prefetch, %o0 + 0x140, #n_reads)
+
+	.align		32
+1:	EX_LD(LOAD(lduw, %o0 + 0x00, %o5))
+	EX_LD(LOAD(lduw, %o0 + 0x04, %g1))
+	EX_LD(LOAD(lduw, %o0 + 0x08, %g2))
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x00))
+	EX_LD(LOAD(lduw, %o0 + 0x0c, %o5))
+	add		%o4, %g1, %o4
+	EX_ST(STORE(stw, %g1, %o1 + 0x04))
+	EX_LD(LOAD(lduw, %o0 + 0x10, %g1))
+	add		%o4, %g2, %o4
+	EX_ST(STORE(stw, %g2, %o1 + 0x08))
+	EX_LD(LOAD(lduw, %o0 + 0x14, %g2))
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x0c))
+	EX_LD(LOAD(lduw, %o0 + 0x18, %o5))
+	add		%o4, %g1, %o4
+	EX_ST(STORE(stw, %g1, %o1 + 0x10))
+	EX_LD(LOAD(lduw, %o0 + 0x1c, %g1))
+	add		%o4, %g2, %o4
+	EX_ST(STORE(stw, %g2, %o1 + 0x14))
+	EX_LD(LOAD(lduw, %o0 + 0x20, %g2))
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x18))
+	EX_LD(LOAD(lduw, %o0 + 0x24, %o5))
+	add		%o4, %g1, %o4
+	EX_ST(STORE(stw, %g1, %o1 + 0x1c))
+	EX_LD(LOAD(lduw, %o0 + 0x28, %g1))
+	add		%o4, %g2, %o4
+	EX_ST(STORE(stw, %g2, %o1 + 0x20))
+	EX_LD(LOAD(lduw, %o0 + 0x2c, %g2))
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x24))
+	EX_LD(LOAD(lduw, %o0 + 0x30, %o5))
+	add		%o4, %g1, %o4
+	EX_ST(STORE(stw, %g1, %o1 + 0x28))
+	EX_LD(LOAD(lduw, %o0 + 0x34, %g1))
+	add		%o4, %g2, %o4
+	EX_ST(STORE(stw, %g2, %o1 + 0x2c))
+	EX_LD(LOAD(lduw, %o0 + 0x38, %g2))
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x30))
+	EX_LD(LOAD(lduw, %o0 + 0x3c, %o5))
+	add		%o4, %g1, %o4
+	EX_ST(STORE(stw, %g1, %o1 + 0x34))
+	LOAD(prefetch, %o0 + 0x180, #n_reads)
+	add		%o4, %g2, %o4
+	EX_ST(STORE(stw, %g2, %o1 + 0x38))
+	subcc		%g3, 0x40, %g3
+	add		%o0, 0x40, %o0
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x3c))
+	bne,pt		%icc, 1b
+	 add		%o1, 0x40, %o1
+
+2:	and		%o2, 0x3c, %g3
+	brz,pn		%g3, 2f
+	 sub		%o2, %g3, %o2
+1:	EX_LD(LOAD(lduw, %o0 + 0x00, %o5))
+	subcc		%g3, 0x4, %g3
+	add		%o0, 0x4, %o0
+	add		%o4, %o5, %o4
+	EX_ST(STORE(stw, %o5, %o1 + 0x00))
+	bne,pt		%icc, 1b
+	 add		%o1, 0x4, %o1
+
+2:
+	/* fold 64-->32 */
+	srlx		%o4, 32, %o5
+	srl		%o4, 0, %o4
+	add		%o4, %o5, %o4
+	srlx		%o4, 32, %o5
+	srl		%o4, 0, %o4
+	add		%o4, %o5, %o4
+
+	/* fold 32-->16 */
+	sethi		%hi(0xffff0000), %g1
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+
+60:
+	/* %o4 has the 16-bit sum we have calculated so-far.  */
+	cmp		%o2, 2
+	blu,pt		%icc, 1f
+	 nop
+	EX_LD(LOAD(lduh, %o0 + 0x00, %o5))
+	sub		%o2, 2, %o2
+	add		%o0, 2, %o0
+	add		%o4, %o5, %o4
+	EX_ST(STORE(sth, %o5, %o1 + 0x00))
+	add		%o1, 0x2, %o1
+1:	brz,pt		%o2, 1f
+	 nop
+	EX_LD(LOAD(ldub, %o0 + 0x00, %o5))
+	sub		%o2, 1, %o2
+	add		%o0, 1, %o0
+	EX_ST(STORE(stb, %o5, %o1 + 0x00))
+	sllx		%o5, 8, %o5
+	add		%o1, 1, %o1
+	add		%o4, %o5, %o4
+1:
+	/* fold 32-->16 */
+	sethi		%hi(0xffff0000), %g1
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+	srl		%o4, 16, %o5
+	andn		%o4, %g1, %g2
+	add		%o5, %g2, %o4
+
+1:	brz,pt		GLOBAL_SPARE, 1f
+	 nop
+
+	/* We started with an odd byte, byte-swap the result.  */
+	srl		%o4, 8, %o5
+	and		%o4, 0xff, %g1
+	sll		%g1, 8, %g1
+	or		%o5, %g1, %o4
+
+1:	add		%o3, %o4, %o3
+
+70:
+	retl
+	 mov		%o3, %o0
+
+95:	mov		0, GLOBAL_SPARE
+	brlez,pn	%o2, 4f
+	 andcc		%o0, 1, %o5		
+	be,a,pt		%icc, 1f
+	 srl		%o2, 1, %g1		
+	sub		%o2, 1, %o2	
+	EX_LD(LOAD(ldub, %o0, GLOBAL_SPARE))
+	add		%o0, 1, %o0	
+	EX_ST(STORE(stb, GLOBAL_SPARE, %o1))
+	srl		%o2, 1, %g1
+	add		%o1, 1, %o1
+1:	brz,a,pn	%g1, 3f
+	 andcc		%o2, 1, %g0
+	andcc		%o0, 2, %g0	
+	be,a,pt		%icc, 1f
+	 srl		%g1, 1, %g1
+	EX_LD(LOAD(lduh, %o0, %o4))
+	sub		%o2, 2, %o2	
+	srl		%o4, 8, %g2
+	sub		%g1, 1, %g1	
+	EX_ST(STORE(stb, %g2, %o1))
+	add		%o4, GLOBAL_SPARE, GLOBAL_SPARE
+	EX_ST(STORE(stb, %o4, %o1 + 1))
+	add		%o0, 2, %o0	
+	srl		%g1, 1, %g1
+	add		%o1, 2, %o1
+1:	brz,a,pn	%g1, 2f		
+	 andcc		%o2, 2, %g0
+	EX_LD(LOAD(lduw, %o0, %o4))
+5:	srl		%o4, 24, %g2
+	srl		%o4, 16, %g3
+	EX_ST(STORE(stb, %g2, %o1))
+	srl		%o4, 8, %g2
+	EX_ST(STORE(stb, %g3, %o1 + 1))
+	add		%o0, 4, %o0
+	EX_ST(STORE(stb, %g2, %o1 + 2))
+	addcc		%o4, GLOBAL_SPARE, GLOBAL_SPARE
+	EX_ST(STORE(stb, %o4, %o1 + 3))
+	addc		GLOBAL_SPARE, %g0, GLOBAL_SPARE
+	add		%o1, 4, %o1
+	subcc		%g1, 1, %g1
+	bne,a,pt	%icc, 5b
+	 EX_LD(LOAD(lduw, %o0, %o4))
+	sll		GLOBAL_SPARE, 16, %g2
+	srl		GLOBAL_SPARE, 16, GLOBAL_SPARE
+	srl		%g2, 16, %g2
+	andcc		%o2, 2, %g0
+	add		%g2, GLOBAL_SPARE, GLOBAL_SPARE 
+2:	be,a,pt		%icc, 3f		
+	 andcc		%o2, 1, %g0
+	EX_LD(LOAD(lduh, %o0, %o4))
+	andcc		%o2, 1, %g0
+	srl		%o4, 8, %g2
+	add		%o0, 2, %o0	
+	EX_ST(STORE(stb, %g2, %o1))
+	add		GLOBAL_SPARE, %o4, GLOBAL_SPARE
+	EX_ST(STORE(stb, %o4, %o1 + 1))
+	add		%o1, 2, %o1
+3:	be,a,pt		%icc, 1f		
+	 sll		GLOBAL_SPARE, 16, %o4
+	EX_LD(LOAD(ldub, %o0, %g2))
+	sll		%g2, 8, %o4	
+	EX_ST(STORE(stb, %g2, %o1))
+	add		GLOBAL_SPARE, %o4, GLOBAL_SPARE
+	sll		GLOBAL_SPARE, 16, %o4
+1:	addcc		%o4, GLOBAL_SPARE, GLOBAL_SPARE
+	srl		GLOBAL_SPARE, 16, %o4
+	addc		%g0, %o4, GLOBAL_SPARE
+	brz,pt		%o5, 4f
+	 srl		GLOBAL_SPARE, 8, %o4
+	and		GLOBAL_SPARE, 0xff, %g2
+	and		%o4, 0xff, %o4
+	sll		%g2, 8, %g2
+	or		%g2, %o4, GLOBAL_SPARE
+4:	addcc		%o3, GLOBAL_SPARE, %o3
+	addc		%g0, %o3, %o0
+	retl
+	 srl		%o0, 0, %o0
+	.size		FUNC_NAME, .-FUNC_NAME
diff --git a/arch/sparc64/lib/csum_copy_from_user.S b/arch/sparc64/lib/csum_copy_from_user.S
new file mode 100644
--- /dev/null
+++ b/arch/sparc64/lib/csum_copy_from_user.S
@@ -0,0 +1,21 @@
+/* csum_copy_from_user.S: Checksum+copy from userspace.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_LD(x)		\
+98:	x;			\
+	.section .fixup;	\
+	.align 4;		\
+99:	retl;			\
+	 mov	-1, %o0;	\
+	.section __ex_table;	\
+	.align 4;		\
+	.word 98b, 99b;		\
+	.text;			\
+	.align 4;
+
+#define FUNC_NAME		__csum_partial_copy_from_user
+#define LOAD(type,addr,dest)	type##a [addr] %asi, dest
+
+#include "csum_copy.S"
diff --git a/arch/sparc64/lib/csum_copy_to_user.S b/arch/sparc64/lib/csum_copy_to_user.S
new file mode 100644
--- /dev/null
+++ b/arch/sparc64/lib/csum_copy_to_user.S
@@ -0,0 +1,21 @@
+/* csum_copy_to_user.S: Checksum+copy to userspace.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_ST(x)		\
+98:	x;			\
+	.section .fixup;	\
+	.align 4;		\
+99:	retl;			\
+	 mov	-1, %o0;	\
+	.section __ex_table;	\
+	.align 4;		\
+	.word 98b, 99b;		\
+	.text;			\
+	.align 4;
+
+#define FUNC_NAME		__csum_partial_copy_to_user
+#define STORE(type,src,addr)	type##a src, [addr] %asi
+
+#include "csum_copy.S"
diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c
--- a/arch/sparc64/lib/debuglocks.c
+++ b/arch/sparc64/lib/debuglocks.c
@@ -138,15 +138,15 @@ wlock_again:
 	}
 	/* Try once to increment the counter.  */
 	__asm__ __volatile__(
-"	ldx		[%0], %%g5\n"
-"	brlz,a,pn	%%g5, 2f\n"
+"	ldx		[%0], %%g1\n"
+"	brlz,a,pn	%%g1, 2f\n"
 "	 mov		1, %0\n"
-"	add		%%g5, 1, %%g7\n"
-"	casx		[%0], %%g5, %%g7\n"
-"	sub		%%g5, %%g7, %0\n"
+"	add		%%g1, 1, %%g7\n"
+"	casx		[%0], %%g1, %%g7\n"
+"	sub		%%g1, %%g7, %0\n"
 "2:"	: "=r" (val)
 	: "0" (&(rw->lock))
-	: "g5", "g7", "memory");
+	: "g1", "g7", "memory");
 	membar("#StoreLoad | #StoreStore");
 	if (val)
 		goto wlock_again;
@@ -173,14 +173,14 @@ runlock_again:
 	/* Spin trying to decrement the counter using casx.  */
 	__asm__ __volatile__(
 "	membar	#StoreLoad | #LoadLoad\n"
-"	ldx	[%0], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	casx	[%0], %%g5, %%g7\n"
+"	ldx	[%0], %%g1\n"
+"	sub	%%g1, 1, %%g7\n"
+"	casx	[%0], %%g1, %%g7\n"
 "	membar	#StoreLoad | #StoreStore\n"
-"	sub	%%g5, %%g7, %0\n"
+"	sub	%%g1, %%g7, %0\n"
 	: "=r" (val)
 	: "0" (&(rw->lock))
-	: "g5", "g7", "memory");
+	: "g1", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
 			if (shown++ <= 2)
@@ -216,17 +216,17 @@ wlock_again:
 	__asm__ __volatile__(
 "	mov	1, %%g3\n"
 "	sllx	%%g3, 63, %%g3\n"
-"	ldx	[%0], %%g5\n"
-"	brlz,pn	%%g5, 1f\n"
-"	 or	%%g5, %%g3, %%g7\n"
-"	casx	[%0], %%g5, %%g7\n"
+"	ldx	[%0], %%g1\n"
+"	brlz,pn	%%g1, 1f\n"
+"	 or	%%g1, %%g3, %%g7\n"
+"	casx	[%0], %%g1, %%g7\n"
 "	membar	#StoreLoad | #StoreStore\n"
 "	ba,pt	%%xcc, 2f\n"
-"	 sub	%%g5, %%g7, %0\n"
+"	 sub	%%g1, %%g7, %0\n"
 "1:	mov	1, %0\n"
 "2:"	: "=r" (val)
 	: "0" (&(rw->lock))
-	: "g3", "g5", "g7", "memory");
+	: "g3", "g1", "g7", "memory");
 	if (val) {
 		/* We couldn't get the write bit. */
 		if (!--stuck) {
@@ -248,15 +248,15 @@ wlock_again:
 		__asm__ __volatile__(
 "		mov	1, %%g3\n"
 "		sllx	%%g3, 63, %%g3\n"
-"1:		ldx	[%0], %%g5\n"
-"		andn	%%g5, %%g3, %%g7\n"
-"		casx	[%0], %%g5, %%g7\n"
-"		cmp	%%g5, %%g7\n"
+"1:		ldx	[%0], %%g1\n"
+"		andn	%%g1, %%g3, %%g7\n"
+"		casx	[%0], %%g1, %%g7\n"
+"		cmp	%%g1, %%g7\n"
 "		bne,pn	%%xcc, 1b\n"
 "		 membar	#StoreLoad | #StoreStore"
 		: /* no outputs */
 		: "r" (&(rw->lock))
-		: "g3", "g5", "g7", "cc", "memory");
+		: "g3", "g1", "g7", "cc", "memory");
 		while(rw->lock != 0) {
 			if (!--stuck) {
 				if (shown++ <= 2)
@@ -294,14 +294,14 @@ wlock_again:
 "	membar	#StoreLoad | #LoadLoad\n"
 "	mov	1, %%g3\n"
 "	sllx	%%g3, 63, %%g3\n"
-"	ldx	[%0], %%g5\n"
-"	andn	%%g5, %%g3, %%g7\n"
-"	casx	[%0], %%g5, %%g7\n"
+"	ldx	[%0], %%g1\n"
+"	andn	%%g1, %%g3, %%g7\n"
+"	casx	[%0], %%g1, %%g7\n"
 "	membar	#StoreLoad | #StoreStore\n"
-"	sub	%%g5, %%g7, %0\n"
+"	sub	%%g1, %%g7, %0\n"
 	: "=r" (val)
 	: "0" (&(rw->lock))
-	: "g3", "g5", "g7", "memory");
+	: "g3", "g1", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
 			if (shown++ <= 2)
@@ -323,17 +323,17 @@ int _do_write_trylock (rwlock_t *rw, cha
 	__asm__ __volatile__(
 "	mov	1, %%g3\n"
 "	sllx	%%g3, 63, %%g3\n"
-"	ldx	[%0], %%g5\n"
-"	brlz,pn	%%g5, 1f\n"
-"	 or	%%g5, %%g3, %%g7\n"
-"	casx	[%0], %%g5, %%g7\n"
+"	ldx	[%0], %%g1\n"
+"	brlz,pn	%%g1, 1f\n"
+"	 or	%%g1, %%g3, %%g7\n"
+"	casx	[%0], %%g1, %%g7\n"
 "	membar	#StoreLoad | #StoreStore\n"
 "	ba,pt	%%xcc, 2f\n"
-"	 sub	%%g5, %%g7, %0\n"
+"	 sub	%%g1, %%g7, %0\n"
 "1:	mov	1, %0\n"
 "2:"	: "=r" (val)
 	: "0" (&(rw->lock))
-	: "g3", "g5", "g7", "memory");
+	: "g3", "g1", "g7", "memory");
 
 	if (val) {
 		put_cpu();
@@ -347,15 +347,15 @@ int _do_write_trylock (rwlock_t *rw, cha
 		__asm__ __volatile__(
 "		mov	1, %%g3\n"
 "		sllx	%%g3, 63, %%g3\n"
-"1:		ldx	[%0], %%g5\n"
-"		andn	%%g5, %%g3, %%g7\n"
-"		casx	[%0], %%g5, %%g7\n"
-"		cmp	%%g5, %%g7\n"
+"1:		ldx	[%0], %%g1\n"
+"		andn	%%g1, %%g3, %%g7\n"
+"		casx	[%0], %%g1, %%g7\n"
+"		cmp	%%g1, %%g7\n"
 "		bne,pn	%%xcc, 1b\n"
 "		 membar	#StoreLoad | #StoreStore"
 		: /* no outputs */
 		: "r" (&(rw->lock))
-		: "g3", "g5", "g7", "cc", "memory");
+		: "g3", "g1", "g7", "cc", "memory");
 
 		put_cpu();
 
diff --git a/arch/sparc64/lib/dec_and_lock.S b/arch/sparc64/lib/dec_and_lock.S
--- a/arch/sparc64/lib/dec_and_lock.S
+++ b/arch/sparc64/lib/dec_and_lock.S
@@ -27,12 +27,12 @@
 
 	.globl	_atomic_dec_and_lock
 _atomic_dec_and_lock:	/* %o0 = counter, %o1 = lock */
-loop1:	lduw	[%o0], %g5
-	subcc	%g5, 1, %g7
+loop1:	lduw	[%o0], %g2
+	subcc	%g2, 1, %g7
 	be,pn	%icc, start_to_zero
 	 nop
-nzero:	cas	[%o0], %g5, %g7
-	cmp	%g5, %g7
+nzero:	cas	[%o0], %g2, %g7
+	cmp	%g2, %g7
 	bne,pn	%icc, loop1
 	 mov	0, %g1
 
@@ -50,13 +50,13 @@ to_zero:
 	ldstub	[%o1], %g3
 	brnz,pn	%g3, spin_on_lock
 	 membar	#StoreLoad | #StoreStore
-loop2:	cas	[%o0], %g5, %g7		/* ASSERT(g7 == 0) */
-	cmp	%g5, %g7
+loop2:	cas	[%o0], %g2, %g7		/* ASSERT(g7 == 0) */
+	cmp	%g2, %g7
 
 	be,pt	%icc, out
 	 mov	1, %g1
-	lduw	[%o0], %g5
-	subcc	%g5, 1, %g7
+	lduw	[%o0], %g2
+	subcc	%g2, 1, %g7
 	be,pn	%icc, loop2
 	 nop
 	membar	#StoreStore | #LoadStore
diff --git a/arch/sparc64/lib/mcount.S b/arch/sparc64/lib/mcount.S
--- a/arch/sparc64/lib/mcount.S
+++ b/arch/sparc64/lib/mcount.S
@@ -38,22 +38,22 @@ _mcount:
 	 * Check whether %sp is dangerously low.
 	 */
 	ldub		[%g6 + TI_FPDEPTH], %g1
-	srl		%g1, 1, %g5
-	add		%g5, 1, %g5
-	sllx		%g5, 8, %g5			! each fpregs frame is 256b
-	add		%g5, 192, %g5
-	add		%g6, %g5, %g5			! where does task_struct+frame end?
-	sub		%g5, STACK_BIAS, %g5
-	cmp		%sp, %g5
+	srl		%g1, 1, %g3
+	add		%g3, 1, %g3
+	sllx		%g3, 8, %g3			! each fpregs frame is 256b
+	add		%g3, 192, %g3
+	add		%g6, %g3, %g3			! where does task_struct+frame end?
+	sub		%g3, STACK_BIAS, %g3
+	cmp		%sp, %g3
 	bg,pt		%xcc, 1f
-	 sethi		%hi(panicstring), %g5
+	 sethi		%hi(panicstring), %g3
 	sethi		%hi(ovstack), %g7		! cant move to panic stack fast enough
 	 or		%g7, %lo(ovstack), %g7
 	add		%g7, OVSTACKSIZE, %g7
 	sub		%g7, STACK_BIAS, %g7
 	mov		%g7, %sp
 	call		prom_printf
-	 or		%g5, %lo(panicstring), %o0
+	 or		%g3, %lo(panicstring), %o0
 	call		prom_halt
 	 nop
 #endif
diff --git a/arch/sparc64/lib/memcmp.S b/arch/sparc64/lib/memcmp.S
--- a/arch/sparc64/lib/memcmp.S
+++ b/arch/sparc64/lib/memcmp.S
@@ -13,12 +13,12 @@ memcmp:
 	cmp	%o2, 0		! IEU1	Group
 loop:	be,pn	%icc, ret_0	! CTI
 	 nop			! IEU0
-	ldub	[%o0], %g5	! LSU	Group
+	ldub	[%o0], %g7	! LSU	Group
 	ldub	[%o1], %g3	! LSU	Group
 	sub	%o2, 1, %o2	! IEU0
 	add	%o0, 1, %o0	! IEU1
 	add	%o1, 1, %o1	! IEU0	Group
-	subcc	%g5, %g3, %g3	! IEU1	Group
+	subcc	%g7, %g3, %g3	! IEU1	Group
 	be,pt	%icc, loop	! CTI
 	 cmp	%o2, 0		! IEU1	Group
 
diff --git a/arch/sparc64/lib/memmove.S b/arch/sparc64/lib/memmove.S
--- a/arch/sparc64/lib/memmove.S
+++ b/arch/sparc64/lib/memmove.S
@@ -12,17 +12,17 @@ memmove:		/* o0=dst o1=src o2=len */
 	mov		%o0, %g1
 	cmp		%o0, %o1
 	bleu,pt		%xcc, memcpy
-	 add		%o1, %o2, %g5
-	cmp		%g5, %o0
+	 add		%o1, %o2, %g7
+	cmp		%g7, %o0
 	bleu,pt		%xcc, memcpy
 	 add		%o0, %o2, %o5
-	sub		%g5, 1, %o1
+	sub		%g7, 1, %o1
 
 	sub		%o5, 1, %o0
-1:	ldub		[%o1], %g5
+1:	ldub		[%o1], %g7
 	subcc		%o2, 1, %o2
 	sub		%o1, 1, %o1
-	stb		%g5, [%o0]
+	stb		%g7, [%o0]
 	bne,pt		%icc, 1b
 	 sub		%o0, 1, %o0
 
diff --git a/arch/sparc64/lib/memscan.S b/arch/sparc64/lib/memscan.S
--- a/arch/sparc64/lib/memscan.S
+++ b/arch/sparc64/lib/memscan.S
@@ -52,43 +52,43 @@ check_bytes:
 	 andcc		%o5, 0xff, %g0
 	add		%o0, -5, %g2
 	ba,pt		%xcc, 3f
-	 srlx		%o5, 32, %g5
+	 srlx		%o5, 32, %g7
 
-2:	srlx		%o5, 8, %g5
+2:	srlx		%o5, 8, %g7
 	be,pn		%icc, 1f
 	 add		%o0, -8, %g2
-	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 	be,pn		%icc, 1f
 	 inc		%g2
-	andcc		%g5, 0xff, %g0
+	andcc		%g7, 0xff, %g0
 
-	srlx		%g5, 8, %g5
+	srlx		%g7, 8, %g7
 	be,pn		%icc, 1f
 	 inc		%g2
-	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 	be,pn		%icc, 1f
 	 inc		%g2
 	andcc		%g3, %o3, %g0
 
 	be,a,pn		%icc, 2f
 	 mov		%o0, %g2
-3:	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+3:	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 	be,pn		%icc, 1f
 	 inc		%g2
-	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 
 	be,pn		%icc, 1f
 	 inc		%g2
-	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 	be,pn		%icc, 1f
 	 inc		%g2
-	andcc		%g5, 0xff, %g0
-	srlx		%g5, 8, %g5
+	andcc		%g7, 0xff, %g0
+	srlx		%g7, 8, %g7
 
 	be,pn		%icc, 1f
 	 inc		%g2
diff --git a/arch/sparc64/lib/rwsem.S b/arch/sparc64/lib/rwsem.S
new file mode 100644
--- /dev/null
+++ b/arch/sparc64/lib/rwsem.S
@@ -0,0 +1,165 @@
+/* rwsem.S: RW semaphore assembler.
+ *
+ * Written by David S. Miller (davem@redhat.com), 2001.
+ * Derived from asm-i386/rwsem.h
+ */
+
+#include <asm/rwsem-const.h>
+
+	.section	.sched.text
+
+	.globl		__down_read
+__down_read:
+1:	lduw		[%o0], %g1
+	add		%g1, 1, %g7
+	cas		[%o0], %g1, %g7
+	cmp		%g1, %g7
+	bne,pn		%icc, 1b
+	 add		%g7, 1, %g7
+	cmp		%g7, 0
+	bl,pn		%icc, 3f
+	 membar		#StoreLoad | #StoreStore
+2:
+	retl
+	 nop
+3:
+	save		%sp, -192, %sp
+	call		rwsem_down_read_failed
+	 mov		%i0, %o0
+	ret
+	 restore
+	.size		__down_read, .-__down_read
+
+	.globl		__down_read_trylock
+__down_read_trylock:
+1:	lduw		[%o0], %g1
+	add		%g1, 1, %g7
+	cmp		%g7, 0
+	bl,pn		%icc, 2f
+	 mov		0, %o1
+	cas		[%o0], %g1, %g7
+	cmp		%g1, %g7
+	bne,pn		%icc, 1b
+	 mov		1, %o1
+	membar		#StoreLoad | #StoreStore
+2:	retl
+	 mov		%o1, %o0
+	.size		__down_read_trylock, .-__down_read_trylock
+
+	.globl		__down_write
+__down_write:
+	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+	lduw		[%o0], %g3
+	add		%g3, %g1, %g7
+	cas		[%o0], %g3, %g7
+	cmp		%g3, %g7
+	bne,pn		%icc, 1b
+	 cmp		%g7, 0
+	bne,pn		%icc, 3f
+	 membar		#StoreLoad | #StoreStore
+2:	retl
+	 nop
+3:
+	save		%sp, -192, %sp
+	call		rwsem_down_write_failed
+	 mov		%i0, %o0
+	ret
+	 restore
+	.size		__down_write, .-__down_write
+
+	.globl		__down_write_trylock
+__down_write_trylock:
+	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+	lduw		[%o0], %g3
+	cmp		%g3, 0
+	bne,pn		%icc, 2f
+	 mov		0, %o1
+	add		%g3, %g1, %g7
+	cas		[%o0], %g3, %g7
+	cmp		%g3, %g7
+	bne,pn		%icc, 1b
+	 mov		1, %o1
+	membar		#StoreLoad | #StoreStore
+2:	retl
+	 mov		%o1, %o0
+	.size		__down_write_trylock, .-__down_write_trylock
+
+	.globl		__up_read
+__up_read:
+1:
+	lduw		[%o0], %g1
+	sub		%g1, 1, %g7
+	cas		[%o0], %g1, %g7
+	cmp		%g1, %g7
+	bne,pn		%icc, 1b
+	 cmp		%g7, 0
+	bl,pn		%icc, 3f
+	 membar		#StoreLoad | #StoreStore
+2:	retl
+	 nop
+3:	sethi		%hi(RWSEM_ACTIVE_MASK), %g1
+	sub		%g7, 1, %g7
+	or		%g1, %lo(RWSEM_ACTIVE_MASK), %g1
+	andcc		%g7, %g1, %g0
+	bne,pn		%icc, 2b
+	 nop
+	save		%sp, -192, %sp
+	call		rwsem_wake
+	 mov		%i0, %o0
+	ret
+	 restore
+	.size		__up_read, .-__up_read
+
+	.globl		__up_write
+__up_write:
+	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+	lduw		[%o0], %g3
+	sub		%g3, %g1, %g7
+	cas		[%o0], %g3, %g7
+	cmp		%g3, %g7
+	bne,pn		%icc, 1b
+	 sub		%g7, %g1, %g7
+	cmp		%g7, 0
+	bl,pn		%icc, 3f
+	 membar		#StoreLoad | #StoreStore
+2:
+	retl
+	 nop
+3:
+	save		%sp, -192, %sp
+	call		rwsem_wake
+	 mov		%i0, %o0
+	ret
+	 restore
+	.size		__up_write, .-__up_write
+
+	.globl		__downgrade_write
+__downgrade_write:
+	sethi		%hi(RWSEM_WAITING_BIAS), %g1
+	or		%g1, %lo(RWSEM_WAITING_BIAS), %g1
+1:
+	lduw		[%o0], %g3
+	sub		%g3, %g1, %g7
+	cas		[%o0], %g3, %g7
+	cmp		%g3, %g7
+	bne,pn		%icc, 1b
+	 sub		%g7, %g1, %g7
+	cmp		%g7, 0
+	bl,pn		%icc, 3f
+	 membar		#StoreLoad | #StoreStore
+2:
+	retl
+	 nop
+3:
+	save		%sp, -192, %sp
+	call		rwsem_downgrade_wake
+	 mov		%i0, %o0
+	ret
+	 restore
+	.size		__downgrade_write, .-__downgrade_write
diff --git a/arch/sparc64/lib/rwsem.c b/arch/sparc64/lib/rwsem.c
deleted file mode 100644
--- a/arch/sparc64/lib/rwsem.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* rwsem.c: Don't inline expand these suckers all over the place.
- *
- * Written by David S. Miller (davem@redhat.com), 2001.
- * Derived from asm-i386/rwsem.h
- */
-
-#include <linux/kernel.h>
-#include <linux/rwsem.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
-extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *));
-
-void __sched __down_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __down_read\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"add		%%g5, 1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" add		%%g7, 1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g1, %%l1\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l1, %%g1\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __down_read"
-		: : "r" (sem), "i" (rwsem_down_read_failed)
-		: "g5", "g7", "memory", "cc");
-}
-EXPORT_SYMBOL(__down_read);
-
-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;
-}
-EXPORT_SYMBOL(__down_read_trylock);
-
-void __sched __down_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __down_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"add		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" cmp		%%g7, 0\n\t"
-		"bne,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __down_write"
-		: : "r" (sem), "i" (rwsem_down_write_failed),
-		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-EXPORT_SYMBOL(__down_write);
-
-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;
-}
-EXPORT_SYMBOL(__down_write_trylock);
-
-void __up_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __up_read\n\t"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, 1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tsethi	%%hi(%2), %%g1\n\t"
-		"sub		%%g7, 1, %%g7\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n\t"
-		"andcc		%%g7, %%g1, %%g0\n\t"
-		"bne,pn		%%icc, 2b\n\t"
-		" mov		%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_read"
-		: : "r" (sem), "i" (rwsem_wake),
-		    "i" (RWSEM_ACTIVE_MASK)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-EXPORT_SYMBOL(__up_read);
-
-void __up_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __up_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" sub		%%g7, %%g1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection 2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_write"
-		: : "r" (sem), "i" (rwsem_wake),
-		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-EXPORT_SYMBOL(__up_write);
-
-void __downgrade_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __downgrade_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" sub		%%g7, %%g1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection 2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_write"
-		: : "r" (sem), "i" (rwsem_downgrade_wake),
-		    "i" (RWSEM_WAITING_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-EXPORT_SYMBOL(__downgrade_write);
diff --git a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S
--- a/arch/sparc64/lib/strlen.S
+++ b/arch/sparc64/lib/strlen.S
@@ -48,16 +48,16 @@ strlen:
 	 add	%o0, 4, %o0
 
 	/* Check every byte. */
-	srl	%o5, 24, %g5
-	andcc	%g5, 0xff, %g0
+	srl	%o5, 24, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o0, -4, %o4
-	srl	%o5, 16, %g5
-	andcc	%g5, 0xff, %g0
+	srl	%o5, 16, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o4, 1, %o4
-	srl	%o5, 8, %g5
-	andcc	%g5, 0xff, %g0
+	srl	%o5, 8, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o4, 1, %o4
 	andcc	%o5, 0xff, %g0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -54,16 +54,16 @@ __strnlen_user:	
 	ba,a,pt	%xcc, 1f
 
 	/* Check every byte. */
-82:	srl	%o5, 24, %g5
-	andcc	%g5, 0xff, %g0
+82:	srl	%o5, 24, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o0, -3, %o4
-	srl	%o5, 16, %g5
-	andcc	%g5, 0xff, %g0
+	srl	%o5, 16, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o4, 1, %o4
-	srl	%o5, 8, %g5
-	andcc	%g5, 0xff, %g0
+	srl	%o5, 8, %g7
+	andcc	%g7, 0xff, %g0
 	be,pn	%icc, 1f
 	 add	%o4, 1, %o4
 	andcc	%o5, 0xff, %g0
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -34,15 +34,15 @@
 	.type	__strncpy_from_user,#function
 __strncpy_from_user:
 	/* %o0=dest, %o1=src, %o2=count */
-	sethi	%hi(0b), %o5		! IEU0	Group
-	andcc	%o1, 7, %g0		! IEU1
+	andcc	%o1, 7, %g0		! IEU1	Group
 	bne,pn	%icc, 30f		! CTI
-	 ldx	[%o5 + %lo(0b)], %o4	! Load	Group
-	add	%o0, %o2, %g3		! IEU0
+	 add	%o0, %o2, %g3		! IEU0
 60:	ldxa	[%o1] %asi, %g1		! Load	Group
 	brlez,pn %o2, 10f		! CTI
-	 sllx	%o4, 7, %o5		! IEU0	Group
-	mov	%o0, %o3		! IEU1
+	 mov	%o0, %o3		! IEU0
+50:	sethi	%hi(0b), %o4		! IEU0	Group
+	ldx	[%o4 + %lo(0b)], %o4	! Load
+	sllx	%o4, 7, %o5		! IEU1	Group
 1:	sub	%g1, %o4, %g2		! IEU0	Group
 	stx	%g1, [%o0]		! Store
 	add	%o0, 8, %o0		! IEU1
@@ -55,34 +55,34 @@ __strncpy_from_user:
 10:	retl				! CTI	Group
 	 mov	%o2, %o0		! IEU0
 5:	srlx	%g2, 32, %g7		! IEU0	Group
-	sethi	%hi(0xff00), %g5	! IEU1
+	sethi	%hi(0xff00), %o4	! IEU1
 	andcc	%g7, %o5, %g0		! IEU1	Group
 	be,pn	%icc, 2f		! CTI
-	 or	%g5, %lo(0xff00), %g5	! IEU0
+	 or	%o4, %lo(0xff00), %o4	! IEU0
 	srlx	%g1, 48, %g7		! IEU0	Group
-	andcc	%g7, %g5, %g0		! IEU1	Group
+	andcc	%g7, %o4, %g0		! IEU1	Group
 	be,pn	%icc, 50f		! CTI
 	 andcc	%g7, 0xff, %g0		! IEU1	Group
 	be,pn	%icc, 51f		! CTI
 	 srlx	%g1, 32, %g7		! IEU0
-	andcc	%g7, %g5, %g0		! IEU1	Group
+	andcc	%g7, %o4, %g0		! IEU1	Group
 	be,pn	%icc, 52f		! CTI
 	 andcc	%g7, 0xff, %g0		! IEU1	Group
 	be,pn	%icc, 53f		! CTI
 2:	 andcc	%g2, %o5, %g0		! IEU1	Group
 	be,pn	%icc, 2f		! CTI
 	 srl	%g1, 16, %g7		! IEU0
-	andcc	%g7, %g5, %g0		! IEU1	Group
+	andcc	%g7, %o4, %g0		! IEU1	Group
 	be,pn	%icc, 54f		! CTI
 	 andcc	%g7, 0xff, %g0		! IEU1	Group
 	be,pn	%icc, 55f		! CTI
-	 andcc	%g1, %g5, %g0		! IEU1	Group
+	 andcc	%g1, %o4, %g0		! IEU1	Group
 	be,pn	%icc, 56f		! CTI
 	 andcc	%g1, 0xff, %g0		! IEU1	Group
 	be,a,pn	%icc, 57f		! CTI
 	 sub	%o0, %o3, %o0		! IEU0
 2:	cmp	%o0, %g3		! IEU1	Group
-	bl,a,pt	%xcc, 1b		! CTI
+	bl,a,pt	%xcc, 50b		! CTI
 62:	 ldxa	[%o1] %asi, %g1		! Load
 	retl				! CTI	Group
 	 mov	%o2, %o0		! IEU0
diff --git a/arch/sparc64/lib/xor.S b/arch/sparc64/lib/xor.S
--- a/arch/sparc64/lib/xor.S
+++ b/arch/sparc64/lib/xor.S
@@ -248,7 +248,7 @@ xor_vis_4:
 	.globl	xor_vis_5
 	.type	xor_vis_5,#function
 xor_vis_5:
-	mov	%o5, %g5
+	save	%sp, -192, %sp
 	rd	%fprs, %o5
 	andcc	%o5, FPRS_FEF|FPRS_DU, %g0
 	be,pt	%icc, 0f
@@ -256,61 +256,60 @@ xor_vis_5:
 	jmpl	%g1 + %lo(VISenter), %g7
 	 add	%g7, 8, %g7
 0:	wr	%g0, FPRS_FEF, %fprs
-	mov	%g5, %o5
 	rd	%asi, %g1
 	wr	%g0, ASI_BLK_P, %asi
 	membar	#LoadStore|#StoreLoad|#StoreStore
-	sub	%o0, 64, %o0
-	ldda	[%o1] %asi, %f0
-	ldda	[%o2] %asi, %f16
+	sub	%i0, 64, %i0
+	ldda	[%i1] %asi, %f0
+	ldda	[%i2] %asi, %f16
 
-5:	ldda	[%o3] %asi, %f32
+5:	ldda	[%i3] %asi, %f32
 	fxor	%f0, %f16, %f48
 	fxor	%f2, %f18, %f50
-	add	%o1, 64, %o1
+	add	%i1, 64, %i1
 	fxor	%f4, %f20, %f52
 	fxor	%f6, %f22, %f54
-	add	%o2, 64, %o2
+	add	%i2, 64, %i2
 	fxor	%f8, %f24, %f56
 	fxor	%f10, %f26, %f58
 	fxor	%f12, %f28, %f60
 	fxor	%f14, %f30, %f62
-	ldda	[%o4] %asi, %f16
+	ldda	[%i4] %asi, %f16
 	fxor	%f48, %f32, %f48
 	fxor	%f50, %f34, %f50
 	fxor	%f52, %f36, %f52
 	fxor	%f54, %f38, %f54
-	add	%o3, 64, %o3
+	add	%i3, 64, %i3
 	fxor	%f56, %f40, %f56
 	fxor	%f58, %f42, %f58
 	fxor	%f60, %f44, %f60
 	fxor	%f62, %f46, %f62
-	ldda	[%o5] %asi, %f32
+	ldda	[%i5] %asi, %f32
 	fxor	%f48, %f16, %f48
 	fxor	%f50, %f18, %f50
-	add	%o4, 64, %o4
+	add	%i4, 64, %i4
 	fxor	%f52, %f20, %f52
 	fxor	%f54, %f22, %f54
-	add	%o5, 64, %o5
+	add	%i5, 64, %i5
 	fxor	%f56, %f24, %f56
 	fxor	%f58, %f26, %f58
 	fxor	%f60, %f28, %f60
 	fxor	%f62, %f30, %f62
-	ldda	[%o1] %asi, %f0
+	ldda	[%i1] %asi, %f0
 	fxor	%f48, %f32, %f48
 	fxor	%f50, %f34, %f50
 	fxor	%f52, %f36, %f52
 	fxor	%f54, %f38, %f54
 	fxor	%f56, %f40, %f56
 	fxor	%f58, %f42, %f58
-	subcc	%o0, 64, %o0
+	subcc	%i0, 64, %i0
 	fxor	%f60, %f44, %f60
 	fxor	%f62, %f46, %f62
-	stda	%f48, [%o1 - 64] %asi
+	stda	%f48, [%i1 - 64] %asi
 	bne,pt	%xcc, 5b
-	 ldda	[%o2] %asi, %f16
+	 ldda	[%i2] %asi, %f16
 
-	ldda	[%o3] %asi, %f32
+	ldda	[%i3] %asi, %f32
 	fxor	%f0, %f16, %f48
 	fxor	%f2, %f18, %f50
 	fxor	%f4, %f20, %f52
@@ -319,7 +318,7 @@ xor_vis_5:
 	fxor	%f10, %f26, %f58
 	fxor	%f12, %f28, %f60
 	fxor	%f14, %f30, %f62
-	ldda	[%o4] %asi, %f16
+	ldda	[%i4] %asi, %f16
 	fxor	%f48, %f32, %f48
 	fxor	%f50, %f34, %f50
 	fxor	%f52, %f36, %f52
@@ -328,7 +327,7 @@ xor_vis_5:
 	fxor	%f58, %f42, %f58
 	fxor	%f60, %f44, %f60
 	fxor	%f62, %f46, %f62
-	ldda	[%o5] %asi, %f32
+	ldda	[%i5] %asi, %f32
 	fxor	%f48, %f16, %f48
 	fxor	%f50, %f18, %f50
 	fxor	%f52, %f20, %f52
@@ -346,9 +345,10 @@ xor_vis_5:
 	fxor	%f58, %f42, %f58
 	fxor	%f60, %f44, %f60
 	fxor	%f62, %f46, %f62
-	stda	%f48, [%o1] %asi
+	stda	%f48, [%i1] %asi
 	membar	#Sync|#StoreStore|#StoreLoad
 	wr	%g1, %g0, %asi
-	retl
-	 wr	%g0, 0, %fprs
+	wr	%g0, 0, %fprs
+	ret
+	 restore
 	.size	xor_vis_5, .-xor_vis_5
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -144,7 +144,9 @@ static void unhandled_fault(unsigned lon
 		       "at virtual address %016lx\n", (unsigned long)address);
 	}
 	printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n",
-	       (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
+	       (tsk->mm ?
+		CTX_HWBITS(tsk->mm->context) :
+		CTX_HWBITS(tsk->active_mm->context)));
 	printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
 	       (tsk->mm ? (unsigned long) tsk->mm->pgd :
 		          (unsigned long) tsk->active_mm->pgd));
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
--- a/arch/sparc64/mm/generic.c
+++ b/arch/sparc64/mm/generic.c
@@ -20,16 +20,17 @@
  *
  * They use a pgprot that sets PAGE_IO and does not check the
  * mem_map table as this is independent of normal memory.
- *
- * As a special hack if the lowest bit of offset is set the
- * side-effect bit will be turned off.  This is used as a
- * performance improvement on FFB/AFB. -DaveM
  */
-static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
+static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
+				      unsigned long address,
+				      unsigned long size,
+				      unsigned long offset, pgprot_t prot,
+				      int space)
 {
 	unsigned long end;
 
+	/* clear hack bit that was used as a write_combine side-effect flag */
+	offset &= ~0x1UL;
 	address &= ~PMD_MASK;
 	end = address + size;
 	if (end > PMD_SIZE)
@@ -38,22 +39,22 @@ static inline void io_remap_pte_range(pt
 		pte_t entry;
 		unsigned long curend = address + PAGE_SIZE;
 		
-		entry = mk_pte_io((offset & ~(0x1UL)), prot, space);
+		entry = mk_pte_io(offset, prot, space);
 		if (!(address & 0xffff)) {
 			if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) {
-				entry = mk_pte_io((offset & ~(0x1UL)),
+				entry = mk_pte_io(offset,
 						  __pgprot(pgprot_val (prot) | _PAGE_SZ4MB),
 						  space);
 				curend = address + 0x400000;
 				offset += 0x400000;
 			} else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) {
-				entry = mk_pte_io((offset & ~(0x1UL)),
+				entry = mk_pte_io(offset,
 						  __pgprot(pgprot_val (prot) | _PAGE_SZ512K),
 						  space);
 				curend = address + 0x80000;
 				offset += 0x80000;
 			} else if (!(offset & 0xfffe) && end >= address + 0x10000) {
-				entry = mk_pte_io((offset & ~(0x1UL)),
+				entry = mk_pte_io(offset,
 						  __pgprot(pgprot_val (prot) | _PAGE_SZ64K),
 						  space);
 				curend = address + 0x10000;
@@ -63,18 +64,16 @@ static inline void io_remap_pte_range(pt
 		} else
 			offset += PAGE_SIZE;
 
-		if (offset & 0x1UL)
-			pte_val(entry) &= ~(_PAGE_E);
 		do {
 			BUG_ON(!pte_none(*pte));
-			set_pte(pte, entry);
+			set_pte_at(mm, address, pte, entry);
 			address += PAGE_SIZE;
 			pte++;
 		} while (address < curend);
 	} while (address < end);
 }
 
-static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
+static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
 	unsigned long offset, pgprot_t prot, int space)
 {
 	unsigned long end;
@@ -85,10 +84,10 @@ static inline int io_remap_pmd_range(pmd
 		end = PGDIR_SIZE;
 	offset -= address;
 	do {
-		pte_t * pte = pte_alloc_map(current->mm, pmd, address);
+		pte_t * pte = pte_alloc_map(mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		io_remap_pte_range(pte, address, end - address, address + offset, prot, space);
+		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
 		pte_unmap(pte);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
@@ -96,7 +95,7 @@ static inline int io_remap_pmd_range(pmd
 	return 0;
 }
 
-static inline int io_remap_pud_range(pud_t * pud, unsigned long address, unsigned long size,
+static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size,
 	unsigned long offset, pgprot_t prot, int space)
 {
 	unsigned long end;
@@ -107,10 +106,10 @@ static inline int io_remap_pud_range(pud
 		end = PUD_SIZE;
 	offset -= address;
 	do {
-		pmd_t *pmd = pmd_alloc(current->mm, pud, address);
+		pmd_t *pmd = pmd_alloc(mm, pud, address);
 		if (!pud)
 			return -ENOMEM;
-		io_remap_pmd_range(pmd, address, end - address, address + offset, prot, space);
+		io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space);
 		address = (address + PUD_SIZE) & PUD_MASK;
 		pud++;
 	} while (address < end);
@@ -132,11 +131,45 @@ int io_remap_page_range(struct vm_area_s
 
 	spin_lock(&mm->page_table_lock);
 	while (from < end) {
+		pud_t *pud = pud_alloc(mm, dir, from);
+		error = -ENOMEM;
+		if (!pud)
+			break;
+		error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
+		if (error)
+			break;
+		from = (from + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_range(vma, beg, end);
+	spin_unlock(&mm->page_table_lock);
+
+	return error;
+}
+
+int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+		unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+	int error = 0;
+	pgd_t * dir;
+	unsigned long beg = from;
+	unsigned long end = from + size;
+	struct mm_struct *mm = vma->vm_mm;
+	int space = GET_IOSPACE(pfn);
+	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+
+	prot = __pgprot(pg_iobits);
+	offset -= from;
+	dir = pgd_offset(mm, from);
+	flush_cache_range(vma, beg, end);
+
+	spin_lock(&mm->page_table_lock);
+	while (from < end) {
 		pud_t *pud = pud_alloc(current->mm, dir, from);
 		error = -ENOMEM;
 		if (!pud)
 			break;
-		error = io_remap_pud_range(pud, from, end - from, offset + from, prot, space);
+		error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
 		if (error)
 			break;
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
--- a/arch/sparc64/mm/hugetlbpage.c
+++ b/arch/sparc64/mm/hugetlbpage.c
@@ -20,6 +20,7 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
 
 static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
 {
@@ -62,12 +63,13 @@ static pte_t *huge_pte_offset(struct mm_
 #define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0)
 
 static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+			 unsigned long addr,
 			 struct page *page, pte_t * page_table, int write_access)
 {
 	unsigned long i;
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
 
 	if (write_access)
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -78,8 +80,9 @@ static void set_huge_pte(struct mm_struc
 	mk_pte_huge(entry);
 
 	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-		set_pte(page_table, entry);
+		set_pte_at(mm, addr, page_table, entry);
 		page_table++;
+		addr += PAGE_SIZE;
 
 		pte_val(entry) += PAGE_SIZE;
 	}
@@ -116,12 +119,12 @@ int copy_hugetlb_page_range(struct mm_st
 		ptepage = pte_page(entry);
 		get_page(ptepage);
 		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-			set_pte(dst_pte, entry);
+			set_pte_at(dst, addr, dst_pte, entry);
 			pte_val(entry) += PAGE_SIZE;
 			dst_pte++;
+			addr += PAGE_SIZE;
 		}
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
-		addr += HPAGE_SIZE;
+		add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
 	}
 	return 0;
 
@@ -207,20 +210,58 @@ void unmap_hugepage_range(struct vm_area
 		page = pte_page(*pte);
 		put_page(page);
 		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-			pte_clear(pte);
+			pte_clear(mm, address+(i*PAGE_SIZE), pte);
 			pte++;
 		}
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
+	add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
 	flush_tlb_range(vma, start, end);
 }
 
+static void context_reload(void *__data)
+{
+	struct mm_struct *mm = __data;
+
+	if (mm == current->mm)
+		load_secondary_context(mm);
+}
+
 int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
 	int ret = 0;
 
+	/* On UltraSPARC-III+ and later, configure the second half of
+	 * the Data-TLB for huge pages.
+	 */
+	if (tlb_type == cheetah_plus) {
+		unsigned long ctx;
+
+		spin_lock(&ctx_alloc_lock);
+		ctx = mm->context.sparc64_ctx_val;
+		ctx &= ~CTX_PGSZ_MASK;
+		ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT;
+		ctx |= CTX_PGSZ_HUGE << CTX_PGSZ1_SHIFT;
+
+		if (ctx != mm->context.sparc64_ctx_val) {
+			/* When changing the page size fields, we
+			 * must perform a context flush so that no
+			 * stale entries match.  This flush must
+			 * occur with the original context register
+			 * settings.
+			 */
+			do_flush_tlb_mm(mm);
+
+			/* Reload the context register of all processors
+			 * also executing in this address space.
+			 */
+			mm->context.sparc64_ctx_val = ctx;
+			on_each_cpu(context_reload, mm, 0, 0);
+		}
+		spin_unlock(&ctx_alloc_lock);
+	}
+
 	BUG_ON(vma->vm_start & ~HPAGE_MASK);
 	BUG_ON(vma->vm_end & ~HPAGE_MASK);
 
@@ -261,7 +302,7 @@ int hugetlb_prefault(struct address_spac
 				goto out;
 			}
 		}
-		set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
+		set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE);
 	}
 out:
 	spin_unlock(&mm->page_table_lock);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -61,7 +61,7 @@ static unsigned long bootmap_base;
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
 unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
-#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
+#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6))
 unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
 
 /* References to special section boundaries */
@@ -85,40 +85,14 @@ void check_pgt_cache(void)
 	preempt_disable();
 	if (pgtable_cache_size > PGT_CACHE_HIGH) {
 		do {
-#ifdef CONFIG_SMP
 			if (pgd_quicklist)
 				free_pgd_slow(get_pgd_fast());
-#endif
 			if (pte_quicklist[0])
 				free_pte_slow(pte_alloc_one_fast(NULL, 0));
 			if (pte_quicklist[1])
 				free_pte_slow(pte_alloc_one_fast(NULL, 1 << (PAGE_SHIFT + 10)));
 		} while (pgtable_cache_size > PGT_CACHE_LOW);
 	}
-#ifndef CONFIG_SMP
-        if (pgd_cache_size > PGT_CACHE_HIGH / 4) {
-		struct page *page, *page2;
-                for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
-                        if ((unsigned long)page->lru.prev == 3) {
-                                if (page2)
-                                        page2->lru.next = page->lru.next;
-                                else
-                                        pgd_quicklist = (void *) page->lru.next;
-                                pgd_cache_size -= 2;
-                                __free_page(page);
-                                if (page2)
-                                        page = (struct page *)page2->lru.next;
-                                else
-                                        page = (struct page *)pgd_quicklist;
-                                if (pgd_cache_size <= PGT_CACHE_LOW / 4)
-                                        break;
-                                continue;
-                        }
-                        page2 = page;
-                        page = (struct page *)page->lru.next;
-                }
-        }
-#endif
 	preempt_enable();
 }
 
@@ -135,7 +109,7 @@ __inline__ void flush_dcache_page_impl(s
 	atomic_inc(&dcpage_flushes);
 #endif
 
-#if (L1DCACHE_SIZE > PAGE_SIZE)
+#ifdef DCACHE_ALIASING_POSSIBLE
 	__flush_dcache_page(page_address(page),
 			    ((tlb_type == spitfire) &&
 			     page_mapping(page) != NULL));
@@ -158,15 +132,15 @@ static __inline__ void set_dcache_dirty(
 	mask = (mask << 24) | (1UL << PG_dcache_dirty);
 	__asm__ __volatile__("1:\n\t"
 			     "ldx	[%2], %%g7\n\t"
-			     "and	%%g7, %1, %%g5\n\t"
-			     "or	%%g5, %0, %%g5\n\t"
-			     "casx	[%2], %%g7, %%g5\n\t"
-			     "cmp	%%g7, %%g5\n\t"
+			     "and	%%g7, %1, %%g1\n\t"
+			     "or	%%g1, %0, %%g1\n\t"
+			     "casx	[%2], %%g7, %%g1\n\t"
+			     "cmp	%%g7, %%g1\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
 			     " membar	#StoreLoad | #StoreStore"
 			     : /* no outputs */
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
-			     : "g5", "g7");
+			     : "g1", "g7");
 }
 
 static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long cpu)
@@ -176,20 +150,20 @@ static __inline__ void clear_dcache_dirt
 	__asm__ __volatile__("! test_and_clear_dcache_dirty\n"
 			     "1:\n\t"
 			     "ldx	[%2], %%g7\n\t"
-			     "srlx	%%g7, 24, %%g5\n\t"
-			     "and	%%g5, %3, %%g5\n\t"
-			     "cmp	%%g5, %0\n\t"
+			     "srlx	%%g7, 24, %%g1\n\t"
+			     "and	%%g1, %3, %%g1\n\t"
+			     "cmp	%%g1, %0\n\t"
 			     "bne,pn	%%icc, 2f\n\t"
-			     " andn	%%g7, %1, %%g5\n\t"
-			     "casx	[%2], %%g7, %%g5\n\t"
-			     "cmp	%%g7, %%g5\n\t"
+			     " andn	%%g7, %1, %%g1\n\t"
+			     "casx	[%2], %%g7, %%g1\n\t"
+			     "cmp	%%g7, %%g1\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
 			     " membar	#StoreLoad | #StoreStore\n"
 			     "2:"
 			     : /* no outputs */
 			     : "r" (cpu), "r" (mask), "r" (&page->flags),
 			       "i" (NR_CPUS - 1UL)
-			     : "g5", "g7");
+			     : "g1", "g7");
 }
 
 extern void __update_mmu_cache(unsigned long mmu_context_hw, unsigned long address, pte_t pte, int code);
@@ -219,20 +193,32 @@ void update_mmu_cache(struct vm_area_str
 
 		put_cpu();
 	}
+
 	if (get_thread_fault_code())
-		__update_mmu_cache(vma->vm_mm->context & TAG_CONTEXT_BITS,
+		__update_mmu_cache(CTX_NRBITS(vma->vm_mm->context),
 				   address, pte, get_thread_fault_code());
 }
 
 void flush_dcache_page(struct page *page)
 {
-	struct address_space *mapping = page_mapping(page);
-	int dirty = test_bit(PG_dcache_dirty, &page->flags);
-	int dirty_cpu = dcache_dirty_cpu(page);
-	int this_cpu = get_cpu();
+	struct address_space *mapping;
+	int this_cpu;
+
+	/* Do not bother with the expensive D-cache flush if it
+	 * is merely the zero page.  The 'bigcore' testcase in GDB
+	 * causes this case to run millions of times.
+	 */
+	if (page == ZERO_PAGE(0))
+		return;
 
+	this_cpu = get_cpu();
+
+	mapping = page_mapping(page);
 	if (mapping && !mapping_mapped(mapping)) {
+		int dirty = test_bit(PG_dcache_dirty, &page->flags);
 		if (dirty) {
+			int dirty_cpu = dcache_dirty_cpu(page);
+
 			if (dirty_cpu == this_cpu)
 				goto out;
 			smp_flush_dcache_page_impl(page, dirty_cpu);
@@ -281,9 +267,6 @@ void show_mem(void)
 	printk("%ld pages of RAM\n", num_physpages);
 	printk("%d free pages\n", nr_free_pages());
 	printk("%d pages in page table cache\n",pgtable_cache_size);
-#ifndef CONFIG_SMP
-	printk("%d entries in page dir cache\n",pgd_cache_size);
-#endif	
 }
 
 void mmu_info(struct seq_file *m)
@@ -392,10 +375,10 @@ static void inherit_prom_mappings(void)
 	n = n / sizeof(*trans);
 
 	/*
-	 * The obp translations are saved based on 8k pagesize, since obp can use
-	 * a mixture of pagesizes. Misses to the 0xf0000000 - 0x100000000, ie obp 
-	 * range, are handled in entry.S and do not use the vpte scheme (see rant
-	 * in inherit_locked_prom_mappings()).
+	 * The obp translations are saved based on 8k pagesize, since obp can
+	 * use a mixture of pagesizes. Misses to the 0xf0000000 - 0x100000000,
+	 * ie obp range, are handled in entry.S and do not use the vpte scheme
+	 * (see rant in inherit_locked_prom_mappings()).
 	 */
 #define OBP_PMD_SIZE 2048
 	prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, bootmap_base);
@@ -431,7 +414,8 @@ static void inherit_prom_mappings(void)
 				if (tlb_type == spitfire)
 					val &= ~0x0003fe0000000000UL;
 
-				set_pte (ptep, __pte(val | _PAGE_MODIFIED));
+				set_pte_at(&init_mm, vaddr,
+					   ptep, __pte(val | _PAGE_MODIFIED));
 				trans[i].data += BASE_PAGE_SIZE;
 			}
 		}
@@ -448,11 +432,15 @@ static void inherit_prom_mappings(void)
 	prom_printf("Remapping the kernel... ");
 
 	/* Spitfire Errata #32 workaround */
+	/* NOTE: Using plain zero for the context value is
+	 *       correct here, we are not using the Linux trap
+	 *       tables yet so we should not use the special
+	 *       UltraSPARC-III+ page size encodings yet.
+	 */
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "flush	%%g6"
 			     : /* No outputs */
-			     : "r" (0),
-			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+			     : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
 	switch (tlb_type) {
 	default:
@@ -512,6 +500,11 @@ static void inherit_prom_mappings(void)
 	tte_vaddr = (unsigned long) KERNBASE;
 
 	/* Spitfire Errata #32 workaround */
+	/* NOTE: Using plain zero for the context value is
+	 *       correct here, we are not using the Linux trap
+	 *       tables yet so we should not use the special
+	 *       UltraSPARC-III+ page size encodings yet.
+	 */
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "flush	%%g6"
 			     : /* No outputs */
@@ -530,6 +523,11 @@ static void inherit_prom_mappings(void)
 
 
 	/* Spitfire Errata #32 workaround */
+	/* NOTE: Using plain zero for the context value is
+	 *       correct here, we are not using the Linux trap
+	 *       tables yet so we should not use the special
+	 *       UltraSPARC-III+ page size encodings yet.
+	 */
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "flush	%%g6"
 			     : /* No outputs */
@@ -616,6 +614,9 @@ static void __flush_nucleus_vptes(void)
 			unsigned long tag;
 
 			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no cheetah+
+			 *       page size encodings.
+			 */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
@@ -782,6 +783,9 @@ void inherit_locked_prom_mappings(int sa
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no cheetah+
+			 *       page size encodings.
+			 */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
@@ -793,6 +797,9 @@ void inherit_locked_prom_mappings(int sa
 				unsigned long tag;
 
 				/* Spitfire Errata #32 workaround */
+				/* NOTE: Always runs on spitfire, so no
+				 *       cheetah+ page size encodings.
+				 */
 				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 						     "flush	%%g6"
 						     : /* No outputs */
@@ -820,6 +827,9 @@ void inherit_locked_prom_mappings(int sa
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no
+			 *       cheetah+ page size encodings.
+			 */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
@@ -831,6 +841,9 @@ void inherit_locked_prom_mappings(int sa
 				unsigned long tag;
 
 				/* Spitfire Errata #32 workaround */
+				/* NOTE: Always runs on spitfire, so no
+				 *       cheetah+ page size encodings.
+				 */
 				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 						     "flush	%%g6"
 						     : /* No outputs */
@@ -946,6 +959,7 @@ void prom_reload_locked(void)
 	}
 }
 
+#ifdef DCACHE_ALIASING_POSSIBLE
 void __flush_dcache_range(unsigned long start, unsigned long end)
 {
 	unsigned long va;
@@ -969,6 +983,7 @@ void __flush_dcache_range(unsigned long 
 					       "i" (ASI_DCACHE_INVALIDATE));
 	}
 }
+#endif /* DCACHE_ALIASING_POSSIBLE */
 
 /* If not locked, zap it. */
 void __flush_tlb_all(void)
@@ -984,6 +999,9 @@ void __flush_tlb_all(void)
 	if (tlb_type == spitfire) {
 		for (i = 0; i < 64; i++) {
 			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no
+			 *       cheetah+ page size encodings.
+			 */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
@@ -999,6 +1017,9 @@ void __flush_tlb_all(void)
 			}
 
 			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no
+			 *       cheetah+ page size encodings.
+			 */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 					     "flush	%%g6"
 					     : /* No outputs */
@@ -1032,11 +1053,14 @@ void __flush_tlb_all(void)
 void get_new_mmu_context(struct mm_struct *mm)
 {
 	unsigned long ctx, new_ctx;
+	unsigned long orig_pgsz_bits;
 	
+
 	spin_lock(&ctx_alloc_lock);
-	ctx = CTX_HWBITS(tlb_context_cache + 1);
-	new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx);
-	if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) {
+	orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);
+	ctx = (tlb_context_cache + 1) & CTX_NR_MASK;
+	new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx);
+	if (new_ctx >= (1 << CTX_NR_BITS)) {
 		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
 		if (new_ctx >= ctx) {
 			int i;
@@ -1065,9 +1089,8 @@ void get_new_mmu_context(struct mm_struc
 	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
 out:
 	tlb_context_cache = new_ctx;
+	mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits;
 	spin_unlock(&ctx_alloc_lock);
-
-	mm->context = new_ctx;
 }
 
 #ifndef CONFIG_SMP
@@ -1086,12 +1109,12 @@ struct pgtable_cache_struct pgt_quicklis
  * using the later address range, accesses with the first address
  * range will see the newly initialized data rather than the garbage.
  */
-#if (L1DCACHE_SIZE > PAGE_SIZE)			/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 #define DC_ALIAS_SHIFT	1
 #else
 #define DC_ALIAS_SHIFT	0
 #endif
-pte_t *__pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
 	struct page *page;
 	unsigned long color;
@@ -1110,7 +1133,7 @@ pte_t *__pte_alloc_one_kernel(struct mm_
 		unsigned long paddr;
 		pte_t *pte;
 
-#if (L1DCACHE_SIZE > PAGE_SIZE)			/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 		set_page_count(page, 1);
 		ClearPageCompound(page);
 
@@ -1128,7 +1151,7 @@ pte_t *__pte_alloc_one_kernel(struct mm_
 			to_free = (unsigned long *) paddr;
 		}
 
-#if (L1DCACHE_SIZE > PAGE_SIZE)			/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 		/* Now free the other one up, adjust cache size. */
 		preempt_disable();
 		*to_free = (unsigned long) pte_quicklist[color ^ 0x1];
@@ -1512,7 +1535,6 @@ void __init paging_init(void)
 
 		free_area_init_node(0, &contig_page_data, zones_size,
 				    phys_base >> PAGE_SHIFT, zholes_size);
-		mem_map = contig_page_data.node_mem_map;
 	}
 
 	device_scan();
@@ -1702,22 +1724,6 @@ void __init mem_init(void)
 	initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin));
 	initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
 
-#ifndef CONFIG_SMP
-	{
-		/* Put empty_pg_dir on pgd_quicklist */
-		extern pgd_t empty_pg_dir[1024];
-		unsigned long addr = (unsigned long)empty_pg_dir;
-		unsigned long alias_base = kern_base + PAGE_OFFSET -
-			(long)(KERNBASE);
-		
-		memset(empty_pg_dir, 0, sizeof(empty_pg_dir));
-		addr += alias_base;
-		free_pgd_fast((pgd_t *)addr);
-		num_physpages++;
-		totalram_pages++;
-	}
-#endif
-
 	printk("Memory: %uk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n",
 	       nr_free_pages() << (PAGE_SHIFT-10),
 	       codepages << (PAGE_SHIFT-10),
diff --git a/arch/sparc64/mm/tlb.c b/arch/sparc64/mm/tlb.c
--- a/arch/sparc64/mm/tlb.c
+++ b/arch/sparc64/mm/tlb.c
@@ -26,39 +26,25 @@ void flush_tlb_pending(void)
 	struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
 
 	if (mp->tlb_nr) {
-		unsigned long context = mp->mm->context;
-
-		if (CTX_VALID(context)) {
+		if (CTX_VALID(mp->mm->context)) {
 #ifdef CONFIG_SMP
 			smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
 					      &mp->vaddrs[0]);
 #else
-			__flush_tlb_pending(CTX_HWBITS(context), mp->tlb_nr,
-					    &mp->vaddrs[0]);
+			__flush_tlb_pending(CTX_HWBITS(mp->mm->context),
+					    mp->tlb_nr, &mp->vaddrs[0]);
 #endif
 		}
 		mp->tlb_nr = 0;
 	}
 }
 
-void tlb_batch_add(pte_t *ptep, pte_t orig)
+void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig)
 {
 	struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
-	struct page *ptepage;
-	struct mm_struct *mm;
-	unsigned long vaddr, nr;
-
-	ptepage = virt_to_page(ptep);
-	mm = (struct mm_struct *) ptepage->mapping;
-
-	/* It is more efficient to let flush_tlb_kernel_range()
-	 * handle these cases.
-	 */
-	if (mm == &init_mm)
-		return;
+	unsigned long nr;
 
-	vaddr = ptepage->index +
-		(((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE);
+	vaddr &= PAGE_MASK;
 	if (pte_exec(orig))
 		vaddr |= 0x1UL;
 
@@ -85,6 +71,7 @@ void tlb_batch_add(pte_t *ptep, pte_t or
 	}
 
 no_cache_flush:
+
 	if (mp->tlb_frozen)
 		return;
 
@@ -113,11 +100,10 @@ void flush_tlb_pgtables(struct mm_struct
 	if (mp->tlb_frozen)
 		return;
 
-	/* Nobody should call us with start below VM hole and end above.
-	 * See if it is really true.
-	 */
-	BUG_ON(s > e);
+	/* If start is greater than end, that is a real problem.  */
+	BUG_ON(start > end);
 
+	/* However, straddling the VA space hole is quite normal. */
 	s &= PMD_MASK;
 	e = (e + PMD_SIZE - 1) & PMD_MASK;
 
@@ -135,6 +121,22 @@ void flush_tlb_pgtables(struct mm_struct
 
 	start = vpte_base + (s >> (PAGE_SHIFT - 3));
 	end = vpte_base + (e >> (PAGE_SHIFT - 3));
+
+	/* If the request straddles the VA space hole, we
+	 * need to swap start and end.  The reason this
+	 * occurs is that "vpte_base" is the center of
+	 * the linear page table mapping area.  Thus,
+	 * high addresses with the sign bit set map to
+	 * addresses below vpte_base and non-sign bit
+	 * addresses map to addresses above vpte_base.
+	 */
+	if (end < start) {
+		unsigned long tmp = start;
+
+		start = end;
+		end = tmp;
+	}
+
 	while (start < end) {
 		mp->vaddrs[nr] = start;
 		mp->tlb_nr = ++nr;
@@ -147,10 +149,3 @@ void flush_tlb_pgtables(struct mm_struct
 	if (nr)
 		flush_tlb_pending();
 }
-
-unsigned long __ptrs_per_pmd(void)
-{
-	if (test_thread_flag(TIF_32BIT))
-		return (1UL << (32 - (PAGE_SHIFT-3) - PAGE_SHIFT));
-	return REAL_PTRS_PER_PMD;
-}
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -13,6 +13,7 @@
 #include <asm/pil.h>
 #include <asm/head.h>
 #include <asm/thread_info.h>
+#include <asm/cacheflush.h>
 
 	/* Basically, most of the Spitfire vs. Cheetah madness
 	 * has to do with the fact that Cheetah does not support
@@ -49,9 +50,9 @@ __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEX
 	.globl		__flush_tlb_pending
 __flush_tlb_pending:
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
-	rdpr		%pstate, %g5
+	rdpr		%pstate, %g7
 	sllx		%o1, 3, %o1
-	andn		%g5, PSTATE_IE, %g2
+	andn		%g7, PSTATE_IE, %g2
 	wrpr		%g2, %pstate
 	mov		SECONDARY_CONTEXT, %o4
 	ldxa		[%o4] ASI_DMMU, %g2
@@ -70,7 +71,7 @@ __flush_tlb_pending:
 	stxa		%g2, [%o4] ASI_DMMU
 	flush		%g6
 	retl
-	 wrpr		%g5, 0x0, %pstate
+	 wrpr		%g7, 0x0, %pstate
 
 	.align		32
 	.globl		__flush_tlb_kernel_range
@@ -114,64 +115,27 @@ __spitfire_flush_tlb_mm_slow:
 	.align		32
 	.globl		__flush_icache_page
 __flush_icache_page:	/* %o0 = phys_page */
-	sethi		%hi(1 << 13), %o2	! IC_set bit
-	mov		1, %g1
-	srlx		%o0, 5, %o0
-	clr		%o1			! IC_addr
-	sllx		%g1, 36, %g1
-	ldda		[%o1] ASI_IC_TAG, %o4
-	sub		%g1, 1, %g2
-	or		%o0, %g1, %o0		! VALID+phys-addr comparitor
-
-	sllx		%g2, 1, %g2
-	andn		%g2, ITAG_MASK, %g2	! IC_tag mask
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-
-1:	addx		%g0, %g0, %g0
-	ldda		[%o1 + %o2] ASI_IC_TAG, %g4
-	addx		%g0, %g0, %g0
-	and		%o5, %g2, %g3
-	cmp		%g3, %o0
-	add		%o1, 0x20, %o1
-	ldda		[%o1] ASI_IC_TAG, %o4
-	be,pn		%xcc, iflush1
-
-2:	 nop
-	and		%g5, %g2, %g5
-	cmp		%g5, %o0
-	be,pn		%xcc, iflush2
-3:	 cmp		%o1, %o2
-	bne,pt		%xcc, 1b
-	 addx		%g0, %g0, %g0
-	nop
-
+	membar		#StoreStore
+	srlx		%o0, PAGE_SHIFT, %o0
+	sethi		%uhi(PAGE_OFFSET), %g1
+	sllx		%o0, PAGE_SHIFT, %o0
+	sethi		%hi(PAGE_SIZE), %g2
+	sllx		%g1, 32, %g1
+	add		%o0, %g1, %o0
+1:	subcc		%g2, 32, %g2
+	bne,pt		%icc, 1b
+	 flush		%o0 + %g2
 	retl
-	 ldx		[%g6 + TI_TASK], %g4
+	 nop
 
-iflush1:sub		%o1, 0x20, %g3
-	stxa		%g0, [%g3] ASI_IC_TAG
-	flush		%g6
-	ba,a,pt		%xcc, 2b
-iflush2:sub		%o1, 0x20, %g3
-	stxa		%g0, [%o1 + %o2] ASI_IC_TAG
-	flush		%g6
-	ba,a,pt		%xcc, 3b
+#ifdef DCACHE_ALIASING_POSSIBLE
 
-#if (PAGE_SHIFT == 13)
-#define DTAG_MASK 0x3
-#elif (PAGE_SHIFT == 16)
-#define DTAG_MASK 0x1f
-#elif (PAGE_SHIFT == 19)
-#define DTAG_MASK 0xff
-#elif (PAGE_SHIFT == 22)
-#define DTAG_MASK 0x3ff
+#if (PAGE_SHIFT != 13)
+#error only page shift of 13 is supported by dcache flush
 #endif
 
+#define DTAG_MASK 0x3
+
 	.align		64
 	.globl		__flush_dcache_page
 __flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
@@ -228,6 +192,7 @@ dflush4:stxa		%g0, [%o4] ASI_DCACHE_TAG
 	membar		#Sync
 	ba,pt		%xcc, 2b
 	 nop
+#endif /* DCACHE_ALIASING_POSSIBLE */
 
 	.align		32
 __prefill_dtlb:
@@ -258,10 +223,18 @@ __update_mmu_cache:	/* %o0=hw_context, %
 	 or		%o5, %o0, %o5
 	ba,a,pt		%xcc, __prefill_itlb
 
-	/* Cheetah specific versions, patched at boot time.  */
+	/* Cheetah specific versions, patched at boot time.
+	 *
+	 * This writes of the PRIMARY_CONTEXT register in this file are
+	 * safe even on Cheetah+ and later wrt. the page size fields.
+	 * The nucleus page size fields do not matter because we make
+	 * no data references, and these instructions execute out of a
+	 * locked I-TLB entry sitting in the fully assosciative I-TLB.
+	 * This sequence should also never trap.
+	 */
 __cheetah_flush_tlb_mm: /* 15 insns */
-	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
+	rdpr		%pstate, %g7
+	andn		%g7, PSTATE_IE, %g2
 	wrpr		%g2, 0x0, %pstate
 	wrpr		%g0, 1, %tl
 	mov		PRIMARY_CONTEXT, %o2
@@ -274,13 +247,13 @@ __cheetah_flush_tlb_mm: /* 15 insns */
 	flush		%g6
 	wrpr		%g0, 0, %tl
 	retl
-	 wrpr		%g5, 0x0, %pstate
+	 wrpr		%g7, 0x0, %pstate
 
 __cheetah_flush_tlb_pending:	/* 22 insns */
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
-	rdpr		%pstate, %g5
+	rdpr		%pstate, %g7
 	sllx		%o1, 3, %o1
-	andn		%g5, PSTATE_IE, %g2
+	andn		%g7, PSTATE_IE, %g2
 	wrpr		%g2, 0x0, %pstate
 	wrpr		%g0, 1, %tl
 	mov		PRIMARY_CONTEXT, %o4
@@ -299,8 +272,9 @@ __cheetah_flush_tlb_pending:	/* 22 insns
 	flush		%g6
 	wrpr		%g0, 0, %tl
 	retl
-	 wrpr		%g5, 0x0, %pstate
+	 wrpr		%g7, 0x0, %pstate
 
+#ifdef DCACHE_ALIASING_POSSIBLE
 flush_dcpage_cheetah: /* 11 insns */
 	sethi		%uhi(PAGE_OFFSET), %g1
 	sllx		%g1, 32, %g1
@@ -313,6 +287,7 @@ flush_dcpage_cheetah: /* 11 insns */
 	 nop
 	retl		/* I-cache flush never needed on Cheetah, see callers. */
 	 nop
+#endif /* DCACHE_ALIASING_POSSIBLE */
 
 cheetah_patch_one:
 1:	lduw		[%o1], %g1
@@ -343,12 +318,14 @@ cheetah_patch_cachetlbops:
 	call		cheetah_patch_one
 	 mov		22, %o2
 
+#ifdef DCACHE_ALIASING_POSSIBLE
 	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		11, %o2
+#endif /* DCACHE_ALIASING_POSSIBLE */
 
 	ret
 	 restore
@@ -464,6 +441,7 @@ xcall_report_regs:
 	b		rtrap_xcall
 	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 
+#ifdef DCACHE_ALIASING_POSSIBLE
 	.align		32
 	.globl		xcall_flush_dcache_page_cheetah
 xcall_flush_dcache_page_cheetah: /* %g1 == physical page address */
@@ -475,12 +453,13 @@ xcall_flush_dcache_page_cheetah: /* %g1 
 	 nop
 	retry
 	nop
+#endif /* DCACHE_ALIASING_POSSIBLE */
 
 	.globl		xcall_flush_dcache_page_spitfire
 xcall_flush_dcache_page_spitfire: /* %g1 == physical page address
 				     %g7 == kernel page virtual address
 				     %g5 == (page->mapping != NULL)  */
-#if (L1DCACHE_SIZE > PAGE_SIZE)
+#ifdef DCACHE_ALIASING_POSSIBLE
 	srlx		%g1, (13 - 2), %g1	! Form tag comparitor
 	sethi		%hi(L1DCACHE_SIZE), %g3	! D$ size == 16K
 	sub		%g3, (1 << 5), %g3	! D$ linesize == 32
@@ -499,7 +478,7 @@ xcall_flush_dcache_page_spitfire: /* %g1
 	 sub		%g3, (1 << 5), %g3
 
 	brz,pn		%g5, 2f
-#endif /* L1DCACHE_SIZE > PAGE_SIZE */
+#endif /* DCACHE_ALIASING_POSSIBLE */
 	 sethi		%hi(PAGE_SIZE), %g3
 
 1:	flush		%g7
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S
--- a/arch/sparc64/prom/map.S
+++ b/arch/sparc64/prom/map.S
@@ -32,6 +32,7 @@ prom_remap:	/* %o0 = physpage, %o1 = vir
 	ldx	[%g2 + 0x08], %l0		! prom_cif_handler
 	mov	%g6, %i3
 	mov	%g4, %i4
+	mov	%g5, %i5
 	flushw
 
 	sethi	%hi(prom_remap - call_method), %g7
@@ -62,6 +63,7 @@ prom_remap:	/* %o0 = physpage, %o1 = vir
 	/* Restore hard-coded globals. */
 	mov	%i3, %g6
 	mov	%i4, %g4
+	mov	%i5, %g5
 
 	/* Wheee.... we are done. */
 	ret
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -30,6 +30,16 @@ extern void prom_world(int);
 extern void prom_cif_interface(void);
 extern void prom_cif_callback(void);
 
+static inline unsigned long spitfire_get_primary_context(void)
+{
+	unsigned long ctx;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (ctx)
+			     : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+	return ctx;
+}
+
 /*
  * This provides SMP safety on the p1275buf. prom_callback() drops this lock
  * to allow recursuve acquisition.
@@ -43,14 +53,9 @@ long p1275_cmd (char *service, long fmt,
 	int nargs, nrets, i;
 	va_list list;
 	long attrs, x;
-	long ctx = 0;
 	
 	p = p1275buf.prom_buffer;
-	ctx = spitfire_get_primary_context ();
-	if (ctx) {
-		flushw_user ();
-		spitfire_set_primary_context (0);
-	}
+	BUG_ON((spitfire_get_primary_context() & CTX_NR_MASK) != 0);
 
 	spin_lock_irqsave(&prom_entry_lock, flags);
 
@@ -146,9 +151,6 @@ long p1275_cmd (char *service, long fmt,
 
 	spin_unlock_irqrestore(&prom_entry_lock, flags);
 
-	if (ctx)
-		spitfire_set_primary_context (ctx);
-
 	return x;
 }
 
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -3,7 +3,7 @@ config GENERIC_HARDIRQS
 	bool
 	default y
 
-config USERMODE
+config UML
 	bool
 	default y
 
@@ -244,7 +244,7 @@ config KERNEL_HALF_GIGS
 
 config HIGHMEM
 	bool "Highmem support"
-	depends on BROKEN
+	depends on !64BIT
 
 config KERNEL_STACK_ORDER
 	int "Kernel stack size order"
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -2,13 +2,9 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config FRAME_POINTER
-	bool
-	default y if DEBUG_INFO
-
 config PT_PROXY
 	bool "Enable ptrace proxy"
-	depends on XTERM_CHAN && DEBUG_INFO
+	depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
 	help
 	This option enables a debugging interface which allows gdb to debug
 	the kernel without needing to actually attach to kernel threads.
@@ -16,7 +12,7 @@ config PT_PROXY
 
 config GPROF
 	bool "Enable gprof support"
-	depends on DEBUG_INFO
+	depends on DEBUG_INFO && MODE_SKAS && !MODE_TT
 	help
         This allows profiling of a User-Mode Linux kernel with the gprof
         utility.
@@ -29,7 +25,7 @@ config GPROF
 
 config GCOV
 	bool "Enable gcov support"
-	depends on DEBUG_INFO
+	depends on DEBUG_INFO && MODE_SKAS
 	help
         This option allows developers to retrieve coverage data from a UML
         session.
@@ -40,4 +36,14 @@ config GCOV
         If you're involved in UML kernel development and want to use gcov,
         say Y.  If you're unsure, say N.
 
+config SYSCALL_DEBUG
+	bool "Enable system call debugging"
+	default N
+	depends on DEBUG_INFO
+	help
+	This adds some system debugging to UML, including keeping a ring buffer
+	with recent system calls and some global and per-task statistics.
+
+	If unsure, say N
+
 endmenu
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char
--- a/arch/um/Kconfig_char
+++ b/arch/um/Kconfig_char
@@ -190,5 +190,25 @@ config HOSTAUDIO
 	tristate
 	default UML_SOUND
 
+config UML_RANDOM
+	tristate "Hardware random number generator"
+	help
+	This option enables UML's "hardware" random number generator.  It
+	attaches itself to the host's /dev/random, supplying as much entropy
+	as the host has, rather than the small amount the UML gets from its
+	own drivers.  It registers itself as a standard hardware random number
+	generator, major 10, minor 183, and the canonical device name is
+	/dev/hwrng.
+	The way to make use of this is to install the rng-tools package
+	(check your distro, or download from
+	http://sourceforge.net/projects/gkernel/).  rngd periodically reads
+	/dev/hwrng and injects the entropy into /dev/random.
+
+config MMAPPER
+	tristate "iomem emulation driver"
+	help
+	This driver allows a host file to be used as emulated IO memory inside
+	UML.
+
 endmenu
 
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -1,4 +1,8 @@
-config 64_BIT
+config UML_X86
+	bool
+	default y
+
+config 64BIT
 	bool
 	default n
 
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -1,7 +1,15 @@
-config 64_BIT
+config UML_X86
 	bool
 	default y
 
+config 64BIT
+	bool
+	default y
+
+config TOP_ADDR
+ 	hex
+	default 0x80000000
+
 config 3_LEVEL_PGTABLES
        bool
        default y
diff --git a/arch/um/Makefile b/arch/um/Makefile
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -17,7 +17,7 @@ core-y			+= $(ARCH_DIR)/kernel/		\
 
 # Have to precede the include because the included Makefiles reference them.
 SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \
-	arch-signal.h module.h vm-flags.h
+	module.h vm-flags.h elf.h
 SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
 
 # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes
@@ -44,6 +44,11 @@ ifneq ($(MAKEFILES-INCL),)
 endif
 
 ARCH_INCLUDE	:= -I$(ARCH_DIR)/include
+ifneq ($(KBUILD_SRC),)
+ARCH_INCLUDE	+= -I$(ARCH_DIR)/include2
+ARCH_INCLUDE	+= -I$(srctree)/$(ARCH_DIR)/include
+MRPROPER_DIRS	+= $(ARCH_DIR)/include2
+endif
 SYS_DIR		:= $(ARCH_DIR)/include/sysdep-$(SUBARCH)
 
 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
@@ -94,17 +99,18 @@ define archhelp
   echo '		   find in the kernel root.'
 endef
 
+ifneq ($(KBUILD_SRC),)
+$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig_$(SUBARCH) $(ARCH_DIR)/Kconfig_arch)
+CLEAN_FILES += $(ARCH_DIR)/Kconfig_arch
+else
 $(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch)
+endif
 
-prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \
-	$(ARCH_DIR)/kernel/vmlinux.lds.S
+prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
 LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
 
-LD_SCRIPT-$(CONFIG_LD_SCRIPT_STATIC) := uml.lds.S
-LD_SCRIPT-$(CONFIG_LD_SCRIPT_DYN) := dyn.lds.S
-
 CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT
 CONFIG_KERNEL_STACK_ORDER ?= 2
 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
@@ -126,7 +132,7 @@ define cmd_vmlinux__
 	$(CC) $(CFLAGS_vmlinux) -o $@ \
 	-Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
 	-Wl,--start-group $(vmlinux-main) -Wl,--end-group \
-	-L/usr/lib -lutil \
+	-lutil \
 	$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \
 	FORCE ,$^) ; rm -f linux
 endef
@@ -145,31 +151,42 @@ archclean:
 	@find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
 		-o -name '*.gcov' \) -type f -print | xargs rm -f
 
-#We need to re-preprocess this when the symlink dest changes.
-#So we touch it when needed.
-$(ARCH_DIR)/kernel/vmlinux.lds.S: FORCE
-	$(Q)if [ "$(shell readlink $@)" != "$(LD_SCRIPT-y)" ]; then \
-		echo '  SYMLINK $@'; \
-		ln -sf $(LD_SCRIPT-y) $@; \
-		touch $@; \
-	fi;
-
 $(SYMLINK_HEADERS):
 	@echo '  SYMLINK $@'
+ifneq ($(KBUILD_SRC),)
+	ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@
+else
 	$(Q)cd $(TOPDIR)/$(dir $@) ; \
 	ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
+endif
 
 include/asm-um/arch:
 	@echo '  SYMLINK $@'
+ifneq ($(KBUILD_SRC),)
+	$(Q)mkdir -p include/asm-um
+	$(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch
+else
 	$(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
+endif
 
 $(ARCH_DIR)/include/sysdep:
 	@echo '  SYMLINK $@'
+ifneq ($(KBUILD_SRC),)
+	$(Q)mkdir -p $(ARCH_DIR)/include
+	$(Q)mkdir -p $(ARCH_DIR)/include2
+	$(Q)ln -fsn sysdep-$(SUBARCH) $(ARCH_DIR)/include/sysdep
+	$(Q)ln -fsn $(srctree)/$(ARCH_DIR)/include/sysdep-$(SUBARCH) $(ARCH_DIR)/include2/sysdep
+else
 	$(Q)cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep
+endif
 
 $(ARCH_DIR)/os:
 	@echo '  SYMLINK $@'
+ifneq ($(KBUILD_SRC),)
+	$(Q)ln -fsn $(srctree)/$(ARCH_DIR)/os-$(OS) $(ARCH_DIR)/os
+else
 	$(Q)cd $(ARCH_DIR) && ln -sf os-$(OS) os
+endif
 
 # Generated files
 define filechk_umlconfig
@@ -179,24 +196,53 @@ endef
 $(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h
 	$(call filechk,umlconfig)
 
+$(ARCH_DIR)/user-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.c
+	$(CC) $(USER_CFLAGS) -S -o $@ $<
+
+$(ARCH_DIR)/user-offsets.h: $(ARCH_DIR)/user-offsets.s
+	$(call filechk,gen-asm-offsets)
+
+CLEAN_FILES += $(ARCH_DIR)/user-offsets.s  $(ARCH_DIR)/user-offsets.h
+
+$(ARCH_DIR)/kernel-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/kernel-offsets.c \
+				   $(ARCH_SYMLINKS) \
+				   $(SYS_DIR)/sc.h \
+				   include/asm include/linux/version.h \
+				   include/config/MARKER \
+				   $(ARCH_DIR)/include/user_constants.h
+	$(CC) $(CFLAGS) $(NOSTDINC_FLAGS) $(CPPFLAGS) -S -o $@ $<
+
+$(ARCH_DIR)/kernel-offsets.h: $(ARCH_DIR)/kernel-offsets.s
+	$(call filechk,gen-asm-offsets)
+
+CLEAN_FILES += $(ARCH_DIR)/kernel-offsets.s  $(ARCH_DIR)/kernel-offsets.h
+
 $(ARCH_DIR)/include/task.h: $(ARCH_DIR)/util/mk_task
 	$(call filechk,gen_header)
 
+$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/os-$(OS)/util/mk_user_constants
+	$(call filechk,gen_header)
+
 $(ARCH_DIR)/include/kern_constants.h: $(ARCH_DIR)/util/mk_constants
 	$(call filechk,gen_header)
 
 $(ARCH_DIR)/include/skas_ptregs.h: $(ARCH_DIR)/kernel/skas/util/mk_ptregs
 	$(call filechk,gen_header)
 
-$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants: $(ARCH_DIR)/util \
+$(ARCH_DIR)/os-$(OS)/util/mk_user_constants: $(ARCH_DIR)/os-$(OS)/util FORCE ;
+
+$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants: $(ARCH_DIR)/include/user_constants.h $(ARCH_DIR)/util \
 	FORCE ;
 
 $(ARCH_DIR)/kernel/skas/util/mk_ptregs: $(ARCH_DIR)/kernel/skas/util FORCE ;
 
-$(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h FORCE
+$(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h $(ARCH_DIR)/kernel-offsets.h FORCE
+	$(Q)$(MAKE) $(build)=$@
+
+$(ARCH_DIR)/kernel/skas/util: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
 	$(Q)$(MAKE) $(build)=$@
 
-$(ARCH_DIR)/kernel/skas/util: scripts_basic FORCE
+$(ARCH_DIR)/os-$(OS)/util: scripts_basic FORCE
 	$(Q)$(MAKE) $(build)=$@
 
 export SUBARCH USER_CFLAGS OS
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -1,4 +1,4 @@
-SUBARCH_CORE := arch/um/sys-i386/
+SUBARCH_CORE := arch/um/sys-i386/ arch/i386/crypto/
 
 TOP_ADDR := $(CONFIG_TOP_ADDR)
 
@@ -32,10 +32,10 @@ $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
 $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread 
 	$(call filechk,gen_header)
 
-$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE
+$(SYS_UTIL_DIR)/mk_sc: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
 	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
 
-$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE
+$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_DIR)/kernel-offsets.h FORCE
 	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
 
 $(SYS_UTIL_DIR): scripts_basic include/asm FORCE
diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas
--- a/arch/um/Makefile-skas
+++ b/arch/um/Makefile-skas
@@ -3,10 +3,12 @@
 # Licensed under the GPL
 #
 
-PROFILE += -pg
+GPROF_OPT += -pg
+GCOV_OPT += -fprofile-arcs -ftest-coverage
 
-CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
-CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
-LINK-$(CONFIG_GPROF) += $(PROFILE)
+CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT)
+CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
+LINK-$(CONFIG_GCOV) += $(GCOV_OPT)
+LINK-$(CONFIG_GPROF) += $(GPROF_OPT)
 
 GEN_HEADERS += $(ARCH_DIR)/include/skas_ptregs.h
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -23,14 +23,10 @@ $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
 $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
 	$(call filechk,gen_header)
 
-$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE
+$(SYS_UTIL_DIR)/mk_sc: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
 	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
 
-$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE
+$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(GEN_HEADERS) $(ARCH_DIR)/kernel-offsets.h FORCE
 	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
 
 CLEAN_FILES += $(SYS_HEADERS)
-
-LIBC_DIR := /usr/lib64
-
-export LIBC_DIR
diff --git a/arch/um/defconfig b/arch/um/defconfig
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,13 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2-mm4
-# Wed Dec  1 13:45:40 2004
+# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
+# Sun Apr 24 19:46:10 2005
 #
 CONFIG_GENERIC_HARDIRQS=y
-CONFIG_USERMODE=y
+CONFIG_UML=y
 CONFIG_MMU=y
-# CONFIG_64_BIT is not set
-CONFIG_TOP_ADDR=0xc0000000
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -17,12 +15,19 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 #
 CONFIG_MODE_TT=y
 CONFIG_MODE_SKAS=y
+CONFIG_UML_X86=y
+# CONFIG_64BIT is not set
+CONFIG_TOP_ADDR=0xc0000000
 # CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_ARCH_HAS_SC_SIGNALS=y
+CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
+CONFIG_LD_SCRIPT_STATIC=y
 CONFIG_NET=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 CONFIG_HOSTFS=y
 CONFIG_MCONSOLE=y
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_HOST_2G_2G is not set
 # CONFIG_SMP is not set
 CONFIG_NEST_LEVEL=0
@@ -37,6 +42,7 @@ CONFIG_UML_REAL_TIME_CLOCK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -49,7 +55,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
@@ -58,15 +63,16 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -75,7 +81,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
@@ -84,6 +89,7 @@ CONFIG_KMOD=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -97,7 +103,7 @@ CONFIG_PORT_CHAN=y
 CONFIG_PTY_CHAN=y
 CONFIG_TTY_CHAN=y
 CONFIG_XTERM_CHAN=y
-CONFIG_NOCONFIG_CHAN=y
+# CONFIG_NOCONFIG_CHAN is not set
 CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
 CONFIG_CON_CHAN="xterm"
 CONFIG_SSL_CHAN="pty"
@@ -108,17 +114,21 @@ CONFIG_LEGACY_PTY_COUNT=256
 CONFIG_UML_SOUND=m
 CONFIG_SOUND=m
 CONFIG_HOSTAUDIO=m
+CONFIG_UML_RANDOM=y
 
 #
-# Block Devices
+# Block devices
 #
 CONFIG_BLK_DEV_UBD=y
 CONFIG_BLK_DEV_UBD_SYNC=y
 CONFIG_BLK_DEV_COW_COMMON=y
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -127,6 +137,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 CONFIG_NETDEVICES=y
 
 #
@@ -149,7 +160,6 @@ CONFIG_UML_NET_SLIRP=y
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -196,10 +206,7 @@ CONFIG_IP_TCPDIAG=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-# CONFIG_KGDBOE is not set
 # CONFIG_NETPOLL is not set
-# CONFIG_NETPOLL_RX is not set
-# CONFIG_NETPOLL_TRAP is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
@@ -210,28 +217,6 @@ CONFIG_DUMMY=m
 CONFIG_TUN=m
 
 #
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
 # Wan interfaces
 #
 # CONFIG_WAN is not set
@@ -259,12 +244,15 @@ CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
-# CONFIG_REISER4_FS is not set
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_REISERFS_FS_XATTR is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -277,11 +265,6 @@ CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 
 #
-# Caches
-#
-# CONFIG_FSCACHE is not set
-
-#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -331,7 +314,6 @@ CONFIG_RAMFS=y
 #
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -400,10 +382,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=m
 # CONFIG_LIBCRC32C is not set
 
 #
@@ -415,15 +401,17 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_PT_PROXY=y
-# CONFIG_GPROF is not set
 # CONFIG_GCOV is not set
+# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -3,8 +3,6 @@
 # Licensed under the GPL
 #
 
-CHAN_OBJS := chan_kern.o chan_user.o line.o 
-
 # pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
 # in to pcap.o
 
@@ -20,12 +18,12 @@ ubd-objs := ubd_kern.o ubd_user.o
 port-objs := port_kern.o port_user.o
 harddog-objs := harddog_kern.o harddog_user.o
 
-obj-y := stdio_console.o fd.o $(CHAN_OBJS)
+obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
 obj-$(CONFIG_SSL) += ssl.o
 obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
 
-obj-$(CONFIG_UML_NET_SLIP) += slip.o
-obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
+obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
+obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
 obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
 obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
 #obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
@@ -41,13 +39,8 @@ obj-$(CONFIG_TTY_CHAN) += tty.o 
 obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
 obj-$(CONFIG_UML_WATCHDOG) += harddog.o
 obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
+obj-$(CONFIG_UML_RANDOM) += random.o
 
+USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o
 
-USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
-
-USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
-	null.o pty.o tty.o xterm.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -20,6 +20,14 @@
 #include "os.h"
 
 #ifdef CONFIG_NOCONFIG_CHAN
+
+/* The printk's here are wrong because we are complaining that there is no
+ * output device, but printk is printing to that output device.  The user will
+ * never see the error.  printf would be better, except it can't run on a
+ * kernel stack because it will overflow it.
+ * Use printk for now since that will avoid crashing.
+ */
+
 static void *not_configged_init(char *str, int device, struct chan_opts *opts)
 {
 	printk(KERN_ERR "Using a channel type which is configured out of "
@@ -73,7 +81,7 @@ static int not_configged_window_size(int
 
 static void not_configged_free(void *data)
 {
-	printk(KERN_ERR "Using a channel type which is configured out of "
+	printf(KERN_ERR "Using a channel type which is configured out of "
 	       "UML\n");
 }
 
@@ -218,7 +226,6 @@ void enable_chan(struct list_head *chans
 
 void close_chan(struct list_head *chans)
 {
-	struct list_head *ele;
 	struct chan *chan;
 
 	/* Close in reverse order as open in case more than one of them
@@ -226,8 +233,7 @@ void close_chan(struct list_head *chans)
 	 * state.  Then, the first one opened will have the original state,
 	 * so it must be the last closed.
 	 */
-        for(ele = chans->prev; ele != chans; ele = ele->prev){
-                chan = list_entry(ele, struct chan, list);
+	list_for_each_entry_reverse(chan, chans, list) {
 		if(!chan->opened) continue;
 		if(chan->ops->close != NULL)
 			(*chan->ops->close)(chan->fd, chan->data);
@@ -250,11 +256,8 @@ int write_chan(struct list_head *chans, 
 		n = chan->ops->write(chan->fd, buf, len, chan->data);
 		if (chan->primary) {
 			ret = n;
-			if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
+			if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
 				reactivate_fd(chan->fd, write_irq);
-				if (ret == -EAGAIN)
-					ret = 0;
-			}
 		}
 	}
 	return(ret);
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -143,22 +143,22 @@ static int winch_tramp(int fd, struct tt
 {
 	struct winch_data data;
 	unsigned long stack;
-	int fds[2], pid, n, err;
+	int fds[2], n, err;
 	char c;
 
 	err = os_pipe(fds, 1, 1);
 	if(err < 0){
 		printk("winch_tramp : os_pipe failed, err = %d\n", -err);
-		return(err);
+		goto out;
 	}
 
 	data = ((struct winch_data) { .pty_fd 		= fd,
 				      .pipe_fd 		= fds[1],
 				      .close_me 	= fds[0] } );
-	pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
-	if(pid < 0){
+	err = run_helper_thread(winch_thread, &data, 0, &stack, 0);
+	if(err < 0){
 		printk("fork of winch_thread failed - errno = %d\n", errno);
-		return(pid);
+		goto out_close;
 	}
 
 	os_close_file(fds[1]);
@@ -168,14 +168,22 @@ static int winch_tramp(int fd, struct tt
 		printk("winch_tramp : failed to read synchronization byte\n");
 		printk("read failed, err = %d\n", -n);
 		printk("fd %d will not support SIGWINCH\n", fd);
-		*fd_out = -1;
+                err = -EINVAL;
+		goto out_close1;
 	}
-	return(pid);
+	return err ;
+
+ out_close:
+	os_close_file(fds[1]);
+ out_close1:
+	os_close_file(fds[0]);
+ out:
+	return err;
 }
 
 void register_winch(int fd, struct tty_struct *tty)
 {
-	int pid, thread, thread_fd;
+	int pid, thread, thread_fd = -1;
 	int count;
 	char c = 1;
 
@@ -186,7 +194,7 @@ void register_winch(int fd, struct tty_s
 	if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
 			     tty) && (pid == -1)){
 		thread = winch_tramp(fd, tty, &thread_fd);
-		if(fd != -1){
+		if(thread > 0){
 			register_winch_irq(thread_fd, fd, thread, tty);
 
 			count = os_write_file(thread_fd, &c, sizeof(c));
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
--- a/arch/um/drivers/cow_user.c
+++ b/arch/um/drivers/cow_user.c
@@ -1,6 +1,9 @@
 #include <stddef.h>
 #include <string.h>
 #include <errno.h>
+/* _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines
+ * that.
+ */
 #include <unistd.h>
 #include <byteswap.h>
 #include <sys/time.h>
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -19,7 +19,7 @@ struct fd_chan {
 	char str[sizeof("1234567890\0")];
 };
 
-void *fd_init(char *str, int device, struct chan_opts *opts)
+static void *fd_init(char *str, int device, struct chan_opts *opts)
 {
 	struct fd_chan *data;
 	char *end;
@@ -43,7 +43,7 @@ void *fd_init(char *str, int device, str
 	return(data);
 }
 
-int fd_open(int input, int output, int primary, void *d, char **dev_out)
+static int fd_open(int input, int output, int primary, void *d, char **dev_out)
 {
 	struct fd_chan *data = d;
 	int err;
@@ -62,7 +62,7 @@ int fd_open(int input, int output, int p
 	return(data->fd);
 }
 
-void fd_close(int fd, void *d)
+static void fd_close(int fd, void *d)
 {
 	struct fd_chan *data = d;
 	int err;
@@ -76,7 +76,7 @@ void fd_close(int fd, void *d)
 	}
 }
 
-int fd_console_write(int fd, const char *buf, int n, void *d)
+static int fd_console_write(int fd, const char *buf, int n, void *d)
 {
 	struct fd_chan *data = d;
 
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -39,19 +39,69 @@ static void line_timer_cb(void *arg)
 	line_interrupt(line->driver->read_irq, arg, NULL);
 }
 
-static int write_room(struct line *dev)
+/* Returns the free space inside the ring buffer of this line.
+ *
+ * Should be called while holding line->lock (this does not modify datas).
+ */
+static int write_room(struct line *line)
 {
 	int n;
 
-	if (dev->buffer == NULL)
-		return (LINE_BUFSIZE - 1);
+	if (line->buffer == NULL)
+		return LINE_BUFSIZE - 1;
+
+	/* This is for the case where the buffer is wrapped! */
+	n = line->head - line->tail;
 
-	n = dev->head - dev->tail;
 	if (n <= 0)
-		n = LINE_BUFSIZE + n;
-	return (n - 1);
+		n = LINE_BUFSIZE + n; /* The other case */
+	return n - 1;
+}
+
+int line_write_room(struct tty_struct *tty)
+{
+	struct line *line = tty->driver_data;
+	unsigned long flags;
+	int room;
+
+	if (tty->stopped)
+		return 0;
+
+	spin_lock_irqsave(&line->lock, flags);
+	room = write_room(line);
+	spin_unlock_irqrestore(&line->lock, flags);
+
+	/*XXX: Warning to remove */
+	if (0 == room)
+		printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
+		       __FUNCTION__,tty->name);
+	return room;
+}
+
+int line_chars_in_buffer(struct tty_struct *tty)
+{
+	struct line *line = tty->driver_data;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&line->lock, flags);
+
+	/*write_room subtracts 1 for the needed NULL, so we readd it.*/
+	ret = LINE_BUFSIZE - (write_room(line) + 1);
+	spin_unlock_irqrestore(&line->lock, flags);
+
+	return ret;
 }
 
+/*
+ * This copies the content of buf into the circular buffer associated with
+ * this line.
+ * The return value is the number of characters actually copied, i.e. the ones
+ * for which there was space: this function is not supposed to ever flush out
+ * the circular buffer.
+ *
+ * Must be called while holding line->lock!
+ */
 static int buffer_data(struct line *line, const char *buf, int len)
 {
 	int end, room;
@@ -70,48 +120,95 @@ static int buffer_data(struct line *line
 	len = (len > room) ? room : len;
 
 	end = line->buffer + LINE_BUFSIZE - line->tail;
-	if(len < end){
+
+	if (len < end){
 		memcpy(line->tail, buf, len);
 		line->tail += len;
-	}
-	else {
+	} else {
+		/* The circular buffer is wrapping */
 		memcpy(line->tail, buf, end);
 		buf += end;
 		memcpy(line->buffer, buf, len - end);
 		line->tail = line->buffer + len - end;
 	}
 
-	return(len);
+	return len;
 }
 
+/*
+ * Flushes the ring buffer to the output channels. That is, write_chan is
+ * called, passing it line->head as buffer, and an appropriate count.
+ *
+ * On exit, returns 1 when the buffer is empty,
+ * 0 when the buffer is not empty on exit,
+ * and -errno when an error occurred.
+ *
+ * Must be called while holding line->lock!*/
 static int flush_buffer(struct line *line)
 {
 	int n, count;
 
 	if ((line->buffer == NULL) || (line->head == line->tail))
-		return(1);
+		return 1;
 
 	if (line->tail < line->head) {
+		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */
 		count = line->buffer + LINE_BUFSIZE - line->head;
+
 		n = write_chan(&line->chan_list, line->head, count,
 			       line->driver->write_irq);
 		if (n < 0)
-			return(n);
-		if (n == count)
+			return n;
+		if (n == count) {
+			/* We have flushed from ->head to buffer end, now we
+			 * must flush only from the beginning to ->tail.*/
 			line->head = line->buffer;
-		else {
+		} else {
 			line->head += n;
-			return(0);
+			return 0;
 		}
 	}
 
 	count = line->tail - line->head;
 	n = write_chan(&line->chan_list, line->head, count, 
 		       line->driver->write_irq);
-	if(n < 0) return(n);
+
+	if(n < 0)
+		return n;
 
 	line->head += n;
-	return(line->head == line->tail);
+	return line->head == line->tail;
+}
+
+void line_flush_buffer(struct tty_struct *tty)
+{
+	struct line *line = tty->driver_data;
+	unsigned long flags;
+	int err;
+
+	/*XXX: copied from line_write, verify if it is correct!*/
+	if(tty->stopped)
+		return;
+		//return 0;
+
+	spin_lock_irqsave(&line->lock, flags);
+	err = flush_buffer(line);
+	/*if (err == 1)
+		err = 0;*/
+	spin_unlock_irqrestore(&line->lock, flags);
+	//return err;
+}
+
+/* We map both ->flush_chars and ->put_char (which go in pair) onto ->flush_buffer
+ * and ->write. Hope it's not that bad.*/
+void line_flush_chars(struct tty_struct *tty)
+{
+	line_flush_buffer(tty);
+}
+
+void line_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	line_write(tty, &ch, sizeof(ch));
 }
 
 int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
@@ -120,38 +217,31 @@ int line_write(struct tty_struct *tty, c
 	unsigned long flags;
 	int n, err, ret = 0;
 
-	if(tty->stopped) return 0;
+	if(tty->stopped)
+		return 0;
 
-	down(&line->sem);
-	if(line->head != line->tail){
-		local_irq_save(flags);
+	spin_lock_irqsave(&line->lock, flags);
+	if (line->head != line->tail) {
 		ret = buffer_data(line, buf, len);
 		err = flush_buffer(line);
-		local_irq_restore(flags);
-		if(err <= 0)
+		if (err <= 0 && (err != -EAGAIN || !ret))
 			ret = err;
-	}
-	else {
+	} else {
 		n = write_chan(&line->chan_list, buf, len, 
 			       line->driver->write_irq);
-		if(n < 0){
+		if (n < 0) {
 			ret = n;
 			goto out_up;
 		}
 
 		len -= n;
 		ret += n;
-		if(len > 0)
+		if (len > 0)
 			ret += buffer_data(line, buf + n, len);
 	}
- out_up:
-	up(&line->sem);
-	return(ret);
-}
-
-void line_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	line_write(tty, &ch, sizeof(ch));
+out_up:
+	spin_unlock_irqrestore(&line->lock, flags);
+	return ret;
 }
 
 void line_set_termios(struct tty_struct *tty, struct termios * old)
@@ -159,11 +249,6 @@ void line_set_termios(struct tty_struct 
 	/* nothing */
 }
 
-int line_chars_in_buffer(struct tty_struct *tty)
-{
-	return 0;
-}
-
 static struct {
 	int  cmd;
 	char *level;
@@ -250,7 +335,7 @@ int line_ioctl(struct tty_struct *tty, s
 		ret = -ENOIOCTLCMD;
 		break;
 	}
-	return(ret);
+	return ret;
 }
 
 static irqreturn_t line_write_interrupt(int irq, void *data,
@@ -260,18 +345,23 @@ static irqreturn_t line_write_interrupt(
 	struct line *line = tty->driver_data;
 	int err;
 
+	/* Interrupts are enabled here because we registered the interrupt with
+	 * SA_INTERRUPT (see line_setup_irq).*/
+
+	spin_lock_irq(&line->lock);
 	err = flush_buffer(line);
-	if(err == 0)
-		return(IRQ_NONE);
-	else if(err < 0){
+	if (err == 0) {
+		return IRQ_NONE;
+	} else if(err < 0) {
 		line->head = line->buffer;
 		line->tail = line->buffer;
 	}
+	spin_unlock_irq(&line->lock);
 
 	if(tty == NULL)
-		return(IRQ_NONE);
+		return IRQ_NONE;
 
-	if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
 	   (tty->ldisc.write_wakeup != NULL))
 		(tty->ldisc.write_wakeup)(tty);
 	
@@ -281,9 +371,9 @@ static irqreturn_t line_write_interrupt(
 	 * writes.
 	 */
 
-	if(waitqueue_active(&tty->write_wait))
+	if (waitqueue_active(&tty->write_wait))
 		wake_up_interruptible(&tty->write_wait);
-	return(IRQ_HANDLED);
+	return IRQ_HANDLED;
 }
 
 int line_setup_irq(int fd, int input, int output, struct tty_struct *tty)
@@ -292,15 +382,18 @@ int line_setup_irq(int fd, int input, in
 	struct line_driver *driver = line->driver;
 	int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
 
-	if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, 
+	if (input)
+		err = um_request_irq(driver->read_irq, fd, IRQ_READ,
 				       line_interrupt, flags, 
 				       driver->read_irq_name, tty);
-	if(err) return(err);
-	if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, 
+	if (err)
+		return err;
+	if (output)
+		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
 					line_write_interrupt, flags, 
 					driver->write_irq_name, tty);
 	line->have_irq = 1;
-	return(err);
+	return err;
 }
 
 void line_disable(struct tty_struct *tty, int current_irq)
@@ -336,7 +429,9 @@ int line_open(struct line *lines, struct
 	line = &lines[tty->index];
 	tty->driver_data = line;
 
-	down(&line->sem);
+	/* The IRQ which takes this lock is not yet enabled and won't be run
+	 * before the end, so we don't need to use spin_lock_irq.*/
+	spin_lock(&line->lock);
 	if (tty->count == 1) {
 		if (!line->valid) {
 			err = -ENODEV;
@@ -349,6 +444,7 @@ int line_open(struct line *lines, struct
 			err = open_chan(&line->chan_list);
 			if(err) goto out;
 		}
+		/* Here the interrupt is registered.*/
 		enable_chan(&line->chan_list, tty);
 		INIT_WORK(&line->task, line_timer_cb, tty);
 	}
@@ -362,21 +458,36 @@ int line_open(struct line *lines, struct
 	line->count++;
 
 out:
-	up(&line->sem);
-	return(err);
+	spin_unlock(&line->lock);
+	return err;
 }
 
+static void unregister_winch(struct tty_struct *tty);
+
 void line_close(struct tty_struct *tty, struct file * filp)
 {
 	struct line *line = tty->driver_data;
 
-	down(&line->sem);
+	/* XXX: I assume this should be called in process context, not with
+         *  interrupts disabled!
+         */
+	spin_lock_irq(&line->lock);
+
+	/* We ignore the error anyway! */
+	flush_buffer(line);
+
 	line->count--;
 	if (tty->count == 1) {
 		line_disable(tty, -1);
 		tty->driver_data = NULL;
 	}
-	up(&line->sem);
+
+        if((line->count == 0) && line->sigio){
+                unregister_winch(tty);
+                line->sigio = 0;
+        }
+
+	spin_unlock_irq(&line->lock);
 }
 
 void close_lines(struct line *lines, int nlines)
@@ -387,31 +498,41 @@ void close_lines(struct line *lines, int
 		close_chan(&lines[i].chan_list);
 }
 
-int line_setup(struct line *lines, int num, char *init, int all_allowed)
+/* Common setup code for both startup command line and mconsole initialization.
+ * @lines contains the the array (of size @num) to modify;
+ * @init is the setup string;
+ * @all_allowed is a boolean saying if we can setup the whole @lines
+ * at once. For instance, it will be usually true for startup init. (where we
+ * can use con=xterm) and false for mconsole.*/
+
+int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed)
 {
 	int i, n;
 	char *end;
 
-	if(*init == '=') n = -1;
-	else {
+	if(*init == '=') {
+		/* We said con=/ssl= instead of con#=, so we are configuring all
+		 * consoles at once.*/
+		n = -1;
+	} else {
 		n = simple_strtoul(init, &end, 0);
 		if(*end != '='){
 			printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
 			       init);
-			return(0);
+			return 0;
 		}
 		init = end;
 	}
 	init++;
-	if((n >= 0) && (n >= num)){
+
+	if (n >= (signed int) num) {
 		printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
 		       n, num - 1);
-		return(0);
-	}
-	else if (n >= 0){
+		return 0;
+	} else if (n >= 0){
 		if (lines[n].count > 0) {
 			printk("line_setup - device %d is open\n", n);
-			return(0);
+			return 0;
 		}
 		if (lines[n].init_pri <= INIT_ONE){
 			lines[n].init_pri = INIT_ONE;
@@ -422,13 +543,11 @@ int line_setup(struct line *lines, int n
 				lines[n].valid = 1;
 			}	
 		}
-	}
-	else if(!all_allowed){
+	} else if(!all_allowed){
 		printk("line_setup - can't configure all devices from "
 		       "mconsole\n");
-		return(0);
-	}
-	else {
+		return 0;
+	} else {
 		for(i = 0; i < num; i++){
 			if(lines[i].init_pri <= INIT_ALL){
 				lines[i].init_pri = INIT_ALL;
@@ -440,21 +559,21 @@ int line_setup(struct line *lines, int n
 			}
 		}
 	}
-	return(1);
+	return 1;
 }
 
-int line_config(struct line *lines, int num, char *str)
+int line_config(struct line *lines, unsigned int num, char *str)
 {
 	char *new = uml_strdup(str);
 
 	if(new == NULL){
 		printk("line_config - uml_strdup failed\n");
-		return(-ENOMEM);
+		return -ENOMEM;
 	}
-	return(!line_setup(lines, num, new, 0));
+	return !line_setup(lines, num, new, 0);
 }
 
-int line_get_config(char *name, struct line *lines, int num, char *str, 
+int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
 		    int size, char **error_out)
 {
 	struct line *line;
@@ -464,47 +583,33 @@ int line_get_config(char *name, struct l
 	dev = simple_strtoul(name, &end, 0);
 	if((*end != '\0') || (end == name)){
 		*error_out = "line_get_config failed to parse device number";
-		return(0);
+		return 0;
 	}
 
 	if((dev < 0) || (dev >= num)){
-		*error_out = "device number of of range";
-		return(0);
+		*error_out = "device number out of range";
+		return 0;
 	}
 
 	line = &lines[dev];
 
-	down(&line->sem);
+	spin_lock(&line->lock);
 	if(!line->valid)
 		CONFIG_CHUNK(str, size, n, "none", 1);
 	else if(line->count == 0)
 		CONFIG_CHUNK(str, size, n, line->init_str, 1);
 	else n = chan_config_string(&line->chan_list, str, size, error_out);
-	up(&line->sem);
+	spin_unlock(&line->lock);
 
-	return(n);
+	return n;
 }
 
-int line_remove(struct line *lines, int num, char *str)
+int line_remove(struct line *lines, unsigned int num, char *str)
 {
 	char config[sizeof("conxxxx=none\0")];
 
 	sprintf(config, "%s=none", str);
-	return(!line_setup(lines, num, config, 0));
-}
-
-int line_write_room(struct tty_struct *tty)
-{
-	struct line *dev = tty->driver_data;
-	int room;
-
-	if (tty->stopped)
-		return 0;
-	room = write_room(dev);
-	if (0 == room)
-		printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
-		       __FUNCTION__,tty->name);
-	return room;
+	return !line_setup(lines, num, config, 0);
 }
 
 struct tty_driver *line_register_devfs(struct lines *set,
@@ -553,7 +658,7 @@ void lines_init(struct line *lines, int 
 	for(i = 0; i < nlines; i++){
 		line = &lines[i];
 		INIT_LIST_HEAD(&line->chan_list);
-		sema_init(&line->sem, 1);
+		spin_lock_init(&line->lock);
 		if(line->init_str != NULL){
 			line->init_str = uml_strdup(line->init_str);
 			if(line->init_str == NULL)
@@ -587,7 +692,7 @@ irqreturn_t winch_interrupt(int irq, voi
 				       "errno = %d\n", -err);
 				printk("fd %d is losing SIGWINCH support\n",
 				       winch->tty_fd);
-				return(IRQ_HANDLED);
+				return IRQ_HANDLED;
 			}
 			goto out;
 		}
@@ -603,7 +708,7 @@ irqreturn_t winch_interrupt(int irq, voi
  out:
 	if(winch->fd != -1)
 		reactivate_fd(winch->fd, WINCH_IRQ);
-	return(IRQ_HANDLED);
+	return IRQ_HANDLED;
 }
 
 DECLARE_MUTEX(winch_handler_sem);
@@ -625,7 +730,7 @@ void register_winch_irq(int fd, int tty_
 				   .pid  	= pid,
 				   .tty 	= tty });
 	list_add(&winch->list, &winch_handlers);
-	if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 
+	if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
 			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
 			  "winch", winch) < 0)
 		printk("register_winch_irq - failed to register IRQ\n");
@@ -633,6 +738,34 @@ void register_winch_irq(int fd, int tty_
 	up(&winch_handler_sem);
 }
 
+static void unregister_winch(struct tty_struct *tty)
+{
+	struct list_head *ele;
+	struct winch *winch, *found = NULL;
+
+	down(&winch_handler_sem);
+	list_for_each(ele, &winch_handlers){
+		winch = list_entry(ele, struct winch, list);
+                if(winch->tty == tty){
+                        found = winch;
+                        break;
+                }
+        }
+
+        if(found == NULL)
+                goto out;
+
+        if(winch->pid != -1)
+                os_kill_process(winch->pid, 1);
+
+        free_irq_by_irq_and_dev(WINCH_IRQ, winch);
+        free_irq(WINCH_IRQ, winch);
+        list_del(&winch->list);
+        kfree(winch);
+ out:
+	up(&winch_handler_sem);
+}
+
 static void winch_cleanup(void)
 {
 	struct list_head *ele;
@@ -656,26 +789,16 @@ char *add_xterm_umid(char *base)
 	int len;
 
 	umid = get_umid(1);
-	if(umid == NULL) return(base);
+	if(umid == NULL)
+		return base;
 	
 	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
 	title = kmalloc(len, GFP_KERNEL);
 	if(title == NULL){
 		printk("Failed to allocate buffer for xterm title\n");
-		return(base);
+		return base;
 	}
 
 	snprintf(title, len, "%s (%s)", base, umid);
-	return(title);
+	return title;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -73,7 +73,6 @@ int mcast_setup(char *str, char **mac_ou
 	struct mcast_init *init = data;
 	char *port_str = NULL, *ttl_str = NULL, *remain;
 	char *last;
-	int n;
 
 	*init = ((struct mcast_init)
 		{ .addr 	= "239.192.168.1",
@@ -89,13 +88,12 @@ int mcast_setup(char *str, char **mac_ou
 	}
 	
 	if(port_str != NULL){
-		n = simple_strtoul(port_str, &last, 10);
+		init->port = simple_strtoul(port_str, &last, 10);
 		if((*last != '\0') || (last == port_str)){
 			printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", 
 			       port_str);
 			return(0);
 		}
-		init->port = htons(n);
 	}
 
 	if(ttl_str != NULL){
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -38,7 +38,7 @@ static struct sockaddr_in *new_addr(char
 	}
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = in_aton(addr);
-	sin->sin_port = port;
+	sin->sin_port = htons(port);
 	return(sin);
 }
 
@@ -55,28 +55,25 @@ static int mcast_open(void *data)
 	struct mcast_data *pri = data;
 	struct sockaddr_in *sin = pri->mcast_addr;
 	struct ip_mreq mreq;
-	int fd, yes = 1;
+	int fd = -EINVAL, yes = 1, err = -EINVAL;;
 
 
-	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
-		fd = -EINVAL;
+	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
 		goto out;
-	}
 
 	fd = socket(AF_INET, SOCK_DGRAM, 0);
+
 	if (fd < 0){
 		printk("mcast_open : data socket failed, errno = %d\n", 
 		       errno);
-		fd = -ENOMEM;
+		fd = -errno;
 		goto out;
 	}
 
 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
 		printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
 			errno);
-		os_close_file(fd);
-		fd = -EINVAL;
-		goto out;
+		goto out_close;
 	}
 
 	/* set ttl according to config */
@@ -84,26 +81,20 @@ static int mcast_open(void *data)
 		       sizeof(pri->ttl)) < 0) {
 		printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
 			errno);
-		os_close_file(fd);
-		fd = -EINVAL;
-		goto out;
+		goto out_close;
 	}
 
 	/* set LOOP, so data does get fed back to local sockets */
 	if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
 		printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
 			errno);
-		os_close_file(fd);
-		fd = -EINVAL;
-		goto out;
+		goto out_close;
 	}
 
 	/* bind socket to mcast address */
 	if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
 		printk("mcast_open : data bind failed, errno = %d\n", errno);
-		os_close_file(fd);
-		fd = -EINVAL;
-		goto out;
+		goto out_close;
 	}		
 	
 	/* subscribe to the multicast group */
@@ -117,12 +108,15 @@ static int mcast_open(void *data)
 		       "interface on the host.\n");
 		printk("eth0 should be configured in order to use the "
 		       "multicast transport.\n");
-		os_close_file(fd);
-		fd = -EINVAL;
+                goto out_close;
 	}
 
  out:
-	return(fd);
+	return fd;
+
+ out_close:
+        os_close_file(fd);
+        return err;
 }
 
 static void mcast_close(int fd, void *data)
@@ -164,14 +158,3 @@ struct net_user_info mcast_user_info = {
 	.delete_address = NULL,
 	.max_packet	= MAX_PACKET - ETH_HEADER_OTHER
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/init.h> 
 #include <linux/smp_lock.h>
+#include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
@@ -117,24 +118,39 @@ static struct file_operations mmapper_fo
 	.release	= mmapper_release,
 };
 
+static struct miscdevice mmapper_dev = {
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= "mmapper",
+	.fops		= &mmapper_fops
+};
+
 static int __init mmapper_init(void)
 {
+	int err;
+
 	printk(KERN_INFO "Mapper v0.1\n");
 
 	v_buf = (char *) find_iomem("mmapper", &mmapper_size);
 	if(mmapper_size == 0){
 		printk(KERN_ERR "mmapper_init - find_iomem failed\n");
-		return(0);
+		goto out;
 	}
 
-	p_buf = __pa(v_buf);
+	err = misc_register(&mmapper_dev);
+	if(err){
+		printk(KERN_ERR "mmapper - misc_register failed, err = %d\n",
+		       err);
+		goto out;
+	}
 
-	devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUGO|S_IWUGO, "mmapper");
-	return(0);
+	p_buf = __pa(v_buf);
+out:
+	return 0;
 }
 
 static void mmapper_exit(void)
 {
+	misc_deregister(&mmapper_dev);
 }
 
 module_init(mmapper_init);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -383,7 +383,6 @@ static int eth_configure(int n, void *in
 	save = lp->user[0];
 	*lp = ((struct uml_net_private)
 		{ .list  		= LIST_HEAD_INIT(lp->list),
-		  .lock 		= SPIN_LOCK_UNLOCKED,
 		  .dev 			= dev,
 		  .fd 			= -1,
 		  .mac 			= { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
@@ -400,6 +399,7 @@ static int eth_configure(int n, void *in
 		  .user  		= { save } });
 
 	init_timer(&lp->tl);
+	spin_lock_init(&lp->lock);
 	lp->tl.function = uml_net_user_timer_expire;
 	if (lp->have_mac)
 		memcpy(lp->mac, device->mac, sizeof(lp->mac));
@@ -728,7 +728,8 @@ static void close_devices(void)
 
 	list_for_each(ele, &opened){
 		lp = list_entry(ele, struct uml_net_private, list);
-		if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
+		if((lp->close != NULL) && (lp->fd >= 0))
+			(*lp->close)(lp->fd, &lp->user);
 		if(lp->remove != NULL) (*lp->remove)(&lp->user);
 	}
 }
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -32,7 +32,7 @@ int tap_open_common(void *dev, char *gat
 	return(0);
 }
 
-void tap_check_ips(char *gate_addr, char *eth_addr)
+void tap_check_ips(char *gate_addr, unsigned char *eth_addr)
 {
 	int tap_addr[4];
 
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -10,23 +10,24 @@
 
 static int null_chan;
 
-void *null_init(char *str, int device, struct chan_opts *opts)
+static void *null_init(char *str, int device, struct chan_opts *opts)
 {
 	return(&null_chan);
 }
 
-int null_open(int input, int output, int primary, void *d, char **dev_out)
+static int null_open(int input, int output, int primary, void *d,
+		     char **dev_out)
 {
 	*dev_out = NULL;
 	return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
 }
 
-int null_read(int fd, char *c_out, void *unused)
+static int null_read(int fd, char *c_out, void *unused)
 {
 	return(-ENODEV);
 }
 
-void null_free(void *data)
+static void null_free(void *data)
 {
 }
 
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -10,6 +10,7 @@
 #include "linux/irq.h"
 #include "linux/spinlock.h"
 #include "linux/errno.h"
+#include "asm/atomic.h"
 #include "asm/semaphore.h"
 #include "asm/errno.h"
 #include "kern_util.h"
@@ -22,8 +23,9 @@
 
 struct port_list {
 	struct list_head list;
+	atomic_t wait_count;
 	int has_connection;
-	struct semaphore sem;
+	struct completion done;
 	int port;
 	int fd;
 	spinlock_t lock;
@@ -66,10 +68,17 @@ static irqreturn_t pipe_interrupt(int ir
 	conn->fd = fd;
 	list_add(&conn->list, &conn->port->connections);
 
-	up(&conn->port->sem);
+	complete(&conn->port->done);
 	return(IRQ_HANDLED);
 }
 
+#define NO_WAITER_MSG \
+    "****\n" \
+    "There are currently no UML consoles waiting for port connections.\n" \
+    "Either disconnect from one to make it available or activate some more\n" \
+    "by enabling more consoles in the UML /etc/inittab.\n" \
+    "****\n"
+
 static int port_accept(struct port_list *port)
 {
 	struct connection *conn;
@@ -104,6 +113,10 @@ static int port_accept(struct port_list 
 		goto out_free;
 	}
 
+	if(atomic_read(&port->wait_count) == 0){
+		os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG));
+		printk("No one waiting for port\n");
+	}
 	list_add(&conn->list, &port->pending);
 	return(1);
 
@@ -182,14 +195,14 @@ void *port_data(int port_num)
 
 	*port = ((struct port_list) 
 		{ .list 	 	= LIST_HEAD_INIT(port->list),
+		  .wait_count		= ATOMIC_INIT(0),
 		  .has_connection 	= 0,
-		  .sem 			= __SEMAPHORE_INITIALIZER(port->sem, 
-								  0),
-		  .lock 		= SPIN_LOCK_UNLOCKED,
 		  .port 	 	= port_num,
 		  .fd  			= fd,
 		  .pending 		= LIST_HEAD_INIT(port->pending),
 		  .connections 		= LIST_HEAD_INIT(port->connections) });
+	spin_lock_init(&port->lock);
+	init_completion(&port->done);
 	list_add(&port->list, &ports);
 
  found:
@@ -220,9 +233,11 @@ int port_wait(void *data)
 	struct port_list *port = dev->port;
 	int fd;
 
+        atomic_inc(&port->wait_count);
 	while(1){
-		if(down_interruptible(&port->sem))
-			return(-ERESTARTSYS);
+		fd = -ERESTARTSYS;
+                if(wait_for_completion_interruptible(&port->done))
+                        goto out;
 
 		spin_lock(&port->lock);
 
@@ -254,8 +269,9 @@ int port_wait(void *data)
 	dev->helper_pid = conn->helper_pid;
 	dev->telnetd_pid = conn->telnetd_pid;
 	kfree(conn);
-
-	return(fd);
+ out:
+	atomic_dec(&port->wait_count);
+	return fd;
 }
 
 void port_remove_dev(void *d)
@@ -291,14 +307,3 @@ static void free_port(void)
 }
 
 __uml_exitcall(free_port);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -28,7 +28,7 @@ struct port_chan {
 	char dev[sizeof("32768\0")];
 };
 
-void *port_init(char *str, int device, struct chan_opts *opts)
+static void *port_init(char *str, int device, struct chan_opts *opts)
 {
 	struct port_chan *data;
 	void *kern_data;
@@ -65,7 +65,7 @@ void *port_init(char *str, int device, s
 	return(NULL);
 }
 
-void port_free(void *d)
+static void port_free(void *d)
 {
 	struct port_chan *data = d;
 
@@ -73,7 +73,8 @@ void port_free(void *d)
 	kfree(data);
 }
 
-int port_open(int input, int output, int primary, void *d, char **dev_out)
+static int port_open(int input, int output, int primary, void *d,
+		     char **dev_out)
 {
 	struct port_chan *data = d;
 	int fd, err;
@@ -92,7 +93,7 @@ int port_open(int input, int output, int
 	return(fd);
 }
 
-void port_close(int fd, void *d)
+static void port_close(int fd, void *d)
 {
 	struct port_chan *data = d;
 
@@ -100,7 +101,7 @@ void port_close(int fd, void *d)
 	os_close_file(fd);
 }
 
-int port_console_write(int fd, const char *buf, int n, void *d)
+static int port_console_write(int fd, const char *buf, int n, void *d)
 {
 	struct port_chan *data = d;
 
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -22,7 +22,7 @@ struct pty_chan {
 	char dev_name[sizeof("/dev/pts/0123456\0")];
 };
 
-void *pty_chan_init(char *str, int device, struct chan_opts *opts)
+static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
 {
 	struct pty_chan *data;
 
@@ -34,7 +34,8 @@ void *pty_chan_init(char *str, int devic
 	return(data);
 }
 
-int pts_open(int input, int output, int primary, void *d, char **dev_out)
+static int pts_open(int input, int output, int primary, void *d,
+		    char **dev_out)
 {
 	struct pty_chan *data = d;
 	char *dev;
@@ -63,7 +64,7 @@ int pts_open(int input, int output, int 
 	return(fd);
 }
 
-int getmaster(char *line)
+static int getmaster(char *line)
 {
 	char *pty, *bank, *cp;
 	int master, err;
@@ -92,7 +93,8 @@ int getmaster(char *line)
 	return(-1);
 }
 
-int pty_open(int input, int output, int primary, void *d, char **dev_out)
+static int pty_open(int input, int output, int primary, void *d,
+		    char **dev_out)
 {
 	struct pty_chan *data = d;
 	int fd, err;
@@ -115,7 +117,7 @@ int pty_open(int input, int output, int 
 	return(fd);
 }
 
-int pty_console_write(int fd, const char *buf, int n, void *d)
+static int pty_console_write(int fd, const char *buf, int n, void *d)
 {
 	struct pty_chan *data = d;
 
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
new file mode 100644
--- /dev/null
+++ b/arch/um/drivers/random.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */
+/* Much of this ripped from drivers/char/hw_random.c, see there for other
+ * copyright.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include "os.h"
+
+/*
+ * core module and version information
+ */
+#define RNG_VERSION "1.0.0"
+#define RNG_MODULE_NAME "random"
+
+#define RNG_MISCDEV_MINOR		183 /* official */
+
+static int random_fd = -1;
+
+static int rng_dev_open (struct inode *inode, struct file *filp)
+{
+	/* enforce read-only access to this chrdev */
+	if ((filp->f_mode & FMODE_READ) == 0)
+		return -EINVAL;
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
+                             loff_t * offp)
+{
+        u32 data;
+        int n, ret = 0, have_data;
+
+        while(size){
+                n = os_read_file(random_fd, &data, sizeof(data));
+                if(n > 0){
+                        have_data = n;
+                        while (have_data && size) {
+                                if (put_user((u8)data, buf++)) {
+                                        ret = ret ? : -EFAULT;
+                                        break;
+                                }
+                                size--;
+                                ret++;
+                                have_data--;
+                                data>>=8;
+                        }
+                }
+                else if(n == -EAGAIN){
+                        if (filp->f_flags & O_NONBLOCK)
+                                return ret ? : -EAGAIN;
+
+                        if(need_resched()){
+                                current->state = TASK_INTERRUPTIBLE;
+                                schedule_timeout(1);
+                        }
+                }
+                else return n;
+		if (signal_pending (current))
+			return ret ? : -ERESTARTSYS;
+	}
+	return ret;
+}
+
+static struct file_operations rng_chrdev_ops = {
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.read		= rng_dev_read,
+};
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	RNG_MODULE_NAME,
+	&rng_chrdev_ops,
+};
+
+/*
+ * rng_init - initialize RNG module
+ */
+static int __init rng_init (void)
+{
+	int err;
+
+        err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
+        if(err < 0)
+                goto out;
+
+        random_fd = err;
+
+        err = os_set_fd_block(random_fd, 0);
+        if(err)
+		goto err_out_cleanup_hw;
+
+	err = misc_register (&rng_miscdev);
+	if (err) {
+		printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n");
+		goto err_out_cleanup_hw;
+	}
+
+ out:
+        return err;
+
+ err_out_cleanup_hw:
+        random_fd = -1;
+        goto out;
+}
+
+/*
+ * rng_cleanup - shutdown RNG module
+ */
+static void __exit rng_cleanup (void)
+{
+	misc_deregister (&rng_miscdev);
+}
+
+module_init (rng_init);
+module_exit (rng_cleanup);
+
+MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
--- a/arch/um/drivers/slip.h
+++ b/arch/um/drivers/slip.h
@@ -1,10 +1,7 @@
 #ifndef __UM_SLIP_H
 #define __UM_SLIP_H
 
-#define BUF_SIZE 1500
- /* two bytes each for a (pathological) max packet of escaped chars +  * 
-  * terminating END char + initial END char                            */
-#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+#include "slip_common.h"
 
 struct slip_data {
 	void *dev;
@@ -12,28 +9,12 @@ struct slip_data {
 	char *addr;
 	char *gate_addr;
 	int slave;
-	char ibuf[ENC_BUF_SIZE];
-	char obuf[ENC_BUF_SIZE];
-	int more; /* more data: do not read fd until ibuf has been drained */
-	int pos;
-	int esc;
+	struct slip_proto slip;
 };
 
 extern struct net_user_info slip_user_info;
 
-extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
 extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
 extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slip_common.c b/arch/um/drivers/slip_common.c
new file mode 100644
--- /dev/null
+++ b/arch/um/drivers/slip_common.c
@@ -0,0 +1,54 @@
+#include <string.h>
+#include "slip_common.h"
+#include "net_user.h"
+
+int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip)
+{
+	int i, n, size, start;
+
+	if(slip->more > 0){
+		i = 0;
+		while(i < slip->more){
+			size = slip_unesc(slip->ibuf[i++], slip->ibuf,
+					  &slip->pos, &slip->esc);
+			if(size){
+				memcpy(buf, slip->ibuf, size);
+				memmove(slip->ibuf, &slip->ibuf[i],
+					slip->more - i);
+				slip->more = slip->more - i;
+				return size;
+			}
+		}
+		slip->more = 0;
+	}
+
+	n = net_read(fd, &slip->ibuf[slip->pos],
+		     sizeof(slip->ibuf) - slip->pos);
+	if(n <= 0)
+		return n;
+
+	start = slip->pos;
+	for(i = 0; i < n; i++){
+		size = slip_unesc(slip->ibuf[start + i], slip->ibuf,&slip->pos,
+				  &slip->esc);
+		if(size){
+			memcpy(buf, slip->ibuf, size);
+			memmove(slip->ibuf, &slip->ibuf[start+i+1],
+				n - (i + 1));
+			slip->more = n - (i + 1);
+			return size;
+		}
+	}
+	return 0;
+}
+
+int slip_proto_write(int fd, void *buf, int len, struct slip_proto *slip)
+{
+	int actual, n;
+
+	actual = slip_esc(buf, slip->obuf, len);
+	n = net_write(fd, slip->obuf, actual);
+	if(n < 0)
+		return n;
+	else return len;
+}
diff --git a/arch/um/drivers/slip_common.h b/arch/um/drivers/slip_common.h
new file mode 100644
--- /dev/null
+++ b/arch/um/drivers/slip_common.h
@@ -0,0 +1,104 @@
+#ifndef __UM_SLIP_COMMON_H
+#define __UM_SLIP_COMMON_H
+
+#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars +  *
+  * terminating END char + initial END char                            */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+
+/* SLIP protocol characters. */
+#define SLIP_END             0300	/* indicates end of frame	*/
+#define SLIP_ESC             0333	/* indicates byte stuffing	*/
+#define SLIP_ESC_END         0334	/* ESC ESC_END means END 'data'	*/
+#define SLIP_ESC_ESC         0335	/* ESC ESC_ESC means ESC 'data'	*/
+
+static inline int slip_unesc(unsigned char c, unsigned char *buf, int *pos,
+                             int *esc)
+{
+	int ret;
+
+	switch(c){
+	case SLIP_END:
+		*esc = 0;
+		ret=*pos;
+		*pos=0;
+		return(ret);
+	case SLIP_ESC:
+		*esc = 1;
+		return(0);
+	case SLIP_ESC_ESC:
+		if(*esc){
+			*esc = 0;
+			c = SLIP_ESC;
+		}
+		break;
+	case SLIP_ESC_END:
+		if(*esc){
+			*esc = 0;
+			c = SLIP_END;
+		}
+		break;
+	}
+	buf[(*pos)++] = c;
+	return(0);
+}
+
+static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+	unsigned char *ptr = d;
+	unsigned char c;
+
+	/*
+	 * Send an initial END character to flush out any
+	 * data that may have accumulated in the receiver
+	 * due to line noise.
+	 */
+
+	*ptr++ = SLIP_END;
+
+	/*
+	 * For each byte in the packet, send the appropriate
+	 * character sequence, according to the SLIP protocol.
+	 */
+
+	while (len-- > 0) {
+		switch(c = *s++) {
+		case SLIP_END:
+			*ptr++ = SLIP_ESC;
+			*ptr++ = SLIP_ESC_END;
+			break;
+		case SLIP_ESC:
+			*ptr++ = SLIP_ESC;
+			*ptr++ = SLIP_ESC_ESC;
+			break;
+		default:
+			*ptr++ = c;
+			break;
+		}
+	}
+	*ptr++ = SLIP_END;
+	return (ptr - d);
+}
+
+struct slip_proto {
+	unsigned char ibuf[ENC_BUF_SIZE];
+	unsigned char obuf[ENC_BUF_SIZE];
+	int more; /* more data: do not read fd until ibuf has been drained */
+	int pos;
+	int esc;
+};
+
+#define SLIP_PROTO_INIT { \
+	.ibuf  	= { '\0' }, \
+	.obuf  	= { '\0' }, \
+        .more	= 0, \
+	.pos	= 0, \
+	.esc	= 0 \
+}
+
+extern int slip_proto_read(int fd, void *buf, int len,
+			   struct slip_proto *slip);
+extern int slip_proto_write(int fd, void *buf, int len,
+			    struct slip_proto *slip);
+
+#endif
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -26,16 +26,16 @@ void slip_init(struct net_device *dev, v
 		  .addr		= NULL,
 		  .gate_addr 	= init->gate_addr,
 		  .slave  	= -1,
-		  .ibuf  	= { '\0' },
-		  .obuf  	= { '\0' },
-		  .pos 		= 0,
-		  .esc 		= 0,
+		  .slip		= SLIP_PROTO_INIT,
 		  .dev 		= dev });
 
 	dev->init = NULL;
+	dev->header_cache_update = NULL;
+	dev->hard_header_cache = NULL;
+	dev->hard_header = NULL;
 	dev->hard_header_len = 0;
-	dev->addr_len = 4;
-	dev->type = ARPHRD_ETHER;
+	dev->addr_len = 0;
+	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = 256;
 	dev->flags = IFF_NOARP;
 	printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h
deleted file mode 100644
--- a/arch/um/drivers/slip_proto.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_SLIP_PROTO_H__
-#define __UM_SLIP_PROTO_H__
-
-/* SLIP protocol characters. */
-#define SLIP_END             0300	/* indicates end of frame	*/
-#define SLIP_ESC             0333	/* indicates byte stuffing	*/
-#define SLIP_ESC_END         0334	/* ESC ESC_END means END 'data'	*/
-#define SLIP_ESC_ESC         0335	/* ESC ESC_ESC means ESC 'data'	*/
-
-static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
-{
-	int ret;
-
-	switch(c){
-	case SLIP_END:
-		*esc = 0;
-		ret=*pos;
-		*pos=0;
-		return(ret);
-	case SLIP_ESC:
-		*esc = 1;
-		return(0);
-	case SLIP_ESC_ESC:
-		if(*esc){
-			*esc = 0;
-			c = SLIP_ESC;
-		}
-		break;
-	case SLIP_ESC_END:
-		if(*esc){
-			*esc = 0;
-			c = SLIP_END;
-		}
-		break;
-	}
-	buf[(*pos)++] = c;
-	return(0);
-}
-
-static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
-{
-	unsigned char *ptr = d;
-	unsigned char c;
-
-	/*
-	 * Send an initial END character to flush out any
-	 * data that may have accumulated in the receiver
-	 * due to line noise.
-	 */
-
-	*ptr++ = SLIP_END;
-
-	/*
-	 * For each byte in the packet, send the appropriate
-	 * character sequence, according to the SLIP protocol.
-	 */
-
-	while (len-- > 0) {
-		switch(c = *s++) {
-		case SLIP_END:
-			*ptr++ = SLIP_ESC;
-			*ptr++ = SLIP_ESC_END;
-			break;
-		case SLIP_ESC:
-			*ptr++ = SLIP_ESC;
-			*ptr++ = SLIP_ESC_ESC;
-			break;
-		default:
-			*ptr++ = c;
-			break;
-		}
-	}
-	*ptr++ = SLIP_END;
-	return (ptr - d);
-}
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -13,7 +13,7 @@
 #include "user.h"
 #include "net_user.h"
 #include "slip.h"
-#include "slip_proto.h"
+#include "slip_common.h"
 #include "helper.h"
 #include "os.h"
 
@@ -77,38 +77,51 @@ static int slip_tramp(char **argv, int f
 	err = os_pipe(fds, 1, 0);
 	if(err < 0){
 		printk("slip_tramp : pipe failed, err = %d\n", -err);
-		return(err);
+		goto out;
 	}
 
 	err = 0;
 	pe_data.stdin = fd;
 	pe_data.stdout = fds[1];
 	pe_data.close_me = fds[0];
-	pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
-
-	if(pid < 0) err = pid;
-	else {
-		output_len = page_size();
-		output = um_kmalloc(output_len);
-		if(output == NULL)
-			printk("slip_tramp : failed to allocate output "
-			       "buffer\n");
-
-		os_close_file(fds[1]);
-		read_output(fds[0], output, output_len);
-		if(output != NULL){
-			printk("%s", output);
-			kfree(output);
-		}
-		CATCH_EINTR(err = waitpid(pid, &status, 0));
-		if(err < 0)
-			err = errno;
-		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
-			printk("'%s' didn't exit with status 0\n", argv[0]);
-			err = -EINVAL;
-		}
-	}
-	return(err);
+	err = run_helper(slip_pre_exec, &pe_data, argv, NULL);
+	if(err < 0)
+		goto out_close;
+	pid = err;
+
+	output_len = page_size();
+	output = um_kmalloc(output_len);
+	if(output == NULL){
+		printk("slip_tramp : failed to allocate output buffer\n");
+		os_kill_process(pid, 1);
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	os_close_file(fds[1]);
+	read_output(fds[0], output, output_len);
+	printk("%s", output);
+
+	CATCH_EINTR(err = waitpid(pid, &status, 0));
+	if(err < 0)
+		err = errno;
+	else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+		printk("'%s' didn't exit with status 0\n", argv[0]);
+		err = -EINVAL;
+	}
+	else err = 0;
+
+	os_close_file(fds[0]);
+
+out_free:
+	kfree(output);
+	return err;
+
+out_close:
+	os_close_file(fds[0]);
+	os_close_file(fds[1]);
+out:
+	return err;
 }
 
 static int slip_open(void *data)
@@ -120,20 +133,26 @@ static int slip_open(void *data)
 			 NULL };
 	int sfd, mfd, err;
 
-	mfd = get_pty();
-	if(mfd < 0){
-		printk("umn : Failed to open pty, err = %d\n", -mfd);
-		return(mfd);
+	err = get_pty();
+	if(err < 0){
+		printk("slip-open : Failed to open pty, err = %d\n", -err);
+		goto out;
 	}
-	sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
-	if(sfd < 0){
-		printk("Couldn't open tty for slip line, err = %d\n", -sfd);
-		return(sfd);
+	mfd = err;
+
+	err = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
+	if(err < 0){
+		printk("Couldn't open tty for slip line, err = %d\n", -err);
+		goto out_close;
 	}
-	if(set_up_tty(sfd)) return(-1);
+	sfd = err;
+
+	if(set_up_tty(sfd))
+		goto out_close2;
+
 	pri->slave = sfd;
-	pri->pos = 0;
-	pri->esc = 0;
+	pri->slip.pos = 0;
+	pri->slip.esc = 0;
 	if(pri->gate_addr != NULL){
 		sprintf(version_buf, "%d", UML_NET_VERSION);
 		strcpy(gate_buf, pri->gate_addr);
@@ -142,12 +161,12 @@ static int slip_open(void *data)
 
 		if(err < 0){
 			printk("slip_tramp failed - err = %d\n", -err);
-			return(err);
+			goto out_close2;
 		}
 		err = os_get_ifname(pri->slave, pri->name);
 		if(err < 0){
 			printk("get_ifname failed, err = %d\n", -err);
-			return(err);
+			goto out_close2;
 		}
 		iter_addresses(pri->dev, open_addr, pri->name);
 	}
@@ -156,10 +175,16 @@ static int slip_open(void *data)
 		if(err < 0){
 			printk("Failed to set slip discipline encapsulation - "
 			       "err = %d\n", -err);
-			return(err);
+			goto out_close2;
 		}
 	}
 	return(mfd);
+out_close2:
+	os_close_file(sfd);
+out_close:
+	os_close_file(mfd);
+out:
+	return err;
 }
 
 static void slip_close(int fd, void *data)
@@ -175,7 +200,7 @@ static void slip_close(int fd, void *dat
 
 	sprintf(version_buf, "%d", UML_NET_VERSION);
 
-	err = slip_tramp(argv, -1);
+	err = slip_tramp(argv, pri->slave);
 
 	if(err != 0)
 		printk("slip_tramp failed - errno = %d\n", -err);
@@ -186,48 +211,12 @@ static void slip_close(int fd, void *dat
 
 int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
 {
-	int i, n, size, start;
-
-	if(pri->more>0) {
-		i = 0;
-		while(i < pri->more) {
-			size = slip_unesc(pri->ibuf[i++],
-					pri->ibuf, &pri->pos, &pri->esc);
-			if(size){
-				memcpy(buf, pri->ibuf, size);
-				memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
-				pri->more=pri->more-i; 
-				return(size);
-			}
-		}
-		pri->more=0;
-	}
-
-	n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
-	if(n <= 0) return(n);
-
-	start = pri->pos;
-	for(i = 0; i < n; i++){
-		size = slip_unesc(pri->ibuf[start + i],
-				pri->ibuf, &pri->pos, &pri->esc);
-		if(size){
-			memcpy(buf, pri->ibuf, size);
-			memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
-			pri->more=n-(i+1); 
-			return(size);
-		}
-	}
-	return(0);
+	return slip_proto_read(fd, buf, len, &pri->slip);
 }
 
 int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
 {
-	int actual, n;
-
-	actual = slip_esc(buf, pri->obuf, len);
-	n = net_write(fd, pri->obuf, actual);
-	if(n < 0) return(n);
-	else return(len);
+	return slip_proto_write(fd, buf, len, &pri->slip);
 }
 
 static int slip_set_mtu(int mtu, void *data)
@@ -263,14 +252,3 @@ struct net_user_info slip_user_info = {
 	.delete_address = slip_del_addr,
 	.max_packet	= BUF_SIZE
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
--- a/arch/um/drivers/slirp.h
+++ b/arch/um/drivers/slirp.h
@@ -1,10 +1,7 @@
 #ifndef __UM_SLIRP_H
 #define __UM_SLIRP_H
 
-#define BUF_SIZE 1500
- /* two bytes each for a (pathological) max packet of escaped chars +  * 
-  * terminating END char + initial END char                            */
-#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+#include "slip_common.h"
 
 #define SLIRP_MAX_ARGS 100
 /*
@@ -24,28 +21,13 @@ struct slirp_data {
 	struct arg_list_dummy_wrapper argw;
 	int pid;
 	int slave;
-	char ibuf[ENC_BUF_SIZE];
-	char obuf[ENC_BUF_SIZE];
-	int more; /* more data: do not read fd until ibuf has been drained */
-	int pos;
-	int esc;
+	struct slip_proto slip;
 };
 
 extern struct net_user_info slirp_user_info;
 
-extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
 extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
-extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
+extern int slirp_user_write(int fd, void *buf, int len,
+			    struct slirp_data *pri);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -25,16 +25,16 @@ void slirp_init(struct net_device *dev, 
 		{ .argw 	= init->argw,
 		  .pid  	= -1,
 		  .slave  	= -1,
-		  .ibuf  	= { '\0' },
-		  .obuf  	= { '\0' },
-		  .pos 		= 0,
-		  .esc 		= 0,
+		  .slip		= SLIP_PROTO_INIT,
 		  .dev 		= dev });
 
 	dev->init = NULL;
 	dev->hard_header_len = 0;
-	dev->addr_len = 4;
-	dev->type = ARPHRD_ETHER;
+	dev->header_cache_update = NULL;
+	dev->hard_header_cache = NULL;
+	dev->hard_header = NULL;
+	dev->addr_len = 0;
+	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = 256;
 	dev->flags = IFF_NOARP;
 	printk("SLIRP backend - command line:");
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -12,7 +12,7 @@
 #include "user.h"
 #include "net_user.h"
 #include "slirp.h"
-#include "slip_proto.h"
+#include "slip_common.h"
 #include "helper.h"
 #include "os.h"
 
@@ -48,47 +48,32 @@ static int slirp_tramp(char **argv, int 
 	return(pid);
 }
 
-/* XXX This is just a trivial wrapper around os_pipe */
-static int slirp_datachan(int *mfd, int *sfd)
-{
-	int fds[2], err;
-
-	err = os_pipe(fds, 1, 1);
-	if(err < 0){
-		printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
-		return(err);
-	}
-
-	*mfd = fds[0];
-	*sfd = fds[1];
-	return(0);
-}
-
 static int slirp_open(void *data)
 {
 	struct slirp_data *pri = data;
-	int sfd, mfd, pid, err;
+	int fds[2], pid, err;
 
-	err = slirp_datachan(&mfd, &sfd);
+	err = os_pipe(fds, 1, 1);
 	if(err)
 		return(err);
 
-	pid = slirp_tramp(pri->argw.argv, sfd);
-
-	if(pid < 0){
-		printk("slirp_tramp failed - errno = %d\n", -pid);
-		os_close_file(sfd);	
-		os_close_file(mfd);	
-		return(pid);
+	err = slirp_tramp(pri->argw.argv, fds[1]);
+	if(err < 0){
+		printk("slirp_tramp failed - errno = %d\n", -err);
+		goto out;
 	}
+	pid = err;
 
-	pri->slave = sfd;
-	pri->pos = 0;
-	pri->esc = 0;
-
-	pri->pid = pid;
-
-	return(mfd);
+	pri->slave = fds[1];
+	pri->slip.pos = 0;
+	pri->slip.esc = 0;
+	pri->pid = err;
+
+	return(fds[0]);
+out:
+	os_close_file(fds[0]);
+	os_close_file(fds[1]);
+	return err;
 }
 
 static void slirp_close(int fd, void *data)
@@ -129,48 +114,12 @@ static void slirp_close(int fd, void *da
 
 int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
 {
-	int i, n, size, start;
-
-	if(pri->more>0) {
-		i = 0;
-		while(i < pri->more) {
-			size = slip_unesc(pri->ibuf[i++],
-					pri->ibuf,&pri->pos,&pri->esc);
-			if(size){
-				memcpy(buf, pri->ibuf, size);
-				memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
-				pri->more=pri->more-i; 
-				return(size);
-			}
-		}
-		pri->more=0;
-	}
-
-	n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
-	if(n <= 0) return(n);
-
-	start = pri->pos;
-	for(i = 0; i < n; i++){
-		size = slip_unesc(pri->ibuf[start + i],
-				pri->ibuf,&pri->pos,&pri->esc);
-		if(size){
-			memcpy(buf, pri->ibuf, size);
-			memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
-			pri->more=n-(i+1); 
-			return(size);
-		}
-	}
-	return(0);
+	return slip_proto_read(fd, buf, len, &pri->slip);
 }
 
 int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
 {
-	int actual, n;
-
-	actual = slip_esc(buf, pri->obuf, len);
-	n = net_write(fd, pri->obuf, actual);
-	if(n < 0) return(n);
-	else return(len);
+	return slip_proto_write(fd, buf, len, &pri->slip);
 }
 
 static int slirp_set_mtu(int mtu, void *data)
@@ -188,14 +137,3 @@ struct net_user_info slirp_user_info = {
 	.delete_address = NULL,
 	.max_packet	= BUF_SIZE
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -22,7 +22,6 @@
 #include "init.h"
 #include "irq_user.h"
 #include "mconsole_kern.h"
-#include "2_5compat.h"
 
 static int ssl_version = 1;
 
@@ -107,11 +106,6 @@ int ssl_open(struct tty_struct *tty, str
 }
 
 #if 0
-static int ssl_chars_in_buffer(struct tty_struct *tty)
-{
-	return(0);
-}
-
 static void ssl_flush_buffer(struct tty_struct *tty)
 {
 	return;
@@ -149,11 +143,11 @@ static struct tty_operations ssl_ops = {
 	.put_char 		= line_put_char,
 	.write_room		= line_write_room,
 	.chars_in_buffer 	= line_chars_in_buffer,
+	.flush_buffer 		= line_flush_buffer,
+	.flush_chars 		= line_flush_chars,
 	.set_termios 		= line_set_termios,
 	.ioctl 	 		= line_ioctl,
 #if 0
-	.flush_chars 		= ssl_flush_chars,
-	.flush_buffer 		= ssl_flush_buffer,
 	.throttle 		= ssl_throttle,
 	.unthrottle 		= ssl_unthrottle,
 	.stop 	 		= ssl_stop,
@@ -171,10 +165,11 @@ static void ssl_console_write(struct con
 			      unsigned len)
 {
 	struct line *line = &serial_lines[c->index];
+	unsigned long flags;
 
-	down(&line->sem);
+	spin_lock_irqsave(&line->lock, flags);
 	console_write_chan(&line->chan_list, string, len);
-	up(&line->sem);
+	spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *ssl_console_device(struct console *c, int *index)
@@ -238,14 +233,3 @@ static int ssl_chan_setup(char *str)
 
 __setup("ssl", ssl_chan_setup);
 __channel_help(ssl_chan_setup, "ssl");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c
--- a/arch/um/drivers/stderr_console.c
+++ b/arch/um/drivers/stderr_console.c
@@ -22,9 +22,9 @@ static void stderr_console_write(struct 
 }
 
 static struct console stderr_console = {
-	.name		"stderr",
-	.write		stderr_console_write,
-	.flags		CON_PRINTBUFFER,
+	.name		= "stderr",
+	.write		= stderr_console_write,
+	.flags		= CON_PRINTBUFFER,
 };
 
 static int __init stderr_console_init(void)
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -28,7 +28,6 @@
 #include "irq_user.h"
 #include "mconsole_kern.h"
 #include "init.h"
-#include "2_5compat.h"
 
 #define MAX_TTYS (16)
 
@@ -116,8 +115,11 @@ static struct tty_operations console_ops
 	.open 	 		= con_open,
 	.close 	 		= line_close,
 	.write 	 		= line_write,
+	.put_char 		= line_put_char,
  	.write_room		= line_write_room,
 	.chars_in_buffer 	= line_chars_in_buffer,
+	.flush_buffer 		= line_flush_buffer,
+	.flush_chars 		= line_flush_chars,
 	.set_termios 		= line_set_termios,
 	.ioctl 	 		= line_ioctl,
 };
@@ -126,10 +128,11 @@ static void uml_console_write(struct con
 			  unsigned len)
 {
 	struct line *line = &vts[console->index];
+	unsigned long flags;
 
-	down(&line->sem);
+	spin_lock_irqsave(&line->lock, flags);
 	console_write_chan(&line->chan_list, string, len);
-	up(&line->sem);
+	spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *uml_console_device(struct console *c, int *index)
@@ -192,14 +195,3 @@ static int console_chan_setup(char *str)
 }
 __setup("con", console_chan_setup);
 __channel_help(console_chan_setup, "con");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -18,7 +18,7 @@ struct tty_chan {
 	struct termios tt;
 };
 
-void *tty_chan_init(char *str, int device, struct chan_opts *opts)
+static void *tty_chan_init(char *str, int device, struct chan_opts *opts)
 {
 	struct tty_chan *data;
 
@@ -38,7 +38,8 @@ void *tty_chan_init(char *str, int devic
 	return(data);
 }
 
-int tty_open(int input, int output, int primary, void *d, char **dev_out)
+static int tty_open(int input, int output, int primary, void *d,
+		    char **dev_out)
 {
 	struct tty_chan *data = d;
 	int fd, err;
@@ -59,7 +60,7 @@ int tty_open(int input, int output, int 
 	return(fd);
 }
 
-int tty_console_write(int fd, const char *buf, int n, void *d)
+static int tty_console_write(int fd, const char *buf, int n, void *d)
 {
 	struct tty_chan *data = d;
 
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -49,13 +49,12 @@
 #include "irq_user.h"
 #include "irq_kern.h"
 #include "ubd_user.h"
-#include "2_5compat.h"
 #include "os.h"
 #include "mem.h"
 #include "mem_kern.h"
 #include "cow.h"
 
-enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
+enum ubd_req { UBD_READ, UBD_WRITE };
 
 struct io_thread_req {
 	enum ubd_req op;
@@ -68,8 +67,6 @@ struct io_thread_req {
 	unsigned long sector_mask;
 	unsigned long long cow_offset;
 	unsigned long bitmap_words[2];
-	int map_fd;
-	unsigned long long map_offset;
 	int error;
 };
 
@@ -122,10 +119,6 @@ static int ubd_ioctl(struct inode * inod
 
 #define MAX_DEV (8)
 
-/* Changed in early boot */
-static int ubd_do_mmap = 0;
-#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
-
 static struct block_device_operations ubd_blops = {
         .owner		= THIS_MODULE,
         .open		= ubd_open,
@@ -156,6 +149,7 @@ static struct gendisk *fake_gendisk[MAX_
 static struct openflags global_openflags = OPEN_FLAGS;
 
 struct cow {
+	/* This is the backing file, actually */
 	char *file;
 	int fd;
 	unsigned long *bitmap;
@@ -174,12 +168,6 @@ struct ubd {
 	int no_cow;
 	struct cow cow;
 	struct platform_device pdev;
-
-	int map_writes;
-	int map_reads;
-	int nomap_writes;
-	int nomap_reads;
-	int write_maps;
 };
 
 #define DEFAULT_COW { \
@@ -199,11 +187,6 @@ struct ubd {
 	.openflags =		OPEN_FLAGS, \
         .no_cow =               0, \
         .cow =			DEFAULT_COW, \
-	.map_writes		= 0, \
-	.map_reads		= 0, \
-	.nomap_writes		= 0, \
-	.nomap_reads		= 0, \
-	.write_maps		= 0, \
 }
 
 struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
@@ -313,13 +296,6 @@ static int ubd_setup_common(char *str, i
 		int major;
 
 		str++;
-		if(!strcmp(str, "mmap")){
-			CHOOSE_MODE(printk("mmap not supported by the ubd "
-					   "driver in tt mode\n"),
-				    ubd_do_mmap = 1);
-			return(0);
-		}
-
 		if(!strcmp(str, "sync")){
 			global_openflags = of_sync(global_openflags);
 			return(0);
@@ -453,6 +429,22 @@ __uml_help(ubd_setup,
 "    an 's' will cause data to be written to disk on the host immediately.\n\n"
 );
 
+static int udb_setup(char *str)
+{
+	printk("udb%s specified on command line is almost certainly a ubd -> "
+	       "udb TYPO\n", str);
+	return(1);
+}
+
+__setup("udb", udb_setup);
+__uml_help(udb_setup,
+"udb\n"
+"    This option is here solely to catch ubd -> udb typos, which can be\n"
+"    to impossible to catch visually unless you specifically look for\n"
+"    them.  The only result of any option starting with 'udb' is an error\n"
+"    in the boot output.\n\n"
+);
+
 static int fakehd_set = 0;
 static int fakehd(char *str)
 {
@@ -507,7 +499,7 @@ static void ubd_handler(void)
 {
 	struct io_thread_req req;
 	struct request *rq = elv_next_request(ubd_queue);
-	int n, err;
+	int n;
 
 	do_ubd = NULL;
 	intr_count++;
@@ -521,19 +513,6 @@ static void ubd_handler(void)
 		return;
 	}
         
-	if((req.op != UBD_MMAP) &&
-	   ((req.offset != ((__u64) (rq->sector)) << 9) ||
-	    (req.length != (rq->current_nr_sectors) << 9)))
-		panic("I/O op mismatch");
-	
-	if(req.map_fd != -1){
-		err = physmem_subst_mapping(req.buffer, req.map_fd,
-					    req.map_offset, 1);
-		if(err)
-			printk("ubd_handler - physmem_subst_mapping failed, "
-			       "err = %d\n", -err);
-	}
-
 	ubd_finish(rq, req.error);
 	reactivate_fd(thread_fd, UBD_IRQ);	
 	do_ubd_request(ubd_queue);
@@ -566,14 +545,10 @@ static int ubd_file_size(struct ubd *dev
 
 static void ubd_close(struct ubd *dev)
 {
-	if(ubd_do_mmap)
-		physmem_forget_descriptor(dev->fd);
 	os_close_file(dev->fd);
 	if(dev->cow.file == NULL)
 		return;
 
-	if(ubd_do_mmap)
-		physmem_forget_descriptor(dev->cow.fd);
 	os_close_file(dev->cow.fd);
 	vfree(dev->cow.bitmap);
 	dev->cow.bitmap = NULL;
@@ -605,7 +580,11 @@ static int ubd_open_dev(struct ubd *dev)
 		}
 	}
 
-	if(dev->fd < 0) return(dev->fd);
+	if(dev->fd < 0){
+		printk("Failed to open '%s', errno = %d\n", dev->file,
+		       -dev->fd);
+		return(dev->fd);
+	}
 
 	if(dev->cow.file != NULL){
 		err = -ENOMEM;
@@ -746,15 +725,9 @@ static int ubd_config(char *str)
 static int ubd_get_config(char *name, char *str, int size, char **error_out)
 {
 	struct ubd *dev;
-	char *end;
 	int n, len = 0;
 
-	n = simple_strtoul(name, &end, 0);
-	if((*end != '\0') || (end == name)){
-		*error_out = "ubd_get_config : didn't parse device number";
-		return(-1);
-	}
-
+	n = parse_unit(&name);
 	if((n >= MAX_DEV) || (n < 0)){
 		*error_out = "ubd_get_config : device number out of range";
 		return(-1);
@@ -913,10 +886,14 @@ static int ubd_open(struct inode *inode,
 		}
 	}
 	dev->count++;
-	if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
+	set_disk_ro(disk, !dev->openflags.w);
+
+	/* This should no more be needed. And it didn't work anyway to exclude
+	 * read-write remounting of filesystems.*/
+	/*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
 	        if(--dev->count == 0) ubd_close(dev);
 	        err = -EROFS;
-	}
+	}*/
  out:
 	return(err);
 }
@@ -991,97 +968,17 @@ static void cowify_req(struct io_thread_
 			   req->bitmap_words, bitmap_len);
 }
 
-static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
-{
-	__u64 sector;
-	unsigned char *bitmap;
-	int bit, i;
-
-	/* mmap must have been requested on the command line */
-	if(!ubd_do_mmap)
-		return(-1);
-
-	/* The buffer must be page aligned */
-	if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
-		return(-1);
-
-	/* The request must be a page long */
-	if((req->current_nr_sectors << 9) != PAGE_SIZE)
-		return(-1);
-
-	if(dev->cow.file == NULL)
-		return(dev->fd);
-
-	sector = offset >> 9;
-	bitmap = (unsigned char *) dev->cow.bitmap;
-	bit = ubd_test_bit(sector, bitmap);
-
-	for(i = 1; i < req->current_nr_sectors; i++){
-		if(ubd_test_bit(sector + i, bitmap) != bit)
-			return(-1);
-	}
-
-	if(bit || (rq_data_dir(req) == WRITE))
-		offset += dev->cow.data_offset;
-
-	/* The data on disk must be page aligned */
-	if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
-		return(-1);
-
-	return(bit ? dev->fd : dev->cow.fd);
-}
-
-static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
-				struct request *req,
-				struct io_thread_req *io_req)
-{
-	int err;
-
-	if(rq_data_dir(req) == WRITE){
-		/* Writes are almost no-ops since the new data is already in the
-		 * host page cache
-		 */
-		dev->map_writes++;
-		if(dev->cow.file != NULL)
-			cowify_bitmap(io_req->offset, io_req->length,
-				      &io_req->sector_mask, &io_req->cow_offset,
-				      dev->cow.bitmap, dev->cow.bitmap_offset,
-				      io_req->bitmap_words,
-				      dev->cow.bitmap_len);
-	}
-	else {
-		int w;
-
-		if((dev->cow.file != NULL) && (fd == dev->cow.fd))
-			w = 0;
-		else w = dev->openflags.w;
-
-		if((dev->cow.file != NULL) && (fd == dev->fd))
-			offset += dev->cow.data_offset;
-
-		err = physmem_subst_mapping(req->buffer, fd, offset, w);
-		if(err){
-			printk("physmem_subst_mapping failed, err = %d\n",
-			       -err);
-			return(1);
-		}
-		dev->map_reads++;
-	}
-	io_req->op = UBD_MMAP;
-	io_req->buffer = req->buffer;
-	return(0);
-}
-
 /* Called with ubd_io_lock held */
 static int prepare_request(struct request *req, struct io_thread_req *io_req)
 {
 	struct gendisk *disk = req->rq_disk;
 	struct ubd *dev = disk->private_data;
 	__u64 offset;
-	int len, fd;
+	int len;
 
 	if(req->rq_status == RQ_INACTIVE) return(1);
 
+	/* This should be impossible now */
 	if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
 		printk("Write attempted on readonly ubd device %s\n", 
 		       disk->disk_name);
@@ -1094,34 +991,12 @@ static int prepare_request(struct reques
 
 	io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
 	io_req->fds[1] = dev->fd;
-	io_req->map_fd = -1;
 	io_req->cow_offset = -1;
 	io_req->offset = offset;
 	io_req->length = len;
 	io_req->error = 0;
 	io_req->sector_mask = 0;
 
-	fd = mmap_fd(req, dev, io_req->offset);
-	if(fd > 0){
-		/* If mmapping is otherwise OK, but the first access to the
-		 * page is a write, then it's not mapped in yet.  So we have
-		 * to write the data to disk first, then we can map the disk
-		 * page in and continue normally from there.
-		 */
-		if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
-			io_req->map_fd = dev->fd;
-			io_req->map_offset = io_req->offset +
-				dev->cow.data_offset;
-			dev->write_maps++;
-		}
-		else return(prepare_mmap_request(dev, fd, io_req->offset, req,
-						 io_req));
-	}
-
-	if(rq_data_dir(req) == READ)
-		dev->nomap_reads++;
-	else dev->nomap_writes++;
-
 	io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
 	io_req->offsets[0] = 0;
 	io_req->offsets[1] = dev->cow.data_offset;
@@ -1209,142 +1084,6 @@ static int ubd_ioctl(struct inode * inod
 	return(-EINVAL);
 }
 
-static int ubd_check_remapped(int fd, unsigned long address, int is_write,
-			      __u64 offset)
-{
-	__u64 bitmap_offset;
-	unsigned long new_bitmap[2];
-	int i, err, n;
-
-	/* If it's not a write access, we can't do anything about it */
-	if(!is_write)
-		return(0);
-
-	/* We have a write */
-	for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
-		struct ubd *dev = &ubd_dev[i];
-
-		if((dev->fd != fd) && (dev->cow.fd != fd))
-			continue;
-
-		/* It's a write to a ubd device */
-
-		if(!dev->openflags.w){
-			/* It's a write access on a read-only device - probably
-			 * shouldn't happen.  If the kernel is trying to change
-			 * something with no intention of writing it back out,
-			 * then this message will clue us in that this needs
-			 * fixing
-			 */
-			printk("Write access to mapped page from readonly ubd "
-			       "device %d\n", i);
-			return(0);
-		}
-
-		/* It's a write to a writeable ubd device - it must be COWed
-		 * because, otherwise, the page would have been mapped in
-		 * writeable
-		 */
-
-		if(!dev->cow.file)
-			panic("Write fault on writeable non-COW ubd device %d",
-			      i);
-
-		/* It should also be an access to the backing file since the
-		 * COW pages should be mapped in read-write
-		 */
-
-		if(fd == dev->fd)
-			panic("Write fault on a backing page of ubd "
-			      "device %d\n", i);
-
-		/* So, we do the write, copying the backing data to the COW
-		 * file...
-		 */
-
-		err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
-		if(err < 0)
-			panic("Couldn't seek to %lld in COW file of ubd "
-			      "device %d, err = %d",
-			      offset + dev->cow.data_offset, i, -err);
-
-		n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
-		if(n != PAGE_SIZE)
-			panic("Couldn't copy data to COW file of ubd "
-			      "device %d, err = %d", i, -n);
-
-		/* ... updating the COW bitmap... */
-
-		cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,
-			      dev->cow.bitmap, dev->cow.bitmap_offset,
-			      new_bitmap, dev->cow.bitmap_len);
-
-		err = os_seek_file(dev->fd, bitmap_offset);
-		if(err < 0)
-			panic("Couldn't seek to %lld in COW file of ubd "
-			      "device %d, err = %d", bitmap_offset, i, -err);
-
-		n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
-		if(n != sizeof(new_bitmap))
-			panic("Couldn't update bitmap  of ubd device %d, "
-			      "err = %d", i, -n);
-
-		/* Maybe we can map the COW page in, and maybe we can't.  If
-		 * it is a pre-V3 COW file, we can't, since the alignment will
-		 * be wrong.  If it is a V3 or later COW file which has been
-		 * moved to a system with a larger page size, then maybe we
-		 * can't, depending on the exact location of the page.
-		 */
-
-		offset += dev->cow.data_offset;
-
-		/* Remove the remapping, putting the original anonymous page
-		 * back.  If the COW file can be mapped in, that is done.
-		 * Otherwise, the COW page is read in.
-		 */
-
-		if(!physmem_remove_mapping((void *) address))
-			panic("Address 0x%lx not remapped by ubd device %d",
-			      address, i);
-		if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
-			physmem_subst_mapping((void *) address, dev->fd,
-					      offset, 1);
-		else {
-			err = os_seek_file(dev->fd, offset);
-			if(err < 0)
-				panic("Couldn't seek to %lld in COW file of "
-				      "ubd device %d, err = %d", offset, i,
-				      -err);
-
-			n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
-			if(n != PAGE_SIZE)
-				panic("Failed to read page from offset %llx of "
-				      "COW file of ubd device %d, err = %d",
-				      offset, i, -n);
-		}
-
-		return(1);
-	}
-
-	/* It's not a write on a ubd device */
-	return(0);
-}
-
-static struct remapper ubd_remapper = {
-	.list	= LIST_HEAD_INIT(ubd_remapper.list),
-	.proc	= ubd_check_remapped,
-};
-
-static int ubd_remapper_setup(void)
-{
-	if(ubd_do_mmap)
-		register_remapper(&ubd_remapper);
-
-	return(0);
-}
-
-__initcall(ubd_remapper_setup);
-
 static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
 {
 	struct uml_stat buf1, buf2;
@@ -1547,15 +1286,6 @@ void do_io(struct io_thread_req *req)
 	int err;
 	__u64 off;
 
-	if(req->op == UBD_MMAP){
-		/* Touch the page to force the host to do any necessary IO to
-		 * get it into memory
-		 */
-		n = *((volatile int *) req->buffer);
-		req->error = update_bitmap(req);
-		return;
-	}
-
 	nsectors = req->length / req->sectorsize;
 	start = 0;
 	do {
@@ -1591,8 +1321,7 @@ void do_io(struct io_thread_req *req)
 				}
 			} while((n < len) && (n != 0));
 			if (n < len) memset(&buf[n], 0, len - n);
-		}
-		else {
+		} else {
 			n = os_write_file(req->fds[bit], buf, len);
 			if(n != len){
 				printk("do_io - write failed err = %d "
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -31,6 +31,7 @@ struct xterm_chan {
 	int direct_rcv;
 };
 
+/* Not static because it's called directly by the tt mode gdb code */
 void *xterm_init(char *str, int device, struct chan_opts *opts)
 {
 	struct xterm_chan *data;
@@ -83,8 +84,11 @@ __uml_setup("xterm=", xterm_setup,
 "    are 'xterm=gnome-terminal,-t,-x'.\n\n"
 );
 
-/* XXX This badly needs some cleaning up in the error paths */
-int xterm_open(int input, int output, int primary, void *d, char **dev_out)
+/* XXX This badly needs some cleaning up in the error paths
+ * Not static because it's called directly by the tt mode gdb code
+ */
+int xterm_open(int input, int output, int primary, void *d,
+		      char **dev_out)
 {
 	struct xterm_chan *data = d;
 	unsigned long stack;
@@ -170,6 +174,7 @@ int xterm_open(int input, int output, in
 	return(new);
 }
 
+/* Not static because it's called directly by the tt mode gdb code */
 void xterm_close(int fd, void *d)
 {
 	struct xterm_chan *data = d;
@@ -183,12 +188,12 @@ void xterm_close(int fd, void *d)
 	os_close_file(fd);
 }
 
-void xterm_free(void *d)
+static void xterm_free(void *d)
 {
 	free(d);
 }
 
-int xterm_console_write(int fd, const char *buf, int n, void *d)
+static int xterm_console_write(int fd, const char *buf, int n, void *d)
 {
 	struct xterm_chan *data = d;
 
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -7,7 +7,6 @@
 #include "linux/slab.h"
 #include "linux/signal.h"
 #include "linux/interrupt.h"
-#include "asm/semaphore.h"
 #include "asm/irq.h"
 #include "irq_user.h"
 #include "irq_kern.h"
@@ -16,7 +15,7 @@
 #include "xterm.h"
 
 struct xterm_wait {
-	struct semaphore sem;
+	struct completion ready;
 	int fd;
 	int pid;
 	int new_fd;
@@ -32,7 +31,7 @@ static irqreturn_t xterm_interrupt(int i
 		return(IRQ_NONE);
 
 	xterm->new_fd = fd;
-	up(&xterm->sem);
+	complete(&xterm->ready);
 	return(IRQ_HANDLED);
 }
 
@@ -49,10 +48,10 @@ int xterm_fd(int socket, int *pid_out)
 
 	/* This is a locked semaphore... */
 	*data = ((struct xterm_wait) 
-		{ .sem  	= __SEMAPHORE_INITIALIZER(data->sem, 0),
-		  .fd 		= socket,
+		{ .fd 		= socket,
 		  .pid 		= -1,
 		  .new_fd 	= -1 });
+	init_completion(&data->ready);
 
 	err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, 
 			     SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
@@ -68,7 +67,7 @@ int xterm_fd(int socket, int *pid_out)
 	 *
 	 * XXX Note, if the xterm doesn't work for some reason (eg. DISPLAY
 	 * isn't set) this will hang... */
-	down(&data->sem);
+	wait_for_completion(&data->ready);
 
 	free_irq_by_irq_and_dev(XTERM_IRQ, data);
 	free_irq(XTERM_IRQ, data);
diff --git a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
deleted file mode 100644
--- a/arch/um/include/2_5compat.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __2_5_COMPAT_H__
-#define __2_5_COMPAT_H__
-
-#define INIT_HARDSECT(arr, maj, sizes)
-
-#define SET_PRI(task) do ; while(0)
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h
--- a/arch/um/include/choose-mode.h
+++ b/arch/um/include/choose-mode.h
@@ -11,6 +11,13 @@
 #if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS)
 #define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
 
+extern int mode_tt;
+static inline void *__choose_mode(void *tt, void *skas) {
+	return mode_tt ? tt : skas;
+}
+
+#define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas))))
+
 #elif defined(UML_CONFIG_MODE_SKAS)
 #define CHOOSE_MODE(tt, skas) (skas)
 
@@ -21,15 +28,8 @@
 #define CHOOSE_MODE_PROC(tt, skas, args...) \
 	CHOOSE_MODE(tt(args), skas(args))
 
+#ifndef __CHOOSE_MODE
+#define __CHOOSE_MODE(tt, skas) CHOOSE_MODE(tt, skas)
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+#endif
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/common-offsets.h
@@ -0,0 +1,14 @@
+/* for use by sys-$SUBARCH/kernel-offsets.c */
+
+OFFSET(TASK_REGS, task_struct, thread.regs);
+OFFSET(TASK_PID, task_struct, pid);
+DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE);
+DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
+DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
+DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
+DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
+DEFINE_STR(UM_KERN_ERR, KERN_ERR);
+DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
+DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
+DEFINE_STR(UM_KERN_INFO, KERN_INFO);
+DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h
--- a/arch/um/include/kern.h
+++ b/arch/um/include/kern.h
@@ -26,6 +26,7 @@ extern void *malloc(int size);
 extern void perror(char *err);
 extern int kill(int pid, int sig);
 extern int getuid(void);
+extern int getgid(void);
 extern int pause(void);
 extern int write(int, const void *, int);
 extern int exit(int);
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -8,6 +8,7 @@
 
 #include "linux/threads.h"
 #include "sysdep/ptrace.h"
+#include "sysdep/faultinfo.h"
 
 extern int ncpus;
 extern char *linux_prog;
@@ -31,8 +32,8 @@ extern int current_pid(void);
 extern unsigned long alloc_stack(int order, int atomic);
 extern int do_signal(void);
 extern int is_stack_fault(unsigned long sp);
-extern unsigned long segv(unsigned long address, unsigned long ip, 
-			  int is_write, int is_user, void *sc);
+extern unsigned long segv(struct faultinfo fi, unsigned long ip,
+			  int is_user, void *sc);
 extern int handle_page_fault(unsigned long address, unsigned long ip,
 			     int is_write, int is_user, int *code_out);
 extern void syscall_ready(void);
@@ -82,7 +83,7 @@ extern void timer_irq(union uml_pt_regs 
 extern void unprotect_stack(unsigned long stack);
 extern void do_uml_exitcalls(void);
 extern int attach_debugger(int idle_pid, int pid, int stop);
-extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
+extern void bad_segv(struct faultinfo fi, unsigned long ip);
 extern int config_gdb(char *str);
 extern int remove_gdb(void);
 extern char *uml_strdup(char *string);
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -10,7 +10,7 @@
 #include "linux/workqueue.h"
 #include "linux/tty.h"
 #include "linux/interrupt.h"
-#include "asm/semaphore.h"
+#include "linux/spinlock.h"
 #include "chan_user.h"
 #include "mconsole_kern.h"
 
@@ -37,10 +37,18 @@ struct line {
 	struct list_head chan_list;
 	int valid;
 	int count;
-	struct semaphore sem;
+	/*This lock is actually, mostly, local to*/
+	spinlock_t lock;
+
+	/* Yes, this is a real circular buffer.
+	 * XXX: And this should become a struct kfifo!
+	 *
+	 * buffer points to a buffer allocated on demand, of length
+	 * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/
 	char *buffer;
 	char *head;
 	char *tail;
+
 	int sigio;
 	struct work_struct task;
 	struct line_driver *driver;
@@ -52,7 +60,6 @@ struct line {
 	  init_pri :	INIT_STATIC, \
 	  chan_list : 	{ }, \
 	  valid :	1, \
-	  sem : 	{ }, \
 	  buffer :	NULL, \
 	  head :	NULL, \
 	  tail :	NULL, \
@@ -69,15 +76,18 @@ struct lines {
 extern void line_close(struct tty_struct *tty, struct file * filp);
 extern int line_open(struct line *lines, struct tty_struct *tty, 
 		     struct chan_opts *opts);
-extern int line_setup(struct line *lines, int num, char *init, 
+extern int line_setup(struct line *lines, unsigned int sizeof_lines, char *init,
 		      int all_allowed);
 extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len);
 extern void line_put_char(struct tty_struct *tty, unsigned char ch);
 extern void line_set_termios(struct tty_struct *tty, struct termios * old);
 extern int line_chars_in_buffer(struct tty_struct *tty);
+extern void line_flush_buffer(struct tty_struct *tty);
+extern void line_flush_chars(struct tty_struct *tty);
 extern int line_write_room(struct tty_struct *tty);
 extern int line_ioctl(struct tty_struct *tty, struct file * file,
 		      unsigned int cmd, unsigned long arg);
+
 extern char *add_xterm_umid(char *base);
 extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty);
 extern void line_close_chan(struct line *line);
@@ -89,20 +99,10 @@ extern struct tty_driver * line_register
 				int nlines);
 extern void lines_init(struct line *lines, int nlines);
 extern void close_lines(struct line *lines, int nlines);
-extern int line_config(struct line *lines, int num, char *str);
-extern int line_remove(struct line *lines, int num, char *str);
-extern int line_get_config(char *dev, struct line *lines, int num, char *str, 
+
+extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str,
 			   int size, char **error_out);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
--- a/arch/um/include/mconsole.h
+++ b/arch/um/include/mconsole.h
@@ -56,7 +56,7 @@ struct mc_request
 	int as_interrupt;
 
 	int originating_fd;
-	int originlen;
+	unsigned int originlen;
 	unsigned char origin[128];			/* sockaddr_un */
 
 	struct mconsole_request request;
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -35,7 +35,7 @@ extern void *get_output_buffer(int *len_
 extern void free_output_buffer(void *buffer);
 
 extern int tap_open_common(void *dev, char *gate_addr);
-extern void tap_check_ips(char *gate_addr, char *eth_addr);
+extern void tap_check_ips(char *gate_addr, unsigned char *eth_addr);
 
 extern void read_output(int fd, char *output_out, int len);
 
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -136,7 +136,7 @@ extern int os_seek_file(int fd, __u64 of
 extern int os_open_file(char *file, struct openflags flags, int mode);
 extern int os_read_file(int fd, void *buf, int len);
 extern int os_write_file(int fd, const void *buf, int count);
-extern int os_file_size(char *file, long long *size_out);
+extern int os_file_size(char *file, unsigned long long *size_out);
 extern int os_file_modtime(char *file, unsigned long *modtime);
 extern int os_pipe(int *fd, int stream, int close_on_exec);
 extern int os_set_fd_async(int fd, int owner);
@@ -160,6 +160,7 @@ extern void os_kill_process(int pid, int
 extern void os_kill_ptraced_process(int pid, int reap_child);
 extern void os_usr1_process(int pid);
 extern int os_getpid(void);
+extern int os_getpgrp(void);
 
 extern int os_map_memory(void *virt, int fd, unsigned long long off,
 			 unsigned long len, int r, int w, int x);
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -9,6 +9,8 @@
 #include "sysdep/ptrace.h"
 
 extern void init_thread_registers(union uml_pt_regs *to);
+extern int save_fp_registers(int pid, unsigned long *fp_regs);
+extern int restore_fp_registers(int pid, unsigned long *fp_regs);
 extern void save_registers(int pid, union uml_pt_regs *regs);
 extern void restore_registers(int pid, union uml_pt_regs *regs);
 extern void init_registers(int pid);
diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h
--- a/arch/um/include/skas_ptrace.h
+++ b/arch/um/include/skas_ptrace.h
@@ -6,22 +6,11 @@
 #ifndef __SKAS_PTRACE_H
 #define __SKAS_PTRACE_H
 
-struct ptrace_faultinfo {
-	int is_write;
-	unsigned long addr;
-};
-
-struct ptrace_ldt {
-	int func;
-  	void *ptr;
-	unsigned long bytecount;
-};
-
 #define PTRACE_FAULTINFO 52
-#define PTRACE_SIGPENDING 53
-#define PTRACE_LDT 54
 #define PTRACE_SWITCH_MM 55
 
+#include "sysdep/skas_ptrace.h"
+
 #endif
 
 /*
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
--- a/arch/um/include/sysdep-i386/checksum.h
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -24,24 +24,11 @@ unsigned int csum_partial(const unsigned
 			  unsigned int sum);
 
 /*
- * the same as csum_partial, but copies from src while it
- * checksums, and handles user-space pointer exceptions correctly, when needed.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-unsigned int csum_partial_copy_to(const unsigned char *src, unsigned char *dst,
-				  int len, int sum, int *err_ptr);
-unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst,
-				    int len, int sum, int *err_ptr);
-
-/*
  *	Note: when you get a NULL pointer exception here this means someone
  *	passed in an incorrect kernel address to one of these functions.
  *
  *	If you use these functions directly please don't forget the
- *	verify_area().
+ *	access_ok().
  */
 
 static __inline__
@@ -52,11 +39,24 @@ unsigned int csum_partial_copy_nocheck(c
 	return(csum_partial(dst, len, sum));
 }
 
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
 static __inline__
 unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
 					 int len, int sum, int *err_ptr)
 {
-	return csum_partial_copy_from(src, dst, len, sum, err_ptr);
+	if(copy_from_user(dst, src, len)){
+		*err_ptr = -EFAULT;
+		return(-1);
+	}
+
+	return csum_partial(dst, len, sum);
 }
 
 /*
@@ -67,7 +67,6 @@ unsigned int csum_partial_copy_from_user
  */
 
 #define csum_partial_copy_fromuser csum_partial_copy_from_user
-unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, int len, int sum);
 
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
@@ -196,8 +195,14 @@ static __inline__ unsigned int csum_and_
 						     unsigned char *dst,
 						     int len, int sum, int *err_ptr)
 {
-	if (access_ok(VERIFY_WRITE, dst, len))
-		return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
+	if (access_ok(VERIFY_WRITE, dst, len)){
+		if(copy_to_user(dst, src, len)){
+			*err_ptr = -EFAULT;
+			return(-1);
+		}
+
+		return csum_partial(src, len, sum);
+	}
 
 	if (len)
 		*err_ptr = -EFAULT;
diff --git a/arch/um/include/sysdep-i386/faultinfo.h b/arch/um/include/sysdep-i386/faultinfo.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-i386/faultinfo.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ * Licensed under the GPL
+ */
+
+#ifndef __FAULTINFO_I386_H
+#define __FAULTINFO_I386_H
+
+/* this structure contains the full arch-specific faultinfo
+ * from the traps.
+ * On i386, ptrace_faultinfo unfortunately doesn't provide
+ * all the info, since trap_no is missing.
+ * All common elements are defined at the same position in
+ * both structures, thus making it easy to copy the
+ * contents without knowledge about the structure elements.
+ */
+struct faultinfo {
+        int error_code; /* in ptrace_faultinfo misleadingly called is_write */
+        unsigned long cr2; /* in ptrace_faultinfo called addr */
+        int trap_no; /* missing in ptrace_faultinfo */
+};
+
+#define FAULT_WRITE(fi) ((fi).error_code & 2)
+#define FAULT_ADDRESS(fi) ((fi).cr2)
+
+#define PTRACE_FULL_FAULTINFO 0
+
+#endif
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
--- a/arch/um/include/sysdep-i386/ptrace.h
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -7,12 +7,14 @@
 #define __SYSDEP_I386_PTRACE_H
 
 #include "uml-config.h"
+#include "user_constants.h"
+#include "sysdep/faultinfo.h"
+#include "choose-mode.h"
 
-#ifdef UML_CONFIG_MODE_TT
-#include "sysdep/sc.h"
-#endif
+#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
+#define MAX_REG_OFFSET (UM_FRAME_SIZE)
 
-#ifdef UML_CONFIG_MODE_SKAS
+extern void update_debugregs(int seq);
 
 /* syscall emulation path in ptrace */
 
@@ -24,9 +26,13 @@ void set_using_sysemu(int value);
 int get_using_sysemu(void);
 extern int sysemu_supported;
 
-#include "skas_ptregs.h"
+#ifdef UML_CONFIG_MODE_TT
+#include "sysdep/sc.h"
+#endif
 
-#define HOST_FRAME_SIZE 17
+#ifdef UML_CONFIG_MODE_SKAS
+
+#include "skas_ptregs.h"
 
 #define REGS_IP(r) ((r)[HOST_IP])
 #define REGS_SP(r) ((r)[HOST_SP])
@@ -49,24 +55,17 @@ extern int sysemu_supported;
 
 #define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
 
-#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
-
-#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
-
-#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
-
 #endif
 #ifndef PTRACE_SYSEMU_SINGLESTEP
 #define PTRACE_SYSEMU_SINGLESTEP 32
 #endif
 
-#include "choose-mode.h"
-
 union uml_pt_regs {
 #ifdef UML_CONFIG_MODE_TT
 	struct tt_regs {
 		long syscall;
 		void *sc;
+                struct faultinfo faultinfo;
 	} tt;
 #endif
 #ifdef UML_CONFIG_MODE_SKAS
@@ -74,9 +73,7 @@ union uml_pt_regs {
 		unsigned long regs[HOST_FRAME_SIZE];
 		unsigned long fp[HOST_FP_SIZE];
 		unsigned long xfp[HOST_XFP_SIZE];
-		unsigned long fault_addr;
-		unsigned long fault_type;
-		unsigned long trap_type;
+                struct faultinfo faultinfo;
 		long syscall;
 		int is_user;
 	} skas;
@@ -89,39 +86,39 @@ extern int mode_tt;
 
 #define UPT_SC(r) ((r)->tt.sc)
 #define UPT_IP(r) \
-	CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
+	__CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
 #define UPT_SP(r) \
-	CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
+	__CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
 #define UPT_EFLAGS(r) \
-	CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
+	__CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
 #define UPT_EAX(r) \
-	CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
+	__CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
 #define UPT_EBX(r) \
-	CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
+	__CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
 #define UPT_ECX(r) \
-	CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
+	__CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
 #define UPT_EDX(r) \
-	CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
+	__CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
 #define UPT_ESI(r) \
-	CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
+	__CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
 #define UPT_EDI(r) \
-	CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
+	__CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
 #define UPT_EBP(r) \
-	CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
+	__CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
 #define UPT_ORIG_EAX(r) \
-	CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+	__CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
 #define UPT_CS(r) \
-	CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+	__CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
 #define UPT_SS(r) \
-	CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
+	__CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
 #define UPT_DS(r) \
-	CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
+	__CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
 #define UPT_ES(r) \
-	CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
+	__CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
 #define UPT_FS(r) \
-	CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
+	__CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
 #define UPT_GS(r) \
-	CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
+	__CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
 
 #define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
 #define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
@@ -213,15 +210,8 @@ struct syscall_args {
 #define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
 #define UPT_SYSCALL_RET(r) UPT_EAX(r)
 
-#define UPT_SEGV_IS_FIXABLE(r) \
-	CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
-                    REGS_SEGV_IS_FIXABLE(&r->skas))
-
-#define UPT_FAULT_ADDR(r) \
-	CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
-
-#define UPT_FAULT_WRITE(r) \
-	CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
+#define UPT_FAULTINFO(r) \
+        CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo))
 
 #endif
 
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -6,6 +6,8 @@
 #ifndef __SYSDEP_I386_PTRACE_USER_H__
 #define __SYSDEP_I386_PTRACE_USER_H__
 
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
 #include <asm/ptrace.h>
 
 #define PT_OFFSET(r) ((r) * sizeof(long))
@@ -33,9 +35,6 @@
 #define FP_FRAME_SIZE (27)
 #define FPX_FRAME_SIZE (128)
 
-#define MAX_REG_OFFSET (FRAME_SIZE_OFFSET)
-#define MAX_REG_NR (FRAME_SIZE)
-
 #ifdef PTRACE_GETREGS
 #define UM_HAVE_GETREGS
 #endif
@@ -60,6 +59,4 @@
 #define UM_HAVE_SETFPXREGS
 #endif
 
-extern void update_debugregs(int seq);
-
 #endif
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
--- a/arch/um/include/sysdep-i386/sigcontext.h
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -6,22 +6,19 @@
 #ifndef __SYS_SIGCONTEXT_I386_H
 #define __SYS_SIGCONTEXT_I386_H
 
-#include "sc.h"
+#include <sysdep/sc.h>
 
 #define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
 
 #define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
 #define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result)
 
-#define SC_FAULT_ADDR(sc) SC_CR2(sc)
-#define SC_FAULT_TYPE(sc) SC_ERR(sc)
-
-#define FAULT_WRITE(err) (err & 2)
-#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
-
-#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
-
-#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
+#define GET_FAULTINFO_FROM_SC(fi,sc) \
+	{ \
+		(fi).cr2 = SC_CR2(sc); \
+		(fi).error_code = SC_ERR(sc); \
+		(fi).trap_no = SC_TRAPNO(sc); \
+	}
 
 /* ptrace expects that, at the start of a system call, %eax contains
  * -ENOSYS, so this makes it so.
@@ -29,9 +26,7 @@
 #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
 
 /* This is Page Fault */
-#define SEGV_IS_FIXABLE(trap) (trap == 14)
-
-#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
+#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14)
 
 extern unsigned long *sc_sigmask(void *sc_ptr);
 extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
diff --git a/arch/um/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h
--- a/arch/um/include/sysdep-i386/signal.h
+++ b/arch/um/include/sysdep-i386/signal.h
@@ -8,6 +8,8 @@
 
 #include <signal.h>
 
+#define ARCH_SIGHDLR_PARAM int sig
+
 #define ARCH_GET_SIGCONTEXT(sc, sig) \
 	do sc = (struct sigcontext *) (&sig + 1); while(0)
 
diff --git a/arch/um/include/sysdep-i386/skas_ptrace.h b/arch/um/include/sysdep-i386/skas_ptrace.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-i386/skas_ptrace.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_SKAS_PTRACE_H
+#define __SYSDEP_I386_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+        int is_write;
+        unsigned long addr;
+};
+
+struct ptrace_ldt {
+        int func;
+        void *ptr;
+        unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
--- a/arch/um/include/sysdep-i386/syscalls.h
+++ b/arch/um/include/sysdep-i386/syscalls.h
@@ -22,102 +22,3 @@ extern syscall_handler_t old_mmap_i386;
 extern long sys_mmap2(unsigned long addr, unsigned long len,
 		      unsigned long prot, unsigned long flags,
 		      unsigned long fd, unsigned long pgoff);
-
-#define ARCH_SYSCALLS \
-	[ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, \
-	[ __NR_break ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_oldstat ] = (syscall_handler_t *) sys_stat, \
-	[ __NR_umount ] = (syscall_handler_t *) sys_oldumount, \
-	[ __NR_stime ] = um_stime, \
-	[ __NR_oldfstat ] = (syscall_handler_t *) sys_fstat, \
-	[ __NR_stty ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_gtty ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_nice ] = (syscall_handler_t *) sys_nice, \
-	[ __NR_ftime ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_prof ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_signal ] = (syscall_handler_t *) sys_signal, \
-	[ __NR_lock ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_mpx ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_ulimit ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_oldolduname ] = (syscall_handler_t *) sys_olduname, \
-	[ __NR_sigaction ] = (syscall_handler_t *) sys_sigaction, \
-	[ __NR_sgetmask ] = (syscall_handler_t *) sys_sgetmask, \
-	[ __NR_ssetmask ] = (syscall_handler_t *) sys_ssetmask, \
-	[ __NR_sigsuspend ] = (syscall_handler_t *) sys_sigsuspend, \
-	[ __NR_sigpending ] = (syscall_handler_t *) sys_sigpending, \
-	[ __NR_oldlstat ] = (syscall_handler_t *) sys_lstat, \
-	[ __NR_readdir ] = old_readdir, \
-	[ __NR_profil ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_socketcall ] = (syscall_handler_t *) sys_socketcall, \
-	[ __NR_olduname ] = (syscall_handler_t *) sys_uname, \
-	[ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_idle ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_ipc ] = (syscall_handler_t *) sys_ipc, \
-	[ __NR_sigreturn ] = (syscall_handler_t *) sys_sigreturn, \
-	[ __NR_sigprocmask ] = (syscall_handler_t *) sys_sigprocmask, \
-	[ __NR_bdflush ] = (syscall_handler_t *) sys_bdflush, \
-	[ __NR__llseek ] = (syscall_handler_t *) sys_llseek, \
-	[ __NR__newselect ] = (syscall_handler_t *) sys_select, \
-	[ __NR_vm86 ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \
-	[ __NR_ugetrlimit ] = (syscall_handler_t *) sys_getrlimit, \
-	[ __NR_mmap2 ] = (syscall_handler_t *) sys_mmap2, \
-	[ __NR_truncate64 ] = (syscall_handler_t *) sys_truncate64, \
-	[ __NR_ftruncate64 ] = (syscall_handler_t *) sys_ftruncate64, \
-	[ __NR_stat64 ] = (syscall_handler_t *) sys_stat64, \
-	[ __NR_lstat64 ] = (syscall_handler_t *) sys_lstat64, \
-	[ __NR_fstat64 ] = (syscall_handler_t *) sys_fstat64, \
-	[ __NR_fcntl64 ] = (syscall_handler_t *) sys_fcntl64, \
-	[ __NR_sendfile64 ] = (syscall_handler_t *) sys_sendfile64, \
-	[ __NR_statfs64 ] = (syscall_handler_t *) sys_statfs64, \
-	[ __NR_fstatfs64 ] = (syscall_handler_t *) sys_fstatfs64, \
-	[ __NR_fadvise64_64 ] = (syscall_handler_t *) sys_fadvise64_64, \
-	[ __NR_select ] = (syscall_handler_t *) old_select, \
-	[ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \
-        [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \
-	[ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \
-	[ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \
-	[ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \
-	[ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \
-	[ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \
-	[ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \
-	[ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \
-	[ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \
-	[ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \
-	[ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \
-	[ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \
-	[ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \
-	[ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \
-	[ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \
-	[ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \
-	[ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \
-	[ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \
-	[ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \
-	[ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \
-	[ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \
-	[ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \
-	[ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \
-        [ 222 ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ 223 ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64, \
-	[ 251 ] = (syscall_handler_t *) sys_ni_syscall, \
-        [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages, \
-	[ __NR_utimes ] = (syscall_handler_t *) sys_utimes, \
-	[ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall,
-        
-/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
-
-#define LAST_ARCH_SYSCALL __NR_vserver
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysdep-ia64/skas_ptrace.h b/arch/um/include/sysdep-ia64/skas_ptrace.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-ia64/skas_ptrace.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SKAS_PTRACE_H
+#define __SYSDEP_IA64_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+        int is_write;
+        unsigned long addr;
+};
+
+struct ptrace_ldt {
+        int func;
+        void *ptr;
+        unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
diff --git a/arch/um/include/sysdep-ppc/skas_ptrace.h b/arch/um/include/sysdep-ppc/skas_ptrace.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-ppc/skas_ptrace.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_PPC_SKAS_PTRACE_H
+#define __SYSDEP_PPC_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+        int is_write;
+        unsigned long addr;
+};
+
+struct ptrace_ldt {
+        int func;
+        void *ptr;
+        unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h
--- a/arch/um/include/sysdep-x86_64/checksum.h
+++ b/arch/um/include/sysdep-x86_64/checksum.h
@@ -9,8 +9,6 @@
 #include "linux/in6.h"
 #include "asm/uaccess.h"
 
-extern unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
-					   int sum, int *err_ptr);
 extern unsigned csum_partial(const unsigned char *buff, unsigned len,
                              unsigned sum);
 
@@ -19,11 +17,11 @@ extern unsigned csum_partial(const unsig
  *	passed in an incorrect kernel address to one of these functions.
  *
  *	If you use these functions directly please don't forget the
- *	verify_area().
+ *	access_ok().
  */
 
 static __inline__
-unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
+unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst,
 				       int len, int sum)
 {
 	memcpy(dst, src, len);
@@ -31,10 +29,15 @@ unsigned int csum_partial_copy_nocheck(c
 }
 
 static __inline__
-unsigned int csum_partial_copy_from_user(const char *src, char *dst,
-					 int len, int sum, int *err_ptr)
-{
-	return csum_partial_copy_from(src, dst, len, sum, err_ptr);
+unsigned int csum_partial_copy_from_user(const unsigned char *src,
+                                         unsigned char *dst, int len, int sum,
+                                         int *err_ptr)
+{
+        if(copy_from_user(dst, src, len)){
+                *err_ptr = -EFAULT;
+                return(-1);
+        }
+        return csum_partial(dst, len, sum);
 }
 
 /**
@@ -137,15 +140,6 @@ static inline unsigned add32_with_carry(
         return a;
 }
 
-#endif
+extern unsigned short ip_compute_csum(unsigned char * buff, int len);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+#endif
diff --git a/arch/um/include/sysdep-x86_64/faultinfo.h b/arch/um/include/sysdep-x86_64/faultinfo.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/faultinfo.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ * Licensed under the GPL
+ */
+
+#ifndef __FAULTINFO_X86_64_H
+#define __FAULTINFO_X86_64_H
+
+/* this structure contains the full arch-specific faultinfo
+ * from the traps.
+ * On i386, ptrace_faultinfo unfortunately doesn't provide
+ * all the info, since trap_no is missing.
+ * All common elements are defined at the same position in
+ * both structures, thus making it easy to copy the
+ * contents without knowledge about the structure elements.
+ */
+struct faultinfo {
+        int error_code; /* in ptrace_faultinfo misleadingly called is_write */
+        unsigned long cr2; /* in ptrace_faultinfo called addr */
+        int trap_no; /* missing in ptrace_faultinfo */
+};
+
+#define FAULT_WRITE(fi) ((fi).error_code & 2)
+#define FAULT_ADDRESS(fi) ((fi).cr2)
+
+#define PTRACE_FULL_FAULTINFO 1
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -8,6 +8,11 @@
 #define __SYSDEP_X86_64_PTRACE_H
 
 #include "uml-config.h"
+#include "user_constants.h"
+#include "sysdep/faultinfo.h"
+
+#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
 
 #ifdef UML_CONFIG_MODE_TT
 #include "sysdep/sc.h"
@@ -79,6 +84,7 @@ union uml_pt_regs {
 		long syscall;
 		unsigned long orig_rax;
 		void *sc;
+                struct faultinfo faultinfo;
 	} tt;
 #endif
 #ifdef UML_CONFIG_MODE_SKAS
@@ -86,9 +92,7 @@ union uml_pt_regs {
 		/* XXX */
 		unsigned long regs[27];
 		unsigned long fp[65];
-		unsigned long fault_addr;
-		unsigned long fault_type;
-		unsigned long trap_type;
+                struct faultinfo faultinfo;
 		long syscall;
 		int is_user;
 	} skas;
@@ -100,37 +104,38 @@ union uml_pt_regs {
 /* XXX */
 extern int mode_tt;
 
-#define UPT_RBX(r) CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
-#define UPT_RCX(r) CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
-#define UPT_RDX(r) CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
-#define UPT_RSI(r) CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs))
-#define UPT_RDI(r) CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs))
-#define UPT_RBP(r) CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs))
-#define UPT_RAX(r) CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs))
-#define UPT_R8(r) CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs))
-#define UPT_R9(r) CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs))
-#define UPT_R10(r) CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs))
-#define UPT_R11(r) CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs))
-#define UPT_R12(r) CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs))
-#define UPT_R13(r) CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs))
-#define UPT_R14(r) CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
-#define UPT_R15(r) CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
-#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
-#define UPT_FS(r) CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
-#define UPT_GS(r) CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
-#define UPT_DS(r) CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
-#define UPT_ES(r) CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
-#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
+#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
+#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
+#define UPT_RSI(r) __CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs))
+#define UPT_RDI(r) __CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs))
+#define UPT_RBP(r) __CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs))
+#define UPT_RAX(r) __CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs))
+#define UPT_R8(r) __CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs))
+#define UPT_R9(r) __CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs))
+#define UPT_R10(r) __CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs))
+#define UPT_R11(r) __CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs))
+#define UPT_R12(r) __CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs))
+#define UPT_R13(r) __CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs))
+#define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
+#define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
+#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
+#define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
+#define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
+#define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
+#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
 #define UPT_ORIG_RAX(r) \
-	CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
+	__CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
 
-#define UPT_IP(r) CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
-#define UPT_SP(r) CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
+#define UPT_IP(r) __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
+#define UPT_SP(r) __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
 
 #define UPT_EFLAGS(r) \
-	CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
+	__CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
 #define UPT_SC(r) ((r)->tt.sc)
-#define UPT_SYSCALL_NR(r) CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+#define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+#define UPT_SYSCALL_RET(r) UPT_RAX(r)
 
 extern int user_context(unsigned long sp);
 
@@ -192,32 +197,32 @@ struct syscall_args {
 
 
 #define UPT_SET(regs, reg, val) \
-        ({      unsigned long val; \
+        ({      unsigned long __upt_val = val; \
                 switch(reg){ \
-		case R8: UPT_R8(regs) = val; break; \
-		case R9: UPT_R9(regs) = val; break; \
-		case R10: UPT_R10(regs) = val; break; \
-		case R11: UPT_R11(regs) = val; break; \
-		case R12: UPT_R12(regs) = val; break; \
-		case R13: UPT_R13(regs) = val; break; \
-		case R14: UPT_R14(regs) = val; break; \
-		case R15: UPT_R15(regs) = val; break; \
-                case RIP: UPT_IP(regs) = val; break; \
-                case RSP: UPT_SP(regs) = val; break; \
-                case RAX: UPT_RAX(regs) = val; break; \
-                case RBX: UPT_RBX(regs) = val; break; \
-                case RCX: UPT_RCX(regs) = val; break; \
-                case RDX: UPT_RDX(regs) = val; break; \
-                case RSI: UPT_RSI(regs) = val; break; \
-                case RDI: UPT_RDI(regs) = val; break; \
-                case RBP: UPT_RBP(regs) = val; break; \
-                case ORIG_RAX: UPT_ORIG_RAX(regs) = val; break; \
-                case CS: UPT_CS(regs) = val; break; \
-                case DS: UPT_DS(regs) = val; break; \
-                case ES: UPT_ES(regs) = val; break; \
-                case FS: UPT_FS(regs) = val; break; \
-                case GS: UPT_GS(regs) = val; break; \
-                case EFLAGS: UPT_EFLAGS(regs) = val; break; \
+                case R8: UPT_R8(regs) = __upt_val; break; \
+                case R9: UPT_R9(regs) = __upt_val; break; \
+                case R10: UPT_R10(regs) = __upt_val; break; \
+                case R11: UPT_R11(regs) = __upt_val; break; \
+                case R12: UPT_R12(regs) = __upt_val; break; \
+                case R13: UPT_R13(regs) = __upt_val; break; \
+                case R14: UPT_R14(regs) = __upt_val; break; \
+                case R15: UPT_R15(regs) = __upt_val; break; \
+                case RIP: UPT_IP(regs) = __upt_val; break; \
+                case RSP: UPT_SP(regs) = __upt_val; break; \
+                case RAX: UPT_RAX(regs) = __upt_val; break; \
+                case RBX: UPT_RBX(regs) = __upt_val; break; \
+                case RCX: UPT_RCX(regs) = __upt_val; break; \
+                case RDX: UPT_RDX(regs) = __upt_val; break; \
+                case RSI: UPT_RSI(regs) = __upt_val; break; \
+                case RDI: UPT_RDI(regs) = __upt_val; break; \
+                case RBP: UPT_RBP(regs) = __upt_val; break; \
+                case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \
+                case CS: UPT_CS(regs) = __upt_val; break; \
+                case DS: UPT_DS(regs) = __upt_val; break; \
+                case ES: UPT_ES(regs) = __upt_val; break; \
+                case FS: UPT_FS(regs) = __upt_val; break; \
+                case GS: UPT_GS(regs) = __upt_val; break; \
+                case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \
                 default :  \
                         panic("Bad register in UPT_SET : %d\n", reg);  \
 			break; \
@@ -237,24 +242,7 @@ struct syscall_args {
 	CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
                     REGS_SEGV_IS_FIXABLE(&r->skas))
 
-#define UPT_FAULT_ADDR(r) \
-	CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
-
-#define UPT_FAULT_WRITE(r) \
-	CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
-
-#define UPT_TRAP(r) CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas))
-#define UPT_ERR(r) CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas))
+#define UPT_FAULTINFO(r) \
+        CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo))
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -8,6 +8,8 @@
 #define __SYSDEP_X86_64_PTRACE_USER_H__
 
 #define __FRAME_OFFSETS
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
 #include <asm/ptrace.h>
 #undef __FRAME_OFFSETS
 
@@ -45,9 +47,6 @@
 #define PT_ORIG_RAX_OFFSET (ORIG_RAX)
 #define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)])
 
-#define MAX_REG_OFFSET (FRAME_SIZE)
-#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
-
 /* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
  * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the
  * 2.4 name and value for 2.4 host compatibility.
diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h
--- a/arch/um/include/sysdep-x86_64/sigcontext.h
+++ b/arch/um/include/sysdep-x86_64/sigcontext.h
@@ -7,7 +7,7 @@
 #ifndef __SYSDEP_X86_64_SIGCONTEXT_H
 #define __SYSDEP_X86_64_SIGCONTEXT_H
 
-#include "sc.h"
+#include <sysdep/sc.h>
 
 #define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
 
@@ -17,11 +17,12 @@
 #define SC_FAULT_ADDR(sc) SC_CR2(sc)
 #define SC_FAULT_TYPE(sc) SC_ERR(sc)
 
-#define FAULT_WRITE(err) ((err) & 2)
-
-#define SC_FAULT_WRITE(sc) FAULT_WRITE(SC_FAULT_TYPE(sc))
-
-#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
+#define GET_FAULTINFO_FROM_SC(fi,sc) \
+	{ \
+		(fi).cr2 = SC_CR2(sc); \
+		(fi).error_code = SC_ERR(sc); \
+		(fi).trap_no = SC_TRAPNO(sc); \
+	}
 
 /* ptrace expects that, at the start of a system call, %eax contains
  * -ENOSYS, so this makes it so.
@@ -29,8 +30,8 @@
 
 #define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0)
 
-#define SEGV_IS_FIXABLE(trap) ((trap) == 14)
-#define SC_SEGV_IS_FIXABLE(sc) SEGV_IS_FIXABLE(SC_TRAP_TYPE(sc))
+/* This is Page Fault */
+#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14)
 
 extern unsigned long *sc_sigmask(void *sc_ptr);
 
diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h
--- a/arch/um/include/sysdep-x86_64/signal.h
+++ b/arch/um/include/sysdep-x86_64/signal.h
@@ -6,6 +6,8 @@
 #ifndef __X86_64_SIGNAL_H_
 #define __X86_64_SIGNAL_H_
 
+#define ARCH_SIGHDLR_PARAM int sig
+
 #define ARCH_GET_SIGCONTEXT(sc, sig_addr) \
 	do { \
 		struct ucontext *__uc; \
diff --git a/arch/um/include/sysdep-x86_64/skas_ptrace.h b/arch/um/include/sysdep-x86_64/skas_ptrace.h
new file mode 100644
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/skas_ptrace.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_X86_64_SKAS_PTRACE_H
+#define __SYSDEP_X86_64_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+        int is_write;
+        unsigned long addr;
+};
+
+struct ptrace_ldt {
+        int func;
+        void *ptr;
+        unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
--- a/arch/um/include/sysdep-x86_64/syscalls.h
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -26,71 +26,9 @@ extern syscall_handler_t *ia32_sys_call_
 extern long old_mmap(unsigned long addr, unsigned long len,
 		     unsigned long prot, unsigned long flags,
 		     unsigned long fd, unsigned long pgoff);
-extern syscall_handler_t wrap_sys_shmat;
 extern syscall_handler_t sys_modify_ldt;
 extern syscall_handler_t sys_arch_prctl;
 
-#define ARCH_SYSCALLS \
-	[ __NR_mmap ] = (syscall_handler_t *) old_mmap, \
-	[ __NR_select ] = (syscall_handler_t *) sys_select, \
-	[ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \
-	[ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \
-	[ __NR_shmget ] = (syscall_handler_t *) sys_shmget, \
-	[ __NR_shmat ] = (syscall_handler_t *) wrap_sys_shmat, \
-	[ __NR_shmctl ] = (syscall_handler_t *) sys_shmctl, \
-	[ __NR_semop ] = (syscall_handler_t *) sys_semop, \
-	[ __NR_semget ] = (syscall_handler_t *) sys_semget, \
-	[ __NR_semctl ] = (syscall_handler_t *) sys_semctl, \
-	[ __NR_shmdt ] = (syscall_handler_t *) sys_shmdt, \
-	[ __NR_msgget ] = (syscall_handler_t *) sys_msgget, \
-	[ __NR_msgsnd ] = (syscall_handler_t *) sys_msgsnd, \
-	[ __NR_msgrcv ] = (syscall_handler_t *) sys_msgrcv, \
-	[ __NR_msgctl ] = (syscall_handler_t *) sys_msgctl, \
-	[ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \
-	[ __NR_tuxcall ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_security ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_epoll_ctl_old ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_epoll_wait_old ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \
-	[ __NR_arch_prctl ] = (syscall_handler_t *) sys_arch_prctl, \
-	[ __NR_socket ] = (syscall_handler_t *) sys_socket, \
-	[ __NR_connect ] = (syscall_handler_t *) sys_connect, \
-	[ __NR_accept ] = (syscall_handler_t *) sys_accept, \
-	[ __NR_recvfrom ] = (syscall_handler_t *) sys_recvfrom, \
-	[ __NR_recvmsg ] = (syscall_handler_t *) sys_recvmsg, \
-	[ __NR_sendmsg ] = (syscall_handler_t *) sys_sendmsg, \
-	[ __NR_bind ] = (syscall_handler_t *) sys_bind, \
-	[ __NR_listen ] = (syscall_handler_t *) sys_listen, \
-	[ __NR_getsockname ] = (syscall_handler_t *) sys_getsockname, \
-	[ __NR_getpeername ] = (syscall_handler_t *) sys_getpeername, \
-	[ __NR_socketpair ] = (syscall_handler_t *) sys_socketpair, \
-	[ __NR_sendto ] = (syscall_handler_t *) sys_sendto, \
-	[ __NR_shutdown ] = (syscall_handler_t *) sys_shutdown, \
-	[ __NR_setsockopt ] = (syscall_handler_t *) sys_setsockopt, \
-	[ __NR_getsockopt ] = (syscall_handler_t *) sys_getsockopt, \
-	[ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
-        [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages, \
-	[ __NR_semtimedop ] = (syscall_handler_t *) sys_semtimedop, \
-	[ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64, \
-	[ 223 ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ __NR_utimes ] = (syscall_handler_t *) sys_utimes, \
-	[ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall, \
-	[ 251 ] = (syscall_handler_t *) sys_ni_syscall,
-
-#define LAST_ARCH_SYSCALL 251
-#define NR_syscalls 1024
+#define NR_syscalls (__NR_syscall_max + 1)
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysrq.h b/arch/um/include/sysrq.h
--- a/arch/um/include/sysrq.h
+++ b/arch/um/include/sysrq.h
@@ -1,6 +1,7 @@
 #ifndef __UM_SYSRQ_H
 #define __UM_SYSRQ_H
 
-extern void show_trace(unsigned long *stack);
+struct task_struct;
+extern void show_trace(struct task_struct* task, unsigned long *stack);
 
 #endif
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -6,9 +6,53 @@
 #ifndef __TLB_H__
 #define __TLB_H__
 
+#include "um_mmu.h"
+
+struct host_vm_op {
+	enum { MMAP, MUNMAP, MPROTECT } type;
+	union {
+		struct {
+			unsigned long addr;
+			unsigned long len;
+			unsigned int r:1;
+			unsigned int w:1;
+			unsigned int x:1;
+			int fd;
+			__u64 offset;
+		} mmap;
+		struct {
+			unsigned long addr;
+			unsigned long len;
+		} munmap;
+		struct {
+			unsigned long addr;
+			unsigned long len;
+			unsigned int r:1;
+			unsigned int w:1;
+			unsigned int x:1;
+		} mprotect;
+	} u;
+};
+
 extern void mprotect_kernel_vm(int w);
 extern void force_flush_all(void);
+extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
+			     unsigned long end_addr, int force, int data,
+			     void (*do_ops)(int, struct host_vm_op *, int));
+extern int flush_tlb_kernel_range_common(unsigned long start,
+					 unsigned long end);
 
+extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
+		    int r, int w, int x, struct host_vm_op *ops, int index,
+		    int last_filled, int data,
+		    void (*do_ops)(int, struct host_vm_op *, int));
+extern int add_munmap(unsigned long addr, unsigned long len,
+		      struct host_vm_op *ops, int index, int last_filled,
+		      int data, void (*do_ops)(int, struct host_vm_op *, int));
+extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
+			int x, struct host_vm_op *ops, int index,
+			int last_filled, int data,
+			void (*do_ops)(int, struct host_vm_op *, int));
 #endif
 
 /*
diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h
--- a/arch/um/include/um_mmu.h
+++ b/arch/um/include/um_mmu.h
@@ -6,22 +6,22 @@
 #ifndef __ARCH_UM_MMU_H
 #define __ARCH_UM_MMU_H
 
-#include "linux/config.h"
+#include "uml-config.h"
 #include "choose-mode.h"
 
-#ifdef CONFIG_MODE_TT
+#ifdef UML_CONFIG_MODE_TT
 #include "mmu-tt.h"
 #endif
 
-#ifdef CONFIG_MODE_SKAS
+#ifdef UML_CONFIG_MODE_SKAS
 #include "mmu-skas.h"
 #endif
 
-typedef union {
-#ifdef CONFIG_MODE_TT
+typedef union mm_context {
+#ifdef UML_CONFIG_MODE_TT
 	struct mmu_context_tt tt;
 #endif
-#ifdef CONFIG_MODE_SKAS
+#ifdef UML_CONFIG_MODE_SKAS
 	struct mmu_context_skas skas;
 #endif
 } mm_context_t;
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -20,7 +20,8 @@
 #define access_ok(type, addr, size) \
 	CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
 
-static inline int verify_area(int type, const void __user *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
 {
 	return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
 				size));
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -41,9 +41,6 @@ extern unsigned long highmem;
 extern char host_info[];
 
 extern char saved_command_line[];
-extern char command_line[];
-
-extern char *tempdir;
 
 extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
 extern unsigned long _unprotected_end;
@@ -67,7 +64,6 @@ extern void *um_kmalloc(int size);
 extern int switcheroo(int fd, int prot, void *from, void *to, int size);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(void);
-extern void add_arg(char *cmd_line, char *arg);
 extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
 extern void init_new_thread_signals(int altstack);
 extern void do_exec(int old_pid, int new_pid);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -4,40 +4,52 @@
 #
 
 extra-y := vmlinux.lds
-clean-files := vmlinux.lds.S
+clean-files :=
 
-obj-y = checksum.o config.o exec_kern.o exitcode.o \
+obj-y = config.o exec_kern.o exitcode.o \
 	helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
 	physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
 	sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
-	syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \
-	time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \
-	um_arch.o umid.o user_util.o
+	syscall_kern.o sysrq.o tempfile.o time.o time_kern.o \
+	tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \
+	user_util.o
 
-obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
+obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)	+= gprof_syms.o
 obj-$(CONFIG_GCOV)	+= gmon_syms.o
 obj-$(CONFIG_TTY_LOG)	+= tty_log.o
+obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
 
 obj-$(CONFIG_MODE_TT) += tt/
 obj-$(CONFIG_MODE_SKAS) += skas/
 
 user-objs-$(CONFIG_TTY_LOG) += tty_log.o
 
-USER_OBJS := $(filter %_user.o,$(obj-y))  $(user-objs-y) config.o helper.o \
-	main.o process.o tempfile.o time.o tty_log.o umid.o user_util.o frame.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
+	time.o tty_log.o umid.o user_util.o
 
-CFLAGS_frame.o := -fno-omit-frame-pointer
+include arch/um/scripts/Makefile.rules
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -c -o $@ $<
+targets := config.c config.tmp
 
-QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
-
-quiet_cmd_quote = QUOTE   $@
-cmd_quote = $(PERL) -e $(QUOTE) < $< > $@
-
-targets += config.c
-$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config FORCE
-	$(call if_changed,quote)
+# Be careful with the below Sed code - sed is pitfall-rich!
+# We use sed to lower build requirements, for "embedded" builders for instance.
+
+$(obj)/config.tmp: $(objtree)/.config FORCE
+	$(call if_changed,quote1)
+
+quiet_cmd_quote1 = QUOTE   $@
+      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
+		   $< > $@
+
+$(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
+	$(call if_changed,quote2)
+
+quiet_cmd_quote2 = QUOTE   $@
+      cmd_quote2 = sed -e '/CONFIG/{'          \
+		  -e 's/"CONFIG"\;/""/'        \
+		  -e 'r $(obj)/config.tmp'     \
+		  -e 'a \'                     \
+		  -e '""\;'                    \
+		  -e '}'                       \
+		  $< > $@
diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c
deleted file mode 100644
--- a/arch/um/kernel/checksum.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "asm/uaccess.h"
-#include "linux/errno.h"
-#include "linux/module.h"
-
-unsigned int arch_csum_partial(const unsigned char *buff, int len, int sum);
-
-unsigned int csum_partial(unsigned char *buff, int len, int sum)
-{
-	return arch_csum_partial(buff, len, sum);
-}
-
-EXPORT_SYMBOL(csum_partial);
-
-unsigned int csum_partial_copy_to(const unsigned char *src, char __user *dst,
-				int len, int sum, int *err_ptr)
-{
-	if(copy_to_user(dst, src, len)){
-		*err_ptr = -EFAULT;
-		return(-1);
-	}
-
-	return(arch_csum_partial(src, len, sum));
-}
-
-unsigned int csum_partial_copy_from(const unsigned char __user *src, char *dst,
-				int len, int sum, int *err_ptr)
-{
-	if(copy_from_user(dst, src, len)){
-		*err_ptr = -EFAULT;
-		return(-1);
-	}
-
-	return arch_csum_partial(dst, len, sum);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -16,7 +16,6 @@
 #include "kern.h"
 #include "irq_user.h"
 #include "tlb.h"
-#include "2_5compat.h"
 #include "os.h"
 #include "time_user.h"
 #include "choose-mode.h"
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -8,6 +8,20 @@
 extern void __bb_init_func(void *);
 EXPORT_SYMBOL(__bb_init_func);
 
+/* This is defined (and referred to in profiling stub code) only by some GCC
+ * versions in libgcov.
+ *
+ * Since SuSE backported the fix, we cannot handle it depending on GCC version.
+ * So, unconditinally export it. But also give it a weak declaration, which will
+ * be overriden by any other one.
+ */
+
+extern void __gcov_init(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_init);
+
+extern void __gcov_merge_add(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_merge_add);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c
new file mode 100644
--- /dev/null
+++ b/arch/um/kernel/initrd.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/initrd.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+
+/* Changed by uml_initrd_setup, which is a setup */
+static char *initrd __initdata = NULL;
+
+static int __init read_initrd(void)
+{
+	void *area;
+	long long size;
+	int err;
+
+	if(initrd == NULL) return 0;
+	err = os_file_size(initrd, &size);
+	if(err) return 0;
+	area = alloc_bootmem(size);
+	if(area == NULL) return 0;
+	if(load_initrd(initrd, area, size) == -1) return 0;
+	initrd_start = (unsigned long) area;
+	initrd_end = initrd_start + size;
+	return 0;
+}
+
+__uml_postsetup(read_initrd);
+
+static int __init uml_initrd_setup(char *line, int *add)
+{
+	initrd = line;
+	return 0;
+}
+
+__uml_setup("initrd=", uml_initrd_setup,
+"initrd=<initrd image>\n"
+"    This is used to boot UML from an initrd image.  The argument is the\n"
+"    name of the file containing the image.\n\n"
+);
+
+int load_initrd(char *filename, void *buf, int size)
+{
+	int fd, n;
+
+	fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
+	if(fd < 0){
+		printk("Opening '%s' failed - err = %d\n", filename, -fd);
+		return(-1);
+	}
+	n = os_read_file(fd, buf, size);
+	if(n != size){
+		printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+		       filename, -n);
+		return(-1);
+	}
+
+	os_close_file(fd);
+	return(0);
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c
deleted file mode 100644
--- a/arch/um/kernel/initrd_kern.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/init.h"
-#include "linux/bootmem.h"
-#include "linux/initrd.h"
-#include "asm/types.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "initrd.h"
-#include "init.h"
-#include "os.h"
-
-/* Changed by uml_initrd_setup, which is a setup */
-static char *initrd __initdata = NULL;
-
-static int __init read_initrd(void)
-{
-	void *area;
-	long long size;
-	int err;
-
-	if(initrd == NULL) return 0;
-	err = os_file_size(initrd, &size);
-	if(err) return 0;
-	area = alloc_bootmem(size);
-	if(area == NULL) return 0;
-	if(load_initrd(initrd, area, size) == -1) return 0;
-	initrd_start = (unsigned long) area;
-	initrd_end = initrd_start + size;
-	return 0;
-}
-
-__uml_postsetup(read_initrd);
-
-static int __init uml_initrd_setup(char *line, int *add)
-{
-	initrd = line;
-	return 0;
-}
-
-__uml_setup("initrd=", uml_initrd_setup, 
-"initrd=<initrd image>\n"
-"    This is used to boot UML from an initrd image.  The argument is the\n"
-"    name of the file containing the image.\n\n"
-);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
deleted file mode 100644
--- a/arch/um/kernel/initrd_user.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "initrd.h"
-#include "os.h"
-
-int load_initrd(char *filename, void *buf, int size)
-{
-	int fd, n;
-
-	fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
-	if(fd < 0){
-		printk("Opening '%s' failed - err = %d\n", filename, -fd);
-		return(-1);
-	}
-	n = os_read_file(fd, buf, size);
-	if(n != size){
-		printk("Read of %d bytes from '%s' failed, err = %d\n", size,
-		       filename, -n);
-		return(-1);
-	}
-
-	os_close_file(fd);
-	return(0);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -163,7 +163,6 @@ void __init init_IRQ(void)
 		irq_desc[i].handler = &SIGIO_irq_type;
 		enable_irq(i);
 	}
-	init_irq_signals(0);
 }
 
 /*
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -236,9 +236,15 @@ static void free_irq_by_cb(int (*test)(s
 				       (*prev)->fd, pollfds[i].fd);
 				goto out;
 			}
-			memcpy(&pollfds[i], &pollfds[i + 1],
-			       (pollfds_num - i - 1) * sizeof(pollfds[0]));
+
 			pollfds_num--;
+
+			/* This moves the *whole* array after pollfds[i] (though
+			 * it doesn't spot as such)! */
+
+			memmove(&pollfds[i], &pollfds[i + 1],
+			       (pollfds_num - i) * sizeof(pollfds[0]));
+
 			if(last_irq_ptr == &old_fd->next) 
 				last_irq_ptr = prev;
 			*prev = (*prev)->next;
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -10,7 +10,6 @@
 #include "linux/spinlock.h"
 #include "linux/highmem.h"
 #include "asm/current.h"
-#include "asm/delay.h"
 #include "asm/processor.h"
 #include "asm/unistd.h"
 #include "asm/pgalloc.h"
@@ -28,8 +27,6 @@ EXPORT_SYMBOL(uml_physmem);
 EXPORT_SYMBOL(set_signals);
 EXPORT_SYMBOL(get_signals);
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(__const_udelay);
-EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(sys_waitpid);
 EXPORT_SYMBOL(task_size);
 EXPORT_SYMBOL(flush_tlb_range);
@@ -60,6 +57,7 @@ EXPORT_SYMBOL(copy_to_user_tt);
 EXPORT_SYMBOL(strncpy_from_user_skas);
 EXPORT_SYMBOL(copy_to_user_skas);
 EXPORT_SYMBOL(copy_from_user_skas);
+EXPORT_SYMBOL(clear_user_skas);
 #endif
 EXPORT_SYMBOL(uml_strdup);
 
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
--- a/arch/um/kernel/main.c
+++ b/arch/um/kernel/main.c
@@ -24,8 +24,6 @@
 #include "mode.h"
 #include "choose-mode.h"
 #include "uml-config.h"
-#include "irq_user.h"
-#include "time_user.h"
 #include "os.h"
 
 /* Set in set_stklim, which is called from main and __wrap_malloc.
@@ -71,7 +69,7 @@ static __init void do_uml_initcalls(void
 
 static void last_ditch_exit(int sig)
 {
-	CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
+        kmalloc_ok = 0;
 	signal(SIGINT, SIG_DFL);
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
@@ -87,7 +85,7 @@ int main(int argc, char **argv, char **e
 {
 	char **new_argv;
 	sigset_t mask;
-	int ret, i;
+	int ret, i, err;
 
 	/* Enable all signals except SIGIO - in some environments, we can
 	 * enter with some signals blocked
@@ -160,27 +158,29 @@ int main(int argc, char **argv, char **e
 	 */
 	change_sig(SIGPROF, 0);
 
+        /* This signal stuff used to be in the reboot case.  However,
+         * sometimes a SIGVTALRM can come in when we're halting (reproducably
+         * when writing out gcov information, presumably because that takes
+         * some time) and cause a segfault.
+         */
+
+        /* stop timers and set SIG*ALRM to be ignored */
+        disable_timer();
+
+        /* disable SIGIO for the fds and set SIGIO to be ignored */
+        err = deactivate_all_fds();
+        if(err)
+                printf("deactivate_all_fds failed, errno = %d\n", -err);
+
+        /* Let any pending signals fire now.  This ensures
+         * that they won't be delivered after the exec, when
+         * they are definitely not expected.
+         */
+        unblock_signals();
+
 	/* Reboot */
 	if(ret){
-		int err;
-
 		printf("\n");
-
-		/* stop timers and set SIG*ALRM to be ignored */
-		disable_timer();
-
-		/* disable SIGIO for the fds and set SIGIO to be ignored */
-		err = deactivate_all_fds();
-		if(err)
-			printf("deactivate_all_fds failed, errno = %d\n",
-			       -err);
-
-		/* Let any pending signals fire now.  This ensures
-		 * that they won't be delivered after the exec, when
-		 * they are definitely not expected.
-		 */
-		unblock_signals();
-
 		execvp(new_argv[0], new_argv);
 		perror("Failed to exec kernel");
 		ret = 1;
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -100,12 +100,37 @@ void mem_init(void)
 #endif
 }
 
+/*
+ * Create a page table and place a pointer to it in a middle page
+ * directory entry.
+ */
+static void __init one_page_table_init(pmd_t *pmd)
+{
+	if (pmd_none(*pmd)) {
+		pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		set_pmd(pmd, __pmd(_KERNPG_TABLE +
+					   (unsigned long) __pa(pte)));
+		if (pte != pte_offset_kernel(pmd, 0))
+			BUG();
+	}
+}
+
+static void __init one_md_table_init(pud_t *pud)
+{
+#ifdef CONFIG_3_LEVEL_PGTABLES
+	pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+	set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table)));
+	if (pmd_table != pmd_offset(pud, 0))
+		BUG();
+#endif
+}
+
 static void __init fixrange_init(unsigned long start, unsigned long end, 
 				 pgd_t *pgd_base)
 {
 	pgd_t *pgd;
+	pud_t *pud;
 	pmd_t *pmd;
-	pte_t *pte;
 	int i, j;
 	unsigned long vaddr;
 
@@ -115,15 +140,12 @@ static void __init fixrange_init(unsigne
 	pgd = pgd_base + i;
 
 	for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
-		pmd = (pmd_t *)pgd;
+		pud = pud_offset(pgd, vaddr);
+		if (pud_none(*pud))
+			one_md_table_init(pud);
+		pmd = pmd_offset(pud, vaddr);
 		for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
-			if (pmd_none(*pmd)) {
-				pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-				set_pmd(pmd, __pmd(_KERNPG_TABLE + 
-						   (unsigned long) __pa(pte)));
-				if (pte != pte_offset_kernel(pmd, 0))
-					BUG();
-			}
+			one_page_table_init(pmd);
 			vaddr += PMD_SIZE;
 		}
 		j = 0;
@@ -138,7 +160,7 @@ pgprot_t kmap_prot;
 	pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
  			  (vaddr)), (vaddr))
 
-void __init kmap_init(void)
+static void __init kmap_init(void)
 {
 	unsigned long kmap_vstart;
 
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -294,7 +294,6 @@ int init_maps(unsigned long physmem, uns
 		INIT_LIST_HEAD(&p->lru);
 	}
 
-	mem_map = map;
 	max_mapnr = total_pages;
 	return(0);
 }
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -12,11 +12,6 @@
 #include <stdlib.h>
 #include <setjmp.h>
 #include <sys/time.h>
-#include <sys/ptrace.h>
-
-/*Userspace header, must be after sys/ptrace.h, and both must be included. */
-#include <linux/ptrace.h>
-
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <asm/unistd.h>
@@ -28,7 +23,6 @@
 #include "signal_kern.h"
 #include "signal_user.h"
 #include "sysdep/ptrace.h"
-#include "sysdep/ptrace_user.h"
 #include "sysdep/sigcontext.h"
 #include "irq_user.h"
 #include "ptrace_user.h"
@@ -70,8 +64,6 @@ void init_new_thread_signals(int altstac
 		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
 		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-	set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
 		    flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	signal(SIGHUP, SIG_IGN);
@@ -138,7 +130,7 @@ int start_fork_tramp(void *thread_arg, u
 	return(arg.pid);
 }
 
-static int ptrace_child(void *arg)
+static int ptrace_child(void)
 {
 	int ret;
 	int pid = os_getpid(), ppid = getppid();
@@ -167,20 +159,16 @@ static int ptrace_child(void *arg)
 	_exit(ret);
 }
 
-static int start_ptraced_child(void **stack_out)
+static int start_ptraced_child(void)
 {
-	void *stack;
-	unsigned long sp;
 	int pid, n, status;
 	
-	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
-		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-	if(stack == MAP_FAILED)
-		panic("check_ptrace : mmap failed, errno = %d", errno);
-	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
-	pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
+	pid = fork();
+	if(pid == 0)
+		ptrace_child();
+
 	if(pid < 0)
-		panic("check_ptrace : clone failed, errno = %d", errno);
+		panic("check_ptrace : fork failed, errno = %d", errno);
 	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
 	if(n < 0)
 		panic("check_ptrace : wait failed, errno = %d", errno);
@@ -188,7 +176,6 @@ static int start_ptraced_child(void **st
 		panic("check_ptrace : expected SIGSTOP, got status = %d",
 		      status);
 
-	*stack_out = stack;
 	return(pid);
 }
 
@@ -196,12 +183,12 @@ static int start_ptraced_child(void **st
  * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
  * So only for SYSEMU features we test mustpanic, while normal host features
  * must work anyway!*/
-static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
+static int stop_ptraced_child(int pid, int exitcode, int mustexit)
 {
 	int status, n, ret = 0;
 
 	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
-		panic("check_ptrace : ptrace failed, errno = %d", errno);
+		panic("stop_ptraced_child : ptrace failed, errno = %d", errno);
 	CATCH_EINTR(n = waitpid(pid, &status, 0));
 	if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
 		int exit_with = WEXITSTATUS(status);
@@ -212,15 +199,13 @@ static int stop_ptraced_child(int pid, v
 		printk("check_ptrace : child exited with exitcode %d, while "
 		      "expecting %d; status 0x%x", exit_with,
 		      exitcode, status);
-		if (mustpanic)
+		if (mustexit)
 			panic("\n");
 		else
 			printk("\n");
 		ret = -1;
 	}
 
-	if(munmap(stack, PAGE_SIZE) < 0)
-		panic("check_ptrace : munmap failed, errno = %d", errno);
 	return ret;
 }
 
@@ -242,12 +227,11 @@ __uml_setup("nosysemu", nosysemu_cmd_par
 
 static void __init check_sysemu(void)
 {
-	void *stack;
 	int pid, syscall, n, status, count=0;
 
 	printk("Checking syscall emulation patch for ptrace...");
 	sysemu_supported = 0;
-	pid = start_ptraced_child(&stack);
+	pid = start_ptraced_child();
 
 	if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
 		goto fail;
@@ -259,13 +243,13 @@ static void __init check_sysemu(void)
 		panic("check_sysemu : expected SIGTRAP, "
 		      "got status = %d", status);
 
-	n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
+	n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
 		   os_getpid());
 	if(n < 0)
 		panic("check_sysemu : failed to modify system "
 		      "call return, errno = %d", errno);
 
-	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
+	if (stop_ptraced_child(pid, 0, 0) < 0)
 		goto fail_stopped;
 
 	sysemu_supported = 1;
@@ -273,7 +257,7 @@ static void __init check_sysemu(void)
 	set_using_sysemu(!force_sysemu_disabled);
 
 	printk("Checking advanced syscall emulation patch for ptrace...");
-	pid = start_ptraced_child(&stack);
+	pid = start_ptraced_child();
 	while(1){
 		count++;
 		if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
@@ -285,12 +269,12 @@ static void __init check_sysemu(void)
 			panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), "
 			      "got status = %d", status);
 
-		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
+		syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
 				 0);
 		if(syscall == __NR_getpid){
 			if (!count)
 				panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep");
-			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
+			n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
 				   os_getpid());
 			if(n < 0)
 				panic("check_sysemu : failed to modify system "
@@ -298,7 +282,7 @@ static void __init check_sysemu(void)
 			break;
 		}
 	}
-	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
+	if (stop_ptraced_child(pid, 0, 0) < 0)
 		goto fail_stopped;
 
 	sysemu_supported = 2;
@@ -309,18 +293,17 @@ static void __init check_sysemu(void)
 	return;
 
 fail:
-	stop_ptraced_child(pid, stack, 1, 0);
+	stop_ptraced_child(pid, 1, 0);
 fail_stopped:
 	printk("missing\n");
 }
 
 void __init check_ptrace(void)
 {
-	void *stack;
 	int pid, syscall, n, status;
 
 	printk("Checking that ptrace can change system call numbers...");
-	pid = start_ptraced_child(&stack);
+	pid = start_ptraced_child();
 
 	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
 		panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
@@ -336,10 +319,10 @@ void __init check_ptrace(void)
 			panic("check_ptrace : expected SIGTRAP + 0x80, "
 			      "got status = %d", status);
 		
-		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
+		syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
 				 0);
 		if(syscall == __NR_getpid){
-			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
+			n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
 				   __NR_getppid);
 			if(n < 0)
 				panic("check_ptrace : failed to modify system "
@@ -347,7 +330,7 @@ void __init check_ptrace(void)
 			break;
 		}
 	}
-	stop_ptraced_child(pid, stack, 0, 1);
+	stop_ptraced_child(pid, 0, 1);
 	printk("OK\n");
 	check_sysemu();
 }
@@ -379,11 +362,10 @@ void forward_pending_sigio(int target)
 static inline int check_skas3_ptrace_support(void)
 {
 	struct ptrace_faultinfo fi;
-	void *stack;
 	int pid, n, ret = 1;
 
 	printf("Checking for the skas3 patch in the host...");
-	pid = start_ptraced_child(&stack);
+	pid = start_ptraced_child();
 
 	n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
 	if (n < 0) {
@@ -398,7 +380,7 @@ static inline int check_skas3_ptrace_sup
 	}
 
 	init_registers(pid);
-	stop_ptraced_child(pid, stack, 1, 1);
+	stop_ptraced_child(pid, 1, 1);
 
 	return(ret);
 }
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -21,6 +21,7 @@
 #include "linux/spinlock.h"
 #include "linux/proc_fs.h"
 #include "linux/ptrace.h"
+#include "linux/random.h"
 #include "asm/unistd.h"
 #include "asm/mman.h"
 #include "asm/segment.h"
@@ -42,7 +43,6 @@
 #include "tlb.h"
 #include "frame_kern.h"
 #include "sigcontext.h"
-#include "2_5compat.h"
 #include "os.h"
 #include "mode.h"
 #include "mode_kern.h"
@@ -54,18 +54,6 @@
  */
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
-struct task_struct *get_task(int pid, int require)
-{
-        struct task_struct *ret;
-
-        read_lock(&tasklist_lock);
-	ret = find_task_by_pid(pid);
-        read_unlock(&tasklist_lock);
-
-        if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
-        return(ret);
-}
-
 int external_pid(void *t)
 {
 	struct task_struct *task = t ? t : current;
@@ -114,16 +102,6 @@ int kernel_thread(int (*fn)(void *), voi
 	return(pid);
 }
 
-void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
-	       struct task_struct *tsk)
-{
-	int cpu = smp_processor_id();
-
-	if (prev != next) 
-		cpu_clear(cpu, prev->cpu_vm_mask);
-	cpu_set(cpu, next->cpu_vm_mask);
-}
-
 void set_current(void *t)
 {
 	struct task_struct *task = t;
@@ -151,7 +129,6 @@ void release_thread(struct task_struct *
  
 void exit_thread(void)
 {
-	CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
 	unprotect_stack((unsigned long) current_thread);
 }
  
@@ -160,10 +137,6 @@ void *get_current(void)
 	return(current);
 }
 
-void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		unsigned long stack_top, struct task_struct * p, 
 		struct pt_regs *regs)
@@ -203,7 +176,6 @@ void default_idle(void)
 
 	while(1){
 		/* endless idle loop with no priority at all */
-		SET_PRI(current);
 
 		/*
 		 * although we are an idle CPU, we do not want to
@@ -226,11 +198,6 @@ int page_size(void)
 	return(PAGE_SIZE);
 }
 
-unsigned long page_mask(void)
-{
-	return(PAGE_MASK);
-}
-
 void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
 		      pte_t *pte_out)
 {
@@ -363,11 +330,6 @@ char *uml_strdup(char *string)
 	return(new);
 }
 
-void *get_init_task(void)
-{
-	return(&init_thread_union.thread_info.task);
-}
-
 int copy_to_user_proc(void __user *to, void *from, int size)
 {
 	return(copy_to_user(to, from, size));
@@ -480,12 +442,17 @@ int singlestepping(void * t)
 }
 
 /*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
+ * Only x86 and x86_64 have an arch_align_stack().
+ * All other arches have "#define arch_align_stack(x) (x)"
+ * in their asm/system.h
+ * As this is included in UML from asm-um/system-generic.h,
+ * we can use it to behave as the subarch does.
  */
+#ifndef arch_align_stack
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (randomize_va_space)
+		sp -= get_random_int() % 8192;
+	return sp & ~0xf;
+}
+#endif
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -9,24 +9,40 @@
 #include "linux/smp_lock.h"
 #include "linux/security.h"
 #include "linux/ptrace.h"
+#include "linux/audit.h"
 #ifdef CONFIG_PROC_MM
 #include "linux/proc_mm.h"
 #endif
 #include "asm/ptrace.h"
 #include "asm/uaccess.h"
 #include "kern_util.h"
-#include "ptrace_user.h"
 #include "skas_ptrace.h"
+#include "sysdep/ptrace.h"
+
+static inline void set_singlestepping(struct task_struct *child, int on)
+{
+        if (on)
+                child->ptrace |= PT_DTRACE;
+        else
+                child->ptrace &= ~PT_DTRACE;
+        child->thread.singlestep_syscall = 0;
+
+#ifdef SUBARCH_SET_SINGLESTEPPING
+        SUBARCH_SET_SINGLESTEPPING(child, on);
+#endif
+}
 
 /*
  * Called by kernel/ptrace.c when detaching..
  */
 void ptrace_disable(struct task_struct *child)
 { 
-	child->ptrace &= ~PT_DTRACE;
-	child->thread.singlestep_syscall = 0;
+        set_singlestepping(child,0);
 }
 
+extern int peek_user(struct task_struct * child, long addr, long data);
+extern int poke_user(struct task_struct * child, long addr, long data);
+
 long sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -66,6 +82,10 @@ long sys_ptrace(long request, long pid, 
 		goto out_tsk;
 	}
 
+#ifdef SUBACH_PTRACE_SPECIAL
+        SUBARCH_PTRACE_SPECIAL(child,request,addr,data);
+#endif
+
 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
 	if (ret < 0)
 		goto out_tsk;
@@ -86,26 +106,9 @@ long sys_ptrace(long request, long pid, 
 	}
 
 	/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR: {
-		unsigned long tmp;
-
-		ret = -EIO;
-		if ((addr & 3) || addr < 0) 
-			break;
-
-		tmp = 0;  /* Default return condition */
-		if(addr < MAX_REG_OFFSET){
-			tmp = getreg(child, addr);
-		}
-		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
-			(addr <= offsetof(struct user, u_debugreg[7]))){
-			addr -= offsetof(struct user, u_debugreg[0]);
-			addr = addr >> 2;
-			tmp = child->thread.arch.debugregs[addr];
-		}
-		ret = put_user(tmp, (unsigned long __user *) data);
-		break;
-	}
+        case PTRACE_PEEKUSR:
+                ret = peek_user(child, addr, data);
+                break;
 
 	/* when I and D space are separate, this will have to be fixed. */
 	case PTRACE_POKETEXT: /* write the word at location addr. */
@@ -118,35 +121,16 @@ long sys_ptrace(long request, long pid, 
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret = -EIO;
-		if ((addr & 3) || addr < 0)
-			break;
-
-		if (addr < MAX_REG_OFFSET) {
-			ret = putreg(child, addr, data);
-			break;
-		}
-#if 0 /* XXX x86_64 */
-		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
-			(addr <= offsetof(struct user, u_debugreg[7]))){
-			  addr -= offsetof(struct user, u_debugreg[0]);
-			  addr = addr >> 2;
-			  if((addr == 4) || (addr == 5)) break;
-			  child->thread.arch.debugregs[addr] = data;
-			  ret = 0;
-		}
-#endif
-
-		break;
+                ret = poke_user(child, addr, data);
+                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)
+		if (!valid_signal(data))
 			break;
 
-		child->ptrace &= ~PT_DTRACE;
-		child->thread.singlestep_syscall = 0;
+                set_singlestepping(child, 0);
 		if (request == PTRACE_SYSCALL) {
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		}
@@ -169,8 +153,7 @@ long sys_ptrace(long request, long pid, 
 		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
 			break;
 
-		child->ptrace &= ~PT_DTRACE;
-		child->thread.singlestep_syscall = 0;
+                set_singlestepping(child, 0);
 		child->exit_code = SIGKILL;
 		wake_up_process(child);
 		break;
@@ -178,11 +161,10 @@ long sys_ptrace(long request, long pid, 
 
 	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		child->ptrace |= PT_DTRACE;
-		child->thread.singlestep_syscall = 0;
+                set_singlestepping(child, 1);
 		child->exit_code = data;
 		/* give it a chance to run. */
 		wake_up_process(child);
@@ -249,23 +231,19 @@ long sys_ptrace(long request, long pid, 
 		break;
 #endif
 	case PTRACE_FAULTINFO: {
-		struct ptrace_faultinfo fault;
-
-		fault = ((struct ptrace_faultinfo) 
-			{ .is_write	= child->thread.err,
-			  .addr		= child->thread.cr2 });
-		ret = copy_to_user((unsigned long __user *) data, &fault,
-				   sizeof(fault));
+                /* Take the info from thread->arch->faultinfo,
+                 * but transfer max. sizeof(struct ptrace_faultinfo).
+                 * On i386, ptrace_faultinfo is smaller!
+                 */
+                ret = copy_to_user((unsigned long __user *) data,
+                                   &child->thread.arch.faultinfo,
+                                   sizeof(struct ptrace_faultinfo));
 		if(ret)
 			break;
 		break;
 	}
-	case PTRACE_SIGPENDING:
-		ret = copy_to_user((unsigned long __user *) data,
-				   &child->pending.signal,
-				   sizeof(child->pending.signal));
-		break;
 
+#ifdef PTRACE_LDT
 	case PTRACE_LDT: {
 		struct ptrace_ldt ldt;
 
@@ -281,6 +259,7 @@ long sys_ptrace(long request, long pid, 
 		ret = -EIO;
 		break;
 	}
+#endif
 #ifdef CONFIG_PROC_MM
 	case PTRACE_SWITCH_MM: {
 		struct mm_struct *old = child->mm;
@@ -336,11 +315,16 @@ void syscall_trace(union uml_pt_regs *re
 
 	if (unlikely(current->audit_context)) {
 		if (!entryexit)
-			audit_syscall_entry(current, regs->orig_eax,
-					    regs->ebx, regs->ecx,
-					    regs->edx, regs->esi);
-		else
-			audit_syscall_exit(current, regs->eax);
+			audit_syscall_entry(current,
+                                            HOST_AUDIT_ARCH,
+					    UPT_SYSCALL_NR(regs),
+					    UPT_SYSCALL_ARG1(regs),
+					    UPT_SYSCALL_ARG2(regs),
+					    UPT_SYSCALL_ARG3(regs),
+					    UPT_SYSCALL_ARG4(regs));
+		else audit_syscall_exit(current,
+                                        AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
+                                        UPT_SYSCALL_RET(regs));
 	}
 
 	/* Fake a debug trap */
@@ -370,14 +354,3 @@ void syscall_trace(union uml_pt_regs *re
 		current->exit_code = 0;
 	}
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -108,12 +108,14 @@ static void tty_output(int master, int s
 		panic("check_sigio : write failed, errno = %d\n", errno);
 	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
 
-	if(got_sigio){
+	if (got_sigio) {
 		printk("Yes\n");
 		pty_output_sigio = 1;
+	} else if (n == -EAGAIN) {
+		printk("No, enabling workaround\n");
+	} else {
+		panic("check_sigio : read failed, err = %d\n", n);
 	}
-	else if(n == -EAGAIN) printk("No, enabling workaround\n");
-	else panic("check_sigio : read failed, err = %d\n", n);
 }
 
 static void tty_close(int master, int slave)
@@ -180,6 +182,7 @@ static int write_sigio_thread(void *unus
 	int i, n, respond_fd;
 	char c;
 
+        signal(SIGWINCH, SIG_IGN);
 	fds = &current_poll;
 	while(1){
 		n = poll(fds->poll, fds->used, -1);
@@ -235,6 +238,8 @@ static int need_poll(int n)
 	return(0);
 }
 
+/* Must be called with sigio_lock held, because it's needed by the marked
+ * critical section. */
 static void update_thread(void)
 {
 	unsigned long flags;
@@ -257,7 +262,7 @@ static void update_thread(void)
 	set_signals(flags);
 	return;
  fail:
-	sigio_lock();
+	/* Critical section start */
 	if(write_sigio_pid != -1) 
 		os_kill_process(write_sigio_pid, 1);
 	write_sigio_pid = -1;
@@ -265,7 +270,7 @@ static void update_thread(void)
 	os_close_file(sigio_private[1]);
 	os_close_file(write_sigio_fds[0]);
 	os_close_file(write_sigio_fds[1]);
-	sigio_unlock();
+	/* Critical section end */
 	set_signals(flags);
 }
 
@@ -418,19 +423,10 @@ int read_sigio_fd(int fd)
 
 static void sigio_cleanup(void)
 {
-	if(write_sigio_pid != -1)
+	if (write_sigio_pid != -1) {
 		os_kill_process(write_sigio_pid, 1);
+		write_sigio_pid = -1;
+	}
 }
 
 __uml_exitcall(sigio_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -6,10 +6,8 @@
 obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
 	syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
 
-USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+subdir- := util
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+USER_OBJS := process.o time.o
 
-subdir- := util
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
--- a/arch/um/kernel/skas/include/mode_kern-skas.h
+++ b/arch/um/kernel/skas/include/mode_kern-skas.h
@@ -18,7 +18,6 @@ extern int copy_thread_skas(int nr, unsi
 			    unsigned long sp, unsigned long stack_top,
 			    struct task_struct *p, struct pt_regs *regs);
 extern void release_thread_skas(struct task_struct *task);
-extern void exit_thread_skas(void);
 extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
 extern void init_idle_skas(void);
 extern void flush_tlb_kernel_range_skas(unsigned long start,
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -22,14 +22,16 @@ extern void new_thread_proc(void *stack,
 extern void remove_sigstack(void);
 extern void new_thread_handler(int sig);
 extern void handle_syscall(union uml_pt_regs *regs);
-extern void map(int fd, unsigned long virt, unsigned long phys, 
-		unsigned long len, int r, int w, int x);
-extern int unmap(int fd, void *addr, int len);
+extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
+		int x, int phys_fd, unsigned long long offset);
+extern int unmap(int fd, void *addr, unsigned long len);
 extern int protect(int fd, unsigned long addr, unsigned long len, 
-		   int r, int w, int x, int must_succeed);
-extern void user_signal(int sig, union uml_pt_regs *regs);
+		   int r, int w, int x);
+extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
 extern int new_mm(int from);
 extern void start_userspace(int cpu);
+extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
+extern long execute_syscall_skas(void *r);
 
 #endif
 
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -19,7 +19,7 @@
 	  ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
 
 static inline int verify_area_skas(int type, const void * addr,
-				   unsigned long size)
+                                   unsigned long size)
 {
 	return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
 }
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -5,23 +5,20 @@
 
 #include <errno.h>
 #include <sys/mman.h>
-#include <sys/ptrace.h>
 #include "mem_user.h"
 #include "mem.h"
 #include "user.h"
 #include "os.h"
 #include "proc_mm.h"
 
-void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, 
-	 int r, int w, int x)
+void map(int fd, unsigned long virt, unsigned long len, int r, int w,
+	 int x, int phys_fd, unsigned long long offset)
 {
 	struct proc_mm_op map;
-	__u64 offset;
-	int prot, n, phys_fd;
+	int prot, n;
 
 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
 		(x ? PROT_EXEC : 0);
-	phys_fd = phys_mapping(phys, &offset);
 
 	map = ((struct proc_mm_op) { .op 	= MM_MMAP,
 				     .u 	= 
@@ -39,7 +36,7 @@ void map(int fd, unsigned long virt, uns
 		printk("map : /proc/mm map failed, err = %d\n", -n);
 }
 
-int unmap(int fd, void *addr, int len)
+int unmap(int fd, void *addr, unsigned long len)
 {
 	struct proc_mm_op unmap;
 	int n;
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -4,14 +4,13 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
 #include <setjmp.h>
 #include <sched.h>
 #include <sys/wait.h>
-#include <sys/ptrace.h>
-#include <linux/ptrace.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <asm/unistd.h>
@@ -29,27 +28,37 @@
 #include "chan_user.h"
 #include "signal_user.h"
 #include "registers.h"
+#include "process.h"
 
 int is_skas_winch(int pid, int fd, void *data)
 {
-	if(pid != os_getpid())
+        if(pid != os_getpgrp())
 		return(0);
 
 	register_winch_irq(-1, fd, -1, data);
 	return(1);
 }
 
-static void handle_segv(int pid)
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
 {
-	struct ptrace_faultinfo fault;
 	int err;
 
-	err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
+        err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
 	if(err)
-		panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
-		      errno);
+                panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+                      "errno = %d\n", errno);
+
+        /* Special handling for i386, which has different structs */
+        if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+                memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+                       sizeof(struct faultinfo) -
+                       sizeof(struct ptrace_faultinfo));
+}
 
-	segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
+static void handle_segv(int pid, union uml_pt_regs * regs)
+{
+        get_skas_faultinfo(pid, &regs->skas.faultinfo);
+        segv(regs->skas.faultinfo, 0, 1, NULL);
 }
 
 /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
@@ -62,7 +71,7 @@ static void handle_trap(int pid, union u
 
 	if (!local_using_sysemu)
 	{
-		err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+		err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
 		if(err < 0)
 			panic("handle_trap - nullifying syscall failed errno = %d\n",
 			      errno);
@@ -139,17 +148,20 @@ void userspace(union uml_pt_regs *regs)
 	int err, status, op, pid = userspace_pid[0];
 	int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
 
-	restore_registers(pid, regs);
-		
-	local_using_sysemu = get_using_sysemu();
+	while(1){
+		restore_registers(pid, regs);
 
-	op = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
-	err = ptrace(op, pid, 0, 0);
+		/* Now we set local_using_sysemu to be used for one loop */
+		local_using_sysemu = get_using_sysemu();
+
+		op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+
+		err = ptrace(op, pid, 0, 0);
+		if(err)
+			panic("userspace - could not resume userspace process, "
+			      "pid=%d, ptrace operation = %d, errno = %d\n",
+			      op, errno);
 
-	if(err)
-		panic("userspace - PTRACE_%s failed, errno = %d\n",
-		       local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
-	while(1){
 		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
 		if(err < 0)
 			panic("userspace - waitpid failed, errno = %d\n", 
@@ -162,7 +174,7 @@ void userspace(union uml_pt_regs *regs)
 		if(WIFSTOPPED(status)){
 		  	switch(WSTOPSIG(status)){
 			case SIGSEGV:
-				handle_segv(pid);
+                                handle_segv(pid, regs);
 				break;
 			case SIGTRAP + 0x80:
 			        handle_trap(pid, regs, local_using_sysemu);
@@ -176,7 +188,7 @@ void userspace(union uml_pt_regs *regs)
 			case SIGBUS:
 			case SIGFPE:
 			case SIGWINCH:
-				user_signal(WSTOPSIG(status), regs);
+                                user_signal(WSTOPSIG(status), regs, pid);
 				break;
 			default:
 			        printk("userspace - child stopped with signal "
@@ -187,21 +199,13 @@ void userspace(union uml_pt_regs *regs)
 			/* Avoid -ERESTARTSYS handling in host */
 			PT_SYSCALL_NR(regs->skas.regs) = -1;
 		}
-
-		restore_registers(pid, regs);
-
-		/*Now we ended the syscall, so re-read local_using_sysemu.*/
-		local_using_sysemu = get_using_sysemu();
-
-		op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
-
-		err = ptrace(op, pid, 0, 0);
-		if(err)
-			panic("userspace - PTRACE_%s failed, "
-			      "errno = %d\n",
-			      local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
 	}
 }
+#define INIT_JMP_NEW_THREAD 0
+#define INIT_JMP_REMOVE_SIGSTACK 1
+#define INIT_JMP_CALLBACK 2
+#define INIT_JMP_HALT 3
+#define INIT_JMP_REBOOT 4
 
 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
 		void (*handler)(int))
@@ -237,7 +241,7 @@ void thread_wait(void *sw, void *fb)
 	*switch_buf = &buf;
 	fork_buf = fb;
 	if(sigsetjmp(buf, 1) == 0)
-		siglongjmp(*fork_buf, 1);
+		siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
 }
 
 void switch_threads(void *me, void *next)
@@ -261,23 +265,31 @@ int start_idle_thread(void *stack, void 
 	sigjmp_buf **switch_buf = switch_buf_ptr;
 	int n;
 
+	set_handler(SIGWINCH, (__sighandler_t) sig_handler,
+		    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
+		    SIGVTALRM, -1);
+
 	*fork_buf_ptr = &initial_jmpbuf;
 	n = sigsetjmp(initial_jmpbuf, 1);
-	if(n == 0)
-		new_thread_proc((void *) stack, new_thread_handler);
-	else if(n == 1)
-		remove_sigstack();
-	else if(n == 2){
+        switch(n){
+        case INIT_JMP_NEW_THREAD:
+                new_thread_proc((void *) stack, new_thread_handler);
+                break;
+        case INIT_JMP_REMOVE_SIGSTACK:
+                remove_sigstack();
+                break;
+        case INIT_JMP_CALLBACK:
 		(*cb_proc)(cb_arg);
 		siglongjmp(*cb_back, 1);
-	}
-	else if(n == 3){
+                break;
+        case INIT_JMP_HALT:
 		kmalloc_ok = 0;
 		return(0);
-	}
-	else if(n == 4){
+        case INIT_JMP_REBOOT:
 		kmalloc_ok = 0;
 		return(1);
+        default:
+                panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
 	}
 	siglongjmp(**switch_buf, 1);
 }
@@ -302,7 +314,7 @@ void initial_thread_cb_skas(void (*proc)
 
 	block_signals();
 	if(sigsetjmp(here, 1) == 0)
-		siglongjmp(initial_jmpbuf, 2);
+		siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK);
 	unblock_signals();
 
 	cb_proc = NULL;
@@ -313,13 +325,13 @@ void initial_thread_cb_skas(void (*proc)
 void halt_skas(void)
 {
 	block_signals();
-	siglongjmp(initial_jmpbuf, 3);
+	siglongjmp(initial_jmpbuf, INIT_JMP_HALT);
 }
 
 void reboot_skas(void)
 {
 	block_signals();
-	siglongjmp(initial_jmpbuf, 4);
+	siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
 }
 
 void switch_mm_skas(int mm_fd)
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -68,8 +68,11 @@ void new_thread_handler(int sig)
 	 * 0 if it just exits
 	 */
 	n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
-	if(n == 1)
+	if(n == 1){
+		/* Handle any immediate reschedules or signals */
+		interrupt_end();
 		userspace(&current->thread.regs.regs);
+	}
 	else do_exit(0);
 }
 
@@ -83,10 +86,6 @@ void release_thread_skas(struct task_str
 {
 }
 
-void exit_thread_skas(void)
-{
-}
-
 void fork_handler(int sig)
 {
         change_sig(SIGUSR1, 1);
@@ -100,6 +99,8 @@ void fork_handler(int sig)
 	schedule_tail(current->thread.prev_sched);
 	current->thread.prev_sched = NULL;
 
+	/* Handle any immediate reschedules or signals */
+	interrupt_end();
 	userspace(&current->thread.regs.regs);
 }
 
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
--- a/arch/um/kernel/skas/syscall_user.c
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -6,25 +6,30 @@
 #include <stdlib.h>
 #include <signal.h>
 #include "kern_util.h"
+#include "uml-config.h"
 #include "syscall_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
-
+#include "skas.h"
 
 void handle_syscall(union uml_pt_regs *regs)
 {
 	long result;
-	int index;
+#if UML_CONFIG_SYSCALL_DEBUG
+  	int index;
 
-	index = record_syscall_start(UPT_SYSCALL_NR(regs));
+  	index = record_syscall_start(UPT_SYSCALL_NR(regs));
+#endif
 
 	syscall_trace(regs, 0);
-	result = execute_syscall(regs);
+	result = execute_syscall_skas(regs);
 
 	REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
 
 	syscall_trace(regs, 1);
-	record_syscall_end(index, result);
+#if UML_CONFIG_SYSCALL_DEBUG
+  	record_syscall_end(index, result);
+#endif
 }
 
 /*
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -12,215 +12,74 @@
 #include "asm/mmu.h"
 #include "user_util.h"
 #include "mem_user.h"
+#include "mem.h"
 #include "skas.h"
 #include "os.h"
+#include "tlb.h"
 
-static void fix_range(struct mm_struct *mm, unsigned long start_addr,
-		      unsigned long end_addr, int force)
+static void do_ops(int fd, struct host_vm_op *ops, int last)
 {
-	pgd_t *npgd;
-	pud_t *npud;
-	pmd_t *npmd;
-	pte_t *npte;
-	unsigned long addr,  end;
-	int r, w, x, err, fd;
-
-	if(mm == NULL) return;
-	fd = mm->context.skas.mm_fd;
-	for(addr = start_addr; addr < end_addr;){
-		npgd = pgd_offset(mm, addr);
-		if(!pgd_present(*npgd)){
-			if(force || pgd_newpage(*npgd)){
-				end = addr + PGDIR_SIZE;
-				if(end > end_addr)
-					end = end_addr;
-				err = unmap(fd, (void *) addr, end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pgd_mkuptodate(*npgd);
-			}
-			addr += PGDIR_SIZE;
-			continue;
-		}
-
-		npud = pud_offset(npgd, addr);
-		if(!pud_present(*npud)){
-			if(force || pud_newpage(*npud)){
-				end = addr + PUD_SIZE;
-				if(end > end_addr)
-					end = end_addr;
-				err = unmap(fd, (void *) addr, end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pud_mkuptodate(*npud);
-			}
-			addr += PUD_SIZE;
-			continue;
-		}
-
-		npmd = pmd_offset(npud, addr);
-		if(!pmd_present(*npmd)){
-			if(force || pmd_newpage(*npmd)){
-				end = addr + PMD_SIZE;
-				if(end > end_addr)
-					end = end_addr;
-				err = unmap(fd, (void *) addr, end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pmd_mkuptodate(*npmd);
-			}
-			addr += PMD_SIZE;
-			continue;
-		}
+	struct host_vm_op *op;
+	int i;
 
-		npte = pte_offset_kernel(npmd, addr);
-		r = pte_read(*npte);
-		w = pte_write(*npte);
-		x = pte_exec(*npte);
-		if(!pte_dirty(*npte))
-			w = 0;
-		if(!pte_young(*npte)){
-			r = 0;
-			w = 0;
-		}
-		if(force || pte_newpage(*npte)){
-			err = unmap(fd, (void *) addr, PAGE_SIZE);
-			if(err < 0)
-				panic("munmap failed, errno = %d\n", -err);
-			if(pte_present(*npte))
-				map(fd, addr, pte_val(*npte) & PAGE_MASK,
-				    PAGE_SIZE, r, w, x);
+	for(i = 0; i <= last; i++){
+		op = &ops[i];
+		switch(op->type){
+		case MMAP:
+			map(fd, op->u.mmap.addr, op->u.mmap.len,
+			    op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
+			    op->u.mmap.fd, op->u.mmap.offset);
+			break;
+		case MUNMAP:
+			unmap(fd, (void *) op->u.munmap.addr,
+			      op->u.munmap.len);
+			break;
+		case MPROTECT:
+			protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
+				op->u.mprotect.r, op->u.mprotect.w,
+				op->u.mprotect.x);
+			break;
+		default:
+			printk("Unknown op type %d in do_ops\n", op->type);
+			break;
 		}
-		else if(pte_newprot(*npte))
-			protect(fd, addr, PAGE_SIZE, r, w, x, 1);
-
-		*npte = pte_mkuptodate(*npte);
-		addr += PAGE_SIZE;
 	}
 }
 
-void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end)
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+		      unsigned long end_addr, int force)
 {
-	struct mm_struct *mm;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long addr, last;
-	int updated = 0, err;
-
-	mm = &init_mm;
-	for(addr = start; addr < end;){
-		pgd = pgd_offset(mm, addr);
-		pud = pud_offset(pgd, addr);
-		pmd = pmd_offset(pud, addr);
- 		if(!pgd_present(*pgd)){
-			if(pgd_newpage(*pgd)){
-				updated = 1;
-				last = addr + PGDIR_SIZE;
-				if(last > end)
-					last = end;
-				err = os_unmap_memory((void *) addr, 
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PGDIR_SIZE;
-			continue;
-		}
+        int fd = mm->context.skas.mm_fd;
 
-		pud = pud_offset(pgd, addr);
-		if(!pud_present(*pud)){
-			if(pud_newpage(*pud)){
-				updated = 1;
-				last = addr + PUD_SIZE;
-				if(last > end)
-					last = end;
-				err = os_unmap_memory((void *) addr,
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PUD_SIZE;
-			continue;
-		}
-
-		pmd = pmd_offset(pud, addr);
-		if(!pmd_present(*pmd)){
-			if(pmd_newpage(*pmd)){
-				updated = 1;
-				last = addr + PMD_SIZE;
-				if(last > end)
-					last = end;
-				err = os_unmap_memory((void *) addr,
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PMD_SIZE;
-			continue;
-		}
-
-		pte = pte_offset_kernel(pmd, addr);
-		if(!pte_present(*pte) || pte_newpage(*pte)){
-			updated = 1;
-			err = os_unmap_memory((void *) addr, PAGE_SIZE);
-			if(err < 0)
-				panic("munmap failed, errno = %d\n", -err);
-			if(pte_present(*pte))
-				map_memory(addr, pte_val(*pte) & PAGE_MASK,
-					   PAGE_SIZE, 1, 1, 1);
-		}
-		else if(pte_newprot(*pte)){
-			updated = 1;
-			protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
-  		}
-		addr += PAGE_SIZE;
-	}
-}
-
-void flush_tlb_kernel_vm_skas(void)
-{
-	flush_tlb_kernel_range_skas(start_vm, end_vm);
+        fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
 }
 
 void __flush_tlb_one_skas(unsigned long addr)
 {
-	flush_tlb_kernel_range_skas(addr, addr + PAGE_SIZE);
+        flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
 }
 
 void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, 
 		     unsigned long end)
 {
-	if(vma->vm_mm == NULL)
-		flush_tlb_kernel_range_skas(start, end);
-	else fix_range(vma->vm_mm, start, end, 0);
+        if(vma->vm_mm == NULL)
+                flush_tlb_kernel_range_common(start, end);
+        else fix_range(vma->vm_mm, start, end, 0);
 }
 
 void flush_tlb_mm_skas(struct mm_struct *mm)
 {
-	flush_tlb_kernel_vm_skas();
-	fix_range(mm, 0, host_task_size, 0);
+	/* Don't bother flushing if this address space is about to be
+         * destroyed.
+         */
+        if(atomic_read(&mm->mm_users) == 0)
+                return;
+
+        fix_range(mm, 0, host_task_size, 0);
+        flush_tlb_kernel_range_common(start_vm, end_vm);
 }
 
 void force_flush_all_skas(void)
 {
-	fix_range(current->mm, 0, host_task_size, 1);
+        fix_range(current->mm, 0, host_task_size, 1);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/kernel/skas/trap_user.c
@@ -5,12 +5,15 @@
 
 #include <signal.h>
 #include <errno.h>
-#include "sysdep/ptrace.h"
 #include "signal_user.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "task.h"
 #include "sigcontext.h"
+#include "skas.h"
+#include "ptrace_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/ptrace_user.h"
 
 void sig_handler_common_skas(int sig, void *sc_ptr)
 {
@@ -31,9 +34,11 @@ void sig_handler_common_skas(int sig, vo
 	r = &TASK_REGS(get_current())->skas;
 	save_user = r->is_user;
 	r->is_user = 0;
-	r->fault_addr = SC_FAULT_ADDR(sc);
-	r->fault_type = SC_FAULT_TYPE(sc);
-	r->trap_type = SC_TRAP_TYPE(sc);
+        if ( sig == SIGFPE || sig == SIGSEGV ||
+             sig == SIGBUS || sig == SIGILL ||
+             sig == SIGTRAP ) {
+                GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+        }
 
 	change_sig(SIGUSR1, 1);
 	info = &sig_info[sig];
@@ -45,14 +50,17 @@ void sig_handler_common_skas(int sig, vo
 	r->is_user = save_user;
 }
 
-void user_signal(int sig, union uml_pt_regs *regs)
+extern int ptrace_faultinfo;
+
+void user_signal(int sig, union uml_pt_regs *regs, int pid)
 {
 	struct signal_info *info;
+        int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
+                    (sig == SIGILL) || (sig == SIGTRAP));
 
 	regs->skas.is_user = 1;
-	regs->skas.fault_addr = 0;
-	regs->skas.fault_type = 0;
-	regs->skas.trap_type = 0;
+	if (segv)
+		get_skas_faultinfo(pid, &regs->skas.faultinfo);
 	info = &sig_info[sig];
 	(*info->handler)(sig, regs);
 
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -3,6 +3,7 @@
  * Licensed under the GPL
  */
 
+#include "linux/compiler.h"
 #include "linux/stddef.h"
 #include "linux/kernel.h"
 #include "linux/string.h"
@@ -28,9 +29,12 @@ static unsigned long maybe_map(unsigned 
 	if(IS_ERR(phys) || (is_write && !pte_write(pte))){
 		err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
 		if(err)
-			return(0);
+			return(-1UL);
 		phys = um_virt_to_phys(current, virt, NULL);
 	}
+        if(IS_ERR(phys))
+                phys = (void *) -1;
+
 	return((unsigned long) phys);
 }
 
@@ -41,7 +45,7 @@ static int do_op(unsigned long addr, int
 	int n;
 
 	addr = maybe_map(addr, is_write);
-	if(addr == -1)
+	if(addr == -1UL)
 		return(-1);
 
 	page = phys_to_page(addr);
diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
--- a/arch/um/kernel/skas/util/Makefile
+++ b/arch/um/kernel/skas/util/Makefile
@@ -2,3 +2,4 @@ hostprogs-y		:= mk_ptregs
 always			:= $(hostprogs-y)
 
 mk_ptregs-objs := mk_ptregs-$(SUBARCH).o
+HOSTCFLAGS_mk_ptregs-$(SUBARCH).o := -I$(objtree)/arch/um
diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c
--- a/arch/um/kernel/skas/util/mk_ptregs-i386.c
+++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c
@@ -1,8 +1,7 @@
 #include <stdio.h>
-#include <asm/ptrace.h>
-#include <asm/user.h>
+#include <user-offsets.h>
 
-#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
+#define SHOW(name) printf("#define %s %d\n", #name, name)
 
 int main(int argc, char **argv)
 {
@@ -12,28 +11,27 @@ int main(int argc, char **argv)
 	printf("#ifndef __SKAS_PT_REGS_\n");
 	printf("#define __SKAS_PT_REGS_\n");
 	printf("\n");
-	printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
-	printf("#define HOST_FP_SIZE %d\n",
-	       sizeof(struct user_i387_struct) / sizeof(unsigned long));
-	printf("#define HOST_XFP_SIZE %d\n",
-	       sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
+	SHOW(HOST_FRAME_SIZE);
+	SHOW(HOST_FP_SIZE);
+	SHOW(HOST_XFP_SIZE);
+
+	SHOW(HOST_IP);
+	SHOW(HOST_SP);
+	SHOW(HOST_EFLAGS);
+	SHOW(HOST_EAX);
+	SHOW(HOST_EBX);
+	SHOW(HOST_ECX);
+	SHOW(HOST_EDX);
+	SHOW(HOST_ESI);
+	SHOW(HOST_EDI);
+	SHOW(HOST_EBP);
+	SHOW(HOST_CS);
+	SHOW(HOST_SS);
+	SHOW(HOST_DS);
+	SHOW(HOST_FS);
+	SHOW(HOST_ES);
+	SHOW(HOST_GS);
 
-	PRINT_REG("IP", EIP);
-	PRINT_REG("SP", UESP);
-	PRINT_REG("EFLAGS", EFL);
-	PRINT_REG("EAX", EAX);
-	PRINT_REG("EBX", EBX);
-	PRINT_REG("ECX", ECX);
-	PRINT_REG("EDX", EDX);
-	PRINT_REG("ESI", ESI);
-	PRINT_REG("EDI", EDI);
-	PRINT_REG("EBP", EBP);
-	PRINT_REG("CS", CS);
-	PRINT_REG("SS", SS);
-	PRINT_REG("DS", DS);
-	PRINT_REG("FS", FS);
-	PRINT_REG("ES", ES);
-	PRINT_REG("GS", GS);
 	printf("\n");
 	printf("#endif\n");
 	return(0);
diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
--- a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
+++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
@@ -5,11 +5,10 @@
  */
 
 #include <stdio.h>
-#define __FRAME_OFFSETS
-#include <asm/ptrace.h>
+#include <user-offsets.h>
 
-#define PRINT_REG(name, val) \
-	printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val))
+#define SHOW(name) \
+	printf("#define %s (%d / sizeof(unsigned long))\n", #name, name)
 
 int main(int argc, char **argv)
 {
@@ -18,36 +17,35 @@ int main(int argc, char **argv)
 	printf("\n");
 	printf("#ifndef __SKAS_PT_REGS_\n");
 	printf("#define __SKAS_PT_REGS_\n");
-	printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n",
-	       FRAME_SIZE);
-	PRINT_REG("RBX", RBX);
-	PRINT_REG("RCX", RCX);
-	PRINT_REG("RDI", RDI);
-	PRINT_REG("RSI", RSI);
-	PRINT_REG("RDX", RDX);
-	PRINT_REG("RBP", RBP);
-	PRINT_REG("RAX", RAX);
-	PRINT_REG("R8", R8);
-	PRINT_REG("R9", R9);
-	PRINT_REG("R10", R10);
-	PRINT_REG("R11", R11);
-	PRINT_REG("R12", R12);
-	PRINT_REG("R13", R13);
-	PRINT_REG("R14", R14);
-	PRINT_REG("R15", R15);
-	PRINT_REG("ORIG_RAX", ORIG_RAX);
-	PRINT_REG("CS", CS);
-	PRINT_REG("SS", SS);
-	PRINT_REG("EFLAGS", EFLAGS);
+	SHOW(HOST_FRAME_SIZE);
+	SHOW(HOST_RBX);
+	SHOW(HOST_RCX);
+	SHOW(HOST_RDI);
+	SHOW(HOST_RSI);
+	SHOW(HOST_RDX);
+	SHOW(HOST_RBP);
+	SHOW(HOST_RAX);
+	SHOW(HOST_R8);
+	SHOW(HOST_R9);
+	SHOW(HOST_R10);
+	SHOW(HOST_R11);
+	SHOW(HOST_R12);
+	SHOW(HOST_R13);
+	SHOW(HOST_R14);
+	SHOW(HOST_R15);
+	SHOW(HOST_ORIG_RAX);
+	SHOW(HOST_CS);
+	SHOW(HOST_SS);
+	SHOW(HOST_EFLAGS);
 #if 0
-	PRINT_REG("FS", FS);
-	PRINT_REG("GS", GS);
-	PRINT_REG("DS", DS);
-	PRINT_REG("ES", ES);
+	SHOW(HOST_FS);
+	SHOW(HOST_GS);
+	SHOW(HOST_DS);
+	SHOW(HOST_ES);
 #endif
 
-	PRINT_REG("IP", RIP);
-	PRINT_REG("SP", RSP);
+	SHOW(HOST_IP);
+	SHOW(HOST_SP);
 	printf("#define HOST_FP_SIZE 0\n");
 	printf("#define HOST_XFP_SIZE 0\n");
 	printf("\n");
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -41,15 +41,9 @@ EXPORT_SYMBOL(cpu_possible_map);
  */
 struct cpuinfo_um cpu_data[NR_CPUS];
 
-/* Set when the idlers are all forked */
-int smp_threads_ready = 0;
-
 /* A statistic, can be a little off */
 int num_reschedules_sent = 0;
 
-/* Small, random number, never changed */
-unsigned long cache_decay_ticks = 5;
-
 /* Not changed after boot */
 struct task_struct *idle_threads[NR_CPUS];
 
diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
deleted file mode 100644
--- a/arch/um/kernel/sys_call_table.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Copyright 2003 PathScale, Inc.
- * Licensed under the GPL
- */
-
-#include "linux/config.h"
-#include "linux/unistd.h"
-#include "linux/sys.h"
-#include "linux/swap.h"
-#include "linux/syscalls.h"
-#include "linux/sysctl.h"
-#include "asm/signal.h"
-#include "sysdep/syscalls.h"
-#include "kern_util.h"
-
-#ifdef CONFIG_NFSD
-#define NFSSERVCTL sys_nfsservctl
-#else
-#define NFSSERVCTL sys_ni_syscall
-#endif
-
-#define LAST_GENERIC_SYSCALL __NR_keyctl
-
-#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
-#define LAST_SYSCALL LAST_GENERIC_SYSCALL
-#else
-#define LAST_SYSCALL LAST_ARCH_SYSCALL
-#endif
-
-extern syscall_handler_t sys_fork;
-extern syscall_handler_t sys_execve;
-extern syscall_handler_t um_time;
-extern syscall_handler_t um_mount;
-extern syscall_handler_t um_stime;
-extern syscall_handler_t sys_pipe;
-extern syscall_handler_t sys_olduname;
-extern syscall_handler_t sys_sigaction;
-extern syscall_handler_t sys_sigsuspend;
-extern syscall_handler_t old_readdir;
-extern syscall_handler_t sys_uname;
-extern syscall_handler_t sys_ipc;
-extern syscall_handler_t sys_sigreturn;
-extern syscall_handler_t sys_clone;
-extern syscall_handler_t sys_rt_sigreturn;
-extern syscall_handler_t sys_sigaltstack;
-extern syscall_handler_t sys_vfork;
-extern syscall_handler_t old_select;
-extern syscall_handler_t sys_modify_ldt;
-extern syscall_handler_t sys_rt_sigsuspend;
-extern syscall_handler_t sys_vserver;
-extern syscall_handler_t sys_mbind;
-extern syscall_handler_t sys_get_mempolicy;
-extern syscall_handler_t sys_set_mempolicy;
-extern syscall_handler_t sys_sys_setaltroot;
-
-syscall_handler_t *sys_call_table[] = {
-	[ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
-	[ __NR_exit ] = (syscall_handler_t *) sys_exit,
-	[ __NR_fork ] = (syscall_handler_t *) sys_fork,
-	[ __NR_read ] = (syscall_handler_t *) sys_read,
-	[ __NR_write ] = (syscall_handler_t *) sys_write,
-
-	/* These three are declared differently in asm/unistd.h */
-	[ __NR_open ] = (syscall_handler_t *) sys_open,
-	[ __NR_close ] = (syscall_handler_t *) sys_close,
-	[ __NR_creat ] = (syscall_handler_t *) sys_creat,
-	[ __NR_link ] = (syscall_handler_t *) sys_link,
-	[ __NR_unlink ] = (syscall_handler_t *) sys_unlink,
-	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
-
-	/* declared differently in kern_util.h */
-	[ __NR_chdir ] = (syscall_handler_t *) sys_chdir,
-	[ __NR_time ] = um_time,
-	[ __NR_mknod ] = (syscall_handler_t *) sys_mknod,
-	[ __NR_chmod ] = (syscall_handler_t *) sys_chmod,
-	[ __NR_lchown ] = (syscall_handler_t *) sys_lchown16,
-	[ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
-	[ __NR_getpid ] = (syscall_handler_t *) sys_getpid,
-	[ __NR_mount ] = um_mount,
-	[ __NR_setuid ] = (syscall_handler_t *) sys_setuid16,
-	[ __NR_getuid ] = (syscall_handler_t *) sys_getuid16,
- 	[ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace,
-	[ __NR_alarm ] = (syscall_handler_t *) sys_alarm,
-	[ __NR_pause ] = (syscall_handler_t *) sys_pause,
-	[ __NR_utime ] = (syscall_handler_t *) sys_utime,
-	[ __NR_access ] = (syscall_handler_t *) sys_access,
-	[ __NR_sync ] = (syscall_handler_t *) sys_sync,
-	[ __NR_kill ] = (syscall_handler_t *) sys_kill,
-	[ __NR_rename ] = (syscall_handler_t *) sys_rename,
-	[ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir,
-	[ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir,
-
-	/* Declared differently in asm/unistd.h */
-	[ __NR_dup ] = (syscall_handler_t *) sys_dup,
-	[ __NR_pipe ] = (syscall_handler_t *) sys_pipe,
-	[ __NR_times ] = (syscall_handler_t *) sys_times,
-	[ __NR_brk ] = (syscall_handler_t *) sys_brk,
-	[ __NR_setgid ] = (syscall_handler_t *) sys_setgid16,
-	[ __NR_getgid ] = (syscall_handler_t *) sys_getgid16,
-	[ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16,
-	[ __NR_getegid ] = (syscall_handler_t *) sys_getegid16,
-	[ __NR_acct ] = (syscall_handler_t *) sys_acct,
-	[ __NR_umount2 ] = (syscall_handler_t *) sys_umount,
-	[ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl,
-	[ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl,
-	[ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid,
-	[ __NR_umask ] = (syscall_handler_t *) sys_umask,
-	[ __NR_chroot ] = (syscall_handler_t *) sys_chroot,
-	[ __NR_ustat ] = (syscall_handler_t *) sys_ustat,
-	[ __NR_dup2 ] = (syscall_handler_t *) sys_dup2,
-	[ __NR_getppid ] = (syscall_handler_t *) sys_getppid,
-	[ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp,
-	[ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
-	[ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16,
-	[ __NR_setregid ] = (syscall_handler_t *) sys_setregid16,
-	[ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname,
-	[ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit,
-	[ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit,
-	[ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage,
-	[ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday,
-	[ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday,
-	[ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16,
-	[ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16,
-	[ __NR_symlink ] = (syscall_handler_t *) sys_symlink,
-	[ __NR_readlink ] = (syscall_handler_t *) sys_readlink,
-	[ __NR_uselib ] = (syscall_handler_t *) sys_uselib,
-	[ __NR_swapon ] = (syscall_handler_t *) sys_swapon,
-	[ __NR_reboot ] = (syscall_handler_t *) sys_reboot,
-	[ __NR_munmap ] = (syscall_handler_t *) sys_munmap,
-	[ __NR_truncate ] = (syscall_handler_t *) sys_truncate,
-	[ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate,
-	[ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod,
-	[ __NR_fchown ] = (syscall_handler_t *) sys_fchown16,
-	[ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority,
-	[ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority,
-	[ __NR_statfs ] = (syscall_handler_t *) sys_statfs,
-	[ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs,
-	[ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_syslog ] = (syscall_handler_t *) sys_syslog,
-	[ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer,
-	[ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer,
-	[ __NR_stat ] = (syscall_handler_t *) sys_newstat,
-	[ __NR_lstat ] = (syscall_handler_t *) sys_newlstat,
-	[ __NR_fstat ] = (syscall_handler_t *) sys_newfstat,
-	[ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup,
-	[ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
-	[ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff,
-	[ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo,
-	[ __NR_fsync ] = (syscall_handler_t *) sys_fsync,
-	[ __NR_clone ] = (syscall_handler_t *) sys_clone,
-	[ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname,
-	[ __NR_uname ] = (syscall_handler_t *) sys_newuname,
-	[ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex,
-	[ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect,
-	[ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_init_module ] = (syscall_handler_t *) sys_init_module,
-	[ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module,
-	[ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl,
-	[ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid,
-	[ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir,
-	[ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs,
-	[ __NR_personality ] = (syscall_handler_t *) sys_personality,
-	[ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16,
-	[ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16,
-	[ __NR_getdents ] = (syscall_handler_t *) sys_getdents,
-	[ __NR_flock ] = (syscall_handler_t *) sys_flock,
-	[ __NR_msync ] = (syscall_handler_t *) sys_msync,
-	[ __NR_readv ] = (syscall_handler_t *) sys_readv,
-	[ __NR_writev ] = (syscall_handler_t *) sys_writev,
-	[ __NR_getsid ] = (syscall_handler_t *) sys_getsid,
-	[ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync,
-	[ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl,
-	[ __NR_mlock ] = (syscall_handler_t *) sys_mlock,
-	[ __NR_munlock ] = (syscall_handler_t *) sys_munlock,
-	[ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall,
-	[ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall,
-	[ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam,
-	[ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam,
-	[ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler,
-	[ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler,
-	[ __NR_sched_yield ] = (syscall_handler_t *) yield,
-	[ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max,
-	[ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min,
-	[ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval,
-	[ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep,
-	[ __NR_mremap ] = (syscall_handler_t *) sys_mremap,
-	[ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16,
-	[ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16,
-	[ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_poll ] = (syscall_handler_t *) sys_poll,
-	[ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL,
-	[ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16,
-	[ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16,
-	[ __NR_prctl ] = (syscall_handler_t *) sys_prctl,
-	[ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn,
-	[ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction,
-	[ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask,
-	[ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending,
-	[ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait,
-	[ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo,
-	[ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend,
-	[ __NR_pread64 ] = (syscall_handler_t *) sys_pread64,
-	[ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64,
-	[ __NR_chown ] = (syscall_handler_t *) sys_chown16,
-	[ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd,
-	[ __NR_capget ] = (syscall_handler_t *) sys_capget,
-	[ __NR_capset ] = (syscall_handler_t *) sys_capset,
-	[ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack,
-	[ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile,
-	[ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_vfork ] = (syscall_handler_t *) sys_vfork,
-	[ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64,
-	[ __NR_gettid ] = (syscall_handler_t *) sys_gettid,
-	[ __NR_readahead ] = (syscall_handler_t *) sys_readahead,
-	[ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr,
-	[ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr,
-	[ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr,
-	[ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr,
-	[ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr,
-	[ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr,
-	[ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr,
-	[ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr,
-	[ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr,
-	[ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr,
-	[ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr,
-	[ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr,
-	[ __NR_tkill ] = (syscall_handler_t *) sys_tkill,
-	[ __NR_futex ] = (syscall_handler_t *) sys_futex,
-	[ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity,
-	[ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity,
-	[ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup,
-	[ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy,
-	[ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents,
-	[ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit,
-	[ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel,
-	[ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group,
-	[ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie,
-	[ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create,
-	[ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl,
-	[ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait,
-        [ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address,
-	[ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create,
-	[ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime,
-	[ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime,
-	[ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun,
-	[ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete,
-	[ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime,
-	[ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime,
-	[ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres,
-	[ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep,
-	[ __NR_statfs64 ] = (syscall_handler_t *) sys_statfs64,
-	[ __NR_fstatfs64 ] = (syscall_handler_t *) sys_fstatfs64,
-	[ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill,
-	[ __NR_utimes ] = (syscall_handler_t *) sys_utimes,
-	[ __NR_fadvise64_64 ] = (syscall_handler_t *) sys_fadvise64_64,
-	[ __NR_vserver ] = (syscall_handler_t *) sys_vserver,
-	[ __NR_mbind ] = (syscall_handler_t *) sys_mbind,
-	[ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy,
-	[ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy,
-	[ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open,
-	[ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink,
-	[ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend,
-	[ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive,
-	[ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify,
-	[ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr,
-	[ __NR_sys_kexec_load ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_waitid ] = (syscall_handler_t *) sys_waitid,
-	[ 285 ] = (syscall_handler_t *) sys_ni_syscall,
-	[ __NR_add_key ] = (syscall_handler_t *) sys_add_key,
-	[ __NR_request_key ] = (syscall_handler_t *) sys_request_key,
-	[ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl,
-
-	ARCH_SYSCALLS
-	[ LAST_SYSCALL + 1 ... NR_syscalls ] = 
-	        (syscall_handler_t *) sys_ni_syscall
-};
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -17,7 +17,6 @@
 #include "linux/utime.h"
 #include "asm/mman.h"
 #include "asm/uaccess.h"
-#include "asm/ipc.h"
 #include "kern_util.h"
 #include "user_util.h"
 #include "sysdep/syscalls.h"
@@ -27,12 +26,6 @@
 /*  Unlocked, I don't care if this is a bit off */
 int nsyscalls = 0;
 
-long um_mount(char __user * dev_name, char __user * dir_name,
-	      char __user * type, unsigned long new_flags, void __user * data)
-{
-	return(sys_mount(dev_name, dir_name, type, new_flags, data));
-}
-
 long sys_fork(void)
 {
 	long ret;
@@ -154,11 +147,6 @@ long sys_olduname(struct oldold_utsname 
 	return error;
 }
 
-long execute_syscall(void *r)
-{
-	return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
-}
-
 DEFINE_SPINLOCK(syscall_lock);
 
 static int syscall_index = 0;
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -3,6 +3,7 @@
  * Licensed under the GPL
  */
 
+#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/kernel.h"
 #include "linux/module.h"
@@ -12,14 +13,14 @@
 #include "sysrq.h"
 #include "user_util.h"
 
-void show_trace(unsigned long * stack)
+/* Catch non-i386 SUBARCH's. */
+#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
+void show_trace(struct task_struct *task, unsigned long * stack)
 {
-	/* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from
-	 * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/
         unsigned long addr;
 
         if (!stack) {
-                stack = (unsigned long*) &stack;
+		stack = (unsigned long*) &stack;
 		WARN_ON(1);
 	}
 
@@ -35,6 +36,7 @@ void show_trace(unsigned long * stack)
         }
         printk("\n");
 }
+#endif
 
 /*
  * stack dumps generator - this is used by arch-independent code.
@@ -44,7 +46,7 @@ void dump_stack(void)
 {
 	unsigned long stack;
 
-	show_trace(&stack);
+	show_trace(current, &stack);
 }
 EXPORT_SYMBOL(dump_stack);
 
@@ -59,7 +61,11 @@ void show_stack(struct task_struct *task
 	int i;
 
 	if (esp == NULL) {
-		if (task != current) {
+		if (task != current && task != NULL) {
+			/* XXX: Isn't this bogus? I.e. isn't this the
+			 * *userspace* stack of this task? If not so, use this
+			 * even when task == current (as in i386).
+			 */
 			esp = (unsigned long *) KSTK_ESP(task);
 			/* Which one? No actual difference - just coding style.*/
 			//esp = (unsigned long *) PT_REGS_IP(&task->thread.regs);
@@ -77,5 +83,6 @@ void show_stack(struct task_struct *task
 		printk("%08lx ", *stack++);
 	}
 
-	show_trace(esp);
+	printk("Call Trace: \n");
+	show_trace(current, esp);
 }
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -48,8 +48,6 @@ static unsigned long long prev_usecs;
 static long long delta;   		/* Deviation per interval */
 #endif
 
-#define MILLION 1000000
-
 void timer_irq(union uml_pt_regs *regs)
 {
 	unsigned long long ticks = 0;
@@ -136,22 +134,6 @@ long um_stime(int __user *tptr)
 	return 0;
 }
 
-void __udelay(unsigned long usecs)
-{
-	int i, n;
-
-	n = (loops_per_jiffy * HZ * usecs) / MILLION;
-	for(i=0;i<n;i++) ;
-}
-
-void __const_udelay(unsigned long usecs)
-{
-	int i, n;
-
-	n = (loops_per_jiffy * HZ * usecs) / MILLION;
-	for(i=0;i<n;i++) ;
-}
-
 void timer_handler(int sig, union uml_pt_regs *regs)
 {
 	local_irq_disable();
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -9,87 +9,361 @@
 #include "asm/tlbflush.h"
 #include "choose-mode.h"
 #include "mode_kern.h"
+#include "user_util.h"
+#include "tlb.h"
+#include "mem.h"
+#include "mem_user.h"
+#include "os.h"
+
+#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
+
+void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
+                      unsigned long end_addr, int force, int data,
+                      void (*do_ops)(int, struct host_vm_op *, int))
+{
+        pgd_t *npgd;
+        pud_t *npud;
+        pmd_t *npmd;
+        pte_t *npte;
+        unsigned long addr, end;
+        int r, w, x;
+        struct host_vm_op ops[16];
+        int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
+
+        if(mm == NULL) return;
+
+        for(addr = start_addr; addr < end_addr;){
+                npgd = pgd_offset(mm, addr);
+                if(!pgd_present(*npgd)){
+                        end = ADD_ROUND(addr, PGDIR_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pgd_newpage(*npgd)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pgd_mkuptodate(*npgd);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npud = pud_offset(npgd, addr);
+                if(!pud_present(*npud)){
+                        end = ADD_ROUND(addr, PUD_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pud_newpage(*npud)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pud_mkuptodate(*npud);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npmd = pmd_offset(npud, addr);
+                if(!pmd_present(*npmd)){
+                        end = ADD_ROUND(addr, PMD_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pmd_newpage(*npmd)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pmd_mkuptodate(*npmd);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npte = pte_offset_kernel(npmd, addr);
+                r = pte_read(*npte);
+                w = pte_write(*npte);
+                x = pte_exec(*npte);
+                if(!pte_dirty(*npte))
+                        w = 0;
+                if(!pte_young(*npte)){
+                        r = 0;
+                        w = 0;
+                }
+                if(force || pte_newpage(*npte)){
+                        if(pte_present(*npte))
+                                op_index = add_mmap(addr,
+                                                    pte_val(*npte) & PAGE_MASK,
+                                                    PAGE_SIZE, r, w, x, ops,
+                                                    op_index, last_op, data,
+                                                    do_ops);
+                        else op_index = add_munmap(addr, PAGE_SIZE, ops,
+                                                   op_index, last_op, data,
+                                                   do_ops);
+                }
+                else if(pte_newprot(*npte))
+                        op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
+                                                op_index, last_op, data,
+                                                do_ops);
+
+                *npte = pte_mkuptodate(*npte);
+                addr += PAGE_SIZE;
+        }
+        (*do_ops)(data, ops, op_index);
+}
+
+int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
+{
+        struct mm_struct *mm;
+        pgd_t *pgd;
+        pud_t *pud;
+        pmd_t *pmd;
+        pte_t *pte;
+        unsigned long addr, last;
+        int updated = 0, err;
+
+        mm = &init_mm;
+        for(addr = start; addr < end;){
+                pgd = pgd_offset(mm, addr);
+                if(!pgd_present(*pgd)){
+                        last = ADD_ROUND(addr, PGDIR_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pgd_newpage(*pgd)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pud = pud_offset(pgd, addr);
+                if(!pud_present(*pud)){
+                        last = ADD_ROUND(addr, PUD_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pud_newpage(*pud)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pmd = pmd_offset(pud, addr);
+                if(!pmd_present(*pmd)){
+                        last = ADD_ROUND(addr, PMD_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pmd_newpage(*pmd)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pte = pte_offset_kernel(pmd, addr);
+                if(!pte_present(*pte) || pte_newpage(*pte)){
+                        updated = 1;
+                        err = os_unmap_memory((void *) addr,
+                                              PAGE_SIZE);
+                        if(err < 0)
+                                panic("munmap failed, errno = %d\n",
+                                      -err);
+                        if(pte_present(*pte))
+                                map_memory(addr,
+                                           pte_val(*pte) & PAGE_MASK,
+                                           PAGE_SIZE, 1, 1, 1);
+                }
+                else if(pte_newprot(*pte)){
+                        updated = 1;
+                        protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
+                }
+                addr += PAGE_SIZE;
+        }
+        return(updated);
+}
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
 {
-	address &= PAGE_MASK;
-	flush_tlb_range(vma, address, address + PAGE_SIZE);
+        address &= PAGE_MASK;
+        flush_tlb_range(vma, address, address + PAGE_SIZE);
 }
 
 void flush_tlb_all(void)
 {
-	flush_tlb_mm(current->mm);
+        flush_tlb_mm(current->mm);
 }
   
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
-	CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, 
-			 flush_tlb_kernel_range_skas, start, end);
+        CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+                         flush_tlb_kernel_range_common, start, end);
 }
 
 void flush_tlb_kernel_vm(void)
 {
-	CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas());
+        CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+                    flush_tlb_kernel_range_common(start_vm, end_vm));
 }
 
 void __flush_tlb_one(unsigned long addr)
 {
-	CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+        CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
 }
 
 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
-		     unsigned long end)
+     unsigned long end)
 {
-	CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, 
-			 end);
+        CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+                         end);
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
 {
-	CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+        CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
 }
 
 void force_flush_all(void)
 {
-	CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+        CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
 }
 
 pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
 {
-	return(pgd_offset(mm, address));
+        return(pgd_offset(mm, address));
 }
 
 pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
 {
-	return(pud_offset(pgd, address));
+        return(pud_offset(pgd, address));
 }
 
 pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
 {
-	return(pmd_offset(pud, address));
+        return(pmd_offset(pud, address));
 }
 
 pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
 {
-	return(pte_offset_kernel(pmd, address));
+        return(pte_offset_kernel(pmd, address));
 }
 
 pte_t *addr_pte(struct task_struct *task, unsigned long addr)
 {
-	pgd_t *pgd = pgd_offset(task->mm, addr);
-	pud_t *pud = pud_offset(pgd, addr);
-	pmd_t *pmd = pmd_offset(pud, addr);
-
-	return(pte_offset_map(pmd, addr));
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+        pgd_t *pgd = pgd_offset(task->mm, addr);
+        pud_t *pud = pud_offset(pgd, addr);
+        pmd_t *pmd = pmd_offset(pud, addr);
+
+        return(pte_offset_map(pmd, addr));
+}
+
+int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
+     int r, int w, int x, struct host_vm_op *ops, int index,
+     int last_filled, int data,
+     void (*do_ops)(int, struct host_vm_op *, int))
+{
+        __u64 offset;
+	struct host_vm_op *last;
+	int fd;
+
+	fd = phys_mapping(phys, &offset);
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MMAP) &&
+		   (last->u.mmap.addr + last->u.mmap.len == virt) &&
+		   (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
+		   (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+		   (last->u.mmap.offset + last->u.mmap.len == offset)){
+			last->u.mmap.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MMAP,
+					      .u = { .mmap = {
+						      .addr	= virt,
+						      .len	= len,
+						      .r	= r,
+						      .w	= w,
+						      .x	= x,
+						      .fd	= fd,
+						      .offset	= offset }
+					      } });
+	return(index);
+}
+
+int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
+	       int index, int last_filled, int data,
+	       void (*do_ops)(int, struct host_vm_op *, int))
+{
+	struct host_vm_op *last;
+
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MUNMAP) &&
+		   (last->u.munmap.addr + last->u.mmap.len == addr)){
+			last->u.munmap.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MUNMAP,
+					      .u = { .munmap = {
+						      .addr	= addr,
+						      .len	= len } } });
+	return(index);
+}
+
+int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
+		 struct host_vm_op *ops, int index, int last_filled, int data,
+		 void (*do_ops)(int, struct host_vm_op *, int))
+{
+	struct host_vm_op *last;
+
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MPROTECT) &&
+		   (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
+		   (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
+		   (last->u.mprotect.x == x)){
+			last->u.mprotect.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MPROTECT,
+					      .u = { .mprotect = {
+						      .addr	= addr,
+						      .len	= len,
+						      .r	= r,
+						      .w	= w,
+						      .x	= x } } });
+	return(index);
+}
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -23,7 +23,6 @@
 #include "kern.h"
 #include "chan_kern.h"
 #include "mconsole_kern.h"
-#include "2_5compat.h"
 #include "mem.h"
 #include "mem_kern.h"
 
@@ -48,7 +47,7 @@ int handle_page_fault(unsigned long addr
 		goto good_area;
 	else if(!(vma->vm_flags & VM_GROWSDOWN)) 
 		goto out;
-	else if(!ARCH_IS_STACKGROW(address))
+	else if(is_user && !ARCH_IS_STACKGROW(address))
 		goto out;
 	else if(expand_stack(vma, address)) 
 		goto out;
@@ -57,10 +56,11 @@ int handle_page_fault(unsigned long addr
 	*code_out = SEGV_ACCERR;
 	if(is_write && !(vma->vm_flags & VM_WRITE)) 
 		goto out;
+
+        if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                goto out;
+
 	page = address & PAGE_MASK;
-	pgd = pgd_offset(mm, page);
-	pud = pud_offset(pgd, page);
-	pmd = pmd_offset(pud, page);
 	do {
  survive:
 		switch (handle_mm_fault(mm, vma, address, is_write)){
@@ -106,46 +106,24 @@ out_of_memory:
 	goto out;
 }
 
-LIST_HEAD(physmem_remappers);
-
-void register_remapper(struct remapper *info)
-{
-	list_add(&info->list, &physmem_remappers);
-}
-
-static int check_remapped_addr(unsigned long address, int is_write)
-{
-	struct remapper *remapper;
-	struct list_head *ele;
-	__u64 offset;
-	int fd;
-
-	fd = phys_mapping(__pa(address), &offset);
-	if(fd == -1)
-		return(0);
-
-	list_for_each(ele, &physmem_remappers){
-		remapper = list_entry(ele, struct remapper, list);
-		if((*remapper->proc)(fd, address, is_write, offset))
-			return(1);
-	}
-
-	return(0);
-}
-
-unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
-		   int is_user, void *sc)
+/*
+ * We give a *copy* of the faultinfo in the regs to segv.
+ * This must be done, since nesting SEGVs could overwrite
+ * the info in the regs. A pointer to the info then would
+ * give us bad data!
+ */
+unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
 {
 	struct siginfo si;
 	void *catcher;
 	int err;
+        int is_write = FAULT_WRITE(fi);
+        unsigned long address = FAULT_ADDRESS(fi);
 
         if(!is_user && (address >= start_vm) && (address < end_vm)){
                 flush_tlb_kernel_vm();
                 return(0);
         }
-	else if(check_remapped_addr(address & PAGE_MASK, is_write))
-		return(0);
 	else if(current->mm == NULL)
 		panic("Segfault with no mm");
 	err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -159,7 +137,7 @@ unsigned long segv(unsigned long address
 	} 
 	else if(current->thread.fault_addr != NULL)
 		panic("fault_addr set but no fault catcher");
-	else if(arch_fixup(ip, sc))
+        else if(!is_user && arch_fixup(ip, sc))
 		return(0);
 
  	if(!is_user) 
@@ -171,6 +149,7 @@ unsigned long segv(unsigned long address
 		si.si_errno = 0;
 		si.si_code = BUS_ADRERR;
 		si.si_addr = (void *)address;
+                current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGBUS, &si, current);
 	}
 	else if(err == -ENOMEM){
@@ -180,22 +159,20 @@ unsigned long segv(unsigned long address
 	else {
 		si.si_signo = SIGSEGV;
 		si.si_addr = (void *) address;
-		current->thread.cr2 = address;
-		current->thread.err = is_write;
+                current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGSEGV, &si, current);
 	}
 	return(0);
 }
 
-void bad_segv(unsigned long address, unsigned long ip, int is_write)
+void bad_segv(struct faultinfo fi, unsigned long ip)
 {
 	struct siginfo si;
 
 	si.si_signo = SIGSEGV;
 	si.si_code = SEGV_ACCERR;
-	si.si_addr = (void *) address;
-	current->thread.cr2 = address;
-	current->thread.err = is_write;
+        si.si_addr = (void *) FAULT_ADDRESS(fi);
+        current->thread.arch.faultinfo = fi;
 	force_sig_info(SIGSEGV, &si, current);
 }
 
@@ -204,6 +181,7 @@ void relay_signal(int sig, union uml_pt_
 	if(arch_handle_signal(sig, regs)) return;
 	if(!UPT_IS_USER(regs))
 		panic("Kernel mode signal %d", sig);
+        current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
 	force_sig(sig, current);
 }
 
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
--- a/arch/um/kernel/trap_user.c
+++ b/arch/um/kernel/trap_user.c
@@ -8,7 +8,6 @@
 #include <setjmp.h>
 #include <signal.h>
 #include <sys/time.h>
-#include <sys/ptrace.h>
 #include <sys/wait.h>
 #include <asm/page.h>
 #include <asm/unistd.h>
@@ -55,23 +54,22 @@ struct {
 void segv_handler(int sig, union uml_pt_regs *regs)
 {
 	int index, max;
+        struct faultinfo * fi = UPT_FAULTINFO(regs);
 
-	if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){
-		bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), 
-			 UPT_FAULT_WRITE(regs));
+        if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
+                bad_segv(*fi, UPT_IP(regs));
 		return;
 	}
 	max = sizeof(segfault_record)/sizeof(segfault_record[0]);
 	index = next_trap_index(max);
 
 	nsegfaults++;
-	segfault_record[index].address = UPT_FAULT_ADDR(regs);
+        segfault_record[index].address = FAULT_ADDRESS(*fi);
 	segfault_record[index].pid = os_getpid();
-	segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
+        segfault_record[index].is_write = FAULT_WRITE(*fi);
 	segfault_record[index].sp = UPT_SP(regs);
 	segfault_record[index].is_user = UPT_IS_USER(regs);
-	segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
-	     UPT_IS_USER(regs), regs);
+        segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
 }
 
 void usr2_handler(int sig, union uml_pt_regs *regs)
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
--- a/arch/um/kernel/tt/Makefile
+++ b/arch/um/kernel/tt/Makefile
@@ -4,6 +4,7 @@
 #
 
 extra-y := unmap_fin.o
+targets := unmap.o
 clean-files := unmap_tmp.o
 
 obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
@@ -12,21 +13,17 @@ obj-y = exec_kern.o exec_user.o gdb.o ks
 
 obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
 
-USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+USER_OBJS := gdb.o time.o tracer.o
+
+include arch/um/scripts/Makefile.rules
 
 UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
 UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-$(obj)/unmap.o: $(src)/unmap.c
-	$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
-
-LIBC_DIR ?= /usr/lib
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
 
 $(obj)/unmap_fin.o : $(obj)/unmap.o
-	ld -r -o $(obj)/unmap_tmp.o  $< -lc -L$(LIBC_DIR)
-	objcopy $(obj)/unmap_tmp.o $@ -G switcheroo
+	$(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
+	$(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
 
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
--- a/arch/um/kernel/tt/exec_user.c
+++ b/arch/um/kernel/tt/exec_user.c
@@ -9,8 +9,6 @@
 #include <sched.h>
 #include <errno.h>
 #include <sys/wait.h>
-#include <sys/ptrace.h>
-#include <linux/ptrace.h>
 #include <signal.h>
 #include "user_util.h"
 #include "kern_util.h"
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -8,8 +8,8 @@
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
-#include <sys/ptrace.h>
 #include <sys/types.h>
+#include "ptrace_user.h"
 #include "uml-config.h"
 #include "kern_constants.h"
 #include "chan_user.h"
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
--- a/arch/um/kernel/tt/include/mode_kern-tt.h
+++ b/arch/um/kernel/tt/include/mode_kern-tt.h
@@ -19,7 +19,6 @@ extern int copy_thread_tt(int nr, unsign
 			  unsigned long stack_top, struct task_struct *p,
 			  struct pt_regs *regs);
 extern void release_thread_tt(struct task_struct *task);
-extern void exit_thread_tt(void);
 extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
 extern void init_idle_tt(void);
 extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
--- a/arch/um/kernel/tt/include/tt.h
+++ b/arch/um/kernel/tt/include/tt.h
@@ -30,6 +30,7 @@ extern void do_syscall(void *task, int p
 extern void do_sigtrap(void *task);
 extern int is_valid_pid(int pid);
 extern void remap_data(void *segment_start, void *segment_end, int w);
+extern long execute_syscall_tt(void *r);
 
 #endif
 
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -34,7 +34,7 @@ extern unsigned long uml_physmem;
           (under_task_size(addr, size) || is_stack(addr, size))))
 
 static inline int verify_area_tt(int type, const void * addr,
-				 unsigned long size)
+                                 unsigned long size)
 {
 	return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
 }
diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
--- a/arch/um/kernel/tt/ksyms.c
+++ b/arch/um/kernel/tt/ksyms.c
@@ -12,6 +12,7 @@ EXPORT_SYMBOL(__do_copy_to_user);
 EXPORT_SYMBOL(__do_strncpy_from_user);
 EXPORT_SYMBOL(__do_strnlen_user); 
 EXPORT_SYMBOL(__do_clear_user);
+EXPORT_SYMBOL(clear_user_tt);
 
 EXPORT_SYMBOL(tracing_pid);
 EXPORT_SYMBOL(honeypot);
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -15,20 +15,14 @@
 
 void before_mem_tt(unsigned long brk_start)
 {
-	if(!jail || debug)
+	if(debug)
 		remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
 	remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
 	remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
 }
 
-#ifdef CONFIG_HOST_2G_2G
-#define TOP 0x80000000
-#else
-#define TOP 0xc0000000
-#endif
-
 #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
-#define START (TOP - SIZE)
+#define START (CONFIG_TOP_ADDR - SIZE)
 
 unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, 
 				unsigned long *task_size_out)
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -32,10 +32,6 @@ void *switch_to_tt(void *prev, void *nex
 	unsigned long flags;
 	int err, vtalrm, alrm, prof, cpu;
 	char c;
-	/* jailing and SMP are incompatible, so this doesn't need to be 
-	 * made per-cpu 
-	 */
-	static int reading;
 
 	from = prev;
 	to = next;
@@ -59,14 +55,11 @@ void *switch_to_tt(void *prev, void *nex
 	c = 0;
 	set_current(to);
 
-	reading = 0;
 	err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
 	if(err != sizeof(c))
 		panic("write of switch_pipe failed, err = %d", -err);
 
-	reading = 1;
-	if((from->exit_state == EXIT_ZOMBIE) ||
-	   (from->exit_state == EXIT_DEAD))
+	if(from->thread.mode.tt.switch_pipe[0] == -1)
 		os_kill_process(os_getpid(), 0);
 
 	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
@@ -81,28 +74,9 @@ void *switch_to_tt(void *prev, void *nex
 	 * in case it has not already killed itself.
 	 */
 	prev_sched = current->thread.prev_sched;
-	if((prev_sched->exit_state == EXIT_ZOMBIE) ||
-	   (prev_sched->exit_state == EXIT_DEAD))
+        if(prev_sched->thread.mode.tt.switch_pipe[0] == -1)
 		os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
 
-	/* This works around a nasty race with 'jail'.  If we are switching
-	 * between two threads of a threaded app and the incoming process 
-	 * runs before the outgoing process reaches the read, and it makes
-	 * it all the way out to userspace, then it will have write-protected 
-	 * the outgoing process stack.  Then, when the outgoing process 
-	 * returns from the write, it will segfault because it can no longer
-	 * write its own stack.  So, in order to avoid that, the incoming 
-	 * thread sits in a loop yielding until 'reading' is set.  This 
-	 * isn't entirely safe, since there may be a reschedule from a timer
-	 * happening between setting 'reading' and sleeping in read.  But,
-	 * it should get a whole quantum in which to reach the read and sleep,
-	 * which should be enough.
-	 */
-
-	if(jail){
-		while(!reading) sched_yield();
-	}
-
 	change_sig(SIGVTALRM, vtalrm);
 	change_sig(SIGALRM, alrm);
 	change_sig(SIGPROF, prof);
@@ -119,14 +93,18 @@ void release_thread_tt(struct task_struc
 {
 	int pid = task->thread.mode.tt.extern_pid;
 
+	/*
+         * We first have to kill the other process, before
+         * closing its switch_pipe. Else it might wake up
+         * and receive "EOF" before we could kill it.
+         */
 	if(os_getpid() != pid)
 		os_kill_process(pid, 0);
-}
 
-void exit_thread_tt(void)
-{
-	os_close_file(current->thread.mode.tt.switch_pipe[0]);
-	os_close_file(current->thread.mode.tt.switch_pipe[1]);
+        os_close_file(task->thread.mode.tt.switch_pipe[0]);
+        os_close_file(task->thread.mode.tt.switch_pipe[1]);
+	/* use switch_pipe as flag: thread is released */
+        task->thread.mode.tt.switch_pipe[0] = -1;
 }
 
 void suspend_new_thread(int fd)
@@ -394,84 +372,6 @@ void init_idle_tt(void)
 	default_idle();
 }
 
-/* Changed by jail_setup, which is a setup */
-int jail = 0;
-
-int __init jail_setup(char *line, int *add)
-{
-	int ok = 1;
-
-	if(jail) return(0);
-#ifdef CONFIG_SMP
-	printf("'jail' may not used used in a kernel with CONFIG_SMP "
-	       "enabled\n");
-	ok = 0;
-#endif
-#ifdef CONFIG_HOSTFS
-	printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
-	       "enabled\n");
-	ok = 0;
-#endif
-#ifdef CONFIG_MODULES
-	printf("'jail' may not used used in a kernel with CONFIG_MODULES "
-	       "enabled\n");
-	ok = 0;
-#endif	
-	if(!ok) exit(1);
-
-	/* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
-	 * Removing it from the bounding set eliminates the ability of anything
-	 * to acquire it, and thus read or write kernel memory.
-	 */
-	cap_lower(cap_bset, CAP_SYS_RAWIO);
-	jail = 1;
-	return(0);
-}
-
-__uml_setup("jail", jail_setup,
-"jail\n"
-"    Enables the protection of kernel memory from processes.\n\n"
-);
-
-static void mprotect_kernel_mem(int w)
-{
-	unsigned long start, end;
-	int pages;
-
-	if(!jail || (current == &init_task)) return;
-
-	pages = (1 << CONFIG_KERNEL_STACK_ORDER);
-
-	start = (unsigned long) current_thread + PAGE_SIZE;
-	end = (unsigned long) current_thread + PAGE_SIZE * pages;
-	protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
-	protect_memory(end, high_physmem - end, 1, w, 1, 1);
-
-	start = (unsigned long) UML_ROUND_DOWN(&_stext);
-	end = (unsigned long) UML_ROUND_UP(&_etext);
-	protect_memory(start, end - start, 1, w, 1, 1);
-
-	start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end);
-	end = (unsigned long) UML_ROUND_UP(&_edata);
-	protect_memory(start, end - start, 1, w, 1, 1);
-
-	start = (unsigned long) UML_ROUND_DOWN(&__bss_start);
-	end = (unsigned long) UML_ROUND_UP(brk_start);
-	protect_memory(start, end - start, 1, w, 1, 1);
-
-	mprotect_kernel_vm(w);
-}
-
-void unprotect_kernel_mem(void)
-{
-	mprotect_kernel_mem(1);
-}
-
-void protect_kernel_mem(void)
-{
-	mprotect_kernel_mem(0);
-}
-
 extern void start_kernel(void);
 
 static int start_kernel_proc(void *unused)
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
--- a/arch/um/kernel/tt/ptproxy/Makefile
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -5,7 +5,6 @@
 
 obj-y = proxy.o ptrace.o sysdep.o wait.o
 
-USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file))
+USER_OBJS := $(obj-y)
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
--- a/arch/um/kernel/tt/ptproxy/proxy.c
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -18,9 +18,9 @@ Jeff Dike (jdike@karaya.com) : Modified 
 #include <termios.h>
 #include <sys/wait.h>
 #include <sys/types.h>
-#include <sys/ptrace.h>
 #include <sys/ioctl.h>
 #include <asm/unistd.h>
+#include "ptrace_user.h"
 
 #include "ptproxy.h"
 #include "sysdep.h"
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
--- a/arch/um/kernel/tt/ptproxy/ptrace.c
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -12,9 +12,7 @@ Jeff Dike (jdike@karaya.com) : Modified 
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/time.h>
-#include <sys/ptrace.h>
 #include <sys/wait.h>
-#include <asm/ptrace.h>
 
 #include "ptproxy.h"
 #include "debug.h"
@@ -127,7 +125,7 @@ long proxy_ptrace(struct debugger *debug
 
 	case PTRACE_PEEKDATA:
 	case PTRACE_PEEKTEXT:
-	case PTRACE_PEEKUSER:
+	case PTRACE_PEEKUSR:
 		/* The value being read out could be -1, so we have to 
 		 * check errno to see if there's an error, and zero it
 		 * beforehand so we're not faked out by an old error
@@ -144,11 +142,11 @@ long proxy_ptrace(struct debugger *debug
 
 	case PTRACE_POKEDATA:
 	case PTRACE_POKETEXT:
-	case PTRACE_POKEUSER:
+	case PTRACE_POKEUSR:
 		result = ptrace(arg1, child, arg3, arg4);
 		if(result == -1) return(-errno);
 
-		if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4);
+		if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
 		return(result);
 
 #ifdef UM_HAVE_SETFPREGS
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -11,7 +11,6 @@ terms and conditions.
 #include <signal.h>
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/ptrace.h>
 #include <linux/unistd.h>
 #include "ptrace_user.h"
 #include "user_util.h"
@@ -20,21 +19,21 @@ terms and conditions.
 int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, 
 		long *arg5)
 {
-	*arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0);
-	*arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0);
-	*arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0);
-	*arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0);
-	*arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0);
-	return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0));
+	*arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
+	*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
+	*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
+	*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
+	*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
+	return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
 }
 
 void syscall_cancel(pid_t pid, int result)
 {
-	if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+	if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
 		   __NR_getpid) < 0) ||
 	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
 	   (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
-	   (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
+	   (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
 	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
 		printk("ptproxy: couldn't cancel syscall: errno = %d\n", 
 		       errno);
@@ -42,7 +41,7 @@ void syscall_cancel(pid_t pid, int resul
 
 void syscall_set_result(pid_t pid, long result)
 {
-	ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result);
+	ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
 }
 
 void syscall_continue(pid_t pid)
@@ -52,7 +51,7 @@ void syscall_continue(pid_t pid)
 
 int syscall_pause(pid_t pid) 
 {
-	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
+	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
 		printk("syscall_change - ptrace failed, errno = %d\n", errno);
 		return(-1);
 	}
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
--- a/arch/um/kernel/tt/ptproxy/wait.c
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -9,14 +9,13 @@ terms and conditions.
 #include <errno.h>
 #include <signal.h>
 #include <sys/wait.h>
-#include <sys/ptrace.h>
 
 #include "ptproxy.h"
 #include "sysdep.h"
 #include "wait.h"
 #include "user_util.h"
+#include "ptrace_user.h"
 #include "sysdep/ptrace.h"
-#include "sysdep/ptrace_user.h"
 #include "sysdep/sigcontext.h"
 
 int proxy_wait_return(struct debugger *debugger, pid_t unused)
@@ -59,10 +58,10 @@ int real_wait_return(struct debugger *de
 
 	pid = debugger->pid;
 
-	ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+	ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
 	IP_RESTART_SYSCALL(ip);
 
-	if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
+	if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
 		tracer_panic("real_wait_return : Failed to restart system "
 			     "call, errno = %d\n", errno);
 
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
--- a/arch/um/kernel/tt/syscall_kern.c
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -22,8 +22,10 @@ long execute_syscall_tt(void *r)
 	long res;
 	int syscall;
 
+#ifdef CONFIG_SYSCALL_DEBUG
 	current->thread.nsyscalls++;
 	nsyscalls++;
+#endif
 	syscall = UPT_SYSCALL_NR(&regs->regs);
 
 	if((syscall >= NR_syscalls) || (syscall < 0))
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
--- a/arch/um/kernel/tt/syscall_user.c
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -6,7 +6,6 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
-#include <sys/ptrace.h>
 #include <asm/unistd.h>
 #include "sysdep/ptrace.h"
 #include "sigcontext.h"
@@ -22,15 +21,20 @@ void syscall_handler_tt(int sig, union u
 {
 	void *sc;
 	long result;
-	int index, syscall;
+	int syscall;
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+	int index;
+#endif
 
 	syscall = UPT_SYSCALL_NR(regs);
 	sc = UPT_SC(regs);
 	SC_START_SYSCALL(sc);
 
-	index = record_syscall_start(syscall);
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	index = record_syscall_start(syscall);
+#endif
 	syscall_trace(regs, 0);
-	result = execute_syscall(regs);
+	result = execute_syscall_tt(regs);
 
 	/* regs->sc may have changed while the system call ran (there may
 	 * have been an interrupt or segfault), so it needs to be refreshed.
@@ -40,7 +44,9 @@ void syscall_handler_tt(int sig, union u
 	SC_SET_SYSCALL_RETURN(sc, result);
 
 	syscall_trace(regs, 1);
-	record_syscall_end(index, result);
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	record_syscall_end(index, result);
+#endif
 }
 
 void do_sigtrap(void *task)
@@ -57,6 +63,10 @@ void do_syscall(void *task, int pid, int
 
 	UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
 
+#ifdef UPT_ORIGGPR2
+        UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs);
+#endif
+
 	if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
 	   ((unsigned long *) PT_IP(proc_regs) <= &_etext))
 		tracer_panic("I'm tracing myself and I can't get out");
@@ -66,7 +76,7 @@ void do_syscall(void *task, int pid, int
 		return;
 
 	/* syscall number -1 in sysemu skips syscall restarting in host */
-	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
 		  local_using_sysemu ? -1 : __NR_getpid) < 0)
 		tracer_panic("do_syscall : Nullifying syscall failed, "
 			     "errno = %d", errno);
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -15,203 +15,55 @@
 #include "user_util.h"
 #include "mem_user.h"
 #include "os.h"
+#include "tlb.h"
 
-static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
-		      unsigned long end_addr, int force)
+static void do_ops(int unused, struct host_vm_op *ops, int last)
 {
-	pgd_t *npgd;
-	pud_t *npud;
-	pmd_t *npmd;
-	pte_t *npte;
-	unsigned long addr, end;
-	int r, w, x, err;
-
-	if((current->thread.mode.tt.extern_pid != -1) && 
-	   (current->thread.mode.tt.extern_pid != os_getpid()))
-		panic("fix_range fixing wrong address space, current = 0x%p",
-		      current);
-	if(mm == NULL) return;
-	for(addr=start_addr;addr<end_addr;){
-		if(addr == TASK_SIZE){
-			/* Skip over kernel text, kernel data, and physical
-			 * memory, which don't have ptes, plus kernel virtual
-			 * memory, which is flushed separately, and remap
-			 * the process stack.  The only way to get here is
-			 * if (end_addr == STACK_TOP) > TASK_SIZE, which is
-			 * only true in the honeypot case.
-			 */
-			addr = STACK_TOP - ABOVE_KMEM;
-			continue;
-		}
-
-		npgd = pgd_offset(mm, addr);
- 		if(!pgd_present(*npgd)){
- 			if(force || pgd_newpage(*npgd)){
- 				end = addr + PGDIR_SIZE;
- 				if(end > end_addr)
- 					end = end_addr;
-				err = os_unmap_memory((void *) addr,
- 						      end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pgd_mkuptodate(*npgd);
- 			}
-			addr += PGDIR_SIZE;
-			continue;
- 		}
-
-		npud = pud_offset(npgd, addr);
-		if(!pud_present(*npud)){
-			if(force || pud_newpage(*npud)){
- 				end = addr + PUD_SIZE;
- 				if(end > end_addr)
- 					end = end_addr;
-				err = os_unmap_memory((void *) addr, 
-						      end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pud_mkuptodate(*npud);
-			}
-			addr += PUD_SIZE;
-			continue;
-		}
+	struct host_vm_op *op;
+	int i;
 
-		npmd = pmd_offset(npud, addr);
-		if(!pmd_present(*npmd)){
-			if(force || pmd_newpage(*npmd)){
- 				end = addr + PMD_SIZE;
- 				if(end > end_addr)
- 					end = end_addr;
-				err = os_unmap_memory((void *) addr,
-						      end - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-				pmd_mkuptodate(*npmd);
-			}
-			addr += PMD_SIZE;
-			continue;
+	for(i = 0; i <= last; i++){
+		op = &ops[i];
+		switch(op->type){
+		case MMAP:
+                        os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
+				      op->u.mmap.offset, op->u.mmap.len,
+				      op->u.mmap.r, op->u.mmap.w,
+				      op->u.mmap.x);
+			break;
+		case MUNMAP:
+			os_unmap_memory((void *) op->u.munmap.addr,
+					op->u.munmap.len);
+			break;
+		case MPROTECT:
+			protect_memory(op->u.mprotect.addr, op->u.munmap.len,
+				       op->u.mprotect.r, op->u.mprotect.w,
+				       op->u.mprotect.x, 1);
+			break;
+		default:
+			printk("Unknown op type %d in do_ops\n", op->type);
+			break;
 		}
-
-		npte = pte_offset_kernel(npmd, addr);
-		r = pte_read(*npte);
-		w = pte_write(*npte);
-		x = pte_exec(*npte);
-		if(!pte_dirty(*npte))
-			w = 0;
-		if(!pte_young(*npte)){
-			r = 0;
-			w = 0;
-		}
-		if(force || pte_newpage(*npte)){
-			err = os_unmap_memory((void *) addr, PAGE_SIZE);
-			if(err < 0)
-				panic("munmap failed, errno = %d\n", -err);
-			if(pte_present(*npte))
-				map_memory(addr, pte_val(*npte) & PAGE_MASK,
-					   PAGE_SIZE, r, w, x);
-		}
-		else if(pte_newprot(*npte))
-			protect_memory(addr, PAGE_SIZE, r, w, x, 1);
-
-		*npte = pte_mkuptodate(*npte);
-		addr += PAGE_SIZE;
 	}
 }
 
-atomic_t vmchange_seq = ATOMIC_INIT(1);
-
-static void flush_kernel_vm_range(unsigned long start, unsigned long end, 
-				  int update_seq)
+static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
+		      unsigned long end_addr, int force)
 {
-	struct mm_struct *mm;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long addr, last;
-	int updated = 0, err;
+        if((current->thread.mode.tt.extern_pid != -1) &&
+           (current->thread.mode.tt.extern_pid != os_getpid()))
+                panic("fix_range fixing wrong address space, current = 0x%p",
+                      current);
 
-	mm = &init_mm;
-	for(addr = start; addr < end;){
-		pgd = pgd_offset(mm, addr);
- 		if(!pgd_present(*pgd)){
- 			if(pgd_newpage(*pgd)){
-				updated = 1;
- 				last = addr + PGDIR_SIZE;
- 				if(last > end)
- 					last = end;
-				err = os_unmap_memory((void *) addr, 
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PGDIR_SIZE;
-			continue;
-		}
-
-		pud = pud_offset(pgd, addr);
-		if(!pud_present(*pud)){
-			if(pud_newpage(*pud)){
-				updated = 1;
-				last = addr + PUD_SIZE;
-				if(last > end)
-					last = end;
-				err = os_unmap_memory((void *) addr,
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PUD_SIZE;
-			continue;
-		}
-
-		pmd = pmd_offset(pud, addr);
-		if(!pmd_present(*pmd)){
-			if(pmd_newpage(*pmd)){
-				updated = 1;
-				last = addr + PMD_SIZE;
-				if(last > end)
-					last = end;
-				err = os_unmap_memory((void *) addr,
-						      last - addr);
-				if(err < 0)
-					panic("munmap failed, errno = %d\n",
-					      -err);
-			}
-			addr += PMD_SIZE;
-			continue;
-		}
-
-		pte = pte_offset_kernel(pmd, addr);
-		if(!pte_present(*pte) || pte_newpage(*pte)){
-			updated = 1;
-			err = os_unmap_memory((void *) addr,
-					      PAGE_SIZE);
-			if(err < 0)
-				panic("munmap failed, errno = %d\n",
-				      -err);
-			if(pte_present(*pte))
-				map_memory(addr,
-					   pte_val(*pte) & PAGE_MASK,
-					   PAGE_SIZE, 1, 1, 1);
-		}
-		else if(pte_newprot(*pte)){
-			updated = 1;
-			protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
-		}
-		addr += PAGE_SIZE;
-	}
-	if(updated && update_seq) atomic_inc(&vmchange_seq);
+        fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
 }
 
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
 void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
 {
-        flush_kernel_vm_range(start, end, 1);
+        if(flush_tlb_kernel_range_common(start, end))
+                atomic_inc(&vmchange_seq);
 }
 
 static void protect_vm_page(unsigned long addr, int w, int must_succeed)
@@ -268,8 +120,10 @@ void flush_tlb_range_tt(struct vm_area_s
 	/* Assumes that the range start ... end is entirely within
 	 * either process memory or kernel vm
 	 */
-	if((start >= start_vm) && (start < end_vm)) 
-		flush_kernel_vm_range(start, end, 1);
+	if((start >= start_vm) && (start < end_vm)){
+		if(flush_tlb_kernel_range_common(start, end))
+			atomic_inc(&vmchange_seq);
+	}
 	else fix_range(vma->vm_mm, start, end, 0);
 }
 
@@ -282,24 +136,14 @@ void flush_tlb_mm_tt(struct mm_struct *m
 	fix_range(mm, 0, STACK_TOP, 0);
 
 	seq = atomic_read(&vmchange_seq);
-	if(current->thread.mode.tt.vm_seq == seq) return;
+	if(current->thread.mode.tt.vm_seq == seq)
+		return;
 	current->thread.mode.tt.vm_seq = seq;
-	flush_kernel_vm_range(start_vm, end_vm, 0);
+	flush_tlb_kernel_range_common(start_vm, end_vm);
 }
 
 void force_flush_all_tt(void)
 {
 	fix_range(current->mm, 0, STACK_TOP, 1);
-	flush_kernel_vm_range(start_vm, end_vm, 0);
+	flush_tlb_kernel_range_common(start_vm, end_vm);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
--- a/arch/um/kernel/tt/tracer.c
+++ b/arch/um/kernel/tt/tracer.c
@@ -12,8 +12,6 @@
 #include <sched.h>
 #include <string.h>
 #include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <linux/ptrace.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include "user.h"
@@ -28,6 +26,7 @@
 #include "kern_util.h"
 #include "chan_user.h"
 #include "ptrace_user.h"
+#include "irq_user.h"
 #include "mode.h"
 #include "tt.h"
 
@@ -35,7 +34,7 @@ static int tracer_winch[2];
 
 int is_tracer_winch(int pid, int fd, void *data)
 {
-	if(pid != tracing_pid)
+	if(pid != os_getpgrp())
 		return(0);
 
 	register_winch_irq(tracer_winch[0], fd, -1, data);
@@ -91,8 +90,10 @@ void tracer_panic(char *format, ...)
 
 static void tracer_segv(int sig, struct sigcontext sc)
 {
+        struct faultinfo fi;
+        GET_FAULTINFO_FROM_SC(fi, &sc);
 	printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
-	       SC_FAULT_ADDR(&sc), SC_IP(&sc));
+               FAULT_ADDRESS(fi), SC_IP(&sc));
 	while(1)
 		pause();
 }
@@ -119,6 +120,7 @@ static int signal_tramp(void *arg)
 	signal(SIGSEGV, (__sighandler_t) sig_handler);
 	set_cmdline("(idle thread)");
 	set_init_pid(os_getpid());
+	init_irq_signals(0);
 	proc = arg;
 	return((*proc)(NULL));
 }
@@ -184,11 +186,13 @@ int tracing_pid = -1;
 int tracer(int (*init_proc)(void *), void *sp)
 {
 	void *task = NULL;
-	unsigned long eip = 0;
 	int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
-	int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
+	int proc_id = 0, n, err, old_tracing = 0, strace = 0;
 	int local_using_sysemu = 0;
-
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+	unsigned long eip = 0;
+	int last_index;
+#endif
 	signal(SIGPIPE, SIG_IGN);
 	setup_tracer_winch();
 	tracing_pid = os_getpid();
@@ -279,22 +283,23 @@ int tracer(int (*init_proc)(void *), voi
 		else if(WIFSTOPPED(status)){
 			proc_id = pid_to_processor_id(pid);
 			sig = WSTOPSIG(status);
+#ifdef UML_CONFIG_SYSCALL_DEBUG
 			if(signal_index[proc_id] == 1024){
 				signal_index[proc_id] = 0;
 				last_index = 1023;
 			}
 			else last_index = signal_index[proc_id] - 1;
-			if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
+			if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
 			    (sig == SIGALRM)) &&
 			   (signal_record[proc_id][last_index].signal == sig)&&
 			   (signal_record[proc_id][last_index].pid == pid))
 				signal_index[proc_id] = last_index;
 			signal_record[proc_id][signal_index[proc_id]].pid = pid;
 			gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
-			eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+			eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
 			signal_record[proc_id][signal_index[proc_id]].addr = eip;
 			signal_record[proc_id][signal_index[proc_id]++].signal = sig;
-			
+#endif
 			if(proc_id == -1){
 				sleeping_process_signal(pid, sig);
 				continue;
@@ -467,19 +472,6 @@ __uml_setup("debugtrace", uml_debugtrace
 "    the debug switch.\n\n"
 );
 
-static int __init uml_honeypot_setup(char *line, int *add)
-{
-	jail_setup("", add);
-	honeypot = 1;
-	return 0;
-}
-__uml_setup("honeypot", uml_honeypot_setup, 
-"honeypot\n"
-"    This makes UML put process stacks in the same location as they are\n"
-"    on the host, allowing expoits such as stack smashes to work against\n"
-"    UML.  This implies 'jail'.\n\n"
-);
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
--- a/arch/um/kernel/tt/trap_user.c
+++ b/arch/um/kernel/tt/trap_user.c
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <signal.h>
 #include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
 #include "signal_user.h"
 #include "user_util.h"
 #include "kern_util.h"
@@ -20,8 +21,6 @@ void sig_handler_common_tt(int sig, void
 	struct signal_info *info;
 	int save_errno = errno, is_user;
 
-	unprotect_kernel_mem();
-
 	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
 	 * handler.  This can happen in copy_user, and if SEGV is disabled,
 	 * the process will die.
@@ -30,6 +29,11 @@ void sig_handler_common_tt(int sig, void
 		change_sig(SIGSEGV, 1);
 
 	r = &TASK_REGS(get_current())->tt;
+        if ( sig == SIGFPE || sig == SIGSEGV ||
+             sig == SIGBUS || sig == SIGILL ||
+             sig == SIGTRAP ) {
+                GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+        }
 	save_regs = *r;
 	is_user = user_context(SC_SP(sc));
 	r->sc = sc;
@@ -48,7 +52,6 @@ void sig_handler_common_tt(int sig, void
 	}
 	*r = save_regs;
 	errno = save_errno;
-	if(is_user) protect_kernel_mem();
 }
 
 /*
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -23,6 +23,7 @@
 #include "asm/ptrace.h"
 #include "asm/elf.h"
 #include "asm/user.h"
+#include "asm/setup.h"
 #include "ubd_user.h"
 #include "asm/current.h"
 #include "user_util.h"
@@ -40,6 +41,20 @@
 
 #define DEFAULT_COMMAND_LINE "root=98:0"
 
+/* Changed in linux_main and setup_arch, which run before SMP is started */
+static char command_line[COMMAND_LINE_SIZE] = { 0 };
+
+static void add_arg(char *arg)
+{
+	if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
+		printf("add_arg: Too many command line arguments!\n");
+		exit(1);
+	}
+	if(strlen(command_line) > 0)
+		strcat(command_line, " ");
+	strcat(command_line, arg);
+}
+
 struct cpuinfo_um boot_cpu_data = { 
 	.loops_per_jiffy	= 0,
 	.ipi_pipe		= { -1, -1 }
@@ -95,12 +110,6 @@ struct seq_operations cpuinfo_op = {
 	.show	= show_cpuinfo,
 };
 
-pte_t * __bad_pagetable(void)
-{
-	panic("Someone should implement __bad_pagetable");
-	return(NULL);
-}
-
 /* Set in linux_main */
 unsigned long host_task_size;
 unsigned long task_size;
@@ -314,9 +323,11 @@ int linux_main(int argc, char **argv)
 		if((i == 1) && (argv[i][0] == ' ')) continue;
 		add = 1;
 		uml_checksetup(argv[i], &add);
-		if(add) add_arg(saved_command_line, argv[i]);
+		if (add)
+			add_arg(argv[i]);
 	}
-	if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
+	if(have_root == 0)
+		add_arg(DEFAULT_COMMAND_LINE);
 
 	mode_tt = force_tt ? 1 : !can_do_skas();
 #ifndef CONFIG_MODE_TT
@@ -432,7 +443,7 @@ void __init setup_arch(char **cmdline_p)
 {
 	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
 	paging_init();
- 	strcpy(command_line, saved_command_line);
+        strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
  	*cmdline_p = command_line;
 	setup_hostinfo();
 }
@@ -448,14 +459,3 @@ void __init check_bugs(void)
 void apply_alternatives(void *start, void *end)
 {
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -73,6 +73,8 @@ SECTIONS
 
   .got           : { *(.got.plt) *(.got) }
   .dynamic       : { *(.dynamic) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   /* We want the small data sections together, so single-instruction offsets
      can access them all, and initialized data all before uninitialized, so
      we can shorten the on-disk segment size.  */
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
--- a/arch/um/kernel/user_util.c
+++ b/arch/um/kernel/user_util.c
@@ -10,7 +10,6 @@
 #include <setjmp.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/ptrace.h>
 #include <sys/utsname.h>
 #include <sys/param.h>
 #include <sys/time.h>
@@ -29,23 +28,9 @@
 #include "mem_user.h"
 #include "init.h"
 #include "helper.h"
+#include "ptrace_user.h"
 #include "uml-config.h"
 
-#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
-
-/* Changed in linux_main and setup_arch, which run before SMP is started */
-char command_line[COMMAND_LINE_SIZE] = { 0 };
-
-void add_arg(char *cmd_line, char *arg)
-{
-	if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
-		printf("add_arg: Too much command line!\n");
-		exit(1);
-	}
-	if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
-	strcat(cmd_line, arg);
-}
-
 void stop(void)
 {
 	while(1) sleep(1000000);
diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S
new file mode 100644
--- /dev/null
+++ b/arch/um/kernel/vmlinux.lds.S
@@ -0,0 +1,6 @@
+#include <linux/config.h>
+#ifdef CONFIG_LD_SCRIPT_STATIC
+#include "uml.lds.S"
+#else
+#include "dyn.lds.S"
+#endif
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -7,9 +7,7 @@ obj-y = elf_aux.o file.o process.o signa
 	sys-$(SUBARCH)/
 
 USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
 
 CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
--- a/arch/um/os-Linux/drivers/Makefile
+++ b/arch/um/os-Linux/drivers/Makefile
@@ -10,10 +10,4 @@ obj-y = 
 obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
 obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
 
-USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
-
-USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -45,7 +45,11 @@ __init void scan_elf_aux( char **envp)
 				elf_aux_hwcap = auxv->a_un.a_val;
 				break;
 			case AT_PLATFORM:
-				elf_aux_platform = auxv->a_un.a_ptr;
+                                /* elf.h removed the pointer elements from
+                                 * a_un, so we have to use a_val, which is
+                                 * all that's left.
+                                 */
+				elf_aux_platform = (char *) auxv->a_un.a_val;
 				break;
 			case AT_PAGESZ:
 				page_size = auxv->a_un.a_val;
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -363,7 +363,7 @@ int os_write_file(int fd, const void *bu
 		       (int (*)(int, void *, int)) write, copy_to_user_proc));
 }
 
-int os_file_size(char *file, long long *size_out)
+int os_file_size(char *file, unsigned long long *size_out)
 {
 	struct uml_stat buf;
 	int err;
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -8,9 +8,9 @@
 #include <errno.h>
 #include <signal.h>
 #include <linux/unistd.h>
-#include <sys/ptrace.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
+#include "ptrace_user.h"
 #include "os.h"
 #include "user.h"
 #include "user_util.h"
@@ -123,6 +123,11 @@ int os_getpid(void)
 	return(getpid());
 }
 
+int os_getpgrp(void)
+{
+	return getpgrp();
+}
+
 int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
 		  int r, int w, int x)
 {
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -8,7 +8,7 @@
 #include "mode.h"
 #include "sysdep/signal.h"
 
-void sig_handler(int sig)
+void sig_handler(ARCH_SIGHDLR_PARAM)
 {
 	struct sigcontext *sc;
 
@@ -19,7 +19,7 @@ void sig_handler(int sig)
 
 extern int timer_irq_inited;
 
-void alarm_handler(int sig)
+void alarm_handler(ARCH_SIGHDLR_PARAM)
 {
 	struct sigcontext *sc;
 
diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile
--- a/arch/um/os-Linux/sys-i386/Makefile
+++ b/arch/um/os-Linux/sys-i386/Makefile
@@ -5,7 +5,6 @@
 
 obj-$(CONFIG_MODE_SKAS) = registers.o
 
-USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
+USER_OBJS := $(obj-y)
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -5,7 +5,7 @@
 
 #include <errno.h>
 #include <string.h>
-#include <sys/ptrace.h>
+#include "sysdep/ptrace_user.h"
 #include "sysdep/ptrace.h"
 #include "uml-config.h"
 #include "skas_ptregs.h"
@@ -27,6 +27,23 @@ void init_thread_registers(union uml_pt_
 		memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp));
 }
 
+/* XXX These need to use [GS]ETFPXREGS and copy_sc_{to,from}_user_skas needs
+ * to pass in a sufficiently large buffer
+ */
+int save_fp_registers(int pid, unsigned long *fp_regs)
+{
+	if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
+		return(-errno);
+	return(0);
+}
+
+int restore_fp_registers(int pid, unsigned long *fp_regs)
+{
+	if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
+		return(-errno);
+	return(0);
+}
+
 static int move_registers(int pid, int int_op, union uml_pt_regs *regs,
 			  int fp_op, unsigned long *fp_regs)
 {
@@ -88,14 +105,15 @@ void init_registers(int pid)
 		panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
 		      err);
 
+	errno = 0;
 	err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
 	if(!err)
 		return;
+	if(errno != EIO)
+		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
+		      errno);
 
 	have_fpx_regs = 0;
-	if(err != EIO)
-		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
-		      err);
 
 	err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
 	if(err)
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile
--- a/arch/um/os-Linux/sys-x86_64/Makefile
+++ b/arch/um/os-Linux/sys-x86_64/Makefile
@@ -5,7 +5,6 @@
 
 obj-$(CONFIG_MODE_SKAS) = registers.o
 
-USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
+USER_OBJS := $(obj-y)
 
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -5,8 +5,7 @@
 
 #include <errno.h>
 #include <string.h>
-#include <sys/ptrace.h>
-#include "sysdep/ptrace.h"
+#include "ptrace_user.h"
 #include "uml-config.h"
 #include "skas_ptregs.h"
 #include "registers.h"
diff --git a/arch/um/os-Linux/util/Makefile b/arch/um/os-Linux/util/Makefile
new file mode 100644
--- /dev/null
+++ b/arch/um/os-Linux/util/Makefile
@@ -0,0 +1,4 @@
+hostprogs-y		:= mk_user_constants
+always			:= $(hostprogs-y)
+
+HOSTCFLAGS_mk_user_constants.o := -I$(objtree)/arch/um
diff --git a/arch/um/os-Linux/util/mk_user_constants.c b/arch/um/os-Linux/util/mk_user_constants.c
new file mode 100644
--- /dev/null
+++ b/arch/um/os-Linux/util/mk_user_constants.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <user-offsets.h>
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_user_constants\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __UM_USER_CONSTANTS_H\n");
+  printf("#define __UM_USER_CONSTANTS_H\n");
+  printf("\n");
+  /* I'd like to use FRAME_SIZE from ptrace.h here, but that's wrong on
+   * x86_64 (216 vs 168 bytes).  user_regs_struct is the correct size on
+   * both x86_64 and i386.
+   */
+  printf("#define UM_FRAME_SIZE %d\n", __UM_FRAME_SIZE);
+
+  printf("\n");
+  printf("#endif\n");
+
+  return(0);
+}
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
new file mode 100644
--- /dev/null
+++ b/arch/um/scripts/Makefile.rules
@@ -0,0 +1,28 @@
+# ===========================================================================
+# arch/um: Generic definitions
+# ===========================================================================
+
+USER_SINGLE_OBJS := \
+	$(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m)  $(USER_SINGLE_OBJS))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS) : c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \
+	$(CFLAGS_$(notdir $@))
+
+quiet_cmd_make_link = SYMLINK $@
+cmd_make_link       = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
+
+# this needs to be before the foreach, because targets does not accept
+# complete paths like $(obj)/$(f). To make sure this works, use a := assignment
+# or we will get $(obj)/$(f) in the "targets" value.
+# Also, this forces you to use the := syntax when assigning to targets.
+# Otherwise the line below will cause an infinite loop (if you don't know why,
+# just do it).
+
+targets := $(targets) $(SYMLINKS)
+
+SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f))
+
+$(SYMLINKS): FORCE
+	$(call if_changed,make_link)
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,34 +1,19 @@
 obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o
+	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
+	sys_call_table.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 obj-$(CONFIG_MODULES) += module.o
 
 USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 SYMLINKS = bitops.c semaphore.c highmem.c module.c
 
-# this needs to be before the foreach, because clean-files does not accept
-# complete paths like $(src)/$f.
-clean-files := $(SYMLINKS)
-
-SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
+include arch/um/scripts/Makefile.rules
 
 bitops.c-dir = lib
 semaphore.c-dir = kernel
 highmem.c-dir = mm
 module.c-dir = kernel
 
-define make_link
-	-rm -f $1
-	ln -sf $(TOPDIR)/arch/i386/$($(notdir $1)-dir)/$(notdir $1) $1
-endef
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-$(SYMLINKS): 
-	$(call make_link,$@)
-
 subdir- := util
diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S
--- a/arch/um/sys-i386/checksum.S
+++ b/arch/um/sys-i386/checksum.S
@@ -38,7 +38,7 @@ unsigned int csum_partial(const unsigned
 		
 .text
 .align 4
-.globl arch_csum_partial								
+.globl csum_partial
 		
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
@@ -49,7 +49,7 @@ unsigned int csum_partial(const unsigned
 	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
 	   * alignment for the unrolled loop.
 	   */		
-arch_csum_partial:	
+csum_partial:
 	pushl %esi
 	pushl %ebx
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
@@ -119,7 +119,7 @@ arch_csum_partial:	
 
 /* Version for PentiumII/PPro */
 
-arch_csum_partial:
+csum_partial:
 	pushl %esi
 	pushl %ebx
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c
--- a/arch/um/sys-i386/delay.c
+++ b/arch/um/sys-i386/delay.c
@@ -1,3 +1,8 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <asm/param.h>
+
 void __delay(unsigned long time)
 {
 	/* Stolen from the i386 __loop_delay */
@@ -12,3 +17,24 @@ void __delay(unsigned long time)
 		:"0" (time));
 }
 
+void __udelay(unsigned long usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+        for(i=0;i<n;i++)
+                cpu_relax();
+}
+
+EXPORT_SYMBOL(__udelay);
+
+void __const_udelay(unsigned long usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+        for(i=0;i<n;i++)
+                cpu_relax();
+}
+
+EXPORT_SYMBOL(__const_udelay);
diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/sys-i386/kernel-offsets.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-i386/kernel-offsets.c
@@ -0,0 +1,25 @@
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <asm/page.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define STR(x) #x
+#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
+
+#define BLANK() asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+	OFFSET(TASK_DEBUGREGS, task_struct, thread.arch.debugregs);
+#ifdef CONFIG_MODE_TT
+	OFFSET(TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+#endif
+#include <common-offsets.h>
+}
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
--- a/arch/um/sys-i386/ksyms.c
+++ b/arch/um/sys-i386/ksyms.c
@@ -2,6 +2,7 @@
 #include "linux/in6.h"
 #include "linux/rwsem.h"
 #include "asm/byteorder.h"
+#include "asm/delay.h"
 #include "asm/semaphore.h"
 #include "asm/uaccess.h"
 #include "asm/checksum.h"
@@ -13,5 +14,8 @@ EXPORT_SYMBOL(__down_failed_trylock);
 EXPORT_SYMBOL(__up_wakeup);
 
 /* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_from);
-EXPORT_SYMBOL(csum_partial_copy_to);
+EXPORT_SYMBOL(csum_partial);
+
+/* delay core functions */
+EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(__udelay);
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -17,7 +17,7 @@ extern int modify_ldt(int func, void *pt
 
 int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
 {
-	if (verify_area(VERIFY_READ, ptr, bytecount))
+	if (!access_ok(VERIFY_READ, ptr, bytecount))
 		return -EFAULT;
 
 	return modify_ldt(func, ptr, bytecount);
@@ -25,7 +25,7 @@ int sys_modify_ldt_tt(int func, void __u
 #endif
 
 #ifdef CONFIG_MODE_SKAS
-extern int userspace_pid;
+extern int userspace_pid[];
 
 #include "skas_ptrace.h"
 
@@ -56,7 +56,8 @@ int sys_modify_ldt_skas(int func, void _
 	ldt = ((struct ptrace_ldt) { .func	= func,
 				     .ptr	= buf,
 				     .bytecount = bytecount });
-	res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
+#warning Need to look up userspace_pid by cpu
+	res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
 	if(res < 0)
 		goto out;
 
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -10,7 +10,7 @@
 #include "asm/ptrace.h"
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
-#include "ptrace_user.h"
+#include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
 #include "sysdep/sc.h"
 
@@ -73,6 +73,25 @@ int putreg(struct task_struct *child, in
 	return 0;
 }
 
+int poke_user(struct task_struct *child, long addr, long data)
+{
+        if ((addr & 3) || addr < 0)
+                return -EIO;
+
+        if (addr < MAX_REG_OFFSET)
+                return putreg(child, addr, data);
+
+        else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+                (addr <= offsetof(struct user, u_debugreg[7]))){
+                addr -= offsetof(struct user, u_debugreg[0]);
+                addr = addr >> 2;
+                if((addr == 4) || (addr == 5)) return -EIO;
+                child->thread.arch.debugregs[addr] = data;
+                return 0;
+        }
+        return -EIO;
+}
+
 unsigned long getreg(struct task_struct *child, int regno)
 {
 	unsigned long retval = ~0UL;
@@ -93,6 +112,27 @@ unsigned long getreg(struct task_struct 
 	return retval;
 }
 
+int peek_user(struct task_struct *child, long addr, long data)
+{
+/* read the word at location addr in the USER area. */
+        unsigned long tmp;
+
+        if ((addr & 3) || addr < 0)
+                return -EIO;
+
+        tmp = 0;  /* Default return condition */
+        if(addr < MAX_REG_OFFSET){
+                tmp = getreg(child, addr);
+        }
+        else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+                (addr <= offsetof(struct user, u_debugreg[7]))){
+                addr -= offsetof(struct user, u_debugreg[0]);
+                addr = addr >> 2;
+                tmp = child->thread.arch.debugregs[addr];
+        }
+        return put_user(tmp, (unsigned long *) data);
+}
+
 struct i387_fxsave_struct {
 	unsigned short	cwd;
 	unsigned short	swd;
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -7,8 +7,8 @@
 #include <errno.h>
 #include <unistd.h>
 #include <linux/stddef.h>
-#include <sys/ptrace.h>
-#include <asm/ptrace.h>
+#include "ptrace_user.h"
+/* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */
 #include <asm/user.h>
 #include "kern_util.h"
 #include "sysdep/thread.h"
@@ -52,7 +52,7 @@ static void write_debugregs(int pid, uns
 	nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
 	for(i = 0; i < nregs; i++){
 		if((i == 4) || (i == 5)) continue;
-		if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i],
+		if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
 			  regs[i]) < 0)
 			printk("write_debugregs - ptrace failed on "
 			       "register %d, value = 0x%x, errno = %d\n", i,
@@ -68,7 +68,7 @@ static void read_debugregs(int pid, unsi
 	dummy = NULL;
 	nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
 	for(i = 0; i < nregs; i++){
-		regs[i] = ptrace(PTRACE_PEEKUSER, pid,
+		regs[i] = ptrace(PTRACE_PEEKUSR, pid,
 				 &dummy->u_debugreg[i], 0);
 	}
 }
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -11,8 +11,8 @@
 #include "asm/unistd.h"
 #include "frame_kern.h"
 #include "signal_user.h"
-#include "ptrace_user.h"
 #include "sigcontext.h"
+#include "registers.h"
 #include "mode.h"
 
 #ifdef CONFIG_MODE_SKAS
@@ -47,11 +47,8 @@ static int copy_sc_from_user_skas(struct
 	REGS_CS(regs->regs.skas.regs) = sc.cs;
 	REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
 	REGS_SS(regs->regs.skas.regs) = sc.ss;
-	regs->regs.skas.fault_addr = sc.cr2;
-	regs->regs.skas.fault_type = FAULT_WRITE(sc.err);
-	regs->regs.skas.trap_type = sc.trapno;
 
-	err = ptrace_setfpregs(userspace_pid[0], fpregs);
+	err = restore_fp_registers(userspace_pid[0], fpregs);
 	if(err < 0){
 	  	printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
 		       "errno = %d\n", err);
@@ -62,11 +59,11 @@ static int copy_sc_from_user_skas(struct
 }
 
 int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
-			 struct pt_regs *regs, unsigned long fault_addr,
-			 int fault_type)
+                         struct pt_regs *regs)
 {
   	struct sigcontext sc;
 	unsigned long fpregs[HOST_FP_SIZE];
+	struct faultinfo * fi = &current->thread.arch.faultinfo;
 	int err;
 
 	sc.gs = REGS_GS(regs->regs.skas.regs);
@@ -86,11 +83,11 @@ int copy_sc_to_user_skas(struct sigconte
 	sc.eflags = REGS_EFLAGS(regs->regs.skas.regs);
 	sc.esp_at_signal = regs->regs.skas.regs[UESP];
 	sc.ss = regs->regs.skas.regs[SS];
-	sc.cr2 = fault_addr;
-	sc.err = TO_SC_ERR(fault_type);
-	sc.trapno = regs->regs.skas.trap_type;
+        sc.cr2 = fi->cr2;
+        sc.err = fi->error_code;
+        sc.trapno = fi->trap_no;
 
-	err = ptrace_getfpregs(userspace_pid[0], fpregs);
+	err = save_fp_registers(userspace_pid[0], fpregs);
 	if(err < 0){
 	  	printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
 		       "errno = %d\n", err);
@@ -108,6 +105,15 @@ int copy_sc_to_user_skas(struct sigconte
 #endif
 
 #ifdef CONFIG_MODE_TT
+
+/* These copy a sigcontext to/from userspace.  They copy the fpstate pointer,
+ * blowing away the old, good one.  So, that value is saved, and then restored
+ * after the sigcontext copy.  In copy_from, the variable holding the saved
+ * fpstate pointer, and the sigcontext that it should be restored to are both
+ * in the kernel, so we can just restore using an assignment.  In copy_to, the
+ * saved pointer is in the kernel, but the sigcontext is in userspace, so we
+ * copy_to_user it.
+ */
 int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
 			 int fpsize)
 {
@@ -120,11 +126,9 @@ int copy_sc_from_user_tt(struct sigconte
 	sigs = to->oldmask;
 	err = copy_from_user(to, from, sizeof(*to));
 	to->oldmask = sigs;
-	if(to_fp != NULL){
-		err |= copy_from_user(&to->fpstate, &to_fp,
-				      sizeof(to->fpstate));
+	to->fpstate = to_fp;
+	if(to_fp != NULL)
 		err |= copy_from_user(to_fp, from_fp, fpsize);
-	}
 	return(err);
 }
 
@@ -138,8 +142,7 @@ int copy_sc_to_user_tt(struct sigcontext
 	from_fp = from->fpstate;
 	err = copy_to_user(to, from, sizeof(*to));
 	if(from_fp != NULL){
-		err |= copy_to_user(&to->fpstate, &to_fp,
-					 sizeof(to->fpstate));
+		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
 		err |= copy_to_user(to_fp, from_fp, fpsize);
 	}
 	return(err);
@@ -161,9 +164,7 @@ static int copy_sc_to_user(struct sigcon
 {
 	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
 					      sizeof(*fp)),
-			   copy_sc_to_user_skas(to, fp, from,
-						current->thread.cr2,
-						current->thread.err)));
+                           copy_sc_to_user_skas(to, fp, from)));
 }
 
 static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
@@ -211,8 +212,8 @@ int setup_signal_stack_sc(unsigned long 
 
 	stack_top &= -8UL;
 	frame = (struct sigframe *) stack_top - 1;
-	if(verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		return(1);
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return 1;
 
 	restorer = (void *) frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
@@ -261,8 +262,8 @@ int setup_signal_stack_si(unsigned long 
 
 	stack_top &= -8UL;
 	frame = (struct rt_sigframe *) stack_top - 1;
-	if(verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		return(1);
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return 1;
 
 	restorer = (void *) frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
@@ -303,7 +304,7 @@ int setup_signal_stack_si(unsigned long 
 
 long sys_sigreturn(struct pt_regs regs)
 {
-	unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
+	unsigned long sp = PT_REGS_SP(&current->thread.regs);
 	struct sigframe __user *frame = (struct sigframe *)(sp - 8);
 	sigset_t set;
 	struct sigcontext __user *sc = &frame->sc;
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-i386/sys_call_table.S
@@ -0,0 +1,16 @@
+#include <linux/linkage.h>
+/* Steal i386 syscall table for our purposes, but with some slight changes.*/
+
+#define sys_iopl sys_ni_syscall
+#define sys_ioperm sys_ni_syscall
+
+#define sys_vm86old sys_ni_syscall
+#define sys_vm86 sys_ni_syscall
+#define sys_set_thread_area sys_ni_syscall
+#define sys_get_thread_area sys_ni_syscall
+
+#define sys_stime um_stime
+#define sys_time um_time
+#define old_mmap old_mmap_i386
+
+#include "../../i386/kernel/syscall_table.S"
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
--- a/arch/um/sys-i386/syscalls.c
+++ b/arch/um/sys-i386/syscalls.c
@@ -88,7 +88,7 @@ long sys_clone(unsigned long clone_flags
  * This is really horribly ugly.
  */
 long sys_ipc (uint call, int first, int second,
-	     int third, void *__user ptr, long fifth)
+	     int third, void __user *ptr, long fifth)
 {
 	int version, ret;
 
@@ -175,7 +175,7 @@ long sys_sigaction(int sig, const struct
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -187,7 +187,7 @@ long sys_sigaction(int sig, const struct
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
--- a/arch/um/sys-i386/sysrq.c
+++ b/arch/um/sys-i386/sysrq.c
@@ -3,12 +3,15 @@
  * Licensed under the GPL
  */
 
+#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/smp.h"
 #include "linux/sched.h"
+#include "linux/kallsyms.h"
 #include "asm/ptrace.h"
 #include "sysrq.h"
 
+/* This is declared by <linux/sched.h> */
 void show_regs(struct pt_regs *regs)
 {
         printk("\n");
@@ -31,5 +34,80 @@ void show_regs(struct pt_regs *regs)
 	       0xffff & PT_REGS_DS(regs), 
 	       0xffff & PT_REGS_ES(regs));
 
-        show_trace((unsigned long *) &regs);
+        show_trace(NULL, (unsigned long *) &regs);
 }
+
+/* Copied from i386. */
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+	return	p > (void *)tinfo &&
+		p < (void *)tinfo + THREAD_SIZE - 3;
+}
+
+/* Adapted from i386 (we also print the address we read from). */
+static inline unsigned long print_context_stack(struct thread_info *tinfo,
+				unsigned long *stack, unsigned long ebp)
+{
+	unsigned long addr;
+
+#ifdef CONFIG_FRAME_POINTER
+	while (valid_stack_ptr(tinfo, (void *)ebp)) {
+		addr = *(unsigned long *)(ebp + 4);
+		printk("%08lx:  [<%08lx>]", ebp + 4, addr);
+		print_symbol(" %s", addr);
+		printk("\n");
+		ebp = *(unsigned long *)ebp;
+	}
+#else
+	while (valid_stack_ptr(tinfo, stack)) {
+		addr = *stack;
+		if (__kernel_text_address(addr)) {
+			printk("%08lx:  [<%08lx>]", (unsigned long) stack, addr);
+			print_symbol(" %s", addr);
+			printk("\n");
+		}
+		stack++;
+	}
+#endif
+	return ebp;
+}
+
+void show_trace(struct task_struct* task, unsigned long * stack)
+{
+	unsigned long ebp;
+	struct thread_info *context;
+
+	/* Turn this into BUG_ON if possible. */
+	if (!stack) {
+		stack = (unsigned long*) &stack;
+		printk("show_trace: got NULL stack, implicit assumption task == current");
+		WARN_ON(1);
+	}
+
+	if (!task)
+		task = current;
+
+	if (task != current) {
+		//ebp = (unsigned long) KSTK_EBP(task);
+		/* Which one? No actual difference - just coding style.*/
+		ebp = (unsigned long) PT_REGS_EBP(&task->thread.regs);
+	} else {
+		asm ("movl %%ebp, %0" : "=r" (ebp) : );
+	}
+
+	context = (struct thread_info *)
+		((unsigned long)stack & (~(THREAD_SIZE - 1)));
+	print_context_stack(context, stack, ebp);
+
+	/*while (((long) stack & (THREAD_SIZE-1)) != 0) {
+		addr = *stack;
+		if (__kernel_text_address(addr)) {
+			printk("%08lx:	[<%08lx>]", (unsigned long) stack, addr);
+			print_symbol(" %s", addr);
+			printk("\n");
+		}
+		stack++;
+	}*/
+	printk("\n");
+}
+
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-i386/user-offsets.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <signal.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <linux/stddef.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+	OFFSET(SC_IP, sigcontext, eip);
+	OFFSET(SC_SP, sigcontext, esp);
+	OFFSET(SC_FS, sigcontext, fs);
+	OFFSET(SC_GS, sigcontext, gs);
+	OFFSET(SC_DS, sigcontext, ds);
+	OFFSET(SC_ES, sigcontext, es);
+	OFFSET(SC_SS, sigcontext, ss);
+	OFFSET(SC_CS, sigcontext, cs);
+	OFFSET(SC_EFLAGS, sigcontext, eflags);
+	OFFSET(SC_EAX, sigcontext, eax);
+	OFFSET(SC_EBX, sigcontext, ebx);
+	OFFSET(SC_ECX, sigcontext, ecx);
+	OFFSET(SC_EDX, sigcontext, edx);
+	OFFSET(SC_EDI, sigcontext, edi);
+	OFFSET(SC_ESI, sigcontext, esi);
+	OFFSET(SC_EBP, sigcontext, ebp);
+	OFFSET(SC_TRAPNO, sigcontext, trapno);
+	OFFSET(SC_ERR, sigcontext, err);
+	OFFSET(SC_CR2, sigcontext, cr2);
+	OFFSET(SC_FPSTATE, sigcontext, fpstate);
+	OFFSET(SC_SIGMASK, sigcontext, oldmask);
+	OFFSET(SC_FP_CW, _fpstate, cw);
+	OFFSET(SC_FP_SW, _fpstate, sw);
+	OFFSET(SC_FP_TAG, _fpstate, tag);
+	OFFSET(SC_FP_IPOFF, _fpstate, ipoff);
+	OFFSET(SC_FP_CSSEL, _fpstate, cssel);
+	OFFSET(SC_FP_DATAOFF, _fpstate, dataoff);
+	OFFSET(SC_FP_DATASEL, _fpstate, datasel);
+	OFFSET(SC_FP_ST, _fpstate, _st);
+	OFFSET(SC_FXSR_ENV, _fpstate, _fxsr_env);
+
+	DEFINE(HOST_FRAME_SIZE, FRAME_SIZE);
+	DEFINE(HOST_FP_SIZE,
+		sizeof(struct user_i387_struct) / sizeof(unsigned long));
+	DEFINE(HOST_XFP_SIZE,
+	       sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
+
+	DEFINE(HOST_IP, EIP);
+	DEFINE(HOST_SP, UESP);
+	DEFINE(HOST_EFLAGS, EFL);
+	DEFINE(HOST_EAX, EAX);
+	DEFINE(HOST_EBX, EBX);
+	DEFINE(HOST_ECX, ECX);
+	DEFINE(HOST_EDX, EDX);
+	DEFINE(HOST_ESI, ESI);
+	DEFINE(HOST_EDI, EDI);
+	DEFINE(HOST_EBP, EBP);
+	DEFINE(HOST_CS, CS);
+	DEFINE(HOST_SS, SS);
+	DEFINE(HOST_DS, DS);
+	DEFINE(HOST_FS, FS);
+	DEFINE(HOST_ES, ES);
+	DEFINE(HOST_GS, GS);
+	DEFINE(__UM_FRAME_SIZE, sizeof(struct user_regs_struct));
+}
diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
--- a/arch/um/sys-i386/util/Makefile
+++ b/arch/um/sys-i386/util/Makefile
@@ -1,8 +1,5 @@
-
 hostprogs-y	:= mk_sc mk_thread
 always		:= $(hostprogs-y)
 
-mk_thread-objs	:= mk_thread_kern.o mk_thread_user.o
-
-HOSTCFLAGS_mk_thread_kern.o	:= $(CFLAGS) $(CPPFLAGS)
-HOSTCFLAGS_mk_thread_user.o	:= $(USER_CFLAGS)
+HOSTCFLAGS_mk_sc.o := -I$(objtree)/arch/um
+HOSTCFLAGS_mk_thread.o := -I$(objtree)/arch/um
diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
--- a/arch/um/sys-i386/util/mk_sc.c
+++ b/arch/um/sys-i386/util/mk_sc.c
@@ -1,52 +1,51 @@
 #include <stdio.h>
-#include <signal.h>
-#include <linux/stddef.h>
+#include <user-offsets.h>
 
 #define SC_OFFSET(name, field) \
-  printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
-	 offsetof(struct sigcontext, field))
+  printf("#define " #name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
+	 name)
 
 #define SC_FP_OFFSET(name, field) \
-  printf("#define " name \
+  printf("#define " #name \
 	 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
-	 offsetof(struct _fpstate, field))
+	 name)
 
 #define SC_FP_OFFSET_PTR(name, field, type) \
-  printf("#define " name \
+  printf("#define " #name \
 	 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
-	 offsetof(struct _fpstate, field))
+	 name)
 
 int main(int argc, char **argv)
 {
-  SC_OFFSET("SC_IP", eip);
-  SC_OFFSET("SC_SP", esp);
-  SC_OFFSET("SC_FS", fs);
-  SC_OFFSET("SC_GS", gs);
-  SC_OFFSET("SC_DS", ds);
-  SC_OFFSET("SC_ES", es);
-  SC_OFFSET("SC_SS", ss);
-  SC_OFFSET("SC_CS", cs);
-  SC_OFFSET("SC_EFLAGS", eflags);
-  SC_OFFSET("SC_EAX", eax);
-  SC_OFFSET("SC_EBX", ebx);
-  SC_OFFSET("SC_ECX", ecx);
-  SC_OFFSET("SC_EDX", edx);
-  SC_OFFSET("SC_EDI", edi);
-  SC_OFFSET("SC_ESI", esi);
-  SC_OFFSET("SC_EBP", ebp);
-  SC_OFFSET("SC_TRAPNO", trapno);
-  SC_OFFSET("SC_ERR", err);
-  SC_OFFSET("SC_CR2", cr2);
-  SC_OFFSET("SC_FPSTATE", fpstate);
-  SC_OFFSET("SC_SIGMASK", oldmask);
-  SC_FP_OFFSET("SC_FP_CW", cw);
-  SC_FP_OFFSET("SC_FP_SW", sw);
-  SC_FP_OFFSET("SC_FP_TAG", tag);
-  SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
-  SC_FP_OFFSET("SC_FP_CSSEL", cssel);
-  SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
-  SC_FP_OFFSET("SC_FP_DATASEL", datasel);
-  SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
-  SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
+  SC_OFFSET(SC_IP, eip);
+  SC_OFFSET(SC_SP, esp);
+  SC_OFFSET(SC_FS, fs);
+  SC_OFFSET(SC_GS, gs);
+  SC_OFFSET(SC_DS, ds);
+  SC_OFFSET(SC_ES, es);
+  SC_OFFSET(SC_SS, ss);
+  SC_OFFSET(SC_CS, cs);
+  SC_OFFSET(SC_EFLAGS, eflags);
+  SC_OFFSET(SC_EAX, eax);
+  SC_OFFSET(SC_EBX, ebx);
+  SC_OFFSET(SC_ECX, ecx);
+  SC_OFFSET(SC_EDX, edx);
+  SC_OFFSET(SC_EDI, edi);
+  SC_OFFSET(SC_ESI, esi);
+  SC_OFFSET(SC_EBP, ebp);
+  SC_OFFSET(SC_TRAPNO, trapno);
+  SC_OFFSET(SC_ERR, err);
+  SC_OFFSET(SC_CR2, cr2);
+  SC_OFFSET(SC_FPSTATE, fpstate);
+  SC_OFFSET(SC_SIGMASK, oldmask);
+  SC_FP_OFFSET(SC_FP_CW, cw);
+  SC_FP_OFFSET(SC_FP_SW, sw);
+  SC_FP_OFFSET(SC_FP_TAG, tag);
+  SC_FP_OFFSET(SC_FP_IPOFF, ipoff);
+  SC_FP_OFFSET(SC_FP_CSSEL, cssel);
+  SC_FP_OFFSET(SC_FP_DATAOFF, dataoff);
+  SC_FP_OFFSET(SC_FP_DATASEL, datasel);
+  SC_FP_OFFSET_PTR(SC_FP_ST, _st, "struct _fpstate");
+  SC_FP_OFFSET_PTR(SC_FXSR_ENV, _fxsr_env, "void");
   return(0);
 }
diff --git a/arch/um/sys-i386/util/mk_thread.c b/arch/um/sys-i386/util/mk_thread.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <kernel-offsets.h>
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_thread\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __UM_THREAD_H\n");
+  printf("#define __UM_THREAD_H\n");
+  printf("\n");
+  printf("#define TASK_DEBUGREGS(task) ((unsigned long *) "
+	 "&(((char *) (task))[%d]))\n", TASK_DEBUGREGS);
+#ifdef TASK_EXTERN_PID
+  printf("#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[%d]))\n",
+	 TASK_EXTERN_PID);
+#endif
+  printf("\n");
+  printf("#endif\n");
+  return(0);
+}
diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
deleted file mode 100644
--- a/arch/um/sys-i386/util/mk_thread_kern.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "linux/config.h"
-#include "linux/stddef.h"
-#include "linux/sched.h"
-
-extern void print_head(void);
-extern void print_constant_ptr(char *name, int value);
-extern void print_constant(char *name, char *type, int value);
-extern void print_tail(void);
-
-#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
-
-int main(int argc, char **argv)
-{
-  print_head();
-  print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
-#ifdef CONFIG_MODE_TT
-  print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
-#endif
-  print_tail();
-  return(0);
-}
-
diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
deleted file mode 100644
--- a/arch/um/sys-i386/util/mk_thread_user.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <stdio.h>
-
-void print_head(void)
-{
-  printf("/*\n");
-  printf(" * Generated by mk_thread\n");
-  printf(" */\n");
-  printf("\n");
-  printf("#ifndef __UM_THREAD_H\n");
-  printf("#define __UM_THREAD_H\n");
-  printf("\n");
-}
-
-void print_constant_ptr(char *name, int value)
-{
-  printf("#define %s(task) ((unsigned long *) "
-	 "&(((char *) (task))[%d]))\n", name, value);
-}
-
-void print_constant(char *name, char *type, int value)
-{
-  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, 
-	 value);
-}
-
-void print_tail(void)
-{
-  printf("\n");
-  printf("#endif\n");
-}
diff --git a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c
--- a/arch/um/sys-ppc/ptrace.c
+++ b/arch/um/sys-ppc/ptrace.c
@@ -8,6 +8,25 @@ int putreg(struct task_struct *child, un
 	return 0;
 }
 
+int poke_user(struct task_struct *child, long addr, long data)
+{
+	if ((addr & 3) || addr < 0)
+		return -EIO;
+
+	if (addr < MAX_REG_OFFSET)
+		return putreg(child, addr, data);
+
+	else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+		(addr <= offsetof(struct user, u_debugreg[7]))){
+		  addr -= offsetof(struct user, u_debugreg[0]);
+		  addr = addr >> 2;
+		  if((addr == 4) || (addr == 5)) return -EIO;
+		  child->thread.arch.debugregs[addr] = data;
+		  return 0;
+	}
+	return -EIO;
+}
+
 unsigned long getreg(struct task_struct *child, unsigned long regno)
 {
 	unsigned long retval = ~0UL;
@@ -16,6 +35,27 @@ unsigned long getreg(struct task_struct 
 	return retval;
 }
 
+int peek_user(struct task_struct *child, long addr, long data)
+{
+	/* read the word at location addr in the USER area. */
+	unsigned long tmp;
+
+	if ((addr & 3) || addr < 0)
+		return -EIO;
+
+	tmp = 0;  /* Default return condition */
+	if(addr < MAX_REG_OFFSET){
+		tmp = getreg(child, addr);
+	}
+	else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+		(addr <= offsetof(struct user, u_debugreg[7]))){
+		addr -= offsetof(struct user, u_debugreg[0]);
+		addr = addr >> 2;
+		tmp = child->thread.arch.debugregs[addr];
+	}
+	return put_user(tmp, (unsigned long *) data);
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c
--- a/arch/um/sys-ppc/ptrace_user.c
+++ b/arch/um/sys-ppc/ptrace_user.c
@@ -1,4 +1,3 @@
-#include <sys/ptrace.h>
 #include <errno.h>
 #include <asm/ptrace.h>
 #include "sysdep/ptrace.h"
@@ -8,7 +7,7 @@ int ptrace_getregs(long pid, unsigned lo
     int i;
     for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
 	errno = 0;
-	regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0);
+	regs_out->regs[i] = ptrace(PTRACE_PEEKUSR, pid, i*4, 0);
 	if (errno) {
 	    return -errno;
 	}
@@ -21,7 +20,7 @@ int ptrace_setregs(long pid, unsigned lo
     int i;
     for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
 	if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
-	    if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) {
+	    if (ptrace(PTRACE_POKEUSR, pid, i*4, regs_in->regs[i]) < 0) {
 		return -errno;
 	    }
 	}
diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c
--- a/arch/um/sys-ppc/sysrq.c
+++ b/arch/um/sys-ppc/sysrq.c
@@ -27,17 +27,5 @@ void show_regs(struct pt_regs_subarch *r
                 0xffff & regs->xds, 0xffff & regs->xes);
 #endif
 
-        show_trace(&regs->gpr[1]);
+        show_trace(current, &regs->gpr[1]);
 }
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -4,18 +4,20 @@
 # Licensed under the GPL
 #
 
+#XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
 	ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
-	syscalls.o sysrq.o thunk.o
+	syscalls.o sysrq.o thunk.o syscall_table.o
+
+obj-y := ksyms.o
+obj-$(CONFIG_MODULES) += module.o um_module.o
 
 USER_OBJS := ptrace_user.o sigcontext.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
-	semaphore.c thunk.S
-SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
+	semaphore.c thunk.S module.c
 
-clean-files := $(SYMLINKS)
+include arch/um/scripts/Makefile.rules
 
 bitops.c-dir = lib
 csum-copy.S-dir = lib
@@ -24,16 +26,6 @@ csum-wrappers.c-dir = lib
 memcpy.S-dir = lib
 semaphore.c-dir = kernel
 thunk.S-dir = lib
+module.c-dir = kernel
 
-define make_link
-       -rm -f $1
-       ln -sf $(TOPDIR)/arch/x86_64/$($(notdir $1)-dir)/$(notdir $1) $1
-endef
-
-$(SYMLINKS):
-	$(call make_link,$@)
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial
+subdir- := util
diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c
--- a/arch/um/sys-x86_64/delay.c
+++ b/arch/um/sys-x86_64/delay.c
@@ -5,22 +5,37 @@
  * Licensed under the GPL
  */
 
-#include "asm/processor.h"
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/processor.h>
+#include <asm/param.h>
 
 void __delay(unsigned long loops)
 {
 	unsigned long i;
 
-	for(i = 0; i < loops; i++) ;
+        for(i = 0; i < loops; i++)
+                cpu_relax();
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+void __udelay(unsigned long usecs)
+{
+	unsigned long i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+        for(i=0;i<n;i++)
+                cpu_relax();
+}
+
+EXPORT_SYMBOL(__udelay);
+
+void __const_udelay(unsigned long usecs)
+{
+	unsigned long i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+        for(i=0;i<n;i++)
+                cpu_relax();
+}
+
+EXPORT_SYMBOL(__const_udelay);
diff --git a/arch/um/sys-x86_64/kernel-offsets.c b/arch/um/sys-x86_64/kernel-offsets.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/kernel-offsets.c
@@ -0,0 +1,24 @@
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <asm/page.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define DEFINE_STR1(x) #x
+#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " DEFINE_STR1(val) " " #val: : )
+
+#define BLANK() asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+#ifdef CONFIG_MODE_TT
+	OFFSET(TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+#endif
+#include <common-offsets.h>
+}
diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/ksyms.c
@@ -0,0 +1,19 @@
+#include "linux/module.h"
+#include "linux/in6.h"
+#include "linux/rwsem.h"
+#include "asm/byteorder.h"
+#include "asm/semaphore.h"
+#include "asm/uaccess.h"
+#include "asm/checksum.h"
+#include "asm/errno.h"
+
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__down_failed_trylock);
+EXPORT_SYMBOL(__up_wakeup);
+
+/*XXX: we need them because they would be exported by x86_64 */
+EXPORT_SYMBOL(__memcpy);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(ip_compute_csum);
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -5,10 +5,11 @@
  */
 
 #define __FRAME_OFFSETS
-#include "asm/ptrace.h"
-#include "linux/sched.h"
-#include "linux/errno.h"
-#include "asm/elf.h"
+#include <asm/ptrace.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/elf.h>
 
 /* XXX x86_64 */
 unsigned long not_ss;
@@ -62,6 +63,27 @@ int putreg(struct task_struct *child, in
 	return 0;
 }
 
+int poke_user(struct task_struct *child, long addr, long data)
+{
+        if ((addr & 3) || addr < 0)
+                return -EIO;
+
+        if (addr < MAX_REG_OFFSET)
+                return putreg(child, addr, data);
+
+#if 0 /* Need x86_64 debugregs handling */
+        else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+                (addr <= offsetof(struct user, u_debugreg[7]))){
+                addr -= offsetof(struct user, u_debugreg[0]);
+                addr = addr >> 2;
+                if((addr == 4) || (addr == 5)) return -EIO;
+                child->thread.arch.debugregs[addr] = data;
+                return 0;
+        }
+#endif
+        return -EIO;
+}
+
 unsigned long getreg(struct task_struct *child, int regno)
 {
 	unsigned long retval = ~0UL;
@@ -84,6 +106,29 @@ unsigned long getreg(struct task_struct 
 	return retval;
 }
 
+int peek_user(struct task_struct *child, long addr, long data)
+{
+	/* read the word at location addr in the USER area. */
+        unsigned long tmp;
+
+        if ((addr & 3) || addr < 0)
+                return -EIO;
+
+        tmp = 0;  /* Default return condition */
+        if(addr < MAX_REG_OFFSET){
+                tmp = getreg(child, addr);
+        }
+#if 0 /* Need x86_64 debugregs handling */
+        else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+                (addr <= offsetof(struct user, u_debugreg[7]))){
+                addr -= offsetof(struct user, u_debugreg[0]);
+                addr = addr >> 2;
+                tmp = child->thread.arch.debugregs[addr];
+        }
+#endif
+        return put_user(tmp, (unsigned long *) data);
+}
+
 void arch_switch(void)
 {
 /* XXX
diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c
--- a/arch/um/sys-x86_64/ptrace_user.c
+++ b/arch/um/sys-x86_64/ptrace_user.c
@@ -6,9 +6,7 @@
 
 #include <stddef.h>
 #include <errno.h>
-#define __FRAME_OFFSETS
-#include <sys/ptrace.h>
-#include <asm/ptrace.h>
+#include "ptrace_user.h"
 #include "user.h"
 #include "kern_constants.h"
 
@@ -42,23 +40,12 @@ void arch_enter_kernel(void *task, int p
 void arch_leave_kernel(void *task, int pid)
 {
 #ifdef UM_USER_CS
-	if(ptrace(PTRACE_POKEUSER, pid, CS, UM_USER_CS) < 0)
-		tracer_panic("POKEUSER CS failed");
+        if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0)
+                printk("POKEUSR CS failed");
 #endif
 
-	if(ptrace(PTRACE_POKEUSER, pid, DS, __USER_DS) < 0)
-		tracer_panic("POKEUSER DS failed");
-	if(ptrace(PTRACE_POKEUSER, pid, ES, __USER_DS) < 0)
-		tracer_panic("POKEUSER ES failed");
+        if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0)
+                printk("POKEUSR DS failed");
+        if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0)
+                printk("POKEUSR ES failed");
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -57,7 +57,7 @@ static int copy_sc_from_user_skas(struct
 int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
                         struct pt_regs *regs, unsigned long mask)
 {
-	unsigned long eflags;
+        struct faultinfo * fi = &current->thread.arch.faultinfo;
 	int err = 0;
 
 	err |= __put_user(0, &to->gs);
@@ -84,14 +84,16 @@ int copy_sc_to_user_skas(struct sigconte
 	err |= PUTREG(regs, R14, to, r14);
 	err |= PUTREG(regs, R15, to, r15);
 	err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */
-	err |= __put_user(current->thread.err, &to->err);
-	err |= __put_user(current->thread.trap_no, &to->trapno);
+
+        err |= __put_user(fi->cr2, &to->cr2);
+        err |= __put_user(fi->error_code, &to->err);
+        err |= __put_user(fi->trap_no, &to->trapno);
+
 	err |= PUTREG(regs, RIP, to, rip);
 	err |= PUTREG(regs, EFLAGS, to, eflags);
 #undef PUTREG
 
 	err |= __put_user(mask, &to->oldmask);
-	err |= __put_user(current->thread.cr2, &to->cr2);
 
 	return(err);
 }
@@ -166,7 +168,7 @@ int setup_signal_stack_si(unsigned long 
 
 	frame = (struct rt_sigframe __user *)
 		round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8;
-	frame -= 128;
+	((unsigned char *) frame) -= 128;
 
 	if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
 		goto out;
@@ -237,7 +239,7 @@ int setup_signal_stack_si(unsigned long 
 
 long sys_rt_sigreturn(struct pt_regs *regs)
 {
-	unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
+	unsigned long sp = PT_REGS_SP(&current->thread.regs);
 	struct rt_sigframe __user *frame =
 		(struct rt_sigframe __user *)(sp - 8);
 	struct ucontext __user *uc = &frame->uc;
diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/syscall_table.c
@@ -0,0 +1,59 @@
+/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
+ * with some changes for UML. */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+#include <linux/config.h>
+
+#define __NO_STUBS
+
+/* Below you can see, in terms of #define's, the differences between the x86-64
+ * and the UML syscall table. */
+
+/* Not going to be implemented by UML, since we have no hardware. */
+#define stub_iopl sys_ni_syscall
+#define sys_ioperm sys_ni_syscall
+
+/* The UML TLS problem. Note that x86_64 does not implement this, so the below
+ * is needed only for the ia32 compatibility. */
+/*#define sys_set_thread_area sys_ni_syscall
+#define sys_get_thread_area sys_ni_syscall*/
+
+/* For __NR_time. The x86-64 name hopefully will change from sys_time64 to
+ * sys_time (since the current situation is bogus). I've sent a patch to cleanup
+ * this. Remove below the obsoleted line. */
+#define sys_time64 um_time
+#define sys_time um_time
+
+/* On UML we call it this way ("old" means it's not mmap2) */
+#define sys_mmap old_mmap
+/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
+ * See arch/x86_64/kernel/sys_x86_64.c */
+#define sys_uname sys_uname64
+
+#define stub_clone sys_clone
+#define stub_fork sys_fork
+#define stub_vfork sys_vfork
+#define stub_execve sys_execve
+#define stub_rt_sigsuspend sys_rt_sigsuspend
+#define stub_sigaltstack sys_sigaltstack
+#define stub_rt_sigreturn sys_rt_sigreturn
+
+#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 --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -7,18 +7,25 @@
 #include "linux/linkage.h"
 #include "linux/slab.h"
 #include "linux/shm.h"
+#include "linux/utsname.h"
+#include "linux/personality.h"
 #include "asm/uaccess.h"
 #define __FRAME_OFFSETS
 #include "asm/ptrace.h"
 #include "asm/unistd.h"
 #include "asm/prctl.h" /* XXX This should get the constants from libc */
 #include "choose-mode.h"
+#include "kern.h"
 
-asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
+asmlinkage long sys_uname64(struct new_utsname __user * name)
 {
-	unsigned long raddr;
-
-	return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr;
+	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;
 }
 
 #ifdef CONFIG_MODE_TT
@@ -29,22 +36,20 @@ long sys_modify_ldt_tt(int func, void *p
 	/* XXX This should check VERIFY_WRITE depending on func, check this
 	 * in i386 as well.
 	 */
-	if(verify_area(VERIFY_READ, ptr, bytecount))
-		return(-EFAULT);
+	if (!access_ok(VERIFY_READ, ptr, bytecount))
+		return -EFAULT;
 	return(modify_ldt(func, ptr, bytecount));
 }
 #endif
 
 #ifdef CONFIG_MODE_SKAS
-extern int userspace_pid;
+extern int userspace_pid[];
 
-#ifndef __NR_mm_indirect
-#define __NR_mm_indirect 241
-#endif
+#include "skas_ptrace.h"
 
 long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
 {
-	unsigned long args[6];
+	struct ptrace_ldt ldt;
         void *buf;
         int res, n;
 
@@ -66,12 +71,11 @@ long sys_modify_ldt_skas(int func, void 
                 goto out;
         }
 
-	args[0] = func;
-	args[1] = (unsigned long) buf;
-	args[2] = bytecount;
-	res = syscall(__NR_mm_indirect, &current->mm->context.u,
-		      __NR_modify_ldt, args);
-
+	ldt = ((struct ptrace_ldt) { .func	= func,
+				     .ptr	= buf,
+				     .bytecount = bytecount });
+#warning Need to look up userspace_pid by cpu
+	res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
         if(res < 0)
                 goto out;
 
@@ -129,23 +133,27 @@ static long arch_prctl_tt(int code, unsi
 
 #ifdef CONFIG_MODE_SKAS
 
+/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */
 static long arch_prctl_skas(int code, unsigned long addr)
 {
 	long ret = 0;
 
 	switch(code){
-	case ARCH_SET_GS:
-		current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
-		break;
 	case ARCH_SET_FS:
 		current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
 		break;
+	case ARCH_SET_GS:
+		current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
+		break;
 	case ARCH_GET_FS:
-		ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr);
+		ret = put_user(current->thread.regs.regs.skas.
+				regs[FS_BASE / sizeof(unsigned long)],
+				(unsigned long __user *)addr);
 	        break;
 	case ARCH_GET_GS:
-		ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \
-long)], &addr);
+		ret = put_user(current->thread.regs.regs.skas.
+				regs[GS_BASE / sizeof(unsigned long)],
+				(unsigned long __user *)addr);
 	        break;
 	default:
 		ret = -EINVAL;
diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c
--- a/arch/um/sys-x86_64/sysrq.c
+++ b/arch/um/sys-x86_64/sysrq.c
@@ -36,14 +36,5 @@ void __show_regs(struct pt_regs * regs)
 void show_regs(struct pt_regs *regs)
 {
 	__show_regs(regs);
-	show_trace((unsigned long *) &regs);
+	show_trace(current, (unsigned long *) &regs);
 }
-
-/* Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/um_module.c
@@ -0,0 +1,19 @@
+#include <linux/vmalloc.h>
+#include <linux/moduleloader.h>
+
+/*Copied from i386 arch/i386/kernel/module.c */
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc_exec(size);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/user-offsets.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <signal.h>
+#define __FRAME_OFFSETS
+#include <asm/ptrace.h>
+#include <asm/types.h>
+/* For some reason, x86_64 defines u64 and u32 only in <pci/types.h>, which I
+ * refuse to include here, even though they're used throughout the headers.
+ * These are used in asm/user.h, and that include can't be avoided because of
+ * the sizeof(struct user_regs_struct) below.
+ */
+typedef __u64 u64;
+typedef __u32 u32;
+#include <asm/user.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+	OFFSET(SC_RBX, sigcontext, rbx);
+	OFFSET(SC_RCX, sigcontext, rcx);
+	OFFSET(SC_RDX, sigcontext, rdx);
+	OFFSET(SC_RSI, sigcontext, rsi);
+	OFFSET(SC_RDI, sigcontext, rdi);
+	OFFSET(SC_RBP, sigcontext, rbp);
+	OFFSET(SC_RAX, sigcontext, rax);
+	OFFSET(SC_R8, sigcontext, r8);
+	OFFSET(SC_R9, sigcontext, r9);
+	OFFSET(SC_R10, sigcontext, r10);
+	OFFSET(SC_R11, sigcontext, r11);
+	OFFSET(SC_R12, sigcontext, r12);
+	OFFSET(SC_R13, sigcontext, r13);
+	OFFSET(SC_R14, sigcontext, r14);
+	OFFSET(SC_R15, sigcontext, r15);
+	OFFSET(SC_IP, sigcontext, rip);
+	OFFSET(SC_SP, sigcontext, rsp);
+	OFFSET(SC_CR2, sigcontext, cr2);
+	OFFSET(SC_ERR, sigcontext, err);
+	OFFSET(SC_TRAPNO, sigcontext, trapno);
+	OFFSET(SC_CS, sigcontext, cs);
+	OFFSET(SC_FS, sigcontext, fs);
+	OFFSET(SC_GS, sigcontext, gs);
+	OFFSET(SC_EFLAGS, sigcontext, eflags);
+	OFFSET(SC_SIGMASK, sigcontext, oldmask);
+#if 0
+	OFFSET(SC_ORIG_RAX, sigcontext, orig_rax);
+	OFFSET(SC_DS, sigcontext, ds);
+	OFFSET(SC_ES, sigcontext, es);
+	OFFSET(SC_SS, sigcontext, ss);
+#endif
+
+	DEFINE(HOST_FRAME_SIZE, FRAME_SIZE);
+	DEFINE(HOST_RBX, RBX);
+	DEFINE(HOST_RCX, RCX);
+	DEFINE(HOST_RDI, RDI);
+	DEFINE(HOST_RSI, RSI);
+	DEFINE(HOST_RDX, RDX);
+	DEFINE(HOST_RBP, RBP);
+	DEFINE(HOST_RAX, RAX);
+	DEFINE(HOST_R8, R8);
+	DEFINE(HOST_R9, R9);
+	DEFINE(HOST_R10, R10);
+	DEFINE(HOST_R11, R11);
+	DEFINE(HOST_R12, R12);
+	DEFINE(HOST_R13, R13);
+	DEFINE(HOST_R14, R14);
+	DEFINE(HOST_R15, R15);
+	DEFINE(HOST_ORIG_RAX, ORIG_RAX);
+	DEFINE(HOST_CS, CS);
+	DEFINE(HOST_SS, SS);
+	DEFINE(HOST_EFLAGS, EFLAGS);
+#if 0
+	DEFINE(HOST_FS, FS);
+	DEFINE(HOST_GS, GS);
+	DEFINE(HOST_DS, DS);
+	DEFINE(HOST_ES, ES);
+#endif
+
+	DEFINE(HOST_IP, RIP);
+	DEFINE(HOST_SP, RSP);
+	DEFINE(__UM_FRAME_SIZE, sizeof(struct user_regs_struct));
+}
diff --git a/arch/um/sys-x86_64/util/Makefile b/arch/um/sys-x86_64/util/Makefile
--- a/arch/um/sys-x86_64/util/Makefile
+++ b/arch/um/sys-x86_64/util/Makefile
@@ -4,7 +4,5 @@
 hostprogs-y	:= mk_sc mk_thread
 always		:= $(hostprogs-y)
 
-mk_thread-objs	:= mk_thread_kern.o mk_thread_user.o
-
-HOSTCFLAGS_mk_thread_kern.o	:= $(CFLAGS) $(CPPFLAGS)
-HOSTCFLAGS_mk_thread_user.o	:= $(USER_CFLAGS)
+HOSTCFLAGS_mk_sc.o := -I$(objtree)/arch/um
+HOSTCFLAGS_mk_thread.o := -I$(objtree)/arch/um
diff --git a/arch/um/sys-x86_64/util/mk_sc.c b/arch/um/sys-x86_64/util/mk_sc.c
--- a/arch/um/sys-x86_64/util/mk_sc.c
+++ b/arch/um/sys-x86_64/util/mk_sc.c
@@ -3,56 +3,45 @@
  */
 
 #include <stdio.h>
-#include <signal.h>
-#include <linux/stddef.h>
+#include <user-offsets.h>
 
-#define SC_OFFSET(name, field) \
-  printf("#define " name \
-	 "(sc) *((unsigned long *) &(((char *) (sc))[%ld]))\n",\
-	 offsetof(struct sigcontext, field))
-
-#define SC_FP_OFFSET(name, field) \
-  printf("#define " name \
-	 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%ld]))\n",\
-	 offsetof(struct _fpstate, field))
-
-#define SC_FP_OFFSET_PTR(name, field, type) \
-  printf("#define " name \
-	 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
-	 offsetof(struct _fpstate, field))
+#define SC_OFFSET(name) \
+  printf("#define " #name \
+	 "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
+	 name)
 
 int main(int argc, char **argv)
 {
-  SC_OFFSET("SC_RBX", rbx);
-  SC_OFFSET("SC_RCX", rcx);
-  SC_OFFSET("SC_RDX", rdx);
-  SC_OFFSET("SC_RSI", rsi);
-  SC_OFFSET("SC_RDI", rdi);
-  SC_OFFSET("SC_RBP", rbp);
-  SC_OFFSET("SC_RAX", rax);
-  SC_OFFSET("SC_R8", r8);
-  SC_OFFSET("SC_R9", r9);
-  SC_OFFSET("SC_R10", r10);
-  SC_OFFSET("SC_R11", r11);
-  SC_OFFSET("SC_R12", r12);
-  SC_OFFSET("SC_R13", r13);
-  SC_OFFSET("SC_R14", r14);
-  SC_OFFSET("SC_R15", r15);
-  SC_OFFSET("SC_IP", rip);
-  SC_OFFSET("SC_SP", rsp);
-  SC_OFFSET("SC_CR2", cr2);
-  SC_OFFSET("SC_ERR", err);
-  SC_OFFSET("SC_TRAPNO", trapno);
-  SC_OFFSET("SC_CS", cs);
-  SC_OFFSET("SC_FS", fs);
-  SC_OFFSET("SC_GS", gs);
-  SC_OFFSET("SC_EFLAGS", eflags);
-  SC_OFFSET("SC_SIGMASK", oldmask);
+  SC_OFFSET(SC_RBX);
+  SC_OFFSET(SC_RCX);
+  SC_OFFSET(SC_RDX);
+  SC_OFFSET(SC_RSI);
+  SC_OFFSET(SC_RDI);
+  SC_OFFSET(SC_RBP);
+  SC_OFFSET(SC_RAX);
+  SC_OFFSET(SC_R8);
+  SC_OFFSET(SC_R9);
+  SC_OFFSET(SC_R10);
+  SC_OFFSET(SC_R11);
+  SC_OFFSET(SC_R12);
+  SC_OFFSET(SC_R13);
+  SC_OFFSET(SC_R14);
+  SC_OFFSET(SC_R15);
+  SC_OFFSET(SC_IP);
+  SC_OFFSET(SC_SP);
+  SC_OFFSET(SC_CR2);
+  SC_OFFSET(SC_ERR);
+  SC_OFFSET(SC_TRAPNO);
+  SC_OFFSET(SC_CS);
+  SC_OFFSET(SC_FS);
+  SC_OFFSET(SC_GS);
+  SC_OFFSET(SC_EFLAGS);
+  SC_OFFSET(SC_SIGMASK);
 #if 0
-  SC_OFFSET("SC_ORIG_RAX", orig_rax);
-  SC_OFFSET("SC_DS", ds);
-  SC_OFFSET("SC_ES", es);
-  SC_OFFSET("SC_SS", ss);
+  SC_OFFSET(SC_ORIG_RAX);
+  SC_OFFSET(SC_DS);
+  SC_OFFSET(SC_ES);
+  SC_OFFSET(SC_SS);
 #endif
   return(0);
 }
diff --git a/arch/um/sys-x86_64/util/mk_thread.c b/arch/um/sys-x86_64/util/mk_thread.c
new file mode 100644
--- /dev/null
+++ b/arch/um/sys-x86_64/util/mk_thread.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <kernel-offsets.h>
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_thread\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __UM_THREAD_H\n");
+  printf("#define __UM_THREAD_H\n");
+  printf("\n");
+#ifdef TASK_EXTERN_PID
+  printf("#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[%d]))\n",
+	 TASK_EXTERN_PID);
+#endif
+  printf("\n");
+  printf("#endif\n");
+  return(0);
+}
diff --git a/arch/um/sys-x86_64/util/mk_thread_kern.c b/arch/um/sys-x86_64/util/mk_thread_kern.c
deleted file mode 100644
--- a/arch/um/sys-x86_64/util/mk_thread_kern.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "linux/config.h"
-#include "linux/stddef.h"
-#include "linux/sched.h"
-
-extern void print_head(void);
-extern void print_constant_ptr(char *name, int value);
-extern void print_constant(char *name, char *type, int value);
-extern void print_tail(void);
-
-#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
-
-int main(int argc, char **argv)
-{
-  print_head();
-#ifdef CONFIG_MODE_TT
-  print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
-#endif
-  print_tail();
-  return(0);
-}
-
diff --git a/arch/um/sys-x86_64/util/mk_thread_user.c b/arch/um/sys-x86_64/util/mk_thread_user.c
deleted file mode 100644
--- a/arch/um/sys-x86_64/util/mk_thread_user.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <stdio.h>
-
-void print_head(void)
-{
-  printf("/*\n");
-  printf(" * Generated by mk_thread\n");
-  printf(" */\n");
-  printf("\n");
-  printf("#ifndef __UM_THREAD_H\n");
-  printf("#define __UM_THREAD_H\n");
-  printf("\n");
-}
-
-void print_constant_ptr(char *name, int value)
-{
-  printf("#define %s(task) ((unsigned long *) "
-	 "&(((char *) (task))[%d]))\n", name, value);
-}
-
-void print_constant(char *name, char *type, int value)
-{
-  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
-	 value);
-}
-
-void print_tail(void)
-{
-  printf("\n");
-  printf("#endif\n");
-}
diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile
--- a/arch/um/util/Makefile
+++ b/arch/um/util/Makefile
@@ -1,8 +1,5 @@
 hostprogs-y		:= mk_task mk_constants
 always			:= $(hostprogs-y)
 
-mk_task-objs		:= mk_task_user.o mk_task_kern.o
-mk_constants-objs	:= mk_constants_user.o mk_constants_kern.o
-
-HOSTCFLAGS_mk_task_kern.o	:= $(CFLAGS) $(CPPFLAGS)
-HOSTCFLAGS_mk_constants_kern.o	:= $(CFLAGS) $(CPPFLAGS)
+HOSTCFLAGS_mk_task.o := -I$(objtree)/arch/um
+HOSTCFLAGS_mk_constants.o := -I$(objtree)/arch/um
diff --git a/arch/um/util/mk_constants.c b/arch/um/util/mk_constants.c
new file mode 100644
--- /dev/null
+++ b/arch/um/util/mk_constants.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <kernel-offsets.h>
+
+#define SHOW_INT(sym) printf("#define %s %d\n", #sym, sym)
+#define SHOW_STR(sym) printf("#define %s %s\n", #sym, sym)
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_constants\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __UM_CONSTANTS_H\n");
+  printf("#define __UM_CONSTANTS_H\n");
+  printf("\n");
+
+  SHOW_INT(UM_KERN_PAGE_SIZE);
+
+  SHOW_STR(UM_KERN_EMERG);
+  SHOW_STR(UM_KERN_ALERT);
+  SHOW_STR(UM_KERN_CRIT);
+  SHOW_STR(UM_KERN_ERR);
+  SHOW_STR(UM_KERN_WARNING);
+  SHOW_STR(UM_KERN_NOTICE);
+  SHOW_STR(UM_KERN_INFO);
+  SHOW_STR(UM_KERN_DEBUG);
+
+  SHOW_INT(UM_NSEC_PER_SEC);
+  printf("\n");
+  printf("#endif\n");
+  return(0);
+}
diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
deleted file mode 100644
--- a/arch/um/util/mk_constants_kern.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "linux/kernel.h"
-#include "linux/stringify.h"
-#include "linux/time.h"
-#include "asm/page.h"
-
-extern void print_head(void);
-extern void print_constant_str(char *name, char *value);
-extern void print_constant_int(char *name, int value);
-extern void print_tail(void);
-
-int main(int argc, char **argv)
-{
-  print_head();
-  print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
-
-  print_constant_str("UM_KERN_EMERG", KERN_EMERG);
-  print_constant_str("UM_KERN_ALERT", KERN_ALERT);
-  print_constant_str("UM_KERN_CRIT", KERN_CRIT);
-  print_constant_str("UM_KERN_ERR", KERN_ERR);
-  print_constant_str("UM_KERN_WARNING", KERN_WARNING);
-  print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
-  print_constant_str("UM_KERN_INFO", KERN_INFO);
-  print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
-
-  print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC);
-  print_tail();
-  return(0);
-}
diff --git a/arch/um/util/mk_constants_user.c b/arch/um/util/mk_constants_user.c
deleted file mode 100644
--- a/arch/um/util/mk_constants_user.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-
-void print_head(void)
-{
-  printf("/*\n");
-  printf(" * Generated by mk_constants\n");
-  printf(" */\n");
-  printf("\n");
-  printf("#ifndef __UM_CONSTANTS_H\n");
-  printf("#define __UM_CONSTANTS_H\n");
-  printf("\n");
-}
-
-void print_constant_str(char *name, char *value)
-{
-  printf("#define %s \"%s\"\n", name, value);
-}
-
-void print_constant_int(char *name, int value)
-{
-  printf("#define %s %d\n", name, value);
-}
-
-void print_tail(void)
-{
-  printf("\n");
-  printf("#endif\n");
-}
diff --git a/arch/um/util/mk_task.c b/arch/um/util/mk_task.c
new file mode 100644
--- /dev/null
+++ b/arch/um/util/mk_task.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <kernel-offsets.h>
+
+void print_ptr(char *name, char *type, int offset)
+{
+  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+void print(char *name, char *type, int offset)
+{
+  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_task\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __TASK_H\n");
+  printf("#define __TASK_H\n");
+  printf("\n");
+  print_ptr("TASK_REGS", "union uml_pt_regs", TASK_REGS);
+  print("TASK_PID", "int", TASK_PID);
+  printf("\n");
+  printf("#endif\n");
+  return(0);
+}
diff --git a/arch/um/util/mk_task_kern.c b/arch/um/util/mk_task_kern.c
deleted file mode 100644
--- a/arch/um/util/mk_task_kern.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "linux/sched.h"
-#include "linux/stddef.h"
-
-extern void print(char *name, char *type, int offset);
-extern void print_ptr(char *name, char *type, int offset);
-extern void print_head(void);
-extern void print_tail(void);
-
-int main(int argc, char **argv)
-{
-  print_head();
-  print_ptr("TASK_REGS", "union uml_pt_regs", 
-	    offsetof(struct task_struct, thread.regs));
-  print("TASK_PID", "int", offsetof(struct task_struct, pid));
-  print_tail();
-  return(0);
-}
diff --git a/arch/um/util/mk_task_user.c b/arch/um/util/mk_task_user.c
deleted file mode 100644
--- a/arch/um/util/mk_task_user.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <stdio.h>
-
-void print(char *name, char *type, int offset)
-{
-  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
-	 offset);
-}
-
-void print_ptr(char *name, char *type, int offset)
-{
-  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
-	 offset);
-}
-
-void print_head(void)
-{
-  printf("/*\n");
-  printf(" * Generated by mk_task\n");
-  printf(" */\n");
-  printf("\n");
-  printf("#ifndef __TASK_H\n");
-  printf("#define __TASK_H\n");
-  printf("\n");
-}
-
-void print_tail(void)
-{
-  printf("\n");
-  printf("#endif\n");
-}
diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
--- a/arch/v850/kernel/ptrace.c
+++ b/arch/v850/kernel/ptrace.c
@@ -23,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/ptrace.h>
+#include <linux/signal.h>
 
 #include <asm/errno.h>
 #include <asm/ptrace.h>
@@ -208,7 +209,7 @@ int sys_ptrace(long request, long pid, l
 	/* Execute a single instruction. */
 	case PTRACE_SINGLESTEP:
 		rval = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 
 		/* Turn CHILD's single-step flag on or off.  */
diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c
--- a/arch/v850/kernel/setup.c
+++ b/arch/v850/kernel/setup.c
@@ -283,5 +283,4 @@ init_mem_alloc (unsigned long ram_start,
 	NODE_DATA(0)->node_mem_map = NULL;
 	free_area_init_node (0, NODE_DATA(0), zones_size,
 			     ADDR_TO_PAGE (PAGE_OFFSET), 0);
-	mem_map = NODE_DATA(0)->node_mem_map;
 }
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
--- a/arch/v850/kernel/signal.c
+++ b/arch/v850/kernel/signal.c
@@ -102,7 +102,7 @@ sys_sigaction(int sig, const struct old_
 
 	if (act) {
 		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 			return -EFAULT;
@@ -114,7 +114,7 @@ sys_sigaction(int sig, const struct old_
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 			return -EFAULT;
@@ -178,7 +178,7 @@ asmlinkage int sys_sigreturn(struct pt_r
 	sigset_t set;
 	int rval;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -209,7 +209,7 @@ asmlinkage int sys_rt_sigreturn(struct p
 	stack_t st;
 	int rval;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
--- a/arch/v850/kernel/syscalls.c
+++ b/arch/v850/kernel/syscalls.c
@@ -62,7 +62,7 @@ sys_ipc (uint call, int first, int secon
 
 		if (!ptr)
 			break;
-		if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+		if ((ret = access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
 		    || (ret = get_user(fourth.__pad, (void **)ptr)))
 			break;
 		ret = sys_semctl (first, second, third, fourth);
@@ -78,7 +78,7 @@ sys_ipc (uint call, int first, int secon
 
 			if (!ptr)
 				break;
-			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+			if ((ret = access_ok(VERIFY_READ, ptr, sizeof(tmp)) ? 0 : -EFAULT)
 			    || (ret = copy_from_user(&tmp,
 						(struct ipc_kludge *) ptr,
 						sizeof (tmp))))
@@ -104,8 +104,8 @@ sys_ipc (uint call, int first, int secon
 		default: {
 			ulong raddr;
 
-			if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
-					       sizeof(ulong))))
+			if ((ret = access_ok(VERIFY_WRITE, (ulong*) third,
+					       sizeof(ulong)) ? 0 : -EFAULT))
 				break;
 			ret = do_shmat (first, (char *) ptr, second, &raddr);
 			if (ret)
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -53,23 +53,6 @@ config EARLY_PRINTK
 	bool
 	default y
 
-config HPET_TIMER
-	bool
-	default y
-	help
-	  Use the IA-PC HPET (High Precision Event Timer) to manage
-	  time in preference to the PIT and RTC, if a HPET is
-	  present.  The HPET provides a stable time base on SMP
-	  systems, unlike the RTC, but it is more expensive to access,
-	  as it is off-chip.  You can find the HPET spec at
-	  <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
-
-	  If unsure, say Y.
-
-config HPET_EMULATE_RTC
-	bool "Provide RTC interrupt"
-	depends on HPET_TIMER && RTC=y
-
 config GENERIC_ISA_DMA
 	bool
 	default y
@@ -254,7 +237,7 @@ config PREEMPT_BKL
 config SCHED_SMT
 	bool "SMT (Hyperthreading) scheduler support"
 	depends on SMP
-	default off
+	default n
 	help
 	  SMT scheduler support improves the CPU scheduler's decision making
 	  when dealing with Intel Pentium 4 chips with HyperThreading at a
@@ -309,6 +292,36 @@ config NR_CPUS
 	  This is purely to save memory - each supported CPU requires
 	  memory in the static kernel configuration.
 
+config HPET_TIMER
+	bool
+	default y
+	help
+	  Use the IA-PC HPET (High Precision Event Timer) to manage
+	  time in preference to the PIT and RTC, if a HPET is
+	  present.  The HPET provides a stable time base on SMP
+	  systems, unlike the TSC, but it is more expensive to access,
+	  as it is off-chip.  You can find the HPET spec at
+	  <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
+
+config X86_PM_TIMER
+	bool "PM timer"
+	depends on ACPI
+	default y
+	help
+	  Support the ACPI PM timer for time keeping. This is slow,
+	  but is useful on some chipsets without HPET on systems with more
+	  than one CPU. On a single processor or single socket multi core
+	  system it is normally not required.
+	  When the PM timer is active 64bit vsyscalls are disabled
+	  and should not be enabled (/proc/sys/kernel/vsyscall64 should
+	  not be changed).
+	  The kernel selects the PM timer only as a last resort, so it is
+	  useful to enable just in case.
+
+config HPET_EMULATE_RTC
+	bool "Provide RTC interrupt"
+	depends on HPET_TIMER && RTC=y
+
 config GART_IOMMU
 	bool "IOMMU support"
 	depends on PCI
@@ -350,6 +363,24 @@ config X86_MCE_INTEL
 	help
 	   Additional support for intel specific MCE features such as
 	   the thermal monitor.
+
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
 #
@@ -363,6 +394,11 @@ config GENERIC_IRQ_PROBE
 	bool
 	default y
 
+# we have no ISA slots, but we do have ISA-style DMA.
+config ISA_DMA_API
+	bool
+	default y
+
 menu "Power management options"
 
 source kernel/power/Kconfig
@@ -386,7 +422,7 @@ config PCI_DIRECT
 
 config PCI_MMCONFIG
 	bool "Support mmconfig PCI config space access"
-	depends on PCI
+	depends on PCI && ACPI
 	select ACPI_BOOT
 
 config UNORDERED_IO
@@ -399,6 +435,8 @@ config UNORDERED_IO
 	 from i386. Requires that the driver writer used memory barriers
 	 properly.
 
+source "drivers/pci/pcie/Kconfig"
+
 source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
diff --git a/arch/x86_64/boot/bootsect.S b/arch/x86_64/boot/bootsect.S
--- a/arch/x86_64/boot/bootsect.S
+++ b/arch/x86_64/boot/bootsect.S
@@ -63,7 +63,7 @@ msg_loop:
 	jz	die
 	movb	$0xe, %ah
 	movw	$7, %bx
- 	int	$0x10
+	int	$0x10
 	jmp	msg_loop
 
 die:
@@ -71,7 +71,7 @@ die:
 	xorw	%ax, %ax
 	int	$0x16
 	int	$0x19
-	
+
 	# int 0x19 should never return.  In case it does anyway,
 	# invoke the BIOS reset code...
 	ljmp	$0xf000,$0xfff0
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -160,7 +160,7 @@ ramdisk_max:	.long 0xffffffff
 trampoline:	call	start_of_setup
 		.align 16
 					# The offset at this point is 0x240
-		.space  (0x7ff-0x240+1)	# E820 & EDD space (ending at 0x7ff)
+		.space  (0xeff-0x240+1)	# E820 & EDD space (ending at 0xeff)
 # End of setup header #####################################################
 
 start_of_setup:
@@ -412,9 +412,9 @@ jmpe820:
 	# sizeof(e820rec).
 	#
 good820:
-	movb	(E820NR), %al			# up to 32 entries
+	movb	(E820NR), %al			# up to 128 entries
 	cmpb	$E820MAX, %al
-	jnl	bail820
+	jae	bail820
 
 	incb	(E820NR)
 	movw	%di, %ax
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,17 +1,16 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-bk7
-# Fri Jan  7 06:27:52 2005
+# Linux kernel version: 2.6.12-rc4
+# Fri May 13 06:39:11 2005
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
 CONFIG_X86=y
 CONFIG_MMU=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_X86_CMPXCHG=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_HPET_TIMER=y
-CONFIG_HPET_EMULATE_RTC=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
 
@@ -21,6 +20,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -32,24 +32,27 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=18
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -89,12 +92,17 @@ CONFIG_DISCONTIGMEM=y
 CONFIG_NUMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_NR_CPUS=8
+CONFIG_HPET_TIMER=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
 CONFIG_GART_IOMMU=y
 CONFIG_SWIOTLB=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_INTEL=y
+CONFIG_SECCOMP=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Power management options
@@ -124,7 +132,7 @@ CONFIG_ACPI_NUMA=y
 # CONFIG_ACPI_IBM is not set
 CONFIG_ACPI_TOSHIBA=y
 CONFIG_ACPI_BLACKLIST_YEAR=2001
-CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_BUS=y
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
@@ -136,16 +144,16 @@ CONFIG_ACPI_SYSTEM=y
 # CPU Frequency scaling
 #
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_PROC_INTF=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_24_API=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_TABLE=y
 
 #
 # CPUFreq processor drivers
@@ -159,6 +167,7 @@ CONFIG_X86_ACPI_CPUFREQ=y
 # shared options
 #
 CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
+# CONFIG_X86_SPEEDSTEP_LIB is not set
 
 #
 # Bus options (PCI etc.)
@@ -167,9 +176,21 @@ CONFIG_PCI=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
 CONFIG_UNORDERED_IO=y
+# CONFIG_PCIEPORTBUS is not set
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
 
 #
 # Executable file formats / Emulations
@@ -191,6 +212,7 @@ CONFIG_UID16=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -216,6 +238,7 @@ CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -233,9 +256,10 @@ CONFIG_LBD=y
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_AS is not set
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -286,7 +310,8 @@ CONFIG_BLK_DEV_AMD74XX=y
 CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
 # CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
@@ -331,7 +356,7 @@ CONFIG_BLK_DEV_SD=y
 #
 # SCSI low-level drivers
 #
-CONFIG_BLK_DEV_3W_XXXX_RAID=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AACRAID is not set
@@ -352,6 +377,7 @@ CONFIG_SCSI_SATA=y
 CONFIG_SCSI_ATA_PIIX=y
 # CONFIG_SCSI_SATA_NV is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
 # CONFIG_SCSI_SATA_SX4 is not set
 # CONFIG_SCSI_SATA_SIL is not set
 # CONFIG_SCSI_SATA_SIS is not set
@@ -361,7 +387,6 @@ CONFIG_SCSI_SATA_VIA=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA 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_IPS is not set
@@ -369,7 +394,6 @@ CONFIG_SCSI_SATA_VIA=y
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR 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_QLA2XXX=y
@@ -378,6 +402,7 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -414,7 +439,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -479,7 +503,7 @@ CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=y
 
 #
 # ARCnet devices
@@ -502,8 +526,7 @@ CONFIG_MII=y
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
-CONFIG_AMD8111_ETH=y
-# CONFIG_AMD8111E_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 CONFIG_FORCEDETH=y
@@ -513,8 +536,8 @@ CONFIG_FORCEDETH=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=m
-CONFIG_8139TOO=m
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
@@ -597,18 +620,6 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -626,6 +637,19 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -647,6 +671,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -672,7 +697,7 @@ CONFIG_RTC=y
 #
 CONFIG_AGP=y
 CONFIG_AGP_AMD64=y
-# CONFIG_AGP_INTEL_MCH is not set
+CONFIG_AGP_INTEL=y
 # CONFIG_DRM is not set
 # CONFIG_MWAVE is not set
 CONFIG_RAW_DRIVER=y
@@ -680,7 +705,12 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 CONFIG_MAX_RAW_DEVS=256
-CONFIG_HANGCHECK_TIMER=y
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -711,7 +741,7 @@ CONFIG_HANGCHECK_TIMER=y
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
 
 #
 # Console display driver support
@@ -758,6 +788,8 @@ CONFIG_SOUND_ICH=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -769,8 +801,6 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -779,6 +809,8 @@ CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
 
@@ -796,12 +828,11 @@ CONFIG_USB_PRINTER=y
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT 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_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
@@ -827,7 +858,6 @@ CONFIG_USB_HIDINPUT=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
@@ -846,6 +876,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
 
 #
 # USB port drivers
@@ -861,7 +892,6 @@ CONFIG_USB_HIDINPUT=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
@@ -870,6 +900,8 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_CYTHERM is not set
 # CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -918,6 +950,10 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
 # CONFIG_REISERFS_FS_SECURITY is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -930,7 +966,7 @@ CONFIG_AUTOFS_FS=y
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 # CONFIG_UDF_FS is not set
 
@@ -1057,14 +1093,17 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=18
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
 CONFIG_INIT_DEBUG=y
 # CONFIG_IOMMU_DEBUG is not set
 CONFIG_KPROBES=y
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
--- a/arch/x86_64/ia32/ia32_aout.c
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -182,9 +182,9 @@ static int aout_core_dump(long signr, st
 
 /* make sure we actually have a data and stack area to dump */
 	set_fs(USER_DS);
-	if (verify_area(VERIFY_READ, (void *) (unsigned long)START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
+	if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 		dump.u_dsize = 0;
-	if (verify_area(VERIFY_READ, (void *) (unsigned long)START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
+	if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
 		dump.u_ssize = 0;
 
 	set_fs(KERNEL_DS);
@@ -313,7 +313,7 @@ static int load_aout_binary(struct linux
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
 
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -312,6 +312,10 @@ MODULE_AUTHOR("Eric Youngdale, Andi Klee
 
 static void elf32_init(struct pt_regs *);
 
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+#define arch_setup_additional_pages syscall32_setup_pages
+extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
+
 #include "../../../fs/binfmt_elf.c" 
 
 static void elf32_init(struct pt_regs *regs)
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -49,12 +49,12 @@ int copy_siginfo_to_user32(compat_siginf
 		return -EFAULT;
 
 	/* If you change siginfo_t structure, please make sure that
-		   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);
+	   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);
 
 	if (from->si_code < 0) {
@@ -72,6 +72,7 @@ int copy_siginfo_to_user32(compat_siginf
 			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);
+			/* FALL THROUGH */
 		default:
 		case __SI_KILL >> 16:
 			err |= __put_user(from->si_uid, &to->si_uid);
@@ -81,7 +82,8 @@ int copy_siginfo_to_user32(compat_siginf
 			break;
 		case __SI_TIMER >> 16:
 			err |= __put_user(from->si_overrun, &to->si_overrun); 
-			err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
+			err |= __put_user(ptr_to_compat(from->si_ptr),
+					&to->si_ptr);
 			break;
 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
 		case __SI_MESGQ >> 16:
@@ -205,14 +207,14 @@ ia32_restore_sigcontext(struct pt_regs *
 		sc, sc->err, sc->eip, sc->cs, sc->eflags);
 #endif
 #define COPY(x)		{ \
-	unsigned int reg;	\
+	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;				\
+	{ unsigned int cur; 						\
+	  unsigned short pre;						\
 	  err |= __get_user(pre, &sc->seg);				\
     	  asm volatile("movl %%" #seg ",%0" : "=r" (cur));		\
 	  pre |= mask; 							\
@@ -256,7 +258,7 @@ ia32_restore_sigcontext(struct pt_regs *
 		err |= __get_user(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
 		if (buf) {
-			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
 				goto badframe;
 			err |= restore_i387_ia32(current, buf, 0);
 		} else {
@@ -285,7 +287,7 @@ asmlinkage long sys32_sigreturn(struct p
 	sigset_t set;
 	unsigned int eax;
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_COMPAT_NSIG_WORDS > 1
@@ -317,7 +319,7 @@ asmlinkage long sys32_rt_sigreturn(struc
 
 	frame = (struct rt_sigframe __user *)(regs->rsp - 4);
 
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
@@ -377,19 +379,19 @@ ia32_setup_sigcontext(struct sigcontext_
 	err |= __put_user(current->thread.error_code, &sc->err);
 	err |= __put_user((u32)regs->rip, &sc->eip);
 	eflags = regs->eflags;
-	if (current->ptrace & PT_PTRACED) {
+	if (current->ptrace & PT_PTRACED)
 		eflags &= ~TF_MASK;
-	}
 	err |= __put_user((u32)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;
+		err = -EFAULT;
 	else { 
 		clear_used_math();
 		stts();
-	  err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), &sc->fpstate);
+		err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
+					&sc->fpstate);
 	}
 
 	/* non-iBCS2 extensions.. */
@@ -439,7 +441,7 @@ void ia32_setup_frame(int sig, struct k_
 
 	{
 		struct exec_domain *ed = current_thread_info()->exec_domain;
-	err |= __put_user((ed
+		err |= __put_user((ed
 		           && ed->signal_invmap
 		           && sig < 32
 		           ? ed->signal_invmap[sig]
@@ -449,7 +451,8 @@ void ia32_setup_frame(int sig, struct k_
 	if (err)
 		goto give_sigsegv;
 
-	err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+	err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs,
+					set->sig[0]);
 	if (err)
 		goto give_sigsegv;
 
@@ -528,10 +531,9 @@ void ia32_setup_rt_frame(int sig, struct
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-
 	{
 		struct exec_domain *ed = current_thread_info()->exec_domain;
-	err |= __put_user((ed
+		err |= __put_user((ed
 		    	   && ed->signal_invmap
 		    	   && sig < 32
 		    	   ? ed->signal_invmap[sig]
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -78,7 +78,7 @@ ENTRY(ia32_sysenter_target)
  	.quad 1b,ia32_badarg
  	.previous	
 	GET_THREAD_INFO(%r10)
-	testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
 	jnz  sysenter_tracesys
 sysenter_do_call:	
 	cmpl	$(IA32_NR_syscalls),%eax
@@ -163,7 +163,7 @@ ENTRY(ia32_cstar_target)
 	.quad 1b,ia32_badarg
 	.previous	
 	GET_THREAD_INFO(%r10)
-	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
 	jnz   cstar_tracesys
 cstar_do_call:	
 	cmpl $IA32_NR_syscalls,%eax
@@ -236,7 +236,7 @@ ENTRY(ia32_syscall)
 	   this could be a problem. */
 	SAVE_ARGS 0,0,1
 	GET_THREAD_INFO(%r10)
-	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
 	jnz ia32_tracesys
 ia32_do_syscall:	
 	cmpl $(IA32_NR_syscalls),%eax
@@ -590,7 +590,7 @@ ia32_sys_call_table:
 	.quad compat_sys_mq_notify
 	.quad compat_sys_mq_getsetattr
 	.quad quiet_ni_syscall		/* reserved for kexec */
-	.quad sys32_waitid
+	.quad compat_sys_waitid
 	.quad quiet_ni_syscall		/* sys_altroot */
 	.quad sys_add_key
 	.quad sys_request_key
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -65,7 +65,6 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-#include <asm/ipc.h>
 #include <asm/atomic.h>
 #include <asm/ldt.h>
 
@@ -85,7 +84,7 @@ int cp_compat_stat(struct kstat *kbuf, s
 		return -EOVERFLOW;
 	if (kbuf->size >= 0x7fffffff)
 		return -EOVERFLOW;
-	if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
 	    __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
 	    __put_user (kbuf->ino, &ubuf->st_ino) ||
 	    __put_user (kbuf->mode, &ubuf->st_mode) ||
@@ -128,7 +127,7 @@ cp_stat64(struct stat64 __user *ubuf, st
 	typeof(ubuf->st_gid) gid = 0;
 	SET_UID(uid, stat->uid);
 	SET_GID(gid, stat->gid);
-	if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
 	    __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
 	    __put_user (stat->ino, &ubuf->__st_ino) ||
 	    __put_user (stat->ino, &ubuf->st_ino) ||
@@ -262,7 +261,7 @@ sys32_rt_sigaction(int sig, struct sigac
 	if (act) {
 		compat_uptr_t handler, restorer;
 
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 		    __get_user(restorer, &act->sa_restorer)||
@@ -301,7 +300,7 @@ sys32_rt_sigaction(int sig, struct sigac
 			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)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
 		    __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
@@ -322,7 +321,7 @@ sys32_sigaction (int sig, struct old_sig
 		compat_old_sigset_t mask;
 		compat_uptr_t handler, restorer;
 
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 		    __get_user(restorer, &act->sa_restorer) ||
@@ -338,7 +337,7 @@ sys32_sigaction (int sig, struct old_sig
         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
 		    __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
@@ -567,7 +566,7 @@ sys32_sysinfo(struct sysinfo32 __user *i
 		s.freehigh >>= bitcount;
 	}
 
-	if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
+	if (!access_ok(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]) ||
@@ -782,7 +781,7 @@ sys32_adjtimex(struct timex32 __user *ut
 
 	memset(&txc, 0, sizeof(struct timex));
 
-	if(verify_area(VERIFY_READ, utp, sizeof(struct timex32)) ||
+	if (!access_ok(VERIFY_READ, utp, sizeof(struct timex32)) ||
 	   __get_user(txc.modes, &utp->modes) ||
 	   __get_user(txc.offset, &utp->offset) ||
 	   __get_user(txc.freq, &utp->freq) ||
@@ -807,7 +806,7 @@ sys32_adjtimex(struct timex32 __user *ut
 
 	ret = do_adjtimex(&txc);
 
-	if(verify_area(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
+	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
 	   __put_user(txc.modes, &utp->modes) ||
 	   __put_user(txc.offset, &utp->offset) ||
 	   __put_user(txc.freq, &utp->freq) ||
@@ -955,32 +954,6 @@ asmlinkage long sys32_clone(unsigned int
         return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 }
 
-asmlinkage long sys32_waitid(int which, compat_pid_t pid,
-			     compat_siginfo_t __user *uinfo, int options,
-			     struct compat_rusage __user *uru)
-{
-	siginfo_t info;
-	struct rusage ru;
-	long ret;
-	mm_segment_t old_fs = get_fs();
-
-	info.si_signo = 0;
-	set_fs (KERNEL_DS);
-	ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
-			 uru ? &ru : NULL);
-	set_fs (old_fs);
-
-	if (ret < 0 || info.si_signo == 0)
-		return ret;
-
-	if (uru && (ret = put_compat_rusage(&ru, uru)))
-		return ret;
-
-	BUG_ON(info.si_code & __SI_MASK);
-	info.si_code |= __SI_CHLD;
-	return copy_siginfo_to_user32(uinfo, &info);
-}
-
 /*
  * Some system calls that need sign extended arguments. This could be done by a generic wrapper.
  */ 
@@ -1019,31 +992,19 @@ asmlinkage long sys32_open(const char __
 	return fd;
 }
 
-struct sigevent32 { 
-	u32 sigev_value;
-	u32 sigev_signo; 
-	u32 sigev_notify; 
-	u32 payload[(64 / 4) - 3]; 
-}; 
-
 extern asmlinkage long
 sys_timer_create(clockid_t which_clock,
 		 struct sigevent __user *timer_event_spec,
 		 timer_t __user * created_timer_id);
 
 long
-sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id)
+sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id)
 {
 	struct sigevent __user *p = NULL;
 	if (se32) { 
 		struct sigevent se;
 		p = compat_alloc_user_space(sizeof(struct sigevent));
-		memset(&se, 0, sizeof(struct sigevent)); 
-		if (get_user(se.sigev_value.sival_int,  &se32->sigev_value) ||
-		    __get_user(se.sigev_signo, &se32->sigev_signo) ||
-		    __get_user(se.sigev_notify, &se32->sigev_notify) ||
-		    __copy_from_user(&se._sigev_un._pad, &se32->payload, 
-				     sizeof(se32->payload)) ||
+		if (get_compat_sigevent(&se, se32) ||
 		    copy_to_user(p, &se, sizeof(se)))
 			return -EFAULT;
 	} 
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -9,6 +9,7 @@
 #include <linux/gfp.h>
 #include <linux/init.h>
 #include <linux/stringify.h>
+#include <linux/security.h>
 #include <asm/proto.h>
 #include <asm/tlbflush.h>
 #include <asm/ia32_unistd.h>
@@ -30,51 +31,57 @@ extern int sysctl_vsyscall32;
 char *syscall32_page; 
 static int use_sysenter = -1;
 
-/*
- * Map the 32bit vsyscall page on demand.
- *
- * RED-PEN: This knows too much about high level VM.
- *
- * Alternative would be to generate a vma with appropriate backing options
- * and let it be handled by generic VM.
- */
-int __map_syscall32(struct mm_struct *mm, unsigned long address)
-{ 
-	pgd_t *pgd;
-	pud_t *pud;
-	pte_t *pte;
-	pmd_t *pmd;
-	int err = -ENOMEM;
-
-	spin_lock(&mm->page_table_lock); 
- 	pgd = pgd_offset(mm, address);
- 	pud = pud_alloc(mm, pgd, address);
- 	if (pud) {
- 		pmd = pmd_alloc(mm, pud, address);
- 		if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) {
- 			if (pte_none(*pte)) {
- 				set_pte(pte,
- 					mk_pte(virt_to_page(syscall32_page),
- 					       PAGE_KERNEL_VSYSCALL32));
- 			}
- 			/* Flush only the local CPU. Other CPUs taking a fault
- 			   will just end up here again
-			   This probably not needed and just paranoia. */
- 			__flush_tlb_one(address);
- 			err = 0;
-		}
-	}
-	spin_unlock(&mm->page_table_lock);
-	return err;
+static struct page *
+syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type)
+{
+	struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page);
+	get_page(p);
+	return p;
 }
 
-int map_syscall32(struct mm_struct *mm, unsigned long address)
+/* Prevent VMA merging */
+static void syscall32_vma_close(struct vm_area_struct *vma)
 {
-	int err;
-	down_read(&mm->mmap_sem);
-	err = __map_syscall32(mm, address);
-	up_read(&mm->mmap_sem);
-	return err;
+}
+
+static struct vm_operations_struct syscall32_vm_ops = {
+	.close = syscall32_vma_close,
+	.nopage = syscall32_nopage,
+};
+
+struct linux_binprm;
+
+/* Setup a VMA at program startup for the vsyscall page */
+int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
+{
+	int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
+
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (!vma)
+		return -ENOMEM;
+	if (security_vm_enough_memory(npages)) {
+		kmem_cache_free(vm_area_cachep, vma);
+		return -ENOMEM;
+	}
+
+	memset(vma, 0, sizeof(struct vm_area_struct));
+	/* Could randomize here */
+	vma->vm_start = VSYSCALL32_BASE;
+	vma->vm_end = VSYSCALL32_END;
+	/* MAYWRITE to allow gdb to COW and set breakpoints */
+	vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYEXEC|VM_MAYWRITE;
+	vma->vm_flags |= mm->def_flags;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+	vma->vm_ops = &syscall32_vm_ops;
+	vma->vm_mm = mm;
+
+	down_write(&mm->mmap_sem);
+	insert_vm_struct(mm, vma);
+	mm->total_vm += npages;
+	up_write(&mm->mmap_sem);
+	return 0;
 }
 
 static int __init init_syscall32(void)
@@ -82,7 +89,6 @@ static int __init init_syscall32(void)
 	syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); 
 	if (!syscall32_page) 
 		panic("Cannot allocate syscall32 page"); 
-	SetPageReserved(virt_to_page(syscall32_page));
  	if (use_sysenter > 0) {
  		memcpy(syscall32_page, syscall32_sysenter,
  		       syscall32_sysenter_end - syscall32_sysenter);
diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S
--- a/arch/x86_64/ia32/vsyscall-sigreturn.S
+++ b/arch/x86_64/ia32/vsyscall-sigreturn.S
@@ -118,3 +118,6 @@ __kernel_rt_sigreturn:
 
 	.align 4
 .LENDFDE3:
+
+#include "../../i386/kernel/vsyscall-note.S"
+
diff --git a/arch/x86_64/ia32/vsyscall.lds b/arch/x86_64/ia32/vsyscall.lds
--- a/arch/x86_64/ia32/vsyscall.lds
+++ b/arch/x86_64/ia32/vsyscall.lds
@@ -36,6 +36,7 @@ SECTIONS
 
   .text.rtsigreturn : { *(.text.rtsigreturn) }   :text =0x90909090
 	
+  .note		  : { *(.note.*) }		:text :note
   .eh_frame_hdr   : { *(.eh_frame_hdr) }	:text :eh_frame_hdr
   .eh_frame       : { KEEP (*(.eh_frame)) }	:text
   .dynamic        : { *(.dynamic) }		:text :dynamic
@@ -55,6 +56,7 @@ PHDRS
 {
   text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
   dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  note PT_NOTE FLAGS(4); /* PF_R */
   eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
 }
 
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_GART_IOMMU)	+= pci-gart.o a
 obj-$(CONFIG_DUMMY_IOMMU)	+= pci-nommu.o pci-dma.o
 obj-$(CONFIG_SWIOTLB)		+= swiotlb.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer.o
 
 obj-$(CONFIG_MODULES)		+= module.o
 
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -87,15 +87,6 @@ int acpi_save_state_mem (void)
 	return 0;
 }
 
-/**
- * acpi_save_state_disk - save kernel state to disk
- *
- */
-int acpi_save_state_disk (void)
-{
-	return 1;
-}
-
 /*
  * acpi_restore_state
  */
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -33,7 +33,7 @@ int fallback_aper_force __initdata = 0; 
 
 int fix_aperture __initdata = 1;
 
-/* This code runs before the PCI subsystem is initialized, so just 
+/* 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))
@@ -53,9 +53,9 @@ static u32 __init allocate_aperture(void
 	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
 
 	/* 
-	 * Aperture has to be naturally aligned. This means an 2GB aperture won't 
-	 * have much chances to find a place in the lower 4GB of memory. 
-	 * Unfortunately we cannot move it up because that would make the 
+	 * Aperture has to be naturally aligned. This means an 2GB aperture won't
+	 * have much chances to find a place 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); 
@@ -66,7 +66,7 @@ static u32 __init allocate_aperture(void
 			free_bootmem_node(nd0, (unsigned long)p, aper_size); 
 		return 0;
 	}
-	printk("Mapping aperture over %d KB of RAM @ %lx\n",  
+	printk("Mapping aperture over %d KB of RAM @ %lx\n",
 	       aper_size >> 10, __pa(p)); 
 	return (u32)__pa(p); 
 }
@@ -90,7 +90,7 @@ static int __init aperture_valid(char *n
 	return 1;
 } 
 
-/* Find a PCI capability */ 
+/* Find a PCI capability */
 static __u32 __init find_cap(int num, int slot, int func, int cap) 
 { 
 	u8 pos;
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -33,6 +33,7 @@
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
 #include <asm/mach_apic.h>
+#include <asm/nmi.h>
 
 int apic_verbosity;
 
@@ -457,7 +458,7 @@ static struct {
 	unsigned int apic_thmr;
 } apic_pm_state;
 
-static int lapic_suspend(struct sys_device *dev, u32 state)
+static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 {
 	unsigned long flags;
 
@@ -650,7 +651,7 @@ void __init init_apic_mappings(void)
 
 #define APIC_DIVISOR 16
 
-void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks)
 {
 	unsigned int lvtt_value, tmp_value, ver;
 
@@ -723,7 +724,7 @@ static void setup_APIC_timer(unsigned in
 
 #define TICK_COUNT 100000000
 
-int __init calibrate_APIC_clock(void)
+static int __init calibrate_APIC_clock(void)
 {
 	int apic, apic_start, tsc, tsc_start;
 	int result;
@@ -925,7 +926,7 @@ __init int oem_force_hpet_timer(void)
 	unsigned id;
 	DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
 
-	bitmap_empty(clustermap, NUM_APIC_CLUSTERS);
+	bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
 
 	for (i = 0; i < NR_CPUS; i++) {
 		id = bios_cpu_apicid[i];
@@ -1056,7 +1057,7 @@ int __init APIC_init_uniprocessor (void)
 		nr_ioapics = 0;
 #endif
 	setup_boot_APIC_clock();
-
+	check_nmi_watchdog();
 	return 0;
 }
 
diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c
--- a/arch/x86_64/kernel/asm-offsets.c
+++ b/arch/x86_64/kernel/asm-offsets.c
@@ -62,8 +62,8 @@ int main(void)
 	       offsetof (struct rt_sigframe32, uc.uc_mcontext));
 	BLANK();
 #endif
-	DEFINE(SIZEOF_PBE, sizeof(struct pbe));
 	DEFINE(pbe_address, offsetof(struct pbe, address));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+	DEFINE(pbe_next, offsetof(struct pbe, next));
 	return 0;
 }
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -6,22 +6,13 @@ menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
 
-config CPU_FREQ_TABLE
-       tristate "CPU frequency table helpers"
-       depends on CPU_FREQ
-       default y
-       help
-         Many CPUFreq drivers use these helpers, so only say N here if
-	 the CPUFreq driver of your choice doesn't need these helpers.
-
-	 If in doubt, say Y.
+if CPU_FREQ
 
 comment "CPUFreq processor drivers"
-       depends on CPU_FREQ
 
 config X86_POWERNOW_K8
 	tristate "AMD Opteron/Athlon64 PowerNow!"
-	depends on CPU_FREQ_TABLE
+	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
 
@@ -31,12 +22,14 @@ config X86_POWERNOW_K8
 
 config X86_POWERNOW_K8_ACPI
 	bool
-	depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+	depends on X86_POWERNOW_K8 && ACPI_PROCESSOR
+	depends on !(X86_POWERNOW_K8 = y && ACPI_PROCESSOR = m)
 	default y
 
 config X86_SPEEDSTEP_CENTRINO
 	tristate "Intel Enhanced SpeedStep"
-	depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
+	select CPU_FREQ_TABLE
+	depends on ACPI_PROCESSOR
 	help
 	  This adds the CPUFreq driver for Enhanced SpeedStep enabled
 	  mobile CPUs.  This means Intel Pentium M (Centrino) CPUs
@@ -53,7 +46,7 @@ config X86_SPEEDSTEP_CENTRINO_ACPI
 
 config X86_ACPI_CPUFREQ
 	tristate "ACPI Processor P-States driver"
-	depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
+	depends on ACPI_PROCESSOR
 	help
 	  This driver adds a CPUFreq driver which utilizes the ACPI
 	  Processor Performance States.
@@ -63,7 +56,6 @@ config X86_ACPI_CPUFREQ
 	  If in doubt, say N.
 
 comment "shared options"
-	depends on CPU_FREQ
 
 config X86_ACPI_CPUFREQ_PROC_INTF
         bool "/proc/acpi/processor/../performance interface (deprecated)"
@@ -78,7 +70,7 @@ config X86_ACPI_CPUFREQ_PROC_INTF
 
 config X86_P4_CLOCKMOD
 	tristate "Intel Pentium 4 clock modulation"
-	depends on CPU_FREQ_TABLE && EMBEDDED
+	depends on EMBEDDED
 	help
 	  This adds the clock modulation driver for Intel Pentium 4 / XEON
 	  processors.  When enabled it will lower CPU temperature by skipping
@@ -96,9 +88,9 @@ config X86_P4_CLOCKMOD
 
 config X86_SPEEDSTEP_LIB
         tristate
-        depends on (X86_P4_CLOCKMOD)
-        default (X86_P4_CLOCKMOD)
+        default X86_P4_CLOCKMOD
 
+endif
 
 endmenu
 
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -2,6 +2,12 @@
  * 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 $
+ *
+ *  Getting sanitize_e820_map() in sync with i386 version by applying change:
+ *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *     Alex Achenbach <xela@slit.de>, December 2002.
+ *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ *
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -277,7 +283,7 @@ static int __init sanitize_e820_map(stru
 	int chgidx, still_changing;
 	int overlap_entries;
 	int new_bios_entry;
-	int old_nr, new_nr;
+	int old_nr, new_nr, chg_nr;
 	int i;
 
 	/*
@@ -331,20 +337,24 @@ static int __init sanitize_e820_map(stru
 	for (i=0; i < 2*old_nr; i++)
 		change_point[i] = &change_point_list[i];
 
-	/* record all known change-points (starting and ending addresses) */
+	/* record all known change-points (starting and ending addresses),
+	   omitting those that are for empty memory regions */
 	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];
+		if (biosmap[i].size != 0) {
+			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];
+		}
 	}
+	chg_nr = chgidx;
 
 	/* 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++)  {
+		for (i=1; i < chg_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) ||
@@ -367,7 +377,7 @@ static int __init sanitize_e820_map(stru
 	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++)
+	for (chgidx=0; chgidx < chg_nr; chgidx++)
 	{
 		/* keep track of all overlapping bios entries */
 		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
@@ -507,21 +517,66 @@ void __init setup_memory_region(void)
 
 void __init parse_memopt(char *p, char **from) 
 { 
-	/*
-	 * mem=XXX[kKmM] limits kernel memory to XXX+1MB
-	 *
-	 * It would be more logical to count from 0 instead of from
-	 * HIGH_MEMORY, but we keep that for now for i386 compatibility. 
-	 *	
-	 * No support for custom mapping like i386.  The reason is
-	 * that we need to read the e820 map anyways to handle the
-	 * ACPI mappings in the direct map.  Also on x86-64 there
-	 * should be always a good e820 map. This is only an upper
-	 * limit, you cannot force usage of memory not in e820.
-	 *
-	 * -AK
-			 */
-	end_user_pfn = memparse(p, from) + HIGH_MEMORY;
+	end_user_pfn = memparse(p, from);
 	end_user_pfn >>= PAGE_SHIFT;	
 } 
 
+unsigned long pci_mem_start = 0xaeedbabe;
+
+/*
+ * Search for the biggest gap in the low 32 bits of the e820
+ * memory space.  We pass this space to PCI to assign MMIO resources
+ * for hotplug or unconfigured devices in.
+ * Hopefully the BIOS let enough space left.
+ */
+__init void e820_setup_gap(void)
+{
+	unsigned long gapstart, gapsize;
+	unsigned long last;
+	int i;
+	int found = 0;
+
+	last = 0x100000000ull;
+	gapstart = 0x10000000;
+	gapsize = 0x400000;
+	i = e820.nr_map;
+	while (--i >= 0) {
+		unsigned long long start = e820.map[i].addr;
+		unsigned long long end = start + e820.map[i].size;
+
+		/*
+		 * Since "last" is at most 4GB, we know we'll
+		 * fit in 32 bits if this condition is true
+		 */
+		if (last > end) {
+			unsigned long gap = last - end;
+
+			if (gap > gapsize) {
+				gapsize = gap;
+				gapstart = end;
+				found = 1;
+			}
+		}
+		if (start < last)
+			last = start;
+	}
+
+	if (!found) {
+		gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
+		printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n"
+		       KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n");
+	}
+
+	/*
+	 * Start allocating dynamic PCI memory a bit into the gap,
+	 * aligned up to the nearest megabyte.
+	 *
+	 * Question: should we try to pad it up a bit (do something
+	 * like " + (gapsize >> 3)" in there too?). We now have the
+	 * technology.
+	 */
+	pci_mem_start = (gapstart + 0xfffff) & ~0xfffff;
+
+	printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
+		pci_mem_start, gapstart, gapsize);
+}
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -60,7 +60,7 @@ static struct console early_vga_console 
 
 /* Serial functions loosely based on a similar package from Klaus P. Gerlicher */ 
 
-int early_serial_base = 0x3f8;  /* ttyS0 */ 
+static int early_serial_base = 0x3f8;  /* ttyS0 */
 
 #define XMTRDY          0x20
 
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -44,10 +44,7 @@
 
 	.code64
 
-#ifdef CONFIG_PREEMPT
-#define preempt_stop cli
-#else
-#define preempt_stop
+#ifndef CONFIG_PREEMPT
 #define retint_kernel retint_restore_args
 #endif	
 	
@@ -184,7 +181,7 @@ ENTRY(system_call)
 	movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
 	movq  %rcx,RIP-ARGOFFSET(%rsp)  
 	GET_THREAD_INFO(%rcx)
-	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
 	jnz tracesys
 	cmpq $__NR_syscall_max,%rax
 	ja badsys
@@ -197,7 +194,7 @@ ENTRY(system_call)
  */		
 	.globl ret_from_sys_call
 ret_from_sys_call:
-	movl $_TIF_WORK_MASK,%edi
+	movl $_TIF_ALLWORK_MASK,%edi
 	/* edi:	flagmask */
 sysret_check:		
 	GET_THREAD_INFO(%rcx)
@@ -289,6 +286,7 @@ int_careful:
 	pushq %rdi
 	call schedule
 	popq %rdi
+	cli
 	jmp int_with_check
 
 	/* handle signals and tracing -- both require a full stack frame */
@@ -302,9 +300,8 @@ int_very_careful:
 	leaq 8(%rsp),%rdi	# &ptregs -> arg1	
 	call syscall_trace_leave
 	popq %rdi
-	btr  $TIF_SYSCALL_TRACE,%edi
-	btr  $TIF_SYSCALL_AUDIT,%edi
-	btr  $TIF_SINGLESTEP,%edi
+	andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
+	cli
 	jmp int_restore_rest
 	
 int_signal:
@@ -316,6 +313,7 @@ int_signal:
 1:	movl $_TIF_NEED_RESCHED,%edi	
 int_restore_rest:
 	RESTORE_REST
+	cli
 	jmp int_with_check
 	CFI_ENDPROC
 		
@@ -460,7 +458,6 @@ retint_check:			
 	andl %edi,%edx
 	jnz  retint_careful
 retint_swapgs:	 	
-	cli
 	swapgs 
 retint_restore_args:				
 	cli
@@ -503,7 +500,7 @@ retint_signal:
 	RESTORE_REST
 	cli
 	movl $_TIF_NEED_RESCHED,%edi
-	GET_THREAD_INFO(%rcx)	
+	GET_THREAD_INFO(%rcx)
 	jmp retint_check
 
 #ifdef CONFIG_PREEMPT
@@ -516,13 +513,8 @@ retint_kernel:	
 	bt  $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
 	jnc  retint_restore_args
 	bt   $9,EFLAGS-ARGOFFSET(%rsp)	/* interrupts off? */
-	jc   retint_restore_args
-	movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx)
-	sti
-	call schedule
-	cli
-	GET_THREAD_INFO(%rcx)
-	movl $0,threadinfo_preempt_count(%rcx) 
+	jnc  retint_restore_args
+	call preempt_schedule_irq
 	jmp exit_intr
 #endif	
 	CFI_ENDPROC
@@ -594,6 +586,7 @@ ENTRY(spurious_interrupt)
 	movq ORIG_RAX(%rsp),%rsi
 	movq $-1,ORIG_RAX(%rsp)
 	call \sym
+	cli
 	.endm
 	
 /*
@@ -809,10 +802,6 @@ ENTRY(debug)
 	pushq $0
 	CFI_ADJUST_CFA_OFFSET 8		
 	paranoidentry do_debug
-	/* switch back to process stack to restore the state ptrace touched */
-	movq %rax,%rsp	
-	testl $3,CS(%rsp)
-	jnz   paranoid_userspace	
 	jmp paranoid_exit
 	CFI_ENDPROC
 
@@ -822,37 +811,49 @@ ENTRY(nmi)
 	pushq $-1
 	CFI_ADJUST_CFA_OFFSET 8		
 	paranoidentry do_nmi
+	/*
+ 	 * "Paranoid" exit path from exception stack.
+  	 * Paranoid because this is used by NMIs and cannot take
+	 * any kernel state for granted.
+	 * We don't do kernel preemption checks here, because only
+	 * NMI should be common and it does not enable IRQs and
+	 * cannot get reschedule ticks.
+	 */
 	/* ebx:	no swapgs flag */
 paranoid_exit:
 	testl %ebx,%ebx				/* swapgs needed? */
 	jnz paranoid_restore
+	testl $3,CS(%rsp)
+	jnz   paranoid_userspace
 paranoid_swapgs:	
-	cli
 	swapgs
 paranoid_restore:	
 	RESTORE_ALL 8
 	iretq
 paranoid_userspace:	
-	cli
 	GET_THREAD_INFO(%rcx)
-	movl threadinfo_flags(%rcx),%edx
-	testl $_TIF_NEED_RESCHED,%edx
-	jnz paranoid_resched
-	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
-	jnz paranoid_signal
-	jmp paranoid_swapgs
-paranoid_resched:		
-	sti
-	call schedule
-	jmp paranoid_exit
-paranoid_signal:		
+	movl threadinfo_flags(%rcx),%ebx
+	andl $_TIF_WORK_MASK,%ebx
+	jz paranoid_swapgs
+	movq %rsp,%rdi			/* &pt_regs */
+	call sync_regs
+	movq %rax,%rsp			/* switch stack for scheduling */
+	testl $_TIF_NEED_RESCHED,%ebx
+	jnz paranoid_schedule
+	movl %ebx,%edx			/* arg3: thread flags */
 	sti
-	xorl %esi,%esi /* oldset */
-	movq %rsp,%rdi /* &pt_regs */
+	xorl %esi,%esi 			/* arg2: oldset */
+	movq %rsp,%rdi 			/* arg1: &pt_regs */
 	call do_notify_resume
-	jmp paranoid_exit
+	cli
+	jmp paranoid_userspace
+paranoid_schedule:
+	sti
+	call schedule
+	cli
+	jmp paranoid_userspace
 	CFI_ENDPROC
-	
+
 ENTRY(int3)
 	zeroentry do_int3	
 
@@ -875,9 +876,6 @@ ENTRY(reserved)
 ENTRY(double_fault)
 	CFI_STARTPROC
 	paranoidentry do_double_fault
-	movq %rax,%rsp
-	testl $3,CS(%rsp)
-	jnz paranoid_userspace		
 	jmp paranoid_exit
 	CFI_ENDPROC
 
@@ -891,9 +889,6 @@ ENTRY(segment_not_present)
 ENTRY(stack_segment)
 	CFI_STARTPROC
 	paranoidentry do_stack_segment
-	movq %rax,%rsp
-	testl $3,CS(%rsp)
-	jnz paranoid_userspace
 	jmp paranoid_exit
 	CFI_ENDPROC
 
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -20,6 +20,10 @@
 #include <asm/smp.h>
 #include <asm/ipi.h>
 
+#if defined(CONFIG_ACPI_BUS)
+#include <acpi/acpi_bus.h>
+#endif
+
 /* which logical CPU number maps to which CPU (physical APIC ID) */
 u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 EXPORT_SYMBOL(x86_cpu_to_apicid);
@@ -47,6 +51,18 @@ void __init clustered_apic_check(void)
 		goto print;
 	}
 
+#if defined(CONFIG_ACPI_BUS)
+	/*
+	 * Some x86_64 machines use physical APIC mode regardless of how many
+	 * procs/clusters are present (x86_64 ES7000 is an example).
+	 */
+	if (acpi_fadt.revision > FADT2_REVISION_ID)
+		if (acpi_fadt.force_apic_physical_destination_mode) {
+			genapic = &apic_cluster;
+			goto print;
+		}
+#endif
+
 	memset(cluster_cnt, 0, sizeof(cluster_cnt));
 
 	for (i = 0; i < NR_CPUS; i++) {
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -26,6 +26,7 @@
 
 	.text
 	.code32
+	.globl startup_32
 /* %bx:	 1 if coming from smp trampoline on secondary cpu */ 
 startup_32:
 	
@@ -37,11 +38,13 @@ startup_32:
  	 * There is no stack until we set one up.
 	 */
 
-	movl %ebx,%ebp	/* Save trampoline flag */
-	
+	/* Initialize the %ds segment register */
 	movl $__KERNEL_DS,%eax
 	movl %eax,%ds
-	
+
+	/* Load new GDT with the 64bit segments using 32bit descriptor */
+	lgdt	pGDT32 - __START_KERNEL_map
+
 	/* If the CPU doesn't support CPUID this will double fault.
 	 * Unfortunately it is hard to check for CPUID without a stack. 
 	 */
@@ -57,16 +60,13 @@ startup_32:
 	btl	$29, %edx
 	jnc	no_long_mode
 
-	movl	%edx,%edi
-	
 	/*
 	 * Prepare for entering 64bits mode
 	 */
 
-	/* Enable PAE mode and PGE */
+	/* Enable PAE mode */
 	xorl	%eax, %eax
 	btsl	$5, %eax
-	btsl	$7, %eax
 	movl	%eax, %cr4
 
 	/* Setup early boot stage 4 level pagetables */
@@ -79,14 +79,6 @@ startup_32:
 
 	/* Enable Long Mode */
 	btsl	$_EFER_LME, %eax
-	/* Enable System Call */
-	btsl	$_EFER_SCE, %eax
-
-	/* No Execute supported? */	
-	btl	$20,%edi
-	jnc     1f
-	btsl	$_EFER_NX, %eax
-1:	
 				
 	/* Make changes effective */
 	wrmsr
@@ -94,38 +86,69 @@ startup_32:
 	xorl	%eax, %eax
 	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
 	btsl	$0, %eax			/* Enable protected mode */
-	btsl	$1, %eax			/* Enable MP */
-	btsl	$4, %eax			/* Enable ET */
-	btsl	$5, %eax			/* Enable NE */
-	btsl	$16, %eax			/* Enable WP */
-	btsl	$18, %eax			/* Enable AM */
 	/* 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
+	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
 	 * 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 */
-	movl	$(pGDT32 - __START_KERNEL_map), %eax
-	lgdt	(%eax)
-
-second:	
-	movl    $(ljumpvector - __START_KERNEL_map), %eax
-	/* Finally jump in 64bit mode */
-	ljmp	*(%eax)
+	ljmp	$__KERNEL_CS, $(startup_64 - __START_KERNEL_map)
 
 	.code64
 	.org 0x100	
-reach_long64:
+	.globl startup_64
+startup_64:
+	/* We come here either from startup_32
+	 * or directly from a 64bit bootloader.
+	 * Since we may have come directly from a bootloader we
+	 * reload the page tables here.
+	 */
+
+	/* Enable PAE mode and PGE */
+	xorq	%rax, %rax
+	btsq	$5, %rax
+	btsq	$7, %rax
+	movq	%rax, %cr4
+
+	/* Setup early boot stage 4 level pagetables. */
+	movq	$(init_level4_pgt - __START_KERNEL_map), %rax
+	movq	%rax, %cr3
+
+	/* Check if nx is implemented */
+	movl	$0x80000001, %eax
+	cpuid
+	movl	%edx,%edi
+
+	/* Setup EFER (Extended Feature Enable Register) */
+	movl	$MSR_EFER, %ecx
+	rdmsr
+
+	/* Enable System Call */
+	btsl	$_EFER_SCE, %eax
+
+	/* No Execute supported? */
+	btl	$20,%edi
+	jnc     1f
+	btsl	$_EFER_NX, %eax
+1:
+	/* Make changes effective */
+	wrmsr
+
+	/* Setup cr0 */
+	xorq	%rax, %rax
+	btsq	$31, %rax			/* Enable paging */
+	btsq	$0, %rax			/* Enable protected mode */
+	btsq	$1, %rax			/* Enable MP */
+	btsq	$4, %rax			/* Enable ET */
+	btsq	$5, %rax			/* Enable NE */
+	btsq	$16, %rax			/* Enable WP */
+	btsq	$18, %rax			/* Enable AM */
+	/* Make changes effective */
+	movq	%rax, %cr0
+
+	/* Setup a boot time stack */
 	movq init_rsp(%rip),%rsp
 
 	/* zero EFLAGS after setting rsp */
@@ -177,14 +200,22 @@ init_rsp:
 	.quad  init_thread_union+THREAD_SIZE-8
 
 ENTRY(early_idt_handler)
+	cmpl $2,early_recursion_flag(%rip)
+	jz  1f
+	incl early_recursion_flag(%rip)
 	xorl %eax,%eax
 	movq 8(%rsp),%rsi	# get rip
 	movq (%rsp),%rdx
 	movq %cr2,%rcx
 	leaq early_idt_msg(%rip),%rdi
 	call early_printk
+	cmpl $2,early_recursion_flag(%rip)
+	jz  1f
+	call dump_stack
 1:	hlt
 	jmp 1b
+early_recursion_flag:
+	.long 0
 
 early_idt_msg:
 	.asciz "PANIC: early exception rip %lx error %lx cr2 %lx\n"
@@ -198,12 +229,12 @@ ENTRY(no_long_mode)
 .org 0xf00
 	.globl pGDT32
 pGDT32:
-	.word	gdt32_end-gdt_table32
-	.long	gdt_table32-__START_KERNEL_map
+	.word	gdt_end-cpu_gdt_table
+	.long	cpu_gdt_table-__START_KERNEL_map
 
 .org 0xf10	
 ljumpvector:
-	.long	reach_long64-__START_KERNEL_map
+	.long	startup_64-__START_KERNEL_map
 	.word	__KERNEL_CS
 
 ENTRY(stext)
@@ -334,12 +365,6 @@ gdt:
 	.endr
 #endif
 
-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 
@@ -360,9 +385,8 @@ ENTRY(cpu_gdt_table)
 	.quad	0x00affa000000ffff	/* __USER_CS */
 	.quad	0x00cf9a000000ffff	/* __KERNEL32_CS */
 	.quad	0,0			/* TSS */
-	.quad	0			/* LDT */
+	.quad	0,0			/* LDT */
 	.quad   0,0,0			/* three TLS descriptors */ 
-	.quad	0			/* unused now */
 	.quad	0x00009a000000ffff	/* __KERNEL16_CS - 16bit PM for S3 wakeup. */
 					/* base must be patched for real base address. */
 gdt_end:	
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -29,8 +29,6 @@ static void __init clear_bss(void)
 	       (unsigned long) __bss_end - (unsigned long) __bss_start);
 }
 
-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
@@ -44,7 +42,7 @@ static void __init copy_bootdata(char *r
 	int new_data;
 	char * command_line;
 
-	memcpy(x86_boot_params, real_mode_data, 2048); 
+	memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
 	new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
 	if (!new_data) {
 		if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
@@ -93,9 +91,6 @@ void __init x86_64_start_kernel(char * r
 #ifdef CONFIG_SMP
 	cpu_set(0, cpu_online_map);
 #endif
-	/* default console: */
-	if (!strstr(saved_command_line, "console="))
-		strcat(saved_command_line, " console=tty0"); 
 	s = strstr(saved_command_line, "earlyprintk=");
 	if (s != NULL)
 		setup_early_printk(s);
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -148,7 +148,7 @@ static void end_8259A_irq (unsigned int 
 
 #define shutdown_8259A_irq	disable_8259A_irq
 
-void mask_and_ack_8259A(unsigned int);
+static void mask_and_ack_8259A(unsigned int);
 
 static unsigned int startup_8259A_irq(unsigned int irq)
 { 
@@ -272,7 +272,7 @@ static inline int i8259A_irq_real(unsign
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(unsigned int irq)
 {
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
@@ -409,7 +409,7 @@ static int i8259A_resume(struct sys_devi
 	return 0;
 }
 
-static int i8259A_suspend(struct sys_device *dev, u32 state)
+static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
 {
 	save_ELCR(irq_trigger);
 	return 0;
@@ -477,6 +477,7 @@ void reschedule_interrupt(void);
 void call_function_interrupt(void);
 void invalidate_interrupt(void);
 void thermal_interrupt(void);
+void i8254_timer_resume(void);
 
 static void setup_timer(void)
 {
@@ -493,6 +494,11 @@ static int timer_resume(struct sys_devic
 	return 0;
 }
 
+void i8254_timer_resume(void)
+{
+	setup_timer();
+}
+
 static struct sysdev_class timer_sysclass = {
 	set_kset_name("timer"),
 	.resume		= timer_resume,
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -37,11 +37,14 @@
 #include <asm/desc.h>
 #include <asm/proto.h>
 #include <asm/mach_apic.h>
+#include <asm/acpi.h>
 
 #define __apicdebuginit  __init
 
 int sis_apic_bug; /* not actually supported, dummy for compile */
 
+static int no_timer_check;
+
 static DEFINE_SPINLOCK(ioapic_lock);
 
 /*
@@ -147,7 +150,7 @@ static void unmask_IO_APIC_irq (unsigned
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
@@ -185,8 +188,8 @@ static void clear_IO_APIC (void)
  */
 
 #define MAX_PIRQS 8
-int pirq_entries [MAX_PIRQS];
-int pirqs_enabled;
+static int pirq_entries [MAX_PIRQS];
+static int pirqs_enabled;
 int skip_ioapic_setup;
 int ioapic_force;
 
@@ -707,7 +710,7 @@ static inline void ioapic_register_intr(
 	}
 }
 
-void __init setup_IO_APIC_irqs(void)
+static void __init setup_IO_APIC_irqs(void)
 {
 	struct IO_APIC_route_entry entry;
 	int apic, pin, idx, irq, first_notcon = 1, vector;
@@ -776,7 +779,7 @@ void __init setup_IO_APIC_irqs(void)
  * Set up the 8259A-master output pin as broadcast to all
  * CPUs.
  */
-void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
+static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
@@ -948,6 +951,8 @@ void __apicdebuginit print_IO_APIC(void)
 	return;
 }
 
+#if 0
+
 static __apicdebuginit void print_APIC_bitfield (int base)
 {
 	unsigned int v;
@@ -1090,6 +1095,8 @@ void __apicdebuginit print_PIC(void)
 	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
+#endif  /*  0  */
+
 static void __init enable_IO_APIC(void)
 {
 	union IO_APIC_reg_01 reg_01;
@@ -1597,13 +1604,12 @@ static inline void check_timer(void)
 		 * Ok, does IRQ0 through the IOAPIC work?
 		 */
 		unmask_IO_APIC_irq(0);
-		if (timer_irq_works()) {
+		if (!no_timer_check && timer_irq_works()) {
 			nmi_watchdog_default();
 			if (nmi_watchdog == NMI_IO_APIC) {
 				disable_8259A_irq(0);
 				setup_nmi();
 				enable_8259A_irq(0);
-				check_nmi_watchdog();
 			}
 			return;
 		}
@@ -1623,7 +1629,6 @@ static inline void check_timer(void)
 			nmi_watchdog_default();
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
-				check_nmi_watchdog();
 			}
 			return;
 		}
@@ -1669,6 +1674,13 @@ static inline void check_timer(void)
 	panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n");
 }
 
+static int __init notimercheck(char *s)
+{
+	no_timer_check = 1;
+	return 1;
+}
+__setup("no_timer_check", notimercheck);
+
 /*
  *
  * IRQ's that are handled by the PIC in the MPS IOAPIC case.
@@ -1708,7 +1720,7 @@ struct sysfs_ioapic_data {
 };
 static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
 
-static int ioapic_suspend(struct sys_device *dev, u32 state)
+static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
 {
 	struct IO_APIC_route_entry *entry;
 	struct sysfs_ioapic_data *data;
@@ -1802,76 +1814,6 @@ device_initcall(ioapic_init_sysfs);
 
 #define IO_APIC_MAX_ID		0xFE
 
-int __init io_apic_get_unique_id (int ioapic, int apic_id)
-{
-	union IO_APIC_reg_00 reg_00;
-	static physid_mask_t apic_id_map;
-	unsigned long flags;
-	int i = 0;
-
-	/*
-	 * The P4 platform supports up to 256 APIC IDs on two separate APIC 
-	 * buses (one for LAPICs, one for IOAPICs), where predecessors only 
-	 * supports up to 16 on one shared APIC bus.
-	 * 
-	 * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
-	 *      advantage of new APIC bus architecture.
-	 */
-
-	if (physids_empty(apic_id_map))
-		apic_id_map = phys_cpu_present_map;
-
-	spin_lock_irqsave(&ioapic_lock, flags);
-	reg_00.raw = io_apic_read(ioapic, 0);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
-
-	if (apic_id >= IO_APIC_MAX_ID) {
-		apic_printk(APIC_QUIET, KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
-			"%d\n", ioapic, apic_id, reg_00.bits.ID);
-		apic_id = reg_00.bits.ID;
-	}
-
-	/*
-	 * 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 (physid_isset(apic_id, apic_id_map)) {
-
-		for (i = 0; i < IO_APIC_MAX_ID; i++) {
-			if (!physid_isset(i, apic_id_map))
-				break;
-		}
-
-		if (i == IO_APIC_MAX_ID)
-			panic("Max apic_id exceeded!\n");
-
-		apic_printk(APIC_VERBOSE, KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
-			"trying %d\n", ioapic, apic_id, i);
-
-		apic_id = i;
-	} 
-
-	physid_set(apic_id, apic_id_map);
-
-	if (reg_00.bits.ID != apic_id) {
-		reg_00.bits.ID = apic_id;
-
-		spin_lock_irqsave(&ioapic_lock, flags);
-		io_apic_write(ioapic, 0, reg_00.raw);
-		reg_00.raw = io_apic_read(ioapic, 0);
-		spin_unlock_irqrestore(&ioapic_lock, flags);
-
-		/* Sanity check */
-		if (reg_00.bits.ID != apic_id)
-			panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
-	}
-
-	apic_printk(APIC_VERBOSE,KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
-
-	return apic_id;
-}
-
-
 int __init io_apic_get_version (int ioapic)
 {
 	union IO_APIC_reg_01	reg_01;
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -25,6 +25,8 @@
  *		interface to access function arguments.
  * 2004-Oct	Jim Keniston <kenistoj@us.ibm.com> and Prasanna S Panchamukhi
  *		<prasanna@in.ibm.com> adapted for x86_64
+ * 2005-Mar	Roland McGrath <roland@redhat.com>
+ *		Fixed to handle %rip-relative addressing mode correctly.
  */
 
 #include <linux/config.h>
@@ -34,7 +36,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
-#include <linux/vmalloc.h>
+#include <linux/moduleloader.h>
 
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
@@ -86,9 +88,132 @@ int arch_prepare_kprobe(struct kprobe *p
 	return 0;
 }
 
+/*
+ * Determine if the instruction uses the %rip-relative addressing mode.
+ * If it does, return the address of the 32-bit displacement word.
+ * If not, return null.
+ */
+static inline s32 *is_riprel(u8 *insn)
+{
+#define W(row,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf)		      \
+	(((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
+	  (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) |   \
+	  (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) |   \
+	  (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf))    \
+	 << (row % 64))
+	static const u64 onebyte_has_modrm[256 / 64] = {
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+		/*      -------------------------------         */
+		W(0x00, 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0)| /* 00 */
+		W(0x10, 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0)| /* 10 */
+		W(0x20, 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0)| /* 20 */
+		W(0x30, 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0), /* 30 */
+		W(0x40, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 40 */
+		W(0x50, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 50 */
+		W(0x60, 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0)| /* 60 */
+		W(0x70, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 70 */
+		W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
+		W(0x90, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 90 */
+		W(0xa0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* a0 */
+		W(0xb0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* b0 */
+		W(0xc0, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0)| /* c0 */
+		W(0xd0, 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1)| /* d0 */
+		W(0xe0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* e0 */
+		W(0xf0, 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1)  /* f0 */
+		/*      -------------------------------         */
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+	};
+	static const u64 twobyte_has_modrm[256 / 64] = {
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+		/*      -------------------------------         */
+		W(0x00, 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1)| /* 0f */
+		W(0x10, 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0)| /* 1f */
+		W(0x20, 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1)| /* 2f */
+		W(0x30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 3f */
+		W(0x40, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 4f */
+		W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 5f */
+		W(0x60, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 6f */
+		W(0x70, 1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1), /* 7f */
+		W(0x80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 8f */
+		W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 9f */
+		W(0xa0, 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1)| /* af */
+		W(0xb0, 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1), /* bf */
+		W(0xc0, 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0)| /* cf */
+		W(0xd0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* df */
+		W(0xe0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* ef */
+		W(0xf0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0)  /* ff */
+		/*      -------------------------------         */
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+	};
+#undef	W
+	int need_modrm;
+
+	/* Skip legacy instruction prefixes.  */
+	while (1) {
+		switch (*insn) {
+		case 0x66:
+		case 0x67:
+		case 0x2e:
+		case 0x3e:
+		case 0x26:
+		case 0x64:
+		case 0x65:
+		case 0x36:
+		case 0xf0:
+		case 0xf3:
+		case 0xf2:
+			++insn;
+			continue;
+		}
+		break;
+	}
+
+	/* Skip REX instruction prefix.  */
+	if ((*insn & 0xf0) == 0x40)
+		++insn;
+
+	if (*insn == 0x0f) {	/* Two-byte opcode.  */
+		++insn;
+		need_modrm = test_bit(*insn, twobyte_has_modrm);
+	} else {		/* One-byte opcode.  */
+		need_modrm = test_bit(*insn, onebyte_has_modrm);
+	}
+
+	if (need_modrm) {
+		u8 modrm = *++insn;
+		if ((modrm & 0xc7) == 0x05) { /* %rip+disp32 addressing mode */
+			/* Displacement follows ModRM byte.  */
+			return (s32 *) ++insn;
+		}
+	}
+
+	/* No %rip-relative addressing mode here.  */
+	return NULL;
+}
+
 void arch_copy_kprobe(struct kprobe *p)
 {
+	s32 *ripdisp;
 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
+	ripdisp = is_riprel(p->ainsn.insn);
+	if (ripdisp) {
+		/*
+		 * The copied instruction uses the %rip-relative
+		 * addressing mode.  Adjust the displacement for the
+		 * difference between the original location of this
+		 * instruction and the location of the copy that will
+		 * actually be run.  The tricky bit here is making sure
+		 * that the sign extension happens correctly in this
+		 * calculation, since we need a signed 32-bit result to
+		 * be sign-extended to 64 bits when it's added to the
+		 * %rip value and yield the same 64-bit result that the
+		 * sign-extension of the original signed 32-bit
+		 * displacement would have given.
+		 */
+		s64 disp = (u8 *) p->addr + *ripdisp - (u8 *) p->ainsn.insn;
+		BUG_ON((s64) (s32) disp != disp); /* Sanity check.  */
+		*ripdisp = disp;
+	}
 }
 
 void arch_remove_kprobe(struct kprobe *p)
@@ -108,8 +233,11 @@ static void prepare_singlestep(struct kp
 {
 	regs->eflags |= TF_MASK;
 	regs->eflags &= ~IF_MASK;
-
-	regs->rip = (unsigned long)p->ainsn.insn;
+	/*single step inline if the instruction is an int3*/
+	if (p->opcode == BREAKPOINT_INSTRUCTION)
+		regs->rip = (unsigned long)p->addr;
+	else
+		regs->rip = (unsigned long)p->ainsn.insn;
 }
 
 /*
@@ -131,6 +259,12 @@ int kprobe_handler(struct pt_regs *regs)
 		   Disarm the probe we just hit, and ignore it. */
 		p = get_kprobe(addr);
 		if (p) {
+			if (kprobe_status == KPROBE_HIT_SS) {
+				regs->eflags &= ~TF_MASK;
+				regs->eflags |= kprobe_saved_rflags;
+				unlock_kprobes();
+				goto no_kprobe;
+			}
 			disarm_kprobe(p, regs);
 			ret = 1;
 		} else {
@@ -168,17 +302,16 @@ int kprobe_handler(struct pt_regs *regs)
 	if (is_IF_modifier(p->ainsn.insn))
 		kprobe_saved_rflags &= ~IF_MASK;
 
-	if (p->pre_handler(p, regs)) {
+	if (p->pre_handler && p->pre_handler(p, regs))
 		/* handler has already set things up, so skip ss setup */
 		return 1;
-	}
 
-      ss_probe:
+ss_probe:
 	prepare_singlestep(p, regs);
 	kprobe_status = KPROBE_HIT_SS;
 	return 1;
 
-      no_kprobe:
+no_kprobe:
 	preempt_enable_no_resched();
 	return ret;
 }
@@ -222,6 +355,13 @@ static void resume_execution(struct kpro
 		*tos &= ~(TF_MASK | IF_MASK);
 		*tos |= kprobe_old_rflags;
 		break;
+	case 0xc3:		/* ret/lret */
+	case 0xcb:
+	case 0xc2:
+	case 0xca:
+		regs->eflags &= ~TF_MASK;
+		/* rip is already adjusted, no more changes required*/
+		return;
 	case 0xe8:		/* call relative - Fix return addr */
 		*tos = orig_rip + (*tos - copy_rip);
 		break;
@@ -439,8 +579,15 @@ static kprobe_opcode_t *get_insn_slot(vo
 	if (!kip) {
 		return NULL;
 	}
-	kip->insns = (kprobe_opcode_t*) __vmalloc(PAGE_SIZE,
-		GFP_KERNEL|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC));
+
+	/*
+	 * For the %rip-relative displacement fixups to be doable, we
+	 * need our instruction copy to be within +/- 2GB of any data it
+	 * might access via %rip.  That is, within 2GB of where the
+	 * kernel image and loaded module images reside.  So we allocate
+	 * a page in the module loading area.
+	 */
+	kip->insns = module_alloc(PAGE_SIZE);
 	if (!kip->insns) {
 		kfree(kip);
 		return NULL;
@@ -481,7 +628,7 @@ static void free_insn_slot(kprobe_opcode
 					hlist_add_head(&kip->hlist,
 						&kprobe_insn_pages);
 				} else {
-					vfree(kip->insns);
+					module_free(NULL, kip->insns);
 					kfree(kip);
 				}
 			}
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -33,6 +33,7 @@ static int banks;
 static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
 static unsigned long console_logged;
 static int notify_user;
+static int rip_msr;
 
 /*
  * Lockless MCE logging infrastructure.
@@ -124,6 +125,23 @@ static int mce_available(struct cpuinfo_
 	       test_bit(X86_FEATURE_MCA, &c->x86_capability);
 }
 
+static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
+{
+	if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) {
+		m->rip = regs->rip;
+		m->cs = regs->cs;
+	} else {
+		m->rip = 0;
+		m->cs = 0;
+	}
+	if (rip_msr) {
+		/* Assume the RIP in the MSR is exact. Is this true? */
+		m->mcgstatus |= MCG_STATUS_EIPV;
+		rdmsrl(rip_msr, m->rip);
+		m->cs = 0;
+	}
+}
+
 /* 
  * The actual machine check handler
  */
@@ -176,14 +194,7 @@ void do_machine_check(struct pt_regs * r
 		if (m.status & MCI_STATUS_ADDRV)
 			rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
 
-		if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) {
-			m.rip = regs->rip;
-			m.cs = regs->cs;
-		} else {
-			m.rip = 0;
-			m.cs = 0;
-		}
-
+		mce_get_rip(&m, regs);
 		if (error_code != -1)
 			rdtscll(m.tsc);
 		wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
@@ -296,6 +307,9 @@ static void mce_init(void *dummy)
 		printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
 		banks = NR_BANKS; 
 	}
+	/* Use accurate RIP reporting if available. */
+	if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
+		rip_msr = MSR_IA32_MCG_EIP;
 
 	/* Log the machine checks left over from the previous reset.
 	   This also clears all registers */
@@ -365,18 +379,23 @@ static void collect_tscs(void *data) 
 
 static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off)
 {
-	unsigned long cpu_tsc[NR_CPUS];
+	unsigned long *cpu_tsc;
 	static DECLARE_MUTEX(mce_read_sem);
 	unsigned next;
 	char __user *buf = ubuf;
 	int i, err;
 
+	cpu_tsc = kmalloc(NR_CPUS * sizeof(long), GFP_KERNEL);
+	if (!cpu_tsc)
+		return -ENOMEM;
+
 	down(&mce_read_sem); 
 	next = rcu_dereference(mcelog.next);
 
 	/* Only supports full reads right now */
 	if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { 
 		up(&mce_read_sem);
+		kfree(cpu_tsc);
 		return -EINVAL;
 	}
 
@@ -407,6 +426,7 @@ static ssize_t mce_read(struct file *fil
 		}
 	} 	
 	up(&mce_read_sem);
+	kfree(cpu_tsc);
 	return err ? -EFAULT : buf - ubuf; 
 }
 
diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c
--- a/arch/x86_64/kernel/module.c
+++ b/arch/x86_64/kernel/module.c
@@ -29,108 +29,32 @@
 #include <asm/pgtable.h>
 
 #define DEBUGP(fmt...) 
- 
-static struct vm_struct *mod_vmlist;
 
+#ifndef CONFIG_UML
 void module_free(struct module *mod, void *module_region)
 {
-	struct vm_struct **prevp, *map;
-	int i;
-	unsigned long addr = (unsigned long)module_region;
-
-	if (!addr)
-		return;
-	write_lock(&vmlist_lock); 
-	for (prevp = &mod_vmlist ; (map = *prevp) ; prevp = &map->next) {
-		if ((unsigned long)map->addr == addr) {
-			*prevp = map->next;
-			goto found;
-		}
-	}
-	write_unlock(&vmlist_lock); 
-	printk("Trying to unmap nonexistent module vm area (%lx)\n", addr);
-	return;
- found:
-	unmap_vm_area(map);
-	write_unlock(&vmlist_lock); 
-	if (map->pages) {
-		for (i = 0; i < map->nr_pages; i++)
-			if (map->pages[i])
-				__free_page(map->pages[i]);	
-		kfree(map->pages);
-	}
-	kfree(map);					
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
 }
 
 void *module_alloc(unsigned long size)
 {
-	struct vm_struct **p, *tmp, *area;
-	struct page **pages;
-	void *addr;
-	unsigned int nr_pages, array_size, i;
+	struct vm_struct *area;
 
 	if (!size)
-		return NULL; 
+		return NULL;
 	size = PAGE_ALIGN(size);
 	if (size > MODULES_LEN)
 		return NULL;
 
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
 	if (!area)
 		return NULL;
-	memset(area, 0, sizeof(struct vm_struct));
-
-	write_lock(&vmlist_lock);
-	addr = (void *) MODULES_VADDR;
-	for (p = &mod_vmlist; (tmp = *p); p = &tmp->next) {
-		void *next; 
-		DEBUGP("vmlist %p %lu addr %p\n", tmp->addr, tmp->size, addr);
-		if (size + (unsigned long) addr + PAGE_SIZE < (unsigned long) tmp->addr)
-			break;
-		next = (void *) (tmp->size + (unsigned long) tmp->addr);
-		if (next > addr) 
-			addr = next;
-	}
-
-	if ((unsigned long)addr + size >= MODULES_END) {
-		write_unlock(&vmlist_lock);
-		kfree(area); 
-		return NULL;
-	}
-	DEBUGP("addr %p\n", addr);
 
-	area->next = *p;
-	*p = area;
-	area->size = size + PAGE_SIZE;
-	area->addr = addr;
-	write_unlock(&vmlist_lock);
-
-	nr_pages = size >> PAGE_SHIFT;
-	array_size = (nr_pages * sizeof(struct page *));
-
-	area->nr_pages = nr_pages;
-	area->pages = pages = kmalloc(array_size, GFP_KERNEL);
-	if (!area->pages) 
-		goto fail;
-
-	memset(area->pages, 0, array_size);
-	for (i = 0; i < nr_pages; i++) {
-		area->pages[i] = alloc_page(GFP_KERNEL);
-		if (area->pages[i] == NULL)
-			goto fail;
-	}
-	
-	if (map_vm_area(area, PAGE_KERNEL_EXEC, &pages))
-		goto fail;
-	
-	memset(addr, 0, size);
-	DEBUGP("module_alloc size %lu = %p\n", size, addr);
-	return addr;
-
-fail:
-	module_free(NULL, addr);
-	return NULL;
+	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
 }
+#endif
 
 /* We don't need anything special. */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -30,6 +30,7 @@
 #include <asm/pgalloc.h>
 #include <asm/io_apic.h>
 #include <asm/proto.h>
+#include <asm/acpi.h>
 
 /* Have we found an MP table */
 int smp_found_config;
@@ -46,7 +47,7 @@ unsigned char mp_bus_id_to_type [MAX_MP_
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 cpumask_t pci_bus_to_cpumask [256] = { [0 ... 255] = CPU_MASK_ALL };
 
-int mp_current_pci_id = 0;
+static int mp_current_pci_id = 0;
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
@@ -107,6 +108,7 @@ static int __init mpf_checksum(unsigned 
 static void __init MP_processor_info (struct mpc_config_processor *m)
 {
 	int ver;
+	static int found_bsp=0;
 
 	if (!(m->mpc_cpuflag & CPU_ENABLED))
 		return;
@@ -126,11 +128,6 @@ static void __init MP_processor_info (st
 			" Processor ignored.\n", NR_CPUS);
 		return;
 	}
-	if (num_processors >= maxcpus) {
-		printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."
-			" Processor ignored.\n", maxcpus);
-		return;
-	}
 
 	num_processors++;
 
@@ -150,7 +147,19 @@ static void __init MP_processor_info (st
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
-	bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
+ 	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+ 		/*
+ 		 * bios_cpu_apicid is required to have processors listed
+ 		 * in same order as logical cpu numbers. Hence the first
+ 		 * entry is BSP, and so on.
+ 		 */
+ 		bios_cpu_apicid[0] = m->mpc_apicid;
+ 		x86_cpu_to_apicid[0] = m->mpc_apicid;
+ 		found_bsp = 1;
+ 	} else {
+ 		bios_cpu_apicid[num_processors - found_bsp] = m->mpc_apicid;
+ 		x86_cpu_to_apicid[num_processors - found_bsp] = m->mpc_apicid;
+ 	}
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -708,7 +717,7 @@ void __init mp_register_lapic (
 #define MP_ISA_BUS		0
 #define MP_MAX_IOAPIC_PIN	127
 
-struct mp_ioapic_routing {
+static struct mp_ioapic_routing {
 	int			apic_id;
 	int			gsi_start;
 	int			gsi_end;
@@ -759,7 +768,7 @@ void __init mp_register_ioapic (
 	mp_ioapics[idx].mpc_apicaddr = address;
 
 	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-	mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id);
+	mp_ioapics[idx].mpc_apicid = id;
 	mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
 	
 	/* 
diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c
--- a/arch/x86_64/kernel/msr.c
+++ b/arch/x86_64/kernel/msr.c
@@ -255,7 +255,7 @@ static struct file_operations msr_fops =
 	.open = msr_open,
 };
 
-int __init msr_init(void)
+static 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",
@@ -266,7 +266,7 @@ int __init msr_init(void)
 	return 0;
 }
 
-void __exit msr_exit(void)
+static void __exit msr_exit(void)
 {
 	unregister_chrdev(MSR_MAJOR, "cpu/msr");
 }
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -33,6 +33,7 @@
 #include <asm/msr.h>
 #include <asm/proto.h>
 #include <asm/kdebug.h>
+#include <asm/local.h>
 
 /*
  * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
@@ -59,7 +60,8 @@ int panic_on_timeout;
 
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
-unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
+static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
+static unsigned int nmi_p4_cccr_val;
 
 /* Note that these events don't tick when the CPU idles. This means
    the frequency varies with CPU load. */
@@ -71,80 +73,110 @@ unsigned int nmi_perfctr_msr;	/* the MSR
 #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_PMI0	(1<<26)
+#define P4_CCCR_OVF_PMI1	(1<<27)
+#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 P4_NMI_CRU_ESCR0	(P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0	\
+	(P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
+	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
+static __init inline int nmi_known_cpu(void)
+{
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		return boot_cpu_data.x86 == 15;
+	case X86_VENDOR_INTEL:
+		return boot_cpu_data.x86 == 15;
+	}
+	return 0;
+}
 
 /* Run after command line and cpu_init init, but before all other checks */
 void __init nmi_watchdog_default(void)
 {
 	if (nmi_watchdog != NMI_DEFAULT)
 		return;
-
-	/* For some reason the IO APIC watchdog doesn't work on the AMD
-	   8111 chipset. For now switch to local APIC mode using
-	   perfctr0 there.  On Intel CPUs we don't have code to handle
-	   the perfctr and the IO-APIC seems to work, so use that.  */
-
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
-		nmi_watchdog = NMI_LOCAL_APIC; 
-		printk(KERN_INFO 
-              "Using local APIC NMI watchdog using perfctr0\n");
-	} else {
-		printk(KERN_INFO "Using IO APIC NMI watchdog\n");
+	if (nmi_known_cpu())
+		nmi_watchdog = NMI_LOCAL_APIC;
+	else
 		nmi_watchdog = NMI_IO_APIC;
-	}
 }
 
-/* Why is there no CPUID flag for this? */
-static __init int cpu_has_lapic(void)
+#ifdef CONFIG_SMP
+/* The performance counters used by NMI_LOCAL_APIC don't trigger when
+ * the CPU is idle. To make sure the NMI watchdog really ticks on all
+ * CPUs during the test make them busy.
+ */
+static __init void nmi_cpu_busy(void *data)
 {
-	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 different way to figure this out. */	
-	default:
-		return 0;
-	} 	
+	volatile int *endflag = data;
+	local_irq_enable();
+	/* Intentionally don't use cpu_relax here. This is
+	   to make sure that the performance counter really ticks,
+	   even if there is a simulator or similar that catches the
+	   pause instruction. On a real HT machine this is fine because
+	   all other CPUs are busy with "useless" delay loops and don't
+	   care if they get somewhat less cycles. */
+	while (*endflag == 0)
+		barrier();
 }
+#endif
 
 int __init check_nmi_watchdog (void)
 {
-	int counts[NR_CPUS];
+	volatile int endflag = 0;
+	int *counts;
 	int cpu;
 
-	if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic())  {
-		nmi_watchdog = NMI_NONE;
-		return -1; 
-	}	
+	counts = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+	if (!counts)
+		return -1;
 
 	printk(KERN_INFO "testing NMI watchdog ... ");
 
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
+
 	for (cpu = 0; cpu < NR_CPUS; cpu++)
 		counts[cpu] = cpu_pda[cpu].__nmi_count; 
 	local_irq_enable();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-#ifdef CONFIG_SMP
-		/* Check cpu_callin_map here because that is set
-		   after the timer is started. */
-		if (!cpu_isset(cpu, cpu_callin_map))
+		if (!cpu_online(cpu))
 			continue;
-#endif
 		if (cpu_pda[cpu].__nmi_count - counts[cpu] <= 5) {
-			printk("CPU#%d: NMI appears to be stuck (%d)!\n", 
+			endflag = 1;
+			printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
 			       cpu,
+			       counts[cpu],
 			       cpu_pda[cpu].__nmi_count);
 			nmi_active = 0;
 			lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
+			nmi_perfctr_msr = 0;
+			kfree(counts);
 			return -1;
 		}
 	}
+	endflag = 1;
 	printk("OK.\n");
 
 	/* now that we know it works we can reduce NMI frequency to
@@ -152,6 +184,7 @@ int __init check_nmi_watchdog (void)
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		nmi_hz = 1;
 
+	kfree(counts);
 	return 0;
 }
 
@@ -171,7 +204,7 @@ int __init setup_nmi_watchdog(char *str)
 
 	if (nmi >= NMI_INVALID)
 		return 0;
-		nmi_watchdog = nmi;
+	nmi_watchdog = nmi;
 	return 1;
 }
 
@@ -186,7 +219,10 @@ static void disable_lapic_nmi_watchdog(v
 		wrmsr(MSR_K7_EVNTSEL0, 0, 0);
 		break;
 	case X86_VENDOR_INTEL:
-		wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+		if (boot_cpu_data.x86 == 15) {
+			wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+			wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+		}
 		break;
 	}
 	nmi_active = -1;
@@ -301,22 +337,27 @@ late_initcall(init_lapic_nmi_sysfs);
  * Original code written by Keith Owens.
  */
 
+static void 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 setup_k7_watchdog(void)
 {
 	int i;
 	unsigned int evntsel;
 
-	/* No check, so can start with slow frequency */
-	nmi_hz = 1; 
-
-	/* XXX should check these in EFER */
-
 	nmi_perfctr_msr = MSR_K7_PERFCTR0;
 
 	for(i = 0; i < 4; ++i) {
 		/* Simulator may not support it */
-		if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL))
+		if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL)) {
+			nmi_perfctr_msr = 0;
 			return;
+		}
 		wrmsrl(MSR_K7_PERFCTR0+i, 0UL);
 	}
 
@@ -326,22 +367,71 @@ static void setup_k7_watchdog(void)
 		| K7_NMI_EVENT;
 
 	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
-	wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz*1000) / nmi_hz);
+	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 int 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;
+	nmi_p4_cccr_val = P4_NMI_IQ_CCCR0;
+#ifdef CONFIG_SMP
+	if (smp_num_siblings == 2)
+		nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
+#endif
+
+	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. */
+	if (boot_cpu_data.x86_model >= 0x3) {
+		/* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
+		clear_msr_range(0x3A0, 26);
+		clear_msr_range(0x3BC, 3);
+	} else {
+		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, nmi_p4_cccr_val, 0);
+	return 1;
+}
+
 void setup_apic_nmi_watchdog(void)
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 < 6)
+		if (boot_cpu_data.x86 != 15)
 			return;
 		if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
 			return;
 		setup_k7_watchdog();
 		break;
+	case X86_VENDOR_INTEL:
+		if (boot_cpu_data.x86 != 15)
+			return;
+		if (!setup_p4_watchdog())
+			return;
+		break;
+
 	default:
 		return;
 	}
@@ -356,56 +446,67 @@ void setup_apic_nmi_watchdog(void)
  *
  * as these watchdog NMI IRQs are generated on every CPU, we only
  * have to check the current processor.
- *
- * since NMIs don't 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];
+static DEFINE_PER_CPU(unsigned, last_irq_sum);
+static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(int, nmi_touch);
 
 void touch_nmi_watchdog (void)
 {
 	int i;
 
 	/*
-	 * Just reset the alert counters, (other CPUs might be
-	 * spinning on locks we hold):
+ 	 * Tell other CPUs to reset their alert counters. We cannot
+	 * do it ourselves because the alert count increase is not
+	 * atomic.
 	 */
 	for (i = 0; i < NR_CPUS; i++)
-		alert_counter[i] = 0;
+		per_cpu(nmi_touch, i) = 1;
 }
 
 void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
 {
-	int sum, cpu;
+	int sum;
+	int touched = 0;
 
-	cpu = safe_smp_processor_id();
 	sum = read_pda(apic_timer_irqs);
-	if (last_irq_sums[cpu] == sum) {
+	if (__get_cpu_var(nmi_touch)) {
+		__get_cpu_var(nmi_touch) = 0;
+		touched = 1;
+	}
+	if (!touched && __get_cpu_var(last_irq_sum) == 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) {
+		local_inc(&__get_cpu_var(alert_counter));
+		if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) {
 			if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
 							== NOTIFY_STOP) {
-				alert_counter[cpu] = 0; 
+				local_set(&__get_cpu_var(alert_counter), 0);
 				return;
 			} 
 			die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs);
 		}
 	} else {
-		last_irq_sums[cpu] = sum;
-		alert_counter[cpu] = 0;
+		__get_cpu_var(last_irq_sum) = sum;
+		local_set(&__get_cpu_var(alert_counter), 0);
 	}
-	if (nmi_perfctr_msr)
+	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, nmi_p4_cccr_val, 0);
+ 			apic_write(APIC_LVTPC, APIC_DM_NMI);
+ 		}
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+	}
 }
 
 static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -193,7 +193,7 @@ static void *dma_alloc_pages(struct devi
 	int node;
 	if (dev->bus == &pci_bus_type) {
 		cpumask_t mask;
-		mask = pcibus_to_cpumask(to_pci_dev(dev)->bus->number);
+		mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
 		node = cpu_to_node(first_cpu(mask));
 	} else
 		node = numa_node_id();
@@ -720,6 +720,7 @@ static __init int init_k8_gatt(struct ag
 	unsigned aper_base, new_aper_base;
 	unsigned aper_size, gatt_size, new_aper_size;
 	
+	printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
 	aper_size = aper_base = info->aper_size = 0;
 	for_all_nb(dev) { 
 		new_aper_base = read_aperture(dev, &new_aper_size); 
@@ -789,7 +790,7 @@ static int __init pci_iommu_init(void)
 	/* Add other K8 AGP bridge drivers here */
 	no_agp = no_agp || 
 		(agp_amd64_init() < 0) || 
-		(agp_copy_info(&info) < 0); 
+		(agp_copy_info(agp_bridge, &info) < 0);
 #endif	
 
 	if (swiotlb) { 
@@ -798,26 +799,15 @@ static int __init pci_iommu_init(void)
 		return -1; 
 	} 
 	
-	if (no_iommu || (!force_iommu && end_pfn < 0xffffffff>>PAGE_SHIFT) || 
-	    !iommu_aperture) {
+	if (no_iommu ||
+	    (!force_iommu && end_pfn < 0xffffffff>>PAGE_SHIFT) ||
+	    !iommu_aperture ||
+	    (no_agp && init_k8_gatt(&info) < 0)) {
 		printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); 
 		no_iommu = 1;
 		return -1;
 	}
 
-	if (no_agp) { 
-		int err = -1;
-		printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
-		no_agp = 1;
-		if (force_iommu || 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 -1;
-		}
-	} 
-
 	aper_size = info.aper_size * 1024 * 1024;	
 	iommu_size = check_iommu_size(info.aper_base, aper_size); 
 	iommu_pages = iommu_size >> PAGE_SHIFT; 
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c
new file mode 100644
--- /dev/null
+++ b/arch/x86_64/kernel/pmtimer.c
@@ -0,0 +1,101 @@
+/* Ported over from i386 by AK, original copyright was:
+ *
+ * (C) Dominik Brodowski <linux@brodo.de> 2003
+ *
+ * Driver to use the Power Management Timer (PMTMR) available in some
+ * southbridges as primary timing source for the Linux kernel.
+ *
+ * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
+ * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
+ *
+ * This file is licensed under the GPL v2.
+ *
+ * Dropped all the hardware bug workarounds for now. Hopefully they
+ * are not needed on 64bit chipsets.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <asm/io.h>
+#include <asm/proto.h>
+#include <asm/msr.h>
+#include <asm/vsyscall.h>
+
+/* The I/O port the PMTMR resides at.
+ * The location is detected during setup_arch(),
+ * in arch/i386/kernel/acpi/boot.c */
+u32 pmtmr_ioport;
+
+/* value of the Power timer at last timer interrupt */
+static u32 offset_delay;
+static u32 last_pmtmr_tick;
+
+#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
+
+static inline u32 cyc2us(u32 cycles)
+{
+	/* The Power Management Timer ticks at 3.579545 ticks per microsecond.
+	 * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
+	 *
+	 * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
+	 * easily be multiplied with 286 (=0x11E) without having to fear
+	 * u32 overflows.
+	 */
+	cycles *= 286;
+	return (cycles >> 10);
+}
+
+int pmtimer_mark_offset(void)
+{
+	static int first_run = 1;
+	unsigned long tsc;
+	u32 lost;
+
+	u32 tick = inl(pmtmr_ioport);
+	u32 delta;
+
+	delta = cyc2us((tick - last_pmtmr_tick) & ACPI_PM_MASK);
+
+	last_pmtmr_tick = tick;
+	monotonic_base += delta * NSEC_PER_USEC;
+
+	delta += offset_delay;
+
+	lost = delta / (USEC_PER_SEC / HZ);
+	offset_delay = delta % (USEC_PER_SEC / HZ);
+
+	rdtscll(tsc);
+	vxtime.last_tsc = tsc - offset_delay * cpu_khz;
+
+	/* don't calculate delay for first run,
+	   or if we've got less then a tick */
+	if (first_run || (lost < 1)) {
+		first_run = 0;
+		offset_delay = 0;
+	}
+
+	return lost - 1;
+}
+
+unsigned int do_gettimeoffset_pm(void)
+{
+	u32 now, offset, delta = 0;
+
+	offset = last_pmtmr_tick;
+	now = inl(pmtmr_ioport);
+	delta = (now - offset) & ACPI_PM_MASK;
+
+	return offset_delay + cyc2us(delta);
+}
+
+
+static int __init nopmtimer_setup(char *s)
+{
+	pmtmr_ioport = 0;
+	return 0;
+}
+
+__setup("nopmtimer", nopmtimer_setup);
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -33,6 +33,7 @@
 #include <linux/irq.h>
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
+#include <linux/random.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -52,7 +53,7 @@ asmlinkage extern void ret_from_fork(voi
 
 unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
 
-atomic_t hlt_counter = ATOMIC_INIT(0);
+static atomic_t hlt_counter = ATOMIC_INIT(0);
 
 unsigned long boot_option_idle_override = 0;
 EXPORT_SYMBOL(boot_option_idle_override);
@@ -61,7 +62,7 @@ EXPORT_SYMBOL(boot_option_idle_override)
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void);
-static cpumask_t cpu_idle_map;
+static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
 void disable_hlt(void)
 {
@@ -124,20 +125,31 @@ static void poll_idle (void)
 	}
 }
 
-
 void cpu_idle_wait(void)
 {
-        int cpu;
-        cpumask_t map;
+	unsigned int cpu, this_cpu = get_cpu();
+	cpumask_t map;
 
-        for_each_online_cpu(cpu)
-                cpu_set(cpu, cpu_idle_map);
+	set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
+	put_cpu();
 
-        wmb();
-        do {
-                ssleep(1);
-                cpus_and(map, cpu_idle_map, cpu_online_map);
-        } while (!cpus_empty(map));
+	cpus_clear(map);
+	for_each_online_cpu(cpu) {
+		per_cpu(cpu_idle_state, cpu) = 1;
+		cpu_set(cpu, map);
+	}
+
+	__get_cpu_var(cpu_idle_state) = 0;
+
+	wmb();
+	do {
+		ssleep(1);
+		for_each_online_cpu(cpu) {
+			if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+				cpu_clear(cpu, map);
+		}
+		cpus_and(map, map, cpu_online_map);
+	} while (!cpus_empty(map));
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
@@ -149,21 +161,21 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
  */
 void cpu_idle (void)
 {
-	int cpu = smp_processor_id();
-
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
 			void (*idle)(void);
 
-			if (cpu_isset(cpu, cpu_idle_map))
-				cpu_clear(cpu, cpu_idle_map);
+			if (__get_cpu_var(cpu_idle_state))
+				__get_cpu_var(cpu_idle_state) = 0;
+
 			rmb();
 			idle = pm_idle;
 			if (!idle)
 				idle = default_idle;
 			idle();
 		}
+
 		schedule();
 	}
 }
@@ -390,10 +402,10 @@ int copy_thread(int nr, unsigned long cl
 	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));
+	asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
+	asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
+	asm("mov %%es,%0" : "=m" (p->thread.es));
+	asm("mov %%ds,%0" : "=m" (p->thread.ds));
 
 	if (unlikely(me->thread.io_bitmap_ptr != NULL)) { 
 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
@@ -456,11 +468,11 @@ struct task_struct *__switch_to(struct t
 	 * Switch DS and ES.
 	 * This won't pick up thread selector changes, but I guess that is ok.
 	 */
-	asm volatile("movl %%es,%0" : "=m" (prev->es)); 
+	asm volatile("mov %%es,%0" : "=m" (prev->es));
 	if (unlikely(next->es | prev->es))
 		loadsegment(es, next->es); 
 	
-	asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); 
+	asm volatile ("mov %%ds,%0" : "=m" (prev->ds));
 	if (unlikely(next->ds | prev->ds))
 		loadsegment(ds, next->ds);
 
@@ -471,7 +483,7 @@ struct task_struct *__switch_to(struct t
 	 */
 	{ 
 		unsigned fsindex;
-		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
+		asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
 		/* segment register != 0 always requires a reload. 
 		   also reload when it has changed. 
 		   when prev process used 64bit base always reload
@@ -492,7 +504,7 @@ struct task_struct *__switch_to(struct t
 	}
 	{ 
 		unsigned gsindex;
-		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+		asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
 		if (unlikely(gsindex | next->gsindex | prev->gs)) {
 			load_gs_index(next->gsindex);
 			if (gsindex)
@@ -749,3 +761,10 @@ int dump_task_regs(struct task_struct *t
  
 	return 1;
 }
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (randomize_va_space)
+		sp -= get_random_int() % 8192;
+	return sp & ~0xf;
+}
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -17,6 +17,8 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
+#include <linux/seccomp.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -62,6 +64,12 @@ static inline unsigned long get_stack_lo
 	return (*((unsigned long *)stack));
 }
 
+static inline struct pt_regs *get_child_regs(struct task_struct *task)
+{
+	struct pt_regs *regs = (void *)task->thread.rsp0;
+	return regs - 1;
+}
+
 /*
  * 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.  
@@ -79,6 +87,130 @@ static inline long put_stack_long(struct
 	return 0;
 }
 
+#define LDT_SEGMENT 4
+
+unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs)
+{
+	unsigned long addr, seg;
+
+	addr = regs->rip;
+	seg = regs->cs & 0xffff;
+
+	/*
+	 * We'll assume that the code segments in the GDT
+	 * are all zero-based. That is largely true: the
+	 * TLS segments are used for data, and the PNPBIOS
+	 * and APM bios ones we just ignore here.
+	 */
+	if (seg & LDT_SEGMENT) {
+		u32 *desc;
+		unsigned long base;
+
+		down(&child->mm->context.sem);
+		desc = child->mm->context.ldt + (seg & ~7);
+		base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+
+		/* 16-bit code segment? */
+		if (!((desc[1] >> 22) & 1))
+			addr &= 0xffff;
+		addr += base;
+		up(&child->mm->context.sem);
+	}
+	return addr;
+}
+
+static int is_at_popf(struct task_struct *child, struct pt_regs *regs)
+{
+	int i, copied;
+	unsigned char opcode[16];
+	unsigned long addr = convert_rip_to_linear(child, regs);
+
+	copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
+	for (i = 0; i < copied; i++) {
+		switch (opcode[i]) {
+		/* popf */
+		case 0x9d:
+			return 1;
+
+			/* CHECKME: 64 65 */
+
+		/* opcode and address size prefixes */
+		case 0x66: case 0x67:
+			continue;
+		/* irrelevant prefixes (segment overrides and repeats) */
+		case 0x26: case 0x2e:
+		case 0x36: case 0x3e:
+		case 0x64: case 0x65:
+		case 0xf0: case 0xf2: case 0xf3:
+			continue;
+
+		/* REX prefixes */
+		case 0x40 ... 0x4f:
+			continue;
+
+			/* CHECKME: f0, f2, f3 */
+
+		/*
+		 * pushf: NOTE! We should probably not let
+		 * the user see the TF bit being set. But
+		 * it's more pain than it's worth to avoid
+		 * it, and a debugger could emulate this
+		 * all in user space if it _really_ cares.
+		 */
+		case 0x9c:
+		default:
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static void set_singlestep(struct task_struct *child)
+{
+	struct pt_regs *regs = get_child_regs(child);
+
+	/*
+	 * Always set TIF_SINGLESTEP - this guarantees that
+	 * we single-step system calls etc..  This will also
+	 * cause us to set TF when returning to user mode.
+	 */
+	set_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+	/*
+	 * If TF was already set, don't do anything else
+	 */
+	if (regs->eflags & TRAP_FLAG)
+		return;
+
+	/* Set TF on the kernel stack.. */
+	regs->eflags |= TRAP_FLAG;
+
+	/*
+	 * ..but if TF is changed by the instruction we will trace,
+	 * don't mark it as being "us" that set it, so that we
+	 * won't clear it by hand later.
+	 *
+	 * AK: this is not enough, LAHF and IRET can change TF in user space too.
+	 */
+	if (is_at_popf(child, regs))
+		return;
+
+	child->ptrace |= PT_DTRACE;
+}
+
+static void clear_singlestep(struct task_struct *child)
+{
+	/* Always clear TIF_SINGLESTEP... */
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+	/* But touch TF only if it was set by us.. */
+	if (child->ptrace & PT_DTRACE) {
+		struct pt_regs *regs = get_child_regs(child);
+		regs->eflags &= ~TRAP_FLAG;
+		child->ptrace &= ~PT_DTRACE;
+	}
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -86,11 +218,7 @@ static inline long put_stack_long(struct
  */
 void ptrace_disable(struct task_struct *child)
 { 
-	long tmp;
-
-	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-	tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
-	put_stack_long(child, EFL_OFFSET, tmp);
+	clear_singlestep(child);
 }
 
 static int putreg(struct task_struct *child,
@@ -129,13 +257,13 @@ static int putreg(struct task_struct *ch
 			value &= 0xffff;
 			return 0;
 		case offsetof(struct user_regs_struct,fs_base):
-			if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
-				return -EIO; 
+			if (value >= TASK_SIZE)
+				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; 
+			if (value >= TASK_SIZE)
+				return -EIO;
 			child->thread.gs = value;
 			return 0;
 		case offsetof(struct user_regs_struct, eflags):
@@ -149,6 +277,11 @@ static int putreg(struct task_struct *ch
 				return -EIO;
 			value &= 0xffff;
 			break;
+		case offsetof(struct user_regs_struct, rip):
+			/* Check if the new RIP address is canonical */
+			if (value >= TASK_SIZE)
+				return -EIO;
+			break;
 	}
 	put_stack_long(child, regno - sizeof(struct pt_regs), value);
 	return 0;
@@ -247,7 +380,7 @@ asmlinkage long sys_ptrace(long request,
 			break;
 
 		switch (addr) { 
-		case 0 ... sizeof(struct user_regs_struct):
+		case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
 			tmp = getreg(child, addr);
 			break;
 		case offsetof(struct user, u_debugreg[0]):
@@ -292,7 +425,7 @@ asmlinkage long sys_ptrace(long request,
 			break;
 
 		switch (addr) { 
-		case 0 ... sizeof(struct user_regs_struct): 
+		case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
 			ret = putreg(child, addr, data);
 			break;
 		/* Disallows to set a breakpoint into the vsyscall */
@@ -337,11 +470,10 @@ asmlinkage long sys_ptrace(long request,
 		}
 		break;
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-	case PTRACE_CONT: { /* restart after signal. */
-		long tmp;
+	case PTRACE_CONT:    /* restart after signal. */
 
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
@@ -349,14 +481,11 @@ asmlinkage long sys_ptrace(long request,
 			clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
 		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		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);
+		/* make sure the single step bit is not set. */
+		clear_singlestep(child);
 		wake_up_process(child);
 		ret = 0;
 		break;
-	}
 
 #ifdef CONFIG_IA32_EMULATION
 		/* This makes only sense with 32bit programs. Allow a
@@ -393,41 +522,28 @@ asmlinkage long sys_ptrace(long request,
  * perhaps it should be put in the status that it wants to 
  * exit.
  */
-	case PTRACE_KILL: {
-		long tmp;
-
+	case PTRACE_KILL:
 		ret = 0;
 		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
 			break;
 		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		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);
+		clear_singlestep(child);
 		wake_up_process(child);
 		break;
-	}
-
-	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-		long tmp;
 
+	case PTRACE_SINGLESTEP:    /* set the trap flag. */
 		ret = -EIO;
-		if ((unsigned long) data > _NSIG)
+		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
-		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);
-		set_tsk_thread_flag(child, TIF_SINGLESTEP);
+		set_singlestep(child);
 		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. */
@@ -521,20 +637,32 @@ static void syscall_trace(struct pt_regs
 
 asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 {
-	if (unlikely(current->audit_context))
-		audit_syscall_entry(current, regs->orig_rax,
-				    regs->rdi, regs->rsi,
-				    regs->rdx, regs->r10);
+	/* do the secure computing check first */
+	secure_computing(regs->orig_rax);
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)
 	    && (current->ptrace & PT_PTRACED))
 		syscall_trace(regs);
+
+	if (unlikely(current->audit_context)) {
+		if (test_thread_flag(TIF_IA32)) {
+			audit_syscall_entry(current, AUDIT_ARCH_I386,
+					    regs->orig_rax,
+					    regs->rbx, regs->rcx,
+					    regs->rdx, regs->rsi);
+		} else {
+			audit_syscall_entry(current, AUDIT_ARCH_X86_64,
+					    regs->orig_rax,
+					    regs->rdi, regs->rsi,
+					    regs->rdx, regs->r10);
+		}
+	}
 }
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
 	if (unlikely(current->audit_context))
-		audit_syscall_exit(current, regs->rax);
+		audit_syscall_exit(current, AUDITSC_RESULT(regs->rax), regs->rax);
 
 	if ((test_thread_flag(TIF_SYSCALL_TRACE)
 	     || test_thread_flag(TIF_SINGLESTEP))
diff --git a/arch/x86_64/kernel/semaphore.c b/arch/x86_64/kernel/semaphore.c
--- a/arch/x86_64/kernel/semaphore.c
+++ b/arch/x86_64/kernel/semaphore.c
@@ -10,7 +10,7 @@
  *	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>
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 #include <linux/config.h>
 #include <linux/sched.h>
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -65,7 +65,6 @@
 struct cpuinfo_x86 boot_cpu_data;
 
 unsigned long mmu_cr4_features;
-EXPORT_SYMBOL_GPL(mmu_cr4_features);
 
 int acpi_disabled;
 EXPORT_SYMBOL(acpi_disabled);
@@ -77,9 +76,6 @@ int __initdata acpi_force = 0;
 
 int acpi_numa __initdata;
 
-/* For PCI or other memory-mapped resources */
-unsigned long pci_mem_start = 0x10000000;
-
 /* Boot loader ID as an integer, for the benefit of proc_dointvec */
 int bootloader_type;
 
@@ -103,8 +99,6 @@ struct sys_desc_table_struct {
 struct edid_info edid_info;
 struct e820map e820;
 
-unsigned char aux_device_present;
-
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
@@ -333,6 +327,10 @@ static __init void parse_cmdline_early (
 		else if (!memcmp(from, "acpi=strict", 11)) {
 			acpi_strict = 1;
 		}
+#ifdef CONFIG_X86_IO_APIC
+		else if (!memcmp(from, "acpi_skip_timer_override", 24))
+			acpi_skip_timer_override = 1;
+#endif
 #endif
 
 		if (!memcmp(from, "nolapic", 7) ||
@@ -498,14 +496,12 @@ static void __init reserve_ebda_region(v
 
 void __init setup_arch(char **cmdline_p)
 {
-	unsigned long low_mem_size;
 	unsigned long kernel_end;
 
  	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
 	edid_info = EDID_INFO;
-	aux_device_present = AUX_DEVICE_INFO;
 	saved_video_mode = SAVED_VIDEO_MODE;
 	bootloader_type = LOADER_TYPE;
 
@@ -658,13 +654,7 @@ void __init setup_arch(char **cmdline_p)
 		request_resource(&ioport_resource, &standard_io_resources[i]);
 	}
 
-	/* Will likely break when you have unassigned resources with more
-	   than 4GB memory and bridges that don't support more than 4GB. 
-	   Doing it properly would require to use pci_alloc_consistent
-	   in this case. */
-	low_mem_size = ((end_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
-	if (low_mem_size > pci_mem_start)
-		pci_mem_start = low_mem_size;
+	e820_setup_gap();
 
 #ifdef CONFIG_GART_IOMMU
        iommu_hole_init();
@@ -683,7 +673,7 @@ static int __init get_model_name(struct 
 {
 	unsigned int *v;
 
-	if (c->x86_cpuid_level < 0x80000004)
+	if (c->extended_cpuid_level < 0x80000004)
 		return 0;
 
 	v = (unsigned int *) c->x86_model_id;
@@ -699,7 +689,7 @@ static void __init display_cacheinfo(str
 {
 	unsigned int n, dummy, eax, ebx, ecx, edx;
 
-	n = c->x86_cpuid_level;
+	n = c->extended_cpuid_level;
 
 	if (n >= 0x80000005) {
 		cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
@@ -729,14 +719,50 @@ static void __init display_cacheinfo(str
 	}
 }
 
+/*
+ * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
+ * Assumes number of cores is a power of two.
+ */
+static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+	int cpu = smp_processor_id();
+	int node = 0;
+	unsigned bits;
+	if (c->x86_num_cores == 1)
+		return;
+
+	bits = 0;
+	while ((1 << bits) < c->x86_num_cores)
+		bits++;
+
+	/* Low order bits define the core id (index of core in socket) */
+	cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1);
+	/* Convert the APIC ID into the socket ID */
+	phys_proc_id[cpu] >>= bits;
+
+#ifdef CONFIG_NUMA
+	/* When an ACPI SRAT table is available use the mappings from SRAT
+ 	   instead. */
+	if (acpi_numa <= 0) {
+		node = phys_proc_id[cpu];
+		if (!node_online(node))
+			node = first_node(node_online_map);
+		cpu_to_node[cpu] = node;
+	} else {
+		node = cpu_to_node[cpu];
+	}
+#endif
+
+	printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
+			cpu, c->x86_num_cores, node, cpu_core_id[cpu]);
+#endif
+}
 
 static int __init init_amd(struct cpuinfo_x86 *c)
 {
 	int r;
 	int level;
-#ifdef CONFIG_NUMA
-	int cpu;
-#endif
 
 	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
 	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
@@ -759,26 +785,12 @@ static int __init init_amd(struct cpuinf
 	} 
 	display_cacheinfo(c);
 
-	if (c->x86_cpuid_level >= 0x80000008) {
+	if (c->extended_cpuid_level >= 0x80000008) {
 		c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
 		if (c->x86_num_cores & (c->x86_num_cores - 1))
 			c->x86_num_cores = 1;
 
-#ifdef CONFIG_NUMA
-		/* On a dual core setup the lower bits of apic id
-		   distingush the cores. Fix up the CPU<->node mappings
-		   here based on that.
-		   Assumes number of cores is a power of two.
-		   When using SRAT use mapping from SRAT. */
-		cpu = c->x86_apicid;
-		if (acpi_numa <= 0 && c->x86_num_cores > 1) {
-			cpu_to_node[cpu] = cpu >> hweight32(c->x86_num_cores - 1);
-			if (!node_online(cpu_to_node[cpu]))
-				cpu_to_node[cpu] = first_node(node_online_map);
-		}
-		printk(KERN_INFO "CPU %d(%d) -> Node %d\n",
-				cpu, c->x86_num_cores, cpu_to_node[cpu]);
-#endif
+		amd_detect_cmp(c);
 	}
 
 	return r;
@@ -788,10 +800,10 @@ static void __init detect_ht(struct cpui
 {
 #ifdef CONFIG_SMP
 	u32 	eax, ebx, ecx, edx;
-	int 	index_lsb, index_msb, tmp;
+	int 	index_msb, tmp;
 	int 	cpu = smp_processor_id();
 	
-	if (!cpu_has(c, X86_FEATURE_HT))
+	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
 		return;
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
@@ -800,7 +812,6 @@ static void __init detect_ht(struct cpui
 	if (smp_num_siblings == 1) {
 		printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
 	} else if (smp_num_siblings > 1) {
-		index_lsb = 0;
 		index_msb = 31;
 		/*
 		 * At this point we only support two siblings per
@@ -812,45 +823,65 @@ static void __init detect_ht(struct cpui
 			return;
 		}
 		tmp = smp_num_siblings;
-		while ((tmp & 1) == 0) {
-			tmp >>=1 ;
-			index_lsb++;
-		}
-		tmp = smp_num_siblings;
 		while ((tmp & 0x80000000 ) == 0) {
 			tmp <<=1 ;
 			index_msb--;
 		}
-		if (index_lsb != index_msb )
+		if (smp_num_siblings & (smp_num_siblings - 1))
 			index_msb++;
 		phys_proc_id[cpu] = phys_pkg_id(index_msb);
 		
 		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
 		       phys_proc_id[cpu]);
+
+		smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+
+		tmp = smp_num_siblings;
+		index_msb = 31;
+		while ((tmp & 0x80000000) == 0) {
+			tmp <<=1 ;
+			index_msb--;
+		}
+		if (smp_num_siblings & (smp_num_siblings - 1))
+			index_msb++;
+
+		cpu_core_id[cpu] = phys_pkg_id(index_msb);
+
+		if (c->x86_num_cores > 1)
+			printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+			       cpu_core_id[cpu]);
 	}
 #endif
 }
 
-static void __init sched_cmp_hack(struct cpuinfo_x86 *c)
+/*
+ * find out the number of processor cores on the die
+ */
+static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_SMP
-	/* AMD dual core looks like HT but isn't really. Hide it from the
-	   scheduler. This works around problems with the domain scheduler.
-	   Also probably gives slightly better scheduling and disables
-	   SMT nice which is harmful on dual core.
-	   TBD tune the domain scheduler for dual core. */
-	if (c->x86_vendor == X86_VENDOR_AMD && cpu_has(c, X86_FEATURE_CMP_LEGACY))
-		smp_num_siblings = 1;
-#endif
+	unsigned int eax;
+
+	if (c->cpuid_level < 4)
+		return 1;
+
+	__asm__("cpuid"
+		: "=a" (eax)
+		: "0" (4), "c" (0)
+		: "bx", "dx");
+
+	if (eax & 0x1f)
+		return ((eax >> 26) + 1);
+	else
+		return 1;
 }
-	
+
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
 	/* Cache sizes */
 	unsigned n;
 
 	init_intel_cacheinfo(c);
-	n = c->x86_cpuid_level;
+	n = c->extended_cpuid_level;
 	if (n >= 0x80000008) {
 		unsigned eax = cpuid_eax(0x80000008);
 		c->x86_virt_bits = (eax >> 8) & 0xff;
@@ -859,6 +890,9 @@ static void __init init_intel(struct cpu
 
 	if (c->x86 == 15)
 		c->x86_cache_alignment = c->x86_clflush_size * 2;
+	if (c->x86 >= 15)
+		set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
+ 	c->x86_num_cores = intel_num_cpu_cores(c);
 }
 
 void __init get_cpu_vendor(struct cpuinfo_x86 *c)
@@ -895,8 +929,7 @@ void __init early_identify_cpu(struct cp
 	c->x86_clflush_size = 64;
 	c->x86_cache_alignment = c->x86_clflush_size;
 	c->x86_num_cores = 1;
-	c->x86_apicid = c == &boot_cpu_data ? 0 : c - cpu_data;
-	c->x86_cpuid_level = 0;
+	c->extended_cpuid_level = 0;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
 	/* Get vendor name */
@@ -924,11 +957,14 @@ void __init early_identify_cpu(struct cp
 		} 
 		if (c->x86_capability[0] & (1<<19)) 
 			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
-		c->x86_apicid = misc >> 24;
 	} else {
 		/* Have CPUID level 0 only - unheard of */
 		c->x86 = 4;
 	}
+
+#ifdef CONFIG_SMP
+	phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
 }
 
 /*
@@ -943,11 +979,11 @@ void __init identify_cpu(struct cpuinfo_
 
 	/* AMD-defined flags: level 0x80000001 */
 	xlvl = cpuid_eax(0x80000000);
-	c->x86_cpuid_level = xlvl;
+	c->extended_cpuid_level = xlvl;
 	if ((xlvl & 0xffff0000) == 0x80000000) {
 		if (xlvl >= 0x80000001) {
 			c->x86_capability[1] = cpuid_edx(0x80000001);
-			c->x86_capability[5] = cpuid_ecx(0x80000001);
+			c->x86_capability[6] = cpuid_ecx(0x80000001);
 		}
 		if (xlvl >= 0x80000004)
 			get_model_name(c); /* Default name */
@@ -988,7 +1024,6 @@ void __init identify_cpu(struct cpuinfo_
 
 	select_idle_routine(c);
 	detect_ht(c); 
-	sched_cmp_hack(c);
 
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
@@ -1047,7 +1082,7 @@ static int show_cpuinfo(struct seq_file 
 	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
 
 		/* AMD-defined */
-		"pni", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		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, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
@@ -1059,7 +1094,8 @@ static int show_cpuinfo(struct seq_file 
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 		/* Other (Linux-defined) */
-		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+		"cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
+		"constant_tsc", 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,
@@ -1070,17 +1106,25 @@ static int show_cpuinfo(struct seq_file 
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
+		/* VIA/Cyrix/Centaur-defined */
+		NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
 		/* AMD-defined (#2) */
 		"lahf_lm", "cmp_legacy", 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, NULL, NULL, NULL, NULL, NULL, NULL,
 	};
 	static char *x86_power_flags[] = { 
 		"ts",	/* temperature sensor */
 		"fid",  /* frequency id control */
 		"vid",  /* voltage id control */
 		"ttp",  /* thermal trip */
+		"tm",
+		"stc"
 	};
 
 
@@ -1115,8 +1159,14 @@ static int show_cpuinfo(struct seq_file 
 		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
 	
 #ifdef CONFIG_SMP
-	seq_printf(m, "physical id\t: %d\n", phys_proc_id[c - cpu_data]);
-	seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings);
+	if (smp_num_siblings * c->x86_num_cores > 1) {
+		int cpu = c - cpu_data;
+		seq_printf(m, "physical id\t: %d\n", phys_proc_id[cpu]);
+		seq_printf(m, "siblings\t: %d\n",
+				c->x86_num_cores * smp_num_siblings);
+		seq_printf(m, "core id\t\t: %d\n", cpu_core_id[cpu]);
+		seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
+	}
 #endif	
 
 	seq_printf(m,
@@ -1158,12 +1208,8 @@ static int show_cpuinfo(struct seq_file 
 					seq_printf(m, " [%d]", i);
 			}
 	}
-	seq_printf(m, "\n");
-
-	if (c->x86_num_cores > 1)
-		seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
 
-	seq_printf(m, "\n\n"); 
+	seq_printf(m, "\n\n");
 
 	return 0;
 }
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/bootmem.h>
 #include <linux/bitops.h>
+#include <asm/bootsetup.h>
 #include <asm/pda.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -26,7 +27,7 @@
 #include <asm/mman.h>
 #include <asm/numa.h>
 
-char x86_boot_params[2048] __initdata = {0,};
+char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
 
 cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
 
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -28,6 +28,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/proto.h>
+#include <asm/ia32_unistd.h>
 
 /* #define DEBUG_SIG 1 */
 
@@ -83,7 +84,7 @@ sys_sigaltstack(const stack_t __user *us
 
 struct rt_sigframe
 {
-	char *pretcode;
+	char __user *pretcode;
 	struct ucontext uc;
 	struct siginfo info;
 };
@@ -121,7 +122,7 @@ restore_sigcontext(struct pt_regs *regs,
 		err |= __get_user(buf, &sc->fpstate);
 
 		if (buf) {
-			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
 				goto badframe;
 			err |= restore_i387(buf);
 		} else {
@@ -147,7 +148,7 @@ asmlinkage long sys_rt_sigreturn(struct 
 	unsigned long eax;
 
 	frame = (struct rt_sigframe __user *)(regs->rsp - 8);
-	if (verify_area(VERIFY_READ, frame, sizeof(*frame))) { 
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) {
 		goto badframe;
 	} 
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) { 
@@ -160,9 +161,8 @@ asmlinkage long sys_rt_sigreturn(struct 
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 	
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) {
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
 		goto badframe;
-	} 
 
 #ifdef DEBUG_SIG
 	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
@@ -186,7 +186,6 @@ static inline int
 setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me)
 {
 	int err = 0;
-	unsigned long eflags;
 
 	err |= __put_user(0, &sc->gs);
 	err |= __put_user(0, &sc->fs);
@@ -210,11 +209,7 @@ setup_sigcontext(struct sigcontext __use
 	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);
-	eflags = regs->eflags;
-	if (current->ptrace & PT_PTRACED) {
-		eflags &= ~TF_MASK;
-	}
-	err |= __put_user(eflags, &sc->eflags);
+	err |= __put_user(regs->eflags, &sc->eflags);
 	err |= __put_user(mask, &sc->oldmask);
 	err |= __put_user(me->thread.cr2, &sc->cr2);
 
@@ -253,28 +248,25 @@ static void setup_rt_frame(int sig, stru
 
 	if (used_math()) {
 		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
-		frame = (void __user *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
+		frame = (void __user *)round_down(
+			(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
-		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
-		goto give_sigsegv;
-		}
+		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
+			goto give_sigsegv;
 
 		if (save_i387(fp) < 0) 
 			err |= -1; 
-	} else {
+	} else
 		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
-	}
 
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
+	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) { 
+		if (err)
 			goto give_sigsegv;
 	}
-	}
 		
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
@@ -288,9 +280,8 @@ static void setup_rt_frame(int sig, stru
 	if (sizeof(*set) == 16) { 
 		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
 		__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); 
-	} else { 		
-	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-	}
+	} else
+		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.  */
@@ -302,9 +293,8 @@ static void setup_rt_frame(int sig, stru
 		goto give_sigsegv; 
 	}
 
-	if (err) { 
+	if (err)
 		goto give_sigsegv;
-	} 
 
 #ifdef DEBUG_SIG
 	printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax);
@@ -329,14 +319,9 @@ static void setup_rt_frame(int sig, stru
 	regs->rsp = (unsigned long)frame;
 
 	set_fs(USER_DS);
-	if (regs->eflags & TF_MASK) {
-		if ((current->ptrace & (PT_PTRACED | PT_DTRACE)) == (PT_PTRACED | PT_DTRACE)) {
-			ptrace_notify(SIGTRAP);
-		} else {
-			regs->eflags &= ~TF_MASK;
-		}
-	}
-
+	regs->eflags &= ~TF_MASK;
+	if (test_thread_flag(TIF_SINGLESTEP))
+		ptrace_notify(SIGTRAP);
 #ifdef DEBUG_SIG
 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
 		current->comm, current->pid, frame, regs->rip, frame->pretcode);
@@ -357,7 +342,8 @@ handle_signal(unsigned long sig, siginfo
 		sigset_t *oldset, struct pt_regs *regs)
 {
 #ifdef DEBUG_SIG
-	printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, 
+	printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n",
+		current->pid, sig,
 		regs->rip, regs->rsp, regs);
 #endif
 
@@ -375,10 +361,23 @@ handle_signal(unsigned long sig, siginfo
 					regs->rax = -EINTR;
 					break;
 				}
-			/* fallthrough */
+				/* fallthrough */
 			case -ERESTARTNOINTR:
 				regs->rax = regs->orig_rax;
 				regs->rip -= 2;
+				break;
+		}
+	}
+
+	/*
+	 * If TF is set due to a debugger (PT_DTRACE), clear the TF
+	 * flag so that register information in the sigcontext is
+	 * correct.
+	 */
+	if (unlikely(regs->eflags & TF_MASK)) {
+		if (likely(current->ptrace & PT_DTRACE)) {
+			current->ptrace &= ~PT_DTRACE;
+			regs->eflags &= ~TF_MASK;
 		}
 	}
 
@@ -418,9 +417,8 @@ int do_signal(struct pt_regs *regs, sigs
 	 * kernel mode. Just return without doing anything
 	 * if so.
 	 */
-	if ((regs->cs & 3) != 3) {
+	if ((regs->cs & 3) != 3)
 		return 1;
-	} 	
 
 	if (try_to_freeze(0))
 		goto no_signal;
@@ -455,7 +453,9 @@ int do_signal(struct pt_regs *regs, sigs
 			regs->rip -= 2;
 		}
 		if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) {
-			regs->rax = __NR_restart_syscall;
+			regs->rax = test_thread_flag(TIF_IA32) ?
+					__NR_ia32_restart_syscall :
+					__NR_restart_syscall;
 			regs->rip -= 2;
 		}
 	}
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -25,7 +25,9 @@
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mach_apic.h>
+#include <asm/mmu_context.h>
 #include <asm/proto.h>
+#include <asm/apicdef.h>
 
 /*
  *	Smarter SMP flushing macros. 
@@ -41,7 +43,7 @@ static cpumask_t flush_cpumask;
 static struct mm_struct * flush_mm;
 static unsigned long flush_va;
 static DEFINE_SPINLOCK(tlbstate_lock);
-#define FLUSH_ALL	0xffffffff
+#define FLUSH_ALL	-1ULL
 
 /*
  * We cannot call mmdrop() because we are in interrupt context, 
@@ -52,7 +54,7 @@ static inline void leave_mm (unsigned lo
 	if (read_pda(mmu_state) == TLBSTATE_OK)
 		BUG();
 	clear_bit(cpu, &read_pda(active_mm)->cpu_vm_mask);
-	__flush_tlb();
+	load_cr3(swapper_pg_dir);
 }
 
 /*
@@ -372,7 +374,10 @@ void smp_send_stop(void)
 	__smp_call_function(smp_really_stop_cpu, NULL, 0, 0);
 	if (!nolock)
 		spin_unlock(&call_lock);
-	smp_stop_cpu();
+
+	local_irq_disable();
+	disable_local_APIC();
+	local_irq_enable();
 }
 
 /*
@@ -409,3 +414,27 @@ asmlinkage void smp_call_function_interr
 		atomic_inc(&call_data->finished);
 	}
 }
+
+int safe_smp_processor_id(void)
+{
+	int apicid, i;
+
+	if (disable_apic)
+		return 0;
+
+	apicid = hard_smp_processor_id();
+	if (x86_cpu_to_apicid[apicid] == apicid)
+		return apicid;
+
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (x86_cpu_to_apicid[i] == apicid)
+			return i;
+	}
+
+	/* No entries in x86_cpu_to_apicid?  Either no MPS|ACPI,
+	 * or called too early.  Either way, we must be CPU 0. */
+      	if (x86_cpu_to_apicid[0] == BAD_APICID)
+		return 0;
+
+	return 0; /* Should not happen */
+}
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -12,8 +12,7 @@
  *	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.
+ *	This code is released under the GNU General Public License version 2
  *
  *	Fixes
  *		Felix Koop	:	NR_CPUS used properly
@@ -31,9 +30,13 @@
  *		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.
- *		Rusty Russell	:	Hacked into shape for new "hotplug" boot process. 
+ *		Rusty Russell	:	Hacked into shape for new "hotplug" boot process.
+ *      Andi Kleen              :       Converted to new state machine.
+ *					Various cleanups.
+ *					Probably mostly hotplug CPU ready now.
  */
 
+
 #include <linux/config.h>
 #include <linux/init.h>
 
@@ -53,19 +56,35 @@
 #include <asm/kdebug.h>
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
+#include <asm/nmi.h>
+
+/* Change for real CPU hotplug. Note other files need to be fixed
+   first too. */
+#define __cpuinit __init
+#define __cpuinitdata __initdata
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
 /* Package ID of each logical CPU */
 u8 phys_proc_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_core_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 EXPORT_SYMBOL(phys_proc_id);
+EXPORT_SYMBOL(cpu_core_id);
 
 /* Bitmask of currently online CPUs */
 cpumask_t cpu_online_map;
 
+EXPORT_SYMBOL(cpu_online_map);
+
+/*
+ * Private maps to synchronize booting between AP and BP.
+ * Probably not needed anymore, but it makes for easier debugging. -AK
+ */
 cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
-static cpumask_t smp_commenced_mask;
+
+cpumask_t cpu_possible_map;
+EXPORT_SYMBOL(cpu_possible_map);
 
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
@@ -74,13 +93,15 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] __c
 int smp_threads_ready;
 
 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
 
 /*
  * Trampoline 80x86 program as an array.
  */
 
-extern unsigned char trampoline_data [];
-extern unsigned char trampoline_end  [];
+extern unsigned char trampoline_data[];
+extern unsigned char trampoline_end[];
 
 /*
  * Currently trivial. Write the real->protected mode
@@ -88,11 +109,9 @@ extern unsigned char trampoline_end  [];
  * has made sure it's suitably aligned.
  */
 
-static unsigned long __init setup_trampoline(void)
+static unsigned long __cpuinit setup_trampoline(void)
 {
 	void *tramp = __va(SMP_TRAMPOLINE_BASE); 
-	extern volatile __u32 tramp_gdt_ptr; 
-	tramp_gdt_ptr = __pa_symbol(&cpu_gdt_table); 
 	memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
 	return virt_to_phys(tramp);
 }
@@ -102,154 +121,224 @@ static unsigned long __init setup_trampo
  * a given CPU
  */
 
-static void __init smp_store_cpu_info(int id)
+static void __cpuinit smp_store_cpu_info(int id)
 {
 	struct cpuinfo_x86 *c = cpu_data + id;
 
 	*c = boot_cpu_data;
 	identify_cpu(c);
+	print_cpu_info(c);
 }
 
 /*
- * TSC synchronization.
+ * New Funky TSC sync algorithm borrowed from IA64.
+ * Main advantage is that it doesn't reset the TSCs fully and
+ * in general looks more robust and it works better than my earlier
+ * attempts. I believe it was written by David Mosberger. Some minor
+ * adjustments for x86-64 by me -AK
+ *
+ * Original comment reproduced below.
+ *
+ * Synchronize TSC of the current (slave) CPU with the TSC of the
+ * MASTER CPU (normally the time-keeper CPU).  We use a closed loop to
+ * eliminate the possibility of unaccounted-for errors (such as
+ * getting a machine check in the middle of a calibration step).  The
+ * basic idea is for the slave to ask the master what itc value it has
+ * and to read its own itc before and after the master responds.  Each
+ * iteration gives us three timestamps:
  *
- * We first check whether all CPUs have their TSC's synchronized,
- * then we print a warning if not, and always resync.
+ *	slave		master
+ *
+ *	t0 ---\
+ *             ---\
+ *		   --->
+ *			tm
+ *		   /---
+ *	       /---
+ *	t1 <---
+ *
+ *
+ * The goal is to adjust the slave's TSC such that tm falls exactly
+ * half-way between t0 and t1.  If we achieve this, the clocks are
+ * synchronized provided the interconnect between the slave and the
+ * master is symmetric.  Even if the interconnect were asymmetric, we
+ * would still know that the synchronization error is smaller than the
+ * roundtrip latency (t0 - t1).
+ *
+ * When the interconnect is quiet and symmetric, this lets us
+ * synchronize the TSC to within one or two cycles.  However, we can
+ * only *guarantee* that the synchronization is accurate to within a
+ * round-trip time, which is typically in the range of several hundred
+ * cycles (e.g., ~500 cycles).  In practice, this means that the TSCs
+ * are usually almost perfectly synchronized, but we shouldn't assume
+ * that the accuracy is much better than half a micro second or so.
+ *
+ * [there are other errors like the latency of RDTSC and of the
+ * WRMSR. These can also account to hundreds of cycles. So it's
+ * probably worse. It claims 153 cycles error on a dual Opteron,
+ * but I suspect the numbers are actually somewhat worse -AK]
  */
 
-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 MASTER	0
+#define SLAVE	(SMP_CACHE_BYTES/8)
 
-#define NR_LOOPS 5
+/* Intentionally don't use cpu_relax() while TSC synchronization
+   because we don't want to go into funky power save modi or cause
+   hypervisors to schedule us away.  Going to sleep would likely affect
+   latency and low latency is the primary objective here. -AK */
+#define no_cpu_relax() barrier()
+
+static __cpuinitdata DEFINE_SPINLOCK(tsc_sync_lock);
+static volatile __cpuinitdata unsigned long go[SLAVE + 1];
+static int notscsync __cpuinitdata;
 
-extern unsigned int fast_gettimeoffset_quotient;
+#undef DEBUG_TSC_SYNC
 
-static void __init synchronize_tsc_bp (void)
-{
-	int i;
-	unsigned long long t0;
-	unsigned long long sum, avg;
-	long long delta;
-	long one_usec;
-	int buggy = 0;
-
-	printk(KERN_INFO "checking TSC synchronization across %u CPUs: ",num_booting_cpus());
-
-	one_usec = cpu_khz; 
-
-	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) != num_booting_cpus()-1) mb();
-		atomic_set(&tsc_count_stop, 0);
-		wmb();
-		/*
-		 * this lets the APs save their current TSC:
-		 */
-		atomic_inc(&tsc_count_start);
-
-		sync_core();
-		rdtscll(tsc_values[smp_processor_id()]);
-		/*
-		 * We clear the TSC in the last loop:
-		 */
-		if (i == NR_LOOPS-1)
-			write_tsc(0, 0);
+#define NUM_ROUNDS	64	/* magic value */
+#define NUM_ITERS	5	/* likewise */
 
-		/*
-		 * Wait for all APs to leave the synchronization point:
-		 */
-		while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1) mb();
-		atomic_set(&tsc_count_start, 0);
-		wmb();
-		atomic_inc(&tsc_count_stop);
-	}
-
-	sum = 0;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_isset(i, cpu_callout_map)) {
-		t0 = tsc_values[i];
-		sum += t0;
-	}
-	}
-	avg = sum / num_booting_cpus();
+/* Callback on boot CPU */
+static __cpuinit void sync_master(void *arg)
+{
+	unsigned long flags, i;
 
-	sum = 0;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!cpu_isset(i, cpu_callout_map))
-			continue;
+	if (smp_processor_id() != boot_cpu_id)
+		return;
 
-		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 = delta / one_usec;
-			if (tsc_values[i] < avg)
-				realdelta = -realdelta;
+	go[MASTER] = 0;
 
-			printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
-				i, realdelta);
+	local_irq_save(flags);
+	{
+		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
+			while (!go[MASTER])
+				no_cpu_relax();
+			go[MASTER] = 0;
+			rdtscll(go[SLAVE]);
 		}
-
-		sum += delta;
 	}
-	if (!buggy)
-		printk("passed.\n");
+	local_irq_restore(flags);
 }
 
-static void __init synchronize_tsc_ap (void)
+/*
+ * Return the number of cycles by which our tsc differs from the tsc
+ * on the master (time-keeper) CPU.  A positive number indicates our
+ * tsc is ahead of the master, negative that it is behind.
+ */
+static inline long
+get_delta(long *rt, long *master)
 {
+	unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
+	unsigned long tcenter, t0, t1, tm;
 	int i;
 
-	/*
-	 * Not every cpu is online 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 < NUM_ITERS; ++i) {
+		rdtscll(t0);
+		go[MASTER] = 1;
+		while (!(tm = go[SLAVE]))
+			no_cpu_relax();
+		go[SLAVE] = 0;
+		rdtscll(t1);
+
+		if (t1 - t0 < best_t1 - best_t0)
+			best_t0 = t0, best_t1 = t1, best_tm = tm;
+	}
+
+	*rt = best_t1 - best_t0;
+	*master = best_tm - best_t0;
+
+	/* average best_t0 and best_t1 without overflow: */
+	tcenter = (best_t0/2 + best_t1/2);
+	if (best_t0 % 2 + best_t1 % 2 == 2)
+		++tcenter;
+	return tcenter - best_tm;
+}
 
-	for (i = 0; i < NR_LOOPS; i++) {
-		atomic_inc(&tsc_count_start);
-		while (atomic_read(&tsc_count_start) != num_booting_cpus()) mb();
+static __cpuinit void sync_tsc(void)
+{
+	int i, done = 0;
+	long delta, adj, adjust_latency = 0;
+	unsigned long flags, rt, master_time_stamp, bound;
+#if DEBUG_TSC_SYNC
+	static struct syncdebug {
+		long rt;	/* roundtrip time */
+		long master;	/* master's timestamp */
+		long diff;	/* difference between midpoint and master's timestamp */
+		long lat;	/* estimate of tsc adjustment latency */
+	} t[NUM_ROUNDS] __cpuinitdata;
+#endif
+
+	go[MASTER] = 1;
+
+	smp_call_function(sync_master, NULL, 1, 0);
+
+	while (go[MASTER])	/* wait for master to be ready */
+		no_cpu_relax();
+
+	spin_lock_irqsave(&tsc_sync_lock, flags);
+	{
+		for (i = 0; i < NUM_ROUNDS; ++i) {
+			delta = get_delta(&rt, &master_time_stamp);
+			if (delta == 0) {
+				done = 1;	/* let's lock on to this... */
+				bound = rt;
+			}
 
-		sync_core();
-		rdtscll(tsc_values[smp_processor_id()]);
-		if (i == NR_LOOPS-1)
-			write_tsc(0, 0);
+			if (!done) {
+				unsigned long t;
+				if (i > 0) {
+					adjust_latency += -delta;
+					adj = -delta + adjust_latency/4;
+				} else
+					adj = -delta;
 
-		atomic_inc(&tsc_count_stop);
-		while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
+				rdtscll(t);
+				wrmsrl(MSR_IA32_TSC, t + adj);
+			}
+#if DEBUG_TSC_SYNC
+			t[i].rt = rt;
+			t[i].master = master_time_stamp;
+			t[i].diff = delta;
+			t[i].lat = adjust_latency/4;
+#endif
+		}
 	}
+	spin_unlock_irqrestore(&tsc_sync_lock, flags);
+
+#if DEBUG_TSC_SYNC
+	for (i = 0; i < NUM_ROUNDS; ++i)
+		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
+		       t[i].rt, t[i].master, t[i].diff, t[i].lat);
+#endif
+
+	printk(KERN_INFO
+	       "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, "
+	       "maxerr %lu cycles)\n",
+	       smp_processor_id(), boot_cpu_id, delta, rt);
 }
-#undef NR_LOOPS
 
-static atomic_t init_deasserted;
+static void __cpuinit tsc_sync_wait(void)
+{
+	if (notscsync || !cpu_has_tsc)
+		return;
+	printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", smp_processor_id(),
+			boot_cpu_id);
+	sync_tsc();
+}
 
-void __init smp_callin(void)
+static __init int notscsync_setup(char *s)
+{
+	notscsync = 1;
+	return 0;
+}
+__setup("notscsync", notscsync_setup);
+
+static atomic_t init_deasserted __cpuinitdata;
+
+/*
+ * Report back to the Boot Processor.
+ * Running on AP.
+ */
+void __cpuinit smp_callin(void)
 {
 	int cpuid, phys_id;
 	unsigned long timeout;
@@ -260,7 +349,8 @@ void __init smp_callin(void)
 	 * our local APIC.  We have to wait for the IPI or we'll
 	 * lock up on an APIC access.
 	 */
-	while (!atomic_read(&init_deasserted));
+	while (!atomic_read(&init_deasserted))
+		cpu_relax();
 
 	/*
 	 * (This works even if the APIC is not enabled.)
@@ -291,7 +381,7 @@ void __init smp_callin(void)
 		 */
 		if (cpu_isset(cpuid, cpu_callout_map))
 			break;
-		rep_nop();
+		cpu_relax();
 	}
 
 	if (!time_before(jiffies, timeout)) {
@@ -309,8 +399,6 @@ void __init smp_callin(void)
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	setup_local_APIC();
 
-	local_irq_enable();
-
 	/*
 	 * Get our bogomips.
 	 */
@@ -324,26 +412,16 @@ void __init smp_callin(void)
 	 */
  	smp_store_cpu_info(cpuid);
 
-	local_irq_disable();
-
 	/*
 	 * Allow the master to continue.
 	 */
 	cpu_set(cpuid, cpu_callin_map);
-
-	/*
-	 *      Synchronize the TSC with the BP
-	 */
-	if (cpu_has_tsc)
-		synchronize_tsc_ap();
 }
 
-int cpucount;
-
 /*
- * Activate a secondary processor.
+ * Setup code on secondary processor (after comming out of the trampoline)
  */
-void __init start_secondary(void)
+void __cpuinit start_secondary(void)
 {
 	/*
 	 * Dont put anything before smp_callin(), SMP
@@ -356,14 +434,10 @@ void __init start_secondary(void)
 	/* otherwise gcc will move up the smp_processor_id before the cpu_init */
 	barrier();
 
-	Dprintk("cpu %d: waiting for commence\n", smp_processor_id()); 
-	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
-		rep_nop();
-
 	Dprintk("cpu %d: setting up apic clock\n", smp_processor_id()); 	
 	setup_secondary_APIC_clock();
 
-	Dprintk("cpu %d: enabling apic timer\n", smp_processor_id()); 
+	Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
 
 	if (nmi_watchdog == NMI_IO_APIC) {
 		disable_8259A_irq(0);
@@ -371,27 +445,27 @@ void __init start_secondary(void)
 		enable_8259A_irq(0);
 	}
 
-
-	enable_APIC_timer(); 
+	enable_APIC_timer();
 
 	/*
-	 * low-memory mappings have been cleared, flush them from
-	 * the local TLBs too.
+	 * Allow the master to continue.
 	 */
-	local_flush_tlb();
-
-	Dprintk("cpu %d eSetting cpu_online_map\n", smp_processor_id()); 
 	cpu_set(smp_processor_id(), cpu_online_map);
-	wmb();
-	
+	mb();
+
+	/* Wait for TSC sync to not schedule things before.
+	   We still process interrupts, which could see an inconsistent
+	   time in that window unfortunately. */
+	tsc_sync_wait();
+
 	cpu_idle();
 }
 
-extern volatile unsigned long init_rsp; 
+extern volatile unsigned long init_rsp;
 extern void (*initial_code)(void);
 
 #if APIC_DEBUG
-static inline void inquire_remote_apic(int apicid)
+static void inquire_remote_apic(int apicid)
 {
 	unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
 	char *names[] = { "ID", "VERSION", "SPIV" };
@@ -428,7 +502,10 @@ static inline void inquire_remote_apic(i
 }
 #endif
 
-static int __init wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
+/*
+ * Kick the secondary to wake up.
+ */
+static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
 {
 	unsigned long send_status = 0, accept_status = 0;
 	int maxlvt, timeout, num_starts, j;
@@ -551,33 +628,35 @@ static int __init wakeup_secondary_via_I
 	return (send_status | accept_status);
 }
 
-static void __init do_boot_cpu (int apicid)
+/*
+ * Boot one CPU.
+ */
+static int __cpuinit do_boot_cpu(int cpu, int apicid)
 {
 	struct task_struct *idle;
 	unsigned long boot_error;
-	int timeout, cpu;
+	int timeout;
 	unsigned long start_rip;
-
-	cpu = ++cpucount;
 	/*
 	 * We can't use kernel_thread since we must avoid to
 	 * reschedule the child.
 	 */
 	idle = fork_idle(cpu);
-	if (IS_ERR(idle))
-		panic("failed fork for CPU %d", cpu);
-	x86_cpu_to_apicid[cpu] = apicid;
+	if (IS_ERR(idle)) {
+		printk("failed fork for CPU %d\n", cpu);
+		return PTR_ERR(idle);
+	}
 
 	cpu_pda[cpu].pcurrent = idle;
 
 	start_rip = setup_trampoline();
 
-	init_rsp = idle->thread.rsp; 
+	init_rsp = idle->thread.rsp;
 	per_cpu(init_tss,cpu).rsp0 = init_rsp;
 	initial_code = start_secondary;
 	clear_ti_thread_flag(idle->thread_info, TIF_FORK);
 
-	printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid, 
+	printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid,
 	       start_rip, init_rsp);
 
 	/*
@@ -614,7 +693,7 @@ static void __init do_boot_cpu (int apic
 	/*
 	 * Starting actual IPI sequence...
 	 */
-	boot_error = wakeup_secondary_via_INIT(apicid, start_rip); 
+	boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
 
 	if (!boot_error) {
 		/*
@@ -635,8 +714,6 @@ static void __init do_boot_cpu (int apic
 
 		if (cpu_isset(cpu, cpu_callin_map)) {
 			/* number CPUs logically, starting from 1 (BSP is 0) */
-			Dprintk("OK.\n");
-			print_cpu_info(&cpu_data[cpu]);
 			Dprintk("CPU has booted.\n");
 		} else {
 			boot_error = 1;
@@ -655,76 +732,131 @@ static void __init do_boot_cpu (int apic
 	if (boot_error) {
 		cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
 		clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
-		cpucount--;
+		cpu_clear(cpu, cpu_present_map);
+		cpu_clear(cpu, cpu_possible_map);
 		x86_cpu_to_apicid[cpu] = BAD_APICID;
 		x86_cpu_to_log_apicid[cpu] = BAD_APICID;
+		return -EIO;
 	}
+
+	return 0;
 }
 
 cycles_t cacheflush_time;
 unsigned long cache_decay_ticks;
 
-static void smp_tune_scheduling (void)
+/*
+ * Construct cpu_sibling_map[], so that we can tell the sibling CPU
+ * on SMT systems efficiently.
+ */
+static __cpuinit void detect_siblings(void)
 {
-	int cachesize;       /* kB   */
-	unsigned long bandwidth = 1000; /* 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)
-	 */
+	int cpu;
 
-	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;
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		cpus_clear(cpu_sibling_map[cpu]);
+		cpus_clear(cpu_core_map[cpu]);
 	}
 
-	cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
+	for_each_online_cpu (cpu) {
+		struct cpuinfo_x86 *c = cpu_data + cpu;
+		int siblings = 0;
+		int i;
+		if (smp_num_siblings > 1) {
+			for_each_online_cpu (i) {
+				if (cpu_core_id[cpu] == cpu_core_id[i]) {
+					siblings++;
+					cpu_set(i, cpu_sibling_map[cpu]);
+				}
+			}
+		} else {
+			siblings++;
+			cpu_set(cpu, cpu_sibling_map[cpu]);
+		}
 
-	printk(KERN_INFO "per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
-		(long)cacheflush_time/(cpu_khz/1000),
-		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
-	printk(KERN_INFO "task migration cache decay timeout: %ld msecs.\n",
-		(cache_decay_ticks + 1) * 1000 / HZ);
+		if (siblings != smp_num_siblings) {
+			printk(KERN_WARNING
+	       "WARNING: %d siblings found for CPU%d, should be %d\n",
+			       siblings, cpu, smp_num_siblings);
+			smp_num_siblings = siblings;
+		}
+		if (c->x86_num_cores > 1) {
+			for_each_online_cpu(i) {
+				if (phys_proc_id[cpu] == phys_proc_id[i])
+					cpu_set(i, cpu_core_map[cpu]);
+			}
+		} else
+			cpu_core_map[cpu] = cpu_sibling_map[cpu];
+	}
 }
 
 /*
- * Cycle through the processors sending APIC IPIs to boot each.
+ * Cleanup possible dangling ends...
  */
-
-static void __init smp_boot_cpus(unsigned int max_cpus)
+static __cpuinit void smp_cleanup_boot(void)
 {
-	unsigned apicid, cpu, bit, kicked;
+	/*
+	 * Paranoid:  Set warm reset code and vector here back
+	 * to default values.
+	 */
+	CMOS_WRITE(0, 0xf);
 
-	nmi_watchdog_default();
+	/*
+	 * Reset trampoline flag
+	 */
+	*((volatile int *) phys_to_virt(0x467)) = 0;
 
+#ifndef CONFIG_HOTPLUG_CPU
 	/*
-	 * Setup boot CPU information
+	 * Free pages reserved for SMP bootup.
+	 * When you add hotplug CPU support later remove this
+	 * Note there is more work to be done for later CPU bootup.
 	 */
-	smp_store_cpu_info(0); /* Final full version of the data */
-	printk(KERN_INFO "CPU%d: ", 0);
-	print_cpu_info(&cpu_data[0]);
 
-	current_thread_info()->cpu = 0;
-	smp_tune_scheduling();
+	free_page((unsigned long) __va(PAGE_SIZE));
+	free_page((unsigned long) __va(SMP_TRAMPOLINE_BASE));
+#endif
+}
+
+/*
+ * Fall back to non SMP mode after errors.
+ *
+ * RED-PEN audit/test this more. I bet there is more state messed up here.
+ */
+static __cpuinit void disable_smp(void)
+{
+	cpu_present_map = cpumask_of_cpu(0);
+	cpu_possible_map = cpumask_of_cpu(0);
+	if (smp_found_config)
+		phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
+	else
+		phys_cpu_present_map = physid_mask_of_physid(0);
+	cpu_set(0, cpu_sibling_map[0]);
+	cpu_set(0, cpu_core_map[0]);
+}
+
+/*
+ * Handle user cpus=... parameter.
+ */
+static __cpuinit void enforce_max_cpus(unsigned max_cpus)
+{
+	int i, k;
+	k = 0;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!cpu_possible(i))
+			continue;
+		if (++k > max_cpus) {
+			cpu_clear(i, cpu_possible_map);
+			cpu_clear(i, cpu_present_map);
+		}
+	}
+}
 
+/*
+ * Various sanity checks.
+ */
+static int __cpuinit smp_sanity_check(unsigned max_cpus)
+{
 	if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
 		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
 		       hard_smp_processor_id());
@@ -737,13 +869,11 @@ static void __init smp_boot_cpus(unsigne
 	 */
 	if (!smp_found_config) {
 		printk(KERN_NOTICE "SMP motherboard not detected.\n");
-		io_apic_irqs = 0;
-		cpu_online_map = cpumask_of_cpu(0);
-		phys_cpu_present_map = physid_mask_of_physid(0);
+		disable_smp();
 		if (APIC_init_uniprocessor())
 			printk(KERN_NOTICE "Local APIC not detected."
 					   " Using dummy APIC emulation.\n");
-		goto smp_done;
+		return -1;
 	}
 
 	/*
@@ -763,196 +893,143 @@ static void __init smp_boot_cpus(unsigne
 		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 = cpumask_of_cpu(0);
-		phys_cpu_present_map = physid_mask_of_physid(0);
-		disable_apic = 1;
-		goto smp_done;
+		nr_ioapics = 0;
+		return -1;
 	}
 
-	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 = cpumask_of_cpu(0);
-		phys_cpu_present_map = physid_mask_of_physid(0);
-		disable_apic = 1;
-		goto smp_done;
+		nr_ioapics = 0;
+		return -1;
 	}
 
-	connect_bsp_APIC();
-	setup_local_APIC();
-
-	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
-		BUG();
-
-	x86_cpu_to_apicid[0] = boot_cpu_id;
-
-	/*
-	 * Now scan the CPU present map and fire up the other CPUs.
-	 */
-	Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map));
+	return 0;
+}
 
-	kicked = 1;
-	for (bit = 0; kicked < NR_CPUS && bit < MAX_APICS; bit++) {
-		apicid = cpu_present_to_apicid(bit);
-		/*
-		 * Don't even attempt to start the boot CPU!
-		 */
-		if (apicid == boot_cpu_id || (apicid == BAD_APICID))
-			continue;
+/*
+ * Prepare for SMP bootup.  The MP table or ACPI has been read
+ * earlier.  Just do some sanity checking here and enable APIC mode.
+ */
+void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i;
 
-		if (!physid_isset(apicid, phys_cpu_present_map))
-			continue;
-		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
-			continue;
+	nmi_watchdog_default();
+	current_cpu_data = boot_cpu_data;
+	current_thread_info()->cpu = 0;  /* needed? */
 
-		do_boot_cpu(apicid);
-		++kicked;
-	}
+	enforce_max_cpus(max_cpus);
 
 	/*
-	 * Cleanup possible dangling ends...
+	 * Fill in cpu_present_mask
 	 */
-	{
-		/*
-		 * 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;
+	for (i = 0; i < NR_CPUS; i++) {
+		int apicid = cpu_present_to_apicid(i);
+		if (physid_isset(apicid, phys_cpu_present_map)) {
+			cpu_set(i, cpu_present_map);
+			/* possible map would be different if we supported real
+			   CPU hotplug. */
+			cpu_set(i, cpu_possible_map);
+		}
 	}
 
-	/*
-	 * Allow the user to impress friends.
-	 */
-
-	Dprintk("Before bogomips.\n");
-	if (!cpucount) {
-		printk(KERN_INFO "Only one processor found.\n");
-	} else {
-		unsigned long bogosum = 0;
-		for (cpu = 0; cpu < NR_CPUS; cpu++)
-			if (cpu_isset(cpu, cpu_callout_map))
-				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");
+	if (smp_sanity_check(max_cpus) < 0) {
+		printk(KERN_INFO "SMP disabled\n");
+		disable_smp();
+		return;
 	}
 
+
 	/*
-	 * Construct cpu_sibling_map[], so that we can tell the
-	 * sibling CPU efficiently.
+	 * Switch from PIC to APIC mode.
 	 */
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
-		cpus_clear(cpu_sibling_map[cpu]);
-
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		int siblings = 0;
-		int i;
-		if (!cpu_isset(cpu, cpu_callout_map))
-			continue;
-
-		if (smp_num_siblings > 1) {
-			for (i = 0; i < NR_CPUS; i++) {
-				if (!cpu_isset(i, cpu_callout_map))
-					continue;
-				if (phys_proc_id[cpu] == phys_proc_id[i]) {
-					siblings++;
-					cpu_set(i, cpu_sibling_map[cpu]);
-				}
-			}
-		} else { 
-			siblings++;
-			cpu_set(cpu, cpu_sibling_map[cpu]);
-		}
+	connect_bsp_APIC();
+	setup_local_APIC();
 
-		if (siblings != smp_num_siblings) {
-			printk(KERN_WARNING 
-	       "WARNING: %d siblings found for CPU%d, should be %d\n", 
-			       siblings, cpu, smp_num_siblings);
-			smp_num_siblings = siblings;
-		}       
+	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) {
+		panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+		      GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_id);
+		/* Or can we switch back to PIC here? */
 	}
 
-	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:
+	 * Now start the IO-APICs
 	 */
 	if (!skip_ioapic_setup && nr_ioapics)
 		setup_IO_APIC();
 	else
 		nr_ioapics = 0;
 
-	setup_boot_APIC_clock();
-
 	/*
-	 * Synchronize the TSC with the AP
+	 * Set up local APIC timer on boot CPU.
 	 */
-	if (cpu_has_tsc && cpucount)
-		synchronize_tsc_bp();
 
- smp_done:
-	time_init_smp();
+	setup_boot_APIC_clock();
 }
 
-/* These are wrappers to interface to the new boot process.  Someone
-   who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
-void __init smp_prepare_cpus(unsigned int max_cpus)
+/*
+ * Early setup to make printk work.
+ */
+void __init smp_prepare_boot_cpu(void)
 {
-	smp_boot_cpus(max_cpus);
+	int me = smp_processor_id();
+	cpu_set(me, cpu_online_map);
+	cpu_set(me, cpu_callout_map);
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+/*
+ * Entry point to boot a CPU.
+ *
+ * This is all __cpuinit, not __devinit for now because we don't support
+ * CPU hotplug (yet).
+ */
+int __cpuinit __cpu_up(unsigned int cpu)
 {
-	cpu_set(smp_processor_id(), cpu_online_map);
-	cpu_set(smp_processor_id(), cpu_callout_map);
-}
+	int err;
+	int apicid = cpu_present_to_apicid(cpu);
 
-int __devinit __cpu_up(unsigned int cpu)
-{
-	/* This only works at boot for x86.  See "rewrite" above. */
-	if (cpu_isset(cpu, smp_commenced_mask)) {
-		local_irq_enable();
-		return -ENOSYS;
+	WARN_ON(irqs_disabled());
+
+	Dprintk("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
+
+	if (apicid == BAD_APICID || apicid == boot_cpu_id ||
+	    !physid_isset(apicid, phys_cpu_present_map)) {
+		printk("__cpu_up: bad cpu %d\n", cpu);
+		return -EINVAL;
 	}
 
-	/* In case one didn't come up */
-	if (!cpu_isset(cpu, cpu_callin_map)) {
-		local_irq_enable();
-		return -EIO;
+	/* Boot it! */
+	err = do_boot_cpu(cpu, apicid);
+	if (err < 0) {
+		Dprintk("do_boot_cpu failed %d\n", err);
+		return err;
 	}
-	local_irq_enable();
 
 	/* Unleash the CPU! */
 	Dprintk("waiting for cpu %d\n", cpu);
 
-	cpu_set(cpu, smp_commenced_mask);
 	while (!cpu_isset(cpu, cpu_online_map))
-		mb();
+		cpu_relax();
 	return 0;
 }
 
-void __init smp_cpus_done(unsigned int max_cpus)
+/*
+ * Finish the SMP boot.
+ */
+void __cpuinit smp_cpus_done(unsigned int max_cpus)
 {
+	zap_low_mappings();
+	smp_cleanup_boot();
+
 #ifdef CONFIG_X86_IO_APIC
 	setup_ioapic_dest();
 #endif
-	zap_low_mappings();
-}
 
+	detect_siblings();
+	time_init_gtod();
+
+	check_nmi_watchdog();
+}
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
--- a/arch/x86_64/kernel/suspend_asm.S
+++ b/arch/x86_64/kernel/suspend_asm.S
@@ -54,16 +54,10 @@ ENTRY(swsusp_arch_resume)
 	movq	%rax, %cr4;  # turn PGE back on
 
 	movq	pagedir_nosave(%rip), %rdx
-	/* compute the limit */
-	movl	nr_copy_pages(%rip), %eax
-	testl	%eax, %eax
-	jz	done
-	movq	%rdx,%r8
-	movl	$SIZEOF_PBE,%r9d
-	mul		%r9  # with rax, clobbers rdx
-	movq 	%r8, %rdx
-	addq	%r8, %rax
 loop:
+	testq	%rdx, %rdx
+	jz	done
+
 	/* get addresses from the pbe and copy the page */
 	movq	pbe_address(%rdx), %rsi
 	movq	pbe_orig_address(%rdx), %rdi
@@ -72,16 +66,24 @@ loop:
 	movsq
 
 	/* progress to the next pbe */
-	addq	$SIZEOF_PBE, %rdx
-	cmpq	%rax, %rdx
-	jb	loop
+	movq	pbe_next(%rdx), %rdx
+	jmp	loop
 done:
+	/* Flush TLB, including "global" things (vmalloc) */
+	movq	mmu_cr4_features(%rip), %rax
+	movq	%rax, %rdx
+	andq	$~(1<<7), %rdx;  # PGE
+	movq	%rdx, %cr4;  # turn off PGE
+	movq	%cr3, %rcx;  # flush TLB
+	movq	%rcx, %cr3
+	movq	%rax, %cr4;  # turn PGE back on
+
 	movl	$24, %eax
 	movl	%eax, %ds
 
 	movq saved_context_esp(%rip), %rsp
 	movq saved_context_ebp(%rip), %rbp
-	movq saved_context_eax(%rip), %rax
+	/* Don't restore %rax, it must be 0 anyway */
 	movq saved_context_ebx(%rip), %rbx
 	movq saved_context_ecx(%rip), %rcx
 	movq saved_context_edx(%rip), %rdx
@@ -96,5 +98,7 @@ done:
 	movq saved_context_r14(%rip), %r14
 	movq saved_context_r15(%rip), %r15
 	pushq saved_context_eflags(%rip) ; popfq
-	call	swsusp_restore
+
+	xorq	%rax, %rax
+
 	ret
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -18,7 +18,6 @@
 #include <linux/personality.h>
 
 #include <asm/uaccess.h>
-#include <asm/ipc.h>
 #include <asm/ia32.h>
 
 /*
@@ -38,7 +37,7 @@ asmlinkage long sys_pipe(int __user *fil
 	return error;
 }
 
-long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long off)
 {
 	long error;
@@ -153,12 +152,6 @@ asmlinkage long sys_uname(struct new_uts
 	return err ? -EFAULT : 0;
 }
 
-asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
-{
-	unsigned long raddr;
-	return do_shmat(shmid,shmaddr,shmflg,&raddr) ?: (long)raddr;
-}
-
 asmlinkage long sys_time64(long __user * tloc)
 {
 	struct timeval now; 
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -26,6 +26,10 @@
 #include <linux/sysdev.h>
 #include <linux/bcd.h>
 #include <linux/kallsyms.h>
+#include <linux/acpi.h>
+#ifdef CONFIG_ACPI
+#include <acpi/achware.h>	/* for PM timer frequency */
+#endif
 #include <asm/8253pit.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
@@ -46,7 +50,7 @@ EXPORT_SYMBOL(jiffies_64);
 #ifdef CONFIG_CPU_FREQ
 static void cpufreq_delayed_get(void);
 #endif
-
+extern void i8254_timer_resume(void);
 extern int using_apic_timer;
 
 DEFINE_SPINLOCK(rtc_lock);
@@ -58,7 +62,7 @@ static int notsc __initdata = 0;
 #undef HPET_HACK_ENABLE_DANGEROUS
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
-unsigned long hpet_period;				/* fsecs / HPET clock */
+static unsigned long hpet_period;			/* fsecs / HPET clock */
 unsigned long hpet_tick;				/* HPET clocks / interrupt */
 unsigned long vxtime_hz = PIT_TICK_RATE;
 int report_lost_ticks;				/* command line option */
@@ -396,6 +400,10 @@ static irqreturn_t timer_interrupt(int i
 			(offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick;
 
 		vxtime.last = offset;
+#ifdef CONFIG_X86_PM_TIMER
+	} else if (vxtime.mode == VXTIME_PMTMR) {
+		lost = pmtimer_mark_offset();
+#endif
 	} else {
 		offset = (((tsc - vxtime.last_tsc) *
 			   vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ);
@@ -551,11 +559,10 @@ unsigned long get_cmos_time(void)
 	    BCD_TO_BIN(year);
 
 /*
- * This will work up to Dec 31, 2069.
+ * x86-64 systems only exists since 2002.
+ * This will work up to Dec 31, 2100
  */
-
-	if ((year += 1900) < 1970)
-		year += 100;
+	year += 2000;
 
 	return mktime(year, mon, day, hour, min, sec);
 }
@@ -615,6 +622,9 @@ static int time_cpufreq_notifier(struct 
         struct cpufreq_freqs *freq = data;
 	unsigned long *lpj, dummy;
 
+	if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC))
+		return 0;
+
 	lpj = &dummy;
 	if (!(freq->flags & CPUFREQ_CONST_LOOPS))
 #ifdef CONFIG_SMP
@@ -623,8 +633,6 @@ static int time_cpufreq_notifier(struct 
 	lpj = &boot_cpu_data.loops_per_jiffy;
 #endif
 
-
-
 	if (!ref_freq) {
 		ref_freq = freq->old;
 		loops_per_jiffy_ref = *lpj;
@@ -898,6 +906,13 @@ void __init time_init(void)
 			hpet_period;
 		cpu_khz = hpet_calibrate_tsc();
 		timename = "HPET";
+#ifdef CONFIG_X86_PM_TIMER
+	} else if (pmtmr_ioport) {
+		vxtime_hz = PM_TIMER_FREQUENCY;
+		timename = "PM";
+		pit_init();
+		cpu_khz = pit_calibrate_tsc();
+#endif
 	} else {
 		pit_init();
 		cpu_khz = pit_calibrate_tsc();
@@ -916,35 +931,57 @@ void __init time_init(void)
 	setup_irq(0, &irq0);
 
 	set_cyc2ns_scale(cpu_khz / 1000);
+
+#ifndef CONFIG_SMP
+	time_init_gtod();
+#endif
+}
+
+/*
+ * Make an educated guess if the TSC is trustworthy and synchronized
+ * over all CPUs.
+ */
+static __init int unsynchronized_tsc(void)
+{
+#ifdef CONFIG_SMP
+	if (oem_force_hpet_timer())
+		return 1;
+ 	/* Intel systems are normally all synchronized. Exceptions
+ 	   are handled in the OEM check above. */
+ 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ 		return 0;
+ 	/* All in a single socket - should be synchronized */
+ 	if (cpus_weight(cpu_core_map[0]) == num_online_cpus())
+ 		return 0;
+#endif
+ 	/* Assume multi socket systems are not synchronized */
+ 	return num_online_cpus() > 1;
 }
 
-void __init time_init_smp(void)
+/*
+ * Decide after all CPUs are booted what mode gettimeofday should use.
+ */
+void __init time_init_gtod(void)
 {
 	char *timetype;
 
-	/*
-	 * AMD systems with more than one CPU don't have fully synchronized
-	 * TSCs. Always use HPET gettimeofday for these, although it is slower.
-	 * Intel SMP systems usually have synchronized TSCs, so use always
-	 * the TSC.
-	 *
-	 * Exceptions:
-	 * IBM Summit2 checked by oem_force_hpet_timer().
- 	 * AMD dual core may also not need HPET. Check me.
-	 *
-	 * Can be turned off with "notsc".
-	 */
-	if (num_online_cpus() > 1 &&
-	    boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-		notsc = 1;
-	/* Some systems will want to disable TSC and use HPET. */
-	if (oem_force_hpet_timer())
+	if (unsynchronized_tsc())
 		notsc = 1;
 	if (vxtime.hpet_address && notsc) {
 		timetype = "HPET";
 		vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
 		vxtime.mode = VXTIME_HPET;
 		do_gettimeoffset = do_gettimeoffset_hpet;
+#ifdef CONFIG_X86_PM_TIMER
+	/* Using PM for gettimeofday is quite slow, but we have no other
+	   choice because the TSC is too unreliable on some systems. */
+	} else if (pmtmr_ioport && !vxtime.hpet_address && notsc) {
+		timetype = "PM";
+		do_gettimeoffset = do_gettimeoffset_pm;
+		vxtime.mode = VXTIME_PMTMR;
+		sysctl_vsyscall = 0;
+		printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n");
+#endif
 	} else {
 		timetype = vxtime.hpet_address ? "HPET/TSC" : "PIT/TSC";
 		vxtime.mode = VXTIME_TSC;
@@ -958,7 +995,7 @@ __setup("report_lost_ticks", time_setup)
 static long clock_cmos_diff;
 static unsigned long sleep_start;
 
-static int timer_suspend(struct sys_device *dev, u32 state)
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
 	/*
 	 * Estimate time zone so that set_time can update the clock
@@ -980,6 +1017,8 @@ static int timer_resume(struct sys_devic
 
 	if (vxtime.hpet_address)
 		hpet_reenable();
+	else
+		i8254_timer_resume();
 
 	sec = ctime + clock_cmos_diff;
 	write_seqlock_irqsave(&xtime_lock,flags);
diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
--- a/arch/x86_64/kernel/trampoline.S
+++ b/arch/x86_64/kernel/trampoline.S
@@ -37,7 +37,6 @@ 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
@@ -46,31 +45,20 @@ r_base = .
 	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
+	# flaush prefetch and jump to startup_32 in arch/x86_64/kernel/head.S
+	ljmpl	$__KERNEL32_CS, $(startup_32-__START_KERNEL_map)
 
+	# Careful these need to be in the same 64K segment as the above;
 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. 
-	
+	.short	__KERNEL32_CS + 7	# gdt limit
+	.long	cpu_gdt_table-__START_KERNEL_map
 
 .globl trampoline_end
 trampoline_end:	
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/nmi.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -119,95 +120,106 @@ int printk_address(unsigned long address
 } 
 #endif
 
-unsigned long *in_exception_stack(int cpu, unsigned long stack) 
-{ 
-	int k;
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+					unsigned *usedp, const char **idp)
+{
+	static const char ids[N_EXCEPTION_STACKS][8] = {
+		[DEBUG_STACK - 1] = "#DB",
+		[NMI_STACK - 1] = "NMI",
+		[DOUBLEFAULT_STACK - 1] = "#DF",
+		[STACKFAULT_STACK - 1] = "#SS",
+		[MCE_STACK - 1] = "#MC",
+	};
+	unsigned k;
+
 	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
-		struct tss_struct *tss = &per_cpu(init_tss, cpu);
-		unsigned long end = tss->ist[k] + EXCEPTION_STKSZ;
+		unsigned long end;
 
-		if (stack >= tss->ist[k]  && stack <= end)
+		end = per_cpu(init_tss, cpu).ist[k];
+		if (stack >= end)
+			continue;
+		if (stack >= end - EXCEPTION_STKSZ) {
+			if (*usedp & (1U << k))
+				break;
+			*usedp |= 1U << k;
+			*idp = ids[k];
 			return (unsigned long *)end;
+		}
 	}
 	return NULL;
-} 
+}
 
 /*
  * x86-64 can have upto three kernel stacks: 
  * process stack
  * interrupt stack
- * severe exception (double fault, nmi, stack fault) hardware stack
- * Check and process them in order.
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
  */
 
 void show_trace(unsigned long *stack)
 {
 	unsigned long addr;
-	unsigned long *irqstack, *irqstack_end, *estack_end;
-	const int cpu = safe_smp_processor_id();
+	const unsigned cpu = safe_smp_processor_id();
+	unsigned long *irqstack_end = (unsigned long *)cpu_pda[cpu].irqstackptr;
 	int i;
+	unsigned used = 0;
 
 	printk("\nCall Trace:");
-	i = 0; 
-	
-	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;
-				}
-			}
+
+#define HANDLE_STACK(cond) \
+	do while (cond) { \
+		addr = *stack++; \
+		if (kernel_text_address(addr)) { \
+			/* \
+			 * 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. \
+			 */ \
+			i += printk_address(addr); \
+			if (i > 50) { \
+				printk("\n       "); \
+				i = 0; \
+			} \
+			else \
+				i += printk(" "); \
+		} \
+	} while (0)
+
+	for(i = 0; ; ) {
+		const char *id;
+		unsigned long *estack_end;
+		estack_end = in_exception_stack(cpu, (unsigned long)stack,
+						&used, &id);
+
+		if (estack_end) {
+			i += printk(" <%s> ", id);
+			HANDLE_STACK (stack < estack_end);
+			i += printk(" <EOE> ");
+			stack = (unsigned long *) estack_end[-2];
+			continue;
 		}
-		i += 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 + 64);
-
-	if (stack >= irqstack && stack < irqstack_end) {
-		printk("<IRQ> ");  
-		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;
-				 } 
+		if (irqstack_end) {
+			unsigned long *irqstack;
+			irqstack = irqstack_end -
+				(IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+			if (stack >= irqstack && stack < irqstack_end) {
+				i += printk(" <IRQ> ");
+				HANDLE_STACK (stack < irqstack_end);
+				stack = (unsigned long *) (irqstack_end[-1]);
+				irqstack_end = NULL;
+				i += printk(" <EOI> ");
+				continue;
 			}
-		} 
-		stack = (unsigned long *) (irqstack_end[-1]);
-		printk(" <EOI> ");
-		i += 7;
-	} 
-
-	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;
-			} 
 		}
+		break;
 	}
+
+	HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0);
+#undef HANDLE_STACK
 	printk("\n");
 }
 
@@ -243,6 +255,7 @@ void show_stack(struct task_struct *tsk,
 		if (i && ((i % 4) == 0))
 			printk("\n       ");
 		printk("%016lx ", *stack++);
+		touch_nmi_watchdog();
 	}
 	show_trace((unsigned long *)rsp);
 }
@@ -319,10 +332,12 @@ void handle_BUG(struct pt_regs *regs)
 	printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line);
 } 
 
+#ifdef CONFIG_BUG
 void out_of_line_bug(void)
 { 
 	BUG(); 
 } 
+#endif
 
 static DEFINE_SPINLOCK(die_lock);
 static int die_owner = -1;
@@ -348,7 +363,6 @@ void oops_end(void)
 	die_owner = -1;
 	bust_spinlocks(0); 
 	spin_unlock(&die_lock); 
-	local_irq_enable();	/* make sure back scroll still works */
 	if (panic_on_oops)
 		panic("Oops"); 
 } 
@@ -487,24 +501,8 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", inv
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 DO_ERROR(18, SIGSEGV, "reserved", reserved)
-
-#define DO_ERROR_STACK(trapnr, signr, str, name) \
-asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \
-{ \
-	struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
-							== NOTIFY_STOP) \
-		return regs; \
-	if (regs->cs & 3) { \
-		memcpy(pr, regs, sizeof(struct pt_regs)); \
-		regs = pr; \
-	} \
-	do_trap(trapnr, signr, str, regs, error_code, NULL); \
-	return regs;		\
-}
-
-DO_ERROR_STACK(12, SIGBUS,  "stack segment", stack_segment)
-DO_ERROR_STACK( 8, SIGSEGV, "double fault", double_fault)
+DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
@@ -583,6 +581,8 @@ static void unknown_nmi_error(unsigned c
 	printk("Do you have a strange power saving mode enabled?\n");
 }
 
+/* Runs on IST stack. This code must keep interrupts off all the time.
+   Nested NMIs are prevented by the CPU. */
 asmlinkage void default_do_nmi(struct pt_regs *regs)
 {
 	unsigned char reason = 0;
@@ -617,15 +617,6 @@ asmlinkage void default_do_nmi(struct pt
 		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_int3(struct pt_regs * regs, long error_code)
@@ -637,20 +628,34 @@ asmlinkage void do_int3(struct pt_regs *
 	return;
 }
 
+/* Help handler running on IST stack to switch back to user stack
+   for scheduling or signal handling. The actual stack switch is done in
+   entry.S */
+asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+	struct pt_regs *regs = eregs;
+	/* Did already sync */
+	if (eregs == (struct pt_regs *)eregs->rsp)
+		;
+	/* Exception from user space */
+	else if (eregs->cs & 3)
+		regs = ((struct pt_regs *)current->thread.rsp0) - 1;
+	/* Exception from kernel and interrupts are enabled. Move to
+ 	   kernel process stack. */
+	else if (eregs->eflags & X86_EFLAGS_IF)
+		regs = (struct pt_regs *)(eregs->rsp -= sizeof(struct pt_regs));
+	if (eregs != regs)
+		*regs = *eregs;
+	return regs;
+}
+
 /* runs on IST stack. */
-asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
+asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code)
 {
-	struct pt_regs *pr;
 	unsigned long condition;
 	struct task_struct *tsk = current;
 	siginfo_t info;
 
-	pr = (struct pt_regs *)(current->thread.rsp0)-1;
-	if (regs->cs & 3) {
-		memcpy(pr, regs, sizeof(struct pt_regs));
-		regs = pr;
-	}	
-
 #ifdef CONFIG_CHECKING
        { 
 	       /* RED-PEN interaction with debugger - could destroy gs */
@@ -667,9 +672,9 @@ asmlinkage void *do_debug(struct pt_regs
 	asm("movq %%db6,%0" : "=r" (condition));
 
 	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-						SIGTRAP) == NOTIFY_STOP) {
-		return regs;
-	}
+						SIGTRAP) == NOTIFY_STOP)
+		return;
+
 	conditional_sti(regs);
 
 	/* Mask out spurious debug traps due to lazy DR7 setting */
@@ -682,9 +687,7 @@ asmlinkage void *do_debug(struct pt_regs
 	tsk->thread.debugreg6 = condition;
 
 	/* Mask out spurious TF errors due to lazy TF clearing */
-	if ((condition & DR_STEP) &&
-	    (notify_die(DIE_DEBUGSTEP, "debugstep", regs, condition,
-			1, SIGTRAP) != NOTIFY_STOP)) {
+	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
@@ -696,8 +699,14 @@ asmlinkage void *do_debug(struct pt_regs
 		 */
                 if ((regs->cs & 3) == 0)
                        goto clear_TF_reenable;
-		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
-			goto clear_TF;
+		/*
+		 * Was the TF flag set by a debugger? If so, clear it now,
+		 * so that register information is correct.
+		 */
+		if (tsk->ptrace & PT_DTRACE) {
+			regs->eflags &= ~TF_MASK;
+			tsk->ptrace &= ~PT_DTRACE;
+		}
 	}
 
 	/* Ok, finally something we can handle */
@@ -713,18 +722,11 @@ asmlinkage void *do_debug(struct pt_regs
 	force_sig_info(SIGTRAP, &info, tsk);	
 clear_dr7:
 	asm volatile("movq %0,%%db7"::"r"(0UL));
-	notify_die(DIE_DEBUG, "debug", regs, condition, 1, SIGTRAP);
-	return regs;
+	return;
 
 clear_TF_reenable:
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-
-clear_TF:
-	/* RED-PEN could cause spurious errors */
-	if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) 
-								!= NOTIFY_STOP)
 	regs->eflags &= ~TF_MASK;
-	return regs;	
 }
 
 static int kernel_math_error(struct pt_regs *regs, char *str)
@@ -736,14 +738,8 @@ static int kernel_math_error(struct pt_r
 		return 1;
 	}
 	notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE);
-#if 0
-	/* This should be a die, but warn only for now */
+	/* Illegal floating point operation in the kernel */
 	die(str, regs, 0);
-#else
-	printk(KERN_DEBUG "%s: %s at ", current->comm, str);
-	printk_address(regs->rip);
-	printk("\n");
-#endif
 	return 0;
 }
 
@@ -827,7 +823,7 @@ asmlinkage void do_simd_coprocessor_erro
 
 	conditional_sti(regs);
 	if ((regs->cs & 3) == 0 &&
-        	kernel_math_error(regs, "simd math error"))
+        	kernel_math_error(regs, "kernel simd math error"))
 		return;
 
 	/*
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -7,11 +7,12 @@
 
 OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
 OUTPUT_ARCH(i386:x86-64)
-ENTRY(_start)
+ENTRY(phys_startup_64)
 jiffies_64 = jiffies;
 SECTIONS
 {
   . = 0xffffffff80100000;
+  phys_startup_64 = startup_64 - LOAD_OFFSET;
   _text = .;			/* Text and read-only data */
   .text : {
 	*(.text)
diff --git a/arch/x86_64/kernel/vsyscall.S b/arch/x86_64/kernel/vsyscall.S
deleted file mode 100644
--- a/arch/x86_64/kernel/vsyscall.S
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Code for the vsyscall page.  This version uses the syscall instruction.
- */
-
-#include <asm/ia32_unistd.h>
-#include <asm/offset.h>
-
-	.text
-	.globl __kernel_vsyscall
-	.type __kernel_vsyscall,@function
-__kernel_vsyscall:
-.LSTART_vsyscall:
-	push	%ebp
-.Lpush_ebp:
-	movl	%ecx, %ebp
-	syscall
-	popl	%ebp
-.Lpop_ebp:
-	ret
-.LEND_vsyscall:
-	.size __kernel_vsyscall,.-.LSTART_vsyscall
-
-	.balign 32
-	.globl __kernel_sigreturn
-	.type __kernel_sigreturn,@function
-__kernel_sigreturn:
-.LSTART_sigreturn:
-	popl %eax
-	movl $__NR_ia32_sigreturn, %eax
-	syscall
-.LEND_sigreturn:
-	.size __kernel_sigreturn,.-.LSTART_sigreturn
-
-	.balign 32
-	.globl __kernel_rt_sigreturn
-	.type __kernel_rt_sigreturn,@function
-__kernel_rt_sigreturn:
-.LSTART_rt_sigreturn:
-	movl $__NR_ia32_rt_sigreturn, %eax
-	syscall
-.LEND_rt_sigreturn:
-	.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
-
-	.section .eh_frame,"a",@progbits
-.LSTARTFRAME:
-	.long .LENDCIE-.LSTARTCIE
-.LSTARTCIE:
-	.long 0			/* CIE ID */
-	.byte 1			/* Version number */
-	.string "zR"		/* NUL-terminated augmentation string */
-	.uleb128 1		/* Code alignment factor */
-	.sleb128 -4		/* Data alignment factor */
-	.byte 8			/* Return address register column */
-	.uleb128 1		/* Augmentation value length */
-	.byte 0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
-	.byte 0x0c		/* DW_CFA_def_cfa */
-	.uleb128 4
-	.uleb128 4
-	.byte 0x88		/* DW_CFA_offset, column 0x8 */
-	.uleb128 1
-	.align 4
-.LENDCIE:
-
-	.long .LENDFDE1-.LSTARTFDE1	/* Length FDE */
-.LSTARTFDE1:
-	.long .LSTARTFDE1-.LSTARTFRAME	/* CIE pointer */
-	.long .LSTART_vsyscall-.	/* PC-relative start address */
-	.long .LEND_vsyscall-.LSTART_vsyscall
-	.uleb128 0			/* Augmentation length */
-	/* What follows are the instructions for the table generation.
-	   We have to record all changes of the stack pointer.  */
-	.byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */
-	.byte 0x0e		/* DW_CFA_def_cfa_offset */
-	.uleb128 8
-	.byte 0x85, 0x02	/* DW_CFA_offset %ebp -8 */
-	.byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */
-	.byte 0xc5		/* DW_CFA_restore %ebp */
-	.byte 0x0e		/* DW_CFA_def_cfa_offset */
-	.uleb128 4
-	.align 4
-.LENDFDE1:
-
-	.long .LENDFDE2-.LSTARTFDE2	/* Length FDE */
-.LSTARTFDE2:
-	.long .LSTARTFDE2-.LSTARTFRAME	/* CIE pointer */
-	/* HACK: The dwarf2 unwind routines will subtract 1 from the
-	   return address to get an address in the middle of the
-	   presumed call instruction.  Since we didn't get here via
-	   a call, we need to include the nop before the real start
-	   to make up for it.  */
-	.long .LSTART_sigreturn-1-.	/* PC-relative start address */
-	.long .LEND_sigreturn-.LSTART_sigreturn+1
-	.uleb128 0			/* Augmentation length */
-	/* What follows are the instructions for the table generation.
-	   We record the locations of each register saved.  This is
-	   complicated by the fact that the "CFA" is always assumed to
-	   be the value of the stack pointer in the caller.  This means
-	   that we must define the CFA of this body of code to be the
-	   saved value of the stack pointer in the sigcontext.  Which
-	   also means that there is no fixed relation to the other 
-	   saved registers, which means that we must use DW_CFA_expression
-	   to compute their addresses.  It also means that when we 
-	   adjust the stack with the popl, we have to do it all over again.  */
-
-#define do_cfa_expr(offset)						\
-	.byte 0x0f;			/* DW_CFA_def_cfa_expression */	\
-	.uleb128 1f-0f;			/*   length */			\
-0:	.byte 0x74;			/*     DW_OP_breg4 */		\
-	.sleb128 offset;		/*      offset */		\
-	.byte 0x06;			/*     DW_OP_deref */		\
-1:
-
-#define do_expr(regno, offset)						\
-	.byte 0x10;			/* DW_CFA_expression */		\
-	.uleb128 regno;			/*   regno */			\
-	.uleb128 1f-0f;			/*   length */			\
-0:	.byte 0x74;			/*     DW_OP_breg4 */		\
-	.sleb128 offset;		/*       offset */		\
-1:
-
-	do_cfa_expr(IA32_SIGCONTEXT_esp+4)
-	do_expr(0, IA32_SIGCONTEXT_eax+4)
-	do_expr(1, IA32_SIGCONTEXT_ecx+4)
-	do_expr(2, IA32_SIGCONTEXT_edx+4)
-	do_expr(3, IA32_SIGCONTEXT_ebx+4)
-	do_expr(5, IA32_SIGCONTEXT_ebp+4)
-	do_expr(6, IA32_SIGCONTEXT_esi+4)
-	do_expr(7, IA32_SIGCONTEXT_edi+4)
-	do_expr(8, IA32_SIGCONTEXT_eip+4)
-
-	.byte 0x42	/* DW_CFA_advance_loc 2 -- nop; popl eax. */
-
-	do_cfa_expr(IA32_SIGCONTEXT_esp)
-	do_expr(0, IA32_SIGCONTEXT_eax)
-	do_expr(1, IA32_SIGCONTEXT_ecx)
-	do_expr(2, IA32_SIGCONTEXT_edx)
-	do_expr(3, IA32_SIGCONTEXT_ebx)
-	do_expr(5, IA32_SIGCONTEXT_ebp)
-	do_expr(6, IA32_SIGCONTEXT_esi)
-	do_expr(7, IA32_SIGCONTEXT_edi)
-	do_expr(8, IA32_SIGCONTEXT_eip)
-
-	.align 4
-.LENDFDE2:
-
-	.long .LENDFDE3-.LSTARTFDE3	/* Length FDE */
-.LSTARTFDE3:
-	.long .LSTARTFDE3-.LSTARTFRAME	/* CIE pointer */
-	/* HACK: See above wrt unwind library assumptions.  */
-	.long .LSTART_rt_sigreturn-1-.	/* PC-relative start address */
-	.long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
-	.uleb128 0			/* Augmentation */
-	/* What follows are the instructions for the table generation.
-	   We record the locations of each register saved.  This is
-	   slightly less complicated than the above, since we don't
-	   modify the stack pointer in the process.  */
-
-	do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp)
-	do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax)
-	do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx)
-	do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx)
-	do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx)
-	do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp)
-	do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi)
-	do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi)
-	do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip)
-
-	.align 4
-.LENDFDE3:
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -9,30 +9,14 @@
  *  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
+ *  at virtual address -10Mbyte+1024bytes etc... There are at max 4
  *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
- *  jumping out of line if necessary.
+ *  jumping out of line if necessary. We cannot add more with this
+ *  mechanism because older kernels won't return -ENOSYS.
+ *  If we want more than four we need a vDSO.
  *
- *  Note: the concept clashes with user mode linux. If you use UML just
- *  set the kernel.vsyscall sysctl to 0.
- */
-
-/*
- * 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.
+ *  Note: the concept clashes with user mode linux. If you use UML and
+ *  want per guest time just set the kernel.vsyscall64 sysctl to 0.
  */
 
 #include <linux/time.h>
@@ -41,6 +25,7 @@
 #include <linux/timer.h>
 #include <linux/seqlock.h>
 #include <linux/jiffies.h>
+#include <linux/sysctl.h>
 
 #include <asm/vsyscall.h>
 #include <asm/pgtable.h>
@@ -62,8 +47,7 @@ static force_inline void timeval_normali
 	time_t __sec;
 
 	__sec = tv->tv_usec / 1000000;
-	if (__sec)
-	{
+	if (__sec) {
 		tv->tv_usec %= 1000000;
 		tv->tv_sec += __sec;
 	}
@@ -81,13 +65,14 @@ static force_inline void do_vgettimeofda
 		usec = (__xtime.tv_nsec / 1000) +
 			(__jiffies - __wall_jiffies) * (1000000 / HZ);
 
-		if (__vxtime.mode == VXTIME_TSC) {
+		if (__vxtime.mode != VXTIME_HPET) {
 			sync_core();
 			rdtscll(t);
-			if (t < __vxtime.last_tsc) t = __vxtime.last_tsc;
+			if (t < __vxtime.last_tsc)
+				t = __vxtime.last_tsc;
 			usec += ((t - __vxtime.last_tsc) *
 				 __vxtime.tsc_quot) >> 32;
-			/* See comment in x86_64 do_gettimeofday. */ 
+			/* See comment in x86_64 do_gettimeofday. */
 		} else {
 			usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
 				  __vxtime.last) * __vxtime.quot) >> 32;
@@ -101,14 +86,13 @@ static force_inline void do_vgettimeofda
 /* RED-PEN may want to readd seq locking, but then the variable should be write-once. */
 static force_inline void do_get_tz(struct timezone * tz)
 {
-		*tz = __sys_tz;
+	*tz = __sys_tz;
 }
 
-
 static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
 	int ret;
-	asm volatile("syscall" 
+	asm volatile("vsysc2: syscall"
 		: "=a" (ret)
 		: "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber );
 	return ret;
@@ -117,7 +101,7 @@ static force_inline int gettimeofday(str
 static force_inline long time_syscall(long *t)
 {
 	long secs;
-	asm volatile("syscall" 
+	asm volatile("vsysc1: syscall"
 		: "=a" (secs)
 		: "0" (__NR_time),"D" (t) : __syscall_clobber);
 	return secs;
@@ -126,7 +110,7 @@ static force_inline long time_syscall(lo
 static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
 	if (unlikely(!__sysctl_vsyscall))
-	return gettimeofday(tv,tz); 
+		return gettimeofday(tv,tz);
 	if (tv)
 		do_vgettimeofday(tv);
 	if (tz)
@@ -153,9 +137,71 @@ static long __vsyscall(2) venosys_0(void
 static long __vsyscall(3) venosys_1(void)
 {
 	return -ENOSYS;
+}
+
+#ifdef CONFIG_SYSCTL
+
+#define SYSCALL 0x050f
+#define NOP2    0x9090
+
+/*
+ * NOP out syscall in vsyscall page when not needed.
+ */
+static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	extern u16 vsysc1, vsysc2;
+	u16 *map1, *map2;
+	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+	if (!write)
+		return ret;
+	/* gcc has some trouble with __va(__pa()), so just do it this
+	   way. */
+	map1 = ioremap(__pa_symbol(&vsysc1), 2);
+	if (!map1)
+		return -ENOMEM;
+	map2 = ioremap(__pa_symbol(&vsysc2), 2);
+	if (!map2) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	if (!sysctl_vsyscall) {
+		*map1 = SYSCALL;
+		*map2 = SYSCALL;
+	} else {
+		*map1 = NOP2;
+		*map2 = NOP2;
+	}
+	iounmap(map2);
+out:
+	iounmap(map1);
+	return ret;
+}
 
+static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
+				void __user *oldval, size_t __user *oldlenp,
+				void __user *newval, size_t newlen,
+				void **context)
+{
+	return -ENOSYS;
 }
 
+static ctl_table kernel_table2[] = {
+	{ .ctl_name = 99, .procname = "vsyscall64",
+	  .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644,
+	  .strategy = vsyscall_sysctl_nostrat,
+	  .proc_handler = vsyscall_sysctl_change },
+	{ 0, }
+};
+
+static ctl_table kernel_root_table2[] = {
+	{ .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555,
+	  .child = kernel_table2 },
+	{ 0 },
+};
+
+#endif
+
 static void __init map_vsyscall(void)
 {
 	extern char __vsyscall_0;
@@ -166,13 +212,14 @@ static void __init map_vsyscall(void)
 
 static int __init vsyscall_init(void)
 {
-        BUG_ON(((unsigned long) &vgettimeofday != 
-		      VSYSCALL_ADDR(__NR_vgettimeofday)));
+	BUG_ON(((unsigned long) &vgettimeofday !=
+			VSYSCALL_ADDR(__NR_vgettimeofday)));
 	BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
 	BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
 	map_vsyscall();
-	sysctl_vsyscall = 1; 
-
+#ifdef CONFIG_SYSCTL
+	register_sysctl_table(kernel_root_table2, 0);
+#endif
 	return 0;
 }
 
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -103,7 +103,6 @@ EXPORT_SYMBOL(pci_free_consistent);
 #endif
 
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(pcibios_penalize_isa_irq);
 EXPORT_SYMBOL(pci_mem_start);
 #endif
 
@@ -140,35 +139,23 @@ EXPORT_SYMBOL_GPL(unset_nmi_callback);
 #undef memmove
 #undef memchr
 #undef strlen
-#undef strcpy
 #undef strncmp
 #undef strncpy
 #undef strchr	
-#undef strcmp 
-#undef strcpy 
-#undef strcat
-#undef memcmp
 
 extern void * memset(void *,int,__kernel_size_t);
 extern size_t strlen(const char *);
 extern void * memmove(void * dest,const void *src,size_t count);
-extern char * strcpy(char * dest,const char *src);
-extern int strcmp(const char * cs,const char * ct);
 extern void *memchr(const void *s, int c, size_t n);
 extern void * memcpy(void *,const void *,__kernel_size_t);
 extern void * __memcpy(void *,const void *,__kernel_size_t);
-extern char * strcat(char *, const char *);
-extern int memcmp(const void * cs,const void * ct,size_t count);
 
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(strrchr);
@@ -176,7 +163,6 @@ EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
-EXPORT_SYMBOL(memcmp);
 
 #ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
 /* prototypes are wrong, these are assembly with custom calling functions */
@@ -207,8 +193,9 @@ EXPORT_SYMBOL(smp_num_siblings);
 extern void do_softirq_thunk(void);
 EXPORT_SYMBOL(do_softirq_thunk);
 
-void out_of_line_bug(void);
+#ifdef CONFIG_BUG
 EXPORT_SYMBOL(out_of_line_bug);
+#endif
 
 EXPORT_SYMBOL(init_level4_pgt);
 
@@ -217,7 +204,6 @@ EXPORT_SYMBOL(__supported_pte_mask);
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(flush_tlb_page);
-EXPORT_SYMBOL_GPL(flush_tlb_all);
 #endif
 
 EXPORT_SYMBOL(cpu_khz);
diff --git a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops.c
--- a/arch/x86_64/lib/bitops.c
+++ b/arch/x86_64/lib/bitops.c
@@ -1,4 +1,3 @@
-#include <linux/module.h>
 #include <linux/bitops.h>
 
 #undef find_first_zero_bit
@@ -134,6 +133,8 @@ long find_next_bit(const unsigned long *
 	return (offset + set + res);
 }
 
+#include <linux/module.h>
+
 EXPORT_SYMBOL(find_next_bit);
 EXPORT_SYMBOL(find_first_bit);
 EXPORT_SYMBOL(find_first_zero_bit);
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -21,7 +21,7 @@ int x86_udelay_tsc = 0;		/* Delay via TS
 
 void __delay(unsigned long loops)
 {
-	unsigned long bclock, now;
+	unsigned bclock, now;
 	
 	rdtscl(bclock);
 	do
diff --git a/arch/x86_64/lib/getuser.S b/arch/x86_64/lib/getuser.S
--- a/arch/x86_64/lib/getuser.S
+++ b/arch/x86_64/lib/getuser.S
@@ -2,6 +2,7 @@
  * __get_user functions.
  *
  * (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
  *
  * These functions have a non-standard call interface
  * to make them more efficient, especially as they
@@ -12,12 +13,14 @@
 /*
  * __get_user_X
  *
- * Inputs:	%rax contains the address
+ * Inputs:	%rcx contains the address.
+ *		The register is modified, but all changes are undone
+ *		before returning because the C code doesn't know about it.
  *
  * Outputs:	%rax is error code (0 or -EFAULT)
  *		%rdx contains zero-extended value
  * 
- * %rbx is destroyed.
+ * %r8 is destroyed.
  *
  * These functions should not modify any other registers,
  * as they get called from within inline assembly.
@@ -33,52 +36,60 @@
 	.p2align 4
 .globl __get_user_1
 __get_user_1:	
-	GET_THREAD_INFO(%rbx)
-	cmpq threadinfo_addr_limit(%rbx),%rax
+	GET_THREAD_INFO(%r8)
+	cmpq threadinfo_addr_limit(%r8),%rcx
 	jae bad_get_user
-1:	movzb (%rax),%edx
-	xorq %rax,%rax
+1:	movzb (%rcx),%edx
+	xorl %eax,%eax
 	ret
 
 	.p2align 4
 .globl __get_user_2
 __get_user_2:
-	GET_THREAD_INFO(%rbx) 
-	addq $1,%rax
-	jc bad_get_user
-	cmpq threadinfo_addr_limit(%rbx),%rax 
-	jae	 bad_get_user
-2:	movzwl -1(%rax),%edx
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $1,%rcx
+	jc 20f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae 20f
+	decq   %rcx
+2:	movzwl (%rcx),%edx
+	xorl %eax,%eax
 	ret
+20:	decq    %rcx
+	jmp	bad_get_user
 
 	.p2align 4
 .globl __get_user_4
 __get_user_4:
-	GET_THREAD_INFO(%rbx) 
-	addq $3,%rax
-	jc bad_get_user
-	cmpq threadinfo_addr_limit(%rbx),%rax 
-	jae bad_get_user
-3:	movl -3(%rax),%edx
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $3,%rcx
+	jc 30f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae 30f
+	subq $3,%rcx
+3:	movl (%rcx),%edx
+	xorl %eax,%eax
 	ret
+30:	subq $3,%rcx
+	jmp bad_get_user
 
 	.p2align 4
 .globl __get_user_8
 __get_user_8:
-	GET_THREAD_INFO(%rbx) 
-	addq $7,%rax
-	jc bad_get_user
-	cmpq threadinfo_addr_limit(%rbx),%rax
-	jae	bad_get_user
-4:	movq -7(%rax),%rdx
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $7,%rcx
+	jc 40f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae	40f
+	subq	$7,%rcx
+4:	movq (%rcx),%rdx
+	xorl %eax,%eax
 	ret
+40:	subq $7,%rcx
+	jmp bad_get_user
 
-ENTRY(bad_get_user)
 bad_get_user:
-	xorq %rdx,%rdx
+	xorl %edx,%edx
 	movq $(-EFAULT),%rax
 	ret
 
diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser.S
--- a/arch/x86_64/lib/putuser.S
+++ b/arch/x86_64/lib/putuser.S
@@ -2,80 +2,90 @@
  * __put_user functions.
  *
  * (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
  *
  * These functions have a non-standard call interface
- * to make them more efficient.
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
  */
 
 /*
  * __put_user_X
  *
- * Inputs:	%rax contains the address
- *		%rdx contains the value
+ * Inputs:	%rcx contains the address
+ *		%rdx contains new value
  *
  * Outputs:	%rax is error code (0 or -EFAULT)
- *		%rbx is corrupted (will contain "current_task").
+ *
+ * %r8 is destroyed.
  *
  * 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/offset.h>
 #include <asm/thread_info.h>
 
-.text
-.p2align
+	.text
+	.p2align 4
 .globl __put_user_1
 __put_user_1:
-	GET_THREAD_INFO(%rbx)
-	cmpq threadinfo_addr_limit(%rbx),%rax
+	GET_THREAD_INFO(%r8)
+	cmpq threadinfo_addr_limit(%r8),%rcx
 	jae bad_put_user
-1:	movb %dl,(%rax)
-	xorq %rax,%rax
+1:	movb %dl,(%rcx)
+	xorl %eax,%eax
 	ret
 
-.p2align
+	.p2align 4
 .globl __put_user_2
 __put_user_2:
-	GET_THREAD_INFO(%rbx) 
-	addq $1,%rax
-	jc		bad_put_user
-	cmpq	threadinfo_addr_limit(%rbx),%rax
-	jae 	bad_put_user
-2:	movw %dx,-1(%rax)
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $1,%rcx
+	jc 20f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae 20f
+	decq %rcx
+2:	movw %dx,(%rcx)
+	xorl %eax,%eax
 	ret
+20:	decq %rcx
+	jmp bad_put_user
 
-.p2align
+	.p2align 4
 .globl __put_user_4
 __put_user_4:
-	GET_THREAD_INFO(%rbx) 
-	addq $3,%rax
-	jc		bad_put_user
-	cmpq	threadinfo_addr_limit(%rbx),%rax
-	jae 	bad_put_user
-3:	movl %edx,-3(%rax)
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $3,%rcx
+	jc 30f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae 30f
+	subq $3,%rcx
+3:	movl %edx,(%rcx)
+	xorl %eax,%eax
 	ret
+30:	subq $3,%rcx
+	jmp bad_put_user
 
-.p2align
+	.p2align 4
 .globl __put_user_8
 __put_user_8:
-	GET_THREAD_INFO(%rbx) 
-	addq $7,%rax
-	jc	bad_put_user
-	cmpq	threadinfo_addr_limit(%rbx),%rax
-	jae 	bad_put_user
-4:	movq %rdx,-7(%rax)
-	xorq %rax,%rax
+	GET_THREAD_INFO(%r8)
+	addq $7,%rcx
+	jc 40f
+	cmpq threadinfo_addr_limit(%r8),%rcx
+	jae 40f
+	subq $7,%rcx
+4:	movq %rdx,(%rcx)
+	xorl %eax,%eax
 	ret
+40:	subq $7,%rcx
+	jmp bad_put_user
 
-ENTRY(bad_put_user)	
 bad_put_user:
 	movq $(-EFAULT),%rax
 	ret
@@ -84,5 +94,5 @@ bad_put_user:
 	.quad 1b,bad_put_user
 	.quad 2b,bad_put_user
 	.quad 3b,bad_put_user
-	.quad 4b,bad_put_user	
+	.quad 4b,bad_put_user
 .previous
diff --git a/arch/x86_64/mm/extable.c b/arch/x86_64/mm/extable.c
--- a/arch/x86_64/mm/extable.c
+++ b/arch/x86_64/mm/extable.c
@@ -33,26 +33,3 @@ search_extable(const struct exception_ta
         }
         return NULL;
 }
-
-/* When an exception handler is in an non standard section (like __init)
-   the fixup table can end up unordered. Fix that here. */
-void sort_extable(struct exception_table_entry *start,
-		  struct exception_table_entry *finish)
-{
-	struct exception_table_entry *e;
-	int change;
-
-	/* The input is near completely presorted, which makes bubble sort the
-	   best (and simplest) sort algorithm. */
-	do {
-		change = 0;
-		for (e = start+1; e < finish; e++) {
-			if (e->insn < e[-1].insn) {
-				struct exception_table_entry tmp = e[-1];
-				e[-1] = e[0];
-				e[0] = tmp;
-				change = 1;
-			}
-		}
-	} while (change != 0);
-}
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -62,21 +62,19 @@ void bust_spinlocks(int yes)
 static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr,
 				unsigned long error_code)
 { 
-	unsigned char *instr = (unsigned char *)(regs->rip);
+	unsigned char *instr;
 	int scan_more = 1;
 	int prefetch = 0; 
-	unsigned char *max_instr = instr + 15;
+	unsigned char *max_instr;
 
 	/* If it was a exec fault ignore */
 	if (error_code & (1<<4))
 		return 0;
 	
-	/* Code segments in LDT could have a non zero base. Don't check
-	   when that's possible */
-	if (regs->cs & (1<<2))
-		return 0;
+	instr = (unsigned char *)convert_rip_to_linear(current, regs);
+	max_instr = instr + 15;
 
-	if ((regs->cs & 3) != 0 && regs->rip >= TASK_SIZE)
+	if ((regs->cs & 3) != 0 && instr >= (unsigned char *)TASK_SIZE)
 		return 0;
 
 	while (scan_more && instr < max_instr) { 
@@ -236,6 +234,8 @@ static noinline void pgtable_bad(unsigne
 
 /*
  * Handle a fault on the vmalloc or module mapping area
+ *
+ * This assumes no large pages in there.
  */
 static int vmalloc_fault(unsigned long address)
 {
@@ -274,7 +274,10 @@ static int vmalloc_fault(unsigned long a
 	if (!pte_present(*pte_ref))
 		return -1;
 	pte = pte_offset_kernel(pmd, address);
-	if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref))
+	/* Don't use pte_page here, because the mappings can point
+	   outside mem_map, and the NUMA hash lookup cannot handle
+	   that. */
+	if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
 		BUG();
 	__flush_tlb_all();
 	return 0;
@@ -348,7 +351,9 @@ asmlinkage void do_page_fault(struct pt_
 	 * protection error (error_code & 1) == 0.
 	 */
 	if (unlikely(address >= TASK_SIZE)) {
-		if (!(error_code & 5)) {
+		if (!(error_code & 5) &&
+		      ((address >= VMALLOC_START && address < VMALLOC_END) ||
+		       (address >= MODULES_VADDR && address < MODULES_END))) {
 			if (vmalloc_fault(address) < 0)
 				goto bad_area_nosemaphore;
 			return;
@@ -458,17 +463,6 @@ bad_area:
 	up_read(&mm->mmap_sem);
 
 bad_area_nosemaphore:
-
-#ifdef CONFIG_IA32_EMULATION
-	/* 32bit vsyscall. map on demand. */
-	if (test_thread_flag(TIF_IA32) &&
-	    address >= VSYSCALL32_BASE && address < VSYSCALL32_END) {
-		if (map_syscall32(mm, address) < 0)
-			goto out_of_memory2;
-		return;
-	}
-#endif
-
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
 		if (is_prefetch(regs, address, error_code))
@@ -550,7 +544,6 @@ no_context:
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
-out_of_memory2:
 	if (current->pid == 1) { 
 		yield();
 		goto again;
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -583,9 +583,9 @@ static __init int x8664_sysctl_init(void
 __initcall(x8664_sysctl_init);
 #endif
 
-/* Pseudo VMAs to allow ptrace access for the vsyscall pages.  x86-64 has two
-   different ones: one for 32bit and one for 64bit. Use the appropiate
-   for the target task. */
+/* A pseudo VMAs to allow ptrace access for the vsyscall page.   This only
+   covers the 64bit vsyscall page now. 32bit has a real VMA now and does
+   not need special handling anymore. */
 
 static struct vm_area_struct gate_vma = {
 	.vm_start = VSYSCALL_START,
@@ -593,22 +593,11 @@ static struct vm_area_struct gate_vma = 
 	.vm_page_prot = PAGE_READONLY
 };
 
-static struct vm_area_struct gate32_vma = {
-	.vm_start = VSYSCALL32_BASE,
-	.vm_end = VSYSCALL32_END,
-	.vm_page_prot = PAGE_READONLY
-};
-
 struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
 {
 #ifdef CONFIG_IA32_EMULATION
-	if (test_tsk_thread_flag(tsk, TIF_IA32)) {
-		/* lookup code assumes the pages are present. set them up
-		   now */
-		if (__map_syscall32(tsk->mm, VSYSCALL32_BASE) < 0)
-			return NULL;
-		return &gate32_vma;
-	}
+	if (test_tsk_thread_flag(tsk, TIF_IA32))
+		return NULL;
 #endif
 	return &gate_vma;
 }
@@ -616,6 +605,8 @@ struct vm_area_struct *get_gate_vma(stru
 int in_gate_area(struct task_struct *task, unsigned long addr)
 {
 	struct vm_area_struct *vma = get_gate_vma(task);
+	if (!vma)
+		return 0;
 	return (addr >= vma->vm_start) && (addr < vma->vm_end);
 }
 
@@ -625,6 +616,5 @@ int in_gate_area(struct task_struct *tas
  */
 int in_gate_area_no_task(unsigned long addr)
 {
-	return (((addr >= VSYSCALL_START) && (addr < VSYSCALL_END)) ||
-		((addr >= VSYSCALL32_BASE) && (addr < VSYSCALL32_END)));
+	return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -18,6 +18,9 @@
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
 
+#define ISA_START_ADDRESS      0xa0000
+#define ISA_END_ADDRESS                0x100000
+
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
 {
@@ -130,7 +133,7 @@ ioremap_change_attr(unsigned long phys_a
 					unsigned long flags)
 {
 	int err = 0;
-	if (flags && phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) {
+	if (phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) {
 		unsigned long npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 		unsigned long vaddr = (unsigned long) __va(phys_addr);
 
@@ -172,7 +175,7 @@ void __iomem * __ioremap(unsigned long p
 	/*
 	 * Don't remap the low PCI/ISA area, it's always mapped..
 	 */
-	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+	if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
 		return (__force void __iomem *)phys_to_virt(phys_addr);
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -211,7 +214,7 @@ void __iomem * __ioremap(unsigned long p
 		remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
 		return NULL;
 	}
-	if (ioremap_change_attr(phys_addr, size, flags) < 0) {
+	if (flags && ioremap_change_attr(phys_addr, size, flags) < 0) {
 		area->flags &= 0xffffff;
 		vunmap(addr);
 		return NULL;
@@ -248,30 +251,20 @@ void __iomem *ioremap_nocache (unsigned 
 
 void iounmap(volatile void __iomem *addr)
 {
-	struct vm_struct *p, **pprev;
+	struct vm_struct *p;
 
 	if (addr <= high_memory) 
 		return; 
+	if (addr >= phys_to_virt(ISA_START_ADDRESS) &&
+		addr < phys_to_virt(ISA_END_ADDRESS))
+		return;
 
 	write_lock(&vmlist_lock);
-	for (p = vmlist, pprev = &vmlist; p != NULL; pprev = &p->next, p = *pprev)
-		if (p->addr == (void *)(PAGE_MASK & (unsigned long)addr))
-			break;
-	if (!p) { 
-		printk("__iounmap: bad address %p\n", addr);
-		goto out_unlock;
-	}
-	*pprev = p->next;
-	unmap_vm_area(p);
-	if ((p->flags >> 20) &&
-		p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) {
-		/* p->size includes the guard page, but cpa doesn't like that */
-		change_page_attr(virt_to_page(__va(p->phys_addr)),
-				 (p->size - PAGE_SIZE) >> PAGE_SHIFT,
-				 PAGE_KERNEL); 				 
-		global_flush_tlb();
-	} 
-out_unlock:
+	p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK));
+	if (!p)
+		printk("iounmap: bad address %p\n", addr);
+	else if (p->flags >> 20)
+		ioremap_change_attr(p->phys_addr, p->size, 0);
 	write_unlock(&vmlist_lock);
 	kfree(p); 
 }
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -29,7 +29,7 @@ __init static int
 fill_mp_bus_to_cpumask(void)
 {
 	struct pci_dev *nb_dev = NULL;
-	int i, j;
+	int i, j, printed;
 	u32 ldtbus, nid;
 	static int lbnr[3] = {
 		LDT_BUS_NUMBER_REGISTER_0,
@@ -60,11 +60,15 @@ fill_mp_bus_to_cpumask(void)
 	}
 
 	/* quick sanity check */
+	printed = 0;
 	for (i = 0; i < 256; i++) {
 		if (cpus_empty(pci_bus_to_cpumask[i])) {
-			printk(KERN_ERR
-			       "k8-bus.c: bus %i has empty cpu mask\n", i);
 			pci_bus_to_cpumask[i] = CPU_MASK_ALL;
+			if (printed)
+				continue;
+			printk(KERN_ERR
+			       "k8-bus.c: some busses have empty cpu mask\n");
+			printed = 1;
 		}
 	}
 
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -17,12 +17,13 @@ u32 pci_mmcfg_base_addr;
 /* Static virtual mapping of the MMCONFIG aperture */
 char *pci_mmcfg_virt;
 
-static inline char *pci_dev_base(int bus, int devfn)
+static inline char *pci_dev_base(unsigned int bus, unsigned int devfn)
 {
 	return pci_mmcfg_virt + ((bus << 20) | (devfn << 12));
 }
 
-static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 *value)
 {
 	char *addr = pci_dev_base(bus, devfn); 
 
@@ -44,7 +45,8 @@ static int pci_mmcfg_read(int seg, int b
 	return 0;
 }
 
-static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
+static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+			   unsigned int devfn, int reg, int len, u32 value)
 {
 	char *addr = pci_dev_base(bus,devfn);
 
diff --git a/crypto/Kconfig b/crypto/Kconfig
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -79,6 +79,19 @@ config CRYPTO_WP512
 	  See also:
 	  <http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html>
 
+config CRYPTO_TGR192
+	tristate "Tiger digest algorithms"
+	depends on CRYPTO
+	help
+	  Tiger hash algorithm 192, 160 and 128-bit hashes
+
+	  Tiger is a hash function optimized for 64-bit processors while
+	  still having decent performance on 32-bit processors.
+	  Tiger was developed by Ross Anderson and Eli Biham.
+
+	  See also:
+	  <http://www.cs.technion.ac.il/~biham/Reports/Tiger/>.
+
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	depends on CRYPTO
@@ -133,7 +146,7 @@ config CRYPTO_SERPENT
 
 config CRYPTO_AES
 	tristate "AES cipher algorithms"
-	depends on CRYPTO && !(X86 && !X86_64)
+	depends on CRYPTO && !((X86 || UML_X86) && !64BIT)
 	help
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  algorithm.
@@ -153,7 +166,7 @@ config CRYPTO_AES
 
 config CRYPTO_AES_586
 	tristate "AES cipher algorithms (i586)"
-	depends on CRYPTO && (X86 && !X86_64)
+	depends on CRYPTO && ((X86 || UML_X86) && !64BIT)
 	help
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  algorithm.
diff --git a/crypto/Makefile b/crypto/Makefile
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_CRYPTO_SHA1) += sha1.o
 obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
 obj-$(CONFIG_CRYPTO_SHA512) += sha512.o
 obj-$(CONFIG_CRYPTO_WP512) += wp512.o
+obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
diff --git a/crypto/aes.c b/crypto/aes.c
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -64,23 +64,6 @@
 
 #define AES_BLOCK_SIZE		16
 
-static inline 
-u32 generic_rotr32 (const u32 x, const unsigned bits)
-{
-	const unsigned n = bits % 32;
-	return (x >> n) | (x << (32 - n));
-}
-
-static inline 
-u32 generic_rotl32 (const u32 x, const unsigned bits)
-{
-	const unsigned n = bits % 32;
-	return (x << n) | (x >> (32 - n));
-}
-
-#define rotl generic_rotl32
-#define rotr generic_rotr32
-
 /*
  * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) 
  */
@@ -191,26 +174,26 @@ gen_tabs (void)
 
 		t = p;
 		fl_tab[0][i] = t;
-		fl_tab[1][i] = rotl (t, 8);
-		fl_tab[2][i] = rotl (t, 16);
-		fl_tab[3][i] = rotl (t, 24);
+		fl_tab[1][i] = rol32(t, 8);
+		fl_tab[2][i] = rol32(t, 16);
+		fl_tab[3][i] = rol32(t, 24);
 
 		t = ((u32) ff_mult (2, p)) |
 		    ((u32) p << 8) |
 		    ((u32) p << 16) | ((u32) ff_mult (3, p) << 24);
 
 		ft_tab[0][i] = t;
-		ft_tab[1][i] = rotl (t, 8);
-		ft_tab[2][i] = rotl (t, 16);
-		ft_tab[3][i] = rotl (t, 24);
+		ft_tab[1][i] = rol32(t, 8);
+		ft_tab[2][i] = rol32(t, 16);
+		ft_tab[3][i] = rol32(t, 24);
 
 		p = isb_tab[i];
 
 		t = p;
 		il_tab[0][i] = t;
-		il_tab[1][i] = rotl (t, 8);
-		il_tab[2][i] = rotl (t, 16);
-		il_tab[3][i] = rotl (t, 24);
+		il_tab[1][i] = rol32(t, 8);
+		il_tab[2][i] = rol32(t, 16);
+		il_tab[3][i] = rol32(t, 24);
 
 		t = ((u32) ff_mult (14, p)) |
 		    ((u32) ff_mult (9, p) << 8) |
@@ -218,9 +201,9 @@ gen_tabs (void)
 		    ((u32) ff_mult (11, p) << 24);
 
 		it_tab[0][i] = t;
-		it_tab[1][i] = rotl (t, 8);
-		it_tab[2][i] = rotl (t, 16);
-		it_tab[3][i] = rotl (t, 24);
+		it_tab[1][i] = rol32(t, 8);
+		it_tab[2][i] = rol32(t, 16);
+		it_tab[3][i] = rol32(t, 24);
 	}
 }
 
@@ -232,14 +215,14 @@ gen_tabs (void)
     w   = star_x(v);        \
     t   = w ^ (x);          \
    (y)  = u ^ v ^ w;        \
-   (y) ^= rotr(u ^ t,  8) ^ \
-          rotr(v ^ t, 16) ^ \
-          rotr(t,24)
+   (y) ^= ror32(u ^ t,  8) ^ \
+          ror32(v ^ t, 16) ^ \
+          ror32(t,24)
 
 /* initialise the key schedule from the user supplied key */
 
 #define loop4(i)                                    \
-{   t = rotr(t,  8); t = ls_box(t) ^ rco_tab[i];    \
+{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
     t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;    \
     t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;    \
     t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;    \
@@ -247,7 +230,7 @@ gen_tabs (void)
 }
 
 #define loop6(i)                                    \
-{   t = rotr(t,  8); t = ls_box(t) ^ rco_tab[i];    \
+{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
     t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;    \
     t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;    \
     t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;    \
@@ -257,7 +240,7 @@ gen_tabs (void)
 }
 
 #define loop8(i)                                    \
-{   t = rotr(t,  8); ; t = ls_box(t) ^ rco_tab[i];  \
+{   t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i];  \
     t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;    \
     t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;    \
     t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;   \
diff --git a/crypto/blowfish.c b/crypto/blowfish.c
--- a/crypto/blowfish.c
+++ b/crypto/blowfish.c
@@ -349,8 +349,8 @@ static void encrypt_block(struct bf_ctx 
 
 static void bf_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	const u32 *in_blk = (const u32 *)src;
-	u32 *const out_blk = (u32 *)dst;
+	const __be32 *in_blk = (const __be32 *)src;
+	__be32 *const out_blk = (__be32 *)dst;
 	u32 in32[2], out32[2];
 
 	in32[0] = be32_to_cpu(in_blk[0]);
@@ -362,8 +362,8 @@ static void bf_encrypt(void *ctx, u8 *ds
 
 static void bf_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	const u32 *in_blk = (const u32 *)src;
-	u32 *const out_blk = (u32 *)dst;
+	const __be32 *in_blk = (const __be32 *)src;
+	__be32 *const out_blk = (__be32 *)dst;
 	const u32 *P = ((struct bf_ctx *)ctx)->p;
 	const u32 *S = ((struct bf_ctx *)ctx)->s;
 	u32 yl = be32_to_cpu(in_blk[0]);
diff --git a/crypto/cast5.c b/crypto/cast5.c
--- a/crypto/cast5.c
+++ b/crypto/cast5.c
@@ -567,14 +567,11 @@ static const u32 sb8[256] = {
 	0xeaee6801, 0x8db2a283, 0xea8bf59e
 };
 
-
-#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
-
-#define F1(D,m,r)  (  (I = ((m) + (D))), (I=rol((r),I)),   \
+#define F1(D,m,r)  (  (I = ((m) + (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
-#define F2(D,m,r)  (  (I = ((m) ^ (D))), (I=rol((r),I)),   \
+#define F2(D,m,r)  (  (I = ((m) ^ (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
-#define F3(D,m,r)  (  (I = ((m) - (D))), (I=rol((r),I)),   \
+#define F3(D,m,r)  (  (I = ((m) - (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
 
 
diff --git a/crypto/cast6.c b/crypto/cast6.c
--- a/crypto/cast6.c
+++ b/crypto/cast6.c
@@ -33,13 +33,11 @@ struct cast6_ctx {
 	u8 Kr[12][4];
 };
 
-#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
-
-#define F1(D,r,m)  (  (I = ((m) + (D))), (I=rol((r),I)),   \
+#define F1(D,r,m)  (  (I = ((m) + (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
-#define F2(D,r,m)  (  (I = ((m) ^ (D))), (I=rol((r),I)),   \
+#define F2(D,r,m)  (  (I = ((m) ^ (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
-#define F3(D,r,m)  (  (I = ((m) - (D))), (I=rol((r),I)),   \
+#define F3(D,r,m)  (  (I = ((m) - (D))), (I=rol32(I,(r))),   \
     (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
 
 static const u32 s1[256] = {
diff --git a/crypto/cipher.c b/crypto/cipher.c
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -11,18 +11,20 @@
  * any later version.
  *
  */
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/crypto.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <asm/scatterlist.h>
 #include "internal.h"
 #include "scatterwalk.h"
 
 typedef void (cryptfn_t)(void *, u8 *, const u8 *);
 typedef void (procfn_t)(struct crypto_tfm *, u8 *,
-                        u8*, cryptfn_t, int enc, void *, int);
+                        u8*, cryptfn_t, void *);
 
 static inline void xor_64(u8 *a, const u8 *b)
 {
@@ -37,7 +39,47 @@ static inline void xor_128(u8 *a, const 
 	((u32 *)a)[2] ^= ((u32 *)b)[2];
 	((u32 *)a)[3] ^= ((u32 *)b)[3];
 }
+ 
+static inline void *prepare_src(struct scatter_walk *walk, int bsize,
+				void *tmp, int in_place)
+{
+	void *src = walk->data;
+	int n = bsize;
+
+	if (unlikely(scatterwalk_across_pages(walk, bsize))) {
+		src = tmp;
+		n = scatterwalk_copychunks(src, walk, bsize, 0);
+	}
+	scatterwalk_advance(walk, n);
+	return src;
+}
+
+static inline void *prepare_dst(struct scatter_walk *walk, int bsize,
+				void *tmp, int in_place)
+{
+	void *dst = walk->data;
+
+	if (unlikely(scatterwalk_across_pages(walk, bsize)) || in_place)
+		dst = tmp;
+	return dst;
+}
 
+static inline void complete_src(struct scatter_walk *walk, int bsize,
+				void *src, int in_place)
+{
+}
+
+static inline void complete_dst(struct scatter_walk *walk, int bsize,
+				void *dst, int in_place)
+{
+	int n = bsize;
+
+	if (unlikely(scatterwalk_across_pages(walk, bsize)))
+		n = scatterwalk_copychunks(dst, walk, bsize, 1);
+	else if (in_place)
+		memcpy(walk->data, dst, bsize);
+	scatterwalk_advance(walk, n);
+}
 
 /* 
  * Generic encrypt/decrypt wrapper for ciphers, handles operations across
@@ -48,7 +90,7 @@ static int crypt(struct crypto_tfm *tfm,
 		 struct scatterlist *dst,
 		 struct scatterlist *src,
                  unsigned int nbytes, cryptfn_t crfn,
-                 procfn_t prfn, int enc, void *info)
+                 procfn_t prfn, void *info)
 {
 	struct scatter_walk walk_in, walk_out;
 	const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
@@ -72,20 +114,26 @@ static int crypt(struct crypto_tfm *tfm,
 
 		scatterwalk_map(&walk_in, 0);
 		scatterwalk_map(&walk_out, 1);
-		src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src);
-		dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst);
-		in_place = scatterwalk_samebuf(&walk_in, &walk_out,
-					       src_p, dst_p);
 
-		nbytes -= bsize;
+		in_place = scatterwalk_samebuf(&walk_in, &walk_out);
 
-		scatterwalk_copychunks(src_p, &walk_in, bsize, 0);
-
-		prfn(tfm, dst_p, src_p, crfn, enc, info, in_place);
+		do {
+			src_p = prepare_src(&walk_in, bsize, tmp_src,
+					    in_place);
+			dst_p = prepare_dst(&walk_out, bsize, tmp_dst,
+					    in_place);
+
+			prfn(tfm, dst_p, src_p, crfn, info);
+
+			complete_src(&walk_in, bsize, src_p, in_place);
+			complete_dst(&walk_out, bsize, dst_p, in_place);
+
+			nbytes -= bsize;
+		} while (nbytes &&
+			 !scatterwalk_across_pages(&walk_in, bsize) &&
+			 !scatterwalk_across_pages(&walk_out, bsize));
 
 		scatterwalk_done(&walk_in, 0, nbytes);
-
-		scatterwalk_copychunks(dst_p, &walk_out, bsize, 1);
 		scatterwalk_done(&walk_out, 1, nbytes);
 
 		if (!nbytes)
@@ -95,33 +143,28 @@ static int crypt(struct crypto_tfm *tfm,
 	}
 }
 
-static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
-			cryptfn_t fn, int enc, void *info, int in_place)
+static void cbc_process_encrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
+				cryptfn_t fn, void *info)
 {
 	u8 *iv = info;
-	
-	/* Null encryption */
-	if (!iv)
-		return;
-		
-	if (enc) {
-		tfm->crt_u.cipher.cit_xor_block(iv, src);
-		fn(crypto_tfm_ctx(tfm), dst, iv);
-		memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
-	} else {
-		u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0];
-		u8 *buf = in_place ? stack : dst;
-
-		fn(crypto_tfm_ctx(tfm), buf, src);
-		tfm->crt_u.cipher.cit_xor_block(buf, iv);
-		memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
-		if (buf != dst)
-			memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm));
-	}
+
+	tfm->crt_u.cipher.cit_xor_block(iv, src);
+	fn(crypto_tfm_ctx(tfm), dst, iv);
+	memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
+}
+
+static void cbc_process_decrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
+				cryptfn_t fn, void *info)
+{
+	u8 *iv = info;
+
+	fn(crypto_tfm_ctx(tfm), dst, src);
+	tfm->crt_u.cipher.cit_xor_block(dst, iv);
+	memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
 }
 
 static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
-			cryptfn_t fn, int enc, void *info, int in_place)
+			cryptfn_t fn, void *info)
 {
 	fn(crypto_tfm_ctx(tfm), dst, src);
 }
@@ -144,7 +187,7 @@ static int ecb_encrypt(struct crypto_tfm
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             ecb_process, 1, NULL);
+	             ecb_process, NULL);
 }
 
 static int ecb_decrypt(struct crypto_tfm *tfm,
@@ -154,7 +197,7 @@ static int ecb_decrypt(struct crypto_tfm
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             ecb_process, 1, NULL);
+	             ecb_process, NULL);
 }
 
 static int cbc_encrypt(struct crypto_tfm *tfm,
@@ -164,7 +207,7 @@ static int cbc_encrypt(struct crypto_tfm
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             cbc_process, 1, tfm->crt_cipher.cit_iv);
+	             cbc_process_encrypt, tfm->crt_cipher.cit_iv);
 }
 
 static int cbc_encrypt_iv(struct crypto_tfm *tfm,
@@ -174,7 +217,7 @@ static int cbc_encrypt_iv(struct crypto_
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             cbc_process, 1, iv);
+	             cbc_process_encrypt, iv);
 }
 
 static int cbc_decrypt(struct crypto_tfm *tfm,
@@ -184,7 +227,7 @@ static int cbc_decrypt(struct crypto_tfm
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             cbc_process, 0, tfm->crt_cipher.cit_iv);
+	             cbc_process_decrypt, tfm->crt_cipher.cit_iv);
 }
 
 static int cbc_decrypt_iv(struct crypto_tfm *tfm,
@@ -194,7 +237,7 @@ static int cbc_decrypt_iv(struct crypto_
 {
 	return crypt(tfm, dst, src, nbytes,
 	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             cbc_process, 0, iv);
+	             cbc_process_decrypt, iv);
 }
 
 static int nocrypt(struct crypto_tfm *tfm,
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <asm/scatterlist.h>
 #include <linux/crypto.h>
+#include <linux/string.h>
 
 #define NULL_KEY_SIZE		0
 #define NULL_BLOCK_SIZE		1
@@ -28,11 +29,13 @@
 
 static int null_compress(void *ctx, const u8 *src, unsigned int slen,
                          u8 *dst, unsigned int *dlen)
-{ return 0; }
-
-static int null_decompress(void *ctx, const u8 *src, unsigned int slen,
-                           u8 *dst, unsigned int *dlen)
-{ return 0; }
+{
+	if (slen > *dlen)
+		return -EINVAL;
+	memcpy(dst, src, slen);
+	*dlen = slen;
+	return 0;
+}
 
 static void null_init(void *ctx)
 { }
@@ -47,11 +50,10 @@ static int null_setkey(void *ctx, const 
                        unsigned int keylen, u32 *flags)
 { return 0; }
 
-static void null_encrypt(void *ctx, u8 *dst, const u8 *src)
-{ }
-
-static void null_decrypt(void *ctx, u8 *dst, const u8 *src)
-{ }
+static void null_crypt(void *ctx, u8 *dst, const u8 *src)
+{
+	memcpy(dst, src, NULL_BLOCK_SIZE);
+}
 
 static struct crypto_alg compress_null = {
 	.cra_name		=	"compress_null",
@@ -62,7 +64,7 @@ static struct crypto_alg compress_null =
 	.cra_list		=       LIST_HEAD_INIT(compress_null.cra_list),
 	.cra_u			=	{ .compress = {
 	.coa_compress 		=	null_compress,
-	.coa_decompress		=	null_decompress } }
+	.coa_decompress		=	null_compress } }
 };
 
 static struct crypto_alg digest_null = {
@@ -90,8 +92,8 @@ static struct crypto_alg cipher_null = {
 	.cia_min_keysize	=	NULL_KEY_SIZE,
 	.cia_max_keysize	=	NULL_KEY_SIZE,
 	.cia_setkey		= 	null_setkey,
-	.cia_encrypt		=	null_encrypt,
-	.cia_decrypt		=	null_decrypt } }
+	.cia_encrypt		=	null_crypt,
+	.cia_decrypt		=	null_crypt } }
 };
 
 MODULE_ALIAS("compress_null");
diff --git a/crypto/deflate.c b/crypto/deflate.c
--- a/crypto/deflate.c
+++ b/crypto/deflate.c
@@ -93,11 +93,13 @@ out_free:
 
 static void deflate_comp_exit(struct deflate_ctx *ctx)
 {
+	zlib_deflateEnd(&ctx->comp_stream);
 	vfree(ctx->comp_stream.workspace);
 }
 
 static void deflate_decomp_exit(struct deflate_ctx *ctx)
 {
+	zlib_inflateEnd(&ctx->decomp_stream);
 	kfree(ctx->decomp_stream.workspace);
 }
 
diff --git a/crypto/internal.h b/crypto/internal.h
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -38,7 +38,7 @@ static inline void crypto_kunmap(void *v
 
 static inline void crypto_yield(struct crypto_tfm *tfm)
 {
-	if (!in_softirq())
+	if (!in_atomic())
 		cond_resched();
 }
 
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -24,18 +24,6 @@ struct michael_mic_ctx {
 };
 
 
-static inline u32 rotl(u32 val, int bits)
-{
-	return (val << bits) | (val >> (32 - bits));
-}
-
-
-static inline u32 rotr(u32 val, int bits)
-{
-	return (val >> bits) | (val << (32 - bits));
-}
-
-
 static inline u32 xswap(u32 val)
 {
 	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
@@ -44,13 +32,13 @@ static inline u32 xswap(u32 val)
 
 #define michael_block(l, r)	\
 do {				\
-	r ^= rotl(l, 17);	\
+	r ^= rol32(l, 17);	\
 	l += r;			\
 	r ^= xswap(l);		\
 	l += r;			\
-	r ^= rotl(l, 3);	\
+	r ^= rol32(l, 3);	\
 	l += r;			\
-	r ^= rotr(l, 2);	\
+	r ^= ror32(l, 2);	\
 	l += r;			\
 } while (0)
 
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
+#include <asm/bug.h>
 #include <asm/scatterlist.h>
 #include "internal.h"
 #include "scatterwalk.h"
@@ -28,16 +29,6 @@ enum km_type crypto_km_types[] = {
 	KM_SOFTIRQ1,
 };
 
-void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch)
-{
-	if (nbytes <= walk->len_this_page &&
-	    (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <=
-	    PAGE_CACHE_SIZE)
-		return walk->data;
-	else
-		return scratch;
-}
-
 static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
 {
 	if (out)
@@ -55,6 +46,8 @@ void scatterwalk_start(struct scatter_wa
 	walk->page = sg->page;
 	walk->len_this_segment = sg->length;
 
+	BUG_ON(!sg->length);
+
 	rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
 	walk->len_this_page = min(sg->length, rest_of_page);
 	walk->offset = sg->offset;
@@ -65,13 +58,17 @@ void scatterwalk_map(struct scatter_walk
 	walk->data = crypto_kmap(walk->page, out) + walk->offset;
 }
 
-static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
-				 unsigned int more)
+static inline void scatterwalk_unmap(struct scatter_walk *walk, int out)
 {
 	/* walk->data may be pointing the first byte of the next page;
 	   however, we know we transfered at least one byte.  So,
 	   walk->data - 1 will be a virtual address in the mapped page. */
+	crypto_kunmap(walk->data - 1, out);
+}
 
+static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
+				 unsigned int more)
+{
 	if (out)
 		flush_dcache_page(walk->page);
 
@@ -91,7 +88,7 @@ static void scatterwalk_pagedone(struct 
 
 void scatterwalk_done(struct scatter_walk *walk, int out, int more)
 {
-	crypto_kunmap(walk->data, out);
+	scatterwalk_unmap(walk, out);
 	if (walk->len_this_page == 0 || !more)
 		scatterwalk_pagedone(walk, out, more);
 }
@@ -103,22 +100,16 @@ void scatterwalk_done(struct scatter_wal
 int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
 			   size_t nbytes, int out)
 {
-	if (buf != walk->data) {
-		while (nbytes > walk->len_this_page) {
-			memcpy_dir(buf, walk->data, walk->len_this_page, out);
-			buf += walk->len_this_page;
-			nbytes -= walk->len_this_page;
-
-			crypto_kunmap(walk->data, out);
-			scatterwalk_pagedone(walk, out, 1);
-			scatterwalk_map(walk, out);
-		}
-
-		memcpy_dir(buf, walk->data, nbytes, out);
-	}
+	do {
+		memcpy_dir(buf, walk->data, walk->len_this_page, out);
+		buf += walk->len_this_page;
+		nbytes -= walk->len_this_page;
+
+		scatterwalk_unmap(walk, out);
+		scatterwalk_pagedone(walk, out, 1);
+		scatterwalk_map(walk, out);
+	} while (nbytes > walk->len_this_page);
 
-	walk->offset += nbytes;
-	walk->len_this_page -= nbytes;
-	walk->len_this_segment -= nbytes;
-	return 0;
+	memcpy_dir(buf, walk->data, nbytes, out);
+	return nbytes;
 }
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
--- a/crypto/scatterwalk.h
+++ b/crypto/scatterwalk.h
@@ -34,15 +34,27 @@ static inline struct scatterlist *sg_nex
 }
 
 static inline int scatterwalk_samebuf(struct scatter_walk *walk_in,
-				      struct scatter_walk *walk_out,
-				      void *src_p, void *dst_p)
+				      struct scatter_walk *walk_out)
 {
 	return walk_in->page == walk_out->page &&
-	       walk_in->offset == walk_out->offset &&
-	       walk_in->data == src_p && walk_out->data == dst_p;
+	       walk_in->offset == walk_out->offset;
+}
+
+static inline int scatterwalk_across_pages(struct scatter_walk *walk,
+					   unsigned int nbytes)
+{
+	return nbytes > walk->len_this_page;
+}
+
+static inline void scatterwalk_advance(struct scatter_walk *walk,
+				       unsigned int nbytes)
+{
+	walk->data += nbytes;
+	walk->offset += nbytes;
+	walk->len_this_page -= nbytes;
+	walk->len_this_segment -= nbytes;
 }
 
-void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch);
 void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
 int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out);
 void scatterwalk_map(struct scatter_walk *walk, int out);
diff --git a/crypto/serpent.c b/crypto/serpent.c
--- a/crypto/serpent.c
+++ b/crypto/serpent.c
@@ -31,11 +31,9 @@
 #define SERPENT_BLOCK_SIZE		 16
 
 #define PHI 0x9e3779b9UL
-#define ROL(x,r) ((x) = ((x) << (r)) | ((x) >> (32-(r))))
-#define ROR(x,r) ((x) = ((x) >> (r)) | ((x) << (32-(r))))
 
 #define keyiter(a,b,c,d,i,j) \
-        b ^= d; b ^= c; b ^= a; b ^= PHI ^ i; ROL(b,11); k[j] = b;
+        b ^= d; b ^= c; b ^= a; b ^= PHI ^ i; b = rol32(b,11); k[j] = b;
 
 #define loadkeys(x0,x1,x2,x3,i) \
 	x0=k[i]; x1=k[i+1]; x2=k[i+2]; x3=k[i+3];
@@ -48,24 +46,24 @@
 	x1 ^= k[4*(i)+1];        x0 ^= k[4*(i)+0];
 
 #define LK(x0,x1,x2,x3,x4,i)				\
-					ROL(x0,13);	\
-	ROL(x2,3);	x1 ^= x0;	x4  = x0 << 3;	\
+					x0=rol32(x0,13);\
+	x2=rol32(x2,3);	x1 ^= x0;	x4  = x0 << 3;	\
 	x3 ^= x2;	x1 ^= x2;			\
-	ROL(x1,1);	x3 ^= x4;			\
-	ROL(x3,7);	x4  = x1;			\
+	x1=rol32(x1,1);	x3 ^= x4;			\
+	x3=rol32(x3,7);	x4  = x1;			\
 	x0 ^= x1;	x4 <<= 7;	x2 ^= x3;	\
 	x0 ^= x3;	x2 ^= x4;	x3 ^= k[4*i+3];	\
-	x1 ^= k[4*i+1];	ROL(x0,5);	ROL(x2,22);	\
+	x1 ^= k[4*i+1];	x0=rol32(x0,5);	x2=rol32(x2,22);\
 	x0 ^= k[4*i+0];	x2 ^= k[4*i+2];
 
 #define KL(x0,x1,x2,x3,x4,i)				\
 	x0 ^= k[4*i+0];	x1 ^= k[4*i+1];	x2 ^= k[4*i+2];	\
-	x3 ^= k[4*i+3];	ROR(x0,5);	ROR(x2,22);	\
+	x3 ^= k[4*i+3];	x0=ror32(x0,5);	x2=ror32(x2,22);\
 	x4 =  x1;	x2 ^= x3;	x0 ^= x3;	\
-	x4 <<= 7;	x0 ^= x1;	ROR(x1,1);	\
-	x2 ^= x4;	ROR(x3,7);	x4 = x0 << 3;	\
-	x1 ^= x0;	x3 ^= x4;	ROR(x0,13);	\
-	x1 ^= x2;	x3 ^= x2;	ROR(x2,3);
+	x4 <<= 7;	x0 ^= x1;	x1=ror32(x1,1);	\
+	x2 ^= x4;	x3=ror32(x3,7);	x4 = x0 << 3;	\
+	x1 ^= x0;	x3 ^= x4;	x0=ror32(x0,13);\
+	x1 ^= x2;	x3 ^= x2;	x2=ror32(x2,3);
 
 #define S0(x0,x1,x2,x3,x4)				\
 					x4  = x3;	\
diff --git a/crypto/sha1.c b/crypto/sha1.c
--- a/crypto/sha1.c
+++ b/crypto/sha1.c
@@ -4,8 +4,7 @@
  * SHA1 Secure Hash Algorithm.
  *
  * Derived from cryptoapi implementation, adapted for in-place
- * scatterlist interface.  Originally based on the public domain
- * implementation written by Steve Reid.
+ * scatterlist interface.
  *
  * Copyright (c) Alan Smithee.
  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
@@ -13,7 +12,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) 
+ * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
  */
@@ -21,89 +20,19 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/crypto.h>
+#include <linux/cryptohash.h>
 #include <asm/scatterlist.h>
 #include <asm/byteorder.h>
 
 #define SHA1_DIGEST_SIZE	20
 #define SHA1_HMAC_BLOCK_SIZE	64
 
-static inline u32 rol(u32 value, u32 bits)
-{
-	return (((value) << (bits)) | ((value) >> (32 - (bits))));
-}
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-# define blk0(i) block32[i]
-
-#define blk(i) (block32[i&15] = rol(block32[(i+13)&15]^block32[(i+8)&15] \
-    ^block32[(i+2)&15]^block32[i&15],1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5); \
-                        w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5); \
-                        w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5); \
-                        w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-
 struct sha1_ctx {
         u64 count;
         u32 state[5];
         u8 buffer[64];
 };
 
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-static void sha1_transform(u32 *state, const u8 *in)
-{
-	u32 a, b, c, d, e;
-	u32 block32[16];
-
-	/* convert/copy data to workspace */
-	for (a = 0; a < sizeof(block32)/sizeof(u32); a++)
-	  block32[a] = be32_to_cpu (((const u32 *)in)[a]);
-
-	/* Copy context->state[] to working vars */
-	a = state[0];
-	b = state[1];
-	c = state[2];
-	d = state[3];
-	e = state[4];
-
-	/* 4 rounds of 20 operations each. Loop unrolled. */
-	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
-	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
-	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
-	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
-	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
-	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
-	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
-	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
-	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
-	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
-	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
-	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
-	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
-	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
-	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
-	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
-	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
-	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
-	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
-	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
-	/* Add the working vars back into context.state[] */
-	state[0] += a;
-	state[1] += b;
-	state[2] += c;
-	state[3] += d;
-	state[4] += e;
-	/* Wipe variables */
-	a = b = c = d = e = 0;
-	memset (block32, 0x00, sizeof block32);
-}
-
 static void sha1_init(void *ctx)
 {
 	struct sha1_ctx *sctx = ctx;
@@ -120,19 +49,21 @@ static void sha1_update(void *ctx, const
 {
 	struct sha1_ctx *sctx = ctx;
 	unsigned int i, j;
+	u32 temp[SHA_WORKSPACE_WORDS];
 
 	j = (sctx->count >> 3) & 0x3f;
 	sctx->count += len << 3;
 
 	if ((j + len) > 63) {
 		memcpy(&sctx->buffer[j], data, (i = 64-j));
-		sha1_transform(sctx->state, sctx->buffer);
+		sha_transform(sctx->state, sctx->buffer, temp);
 		for ( ; i + 63 < len; i += 64) {
-			sha1_transform(sctx->state, &data[i]);
+			sha_transform(sctx->state, &data[i], temp);
 		}
 		j = 0;
 	}
 	else i = 0;
+	memset(temp, 0, sizeof(temp));
 	memcpy(&sctx->buffer[j], &data[i], len - i);
 }
 
diff --git a/crypto/sha256.c b/crypto/sha256.c
--- a/crypto/sha256.c
+++ b/crypto/sha256.c
@@ -42,15 +42,10 @@ static inline u32 Maj(u32 x, u32 y, u32 
 	return (x & y) | (z & (x | y));
 }
 
-static inline u32 RORu32(u32 x, u32 y)
-{
-	return (x >> y) | (x << (32 - y));
-}
-
-#define e0(x)       (RORu32(x, 2) ^ RORu32(x,13) ^ RORu32(x,22))
-#define e1(x)       (RORu32(x, 6) ^ RORu32(x,11) ^ RORu32(x,25))
-#define s0(x)       (RORu32(x, 7) ^ RORu32(x,18) ^ (x >> 3))
-#define s1(x)       (RORu32(x,17) ^ RORu32(x,19) ^ (x >> 10))
+#define e0(x)       (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22))
+#define e1(x)       (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25))
+#define s0(x)       (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3))
+#define s1(x)       (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))
 
 #define H0         0x6a09e667
 #define H1         0xbb67ae85
@@ -63,7 +58,7 @@ static inline u32 RORu32(u32 x, u32 y)
 
 static inline void LOAD_OP(int I, u32 *W, const u8 *input)
 {
-	W[I] = __be32_to_cpu( ((u32*)(input))[I] );
+	W[I] = __be32_to_cpu( ((__be32*)(input))[I] );
 }
 
 static inline void BLEND_OP(int I, u32 *W)
diff --git a/crypto/sha512.c b/crypto/sha512.c
--- a/crypto/sha512.c
+++ b/crypto/sha512.c
@@ -105,7 +105,7 @@ static const u64 sha512_K[80] = {
 
 static inline void LOAD_OP(int I, u64 *W, const u8 *input)
 {
-	W[I] = __be64_to_cpu( ((u64*)(input))[I] );
+	W[I] = __be64_to_cpu( ((__be64*)(input))[I] );
 }
 
 static inline void BLEND_OP(int I, u64 *W)
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -695,6 +695,9 @@ do_test(void)
 		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
 		test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS);
 		test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS);
+		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
+		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
+		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
 		test_deflate();
 		test_crc32c();
 #ifdef CONFIG_CRYPTO_HMAC
@@ -832,6 +835,19 @@ do_test(void)
 		test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
 		break;
 
+	case 27:
+		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
+		break;
+
+	case 28:
+
+		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
+		break;
+
+	case 29:
+		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
+		break;
+
 #ifdef CONFIG_CRYPTO_HMAC
 	case 100:
 		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -553,6 +553,137 @@ static struct hash_testvec wp256_tv_temp
 	},
 };
 
+/*
+ * TIGER test vectors from Tiger website 
+ */
+#define TGR192_TEST_VECTORS	6
+
+static struct hash_testvec tgr192_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = { 0x24, 0xf0, 0x13, 0x0c, 0x63, 0xac, 0x93, 0x32,
+			    0x16, 0x16, 0x6e, 0x76, 0xb1, 0xbb, 0x92, 0x5f,
+			    0xf3, 0x73, 0xde, 0x2d, 0x49, 0x58, 0x4e, 0x7a },
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = { 0xf2, 0x58, 0xc1, 0xe8, 0x84, 0x14, 0xab, 0x2a,
+			    0x52, 0x7a, 0xb5, 0x41, 0xff, 0xc5, 0xb8, 0xbf,
+			    0x93, 0x5f, 0x7b, 0x95, 0x1c, 0x13, 0x29, 0x51 },
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = { 0x9f, 0x00, 0xf5, 0x99, 0x07, 0x23, 0x00, 0xdd,
+			    0x27, 0x6a, 0xbb, 0x38, 0xc8, 0xeb, 0x6d, 0xec,
+			    0x37, 0x79, 0x0c, 0x11, 0x6f, 0x9d, 0x2b, 0xdf },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = { 0x87, 0xfb, 0x2a, 0x90, 0x83, 0x85, 0x1c, 0xf7,
+			    0x47, 0x0d, 0x2c, 0xf8, 0x10, 0xe6, 0xdf, 0x9e,
+			    0xb5, 0x86, 0x44, 0x50, 0x34, 0xa5, 0xa3, 0x86 },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = { 0x46, 0x7d, 0xb8, 0x08, 0x63, 0xeb, 0xce, 0x48,
+			    0x8d, 0xf1, 0xcd, 0x12, 0x61, 0x65, 0x5d, 0xe9,
+			    0x57, 0x89, 0x65, 0x65, 0x97, 0x5f, 0x91, 0x97 },
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			     "by Ross Anderson and Eli Biham, "
+			     "proceedings of Fast Software Encryption 3, "
+			     "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = { 0x3d, 0x9a, 0xeb, 0x03, 0xd1, 0xbd, 0x1a, 0x63,
+			    0x57, 0xb2, 0x77, 0x4d, 0xfd, 0x6d, 0x5b, 0x24,
+			    0xdd, 0x68, 0x15, 0x1d, 0x50, 0x39, 0x74, 0xfc },
+	},
+};
+
+#define TGR160_TEST_VECTORS	6
+
+static struct hash_testvec tgr160_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = { 0x24, 0xf0, 0x13, 0x0c, 0x63, 0xac, 0x93, 0x32,
+			    0x16, 0x16, 0x6e, 0x76, 0xb1, 0xbb, 0x92, 0x5f,
+			    0xf3, 0x73, 0xde, 0x2d },
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = { 0xf2, 0x58, 0xc1, 0xe8, 0x84, 0x14, 0xab, 0x2a,
+			    0x52, 0x7a, 0xb5, 0x41, 0xff, 0xc5, 0xb8, 0xbf,
+			    0x93, 0x5f, 0x7b, 0x95 },
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = { 0x9f, 0x00, 0xf5, 0x99, 0x07, 0x23, 0x00, 0xdd,
+			    0x27, 0x6a, 0xbb, 0x38, 0xc8, 0xeb, 0x6d, 0xec,
+			    0x37, 0x79, 0x0c, 0x11 },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = { 0x87, 0xfb, 0x2a, 0x90, 0x83, 0x85, 0x1c, 0xf7,
+			    0x47, 0x0d, 0x2c, 0xf8, 0x10, 0xe6, 0xdf, 0x9e,
+			    0xb5, 0x86, 0x44, 0x50 },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = { 0x46, 0x7d, 0xb8, 0x08, 0x63, 0xeb, 0xce, 0x48,
+			    0x8d, 0xf1, 0xcd, 0x12, 0x61, 0x65, 0x5d, 0xe9,
+			    0x57, 0x89, 0x65, 0x65 },
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			     "by Ross Anderson and Eli Biham, "
+			     "proceedings of Fast Software Encryption 3, "
+			     "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = { 0x3d, 0x9a, 0xeb, 0x03, 0xd1, 0xbd, 0x1a, 0x63,
+			    0x57, 0xb2, 0x77, 0x4d, 0xfd, 0x6d, 0x5b, 0x24,
+			    0xdd, 0x68, 0x15, 0x1d },
+	},
+};
+
+#define TGR128_TEST_VECTORS	6
+
+static struct hash_testvec tgr128_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = { 0x24, 0xf0, 0x13, 0x0c, 0x63, 0xac, 0x93, 0x32,
+			    0x16, 0x16, 0x6e, 0x76, 0xb1, 0xbb, 0x92, 0x5f },
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = { 0xf2, 0x58, 0xc1, 0xe8, 0x84, 0x14, 0xab, 0x2a,
+			    0x52, 0x7a, 0xb5, 0x41, 0xff, 0xc5, 0xb8, 0xbf },
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = { 0x9f, 0x00, 0xf5, 0x99, 0x07, 0x23, 0x00, 0xdd,
+			    0x27, 0x6a, 0xbb, 0x38, 0xc8, 0xeb, 0x6d, 0xec },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = { 0x87, 0xfb, 0x2a, 0x90, 0x83, 0x85, 0x1c, 0xf7,
+			    0x47, 0x0d, 0x2c, 0xf8, 0x10, 0xe6, 0xdf, 0x9e },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = { 0x46, 0x7d, 0xb8, 0x08, 0x63, 0xeb, 0xce, 0x48,
+			    0x8d, 0xf1, 0xcd, 0x12, 0x61, 0x65, 0x5d, 0xe9 },
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			     "by Ross Anderson and Eli Biham, "
+			     "proceedings of Fast Software Encryption 3, "
+			     "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = { 0x3d, 0x9a, 0xeb, 0x03, 0xd1, 0xbd, 0x1a, 0x63,
+			    0x57, 0xb2, 0x77, 0x4d, 0xfd, 0x6d, 0x5b, 0x24 },
+	},
+};
 
 #ifdef CONFIG_CRYPTO_HMAC
 /*
diff --git a/crypto/tea.c b/crypto/tea.c
--- a/crypto/tea.c
+++ b/crypto/tea.c
@@ -31,8 +31,8 @@
 #define XTEA_ROUNDS		32
 #define XTEA_DELTA		0x9e3779b9
 
-#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
-#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from))
+#define u32_in(x) le32_to_cpu(*(const __le32 *)(x))
+#define u32_out(to, from) (*(__le32 *)(to) = cpu_to_le32(from))
 
 struct tea_ctx {
 	u32 KEY[4];
diff --git a/crypto/tgr192.c b/crypto/tgr192.c
new file mode 100644
--- /dev/null
+++ b/crypto/tgr192.c
@@ -0,0 +1,735 @@
+/*
+ * Cryptographic API.
+ *
+ * Tiger hashing Algorithm
+ *
+ *      Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * The Tiger algorithm was developed by Ross Anderson and Eli Biham.
+ * It was optimized for 64-bit processors while still delievering
+ * decent performance on 32 and 16-bit processors.
+ *
+ * This version is derived from the GnuPG implementation and the
+ * Tiger-Perl interface written by Rafael Sevilla
+ *
+ * Adapted for Linux Kernel Crypto  by Aaron Grothe 
+ * ajgrothe@yahoo.com, February 22, 2005
+ *
+ * This program is free software; you can redistribute it 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/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define TGR192_DIGEST_SIZE 24
+#define TGR160_DIGEST_SIZE 20
+#define TGR128_DIGEST_SIZE 16
+
+#define TGR192_BLOCK_SIZE  64
+
+struct tgr192_ctx {
+	u64 a, b, c;
+	u8 hash[64];
+	int count;
+	u32 nblocks;
+};
+
+static const u64 sbox1[256] = {
+	0x02aab17cf7e90c5eULL, 0xac424b03e243a8ecULL, 0x72cd5be30dd5fcd3ULL,
+	0x6d019b93f6f97f3aULL, 0xcd9978ffd21f9193ULL, 0x7573a1c9708029e2ULL,
+	0xb164326b922a83c3ULL, 0x46883eee04915870ULL, 0xeaace3057103ece6ULL,
+	0xc54169b808a3535cULL, 0x4ce754918ddec47cULL, 0x0aa2f4dfdc0df40cULL,
+	0x10b76f18a74dbefaULL, 0xc6ccb6235ad1ab6aULL, 0x13726121572fe2ffULL,
+	0x1a488c6f199d921eULL, 0x4bc9f9f4da0007caULL, 0x26f5e6f6e85241c7ULL,
+	0x859079dbea5947b6ULL, 0x4f1885c5c99e8c92ULL, 0xd78e761ea96f864bULL,
+	0x8e36428c52b5c17dULL, 0x69cf6827373063c1ULL, 0xb607c93d9bb4c56eULL,
+	0x7d820e760e76b5eaULL, 0x645c9cc6f07fdc42ULL, 0xbf38a078243342e0ULL,
+	0x5f6b343c9d2e7d04ULL, 0xf2c28aeb600b0ec6ULL, 0x6c0ed85f7254bcacULL,
+	0x71592281a4db4fe5ULL, 0x1967fa69ce0fed9fULL, 0xfd5293f8b96545dbULL,
+	0xc879e9d7f2a7600bULL, 0x860248920193194eULL, 0xa4f9533b2d9cc0b3ULL,
+	0x9053836c15957613ULL, 0xdb6dcf8afc357bf1ULL, 0x18beea7a7a370f57ULL,
+	0x037117ca50b99066ULL, 0x6ab30a9774424a35ULL, 0xf4e92f02e325249bULL,
+	0x7739db07061ccae1ULL, 0xd8f3b49ceca42a05ULL, 0xbd56be3f51382f73ULL,
+	0x45faed5843b0bb28ULL, 0x1c813d5c11bf1f83ULL, 0x8af0e4b6d75fa169ULL,
+	0x33ee18a487ad9999ULL, 0x3c26e8eab1c94410ULL, 0xb510102bc0a822f9ULL,
+	0x141eef310ce6123bULL, 0xfc65b90059ddb154ULL, 0xe0158640c5e0e607ULL,
+	0x884e079826c3a3cfULL, 0x930d0d9523c535fdULL, 0x35638d754e9a2b00ULL,
+	0x4085fccf40469dd5ULL, 0xc4b17ad28be23a4cULL, 0xcab2f0fc6a3e6a2eULL,
+	0x2860971a6b943fcdULL, 0x3dde6ee212e30446ULL, 0x6222f32ae01765aeULL,
+	0x5d550bb5478308feULL, 0xa9efa98da0eda22aULL, 0xc351a71686c40da7ULL,
+	0x1105586d9c867c84ULL, 0xdcffee85fda22853ULL, 0xccfbd0262c5eef76ULL,
+	0xbaf294cb8990d201ULL, 0xe69464f52afad975ULL, 0x94b013afdf133e14ULL,
+	0x06a7d1a32823c958ULL, 0x6f95fe5130f61119ULL, 0xd92ab34e462c06c0ULL,
+	0xed7bde33887c71d2ULL, 0x79746d6e6518393eULL, 0x5ba419385d713329ULL,
+	0x7c1ba6b948a97564ULL, 0x31987c197bfdac67ULL, 0xde6c23c44b053d02ULL,
+	0x581c49fed002d64dULL, 0xdd474d6338261571ULL, 0xaa4546c3e473d062ULL,
+	0x928fce349455f860ULL, 0x48161bbacaab94d9ULL, 0x63912430770e6f68ULL,
+	0x6ec8a5e602c6641cULL, 0x87282515337ddd2bULL, 0x2cda6b42034b701bULL,
+	0xb03d37c181cb096dULL, 0xe108438266c71c6fULL, 0x2b3180c7eb51b255ULL,
+	0xdf92b82f96c08bbcULL, 0x5c68c8c0a632f3baULL, 0x5504cc861c3d0556ULL,
+	0xabbfa4e55fb26b8fULL, 0x41848b0ab3baceb4ULL, 0xb334a273aa445d32ULL,
+	0xbca696f0a85ad881ULL, 0x24f6ec65b528d56cULL, 0x0ce1512e90f4524aULL,
+	0x4e9dd79d5506d35aULL, 0x258905fac6ce9779ULL, 0x2019295b3e109b33ULL,
+	0xf8a9478b73a054ccULL, 0x2924f2f934417eb0ULL, 0x3993357d536d1bc4ULL,
+	0x38a81ac21db6ff8bULL, 0x47c4fbf17d6016bfULL, 0x1e0faadd7667e3f5ULL,
+	0x7abcff62938beb96ULL, 0xa78dad948fc179c9ULL, 0x8f1f98b72911e50dULL,
+	0x61e48eae27121a91ULL, 0x4d62f7ad31859808ULL, 0xeceba345ef5ceaebULL,
+	0xf5ceb25ebc9684ceULL, 0xf633e20cb7f76221ULL, 0xa32cdf06ab8293e4ULL,
+	0x985a202ca5ee2ca4ULL, 0xcf0b8447cc8a8fb1ULL, 0x9f765244979859a3ULL,
+	0xa8d516b1a1240017ULL, 0x0bd7ba3ebb5dc726ULL, 0xe54bca55b86adb39ULL,
+	0x1d7a3afd6c478063ULL, 0x519ec608e7669eddULL, 0x0e5715a2d149aa23ULL,
+	0x177d4571848ff194ULL, 0xeeb55f3241014c22ULL, 0x0f5e5ca13a6e2ec2ULL,
+	0x8029927b75f5c361ULL, 0xad139fabc3d6e436ULL, 0x0d5df1a94ccf402fULL,
+	0x3e8bd948bea5dfc8ULL, 0xa5a0d357bd3ff77eULL, 0xa2d12e251f74f645ULL,
+	0x66fd9e525e81a082ULL, 0x2e0c90ce7f687a49ULL, 0xc2e8bcbeba973bc5ULL,
+	0x000001bce509745fULL, 0x423777bbe6dab3d6ULL, 0xd1661c7eaef06eb5ULL,
+	0xa1781f354daacfd8ULL, 0x2d11284a2b16affcULL, 0xf1fc4f67fa891d1fULL,
+	0x73ecc25dcb920adaULL, 0xae610c22c2a12651ULL, 0x96e0a810d356b78aULL,
+	0x5a9a381f2fe7870fULL, 0xd5ad62ede94e5530ULL, 0xd225e5e8368d1427ULL,
+	0x65977b70c7af4631ULL, 0x99f889b2de39d74fULL, 0x233f30bf54e1d143ULL,
+	0x9a9675d3d9a63c97ULL, 0x5470554ff334f9a8ULL, 0x166acb744a4f5688ULL,
+	0x70c74caab2e4aeadULL, 0xf0d091646f294d12ULL, 0x57b82a89684031d1ULL,
+	0xefd95a5a61be0b6bULL, 0x2fbd12e969f2f29aULL, 0x9bd37013feff9fe8ULL,
+	0x3f9b0404d6085a06ULL, 0x4940c1f3166cfe15ULL, 0x09542c4dcdf3defbULL,
+	0xb4c5218385cd5ce3ULL, 0xc935b7dc4462a641ULL, 0x3417f8a68ed3b63fULL,
+	0xb80959295b215b40ULL, 0xf99cdaef3b8c8572ULL, 0x018c0614f8fcb95dULL,
+	0x1b14accd1a3acdf3ULL, 0x84d471f200bb732dULL, 0xc1a3110e95e8da16ULL,
+	0x430a7220bf1a82b8ULL, 0xb77e090d39df210eULL, 0x5ef4bd9f3cd05e9dULL,
+	0x9d4ff6da7e57a444ULL, 0xda1d60e183d4a5f8ULL, 0xb287c38417998e47ULL,
+	0xfe3edc121bb31886ULL, 0xc7fe3ccc980ccbefULL, 0xe46fb590189bfd03ULL,
+	0x3732fd469a4c57dcULL, 0x7ef700a07cf1ad65ULL, 0x59c64468a31d8859ULL,
+	0x762fb0b4d45b61f6ULL, 0x155baed099047718ULL, 0x68755e4c3d50baa6ULL,
+	0xe9214e7f22d8b4dfULL, 0x2addbf532eac95f4ULL, 0x32ae3909b4bd0109ULL,
+	0x834df537b08e3450ULL, 0xfa209da84220728dULL, 0x9e691d9b9efe23f7ULL,
+	0x0446d288c4ae8d7fULL, 0x7b4cc524e169785bULL, 0x21d87f0135ca1385ULL,
+	0xcebb400f137b8aa5ULL, 0x272e2b66580796beULL, 0x3612264125c2b0deULL,
+	0x057702bdad1efbb2ULL, 0xd4babb8eacf84be9ULL, 0x91583139641bc67bULL,
+	0x8bdc2de08036e024ULL, 0x603c8156f49f68edULL, 0xf7d236f7dbef5111ULL,
+	0x9727c4598ad21e80ULL, 0xa08a0896670a5fd7ULL, 0xcb4a8f4309eba9cbULL,
+	0x81af564b0f7036a1ULL, 0xc0b99aa778199abdULL, 0x959f1ec83fc8e952ULL,
+	0x8c505077794a81b9ULL, 0x3acaaf8f056338f0ULL, 0x07b43f50627a6778ULL,
+	0x4a44ab49f5eccc77ULL, 0x3bc3d6e4b679ee98ULL, 0x9cc0d4d1cf14108cULL,
+	0x4406c00b206bc8a0ULL, 0x82a18854c8d72d89ULL, 0x67e366b35c3c432cULL,
+	0xb923dd61102b37f2ULL, 0x56ab2779d884271dULL, 0xbe83e1b0ff1525afULL,
+	0xfb7c65d4217e49a9ULL, 0x6bdbe0e76d48e7d4ULL, 0x08df828745d9179eULL,
+	0x22ea6a9add53bd34ULL, 0xe36e141c5622200aULL, 0x7f805d1b8cb750eeULL,
+	0xafe5c7a59f58e837ULL, 0xe27f996a4fb1c23cULL, 0xd3867dfb0775f0d0ULL,
+	0xd0e673de6e88891aULL, 0x123aeb9eafb86c25ULL, 0x30f1d5d5c145b895ULL,
+	0xbb434a2dee7269e7ULL, 0x78cb67ecf931fa38ULL, 0xf33b0372323bbf9cULL,
+	0x52d66336fb279c74ULL, 0x505f33ac0afb4eaaULL, 0xe8a5cd99a2cce187ULL,
+	0x534974801e2d30bbULL, 0x8d2d5711d5876d90ULL, 0x1f1a412891bc038eULL,
+	0xd6e2e71d82e56648ULL, 0x74036c3a497732b7ULL, 0x89b67ed96361f5abULL,
+	0xffed95d8f1ea02a2ULL, 0xe72b3bd61464d43dULL, 0xa6300f170bdc4820ULL,
+	0xebc18760ed78a77aULL
+};
+
+static const u64 sbox2[256] = {
+	0xe6a6be5a05a12138ULL, 0xb5a122a5b4f87c98ULL, 0x563c6089140b6990ULL,
+	0x4c46cb2e391f5dd5ULL, 0xd932addbc9b79434ULL, 0x08ea70e42015aff5ULL,
+	0xd765a6673e478cf1ULL, 0xc4fb757eab278d99ULL, 0xdf11c6862d6e0692ULL,
+	0xddeb84f10d7f3b16ULL, 0x6f2ef604a665ea04ULL, 0x4a8e0f0ff0e0dfb3ULL,
+	0xa5edeef83dbcba51ULL, 0xfc4f0a2a0ea4371eULL, 0xe83e1da85cb38429ULL,
+	0xdc8ff882ba1b1ce2ULL, 0xcd45505e8353e80dULL, 0x18d19a00d4db0717ULL,
+	0x34a0cfeda5f38101ULL, 0x0be77e518887caf2ULL, 0x1e341438b3c45136ULL,
+	0xe05797f49089ccf9ULL, 0xffd23f9df2591d14ULL, 0x543dda228595c5cdULL,
+	0x661f81fd99052a33ULL, 0x8736e641db0f7b76ULL, 0x15227725418e5307ULL,
+	0xe25f7f46162eb2faULL, 0x48a8b2126c13d9feULL, 0xafdc541792e76eeaULL,
+	0x03d912bfc6d1898fULL, 0x31b1aafa1b83f51bULL, 0xf1ac2796e42ab7d9ULL,
+	0x40a3a7d7fcd2ebacULL, 0x1056136d0afbbcc5ULL, 0x7889e1dd9a6d0c85ULL,
+	0xd33525782a7974aaULL, 0xa7e25d09078ac09bULL, 0xbd4138b3eac6edd0ULL,
+	0x920abfbe71eb9e70ULL, 0xa2a5d0f54fc2625cULL, 0xc054e36b0b1290a3ULL,
+	0xf6dd59ff62fe932bULL, 0x3537354511a8ac7dULL, 0xca845e9172fadcd4ULL,
+	0x84f82b60329d20dcULL, 0x79c62ce1cd672f18ULL, 0x8b09a2add124642cULL,
+	0xd0c1e96a19d9e726ULL, 0x5a786a9b4ba9500cULL, 0x0e020336634c43f3ULL,
+	0xc17b474aeb66d822ULL, 0x6a731ae3ec9baac2ULL, 0x8226667ae0840258ULL,
+	0x67d4567691caeca5ULL, 0x1d94155c4875adb5ULL, 0x6d00fd985b813fdfULL,
+	0x51286efcb774cd06ULL, 0x5e8834471fa744afULL, 0xf72ca0aee761ae2eULL,
+	0xbe40e4cdaee8e09aULL, 0xe9970bbb5118f665ULL, 0x726e4beb33df1964ULL,
+	0x703b000729199762ULL, 0x4631d816f5ef30a7ULL, 0xb880b5b51504a6beULL,
+	0x641793c37ed84b6cULL, 0x7b21ed77f6e97d96ULL, 0x776306312ef96b73ULL,
+	0xae528948e86ff3f4ULL, 0x53dbd7f286a3f8f8ULL, 0x16cadce74cfc1063ULL,
+	0x005c19bdfa52c6ddULL, 0x68868f5d64d46ad3ULL, 0x3a9d512ccf1e186aULL,
+	0x367e62c2385660aeULL, 0xe359e7ea77dcb1d7ULL, 0x526c0773749abe6eULL,
+	0x735ae5f9d09f734bULL, 0x493fc7cc8a558ba8ULL, 0xb0b9c1533041ab45ULL,
+	0x321958ba470a59bdULL, 0x852db00b5f46c393ULL, 0x91209b2bd336b0e5ULL,
+	0x6e604f7d659ef19fULL, 0xb99a8ae2782ccb24ULL, 0xccf52ab6c814c4c7ULL,
+	0x4727d9afbe11727bULL, 0x7e950d0c0121b34dULL, 0x756f435670ad471fULL,
+	0xf5add442615a6849ULL, 0x4e87e09980b9957aULL, 0x2acfa1df50aee355ULL,
+	0xd898263afd2fd556ULL, 0xc8f4924dd80c8fd6ULL, 0xcf99ca3d754a173aULL,
+	0xfe477bacaf91bf3cULL, 0xed5371f6d690c12dULL, 0x831a5c285e687094ULL,
+	0xc5d3c90a3708a0a4ULL, 0x0f7f903717d06580ULL, 0x19f9bb13b8fdf27fULL,
+	0xb1bd6f1b4d502843ULL, 0x1c761ba38fff4012ULL, 0x0d1530c4e2e21f3bULL,
+	0x8943ce69a7372c8aULL, 0xe5184e11feb5ce66ULL, 0x618bdb80bd736621ULL,
+	0x7d29bad68b574d0bULL, 0x81bb613e25e6fe5bULL, 0x071c9c10bc07913fULL,
+	0xc7beeb7909ac2d97ULL, 0xc3e58d353bc5d757ULL, 0xeb017892f38f61e8ULL,
+	0xd4effb9c9b1cc21aULL, 0x99727d26f494f7abULL, 0xa3e063a2956b3e03ULL,
+	0x9d4a8b9a4aa09c30ULL, 0x3f6ab7d500090fb4ULL, 0x9cc0f2a057268ac0ULL,
+	0x3dee9d2dedbf42d1ULL, 0x330f49c87960a972ULL, 0xc6b2720287421b41ULL,
+	0x0ac59ec07c00369cULL, 0xef4eac49cb353425ULL, 0xf450244eef0129d8ULL,
+	0x8acc46e5caf4deb6ULL, 0x2ffeab63989263f7ULL, 0x8f7cb9fe5d7a4578ULL,
+	0x5bd8f7644e634635ULL, 0x427a7315bf2dc900ULL, 0x17d0c4aa2125261cULL,
+	0x3992486c93518e50ULL, 0xb4cbfee0a2d7d4c3ULL, 0x7c75d6202c5ddd8dULL,
+	0xdbc295d8e35b6c61ULL, 0x60b369d302032b19ULL, 0xce42685fdce44132ULL,
+	0x06f3ddb9ddf65610ULL, 0x8ea4d21db5e148f0ULL, 0x20b0fce62fcd496fULL,
+	0x2c1b912358b0ee31ULL, 0xb28317b818f5a308ULL, 0xa89c1e189ca6d2cfULL,
+	0x0c6b18576aaadbc8ULL, 0xb65deaa91299fae3ULL, 0xfb2b794b7f1027e7ULL,
+	0x04e4317f443b5bebULL, 0x4b852d325939d0a6ULL, 0xd5ae6beefb207ffcULL,
+	0x309682b281c7d374ULL, 0xbae309a194c3b475ULL, 0x8cc3f97b13b49f05ULL,
+	0x98a9422ff8293967ULL, 0x244b16b01076ff7cULL, 0xf8bf571c663d67eeULL,
+	0x1f0d6758eee30da1ULL, 0xc9b611d97adeb9b7ULL, 0xb7afd5887b6c57a2ULL,
+	0x6290ae846b984fe1ULL, 0x94df4cdeacc1a5fdULL, 0x058a5bd1c5483affULL,
+	0x63166cc142ba3c37ULL, 0x8db8526eb2f76f40ULL, 0xe10880036f0d6d4eULL,
+	0x9e0523c9971d311dULL, 0x45ec2824cc7cd691ULL, 0x575b8359e62382c9ULL,
+	0xfa9e400dc4889995ULL, 0xd1823ecb45721568ULL, 0xdafd983b8206082fULL,
+	0xaa7d29082386a8cbULL, 0x269fcd4403b87588ULL, 0x1b91f5f728bdd1e0ULL,
+	0xe4669f39040201f6ULL, 0x7a1d7c218cf04adeULL, 0x65623c29d79ce5ceULL,
+	0x2368449096c00bb1ULL, 0xab9bf1879da503baULL, 0xbc23ecb1a458058eULL,
+	0x9a58df01bb401eccULL, 0xa070e868a85f143dULL, 0x4ff188307df2239eULL,
+	0x14d565b41a641183ULL, 0xee13337452701602ULL, 0x950e3dcf3f285e09ULL,
+	0x59930254b9c80953ULL, 0x3bf299408930da6dULL, 0xa955943f53691387ULL,
+	0xa15edecaa9cb8784ULL, 0x29142127352be9a0ULL, 0x76f0371fff4e7afbULL,
+	0x0239f450274f2228ULL, 0xbb073af01d5e868bULL, 0xbfc80571c10e96c1ULL,
+	0xd267088568222e23ULL, 0x9671a3d48e80b5b0ULL, 0x55b5d38ae193bb81ULL,
+	0x693ae2d0a18b04b8ULL, 0x5c48b4ecadd5335fULL, 0xfd743b194916a1caULL,
+	0x2577018134be98c4ULL, 0xe77987e83c54a4adULL, 0x28e11014da33e1b9ULL,
+	0x270cc59e226aa213ULL, 0x71495f756d1a5f60ULL, 0x9be853fb60afef77ULL,
+	0xadc786a7f7443dbfULL, 0x0904456173b29a82ULL, 0x58bc7a66c232bd5eULL,
+	0xf306558c673ac8b2ULL, 0x41f639c6b6c9772aULL, 0x216defe99fda35daULL,
+	0x11640cc71c7be615ULL, 0x93c43694565c5527ULL, 0xea038e6246777839ULL,
+	0xf9abf3ce5a3e2469ULL, 0x741e768d0fd312d2ULL, 0x0144b883ced652c6ULL,
+	0xc20b5a5ba33f8552ULL, 0x1ae69633c3435a9dULL, 0x97a28ca4088cfdecULL,
+	0x8824a43c1e96f420ULL, 0x37612fa66eeea746ULL, 0x6b4cb165f9cf0e5aULL,
+	0x43aa1c06a0abfb4aULL, 0x7f4dc26ff162796bULL, 0x6cbacc8e54ed9b0fULL,
+	0xa6b7ffefd2bb253eULL, 0x2e25bc95b0a29d4fULL, 0x86d6a58bdef1388cULL,
+	0xded74ac576b6f054ULL, 0x8030bdbc2b45805dULL, 0x3c81af70e94d9289ULL,
+	0x3eff6dda9e3100dbULL, 0xb38dc39fdfcc8847ULL, 0x123885528d17b87eULL,
+	0xf2da0ed240b1b642ULL, 0x44cefadcd54bf9a9ULL, 0x1312200e433c7ee6ULL,
+	0x9ffcc84f3a78c748ULL, 0xf0cd1f72248576bbULL, 0xec6974053638cfe4ULL,
+	0x2ba7b67c0cec4e4cULL, 0xac2f4df3e5ce32edULL, 0xcb33d14326ea4c11ULL,
+	0xa4e9044cc77e58bcULL, 0x5f513293d934fcefULL, 0x5dc9645506e55444ULL,
+	0x50de418f317de40aULL, 0x388cb31a69dde259ULL, 0x2db4a83455820a86ULL,
+	0x9010a91e84711ae9ULL, 0x4df7f0b7b1498371ULL, 0xd62a2eabc0977179ULL,
+	0x22fac097aa8d5c0eULL
+};
+
+static const u64 sbox3[256] = {
+	0xf49fcc2ff1daf39bULL, 0x487fd5c66ff29281ULL, 0xe8a30667fcdca83fULL,
+	0x2c9b4be3d2fcce63ULL, 0xda3ff74b93fbbbc2ULL, 0x2fa165d2fe70ba66ULL,
+	0xa103e279970e93d4ULL, 0xbecdec77b0e45e71ULL, 0xcfb41e723985e497ULL,
+	0xb70aaa025ef75017ULL, 0xd42309f03840b8e0ULL, 0x8efc1ad035898579ULL,
+	0x96c6920be2b2abc5ULL, 0x66af4163375a9172ULL, 0x2174abdcca7127fbULL,
+	0xb33ccea64a72ff41ULL, 0xf04a4933083066a5ULL, 0x8d970acdd7289af5ULL,
+	0x8f96e8e031c8c25eULL, 0xf3fec02276875d47ULL, 0xec7bf310056190ddULL,
+	0xf5adb0aebb0f1491ULL, 0x9b50f8850fd58892ULL, 0x4975488358b74de8ULL,
+	0xa3354ff691531c61ULL, 0x0702bbe481d2c6eeULL, 0x89fb24057deded98ULL,
+	0xac3075138596e902ULL, 0x1d2d3580172772edULL, 0xeb738fc28e6bc30dULL,
+	0x5854ef8f63044326ULL, 0x9e5c52325add3bbeULL, 0x90aa53cf325c4623ULL,
+	0xc1d24d51349dd067ULL, 0x2051cfeea69ea624ULL, 0x13220f0a862e7e4fULL,
+	0xce39399404e04864ULL, 0xd9c42ca47086fcb7ULL, 0x685ad2238a03e7ccULL,
+	0x066484b2ab2ff1dbULL, 0xfe9d5d70efbf79ecULL, 0x5b13b9dd9c481854ULL,
+	0x15f0d475ed1509adULL, 0x0bebcd060ec79851ULL, 0xd58c6791183ab7f8ULL,
+	0xd1187c5052f3eee4ULL, 0xc95d1192e54e82ffULL, 0x86eea14cb9ac6ca2ULL,
+	0x3485beb153677d5dULL, 0xdd191d781f8c492aULL, 0xf60866baa784ebf9ULL,
+	0x518f643ba2d08c74ULL, 0x8852e956e1087c22ULL, 0xa768cb8dc410ae8dULL,
+	0x38047726bfec8e1aULL, 0xa67738b4cd3b45aaULL, 0xad16691cec0dde19ULL,
+	0xc6d4319380462e07ULL, 0xc5a5876d0ba61938ULL, 0x16b9fa1fa58fd840ULL,
+	0x188ab1173ca74f18ULL, 0xabda2f98c99c021fULL, 0x3e0580ab134ae816ULL,
+	0x5f3b05b773645abbULL, 0x2501a2be5575f2f6ULL, 0x1b2f74004e7e8ba9ULL,
+	0x1cd7580371e8d953ULL, 0x7f6ed89562764e30ULL, 0xb15926ff596f003dULL,
+	0x9f65293da8c5d6b9ULL, 0x6ecef04dd690f84cULL, 0x4782275fff33af88ULL,
+	0xe41433083f820801ULL, 0xfd0dfe409a1af9b5ULL, 0x4325a3342cdb396bULL,
+	0x8ae77e62b301b252ULL, 0xc36f9e9f6655615aULL, 0x85455a2d92d32c09ULL,
+	0xf2c7dea949477485ULL, 0x63cfb4c133a39ebaULL, 0x83b040cc6ebc5462ULL,
+	0x3b9454c8fdb326b0ULL, 0x56f56a9e87ffd78cULL, 0x2dc2940d99f42bc6ULL,
+	0x98f7df096b096e2dULL, 0x19a6e01e3ad852bfULL, 0x42a99ccbdbd4b40bULL,
+	0xa59998af45e9c559ULL, 0x366295e807d93186ULL, 0x6b48181bfaa1f773ULL,
+	0x1fec57e2157a0a1dULL, 0x4667446af6201ad5ULL, 0xe615ebcacfb0f075ULL,
+	0xb8f31f4f68290778ULL, 0x22713ed6ce22d11eULL, 0x3057c1a72ec3c93bULL,
+	0xcb46acc37c3f1f2fULL, 0xdbb893fd02aaf50eULL, 0x331fd92e600b9fcfULL,
+	0xa498f96148ea3ad6ULL, 0xa8d8426e8b6a83eaULL, 0xa089b274b7735cdcULL,
+	0x87f6b3731e524a11ULL, 0x118808e5cbc96749ULL, 0x9906e4c7b19bd394ULL,
+	0xafed7f7e9b24a20cULL, 0x6509eadeeb3644a7ULL, 0x6c1ef1d3e8ef0edeULL,
+	0xb9c97d43e9798fb4ULL, 0xa2f2d784740c28a3ULL, 0x7b8496476197566fULL,
+	0x7a5be3e6b65f069dULL, 0xf96330ed78be6f10ULL, 0xeee60de77a076a15ULL,
+	0x2b4bee4aa08b9bd0ULL, 0x6a56a63ec7b8894eULL, 0x02121359ba34fef4ULL,
+	0x4cbf99f8283703fcULL, 0x398071350caf30c8ULL, 0xd0a77a89f017687aULL,
+	0xf1c1a9eb9e423569ULL, 0x8c7976282dee8199ULL, 0x5d1737a5dd1f7abdULL,
+	0x4f53433c09a9fa80ULL, 0xfa8b0c53df7ca1d9ULL, 0x3fd9dcbc886ccb77ULL,
+	0xc040917ca91b4720ULL, 0x7dd00142f9d1dcdfULL, 0x8476fc1d4f387b58ULL,
+	0x23f8e7c5f3316503ULL, 0x032a2244e7e37339ULL, 0x5c87a5d750f5a74bULL,
+	0x082b4cc43698992eULL, 0xdf917becb858f63cULL, 0x3270b8fc5bf86ddaULL,
+	0x10ae72bb29b5dd76ULL, 0x576ac94e7700362bULL, 0x1ad112dac61efb8fULL,
+	0x691bc30ec5faa427ULL, 0xff246311cc327143ULL, 0x3142368e30e53206ULL,
+	0x71380e31e02ca396ULL, 0x958d5c960aad76f1ULL, 0xf8d6f430c16da536ULL,
+	0xc8ffd13f1be7e1d2ULL, 0x7578ae66004ddbe1ULL, 0x05833f01067be646ULL,
+	0xbb34b5ad3bfe586dULL, 0x095f34c9a12b97f0ULL, 0x247ab64525d60ca8ULL,
+	0xdcdbc6f3017477d1ULL, 0x4a2e14d4decad24dULL, 0xbdb5e6d9be0a1eebULL,
+	0x2a7e70f7794301abULL, 0xdef42d8a270540fdULL, 0x01078ec0a34c22c1ULL,
+	0xe5de511af4c16387ULL, 0x7ebb3a52bd9a330aULL, 0x77697857aa7d6435ULL,
+	0x004e831603ae4c32ULL, 0xe7a21020ad78e312ULL, 0x9d41a70c6ab420f2ULL,
+	0x28e06c18ea1141e6ULL, 0xd2b28cbd984f6b28ULL, 0x26b75f6c446e9d83ULL,
+	0xba47568c4d418d7fULL, 0xd80badbfe6183d8eULL, 0x0e206d7f5f166044ULL,
+	0xe258a43911cbca3eULL, 0x723a1746b21dc0bcULL, 0xc7caa854f5d7cdd3ULL,
+	0x7cac32883d261d9cULL, 0x7690c26423ba942cULL, 0x17e55524478042b8ULL,
+	0xe0be477656a2389fULL, 0x4d289b5e67ab2da0ULL, 0x44862b9c8fbbfd31ULL,
+	0xb47cc8049d141365ULL, 0x822c1b362b91c793ULL, 0x4eb14655fb13dfd8ULL,
+	0x1ecbba0714e2a97bULL, 0x6143459d5cde5f14ULL, 0x53a8fbf1d5f0ac89ULL,
+	0x97ea04d81c5e5b00ULL, 0x622181a8d4fdb3f3ULL, 0xe9bcd341572a1208ULL,
+	0x1411258643cce58aULL, 0x9144c5fea4c6e0a4ULL, 0x0d33d06565cf620fULL,
+	0x54a48d489f219ca1ULL, 0xc43e5eac6d63c821ULL, 0xa9728b3a72770dafULL,
+	0xd7934e7b20df87efULL, 0xe35503b61a3e86e5ULL, 0xcae321fbc819d504ULL,
+	0x129a50b3ac60bfa6ULL, 0xcd5e68ea7e9fb6c3ULL, 0xb01c90199483b1c7ULL,
+	0x3de93cd5c295376cULL, 0xaed52edf2ab9ad13ULL, 0x2e60f512c0a07884ULL,
+	0xbc3d86a3e36210c9ULL, 0x35269d9b163951ceULL, 0x0c7d6e2ad0cdb5faULL,
+	0x59e86297d87f5733ULL, 0x298ef221898db0e7ULL, 0x55000029d1a5aa7eULL,
+	0x8bc08ae1b5061b45ULL, 0xc2c31c2b6c92703aULL, 0x94cc596baf25ef42ULL,
+	0x0a1d73db22540456ULL, 0x04b6a0f9d9c4179aULL, 0xeffdafa2ae3d3c60ULL,
+	0xf7c8075bb49496c4ULL, 0x9cc5c7141d1cd4e3ULL, 0x78bd1638218e5534ULL,
+	0xb2f11568f850246aULL, 0xedfabcfa9502bc29ULL, 0x796ce5f2da23051bULL,
+	0xaae128b0dc93537cULL, 0x3a493da0ee4b29aeULL, 0xb5df6b2c416895d7ULL,
+	0xfcabbd25122d7f37ULL, 0x70810b58105dc4b1ULL, 0xe10fdd37f7882a90ULL,
+	0x524dcab5518a3f5cULL, 0x3c9e85878451255bULL, 0x4029828119bd34e2ULL,
+	0x74a05b6f5d3ceccbULL, 0xb610021542e13ecaULL, 0x0ff979d12f59e2acULL,
+	0x6037da27e4f9cc50ULL, 0x5e92975a0df1847dULL, 0xd66de190d3e623feULL,
+	0x5032d6b87b568048ULL, 0x9a36b7ce8235216eULL, 0x80272a7a24f64b4aULL,
+	0x93efed8b8c6916f7ULL, 0x37ddbff44cce1555ULL, 0x4b95db5d4b99bd25ULL,
+	0x92d3fda169812fc0ULL, 0xfb1a4a9a90660bb6ULL, 0x730c196946a4b9b2ULL,
+	0x81e289aa7f49da68ULL, 0x64669a0f83b1a05fULL, 0x27b3ff7d9644f48bULL,
+	0xcc6b615c8db675b3ULL, 0x674f20b9bcebbe95ULL, 0x6f31238275655982ULL,
+	0x5ae488713e45cf05ULL, 0xbf619f9954c21157ULL, 0xeabac46040a8eae9ULL,
+	0x454c6fe9f2c0c1cdULL, 0x419cf6496412691cULL, 0xd3dc3bef265b0f70ULL,
+	0x6d0e60f5c3578a9eULL
+};
+
+static const u64 sbox4[256] = {
+	0x5b0e608526323c55ULL, 0x1a46c1a9fa1b59f5ULL, 0xa9e245a17c4c8ffaULL,
+	0x65ca5159db2955d7ULL, 0x05db0a76ce35afc2ULL, 0x81eac77ea9113d45ULL,
+	0x528ef88ab6ac0a0dULL, 0xa09ea253597be3ffULL, 0x430ddfb3ac48cd56ULL,
+	0xc4b3a67af45ce46fULL, 0x4ececfd8fbe2d05eULL, 0x3ef56f10b39935f0ULL,
+	0x0b22d6829cd619c6ULL, 0x17fd460a74df2069ULL, 0x6cf8cc8e8510ed40ULL,
+	0xd6c824bf3a6ecaa7ULL, 0x61243d581a817049ULL, 0x048bacb6bbc163a2ULL,
+	0xd9a38ac27d44cc32ULL, 0x7fddff5baaf410abULL, 0xad6d495aa804824bULL,
+	0xe1a6a74f2d8c9f94ULL, 0xd4f7851235dee8e3ULL, 0xfd4b7f886540d893ULL,
+	0x247c20042aa4bfdaULL, 0x096ea1c517d1327cULL, 0xd56966b4361a6685ULL,
+	0x277da5c31221057dULL, 0x94d59893a43acff7ULL, 0x64f0c51ccdc02281ULL,
+	0x3d33bcc4ff6189dbULL, 0xe005cb184ce66af1ULL, 0xff5ccd1d1db99beaULL,
+	0xb0b854a7fe42980fULL, 0x7bd46a6a718d4b9fULL, 0xd10fa8cc22a5fd8cULL,
+	0xd31484952be4bd31ULL, 0xc7fa975fcb243847ULL, 0x4886ed1e5846c407ULL,
+	0x28cddb791eb70b04ULL, 0xc2b00be2f573417fULL, 0x5c9590452180f877ULL,
+	0x7a6bddfff370eb00ULL, 0xce509e38d6d9d6a4ULL, 0xebeb0f00647fa702ULL,
+	0x1dcc06cf76606f06ULL, 0xe4d9f28ba286ff0aULL, 0xd85a305dc918c262ULL,
+	0x475b1d8732225f54ULL, 0x2d4fb51668ccb5feULL, 0xa679b9d9d72bba20ULL,
+	0x53841c0d912d43a5ULL, 0x3b7eaa48bf12a4e8ULL, 0x781e0e47f22f1ddfULL,
+	0xeff20ce60ab50973ULL, 0x20d261d19dffb742ULL, 0x16a12b03062a2e39ULL,
+	0x1960eb2239650495ULL, 0x251c16fed50eb8b8ULL, 0x9ac0c330f826016eULL,
+	0xed152665953e7671ULL, 0x02d63194a6369570ULL, 0x5074f08394b1c987ULL,
+	0x70ba598c90b25ce1ULL, 0x794a15810b9742f6ULL, 0x0d5925e9fcaf8c6cULL,
+	0x3067716cd868744eULL, 0x910ab077e8d7731bULL, 0x6a61bbdb5ac42f61ULL,
+	0x93513efbf0851567ULL, 0xf494724b9e83e9d5ULL, 0xe887e1985c09648dULL,
+	0x34b1d3c675370cfdULL, 0xdc35e433bc0d255dULL, 0xd0aab84234131be0ULL,
+	0x08042a50b48b7eafULL, 0x9997c4ee44a3ab35ULL, 0x829a7b49201799d0ULL,
+	0x263b8307b7c54441ULL, 0x752f95f4fd6a6ca6ULL, 0x927217402c08c6e5ULL,
+	0x2a8ab754a795d9eeULL, 0xa442f7552f72943dULL, 0x2c31334e19781208ULL,
+	0x4fa98d7ceaee6291ULL, 0x55c3862f665db309ULL, 0xbd0610175d53b1f3ULL,
+	0x46fe6cb840413f27ULL, 0x3fe03792df0cfa59ULL, 0xcfe700372eb85e8fULL,
+	0xa7be29e7adbce118ULL, 0xe544ee5cde8431ddULL, 0x8a781b1b41f1873eULL,
+	0xa5c94c78a0d2f0e7ULL, 0x39412e2877b60728ULL, 0xa1265ef3afc9a62cULL,
+	0xbcc2770c6a2506c5ULL, 0x3ab66dd5dce1ce12ULL, 0xe65499d04a675b37ULL,
+	0x7d8f523481bfd216ULL, 0x0f6f64fcec15f389ULL, 0x74efbe618b5b13c8ULL,
+	0xacdc82b714273e1dULL, 0xdd40bfe003199d17ULL, 0x37e99257e7e061f8ULL,
+	0xfa52626904775aaaULL, 0x8bbbf63a463d56f9ULL, 0xf0013f1543a26e64ULL,
+	0xa8307e9f879ec898ULL, 0xcc4c27a4150177ccULL, 0x1b432f2cca1d3348ULL,
+	0xde1d1f8f9f6fa013ULL, 0x606602a047a7ddd6ULL, 0xd237ab64cc1cb2c7ULL,
+	0x9b938e7225fcd1d3ULL, 0xec4e03708e0ff476ULL, 0xfeb2fbda3d03c12dULL,
+	0xae0bced2ee43889aULL, 0x22cb8923ebfb4f43ULL, 0x69360d013cf7396dULL,
+	0x855e3602d2d4e022ULL, 0x073805bad01f784cULL, 0x33e17a133852f546ULL,
+	0xdf4874058ac7b638ULL, 0xba92b29c678aa14aULL, 0x0ce89fc76cfaadcdULL,
+	0x5f9d4e0908339e34ULL, 0xf1afe9291f5923b9ULL, 0x6e3480f60f4a265fULL,
+	0xeebf3a2ab29b841cULL, 0xe21938a88f91b4adULL, 0x57dfeff845c6d3c3ULL,
+	0x2f006b0bf62caaf2ULL, 0x62f479ef6f75ee78ULL, 0x11a55ad41c8916a9ULL,
+	0xf229d29084fed453ULL, 0x42f1c27b16b000e6ULL, 0x2b1f76749823c074ULL,
+	0x4b76eca3c2745360ULL, 0x8c98f463b91691bdULL, 0x14bcc93cf1ade66aULL,
+	0x8885213e6d458397ULL, 0x8e177df0274d4711ULL, 0xb49b73b5503f2951ULL,
+	0x10168168c3f96b6bULL, 0x0e3d963b63cab0aeULL, 0x8dfc4b5655a1db14ULL,
+	0xf789f1356e14de5cULL, 0x683e68af4e51dac1ULL, 0xc9a84f9d8d4b0fd9ULL,
+	0x3691e03f52a0f9d1ULL, 0x5ed86e46e1878e80ULL, 0x3c711a0e99d07150ULL,
+	0x5a0865b20c4e9310ULL, 0x56fbfc1fe4f0682eULL, 0xea8d5de3105edf9bULL,
+	0x71abfdb12379187aULL, 0x2eb99de1bee77b9cULL, 0x21ecc0ea33cf4523ULL,
+	0x59a4d7521805c7a1ULL, 0x3896f5eb56ae7c72ULL, 0xaa638f3db18f75dcULL,
+	0x9f39358dabe9808eULL, 0xb7defa91c00b72acULL, 0x6b5541fd62492d92ULL,
+	0x6dc6dee8f92e4d5bULL, 0x353f57abc4beea7eULL, 0x735769d6da5690ceULL,
+	0x0a234aa642391484ULL, 0xf6f9508028f80d9dULL, 0xb8e319a27ab3f215ULL,
+	0x31ad9c1151341a4dULL, 0x773c22a57bef5805ULL, 0x45c7561a07968633ULL,
+	0xf913da9e249dbe36ULL, 0xda652d9b78a64c68ULL, 0x4c27a97f3bc334efULL,
+	0x76621220e66b17f4ULL, 0x967743899acd7d0bULL, 0xf3ee5bcae0ed6782ULL,
+	0x409f753600c879fcULL, 0x06d09a39b5926db6ULL, 0x6f83aeb0317ac588ULL,
+	0x01e6ca4a86381f21ULL, 0x66ff3462d19f3025ULL, 0x72207c24ddfd3bfbULL,
+	0x4af6b6d3e2ece2ebULL, 0x9c994dbec7ea08deULL, 0x49ace597b09a8bc4ULL,
+	0xb38c4766cf0797baULL, 0x131b9373c57c2a75ULL, 0xb1822cce61931e58ULL,
+	0x9d7555b909ba1c0cULL, 0x127fafdd937d11d2ULL, 0x29da3badc66d92e4ULL,
+	0xa2c1d57154c2ecbcULL, 0x58c5134d82f6fe24ULL, 0x1c3ae3515b62274fULL,
+	0xe907c82e01cb8126ULL, 0xf8ed091913e37fcbULL, 0x3249d8f9c80046c9ULL,
+	0x80cf9bede388fb63ULL, 0x1881539a116cf19eULL, 0x5103f3f76bd52457ULL,
+	0x15b7e6f5ae47f7a8ULL, 0xdbd7c6ded47e9ccfULL, 0x44e55c410228bb1aULL,
+	0xb647d4255edb4e99ULL, 0x5d11882bb8aafc30ULL, 0xf5098bbb29d3212aULL,
+	0x8fb5ea14e90296b3ULL, 0x677b942157dd025aULL, 0xfb58e7c0a390acb5ULL,
+	0x89d3674c83bd4a01ULL, 0x9e2da4df4bf3b93bULL, 0xfcc41e328cab4829ULL,
+	0x03f38c96ba582c52ULL, 0xcad1bdbd7fd85db2ULL, 0xbbb442c16082ae83ULL,
+	0xb95fe86ba5da9ab0ULL, 0xb22e04673771a93fULL, 0x845358c9493152d8ULL,
+	0xbe2a488697b4541eULL, 0x95a2dc2dd38e6966ULL, 0xc02c11ac923c852bULL,
+	0x2388b1990df2a87bULL, 0x7c8008fa1b4f37beULL, 0x1f70d0c84d54e503ULL,
+	0x5490adec7ece57d4ULL, 0x002b3c27d9063a3aULL, 0x7eaea3848030a2bfULL,
+	0xc602326ded2003c0ULL, 0x83a7287d69a94086ULL, 0xc57a5fcb30f57a8aULL,
+	0xb56844e479ebe779ULL, 0xa373b40f05dcbce9ULL, 0xd71a786e88570ee2ULL,
+	0x879cbacdbde8f6a0ULL, 0x976ad1bcc164a32fULL, 0xab21e25e9666d78bULL,
+	0x901063aae5e5c33cULL, 0x9818b34448698d90ULL, 0xe36487ae3e1e8abbULL,
+	0xafbdf931893bdcb4ULL, 0x6345a0dc5fbbd519ULL, 0x8628fe269b9465caULL,
+	0x1e5d01603f9c51ecULL, 0x4de44006a15049b7ULL, 0xbf6c70e5f776cbb1ULL,
+	0x411218f2ef552bedULL, 0xcb0c0708705a36a3ULL, 0xe74d14754f986044ULL,
+	0xcd56d9430ea8280eULL, 0xc12591d7535f5065ULL, 0xc83223f1720aef96ULL,
+	0xc3a0396f7363a51fULL
+};
+
+
+static void tgr192_round(u64 * ra, u64 * rb, u64 * rc, u64 x, int mul)
+{
+	u64 a = *ra;
+	u64 b = *rb;
+	u64 c = *rc;
+
+	c ^= x;
+	a -= sbox1[c         & 0xff] ^ sbox2[(c >> 16) & 0xff]
+	   ^ sbox3[(c >> 32) & 0xff] ^ sbox4[(c >> 48) & 0xff];
+	b += sbox4[(c >>  8) & 0xff] ^ sbox3[(c >> 24) & 0xff]
+	   ^ sbox2[(c >> 40) & 0xff] ^ sbox1[(c >> 56) & 0xff];
+	b *= mul;
+
+	*ra = a;
+	*rb = b;
+	*rc = c;
+}
+
+
+static void tgr192_pass(u64 * ra, u64 * rb, u64 * rc, u64 * x, int mul)
+{
+	u64 a = *ra;
+	u64 b = *rb;
+	u64 c = *rc;
+
+	tgr192_round(&a, &b, &c, x[0], mul);
+	tgr192_round(&b, &c, &a, x[1], mul);
+	tgr192_round(&c, &a, &b, x[2], mul);
+	tgr192_round(&a, &b, &c, x[3], mul);
+	tgr192_round(&b, &c, &a, x[4], mul);
+	tgr192_round(&c, &a, &b, x[5], mul);
+	tgr192_round(&a, &b, &c, x[6], mul);
+	tgr192_round(&b, &c, &a, x[7], mul);
+
+	*ra = a;
+	*rb = b;
+	*rc = c;
+}
+
+
+static void tgr192_key_schedule(u64 * x)
+{
+	x[0] -= x[7] ^ 0xa5a5a5a5a5a5a5a5ULL;
+	x[1] ^= x[0];
+	x[2] += x[1];
+	x[3] -= x[2] ^ ((~x[1]) << 19);
+	x[4] ^= x[3];
+	x[5] += x[4];
+	x[6] -= x[5] ^ ((~x[4]) >> 23);
+	x[7] ^= x[6];
+	x[0] += x[7];
+	x[1] -= x[0] ^ ((~x[7]) << 19);
+	x[2] ^= x[1];
+	x[3] += x[2];
+	x[4] -= x[3] ^ ((~x[2]) >> 23);
+	x[5] ^= x[4];
+	x[6] += x[5];
+	x[7] -= x[6] ^ 0x0123456789abcdefULL;
+}
+
+
+/****************
+ * Transform the message DATA which consists of 512 bytes (8 words)
+ */
+
+static void tgr192_transform(struct tgr192_ctx *tctx, const u8 * data)
+{
+	u64 a, b, c, aa, bb, cc;
+	u64 x[8];
+	int i;
+	const u8 *ptr = data;
+
+	for (i = 0; i < 8; i++, ptr += 8) {
+		x[i] = (((u64)ptr[7] ) << 56) ^
+		(((u64)ptr[6] & 0xffL) << 48) ^
+		(((u64)ptr[5] & 0xffL) << 40) ^
+		(((u64)ptr[4] & 0xffL) << 32) ^
+		(((u64)ptr[3] & 0xffL) << 24) ^
+		(((u64)ptr[2] & 0xffL) << 16) ^
+		(((u64)ptr[1] & 0xffL) <<  8) ^
+		(((u64)ptr[0] & 0xffL)      );
+	}
+
+	/* save */
+	a = aa = tctx->a;
+	b = bb = tctx->b;
+	c = cc = tctx->c;
+
+	tgr192_pass(&a, &b, &c, x, 5);
+	tgr192_key_schedule(x);
+	tgr192_pass(&c, &a, &b, x, 7);
+	tgr192_key_schedule(x);
+	tgr192_pass(&b, &c, &a, x, 9);
+
+
+	/* feedforward */
+	a ^= aa;
+	b -= bb;
+	c += cc;
+	/* store */
+	tctx->a = a;
+	tctx->b = b;
+	tctx->c = c;
+}
+
+static void tgr192_init(void *ctx)
+{
+	struct tgr192_ctx *tctx = ctx;
+
+	memset (tctx->hash, 0, 64);
+	tctx->a = 0x0123456789abcdefULL;
+	tctx->b = 0xfedcba9876543210ULL;
+	tctx->c = 0xf096a5b4c3b2e187ULL;
+	tctx->nblocks = 0;
+	tctx->count = 0;
+}
+
+
+/* Update the message digest with the contents
+ * of INBUF with length INLEN. */
+static void tgr192_update(void *ctx, const u8 * inbuf, unsigned int len)
+{
+	struct tgr192_ctx *tctx = ctx;
+
+	if (tctx->count == 64) {	/* flush the buffer */
+		tgr192_transform(tctx, tctx->hash);
+		tctx->count = 0;
+		tctx->nblocks++;
+	}
+	if (!inbuf) {
+		return;
+	}
+	if (tctx->count) {
+		for (; len && tctx->count < 64; len--) {
+			tctx->hash[tctx->count++] = *inbuf++;
+		}
+		tgr192_update(tctx, NULL, 0);
+		if (!len) {
+			return;
+		}
+
+	}
+
+	while (len >= 64) {
+		tgr192_transform(tctx, inbuf);
+		tctx->count = 0;
+		tctx->nblocks++;
+		len -= 64;
+		inbuf += 64;
+	}
+	for (; len && tctx->count < 64; len--) {
+		tctx->hash[tctx->count++] = *inbuf++;
+	}
+}
+
+
+
+/* The routine terminates the computation */
+static void tgr192_final(void *ctx, u8 * out)
+{
+	struct tgr192_ctx *tctx = ctx;
+	u32 t, msb, lsb;
+	u8 *p;
+	int i, j;
+
+	tgr192_update(tctx, NULL, 0); /* flush */ ;
+
+	msb = 0;
+	t = tctx->nblocks;
+	if ((lsb = t << 6) < t) { /* multiply by 64 to make a byte count */
+		msb++;
+	}
+	msb += t >> 26;
+	t = lsb;
+	if ((lsb = t + tctx->count) < t) {	/* add the count */
+		msb++;
+	}
+	t = lsb;
+	if ((lsb = t << 3) < t)	{ /* multiply by 8 to make a bit count */
+		msb++;
+	}
+	msb += t >> 29;
+
+	if (tctx->count < 56) {	/* enough room */
+		tctx->hash[tctx->count++] = 0x01;	/* pad */
+		while (tctx->count < 56) {
+			tctx->hash[tctx->count++] = 0;	/* pad */
+		}
+	} else {		/* need one extra block */
+		tctx->hash[tctx->count++] = 0x01;	/* pad character */
+		while (tctx->count < 64) {
+			tctx->hash[tctx->count++] = 0;
+		}
+		tgr192_update(tctx, NULL, 0); /* flush */ ;
+		memset(tctx->hash, 0, 56);    /* fill next block with zeroes */
+	}
+	/* append the 64 bit count */
+	tctx->hash[56] = lsb;
+	tctx->hash[57] = lsb >> 8;
+	tctx->hash[58] = lsb >> 16;
+	tctx->hash[59] = lsb >> 24;
+	tctx->hash[60] = msb;
+	tctx->hash[61] = msb >> 8;
+	tctx->hash[62] = msb >> 16;
+	tctx->hash[63] = msb >> 24;
+	tgr192_transform(tctx, tctx->hash);
+
+	p = tctx->hash;
+	*p++ = tctx->a >> 56; *p++ = tctx->a >> 48; *p++ = tctx->a >> 40;
+	*p++ = tctx->a >> 32; *p++ = tctx->a >> 24; *p++ = tctx->a >> 16;
+	*p++ = tctx->a >>  8; *p++ = tctx->a;\
+	*p++ = tctx->b >> 56; *p++ = tctx->b >> 48; *p++ = tctx->b >> 40;
+	*p++ = tctx->b >> 32; *p++ = tctx->b >> 24; *p++ = tctx->b >> 16;
+	*p++ = tctx->b >>  8; *p++ = tctx->b;
+	*p++ = tctx->c >> 56; *p++ = tctx->c >> 48; *p++ = tctx->c >> 40;
+	*p++ = tctx->c >> 32; *p++ = tctx->c >> 24; *p++ = tctx->c >> 16;
+	*p++ = tctx->c >>  8; *p++ = tctx->c;
+
+
+	/* unpack the hash */
+	j = 7;
+	for (i = 0; i < 8; i++) {
+		out[j--] = (tctx->a >> 8 * i) & 0xff;
+	}
+	j = 15;
+	for (i = 0; i < 8; i++) {
+		out[j--] = (tctx->b >> 8 * i) & 0xff;
+	}
+	j = 23;
+	for (i = 0; i < 8; i++) {
+		out[j--] = (tctx->c >> 8 * i) & 0xff;
+	}
+}
+
+static void tgr160_final(void *ctx, u8 * out)
+{
+	struct tgr192_ctx *wctx = ctx;
+	u8 D[64];
+
+	tgr192_final(wctx, D);
+	memcpy(out, D, TGR160_DIGEST_SIZE);
+	memset(D, 0, TGR192_DIGEST_SIZE);
+}
+
+static void tgr128_final(void *ctx, u8 * out)
+{
+	struct tgr192_ctx *wctx = ctx;
+	u8 D[64];
+
+	tgr192_final(wctx, D);
+	memcpy(out, D, TGR128_DIGEST_SIZE);
+	memset(D, 0, TGR192_DIGEST_SIZE);
+}
+
+static struct crypto_alg tgr192 = {
+	.cra_name = "tgr192",
+	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize = TGR192_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct tgr192_ctx),
+	.cra_module = THIS_MODULE,
+	.cra_list = LIST_HEAD_INIT(tgr192.cra_list),
+	.cra_u = {.digest = {
+			     .dia_digestsize = TGR192_DIGEST_SIZE,
+			     .dia_init = tgr192_init,
+			     .dia_update = tgr192_update,
+			     .dia_final = tgr192_final}}
+};
+
+static struct crypto_alg tgr160 = {
+	.cra_name = "tgr160",
+	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize = TGR192_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct tgr192_ctx),
+	.cra_module = THIS_MODULE,
+	.cra_list = LIST_HEAD_INIT(tgr160.cra_list),
+	.cra_u = {.digest = {
+			     .dia_digestsize = TGR160_DIGEST_SIZE,
+			     .dia_init = tgr192_init,
+			     .dia_update = tgr192_update,
+			     .dia_final = tgr160_final}}
+};
+
+static struct crypto_alg tgr128 = {
+	.cra_name = "tgr128",
+	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize = TGR192_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct tgr192_ctx),
+	.cra_module = THIS_MODULE,
+	.cra_list = LIST_HEAD_INIT(tgr128.cra_list),
+	.cra_u = {.digest = {
+			     .dia_digestsize = TGR128_DIGEST_SIZE,
+			     .dia_init = tgr192_init,
+			     .dia_update = tgr192_update,
+			     .dia_final = tgr128_final}}
+};
+
+static int __init init(void)
+{
+	int ret = 0;
+
+	ret = crypto_register_alg(&tgr192);
+
+	if (ret < 0) {
+		goto out;
+	}
+
+	ret = crypto_register_alg(&tgr160);
+	if (ret < 0) {
+		crypto_unregister_alg(&tgr192);
+		goto out;
+	}
+
+	ret = crypto_register_alg(&tgr128);
+	if (ret < 0) {
+		crypto_unregister_alg(&tgr192);
+		crypto_unregister_alg(&tgr160);
+	}
+      out:
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&tgr192);
+	crypto_unregister_alg(&tgr160);
+	crypto_unregister_alg(&tgr128);
+}
+
+MODULE_ALIAS("tgr160");
+MODULE_ALIAS("tgr128");
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Tiger Message Digest Algorithm");
diff --git a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -47,8 +47,8 @@ obj-$(CONFIG_PARIDE) 		+= block/paride/
 obj-$(CONFIG_TC)		+= tc/
 obj-$(CONFIG_USB)		+= usb/
 obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
-obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
+obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
@@ -61,5 +61,6 @@ obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-$(CONFIG_INFINIBAND)	+= infiniband/
+obj-$(CONFIG_BLK_DEV_SGIIOC4)	+= sn/
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
--- a/drivers/acorn/char/i2c.c
+++ b/drivers/acorn/char/i2c.c
@@ -313,7 +313,7 @@ static struct i2c_algo_bit_data ioc_data
 
 static int ioc_client_reg(struct i2c_client *client)
 {
-	if (client->id == I2C_DRIVERID_PCF8583 &&
+	if (client->driver->id == I2C_DRIVERID_PCF8583 &&
 	    client->addr == 0x50) {
 		struct rtc_tm rtctm;
 		unsigned int year;
diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c
--- a/drivers/acorn/char/pcf8583.c
+++ b/drivers/acorn/char/pcf8583.c
@@ -51,7 +51,6 @@ pcf8583_attach(struct i2c_adapter *adap,
 		return -ENOMEM;
 
 	memset(c, 0, sizeof(*c));
-	c->id		= pcf8583_driver.id;
 	c->addr		= addr;
 	c->adapter	= adap;
 	c->driver	= &pcf8583_driver;
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -40,21 +40,22 @@ config ACPI
 	  available at:
 	  <http://www.acpi.info>
 
+if ACPI
+
 config ACPI_BOOT
 	bool
-	depends on ACPI || X86_HT
 	default y
 
 config ACPI_INTERPRETER
 	bool
-	depends on ACPI
 	depends on !IA64_SGI_SN
 	default y
 
+if ACPI_INTERPRETER
+
 config ACPI_SLEEP
 	bool "Sleep States (EXPERIMENTAL)"
-	depends on X86 && ACPI
-	depends on ACPI_INTERPRETER
+	depends on X86
 	depends on EXPERIMENTAL && PM
 	default y
 	---help---
@@ -81,7 +82,6 @@ config ACPI_SLEEP_PROC_FS
 config ACPI_AC
 	tristate "AC Adapter"
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default m
 	help
 	  This driver adds support for the AC Adapter object, which indicates
@@ -91,7 +91,6 @@ config ACPI_AC
 config ACPI_BATTERY
 	tristate "Battery"
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default m
 	help
 	  This driver adds support for battery information through
@@ -100,7 +99,6 @@ config ACPI_BATTERY
 
 config ACPI_BUTTON
 	tristate "Button"
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default m
 	help
@@ -112,7 +110,6 @@ config ACPI_BUTTON
 
 config ACPI_VIDEO
 	tristate "Video"
-	depends on ACPI_INTERPRETER
 	depends on EXPERIMENTAL
 	depends on !IA64_SGI_SN
 	default m
@@ -127,7 +124,6 @@ config ACPI_VIDEO
 
 config ACPI_FAN
 	tristate "Fan"
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default m
 	help
@@ -136,7 +132,6 @@ config ACPI_FAN
 
 config ACPI_PROCESSOR
 	tristate "Processor"
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default m
 	help
@@ -165,7 +160,6 @@ config ACPI_THERMAL
 
 config ACPI_NUMA
 	bool "NUMA support"
-	depends on ACPI_INTERPRETER
 	depends on NUMA
 	depends on (IA64 || X86_64)
 	default y if IA64_GENERIC || IA64_SGI_SN2
@@ -173,7 +167,6 @@ config ACPI_NUMA
 config ACPI_ASUS
         tristate "ASUS/Medion Laptop Extras"
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default m
         ---help---
           This driver provides support for extra features of ACPI-compatible
@@ -203,7 +196,6 @@ config ACPI_ASUS
 config ACPI_IBM
 	tristate "IBM ThinkPad Laptop Extras"
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default m
 	---help---
 	  This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
@@ -217,7 +209,6 @@ config ACPI_IBM
 config ACPI_TOSHIBA
 	tristate "Toshiba Laptop Extras"
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default m
 	---help---
 	  This driver adds support for access to certain system settings
@@ -244,7 +235,7 @@ config ACPI_TOSHIBA
 
 config ACPI_CUSTOM_DSDT
 	bool "Include Custom DSDT"
-	depends on ACPI_INTERPRETER && !STANDALONE
+	depends on !STANDALONE
 	default n 
 	help
 	  Thist option is to load a custom ACPI DSDT
@@ -271,7 +262,6 @@ config ACPI_BLACKLIST_YEAR
 
 config ACPI_DEBUG
 	bool "Debug Statements"
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default n
 	help
@@ -281,14 +271,12 @@ config ACPI_DEBUG
 
 config ACPI_BUS
 	bool
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default y
 
 config ACPI_EC
 	bool
 	depends on X86
-	depends on ACPI_INTERPRETER
 	default y
 	help
 	  This driver is required on some systems for the proper operation of
@@ -297,28 +285,27 @@ config ACPI_EC
 
 config ACPI_POWER
 	bool
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default y
 
 config ACPI_PCI
 	bool
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default PCI
 
 config ACPI_SYSTEM
 	bool
-	depends on ACPI_INTERPRETER
 	depends on !IA64_SGI_SN
 	default y
 	help
 	  This driver will enable your system to shut down using ACPI, and
 	  dump your ACPI DSDT table using /proc/acpi/dsdt.
 
+endif	# ACPI_INTERPRETER
+
 config X86_PM_TIMER
 	bool "Power Management Timer Support"
-	depends on X86 && ACPI
+	depends on X86
 	depends on ACPI_BOOT && EXPERIMENTAL
 	depends on !X86_64
 	default n
@@ -337,10 +324,32 @@ config X86_PM_TIMER
 
 config ACPI_CONTAINER
 	tristate "ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)"
-	depends on ACPI && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
 	 ---help---
 	 	This is the ACPI generic container driver which supports
 		ACPI0004, PNP0A05 and PNP0A06 devices
 
+config ACPI_HOTPLUG_MEMORY
+	tristate "Memory Hotplug"
+	depends on ACPI
+	depends on MEMORY_HOTPLUG
+	default n
+	help
+	  This driver adds supports for ACPI Memory Hotplug.  This driver
+	  provides support for fielding notifications on ACPI memory
+	  devices (PNP0C80) which represent memory ranges that may be
+	  onlined or offlined during runtime.  
+
+	  Enabling this driver assumes that your platform hardware
+	  and firmware have support for hot-plugging physical memory. If
+	  your system does not support physically adding or ripping out 
+	  memory DIMMs at some platfrom defined granularity (individually 
+	  or as a bank) at runtime, then you need not enable this driver.
+
+	  If one selects "m," this driver can be loaded using the following
+	  command: 
+		$>modprobe acpi_memhotplug 
+endif	# ACPI
+
 endmenu
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_ACPI_IBM)		+= ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 obj-$(CONFIG_ACPI_BUS)		+= scan.o motherboard.o
+obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)	+= acpi_memhotplug.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -51,8 +51,8 @@ MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-int acpi_ac_add (struct acpi_device *device);
-int acpi_ac_remove (struct acpi_device *device, int type);
+static int acpi_ac_add (struct acpi_device *device);
+static int acpi_ac_remove (struct acpi_device *device, int type);
 static int acpi_ac_open_fs(struct inode *inode, struct file *file);
 
 static struct acpi_driver acpi_ac_driver = {
@@ -108,9 +108,9 @@ acpi_ac_get_state (
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_ac_dir;
+static struct proc_dir_entry	*acpi_ac_dir;
 
-int acpi_ac_seq_show(struct seq_file *seq, void *offset)
+static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
 {
 	struct acpi_ac		*ac = (struct acpi_ac *) seq->private;
 
@@ -200,7 +200,7 @@ acpi_ac_remove_fs (
                                    Driver Model
    -------------------------------------------------------------------------- */
 
-void
+static void
 acpi_ac_notify (
 	acpi_handle		handle,
 	u32			event,
@@ -232,7 +232,7 @@ acpi_ac_notify (
 }
 
 
-int
+static int
 acpi_ac_add (
 	struct acpi_device	*device)
 {
@@ -286,7 +286,7 @@ end:
 }
 
 
-int
+static int
 acpi_ac_remove (
 	struct acpi_device	*device,
 	int			type)
@@ -315,7 +315,7 @@ acpi_ac_remove (
 }
 
 
-int __init
+static int __init
 acpi_ac_init (void)
 {
 	int			result = 0;
@@ -337,7 +337,7 @@ acpi_ac_init (void)
 }
 
 
-void __exit
+static void __exit
 acpi_ac_exit (void)
 {
 	ACPI_FUNCTION_TRACE("acpi_ac_exit");
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
new file mode 100644
--- /dev/null
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
+ *
+ * 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.
+ *
+ *
+ * ACPI based HotPlug driver that supports Memory Hotplug
+ * This driver fields notifications from firmare for memory add
+ * and remove operations and alerts the VM of the affected memory
+ * ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/memory_hotplug.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_MEMORY_DEVICE_COMPONENT		0x08000000UL
+#define ACPI_MEMORY_DEVICE_CLASS		"memory"
+#define ACPI_MEMORY_DEVICE_HID			"PNP0C80"
+#define ACPI_MEMORY_DEVICE_DRIVER_NAME		"Hotplug Mem Driver"
+#define ACPI_MEMORY_DEVICE_NAME			"Hotplug Mem Device"
+
+#define _COMPONENT		ACPI_MEMORY_DEVICE_COMPONENT
+
+ACPI_MODULE_NAME		("acpi_memory")
+MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
+MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+/* ACPI _STA method values */
+#define ACPI_MEMORY_STA_PRESENT		(0x00000001UL)
+#define ACPI_MEMORY_STA_ENABLED		(0x00000002UL)
+#define ACPI_MEMORY_STA_FUNCTIONAL	(0x00000008UL)
+
+/* Memory Device States */
+#define MEMORY_INVALID_STATE	0
+#define MEMORY_POWER_ON_STATE	1
+#define MEMORY_POWER_OFF_STATE	2
+
+static int acpi_memory_device_add (struct acpi_device *device);
+static int acpi_memory_device_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_memory_device_driver = {
+	.name =		ACPI_MEMORY_DEVICE_DRIVER_NAME,
+	.class =	ACPI_MEMORY_DEVICE_CLASS,
+	.ids =		ACPI_MEMORY_DEVICE_HID,
+	.ops =		{
+				.add =		acpi_memory_device_add,
+				.remove =	acpi_memory_device_remove,
+			},
+};
+
+struct acpi_memory_device {
+	acpi_handle handle;
+	unsigned int state;		/* State of the memory device */
+	unsigned short cache_attribute;	/* memory cache attribute */
+	unsigned short read_write_attribute;/* memory read/write attribute */
+	u64 start_addr;	/* Memory Range start physical addr */
+	u64 end_addr;	/* Memory Range end physical addr */
+};
+
+
+static int
+acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_resource *resource = NULL;
+	struct acpi_resource_address64 address64;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
+
+	/* Get the range from the _CRS */
+	status = acpi_get_current_resources(mem_device->handle, &buffer);
+	if (ACPI_FAILURE(status))
+		return_VALUE(-EINVAL);
+
+	resource = (struct acpi_resource *) buffer.pointer;
+	status = acpi_resource_to_address64(resource, &address64);
+	if (ACPI_SUCCESS(status)) {
+		if (address64.resource_type == ACPI_MEMORY_RANGE) {
+			/* Populate the structure */
+			mem_device->cache_attribute =
+				address64.attribute.memory.cache_attribute;
+			mem_device->read_write_attribute =
+			address64.attribute.memory.read_write_attribute;
+			mem_device->start_addr = address64.min_address_range;
+			mem_device->end_addr = address64.max_address_range;
+		}
+	}
+
+	acpi_os_free(buffer.pointer);
+	return_VALUE(0);
+}
+
+static int
+acpi_memory_get_device(acpi_handle handle,
+	struct acpi_memory_device **mem_device)
+{
+	acpi_status status;
+	acpi_handle phandle;
+	struct acpi_device *device = NULL;
+	struct acpi_device *pdevice = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_get_device");
+
+	if (!acpi_bus_get_device(handle, &device) && device)
+		goto end;
+
+	status = acpi_get_parent(handle, &phandle);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Error in acpi_get_parent\n"));
+		return_VALUE(-EINVAL);
+	}
+
+	/* Get the parent device */
+	status = acpi_bus_get_device(phandle, &pdevice);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Error in acpi_bus_get_device\n"));
+		return_VALUE(-EINVAL);
+	}
+
+	/*
+	 * Now add the notified device.  This creates the acpi_device
+	 * and invokes .add function
+	 */
+	status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Error in acpi_bus_add\n"));
+		return_VALUE(-EINVAL);
+	}
+
+end:
+	*mem_device = acpi_driver_data(device);
+	if (!(*mem_device)) {
+		printk(KERN_ERR "\n driver data not found" );
+		return_VALUE(-ENODEV);
+	}
+
+	return_VALUE(0);
+}
+
+static int
+acpi_memory_check_device(struct acpi_memory_device *mem_device)
+{
+	unsigned long current_status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_check_device");
+
+	/* Get device present/absent information from the _STA */
+	if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->handle, "_STA",
+		NULL, &current_status)))
+		return_VALUE(-ENODEV);
+	/*
+	 * Check for device status. Device should be
+	 * present/enabled/functioning.
+	 */
+	if (!((current_status & ACPI_MEMORY_STA_PRESENT)
+		&& (current_status & ACPI_MEMORY_STA_ENABLED)
+		&& (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+		return_VALUE(-ENODEV);
+
+	return_VALUE(0);
+}
+
+static int
+acpi_memory_enable_device(struct acpi_memory_device *mem_device)
+{
+	int result;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
+
+	/* Get the range from the _CRS */
+	result = acpi_memory_get_device_resources(mem_device);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"\nget_device_resources failed\n"));
+		mem_device->state = MEMORY_INVALID_STATE;
+		return result;
+	}
+
+	/*
+	 * Tell the VM there is more memory here...
+	 * Note: Assume that this function returns zero on success
+	 */
+	result = add_memory(mem_device->start_addr,
+			(mem_device->end_addr - mem_device->start_addr) + 1,
+			mem_device->read_write_attribute);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"\nadd_memory failed\n"));
+		mem_device->state = MEMORY_INVALID_STATE;
+		return result;
+	}
+
+	return result;
+}
+
+static int
+acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
+{
+	acpi_status status;
+	struct acpi_object_list	arg_list;
+	union acpi_object arg;
+	unsigned long current_status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_powerdown_device");
+
+	/* Issue the _EJ0 command */
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = 1;
+	status = acpi_evaluate_object(mem_device->handle,
+			"_EJ0", &arg_list, NULL);
+	/* Return on _EJ0 failure */
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"_EJ0 failed.\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	/* Evalute _STA to check if the device is disabled */
+	status = acpi_evaluate_integer(mem_device->handle, "_STA",
+		NULL, &current_status);
+	if (ACPI_FAILURE(status))
+		return_VALUE(-ENODEV);
+
+	/* Check for device status.  Device should be disabled */
+	if (current_status & ACPI_MEMORY_STA_ENABLED)
+		return_VALUE(-EINVAL);
+
+	return_VALUE(0);
+}
+
+static int
+acpi_memory_disable_device(struct acpi_memory_device *mem_device)
+{
+	int result;
+	u64 start = mem_device->start_addr;
+	u64 len = mem_device->end_addr - start + 1;
+	unsigned long attr = mem_device->read_write_attribute;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
+
+	/*
+	 * Ask the VM to offline this memory range.
+	 * Note: Assume that this function returns zero on success
+	 */
+	result = remove_memory(start, len, attr);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
+		return_VALUE(result);
+	}
+
+	/* Power-off and eject the device */
+	result = acpi_memory_powerdown_device(mem_device);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					"Device Power Down failed.\n"));
+		/* Set the status of the device to invalid */
+		mem_device->state = MEMORY_INVALID_STATE;
+		return result;
+	}
+
+	mem_device->state = MEMORY_POWER_OFF_STATE;
+	return result;
+}
+
+static void
+acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct acpi_memory_device *mem_device;
+	struct acpi_device *device;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_notify");
+
+	switch (event) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"\nReceived BUS CHECK notification for device\n"));
+		/* Fall Through */
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		if (event == ACPI_NOTIFY_DEVICE_CHECK)
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"\nReceived DEVICE CHECK notification for device\n"));
+		if (acpi_memory_get_device(handle, &mem_device)) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error in finding driver data\n"));
+			return_VOID;
+		}
+
+		if (!acpi_memory_check_device(mem_device)) {
+			if (acpi_memory_enable_device(mem_device))
+				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error in acpi_memory_enable_device\n"));
+		}
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"\nReceived EJECT REQUEST notification for device\n"));
+
+		if (acpi_bus_get_device(handle, &device)) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					"Device doesn't exist\n"));
+			break;
+		}
+		mem_device = acpi_driver_data(device);
+		if (!mem_device) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					"Driver Data is NULL\n"));
+			break;
+		}
+
+		/*
+		 * Currently disabling memory device from kernel mode
+		 * TBD: Can also be disabled from user mode scripts
+		 * TBD: Can also be disabled by Callback registration
+		 * 	with generic sysfs driver
+		 */
+		if (acpi_memory_disable_device(mem_device))
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error in acpi_memory_disable_device\n"));
+		/*
+		 * TBD: Invoke acpi_bus_remove to cleanup data structures
+		 */
+		break;
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"Unsupported event [0x%x]\n", event));
+		break;
+	}
+
+	return_VOID;
+}
+
+static int
+acpi_memory_device_add(struct acpi_device *device)
+{
+	int result;
+	struct acpi_memory_device *mem_device = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_add");
+
+	if (!device)
+		return_VALUE(-EINVAL);
+
+	mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
+	if (!mem_device)
+		return_VALUE(-ENOMEM);
+	memset(mem_device, 0, sizeof(struct acpi_memory_device));
+
+	mem_device->handle = device->handle;
+	sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
+	sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
+	acpi_driver_data(device) = mem_device;
+
+	/* Get the range from the _CRS */
+	result = acpi_memory_get_device_resources(mem_device);
+	if (result) {
+		kfree(mem_device);
+		return_VALUE(result);
+	}
+
+	/* Set the device state */
+	mem_device->state = MEMORY_POWER_ON_STATE;
+
+	printk(KERN_INFO "%s \n", acpi_device_name(device));
+
+	return_VALUE(result);
+}
+
+static int
+acpi_memory_device_remove (struct acpi_device *device, int type)
+{
+	struct acpi_memory_device *mem_device = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_remove");
+
+	if (!device || !acpi_driver_data(device))
+		return_VALUE(-EINVAL);
+
+	mem_device = (struct acpi_memory_device *) acpi_driver_data(device);
+	kfree(mem_device);
+
+	return_VALUE(0);
+}
+
+/*
+ * Helper function to check for memory device
+ */
+static acpi_status
+is_memory_device(acpi_handle handle)
+{
+	char *hardware_id;
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_device_info *info;
+
+	ACPI_FUNCTION_TRACE("is_memory_device");
+
+	status = acpi_get_object_info(handle, &buffer);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(AE_ERROR);
+
+	info = buffer.pointer;
+	if (!(info->valid & ACPI_VALID_HID)) {
+		acpi_os_free(buffer.pointer);
+		return_ACPI_STATUS(AE_ERROR);
+	}
+
+	hardware_id = info->hardware_id.value;
+	if ((hardware_id == NULL) ||
+		(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
+		status = AE_ERROR;
+
+	acpi_os_free(buffer.pointer);
+	return_ACPI_STATUS(status);
+}
+
+static acpi_status
+acpi_memory_register_notify_handler (acpi_handle handle,
+	u32 level, void *ctxt, void **retv)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_register_notify_handler");
+
+	status = is_memory_device(handle);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(AE_OK);	/* continue */
+
+	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+			acpi_memory_device_notify, NULL);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Error installing notify handler\n"));
+		return_ACPI_STATUS(AE_OK);	/* continue */
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+static acpi_status
+acpi_memory_deregister_notify_handler (acpi_handle handle,
+			       u32 level, void *ctxt, void **retv)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_deregister_notify_handler");
+
+	status = is_memory_device(handle);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(AE_OK);	/* continue */
+
+	status = acpi_remove_notify_handler(handle,
+			ACPI_SYSTEM_NOTIFY, acpi_memory_device_notify);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error removing notify handler\n"));
+		return_ACPI_STATUS(AE_OK);	/* continue */
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+static int __init
+acpi_memory_device_init (void)
+{
+	int result;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_init");
+
+	result = acpi_bus_register_driver(&acpi_memory_device_driver);
+
+	if (result < 0)
+		return_VALUE(-ENODEV);
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				ACPI_UINT32_MAX,
+				acpi_memory_register_notify_handler,
+				NULL, NULL);
+
+	if (ACPI_FAILURE (status)) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
+		acpi_bus_unregister_driver(&acpi_memory_device_driver);
+		return_VALUE(-ENODEV);
+        }
+
+	return_VALUE(0);
+}
+
+static void __exit
+acpi_memory_device_exit (void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_exit");
+
+	/*
+	 * Adding this to un-install notification handlers for all the device
+	 * handles.
+	 */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+			ACPI_UINT32_MAX,
+			acpi_memory_deregister_notify_handler,
+			NULL, NULL);
+
+	if (ACPI_FAILURE (status))
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
+
+	acpi_bus_unregister_driver(&acpi_memory_device_driver);
+
+	return_VOID;
+}
+
+module_init(acpi_memory_device_init);
+module_exit(acpi_memory_device_exit);
+
+
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -341,7 +341,7 @@ acpi_battery_check (
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_battery_dir;
+static struct proc_dir_entry	*acpi_battery_dir;
 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 {
 	int			result = 0;
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -275,7 +275,7 @@ acpi_button_remove_fs (
                                 Driver Interface
    -------------------------------------------------------------------------- */
 
-void
+static void
 acpi_button_notify (
 	acpi_handle		handle,
 	u32			event,
@@ -302,7 +302,7 @@ acpi_button_notify (
 }
 
 
-acpi_status
+static acpi_status
 acpi_button_notify_fixed (
 	void			*data)
 {
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -177,13 +177,18 @@ container_notify_cb(acpi_handle handle, 
 		printk("Container driver received %s event\n",
 			(type == ACPI_NOTIFY_BUS_CHECK)?
 			"ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK");
+		status = acpi_bus_get_device(handle, &device);
 		if (present) {
-			status = acpi_bus_get_device(handle, &device);
 			if (ACPI_FAILURE(status) || !device) {
 				result = container_device_add(&device, handle);
 				if (!result)
-					kobject_hotplug(&device->kobj, KOBJ_ONLINE);
-			} else {
+					kobject_hotplug(&device->kobj,
+							KOBJ_ONLINE);
+				else
+					printk("Failed to add container\n");
+			}
+		} else {
+			if (ACPI_SUCCESS(status)) {
 				/* device exist and this is a remove request */
 				kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
 			}
@@ -255,7 +260,7 @@ end:
 }
 
 
-int __init
+static int __init
 acpi_container_init(void)
 {
 	int	result = 0;
@@ -276,7 +281,7 @@ acpi_container_init(void)
 	return(0);
 }
 
-void __exit
+static void __exit
 acpi_container_exit(void)
 {
 	int			action = UNINSTALL_NOTIFY_HANDLER;
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -35,7 +35,7 @@ struct acpi_dlevel {
 };
 #define ACPI_DEBUG_INIT(v)	{ .name = #v, .value = v }
 
-const struct acpi_dlayer acpi_debug_layers[] =
+static const struct acpi_dlayer acpi_debug_layers[] =
 {
 	ACPI_DEBUG_INIT(ACPI_UTILITIES),
 	ACPI_DEBUG_INIT(ACPI_HARDWARE),
@@ -53,7 +53,7 @@ const struct acpi_dlayer acpi_debug_laye
 	ACPI_DEBUG_INIT(ACPI_TOOLS),
 };
 
-const struct acpi_dlevel acpi_debug_levels[] =
+static const struct acpi_dlevel acpi_debug_levels[] =
 {
 	ACPI_DEBUG_INIT(ACPI_LV_ERROR),
 	ACPI_DEBUG_INIT(ACPI_LV_WARN),
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -448,7 +448,16 @@ acpi_ds_restart_control_method (
 			 */
 			walk_state->return_desc = return_desc;
 		}
-		else {
+
+		/*
+		 * The following code is the
+		 * optional support for a so-called "implicit return". Some AML code
+		 * assumes that the last value of the method is "implicitly" returned
+		 * to the caller. Just save the last result as the return value.
+		 * NOTE: this is optional because the ASL language does not actually
+		 * support this behavior.
+		 */
+		else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) {
 			/*
 			 * Delete the return value if it will not be used by the
 			 * calling method
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -1010,6 +1010,10 @@ acpi_ds_exec_end_control_op (
 		 * has been bubbled up the tree
 		 */
 		if (op->common.value.arg) {
+			/* Since we have a real Return(), delete any implicit return */
+
+			acpi_ds_clear_implicit_return (walk_state);
+
 			/* Return statement has an immediate operand */
 
 			status = acpi_ds_create_operands (walk_state, op->common.value.arg);
@@ -1036,6 +1040,10 @@ acpi_ds_exec_end_control_op (
 		}
 		else if ((walk_state->results) &&
 				 (walk_state->results->results.num_results > 0)) {
+			/* Since we have a real Return(), delete any implicit return */
+
+			acpi_ds_clear_implicit_return (walk_state);
+
 			/*
 			 * The return value has come from a previous calculation.
 			 *
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -54,10 +54,120 @@
 	 ACPI_MODULE_NAME    ("dsutils")
 
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_clear_implicit_return
+ *
+ * PARAMETERS:  walk_state          - Current State
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Clear and remove a reference on an implicit return value.  Used
+ *              to delete "stale" return values (if enabled, the return value
+ *              from every operator is saved at least momentarily, in case the
+ *              parent method exits.)
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_clear_implicit_return (
+	struct acpi_walk_state          *walk_state)
+{
+	ACPI_FUNCTION_NAME ("ds_clear_implicit_return");
+
+
+	/*
+	 * Slack must be enabled for this feature
+	 */
+	if (!acpi_gbl_enable_interpreter_slack) {
+		return;
+	}
+
+	if (walk_state->implicit_return_obj) {
+		/*
+		 * Delete any "stale" implicit return. However, in
+		 * complex statements, the implicit return value can be
+		 * bubbled up several levels.
+		 */
+		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+			"Removing reference on stale implicit return obj %p\n",
+			walk_state->implicit_return_obj));
+
+		acpi_ut_remove_reference (walk_state->implicit_return_obj);
+		walk_state->implicit_return_obj = NULL;
+	}
+}
+
+
 #ifndef ACPI_NO_METHOD_EXECUTION
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ds_do_implicit_return
+ *
+ * PARAMETERS:  return_desc         - The return value
+ *              walk_state          - Current State
+ *              add_reference       - True if a reference should be added to the
+ *                                    return object
+ *
+ * RETURN:      TRUE if implicit return enabled, FALSE otherwise
+ *
+ * DESCRIPTION: Implements the optional "implicit return".  We save the result
+ *              of every ASL operator and control method invocation in case the
+ *              parent method exit.  Before storing a new return value, we
+ *              delete the previous return value.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_do_implicit_return (
+	union acpi_operand_object       *return_desc,
+	struct acpi_walk_state          *walk_state,
+	u8                              add_reference)
+{
+	ACPI_FUNCTION_NAME ("ds_do_implicit_return");
+
+
+	/*
+	 * Slack must be enabled for this feature, and we must
+	 * have a valid return object
+	 */
+	if ((!acpi_gbl_enable_interpreter_slack) ||
+		(!return_desc)) {
+		return (FALSE);
+	}
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+			"Result %p will be implicitly returned; Prev=%p\n",
+			return_desc,
+			walk_state->implicit_return_obj));
+
+	/*
+	 * Delete any "stale" implicit return value first. However, in
+	 * complex statements, the implicit return value can be
+	 * bubbled up several levels, so we don't clear the value if it
+	 * is the same as the return_desc.
+	 */
+	if (walk_state->implicit_return_obj) {
+		if (walk_state->implicit_return_obj == return_desc) {
+			return (TRUE);
+		}
+		acpi_ds_clear_implicit_return (walk_state);
+	}
+
+	/* Save the implicit return value, add a reference if requested */
+
+	walk_state->implicit_return_obj = return_desc;
+	if (add_reference) {
+		acpi_ut_add_reference (return_desc);
+	}
+
+	return (TRUE);
+}
+
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ds_is_result_used
  *
  * PARAMETERS:  Op                  - Current Op
@@ -76,7 +186,6 @@ acpi_ds_is_result_used (
 {
 	const struct acpi_opcode_info   *parent_info;
 
-
 	ACPI_FUNCTION_TRACE_PTR ("ds_is_result_used", op);
 
 
@@ -88,6 +197,19 @@ acpi_ds_is_result_used (
 	}
 
 	/*
+	 * We know that this operator is not a
+	 * Return() operator (would not come here.) The following code is the
+	 * optional support for a so-called "implicit return". Some AML code
+	 * assumes that the last value of the method is "implicitly" returned
+	 * to the caller. Just save the last result as the return value.
+	 * NOTE: this is optional because the ASL language does not actually
+	 * support this behavior.
+	 */
+	acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE);
+
+	/*
+	 * Now determine if the parent will use the result
+	 *
 	 * If there is no parent, or the parent is a scope_op, we are executing
 	 * at the method level. An executing method typically has no parent,
 	 * since each method is parsed separately.  A method invoked externally
@@ -95,29 +217,10 @@ acpi_ds_is_result_used (
 	 */
 	if ((!op->common.parent) ||
 		(op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
-		/*
-		 * If this is the last statement in the method, we know it is not a
-		 * Return() operator (would not come here.) The following code is the
-		 * optional support for a so-called "implicit return". Some AML code
-		 * assumes that the last value of the method is "implicitly" returned
-		 * to the caller. Just save the last result as the return value.
-		 * NOTE: this is optional because the ASL language does not actually
-		 * support this behavior.
-		 */
-		if ((acpi_gbl_enable_interpreter_slack) &&
-			(walk_state->parser_state.aml >= walk_state->parser_state.aml_end)) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
-					"Result of [%s] will be implicitly returned\n",
-					acpi_ps_get_opcode_name (op->common.aml_opcode)));
-
-			/* Use the top of the result stack as the implicit return value */
-
-			walk_state->return_desc = walk_state->results->results.obj_desc[0];
-			return_VALUE (TRUE);
-		}
-
 		/* No parent, the return value cannot possibly be used */
 
+		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n",
+				acpi_ps_get_opcode_name (op->common.aml_opcode)));
 		return_VALUE (FALSE);
 	}
 
@@ -262,9 +365,8 @@ acpi_ds_delete_result_if_not_used (
 	}
 
 	if (!acpi_ds_is_result_used (op, walk_state)) {
-		/*
-		 * Must pop the result stack (obj_desc should be equal to result_obj)
-		 */
+		/* Must pop the result stack (obj_desc should be equal to result_obj) */
+
 		status = acpi_ds_result_pop (&obj_desc, walk_state);
 		if (ACPI_SUCCESS (status)) {
 			acpi_ut_remove_reference (result_obj);
@@ -338,9 +440,8 @@ acpi_ds_clear_operands (
 	ACPI_FUNCTION_TRACE_PTR ("ds_clear_operands", walk_state);
 
 
-	/*
-	 * Remove a reference on each operand on the stack
-	 */
+	/* Remove a reference on each operand on the stack */
+
 	for (i = 0; i < walk_state->num_operands; i++) {
 		/*
 		 * Remove a reference to all operands, including both
@@ -407,11 +508,7 @@ acpi_ds_create_operand (
 			return_ACPI_STATUS (status);
 		}
 
-		/*
-		 * All prefixes have been handled, and the name is
-		 * in name_string
-		 */
-
+		/* All prefixes have been handled, and the name is in name_string */
 
 		/*
 		 * Special handling for buffer_field declarations. This is a deferred
@@ -586,7 +683,8 @@ acpi_ds_create_operand (
  *
  * FUNCTION:    acpi_ds_create_operands
  *
- * PARAMETERS:  first_arg           - First argument of a parser argument tree
+ * PARAMETERS:  walk_state          - Current state
+ *              first_arg           - First argument of a parser argument tree
  *
  * RETURN:      Status
  *
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -91,6 +91,7 @@ acpi_ds_get_predicate_value (
 	union acpi_operand_object       *result_obj) {
 	acpi_status                     status = AE_OK;
 	union acpi_operand_object       *obj_desc;
+	union acpi_operand_object       *local_obj_desc = NULL;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("ds_get_predicate_value", walk_state);
@@ -130,12 +131,17 @@ acpi_ds_get_predicate_value (
 	}
 
 	/*
-	 * Result of predicate evaluation currently must
-	 * be a number
+	 * Result of predicate evaluation must be an Integer
+	 * object. Implicitly convert the argument if necessary.
 	 */
-	if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_INTEGER) {
+	status = acpi_ex_convert_to_integer (obj_desc, &local_obj_desc, 16);
+	if (ACPI_FAILURE (status)) {
+		goto cleanup;
+	}
+
+	if (ACPI_GET_OBJECT_TYPE (local_obj_desc) != ACPI_TYPE_INTEGER) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-			"Bad predicate (not a number) obj_desc=%p State=%p Type=%X\n",
+			"Bad predicate (not an integer) obj_desc=%p State=%p Type=%X\n",
 			obj_desc, walk_state, ACPI_GET_OBJECT_TYPE (obj_desc)));
 
 		status = AE_AML_OPERAND_TYPE;
@@ -144,13 +150,13 @@ acpi_ds_get_predicate_value (
 
 	/* Truncate the predicate to 32-bits if necessary */
 
-	acpi_ex_truncate_for32bit_table (obj_desc);
+	acpi_ex_truncate_for32bit_table (local_obj_desc);
 
 	/*
 	 * Save the result of the predicate evaluation on
 	 * the control stack
 	 */
-	if (obj_desc->integer.value) {
+	if (local_obj_desc->integer.value) {
 		walk_state->control_state->common.value = TRUE;
 	}
 	else {
@@ -170,12 +176,15 @@ cleanup:
 
 	 /* Break to debugger to display result */
 
-	ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (obj_desc, walk_state));
+	ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (local_obj_desc, walk_state));
 
 	/*
 	 * Delete the predicate result object (we know that
 	 * we don't need it anymore)
 	 */
+	if (local_obj_desc != obj_desc) {
+		acpi_ut_remove_reference (local_obj_desc);
+	}
 	acpi_ut_remove_reference (obj_desc);
 
 	walk_state->control_state->common.state = ACPI_CONTROL_NORMAL;
@@ -306,9 +315,10 @@ acpi_ds_exec_begin_op (
 	case AML_CLASS_EXECUTE:
 	case AML_CLASS_CREATE:
 
-		/* most operators with arguments */
-		/* Start a new result/operand state */
-
+		/*
+		 * Most operators with arguments.
+		 * Start a new result/operand state
+		 */
 		status = acpi_ds_result_stack_push (walk_state);
 		break;
 
@@ -471,20 +481,41 @@ acpi_ds_exec_end_op (
 			/* 1 Operand, 0 external_result, 0 internal_result */
 
 			status = acpi_ds_exec_end_control_op (walk_state, op);
-			if (ACPI_FAILURE (status)) {
-				break;
-			}
 
-			status = acpi_ds_result_stack_pop (walk_state);
+			/* Make sure to properly pop the result stack */
+
+			if (ACPI_SUCCESS (status)) {
+				status = acpi_ds_result_stack_pop (walk_state);
+			}
+			else if (status == AE_CTRL_PENDING) {
+				status = acpi_ds_result_stack_pop (walk_state);
+				if (ACPI_SUCCESS (status)) {
+					status = AE_CTRL_PENDING;
+				}
+			}
 			break;
 
 
 		case AML_TYPE_METHOD_CALL:
 
+			/*
+			 * If the method is referenced from within a package
+			 * declaration, it is not a invocation of the method, just
+			 * a reference to it.
+			 */
+			if ((op->asl.parent) &&
+			   ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) ||
+				(op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op));
+				op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object;
+				acpi_ut_add_reference (op->asl.value.arg->asl.node->object);
+				return_ACPI_STATUS (AE_OK);
+			}
+
 			ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method invocation, Op=%p\n", op));
 
 			/*
-			 * (AML_METHODCALL) Op->Value->Arg->Node contains
+			 * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains
 			 * the method Node pointer
 			 */
 			/* next_op points to the op that holds the method name */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -514,7 +514,7 @@ out:
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_ec_dir;
+static struct proc_dir_entry	*acpi_ec_dir;
 
 
 static int
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -149,7 +149,9 @@ acpi_install_fixed_event_handler (
 	acpi_gbl_fixed_event_handlers[event].handler = handler;
 	acpi_gbl_fixed_event_handlers[event].context = context;
 
-	status = acpi_enable_event (event, 0);
+	status = acpi_clear_event (event);
+	if (ACPI_SUCCESS(status))
+		status = acpi_enable_event (event, 0);
 	if (ACPI_FAILURE (status)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n"));
 
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -95,6 +95,7 @@ acpi_ex_get_object_reference (
 		switch (obj_desc->reference.opcode) {
 		case AML_LOCAL_OP:
 		case AML_ARG_OP:
+		case AML_DEBUG_OP:
 
 			/* The referenced object is the pseudo-node for the local/arg */
 
@@ -103,7 +104,7 @@ acpi_ex_get_object_reference (
 
 		default:
 
-			ACPI_REPORT_ERROR (("Unknown Reference subtype in get ref %X\n",
+			ACPI_REPORT_ERROR (("Unknown Reference opcode in get_reference %X\n",
 				obj_desc->reference.opcode));
 			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
@@ -121,7 +122,7 @@ acpi_ex_get_object_reference (
 
 	default:
 
-		ACPI_REPORT_ERROR (("Invalid descriptor type in get ref: %X\n",
+		ACPI_REPORT_ERROR (("Invalid descriptor type in get_reference: %X\n",
 				ACPI_GET_DESCRIPTOR_TYPE (obj_desc)));
 		return_ACPI_STATUS (AE_TYPE);
 	}
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -442,6 +442,12 @@ acpi_ex_opcode_2A_1T_1R (
 			return_desc->reference.object    = operand[0];
 		}
 
+		/*
+		 * Add a reference to the target package/buffer/string for the life
+		 * of the index.
+		 */
+		acpi_ut_add_reference (operand[0]);
+
 		/* Complete the Index reference object */
 
 		return_desc->reference.opcode    = AML_INDEX_OP;
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -422,6 +422,12 @@ acpi_ex_resolve_multiple (
 			 * This could of course in turn be another reference object.
 			 */
 			obj_desc = *(obj_desc->reference.where);
+			if (!obj_desc) {
+				/* NULL package elements are allowed */
+
+				type = 0; /* Uninitialized */
+				goto exit;
+			}
 			break;
 
 
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -206,7 +206,6 @@ acpi_ex_store_object_to_object (
 {
 	union acpi_operand_object       *actual_src_desc;
 	acpi_status                     status = AE_OK;
-	acpi_object_type                original_src_type;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_object", source_desc);
@@ -223,8 +222,7 @@ acpi_ex_store_object_to_object (
 		return_ACPI_STATUS (status);
 	}
 
-	original_src_type = ACPI_GET_OBJECT_TYPE (source_desc);
-	if (original_src_type != ACPI_GET_OBJECT_TYPE (dest_desc)) {
+	if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_GET_OBJECT_TYPE (dest_desc)) {
 		/*
 		 * The source type does not match the type of the destination.
 		 * Perform the "implicit conversion" of the source to the current type
@@ -275,8 +273,7 @@ acpi_ex_store_object_to_object (
 		 * Note: There is different store behavior depending on the original
 		 * source type
 		 */
-		status = acpi_ex_store_buffer_to_buffer (original_src_type, actual_src_desc,
-				 dest_desc);
+		status = acpi_ex_store_buffer_to_buffer (actual_src_desc, dest_desc);
 		break;
 
 	case ACPI_TYPE_PACKAGE:
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -66,7 +66,6 @@
 
 acpi_status
 acpi_ex_store_buffer_to_buffer (
-	acpi_object_type                original_src_type,
 	union acpi_operand_object       *source_desc,
 	union acpi_operand_object       *target_desc)
 {
@@ -77,9 +76,8 @@ acpi_ex_store_buffer_to_buffer (
 	ACPI_FUNCTION_TRACE_PTR ("ex_store_buffer_to_buffer", source_desc);
 
 
-	/*
-	 * We know that source_desc is a buffer by now
-	 */
+	/* We know that source_desc is a buffer by now */
+
 	buffer = (u8 *) source_desc->buffer.pointer;
 	length = source_desc->buffer.length;
 
@@ -105,7 +103,17 @@ acpi_ex_store_buffer_to_buffer (
 		ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length);
 		ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length);
 
+#ifdef ACPI_OBSOLETE_BEHAVIOR
+		/*
+		 * NOTE: ACPI versions up to 3.0 specified that the buffer must be
+		 * truncated if the string is smaller than the buffer.  However, "other"
+		 * implementations of ACPI never did this and thus became the defacto
+		 * standard. ACPi 3.0_a changes this behavior such that the buffer
+		 * is no longer truncated.
+		 */
+
 		/*
+		 * OBSOLETE BEHAVIOR:
 		 * If the original source was a string, we must truncate the buffer,
 		 * according to the ACPI spec.  Integer-to-Buffer and Buffer-to-Buffer
 		 * copy must not truncate the original buffer.
@@ -115,6 +123,7 @@ acpi_ex_store_buffer_to_buffer (
 
 			target_desc->buffer.length = length;
 		}
+#endif
 	}
 	else {
 		/* Truncate the source, copy only what will fit */
@@ -159,9 +168,8 @@ acpi_ex_store_string_to_string (
 	ACPI_FUNCTION_TRACE_PTR ("ex_store_string_to_string", source_desc);
 
 
-	/*
-	 * We know that source_desc is a string by now.
-	 */
+	/* We know that source_desc is a string by now */
+
 	buffer = (u8 *) source_desc->string.pointer;
 	length = source_desc->string.length;
 
@@ -185,9 +193,8 @@ acpi_ex_store_string_to_string (
 		 */
 		if (target_desc->string.pointer &&
 		   (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
-			/*
-			 * Only free if not a pointer into the DSDT
-			 */
+			/* Only free if not a pointer into the DSDT */
+
 			ACPI_MEM_FREE (target_desc->string.pointer);
 		}
 
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -50,8 +50,8 @@ MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-int acpi_fan_add (struct acpi_device *device);
-int acpi_fan_remove (struct acpi_device *device, int type);
+static int acpi_fan_add (struct acpi_device *device);
+static int acpi_fan_remove (struct acpi_device *device, int type);
 
 static struct acpi_driver acpi_fan_driver = {
 	.name =		ACPI_FAN_DRIVER_NAME,
@@ -72,27 +72,24 @@ struct acpi_fan {
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_fan_dir;
+static struct proc_dir_entry	*acpi_fan_dir;
 
 
 static int
 acpi_fan_read_state (struct seq_file *seq, void *offset)
 {
-	struct acpi_fan		*fan = (struct acpi_fan *) seq->private;
+	struct acpi_fan		*fan = seq->private;
 	int			state = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_fan_read_state");
 
-	if (!fan)
-		goto end;
-
-	if (acpi_bus_get_power(fan->handle, &state))
-		goto end;
-
-	seq_printf(seq, "status:                  %s\n",
-		!state?"on":"off");
-
-end:
+	if (fan) {
+		if (acpi_bus_get_power(fan->handle, &state))
+			seq_printf(seq, "status:                  ERROR\n");
+		else
+			seq_printf(seq, "status:                  %s\n",
+				     !state?"on":"off");
+	}
 	return_VALUE(0);
 }
 
@@ -197,7 +194,7 @@ acpi_fan_remove_fs (
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
-int
+static int
 acpi_fan_add (
 	struct acpi_device	*device)
 {
@@ -243,7 +240,7 @@ end:
 }
 
 
-int
+static int
 acpi_fan_remove (
 	struct acpi_device	*device,
 	int			type)
@@ -265,7 +262,7 @@ acpi_fan_remove (
 }
 
 
-int __init
+static int __init
 acpi_fan_init (void)
 {
 	int			result = 0;
@@ -287,7 +284,7 @@ acpi_fan_init (void)
 }
 
 
-void __exit
+static void __exit
 acpi_fan_exit (void)
 {
 	ACPI_FUNCTION_TRACE("acpi_fan_exit");
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -155,7 +155,7 @@ struct ibm_struct {
 	int experimental;
 };
 
-struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir = NULL;
 
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
@@ -856,7 +856,7 @@ static int beep_write(struct ibm_struct 
 	return 0;
 }	
 		
-struct ibm_struct ibms[] = {
+static struct ibm_struct ibms[] = {
 	{
 		.name	= "driver",
 		.init	= driver_init,
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -170,7 +170,7 @@ acpi_table_parse_srat (
 
 
 int __init
-acpi_numa_init()
+acpi_numa_init(void)
 {
 	int			result;
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -563,7 +563,7 @@ acpi_os_write_pci_configuration (struct 
 }
 
 /* TODO: Change code to take advantage of driver model more */
-void
+static void
 acpi_os_derive_pci_id_2 (
 	acpi_handle		rhandle,        /* upper bound  */
 	acpi_handle		chandle,        /* current node */
@@ -1071,7 +1071,7 @@ acpi_os_signal (
 }
 EXPORT_SYMBOL(acpi_os_signal);
 
-int __init
+static int __init
 acpi_os_name_setup(char *str)
 {
 	char *p = acpi_os_name;
@@ -1101,7 +1101,7 @@ __setup("acpi_os_name=", acpi_os_name_se
  * empty string disables _OSI
  * TBD additional string adds to _OSI
  */
-int __init
+static int __init
 acpi_osi_setup(char *str)
 {
 	if (str == NULL || *str == '\0') {
@@ -1119,7 +1119,7 @@ acpi_osi_setup(char *str)
 __setup("acpi_osi=", acpi_osi_setup);
 
 /* enable serialization to combat AE_ALREADY_EXISTS errors */
-int __init
+static int __init
 acpi_serialize_setup(char *str)
 {
 	printk(KERN_INFO PREFIX "serialize enabled\n");
@@ -1140,7 +1140,7 @@ __setup("acpi_serialize", acpi_serialize
  * Run-time events on the same GPE this flag is available
  * to tell Linux to keep the wake-time GPEs enabled at run-time.
  */
-int __init
+static int __init
 acpi_wake_gpes_always_on_setup(char *str)
 {
 	printk(KERN_INFO PREFIX "wake GPEs not disabled\n");
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -522,7 +522,7 @@ const struct acpi_opcode_info     acpi_g
 /* 2E */ ACPI_OP ("DerefOf",            ARGP_DEREF_OF_OP,          ARGI_DEREF_OF_OP,           ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_1A_0T_1R,   AML_FLAGS_EXEC_1A_0T_1R),
 /* 2F */ ACPI_OP ("Notify",             ARGP_NOTIFY_OP,            ARGI_NOTIFY_OP,             ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_0R,   AML_FLAGS_EXEC_2A_0T_0R),
 /* 30 */ ACPI_OP ("SizeOf",             ARGP_SIZE_OF_OP,           ARGI_SIZE_OF_OP,            ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_1A_0T_1R,   AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
-/* 31 */ ACPI_OP ("Index",              ARGP_INDEX_OP,             ARGI_INDEX_OP,              ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_1T_1R,   AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+/* 31 */ ACPI_OP ("Index",              ARGP_INDEX_OP,             ARGI_INDEX_OP,              ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_1T_1R,   AML_FLAGS_EXEC_2A_1T_1R),
 /* 32 */ ACPI_OP ("Match",              ARGP_MATCH_OP,             ARGI_MATCH_OP,              ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_6A_0T_1R,   AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
 /* 33 */ ACPI_OP ("CreateDWordField",   ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,      AML_CLASS_CREATE,          AML_TYPE_CREATE_FIELD,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
 /* 34 */ ACPI_OP ("CreateWordField",    ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP,  ACPI_TYPE_BUFFER_FIELD,      AML_CLASS_CREATE,          AML_TYPE_CREATE_FIELD,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -1187,8 +1187,8 @@ acpi_ps_parse_aml (
 
 		previous_walk_state = walk_state;
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, State=%p\n",
-			walk_state->return_desc, walk_state));
+		ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n",
+			walk_state->return_desc, walk_state->implicit_return_obj, walk_state));
 
 		/* Check if we have restarted a preempted walk */
 
@@ -1200,8 +1200,20 @@ acpi_ps_parse_aml (
 				 * If the method return value is not used by the parent,
 				 * The object is deleted
 				 */
-				status = acpi_ds_restart_control_method (walk_state,
-						 previous_walk_state->return_desc);
+				if (!previous_walk_state->return_desc) {
+					status = acpi_ds_restart_control_method (walk_state,
+							 previous_walk_state->implicit_return_obj);
+				}
+				else {
+					/*
+					 * We have a valid return value, delete any implicit
+					 * return value.
+					 */
+					acpi_ds_clear_implicit_return (previous_walk_state);
+
+					status = acpi_ds_restart_control_method (walk_state,
+							 previous_walk_state->return_desc);
+				}
 				if (ACPI_SUCCESS (status)) {
 					walk_state->walk_type |= ACPI_WALK_METHOD_RESTART;
 				}
@@ -1218,12 +1230,26 @@ acpi_ps_parse_aml (
 		 * value (if any)
 		 */
 		else if (previous_walk_state->caller_return_desc) {
-			*(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc; /* NULL if no return value */
+			if (previous_walk_state->implicit_return_obj) {
+				*(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj;
+			}
+			else {
+				 /* NULL if no return value */
+
+				*(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc;
+			}
 		}
-		else if (previous_walk_state->return_desc) {
-			/* Caller doesn't want it, must delete it */
+		else {
+			if (previous_walk_state->return_desc) {
+				/* Caller doesn't want it, must delete it */
 
-			acpi_ut_remove_reference (previous_walk_state->return_desc);
+				acpi_ut_remove_reference (previous_walk_state->return_desc);
+			}
+			if (previous_walk_state->implicit_return_obj) {
+				/* Caller doesn't want it, must delete it */
+
+				acpi_ut_remove_reference (previous_walk_state->implicit_return_obj);
+			}
 		}
 
 		acpi_ds_delete_walk_state (previous_walk_state);
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -44,7 +44,6 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acparser.h>
-#include <acpi/acdispat.h>
 
 #define _COMPONENT          ACPI_PARSER
 	 ACPI_MODULE_NAME    ("pswalk")
@@ -52,256 +51,65 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ps_get_next_walk_op
+ * FUNCTION:    acpi_ps_delete_parse_tree
  *
- * PARAMETERS:  walk_state          - Current state of the walk
- *              Op                  - Current Op to be walked
- *              ascending_callback  - Procedure called when Op is complete
+ * PARAMETERS:  subtree_root        - Root of tree (or subtree) to delete
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: Get the next Op in a walk of the parse tree.
+ * DESCRIPTION: Delete a portion of or an entire parse tree.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_ps_get_next_walk_op (
-	struct acpi_walk_state          *walk_state,
-	union acpi_parse_object         *op,
-	acpi_parse_upwards              ascending_callback)
+void
+acpi_ps_delete_parse_tree (
+	union acpi_parse_object         *subtree_root)
 {
-	union acpi_parse_object         *next;
-	union acpi_parse_object         *parent;
-	union acpi_parse_object         *grand_parent;
-	acpi_status                     status;
+	union acpi_parse_object         *op = subtree_root;
+	union acpi_parse_object         *next = NULL;
+	union acpi_parse_object         *parent = NULL;
 
 
-	ACPI_FUNCTION_TRACE_PTR ("ps_get_next_walk_op", op);
+	ACPI_FUNCTION_TRACE_PTR ("ps_delete_parse_tree", subtree_root);
 
 
-	/* Check for a argument only if we are descending in the tree */
+	/* Visit all nodes in the subtree */
 
-	if (walk_state->next_op_info != ACPI_NEXT_OP_UPWARD) {
-		/* Look for an argument or child of the current op */
+	while (op) {
+		/* Check if we are not ascending */
 
-		next = acpi_ps_get_arg (op, 0);
-		if (next) {
-			/* Still going downward in tree (Op is not completed yet) */
+		if (op != parent) {
+			/* Look for an argument or child of the current op */
 
-			walk_state->prev_op     = op;
-			walk_state->next_op     = next;
-			walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
+			next = acpi_ps_get_arg (op, 0);
+			if (next) {
+				/* Still going downward in tree (Op is not completed yet) */
 
-			return_ACPI_STATUS (AE_OK);
+				op = next;
+				continue;
+			}
 		}
 
 		/*
-		 * No more children, this Op is complete.  Save Next and Parent
-		 * in case the Op object gets deleted by the callback routine
+		 * No more children, this Op is complete.
 		 */
-		next    = op->common.next;
-		parent  = op->common.parent;
+		next = op->common.next;
+		parent = op->common.parent;
 
-		walk_state->op    = op;
-		walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
-		walk_state->opcode = op->common.aml_opcode;
-
-		status = ascending_callback (walk_state);
+		acpi_ps_free_op (op);
 
 		/*
 		 * If we are back to the starting point, the walk is complete.
 		 */
-		if (op == walk_state->origin) {
-			/* Reached the point of origin, the walk is complete */
-
-			walk_state->prev_op     = op;
-			walk_state->next_op     = NULL;
-
-			return_ACPI_STATUS (status);
+		if (op == subtree_root) {
+			return_VOID;
 		}
-
-		/*
-		 * Check for a sibling to the current op.  A sibling means
-		 * we are still going "downward" in the tree.
-		 */
 		if (next) {
-			/* There is a sibling, it will be next */
-
-			walk_state->prev_op     = op;
-			walk_state->next_op     = next;
-			walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
-			/* Continue downward */
-
-			return_ACPI_STATUS (status);
-		}
-
-		/*
-		 * Drop into the loop below because we are moving upwards in
-		 * the tree
-		 */
-	}
-	else {
-		/*
-		 * We are resuming a walk, and we were (are) going upward in the tree.
-		 * So, we want to drop into the parent loop below.
-		 */
-		parent = op;
-	}
-
-	/*
-	 * Look for a sibling of the current Op's parent
-	 * Continue moving up the tree until we find a node that has not been
-	 * visited, or we get back to where we started.
-	 */
-	while (parent) {
-		/* We are moving up the tree, therefore this parent Op is complete */
-
-		grand_parent = parent->common.parent;
-		next        = parent->common.next;
-
-		walk_state->op    = parent;
-		walk_state->op_info = acpi_ps_get_opcode_info (parent->common.aml_opcode);
-		walk_state->opcode = parent->common.aml_opcode;
-
-		status = ascending_callback (walk_state);
-
-		/*
-		 * If we are back to the starting point, the walk is complete.
-		 */
-		if (parent == walk_state->origin) {
-			/* Reached the point of origin, the walk is complete */
-
-			walk_state->prev_op     = parent;
-			walk_state->next_op     = NULL;
-
-			return_ACPI_STATUS (status);
+			op = next;
 		}
-
-		/*
-		 * If there is a sibling to this parent (it is not the starting point
-		 * Op), then we will visit it.
-		 */
-		if (next) {
-			/* found sibling of parent */
-
-			walk_state->prev_op     = parent;
-			walk_state->next_op     = next;
-			walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
-			return_ACPI_STATUS (status);
+		else {
+			op = parent;
 		}
-
-		/* No siblings, no errors, just move up one more level in the tree */
-
-		op                  = parent;
-		parent              = grand_parent;
-		walk_state->prev_op = op;
 	}
-
-
-	/*
-	 * Got all the way to the top of the tree, we must be done!
-	 * However, the code should have terminated in the loop above
-	 */
-	walk_state->next_op     = NULL;
-
-	return_ACPI_STATUS (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_delete_completed_op
- *
- * PARAMETERS:  State           - Walk state
- *              Op              - Completed op
- *
- * RETURN:      AE_OK
- *
- * DESCRIPTION: Callback function for acpi_ps_get_next_walk_op(). Used during
- *              acpi_ps_delete_parse tree to delete Op objects when all sub-objects
- *              have been visited (and deleted.)
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ps_delete_completed_op (
-	struct acpi_walk_state          *walk_state)
-{
-
-	acpi_ps_free_op (walk_state->op);
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_delete_parse_tree
- *
- * PARAMETERS:  subtree_root        - Root of tree (or subtree) to delete
- *
- * RETURN:      None
- *
- * DESCRIPTION: Delete a portion of or an entire parse tree.
- *
- ******************************************************************************/
-
-void
-acpi_ps_delete_parse_tree (
-	union acpi_parse_object         *subtree_root)
-{
-	struct acpi_walk_state          *walk_state;
-	struct acpi_thread_state        *thread;
-	acpi_status                     status;
-
-
-	ACPI_FUNCTION_TRACE_PTR ("ps_delete_parse_tree", subtree_root);
-
-
-	if (!subtree_root) {
-		return_VOID;
-	}
-
-	/* Create and initialize a new walk list */
-
-	thread = acpi_ut_create_thread_state ();
-	if (!thread) {
-		return_VOID;
-	}
-
-	walk_state = acpi_ds_create_walk_state (0, NULL, NULL, thread);
-	if (!walk_state) {
-		return_VOID;
-	}
-
-	walk_state->parse_flags         = 0;
-	walk_state->descending_callback = NULL;
-	walk_state->ascending_callback  = NULL;
-
-	walk_state->origin = subtree_root;
-	walk_state->next_op = subtree_root;
-
-	/* Head downward in the tree */
-
-	walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
-	/* Visit all nodes in the subtree */
-
-	while (walk_state->next_op) {
-		status = acpi_ps_get_next_walk_op (walk_state, walk_state->next_op,
-				 acpi_ps_delete_completed_op);
-		if (ACPI_FAILURE (status)) {
-			break;
-		}
-	}
-
-	/* We are done with this walk */
-
-	acpi_ut_delete_generic_state (ACPI_CAST_PTR (union acpi_generic_state, thread));
-	acpi_ds_delete_walk_state (walk_state);
-
 	return_VOID;
 }
-
-
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -42,8 +42,8 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME		("pci_irq")
 
-struct acpi_prt_list		acpi_prt;
-DEFINE_SPINLOCK(acpi_prt_lock);
+static struct acpi_prt_list	acpi_prt;
+static DEFINE_SPINLOCK(acpi_prt_lock);
 
 /* --------------------------------------------------------------------------
                          PCI IRQ Routing Table (PRT) Support
@@ -281,7 +281,8 @@ acpi_pci_irq_lookup (
 	int			device,
 	int			pin,
 	int			*edge_level,
-	int			*active_high_low)
+	int			*active_high_low,
+	char			**link)
 {
 	struct acpi_prt_entry	*entry = NULL;
 	int segment = pci_domain_nr(bus);
@@ -301,7 +302,8 @@ acpi_pci_irq_lookup (
 	}
 	
 	if (entry->link.handle) {
-		irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, edge_level, active_high_low);
+		irq = acpi_pci_link_get_irq(entry->link.handle,
+			entry->link.index, edge_level, active_high_low, link);
 		if (irq < 0) {
 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
 			return_VALUE(-1);
@@ -327,7 +329,8 @@ acpi_pci_irq_derive (
 	struct pci_dev		*dev,
 	int			pin,
 	int			*edge_level,
-	int			*active_high_low)
+	int			*active_high_low,
+	char			**link)
 {
 	struct pci_dev		*bridge = dev;
 	int			irq = -1;
@@ -360,7 +363,7 @@ acpi_pci_irq_derive (
 		}
 
 		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
-			pin, edge_level, active_high_low);
+			pin, edge_level, active_high_low, link);
 	}
 
 	if (irq < 0) {
@@ -388,7 +391,7 @@ acpi_pci_irq_enable (
 	u8			pin = 0;
 	int			edge_level = ACPI_LEVEL_SENSITIVE;
 	int			active_high_low = ACPI_ACTIVE_LOW;
-	extern int		via_interrupt_line_quirk;
+	char			*link = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
 
@@ -411,21 +414,23 @@ acpi_pci_irq_enable (
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
 	 * values override any BIOS-assigned IRQs set during boot.
 	 */
- 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, &edge_level, &active_high_low);
+ 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
+		&edge_level, &active_high_low, &link);
 
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
 	 */
 	if (irq < 0)
- 		irq = acpi_pci_irq_derive(dev, pin, &edge_level, &active_high_low);
+ 		irq = acpi_pci_irq_derive(dev, pin, &edge_level,
+			&active_high_low, &link);
  
 	/*
 	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
 	 * driver reported one, then use it. Exit in any case.
 	 */
 	if (irq < 0) {
-		printk(KERN_WARNING PREFIX "PCI interrupt %s[%c]: no GSI",
+		printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
 			pci_name(dev), ('A' + pin));
 		/* Interrupt Line values above 0xF are forbidden */
 		if (dev->irq >= 0 && (dev->irq <= 0xF)) {
@@ -438,14 +443,15 @@ acpi_pci_irq_enable (
 		}
  	}
 
-	if (via_interrupt_line_quirk)
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15);
-
 	dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
 
-	printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI %u "
-		"(%s, %s) -> IRQ %d\n",
-		pci_name(dev), 'A' + pin, irq,
+	printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
+		pci_name(dev), 'A' + pin);
+
+	if (link)
+		printk("Link [%s] -> ", link);
+
+	printk("GSI %u (%s, %s) -> IRQ %d\n", irq,
 		(edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
 		(active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high",
 		dev->irq);
@@ -482,14 +488,14 @@ acpi_pci_irq_disable (
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.
 	 */
  	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
-				  &edge_level, &active_high_low);
+				  &edge_level, &active_high_low, NULL);
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
 	 */
 	if (gsi < 0)
  		gsi = acpi_pci_irq_derive(dev, pin,
-					  &edge_level, &active_high_low);
+					  &edge_level, &active_high_low, NULL);
 	if (gsi < 0)
 		return_VOID;
 
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -522,9 +522,11 @@ acpi_irq_penalty_init(void)
 
 static int acpi_irq_balance;	/* 0: static, 1: balance */
 
-static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
-	int irq;
-	int i;
+static int acpi_pci_link_allocate(
+	struct acpi_pci_link	*link)
+{
+	int			irq;
+	int			i;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
 
@@ -597,8 +599,9 @@ int
 acpi_pci_link_get_irq (
 	acpi_handle		handle,
 	int			index,
-	int*			edge_level,
-	int*			active_high_low)
+	int			*edge_level,
+	int			*active_high_low,
+	char			**name)
 {
 	int                     result = 0;
 	struct acpi_device	*device = NULL;
@@ -634,6 +637,7 @@ acpi_pci_link_get_irq (
 
 	if (edge_level) *edge_level = link->irq.edge_level;
 	if (active_high_low) *active_high_low = link->irq.active_high_low;
+	if (name) *name = acpi_device_bid(link->device);
 	return_VALUE(link->irq.active);
 }
 
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -258,7 +258,7 @@ acpi_pci_root_add (
  	/* TBD: Locking */
  	list_add_tail(&root->node, &acpi_pci_roots);
 
-	printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x)\n", 
+	printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", 
 		acpi_device_name(device), acpi_device_bid(device),
 		root->id.segment, root->id.bus);
 
@@ -272,7 +272,7 @@ acpi_pci_root_add (
 	root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
 	if (!root->bus) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
-			"Bus %02x:%02x not present in PCI namespace\n", 
+			"Bus %04x:%02x not present in PCI namespace\n", 
 			root->id.segment, root->id.bus));
 		result = -ENODEV;
 		goto end;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -58,8 +58,8 @@ ACPI_MODULE_NAME		("acpi_power")
 #define ACPI_POWER_RESOURCE_STATE_ON	0x01
 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
 
-int acpi_power_add (struct acpi_device *device);
-int acpi_power_remove (struct acpi_device *device, int type);
+static int acpi_power_add (struct acpi_device *device);
+static int acpi_power_remove (struct acpi_device *device, int type);
 static int acpi_power_open_fs(struct inode *inode, struct file *file);
 
 static struct acpi_driver acpi_power_driver = {
@@ -479,7 +479,7 @@ end:
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_power_dir;
+static struct proc_dir_entry	*acpi_power_dir;
 
 static int acpi_power_seq_show(struct seq_file *seq, void *offset)
 {
@@ -576,7 +576,7 @@ acpi_power_remove_fs (
                                 Driver Interface
    -------------------------------------------------------------------------- */
 
-int
+static int
 acpi_power_add (
 	struct acpi_device	*device)
 {
@@ -642,7 +642,7 @@ end:
 }
 
 
-int
+static int
 acpi_power_remove (
 	struct acpi_device	*device,
 	int			type)
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -105,7 +105,7 @@ static struct acpi_driver acpi_processor
 #define UNINSTALL_NOTIFY_HANDLER	2
 
 
-struct file_operations acpi_processor_info_fops = {
+static struct file_operations acpi_processor_info_fops = {
 	.open 		= acpi_processor_info_open_fs,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -121,7 +121,7 @@ struct acpi_processor_errata errata;
                                 Errata Handling
    -------------------------------------------------------------------------- */
 
-int
+static int
 acpi_processor_errata_piix4 (
 	struct pci_dev		*dev)
 {
@@ -259,7 +259,7 @@ acpi_processor_errata (
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_processor_dir = NULL;
+static struct proc_dir_entry	*acpi_processor_dir = NULL;
 
 static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
 {
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -838,7 +838,7 @@ int acpi_processor_cst_has_changed (stru
 
 	/* Fall back to the default idle loop */
 	pm_idle = pm_idle_save;
-	synchronize_kernel();
+	synchronize_sched();  /* Relies on interrupts forcing exit from idle. */
 
 	pr->flags.power = 0;
 	result = acpi_processor_get_power_info(pr);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -345,7 +345,7 @@ end:
 	return_VALUE(0);
 }
 
-int acpi_processor_limit_open_fs(struct inode *inode, struct file *file)
+static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file)
 {
 	return single_open(file, acpi_processor_limit_seq_show,
 						PDE(inode)->data);
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -308,7 +308,7 @@ end:
 	return_VALUE(0);
 }
 
-int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file)
+static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file)
 {
 	return single_open(file, acpi_processor_throttling_seq_show,
 						PDE(inode)->data);
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -110,13 +110,13 @@ acpi_rs_address16_resource (
 	buffer += 2;
 	temp8 = *buffer;
 
-	/* Values 0-2 are valid */
+	/* Values 0-2 and 0xC0-0xFF are valid */
 
-	if (temp8 > 2) {
+	if ((temp8 > 2) && (temp8 < 0xC0)) {
 		return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
 	}
 
-	output_struct->data.address16.resource_type = temp8 & 0x03;
+	output_struct->data.address16.resource_type = temp8;
 
 	/*
 	 * Get the General Flags (Byte4)
@@ -496,12 +496,13 @@ acpi_rs_address32_resource (
 	buffer += 2;
 	temp8 = *buffer;
 
-	/* Values 0-2 are valid */
-	if(temp8 > 2) {
+	/* Values 0-2 and 0xC0-0xFF are valid */
+
+	if ((temp8 > 2) && (temp8 < 0xC0)) {
 		return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
 	}
 
-	output_struct->data.address32.resource_type = temp8 & 0x03;
+	output_struct->data.address32.resource_type = temp8;
 
 	/*
 	 * Get the General Flags (Byte4)
@@ -850,6 +851,7 @@ acpi_rs_address64_resource (
 	struct acpi_resource            *output_struct = (void *) *output_buffer;
 	u16                             temp16;
 	u8                              temp8;
+	u8                              resource_type;
 	u8                              *temp_ptr;
 	acpi_size                       struct_size;
 	u32                             index;
@@ -860,6 +862,7 @@ acpi_rs_address64_resource (
 
 	buffer = byte_stream_buffer;
 	struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
+	resource_type = *buffer;
 
 	/*
 	 * Point past the Descriptor to get the number of bytes consumed
@@ -882,13 +885,13 @@ acpi_rs_address64_resource (
 	buffer += 2;
 	temp8 = *buffer;
 
-	/* Values 0-2 are valid */
+	/* Values 0-2 and 0xC0-0xFF are valid */
 
-	if(temp8 > 2) {
+	if ((temp8 > 2) && (temp8 < 0xC0)) {
 		return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
 	}
 
-	output_struct->data.address64.resource_type = temp8 & 0x03;
+	output_struct->data.address64.resource_type = temp8;
 
 	/*
 	 * Get the General Flags (Byte4)
@@ -942,98 +945,113 @@ acpi_rs_address64_resource (
 		}
 	}
 
+	if (resource_type == ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE) {
+		/* Move past revision_id and Reserved byte */
+
+		buffer += 2;
+	}
+
 	/*
-	 * Get Granularity (Bytes 6-13)
+	 * Get Granularity (Bytes 6-13) or (Bytes 8-15)
 	 */
 	buffer += 1;
 	ACPI_MOVE_64_TO_64 (&output_struct->data.address64.granularity, buffer);
 
 	/*
-	 * Get min_address_range (Bytes 14-21)
+	 * Get min_address_range (Bytes 14-21) or (Bytes 16-23)
 	 */
 	buffer += 8;
 	ACPI_MOVE_64_TO_64 (&output_struct->data.address64.min_address_range, buffer);
 
 	/*
-	 * Get max_address_range (Bytes 22-29)
+	 * Get max_address_range (Bytes 22-29) or (Bytes 24-31)
 	 */
 	buffer += 8;
 	ACPI_MOVE_64_TO_64 (&output_struct->data.address64.max_address_range, buffer);
 
 	/*
-	 * Get address_translation_offset (Bytes 30-37)
+	 * Get address_translation_offset (Bytes 30-37) or (Bytes 32-39)
 	 */
 	buffer += 8;
 	ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer);
 
 	/*
-	 * Get address_length (Bytes 38-45)
+	 * Get address_length (Bytes 38-45) or (Bytes 40-47)
 	 */
 	buffer += 8;
 	ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_length, buffer);
 
-	/*
-	 * Resource Source Index (if present)
-	 */
-	buffer += 8;
+	output_struct->data.address64.resource_source.index = 0x00;
+	output_struct->data.address64.resource_source.string_length = 0;
+	output_struct->data.address64.resource_source.string_ptr = NULL;
 
-	/*
-	 * This will leave us pointing to the Resource Source Index
-	 * If it is present, then save it off and calculate the
-	 * pointer to where the null terminated string goes:
-	 * Each Interrupt takes 32-bits + the 5 bytes of the
-	 * stream that are default.
-	 *
-	 * Note: Some resource descriptors will have an additional null, so
-	 * we add 1 to the length.
-	 */
-	if (*bytes_consumed > (46 + 1)) {
-		/* Dereference the Index */
+	if (resource_type == ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE) {
+		/* Get type_specific_attribute (Bytes 48-55) */
 
-		temp8 = *buffer;
-		output_struct->data.address64.resource_source.index =
-				(u32) temp8;
+		buffer += 8;
+		ACPI_MOVE_64_TO_64 (&output_struct->data.address64.type_specific_attributes, buffer);
+	}
+	else {
+		output_struct->data.address64.type_specific_attributes = 0;
 
-		/* Point to the String */
+		/*
+		 * Resource Source Index (if present)
+		 */
+		buffer += 8;
 
-		buffer += 1;
+		/*
+		 * This will leave us pointing to the Resource Source Index
+		 * If it is present, then save it off and calculate the
+		 * pointer to where the null terminated string goes:
+		 * Each Interrupt takes 32-bits + the 5 bytes of the
+		 * stream that are default.
+		 *
+		 * Note: Some resource descriptors will have an additional null, so
+		 * we add 1 to the length.
+		 */
+		if (*bytes_consumed > (46 + 1)) {
+			/* Dereference the Index */
 
-		/* Point the String pointer to the end of this structure */
+			temp8 = *buffer;
+			output_struct->data.address64.resource_source.index =
+					(u32) temp8;
 
-		output_struct->data.address64.resource_source.string_ptr =
-				(char *)((u8 *)output_struct + struct_size);
+			/* Point to the String */
 
-		temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr;
+			buffer += 1;
 
-		/* Copy the string into the buffer */
+			/* Point the String pointer to the end of this structure */
 
-		index = 0;
-		while (0x00 != *buffer) {
-			*temp_ptr = *buffer;
+			output_struct->data.address64.resource_source.string_ptr =
+					(char *)((u8 *)output_struct + struct_size);
 
-			temp_ptr += 1;
-			buffer += 1;
-			index += 1;
-		}
+			temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr;
 
-		/*
-		 * Add the terminating null
-		 */
-		*temp_ptr = 0x00;
-		output_struct->data.address64.resource_source.string_length = index + 1;
+			/* Copy the string into the buffer */
 
-		/*
-		 * In order for the struct_size to fall on a 32-bit boundary,
-		 * calculate the length of the string and expand the
-		 * struct_size to the next 32-bit boundary.
-		 */
-		temp8 = (u8) (index + 1);
-		struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
-	}
-	else {
-		output_struct->data.address64.resource_source.index = 0x00;
-		output_struct->data.address64.resource_source.string_length = 0;
-		output_struct->data.address64.resource_source.string_ptr = NULL;
+			index = 0;
+			while (0x00 != *buffer) {
+				*temp_ptr = *buffer;
+
+				temp_ptr += 1;
+				buffer += 1;
+				index += 1;
+			}
+
+			/*
+			 * Add the terminating null
+			 */
+			*temp_ptr = 0x00;
+			output_struct->data.address64.resource_source.string_length = index + 1;
+
+			/*
+			 * In order for the struct_size to fall on a 32-bit boundary,
+			 * calculate the length of the string and expand the
+			 * struct_size to the next 32-bit boundary.
+			 */
+			temp8 = (u8) (index + 1);
+			struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
+		}
 	}
 
 	/*
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -376,6 +376,20 @@ acpi_rs_get_list_length (
 			break;
 
 
+		case ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE:
+			/*
+			 * 64-Bit Address Resource
+			 */
+			buffer = byte_stream_buffer;
+
+			++buffer;
+			ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+			bytes_consumed = temp16 + 3;
+			structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
+			break;
+
+
 		case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE:
 			/*
 			 * 64-Bit Address Resource
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -571,7 +571,7 @@ acpi_rs_dump_address16 (
 			break;
 		}
 
-		acpi_os_printf (" Type Specific: %s Translation\n",
+		acpi_os_printf ("  Type Specific: %s Translation\n",
 			ACPI_SPARSE_TRANSLATION ==
 			address16_data->attribute.io.translation_attribute ?
 			"Sparse" : "Dense");
@@ -584,8 +584,8 @@ acpi_rs_dump_address16 (
 
 	default:
 
-		acpi_os_printf ("Invalid resource type. Exiting.\n");
-		return;
+		acpi_os_printf ("0x%2.2X\n", address16_data->resource_type);
+		break;
 	}
 
 	acpi_os_printf ("  Resource %s\n",
@@ -718,7 +718,7 @@ acpi_rs_dump_address32 (
 			break;
 		}
 
-		acpi_os_printf (" Type Specific: %s Translation\n",
+		acpi_os_printf ("  Type Specific: %s Translation\n",
 			ACPI_SPARSE_TRANSLATION ==
 			address32_data->attribute.io.translation_attribute ?
 			"Sparse" : "Dense");
@@ -731,8 +731,8 @@ acpi_rs_dump_address32 (
 
 	default:
 
-		acpi_os_printf ("  Invalid Resource Type..exiting.\n");
-		return;
+		acpi_os_printf ("  Resource Type: 0x%2.2X\n", address32_data->resource_type);
+		break;
 	}
 
 	acpi_os_printf ("  Resource %s\n",
@@ -865,7 +865,7 @@ acpi_rs_dump_address64 (
 			break;
 		}
 
-		acpi_os_printf (" Type Specific: %s Translation\n",
+		acpi_os_printf ("  Type Specific: %s Translation\n",
 			ACPI_SPARSE_TRANSLATION ==
 			address64_data->attribute.io.translation_attribute ?
 			"Sparse" : "Dense");
@@ -878,8 +878,8 @@ acpi_rs_dump_address64 (
 
 	default:
 
-		acpi_os_printf ("  Invalid Resource Type..exiting.\n");
-		return;
+		acpi_os_printf ("  Resource Type: 0x%2.2X\n", address64_data->resource_type);
+		break;
 	}
 
 	acpi_os_printf ("  Resource %s\n",
@@ -913,7 +913,10 @@ acpi_rs_dump_address64 (
 	acpi_os_printf ("  Address Length: %8.8X%8.8X\n",
 			 ACPI_FORMAT_UINT64 (address64_data->address_length));
 
-	if(0xFF != address64_data->resource_source.index) {
+	acpi_os_printf ("  Type Specific Attributes: %8.8X%8.8X\n",
+			 ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes));
+
+	if (0xFF != address64_data->resource_source.index) {
 		acpi_os_printf ("  Resource Source Index: %X\n",
 				 address64_data->resource_source.index);
 		acpi_os_printf ("  Resource Source: %s\n",
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -178,6 +178,7 @@ acpi_rs_byte_stream_to_list (
 
 
 		case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE:
+		case ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE:
 			/*
 			 * 64-Bit Address Resource
 			 */
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -27,6 +27,10 @@ static LIST_HEAD(acpi_device_list);
 DEFINE_SPINLOCK(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
 
+static int
+acpi_bus_trim(struct acpi_device	*start,
+		int rmdevice);
+
 static void acpi_device_release(struct kobject * kobj)
 {
 	struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);
@@ -81,12 +85,37 @@ static struct kobj_type ktype_acpi_ns = 
 	.release	= acpi_device_release,
 };
 
+static int namespace_hotplug(struct kset *kset, struct kobject *kobj,
+			     char **envp, int num_envp, char *buffer,
+			     int buffer_size)
+{
+	struct acpi_device *dev = to_acpi_device(kobj);
+	int i = 0;
+	int len = 0;
+
+	if (!dev->driver)
+		return 0;
+
+	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+				"PHYSDEVDRIVER=%s", dev->driver->name))
+		return -ENOMEM;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static struct kset_hotplug_ops namespace_hotplug_ops = {
+	.hotplug = &namespace_hotplug,
+};
+
 static struct kset acpi_namespace_kset = {
 	.kobj		= { 
 		.name = "namespace",
 	},
 	.subsys = &acpi_subsys,
 	.ktype	= &ktype_acpi_ns,
+	.hotplug_ops = &namespace_hotplug_ops,
 };
 
 
@@ -350,15 +379,23 @@ ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi
 
 /**
  * setup_sys_fs_device_files - sets up the device files under device namespace
- * @@dev:	acpi_device object
- * @@func:	function pointer to create or destroy the device file
+ * @dev:	acpi_device object
+ * @func:	function pointer to create or destroy the device file
  */
 static void
 setup_sys_fs_device_files (
 	struct acpi_device *dev,
 	acpi_device_sysfs_files *func)
 {
-	if (dev->flags.ejectable == 1)
+	acpi_status		status;
+	acpi_handle		temp = NULL;
+
+	/*
+	 * If device has _EJ0, 'eject' file is created that is used to trigger
+	 * hot-removal function from userland.
+	 */
+	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+	if (ACPI_SUCCESS(status))
 		(*(func))(&dev->kobj,&acpi_device_attr_eject.attr);
 }
 
@@ -857,7 +894,7 @@ static void acpi_device_set_id(struct ac
 	acpi_os_free(buffer.pointer);
 }
 
-int acpi_device_set_context(struct acpi_device * device, int type)
+static int acpi_device_set_context(struct acpi_device * device, int type)
 {
 	acpi_status status = AE_OK;
 	int result = 0;
@@ -882,7 +919,7 @@ int acpi_device_set_context(struct acpi_
 	return result;
 }
 
-void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
+static void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
 {
 #ifdef CONFIG_ACPI_DEBUG_OUTPUT
 	char		*type_string = NULL;
@@ -925,7 +962,7 @@ void acpi_device_get_debug_info(struct a
 }
 
 
-int
+static int
 acpi_bus_remove (
 	struct acpi_device *dev,
 	int rmdevice)
@@ -1223,7 +1260,7 @@ int acpi_bus_scan (struct acpi_device	*s
 EXPORT_SYMBOL(acpi_bus_scan);
 
 
-int
+static int
 acpi_bus_trim(struct acpi_device	*start,
 		int rmdevice)
 {
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -84,10 +84,11 @@ static int acpi_system_alarm_seq_show(st
 	u32			sec, min, hr;
 	u32			day, mo, yr;
 	unsigned char		rtc_control = 0;
+	unsigned long 		flags;
 
 	ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
 
-	spin_lock(&rtc_lock);
+	spin_lock_irqsave(&rtc_lock, flags);
 
 	sec = CMOS_READ(RTC_SECONDS_ALARM);
 	min = CMOS_READ(RTC_MINUTES_ALARM);
@@ -109,7 +110,7 @@ static int acpi_system_alarm_seq_show(st
 	else
 		yr = CMOS_READ(RTC_YEAR);
 
-	spin_unlock(&rtc_lock);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BCD_TO_BIN(sec);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -774,7 +774,7 @@ acpi_thermal_check (
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_thermal_dir;
+static struct proc_dir_entry	*acpi_thermal_dir;
 
 static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
 {
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -481,7 +481,7 @@ read_version(char* p)
 
 #define PROC_TOSHIBA		"toshiba"
 
-ProcItem proc_items[] =
+static ProcItem proc_items[] =
 {
 	{ "lcd"		, read_lcd	, write_lcd	},
 	{ "video"	, read_video	, write_video	},
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -659,15 +659,17 @@ acpi_ut_copy_simple_object (
 			/* Create an actual buffer only if length > 0 */
 
 			if (source_desc->buffer.length) {
-				dest_desc->buffer.pointer = ACPI_MEM_ALLOCATE (source_desc->buffer.length);
+				dest_desc->buffer.pointer =
+					ACPI_MEM_ALLOCATE (source_desc->buffer.length);
 				if (!dest_desc->buffer.pointer) {
 					return (AE_NO_MEMORY);
 				}
 
 				/* Copy the actual buffer data */
 
-				ACPI_MEMCPY (dest_desc->buffer.pointer, source_desc->buffer.pointer,
-						  source_desc->buffer.length);
+				ACPI_MEMCPY (dest_desc->buffer.pointer,
+						source_desc->buffer.pointer,
+						source_desc->buffer.length);
 			}
 		}
 		break;
@@ -682,7 +684,8 @@ acpi_ut_copy_simple_object (
 		 */
 		if ((source_desc->string.pointer) &&
 			(!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
-			dest_desc->string.pointer = ACPI_MEM_ALLOCATE ((acpi_size) source_desc->string.length + 1);
+			dest_desc->string.pointer =
+				ACPI_MEM_ALLOCATE ((acpi_size) source_desc->string.length + 1);
 			if (!dest_desc->string.pointer) {
 				return (AE_NO_MEMORY);
 			}
@@ -692,6 +695,14 @@ acpi_ut_copy_simple_object (
 		}
 		break;
 
+	case ACPI_TYPE_LOCAL_REFERENCE:
+		/*
+		 * We copied the reference object, so we now must add a reference
+		 * to the object pointed to by the reference
+		 */
+		acpi_ut_add_reference (source_desc->reference.object);
+		break;
+
 	default:
 		/* Nothing to do for other simple objects */
 		break;
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -46,6 +46,7 @@
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acevents.h>
+#include <acpi/amlcode.h>
 
 #define _COMPONENT          ACPI_UTILITIES
 	 ACPI_MODULE_NAME    ("utdelete")
@@ -562,8 +563,23 @@ acpi_ut_update_object_reference (
 			break;
 
 
-		case ACPI_TYPE_REGION:
 		case ACPI_TYPE_LOCAL_REFERENCE:
+
+			/*
+			 * The target of an Index (a package, string, or buffer) must track
+			 * changes to the ref count of the index.
+			 */
+			if (object->reference.opcode == AML_INDEX_OP) {
+				status = acpi_ut_create_update_state_and_push (
+						 object->reference.object, action, &state_list);
+				if (ACPI_FAILURE (status)) {
+					goto error_exit;
+				}
+			}
+			break;
+
+
+		case ACPI_TYPE_REGION:
 		default:
 
 			/* No subobjects */
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -194,6 +194,8 @@ const char                          *acp
  */
 const char                          *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] =
 {
+	/* Operating System Vendor Strings */
+
 	"Linux",
 	"Windows 2000",
 	"Windows 2001",
@@ -202,7 +204,11 @@ const char                          *acp
 	"Windows 2001 SP1",
 	"Windows 2001 SP2",
 	"Windows 2001 SP3",
-	"Windows 2001 SP4"
+	"Windows 2001 SP4",
+
+	/* Feature Group Strings */
+
+	"Extended Address Space Descriptor"
 };
 
 
@@ -355,6 +361,7 @@ struct acpi_bit_register_info       acpi
 	/* ACPI_BITREG_SLEEP_BUTTON_STATUS  */   {ACPI_REGISTER_PM1_STATUS,   ACPI_BITPOSITION_SLEEP_BUTTON_STATUS,   ACPI_BITMASK_SLEEP_BUTTON_STATUS},
 	/* ACPI_BITREG_RT_CLOCK_STATUS      */   {ACPI_REGISTER_PM1_STATUS,   ACPI_BITPOSITION_RT_CLOCK_STATUS,       ACPI_BITMASK_RT_CLOCK_STATUS},
 	/* ACPI_BITREG_WAKE_STATUS          */   {ACPI_REGISTER_PM1_STATUS,   ACPI_BITPOSITION_WAKE_STATUS,           ACPI_BITMASK_WAKE_STATUS},
+	/* ACPI_BITREG_PCIEXP_WAKE_STATUS   */   {ACPI_REGISTER_PM1_STATUS,   ACPI_BITPOSITION_PCIEXP_WAKE_STATUS,    ACPI_BITMASK_PCIEXP_WAKE_STATUS},
 
 	/* ACPI_BITREG_TIMER_ENABLE         */   {ACPI_REGISTER_PM1_ENABLE,   ACPI_BITPOSITION_TIMER_ENABLE,          ACPI_BITMASK_TIMER_ENABLE},
 	/* ACPI_BITREG_GLOBAL_LOCK_ENABLE   */   {ACPI_REGISTER_PM1_ENABLE,   ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE,    ACPI_BITMASK_GLOBAL_LOCK_ENABLE},
@@ -362,6 +369,7 @@ struct acpi_bit_register_info       acpi
 	/* ACPI_BITREG_SLEEP_BUTTON_ENABLE  */   {ACPI_REGISTER_PM1_ENABLE,   ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE,   ACPI_BITMASK_SLEEP_BUTTON_ENABLE},
 	/* ACPI_BITREG_RT_CLOCK_ENABLE      */   {ACPI_REGISTER_PM1_ENABLE,   ACPI_BITPOSITION_RT_CLOCK_ENABLE,       ACPI_BITMASK_RT_CLOCK_ENABLE},
 	/* ACPI_BITREG_WAKE_ENABLE          */   {ACPI_REGISTER_PM1_ENABLE,   0,                                      0},
+	/* ACPI_BITREG_PCIEXP_WAKE_DISABLE  */   {ACPI_REGISTER_PM1_ENABLE,   ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE,   ACPI_BITMASK_PCIEXP_WAKE_DISABLE},
 
 	/* ACPI_BITREG_SCI_ENABLE           */   {ACPI_REGISTER_PM1_CONTROL,  ACPI_BITPOSITION_SCI_ENABLE,            ACPI_BITMASK_SCI_ENABLE},
 	/* ACPI_BITREG_BUS_MASTER_RLD       */   {ACPI_REGISTER_PM1_CONTROL,  ACPI_BITPOSITION_BUS_MASTER_RLD,        ACPI_BITMASK_BUS_MASTER_RLD},
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -372,7 +372,7 @@ acpi_ut_strtoul64 (
 	u32                             base,
 	acpi_integer                    *ret_integer)
 {
-	u32                             this_digit;
+	u32                             this_digit = 0;
 	acpi_integer                    return_value = 0;
 	acpi_integer                    quotient;
 
@@ -380,6 +380,10 @@ acpi_ut_strtoul64 (
 	ACPI_FUNCTION_TRACE ("ut_stroul64");
 
 
+	if ((!string) || !(*string)) {
+		goto error_exit;
+	}
+
 	switch (base) {
 	case ACPI_ANY_BASE:
 	case 10:
@@ -394,7 +398,7 @@ acpi_ut_strtoul64 (
 	/* Skip over any white space in the buffer */
 
 	while (ACPI_IS_SPACE (*string) || *string == '\t') {
-		++string;
+		string++;
 	}
 
 	/*
@@ -403,9 +407,9 @@ acpi_ut_strtoul64 (
 	 */
 	if (base == 0) {
 		if ((*string == '0') &&
-			(ACPI_TOLOWER (*(++string)) == 'x')) {
+			(ACPI_TOLOWER (*(string + 1)) == 'x')) {
 			base = 16;
-			++string;
+			string += 2;
 		}
 		else {
 			base = 10;
@@ -416,10 +420,10 @@ acpi_ut_strtoul64 (
 	 * For hexadecimal base, skip over the leading
 	 * 0 or 0x, if they are present.
 	 */
-	if (base == 16 &&
-		*string == '0' &&
-		ACPI_TOLOWER (*(++string)) == 'x') {
-		string++;
+	if ((base == 16) &&
+		(*string == '0') &&
+		(ACPI_TOLOWER (*(string + 1)) == 'x')) {
+		string += 2;
 	}
 
 	/* Any string left? */
@@ -437,23 +441,27 @@ acpi_ut_strtoul64 (
 			this_digit = ((u8) *string) - '0';
 		}
 		else {
+			if (base == 10) {
+				/* Digit is out of range */
+
+				goto error_exit;
+			}
+
 			this_digit = (u8) ACPI_TOUPPER (*string);
-			if (ACPI_IS_UPPER ((char) this_digit)) {
+			if (ACPI_IS_XDIGIT ((char) this_digit)) {
 				/* Convert ASCII Hex char to value */
 
 				this_digit = this_digit - 'A' + 10;
 			}
 			else {
-				goto error_exit;
+				/*
+				 * We allow non-hex chars, just stop now, same as end-of-string.
+				 * See ACPI spec, string-to-integer conversion.
+				 */
+				break;
 			}
 		}
 
-		/* Check to see if digit is out of range */
-
-		if (this_digit >= base) {
-			goto error_exit;
-		}
-
 		/* Divide the digit into the correct position */
 
 		(void) acpi_ut_short_divide ((ACPI_INTEGER_MAX - (acpi_integer) this_digit),
@@ -464,9 +472,11 @@ acpi_ut_strtoul64 (
 
 		return_value *= base;
 		return_value += this_digit;
-		++string;
+		string++;
 	}
 
+	/* All done, normal exit */
+
 	*ret_integer = return_value;
 	return_ACPI_STATUS (AE_OK);
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -683,7 +683,7 @@ acpi_video_bus_check (
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_video_dir;
+static struct proc_dir_entry	*acpi_video_dir;
 
 /* video devices */
 
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
   fore_200e-objs		+= fore200e_pca_fw.o
   # guess the target endianess to choose the right PCA-200E firmware image
   ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
-    CONFIG_ATM_FORE200E_PCA_FW = $(shell if test -n "`$(CC) -E -dM $(src)/../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo $(obj)/pca200e.bin; else echo $(obj)/pca200e_ecd.bin2; fi)
+    byteorder.h			:= include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h
+    CONFIG_ATM_FORE200E_PCA_FW	:= $(obj)/pca200e$(if $(shell $(CC) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
   endif
 endif
 
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -296,16 +296,16 @@ static inline void __init show_version (
 #endif
 #define UCODE2(x) #x
 
-static u32 __initdata ucode_start = 
+static u32 __devinitdata ucode_start =
 #include UCODE(start)
 ;
 
-static region __initdata ucode_regions[] = {
+static region __devinitdata ucode_regions[] = {
 #include UCODE(regions)
   { 0, 0 }
 };
 
-static u32 __initdata ucode_data[] = {
+static u32 __devinitdata ucode_data[] = {
 #include UCODE(data)
   0xdeadbeef
 };
@@ -345,7 +345,7 @@ static inline u32 rd_plain (const amb_de
 }
 
 static inline void wr_mem (const amb_dev * dev, size_t addr, u32 data) {
-  u32 be = cpu_to_be32 (data);
+  __be32 be = cpu_to_be32 (data);
   PRINTD (DBG_FLOW|DBG_REGS, "wr: %08zx <- %08x b[%08x]", addr, data, be);
 #ifdef AMB_MMIO
   dev->membase[addr / sizeof(u32)] = be;
@@ -356,9 +356,9 @@ static inline void wr_mem (const amb_dev
 
 static inline u32 rd_mem (const amb_dev * dev, size_t addr) {
 #ifdef AMB_MMIO
-  u32 be = dev->membase[addr / sizeof(u32)];
+  __be32 be = dev->membase[addr / sizeof(u32)];
 #else
-  u32 be = inl (dev->iobase + addr);
+  __be32 be = inl (dev->iobase + addr);
 #endif
   u32 data = be32_to_cpu (be);
   PRINTD (DBG_FLOW|DBG_REGS, "rd: %08zx -> %08x b[%08x]", addr, data, be);
@@ -1539,7 +1539,7 @@ static void do_housekeeping (unsigned lo
 
 /********** creation of communication queues **********/
 
-static int __init create_queues (amb_dev * dev, unsigned int cmds,
+static int __devinit create_queues (amb_dev * dev, unsigned int cmds,
 				 unsigned int txs, unsigned int * rxs,
 				 unsigned int * rx_buffer_sizes) {
   unsigned char pool;
@@ -1769,7 +1769,7 @@ static  int decode_loader_result (loader
 	return res;
 }
 
-static int __init do_loader_command (volatile loader_block * lb,
+static int __devinit do_loader_command (volatile loader_block * lb,
 				     const amb_dev * dev, loader_command cmd) {
   
   unsigned long timeout;
@@ -1825,7 +1825,7 @@ static int __init do_loader_command (vol
 
 /* loader: determine loader version */
 
-static int __init get_loader_version (loader_block * lb,
+static int __devinit get_loader_version (loader_block * lb,
 				      const amb_dev * dev, u32 * version) {
   int res;
   
@@ -1841,7 +1841,7 @@ static int __init get_loader_version (lo
 
 /* loader: write memory data blocks */
 
-static int __init loader_write (loader_block * lb,
+static int __devinit loader_write (loader_block * lb,
 				const amb_dev * dev, const u32 * data,
 				u32 address, unsigned int count) {
   unsigned int i;
@@ -1860,7 +1860,7 @@ static int __init loader_write (loader_b
 
 /* loader: verify memory data blocks */
 
-static int __init loader_verify (loader_block * lb,
+static int __devinit loader_verify (loader_block * lb,
 				 const amb_dev * dev, const u32 * data,
 				 u32 address, unsigned int count) {
   unsigned int i;
@@ -1885,7 +1885,7 @@ static int __init loader_verify (loader_
 
 /* loader: start microcode */
 
-static int __init loader_start (loader_block * lb,
+static int __devinit loader_start (loader_block * lb,
 				const amb_dev * dev, u32 address) {
   PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
   
@@ -1961,7 +1961,7 @@ static int amb_reset (amb_dev * dev, int
 
 /********** transfer and start the microcode **********/
 
-static int __init ucode_init (loader_block * lb, amb_dev * dev) {
+static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
   unsigned int i = 0;
   unsigned int total = 0;
   const u32 * pointer = ucode_data;
@@ -2007,11 +2007,11 @@ static int __init ucode_init (loader_blo
 
 /********** give adapter parameters **********/
   
-static inline u32 bus_addr(void * addr) {
+static inline __be32 bus_addr(void * addr) {
     return cpu_to_be32 (virt_to_bus (addr));
 }
 
-static int __init amb_talk (amb_dev * dev) {
+static int __devinit amb_talk (amb_dev * dev) {
   adap_talk_block a;
   unsigned char pool;
   unsigned long timeout;
@@ -2058,7 +2058,7 @@ static int __init amb_talk (amb_dev * de
 }
 
 // get microcode version
-static void __init amb_ucode_version (amb_dev * dev) {
+static void __devinit amb_ucode_version (amb_dev * dev) {
   u32 major;
   u32 minor;
   command cmd;
@@ -2085,7 +2085,7 @@ static u8 bit_swap (u8 byte)
 }
 
 // get end station address
-static void __init amb_esi (amb_dev * dev, u8 * esi) {
+static void __devinit amb_esi (amb_dev * dev, u8 * esi) {
   u32 lower4;
   u16 upper2;
   command cmd;
@@ -2131,7 +2131,7 @@ static void fixup_plx_window (amb_dev *d
 	return;
 }
 
-static int __init amb_init (amb_dev * dev)
+static int __devinit amb_init (amb_dev * dev)
 {
   loader_block lb;
   
@@ -2447,7 +2447,7 @@ static int __init amb_module_init (void)
   amb_check_args();
   
   // get the juice
-  return pci_module_init(&amb_driver);
+  return pci_register_driver(&amb_driver);
 }
 
 /********** module exit **********/
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -342,21 +342,21 @@ typedef struct {
 #define MAX_TRANSFER_DATA 11
 
 typedef struct {
-  u32 address;
-  u32 count;
-  u32 data[MAX_TRANSFER_DATA];
+  __be32 address;
+  __be32 count;
+  __be32 data[MAX_TRANSFER_DATA];
 } transfer_block;
 
 typedef struct {
-  u32 result;
-  u32 command;
+  __be32 result;
+  __be32 command;
   union {
     transfer_block transfer;
-    u32 version;
-    u32 start;
-    u32 data[MAX_COMMAND_DATA];
+    __be32 version;
+    __be32 start;
+    __be32 data[MAX_COMMAND_DATA];
   } payload;
-  u32 valid;
+  __be32 valid;
 } loader_block;
 
 /* command queue */
@@ -366,46 +366,46 @@ typedef struct {
 typedef	struct {
   union {
     struct {
-      u32 vc;
-      u32 flags;
-      u32 rate;
+      __be32 vc;
+      __be32 flags;
+      __be32 rate;
     } open;
     struct {
-      u32 vc;
-      u32 rate;
+      __be32 vc;
+      __be32 rate;
     } modify_rate;
     struct {
-      u32 vc;
-      u32 flags;
+      __be32 vc;
+      __be32 flags;
     } modify_flags;
     struct {
-      u32 vc;
+      __be32 vc;
     } close;
     struct {
-      u32 lower4;
-      u32 upper2;
+      __be32 lower4;
+      __be32 upper2;
     } bia;
     struct {
-      u32 address;
+      __be32 address;
     } suni;
     struct {
-      u32 major;
-      u32 minor;
+      __be32 major;
+      __be32 minor;
     } version;
     struct {
-      u32 read;
-      u32 write;
+      __be32 read;
+      __be32 write;
     } speed;
     struct {
-      u32 flags;
+      __be32 flags;
     } flush;
     struct {
-      u32 address;
-      u32 data;
+      __be32 address;
+      __be32 data;
     } memory;
-    u32 par[3];
+    __be32 par[3];
   } args;
-  u32 request;
+  __be32 request;
 } command;
 
 /* transmit queues and associated structures */
@@ -417,8 +417,8 @@ typedef	struct {
 /* TX is described by 1+ tx_frags followed by a tx_frag_end */
 
 typedef struct {
-  u32 bytes;
-  u32 address;
+  __be32 bytes;
+  __be32 address;
 } tx_frag;
 
 /* apart from handle the fields here are for the adapter to play with
@@ -452,9 +452,9 @@ typedef union {
 /* this "points" to the sequence of fragments and trailer */
 
 typedef	struct {
-  u16	vc;
-  u16	tx_descr_length;
-  u32	tx_descr_addr;
+  __be16	vc;
+  __be16	tx_descr_length;
+  __be32	tx_descr_addr;
 } tx_in;
 
 /* handle is the handle from tx_in */
@@ -471,17 +471,17 @@ typedef	struct {
 
 typedef struct {
   u32  handle;
-  u16  vc;
-  u16  lec_id; // unused
-  u16  status;
-  u16  length;
+  __be16  vc;
+  __be16  lec_id; // unused
+  __be16  status;
+  __be16  length;
 } rx_out;
 
 /* buffer supply structure */
 
 typedef	struct {
   u32 handle;
-  u32 host_address;
+  __be32 host_address;
 } rx_in;
 
 /* This first structure is the area in host memory where the adapter
@@ -495,22 +495,22 @@ typedef	struct {
    adapter. */
 
 typedef struct {
-  u32 command_start;		/* SRB commands completions */
-  u32 command_end;		/* SRB commands completions */
-  u32 tx_start;
-  u32 tx_end;
-  u32 txcom_start;		/* tx completions */
-  u32 txcom_end;		/* tx completions */
+  __be32 command_start;		/* SRB commands completions */
+  __be32 command_end;		/* SRB commands completions */
+  __be32 tx_start;
+  __be32 tx_end;
+  __be32 txcom_start;		/* tx completions */
+  __be32 txcom_end;		/* tx completions */
   struct {
-    u32 buffer_start;
-    u32 buffer_end;
+    __be32 buffer_start;
+    __be32 buffer_end;
     u32 buffer_q_get;
     u32 buffer_q_end;
     u32 buffer_aptr;
-    u32 rx_start;		/* rx completions */
-    u32 rx_end;
+    __be32 rx_start;		/* rx completions */
+    __be32 rx_end;
     u32 rx_ptr;
-    u32 buffer_size;		/* size of host buffer */
+    __be32 buffer_size;		/* size of host buffer */
   } rec_struct[NUM_RX_POOLS];
 #ifdef AMB_NEW_MICROCODE
   u16 init_flags;
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -67,7 +67,7 @@ static int atmtcp_send_control(struct at
 	*(struct atm_vcc **) &new_msg->vcc = vcc;
 	old_test = test_bit(flag,&vcc->flags);
 	out_vcc->push(out_vcc,skb);
-	add_wait_queue(vcc->sk->sk_sleep, &wait);
+	add_wait_queue(sk_atm(vcc)->sk_sleep, &wait);
 	while (test_bit(flag,&vcc->flags) == old_test) {
 		mb();
 		out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
@@ -79,7 +79,7 @@ static int atmtcp_send_control(struct at
 		schedule();
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(vcc->sk->sk_sleep, &wait);
+	remove_wait_queue(sk_atm(vcc)->sk_sleep, &wait);
 	return error;
 }
 
@@ -91,7 +91,7 @@ static int atmtcp_recv_control(const str
 	vcc->vpi = msg->addr.sap_addr.vpi;
 	vcc->vci = msg->addr.sap_addr.vci;
 	vcc->qos = msg->qos;
-	vcc->sk->sk_err = -msg->result;
+	sk_atm(vcc)->sk_err = -msg->result;
 	switch (msg->type) {
 	    case ATMTCP_CTRL_OPEN:
 		change_bit(ATM_VF_READY,&vcc->flags);
@@ -104,7 +104,7 @@ static int atmtcp_recv_control(const str
 		    msg->type);
 		return -EINVAL;
 	}
-	wake_up(vcc->sk->sk_sleep);
+	wake_up(sk_atm(vcc)->sk_sleep);
 	return 0;
 }
 
@@ -135,7 +135,7 @@ static int atmtcp_v_open(struct atm_vcc 
 	clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */
 	error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
 	if (error) return error;
-	return -vcc->sk->sk_err;
+	return -sk_atm(vcc)->sk_err;
 }
 
 
@@ -267,7 +267,7 @@ static void atmtcp_c_close(struct atm_vc
 			walk = atm_sk(s);
 			if (walk->dev != atmtcp_dev)
 				continue;
-			wake_up(walk->sk->sk_sleep);
+			wake_up(s->sk_sleep);
 		}
 	}
 	read_unlock(&vcc_sklist_lock);
@@ -417,7 +417,7 @@ static int atmtcp_attach(struct atm_vcc 
 	}
 	PRIV(dev)->vcc = vcc;
 	vcc->dev = &atmtcp_control_dev;
-	vcc_insert_socket(vcc->sk);
+	vcc_insert_socket(sk_atm(vcc));
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 	vcc->dev_data = dev;
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -59,7 +59,6 @@
  * - doesn't support OAM cells
  * - eni_put_free may hang if not putting memory fragments that _complete_
  *   2^n block (never happens in real life, though)
- * - keeps IRQ even if initialization fails
  */
 
 
@@ -1802,22 +1801,22 @@ static int __devinit eni_start(struct at
 	if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
 		    dev->number,eni_dev->irq);
-		return -EAGAIN;
+		error = -EAGAIN;
+		goto out;
 	}
-	/* @@@ should release IRQ on error */
 	pci_set_master(eni_dev->pci_dev);
 	if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND,
 	    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
 	    (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+"
 		    "master (0x%02x)\n",dev->number,error);
-		return error;
+		goto free_irq;
 	}
 	if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL,
 	    END_SWAP_DMA))) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap "
 		    "(0x%02x)\n",dev->number,error);
-		return error;
+		goto free_irq;
 	}
 	/* determine addresses of internal tables */
 	eni_dev->vci = eni_dev->ram;
@@ -1839,7 +1838,8 @@ static int __devinit eni_start(struct at
 	if (!eni_dev->free_list) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n",
 		    dev->number);
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto free_irq;
 	}
 	eni_dev->free_len = 0;
 	eni_put_free(eni_dev,buf,buffer_mem);
@@ -1855,17 +1855,26 @@ static int __devinit eni_start(struct at
 	 */
 	eni_out(0xffffffff,MID_IE);
 	error = start_tx(dev);
-	if (error) return error;
+	if (error) goto free_list;
 	error = start_rx(dev);
-	if (error) return error;
+	if (error) goto free_list;
 	error = dev->phy->start(dev);
-	if (error) return error;
+	if (error) goto free_list;
 	eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) |
 	    MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE,
 	    MID_MC_S);
 	    /* Tonga uses SBus INTReq1 */
 	(void) eni_in(MID_ISA); /* clear Midway interrupts */
 	return 0;
+
+free_list:
+	kfree(eni_dev->free_list);
+
+free_irq:
+	free_irq(eni_dev->irq, eni_dev);
+
+out:
+	return error;
 }
 
 
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -2034,7 +2034,7 @@ static int __init firestream_init_module
 	int error;
 
 	func_enter ();
-	error = pci_module_init(&firestream_driver);
+	error = pci_register_driver(&firestream_driver);
 	func_exit ();
 	return error;
 }
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -96,10 +96,6 @@
 
 #define FORE200E_NEXT_ENTRY(index, modulo)         (index = ++(index) % (modulo))
 
-
-#define MSECS(ms)  (((ms)*HZ/1000)+1)
-
-
 #if 1
 #define ASSERT(expr)     if (!(expr)) { \
 			     printk(FORE200E "assertion failed! %s[%d]: %s\n", \
@@ -114,7 +110,7 @@
 static const struct atmdev_ops   fore200e_ops;
 static const struct fore200e_bus fore200e_bus[];
 
-static struct fore200e* fore200e_boards = NULL;
+static LIST_HEAD(fore200e_boards);
 
 
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
@@ -246,7 +242,7 @@ fore200e_chunk_free(struct fore200e* for
 static void
 fore200e_spin(int msecs)
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     while (time_before(jiffies, timeout));
 }
 
@@ -254,7 +250,7 @@ fore200e_spin(int msecs)
 static int
 fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     int           ok;
 
     mb();
@@ -278,7 +274,7 @@ fore200e_poll(struct fore200e* fore200e,
 static int
 fore200e_io_poll(struct fore200e* fore200e, volatile u32 __iomem *addr, u32 val, int msecs)
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     int           ok;
 
     do {
@@ -387,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore2
     switch(fore200e->state) {
 
     case FORE200E_STATE_COMPLETE:
-	if (fore200e->stats)
-	    kfree(fore200e->stats);
+	kfree(fore200e->stats);
 
     case FORE200E_STATE_IRQ:
 	free_irq(fore200e->irq, fore200e->atm_dev);
@@ -637,39 +632,6 @@ fore200e_pca_configure(struct fore200e* 
 }
 
 
-static struct fore200e* __init
-fore200e_pca_detect(const struct fore200e_bus* bus, int index)
-{
-    struct fore200e* fore200e;
-    struct pci_dev*  pci_dev = NULL;
-    int              count = index;
-    
-    do {
-	pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev);
-	if (pci_dev == NULL)
-	    return NULL;
-    } while (count--);
-
-    if (pci_enable_device(pci_dev))
-	return NULL;
-    
-    fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
-    if (fore200e == NULL)
-	return NULL;
-
-    fore200e->bus       = bus;
-    fore200e->bus_dev   = pci_dev;    
-    fore200e->irq       = pci_dev->irq;
-    fore200e->phys_base = pci_resource_start(pci_dev, 0);
-
-    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
-
-    pci_set_master(pci_dev);
-
-    return fore200e;
-}
-
-
 static int __init
 fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
 {
@@ -1000,8 +962,7 @@ fore200e_tx_irq(struct fore200e* fore200
 		entry, txq->tail, entry->vc_map, entry->skb);
 
 	/* free copy of misaligned data */
-	if (entry->data)
-	    kfree(entry->data);
+	kfree(entry->data);
 	
 	/* remove DMA mapping */
 	fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
@@ -1027,7 +988,7 @@ fore200e_tx_irq(struct fore200e* fore200
 		/* when a vcc is closed, some PDUs may be still pending in the tx queue.
 		   if the same vcc is immediately re-opened, those pending PDUs must
 		   not be popped after the completion of their emission, as they refer
-		   to the prior incarnation of that vcc. otherwise, vcc->sk->sk_wmem_alloc
+		   to the prior incarnation of that vcc. otherwise, sk_atm(vcc)->sk_wmem_alloc
 		   would be decremented by the size of the (unrelated) skb, possibly
 		   leading to a negative sk->sk_wmem_alloc count, ultimately freezing the vcc.
 		   we thus bind the tx entry to the current incarnation of the vcc
@@ -1054,8 +1015,8 @@ fore200e_tx_irq(struct fore200e* fore200
 		}
 #if 1
 		/* race fixed by the above incarnation mechanism, but... */
-		if (atomic_read(&vcc->sk->sk_wmem_alloc) < 0) {
-		    atomic_set(&vcc->sk->sk_wmem_alloc, 0);
+		if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) {
+		    atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0);
 		}
 #endif
 		/* check error condition */
@@ -1258,12 +1219,12 @@ fore200e_push_rpd(struct fore200e* fore2
 	return -ENOMEM;
     }
 
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
 
     vcc->push(vcc, skb);
     atomic_inc(&vcc->stats->rx);
 
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
 
     return 0;
 }
@@ -1700,7 +1661,7 @@ fore200e_send(struct atm_vcc *vcc, struc
     unsigned long           flags;
 
     ASSERT(vcc);
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
     ASSERT(fore200e);
     ASSERT(fore200e_vcc);
 
@@ -2596,7 +2557,7 @@ static int __init
 fore200e_monitor_getc(struct fore200e* fore200e)
 {
     struct cp_monitor __iomem * monitor = fore200e->cp_monitor;
-    unsigned long      timeout = jiffies + MSECS(50);
+    unsigned long      timeout = jiffies + msecs_to_jiffies(50);
     int                c;
 
     while (time_before(jiffies, timeout)) {
@@ -2768,20 +2729,105 @@ fore200e_init(struct fore200e* fore200e)
     return 0;
 }
 
+
+static int __devinit
+fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+{
+    const struct fore200e_bus* bus = (struct fore200e_bus*) pci_ent->driver_data;
+    struct fore200e* fore200e;
+    int err = 0;
+    static int index = 0;
+
+    if (pci_enable_device(pci_dev)) {
+	err = -EINVAL;
+	goto out;
+    }
+    
+    fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+    if (fore200e == NULL) {
+	err = -ENOMEM;
+	goto out_disable;
+    }
+
+    fore200e->bus       = bus;
+    fore200e->bus_dev   = pci_dev;    
+    fore200e->irq       = pci_dev->irq;
+    fore200e->phys_base = pci_resource_start(pci_dev, 0);
+
+    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+
+    pci_set_master(pci_dev);
+
+    printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
+	   fore200e->bus->model_name, 
+	   fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
+
+    sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+    err = fore200e_init(fore200e);
+    if (err < 0) {
+	fore200e_shutdown(fore200e);
+	goto out_free;
+    }
+
+    ++index;
+    pci_set_drvdata(pci_dev, fore200e);
+
+out:
+    return err;
+
+out_free:
+    kfree(fore200e);
+out_disable:
+    pci_disable_device(pci_dev);
+    goto out;
+}
+
+
+static void __devexit fore200e_pca_remove_one(struct pci_dev *pci_dev)
+{
+    struct fore200e *fore200e;
+
+    fore200e = pci_get_drvdata(pci_dev);
+
+    fore200e_shutdown(fore200e);
+    kfree(fore200e);
+    pci_disable_device(pci_dev);
+}
+
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+static struct pci_device_id fore200e_pca_tbl[] = {
+    { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID,
+      0, 0, (unsigned long) &fore200e_bus[0] },
+    { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, fore200e_pca_tbl);
+
+static struct pci_driver fore200e_pca_driver = {
+    .name =     "fore_200e",
+    .probe =    fore200e_pca_detect,
+    .remove =   __devexit_p(fore200e_pca_remove_one),
+    .id_table = fore200e_pca_tbl,
+};
+#endif
+
+
 static int __init
 fore200e_module_init(void)
 {
     const struct fore200e_bus* bus;
     struct       fore200e*     fore200e;
-    int                        index, link;
+    int                        index;
 
     printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
     /* for each configured bus interface */
-    for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
+    for (bus = fore200e_bus; bus->model_name; bus++) {
 
 	/* detect all boards present on that bus */
-	for (index = 0; (fore200e = bus->detect(bus, index)); index++) {
+	for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
 	    
 	    printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
 		   fore200e->bus->model_name, 
@@ -2795,15 +2841,18 @@ fore200e_module_init(void)
 		break;
 	    }
 
-	    link++;
-
-	    fore200e->next  = fore200e_boards;
-	    fore200e_boards = fore200e;
+	    list_add(&fore200e->entry, &fore200e_boards);
 	}
     }
 
-    if (link)
-        return 0;
+#ifdef CONFIG_ATM_FORE200E_PCA
+    if (!pci_register_driver(&fore200e_pca_driver))
+	return 0;
+#endif
+
+    if (!list_empty(&fore200e_boards))
+	return 0;
+
     return -ENODEV;
 }
 
@@ -2811,11 +2860,14 @@ fore200e_module_init(void)
 static void __exit
 fore200e_module_cleanup(void)
 {
-    while (fore200e_boards) {
-        struct fore200e* fore200e = fore200e_boards;
+    struct fore200e *fore200e, *next;
 
+#ifdef CONFIG_ATM_FORE200E_PCA
+    pci_unregister_driver(&fore200e_pca_driver);
+#endif
+
+    list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
 	fore200e_shutdown(fore200e);
-	fore200e_boards = fore200e->next;
 	kfree(fore200e);
     }
     DPRINTK(1, "module being removed\n");
@@ -3150,7 +3202,7 @@ static const struct fore200e_bus fore200
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
-      fore200e_pca_detect,
+      NULL,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -841,7 +841,7 @@ typedef struct fore200e_vc_map {
 /* per-device data */
 
 typedef struct fore200e {
-    struct       fore200e*     next;                   /* next device                        */
+    struct       list_head     entry;                  /* next device                        */
     const struct fore200e_bus* bus;                    /* bus-dependent code and data        */
     union        fore200e_regs regs;                   /* bus-dependent registers            */
     struct       atm_dev*      atm_dev;                /* ATM device                         */
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -70,6 +70,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
@@ -371,7 +372,7 @@ he_init_one(struct pci_dev *pci_dev, con
 
 	if (pci_enable_device(pci_dev))
 		return -EIO;
-	if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0) {
+	if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK) != 0) {
 		printk(KERN_WARNING "he: no suitable dma available\n");
 		err = -EIO;
 		goto init_one_failure;
@@ -411,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, con
 init_one_failure:
 	if (atm_dev)
 		atm_dev_deregister(atm_dev);
-	if (he_dev)
-		kfree(he_dev);
+	kfree(he_dev);
 	pci_disable_device(pci_dev);
 	return err;
 }
@@ -2533,8 +2533,7 @@ he_open(struct atm_vcc *vcc)
 open_failed:
 
 	if (err) {
-		if (he_vcc)
-			kfree(he_vcc);
+		kfree(he_vcc);
 		clear_bit(ATM_VF_ADDR, &vcc->flags);
 	}
 	else
@@ -2610,7 +2609,7 @@ he_close(struct atm_vcc *vcc)
 		 * TBRQ, the host issues the close command to the adapter.
 		 */
 
-		while (((tx_inuse = atomic_read(&vcc->sk->sk_wmem_alloc)) > 0) &&
+		while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 0) &&
 		       (retry < MAX_RETRY)) {
 			msleep(sleep);
 			if (sleep < 250)
@@ -3079,7 +3078,7 @@ static struct pci_driver he_driver = {
 
 static int __init he_init(void)
 {
-	return pci_module_init(&he_driver);
+	return pci_register_driver(&he_driver);
 }
 
 static void __exit he_cleanup(void)
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -380,8 +380,6 @@ struct he_vcc
 #define PCI_VENDOR_ID_FORE	0x1127
 #define PCI_DEVICE_ID_FORE_HE	0x400
 
-#define HE_DMA_MASK		0xffffffff
-
 #define GEN_CNTL_0				0x40
 #define  INT_PROC_ENBL		(1<<25)
 #define  SLAVE_ENDIAN_MODE	(1<<16)
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -2938,7 +2938,7 @@ static int __init hrz_module_init (void)
   hrz_check_args();
   
   // get the juice
-  return pci_module_init(&hrz_driver);
+  return pci_register_driver(&hrz_driver);
 }
 
 /********** module exit **********/
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -727,10 +727,11 @@ push_on_scq(struct idt77252_dev *card, s
 	spin_lock_irqsave(&vc->lock, flags);
 	if (vc->estimator) {
 		struct atm_vcc *vcc = vc->tx_vcc;
+		struct sock *sk = sk_atm(vcc);
 
 		vc->estimator->cells += (skb->len + 47) / 48;
-		if (atomic_read(&vcc->sk->sk_wmem_alloc) >
-		    (vcc->sk->sk_sndbuf >> 1)) {
+		if (atomic_read(&sk->sk_wmem_alloc) >
+		    (sk->sk_sndbuf >> 1)) {
 			u32 cps = vc->estimator->maxcps;
 
 			vc->estimator->cps = cps;
@@ -1325,7 +1326,7 @@ idt77252_rx_raw(struct idt77252_dev *car
 			goto drop;
 		}
 
-		if ((vcc->sk != NULL) && !atm_charge(vcc, sb->truesize)) {
+		if (!atm_charge(vcc, sb->truesize)) {
 			RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n",
 				 card->name);
 			dev_kfree_skb(sb);
@@ -2029,7 +2030,7 @@ idt77252_send_oam(struct atm_vcc *vcc, v
 		atomic_inc(&vcc->stats->tx_err);
 		return -ENOMEM;
 	}
-	atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 
 	memcpy(skb_put(skb, 52), cell, 52);
 
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -1778,16 +1778,18 @@ static int open_tx(struct atm_vcc *vcc) 
         if (ia_vcc->pcr < iadev->rate_limit)
            skb_queue_head_init (&ia_vcc->txing_skb);
         if (ia_vcc->pcr < iadev->rate_limit) {
-           if (vcc->qos.txtp.max_sdu != 0) {
+	   struct sock *sk = sk_atm(vcc);
+
+	   if (vcc->qos.txtp.max_sdu != 0) {
                if (ia_vcc->pcr > 60000)
-                  vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 5;
+                  sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 5;
                else if (ia_vcc->pcr > 2000)
-                  vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 4;
+                  sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 4;
                else
-                 vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 3;
+                 sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 3;
            }
            else
-             vcc->sk->sk_sndbuf = 24576;
+             sk->sk_sndbuf = 24576;
         }
            
 	vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR;  
@@ -3244,8 +3246,8 @@ static void __devexit ia_remove_one(stru
 	iadev_count--;
 	ia_dev[iadev_count] = NULL;
 	_ia_dev[iadev_count] = NULL;
+	IF_EVENT(printk("deregistering iav at (itf:%d)\n", dev->number);)
 	atm_dev_deregister(dev);
-	IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
 
       	iounmap(iadev->base);  
 	pci_disable_device(pdev);
@@ -3274,7 +3276,7 @@ static int __init ia_module_init(void)
 {
 	int ret;
 
-	ret = pci_module_init(&ia_driver);
+	ret = pci_register_driver(&ia_driver);
 	if (ret >= 0) {
 		ia_timer.expires = jiffies + 3*HZ;
 		add_timer(&ia_timer); 
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -61,9 +61,11 @@
 #include <asm/byteorder.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 
 /* -------------------- TUNABLE PARAMATERS: */
 
@@ -566,7 +568,7 @@ static int __init sram_test_word(
 	return -EIO;
 }
 
-static int __init sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
+static int __devinit sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
 {
 	int offset, result = 0;
 	for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4)
@@ -574,7 +576,7 @@ static int __init sram_test_pass(const s
 	return result;
 }
 
-static int __init sram_test_and_clear(const struct lanai_dev *lanai)
+static int __devinit sram_test_and_clear(const struct lanai_dev *lanai)
 {
 #ifdef FULL_MEMORY_TEST
 	int result;
@@ -650,7 +652,7 @@ static inline u32 cardvcc_read(const str
 	enum lanai_vcc_offset offset)
 {
 	u32 val;
-	APRINTK(lvcc->vbase != 0, "cardvcc_read: unbound vcc!\n");
+	APRINTK(lvcc->vbase != NULL, "cardvcc_read: unbound vcc!\n");
 	val= readl(lvcc->vbase + offset);
 	RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n",
 	    lvcc->vci, (int) offset, val);
@@ -660,7 +662,7 @@ static inline u32 cardvcc_read(const str
 static inline void cardvcc_write(const struct lanai_vcc *lvcc,
 	u32 val, enum lanai_vcc_offset offset)
 {
-	APRINTK(lvcc->vbase != 0, "cardvcc_write: unbound vcc!\n");
+	APRINTK(lvcc->vbase != NULL, "cardvcc_write: unbound vcc!\n");
 	APRINTK((val & ~0xFFFF) == 0,
 	    "cardvcc_write: bad val 0x%X (vci=%d, addr=0x%02X)\n",
 	    (unsigned int) val, lvcc->vci, (unsigned int) offset);
@@ -748,7 +750,7 @@ static void host_vcc_start_tx(const stru
 /* Shutdown receiving on card */
 static void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc)
 {
-	if (lvcc->vbase == 0)		/* We were never bound to a VCI */
+	if (lvcc->vbase == NULL)	/* We were never bound to a VCI */
 		return;
 	/* 15.1.1 - set to trashing, wait one cell time (15us) */
 	cardvcc_write(lvcc,
@@ -779,7 +781,7 @@ static void lanai_shutdown_tx_vci(struct
 	int read, write, lastread = -1;
 	APRINTK(!in_interrupt(),
 	    "lanai_shutdown_tx_vci called w/o process context!\n");
-	if (lvcc->vbase == 0)		/* We were never bound to a VCI */
+	if (lvcc->vbase == NULL)	/* We were never bound to a VCI */
 		return;
 	/* 15.2.1 - wait for queue to drain */
 	while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL)
@@ -860,7 +862,7 @@ static inline void aal0_buffer_free(stru
 #ifndef READ_EEPROM
 
 /* Stub functions to use if EEPROM reading is disabled */
-static int __init eeprom_read(struct lanai_dev *lanai)
+static int __devinit eeprom_read(struct lanai_dev *lanai)
 {
 	printk(KERN_INFO DEV_LABEL "(itf %d): *NOT* reading EEPROM\n",
 	    lanai->number);
@@ -868,7 +870,7 @@ static int __init eeprom_read(struct lan
 	return 0;
 }
 
-static int __init eeprom_validate(struct lanai_dev *lanai)
+static int __devinit eeprom_validate(struct lanai_dev *lanai)
 {
 	lanai->serialno = 0;
 	lanai->magicno = EEPROM_MAGIC_VALUE;
@@ -877,7 +879,7 @@ static int __init eeprom_validate(struct
 
 #else /* READ_EEPROM */
 
-static int __init eeprom_read(struct lanai_dev *lanai)
+static int __devinit eeprom_read(struct lanai_dev *lanai)
 {
 	int i, address;
 	u8 data;
@@ -953,7 +955,7 @@ static inline u32 eeprom_be4(const struc
 }
 
 /* Checksum/validate EEPROM contents */
-static int __init eeprom_validate(struct lanai_dev *lanai)
+static int __devinit eeprom_validate(struct lanai_dev *lanai)
 {
 	int i, s;
 	u32 v;
@@ -1449,7 +1451,7 @@ static void vcc_rx_aal0(struct lanai_dev
 #include <linux/vmalloc.h>
 #endif
 
-static int __init vcc_table_allocate(struct lanai_dev *lanai)
+static int __devinit vcc_table_allocate(struct lanai_dev *lanai)
 {
 #ifdef VCCTABLE_GETFREEPAGE
 	APRINTK((lanai->num_vci) * sizeof(struct lanai_vcc *) <= PAGE_SIZE,
@@ -1544,7 +1546,7 @@ static int lanai_setup_tx_vci(struct lan
 static inline void host_vcc_bind(struct lanai_dev *lanai,
 	struct lanai_vcc *lvcc, vci_t vci)
 {
-	if (lvcc->vbase != 0)
+	if (lvcc->vbase != NULL)
 		return;    /* We already were bound in the other direction */
 	DPRINTK("Binding vci %d\n", vci);
 #ifdef USE_POWERDOWN
@@ -1562,7 +1564,7 @@ static inline void host_vcc_bind(struct 
 static inline void host_vcc_unbind(struct lanai_dev *lanai,
 	struct lanai_vcc *lvcc)
 {
-	if (lvcc->vbase == 0)
+	if (lvcc->vbase == NULL)
 		return;	/* This vcc was never bound */
 	DPRINTK("Unbinding vci %d\n", lvcc->vci);
 	lvcc->vbase = NULL;
@@ -1596,7 +1598,7 @@ static void lanai_reset(struct lanai_dev
 /*
  * Allocate service buffer and tell card about it
  */
-static int __init service_buffer_allocate(struct lanai_dev *lanai)
+static int __devinit service_buffer_allocate(struct lanai_dev *lanai)
 {
 	lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 8,
 	    lanai->pci);
@@ -1952,7 +1954,7 @@ static int check_board_id_and_rev(const 
 
 /* -------------------- PCI INITIALIZATION/SHUTDOWN: */
 
-static int __init lanai_pci_start(struct lanai_dev *lanai)
+static int __devinit lanai_pci_start(struct lanai_dev *lanai)
 {
 	struct pci_dev *pci = lanai->pci;
 	int result;
@@ -1964,7 +1966,7 @@ static int __init lanai_pci_start(struct
 		return -ENXIO;
 	}
 	pci_set_master(pci);
-	if (pci_set_dma_mask(pci, 0xFFFFFFFF) != 0) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) != 0) {
 		printk(KERN_WARNING DEV_LABEL
 		    "(itf %d): No suitable DMA available.\n", lanai->number);
 		return -EBUSY;
@@ -2148,7 +2150,7 @@ static inline void lanai_cbr_shutdown(st
 /* -------------------- OPERATIONS: */
 
 /* setup a newly detected device */
-static int __init lanai_dev_open(struct atm_dev *atmdev)
+static int __devinit lanai_dev_open(struct atm_dev *atmdev)
 {
 	struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data;
 	unsigned long raw_base;
@@ -2179,7 +2181,7 @@ static int __init lanai_dev_open(struct 
 		goto error;
 	raw_base = lanai->pci->resource[0].start;
 	lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE);
-	if (lanai->base == 0) {
+	if (lanai->base == NULL) {
 		printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n");
 		goto error_pci;
 	}
@@ -2333,7 +2335,7 @@ static void lanai_close(struct atm_vcc *
 	}
 	if (lvcc->tx.atmvcc == atmvcc) {
 		if (atmvcc == lanai->cbrvcc) {
-			if (lvcc->vbase != 0)
+			if (lvcc->vbase != NULL)
 				lanai_cbr_shutdown(lanai);
 			lanai->cbrvcc = NULL;
 		}
@@ -2524,7 +2526,7 @@ static int lanai_send(struct atm_vcc *at
 	struct lanai_vcc *lvcc = (struct lanai_vcc *) atmvcc->dev_data;
 	struct lanai_dev *lanai = (struct lanai_dev *) atmvcc->dev->dev_data;
 	unsigned long flags;
-	if (unlikely(lvcc == NULL || lvcc->vbase == 0 ||
+	if (unlikely(lvcc == NULL || lvcc->vbase == NULL ||
 	      lvcc->tx.atmvcc != atmvcc))
 		goto einval;
 #ifdef DEBUG
@@ -2746,7 +2748,7 @@ static int __init lanai_module_init(void
 {
 	int x;
 
-	x = pci_module_init(&lanai_driver);
+	x = pci_register_driver(&lanai_driver);
 	if (x != 0)
 		printk(KERN_ERR DEV_LABEL ": no adapter found\n");
 	return x;
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -350,7 +350,7 @@ static void __devexit nicstar_remove_one
    kfree(card->rsq.org);
    kfree(card->tsq.org);
    free_irq(card->pcidev->irq, card);
-   iounmap((void *) card->membase);
+   iounmap(card->membase);
    kfree(card);
 }
 
@@ -381,7 +381,7 @@ static int __init nicstar_init(void)
 
    XPRINTK("nicstar: nicstar_init() called.\n");
 
-   error = pci_module_init(&nicstar_driver);
+   error = pci_register_driver(&nicstar_driver);
    
    TXPRINTK("nicstar: TX debug enabled.\n");
    RXPRINTK("nicstar: RX debug enabled.\n");
@@ -676,10 +676,10 @@ static int __devinit ns_init_card(int i,
    PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
       
    /* Initialize SCQ0, the only VBR SCQ used */
-   card->scq1 = (scq_info *) NULL;
-   card->scq2 = (scq_info *) NULL;
+   card->scq1 = NULL;
+   card->scq2 = NULL;
    card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
-   if (card->scq0 == (scq_info *) NULL)
+   if (card->scq0 == NULL)
    {
       printk("nicstar%d: can't get SCQ0.\n", i);
       error = 12;
@@ -976,7 +976,7 @@ static void __devinit ns_init_card_error
    }
    if (error >= 4)
    {
-      iounmap((void *) card->membase);
+      iounmap(card->membase);
    }
    if (error >= 3)
    {
@@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 s
    int i;
 
    if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
-      return (scq_info *) NULL;
+      return NULL;
 
    scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
-   if (scq == (scq_info *) NULL)
-      return (scq_info *) NULL;
+   if (scq == NULL)
+      return NULL;
    scq->org = kmalloc(2 * size, GFP_KERNEL);
    if (scq->org == NULL)
    {
       kfree(scq);
-      return (scq_info *) NULL;
+      return NULL;
    }
    scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
                                           (size / NS_SCQE_SIZE), GFP_KERNEL);
-   if (scq->skb == (struct sk_buff **) NULL)
+   if (scq->skb == NULL)
    {
       kfree(scq->org);
       kfree(scq);
-      return (scq_info *) NULL;
+      return NULL;
    }
    scq->num_entries = size / NS_SCQE_SIZE;
    scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
@@ -1498,7 +1498,7 @@ static int ns_open(struct atm_vcc *vcc)
          vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
 
          scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
-         if (scq == (scq_info *) NULL)
+         if (scq == NULL)
          {
             PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
             card->scd2vc[frscdi] = NULL;
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -739,8 +739,8 @@ typedef struct skb_pool
 
 typedef struct vc_map
 {
-   volatile int tx:1;				/* TX vc? */
-   volatile int rx:1;				/* RX vc? */
+   volatile unsigned int tx:1;				/* TX vc? */
+   volatile unsigned int rx:1;				/* RX vc? */
    struct atm_vcc *tx_vcc, *rx_vcc;
    struct sk_buff *rx_iov;		/* RX iovector skb */
    scq_info *scq;			/* To keep track of the SCQ */
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -411,7 +411,7 @@ printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 
 #if 0
 printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
 #endif
-		size = error ? 0 : ntohs(((u16 *) skb->data)[cells*
+		size = error ? 0 : ntohs(((__be16 *) skb->data)[cells*
 		    ATM_CELL_PAYLOAD/sizeof(u16)-3]);
 		EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size);
 		chan = (here[3] & uPD98401_AAL5_CHAN) >>
@@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc
 		zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
 		dealloc_shaper(vcc->dev,zatm_vcc->shaper);
 	}
-	if (zatm_vcc->ring) kfree(zatm_vcc->ring);
+	kfree(zatm_vcc->ring);
 }
 
 
@@ -1090,7 +1090,7 @@ static irqreturn_t zatm_int(int irq,void
 /*----------------------------- (E)EPROM access -----------------------------*/
 
 
-static void __init eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
+static void __devinit eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
     unsigned short cmd)
 {
 	int error;
@@ -1101,7 +1101,7 @@ static void __init eprom_set(struct zatm
 }
 
 
-static unsigned long __init eprom_get(struct zatm_dev *zatm_dev,
+static unsigned long __devinit eprom_get(struct zatm_dev *zatm_dev,
     unsigned short cmd)
 {
 	unsigned int value;
@@ -1114,7 +1114,7 @@ static unsigned long __init eprom_get(st
 }
 
 
-static void __init eprom_put_bits(struct zatm_dev *zatm_dev,
+static void __devinit eprom_put_bits(struct zatm_dev *zatm_dev,
     unsigned long data,int bits,unsigned short cmd)
 {
 	unsigned long value;
@@ -1129,7 +1129,7 @@ static void __init eprom_put_bits(struct
 }
 
 
-static void __init eprom_get_byte(struct zatm_dev *zatm_dev,
+static void __devinit eprom_get_byte(struct zatm_dev *zatm_dev,
     unsigned char *byte,unsigned short cmd)
 {
 	int i;
@@ -1145,7 +1145,7 @@ static void __init eprom_get_byte(struct
 }
 
 
-static unsigned char __init eprom_try_esi(struct atm_dev *dev,
+static unsigned char __devinit eprom_try_esi(struct atm_dev *dev,
     unsigned short cmd,int offset,int swap)
 {
 	unsigned char buf[ZEPROM_SIZE];
@@ -1166,7 +1166,7 @@ static unsigned char __init eprom_try_es
 }
 
 
-static void __init eprom_get_esi(struct atm_dev *dev)
+static void __devinit eprom_get_esi(struct atm_dev *dev)
 {
 	if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return;
 	(void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0);
@@ -1339,12 +1339,9 @@ static int __init zatm_start(struct atm_
 	return 0;
     out:
 	for (i = 0; i < NR_MBX; i++)
-		if (zatm_dev->mbx_start[i] != 0)
-			kfree((void *) zatm_dev->mbx_start[i]);
-	if (zatm_dev->rx_map != NULL)
-		kfree(zatm_dev->rx_map);
-	if (zatm_dev->tx_map != NULL)
-		kfree(zatm_dev->tx_map);
+		kfree(zatm_dev->mbx_start[i]);
+	kfree(zatm_dev->rx_map);
+	kfree(zatm_dev->tx_map);
 	free_irq(zatm_dev->irq, dev);
 	return error;
 }
@@ -1639,7 +1636,7 @@ static struct pci_driver zatm_driver = {
 
 static int __init zatm_init_module(void)
 {
-	return pci_module_init(&zatm_driver);
+	return pci_register_driver(&zatm_driver);
 }
 
 module_init(zatm_init_module);
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o sys.o interface.o bus.o \
+obj-y			:= core.o sys.o bus.o \
 			   driver.o class.o class_simple.o platform.o \
 			   cpu.o firmware.o init.o map.o dmapool.o \
 			   attribute_container.o transport_class.o
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -65,7 +65,7 @@ static struct sysfs_ops driver_sysfs_ops
 static void driver_release(struct kobject * kobj)
 {
 	struct device_driver * drv = to_driver(kobj);
-	up(&drv->unload_sem);
+	complete(&drv->unloaded);
 }
 
 static struct kobj_type ktype_driver = {
@@ -390,7 +390,6 @@ void device_release_driver(struct device
 		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
 		sysfs_remove_link(&dev->kobj, "driver");
 		list_del_init(&dev->driver_list);
-		device_detach_shutdown(dev);
 		if (drv->remove)
 			drv->remove(dev);
 		dev->driver = NULL;
@@ -405,9 +404,8 @@ void device_release_driver(struct device
 
 static void driver_detach(struct device_driver * drv)
 {
-	struct list_head * entry, * next;
-	list_for_each_safe(entry, next, &drv->devices) {
-		struct device * dev = container_of(entry, struct device, driver_list);
+	while (!list_empty(&drv->devices)) {
+		struct device * dev = container_of(drv->devices.next, struct device, driver_list);
 		device_release_driver(dev);
 	}
 }
@@ -465,6 +463,7 @@ int bus_add_device(struct device * dev)
 		up_write(&dev->bus->subsys.rwsem);
 		device_add_attrs(bus, dev);
 		sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
+		sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
 	}
 	return error;
 }
@@ -481,6 +480,7 @@ int bus_add_device(struct device * dev)
 void bus_remove_device(struct device * dev)
 {
 	if (dev->bus) {
+		sysfs_remove_link(&dev->kobj, "bus");
 		sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
 		device_remove_attrs(dev->bus, dev);
 		down_write(&dev->bus->subsys.rwsem);
diff --git a/drivers/base/class.c b/drivers/base/class.c
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/kdev_t.h>
 #include "base.h"
 
 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
@@ -139,6 +140,7 @@ int class_register(struct class * cls)
 
 	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->interfaces);
+	init_MUTEX(&cls->sem);
 	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
 	if (error)
 		return error;
@@ -195,33 +197,6 @@ void class_device_remove_bin_file(struct
 		sysfs_remove_bin_file(&class_dev->kobj, attr);
 }
 
-static int class_device_dev_link(struct class_device * class_dev)
-{
-	if (class_dev->dev)
-		return sysfs_create_link(&class_dev->kobj,
-					 &class_dev->dev->kobj, "device");
-	return 0;
-}
-
-static void class_device_dev_unlink(struct class_device * class_dev)
-{
-	sysfs_remove_link(&class_dev->kobj, "device");
-}
-
-static int class_device_driver_link(struct class_device * class_dev)
-{
-	if ((class_dev->dev) && (class_dev->dev->driver))
-		return sysfs_create_link(&class_dev->kobj,
-					 &class_dev->dev->driver->kobj, "driver");
-	return 0;
-}
-
-static void class_device_driver_unlink(struct class_device * class_dev)
-{
-	sysfs_remove_link(&class_dev->kobj, "driver");
-}
-
-
 static ssize_t
 class_device_attr_show(struct kobject * kobj, struct attribute * attr,
 		       char * buf)
@@ -298,9 +273,9 @@ static int class_hotplug(struct kset *ks
 			 int num_envp, char *buffer, int buffer_size)
 {
 	struct class_device *class_dev = to_class_dev(kobj);
-	int retval = 0;
 	int i = 0;
 	int length = 0;
+	int retval = 0;
 
 	pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 
@@ -313,26 +288,34 @@ static int class_hotplug(struct kset *ks
 				    &length, "PHYSDEVPATH=%s", path);
 		kfree(path);
 
-		/* add bus name of physical device */
 		if (dev->bus)
 			add_hotplug_env_var(envp, num_envp, &i,
 					    buffer, buffer_size, &length,
 					    "PHYSDEVBUS=%s", dev->bus->name);
 
-		/* add driver name of physical device */
 		if (dev->driver)
 			add_hotplug_env_var(envp, num_envp, &i,
 					    buffer, buffer_size, &length,
 					    "PHYSDEVDRIVER=%s", dev->driver->name);
-
-		/* terminate, set to next free slot, shrink available space */
-		envp[i] = NULL;
-		envp = &envp[i];
-		num_envp -= i;
-		buffer = &buffer[length];
-		buffer_size -= length;
 	}
 
+	if (MAJOR(class_dev->devt)) {
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "MAJOR=%u", MAJOR(class_dev->devt));
+
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "MINOR=%u", MINOR(class_dev->devt));
+	}
+
+	/* terminate, set to next free slot, shrink available space */
+	envp[i] = NULL;
+	envp = &envp[i];
+	num_envp -= i;
+	buffer = &buffer[length];
+	buffer_size -= length;
+
 	if (class_dev->class->hotplug) {
 		/* have the bus specific function add its stuff */
 		retval = class_dev->class->hotplug (class_dev, envp, num_envp,
@@ -388,6 +371,12 @@ static void class_device_remove_attrs(st
 	}
 }
 
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	return print_dev_t(buf, class_dev->devt);
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
 void class_device_initialize(struct class_device *class_dev)
 {
 	kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -425,17 +414,23 @@ int class_device_add(struct class_device
 
 	/* now take care of our own registration */
 	if (parent) {
-		down_write(&parent->subsys.rwsem);
+		down(&parent->sem);
 		list_add_tail(&class_dev->node, &parent->children);
 		list_for_each_entry(class_intf, &parent->interfaces, node)
 			if (class_intf->add)
 				class_intf->add(class_dev);
-		up_write(&parent->subsys.rwsem);
+		up(&parent->sem);
 	}
+
+	if (MAJOR(class_dev->devt))
+		class_device_create_file(class_dev, &class_device_attr_dev);
+
 	class_device_add_attrs(class_dev);
-	class_device_dev_link(class_dev);
-	class_device_driver_link(class_dev);
+	if (class_dev->dev)
+		sysfs_create_link(&class_dev->kobj,
+				  &class_dev->dev->kobj, "device");
 
+	kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
  register_done:
 	if (error && parent)
 		class_put(parent);
@@ -455,18 +450,19 @@ void class_device_del(struct class_devic
 	struct class_interface * class_intf;
 
 	if (parent) {
-		down_write(&parent->subsys.rwsem);
+		down(&parent->sem);
 		list_del_init(&class_dev->node);
 		list_for_each_entry(class_intf, &parent->interfaces, node)
 			if (class_intf->remove)
 				class_intf->remove(class_dev);
-		up_write(&parent->subsys.rwsem);
+		up(&parent->sem);
 	}
 
-	class_device_dev_unlink(class_dev);
-	class_device_driver_unlink(class_dev);
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, "device");
 	class_device_remove_attrs(class_dev);
 
+	kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
 	kobject_del(&class_dev->kobj);
 
 	if (parent)
@@ -516,8 +512,8 @@ void class_device_put(struct class_devic
 
 int class_interface_register(struct class_interface *class_intf)
 {
-	struct class * parent;
-	struct class_device * class_dev;
+	struct class *parent;
+	struct class_device *class_dev;
 
 	if (!class_intf || !class_intf->class)
 		return -ENODEV;
@@ -526,14 +522,13 @@ int class_interface_register(struct clas
 	if (!parent)
 		return -EINVAL;
 
-	down_write(&parent->subsys.rwsem);
+	down(&parent->sem);
 	list_add_tail(&class_intf->node, &parent->interfaces);
-
 	if (class_intf->add) {
 		list_for_each_entry(class_dev, &parent->children, node)
 			class_intf->add(class_dev);
 	}
-	up_write(&parent->subsys.rwsem);
+	up(&parent->sem);
 
 	return 0;
 }
@@ -546,14 +541,13 @@ void class_interface_unregister(struct c
 	if (!parent)
 		return;
 
-	down_write(&parent->subsys.rwsem);
+	down(&parent->sem);
 	list_del_init(&class_intf->node);
-
 	if (class_intf->remove) {
 		list_for_each_entry(class_dev, &parent->children, node)
 			class_intf->remove(class_dev);
 	}
-	up_write(&parent->subsys.rwsem);
+	up(&parent->sem);
 
 	class_put(parent);
 }
diff --git a/drivers/base/class_simple.c b/drivers/base/class_simple.c
--- a/drivers/base/class_simple.c
+++ b/drivers/base/class_simple.c
@@ -10,18 +10,15 @@
 
 #include <linux/config.h>
 #include <linux/device.h>
-#include <linux/kdev_t.h>
 #include <linux/err.h>
 
 struct class_simple {
-	struct class_device_attribute attr;
 	struct class class;
 };
 #define to_class_simple(d) container_of(d, struct class_simple, class)
 
 struct simple_dev {
 	struct list_head node;
-	dev_t dev;
 	struct class_device class_dev;
 };
 #define to_simple_dev(d) container_of(d, struct simple_dev, class_dev)
@@ -35,12 +32,6 @@ static void release_simple_dev(struct cl
 	kfree(s_dev);
 }
 
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
-	struct simple_dev *s_dev = to_simple_dev(class_dev);
-	return print_dev_t(buf, s_dev->dev);
-}
-
 static void class_simple_release(struct class *class)
 {
 	struct class_simple *cs = to_class_simple(class);
@@ -75,12 +66,6 @@ struct class_simple *class_simple_create
 	cs->class.class_release = class_simple_release;
 	cs->class.release = release_simple_dev;
 
-	cs->attr.attr.name = "dev";
-	cs->attr.attr.mode = S_IRUGO;
-	cs->attr.attr.owner = owner;
-	cs->attr.show = show_dev;
-	cs->attr.store = NULL;
-
 	retval = class_register(&cs->class);
 	if (retval)
 		goto error;
@@ -143,7 +128,7 @@ struct class_device *class_simple_device
 	}
 	memset(s_dev, 0x00, sizeof(*s_dev));
 
-	s_dev->dev = dev;
+	s_dev->class_dev.devt = dev;
 	s_dev->class_dev.dev = device;
 	s_dev->class_dev.class = &cs->class;
 
@@ -154,8 +139,6 @@ struct class_device *class_simple_device
 	if (retval)
 		goto error;
 
-	class_device_create_file(&s_dev->class_dev, &cs->attr);
-
 	spin_lock(&simple_dev_list_lock);
 	list_add(&s_dev->node, &simple_dev_list);
 	spin_unlock(&simple_dev_list_lock);
@@ -200,7 +183,7 @@ void class_simple_device_remove(dev_t de
 
 	spin_lock(&simple_dev_list_lock);
 	list_for_each_entry(s_dev, &simple_dev_list, node) {
-		if (s_dev->dev == dev) {
+		if (s_dev->class_dev.devt == dev) {
 			found = 1;
 			break;
 		}
diff --git a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct dev
 #define to_dev(obj) container_of(obj, struct device, kobj)
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
-extern struct attribute * dev_default_attrs[];
-
 static ssize_t
 dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -89,7 +87,6 @@ static void device_release(struct kobjec
 static struct kobj_type ktype_device = {
 	.release	= device_release,
 	.sysfs_ops	= &dev_sysfs_ops,
-	.default_attrs	= dev_default_attrs,
 };
 
 
@@ -139,7 +136,7 @@ static int dev_hotplug(struct kset *kset
 	buffer = &buffer[length];
 	buffer_size -= length;
 
-	if (dev->bus->hotplug) {
+	if (dev->bus && dev->bus->hotplug) {
 		/* have the bus specific function add its stuff */
 		retval = dev->bus->hotplug (dev, envp, num_envp, buffer, buffer_size);
 			if (retval) {
@@ -248,6 +245,7 @@ int device_add(struct device *dev)
 
 	if ((error = kobject_add(&dev->kobj)))
 		goto Error;
+	kobject_hotplug(&dev->kobj, KOBJ_ADD);
 	if ((error = device_pm_add(dev)))
 		goto PMError;
 	if ((error = bus_add_device(dev)))
@@ -266,6 +264,7 @@ int device_add(struct device *dev)
  BusError:
 	device_pm_remove(dev);
  PMError:
+	kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
  Error:
 	if (parent)
@@ -349,6 +348,7 @@ void device_del(struct device * dev)
 		platform_notify_remove(dev);
 	bus_remove_device(dev);
 	device_pm_remove(dev);
+	kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
 	if (parent)
 		put_device(parent);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -156,7 +156,7 @@ dma_pool_create (const char *name, struc
 
 
 static struct dma_page *
-pool_alloc_page (struct dma_pool *pool, int mem_flags)
+pool_alloc_page (struct dma_pool *pool, unsigned int __nocast mem_flags)
 {
 	struct dma_page	*page;
 	int		mapsize;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -79,14 +79,14 @@ void put_driver(struct device_driver * d
  *	since most of the things we have to do deal with the bus
  *	structures.
  *
- *	The one interesting aspect is that we initialize @drv->unload_sem
- *	to a locked state here. It will be unlocked when the driver
- *	reference count reaches 0.
+ *	The one interesting aspect is that we setup @drv->unloaded
+ *	as a completion that gets complete when the driver reference
+ *	count reaches 0.
  */
 int driver_register(struct device_driver * drv)
 {
 	INIT_LIST_HEAD(&drv->devices);
-	init_MUTEX_LOCKED(&drv->unload_sem);
+	init_completion(&drv->unloaded);
 	return bus_add_driver(drv);
 }
 
@@ -97,7 +97,7 @@ int driver_register(struct device_driver
  *
  *	Again, we pass off most of the work to the bus-level call.
  *
- *	Though, once that is done, we attempt to take @drv->unload_sem.
+ *	Though, once that is done, we wait until @drv->unloaded is completed.
  *	This will block until the driver refcount reaches 0, and it is
  *	released. Only modular drivers will call this function, and we
  *	have to guarantee that it won't complete, letting the driver
@@ -107,8 +107,7 @@ int driver_register(struct device_driver
 void driver_unregister(struct device_driver * drv)
 {
 	bus_remove_driver(drv);
-	down(&drv->unload_sem);
-	up(&drv->unload_sem);
+	wait_for_completion(&drv->unloaded);
 }
 
 /**
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -102,6 +102,9 @@ firmware_class_hotplug(struct class_devi
 	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
 			"FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
+	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			"TIMEOUT=%i", loading_timeout))
+		return -ENOMEM;
 
 	envp[i] = NULL;
 
diff --git a/drivers/base/interface.c b/drivers/base/interface.c
deleted file mode 100644
--- a/drivers/base/interface.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * drivers/base/interface.c - common driverfs interface that's exported to
- * 	the world for all devices.
- *
- * Copyright (c) 2002-3 Patrick Mochel
- * Copyright (c) 2002-3 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-
-/**
- *	detach_state - control the default power state for the device.
- *
- *	This is the state the device enters when it's driver module is
- *	unloaded. The value is an unsigned integer, in the range of 0-4.
- *	'0' indicates 'On', so no action will be taken when the driver is
- *	unloaded. This is the default behavior.
- *	'4' indicates 'Off', meaning the driver core will call the driver's
- *	shutdown method to quiesce the device.
- *	1-3 indicate a low-power state for the device to enter via the
- *	driver's suspend method.
- */
-
-static ssize_t detach_show(struct device * dev, char * buf)
-{
-	return sprintf(buf, "%u\n", dev->detach_state);
-}
-
-static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
-{
-	u32 state;
-	state = simple_strtoul(buf, NULL, 10);
-	if (state > 4)
-		return -EINVAL;
-	dev->detach_state = state;
-	return n;
-}
-
-static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
-
-
-struct attribute * dev_default_attrs[] = {
-	&dev_attr_detach_state.attr,
-	NULL,
-};
diff --git a/drivers/base/map.c b/drivers/base/map.c
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -25,7 +25,7 @@ struct kobj_map {
 		int (*lock)(dev_t, void *);
 		void *data;
 	} *probes[255];
-	struct rw_semaphore *sem;
+	struct semaphore *sem;
 };
 
 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
@@ -53,7 +53,7 @@ int kobj_map(struct kobj_map *domain, de
 		p->range = range;
 		p->data = data;
 	}
-	down_write(domain->sem);
+	down(domain->sem);
 	for (i = 0, p -= n; i < n; i++, p++, index++) {
 		struct probe **s = &domain->probes[index % 255];
 		while (*s && (*s)->range < range)
@@ -61,7 +61,7 @@ int kobj_map(struct kobj_map *domain, de
 		p->next = *s;
 		*s = p;
 	}
-	up_write(domain->sem);
+	up(domain->sem);
 	return 0;
 }
 
@@ -75,7 +75,7 @@ void kobj_unmap(struct kobj_map *domain,
 	if (n > 255)
 		n = 255;
 
-	down_write(domain->sem);
+	down(domain->sem);
 	for (i = 0; i < n; i++, index++) {
 		struct probe **s;
 		for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
@@ -88,7 +88,7 @@ void kobj_unmap(struct kobj_map *domain,
 			}
 		}
 	}
-	up_write(domain->sem);
+	up(domain->sem);
 	kfree(found);
 }
 
@@ -99,7 +99,7 @@ struct kobject *kobj_lookup(struct kobj_
 	unsigned long best = ~0UL;
 
 retry:
-	down_read(domain->sem);
+	down(domain->sem);
 	for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
 		struct kobject *(*probe)(dev_t, int *, void *);
 		struct module *owner;
@@ -120,7 +120,7 @@ retry:
 			module_put(owner);
 			continue;
 		}
-		up_read(domain->sem);
+		up(domain->sem);
 		kobj = probe(dev, index, data);
 		/* Currently ->owner protects _only_ ->probe() itself. */
 		module_put(owner);
@@ -128,12 +128,11 @@ retry:
 			return kobj;
 		goto retry;
 	}
-	up_read(domain->sem);
+	up(domain->sem);
 	return NULL;
 }
 
-struct kobj_map *kobj_map_init(kobj_probe_t *base_probe,
-		struct subsystem *s)
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
 {
 	struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
 	struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
@@ -151,6 +150,6 @@ struct kobj_map *kobj_map_init(kobj_prob
 	base->get = base_probe;
 	for (i = 0; i < 255; i++)
 		p->probes[i] = base;
-	p->sem = &s->rwsem;
+	p->sem = sem;
 	return p;
 }
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -115,7 +115,7 @@ int platform_add_devices(struct platform
 
 /**
  *	platform_device_register - add a platform-level device
- *	@dev:	platform device we're adding
+ *	@pdev:	platform device we're adding
  *
  */
 int platform_device_register(struct platform_device * pdev)
@@ -131,7 +131,7 @@ int platform_device_register(struct plat
 	pdev->dev.bus = &platform_bus_type;
 
 	if (pdev->id != -1)
-		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id);
+		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
 	else
 		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
 
@@ -174,7 +174,7 @@ int platform_device_register(struct plat
 
 /**
  *	platform_device_unregister - remove a platform-level device
- *	@dev:	platform device we're removing
+ *	@pdev:	platform device we're removing
  *
  *	Note that this function will also release all memory- and port-based
  *	resources owned by the device (@dev->resource).
@@ -341,6 +341,7 @@ EXPORT_SYMBOL_GPL(dma_get_required_mask)
 
 EXPORT_SYMBOL_GPL(platform_bus);
 EXPORT_SYMBOL_GPL(platform_bus_type);
+EXPORT_SYMBOL_GPL(platform_add_devices);
 EXPORT_SYMBOL_GPL(platform_device_register);
 EXPORT_SYMBOL_GPL(platform_device_register_simple);
 EXPORT_SYMBOL_GPL(platform_device_unregister);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,18 +1,7 @@
-
-
-enum {
-	DEVICE_PM_ON,
-	DEVICE_PM1,
-	DEVICE_PM2,
-	DEVICE_PM3,
-	DEVICE_PM_OFF,
-};
-
 /*
  * shutdown.c
  */
 
-extern int device_detach_shutdown(struct device *);
 extern void device_shutdown(void);
 
 
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -22,8 +22,17 @@ extern int sysdev_resume(void);
 
 int resume_device(struct device * dev)
 {
-	if (dev->bus && dev->bus->resume)
+	if (dev->power.pm_parent
+			&& dev->power.pm_parent->power.power_state) {
+		dev_err(dev, "PM: resume from %d, parent %s still %d\n",
+			dev->power.power_state,
+			dev->power.pm_parent->bus_id,
+			dev->power.pm_parent->power.power_state);
+	}
+	if (dev->bus && dev->bus->resume) {
+		dev_dbg(dev,"resuming\n");
 		return dev->bus->resume(dev);
+	}
 	return 0;
 }
 
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -19,20 +19,6 @@
 extern struct subsystem devices_subsys;
 
 
-int device_detach_shutdown(struct device * dev)
-{
-	if (!dev->detach_state)
-		return 0;
-
-	if (dev->detach_state == DEVICE_PM_OFF) {
-		if (dev->driver && dev->driver->shutdown)
-			dev->driver->shutdown(dev);
-		return 0;
-	}
-	return dpm_runtime_suspend(dev, dev->detach_state);
-}
-
-
 /**
  * We handle system devices differently - we suspend and shut them
  * down last and resume them first. That way, we don't do anything stupid like
@@ -52,13 +38,12 @@ void device_shutdown(void)
 	struct device * dev;
 
 	down_write(&devices_subsys.rwsem);
-	list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) {
-		pr_debug("shutting down %s: ", dev->bus_id);
+	list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
+				kobj.entry) {
 		if (dev->driver && dev->driver->shutdown) {
-			pr_debug("Ok\n");
+			dev_dbg(dev, "shutdown\n");
 			dev->driver->shutdown(dev);
-		} else
-			pr_debug("Ignored.\n");
+		}
 	}
 	up_write(&devices_subsys.rwsem);
 
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, 
 {
 	int error = 0;
 
-	dev_dbg(dev, "suspending\n");
+	if (dev->power.power_state) {
+		dev_dbg(dev, "PM: suspend %d-->%d\n",
+			dev->power.power_state, state);
+	}
+	if (dev->power.pm_parent
+			&& dev->power.pm_parent->power.power_state) {
+		dev_err(dev,
+			"PM: suspend %d->%d, parent %s already %d\n",
+			dev->power.power_state, state,
+			dev->power.pm_parent->bus_id,
+			dev->power.pm_parent->power.power_state);
+	}
 
 	dev->power.prev_state = dev->power.power_state;
 
-	if (dev->bus && dev->bus->suspend && !dev->power.power_state)
+	if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
+		dev_dbg(dev, "suspending\n");
 		error = dev->bus->suspend(dev, state);
+	}
 
 	return error;
 }
@@ -134,6 +147,8 @@ int device_power_down(pm_message_t state
  Done:
 	return error;
  Error:
+	printk(KERN_ERR "Could not power down device %s: "
+		"error %d\n", kobject_name(&dev->kobj), error);
 	dpm_power_up();
 	goto Done;
 }
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/pm.h>
 
 
 extern struct subsystem devices_subsys;
@@ -79,7 +80,7 @@ EXPORT_SYMBOL_GPL(sysdev_remove_file);
 /*
  * declare system_subsys
  */
-decl_subsys(system, &ktype_sysdev, NULL);
+static decl_subsys(system, &ktype_sysdev, NULL);
 
 int sysdev_class_register(struct sysdev_class * cls)
 {
@@ -102,7 +103,8 @@ EXPORT_SYMBOL_GPL(sysdev_class_register)
 EXPORT_SYMBOL_GPL(sysdev_class_unregister);
 
 
-static LIST_HEAD(global_drivers);
+static LIST_HEAD(sysdev_drivers);
+static DECLARE_MUTEX(sysdev_drivers_lock);
 
 /**
  *	sysdev_driver_register - Register auxillary driver
@@ -112,14 +114,14 @@ static LIST_HEAD(global_drivers);
  *	If @cls is valid, then @drv is inserted into @cls->drivers to be
  *	called on each operation on devices of that class. The refcount
  *	of @cls is incremented.
- *	Otherwise, @drv is inserted into global_drivers, and called for
+ *	Otherwise, @drv is inserted into sysdev_drivers, and called for
  *	each device.
  */
 
 int sysdev_driver_register(struct sysdev_class * cls,
 			   struct sysdev_driver * drv)
 {
-	down_write(&system_subsys.rwsem);
+	down(&sysdev_drivers_lock);
 	if (cls && kset_get(&cls->kset)) {
 		list_add_tail(&drv->entry, &cls->drivers);
 
@@ -130,8 +132,8 @@ int sysdev_driver_register(struct sysdev
 				drv->add(dev);
 		}
 	} else
-		list_add_tail(&drv->entry, &global_drivers);
-	up_write(&system_subsys.rwsem);
+		list_add_tail(&drv->entry, &sysdev_drivers);
+	up(&sysdev_drivers_lock);
 	return 0;
 }
 
@@ -144,7 +146,7 @@ int sysdev_driver_register(struct sysdev
 void sysdev_driver_unregister(struct sysdev_class * cls,
 			      struct sysdev_driver * drv)
 {
-	down_write(&system_subsys.rwsem);
+	down(&sysdev_drivers_lock);
 	list_del_init(&drv->entry);
 	if (cls) {
 		if (drv->remove) {
@@ -154,7 +156,7 @@ void sysdev_driver_unregister(struct sys
 		}
 		kset_put(&cls->kset);
 	}
-	up_write(&system_subsys.rwsem);
+	up(&sysdev_drivers_lock);
 }
 
 EXPORT_SYMBOL_GPL(sysdev_driver_register);
@@ -193,13 +195,13 @@ int sysdev_register(struct sys_device * 
 	if (!error) {
 		struct sysdev_driver * drv;
 
-		down_write(&system_subsys.rwsem);
+		down(&sysdev_drivers_lock);
 		/* Generic notification is implicit, because it's that
 		 * code that should have called us.
 		 */
 
 		/* Notify global drivers */
-		list_for_each_entry(drv, &global_drivers, entry) {
+		list_for_each_entry(drv, &sysdev_drivers, entry) {
 			if (drv->add)
 				drv->add(sysdev);
 		}
@@ -209,7 +211,7 @@ int sysdev_register(struct sys_device * 
 			if (drv->add)
 				drv->add(sysdev);
 		}
-		up_write(&system_subsys.rwsem);
+		up(&sysdev_drivers_lock);
 	}
 	return error;
 }
@@ -218,8 +220,8 @@ void sysdev_unregister(struct sys_device
 {
 	struct sysdev_driver * drv;
 
-	down_write(&system_subsys.rwsem);
-	list_for_each_entry(drv, &global_drivers, entry) {
+	down(&sysdev_drivers_lock);
+	list_for_each_entry(drv, &sysdev_drivers, entry) {
 		if (drv->remove)
 			drv->remove(sysdev);
 	}
@@ -228,7 +230,7 @@ void sysdev_unregister(struct sys_device
 		if (drv->remove)
 			drv->remove(sysdev);
 	}
-	up_write(&system_subsys.rwsem);
+	up(&sysdev_drivers_lock);
 
 	kobject_unregister(&sysdev->kobj);
 }
@@ -255,7 +257,7 @@ void sysdev_shutdown(void)
 
 	pr_debug("Shutting Down System Devices\n");
 
-	down_write(&system_subsys.rwsem);
+	down(&sysdev_drivers_lock);
 	list_for_each_entry_reverse(cls, &system_subsys.kset.list,
 				    kset.kobj.entry) {
 		struct sys_device * sysdev;
@@ -268,7 +270,7 @@ void sysdev_shutdown(void)
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
 			/* Call global drivers first. */
-			list_for_each_entry(drv, &global_drivers, entry) {
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
 				if (drv->shutdown)
 					drv->shutdown(sysdev);
 			}
@@ -284,7 +286,7 @@ void sysdev_shutdown(void)
 				cls->shutdown(sysdev);
 		}
 	}
-	up_write(&system_subsys.rwsem);
+	up(&sysdev_drivers_lock);
 }
 
 
@@ -301,7 +303,7 @@ void sysdev_shutdown(void)
  *	all synchronization.
  */
 
-int sysdev_suspend(u32 state)
+int sysdev_suspend(pm_message_t state)
 {
 	struct sysdev_class * cls;
 
@@ -319,7 +321,7 @@ int sysdev_suspend(u32 state)
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
 			/* Call global drivers first. */
-			list_for_each_entry(drv, &global_drivers, entry) {
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
 				if (drv->suspend)
 					drv->suspend(sysdev, state);
 			}
@@ -375,7 +377,7 @@ int sysdev_resume(void)
 			}
 
 			/* Call global drivers. */
-			list_for_each_entry(drv, &global_drivers, entry) {
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
 				if (drv->resume)
 					drv->resume(sysdev);
 			}
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c
--- a/drivers/base/transport_class.c
+++ b/drivers/base/transport_class.c
@@ -145,6 +145,20 @@ void transport_setup_device(struct devic
 }
 EXPORT_SYMBOL_GPL(transport_setup_device);
 
+static int transport_add_class_device(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	int error = attribute_container_add_class_device(classdev);
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+
+	if (!error && tcont->statistics)
+		error = sysfs_create_group(&classdev->kobj, tcont->statistics);
+
+	return error;
+}
+
 
 /**
  * transport_add_device - declare a new dev for transport class association
@@ -159,8 +173,7 @@ EXPORT_SYMBOL_GPL(transport_setup_device
 
 void transport_add_device(struct device *dev)
 {
-	attribute_container_device_trigger(dev,
-			   attribute_container_add_class_device_adapter);
+	attribute_container_device_trigger(dev, transport_add_class_device);
 }
 EXPORT_SYMBOL_GPL(transport_add_device);
 
@@ -197,13 +210,18 @@ static int transport_remove_classdev(str
 				     struct device *dev,
 				     struct class_device *classdev)
 {
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
 	struct transport_class *tclass = class_to_transport_class(cont->class);
 
 	if (tclass->remove)
 		tclass->remove(dev);
 
-	if (tclass->remove != anon_transport_dummy_function)
+	if (tclass->remove != anon_transport_dummy_function) {
+		if (tcont->statistics)
+			sysfs_remove_group(&classdev->kobj, tcont->statistics);
 		attribute_container_class_device_del(classdev);
+	}
 
 	return 0;
 }
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -3,6 +3,7 @@
   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
   Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Portions Copyright 2002 by Mylex (An IBM Business Unit)
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -532,6 +533,34 @@ static void DAC960_WaitForCommand(DAC960
   spin_lock_irq(&Controller->queue_lock);
 }
 
+/*
+  DAC960_GEM_QueueCommand queues Command for DAC960 GEM Series Controllers.
+*/
+
+static void DAC960_GEM_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+      Controller->V2.NextCommandMailbox;
+
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_GEM_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+
+  if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+      DAC960_GEM_MemoryMailboxNewCommand(ControllerBaseAddress);
+
+  Controller->V2.PreviousCommandMailbox2 =
+      Controller->V2.PreviousCommandMailbox1;
+  Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+
+  if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+      NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+
+  Controller->V2.NextCommandMailbox = NextCommandMailbox;
+}
 
 /*
   DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
@@ -1464,6 +1493,17 @@ static boolean DAC960_V2_EnableMemoryMai
     					Controller->V2.FirstStatusMailboxDMA;
   switch (Controller->HardwareType)
     {
+    case DAC960_GEM_Controller:
+      while (DAC960_GEM_HardwareMailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_GEM_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA);
+      DAC960_GEM_HardwareMailboxNewCommand(ControllerBaseAddress);
+      while (!DAC960_GEM_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
+	udelay(1);
+      CommandStatus = DAC960_GEM_ReadCommandStatus(ControllerBaseAddress);
+      DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+      DAC960_GEM_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
+      break;
     case DAC960_BA_Controller:
       while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress))
 	udelay(1);
@@ -2627,6 +2667,9 @@ static void DAC960_DetectCleanup(DAC960_
   if (Controller->MemoryMappedAddress) {
   	switch(Controller->HardwareType)
   	{
+		case DAC960_GEM_Controller:
+			DAC960_GEM_DisableInterrupts(Controller->BaseAddress);
+			break;
 		case DAC960_BA_Controller:
 			DAC960_BA_DisableInterrupts(Controller->BaseAddress);
 			break;
@@ -2700,13 +2743,14 @@ DAC960_DetectController(struct pci_dev *
   Controller->PCIDevice = PCI_Device;
   strcpy(Controller->FullModelName, "DAC960");
 
-  if (pci_enable_device(PCI_Device))  {
-        kfree(Controller);
+  if (pci_enable_device(PCI_Device))
 	goto Failure;
-  }
 
   switch (Controller->HardwareType)
   {
+	case DAC960_GEM_Controller:
+	  Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
+	  break;
 	case DAC960_BA_Controller:
 	  Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
 	  break;
@@ -2758,6 +2802,36 @@ DAC960_DetectController(struct pci_dev *
   BaseAddress = Controller->BaseAddress;
   switch (Controller->HardwareType)
   {
+	case DAC960_GEM_Controller:
+	  DAC960_GEM_DisableInterrupts(BaseAddress);
+	  DAC960_GEM_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_GEM_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_GEM_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_GEM_EnableInterrupts(BaseAddress);
+	  Controller->QueueCommand = DAC960_GEM_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V2_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V2_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V2_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V2_QueueReadWriteCommand;
+	  break;
 	case DAC960_BA_Controller:
 	  DAC960_BA_DisableInterrupts(BaseAddress);
 	  DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress);
@@ -5191,6 +5265,47 @@ static void DAC960_V2_ProcessCompletedCo
   wake_up(&Controller->CommandWaitQueue);
 }
 
+/*
+  DAC960_GEM_InterruptHandler handles hardware interrupts from DAC960 GEM Series
+  Controllers.
+*/
+
+static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       struct pt_regs *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
+  DAC960_GEM_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V2.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.CommandIdentifier > 0)
+    {
+       DAC960_V2_CommandIdentifier_T CommandIdentifier =
+           NextStatusMailbox->Fields.CommandIdentifier;
+       DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+       Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+       Command->V2.RequestSenseLength =
+           NextStatusMailbox->Fields.RequestSenseLength;
+       Command->V2.DataTransferResidue =
+           NextStatusMailbox->Fields.DataTransferResidue;
+       NextStatusMailbox->Words[0] = 0;
+       if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
+           NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+       DAC960_V2_ProcessCompletedCommand(Command);
+    }
+  Controller->V2.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  DAC960_ProcessRequest(Controller);
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
+  return IRQ_HANDLED;
+}
 
 /*
   DAC960_BA_InterruptHandler handles hardware interrupts from DAC960 BA Series
@@ -6964,6 +7079,14 @@ static void DAC960_gam_cleanup(void)
 
 #endif /* DAC960_GAM_MINOR */
 
+static struct DAC960_privdata DAC960_GEM_privdata = {
+	.HardwareType =		DAC960_GEM_Controller,
+	.FirmwareType 	=	DAC960_V2_Controller,
+	.InterruptHandler =	DAC960_GEM_InterruptHandler,
+	.MemoryWindowSize =	DAC960_GEM_RegisterWindowSize,
+};
+
+
 static struct DAC960_privdata DAC960_BA_privdata = {
 	.HardwareType =		DAC960_BA_Controller,
 	.FirmwareType 	=	DAC960_V2_Controller,
@@ -7009,6 +7132,13 @@ static struct DAC960_privdata DAC960_P_p
 static struct pci_device_id DAC960_id_table[] = {
 	{
 		.vendor 	= PCI_VENDOR_ID_MYLEX,
+		.device		= PCI_DEVICE_ID_MYLEX_DAC960_GEM,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long) &DAC960_GEM_privdata,
+	},
+	{
+		.vendor 	= PCI_VENDOR_ID_MYLEX,
 		.device		= PCI_DEVICE_ID_MYLEX_DAC960_BA,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
--- a/drivers/block/DAC960.h
+++ b/drivers/block/DAC960.h
@@ -2114,7 +2114,8 @@ typedef enum
   DAC960_LA_Controller =			3,	/* DAC1164P */
   DAC960_PG_Controller =			4,	/* DAC960PTL/PJ/PG */
   DAC960_PD_Controller =			5,	/* DAC960PU/PD/PL/P */
-  DAC960_P_Controller =				6	/* DAC960PU/PD/PL/P */
+  DAC960_P_Controller =				6,	/* DAC960PU/PD/PL/P */
+  DAC960_GEM_Controller =			7,	/* AcceleRAID 4/5/600 */
 }
 DAC960_HardwareType_T;
 
@@ -2541,6 +2542,320 @@ void dma_addr_writeql(dma_addr_t addr, v
 }
 
 /*
+  Define the DAC960 GEM Series Controller Interface Register Offsets.
+ */
+
+#define DAC960_GEM_RegisterWindowSize	0x600
+
+typedef enum
+{
+  DAC960_GEM_InboundDoorBellRegisterReadSetOffset   =   0x214,
+  DAC960_GEM_InboundDoorBellRegisterClearOffset     =   0x218,
+  DAC960_GEM_OutboundDoorBellRegisterReadSetOffset  =   0x224,
+  DAC960_GEM_OutboundDoorBellRegisterClearOffset    =   0x228,
+  DAC960_GEM_InterruptStatusRegisterOffset          =   0x208,
+  DAC960_GEM_InterruptMaskRegisterReadSetOffset     =   0x22C,
+  DAC960_GEM_InterruptMaskRegisterClearOffset       =   0x230,
+  DAC960_GEM_CommandMailboxBusAddressOffset         =   0x510,
+  DAC960_GEM_CommandStatusOffset                    =   0x518,
+  DAC960_GEM_ErrorStatusRegisterReadSetOffset       =   0x224,
+  DAC960_GEM_ErrorStatusRegisterClearOffset         =   0x228,
+}
+DAC960_GEM_RegisterOffsets_T;
+
+/*
+  Define the structure of the DAC960 GEM Series Inbound Door Bell
+ */
+
+typedef union DAC960_GEM_InboundDoorBellRegister
+{
+  unsigned int All;
+  struct {
+    unsigned int :24;
+    boolean HardwareMailboxNewCommand:1;
+    boolean AcknowledgeHardwareMailboxStatus:1;
+    boolean GenerateInterrupt:1;
+    boolean ControllerReset:1;
+    boolean MemoryMailboxNewCommand:1;
+    unsigned int :3;
+  } Write;
+  struct {
+    unsigned int :24;
+    boolean HardwareMailboxFull:1;
+    boolean InitializationInProgress:1;
+    unsigned int :6;
+  } Read;
+}
+DAC960_GEM_InboundDoorBellRegister_T;
+
+/*
+  Define the structure of the DAC960 GEM Series Outbound Door Bell Register.
+ */
+typedef union DAC960_GEM_OutboundDoorBellRegister
+{
+  unsigned int All;
+  struct {
+    unsigned int :24;
+    boolean AcknowledgeHardwareMailboxInterrupt:1;
+    boolean AcknowledgeMemoryMailboxInterrupt:1;
+    unsigned int :6;
+  } Write;
+  struct {
+    unsigned int :24;
+    boolean HardwareMailboxStatusAvailable:1;
+    boolean MemoryMailboxStatusAvailable:1;
+    unsigned int :6;
+  } Read;
+}
+DAC960_GEM_OutboundDoorBellRegister_T;
+
+/*
+  Define the structure of the DAC960 GEM Series Interrupt Mask Register.
+ */
+typedef union DAC960_GEM_InterruptMaskRegister
+{
+  unsigned int All;
+  struct {
+    unsigned int :16;
+    unsigned int :8;
+    unsigned int HardwareMailboxInterrupt:1;
+    unsigned int MemoryMailboxInterrupt:1;
+    unsigned int :6;
+  } Bits;
+}
+DAC960_GEM_InterruptMaskRegister_T;
+
+/*
+  Define the structure of the DAC960 GEM Series Error Status Register.
+ */
+
+typedef union DAC960_GEM_ErrorStatusRegister
+{
+  unsigned int All;
+  struct {
+    unsigned int :24;
+    unsigned int :5;
+    boolean ErrorStatusPending:1;
+    unsigned int :2;
+  } Bits;
+}
+DAC960_GEM_ErrorStatusRegister_T;
+
+/*
+  Define inline functions to provide an abstraction for reading and writing the
+  DAC960 GEM Series Controller Interface Registers.
+*/
+
+static inline
+void DAC960_GEM_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+}
+
+static inline
+void DAC960_GEM_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterClearOffset);
+}
+
+static inline
+void DAC960_GEM_GenerateInterrupt(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.GenerateInterrupt = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+}
+
+static inline
+void DAC960_GEM_ControllerReset(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.ControllerReset = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+}
+
+static inline
+void DAC960_GEM_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+}
+
+static inline
+boolean DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readl(ControllerBaseAddress +
+          DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+  return InboundDoorBellRegister.Read.HardwareMailboxFull;
+}
+
+static inline
+boolean DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readl(ControllerBaseAddress +
+          DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
+  return InboundDoorBellRegister.Read.InitializationInProgress;
+}
+
+static inline
+void DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  writel(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
+}
+
+static inline
+void DAC960_GEM_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writel(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
+}
+
+static inline
+void DAC960_GEM_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writel(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
+}
+
+static inline
+boolean DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readl(ControllerBaseAddress +
+          DAC960_GEM_OutboundDoorBellRegisterReadSetOffset);
+  return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
+}
+
+static inline
+boolean DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readl(ControllerBaseAddress +
+          DAC960_GEM_OutboundDoorBellRegisterReadSetOffset);
+  return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
+}
+
+static inline
+void DAC960_GEM_EnableInterrupts(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0;
+  InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true;
+  InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true;
+  writel(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterClearOffset);
+}
+
+static inline
+void DAC960_GEM_DisableInterrupts(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0;
+  InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true;
+  InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true;
+  writel(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterReadSetOffset);
+}
+
+static inline
+boolean DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+{
+  DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All =
+    readl(ControllerBaseAddress +
+          DAC960_GEM_InterruptMaskRegisterReadSetOffset);
+  return !(InterruptMaskRegister.Bits.HardwareMailboxInterrupt ||
+           InterruptMaskRegister.Bits.MemoryMailboxInterrupt);
+}
+
+static inline
+void DAC960_GEM_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
+				     *MemoryCommandMailbox,
+				   DAC960_V2_CommandMailbox_T
+				     *CommandMailbox)
+{
+  memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
+	 sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
+  wmb();
+  MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
+  mb();
+}
+
+static inline
+void DAC960_GEM_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
+				    dma_addr_t CommandMailboxDMA)
+{
+	dma_addr_writeql(CommandMailboxDMA,
+		ControllerBaseAddress +
+		DAC960_GEM_CommandMailboxBusAddressOffset);
+}
+
+static inline DAC960_V2_CommandIdentifier_T
+DAC960_GEM_ReadCommandIdentifier(void __iomem *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset);
+}
+
+static inline DAC960_V2_CommandStatus_T
+DAC960_GEM_ReadCommandStatus(void __iomem *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset + 2);
+}
+
+static inline boolean
+DAC960_GEM_ReadErrorStatus(void __iomem *ControllerBaseAddress,
+			  unsigned char *ErrorStatus,
+			  unsigned char *Parameter0,
+			  unsigned char *Parameter1)
+{
+  DAC960_GEM_ErrorStatusRegister_T ErrorStatusRegister;
+  ErrorStatusRegister.All =
+    readl(ControllerBaseAddress + DAC960_GEM_ErrorStatusRegisterReadSetOffset);
+  if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
+  ErrorStatusRegister.Bits.ErrorStatusPending = false;
+  *ErrorStatus = ErrorStatusRegister.All;
+  *Parameter0 =
+    readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 0);
+  *Parameter1 =
+    readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 1);
+  writel(0x03000000, ControllerBaseAddress +
+         DAC960_GEM_ErrorStatusRegisterClearOffset);
+  return true;
+}
+
+/*
   Define the DAC960 BA Series Controller Interface Register Offsets.
 */
 
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -6,7 +6,7 @@ menu "Block devices"
 
 config BLK_DEV_FD
 	tristate "Normal floppy disk support"
-	depends on (!ARCH_S390 && !M68K && !IA64 && !USERMODE) || Q40 || (SUN3X && BROKEN)
+	depends on (!ARCH_S390 && !M68K && !IA64 && !UML && !ARM) || Q40 || (SUN3X && BROKEN) || ARCH_RPC || ARCH_EBSA285
 	---help---
 	  If you want to use the floppy disk drive(s) of your PC under Linux,
 	  say Y. Information about this driver, especially important for IBM
@@ -42,7 +42,7 @@ config MAC_FLOPPY
 
 config BLK_DEV_PS2
 	tristate "PS/2 ESDI hard disk support"
-	depends on MCA && MCA_LEGACY
+	depends on MCA && MCA_LEGACY && BROKEN
 	help
 	  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
 	  hard disk.
@@ -105,7 +105,7 @@ config ATARI_SLM
 
 config BLK_DEV_XD
 	tristate "XT hard disk support"
-	depends on ISA
+	depends on ISA && ISA_DMA_API
 	help
 	  Very old 8 bit hard disk controllers used in the IBM XT computer
 	  will be supported if you say Y here.
@@ -210,7 +210,7 @@ config BLK_DEV_UMEM
 
 config BLK_DEV_UBD
 	bool "Virtual block device"
-	depends on USERMODE
+	depends on UML
 	---help---
           The User-Mode Linux port includes a driver called UBD which will let
           you access arbitrary files on the host computer as block devices.
@@ -243,7 +243,7 @@ config BLK_DEV_COW_COMMON
 
 config MMAPPER
 	tristate "Example IO memory driver (BROKEN)"
-	depends on USERMODE && BROKEN
+	depends on UML && BROKEN
 	---help---
           The User-Mode Linux port can provide support for IO Memory
           emulation with this option.  This allows a host file to be
@@ -455,7 +455,7 @@ config INITRAMFS_ROOT_GID
 #for instance.
 config LBD
 	bool "Support for Large Block Devices"
-	depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || USERMODE
+	depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || UML
 	help
 	  Say Y here if you want to attach large (bigger than 2TB) discs to
 	  your machine, or if you want to have a raid or loopback device
@@ -463,7 +463,7 @@ config LBD
 
 config CDROM_PKTCDVD
 	tristate "Packet writing on CD/DVD media"
-	depends on !USERMODE
+	depends on !UML
 	help
 	  If you have a CDROM drive that supports packet writing, say Y to
 	  include preliminary support. It should work with any MMC/Mt Fuji
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -1,10 +1,15 @@
 /* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "5"
+#define VERSION "10"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
+
+/* set AOE_PARTITIONS to 1 to use whole-disks only
+ * default is 16, which is 15 partitions plus the whole disk
+ */
 #ifndef AOE_PARTITIONS
 #define AOE_PARTITIONS 16
 #endif
+
 #define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor))
 #define AOEMAJOR(sysminor) ((sysminor) / 10)
 #define AOEMINOR(sysminor) ((sysminor) % 10)
@@ -34,13 +39,13 @@ enum {
 struct aoe_hdr {
 	unsigned char dst[6];
 	unsigned char src[6];
-	unsigned char type[2];
+	__be16 type;
 	unsigned char verfl;
 	unsigned char err;
-	unsigned char major[2];
+	__be16 major;
 	unsigned char minor;
 	unsigned char cmd;
-	unsigned char tag[4];
+	__be32 tag;
 };
 
 struct aoe_atahdr {
@@ -58,8 +63,8 @@ struct aoe_atahdr {
 };
 
 struct aoe_cfghdr {
-	unsigned char bufcnt[2];
-	unsigned char fwver[2];
+	__be16 bufcnt;
+	__be16 fwver;
 	unsigned char res;
 	unsigned char aoeccmd;
 	unsigned char cslen[2];
@@ -85,6 +90,7 @@ enum {
 
 struct buf {
 	struct list_head bufs;
+	ulong start_time;	/* for disk stats */
 	ulong flags;
 	ulong nframesout;
 	char *bufaddr;
@@ -125,7 +131,8 @@ struct aoedev {
 	struct timer_list timer;
 	spinlock_t lock;
 	struct net_device *ifp;	/* interface ed is attached to */
-	struct sk_buff *skblist;/* packets needing to be sent */
+	struct sk_buff *sendq_hd; /* packets needing to be sent, list head */
+	struct sk_buff *sendq_tl;
 	mempool_t *bufpool;	/* for deadlock-free Buf allocation */
 	struct list_head bufq;	/* queue of bios to work on */
 	struct buf *inprocess;	/* the one we're currently working on */
@@ -143,7 +150,6 @@ void aoedisk_rm_sysfs(struct aoedev *d);
 int aoechr_init(void);
 void aoechr_exit(void);
 void aoechr_error(char *);
-void aoechr_hdump(char *, int len);
 
 void aoecmd_work(struct aoedev *d);
 void aoecmd_cfg(ushort, unsigned char);
@@ -152,7 +158,7 @@ void aoecmd_cfg_rsp(struct sk_buff *);
 
 int aoedev_init(void);
 void aoedev_exit(void);
-struct aoedev *aoedev_bymac(unsigned char *);
+struct aoedev *aoedev_by_aoeaddr(int maj, int min);
 void aoedev_downdev(struct aoedev *d);
 struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
 int aoedev_busy(void);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -28,7 +28,8 @@ static ssize_t aoedisk_show_mac(struct g
 {
 	struct aoedev *d = disk->private_data;
 
-	return snprintf(page, PAGE_SIZE, "%012llx\n", mac_addr(d->addr));
+	return snprintf(page, PAGE_SIZE, "%012llx\n",
+			(unsigned long long)mac_addr(d->addr));
 }
 static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
 {
@@ -36,6 +37,13 @@ static ssize_t aoedisk_show_netif(struct
 
 	return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
 }
+/* firmware version */
+static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page)
+{
+	struct aoedev *d = disk->private_data;
+
+	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
+}
 
 static struct disk_attribute disk_attr_state = {
 	.attr = {.name = "state", .mode = S_IRUGO },
@@ -49,6 +57,10 @@ static struct disk_attribute disk_attr_n
 	.attr = {.name = "netif", .mode = S_IRUGO },
 	.show = aoedisk_show_netif
 };
+static struct disk_attribute disk_attr_fwver = {
+	.attr = {.name = "firmware-version", .mode = S_IRUGO },
+	.show = aoedisk_show_fwver
+};
 
 static void
 aoedisk_add_sysfs(struct aoedev *d)
@@ -56,6 +68,7 @@ aoedisk_add_sysfs(struct aoedev *d)
 	sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr);
 	sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr);
 	sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr);
+	sysfs_create_file(&d->gd->kobj, &disk_attr_fwver.attr);
 }
 void
 aoedisk_rm_sysfs(struct aoedev *d)
@@ -63,6 +76,7 @@ aoedisk_rm_sysfs(struct aoedev *d)
 	sysfs_remove_link(&d->gd->kobj, "state");
 	sysfs_remove_link(&d->gd->kobj, "mac");
 	sysfs_remove_link(&d->gd->kobj, "netif");
+	sysfs_remove_link(&d->gd->kobj, "firmware-version");
 }
 
 static int
@@ -124,6 +138,7 @@ aoeblk_make_request(request_queue_t *q, 
 	}
 	memset(buf, 0, sizeof(*buf));
 	INIT_LIST_HEAD(&buf->bufs);
+	buf->start_time = jiffies;
 	buf->bio = bio;
 	buf->resid = bio->bi_size;
 	buf->sector = bio->bi_sector;
@@ -145,8 +160,8 @@ aoeblk_make_request(request_queue_t *q, 
 	list_add_tail(&buf->bufs, &d->bufq);
 	aoecmd_work(d);
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
@@ -241,7 +256,8 @@ aoeblk_gdalloc(void *vp)
 	aoedisk_add_sysfs(d);
 	
 	printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
-		"sectors\n", mac_addr(d->addr), d->aoemajor, d->aoeminor,
+		"sectors\n", (unsigned long long)mac_addr(d->addr),
+		d->aoemajor, d->aoeminor,
 		d->fw_ver, (long long)d->ssize);
 }
 
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -99,41 +99,6 @@ bail:		spin_unlock_irqrestore(&emsgs_loc
 		up(&emsgs_sema);
 }
 
-#define PERLINE 16
-void
-aoechr_hdump(char *buf, int n)
-{
-	int bufsiz;
-	char *fbuf;
-	int linelen;
-	char *p, *e, *fp;
-
-	bufsiz = n * 3;			/* 2 hex digits and a space */
-	bufsiz += n / PERLINE + 1;	/* the newline characters */
-	bufsiz += 1;			/* the final '\0' */
-
-	fbuf = kmalloc(bufsiz, GFP_ATOMIC);
-	if (!fbuf) {
-		printk(KERN_INFO
-		       "%s: cannot allocate memory\n",
-		       __FUNCTION__);
-		return;
-	}
-	
-	for (p = buf; n <= 0;) {
-		linelen = n > PERLINE ? PERLINE : n;
-		n -= linelen;
-
-		fp = fbuf;
-		for (e=p+linelen; p<e; p++)
-			fp += sprintf(fp, "%2.2X ", *p & 255);
-		sprintf(fp, "\n");
-		aoechr_error(fbuf);
-	}
-
-	kfree(fbuf);
-}
-
 static ssize_t
 aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
 {
@@ -178,13 +143,13 @@ aoechr_rel(struct inode *inode, struct f
 static ssize_t
 aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
 {
-	int n;
+	unsigned long n;
 	char *mp;
 	struct ErrMsg *em;
 	ssize_t len;
 	ulong flags;
 
-	n = (int) filp->private_data;
+	n = (unsigned long) filp->private_data;
 	switch (n) {
 	case MINOR_ERR:
 		spin_lock_irqsave(&emsgs_lock, flags);
@@ -233,7 +198,7 @@ loop:
 	}
 }
 
-struct file_operations aoe_fops = {
+static struct file_operations aoe_fops = {
 	.write = aoechr_write,
 	.read = aoechr_read,
 	.open = aoechr_open,
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -90,19 +90,16 @@ newtag(struct aoedev *d)
 static int
 aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h)
 {
-	u16 type = __constant_cpu_to_be16(ETH_P_AOE);
-	u16 aoemajor = __cpu_to_be16(d->aoemajor);
 	u32 host_tag = newtag(d);
-	u32 tag = __cpu_to_be32(host_tag);
 
 	memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
 	memcpy(h->dst, d->addr, sizeof h->dst);
-	memcpy(h->type, &type, sizeof type);
+	h->type = __constant_cpu_to_be16(ETH_P_AOE);
 	h->verfl = AOE_HVER;
-	memcpy(h->major, &aoemajor, sizeof aoemajor);
+	h->major = cpu_to_be16(d->aoemajor);
 	h->minor = d->aoeminor;
 	h->cmd = AOECMD_ATA;
-	memcpy(h->tag, &tag, sizeof tag);
+	h->tag = cpu_to_be32(host_tag);
 
 	return host_tag;
 }
@@ -181,8 +178,12 @@ aoecmd_ata_rw(struct aoedev *d, struct f
 
 	skb = skb_prepare(d, f);
 	if (skb) {
-		skb->next = d->skblist;
-		d->skblist = skb;
+		skb->next = NULL;
+		if (d->sendq_hd)
+			d->sendq_tl->next = skb;
+		else
+			d->sendq_hd = skb;
+		d->sendq_tl = skb;
 	}
 }
 
@@ -215,7 +216,6 @@ rexmit(struct aoedev *d, struct frame *f
 	struct aoe_hdr *h;
 	char buf[128];
 	u32 n;
-	u32 net_tag;
 
 	n = newtag(d);
 
@@ -227,13 +227,16 @@ rexmit(struct aoedev *d, struct frame *f
 
 	h = (struct aoe_hdr *) f->data;
 	f->tag = n;
-	net_tag = __cpu_to_be32(n);
-	memcpy(h->tag, &net_tag, sizeof net_tag);
+	h->tag = cpu_to_be32(n);
 
 	skb = skb_prepare(d, f);
 	if (skb) {
-		skb->next = d->skblist;
-		d->skblist = skb;
+		skb->next = NULL;
+		if (d->sendq_hd)
+			d->sendq_tl->next = skb;
+		else
+			d->sendq_hd = skb;
+		d->sendq_tl = skb;
 	}
 }
 
@@ -285,8 +288,8 @@ tdie:		spin_unlock_irqrestore(&d->lock, 
 		}
 	}
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 	if (sl) {
 		n = d->rttavg <<= 1;
 		if (n > MAXTIMER)
@@ -308,16 +311,16 @@ ataid_complete(struct aoedev *d, unsigne
 	u16 n;
 
 	/* word 83: command set supported */
-	n = __le16_to_cpu(*((u16 *) &id[83<<1]));
+	n = le16_to_cpup((__le16 *) &id[83<<1]);
 
 	/* word 86: command set/feature enabled */
-	n |= __le16_to_cpu(*((u16 *) &id[86<<1]));
+	n |= le16_to_cpup((__le16 *) &id[86<<1]);
 
 	if (n & (1<<10)) {	/* bit 10: LBA 48 */
 		d->flags |= DEVFL_EXT;
 
 		/* word 100: number lba48 sectors */
-		ssize = __le64_to_cpu(*((u64 *) &id[100<<1]));
+		ssize = le64_to_cpup((__le64 *) &id[100<<1]);
 
 		/* set as in ide-disk.c:init_idedisk_capacity */
 		d->geo.cylinders = ssize;
@@ -328,12 +331,12 @@ ataid_complete(struct aoedev *d, unsigne
 		d->flags &= ~DEVFL_EXT;
 
 		/* number lba28 sectors */
-		ssize = __le32_to_cpu(*((u32 *) &id[60<<1]));
+		ssize = le32_to_cpup((__le32 *) &id[60<<1]);
 
 		/* NOTE: obsolete in ATA 6 */
-		d->geo.cylinders = __le16_to_cpu(*((u16 *) &id[54<<1]));
-		d->geo.heads = __le16_to_cpu(*((u16 *) &id[55<<1]));
-		d->geo.sectors = __le16_to_cpu(*((u16 *) &id[56<<1]));
+		d->geo.cylinders = le16_to_cpup((__le16 *) &id[54<<1]);
+		d->geo.heads = le16_to_cpup((__le16 *) &id[55<<1]);
+		d->geo.sectors = le16_to_cpup((__le16 *) &id[56<<1]);
 	}
 	d->ssize = ssize;
 	d->geo.start = 0;
@@ -380,29 +383,30 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 	register long n;
 	ulong flags;
 	char ebuf[128];
-	
+	u16 aoemajor;
+
 	hin = (struct aoe_hdr *) skb->mac.raw;
-	d = aoedev_bymac(hin->src);
+	aoemajor = be16_to_cpu(hin->major);
+	d = aoedev_by_aoeaddr(aoemajor, hin->minor);
 	if (d == NULL) {
 		snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
 			"for unknown device %d.%d\n",
-			 __be16_to_cpu(*((u16 *) hin->major)),
-			hin->minor);
+			 aoemajor, hin->minor);
 		aoechr_error(ebuf);
 		return;
 	}
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	f = getframe(d, __be32_to_cpu(*((u32 *) hin->tag)));
+	f = getframe(d, be32_to_cpu(hin->tag));
 	if (f == NULL) {
 		spin_unlock_irqrestore(&d->lock, flags);
 		snprintf(ebuf, sizeof ebuf,
 			"%15s e%d.%d    tag=%08x@%08lx\n",
 			"unexpected rsp",
-			__be16_to_cpu(*((u16 *) hin->major)),
+			be16_to_cpu(hin->major),
 			hin->minor,
-			__be32_to_cpu(*((u32 *) hin->tag)),
+			be32_to_cpu(hin->tag),
 			jiffies);
 		aoechr_error(ebuf);
 		return;
@@ -416,7 +420,9 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 
 	if (ahin->cmdstat & 0xa9) {	/* these bits cleared on success */
 		printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
-			"stat=%2.2Xh\n", ahout->cmdstat, ahin->cmdstat);
+			"stat=%2.2Xh from e%ld.%ld\n", 
+			ahout->cmdstat, ahin->cmdstat,
+			d->aoemajor, d->aoeminor);
 		if (buf)
 			buf->flags |= BUFFL_FAIL;
 	} else {
@@ -450,7 +456,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 			printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
 			       "outbound ata command %2.2Xh for %d.%d\n", 
 			       ahout->cmdstat,
-			       __be16_to_cpu(*((u16 *) hin->major)),
+			       be16_to_cpu(hin->major),
 			       hin->minor);
 		}
 	}
@@ -458,8 +464,22 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 	if (buf) {
 		buf->nframesout -= 1;
 		if (buf->nframesout == 0 && buf->resid == 0) {
-			n = !(buf->flags & BUFFL_FAIL);
-			bio_endio(buf->bio, buf->bio->bi_size, 0);
+			unsigned long duration = jiffies - buf->start_time;
+			unsigned long n_sect = buf->bio->bi_size >> 9;
+			struct gendisk *disk = d->gd;
+
+			if (bio_data_dir(buf->bio) == WRITE) {
+				disk_stat_inc(disk, writes);
+				disk_stat_add(disk, write_ticks, duration);
+				disk_stat_add(disk, write_sectors, n_sect);
+			} else {
+				disk_stat_inc(disk, reads);
+				disk_stat_add(disk, read_ticks, duration);
+				disk_stat_add(disk, read_sectors, n_sect);
+			}
+			disk_stat_add(disk, io_ticks, duration);
+			n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
+			bio_endio(buf->bio, buf->bio->bi_size, n);
 			mempool_free(buf, d->bufpool);
 		}
 	}
@@ -469,8 +489,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 
 	aoecmd_work(d);
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
@@ -484,8 +504,6 @@ aoecmd_cfg(ushort aoemajor, unsigned cha
 	struct aoe_cfghdr *ch;
 	struct sk_buff *skb, *sl;
 	struct net_device *ifp;
-	u16 aoe_type = __constant_cpu_to_be16(ETH_P_AOE);
-	u16 net_aoemajor = __cpu_to_be16(aoemajor);
 
 	sl = NULL;
 
@@ -505,9 +523,9 @@ aoecmd_cfg(ushort aoemajor, unsigned cha
 
 		memset(h->dst, 0xff, sizeof h->dst);
 		memcpy(h->src, ifp->dev_addr, sizeof h->src);
-		memcpy(h->type, &aoe_type, sizeof aoe_type);
+		h->type = __constant_cpu_to_be16(ETH_P_AOE);
 		h->verfl = AOE_HVER;
-		memcpy(h->major, &net_aoemajor, sizeof net_aoemajor);
+		h->major = cpu_to_be16(aoemajor);
 		h->minor = aoeminor;
 		h->cmd = AOECMD_CFG;
 
@@ -521,7 +539,7 @@ aoecmd_cfg(ushort aoemajor, unsigned cha
  
 /*
  * Since we only call this in one place (and it only prepares one frame)
- * we just return the skb.  Usually we'd chain it up to the d->skblist.
+ * we just return the skb.  Usually we'd chain it up to the aoedev sendq.
  */
 static struct sk_buff *
 aoecmd_ata_id(struct aoedev *d)
@@ -573,9 +591,10 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
 	struct aoedev *d;
 	struct aoe_hdr *h;
 	struct aoe_cfghdr *ch;
-	ulong flags, bufcnt, sysminor, aoemajor;
+	ulong flags, sysminor, aoemajor;
+	u16 bufcnt;
 	struct sk_buff *sl;
-	enum { MAXFRAMES = 8, MAXSYSMINOR = 255 };
+	enum { MAXFRAMES = 8 };
 
 	h = (struct aoe_hdr *) skb->mac.raw;
 	ch = (struct aoe_cfghdr *) (h+1);
@@ -584,7 +603,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
 	 * Enough people have their dip switches set backwards to
 	 * warrant a loud message for this special case.
 	 */
-	aoemajor = __be16_to_cpu(*((u16 *) h->major));
+	aoemajor = be16_to_cpu(h->major);
 	if (aoemajor == 0xfff) {
 		printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf "
 			"address is all ones.  Check shelf dip switches\n");
@@ -592,13 +611,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
 	}
 
 	sysminor = SYSMINOR(aoemajor, h->minor);
-	if (sysminor > MAXSYSMINOR) {
-		printk(KERN_INFO "aoe: aoecmd_cfg_rsp: sysminor %ld too "
-			"large\n", sysminor);
+	if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
+		printk(KERN_INFO
+			"aoe: e%ld.%d: minor number too large\n", 
+			aoemajor, (int) h->minor);
 		return;
 	}
 
-	bufcnt = __be16_to_cpu(*((u16 *) ch->bufcnt));
+	bufcnt = be16_to_cpu(ch->bufcnt);
 	if (bufcnt > MAXFRAMES)	/* keep it reasonable */
 		bufcnt = MAXFRAMES;
 
@@ -615,7 +635,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
 		return;
 	}
 
-	d->fw_ver = __be16_to_cpu(*((u16 *) ch->fwver));
+	d->fw_ver = be16_to_cpu(ch->fwver);
 
 	/* we get here only if the device is new */
 	sl = aoecmd_ata_id(d);
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -13,7 +13,7 @@ static struct aoedev *devlist;
 static spinlock_t devlist_lock;
 
 struct aoedev *
-aoedev_bymac(unsigned char *macaddr)
+aoedev_by_aoeaddr(int maj, int min)
 {
 	struct aoedev *d;
 	ulong flags;
@@ -21,7 +21,7 @@ aoedev_bymac(unsigned char *macaddr)
 	spin_lock_irqsave(&devlist_lock, flags);
 
 	for (d=devlist; d; d=d->next)
-		if (!memcmp(d->addr, macaddr, 6))
+		if (d->aoemajor == maj && d->aoeminor == min)
 			break;
 
 	spin_unlock_irqrestore(&devlist_lock, flags);
@@ -109,26 +109,22 @@ aoedev_set(ulong sysminor, unsigned char
 	spin_lock_irqsave(&devlist_lock, flags);
 
 	for (d=devlist; d; d=d->next)
-		if (d->sysminor == sysminor
-		|| memcmp(d->addr, addr, sizeof d->addr) == 0)
+		if (d->sysminor == sysminor)
 			break;
 
 	if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) {
 		spin_unlock_irqrestore(&devlist_lock, flags);
 		printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
 		return NULL;
-	}
+	} /* if newdev, (d->flags & DEVFL_UP) == 0 for below */
 
 	spin_unlock_irqrestore(&devlist_lock, flags);
 	spin_lock_irqsave(&d->lock, flags);
 
 	d->ifp = ifp;
-
-	if (d->sysminor != sysminor
-	|| memcmp(d->addr, addr, sizeof d->addr)
-	|| (d->flags & DEVFL_UP) == 0) {
+	memcpy(d->addr, addr, sizeof d->addr);
+	if ((d->flags & DEVFL_UP) == 0) {
 		aoedev_downdev(d); /* flushes outstanding frames */
-		memcpy(d->addr, addr, sizeof d->addr);
 		d->sysminor = sysminor;
 		d->aoemajor = AOEMAJOR(sysminor);
 		d->aoeminor = AOEMINOR(sysminor);
@@ -147,7 +143,8 @@ aoedev_freedev(struct aoedev *d)
 		put_disk(d->gd);
 	}
 	kfree(d->frames);
-	mempool_destroy(d->bufpool);
+	if (d->bufpool)
+		mempool_destroy(d->bufpool);
 	kfree(d);
 }
 
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -7,6 +7,7 @@
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
 #include <linux/netdevice.h>
+#include <linux/moduleparam.h>
 #include "aoe.h"
 
 #define NECODES 5
@@ -26,6 +27,19 @@ enum {
 };
 
 static char aoe_iflist[IFLISTSZ];
+module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600);
+MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"\n");
+
+#ifndef MODULE
+static int __init aoe_iflist_setup(char *str)
+{
+	strncpy(aoe_iflist, str, IFLISTSZ);
+	aoe_iflist[IFLISTSZ - 1] = '\0';
+	return 1;
+}
+
+__setup("aoe_iflist=", aoe_iflist_setup);
+#endif
 
 int
 is_aoe_netif(struct net_device *ifp)
@@ -36,7 +50,8 @@ is_aoe_netif(struct net_device *ifp)
 	if (aoe_iflist[0] == '\0')
 		return 1;
 
-	for (p = aoe_iflist; *p; p = q + strspn(q, WHITESPACE)) {
+	p = aoe_iflist + strspn(aoe_iflist, WHITESPACE);
+	for (; *p; p = q + strspn(q, WHITESPACE)) {
 		q = p + strcspn(p, WHITESPACE);
 		if (q != p)
 			len = q - p;
@@ -69,7 +84,7 @@ set_aoe_iflist(const char __user *user_s
 u64
 mac_addr(char addr[6])
 {
-	u64 n = 0;
+	__be64 n = 0;
 	char *p = (char *) &n;
 
 	memcpy(p + 2, addr, 6);	/* (sizeof addr != 6) */
@@ -108,7 +123,7 @@ static int
 aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt)
 {
 	struct aoe_hdr *h;
-	ulong n;
+	u32 n;
 
 	skb = skb_check(skb);
 	if (!skb)
@@ -121,7 +136,7 @@ aoenet_rcv(struct sk_buff *skb, struct n
 	skb_push(skb, ETH_HLEN);	/* (1) */
 
 	h = (struct aoe_hdr *) skb->mac.raw;
-	n = __be32_to_cpu(*((u32 *) h->tag));
+	n = be32_to_cpu(h->tag);
 	if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
 		goto exit;
 
@@ -132,7 +147,7 @@ aoenet_rcv(struct sk_buff *skb, struct n
 		if (net_ratelimit())
 			printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; "
 			       "ecode=%d '%s'\n",
-			       __be16_to_cpu(*((u16 *) h->major)), h->minor, 
+			       be16_to_cpu(h->major), h->minor, 
 			       h->err, aoe_errlist[n]);
 		goto exit;
 	}
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -25,7 +25,7 @@
 #define REQ_ASYNC	0
 
 /*
- * See Documentation/as-iosched.txt
+ * See Documentation/block/as-iosched.txt
  */
 
 /*
@@ -1463,35 +1463,36 @@ static void as_add_request(struct as_dat
 	arq->state = AS_RQ_QUEUED;
 }
 
-/*
- * requeue the request. The request has not been completed, nor is it a
- * new request, so don't touch accounting.
- */
-static void as_requeue_request(request_queue_t *q, struct request *rq)
+static void as_deactivate_request(request_queue_t *q, struct request *rq)
 {
 	struct as_data *ad = q->elevator->elevator_data;
 	struct as_rq *arq = RQ_DATA(rq);
 
 	if (arq) {
-		if (arq->state != AS_RQ_REMOVED) {
-			printk("arq->state %d\n", arq->state);
-			WARN_ON(1);
+		if (arq->state == AS_RQ_REMOVED) {
+			arq->state = AS_RQ_DISPATCHED;
+			if (arq->io_context && arq->io_context->aic)
+				atomic_inc(&arq->io_context->aic->nr_dispatched);
 		}
-
-		arq->state = AS_RQ_DISPATCHED;
-		if (arq->io_context && arq->io_context->aic)
-			atomic_inc(&arq->io_context->aic->nr_dispatched);
 	} else
 		WARN_ON(blk_fs_request(rq)
 			&& (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) );
 
-	list_add(&rq->queuelist, ad->dispatch);
-
 	/* Stop anticipating - let this request get through */
 	as_antic_stop(ad);
 }
 
 /*
+ * requeue the request. The request has not been completed, nor is it a
+ * new request, so don't touch accounting.
+ */
+static void as_requeue_request(request_queue_t *q, struct request *rq)
+{
+	as_deactivate_request(q, rq);
+	list_add(&rq->queuelist, &q->queue_head);
+}
+
+/*
  * Account a request that is inserted directly onto the dispatch queue.
  * arq->io_context->aic->nr_dispatched should not need to be incremented
  * because only new requests should come through here: requeues go through
@@ -2080,6 +2081,7 @@ static struct elevator_type iosched_as =
 		.elevator_add_req_fn =		as_insert_request,
 		.elevator_remove_req_fn =	as_remove_request,
 		.elevator_requeue_req_fn = 	as_requeue_request,
+		.elevator_deactivate_req_fn = 	as_deactivate_request,
 		.elevator_queue_empty_fn =	as_queue_empty,
 		.elevator_completed_req_fn =	as_completed_request,
 		.elevator_former_req_fn =	as_former_request,
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -46,14 +46,14 @@
 #include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.4)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,4)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.6)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.4");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-			" SA6i P600");
+			" SA6i P600 P800 E400");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
 #include <linux/cciss_ioctl.h>
 
 /* define the PCI info for the cards we can control */
-const struct pci_device_id cciss_pci_device_id[] = {
+static const struct pci_device_id cciss_pci_device_id[] = {
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
 			0x0E11, 0x4070, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
@@ -82,6 +82,10 @@ const struct pci_device_id cciss_pci_dev
 		0x0E11, 0x4091, 0, 0, 0},
 	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
 		0x103C, 0x3225, 0, 0, 0},
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+		0x103c, 0x3223, 0, 0, 0},
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+		0x103c, 0x3231, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -103,6 +107,8 @@ static struct board_type products[] = {
 	{ 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
 	{ 0x40910E11, "Smart Array 6i", &SA5_access},
 	{ 0x3225103C, "Smart Array P600", &SA5_access},
+	{ 0x3223103C, "Smart Array P800", &SA5_access},
+	{ 0x3231103C, "Smart Array E400", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -114,7 +120,11 @@ static struct board_type products[] = {
 
 #define READ_AHEAD 	 1024
 #define NR_CMDS		 384 /* #commands that can be outstanding */
-#define MAX_CTLR 8
+#define MAX_CTLR	32
+
+/* Originally cciss driver only supports 8 major numbers */
+#define MAX_CTLR_ORIG 	8
+
 
 #define CCISS_DMA_MASK	0xFFFFFFFF	/* 32 bit DMA */
 
@@ -294,7 +304,7 @@ cciss_proc_write(struct file *file, cons
 	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
 	cmd[count] = '\0';
 	len = strlen(cmd);	// above 3 lines ensure safety
-	if (cmd[len-1] == '\n') 
+	if (len && cmd[len-1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
@@ -2080,6 +2090,9 @@ static void do_cciss_request(request_que
 	drive_info_struct *drv;
 	int i, dir;
 
+	/* We call start_io here in case there is a command waiting on the
+	 * queue that has not been sent.
+	*/
 	if (blk_queue_plugged(q))
 		goto startio;
 
@@ -2168,6 +2181,9 @@ queue:
 full:
 	blk_stop_queue(q);
 startio:
+	/* We will already have the driver lock here so not need
+	 * to lock it.
+	*/
 	start_io(h);
 }
 
@@ -2177,7 +2193,8 @@ static irqreturn_t do_cciss_intr(int irq
 	CommandList_struct *c;
 	unsigned long flags;
 	__u32 a, a1;
-
+	int j;
+	int start_queue = h->next_to_run;
 
 	/* Is this interrupt for us? */
 	if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))
@@ -2224,13 +2241,50 @@ static irqreturn_t do_cciss_intr(int irq
 		}
 	}
 
-	/*
-	 * See if we can queue up some more IO
+ 	/* check to see if we have maxed out the number of commands that can
+ 	 * be placed on the queue.  If so then exit.  We do this check here
+ 	 * in case the interrupt we serviced was from an ioctl and did not
+ 	 * free any new commands.
 	 */
-	blk_start_queue(h->queue);
+ 	if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ 		goto cleanup;
+
+ 	/* We have room on the queue for more commands.  Now we need to queue
+ 	 * them up.  We will also keep track of the next queue to run so
+ 	 * that every queue gets a chance to be started first.
+ 	*/
+ 	for (j=0; j < NWD; j++){
+ 		int curr_queue = (start_queue + j) % NWD;
+ 		/* make sure the disk has been added and the drive is real
+ 		 * because this can be called from the middle of init_one.
+ 		*/
+ 		if(!(h->gendisk[curr_queue]->queue) ||
+		 		   !(h->drv[curr_queue].heads))
+ 			continue;
+ 		blk_start_queue(h->gendisk[curr_queue]->queue);
+
+ 		/* check to see if we have maxed out the number of commands
+ 		 * that can be placed on the queue.
+ 		*/
+ 		if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ 		{
+ 			if (curr_queue == start_queue){
+ 				h->next_to_run = (start_queue + 1) % NWD;
+ 				goto cleanup;
+ 			} else {
+ 				h->next_to_run = curr_queue;
+ 				goto cleanup;
+ 	}
+ 		} else {
+ 			curr_queue = (curr_queue + 1) % NWD;
+ 		}
+ 	}
+
+cleanup:
 	spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 	return IRQ_HANDLED;
 }
+
 /* 
  *  We cannot read the structure directly, for portablity we must use 
  *   the io functions.
@@ -2644,7 +2698,7 @@ static int alloc_cciss_hba(void)
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
-		" of 8 controllers.\n");
+		" of %d controllers.\n", MAX_CTLR);
 	goto out;
 Enomem:
 	printk(KERN_ERR "cciss: out of memory.\n");
@@ -2676,13 +2730,14 @@ static int __devinit cciss_init_one(stru
 	request_queue_t *q;
 	int i;
 	int j;
+	int rc;
 
 	printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
 			" bus %d dev %d func %d\n",
 		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
 			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if( i < 0 ) 
+	if(i < 0)
 		return (-1);
 	if (cciss_pci_init(hba[i], pdev) != 0)
 		goto clean1;
@@ -2701,11 +2756,24 @@ static int __devinit cciss_init_one(stru
 		goto clean1;
 	}
 
-	if (register_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname)) {
-		printk(KERN_ERR "cciss: Unable to register device %s\n",
-				hba[i]->devname);
+	/*
+	 * register with the major number, or get a dynamic major number
+	 * by passing 0 as argument.  This is done for greater than
+	 * 8 controller support.
+	 */
+	if (i < MAX_CTLR_ORIG)
+		hba[i]->major = MAJOR_NR + i;
+	rc = register_blkdev(hba[i]->major, hba[i]->devname);
+	if(rc == -EBUSY || rc == -EINVAL) {
+		printk(KERN_ERR
+			"cciss:  Unable to get major number %d for %s "
+			"on hba %d\n", hba[i]->major, hba[i]->devname, i);
 		goto clean1;
 	}
+	else {
+		if (i >= MAX_CTLR_ORIG)
+			hba[i]->major = rc;
+	}
 
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
@@ -2776,7 +2844,7 @@ static int __devinit cciss_init_one(stru
 
 		sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
 		sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j);
-		disk->major = COMPAQ_CISS_MAJOR + i;
+		disk->major = hba[i]->major;
 		disk->first_minor = j << NWD_SHIFT;
 		disk->fops = &cciss_fops;
 		disk->queue = hba[i]->queue;
@@ -2805,7 +2873,7 @@ clean4:
 			hba[i]->errinfo_pool_dhandle);
 	free_irq(hba[i]->intr, hba[i]);
 clean2:
-	unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname);
+	unregister_blkdev(hba[i]->major, hba[i]->devname);
 clean1:
 	release_io_mem(hba[i]);
 	free_hba(i);
@@ -2847,7 +2915,7 @@ static void __devexit cciss_remove_one (
 	pci_set_drvdata(pdev, NULL);
 	iounmap(hba[i]->vaddr);
 	cciss_unregister_scsi(i);  /* unhook from SCSI subsystem */
-	unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname);
+	unregister_blkdev(hba[i]->major, hba[i]->devname);
 	remove_proc_entry(hba[i]->devname, proc_cciss);	
 	
 	/* remove it from the disk list */
@@ -2878,7 +2946,7 @@ static struct pci_driver cciss_pci_drive
  *  This is it.  Register the PCI driver information for the cards we control
  *  the OS will call our registered routines when it finds one of our cards. 
  */
-int __init cciss_init(void)
+static int __init cciss_init(void)
 {
 	printk(KERN_INFO DRIVER_NAME "\n");
 
@@ -2886,12 +2954,7 @@ int __init cciss_init(void)
 	return pci_module_init(&cciss_pci_driver);
 }
 
-static int __init init_cciss_module(void)
-{
-	return ( cciss_init());
-}
-
-static void __exit cleanup_cciss_module(void)
+static void __exit cciss_cleanup(void)
 {
 	int i;
 
@@ -2909,5 +2972,5 @@ static void __exit cleanup_cciss_module(
 	remove_proc_entry("cciss", proc_root_driver);
 }
 
-module_init(init_cciss_module);
-module_exit(cleanup_cciss_module);
+module_init(cciss_init);
+module_exit(cciss_cleanup);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -13,6 +13,8 @@
 #define IO_OK		0
 #define IO_ERROR	1
 
+#define MAJOR_NR COMPAQ_CISS_MAJOR
+
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
@@ -50,6 +52,7 @@ struct ctlr_info 
 	CfgTable_struct __iomem *cfgtable;
 	unsigned int intr;
 	int	interrupts_enabled;
+	int	major;
 	int 	max_commands;
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
@@ -81,6 +84,11 @@ struct ctlr_info 
 	int			nr_frees; 
 	int			busy_configuring;
 
+	/* This element holds the zero based queue number of the last
+	 * queue to be started.  It is used for fairness.
+	*/
+	int			next_to_run;
+
 	// Disk structures we need to pass back
 	struct gendisk   *gendisk[NWD];
 #ifdef CONFIG_CISS_SCSI_TAPE
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -53,9 +53,7 @@ static int sendcmd(
 	int cmd_type);
 
 
-const char *cciss_scsi_info(struct Scsi_Host *sa);
-
-int cciss_scsi_proc_info(
+static int cciss_scsi_proc_info(
 		struct Scsi_Host *sh,
 		char *buffer, /* data buffer */
 		char **start, 	   /* where data in buffer starts */
@@ -63,7 +61,7 @@ int cciss_scsi_proc_info(
 		int length, 	   /* length of data in buffer */
 		int func);	   /* 0 == read, 1 == write */
 
-int cciss_scsi_queue_command (struct scsi_cmnd *cmd, 
+static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
 		void (* done)(struct scsi_cmnd *));
 
 static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
@@ -717,8 +715,6 @@ cciss_scsi_detect(int ctlr)
 	return 0;
 }
 
-static void __exit cleanup_cciss_module(void);
-
 static void
 cciss_unmap_one(struct pci_dev *pdev,
 		CommandList_struct *cp,
@@ -1119,7 +1115,7 @@ cciss_scsi_user_command(int ctlr, int ho
 }
 
 
-int
+static int
 cciss_scsi_proc_info(struct Scsi_Host *sh,
 		char *buffer, /* data buffer */
 		char **start, 	   /* where data in buffer starts */
@@ -1154,29 +1150,6 @@ cciss_scsi_proc_info(struct Scsi_Host *s
 			buffer, length);	
 } 
 
-/* this is via the generic proc support */
-const char *
-cciss_scsi_info(struct Scsi_Host *sa)
-{
-	static char buf[300];
-	ctlr_info_t *ci;
-
-	/* probably need to work on putting a bit more info in here... */
-	/* this is output via the /proc filesystem. */
-
-	ci = (ctlr_info_t *) sa->hostdata[0];
-
-	sprintf(buf, "%s %c%c%c%c\n",
-		ci->product_name, 
-		ci->firm_ver[0],
-		ci->firm_ver[1],
-		ci->firm_ver[2],
-		ci->firm_ver[3]);
-
-	return buf; 
-}
-
-
 /* cciss_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci 
    dma mapping  and fills in the scatter gather entries of the 
    cciss command, cp. */
@@ -1230,7 +1203,7 @@ cciss_scatter_gather(struct pci_dev *pde
 }
 
 
-int 
+static int
 cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
 {
 	ctlr_info_t **c;
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -39,7 +39,6 @@
 #define SCSI_CCISS_CAN_QUEUE 2
 
 /* 
-	info:           	cciss_scsi_info,		\
 
 Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
 Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -607,10 +607,7 @@ out:
 	return NULL;
 }
 
-/*
- * make sure the service time gets corrected on reissue of this request
- */
-static void cfq_requeue_request(request_queue_t *q, struct request *rq)
+static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
 {
 	struct cfq_rq *crq = RQ_DATA(rq);
 
@@ -627,6 +624,14 @@ static void cfq_requeue_request(request_
 			cfqq->cfqd->rq_in_driver--;
 		}
 	}
+}
+
+/*
+ * make sure the service time gets corrected on reissue of this request
+ */
+static void cfq_requeue_request(request_queue_t *q, struct request *rq)
+{
+	cfq_deactivate_request(q, rq);
 	list_add(&rq->queuelist, &q->queue_head);
 }
 
@@ -1197,13 +1202,16 @@ retry:
 		if (new_cfqq) {
 			cfqq = new_cfqq;
 			new_cfqq = NULL;
-		} else if (gfp_mask & __GFP_WAIT) {
+		} else {
 			spin_unlock_irq(cfqd->queue->queue_lock);
 			new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
 			spin_lock_irq(cfqd->queue->queue_lock);
+
+			if (!new_cfqq && !(gfp_mask & __GFP_WAIT))
+				goto out;
+
 			goto retry;
-		} else
-			goto out;
+		}
 
 		memset(cfqq, 0, sizeof(*cfqq));
 
@@ -1790,7 +1798,7 @@ static struct sysfs_ops cfq_sysfs_ops = 
 	.store	= cfq_attr_store,
 };
 
-struct kobj_type cfq_ktype = {
+static struct kobj_type cfq_ktype = {
 	.sysfs_ops	= &cfq_sysfs_ops,
 	.default_attrs	= default_attrs,
 };
@@ -1804,6 +1812,7 @@ static struct elevator_type iosched_cfq 
 		.elevator_add_req_fn =		cfq_insert_request,
 		.elevator_remove_req_fn =	cfq_remove_request,
 		.elevator_requeue_req_fn =	cfq_requeue_request,
+		.elevator_deactivate_req_fn =	cfq_deactivate_request,
 		.elevator_queue_empty_fn =	cfq_queue_empty,
 		.elevator_completed_req_fn =	cfq_completed_request,
 		.elevator_former_req_fn =	cfq_former_request,
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -97,7 +97,7 @@ static struct board_type products[] = {
 };
 
 /* define the PCI info for the PCI cards this driver can control */
-const struct pci_device_id cpqarray_pci_device_id[] =
+static const struct pci_device_id cpqarray_pci_device_id[] =
 {
 	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
 		0x0E11, 0x4058, 0, 0, 0},       /* SA431 */
@@ -135,7 +135,6 @@ static struct gendisk *ida_gendisk[MAX_C
 /* Debug Extra Paranoid... */
 #define DBGPX(s) do { } while(0)
 
-int cpqarray_init_step2(void);
 static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);
 static void __iomem *remap_pci_mem(ulong base, ulong size);
 static int cpqarray_eisa_detect(void);
@@ -312,14 +311,6 @@ static int ida_proc_get_info(char *buffe
 
 module_param_array(eisa, int, NULL, 0);
 
-/* This is a bit of a hack,
- * necessary to support both eisa and pci
- */
-int __init cpqarray_init(void)
-{
-	return (cpqarray_init_step2());
-}
-
 static void release_io_mem(ctlr_info_t *c)
 {
 	/* if IO mem was not protected do nothing */
@@ -560,7 +551,7 @@ static struct pci_driver cpqarray_pci_dr
  *  This is it.  Find all the controllers and register them.
  *  returns the number of block devices registered.
  */
-int __init cpqarray_init_step2(void)
+static int __init cpqarray_init(void)
 {
 	int num_cntlrs_reg = 0;
 	int i;
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -19,7 +19,7 @@
 #include <linux/rbtree.h>
 
 /*
- * See Documentation/deadline-iosched.txt
+ * See Documentation/block/deadline-iosched.txt
  */
 static int read_expire = HZ / 2;  /* max time before a read is submitted. */
 static int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */
@@ -909,7 +909,7 @@ static struct sysfs_ops deadline_sysfs_o
 	.store	= deadline_attr_store,
 };
 
-struct kobj_type deadline_ktype = {
+static struct kobj_type deadline_ktype = {
 	.sysfs_ops	= &deadline_sysfs_ops,
 	.default_attrs	= default_attrs,
 };
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -92,7 +92,7 @@ inline int elv_try_last_merge(request_qu
 }
 EXPORT_SYMBOL(elv_try_last_merge);
 
-struct elevator_type *elevator_find(const char *name)
+static struct elevator_type *elevator_find(const char *name)
 {
 	struct elevator_type *e = NULL;
 	struct list_head *entry;
@@ -220,11 +220,6 @@ void elevator_exit(elevator_t *e)
 	kfree(e);
 }
 
-int elevator_global_init(void)
-{
-	return 0;
-}
-
 int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
 {
 	elevator_t *e = q->elevator;
@@ -255,8 +250,16 @@ void elv_merge_requests(request_queue_t 
 		e->ops->elevator_merge_req_fn(q, rq, next);
 }
 
-void elv_requeue_request(request_queue_t *q, struct request *rq)
+/*
+ * For careful internal use by the block layer. Essentially the same as
+ * a requeue in that it tells the io scheduler that this request is not
+ * active in the driver or hardware anymore, but we don't want the request
+ * added back to the scheduler. Function is not exported.
+ */
+void elv_deactivate_request(request_queue_t *q, struct request *rq)
 {
+	elevator_t *e = q->elevator;
+
 	/*
 	 * it already went through dequeue, we need to decrement the
 	 * in_flight count again
@@ -264,6 +267,24 @@ void elv_requeue_request(request_queue_t
 	if (blk_account_rq(rq))
 		q->in_flight--;
 
+	rq->flags &= ~REQ_STARTED;
+
+	if (e->ops->elevator_deactivate_req_fn)
+		e->ops->elevator_deactivate_req_fn(q, rq);
+}
+
+void elv_requeue_request(request_queue_t *q, struct request *rq)
+{
+	elv_deactivate_request(q, rq);
+
+	/*
+	 * if this is the flush, requeue the original instead and drop the flush
+	 */
+	if (rq->flags & REQ_BAR_FLUSH) {
+		clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+		rq = rq->end_io_data;
+	}
+
 	/*
 	 * if iosched has an explicit requeue hook, then use that. otherwise
 	 * just put the request at the front of the queue
@@ -296,7 +317,7 @@ void __elv_add_request(request_queue_t *
 			int nrq = q->rq.count[READ] + q->rq.count[WRITE]
 				  - q->in_flight;
 
-			if (nrq == q->unplug_thresh)
+			if (nrq >= q->unplug_thresh)
 				__generic_unplug_device(q);
 		}
 	} else
@@ -320,7 +341,21 @@ void elv_add_request(request_queue_t *q,
 
 static inline struct request *__elv_next_request(request_queue_t *q)
 {
-	return q->elevator->ops->elevator_next_req_fn(q);
+	struct request *rq = q->elevator->ops->elevator_next_req_fn(q);
+
+	/*
+	 * if this is a barrier write and the device has to issue a
+	 * flush sequence to support it, check how far we are
+	 */
+	if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) {
+		BUG_ON(q->ordered == QUEUE_ORDERED_NONE);
+
+		if (q->ordered == QUEUE_ORDERED_FLUSH &&
+		    !blk_barrier_preflush(rq))
+			rq = blk_start_pre_flush(q, rq);
+	}
+
+	return rq;
 }
 
 struct request *elv_next_request(request_queue_t *q)
@@ -652,8 +687,6 @@ ssize_t elv_iosched_show(request_queue_t
 	return len;
 }
 
-module_init(elevator_global_init);
-
 EXPORT_SYMBOL(elv_add_request);
 EXPORT_SYMBOL(__elv_add_request);
 EXPORT_SYMBOL(elv_requeue_request);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3345,7 +3345,7 @@ static inline int set_geometry(unsigned 
 			struct block_device *bdev = opened_bdev[cnt];
 			if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
 				continue;
-			__invalidate_device(bdev, 0);
+			__invalidate_device(bdev);
 		}
 		up(&open_lock);
 	} else {
@@ -4217,7 +4217,7 @@ static struct kobject *floppy_find(dev_t
 	return get_disk(disks[drive]);
 }
 
-int __init floppy_init(void)
+static int __init floppy_init(void)
 {
 	int i, unit, drive;
 	int err, dr;
@@ -4370,6 +4370,10 @@ int __init floppy_init(void)
 		goto out_flush_work;
 	}
 
+	err = platform_device_register(&floppy_device);
+	if (err)
+		goto out_flush_work;
+
 	for (drive = 0; drive < N_DRIVE; drive++) {
 		if (!(allowed_drive_mask & (1 << drive)))
 			continue;
@@ -4379,23 +4383,12 @@ int __init floppy_init(void)
 		disks[drive]->private_data = (void *)(long)drive;
 		disks[drive]->queue = floppy_queue;
 		disks[drive]->flags |= GENHD_FL_REMOVABLE;
+		disks[drive]->driverfs_dev = &floppy_device.dev;
 		add_disk(disks[drive]);
 	}
 
-	err = platform_device_register(&floppy_device);
-	if (err)
-		goto out_del_disk;
-
 	return 0;
 
-out_del_disk:
-	for (drive = 0; drive < N_DRIVE; drive++) {
-		if (!(allowed_drive_mask & (1 << drive)))
-			continue;
-		if (fdc_state[FDC(drive)].version == FDC_NONE)
-			continue;
-		del_gendisk(disks[drive]);
-	}
 out_flush_work:
 	flush_scheduled_work();
 	if (usage_count)
@@ -4558,7 +4551,7 @@ static void floppy_release_irq_and_dma(v
 
 #ifdef MODULE
 
-char *floppy;
+static char *floppy;
 
 static void unregister_devfs_entries(int drive)
 {
@@ -4600,7 +4593,6 @@ void cleanup_module(void)
 	int drive;
 
 	init_completion(&device_release);
-	platform_device_unregister(&floppy_device);
 	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 
@@ -4614,6 +4606,7 @@ void cleanup_module(void)
 		}
 		put_disk(disks[drive]);
 	}
+	platform_device_unregister(&floppy_device);
 	devfs_remove("floppy");
 
 	del_timer_sync(&fd_timeout);
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
+#include <linux/buffer_head.h>
 
 #define MAX_PROBE_HASH 255	/* random */
 
@@ -302,7 +303,7 @@ static struct kobject *base_probe(dev_t 
 
 static int __init genhd_device_init(void)
 {
-	bdev_map = kobj_map_init(base_probe, &block_subsys);
+	bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
 	blk_dev_init();
 	subsystem_register(&block_subsys);
 	return 0;
@@ -430,43 +431,58 @@ static int block_hotplug_filter(struct k
 static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
 			 int num_envp, char *buffer, int buffer_size)
 {
-	struct device *dev = NULL;
 	struct kobj_type *ktype = get_ktype(kobj);
+	struct device *physdev;
+	struct gendisk *disk;
+	struct hd_struct *part;
 	int length = 0;
 	int i = 0;
 
-	/* get physical device backing disk or partition */
 	if (ktype == &ktype_block) {
-		struct gendisk *disk = container_of(kobj, struct gendisk, kobj);
-		dev = disk->driverfs_dev;
+		disk = container_of(kobj, struct gendisk, kobj);
+		add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+				    &length, "MINOR=%u", disk->first_minor);
 	} else if (ktype == &ktype_part) {
-		struct gendisk *disk = container_of(kobj->parent, struct gendisk, kobj);
-		dev = disk->driverfs_dev;
-	}
+		disk = container_of(kobj->parent, struct gendisk, kobj);
+		part = container_of(kobj, struct hd_struct, kobj);
+		add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+				    &length, "MINOR=%u",
+				    disk->first_minor + part->partno);
+	} else
+		return 0;
 
-	if (dev) {
-		/* add physical device, backing this device  */
-		char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+	add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length,
+			    "MAJOR=%u", disk->major);
+
+	/* add physical device, backing this device  */
+	physdev = disk->driverfs_dev;
+	if (physdev) {
+		char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
 
 		add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
 				    &length, "PHYSDEVPATH=%s", path);
 		kfree(path);
 
-		/* add bus name of physical device */
-		if (dev->bus)
+		if (physdev->bus)
 			add_hotplug_env_var(envp, num_envp, &i,
 					    buffer, buffer_size, &length,
-					    "PHYSDEVBUS=%s", dev->bus->name);
+					    "PHYSDEVBUS=%s",
+					    physdev->bus->name);
 
-		/* add driver name of physical device */
-		if (dev->driver)
+		if (physdev->driver)
 			add_hotplug_env_var(envp, num_envp, &i,
 					    buffer, buffer_size, &length,
-					    "PHYSDEVDRIVER=%s", dev->driver->name);
-
-		envp[i] = NULL;
+					    "PHYSDEVDRIVER=%s",
+					    physdev->driver->name);
 	}
 
+	/* terminate, set to next free slot, shrink available space */
+	envp[i] = NULL;
+	envp = &envp[i];
+	num_envp -= i;
+	buffer = &buffer[length];
+	buffer_size -= length;
+
 	return 0;
 }
 
@@ -661,7 +677,8 @@ int invalidate_partition(struct gendisk 
 	int res = 0;
 	struct block_device *bdev = bdget_disk(disk, index);
 	if (bdev) {
-		res = __invalidate_device(bdev, 1);
+		fsync_bdev(bdev);
+		res = __invalidate_device(bdev);
 		bdput(bdev);
 	}
 	return res;
diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c
--- a/drivers/block/ioctl.c
+++ b/drivers/block/ioctl.c
@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *fi
 	}
 	return ret;
 }
+
+EXPORT_SYMBOL_GPL(blkdev_ioctl);
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -238,7 +238,7 @@ void blk_queue_make_request(request_queu
 	q->make_request_fn = mfn;
 	q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 	q->backing_dev_info.state = 0;
-	q->backing_dev_info.memory_backed = 0;
+	q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
 	blk_queue_max_sectors(q, MAX_SECTORS);
 	blk_queue_hardsect_size(q, 512);
 	blk_queue_dma_alignment(q, 511);
@@ -267,6 +267,25 @@ void blk_queue_make_request(request_queu
 
 EXPORT_SYMBOL(blk_queue_make_request);
 
+static inline void rq_init(request_queue_t *q, struct request *rq)
+{
+	INIT_LIST_HEAD(&rq->queuelist);
+
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->bio = rq->biotail = NULL;
+	rq->buffer = NULL;
+	rq->ref_count = 1;
+	rq->q = q;
+	rq->waiting = NULL;
+	rq->special = NULL;
+	rq->data_len = 0;
+	rq->data = NULL;
+	rq->sense = NULL;
+	rq->end_io = NULL;
+	rq->end_io_data = NULL;
+}
+
 /**
  * blk_queue_ordered - does this queue support ordered writes
  * @q:     the request queue
@@ -281,10 +300,26 @@ EXPORT_SYMBOL(blk_queue_make_request);
  **/
 void blk_queue_ordered(request_queue_t *q, int flag)
 {
-	if (flag)
-		set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
-	else
-		clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
+	switch (flag) {
+		case QUEUE_ORDERED_NONE:
+			if (q->flush_rq)
+				kmem_cache_free(request_cachep, q->flush_rq);
+			q->flush_rq = NULL;
+			q->ordered = flag;
+			break;
+		case QUEUE_ORDERED_TAG:
+			q->ordered = flag;
+			break;
+		case QUEUE_ORDERED_FLUSH:
+			q->ordered = flag;
+			if (!q->flush_rq)
+				q->flush_rq = kmem_cache_alloc(request_cachep,
+								GFP_KERNEL);
+			break;
+		default:
+			printk("blk_queue_ordered: bad value %d\n", flag);
+			break;
+	}
 }
 
 EXPORT_SYMBOL(blk_queue_ordered);
@@ -306,6 +341,169 @@ void blk_queue_issue_flush_fn(request_qu
 
 EXPORT_SYMBOL(blk_queue_issue_flush_fn);
 
+/*
+ * Cache flushing for ordered writes handling
+ */
+static void blk_pre_flush_end_io(struct request *flush_rq)
+{
+	struct request *rq = flush_rq->end_io_data;
+	request_queue_t *q = rq->q;
+
+	rq->flags |= REQ_BAR_PREFLUSH;
+
+	if (!flush_rq->errors)
+		elv_requeue_request(q, rq);
+	else {
+		q->end_flush_fn(q, flush_rq);
+		clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+		q->request_fn(q);
+	}
+}
+
+static void blk_post_flush_end_io(struct request *flush_rq)
+{
+	struct request *rq = flush_rq->end_io_data;
+	request_queue_t *q = rq->q;
+
+	rq->flags |= REQ_BAR_POSTFLUSH;
+
+	q->end_flush_fn(q, flush_rq);
+	clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+	q->request_fn(q);
+}
+
+struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
+{
+	struct request *flush_rq = q->flush_rq;
+
+	BUG_ON(!blk_barrier_rq(rq));
+
+	if (test_and_set_bit(QUEUE_FLAG_FLUSH, &q->queue_flags))
+		return NULL;
+
+	rq_init(q, flush_rq);
+	flush_rq->elevator_private = NULL;
+	flush_rq->flags = REQ_BAR_FLUSH;
+	flush_rq->rq_disk = rq->rq_disk;
+	flush_rq->rl = NULL;
+
+	/*
+	 * prepare_flush returns 0 if no flush is needed, just mark both
+	 * pre and post flush as done in that case
+	 */
+	if (!q->prepare_flush_fn(q, flush_rq)) {
+		rq->flags |= REQ_BAR_PREFLUSH | REQ_BAR_POSTFLUSH;
+		clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+		return rq;
+	}
+
+	/*
+	 * some drivers dequeue requests right away, some only after io
+	 * completion. make sure the request is dequeued.
+	 */
+	if (!list_empty(&rq->queuelist))
+		blkdev_dequeue_request(rq);
+
+	elv_deactivate_request(q, rq);
+
+	flush_rq->end_io_data = rq;
+	flush_rq->end_io = blk_pre_flush_end_io;
+
+	__elv_add_request(q, flush_rq, ELEVATOR_INSERT_FRONT, 0);
+	return flush_rq;
+}
+
+static void blk_start_post_flush(request_queue_t *q, struct request *rq)
+{
+	struct request *flush_rq = q->flush_rq;
+
+	BUG_ON(!blk_barrier_rq(rq));
+
+	rq_init(q, flush_rq);
+	flush_rq->elevator_private = NULL;
+	flush_rq->flags = REQ_BAR_FLUSH;
+	flush_rq->rq_disk = rq->rq_disk;
+	flush_rq->rl = NULL;
+
+	if (q->prepare_flush_fn(q, flush_rq)) {
+		flush_rq->end_io_data = rq;
+		flush_rq->end_io = blk_post_flush_end_io;
+
+		__elv_add_request(q, flush_rq, ELEVATOR_INSERT_FRONT, 0);
+		q->request_fn(q);
+	}
+}
+
+static inline int blk_check_end_barrier(request_queue_t *q, struct request *rq,
+					int sectors)
+{
+	if (sectors > rq->nr_sectors)
+		sectors = rq->nr_sectors;
+
+	rq->nr_sectors -= sectors;
+	return rq->nr_sectors;
+}
+
+static int __blk_complete_barrier_rq(request_queue_t *q, struct request *rq,
+				     int sectors, int queue_locked)
+{
+	if (q->ordered != QUEUE_ORDERED_FLUSH)
+		return 0;
+	if (!blk_fs_request(rq) || !blk_barrier_rq(rq))
+		return 0;
+	if (blk_barrier_postflush(rq))
+		return 0;
+
+	if (!blk_check_end_barrier(q, rq, sectors)) {
+		unsigned long flags = 0;
+
+		if (!queue_locked)
+			spin_lock_irqsave(q->queue_lock, flags);
+
+		blk_start_post_flush(q, rq);
+
+		if (!queue_locked)
+			spin_unlock_irqrestore(q->queue_lock, flags);
+	}
+
+	return 1;
+}
+
+/**
+ * blk_complete_barrier_rq - complete possible barrier request
+ * @q:  the request queue for the device
+ * @rq:  the request
+ * @sectors:  number of sectors to complete
+ *
+ * Description:
+ *   Used in driver end_io handling to determine whether to postpone
+ *   completion of a barrier request until a post flush has been done. This
+ *   is the unlocked variant, used if the caller doesn't already hold the
+ *   queue lock.
+ **/
+int blk_complete_barrier_rq(request_queue_t *q, struct request *rq, int sectors)
+{
+	return __blk_complete_barrier_rq(q, rq, sectors, 0);
+}
+EXPORT_SYMBOL(blk_complete_barrier_rq);
+
+/**
+ * blk_complete_barrier_rq_locked - complete possible barrier request
+ * @q:  the request queue for the device
+ * @rq:  the request
+ * @sectors:  number of sectors to complete
+ *
+ * Description:
+ *   See blk_complete_barrier_rq(). This variant must be used if the caller
+ *   holds the queue lock.
+ **/
+int blk_complete_barrier_rq_locked(request_queue_t *q, struct request *rq,
+				   int sectors)
+{
+	return __blk_complete_barrier_rq(q, rq, sectors, 1);
+}
+EXPORT_SYMBOL(blk_complete_barrier_rq_locked);
+
 /**
  * blk_queue_bounce_limit - set bounce buffer limit for queue
  * @q:  the request queue for the device
@@ -618,6 +816,7 @@ fail:
  * blk_queue_init_tags - initialize the queue tag info
  * @q:  the request queue for the device
  * @depth:  the maximum queue depth supported
+ * @tags: the tag to use
  **/
 int blk_queue_init_tags(request_queue_t *q, int depth,
 			struct blk_queue_tag *tags)
@@ -1390,7 +1589,8 @@ void blk_run_queue(struct request_queue 
 
 	spin_lock_irqsave(q->queue_lock, flags);
 	blk_remove_plug(q);
-	q->request_fn(q);
+	if (!elv_queue_empty(q))
+		q->request_fn(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_run_queue);
@@ -1428,6 +1628,8 @@ void blk_cleanup_queue(request_queue_t *
 	if (q->queue_tags)
 		__blk_queue_free_tags(q);
 
+	blk_queue_ordered(q, QUEUE_ORDERED_NONE);
+
 	kmem_cache_free(requestq_cachep, q);
 }
 
@@ -1513,6 +1715,15 @@ request_queue_t *blk_init_queue(request_
 	if (blk_init_free_list(q))
 		goto out_init;
 
+	/*
+	 * if caller didn't supply a lock, they get per-queue locking with
+	 * our embedded lock
+	 */
+	if (!lock) {
+		spin_lock_init(&q->__queue_lock);
+		lock = &q->__queue_lock;
+	}
+
 	q->request_fn		= rfn;
 	q->back_merge_fn       	= ll_back_merge_fn;
 	q->front_merge_fn      	= ll_front_merge_fn;
@@ -1739,21 +1950,8 @@ rq_starved:
 	if (ioc_batching(q, ioc))
 		ioc->nr_batch_requests--;
 	
-	INIT_LIST_HEAD(&rq->queuelist);
-
-	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->bio = rq->biotail = NULL;
-	rq->buffer = NULL;
-	rq->ref_count = 1;
-	rq->q = q;
+	rq_init(q, rq);
 	rq->rl = rl;
-	rq->waiting = NULL;
-	rq->special = NULL;
-	rq->data_len = 0;
-	rq->data = NULL;
-	rq->sense = NULL;
-
 out:
 	put_io_context(ioc);
 	return rq;
@@ -1963,7 +2161,7 @@ EXPORT_SYMBOL(blk_rq_map_user);
 /**
  * blk_rq_unmap_user - unmap a request with user data
  * @rq:		request to be unmapped
- * @ubuf:	user buffer
+ * @bio:	bio for the request
  * @ulen:	length of user buffer
  *
  * Description:
@@ -2018,11 +2216,11 @@ int blk_execute_rq(request_queue_t *q, s
 	}
 
 	rq->flags |= REQ_NOMERGE;
-	if (!rq->waiting)
-		rq->waiting = &wait;
+	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
-	wait_for_completion(rq->waiting);
+	wait_for_completion(&wait);
 	rq->waiting = NULL;
 
 	if (rq->errors)
@@ -2171,7 +2369,7 @@ void disk_round_stats(struct gendisk *di
 /*
  * queue lock must be held
  */
-void __blk_put_request(request_queue_t *q, struct request *req)
+static void __blk_put_request(request_queue_t *q, struct request *req)
 {
 	struct request_list *rl = req->rl;
 
@@ -2219,6 +2417,25 @@ void blk_put_request(struct request *req
 EXPORT_SYMBOL(blk_put_request);
 
 /**
+ * blk_end_sync_rq - executes a completion event on a request
+ * @rq: request to complete
+ */
+void blk_end_sync_rq(struct request *rq)
+{
+	struct completion *waiting = rq->waiting;
+
+	rq->waiting = NULL;
+	__blk_put_request(rq->q, rq);
+
+	/*
+	 * complete last, if this is a stack request the process (and thus
+	 * the rq pointer) could be invalid right after this complete()
+	 */
+	complete(waiting);
+}
+EXPORT_SYMBOL(blk_end_sync_rq);
+
+/**
  * blk_congestion_wait - wait for a queue to become uncongested
  * @rw: READ or WRITE
  * @timeout: timeout in jiffies
@@ -2352,7 +2569,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge);
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
 	struct request *req, *freereq = NULL;
-	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err;
+	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
 	sector_t sector;
 
 	sector = bio->bi_sector;
@@ -2360,6 +2577,7 @@ static int __make_request(request_queue_
 	cur_nr_sectors = bio_cur_sectors(bio);
 
 	rw = bio_data_dir(bio);
+	sync = bio_sync(bio);
 
 	/*
 	 * low level driver can indicate that it wants pages above a
@@ -2371,7 +2589,7 @@ static int __make_request(request_queue_
 	spin_lock_prefetch(q->queue_lock);
 
 	barrier = bio_barrier(bio);
-	if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) {
+	if (barrier && (q->ordered == QUEUE_ORDERED_NONE)) {
 		err = -EOPNOTSUPP;
 		goto end_io;
 	}
@@ -2491,7 +2709,7 @@ get_rq:
 out:
 	if (freereq)
 		__blk_put_request(q, freereq);
-	if (bio_sync(bio))
+	if (sync)
 		__generic_unplug_device(q);
 
 	spin_unlock_irq(q->queue_lock);
@@ -2978,7 +3196,6 @@ EXPORT_SYMBOL(end_that_request_chunk);
 void end_that_request_last(struct request *req)
 {
 	struct gendisk *disk = req->rq_disk;
-	struct completion *waiting = req->waiting;
 
 	if (unlikely(laptop_mode) && blk_fs_request(req))
 		laptop_io_completion();
@@ -2998,10 +3215,10 @@ void end_that_request_last(struct reques
 		disk_round_stats(disk);
 		disk->in_flight--;
 	}
-	__blk_put_request(req->q, req);
-	/* Do this LAST! The structure may be freed immediately afterwards */
-	if (waiting)
-		complete(waiting);
+	if (req->end_io)
+		req->end_io(req);
+	else
+		__blk_put_request(req->q, req);
 }
 
 EXPORT_SYMBOL(end_that_request_last);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -39,6 +39,11 @@
  * Support up to 256 loop devices
  * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
  *
+ * Support for falling back on the write file operation when the address space
+ * operations prepare_write and/or commit_write are not available on the
+ * backing filesystem.
+ * Anton Altaparmakov, 16 Feb 2005
+ *
  * Still To Fix:
  * - Advisory locking is ignored here.
  * - Should use an own CAP_* category instead of CAP_SYS_ADMIN
@@ -67,6 +72,8 @@
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>		/* for invalidate_bdev() */
 #include <linux/completion.h>
+#include <linux/highmem.h>
+#include <linux/gfp.h>
 
 #include <asm/uaccess.h>
 
@@ -127,7 +134,7 @@ static int transfer_xor(struct loop_devi
 
 static int xor_init(struct loop_device *lo, const struct loop_info64 *info)
 {
-	if (info->lo_encrypt_key_size <= 0)
+	if (unlikely(info->lo_encrypt_key_size <= 0))
 		return -EINVAL;
 	return 0;
 }
@@ -173,7 +180,7 @@ figure_loop_size(struct loop_device *lo)
 	loff_t size = get_loop_size(lo, lo->lo_backing_file);
 	sector_t x = (sector_t)size;
 
-	if ((loff_t)x != size)
+	if (unlikely((loff_t)x != size))
 		return -EFBIG;
 
 	set_capacity(disks[lo->lo_number], x);
@@ -186,23 +193,27 @@ lo_do_transfer(struct loop_device *lo, i
 	       struct page *lpage, unsigned loffs,
 	       int size, sector_t rblock)
 {
-	if (!lo->transfer)
+	if (unlikely(!lo->transfer))
 		return 0;
 
 	return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock);
 }
 
-static int
-do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
+/**
+ * do_lo_send_aops - helper for writing data to a loop device
+ *
+ * This is the fast version for backing filesystems which implement the address
+ * space operations prepare_write and commit_write.
+ */
+static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
+		int bsize, loff_t pos, struct page *page)
 {
 	struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
 	struct address_space *mapping = file->f_mapping;
 	struct address_space_operations *aops = mapping->a_ops;
-	struct page *page;
 	pgoff_t index;
-	unsigned size, offset, bv_offs;
-	int len;
-	int ret = 0;
+	unsigned offset, bv_offs;
+	int len, ret = 0;
 
 	down(&mapping->host->i_sem);
 	index = pos >> PAGE_CACHE_SHIFT;
@@ -211,23 +222,22 @@ do_lo_send(struct loop_device *lo, struc
 	len = bvec->bv_len;
 	while (len > 0) {
 		sector_t IV;
+		unsigned size;
 		int transfer_result;
 
 		IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
-
 		size = PAGE_CACHE_SIZE - offset;
 		if (size > len)
 			size = len;
-
 		page = grab_cache_page(mapping, index);
-		if (!page)
+		if (unlikely(!page))
 			goto fail;
-		if (aops->prepare_write(file, page, offset, offset+size))
+		if (unlikely(aops->prepare_write(file, page, offset,
+				offset + size)))
 			goto unlock;
 		transfer_result = lo_do_transfer(lo, WRITE, page, offset,
-						 bvec->bv_page, bv_offs,
-						 size, IV);
-		if (transfer_result) {
+				bvec->bv_page, bv_offs, size, IV);
+		if (unlikely(transfer_result)) {
 			char *kaddr;
 
 			/*
@@ -241,9 +251,10 @@ do_lo_send(struct loop_device *lo, struc
 			kunmap_atomic(kaddr, KM_USER0);
 		}
 		flush_dcache_page(page);
-		if (aops->commit_write(file, page, offset, offset+size))
+		if (unlikely(aops->commit_write(file, page, offset,
+				offset + size)))
 			goto unlock;
-		if (transfer_result)
+		if (unlikely(transfer_result))
 			goto unlock;
 		bv_offs += size;
 		len -= size;
@@ -253,32 +264,125 @@ do_lo_send(struct loop_device *lo, struc
 		unlock_page(page);
 		page_cache_release(page);
 	}
-	up(&mapping->host->i_sem);
 out:
+	up(&mapping->host->i_sem);
 	return ret;
-
 unlock:
 	unlock_page(page);
 	page_cache_release(page);
 fail:
-	up(&mapping->host->i_sem);
 	ret = -1;
 	goto out;
 }
 
-static int
-lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+/**
+ * __do_lo_send_write - helper for writing data to a loop device
+ *
+ * This helper just factors out common code between do_lo_send_direct_write()
+ * and do_lo_send_write().
+ */
+static inline int __do_lo_send_write(struct file *file,
+		u8 __user *buf, const int len, loff_t pos)
 {
+	ssize_t bw;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(get_ds());
+	bw = file->f_op->write(file, buf, len, &pos);
+	set_fs(old_fs);
+	if (likely(bw == len))
+		return 0;
+	printk(KERN_ERR "loop: Write error at byte offset %llu, length %i.\n",
+			(unsigned long long)pos, len);
+	if (bw >= 0)
+		bw = -EIO;
+	return bw;
+}
+
+/**
+ * do_lo_send_direct_write - helper for writing data to a loop device
+ *
+ * This is the fast, non-transforming version for backing filesystems which do
+ * not implement the address space operations prepare_write and commit_write.
+ * It uses the write file operation which should be present on all writeable
+ * filesystems.
+ */
+static int do_lo_send_direct_write(struct loop_device *lo,
+		struct bio_vec *bvec, int bsize, loff_t pos, struct page *page)
+{
+	ssize_t bw = __do_lo_send_write(lo->lo_backing_file,
+			(u8 __user *)kmap(bvec->bv_page) + bvec->bv_offset,
+			bvec->bv_len, pos);
+	kunmap(bvec->bv_page);
+	cond_resched();
+	return bw;
+}
+
+/**
+ * do_lo_send_write - helper for writing data to a loop device
+ *
+ * This is the slow, transforming version for filesystems which do not
+ * implement the address space operations prepare_write and commit_write.  It
+ * uses the write file operation which should be present on all writeable
+ * filesystems.
+ *
+ * Using fops->write is slower than using aops->{prepare,commit}_write in the
+ * transforming case because we need to double buffer the data as we cannot do
+ * the transformations in place as we do not have direct access to the
+ * destination pages of the backing file.
+ */
+static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
+		int bsize, loff_t pos, struct page *page)
+{
+	int ret = lo_do_transfer(lo, WRITE, page, 0, bvec->bv_page,
+			bvec->bv_offset, bvec->bv_len, pos >> 9);
+	if (likely(!ret))
+		return __do_lo_send_write(lo->lo_backing_file,
+				(u8 __user *)page_address(page), bvec->bv_len,
+				pos);
+	printk(KERN_ERR "loop: Transfer error at byte offset %llu, "
+			"length %i.\n", (unsigned long long)pos, bvec->bv_len);
+	if (ret > 0)
+		ret = -EIO;
+	return ret;
+}
+
+static int lo_send(struct loop_device *lo, struct bio *bio, int bsize,
+		loff_t pos)
+{
+	int (*do_lo_send)(struct loop_device *, struct bio_vec *, int, loff_t,
+			struct page *page);
 	struct bio_vec *bvec;
+	struct page *page = NULL;
 	int i, ret = 0;
 
+	do_lo_send = do_lo_send_aops;
+	if (!(lo->lo_flags & LO_FLAGS_USE_AOPS)) {
+		do_lo_send = do_lo_send_direct_write;
+		if (lo->transfer != transfer_none) {
+			page = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
+			if (unlikely(!page))
+				goto fail;
+			kmap(page);
+			do_lo_send = do_lo_send_write;
+		}
+	}
 	bio_for_each_segment(bvec, bio, i) {
-		ret = do_lo_send(lo, bvec, bsize, pos);
+		ret = do_lo_send(lo, bvec, bsize, pos, page);
 		if (ret < 0)
 			break;
 		pos += bvec->bv_len;
 	}
+	if (page) {
+		kunmap(page);
+		__free_page(page);
+	}
+out:
 	return ret;
+fail:
+	printk(KERN_ERR "loop: Failed to allocate temporary page for write.\n");
+	ret = -ENOMEM;
+	goto out;
 }
 
 struct lo_read_data {
@@ -584,7 +688,7 @@ static int loop_change_fd(struct loop_de
 
 	/* the loop device has to be read-only */
 	error = -EINVAL;
-	if (lo->lo_flags != LO_FLAGS_READ_ONLY)
+	if (!(lo->lo_flags & LO_FLAGS_READ_ONLY))
 		goto out;
 
 	error = -EBADF;
@@ -683,8 +787,9 @@ static int loop_set_fd(struct loop_devic
 		 */
 		if (!file->f_op->sendfile)
 			goto out_putf;
-
-		if (!aops->prepare_write || !aops->commit_write)
+		if (aops->prepare_write && aops->commit_write)
+			lo_flags |= LO_FLAGS_USE_AOPS;
+		if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
 			lo_flags |= LO_FLAGS_READ_ONLY;
 
 		lo_blocksize = inode->i_blksize;
@@ -1137,7 +1242,7 @@ int loop_unregister_transfer(int number)
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-int __init loop_init(void)
+static int __init loop_init(void)
 {
 	int	i;
 
@@ -1212,7 +1317,7 @@ out_mem1:
 	return -ENOMEM;
 }
 
-void loop_exit(void)
+static void loop_exit(void)
 {
 	int i;
 
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -38,7 +38,7 @@
  * 03-06-24 Cleanup PARANOIA usage & code. <ldl@aros.net>
  * 04-02-19 Remove PARANOIA, plus various cleanups (Paul Clements)
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
- * why not: would need verify_area and friends, would share yet another 
+ * why not: would need access_ok and friends, would share yet another
  *          structure with userland
  */
 
@@ -78,6 +78,7 @@
 #define DBG_RX          0x0200
 #define DBG_TX          0x0400
 static unsigned int debugflags;
+static unsigned int nbds_max = 16;
 #endif /* NDEBUG */
 
 static struct nbd_device nbd_dev[MAX_NBD];
@@ -315,7 +316,7 @@ static inline int sock_recv_bvec(struct 
 }
 
 /* NULL returned = something went wrong, inform userspace */
-struct request *nbd_read_stat(struct nbd_device *lo)
+static struct request *nbd_read_stat(struct nbd_device *lo)
 {
 	int result;
 	struct nbd_reply reply;
@@ -377,7 +378,7 @@ harderror:
 	return NULL;
 }
 
-void nbd_do_it(struct nbd_device *lo)
+static void nbd_do_it(struct nbd_device *lo)
 {
 	struct request *req;
 
@@ -388,7 +389,7 @@ void nbd_do_it(struct nbd_device *lo)
 	return;
 }
 
-void nbd_clear_que(struct nbd_device *lo)
+static void nbd_clear_que(struct nbd_device *lo)
 {
 	struct request *req;
 
@@ -549,7 +550,7 @@ static int nbd_ioctl(struct inode *inode
 		file = fget(arg);
 		if (file) {
 			inode = file->f_dentry->d_inode;
-			if (inode->i_sock) {
+			if (S_ISSOCK(inode->i_mode)) {
 				lo->file = file;
 				lo->sock = SOCKET_I(inode);
 				error = 0;
@@ -647,7 +648,13 @@ static int __init nbd_init(void)
 		return -EIO;
 	}
 
-	for (i = 0; i < MAX_NBD; i++) {
+	if (nbds_max > MAX_NBD) {
+		printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD,
+				nbds_max);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < nbds_max; i++) {
 		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			goto out;
@@ -673,7 +680,7 @@ static int __init nbd_init(void)
 	dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);
 
 	devfs_mk_dir("nbd");
-	for (i = 0; i < MAX_NBD; i++) {
+	for (i = 0; i < nbds_max; i++) {
 		struct gendisk *disk = nbd_dev[i].disk;
 		nbd_dev[i].file = NULL;
 		nbd_dev[i].magic = LO_MAGIC;
@@ -706,8 +713,9 @@ out:
 static void __exit nbd_cleanup(void)
 {
 	int i;
-	for (i = 0; i < MAX_NBD; i++) {
+	for (i = 0; i < nbds_max; i++) {
 		struct gendisk *disk = nbd_dev[i].disk;
+		nbd_dev[i].magic = 0;
 		if (disk) {
 			del_gendisk(disk);
 			blk_cleanup_queue(disk->queue);
@@ -725,6 +733,8 @@ module_exit(nbd_cleanup);
 MODULE_DESCRIPTION("Network Block Device");
 MODULE_LICENSE("GPL");
 
+module_param(nbds_max, int, 0444);
+MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize.");
 #ifndef NDEBUG
 module_param(debugflags, int, 0644);
 MODULE_PARM_DESC(debugflags, "flags for controlling debug output");
diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c
--- a/drivers/block/noop-iosched.c
+++ b/drivers/block/noop-iosched.c
@@ -13,34 +13,13 @@
 static int elevator_noop_merge(request_queue_t *q, struct request **req,
 			       struct bio *bio)
 {
-	struct list_head *entry = &q->queue_head;
-	struct request *__rq;
 	int ret;
 
-	if ((ret = elv_try_last_merge(q, bio))) {
+	ret = elv_try_last_merge(q, bio);
+	if (ret != ELEVATOR_NO_MERGE)
 		*req = q->last_merge;
-		return ret;
-	}
 
-	while ((entry = entry->prev) != &q->queue_head) {
-		__rq = list_entry_rq(entry);
-
-		if (__rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER))
-			break;
-		else if (__rq->flags & REQ_STARTED)
-			break;
-
-		if (!blk_fs_request(__rq))
-			continue;
-
-		if ((ret = elv_try_merge(__rq, bio))) {
-			*req = __rq;
-			q->last_merge = __rq;
-			return ret;
-		}
-	}
-
-	return ELEVATOR_NO_MERGE;
+	return ret;
 }
 
 static void elevator_noop_merge_requests(request_queue_t *q, struct request *req,
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -142,26 +142,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV,
 
 static spinlock_t pcd_lock;
 
-#ifndef MODULE
-
-#include "setup.h"
-
-static STT pcd_stt[6] = {
-	{"drive0", 6, drive0},
-	{"drive1", 6, drive1},
-	{"drive2", 6, drive2},
-	{"drive3", 6, drive3},
-	{"disable", 1, &disable},
-	{"nice", 1, &nice}
-};
-
-void pcd_setup(char *str, int *ints)
-{
-	generic_setup(pcd_stt, 6, str);
-}
-
-#endif
-
 module_param(verbose, bool, 0644);
 module_param(major, int, 0);
 module_param(name, charp, 0);
@@ -218,7 +198,7 @@ struct pcd_unit {
 	struct gendisk *disk;
 };
 
-struct pcd_unit pcd[PCD_UNITS];
+static struct pcd_unit pcd[PCD_UNITS];
 
 static char pcd_scratch[64];
 static char pcd_buffer[2048];	/* raw block buffer */
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -157,27 +157,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO,
 
 static DEFINE_SPINLOCK(pd_lock);
 
-#ifndef MODULE
-
-#include "setup.h"
-
-static STT pd_stt[7] = {
-	{"drive0", 8, drive0},
-	{"drive1", 8, drive1},
-	{"drive2", 8, drive2},
-	{"drive3", 8, drive3},
-	{"disable", 1, &disable},
-	{"cluster", 1, &cluster},
-	{"nice", 1, &nice}
-};
-
-void pd_setup(char *str, int *ints)
-{
-	generic_setup(pd_stt, 7, str);
-}
-
-#endif
-
 module_param(verbose, bool, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
@@ -255,7 +234,7 @@ struct pd_unit {
 	struct gendisk *gd;
 };
 
-struct pd_unit pd[PD_UNITS];
+static struct pd_unit pd[PD_UNITS];
 
 static char pd_scratch[512];	/* scratch block buffer */
 
@@ -743,6 +722,7 @@ static int pd_special_command(struct pd_
 	rq.rq_disk = disk->gd;
 	rq.ref_count = 1;
 	rq.waiting = &wait;
+	rq.end_io = blk_end_sync_rq;
 	blk_insert_request(disk->gd->queue, &rq, 0, func, 0);
 	wait_for_completion(&wait);
 	rq.waiting = NULL;
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -156,27 +156,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV,
 
 static spinlock_t pf_spin_lock;
 
-#ifndef MODULE
-
-#include "setup.h"
-
-static STT pf_stt[7] = {
-	{"drive0", 7, drive0},
-	{"drive1", 7, drive1},
-	{"drive2", 7, drive2},
-	{"drive3", 7, drive3},
-	{"disable", 1, &disable},
-	{"cluster", 1, &cluster},
-	{"nice", 1, &nice}
-};
-
-void pf_setup(char *str, int *ints)
-{
-	generic_setup(pf_stt, 7, str);
-}
-
-#endif
-
 module_param(verbose, bool, 0644);
 module_param(major, int, 0);
 module_param(name, charp, 0);
@@ -256,7 +235,7 @@ struct pf_unit {
 	struct gendisk *disk;
 };
 
-struct pf_unit units[PF_UNITS];
+static struct pf_unit units[PF_UNITS];
 
 static int pf_identify(struct pf_unit *pf);
 static void pf_lock(struct pf_unit *pf, int func);
@@ -290,7 +269,7 @@ static struct block_device_operations pf
 	.media_changed	= pf_check_media,
 };
 
-void pf_init_units(void)
+static void __init pf_init_units(void)
 {
 	struct pf_unit *pf;
 	int unit;
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -165,25 +165,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV,
 
 #include <asm/uaccess.h>
 
-#ifndef MODULE
-
-#include "setup.h"
-
-static STT pg_stt[5] = {
-	{"drive0", 6, drive0},
-	{"drive1", 6, drive1},
-	{"drive2", 6, drive2},
-	{"drive3", 6, drive3},
-	{"disable", 1, &disable}
-};
-
-void pg_setup(char *str, int *ints)
-{
-	generic_setup(pg_stt, 5, str);
-}
-
-#endif
-
 module_param(verbose, bool, 0644);
 module_param(major, int, 0);
 module_param(name, charp, 0);
@@ -235,7 +216,7 @@ struct pg {
 	char name[PG_NAMELEN];	/* pg0, pg1, ... */
 };
 
-struct pg devices[PG_UNITS];
+static struct pg devices[PG_UNITS];
 
 static int pg_identify(struct pg *dev, int log);
 
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -149,26 +149,6 @@ static int (*drives[4])[6] = {&drive0, &
 
 #include <asm/uaccess.h>
 
-#ifndef MODULE
-
-#include "setup.h"
-
-static STT pt_stt[5] = {
-	{"drive0", 6, drive0},
-	{"drive1", 6, drive1},
-	{"drive2", 6, drive2},
-	{"drive3", 6, drive3},
-	{"disable", 1, &disable}
-};
-
-void
-pt_setup(char *str, int *ints)
-{
-	generic_setup(pt_stt, 5, str);
-}
-
-#endif
-
 module_param(verbose, bool, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
@@ -246,7 +226,7 @@ struct pt_unit {
 
 static int pt_identify(struct pt_unit *tape);
 
-struct pt_unit pt[PT_UNITS];
+static struct pt_unit pt[PT_UNITS];
 
 static char pt_scratch[512];	/* scratch block buffer */
 
diff --git a/drivers/block/paride/setup.h b/drivers/block/paride/setup.h
deleted file mode 100644
--- a/drivers/block/paride/setup.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-	setup.h	   (c) 1997-8   Grant R. Guenther <grant@torque.net>
-		                Under the terms of the GNU General Public License.
-
-        This is a table driven setup function for kernel modules
-        using the module.variable=val,... command line notation.
-
-*/
-
-/* Changes:
-
-	1.01	GRG 1998.05.05	Allow negative and defaulted values
-
-*/
-
-#include <linux/ctype.h>
-#include <linux/string.h>
-
-struct setup_tab_t {
-
-	char	*tag;	/* variable name */
-	int	size;	/* number of elements in array */
-	int	*iv;	/* pointer to variable */
-};
-
-typedef struct setup_tab_t STT;
-
-/*  t 	  is a table that describes the variables that can be set
-	  by gen_setup
-    n	  is the number of entries in the table
-    ss	  is a string of the form:
-
-		<tag>=[<val>,...]<val>
-*/
-
-static void generic_setup( STT t[], int n, char *ss )
-
-{	int	j,k, sgn;
-
-	k = 0;
-	for (j=0;j<n;j++) {
-		k = strlen(t[j].tag);
-		if (strncmp(ss,t[j].tag,k) == 0) break;
-	}
-	if (j == n) return;
-
-	if (ss[k] == 0) {
-		t[j].iv[0] = 1;
-		return;
-	}
-
-	if (ss[k] != '=') return;
-	ss += (k+1);
-
-	k = 0;
-	while (ss && (k < t[j].size)) {
-		if (!*ss) break;
-		sgn = 1;
-		if (*ss == '-') { ss++; sgn = -1; }
-		if (!*ss) break;
-		if (isdigit(*ss))
-		  t[j].iv[k] = sgn * simple_strtoul(ss,NULL,0);
-		k++; 
-		if ((ss = strchr(ss,',')) != NULL) ss++;
-	}
-}
-
-/* end of setup.h */
-
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -219,7 +219,7 @@ static int pkt_grow_pktlist(struct pktcd
 	return 1;
 }
 
-static void *pkt_rb_alloc(int gfp_mask, void *data)
+static void *pkt_rb_alloc(unsigned int __nocast gfp_mask, void *data)
 {
 	return kmalloc(sizeof(struct pkt_rb_node), gfp_mask);
 }
@@ -375,6 +375,7 @@ static int pkt_generic_packet(struct pkt
 	rq->ref_count++;
 	rq->flags |= REQ_NOMERGE;
 	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
 	wait_for_completion(&wait);
@@ -913,8 +914,10 @@ static int pkt_handle_queue(struct pktcd
 		bio = node->bio;
 		zone = ZONE(bio->bi_sector, pd);
 		list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
-			if (p->sector == zone)
+			if (p->sector == zone) {
+				bio = NULL;
 				goto try_next_bio;
+			}
 		}
 		break;
 try_next_bio:
@@ -1420,8 +1423,8 @@ static int pkt_set_write_settings(struct
 	char buffer[128];
 	int ret, size;
 
-	/* doesn't apply to DVD+RW */
-	if (pd->mmc3_profile == 0x1a)
+	/* doesn't apply to DVD+RW or DVD-RAM */
+	if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12))
 		return 0;
 
 	memset(buffer, 0, sizeof(buffer));
@@ -1535,6 +1538,7 @@ static int pkt_good_disc(struct pktcdvd_
 			break;
 		case 0x1a: /* DVD+RW */
 		case 0x13: /* DVD-RW */
+		case 0x12: /* DVD-RAM */
 			return 0;
 		default:
 			printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
@@ -1600,6 +1604,9 @@ static int pkt_probe_settings(struct pkt
 		case 0x13: /* DVD-RW */
 			printk("pktcdvd: inserted media is DVD-RW\n");
 			break;
+		case 0x12: /* DVD-RAM */
+			printk("pktcdvd: inserted media is DVD-RAM\n");
+			break;
 		default:
 			printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
 			break;
@@ -1892,6 +1899,7 @@ static int pkt_open_write(struct pktcdvd
 	switch (pd->mmc3_profile) {
 		case 0x13: /* DVD-RW */
 		case 0x1a: /* DVD+RW */
+		case 0x12: /* DVD-RAM */
 			DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
 			break;
 		default:
@@ -2013,7 +2021,13 @@ static int pkt_open(struct inode *inode,
 	BUG_ON(pd->refcnt < 0);
 
 	pd->refcnt++;
-	if (pd->refcnt == 1) {
+	if (pd->refcnt > 1) {
+		if ((file->f_mode & FMODE_WRITE) &&
+		    !test_bit(PACKET_WRITABLE, &pd->flags)) {
+			ret = -EBUSY;
+			goto out_dec;
+		}
+	} else {
 		if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) {
 			ret = -EIO;
 			goto out_dec;
@@ -2053,7 +2067,7 @@ static int pkt_close(struct inode *inode
 }
 
 
-static void *psd_pool_alloc(int gfp_mask, void *data)
+static void *psd_pool_alloc(unsigned int __nocast gfp_mask, void *data)
 {
 	return kmalloc(sizeof(struct packet_stacked_data), gfp_mask);
 }
@@ -2400,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode
 	case CDROM_LAST_WRITTEN:
 	case CDROM_SEND_PACKET:
 	case SCSI_IOCTL_SEND_COMMAND:
-		return ioctl_by_bdev(pd->bdev, cmd, arg);
+		return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
 	case CDROMEJECT:
 		/*
@@ -2408,7 +2422,7 @@ static int pkt_ioctl(struct inode *inode
 		 * have to unlock it or else the eject command fails.
 		 */
 		pkt_lock_door(pd, 0);
-		return ioctl_by_bdev(pd->bdev, cmd, arg);
+		return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
 	default:
 		printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
@@ -2623,7 +2637,7 @@ static struct miscdevice pkt_misc = {
 	.fops  		= &pkt_ctl_fops
 };
 
-static int pkt_init(void)
+static int __init pkt_init(void)
 {
 	int ret;
 
@@ -2659,7 +2673,7 @@ out2:
 	return ret;
 }
 
-static void pkt_exit(void)
+static void __exit pkt_exit(void)
 {
 	remove_proc_entry("pktcdvd", proc_root_driver);
 	misc_deregister(&pkt_misc);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -86,7 +86,7 @@ int rd_size = CONFIG_BLK_DEV_RAM_SIZE;		
  * behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that
  * supposes the filesystem in the image uses a BLOCK_SIZE blocksize).
  */
-int rd_blocksize = BLOCK_SIZE;			/* blocksize of the RAM disks */
+static int rd_blocksize = BLOCK_SIZE;		/* blocksize of the RAM disks */
 
 /*
  * Copyright (C) 2000 Linus Torvalds.
@@ -325,7 +325,7 @@ static int rd_ioctl(struct inode *inode,
  */
 static struct backing_dev_info rd_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY,
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 
@@ -336,7 +336,7 @@ static struct backing_dev_info rd_backin
  */
 static struct backing_dev_info rd_file_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 0,	/* Does contribute to dirty memory */
+	.capabilities	= BDI_CAP_MAP_COPY,	/* Does contribute to dirty memory */
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
--- a/drivers/block/scsi_ioctl.c
+++ b/drivers/block/scsi_ioctl.c
@@ -328,11 +328,6 @@ static int sg_io(struct file *file, requ
 	return 0;
 }
 
-#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
-#define START_STOP_TIMEOUT		(60 * HZ)
-#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
-#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
-#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )
 #define OMAX_SB_LEN 16          /* For backward compatibility */
 
 static int sg_scsi_ioctl(struct file *file, request_queue_t *q,
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -8,13 +8,12 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
+ *  -- Kill first_open (Al Viro fixed the block layer now)
  *  -- Do resets with usb_device_reset (needs a thread context, use khubd)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
- *  -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- verify the 13 conditions and do bulk resets
- *  -- normal pool of commands instead of cmdv[]?
  *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- highmem and sg
@@ -49,7 +48,14 @@
 #define US_SC_SCSI	0x06		/* Transparent */
 
 /*
+ * This many LUNs per USB device.
+ * Every one of them takes a host, see UB_MAX_HOSTS.
  */
+#define UB_MAX_LUNS   9
+
+/*
+ */
+
 #define UB_MINORS_PER_MAJOR	8
 
 #define UB_MAX_CDB_SIZE      16		/* Corresponds to Bulk */
@@ -65,7 +71,7 @@ struct bulk_cb_wrap {
 	u32	Tag;			/* unique per command id */
 	__le32	DataTransferLength;	/* size of data */
 	u8	Flags;			/* direction in bit 0 */
-	u8	Lun;			/* LUN normally 0 */
+	u8	Lun;			/* LUN */
 	u8	Length;			/* of of the CDB */
 	u8	CDB[UB_MAX_CDB_SIZE];	/* max command */
 };
@@ -168,6 +174,7 @@ struct ub_scsi_cmd {
 	unsigned int len;		/* Requested length */
 	// struct scatterlist sgv[UB_MAX_REQ_SG];
 
+	struct ub_lun *lun;
 	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
 	void *back;
 };
@@ -252,25 +259,47 @@ struct ub_scsi_cmd_queue {
 };
 
 /*
- * The UB device instance.
+ * The block device instance (one per LUN).
+ */
+struct ub_lun {
+	struct ub_dev *udev;
+	struct list_head link;
+	struct gendisk *disk;
+	int id;				/* Host index */
+	int num;			/* LUN number */
+	char name[16];
+
+	int changed;			/* Media was changed */
+	int removable;
+	int readonly;
+	int first_open;			/* Kludge. See ub_bd_open. */
+
+	/* Use Ingo's mempool if or when we have more than one command. */
+	/*
+	 * Currently we never need more than one command for the whole device.
+	 * However, giving every LUN a command is a cheap and automatic way
+	 * to enforce fairness between them.
+	 */
+	int cmda[1];
+	struct ub_scsi_cmd cmdv[1];
+
+	struct ub_capacity capacity; 
+};
+
+/*
+ * The USB device instance.
  */
 struct ub_dev {
 	spinlock_t lock;
-	int id;				/* Number among ub's */
 	atomic_t poison;		/* The USB device is disconnected */
 	int openc;			/* protected by ub_lock! */
 					/* kref is too implicit for our taste */
 	unsigned int tagcnt;
-	int changed;			/* Media was changed */
-	int removable;
-	int readonly;
-	int first_open;			/* Kludge. See ub_bd_open. */
-	char name[8];
+	char name[12];
 	struct usb_device *dev;
 	struct usb_interface *intf;
 
-	struct ub_capacity capacity; 
-	struct gendisk *disk;
+	struct list_head luns;
 
 	unsigned int send_bulk_pipe;	/* cached pipe values */
 	unsigned int recv_bulk_pipe;
@@ -279,10 +308,6 @@ struct ub_dev {
 
 	struct tasklet_struct tasklet;
 
-	/* XXX Use Ingo's mempool (once we have more than one) */
-	int cmda[1];
-	struct ub_scsi_cmd cmdv[1];
-
 	struct ub_scsi_cmd_queue cmd_queue;
 	struct ub_scsi_cmd top_rqs_cmd;	/* REQUEST SENSE */
 	unsigned char top_sense[UB_SENSE_SIZE];
@@ -300,9 +325,10 @@ struct ub_dev {
 
 /*
  */
-static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq);
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq);
+static void ub_cleanup(struct ub_dev *sc);
+static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
+static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq);
 static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
     struct request *rq);
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -319,8 +345,10 @@ static void ub_state_sense(struct ub_dev
 static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
     int stalled_pipe);
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
-static int ub_sync_tur(struct ub_dev *sc);
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret);
+static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_capacity *ret);
+static int ub_probe_lun(struct ub_dev *sc, int lnum);
 
 /*
  */
@@ -341,6 +369,7 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
  */
 #define UB_MAX_HOSTS  26
 static char ub_hostv[UB_MAX_HOSTS];
+
 static DEFINE_SPINLOCK(ub_lock);	/* Locks globals and ->openc */
 
 /*
@@ -405,6 +434,8 @@ static ssize_t ub_diag_show(struct devic
 {
 	struct usb_interface *intf;
 	struct ub_dev *sc;
+	struct list_head *p;
+	struct ub_lun *lun;
 	int cnt;
 	unsigned long flags;
 	int nc, nh;
@@ -420,9 +451,15 @@ static ssize_t ub_diag_show(struct devic
 	spin_lock_irqsave(&sc->lock, flags);
 
 	cnt += sprintf(page + cnt,
-	    "qlen %d qmax %d changed %d removable %d readonly %d\n",
-	    sc->cmd_queue.qlen, sc->cmd_queue.qmax,
-	    sc->changed, sc->removable, sc->readonly);
+	    "qlen %d qmax %d\n",
+	    sc->cmd_queue.qlen, sc->cmd_queue.qmax);
+
+	list_for_each (p, &sc->luns) {
+		lun = list_entry(p, struct ub_lun, link);
+		cnt += sprintf(page + cnt,
+		    "lun %u changed %d removable %d readonly %d\n",
+		    lun->num, lun->changed, lun->removable, lun->readonly);
+	}
 
 	if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
 	for (j = 0; j < SCMD_TRACE_SZ; j++) {
@@ -478,66 +515,107 @@ static int ub_id_get(void)
 
 static void ub_id_put(int id)
 {
+	unsigned long flags;
 
 	if (id < 0 || id >= UB_MAX_HOSTS) {
 		printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
 		return;
 	}
+
+	spin_lock_irqsave(&ub_lock, flags);
 	if (ub_hostv[id] == 0) {
+		spin_unlock_irqrestore(&ub_lock, flags);
 		printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
 		return;
 	}
 	ub_hostv[id] = 0;
+	spin_unlock_irqrestore(&ub_lock, flags);
+}
+
+/*
+ * Downcount for deallocation. This rides on two assumptions:
+ *  - once something is poisoned, its refcount cannot grow
+ *  - opens cannot happen at this time (del_gendisk was done)
+ * If the above is true, we can drop the lock, which we need for
+ * blk_cleanup_queue(): the silly thing may attempt to sleep.
+ * [Actually, it never needs to sleep for us, but it calls might_sleep()]
+ */
+static void ub_put(struct ub_dev *sc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ub_lock, flags);
+	--sc->openc;
+	if (sc->openc == 0 && atomic_read(&sc->poison)) {
+		spin_unlock_irqrestore(&ub_lock, flags);
+		ub_cleanup(sc);
+	} else {
+		spin_unlock_irqrestore(&ub_lock, flags);
+	}
 }
 
 /*
  * Final cleanup and deallocation.
- * This must be called with ub_lock taken.
  */
 static void ub_cleanup(struct ub_dev *sc)
 {
+	struct list_head *p;
+	struct ub_lun *lun;
+	request_queue_t *q;
 
-	/*
-	 * If we zero disk->private_data BEFORE put_disk, we have to check
-	 * for NULL all over the place in open, release, check_media and
-	 * revalidate, because the block level semaphore is well inside the
-	 * put_disk. But we cannot zero after the call, because *disk is gone.
-	 * The sd.c is blatantly racy in this area.
-	 */
-	/* disk->private_data = NULL; */
-	put_disk(sc->disk);
-	sc->disk = NULL;
+	while (!list_empty(&sc->luns)) {
+		p = sc->luns.next;
+		lun = list_entry(p, struct ub_lun, link);
+		list_del(p);
+
+		/* I don't think queue can be NULL. But... Stolen from sx8.c */
+		if ((q = lun->disk->queue) != NULL)
+			blk_cleanup_queue(q);
+		/*
+		 * If we zero disk->private_data BEFORE put_disk, we have
+		 * to check for NULL all over the place in open, release,
+		 * check_media and revalidate, because the block level
+		 * semaphore is well inside the put_disk.
+		 * But we cannot zero after the call, because *disk is gone.
+		 * The sd.c is blatantly racy in this area.
+		 */
+		/* disk->private_data = NULL; */
+		put_disk(lun->disk);
+		lun->disk = NULL;
+
+		ub_id_put(lun->id);
+		kfree(lun);
+	}
 
-	ub_id_put(sc->id);
 	kfree(sc);
 }
 
 /*
  * The "command allocator".
  */
-static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc)
+static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun)
 {
 	struct ub_scsi_cmd *ret;
 
-	if (sc->cmda[0])
+	if (lun->cmda[0])
 		return NULL;
-	ret = &sc->cmdv[0];
-	sc->cmda[0] = 1;
+	ret = &lun->cmdv[0];
+	lun->cmda[0] = 1;
 	return ret;
 }
 
-static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd)
 {
-	if (cmd != &sc->cmdv[0]) {
+	if (cmd != &lun->cmdv[0]) {
 		printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
-		    sc->name, cmd);
+		    lun->name, cmd);
 		return;
 	}
-	if (!sc->cmda[0]) {
-		printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name);
+	if (!lun->cmda[0]) {
+		printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name);
 		return;
 	}
-	sc->cmda[0] = 0;
+	lun->cmda[0] = 0;
 }
 
 /*
@@ -598,29 +676,30 @@ static struct ub_scsi_cmd *ub_cmdq_pop(s
 
 static void ub_bd_rq_fn(request_queue_t *q)
 {
-	struct ub_dev *sc = q->queuedata;
+	struct ub_lun *lun = q->queuedata;
 	struct request *rq;
 
 	while ((rq = elv_next_request(q)) != NULL) {
-		if (ub_bd_rq_fn_1(sc, rq) != 0) {
+		if (ub_bd_rq_fn_1(lun, rq) != 0) {
 			blk_stop_queue(q);
 			break;
 		}
 	}
 }
 
-static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq)
+static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
 {
+	struct ub_dev *sc = lun->udev;
 	struct ub_scsi_cmd *cmd;
 	int rc;
 
-	if (atomic_read(&sc->poison) || sc->changed) {
+	if (atomic_read(&sc->poison) || lun->changed) {
 		blkdev_dequeue_request(rq);
 		ub_end_rq(rq, 0);
 		return 0;
 	}
 
-	if ((cmd = ub_get_cmd(sc)) == NULL)
+	if ((cmd = ub_get_cmd(lun)) == NULL)
 		return -1;
 	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
@@ -629,32 +708,30 @@ static int ub_bd_rq_fn_1(struct ub_dev *
 	if (blk_pc_request(rq)) {
 		rc = ub_cmd_build_packet(sc, cmd, rq);
 	} else {
-		rc = ub_cmd_build_block(sc, cmd, rq);
+		rc = ub_cmd_build_block(sc, lun, cmd, rq);
 	}
 	if (rc != 0) {
-		ub_put_cmd(sc, cmd);
+		ub_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
-		blk_start_queue(sc->disk->queue);
 		return 0;
 	}
-
 	cmd->state = UB_CMDST_INIT;
+	cmd->lun = lun;
 	cmd->done = ub_rw_cmd_done;
 	cmd->back = rq;
 
 	cmd->tag = sc->tagcnt++;
 	if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
-		ub_put_cmd(sc, cmd);
+		ub_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
-		blk_start_queue(sc->disk->queue);
 		return 0;
 	}
 
 	return 0;
 }
 
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq)
+static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq)
 {
 	int ub_dir;
 #if 0 /* We use rq->buffer for now */
@@ -675,7 +752,7 @@ static int ub_cmd_build_block(struct ub_
 	sg = &cmd->sgv[0];
 	n_elem = blk_rq_map_sg(q, rq, sg);
 	if (n_elem <= 0) {
-		ub_put_cmd(sc, cmd);
+		ub_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
 		blk_start_queue(q);
 		return 0;		/* request with no s/g entries? */
@@ -684,7 +761,7 @@ static int ub_cmd_build_block(struct ub_
 	if (n_elem != 1) {		/* Paranoia */
 		printk(KERN_WARNING "%s: request with %d segments\n",
 		    sc->name, n_elem);
-		ub_put_cmd(sc, cmd);
+		ub_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
 		blk_start_queue(q);
 		return 0;
@@ -716,8 +793,8 @@ static int ub_cmd_build_block(struct ub_
 	 * The call to blk_queue_hardsect_size() guarantees that request
 	 * is aligned, but it is given in terms of 512 byte units, always.
 	 */
-	block = rq->sector >> sc->capacity.bshift;
-	nblks = rq->nr_sectors >> sc->capacity.bshift;
+	block = rq->sector >> lun->capacity.bshift;
+	nblks = rq->nr_sectors >> lun->capacity.bshift;
 
 	cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
 	/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
@@ -771,7 +848,8 @@ static int ub_cmd_build_packet(struct ub
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
 	struct request *rq = cmd->back;
-	struct gendisk *disk = sc->disk;
+	struct ub_lun *lun = cmd->lun;
+	struct gendisk *disk = lun->disk;
 	request_queue_t *q = disk->queue;
 	int uptodate;
 
@@ -786,7 +864,7 @@ static void ub_rw_cmd_done(struct ub_dev
 	else
 		uptodate = 0;
 
-	ub_put_cmd(sc, cmd);
+	ub_put_cmd(lun, cmd);
 	ub_end_rq(rq, uptodate);
 	blk_start_queue(q);
 }
@@ -855,7 +933,7 @@ static int ub_scsi_cmd_start(struct ub_d
 	bcb->Tag = cmd->tag;		/* Endianness is not important */
 	bcb->DataTransferLength = cpu_to_le32(cmd->len);
 	bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
-	bcb->Lun = 0;			/* No multi-LUN yet */
+	bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;
 	bcb->Length = cmd->cdb_len;
 
 	/* copy the command payload */
@@ -970,9 +1048,8 @@ static void ub_scsi_urb_compl(struct ub_
 			 * The control pipe clears itself - nothing to do.
 			 * XXX Might try to reset the device here and retry.
 			 */
-			printk(KERN_NOTICE "%s: "
-			    "stall on control pipe for device %u\n",
-			    sc->name, sc->dev->devnum);
+			printk(KERN_NOTICE "%s: stall on control pipe\n",
+			    sc->name);
 			goto Bad_End;
 		}
 
@@ -993,9 +1070,8 @@ static void ub_scsi_urb_compl(struct ub_
 			 * The control pipe clears itself - nothing to do.
 			 * XXX Might try to reset the device here and retry.
 			 */
-			printk(KERN_NOTICE "%s: "
-			    "stall on control pipe for device %u\n",
-			    sc->name, sc->dev->devnum);
+			printk(KERN_NOTICE "%s: stall on control pipe\n",
+			    sc->name);
 			goto Bad_End;
 		}
 
@@ -1014,9 +1090,8 @@ static void ub_scsi_urb_compl(struct ub_
 			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
 			if (rc != 0) {
 				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear for device %u"
-				    " (code %d)\n",
-				    sc->name, sc->dev->devnum, rc);
+				    "unable to submit clear (%d)\n",
+				    sc->name, rc);
 				/*
 				 * This is typically ENOMEM or some other such shit.
 				 * Retrying is pointless. Just do Bad End on it...
@@ -1075,9 +1150,8 @@ static void ub_scsi_urb_compl(struct ub_
 			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
 			if (rc != 0) {
 				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear for device %u"
-				    " (code %d)\n",
-				    sc->name, sc->dev->devnum, rc);
+				    "unable to submit clear (%d)\n",
+				    sc->name, rc);
 				/*
 				 * This is typically ENOMEM or some other such shit.
 				 * Retrying is pointless. Just do Bad End on it...
@@ -1108,9 +1182,8 @@ static void ub_scsi_urb_compl(struct ub_
 			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
 			if (rc != 0) {
 				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear for device %u"
-				    " (code %d)\n",
-				    sc->name, sc->dev->devnum, rc);
+				    "unable to submit clear (%d)\n",
+				    sc->name, rc);
 				/*
 				 * This is typically ENOMEM or some other such shit.
 				 * Retrying is pointless. Just do Bad End on it...
@@ -1132,9 +1205,8 @@ static void ub_scsi_urb_compl(struct ub_
 			 * encounter such a thing, try to read the CSW again.
 			 */
 			if (++cmd->stat_count >= 4) {
-				printk(KERN_NOTICE "%s: "
-				    "unable to get CSW on device %u\n",
-				    sc->name, sc->dev->devnum);
+				printk(KERN_NOTICE "%s: unable to get CSW\n",
+				    sc->name);
 				goto Bad_End;
 			}
 			__ub_state_stat(sc, cmd);
@@ -1175,10 +1247,8 @@ static void ub_scsi_urb_compl(struct ub_
 			 */
 			if (++cmd->stat_count >= 4) {
 				printk(KERN_NOTICE "%s: "
-				    "tag mismatch orig 0x%x reply 0x%x "
-				    "on device %u\n",
-				    sc->name, cmd->tag, bcs->Tag,
-				    sc->dev->devnum);
+				    "tag mismatch orig 0x%x reply 0x%x\n",
+				    sc->name, cmd->tag, bcs->Tag);
 				goto Bad_End;
 			}
 			__ub_state_stat(sc, cmd);
@@ -1212,8 +1282,8 @@ static void ub_scsi_urb_compl(struct ub_
 
 	} else {
 		printk(KERN_WARNING "%s: "
-		    "wrong command state %d on device %u\n",
-		    sc->name, cmd->state, sc->dev->devnum);
+		    "wrong command state %d\n",
+		    sc->name, cmd->state);
 		goto Bad_End;
 	}
 	return;
@@ -1256,7 +1326,6 @@ static void __ub_state_stat(struct ub_de
 
 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
 		/* XXX Clear stalls */
-		printk("%s: CSW #%d submit failed (%d)\n", sc->name, cmd->tag, rc); /* P3 */
 		ub_complete(&sc->work_done);
 		ub_state_done(sc, cmd, rc);
 		return;
@@ -1301,6 +1370,7 @@ static void ub_state_sense(struct ub_dev
 	scmd->state = UB_CMDST_INIT;
 	scmd->data = sc->top_sense;
 	scmd->len = UB_SENSE_SIZE;
+	scmd->lun = cmd->lun;
 	scmd->done = ub_top_sense_done;
 	scmd->back = cmd;
 
@@ -1379,14 +1449,14 @@ static void ub_top_sense_done(struct ub_
 	}
 	if (cmd != scmd->back) {
 		printk(KERN_WARNING "%s: "
-		    "sense done for wrong command 0x%x on device %u\n",
-		    sc->name, cmd->tag, sc->dev->devnum);
+		    "sense done for wrong command 0x%x\n",
+		    sc->name, cmd->tag);
 		return;
 	}
 	if (cmd->state != UB_CMDST_SENSE) {
 		printk(KERN_WARNING "%s: "
-		    "sense done with bad cmd state %d on device %u\n",
-		    sc->name, cmd->state, sc->dev->devnum);
+		    "sense done with bad cmd state %d\n",
+		    sc->name, cmd->state);
 		return;
 	}
 
@@ -1397,68 +1467,32 @@ static void ub_top_sense_done(struct ub_
 	ub_scsi_urb_compl(sc, cmd);
 }
 
-#if 0
-/* Determine what the maximum LUN supported is */
-int usb_stor_Bulk_max_lun(struct us_data *us)
-{
-	int result;
-
-	/* issue the command */
-	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
-				 US_BULK_GET_MAX_LUN, 
-				 USB_DIR_IN | USB_TYPE_CLASS | 
-				 USB_RECIP_INTERFACE,
-				 0, us->ifnum, us->iobuf, 1, HZ);
-
-	/* 
-	 * Some devices (i.e. Iomega Zip100) need this -- apparently
-	 * the bulk pipes get STALLed when the GetMaxLUN request is
-	 * processed.   This is, in theory, harmless to all other devices
-	 * (regardless of if they stall or not).
-	 */
-	if (result < 0) {
-		usb_stor_clear_halt(us, us->recv_bulk_pipe);
-		usb_stor_clear_halt(us, us->send_bulk_pipe);
-	}
-
-	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
-		  result, us->iobuf[0]);
-
-	/* if we have a successful request, return the result */
-	if (result == 1)
-		return us->iobuf[0];
-
-	/* return the default -- no LUNs */
-	return 0;
-}
-#endif
-
 /*
  * This is called from a process context.
  */
-static void ub_revalidate(struct ub_dev *sc)
+static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
 {
 
-	sc->readonly = 0;	/* XXX Query this from the device */
+	lun->readonly = 0;	/* XXX Query this from the device */
 
-	sc->capacity.nsec = 0;
-	sc->capacity.bsize = 512;
-	sc->capacity.bshift = 0;
+	lun->capacity.nsec = 0;
+	lun->capacity.bsize = 512;
+	lun->capacity.bshift = 0;
 
-	if (ub_sync_tur(sc) != 0)
+	if (ub_sync_tur(sc, lun) != 0)
 		return;			/* Not ready */
-	sc->changed = 0;
+	lun->changed = 0;
 
-	if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
+	if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
 		/*
 		 * The retry here means something is wrong, either with the
 		 * device, with the transport, or with our code.
 		 * We keep this because sd.c has retries for capacity.
 		 */
-		if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
-			sc->capacity.nsec = 0;
-			sc->capacity.bsize = 512;
-			sc->capacity.bshift = 0;
+		if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
+			lun->capacity.nsec = 0;
+			lun->capacity.bsize = 512;
+			lun->capacity.bshift = 0;
 		}
 	}
 }
@@ -1471,12 +1505,15 @@ static void ub_revalidate(struct ub_dev 
 static int ub_bd_open(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ub_lun *lun;
 	struct ub_dev *sc;
 	unsigned long flags;
 	int rc;
 
-	if ((sc = disk->private_data) == NULL)
+	if ((lun = disk->private_data) == NULL)
 		return -ENXIO;
+	sc = lun->udev;
+
 	spin_lock_irqsave(&ub_lock, flags);
 	if (atomic_read(&sc->poison)) {
 		spin_unlock_irqrestore(&ub_lock, flags);
@@ -1497,15 +1534,15 @@ static int ub_bd_open(struct inode *inod
 	 * The bottom line is, Al Viro says that we should not allow
 	 * bdev->bd_invalidated to be set when doing add_disk no matter what.
 	 */
-	if (sc->first_open) {
-		if (sc->changed) {
-			sc->first_open = 0;
+	if (lun->first_open) {
+		lun->first_open = 0;
+		if (lun->changed) {
 			rc = -ENOMEDIUM;
 			goto err_open;
 		}
 	}
 
-	if (sc->removable || sc->readonly)
+	if (lun->removable || lun->readonly)
 		check_disk_change(inode->i_bdev);
 
 	/*
@@ -1513,12 +1550,12 @@ static int ub_bd_open(struct inode *inod
 	 * under some pretty murky conditions (a failure of READ CAPACITY).
 	 * We may need it one day.
 	 */
-	if (sc->removable && sc->changed && !(filp->f_flags & O_NDELAY)) {
+	if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {
 		rc = -ENOMEDIUM;
 		goto err_open;
 	}
 
-	if (sc->readonly && (filp->f_mode & FMODE_WRITE)) {
+	if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {
 		rc = -EROFS;
 		goto err_open;
 	}
@@ -1526,11 +1563,7 @@ static int ub_bd_open(struct inode *inod
 	return 0;
 
 err_open:
-	spin_lock_irqsave(&ub_lock, flags);
-	--sc->openc;
-	if (sc->openc == 0 && atomic_read(&sc->poison))
-		ub_cleanup(sc);
-	spin_unlock_irqrestore(&ub_lock, flags);
+	ub_put(sc);
 	return rc;
 }
 
@@ -1539,16 +1572,10 @@ err_open:
 static int ub_bd_release(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
-	struct ub_dev *sc = disk->private_data;
-	unsigned long flags;
+	struct ub_lun *lun = disk->private_data;
+	struct ub_dev *sc = lun->udev;
 
-	spin_lock_irqsave(&ub_lock, flags);
-	--sc->openc;
-	if (sc->openc == 0)
-		sc->first_open = 0;
-	if (sc->openc == 0 && atomic_read(&sc->poison))
-		ub_cleanup(sc);
-	spin_unlock_irqrestore(&ub_lock, flags);
+	ub_put(sc);
 	return 0;
 }
 
@@ -1576,20 +1603,14 @@ static int ub_bd_ioctl(struct inode *ino
  */
 static int ub_bd_revalidate(struct gendisk *disk)
 {
-	struct ub_dev *sc = disk->private_data;
+	struct ub_lun *lun = disk->private_data;
 
-	ub_revalidate(sc);
-	/* This is pretty much a long term P3 */
-	if (!atomic_read(&sc->poison)) {		/* Cover sc->dev */
-		printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
-		    sc->name, sc->dev->devnum,
-		    sc->capacity.nsec, sc->capacity.bsize);
-	}
+	ub_revalidate(lun->udev, lun);
 
 	/* XXX Support sector size switching like in sr.c */
-	blk_queue_hardsect_size(disk->queue, sc->capacity.bsize);
-	set_capacity(disk, sc->capacity.nsec);
-	// set_disk_ro(sdkp->disk, sc->readonly);
+	blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
+	set_capacity(disk, lun->capacity.nsec);
+	// set_disk_ro(sdkp->disk, lun->readonly);
 
 	return 0;
 }
@@ -1605,9 +1626,9 @@ static int ub_bd_revalidate(struct gendi
  */
 static int ub_bd_media_changed(struct gendisk *disk)
 {
-	struct ub_dev *sc = disk->private_data;
+	struct ub_lun *lun = disk->private_data;
 
-	if (!sc->removable)
+	if (!lun->removable)
 		return 0;
 
 	/*
@@ -1619,12 +1640,12 @@ static int ub_bd_media_changed(struct ge
 	 * will fail, then block layer discards the data. Since we never
 	 * spin drives up, such devices simply cannot be used with ub anyway.
 	 */
-	if (ub_sync_tur(sc) != 0) {
-		sc->changed = 1;
+	if (ub_sync_tur(lun->udev, lun) != 0) {
+		lun->changed = 1;
 		return 1;
 	}
 
-	return sc->changed;
+	return lun->changed;
 }
 
 static struct block_device_operations ub_bd_fops = {
@@ -1648,7 +1669,7 @@ static void ub_probe_done(struct ub_dev 
 /*
  * Test if the device has a check condition on it, synchronously.
  */
-static int ub_sync_tur(struct ub_dev *sc)
+static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
 {
 	struct ub_scsi_cmd *cmd;
 	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };
@@ -1667,6 +1688,7 @@ static int ub_sync_tur(struct ub_dev *sc
 	cmd->cdb_len = 6;
 	cmd->dir = UB_DIR_NONE;
 	cmd->state = UB_CMDST_INIT;
+	cmd->lun = lun;			/* This may be NULL, but that's ok */
 	cmd->done = ub_probe_done;
 	cmd->back = &compl;
 
@@ -1697,7 +1719,8 @@ err_alloc:
 /*
  * Read the SCSI capacity synchronously (for probing).
  */
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret)
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_capacity *ret)
 {
 	struct ub_scsi_cmd *cmd;
 	char *p;
@@ -1722,6 +1745,7 @@ static int ub_sync_read_cap(struct ub_de
 	cmd->state = UB_CMDST_INIT;
 	cmd->data = p;
 	cmd->len = 8;
+	cmd->lun = lun;
 	cmd->done = ub_probe_done;
 	cmd->back = &compl;
 
@@ -1791,6 +1815,90 @@ static void ub_probe_timeout(unsigned lo
 }
 
 /*
+ * Get number of LUNs by the way of Bulk GetMaxLUN command.
+ */
+static int ub_sync_getmaxlun(struct ub_dev *sc)
+{
+	int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
+	unsigned char *p;
+	enum { ALLOC_SIZE = 1 };
+	struct usb_ctrlrequest *cr;
+	struct completion compl;
+	struct timer_list timer;
+	int nluns;
+	int rc;
+
+	init_completion(&compl);
+
+	rc = -ENOMEM;
+	if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+		goto err_alloc;
+	*p = 55;
+
+	cr = &sc->work_cr;
+	cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	cr->bRequest = US_BULK_GET_MAX_LUN;
+	cr->wValue = cpu_to_le16(0);
+	cr->wIndex = cpu_to_le16(ifnum);
+	cr->wLength = cpu_to_le16(1);
+
+	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
+	    (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
+	sc->work_urb.transfer_flags = 0;
+	sc->work_urb.actual_length = 0;
+	sc->work_urb.error_count = 0;
+	sc->work_urb.status = 0;
+
+	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+		if (rc == -EPIPE) {
+			printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
+			     sc->name); /* P3 */
+		} else {
+			printk(KERN_WARNING
+			     "%s: Unable to submit GetMaxLUN (%d)\n",
+			     sc->name, rc);
+		}
+		goto err_submit;
+	}
+
+	init_timer(&timer);
+	timer.function = ub_probe_timeout;
+	timer.data = (unsigned long) &compl;
+	timer.expires = jiffies + UB_CTRL_TIMEOUT;
+	add_timer(&timer);
+
+	wait_for_completion(&compl);
+
+	del_timer_sync(&timer);
+	usb_kill_urb(&sc->work_urb);
+
+	if (sc->work_urb.actual_length != 1) {
+		printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
+		    sc->work_urb.actual_length); /* P3 */
+		nluns = 0;
+	} else {
+		if ((nluns = *p) == 55) {
+			nluns = 0;
+		} else {
+  			/* GetMaxLUN returns the maximum LUN number */
+			nluns += 1;
+			if (nluns > UB_MAX_LUNS)
+				nluns = UB_MAX_LUNS;
+		}
+		printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name,
+		    *p, nluns); /* P3 */
+	}
+
+	kfree(p);
+	return nluns;
+
+err_submit:
+	kfree(p);
+err_alloc:
+	return rc;
+}
+
+/*
  * Clear initial stalls.
  */
 static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
@@ -1876,8 +1984,8 @@ static int ub_get_pipes(struct ub_dev *s
 	}
 
 	if (ep_in == NULL || ep_out == NULL) {
-		printk(KERN_NOTICE "%s: device %u failed endpoint check\n",
-		    sc->name, sc->dev->devnum);
+		printk(KERN_NOTICE "%s: failed endpoint check\n",
+		    sc->name);
 		return -EIO;
 	}
 
@@ -1900,8 +2008,7 @@ static int ub_probe(struct usb_interface
     const struct usb_device_id *dev_id)
 {
 	struct ub_dev *sc;
-	request_queue_t *q;
-	struct gendisk *disk;
+	int nluns;
 	int rc;
 	int i;
 
@@ -1910,6 +2017,7 @@ static int ub_probe(struct usb_interface
 		goto err_core;
 	memset(sc, 0, sizeof(struct ub_dev));
 	spin_lock_init(&sc->lock);
+	INIT_LIST_HEAD(&sc->luns);
 	usb_init_urb(&sc->work_urb);
 	tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
 	atomic_set(&sc->poison, 0);
@@ -1921,19 +2029,16 @@ static int ub_probe(struct usb_interface
 	ub_init_completion(&sc->work_done);
 	sc->work_done.done = 1;		/* A little yuk, but oh well... */
 
-	rc = -ENOSR;
-	if ((sc->id = ub_id_get()) == -1)
-		goto err_id;
-	snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a');
-
 	sc->dev = interface_to_usbdev(intf);
 	sc->intf = intf;
 	// sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
 	usb_set_intfdata(intf, sc);
 	usb_get_dev(sc->dev);
 	// usb_get_intf(sc->intf);	/* Do we need this? */
 
+	snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
+	    sc->dev->bus->busnum, sc->dev->devnum);
+
 	/* XXX Verify that we can handle the device (from descriptors) */
 
 	ub_get_pipes(sc, sc->dev, intf);
@@ -1971,35 +2076,88 @@ static int ub_probe(struct usb_interface
 	 * In any case it's not our business how revaliadation is implemented.
 	 */
 	for (i = 0; i < 3; i++) {	/* Retries for benh's key */
-		if ((rc = ub_sync_tur(sc)) <= 0) break;
+		if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
 		if (rc != 0x6) break;
 		msleep(10);
 	}
 
-	sc->removable = 1;		/* XXX Query this from the device */
-	sc->changed = 1;		/* ub_revalidate clears only */
-	sc->first_open = 1;
+	nluns = 1;
+	for (i = 0; i < 3; i++) {
+		if ((rc = ub_sync_getmaxlun(sc)) < 0) {
+			/* 
+			 * Some devices (i.e. Iomega Zip100) need this --
+			 * apparently the bulk pipes get STALLed when the
+			 * GetMaxLUN request is processed.
+			 * XXX I have a ZIP-100, verify it does this.
+			 */
+			if (rc == -EPIPE) {
+				ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+				ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+			}
+			break;
+		}
+		if (rc != 0) {
+			nluns = rc;
+			break;
+		}
+		msleep(100);
+	}
 
-	ub_revalidate(sc);
-	/* This is pretty much a long term P3 */
-	printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
-	    sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize);
+	for (i = 0; i < nluns; i++) {
+		ub_probe_lun(sc, i);
+	}
+	return 0;
+
+	/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
+err_diag:
+	usb_set_intfdata(intf, NULL);
+	// usb_put_intf(sc->intf);
+	usb_put_dev(sc->dev);
+	kfree(sc);
+err_core:
+	return rc;
+}
+
+static int ub_probe_lun(struct ub_dev *sc, int lnum)
+{
+	struct ub_lun *lun;
+	request_queue_t *q;
+	struct gendisk *disk;
+	int rc;
+
+	rc = -ENOMEM;
+	if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+		goto err_alloc;
+	memset(lun, 0, sizeof(struct ub_lun));
+	lun->num = lnum;
+
+	rc = -ENOSR;
+	if ((lun->id = ub_id_get()) == -1)
+		goto err_id;
+
+	lun->udev = sc;
+	list_add(&lun->link, &sc->luns);
+
+	snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
+	    lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
+
+	lun->removable = 1;		/* XXX Query this from the device */
+	lun->changed = 1;		/* ub_revalidate clears only */
+	lun->first_open = 1;
+	ub_revalidate(sc, lun);
 
-	/*
-	 * Just one disk per sc currently, but maybe more.
-	 */
 	rc = -ENOMEM;
 	if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL)
 		goto err_diskalloc;
 
-	sc->disk = disk;
-	sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a');
-	sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a');
+	lun->disk = disk;
+	sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
+	sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
 	disk->major = UB_MAJOR;
-	disk->first_minor = sc->id * UB_MINORS_PER_MAJOR;
+	disk->first_minor = lun->id * UB_MINORS_PER_MAJOR;
 	disk->fops = &ub_bd_fops;
-	disk->private_data = sc;
-	disk->driverfs_dev = &intf->dev;
+	disk->private_data = lun;
+	disk->driverfs_dev = &sc->intf->dev;	/* XXX Many to one ok? */
 
 	rc = -ENOMEM;
 	if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
@@ -2007,28 +2165,17 @@ static int ub_probe(struct usb_interface
 
 	disk->queue = q;
 
-        // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 	blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
 	blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
-	// blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
+	blk_queue_segment_boundary(q, 0xffffffff);	/* Dubious. */
 	blk_queue_max_sectors(q, UB_MAX_SECTORS);
-	blk_queue_hardsect_size(q, sc->capacity.bsize);
-
-	/*
-	 * This is a serious infraction, caused by a deficiency in the
-	 * USB sg interface (usb_sg_wait()). We plan to remove this once
-	 * we get mileage on the driver and can justify a change to USB API.
-	 * See blk_queue_bounce_limit() to understand this part.
-	 *
-	 * XXX And I still need to be aware of the DMA mask in the HC.
-	 */
-	q->bounce_pfn = blk_max_low_pfn;
-	q->bounce_gfp = GFP_NOIO;
+	blk_queue_hardsect_size(q, lun->capacity.bsize);
 
-	q->queuedata = sc;
+	q->queuedata = lun;
 
-	set_capacity(disk, sc->capacity.nsec);
-	if (sc->removable)
+	set_capacity(disk, lun->capacity.nsec);
+	if (lun->removable)
 		disk->flags |= GENHD_FL_REMOVABLE;
 
 	add_disk(disk);
@@ -2038,28 +2185,32 @@ static int ub_probe(struct usb_interface
 err_blkqinit:
 	put_disk(disk);
 err_diskalloc:
-	device_remove_file(&sc->intf->dev, &dev_attr_diag);
-err_diag:
-	usb_set_intfdata(intf, NULL);
-	// usb_put_intf(sc->intf);
-	usb_put_dev(sc->dev);
-	spin_lock_irq(&ub_lock);
-	ub_id_put(sc->id);
-	spin_unlock_irq(&ub_lock);
+	list_del(&lun->link);
+	ub_id_put(lun->id);
 err_id:
-	kfree(sc);
-err_core:
+	kfree(lun);
+err_alloc:
 	return rc;
 }
 
 static void ub_disconnect(struct usb_interface *intf)
 {
 	struct ub_dev *sc = usb_get_intfdata(intf);
-	struct gendisk *disk = sc->disk;
-	request_queue_t *q = disk->queue;
+	struct list_head *p;
+	struct ub_lun *lun;
+	struct gendisk *disk;
 	unsigned long flags;
 
 	/*
+	 * Prevent ub_bd_release from pulling the rug from under us.
+	 * XXX This is starting to look like a kref.
+	 * XXX Why not to take this ref at probe time?
+	 */
+	spin_lock_irqsave(&ub_lock, flags);
+	sc->openc++;
+	spin_unlock_irqrestore(&ub_lock, flags);
+
+	/*
 	 * Fence stall clearnings, operations triggered by unlinkings and so on.
 	 * We do not attempt to unlink any URBs, because we do not trust the
 	 * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
@@ -2095,17 +2246,22 @@ static void ub_disconnect(struct usb_int
 	spin_unlock_irqrestore(&sc->lock, flags);
 
 	/*
-	 * Unregister the upper layer, this waits for all commands to end.
+	 * Unregister the upper layer.
 	 */
-	if (disk->flags & GENHD_FL_UP)
-		del_gendisk(disk);
-	if (q)
-		blk_cleanup_queue(q);
+	list_for_each (p, &sc->luns) {
+		lun = list_entry(p, struct ub_lun, link);
+		disk = lun->disk;
+		if (disk->flags & GENHD_FL_UP)
+			del_gendisk(disk);
+		/*
+		 * I wish I could do:
+		 *    set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+		 * As it is, we rely on our internal poisoning and let
+		 * the upper levels to spin furiously failing all the I/O.
+		 */
+	}
 
 	/*
-	 * We really expect blk_cleanup_queue() to wait, so no amount
-	 * of paranoya is too much.
-	 *
 	 * Taking a lock on a structure which is about to be freed
 	 * is very nonsensual. Here it is largely a way to do a debug freeze,
 	 * and a bracket which shows where the nonsensual code segment ends.
@@ -2139,13 +2295,10 @@ static void ub_disconnect(struct usb_int
 	usb_put_dev(sc->dev);
 	sc->dev = NULL;
 
-	spin_lock_irqsave(&ub_lock, flags);
-	if (sc->openc == 0)
-		ub_cleanup(sc);
-	spin_unlock_irqrestore(&ub_lock, flags);
+	ub_put(sc);
 }
 
-struct usb_driver ub_driver = {
+static struct usb_driver ub_driver = {
 	.owner =	THIS_MODULE,
 	.name =		"ub",
 	.probe =	ub_probe,
@@ -2157,8 +2310,8 @@ static int __init ub_init(void)
 {
 	int rc;
 
-	/* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n",
-			sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev));
+	/* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu ub_lun %zu\n",
+			sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev), sizeof(struct ub_lun));
 
 	if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
 		goto err_regblkdev;
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -1181,7 +1181,7 @@ static struct pci_driver mm_pci_driver =
 -----------------------------------------------------------------------------------
 */
 
-int __init mm_init(void)
+static int __init mm_init(void)
 {
 	int retval, i;
 	int err;
@@ -1232,7 +1232,7 @@ out:
 --                             mm_cleanup
 -----------------------------------------------------------------------------------
 */
-void __exit mm_cleanup(void)
+static void __exit mm_cleanup(void)
 {
 	int i;
 
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -250,7 +250,6 @@ static int viodasd_release(struct inode 
 static int viodasd_ioctl(struct inode *ino, struct file *fil,
 			 unsigned int cmd, unsigned long arg)
 {
-	int err;
 	unsigned char sectors;
 	unsigned char heads;
 	unsigned short cylinders;
@@ -263,9 +262,8 @@ static int viodasd_ioctl(struct inode *i
 		geo = (struct hd_geometry *)arg;
 		if (geo == NULL)
 			return -EINVAL;
-		err = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
-		if (err)
-			return err;
+		if (!access_ok(VERIFY_WRITE, geo, sizeof(*geo)))
+			return -EFAULT;
 		gendisk = ino->i_bdev->bd_disk;
 		d = gendisk->private_data;
 		sectors = d->sectors;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -67,7 +67,7 @@ static int xd[5] = { -1,-1,-1,-1, };
 /* Above may need to be increased if a problem with the 2nd drive detection
    (ST11M controller) or resetting a controller (WD) appears */
 
-XD_INFO xd_info[XD_MAXDRIVES];
+static XD_INFO xd_info[XD_MAXDRIVES];
 
 /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
    signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -63,7 +63,7 @@ MODULE_DEVICE_TABLE(usb, bfusb_table);
 
 #define BFUSB_MAX_BLOCK_SIZE	256
 
-#define BFUSB_BLOCK_TIMEOUT	(HZ * 3)
+#define BFUSB_BLOCK_TIMEOUT	3000
 
 #define BFUSB_TX_PROCESS	1
 #define BFUSB_TX_WAKEUP		2
@@ -582,7 +582,7 @@ static int bfusb_load_firmware(struct bf
 	pipe = usb_sndctrlpipe(bfusb->udev, 0);
 
 	if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-				0, 1, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT) < 0) {
+				0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
 		BT_ERR("Can't change to loading configuration");
 		return -EBUSY;
 	}
@@ -623,7 +623,7 @@ static int bfusb_load_firmware(struct bf
 	pipe = usb_sndctrlpipe(bfusb->udev, 0);
 
         if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-				0, 2, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) {
+				0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
 		BT_ERR("Can't change to running configuration");
 		goto error;
 	}
@@ -641,7 +641,7 @@ error:
 	pipe = usb_sndctrlpipe(bfusb->udev, 0);
 
 	usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-				0, 0, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+				0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
 
 	return err;
 }
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -35,6 +35,7 @@
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <linux/moduleparam.h>
+#include <linux/wait.h>
 
 #include <linux/skbuff.h>
 #include <asm/io.h>
@@ -289,8 +290,9 @@ static void bluecard_write_wakeup(blueca
 		clear_bit(ready_bit, &(info->tx_state));
 
 		if (skb->pkt_type & 0x80) {
+			DECLARE_WAIT_QUEUE_HEAD(wq);
+			DEFINE_WAIT(wait);
 
-			wait_queue_head_t wait;
 			unsigned char baud_reg;
 
 			switch (skb->pkt_type) {
@@ -311,8 +313,9 @@ static void bluecard_write_wakeup(blueca
 			}
 
 			/* Wait until the command reaches the baseband */
-			init_waitqueue_head(&wait);
-			interruptible_sleep_on_timeout(&wait, HZ / 10);
+			prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ/10);
+			finish_wait(&wq, &wait);
 
 			/* Set baud on baseband */
 			info->ctrl_reg &= ~0x03;
@@ -324,8 +327,9 @@ static void bluecard_write_wakeup(blueca
 			outb(info->ctrl_reg, iobase + REG_CONTROL);
 
 			/* Wait before the next HCI packet can be send */
-			interruptible_sleep_on_timeout(&wait, HZ);
-
+			prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ);
+			finish_wait(&wq, &wait);
 		}
 
 		if (len == skb->len) {
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -28,7 +28,7 @@
  * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $
  */
 
-#define VERSION "0.1"
+#define VERSION "0.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -62,6 +62,8 @@
 #define BT_DMP( A... )
 #endif
 
+static int hciextn = 1;
+
 /* ---- BCSP CRC calculation ---- */
 
 /* Table for calculating CRC for polynomial 0x1021, LSB processed first,
@@ -158,12 +160,13 @@ static int bcsp_enqueue(struct hci_uart 
 	case HCI_SCODATA_PKT:
 		skb_queue_tail(&bcsp->unrel, skb);
 		break;
-		
+
 	default:
 		BT_ERR("Unknown packet type");
 		kfree_skb(skb);
 		break;
 	}
+
 	return 0;
 }
 
@@ -171,7 +174,7 @@ static struct sk_buff *bcsp_prepare_pkt(
 		int len, int pkt_type)
 {
 	struct sk_buff *nskb;
-	u8  hdr[4], chan;
+	u8 hdr[4], chan;
 	int rel, i;
 
 #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
@@ -204,6 +207,19 @@ static struct sk_buff *bcsp_prepare_pkt(
 		return NULL;
 	}
 
+	if (hciextn && chan == 5) {
+		struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
+
+		if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
+			u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
+			if ((desc & 0xf0) == 0xc0) {
+				data += HCI_COMMAND_HDR_SIZE + 1;
+				len  -= HCI_COMMAND_HDR_SIZE + 1;
+				chan = desc & 0x0f;
+			}
+		}
+	}
+
 	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
 	   (because bytes 0xc0 and 0xdb are escaped, worst case is
 	   when the packet is all made of 0xc0 and 0xdb :) )
@@ -226,19 +242,18 @@ static struct sk_buff *bcsp_prepare_pkt(
 		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
 		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
 	}
-#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
 	hdr[0] |= 0x40;
 #endif
 
-	hdr[1]  = (len << 4) & 0xFF;
-	hdr[1] |= chan;
-	hdr[2]  = len >> 4;
-	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
+	hdr[1] = ((len << 4) & 0xff) | chan;
+	hdr[2] = len >> 4;
+	hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
 
 	/* Put BCSP header */
 	for (i = 0; i < 4; i++) {
 		bcsp_slip_one_byte(nskb, hdr[i]);
-#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
 		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
 #endif
 	}
@@ -246,7 +261,7 @@ static struct sk_buff *bcsp_prepare_pkt(
 	/* Put payload */
 	for (i = 0; i < len; i++) {
 		bcsp_slip_one_byte(nskb, data[i]);
-#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
 		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
 #endif
 	}
@@ -487,14 +502,30 @@ static inline void bcsp_complete_rx_pkt(
 		pass_up = 0;
 
 	if (!pass_up) {
-		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
-	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
-			BT_ERR ("Packet for unknown channel (%u %s)",
-				bcsp->rx_skb->data[1] & 0x0f,
-				bcsp->rx_skb->data[0] & 0x80 ? 
-				"reliable" : "unreliable");
-		}
-		kfree_skb(bcsp->rx_skb);
+		struct hci_event_hdr hdr;
+		u8 desc = (bcsp->rx_skb->data[1] & 0x0f);
+
+		if (desc != 0 && desc != 1) {
+			if (hciextn) {
+				desc |= 0xc0;
+				skb_pull(bcsp->rx_skb, 4);
+				memcpy(skb_push(bcsp->rx_skb, 1), &desc, 1);
+
+				hdr.evt = 0xff;
+				hdr.plen = bcsp->rx_skb->len;
+				memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE);
+				bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+
+				hci_recv_frame(bcsp->rx_skb);
+			} else {
+				BT_ERR ("Packet for unknown channel (%u %s)",
+					bcsp->rx_skb->data[1] & 0x0f,
+					bcsp->rx_skb->data[0] & 0x80 ? 
+					"reliable" : "unreliable");
+				kfree_skb(bcsp->rx_skb);
+			}
+		} else
+			kfree_skb(bcsp->rx_skb);
 	} else {
 		/* Pull out BCSP hdr */
 		skb_pull(bcsp->rx_skb, 4);
@@ -713,3 +744,6 @@ int bcsp_deinit(void)
 {
 	return hci_uart_unregister_proto(&bcsp);
 }
+
+module_param(hciextn, bool, 0644);
+MODULE_PARM_DESC(hciextn, "Convert HCI Extensions into BCSP packets");
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -888,7 +888,7 @@ static int hci_usb_probe(struct usb_inte
 	isoc_ifnum = 1;
 
 #ifdef CONFIG_BT_HCIUSB_SCO
-	if (isoc && !(id->driver_info & HCI_BROKEN_ISOC))
+	if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER)))
 		isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum);
 
 	if (isoc_iface) {
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -157,7 +157,7 @@ static ssize_t hci_vhci_chr_write(struct
 {
 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
 
-	if (verify_area(VERIFY_READ, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 
 	return hci_vhci_get_user(hci_vhci, buf, count);
@@ -222,7 +222,7 @@ static ssize_t hci_vhci_chr_read(struct 
 			continue;
 		}
 
-		if (!verify_area(VERIFY_WRITE, buf, count))
+		if (access_ok(VERIFY_WRITE, buf, count))
 			ret = hci_vhci_put_user(hci_vhci, skb, buf, count);
 		else
 			ret = -EFAULT;
@@ -308,12 +308,13 @@ static int hci_vhci_chr_open(struct inod
 static int hci_vhci_chr_close(struct inode *inode, struct file *file)
 {
 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
+	struct hci_dev *hdev = hci_vhci->hdev;
 
-	if (hci_unregister_dev(hci_vhci->hdev) < 0) {
-		BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev->name);
+	if (hci_unregister_dev(hdev) < 0) {
+		BT_ERR("Can't unregister HCI device %s", hdev->name);
 	}
 
-	hci_free_dev(hci_vhci->hdev);
+	hci_free_dev(hdev);
 
 	file->private_data = NULL;
 	return 0;
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
--- a/drivers/cdrom/Kconfig
+++ b/drivers/cdrom/Kconfig
@@ -103,60 +103,14 @@ config SBPCD
 	  To compile this driver as a module, choose M here: the
 	  module will be called sbpcd.
 
-config MCD
-	tristate "Mitsumi (standard) [no XA/Multisession] CDROM support"
-	depends on CD_NO_IDESCSI && BROKEN
-	---help---
-	  This is the older of the two drivers for the older Mitsumi models
-	  LU-005, FX-001 and FX-001D. This is not the right driver for the
-	  FX-001DE and the triple or quad speed models (all these are
-	  IDE/ATAPI models). Please also the file
-	  <file:Documentation/cdrom/mcd>.
-
-	  With the old LU-005 model, the whole drive chassis slides out for cd
-	  insertion. The FX-xxx models use a motorized tray type mechanism.
-	  Note that this driver does not support XA or MultiSession CDs
-	  (PhotoCDs). There is a new driver (next question) which can do
-	  this. If you want that one, say N here.
-
-	  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-	  file system support" below, because that's the file system used on
-	  CD-ROMs.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called mcd.
-
-config MCD_IRQ
-	int "MCD IRQ"
-	depends on MCD
-	default "11"
-	help
-	  This allows you to specify the default value of the IRQ used by the
-	  driver. This setting can be overridden by passing the "mcd="
-	  parameter to the kernel at boot time (or at module load time if you
-	  said M to "Standard Mitsumi CD-ROM support").
-
-config MCD_BASE
-	hex "MCD I/O base"
-	depends on MCD
-	default "300"
-	help
-	  This allows you to specify the default value of the I/O base address
-	  used by the driver. This setting can be overridden by passing the
-	  "mcd=" parameter to the kernel at boot time (or at module load time
-	  if you said M to "Standard Mitsumi CD-ROM support").
-
 config MCDX
-	tristate "Mitsumi [XA/MultiSession] CDROM support"
+	tristate "Mitsumi CDROM support"
 	depends on CD_NO_IDESCSI
 	---help---
-	  Use this driver if you want to be able to read XA or MultiSession
-	  CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005,
-	  FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much
-	  less kernel memory than the old one, if that is a concern. This
-	  driver is able to support more than one drive, but each drive needs
-	  a separate interface card. Please read the file
-	  <file:Documentation/cdrom/mcdx>.
+	  Use this driver if you want to be able to use your Mitsumi LU-005,
+	  FX-001 or FX-001D CD-ROM drive.
+
+	  Please read the file <file:Documentation/cdrom/mcdx>.
 
 	  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
 	  file system support" below, because that's the file system used on
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
--- a/drivers/cdrom/Makefile
+++ b/drivers/cdrom/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_CDU31A)		+= cdu31a.o     cd
 obj-$(CONFIG_CM206)		+= cm206.o      cdrom.o
 obj-$(CONFIG_GSCD)		+= gscd.o
 obj-$(CONFIG_ISP16_CDI)		+= isp16.o
-obj-$(CONFIG_MCD)		+= mcd.o        cdrom.o
 obj-$(CONFIG_MCDX)		+= mcdx.o       cdrom.o
 obj-$(CONFIG_OPTCD)		+= optcd.o
 obj-$(CONFIG_SBPCD)		+= sbpcd.o      cdrom.o
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -645,7 +645,7 @@ static int cdrom_mrw_exit(struct cdrom_d
 		ret = cdrom_mrw_bgformat_susp(cdi, 0);
 	}
 
-	if (!ret)
+	if (!ret && cdi->media_written)
 		ret = cdrom_flush_cache(cdi);
 
 	return ret;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -148,10 +148,10 @@
  *			Ondrej Zary <rainbow@rainbow-software.org>
 */
 
-#include <linux/major.h>
+#define DEBUG 1
 
+#include <linux/major.h>
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -166,13 +166,13 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/cdrom.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 
-#include <linux/cdrom.h>
 #include "cdu31a.h"
 
 #define MAJOR_NR CDU31A_CDROM_MAJOR
@@ -180,10 +180,7 @@
 
 #define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
 
-#define DEBUG 1
-
-/* Define the following if you have data corruption problems. */
-#undef SONY_POLL_EACH_BYTE
+#define PFX "CDU31A: "
 
 /*
 ** Edit the following data to change interrupts, DMA channels, etc.
@@ -267,14 +264,7 @@ static int sony_toc_read = 0;	/* Has the
 static struct s_sony_subcode last_sony_subcode;	/* Points to the last
 						   subcode address read */
 
-static volatile int sony_inuse = 0;	/* Is the drive in use?  Only one operation
-					   at a time allowed */
-
-static DECLARE_WAIT_QUEUE_HEAD(sony_wait);	/* Things waiting for the drive */
-
-static struct task_struct *has_cd_task = NULL;	/* The task that is currently
-						   using the CDROM drive, or
-						   NULL if none. */
+static DECLARE_MUTEX(sony_sem);		/* Semaphore for drive hardware access */
 
 static int is_double_speed = 0;	/* does the drive support double speed ? */
 
@@ -302,7 +292,8 @@ module_param(cdu31a_irq, int, 0);
 
 /* The interrupt handler will wake this queue up when it gets an
    interrupts. */
-DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait);
+static DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait);
+static int irq_flag = 0;
 
 static int curr_control_reg = 0;	/* Current value of the control register */
 
@@ -344,13 +335,16 @@ static int scd_media_changed(struct cdro
  */
 static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 {
-	if (CDSL_CURRENT != slot_nr) {
+	if (CDSL_CURRENT != slot_nr)
 		/* we have no changer support */
 		return -EINVAL;
-	}
-	if (scd_spinup() == 0) {
+	if (sony_spun_up)
+		return CDS_DISC_OK;
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
+	if (scd_spinup() == 0)
 		sony_spun_up = 1;
-	}
+	up(&sony_sem);
 	return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
 }
 
@@ -376,17 +370,31 @@ static inline void disable_interrupts(vo
  */
 static inline void sony_sleep(void)
 {
-	unsigned long flags;
-
 	if (cdu31a_irq <= 0) {
 		yield();
 	} else {		/* Interrupt driven */
+		DEFINE_WAIT(w);
+		int first = 1;
 
-		save_flags(flags);
-		cli();
-		enable_interrupts();
-		interruptible_sleep_on(&cdu31a_irq_wait);
-		restore_flags(flags);
+		while (1) {
+			prepare_to_wait(&cdu31a_irq_wait, &w,
+					TASK_INTERRUPTIBLE);
+			if (first) {
+				enable_interrupts();
+				first = 0;
+			}
+
+			if (irq_flag != 0)
+				break;
+			if (!signal_pending(current)) {
+				schedule();
+				continue;
+			} else
+				disable_interrupts();
+			break;
+		}
+		finish_wait(&cdu31a_irq_wait, &w);
+		irq_flag = 0;
 	}
 }
 
@@ -397,37 +405,37 @@ static inline void sony_sleep(void)
  */
 static inline int is_attention(void)
 {
-	return ((inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0);
+	return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0;
 }
 
 static inline int is_busy(void)
 {
-	return ((inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0);
+	return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0;
 }
 
 static inline int is_data_ready(void)
 {
-	return ((inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0);
+	return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0;
 }
 
 static inline int is_data_requested(void)
 {
-	return ((inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0);
+	return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0;
 }
 
 static inline int is_result_ready(void)
 {
-	return ((inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0);
+	return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0;
 }
 
 static inline int is_param_write_rdy(void)
 {
-	return ((inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0);
+	return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0;
 }
 
 static inline int is_result_reg_not_empty(void)
 {
-	return ((inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0);
+	return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0;
 }
 
 static inline void reset_drive(void)
@@ -445,6 +453,8 @@ static int scd_reset(struct cdrom_device
 {
 	unsigned long retry_count;
 
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	reset_drive();
 
 	retry_count = jiffies + SONY_RESET_TIMEOUT;
@@ -452,6 +462,7 @@ static int scd_reset(struct cdrom_device
 		sony_sleep();
 	}
 
+	up(&sony_sem);
 	return 0;
 }
 
@@ -478,17 +489,17 @@ static inline void clear_param_reg(void)
 
 static inline unsigned char read_status_register(void)
 {
-	return (inb(sony_cd_status_reg));
+	return inb(sony_cd_status_reg);
 }
 
 static inline unsigned char read_result_register(void)
 {
-	return (inb(sony_cd_result_reg));
+	return inb(sony_cd_result_reg);
 }
 
 static inline unsigned char read_data_register(void)
 {
-	return (inb(sony_cd_read_reg));
+	return inb(sony_cd_read_reg);
 }
 
 static inline void write_param(unsigned char param)
@@ -527,15 +538,17 @@ static irqreturn_t cdu31a_interrupt(int 
 		/* If something was waiting, wake it up now. */
 		if (waitqueue_active(&cdu31a_irq_wait)) {
 			disable_interrupts();
-			wake_up(&cdu31a_irq_wait);
+			irq_flag = 1;
+			wake_up_interruptible(&cdu31a_irq_wait);
 		}
 	} else if (waitqueue_active(&cdu31a_irq_wait)) {
 		disable_interrupts();
-		wake_up(&cdu31a_irq_wait);
+		irq_flag = 1;
+		wake_up_interruptible(&cdu31a_irq_wait);
 	} else {
 		disable_interrupts();
-		printk
-		    ("CDU31A: Got an interrupt but nothing was waiting\n");
+		printk(KERN_NOTICE PFX
+				"Got an interrupt but nothing was waiting\n");
 	}
 	return IRQ_HANDLED;
 }
@@ -610,8 +623,8 @@ static void set_drive_params(int want_do
 	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
 		       params, 2, res_reg, &res_size);
 	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-		printk("  Unable to set spin-down time: 0x%2.2x\n",
-		       res_reg[1]);
+		printk(KERN_NOTICE PFX
+			"Unable to set spin-down time: 0x%2.2x\n", res_reg[1]);
 	}
 
 	params[0] = SONY_SD_MECH_CONTROL;
@@ -627,8 +640,8 @@ static void set_drive_params(int want_do
 	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
 		       params, 2, res_reg, &res_size);
 	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-		printk("  Unable to set mechanical parameters: 0x%2.2x\n",
-		       res_reg[1]);
+		printk(KERN_NOTICE PFX "Unable to set mechanical "
+				"parameters: 0x%2.2x\n", res_reg[1]);
 	}
 }
 
@@ -643,7 +656,10 @@ static int scd_select_speed(struct cdrom
 	else
 		sony_speed = speed - 1;
 
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	set_drive_params(sony_speed);
+	up(&sony_sem);
 	return 0;
 }
 
@@ -658,7 +674,10 @@ static int scd_lock_door(struct cdrom_de
 	} else {
 		is_auto_eject = 0;
 	}
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	set_drive_params(sony_speed);
+	up(&sony_sem);
 	return 0;
 }
 
@@ -672,7 +691,7 @@ static void restart_on_error(void)
 	unsigned long retry_count;
 
 
-	printk("cdu31a: Resetting drive on error\n");
+	printk(KERN_NOTICE PFX "Resetting drive on error\n");
 	reset_drive();
 	retry_count = jiffies + SONY_RESET_TIMEOUT;
 	while (time_before(jiffies, retry_count) && (!is_attention())) {
@@ -681,7 +700,7 @@ static void restart_on_error(void)
 	set_drive_params(sony_speed);
 	do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
 	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-		printk("cdu31a: Unable to spin up drive: 0x%2.2x\n",
+		printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n",
 		       res_reg[1]);
 	}
 
@@ -741,9 +760,7 @@ get_result(unsigned char *result_buffer,
 		while (handle_sony_cd_attention());
 	}
 	if (is_busy() || (!(is_result_ready()))) {
-#if DEBUG
-		printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+		pr_debug(PFX "timeout out %d\n", __LINE__);
 		result_buffer[0] = 0x20;
 		result_buffer[1] = SONY_TIMEOUT_OP_ERR;
 		*result_size = 2;
@@ -794,10 +811,8 @@ get_result(unsigned char *result_buffer,
 					retry_count--;
 				}
 				if (!is_result_ready()) {
-#if DEBUG
-					printk("CDU31A timeout out %d\n",
+					pr_debug(PFX "timeout out %d\n",
 					       __LINE__);
-#endif
 					result_buffer[0] = 0x20;
 					result_buffer[1] =
 					    SONY_TIMEOUT_OP_ERR;
@@ -823,10 +838,8 @@ get_result(unsigned char *result_buffer,
 					retry_count--;
 				}
 				if (!is_result_ready()) {
-#if DEBUG
-					printk("CDU31A timeout out %d\n",
+					pr_debug(PFX "timeout out %d\n",
 					       __LINE__);
-#endif
 					result_buffer[0] = 0x20;
 					result_buffer[1] =
 					    SONY_TIMEOUT_OP_ERR;
@@ -857,38 +870,12 @@ do_sony_cd_cmd(unsigned char cmd,
 	       unsigned char *result_buffer, unsigned int *result_size)
 {
 	unsigned long retry_count;
-	int num_retries;
-	int recursive_call;
-	unsigned long flags;
+	int num_retries = 0;
 
-
-	save_flags(flags);
-	cli();
-	if (current != has_cd_task) {	/* Allow recursive calls to this routine */
-		while (sony_inuse) {
-			interruptible_sleep_on(&sony_wait);
-			if (signal_pending(current)) {
-				result_buffer[0] = 0x20;
-				result_buffer[1] = SONY_SIGNAL_OP_ERR;
-				*result_size = 2;
-				restore_flags(flags);
-				return;
-			}
-		}
-		sony_inuse = 1;
-		has_cd_task = current;
-		recursive_call = 0;
-	} else {
-		recursive_call = 1;
-	}
-
-	num_retries = 0;
 retry_cd_operation:
 
 	while (handle_sony_cd_attention());
 
-	sti();
-
 	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
 	while (time_before(jiffies, retry_count) && (is_busy())) {
 		sony_sleep();
@@ -896,9 +883,7 @@ retry_cd_operation:
 		while (handle_sony_cd_attention());
 	}
 	if (is_busy()) {
-#if DEBUG
-		printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+		pr_debug(PFX "timeout out %d\n", __LINE__);
 		result_buffer[0] = 0x20;
 		result_buffer[1] = SONY_TIMEOUT_OP_ERR;
 		*result_size = 2;
@@ -918,14 +903,6 @@ retry_cd_operation:
 		msleep(100);
 		goto retry_cd_operation;
 	}
-
-	if (!recursive_call) {
-		has_cd_task = NULL;
-		sony_inuse = 0;
-		wake_up_interruptible(&sony_wait);
-	}
-
-	restore_flags(flags);
 }
 
 
@@ -945,21 +922,18 @@ static int handle_sony_cd_attention(void
 	volatile int val;
 
 
-#if 0*DEBUG
-	printk("Entering handle_sony_cd_attention\n");
+#if 0
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 #endif
 	if (is_attention()) {
 		if (num_consecutive_attentions >
 		    CDU31A_MAX_CONSECUTIVE_ATTENTIONS) {
-			printk
-			    ("cdu31a: Too many consecutive attentions: %d\n",
-			     num_consecutive_attentions);
+			printk(KERN_NOTICE PFX "Too many consecutive "
+				"attentions: %d\n", num_consecutive_attentions);
 			num_consecutive_attentions = 0;
-#if DEBUG
-			printk("Leaving handle_sony_cd_attention at %d\n",
+			pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__,
 			       __LINE__);
-#endif
-			return (0);
+			return 0;
 		}
 
 		clear_attention();
@@ -999,11 +973,8 @@ static int handle_sony_cd_attention(void
 		}
 
 		num_consecutive_attentions++;
-#if DEBUG
-		printk("Leaving handle_sony_cd_attention at %d\n",
-		       __LINE__);
-#endif
-		return (1);
+		pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+		return 1;
 	} else if (abort_read_started) {
 		while (is_result_reg_not_empty()) {
 			val = read_result_register();
@@ -1015,18 +986,15 @@ static int handle_sony_cd_attention(void
 			val = read_data_register();
 		}
 		abort_read_started = 0;
-#if DEBUG
-		printk("Leaving handle_sony_cd_attention at %d\n",
-		       __LINE__);
-#endif
-		return (1);
+		pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+		return 1;
 	}
 
 	num_consecutive_attentions = 0;
-#if 0*DEBUG
-	printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);
+#if 0
+	pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
 #endif
-	return (0);
+	return 0;
 }
 
 
@@ -1038,14 +1006,14 @@ static inline unsigned int int_to_bcd(un
 
 	retval = (val / 10) << 4;
 	retval = retval | val % 10;
-	return (retval);
+	return retval;
 }
 
 
 /* Convert from BCD to an integer from 0-99 */
 static unsigned int bcd_to_int(unsigned int bcd)
 {
-	return ((((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f));
+	return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f);
 }
 
 
@@ -1105,9 +1073,7 @@ start_request(unsigned int sector, unsig
 	unsigned long retry_count;
 
 
-#if DEBUG
-	printk("Entering start_request\n");
-#endif
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 	log_to_msf(sector, params);
 	size_to_buf(nsect, &params[3]);
 
@@ -1125,11 +1091,10 @@ start_request(unsigned int sector, unsig
 	}
 
 	if (is_busy()) {
-		printk("CDU31A: Timeout while waiting to issue command\n");
-#if DEBUG
-		printk("Leaving start_request at %d\n", __LINE__);
-#endif
-		return (1);
+		printk(KERN_NOTICE PFX "Timeout while waiting "
+				"to issue command\n");
+		pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+		return 1;
 	} else {
 		/* Issue the command */
 		clear_result_ready();
@@ -1140,14 +1105,10 @@ start_request(unsigned int sector, unsig
 
 		sony_blocks_left = nsect * 4;
 		sony_next_block = sector * 4;
-#if DEBUG
-		printk("Leaving start_request at %d\n", __LINE__);
-#endif
-		return (0);
+		pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+		return 0;
 	}
-#if DEBUG
-	printk("Leaving start_request at %d\n", __LINE__);
-#endif
+	pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
 }
 
 /* Abort a pending read operation.  Clear all the drive status variables. */
@@ -1160,7 +1121,7 @@ static void abort_read(void)
 
 	do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size);
 	if ((result_reg[0] & 0xf0) == 0x20) {
-		printk("CDU31A: Error aborting read, %s error\n",
+		printk(KERN_ERR PFX "Aborting read, %s error\n",
 		       translate_error(result_reg[1]));
 	}
 
@@ -1181,15 +1142,9 @@ static void abort_read(void)
    pending read operation. */
 static void handle_abort_timeout(unsigned long data)
 {
-	unsigned long flags;
-
-#if DEBUG
-	printk("Entering handle_abort_timeout\n");
-#endif
-	save_flags(flags);
-	cli();
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 	/* If it is in use, ignore it. */
-	if (!sony_inuse) {
+	if (down_trylock(&sony_sem) == 0) {
 		/* We can't use abort_read(), because it will sleep
 		   or schedule in the timer interrupt.  Just start
 		   the operation, finish it on the next access to
@@ -1200,20 +1155,16 @@ static void handle_abort_timeout(unsigne
 
 		sony_blocks_left = 0;
 		abort_read_started = 1;
+		up(&sony_sem);
 	}
-	restore_flags(flags);
-#if DEBUG
-	printk("Leaving handle_abort_timeout\n");
-#endif
+	pr_debug(PFX "Leaving %s\n", __FUNCTION__);
 }
 
 /* Actually get one sector of data from the drive. */
 static void
 input_data_sector(char *buffer)
 {
-#if DEBUG
-	printk("Entering input_data_sector\n");
-#endif
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 
 	/* If an XA disk on a CDU31A, skip the first 12 bytes of data from
 	   the disk.  The real data is after that. We can use audio_buffer. */
@@ -1229,9 +1180,7 @@ input_data_sector(char *buffer)
 	if (sony_xa_mode)
 		insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL);
 
-#if DEBUG
-	printk("Leaving input_data_sector\n");
-#endif
+	pr_debug(PFX "Leaving %s\n", __FUNCTION__);
 }
 
 /* read data from the drive.  Note the nsect must be <= 4. */
@@ -1243,9 +1192,7 @@ read_data_block(char *buffer,
 {
 	unsigned long retry_count;
 
-#if DEBUG
-	printk("Entering read_data_block\n");
-#endif
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 
 	res_reg[0] = 0;
 	res_reg[1] = 0;
@@ -1262,18 +1209,15 @@ read_data_block(char *buffer,
 		if (is_result_ready()) {
 			get_result(res_reg, res_size);
 			if ((res_reg[0] & 0xf0) != 0x20) {
-				printk
-				    ("CDU31A: Got result that should have been error: %d\n",
-				     res_reg[0]);
+				printk(KERN_NOTICE PFX "Got result that should"
+					" have been error: %d\n", res_reg[0]);
 				res_reg[0] = 0x20;
 				res_reg[1] = SONY_BAD_DATA_ERR;
 				*res_size = 2;
 			}
 			abort_read();
 		} else {
-#if DEBUG
-			printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+			pr_debug(PFX "timeout out %d\n", __LINE__);
 			res_reg[0] = 0x20;
 			res_reg[1] = SONY_TIMEOUT_OP_ERR;
 			*res_size = 2;
@@ -1294,9 +1238,7 @@ read_data_block(char *buffer,
 		}
 
 		if (!is_result_ready()) {
-#if DEBUG
-			printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+			pr_debug(PFX "timeout out %d\n", __LINE__);
 			res_reg[0] = 0x20;
 			res_reg[1] = SONY_TIMEOUT_OP_ERR;
 			*res_size = 2;
@@ -1315,9 +1257,8 @@ read_data_block(char *buffer,
 					SONY_RECOV_LECC_ERR_BLK_STAT)) {
 					/* nothing here */
 				} else {
-					printk
-					    ("CDU31A: Data block error: 0x%x\n",
-					     res_reg[0]);
+					printk(KERN_ERR PFX "Data block "
+						"error: 0x%x\n", res_reg[0]);
 					res_reg[0] = 0x20;
 					res_reg[1] = SONY_BAD_DATA_ERR;
 					*res_size = 2;
@@ -1330,9 +1271,8 @@ read_data_block(char *buffer,
 			} else if ((res_reg[0] & 0xf0) != 0x20) {
 				/* The drive gave me bad status, I don't know what to do.
 				   Reset the driver and return an error. */
-				printk
-				    ("CDU31A: Invalid block status: 0x%x\n",
-				     res_reg[0]);
+				printk(KERN_ERR PFX "Invalid block "
+					"status: 0x%x\n", res_reg[0]);
 				restart_on_error();
 				res_reg[0] = 0x20;
 				res_reg[1] = SONY_BAD_DATA_ERR;
@@ -1340,9 +1280,7 @@ read_data_block(char *buffer,
 			}
 		}
 	}
-#if DEBUG
-	printk("Leaving read_data_block at %d\n", __LINE__);
-#endif
+	pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
 }
 
 
@@ -1359,32 +1297,14 @@ static void do_cdu31a_request(request_qu
 	int block, nblock, num_retries;
 	unsigned char res_reg[12];
 	unsigned int res_size;
-	unsigned long flags;
 
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 
-#if DEBUG
-	printk("Entering do_cdu31a_request\n");
-#endif
-
-	/* 
-	 * Make sure no one else is using the driver; wait for them
-	 * to finish if it is so.
-	 */
-	save_flags(flags);
-	cli();
-	while (sony_inuse) {
-		interruptible_sleep_on(&sony_wait);
-		if (signal_pending(current)) {
-			restore_flags(flags);
-#if DEBUG
-			printk("Leaving do_cdu31a_request at %d\n",
-			       __LINE__);
-#endif
-			return;
-		}
+	spin_unlock_irq(q->queue_lock);
+	if (down_interruptible(&sony_sem)) {
+		spin_lock_irq(q->queue_lock);
+		return;
 	}
-	sony_inuse = 1;
-	has_cd_task = current;
 
 	/* Get drive status before doing anything. */
 	while (handle_sony_cd_attention());
@@ -1392,10 +1312,6 @@ static void do_cdu31a_request(request_qu
 	/* Make sure we have a valid TOC. */
 	sony_get_toc();
 
-	/*
-	 * jens: driver has lots of races
-	 */
-	spin_unlock_irq(q->queue_lock);
 
 	/* Make sure the timer is cancelled. */
 	del_timer(&cdu31a_abort_timer);
@@ -1414,12 +1330,10 @@ static void do_cdu31a_request(request_qu
 
 		block = req->sector;
 		nblock = req->nr_sectors;
-#if DEBUG
-		printk("CDU31A: request at block %d, length %d blocks\n",
+		pr_debug(PFX "request at block %d, length %d blocks\n",
 			block, nblock);
-#endif
 		if (!sony_toc_read) {
-			printk("CDU31A: TOC not read\n");
+			printk(KERN_NOTICE PFX "TOC not read\n");
 			end_request(req, 0);
 			continue;
 		}
@@ -1431,14 +1345,13 @@ static void do_cdu31a_request(request_qu
 			end_request(req, 0);
 			continue;
 		}
-		if (rq_data_dir(req) != READ)
-			panic("CDU31A: Unknown cmd");
+
 		/*
 		 * If the block address is invalid or the request goes beyond the end of
 		 * the media, return an error.
 		 */
 		if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) {
-			printk("CDU31A: Request past end of media\n");
+			printk(KERN_NOTICE PFX "Request past end of media\n");
 			end_request(req, 0);
 			continue;
 		}
@@ -1451,7 +1364,7 @@ static void do_cdu31a_request(request_qu
 		while (handle_sony_cd_attention());
 
 		if (!sony_toc_read) {
-			printk("CDU31A: TOC not read\n");
+			printk(KERN_NOTICE PFX "TOC not read\n");
 			end_request(req, 0);
 			continue;
 		}
@@ -1468,18 +1381,16 @@ static void do_cdu31a_request(request_qu
 		   the driver, abort the current operation and start a
 		   new one. */
 		else if (block != sony_next_block) {
-#if DEBUG
-			printk("CDU31A Warning: Read for block %d, expected %d\n",
+			pr_debug(PFX "Read for block %d, expected %d\n",
 				 block, sony_next_block);
-#endif
 			abort_read();
 			if (!sony_toc_read) {
-				printk("CDU31A: TOC not read\n");
+				printk(KERN_NOTICE PFX "TOC not read\n");
 				end_request(req, 0);
 				continue;
 			}
 			if (start_request(block / 4, nblock / 4)) {
-				printk("CDU31a: start request failed\n");
+				printk(KERN_NOTICE PFX "start request failed\n");
 				end_request(req, 0);
 				continue;
 			}
@@ -1507,13 +1418,12 @@ static void do_cdu31a_request(request_qu
 			do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
 					&res_size);
 		} else {
-			printk("CDU31A: %s error for block %d, nblock %d\n",
+			printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n",
 				 translate_error(res_reg[1]), block, nblock);
 		}
 		goto try_read_again;
 	}
       end_do_cdu31a_request:
-	spin_lock_irq(q->queue_lock);
 #if 0
 	/* After finished, cancel any pending operations. */
 	abort_read();
@@ -1524,13 +1434,9 @@ static void do_cdu31a_request(request_qu
 	add_timer(&cdu31a_abort_timer);
 #endif
 
-	has_cd_task = NULL;
-	sony_inuse = 0;
-	wake_up_interruptible(&sony_wait);
-	restore_flags(flags);
-#if DEBUG
-	printk("Leaving do_cdu31a_request at %d\n", __LINE__);
-#endif
+	up(&sony_sem);
+	spin_lock_irq(q->queue_lock);
+	pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
 }
 
 
@@ -1549,9 +1455,7 @@ static void sony_get_toc(void)
 	int mint = 99;
 	int maxt = 0;
 
-#if DEBUG
-	printk("Entering sony_get_toc\n");
-#endif
+	pr_debug(PFX "Entering %s\n", __FUNCTION__);
 
 	num_spin_ups = 0;
 	if (!sony_toc_read) {
@@ -1602,16 +1506,12 @@ static void sony_get_toc(void)
 /* This seems to slow things down enough to make it work.  This
  * appears to be a problem in do_sony_cd_cmd.  This printk seems 
  * to address the symptoms...  -Erik */
-#if DEBUG
-			printk("cdu31a: Trying session %d\n", session);
-#endif
+			pr_debug(PFX "Trying session %d\n", session);
 			parms[0] = session;
 			do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD,
 				       parms, 1, res_reg, &res_size);
 
-#if DEBUG
-			printk("%2.2x %2.2x\n", res_reg[0], res_reg[1]);
-#endif
+			pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]);
 
 			if ((res_size < 2)
 			    || ((res_reg[0] & 0xf0) == 0x20)) {
@@ -1621,9 +1521,7 @@ static void sony_get_toc(void)
 					    ("Yikes! Couldn't read any sessions!");
 				break;
 			}
-#if DEBUG
-			printk("Reading session %d\n", session);
-#endif
+			pr_debug(PFX "Reading session %d\n", session);
 
 			parms[0] = session;
 			do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
@@ -1634,8 +1532,8 @@ static void sony_get_toc(void)
 			if ((res_size < 2)
 			    || ((single_toc.exec_status[0] & 0xf0) ==
 				0x20)) {
-				printk
-				    ("cdu31a: Error reading session %d: %x %s\n",
+				printk(KERN_ERR PFX "Error reading "
+						"session %d: %x %s\n",
 				     session, single_toc.exec_status[0],
 				     translate_error(single_toc.
 						     exec_status[1]));
@@ -1643,29 +1541,27 @@ static void sony_get_toc(void)
 				   set. */
 				return;
 			}
-#if DEBUG
-			printk
-			    ("add0 %01x, con0 %01x, poi0 %02x, 1st trk %d, dsktyp %x, dum0 %x\n",
+			pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, "
+					"1st trk %d, dsktyp %x, dum0 %x\n",
 			     single_toc.address0, single_toc.control0,
 			     single_toc.point0,
 			     bcd_to_int(single_toc.first_track_num),
 			     single_toc.disk_type, single_toc.dummy0);
-			printk
-			    ("add1 %01x, con1 %01x, poi1 %02x, lst trk %d, dummy1 %x, dum2 %x\n",
+			pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, "
+					"lst trk %d, dummy1 %x, dum2 %x\n",
 			     single_toc.address1, single_toc.control1,
 			     single_toc.point1,
 			     bcd_to_int(single_toc.last_track_num),
 			     single_toc.dummy1, single_toc.dummy2);
-			printk
-			    ("add2 %01x, con2 %01x, poi2 %02x leadout start min %d, sec %d, frame %d\n",
+			pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x "
+				"leadout start min %d, sec %d, frame %d\n",
 			     single_toc.address2, single_toc.control2,
 			     single_toc.point2,
 			     bcd_to_int(single_toc.lead_out_start_msf[0]),
 			     bcd_to_int(single_toc.lead_out_start_msf[1]),
 			     bcd_to_int(single_toc.lead_out_start_msf[2]));
 			if (res_size > 18 && single_toc.pointb0 > 0xaf)
-				printk
-				    ("addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
+				pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
 				     "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n",
 				     single_toc.addressb0,
 				     single_toc.controlb0,
@@ -1690,8 +1586,7 @@ static void sony_get_toc(void)
 						max_start_outer_leadout_msf
 						[2]));
 			if (res_size > 27 && single_toc.pointb1 > 0xaf)
-				printk
-				    ("addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
+				pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
 				     single_toc.addressb1,
 				     single_toc.controlb1,
 				     single_toc.pointb1,
@@ -1703,8 +1598,7 @@ static void sony_get_toc(void)
 				     single_toc.num_skip_track_assignments,
 				     single_toc.dummyb0_2);
 			if (res_size > 36 && single_toc.pointb2 > 0xaf)
-				printk
-				    ("addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+				pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
 				     single_toc.addressb2,
 				     single_toc.controlb2,
 				     single_toc.pointb2,
@@ -1716,8 +1610,7 @@ static void sony_get_toc(void)
 				     single_toc.tracksb2[5],
 				     single_toc.tracksb2[6]);
 			if (res_size > 45 && single_toc.pointb3 > 0xaf)
-				printk
-				    ("addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+				pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
 				     single_toc.addressb3,
 				     single_toc.controlb3,
 				     single_toc.pointb3,
@@ -1729,8 +1622,7 @@ static void sony_get_toc(void)
 				     single_toc.tracksb3[5],
 				     single_toc.tracksb3[6]);
 			if (res_size > 54 && single_toc.pointb4 > 0xaf)
-				printk
-				    ("addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+				pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
 				     single_toc.addressb4,
 				     single_toc.controlb4,
 				     single_toc.pointb4,
@@ -1742,8 +1634,7 @@ static void sony_get_toc(void)
 				     single_toc.tracksb4[5],
 				     single_toc.tracksb4[6]);
 			if (res_size > 63 && single_toc.pointc0 > 0xaf)
-				printk
-				    ("addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+				pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
 				     single_toc.addressc0,
 				     single_toc.controlc0,
 				     single_toc.pointc0,
@@ -1754,7 +1645,6 @@ static void sony_get_toc(void)
 				     single_toc.dummyc0[4],
 				     single_toc.dummyc0[5],
 				     single_toc.dummyc0[6]);
-#endif
 #undef DEBUG
 #define DEBUG 0
 
@@ -1823,8 +1713,8 @@ static void sony_get_toc(void)
 				res_size += 9;
 			}
 #if DEBUG
-			printk
-			    ("start track lba %u,  leadout start lba %u\n",
+			printk(PRINT_INFO PFX "start track lba %u,  "
+					"leadout start lba %u\n",
 			     single_toc.start_track_lba,
 			     single_toc.lead_out_start_lba);
 			{
@@ -1836,8 +1726,7 @@ static void sony_get_toc(void)
 				     -
 				     bcd_to_int(single_toc.
 						first_track_num); i++) {
-					printk
-					    ("trk %02d: add 0x%01x, con 0x%01x,  track %02d, start min %02d, sec %02d, frame %02d\n",
+					printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x,  track %02d, start min %02d, sec %02d, frame %02d\n",
 					     i,
 					     single_toc.tracks[i].address,
 					     single_toc.tracks[i].control,
@@ -1870,8 +1759,8 @@ static void sony_get_toc(void)
 							       tracks[i].
 							       track);
 				}
-				printk
-				    ("min track number %d,   max track number %d\n",
+				printk(KERN_INFO PFX "min track number %d,  "
+						"max track number %d\n",
 				     mint, maxt);
 			}
 #endif
@@ -1976,8 +1865,8 @@ static void sony_get_toc(void)
 
 			/* Let's not get carried away... */
 			if (session > 40) {
-				printk("cdu31a: too many sessions: %d\n",
-				       session);
+				printk(KERN_NOTICE PFX "too many sessions: "
+						"%d\n", session);
 				break;
 			}
 			session++;
@@ -1995,17 +1884,13 @@ static void sony_get_toc(void)
 		    sony_toc.lead_out_start_msf[2];
 
 		sony_toc_read = 1;
-#undef DEBUG
-#if DEBUG
-		printk
-		    ("Disk session %d, start track: %d, stop track: %d\n",
+
+		pr_debug(PFX "Disk session %d, start track: %d, "
+				"stop track: %d\n",
 		     session, single_toc.start_track_lba,
 		     single_toc.lead_out_start_lba);
-#endif
 	}
-#if DEBUG
-	printk("Leaving sony_get_toc\n");
-#endif
+	pr_debug(PFX "Leaving %s\n", __FUNCTION__);
 }
 
 
@@ -2019,8 +1904,12 @@ static int scd_get_last_session(struct c
 	if (ms_info == NULL)
 		return 1;
 
-	if (!sony_toc_read)
+	if (!sony_toc_read) {
+		if (down_interruptible(&sony_sem))
+			return -ERESTARTSYS;
 		sony_get_toc();
+		up(&sony_sem);
+	}
 
 	ms_info->addr_format = CDROM_LBA;
 	ms_info->addr.lba = sony_toc.start_track_lba;
@@ -2060,7 +1949,7 @@ static int read_subcode(void)
 		       0, (unsigned char *) &last_sony_subcode, &res_size);
 	if ((res_size < 2)
 	    || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) {
-		printk("Sony CDROM error %s (read_subcode)\n",
+		printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n",
 		       translate_error(last_sony_subcode.exec_status[1]));
 		return -EIO;
 	}
@@ -2098,8 +1987,11 @@ scd_get_mcn(struct cdrom_device_info *cd
 	unsigned int res_size;
 
 	memset(mcn->medium_catalog_number, 0, 14);
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD,
 		       NULL, 0, resbuffer, &res_size);
+	up(&sony_sem);
 	if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20));
 	else {
 		/* packed bcd to single ASCII digits */
@@ -2228,8 +2120,8 @@ read_audio_data(char *buffer, unsigned c
 			}
 			/* Invalid data from the drive.  Shut down the operation. */
 			else if ((res_reg[0] & 0xf0) != 0x20) {
-				printk
-				    ("CDU31A: Got result that should have been error: %d\n",
+				printk(KERN_WARNING PFX "Got result that "
+						"should have been error: %d\n",
 				     res_reg[0]);
 				res_reg[0] = 0x20;
 				res_reg[1] = SONY_BAD_DATA_ERR;
@@ -2237,9 +2129,7 @@ read_audio_data(char *buffer, unsigned c
 			}
 			abort_read();
 		} else {
-#if DEBUG
-			printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+			pr_debug(PFX "timeout out %d\n", __LINE__);
 			res_reg[0] = 0x20;
 			res_reg[1] = SONY_TIMEOUT_OP_ERR;
 			*res_size = 2;
@@ -2269,10 +2159,7 @@ read_audio_data(char *buffer, unsigned c
 			}
 
 			if (!is_result_ready()) {
-#if DEBUG
-				printk("CDU31A timeout out %d\n",
-				       __LINE__);
-#endif
+				pr_debug(PFX "timeout out %d\n", __LINE__);
 				res_reg[0] = 0x20;
 				res_reg[1] = SONY_TIMEOUT_OP_ERR;
 				*res_size = 2;
@@ -2290,7 +2177,7 @@ read_audio_data(char *buffer, unsigned c
 			    || (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) {
 				/* Ok, nothing to do. */
 			} else {
-				printk("CDU31A: Data block error: 0x%x\n",
+				printk(KERN_ERR PFX "Data block error: 0x%x\n",
 				       res_reg[0]);
 				res_reg[0] = 0x20;
 				res_reg[1] = SONY_BAD_DATA_ERR;
@@ -2299,7 +2186,7 @@ read_audio_data(char *buffer, unsigned c
 		} else if ((res_reg[0] & 0xf0) != 0x20) {
 			/* The drive gave me bad status, I don't know what to do.
 			   Reset the driver and return an error. */
-			printk("CDU31A: Invalid block status: 0x%x\n",
+			printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n",
 			       res_reg[0]);
 			restart_on_error();
 			res_reg[0] = 0x20;
@@ -2318,28 +2205,11 @@ static int read_audio(struct cdrom_read_
 	unsigned char res_reg[12];
 	unsigned int res_size;
 	unsigned int cframe;
-	unsigned long flags;
 
-	/* 
-	 * Make sure no one else is using the driver; wait for them
-	 * to finish if it is so.
-	 */
-	save_flags(flags);
-	cli();
-	while (sony_inuse) {
-		interruptible_sleep_on(&sony_wait);
-		if (signal_pending(current)) {
-			restore_flags(flags);
-			return -EAGAIN;
-		}
-	}
-	sony_inuse = 1;
-	has_cd_task = current;
-	restore_flags(flags);
-
-	if (!sony_spun_up) {
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
+	if (!sony_spun_up)
 		scd_spinup();
-	}
 
 	/* Set the drive to do raw operations. */
 	params[0] = SONY_SD_DECODE_PARAM;
@@ -2347,9 +2217,10 @@ static int read_audio(struct cdrom_read_
 	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
 		       params, 2, res_reg, &res_size);
 	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-		printk("CDU31A: Unable to set decode params: 0x%2.2x\n",
+		printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n",
 		       res_reg[1]);
-		return -EIO;
+		retval = -EIO;
+		goto out_up;
 	}
 
 	/* From here down, we have to goto exit_read_audio instead of returning
@@ -2368,8 +2239,8 @@ static int read_audio(struct cdrom_read_
 		read_audio_data(audio_buffer, res_reg, &res_size);
 		if ((res_reg[0] & 0xf0) == 0x20) {
 			if (res_reg[1] == SONY_BAD_DATA_ERR) {
-				printk
-				    ("CDU31A: Data error on audio sector %d\n",
+				printk(KERN_ERR PFX "Data error on audio "
+						"sector %d\n",
 				     ra->addr.lba + cframe);
 			} else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) {
 				/* Illegal track type, change track types and start over. */
@@ -2384,8 +2255,8 @@ static int read_audio(struct cdrom_read_
 					       2, res_reg, &res_size);
 				if ((res_size < 2)
 				    || ((res_reg[0] & 0xf0) == 0x20)) {
-					printk
-					    ("CDU31A: Unable to set decode params: 0x%2.2x\n",
+					printk(KERN_ERR PFX "Unable to set "
+						"decode params: 0x%2.2x\n",
 					     res_reg[1]);
 					retval = -EIO;
 					goto exit_read_audio;
@@ -2407,13 +2278,12 @@ static int read_audio(struct cdrom_read_
 				if ((res_reg[0] & 0xf0) == 0x20) {
 					if (res_reg[1] ==
 					    SONY_BAD_DATA_ERR) {
-						printk
-						    ("CDU31A: Data error on audio sector %d\n",
+						printk(KERN_ERR PFX "Data error"
+							" on audio sector %d\n",
 						     ra->addr.lba +
 						     cframe);
 					} else {
-						printk
-						    ("CDU31A: Error reading audio data on sector %d: %s\n",
+						printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n",
 						     ra->addr.lba + cframe,
 						     translate_error
 						     (res_reg[1]));
@@ -2429,8 +2299,8 @@ static int read_audio(struct cdrom_read_
 					goto exit_read_audio;
 				}
 			} else {
-				printk
-				    ("CDU31A: Error reading audio data on sector %d: %s\n",
+				printk(KERN_ERR PFX "Error reading audio "
+						"data on sector %d: %s\n",
 				     ra->addr.lba + cframe,
 				     translate_error(res_reg[1]));
 				retval = -EIO;
@@ -2448,7 +2318,7 @@ static int read_audio(struct cdrom_read_
 
 	get_result(res_reg, &res_size);
 	if ((res_reg[0] & 0xf0) == 0x20) {
-		printk("CDU31A: Error return from audio read: %s\n",
+		printk(KERN_ERR PFX "Error return from audio read: %s\n",
 		       translate_error(res_reg[1]));
 		retval = -EIO;
 		goto exit_read_audio;
@@ -2466,16 +2336,15 @@ static int read_audio(struct cdrom_read_
 	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
 		       params, 2, res_reg, &res_size);
 	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-		printk("CDU31A: Unable to reset decode params: 0x%2.2x\n",
+		printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n",
 		       res_reg[1]);
-		return -EIO;
+		retval = -EIO;
 	}
 
-	has_cd_task = NULL;
-	sony_inuse = 0;
-	wake_up_interruptible(&sony_wait);
+ out_up:
+	up(&sony_sem);
 
-	return (retval);
+	return retval;
 }
 
 static int
@@ -2488,7 +2357,7 @@ do_sony_cd_cmd_chk(const char *name,
 	do_sony_cd_cmd(cmd, params, num_params, result_buffer,
 		       result_size);
 	if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) {
-		printk("Sony CDROM error %s (CDROM%s)\n",
+		printk(KERN_ERR PFX "Error %s (CDROM%s)\n",
 		       translate_error(result_buffer[1]), name);
 		return -EIO;
 	}
@@ -2501,6 +2370,10 @@ do_sony_cd_cmd_chk(const char *name,
  */
 static int scd_tray_move(struct cdrom_device_info *cdi, int position)
 {
+	int retval;
+
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	if (position == 1 /* open tray */ ) {
 		unsigned char res_reg[12];
 		unsigned int res_size;
@@ -2511,13 +2384,15 @@ static int scd_tray_move(struct cdrom_de
 			       &res_size);
 
 		sony_audio_status = CDROM_AUDIO_INVALID;
-		return do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0,
+		retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0,
 					  res_reg, &res_size);
 	} else {
 		if (0 == scd_spinup())
 			sony_spun_up = 1;
-		return 0;
+		retval = 0;
 	}
+	up(&sony_sem);
+	return retval;
 }
 
 /*
@@ -2529,12 +2404,13 @@ static int scd_audio_ioctl(struct cdrom_
 	unsigned char res_reg[12];
 	unsigned int res_size;
 	unsigned char params[7];
-	int i;
-
+	int i, retval;
 
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	switch (cmd) {
 	case CDROMSTART:	/* Spin up the drive */
-		return do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL,
+		retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL,
 					  0, res_reg, &res_size);
 		break;
 
@@ -2547,28 +2423,33 @@ static int scd_audio_ioctl(struct cdrom_
 		 * already not spinning.
 		 */
 		sony_audio_status = CDROM_AUDIO_NO_STATUS;
-		return do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL,
+		retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL,
 					  0, res_reg, &res_size);
+		break;
 
 	case CDROMPAUSE:	/* Pause the drive */
 		if (do_sony_cd_cmd_chk
 		    ("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg,
-		     &res_size))
-			return -EIO;
+		     &res_size)) {
+			retval = -EIO;
+			break;
+		}
 		/* Get the current position and save it for resuming */
 		if (read_subcode() < 0) {
-			return -EIO;
+			retval = -EIO;
+			break;
 		}
 		cur_pos_msf[0] = last_sony_subcode.abs_msf[0];
 		cur_pos_msf[1] = last_sony_subcode.abs_msf[1];
 		cur_pos_msf[2] = last_sony_subcode.abs_msf[2];
 		sony_audio_status = CDROM_AUDIO_PAUSED;
-		return 0;
+		retval = 0;
 		break;
 
 	case CDROMRESUME:	/* Start the drive after being paused */
 		if (sony_audio_status != CDROM_AUDIO_PAUSED) {
-			return -EINVAL;
+			retval = -EINVAL;
+			break;
 		}
 
 		do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
@@ -2584,10 +2465,13 @@ static int scd_audio_ioctl(struct cdrom_
 		params[0] = 0x03;
 		if (do_sony_cd_cmd_chk
 		    ("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg,
-		     &res_size) < 0)
-			return -EIO;
+		     &res_size) < 0) {
+			retval = -EIO;
+			break;
+		}
 		sony_audio_status = CDROM_AUDIO_PLAY;
-		return 0;
+		retval = 0;
+		break;
 
 	case CDROMPLAYMSF:	/* Play starting at the given MSF address. */
 		do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
@@ -2601,15 +2485,18 @@ static int scd_audio_ioctl(struct cdrom_
 		params[0] = 0x03;
 		if (do_sony_cd_cmd_chk
 		    ("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7,
-		     res_reg, &res_size) < 0)
-			return -EIO;
+		     res_reg, &res_size) < 0) {
+			retval = -EIO;
+			break;
+		}
 
 		/* Save the final position for pauses and resumes */
 		final_pos_msf[0] = bcd_to_int(params[4]);
 		final_pos_msf[1] = bcd_to_int(params[5]);
 		final_pos_msf[2] = bcd_to_int(params[6]);
 		sony_audio_status = CDROM_AUDIO_PLAY;
-		return 0;
+		retval = 0;
+		break;
 
 	case CDROMREADTOCHDR:	/* Read the table of contents header */
 		{
@@ -2617,14 +2504,16 @@ static int scd_audio_ioctl(struct cdrom_
 
 			sony_get_toc();
 			if (!sony_toc_read) {
-				return -EIO;
+				retval = -EIO;
+				break;
 			}
 
 			hdr = (struct cdrom_tochdr *) arg;
 			hdr->cdth_trk0 = sony_toc.first_track_num;
 			hdr->cdth_trk1 = sony_toc.last_track_num;
 		}
-		return 0;
+		retval = 0;
+		break;
 
 	case CDROMREADTOCENTRY:	/* Read a given table of contents entry */
 		{
@@ -2634,14 +2523,16 @@ static int scd_audio_ioctl(struct cdrom_
 
 			sony_get_toc();
 			if (!sony_toc_read) {
-				return -EIO;
+				retval = -EIO;
+				break;
 			}
 
 			entry = (struct cdrom_tocentry *) arg;
 
 			track_idx = find_track(entry->cdte_track);
 			if (track_idx < 0) {
-				return -EINVAL;
+				retval = -EINVAL;
+				break;
 			}
 
 			entry->cdte_adr =
@@ -2662,7 +2553,7 @@ static int scd_audio_ioctl(struct cdrom_
 				    *(msf_val + 2);
 			}
 		}
-		return 0;
+		retval = 0;
 		break;
 
 	case CDROMPLAYTRKIND:	/* Play a track.  This currently ignores index. */
@@ -2672,18 +2563,21 @@ static int scd_audio_ioctl(struct cdrom_
 
 			sony_get_toc();
 			if (!sony_toc_read) {
-				return -EIO;
+				retval = -EIO;
+				break;
 			}
 
 			if ((ti->cdti_trk0 < sony_toc.first_track_num)
 			    || (ti->cdti_trk0 > sony_toc.last_track_num)
 			    || (ti->cdti_trk1 < ti->cdti_trk0)) {
-				return -EINVAL;
+				retval = -EINVAL;
+				break;
 			}
 
 			track_idx = find_track(ti->cdti_trk0);
 			if (track_idx < 0) {
-				return -EINVAL;
+				retval = -EINVAL;
+				break;
 			}
 			params[1] =
 			    int_to_bcd(sony_toc.tracks[track_idx].
@@ -2705,7 +2599,8 @@ static int scd_audio_ioctl(struct cdrom_
 				track_idx = find_track(ti->cdti_trk1 + 1);
 			}
 			if (track_idx < 0) {
-				return -EINVAL;
+				retval = -EINVAL;
+				break;
 			}
 			params[4] =
 			    int_to_bcd(sony_toc.tracks[track_idx].
@@ -2726,14 +2621,16 @@ static int scd_audio_ioctl(struct cdrom_
 
 			if ((res_size < 2)
 			    || ((res_reg[0] & 0xf0) == 0x20)) {
-				printk("Params: %x %x %x %x %x %x %x\n",
+				printk(KERN_ERR PFX
+					"Params: %x %x %x %x %x %x %x\n",
 				       params[0], params[1], params[2],
 				       params[3], params[4], params[5],
 				       params[6]);
-				printk
-				    ("Sony CDROM error %s (CDROMPLAYTRKIND)\n",
+				printk(KERN_ERR PFX
+					"Error %s (CDROMPLAYTRKIND)\n",
 				     translate_error(res_reg[1]));
-				return -EIO;
+				retval = -EIO;
+				break;
 			}
 
 			/* Save the final position for pauses and resumes */
@@ -2741,7 +2638,8 @@ static int scd_audio_ioctl(struct cdrom_
 			final_pos_msf[1] = bcd_to_int(params[5]);
 			final_pos_msf[2] = bcd_to_int(params[6]);
 			sony_audio_status = CDROM_AUDIO_PLAY;
-			return 0;
+			retval = 0;
+			break;
 		}
 
 	case CDROMVOLCTRL:	/* Volume control.  What volume does this change, anyway? */
@@ -2752,25 +2650,32 @@ static int scd_audio_ioctl(struct cdrom_
 			params[0] = SONY_SD_AUDIO_VOLUME;
 			params[1] = volctrl->channel0;
 			params[2] = volctrl->channel1;
-			return do_sony_cd_cmd_chk("VOLCTRL",
+			retval = do_sony_cd_cmd_chk("VOLCTRL",
 						  SONY_SET_DRIVE_PARAM_CMD,
 						  params, 3, res_reg,
 						  &res_size);
+			break;
 		}
 	case CDROMSUBCHNL:	/* Get subchannel info */
-		return sony_get_subchnl_info((struct cdrom_subchnl *) arg);
+		retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg);
+		break;
 
 	default:
-		return -EINVAL;
+		retval = -EINVAL;
+		break;
 	}
+	up(&sony_sem);
+	return retval;
 }
 
 static int scd_dev_ioctl(struct cdrom_device_info *cdi,
 			 unsigned int cmd, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
-	int i;
+	int retval;
 
+	if (down_interruptible(&sony_sem))
+		return -ERESTARTSYS;
 	switch (cmd) {
 	case CDROMREADAUDIO:	/* Read 2352 byte audio tracks and 2340 byte
 				   raw data tracks. */
@@ -2780,33 +2685,38 @@ static int scd_dev_ioctl(struct cdrom_de
 
 			sony_get_toc();
 			if (!sony_toc_read) {
-				return -EIO;
+				retval = -EIO;
+				break;
 			}
 
-			if (copy_from_user(&ra, argp, sizeof(ra)))
-				return -EFAULT;
+			if (copy_from_user(&ra, argp, sizeof(ra))) {
+				retval = -EFAULT;
+				break;
+			}
 
 			if (ra.nframes == 0) {
-				return 0;
+				retval = 0;
+				break;
 			}
 
-			i = verify_area(VERIFY_WRITE, ra.buf,
-					CD_FRAMESIZE_RAW * ra.nframes);
-			if (i < 0)
-				return i;
+			if (!access_ok(VERIFY_WRITE, ra.buf,
+					CD_FRAMESIZE_RAW * ra.nframes))
+				return -EFAULT;
 
 			if (ra.addr_format == CDROM_LBA) {
 				if ((ra.addr.lba >=
 				     sony_toc.lead_out_start_lba)
 				    || (ra.addr.lba + ra.nframes >=
 					sony_toc.lead_out_start_lba)) {
-					return -EINVAL;
+					retval = -EINVAL;
+					break;
 				}
 			} else if (ra.addr_format == CDROM_MSF) {
 				if ((ra.addr.msf.minute >= 75)
 				    || (ra.addr.msf.second >= 60)
 				    || (ra.addr.msf.frame >= 75)) {
-					return -EINVAL;
+					retval = -EINVAL;
+					break;
 				}
 
 				ra.addr.lba = ((ra.addr.msf.minute * 4500)
@@ -2816,7 +2726,8 @@ static int scd_dev_ioctl(struct cdrom_de
 				     sony_toc.lead_out_start_lba)
 				    || (ra.addr.lba + ra.nframes >=
 					sony_toc.lead_out_start_lba)) {
-					return -EINVAL;
+					retval = -EINVAL;
+					break;
 				}
 
 				/* I know, this can go negative on an unsigned.  However,
@@ -2824,17 +2735,21 @@ static int scd_dev_ioctl(struct cdrom_de
 				   so this should compensate and allow direct msf access. */
 				ra.addr.lba -= LOG_START_OFFSET;
 			} else {
-				return -EINVAL;
+				retval = -EINVAL;
+				break;
 			}
 
-			return (read_audio(&ra));
+			retval = read_audio(&ra);
+			break;
 		}
-		return 0;
+		retval = 0;
 		break;
 
 	default:
-		return -EINVAL;
+		retval = -EINVAL;
 	}
+	up(&sony_sem);
+	return retval;
 }
 
 static int scd_spinup(void)
@@ -2851,7 +2766,7 @@ static int scd_spinup(void)
 	/* The drive sometimes returns error 0.  I don't know why, but ignore
 	   it.  It seems to mean the drive has already done the operation. */
 	if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) {
-		printk("Sony CDROM %s error (scd_open, spin up)\n",
+		printk(KERN_ERR PFX "%s error (scd_open, spin up)\n",
 		       translate_error(res_reg[1]));
 		return 1;
 	}
@@ -2875,7 +2790,7 @@ static int scd_spinup(void)
 			goto respinup_on_open;
 		}
 
-		printk("Sony CDROM error %s (scd_open, read toc)\n",
+		printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n",
 		       translate_error(res_reg[1]));
 		do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg,
 			       &res_size);
@@ -2921,9 +2836,8 @@ static int scd_open(struct cdrom_device_
 				       params, 2, res_reg, &res_size);
 			if ((res_size < 2)
 			    || ((res_reg[0] & 0xf0) == 0x20)) {
-				printk
-				    ("CDU31A: Unable to set XA params: 0x%2.2x\n",
-				     res_reg[1]);
+				printk(KERN_WARNING PFX "Unable to set "
+					"XA params: 0x%2.2x\n", res_reg[1]);
 			}
 			sony_xa_mode = 1;
 		}
@@ -2935,9 +2849,8 @@ static int scd_open(struct cdrom_device_
 				       params, 2, res_reg, &res_size);
 			if ((res_size < 2)
 			    || ((res_reg[0] & 0xf0) == 0x20)) {
-				printk
-				    ("CDU31A: Unable to reset XA params: 0x%2.2x\n",
-				     res_reg[1]);
+				printk(KERN_WARNING PFX "Unable to reset "
+					"XA params: 0x%2.2x\n", res_reg[1]);
 			}
 			sony_xa_mode = 0;
 		}
@@ -3009,6 +2922,8 @@ static int scd_block_release(struct inod
 static int scd_block_ioctl(struct inode *inode, struct file *file,
 				unsigned cmd, unsigned long arg)
 {
+	int retval;
+
 	/* The eject and close commands should be handled by Uniform CD-ROM
 	 * driver - but I always got hard lockup instead of eject
 	 * until I put this here.
@@ -3016,12 +2931,15 @@ static int scd_block_ioctl(struct inode 
 	switch (cmd) {
 		case CDROMEJECT:
 			scd_lock_door(&scd_info, 0);
-			return scd_tray_move(&scd_info, 1);
+			retval = scd_tray_move(&scd_info, 1);
+			break;
 		case CDROMCLOSETRAY:
-			return scd_tray_move(&scd_info, 0);
+			retval = scd_tray_move(&scd_info, 0);
+			break;
 		default:
-			return cdrom_ioctl(file, &scd_info, inode, cmd, arg);
+			retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg);
 	}
+	return retval;
 }
 
 static int scd_block_media_changed(struct gendisk *disk)
@@ -3029,7 +2947,7 @@ static int scd_block_media_changed(struc
 	return cdrom_media_changed(&scd_info);
 }
 
-struct block_device_operations scd_bdops =
+static struct block_device_operations scd_bdops =
 {
 	.owner		= THIS_MODULE,
 	.open		= scd_block_open,
@@ -3114,7 +3032,6 @@ out_err:
 #ifndef MODULE
 /*
  * Set up base I/O and interrupts, called from main.c.
- 
  */
 
 static int __init cdu31a_setup(char *strings)
@@ -3133,7 +3050,7 @@ static int __init cdu31a_setup(char *str
 		if (strcmp(strings, "PAS") == 0) {
 			sony_pas_init = 1;
 		} else {
-			printk("CDU31A: Unknown interface type: %s\n",
+			printk(KERN_NOTICE PFX "Unknown interface type: %s\n",
 			       strings);
 		}
 	}
@@ -3225,9 +3142,8 @@ int __init cdu31a_init(void)
 		if (request_irq
 		    (cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT,
 		     "cdu31a", NULL)) {
-			printk
-			    ("Unable to grab IRQ%d for the CDU31A driver\n",
-			     cdu31a_irq);
+			printk(KERN_WARNING PFX "Unable to grab IRQ%d for "
+					"the CDU31A driver\n", cdu31a_irq);
 			cdu31a_irq = 0;
 		}
 	}
@@ -3262,8 +3178,8 @@ int __init cdu31a_init(void)
 		strcat(msg, buf);
 	}
 	strcat(msg, "\n");
-	printk("%s",msg);
-	
+	printk(KERN_INFO PFX "%s",msg);
+
 	cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock);
 	if (!cdu31a_queue)
 		goto errout0;
@@ -3280,18 +3196,18 @@ int __init cdu31a_init(void)
 	add_disk(disk);
 
 	disk_changed = 1;
-	return (0);
+	return 0;
 
 err:
 	blk_cleanup_queue(cdu31a_queue);
 errout0:
 	if (cdu31a_irq)
 		free_irq(cdu31a_irq, NULL);
-	printk("Unable to register CDU-31a with Uniform cdrom driver\n");
+	printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n");
 	put_disk(disk);
 errout1:
 	if (unregister_blkdev(MAJOR_NR, "cdu31a")) {
-		printk("Can't unregister block device for cdu31a\n");
+		printk(KERN_WARNING PFX "Can't unregister block device\n");
 	}
 errout2:
 	release_region(cdu31a_port, 4);
@@ -3300,17 +3216,17 @@ errout3:
 }
 
 
-void __exit cdu31a_exit(void)
+static void __exit cdu31a_exit(void)
 {
 	del_gendisk(scd_gendisk);
 	put_disk(scd_gendisk);
 	if (unregister_cdrom(&scd_info)) {
-		printk
-		    ("Can't unregister cdu31a from Uniform cdrom driver\n");
+		printk(KERN_WARNING PFX "Can't unregister from Uniform "
+				"cdrom driver\n");
 		return;
 	}
 	if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) {
-		printk("Can't unregister cdu31a\n");
+		printk(KERN_WARNING PFX "Can't unregister\n");
 		return;
 	}
 
@@ -3320,7 +3236,7 @@ void __exit cdu31a_exit(void)
 		free_irq(cdu31a_irq, NULL);
 
 	release_region(cdu31a_port, 4);
-	printk(KERN_INFO "cdu31a module released.\n");
+	printk(KERN_INFO PFX "module released.\n");
 }
 
 #ifdef MODULE
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
deleted file mode 100644
--- a/drivers/cdrom/mcd.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
-	linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
-
-	Copyright (C) 1992  Martin Harriss
-	Portions Copyright (C) 2001 Red Hat
-
-	martin@bdsi.com (no longer valid - where are you now, Martin?)
-
-	This program is free software; you can redistribute 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.
-
-	HISTORY
-
-	0.1	First attempt - internal use only
-	0.2	Cleaned up delays and use of timer - alpha release
-	0.3	Audio support added
-	0.3.1 Changes for mitsumi CRMC LU005S march version
-		   (stud11@cc4.kuleuven.ac.be)
-        0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
-		   (Jon Tombs <jon@robots.ox.ac.uk>)
-        0.3.3 Added more #defines and mcd_setup()
-   		   (Jon Tombs <jon@gtex02.us.es>)
-
-	October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
-	Braunschweig, Germany: rework to speed up data read operation.
-	Also enabled definition of irq and address from bootstrap, using the
-	environment.
-	November 93 added code for FX001 S,D (single & double speed).
-	February 94 added code for broken M 5/6 series of 16-bit single speed.
-
-
-        0.4   
-        Added support for loadable MODULEs, so mcd can now also be loaded by 
-        insmod and removed by rmmod during runtime.
-        Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
-
-	0.5
-	I added code for FX001 D to drop from double speed to single speed 
-	when encountering errors... this helps with some "problematic" CD's
-	that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
-	severely scratched, or possibly slightly warped! I have noticed that
-	the Mitsumi 2x/4x drives are just less tolerant and the firmware is 
-	not smart enough to drop speed,	so let's just kludge it with software!
-	****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
-	Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
-	even WORSE! ;)
-	** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
-	certain "large" CD's that have data on the outside edge in your 
-	DOS DRIVERS .... Accuracy counts... speed is secondary ;)
-	17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
-	07 July 1995 Modifications by Andrew J. Kroll
-
-	Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
-
-	Michael K. Johnson <johnsonm@redhat.com> added retries on open
-	for slow drives which take a while to recognize that they contain
-	a CD.
-
-	November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
-	March    1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
-	
-	November 1999 -- Make kernel-parameter implementation work with 2.3.x 
-	                 Removed init_module & cleanup_module in favor of 
-			 module_init & module_exit.
-			 Torben Mathiasen <tmm@image.dk>
-		
-	September 2001 - Reformatted and cleaned up the code
-			 Alan Cox <alan@redhat.com>			 
-*/
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/config.h>
-
-/* #define REALLY_SLOW_IO  */
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/current.h>
-#include <asm/uaccess.h>
-#include <linux/blkdev.h>
-
-#include "mcd.h"
-
-/* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
-static int mcdDouble;
-
-/* How many sectors to hold at 1x speed counter */
-static int mcd1xhold;
-
-/* Is the drive connected properly and responding?? */
-static int mcdPresent;
-static struct request_queue *mcd_queue;
-
-#define MAJOR_NR MITSUMI_CDROM_MAJOR
-#define QUEUE (mcd_queue)
-#define CURRENT elv_next_request(mcd_queue)
-
-#define QUICK_LOOP_DELAY udelay(45)	/* use udelay */
-#define QUICK_LOOP_COUNT 20
-
-static int current_valid(void)
-{
-        return CURRENT &&
-		CURRENT->cmd == READ &&
-		CURRENT->sector != -1;
-}
-
-#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
-#define MCD_BUF_SIZ 16
-static volatile int mcd_transfer_is_active;
-static char mcd_buf[2048 * MCD_BUF_SIZ];	/* buffer for block size conversion */
-static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
-static volatile int mcd_buf_in, mcd_buf_out = -1;
-static volatile int mcd_error;
-static int mcd_open_count;
-enum mcd_state_e {
-	MCD_S_IDLE,		/* 0 */
-	MCD_S_START,		/* 1 */
-	MCD_S_MODE,		/* 2 */
-	MCD_S_READ,		/* 3 */
-	MCD_S_DATA,		/* 4 */
-	MCD_S_STOP,		/* 5 */
-	MCD_S_STOPPING		/* 6 */
-};
-static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
-static int mcd_mode = -1;
-static int MCMD_DATA_READ = MCMD_PLAY_READ;
-
-#define READ_TIMEOUT 3000
-
-int mitsumi_bug_93_wait;
-
-static short mcd_port = CONFIG_MCD_BASE;	/* used as "mcd" by "insmod" */
-static int mcd_irq = CONFIG_MCD_IRQ;	/* must directly follow mcd_port */
-
-static int McdTimeout, McdTries;
-static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
-
-static struct mcd_DiskInfo DiskInfo;
-static struct mcd_Toc Toc[MAX_TRACKS];
-static struct mcd_Play_msf mcd_Play;
-
-static int audioStatus;
-static char mcdDiskChanged;
-static char tocUpToDate;
-static char mcdVersion;
-
-static void mcd_transfer(void);
-static void mcd_poll(unsigned long dummy);
-static void mcd_invalidate_buffers(void);
-static void hsg2msf(long hsg, struct msf *msf);
-static void bin2bcd(unsigned char *p);
-static int bcd2bin(unsigned char bcd);
-static int mcdStatus(void);
-static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
-static int getMcdStatus(int timeout);
-static int GetQChannelInfo(struct mcd_Toc *qp);
-static int updateToc(void);
-static int GetDiskInfo(void);
-static int GetToc(void);
-static int getValue(unsigned char *result);
-static int mcd_open(struct cdrom_device_info *cdi, int purpose);
-static void mcd_release(struct cdrom_device_info *cdi);
-static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
-static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
-static DEFINE_SPINLOCK(mcd_spinlock);
-static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-		    void *arg);
-static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
-
-static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
-
-static struct cdrom_device_ops mcd_dops = {
-	.open			= mcd_open,
-	.release		= mcd_release,
-	.drive_status		= mcd_drive_status,
-	.media_changed		= mcd_media_changed,
-	.tray_move		= mcd_tray_move,
-	.audio_ioctl		= mcd_audio_ioctl,
-	.capability		= CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
-				  CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
-};
-
-static struct cdrom_device_info mcd_info = {
-	.ops		= &mcd_dops,
-	.speed		= 2,
-	.capacity	= 1,
-	.name		= "mcd",
-};
-
-static int mcd_block_open(struct inode *inode, struct file *file)
-{
-	return cdrom_open(&mcd_info, inode, file);
-}
-
-static int mcd_block_release(struct inode *inode, struct file *file)
-{
-	return cdrom_release(&mcd_info, file);
-}
-
-static int mcd_block_ioctl(struct inode *inode, struct file *file,
-				unsigned cmd, unsigned long arg)
-{
-	return cdrom_ioctl(file, &mcd_info, inode, cmd, arg);
-}
-
-static int mcd_block_media_changed(struct gendisk *disk)
-{
-	return cdrom_media_changed(&mcd_info);
-}
-
-static struct block_device_operations mcd_bdops =
-{
-	.owner		= THIS_MODULE,
-	.open		= mcd_block_open,
-	.release	= mcd_block_release,
-	.ioctl		= mcd_block_ioctl,
-	.media_changed	= mcd_block_media_changed,
-};
-
-static struct gendisk *mcd_gendisk;
-
-static int __init mcd_setup(char *str)
-{
-	int ints[9];
-
-	(void) get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0)
-		mcd_port = ints[1];
-	if (ints[0] > 1)
-		mcd_irq = ints[2];
-	if (ints[0] > 2)
-		mitsumi_bug_93_wait = ints[3];
-
-	return 1;
-}
-
-__setup("mcd=", mcd_setup);
-
-#ifdef MODULE
-static int __init param_set_mcd(const char *val, struct kernel_param *kp)
-{
-	mcd_setup(val);
-	return 0;
-}
-module_param_call(mcd, param_set_mcd, NULL, NULL, 0);
-#endif
-
-static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-{
-	return 0;
-}
-
-
-/*
- * Do a 'get status' command and get the result.  Only use from the top half
- * because it calls 'getMcdStatus' which sleeps.
- */
-
-static int statusCmd(void)
-{
-	int st = -1, retry;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		/* send get-status cmd */
-		outb(MCMD_GET_STATUS, MCDPORT(0));
-
-		st = getMcdStatus(MCD_STATUS_DELAY);
-		if (st != -1)
-			break;
-	}
-
-	return st;
-}
-
-
-/*
- * Send a 'Play' command and get the status.  Use only from the top half.
- */
-
-static int mcdPlay(struct mcd_Play_msf *arg)
-{
-	int retry, st = -1;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		sendMcdCmd(MCMD_PLAY_READ, arg);
-		st = getMcdStatus(2 * MCD_STATUS_DELAY);
-		if (st != -1)
-			break;
-	}
-
-	return st;
-}
-
-
-static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
-{
-	int i;
-	if (position) {
-		/*  Eject */
-		/* all drives can at least stop! */
-		if (audioStatus == CDROM_AUDIO_PLAY) {
-			outb(MCMD_STOP, MCDPORT(0));
-			i = getMcdStatus(MCD_STATUS_DELAY);
-		}
-
-		audioStatus = CDROM_AUDIO_NO_STATUS;
-
-		outb(MCMD_EJECT, MCDPORT(0));
-		/*
-		 * the status (i) shows failure on all but the FX drives.
-		 * But nothing we can do about that in software!
-		 * So just read the status and forget it. - Jon.
-		 */
-		i = getMcdStatus(MCD_STATUS_DELAY);
-		return 0;
-	} else
-		return -EINVAL;
-}
-
-long msf2hsg(struct msf *mp)
-{
-	return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
-}
-
-
-int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-		    void *arg)
-{
-	int i, st;
-	struct mcd_Toc qInfo;
-	struct cdrom_ti *ti;
-	struct cdrom_tochdr *tocHdr;
-	struct cdrom_msf *msf;
-	struct cdrom_subchnl *subchnl;
-	struct cdrom_tocentry *entry;
-	struct mcd_Toc *tocPtr;
-	struct cdrom_volctrl *volctrl;
-
-	st = statusCmd();
-	if (st < 0)
-		return -EIO;
-
-	if (!tocUpToDate) {
-		i = updateToc();
-		if (i < 0)
-			return i;	/* error reading TOC */
-	}
-
-	switch (cmd) {
-	case CDROMSTART:	/* Spin up the drive */
-		/* Don't think we can do this.  Even if we could,
-		 * I think the drive times out and stops after a while
-		 * anyway.  For now, ignore it.
-		 */
-
-		return 0;
-
-	case CDROMSTOP:	/* Spin down the drive */
-		outb(MCMD_STOP, MCDPORT(0));
-		i = getMcdStatus(MCD_STATUS_DELAY);
-
-		/* should we do anything if it fails? */
-
-		audioStatus = CDROM_AUDIO_NO_STATUS;
-		return 0;
-
-	case CDROMPAUSE:	/* Pause the drive */
-		if (audioStatus != CDROM_AUDIO_PLAY)
-			return -EINVAL;
-
-		outb(MCMD_STOP, MCDPORT(0));
-		i = getMcdStatus(MCD_STATUS_DELAY);
-
-		if (GetQChannelInfo(&qInfo) < 0) {
-			/* didn't get q channel info */
-
-			audioStatus = CDROM_AUDIO_NO_STATUS;
-			return 0;
-		}
-
-		mcd_Play.start = qInfo.diskTime;	/* remember restart point */
-
-		audioStatus = CDROM_AUDIO_PAUSED;
-		return 0;
-
-	case CDROMRESUME:	/* Play it again, Sam */
-		if (audioStatus != CDROM_AUDIO_PAUSED)
-			return -EINVAL;
-
-		/* restart the drive at the saved position. */
-
-		i = mcdPlay(&mcd_Play);
-		if (i < 0) {
-			audioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-
-		audioStatus = CDROM_AUDIO_PLAY;
-		return 0;
-
-	case CDROMPLAYTRKIND:	/* Play a track.  This currently ignores index. */
-
-		ti = (struct cdrom_ti *) arg;
-
-		if (ti->cdti_trk0 < DiskInfo.first
-		    || ti->cdti_trk0 > DiskInfo.last
-		    || ti->cdti_trk1 < ti->cdti_trk0) {
-			return -EINVAL;
-		}
-
-		if (ti->cdti_trk1 > DiskInfo.last)
-			ti->cdti_trk1 = DiskInfo.last;
-
-		mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
-		mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
-
-#ifdef MCD_DEBUG
-		printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-		       mcd_Play.start.min, mcd_Play.start.sec,
-		       mcd_Play.start.frame, mcd_Play.end.min,
-		       mcd_Play.end.sec, mcd_Play.end.frame);
-#endif
-
-		i = mcdPlay(&mcd_Play);
-		if (i < 0) {
-			audioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-
-		audioStatus = CDROM_AUDIO_PLAY;
-		return 0;
-
-	case CDROMPLAYMSF:	/* Play starting at the given MSF address. */
-
-		if (audioStatus == CDROM_AUDIO_PLAY) {
-			outb(MCMD_STOP, MCDPORT(0));
-			i = getMcdStatus(MCD_STATUS_DELAY);
-			audioStatus = CDROM_AUDIO_NO_STATUS;
-		}
-
-		msf = (struct cdrom_msf *) arg;
-
-		/* convert to bcd */
-
-		bin2bcd(&msf->cdmsf_min0);
-		bin2bcd(&msf->cdmsf_sec0);
-		bin2bcd(&msf->cdmsf_frame0);
-		bin2bcd(&msf->cdmsf_min1);
-		bin2bcd(&msf->cdmsf_sec1);
-		bin2bcd(&msf->cdmsf_frame1);
-
-		mcd_Play.start.min = msf->cdmsf_min0;
-		mcd_Play.start.sec = msf->cdmsf_sec0;
-		mcd_Play.start.frame = msf->cdmsf_frame0;
-		mcd_Play.end.min = msf->cdmsf_min1;
-		mcd_Play.end.sec = msf->cdmsf_sec1;
-		mcd_Play.end.frame = msf->cdmsf_frame1;
-
-#ifdef MCD_DEBUG
-		printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-		       mcd_Play.start.min, mcd_Play.start.sec,
-		       mcd_Play.start.frame, mcd_Play.end.min,
-		       mcd_Play.end.sec, mcd_Play.end.frame);
-#endif
-
-		i = mcdPlay(&mcd_Play);
-		if (i < 0) {
-			audioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-
-		audioStatus = CDROM_AUDIO_PLAY;
-		return 0;
-
-	case CDROMREADTOCHDR:	/* Read the table of contents header */
-		tocHdr = (struct cdrom_tochdr *) arg;
-		tocHdr->cdth_trk0 = DiskInfo.first;
-		tocHdr->cdth_trk1 = DiskInfo.last;
-		return 0;
-
-	case CDROMREADTOCENTRY:	/* Read an entry in the table of contents */
-		entry = (struct cdrom_tocentry *) arg;
-		if (entry->cdte_track == CDROM_LEADOUT)
-			tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
-
-		else if (entry->cdte_track > DiskInfo.last
-			 || entry->cdte_track < DiskInfo.first)
-			return -EINVAL;
-
-		else
-			tocPtr = &Toc[entry->cdte_track];
-
-		entry->cdte_adr = tocPtr->ctrl_addr;
-		entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
-
-		if (entry->cdte_format == CDROM_LBA)
-			entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
-
-		else if (entry->cdte_format == CDROM_MSF) {
-			entry->cdte_addr.msf.minute =
-			    bcd2bin(tocPtr->diskTime.min);
-			entry->cdte_addr.msf.second =
-			    bcd2bin(tocPtr->diskTime.sec);
-			entry->cdte_addr.msf.frame =
-			    bcd2bin(tocPtr->diskTime.frame);
-		}
-
-		else
-			return -EINVAL;
-
-		return 0;
-
-	case CDROMSUBCHNL:	/* Get subchannel info */
-
-		subchnl = (struct cdrom_subchnl *) arg;
-		if (GetQChannelInfo(&qInfo) < 0)
-			return -EIO;
-
-		subchnl->cdsc_audiostatus = audioStatus;
-		subchnl->cdsc_adr = qInfo.ctrl_addr;
-		subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
-		subchnl->cdsc_trk = bcd2bin(qInfo.track);
-		subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
-		subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
-		subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
-		subchnl->cdsc_absaddr.msf.frame  = bcd2bin(qInfo.diskTime.frame);
-		subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
-		subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
-		subchnl->cdsc_reladdr.msf.frame  = bcd2bin(qInfo.trackTime.frame);
-		return (0);
-
-	case CDROMVOLCTRL:	/* Volume control */
-		volctrl = (struct cdrom_volctrl *) arg;
-		outb(MCMD_SET_VOLUME, MCDPORT(0));
-		outb(volctrl->channel0, MCDPORT(0));
-		outb(255, MCDPORT(0));
-		outb(volctrl->channel1, MCDPORT(0));
-		outb(255, MCDPORT(0));
-
-		i = getMcdStatus(MCD_STATUS_DELAY);
-		if (i < 0)
-			return -EIO;
-
-		{
-			char a, b, c, d;
-
-			getValue(&a);
-			getValue(&b);
-			getValue(&c);
-			getValue(&d);
-		}
-
-		return 0;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-
-static void mcd_transfer(void)
-{
-	if (!current_valid())
-		return;
-
-	while (CURRENT->nr_sectors) {
-		int bn = CURRENT->sector / 4;
-		int i;
-		for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
-			;
-		if (i < MCD_BUF_SIZ) {
-			int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
-			int nr_sectors = 4 - (CURRENT->sector & 3);
-			if (mcd_buf_out != i) {
-				mcd_buf_out = i;
-				if (mcd_buf_bn[i] != bn) {
-					mcd_buf_out = -1;
-					continue;
-				}
-			}
-			if (nr_sectors > CURRENT->nr_sectors)
-				nr_sectors = CURRENT->nr_sectors;
-			memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
-			CURRENT->nr_sectors -= nr_sectors;
-			CURRENT->sector += nr_sectors;
-			CURRENT->buffer += nr_sectors * 512;
-		} else {
-		        mcd_buf_out = -1;
-			break;
-		}
-	}
-}
-
-
-/*
- * We only seem to get interrupts after an error.
- * Just take the interrupt and clear out the status reg.
- */
-
-static irqreturn_t mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int st;
-
-	st = inb(MCDPORT(1)) & 0xFF;
-	test1(printk("<int1-%02X>", st));
-	if (!(st & MFL_STATUS)) {
-		st = inb(MCDPORT(0)) & 0xFF;
-		test1(printk("<int0-%02X>", st));
-		if ((st & 0xFF) != 0xFF)
-			mcd_error = st ? st & 0xFF : -1;
-	}
-	return IRQ_HANDLED;
-}
-
-
-static void do_mcd_request(request_queue_t * q)
-{
-	test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
-	       CURRENT->nr_sectors));
-
-		mcd_transfer_is_active = 1;
-	while (current_valid()) {
-		mcd_transfer();
-		if (CURRENT->nr_sectors == 0) {
-			end_request(CURRENT, 1);
-		} else {
-			mcd_buf_out = -1;	/* Want to read a block not in buffer */
-			if (mcd_state == MCD_S_IDLE) {
-				if (!tocUpToDate) {
-					if (updateToc() < 0) {
-						while (current_valid())
-							end_request(CURRENT, 0);
-						break;
-					}
-				}
-				mcd_state = MCD_S_START;
-				McdTries = 5;
-				mcd_timer.function = mcd_poll;
-				mod_timer(&mcd_timer, jiffies + 1);
-			}
-			break;
-		}
-	}
-	mcd_transfer_is_active = 0;
-	test2(printk(" do_mcd_request ends\n"));
-}
-
-
-
-static void mcd_poll(unsigned long dummy)
-{
-	int st;
-
-
-	if (mcd_error) {
-		if (mcd_error & 0xA5) {
-			printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
-			if (mcd_error & 0x80)
-				printk(" (Door open)");
-			if (mcd_error & 0x20)
-				printk(" (Disk changed)");
-			if (mcd_error & 0x04) {
-				printk(" (Read error)");	/* Bitch about the problem. */
-
-				/* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
-				/* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
-				/* But I find that rather HANDY!!! */
-				/* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
-				/* AJK [06/17/95] */
-
-				/* Slap the CD down to single speed! */
-				if (mcdDouble == 1
-				    && McdTries == MCD_RETRY_ATTEMPTS
-				    && MCMD_DATA_READ == MCMD_2X_READ) {
-					MCMD_DATA_READ = MCMD_PLAY_READ;	/* Uhhh, Ummmm, muhuh-huh! */
-					mcd1xhold = SINGLE_HOLD_SECTORS;	/* Hey Beavis! */
-					printk(" Speed now 1x");	/* Pull my finger! */
-				}
-			}
-			printk("\n");
-			mcd_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
-			if (McdTries == MCD_RETRY_ATTEMPTS)
-				printk(KERN_ERR "mcd: read of block %d failed\n",
-				       mcd_next_bn);
-#endif
-			if (!McdTries--) {
-				/* Nuts! This cd is ready for recycling! */
-				/* When WAS the last time YOU cleaned it CORRECTLY?! */
-				printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
-				     mcd_next_bn);
-				if (mcd_transfer_is_active) {
-					McdTries = 0;
-					goto ret;
-				}
-				if (current_valid())
-					end_request(CURRENT, 0);
-				McdTries = MCD_RETRY_ATTEMPTS;
-			}
-		}
-		mcd_error = 0;
-		mcd_state = MCD_S_STOP;
-	}
-	/* Switch back to Double speed if enough GOOD sectors were read! */
-
-	/* Are we a double speed with a crappy CD?! */
-	if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
-	    && MCMD_DATA_READ == MCMD_PLAY_READ) {
-		/* We ARE a double speed and we ARE bitching! */
-		if (mcd1xhold == 0) {	/* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
-			MCMD_DATA_READ = MCMD_2X_READ;	/* Uhhh... BACK You GO! */
-			printk(KERN_INFO "mcd: Switching back to 2X speed!\n");	/* Tell 'em! */
-		} else
-			mcd1xhold--;	/* No?! Count down the good reads some more... */
-		/* and try, try again! */
-	}
-
-immediately:
-	switch (mcd_state) {
-	case MCD_S_IDLE:
-		test3(printk("MCD_S_IDLE\n"));
-		goto out;
-
-	case MCD_S_START:
-		test3(printk("MCD_S_START\n"));
-		outb(MCMD_GET_STATUS, MCDPORT(0));
-		mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
-		McdTimeout = 3000;
-		break;
-
-	case MCD_S_MODE:
-		test3(printk("MCD_S_MODE\n"));
-		if ((st = mcdStatus()) != -1) {
-			if (st & MST_DSK_CHG) {
-				mcdDiskChanged = 1;
-				tocUpToDate = 0;
-				mcd_invalidate_buffers();
-			}
-
-set_mode_immediately:
-			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
-				mcdDiskChanged = 1;
-				tocUpToDate = 0;
-				if (mcd_transfer_is_active) {
-					mcd_state = MCD_S_START;
-					goto immediately;
-				}
-				printk(KERN_INFO);
-				printk((st & MST_DOOR_OPEN) ?
-				       "mcd: door open\n" :
-				       "mcd: disk removed\n");
-				mcd_state = MCD_S_IDLE;
-				while (current_valid())
-					end_request(CURRENT, 0);
-				goto out;
-			}
-			outb(MCMD_SET_MODE, MCDPORT(0));
-			outb(1, MCDPORT(0));
-			mcd_mode = 1;
-			mcd_state = MCD_S_READ;
-			McdTimeout = 3000;
-		}
-		break;
-
-	case MCD_S_READ:
-		test3(printk("MCD_S_READ\n"));
-		if ((st = mcdStatus()) != -1) {
-			if (st & MST_DSK_CHG) {
-				mcdDiskChanged = 1;
-				tocUpToDate = 0;
-				mcd_invalidate_buffers();
-			}
-
-read_immediately:
-			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
-				mcdDiskChanged = 1;
-				tocUpToDate = 0;
-				if (mcd_transfer_is_active) {
-					mcd_state = MCD_S_START;
-					goto immediately;
-				}
-				printk(KERN_INFO);
-				printk((st & MST_DOOR_OPEN) ?
-				       "mcd: door open\n" :
-				       "mcd: disk removed\n");
-				mcd_state = MCD_S_IDLE;
-				while (current_valid())
-					end_request(CURRENT, 0);
-				goto out;
-			}
-
-			if (current_valid()) {
-				struct mcd_Play_msf msf;
-				mcd_next_bn = CURRENT->sector / 4;
-				hsg2msf(mcd_next_bn, &msf.start);
-				msf.end.min = ~0;
-				msf.end.sec = ~0;
-				msf.end.frame = ~0;
-				sendMcdCmd(MCMD_DATA_READ, &msf);
-				mcd_state = MCD_S_DATA;
-				McdTimeout = READ_TIMEOUT;
-			} else {
-				mcd_state = MCD_S_STOP;
-				goto immediately;
-			}
-
-		}
-		break;
-
-	case MCD_S_DATA:
-		test3(printk("MCD_S_DATA\n"));
-		st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
-data_immediately:
-		test5(printk("Status %02x\n", st))
-		switch (st) {
-		case MFL_DATA:
-#ifdef WARN_IF_READ_FAILURE
-			if (McdTries == 5)
-				printk(KERN_WARNING "mcd: read of block %d failed\n",
-				       mcd_next_bn);
-#endif
-			if (!McdTries--) {
-				printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
-				if (mcd_transfer_is_active) {
-					McdTries = 0;
-					break;
-				}
-				if (current_valid())
-					end_request(CURRENT, 0);
-				McdTries = 5;
-			}
-			mcd_state = MCD_S_START;
-			McdTimeout = READ_TIMEOUT;
-			goto immediately;
-
-		case MFL_STATUSorDATA:
-			break;
-
-		default:
-			McdTries = 5;
-			if (!current_valid() && mcd_buf_in == mcd_buf_out) {
-				mcd_state = MCD_S_STOP;
-				goto immediately;
-			}
-			mcd_buf_bn[mcd_buf_in] = -1;
-			insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
-				  2048);
-			mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
-			if (mcd_buf_out == -1)
-				mcd_buf_out = mcd_buf_in;
-			mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
-			if (!mcd_transfer_is_active) {
-				while (current_valid()) {
-					mcd_transfer();
-					if (CURRENT->nr_sectors == 0)
-						end_request(CURRENT, 1);
-					else
-						break;
-				}
-			}
-
-			if (current_valid()
-			    && (CURRENT->sector / 4 < mcd_next_bn ||
-				CURRENT->sector / 4 > mcd_next_bn + 16)) {
-				mcd_state = MCD_S_STOP;
-				goto immediately;
-			}
-			McdTimeout = READ_TIMEOUT;
-			{
-				int count = QUICK_LOOP_COUNT;
-				while (count--) {
-					QUICK_LOOP_DELAY;
-					if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
-						test4(printk(" %d ", QUICK_LOOP_COUNT - count));
-						goto data_immediately;
-					}
-				}
-				test4(printk("ended "));
-			}
-			break;
-		}
-		break;
-
-	case MCD_S_STOP:
-		test3(printk("MCD_S_STOP\n"));
-		if (!mitsumi_bug_93_wait)
-			goto do_not_work_around_mitsumi_bug_93_1;
-
-		McdTimeout = mitsumi_bug_93_wait;
-		mcd_state = 9 + 3 + 1;
-		break;
-
-	case 9 + 3 + 1:
-		if (McdTimeout)
-			break;
-
-do_not_work_around_mitsumi_bug_93_1:
-		outb(MCMD_STOP, MCDPORT(0));
-		if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
-			int i = 4096;
-			do {
-				inb(MCDPORT(0));
-			} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
-			outb(MCMD_STOP, MCDPORT(0));
-			if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
-				i = 4096;
-				do {
-					inb(MCDPORT(0));
-				} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
-				outb(MCMD_STOP, MCDPORT(0));
-			}
-		}
-
-		mcd_state = MCD_S_STOPPING;
-		McdTimeout = 1000;
-		break;
-
-	case MCD_S_STOPPING:
-		test3(printk("MCD_S_STOPPING\n"));
-		if ((st = mcdStatus()) == -1 && McdTimeout)
-			break;
-
-		if ((st != -1) && (st & MST_DSK_CHG)) {
-			mcdDiskChanged = 1;
-			tocUpToDate = 0;
-			mcd_invalidate_buffers();
-		}
-		if (!mitsumi_bug_93_wait)
-			goto do_not_work_around_mitsumi_bug_93_2;
-
-		McdTimeout = mitsumi_bug_93_wait;
-		mcd_state = 9 + 3 + 2;
-		break;
-
-	case 9 + 3 + 2:
-		if (McdTimeout)
-			break;
-		st = -1;
-
-do_not_work_around_mitsumi_bug_93_2:
-		test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
-			    mcd_mode));
-		if (current_valid()) {
-			if (st != -1) {
-				if (mcd_mode == 1)
-					goto read_immediately;
-				else
-					goto set_mode_immediately;
-			} else {
-				mcd_state = MCD_S_START;
-				McdTimeout = 1;
-			}
-		} else {
-			mcd_state = MCD_S_IDLE;
-			goto out;
-		}
-		break;
-	default:
-		printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
-		goto out;
-	}
-ret:
-	if (!McdTimeout--) {
-		printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
-		mcd_state = MCD_S_STOP;
-	}
-	mcd_timer.function = mcd_poll;
-	mod_timer(&mcd_timer, jiffies + 1);
-out:
-	return;
-}
-
-static void mcd_invalidate_buffers(void)
-{
-	int i;
-	for (i = 0; i < MCD_BUF_SIZ; ++i)
-		mcd_buf_bn[i] = -1;
-	mcd_buf_out = -1;
-}
-
-/*
- * Open the device special file.  Check that a disk is in.
- */
-static int mcd_open(struct cdrom_device_info *cdi, int purpose)
-{
-	int st, count = 0;
-	if (mcdPresent == 0)
-		return -ENXIO;	/* no hardware */
-
-	if (mcd_open_count || mcd_state != MCD_S_IDLE)
-		goto bump_count;
-
-	mcd_invalidate_buffers();
-	do {
-		st = statusCmd();	/* check drive status */
-		if (st == -1)
-			goto err_out;	/* drive doesn't respond */
-		if ((st & MST_READY) == 0) 	/* no disk? wait a sec... */
-			msleep(1000);
-
-	} while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
-
-	if (updateToc() < 0)
-		goto err_out;
-
-bump_count:
-	++mcd_open_count;
-	return 0;
-
-err_out:
-	return -EIO;
-}
-
-
-/*
- * On close, we flush all mcd blocks from the buffer cache.
- */
-static void mcd_release(struct cdrom_device_info *cdi)
-{
-	if (!--mcd_open_count) {
-		mcd_invalidate_buffers();
-	}
-}
-
-/*
- * Test for presence of drive and initialize it.  Called at boot time.
- */
-
-int __init mcd_init(void)
-{
-	struct gendisk *disk = alloc_disk(1);
-	int count;
-	unsigned char result[3];
-	char msg[80];
-
-	if (!disk) {
-		printk(KERN_INFO "mcd: can't allocated disk.\n");
-		return -ENOMEM;
-	}
-	if (mcd_port <= 0 || mcd_irq <= 0) {
-		printk(KERN_INFO "mcd: not probing.\n");
-		put_disk(disk);
-		return -EIO;
-	}
-	if (register_blkdev(MAJOR_NR, "mcd")) {
-		put_disk(disk);
-		return -EIO;
-	}
-	if (!request_region(mcd_port, 4, "mcd")) {
-		printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
-		goto out_region;
-	}
-
-	mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
-	if (!mcd_queue)
-		goto out_queue;
-
-	/* check for card */
-
-	outb(0, MCDPORT(1));	/* send reset */
-	for (count = 0; count < 2000000; count++)
-		(void) inb(MCDPORT(1));	/* delay a bit */
-
-	outb(0x40, MCDPORT(0));	/* send get-stat cmd */
-	for (count = 0; count < 2000000; count++)
-		if (!(inb(MCDPORT(1)) & MFL_STATUS))
-			break;
-
-	if (count >= 2000000) {
-		printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
-		       mcd_port, mcd_irq);
-		goto out_probe;
-	}
-	count = inb(MCDPORT(0));	/* pick up the status */
-
-	outb(MCMD_GET_VERSION, MCDPORT(0));
-	for (count = 0; count < 3; count++)
-		if (getValue(result + count)) {
-			printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
-			       mcd_port);
-			goto out_probe;
-		}
-
-	if (result[0] == result[1] && result[1] == result[2])
-		goto out_probe;
-
-	mcdVersion = result[2];
-
-	if (mcdVersion >= 4)
-		outb(4, MCDPORT(2));	/* magic happens */
-
-	/* don't get the IRQ until we know for sure the drive is there */
-
-	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
-		printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
-		goto out_probe;
-	}
-
-	if (result[1] == 'D') {
-		MCMD_DATA_READ = MCMD_2X_READ;
-		/* Added flag to drop to 1x speed if too many errors */
-		mcdDouble = 1;
-	} else
-		mcd_info.speed = 1;
-	sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
-		" irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
-		mcd_port, mcd_irq);
-
-	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
-	outb(0x02, MCDPORT(0));
-	outb(0x00, MCDPORT(0));
-	getValue(result);
-
-	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
-	outb(0x10, MCDPORT(0));
-	outb(0x04, MCDPORT(0));
-	getValue(result);
-
-	mcd_invalidate_buffers();
-	mcdPresent = 1;
-
-	disk->major = MAJOR_NR;
-	disk->first_minor = 0;
-	sprintf(disk->disk_name, "mcd");
-	disk->fops = &mcd_bdops;
-	disk->flags = GENHD_FL_CD;
-	mcd_gendisk = disk;
-
-	if (register_cdrom(&mcd_info) != 0) {
-		printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
-		goto out_cdrom;
-	}
-	disk->queue = mcd_queue;
-	add_disk(disk);
-	printk(msg);
-	return 0;
-
-out_cdrom:
-	free_irq(mcd_irq, NULL);
-out_queue:
-	release_region(mcd_port, 4);
-out_probe:
-	blk_cleanup_queue(mcd_queue);
-out_region:
-	unregister_blkdev(MAJOR_NR, "mcd");
-	put_disk(disk);
-	return -EIO;
-}
-
-
-static void hsg2msf(long hsg, struct msf *msf)
-{
-	hsg += 150;
-	msf->min = hsg / 4500;
-	hsg %= 4500;
-	msf->sec = hsg / 75;
-	msf->frame = hsg % 75;
-
-	bin2bcd(&msf->min);	/* convert to BCD */
-	bin2bcd(&msf->sec);
-	bin2bcd(&msf->frame);
-}
-
-
-static void bin2bcd(unsigned char *p)
-{
-	int u, t;
-
-	u = *p % 10;
-	t = *p / 10;
-	*p = u | (t << 4);
-}
-
-static int bcd2bin(unsigned char bcd)
-{
-	return (bcd >> 4) * 10 + (bcd & 0xF);
-}
-
-
-/*
- * See if a status is ready from the drive and return it
- * if it is ready.
- */
-
-static int mcdStatus(void)
-{
-	int i;
-	int st;
-
-	st = inb(MCDPORT(1)) & MFL_STATUS;
-	if (!st) {
-		i = inb(MCDPORT(0)) & 0xFF;
-		return i;
-	} else
-		return -1;
-}
-
-
-/*
- * Send a play or read command to the drive
- */
-
-static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
-{
-	outb(cmd, MCDPORT(0));
-	outb(params->start.min, MCDPORT(0));
-	outb(params->start.sec, MCDPORT(0));
-	outb(params->start.frame, MCDPORT(0));
-	outb(params->end.min, MCDPORT(0));
-	outb(params->end.sec, MCDPORT(0));
-	outb(params->end.frame, MCDPORT(0));
-}
-
-
-/*
- * Timer interrupt routine to test for status ready from the drive.
- * (see the next routine)
- */
-
-static void mcdStatTimer(unsigned long dummy)
-{
-	if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
-		wake_up(&mcd_waitq);
-		return;
-	}
-
-	McdTimeout--;
-	if (McdTimeout <= 0) {
-		wake_up(&mcd_waitq);
-		return;
-	}
-	mcd_timer.function = mcdStatTimer;
-	mod_timer(&mcd_timer, jiffies + 1);
-}
-
-
-/*
- * Wait for a status to be returned from the drive.  The actual test
- * (see routine above) is done by the timer interrupt to avoid
- * excessive rescheduling.
- */
-
-static int getMcdStatus(int timeout)
-{
-	int st;
-
-	McdTimeout = timeout;
-	mcd_timer.function = mcdStatTimer;
-	mod_timer(&mcd_timer, jiffies + 1);
-	sleep_on(&mcd_waitq);
-	if (McdTimeout <= 0)
-		return -1;
-
-	st = inb(MCDPORT(0)) & 0xFF;
-	if (st == 0xFF)
-		return -1;
-
-	if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
-		/* XXX might be an error? look at q-channel? */
-		audioStatus = CDROM_AUDIO_COMPLETED;
-
-	if (st & MST_DSK_CHG) {
-		mcdDiskChanged = 1;
-		tocUpToDate = 0;
-		audioStatus = CDROM_AUDIO_NO_STATUS;
-	}
-
-	return st;
-}
-
-
-/* gives current state of the drive This function is quite unreliable, 
-   and should probably be rewritten by someone, eventually... */
-
-int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
-	int st;
-
-	st = statusCmd();	/* check drive status */
-	if (st == -1)
-		return -EIO;	/* drive doesn't respond */
-	if ((st & MST_READY))
-		return CDS_DISC_OK;
-	if ((st & MST_DOOR_OPEN))
-		return CDS_TRAY_OPEN;
-	if ((st & MST_DSK_CHG))
-		return CDS_NO_DISC;
-	if ((st & MST_BUSY))
-		return CDS_DRIVE_NOT_READY;
-	return -EIO;
-}
-
-
-/*
- * Read a value from the drive.
- */
-
-static int getValue(unsigned char *result)
-{
-	int count;
-	int s;
-
-	for (count = 0; count < 2000; count++)
-		if (!(inb(MCDPORT(1)) & MFL_STATUS))
-			break;
-
-	if (count >= 2000) {
-		printk("mcd: getValue timeout\n");
-		return -1;
-	}
-
-	s = inb(MCDPORT(0)) & 0xFF;
-	*result = (unsigned char) s;
-	return 0;
-}
-
-/*
- * Read the current Q-channel info.  Also used for reading the
- * table of contents.
- */
-
-int GetQChannelInfo(struct mcd_Toc *qp)
-{
-	unsigned char notUsed;
-	int retry;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
-		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
-			break;
-	}
-
-	if (retry >= MCD_RETRY_ATTEMPTS)
-		return -1;
-
-	if (getValue(&qp->ctrl_addr) < 0)
-		return -1;
-	if (getValue(&qp->track) < 0)
-		return -1;
-	if (getValue(&qp->pointIndex) < 0)
-		return -1;
-	if (getValue(&qp->trackTime.min) < 0)
-		return -1;
-	if (getValue(&qp->trackTime.sec) < 0)
-		return -1;
-	if (getValue(&qp->trackTime.frame) < 0)
-		return -1;
-	if (getValue(&notUsed) < 0)
-		return -1;
-	if (getValue(&qp->diskTime.min) < 0)
-		return -1;
-	if (getValue(&qp->diskTime.sec) < 0)
-		return -1;
-	if (getValue(&qp->diskTime.frame) < 0)
-		return -1;
-
-	return 0;
-}
-
-/*
- * Read the table of contents (TOC) and TOC header if necessary
- */
-
-static int updateToc(void)
-{
-	if (tocUpToDate)
-		return 0;
-
-	if (GetDiskInfo() < 0)
-		return -EIO;
-
-	if (GetToc() < 0)
-		return -EIO;
-
-	tocUpToDate = 1;
-	return 0;
-}
-
-/*
- * Read the table of contents header
- */
-
-static int GetDiskInfo(void)
-{
-	int retry;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		outb(MCMD_GET_DISK_INFO, MCDPORT(0));
-		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
-			break;
-	}
-
-	if (retry >= MCD_RETRY_ATTEMPTS)
-		return -1;
-
-	if (getValue(&DiskInfo.first) < 0)
-		return -1;
-	if (getValue(&DiskInfo.last) < 0)
-		return -1;
-
-	DiskInfo.first = bcd2bin(DiskInfo.first);
-	DiskInfo.last = bcd2bin(DiskInfo.last);
-
-#ifdef MCD_DEBUG
-	printk
-	    ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
-	     DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
-	     DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
-	     DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
-	     DiskInfo.firstTrack.frame);
-#endif
-
-	if (getValue(&DiskInfo.diskLength.min) < 0)
-		return -1;
-	if (getValue(&DiskInfo.diskLength.sec) < 0)
-		return -1;
-	if (getValue(&DiskInfo.diskLength.frame) < 0)
-		return -1;
-	if (getValue(&DiskInfo.firstTrack.min) < 0)
-		return -1;
-	if (getValue(&DiskInfo.firstTrack.sec) < 0)
-		return -1;
-	if (getValue(&DiskInfo.firstTrack.frame) < 0)
-		return -1;
-
-	return 0;
-}
-
-/*
- * Read the table of contents (TOC)
- */
-
-static int GetToc(void)
-{
-	int i, px;
-	int limit;
-	int retry;
-	struct mcd_Toc qInfo;
-
-	for (i = 0; i < MAX_TRACKS; i++)
-		Toc[i].pointIndex = 0;
-
-	i = DiskInfo.last + 3;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		outb(MCMD_STOP, MCDPORT(0));
-		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
-			break;
-	}
-
-	if (retry >= MCD_RETRY_ATTEMPTS)
-		return -1;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		outb(MCMD_SET_MODE, MCDPORT(0));
-		outb(0x05, MCDPORT(0));	/* mode: toc */
-		mcd_mode = 0x05;
-		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
-			break;
-	}
-
-	if (retry >= MCD_RETRY_ATTEMPTS)
-		return -1;
-
-	for (limit = 300; limit > 0; limit--) {
-		if (GetQChannelInfo(&qInfo) < 0)
-			break;
-
-		px = bcd2bin(qInfo.pointIndex);
-		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
-			if (Toc[px].pointIndex == 0) {
-				Toc[px] = qInfo;
-				i--;
-			}
-
-		if (i <= 0)
-			break;
-	}
-
-	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-
-	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
-		outb(MCMD_SET_MODE, MCDPORT(0));
-		outb(0x01, MCDPORT(0));
-		mcd_mode = 1;
-		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
-			break;
-	}
-
-#ifdef MCD_DEBUG
-	for (i = 1; i <= DiskInfo.last; i++)
-		printk
-		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
-		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
-		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
-		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-	for (i = 100; i < 103; i++)
-		printk
-		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
-		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
-		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
-		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-#endif
-
-	return limit > 0 ? 0 : -1;
-}
-
-void __exit mcd_exit(void)
-{
-	del_gendisk(mcd_gendisk);
-	put_disk(mcd_gendisk);
-	if (unregister_cdrom(&mcd_info)) {
-		printk(KERN_WARNING "Can't unregister cdrom mcd\n");
-		return;
-	}
-	free_irq(mcd_irq, NULL);
-	release_region(mcd_port, 4);
-	if (unregister_blkdev(MAJOR_NR, "mcd")) {
-		printk(KERN_WARNING "Can't unregister major mcd\n");
-		return;
-	}
-	blk_cleanup_queue(mcd_queue);
-	del_timer_sync(&mcd_timer);
-}
-
-#ifdef MODULE
-module_init(mcd_init);
-#endif
-module_exit(mcd_exit);
-
-MODULE_AUTHOR("Martin Harriss");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);
diff --git a/drivers/cdrom/mcd.h b/drivers/cdrom/mcd.h
deleted file mode 100644
--- a/drivers/cdrom/mcd.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Definitions for a Mitsumi CD-ROM interface
- *
- *	Copyright (C) 1992  Martin Harriss
- *
- *	martin@bdsi.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* Increase this if you get lots of timeouts */
-#define MCD_STATUS_DELAY	1000
-
-/* number of times to retry a command before giving up */
-#define MCD_RETRY_ATTEMPTS      10
-
-/* port access macro */
-#define MCDPORT(x)		(mcd_port + (x))
-
-/* How many sectors to read at 1x when an error at 2x speed occurs. */
-/* You can change this to anything from 2 to 32767, but 30 seems to */
-/* work best for me.  I have found that when the drive has problems */
-/* reading one sector, it will have troubles reading the next few.  */
-#define SINGLE_HOLD_SECTORS 30	
-
-#define MCMD_2X_READ 0xC1	/* Double Speed Read DON'T TOUCH! */
-
-/* status bits */
-
-#define MST_CMD_CHECK		0x01		/* command error */
-#define MST_BUSY		0x02		/* now playing */
-#define MST_READ_ERR		0x04		/* read error */
-#define MST_DSK_TYPE		0x08
-#define MST_SERVO_CHECK		0x10
-#define MST_DSK_CHG		0x20		/* disk removed or changed */
-#define MST_READY		0x40		/* disk in the drive */
-#define MST_DOOR_OPEN		0x80		/* door is open */
-
-/* flag bits */
-
-#define MFL_DATA		0x02		/* data available */
-#define MFL_STATUS		0x04		/* status available */
-
-/* commands */
-
-#define MCMD_GET_DISK_INFO	0x10		/* read info from disk */
-#define MCMD_GET_Q_CHANNEL	0x20		/* read info from q channel */
-#define MCMD_GET_STATUS		0x40
-#define MCMD_SET_MODE		0x50
-#define MCMD_SOFT_RESET		0x60
-#define MCMD_STOP		0x70		/* stop play */
-#define MCMD_CONFIG_DRIVE	0x90
-#define MCMD_SET_VOLUME		0xAE		/* set audio level */
-#define MCMD_PLAY_READ		0xC0		/* play or read data */
-#define MCMD_GET_VERSION  	0xDC
-#define MCMD_EJECT		0xF6            /* eject (FX drive) */
-
-/* borrowed from hd.c */
-
-#define MAX_TRACKS		104
-
-struct msf {
-	unsigned char	min;
-	unsigned char	sec;
-	unsigned char	frame;
-};
-
-struct mcd_Play_msf {
-	struct msf	start;
-	struct msf	end;
-};
-
-struct mcd_DiskInfo {
-	unsigned char	first;
-	unsigned char	last;
-	struct msf	diskLength;
-	struct msf	firstTrack;
-};
-
-struct mcd_Toc {
-	unsigned char	ctrl_addr;
-	unsigned char	track;
-	unsigned char	pointIndex;
-	struct msf	trackTime;
-	struct msf	diskTime;
-};
-
-#define test1(x)
-#define test2(x)
-#define test3(x)
-#define test4(x)
-#define test5(x)
-
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -107,20 +107,20 @@ static const char *mcdx_c_version
    The _direct_ size is the number of sectors we're allowed to skip
    directly (performing a read instead of requesting the new sector
    needed */
-const int REQUEST_SIZE = 800;	/* should be less then 255 * 4 */
-const int DIRECT_SIZE = 400;	/* should be less then REQUEST_SIZE */
+static const int REQUEST_SIZE = 800;	/* should be less then 255 * 4 */
+static const int DIRECT_SIZE = 400;	/* should be less then REQUEST_SIZE */
 
 enum drivemodes { TOC, DATA, RAW, COOKED };
 enum datamodes { MODE0, MODE1, MODE2 };
 enum resetmodes { SOFT, HARD };
 
-const int SINGLE = 0x01;	/* single speed drive (FX001S, LU) */
-const int DOUBLE = 0x02;	/* double speed drive (FX001D, ..? */
-const int DOOR = 0x04;		/* door locking capability */
-const int MULTI = 0x08;		/* multi session capability */
+static const int SINGLE = 0x01;		/* single speed drive (FX001S, LU) */
+static const int DOUBLE = 0x02;		/* double speed drive (FX001D, ..? */
+static const int DOOR = 0x04;		/* door locking capability */
+static const int MULTI = 0x08;		/* multi session capability */
 
-const unsigned char READ1X = 0xc0;
-const unsigned char READ2X = 0xc1;
+static const unsigned char READ1X = 0xc0;
+static const unsigned char READ2X = 0xc1;
 
 
 /* DECLARATIONS ****************************************************/
@@ -210,9 +210,7 @@ struct s_drive_stuff {
  	repeated here to show what's going on.  And to sense, if they're
 	changed elsewhere. */
 
-/* declared in blk.h */
-int mcdx_init(void);
-void do_mcdx_request(request_queue_t * q);
+static int mcdx_init(void);
 
 static int mcdx_block_open(struct inode *inode, struct file *file)
 {
@@ -569,7 +567,7 @@ static int mcdx_audio_ioctl(struct cdrom
 	}
 }
 
-void do_mcdx_request(request_queue_t * q)
+static void do_mcdx_request(request_queue_t * q)
 {
 	struct s_drive_stuff *stuffp;
 	struct request *req;
@@ -1028,7 +1026,7 @@ int __mcdx_init(void)
 	return 0;
 }
 
-void __exit mcdx_exit(void)
+static void __exit mcdx_exit(void)
 {
 	int i;
 
@@ -1075,7 +1073,7 @@ module_exit(mcdx_exit);
 
 /* Support functions ************************************************/
 
-int __init mcdx_init_drive(int drive)
+static int __init mcdx_init_drive(int drive)
 {
 	struct s_version version;
 	struct gendisk *disk;
@@ -1261,7 +1259,7 @@ int __init mcdx_init_drive(int drive)
 	return 0;
 }
 
-int __init mcdx_init(void)
+static int __init mcdx_init(void)
 {
 	int drive;
 	xwarn("Version 2.14(hs) \n");
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -4266,9 +4266,9 @@ static int sbpcd_dev_ioctl(struct cdrom_
 				   sizeof(struct cdrom_read_audio)))
 			RETURN_UP(-EFAULT);
 		if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL);
-		i=verify_area(VERIFY_WRITE, read_audio.buf,
-			      read_audio.nframes*CD_FRAMESIZE_RAW);
-		if (i) RETURN_UP(i);
+		if (!access_ok(VERIFY_WRITE, read_audio.buf,
+			      read_audio.nframes*CD_FRAMESIZE_RAW))
+                	RETURN_UP(-EFAULT);
 		
 		if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */
 			block=msf2lba(&read_audio.addr.msf.minute);
@@ -5895,7 +5895,7 @@ int __init sbpcd_init(void)
 }
 /*==========================================================================*/
 #ifdef MODULE
-void sbpcd_exit(void)
+static void sbpcd_exit(void)
 {
 	int j;
 	
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -831,8 +831,8 @@ static int sjcd_ioctl(struct inode *ip, 
 			printk("SJCD: ioctl: playmsf\n");
 #endif
 			if ((s =
-			     verify_area(VERIFY_READ, argp,
-					 sizeof(sjcd_msf))) == 0) {
+			     access_ok(VERIFY_READ, argp, sizeof(sjcd_msf))
+			     		? 0 : -EFAULT) == 0) {
 				if (sjcd_audio_status == CDROM_AUDIO_PLAY) {
 					sjcd_send_cmd(SCMD_PAUSE);
 					(void) sjcd_receive_status();
@@ -888,8 +888,8 @@ static int sjcd_ioctl(struct inode *ip, 
 			printk("SJCD: ioctl: readtocentry\n");
 #endif
 			if ((s =
-			     verify_area(VERIFY_WRITE, argp,
-					 sizeof(toc_entry))) == 0) {
+			     access_ok(VERIFY_WRITE, argp, sizeof(toc_entry))
+			     		? 0 : -EFAULT) == 0) {
 				struct sjcd_hw_disk_info *tp;
 
 				if (copy_from_user(&toc_entry, argp,
@@ -943,8 +943,8 @@ static int sjcd_ioctl(struct inode *ip, 
 			printk("SJCD: ioctl: subchnl\n");
 #endif
 			if ((s =
-			     verify_area(VERIFY_WRITE, argp,
-					 sizeof(subchnl))) == 0) {
+			     access_ok(VERIFY_WRITE, argp, sizeof(subchnl))
+			     		? 0 : -EFAULT) == 0) {
 				struct sjcd_hw_qinfo q_info;
 
 				if (copy_from_user(&subchnl, argp,
@@ -1002,8 +1002,8 @@ static int sjcd_ioctl(struct inode *ip, 
 			printk("SJCD: ioctl: volctrl\n");
 #endif
 			if ((s =
-			     verify_area(VERIFY_READ, argp,
-					 sizeof(vol_ctrl))) == 0) {
+			     access_ok(VERIFY_READ, argp, sizeof(vol_ctrl))
+			     		? 0 : -EFAULT) == 0) {
 				unsigned char dummy[4];
 
 				if (copy_from_user(&vol_ctrl, argp,
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -488,6 +488,20 @@ static int viocd_packet(struct cdrom_dev
 					 & (CDC_DVD_RAM | CDC_RAM)) != 0;
 		}
 		break;
+	case GPCMD_GET_CONFIGURATION:
+		if (cgc->cmd[3] == CDF_RWRT) {
+			struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
+
+			if ((buflen >=
+			     (sizeof(struct feature_header) + sizeof(*rfd))) &&
+			    (cdi->ops->capability & ~cdi->mask
+			     & (CDC_DVD_RAM | CDC_RAM))) {
+				rfd->feature_code = cpu_to_be16(CDF_RWRT);
+				rfd->curr = 1;
+				ret = 0;
+			}
+		}
+		break;
 	default:
 		if (cgc->sense) {
 			/* indicate Unknown code */
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -59,7 +59,7 @@ config VT_CONSOLE
 
 config HW_CONSOLE
 	bool
-	depends on VT && !S390 && !USERMODE
+	depends on VT && !S390 && !UML
 	default y
 
 config SERIAL_NONSTANDARD
@@ -148,29 +148,12 @@ config DIGIEPCA
 	  you have a card like this, say Y here and read the file
 	  <file:Documentation/digiepca.txt>.
 
-	  NOTE: There is another, separate driver for the Digiboard PC boards:
-	  "Digiboard PC/Xx Support" below. You should (and can) only select
-	  one of the two drivers.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called epca.
 
-config DIGI
-	tristate "Digiboard PC/Xx Support"
-	depends on SERIAL_NONSTANDARD && DIGIEPCA=n && BROKEN_ON_SMP
-	help
-	  This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
-	  that give you many serial ports. You would need something like this
-	  to connect more than two modems to your Linux box, for instance in
-	  order to become a dial-in server. If you have a card like that, say
-	  Y here and read the file <file:Documentation/digiboard.txt>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called pcxx.
-
 config ESPSERIAL
 	tristate "Hayes ESP serial port support"
-	depends on SERIAL_NONSTANDARD && ISA && BROKEN_ON_SMP
+	depends on SERIAL_NONSTANDARD && ISA && BROKEN_ON_SMP && ISA_DMA_API
 	help
 	  This is a driver which supports Hayes ESP serial ports.  Both single
 	  port cards and multiport cards are supported.  Make sure to read
@@ -212,7 +195,7 @@ config ISI
 
 config SYNCLINK
 	tristate "Microgate SyncLink card support"
-	depends on SERIAL_NONSTANDARD && PCI
+	depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API
 	help
 	  Provides support for the SyncLink ISA and PCI multiprotocol serial
 	  adapters. These adapters support asynchronous and HDLC bit
@@ -264,7 +247,7 @@ config RISCOM8
 
 config SPECIALIX
 	tristate "Specialix IO8+ card support"
-	depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+	depends on SERIAL_NONSTANDARD
 	help
 	  This is a driver for the Specialix IO8+ multiport card (both the
 	  ISA and the PCI version) which gives you many serial ports. You
@@ -288,7 +271,7 @@ config SPECIALIX_RTSCTS
 
 config SX
 	tristate "Specialix SX (and SI) card support"
-	depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+	depends on SERIAL_NONSTANDARD
 	help
 	  This is a driver for the SX and SI multiport serial cards.
 	  Please read the file <file:Documentation/sx.txt> for details.
@@ -416,6 +399,20 @@ config SGI_SNSC
 	  controller communication from user space (you want this!),
 	  say Y.  Otherwise, say N.
 
+config SGI_TIOCX
+       bool "SGI TIO CX driver support"
+       depends on (IA64_SGI_SN2 || IA64_GENERIC)
+       help
+         If you have an SGI Altix and you have fpga devices attached
+         to your TIO, say Y here, otherwise say N.
+
+config SGI_MBCS
+       tristate "SGI FPGA Core Services driver support"
+       depends on SGI_TIOCX
+       help
+         If you have an SGI Altix with an attached SABrick
+         say Y or M here, otherwise say N.
+
 source "drivers/serial/Kconfig"
 
 config UNIX98_PTYS
@@ -782,6 +779,10 @@ config S3C2410_RTC
 	  Samsung S3C2410. This can provide periodic interrupt rates
 	  from 1Hz to 64Hz for user programs, and wakeup from Alarm.
 
+config RTC_VR41XX
+	tristate "NEC VR4100 series Real Time Clock Support"
+	depends on CPU_VR41XX
+
 config COBALT_LCD
 	bool "Support for Cobalt LCD"
 	depends on MIPS_COBALT
@@ -839,6 +840,10 @@ config SONYPI
 	  To compile this driver as a module, choose M here: the
 	  module will be called sonypi.
 
+config TANBAC_TB0219
+	tristate "TANBAC TB0219 base board support"
+	depends TANBAC_TB0229
+
 
 menu "Ftape, the floppy tape device driver"
 
@@ -977,7 +982,7 @@ config MAX_RAW_DEVS
 
 config HANGCHECK_TIMER
 	tristate "Hangcheck timer"
-	depends on X86_64 || X86
+	depends on X86_64 || X86 || IA64 || PPC64 || ARCH_S390
 	help
 	  The hangcheck-timer module detects when the system has gone
 	  out to lunch past a certain margin.  It can reboot the system
@@ -991,5 +996,7 @@ config MMTIMER
 	  The mmtimer device allows direct userspace access to the
 	  Altix system timer.
 
+source "drivers/char/tpm/Kconfig"
+
 endmenu
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_SERIAL167)		+= serial167.o
 obj-$(CONFIG_CYCLADES)		+= cyclades.o
 obj-$(CONFIG_STALLION)		+= stallion.o
 obj-$(CONFIG_ISTALLION)		+= istallion.o
-obj-$(CONFIG_DIGI)		+= pcxx.o
 obj-$(CONFIG_DIGIEPCA)		+= epca.o
 obj-$(CONFIG_SPECIALIX)		+= specialix.o
 obj-$(CONFIG_MOXA_INTELLIO)	+= moxa.o
@@ -43,11 +42,12 @@ obj-$(CONFIG_SX)		+= sx.o generic_serial
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
 obj-$(CONFIG_HVC_CONSOLE)	+= hvc_console.o hvsi.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
-obj-$(CONFIG_SGI_SNSC)		+= snsc.o
+obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
 obj-$(CONFIG_MMTIMER)		+= mmtimer.o
 obj-$(CONFIG_VIOCONS) += viocons.o
 obj-$(CONFIG_VIOTAPE)		+= viotape.o
 obj-$(CONFIG_HVCS)		+= hvcs.o
+obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
 
 obj-$(CONFIG_PRINTER) += lp.o
 obj-$(CONFIG_TIPAR) += tipar.o
@@ -64,6 +64,7 @@ obj-$(CONFIG_SGI_DS1286) += ds1286.o
 obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
 obj-$(CONFIG_DS1302) += ds1302.o
 obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
+obj-$(CONFIG_RTC_VR41XX) += vr41xx_rtc.o
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
   obj-$(CONFIG_NVRAM) += generic_nvram.o
 else
@@ -73,13 +74,13 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o
 obj-$(CONFIG_I8K) += i8k.o
 obj-$(CONFIG_DS1620) += ds1620.o
 obj-$(CONFIG_HW_RANDOM) += hw_random.o
-obj-$(CONFIG_QIC02_TAPE) += tpqic02.o
 obj-$(CONFIG_FTAPE) += ftape/
 obj-$(CONFIG_COBALT_LCD) += lcd.o
 obj-$(CONFIG_PPDEV) += ppdev.o
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
 obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
+obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
 
 obj-$(CONFIG_WATCHDOG)	+= watchdog/
 obj-$(CONFIG_MWAVE) += mwave/
@@ -89,7 +90,7 @@ obj-$(CONFIG_PCMCIA) += pcmcia/
 obj-$(CONFIG_IPMI_HANDLER) += ipmi/
 
 obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
-
+obj-$(CONFIG_TCG_TPM) += tpm/
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
 
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,6 +1,6 @@
 config AGP
 	tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU
-	depends on ALPHA || IA64 || PPC32 || X86
+	depends on ALPHA || IA64 || PPC || X86
 	default y if GART_IOMMU
 	---help---
 	  AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -78,7 +78,7 @@ config AGP_AMD64
 
 config AGP_INTEL
 	tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
-	depends on AGP && X86 && !X86_64
+	depends on AGP && X86
 	help
 	  This option gives you AGP support for the GLX component of XFree86 4.x
 	  on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
@@ -89,16 +89,6 @@ config AGP_INTEL
 	  use GLX or DRI, or if you have any Intel integrated graphics
 	  chipsets.  If unsure, say Y.
 
-config AGP_INTEL_MCH
-	tristate "Intel i865 chipset support"
-	depends on AGP && X86
-	help
-	  This option gives you AGP support for the GLX component of XFree86 4.x
-	  on Intel chipsets that support Intel EM64T processors.
-
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say Y.
-
 config AGP_NVIDIA
 	tristate "NVIDIA nForce/nForce2 chipset support"
 	depends on AGP && X86 && !X86_64
@@ -156,11 +146,11 @@ config AGP_ALPHA_CORE
 	default AGP
 
 config AGP_UNINORTH
-	tristate "Apple UniNorth AGP support"
+	tristate "Apple UniNorth & U3 AGP support"
 	depends on AGP && PPC_PMAC
 	help
 	  This option gives you AGP support for Apple machines with a
-	  UniNorth bridge.
+	  UniNorth or U3 (Apple G5) bridge.
 
 config AGP_EFFICEON
 	tristate "Transmeta Efficeon support"
@@ -172,3 +162,10 @@ config AGP_EFFICEON
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
 	  use GLX or DRI.  If unsure, say Y.
 
+config AGP_SGI_TIOCA
+        tristate "SGI TIO chipset AGP support"
+        depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
+        help
+          This option gives you AGP GART support for the SGI TIO chipset
+          for IA64 processors.
+
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -9,11 +9,10 @@ obj-$(CONFIG_AGP_ALPHA_CORE)	+= alpha-ag
 obj-$(CONFIG_AGP_EFFICEON)	+= efficeon-agp.o
 obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o
 obj-$(CONFIG_AGP_I460)		+= i460-agp.o
-obj-$(CONFIG_AGP_INTEL_MCH)		+= intel-mch-agp.o
 obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
 obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
+obj-$(CONFIG_AGP_SGI_TIOCA)	+= sgi-agp.o
 obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
 obj-$(CONFIG_AGP_SWORKS)	+= sworks-agp.o
 obj-$(CONFIG_AGP_UNINORTH)	+= uninorth-agp.o
 obj-$(CONFIG_AGP_VIA)		+= via-agp.o
-
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -1,5 +1,6 @@
 /*
  * AGPGART
+ * Copyright (C) 2004 Silicon Graphics, Inc.
  * Copyright (C) 2002-2004 Dave Jones
  * Copyright (C) 1999 Jeff Hartmann
  * Copyright (C) 1999 Precision Insight, Inc.
@@ -100,18 +101,19 @@ struct agp_bridge_driver {
 	struct gatt_mask *masks;
 	int (*fetch_size)(void);
 	int (*configure)(void);
-	void (*agp_enable)(u32);
+	void (*agp_enable)(struct agp_bridge_data *, u32);
 	void (*cleanup)(void);
 	void (*tlb_flush)(struct agp_memory *);
-	unsigned long (*mask_memory)(unsigned long, int);
+	unsigned long (*mask_memory)(struct agp_bridge_data *,
+		unsigned long, int);
 	void (*cache_flush)(void);
-	int (*create_gatt_table)(void);
-	int (*free_gatt_table)(void);
+	int (*create_gatt_table)(struct agp_bridge_data *);
+	int (*free_gatt_table)(struct agp_bridge_data *);
 	int (*insert_memory)(struct agp_memory *, off_t, int);
 	int (*remove_memory)(struct agp_memory *, off_t, int);
 	struct agp_memory *(*alloc_by_type) (size_t, int);
 	void (*free_by_type)(struct agp_memory *);
-	void *(*agp_alloc_page)(void);
+	void *(*agp_alloc_page)(struct agp_bridge_data *);
 	void (*agp_destroy_page)(void *);
 };
 
@@ -137,8 +139,10 @@ struct agp_bridge_data {
 	int max_memory_agp;	/* in number of pages */
 	int aperture_size_idx;
 	int capndx;
+	int flags;
 	char major_version;
 	char minor_version;
+	struct list_head list;
 };
 
 #define KB(x)	((x) * 1024)
@@ -243,24 +247,26 @@ int agp_frontend_initialize(void);
 void agp_frontend_cleanup(void);
 
 /* Generic routines. */
-void agp_generic_enable(u32 mode);
-int agp_generic_create_gatt_table(void);
-int agp_generic_free_gatt_table(void);
+void agp_generic_enable(struct agp_bridge_data *bridge, u32 mode);
+int agp_generic_create_gatt_table(struct agp_bridge_data *bridge);
+int agp_generic_free_gatt_table(struct agp_bridge_data *bridge);
 struct agp_memory *agp_create_memory(int scratch_pages);
 int agp_generic_insert_memory(struct agp_memory *mem, off_t pg_start, int type);
 int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
 struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
 void agp_generic_free_by_type(struct agp_memory *curr);
-void *agp_generic_alloc_page(void);
+void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
 void agp_generic_destroy_page(void *addr);
 void agp_free_key(int key);
 int agp_num_entries(void);
-u32 agp_collect_device_status(u32 mode, u32 command);
+u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
 void agp_device_command(u32 command, int agp_v3);
 int agp_3_5_enable(struct agp_bridge_data *bridge);
 void global_cache_flush(void);
 void get_agp_version(struct agp_bridge_data *bridge);
-unsigned long agp_generic_mask_memory(unsigned long addr, int type);
+unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
+	unsigned long addr, int type);
+struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
 
 /* generic routines for agp>=3 */
 int agp3_generic_fetch_size(void);
@@ -272,6 +278,8 @@ void agp3_generic_cleanup(void);
 #define AGP_GENERIC_SIZES_ENTRIES 11
 extern struct aper_size_info_16 agp3_generic_sizes[];
 
+#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
+#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
 
 extern int agp_off;
 extern int agp_try_unsupported_boot;
@@ -315,4 +323,11 @@ extern int agp_try_unsupported_boot;
 #define AGPCTRL_APERENB		(1<<8)
 #define AGPCTRL_GTLBEN		(1<<7)
 
+#define AGP2_RESERVED_MASK 0x00fffcc8
+#define AGP3_RESERVED_MASK 0x00ff00c4
+
+#define AGP_ERRATA_FASTWRITES 1<<0
+#define AGP_ERRATA_SBA	 1<<1
+#define AGP_ERRATA_1X 1<<2
+
 #endif	/* _AGP_BACKEND_PRIV_H */
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -139,9 +139,9 @@ static void m1541_cache_flush(void)
 	}
 }
 
-static void *m1541_alloc_page(void)
+static void *m1541_alloc_page(struct agp_bridge_data *bridge)
 {
-	void *addr = agp_generic_alloc_page();
+	void *addr = agp_generic_alloc_page(agp_bridge);
 	u32 temp;
 
 	if (!addr)
@@ -150,7 +150,7 @@ static void *m1541_alloc_page(void)
 	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(addr)) | ALI_CACHE_FLUSH_EN ));
+			  virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN ));
 	return addr;
 }
 
@@ -174,7 +174,7 @@ static void m1541_destroy_page(void * ad
 	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(addr)) | ALI_CACHE_FLUSH_EN));
+			  virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
 	agp_generic_destroy_page(addr);
 }
 
@@ -192,7 +192,7 @@ static struct aper_size_info_32 ali_gene
 	{4, 1024, 0, 3}
 };
 
-struct agp_bridge_driver ali_generic_bridge = {
+static struct agp_bridge_driver ali_generic_bridge = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= ali_generic_sizes,
 	.size_type		= U32_APER_SIZE,
@@ -215,7 +215,7 @@ struct agp_bridge_driver ali_generic_bri
 	.agp_destroy_page	= ali_destroy_page,
 };
 
-struct agp_bridge_driver ali_m1541_bridge = {
+static struct agp_bridge_driver ali_m1541_bridge = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= ali_generic_sizes,
 	.size_type		= U32_APER_SIZE,
@@ -398,7 +398,7 @@ static int __init agp_ali_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_ali_pci_driver);
+	return pci_register_driver(&agp_ali_pci_driver);
 }
 
 static void __exit agp_ali_cleanup(void)
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -76,11 +76,12 @@ static void alpha_core_agp_tlbflush(stru
 	alpha_mv.mv_pci_tbi(agp->hose, 0, -1);
 }
 
-static void alpha_core_agp_enable(u32 mode)
+static void alpha_core_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
-	alpha_agp_info *agp = agp_bridge->dev_private_data;
+	alpha_agp_info *agp = bridge->dev_private_data;
 
-	agp->mode.lw = agp_collect_device_status(mode, agp->capability.lw);
+	agp->mode.lw = agp_collect_device_status(bridge, mode,
+					agp->capability.lw);
 
 	agp->mode.bits.enable = 1;
 	agp->ops->configure(agp);
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -43,7 +43,7 @@ static int amd_create_page_map(struct am
 
 	SetPageReserved(virt_to_page(page_map->real));
 	global_cache_flush();
-	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
+	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
 		ClearPageReserved(virt_to_page(page_map->real));
@@ -132,7 +132,7 @@ static int amd_create_gatt_pages(int nr_
 #define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
 	GET_PAGE_DIR_IDX(addr)]->remapped)
 
-static int amd_create_gatt_table(void)
+static int amd_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	struct aper_size_info_lvl2 *value;
 	struct amd_page_map page_dir;
@@ -154,7 +154,7 @@ static int amd_create_gatt_table(void)
 
 	agp_bridge->gatt_table_real = (u32 *)page_dir.real;
 	agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
-	agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
+	agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
 
 	/* Get the address for the gart region.
 	 * This is a bus address even on the alpha, b/c its
@@ -167,7 +167,7 @@ static int amd_create_gatt_table(void)
 
 	/* Calculate the agp offset */
 	for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
-		writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1,
+		writel(virt_to_gart(amd_irongate_private.gatt_pages[i]->real) | 1,
 			page_dir.remapped+GET_PAGE_DIR_OFF(addr));
 		readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));	/* PCI Posting. */
 	}
@@ -175,7 +175,7 @@ static int amd_create_gatt_table(void)
 	return 0;
 }
 
-static int amd_free_gatt_table(void)
+static int amd_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	struct amd_page_map page_dir;
 
@@ -314,7 +314,8 @@ static int amd_insert_memory(struct agp_
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		writel(agp_generic_mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+		writel(agp_generic_mask_memory(agp_bridge,
+			mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
 		readl(cur_gatt+GET_GATT_OFF(addr));	/* PCI Posting. */
 	}
 	amd_irongate_tlbflush(mem);
@@ -357,7 +358,7 @@ static struct gatt_mask amd_irongate_mas
 	{.mask = 1, .type = 0}
 };
 
-struct agp_bridge_driver amd_irongate_driver = {
+static struct agp_bridge_driver amd_irongate_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= amd_irongate_sizes,
 	.size_type		= LVL2_APER_SIZE,
@@ -421,6 +422,53 @@ static int __devinit agp_amdk7_probe(str
 	bridge->dev = pdev;
 	bridge->capndx = cap_ptr;
 
+	/* 751 Errata (22564_B-1.PDF)
+	   erratum 20: strobe glitch with Nvidia NV10 GeForce cards.
+	   system controller may experience noise due to strong drive strengths
+	 */
+	if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_7006) {
+		u8 cap_ptr=0;
+		struct pci_dev *gfxcard=NULL;
+		while (!cap_ptr) {
+			gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard);
+			if (!gfxcard) {
+				printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n");
+				return -ENODEV;
+			}
+			cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP);
+			if (!cap_ptr) {
+				pci_dev_put(gfxcard);
+				continue;
+			}
+		}
+
+		/* With so many variants of NVidia cards, it's simpler just
+		   to blacklist them all, and then whitelist them as needed
+		   (if necessary at all). */
+		if (gfxcard->vendor == PCI_VENDOR_ID_NVIDIA) {
+			agp_bridge->flags |= AGP_ERRATA_1X;
+			printk (KERN_INFO PFX "AMD 751 chipset with NVidia GeForce detected. Forcing to 1X due to errata.\n");
+		}
+		pci_dev_put(gfxcard);
+	}
+
+	/* 761 Errata (23613_F.pdf)
+	 * Revisions B0/B1 were a disaster.
+	 * erratum 44: SYSCLK/AGPCLK skew causes 2X failures -- Force mode to 1X
+	 * erratum 45: Timing problem prevents fast writes -- Disable fast write.
+	 * erratum 46: Setup violation on AGP SBA pins - Disable side band addressing.
+	 * With this lot disabled, we should prevent lockups. */
+	if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_700E) {
+		u8 revision=0;
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
+		if (revision == 0x10 || revision == 0x11) {
+			agp_bridge->flags = AGP_ERRATA_FASTWRITES;
+			agp_bridge->flags |= AGP_ERRATA_SBA;
+			agp_bridge->flags |= AGP_ERRATA_1X;
+			printk (KERN_INFO PFX "AMD 761 chipset with errata detected - disabling AGP fast writes & SBA and forcing to 1X.\n");
+		}
+	}
+
 	/* Fill in the mode register */
 	pci_read_config_dword(pdev,
 			bridge->capndx+PCI_AGP_STATUS,
@@ -480,7 +528,7 @@ static int __init agp_amdk7_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_amdk7_pci_driver);
+	return pci_register_driver(&agp_amdk7_pci_driver);
 }
 
 static void __exit agp_amdk7_cleanup(void)
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -106,7 +106,8 @@ static int amd64_insert_memory(struct ag
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		tmp = agp_bridge->driver->mask_memory(mem->memory[i], mem->type);
+		tmp = agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type);
 
 		BUG_ON(tmp & 0xffffff0000000ffcULL);
 		pte = (tmp & 0x000000ff00000000ULL) >> 28;
@@ -218,7 +219,7 @@ static struct aper_size_info_32 amd_8151
 
 static int amd_8151_configure(void)
 {
-	unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
+	unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
 
 	/* Configure AGP regs in each x86-64 host bridge. */
 	for_each_nb() {
@@ -242,7 +243,7 @@ static void amd64_cleanup(void)
 }
 
 
-struct agp_bridge_driver amd_8151_driver = {
+static struct agp_bridge_driver amd_8151_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= amd_8151_sizes,
 	.size_type		= U32_APER_SIZE,
@@ -590,7 +591,7 @@ static void __devexit agp_amd64_remove(s
 {
 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	release_mem_region(virt_to_phys(bridge->gatt_table_real),
+	release_mem_region(virt_to_gart(bridge->gatt_table_real),
 			   amd64_aperture_sizes[bridge->aperture_size_idx].size);
 	agp_remove_bridge(bridge);
 	agp_put_bridge(bridge);
@@ -709,7 +710,7 @@ int __init agp_amd64_init(void)
 
 	if (agp_off)
 		return -EINVAL;
-	if (pci_module_init(&agp_amd64_pci_driver) > 0) {
+	if (pci_register_driver(&agp_amd64_pci_driver) > 0) {
 		struct pci_dev *dev;
 		if (!agp_try_unsupported && !agp_try_unsupported_boot) {
 			printk(KERN_INFO PFX "No supported AGP bridge found.\n");
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -61,7 +61,7 @@ static int ati_create_page_map(ati_page_
 
 	SetPageReserved(virt_to_page(page_map->real));
 	err = map_page_into_agp(virt_to_page(page_map->real));
-	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
+	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL || err) {
 		ClearPageReserved(virt_to_page(page_map->real));
@@ -291,7 +291,8 @@ static int ati_insert_memory(struct agp_
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+		writel(agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
 		readl(cur_gatt+GET_GATT_OFF(addr));	/* PCI Posting. */
 	}
 	agp_bridge->driver->tlb_flush(mem);
@@ -319,7 +320,7 @@ static int ati_remove_memory(struct agp_
 	return 0;
 }
 
-static int ati_create_gatt_table(void)
+static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	struct aper_size_info_lvl2 *value;
 	ati_page_map page_dir;
@@ -342,7 +343,7 @@ static int ati_create_gatt_table(void)
 
 	agp_bridge->gatt_table_real = (u32 *)page_dir.real;
 	agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
-	agp_bridge->gatt_bus_addr = virt_to_bus(page_dir.real);
+	agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
 
 	/* Write out the size register */
 	current_size = A_SIZE_LVL2(agp_bridge->current_size);
@@ -372,7 +373,7 @@ static int ati_create_gatt_table(void)
 
 	/* Calculate the agp offset */
 	for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
-		writel(virt_to_bus(ati_generic_private.gatt_pages[i]->real) | 1,
+		writel(virt_to_gart(ati_generic_private.gatt_pages[i]->real) | 1,
 			page_dir.remapped+GET_PAGE_DIR_OFF(addr));
 		readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));	/* PCI Posting. */
 	}
@@ -380,7 +381,7 @@ static int ati_create_gatt_table(void)
 	return 0;
 }
 
-static int ati_free_gatt_table(void)
+static int ati_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	ati_page_map page_dir;
 
@@ -392,7 +393,7 @@ static int ati_free_gatt_table(void)
 	return 0;
 }
 
-struct agp_bridge_driver ati_generic_bridge = {
+static struct agp_bridge_driver ati_generic_bridge = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= ati_generic_sizes,
 	.size_type		= LVL2_APER_SIZE,
@@ -531,7 +532,7 @@ static int __init agp_ati_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_ati_pci_driver);
+	return pci_register_driver(&agp_ati_pci_driver);
 }
 
 static void __exit agp_ati_cleanup(void)
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -1,5 +1,6 @@
 /*
  * AGPGART driver backend routines.
+ * Copyright (C) 2004 Silicon Graphics, Inc.
  * Copyright (C) 2002-2003 Dave Jones.
  * Copyright (C) 1999 Jeff Hartmann.
  * Copyright (C) 1999 Precision Insight, Inc.
@@ -18,12 +19,12 @@
  * 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
- * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS 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 
+ * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS 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.
  *
- * TODO: 
+ * TODO:
  * - Allocate more than order 0 pages to avoid too much linear map splitting.
  */
 #include <linux/module.h>
@@ -42,34 +43,39 @@
  * fix some real stupidity. It's only by chance we can bump
  * past 0.99 at all due to some boolean logic error. */
 #define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 100
+#define AGPGART_VERSION_MINOR 101
 static struct agp_version agp_current_version =
 {
 	.major = AGPGART_VERSION_MAJOR,
 	.minor = AGPGART_VERSION_MINOR,
 };
 
-static int agp_count=0;
+struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
+	&agp_generic_find_bridge;
 
-struct agp_bridge_data agp_bridge_dummy = { .type = NOT_SUPPORTED };
-struct agp_bridge_data *agp_bridge = &agp_bridge_dummy;
+struct agp_bridge_data *agp_bridge;
+LIST_HEAD(agp_bridges);
 EXPORT_SYMBOL(agp_bridge);
-
+EXPORT_SYMBOL(agp_bridges);
+EXPORT_SYMBOL(agp_find_bridge);
 
 /**
- *	agp_backend_acquire  -  attempt to acquire the agp backend.
+ *	agp_backend_acquire  -  attempt to acquire an agp backend.
  *
- *	returns -EBUSY if agp is in use,
- *	returns 0 if the caller owns the agp backend
  */
-int agp_backend_acquire(void)
+struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
 {
-	if (agp_bridge->type == NOT_SUPPORTED)
-		return -EINVAL;
-	if (atomic_read(&agp_bridge->agp_in_use))
-		return -EBUSY;
-	atomic_inc(&agp_bridge->agp_in_use);
-	return 0;
+	struct agp_bridge_data *bridge;
+
+	bridge = agp_find_bridge(pdev);
+
+	if (!bridge)
+		return NULL;
+
+	if (atomic_read(&bridge->agp_in_use))
+		return NULL;
+	atomic_inc(&bridge->agp_in_use);
+	return bridge;
 }
 EXPORT_SYMBOL(agp_backend_acquire);
 
@@ -82,15 +88,16 @@ EXPORT_SYMBOL(agp_backend_acquire);
  *
  *	(Ensure that all memory it bound is unbound.)
  */
-void agp_backend_release(void)
+void agp_backend_release(struct agp_bridge_data *bridge)
 {
-	if (agp_bridge->type != NOT_SUPPORTED)
-		atomic_dec(&agp_bridge->agp_in_use);
+
+	if (bridge)
+		atomic_dec(&bridge->agp_in_use);
 }
 EXPORT_SYMBOL(agp_backend_release);
 
 
-struct { int mem, agp; } maxes_table[] = {
+static struct { int mem, agp; } maxes_table[] = {
 	{0, 0},
 	{32, 4},
 	{64, 28},
@@ -121,7 +128,6 @@ static int agp_find_max(void)
 	     (maxes_table[index].agp - maxes_table[index - 1].agp)) /
 	   (maxes_table[index].mem - maxes_table[index - 1].mem);
 
-	printk(KERN_INFO PFX "Maximum main memory to use for agp memory: %ldM\n", result);
 	result = result << (20 - PAGE_SHIFT);
 	return result;
 }
@@ -135,16 +141,16 @@ static int agp_backend_initialize(struct
 	bridge->version = &agp_current_version;
 
 	if (bridge->driver->needs_scratch_page) {
-		void *addr = bridge->driver->agp_alloc_page();
+		void *addr = bridge->driver->agp_alloc_page(bridge);
 
 		if (!addr) {
 			printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
 			return -ENOMEM;
 		}
 
-		bridge->scratch_page_real = virt_to_phys(addr);
+		bridge->scratch_page_real = virt_to_gart(addr);
 		bridge->scratch_page =
-		    bridge->driver->mask_memory(bridge->scratch_page_real, 0);
+		    bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0);
 	}
 
 	size_value = bridge->driver->fetch_size();
@@ -153,14 +159,14 @@ static int agp_backend_initialize(struct
 		rc = -EINVAL;
 		goto err_out;
 	}
-	if (bridge->driver->create_gatt_table()) {
+	if (bridge->driver->create_gatt_table(bridge)) {
 		printk(KERN_ERR PFX
 		    "unable to get memory for graphics translation table.\n");
 		rc = -ENOMEM;
 		goto err_out;
 	}
 	got_gatt = 1;
-	
+
 	bridge->key_list = vmalloc(PAGE_SIZE * 4);
 	if (bridge->key_list == NULL) {
 		printk(KERN_ERR PFX "error allocating memory for key lists.\n");
@@ -168,7 +174,7 @@ static int agp_backend_initialize(struct
 		goto err_out;
 	}
 	got_keylist = 1;
-	
+
 	/* FIXME vmalloc'd memory not guaranteed contiguous */
 	memset(bridge->key_list, 0, PAGE_SIZE * 4);
 
@@ -178,17 +184,14 @@ static int agp_backend_initialize(struct
 		goto err_out;
 	}
 
-	printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
-	       size_value, bridge->gart_bus_addr);
-
 	return 0;
 
 err_out:
 	if (bridge->driver->needs_scratch_page)
 		bridge->driver->agp_destroy_page(
-				phys_to_virt(bridge->scratch_page_real));
+				gart_to_virt(bridge->scratch_page_real));
 	if (got_gatt)
-		bridge->driver->free_gatt_table();
+		bridge->driver->free_gatt_table(bridge);
 	if (got_keylist) {
 		vfree(bridge->key_list);
 		bridge->key_list = NULL;
@@ -202,7 +205,7 @@ static void agp_backend_cleanup(struct a
 	if (bridge->driver->cleanup)
 		bridge->driver->cleanup();
 	if (bridge->driver->free_gatt_table)
-		bridge->driver->free_gatt_table();
+		bridge->driver->free_gatt_table(bridge);
 	if (bridge->key_list) {
 		vfree(bridge->key_list);
 		bridge->key_list = NULL;
@@ -211,19 +214,38 @@ static void agp_backend_cleanup(struct a
 	if (bridge->driver->agp_destroy_page &&
 	    bridge->driver->needs_scratch_page)
 		bridge->driver->agp_destroy_page(
-				phys_to_virt(bridge->scratch_page_real));
+				gart_to_virt(bridge->scratch_page_real));
 }
 
-/* XXX Kludge alert: agpgart isn't ready for multiple bridges yet */
+/* When we remove the global variable agp_bridge from all drivers
+ * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
+ */
+
 struct agp_bridge_data *agp_alloc_bridge(void)
 {
-	return agp_bridge;
+	struct agp_bridge_data *bridge = kmalloc(sizeof(*bridge), GFP_KERNEL);
+
+	if (!bridge)
+		return NULL;
+
+	memset(bridge, 0, sizeof(*bridge));
+	atomic_set(&bridge->agp_in_use, 0);
+	atomic_set(&bridge->current_memory_agp, 0);
+
+	if (list_empty(&agp_bridges))
+		agp_bridge = bridge;
+
+	return bridge;
 }
 EXPORT_SYMBOL(agp_alloc_bridge);
 
 
 void agp_put_bridge(struct agp_bridge_data *bridge)
 {
+        kfree(bridge);
+
+        if (list_empty(&agp_bridges))
+                agp_bridge = NULL;
 }
 EXPORT_SYMBOL(agp_put_bridge);
 
@@ -240,40 +262,38 @@ int agp_add_bridge(struct agp_bridge_dat
 		return -EINVAL;
 	}
 
-	if (agp_count) {
-		printk (KERN_INFO PFX
-		       "Only one agpgart device currently supported.\n");
-		return -ENODEV;
-	}
-
 	/* Grab reference on the chipset driver. */
 	if (!try_module_get(bridge->driver->owner)) {
 		printk (KERN_INFO PFX "Couldn't lock chipset driver.\n");
 		return -EINVAL;
 	}
 
-	bridge->type = SUPPORTED;
-
-	error = agp_backend_initialize(agp_bridge);
+	error = agp_backend_initialize(bridge);
 	if (error) {
 		printk (KERN_INFO PFX "agp_backend_initialize() failed.\n");
 		goto err_out;
 	}
 
-	error = agp_frontend_initialize();
-	if (error) {
-		printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n");
-		goto frontend_err;
+	if (list_empty(&agp_bridges)) {
+		error = agp_frontend_initialize();
+		if (error) {
+			printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n");
+			goto frontend_err;
+		}
+
+		printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
+			bridge->driver->fetch_size(), bridge->gart_bus_addr);
+
 	}
 
-	agp_count++;
+	list_add(&bridge->list, &agp_bridges);
 	return 0;
 
 frontend_err:
-	agp_backend_cleanup(agp_bridge);
+	agp_backend_cleanup(bridge);
 err_out:
-	bridge->type = NOT_SUPPORTED;
 	module_put(bridge->driver->owner);
+	agp_put_bridge(bridge);
 	return error;
 }
 EXPORT_SYMBOL_GPL(agp_add_bridge);
@@ -281,10 +301,10 @@ EXPORT_SYMBOL_GPL(agp_add_bridge);
 
 void agp_remove_bridge(struct agp_bridge_data *bridge)
 {
-	bridge->type = NOT_SUPPORTED;
-	agp_frontend_cleanup();
 	agp_backend_cleanup(bridge);
-	agp_count--;
+	list_del(&bridge->list);
+	if (list_empty(&agp_bridges))
+		agp_frontend_cleanup();
 	module_put(bridge->driver->owner);
 }
 EXPORT_SYMBOL_GPL(agp_remove_bridge);
@@ -302,7 +322,7 @@ static int __init agp_init(void)
 	return 0;
 }
 
-void __exit agp_exit(void)
+static void __exit agp_exit(void)
 {
 }
 
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -148,7 +148,7 @@ static int efficeon_configure(void)
 	return 0;
 }
 
-static int efficeon_free_gatt_table(void)
+static int efficeon_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	int index, freed = 0;
 
@@ -183,7 +183,7 @@ static int efficeon_free_gatt_table(void
 #define GET_GATT(addr) (efficeon_private.gatt_pages[\
 	GET_PAGE_DIR_IDX(addr)]->remapped)
 
-static int efficeon_create_gatt_table(void)
+static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	int index;
 	const int pati    = EFFICEON_PATI;
@@ -209,7 +209,7 @@ static int efficeon_create_gatt_table(vo
 
 		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
-			efficeon_free_gatt_table();
+			efficeon_free_gatt_table(agp_bridge);
 			return -ENOMEM;
 		}
 		SetPageReserved(virt_to_page((char *)page));
@@ -219,7 +219,7 @@ static int efficeon_create_gatt_table(vo
 
 		efficeon_private.l1_table[index] = page;
 
-		value = __pa(page) | pati | present | index;
+		value = virt_to_gart(page) | pati | present | index;
 
 		pci_write_config_dword(agp_bridge->dev,
 			EFFICEON_ATTPAGE, value);
@@ -303,7 +303,7 @@ static int efficeon_remove_memory(struct
 }
 
 
-struct agp_bridge_driver efficeon_driver = {
+static struct agp_bridge_driver efficeon_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= efficeon_generic_sizes,
 	.size_type		= LVL2_APER_SIZE,
@@ -408,7 +408,7 @@ static void __devexit agp_efficeon_remov
 	agp_put_bridge(bridge);
 }
 
-static int agp_efficeon_suspend(struct pci_dev *dev, u32 state)
+static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	return 0;
 }
@@ -448,7 +448,7 @@ static int __init agp_efficeon_init(void
 		return 0;
 	agp_initialised=1;
 
-	return pci_module_init(&agp_efficeon_pci_driver);
+	return pci_register_driver(&agp_efficeon_pci_driver);
 }
 
 static void __exit agp_efficeon_cleanup(void)
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -1,5 +1,6 @@
 /*
  * AGPGART driver frontend
+ * Copyright (C) 2004 Silicon Graphics, Inc.
  * Copyright (C) 2002-2003 Dave Jones
  * Copyright (C) 1999 Jeff Hartmann
  * Copyright (C) 1999 Precision Insight, Inc.
@@ -18,9 +19,9 @@
  * 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
- * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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 
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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.
  *
  */
@@ -152,8 +153,8 @@ static void agp_add_seg_to_client(struct
 
 /* Originally taken from linux/mm/mmap.c from the array
  * protection_map.
- * The original really should be exported to modules, or 
- * some routine which does the conversion for you 
+ * The original really should be exported to modules, or
+ * some routine which does the conversion for you
  */
 
 static const pgprot_t my_protect_map[16] =
@@ -234,7 +235,7 @@ static void agp_insert_into_pool(struct 
 
 /* File private list routines */
 
-struct agp_file_private *agp_find_private(pid_t pid)
+static struct agp_file_private *agp_find_private(pid_t pid)
 {
 	struct agp_file_private *curr;
 
@@ -249,7 +250,7 @@ struct agp_file_private *agp_find_privat
 	return NULL;
 }
 
-void agp_insert_file_private(struct agp_file_private * priv)
+static void agp_insert_file_private(struct agp_file_private * priv)
 {
 	struct agp_file_private *prev;
 
@@ -261,7 +262,7 @@ void agp_insert_file_private(struct agp_
 	agp_fe.file_priv_list = priv;
 }
 
-void agp_remove_file_private(struct agp_file_private * priv)
+static void agp_remove_file_private(struct agp_file_private * priv)
 {
 	struct agp_file_private *next;
 	struct agp_file_private *prev;
@@ -285,8 +286,8 @@ void agp_remove_file_private(struct agp_
 
 /* End - File flag list routines */
 
-/* 
- * Wrappers for agp_free_memory & agp_allocate_memory 
+/*
+ * Wrappers for agp_free_memory & agp_allocate_memory
  * These make sure that internal lists are kept updated.
  */
 static void agp_free_memory_wrap(struct agp_memory *memory)
@@ -299,7 +300,7 @@ static struct agp_memory *agp_allocate_m
 {
 	struct agp_memory *memory;
 
-	memory = agp_allocate_memory(pg_count, type);
+	memory = agp_allocate_memory(agp_bridge, pg_count, type);
 	if (memory == NULL)
 		return NULL;
 
@@ -420,7 +421,7 @@ static int agp_remove_controller(struct 
 	if (agp_fe.current_controller == controller) {
 		agp_fe.current_controller = NULL;
 		agp_fe.backend_acquired = FALSE;
-		agp_backend_release();
+		agp_backend_release(agp_bridge);
 	}
 	kfree(controller);
 	return 0;
@@ -468,10 +469,10 @@ static void agp_controller_release_curre
 
 	agp_fe.current_controller = NULL;
 	agp_fe.used_by_controller = FALSE;
-	agp_backend_release();
+	agp_backend_release(agp_bridge);
 }
 
-/* 
+/*
  * Routines for managing client lists -
  * These routines are for managing the list of auth'ed clients.
  */
@@ -605,7 +606,7 @@ static int agp_mmap(struct file *file, s
 	if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags)))
 		goto out_eperm;
 
-	agp_copy_info(&kerninfo);
+	agp_copy_info(agp_bridge, &kerninfo);
 	size = vma->vm_end - vma->vm_start;
 	current_size = kerninfo.aper_size;
 	current_size = current_size * 0x100000;
@@ -627,7 +628,7 @@ static int agp_mmap(struct file *file, s
 		DBG("client vm_ops=%p", kerninfo.vm_ops);
 		if (kerninfo.vm_ops) {
 			vma->vm_ops = kerninfo.vm_ops;
-		} else if (remap_pfn_range(vma, vma->vm_start,
+		} else if (io_remap_pfn_range(vma, vma->vm_start,
 				(kerninfo.aper_base + offset) >> PAGE_SHIFT,
 					    size, vma->vm_page_prot)) {
 			goto out_again;
@@ -643,7 +644,7 @@ static int agp_mmap(struct file *file, s
 		DBG("controller vm_ops=%p", kerninfo.vm_ops);
 		if (kerninfo.vm_ops) {
 			vma->vm_ops = kerninfo.vm_ops;
-		} else if (remap_pfn_range(vma, vma->vm_start,
+		} else if (io_remap_pfn_range(vma, vma->vm_start,
 					    kerninfo.aper_base >> PAGE_SHIFT,
 					    size, vma->vm_page_prot)) {
 			goto out_again;
@@ -757,7 +758,7 @@ static int agpioc_info_wrap(struct agp_f
 	struct agp_info userinfo;
 	struct agp_kern_info kerninfo;
 
-	agp_copy_info(&kerninfo);
+	agp_copy_info(agp_bridge, &kerninfo);
 
 	userinfo.version.major = kerninfo.version.major;
 	userinfo.version.minor = kerninfo.version.minor;
@@ -777,7 +778,6 @@ static int agpioc_info_wrap(struct agp_f
 
 static int agpioc_acquire_wrap(struct agp_file_private *priv)
 {
-	int ret;
 	struct agp_controller *controller;
 
 	DBG("");
@@ -788,11 +788,15 @@ static int agpioc_acquire_wrap(struct ag
 	if (agp_fe.current_controller != NULL)
 		return -EBUSY;
 
-	ret = agp_backend_acquire();
-	if (ret == 0)
-		agp_fe.backend_acquired = TRUE;
-	else
-		return ret;
+	if(!agp_bridge)
+		return -ENODEV;
+
+        if (atomic_read(&agp_bridge->agp_in_use))
+                return -EBUSY;
+
+	atomic_inc(&agp_bridge->agp_in_use);
+
+	agp_fe.backend_acquired = TRUE;
 
 	controller = agp_find_controller_by_pid(priv->my_pid);
 
@@ -803,7 +807,7 @@ static int agpioc_acquire_wrap(struct ag
 
 		if (controller == NULL) {
 			agp_fe.backend_acquired = FALSE;
-			agp_backend_release();
+			agp_backend_release(agp_bridge);
 			return -ENOMEM;
 		}
 		agp_insert_controller(controller);
@@ -830,7 +834,7 @@ static int agpioc_setup_wrap(struct agp_
 	if (copy_from_user(&mode, arg, sizeof(struct agp_setup)))
 		return -EFAULT;
 
-	agp_enable(mode.agp_mode);
+	agp_enable(agp_bridge, mode.agp_mode);
 	return 0;
 }
 
@@ -993,24 +997,24 @@ static int agp_ioctl(struct inode *inode
 	if ((agp_fe.current_controller == NULL) &&
 	    (cmd != AGPIOC_ACQUIRE)) {
 		ret_val = -EINVAL;
-	   	goto ioctl_out;
+		goto ioctl_out;
 	}
 	if ((agp_fe.backend_acquired != TRUE) &&
 	    (cmd != AGPIOC_ACQUIRE)) {
 		ret_val = -EBUSY;
-	   	goto ioctl_out;
+		goto ioctl_out;
 	}
 	if (cmd != AGPIOC_ACQUIRE) {
 		if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) {
 			ret_val = -EPERM;
-		   	goto ioctl_out;
+			goto ioctl_out;
 		}
 		/* Use the original pid of the controller,
 		 * in case it's threaded */
 
 		if (agp_fe.current_controller->pid != curr_priv->my_pid) {
 			ret_val = -EBUSY;
-		   	goto ioctl_out;
+			goto ioctl_out;
 		}
 	}
 
@@ -1022,35 +1026,35 @@ static int agp_ioctl(struct inode *inode
 	case AGPIOC_ACQUIRE:
 		ret_val = agpioc_acquire_wrap(curr_priv);
 		break;
-	   	
+
 	case AGPIOC_RELEASE:
 		ret_val = agpioc_release_wrap(curr_priv);
 		break;
-	   	
+
 	case AGPIOC_SETUP:
 		ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg);
 		break;
-	   	
+
 	case AGPIOC_RESERVE:
 		ret_val = agpioc_reserve_wrap(curr_priv, (void __user *) arg);
 		break;
-	   	
+
 	case AGPIOC_PROTECT:
 		ret_val = agpioc_protect_wrap(curr_priv);
 		break;
-	  	
+
 	case AGPIOC_ALLOCATE:
 		ret_val = agpioc_allocate_wrap(curr_priv, (void __user *) arg);
 		break;
-	   	
+
 	case AGPIOC_DEALLOCATE:
 		ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg);
 		break;
-	   	
+
 	case AGPIOC_BIND:
 		ret_val = agpioc_bind_wrap(curr_priv, (void __user *) arg);
 		break;
-	   	
+
 	case AGPIOC_UNBIND:
 		ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg);
 		break;
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1,6 +1,7 @@
 /*
  * AGPGART driver.
- * Copyright (C) 2002-2004 Dave Jones.
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ * Copyright (C) 2002-2005 Dave Jones.
  * Copyright (C) 1999 Jeff Hartmann.
  * Copyright (C) 1999 Precision Insight, Inc.
  * Copyright (C) 1999 Xi Graphics, Inc.
@@ -35,6 +36,7 @@
 #include <linux/pm.h>
 #include <linux/agp_backend.h>
 #include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
@@ -139,19 +141,19 @@ void agp_free_memory(struct agp_memory *
 {
 	size_t i;
 
-	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))
+	if (curr == NULL)
 		return;
 
 	if (curr->is_bound == TRUE)
 		agp_unbind_memory(curr);
 
 	if (curr->type != 0) {
-		agp_bridge->driver->free_by_type(curr);
+		curr->bridge->driver->free_by_type(curr);
 		return;
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[i]));
+			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
 		}
 	}
 	agp_free_key(curr->key);
@@ -173,20 +175,23 @@ EXPORT_SYMBOL(agp_free_memory);
  *
  *	It returns NULL whenever memory is unavailable.
  */
-struct agp_memory *agp_allocate_memory(size_t page_count, u32 type)
+struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
+					size_t page_count, u32 type)
 {
 	int scratch_pages;
 	struct agp_memory *new;
 	size_t i;
 
-	if (agp_bridge->type == NOT_SUPPORTED)
+	if (!bridge)
 		return NULL;
 
-	if ((atomic_read(&agp_bridge->current_memory_agp) + page_count) > agp_bridge->max_memory_agp)
+	if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
 		return NULL;
 
 	if (type != 0) {
-		new = agp_bridge->driver->alloc_by_type(page_count, type);
+		new = bridge->driver->alloc_by_type(page_count, type);
+		if (new)
+			new->bridge = bridge;
 		return new;
 	}
 
@@ -198,15 +203,16 @@ struct agp_memory *agp_allocate_memory(s
 		return NULL;
 
 	for (i = 0; i < page_count; i++) {
-		void *addr = agp_bridge->driver->agp_alloc_page();
+		void *addr = bridge->driver->agp_alloc_page(bridge);
 
 		if (addr == NULL) {
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[i] = virt_to_phys(addr);
+		new->memory[i] = virt_to_gart(addr);
 		new->page_count++;
 	}
+       new->bridge = bridge;
 
 	flush_agp_mappings();
 
@@ -297,35 +303,36 @@ EXPORT_SYMBOL_GPL(agp_num_entries);
  *	This function copies information about the agp bridge device and the state of
  *	the agp backend into an agp_kern_info pointer.
  */
-int agp_copy_info(struct agp_kern_info *info)
+int agp_copy_info(struct agp_bridge_data *bridge, struct agp_kern_info *info)
 {
 	memset(info, 0, sizeof(struct agp_kern_info));
-	if (!agp_bridge || agp_bridge->type == NOT_SUPPORTED ||
-	    !agp_bridge->version) {
+	if (!bridge) {
 		info->chipset = NOT_SUPPORTED;
 		return -EIO;
 	}
 
-	info->version.major = agp_bridge->version->major;
-	info->version.minor = agp_bridge->version->minor;
-	info->chipset = agp_bridge->type;
-	info->device = agp_bridge->dev;
-	info->mode = agp_bridge->mode;
-	info->aper_base = agp_bridge->gart_bus_addr;
+	info->version.major = bridge->version->major;
+	info->version.minor = bridge->version->minor;
+	info->chipset = SUPPORTED;
+	info->device = bridge->dev;
+	if (bridge->mode & AGPSTAT_MODE_3_0)
+		info->mode = bridge->mode & ~AGP3_RESERVED_MASK;
+	else
+		info->mode = bridge->mode & ~AGP2_RESERVED_MASK;
+	info->mode = bridge->mode;
+	info->aper_base = bridge->gart_bus_addr;
 	info->aper_size = agp_return_size();
-	info->max_memory = agp_bridge->max_memory_agp;
-	info->current_memory = atomic_read(&agp_bridge->current_memory_agp);
-	info->cant_use_aperture = agp_bridge->driver->cant_use_aperture;
-	info->vm_ops = agp_bridge->vm_ops;
+	info->max_memory = bridge->max_memory_agp;
+	info->current_memory = atomic_read(&bridge->current_memory_agp);
+	info->cant_use_aperture = bridge->driver->cant_use_aperture;
+	info->vm_ops = bridge->vm_ops;
 	info->page_mask = ~0UL;
 	return 0;
 }
 EXPORT_SYMBOL(agp_copy_info);
 
-
 /* End - Routine to copy over information structure */
 
-
 /*
  * Routines for handling swapping of agp_memory into the GATT -
  * These routines take agp_memory and insert them into the GATT.
@@ -345,7 +352,7 @@ int agp_bind_memory(struct agp_memory *c
 {
 	int ret_val;
 
-	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))
+	if (curr == NULL)
 		return -EINVAL;
 
 	if (curr->is_bound == TRUE) {
@@ -353,10 +360,10 @@ int agp_bind_memory(struct agp_memory *c
 		return -EINVAL;
 	}
 	if (curr->is_flushed == FALSE) {
-		agp_bridge->driver->cache_flush();
+		curr->bridge->driver->cache_flush();
 		curr->is_flushed = TRUE;
 	}
-	ret_val = agp_bridge->driver->insert_memory(curr, pg_start, curr->type);
+	ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
 	if (ret_val != 0)
 		return ret_val;
@@ -380,7 +387,7 @@ int agp_unbind_memory(struct agp_memory 
 {
 	int ret_val;
 
-	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))
+	if (curr == NULL)
 		return -EINVAL;
 
 	if (curr->is_bound != TRUE) {
@@ -388,7 +395,7 @@ int agp_unbind_memory(struct agp_memory 
 		return -EINVAL;
 	}
 
-	ret_val = agp_bridge->driver->remove_memory(curr, curr->pg_start, curr->type);
+	ret_val = curr->bridge->driver->remove_memory(curr, curr->pg_start, curr->type);
 
 	if (ret_val != 0)
 		return ret_val;
@@ -403,71 +410,133 @@ EXPORT_SYMBOL(agp_unbind_memory);
 
 
 /* Generic Agp routines - Start */
-static void agp_v2_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
+static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_agpstat)
 {
+	u32 tmp;
+
+	if (*requested_mode & AGP2_RESERVED_MASK) {
+		printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
+		*requested_mode &= ~AGP2_RESERVED_MASK;
+	}
+
+	/* Check the speed bits make sense. Only one should be set. */
+	tmp = *requested_mode & 7;
+	switch (tmp) {
+		case 0:
+			printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to x1 mode.\n", current->comm);
+			*requested_mode |= AGPSTAT2_1X;
+			break;
+		case 1:
+		case 2:
+			break;
+		case 3:
+			*requested_mode &= ~(AGPSTAT2_1X);	/* rate=2 */
+			break;
+		case 4:
+			break;
+		case 5:
+		case 6:
+		case 7:
+			*requested_mode &= ~(AGPSTAT2_1X|AGPSTAT2_2X); /* rate=4*/
+			break;
+	}
+
 	/* disable SBA if it's not supported */
-	if (!((*cmd & AGPSTAT_SBA) && (*tmp & AGPSTAT_SBA) && (*mode & AGPSTAT_SBA)))
-		*cmd &= ~AGPSTAT_SBA;
+	if (!((*bridge_agpstat & AGPSTAT_SBA) && (*vga_agpstat & AGPSTAT_SBA) && (*requested_mode & AGPSTAT_SBA)))
+		*bridge_agpstat &= ~AGPSTAT_SBA;
 
-	/* Set speed */
-	if (!((*cmd & AGPSTAT2_4X) && (*tmp & AGPSTAT2_4X) && (*mode & AGPSTAT2_4X)))
-		*cmd &= ~AGPSTAT2_4X;
+	/* Set rate */
+	if (!((*bridge_agpstat & AGPSTAT2_4X) && (*vga_agpstat & AGPSTAT2_4X) && (*requested_mode & AGPSTAT2_4X)))
+		*bridge_agpstat &= ~AGPSTAT2_4X;
 
-	if (!((*cmd & AGPSTAT2_2X) && (*tmp & AGPSTAT2_2X) && (*mode & AGPSTAT2_2X)))
-		*cmd &= ~AGPSTAT2_2X;
+	if (!((*bridge_agpstat & AGPSTAT2_2X) && (*vga_agpstat & AGPSTAT2_2X) && (*requested_mode & AGPSTAT2_2X)))
+		*bridge_agpstat &= ~AGPSTAT2_2X;
 
-	if (!((*cmd & AGPSTAT2_1X) && (*tmp & AGPSTAT2_1X) && (*mode & AGPSTAT2_1X)))
-		*cmd &= ~AGPSTAT2_1X;
+	if (!((*bridge_agpstat & AGPSTAT2_1X) && (*vga_agpstat & AGPSTAT2_1X) && (*requested_mode & AGPSTAT2_1X)))
+		*bridge_agpstat &= ~AGPSTAT2_1X;
 
 	/* Now we know what mode it should be, clear out the unwanted bits. */
-	if (*cmd & AGPSTAT2_4X)
-		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_2X);	/* 4X */
+	if (*bridge_agpstat & AGPSTAT2_4X)
+		*bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_2X);	/* 4X */
+
+	if (*bridge_agpstat & AGPSTAT2_2X)
+		*bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_4X);	/* 2X */
 
-	if (*cmd & AGPSTAT2_2X)
-		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_4X);	/* 2X */
+	if (*bridge_agpstat & AGPSTAT2_1X)
+		*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X);	/* 1X */
 
-	if (*cmd & AGPSTAT2_1X)
-		*cmd &= ~(AGPSTAT2_2X | AGPSTAT2_4X);	/* 1X */
+	/* Apply any errata. */
+	if (agp_bridge->flags & AGP_ERRATA_FASTWRITES)
+		*bridge_agpstat &= ~AGPSTAT_FW;
+
+	if (agp_bridge->flags & AGP_ERRATA_SBA)
+		*bridge_agpstat &= ~AGPSTAT_SBA;
+
+	if (agp_bridge->flags & AGP_ERRATA_1X) {
+		*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X);
+		*bridge_agpstat |= AGPSTAT2_1X;
+	}
+
+	/* If we've dropped down to 1X, disable fast writes. */
+	if (*bridge_agpstat & AGPSTAT2_1X)
+		*bridge_agpstat &= ~AGPSTAT_FW;
 }
 
 /*
- * mode = requested mode.
- * cmd = PCI_AGP_STATUS from agp bridge.
- * tmp = PCI_AGP_STATUS from graphic card.
+ * requested_mode = Mode requested by (typically) X.
+ * bridge_agpstat = PCI_AGP_STATUS from agp bridge.
+ * vga_agpstat = PCI_AGP_STATUS from graphic card.
  */
-static void agp_v3_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
+static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_agpstat)
 {
-	u32 origcmd=*cmd, origtmp=*tmp;
+	u32 origbridge=*bridge_agpstat, origvga=*vga_agpstat;
+	u32 tmp;
+
+	if (*requested_mode & AGP3_RESERVED_MASK) {
+		printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
+		*requested_mode &= ~AGP3_RESERVED_MASK;
+	}
+
+	/* Check the speed bits make sense. */
+	tmp = *requested_mode & 7;
+	if (tmp == 0) {
+		printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm);
+		*requested_mode |= AGPSTAT3_4X;
+	}
+	if (tmp >= 3) {
+		printk (KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4);
+		*requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X;
+	}
 
 	/* ARQSZ - Set the value to the maximum one.
 	 * Don't allow the mode register to override values. */
-	*cmd = ((*cmd & ~AGPSTAT_ARQSZ) |
-		max_t(u32,(*cmd & AGPSTAT_ARQSZ),(*tmp & AGPSTAT_ARQSZ)));
+	*bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_ARQSZ) |
+		max_t(u32,(*bridge_agpstat & AGPSTAT_ARQSZ),(*vga_agpstat & AGPSTAT_ARQSZ)));
 
 	/* Calibration cycle.
 	 * Don't allow the mode register to override values. */
-	*cmd = ((*cmd & ~AGPSTAT_CAL_MASK) |
-		min_t(u32,(*cmd & AGPSTAT_CAL_MASK),(*tmp & AGPSTAT_CAL_MASK)));
+	*bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_CAL_MASK) |
+		min_t(u32,(*bridge_agpstat & AGPSTAT_CAL_MASK),(*vga_agpstat & AGPSTAT_CAL_MASK)));
 
 	/* SBA *must* be supported for AGP v3 */
-	*cmd |= AGPSTAT_SBA;
+	*bridge_agpstat |= AGPSTAT_SBA;
 
 	/*
 	 * Set speed.
 	 * Check for invalid speeds. This can happen when applications
 	 * written before the AGP 3.0 standard pass AGP2.x modes to AGP3 hardware
 	 */
-	if (*mode & AGPSTAT_MODE_3_0) {
+	if (*requested_mode & AGPSTAT_MODE_3_0) {
 		/*
-		 * Caller hasn't a clue what its doing. We are in 3.0 mode,
+		 * Caller hasn't a clue what it is doing. Bridge is in 3.0 mode,
 		 * have been passed a 3.0 mode, but with 2.x speed bits set.
 		 * AGP2.x 4x -> AGP3.0 4x.
 		 */
-		if (*mode & AGPSTAT2_4X) {
+		if (*requested_mode & AGPSTAT2_4X) {
 			printk (KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n",
-						current->comm, *mode);
-			*mode &= ~AGPSTAT2_4X;
-			*mode |= AGPSTAT3_4X;
+						current->comm, *requested_mode);
+			*requested_mode &= ~AGPSTAT2_4X;
+			*requested_mode |= AGPSTAT3_4X;
 		}
 	} else {
 		/*
@@ -476,27 +545,27 @@ static void agp_v3_parse_one(u32 *mode, 
 		 * Convert AGP 1x,2x,4x -> AGP 3.0 4x.
 		 */
 		printk (KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",
-					current->comm, *mode);
-		*mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X);
-		*mode |= AGPSTAT3_4X;
+					current->comm, *requested_mode);
+		*requested_mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X);
+		*requested_mode |= AGPSTAT3_4X;
 	}
 
-	if (*mode & AGPSTAT3_8X) {
-		if (!(*cmd & AGPSTAT3_8X)) {
-			*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
-			*cmd |= AGPSTAT3_4X;
+	if (*requested_mode & AGPSTAT3_8X) {
+		if (!(*bridge_agpstat & AGPSTAT3_8X)) {
+			*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+			*bridge_agpstat |= AGPSTAT3_4X;
 			printk ("%s requested AGPx8 but bridge not capable.\n", current->comm);
 			return;
 		}
-		if (!(*tmp & AGPSTAT3_8X)) {
-			*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
-			*cmd |= AGPSTAT3_4X;
+		if (!(*vga_agpstat & AGPSTAT3_8X)) {
+			*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+			*bridge_agpstat |= AGPSTAT3_4X;
 			printk ("%s requested AGPx8 but graphic card not capable.\n", current->comm);
 			return;
 		}
 		/* All set, bridge & device can do AGP x8*/
-		*cmd &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
-		return;
+		*bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
+		goto done;
 
 	} else {
 
@@ -505,71 +574,97 @@ static void agp_v3_parse_one(u32 *mode, 
 		 * If the hardware can't do x4, we're up shit creek, and never
 		 *  should have got this far.
 		 */
-		*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
-		if ((*cmd & AGPSTAT3_4X) && (*tmp & AGPSTAT3_4X))
-			*cmd |= AGPSTAT3_4X;
+		*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+		if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X))
+			*bridge_agpstat |= AGPSTAT3_4X;
 		else {
 			printk (KERN_INFO PFX "Badness. Don't know which AGP mode to set. "
-							"[cmd:%x tmp:%x fell back to:- cmd:%x tmp:%x]\n",
-							origcmd, origtmp, *cmd, *tmp);
-			if (!(*cmd & AGPSTAT3_4X))
+							"[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n",
+							origbridge, origvga, *bridge_agpstat, *vga_agpstat);
+			if (!(*bridge_agpstat & AGPSTAT3_4X))
 				printk (KERN_INFO PFX "Bridge couldn't do AGP x4.\n");
-			if (!(*tmp & AGPSTAT3_4X))
+			if (!(*vga_agpstat & AGPSTAT3_4X))
 				printk (KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");
+			return;
 		}
 	}
+
+done:
+	/* Apply any errata. */
+	if (agp_bridge->flags & AGP_ERRATA_FASTWRITES)
+		*bridge_agpstat &= ~AGPSTAT_FW;
+
+	if (agp_bridge->flags & AGP_ERRATA_SBA)
+		*bridge_agpstat &= ~AGPSTAT_SBA;
+
+	if (agp_bridge->flags & AGP_ERRATA_1X) {
+		*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X);
+		*bridge_agpstat |= AGPSTAT2_1X;
+	}
 }
 
-//FIXME: This doesn't smell right.
-//We need a function we pass an agp_device to.
-u32 agp_collect_device_status(u32 mode, u32 cmd)
+
+/**
+ * agp_collect_device_status - determine correct agp_cmd from various agp_stat's
+ * @bridge: an agp_bridge_data struct allocated for the AGP host bridge.
+ * @requested_mode: requested agp_stat from userspace (Typically from X)
+ * @bridge_agpstat: current agp_stat from AGP bridge.
+ *
+ * This function will hunt for an AGP graphics card, and try to match
+ * the requested mode to the capabilities of both the bridge and the card.
+ */
+u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode, u32 bridge_agpstat)
 {
 	struct pci_dev *device = NULL;
+	u32 vga_agpstat;
 	u8 cap_ptr;
-	u32 tmp;
-	u32 agp3;
 
-	for_each_pci_dev(device) {
+	for (;;) {
+		device = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, device);
+		if (!device) {
+			printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n");
+			return 0;
+		}
 		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
-		if (!cap_ptr)
-			continue;
+		if (cap_ptr)
+			break;
+	}
 
-		//FIXME: We should probably skip anything here that
-		// isn't an AGP graphic card.
-		/*
-		 * Ok, here we have a AGP device. Disable impossible
-		 * settings, and adjust the readqueue to the minimum.
-		 */
-		pci_read_config_dword(device, cap_ptr+PCI_AGP_STATUS, &tmp);
+	/*
+	 * Ok, here we have a AGP device. Disable impossible
+	 * settings, and adjust the readqueue to the minimum.
+	 */
+	pci_read_config_dword(device, cap_ptr+PCI_AGP_STATUS, &vga_agpstat);
 
-		/* adjust RQ depth */
-		cmd = ((cmd & ~AGPSTAT_RQ_DEPTH) |
-		     min_t(u32, (mode & AGPSTAT_RQ_DEPTH),
-			 min_t(u32, (cmd & AGPSTAT_RQ_DEPTH), (tmp & AGPSTAT_RQ_DEPTH))));
-
-		/* disable FW if it's not supported */
-		if (!((cmd & AGPSTAT_FW) && (tmp & AGPSTAT_FW) && (mode & AGPSTAT_FW)))
-			cmd &= ~AGPSTAT_FW;
-
-		/* Check to see if we are operating in 3.0 mode */
-		pci_read_config_dword(device, cap_ptr+AGPSTAT, &agp3);
-		if (agp3 & AGPSTAT_MODE_3_0) {
-			agp_v3_parse_one(&mode, &cmd, &tmp);
-		} else {
-			agp_v2_parse_one(&mode, &cmd, &tmp);
-		}
-	}
-	return cmd;
+	/* adjust RQ depth */
+	bridge_agpstat = ((bridge_agpstat & ~AGPSTAT_RQ_DEPTH) |
+	     min_t(u32, (requested_mode & AGPSTAT_RQ_DEPTH),
+		 min_t(u32, (bridge_agpstat & AGPSTAT_RQ_DEPTH), (vga_agpstat & AGPSTAT_RQ_DEPTH))));
+
+	/* disable FW if it's not supported */
+	if (!((bridge_agpstat & AGPSTAT_FW) &&
+		 (vga_agpstat & AGPSTAT_FW) &&
+		 (requested_mode & AGPSTAT_FW)))
+		bridge_agpstat &= ~AGPSTAT_FW;
+
+	/* Check to see if we are operating in 3.0 mode */
+	if (agp_bridge->mode & AGPSTAT_MODE_3_0)
+		agp_v3_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat);
+	else
+		agp_v2_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat);
+
+	pci_dev_put(device);
+	return bridge_agpstat;
 }
 EXPORT_SYMBOL(agp_collect_device_status);
 
 
-void agp_device_command(u32 command, int agp_v3)
+void agp_device_command(u32 bridge_agpstat, int agp_v3)
 {
 	struct pci_dev *device = NULL;
 	int mode;
 
-	mode = command & 0x7;
+	mode = bridge_agpstat & 0x7;
 	if (agp_v3)
 		mode *= 4;
 
@@ -580,7 +675,7 @@ void agp_device_command(u32 command, int
 
 		printk(KERN_INFO PFX "Putting AGP V%d device at %s into %dx mode\n",
 				agp_v3 ? 3 : 2, pci_name(device), mode);
-		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command);
+		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, bridge_agpstat);
 	}
 }
 EXPORT_SYMBOL(agp_device_command);
@@ -591,52 +686,53 @@ void get_agp_version(struct agp_bridge_d
 	u32 ncapid;
 
 	/* Exit early if already set by errata workarounds. */
-	if (agp_bridge->major_version != 0)
+	if (bridge->major_version != 0)
 		return;
 
-	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx, &ncapid);
-	agp_bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
-	agp_bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf;
+	pci_read_config_dword(bridge->dev, bridge->capndx, &ncapid);
+	bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
+	bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf;
 }
 EXPORT_SYMBOL(get_agp_version);
 
 
-void agp_generic_enable(u32 mode)
+void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode)
 {
-	u32 command, temp;
-	u32 agp3;
+	u32 bridge_agpstat, temp;
 
 	get_agp_version(agp_bridge);
 
 	printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n",
 				agp_bridge->major_version,
 				agp_bridge->minor_version,
-				agp_bridge->dev->slot_name);
+				pci_name(agp_bridge->dev));
 
 	pci_read_config_dword(agp_bridge->dev,
-		      agp_bridge->capndx + PCI_AGP_STATUS, &command);
+		      agp_bridge->capndx + PCI_AGP_STATUS, &bridge_agpstat);
+
+	bridge_agpstat = agp_collect_device_status(agp_bridge, requested_mode, bridge_agpstat);
+	if (bridge_agpstat == 0)
+		/* Something bad happened. FIXME: Return error code? */
+		return;
 
-	command = agp_collect_device_status(mode, command);
-	command |= AGPSTAT_AGP_ENABLE;
+	bridge_agpstat |= AGPSTAT_AGP_ENABLE;
 
 	/* Do AGP version specific frobbing. */
-	if(agp_bridge->major_version >= 3) {
-		pci_read_config_dword(agp_bridge->dev,
-			agp_bridge->capndx+AGPSTAT, &agp3);
-
-		/* Check to see if we are operating in 3.0 mode */
-		if (agp3 & AGPSTAT_MODE_3_0) {
+	if (bridge->major_version >= 3) {
+		if (bridge->mode & AGPSTAT_MODE_3_0) {
 			/* If we have 3.5, we can do the isoch stuff. */
-			if (agp_bridge->minor_version >= 5)
-				agp_3_5_enable(agp_bridge);
-			agp_device_command(command, TRUE);
+			if (bridge->minor_version >= 5)
+				agp_3_5_enable(bridge);
+			agp_device_command(bridge_agpstat, TRUE);
 			return;
 		} else {
 		    /* Disable calibration cycle in RX91<1> when not in AGP3.0 mode of operation.*/
-		    command &= ~(7<<10) ;
-		    pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &temp);
+		    bridge_agpstat &= ~(7<<10) ;
+		    pci_read_config_dword(bridge->dev,
+					bridge->capndx+AGPCTRL, &temp);
 		    temp |= (1<<9);
-		    pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, temp);
+		    pci_write_config_dword(bridge->dev,
+					bridge->capndx+AGPCTRL, temp);
 
 		    printk (KERN_INFO PFX "Device is in legacy mode,"
 				" falling back to 2.x\n");
@@ -644,12 +740,12 @@ void agp_generic_enable(u32 mode)
 	}
 
 	/* AGP v<3 */
-	agp_device_command(command, FALSE);
+	agp_device_command(bridge_agpstat, FALSE);
 }
 EXPORT_SYMBOL(agp_generic_enable);
 
 
-int agp_generic_create_gatt_table(void)
+int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	char *table;
 	char *table_end;
@@ -661,17 +757,17 @@ int agp_generic_create_gatt_table(void)
 	struct page *page;
 
 	/* The generic routines can't handle 2 level gatt's */
-	if (agp_bridge->driver->size_type == LVL2_APER_SIZE)
+	if (bridge->driver->size_type == LVL2_APER_SIZE)
 		return -EINVAL;
 
 	table = NULL;
-	i = agp_bridge->aperture_size_idx;
-	temp = agp_bridge->current_size;
+	i = bridge->aperture_size_idx;
+	temp = bridge->current_size;
 	size = page_order = num_entries = 0;
 
-	if (agp_bridge->driver->size_type != FIXED_APER_SIZE) {
+	if (bridge->driver->size_type != FIXED_APER_SIZE) {
 		do {
-			switch (agp_bridge->driver->size_type) {
+			switch (bridge->driver->size_type) {
 			case U8_APER_SIZE:
 				size = A_SIZE_8(temp)->size;
 				page_order =
@@ -697,39 +793,38 @@ int agp_generic_create_gatt_table(void)
 				break;
 			}
 
-			table = (char *) __get_free_pages(GFP_KERNEL,
-							  page_order);
+			table = alloc_gatt_pages(page_order);
 
 			if (table == NULL) {
 				i++;
-				switch (agp_bridge->driver->size_type) {
+				switch (bridge->driver->size_type) {
 				case U8_APER_SIZE:
-					agp_bridge->current_size = A_IDX8(agp_bridge);
+					bridge->current_size = A_IDX8(bridge);
 					break;
 				case U16_APER_SIZE:
-					agp_bridge->current_size = A_IDX16(agp_bridge);
+					bridge->current_size = A_IDX16(bridge);
 					break;
 				case U32_APER_SIZE:
-					agp_bridge->current_size = A_IDX32(agp_bridge);
+					bridge->current_size = A_IDX32(bridge);
 					break;
 					/* This case will never really happen. */
 				case FIXED_APER_SIZE:
 				case LVL2_APER_SIZE:
 				default:
-					agp_bridge->current_size =
-					    agp_bridge->current_size;
+					bridge->current_size =
+					    bridge->current_size;
 					break;
 				}
-				temp = agp_bridge->current_size;
+				temp = bridge->current_size;
 			} else {
-				agp_bridge->aperture_size_idx = i;
+				bridge->aperture_size_idx = i;
 			}
-		} while (!table && (i < agp_bridge->driver->num_aperture_sizes));
+		} while (!table && (i < bridge->driver->num_aperture_sizes));
 	} else {
 		size = ((struct aper_size_info_fixed *) temp)->size;
 		page_order = ((struct aper_size_info_fixed *) temp)->page_order;
 		num_entries = ((struct aper_size_info_fixed *) temp)->num_entries;
-		table = (char *) __get_free_pages(GFP_KERNEL, page_order);
+		table = alloc_gatt_pages(page_order);
 	}
 
 	if (table == NULL)
@@ -740,44 +835,44 @@ int agp_generic_create_gatt_table(void)
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		SetPageReserved(page);
 
-	agp_bridge->gatt_table_real = (u32 *) table;
+	bridge->gatt_table_real = (u32 *) table;
 	agp_gatt_table = (void *)table;
 
-	agp_bridge->driver->cache_flush();
-	agp_bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
+	bridge->driver->cache_flush();
+	bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
 					(PAGE_SIZE * (1 << page_order)));
-	agp_bridge->driver->cache_flush();
+	bridge->driver->cache_flush();
 
-	if (agp_bridge->gatt_table == NULL) {
+	if (bridge->gatt_table == NULL) {
 		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 			ClearPageReserved(page);
 
-		free_pages((unsigned long) table, page_order);
+		free_gatt_pages(table, page_order);
 
 		return -ENOMEM;
 	}
-	agp_bridge->gatt_bus_addr = virt_to_phys(agp_bridge->gatt_table_real);
+	bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real);
 
 	/* AK: bogus, should encode addresses > 4GB */
 	for (i = 0; i < num_entries; i++) {
-		writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i);
-		readl(agp_bridge->gatt_table+i);	/* PCI Posting. */
+		writel(bridge->scratch_page, bridge->gatt_table+i);
+		readl(bridge->gatt_table+i);	/* PCI Posting. */
 	}
 
 	return 0;
 }
 EXPORT_SYMBOL(agp_generic_create_gatt_table);
 
-int agp_generic_free_gatt_table(void)
+int agp_generic_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	int page_order;
 	char *table, *table_end;
 	void *temp;
 	struct page *page;
 
-	temp = agp_bridge->current_size;
+	temp = bridge->current_size;
 
-	switch (agp_bridge->driver->size_type) {
+	switch (bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		page_order = A_SIZE_8(temp)->page_order;
 		break;
@@ -803,19 +898,19 @@ int agp_generic_free_gatt_table(void)
 	 * called, then all agp memory is deallocated and removed
 	 * from the table. */
 
-	iounmap(agp_bridge->gatt_table);
-	table = (char *) agp_bridge->gatt_table_real;
+	iounmap(bridge->gatt_table);
+	table = (char *) bridge->gatt_table_real;
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		ClearPageReserved(page);
 
-	free_pages((unsigned long) agp_bridge->gatt_table_real, page_order);
+	free_gatt_pages(bridge->gatt_table_real, page_order);
 
 	agp_gatt_table = NULL;
-	agp_bridge->gatt_table = NULL;
-	agp_bridge->gatt_table_real = NULL;
-	agp_bridge->gatt_bus_addr = 0;
+	bridge->gatt_table = NULL;
+	bridge->gatt_table_real = NULL;
+	bridge->gatt_bus_addr = 0;
 
 	return 0;
 }
@@ -828,10 +923,15 @@ int agp_generic_insert_memory(struct agp
 	size_t i;
 	off_t j;
 	void *temp;
+	struct agp_bridge_data *bridge;
 
-	temp = agp_bridge->current_size;
+	bridge = mem->bridge;
+	if (!bridge)
+		return -EINVAL;
 
-	switch (agp_bridge->driver->size_type) {
+	temp = bridge->current_size;
+
+	switch (bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		num_entries = A_SIZE_8(temp)->num_entries;
 		break;
@@ -868,22 +968,22 @@ int agp_generic_insert_memory(struct agp
 	j = pg_start;
 
 	while (j < (pg_start + mem->page_count)) {
-		if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j)))
+		if (!PGE_EMPTY(bridge, readl(bridge->gatt_table+j)))
 			return -EBUSY;
 		j++;
 	}
 
 	if (mem->is_flushed == FALSE) {
-		agp_bridge->driver->cache_flush();
+		bridge->driver->cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+j);
-		readl(agp_bridge->gatt_table+j);	/* PCI Posting. */
+		writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
+		readl(bridge->gatt_table+j);	/* PCI Posting. */
 	}
 
-	agp_bridge->driver->tlb_flush(mem);
+	bridge->driver->tlb_flush(mem);
 	return 0;
 }
 EXPORT_SYMBOL(agp_generic_insert_memory);
@@ -892,6 +992,11 @@ EXPORT_SYMBOL(agp_generic_insert_memory)
 int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
 	size_t i;
+	struct agp_bridge_data *bridge;
+
+	bridge = mem->bridge;
+	if (!bridge)
+		return -EINVAL;
 
 	if (type != 0 || mem->type != 0) {
 		/* The generic routines know nothing of memory types */
@@ -900,12 +1005,12 @@ int agp_generic_remove_memory(struct agp
 
 	/* AK: bogus, should encode addresses > 4GB */
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-		writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i);
-		readl(agp_bridge->gatt_table+i);	/* PCI Posting. */
+		writel(bridge->scratch_page, bridge->gatt_table+i);
+		readl(bridge->gatt_table+i);	/* PCI Posting. */
 	}
 
 	global_cache_flush();
-	agp_bridge->driver->tlb_flush(mem);
+	bridge->driver->tlb_flush(mem);
 	return 0;
 }
 EXPORT_SYMBOL(agp_generic_remove_memory);
@@ -920,9 +1025,7 @@ EXPORT_SYMBOL(agp_generic_alloc_by_type)
 
 void agp_generic_free_by_type(struct agp_memory *curr)
 {
-	if (curr->memory != NULL)
-		vfree(curr->memory);
-
+	vfree(curr->memory);
 	agp_free_key(curr->key);
 	kfree(curr);
 }
@@ -936,7 +1039,7 @@ EXPORT_SYMBOL(agp_generic_free_by_type);
  * against a maximum value.
  */
 
-void *agp_generic_alloc_page(void)
+void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
 {
 	struct page * page;
 
@@ -978,14 +1081,25 @@ EXPORT_SYMBOL(agp_generic_destroy_page);
  *
  * @mode:	agp mode register value to configure with.
  */
-void agp_enable(u32 mode)
+void agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
-	if (agp_bridge->type == NOT_SUPPORTED)
+	if (!bridge)
 		return;
-	agp_bridge->driver->agp_enable(mode);
+	bridge->driver->agp_enable(bridge, mode);
 }
 EXPORT_SYMBOL(agp_enable);
 
+/* When we remove the global variable agp_bridge from all drivers
+ * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
+ */
+
+struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev)
+{
+	if (list_empty(&agp_bridges))
+		return NULL;
+
+	return agp_bridge;
+}
 
 static void ipi_handler(void *null)
 {
@@ -999,11 +1113,12 @@ void global_cache_flush(void)
 }
 EXPORT_SYMBOL(global_cache_flush);
 
-unsigned long agp_generic_mask_memory(unsigned long addr, int type)
+unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
+	unsigned long addr, int type)
 {
 	/* memory type is ignored in the generic routine */
-	if (agp_bridge->driver->masks)
-		return addr | agp_bridge->driver->masks[0].mask;
+	if (bridge->driver->masks)
+		return addr | bridge->driver->masks[0].mask;
 	else
 		return addr;
 }
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -110,7 +110,7 @@ static int __init hp_zx1_ioc_shared(void
 	hp->gart_size = HP_ZX1_GART_SIZE;
 	hp->gatt_entries = hp->gart_size / hp->io_page_size;
 
-	hp->io_pdir = phys_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
+	hp->io_pdir = gart_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
 	hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
 
 	if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
@@ -248,7 +248,7 @@ hp_zx1_configure (void)
 	agp_bridge->mode = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS);
 
 	if (hp->io_pdir_owner) {
-		writel(virt_to_phys(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
+		writel(virt_to_gart(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
 		readl(hp->ioc_regs+HP_ZX1_PDIR_BASE);
 		writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG);
 		readl(hp->ioc_regs+HP_ZX1_TCNFG);
@@ -289,7 +289,7 @@ hp_zx1_tlbflush (struct agp_memory *mem)
 }
 
 static int
-hp_zx1_create_gatt_table (void)
+hp_zx1_create_gatt_table (struct agp_bridge_data *bridge)
 {
 	struct _hp_private *hp = &hp_private;
 	int i;
@@ -317,7 +317,7 @@ hp_zx1_create_gatt_table (void)
 }
 
 static int
-hp_zx1_free_gatt_table (void)
+hp_zx1_free_gatt_table (struct agp_bridge_data *bridge)
 {
 	struct _hp_private *hp = &hp_private;
 
@@ -367,7 +367,9 @@ hp_zx1_insert_memory (struct agp_memory 
 		for (k = 0;
 		     k < hp->io_pages_per_kpage;
 		     k++, j++, paddr += hp->io_page_size) {
-			hp->gatt[j] = agp_bridge->driver->mask_memory(paddr, type);
+			hp->gatt[j] =
+				agp_bridge->driver->mask_memory(agp_bridge,
+					paddr, type);
 		}
 	}
 
@@ -396,19 +398,20 @@ hp_zx1_remove_memory (struct agp_memory 
 }
 
 static unsigned long
-hp_zx1_mask_memory (unsigned long addr, int type)
+hp_zx1_mask_memory (struct agp_bridge_data *bridge,
+	unsigned long addr, int type)
 {
 	return HP_ZX1_PDIR_VALID_BIT | addr;
 }
 
 static void
-hp_zx1_enable (u32 mode)
+hp_zx1_enable (struct agp_bridge_data *bridge, u32 mode)
 {
 	struct _hp_private *hp = &hp_private;
 	u32 command;
 
 	command = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS);
-	command = agp_collect_device_status(mode, command);
+	command = agp_collect_device_status(bridge, mode, command);
 	command |= 0x00000100;
 
 	writel(command, hp->lba_regs+hp->lba_cap_offset+PCI_AGP_COMMAND);
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -233,7 +233,7 @@ static int i460_configure (void)
 	return 0;
 }
 
-static int i460_create_gatt_table (void)
+static int i460_create_gatt_table (struct agp_bridge_data *bridge)
 {
 	int page_order, num_entries, i;
 	void *temp;
@@ -258,7 +258,7 @@ static int i460_create_gatt_table (void)
 	return 0;
 }
 
-static int i460_free_gatt_table (void)
+static int i460_free_gatt_table (struct agp_bridge_data *bridge)
 {
 	int num_entries, i;
 	void *temp;
@@ -314,7 +314,8 @@ static int i460_insert_memory_small_io_p
 	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
 		paddr = mem->memory[i];
 		for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size)
-			WR_GATT(j, agp_bridge->driver->mask_memory(paddr, mem->type));
+			WR_GATT(j, agp_bridge->driver->mask_memory(agp_bridge,
+				paddr, mem->type));
 	}
 	WR_FLUSH_GATT(j - 1);
 	return 0;
@@ -371,7 +372,7 @@ static int i460_alloc_large_page (struct
 	}
 	memset(lp->alloced_map, 0, map_size);
 
-	lp->paddr = virt_to_phys(lpage);
+	lp->paddr = virt_to_gart(lpage);
 	lp->refcount = 0;
 	atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
 	return 0;
@@ -382,7 +383,7 @@ static void i460_free_large_page (struct
 	kfree(lp->alloced_map);
 	lp->alloced_map = NULL;
 
-	free_pages((unsigned long) phys_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT);
+	free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT);
 	atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
 }
 
@@ -427,7 +428,8 @@ static int i460_insert_memory_large_io_p
 			if (i460_alloc_large_page(lp) < 0)
 				return -ENOMEM;
 			pg = lp - i460.lp_desc;
-			WR_GATT(pg, agp_bridge->driver->mask_memory(lp->paddr, 0));
+			WR_GATT(pg, agp_bridge->driver->mask_memory(agp_bridge,
+				lp->paddr, 0));
 			WR_FLUSH_GATT(pg);
 		}
 
@@ -508,12 +510,12 @@ static int i460_remove_memory (struct ag
  * Let's just hope nobody counts on the allocated AGP memory being there before bind time
  * (I don't think current drivers do)...
  */
-static void *i460_alloc_page (void)
+static void *i460_alloc_page (struct agp_bridge_data *bridge)
 {
 	void *page;
 
 	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT)
-		page = agp_generic_alloc_page();
+		page = agp_generic_alloc_page(agp_bridge);
 	else
 		/* Returning NULL would cause problems */
 		/* AK: really dubious code. */
@@ -529,10 +531,11 @@ static void i460_destroy_page (void *pag
 
 #endif /* I460_LARGE_IO_PAGES */
 
-static unsigned long i460_mask_memory (unsigned long addr, int type)
+static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
+	unsigned long addr, int type)
 {
 	/* Make sure the returned address is a valid GATT entry */
-	return agp_bridge->driver->masks[0].mask
+	return bridge->driver->masks[0].mask
 		| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12);
 }
 
@@ -624,7 +627,7 @@ static int __init agp_intel_i460_init(vo
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_intel_i460_pci_driver);
+	return pci_register_driver(&agp_intel_i460_pci_driver);
 }
 
 static void __exit agp_intel_i460_cleanup(void)
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -150,7 +150,7 @@ static void intel_i810_tlbflush(struct a
 	return;
 }
 
-static void intel_i810_agp_enable(u32 mode)
+static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
 	return;
 }
@@ -229,8 +229,9 @@ static int intel_i810_insert_entries(str
 insert:
 	global_cache_flush();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type),
-				intel_i810_private.registers+I810_PTE_BASE+(j*4));
+		writel(agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type),
+			intel_i810_private.registers+I810_PTE_BASE+(j*4));
 		readl(intel_i810_private.registers+I810_PTE_BASE+(j*4));	/* PCI Posting. */
 	}
 	global_cache_flush();
@@ -268,7 +269,7 @@ static struct agp_memory *alloc_agpphysm
 		return NULL;
 
 	switch (pg_count) {
-	case 1: addr = agp_bridge->driver->agp_alloc_page();
+	case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
 		break;
 	case 4:
 		/* kludge to get 4 physical pages for ARGB cursor */
@@ -285,7 +286,7 @@ static struct agp_memory *alloc_agpphysm
 	if (new == NULL)
 		return NULL;
 
-	new->memory[0] = virt_to_phys(addr);
+	new->memory[0] = virt_to_gart(addr);
 	if (pg_count == 4) {
 		/* kludge to get 4 physical pages for ARGB cursor */
 		new->memory[1] = new->memory[0] + PAGE_SIZE;
@@ -328,19 +329,20 @@ static void intel_i810_free_by_type(stru
 	agp_free_key(curr->key);
 	if(curr->type == AGP_PHYS_MEMORY) {
 		if (curr->page_count == 4)
-			i8xx_destroy_pages(phys_to_virt(curr->memory[0]));
+			i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
 		else
 			agp_bridge->driver->agp_destroy_page(
-				 phys_to_virt(curr->memory[0]));
+				 gart_to_virt(curr->memory[0]));
 		vfree(curr->memory);
 	}
 	kfree(curr);
 }
 
-static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
+static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
+	unsigned long addr, int type)
 {
 	/* Type checking must be done elsewhere */
-	return addr | agp_bridge->driver->masks[type].mask;
+	return addr | bridge->driver->masks[type].mask;
 }
 
 static struct aper_size_info_fixed intel_i830_sizes[] =
@@ -416,7 +418,8 @@ static void intel_i830_init_gtt_entries(
 		case I915_GMCH_GMS_STOLEN_48M:
 			/* Check it's really I915G */
 			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
-			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB)
 				gtt_entries = MB(48) - KB(size);
 			else
 				gtt_entries = 0;
@@ -424,7 +427,8 @@ static void intel_i830_init_gtt_entries(
 		case I915_GMCH_GMS_STOLEN_64M:
 			/* Check it's really I915G */
 			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
-			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB)
 				gtt_entries = MB(64) - KB(size);
 			else
 				gtt_entries = 0;
@@ -447,7 +451,7 @@ static void intel_i830_init_gtt_entries(
 /* The intel i830 automatically initializes the agp aperture during POST.
  * Use the memory already set aside for in the GTT.
  */
-static int intel_i830_create_gatt_table(void)
+static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	int page_order;
 	struct aper_size_info_fixed *size;
@@ -482,7 +486,7 @@ static int intel_i830_create_gatt_table(
 /* Return the gatt table to a sane state. Use the top of stolen
  * memory for the GTT.
  */
-static int intel_i830_free_gatt_table(void)
+static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	return 0;
 }
@@ -582,8 +586,9 @@ static int intel_i830_insert_entries(str
 	global_cache_flush();	/* FIXME: Necessary ?*/
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type),
-				intel_i830_private.registers+I810_PTE_BASE+(j*4));
+		writel(agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type),
+			intel_i830_private.registers+I810_PTE_BASE+(j*4));
 		readl(intel_i830_private.registers+I810_PTE_BASE+(j*4));	/* PCI Posting. */
 	}
 
@@ -691,7 +696,8 @@ static int intel_i915_insert_entries(str
 	global_cache_flush();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), intel_i830_private.gtt+j);
+		writel(agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type), intel_i830_private.gtt+j);
 		readl(intel_i830_private.gtt+j);	/* PCI Posting. */
 	}
 
@@ -743,7 +749,7 @@ static int intel_i915_fetch_size(void)
 /* The intel i915 automatically initializes the agp aperture during POST.
  * Use the memory already set aside for in the GTT.
  */
-static int intel_i915_create_gatt_table(void)
+static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	int page_order;
 	struct aper_size_info_fixed *size;
@@ -1658,6 +1664,14 @@ static int __devinit agp_intel_probe(str
 		}
 		name = "915GM";
 		break;
+	case PCI_DEVICE_ID_INTEL_82945G_HB:
+		if (find_i830(PCI_DEVICE_ID_INTEL_82945G_IG)) {
+			bridge->driver = &intel_915_driver;
+		} else {
+			bridge->driver = &intel_845_driver;
+		}
+		name = "945G";
+		break;
 	case PCI_DEVICE_ID_INTEL_7505_0:
 		bridge->driver = &intel_7505_driver;
 		name = "E7505";
@@ -1758,6 +1772,8 @@ static int agp_intel_resume(struct pci_d
 		intel_i915_configure();
 	else if (bridge->driver == &intel_830_driver)
 		intel_i830_configure();
+	else if (bridge->driver == &intel_810_driver)
+		intel_i810_configure();
 
 	return 0;
 }
@@ -1795,6 +1811,7 @@ static struct pci_device_id agp_intel_pc
 	ID(PCI_DEVICE_ID_INTEL_7205_0),
 	ID(PCI_DEVICE_ID_INTEL_82915G_HB),
 	ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
+	ID(PCI_DEVICE_ID_INTEL_82945G_HB),
 	{ }
 };
 
@@ -1810,7 +1827,9 @@ static struct pci_driver agp_intel_pci_d
 
 static int __init agp_intel_init(void)
 {
-	return pci_module_init(&agp_intel_pci_driver);
+	if (agp_off)
+		return -EINVAL;
+	return pci_register_driver(&agp_intel_pci_driver);
 }
 
 static void __exit agp_intel_cleanup(void)
diff --git a/drivers/char/agp/intel-mch-agp.c b/drivers/char/agp/intel-mch-agp.c
deleted file mode 100644
--- a/drivers/char/agp/intel-mch-agp.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * Intel MCH AGPGART routines.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/agp_backend.h>
-#include "agp.h"
-
-
-#define AGP_DCACHE_MEMORY	1
-#define AGP_PHYS_MEMORY		2
-
-static struct gatt_mask intel_i810_masks[] =
-{
-	{.mask = I810_PTE_VALID, .type = 0},
-	{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
-	{.mask = I810_PTE_VALID, .type = 0}
-};
-
-static void intel_i810_tlbflush(struct agp_memory *mem)
-{
-	return;
-}
-
-static void intel_i810_agp_enable(u32 mode)
-{
-	return;
-}
-
-
-/*
- * The i810/i830 requires a physical address to program its mouse
- * pointer into hardware.
- * However the Xserver still writes to it through the agp aperture.
- */
-static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
-{
-	struct agp_memory *new;
-	void *addr;
-
-	if (pg_count != 1)
-		return NULL;
-
-	addr = agp_bridge->driver->agp_alloc_page();
-	if (addr == NULL)
-		return NULL;
-
-	new = agp_create_memory(1);
-	if (new == NULL)
-		return NULL;
-
-	new->memory[0] = virt_to_phys(addr);
-	new->page_count = 1;
-	new->num_scratch_pages = 1;
-	new->type = AGP_PHYS_MEMORY;
-	new->physical = new->memory[0];
-	return new;
-}
-
-static void intel_i810_free_by_type(struct agp_memory *curr)
-{
-	agp_free_key(curr->key);
-	if(curr->type == AGP_PHYS_MEMORY) {
-		agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0]));
-		vfree(curr->memory);
-	}
-	kfree(curr);
-}
-
-static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
-{
-	/* Type checking must be done elsewhere */
-	return addr | agp_bridge->driver->masks[type].mask;
-}
-
-static struct aper_size_info_fixed intel_i830_sizes[] =
-{
-	{128, 32768, 5},
-	/* The 64M mode still requires a 128k gatt */
-	{64, 16384, 5}
-};
-
-static struct _intel_i830_private {
-	struct pci_dev *i830_dev;		/* device one */
-	volatile u8 __iomem *registers;
-	int gtt_entries;
-} intel_i830_private;
-
-static void intel_i830_init_gtt_entries(void)
-{
-	u16 gmch_ctrl;
-	int gtt_entries;
-	u8 rdct;
-	int local = 0;
-	static const int ddt[4] = { 0, 16, 32, 64 };
-
-	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
-
-	if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-	    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
-		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-		case I830_GMCH_GMS_STOLEN_512:
-			gtt_entries = KB(512) - KB(132);
-			break;
-		case I830_GMCH_GMS_STOLEN_1024:
-			gtt_entries = MB(1) - KB(132);
-			break;
-		case I830_GMCH_GMS_STOLEN_8192:
-			gtt_entries = MB(8) - KB(132);
-			break;
-		case I830_GMCH_GMS_LOCAL:
-			rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE);
-			gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
-					MB(ddt[I830_RDRAM_DDT(rdct)]);
-			local = 1;
-			break;
-		default:
-			gtt_entries = 0;
-			break;
-		}
-	} else {
-		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-		case I855_GMCH_GMS_STOLEN_1M:
-			gtt_entries = MB(1) - KB(132);
-			break;
-		case I855_GMCH_GMS_STOLEN_4M:
-			gtt_entries = MB(4) - KB(132);
-			break;
-		case I855_GMCH_GMS_STOLEN_8M:
-			gtt_entries = MB(8) - KB(132);
-			break;
-		case I855_GMCH_GMS_STOLEN_16M:
-			gtt_entries = MB(16) - KB(132);
-			break;
-		case I855_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(132);
-			break;
-		default:
-			gtt_entries = 0;
-			break;
-		}
-	}
-	if (gtt_entries > 0)
-		printk(KERN_INFO PFX "Detected %dK %s memory.\n",
-		       gtt_entries / KB(1), local ? "local" : "stolen");
-	else
-		printk(KERN_INFO PFX
-		       "No pre-allocated video memory detected.\n");
-	gtt_entries /= KB(4);
-
-	intel_i830_private.gtt_entries = gtt_entries;
-}
-
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(void)
-{
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp;
-
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
-
-	pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
-	temp &= 0xfff80000;
-
-	intel_i830_private.registers = (volatile u8 __iomem*) ioremap(temp,128 * 4096);
-	if (!intel_i830_private.registers)
-		return -ENOMEM;
-
-	temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();	/* FIXME: ?? */
-
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-
-	agp_bridge->gatt_table = NULL;
-
-	agp_bridge->gatt_bus_addr = temp;
-
-	return 0;
-}
-
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(void)
-{
-	return 0;
-}
-
-static int intel_i830_fetch_size(void)
-{
-	u16 gmch_ctrl;
-	struct aper_size_info_fixed *values;
-
-	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-	if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-	    agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-		/* 855GM/852GM/865G has 128MB aperture size */
-		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	}
-
-	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
-
-	if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	} else {
-		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 1;
-		return values[1].size;
-	}
-
-	return 0;
-}
-
-static int intel_i830_configure(void)
-{
-	struct aper_size_info_fixed *current_size;
-	u32 temp;
-	u16 gmch_ctrl;
-	int i;
-
-	current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-	pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
-	gmch_ctrl |= I830_GMCH_ENABLED;
-	pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
-
-	writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL);
-	readl(intel_i830_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
-
-	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) {
-			writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4));
-			readl(intel_i830_private.registers+I810_PTE_BASE+(i*4));	/* PCI Posting. */
-		}
-	}
-	global_cache_flush();
-	return 0;
-}
-
-static void intel_i830_cleanup(void)
-{
-	iounmap((void __iomem *) intel_i830_private.registers);
-}
-
-static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start,
-				int type)
-{
-	int i,j,num_entries;
-	void *temp;
-
-	temp = agp_bridge->current_size;
-	num_entries = A_SIZE_FIX(temp)->num_entries;
-
-	if (pg_start < intel_i830_private.gtt_entries) {
-		printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
-				pg_start,intel_i830_private.gtt_entries);
-
-		printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
-		return -EINVAL;
-	}
-
-	if ((pg_start + mem->page_count) > num_entries)
-		return -EINVAL;
-
-	/* The i830 can't check the GTT for entries since its read only,
-	 * depend on the caller to make the correct offset decisions.
-	 */
-
-	if ((type != 0 && type != AGP_PHYS_MEMORY) ||
-		(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
-		return -EINVAL;
-
-	global_cache_flush();	/* FIXME: ?? */
-
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type),
-				intel_i830_private.registers+I810_PTE_BASE+(j*4));
-		readl(intel_i830_private.registers+I810_PTE_BASE+(j*4));	/* PCI Posting. */
-	}
-
-	global_cache_flush();
-
-	agp_bridge->driver->tlb_flush(mem);
-
-	return 0;
-}
-
-static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
-				int type)
-{
-	int i;
-
-	global_cache_flush();
-
-	if (pg_start < intel_i830_private.gtt_entries) {
-		printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
-		return -EINVAL;
-	}
-
-	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-		writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4));
-		readl(intel_i830_private.registers+I810_PTE_BASE+(i*4));	/* PCI Posting. */
-	}
-
-	global_cache_flush();
-	agp_bridge->driver->tlb_flush(mem);
-	return 0;
-}
-
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
-{
-	if (type == AGP_PHYS_MEMORY)
-		return alloc_agpphysmem_i8xx(pg_count, type);
-
-	/* always return NULL for other allocation types for now */
-	return NULL;
-}
-
-static int intel_8xx_fetch_size(void)
-{
-	u8 temp;
-	int i;
-	struct aper_size_info_8 *values;
-
-	pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
-
-	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
-
-	for (i = 0; i < agp_bridge->driver->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;
-		}
-	}
-	return 0;
-}
-
-static void intel_8xx_tlbflush(struct agp_memory *mem)
-{
-	u32 temp;
-	pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
-	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp & ~(1 << 7));
-	pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
-	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp | (1 << 7));
-}
-
-static void intel_8xx_cleanup(void)
-{
-	u16 temp;
-	struct aper_size_info_8 *previous_size;
-
-	previous_size = A_SIZE_8(agp_bridge->previous_size);
-	pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
-	pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
-	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
-}
-
-static int intel_845_configure(void)
-{
-	u32 temp;
-	u8 temp2;
-	struct aper_size_info_8 *current_size;
-
-	current_size = A_SIZE_8(agp_bridge->current_size);
-
-	/* aperture size */
-	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); 
-
-	/* address to map to */
-	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-	/* attbase - aperture base */
-	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); 
-
-	/* agpctrl */
-	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); 
-
-	/* agpm */
-	pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2);
-	pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
-	/* clear any possible error conditions */
-	pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); 
-	return 0;
-}
-
-
-/* Setup function */
-static struct gatt_mask intel_generic_masks[] =
-{
-	{.mask = 0x00000017, .type = 0}
-};
-
-static struct aper_size_info_8 intel_8xx_sizes[7] =
-{
-	{256, 65536, 6, 0},
-	{128, 32768, 5, 32},
-	{64, 16384, 4, 48},
-	{32, 8192, 3, 56},
-	{16, 4096, 2, 60},
-	{8, 2048, 1, 62},
-	{4, 1024, 0, 63}
-};
-
-static struct agp_bridge_driver intel_830_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes 	= 2,
-	.needs_scratch_page	= TRUE,
-	.configure		= intel_i830_configure,
-	.fetch_size		= intel_i830_fetch_size,
-	.cleanup		= intel_i830_cleanup,
-	.tlb_flush		= intel_i810_tlbflush,
-	.mask_memory		= intel_i810_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i830_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i830_insert_entries,
-	.remove_memory		= intel_i830_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_destroy_page	= agp_generic_destroy_page,
-};
-
-static struct agp_bridge_driver intel_845_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_8xx_sizes,
-	.size_type		= U8_APER_SIZE,
-	.num_aperture_sizes	= 7,
-	.configure		= intel_845_configure,
-	.fetch_size		= intel_8xx_fetch_size,
-	.cleanup		= intel_8xx_cleanup,
-	.tlb_flush		= intel_8xx_tlbflush,
-	.mask_memory		= agp_generic_mask_memory,
-	.masks			= intel_generic_masks,
-	.agp_enable		= agp_generic_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= agp_generic_create_gatt_table,
-	.free_gatt_table	= agp_generic_free_gatt_table,
-	.insert_memory		= agp_generic_insert_memory,
-	.remove_memory		= agp_generic_remove_memory,
-	.alloc_by_type		= agp_generic_alloc_by_type,
-	.free_by_type		= agp_generic_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_destroy_page	= agp_generic_destroy_page,
-};
-
-
-static int find_i830(u16 device)
-{
-	struct pci_dev *i830_dev;
-
-	i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
-	if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) {
-		i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				device, i830_dev);
-	}
-
-	if (!i830_dev)
-		return 0;
-
-	intel_i830_private.i830_dev = i830_dev;
-	return 1;
-}
-
-static int __devinit agp_intelmch_probe(struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
-{
-	struct agp_bridge_data *bridge;
-	struct resource *r;
-	char *name = "(unknown)";
-	u8 cap_ptr = 0;
-
-	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
-	if (!cap_ptr) 
-		return -ENODEV;
-
-	bridge = agp_alloc_bridge();
-	if (!bridge)
-		return -ENOMEM;
-
-	switch (pdev->device) {
-	case PCI_DEVICE_ID_INTEL_82865_HB:
-		if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) {
-			bridge->driver = &intel_830_driver;
-		} else {
-			bridge->driver = &intel_845_driver;
-		}
-		name = "865";
-		break;
-	case PCI_DEVICE_ID_INTEL_82875_HB:
-		bridge->driver = &intel_845_driver;
-		name = "i875";
-		break;
-
-	default:
-		printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x)\n",
-			    pdev->device);
-		return -ENODEV;
-	};
-
-	bridge->dev = pdev;
-	bridge->capndx = cap_ptr;
-
-	if (bridge->driver == &intel_830_driver)
-		bridge->dev_private_data = &intel_i830_private;
-
-	printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name);
-
-	/*
-	* The following fixes the case where the BIOS has "forgotten" to
-	* provide an address range for the GART.
-	* 20030610 - hamish@zot.org
-	*/
-	r = &pdev->resource[0];
-	if (!r->start && r->end) {
-		if(pci_assign_resource(pdev, 0)) {
-			printk(KERN_ERR PFX "could not assign resource 0\n");
-			return -ENODEV;
-		}
-	}
-
-	/*
-	* If the device has not been properly setup, the following will catch
-	* the problem and should stop the system from crashing.
-	* 20030610 - hamish@zot.org
-	*/
-	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR PFX "Unable to Enable PCI device\n");
-		return -ENODEV;
-	}
-
-	/* Fill in the mode register */
-	if (cap_ptr) {
-		pci_read_config_dword(pdev,
-				bridge->capndx+PCI_AGP_STATUS,
-				&bridge->mode);
-	}
-
-	pci_set_drvdata(pdev, bridge);
-	return agp_add_bridge(bridge);
-}
-
-static void __devexit agp_intelmch_remove(struct pci_dev *pdev)
-{
-	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
-
-	agp_remove_bridge(bridge);
-	if (intel_i830_private.i830_dev)
-		pci_dev_put(intel_i830_private.i830_dev);
-	agp_put_bridge(bridge);
-}
-
-static int agp_intelmch_resume(struct pci_dev *pdev)
-{
-	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
-
-	pci_restore_state(pdev);
-
-	if (bridge->driver == &intel_845_driver)
-		intel_845_configure();
-
-	return 0;
-}
-
-static struct pci_device_id agp_intelmch_pci_table[] = {
-	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_INTEL,
-	.device		= PCI_DEVICE_ID_INTEL_82865_HB,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
-	},
-	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_INTEL,
-	.device		= PCI_DEVICE_ID_INTEL_82875_HB,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
-	},
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, agp_intelmch_pci_table);
-
-static struct pci_driver agp_intelmch_pci_driver = {
-	.name		= "agpgart-intel-mch",
-	.id_table	= agp_intelmch_pci_table,
-	.probe		= agp_intelmch_probe,
-	.remove		= agp_intelmch_remove,
-	.resume		= agp_intelmch_resume,
-};
-
-/* intel_agp_init() must not be declared static for explicit
-   early initialization to work (ie i810fb) */
-int __init agp_intelmch_init(void)
-{
-	static int agp_initialised=0;
-
-	if (agp_initialised == 1)
-		return 0;
-	agp_initialised=1;
-
-	return pci_module_init(&agp_intelmch_pci_driver);
-}
-
-static void __exit agp_intelmch_cleanup(void)
-{
-	pci_unregister_driver(&agp_intelmch_pci_driver);
-}
-
-module_init(agp_intelmch_init);
-module_exit(agp_intelmch_cleanup);
-
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -215,7 +215,8 @@ static int nvidia_insert_memory(struct a
 		mem->is_flushed = TRUE;
 	}
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type),
+		writel(agp_bridge->driver->mask_memory(agp_bridge,
+			mem->memory[i], mem->type),
 			agp_bridge->gatt_table+nvidia_private.pg_offset+j);
 		readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j);	/* PCI Posting. */
 	}
@@ -287,7 +288,7 @@ static struct gatt_mask nvidia_generic_m
 };
 
 
-struct agp_bridge_driver nvidia_driver = {
+static struct agp_bridge_driver nvidia_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= nvidia_generic_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -407,7 +408,7 @@ static int __init agp_nvidia_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_nvidia_pci_driver);
+	return pci_register_driver(&agp_nvidia_pci_driver);
 }
 
 static void __exit agp_nvidia_cleanup(void)
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/agp/sgi-agp.c
@@ -0,0 +1,337 @@
+/*
+ * 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) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * SGI TIOCA AGPGART routines.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioca_provider.h>
+#include "agp.h"
+
+extern int agp_memory_reserved;
+extern uint32_t tioca_gart_found;
+extern struct list_head tioca_list;
+static struct agp_bridge_data **sgi_tioca_agp_bridges;
+
+/*
+ * The aperature size and related information is set up at TIOCA init time.
+ * Values for this table will be extracted and filled in at
+ * sgi_tioca_fetch_size() time.
+ */
+
+static struct aper_size_info_fixed sgi_tioca_sizes[] = {
+	{0, 0, 0},
+};
+
+static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
+{
+	struct page *page;
+	int nid;
+	struct tioca_kernel *info =
+	    (struct tioca_kernel *)bridge->dev_private_data;
+
+	nid = info->ca_closest_node;
+	page = alloc_pages_node(nid, GFP_KERNEL, 0);
+	if (page == NULL) {
+		return 0;
+	}
+
+	get_page(page);
+	SetPageLocked(page);
+	atomic_inc(&agp_bridge->current_memory_agp);
+	return page_address(page);
+}
+
+/*
+ * Flush GART tlb's.  Cannot selectively flush based on memory so the mem
+ * arg is ignored.
+ */
+
+static void sgi_tioca_tlbflush(struct agp_memory *mem)
+{
+	tioca_tlbflush(mem->bridge->dev_private_data);
+}
+
+/*
+ * Given an address of a host physical page, turn it into a valid gart
+ * entry.
+ */
+static unsigned long
+sgi_tioca_mask_memory(struct agp_bridge_data *bridge,
+		      unsigned long addr, int type)
+{
+	return tioca_physpage_to_gart(addr);
+}
+
+static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+	tioca_fastwrite_enable(bridge->dev_private_data);
+}
+
+/*
+ * sgi_tioca_configure() doesn't have anything to do since the base CA driver
+ * has alreay set up the GART.
+ */
+
+static int sgi_tioca_configure(void)
+{
+	return 0;
+}
+
+/*
+ * Determine gfx aperature size.  This has already been determined by the
+ * CA driver init, so just need to set agp_bridge values accordingly.
+ */
+
+static int sgi_tioca_fetch_size(void)
+{
+	struct tioca_kernel *info =
+	    (struct tioca_kernel *)agp_bridge->dev_private_data;
+
+	sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
+	sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
+
+	return sgi_tioca_sizes[0].size;
+}
+
+static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
+{
+	struct tioca_kernel *info =
+	    (struct tioca_kernel *)bridge->dev_private_data;
+
+	bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
+	bridge->gatt_table = bridge->gatt_table_real;
+	bridge->gatt_bus_addr = info->ca_gfxgart_base;
+
+	return 0;
+}
+
+static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
+{
+	return 0;
+}
+
+static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
+				   int type)
+{
+	int num_entries;
+	size_t i;
+	off_t j;
+	void *temp;
+	struct agp_bridge_data *bridge;
+	u64 *table;
+
+	bridge = mem->bridge;
+	if (!bridge)
+		return -EINVAL;
+
+	table = (u64 *)bridge->gatt_table;
+
+	temp = bridge->current_size;
+
+	switch (bridge->driver->size_type) {
+	case U8_APER_SIZE:
+		num_entries = A_SIZE_8(temp)->num_entries;
+		break;
+	case U16_APER_SIZE:
+		num_entries = A_SIZE_16(temp)->num_entries;
+		break;
+	case U32_APER_SIZE:
+		num_entries = A_SIZE_32(temp)->num_entries;
+		break;
+	case FIXED_APER_SIZE:
+		num_entries = A_SIZE_FIX(temp)->num_entries;
+		break;
+	case LVL2_APER_SIZE:
+		return -EINVAL;
+		break;
+	default:
+		num_entries = 0;
+		break;
+	}
+
+	num_entries -= agp_memory_reserved / PAGE_SIZE;
+	if (num_entries < 0)
+		num_entries = 0;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	if ((pg_start + mem->page_count) > num_entries)
+		return -EINVAL;
+
+	j = pg_start;
+
+	while (j < (pg_start + mem->page_count)) {
+		if (table[j])
+			return -EBUSY;
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		bridge->driver->cache_flush();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		table[j] =
+		    bridge->driver->mask_memory(bridge, mem->memory[i],
+						mem->type);
+	}
+
+	bridge->driver->tlb_flush(mem);
+	return 0;
+}
+
+static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
+				   int type)
+{
+	size_t i;
+	struct agp_bridge_data *bridge;
+	u64 *table;
+
+	bridge = mem->bridge;
+	if (!bridge)
+		return -EINVAL;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	table = (u64 *)bridge->gatt_table;
+
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		table[i] = 0;
+	}
+
+	bridge->driver->tlb_flush(mem);
+	return 0;
+}
+
+static void sgi_tioca_cache_flush(void)
+{
+}
+
+/*
+ * Cleanup.  Nothing to do as the CA driver owns the GART.
+ */
+
+static void sgi_tioca_cleanup(void)
+{
+}
+
+static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge;
+
+	list_for_each_entry(bridge, &agp_bridges, list) {
+		if (bridge->dev->bus == pdev->bus)
+			break;
+	}
+	return bridge;
+}
+
+struct agp_bridge_driver sgi_tioca_driver = {
+	.owner = THIS_MODULE,
+	.size_type = U16_APER_SIZE,
+	.configure = sgi_tioca_configure,
+	.fetch_size = sgi_tioca_fetch_size,
+	.cleanup = sgi_tioca_cleanup,
+	.tlb_flush = sgi_tioca_tlbflush,
+	.mask_memory = sgi_tioca_mask_memory,
+	.agp_enable = sgi_tioca_agp_enable,
+	.cache_flush = sgi_tioca_cache_flush,
+	.create_gatt_table = sgi_tioca_create_gatt_table,
+	.free_gatt_table = sgi_tioca_free_gatt_table,
+	.insert_memory = sgi_tioca_insert_memory,
+	.remove_memory = sgi_tioca_remove_memory,
+	.alloc_by_type = agp_generic_alloc_by_type,
+	.free_by_type = agp_generic_free_by_type,
+	.agp_alloc_page = sgi_tioca_alloc_page,
+	.agp_destroy_page = agp_generic_destroy_page,
+	.cant_use_aperture = 1,
+	.needs_scratch_page = 0,
+	.num_aperture_sizes = 1,
+};
+
+static int __devinit agp_sgi_init(void)
+{
+	unsigned int j;
+	struct tioca_kernel *info;
+	struct pci_dev *pdev = NULL;
+
+	if (tioca_gart_found)
+		printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
+	else
+		return 0;
+
+	sgi_tioca_agp_bridges =
+	    (struct agp_bridge_data **)kmalloc(tioca_gart_found *
+					       sizeof(struct agp_bridge_data *),
+					       GFP_KERNEL);
+
+	j = 0;
+	list_for_each_entry(info, &tioca_list, ca_list) {
+		struct list_head *tmp;
+		list_for_each(tmp, info->ca_devices) {
+			u8 cap_ptr;
+			pdev = pci_dev_b(tmp);
+			if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
+				continue;
+			cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+			if (!cap_ptr)
+				continue;
+		}
+		sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
+		printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
+		       sgi_tioca_agp_bridges[j]);
+		if (sgi_tioca_agp_bridges[j]) {
+			sgi_tioca_agp_bridges[j]->dev = pdev;
+			sgi_tioca_agp_bridges[j]->dev_private_data = info;
+			sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
+			sgi_tioca_agp_bridges[j]->gart_bus_addr =
+			    info->ca_gfxap_base;
+			sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) |	/* 126 requests */
+			    (0x1 << 9) |	/* SBA supported */
+			    (0x1 << 5) |	/* 64-bit addresses supported */
+			    (0x1 << 4) |	/* FW supported */
+			    (0x1 << 3) |	/* AGP 3.0 mode */
+			    0x2;	/* 8x transfer only */
+			sgi_tioca_agp_bridges[j]->current_size =
+			    sgi_tioca_agp_bridges[j]->previous_size =
+			    (void *)&sgi_tioca_sizes[0];
+			agp_add_bridge(sgi_tioca_agp_bridges[j]);
+		}
+		j++;
+	}
+
+	agp_find_bridge = &sgi_tioca_find_bridge;
+	return 0;
+}
+
+static void __devexit agp_sgi_cleanup(void)
+{
+	if(sgi_tioca_agp_bridges)
+		kfree(sgi_tioca_agp_bridges);
+	sgi_tioca_agp_bridges=NULL;
+}
+
+module_init(agp_sgi_init);
+module_exit(agp_sgi_cleanup);
+
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -1,5 +1,5 @@
 /*
- * SiS AGPGART routines. 
+ * SiS AGPGART routines.
  */
 
 #include <linux/module.h>
@@ -70,7 +70,7 @@ static void sis_cleanup(void)
 			      (previous_size->size_value & ~(0x03)));
 }
 
-static void sis_delayed_enable(u32 mode)
+static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode)
 {
 	struct pci_dev *device = NULL;
 	u32 command;
@@ -79,10 +79,10 @@ static void sis_delayed_enable(u32 mode)
 	printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n",
 		agp_bridge->major_version,
 		agp_bridge->minor_version,
-		agp_bridge->dev->slot_name);
+		pci_name(agp_bridge->dev));
 
 	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &command);
-	command = agp_collect_device_status(mode, command);
+	command = agp_collect_device_status(bridge, mode, command);
 	command |= AGPSTAT_AGP_ENABLE;
 	rate = (command & 0x7) << 2;
 
@@ -99,9 +99,9 @@ static void sis_delayed_enable(u32 mode)
 		/*
 		 * Weird: on some sis chipsets any rate change in the target
 		 * command register triggers a 5ms screwup during which the master
-		 * cannot be configured		 
+		 * cannot be configured
 		 */
-		if (device->device == agp_bridge->dev->device) {
+		if (device->device == bridge->dev->device) {
 			printk(KERN_INFO PFX "SiS delay workaround: giving bridge time to recover.\n");
 			msleep(10);
 		}
@@ -119,7 +119,7 @@ static struct aper_size_info_8 sis_gener
 	{4, 1024, 0, 3}
 };
 
-struct agp_bridge_driver sis_driver = {
+static struct agp_bridge_driver sis_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes 	= sis_generic_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -342,7 +342,7 @@ static int __init agp_sis_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_sis_pci_driver);
+	return pci_register_driver(&agp_sis_pci_driver);
 }
 
 static void __exit agp_sis_cleanup(void)
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -51,7 +51,7 @@ static int serverworks_create_page_map(s
 	}
 	SetPageReserved(virt_to_page(page_map->real));
 	global_cache_flush();
-	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
+	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
 		ClearPageReserved(virt_to_page(page_map->real));
@@ -141,7 +141,7 @@ static int serverworks_create_gatt_pages
 #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
 #endif
 
-static int serverworks_create_gatt_table(void)
+static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	struct aper_size_info_lvl2 *value;
 	struct serverworks_page_map page_dir;
@@ -162,7 +162,7 @@ static int serverworks_create_gatt_table
 	/* Create a fake scratch directory */
 	for(i = 0; i < 1024; i++) {
 		writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i);
-		writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
+		writel(virt_to_gart(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
 	}
 
 	retval = serverworks_create_gatt_pages(value->num_entries / 1024);
@@ -174,7 +174,7 @@ static int serverworks_create_gatt_table
 
 	agp_bridge->gatt_table_real = (u32 *)page_dir.real;
 	agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
-	agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
+	agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
 
 	/* Get the address for the gart region.
 	 * This is a bus address even on the alpha, b/c its
@@ -187,12 +187,12 @@ static int serverworks_create_gatt_table
 	/* Calculate the agp offset */	
 
 	for(i = 0; i < value->num_entries / 1024; i++)
-		writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
+		writel(virt_to_gart(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
 
 	return 0;
 }
 
-static int serverworks_free_gatt_table(void)
+static int serverworks_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	struct serverworks_page_map page_dir;
    
@@ -341,7 +341,7 @@ static int serverworks_insert_memory(str
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+		writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
 	}
 	serverworks_tlbflush(mem);
 	return 0;
@@ -387,15 +387,15 @@ static struct aper_size_info_lvl2 server
 	{32, 8192, 0xfe000000}
 };
 
-static void serverworks_agp_enable(u32 mode)
+static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
 	u32 command;
 
 	pci_read_config_dword(serverworks_private.svrwrks_dev,
-			      agp_bridge->capndx + PCI_AGP_STATUS,
+			      bridge->capndx + PCI_AGP_STATUS,
 			      &command);
 
-	command = agp_collect_device_status(mode, command);
+	command = agp_collect_device_status(bridge, mode, command);
 
 	command &= ~0x10;	/* disable FW */
 	command &= ~0x08;
@@ -403,13 +403,13 @@ static void serverworks_agp_enable(u32 m
 	command |= 0x100;
 
 	pci_write_config_dword(serverworks_private.svrwrks_dev,
-			       agp_bridge->capndx + PCI_AGP_COMMAND,
+			       bridge->capndx + PCI_AGP_COMMAND,
 			       command);
 
 	agp_device_command(command, 0);
 }
 
-struct agp_bridge_driver sworks_driver = {
+static struct agp_bridge_driver sworks_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= serverworks_sizes,
 	.size_type		= LVL2_APER_SIZE,
@@ -541,7 +541,7 @@ static int __init agp_serverworks_init(v
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_serverworks_pci_driver);
+	return pci_register_driver(&agp_serverworks_pci_driver);
 }
 
 static void __exit agp_serverworks_cleanup(void)
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -6,10 +6,28 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
+#include <linux/delay.h>
 #include <asm/uninorth.h>
 #include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
 #include "agp.h"
 
+/*
+ * NOTES for uninorth3 (G5 AGP) supports :
+ *
+ * There maybe also possibility to have bigger cache line size for
+ * agp (see pmac_pci.c and look for cache line). Need to be investigated
+ * by someone.
+ *
+ * PAGE size are hardcoded but this may change, see asm/page.h.
+ *
+ * Jerome Glisse <j.glisse@gmail.com>
+ */
+static int uninorth_rev;
+static int is_u3;
+
+
 static int uninorth_fetch_size(void)
 {
 	int i;
@@ -39,26 +57,39 @@ static int uninorth_fetch_size(void)
 
 static void uninorth_tlbflush(struct agp_memory *mem)
 {
+	u32 ctrl = UNI_N_CFG_GART_ENABLE;
+
+	if (is_u3)
+		ctrl |= U3_N_CFG_GART_PERFRD;
 	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_ENABLE);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_ENABLE);
+			       ctrl | UNI_N_CFG_GART_INVAL);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
+
+	if (uninorth_rev <= 0x30) {
+		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+				       ctrl | UNI_N_CFG_GART_2xRESET);
+		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+				       ctrl);
+	}
 }
 
 static void uninorth_cleanup(void)
 {
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			0);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			UNI_N_CFG_GART_2xRESET);
-	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
-			0);
+	u32 tmp;
+
+	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, &tmp);
+	if (!(tmp & UNI_N_CFG_GART_ENABLE))
+		return;
+	tmp |= UNI_N_CFG_GART_INVAL;
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, tmp);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, 0);
+
+	if (uninorth_rev <= 0x30) {
+		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+				       UNI_N_CFG_GART_2xRESET);
+		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+				       0);
+	}
 }
 
 static int uninorth_configure(void)
@@ -81,8 +112,21 @@ static int uninorth_configure(void)
 	 * the AGP aperture isn't mapped at bus physical address 0
 	 */
 	agp_bridge->gart_bus_addr = 0;
+#ifdef CONFIG_PPC64
+	/* Assume U3 or later on PPC64 systems */
+	/* high 4 bits of GART physical address go in UNI_N_CFG_AGP_BASE */
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_AGP_BASE,
+			       (agp_bridge->gatt_bus_addr >> 32) & 0xf);
+#else
 	pci_write_config_dword(agp_bridge->dev,
 		UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr);
+#endif
+
+	if (is_u3) {
+		pci_write_config_dword(agp_bridge->dev,
+				       UNI_N_CFG_GART_DUMMY_PAGE,
+				       agp_bridge->scratch_page_real >> 12);
+	}
 	
 	return 0;
 }
@@ -105,13 +149,14 @@ static int uninorth_insert_memory(struct
 	j = pg_start;
 
 	while (j < (pg_start + mem->page_count)) {
-		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j]))
+		if (agp_bridge->gatt_table[j])
 			return -EBUSY;
 		j++;
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		agp_bridge->gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL);
+		agp_bridge->gatt_table[j] =
+		    cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL);
 		flush_dcache_range((unsigned long)__va(mem->memory[i]),
 				   (unsigned long)__va(mem->memory[i])+0x1000);
 	}
@@ -124,38 +169,200 @@ static int uninorth_insert_memory(struct
 	return 0;
 }
 
-static void uninorth_agp_enable(u32 mode)
+static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
-	u32 command, scratch;
+	int i, num_entries;
+	void *temp;
+	u32 *gp;
+
+	temp = agp_bridge->current_size;
+	num_entries = A_SIZE_32(temp)->num_entries;
+
+	if (type != 0 || mem->type != 0)
+		/* We know nothing of memory types */
+		return -EINVAL;
+	if ((pg_start + mem->page_count) > num_entries)
+		return -EINVAL;
+
+	gp = (u32 *) &agp_bridge->gatt_table[pg_start];
+	for (i = 0; i < mem->page_count; ++i) {
+		if (gp[i]) {
+			printk("u3_insert_memory: entry 0x%x occupied (%x)\n",
+			       i, gp[i]);
+			return -EBUSY;
+		}
+	}
+
+	for (i = 0; i < mem->page_count; i++) {
+		gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL;
+		flush_dcache_range((unsigned long)__va(mem->memory[i]),
+				   (unsigned long)__va(mem->memory[i])+0x1000);
+	}
+	mb();
+	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
+	uninorth_tlbflush(mem);
+
+	return 0;
+}
+
+int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
+{
+	size_t i;
+	u32 *gp;
+
+	if (type != 0 || mem->type != 0)
+		/* We know nothing of memory types */
+		return -EINVAL;
+
+	gp = (u32 *) &agp_bridge->gatt_table[pg_start];
+	for (i = 0; i < mem->page_count; ++i)
+		gp[i] = 0;
+	mb();
+	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
+	uninorth_tlbflush(mem);
+
+	return 0;
+}
+
+static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+	u32 command, scratch, status;
 	int timeout;
 
-	pci_read_config_dword(agp_bridge->dev,
-			      agp_bridge->capndx + PCI_AGP_STATUS,
-			      &command);
+	pci_read_config_dword(bridge->dev,
+			      bridge->capndx + PCI_AGP_STATUS,
+			      &status);
+
+	command = agp_collect_device_status(bridge, mode, status);
+	command |= PCI_AGP_COMMAND_AGP;
+	
+	if (uninorth_rev == 0x21) {
+		/*
+		 * Darwin disable AGP 4x on this revision, thus we
+		 * may assume it's broken. This is an AGP2 controller.
+		 */
+		command &= ~AGPSTAT2_4X;
+	}
 
-	command = agp_collect_device_status(mode, command);
-	command |= 0x100;
+	if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) {
+		/*
+		 * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
+		 * 2.2 and 2.3, Darwin do so.
+		 */
+		if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7)
+			command = (command & ~AGPSTAT_RQ_DEPTH)
+				| (7 << AGPSTAT_RQ_DEPTH_SHIFT);
+	}
 
 	uninorth_tlbflush(NULL);
 
 	timeout = 0;
 	do {
-		pci_write_config_dword(agp_bridge->dev,
-				       agp_bridge->capndx + PCI_AGP_COMMAND,
+		pci_write_config_dword(bridge->dev,
+				       bridge->capndx + PCI_AGP_COMMAND,
 				       command);
-		pci_read_config_dword(agp_bridge->dev,
-				       agp_bridge->capndx + PCI_AGP_COMMAND,
+		pci_read_config_dword(bridge->dev,
+				      bridge->capndx + PCI_AGP_COMMAND,
 				       &scratch);
-	} while ((scratch & 0x100) == 0 && ++timeout < 1000);
-	if ((scratch & 0x100) == 0)
-		printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n");
-
-	agp_device_command(command, 0);
+	} while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000);
+	if ((scratch & PCI_AGP_COMMAND_AGP) == 0)
+		printk(KERN_ERR PFX "failed to write UniNorth AGP"
+		       " command register\n");
+
+	if (uninorth_rev >= 0x30) {
+		/* This is an AGP V3 */
+		agp_device_command(command, (status & AGPSTAT_MODE_3_0));
+	} else {
+		/* AGP V2 */
+		agp_device_command(command, 0);
+	}
 
 	uninorth_tlbflush(NULL);
 }
 
-static int uninorth_create_gatt_table(void)
+#ifdef CONFIG_PM
+/*
+ * These Power Management routines are _not_ called by the normal PCI PM layer,
+ * but directly by the video driver through function pointers in the device
+ * tree.
+ */
+static int agp_uninorth_suspend(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge;
+	u32 cmd;
+	u8 agp;
+	struct pci_dev *device = NULL;
+
+	bridge = agp_find_bridge(pdev);
+	if (bridge == NULL)
+		return -ENODEV;
+
+	/* Only one suspend supported */
+	if (bridge->dev_private_data)
+		return 0;
+
+	/* turn off AGP on the video chip, if it was enabled */
+	for_each_pci_dev(device) {
+		/* Don't touch the bridge yet, device first */
+		if (device == pdev)
+			continue;
+		/* Only deal with devices on the same bus here, no Mac has a P2P
+		 * bridge on the AGP port, and mucking around the entire PCI
+		 * tree is source of problems on some machines because of a bug
+		 * in some versions of pci_find_capability() when hitting a dead
+		 * device
+		 */
+		if (device->bus != pdev->bus)
+			continue;
+		agp = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (!agp)
+			continue;
+		pci_read_config_dword(device, agp + PCI_AGP_COMMAND, &cmd);
+		if (!(cmd & PCI_AGP_COMMAND_AGP))
+			continue;
+		printk("uninorth-agp: disabling AGP on device %s\n",
+				pci_name(device));
+		cmd &= ~PCI_AGP_COMMAND_AGP;
+		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, cmd);
+	}
+
+	/* turn off AGP on the bridge */
+	agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
+	bridge->dev_private_data = (void *)cmd;
+	if (cmd & PCI_AGP_COMMAND_AGP) {
+		printk("uninorth-agp: disabling AGP on bridge %s\n",
+				pci_name(pdev));
+		cmd &= ~PCI_AGP_COMMAND_AGP;
+		pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, cmd);
+	}
+	/* turn off the GART */
+	uninorth_cleanup();
+
+	return 0;
+}
+
+static int agp_uninorth_resume(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge;
+	u32 command;
+
+	bridge = agp_find_bridge(pdev);
+	if (bridge == NULL)
+		return -ENODEV;
+
+	command = (u32)bridge->dev_private_data;
+	bridge->dev_private_data = NULL;
+	if (!(command & PCI_AGP_COMMAND_AGP))
+		return 0;
+
+	uninorth_agp_enable(bridge, command);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
 {
 	char *table;
 	char *table_end;
@@ -167,12 +374,12 @@ static int uninorth_create_gatt_table(vo
 	struct page *page;
 
 	/* We can't handle 2 level gatt's */
-	if (agp_bridge->driver->size_type == LVL2_APER_SIZE)
+	if (bridge->driver->size_type == LVL2_APER_SIZE)
 		return -EINVAL;
 
 	table = NULL;
-	i = agp_bridge->aperture_size_idx;
-	temp = agp_bridge->current_size;
+	i = bridge->aperture_size_idx;
+	temp = bridge->current_size;
 	size = page_order = num_entries = 0;
 
 	do {
@@ -184,11 +391,11 @@ static int uninorth_create_gatt_table(vo
 
 		if (table == NULL) {
 			i++;
-			agp_bridge->current_size = A_IDX32(agp_bridge);
+			bridge->current_size = A_IDX32(bridge);
 		} else {
-			agp_bridge->aperture_size_idx = i;
+			bridge->aperture_size_idx = i;
 		}
-	} while (!table && (i < agp_bridge->driver->num_aperture_sizes));
+	} while (!table && (i < bridge->driver->num_aperture_sizes));
 
 	if (table == NULL)
 		return -ENOMEM;
@@ -198,28 +405,26 @@ static int uninorth_create_gatt_table(vo
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		SetPageReserved(page);
 
-	agp_bridge->gatt_table_real = (u32 *) table;
-	agp_bridge->gatt_table = (u32 *)table;
-	agp_bridge->gatt_bus_addr = virt_to_phys(table);
-
-	for (i = 0; i < num_entries; i++) {
-		agp_bridge->gatt_table[i] =
-		    (unsigned long) agp_bridge->scratch_page;
-	}
+	bridge->gatt_table_real = (u32 *) table;
+	bridge->gatt_table = (u32 *)table;
+	bridge->gatt_bus_addr = virt_to_gart(table);
+
+	for (i = 0; i < num_entries; i++)
+		bridge->gatt_table[i] = 0;
 
 	flush_dcache_range((unsigned long)table, (unsigned long)table_end);
 
 	return 0;
 }
 
-static int uninorth_free_gatt_table(void)
+static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	int page_order;
 	char *table, *table_end;
 	void *temp;
 	struct page *page;
 
-	temp = agp_bridge->current_size;
+	temp = bridge->current_size;
 	page_order = A_SIZE_32(temp)->page_order;
 
 	/* Do not worry about freeing memory, because if this is
@@ -227,13 +432,13 @@ static int uninorth_free_gatt_table(void
 	 * from the table.
 	 */
 
-	table = (char *) agp_bridge->gatt_table_real;
+	table = (char *) bridge->gatt_table_real;
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		ClearPageReserved(page);
 
-	free_pages((unsigned long) agp_bridge->gatt_table_real, page_order);
+	free_pages((unsigned long) bridge->gatt_table_real, page_order);
 
 	return 0;
 }
@@ -258,6 +463,22 @@ static struct aper_size_info_32 uninorth
 	{4, 1024, 0, 1}
 };
 
+/*
+ * Not sure that u3 supports that high aperture sizes but it
+ * would strange if it did not :)
+ */
+static struct aper_size_info_32 u3_sizes[8] =
+{
+	{512, 131072, 7, 128},
+	{256, 65536, 6, 64},
+	{128, 32768, 5, 32},
+	{64, 16384, 4, 16},
+	{32, 8192, 3, 8},
+	{16, 4096, 2, 4},
+	{8, 2048, 1, 2},
+	{4, 1024, 0, 1}
+};
+
 struct agp_bridge_driver uninorth_agp_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= (void *)uninorth_sizes,
@@ -282,6 +503,31 @@ struct agp_bridge_driver uninorth_agp_dr
 	.cant_use_aperture	= 1,
 };
 
+struct agp_bridge_driver u3_agp_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= (void *)u3_sizes,
+	.size_type		= U32_APER_SIZE,
+	.num_aperture_sizes	= 8,
+	.configure		= uninorth_configure,
+	.fetch_size		= uninorth_fetch_size,
+	.cleanup		= uninorth_cleanup,
+	.tlb_flush		= uninorth_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.cache_flush		= null_cache_flush,
+	.agp_enable		= uninorth_agp_enable,
+	.create_gatt_table	= uninorth_create_gatt_table,
+	.free_gatt_table	= uninorth_free_gatt_table,
+	.insert_memory		= u3_insert_memory,
+	.remove_memory		= u3_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+	.cant_use_aperture	= 1,
+	.needs_scratch_page	= 1,
+};
+
 static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
 	{
 		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP,
@@ -299,6 +545,18 @@ static struct agp_device_ids uninorth_ag
 		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP2,
 		.chipset_name	= "UniNorth 2",
 	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_U3_AGP,
+		.chipset_name	= "U3",
+	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_U3L_AGP,
+		.chipset_name	= "U3L",
+	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_U3H_AGP,
+		.chipset_name	= "U3H",
+	},
 };
 
 static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
@@ -306,6 +564,7 @@ static int __devinit agp_uninorth_probe(
 {
 	struct agp_device_ids *devs = uninorth_agp_device_ids;
 	struct agp_bridge_data *bridge;
+	struct device_node *uninorth_node;
 	u8 cap_ptr;
 	int j;
 
@@ -327,13 +586,42 @@ static int __devinit agp_uninorth_probe(
 	return -ENODEV;
 
  found:
+	/* Set revision to 0 if we could not read it. */
+	uninorth_rev = 0;
+	is_u3 = 0;
+	/* Locate core99 Uni-N */
+	uninorth_node = of_find_node_by_name(NULL, "uni-n");
+	/* Locate G5 u3 */
+	if (uninorth_node == NULL) {
+		is_u3 = 1;
+		uninorth_node = of_find_node_by_name(NULL, "u3");
+	}
+	if (uninorth_node) {
+		int *revprop = (int *)
+			get_property(uninorth_node, "device-rev", NULL);
+		if (revprop != NULL)
+			uninorth_rev = *revprop & 0x3f;
+		of_node_put(uninorth_node);
+	}
+
+#ifdef CONFIG_PM
+	/* Inform platform of our suspend/resume caps */
+	pmac_register_agp_pm(pdev, agp_uninorth_suspend, agp_uninorth_resume);
+#endif
+
+	/* Allocate & setup our driver */
 	bridge = agp_alloc_bridge();
 	if (!bridge)
 		return -ENOMEM;
 
-	bridge->driver = &uninorth_agp_driver;
+	if (is_u3)
+		bridge->driver = &u3_agp_driver;
+	else
+		bridge->driver = &uninorth_agp_driver;
+
 	bridge->dev = pdev;
 	bridge->capndx = cap_ptr;
+	bridge->flags = AGP_ERRATA_FASTWRITES;
 
 	/* Fill in the mode register */
 	pci_read_config_dword(pdev, cap_ptr+PCI_AGP_STATUS, &bridge->mode);
@@ -346,6 +634,11 @@ static void __devexit agp_uninorth_remov
 {
 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
+#ifdef CONFIG_PM
+	/* Inform platform of our suspend/resume caps */
+	pmac_register_agp_pm(pdev, NULL, NULL);
+#endif
+
 	agp_remove_bridge(bridge);
 	agp_put_bridge(bridge);
 }
@@ -375,7 +668,7 @@ static int __init agp_uninorth_init(void
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_uninorth_pci_driver);
+	return pci_register_driver(&agp_uninorth_pci_driver);
 }
 
 static void __exit agp_uninorth_cleanup(void)
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -1,5 +1,5 @@
 /*
- * VIA AGPGART routines. 
+ * VIA AGPGART routines.
  */
 
 #include <linux/types.h>
@@ -36,6 +36,7 @@ static int via_fetch_size(void)
 			return values[i].size;
 		}
 	}
+	printk(KERN_ERR PFX "Unknown aperture size from AGP bridge (0x%x)\n", temp);
 	return 0;
 }
 
@@ -78,12 +79,17 @@ static void via_cleanup(void)
 
 static void via_tlbflush(struct agp_memory *mem)
 {
-	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000008f);
-	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f);
+	u32 temp;
+
+	pci_read_config_dword(agp_bridge->dev, VIA_GARTCTRL, &temp);
+	temp |= (1<<7);
+	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);
+	temp &= ~(1<<7);
+	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);
 }
 
 
-static struct aper_size_info_8 via_generic_sizes[7] =
+static struct aper_size_info_8 via_generic_sizes[9] =
 {
 	{256, 65536, 6, 0},
 	{128, 32768, 5, 128},
@@ -91,7 +97,9 @@ static struct aper_size_info_8 via_gener
 	{32, 8192, 3, 224},
 	{16, 4096, 2, 240},
 	{8, 2048, 1, 248},
-	{4, 1024, 0, 252}
+	{4, 1024, 0, 252},
+	{2, 512, 0, 254},
+	{1, 256, 0, 255}
 };
 
 
@@ -121,7 +129,7 @@ static int via_configure_agp3(void)
 {
 	u32 temp;
 	struct aper_size_info_16 *current_size;
-    
+
 	current_size = A_SIZE_16(agp_bridge->current_size);
 
 	/* address to map too */
@@ -132,13 +140,13 @@ static int via_configure_agp3(void)
 	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE,
 		agp_bridge->gatt_bus_addr & 0xfffff000);
 
-	/* 1. Enable GTLB in RX90<7>, all AGP aperture access needs to fetch 
+	/* 1. Enable GTLB in RX90<7>, all AGP aperture access needs to fetch
 	 *    translation table first.
 	 * 2. Enable AGP aperture in RX91<0>. This bit controls the enabling of the
 	 *    graphics AGP aperture for the AGP3.0 port.
 	 */
 	pci_read_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, &temp);
-	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp | (3<<7));		
+	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp | (3<<7));
 	return 0;
 }
 
@@ -162,7 +170,7 @@ static void via_tlbflush_agp3(struct agp
 }
 
 
-struct agp_bridge_driver via_agp3_driver = {
+static struct agp_bridge_driver via_agp3_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= agp3_generic_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -185,11 +193,11 @@ struct agp_bridge_driver via_agp3_driver
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver via_driver = {
+static struct agp_bridge_driver via_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= via_generic_sizes,
 	.size_type		= U8_APER_SIZE,
-	.num_aperture_sizes	= 7,
+	.num_aperture_sizes	= 9,
 	.configure		= via_configure,
 	.fetch_size		= via_fetch_size,
 	.cleanup		= via_cleanup,
@@ -440,10 +448,10 @@ static void __devexit agp_via_remove(str
 
 #ifdef CONFIG_PM
 
-static int agp_via_suspend(struct pci_dev *pdev, u32 state)
+static int agp_via_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	pci_save_state (pdev);
-	pci_set_power_state (pdev, 3);
+	pci_set_power_state (pdev, PCI_D3hot);
 
 	return 0;
 }
@@ -452,7 +460,7 @@ static int agp_via_resume(struct pci_dev
 {
 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	pci_set_power_state (pdev, 0);
+	pci_set_power_state (pdev, PCI_D0);
 	pci_restore_state(pdev);
 
 	if (bridge->driver == &via_agp3_driver)
@@ -525,7 +533,7 @@ static int __init agp_via_init(void)
 {
 	if (agp_off)
 		return -EINVAL;
-	return pci_module_init(&agp_via_pci_driver);
+	return pci_register_driver(&agp_via_pci_driver);
 }
 
 static void __exit agp_via_cleanup(void)
diff --git a/drivers/char/console_macros.h b/drivers/char/console_macros.h
deleted file mode 100644
--- a/drivers/char/console_macros.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#define cons_num	(vc_cons[currcons].d->vc_num)
-#define video_scan_lines (vc_cons[currcons].d->vc_scan_lines)
-#define sw		(vc_cons[currcons].d->vc_sw)
-#define screenbuf	(vc_cons[currcons].d->vc_screenbuf)
-#define screenbuf_size	(vc_cons[currcons].d->vc_screenbuf_size)
-#define origin		(vc_cons[currcons].d->vc_origin)
-#define scr_top		(vc_cons[currcons].d->vc_scr_top)
-#define visible_origin  (vc_cons[currcons].d->vc_visible_origin)
-#define scr_end		(vc_cons[currcons].d->vc_scr_end)
-#define pos		(vc_cons[currcons].d->vc_pos)
-#define top		(vc_cons[currcons].d->vc_top)
-#define bottom		(vc_cons[currcons].d->vc_bottom)
-#define x		(vc_cons[currcons].d->vc_x)
-#define y		(vc_cons[currcons].d->vc_y)
-#define vc_state	(vc_cons[currcons].d->vc_state)
-#define npar		(vc_cons[currcons].d->vc_npar)
-#define par		(vc_cons[currcons].d->vc_par)
-#define ques		(vc_cons[currcons].d->vc_ques)
-#define attr		(vc_cons[currcons].d->vc_attr)
-#define saved_x		(vc_cons[currcons].d->vc_saved_x)
-#define saved_y		(vc_cons[currcons].d->vc_saved_y)
-#define translate	(vc_cons[currcons].d->vc_translate)
-#define G0_charset	(vc_cons[currcons].d->vc_G0_charset)
-#define G1_charset	(vc_cons[currcons].d->vc_G1_charset)
-#define saved_G0	(vc_cons[currcons].d->vc_saved_G0)
-#define saved_G1	(vc_cons[currcons].d->vc_saved_G1)
-#define utf		(vc_cons[currcons].d->vc_utf)
-#define utf_count	(vc_cons[currcons].d->vc_utf_count)
-#define utf_char	(vc_cons[currcons].d->vc_utf_char)
-#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
-#define disp_ctrl	(vc_cons[currcons].d->vc_disp_ctrl)
-#define toggle_meta	(vc_cons[currcons].d->vc_toggle_meta)
-#define decscnm		(vc_cons[currcons].d->vc_decscnm)
-#define decom		(vc_cons[currcons].d->vc_decom)
-#define decawm		(vc_cons[currcons].d->vc_decawm)
-#define deccm		(vc_cons[currcons].d->vc_deccm)
-#define decim		(vc_cons[currcons].d->vc_decim)
-#define deccolm		(vc_cons[currcons].d->vc_deccolm)
-#define need_wrap	(vc_cons[currcons].d->vc_need_wrap)
-#define kmalloced	(vc_cons[currcons].d->vc_kmalloced)
-#define report_mouse	(vc_cons[currcons].d->vc_report_mouse)
-#define color		(vc_cons[currcons].d->vc_color)
-#define s_color		(vc_cons[currcons].d->vc_s_color)
-#define def_color	(vc_cons[currcons].d->vc_def_color)
-#define foreground	(color & 0x0f)
-#define background	(color & 0xf0)
-#define charset		(vc_cons[currcons].d->vc_charset)
-#define s_charset	(vc_cons[currcons].d->vc_s_charset)
-#define	intensity	(vc_cons[currcons].d->vc_intensity)
-#define	underline	(vc_cons[currcons].d->vc_underline)
-#define	blink		(vc_cons[currcons].d->vc_blink)
-#define	reverse		(vc_cons[currcons].d->vc_reverse)
-#define	s_intensity	(vc_cons[currcons].d->vc_s_intensity)
-#define	s_underline	(vc_cons[currcons].d->vc_s_underline)
-#define	s_blink		(vc_cons[currcons].d->vc_s_blink)
-#define	s_reverse	(vc_cons[currcons].d->vc_s_reverse)
-#define	ulcolor		(vc_cons[currcons].d->vc_ulcolor)
-#define	halfcolor	(vc_cons[currcons].d->vc_halfcolor)
-#define tab_stop	(vc_cons[currcons].d->vc_tab_stop)
-#define palette		(vc_cons[currcons].d->vc_palette)
-#define bell_pitch	(vc_cons[currcons].d->vc_bell_pitch)
-#define bell_duration	(vc_cons[currcons].d->vc_bell_duration)
-#define cursor_type	(vc_cons[currcons].d->vc_cursor_type)
-#define display_fg	(vc_cons[currcons].d->vc_display_fg)
-#define complement_mask (vc_cons[currcons].d->vc_complement_mask)
-#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask)
-#define hi_font_mask	(vc_cons[currcons].d->vc_hi_font_mask)
-
-#define vcmode		(vt_cons[currcons]->vc_mode)
-
-#define structsize	(sizeof(struct vc_data) + sizeof(struct vt_struct))
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -208,9 +208,9 @@ static void set_inverse_transl(struct vc
 	}
 }
 
-unsigned short *set_translate(int m,int currcons)
+unsigned short *set_translate(int m, struct vc_data *vc)
 {
-	inv_translate[currcons] = m;
+	inv_translate[vc->vc_num] = m;
 	return translations[m];
 }
 
@@ -262,9 +262,8 @@ int con_set_trans_old(unsigned char __us
 	int i;
 	unsigned short *p = translations[USER_MAP];
 
-	i = verify_area(VERIFY_READ, arg, E_TABSZ);
-	if (i)
-		return i;
+	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
+		return -EFAULT;
 
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned char uc;
@@ -281,9 +280,8 @@ int con_get_trans_old(unsigned char __us
 	int i, ch;
 	unsigned short *p = translations[USER_MAP];
 
-	i = verify_area(VERIFY_WRITE, arg, E_TABSZ);
-	if (i)
-		return i;
+	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
+		return -EFAULT;
 
 	for (i=0; i<E_TABSZ ; i++)
 	  {
@@ -298,9 +296,8 @@ int con_set_trans_new(ushort __user * ar
 	int i;
 	unsigned short *p = translations[USER_MAP];
 
-	i = verify_area(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short));
-	if (i)
-		return i;
+	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
+		return -EFAULT;
 
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned short us;
@@ -317,9 +314,8 @@ int con_get_trans_new(ushort __user * ar
 	int i;
 	unsigned short *p = translations[USER_MAP];
 
-	i = verify_area(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short));
-	if (i)
-		return i;
+	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
+		return -EFAULT;
 
 	for (i=0; i<E_TABSZ ; i++)
 	  __put_user(p[i], arg+i);
@@ -362,15 +358,16 @@ static void con_release_unimap(struct un
 		}
 }
 
-void con_free_unimap(int con)
+void con_free_unimap(struct vc_data *vc)
 {
 	struct uni_pagedir *p;
-	struct vc_data *conp = vc_cons[con].d;
-	
-	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
-	if (!p) return;
-	*conp->vc_uni_pagedir_loc = 0;
-	if (--p->refcount) return;
+
+	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+	if (!p)
+		return;
+	*vc->vc_uni_pagedir_loc = 0;
+	if (--p->refcount)
+		return;
 	con_release_unimap(p);
 	kfree(p);
 }
@@ -442,12 +439,11 @@ con_insert_unipair(struct uni_pagedir *p
 }
 
 /* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(int con, struct unimapinit *ui)
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
 {
 	struct uni_pagedir *p, *q;
-	struct vc_data *conp = vc_cons[con].d;
   
-	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	if (p && p->readonly) return -EIO;
 	if (!p || --p->refcount) {
 		q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
@@ -457,7 +453,7 @@ int con_clear_unimap(int con, struct uni
 		}
 		memset(q, 0, sizeof(*q));
 		q->refcount=1;
-		*conp->vc_uni_pagedir_loc = (unsigned long)q;
+		*vc->vc_uni_pagedir_loc = (unsigned long)q;
 	} else {
 		if (p == dflt) dflt = NULL;
 		p->refcount++;
@@ -467,14 +463,12 @@ int con_clear_unimap(int con, struct uni
 	return 0;
 }
 
-int
-con_set_unimap(int con, ushort ct, struct unipair __user *list)
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 {
 	int err = 0, err1, i;
 	struct uni_pagedir *p, *q;
-	struct vc_data *conp = vc_cons[con].d;
 
-	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	if (p->readonly) return -EIO;
 	
 	if (!ct) return 0;
@@ -483,10 +477,10 @@ con_set_unimap(int con, ushort ct, struc
 		int j, k;
 		u16 **p1, *p2, l;
 		
-		err1 = con_clear_unimap(con, NULL);
+		err1 = con_clear_unimap(vc, NULL);
 		if (err1) return err1;
 		
-		q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		for (i = 0, l = 0; i < 32; i++)
 		if ((p1 = p->uni_pgdir[i]))
 			for (j = 0; j < 32; j++)
@@ -496,7 +490,7 @@ con_set_unimap(int con, ushort ct, struc
 					err1 = con_insert_unipair(q, l, p2[k]);
 					if (err1) {
 						p->refcount++;
-						*conp->vc_uni_pagedir_loc = (unsigned long)p;
+						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						con_release_unimap(q);
 						kfree(q);
 						return err1; 
@@ -515,11 +509,11 @@ con_set_unimap(int con, ushort ct, struc
 			list++;
 	}
 	
-	if (con_unify_unimap(conp, p))
+	if (con_unify_unimap(vc, p))
 		return err;
 
 	for (i = 0; i <= 3; i++)
-		set_inverse_transl(conp, p, i); /* Update all inverse translations */
+		set_inverse_transl(vc, p, i); /* Update all inverse translations */
   
 	return err;
 }
@@ -529,20 +523,18 @@ con_set_unimap(int con, ushort ct, struc
    with.  This routine is executed at sys_setup time, and when the
    PIO_FONTRESET ioctl is called. */
 
-int
-con_set_default_unimap(int con)
+int con_set_default_unimap(struct vc_data *vc)
 {
 	int i, j, err = 0, err1;
 	u16 *q;
 	struct uni_pagedir *p;
-	struct vc_data *conp = vc_cons[con].d;
-	
+
 	if (dflt) {
-		p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		if (p == dflt)
 			return 0;
 		dflt->refcount++;
-		*conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
 		if (p && --p->refcount) {
 			con_release_unimap(p);
 			kfree(p);
@@ -552,10 +544,10 @@ con_set_default_unimap(int con)
 	
 	/* The default font is always 256 characters */
 
-	err = con_clear_unimap(con,NULL);
+	err = con_clear_unimap(vc, NULL);
 	if (err) return err;
     
-	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	q = dfont_unitable;
 	
 	for (i = 0; i < 256; i++)
@@ -565,47 +557,42 @@ con_set_default_unimap(int con)
 				err = err1;
 		}
 			
-	if (con_unify_unimap(conp, p)) {
-		dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	if (con_unify_unimap(vc, p)) {
+		dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		return err;
 	}
 
 	for (i = 0; i <= 3; i++)
-		set_inverse_transl(conp, p, i);	/* Update all inverse translations */
+		set_inverse_transl(vc, p, i);	/* Update all inverse translations */
 	dflt = p;
 	return err;
 }
 EXPORT_SYMBOL(con_set_default_unimap);
 
-int
-con_copy_unimap(int dstcon, int srccon)
+int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 {
-	struct vc_data *sconp = vc_cons[srccon].d;
-	struct vc_data *dconp = vc_cons[dstcon].d;
 	struct uni_pagedir *q;
-	
-	if (!vc_cons_allocated(srccon) || !*sconp->vc_uni_pagedir_loc)
+
+	if (!*src_vc->vc_uni_pagedir_loc)
 		return -EINVAL;
-	if (*dconp->vc_uni_pagedir_loc == *sconp->vc_uni_pagedir_loc)
+	if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
 		return 0;
-	con_free_unimap(dstcon);
-	q = (struct uni_pagedir *)*sconp->vc_uni_pagedir_loc;
+	con_free_unimap(dst_vc);
+	q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
 	q->refcount++;
-	*dconp->vc_uni_pagedir_loc = (long)q;
+	*dst_vc->vc_uni_pagedir_loc = (long)q;
 	return 0;
 }
 
-int
-con_get_unimap(int con, ushort ct, ushort __user *uct, struct unipair __user *list)
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
 {
 	int i, j, k, ect;
 	u16 **p1, *p2;
 	struct uni_pagedir *p;
-	struct vc_data *conp = vc_cons[con].d;
 
 	ect = 0;
-	if (*conp->vc_uni_pagedir_loc) {
-		p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	if (*vc->vc_uni_pagedir_loc) {
+		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		for (i = 0; i < 32; i++)
 		if ((p1 = p->uni_pgdir[i]))
 			for (j = 0; j < 32; j++)
@@ -625,12 +612,12 @@ con_get_unimap(int con, ushort ct, ushor
 	return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
-void con_protect_unimap(int con, int rdonly)
+void con_protect_unimap(struct vc_data *vc, int rdonly)
 {
-	struct uni_pagedir *p = (struct uni_pagedir *)
-		*vc_cons[con].d->vc_uni_pagedir_loc;
+	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	
-	if (p) p->readonly = rdonly;
+	if (p)
+		p->readonly = rdonly;
 }
 
 int
@@ -679,7 +666,7 @@ console_map_init(void)
 	
 	for (i = 0; i < MAX_NR_CONSOLES; i++)
 		if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
-			con_set_default_unimap(i);
+			con_set_default_unimap(vc_cons[i].d);
 }
 
 EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/char/digi_bios.h b/drivers/char/digi_bios.h
deleted file mode 100644
--- a/drivers/char/digi_bios.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* DigiBoard PCXX Bios */
-
-static unsigned char pcxx_bios[] __initdata = {
-  0x28,0x43,0x29,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,
-  0x74,0x20,0x31,0x39,0x39,0x34,0x2c,0x20,0x44,0x69,0x67,0x69,
-  0x42,0x6f,0x61,0x72,0x64,0x20,0x49,0x6e,0x63,0x2e,0x00,0x00,
-  0x8a,0xf8,0x8a,0xf8,0x15,0xf9,0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,
-  0x8a,0xf8,0x8a,0xf8,0xbc,0xf8,0x8a,0xf8,0x96,0xf8,0x96,0xf8,
-  0x96,0xf8,0x96,0xf8,0x96,0xf8,0x96,0xf8,0x8a,0xf8,0x8a,0xf8,
-  0x96,0xf8,0x96,0xf8,0x8a,0xf8,0xad,0xf8,0xb0,0xf8,0x8a,0xf8,
-  0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,
-  0x8a,0xf8,0x8a,0xf8,0x8a,0xf8,0x04,0x02,0x00,0x02,0x14,0x02,
-  0x10,0x02,0x24,0x02,0x20,0x02,0x34,0x02,0x30,0x02,0x44,0x02,
-  0x40,0x02,0x54,0x02,0x50,0x02,0x64,0x02,0x60,0x02,0x74,0x02,
-  0x70,0x02,0x04,0x01,0x00,0x01,0x1e,0x2e,0x8e,0x1e,0x22,0xf8,
-  0xfe,0x06,0x70,0x00,0x1f,0xcf,0x1e,0x50,0x52,0x2e,0x8e,0x1e,
-  0x22,0xf8,0xfe,0x06,0x71,0x00,0xb8,0x00,0x80,0xba,0x22,0xff,
-  0xef,0x5a,0x58,0x1f,0xcf,0xb4,0x80,0xcf,0x1e,0x2e,0x8e,0x1e,
-  0x22,0xf8,0xfe,0x06,0x2b,0x00,0x1f,0xcf,0x1e,0x52,0x50,0x2e,
-  0x8e,0x1e,0x22,0xf8,0xcd,0x16,0xfe,0x06,0x2a,0x00,0x80,0x3e,
-  0x2a,0x00,0x12,0x72,0x39,0xc6,0x06,0x2a,0x00,0x00,0xfe,0x06,
-  0x29,0x00,0x80,0x3e,0x29,0x00,0x3c,0x72,0x29,0xc6,0x06,0x29,
-  0x00,0x00,0xfe,0x06,0x28,0x00,0x80,0x3e,0x28,0x00,0x3c,0x72,
-  0x19,0xc6,0x06,0x28,0x00,0x00,0xfe,0x06,0x27,0x00,0x80,0x3e,
-  0x27,0x00,0x18,0x72,0x09,0xc6,0x06,0x27,0x00,0x00,0xff,0x06,
-  0x25,0x00,0xba,0x22,0xff,0xb8,0x00,0x80,0xef,0x58,0x5a,0x1f,
-  0xcf,0x60,0x1e,0x06,0xfc,0x2e,0x8e,0x06,0x22,0xf8,0x2e,0x8e,
-  0x1e,0x22,0xf8,0x8d,0x36,0x40,0x00,0xad,0x3c,0x3f,0x7f,0x22,
-  0x3c,0x1f,0x7f,0x22,0x32,0xe4,0xd1,0xe0,0x3d,0x16,0x00,0x90,
-  0x73,0x14,0xbb,0x56,0xf9,0x03,0xd8,0x2e,0xff,0x17,0x8d,0x36,
-  0x40,0x00,0xb0,0x00,0x89,0x04,0x07,0x1f,0x61,0xcf,0xb4,0x80,
-  0xeb,0xf0,0xcd,0x15,0xeb,0xec,0x6c,0xf9,0x79,0xf9,0xb9,0xf9,
-  0xd3,0xf9,0xd8,0xf9,0xe1,0xf9,0xe9,0xf9,0xf2,0xf9,0xfa,0xf9,
-  0xfd,0xf9,0x2a,0xfa,0xe4,0x00,0x24,0xf7,0xe6,0x00,0x0c,0x08,
-  0xe6,0x00,0xb4,0x00,0xc3,0x1e,0xad,0x8b,0xd8,0xad,0x8e,0xdb,
-  0x8b,0xf0,0x33,0xdb,0x8b,0x07,0x3d,0x4f,0x53,0x75,0x2a,0x8a,
-  0x47,0x02,0x32,0xe4,0x86,0xc4,0x8b,0xc8,0x32,0xc0,0x02,0x07,
-  0x43,0xe2,0xfb,0x0a,0xc0,0x75,0x16,0x8c,0xd9,0x1f,0x89,0x0e,
-  0x2e,0x00,0x89,0x36,0x2c,0x00,0x8d,0x1e,0x02,0x00,0xc7,0x07,
-  0x45,0x4d,0x32,0xe4,0xc3,0x1f,0xb4,0x80,0xc3,0xad,0x8b,0xd8,
-  0xad,0x8b,0xd0,0xad,0x8e,0xc0,0xad,0x8b,0xf8,0xad,0x8b,0xc8,
-  0x8b,0xf2,0x1e,0x8e,0xdb,0xf3,0xa4,0x1f,0x32,0xe4,0xc3,0xea,
-  0xf0,0xff,0x00,0xf0,0xad,0x8b,0xd0,0xec,0x88,0x04,0x32,0xe4,
-  0xc3,0xad,0x8b,0xd0,0xac,0xee,0x32,0xe4,0xc3,0xad,0x8b,0xd0,
-  0xed,0x89,0x04,0x32,0xe4,0xc3,0xad,0x8b,0xd0,0xad,0xef,0x32,
-  0xe4,0xc3,0xb4,0x80,0xc3,0xac,0x3c,0x12,0x7f,0x25,0xfe,0xc8,
-  0x32,0xe4,0xd1,0xe0,0x8d,0x1e,0x66,0xf8,0x03,0xd8,0x2e,0x8b,
-  0x17,0xec,0xac,0x3c,0x0f,0x7f,0x10,0x3c,0x00,0x74,0x03,0xee,
-  0x90,0x90,0xec,0x8b,0xfe,0x1e,0x07,0xaa,0x32,0xe4,0xc3,0xb4,
-  0x80,0xc3,0xac,0x3c,0x12,0x7f,0x1f,0xfe,0xc8,0x32,0xe4,0xd1,
-  0xe0,0x8d,0x1e,0x66,0xf8,0x03,0xd8,0x2e,0x8b,0x17,0xec,0xac,
-  0x3c,0x0f,0x7f,0x0a,0x3c,0x00,0x74,0x01,0xee,0xac,0xee,0x32,
-  0xe4,0xc3,0xb4,0x80,0xc3,0xfc,0x8e,0xc0,0xb8,0xff,0xff,0x8b,
-  0xcb,0x33,0xff,0xf3,0xab,0x8b,0xcb,0x33,0xff,0xf3,0xaf,0xe3,
-  0x01,0xc3,0x8b,0xcb,0xbf,0x00,0x00,0x26,0x89,0x3d,0x83,0xc7,
-  0x02,0xe2,0xf8,0xbe,0x00,0x00,0x8b,0xcb,0x26,0x8b,0x3c,0x3b,
-  0xfe,0x74,0x01,0xc3,0x83,0xc6,0x02,0x83,0xc7,0x02,0xe2,0xf0,
-  0x33,0xc0,0x8b,0xcb,0x33,0xff,0xf3,0xab,0x8b,0xcb,0x33,0xff,
-  0xf3,0xaf,0xc3,0x32,0xc0,0x26,0x80,0x3e,0x23,0x00,0x00,0x74,
-  0x02,0x0c,0x01,0x26,0xf7,0x06,0x20,0x00,0x0f,0x00,0x74,0x02,
-  0x0c,0x02,0x26,0xf7,0x06,0x20,0x00,0xf0,0x00,0x74,0x02,0x0c,
-  0x04,0x26,0xf7,0x06,0x20,0x00,0x00,0xff,0x74,0x02,0x0c,0x08,
-  0x26,0xa2,0x24,0x00,0xb8,0x00,0x40,0xba,0x5e,0xff,0xef,0xba,
-  0x66,0xff,0xef,0xba,0x52,0xff,0xb8,0x63,0x0e,0xef,0xba,0x56,
-  0xff,0xb8,0x05,0xe0,0xef,0xba,0x28,0xff,0xb8,0xfc,0x00,0xef,
-  0xb8,0x00,0x02,0x26,0xa3,0x2e,0x00,0xb8,0x04,0x00,0x26,0xa3,
-  0x2c,0x00,0xb0,0xc3,0xe6,0x08,0x8a,0xd8,0xe4,0x08,0x3a,0xc3,
-  0x75,0x06,0x26,0xc6,0x06,0xb4,0x00,0x01,0xb0,0x00,0xe6,0x00,
-  0xfc,0x8d,0x3e,0x00,0x00,0xb8,0x47,0x44,0xab,0xb8,0xff,0xff,
-  0xab,0xab,0xab,0xb8,0x42,0x49,0xab,0xb8,0x4f,0x53,0xab,0xb8,
-  0x58,0x69,0x26,0x80,0x3e,0x10,0x00,0x04,0x74,0x0e,0xb8,0x58,
-  0x65,0x26,0x80,0x3e,0x10,0x00,0x03,0x74,0x03,0xb8,0x58,0x74,
-  0xab,0x8d,0x36,0xfe,0xff,0x8a,0x04,0x8d,0x36,0xff,0xff,0x8a,
-  0x24,0xab,0xfb,0x26,0x81,0x0e,0x12,0x00,0x00,0x08,0x06,0x1f,
-  0xa1,0x00,0x00,0x8b,0x1e,0x02,0x00,0x3d,0x44,0x47,0x75,0x0b,
-  0x26,0x81,0x0e,0x12,0x00,0x00,0x10,0xff,0x2e,0x2c,0x00,0x81,
-  0xfb,0x45,0x4d,0x75,0xe3,0x26,0x81,0x0e,0x12,0x00,0x00,0x20,
-  0xff,0x2e,0x2c,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-  0xff,0xff,0xff,0xff,0xfa,0xba,0xa8,0xff,0xb8,0xba,0x81,0xef,
-  0xba,0xa4,0xff,0xb8,0x3a,0x00,0xef,0x90,0xe4,0x00,0xa8,0x60,
-  0x75,0x0c,0x24,0x06,0x74,0x14,0x3c,0x02,0x74,0x1c,0x3c,0x04,
-  0x74,0x24,0xbb,0x38,0xc0,0xbe,0xf8,0x81,0xbf,0xba,0xa0,0xeb,
-  0x22,0x90,0xbb,0x38,0xf0,0xbe,0xf8,0x41,0xbf,0xba,0x81,0xeb,
-  0x16,0x90,0xbb,0x38,0xf0,0xbe,0xf8,0xe1,0xbf,0xba,0x88,0xeb,
-  0x0a,0x90,0xbb,0x38,0xc0,0xbe,0xf8,0x41,0xbf,0xba,0x81,0xba,
-  0xa0,0xff,0x8b,0xc3,0xef,0xba,0xa2,0xff,0xb8,0xf8,0x0f,0xef,
-  0xba,0xa6,0xff,0x8b,0xc6,0xef,0xba,0xa8,0xff,0x8b,0xc7,0xef,
-  0x8c,0xc8,0x8e,0xd8,0xe4,0x00,0x24,0x06,0x74,0x17,0xbb,0x00,
-  0x80,0xbd,0xc0,0xe0,0x3c,0x02,0x74,0x5a,0xbd,0xc0,0xc0,0x3c,
-  0x04,0x74,0x53,0xbd,0xc0,0x80,0xeb,0x4e,0x90,0xb9,0x08,0x00,
-  0xb8,0x00,0x80,0x8e,0xc0,0x26,0xa3,0x00,0x00,0x05,0x00,0x10,
-  0xe2,0xf5,0xbd,0xc0,0xf0,0xbb,0x00,0x7c,0xb8,0x00,0xe0,0x8e,
-  0xc0,0x26,0x8b,0x0e,0x00,0x00,0x3b,0xc8,0x75,0x28,0xbb,0x00,
-  0x80,0xbd,0xc0,0xe0,0xb8,0x00,0xc0,0x8e,0xc0,0x26,0x8b,0x0e,
-  0x00,0x00,0x3b,0xc8,0x75,0x14,0xbd,0xc0,0xc0,0xb8,0x00,0x80,
-  0x8e,0xc0,0x26,0x8b,0x0e,0x00,0x00,0x3b,0xc8,0x75,0x03,0xbd,
-  0xc0,0x80,0x8c,0xc8,0x8e,0xd0,0xbc,0xed,0xfc,0x8b,0xc5,0x25,
-  0x00,0xf0,0xe9,0x6c,0xfd,0xb4,0x00,0x74,0x06,0xb4,0xff,0xeb,
-  0x02,0xe5,0xfc,0x8e,0xc5,0x2e,0x89,0x2e,0x22,0xf8,0xe4,0x00,
-  0x24,0x16,0x26,0xa2,0x11,0x00,0x26,0x83,0x0e,0x12,0x00,0x01,
-  0x80,0xfc,0x00,0x74,0x06,0x26,0x83,0x0e,0x14,0x00,0x01,0x26,
-  0xc7,0x06,0x18,0x00,0x40,0x00,0x26,0xc6,0x06,0x10,0x00,0x03,
-  0xa8,0x10,0x74,0x06,0x26,0xc6,0x06,0x10,0x00,0x04,0xb8,0x00,
-  0x00,0x8e,0xc0,0xb8,0xaa,0x55,0x26,0xa3,0x00,0x00,0x26,0xc7,
-  0x06,0x02,0x00,0x00,0x00,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,
-  0x8b,0xcd,0x81,0xe1,0x00,0xf0,0x8e,0xc1,0x26,0x8b,0x1e,0x00,
-  0x00,0x3b,0xc3,0x75,0x13,0x8e,0xc5,0x26,0xc6,0x06,0x10,0x00,
-  0x05,0xb8,0x40,0x00,0x8e,0xd0,0xbc,0x00,0x04,0xe9,0x99,0x00,
-  0x8c,0xc8,0x8e,0xd0,0xbc,0x7c,0xfd,0xb8,0x00,0x00,0xbb,0x00,
-  0x20,0xe9,0xdd,0xfc,0xb4,0x00,0x74,0x06,0xb4,0xff,0xeb,0x02,
-  0x74,0xfd,0x8e,0xc5,0x80,0xfc,0x00,0x74,0x08,0x26,0x83,0x0e,
-  0x14,0x00,0x02,0xeb,0x0d,0x26,0xc7,0x06,0x16,0x00,0x10,0x00,
-  0x26,0x83,0x0e,0x12,0x00,0x02,0xb8,0x40,0x00,0x8e,0xd0,0xbc,
-  0x00,0x04,0xe4,0x00,0xa8,0x60,0x75,0x07,0xba,0xa2,0xff,0xb8,
-  0xfc,0x0f,0xef,0xb8,0x00,0x04,0x8e,0xc0,0xb8,0xaa,0x55,0x26,
-  0xa3,0x00,0x00,0x26,0xc7,0x06,0x02,0x00,0x00,0x00,0x26,0xc7,
-  0x06,0x04,0x00,0x00,0x00,0xb9,0x00,0x00,0x8e,0xc1,0x26,0x8b,
-  0x1e,0x00,0x00,0x3b,0xc3,0x75,0x02,0xeb,0x24,0x8e,0xc5,0x26,
-  0x83,0x0e,0x12,0x00,0x04,0xb8,0x00,0x04,0xbb,0x00,0x60,0x06,
-  0xe8,0x66,0xfc,0x07,0x75,0x09,0x26,0xc7,0x06,0x16,0x00,0x40,
-  0x00,0xeb,0x06,0x26,0x83,0x0e,0x14,0x00,0x04,0x8e,0xc5,0x8c,
-  0xc0,0x3d,0xc0,0xf0,0x75,0x03,0xe9,0x9f,0x00,0x3d,0xc0,0x80,
-  0x74,0x62,0x3d,0xc0,0xc0,0x74,0x23,0x26,0x83,0x0e,0x12,0x00,
-  0x08,0xb8,0x00,0xf0,0xbb,0x00,0x7c,0x06,0xe8,0x2e,0xfc,0x07,
-  0x75,0x08,0x26,0x83,0x06,0x18,0x00,0x40,0xeb,0x06,0x26,0x83,
-  0x0e,0x14,0x00,0x08,0xeb,0x72,0xb9,0x03,0x00,0xb8,0x00,0xd0,
-  0xba,0x08,0x00,0xbb,0x00,0x80,0x3d,0x00,0xf0,0x75,0x03,0xbb,
-  0x00,0x7c,0x26,0x09,0x16,0x12,0x00,0x06,0x50,0x51,0xe8,0xfc,
-  0xfb,0x59,0x58,0x07,0x75,0x0f,0x26,0x83,0x06,0x18,0x00,0x40,
-  0xd1,0xe2,0x05,0x00,0x10,0xe2,0xd8,0xeb,0x05,0x26,0x09,0x16,
-  0x14,0x00,0xeb,0x38,0xb9,0x07,0x00,0xb8,0x00,0x90,0xba,0x08,
-  0x00,0xbb,0x00,0x80,0x3d,0x00,0xf0,0x75,0x03,0xbb,0x00,0x7c,
-  0x26,0x09,0x16,0x12,0x00,0x06,0x50,0x51,0xe8,0xc2,0xfb,0x59,
-  0x58,0x07,0x75,0x0f,0x26,0x83,0x06,0x18,0x00,0x40,0xd1,0xe2,
-  0x05,0x00,0x10,0xe2,0xd8,0xeb,0x05,0x26,0x09,0x16,0x14,0x00,
-  0x26,0xa1,0x18,0x00,0x2d,0x10,0x00,0x26,0xa3,0x1a,0x00,0x06,
-  0xfc,0x33,0xff,0x8e,0xc7,0xb9,0x00,0x02,0xb8,0x00,0xf0,0xf3,
-  0xab,0x33,0xff,0xbe,0x24,0xf8,0xb9,0x20,0x00,0xa5,0x47,0x47,
-  0xe2,0xfb,0xbe,0x64,0xf8,0xb9,0xe0,0x00,0x8b,0x1c,0x26,0x89,
-  0x1d,0x83,0xc7,0x04,0xe2,0xf8,0x07,0xba,0x28,0xff,0xb8,0xfd,
-  0x00,0xef,0xba,0x32,0xff,0xb8,0x0d,0x00,0xef,0xba,0x34,0xff,
-  0xb8,0x0f,0x00,0xef,0xba,0x36,0xff,0xb8,0x0e,0x00,0xef,0xba,
-  0x38,0xff,0xb8,0x19,0x00,0xef,0xba,0x3a,0xff,0xb8,0x18,0x00,
-  0xef,0xba,0x3c,0xff,0xb8,0x0b,0x00,0xef,0xba,0x3e,0xff,0xb8,
-  0x1a,0x00,0xef,0x8d,0x3e,0x90,0x00,0x8d,0x36,0x66,0xf8,0xb9,
-  0x10,0x00,0xf3,0xa5,0x8d,0x3e,0xb0,0x00,0x8d,0x36,0x86,0xf8,
-  0xb9,0x02,0x00,0xf3,0xa5,0xb9,0x10,0x00,0x8d,0x36,0x90,0x00,
-  0x83,0xc6,0x1e,0x26,0x8b,0x14,0xb3,0x10,0x32,0xc0,0xec,0xb0,
-  0x0c,0xee,0x8a,0xc3,0x8a,0xc3,0xee,0x83,0xee,0x02,0x26,0x8b,
-  0x14,0xfe,0xcb,0xe2,0xeb,0xb9,0x10,0x00,0x8d,0x36,0x90,0x00,
-  0x26,0x8b,0x14,0xb3,0x01,0xbf,0x00,0x80,0xb0,0x0c,0xee,0xf6,
-  0xe8,0xec,0x3a,0xc3,0x75,0x0e,0xd1,0xc7,0x26,0x09,0x3e,0x20,
-  0x00,0x26,0xfe,0x06,0x22,0x00,0xeb,0x07,0x33,0xc0,0x26,0x89,
-  0x04,0xd1,0xc7,0x83,0xc6,0x02,0x26,0x8b,0x14,0xfe,0xc3,0xe2,
-  0xd7,0x26,0xc6,0x06,0x23,0x00,0x01,0x8d,0x36,0xb0,0x00,0x26,
-  0x8b,0x14,0x32,0xc0,0xee,0xb0,0x0c,0xee,0xb0,0x5a,0xee,0xb0,
-  0x0c,0xee,0xf6,0xe8,0xec,0x3c,0x5a,0x74,0x14,0x26,0xc7,0x06,
-  0xb0,0x00,0x00,0x00,0x26,0xc7,0x06,0xb2,0x00,0x00,0x00,0x26,
-  0xc6,0x06,0x23,0x00,0x00,0xe9,0xd3,0xfa,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0xea,0x00,0xfc,0x00,0xf0,0x4d,0x2f,0x50,
-  0x43,0x2f,0x58,0x2a,0x39,0x34,0x34,0x31
-};
-
-
diff --git a/drivers/char/digi_fep.h b/drivers/char/digi_fep.h
deleted file mode 100644
--- a/drivers/char/digi_fep.h
+++ /dev/null
@@ -1,517 +0,0 @@
-/* DigiBoard PCXX Bios */
-
-static unsigned char pcxx_cook[] __initdata = {
-  0x4f,0x53,0x18,0x80,0xe9,0xbf,0x15,0x00,0x40,0x28,0x23,0x29,
-  0x46,0x45,0x50,0x4f,0x53,0x20,0x37,0x2e,0x30,0x38,0x20,0x34,
-  0x2f,0x32,0x30,0x2f,0x39,0x35,0x00,0x40,0x28,0x23,0x29,0x28,
-  0x43,0x29,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,
-  0x31,0x39,0x38,0x39,0x2d,0x31,0x39,0x39,0x35,0x20,0x44,0x69,
-  0x67,0x69,0x42,0x6f,0x61,0x72,0x64,0x20,0x49,0x6e,0x63,0x2e,
-  0x00,0xcb,0x0c,0xcb,0x0c,0xe2,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,
-  0x0c,0xcb,0x0c,0xcb,0x0c,0x57,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,
-  0x0c,0x53,0x0b,0xcb,0x0c,0xcb,0x0c,0x42,0x0b,0xcb,0x0c,0xcb,
-  0x0c,0x12,0x0d,0xcb,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,
-  0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,0x0c,0xcb,
-  0x0c,0xcb,0x0c,0xcb,0x0c,0x00,0x10,0x80,0x10,0x00,0x11,0x80,
-  0x11,0x00,0x12,0x80,0x12,0x00,0x13,0x80,0x13,0x00,0x14,0x80,
-  0x14,0x00,0x15,0x80,0x15,0x00,0x16,0x80,0x16,0x00,0x17,0x80,
-  0x17,0x78,0x0b,0xb9,0x0b,0x50,0x0c,0xb9,0x0b,0x8d,0x0b,0x8d,
-  0x0b,0x8d,0x0b,0x8d,0x0b,0xc0,0x0b,0xc0,0x0b,0xc0,0x0b,0xc0,
-  0x0b,0x8d,0x0b,0x8d,0x0b,0x8d,0x0b,0x8d,0x0b,0x50,0x0c,0xb9,
-  0x0b,0x50,0x0c,0xb9,0x0b,0x8d,0x0b,0x8d,0x0b,0x8d,0x0b,0x8d,
-  0x0b,0xc0,0x0b,0xc0,0x0b,0xc0,0x0b,0xc0,0x0b,0x8d,0x0b,0x8d,
-  0x0b,0x8d,0x0b,0x8d,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,
-  0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,
-  0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,
-  0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,
-  0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,
-  0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x94,0x0b,0x16,0x00,0xfe,
-  0x11,0xfe,0x0b,0x2c,0x08,0xb5,0x06,0xfe,0x05,0x7e,0x04,0xfe,
-  0x02,0x7e,0x01,0xbe,0x00,0x7e,0x00,0x5e,0x00,0x2e,0x00,0x16,
-  0x00,0x0a,0x00,0x04,0x00,0x16,0x00,0x02,0x00,0x01,0x00,0x00,
-  0x00,0x0e,0x00,0x06,0x00,0x7e,0x04,0xfe,0x02,0x7e,0x01,0xbe,
-  0x00,0x7e,0x00,0x5e,0x00,0x2e,0x00,0x16,0x00,0x0a,0x00,0x04,
-  0x00,0x18,0x00,0x86,0x13,0x03,0x0d,0xdf,0x08,0x41,0x07,0x81,
-  0x06,0xe0,0x04,0x3f,0x03,0x9f,0x01,0xce,0x00,0x89,0x00,0x66,
-  0x00,0x32,0x00,0x18,0x00,0x0b,0x00,0x0b,0x00,0x18,0x00,0x0b,
-  0x00,0x0b,0x00,0x0b,0x00,0x41,0x07,0x81,0x06,0xe0,0x04,0x3f,
-  0x03,0x9f,0x01,0xce,0x00,0x89,0x00,0x66,0x00,0x32,0x00,0x18,
-  0x00,0x0b,0x00,0x0b,0x00,0x00,0x80,0x40,0xc0,0x1f,0x3f,0x7f,
-  0xff,0x00,0x04,0x02,0x06,0x08,0x0c,0x0a,0x0e,0x00,0x04,0x02,
-  0x06,0x08,0x0c,0x0a,0x0e,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0x1e,0x06,0x3e,
-  0x06,0xef,0x06,0xf8,0x05,0x0e,0x06,0x55,0x07,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,
-  0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,
-  0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,
-  0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0xa1,
-  0x05,0xa1,0x05,0xa1,0x05,0xa1,0x05,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x5b,0x05,0xea,0x05,0xea,0x05,0xea,
-  0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,
-  0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,
-  0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,
-  0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0xea,0x05,0x69,
-  0x05,0x77,0x05,0x85,0x05,0x93,0x05,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,0x08,0xa0,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,0x08,0x9d,
-  0x08,0x00,0x00,0xfa,0x8a,0x5c,0x50,0xf6,0xc3,0x0e,0x75,0x3c,
-  0xf6,0xc3,0x40,0x75,0x16,0xf6,0xc3,0x10,0x74,0x26,0xf6,0xc3,
-  0x01,0x75,0x13,0xf6,0xc3,0x20,0x75,0x15,0xc7,0x04,0xb6,0x04,
-  0xe9,0xcf,0x00,0x8b,0x44,0x02,0x89,0x04,0xff,0xe0,0xc7,0x04,
-  0x03,0x05,0xe9,0x0e,0x01,0xc7,0x04,0x66,0x08,0xe9,0x6a,0x04,
-  0xf6,0xc3,0x20,0x74,0x1a,0xc7,0x04,0xb3,0x08,0xe9,0xab,0x04,
-  0x8b,0x54,0x20,0xec,0x8a,0xc8,0xf6,0xc3,0x02,0x75,0x42,0xf6,
-  0xc3,0x08,0x75,0x0e,0xeb,0x69,0x90,0xc7,0x04,0x20,0x04,0xfb,
-  0x81,0xc6,0x80,0x00,0xff,0x24,0xf6,0xc1,0x04,0x74,0x27,0x80,
-  0x64,0x50,0xf7,0xf6,0x44,0x51,0x02,0x74,0x13,0xf6,0x44,0x29,
-  0x10,0x74,0x0d,0x8a,0x44,0x5d,0x83,0xc2,0x02,0xee,0x83,0xea,
-  0x02,0xe9,0x49,0x04,0x8a,0x44,0x5c,0x83,0xc2,0x02,0xee,0x83,
-  0xea,0x02,0xe9,0x3c,0x04,0xf6,0x44,0x50,0x04,0x75,0x28,0x83,
-  0x7c,0x24,0xff,0x74,0x1f,0xa1,0x00,0x0e,0x2b,0x44,0x26,0x3d,
-  0x64,0x00,0x77,0x14,0xb0,0x05,0xee,0x8a,0x44,0x75,0x24,0xef,
-  0x88,0x44,0x75,0xee,0x80,0x64,0x50,0xfd,0x80,0x64,0x4b,0xfd,
-  0xe9,0x0e,0x04,0xb0,0x01,0xee,0x90,0x90,0x90,0xec,0xa8,0x01,
-  0x74,0x25,0xb0,0x05,0xee,0x8a,0x44,0x75,0x0c,0x10,0x88,0x44,
-  0x75,0xee,0xa1,0x00,0x0e,0x03,0x44,0x24,0x89,0x44,0x26,0x80,
-  0x64,0x50,0xfb,0x80,0x64,0x4b,0xfb,0x80,0x4c,0x50,0x02,0x80,
-  0x4c,0x4b,0x02,0xe9,0xdb,0x03,0xfa,0x8b,0x54,0x20,0xec,0x8a,
-  0xc8,0x22,0x44,0x52,0x3a,0x44,0x53,0x75,0x19,0x8b,0x7c,0x0c,
-  0x3b,0x7c,0x0a,0x74,0x18,0x8e,0x44,0x08,0x26,0x8a,0x05,0x47,
-  0x23,0x7c,0x0e,0x89,0x7c,0x0c,0x83,0xc2,0x02,0xee,0xfb,0x81,
-  0xc6,0x80,0x00,0xff,0x24,0xb0,0x01,0xee,0x90,0x90,0x90,0xec,
-  0xa8,0x01,0x74,0x0c,0x80,0x64,0x50,0xef,0x80,0x64,0x4b,0xef,
-  0xc7,0x04,0xc3,0x03,0xfb,0x81,0xc6,0x80,0x00,0xff,0x24,0xfa,
-  0x8b,0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,0x3a,0x44,0x53,
-  0x75,0x3a,0x8b,0x7c,0x0c,0x3b,0x7c,0x0a,0x74,0x1b,0x8e,0x44,
-  0x08,0x26,0x8a,0x05,0x47,0x23,0x7c,0x0e,0x89,0x7c,0x0c,0x8a,
-  0xd8,0x22,0x5c,0x62,0x32,0xff,0x03,0xdb,0x2e,0xff,0xa7,0xc1,
-  0x01,0xb0,0x01,0xee,0x90,0x90,0x90,0xec,0xa8,0x01,0x74,0x0c,
-  0x80,0x64,0x50,0xef,0x80,0x64,0x4b,0xef,0xc7,0x04,0xc3,0x03,
-  0xf6,0xc1,0x01,0x75,0x07,0xfb,0x81,0xc6,0x80,0x00,0xff,0x24,
-  0xe9,0x61,0x03,0xf6,0x44,0x2a,0x01,0x75,0x03,0xe9,0x39,0x03,
-  0xb0,0x27,0xeb,0x42,0x90,0xf6,0x44,0x2a,0x01,0x75,0x03,0xe9,
-  0x2b,0x03,0xb0,0x28,0xeb,0x34,0x90,0xf6,0x44,0x2a,0x01,0x75,
-  0x03,0xe9,0x1d,0x03,0xb0,0x21,0xeb,0x26,0x90,0xf6,0x44,0x2a,
-  0x01,0x75,0x03,0xe9,0x0f,0x03,0xb0,0x29,0xeb,0x18,0x90,0xf6,
-  0x44,0x2a,0x01,0x75,0x03,0xe9,0x01,0x03,0xb0,0x5e,0xeb,0x0a,
-  0x90,0xf6,0x44,0x2a,0x01,0x75,0x03,0xe9,0xf3,0x02,0x88,0x44,
-  0x61,0xb0,0x5c,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0x80,0x4c,
-  0x50,0x40,0xc7,0x04,0xc6,0x05,0xc7,0x44,0x02,0xc6,0x05,0xe9,
-  0xcb,0x02,0xfa,0x8b,0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,
-  0x3a,0x44,0x53,0x75,0x12,0x80,0x64,0x50,0xbf,0xc7,0x04,0x03,
-  0x05,0x83,0x44,0x30,0x02,0x8a,0x44,0x61,0xe9,0xb9,0x02,0xe9,
-  0xa7,0x02,0xf6,0x44,0x2a,0x02,0x75,0x03,0xe9,0xaa,0x02,0x2c,
-  0x20,0xe9,0xa5,0x02,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0xf6,
-  0x44,0x2b,0x40,0x75,0x03,0xe9,0x89,0x02,0xb8,0x7f,0x00,0xe9,
-  0x9b,0x01,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0xf6,0x44,0x2b,
-  0x80,0x75,0xed,0xe9,0x73,0x02,0x83,0xc2,0x02,0xee,0x83,0xea,
-  0x02,0xf7,0x44,0x30,0xff,0xff,0x74,0x03,0xff,0x4c,0x30,0xf6,
-  0x44,0x2b,0x20,0x75,0x03,0xe9,0x59,0x02,0xb8,0x02,0x00,0xe9,
-  0x6b,0x01,0xb3,0x18,0x22,0x5c,0x2b,0x75,0x16,0x83,0xc2,0x02,
-  0xee,0x83,0xea,0x02,0x8b,0x44,0x30,0x05,0x08,0x00,0x25,0xf8,
-  0xff,0x89,0x44,0x30,0xe9,0x36,0x02,0x80,0xfb,0x18,0x75,0x57,
-  0xb0,0x20,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0x8b,0x44,0x30,
-  0x8b,0xd8,0x05,0x08,0x00,0x25,0xf8,0xff,0x89,0x44,0x30,0x2b,
-  0xc3,0x48,0x74,0x38,0x89,0x44,0x32,0x80,0x4c,0x50,0x40,0xc7,
-  0x44,0x02,0x8f,0x06,0xc7,0x04,0x8f,0x06,0xe9,0x02,0x02,0xfa,
-  0x8b,0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,0x3a,0x44,0x53,
-  0x75,0x16,0xb0,0x20,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0xff,
-  0x4c,0x32,0x75,0x08,0x80,0x64,0x50,0xbf,0xc7,0x04,0x03,0x05,
-  0xe9,0xda,0x01,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0x80,0xfb,
-  0x08,0x75,0x18,0x8b,0x44,0x30,0x8b,0xd8,0x05,0x08,0x00,0x25,
-  0xf8,0xff,0x89,0x44,0x30,0x2b,0xc3,0x3d,0x05,0x00,0x7c,0xdc,
-  0xe9,0xce,0x00,0x8b,0x44,0x30,0x8b,0xd8,0x05,0x08,0x00,0x25,
-  0xf8,0xff,0x89,0x44,0x30,0xb8,0x02,0x00,0xe9,0xba,0x00,0xf6,
-  0x44,0x2a,0x20,0x75,0x43,0xf6,0x44,0x2a,0x04,0x74,0x42,0xf6,
-  0x44,0x2a,0x10,0x74,0x07,0xf7,0x44,0x30,0xff,0xff,0x74,0x30,
-  0xb0,0x0d,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0x80,0x4c,0x50,
-  0x40,0xc7,0x04,0x21,0x07,0xc7,0x44,0x02,0x21,0x07,0xe9,0x70,
-  0x01,0xfa,0x8b,0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,0x3a,
-  0x44,0x53,0x75,0x1c,0x80,0x64,0x50,0xbf,0xc7,0x04,0x03,0x05,
-  0xb0,0x0a,0xeb,0x2b,0x90,0xb0,0x0a,0x83,0xc2,0x02,0xee,0x83,
-  0xea,0x02,0xf6,0x44,0x2b,0x01,0x75,0x03,0xe9,0x42,0x01,0xb8,
-  0x05,0x00,0xeb,0x55,0x90,0xf6,0x44,0x2a,0x08,0x75,0xe2,0xf6,
-  0x44,0x2a,0x10,0x74,0x06,0x83,0x7c,0x30,0x00,0x74,0x13,0x83,
-  0xc2,0x02,0xee,0x83,0xea,0x02,0xb3,0x06,0x22,0x5c,0x2b,0x75,
-  0x08,0xc7,0x44,0x30,0x00,0x00,0xe9,0x14,0x01,0x80,0xfb,0x02,
-  0x75,0x14,0x8b,0x44,0x30,0xc1,0xe8,0x04,0x05,0x03,0x00,0x3d,
-  0x06,0x00,0x72,0x14,0xb8,0x06,0x00,0xeb,0x0f,0x90,0x80,0xfb,
-  0x04,0x75,0x06,0xb8,0x05,0x00,0xeb,0x04,0x90,0xb8,0x09,0x00,
-  0xc7,0x44,0x30,0x00,0x00,0xf6,0x44,0x2a,0x40,0x74,0x45,0x3d,
-  0x20,0x00,0x77,0x40,0xbb,0x01,0x00,0x3d,0x03,0x00,0x7e,0x03,
-  0xbb,0x02,0x00,0x89,0x5c,0x32,0x80,0x4c,0x50,0x40,0xc7,0x44,
-  0x02,0xd2,0x07,0xc7,0x04,0xd2,0x07,0xe9,0xbf,0x00,0xfa,0x8b,
-  0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,0x3a,0x44,0x53,0x75,
-  0x10,0x8a,0x44,0x60,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0x83,
-  0x6c,0x32,0x01,0x7e,0x50,0xe9,0x9d,0x00,0x05,0x06,0x00,0x03,
-  0xc0,0x89,0x44,0x32,0x80,0x4c,0x50,0x40,0xc7,0x44,0x02,0x0c,
-  0x08,0xc7,0x04,0x0c,0x08,0xe9,0x85,0x00,0xfa,0x8b,0x54,0x20,
-  0xec,0x8a,0xc8,0xb0,0x01,0xee,0x90,0x90,0x90,0xec,0xa8,0x01,
-  0x74,0x0f,0xa1,0x00,0x0e,0x01,0x44,0x32,0xc7,0x44,0x02,0x30,
-  0x08,0xc7,0x04,0x30,0x08,0xeb,0x62,0x90,0x8b,0x54,0x20,0xec,
-  0x8a,0xc8,0xa1,0x00,0x0e,0x2b,0x44,0x32,0x3d,0xe8,0x03,0x77,
-  0xec,0x80,0x64,0x50,0xbf,0xc7,0x04,0x03,0x05,0xeb,0x46,0x90,
-  0xb0,0x01,0xee,0x90,0x90,0x90,0xec,0xa8,0x01,0x74,0x3a,0x80,
-  0x64,0x50,0xef,0x80,0x64,0x4b,0xef,0xc7,0x04,0xb3,0x08,0xeb,
-  0x2c,0x90,0xfa,0x8b,0x54,0x20,0xec,0x8a,0xc8,0x22,0x44,0x52,
-  0x3a,0x44,0x53,0x75,0x1c,0x8b,0x7c,0x0c,0x3b,0x7c,0x0a,0x74,
-  0xcf,0x8e,0x44,0x08,0x26,0x8a,0x05,0x47,0x23,0x7c,0x0e,0x89,
-  0x7c,0x0c,0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0xf6,0xc1,0x01,
-  0x75,0x26,0xfb,0x81,0xc6,0x80,0x00,0xff,0x24,0xff,0x44,0x30,
-  0x83,0xc2,0x02,0xee,0x83,0xea,0x02,0xf6,0xc1,0x01,0x75,0x10,
-  0xfb,0x81,0xc6,0x80,0x00,0xff,0x24,0xfa,0x8b,0x54,0x20,0xec,
-  0xa8,0x01,0x74,0xda,0xc6,0x44,0x49,0x02,0x8b,0x7c,0x12,0x8e,
-  0x44,0x10,0xb0,0x01,0xee,0x90,0x90,0x90,0xec,0x8a,0xe0,0x90,
-  0xb0,0x30,0xee,0x83,0xc2,0x02,0x90,0xec,0x83,0xea,0x02,0x23,
-  0x44,0x34,0xff,0x64,0x06,0xb3,0x1c,0x22,0x5c,0x51,0x75,0x1a,
-  0xf6,0x44,0x29,0x04,0x74,0x21,0xf6,0x44,0x29,0x20,0x75,0x2b,
-  0x80,0x7c,0x5e,0x00,0x75,0x1d,0xc7,0x44,0x06,0x58,0x0a,0xe9,
-  0x56,0x01,0xf6,0xc3,0x10,0x75,0x2e,0xf6,0xc3,0x04,0x75,0x74,
-  0xeb,0x6b,0x90,0xc7,0x44,0x06,0x62,0x0a,0xe9,0x4b,0x01,0xc7,
-  0x44,0x06,0x53,0x0a,0xe9,0x34,0x01,0x80,0x7c,0x5e,0x00,0x75,
-  0x08,0xc7,0x44,0x06,0xca,0x09,0xe9,0x9d,0x00,0xc7,0x44,0x06,
-  0xc5,0x09,0xe9,0x90,0x00,0x0a,0xc0,0x74,0x2a,0xfe,0x4c,0x63,
-  0x74,0x1a,0x80,0xe3,0xef,0x75,0xc4,0xf6,0x44,0x29,0x04,0x74,
-  0x21,0xf6,0x44,0x29,0x20,0x75,0x21,0x80,0x7c,0x5e,0x00,0x75,
-  0x18,0xe9,0x00,0x01,0x80,0x64,0x51,0xef,0x80,0xe3,0xef,0x75,
-  0xa6,0xeb,0x85,0x80,0x64,0x51,0xef,0xe9,0x06,0x01,0xe9,0xf5,
-  0x00,0xe9,0xe3,0x00,0x80,0x7c,0x5e,0x00,0x75,0x4f,0xeb,0x52,
-  0x90,0x80,0x64,0x51,0xf7,0xe9,0xe2,0x00,0x80,0x64,0x53,0x3f,
-  0x80,0x64,0x54,0xfe,0x80,0x4c,0x58,0x01,0x80,0x64,0x51,0xfb,
-  0xf6,0x44,0x29,0x40,0x75,0x2c,0x3a,0x44,0x5d,0x74,0x27,0x3a,
-  0x44,0x5c,0x74,0x22,0xf6,0x44,0x29,0x20,0x74,0x0a,0x3a,0x44,
-  0x5a,0x74,0x17,0x3a,0x44,0x5b,0x74,0x12,0xf6,0x44,0x5e,0xff,
-  0x74,0x09,0x3a,0x44,0x5e,0x75,0x04,0x80,0x4c,0x51,0x08,0xe9,
-  0xa0,0x00,0xe9,0xab,0x00,0x3a,0x44,0x5e,0x74,0x7d,0x3a,0x44,
-  0x5c,0x74,0x3d,0x3a,0x44,0x5d,0x74,0x55,0x3a,0x44,0x5a,0x74,
-  0x08,0x3a,0x44,0x5b,0x74,0x18,0xe9,0x81,0x00,0xf6,0x44,0x53,
-  0x40,0x74,0x07,0x80,0x64,0x53,0xbf,0xe9,0x82,0x00,0x3a,0x44,
-  0x5b,0x74,0x03,0xeb,0x7b,0x90,0x80,0x4c,0x53,0x40,0xf6,0x44,
-  0x29,0x08,0x74,0x70,0x80,0x4c,0x51,0x04,0xc7,0x44,0x06,0xe1,
-  0x08,0xeb,0x65,0x90,0xf6,0x44,0x53,0x80,0x74,0x0f,0x80,0x64,
-  0x53,0x7f,0x80,0x64,0x54,0xfe,0x80,0x4c,0x58,0x01,0xeb,0x50,
-  0x90,0x3a,0x44,0x5d,0x74,0x03,0xeb,0x48,0x90,0x80,0x4c,0x53,
-  0x80,0x80,0x4c,0x54,0x01,0x80,0x4c,0x58,0x01,0xf6,0x44,0x29,
-  0x08,0x74,0x35,0x80,0x4c,0x51,0x04,0xc7,0x44,0x06,0xe1,0x08,
-  0xeb,0x2a,0x90,0x80,0x4c,0x51,0x08,0xc7,0x44,0x06,0xe1,0x08,
-  0xeb,0x10,0x90,0x3a,0x44,0x5e,0x74,0xef,0x3a,0x44,0x5c,0x74,
-  0xaf,0x3a,0x44,0x5d,0x74,0xc7,0x3d,0xff,0x00,0x73,0x26,0xaa,
-  0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0x4f,0xec,0xa8,0x01,0x74,
-  0x03,0xe9,0x4e,0xfe,0x89,0x7c,0x12,0x2b,0x7c,0x14,0x23,0x7c,
-  0x16,0x3b,0x7c,0x1c,0x73,0x46,0xfb,0x81,0xc6,0x80,0x00,0xff,
-  0x24,0x0a,0xe4,0x75,0x1e,0xb3,0x0c,0x22,0x5c,0x28,0x80,0xfb,
-  0x08,0x75,0xcc,0xaa,0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0x1b,
-  0xaa,0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0x12,0xeb,0xc1,0xf6,
-  0x44,0x28,0x04,0x75,0xbb,0xf6,0x44,0x28,0x08,0x75,0x50,0x32,
-  0xc0,0xeb,0xa8,0x4f,0x23,0x7c,0x16,0x89,0x7c,0x12,0xc6,0x44,
-  0x59,0x01,0xeb,0xa4,0xf6,0x44,0x51,0x02,0x74,0x07,0xfb,0x81,
-  0xc6,0x80,0x00,0xff,0x24,0x80,0x4c,0x51,0x02,0xb0,0x05,0xee,
-  0xb0,0x82,0x22,0x44,0x5f,0xf6,0xd0,0x22,0x44,0x75,0x88,0x44,
-  0x75,0xee,0xf6,0x44,0x29,0x10,0x74,0x10,0x80,0x4c,0x54,0x04,
-  0x80,0x4c,0x58,0x04,0x80,0x74,0x50,0x08,0xc7,0x04,0xc3,0x03,
-  0xfb,0x81,0xc6,0x80,0x00,0xff,0x24,0x26,0xc6,0x05,0xff,0x47,
-  0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0xa7,0x32,0xff,0xf6,0x44,
-  0x29,0x80,0x74,0x0a,0x8a,0xdc,0xc0,0xeb,0x04,0x2e,0x8a,0xbf,
-  0xb1,0x01,0x26,0x88,0x3d,0x47,0x23,0x7c,0x16,0x3b,0x7c,0x14,
-  0x74,0x89,0xaa,0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0x80,0xe9,
-  0x2e,0xff,0x1e,0x2e,0x8e,0x1e,0xc1,0x03,0xff,0x06,0x1c,0x0e,
-  0x60,0xbe,0x00,0x14,0xeb,0x0f,0x90,0x1e,0x2e,0x8e,0x1e,0xc1,
-  0x03,0xff,0x06,0x1a,0x0e,0x60,0xbe,0x00,0x10,0xb9,0x08,0x00,
-  0x8b,0x54,0x20,0xb0,0x03,0xee,0x90,0x90,0x32,0xff,0xec,0x8a,
-  0xd8,0x02,0xd8,0x2e,0xff,0xa7,0xa9,0x00,0x81,0xc6,0x00,0x01,
-  0x8b,0x54,0x20,0x0b,0xd2,0xe0,0xe4,0xb8,0x00,0x80,0xba,0x22,
-  0xff,0xef,0x61,0x1f,0xcf,0x81,0xce,0x80,0x00,0x8b,0x54,0x20,
-  0xff,0x06,0x20,0x0e,0xb0,0x01,0xee,0x8a,0x44,0x71,0x24,0xe7,
-  0x88,0x44,0x71,0xee,0xc6,0x44,0x49,0x02,0x80,0x4c,0x50,0x20,
-  0xc7,0x04,0xc3,0x03,0x81,0xe6,0x7f,0xff,0x8b,0x54,0x20,0xeb,
-  0xae,0x81,0xce,0x80,0x00,0x8b,0x54,0x20,0xff,0x06,0x22,0x0e,
-  0xec,0x0a,0xc0,0x79,0x7a,0x80,0x4c,0x51,0x10,0xc7,0x44,0x06,
-  0xe1,0x08,0xc6,0x44,0x63,0x04,0xf6,0x44,0x51,0x04,0x74,0x08,
-  0x80,0x64,0x51,0xfb,0x80,0x64,0x53,0x3f,0xf6,0x44,0x28,0x01,
-  0x75,0x59,0xf6,0x44,0x28,0x02,0x75,0x4f,0x8b,0x7c,0x12,0x8c,
-  0xc3,0x8e,0x44,0x10,0xf6,0x44,0x28,0x08,0x74,0x1e,0xb0,0xff,
-  0xaa,0x23,0x7c,0x16,0x3b,0x7c,0x14,0x74,0x26,0x32,0xc0,0xf6,
-  0x44,0x29,0x80,0x74,0x02,0xb0,0x10,0xaa,0x23,0x7c,0x16,0x3b,
-  0x7c,0x14,0x74,0x13,0x32,0xc0,0xaa,0x23,0x7c,0x16,0x3b,0x7c,
-  0x14,0x74,0x08,0x8e,0xc3,0x89,0x7c,0x12,0xeb,0x15,0x90,0x8e,
-  0xc3,0x4f,0x23,0x7c,0x16,0x89,0x7c,0x12,0xc6,0x44,0x59,0x01,
-  0xeb,0x05,0x90,0x80,0x4c,0x4f,0x01,0xb0,0x10,0xee,0x81,0xe6,
-  0x7f,0xff,0x8b,0x54,0x20,0xe9,0x17,0xff,0xff,0x06,0x1e,0x0e,
-  0xe9,0x10,0xff,0x1e,0x2e,0x8e,0x1e,0xc1,0x03,0x50,0x52,0x55,
-  0x8b,0xec,0x8b,0x46,0x08,0xa3,0x12,0x0e,0x32,0xe4,0xa0,0x22,
-  0x0c,0xa3,0x10,0x0e,0xff,0x06,0x00,0x0e,0x83,0x06,0x0e,0x0e,
-  0x0a,0x83,0x3e,0x04,0x0e,0x00,0x74,0x31,0x8b,0x16,0x00,0x0e,
-  0x2b,0x16,0x02,0x0e,0x3b,0x16,0x04,0x0e,0x72,0x23,0x8b,0x16,
-  0x00,0x0e,0x89,0x16,0x02,0x0e,0x8b,0x16,0x18,0x0d,0x3b,0x16,
-  0x1a,0x0d,0x74,0x11,0x80,0x3e,0x10,0x0c,0x01,0x74,0x16,0xb0,
-  0x00,0x90,0xe6,0x00,0x0c,0x08,0x90,0xe6,0x00,0xb8,0x00,0x80,
-  0xba,0x22,0xff,0xef,0x5d,0x5a,0x58,0x1f,0xcf,0xb0,0x80,0xe6,
-  0x00,0xa0,0x11,0x0c,0x0c,0x10,0xa2,0x11,0x0c,0xeb,0xe6,0x1e,
-  0x2e,0x8e,0x1e,0xc1,0x03,0xff,0x06,0x28,0x0e,0x55,0x8b,0xec,
-  0x8b,0x6e,0x02,0x89,0x2e,0x16,0x0e,0x5d,0x1f,0xcf,0x1e,0x2e,
-  0x8e,0x1e,0xc1,0x03,0xff,0x06,0x24,0x0e,0x55,0x8b,0xec,0x8b,
-  0x6e,0x02,0x89,0x2e,0x14,0x0e,0x5d,0x80,0x3e,0x10,0x0c,0x01,
-  0x75,0x12,0x50,0xa0,0x11,0x0c,0x0c,0x01,0xa2,0x11,0x0c,0xe4,
-  0x00,0x90,0x90,0x24,0x7f,0xe6,0x00,0x58,0x1f,0xcf,0x1e,0x06,
-  0x60,0xb8,0x00,0x80,0xba,0x22,0xff,0xef,0x2e,0x8e,0x1e,0xc1,
-  0x03,0x2e,0x8e,0x06,0xc1,0x03,0x2e,0xff,0x06,0x30,0x0d,0xfc,
-  0xff,0x26,0x2e,0x0e,0x00,0x00,0xfb,0x40,0x43,0x41,0x42,0x46,
-  0x47,0x45,0xeb,0xf6,0xc3,0x00,0x00,0x8f,0x06,0x2e,0x0e,0x2e,
-  0xff,0x06,0x3d,0x0d,0xb8,0x00,0x00,0xba,0x58,0xff,0xef,0xb8,
-  0x00,0xe0,0xba,0x5e,0xff,0xef,0x61,0x07,0x1f,0xcf,0xc2,0xfe,
-  0xff,0x8b,0x7c,0x0a,0x2b,0x7c,0x0c,0x23,0x7c,0x0e,0x3b,0x7c,
-  0x18,0x77,0x2e,0xc6,0x44,0x4d,0x00,0x80,0x4c,0x4f,0x02,0xeb,
-  0x5a,0x90,0x8b,0x7c,0x0a,0x3b,0x7c,0x0c,0x75,0x1b,0x8b,0x3e,
-  0x10,0x0d,0x3b,0x3e,0x12,0x0d,0x75,0x53,0xf6,0x44,0x4b,0xff,
-  0x75,0x4d,0xc6,0x44,0x4c,0x00,0x80,0x4c,0x4f,0x04,0xeb,0x43,
-  0x90,0xf6,0x44,0x50,0x10,0x75,0x3c,0xeb,0x09,0x90,0x8b,0x7c,
-  0x0a,0x2b,0x7c,0x0c,0x74,0x31,0x80,0x4c,0x50,0x10,0x80,0x4c,
-  0x4b,0x10,0xc7,0x04,0xc3,0x03,0xeb,0x23,0x90,0xfa,0x8b,0x36,
-  0x08,0x0e,0x8b,0x54,0x20,0xec,0x8a,0xf8,0x8a,0x5c,0x54,0x32,
-  0xfb,0xf6,0x44,0x4d,0xff,0x75,0x8e,0xf6,0x44,0x4c,0xff,0x75,
-  0xa1,0xf6,0x44,0x50,0x10,0x74,0xc7,0xec,0x32,0xc3,0x22,0xf8,
-  0x83,0x2e,0x10,0x0e,0x01,0x78,0x05,0xd0,0x6c,0x49,0x72,0x45,
-  0x8b,0x7c,0x12,0x2b,0x7c,0x14,0x74,0x22,0x80,0x7c,0x4e,0x00,
-  0x74,0x1c,0x23,0x7c,0x16,0x03,0xff,0x3b,0x7c,0x16,0x73,0x43,
-  0x8b,0x0e,0x0e,0x0e,0x2b,0x4c,0x6e,0x3b,0x4c,0x22,0x73,0x37,
-  0x80,0x7c,0x49,0x00,0x74,0x31,0xf6,0x44,0x51,0x02,0x75,0x3c,
-  0xec,0x32,0xc3,0x22,0xf8,0x80,0xe7,0x38,0xfb,0x89,0x1e,0x30,
-  0x0e,0xbe,0x00,0x10,0xff,0x14,0xeb,0x61,0x90,0xb0,0x01,0xee,
-  0x8a,0x44,0x71,0x0c,0x10,0x88,0x44,0x71,0xee,0x80,0x64,0x50,
-  0xdf,0xc7,0x04,0xc3,0x03,0xeb,0xa5,0xc6,0x44,0x4e,0x00,0x8b,
-  0x0e,0x0e,0x0e,0x89,0x4c,0x6e,0x80,0x4c,0x4f,0x08,0xeb,0xbe,
-  0x8b,0x7c,0x12,0x2b,0x7c,0x14,0x23,0x7c,0x16,0x3b,0x7c,0x1a,
-  0x73,0xb6,0x80,0x64,0x51,0xfd,0xf6,0x44,0x29,0x10,0x74,0x10,
-  0x80,0x64,0x54,0xfb,0x80,0x4c,0x58,0x04,0x80,0x74,0x50,0x08,
-  0xc7,0x04,0xc3,0x03,0xb0,0x05,0xee,0xb0,0x82,0x22,0x44,0x5f,
-  0x0a,0x44,0x75,0x88,0x44,0x75,0xee,0xeb,0x8b,0xfa,0x8b,0x36,
-  0x08,0x0e,0x8b,0x1e,0x30,0x0e,0x8a,0xcb,0xe5,0x80,0x23,0x44,
-  0x2e,0x74,0x02,0xf6,0xd1,0x80,0xe1,0x40,0x0a,0xf9,0x8a,0xdf,
-  0x22,0x5c,0x55,0x30,0x5c,0x54,0x32,0xfb,0x88,0x7c,0x55,0x0a,
-  0x5c,0x58,0x88,0x5c,0x58,0x22,0x5c,0x56,0x75,0x24,0x80,0x7c,
-  0x4f,0x00,0x75,0x22,0xfb,0x03,0x74,0x1e,0x89,0x36,0x08,0x0e,
-  0xff,0x06,0x26,0x0e,0x8b,0x3e,0x12,0x0d,0x3b,0x3e,0x10,0x0d,
-  0x75,0x46,0xbe,0x00,0x10,0xff,0x14,0xe9,0xd3,0xfe,0x80,0x4c,
-  0x4f,0x20,0x8b,0x3e,0x18,0x0d,0x8a,0x44,0x48,0x8a,0x64,0x4f,
-  0x89,0x85,0x00,0x08,0x8a,0x44,0x54,0x8a,0x64,0x57,0x89,0x85,
-  0x02,0x08,0x83,0xc7,0x04,0x81,0xe7,0xfc,0x03,0x3b,0x3e,0x1a,
-  0x0d,0x74,0x13,0x88,0x44,0x57,0xc6,0x44,0x4f,0x00,0x8a,0x44,
-  0x56,0xf6,0xd0,0x20,0x44,0x58,0x89,0x3e,0x18,0x0d,0xeb,0xa4,
-  0xff,0x06,0x2c,0x0e,0xbe,0x00,0x10,0xff,0x14,0xfa,0x8b,0x3e,
-  0x12,0x0d,0x81,0xc7,0x00,0x04,0x8a,0x5d,0x01,0x83,0xe3,0x0f,
-  0x03,0xdb,0x2e,0x8b,0xb7,0x89,0x00,0x8b,0x54,0x20,0x0b,0xd2,
-  0x74,0x0d,0x8a,0x1d,0x83,0xe3,0x1f,0x03,0xdb,0xfa,0x2e,0xff,
-  0xa7,0x9c,0x0f,0xff,0x06,0x2a,0x0e,0x8b,0x3e,0x12,0x0d,0x8b,
-  0x36,0x18,0x0d,0x8b,0x9d,0x00,0x04,0x89,0x9c,0x00,0x08,0x8b,
-  0x9d,0x02,0x04,0x89,0x9c,0x02,0x08,0x83,0xc6,0x04,0x81,0xe6,
-  0xfc,0x03,0x3b,0x36,0x1a,0x0d,0x74,0x04,0x89,0x36,0x18,0x0d,
-  0xfb,0x8b,0x3e,0x12,0x0d,0x83,0xc7,0x04,0x81,0xe7,0xfc,0x03,
-  0x89,0x3e,0x12,0x0d,0xbe,0x00,0x10,0xff,0x14,0xe9,0x1d,0xfe,
-  0xdc,0x0f,0xe4,0x0f,0xec,0x0f,0x0d,0x10,0x1c,0x10,0x57,0x0f,
-  0x2f,0x10,0x57,0x0f,0x3b,0x10,0x54,0x10,0x83,0x10,0xcf,0x10,
-  0xdb,0x10,0xe4,0x10,0xeb,0x10,0x35,0x11,0x7d,0x11,0x83,0x11,
-  0xa1,0x11,0xb9,0x11,0xf2,0x11,0x38,0x12,0x03,0x13,0x0c,0x13,
-  0x57,0x0f,0x57,0x0f,0x57,0x0f,0x57,0x0f,0x57,0x0f,0x57,0x0f,
-  0x57,0x0f,0x57,0x0f,0x8b,0x45,0x02,0x89,0x44,0x1a,0xeb,0xa0,
-  0x8b,0x45,0x02,0x89,0x44,0x1c,0xeb,0x98,0x8b,0x45,0x02,0x8b,
-  0x5c,0x0a,0x2b,0x5c,0x0c,0x23,0x5c,0x0e,0x8b,0x4c,0x0a,0x2b,
-  0xc8,0x23,0x4c,0x0e,0x3b,0xd9,0x76,0x06,0x23,0x44,0x0e,0x89,
-  0x44,0x0c,0xe9,0x77,0xff,0x80,0x4c,0x53,0x80,0x80,0x4c,0x54,
-  0x01,0x80,0x4c,0x58,0x01,0xe9,0x68,0xff,0x80,0x64,0x53,0x3f,
-  0x80,0x64,0x54,0xfe,0x80,0x4c,0x58,0x01,0x80,0x64,0x51,0xfb,
-  0xe9,0x55,0xff,0x8b,0x45,0x02,0x88,0x44,0x5a,0x88,0x64,0x5b,
-  0xe9,0x49,0xff,0x8b,0x45,0x02,0x0b,0xc0,0x74,0x03,0x89,0x44,
-  0x24,0x80,0x4c,0x50,0x04,0x80,0x4c,0x4b,0x04,0xc7,0x04,0xc3,
-  0x03,0xe9,0x30,0xff,0x8b,0x5d,0x02,0xf6,0xd7,0x22,0x7c,0x54,
-  0x0a,0xdf,0x8a,0x44,0x54,0x32,0xc3,0x24,0x82,0x30,0x44,0x54,
-  0xb0,0x05,0xee,0x8a,0x44,0x75,0x32,0xd8,0x8a,0x7c,0x5f,0xf6,
-  0xd7,0x22,0xdf,0x80,0xe3,0x82,0x32,0xc3,0x88,0x44,0x75,0xee,
-  0xe9,0x01,0xff,0x8b,0x5d,0x02,0xf6,0xc7,0x04,0x75,0x08,0x80,
-  0x64,0x53,0x3f,0x80,0x64,0x51,0xfb,0x8a,0x44,0x29,0x32,0xc7,
-  0xa8,0x10,0x74,0x0e,0xf6,0x44,0x51,0x02,0x74,0x08,0x80,0x74,
-  0x50,0x08,0xc7,0x04,0xc3,0x03,0x88,0x5c,0x28,0x88,0x7c,0x29,
-  0xb4,0x60,0xf6,0xc3,0x10,0x74,0x03,0x80,0xcc,0x10,0x8a,0x44,
-  0x62,0xf6,0xc3,0x20,0x74,0x02,0x24,0x7f,0x89,0x44,0x34,0xc7,
-  0x44,0x06,0xe1,0x08,0xe9,0xb5,0xfe,0x8b,0x45,0x02,0x88,0x44,
-  0x5c,0x88,0x64,0x5d,0xe9,0xa9,0xfe,0x8b,0x45,0x02,0x89,0x44,
-  0x18,0xe9,0xa0,0xfe,0xff,0x1e,0x24,0x0d,0xe9,0x99,0xfe,0xf6,
-  0x44,0x51,0x02,0x75,0x41,0x8b,0x44,0x12,0x2b,0x44,0x14,0x23,
-  0x44,0x16,0x3b,0x44,0x1a,0x72,0x33,0x80,0x4c,0x51,0x02,0xf6,
-  0x44,0x29,0x10,0x74,0x10,0x80,0x4c,0x54,0x04,0x80,0x4c,0x58,
-  0x04,0x80,0x74,0x50,0x08,0xc7,0x04,0xc3,0x03,0xf6,0x44,0x5f,
-  0x82,0x74,0x13,0xb0,0x05,0xee,0x8a,0x44,0x75,0xb4,0x82,0x22,
-  0x64,0x5f,0xf6,0xd4,0x22,0xc4,0x88,0x44,0x75,0xee,0xe9,0x4f,
-  0xfe,0xf6,0x44,0x51,0x02,0x74,0x3f,0x8b,0x44,0x12,0x2b,0x44,
-  0x14,0x23,0x44,0x16,0x3b,0x44,0x1c,0x73,0xe9,0x80,0x64,0x51,
-  0xfd,0xf6,0x44,0x29,0x10,0x74,0x10,0x80,0x64,0x54,0xfb,0x80,
-  0x4c,0x58,0x04,0x80,0x74,0x50,0x08,0xc7,0x04,0xc3,0x03,0xf6,
-  0x44,0x5f,0x02,0x74,0x11,0xb0,0x05,0xee,0x8a,0x44,0x75,0xb4,
-  0x82,0x22,0x64,0x5f,0x0a,0xc4,0x88,0x44,0x75,0xee,0xe9,0x07,
-  0xfe,0xe8,0x8a,0x02,0xe9,0x01,0xfe,0x8b,0x45,0x02,0xbb,0x10,
-  0x27,0xf7,0xe3,0xbb,0x0f,0x00,0xf7,0xf3,0xa3,0x06,0x0e,0xba,
-  0x52,0xff,0xef,0xba,0x50,0xff,0xb8,0x00,0x00,0xef,0xe9,0xe3,
-  0xfd,0x8b,0x45,0x02,0x3a,0x06,0x22,0x0c,0x72,0x0c,0x3b,0x06,
-  0x1a,0x0c,0x77,0x06,0xe8,0xab,0x01,0xe9,0xce,0xfd,0xe9,0x9e,
-  0xfd,0x8b,0x45,0x02,0x88,0x44,0x2a,0x88,0x64,0x2b,0x0b,0xc0,
-  0x75,0x07,0x80,0x64,0x50,0xfe,0xeb,0x10,0x90,0xf6,0x44,0x50,
-  0x01,0x75,0x09,0x80,0x4c,0x50,0x01,0xc7,0x44,0x30,0x00,0x00,
-  0xa8,0x80,0x75,0x07,0xc6,0x44,0x60,0x00,0xeb,0x05,0x90,0xc6,
-  0x44,0x60,0x7f,0xc7,0x04,0xc3,0x03,0xe9,0x92,0xfd,0x8b,0x5d,
-  0x02,0xf6,0xd7,0x22,0x7c,0x5f,0x0a,0xdf,0x8a,0xfb,0x88,0x5c,
-  0x5f,0x8a,0x44,0x52,0x8a,0x64,0x53,0x8b,0xcb,0x33,0xc8,0x81,
-  0xe1,0x38,0x38,0x33,0xc1,0x88,0x44,0x52,0x88,0x64,0x53,0xb0,
-  0x05,0xee,0xf6,0xd3,0x22,0x5c,0x54,0xf6,0x44,0x51,0x02,0x75,
-  0x02,0x0a,0xdf,0x8a,0x44,0x75,0x32,0xd8,0x80,0xe3,0x82,0x32,
-  0xc3,0x88,0x44,0x75,0xee,0xe9,0x4c,0xfd,0x8b,0x5d,0x02,0x88,
-  0x5c,0x2c,0x88,0x7c,0x2d,0x8b,0xcb,0x83,0xe3,0x0f,0x03,0xdb,
-  0x80,0x3e,0x10,0x0c,0x01,0x75,0x1f,0xa1,0x0e,0x0c,0x86,0xe0,
-  0x3d,0x32,0x31,0x73,0x15,0xf6,0xc5,0x04,0x75,0x08,0x2e,0x8b,
-  0x9f,0x69,0x01,0xeb,0x1b,0x90,0x2e,0x8b,0x9f,0x89,0x01,0xeb,
-  0x13,0x90,0xf6,0xc5,0x04,0x75,0x08,0x2e,0x8b,0x9f,0x29,0x01,
-  0xeb,0x06,0x90,0x2e,0x8b,0x9f,0x49,0x01,0xb0,0x0c,0xee,0x8a,
-  0xc3,0x88,0x44,0x7c,0xee,0xb0,0x0d,0x90,0x90,0xee,0x8a,0xc7,
-  0x88,0x44,0x7d,0xee,0xb0,0x04,0xee,0xb0,0x44,0xf6,0xc1,0x40,
-  0x74,0x0c,0xf6,0xc1,0x80,0x74,0x05,0x04,0x04,0xeb,0x03,0x90,
-  0x0c,0x08,0xf6,0xc5,0x01,0x74,0x09,0x0c,0x01,0xf6,0xc5,0x02,
-  0x75,0x02,0x0c,0x02,0x88,0x44,0x74,0xee,0xb0,0x03,0x90,0x90,
-  0xee,0x8a,0xd9,0x80,0xe3,0x30,0xc0,0xeb,0x04,0x32,0xff,0x2e,
-  0x8a,0xa7,0xa9,0x01,0x8a,0x44,0x73,0x24,0x3f,0x0a,0xc4,0x88,
-  0x44,0x73,0xee,0x90,0x90,0xb0,0x05,0xee,0xd0,0xec,0x8a,0x44,
-  0x75,0x24,0x9f,0x0a,0xc4,0x88,0x44,0x75,0xee,0x2e,0x8a,0x87,
-  0xad,0x01,0x88,0x44,0x62,0xf6,0x44,0x28,0x20,0x74,0x02,0x24,
-  0x7f,0x88,0x44,0x34,0xe9,0x81,0xfc,0x8a,0x45,0x02,0x88,0x44,
-  0x5e,0xe9,0x78,0xfc,0x8b,0x45,0x02,0xba,0x5a,0xff,0xef,0x9c,
-  0xff,0x36,0x26,0x0d,0xff,0x36,0x24,0x0d,0x1e,0x06,0x60,0x8b,
-  0x36,0x0a,0x0e,0xc7,0x04,0x3f,0x0d,0xe9,0x5a,0xfc,0xb8,0x00,
-  0x00,0x8e,0xc0,0x8b,0xf0,0x8b,0xf8,0x2e,0x8b,0x9c,0x49,0x00,
-  0x83,0xc6,0x02,0x26,0x89,0x1d,0x26,0x8c,0x4d,0x02,0x83,0xc7,
-  0x04,0x81,0xff,0x80,0x00,0x72,0xe8,0x26,0xc7,0x05,0xcb,0x0c,
-  0x26,0x8c,0x4d,0x02,0x83,0xc7,0x04,0x81,0xff,0x00,0x04,0x72,
-  0xee,0xc3,0xc1,0xe0,0x06,0x8b,0xd8,0x8c,0xda,0x81,0xc2,0x00,
-  0x04,0x8b,0xfa,0x8a,0x0e,0x22,0x0c,0xb5,0x00,0xbe,0x00,0x10,
-  0x33,0xc0,0x89,0x44,0x0a,0x89,0x44,0x0c,0x89,0x44,0x12,0x89,
-  0x44,0x14,0x81,0xc6,0x80,0x00,0xe2,0xee,0x89,0x36,0x0a,0x0e,
-  0xb8,0x01,0x00,0x8b,0xd0,0xb3,0x00,0x8a,0x0e,0x22,0x0c,0xb5,
-  0x00,0xbe,0x00,0x10,0x2b,0xda,0x72,0x29,0x89,0x44,0x16,0x81,
-  0xc6,0x80,0x00,0xe2,0xf3,0x8a,0x0e,0x22,0x0c,0xb5,0x00,0xbe,
-  0x00,0x10,0x2b,0xda,0x72,0x13,0x89,0x44,0x0e,0x81,0xc6,0x80,
-  0x00,0xe2,0xf3,0x8b,0xd0,0x03,0xc0,0x81,0xfa,0x00,0x02,0x72,
-  0xca,0x8a,0x0e,0x22,0x0c,0xb5,0x00,0xbe,0x00,0x10,0x89,0x7c,
-  0x10,0x8b,0x44,0x16,0x03,0xf8,0x8b,0xd7,0xc1,0xe0,0x04,0x48,
-  0x89,0x44,0x16,0x81,0xc6,0x80,0x00,0xe2,0xe9,0x8a,0x0e,0x22,
-  0x0c,0xb5,0x00,0xbe,0x00,0x10,0x89,0x7c,0x08,0x8b,0x44,0x0e,
-  0x03,0xf8,0x8b,0xd7,0xc1,0xe0,0x04,0x48,0x89,0x44,0x0e,0x81,
-  0xc6,0x80,0x00,0xe2,0xe9,0xc3,0xc7,0x04,0x20,0x04,0xc7,0x44,
-  0x06,0xe1,0x08,0x8b,0xc6,0x2d,0x00,0x10,0xb1,0x80,0xf6,0xf1,
-  0x88,0x44,0x48,0xc7,0x44,0x0a,0x00,0x00,0xc7,0x44,0x0c,0x00,
-  0x00,0xc7,0x44,0x12,0x00,0x00,0xc7,0x44,0x14,0x00,0x00,0xc7,
-  0x44,0x18,0x00,0x00,0xc7,0x44,0x1a,0x00,0x00,0xc7,0x44,0x1c,
-  0xff,0xff,0x8a,0x5c,0x48,0x83,0xe3,0x0f,0x03,0xdb,0x8b,0x97,
-  0x90,0x0c,0x89,0x54,0x20,0xb8,0x01,0x00,0x8a,0x4c,0x48,0xd3,
-  0xe0,0x89,0x44,0x2e,0xc7,0x44,0x24,0x19,0x00,0xc7,0x44,0x26,
-  0x00,0x00,0xc6,0x44,0x4a,0x00,0xc7,0x44,0x30,0x00,0x00,0xc7,
-  0x44,0x32,0x00,0x00,0xc6,0x44,0x4c,0x00,0xc6,0x44,0x4d,0x00,
-  0xc6,0x44,0x4e,0x00,0xc6,0x44,0x4f,0x00,0xc6,0x44,0x50,0x00,
-  0xc6,0x44,0x4b,0x00,0xc6,0x44,0x51,0x00,0xc6,0x44,0x28,0x00,
-  0xc6,0x44,0x29,0x00,0xc6,0x44,0x2a,0x00,0xc6,0x44,0x2b,0x00,
-  0xc6,0x44,0x54,0x00,0xc6,0x44,0x57,0x00,0xc6,0x44,0x55,0x00,
-  0xc6,0x44,0x56,0x00,0xc6,0x44,0x58,0x00,0xc6,0x44,0x52,0x04,
-  0xc6,0x44,0x53,0x04,0xc6,0x44,0x5f,0x00,0xc6,0x44,0x2c,0x3d,
-  0xc6,0x44,0x2d,0x00,0xc7,0x44,0x34,0xff,0x60,0xc6,0x44,0x62,
-  0xff,0xc6,0x44,0x5d,0x13,0xc6,0x44,0x5c,0x11,0xc6,0x44,0x5e,
-  0x00,0xc6,0x44,0x60,0x23,0xc6,0x44,0x61,0x23,0x0b,0xd2,0x75,
-  0x03,0xe9,0xd9,0x00,0xb0,0x09,0xee,0x8a,0x4c,0x48,0xb0,0x80,
-  0xd2,0xe8,0xee,0xc6,0x44,0x70,0x00,0xb0,0x01,0xee,0xb0,0x11,
-  0x88,0x44,0x71,0xee,0xb0,0x02,0x90,0x90,0xee,0x8a,0x44,0x48,
-  0xc0,0xe0,0x03,0x24,0xf0,0x88,0x44,0x72,0xee,0xb0,0x03,0x90,
-  0x90,0xee,0xb0,0xc0,0x88,0x44,0x73,0xee,0xb0,0x04,0x90,0x90,
-  0xee,0xb0,0x44,0x88,0x44,0x74,0xee,0xb0,0x05,0x90,0xee,0xb0,
-  0x60,0x88,0x44,0x75,0xee,0xc6,0x44,0x76,0x00,0xc6,0x44,0x77,
-  0x00,0xc6,0x44,0x78,0x00,0xb0,0x09,0xee,0xb0,0x09,0x88,0x44,
-  0x79,0xee,0xc6,0x44,0x7a,0x00,0xb0,0x0b,0xee,0xb0,0x52,0x88,
-  0x44,0x7b,0xee,0x80,0x3e,0x10,0x0c,0x01,0x75,0x21,0xa1,0x0e,
-  0x0c,0x86,0xe0,0x3d,0x32,0x31,0x73,0x17,0xb0,0x0c,0xee,0xb0,
-  0x18,0x88,0x44,0x7c,0xee,0xb0,0x0d,0x90,0x90,0xee,0xb0,0x00,
-  0x88,0x44,0x7d,0xee,0xeb,0x15,0x90,0xb0,0x0c,0xee,0xb0,0x16,
-  0x88,0x44,0x7c,0xee,0xb0,0x0d,0x90,0x90,0xee,0xb0,0x00,0x88,
-  0x44,0x7d,0xee,0xb0,0x0e,0x90,0x90,0xee,0xb0,0x03,0x88,0x44,
-  0x7e,0xee,0xb0,0x0f,0x90,0x90,0xee,0xb0,0x80,0x88,0x44,0x7f,
-  0xee,0xb0,0x03,0x90,0x90,0xee,0x8a,0x44,0x73,0x0c,0x01,0x88,
-  0x44,0x73,0xee,0x90,0x90,0xb0,0x05,0xee,0x8a,0x44,0x75,0x0c,
-  0x08,0x88,0x44,0x75,0xee,0xc3,0xfa,0x8c,0xd8,0x25,0x00,0xf0,
-  0x8e,0xd0,0xbc,0xfe,0x1f,0x8c,0xd8,0x25,0x00,0xf0,0x8e,0xd8,
-  0x80,0x3e,0x40,0x0d,0x01,0x75,0x51,0xa1,0x0e,0x0c,0x86,0xe0,
-  0x3d,0x30,0x32,0x73,0x47,0x8b,0x1e,0x20,0x0c,0x8a,0x16,0x23,
-  0x0c,0xc6,0x06,0x23,0x0c,0x00,0x83,0xfb,0x00,0x74,0x07,0xfe,
-  0xca,0xc6,0x06,0x23,0x0c,0x01,0x88,0x16,0x22,0x0c,0xbe,0x10,
-  0x0c,0xbf,0x90,0x0c,0xb9,0x08,0x00,0x1e,0x07,0xfc,0xf3,0xa5,
-  0xbf,0xa0,0x0c,0xb8,0x00,0x00,0xb9,0x08,0x00,0xf3,0xab,0xc7,
-  0x06,0x1a,0x0c,0x70,0x00,0xa0,0x40,0x0d,0xa2,0x10,0x0c,0xc6,
-  0x06,0x11,0x0c,0x00,0x2e,0x8c,0x1e,0xc1,0x03,0xc7,0x06,0x18,
-  0x0e,0x02,0x00,0xe8,0xec,0xfc,0xc7,0x06,0x24,0x0d,0x5a,0x0d,
-  0x8c,0x0e,0x26,0x0d,0xc7,0x06,0x18,0x0e,0x06,0x00,0xa1,0x1a,
-  0x0c,0xe8,0x0a,0xfd,0xc7,0x06,0x18,0x0e,0x0a,0x00,0xbe,0x00,
-  0x10,0xc7,0x44,0x1e,0x80,0x00,0xe8,0xa5,0xfd,0x81,0xc6,0x80,
-  0x00,0x81,0xfe,0x00,0x18,0x72,0xee,0xa0,0x22,0x0c,0xb4,0x80,
-  0xf6,0xe4,0xbe,0x00,0x10,0x03,0xf0,0x89,0x36,0x0a,0x0e,0x29,
-  0x44,0x9e,0xc7,0x06,0x00,0x0e,0x00,0x00,0xc7,0x06,0x02,0x0e,
-  0x00,0x00,0xc7,0x06,0x04,0x0e,0x00,0x00,0xc7,0x06,0x06,0x0e,
-  0x9a,0x02,0xba,0x52,0xff,0xa1,0x06,0x0e,0xef,0xba,0x50,0xff,
-  0xb8,0x00,0x00,0xef,0xba,0x56,0xff,0xb8,0x05,0xe0,0xef,0xba,
-  0x5e,0xff,0xb8,0x00,0x40,0xef,0xba,0x66,0xff,0xb8,0x00,0x40,
-  0xef,0xc7,0x06,0x10,0x0d,0x00,0x00,0xc7,0x06,0x12,0x0d,0x00,
-  0x00,0xc7,0x06,0x14,0x0d,0x00,0x04,0xc7,0x06,0x16,0x0d,0xfc,
-  0x03,0xc7,0x06,0x18,0x0d,0x00,0x00,0xc7,0x06,0x1a,0x0d,0x00,
-  0x00,0xc7,0x06,0x1c,0x0d,0x00,0x08,0xc7,0x06,0x1e,0x0d,0xfc,
-  0x03,0xb0,0x00,0x90,0xe6,0x00,0xc7,0x06,0x18,0x0e,0x32,0x00,
-  0xba,0x38,0xff,0xb8,0x11,0x00,0xef,0xba,0x3a,0xff,0xb8,0x08,
-  0x00,0xef,0xba,0x3c,0xff,0xb8,0x08,0x00,0xef,0xba,0x3e,0xff,
-  0xb8,0x08,0x00,0x80,0x3e,0x22,0x0c,0x08,0x76,0x03,0xb8,0x12,
-  0x00,0xef,0xba,0x32,0xff,0xb8,0x05,0x00,0xef,0xba,0x28,0xff,
-  0xb8,0x6c,0x00,0xef,0xba,0x22,0xff,0xb8,0x00,0x80,0xef,0xc7,
-  0x06,0x18,0x0e,0x33,0x00,0xc7,0x06,0x20,0x0d,0x4f,0x00,0xc7,
-  0x06,0x21,0x0d,0x53,0x00,0x8b,0x36,0x0a,0x0e,0xc7,0x04,0x3c,
-  0x0d,0xc7,0x06,0x08,0x0e,0x00,0x10,0xe9,0x63,0xf6,0x40,0x28,
-  0x23,0x29,0x20,0x24,0x49,0x64,0x3a,0x20,0x78,0x61,0x63,0x6f,
-  0x6f,0x6b,0x2e,0x61,0x73,0x6d,0x2c,0x76,0x20,0x37,0x2e,0x32,
-  0x35,0x20,0x31,0x39,0x39,0x35,0x2f,0x30,0x31,0x2f,0x31,0x32,
-  0x20,0x32,0x30,0x3a,0x35,0x39,0x3a,0x32,0x31,0x20,0x6d,0x69,
-  0x6c,0x74,0x20,0x45,0x78,0x70,0x20,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,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-};
-
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -18,7 +18,7 @@ config DRM
 
 config DRM_TDFX
 	tristate "3dfx Banshee/Voodoo3+"
-	depends on DRM
+	depends on DRM && PCI
 	help
 	  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
 	  graphics card.  If M is selected, the module will be called tdfx.
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -422,7 +422,7 @@ typedef struct drm_file {
 	unsigned long	  ioctl_count;
 	struct drm_file	  *next;
 	struct drm_file	  *prev;
-	struct drm_device *dev;
+	struct drm_head   *head;
 	int 		  remove_auth_on_close;
 	unsigned long     lock_count;
 	void              *driver_priv;
@@ -497,6 +497,7 @@ typedef struct drm_agp_head {
 	DRM_AGP_KERN       agp_info;	/**< AGP device information */
 	drm_agp_mem_t      *memory;	/**< memory entries */
 	unsigned long      mode;	/**< AGP mode */
+	struct agp_bridge_data  *bridge;
 	int                enabled;	/**< whether the AGP bus as been enabled */
 	int                acquired;	/**< whether the AGP device has been acquired */
 	unsigned long      base;
@@ -592,19 +593,31 @@ struct drm_driver {
 	struct file_operations fops;
 	struct pci_driver pci_driver;
 };
+
 /**
- * DRM device structure.
+ * DRM head structure. This structure represent a video head on a card
+ * that may contain multiple heads. Embed one per head of these in the
+ * private drm_device structure.
+ */
+typedef struct drm_head {
+	int minor;			/**< Minor device number */
+	struct drm_device *dev;
+	struct proc_dir_entry *dev_root;  /**< proc directory entry */
+	dev_t device;			/**< Device number for mknod */
+	struct class_device *dev_class;
+} drm_head_t;
+
+/**
+ * DRM device structure. This structure represent a complete card that
+ * may contain multiple heads.
  */
 typedef struct drm_device {
 	char		  *unique;	/**< Unique identifier: e.g., busid */
 	int		  unique_len;	/**< Length of unique field */
-	dev_t		  device;	/**< Device number for mknod */
 	char		  *devname;	/**< For /proc/interrupts */
-	int		  minor;        /**< Minor device number */
 	int		  if_version;	/**< Highest interface version set */
 
 	int		  blocked;	/**< Blocked due to VC switch? */
-	struct proc_dir_entry *root;	/**< Root for this device's entries */
 
 	/** \name Locks */
 	/*@{*/
@@ -720,17 +733,9 @@ typedef struct drm_device {
 
 	struct            drm_driver *driver;
 	drm_local_map_t   *agp_buffer_map;
+	drm_head_t primary;		/**< primary screen head */
 } drm_device_t;
 
-typedef struct drm_minor {
-	enum {
-		DRM_MINOR_FREE = 0,
-		DRM_MINOR_PRIMARY,
-	} type;
-	drm_device_t *dev;
-	struct proc_dir_entry  *dev_root; /**< proc directory entry */
-} drm_minor_t;
-
 static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature)
 {
 	return ((dev->driver->driver_features & feature) ? 1 : 0);
@@ -807,7 +812,7 @@ extern void	     *drm_ioremap_nocache(un
 					   drm_device_t *dev);
 extern void	     drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev);
 
-extern DRM_AGP_MEM   *drm_alloc_agp(int pages, u32 type);
+extern DRM_AGP_MEM   *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type);
 extern int           drm_free_agp(DRM_AGP_MEM *handle, int pages);
 extern int           drm_bind_agp(DRM_AGP_MEM *handle, unsigned int start);
 extern int           drm_unbind_agp(DRM_AGP_MEM *handle);
@@ -930,10 +935,10 @@ extern int           drm_vblank_wait(drm
 extern void          drm_vbl_send_signals( drm_device_t *dev );
 
 				/* AGP/GART support (drm_agpsupport.h) */
-extern drm_agp_head_t *drm_agp_init(void);
+extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
 extern int            drm_agp_acquire(struct inode *inode, struct file *filp,
 				       unsigned int cmd, unsigned long arg);
-extern void           drm_agp_do_release(void);
+extern void           drm_agp_do_release(drm_device_t *dev);
 extern int            drm_agp_release(struct inode *inode, struct file *filp,
 				       unsigned int cmd, unsigned long arg);
 extern int            drm_agp_enable(struct inode *inode, struct file *filp,
@@ -948,18 +953,20 @@ extern int            drm_agp_unbind(str
 				      unsigned int cmd, unsigned long arg);
 extern int            drm_agp_bind(struct inode *inode, struct file *filp,
 				    unsigned int cmd, unsigned long arg);
-extern DRM_AGP_MEM    *drm_agp_allocate_memory(size_t pages, u32 type);
+extern DRM_AGP_MEM    *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
 extern int            drm_agp_free_memory(DRM_AGP_MEM *handle);
 extern int            drm_agp_bind_memory(DRM_AGP_MEM *handle, off_t start);
 extern int            drm_agp_unbind_memory(DRM_AGP_MEM *handle);
 
 				/* Stub support (drm_stub.h) */
-extern int            drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver);
-
-extern int 	      drm_put_minor(drm_device_t *dev);
+extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+		     struct drm_driver *driver);
+extern int drm_put_dev(drm_device_t * dev);
+extern int drm_get_head(drm_device_t * dev, drm_head_t *head);
+extern int drm_put_head(drm_head_t * head);
 extern unsigned int   drm_debug;
 extern unsigned int   drm_cards_limit;
-extern drm_minor_t    *drm_minors;
+extern drm_head_t **drm_heads;
 extern struct drm_sysfs_class *drm_class;
 extern struct proc_dir_entry *drm_proc_root;
 
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -52,7 +52,7 @@ int drm_agp_info(struct inode *inode, st
 		  unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	DRM_AGP_KERN     *kern;
 	drm_agp_info_t   info;
 
@@ -91,15 +91,14 @@ int drm_agp_acquire(struct inode *inode,
 		     unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
-	int              retcode;
+	drm_device_t	 *dev	 = priv->head->dev;
 
 	if (!dev->agp)
 		return -ENODEV;
 	if (dev->agp->acquired)
 		return -EBUSY;
-	if ((retcode = agp_backend_acquire()))
-		return retcode;
+	if (!(dev->agp->bridge = agp_backend_acquire(dev->pdev)))
+		return -ENODEV;
 	dev->agp->acquired = 1;
 	return 0;
 }
@@ -119,11 +118,11 @@ int drm_agp_release(struct inode *inode,
 		     unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 
 	if (!dev->agp || !dev->agp->acquired)
 		return -EINVAL;
-	agp_backend_release();
+	agp_backend_release(dev->agp->bridge);
 	dev->agp->acquired = 0;
 	return 0;
 
@@ -134,9 +133,9 @@ int drm_agp_release(struct inode *inode,
  *
  * Calls agp_backend_release().
  */
-void drm_agp_do_release(void)
+void drm_agp_do_release(drm_device_t *dev)
 {
-  agp_backend_release();
+  agp_backend_release(dev->agp->bridge);
 }
 
 /**
@@ -155,7 +154,7 @@ int drm_agp_enable(struct inode *inode, 
 		    unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_agp_mode_t   mode;
 
 	if (!dev->agp || !dev->agp->acquired)
@@ -165,7 +164,7 @@ int drm_agp_enable(struct inode *inode, 
 		return -EFAULT;
 
 	dev->agp->mode    = mode.mode;
-	agp_enable(mode.mode);
+	agp_enable(dev->agp->bridge, mode.mode);
 	dev->agp->base    = dev->agp->agp_info.aper_base;
 	dev->agp->enabled = 1;
 	return 0;
@@ -187,7 +186,7 @@ int drm_agp_alloc(struct inode *inode, s
 		   unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_agp_buffer_t request;
 	drm_agp_mem_t    *entry;
 	DRM_AGP_MEM      *memory;
@@ -207,7 +206,7 @@ int drm_agp_alloc(struct inode *inode, s
 	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
 	type = (u32) request.type;
 
-	if (!(memory = drm_alloc_agp(pages, type))) {
+	if (!(memory = drm_alloc_agp(dev->agp->bridge, pages, type))) {
 		drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
 		return -ENOMEM;
 	}
@@ -272,7 +271,7 @@ int drm_agp_unbind(struct inode *inode, 
 		    unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	  *priv	 = filp->private_data;
-	drm_device_t	  *dev	 = priv->dev;
+	drm_device_t	  *dev	 = priv->head->dev;
 	drm_agp_binding_t request;
 	drm_agp_mem_t     *entry;
 	int ret;
@@ -308,7 +307,7 @@ int drm_agp_bind(struct inode *inode, st
 		  unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	  *priv	 = filp->private_data;
-	drm_device_t	  *dev	 = priv->dev;
+	drm_device_t	  *dev	 = priv->head->dev;
 	drm_agp_binding_t request;
 	drm_agp_mem_t     *entry;
 	int               retcode;
@@ -349,7 +348,7 @@ int drm_agp_free(struct inode *inode, st
 		  unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_agp_buffer_t request;
 	drm_agp_mem_t    *entry;
 
@@ -381,14 +380,24 @@ int drm_agp_free(struct inode *inode, st
  * \return pointer to a drm_agp_head structure.
  *
  */
-drm_agp_head_t *drm_agp_init(void)
+drm_agp_head_t *drm_agp_init(drm_device_t *dev)
 {
 	drm_agp_head_t *head         = NULL;
 
 	if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
 		return NULL;
 	memset((void *)head, 0, sizeof(*head));
-	agp_copy_info(&head->agp_info);
+	head->bridge = agp_find_bridge(dev->pdev);
+	if (!head->bridge) {
+		if (!(head->bridge = agp_backend_acquire(dev->pdev))) {
+			drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
+			return NULL;
+		}
+		agp_copy_info(head->bridge, &head->agp_info);
+		agp_backend_release(head->bridge);
+	} else {
+		agp_copy_info(head->bridge, &head->agp_info);
+	}
 	if (head->agp_info.chipset == NOT_SUPPORTED) {
 		drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
 		return NULL;
@@ -406,9 +415,9 @@ drm_agp_head_t *drm_agp_init(void)
 }
 
 /** Calls agp_allocate_memory() */
-DRM_AGP_MEM *drm_agp_allocate_memory(size_t pages, u32 type)
+DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type)
 {
-	return agp_allocate_memory(pages, type);
+	return agp_allocate_memory(bridge, pages, type);
 }
 
 /** Calls agp_free_memory() */
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -176,7 +176,7 @@ int drm_getmagic(struct inode *inode, st
 	static drm_magic_t sequence = 0;
 	static DEFINE_SPINLOCK(lock);
 	drm_file_t	   *priv    = filp->private_data;
-	drm_device_t	   *dev	    = priv->dev;
+	drm_device_t	   *dev	    = priv->head->dev;
 	drm_auth_t	   auth;
 
 				/* Find unique magic */
@@ -214,7 +214,7 @@ int drm_authmagic(struct inode *inode, s
 		   unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	   *priv    = filp->private_data;
-	drm_device_t	   *dev	    = priv->dev;
+	drm_device_t	   *dev	    = priv->head->dev;
 	drm_auth_t	   auth;
 	drm_file_t	   *file;
 
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -77,7 +77,7 @@ int drm_addmap( struct inode *inode, str
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map;
 	drm_map_t __user *argp = (void __user *)arg;
 	drm_map_list_t *list;
@@ -221,7 +221,7 @@ int drm_rmmap(struct inode *inode, struc
 	       unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	*priv	= filp->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	struct list_head *list;
 	drm_map_list_t *r_list = NULL;
 	drm_vma_entry_t *pt, *prev;
@@ -349,7 +349,7 @@ int drm_addbufs_agp( struct inode *inode
 		      unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_desc_t request;
 	drm_buf_entry_t *entry;
@@ -514,7 +514,7 @@ int drm_addbufs_pci( struct inode *inode
 		      unsigned int cmd, unsigned long arg )
 {
    	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_desc_t request;
 	int count;
@@ -744,7 +744,7 @@ int drm_addbufs_sg( struct inode *inode,
                      unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_desc_t __user *argp = (void __user *)arg;
 	drm_buf_desc_t request;
@@ -925,7 +925,7 @@ int drm_addbufs( struct inode *inode, st
 {
 	drm_buf_desc_t request;
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	
 	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
 		return -EINVAL;
@@ -967,7 +967,7 @@ int drm_infobufs( struct inode *inode, s
 		   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_info_t request;
 	drm_buf_info_t __user *argp = (void __user *)arg;
@@ -1052,7 +1052,7 @@ int drm_markbufs( struct inode *inode, s
 		   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_desc_t request;
 	int order;
@@ -1101,7 +1101,7 @@ int drm_freebufs( struct inode *inode, s
 		   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_free_t request;
 	int i;
@@ -1158,7 +1158,7 @@ int drm_mapbufs( struct inode *inode, st
 		  unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_map_t __user *argp = (void __user *)arg;
 	int retcode = 0;
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -208,7 +208,7 @@ int drm_getsareactx(struct inode *inode,
 		     unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	*priv	= filp->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_ctx_priv_map_t __user *argp = (void __user *)arg;
 	drm_ctx_priv_map_t request;
 	drm_map_t *map;
@@ -247,7 +247,7 @@ int drm_setsareactx(struct inode *inode,
 		     unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	*priv	= filp->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_ctx_priv_map_t request;
 	drm_map_t *map = NULL;
 	drm_map_list_t *r_list = NULL;
@@ -395,7 +395,7 @@ int drm_addctx( struct inode *inode, str
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_ctx_list_t * ctx_entry;
 	drm_ctx_t __user *argp = (void __user *)arg;
 	drm_ctx_t ctx;
@@ -489,7 +489,7 @@ int drm_switchctx( struct inode *inode, 
 		    unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_ctx_t ctx;
 
 	if ( copy_from_user( &ctx, (drm_ctx_t __user *)arg, sizeof(ctx) ) )
@@ -514,7 +514,7 @@ int drm_newctx( struct inode *inode, str
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_ctx_t ctx;
 
 	if ( copy_from_user( &ctx, (drm_ctx_t __user *)arg, sizeof(ctx) ) )
@@ -541,7 +541,7 @@ int drm_rmctx( struct inode *inode, stru
 		unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_ctx_t ctx;
 
 	if ( copy_from_user( &ctx, (drm_ctx_t __user *)arg, sizeof(ctx) ) )
diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h
--- a/drivers/char/drm/drm_core.h
+++ b/drivers/char/drm/drm_core.h
@@ -20,15 +20,15 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-#define DRIVER_AUTHOR		"Gareth Hughes, Leif Delgass, JosÃ© Fonseca, Jon Smirl"
+#define CORE_AUTHOR		"Gareth Hughes, Leif Delgass, JosÃ© Fonseca, Jon Smirl"
 
-#define DRIVER_NAME		"drm"
-#define DRIVER_DESC		"DRM shared core routines"
-#define DRIVER_DATE		"20040925"
+#define CORE_NAME		"drm"
+#define CORE_DESC		"DRM shared core routines"
+#define CORE_DATE		"20040925"
 
 #define DRM_IF_MAJOR	1
 #define DRM_IF_MINOR	2
 
-#define DRIVER_MAJOR	1
-#define DRIVER_MINOR	0
-#define DRIVER_PATCHLEVEL 0
+#define CORE_MAJOR	1
+#define CORE_MINOR	0
+#define CORE_PATCHLEVEL 0
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -15,10 +15,6 @@
  * #define DRIVER_DESC		"Matrox G200/G400"
  * #define DRIVER_DATE		"20001127"
  *
- * #define DRIVER_MAJOR		2
- * #define DRIVER_MINOR		0
- * #define DRIVER_PATCHLEVEL	2
- *
  * #define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( mga_ioctls )
  *
  * #define drm_x		mga_##x
@@ -144,23 +140,17 @@ int drm_takedown( drm_device_t *dev )
 	if (dev->driver->pretakedown)
 	  dev->driver->pretakedown(dev);
 
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+
 	if ( dev->irq_enabled ) drm_irq_uninstall( dev );
 
 	down( &dev->struct_sem );
 	del_timer( &dev->timer );
 
-	if ( dev->devname ) {
-		drm_free( dev->devname, strlen( dev->devname ) + 1,
-			   DRM_MEM_DRIVER );
-		dev->devname = NULL;
-	}
-
-	if ( dev->unique ) {
-		drm_free( dev->unique, strlen( dev->unique ) + 1,
-			   DRM_MEM_DRIVER );
-		dev->unique = NULL;
-		dev->unique_len = 0;
-	}
 				/* Clear pid list */
 	for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
 		for ( pt = dev->magiclist[i].head ; pt ; pt = next ) {
@@ -185,7 +175,7 @@ int drm_takedown( drm_device_t *dev )
 		}
 		dev->agp->memory = NULL;
 
-		if ( dev->agp->acquired ) drm_agp_do_release();
+		if ( dev->agp->acquired ) drm_agp_do_release(dev);
 
 		dev->agp->acquired = 0;
 		dev->agp->enabled  = 0;
@@ -307,7 +297,7 @@ int drm_init( struct drm_driver *driver 
 		while ((pdev = pci_get_subsys(pid->vendor, pid->device, pid->subvendor, pid->subdevice, pdev)) != NULL) {
 			/* stealth mode requires a manual probe */
 			pci_dev_get(pdev);
-			drm_probe(pdev, pid, driver);
+			drm_get_dev(pdev, pid, driver);
 		}
 	}
 	return 0;
@@ -351,7 +341,8 @@ static void drm_cleanup( drm_device_t *d
 	if (dev->driver->postcleanup)
 		dev->driver->postcleanup(dev);
 	
-	if ( drm_put_minor(dev) )
+	drm_put_head(&dev->primary);
+	if ( drm_put_dev(dev) )
 		DRM_ERROR( "Cannot unload module\n" );
 }
 
@@ -359,19 +350,19 @@ void drm_exit (struct drm_driver *driver
 {
 	int i;
 	drm_device_t *dev = NULL;
-	drm_minor_t *minor;
+	drm_head_t *head;
 	
 	DRM_DEBUG( "\n" );
 
 	for (i = 0; i < drm_cards_limit; i++) {
-		minor = &drm_minors[i];
-		if (!minor->dev)
+		head = drm_heads[i];
+		if (!head)
 			continue;
-		if (minor->dev->driver!=driver)
+		if (!head->dev)
 			continue;
-
-		dev = minor->dev;
-		
+		if (head->dev->driver!=driver)
+			continue;
+		dev=head->dev;
 	}
 	if (dev) {
 		/* release the pci driver */
@@ -379,7 +370,6 @@ void drm_exit (struct drm_driver *driver
 			pci_dev_put(dev->pdev);
 		drm_cleanup(dev);
 	}
-	
 	DRM_INFO( "Module unloaded\n" );
 }
 EXPORT_SYMBOL(drm_exit);
@@ -395,9 +385,9 @@ static int __init drm_core_init(void)
 	int ret = -ENOMEM;
 	
 	drm_cards_limit = (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1);
-	drm_minors = drm_calloc(drm_cards_limit,
-				sizeof(*drm_minors), DRM_MEM_STUB);
-	if(!drm_minors) 
+	drm_heads = drm_calloc(drm_cards_limit,
+				sizeof(*drm_heads), DRM_MEM_STUB);
+	if(!drm_heads) 
 		goto err_p1;
 	
 	if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
@@ -418,18 +408,14 @@ static int __init drm_core_init(void)
 	}
 		
 	DRM_INFO( "Initialized %s %d.%d.%d %s\n",
-		DRIVER_NAME,
-		DRIVER_MAJOR,
-		DRIVER_MINOR,
-		DRIVER_PATCHLEVEL,
-		DRIVER_DATE
-		);
+		CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL,
+		CORE_DATE);
 	return 0;
 err_p3:
 	drm_sysfs_destroy(drm_class);
 err_p2:
 	unregister_chrdev(DRM_MAJOR, "drm");
-	drm_free(drm_minors, sizeof(*drm_minors) * drm_cards_limit, DRM_MEM_STUB);
+	drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
 err_p1:	
 	return ret;
 }
@@ -441,7 +427,7 @@ static void __exit drm_core_exit (void)
 
 	unregister_chrdev(DRM_MAJOR, "drm");
 
-	drm_free(drm_minors, sizeof(*drm_minors) *
+	drm_free(drm_heads, sizeof(*drm_heads) *
 				drm_cards_limit, DRM_MEM_STUB);
 }
 
@@ -465,7 +451,7 @@ int drm_version( struct inode *inode, st
 		  unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_version_t __user *argp = (void __user *)arg;
 	drm_version_t version;
 	int ret;
@@ -500,7 +486,7 @@ int drm_ioctl( struct inode *inode, stru
 		unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_ioctl_desc_t *ioctl;
 	drm_ioctl_t *func;
 	unsigned int nr = DRM_IOCTL_NR(cmd);
@@ -511,7 +497,7 @@ int drm_ioctl( struct inode *inode, stru
 	++priv->ioctl_count;
 
 	DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
-		   current->pid, cmd, nr, (long)old_encode_dev(dev->device), 
+		   current->pid, cmd, nr, (long)old_encode_dev(priv->head->device), 
 		   priv->authenticated );
 	
 	if (nr < DRIVER_IOCTL_COUNT)
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -143,8 +143,10 @@ int drm_open( struct inode *inode, struc
 	if (!((minor >= 0) && (minor < drm_cards_limit)))
 		return -ENODEV;
 		
-	dev = drm_minors[minor].dev;
-	if (!dev)
+	if (!drm_heads[minor])
+		return -ENODEV;
+
+	if (!(dev = drm_heads[minor]->dev))
 		return -ENODEV;
 	
 	retcode = drm_open_helper( inode, filp, dev );
@@ -181,7 +183,7 @@ int drm_release( struct inode *inode, st
 	int retcode = 0;
 
 	lock_kernel();
-	dev = priv->dev;
+	dev = priv->head->dev;
 
 	DRM_DEBUG( "open_count = %d\n", dev->open_count );
 
@@ -193,7 +195,7 @@ int drm_release( struct inode *inode, st
 	 */
 
 	DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
-		   current->pid, (long)old_encode_dev(dev->device), dev->open_count );
+		   current->pid, (long)old_encode_dev(priv->head->device), dev->open_count );
 
 	if ( priv->lock_count && dev->lock.hw_lock &&
 	     _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
@@ -358,7 +360,7 @@ int drm_open_helper(struct inode *inode,
 	priv->uid	    = current->euid;
 	priv->pid	    = current->pid;
 	priv->minor	    = minor;
-	priv->dev	    = dev;
+	priv->head          = drm_heads[minor];
 	priv->ioctl_count   = 0;
 	priv->authenticated = capable(CAP_SYS_ADMIN);
 	priv->lock_count    = 0;
@@ -412,10 +414,10 @@ out_free:
 int drm_flush(struct file *filp)
 {
 	drm_file_t    *priv   = filp->private_data;
-	drm_device_t  *dev    = priv->dev;
+	drm_device_t  *dev    = priv->head->dev;
 
 	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
-		  current->pid, (long)old_encode_dev(dev->device), dev->open_count);
+		  current->pid, (long)old_encode_dev(priv->head->device), dev->open_count);
 	return 0;
 }
 EXPORT_SYMBOL(drm_flush);
@@ -424,10 +426,10 @@ EXPORT_SYMBOL(drm_flush);
 int drm_fasync(int fd, struct file *filp, int on)
 {
 	drm_file_t    *priv   = filp->private_data;
-	drm_device_t  *dev    = priv->dev;
+	drm_device_t  *dev    = priv->head->dev;
 	int	      retcode;
 
-	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, (long)old_encode_dev(dev->device));
+	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, (long)old_encode_dev(priv->head->device));
 	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
 	if (retcode < 0) return retcode;
 	return 0;
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -53,7 +53,7 @@ int drm_getunique(struct inode *inode, s
 		   unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_unique_t	 __user *argp = (void __user *)arg;
 	drm_unique_t	 u;
 
@@ -87,7 +87,7 @@ int drm_setunique(struct inode *inode, s
 		   unsigned int cmd, unsigned long arg)
 {
 	drm_file_t	 *priv	 = filp->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_unique_t	 u;
 	int		 domain, bus, slot, func, ret;
 
@@ -173,7 +173,7 @@ int drm_getmap( struct inode *inode, str
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t   *priv = filp->private_data;
-	drm_device_t *dev  = priv->dev;
+	drm_device_t *dev  = priv->head->dev;
 	drm_map_t    __user *argp = (void __user *)arg;
 	drm_map_t    map;
 	drm_map_list_t *r_list = NULL;
@@ -233,7 +233,7 @@ int drm_getclient( struct inode *inode, 
 		    unsigned int cmd, unsigned long arg )
 {
 	drm_file_t   *priv = filp->private_data;
-	drm_device_t *dev  = priv->dev;
+	drm_device_t *dev  = priv->head->dev;
 	drm_client_t __user *argp = (void __user *)arg;
 	drm_client_t client;
 	drm_file_t   *pt;
@@ -277,7 +277,7 @@ int drm_getstats( struct inode *inode, s
 		   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t   *priv = filp->private_data;
-	drm_device_t *dev  = priv->dev;
+	drm_device_t *dev  = priv->head->dev;
 	drm_stats_t  stats;
 	int          i;
 
@@ -326,6 +326,8 @@ int drm_setversion(DRM_IOCTL_ARGS)
 
 	DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
 
+	memset(&version, 0, sizeof(version));
+
 	dev->driver->version(&version);
 	retv.drm_di_major = DRM_IF_MAJOR;
 	retv.drm_di_minor = DRM_IF_MINOR;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -54,7 +54,7 @@ int drm_irq_by_busid(struct inode *inode
 		   unsigned int cmd, unsigned long arg)
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_irq_busid_t __user *argp = (void __user *)arg;
 	drm_irq_busid_t p;
 
@@ -196,7 +196,7 @@ int drm_control( struct inode *inode, st
 		  unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_control_t ctl;
 	
 	/* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
@@ -243,7 +243,7 @@ int drm_control( struct inode *inode, st
 int drm_wait_vblank( DRM_IOCTL_ARGS )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_wait_vblank_t __user *argp = (void __user *)data;
 	drm_wait_vblank_t vblwait;
 	struct timeval now;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -50,7 +50,7 @@ int drm_lock( struct inode *inode, struc
 	       unsigned int cmd, unsigned long arg )
 {
         drm_file_t *priv = filp->private_data;
-        drm_device_t *dev = priv->dev;
+        drm_device_t *dev = priv->head->dev;
         DECLARE_WAITQUEUE( entry, current );
         drm_lock_t lock;
         int ret = 0;
@@ -145,7 +145,7 @@ int drm_unlock( struct inode *inode, str
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_lock_t lock;
 
 	if ( copy_from_user( &lock, (drm_lock_t __user *)arg, sizeof(lock) ) )
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -155,9 +155,9 @@ void drm_free_pages(unsigned long addres
 
 #if __OS_HAS_AGP
 /** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(int pages, u32 type)
+DRM_AGP_MEM *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type)
 {
-	return drm_agp_allocate_memory(pages, type);
+	return drm_agp_allocate_memory(bridge, pages, type);
 }
 
 /** Wrapper around agp_free_memory() */
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -35,7 +35,7 @@
 #define DRM_MEMORYBARRIER()		mb()
 /** DRM device local declaration */
 #define DRM_DEVICE	drm_file_t	*priv	= filp->private_data; \
-			drm_device_t	*dev	= priv->dev
+			drm_device_t	*dev	= priv->head->dev
 
 /** IRQ handler arguments and return type and values */
 #define DRM_IRQ_ARGS		int irq, void *arg, struct pt_regs *regs
@@ -89,7 +89,7 @@ static __inline__ int mtrr_del (int reg,
 	copy_to_user(arg1, arg2, arg3)
 /* Macros for copyfrom user, but checking readability only once */
 #define DRM_VERIFYAREA_READ( uaddr, size ) 		\
-	verify_area( VERIFY_READ, uaddr, size )
+	(access_ok( VERIFY_READ, uaddr, size ) ? 0 : -EFAULT)
 #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) 	\
 	__copy_from_user(arg1, arg2, arg3)
 #define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3)	\
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -50,6 +50,7 @@
 	{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
@@ -65,7 +66,7 @@
 	{0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
@@ -218,6 +219,7 @@
 	{0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-	{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -175,10 +175,10 @@ static int drm_name_info(char *buf, char
 	*eof   = 0;
 
 	if (dev->unique) {
-		DRM_PROC_PRINT("%s 0x%lx %s\n",
-			       dev->driver->pci_driver.name, (long)old_encode_dev(dev->device), dev->unique);
+		DRM_PROC_PRINT("%s %s %s\n",
+			       dev->driver->pci_driver.name, pci_name(dev->pdev), dev->unique);
 	} else {
-		DRM_PROC_PRINT("%s 0x%lx\n", dev->driver->pci_driver.name, (long)old_encode_dev(dev->device));
+		DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, pci_name(dev->pdev));
 	}
 
 	if (len > request + offset) return request;
diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c
--- a/drivers/char/drm/drm_scatter.c
+++ b/drivers/char/drm/drm_scatter.c
@@ -65,7 +65,7 @@ int drm_sg_alloc( struct inode *inode, s
 		   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_scatter_gather_t __user *argp = (void __user *)arg;
 	drm_scatter_gather_t request;
 	drm_sg_mem_t *entry;
@@ -205,7 +205,7 @@ int drm_sg_free( struct inode *inode, st
 		 unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_scatter_gather_t request;
 	drm_sg_mem_t *entry;
 
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -40,16 +40,16 @@ unsigned int drm_cards_limit = 16;	/* En
 unsigned int drm_debug = 0;		/* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR( CORE_AUTHOR );
+MODULE_DESCRIPTION( CORE_DESC );
 MODULE_LICENSE("GPL and additional rights");
-MODULE_PARM_DESC(drm_cards_limit, "Maximum number of graphics cards");
-MODULE_PARM_DESC(drm_debug, "Enable debug output");
+MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
+MODULE_PARM_DESC(debug, "Enable debug output");
 
 module_param_named(cards_limit, drm_cards_limit, int, 0444);
 module_param_named(debug, drm_debug, int, 0666);
 
-drm_minor_t *drm_minors;
+drm_head_t **drm_heads;
 struct drm_sysfs_class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 
@@ -91,7 +91,7 @@ static int drm_fill_in_dev(drm_device_t 
 			goto error_out_unreg;
 
 	if (drm_core_has_AGP(dev)) {
-		dev->agp = drm_agp_init();
+		dev->agp = drm_agp_init(dev);
 		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
 			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
 			retcode = -EINVAL;
@@ -112,12 +112,6 @@ static int drm_fill_in_dev(drm_device_t 
 		goto error_out_unreg;
 	}
 
-	dev->device = MKDEV(DRM_MAJOR, dev->minor );
-
-	/* postinit is a required function to display the signon banner */
-	if ((retcode = dev->driver->postinit(dev, ent->driver_data)))
-		goto error_out_unreg;
-
 	return 0;
 	
 error_out_unreg:
@@ -146,8 +140,10 @@ int drm_stub_open(struct inode *inode, s
 	if (!((minor >= 0) && (minor < drm_cards_limit)))
 		return -ENODEV;
 
-	dev = drm_minors[minor].dev;
-	if (!dev)
+	if (!drm_heads[minor])
+		return -ENODEV;
+	
+	if (!(dev = drm_heads[minor]->dev))
 		return -ENODEV;
 
 	old_fops = filp->f_op;
@@ -161,10 +157,11 @@ int drm_stub_open(struct inode *inode, s
 	return err;
 }
 
+
 /**
- * Get a device minor number.
+ * Register.
  *
- * \param pdev PCI device structure
+ * \param pdev - PCI device structure
  * \param ent entry from the PCI ID table with device type flags
  * \return zero on success or a negative number on failure.
  *
@@ -172,50 +169,86 @@ int drm_stub_open(struct inode *inode, s
  * then register the character device and inter module information.
  * Try and register, if we fail to register, backout previous work.
  */
-int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver)
+int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+	      struct drm_driver *driver)
 {
-	struct class_device *dev_class;
 	drm_device_t *dev;
 	int ret;
-	int minor;
-	drm_minor_t *minors = &drm_minors[0];
 
 	DRM_DEBUG("\n");
 
-	for (minor = 0; minor < drm_cards_limit; minor++, minors++) {
-		if (minors->type == DRM_MINOR_FREE) {
+	dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
+	if (!dev)
+		return -ENOMEM;
 
-			DRM_DEBUG("assigning minor %d\n", minor);
-			dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
-			if (!dev)
-				return -ENOMEM;
+	pci_enable_device(pdev);
 
-			*minors = (drm_minor_t){.dev = dev, .type=DRM_MINOR_PRIMARY};
-			dev->minor = minor;
+	if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
+		printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+		goto err_g1;
+	}
+	if ((ret = drm_get_head(dev, &dev->primary)))
+		goto err_g1;
 
-			pci_enable_device(pdev);
+	/* postinit is a required function to display the signon banner */
+	/* drivers add secondary heads here if needed */
+	if ((ret = dev->driver->postinit(dev, ent->driver_data)))
+		goto err_g1;
 
-			if ((ret=drm_fill_in_dev(dev, pdev, ent, driver))) {
-				printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
-				goto err_g1;
-			}
-			if ((ret = drm_proc_init(dev, minor, drm_proc_root, &minors->dev_root))) {
+	return 0;
+
+err_g1:
+	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+	return ret;
+}
+EXPORT_SYMBOL(drm_get_dev);
+
+/**
+ * Get a secondary minor number.
+ *
+ * \param dev device data structure
+ * \param sec-minor structure to hold the assigned minor
+ * \return negative number on failure.
+ *
+ * Search an empty entry and initialize it to the given parameters, and
+ * create the proc init entry via proc_init(). This routines assigns
+ * minor numbers to secondary heads of multi-headed cards
+ */
+int drm_get_head(drm_device_t *dev, drm_head_t *head)
+{
+	drm_head_t **heads = drm_heads;
+	int ret;
+	int minor;
+
+	DRM_DEBUG("\n");
+
+	for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
+		if (!*heads) {
+			
+			*head = (drm_head_t) {
+				.dev = dev,
+				.device = MKDEV(DRM_MAJOR, minor),
+				.minor = minor,
+			};
+			
+			if ((ret = drm_proc_init(dev, minor, drm_proc_root, &head->dev_root))) {
 				printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n");
 				goto err_g1;
 			}
 
 			
-			dev_class = drm_sysfs_device_add(drm_class,
-							 MKDEV(DRM_MAJOR,
-							       minor),
-							 &pdev->dev,
-							 "card%d", minor);
-			if (IS_ERR(dev_class)) {
+			head->dev_class = drm_sysfs_device_add(drm_class,
+							       MKDEV(DRM_MAJOR,
+								     minor),
+							       &dev->pdev->dev,
+							       "card%d", minor);
+			if (IS_ERR(head->dev_class)) {
 				printk(KERN_ERR "DRM: Error sysfs_device_add.\n");
-				ret = PTR_ERR(dev_class);
+				ret = PTR_ERR(head->dev_class);
 				goto err_g2;
 			}
-			
+			*heads = head;
+
 			DRM_DEBUG("new minor assigned %d\n", minor);
 			return 0;
 		}
@@ -223,36 +256,63 @@ int drm_probe(struct pci_dev *pdev, cons
 	DRM_ERROR("out of minors\n");
 	return -ENOMEM;
 err_g2:
-	drm_proc_cleanup(minor, drm_proc_root, minors->dev_root);
+	drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
 err_g1:
-	*minors = (drm_minor_t){.dev = NULL, .type = DRM_MINOR_FREE};
-	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+	*head = (drm_head_t) {.dev = NULL};
 	return ret;
 }
-EXPORT_SYMBOL(drm_probe);
 		
 
 /**
  * Put a device minor number.
  *
- * \param minor minor number.
- * \return always zero.
+ * \param dev device data structure
+ * \return always zero
  *
- * Cleans up the proc resources. If a minor is zero then release the foreign
- * "drm" data, otherwise unregisters the "drm" data, frees the stub list and
- * unregisters the character device. 
+ * Cleans up the proc resources. If it is the last minor then release the foreign
+ * "drm" data, otherwise unregisters the "drm" data, frees the dev list and
+ * unregisters the character device.
  */
-int drm_put_minor(drm_device_t *dev)
+int drm_put_dev(drm_device_t * dev)
 {
-	drm_minor_t *minors = &drm_minors[dev->minor];
+	DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
+
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname) + 1,
+			 DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+	return 0;
+}
+
+/**
+ * Put a secondary minor number.
+ *
+ * \param sec_minor - structure to be released
+ * \return always zero
+ *
+ * Cleans up the proc resources. Not legal for this to be the
+ * last minor released.
+ *
+ */
+int drm_put_head(drm_head_t *head)
+{
+	int minor = head->minor;
 	
-	DRM_DEBUG("release minor %d\n", dev->minor);
+	DRM_DEBUG("release secondary minor %d\n", minor);
 	
-	drm_proc_cleanup(dev->minor, drm_proc_root, minors->dev_root);
-	drm_sysfs_device_remove(MKDEV(DRM_MAJOR, dev->minor));
+	drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
+	drm_sysfs_device_remove(MKDEV(DRM_MAJOR, head->minor));
 	
-	*minors = (drm_minor_t){.dev = NULL, .type = DRM_MINOR_FREE};
-	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+	*head = (drm_head_t){.dev = NULL};
+
+	drm_heads[minor] = NULL;
 	
 	return 0;
 }
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -55,8 +55,8 @@ static void drm_sysfs_class_release(stru
 /* Display the version of drm_core. This doesn't work right in current design */
 static ssize_t version_show(struct class *dev, char *buf)
 {
-	return sprintf(buf, "%s %d.%d.%d %s\n", DRIVER_NAME, DRIVER_MAJOR,
-		       DRIVER_MINOR, DRIVER_PATCHLEVEL, DRIVER_DATE);
+	return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR,
+		       CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
 }
 
 static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -54,7 +54,7 @@ static __inline__ struct page *drm_do_vm
 						 unsigned long address)
 {
 	drm_file_t *priv  = vma->vm_file->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map    = NULL;
 	drm_map_list_t  *r_list;
 	struct list_head *list;
@@ -166,7 +166,7 @@ static __inline__ struct page *drm_do_vm
 void drm_vm_shm_close(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_vma_entry_t *pt, *prev, *next;
 	drm_map_t *map;
 	drm_map_list_t *r_list;
@@ -246,7 +246,7 @@ static __inline__ struct page *drm_do_vm
 						     unsigned long address)
 {
 	drm_file_t	 *priv	 = vma->vm_file->private_data;
-	drm_device_t	 *dev	 = priv->dev;
+	drm_device_t	 *dev	 = priv->head->dev;
 	drm_device_dma_t *dma	 = dev->dma;
 	unsigned long	 offset;
 	unsigned long	 page_nr;
@@ -281,7 +281,7 @@ static __inline__ struct page *drm_do_vm
 {
 	drm_map_t        *map    = (drm_map_t *)vma->vm_private_data;
 	drm_file_t *priv = vma->vm_file->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_device_t *dev = priv->head->dev;
 	drm_sg_mem_t *entry = dev->sg;
 	unsigned long offset;
 	unsigned long map_offset;
@@ -402,7 +402,7 @@ static struct vm_operations_struct   drm
 void drm_vm_open(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_vma_entry_t *vma_entry;
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -431,7 +431,7 @@ void drm_vm_open(struct vm_area_struct *
 void drm_vm_close(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_vma_entry_t *pt, *prev;
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -471,7 +471,7 @@ int drm_mmap_dma(struct file *filp, stru
 	unsigned long	 length	 = vma->vm_end - vma->vm_start;
 
 	lock_kernel();
-	dev	 = priv->dev;
+	dev	 = priv->head->dev;
 	dma	 = dev->dma;
 	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
 		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
@@ -528,7 +528,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
 int drm_mmap(struct file *filp, struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= filp->private_data;
-	drm_device_t	*dev	= priv->dev;
+	drm_device_t	*dev	= priv->head->dev;
 	drm_map_t	*map	= NULL;
 	drm_map_list_t  *r_list;
 	unsigned long   offset  = 0;
@@ -625,12 +625,12 @@ int drm_mmap(struct file *filp, struct v
 #endif
 		offset = dev->driver->get_reg_ofs(dev);
 #ifdef __sparc__
-		if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
-					VM_OFFSET(vma) + offset,
+		if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+					(VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
 					vma->vm_end - vma->vm_start,
-					vma->vm_page_prot, 0))
+					vma->vm_page_prot))
 #else
-		if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+		if (io_remap_pfn_range(vma, vma->vm_start,
 				     (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
 				     vma->vm_end - vma->vm_start,
 				     vma->vm_page_prot))
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -50,26 +50,6 @@
 #define up_write up
 #endif
 
-drm_ioctl_desc_t i810_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_I810_INIT)]    = { i810_dma_init,    1, 1 },
-	[DRM_IOCTL_NR(DRM_I810_VERTEX)]  = { i810_dma_vertex,  1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_CLEAR)]   = { i810_clear_bufs,  1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_FLUSH)]   = { i810_flush_ioctl, 1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_GETAGE)]  = { i810_getage,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_GETBUF)]  = { i810_getbuf,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_SWAP)]    = { i810_swap_bufs,   1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_COPY)]    = { i810_copybuf,     1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_DOCOPY)]  = { i810_docopy,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_OV0INFO)] = { i810_ov0_info,    1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_FSTATUS)] = { i810_fstatus,     1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = { i810_ov0_flip,    1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_MC)]      = { i810_dma_mc,      1, 1 },
-	[DRM_IOCTL_NR(DRM_I810_RSTATUS)] = { i810_rstatus,     1, 0 },
-	[DRM_IOCTL_NR(DRM_I810_FLIP)]    = { i810_flip_bufs,   1, 0 }
-};
-
-int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
-
 static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
    	drm_device_dma_t *dma = dev->dma;
@@ -128,7 +108,7 @@ int i810_mmap_buffers(struct file *filp,
 	drm_i810_buf_priv_t *buf_priv;
 
 	lock_kernel();
-	dev	 = priv->dev;
+	dev	 = priv->head->dev;
 	dev_priv = dev->dev_private;
 	buf      = dev_priv->mmap_buffer;
 	buf_priv = buf->dev_private;
@@ -139,7 +119,7 @@ int i810_mmap_buffers(struct file *filp,
    	buf_priv->currently_mapped = I810_BUF_MAPPED;
 	unlock_kernel();
 
-	if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+	if (io_remap_pfn_range(vma, vma->vm_start,
 			     VM_OFFSET(vma) >> PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot)) return -EAGAIN;
@@ -149,7 +129,7 @@ int i810_mmap_buffers(struct file *filp,
 static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
 {
 	drm_file_t	  *priv	  = filp->private_data;
-	drm_device_t	  *dev	  = priv->dev;
+	drm_device_t	  *dev	  = priv->head->dev;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
       	drm_i810_private_t *dev_priv = dev->dev_private;
    	struct file_operations *old_fops;
@@ -229,7 +209,7 @@ static int i810_dma_get_buffer(drm_devic
 	return retcode;
 }
 
-int i810_dma_cleanup(drm_device_t *dev)
+static int i810_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
 
@@ -455,7 +435,7 @@ static int i810_dma_initialize(drm_devic
  *    If it isn't then we have a v1.1 client. Fix up params.
  *    If it is, then we have a 1.2 client... get the rest of the data.
  */
-int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg)
+static int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg)
 {
 
 	/* Get v1.1 init data */
@@ -487,11 +467,11 @@ int i810_dma_init_compat(drm_i810_init_t
 	return 0;
 }
 
-int i810_dma_init(struct inode *inode, struct file *filp,
+static int i810_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_device_t *dev = priv->head->dev;
    	drm_i810_private_t *dev_priv;
    	drm_i810_init_t init;
    	int retcode = 0;
@@ -942,7 +922,7 @@ static void i810_dma_dispatch_flip( drm_
 
 }
 
-void i810_dma_quiescent(drm_device_t *dev)
+static void i810_dma_quiescent(drm_device_t *dev)
 {
       	drm_i810_private_t *dev_priv = dev->dev_private;
    	RING_LOCALS;
@@ -1027,7 +1007,7 @@ int i810_flush_ioctl(struct inode *inode
 		     unsigned int cmd, unsigned long arg)
 {
    	drm_file_t	  *priv	  = filp->private_data;
-   	drm_device_t	  *dev	  = priv->dev;
+   	drm_device_t	  *dev	  = priv->head->dev;
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
@@ -1036,11 +1016,11 @@ int i810_flush_ioctl(struct inode *inode
 }
 
 
-int i810_dma_vertex(struct inode *inode, struct file *filp,
+static int i810_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_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
    	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
       	u32 *hw_status = dev_priv->hw_status_page;
@@ -1073,11 +1053,11 @@ int i810_dma_vertex(struct inode *inode,
 
 
 
-int i810_clear_bufs(struct inode *inode, struct file *filp,
+static int i810_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_device_t *dev = priv->head->dev;
 	drm_i810_clear_t clear;
 
    	if (copy_from_user(&clear, (drm_i810_clear_t __user *)arg, sizeof(clear)))
@@ -1096,11 +1076,11 @@ int i810_clear_bufs(struct inode *inode,
    	return 0;
 }
 
-int i810_swap_bufs(struct inode *inode, struct file *filp,
+static int i810_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_device_t *dev = priv->head->dev;
 
 	DRM_DEBUG("i810_swap_bufs\n");
 
@@ -1110,11 +1090,11 @@ int i810_swap_bufs(struct inode *inode, 
    	return 0;
 }
 
-int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+static int i810_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_device_t	  *dev	    = priv->head->dev;
    	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
       	u32 *hw_status = dev_priv->hw_status_page;
    	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1124,11 +1104,11 @@ int i810_getage(struct inode *inode, str
 	return 0;
 }
 
-int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+static int i810_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;
+	drm_device_t	  *dev	    = priv->head->dev;
 	int		  retcode   = 0;
 	drm_i810_dma_t	  d;
    	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
@@ -1155,17 +1135,15 @@ int i810_getbuf(struct inode *inode, str
 	return retcode;
 }
 
-int i810_copybuf(struct inode *inode,
-		 struct file *filp, 
-		 unsigned int cmd,
-		 unsigned long arg)
+static int i810_copybuf(struct inode *inode,
+			 struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Never copy - 2.4.x doesn't need it */
 	return 0;
 }
 
-int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg)
 {
 	/* Never copy - 2.4.x doesn't need it */
 	return 0;
@@ -1234,11 +1212,11 @@ static void i810_dma_dispatch_mc(drm_dev
 	ADVANCE_LP_RING();
 }
 
-int i810_dma_mc(struct inode *inode, struct file *filp,
+static 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_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
 	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
 	u32 *hw_status = dev_priv->hw_status_page;
@@ -1265,21 +1243,21 @@ int i810_dma_mc(struct inode *inode, str
 	return 0;
 }
 
-int i810_rstatus(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
+static 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_device_t *dev = priv->head->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)
+static 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_device_t *dev = priv->head->dev;
 	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
 	drm_i810_overlay_t data;
 
@@ -1290,11 +1268,11 @@ int i810_ov0_info(struct inode *inode, s
 	return 0;
 }
 
-int i810_fstatus(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
+static 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_device_t *dev = priv->head->dev;
 	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1302,11 +1280,11 @@ int i810_fstatus(struct inode *inode, st
 	return I810_READ(0x30008);
 }
 
-int i810_ov0_flip(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
+static 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_device_t *dev = priv->head->dev;
 	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1330,7 +1308,7 @@ static void i810_do_init_pageflip( drm_d
 	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
 }
 
-int i810_do_cleanup_pageflip( drm_device_t *dev )
+static int i810_do_cleanup_pageflip( drm_device_t *dev )
 {
 	drm_i810_private_t *dev_priv = dev->dev_private;
 
@@ -1342,11 +1320,11 @@ int i810_do_cleanup_pageflip( drm_device
 	return 0;
 }
 
-int i810_flip_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
+static int i810_flip_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_device_t *dev = priv->head->dev;
 	drm_i810_private_t *dev_priv = dev->dev_private;
 
 	DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1365,6 +1343,16 @@ void i810_driver_pretakedown(drm_device_
 	i810_dma_cleanup( dev );
 }
 
+void i810_driver_prerelease(drm_device_t *dev, DRMFILE filp)
+{
+	if (dev->dev_private) {
+		drm_i810_private_t *dev_priv = dev->dev_private;
+		if (dev_priv->page_flipping) {
+			i810_do_cleanup_pageflip(dev);
+		}
+	}
+}
+
 void i810_driver_release(drm_device_t *dev, struct file *filp)
 {
 	i810_reclaim_buffers(dev, filp);
@@ -1376,4 +1364,22 @@ int i810_driver_dma_quiescent(drm_device
 	return 0;
 }
 
+drm_ioctl_desc_t i810_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_I810_INIT)]    = { i810_dma_init,    1, 1 },
+	[DRM_IOCTL_NR(DRM_I810_VERTEX)]  = { i810_dma_vertex,  1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_CLEAR)]   = { i810_clear_bufs,  1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_FLUSH)]   = { i810_flush_ioctl, 1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_GETAGE)]  = { i810_getage,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_GETBUF)]  = { i810_getbuf,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_SWAP)]    = { i810_swap_bufs,   1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_COPY)]    = { i810_copybuf,     1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_DOCOPY)]  = { i810_docopy,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_OV0INFO)] = { i810_ov0_info,    1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_FSTATUS)] = { i810_fstatus,     1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = { i810_ov0_flip,    1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_MC)]      = { i810_dma_mc,      1, 1 },
+	[DRM_IOCTL_NR(DRM_I810_RSTATUS)] = { i810_rstatus,     1, 0 },
+	[DRM_IOCTL_NR(DRM_I810_FLIP)]    = { i810_flip_bufs,   1, 0 }
+};
 
+int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
--- a/drivers/char/drm/i810_drv.c
+++ b/drivers/char/drm/i810_drv.c
@@ -53,7 +53,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
@@ -83,6 +83,7 @@ static struct drm_driver driver = {
 	.driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE,
 	.dev_priv_size = sizeof(drm_i810_buf_priv_t),
 	.pretakedown = i810_driver_pretakedown,
+	.prerelease = i810_driver_prerelease,
 	.release = i810_driver_release,
 	.dma_quiescent = i810_driver_dma_quiescent,
 	.reclaim_buffers = i810_reclaim_buffers,
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -114,57 +114,13 @@ typedef struct drm_i810_private {
 } drm_i810_private_t;
 
 				/* i810_dma.c */
-extern int  i810_dma_schedule(drm_device_t *dev, int locked);
-extern int  i810_getbuf(struct inode *inode, struct file *filp,
-			unsigned int cmd, unsigned long arg);
-extern int  i810_dma_init(struct inode *inode, struct file *filp,
-			  unsigned int cmd, unsigned long arg);
-extern int  i810_dma_cleanup(drm_device_t *dev);
-extern int  i810_flush_ioctl(struct inode *inode, struct file *filp,
-			     unsigned int cmd, unsigned long arg);
 extern void i810_reclaim_buffers(drm_device_t *dev, struct file *filp);
-extern int  i810_getage(struct inode *inode, struct file *filp,
-			unsigned int cmd, unsigned long arg);
 extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
 
-/* Obsolete:
- */
-extern int i810_copybuf(struct inode *inode, struct file *filp,
-			unsigned int cmd, unsigned long arg);
-/* Obsolete:
- */
-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);
-
-extern int i810_dma_vertex(struct inode *inode, struct file *filp,
-		    unsigned int cmd, unsigned long arg);
-
-extern int i810_swap_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg);
-
-extern int i810_clear_bufs(struct inode *inode, struct file *filp,
-		    unsigned int cmd, unsigned long arg);
-
-extern int i810_flip_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg);
-
 extern int i810_driver_dma_quiescent(drm_device_t *dev);
 extern void i810_driver_release(drm_device_t *dev, struct file *filp);
 extern void i810_driver_pretakedown(drm_device_t *dev);
+extern void i810_driver_prerelease(drm_device_t *dev, DRMFILE filp);
 
 #define I810_BASE(reg)		((unsigned long) \
 				dev_priv->mmio_map->handle)
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -52,42 +52,6 @@
 #define up_write up
 #endif
 
-drm_ioctl_desc_t i830_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_I830_INIT)]     = { i830_dma_init,    1, 1 },
-	[DRM_IOCTL_NR(DRM_I830_VERTEX)]   = { i830_dma_vertex,  1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_CLEAR)]    = { i830_clear_bufs,  1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_FLUSH)]    = { i830_flush_ioctl, 1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_GETAGE)]   = { i830_getage,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_GETBUF)]   = { i830_getbuf,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_SWAP)]     = { i830_swap_bufs,   1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_COPY)]     = { i830_copybuf,     1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_DOCOPY)]   = { i830_docopy,      1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_FLIP)]     = { i830_flip_bufs,   1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = { i830_irq_emit,    1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = { i830_irq_wait,    1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_GETPARAM)] = { i830_getparam,    1, 0 },
-	[DRM_IOCTL_NR(DRM_I830_SETPARAM)] = { i830_setparam,    1, 0 } 
-};
-
-int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
-
-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;
-	u32 *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;
@@ -146,7 +110,7 @@ int i830_mmap_buffers(struct file *filp,
 	drm_i830_buf_priv_t *buf_priv;
 
 	lock_kernel();
-	dev	 = priv->dev;
+	dev	 = priv->head->dev;
 	dev_priv = dev->dev_private;
 	buf      = dev_priv->mmap_buffer;
 	buf_priv = buf->dev_private;
@@ -157,7 +121,7 @@ int i830_mmap_buffers(struct file *filp,
    	buf_priv->currently_mapped = I830_BUF_MAPPED;
 	unlock_kernel();
 
-	if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+	if (io_remap_pfn_range(vma, vma->vm_start,
 			     VM_OFFSET(vma) >> PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot)) return -EAGAIN;
@@ -167,7 +131,7 @@ int i830_mmap_buffers(struct file *filp,
 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_device_t	  *dev	  = priv->head->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;
@@ -247,7 +211,7 @@ static int i830_dma_get_buffer(drm_devic
 	return retcode;
 }
 
-int i830_dma_cleanup(drm_device_t *dev)
+static int i830_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
 
@@ -479,11 +443,11 @@ static int i830_dma_initialize(drm_devic
    	return 0;
 }
 
-int i830_dma_init(struct inode *inode, struct file *filp,
+static 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_device_t *dev = priv->head->dev;
    	drm_i830_private_t *dev_priv;
    	drm_i830_init_t init;
    	int retcode = 0;
@@ -1252,7 +1216,7 @@ static void i830_dma_dispatch_vertex(drm
 }
 
 
-void i830_dma_quiescent(drm_device_t *dev)
+static void i830_dma_quiescent(drm_device_t *dev)
 {
       	drm_i830_private_t *dev_priv = dev->dev_private;
    	RING_LOCALS;
@@ -1329,11 +1293,11 @@ void i830_reclaim_buffers(drm_device_t *
 	}
 }
 
-int i830_flush_ioctl(struct inode *inode, struct file *filp, 
-		     unsigned int cmd, unsigned long arg)
+static 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_device_t	  *dev	  = priv->head->dev;
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
@@ -1341,11 +1305,11 @@ int i830_flush_ioctl(struct inode *inode
    	return 0;
 }
 
-int i830_dma_vertex(struct inode *inode, struct file *filp,
-	       unsigned int cmd, unsigned long arg)
+static 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_t *dev = priv->head->dev;
 	drm_device_dma_t *dma = dev->dma;
    	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
       	u32 *hw_status = dev_priv->hw_status_page;
@@ -1373,11 +1337,11 @@ int i830_dma_vertex(struct inode *inode,
 	return 0;
 }
 
-int i830_clear_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
+static 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_device_t *dev = priv->head->dev;
 	drm_i830_clear_t clear;
 
    	if (copy_from_user(&clear, (drm_i830_clear_t __user *)arg, sizeof(clear)))
@@ -1397,11 +1361,11 @@ int i830_clear_bufs(struct inode *inode,
    	return 0;
 }
 
-int i830_swap_bufs(struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg)
+static 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_device_t *dev = priv->head->dev;
    
 	DRM_DEBUG("i830_swap_bufs\n");
 
@@ -1425,7 +1389,7 @@ static void i830_do_init_pageflip( drm_d
 	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
 }
 
-int i830_do_cleanup_pageflip( drm_device_t *dev )
+static int i830_do_cleanup_pageflip( drm_device_t *dev )
 {
 	drm_i830_private_t *dev_priv = dev->dev_private;
 
@@ -1437,11 +1401,11 @@ int i830_do_cleanup_pageflip( drm_device
 	return 0;
 }
 
-int i830_flip_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
+static int i830_flip_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_device_t *dev = priv->head->dev;
 	drm_i830_private_t *dev_priv = dev->dev_private;
 
 	DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1455,11 +1419,11 @@ int i830_flip_bufs(struct inode *inode, 
    	return 0;
 }
 
-int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+static 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_device_t	  *dev	    = priv->head->dev;
    	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
       	u32 *hw_status = dev_priv->hw_status_page;
    	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
@@ -1469,11 +1433,11 @@ int i830_getage(struct inode *inode, str
 	return 0;
 }
 
-int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+static 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;
+	drm_device_t	  *dev	    = priv->head->dev;
 	int		  retcode   = 0;
 	drm_i830_dma_t	  d;
    	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
@@ -1501,28 +1465,26 @@ int i830_getbuf(struct inode *inode, str
 	return retcode;
 }
 
-int i830_copybuf(struct inode *inode,
-		 struct file *filp, 
-		 unsigned int cmd,
-		 unsigned long arg)
+static int i830_copybuf(struct inode *inode,
+			 struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Never copy - 2.4.x doesn't need it */
 	return 0;
 }
 
-int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg)
 {
 	return 0;
 }
 
 
 
-int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
-		      unsigned long arg )
+static int i830_getparam( 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_t	  *dev	    = priv->head->dev;
 	drm_i830_private_t *dev_priv = dev->dev_private;
 	drm_i830_getparam_t param;
 	int value;
@@ -1552,11 +1514,11 @@ int i830_getparam( struct inode *inode, 
 }
 
 
-int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd,
-		   unsigned long arg )
+static int i830_setparam( 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_t	  *dev	    = priv->head->dev;
 	drm_i830_private_t *dev_priv = dev->dev_private;
 	drm_i830_setparam_t param;
 
@@ -1585,6 +1547,16 @@ void i830_driver_pretakedown(drm_device_
 	i830_dma_cleanup( dev );
 }
 
+void i830_driver_prerelease(drm_device_t *dev, DRMFILE filp)
+{
+	if (dev->dev_private) {
+		drm_i830_private_t *dev_priv = dev->dev_private;
+		if (dev_priv->page_flipping) {
+			i830_do_cleanup_pageflip(dev);
+		}
+	}
+}
+
 void i830_driver_release(drm_device_t *dev, struct file *filp)
 {
 	i830_reclaim_buffers(dev, filp);
@@ -1596,3 +1568,21 @@ int i830_driver_dma_quiescent(drm_device
 	return 0;
 }
 
+drm_ioctl_desc_t i830_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_I830_INIT)]     = { i830_dma_init,    1, 1 },
+	[DRM_IOCTL_NR(DRM_I830_VERTEX)]   = { i830_dma_vertex,  1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_CLEAR)]    = { i830_clear_bufs,  1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_FLUSH)]    = { i830_flush_ioctl, 1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_GETAGE)]   = { i830_getage,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_GETBUF)]   = { i830_getbuf,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_SWAP)]     = { i830_swap_bufs,   1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_COPY)]     = { i830_copybuf,     1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_DOCOPY)]   = { i830_docopy,      1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_FLIP)]     = { i830_flip_bufs,   1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = { i830_irq_emit,    1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = { i830_irq_wait,    1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_GETPARAM)] = { i830_getparam,    1, 0 },
+	[DRM_IOCTL_NR(DRM_I830_SETPARAM)] = { i830_setparam,    1, 0 } 
+};
+
+int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c
--- a/drivers/char/drm/i830_drv.c
+++ b/drivers/char/drm/i830_drv.c
@@ -54,7 +54,7 @@ int postinit( struct drm_device *dev, un
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
@@ -87,6 +87,7 @@ static struct drm_driver driver = {
 #endif
 	.dev_priv_size = sizeof(drm_i830_buf_priv_t),
 	.pretakedown = i830_driver_pretakedown,
+	.prerelease = i830_driver_prerelease,
 	.release = i830_driver_release,
 	.dma_quiescent = i830_driver_dma_quiescent,
 	.reclaim_buffers = i830_reclaim_buffers,
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -120,51 +120,16 @@ typedef struct drm_i830_private {
 
 } 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_dma_cleanup(drm_device_t *dev);
-extern int  i830_flush_ioctl(struct inode *inode, struct file *filp,
-			     unsigned int cmd, unsigned long arg);
+/* i830_dma.c */
 extern void i830_reclaim_buffers(drm_device_t *dev, struct file *filp);
-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);
 
-extern int i830_flip_bufs(struct inode *inode, struct file *filp,
-			 unsigned int cmd, unsigned long arg);
-
-extern int i830_getparam( struct inode *inode, struct file *filp,
-			  unsigned int cmd, unsigned long arg );
-
-extern int i830_setparam( 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);
 
 /* i830_irq.c */
 extern int i830_irq_emit( struct inode *inode, struct file *filp, 
 			  unsigned int cmd, unsigned long arg );
 extern int i830_irq_wait( struct inode *inode, struct file *filp,
 			  unsigned int cmd, unsigned long arg );
-extern int i830_wait_irq(drm_device_t *dev, int irq_nr);
-extern int i830_emit_irq(drm_device_t *dev);
 
 extern irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS );
 extern void i830_driver_irq_preinstall( drm_device_t *dev );
@@ -173,6 +138,7 @@ extern void i830_driver_irq_uninstall( d
 extern void i830_driver_pretakedown(drm_device_t *dev);
 extern void i830_driver_release(drm_device_t *dev, struct file *filp);
 extern int i830_driver_dma_quiescent(drm_device_t *dev);
+extern void i830_driver_prerelease(drm_device_t *dev, DRMFILE filp);
 
 #define I830_BASE(reg)		((unsigned long) \
 				dev_priv->mmio_map->handle)
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -123,7 +123,7 @@ int i830_irq_emit( struct inode *inode, 
 		   unsigned long arg )
 {
 	drm_file_t	  *priv	    = filp->private_data;
-	drm_device_t	  *dev	    = priv->dev;
+	drm_device_t	  *dev	    = priv->head->dev;
 	drm_i830_private_t *dev_priv = dev->dev_private;
 	drm_i830_irq_emit_t emit;
 	int result;
@@ -155,7 +155,7 @@ int i830_irq_wait( struct inode *inode, 
 		   unsigned long arg )
 {
 	drm_file_t	  *priv	    = filp->private_data;
-	drm_device_t	  *dev	    = priv->dev;
+	drm_device_t	  *dev	    = priv->head->dev;
 	drm_i830_private_t *dev_priv = dev->dev_private;
 	drm_i830_irq_wait_t irqwait;
 
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -29,7 +29,7 @@ int postinit( struct drm_device *dev, un
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -41,6 +41,7 @@
 #define MGA_DEFAULT_USEC_TIMEOUT	10000
 #define MGA_FREELIST_DEBUG		0
 
+static int mga_do_cleanup_dma( drm_device_t *dev );
 
 /* ================================================================
  * Engine control
@@ -68,25 +69,7 @@ int mga_do_wait_for_idle( drm_mga_privat
 	return DRM_ERR(EBUSY);
 }
 
-int mga_do_dma_idle( drm_mga_private_t *dev_priv )
-{
-	u32 status = 0;
-	int i;
-	DRM_DEBUG( "\n" );
-
-	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-		status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK;
-		if ( status == MGA_ENDPRDMASTS ) return 0;
-		DRM_UDELAY( 1 );
-	}
-
-#if MGA_DMA_DEBUG
-	DRM_ERROR( "failed! status=0x%08x\n", status );
-#endif
-	return DRM_ERR(EBUSY);
-}
-
-int mga_do_dma_reset( drm_mga_private_t *dev_priv )
+static int mga_do_dma_reset( drm_mga_private_t *dev_priv )
 {
 	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
@@ -110,44 +93,6 @@ int mga_do_dma_reset( drm_mga_private_t 
 	return 0;
 }
 
-int mga_do_engine_reset( drm_mga_private_t *dev_priv )
-{
-	DRM_DEBUG( "\n" );
-
-	/* Okay, so we've completely screwed up and locked the engine.
-	 * How about we clean up after ourselves?
-	 */
-	MGA_WRITE( MGA_RST, MGA_SOFTRESET );
-	DRM_UDELAY( 15 );				/* Wait at least 10 usecs */
-	MGA_WRITE( MGA_RST, 0 );
-
-	/* Initialize the registers that get clobbered by the soft
-	 * reset.  Many of the core register values survive a reset,
-	 * but the drawing registers are basically all gone.
-	 *
-	 * 3D clients should probably die after calling this.  The X
-	 * server should reset the engine state to known values.
-	 */
-#if 0
-	MGA_WRITE( MGA_PRIMPTR,
-		   virt_to_bus((void *)dev_priv->prim.status_page) |
-		   MGA_PRIMPTREN0 |
-		   MGA_PRIMPTREN1 );
-#endif
-
-	MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR );
-	MGA_WRITE( MGA_IEN,    MGA_SOFTRAPIEN );
-
-	/* The primary DMA stream should look like new right about now.
-	 */
-	mga_do_dma_reset( dev_priv );
-
-	/* This bad boy will never fail.
-	 */
-	return 0;
-}
-
-
 /* ================================================================
  * Primary DMA stream
  */
@@ -625,7 +570,7 @@ static int mga_do_init_dma( drm_device_t
 	return 0;
 }
 
-int mga_do_cleanup_dma( drm_device_t *dev )
+static int mga_do_cleanup_dma( drm_device_t *dev )
 {
 	DRM_DEBUG( "\n" );
 
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -51,7 +51,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -121,10 +121,6 @@ extern void mga_driver_pretakedown(drm_d
 extern int mga_driver_dma_quiescent(drm_device_t *dev);
 
 extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv );
-extern int mga_do_dma_idle( drm_mga_private_t *dev_priv );
-extern int mga_do_dma_reset( drm_mga_private_t *dev_priv );
-extern int mga_do_engine_reset( drm_mga_private_t *dev_priv );
-extern int mga_do_cleanup_dma( drm_device_t *dev );
 
 extern void mga_do_dma_flush( drm_mga_private_t *dev_priv );
 extern void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv );
@@ -132,15 +128,6 @@ extern void mga_do_dma_wrap_end( drm_mga
 
 extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf );
 
-				/* mga_state.c */
-extern int  mga_dma_clear( DRM_IOCTL_ARGS );
-extern int  mga_dma_swap( DRM_IOCTL_ARGS );
-extern int  mga_dma_vertex( DRM_IOCTL_ARGS );
-extern int  mga_dma_indices( DRM_IOCTL_ARGS );
-extern int  mga_dma_iload( DRM_IOCTL_ARGS );
-extern int  mga_dma_blit( DRM_IOCTL_ARGS );
-extern int  mga_getparam( DRM_IOCTL_ARGS );
-
 				/* mga_warp.c */
 extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv );
 extern int mga_warp_init( drm_mga_private_t *dev_priv );
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -37,21 +37,6 @@
 #include "mga_drm.h"
 #include "mga_drv.h"
 
-drm_ioctl_desc_t mga_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_MGA_INIT)]    = { mga_dma_init,    1, 1 },
-	[DRM_IOCTL_NR(DRM_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_RESET)]   = { mga_dma_reset,   1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_SWAP)]    = { mga_dma_swap,    1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_BLIT)]    = { mga_dma_blit,    1, 0 },
-	[DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
-};
-
-int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
-
 /* ================================================================
  * DMA hardware state programming functions
  */
@@ -893,7 +878,7 @@ static void mga_dma_dispatch_blit( drm_d
  *
  */
 
-int mga_dma_clear( DRM_IOCTL_ARGS )
+static int mga_dma_clear( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -918,7 +903,7 @@ int mga_dma_clear( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_dma_swap( DRM_IOCTL_ARGS )
+static int mga_dma_swap( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -940,7 +925,7 @@ int mga_dma_swap( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_dma_vertex( DRM_IOCTL_ARGS )
+static int mga_dma_vertex( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -979,7 +964,7 @@ int mga_dma_vertex( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_dma_indices( DRM_IOCTL_ARGS )
+static int mga_dma_indices( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -1018,7 +1003,7 @@ int mga_dma_indices( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_dma_iload( DRM_IOCTL_ARGS )
+static int mga_dma_iload( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_device_dma_t *dma = dev->dma;
@@ -1060,7 +1045,7 @@ int mga_dma_iload( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_dma_blit( DRM_IOCTL_ARGS )
+static int mga_dma_blit( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -1089,7 +1074,7 @@ int mga_dma_blit( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int mga_getparam( DRM_IOCTL_ARGS )
+static int mga_getparam( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_mga_private_t *dev_priv = dev->dev_private;
@@ -1121,3 +1106,18 @@ int mga_getparam( DRM_IOCTL_ARGS )
 	
 	return 0;
 }
+
+drm_ioctl_desc_t mga_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_MGA_INIT)]    = { mga_dma_init,    1, 1 },
+	[DRM_IOCTL_NR(DRM_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_RESET)]   = { mga_dma_reset,   1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_SWAP)]    = { mga_dma_swap,    1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_BLIT)]    = { mga_dma_blit,    1, 0 },
+	[DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
+};
+
+int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -80,7 +80,7 @@ static u32 r128_cce_microcode[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
-int R128_READ_PLL(drm_device_t *dev, int addr)
+static int R128_READ_PLL(drm_device_t *dev, int addr)
 {
 	drm_r128_private_t *dev_priv = dev->dev_private;
 
@@ -808,7 +808,7 @@ static int r128_freelist_init( drm_devic
 }
 #endif
 
-drm_buf_t *r128_freelist_get( drm_device_t *dev )
+static drm_buf_t *r128_freelist_get( drm_device_t *dev )
 {
 	drm_device_dma_t *dma = dev->dma;
 	drm_r128_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -45,7 +45,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -139,27 +139,13 @@ extern int r128_cce_idle( DRM_IOCTL_ARGS
 extern int r128_engine_reset( DRM_IOCTL_ARGS );
 extern int r128_fullscreen( DRM_IOCTL_ARGS );
 extern int r128_cce_buffers( DRM_IOCTL_ARGS );
-extern int r128_getparam( DRM_IOCTL_ARGS );
 
 extern void r128_freelist_reset( drm_device_t *dev );
-extern drm_buf_t *r128_freelist_get( drm_device_t *dev );
 
 extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n );
 
 extern int r128_do_cce_idle( drm_r128_private_t *dev_priv );
 extern int r128_do_cleanup_cce( drm_device_t *dev );
-extern int r128_do_cleanup_pageflip( drm_device_t *dev );
-
-				/* r128_state.c */
-extern int r128_cce_clear( DRM_IOCTL_ARGS );
-extern int r128_cce_swap( DRM_IOCTL_ARGS );
-extern int r128_cce_flip( DRM_IOCTL_ARGS );
-extern int r128_cce_vertex( DRM_IOCTL_ARGS );
-extern int r128_cce_indices( DRM_IOCTL_ARGS );
-extern int r128_cce_blit( DRM_IOCTL_ARGS );
-extern int r128_cce_depth( DRM_IOCTL_ARGS );
-extern int r128_cce_stipple( DRM_IOCTL_ARGS );
-extern int r128_cce_indirect( DRM_IOCTL_ARGS );
 
 extern int r128_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
 
@@ -406,8 +392,6 @@ do {									\
 	R128_WRITE(R128_CLOCK_CNTL_DATA, (val));			\
 } while (0)
 
-extern int R128_READ_PLL(drm_device_t *dev, int addr);
-
 
 #define CCE_PACKET0( reg, n )		(R128_CCE_PACKET0 |		\
 					 ((n) << 16) | ((reg) >> 2))
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -32,27 +32,6 @@
 #include "r128_drm.h"
 #include "r128_drv.h"
 
-drm_ioctl_desc_t r128_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_R128_INIT)]       = { r128_cce_init,     1, 1 },
-	[DRM_IOCTL_NR(DRM_R128_CCE_START)]  = { r128_cce_start,    1, 1 },
-	[DRM_IOCTL_NR(DRM_R128_CCE_STOP)]   = { r128_cce_stop,     1, 1 },
-	[DRM_IOCTL_NR(DRM_R128_CCE_RESET)]  = { r128_cce_reset,    1, 1 },
-	[DRM_IOCTL_NR(DRM_R128_CCE_IDLE)]   = { r128_cce_idle,     1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_RESET)]      = { r128_engine_reset, 1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = { r128_fullscreen,   1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_SWAP)]       = { r128_cce_swap,     1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_FLIP)]       = { r128_cce_flip,     1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_CLEAR)]      = { r128_cce_clear,    1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_VERTEX)]     = { r128_cce_vertex,   1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_INDICES)]    = { r128_cce_indices,  1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_BLIT)]       = { r128_cce_blit,     1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_DEPTH)]      = { r128_cce_depth,    1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_STIPPLE)]    = { r128_cce_stipple,  1, 0 },
-	[DRM_IOCTL_NR(DRM_R128_INDIRECT)]   = { r128_cce_indirect, 1, 1 },
-	[DRM_IOCTL_NR(DRM_R128_GETPARAM)]   = { r128_getparam, 1, 0 },
-};
-
-int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
 
 /* ================================================================
  * CCE hardware state programming functions
@@ -1281,7 +1260,7 @@ static void r128_cce_dispatch_stipple( d
  * IOCTL functions
  */
 
-int r128_cce_clear( DRM_IOCTL_ARGS )
+static int r128_cce_clear( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1349,7 +1328,7 @@ int r128_do_cleanup_pageflip( drm_device
  * They can & should be intermixed to support multiple 3d windows.  
  */
 
-int r128_cce_flip( DRM_IOCTL_ARGS )
+static int r128_cce_flip( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1368,7 +1347,7 @@ int r128_cce_flip( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_cce_swap( DRM_IOCTL_ARGS )
+static int r128_cce_swap( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1390,7 +1369,7 @@ int r128_cce_swap( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_cce_vertex( DRM_IOCTL_ARGS )
+static int r128_cce_vertex( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1450,7 +1429,7 @@ int r128_cce_vertex( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_cce_indices( DRM_IOCTL_ARGS )
+static int r128_cce_indices( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1522,7 +1501,7 @@ int r128_cce_indices( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_cce_blit( DRM_IOCTL_ARGS )
+static int r128_cce_blit( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_device_dma_t *dma = dev->dma;
@@ -1552,7 +1531,7 @@ int r128_cce_blit( DRM_IOCTL_ARGS )
 	return ret;
 }
 
-int r128_cce_depth( DRM_IOCTL_ARGS )
+static int r128_cce_depth( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1570,19 +1549,23 @@ int r128_cce_depth( DRM_IOCTL_ARGS )
 	switch ( depth.func ) {
 	case R128_WRITE_SPAN:
 		ret = r128_cce_dispatch_write_span( dev, &depth );
+		break;
 	case R128_WRITE_PIXELS:
 		ret = r128_cce_dispatch_write_pixels( dev, &depth );
+		break;
 	case R128_READ_SPAN:
 		ret = r128_cce_dispatch_read_span( dev, &depth );
+		break;
 	case R128_READ_PIXELS:
 		ret = r128_cce_dispatch_read_pixels( dev, &depth );
+		break;
 	}
 
 	COMMIT_RING();
 	return ret;
 }
 
-int r128_cce_stipple( DRM_IOCTL_ARGS )
+static int r128_cce_stipple( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1606,7 +1589,7 @@ int r128_cce_stipple( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_cce_indirect( DRM_IOCTL_ARGS )
+static int r128_cce_indirect( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1682,7 +1665,7 @@ int r128_cce_indirect( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int r128_getparam( DRM_IOCTL_ARGS )
+static int r128_getparam( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1730,3 +1713,24 @@ void r128_driver_pretakedown(drm_device_
 	r128_do_cleanup_cce( dev );
 }
 
+drm_ioctl_desc_t r128_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_R128_INIT)]       = { r128_cce_init,     1, 1 },
+	[DRM_IOCTL_NR(DRM_R128_CCE_START)]  = { r128_cce_start,    1, 1 },
+	[DRM_IOCTL_NR(DRM_R128_CCE_STOP)]   = { r128_cce_stop,     1, 1 },
+	[DRM_IOCTL_NR(DRM_R128_CCE_RESET)]  = { r128_cce_reset,    1, 1 },
+	[DRM_IOCTL_NR(DRM_R128_CCE_IDLE)]   = { r128_cce_idle,     1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_RESET)]      = { r128_engine_reset, 1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = { r128_fullscreen,   1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_SWAP)]       = { r128_cce_swap,     1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_FLIP)]       = { r128_cce_flip,     1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_CLEAR)]      = { r128_cce_clear,    1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_VERTEX)]     = { r128_cce_vertex,   1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_INDICES)]    = { r128_cce_indices,  1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_BLIT)]       = { r128_cce_blit,     1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_DEPTH)]      = { r128_cce_depth,    1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_STIPPLE)]    = { r128_cce_stipple,  1, 0 },
+	[DRM_IOCTL_NR(DRM_R128_INDIRECT)]   = { r128_cce_indirect, 1, 1 },
+	[DRM_IOCTL_NR(DRM_R128_GETPARAM)]   = { r128_getparam, 1, 0 },
+};
+
+int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -35,6 +35,7 @@
 
 #define RADEON_FIFO_DEBUG	0
 
+static int radeon_do_cleanup_cp( drm_device_t *dev );
 
 /* CP microcode (from ATI) */
 static u32 R200_cp_microcode[][2] = {
@@ -815,7 +816,7 @@ static u32 R300_cp_microcode[][2] = {
 	{ 0000000000, 0000000000 },
 };
 
-int RADEON_READ_PLL(drm_device_t *dev, int addr)
+static int RADEON_READ_PLL(drm_device_t *dev, int addr)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 
@@ -1538,7 +1539,7 @@ static int radeon_do_init_cp( drm_device
 	return 0;
 }
 
-int radeon_do_cleanup_cp( drm_device_t *dev )
+static int radeon_do_cleanup_cp( drm_device_t *dev )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -146,8 +146,14 @@
 #define RADEON_EMIT_PP_TEX_SIZE_2                   75
 #define R200_EMIT_RB3D_BLENDCOLOR                   76
 #define R200_EMIT_TCL_POINT_SPRITE_CNTL             77
-#define RADEON_MAX_STATE_PACKETS                    78
-
+#define RADEON_EMIT_PP_CUBIC_FACES_0                78
+#define RADEON_EMIT_PP_CUBIC_OFFSETS_T0             79
+#define RADEON_EMIT_PP_CUBIC_FACES_1                80
+#define RADEON_EMIT_PP_CUBIC_OFFSETS_T1             81
+#define RADEON_EMIT_PP_CUBIC_FACES_2                82
+#define RADEON_EMIT_PP_CUBIC_OFFSETS_T2             83
+#define R200_EMIT_PP_TRI_PERF_CNTL                  84
+#define RADEON_MAX_STATE_PACKETS                    85
 
 /* Commands understood by cmd_buffer ioctl.  More can be added but
  * obviously these can't be removed or changed:
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -46,7 +46,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20050125"
+#define DRIVER_DATE		"20050311"
 
 /* Interface history:
  *
@@ -78,9 +78,13 @@
  *     - Add hyperz support, add hyperz flags to clear ioctl.
  * 1.14- Add support for color tiling
  *     - Add R100/R200 surface allocation/free support
+ * 1.15- Add support for texture micro tiling
+ *     - Add support for r100 cube maps
+ * 1.16- Add R200_EMIT_PP_TRI_PERF_CNTL packet to support brilinear
+ *       texture filtering on r200
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		14
+#define DRIVER_MINOR		16
 #define DRIVER_PATCHLEVEL	0
 
 #define GET_RING_HEAD(dev_priv)		DRM_READ32(  (dev_priv)->ring_rptr, 0 )
@@ -284,42 +288,20 @@ extern drm_buf_t *radeon_freelist_get( d
 extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n );
 
 extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv );
-extern int radeon_do_cleanup_cp( drm_device_t *dev );
-extern int radeon_do_cleanup_pageflip( drm_device_t *dev );
 
 extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
 extern int radeon_driver_postcleanup(struct drm_device *dev);
 
-				/* radeon_state.c */
-extern int radeon_cp_clear( DRM_IOCTL_ARGS );
-extern int radeon_cp_swap( DRM_IOCTL_ARGS );
-extern int radeon_cp_vertex( DRM_IOCTL_ARGS );
-extern int radeon_cp_indices( DRM_IOCTL_ARGS );
-extern int radeon_cp_texture( DRM_IOCTL_ARGS );
-extern int radeon_cp_stipple( DRM_IOCTL_ARGS );
-extern int radeon_cp_indirect( DRM_IOCTL_ARGS );
-extern int radeon_cp_vertex2( DRM_IOCTL_ARGS );
-extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS );
-extern int radeon_cp_getparam( DRM_IOCTL_ARGS );
-extern int radeon_cp_setparam( DRM_IOCTL_ARGS );
-extern int radeon_cp_flip( DRM_IOCTL_ARGS );
-
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
 extern int radeon_mem_free( DRM_IOCTL_ARGS );
 extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );
 extern void radeon_mem_takedown( struct mem_block **heap );
 extern void radeon_mem_release( DRMFILE filp, struct mem_block *heap );
-extern int radeon_surface_alloc(DRM_IOCTL_ARGS);
-extern int radeon_surface_free(DRM_IOCTL_ARGS);
 
 				/* radeon_irq.c */
 extern int radeon_irq_emit( DRM_IOCTL_ARGS );
 extern int radeon_irq_wait( DRM_IOCTL_ARGS );
 
-extern int radeon_emit_and_wait_irq(drm_device_t *dev);
-extern int radeon_wait_irq(drm_device_t *dev, int swi_nr);
-extern int radeon_emit_irq(drm_device_t *dev);
-
 extern void radeon_do_release(drm_device_t *dev);
 extern int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
 extern irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS );
@@ -672,6 +654,8 @@ extern int radeon_postcleanup( struct dr
 #	define RADEON_3D_DRAW_IMMD		0x00002900
 #	define RADEON_3D_DRAW_INDX		0x00002A00
 #	define RADEON_3D_LOAD_VBPNTR		0x00002F00
+#	define RADEON_MPEG_IDCT_MACROBLOCK	0x00003000
+#	define RADEON_MPEG_IDCT_MACROBLOCK_REV	0x00003100
 #	define RADEON_3D_CLEAR_ZMASK		0x00003200
 #	define RADEON_3D_CLEAR_HIZ		0x00003700
 #	define RADEON_CNTL_HOSTDATA_BLT		0x00009400
@@ -817,6 +801,12 @@ extern int radeon_postcleanup( struct dr
 #define RADEON_PP_TEX_SIZE_1                0x1d0c
 #define RADEON_PP_TEX_SIZE_2                0x1d14
 
+#define RADEON_PP_CUBIC_FACES_0             0x1d24
+#define RADEON_PP_CUBIC_FACES_1             0x1d28
+#define RADEON_PP_CUBIC_FACES_2             0x1d2c
+#define RADEON_PP_CUBIC_OFFSET_T0_0         0x1dd0	/* bits [31:5] */
+#define RADEON_PP_CUBIC_OFFSET_T1_0         0x1e00
+#define RADEON_PP_CUBIC_OFFSET_T2_0         0x1e14
 
 #define SE_VAP_CNTL__TCL_ENA_MASK                          0x00000001
 #define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK                   0x00010000
@@ -834,6 +824,8 @@ extern int radeon_postcleanup( struct dr
 
 #define R200_SE_TCL_POINT_SPRITE_CNTL     0x22c4
 
+#define R200_PP_TRI_PERF 0x2cf8
+
 /* Constants */
 #define RADEON_MAX_USEC_TIMEOUT		100000	/* 100 ms */
 
@@ -860,9 +852,6 @@ do {									\
 	RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) );			\
 } while (0)
 
-extern int RADEON_READ_PLL( drm_device_t *dev, int addr );
-
-
 #define CP_PACKET0( reg, n )						\
 	(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
 #define CP_PACKET0_TABLE( reg, n )					\
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -93,7 +93,7 @@ static __inline__ void radeon_acknowledg
 		RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
 }
 
-int radeon_emit_irq(drm_device_t *dev)
+static int radeon_emit_irq(drm_device_t *dev)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	unsigned int ret;
@@ -112,7 +112,7 @@ int radeon_emit_irq(drm_device_t *dev)
 }
 
 
-int radeon_wait_irq(drm_device_t *dev, int swi_nr)
+static int radeon_wait_irq(drm_device_t *dev, int swi_nr)
 {
   	drm_radeon_private_t *dev_priv = 
 	   (drm_radeon_private_t *)dev->dev_private;
@@ -123,23 +123,12 @@ int radeon_wait_irq(drm_device_t *dev, i
 
 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
-	/* This is a hack to work around mysterious freezes on certain
-	 * systems:
-	 */ 
-	radeon_acknowledge_irqs( dev_priv );
-
 	DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, 
 		     RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr );
 
 	return ret;
 }
 
-int radeon_emit_and_wait_irq(drm_device_t *dev)
-{
-	return radeon_wait_irq( dev, radeon_emit_irq(dev) );
-}
-
-
 int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
 {
   	drm_radeon_private_t *dev_priv = 
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -33,38 +33,6 @@
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 
-drm_ioctl_desc_t radeon_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_RADEON_CP_INIT)]    = { radeon_cp_init,      1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_CP_START)]   = { radeon_cp_start,     1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_CP_STOP)]    = { radeon_cp_stop,      1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_CP_RESET)]   = { radeon_cp_reset,     1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)]    = { radeon_cp_idle,      1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)]  = { radeon_cp_resume,    1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_RESET)]      = { radeon_engine_reset, 1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = { radeon_fullscreen,   1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_SWAP)]       = { radeon_cp_swap,      1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_CLEAR)]      = { radeon_cp_clear,     1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_VERTEX)]     = { radeon_cp_vertex,    1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_INDICES)]    = { radeon_cp_indices,   1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_TEXTURE)]    = { radeon_cp_texture,   1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_STIPPLE)]    = { radeon_cp_stipple,   1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_INDIRECT)]   = { radeon_cp_indirect,  1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_VERTEX2)]    = { radeon_cp_vertex2,   1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_CMDBUF)]     = { radeon_cp_cmdbuf,    1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_GETPARAM)]   = { radeon_cp_getparam,  1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_FLIP)]       = { radeon_cp_flip,      1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_ALLOC)]      = { radeon_mem_alloc,    1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_FREE)]       = { radeon_mem_free,     1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)]  = { radeon_mem_init_heap,1, 1 },
-	[DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)]   = { radeon_irq_emit,     1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)]   = { radeon_irq_wait,     1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_SETPARAM)]   = { radeon_cp_setparam,  1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = { radeon_surface_alloc,1, 0 },
-	[DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)]  = { radeon_surface_free, 1, 0 }
-};
-
-int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
-
 /* ================================================================
  * Helper functions for client state checking and fixup
  */
@@ -158,6 +126,22 @@ static __inline__ int radeon_check_and_f
 		break;
 	}
 
+	case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
+	case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
+	case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
+			int i;
+			for (i = 0; i < 5; i++) {
+				if (radeon_check_and_fixup_offset(dev_priv,
+								  filp_priv,
+								  &data[i])) {
+					DRM_ERROR
+					    ("Invalid R100 cubic texture offset\n");
+					return DRM_ERR(EINVAL);
+				}
+			}
+		}
+		break;
+
 	case RADEON_EMIT_RB3D_COLORPITCH:
 	case RADEON_EMIT_RE_LINE_PATTERN:
 	case RADEON_EMIT_SE_LINE_WIDTH:
@@ -219,6 +203,10 @@ static __inline__ int radeon_check_and_f
 	case RADEON_EMIT_PP_TEX_SIZE_2:
 	case R200_EMIT_RB3D_BLENDCOLOR:
 	case R200_EMIT_TCL_POINT_SPRITE_CNTL:
+	case RADEON_EMIT_PP_CUBIC_FACES_0:
+	case RADEON_EMIT_PP_CUBIC_FACES_1:
+	case RADEON_EMIT_PP_CUBIC_FACES_2:
+	case R200_EMIT_PP_TRI_PERF_CNTL:
 		/* These packets don't contain memory offsets */
 		break;
 
@@ -573,6 +561,13 @@ static struct { 
 	{ RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2" },
 	{ R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR" },
 	{ R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL" },
+	{ RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
+	{ RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
+	{ RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
+	{ RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
+	{ RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
+	{ RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
+	{ R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
 };
 
 
@@ -1514,6 +1509,7 @@ static int radeon_cp_dispatch_texture( D
 	int size, dwords, tex_width, blit_width;
 	u32 height;
 	int i;
+	u32 texpitch, microtile;
 	RING_LOCALS;
 
 	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
@@ -1576,6 +1572,16 @@ static int radeon_cp_dispatch_texture( D
 		DRM_ERROR( "invalid texture format %d\n", tex->format );
 		return DRM_ERR(EINVAL);
 	}
+	texpitch = tex->pitch;
+	if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
+		microtile = 1;
+		if (tex_width < 64) {
+			texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
+			/* we got tiled coordinates, untile them */
+			image->x *= 2;
+		}
+	}
+	else microtile = 0;
 
 	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width );
 
@@ -1628,7 +1634,7 @@ static int radeon_cp_dispatch_texture( D
 			     RADEON_GMC_CLR_CMP_CNTL_DIS |
 			     RADEON_GMC_WR_MSK_DIS);
 		
-		buffer[2] = (tex->pitch << 22) | (tex->offset >> 10);
+		buffer[2] = (texpitch << 22) | (tex->offset >> 10);
 		buffer[3] = 0xffffffff;
 		buffer[4] = 0xffffffff;
 		buffer[5] = (image->y << 16) | image->x;
@@ -1636,30 +1642,110 @@ static int radeon_cp_dispatch_texture( D
 		buffer[7] = dwords;
 		buffer += 8;
 
-		if ( tex_width >= 32 ) {
-			/* Texture image width is larger than the minimum, so we
-			 * can upload it directly.
-			 */
-			if ( DRM_COPY_FROM_USER( buffer, data, 
-						 dwords * sizeof(u32) ) ) {
-				DRM_ERROR( "EFAULT on data, %d dwords\n", 
-					   dwords );
-				return DRM_ERR(EFAULT);
+		
+
+		if (microtile) {
+			/* texture micro tiling in use, minimum texture width is thus 16 bytes.
+			   however, we cannot use blitter directly for texture width < 64 bytes,
+			   since minimum tex pitch is 64 bytes and we need this to match
+			   the texture width, otherwise the blitter will tile it wrong.
+			   Thus, tiling manually in this case. Additionally, need to special
+			   case tex height = 1, since our actual image will have height 2
+			   and we need to ensure we don't read beyond the texture size
+			   from user space. */
+			if (tex->height == 1) {
+				if (tex_width >= 64 || tex_width <= 16) {
+					if (DRM_COPY_FROM_USER(buffer, data,
+							       tex_width * sizeof(u32))) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+				} else if (tex_width == 32) {
+					if (DRM_COPY_FROM_USER(buffer, data, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					if (DRM_COPY_FROM_USER(buffer + 8, data + 16, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+				}
+			} else if (tex_width >= 64 || tex_width == 16) {
+				if (DRM_COPY_FROM_USER(buffer, data,
+						       dwords * sizeof(u32))) {
+					DRM_ERROR("EFAULT on data, %d dwords\n",
+						  dwords);
+					return DRM_ERR(EFAULT);
+				}
+			} else if (tex_width < 16) {
+				for (i = 0; i < tex->height; i++) {
+					if (DRM_COPY_FROM_USER(buffer, data, tex_width)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					buffer += 4;
+					data += tex_width;
+				}
+			} else if (tex_width == 32) {
+				/* TODO: make sure this works when not fitting in one buffer
+				   (i.e. 32bytes x 2048...) */
+				for (i = 0; i < tex->height; i += 2) {
+					if (DRM_COPY_FROM_USER(buffer, data, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					data += 16;
+					if (DRM_COPY_FROM_USER(buffer + 8, data, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					data += 16;
+					if (DRM_COPY_FROM_USER(buffer + 4, data, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					data += 16;
+					if (DRM_COPY_FROM_USER(buffer + 12, data, 16)) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n",
+							  tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					data += 16;
+					buffer += 16;
+				}
 			}
-		} else {
-			/* Texture image width is less than the minimum, so we
-			 * need to pad out each image scanline to the minimum
-			 * width.
-			 */
-			for ( i = 0 ; i < tex->height ; i++ ) {
-				if ( DRM_COPY_FROM_USER( buffer, data, 
-							 tex_width ) ) {
-					DRM_ERROR( "EFAULT on pad, %d bytes\n",
-						   tex_width );
+		}
+		else {
+			if (tex_width >= 32) {
+				/* Texture image width is larger than the minimum, so we
+				 * can upload it directly.
+				 */
+				if (DRM_COPY_FROM_USER(buffer, data,
+						       dwords * sizeof(u32))) {
+					DRM_ERROR("EFAULT on data, %d dwords\n",
+						  dwords);
 					return DRM_ERR(EFAULT);
 				}
-				buffer += 8;
-				data += tex_width;
+			} else {
+				/* Texture image width is less than the minimum, so we
+				 * need to pad out each image scanline to the minimum
+				 * width.
+				 */
+				for (i = 0 ; i < tex->height ; i++) {
+					if (DRM_COPY_FROM_USER(buffer, data, tex_width )) {
+						DRM_ERROR("EFAULT on pad, %d bytes\n", tex_width);
+						return DRM_ERR(EFAULT);
+					}
+					buffer += 8;
+					data += tex_width;
+				}
 			}
 		}
 
@@ -1842,7 +1928,7 @@ static int free_surface(DRMFILE filp, dr
 				dev_priv->surfaces[s->surface_index].refcount--;
 				if (dev_priv->surfaces[s->surface_index].refcount == 0)
 					dev_priv->surfaces[s->surface_index].flags = 0;
-				s->filp = 0;
+				s->filp = NULL;
 				radeon_apply_surface_regs(s->surface_index, dev_priv);
 				return 0;
 			}
@@ -1864,7 +1950,7 @@ static void radeon_surfaces_release(DRMF
 /* ================================================================
  * IOCTL functions
  */
-int radeon_surface_alloc(DRM_IOCTL_ARGS)
+static int radeon_surface_alloc(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1884,7 +1970,7 @@ int radeon_surface_alloc(DRM_IOCTL_ARGS)
 		return 0;
 }
 
-int radeon_surface_free(DRM_IOCTL_ARGS)
+static int radeon_surface_free(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1904,7 +1990,7 @@ int radeon_surface_free(DRM_IOCTL_ARGS)
 		return 0;
 }
 
-int radeon_cp_clear( DRM_IOCTL_ARGS )
+static int radeon_cp_clear( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1961,7 +2047,7 @@ static int radeon_do_init_pageflip( drm_
 /* Called whenever a client dies, from drm_release.
  * NOTE:  Lock isn't necessarily held when this is called!
  */
-int radeon_do_cleanup_pageflip( drm_device_t *dev )
+static int radeon_do_cleanup_pageflip( drm_device_t *dev )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
@@ -1976,7 +2062,7 @@ int radeon_do_cleanup_pageflip( drm_devi
 /* Swapping and flipping are different operations, need different ioctls.
  * They can & should be intermixed to support multiple 3d windows.  
  */
-int radeon_cp_flip( DRM_IOCTL_ARGS )
+static int radeon_cp_flip( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1995,7 +2081,7 @@ int radeon_cp_flip( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_swap( DRM_IOCTL_ARGS )
+static int radeon_cp_swap( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2016,7 +2102,7 @@ int radeon_cp_swap( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_vertex( DRM_IOCTL_ARGS )
+static int radeon_cp_vertex( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2101,7 +2187,7 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_indices( DRM_IOCTL_ARGS )
+static int radeon_cp_indices( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2203,7 +2289,7 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_texture( DRM_IOCTL_ARGS )
+static int radeon_cp_texture( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2234,7 +2320,7 @@ int radeon_cp_texture( DRM_IOCTL_ARGS )
 	return ret;
 }
 
-int radeon_cp_stipple( DRM_IOCTL_ARGS )
+static int radeon_cp_stipple( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2257,7 +2343,7 @@ int radeon_cp_stipple( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_indirect( DRM_IOCTL_ARGS )
+static int radeon_cp_indirect( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2332,7 +2418,7 @@ int radeon_cp_indirect( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_vertex2( DRM_IOCTL_ARGS )
+static int radeon_cp_vertex2( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2661,7 +2747,7 @@ static int radeon_emit_wait( drm_device_
 	return 0;
 }
 
-int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+static int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2702,8 +2788,10 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 		kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
 		if (kbuf == NULL)
 			return DRM_ERR(ENOMEM);
-		if (DRM_COPY_FROM_USER(kbuf, cmdbuf.buf, cmdbuf.bufsz))
+		if (DRM_COPY_FROM_USER(kbuf, cmdbuf.buf, cmdbuf.bufsz)) {
+			drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
 			return DRM_ERR(EFAULT);
+		}
 		cmdbuf.buf = kbuf;
 	}
 
@@ -2813,7 +2901,7 @@ err:
 
 
 
-int radeon_cp_getparam( DRM_IOCTL_ARGS )
+static int radeon_cp_getparam( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2887,7 +2975,7 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
+static int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_file_t *filp_priv;
@@ -2980,3 +3068,35 @@ void radeon_driver_free_filp_priv(drm_de
 	 
 	 drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
 }
+
+drm_ioctl_desc_t radeon_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_RADEON_CP_INIT)]    = { radeon_cp_init,      1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_CP_START)]   = { radeon_cp_start,     1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_CP_STOP)]    = { radeon_cp_stop,      1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_CP_RESET)]   = { radeon_cp_reset,     1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)]    = { radeon_cp_idle,      1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)]  = { radeon_cp_resume,    1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_RESET)]      = { radeon_engine_reset, 1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = { radeon_fullscreen,   1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_SWAP)]       = { radeon_cp_swap,      1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_CLEAR)]      = { radeon_cp_clear,     1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_VERTEX)]     = { radeon_cp_vertex,    1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_INDICES)]    = { radeon_cp_indices,   1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_TEXTURE)]    = { radeon_cp_texture,   1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_STIPPLE)]    = { radeon_cp_stipple,   1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_INDIRECT)]   = { radeon_cp_indirect,  1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_VERTEX2)]    = { radeon_cp_vertex2,   1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_CMDBUF)]     = { radeon_cp_cmdbuf,    1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_GETPARAM)]   = { radeon_cp_getparam,  1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_FLIP)]       = { radeon_cp_flip,      1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_ALLOC)]      = { radeon_mem_alloc,    1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_FREE)]       = { radeon_mem_free,     1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)]  = { radeon_mem_init_heap,1, 1 },
+	[DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)]   = { radeon_irq_emit,     1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)]   = { radeon_irq_wait,     1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_SETPARAM)]   = { radeon_cp_setparam,  1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = { radeon_surface_alloc,1, 0 },
+	[DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)]  = { radeon_surface_free, 1, 0 }
+};
+
+int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -40,7 +40,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -46,13 +46,6 @@ typedef struct drm_sis_private {
 	memHeap_t *FBHeap;
 } drm_sis_private_t;
 
-extern int sis_fb_alloc( DRM_IOCTL_ARGS );
-extern int sis_fb_free( DRM_IOCTL_ARGS );
-extern int sis_ioctl_agp_init( DRM_IOCTL_ARGS );
-extern int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS );
-extern int sis_ioctl_agp_free( DRM_IOCTL_ARGS );
-extern int sis_fb_init( DRM_IOCTL_ARGS );
-
 extern int sis_init_context(drm_device_t *dev, int context);
 extern int sis_final_context(drm_device_t *dev, int context);
 
diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c
--- a/drivers/char/drm/sis_ds.c
+++ b/drivers/char/drm/sis_ds.c
@@ -194,32 +194,6 @@ int mmBlockInHeap(memHeap_t *heap, PMemB
 		return 0;
 }
 
-/* Kludgey workaround for existing i810 server.  Remove soon.
- */
-memHeap_t *mmAddRange( memHeap_t *heap,
-		       int ofs,
-		       int size )
-{
-	PMemBlock blocks;
-	blocks = (TMemBlock *)drm_calloc(2, sizeof(TMemBlock), DRM_MEM_DRIVER);
-	if (blocks != NULL) {
-		blocks[0].size = size;
-		blocks[0].free = 1;
-		blocks[0].ofs = ofs;
-		blocks[0].next = &blocks[1];
-
-		/* Discontinuity - stops JoinBlock from trying to join
-		 * non-adjacent ranges.
-		 */
-		blocks[1].size = 0;
-		blocks[1].free = 0;
-		blocks[1].ofs = ofs+size;
-		blocks[1].next = (PMemBlock)heap;
-		return (memHeap_t *)blocks;
-	} else
-		return heap;
-}
-
 static TMemBlock* SliceBlock(TMemBlock *p, 
 			     int startofs, int size, 
 			     int reserved, int alignment)
@@ -325,61 +299,3 @@ int mmFreeMem(PMemBlock b)
 	return 0;
 }
 
-int mmReserveMem(memHeap_t *heap, int offset,int size)
-{
-	int endofs;
-	TMemBlock *p;
-
-	if (heap == NULL || size <= 0)
-		return -1;
-
-	endofs = offset + size;
-	p = (TMemBlock *)heap;
-	while (p && p->ofs <= offset) {
-		if (ISFREE(p) && endofs <= (p->ofs+p->size)) {
-			SliceBlock(p,offset,size,1,1);
-			return 0;
-		}
-		p = p->next;
-	}
-	return -1;
-}
-
-int mmFreeReserved(memHeap_t *heap, int offset)
-{
-	TMemBlock *p,*prev;
-
-	if (heap == NULL)
-		return -1;
-
-	p = (TMemBlock *)heap;
-	prev = NULL;
-	while (p != NULL && p->ofs != offset) {
-		prev = p;
-		p = p->next;
-	}
-	if (p == NULL || !p->reserved)
-		return -1;
-
-	p->free = 1;
-	p->reserved = 0;
-	Join2Blocks(p);
-	if (prev != NULL)
-		Join2Blocks(prev);
-	return 0;
-}
-
-void mmDestroy(memHeap_t *heap)
-{
-	TMemBlock *p,*q;
-
-	if (heap == NULL)
-		return;
-
-	p = (TMemBlock *)heap;
-	while (p != NULL) {
-		q = p->next;
-		drm_free(p, sizeof(TMemBlock), DRM_MEM_DRIVER);
-		p = q;
-	}
-}
diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h
--- a/drivers/char/drm/sis_ds.h
+++ b/drivers/char/drm/sis_ds.h
@@ -115,10 +115,6 @@ static __inline__ void mmMarkReserved(PM
  */
 memHeap_t *mmInit( int ofs, int size );
 
-memHeap_t *mmAddRange( memHeap_t *heap,
-		       int ofs,
-		       int size );
-
 /*
  * Allocate 'size' bytes with 2^align2 bytes alignment,
  * restrict the search to free memory after 'startSearch'
@@ -143,21 +139,6 @@ int mmBlockInHeap( PMemBlock heap, PMemB
  */
 int mmFreeMem( PMemBlock b );
 
-/*
- * Reserve 'size' bytes block start at offset
- * This is used to prevent allocation of memory already used
- * by the X server for the front buffer, pixmaps, and cursor
- * input: size, offset
- * output: 0 if OK, -1 if error
- */
-int mmReserveMem( memHeap_t *heap, int offset,int size );
-int mmFreeReserved( memHeap_t *heap, int offset );
-
-/*
- * destroy MM
- */
-void mmDestroy( memHeap_t *mmInit );
-
 /* For debuging purpose. */
 void mmDumpMemInfo( memHeap_t *mmInit );
 
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -36,17 +36,6 @@
 #include <video/sisfb.h>
 #endif
 
-drm_ioctl_desc_t sis_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)]  = { sis_fb_alloc,        1, 0 },
-	[DRM_IOCTL_NR(DRM_SIS_FB_FREE)]   = { sis_fb_free,         1, 0 },
-	[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)]  = { sis_ioctl_agp_init,  1, 1 },
-	[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 },
-	[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)]  = { sis_ioctl_agp_free,  1, 0 },
-	[DRM_IOCTL_NR(DRM_SIS_FB_INIT)]   = { sis_fb_init,         1, 1 }
-};
-
-int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
-
 #define MAX_CONTEXT 100
 #define VIDEO_TYPE 0 
 #define AGP_TYPE 1
@@ -91,12 +80,12 @@ static int del_alloc_set(int context, in
 /* fb management via fb device */ 
 #if defined(__linux__) && defined(CONFIG_FB_SIS)
 
-int sis_fb_init( DRM_IOCTL_ARGS )
+static int sis_fb_init( DRM_IOCTL_ARGS )
 {
 	return 0;
 }
 
-int sis_fb_alloc( DRM_IOCTL_ARGS )
+static int sis_fb_alloc( DRM_IOCTL_ARGS )
 {
 	drm_sis_mem_t fb;
 	struct sis_memreq req;
@@ -129,7 +118,7 @@ int sis_fb_alloc( DRM_IOCTL_ARGS )
 	return retval;
 }
 
-int sis_fb_free( DRM_IOCTL_ARGS )
+static int sis_fb_free( DRM_IOCTL_ARGS )
 {
 	drm_sis_mem_t fb;
 	int retval = 0;
@@ -160,7 +149,7 @@ int sis_fb_free( DRM_IOCTL_ARGS )
  *    X driver/sisfb                                  HW-   Command-
  *  framebuffer memory           DRI heap           Cursor   queue
  */
-int sis_fb_init( DRM_IOCTL_ARGS )
+static int sis_fb_init( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -186,7 +175,7 @@ int sis_fb_init( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int sis_fb_alloc( DRM_IOCTL_ARGS )
+static int sis_fb_alloc( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -223,7 +212,7 @@ int sis_fb_alloc( DRM_IOCTL_ARGS )
 	return retval;
 }
 
-int sis_fb_free( DRM_IOCTL_ARGS )
+static int sis_fb_free( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -250,7 +239,7 @@ int sis_fb_free( DRM_IOCTL_ARGS )
 
 /* agp memory management */ 
 
-int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
+static int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -276,7 +265,7 @@ int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
 	return 0;
 }
 
-int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS )
+static int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -313,7 +302,7 @@ int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS 
 	return retval;
 }
 
-int sis_ioctl_agp_free( DRM_IOCTL_ARGS )
+static int sis_ioctl_agp_free( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
@@ -414,3 +403,15 @@ int sis_final_context(struct drm_device 
 	
 	return 1;
 }
+
+drm_ioctl_desc_t sis_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)]  = { sis_fb_alloc,        1, 0 },
+	[DRM_IOCTL_NR(DRM_SIS_FB_FREE)]   = { sis_fb_free,         1, 0 },
+	[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)]  = { sis_ioctl_agp_init,  1, 1 },
+	[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 },
+	[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)]  = { sis_ioctl_agp_free,  1, 0 },
+	[DRM_IOCTL_NR(DRM_SIS_FB_INIT)]   = { sis_fb_init,         1, 1 }
+};
+
+int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
+
diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c
--- a/drivers/char/drm/tdfx_drv.c
+++ b/drivers/char/drm/tdfx_drv.c
@@ -44,7 +44,7 @@ static int postinit( struct drm_device *
 		DRIVER_MINOR,
 		DRIVER_PATCHLEVEL,
 		DRIVER_DATE,
-		dev->minor,
+		dev->primary.minor,
 		pci_pretty_name(dev->pdev)
 		);
 	return 0;
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -52,7 +52,7 @@
 #define KERNEL
 #include <linux/types.h>
 #include <linux/fs.h>
-#include <linux/mm.h>		/* for verify_area */
+#include <linux/mm.h>
 #include <linux/errno.h>	/* for -EBUSY */
 #include <linux/ioport.h>	/* for request_region */
 #include <linux/delay.h>	/* for loops_per_jiffy */
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -129,8 +129,6 @@ static struct tty_driver *esp_driver;
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 
-#define _INLINE_ inline
-  
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
  tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s)
@@ -211,15 +209,14 @@ static void rs_stop(struct tty_struct *t
 
 	if (serial_paranoia_check(info, tty->name, "rs_stop"))
 		return;
-	
-	save_flags(flags); cli();
+
+	spin_lock_irqsave(&info->lock, flags);
 	if (info->IER & UART_IER_THRI) {
 		info->IER &= ~UART_IER_THRI;
 		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 		serial_out(info, UART_ESI_CMD2, info->IER);
 	}
-
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_start(struct tty_struct *tty)
@@ -230,13 +227,13 @@ static void rs_start(struct tty_struct *
 	if (serial_paranoia_check(info, tty->name, "rs_start"))
 		return;
 	
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
 		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 		serial_out(info, UART_ESI_CMD2, info->IER);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -264,34 +261,41 @@ static void rs_start(struct tty_struct *
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static _INLINE_ void rs_sched_event(struct esp_struct *info,
+static inline void rs_sched_event(struct esp_struct *info,
 				  int event)
 {
 	info->event |= 1 << event;
 	schedule_work(&info->tqueue);
 }
 
-static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void)
+static DEFINE_SPINLOCK(pio_lock);
+
+static inline struct esp_pio_buffer *get_pio_buffer(void)
 {
 	struct esp_pio_buffer *buf;
+	unsigned long flags;
 
+	spin_lock_irqsave(&pio_lock, flags);
 	if (free_pio_buf) {
 		buf = free_pio_buf;
 		free_pio_buf = buf->next;
 	} else {
 		buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC);
 	}
-
+	spin_unlock_irqrestore(&pio_lock, flags);
 	return buf;
 }
 
-static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf)
+static inline void release_pio_buffer(struct esp_pio_buffer *buf)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&pio_lock, flags);
 	buf->next = free_pio_buf;
 	free_pio_buf = buf;
+	spin_unlock_irqrestore(&pio_lock, flags);
 }
 
-static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
+static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
 {
 	struct tty_struct *tty = info->tty;
 	int i;
@@ -311,8 +315,6 @@ static _INLINE_ void receive_chars_pio(s
 		return;
 	}
 
-	sti();
-	
 	status_mask = (info->read_status_mask >> 2) & 0x07;
 		
 	for (i = 0; i < num_bytes - 1; i += 2) {
@@ -329,8 +331,6 @@ static _INLINE_ void receive_chars_pio(s
 			(serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
 	}
 
-	cli();
-
 	/* make sure everything is still ok since interrupts were enabled */
 	tty = info->tty;
 
@@ -371,7 +371,7 @@ static _INLINE_ void receive_chars_pio(s
 	release_pio_buffer(err_buf);
 }
 
-static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
+static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
 {
 	unsigned long flags;
 	info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
@@ -390,7 +390,7 @@ static _INLINE_ void receive_chars_dma(s
         serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
 }
 
-static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
+static inline void receive_chars_dma_done(struct esp_struct *info,
 					    int status)
 {
 	struct tty_struct *tty = info->tty;
@@ -450,7 +450,9 @@ static _INLINE_ void receive_chars_dma_d
 		dma_bytes = 0;
 }
 
-static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
+/* Caller must hold info->lock */
+
+static inline void transmit_chars_pio(struct esp_struct *info,
 					int space_avail)
 {
 	int i;
@@ -478,8 +480,6 @@ static _INLINE_ void transmit_chars_pio(
 		info->xmit_tail = (info->xmit_tail + space_avail) &
 			(ESP_XMIT_SIZE - 1);
 
-		sti();
-
 		for (i = 0; i < space_avail - 1; i += 2) {
 			outw(*((unsigned short *)(pio_buf->data + i)),
 			     info->port + UART_ESI_TX);
@@ -489,8 +489,6 @@ static _INLINE_ void transmit_chars_pio(
 			serial_out(info, UART_ESI_TX,
 				   pio_buf->data[space_avail - 1]);
 
-		cli();
-
 		if (info->xmit_cnt) {
 			serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
 			serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
@@ -520,7 +518,8 @@ static _INLINE_ void transmit_chars_pio(
 	release_pio_buffer(pio_buf);
 }
 
-static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
+/* Caller must hold info->lock */
+static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
 {
 	unsigned long flags;
 	
@@ -567,7 +566,7 @@ static _INLINE_ void transmit_chars_dma(
         serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
 }
 
-static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
+static inline void transmit_chars_dma_done(struct esp_struct *info)
 {
 	int num_bytes;
 	unsigned long flags;
@@ -601,7 +600,7 @@ static _INLINE_ void transmit_chars_dma_
 	}
 }
 
-static _INLINE_ void check_modem_status(struct esp_struct *info)
+static inline void check_modem_status(struct esp_struct *info)
 {
 	int	status;
 	
@@ -654,10 +653,10 @@ static irqreturn_t rs_interrupt_single(i
 	err_status = 0;
 	scratch = serial_in(info, UART_ESI_SID);
 
-	cli();
+	spin_lock(&info->lock);
 	
 	if (!info->tty) {
-		sti();
+		spin_unlock(&info->lock);
 		return IRQ_NONE;
 	}
 
@@ -740,7 +739,7 @@ static irqreturn_t rs_interrupt_single(i
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
-	sti();
+	spin_unlock(&info->lock);
 	return IRQ_HANDLED;
 }
 
@@ -789,10 +788,12 @@ static void do_serial_hangup(void *priva
  * figure out the appropriate timeout for an interrupt chain, routines
  * to initialize and startup a serial port, and routines to shutdown a
  * serial port.  Useful stuff like that.
+ *
+ * Caller should hold lock
  * ---------------------------------------------------------------
  */
 
-static _INLINE_ void esp_basic_init(struct esp_struct * info)
+static inline void esp_basic_init(struct esp_struct * info)
 {
 	/* put ESPC in enhanced mode */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
@@ -859,13 +860,13 @@ static int startup(struct esp_struct * i
 	int	retval=0;
         unsigned int num_chars;
 
-	save_flags(flags); cli();
+        spin_lock_irqsave(&info->lock, flags);
 
 	if (info->flags & ASYNC_INITIALIZED)
 		goto out;
 
 	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC);
 		retval = -ENOMEM;
 		if (!info->xmit_buf)
 			goto out;
@@ -901,6 +902,8 @@ static int startup(struct esp_struct * i
 	if (info->stat_flags & ESP_STAT_NEVER_DMA)
 		info->stat_flags |= ESP_STAT_USE_PIO;
 
+	spin_unlock_irqrestore(&info->lock, flags);
+
 	/*
 	 * Allocate the IRQ
 	 */
@@ -915,7 +918,7 @@ static int startup(struct esp_struct * i
 					&info->tty->flags);
 			retval = 0;
 		}
-		goto out;
+		goto out_unlocked;
 	}
 
 	if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
@@ -935,6 +938,8 @@ static int startup(struct esp_struct * i
 	}
 
 	info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+
+	spin_lock_irqsave(&info->lock, flags);
 	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 	serial_out(info, UART_ESI_CMD2, UART_MCR);
 	serial_out(info, UART_ESI_CMD2, info->MCR);
@@ -951,6 +956,7 @@ static int startup(struct esp_struct * i
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	spin_unlock_irqrestore(&info->lock, flags);
 
 	/*
 	 * Set up the tty->alt_speed kludge
@@ -970,10 +976,12 @@ static int startup(struct esp_struct * i
 	 * set the speed of the serial port
 	 */
 	change_speed(info);
-
 	info->flags |= ASYNC_INITIALIZED;
-	retval = 0;
-out:	restore_flags(flags);
+	return 0;
+
+out:
+	spin_unlock_irqrestore(&info->lock, flags);
+out_unlocked:
 	return retval;
 }
 
@@ -993,8 +1001,7 @@ static void shutdown(struct esp_struct *
 	       info->irq);
 #endif
 	
-	save_flags(flags); cli(); /* Disable interrupts */
-
+	spin_lock_irqsave(&info->lock, flags);
 	/*
 	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
 	 * here so the queue might never be waken up
@@ -1003,7 +1010,7 @@ static void shutdown(struct esp_struct *
 	wake_up_interruptible(&info->break_wait);
 
 	/* stop a DMA transfer on the port being closed */
-	   
+	/* DMA lock is higher priority always */
 	if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
 		f=claim_dma_lock();
 		disable_dma(dma);
@@ -1058,7 +1065,7 @@ static void shutdown(struct esp_struct *
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
 	
 	info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -1172,7 +1179,7 @@ static void change_speed(struct esp_stru
 	if (I_IXOFF(info->tty))
 		flow1 |= 0x81;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	/* set baud */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD);
 	serial_out(info, UART_ESI_CMD2, quot >> 8);
@@ -1219,7 +1226,7 @@ static void change_speed(struct esp_stru
 	serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);
 	serial_out(info, UART_ESI_CMD2, info->config.flow_on);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
@@ -1233,16 +1240,13 @@ static void rs_put_char(struct tty_struc
 	if (!tty || !info->xmit_buf)
 		return;
 
-	save_flags(flags); cli();
-	if (info->xmit_cnt >= ESP_XMIT_SIZE - 1) {
-		restore_flags(flags);
-		return;
+	spin_lock_irqsave(&info->lock, flags);
+	if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
+		info->xmit_buf[info->xmit_head++] = ch;
+		info->xmit_head &= ESP_XMIT_SIZE-1;
+		info->xmit_cnt++;
 	}
-
-	info->xmit_buf[info->xmit_head++] = ch;
-	info->xmit_head &= ESP_XMIT_SIZE-1;
-	info->xmit_cnt++;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_flush_chars(struct tty_struct *tty)
@@ -1253,16 +1257,18 @@ static void rs_flush_chars(struct tty_st
 	if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
 		return;
 
+	spin_lock_irqsave(&info->lock, flags);
+
 	if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf)
-		return;
+		goto out;
 
-	save_flags(flags); cli();
 	if (!(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
 		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 		serial_out(info, UART_ESI_CMD2, info->IER);
 	}
-	restore_flags(flags);
+out:
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static int rs_write(struct tty_struct * tty,
@@ -1305,7 +1311,7 @@ static int rs_write(struct tty_struct * 
 		ret += c;
 	}
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 
 	if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
@@ -1313,7 +1319,7 @@ static int rs_write(struct tty_struct * 
 		serial_out(info, UART_ESI_CMD2, info->IER);
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 	return ret;
 }
 
@@ -1321,12 +1327,17 @@ static int rs_write_room(struct tty_stru
 {
 	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
 	int	ret;
+	unsigned long flags;
 				
 	if (serial_paranoia_check(info, tty->name, "rs_write_room"))
 		return 0;
+
+	spin_lock_irqsave(&info->lock, flags);
+
 	ret = ESP_XMIT_SIZE - info->xmit_cnt - 1;
 	if (ret < 0)
 		ret = 0;
+	spin_unlock_irqrestore(&info->lock, flags);
 	return ret;
 }
 
@@ -1342,12 +1353,13 @@ static int rs_chars_in_buffer(struct tty
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+	unsigned long flags;
 				
 	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
 		return;
-	cli();
+	spin_lock_irqsave(&info->lock, flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	spin_unlock_irqrestore(&info->lock, flags);
 	tty_wakeup(tty);
 }
 
@@ -1362,6 +1374,7 @@ static void rs_flush_buffer(struct tty_s
 static void rs_throttle(struct tty_struct * tty)
 {
 	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
 	
@@ -1371,19 +1384,20 @@ static void rs_throttle(struct tty_struc
 
 	if (serial_paranoia_check(info, tty->name, "rs_throttle"))
 		return;
-	
-	cli();
+
+	spin_lock_irqsave(&info->lock, flags);
 	info->IER &= ~UART_IER_RDI;
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, info->IER);
 	serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
 	serial_out(info, UART_ESI_CMD2, 0x00);
-	sti();
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
 	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
 	
@@ -1394,13 +1408,13 @@ static void rs_unthrottle(struct tty_str
 	if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
 		return;
 	
-	cli();
+	spin_lock_irqsave(&info->lock, flags);
 	info->IER |= UART_IER_RDI;
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, info->IER);
 	serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
 	serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
-	sti();
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -1573,6 +1587,7 @@ static int set_esp_config(struct esp_str
 	unsigned int change_dma;
 	int retval = 0;
 	struct esp_struct *current_async;
+	unsigned long flags;
 
 	/* Perhaps a non-sysadmin user should be able to do some of these */
 	/* operations.  I haven't decided yet. */
@@ -1628,12 +1643,14 @@ static int set_esp_config(struct esp_str
 			
                         /* all ports must use the same DMA channel */
 
+			spin_lock_irqsave(&info->lock, flags);
 			current_async = ports;
 
 			while (current_async) {
 				esp_basic_init(current_async);
 				current_async = current_async->next_port;
 			}
+			spin_unlock_irqrestore(&info->lock, flags);
 		} else {
 			/* DMA mode to PIO mode only */
 			
@@ -1641,8 +1658,10 @@ static int set_esp_config(struct esp_str
 				return -EBUSY;
 
 			shutdown(info);
+			spin_lock_irqsave(&info->lock, flags);
 			info->stat_flags |= ESP_STAT_NEVER_DMA;
 			esp_basic_init(info);
+			spin_unlock_irqrestore(&info->lock, flags);
 		}
 	}
 
@@ -1654,13 +1673,14 @@ static int set_esp_config(struct esp_str
 
 		info->config.flow_off = new_config.flow_off;
 		info->config.flow_on = new_config.flow_on;
-		save_flags(flags); cli();
+
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
 		serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8);
 		serial_out(info, UART_ESI_CMD2, new_config.flow_off);
 		serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8);
 		serial_out(info, UART_ESI_CMD2, new_config.flow_on);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&info->lock, flags);
 	}
 
 	if ((new_config.rx_trigger != info->config.rx_trigger) ||
@@ -1669,7 +1689,7 @@ static int set_esp_config(struct esp_str
 
 		info->config.rx_trigger = new_config.rx_trigger;
 		info->config.tx_trigger = new_config.tx_trigger;
-		save_flags(flags); cli();
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
 		serial_out(info, UART_ESI_CMD2,
 			   new_config.rx_trigger >> 8);
@@ -1677,14 +1697,14 @@ static int set_esp_config(struct esp_str
 		serial_out(info, UART_ESI_CMD2,
 			   new_config.tx_trigger >> 8);
 		serial_out(info, UART_ESI_CMD2, new_config.tx_trigger);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&info->lock, flags);
 	}
 
 	if (new_config.rx_timeout != info->config.rx_timeout) {
 		unsigned long flags;
 
 		info->config.rx_timeout = new_config.rx_timeout;
-		save_flags(flags); cli();
+		spin_lock_irqsave(&info->lock, flags);
 
 		if (info->IER & UART_IER_RDI) {
 			serial_out(info, UART_ESI_CMD1,
@@ -1693,7 +1713,7 @@ static int set_esp_config(struct esp_str
 				   new_config.rx_timeout);
 		}
 
-		restore_flags(flags);
+		spin_unlock_irqrestore(&info->lock, flags);
 	}
 
 	if (!(info->flags & ASYNC_INITIALIZED))
@@ -1716,11 +1736,12 @@ static int get_lsr_info(struct esp_struc
 {
 	unsigned char status;
 	unsigned int result;
+	unsigned long flags;
 
-	cli();
+	spin_lock_irqsave(&info->lock, flags);
 	serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
 	status = serial_in(info, UART_ESI_STAT1);
-	sti();
+	spin_unlock_irqrestore(&info->lock, flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 	return put_user(result,value);
 }
@@ -1730,6 +1751,7 @@ static int esp_tiocmget(struct tty_struc
 {
 	struct esp_struct * info = (struct esp_struct *)tty->driver_data;
 	unsigned char control, status;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
 		return -ENODEV;
@@ -1737,10 +1759,12 @@ static int esp_tiocmget(struct tty_struc
 		return -EIO;
 
 	control = info->MCR;
-	cli();
+
+	spin_lock_irqsave(&info->lock, flags);
 	serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
 	status = serial_in(info, UART_ESI_STAT2);
-	sti();
+	spin_unlock_irqrestore(&info->lock, flags);
+
 	return    ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1753,13 +1777,14 @@ static int esp_tiocmset(struct tty_struc
 			unsigned int set, unsigned int clear)
 {
 	struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
 		return -ENODEV;
 	if (tty->flags & (1 << TTY_IO_ERROR))
 		return -EIO;
 
-	cli();
+	spin_lock_irqsave(&info->lock, flags);
 
 	if (set & TIOCM_RTS)
 		info->MCR |= UART_MCR_RTS;
@@ -1774,7 +1799,8 @@ static int esp_tiocmset(struct tty_struc
 	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 	serial_out(info, UART_ESI_CMD2, UART_MCR);
 	serial_out(info, UART_ESI_CMD2, info->MCR);
-	sti();
+
+	spin_unlock_irqrestore(&info->lock, flags);
 	return 0;
 }
 
@@ -1789,17 +1815,20 @@ static void esp_break(struct tty_struct 
 	if (serial_paranoia_check(info, tty->name, "esp_break"))
 		return;
 
-	save_flags(flags); cli();
 	if (break_state == -1) {
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
 		serial_out(info, UART_ESI_CMD2, 0x01);
+		spin_unlock_irqrestore(&info->lock, flags);
 
+		/* FIXME - new style wait needed here */
 		interruptible_sleep_on(&info->break_wait);
 	} else {
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
 		serial_out(info, UART_ESI_CMD2, 0x00);
+		spin_unlock_irqrestore(&info->lock, flags);
 	}
-	restore_flags(flags);
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1809,6 +1838,7 @@ static int rs_ioctl(struct tty_struct *t
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct __user *p_cuser;	/* user space */
 	void __user *argp = (void __user *)arg;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
 		return -ENODEV;
@@ -1849,17 +1879,18 @@ static int rs_ioctl(struct tty_struct *t
 		 * Caller should use TIOCGICOUNT to see which one it was
 		 */
 		 case TIOCMIWAIT:
-			cli();
+			spin_lock_irqsave(&info->lock, flags);
 			cprev = info->icount;	/* note the counters on entry */
-			sti();
+			spin_unlock_irqrestore(&info->lock, flags);
 			while (1) {
+				/* FIXME: convert to new style wakeup */
 				interruptible_sleep_on(&info->delta_msr_wait);
 				/* see if a signal did it */
 				if (signal_pending(current))
 					return -ERESTARTSYS;
-				cli();
+				spin_lock_irqsave(&info->lock, flags);
 				cnow = info->icount;	/* atomic copy */
-				sti();
+				spin_unlock_irqrestore(&info->lock, flags);
 				if (cnow.rng == cprev.rng &&
 				    cnow.dsr == cprev.dsr && 
 				    cnow.dcd == cprev.dcd &&
@@ -1886,9 +1917,9 @@ static int rs_ioctl(struct tty_struct *t
 		 *     RI where only 0->1 is counted.
 		 */
 		case TIOCGICOUNT:
-			cli();
+			spin_lock_irqsave(&info->lock, flags);
 			cnow = info->icount;
-			sti();
+			spin_unlock_irqrestore(&info->lock, flags);
 			p_cuser = argp;
 			if (put_user(cnow.cts, &p_cuser->cts) ||
 			    put_user(cnow.dsr, &p_cuser->dsr) ||
@@ -1911,53 +1942,42 @@ static int rs_ioctl(struct tty_struct *t
 static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (   (tty->termios->c_cflag == old_termios->c_cflag)
 	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
 		== RELEVANT_IFLAG(old_termios->c_iflag)))
-	  return;
+		return;
 
 	change_speed(info);
 
+	spin_lock_irqsave(&info->lock, flags);
+
 	/* Handle transition to B0 status */
 	if ((old_termios->c_cflag & CBAUD) &&
 		!(tty->termios->c_cflag & CBAUD)) {
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		cli();
 		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 		serial_out(info, UART_ESI_CMD2, UART_MCR);
 		serial_out(info, UART_ESI_CMD2, info->MCR);
-		sti();
 	}
 
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
 		(tty->termios->c_cflag & CBAUD)) {
 		info->MCR |= (UART_MCR_DTR | UART_MCR_RTS);
-		cli();
 		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 		serial_out(info, UART_ESI_CMD2, UART_MCR);
 		serial_out(info, UART_ESI_CMD2, info->MCR);
-		sti();
 	}
 
+	spin_unlock_irqrestore(&info->lock, flags);
+
 	/* Handle turning of CRTSCTS */
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
 		rs_start(tty);
 	}
-
-#if 0
-	/*
-	 * No need to wake up processes in open wait, since they
-	 * sample the CLOCAL flag once, and don't recheck it.
-	 * XXX  It's not clear whether the current behavior is correct
-	 * or not.  Hence, this may change.....
-	 */
-	if (!(old_termios->c_cflag & CLOCAL) &&
-	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&info->open_wait);
-#endif
 }
 
 /*
@@ -1978,7 +1998,7 @@ static void rs_close(struct tty_struct *
 	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
 		return;
 	
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	
 	if (tty_hung_up_p(filp)) {
 		DBG_CNT("before DEC-hung");
@@ -2010,6 +2030,8 @@ static void rs_close(struct tty_struct *
 		goto out;
 	}
 	info->flags |= ASYNC_CLOSING;
+
+	spin_unlock_irqrestore(&info->lock, flags);
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -2027,6 +2049,8 @@ static void rs_close(struct tty_struct *
 	info->IER &= ~UART_IER_RDI;
 	info->read_status_mask &= ~UART_LSR_DR;
 	if (info->flags & ASYNC_INITIALIZED) {
+
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 		serial_out(info, UART_ESI_CMD2, info->IER);
 
@@ -2034,6 +2058,8 @@ static void rs_close(struct tty_struct *
 		serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
 		serial_out(info, UART_ESI_CMD2, 0x00);
 
+		spin_unlock_irqrestore(&info->lock, flags);
+
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -2057,8 +2083,10 @@ static void rs_close(struct tty_struct *
 	}
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	return;
+
 out:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -2076,12 +2104,14 @@ static void rs_wait_until_sent(struct tt
 	if (!char_time)
 		char_time = 1;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
 	serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
 
 	while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
 		(serial_in(info, UART_ESI_STAT2) != 0xff)) {
+
+		spin_unlock_irqrestore(&info->lock, flags);
 		msleep_interruptible(jiffies_to_msecs(char_time));
 
 		if (signal_pending(current))
@@ -2090,11 +2120,11 @@ static void rs_wait_until_sent(struct tt
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 
+		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
 		serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
 	}
-	
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 	set_current_state(TASK_RUNNING);
 }
 
@@ -2174,15 +2204,11 @@ static int block_til_ready(struct tty_st
 	printk("block_til_ready before block: ttys%d, count = %d\n",
 	       info->line, info->count);
 #endif
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp)) 
 		info->count--;
-	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
-		save_flags(flags);
-		cli();
 		if ((tty->termios->c_cflag & CBAUD)) {
 			unsigned int scratch;
 
@@ -2194,7 +2220,6 @@ static int block_til_ready(struct tty_st
 			serial_out(info, UART_ESI_CMD2,
 				scratch | UART_MCR_DTR | UART_MCR_RTS);
 		}
-		restore_flags(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
 		    !(info->flags & ASYNC_INITIALIZED)) {
@@ -2224,13 +2249,16 @@ static int block_til_ready(struct tty_st
 		printk("block_til_ready blocking: ttys%d, count = %d\n",
 		       info->line, info->count);
 #endif
+		spin_unlock_irqrestore(&info->lock, flags);
 		schedule();
+		spin_lock_irqsave(&info->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	if (!tty_hung_up_p(filp))
 		info->count++;
 	info->blocked_open--;
+	spin_unlock_irqrestore(&info->lock, flags);
 #ifdef SERIAL_DEBUG_OPEN
 	printk("block_til_ready after blocking: ttys%d, count = %d\n",
 	       info->line, info->count);
@@ -2251,6 +2279,7 @@ static int esp_open(struct tty_struct *t
 {
 	struct esp_struct	*info;
 	int 			retval, line;
+	unsigned long		flags;
 
 	line = tty->index;
 	if ((line < 0) || (line >= NR_PORTS))
@@ -2271,6 +2300,7 @@ static int esp_open(struct tty_struct *t
 #ifdef SERIAL_DEBUG_OPEN
 	printk("esp_open %s, count = %d\n", tty->name, info->count);
 #endif
+	spin_lock_irqsave(&info->lock, flags);
 	info->count++;
 	tty->driver_data = info;
 	info->tty = tty;
@@ -2317,7 +2347,7 @@ static int esp_open(struct tty_struct *t
  * driver.
  */
  
-static _INLINE_ void show_serial_version(void)
+static inline void show_serial_version(void)
 {
  	printk(KERN_INFO "%s version %s (DMA %u)\n",
 		serial_name, serial_version, dma);
@@ -2327,7 +2357,7 @@ static _INLINE_ void show_serial_version
  * This routine is called by espserial_init() to initialize a specific serial
  * port.
  */
-static _INLINE_ int autoconfig(struct esp_struct * info)
+static inline int autoconfig(struct esp_struct * info)
 {
 	int port_detected = 0;
 	unsigned long flags;
@@ -2335,8 +2365,7 @@ static _INLINE_ int autoconfig(struct es
 	if (!request_region(info->port, REGION_SIZE, "esp serial"))
 		return -EIO;
 
-	save_flags(flags); cli();
-	
+	spin_lock_irqsave(&info->lock, flags);
 	/*
 	 * Check for ESP card
 	 */
@@ -2372,7 +2401,7 @@ static _INLINE_ int autoconfig(struct es
 	if (!port_detected)
 		release_region(info->port, REGION_SIZE);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 	return (port_detected);
 }
 
@@ -2513,6 +2542,7 @@ static int __init espserial_init(void)
 		init_waitqueue_head(&info->close_wait);
 		init_waitqueue_head(&info->delta_msr_wait);
 		init_waitqueue_head(&info->break_wait);
+		spin_lock_init(&info->lock);
 		ports = info;
 		printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
 			info->line, info->port, info->irq);
@@ -2563,18 +2593,14 @@ static int __init espserial_init(void)
 
 static void __exit espserial_exit(void) 
 {
-	unsigned long flags;
 	int e1;
 	struct esp_struct *temp_async;
 	struct esp_pio_buffer *pio_buf;
 
 	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-	save_flags(flags);
-	cli();
 	if ((e1 = tty_unregister_driver(esp_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       e1);
-	restore_flags(flags);
 	put_tty_driver(esp_driver);
 
 	while (ports) {
diff --git a/drivers/char/fep.h b/drivers/char/fep.h
deleted file mode 100644
--- a/drivers/char/fep.h
+++ /dev/null
@@ -1,168 +0,0 @@
-
-#define CSTART       0x400L
-#define CMAX         0x800L
-#define ISTART       0x800L
-#define IMAX         0xC00L
-#define CIN          0xD10L
-#define GLOBAL       0xD10L
-#define EIN          0xD18L
-#define FEPSTAT      0xD20L
-#define CHANSTRUCT   0x1000L
-#define RXTXBUF      0x4000L
-
-
-struct global_data {
-	volatile ushort cin;
-	volatile ushort cout;
-	volatile ushort cstart;
-	volatile ushort cmax;
-	volatile ushort ein;
-	volatile ushort eout;
-	volatile ushort istart;
-	volatile ushort imax;
-};
-
-
-struct board_chan {
-	int filler1; 
-	int filler2;
-	volatile ushort tseg;
-	volatile ushort tin;
-	volatile ushort tout;
-	volatile ushort tmax;
-	
-	volatile ushort rseg;
-	volatile ushort rin;
-	volatile ushort rout;
-	volatile ushort rmax;
-	
-	volatile ushort tlow;
-	volatile ushort rlow;
-	volatile ushort rhigh;
-	volatile ushort incr;
-	
-	volatile ushort etime;
-	volatile ushort edelay;
-	volatile unchar *dev;
-	
-	volatile ushort iflag;
-	volatile ushort oflag;
-	volatile ushort cflag;
-	volatile ushort gmask;
-	
-	volatile ushort col;
-	volatile ushort delay;
-	volatile ushort imask;
-	volatile ushort tflush;
-
-	int filler3;
-	int filler4;
-	int filler5;
-	int filler6;
-	
-	volatile unchar num;
-	volatile unchar ract;
-	volatile unchar bstat;
-	volatile unchar tbusy;
-	volatile unchar iempty;
-	volatile unchar ilow;
-	volatile unchar idata;
-	volatile unchar eflag;
-	
-	volatile unchar tflag;
-	volatile unchar rflag;
-	volatile unchar xmask;
-	volatile unchar xval;
-	volatile unchar mstat;
-	volatile unchar mchange;
-	volatile unchar mint;
-	volatile unchar lstat;
-
-	volatile unchar mtran;
-	volatile unchar orun;
-	volatile unchar startca;
-	volatile unchar stopca;
-	volatile unchar startc;
-	volatile unchar stopc;
-	volatile unchar vnext;
-	volatile unchar hflow;
-
-	volatile unchar fillc;
-	volatile unchar ochar;
-	volatile unchar omask;
-
-	unchar filler7;
-	unchar filler8[28];
-}; 
-
-
-#define SRXLWATER      0xE0
-#define SRXHWATER      0xE1
-#define STOUT          0xE2
-#define PAUSETX        0xE3
-#define RESUMETX       0xE4
-#define SAUXONOFFC     0xE6
-#define SENDBREAK      0xE8
-#define SETMODEM       0xE9
-#define SETIFLAGS      0xEA
-#define SONOFFC        0xEB
-#define STXLWATER      0xEC
-#define PAUSERX        0xEE
-#define RESUMERX       0xEF
-#define SETBUFFER      0xF2
-#define SETCOOKED      0xF3
-#define SETHFLOW       0xF4
-#define SETCTRLFLAGS   0xF5
-#define SETVNEXT       0xF6
-
-
-#define BREAK_IND        0x01
-#define LOWTX_IND        0x02
-#define EMPTYTX_IND      0x04
-#define DATA_IND         0x08
-#define MODEMCHG_IND     0x20
-
-
-#define RTS   0x02
-#define CD    0x08
-#define DSR   0x10
-#define CTS   0x20
-#define RI    0x40
-#define DTR   0x80
-
-	/* These are termios bits as the FEP understands them */
-
-/* c_cflag bit meaning */
-#define FEP_CBAUD	0000017
-#define  FEP_B0		0000000		/* hang up */
-#define  FEP_B50	0000001
-#define  FEP_B75	0000002
-#define  FEP_B110	0000003
-#define  FEP_B134	0000004
-#define  FEP_B150	0000005
-#define  FEP_B200	0000006
-#define  FEP_B300	0000007
-#define  FEP_B600	0000010
-#define  FEP_B1200	0000011
-#define  FEP_B1800	0000012
-#define  FEP_B2400	0000013
-#define  FEP_B4800	0000014
-#define  FEP_B9600	0000015
-#define  FEP_B19200	0000016
-#define  FEP_B38400	0000017
-#define FEP_EXTA FEP_B19200
-#define FEP_EXTB FEP_B38400
-#define FEP_CSIZE	0000060
-#define   FEP_CS5	0000000
-#define   FEP_CS6	0000020
-#define   FEP_CS7	0000040
-#define   FEP_CS8	0000060
-#define FEP_CSTOPB	0000100
-#define FEP_CREAD	0000200
-#define FEP_PARENB	0000400
-#define FEP_PARODD	0001000
-#define FEP_HUPCL	0002000
-#define FEP_CLOCAL	0004000
-#define FEP_CIBAUD	03600000		/* input baud rate (not used) */
-#define FEP_CRTSCTS	  020000000000		/* flow control */
-
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -387,7 +387,8 @@ int fdc_interrupt_wait(unsigned int time
 
 	set_current_state(TASK_INTERRUPTIBLE);
 	add_wait_queue(&ftape_wait_intr, &wait);
-	while (!ft_interrupt_seen && (current->state == TASK_INTERRUPTIBLE)) {
+	while (!ft_interrupt_seen && timeout) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		timeout = schedule_timeout(timeout);
         }
 
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -51,7 +51,7 @@ static ssize_t read_nvram(struct file *f
 	unsigned int i;
 	char __user *p = buf;
 
-	if (verify_area(VERIFY_WRITE, buf, count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 	if (*ppos >= NVRAM_SIZE)
 		return 0;
@@ -69,7 +69,7 @@ static ssize_t write_nvram(struct file *
 	const char __user *p = buf;
 	char c;
 
-	if (verify_area(VERIFY_READ, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 	if (*ppos >= NVRAM_SIZE)
 		return 0;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -26,6 +26,7 @@
 #include <linux/mm.h>
 #include <linux/generic_serial.h>
 #include <linux/interrupt.h>
+#include <linux/tty_flip.h>
 #include <linux/delay.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -45,8 +46,8 @@ static int gs_debug;
 
 #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__)
-
-#ifdef NEW_WRITE_LOCKING
+#define NEW_WRITE_LOCKING 1
+#if NEW_WRITE_LOCKING
 #define DECL      /* Nothing */
 #define LOCKIT    down (& port->port_write_sem);
 #define RELEASEIT up (&port->port_write_sem);
@@ -208,7 +209,7 @@ int gs_write(struct tty_struct * tty,
 	if (!port || !port->xmit_buf || !tmp_buf)
 		return -EIO;
 
-	save_flags(flags);
+	local_save_flags(flags);
 	while (1) {
 		cli();
 		c = count;
@@ -227,14 +228,14 @@ int gs_write(struct tty_struct * tty,
 
 		/* Can't copy more? break out! */
 		if (c <= 0) {
-			restore_flags(flags);
+			local_restore_flags(flags);
 			break;
 		}
 		memcpy(port->xmit_buf + port->xmit_head, buf, c);
 		port->xmit_head = ((port->xmit_head + c) &
 		                   (SERIAL_XMIT_SIZE-1));
 		port->xmit_cnt += c;
-		restore_flags(flags);
+		local_restore_flags(flags);
 		buf += c;
 		count -= c;
 		total += c;
@@ -295,7 +296,7 @@ static int gs_real_chars_in_buffer(struc
 }
 
 
-static int gs_wait_tx_flushed (void * ptr, int timeout) 
+static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) 
 {
 	struct gs_port *port = ptr;
 	unsigned long end_jiffies;
@@ -380,9 +381,9 @@ void gs_flush_buffer(struct tty_struct *
 	if (!port) return;
 
 	/* XXX Would the write semaphore do? */
-	save_flags(flags); cli();
+	spin_lock_irqsave (&port->driver_lock, flags);
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore (&port->driver_lock, flags);
 
 	wake_up_interruptible(&tty->write_wait);
 	tty_wakeup(tty);
@@ -468,8 +469,7 @@ static void gs_shutdown_port (struct gs_
 	if (!(port->flags & ASYNC_INITIALIZED))
 		return;
 
-	save_flags (flags);
-	cli ();
+	spin_lock_irqsave(&port->driver_lock, flags);
 
 	if (port->xmit_buf) {
 		free_page((unsigned long) port->xmit_buf);
@@ -482,7 +482,7 @@ static void gs_shutdown_port (struct gs_
 	port->rd->shutdown_port (port);
 
 	port->flags &= ~ASYNC_INITIALIZED;
-	restore_flags (flags);
+	spin_unlock_irqrestore(&port->driver_lock, flags);
 
 	func_exit();
 }
@@ -519,6 +519,7 @@ int gs_block_til_ready(void *port_, stru
 	int    do_clocal = 0;
 	int    CD;
 	struct tty_struct *tty;
+	unsigned long flags;
 
 	func_enter ();
 
@@ -570,10 +571,11 @@ int gs_block_til_ready(void *port_, stru
 	add_wait_queue(&port->open_wait, &wait);
 
 	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
-	cli();
-	if (!tty_hung_up_p(filp))
+	spin_lock_irqsave(&port->driver_lock, flags);
+	if (!tty_hung_up_p(filp)) {
 		port->count--;
-	sti();
+	}
+	spin_unlock_irqrestore(&port->driver_lock, flags);
 	port->blocked_open++;
 	while (1) {
 		CD = port->rd->get_CD (port);
@@ -602,8 +604,9 @@ int gs_block_til_ready(void *port_, stru
 		    port->blocked_open);
 	set_current_state (TASK_RUNNING);
 	remove_wait_queue(&port->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
+	if (!tty_hung_up_p(filp)) {
 		port->count++;
+	}
 	port->blocked_open--;
 	if (retval)
 		return retval;
@@ -633,27 +636,29 @@ void gs_close(struct tty_struct * tty, s
 		port->tty = tty;
 	}
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&port->driver_lock, flags);
 
 	if (tty_hung_up_p(filp)) {
-		restore_flags(flags);
-		port->rd->hungup (port);
+		spin_unlock_irqrestore(&port->driver_lock, flags);
+		if (port->rd->hungup)
+			port->rd->hungup (port);
 		func_exit ();
 		return;
 	}
 
 	if ((tty->count == 1) && (port->count != 1)) {
-		printk(KERN_ERR "gs: gs_close: bad port count;"
-		       " tty->count is 1, port count is %d\n", port->count);
+		printk(KERN_ERR "gs: gs_close port %p: bad port count;"
+		       " tty->count is 1, port count is %d\n", port, port->count);
 		port->count = 1;
 	}
 	if (--port->count < 0) {
-		printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);
+		printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count);
 		port->count = 0;
 	}
+
 	if (port->count) {
-		gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count);
-		restore_flags(flags);
+		gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count);
+		spin_unlock_irqrestore(&port->driver_lock, flags);
 		func_exit ();
 		return;
 	}
@@ -675,16 +680,17 @@ void gs_close(struct tty_struct * tty, s
 	 */
 
 	port->rd->disable_rx_interrupts (port);
+	spin_unlock_irqrestore(&port->driver_lock, flags);
 
 	/* close has no way of returning "EINTR", so discard return value */
 	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		gs_wait_tx_flushed (port, port->closing_wait); 
+		gs_wait_tx_flushed (port, port->closing_wait);
 
 	port->flags &= ~GS_ACTIVE;
 
 	if (tty->driver->flush_buffer)
 		tty->driver->flush_buffer(tty);
-		
+
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
 
@@ -695,14 +701,15 @@ void gs_close(struct tty_struct * tty, s
 
 	if (port->blocked_open) {
 		if (port->close_delay) {
+			spin_unlock_irqrestore(&port->driver_lock, flags);
 			msleep_interruptible(jiffies_to_msecs(port->close_delay));
+			spin_lock_irqsave(&port->driver_lock, flags);
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
 	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
 	wake_up_interruptible(&port->close_wait);
 
-	restore_flags(flags);
 	func_exit ();
 }
 
@@ -727,6 +734,12 @@ void gs_set_termios (struct tty_struct *
 	port = tty->driver_data;
 
 	if (!port) return;
+	if (!port->tty) {
+		/* This seems to happen when this is called after gs_close. */
+		gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n");
+		port->tty = tty;
+	}
+
 
 	tiosp = tty->termios;
 
@@ -821,7 +834,7 @@ void gs_set_termios (struct tty_struct *
 
 	if (!(old_termios->c_cflag & CLOCAL) &&
 	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&port->gs.open_wait);
 #endif
 
 	func_exit();
@@ -836,56 +849,56 @@ int gs_init_port(struct gs_port *port)
 	unsigned long flags;
 	unsigned long page;
 
-	save_flags (flags);
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
+	func_enter ();
 
-		cli (); /* Don't expect this to make a difference. */ 
+        if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
 		if (tmp_buf)
 			free_page(page);
 		else
 			tmp_buf = (unsigned char *) page;
-		restore_flags (flags);
-
+		spin_unlock_irqrestore (&port->driver_lock, flags);
 		if (!tmp_buf) {
+			func_exit ();
 			return -ENOMEM;
 		}
 	}
 
-	if (port->flags & ASYNC_INITIALIZED)
+	if (port->flags & ASYNC_INITIALIZED) {
+		func_exit ();
 		return 0;
-
+	}
 	if (!port->xmit_buf) {
 		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 
 		tmp = get_zeroed_page(GFP_KERNEL);
-
-		/* Spinlock? */
-		cli ();
+		spin_lock_irqsave (&port->driver_lock, flags);
 		if (port->xmit_buf) 
 			free_page (tmp);
 		else
 			port->xmit_buf = (unsigned char *) tmp;
-		restore_flags (flags);
-
-		if (!port->xmit_buf)
+		spin_unlock_irqrestore(&port->driver_lock, flags);
+		if (!port->xmit_buf) {
+			func_exit ();
 			return -ENOMEM;
+		}
 	}
 
-	cli();
-
+	spin_lock_irqsave (&port->driver_lock, flags);
 	if (port->tty) 
 		clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
+	init_MUTEX(&port->port_write_sem);
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-
+	spin_unlock_irqrestore(&port->driver_lock, flags);
 	gs_set_termios(port->tty, NULL);
-
+	spin_lock_irqsave (&port->driver_lock, flags);
 	port->flags |= ASYNC_INITIALIZED;
 	port->flags &= ~GS_TX_INTEN;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+	func_exit ();
 	return 0;
 }
 
@@ -956,13 +969,15 @@ int gs_getserial(struct gs_port *port, s
 
 void gs_got_break(struct gs_port *port)
 {
+	func_enter ();
+
+	tty_insert_flip_char(port->tty, 0, TTY_BREAK);
+	tty_schedule_flip(port->tty);
 	if (port->flags & ASYNC_SAK) {
 		do_SAK (port->tty);
 	}
-	*(port->tty->flip.flag_buf_ptr) = TTY_BREAK;
-	port->tty->flip.flag_buf_ptr++;
-	port->tty->flip.char_buf_ptr++;
-	port->tty->flip.count++;
+
+	func_exit ();
 }
 
 
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -3,7 +3,7 @@
  *
  * Driver for a little io fencing timer.
  *
- * Copyright (C) 2002 Oracle Corporation.  All rights reserved.
+ * Copyright (C) 2002, 2003 Oracle.  All rights reserved.
  *
  * Author: Joel Becker <joel.becker@oracle.com>
  *
@@ -44,11 +44,14 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/reboot.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
+#include <linux/sysrq.h>
 
 
-#define VERSION_STR "0.5.0"
+#define VERSION_STR "0.9.0"
 
 #define DEFAULT_IOFENCE_MARGIN 60	/* Default fudge factor, in seconds */
 #define DEFAULT_IOFENCE_TICK 180	/* Default timer timeout, in seconds */
@@ -56,18 +59,89 @@
 static int hangcheck_tick = DEFAULT_IOFENCE_TICK;
 static int hangcheck_margin = DEFAULT_IOFENCE_MARGIN;
 static int hangcheck_reboot;  /* Defaults to not reboot */
+static int hangcheck_dump_tasks;  /* Defaults to not dumping SysRQ T */
 
-/* Driver options */
+/* options - modular */
 module_param(hangcheck_tick, int, 0);
 MODULE_PARM_DESC(hangcheck_tick, "Timer delay.");
 module_param(hangcheck_margin, int, 0);
 MODULE_PARM_DESC(hangcheck_margin, "If the hangcheck timer has been delayed more than hangcheck_margin seconds, the driver will fire.");
 module_param(hangcheck_reboot, int, 0);
 MODULE_PARM_DESC(hangcheck_reboot, "If nonzero, the machine will reboot when the timer margin is exceeded.");
+module_param(hangcheck_dump_tasks, int, 0);
+MODULE_PARM_DESC(hangcheck_dump_tasks, "If nonzero, the machine will dump the system task state when the timer margin is exceeded.");
 
-MODULE_AUTHOR("Joel Becker");
+MODULE_AUTHOR("Oracle");
 MODULE_DESCRIPTION("Hangcheck-timer detects when the system has gone out to lunch past a certain margin.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION_STR);
+
+/* options - nonmodular */
+#ifndef MODULE
+
+static int __init hangcheck_parse_tick(char *str)
+{
+	int par;
+	if (get_option(&str,&par))
+		hangcheck_tick = par;
+	return 1;
+}
+
+static int __init hangcheck_parse_margin(char *str)
+{
+	int par;
+	if (get_option(&str,&par))
+		hangcheck_margin = par;
+	return 1;
+}
+
+static int __init hangcheck_parse_reboot(char *str)
+{
+	int par;
+	if (get_option(&str,&par))
+		hangcheck_reboot = par;
+	return 1;
+}
+
+static int __init hangcheck_parse_dump_tasks(char *str)
+{
+	int par;
+	if (get_option(&str,&par))
+		hangcheck_dump_tasks = par;
+	return 1;
+}
+
+__setup("hcheck_tick", hangcheck_parse_tick);
+__setup("hcheck_margin", hangcheck_parse_margin);
+__setup("hcheck_reboot", hangcheck_parse_reboot);
+__setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
+#endif /* not MODULE */
+
+#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
+# define HAVE_MONOTONIC
+# define TIMER_FREQ 1000000000ULL
+#elif defined(CONFIG_ARCH_S390)
+/* FA240000 is 1 Second in the IBM time universe (Page 4-38 Principles of Op for zSeries */
+# define TIMER_FREQ 0xFA240000ULL
+#elif defined(CONFIG_IA64)
+# define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq)
+#elif defined(CONFIG_PPC64)
+# define TIMER_FREQ (HZ*loops_per_jiffy)
+#endif
+
+#ifdef HAVE_MONOTONIC
+extern unsigned long long monotonic_clock(void);
+#else
+static inline unsigned long long monotonic_clock(void)
+{
+# ifdef __s390__
+	/* returns the TOD.  see 4-38 Principles of Op of zSeries */
+	return get_clock();
+# else
+	return get_cycles();
+# endif  /* __s390__ */
+}
+#endif  /* HAVE_MONOTONIC */
 
 
 /* Last time scheduled */
@@ -78,7 +152,6 @@ static void hangcheck_fire(unsigned long
 static struct timer_list hangcheck_ticktock =
 		TIMER_INITIALIZER(hangcheck_fire, 0, 0);
 
-extern unsigned long long monotonic_clock(void);
 
 static void hangcheck_fire(unsigned long data)
 {
@@ -92,6 +165,12 @@ static void hangcheck_fire(unsigned long
 		tsc_diff = (cur_tsc + (~0ULL - hangcheck_tsc)); /* or something */
 
 	if (tsc_diff > hangcheck_tsc_margin) {
+		if (hangcheck_dump_tasks) {
+			printk(KERN_CRIT "Hangcheck: Task state:\n");
+#ifdef CONFIG_MAGIC_SYSRQ
+			handle_sysrq('t', NULL, NULL);
+#endif  /* CONFIG_MAGIC_SYSRQ */
+		}
 		if (hangcheck_reboot) {
 			printk(KERN_CRIT "Hangcheck: hangcheck is restarting the machine.\n");
 			machine_restart(NULL);
@@ -108,10 +187,16 @@ static int __init hangcheck_init(void)
 {
 	printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
 	       VERSION_STR, hangcheck_tick, hangcheck_margin);
-
-	hangcheck_tsc_margin = hangcheck_margin + hangcheck_tick;
-	hangcheck_tsc_margin *= 1000000000;
-
+#if defined (HAVE_MONOTONIC)
+	printk("Hangcheck: Using monotonic_clock().\n");
+#elif defined(__s390__)
+	printk("Hangcheck: Using TOD.\n");
+#else
+	printk("Hangcheck: Using get_cycles().\n");
+#endif  /* HAVE_MONOTONIC */
+	hangcheck_tsc_margin =
+		(unsigned long long)(hangcheck_margin + hangcheck_tick);
+	hangcheck_tsc_margin *= (unsigned long long)TIMER_FREQ;
 
 	hangcheck_tsc = monotonic_clock();
 	mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
@@ -123,6 +208,7 @@ static int __init hangcheck_init(void)
 static void __exit hangcheck_exit(void)
 {
 	del_timer_sync(&hangcheck_ticktock);
+        printk("Hangcheck: Stopped hangcheck timer.\n");
 }
 
 module_init(hangcheck_init);
diff --git a/drivers/char/hp600_keyb.c b/drivers/char/hp600_keyb.c
deleted file mode 100644
--- a/drivers/char/hp600_keyb.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- *	$Id$ 
- *	Copyright (C) 2000 YAEGASHI Takeshi
- *	HP600 keyboard scan routine and translation table
- *	Copyright (C) 2000 Niibe Yutaka
- *	HP620 keyboard translation table
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/machvec.h>
-#include <asm/delay.h>
-#include <asm/io.h>
-#include "scan_keyb.h"
-
-#define PCDR 0xa4000124
-#define PDDR 0xa4000126
-#define PEDR 0xa4000128
-#define PFDR 0xa400012a
-#define PGDR 0xa400012c
-#define PHDR 0xa400012e
-#define PJDR 0xa4000130
-#define PKDR 0xa4000132
-#define PLDR 0xa4000134
-
-static const unsigned char hp620_japanese_table[] = {
-	/* PTD1 */
-	0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x0e, 0x00, 0x00,
-	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
-	/* PTD5 */
-	0x18, 0x19, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-	/* PTD7 */
-	0x26, 0x1a, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
-	/* PTE0 */
-	0x27, 0x1b, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x2a, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* PTE1 */
-	0x35, 0x28, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x70, 0x3a, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x34,
-	/* PTE3 */
-	0x48, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x2d, 0x2e, 0x7b, 0x30, 0x31, 0x32, 0x33,
-	/* PTE6 */
-	0x4b, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x2c, 0x38, 0x00, 0x39, 0x79, 0x7d, 0x73,
-	/* PTE7 */
-	0x41, 0x42, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
-	/* **** */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-
-static const unsigned char hp680_japanese_table[] = {
-	/* PTD1 */
-	0x3a, 0x70, 0x29, 0x00, 0x01, 0x00, 0x00, 0x00,
-	0x3b, 0x3c, 0x3d, 0x42, 0x41, 0x40, 0x3e, 0x3f,
-	/* PTD5 */
-	0x35, 0x28, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00,
-	0x2d, 0x2e, 0x2f, 0x34, 0x33, 0x32, 0x30, 0x31,
-	/* PTD7 */
-	0x50, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x38, 0x7b,
-	/* PTE0 */
-	0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00,
-	0x1d, 0x00, 0x39, 0x53, 0x73, 0xf9, 0x00, 0x00,
-	/* PTE1 */
-	0x27, 0x1b, 0x2b, 0x00, 0x1e, 0x00, 0x00, 0x00,
-	0x1f, 0x20, 0x21, 0x26, 0x25, 0x24, 0x22, 0x23,
-	/* PTE3 */
-	0x48, 0x7d, 0x36, 0x00, 0x0f, 0x00, 0x00, 0x00,
-	0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* PTE6 */
-	0x19, 0x1a, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00,
-	0x11, 0x12, 0x13, 0x18, 0x17, 0x16, 0x14, 0x15,
-	/* PTE7 */
-	0x0b, 0x0c, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00,
-	0x03, 0x04, 0x05, 0x0a, 0x09, 0x08, 0x06, 0x07,
-	/* **** */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-
-static int hp620_japanese_scan_kbd(unsigned char *s)
-{
-	int i;
-	unsigned char matrix_switch[] = {
-		0xfd, 0xff,	/* PTD1 */
-		0xdf, 0xff,	/* PTD5 */
-		0x7f, 0xff,	/* PTD7 */
-		0xff, 0xfe,	/* PTE0 */
-		0xff, 0xfd,	/* PTE1 */
-		0xff, 0xf7,	/* PTE3 */
-		0xff, 0xbf,	/* PTE6 */
-		0xff, 0x7f,	/* PTE7 */
-	}, *t=matrix_switch;
-
-	for(i=0; i<8; i++) {
-		ctrl_outb(*t++, PDDR);
-		ctrl_outb(*t++, PEDR);
-		udelay(50);
-		*s++=ctrl_inb(PCDR);
-		*s++=ctrl_inb(PFDR);
-	}
-
-	ctrl_outb(0xff, PDDR);
-	ctrl_outb(0xff, PEDR);
-
-	*s++=ctrl_inb(PGDR);
-	*s++=ctrl_inb(PHDR);
-
-	return 0;
-}
-
-
-static int hp680_japanese_scan_kbd(unsigned char *s)
-{
-	int i;
-	unsigned char matrix_switch[] = {
-		0xfd, 0xff,	/* PTD1 */
-		0xdf, 0xff,	/* PTD5 */
-		0x7f, 0xff,	/* PTD7 */
-		0xff, 0xfe,	/* PTE0 */
-		0xff, 0xfd,	/* PTE1 */
-		0xff, 0xf7,	/* PTE3 */
-		0xff, 0xbf,	/* PTE6 */
-		0xff, 0x7f,	/* PTE7 */
-	}, *t=matrix_switch;
-
-	for(i=0; i<8; i++) {
-		ctrl_outb(*t++, PDDR);
-		ctrl_outb(*t++, PEDR);
-		*s++=ctrl_inb(PCDR);
-		*s++=ctrl_inb(PFDR);
-	}
-
-	ctrl_outb(0xff, PDDR);
-	ctrl_outb(0xff, PEDR);
-
-	*s++=ctrl_inb(PGDR);
-	*s++=ctrl_inb(PHDR);
-
-	return 0;
-}
-
-
-void __init hp600_kbd_init_hw(void)
-{
-	scan_kbd_init();
-
-	if (MACH_HP620)
-		register_scan_keyboard(hp620_japanese_scan_kbd,
-				       hp620_japanese_table, 18);
-	else if (MACH_HP680 || MACH_HP690) 
-		register_scan_keyboard(hp680_japanese_scan_kbd,
-				       hp680_japanese_table, 18);
-
-	printk(KERN_INFO "HP600 matrix scan keyboard registered\n");
-}
-
-/****************************************************************
-HP Jornada 690(Japanese version) keyboard scan matrix
-
-	PTC7	PTC6	PTC5	PTC4	PTC3	PTC2	PTC1	PTC0	
-PTD1	REC			Escape	on/off	Han/Zen	Hira	Eisu	
-PTD5	REC			Z	on/off	Enter	:	/	
-PTD7	REC						Right	Down	
-PTE0	REC			Windows	on/off				
-PTE1	REC			A	on/off	]	[	;	
-PTE3	REC			Tab	on/off	ShirtR	\	Up	
-PTE6	REC			Q	on/off	BS	@	P	
-PTE7	REC			1	on/off	^	-	0	
-
-	PTF7	PTF6	PTF5	PTF4	PTF3	PTF2	PTF1	PTF0
-PTD1	F5	F4	F6	F7	F8	F3	F2	F1	
-PTD5	N	B	M	,	.	V	C	X	
-PTD7	Muhen	Alt			Left				
-PTE0			Henkan	_	Del	Space		Ctrl	
-PTE1	H	G	J	K	L	F	D	S	
-PTE3							ShiftL		
-PTE6	Y	T	U	I	O	R	E	W	
-PTE7	6	5	7	8	9	4	3	2	
-
-	PTG5	PTG4	PTG3	PTG0	PTH0
-*	REC	REW	FWW	Cover	on/off
-
-
-		7	6	5	4	3	2	1	0
-C: 0xffff 0xdf	IP	IP	IP	IP	IP	IP	IP	IP
-D: 0x6786 0x59	O	I	O	IP	I	F	O	I
-E: 0x5045 0x00	O	O	F	F	O	F	O	O
-F: 0xffff 0xff	IP	IP	IP	IP	IP	IP	IP	IP
-G: 0xaffe 0xfd	I	I	IP	IP	IP	IP	IP	I
-H: 0x70f2 0x49	O	IP	F	F	IP	IP	F	I
-J: 0x0704 0x22	F	F	O	IP	F	F	O	F
-K: 0x0100 0x10	F	F	F	O	F	F	F	F
-L: 0x0c3c 0x26	F	F	IP	F	F	IP	IP	F
-
-****************************************************************/
-
-/****************************************************************
-HP Jornada 620(Japanese version) keyboard scan matrix
-
-	PTC7	PTC6	PTC5	PTC4	PTC3	PTC2	PTC1	PTC0
-PTD1	EREC		BS	Ctrl	on/off	-	0	9
-PTD5	EREC		BS	Ctrl	on/off	^	P	O
-PTD7	EREC		BS	Ctrl	on/off	]	@	L
-PTE0	EREC		BS	Ctrl	on/off	Han/Zen [	;
-PTE1	EREC		BS	Ctrl	on/off	Enter	:	/
-PTE3	EREC		BS	Ctrl	on/off		Right	Up
-PTE6	EREC		BS	Ctrl	on/off		Down	Left
-PTE7	EREC		BS	Ctrl	on/off		F8	F7
-
-	PTF7	PTF6	PTF5	PTF4	PTF3	PTF2	PTF1	PTF0
-PTD1	8	7	6	5	4	3	2	1
-PTD5	I	U	Y	T	R	E	W	Q
-PTD7	K	J	H	G	F	D	S	A
-PTE0						ESC	Tab	Shift
-PTE1	.			V			Caps	Hira
-PTE3	,	M	N	B	Muhen	C	X
-PTE6	_	\	Henkan	Space		Alt	Z
-PTE7	F6	F5	F4	F3	F2	F1		REC
-
-	PTH0
-*	on/off
-
-		7	6	5	4	3	2	1	0
-C: 0xffff 0xff	IP	IP	IP	IP	IP	IP	IP	IP
-D: 0x4404 0xaf	O	F	O	F	F	F	O	F
-E: 0x5045 0xff	O	O	F	F	O	F	O	O
-F: 0xffff 0xff	IP	IP	IP	IP	IP	IP	IP	IP
-G: 0xd5ff 0x00	IP	O	O	O	IP	IP	IP	IP
-H: 0x63ff 0xd1	O	I	F	IP	IP	IP	IP	IP
-J: 0x0004 0x02	F	F	F	F	F	F	O	F
-K: 0x0401 0xff	F	F	O	F	F	F	F	O
-L: 0x0c00 0x20	F	F	IP	F	F	F	F	F
-
-ADCSR: 0x08
-ADCR: 0x3f
-
- ****************************************************************/
-
-/****************************************************************
-Japanese 109 keyboard scan code layout
-
-                                              E02A-     E1- 
-01    3B 3C 3D 3E  3F 40 41 42  43 44 57 58   E037  46  1045
-                                                                   
-29 02 03 04 05 06 07 08 09 0A 0B 0C 0D 7D 0E  E052 E047 E049   45 E035 37  4A
-0F  10 11 12 13 14 15 16 17 18 19 1A 1B   1C  E053 E04F E051   47  48  49  4E
-3A   1E 1F 20 21 22 23 24 25 26 27 28 2B                       4B  4C  4D
-2A    2C 2D 2E 2F 30 31 32 33 34 35 73    36       E048        4F  50  51  E0-
-1D  DB  38  7B   39   79 70  E038 DC DD E01D  E04B E050 E04D     52    53  1C
-
-****************************************************************/
-
-#if 0
-int __init hp620_keyboard_test(void)
-{
-	int i;
-	unsigned char s[18];
-	unsigned long a, b, c, d;
-
-	printk("PCCR: %04lx, PCDR: %02lx\n",
-	       ctrl_inw(0xa4000104), ctrl_inb(0xa4000124));
-	printk("PDCR: %04lx, PDDR: %02lx\n",
-	       ctrl_inw(0xa4000106), ctrl_inb(0xa4000126));
-	printk("PECR: %04lx, PEDR: %02lx\n",
-	       ctrl_inw(0xa4000108), ctrl_inb(0xa4000128));
-	printk("PFCR: %04lx, PFDR: %02lx\n",
-	       ctrl_inw(0xa400010a), ctrl_inb(0xa400012a));
-	printk("PGCR: %04lx, PGDR: %02lx\n",
-	       ctrl_inw(0xa400010c), ctrl_inb(0xa400012c));
-	printk("PHCR: %04lx, PHDR: %02lx\n",
-	       ctrl_inw(0xa400010e), ctrl_inb(0xa400012e));
-	printk("PJCR: %04lx, PJDR: %02lx\n",
-	       ctrl_inw(0xa4000110), ctrl_inb(0xa4000130));
-	printk("PKCR: %04lx, PKDR: %02lx\n",
-	       ctrl_inw(0xa4000112), ctrl_inb(0xa4000132));
-	printk("PLCR: %04lx, PLDR: %02lx\n",
-	       ctrl_inw(0xa4000114), ctrl_inb(0xa4000134));
-
-	printk("ADCSR: %02lx, ADCR: %02lx\n",
-	       ctrl_inb(0xa4000090), ctrl_inb(0xa4000092));
-
-	ctrl_inb(0xa4000004);
-	ctrl_inb(0xa4000006);
-	ctrl_inb(0xa4000008);
-	ctrl_outb(0, 0xa4000004);
-	ctrl_outb(0, 0xa4000006);
-	ctrl_outb(0, 0xa4000008);
-	ctrl_outb(0, 0xa4000090);
-	ctrl_outb(0x3b, 0xa4000090);
-
-	while(1) {
-		hp620_japanese_scan_kbd(s);
-		for(i=0; i<18; i+=2)
-			printk("%02x%02x ", s[i], s[i+1]);
-
-#if 0
-		ctrl_outb(~2, PJDR);
-		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
-		ctrl_outb(0xff, PJDR);
-		ctrl_outb(~1, PKDR);
-		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
-		ctrl_outb(~32, PKDR);
-		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
-		ctrl_outb(0xff, PKDR);
-#endif
-
-		printk("%02lx%02lx%02lx%02lx ", a, b, c, d);
-		if(ctrl_inb(0xa4000090)&0x80) {
-			a=ctrl_inb(0xa4000080);
-			b=ctrl_inb(0xa4000084);
-			c=ctrl_inb(0xa4000088);
-			d=ctrl_inb(0xa400008c);
-			ctrl_outb(0x3b, 0xa4000090);
-		}
-		printk("%02lx%02lx%02lx ",
-		       ctrl_inb(0xa4000004),
-		       ctrl_inb(0xa4000006),
-		       ctrl_inb(0xa4000008));
-
-		printk("\n");
-	}
-
-	return 0;
-}
-module_init(keyboard_probe);
-#endif
-
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -76,6 +76,7 @@ struct hpet_dev {
 struct hpets {
 	struct hpets *hp_next;
 	struct hpet __iomem *hp_hpet;
+	unsigned long hp_hpet_phys;
 	struct time_interpolator *hp_interpolator;
 	unsigned long hp_period;
 	unsigned long hp_delta;
@@ -265,7 +266,7 @@ static int hpet_mmap(struct file *file, 
 		return -EINVAL;
 
 	devp = file->private_data;
-	addr = (unsigned long)devp->hd_hpet;
+	addr = devp->hd_hpets->hp_hpet_phys;
 
 	if (addr & (PAGE_SIZE - 1))
 		return -ENOSYS;
@@ -274,7 +275,7 @@ static int hpet_mmap(struct file *file, 
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	addr = __pa(addr);
 
-	if (remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+	if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
 					PAGE_SIZE, vma->vm_page_prot)) {
 		printk(KERN_ERR "remap_pfn_range failed in hpet.c\n");
 		return -EAGAIN;
@@ -795,6 +796,7 @@ int hpet_alloc(struct hpet_data *hdp)
 
 	hpetp->hp_which = hpet_nhpet++;
 	hpetp->hp_hpet = hdp->hd_address;
+	hpetp->hp_hpet_phys = hdp->hd_phys_address;
 
 	hpetp->hp_ntimer = hdp->hd_nirqs;
 
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -631,27 +631,10 @@ static int __init poll_for_state(struct 
 /* wait for irq handler to change our state */
 static int wait_for_state(struct hvsi_struct *hp, int state)
 {
-	unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
-	unsigned long timeout;
 	int ret = 0;
 
-	DECLARE_WAITQUEUE(myself, current);
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&hp->stateq, &myself);
-
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (hp->state == state)
-			break;
-		timeout = end_jiffies - jiffies;
-		if (time_after(jiffies, end_jiffies)) {
-			ret = -EIO;
-			break;
-		}
-		schedule_timeout(timeout);
-	}
-	remove_wait_queue(&hp->stateq, &myself);
-	set_current_state(TASK_RUNNING);
+	if (!wait_event_timeout(hp->stateq, (hp->state == state), HVSI_TIMEOUT))
+		ret = -EIO;
 
 	return ret;
 }
@@ -868,24 +851,7 @@ static int hvsi_open(struct tty_struct *
 /* wait for hvsi_write_worker to empty hp->outbuf */
 static void hvsi_flush_output(struct hvsi_struct *hp)
 {
-	unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
-	unsigned long timeout;
-
-	DECLARE_WAITQUEUE(myself, current);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&hp->emptyq, &myself);
-
-	for (;;) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (hp->n_outbuf <= 0)
-			break;
-		timeout = end_jiffies - jiffies;
-		if (time_after(jiffies, end_jiffies))
-			break;
-		schedule_timeout(timeout);
-	}
-	remove_wait_queue(&hp->emptyq, &myself);
-	set_current_state(TASK_RUNNING);
+	wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);
 
 	/* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
 	cancel_delayed_work(&hp->writer);
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -235,7 +235,6 @@ static void reset_flags(struct si_sm_dat
 	if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
 	BT_CONTROL(BT_CLR_WR_PTR);
 	BT_CONTROL(BT_SMS_ATN);
-	BT_INTMASK_W(BT_BMC_HWRST);
 #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
 	if (BT_STATUS & BT_B2H_ATN) {
 		int i;
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -44,6 +44,7 @@
 #include <linux/ipmi.h>
 #include <asm/semaphore.h>
 #include <linux/init.h>
+#include <linux/device.h>
 
 #define IPMI_DEVINTF_VERSION "v33"
 
@@ -519,15 +520,21 @@ MODULE_PARM_DESC(ipmi_major, "Sets the m
 		 " interface.  Other values will set the major device number"
 		 " to that value.");
 
+static struct class_simple *ipmi_class;
+
 static void ipmi_new_smi(int if_num)
 {
-	devfs_mk_cdev(MKDEV(ipmi_major, if_num),
-		      S_IFCHR | S_IRUSR | S_IWUSR,
+	dev_t dev = MKDEV(ipmi_major, if_num);
+
+	devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
 		      "ipmidev/%d", if_num);
+
+	class_simple_device_add(ipmi_class, dev, NULL, "ipmi%d", if_num);
 }
 
 static void ipmi_smi_gone(int if_num)
 {
+	class_simple_device_remove(MKDEV(ipmi_major, if_num));
 	devfs_remove("ipmidev/%d", if_num);
 }
 
@@ -548,8 +555,15 @@ static __init int init_ipmi_devintf(void
 	printk(KERN_INFO "ipmi device interface version "
 	       IPMI_DEVINTF_VERSION "\n");
 
+	ipmi_class = class_simple_create(THIS_MODULE, "ipmi");
+	if (IS_ERR(ipmi_class)) {
+		printk(KERN_ERR "ipmi: can't register device class\n");
+		return PTR_ERR(ipmi_class);
+	}
+
 	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
 	if (rv < 0) {
+		class_simple_destroy(ipmi_class);
 		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
 		return rv;
 	}
@@ -563,6 +577,7 @@ static __init int init_ipmi_devintf(void
 	rv = ipmi_smi_watcher_register(&smi_watcher);
 	if (rv) {
 		unregister_chrdev(ipmi_major, DEVICE_NAME);
+		class_simple_destroy(ipmi_class);
 		printk(KERN_WARNING "ipmi: can't register smi watcher\n");
 		return rv;
 	}
@@ -573,6 +588,7 @@ module_init(init_ipmi_devintf);
 
 static __exit void cleanup_ipmi(void)
 {
+	class_simple_destroy(ipmi_class);
 	ipmi_smi_watcher_unregister(&smi_watcher);
 	devfs_remove(DEVICE_NAME);
 	unregister_chrdev(ipmi_major, DEVICE_NAME);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -612,6 +612,7 @@ int ipmi_create_user(unsigned int       
 	unsigned long flags;
 	ipmi_user_t   new_user;
 	int           rv = 0;
+	ipmi_smi_t    intf;
 
 	/* There is no module usecount here, because it's not
            required.  Since this can only be used by and called from
@@ -646,19 +647,29 @@ int ipmi_create_user(unsigned int       
 		goto out_unlock;
 	}
 
+	intf = ipmi_interfaces[if_num];
+
 	new_user->handler = handler;
 	new_user->handler_data = handler_data;
-	new_user->intf = ipmi_interfaces[if_num];
+	new_user->intf = intf;
 	new_user->gets_events = 0;
 
-	if (!try_module_get(new_user->intf->handlers->owner)) {
+	if (!try_module_get(intf->handlers->owner)) {
 		rv = -ENODEV;
 		goto out_unlock;
 	}
 
-	write_lock_irqsave(&new_user->intf->users_lock, flags);
-	list_add_tail(&new_user->link, &new_user->intf->users);
-	write_unlock_irqrestore(&new_user->intf->users_lock, flags);
+	if (intf->handlers->inc_usecount) {
+		rv = intf->handlers->inc_usecount(intf->send_info);
+		if (rv) {
+			module_put(intf->handlers->owner);
+			goto out_unlock;
+		}
+	}
+
+	write_lock_irqsave(&intf->users_lock, flags);
+	list_add_tail(&new_user->link, &intf->users);
+	write_unlock_irqrestore(&intf->users_lock, flags);
 
  out_unlock:	
 	if (rv) {
@@ -729,8 +740,11 @@ int ipmi_destroy_user(ipmi_user_t user)
 	down_read(&interfaces_sem);
 	write_lock_irqsave(&intf->users_lock, flags);
 	rv = ipmi_destroy_user_nolock(user);
-	if (!rv)
+	if (!rv) {
 		module_put(intf->handlers->owner);
+		if (intf->handlers->dec_usecount)
+			intf->handlers->dec_usecount(intf->send_info);
+	}
 		
 	write_unlock_irqrestore(&intf->users_lock, flags);
 	up_read(&interfaces_sem);
@@ -1629,6 +1643,7 @@ int ipmi_register_smi(struct ipmi_smi_ha
 		      void		       *send_info,
 		      unsigned char            version_major,
 		      unsigned char            version_minor,
+		      unsigned char            slave_addr,
 		      ipmi_smi_t               *intf)
 {
 	int              i, j;
@@ -1664,7 +1679,10 @@ int ipmi_register_smi(struct ipmi_smi_ha
 			new_intf->intf_num = i;
 			new_intf->version_major = version_major;
 			new_intf->version_minor = version_minor;
-			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+			if (slave_addr == 0)
+				new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+			else
+				new_intf->my_address = slave_addr;
 			new_intf->my_lun = 2;  /* the SMS LUN. */
 			rwlock_init(&(new_intf->users_lock));
 			INIT_LIST_HEAD(&(new_intf->users));
@@ -2570,28 +2588,20 @@ handle_msg_timeout(struct ipmi_recv_msg 
 	deliver_response(msg);
 }
 
-static void
-send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
-		   struct ipmi_smi_msg *smi_msg,
-		   unsigned char seq, long seqid)
+static struct ipmi_smi_msg *
+smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
+		  unsigned char seq, long seqid)
 {
-	if (!smi_msg)
-		smi_msg = ipmi_alloc_smi_msg();
+	struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
 	if (!smi_msg)
 		/* If we can't allocate the message, then just return, we
 		   get 4 retries, so this should be ok. */
-		return;
+		return NULL;
 
 	memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
 	smi_msg->data_size = recv_msg->msg.data_len;
 	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
 		
-	/* Send the new message.  We send with a zero priority.  It
-	   timed out, I doubt time is that critical now, and high
-	   priority messages are really only for messages to the local
-	   MC, which don't get resent. */
-	intf->handlers->sender(intf->send_info, smi_msg, 0);
-
 #ifdef DEBUG_MSGING
 	{
 		int m;
@@ -2601,6 +2611,7 @@ send_from_recv_msg(ipmi_smi_t intf, stru
 		printk("\n");
 	}
 #endif
+	return smi_msg;
 }
 
 static void
@@ -2665,14 +2676,13 @@ ipmi_timeout_handler(long timeout_period
 					intf->timed_out_ipmb_commands++;
 				spin_unlock(&intf->counter_lock);
 			} else {
+				struct ipmi_smi_msg *smi_msg;
 				/* More retries, send again. */
 
 				/* Start with the max timer, set to normal
 				   timer after the message is sent. */
 				ent->timeout = MAX_MSG_TIMEOUT;
 				ent->retries_left--;
-				send_from_recv_msg(intf, ent->recv_msg, NULL,
-						   j, ent->seqid);
 				spin_lock(&intf->counter_lock);
 				if (ent->recv_msg->addr.addr_type
 				    == IPMI_LAN_ADDR_TYPE)
@@ -2680,6 +2690,20 @@ ipmi_timeout_handler(long timeout_period
 				else
 					intf->retransmitted_ipmb_commands++;
 				spin_unlock(&intf->counter_lock);
+				smi_msg = smi_from_recv_msg(intf,
+						ent->recv_msg, j, ent->seqid);
+				if(!smi_msg)
+					continue;
+
+				spin_unlock_irqrestore(&(intf->seq_lock),flags);
+				/* Send the new message.  We send with a zero
+				 * priority.  It timed out, I doubt time is
+				 * that critical now, and high priority
+				 * messages are really only for messages to the
+				 * local MC, which don't get resent. */
+				intf->handlers->sender(intf->send_info,
+							smi_msg, 0);
+				spin_lock_irqsave(&(intf->seq_lock), flags);
 			}
 		}
 		spin_unlock_irqrestore(&(intf->seq_lock), flags);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -100,6 +100,11 @@ enum si_intf_state {
 	/* FIXME - add watchdog stuff. */
 };
 
+/* Some BT-specific defines we need here. */
+#define IPMI_BT_INTMASK_REG		2
+#define IPMI_BT_INTMASK_CLEAR_IRQ_BIT	2
+#define IPMI_BT_INTMASK_ENABLE_IRQ_BIT	1
+
 enum si_type {
     SI_KCS, SI_SMIC, SI_BT
 };
@@ -176,6 +181,9 @@ struct smi_info
 	unsigned char ipmi_version_major;
 	unsigned char ipmi_version_minor;
 
+	/* Slave address, could be reported from DMI. */
+	unsigned char slave_addr;
+
 	/* Counters and things for the proc filesystem. */
 	spinlock_t count_lock;
 	unsigned long short_timeouts;
@@ -407,7 +415,7 @@ static void handle_transaction_done(stru
 			/* Error fetching flags, just give up for
 			   now. */
 			smi_info->si_state = SI_NORMAL;
-		} else if (len < 3) {
+		} else if (len < 4) {
 			/* Hmm, no flags.  That's technically illegal, but
 			   don't use uninitialized data. */
 			smi_info->si_state = SI_NORMAL;
@@ -872,6 +880,17 @@ static irqreturn_t si_irq_handler(int ir
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct smi_info *smi_info = data;
+	/* We need to clear the IRQ flag for the BT interface. */
+	smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG,
+			     IPMI_BT_INTMASK_CLEAR_IRQ_BIT
+			     | IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
+	return si_irq_handler(irq, data, regs);
+}
+
+
 static struct ipmi_smi_handlers handlers =
 {
 	.owner                  = THIS_MODULE,
@@ -897,21 +916,23 @@ static struct smi_info *smi_infos[SI_MAX
 #define DEFAULT_REGSPACING	1
 
 static int           si_trydefaults = 1;
-static char          *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL };
+static char          *si_type[SI_MAX_PARMS];
 #define MAX_SI_TYPE_STR 30
 static char          si_type_str[MAX_SI_TYPE_STR];
-static unsigned long addrs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
-static int num_addrs = 0;
-static unsigned int  ports[SI_MAX_PARMS] = { 0, 0, 0, 0 };
-static int num_ports = 0;
-static int           irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
-static int num_irqs = 0;
-static int           regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static unsigned long addrs[SI_MAX_PARMS];
+static int num_addrs;
+static unsigned int  ports[SI_MAX_PARMS];
+static int num_ports;
+static int           irqs[SI_MAX_PARMS];
+static int num_irqs;
+static int           regspacings[SI_MAX_PARMS];
 static int num_regspacings = 0;
-static int           regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           regsizes[SI_MAX_PARMS];
 static int num_regsizes = 0;
-static int           regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           regshifts[SI_MAX_PARMS];
 static int num_regshifts = 0;
+static int slave_addrs[SI_MAX_PARMS];
+static int num_slave_addrs = 0;
 
 
 module_param_named(trydefaults, si_trydefaults, bool, 0);
@@ -955,6 +976,12 @@ MODULE_PARM_DESC(regshifts, "The amount 
 		 " IPMI register, in bits.  For instance, if the data"
 		 " is read from a 32-bit word and the IPMI data is in"
 		 " bit 8-15, then the shift would be 8");
+module_param_array(slave_addrs, int, &num_slave_addrs, 0);
+MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
+		 " the controller.  Normally this is 0x20, but can be"
+		 " overridden by this parm.  This is an array indexed"
+		 " by interface number.");
+
 
 #define IPMI_MEM_ADDR_SPACE 1
 #define IPMI_IO_ADDR_SPACE  2
@@ -990,11 +1017,22 @@ static int std_irq_setup(struct smi_info
 	if (!info->irq)
 		return 0;
 
-	rv = request_irq(info->irq,
-			 si_irq_handler,
-			 SA_INTERRUPT,
-			 DEVICE_NAME,
-			 info);
+	if (info->si_type == SI_BT) {
+		rv = request_irq(info->irq,
+				 si_bt_irq_handler,
+				 SA_INTERRUPT,
+				 DEVICE_NAME,
+				 info);
+		if (!rv)
+			/* Enable the interrupt in the BT interface. */
+			info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
+					 IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
+	} else
+		rv = request_irq(info->irq,
+				 si_irq_handler,
+				 SA_INTERRUPT,
+				 DEVICE_NAME,
+				 info);
 	if (rv) {
 		printk(KERN_WARNING
 		       "ipmi_si: %s unable to claim interrupt %d,"
@@ -1013,6 +1051,9 @@ static void std_irq_cleanup(struct smi_i
 	if (!info->irq)
 		return;
 
+	if (info->si_type == SI_BT)
+		/* Disable the interrupt in the BT interface. */
+		info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0);
 	free_irq(info->irq, info);
 }
 
@@ -1466,6 +1507,11 @@ static int try_init_acpi(int intf_num, s
 	if (!is_new_interface(-1, addr_space, spmi->addr.address))
 		return -ENODEV;
 
+	if (!spmi->addr.register_bit_width) {
+		acpi_failure = 1;
+		return -ENODEV;
+	}
+
 	/* Figure out the interface type. */
 	switch (spmi->InterfaceType)
 	{
@@ -1510,8 +1556,17 @@ static int try_init_acpi(int intf_num, s
 		info->irq_setup = NULL;
 	}
 
-	regspacings[intf_num] = spmi->addr.register_bit_width / 8;
-	info->io.regspacing = spmi->addr.register_bit_width / 8;
+	if (spmi->addr.register_bit_width) {
+		/* A (hopefully) properly formed register bit width. */
+		regspacings[intf_num] = spmi->addr.register_bit_width / 8;
+		info->io.regspacing = spmi->addr.register_bit_width / 8;
+	} else {
+		/* Some broken systems get this wrong and set the value
+		 * to zero.  Assume it is the default spacing.  If that
+		 * is wrong, too bad, the vendor should fix the tables. */
+		regspacings[intf_num] = DEFAULT_REGSPACING;
+		info->io.regspacing = DEFAULT_REGSPACING;
+	}
 	regsizes[intf_num] = regspacings[intf_num];
 	info->io.regsize = regsizes[intf_num];
 	regshifts[intf_num] = spmi->addr.register_bit_offset;
@@ -1542,7 +1597,6 @@ static int try_init_acpi(int intf_num, s
 #endif
 
 #ifdef CONFIG_X86
-
 typedef struct dmi_ipmi_data
 {
 	u8   		type;
@@ -1550,23 +1604,28 @@ typedef struct dmi_ipmi_data
 	unsigned long	base_addr;
 	u8   		irq;
 	u8              offset;
-}dmi_ipmi_data_t;
+	u8              slave_addr;
+} dmi_ipmi_data_t;
+
+static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
+static int dmi_data_entries;
 
 typedef struct dmi_header
 {
 	u8	type;
 	u8	length;
 	u16	handle;
-}dmi_header_t;
+} dmi_header_t;
 
-static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data)
+static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
 {
-	u8		*data = (u8 *)dm;
+	u8		__iomem *data = (u8 __iomem *)dm;
 	unsigned long  	base_addr;
 	u8		reg_spacing;
-	u8              len = dm->length;
+	u8              len = readb(&dm->length);
+	dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
 
-	ipmi_data->type = data[4];
+	ipmi_data->type = readb(&data[4]);
 
 	memcpy(&base_addr, data+8, sizeof(unsigned long));
 	if (len >= 0x11) {
@@ -1581,12 +1640,12 @@ static int decode_dmi(dmi_header_t *dm, 
 		}
 		/* If bit 4 of byte 0x10 is set, then the lsb for the address
 		   is odd. */
-		ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
+		ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4);
 
-		ipmi_data->irq = data[0x11];
+		ipmi_data->irq = readb(&data[0x11]);
 
 		/* The top two bits of byte 0x10 hold the register spacing. */
-		reg_spacing = (data[0x10] & 0xC0) >> 6;
+		reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6;
 		switch(reg_spacing){
 		case 0x00: /* Byte boundaries */
 		    ipmi_data->offset = 1;
@@ -1603,27 +1662,37 @@ static int decode_dmi(dmi_header_t *dm, 
 		}
 	} else {
 		/* Old DMI spec. */
-		ipmi_data->base_addr = base_addr;
+		/* Note that technically, the lower bit of the base
+		 * address should be 1 if the address is I/O and 0 if
+		 * the address is in memory.  So many systems get that
+		 * wrong (and all that I have seen are I/O) so we just
+		 * ignore that bit and assume I/O.  Systems that use
+		 * memory should use the newer spec, anyway. */
+		ipmi_data->base_addr = base_addr & 0xfffe;
 		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
 		ipmi_data->offset = 1;
 	}
 
-	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr))
+	ipmi_data->slave_addr = readb(&data[6]);
+
+	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
+		dmi_data_entries++;
 		return 0;
+	}
 
 	memset(ipmi_data, 0, sizeof(dmi_ipmi_data_t));
 
 	return -1;
 }
 
-static int dmi_table(u32 base, int len, int num,
-	dmi_ipmi_data_t *ipmi_data)
+static int dmi_table(u32 base, int len, int num)
 {
-	u8 		  *buf;
-	struct dmi_header *dm;
-	u8 		  *data;
+	u8 		  __iomem *buf;
+	struct dmi_header __iomem *dm;
+	u8 		  __iomem *data;
 	int 		  i=1;
 	int		  status=-1;
+	int               intf_num = 0;
 
 	buf = ioremap(base, len);
 	if(buf==NULL)
@@ -1633,20 +1702,21 @@ static int dmi_table(u32 base, int len, 
 
 	while(i<num && (data - buf) < len)
 	{
-		dm=(dmi_header_t *)data;
+		dm=(dmi_header_t __iomem *)data;
 
-		if((data-buf+dm->length) >= len)
+		if((data-buf+readb(&dm->length)) >= len)
         		break;
 
-		if (dm->type == 38) {
-			if (decode_dmi(dm, ipmi_data) == 0) {
-				status = 0;
-				break;
+		if (readb(&dm->type) == 38) {
+			if (decode_dmi(dm, intf_num) == 0) {
+				intf_num++;
+				if (intf_num >= SI_MAX_DRIVERS)
+					break;
 			}
 		}
 
-	        data+=dm->length;
-		while((data-buf) < len && (*data || data[1]))
+	        data+=readb(&dm->length);
+		while((data-buf) < len && (readb(data)||readb(data+1)))
 			data++;
 		data+=2;
 		i++;
@@ -1666,7 +1736,7 @@ inline static int dmi_checksum(u8 *buf)
 	return (sum==0);
 }
 
-static int dmi_iterator(dmi_ipmi_data_t *ipmi_data)
+static int dmi_decode(void)
 {
 	u8   buf[15];
 	u32  fp=0xF0000;
@@ -1684,7 +1754,7 @@ static int dmi_iterator(dmi_ipmi_data_t 
 			u16 len=buf[7]<<8|buf[6];
 			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
 
-			if(dmi_table(base, len, num, ipmi_data) == 0)
+			if(dmi_table(base, len, num) == 0)
 				return 0;
 		}
 		fp+=16;
@@ -1696,16 +1766,13 @@ static int dmi_iterator(dmi_ipmi_data_t 
 static int try_init_smbios(int intf_num, struct smi_info **new_info)
 {
 	struct smi_info   *info;
-	dmi_ipmi_data_t   ipmi_data;
+	dmi_ipmi_data_t   *ipmi_data = dmi_data+intf_num;
 	char              *io_type;
-	int               status;
-
-	status = dmi_iterator(&ipmi_data);
 
-	if (status < 0)
+	if (intf_num >= dmi_data_entries)
 		return -ENODEV;
 
-	switch(ipmi_data.type) {
+	switch(ipmi_data->type) {
 		case 0x01: /* KCS */
 			si_type[intf_num] = "kcs";
 			break;
@@ -1716,7 +1783,6 @@ static int try_init_smbios(int intf_num,
 			si_type[intf_num] = "bt";
 			break;
 		default:
-			printk("ipmi_si: Unknown SMBIOS SI type.\n");
 			return -EIO;
 	}
 
@@ -1727,15 +1793,15 @@ static int try_init_smbios(int intf_num,
 	}
 	memset(info, 0, sizeof(*info));
 
-	if (ipmi_data.addr_space == 1) {
+	if (ipmi_data->addr_space == 1) {
 		io_type = "memory";
 		info->io_setup = mem_setup;
-		addrs[intf_num] = ipmi_data.base_addr;
+		addrs[intf_num] = ipmi_data->base_addr;
 		info->io.info = &(addrs[intf_num]);
-	} else if (ipmi_data.addr_space == 2) {
+	} else if (ipmi_data->addr_space == 2) {
 		io_type = "I/O";
 		info->io_setup = port_setup;
-		ports[intf_num] = ipmi_data.base_addr;
+		ports[intf_num] = ipmi_data->base_addr;
 		info->io.info = &(ports[intf_num]);
 	} else {
 		kfree(info);
@@ -1743,20 +1809,23 @@ static int try_init_smbios(int intf_num,
 		return -EIO;
 	}
 
-	regspacings[intf_num] = ipmi_data.offset;
+	regspacings[intf_num] = ipmi_data->offset;
 	info->io.regspacing = regspacings[intf_num];
 	if (!info->io.regspacing)
 		info->io.regspacing = DEFAULT_REGSPACING;
 	info->io.regsize = DEFAULT_REGSPACING;
 	info->io.regshift = regshifts[intf_num];
 
-	irqs[intf_num] = ipmi_data.irq;
+	info->slave_addr = ipmi_data->slave_addr;
+
+	irqs[intf_num] = ipmi_data->irq;
 
 	*new_info = info;
 
 	printk("ipmi_si: Found SMBIOS-specified state machine at %s"
-	       " address 0x%lx\n",
-	       io_type, (unsigned long)ipmi_data.base_addr);
+	       " address 0x%lx, slave address 0x%x\n",
+	       io_type, (unsigned long)ipmi_data->base_addr,
+	       ipmi_data->slave_addr);
 	return 0;
 }
 #endif /* CONFIG_X86 */
@@ -2121,6 +2190,7 @@ static int init_one_smi(int intf_num, st
 			       new_smi,
 			       new_smi->ipmi_version_major,
 			       new_smi->ipmi_version_minor,
+			       new_smi->slave_addr,
 			       &(new_smi->intf));
 	if (rv) {
 		printk(KERN_ERR
@@ -2174,7 +2244,7 @@ static int init_one_smi(int intf_num, st
 	/* Wait until we know that we are out of any interrupt
 	   handlers might have been running before we freed the
 	   interrupt. */
-	synchronize_kernel();
+	synchronize_sched();
 
 	if (new_smi->si_sm) {
 		if (new_smi->handlers)
@@ -2222,6 +2292,10 @@ static __init int init_ipmi_si(void)
    	        printk(", BT version %s", bt_smi_handlers.version);
 	printk("\n");
 
+#ifdef CONFIG_X86
+	dmi_decode();
+#endif
+
 	rv = init_one_smi(0, &(smi_infos[pos]));
 	if (rv && !ports[0] && si_trydefaults) {
 		/* If we are trying defaults and the initial port is
@@ -2283,7 +2357,7 @@ static void __exit cleanup_one_si(struct
 	/* Wait until we know that we are out of any interrupt
 	   handlers might have been running before we freed the
 	   interrupt. */
-	synchronize_kernel();
+	synchronize_sched();
 
 	/* Wait for the timer to stop.  This avoids problems with race
 	   conditions removing the timer here. */
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -51,7 +51,7 @@ struct si_sm_io
 	/* Generic info used by the actual handling routines, the
            state machine shouldn't touch these. */
 	void *info;
-	void *addr;
+	void __iomem *addr;
 	int  regspacing;
 	int  regsize;
 	int  regshift;
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -709,11 +709,11 @@ static int ipmi_close(struct inode *ino,
 		if (expect_close == 42) {
 			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
-			clear_bit(0, &ipmi_wdog_open);
 		} else {
 			printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
 			ipmi_heartbeat();
 		}
+		clear_bit(0, &ipmi_wdog_open);
 	}
 
 	ipmi_fasync (-1, filep, 0);
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -151,9 +151,6 @@ MODULE_DEVICE_TABLE(pci, isicom_pci_tbl)
 static int prev_card = 3;	/*	start servicing isi_card[0]	*/
 static struct tty_driver *isicom_normal;
 
-static struct isi_board isi_card[BOARD_COUNT];
-static struct isi_port  isi_ports[PORT_COUNT];
-
 static struct timer_list tx;
 static char re_schedule = 1;
 #ifdef ISICOM_DEBUG
@@ -210,6 +207,9 @@ struct	isi_port {
 	int			xmit_cnt;
 };
 
+static struct isi_board isi_card[BOARD_COUNT];
+static struct isi_port  isi_ports[PORT_COUNT];
+
 /*
  *	Locking functions for card level locking. We need to own both
  *	the kernel lock for the card and have the card in a position that
@@ -381,7 +381,7 @@ static struct file_operations ISILoad_fo
 	.ioctl		= ISILoad_ioctl,
 };
 
-struct miscdevice isiloader_device = {
+static struct miscdevice isiloader_device = {
 	ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
 };
 
@@ -1271,7 +1271,7 @@ static void isicom_shutdown_port(struct 
 	}	
 	port->flags &= ~ASYNC_INITIALIZED;
 	/* 3rd October 2000 : Vinayak P Risbud */
-	port->tty = 0;
+	port->tty = NULL;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 	
 	/*Fix done by Anil .S on 30-04-2001
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
+#include <linux/wait.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1068,11 +1069,10 @@ static int stli_open(struct tty_struct *
 	tty->driver_data = portp;
 	portp->refcount++;
 
-	while (test_bit(ST_INITIALIZING, &portp->state)) {
-		if (signal_pending(current))
-			return(-ERESTARTSYS);
-		interruptible_sleep_on(&portp->raw_wait);
-	}
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_INITIALIZING, &portp->state));
+	if (signal_pending(current))
+		return(-ERESTARTSYS);
 
 	if ((portp->flags & ASYNC_INITIALIZED) == 0) {
 		set_bit(ST_INITIALIZING, &portp->state);
@@ -1275,12 +1275,11 @@ static int stli_rawopen(stlibrd_t *brdp,
  *	order of opens and closes may not be preserved across shared
  *	memory, so we must wait until it is complete.
  */
-	while (test_bit(ST_CLOSING, &portp->state)) {
-		if (signal_pending(current)) {
-			restore_flags(flags);
-			return(-ERESTARTSYS);
-		}
-		interruptible_sleep_on(&portp->raw_wait);
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_CLOSING, &portp->state));
+	if (signal_pending(current)) {
+		restore_flags(flags);
+		return -ERESTARTSYS;
 	}
 
 /*
@@ -1309,13 +1308,10 @@ static int stli_rawopen(stlibrd_t *brdp,
  */
 	rc = 0;
 	set_bit(ST_OPENING, &portp->state);
-	while (test_bit(ST_OPENING, &portp->state)) {
-		if (signal_pending(current)) {
-			rc = -ERESTARTSYS;
-			break;
-		}
-		interruptible_sleep_on(&portp->raw_wait);
-	}
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_OPENING, &portp->state));
+	if (signal_pending(current))
+		rc = -ERESTARTSYS;
 	restore_flags(flags);
 
 	if ((rc == 0) && (portp->rc != 0))
@@ -1352,12 +1348,11 @@ static int stli_rawclose(stlibrd_t *brdp
  *	occurs on this port.
  */
 	if (wait) {
-		while (test_bit(ST_CLOSING, &portp->state)) {
-			if (signal_pending(current)) {
-				restore_flags(flags);
-				return(-ERESTARTSYS);
-			}
-			interruptible_sleep_on(&portp->raw_wait);
+		wait_event_interruptible(portp->raw_wait,
+				!test_bit(ST_CLOSING, &portp->state));
+		if (signal_pending(current)) {
+			restore_flags(flags);
+			return -ERESTARTSYS;
 		}
 	}
 
@@ -1385,13 +1380,10 @@ static int stli_rawclose(stlibrd_t *brdp
  *	to come back.
  */
 	rc = 0;
-	while (test_bit(ST_CLOSING, &portp->state)) {
-		if (signal_pending(current)) {
-			rc = -ERESTARTSYS;
-			break;
-		}
-		interruptible_sleep_on(&portp->raw_wait);
-	}
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_CLOSING, &portp->state));
+	if (signal_pending(current))
+		rc = -ERESTARTSYS;
 	restore_flags(flags);
 
 	if ((rc == 0) && (portp->rc != 0))
@@ -1420,22 +1412,20 @@ static int stli_cmdwait(stlibrd_t *brdp,
 
 	save_flags(flags);
 	cli();
-	while (test_bit(ST_CMDING, &portp->state)) {
-		if (signal_pending(current)) {
-			restore_flags(flags);
-			return(-ERESTARTSYS);
-		}
-		interruptible_sleep_on(&portp->raw_wait);
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_CMDING, &portp->state));
+	if (signal_pending(current)) {
+		restore_flags(flags);
+		return -ERESTARTSYS;
 	}
 
 	stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
 
-	while (test_bit(ST_CMDING, &portp->state)) {
-		if (signal_pending(current)) {
-			restore_flags(flags);
-			return(-ERESTARTSYS);
-		}
-		interruptible_sleep_on(&portp->raw_wait);
+	wait_event_interruptible(portp->raw_wait,
+			!test_bit(ST_CMDING, &portp->state));
+	if (signal_pending(current)) {
+		restore_flags(flags);
+		return -ERESTARTSYS;
 	}
 	restore_flags(flags);
 
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -141,7 +141,7 @@ static struct ledptr {
 /* Simple translation table for the SysRq keys */
 
 #ifdef CONFIG_MAGIC_SYSRQ
-unsigned char kbd_sysrq_xlate[KEY_MAX] =
+unsigned char kbd_sysrq_xlate[KEY_MAX + 1] =
         "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
         "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
         "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
@@ -173,7 +173,7 @@ int getkeycode(unsigned int scancode)
 	if (!dev)
 		return -ENODEV;
 
-	if (scancode < 0 || scancode >= dev->keycodemax)
+	if (scancode >= dev->keycodemax)
 		return -EINVAL;
 
 	return INPUT_KEYCODE(dev, scancode);
@@ -183,7 +183,7 @@ int setkeycode(unsigned int scancode, un
 {
 	struct list_head * node;
 	struct input_dev *dev = NULL;
-	int i, oldkey;
+	unsigned int i, oldkey;
 
 	list_for_each(node,&kbd_handler.h_list) {
 		struct input_handle *handle = to_handle_h(node);
@@ -196,7 +196,9 @@ int setkeycode(unsigned int scancode, un
 	if (!dev)
 		return -ENODEV;
 
-	if (scancode < 0 || scancode >= dev->keycodemax)
+	if (scancode >= dev->keycodemax)
+		return -EINVAL;
+	if (keycode > KEY_MAX)
 		return -EINVAL;
 	if (keycode < 0 || keycode > KEY_MAX)
 		return -EINVAL;
@@ -355,7 +357,7 @@ static void to_utf8(struct vc_data *vc, 
  */
 void compute_shiftstate(void)
 {
-	int i, j, k, sym, val;
+	unsigned int i, j, k, sym, val;
 
 	shift_state = 0;
 	memset(shift_down, 0, sizeof(shift_down));
@@ -396,7 +398,7 @@ void compute_shiftstate(void)
 static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch)
 {
 	int d = diacr;
-	int i;
+	unsigned int i;
 
 	diacr = 0;
 
@@ -536,12 +538,12 @@ static void fn_send_intr(struct vc_data 
 
 static void fn_scroll_forw(struct vc_data *vc, struct pt_regs *regs)
 {
-	scrollfront(0);
+	scrollfront(vc, 0);
 }
 
 static void fn_scroll_back(struct vc_data *vc, struct pt_regs *regs)
 {
-	scrollback(0);
+	scrollback(vc, 0);
 }
 
 static void fn_show_mem(struct vc_data *vc, struct pt_regs *regs)
@@ -581,7 +583,7 @@ static void fn_SAK(struct vc_data *vc, s
 	 */
 	if (tty)
 		do_SAK(tty);
-	reset_vc(fg_console);
+	reset_vc(vc);
 }
 
 static void fn_null(struct vc_data *vc, struct pt_regs *regs)
@@ -931,7 +933,7 @@ static void kbd_refresh_leds(struct inpu
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
     defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) ||\
     defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_RPC))
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
 
 #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
 			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
@@ -1024,7 +1026,8 @@ static void kbd_rawcode(unsigned char da
 		put_queue(vc, data);
 }
 
-void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs)
+static void kbd_keycode(unsigned int keycode, int down,
+			int hw_raw, struct pt_regs *regs)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
 	unsigned short keysym, *key_map;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -12,7 +12,7 @@
  * "lp=" command line parameters added by Grant Guenther, grant@torque.net
  * lp_read (Status readback) support added by Carsten Gross,
  *                                             carsten@sol.wohnheim.uni-ulm.de
- * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
+ * Support for parport by Philip Blundell <philb@gnu.org>
  * Parport sharing hacking by Andrea Arcangeli
  * Fixed kernel_(to/from)_user memory copy to check for errors
  * 				by Riccardo Facchetti <fizban@tin.it>
@@ -127,6 +127,7 @@
 #include <linux/poll.h>
 #include <linux/console.h>
 #include <linux/device.h>
+#include <linux/wait.h>
 
 #include <linux/parport.h>
 #undef LP_STATS
@@ -218,6 +219,7 @@ static int lp_reset(int minor)
 
 static void lp_error (int minor)
 {
+	DEFINE_WAIT(wait);
 	int polling;
 
 	if (LP_F(minor) & LP_ABORT)
@@ -225,8 +227,9 @@ static void lp_error (int minor)
 
 	polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
 	if (polling) lp_release_parport (&lp_table[minor]);
-	interruptible_sleep_on_timeout (&lp_table[minor].waitq,
-					LP_TIMEOUT_POLLED);
+	prepare_to_wait(&lp_table[minor].waitq, &wait, TASK_INTERRUPTIBLE);
+	schedule_timeout(LP_TIMEOUT_POLLED);
+	finish_wait(&lp_table[minor].waitq, &wait);
 	if (polling) lp_claim_parport_or_block (&lp_table[minor]);
 	else parport_yield_blocking (lp_table[minor].dev);
 }
@@ -314,12 +317,14 @@ static ssize_t lp_write(struct file * fi
 	if (copy_size > LP_BUFFER_SIZE)
 		copy_size = LP_BUFFER_SIZE;
 
-	if (copy_from_user (kbuf, buf, copy_size))
-		return -EFAULT;
-
 	if (down_interruptible (&lp_table[minor].port_mutex))
 		return -EINTR;
 
+	if (copy_from_user (kbuf, buf, copy_size)) {
+		retv = -EFAULT;
+		goto out_unlock;
+	}
+
  	/* Claim Parport or sleep until it becomes available
  	 */
 	lp_claim_parport_or_block (&lp_table[minor]);
@@ -398,7 +403,7 @@ static ssize_t lp_write(struct file * fi
 		lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
 		lp_release_parport (&lp_table[minor]);
 	}
-
+out_unlock:
 	up (&lp_table[minor].port_mutex);
 
  	return retv;
@@ -410,6 +415,7 @@ static ssize_t lp_write(struct file * fi
 static ssize_t lp_read(struct file * file, char __user * buf,
 		       size_t count, loff_t *ppos)
 {
+	DEFINE_WAIT(wait);
 	unsigned int minor=iminor(file->f_dentry->d_inode);
 	struct parport *port = lp_table[minor].dev->port;
 	ssize_t retval = 0;
@@ -458,9 +464,11 @@ static ssize_t lp_read(struct file * fil
 				retval = -EIO;
 				goto out;
 			}
-		} else
-			interruptible_sleep_on_timeout (&lp_table[minor].waitq,
-							LP_TIMEOUT_POLLED);
+		} else {
+			prepare_to_wait(&lp_table[minor].waitq, &wait, TASK_INTERRUPTIBLE);
+			schedule_timeout(LP_TIMEOUT_POLLED);
+			finish_wait(&lp_table[minor].waitq, &wait);
+		}
 
 		if (signal_pending (current)) {
 			retval = -ERESTARTSYS;
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/mbcs.c
@@ -0,0 +1,849 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/*
+ *	MOATB Core Services driver.
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/uio.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/tiocx.h>
+#include "mbcs.h"
+
+#define MBCS_DEBUG 0
+#if MBCS_DEBUG
+#define DBG(fmt...)    printk(KERN_ALERT fmt)
+#else
+#define DBG(fmt...)
+#endif
+int mbcs_major;
+
+LIST_HEAD(soft_list);
+
+/*
+ * file operations
+ */
+struct file_operations mbcs_ops = {
+	.open = mbcs_open,
+	.llseek = mbcs_sram_llseek,
+	.read = mbcs_sram_read,
+	.write = mbcs_sram_write,
+	.mmap = mbcs_gscr_mmap,
+};
+
+struct mbcs_callback_arg {
+	int minor;
+	struct cx_dev *cx_dev;
+};
+
+static inline void mbcs_getdma_init(struct getdma *gdma)
+{
+	memset(gdma, 0, sizeof(struct getdma));
+	gdma->DoneIntEnable = 1;
+}
+
+static inline void mbcs_putdma_init(struct putdma *pdma)
+{
+	memset(pdma, 0, sizeof(struct putdma));
+	pdma->DoneIntEnable = 1;
+}
+
+static inline void mbcs_algo_init(struct algoblock *algo_soft)
+{
+	memset(algo_soft, 0, sizeof(struct algoblock));
+}
+
+static inline void mbcs_getdma_set(void *mmr,
+		       uint64_t hostAddr,
+		       uint64_t localAddr,
+		       uint64_t localRamSel,
+		       uint64_t numPkts,
+		       uint64_t amoEnable,
+		       uint64_t intrEnable,
+		       uint64_t peerIO,
+		       uint64_t amoHostDest,
+		       uint64_t amoModType, uint64_t intrHostDest,
+		       uint64_t intrVector)
+{
+	union dma_control rdma_control;
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union dma_localaddr local_addr;
+	union dma_hostaddr host_addr;
+
+	rdma_control.dma_control_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	local_addr.dma_localaddr_reg = 0;
+	host_addr.dma_hostaddr_reg = 0;
+
+	host_addr.dma_sys_addr = hostAddr;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
+
+	local_addr.dma_ram_addr = localAddr;
+	local_addr.dma_ram_sel = localRamSel;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
+
+	rdma_control.dma_op_length = numPkts;
+	rdma_control.done_amo_en = amoEnable;
+	rdma_control.done_int_en = intrEnable;
+	rdma_control.pio_mem_n = peerIO;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg);
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg);
+
+}
+
+static inline void mbcs_putdma_set(void *mmr,
+		       uint64_t hostAddr,
+		       uint64_t localAddr,
+		       uint64_t localRamSel,
+		       uint64_t numPkts,
+		       uint64_t amoEnable,
+		       uint64_t intrEnable,
+		       uint64_t peerIO,
+		       uint64_t amoHostDest,
+		       uint64_t amoModType,
+		       uint64_t intrHostDest, uint64_t intrVector)
+{
+	union dma_control wdma_control;
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union dma_localaddr local_addr;
+	union dma_hostaddr host_addr;
+
+	wdma_control.dma_control_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	local_addr.dma_localaddr_reg = 0;
+	host_addr.dma_hostaddr_reg = 0;
+
+	host_addr.dma_sys_addr = hostAddr;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
+
+	local_addr.dma_ram_addr = localAddr;
+	local_addr.dma_ram_sel = localRamSel;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
+
+	wdma_control.dma_op_length = numPkts;
+	wdma_control.done_amo_en = amoEnable;
+	wdma_control.done_int_en = intrEnable;
+	wdma_control.pio_mem_n = peerIO;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg);
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg);
+
+}
+
+static inline void mbcs_algo_set(void *mmr,
+		     uint64_t amoHostDest,
+		     uint64_t amoModType,
+		     uint64_t intrHostDest,
+		     uint64_t intrVector, uint64_t algoStepCount)
+{
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union algo_step step;
+
+	step.algo_step_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg);
+
+	step.alg_step_cnt = algoStepCount;
+	MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg);
+}
+
+static inline int mbcs_getdma_start(struct mbcs_soft *soft)
+{
+	void *mmr_base;
+	struct getdma *gdma;
+	uint64_t numPkts;
+	union cm_control cm_control;
+
+	mmr_base = soft->mmr_base;
+	gdma = &soft->getdma;
+
+	/* check that host address got setup */
+	if (!gdma->hostAddr)
+		return -1;
+
+	numPkts =
+	    (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
+
+	/* program engine */
+	mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr),
+		   gdma->localAddr,
+		   (gdma->localAddr < MB2) ? 0 :
+		   (gdma->localAddr < MB4) ? 1 :
+		   (gdma->localAddr < MB6) ? 2 : 3,
+		   numPkts,
+		   gdma->DoneAmoEnable,
+		   gdma->DoneIntEnable,
+		   gdma->peerIO,
+		   gdma->amoHostDest,
+		   gdma->amoModType,
+		   gdma->intrHostDest, gdma->intrVector);
+
+	/* start engine */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.rd_dma_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+
+}
+
+static inline int mbcs_putdma_start(struct mbcs_soft *soft)
+{
+	void *mmr_base;
+	struct putdma *pdma;
+	uint64_t numPkts;
+	union cm_control cm_control;
+
+	mmr_base = soft->mmr_base;
+	pdma = &soft->putdma;
+
+	/* check that host address got setup */
+	if (!pdma->hostAddr)
+		return -1;
+
+	numPkts =
+	    (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
+
+	/* program engine */
+	mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr),
+		   pdma->localAddr,
+		   (pdma->localAddr < MB2) ? 0 :
+		   (pdma->localAddr < MB4) ? 1 :
+		   (pdma->localAddr < MB6) ? 2 : 3,
+		   numPkts,
+		   pdma->DoneAmoEnable,
+		   pdma->DoneIntEnable,
+		   pdma->peerIO,
+		   pdma->amoHostDest,
+		   pdma->amoModType,
+		   pdma->intrHostDest, pdma->intrVector);
+
+	/* start engine */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.wr_dma_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+
+}
+
+static inline int mbcs_algo_start(struct mbcs_soft *soft)
+{
+	struct algoblock *algo_soft = &soft->algo;
+	void *mmr_base = soft->mmr_base;
+	union cm_control cm_control;
+
+	if (down_interruptible(&soft->algolock))
+		return -ERESTARTSYS;
+
+	atomic_set(&soft->algo_done, 0);
+
+	mbcs_algo_set(mmr_base,
+		 algo_soft->amoHostDest,
+		 algo_soft->amoModType,
+		 algo_soft->intrHostDest,
+		 algo_soft->intrVector, algo_soft->algoStepCount);
+
+	/* start algorithm */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.alg_done_int_en = 1;
+	cm_control.alg_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	up(&soft->algolock);
+
+	return 0;
+}
+
+static inline ssize_t
+do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
+		      size_t len, loff_t * off)
+{
+	int rv = 0;
+
+	if (down_interruptible(&soft->dmawritelock))
+		return -ERESTARTSYS;
+
+	atomic_set(&soft->dmawrite_done, 0);
+
+	soft->putdma.hostAddr = hostAddr;
+	soft->putdma.localAddr = *off;
+	soft->putdma.bytes = len;
+
+	if (mbcs_putdma_start(soft) < 0) {
+		DBG(KERN_ALERT "do_mbcs_sram_dmawrite: "
+					"mbcs_putdma_start failed\n");
+		rv = -EAGAIN;
+		goto dmawrite_exit;
+	}
+
+	if (wait_event_interruptible(soft->dmawrite_queue,
+					atomic_read(&soft->dmawrite_done))) {
+		rv = -ERESTARTSYS;
+		goto dmawrite_exit;
+	}
+
+	rv = len;
+	*off += len;
+
+dmawrite_exit:
+	up(&soft->dmawritelock);
+
+	return rv;
+}
+
+static inline ssize_t
+do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
+		     size_t len, loff_t * off)
+{
+	int rv = 0;
+
+	if (down_interruptible(&soft->dmareadlock))
+		return -ERESTARTSYS;
+
+	atomic_set(&soft->dmawrite_done, 0);
+
+	soft->getdma.hostAddr = hostAddr;
+	soft->getdma.localAddr = *off;
+	soft->getdma.bytes = len;
+
+	if (mbcs_getdma_start(soft) < 0) {
+		DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n");
+		rv = -EAGAIN;
+		goto dmaread_exit;
+	}
+
+	if (wait_event_interruptible(soft->dmaread_queue,
+					atomic_read(&soft->dmaread_done))) {
+		rv = -ERESTARTSYS;
+		goto dmaread_exit;
+	}
+
+	rv = len;
+	*off += len;
+
+dmaread_exit:
+	up(&soft->dmareadlock);
+
+	return rv;
+}
+
+int mbcs_open(struct inode *ip, struct file *fp)
+{
+	struct mbcs_soft *soft;
+	int minor;
+
+	minor = iminor(ip);
+
+	list_for_each_entry(soft, &soft_list, list) {
+		if (soft->nasid == minor) {
+			fp->private_data = soft->cxdev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft *soft = cx_dev->soft;
+	uint64_t hostAddr;
+	int rv = 0;
+
+	hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
+	if (hostAddr == 0)
+		return -ENOMEM;
+
+	rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off);
+	if (rv < 0)
+		goto exit;
+
+	if (copy_to_user(buf, (void *)hostAddr, len))
+		rv = -EFAULT;
+
+      exit:
+	free_pages(hostAddr, get_order(len));
+
+	return rv;
+}
+
+ssize_t
+mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft *soft = cx_dev->soft;
+	uint64_t hostAddr;
+	int rv = 0;
+
+	hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
+	if (hostAddr == 0)
+		return -ENOMEM;
+
+	if (copy_from_user((void *)hostAddr, buf, len)) {
+		rv = -EFAULT;
+		goto exit;
+	}
+
+	rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off);
+
+      exit:
+	free_pages(hostAddr, get_order(len));
+
+	return rv;
+}
+
+loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+{
+	loff_t newpos;
+
+	switch (whence) {
+	case 0:		/* SEEK_SET */
+		newpos = off;
+		break;
+
+	case 1:		/* SEEK_CUR */
+		newpos = filp->f_pos + off;
+		break;
+
+	case 2:		/* SEEK_END */
+		newpos = MBCS_SRAM_SIZE + off;
+		break;
+
+	default:		/* can't happen */
+		return -EINVAL;
+	}
+
+	if (newpos < 0)
+		return -EINVAL;
+
+	filp->f_pos = newpos;
+
+	return newpos;
+}
+
+static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset)
+{
+	uint64_t mmr_base;
+
+	mmr_base = (uint64_t) (soft->mmr_base + offset);
+
+	return mmr_base;
+}
+
+static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft)
+{
+	soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START);
+}
+
+static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
+{
+	soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
+}
+
+int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft *soft = cx_dev->soft;
+
+	if (vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
+	if (remap_pfn_range(vma,
+			    vma->vm_start,
+			    __pa(soft->gscr_addr) >> PAGE_SHIFT,
+			    PAGE_SIZE,
+			    vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+/**
+ * mbcs_completion_intr_handler - Primary completion handler.
+ * @irq: irq
+ * @arg: soft struct for device
+ * @ep: regs
+ *
+ */
+static irqreturn_t
+mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep)
+{
+	struct mbcs_soft *soft = (struct mbcs_soft *)arg;
+	void *mmr_base;
+	union cm_status cm_status;
+	union cm_control cm_control;
+
+	mmr_base = soft->mmr_base;
+	cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS);
+
+	if (cm_status.rd_dma_done) {
+		/* stop dma-read engine, clear status */
+		cm_control.cm_control_reg =
+		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.rd_dma_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		atomic_set(&soft->dmaread_done, 1);
+		wake_up(&soft->dmaread_queue);
+	}
+	if (cm_status.wr_dma_done) {
+		/* stop dma-write engine, clear status */
+		cm_control.cm_control_reg =
+		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.wr_dma_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		atomic_set(&soft->dmawrite_done, 1);
+		wake_up(&soft->dmawrite_queue);
+	}
+	if (cm_status.alg_done) {
+		/* clear status */
+		cm_control.cm_control_reg =
+		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.alg_done_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		atomic_set(&soft->algo_done, 1);
+		wake_up(&soft->algo_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * mbcs_intr_alloc - Allocate interrupts.
+ * @dev: device pointer
+ *
+ */
+static int mbcs_intr_alloc(struct cx_dev *dev)
+{
+	struct sn_irq_info *sn_irq;
+	struct mbcs_soft *soft;
+	struct getdma *getdma;
+	struct putdma *putdma;
+	struct algoblock *algo;
+
+	soft = dev->soft;
+	getdma = &soft->getdma;
+	putdma = &soft->putdma;
+	algo = &soft->algo;
+
+	soft->get_sn_irq = NULL;
+	soft->put_sn_irq = NULL;
+	soft->algo_sn_irq = NULL;
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq == NULL)
+		return -EAGAIN;
+	soft->get_sn_irq = sn_irq;
+	getdma->intrHostDest = sn_irq->irq_xtalkaddr;
+	getdma->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS get intr", (void *)soft)) {
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq == NULL) {
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+	soft->put_sn_irq = sn_irq;
+	putdma->intrHostDest = sn_irq->irq_xtalkaddr;
+	putdma->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS put intr", (void *)soft)) {
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq == NULL) {
+		free_irq(soft->put_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+	soft->algo_sn_irq = sn_irq;
+	algo->intrHostDest = sn_irq->irq_xtalkaddr;
+	algo->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS algo intr", (void *)soft)) {
+		tiocx_irq_free(soft->algo_sn_irq);
+		free_irq(soft->put_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/**
+ * mbcs_intr_dealloc - Remove interrupts.
+ * @dev: device pointer
+ *
+ */
+static void mbcs_intr_dealloc(struct cx_dev *dev)
+{
+	struct mbcs_soft *soft;
+
+	soft = dev->soft;
+
+	free_irq(soft->get_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->get_sn_irq);
+	free_irq(soft->put_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->put_sn_irq);
+	free_irq(soft->algo_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->algo_sn_irq);
+}
+
+static inline int mbcs_hw_init(struct mbcs_soft *soft)
+{
+	void *mmr_base = soft->mmr_base;
+	union cm_control cm_control;
+	union cm_req_timeout cm_req_timeout;
+	uint64_t err_stat;
+
+	cm_req_timeout.cm_req_timeout_reg =
+	    MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT);
+
+	cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT,
+		     cm_req_timeout.cm_req_timeout_reg);
+
+	mbcs_gscr_pioaddr_set(soft);
+	mbcs_debug_pioaddr_set(soft);
+
+	/* clear errors */
+	err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT);
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat);
+	MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1);
+
+	/* enable interrupts */
+	/* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */
+	MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL);
+
+	/* arm status regs and clear engines */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.rearm_stat_regs = 1;
+	cm_control.alg_clr = 1;
+	cm_control.wr_dma_clr = 1;
+	cm_control.rd_dma_clr = 1;
+
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+}
+
+static ssize_t show_algo(struct device *dev, char *buf)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct mbcs_soft *soft = cx_dev->soft;
+	uint64_t debug0;
+
+	/*
+	 * By convention, the first debug register contains the
+	 * algorithm number and revision.
+	 */
+	debug0 = *(uint64_t *) soft->debug_addr;
+
+	return sprintf(buf, "0x%lx 0x%lx\n",
+		       (debug0 >> 32), (debug0 & 0xffffffff));
+}
+
+static ssize_t store_algo(struct device *dev, const char *buf, size_t count)
+{
+	int n;
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct mbcs_soft *soft = cx_dev->soft;
+
+	if (count <= 0)
+		return 0;
+
+	n = simple_strtoul(buf, NULL, 0);
+
+	if (n == 1) {
+		mbcs_algo_start(soft);
+		if (wait_event_interruptible(soft->algo_queue,
+					atomic_read(&soft->algo_done)))
+			return -ERESTARTSYS;
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(algo, 0644, show_algo, store_algo);
+
+/**
+ * mbcs_probe - Initialize for device
+ * @dev: device pointer
+ * @device_id: id table pointer
+ *
+ */
+static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
+{
+	struct mbcs_soft *soft;
+
+	dev->soft = NULL;
+
+	soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL);
+	if (soft == NULL)
+		return -ENOMEM;
+
+	soft->nasid = dev->cx_id.nasid;
+	list_add(&soft->list, &soft_list);
+	soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid);
+	dev->soft = soft;
+	soft->cxdev = dev;
+
+	init_waitqueue_head(&soft->dmawrite_queue);
+	init_waitqueue_head(&soft->dmaread_queue);
+	init_waitqueue_head(&soft->algo_queue);
+
+	init_MUTEX(&soft->dmawritelock);
+	init_MUTEX(&soft->dmareadlock);
+	init_MUTEX(&soft->algolock);
+
+	mbcs_getdma_init(&soft->getdma);
+	mbcs_putdma_init(&soft->putdma);
+	mbcs_algo_init(&soft->algo);
+
+	mbcs_hw_init(soft);
+
+	/* Allocate interrupts */
+	mbcs_intr_alloc(dev);
+
+	device_create_file(&dev->dev, &dev_attr_algo);
+
+	return 0;
+}
+
+static int mbcs_remove(struct cx_dev *dev)
+{
+	if (dev->soft) {
+		mbcs_intr_dealloc(dev);
+		kfree(dev->soft);
+	}
+
+	device_remove_file(&dev->dev, &dev_attr_algo);
+
+	return 0;
+}
+
+const struct cx_device_id __devinitdata mbcs_id_table[] = {
+	{
+	 .part_num = MBCS_PART_NUM,
+	 .mfg_num = MBCS_MFG_NUM,
+	 },
+	{
+	 .part_num = MBCS_PART_NUM_ALG0,
+	 .mfg_num = MBCS_MFG_NUM,
+	 },
+	{0, 0}
+};
+
+MODULE_DEVICE_TABLE(cx, mbcs_id_table);
+
+struct cx_drv mbcs_driver = {
+	.name = DEVICE_NAME,
+	.id_table = mbcs_id_table,
+	.probe = mbcs_probe,
+	.remove = mbcs_remove,
+};
+
+static void __exit mbcs_exit(void)
+{
+	int rv;
+
+	rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
+	if (rv < 0)
+		DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
+
+	cx_driver_unregister(&mbcs_driver);
+}
+
+static int __init mbcs_init(void)
+{
+	int rv;
+
+	// Put driver into chrdevs[].  Get major number.
+	rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops);
+	if (rv < 0) {
+		DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv);
+		return rv;
+	}
+	mbcs_major = rv;
+
+	return cx_driver_register(&mbcs_driver);
+}
+
+module_init(mbcs_init);
+module_exit(mbcs_exit);
+
+MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
+MODULE_DESCRIPTION("Driver for MOATB Core Services");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
new file mode 100644
--- /dev/null
+++ b/drivers/char/mbcs.h
@@ -0,0 +1,553 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#ifndef __MBCS_H__
+#define __MBCS_H__
+
+/*
+ * General macros
+ */
+#define MB	(1024*1024)
+#define MB2	(2*MB)
+#define MB4	(4*MB)
+#define MB6	(6*MB)
+
+/*
+ * Offsets and masks
+ */
+#define MBCS_CM_ID		0x0000	/* Identification */
+#define MBCS_CM_STATUS		0x0008	/* Status */
+#define MBCS_CM_ERROR_DETAIL1	0x0010	/* Error Detail1 */
+#define MBCS_CM_ERROR_DETAIL2	0x0018	/* Error Detail2 */
+#define MBCS_CM_CONTROL		0x0020	/* Control */
+#define MBCS_CM_REQ_TOUT	0x0028	/* Request Time-out */
+#define MBCS_CM_ERR_INT_DEST	0x0038	/* Error Interrupt Destination */
+#define MBCS_CM_TARG_FL		0x0050	/* Target Flush */
+#define MBCS_CM_ERR_STAT	0x0060	/* Error Status */
+#define MBCS_CM_CLR_ERR_STAT	0x0068	/* Clear Error Status */
+#define MBCS_CM_ERR_INT_EN	0x0070	/* Error Interrupt Enable */
+#define MBCS_RD_DMA_SYS_ADDR	0x0100	/* Read DMA System Address */
+#define MBCS_RD_DMA_LOC_ADDR	0x0108	/* Read DMA Local Address */
+#define MBCS_RD_DMA_CTRL	0x0110	/* Read DMA Control */
+#define MBCS_RD_DMA_AMO_DEST	0x0118	/* Read DMA AMO Destination */
+#define MBCS_RD_DMA_INT_DEST	0x0120	/* Read DMA Interrupt Destination */
+#define MBCS_RD_DMA_AUX_STAT	0x0130	/* Read DMA Auxillary Status */
+#define MBCS_WR_DMA_SYS_ADDR	0x0200	/* Write DMA System Address */
+#define MBCS_WR_DMA_LOC_ADDR	0x0208	/* Write DMA Local Address */
+#define MBCS_WR_DMA_CTRL	0x0210	/* Write DMA Control */
+#define MBCS_WR_DMA_AMO_DEST	0x0218	/* Write DMA AMO Destination */
+#define MBCS_WR_DMA_INT_DEST	0x0220	/* Write DMA Interrupt Destination */
+#define MBCS_WR_DMA_AUX_STAT	0x0230	/* Write DMA Auxillary Status */
+#define MBCS_ALG_AMO_DEST	0x0300	/* Algorithm AMO Destination */
+#define MBCS_ALG_INT_DEST	0x0308	/* Algorithm Interrupt Destination */
+#define MBCS_ALG_OFFSETS	0x0310
+#define MBCS_ALG_STEP		0x0318	/* Algorithm Step */
+
+#define MBCS_GSCR_START		0x0000000
+#define MBCS_DEBUG_START	0x0100000
+#define MBCS_RAM0_START		0x0200000
+#define MBCS_RAM1_START		0x0400000
+#define MBCS_RAM2_START		0x0600000
+
+#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL
+//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL
+
+#define MBCS_SRAM_SIZE		(1024*1024)
+#define MBCS_CACHELINE_SIZE	128
+
+/*
+ * MMR get's and put's
+ */
+#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset))
+#define MBCS_MMR_SET(mmr_base, offset, value) {			\
+	uint64_t *mbcs_mmr_set_u64p, readback;				\
+	mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset);	\
+	*mbcs_mmr_set_u64p = value;					\
+	readback = *mbcs_mmr_set_u64p; \
+}
+#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset)
+#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0)
+
+/*
+ * MBCS mmr structures
+ */
+union cm_id {
+	uint64_t cm_id_reg;
+	struct {
+		uint64_t always_one:1,	// 0
+		 mfg_id:11,	// 11:1
+		 part_num:16,	// 27:12
+		 bitstream_rev:8,	// 35:28
+		:28;		// 63:36
+	};
+};
+
+union cm_status {
+	uint64_t cm_status_reg;
+	struct {
+		uint64_t pending_reads:8,	// 7:0
+		 pending_writes:8,	// 15:8
+		 ice_rsp_credits:8,	// 23:16
+		 ice_req_credits:8,	// 31:24
+		 cm_req_credits:8,	// 39:32
+		:1,		// 40
+		 rd_dma_in_progress:1,	// 41
+		 rd_dma_done:1,	// 42
+		:1,		// 43
+		 wr_dma_in_progress:1,	// 44
+		 wr_dma_done:1,	// 45
+		 alg_waiting:1,	// 46
+		 alg_pipe_running:1,	// 47
+		 alg_done:1,	// 48
+		:3,		// 51:49
+		 pending_int_reqs:8,	// 59:52
+		:3,		// 62:60
+		 alg_half_speed_sel:1;	// 63
+	};
+};
+
+union cm_error_detail1 {
+	uint64_t cm_error_detail1_reg;
+	struct {
+		uint64_t packet_type:4,	// 3:0
+		 source_id:2,	// 5:4
+		 data_size:2,	// 7:6
+		 tnum:8,	// 15:8
+		 byte_enable:8,	// 23:16
+		 gfx_cred:8,	// 31:24
+		 read_type:2,	// 33:32
+		 pio_or_memory:1,	// 34
+		 head_cw_error:1,	// 35
+		:12,		// 47:36
+		 head_error_bit:1,	// 48
+		 data_error_bit:1,	// 49
+		:13,		// 62:50
+		 valid:1;	// 63
+	};
+};
+
+union cm_error_detail2 {
+	uint64_t cm_error_detail2_reg;
+	struct {
+		uint64_t address:56,	// 55:0
+		:8;		// 63:56
+	};
+};
+
+union cm_control {
+	uint64_t cm_control_reg;
+	struct {
+		uint64_t cm_id:2,	// 1:0
+		:2,		// 3:2
+		 max_trans:5,	// 8:4
+		:3,		// 11:9
+		 address_mode:1,	// 12
+		:7,		// 19:13
+		 credit_limit:8,	// 27:20
+		:5,		// 32:28
+		 rearm_stat_regs:1,	// 33
+		 prescalar_byp:1,	// 34
+		 force_gap_war:1,	// 35
+		 rd_dma_go:1,	// 36
+		 wr_dma_go:1,	// 37
+		 alg_go:1,	// 38
+		 rd_dma_clr:1,	// 39
+		 wr_dma_clr:1,	// 40
+		 alg_clr:1,	// 41
+		:2,		// 43:42
+		 alg_wait_step:1,	// 44
+		 alg_done_amo_en:1,	// 45
+		 alg_done_int_en:1,	// 46
+		:1,		// 47
+		 alg_sram0_locked:1,	// 48
+		 alg_sram1_locked:1,	// 49
+		 alg_sram2_locked:1,	// 50
+		 alg_done_clr:1,	// 51
+		:12;		// 63:52
+	};
+};
+
+union cm_req_timeout {
+	uint64_t cm_req_timeout_reg;
+	struct {
+		uint64_t time_out:24,	// 23:0
+		:40;		// 63:24
+	};
+};
+
+union intr_dest {
+	uint64_t intr_dest_reg;
+	struct {
+		uint64_t address:56,	// 55:0
+		 int_vector:8;	// 63:56
+	};
+};
+
+union cm_error_status {
+	uint64_t cm_error_status_reg;
+	struct {
+		uint64_t ecc_sbe:1,	// 0
+		 ecc_mbe:1,	// 1
+		 unsupported_req:1,	// 2
+		 unexpected_rsp:1,	// 3
+		 bad_length:1,	// 4
+		 bad_datavalid:1,	// 5
+		 buffer_overflow:1,	// 6
+		 request_timeout:1,	// 7
+		:8,		// 15:8
+		 head_inv_data_size:1,	// 16
+		 rsp_pactype_inv:1,	// 17
+		 head_sb_err:1,	// 18
+		 missing_head:1,	// 19
+		 head_inv_rd_type:1,	// 20
+		 head_cmd_err_bit:1,	// 21
+		 req_addr_align_inv:1,	// 22
+		 pio_req_addr_inv:1,	// 23
+		 req_range_dsize_inv:1,	// 24
+		 early_term:1,	// 25
+		 early_tail:1,	// 26
+		 missing_tail:1,	// 27
+		 data_flit_sb_err:1,	// 28
+		 cm2hcm_req_cred_of:1,	// 29
+		 cm2hcm_rsp_cred_of:1,	// 30
+		 rx_bad_didn:1,	// 31
+		 rd_dma_err_rsp:1,	// 32
+		 rd_dma_tnum_tout:1,	// 33
+		 rd_dma_multi_tnum_tou:1,	// 34
+		 wr_dma_err_rsp:1,	// 35
+		 wr_dma_tnum_tout:1,	// 36
+		 wr_dma_multi_tnum_tou:1,	// 37
+		 alg_data_overflow:1,	// 38
+		 alg_data_underflow:1,	// 39
+		 ram0_access_conflict:1,	// 40
+		 ram1_access_conflict:1,	// 41
+		 ram2_access_conflict:1,	// 42
+		 ram0_perr:1,	// 43
+		 ram1_perr:1,	// 44
+		 ram2_perr:1,	// 45
+		 int_gen_rsp_err:1,	// 46
+		 int_gen_tnum_tout:1,	// 47
+		 rd_dma_prog_err:1,	// 48
+		 wr_dma_prog_err:1,	// 49
+		:14;		// 63:50
+	};
+};
+
+union cm_clr_error_status {
+	uint64_t cm_clr_error_status_reg;
+	struct {
+		uint64_t clr_ecc_sbe:1,	// 0
+		 clr_ecc_mbe:1,	// 1
+		 clr_unsupported_req:1,	// 2
+		 clr_unexpected_rsp:1,	// 3
+		 clr_bad_length:1,	// 4
+		 clr_bad_datavalid:1,	// 5
+		 clr_buffer_overflow:1,	// 6
+		 clr_request_timeout:1,	// 7
+		:8,		// 15:8
+		 clr_head_inv_data_siz:1,	// 16
+		 clr_rsp_pactype_inv:1,	// 17
+		 clr_head_sb_err:1,	// 18
+		 clr_missing_head:1,	// 19
+		 clr_head_inv_rd_type:1,	// 20
+		 clr_head_cmd_err_bit:1,	// 21
+		 clr_req_addr_align_in:1,	// 22
+		 clr_pio_req_addr_inv:1,	// 23
+		 clr_req_range_dsize_i:1,	// 24
+		 clr_early_term:1,	// 25
+		 clr_early_tail:1,	// 26
+		 clr_missing_tail:1,	// 27
+		 clr_data_flit_sb_err:1,	// 28
+		 clr_cm2hcm_req_cred_o:1,	// 29
+		 clr_cm2hcm_rsp_cred_o:1,	// 30
+		 clr_rx_bad_didn:1,	// 31
+		 clr_rd_dma_err_rsp:1,	// 32
+		 clr_rd_dma_tnum_tout:1,	// 33
+		 clr_rd_dma_multi_tnum:1,	// 34
+		 clr_wr_dma_err_rsp:1,	// 35
+		 clr_wr_dma_tnum_tout:1,	// 36
+		 clr_wr_dma_multi_tnum:1,	// 37
+		 clr_alg_data_overflow:1,	// 38
+		 clr_alg_data_underflo:1,	// 39
+		 clr_ram0_access_confl:1,	// 40
+		 clr_ram1_access_confl:1,	// 41
+		 clr_ram2_access_confl:1,	// 42
+		 clr_ram0_perr:1,	// 43
+		 clr_ram1_perr:1,	// 44
+		 clr_ram2_perr:1,	// 45
+		 clr_int_gen_rsp_err:1,	// 46
+		 clr_int_gen_tnum_tout:1,	// 47
+		 clr_rd_dma_prog_err:1,	// 48
+		 clr_wr_dma_prog_err:1,	// 49
+		:14;		// 63:50
+	};
+};
+
+union cm_error_intr_enable {
+	uint64_t cm_error_intr_enable_reg;
+	struct {
+		uint64_t int_en_ecc_sbe:1,	// 0
+		 int_en_ecc_mbe:1,	// 1
+		 int_en_unsupported_re:1,	// 2
+		 int_en_unexpected_rsp:1,	// 3
+		 int_en_bad_length:1,	// 4
+		 int_en_bad_datavalid:1,	// 5
+		 int_en_buffer_overflo:1,	// 6
+		 int_en_request_timeou:1,	// 7
+		:8,		// 15:8
+		 int_en_head_inv_data_:1,	// 16
+		 int_en_rsp_pactype_in:1,	// 17
+		 int_en_head_sb_err:1,	// 18
+		 int_en_missing_head:1,	// 19
+		 int_en_head_inv_rd_ty:1,	// 20
+		 int_en_head_cmd_err_b:1,	// 21
+		 int_en_req_addr_align:1,	// 22
+		 int_en_pio_req_addr_i:1,	// 23
+		 int_en_req_range_dsiz:1,	// 24
+		 int_en_early_term:1,	// 25
+		 int_en_early_tail:1,	// 26
+		 int_en_missing_tail:1,	// 27
+		 int_en_data_flit_sb_e:1,	// 28
+		 int_en_cm2hcm_req_cre:1,	// 29
+		 int_en_cm2hcm_rsp_cre:1,	// 30
+		 int_en_rx_bad_didn:1,	// 31
+		 int_en_rd_dma_err_rsp:1,	// 32
+		 int_en_rd_dma_tnum_to:1,	// 33
+		 int_en_rd_dma_multi_t:1,	// 34
+		 int_en_wr_dma_err_rsp:1,	// 35
+		 int_en_wr_dma_tnum_to:1,	// 36
+		 int_en_wr_dma_multi_t:1,	// 37
+		 int_en_alg_data_overf:1,	// 38
+		 int_en_alg_data_under:1,	// 39
+		 int_en_ram0_access_co:1,	// 40
+		 int_en_ram1_access_co:1,	// 41
+		 int_en_ram2_access_co:1,	// 42
+		 int_en_ram0_perr:1,	// 43
+		 int_en_ram1_perr:1,	// 44
+		 int_en_ram2_perr:1,	// 45
+		 int_en_int_gen_rsp_er:1,	// 46
+		 int_en_int_gen_tnum_t:1,	// 47
+		 int_en_rd_dma_prog_er:1,	// 48
+		 int_en_wr_dma_prog_er:1,	// 49
+		:14;		// 63:50
+	};
+};
+
+struct cm_mmr {
+	union cm_id id;
+	union cm_status status;
+	union cm_error_detail1 err_detail1;
+	union cm_error_detail2 err_detail2;
+	union cm_control control;
+	union cm_req_timeout req_timeout;
+	uint64_t reserved1[1];
+	union intr_dest int_dest;
+	uint64_t reserved2[2];
+	uint64_t targ_flush;
+	uint64_t reserved3[1];
+	union cm_error_status err_status;
+	union cm_clr_error_status clr_err_status;
+	union cm_error_intr_enable int_enable;
+};
+
+union dma_hostaddr {
+	uint64_t dma_hostaddr_reg;
+	struct {
+		uint64_t dma_sys_addr:56,	// 55:0
+		:8;		// 63:56
+	};
+};
+
+union dma_localaddr {
+	uint64_t dma_localaddr_reg;
+	struct {
+		uint64_t dma_ram_addr:21,	// 20:0
+		 dma_ram_sel:2,	// 22:21
+		:41;		// 63:23
+	};
+};
+
+union dma_control {
+	uint64_t dma_control_reg;
+	struct {
+		uint64_t dma_op_length:16,	// 15:0
+		:18,		// 33:16
+		 done_amo_en:1,	// 34
+		 done_int_en:1,	// 35
+		:1,		// 36
+		 pio_mem_n:1,	// 37
+		:26;		// 63:38
+	};
+};
+
+union dma_amo_dest {
+	uint64_t dma_amo_dest_reg;
+	struct {
+		uint64_t dma_amo_sys_addr:56,	// 55:0
+		 dma_amo_mod_type:3,	// 58:56
+		:5;		// 63:59
+	};
+};
+
+union rdma_aux_status {
+	uint64_t rdma_aux_status_reg;
+	struct {
+		uint64_t op_num_pacs_left:17,	// 16:0
+		:5,		// 21:17
+		 lrsp_buff_empty:1,	// 22
+		:17,		// 39:23
+		 pending_reqs_left:6,	// 45:40
+		:18;		// 63:46
+	};
+};
+
+struct rdma_mmr {
+	union dma_hostaddr host_addr;
+	union dma_localaddr local_addr;
+	union dma_control control;
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union rdma_aux_status aux_status;
+};
+
+union wdma_aux_status {
+	uint64_t wdma_aux_status_reg;
+	struct {
+		uint64_t op_num_pacs_left:17,	// 16:0
+		:4,		// 20:17
+		 lreq_buff_empty:1,	// 21
+		:18,		// 39:22
+		 pending_reqs_left:6,	// 45:40
+		:18;		// 63:46
+	};
+};
+
+struct wdma_mmr {
+	union dma_hostaddr host_addr;
+	union dma_localaddr local_addr;
+	union dma_control control;
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union wdma_aux_status aux_status;
+};
+
+union algo_step {
+	uint64_t algo_step_reg;
+	struct {
+		uint64_t alg_step_cnt:16,	// 15:0
+		:48;		// 63:16
+	};
+};
+
+struct algo_mmr {
+	union dma_amo_dest amo_dest;
+	union intr_dest intr_dest;
+	union {
+		uint64_t algo_offset_reg;
+		struct {
+			uint64_t sram0_offset:7,	// 6:0
+			reserved0:1,	// 7
+			sram1_offset:7,	// 14:8
+			reserved1:1,	// 15
+			sram2_offset:7,	// 22:16
+			reserved2:14;	// 63:23
+		};
+	} sram_offset;
+	union algo_step step;
+};
+
+struct mbcs_mmr {
+	struct cm_mmr cm;
+	uint64_t reserved1[17];
+	struct rdma_mmr rdDma;
+	uint64_t reserved2[25];
+	struct wdma_mmr wrDma;
+	uint64_t reserved3[25];
+	struct algo_mmr algo;
+	uint64_t reserved4[156];
+};
+
+/*
+ * defines
+ */
+#define DEVICE_NAME "mbcs"
+#define MBCS_PART_NUM 0xfff0
+#define MBCS_PART_NUM_ALG0 0xf001
+#define MBCS_MFG_NUM  0x1
+
+struct algoblock {
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+	uint64_t algoStepCount;
+};
+
+struct getdma {
+	uint64_t hostAddr;
+	uint64_t localAddr;
+	uint64_t bytes;
+	uint64_t DoneAmoEnable;
+	uint64_t DoneIntEnable;
+	uint64_t peerIO;
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+};
+
+struct putdma {
+	uint64_t hostAddr;
+	uint64_t localAddr;
+	uint64_t bytes;
+	uint64_t DoneAmoEnable;
+	uint64_t DoneIntEnable;
+	uint64_t peerIO;
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+};
+
+struct mbcs_soft {
+	struct list_head list;
+	struct cx_dev *cxdev;
+	int major;
+	int nasid;
+	void *mmr_base;
+	wait_queue_head_t dmawrite_queue;
+	wait_queue_head_t dmaread_queue;
+	wait_queue_head_t algo_queue;
+	struct sn_irq_info *get_sn_irq;
+	struct sn_irq_info *put_sn_irq;
+	struct sn_irq_info *algo_sn_irq;
+	struct getdma getdma;
+	struct putdma putdma;
+	struct algoblock algo;
+	uint64_t gscr_addr;	// pio addr
+	uint64_t ram0_addr;	// pio addr
+	uint64_t ram1_addr;	// pio addr
+	uint64_t ram2_addr;	// pio addr
+	uint64_t debug_addr;	// pio addr
+	atomic_t dmawrite_done;
+	atomic_t dmaread_done;
+	atomic_t algo_done;
+	struct semaphore dmawritelock;
+	struct semaphore dmareadlock;
+	struct semaphore algolock;
+};
+
+extern int mbcs_open(struct inode *ip, struct file *fp);
+extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+			      loff_t * off);
+extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+			       loff_t * off);
+extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+
+#endif				// __MBCS_H__
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -23,6 +23,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ptrace.h>
 #include <linux/device.h>
+#include <linux/backing-dev.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -76,14 +77,6 @@ static inline int uncached_access(struct
 	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_PPC64)
-	/* On PPC64, we always do non-cacheable access to the IO hole and
-	 * cacheable elsewhere. Cache paradox can checkstop the CPU and
-	 * the high_memory heuristic below is wrong on machines with memory
-	 * above the IO hole... Ah, and of course, XFree86 doesn't pass
-	 * O_SYNC when mapping us to tap IO space. Surprised ?
-	 */
-	return !page_is_ram(addr >> PAGE_SHIFT);
 #else
 	/*
 	 * Accessing memory above the top the kernel knows about or through a file pointer
@@ -111,39 +104,6 @@ static inline int valid_phys_addr_range(
 }
 #endif
 
-static ssize_t do_write_mem(void *p, unsigned long realp,
-			    const char __user * buf, size_t count, loff_t *ppos)
-{
-	ssize_t written;
-	unsigned long copied;
-
-	written = 0;
-#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
-	/* we don't have page 0 mapped on sparc and m68k.. */
-	if (realp < PAGE_SIZE) {
-		unsigned long sz = PAGE_SIZE-realp;
-		if (sz > count) sz = count; 
-		/* Hmm. Do something? */
-		buf+=sz;
-		p+=sz;
-		count-=sz;
-		written+=sz;
-	}
-#endif
-	copied = copy_from_user(p, buf, count);
-	if (copied) {
-		ssize_t ret = written + (count - copied);
-
-		if (ret)
-			return ret;
-		return -EFAULT;
-	}
-	written += count;
-	*ppos += written;
-	return written;
-}
-
-
 /*
  * This funcion reads the *physical* memory. The f_pos points directly to the 
  * memory location. 
@@ -152,15 +112,16 @@ static ssize_t read_mem(struct file * fi
 			size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
-	ssize_t read;
+	ssize_t read, sz;
+	char *ptr;
 
 	if (!valid_phys_addr_range(p, &count))
 		return -EFAULT;
 	read = 0;
-#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
+#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
 	/* we don't have page 0 mapped on sparc and m68k.. */
 	if (p < PAGE_SIZE) {
-		unsigned long sz = PAGE_SIZE-p;
+		sz = PAGE_SIZE - p;
 		if (sz > count) 
 			sz = count; 
 		if (sz > 0) {
@@ -173,9 +134,33 @@ static ssize_t read_mem(struct file * fi
 		}
 	}
 #endif
-	if (copy_to_user(buf, __va(p), count))
-		return -EFAULT;
-	read += count;
+
+	while (count > 0) {
+		/*
+		 * Handle first page in case it's not aligned
+		 */
+		if (-p & (PAGE_SIZE - 1))
+			sz = -p & (PAGE_SIZE - 1);
+		else
+			sz = PAGE_SIZE;
+
+		sz = min_t(unsigned long, sz, count);
+
+		/*
+		 * On ia64 if a page has been mapped somewhere as
+		 * uncached, then it must also be accessed uncached
+		 * by the kernel or data corruption may occur
+		 */
+		ptr = xlate_dev_mem_ptr(p);
+
+		if (copy_to_user(buf, ptr, sz))
+			return -EFAULT;
+		buf += sz;
+		p += sz;
+		count -= sz;
+		read += sz;
+	}
+
 	*ppos += read;
 	return read;
 }
@@ -184,15 +169,75 @@ static ssize_t write_mem(struct file * f
 			 size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
+	ssize_t written, sz;
+	unsigned long copied;
+	void *ptr;
 
 	if (!valid_phys_addr_range(p, &count))
 		return -EFAULT;
-	return do_write_mem(__va(p), p, buf, count, ppos);
+
+	written = 0;
+
+#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
+	/* we don't have page 0 mapped on sparc and m68k.. */
+	if (p < PAGE_SIZE) {
+		unsigned long sz = PAGE_SIZE - p;
+		if (sz > count)
+			sz = count;
+		/* Hmm. Do something? */
+		buf += sz;
+		p += sz;
+		count -= sz;
+		written += sz;
+	}
+#endif
+
+	while (count > 0) {
+		/*
+		 * Handle first page in case it's not aligned
+		 */
+		if (-p & (PAGE_SIZE - 1))
+			sz = -p & (PAGE_SIZE - 1);
+		else
+			sz = PAGE_SIZE;
+
+		sz = min_t(unsigned long, sz, count);
+
+		/*
+		 * On ia64 if a page has been mapped somewhere as
+		 * uncached, then it must also be accessed uncached
+		 * by the kernel or data corruption may occur
+		 */
+		ptr = xlate_dev_mem_ptr(p);
+
+		copied = copy_from_user(ptr, buf, sz);
+		if (copied) {
+			ssize_t ret;
+
+			ret = written + (sz - copied);
+			if (ret)
+				return ret;
+			return -EFAULT;
+		}
+		buf += sz;
+		p += sz;
+		count -= sz;
+		written += sz;
+	}
+
+	*ppos += written;
+	return written;
 }
 
 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 {
-#ifdef pgprot_noncached
+#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	vma->vm_page_prot = phys_mem_access_prot(file, offset,
+						 vma->vm_end - vma->vm_start,
+						 vma->vm_page_prot);
+#elif defined(pgprot_noncached)
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	int uncached;
 
@@ -211,6 +256,23 @@ static int mmap_mem(struct file * file, 
 	return 0;
 }
 
+static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+{
+        unsigned long long val;
+	/*
+	 * RED-PEN: on some architectures there is more mapped memory
+	 * than available in mem_map which pfn_valid checks
+	 * for. Perhaps should add a new macro here.
+	 *
+	 * RED-PEN: vmalloc is not supported right now.
+	 */
+	if (!pfn_valid(vma->vm_pgoff))
+		return -EIO;
+	val = (u64)vma->vm_pgoff << PAGE_SHIFT;
+	vma->vm_pgoff = __pa(val) >> PAGE_SHIFT;
+	return mmap_mem(file, vma);
+}
+
 extern long vread(char *buf, char *addr, unsigned long count);
 extern long vwrite(char *buf, char *addr, unsigned long count);
 
@@ -221,33 +283,55 @@ static ssize_t read_kmem(struct file *fi
 			 size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
-	ssize_t read = 0;
-	ssize_t virtr = 0;
+	ssize_t low_count, read, sz;
 	char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
-		
+
+	read = 0;
 	if (p < (unsigned long) high_memory) {
-		read = count;
+		low_count = count;
 		if (count > (unsigned long) high_memory - p)
-			read = (unsigned long) high_memory - p;
+			low_count = (unsigned long) high_memory - p;
 
-#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
+#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
 		/* we don't have page 0 mapped on sparc and m68k.. */
-		if (p < PAGE_SIZE && read > 0) {
+		if (p < PAGE_SIZE && low_count > 0) {
 			size_t tmp = PAGE_SIZE - p;
-			if (tmp > read) tmp = read;
+			if (tmp > low_count) tmp = low_count;
 			if (clear_user(buf, tmp))
 				return -EFAULT;
 			buf += tmp;
 			p += tmp;
-			read -= tmp;
+			read += tmp;
+			low_count -= tmp;
 			count -= tmp;
 		}
 #endif
-		if (copy_to_user(buf, (char *)p, read))
-			return -EFAULT;
-		p += read;
-		buf += read;
-		count -= read;
+		while (low_count > 0) {
+			/*
+			 * Handle first page in case it's not aligned
+			 */
+			if (-p & (PAGE_SIZE - 1))
+				sz = -p & (PAGE_SIZE - 1);
+			else
+				sz = PAGE_SIZE;
+
+			sz = min_t(unsigned long, sz, low_count);
+
+			/*
+			 * On ia64 if a page has been mapped somewhere as
+			 * uncached, then it must also be accessed uncached
+			 * by the kernel or data corruption may occur
+			 */
+			kbuf = xlate_dev_kmem_ptr((char *)p);
+
+			if (copy_to_user(buf, kbuf, sz))
+				return -EFAULT;
+			buf += sz;
+			p += sz;
+			read += sz;
+			low_count -= sz;
+			count -= sz;
+		}
 	}
 
 	if (count > 0) {
@@ -268,15 +352,79 @@ static ssize_t read_kmem(struct file *fi
 			}
 			count -= len;
 			buf += len;
-			virtr += len;
+			read += len;
 			p += len;
 		}
 		free_page((unsigned long)kbuf);
 	}
  	*ppos = p;
- 	return virtr + read;
+ 	return read;
 }
 
+
+static inline ssize_t
+do_write_kmem(void *p, unsigned long realp, const char __user * buf,
+	      size_t count, loff_t *ppos)
+{
+	ssize_t written, sz;
+	unsigned long copied;
+
+	written = 0;
+#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
+	/* we don't have page 0 mapped on sparc and m68k.. */
+	if (realp < PAGE_SIZE) {
+		unsigned long sz = PAGE_SIZE - realp;
+		if (sz > count)
+			sz = count;
+		/* Hmm. Do something? */
+		buf += sz;
+		p += sz;
+		realp += sz;
+		count -= sz;
+		written += sz;
+	}
+#endif
+
+	while (count > 0) {
+		char *ptr;
+		/*
+		 * Handle first page in case it's not aligned
+		 */
+		if (-realp & (PAGE_SIZE - 1))
+			sz = -realp & (PAGE_SIZE - 1);
+		else
+			sz = PAGE_SIZE;
+
+		sz = min_t(unsigned long, sz, count);
+
+		/*
+		 * On ia64 if a page has been mapped somewhere as
+		 * uncached, then it must also be accessed uncached
+		 * by the kernel or data corruption may occur
+		 */
+		ptr = xlate_dev_kmem_ptr(p);
+
+		copied = copy_from_user(ptr, buf, sz);
+		if (copied) {
+			ssize_t ret;
+
+			ret = written + (sz - copied);
+			if (ret)
+				return ret;
+			return -EFAULT;
+		}
+		buf += sz;
+		p += sz;
+		realp += sz;
+		count -= sz;
+		written += sz;
+	}
+
+	*ppos += written;
+	return written;
+}
+
+
 /*
  * This function writes to the *virtual* memory as seen by the kernel.
  */
@@ -295,7 +443,7 @@ static ssize_t write_kmem(struct file * 
 		if (count > (unsigned long) high_memory - p)
 			wrote = (unsigned long) high_memory - p;
 
-		written = do_write_mem((void*)p, p, buf, wrote, ppos);
+		written = do_write_kmem((void*)p, p, buf, wrote, ppos);
 		if (written != wrote)
 			return written;
 		wrote = written;
@@ -343,7 +491,7 @@ static ssize_t read_port(struct file * f
 	unsigned long i = *ppos;
 	char __user *tmp = buf;
 
-	if (verify_area(VERIFY_WRITE,buf,count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT; 
 	while (count-- > 0 && i < 65536) {
 		if (__put_user(inb(i),tmp) < 0) 
@@ -361,7 +509,7 @@ static ssize_t write_port(struct file * 
 	unsigned long i = *ppos;
 	const char __user * tmp = buf;
 
-	if (verify_area(VERIFY_READ,buf,count))
+	if (!access_ok(VERIFY_READ,buf,count))
 		return -EFAULT;
 	while (count-- > 0 && i < 65536) {
 		char c;
@@ -567,7 +715,6 @@ static int open_port(struct inode * inod
 	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
-#define mmap_kmem	mmap_mem
 #define zero_lseek	null_lseek
 #define full_lseek      null_lseek
 #define write_zero	write_null
@@ -613,6 +760,10 @@ static struct file_operations zero_fops 
 	.mmap		= mmap_zero,
 };
 
+static struct backing_dev_info zero_bdi = {
+	.capabilities	= BDI_CAP_MAP_COPY,
+};
+
 static struct file_operations full_fops = {
 	.llseek		= full_lseek,
 	.read		= read_full,
@@ -659,6 +810,7 @@ static int memory_open(struct inode * in
 			break;
 #endif
 		case 5:
+			filp->f_mapping->backing_dev_info = &zero_bdi;
 			filp->f_op = &zero_fops;
 			break;
 		case 7:
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -71,11 +71,6 @@ static struct file_operations mmtimer_fo
 };
 
 /*
- * Comparators and their associated info.  Shub has
- * three comparison registers.
- */
-
-/*
  * We only have comparison registers RTC1-4 currently available per
  * node.  RTC0 is used by SAL.
  */
@@ -174,14 +169,10 @@ static void inline mmtimer_setup_int_2(u
  * This function must be called with interrupts disabled and preemption off
  * in order to insure that the setup succeeds in a deterministic time frame.
  * It will check if the interrupt setup succeeded.
- * mmtimer_setup will return the cycles that we were too late if the
- * initialization failed.
  */
 static int inline mmtimer_setup(int comparator, unsigned long expires)
 {
 
-	long diff;
-
 	switch (comparator) {
 	case 0:
 		mmtimer_setup_int_0(expires);
@@ -194,17 +185,14 @@ static int inline mmtimer_setup(int comp
 		break;
 	}
 	/* We might've missed our expiration time */
-        diff = rtc_time() - expires;
-	if (diff > 0) {
-		if (mmtimer_int_pending(comparator)) {
-			/* We'll get an interrupt for this once we're done */
-                        return 0;
-		}
-		/* Looks like we missed it */
-		return diff;
-        }
+	if (rtc_time() < expires)
+		return 1;
 
-	return 0;
+	/*
+	 * If an interrupt is already pending then its okay
+	 * if not then we failed
+	 */
+	return mmtimer_int_pending(comparator);
 }
 
 static int inline mmtimer_disable_int(long nasid, int comparator)
@@ -376,7 +364,7 @@ static int sgi_clock_period;
 static struct timespec sgi_clock_offset;
 static int sgi_clock_period;
 
-static int sgi_clock_get(struct timespec *tp)
+static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
 {
 	u64 nsec;
 
@@ -387,7 +375,7 @@ static int sgi_clock_get(struct timespec
 	return 0;
 };
 
-static int sgi_clock_set(struct timespec *tp)
+static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
 {
 
 	u64 nsec;
@@ -418,19 +406,19 @@ static int inline reschedule_periodic_ti
 	int n;
 	struct k_itimer *t = x->timer;
 
-	t->it_timer.magic = x->i;
+	t->it.mmtimer.clock = x->i;
 	t->it_overrun--;
 
 	n = 0;
 	do {
 
-		t->it_timer.expires += t->it_incr << n;
+		t->it.mmtimer.expires += t->it.mmtimer.incr << n;
 		t->it_overrun += 1 << n;
 		n++;
 		if (n > 20)
 			return 1;
 
-	} while (mmtimer_setup(x->i, t->it_timer.expires));
+	} while (!mmtimer_setup(x->i, t->it.mmtimer.expires));
 
 	return 0;
 }
@@ -466,7 +454,7 @@ mmtimer_interrupt(int irq, void *dev_id,
 		spin_lock(&base[i].lock);
 		if (base[i].cpu == smp_processor_id()) {
 			if (base[i].timer)
-				expires = base[i].timer->it_timer.expires;
+				expires = base[i].timer->it.mmtimer.expires;
 			/* expires test won't work with shared irqs */
 			if ((mmtimer_int_pending(i) > 0) ||
 				(expires && (expires < rtc_time()))) {
@@ -497,13 +485,13 @@ void mmtimer_tasklet(unsigned long data)
 		goto out;
 	t->it_overrun = 0;
 
-	if (tasklist_lock.write_lock || posix_timer_event(t, 0) != 0) {
+	if (posix_timer_event(t, 0) != 0) {
 
 		// printk(KERN_WARNING "mmtimer: cannot deliver signal.\n");
 
 		t->it_overrun++;
 	}
-	if(t->it_incr) {
+	if(t->it.mmtimer.incr) {
 		/* Periodic timer */
 		if (reschedule_periodic_timer(x)) {
 			printk(KERN_WARNING "mmtimer: unable to reschedule\n");
@@ -511,7 +499,7 @@ void mmtimer_tasklet(unsigned long data)
 		}
 	} else {
 		/* Ensure we don't false trigger in mmtimer_interrupt */
-		t->it_timer.expires = 0;
+		t->it.mmtimer.expires = 0;
 	}
 	t->it_overrun_last = t->it_overrun;
 out:
@@ -522,7 +510,7 @@ out:
 static int sgi_timer_create(struct k_itimer *timer)
 {
 	/* Insure that a newly created timer is off */
-	timer->it_timer.magic = TIMER_OFF;
+	timer->it.mmtimer.clock = TIMER_OFF;
 	return 0;
 }
 
@@ -533,8 +521,8 @@ static int sgi_timer_create(struct k_iti
  */
 static int sgi_timer_del(struct k_itimer *timr)
 {
-	int i = timr->it_timer.magic;
-	cnodeid_t nodeid = timr->it_timer.data;
+	int i = timr->it.mmtimer.clock;
+	cnodeid_t nodeid = timr->it.mmtimer.node;
 	mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i;
 	unsigned long irqflags;
 
@@ -542,8 +530,8 @@ static int sgi_timer_del(struct k_itimer
 		spin_lock_irqsave(&t->lock, irqflags);
 		mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
 		t->timer = NULL;
-		timr->it_timer.magic = TIMER_OFF;
-		timr->it_timer.expires = 0;
+		timr->it.mmtimer.clock = TIMER_OFF;
+		timr->it.mmtimer.expires = 0;
 		spin_unlock_irqrestore(&t->lock, irqflags);
 	}
 	return 0;
@@ -556,7 +544,7 @@ static int sgi_timer_del(struct k_itimer
 static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
 
-	if (timr->it_timer.magic == TIMER_OFF) {
+	if (timr->it.mmtimer.clock == TIMER_OFF) {
 		cur_setting->it_interval.tv_nsec = 0;
 		cur_setting->it_interval.tv_sec = 0;
 		cur_setting->it_value.tv_nsec = 0;
@@ -564,8 +552,8 @@ static void sgi_timer_get(struct k_itime
 		return;
 	}
 
-	ns_to_timespec(cur_setting->it_interval, timr->it_incr * sgi_clock_period);
-	ns_to_timespec(cur_setting->it_value, (timr->it_timer.expires - rtc_time())* sgi_clock_period);
+	ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
+	ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
 	return;
 }
 
@@ -594,9 +582,15 @@ static int sgi_timer_set(struct k_itimer
 
 	if (flags & TIMER_ABSTIME) {
 		struct timespec n;
+		unsigned long now;
 
 		getnstimeofday(&n);
-		when -= timespec_to_ns(n);
+		now = timespec_to_ns(n);
+		if (when > now)
+			when -= now;
+		else
+			/* Fire the timer immediately */
+			when = 0;
 	}
 
 	/*
@@ -638,19 +632,19 @@ retry:
 	base[i].timer = timr;
 	base[i].cpu = smp_processor_id();
 
-	timr->it_timer.magic = i;
-	timr->it_timer.data = nodeid;
-	timr->it_incr = period;
-	timr->it_timer.expires = when;
+	timr->it.mmtimer.clock = i;
+	timr->it.mmtimer.node = nodeid;
+	timr->it.mmtimer.incr = period;
+	timr->it.mmtimer.expires = when;
 
 	if (period == 0) {
-		if (mmtimer_setup(i, when)) {
+		if (!mmtimer_setup(i, when)) {
 			mmtimer_disable_int(-1, i);
 			posix_timer_event(timr, 0);
-			timr->it_timer.expires = 0;
+			timr->it.mmtimer.expires = 0;
 		}
 	} else {
-		timr->it_timer.expires -= period;
+		timr->it.mmtimer.expires -= period;
 		if (reschedule_periodic_timer(base+i))
 			err = -EINVAL;
 	}
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -3090,6 +3090,7 @@ static int moxaloadc320(int cardno, void
 	return (0);
 }
 
+#if 0
 long MoxaPortGetCurBaud(int port)
 {
 
@@ -3097,6 +3098,7 @@ long MoxaPortGetCurBaud(int port)
 		return (0);
 	return (moxaCurBaud[port]);
 }
+#endif  /*  0  */
 
 static void MoxaSetFifo(int port, int enable)
 {
diff --git a/drivers/char/mwave/smapi.c b/drivers/char/mwave/smapi.c
--- a/drivers/char/mwave/smapi.c
+++ b/drivers/char/mwave/smapi.c
@@ -54,11 +54,11 @@
 static unsigned short g_usSmapiPort = 0;
 
 
-int smapi_request(unsigned short inBX, unsigned short inCX,
-                  unsigned short inDI, unsigned short inSI,
-                  unsigned short *outAX, unsigned short *outBX,
-                  unsigned short *outCX, unsigned short *outDX,
-                  unsigned short *outDI, unsigned short *outSI)
+static int smapi_request(unsigned short inBX, unsigned short inCX,
+			 unsigned short inDI, unsigned short inSI,
+			 unsigned short *outAX, unsigned short *outBX,
+			 unsigned short *outCX, unsigned short *outDX,
+			 unsigned short *outDI, unsigned short *outSI)
 {
 	unsigned short myoutAX = 2, *pmyoutAX = &myoutAX;
 	unsigned short myoutBX = 3, *pmyoutBX = &myoutBX;
@@ -511,8 +511,8 @@ int smapi_set_DSP_power_state(BOOLEAN bO
 	return bRC;
 }
 
-
-int SmapiQuerySystemID(void)
+#if 0
+static int SmapiQuerySystemID(void)
 {
 	int bRC = -EIO;
 	unsigned short usAX = 0xffff, usBX = 0xffff, usCX = 0xffff,
@@ -531,7 +531,7 @@ int SmapiQuerySystemID(void)
 
 	return bRC;
 }
-
+#endif  /*  0  */
 
 int smapi_init(void)
 {
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -179,7 +179,7 @@ static int mxser_numports[] = {
 
 #define UART_TYPE_NUM	2
 
-unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
+static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
 	MOXA_MUST_MU150_HWID,
 	MOXA_MUST_MU860_HWID
 };
@@ -197,7 +197,7 @@ struct mxpciuart_info {
 	long max_baud;
 };
 
-struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
+static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
 	{MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
 	{MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
 	{MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
@@ -548,7 +548,6 @@ static void process_txrx_fifo(struct mxs
 static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
 {
 	struct mxser_struct *info;
-	unsigned long flags;
 	int retval;
 	int i, n;
 
@@ -1996,9 +1995,6 @@ static void mxser_receive_chars(struct m
 	unsigned char ch, gdl;
 	int ignored = 0;
 	int cnt = 0;
-	unsigned char *cp;
-	char *fp;
-	int count;
 	int recv_room;
 	int max = 256;
 	unsigned long flags;
@@ -2012,10 +2008,6 @@ static void mxser_receive_chars(struct m
 		//return;
 	}
 
-	cp = tty->flip.char_buf;
-	fp = tty->flip.flag_buf;
-	count = 0;
-
 	// following add by Victor Yu. 09-02-2002
 	if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
 
@@ -2042,12 +2034,10 @@ static void mxser_receive_chars(struct m
 		}
 		while (gdl--) {
 			ch = inb(info->base + UART_RX);
-			count++;
-			*cp++ = ch;
-			*fp++ = 0;
+			tty_insert_flip_char(tty, ch, 0);
 			cnt++;
 			/*
-			   if((count>=HI_WATER) && (info->stop_rx==0)){
+			   if((cnt>=HI_WATER) && (info->stop_rx==0)){
 			   mxser_stoprx(tty);
 			   info->stop_rx=1;
 			   break;
@@ -2062,7 +2052,7 @@ intr_old:
 		if (max-- < 0)
 			break;
 		/*
-		   if((count>=HI_WATER) && (info->stop_rx==0)){
+		   if((cnt>=HI_WATER) && (info->stop_rx==0)){
 		   mxser_stoprx(tty);
 		   info->stop_rx=1;
 		   break;
@@ -2079,36 +2069,33 @@ intr_old:
 			if (++ignored > 100)
 				break;
 		} else {
-			count++;
+			char flag = 0;
 			if (*status & UART_LSR_SPECIAL) {
 				if (*status & UART_LSR_BI) {
-					*fp++ = TTY_BREAK;
+					flag = TTY_BREAK;
 /* added by casper 1/11/2000 */
 					info->icount.brk++;
-
 /* */
 					if (info->flags & ASYNC_SAK)
 						do_SAK(tty);
 				} else if (*status & UART_LSR_PE) {
-					*fp++ = TTY_PARITY;
+					flag = TTY_PARITY;
 /* added by casper 1/11/2000 */
 					info->icount.parity++;
 /* */
 				} else if (*status & UART_LSR_FE) {
-					*fp++ = TTY_FRAME;
+					flag = TTY_FRAME;
 /* added by casper 1/11/2000 */
 					info->icount.frame++;
 /* */
 				} else if (*status & UART_LSR_OE) {
-					*fp++ = TTY_OVERRUN;
+					flag = TTY_OVERRUN;
 /* added by casper 1/11/2000 */
 					info->icount.overrun++;
 /* */
-				} else
-					*fp++ = 0;
-			} else
-				*fp++ = 0;
-			*cp++ = ch;
+				}
+			}
+			tty_insert_flip_char(tty, ch, flag);
 			cnt++;
 			if (cnt >= recv_room) {
 				if (!info->ldisc_stop_rx) {
@@ -2133,13 +2120,13 @@ intr_old:
 		// above add by Victor Yu. 09-02-2002
 	} while (*status & UART_LSR_DR);
 
-      end_intr:		// add by Victor Yu. 09-02-2002
+end_intr:		// add by Victor Yu. 09-02-2002
 
 	mxvar_log.rxcnt[info->port] += cnt;
 	info->mon_data.rxcnt += cnt;
 	info->mon_data.up_rxcnt += cnt;
 	spin_unlock_irqrestore(&info->slock, flags);
-	
+
 	tty_flip_buffer_push(tty);
 }
 
@@ -3167,22 +3154,5 @@ static void mxser_normal_mode(int port)
 	outb(0x00, port + 4);
 }
 
-// added by James 03-05-2004.
-// for secure device server:
-// stat = 1, the port8 DTR is set to ON.
-// stat = 0, the port8 DTR is set to OFF.
-void SDS_PORT8_DTR(int stat)
-{
-	int _sds_oldmcr;
-	_sds_oldmcr = inb(mxvar_table[7].base + UART_MCR);	// get old MCR
-	if (stat == 1) {
-		outb(_sds_oldmcr | 0x01, mxvar_table[7].base + UART_MCR);	// set DTR ON
-	}
-	if (stat == 0) {
-		outb(_sds_oldmcr & 0xfe, mxvar_table[7].base + UART_MCR);	// set DTR OFF
-	}
-	return;
-}
-
 module_init(mxser_module_init);
 module_exit(mxser_module_exit);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -575,7 +575,6 @@ static ssize_t n_hdlc_tty_read(struct tt
 			   __u8 __user *buf, size_t nr)
 {
 	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-	int error;
 	int ret;
 	struct n_hdlc_buf *rbuf;
 
@@ -587,11 +586,10 @@ static ssize_t n_hdlc_tty_read(struct tt
 		return -EIO;
 
 	/* verify user access to buffer */
-	error = verify_area (VERIFY_WRITE, buf, nr);
-	if (error != 0) {
-		printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user "
-		"buffer\n",__FILE__,__LINE__);
-		return (error);
+	if (!access_ok(VERIFY_WRITE, buf, nr)) {
+		printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
+		"buffer\n", __FILE__, __LINE__);
+		return -EFAULT;
 	}
 
 	for (;;) {
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -606,9 +606,11 @@ static inline void n_tty_receive_overrun
 	char buf[64];
 
 	tty->num_overrun++;
-	if (time_before(tty->overrun_time, jiffies - HZ)) {
-		printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf),
-		       tty->num_overrun);
+	if (time_before(tty->overrun_time, jiffies - HZ) ||
+			time_after(tty->overrun_time, jiffies)) {
+		printk(KERN_WARNING "%s: %d input overrun(s)\n",
+			tty_name(tty, buf),
+			tty->num_overrun);
 		tty->overrun_time = jiffies;
 		tty->num_overrun = 0;
 	}
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -182,7 +182,7 @@ static ssize_t flash_write(struct file *
 	if (count > gbFlashSize - p)
 		count = gbFlashSize - p;
 			
-	if (verify_area(VERIFY_READ, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 
 	/*
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
deleted file mode 100644
--- a/drivers/char/pcxx.c
+++ /dev/null
@@ -1,2353 +0,0 @@
-/*
- *  linux/drivers/char/pcxx.c
- * 
- *  Written by Troy De Jongh, November, 1994
- *
- *  Copyright (C) 1994,1995 Troy De Jongh
- *  This software may be used and distributed according to the terms 
- *  of the GNU General Public License.
- *
- *  This driver is for the DigiBoard PC/Xe and PC/Xi line of products.
- *
- *  This driver does NOT support DigiBoard's fastcook FEP option and
- *  does not support the transparent print (i.e. digiprint) option.
- *
- * This Driver is currently maintained by Christoph Lameter (christoph@lameter.com)
- *
- * Please contact digi for support issues at digilnux@dgii.com.
- * Some more information can be found at
- * http://lameter.com/digi.
- *
- *  1.5.2 Fall 1995 Bug fixes by David Nugent
- *  1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory
- *		allocation harmonized with 1.3.X Series.
- *  1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh
- *		instead of direct assignment to kernel arrays.
- *  1.5.5 April 5, 1996 Major device numbers corrected.
- *              Mike McLagan<mike.mclagan@linux.org>: Add setup
- *              variable handling, instead of using the old pcxxconfig.h
- *  1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
- *		Call out devices changed to /dev/cudxx.
- *  1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
- *		David Nugent: Bug in pcxe_open.
- *		Brian J. Murrell: Modem Control fixes, Majors correctly assigned
- *  1.6.1 April 6, 1997 Bernhard Kaindl: fixed virtual memory access for 2.1
- *              i386-kernels and use on other archtitectures, Allowing use
- *              as module, added module parameters, added switch to enable
- *              verbose messages to assist user during card configuration.
- *              Currently only tested on a PC/Xi card, but should work on Xe
- *              and Xeve also.
- *  1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *  		get rid of panics, release previously allocated resources
- *  1.6.3 August, 23, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *  		cleaned up wrt verify_area.
- *              Christoph Lameter: Update documentation, email addresses
- *              and URLs. Remove some obsolete code.
- *
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#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/delay.h>
-#include <linux/serial.h>
-#include <linux/tty_driver.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#ifndef MODULE
-#include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
-#endif
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-
-#define VERSION 	"1.6.3"
-
-#include "digi.h"
-#include "fep.h"
-#include "pcxx.h"
-#include "digi_fep.h"
-#include "digi_bios.h"
-
-/*
- * Define one default setting if no digi= config line is used.
- * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
- */
-static struct board_info boards[MAX_DIGI_BOARDS] = { {
-/* Board is enabled       */	ENABLED,
-/* Type is auto-detected  */	0,
-/* altping is disabled    */    DISABLED,
-/* number of ports = 16   */	16,
-/* io address is 0x200    */	0x200,
-/* card memory at 0xd0000 */	0xd0000,
-/* first minor device no. */	0
-} };
- 
-static int verbose = 0;
-static int debug   = 0;
-
-#ifdef MODULE
-/* Variables for insmod */
-static int io[]           = {0, 0, 0, 0};
-static int membase[]      = {0, 0, 0, 0};
-static int memsize[]      = {0, 0, 0, 0};
-static int altpin[]       = {0, 0, 0, 0};
-static int numports[]     = {0, 0, 0, 0};
-
-MODULE_AUTHOR("Bernhard Kaindl");
-MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
-MODULE_LICENSE("GPL");
-module_param(verbose,     bool, 0644);
-module_param(debug,       bool, 0644);
-module_param_array(io,          int, NULL, 0);
-module_param_array(membase,     int, NULL, 0);
-module_param_array(memsize,     int, NULL, 0);
-module_param_array(altpin,      int, NULL, 0);
-module_param_array(numports,    int, NULL, 0);
-
-#endif /* MODULE */
-
-static int numcards = 1;
-static int nbdevs = 0;
- 
-static struct channel    *digi_channels;
- 
-int pcxx_ncook=sizeof(pcxx_cook);
-int pcxx_nbios=sizeof(pcxx_bios);
-
-#define pcxxassert(x, msg)  if(!(x)) pcxx_error(__LINE__, msg)
-
-#define FEPTIMEOUT 200000  
-#define SERIAL_TYPE_NORMAL	1
-#define PCXE_EVENT_HANGUP   1
-
-static struct tty_driver *pcxe_driver;
-
-static struct timer_list pcxx_timer;
-
-static void pcxxpoll(unsigned long dummy);
-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 *);
-static void pcxx_error(int, char *);
-static void pcxe_close(struct tty_struct *, struct file *);
-static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
-static void pcxe_set_termios(struct tty_struct *, struct termios *);
-static int pcxe_write(struct tty_struct *, const unsigned char *, int);
-static int pcxe_write_room(struct tty_struct *);
-static int pcxe_chars_in_buffer(struct tty_struct *);
-static void pcxe_flush_buffer(struct tty_struct *);
-static void doevent(int);
-static void receive_data(struct channel *);
-static void pcxxparam(struct tty_struct *, struct channel *ch);
-static void do_softint(void *);
-static inline void pcxe_sched_event(struct channel *, int);
-static void pcxe_start(struct tty_struct *);
-static void pcxe_stop(struct tty_struct *);
-static void pcxe_throttle(struct tty_struct *);
-static void pcxe_unthrottle(struct tty_struct *);
-static void digi_send_break(struct channel *ch, int msec);
-static void shutdown(struct channel *);
-static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
-static inline void memwinon(struct board_info *b, unsigned int win);
-static inline void memwinoff(struct board_info *b, unsigned int win);
-static inline void globalwinon(struct channel *ch);
-static inline void rxwinon(struct channel *ch);
-static inline void txwinon(struct channel *ch);
-static inline void memoff(struct channel *ch);
-static inline void assertgwinon(struct channel *ch);
-static inline void assertmemoff(struct channel *ch);
-static int pcxe_tiocmget(struct tty_struct *tty, struct file *file);
-static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
-			 unsigned int set, unsigned int clear);
-
-#define TZ_BUFSZ 4096
-
-/* function definitions */
-
-/*****************************************************************************/
-
-static void cleanup_board_resources(void)
-{
-	int crd, i;
-	struct board_info *bd;
-	struct channel *ch;
-
-        for(crd = 0; crd < numcards; crd++) {
-                bd = &boards[crd];
-		ch = digi_channels + bd->first_minor;
-
-		if (bd->region)
-			release_region(bd->port, 4);
-
-		for(i = 0; i < bd->numports; i++, ch++)
-			if (ch->tmp_buf)
-				kfree(ch->tmp_buf);
-	}
-}
-
-static void __exit pcxe_cleanup(void)
-{
-
-	unsigned long	flags;
-	int e1;
-
-	printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION);
-
-	save_flags(flags);
-	cli();
-	del_timer_sync(&pcxx_timer);
-
-	if ((e1 = tty_unregister_driver(pcxe_driver)))
-		printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
-
-	put_tty_driver(pcxe_driver);
-	cleanup_board_resources();
-	kfree(digi_channels);
-	restore_flags(flags);
-}
-
-static inline struct channel *chan(register struct tty_struct *tty)
-{
-	if (tty) {
-		register struct channel *ch=(struct channel *)tty->driver_data;
-		if (ch >= digi_channels && ch < digi_channels+nbdevs) {
-			if (ch->magic==PCXX_MAGIC)
-				return ch;
-		}
-	}
-	return NULL;
-}
-
-/* These inline routines are to turn board memory on and off */
-static inline void memwinon(struct board_info *b, unsigned int win)
-{
-	if(b->type == PCXEVE)
-		outb_p(FEPWIN|win, b->port+1);
-	else
-		outb_p(inb(b->port)|FEPMEM, b->port);
-}
-
-static inline void memwinoff(struct board_info *b, unsigned int win)
-{
-	outb_p(inb(b->port)&~FEPMEM, b->port);
-	if(b->type == PCXEVE)
-		outb_p(0, b->port + 1);
-}
-
-static inline void globalwinon(struct channel *ch)
-{
-	if(ch->board->type == PCXEVE)
-		outb_p(FEPWIN, ch->board->port+1);
-	else
-		outb_p(FEPMEM, ch->board->port);
-}
-
-static inline void rxwinon(struct channel *ch)
-{
-	if(ch->rxwin == 0)
-		outb_p(FEPMEM, ch->board->port);
-	else 
-		outb_p(ch->rxwin, ch->board->port+1);
-}
-
-static inline void txwinon(struct channel *ch)
-{
-	if(ch->txwin == 0)
-		outb_p(FEPMEM, ch->board->port);
-	else
-		outb_p(ch->txwin, ch->board->port+1);
-}
-
-static inline void memoff(struct channel *ch)
-{
-	outb_p(0, ch->board->port);
-	if(ch->board->type == PCXEVE)
-		outb_p(0, ch->board->port+1);
-}
-
-static inline void assertgwinon(struct channel *ch)
-{
-	if(ch->board->type != PCXEVE)
-		pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
-}
-
-static inline void assertmemoff(struct channel *ch)
-{
-	if(ch->board->type != PCXEVE)
-		pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
-}
-
-static inline void pcxe_sched_event(struct channel *info, int event)
-{
-	info->event |= 1 << event;
-	schedule_work(&info->tqueue);
-}
-
-static void pcxx_error(int line, char *msg)
-{
-	printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
-}
-
-static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int	retval = 0;
-	int	do_clocal = 0;
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-	/*
-	 * Block waiting for the carrier detect and the line to become free
-	 */
-
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-	info->count--;
-	info->blocked_open++;
-
-	for (;;) {
-		cli();
-		globalwinon(info);
-		info->omodem |= DTR|RTS;
-		fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
-		memoff(info);
-		sti();
-		set_current_state(TASK_INTERRUPTIBLE);
-		if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
-			if(info->asyncflags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-			break;
-		}
-		if ((info->asyncflags & ASYNC_CLOSING) == 0 &&
-			(do_clocal || (info->imodem & info->dcd)))
-			break;
-		if(signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-
-	if(!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-
-	return retval;
-}	
-
-
-int pcxe_open(struct tty_struct *tty, struct file * filp)
-{
-	volatile struct board_chan *bc;
-	struct channel *ch;
-	unsigned long flags;
-	int line;
-	int boardnum;
-	int retval;
-
-	line = tty->index;
-
-	if(line < 0 || line >= nbdevs) {
-		printk("line out of range in pcxe_open\n");
-		tty->driver_data = NULL;
-		return(-ENODEV);
-	}
-
-	for(boardnum=0;boardnum<numcards;boardnum++)
-		if ((line >= boards[boardnum].first_minor) && 
-			(line < boards[boardnum].first_minor + boards[boardnum].numports))
-		break;
-
-	if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
-		(line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
-		tty->driver_data = NULL;   /* Mark this device as 'down' */
-		return(-ENODEV);
-	}
-
-	ch = digi_channels+line;
-
-	if(ch->brdchan == 0) {
-		tty->driver_data = NULL;
-		return(-ENODEV);
-	}
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if(ch->asyncflags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&ch->close_wait);
-		if(ch->asyncflags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-	}
-
-	save_flags(flags);
-	cli();
-	ch->count++;
-	tty->driver_data = ch;
-	ch->tty = tty;
-
-	if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
-		unsigned int head;
-
-		globalwinon(ch);
-		ch->statusflags = 0;
-		bc=ch->brdchan;
-		ch->imodem = bc->mstat;
-		head = bc->rin;
-		bc->rout = head;
-		ch->tty = tty;
-		pcxxparam(tty,ch);
-		ch->imodem = bc->mstat;
-		bc->idata = 1;
-		ch->omodem = DTR|RTS;
-		fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
-		memoff(ch);
-		ch->asyncflags |= ASYNC_INITIALIZED;
-	}
-	restore_flags(flags);
-
-	if(ch->asyncflags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&ch->close_wait);
-		if(ch->asyncflags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-	}
-
-	if (!(filp->f_flags & O_NONBLOCK)) {
-		/* this has to be set in order for the "block until
-		 * CD" code to work correctly.  i'm not sure under
-		 * what circumstances asyncflags should be set to
-		 * ASYNC_NORMAL_ACTIVE though
-		 * brian@ilinx.com
-		 */
-		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-		if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
-			return retval;
-	}
-	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- 	
-	return 0;
-} 
-
-static void shutdown(struct channel *info)
-{
-	unsigned long flags;
-	volatile struct board_chan *bc;
-	struct tty_struct *tty;
-
-	if (!(info->asyncflags & ASYNC_INITIALIZED)) 
-		return;
-
-	save_flags(flags);
-	cli();
-	globalwinon(info);
-
-	bc = info->brdchan;
-	if(bc)
-		bc->idata = 0;
-
-	tty = info->tty;
-
-	/*
-	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
-	 */
-	if(tty->termios->c_cflag & HUPCL) {
-		info->omodem &= ~(RTS|DTR);
-		fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
-	}
-
-	memoff(info);
-	info->asyncflags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
-}
-
-
-static void pcxe_close(struct tty_struct * tty, struct file * filp)
-{
-	struct channel *info;
-
-	if ((info=chan(tty))!=NULL) {
-		unsigned long flags;
-		save_flags(flags);
-		cli();
-
-		if(tty_hung_up_p(filp)) {
-			/* flag that somebody is done with this module */
-			restore_flags(flags);
-			return;
-		}
-		/* this check is in serial.c, it won't hurt to do it here too */
-		if ((tty->count == 1) && (info->count != 1)) {
-			/*
-			 * Uh, oh.  tty->count is 1, which means that the tty
-			 * structure will be freed.  Info->count should always
-			 * be one in these conditions.  If it's greater than
-			 * one, we've got real problems, since it means the
-			 * serial port won't be shutdown.
-			 */
-			printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
-			info->count = 1;
-		}
-		if (info->count-- > 1) {
-			restore_flags(flags);
-			return;
-		}
-		if (info->count < 0) {
-			info->count = 0;
-		}
-
-		info->asyncflags |= ASYNC_CLOSING;
-	
-		tty->closing = 1;
-		if(info->asyncflags & ASYNC_INITIALIZED) {
-			setup_empty_event(tty,info);		
-			tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
-		}
-	
-		if(tty->driver->flush_buffer)
-			tty->driver->flush_buffer(tty);
-		tty_ldisc_flush(tty);
-		shutdown(info);
-		tty->closing = 0;
-		info->event = 0;
-		info->tty = NULL;
-		if(info->blocked_open) {
-			if(info->close_delay) {
-				msleep_interruptible(jiffies_to_msecs(info->close_delay));
-			}
-			wake_up_interruptible(&info->open_wait);
-		}
-		info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-		wake_up_interruptible(&info->close_wait);
-		restore_flags(flags);
-	}
-}
-
-
-void pcxe_hangup(struct tty_struct *tty)
-{
-	struct channel *ch;
-
-	if ((ch=chan(tty))!=NULL) {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		shutdown(ch);
-		ch->event = 0;
-		ch->count = 0;
-		ch->tty = NULL;
-		ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-		wake_up_interruptible(&ch->open_wait);
-		restore_flags(flags);
-	}
-}
-
-
-
-static int pcxe_write(struct tty_struct * tty, const unsigned char *buf, int count)
-{
-	struct channel *ch;
-	volatile struct board_chan *bc;
-	int total, remain, size, stlen;
-	unsigned int head, tail;
-	unsigned long flags;
-	/* printk("Entering pcxe_write()\n"); */
-
-	if ((ch=chan(tty))==NULL)
-		return 0;
-
-	bc = ch->brdchan;
-	size = ch->txbufsize;
-
-	/*
-	 * All data is now local
-	 */
-
-	total = 0;
-	save_flags(flags);
-	cli();
-	globalwinon(ch);
-	head = bc->tin & (size - 1);
-	tail = bc->tout;
-	if (tail != bc->tout)
-		tail = bc->tout;
-	tail &= (size - 1);
-	if (head >= tail) {
-		remain = size - (head - tail) - 1;
-		stlen = size - head;
-	}
-	else {
-		remain = tail - head - 1;
-		stlen = remain;
-	}
-	count = min(remain, count);
-
-	txwinon(ch);
-	while (count > 0) {
-		stlen = min(count, stlen);
-		memcpy(ch->txptr + head, buf, stlen);
-		buf += stlen;
-		count -= stlen;
-		total += stlen;
-		head += stlen;
-		if (head >= size) {
-			head = 0;
-			stlen = tail;
-		}
-	}
-	ch->statusflags |= TXBUSY;
-	globalwinon(ch);
-	bc->tin = head;
-	if ((ch->statusflags & LOWWAIT) == 0) {
-		ch->statusflags |= LOWWAIT;
-		bc->ilow = 1;
-	}
-	memoff(ch);
-	restore_flags(flags);
-	
-	return(total);
-}
-
-
-static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
-{
-	pcxe_write(tty, &c, 1);
-	return;
-}
-
-
-static int pcxe_write_room(struct tty_struct *tty)
-{
-	struct channel *ch;
-	int remain;
-
-	remain = 0;
-	if ((ch=chan(tty))!=NULL) {
-		volatile struct board_chan *bc;
-		unsigned int head, tail;
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		globalwinon(ch);
-
-		bc = ch->brdchan;
-		head = bc->tin & (ch->txbufsize - 1);
-		tail = bc->tout;
-		if (tail != bc->tout)
-			tail = bc->tout;
-		tail &= (ch->txbufsize - 1);
-
-		if((remain = tail - head - 1) < 0 )
-			remain += ch->txbufsize;
-
-		if (remain && (ch->statusflags & LOWWAIT) == 0) {
-			ch->statusflags |= LOWWAIT;
-			bc->ilow = 1;
-		}
-		memoff(ch);
-		restore_flags(flags);
-	}
-
-	return remain;
-}
-
-
-static int pcxe_chars_in_buffer(struct tty_struct *tty)
-{
-	int chars;
-	unsigned int ctail, head, tail;
-	int remain;
-	unsigned long flags;
-	struct channel *ch;
-	volatile struct board_chan *bc;
-
-	if ((ch=chan(tty))==NULL)
-		return(0);
-
-	save_flags(flags);
-	cli();
-	globalwinon(ch);
-
-	bc = ch->brdchan;
-	tail = bc->tout;
-	head = bc->tin;
-	ctail = ch->mailbox->cout;
-	if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
-		chars = 0;
-	else {
-		head = bc->tin & (ch->txbufsize - 1);
-		tail &= (ch->txbufsize - 1);
-		if((remain = tail - head - 1) < 0 )
-			remain += ch->txbufsize;
-
-		chars = (int)(ch->txbufsize - remain);
-
-		/* 
-		 * Make it possible to wakeup anything waiting for output
-		 * in tty_ioctl.c, etc.
-		 */
-		if(!(ch->statusflags & EMPTYWAIT))
-			setup_empty_event(tty,ch);
-	}
-
-	memoff(ch);
-	restore_flags(flags);
-
-	return(chars);
-}
-
-
-static void pcxe_flush_buffer(struct tty_struct *tty)
-{
-	unsigned int tail;
-	volatile struct board_chan *bc;
-	struct channel *ch;
-	unsigned long flags;
-
-	if ((ch=chan(tty))==NULL)
-		return;
-
-	save_flags(flags);
-	cli();
-
-	globalwinon(ch);
-	bc = ch->brdchan;
-	tail = bc->tout;
-	fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
-
-	memoff(ch);
-	restore_flags(flags);
-
-	tty_wakeup(tty);
-}
-
-static void pcxe_flush_chars(struct tty_struct *tty)
-{
-	struct channel * ch;
-
-	if ((ch=chan(tty))!=NULL) {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
-			setup_empty_event(tty,ch);
-		restore_flags(flags);
-	}
-}
-
-#ifndef MODULE
-
-/*
- * Driver setup function when linked into the kernel to optionally parse multible
- * "digi="-lines and initialize the driver at boot time. No probing.
- */
-void __init pcxx_setup(char *str, int *ints)
-{
-
-	struct board_info board;
-	int               i, j, last;
-	char              *temp, *t2;
-	unsigned          len;
-
-	numcards=0;
-
-	memset(&board, 0, sizeof(board));
-
-	for(last=0,i=1;i<=ints[0];i++)
-		switch(i)
-		{
-			case 1:
-				board.status = ints[i];
-				last = i;
-				break;
-
-			case 2:
-				board.type = ints[i];
-				last = i;
-				break;
-
-			case 3:
-				board.altpin = ints[i];
-				last = i;
-				break;
-
-			case 4:
-				board.numports = ints[i];
-				last = i;
-				break;
-
-			case 5:
-				board.port = ints[i];
-				last = i;
-				break;
-
-			case 6:
-				board.membase = ints[i];
-				last = i;
-				break;
-
-			default:
-				printk("PC/Xx: Too many integer parms\n");
-				return;
-		}
-
-	while (str && *str) 
-	{
-		/* find the next comma or terminator */
-		temp = str;
-		while (*temp && (*temp != ','))
-			temp++;
-
-		if (!*temp)
-			temp = NULL;
-		else
-			*temp++ = 0;
-
-		i = last + 1;
-
-		switch(i)
-		{
-			case 1:
-				len = strlen(str);
-				if (strncmp("Disable", str, len) == 0) 
-					board.status = 0;
-				else
-					if (strncmp("Enable", str, len) == 0)
-						board.status = 1;
-					else
-					{
-						printk("PC/Xx: Invalid status %s\n", str);
-						return;
-					}
-				last = i;
-				break;
-
-			case 2:
-				for(j=0;j<PCXX_NUM_TYPES;j++)
-					if (strcmp(board_desc[j], str) == 0)
-						break;
-
-				if (i<PCXX_NUM_TYPES) 
-					board.type = j;
-				else
-				{
-					printk("PC/Xx: Invalid board name: %s\n", str);
-					return;
-				}
-				last = i;
-				break;
-
-			case 3:
-				len = strlen(str);
-				if (strncmp("Disable", str, len) == 0) 
-					board.altpin = 0;
-				else
-					if (strncmp("Enable", str, len) == 0)
-						board.altpin = 1;
-					else
-					{
-						printk("PC/Xx: Invalid altpin %s\n", str);
-						return;
-					}
-				last = i;
-				break;
-
-			case 4:
-				t2 = str;
-				while (isdigit(*t2))
-					t2++;
-
-				if (*t2)
-				{
-					printk("PC/Xx: Invalid port count %s\n", str);
-					return;
-				}
-
-				board.numports = simple_strtoul(str, NULL, 0);
-				last = i;
-				break;
-
-			case 5:
-				t2 = str;
-				while (isxdigit(*t2))
-					t2++;
-
-				if (*t2)
-				{
-					printk("PC/Xx: Invalid io port address %s\n", str);
-					return;
-				}
-
-				board.port = simple_strtoul(str, NULL, 16);
-				last = i;
-				break;
-
-			case 6:
-				t2 = str;
-				while (isxdigit(*t2))
-					t2++;
-
-				if (*t2)
-				{
-					printk("PC/Xx: Invalid memory base %s\n", str);
-					return;
-				}
-
-				board.membase = simple_strtoul(str, NULL, 16);
-				last = i;
-				break;
-
-			default:
-				printk("PC/Xx: Too many string parms\n");
-				return;
-		}
-		str = temp;
-	}
-
-	if (last < 6)  
-	{
-		printk("PC/Xx: Insufficient parms specified\n");
-		return;
-	}
- 
-        /* I should REALLY validate the stuff here */
-
-	memcpy(&boards[numcards],&board, sizeof(board));
-	printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", 
-		numcards, board_desc[board.type], board_mem[board.type], 
-		board.numports, board.port, (unsigned int) board.membase);
-
-	/* keep track of my initial minor number */
-        if (numcards)
-		boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
-	else
-		boards[numcards].first_minor = 0;
-
-	/* yeha!  string parameter was successful! */
-	numcards++;
-}
-#endif
-
-static struct tty_operations pcxe_ops = {
-	.open = pcxe_open,
-	.close = pcxe_close,
-	.write = pcxe_write,
-	.put_char = pcxe_put_char,
-	.flush_chars = pcxe_flush_chars,
-	.write_room = pcxe_write_room,
-	.chars_in_buffer = pcxe_chars_in_buffer,
-	.flush_buffer = pcxe_flush_buffer,
-	.ioctl = pcxe_ioctl,
-	.throttle = pcxe_throttle,
-	.unthrottle = pcxe_unthrottle,
-	.set_termios = pcxe_set_termios,
-	.stop = pcxe_stop,
-	.start = pcxe_start,
-	.hangup = pcxe_hangup,
-	.tiocmget = pcxe_tiocmget,
-	.tiocmset = pcxe_tiocmset,
-};
-
-/*
- * function to initialize the driver with the given parameters, which are either
- * the default values from this file or the parameters given at boot.
- */
-static int __init pcxe_init(void)
-{
-	ulong memory_seg=0, memory_size=0;
-	int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
-	int ret = -ENOMEM;
-	unchar *fepos, *memaddr, *bios, v;
-	volatile struct global_data *gd;
-	volatile struct board_chan *bc;
-	struct board_info *bd;
-	struct channel *ch;
-
-	printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
-
-#ifdef MODULE
-	for (i = 0; i < MAX_DIGI_BOARDS; i++) {
-		if (io[i]) {
-			numcards = 0;
-			break;
-		}
-	}
-	if (numcards == 0) {
-		int first_minor = 0;
-
-		for (i = 0; i < MAX_DIGI_BOARDS; i++) {
-			if (io[i] == 0) {
-				boards[i].port    = 0;
-				boards[i].status  = DISABLED;
-			}
-			else {
-				boards[i].port         = (ushort)io[i];
-				boards[i].status       = ENABLED;
-				boards[i].first_minor  = first_minor;
-				numcards=i+1;
-			}
-			if (membase[i])
-				boards[i].membase = (ulong)membase[i];
-			else
-				boards[i].membase = 0xD0000;
-
-			if (memsize[i])
-				boards[i].memsize = (ulong)(memsize[i] * 1024);
-			else
-				boards[i].memsize = 0;
-
-			if (altpin[i])
-				boards[i].altpin  = ON;
-			else
-				boards[i].altpin  = OFF;
-
-			if (numports[i])
-				boards[i].numports  = (ushort)numports[i];
-			else
-				boards[i].numports  = 16;
-
-			boards[i].region = NULL;
-			first_minor += boards[i].numports;
-		}
-	}
-#endif
-
-	if (numcards <= 0)
-	{
-		printk("PC/Xx: No cards configured, driver not active.\n");
-		return -EIO;
-	}
-#if 1
-	if (debug)
-	    for (i = 0; i < numcards; i++) {
-		    printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
-			    i+1,
-			    boards[i].status,
-			    boards[i].port,
-			    boards[i].membase,
-			    boards[i].memsize,
-			    boards[i].altpin,
-			    boards[i].numports,
-			    boards[i].first_minor);
-	    }
-#endif
-
-	for (i=0;i<numcards;i++)
-		nbdevs += boards[i].numports;
-
-	if (nbdevs <= 0)
-	{
-		printk("PC/Xx: No devices activated, driver not active.\n");
-		return -EIO;
-	}
-
-	pcxe_driver = alloc_tty_driver(nbdevs);
-	if (!pcxe_driver)
-		return -ENOMEM;
-
-	/*
-	 * this turns out to be more memory efficient, as there are no 
-	 * unused spaces.
-	 */
-	digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
-	if (!digi_channels) {
-		printk(KERN_ERR "Unable to allocate digi_channel struct\n");
-		put_tty_driver(pcxe_driver);
-		return -ENOMEM;
-	}
-	memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
-
-	init_timer(&pcxx_timer);
-	pcxx_timer.function = pcxxpoll;
-
-	pcxe_driver->owner = THIS_MODULE;
-	pcxe_driver->name = "ttyD";
-	pcxe_driver->devfs_name = "pcxe/";
-	pcxe_driver->major = DIGI_MAJOR; 
-	pcxe_driver->minor_start = 0;
-	pcxe_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	pcxe_driver->subtype = SERIAL_TYPE_NORMAL;
-	pcxe_driver->init_termios = tty_std_termios;
-	pcxe_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
-	pcxe_driver->flags = TTY_DRIVER_REAL_RAW;
-	tty_set_operations(pcxe_driver, &pcxe_ops);
-
-	for(crd=0; crd < numcards; crd++) {
-		bd = &boards[crd];
-		outb(FEPRST, bd->port);
-		mdelay(1);
-
-		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
-			if(i > 100) {
-				printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
-					bd->port);
-				bd->status = DISABLED;
-				break;
-			}
-#ifdef MODULE
-			schedule();
-#endif
-			mdelay(10);
-		}
-		if(bd->status == DISABLED)
-			continue;
-
-		v = inb(bd->port);
-
-		if((v & 0x1) == 0x1) {
-			if((v & 0x30) == 0) {        /* PC/Xi 64K card */
-				memory_seg = 0xf000;
-				memory_size = 0x10000;
-			} 
-
-			if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */
-				memory_seg = 0xe000;
-				memory_size = 0x20000;
-			}
-			
-			if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */
-				memory_seg = 0xc000;
-				memory_size = 0x40000;
-			}
-
-			if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */
-				memory_seg = 0x8000;
-				memory_size = 0x80000;
-			}
-			bd->type = PCXI;
-		} else {
-			if((v & 0x1) == 0x1) {
-				bd->status = DISABLED;   /* PC/Xm unsupported card */
-				printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
-				continue;
-			} else {
-				if(v & 0xC0) {    
-					topwin = 0x1f00L;
-					outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
-					outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
-					bd->type = PCXEVE; /* PC/Xe 8K card */
-				} else { 
-					bd->type = PCXE;    /* PC/Xe 64K card */
-				}
-					
-				memory_seg = 0xf000;
-				memory_size = 0x10000;
-			}
-		}
-		if (verbose)
-			printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
-				crd+1, board_desc[bd->type], memory_size/1024,
-				bd->port,bd->membase,bd->membase+memory_size-1);
-
-		if (boards[crd].memsize == 0)
-			boards[crd].memsize = memory_size;
-		else
-			if (boards[crd].memsize != memory_size) {
-			    printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
-				    boards[crd].memsize, boards[crd].memsize / 1024,
-				    memory_size, memory_size / 1024);
-			    continue;
-			}
-
-		memaddr = (unchar *)phys_to_virt(bd->membase);
-
-		if (verbose)
-			printk("Resetting board and testing memory access:");
-
-		outb(FEPRST|FEPMEM, bd->port);
-
-		for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
-			if(i > 1000) {
-				printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
-					board_desc[bd->type], bd->port);
-				bd->status = DISABLED;
-				break;
-			}
-#ifdef MODULE
-			schedule();
-#endif
-			mdelay(1);
-		}
-		if(bd->status == DISABLED)
-			continue;
-
-		memwinon(bd,0);
-		*(ulong *)(memaddr + botwin) = 0xa55a3cc3;
-		*(ulong *)(memaddr + topwin) = 0x5aa5c33c;
-
-		if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
-					*(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
-			printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
-				bd->membase, board_desc[bd->type], bd->port);
-			bd->status = DISABLED;
-			continue;
-		}
-		if (verbose)
-			printk(" done.\n");
-
-		for(i=0; i < 16; i++) {
-			memaddr[MISCGLOBAL+i] = 0;
-		}
-
-		if(bd->type == PCXI || bd->type == PCXE) {
-			bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
-
-			if (verbose)
-				printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
-
-			memcpy(bios, pcxx_bios, pcxx_nbios);
-
-			if (verbose)
-				printk(" done.\n");
-
-			outb(FEPMEM, bd->port);
-
-			if (verbose)
-				printk("Waiting for BIOS to become ready");
-
-			for(i=1; i <= 30; i++) {
-				if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
-					goto load_fep;
-				}
-				if (verbose) {
-					printk(".");
-					if (i % 50 == 0)
-						printk("\n");
-				}
-#ifdef MODULE
-				schedule();
-#endif
-				mdelay(50);
-			}
-
-			printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
-							bd->port, bd->membase, bd->membase+bd->memsize);
-			bd->status = DISABLED;
-			continue;
-		}
-
-		if(bd->type == PCXEVE) {
-			bios = memaddr + (BIOSCODE & 0x1fff);
-			memwinon(bd,0xff);
-			
-			memcpy(bios, pcxx_bios, pcxx_nbios);
-
-			outb(FEPCLR, bd->port);
-			memwinon(bd,0);
-
-			for(i=0; i <= 1000; i++) {
-				if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
-					goto load_fep;
-				}
-				if (verbose) {
-					printk(".");
-					if (i % 50 == 0)
-						printk("\n");
-				}
-#ifdef MODULE
-				schedule();
-#endif
-				mdelay(10);
-			}
-
-			printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
-				board_desc[bd->type], bd->port);
-			bd->status = DISABLED;
-			continue;
-		}
-
-load_fep:
-		fepos = memaddr + FEPCODE;
-		if(bd->type == PCXEVE)
-			fepos = memaddr + (FEPCODE & 0x1fff);
-
-		if (verbose)
-			printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
-
-		memwinon(bd, (FEPCODE >> 13));
-		memcpy(fepos, pcxx_cook, pcxx_ncook);
-		memwinon(bd, 0);
-
-		if (verbose)
-			printk(" done.\n");
-
-		*(ushort *)((ulong)memaddr + MBOX +  0) = 2;
-		*(ushort *)((ulong)memaddr + MBOX +  2) = memory_seg + FEPCODESEG;
-		*(ushort *)((ulong)memaddr + MBOX +  4) = 0;
-		*(ushort *)((ulong)memaddr + MBOX +  6) = FEPCODESEG;
-		*(ushort *)((ulong)memaddr + MBOX +  8) = 0;
-		*(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
-
-		outb(FEPMEM|FEPINT, bd->port);
-		outb(FEPMEM, bd->port);
-
-		for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
-			if(i > 2000) {
-				printk("PC/Xx: Command failed for the %s at 0x%x!\n",
-					board_desc[bd->type], bd->port);
-				bd->status = DISABLED;
-				break;
-			}
-#ifdef MODULE
-			schedule();
-#endif
-			mdelay(1);
-		}
-
-		if(bd->status == DISABLED)
-			continue;
-
-		if (verbose)
-			printk("Waiting for FEP/OS to become ready");
-
-		*(ushort *)(memaddr + FEPSTAT) = 0;
-		*(ushort *)(memaddr + MBOX + 0) = 1;
-		*(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
-		*(ushort *)(memaddr + MBOX + 4) = 0x4L;
-
-		outb(FEPINT, bd->port);
-		outb(FEPCLR, bd->port);
-		memwinon(bd, 0);
-
-		for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
-			if(i > 1000) {
-				printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
-					board_desc[bd->type], bd->port);
-				bd->status = DISABLED;
-				break;
-			}
-			if (verbose) {
-				printk(".");
-				if (i % 50 == 0)
-					printk("\n%5d",i/50);
-			}
-#ifdef MODULE
-			schedule();
-#endif
-			mdelay(1);
-		}
-		if(bd->status == DISABLED)
-			continue;
-
-		if (verbose)
-			printk(" ok.\n");
-
-		ch = digi_channels+bd->first_minor;
-		pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
-
-		bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
-		gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
-
-		if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
-			shrinkmem = 1;
-
-		bd->region = request_region(bd->port, 4, "PC/Xx");
-
-		if (!bd->region) {
-			printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port);
-			ret = -EBUSY;
-			goto cleanup_boards;
-		}
-
-		for(i=0; i < bd->numports; i++, ch++, bc++) {
-			if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
-				ch->brdchan = 0;
-				continue;
-			}
-			ch->brdchan = bc;
-			ch->mailbox = gd;
-			INIT_WORK(&ch->tqueue, do_softint, ch);
-			ch->board = &boards[crd];
-#ifdef DEFAULT_HW_FLOW
-			ch->digiext.digi_flags = RTSPACE|CTSPACE;
-#endif
-			if(boards[crd].altpin) {
-				ch->dsr = CD;
-				ch->dcd = DSR;
-				ch->digiext.digi_flags |= DIGI_ALTPIN;
-			} else { 
-				ch->dcd = CD;
-				ch->dsr = DSR;
-			}
-
-			ch->magic = PCXX_MAGIC;
-			ch->boardnum = crd;
-			ch->channelnum = i;
-
-			ch->dev = bd->first_minor + i;
-			ch->tty = 0;
-
-			if(shrinkmem) {
-				fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
-				shrinkmem = 0;
-			}
-			
-			if(bd->type != PCXEVE) {
-				ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
-				ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
-				ch->txwin = ch->rxwin = 0;
-			} else {
-				ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
-				ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
-				ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
-				ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
-			}
-
-			ch->txbufsize = bc->tmax + 1;
-			ch->rxbufsize = bc->rmax + 1;
-			ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
-			init_MUTEX(&ch->tmp_buf_sem);
-
-			if (!ch->tmp_buf) {
-				printk(KERN_ERR "Unable to allocate memory for temp buffers\n");
-				goto cleanup_boards;
-			}
-
-			lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
-			fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
-			fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
-			fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
-
-			bc->edelay = 100;
-			bc->idata = 1;
-
-			ch->startc = bc->startc;
-			ch->stopc = bc->stopc;
-			ch->startca = bc->startca;
-			ch->stopca = bc->stopca;
-
-			ch->fepcflag = 0;
-			ch->fepiflag = 0;
-			ch->fepoflag = 0;
-			ch->fepstartc = 0;
-			ch->fepstopc = 0;
-			ch->fepstartca = 0;
-			ch->fepstopca = 0;
-
-			ch->close_delay = 50;
-			ch->count = 0;
-			ch->blocked_open = 0;
-			init_waitqueue_head(&ch->open_wait);
-			init_waitqueue_head(&ch->close_wait);
-			ch->asyncflags = 0;
-		}
-
-		if (verbose)
-		    printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
-			    crd+1, board_desc[bd->type], board_mem[bd->type], bd->port, 
-			    bd->membase, bd->numports);
-		else
-		    printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
-			    board_desc[bd->type], board_mem[bd->type], bd->port, 
-			    bd->membase, bd->numports);
-
-		memwinoff(bd, 0);
-		enabled_cards++;
-	}
-
-	if (enabled_cards <= 0) {
-		printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
-		ret = -EIO;
-		goto cleanup_boards;
-	}
-
-	ret = tty_register_driver(pcxe_driver);
-	if(ret) {
-		printk(KERN_ERR "Couldn't register PC/Xe driver\n");
-		goto cleanup_boards;
-	}
-
-	/*
-	 * Start up the poller to check for events on all enabled boards
-	 */
-	mod_timer(&pcxx_timer, HZ/25);
-
-	if (verbose)
-		printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
-
-	return 0;
-cleanup_boards:
-	cleanup_board_resources();
-	kfree(digi_channels);
-	put_tty_driver(pcxe_driver);
-	return ret;
-}
-
-module_init(pcxe_init)
-module_exit(pcxe_cleanup)
-
-static void pcxxpoll(unsigned long dummy)
-{
-	unsigned long flags;
-	int crd;
-	volatile unsigned int head, tail;
-	struct channel *ch;
-	struct board_info *bd;
-
-	save_flags(flags);
-	cli();
-
-	for(crd=0; crd < numcards; crd++) {
-		bd = &boards[crd];
-
-		ch = digi_channels+bd->first_minor;
-
-		if(bd->status == DISABLED)
-			continue;
-
-		assertmemoff(ch);
-
-		globalwinon(ch);
-		head = ch->mailbox->ein;
-		tail = ch->mailbox->eout;
-
-		if(head != tail)
-			doevent(crd);
-
-		memoff(ch);
-	}
-
-	mod_timer(&pcxx_timer, jiffies + HZ/25);
-	restore_flags(flags);
-}
-
-static void doevent(int crd)
-{
-	volatile struct board_info *bd;
-	static struct tty_struct *tty;
-	volatile struct board_chan *bc;
-	volatile unchar *eventbuf;
-	volatile unsigned int head;
-	volatile unsigned int tail;
-	struct channel *ch;
-	struct channel *chan0;
-	int channel, event, mstat, lstat;
-
-	bd = &boards[crd];
-
-	chan0 = digi_channels+bd->first_minor;
-	pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
-
-
-	assertgwinon(chan0);
-
-	while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
-		assertgwinon(chan0);
-		eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
-		channel = eventbuf[0];
-		event = eventbuf[1];
-		mstat = eventbuf[2];
-		lstat = eventbuf[3];
-
-		ch=chan0+channel;
-
-		if ((unsigned)channel >= bd->numports || !ch) { 
-			printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
-			printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
-					crd, (unsigned)channel, event, (unsigned)mstat, lstat);
-			if(channel >= bd->numports)
-				ch = chan0;
-			bc = ch->brdchan;
-			goto next;
-		}
-		if ((bc = ch->brdchan) == NULL)
-			goto next;
-
-		if (event & DATA_IND) {
-			receive_data(ch);
-			assertgwinon(ch);
-		}
-
-		if (event & MODEMCHG_IND) {
-			ch->imodem = mstat;
-			if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) {
-				if (ch->asyncflags & ASYNC_CHECK_CD) {
-					if (mstat & ch->dcd) {
-						wake_up_interruptible(&ch->open_wait);
-					} else {
-						pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
-					}
-				}
-			}
-		}
-
-		tty = ch->tty;
-
-		if (tty) {
-
-			if (event & BREAK_IND) {
-				tty->flip.count++;
-				*tty->flip.flag_buf_ptr++ = TTY_BREAK;
-				*tty->flip.char_buf_ptr++ = 0;
-#if 0
-				if (ch->asyncflags & ASYNC_SAK)
-					do_SAK(tty);
-#endif
-				tty_schedule_flip(tty); 
-			}
-
-			if (event & LOWTX_IND) {
-				if (ch->statusflags & LOWWAIT) {
-					ch->statusflags &= ~LOWWAIT;
-					tty_wakeup(tty);
-				}
-			}
-
-			if (event & EMPTYTX_IND) {
-				ch->statusflags &= ~TXBUSY;
-				if (ch->statusflags & EMPTYWAIT) {
-					ch->statusflags &= ~EMPTYWAIT;
-					tty_wakeup(tty);
-				}
-			}
-		}
-
-	next:
-		globalwinon(ch);
-		if(!bc) printk("bc == NULL in doevent!\n");
-		else bc->idata = 1;
-
-		chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
-		globalwinon(chan0);
-	}
-
-}
-
-
-static void 
-fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
-						int bytecmd)
-{
-	unchar *memaddr;
-	unsigned int head, tail;
-	long count;
-	int n;
-
-	if(ch->board->status == DISABLED)
-		return;
-
-	assertgwinon(ch);
-
-	memaddr = (unchar *)phys_to_virt(ch->board->membase);
-	head = ch->mailbox->cin;
-
-	if(head >= (CMAX-CSTART) || (head & 03)) {
-		printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
-		return;
-	}
-
-	if(bytecmd) {
-		*(unchar *)(memaddr+head+CSTART+0) = cmd;
-
-		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
-
-		*(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
-		*(unchar *)(memaddr+head+CSTART+3) = byte2;
-	} else {
-		*(unchar *)(memaddr+head+CSTART+0) = cmd;
-
-		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
-		*(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
-	}
-
-	head = (head+4) & (CMAX-CSTART-4);
-	ch->mailbox->cin = head;
-
-	count = FEPTIMEOUT;
-
-	while(1) {
-		count--;
-		if(count == 0) {
-			printk("Fep not responding in fepcmd()\n");
-			return;
-		}
-
-		head = ch->mailbox->cin;
-		tail = ch->mailbox->cout;
-
-		n = (head-tail) & (CMAX-CSTART-4);
-
-		if(n <= ncmds * (sizeof(short)*4))
-			break;
-		/* Seems not to be good here: schedule(); */
-	}
-}
-
-
-static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
-{
-	unsigned res = 0;
-	if (cflag & CBAUDEX)
-	{
-		ch->digiext.digi_flags |= DIGI_FAST;
-		res |= FEP_HUPCL;
-		/* This gets strange but if we don't do this we will get 78600
-		 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
-		 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
-		 * do 115K
-		 */
-		if (cflag & B115200) res|=1;
-	}
-	else ch->digiext.digi_flags &= ~DIGI_FAST;
-	res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
-	return res;
-}
-
-static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
-{
-	unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
-	
-	if(ch->digiext.digi_flags & DIGI_AIXON)
-		res |= IAIXON;
-	return res;
-}
-
-static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
-{
-	unsigned res = 0;
-
-	if(cflag & CRTSCTS) {
-		ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
-		res |= (CTS | RTS);
-	}
-	if(ch->digiext.digi_flags & RTSPACE)
-		res |= RTS;
-	if(ch->digiext.digi_flags & DTRPACE)
-		res |= DTR;
-	if(ch->digiext.digi_flags & CTSPACE)
-		res |= CTS;
-	if(ch->digiext.digi_flags & DSRPACE)
-		res |= ch->dsr;
-	if(ch->digiext.digi_flags & DCDPACE)
-		res |= ch->dcd;
-
-	if (res & RTS)
-		ch->digiext.digi_flags |= RTSPACE;
-	if (res & CTS)
-		ch->digiext.digi_flags |= CTSPACE;
-
-	return res;
-}
-
-static void pcxxparam(struct tty_struct *tty, struct channel *ch)
-{
-	volatile struct board_chan *bc;
-	unsigned int head;
-	unsigned mval, hflow, cflag, iflag;
-	struct termios *ts;
-
-	bc = ch->brdchan;
-	assertgwinon(ch);
-	ts = tty->termios;
-
-	if((ts->c_cflag & CBAUD) == 0) {
-		head = bc->rin;
-		bc->rout = head;
-		head = bc->tin;
-		fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
-		mval = 0;
-	} else {
-
-		cflag = termios2digi_c(ch, ts->c_cflag);
-
-		if(cflag != ch->fepcflag) {
-			ch->fepcflag = cflag;
-			fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
-		}
-
-		if(cflag & CLOCAL)
-			ch->asyncflags &= ~ASYNC_CHECK_CD;
-		else {
-			ch->asyncflags |= ASYNC_CHECK_CD;
-		}
-
-		mval = DTR | RTS;
-	}
-
-	iflag = termios2digi_i(ch, ts->c_iflag);
-
-	if(iflag != ch->fepiflag) {
-		ch->fepiflag = iflag;
-		fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
-	}
-
-	bc->mint = ch->dcd;
-	if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
-		if(ch->digiext.digi_flags & DIGI_FORCEDCD)
-			bc->mint = 0;
-
-	ch->imodem = bc->mstat;
-
-	hflow = termios2digi_h(ch, ts->c_cflag);
-
-	if(hflow != ch->hflow) {
-		ch->hflow = hflow;
-		fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
-	}
-
-	/* mval ^= ch->modemfake & (mval ^ ch->modem); */
-
-	if(ch->omodem != mval) {
-		ch->omodem = mval;
-		fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
-	}
-
-	if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
-		ch->fepstartc = ch->startc;
-		ch->fepstopc = ch->stopc;
-		fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
-	}
-
-	if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
-		ch->fepstartca = ch->startca;
-		ch->fepstopca = ch->stopca;
-		fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
-	}
-}
-
-
-static void receive_data(struct channel *ch)
-{
-	volatile struct board_chan *bc;
-	struct tty_struct *tty;
-	unsigned int tail, head, wrapmask;
-	int n;
-	int piece;
-	struct termios *ts=0;
-	unchar *rptr;
-	int rc;
-	int wrapgap;
-
-    globalwinon(ch);
-
-	if (ch->statusflags & RXSTOPPED)
-		return;
-
-	tty = ch->tty;
-	if(tty)
-		ts = tty->termios;
-
-	bc = ch->brdchan;
-
-	if(!bc) {
-		printk("bc is NULL in receive_data!\n");
-		return;
-	}
-
-	wrapmask = ch->rxbufsize - 1;
-
-	head = bc->rin;
-	head &= wrapmask;
-	tail = bc->rout & wrapmask;
-
-	n = (head-tail) & wrapmask;
-
-	if(n == 0)
-		return;
-
-	/*
-	 * If CREAD bit is off or device not open, set TX tail to head
-	 */
-	if(!tty || !ts || !(ts->c_cflag & CREAD)) {
-		bc->rout = head;
-		return;
-	}
-
-	if(tty->flip.count == TTY_FLIPBUF_SIZE) {
-		/* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
-		return;
-	}
-
-	if(bc->orun) {
-		bc->orun = 0;
-		printk("overrun! DigiBoard device %s\n", tty->name);
-	}
-
-	rxwinon(ch);
-	rptr = tty->flip.char_buf_ptr;
-	rc = tty->flip.count;
-	while(n > 0) {
-		wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
-		piece = (wrapgap < n) ? wrapgap : n;
-
-		/*
-		 * Make sure we don't overflow the buffer
-		 */
-
-		if ((rc + piece) > TTY_FLIPBUF_SIZE)
-			piece = TTY_FLIPBUF_SIZE - rc;
-
-		if (piece == 0)
-			break;
-
-		memcpy(rptr, ch->rxptr + tail, piece);
-		rptr += piece;
-		rc += piece;
-		tail = (tail + piece) & wrapmask;
-		n -= piece;
-	}
-	tty->flip.count = rc;
-	tty->flip.char_buf_ptr = rptr;
-    globalwinon(ch);
-	bc->rout = tail;
-
-	/* Must be called with global data */
-	tty_schedule_flip(ch->tty); 
-	return;
-}
-
-
-static int pcxe_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	struct channel *ch = (struct channel *) tty->driver_data;
-	volatile struct board_chan *bc;
-	unsigned long flags;
-	int mflag = 0;
-	int mstat;
-
-	if(ch)
-		bc = ch->brdchan;
-	else {
-		printk("ch is NULL in %s!\n", __FUNCTION__);
-		return(-EINVAL);
-	}
-
-	save_flags(flags);
-	cli();
-	globalwinon(ch);
-	mstat = bc->mstat;
-	memoff(ch);
-	restore_flags(flags);
-
-	if(mstat & DTR)
-		mflag |= TIOCM_DTR;
-	if(mstat & RTS)
-		mflag |= TIOCM_RTS;
-	if(mstat & CTS)
-		mflag |= TIOCM_CTS;
-	if(mstat & ch->dsr)
-		mflag |= TIOCM_DSR;
-	if(mstat & RI)
-		mflag |= TIOCM_RI;
-	if(mstat & ch->dcd)
-		mflag |= TIOCM_CD;
-
-	return mflag;
-}
-
-
-static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
-			 unsigned int set, unsigned int clear)
-{
-	struct channel *ch = (struct channel *) tty->driver_data;
-	volatile struct board_chan *bc;
-	unsigned long flags;
-
-	if(ch)
-		bc = ch->brdchan;
-	else {
-		printk("ch is NULL in %s!\n", __FUNCTION__);
-		return(-EINVAL);
-	}
-
-	save_flags(flags);
-	cli();
-	/*
-	 * I think this modemfake stuff is broken.  It doesn't
-	 * correctly reflect the behaviour desired by the TIOCM*
-	 * ioctls.  Therefore this is probably broken.
-	 */
-	if (set & TIOCM_DTR) {
-		ch->modemfake |= DTR;
-		ch->modem |= DTR;
-	}
-	if (set & TIOCM_RTS) {
-		ch->modemfake |= RTS;
-		ch->modem |= RTS;
-	}
-
-	if (clear & TIOCM_DTR) {
-		ch->modemfake |= DTR;
-		ch->modem &= ~DTR;
-	}
-	if (clear & TIOCM_RTS) {
-		ch->modemfake |= RTS;
-		ch->modem &= ~RTS;
-	}
-	globalwinon(ch);
-	pcxxparam(tty,ch);
-	memoff(ch);
-	restore_flags(flags);
-	return 0;
-}
-
-
-static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
-		    unsigned int cmd, unsigned long arg)
-{
-	struct channel *ch = (struct channel *) tty->driver_data;
-	volatile struct board_chan *bc;
-	int retval;
-	unsigned int mflag, mstat;
-	unsigned char startc, stopc;
-	unsigned long flags;
-	digiflow_t dflow;
-
-	if(ch)
-		bc = ch->brdchan;
-	else {
-		printk("ch is NULL in pcxe_ioctl!\n");
-		return(-EINVAL);
-	}
-
-	save_flags(flags);
-
-	switch(cmd) {
-		case TCSBRK:	/* SVID version: non-zero arg --> no break */
-			retval = tty_check_change(tty);
-			if(retval)
-				return retval;
-			setup_empty_event(tty,ch);		
-			tty_wait_until_sent(tty, 0);
-			if(!arg)
-				digi_send_break(ch, HZ/4);    /* 1/4 second */
-			return 0;
-
-		case TCSBRKP:	/* support for POSIX tcsendbreak() */
-			retval = tty_check_change(tty);
-			if(retval)
-				return retval;
-			setup_empty_event(tty,ch);		
-			tty_wait_until_sent(tty, 0);
-			digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
-			return 0;
-
-		case TIOCGSOFTCAR:
-			return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg);
-
-		case TIOCSSOFTCAR:
-			{
-			    unsigned int value;
-			    if (get_user(value, (unsigned int *) arg))
-				    return -EFAULT;
-			    tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
-			}
-			return 0;
-
-		case TIOCMODG:
-			mflag = pcxe_tiocmget(tty, file);
-			if (put_user(mflag, (unsigned int *) arg))
-				return -EFAULT;
-			break;
-
-		case TIOCMODS:
-			if (get_user(mstat, (unsigned int *) arg))
-				return -EFAULT;
-			return pcxe_tiocmset(tty, file, mstat, ~mstat);
-
-		case TIOCSDTR:
-			cli();
-			ch->omodem |= DTR;
-			globalwinon(ch);
-			fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
-			memoff(ch);
-			restore_flags(flags);
-			break;
-
-		case TIOCCDTR:
-			ch->omodem &= ~DTR;
-			cli();
-			globalwinon(ch);
-			fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
-			memoff(ch);
-			restore_flags(flags);
-			break;
-
-		case DIGI_GETA:
-			if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)))
-				return -EFAULT;
-			break;
-
-		case DIGI_SETAW:
-		case DIGI_SETAF:
-			if(cmd == DIGI_SETAW) {
-				setup_empty_event(tty,ch);		
-				tty_wait_until_sent(tty, 0);
-			}
-			else {
-				tty_ldisc_flush(tty);
-			}
-
-			/* Fall Thru */
-
-		case DIGI_SETA:
-			if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)))
-				return -EFAULT;
-#ifdef DEBUG_IOCTL
-			printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
-#endif
-			
-			if(ch->digiext.digi_flags & DIGI_ALTPIN) {
-				ch->dcd = DSR;
-				ch->dsr = CD;
-			} else {
-				ch->dcd = CD;
-				ch->dsr = DSR;
-			}
-		
-			cli();
-			globalwinon(ch);
-			pcxxparam(tty,ch);
-			memoff(ch);
-			restore_flags(flags);
-			break;
-
-		case DIGI_GETFLOW:
-		case DIGI_GETAFLOW:
-			cli();	
-			globalwinon(ch);
-			if(cmd == DIGI_GETFLOW) {
-				dflow.startc = bc->startc;
-				dflow.stopc = bc->stopc;
-			} else {
-				dflow.startc = bc->startca;
-				dflow.stopc = bc->stopca;
-			}
-			memoff(ch);
-			restore_flags(flags);
-
-			if (copy_to_user((char*)arg, &dflow, sizeof(dflow)))
-				return -EFAULT;
-			break;
-
-		case DIGI_SETAFLOW:
-		case DIGI_SETFLOW:
-			if(cmd == DIGI_SETFLOW) {
-				startc = ch->startc;
-				stopc = ch->stopc;
-			} else {
-				startc = ch->startca;
-				stopc = ch->stopca;
-			}
-
-			if (copy_from_user(&dflow, (char*)arg, sizeof(dflow)))
-				return -EFAULT;
-
-			if(dflow.startc != startc || dflow.stopc != stopc) {
-				cli();
-				globalwinon(ch);
-
-				if(cmd == DIGI_SETFLOW) {
-					ch->fepstartc = ch->startc = dflow.startc;
-					ch->fepstopc = ch->stopc = dflow.stopc;
-					fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
-				} else {
-					ch->fepstartca = ch->startca = dflow.startc;
-					ch->fepstopca  = ch->stopca = dflow.stopc;
-					fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
-				}
-
-				if(ch->statusflags & TXSTOPPED)
-					pcxe_start(tty);
-
-				memoff(ch);
-				restore_flags(flags);
-			}
-			break;
-
-		default:
-			return -ENOIOCTLCMD;
-	}
-
-	return 0;
-}
-
-static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-	struct channel *info;
-
-	if ((info=chan(tty))!=NULL) {
-		unsigned long flags;
-		save_flags(flags);
-		cli();
-		globalwinon(info);
-		pcxxparam(tty,info);
-		memoff(info);
-
-		if ((old_termios->c_cflag & CRTSCTS) &&
-			((tty->termios->c_cflag & CRTSCTS) == 0))
-			tty->hw_stopped = 0;
-		if(!(old_termios->c_cflag & CLOCAL) &&
-			(tty->termios->c_cflag & CLOCAL))
-			wake_up_interruptible(&info->open_wait);
-		restore_flags(flags);
-	}
-}
-
-
-
-static void do_softint(void *private_)
-{
-	struct channel *info = (struct channel *) private_;
-	
-	if(info && info->magic == PCXX_MAGIC) {
-		struct tty_struct *tty = info->tty;
-		if (tty && tty->driver_data) {
-			if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
-				tty_hangup(tty);
-				wake_up_interruptible(&info->open_wait);
-				info->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-			}
-		}
-	}
-}
-
-
-static void pcxe_stop(struct tty_struct *tty)
-{
-	struct channel *info;
-
-	if ((info=chan(tty))!=NULL) {
-		unsigned long flags;
-		save_flags(flags); 
-		cli();
-		if ((info->statusflags & TXSTOPPED) == 0) {
-			globalwinon(info);
-			fepcmd(info, PAUSETX, 0, 0, 0, 0);
-			info->statusflags |= TXSTOPPED;
-			memoff(info);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void pcxe_throttle(struct tty_struct * tty)
-{
-	struct channel *info;
-
-	if ((info=chan(tty))!=NULL) {
-		unsigned long flags;
-		save_flags(flags);
-		cli();
-		if ((info->statusflags & RXSTOPPED) == 0) {
-			globalwinon(info);
-			fepcmd(info, PAUSERX, 0, 0, 0, 0);
-			info->statusflags |= RXSTOPPED;
-			memoff(info);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void pcxe_unthrottle(struct tty_struct *tty)
-{
-	struct channel *info;
-
-	if ((info=chan(tty)) != NULL) {
-		unsigned long flags;
-
-		/* Just in case output was resumed because of a change in Digi-flow */
-		save_flags(flags);
-		cli();
-		if(info->statusflags & RXSTOPPED) {
-			volatile struct board_chan *bc;
-			globalwinon(info);
-			bc = info->brdchan;
-			fepcmd(info, RESUMERX, 0, 0, 0, 0);
-			info->statusflags &= ~RXSTOPPED;
-			memoff(info);
-		}
-		restore_flags(flags);
-	}
-}
-
-
-static void pcxe_start(struct tty_struct *tty)
-{
-	struct channel *info;
-
-	if ((info=chan(tty))!=NULL) {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		/* Just in case output was resumed because of a change in Digi-flow */
-		if(info->statusflags & TXSTOPPED) {
-			volatile struct board_chan *bc;
-			globalwinon(info);
-			bc = info->brdchan;
-			if(info->statusflags & LOWWAIT)
-				bc->ilow = 1;
-			fepcmd(info, RESUMETX, 0, 0, 0, 0);
-			info->statusflags &= ~TXSTOPPED;
-			memoff(info);
-		}
-		restore_flags(flags);
-	}
-}
-
-
-void digi_send_break(struct channel *ch, int msec)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	globalwinon(ch);
-
-	/* 
-	 * Maybe I should send an infinite break here, schedule() for
-	 * msec amount of time, and then stop the break.  This way,
-	 * the user can't screw up the FEP by causing digi_send_break()
-	 * to be called (i.e. via an ioctl()) more than once in msec amount 
-	 * of time.  Try this for now...
-	 */
-
-	fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
-	memoff(ch);
-
-	restore_flags(flags);
-}
-
-static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
-{
-	volatile struct board_chan *bc;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	globalwinon(ch);
-	ch->statusflags |= EMPTYWAIT;
-	bc = ch->brdchan;
-	bc->iempty = 1;
-	memoff(ch);
-	restore_flags(flags);
-}
diff --git a/drivers/char/pcxx.h b/drivers/char/pcxx.h
deleted file mode 100644
--- a/drivers/char/pcxx.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#define FEPCODESEG  0x0200L
-#define FEPCODE     0x2000L
-#define BIOSCODE    0xf800L
-
-#define MISCGLOBAL  0x0C00L
-#define NPORT       0x0C22L
-#define MBOX        0x0C40L
-#define PORTBASE    0x0C90L
-
-#define FEPCLR      0x00
-#define FEPMEM      0x02
-#define FEPRST      0x04
-#define FEPINT      0x08
-#define	FEPMASK     0x0e
-#define	FEPWIN      0x80
-
-/* Maximum Number of Boards supported */
-#define MAX_DIGI_BOARDS 4
-
-#define PCXX_NUM_TYPES	4
-
-#define PCXI		0
-#define PCXE		1
-#define	PCXEVE		2
-#define PCXEM		3
-
-static char *board_desc[] = {
-	"PC/Xi",
-	"PC/Xe",
-	"PC/Xeve",
-	"PC/Xem",
-};
-
-static char *board_mem[] = {
-	"64k",
-	"64k",
-	"8k",
-	"32k",
-};
-#define STARTC      021
-#define STOPC       023
-#define IAIXON      0x2000
-
-
-struct board_info	{
-	unchar status;
-	unchar type;
-	unchar altpin;
-	ushort numports;
-	ushort port;
-	ulong  membase;
-	ulong  memsize;
-	ushort first_minor;
-	void *region;
-};
-
-
-#define TXSTOPPED   0x01
-#define LOWWAIT		0x02
-#define EMPTYWAIT	0x04
-#define RXSTOPPED	0x08
-#define TXBUSY		0x10
-
-#define DISABLED   0
-#define ENABLED    1
-#define OFF        0
-#define ON         1
-
-#define FEPTIMEOUT 200000  
-#define SERIAL_TYPE_NORMAL	1
-#define PCXE_EVENT_HANGUP   1
-#define PCXX_MAGIC	0x5c6df104L
-
-struct channel {
-							/* --------- Board/channel information ---------- */
-	long						magic;
-	unchar						boardnum;
-	unchar						channelnum;
-	uint						dev;
-	struct tty_struct			*tty;
-	struct board_info			*board;
-	volatile struct board_chan	*brdchan;
-	volatile struct global_data *mailbox;
-	int							asyncflags;
-	int							count;
-	int							blocked_open;
-	int							close_delay;
-	unsigned long						event;
-	wait_queue_head_t			open_wait;
-	wait_queue_head_t			close_wait;
-	struct work_struct			tqueue;
-							/* ------------ Async control data ------------- */
-	unchar						modemfake;      /* Modem values to be forced */
-	unchar						modem;          /* Force values */
-	ulong						statusflags;
-	unchar						omodem;         /* FEP output modem status */
-	unchar						imodem;         /* FEP input modem status */
-	unchar						hflow;
-	unchar						dsr;
-	unchar						dcd;
-	unchar						stopc;
-	unchar						startc;
-	unchar						stopca;
-	unchar						startca;
-	unchar						fepstopc;
-	unchar						fepstartc;
-	unchar						fepstopca;
-	unchar						fepstartca;
-	ushort						fepiflag;
-	ushort						fepcflag;
-	ushort						fepoflag;
-							/* ---------- Transmit/receive system ---------- */
-	unchar						txwin;
-	unchar						rxwin;
-	ushort						txbufsize;
-	ushort						rxbufsize;
-	unchar						*txptr;
-	unchar						*rxptr;
-	unchar						*tmp_buf;		/* Temp buffer */
-	struct semaphore				tmp_buf_sem;
-							/* ---- Termios data ---- */
-	ulong						c_iflag;
-	ulong						c_cflag;
-	ulong						c_lflag;
-	ulong						c_oflag;
-	struct digi_struct			digiext;
-	ulong						dummy[8];
-};
diff --git a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1,7 +1,7 @@
 /*
  * random.c -- A strong random number generator
  *
- * Version 1.89, last modified 19-Sep-99
+ * Copyright Matt Mackall <mpm@selenic.com>, 2003, 2004, 2005
  *
  * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999.  All
  * rights reserved.
@@ -218,13 +218,6 @@
  * Any flaws in the design are solely my responsibility, and should
  * not be attributed to the Phil, Colin, or any of authors of PGP.
  *
- * The code for SHA transform was taken from Peter Gutmann's
- * implementation, which has been placed in the public domain.
- * The code for MD5 transform was taken from Colin Plumb's
- * implementation, which has been placed in the public domain.
- * The MD5 cryptographic checksum was devised by Ronald Rivest, and is
- * documented in RFC 1321, "The MD5 Message Digest Algorithm".
- *
  * Further background information on this topic may be obtained from
  * RFC 1750, "Randomness Recommendations for Security", by Donald
  * Eastlake, Steve Crocker, and Jeff Schiller.
@@ -242,11 +235,11 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/workqueue.h>
 #include <linux/genhd.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/percpu.h>
+#include <linux/cryptohash.h>
 
 #include <asm/processor.h>
 #include <asm/uaccess.h>
@@ -256,10 +249,9 @@
 /*
  * Configuration information
  */
-#define DEFAULT_POOL_SIZE 512
-#define SECONDARY_POOL_SIZE 128
-#define BATCH_ENTROPY_SIZE 256
-#define USE_SHA
+#define INPUT_POOL_WORDS 128
+#define OUTPUT_POOL_WORDS 32
+#define SEC_XFER_SIZE 512
 
 /*
  * The minimum number of bits of entropy before we wake up a read on
@@ -279,7 +271,7 @@ static int random_write_wakeup_thresh = 
  * samples to avoid wasting CPU time and reduce lock contention.
  */
 
-static int trickle_thresh = DEFAULT_POOL_SIZE * 7;
+static int trickle_thresh = INPUT_POOL_WORDS * 28;
 
 static DEFINE_PER_CPU(int, trickle_count) = 0;
 
@@ -295,42 +287,37 @@ static struct poolinfo {
 	int poolwords;
 	int tap1, tap2, tap3, tap4, tap5;
 } poolinfo_table[] = {
+	/* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
+	{ 128,	103,	76,	51,	25,	1 },
+	/* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
+	{ 32,	26,	20,	14,	7,	1 },
+#if 0
 	/* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1  -- 115 */
 	{ 2048,	1638,	1231,	819,	411,	1 },
 
 	/* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
 	{ 1024,	817,	615,	412,	204,	1 },
-#if 0				/* Alternate polynomial */
+
 	/* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
 	{ 1024,	819,	616,	410,	207,	2 },
-#endif
 
 	/* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
 	{ 512,	411,	308,	208,	104,	1 },
-#if 0				/* Alternates */
+
 	/* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
 	{ 512,	409,	307,	206,	102,	2 },
 	/* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */
 	{ 512,	409,	309,	205,	103,	2 },
-#endif
 
 	/* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
 	{ 256,	205,	155,	101,	52,	1 },
 
-	/* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
-	{ 128,	103,	76,	51,	25,	1 },
-#if 0	/* Alternate polynomial */
 	/* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
 	{ 128,	103,	78,	51,	27,	2 },
-#endif
 
 	/* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */
 	{ 64,	52,	39,	26,	14,	1 },
-
-	/* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
-	{ 32,	26,	20,	14,	7,	1 },
-
-	{ 0,	0,	0,	0,	0,	0 },
+#endif
 };
 
 #define POOLBITS	poolwords*32
@@ -380,104 +367,20 @@ static struct poolinfo {
  */
 
 /*
- * Linux 2.2 compatibility
- */
-#ifndef DECLARE_WAITQUEUE
-#define DECLARE_WAITQUEUE(WAIT, PTR) struct wait_queue WAIT = { PTR, NULL }
-#endif
-#ifndef DECLARE_WAIT_QUEUE_HEAD
-#define DECLARE_WAIT_QUEUE_HEAD(WAIT) struct wait_queue *WAIT
-#endif
-
-/*
  * Static global variables
  */
-static struct entropy_store *random_state; /* The default global store */
-static struct entropy_store *sec_random_state; /* secondary store */
-static struct entropy_store *urandom_state; /* For urandom */
 static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
 static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 
-/*
- * Forward procedure declarations
- */
-#ifdef CONFIG_SYSCTL
-static void sysctl_init_random(struct entropy_store *random_state);
-#endif
-
-/*****************************************************************
- *
- * Utility functions, with some ASM defined functions for speed
- * purposes
- *
- *****************************************************************/
-
-/*
- * Unfortunately, while the GCC optimizer for the i386 understands how
- * to optimize a static rotate left of x bits, it doesn't know how to
- * deal with a variable rotate of x bits.  So we use a bit of asm magic.
- */
-#if (!defined (__i386__))
-static inline __u32 rotate_left(int i, __u32 word)
-{
-	return (word << i) | (word >> (32 - i));
-}
-#else
-static inline __u32 rotate_left(int i, __u32 word)
-{
-	__asm__("roll %%cl,%0"
-		:"=r" (word)
-		:"0" (word),"c" (i));
-	return word;
-}
-#endif
-
-/*
- * More asm magic....
- *
- * For entropy estimation, we need to do an integral base 2
- * logarithm.
- *
- * Note the "12bits" suffix - this is used for numbers between
- * 0 and 4095 only.  This allows a few shortcuts.
- */
-#if 0	/* Slow but clear version */
-static inline __u32 int_ln_12bits(__u32 word)
-{
-	__u32 nbits = 0;
-
-	while (word >>= 1)
-		nbits++;
-	return nbits;
-}
-#else	/* Faster (more clever) version, courtesy Colin Plumb */
-static inline __u32 int_ln_12bits(__u32 word)
-{
-	/* Smear msbit right to make an n-bit mask */
-	word |= word >> 8;
-	word |= word >> 4;
-	word |= word >> 2;
-	word |= word >> 1;
-	/* Remove one bit to make this a logarithm */
-	word >>= 1;
-	/* Count the bits set in the word */
-	word -= (word >> 1) & 0x555;
-	word = (word & 0x333) + ((word >> 2) & 0x333);
-	word += (word >> 4);
-	word += (word >> 8);
-	return word & 15;
-}
-#endif
-
 #if 0
 static int debug = 0;
 module_param(debug, bool, 0644);
 #define DEBUG_ENT(fmt, arg...) do { if (debug) \
 	printk(KERN_DEBUG "random %04d %04d %04d: " \
 	fmt,\
-	random_state->entropy_count,\
-	sec_random_state->entropy_count,\
-	urandom_state->entropy_count,\
+	input_pool.entropy_count,\
+	blocking_pool.entropy_count,\
+	nonblocking_pool.entropy_count,\
 	## arg); } while (0)
 #else
 #define DEBUG_ENT(fmt, arg...) do {} while (0)
@@ -490,11 +393,14 @@ module_param(debug, bool, 0644);
  *
  **********************************************************************/
 
+struct entropy_store;
 struct entropy_store {
 	/* mostly-read data: */
-	struct poolinfo poolinfo;
+	struct poolinfo *poolinfo;
 	__u32 *pool;
 	const char *name;
+	int limit;
+	struct entropy_store *pull;
 
 	/* read-write data: */
 	spinlock_t lock ____cacheline_aligned_in_smp;
@@ -503,57 +409,34 @@ struct entropy_store {
 	int input_rotate;
 };
 
-/*
- * Initialize the entropy store.  The input argument is the size of
- * the random pool.
- *
- * Returns an negative error if there is a problem.
- */
-static int create_entropy_store(int size, const char *name,
-				struct entropy_store **ret_bucket)
-{
-	struct entropy_store *r;
-	struct poolinfo *p;
-	int poolwords;
-
-	poolwords = (size + 3) / 4; /* Convert bytes->words */
-	/* The pool size must be a multiple of 16 32-bit words */
-	poolwords = ((poolwords + 15) / 16) * 16;
-
-	for (p = poolinfo_table; p->poolwords; p++) {
-		if (poolwords == p->poolwords)
-			break;
-	}
-	if (p->poolwords == 0)
-		return -EINVAL;
+static __u32 input_pool_data[INPUT_POOL_WORDS];
+static __u32 blocking_pool_data[OUTPUT_POOL_WORDS];
+static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS];
+
+static struct entropy_store input_pool = {
+	.poolinfo = &poolinfo_table[0],
+	.name = "input",
+	.limit = 1,
+	.lock = SPIN_LOCK_UNLOCKED,
+	.pool = input_pool_data
+};
 
-	r = kmalloc(sizeof(struct entropy_store), GFP_KERNEL);
-	if (!r)
-		return -ENOMEM;
-
-	memset (r, 0, sizeof(struct entropy_store));
-	r->poolinfo = *p;
-
-	r->pool = kmalloc(POOLBYTES, GFP_KERNEL);
-	if (!r->pool) {
-		kfree(r);
-		return -ENOMEM;
-	}
-	memset(r->pool, 0, POOLBYTES);
-	spin_lock_init(&r->lock);
-	r->name = name;
-	*ret_bucket = r;
-	return 0;
-}
+static struct entropy_store blocking_pool = {
+	.poolinfo = &poolinfo_table[1],
+	.name = "blocking",
+	.limit = 1,
+	.pull = &input_pool,
+	.lock = SPIN_LOCK_UNLOCKED,
+	.pool = blocking_pool_data
+};
 
-/* Clear the entropy pool and associated counters. */
-static void clear_entropy_store(struct entropy_store *r)
-{
-	r->add_ptr = 0;
-	r->entropy_count = 0;
-	r->input_rotate = 0;
-	memset(r->pool, 0, r->poolinfo.POOLBYTES);
-}
+static struct entropy_store nonblocking_pool = {
+	.poolinfo = &poolinfo_table[1],
+	.name = "nonblocking",
+	.pull = &input_pool,
+	.lock = SPIN_LOCK_UNLOCKED,
+	.pool = nonblocking_pool_data
+};
 
 /*
  * This function adds a byte into the entropy "pool".  It does not
@@ -573,16 +456,16 @@ static void __add_entropy_words(struct e
 		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
 	unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5;
 	int new_rotate, input_rotate;
-	int wordmask = r->poolinfo.poolwords - 1;
+	int wordmask = r->poolinfo->poolwords - 1;
 	__u32 w, next_w;
 	unsigned long flags;
 
 	/* Taps are constant, so we can load them without holding r->lock.  */
-	tap1 = r->poolinfo.tap1;
-	tap2 = r->poolinfo.tap2;
-	tap3 = r->poolinfo.tap3;
-	tap4 = r->poolinfo.tap4;
-	tap5 = r->poolinfo.tap5;
+	tap1 = r->poolinfo->tap1;
+	tap2 = r->poolinfo->tap2;
+	tap3 = r->poolinfo->tap3;
+	tap4 = r->poolinfo->tap4;
+	tap5 = r->poolinfo->tap5;
 	next_w = *in++;
 
 	spin_lock_irqsave(&r->lock, flags);
@@ -591,7 +474,7 @@ static void __add_entropy_words(struct e
 	add_ptr = r->add_ptr;
 
 	while (nwords--) {
-		w = rotate_left(input_rotate, next_w);
+		w = rol32(next_w, input_rotate);
 		if (nwords > 0)
 			next_w = *in++;
 		i = add_ptr = (add_ptr - 1) & wordmask;
@@ -648,8 +531,8 @@ static void credit_entropy_store(struct 
 		DEBUG_ENT("negative entropy/overflow (%d+%d)\n",
 			  r->entropy_count, nbits);
 		r->entropy_count = 0;
-	} else if (r->entropy_count + nbits > r->poolinfo.POOLBITS) {
-		r->entropy_count = r->poolinfo.POOLBITS;
+	} else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) {
+		r->entropy_count = r->poolinfo->POOLBITS;
 	} else {
 		r->entropy_count += nbits;
 		if (nbits)
@@ -660,118 +543,6 @@ static void credit_entropy_store(struct 
 	spin_unlock_irqrestore(&r->lock, flags);
 }
 
-/**********************************************************************
- *
- * Entropy batch input management
- *
- * We batch entropy to be added to avoid increasing interrupt latency
- *
- **********************************************************************/
-
-struct sample {
-	__u32 data[2];
-	int credit;
-};
-
-static struct sample *batch_entropy_pool, *batch_entropy_copy;
-static int batch_head, batch_tail;
-static DEFINE_SPINLOCK(batch_lock);
-
-static int batch_max;
-static void batch_entropy_process(void *private_);
-static DECLARE_WORK(batch_work, batch_entropy_process, NULL);
-
-/* note: the size must be a power of 2 */
-static int __init batch_entropy_init(int size, struct entropy_store *r)
-{
-	batch_entropy_pool = kmalloc(size*sizeof(struct sample), GFP_KERNEL);
-	if (!batch_entropy_pool)
-		return -1;
-	batch_entropy_copy = kmalloc(size*sizeof(struct sample), GFP_KERNEL);
-	if (!batch_entropy_copy) {
-		kfree(batch_entropy_pool);
-		return -1;
-	}
-	batch_head = batch_tail = 0;
-	batch_work.data = r;
-	batch_max = size;
-	return 0;
-}
-
-/*
- * Changes to the entropy data is put into a queue rather than being added to
- * the entropy counts directly.  This is presumably to avoid doing heavy
- * hashing calculations during an interrupt in add_timer_randomness().
- * Instead, the entropy is only added to the pool by keventd.
- */
-static void batch_entropy_store(u32 a, u32 b, int num)
-{
-	int new;
-	unsigned long flags;
-
-	if (!batch_max)
-		return;
-
-	spin_lock_irqsave(&batch_lock, flags);
-
-	batch_entropy_pool[batch_head].data[0] = a;
-	batch_entropy_pool[batch_head].data[1] = b;
-	batch_entropy_pool[batch_head].credit = num;
-
-	if (((batch_head - batch_tail) & (batch_max - 1)) >= (batch_max / 2))
-		schedule_delayed_work(&batch_work, 1);
-
-	new = (batch_head + 1) & (batch_max - 1);
-	if (new == batch_tail)
-		DEBUG_ENT("batch entropy buffer full\n");
-	else
-		batch_head = new;
-
-	spin_unlock_irqrestore(&batch_lock, flags);
-}
-
-/*
- * Flush out the accumulated entropy operations, adding entropy to the passed
- * store (normally random_state).  If that store has enough entropy, alternate
- * between randomizing the data of the primary and secondary stores.
- */
-static void batch_entropy_process(void *private_)
-{
-	struct entropy_store *r	= (struct entropy_store *) private_, *p;
-	int max_entropy = r->poolinfo.POOLBITS;
-	unsigned head, tail;
-
-	/* Mixing into the pool is expensive, so copy over the batch
-	 * data and release the batch lock. The pool is at least half
-	 * full, so don't worry too much about copying only the used
-	 * part.
-	 */
-	spin_lock_irq(&batch_lock);
-
-	memcpy(batch_entropy_copy, batch_entropy_pool,
-	       batch_max * sizeof(struct sample));
-
-	head = batch_head;
-	tail = batch_tail;
-	batch_tail = batch_head;
-
-	spin_unlock_irq(&batch_lock);
-
-	p = r;
-	while (head != tail) {
-		if (r->entropy_count >= max_entropy) {
-			r = (r == sec_random_state) ? random_state :
-				sec_random_state;
-			max_entropy = r->poolinfo.POOLBITS;
-		}
-		add_entropy_words(r, batch_entropy_copy[tail].data, 2);
-		credit_entropy_store(r, batch_entropy_copy[tail].credit);
-		tail = (tail + 1) & (batch_max - 1);
-	}
-	if (p->entropy_count >= random_read_wakeup_thresh)
-		wake_up_interruptible(&random_read_wait);
-}
-
 /*********************************************************************
  *
  * Entropy input management
@@ -786,7 +557,6 @@ struct timer_rand_state {
 };
 
 static struct timer_rand_state input_timer_state;
-static struct timer_rand_state extract_timer_state;
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 /*
@@ -801,26 +571,33 @@ static struct timer_rand_state *irq_time
  */
 static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
 {
-	cycles_t data;
-	long delta, delta2, delta3, time;
-	int entropy = 0;
+	struct {
+		cycles_t cycles;
+		long jiffies;
+		unsigned num;
+	} sample;
+	long delta, delta2, delta3;
 
 	preempt_disable();
 	/* if over the trickle threshold, use only 1 in 4096 samples */
-	if (random_state->entropy_count > trickle_thresh &&
+	if (input_pool.entropy_count > trickle_thresh &&
 	    (__get_cpu_var(trickle_count)++ & 0xfff))
 		goto out;
 
+	sample.jiffies = jiffies;
+	sample.cycles = get_cycles();
+	sample.num = num;
+	add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4);
+
 	/*
 	 * Calculate number of bits of randomness we probably added.
 	 * We take into account the first, second and third-order deltas
 	 * in order to make our estimate.
 	 */
-	time = jiffies;
 
 	if (!state->dont_count_entropy) {
-		delta = time - state->last_time;
-		state->last_time = time;
+		delta = sample.jiffies - state->last_time;
+		state->last_time = sample.jiffies;
 
 		delta2 = delta - state->last_delta;
 		state->last_delta = delta;
@@ -844,23 +621,13 @@ static void add_timer_randomness(struct 
 		 * Round down by 1 bit on general principles,
 		 * and limit entropy entimate to 12 bits.
 		 */
-		delta >>= 1;
-		delta &= (1 << 12) - 1;
-
-		entropy = int_ln_12bits(delta);
+		credit_entropy_store(&input_pool,
+				     min_t(int, fls(delta>>1), 11));
 	}
 
-	/*
-	 * Use get_cycles() if implemented, otherwise fall back to
-	 * jiffies.
-	 */
-	data = get_cycles();
-	if (data)
-		num ^= (u32)((data >> 31) >> 1);
-	else
-		data = time;
+	if(input_pool.entropy_count >= random_read_wakeup_thresh)
+		wake_up_interruptible(&random_read_wait);
 
-	batch_entropy_store(num, data, entropy);
 out:
 	preempt_enable();
 }
@@ -902,391 +669,7 @@ void add_disk_randomness(struct gendisk 
 
 EXPORT_SYMBOL(add_disk_randomness);
 
-/******************************************************************
- *
- * Hash function definition
- *
- *******************************************************************/
-
-/*
- * This chunk of code defines a function
- * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE],
- * 		__u32 const data[16])
- *
- * The function hashes the input data to produce a digest in the first
- * HASH_BUFFER_SIZE words of the digest[] array, and uses HASH_EXTRA_SIZE
- * more words for internal purposes.  (This buffer is exported so the
- * caller can wipe it once rather than this code doing it each call,
- * and tacking it onto the end of the digest[] array is the quick and
- * dirty way of doing it.)
- *
- * It so happens that MD5 and SHA share most of the initial vector
- * used to initialize the digest[] array before the first call:
- * 1) 0x67452301
- * 2) 0xefcdab89
- * 3) 0x98badcfe
- * 4) 0x10325476
- * 5) 0xc3d2e1f0 (SHA only)
- *
- * For /dev/random purposes, the length of the data being hashed is
- * fixed in length, so appending a bit count in the usual way is not
- * cryptographically necessary.
- */
-
-#ifdef USE_SHA
-
-#define HASH_BUFFER_SIZE 5
-#define HASH_EXTRA_SIZE 80
-#define HASH_TRANSFORM SHATransform
-
-/* Various size/speed tradeoffs are available.  Choose 0..3. */
-#define SHA_CODE_SIZE 0
-
-/*
- * SHA transform algorithm, taken from code written by Peter Gutmann,
- * and placed in the public domain.
- */
-
-/* The SHA f()-functions.  */
-
-#define f1(x,y,z)   (z ^ (x & (y ^ z)))		/* Rounds  0-19: x ? y : z */
-#define f2(x,y,z)   (x ^ y ^ z)			/* Rounds 20-39: XOR */
-#define f3(x,y,z)   ((x & y) + (z & (x ^ y)))	/* Rounds 40-59: majority */
-#define f4(x,y,z)   (x ^ y ^ z)			/* Rounds 60-79: XOR */
-
-/* The SHA Mysterious Constants */
-
-#define K1  0x5A827999L			/* Rounds  0-19: sqrt(2) * 2^30 */
-#define K2  0x6ED9EBA1L			/* Rounds 20-39: sqrt(3) * 2^30 */
-#define K3  0x8F1BBCDCL			/* Rounds 40-59: sqrt(5) * 2^30 */
-#define K4  0xCA62C1D6L			/* Rounds 60-79: sqrt(10) * 2^30 */
-
-#define ROTL(n,X)  (((X) << n ) | ((X) >> (32 - n)))
-
-#define subRound(a, b, c, d, e, f, k, data) \
-    (e += ROTL(5, a) + f(b, c, d) + k + data, b = ROTL(30, b))
-
-static void SHATransform(__u32 digest[85], __u32 const data[16])
-{
-	__u32 A, B, C, D, E;     /* Local vars */
-	__u32 TEMP;
-	int i;
-#define W (digest + HASH_BUFFER_SIZE)	/* Expanded data array */
-
-	/*
-	 * Do the preliminary expansion of 16 to 80 words.  Doing it
-	 * out-of-line line this is faster than doing it in-line on
-	 * register-starved machines like the x86, and not really any
-	 * slower on real processors.
-	 */
-	memcpy(W, data, 16*sizeof(__u32));
-	for (i = 0; i < 64; i++) {
-		TEMP = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13];
-		W[i+16] = ROTL(1, TEMP);
-	}
-
-	/* Set up first buffer and local data buffer */
-	A = digest[ 0 ];
-	B = digest[ 1 ];
-	C = digest[ 2 ];
-	D = digest[ 3 ];
-	E = digest[ 4 ];
-
-	/* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
-#if SHA_CODE_SIZE == 0
-	/*
-	 * Approximately 50% of the speed of the largest version, but
-	 * takes up 1/16 the space.  Saves about 6k on an i386 kernel.
-	 */
-	for (i = 0; i < 80; i++) {
-		if (i < 40) {
-			if (i < 20)
-				TEMP = f1(B, C, D) + K1;
-			else
-				TEMP = f2(B, C, D) + K2;
-		} else {
-			if (i < 60)
-				TEMP = f3(B, C, D) + K3;
-			else
-				TEMP = f4(B, C, D) + K4;
-		}
-		TEMP += ROTL(5, A) + E + W[i];
-		E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
-	}
-#elif SHA_CODE_SIZE == 1
-	for (i = 0; i < 20; i++) {
-		TEMP = f1(B, C, D) + K1 + ROTL(5, A) + E + W[i];
-		E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
-	}
-	for (; i < 40; i++) {
-		TEMP = f2(B, C, D) + K2 + ROTL(5, A) + E + W[i];
-		E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
-	}
-	for (; i < 60; i++) {
-		TEMP = f3(B, C, D) + K3 + ROTL(5, A) + E + W[i];
-		E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
-	}
-	for (; i < 80; i++) {
-		TEMP = f4(B, C, D) + K4 + ROTL(5, A) + E + W[i];
-		E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
-	}
-#elif SHA_CODE_SIZE == 2
-	for (i = 0; i < 20; i += 5) {
-		subRound(A, B, C, D, E, f1, K1, W[i  ]);
-		subRound(E, A, B, C, D, f1, K1, W[i+1]);
-		subRound(D, E, A, B, C, f1, K1, W[i+2]);
-		subRound(C, D, E, A, B, f1, K1, W[i+3]);
-		subRound(B, C, D, E, A, f1, K1, W[i+4]);
-	}
-	for (; i < 40; i += 5) {
-		subRound(A, B, C, D, E, f2, K2, W[i  ]);
-		subRound(E, A, B, C, D, f2, K2, W[i+1]);
-		subRound(D, E, A, B, C, f2, K2, W[i+2]);
-		subRound(C, D, E, A, B, f2, K2, W[i+3]);
-		subRound(B, C, D, E, A, f2, K2, W[i+4]);
-	}
-	for (; i < 60; i += 5) {
-		subRound(A, B, C, D, E, f3, K3, W[i  ]);
-		subRound(E, A, B, C, D, f3, K3, W[i+1]);
-		subRound(D, E, A, B, C, f3, K3, W[i+2]);
-		subRound(C, D, E, A, B, f3, K3, W[i+3]);
-		subRound(B, C, D, E, A, f3, K3, W[i+4]);
-	}
-	for (; i < 80; i += 5) {
-		subRound(A, B, C, D, E, f4, K4, W[i  ]);
-		subRound(E, A, B, C, D, f4, K4, W[i+1]);
-		subRound(D, E, A, B, C, f4, K4, W[i+2]);
-		subRound(C, D, E, A, B, f4, K4, W[i+3]);
-		subRound(B, C, D, E, A, f4, K4, W[i+4]);
-	}
-#elif SHA_CODE_SIZE == 3 /* Really large version */
-	subRound(A, B, C, D, E, f1, K1, W[ 0]);
-	subRound(E, A, B, C, D, f1, K1, W[ 1]);
-	subRound(D, E, A, B, C, f1, K1, W[ 2]);
-	subRound(C, D, E, A, B, f1, K1, W[ 3]);
-	subRound(B, C, D, E, A, f1, K1, W[ 4]);
-	subRound(A, B, C, D, E, f1, K1, W[ 5]);
-	subRound(E, A, B, C, D, f1, K1, W[ 6]);
-	subRound(D, E, A, B, C, f1, K1, W[ 7]);
-	subRound(C, D, E, A, B, f1, K1, W[ 8]);
-	subRound(B, C, D, E, A, f1, K1, W[ 9]);
-	subRound(A, B, C, D, E, f1, K1, W[10]);
-	subRound(E, A, B, C, D, f1, K1, W[11]);
-	subRound(D, E, A, B, C, f1, K1, W[12]);
-	subRound(C, D, E, A, B, f1, K1, W[13]);
-	subRound(B, C, D, E, A, f1, K1, W[14]);
-	subRound(A, B, C, D, E, f1, K1, W[15]);
-	subRound(E, A, B, C, D, f1, K1, W[16]);
-	subRound(D, E, A, B, C, f1, K1, W[17]);
-	subRound(C, D, E, A, B, f1, K1, W[18]);
-	subRound(B, C, D, E, A, f1, K1, W[19]);
-
-	subRound(A, B, C, D, E, f2, K2, W[20]);
-	subRound(E, A, B, C, D, f2, K2, W[21]);
-	subRound(D, E, A, B, C, f2, K2, W[22]);
-	subRound(C, D, E, A, B, f2, K2, W[23]);
-	subRound(B, C, D, E, A, f2, K2, W[24]);
-	subRound(A, B, C, D, E, f2, K2, W[25]);
-	subRound(E, A, B, C, D, f2, K2, W[26]);
-	subRound(D, E, A, B, C, f2, K2, W[27]);
-	subRound(C, D, E, A, B, f2, K2, W[28]);
-	subRound(B, C, D, E, A, f2, K2, W[29]);
-	subRound(A, B, C, D, E, f2, K2, W[30]);
-	subRound(E, A, B, C, D, f2, K2, W[31]);
-	subRound(D, E, A, B, C, f2, K2, W[32]);
-	subRound(C, D, E, A, B, f2, K2, W[33]);
-	subRound(B, C, D, E, A, f2, K2, W[34]);
-	subRound(A, B, C, D, E, f2, K2, W[35]);
-	subRound(E, A, B, C, D, f2, K2, W[36]);
-	subRound(D, E, A, B, C, f2, K2, W[37]);
-	subRound(C, D, E, A, B, f2, K2, W[38]);
-	subRound(B, C, D, E, A, f2, K2, W[39]);
-
-	subRound(A, B, C, D, E, f3, K3, W[40]);
-	subRound(E, A, B, C, D, f3, K3, W[41]);
-	subRound(D, E, A, B, C, f3, K3, W[42]);
-	subRound(C, D, E, A, B, f3, K3, W[43]);
-	subRound(B, C, D, E, A, f3, K3, W[44]);
-	subRound(A, B, C, D, E, f3, K3, W[45]);
-	subRound(E, A, B, C, D, f3, K3, W[46]);
-	subRound(D, E, A, B, C, f3, K3, W[47]);
-	subRound(C, D, E, A, B, f3, K3, W[48]);
-	subRound(B, C, D, E, A, f3, K3, W[49]);
-	subRound(A, B, C, D, E, f3, K3, W[50]);
-	subRound(E, A, B, C, D, f3, K3, W[51]);
-	subRound(D, E, A, B, C, f3, K3, W[52]);
-	subRound(C, D, E, A, B, f3, K3, W[53]);
-	subRound(B, C, D, E, A, f3, K3, W[54]);
-	subRound(A, B, C, D, E, f3, K3, W[55]);
-	subRound(E, A, B, C, D, f3, K3, W[56]);
-	subRound(D, E, A, B, C, f3, K3, W[57]);
-	subRound(C, D, E, A, B, f3, K3, W[58]);
-	subRound(B, C, D, E, A, f3, K3, W[59]);
-
-	subRound(A, B, C, D, E, f4, K4, W[60]);
-	subRound(E, A, B, C, D, f4, K4, W[61]);
-	subRound(D, E, A, B, C, f4, K4, W[62]);
-	subRound(C, D, E, A, B, f4, K4, W[63]);
-	subRound(B, C, D, E, A, f4, K4, W[64]);
-	subRound(A, B, C, D, E, f4, K4, W[65]);
-	subRound(E, A, B, C, D, f4, K4, W[66]);
-	subRound(D, E, A, B, C, f4, K4, W[67]);
-	subRound(C, D, E, A, B, f4, K4, W[68]);
-	subRound(B, C, D, E, A, f4, K4, W[69]);
-	subRound(A, B, C, D, E, f4, K4, W[70]);
-	subRound(E, A, B, C, D, f4, K4, W[71]);
-	subRound(D, E, A, B, C, f4, K4, W[72]);
-	subRound(C, D, E, A, B, f4, K4, W[73]);
-	subRound(B, C, D, E, A, f4, K4, W[74]);
-	subRound(A, B, C, D, E, f4, K4, W[75]);
-	subRound(E, A, B, C, D, f4, K4, W[76]);
-	subRound(D, E, A, B, C, f4, K4, W[77]);
-	subRound(C, D, E, A, B, f4, K4, W[78]);
-	subRound(B, C, D, E, A, f4, K4, W[79]);
-#else
-#error Illegal SHA_CODE_SIZE
-#endif
-
-	/* Build message digest */
-	digest[0] += A;
-	digest[1] += B;
-	digest[2] += C;
-	digest[3] += D;
-	digest[4] += E;
-
-	/* W is wiped by the caller */
-#undef W
-}
-
-#undef ROTL
-#undef f1
-#undef f2
-#undef f3
-#undef f4
-#undef K1
-#undef K2
-#undef K3
-#undef K4
-#undef subRound
-
-#else /* !USE_SHA - Use MD5 */
-
-#define HASH_BUFFER_SIZE 4
-#define HASH_EXTRA_SIZE 0
-#define HASH_TRANSFORM MD5Transform
-
-/*
- * MD5 transform algorithm, taken from code written by Colin Plumb,
- * and put into the public domain
- */
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-	(w += f(x, y, z) + data,  w = w << s | w >> (32 - s),  w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16])
-{
-	__u32 a, b, c, d;
-
-	a = buf[0];
-	b = buf[1];
-	c = buf[2];
-	d = buf[3];
-
-	MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
-	MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
-	MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
-	MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
-	MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
-	MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
-	MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
-	MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
-	MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
-	MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
-	MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
-	MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
-	MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
-	MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
-	MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
-	MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
-
-	MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
-	MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
-	MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
-	MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
-	MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
-	MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
-	MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
-	MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
-	MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
-	MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
-	MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
-	MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
-	MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
-	MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
-	MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
-	MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
-
-	MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
-	MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
-	MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
-	MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
-	MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
-	MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
-	MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
-	MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
-	MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
-	MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
-	MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
-	MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
-	MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
-	MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
-	MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
-	MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
-
-	MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
-	MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
-	MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
-	MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
-	MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
-	MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
-	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
-	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
-	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
-	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
-	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
-	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
-	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
-	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
-	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
-	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
-
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
-}
-
-#undef F1
-#undef F2
-#undef F3
-#undef F4
-#undef MD5STEP
-
-#endif /* !USE_SHA */
+#define EXTRACT_SIZE 10
 
 /*********************************************************************
  *
@@ -1294,157 +677,174 @@ static void MD5Transform(__u32 buf[HASH_
  *
  *********************************************************************/
 
-#define EXTRACT_ENTROPY_USER		1
-#define EXTRACT_ENTROPY_SECONDARY	2
-#define EXTRACT_ENTROPY_LIMIT		4
-#define TMP_BUF_SIZE			(HASH_BUFFER_SIZE + HASH_EXTRA_SIZE)
-#define SEC_XFER_SIZE			(TMP_BUF_SIZE*4)
-
 static ssize_t extract_entropy(struct entropy_store *r, void * buf,
-			       size_t nbytes, int flags);
+			       size_t nbytes, int min, int rsvd);
 
 /*
  * This utility inline function is responsible for transfering entropy
  * from the primary pool to the secondary extraction pool. We make
  * sure we pull enough for a 'catastrophic reseed'.
  */
-static inline void xfer_secondary_pool(struct entropy_store *r,
-				       size_t nbytes, __u32 *tmp)
+static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 {
-	if (r->entropy_count < nbytes * 8 &&
-	    r->entropy_count < r->poolinfo.POOLBITS) {
+	__u32 tmp[OUTPUT_POOL_WORDS];
+
+	if (r->pull && r->entropy_count < nbytes * 8 &&
+	    r->entropy_count < r->poolinfo->POOLBITS) {
 		int bytes = max_t(int, random_read_wakeup_thresh / 8,
-				min_t(int, nbytes, TMP_BUF_SIZE));
+				min_t(int, nbytes, sizeof(tmp)));
+		int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
 
 		DEBUG_ENT("going to reseed %s with %d bits "
 			  "(%d of %d requested)\n",
 			  r->name, bytes * 8, nbytes * 8, r->entropy_count);
 
-		bytes=extract_entropy(random_state, tmp, bytes,
-				      EXTRACT_ENTROPY_LIMIT);
+		bytes=extract_entropy(r->pull, tmp, bytes,
+				      random_read_wakeup_thresh / 8, rsvd);
 		add_entropy_words(r, tmp, (bytes + 3) / 4);
 		credit_entropy_store(r, bytes*8);
 	}
 }
 
 /*
- * This function extracts randomness from the "entropy pool", and
- * returns it in a buffer.  This function computes how many remaining
- * bits of entropy are left in the pool, but it does not restrict the
- * number of bytes that are actually obtained.  If the EXTRACT_ENTROPY_USER
- * flag is given, then the buf pointer is assumed to be in user space.
- *
- * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually
- * extracting entropy from the secondary pool, and can refill from the
- * primary pool if needed.
+ * These functions extracts randomness from the "entropy pool", and
+ * returns it in a buffer.
+ *
+ * The min parameter specifies the minimum amount we can pull before
+ * failing to avoid races that defeat catastrophic reseeding while the
+ * reserved parameter indicates how much entropy we must leave in the
+ * pool after each pull to avoid starving other readers.
  *
  * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words.
  */
-static ssize_t extract_entropy(struct entropy_store *r, void * buf,
-			       size_t nbytes, int flags)
+
+static size_t account(struct entropy_store *r, size_t nbytes, int min,
+		      int reserved)
 {
-	ssize_t ret, i;
-	__u32 tmp[TMP_BUF_SIZE], data[16];
-	__u32 x;
-	unsigned long cpuflags;
-
-	/* Redundant, but just in case... */
-	if (r->entropy_count > r->poolinfo.POOLBITS)
-		r->entropy_count = r->poolinfo.POOLBITS;
+	unsigned long flags;
 
-	if (flags & EXTRACT_ENTROPY_SECONDARY)
-		xfer_secondary_pool(r, nbytes, tmp);
+	BUG_ON(r->entropy_count > r->poolinfo->POOLBITS);
 
 	/* Hold lock while accounting */
-	spin_lock_irqsave(&r->lock, cpuflags);
+	spin_lock_irqsave(&r->lock, flags);
 
 	DEBUG_ENT("trying to extract %d bits from %s\n",
 		  nbytes * 8, r->name);
 
-	if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8)
-		nbytes = r->entropy_count / 8;
-
-	if (r->entropy_count / 8 >= nbytes)
-		r->entropy_count -= nbytes*8;
-	else
-		r->entropy_count = 0;
+	/* Can we pull enough? */
+	if (r->entropy_count / 8 < min + reserved) {
+		nbytes = 0;
+	} else {
+		/* If limited, never pull more than available */
+		if (r->limit && nbytes + reserved >= r->entropy_count / 8)
+			nbytes = r->entropy_count/8 - reserved;
+
+		if(r->entropy_count / 8 >= nbytes + reserved)
+			r->entropy_count -= nbytes*8;
+		else
+			r->entropy_count = reserved;
 
-	if (r->entropy_count < random_write_wakeup_thresh)
-		wake_up_interruptible(&random_write_wait);
+		if (r->entropy_count < random_write_wakeup_thresh)
+			wake_up_interruptible(&random_write_wait);
+	}
 
 	DEBUG_ENT("debiting %d entropy credits from %s%s\n",
-		  nbytes * 8, r->name,
-		  flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)");
+		  nbytes * 8, r->name, r->limit ? "" : " (unlimited)");
 
-	spin_unlock_irqrestore(&r->lock, cpuflags);
+	spin_unlock_irqrestore(&r->lock, flags);
+
+	return nbytes;
+}
+
+static void extract_buf(struct entropy_store *r, __u8 *out)
+{
+	int i, x;
+	__u32 data[16], buf[5 + SHA_WORKSPACE_WORDS];
+
+	sha_init(buf);
+	/*
+	 * As we hash the pool, we mix intermediate values of
+	 * the hash back into the pool.  This eliminates
+	 * backtracking attacks (where the attacker knows
+	 * the state of the pool plus the current outputs, and
+	 * attempts to find previous ouputs), unless the hash
+	 * function can be inverted.
+	 */
+	for (i = 0, x = 0; i < r->poolinfo->poolwords; i += 16, x+=2) {
+		sha_transform(buf, (__u8 *)r->pool+i, buf + 5);
+		add_entropy_words(r, &buf[x % 5], 1);
+	}
+
+	/*
+	 * To avoid duplicates, we atomically extract a
+	 * portion of the pool while mixing, and hash one
+	 * final time.
+	 */
+	__add_entropy_words(r, &buf[x % 5], 1, data);
+	sha_transform(buf, (__u8 *)data, buf + 5);
+
+	/*
+	 * In case the hash function has some recognizable
+	 * output pattern, we fold it in half.
+	 */
+
+	buf[0] ^= buf[3];
+	buf[1] ^= buf[4];
+	buf[0] ^= rol32(buf[3], 16);
+	memcpy(out, buf, EXTRACT_SIZE);
+	memset(buf, 0, sizeof(buf));
+}
+
+static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+			       size_t nbytes, int min, int reserved)
+{
+	ssize_t ret = 0, i;
+	__u8 tmp[EXTRACT_SIZE];
+
+	xfer_secondary_pool(r, nbytes);
+	nbytes = account(r, nbytes, min, reserved);
 
-	ret = 0;
 	while (nbytes) {
-		/*
-		 * Check if we need to break out or reschedule....
-		 */
-		if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
+		extract_buf(r, tmp);
+		i = min_t(int, nbytes, EXTRACT_SIZE);
+		memcpy(buf, tmp, i);
+		nbytes -= i;
+		buf += i;
+		ret += i;
+	}
+
+	/* Wipe data just returned from memory */
+	memset(tmp, 0, sizeof(tmp));
+
+	return ret;
+}
+
+static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
+				    size_t nbytes)
+{
+	ssize_t ret = 0, i;
+	__u8 tmp[EXTRACT_SIZE];
+
+	xfer_secondary_pool(r, nbytes);
+	nbytes = account(r, nbytes, 0, 0);
+
+	while (nbytes) {
+		if (need_resched()) {
 			if (signal_pending(current)) {
 				if (ret == 0)
 					ret = -ERESTARTSYS;
 				break;
 			}
-
 			schedule();
 		}
 
-		/* Hash the pool to get the output */
-		tmp[0] = 0x67452301;
-		tmp[1] = 0xefcdab89;
-		tmp[2] = 0x98badcfe;
-		tmp[3] = 0x10325476;
-#ifdef USE_SHA
-		tmp[4] = 0xc3d2e1f0;
-#endif
-		/*
-		 * As we hash the pool, we mix intermediate values of
-		 * the hash back into the pool.  This eliminates
-		 * backtracking attacks (where the attacker knows
-		 * the state of the pool plus the current outputs, and
-		 * attempts to find previous ouputs), unless the hash
-		 * function can be inverted.
-		 */
-		for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) {
-			HASH_TRANSFORM(tmp, r->pool+i);
-			add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1);
+		extract_buf(r, tmp);
+		i = min_t(int, nbytes, EXTRACT_SIZE);
+		if (copy_to_user(buf, tmp, i)) {
+			ret = -EFAULT;
+			break;
 		}
 
-		/*
-		 * To avoid duplicates, we atomically extract a
-		 * portion of the pool while mixing, and hash one
-		 * final time.
-		 */
-		__add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1, data);
-		HASH_TRANSFORM(tmp, data);
-
-		/*
-		 * In case the hash function has some recognizable
-		 * output pattern, we fold it in half.
-		 */
-		for (i = 0; i <  HASH_BUFFER_SIZE/2; i++)
-			tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2];
-#if HASH_BUFFER_SIZE & 1	/* There's a middle word to deal with */
-		x = tmp[HASH_BUFFER_SIZE/2];
-		x ^= (x >> 16);		/* Fold it in half */
-		((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;
-#endif
-
-		/* Copy data to destination buffer */
-		i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2);
-		if (flags & EXTRACT_ENTROPY_USER) {
-			i -= copy_to_user(buf, (__u8 const *)tmp, i);
-			if (!i) {
-				ret = -EFAULT;
-				break;
-			}
-		} else
-			memcpy(buf, (__u8 const *)tmp, i);
-
 		nbytes -= i;
 		buf += i;
 		ret += i;
@@ -1463,91 +863,41 @@ static ssize_t extract_entropy(struct en
  */
 void get_random_bytes(void *buf, int nbytes)
 {
-	struct entropy_store *r = urandom_state;
-	int flags = EXTRACT_ENTROPY_SECONDARY;
-
-	if (!r)
-		r = sec_random_state;
-	if (!r) {
-		r = random_state;
-		flags = 0;
-	}
-	if (!r) {
-		printk(KERN_NOTICE "get_random_bytes called before "
-				   "random driver initialization\n");
-		return;
-	}
-	extract_entropy(r, (char *) buf, nbytes, flags);
+	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
 }
 
 EXPORT_SYMBOL(get_random_bytes);
 
-/*********************************************************************
- *
- * Functions to interface with Linux
- *
- *********************************************************************/
-
 /*
- * Initialize the random pool with standard stuff.
+ * init_std_data - initialize pool with system data
+ *
+ * @r: pool to initialize
  *
- * NOTE: This is an OS-dependent function.
+ * This function clears the pool's entropy count and mixes some system
+ * data into the pool to prepare it for use. The pool is not cleared
+ * as that can only decrease the entropy in the pool.
  */
 static void init_std_data(struct entropy_store *r)
 {
 	struct timeval tv;
-	__u32 words[2];
-	char *p;
-	int i;
+	unsigned long flags;
 
-	do_gettimeofday(&tv);
-	words[0] = tv.tv_sec;
-	words[1] = tv.tv_usec;
-	add_entropy_words(r, words, 2);
+	spin_lock_irqsave(&r->lock, flags);
+	r->entropy_count = 0;
+	spin_unlock_irqrestore(&r->lock, flags);
 
-	/*
-	 *	This doesn't lock system.utsname. However, we are generating
-	 *	entropy so a race with a name set here is fine.
-	 */
-	p = (char *) &system_utsname;
-	for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
-		memcpy(words, p, sizeof(words));
-		add_entropy_words(r, words, sizeof(words)/4);
-		p += sizeof(words);
-	}
+	do_gettimeofday(&tv);
+	add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4);
+	add_entropy_words(r, (__u32 *)&system_utsname,
+			  sizeof(system_utsname)/4);
 }
 
 static int __init rand_initialize(void)
 {
-	int i;
-
-	if (create_entropy_store(DEFAULT_POOL_SIZE, "primary", &random_state))
-		goto err;
-	if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state))
-		goto err;
-	if (create_entropy_store(SECONDARY_POOL_SIZE, "secondary",
-				 &sec_random_state))
-		goto err;
-	if (create_entropy_store(SECONDARY_POOL_SIZE, "urandom",
-				 &urandom_state))
-		goto err;
-	clear_entropy_store(random_state);
-	clear_entropy_store(sec_random_state);
-	clear_entropy_store(urandom_state);
-	init_std_data(random_state);
-	init_std_data(sec_random_state);
-	init_std_data(urandom_state);
-#ifdef CONFIG_SYSCTL
-	sysctl_init_random(random_state);
-#endif
-	for (i = 0; i < NR_IRQS; i++)
-		irq_timer_state[i] = NULL;
-	memset(&input_timer_state, 0, sizeof(struct timer_rand_state));
-	memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
-	extract_timer_state.dont_count_entropy = 1;
+	init_std_data(&input_pool);
+	init_std_data(&blocking_pool);
+	init_std_data(&nonblocking_pool);
 	return 0;
-err:
-	return -1;
 }
 module_init(rand_initialize);
 
@@ -1587,7 +937,6 @@ void rand_initialize_disk(struct gendisk
 static ssize_t
 random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	ssize_t n, retval = 0, count = 0;
 
 	if (nbytes == 0)
@@ -1600,10 +949,7 @@ random_read(struct file * file, char __u
 
 		DEBUG_ENT("reading %d bits\n", n*8);
 
-		n = extract_entropy(sec_random_state, buf, n,
-				    EXTRACT_ENTROPY_USER |
-				    EXTRACT_ENTROPY_LIMIT |
-				    EXTRACT_ENTROPY_SECONDARY);
+		n = extract_entropy_user(&blocking_pool, buf, n);
 
 		DEBUG_ENT("read got %d bits (%d still needed)\n",
 			  n*8, (nbytes-n)*8);
@@ -1613,20 +959,20 @@ random_read(struct file * file, char __u
 				retval = -EAGAIN;
 				break;
 			}
+
+			DEBUG_ENT("sleeping?\n");
+
+			wait_event_interruptible(random_read_wait,
+				input_pool.entropy_count >=
+						 random_read_wakeup_thresh);
+
+			DEBUG_ENT("awake\n");
+
 			if (signal_pending(current)) {
 				retval = -ERESTARTSYS;
 				break;
 			}
 
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&random_read_wait, &wait);
-
-			if (sec_random_state->entropy_count / 8 == 0)
-				schedule();
-
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&random_read_wait, &wait);
-
 			continue;
 		}
 
@@ -1654,15 +1000,7 @@ static ssize_t
 urandom_read(struct file * file, char __user * buf,
 		      size_t nbytes, loff_t *ppos)
 {
-	int flags = EXTRACT_ENTROPY_USER;
-	unsigned long cpuflags;
-
-	spin_lock_irqsave(&random_state->lock, cpuflags);
-	if (random_state->entropy_count > random_state->poolinfo.POOLBITS)
-		flags |= EXTRACT_ENTROPY_SECONDARY;
-	spin_unlock_irqrestore(&random_state->lock, cpuflags);
-
-	return extract_entropy(urandom_state, buf, nbytes, flags);
+	return extract_entropy_user(&nonblocking_pool, buf, nbytes);
 }
 
 static unsigned int
@@ -1673,9 +1011,9 @@ random_poll(struct file *file, poll_tabl
 	poll_wait(file, &random_read_wait, wait);
 	poll_wait(file, &random_write_wait, wait);
 	mask = 0;
-	if (random_state->entropy_count >= random_read_wakeup_thresh)
+	if (input_pool.entropy_count >= random_read_wakeup_thresh)
 		mask |= POLLIN | POLLRDNORM;
-	if (random_state->entropy_count < random_write_wakeup_thresh)
+	if (input_pool.entropy_count < random_write_wakeup_thresh)
 		mask |= POLLOUT | POLLWRNORM;
 	return mask;
 }
@@ -1701,7 +1039,7 @@ random_write(struct file * file, const c
 		c -= bytes;
 		p += bytes;
 
-		add_entropy_words(random_state, buf, (bytes + 3) / 4);
+		add_entropy_words(&input_pool, buf, (bytes + 3) / 4);
 	}
 	if (p == buffer) {
 		return (ssize_t)ret;
@@ -1723,7 +1061,7 @@ random_ioctl(struct inode * inode, struc
 
 	switch (cmd) {
 	case RNDGETENTCNT:
-		ent_count = random_state->entropy_count;
+		ent_count = input_pool.entropy_count;
 		if (put_user(ent_count, p))
 			return -EFAULT;
 		return 0;
@@ -1732,12 +1070,12 @@ random_ioctl(struct inode * inode, struc
 			return -EPERM;
 		if (get_user(ent_count, p))
 			return -EFAULT;
-		credit_entropy_store(random_state, ent_count);
+		credit_entropy_store(&input_pool, ent_count);
 		/*
 		 * Wake up waiting processes if we have enough
 		 * entropy.
 		 */
-		if (random_state->entropy_count >= random_read_wakeup_thresh)
+		if (input_pool.entropy_count >= random_read_wakeup_thresh)
 			wake_up_interruptible(&random_read_wait);
 		return 0;
 	case RNDADDENTROPY:
@@ -1753,25 +1091,22 @@ random_ioctl(struct inode * inode, struc
 				      size, &file->f_pos);
 		if (retval < 0)
 			return retval;
-		credit_entropy_store(random_state, ent_count);
+		credit_entropy_store(&input_pool, ent_count);
 		/*
 		 * Wake up waiting processes if we have enough
 		 * entropy.
 		 */
-		if (random_state->entropy_count >= random_read_wakeup_thresh)
+		if (input_pool.entropy_count >= random_read_wakeup_thresh)
 			wake_up_interruptible(&random_read_wait);
 		return 0;
 	case RNDZAPENTCNT:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		random_state->entropy_count = 0;
-		return 0;
 	case RNDCLEARPOOL:
-		/* Clear the entropy pool and associated counters. */
+		/* Clear the entropy pool counters. */
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		clear_entropy_store(random_state);
-		init_std_data(random_state);
+		init_std_data(&input_pool);
+		init_std_data(&blocking_pool);
+		init_std_data(&nonblocking_pool);
 		return 0;
 	default:
 		return -EINVAL;
@@ -1822,8 +1157,9 @@ EXPORT_SYMBOL(generate_random_uuid);
 
 #include <linux/sysctl.h>
 
-static int min_read_thresh, max_read_thresh;
-static int min_write_thresh, max_write_thresh;
+static int min_read_thresh = 8, min_write_thresh;
+static int max_read_thresh = INPUT_POOL_WORDS * 32;
+static int max_write_thresh = INPUT_POOL_WORDS * 32;
 static char sysctl_bootid[16];
 
 /*
@@ -1891,7 +1227,7 @@ static int uuid_strategy(ctl_table *tabl
 	return 1;
 }
 
-static int sysctl_poolsize = DEFAULT_POOL_SIZE;
+static int sysctl_poolsize = INPUT_POOL_WORDS * 32;
 ctl_table random_table[] = {
 	{
 		.ctl_name 	= RANDOM_POOLSIZE,
@@ -1907,6 +1243,7 @@ ctl_table random_table[] = {
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
 		.proc_handler	= &proc_dointvec,
+		.data		= &input_pool.entropy_count,
 	},
 	{
 		.ctl_name	= RANDOM_READ_THRESH,
@@ -1949,14 +1286,6 @@ ctl_table random_table[] = {
 	},
 	{ .ctl_name = 0 }
 };
-
-static void sysctl_init_random(struct entropy_store *random_state)
-{
-	min_read_thresh = 8;
-	min_write_thresh = 0;
-	max_read_thresh = max_write_thresh = random_state->poolinfo.POOLBITS;
-	random_table[1].data = &random_state->entropy_count;
-}
 #endif 	/* CONFIG_SYSCTL */
 
 /********************************************************************
@@ -1965,7 +1294,6 @@ static void sysctl_init_random(struct en
  *
  ********************************************************************/
 
-#ifdef CONFIG_INET
 /*
  * TCP initial sequence number picking.  This uses the random number
  * generator to pick an initial secret value.  This value is hashed
@@ -1996,47 +1324,6 @@ static void sysctl_init_random(struct en
 #define K2 013240474631UL
 #define K3 015666365641UL
 
-/*
- * Basic cut-down MD4 transform.  Returns only 32 bits of result.
- */
-static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8])
-{
-	__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
-	/* Round 1 */
-	ROUND(F, a, b, c, d, in[0] + K1,  3);
-	ROUND(F, d, a, b, c, in[1] + K1,  7);
-	ROUND(F, c, d, a, b, in[2] + K1, 11);
-	ROUND(F, b, c, d, a, in[3] + K1, 19);
-	ROUND(F, a, b, c, d, in[4] + K1,  3);
-	ROUND(F, d, a, b, c, in[5] + K1,  7);
-	ROUND(F, c, d, a, b, in[6] + K1, 11);
-	ROUND(F, b, c, d, a, in[7] + K1, 19);
-
-	/* Round 2 */
-	ROUND(G, a, b, c, d, in[1] + K2,  3);
-	ROUND(G, d, a, b, c, in[3] + K2,  5);
-	ROUND(G, c, d, a, b, in[5] + K2,  9);
-	ROUND(G, b, c, d, a, in[7] + K2, 13);
-	ROUND(G, a, b, c, d, in[0] + K2,  3);
-	ROUND(G, d, a, b, c, in[2] + K2,  5);
-	ROUND(G, c, d, a, b, in[4] + K2,  9);
-	ROUND(G, b, c, d, a, in[6] + K2, 13);
-
-	/* Round 3 */
-	ROUND(H, a, b, c, d, in[3] + K3,  3);
-	ROUND(H, d, a, b, c, in[7] + K3,  9);
-	ROUND(H, c, d, a, b, in[2] + K3, 11);
-	ROUND(H, b, c, d, a, in[6] + K3, 15);
-	ROUND(H, a, b, c, d, in[1] + K3,  3);
-	ROUND(H, d, a, b, c, in[5] + K3,  9);
-	ROUND(H, c, d, a, b, in[0] + K3, 11);
-	ROUND(H, b, c, d, a, in[4] + K3, 15);
-
-	return buf[1] + b;	/* "most hashed" word */
-	/* Alternative: return sum of all words? */
-}
-
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
 static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
@@ -2202,6 +1489,31 @@ __u32 secure_tcpv6_sequence_number(__u32
 EXPORT_SYMBOL(secure_tcpv6_sequence_number);
 #endif
 
+/*  The code below is shamelessly stolen from secure_tcp_sequence_number().
+ *  All blames to Andrey V. Savochkin <saw@msu.ru>.
+ */
+__u32 secure_ip_id(__u32 daddr)
+{
+	struct keydata *keyptr;
+	__u32 hash[4];
+
+	keyptr = get_keyptr();
+
+	/*
+	 *  Pick a unique starting offset for each IP destination.
+	 *  The dest ip address is placed in the starting vector,
+	 *  which is then hashed with random data.
+	 */
+	hash[0] = daddr;
+	hash[1] = keyptr->secret[9];
+	hash[2] = keyptr->secret[10];
+	hash[3] = keyptr->secret[11];
+
+	return half_md4_transform(hash, keyptr->secret);
+}
+
+#ifdef CONFIG_INET
+
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
@@ -2221,7 +1533,7 @@ __u32 secure_tcp_sequence_number(__u32 s
 	hash[2]=(sport << 16) + dport;
 	hash[3]=keyptr->secret[11];
 
-	seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
+	seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
 	seq += keyptr->count;
 	/*
 	 *	As close as possible to RFC 793, which
@@ -2242,28 +1554,7 @@ __u32 secure_tcp_sequence_number(__u32 s
 
 EXPORT_SYMBOL(secure_tcp_sequence_number);
 
-/*  The code below is shamelessly stolen from secure_tcp_sequence_number().
- *  All blames to Andrey V. Savochkin <saw@msu.ru>.
- */
-__u32 secure_ip_id(__u32 daddr)
-{
-	struct keydata *keyptr;
-	__u32 hash[4];
-
-	keyptr = get_keyptr();
-
-	/*
-	 *  Pick a unique starting offset for each IP destination.
-	 *  The dest ip address is placed in the starting vector,
-	 *  which is then hashed with random data.
-	 */
-	hash[0] = daddr;
-	hash[1] = keyptr->secret[9];
-	hash[2] = keyptr->secret[10];
-	hash[3] = keyptr->secret[11];
 
-	return halfMD4Transform(hash, keyptr->secret);
-}
 
 /* Generate secure starting point for ephemeral TCP port search */
 u32 secure_tcp_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport)
@@ -2280,106 +1571,59 @@ u32 secure_tcp_port_ephemeral(__u32 sadd
 	hash[2] = dport ^ keyptr->secret[10];
 	hash[3] = keyptr->secret[11];
 
-	return halfMD4Transform(hash, keyptr->secret);
+	return half_md4_transform(hash, keyptr->secret);
 }
 
-#ifdef CONFIG_SYN_COOKIES
-/*
- * Secure SYN cookie computation. This is the algorithm worked out by
- * Dan Bernstein and Eric Schenk.
- *
- * For linux I implement the 1 minute counter by looking at the jiffies clock.
- * The count is passed in as a parameter, so this code doesn't much care.
- */
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+u32 secure_tcpv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dport)
+{
+	struct keydata *keyptr = get_keyptr();
+	u32 hash[12];
 
-#define COOKIEBITS 24	/* Upper bits store count */
-#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+	memcpy(hash, saddr, 16);
+	hash[4] = dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
 
-static int syncookie_init;
-static __u32 syncookie_secret[2][16-3+HASH_BUFFER_SIZE];
+	return twothirdsMD4Transform(daddr, hash);
+}
+EXPORT_SYMBOL(secure_tcpv6_port_ephemeral);
+#endif
 
-__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
-		__u16 dport, __u32 sseq, __u32 count, __u32 data)
-{
-	__u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
-	__u32 seq;
+#endif /* CONFIG_INET */
 
-	/*
-	 * Pick two random secrets the first time we need a cookie.
-	 */
-	if (syncookie_init == 0) {
-		get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
-		syncookie_init = 1;
-	}
 
+/*
+ * Get a random word for internal kernel use only. Similar to urandom but
+ * with the goal of minimal entropy pool depletion. As a result, the random
+ * value is not cryptographically secure but for several uses the cost of
+ * depleting entropy is too high
+ */
+unsigned int get_random_int(void)
+{
 	/*
-	 * Compute the secure sequence number.
-	 * The output should be:
-   	 *   HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24)
-	 *      + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
-	 * Where sseq is their sequence number and count increases every
-	 * minute by 1.
-	 * As an extra hack, we add a small "data" value that encodes the
-	 * MSS into the second hash value.
+	 * Use IP's RNG. It suits our purpose perfectly: it re-keys itself
+	 * every second, from the entropy pool (and thus creates a limited
+	 * drain on it), and uses halfMD4Transform within the second. We
+	 * also mix it with jiffies and the PID:
 	 */
-
-	memcpy(tmp + 3, syncookie_secret[0], sizeof(syncookie_secret[0]));
-	tmp[0]=saddr;
-	tmp[1]=daddr;
-	tmp[2]=(sport << 16) + dport;
-	HASH_TRANSFORM(tmp+16, tmp);
-	seq = tmp[17] + sseq + (count << COOKIEBITS);
-
-	memcpy(tmp + 3, syncookie_secret[1], sizeof(syncookie_secret[1]));
-	tmp[0]=saddr;
-	tmp[1]=daddr;
-	tmp[2]=(sport << 16) + dport;
-	tmp[3] = count;	/* minute counter */
-	HASH_TRANSFORM(tmp + 16, tmp);
-
-	/* Add in the second hash and the data */
-	return seq + ((tmp[17] + data) & COOKIEMASK);
+	return secure_ip_id(current->pid + jiffies);
 }
 
 /*
- * This retrieves the small "data" value from the syncookie.
- * If the syncookie is bad, the data returned will be out of
- * range.  This must be checked by the caller.
- *
- * The count value used to generate the cookie must be within
- * "maxdiff" if the current (passed-in) "count".  The return value
- * is (__u32)-1 if this test fails.
- */
-__u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport,
-		__u16 dport, __u32 sseq, __u32 count, __u32 maxdiff)
-{
-	__u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
-	__u32 diff;
-
-	if (syncookie_init == 0)
-		return (__u32)-1; /* Well, duh! */
-
-	/* Strip away the layers from the cookie */
-	memcpy(tmp + 3, syncookie_secret[0], sizeof(syncookie_secret[0]));
-	tmp[0]=saddr;
-	tmp[1]=daddr;
-	tmp[2]=(sport << 16) + dport;
-	HASH_TRANSFORM(tmp + 16, tmp);
-	cookie -= tmp[17] + sseq;
-	/* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
-
-	diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS);
-	if (diff >= maxdiff)
-		return (__u32)-1;
-
-	memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
-	tmp[0] = saddr;
-	tmp[1] = daddr;
-	tmp[2] = (sport << 16) + dport;
-	tmp[3] = count - diff;	/* minute counter */
-	HASH_TRANSFORM(tmp + 16, tmp);
+ * randomize_range() returns a start address such that
+ *
+ *    [...... <range> .....]
+ *  start                  end
+ *
+ * a <range> with size "len" starting at the return value is inside in the
+ * area defined by [start, end], but is otherwise randomized.
+ */
+unsigned long
+randomize_range(unsigned long start, unsigned long end, unsigned long len)
+{
+	unsigned long range = end - len - start;
 
-	return (cookie - tmp[17]) & COOKIEMASK;	/* Leaving the data behind */
+	if (end <= start + len)
+		return 0;
+	return PAGE_ALIGN(get_random_int() % range + start);
 }
-#endif
-#endif /* CONFIG_INET */
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct fi
 {
 	struct block_device *bdev = filp->private_data;
 
-	return ioctl_by_bdev(bdev, command, arg);
+	return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
 }
 
 static void bind_device(struct raw_config_request *rq)
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -221,7 +221,7 @@ static int rio_probe_addrs[]= {0xc0000, 
 /* Set the mask to all-ones. This alas, only supports 32 interrupts. 
    Some architectures may need more. -- Changed to LONG to
    support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
-long rio_irqmask = -1;
+static long rio_irqmask = -1;
 
 MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
 MODULE_DESCRIPTION("RIO driver");
@@ -681,8 +681,9 @@ static int rio_ioctl (struct tty_struct 
     }
     break;
   case TIOCGSERIAL:
-    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
-                          sizeof(struct serial_struct))) == 0)
+    rc = -EFAULT;
+    if (access_ok(VERIFY_WRITE, (void *) arg,
+                          sizeof(struct serial_struct)))
       rc = gs_getserial(&PortP->gs, (struct serial_struct *) arg);
     break;
   case TCSBRK:
@@ -711,8 +712,9 @@ static int rio_ioctl (struct tty_struct 
     }
     break;
   case TIOCSSERIAL:
-    if ((rc = verify_area(VERIFY_READ, (void *) arg,
-                          sizeof(struct serial_struct))) == 0)
+    rc = -EFAULT;
+    if (access_ok(VERIFY_READ, (void *) arg,
+                          sizeof(struct serial_struct)))
       rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg);
     break;
 #if 0
@@ -722,8 +724,10 @@ static int rio_ioctl (struct tty_struct 
    * #if 0 disablement predates this comment.
    */
   case TIOCMGET:
-    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
-                          sizeof(unsigned int))) == 0) {
+    rc = -EFAULT;
+    if (access_ok(VERIFY_WRITE, (void *) arg,
+                          sizeof(unsigned int))) {
+      rc = 0;
       ival = rio_getsignals(port);
       put_user(ival, (unsigned int *) arg);
     }
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -84,9 +84,7 @@ static struct IdentifyRta IdRta;
 static struct KillNeighbour KillUnit;
 
 int
-RIOFoadRta(HostP, MapP)
-struct Host *	HostP;
-struct Map *	MapP;
+RIOFoadRta(struct Host *HostP, struct Map *MapP)
 {
 	struct CmdBlk *CmdBlkP;
 
@@ -117,9 +115,7 @@ struct Map *	MapP;
 }
 
 int
-RIOZombieRta(HostP, MapP)
-struct Host *	HostP;
-struct Map *	MapP;
+RIOZombieRta(struct Host *HostP, struct Map *MapP)
 {
 	struct CmdBlk *CmdBlkP;
 
@@ -150,10 +146,8 @@ struct Map *	MapP;
 }
 
 int
-RIOCommandRta(p, RtaUnique, func)
-struct rio_info *	p;
-uint RtaUnique;
-int (* func)( struct Host *HostP, struct Map *MapP );
+RIOCommandRta(struct rio_info *p, uint RtaUnique,
+	int (* func)(struct Host *HostP, struct Map *MapP))
 {
 	uint Host;
 
@@ -195,9 +189,7 @@ int (* func)( struct Host *HostP, struct
 
 
 int
-RIOIdentifyRta(p, arg)
-struct rio_info *	p;
-caddr_t arg;
+RIOIdentifyRta(struct rio_info *p, caddr_t arg)
 {
 	uint Host;
 
@@ -263,9 +255,7 @@ caddr_t arg;
 
 
 int
-RIOKillNeighbour(p, arg)
-struct rio_info *	p;
-caddr_t arg;
+RIOKillNeighbour(struct rio_info *p, caddr_t arg)
 {
 	uint Host;
 	uint ID;
@@ -329,10 +319,7 @@ caddr_t arg;
 }
 
 int
-RIOSuspendBootRta(HostP, ID, Link)
-struct Host *HostP;
-int ID;
-int Link; 
+RIOSuspendBootRta(struct Host *HostP, int ID, int Link)
 {
 	struct CmdBlk *CmdBlkP;
 
@@ -363,8 +350,7 @@ int Link; 
 }
 
 int
-RIOFoadWakeup(p)
-struct rio_info *	p;
+RIOFoadWakeup(struct rio_info *p)
 {
 	int port;
 	register struct Port *PortP;
@@ -398,11 +384,7 @@ struct rio_info *	p;
 ** Incoming command on the COMMAND_RUP to be processed.
 */
 static int
-RIOCommandRup(p, Rup, HostP, PacketP)
-struct rio_info *	p;
-uint Rup;
-struct Host *HostP;
-PKT *PacketP; 
+RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP)
 {
 	struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
 	struct Port *PortP;
@@ -619,7 +601,7 @@ PKT *PacketP; 
 ** Allocate an empty command block.
 */
 struct CmdBlk *
-RIOGetCmdBlk()
+RIOGetCmdBlk(void)
 {
 	struct CmdBlk *CmdBlkP;
 
@@ -634,8 +616,7 @@ RIOGetCmdBlk()
 ** Return a block to the head of the free list.
 */
 void
-RIOFreeCmdBlk(CmdBlkP)
-struct CmdBlk *CmdBlkP;
+RIOFreeCmdBlk(struct CmdBlk *CmdBlkP)
 {
 	sysfree((void *)CmdBlkP, sizeof(struct CmdBlk));
 }
@@ -645,10 +626,7 @@ struct CmdBlk *CmdBlkP;
 ** a given rup.
 */
 int
-RIOQueueCmdBlk(HostP, Rup, CmdBlkP)
-struct Host *HostP;
-uint Rup;
-struct CmdBlk *CmdBlkP;
+RIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP)
 {
 	struct CmdBlk **Base;
 	struct UnixRup *UnixRupP;
@@ -679,7 +657,6 @@ struct CmdBlk *CmdBlkP;
 							:TRUE)) {
 		rio_dprintk (RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n",
 					     CmdBlkP->Packet.data[0]);
-                                            
 
 		/*
 		** Whammy! blat that pack!
@@ -737,9 +714,7 @@ struct CmdBlk *CmdBlkP;
 ** must be called at splrio() or higher.
 */
 void
-RIOPollHostCommands(p, HostP)
-struct rio_info *	p;
-struct Host *		HostP;
+RIOPollHostCommands(struct rio_info *p, struct Host *HostP)
 {
 	register struct CmdBlk *CmdBlkP;
 	register struct UnixRup *UnixRupP;
@@ -918,9 +893,7 @@ struct Host *		HostP;
 }
 
 int
-RIOWFlushMark(iPortP, CmdBlkP)
-int iPortP;
-struct CmdBlk *CmdBlkP;
+RIOWFlushMark(int iPortP, struct CmdBlk *CmdBlkP)
 {
 	struct Port *	PortP = (struct Port *)iPortP;
 	unsigned long flags;
@@ -936,9 +909,7 @@ struct CmdBlk *CmdBlkP;
 }
 
 int
-RIORFlushEnable(iPortP, CmdBlkP)
-int iPortP;
-struct CmdBlk *CmdBlkP; 
+RIORFlushEnable(int iPortP, struct CmdBlk *CmdBlkP)
 {
 	struct Port *	PortP = (struct Port *)iPortP;
 	PKT *PacketP;
@@ -965,9 +936,7 @@ struct CmdBlk *CmdBlkP; 
 }
 
 int
-RIOUnUse(iPortP, CmdBlkP)
-int iPortP;
-struct CmdBlk *CmdBlkP; 
+RIOUnUse(int iPortP, struct CmdBlk *CmdBlkP)
 {
 	struct Port *	PortP = (struct Port *)iPortP;
 	unsigned long flags;
@@ -1009,9 +978,7 @@ struct CmdBlk *CmdBlkP; 
 }
 
 void
-ShowPacket(Flags, PacketP)
-uint Flags;
-struct PKT *PacketP; 
+ShowPacket(uint Flags, struct PKT *PacketP)
 {
 }
 
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -73,6 +73,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/sysctl.h>
 #include <linux/wait.h>
@@ -151,8 +152,7 @@ static void set_rtc_irq_bit(unsigned cha
 static void mask_rtc_irq_bit(unsigned char bit);
 #endif
 
-static int rtc_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, void *data);
+static int rtc_proc_open(struct inode *inode, struct file *file);
 
 /*
  *	Bits in rtc_status. (6 bits of room for future expansion)
@@ -871,11 +871,18 @@ static struct file_operations rtc_fops =
 	.fasync		= rtc_fasync,
 };
 
-static struct miscdevice rtc_dev=
-{
-	RTC_MINOR,
-	"rtc",
-	&rtc_fops
+static struct miscdevice rtc_dev = {
+	.minor		= RTC_MINOR,
+	.name		= "rtc",
+	.fops		= &rtc_fops,
+};
+
+static struct file_operations rtc_proc_fops = {
+	.owner = THIS_MODULE,
+	.open = rtc_proc_open,
+	.read  = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
 };
 
 #if defined(RTC_IRQ) && !defined(__sparc__)
@@ -884,6 +891,7 @@ static irqreturn_t (*rtc_int_handler_ptr
 
 static int __init rtc_init(void)
 {
+	struct proc_dir_entry *ent;
 #if defined(__alpha__) || defined(__mips__)
 	unsigned int year, ctrl;
 	unsigned long uip_watchdog;
@@ -974,7 +982,9 @@ no_irq:
 		release_region(RTC_PORT(0), RTC_IO_EXTENT);
 		return -ENODEV;
 	}
-	if (!create_proc_read_entry ("driver/rtc", 0, NULL, rtc_read_proc, NULL)) {
+
+	ent = create_proc_entry("driver/rtc", 0, NULL);
+	if (!ent) {
 #ifdef RTC_IRQ
 		free_irq(RTC_IRQ, NULL);
 #endif
@@ -982,6 +992,7 @@ no_irq:
 		misc_deregister(&rtc_dev);
 		return -ENOMEM;
 	}
+	ent->proc_fops = &rtc_proc_fops;
 
 #if defined(__alpha__) || defined(__mips__)
 	rtc_freq = HZ;
@@ -1119,11 +1130,10 @@ static void rtc_dropped_irq(unsigned lon
  *	Info exported via "/proc/driver/rtc".
  */
 
-static int rtc_proc_output (char *buf)
+static int rtc_proc_show(struct seq_file *seq, void *v)
 {
 #define YN(bit) ((ctrl & bit) ? "yes" : "no")
 #define NY(bit) ((ctrl & bit) ? "no" : "yes")
-	char *p;
 	struct rtc_time tm;
 	unsigned char batt, ctrl;
 	unsigned long freq;
@@ -1134,7 +1144,6 @@ static int rtc_proc_output (char *buf)
 	freq = rtc_freq;
 	spin_unlock_irq(&rtc_lock);
 
-	p = buf;
 
 	rtc_get_rtc_time(&tm);
 
@@ -1142,12 +1151,12 @@ static int rtc_proc_output (char *buf)
 	 * 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",
-		     tm.tm_hour, tm.tm_min, tm.tm_sec,
-		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+	seq_printf(seq,
+		   "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);
 
 	get_rtc_alm_time(&tm);
 
@@ -1156,57 +1165,50 @@ static int rtc_proc_output (char *buf)
 	 * match any value for that particular field. Values that are
 	 * greater than a valid time, but less than 0xc0 shouldn't appear.
 	 */
-	p += sprintf(p, "alarm\t\t: ");
+	seq_puts(seq, "alarm\t\t: ");
 	if (tm.tm_hour <= 24)
-		p += sprintf(p, "%02d:", tm.tm_hour);
+		seq_printf(seq, "%02d:", tm.tm_hour);
 	else
-		p += sprintf(p, "**:");
+		seq_puts(seq, "**:");
 
 	if (tm.tm_min <= 59)
-		p += sprintf(p, "%02d:", tm.tm_min);
+		seq_printf(seq, "%02d:", tm.tm_min);
 	else
-		p += sprintf(p, "**:");
+		seq_puts(seq, "**:");
 
 	if (tm.tm_sec <= 59)
-		p += sprintf(p, "%02d\n", tm.tm_sec);
+		seq_printf(seq, "%02d\n", tm.tm_sec);
 	else
-		p += sprintf(p, "**\n");
+		seq_puts(seq, "**\n");
 
-	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),
-		     freq,
-		     batt ? "okay" : "dead");
+	seq_printf(seq,
+		   "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),
+		   freq,
+		   batt ? "okay" : "dead");
 
-	return  p - buf;
+	return  0;
 #undef YN
 #undef NY
 }
 
-static int rtc_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, void *data)
+static int rtc_proc_open(struct inode *inode, struct file *file)
 {
-        int len = 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;
+	return single_open(file, rtc_proc_show, NULL);
 }
 
 void rtc_get_rtc_time(struct rtc_time *rtc_tm)
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
--- a/drivers/char/s3c2410-rtc.c
+++ b/drivers/char/s3c2410-rtc.c
@@ -13,6 +13,7 @@
  *	08-Nov-2004	BJD	Initial creation
  *	12-Nov-2004	BJD	Added periodic IRQ and PM code
  *	22-Nov-2004	BJD	Sign-test on alarm code to check for <0
+ *	10-Mar-2005	LCVR	Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
 */
 
 #include <linux/module.h>
@@ -38,8 +39,8 @@
 /* need this for the RTC_AF definitions */
 #include <linux/mc146818rtc.h>
 
-#undef S3C2410_VA_RTC
-#define S3C2410_VA_RTC s3c2410_rtc_base
+#undef S3C24XX_VA_RTC
+#define S3C24XX_VA_RTC s3c2410_rtc_base
 
 static struct resource *s3c2410_rtc_mem;
 
@@ -115,7 +116,7 @@ static void s3c2410_rtc_setfreq(int freq
 
 /* Time read/write */
 
-static void s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
+static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
 {
 	unsigned int have_retried = 0;
 
@@ -150,6 +151,8 @@ static void s3c2410_rtc_gettime(struct r
 
 	rtc_tm->tm_year += 100;
 	rtc_tm->tm_mon -= 1;
+
+	return 0;
 }
 
 
@@ -170,7 +173,7 @@ static int s3c2410_rtc_settime(struct rt
 	return 0;
 }
 
-static void s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
+static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
 {
 	struct rtc_time *alm_tm = &alrm->time;
 	unsigned int alm_en;
@@ -230,6 +233,8 @@ static void s3c2410_rtc_getalarm(struct 
 	}
 
 	/* todo - set alrm->enabled ? */
+
+	return 0;
 }
 
 static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
@@ -514,7 +519,7 @@ static struct timespec s3c2410_rtc_delta
 
 static int ticnt_save;
 
-static int s3c2410_rtc_suspend(struct device *dev, u32 state, u32 level)
+static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct rtc_time tm;
 	struct timespec time;
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -43,15 +43,13 @@ static char *sel_buffer;
    from interrupt (via scrollback/front) */
 
 /* set reverse video on characters s-e of console with selection. */
-inline static void
-highlight(const int s, const int e)
+static inline void highlight(const int s, const int e)
 {
 	invert_screen(sel_cons, s, e-s+2, 1);
 }
 
 /* use complementary color to show the pointer */
-inline static void
-highlight_pointer(const int where)
+static inline void highlight_pointer(const int where)
 {
 	complement_pos(sel_cons, where);
 }
@@ -122,7 +120,7 @@ int set_selection(const struct tiocl_sel
 
 	{ unsigned short xs, ys, xe, ye;
 
-	  if (verify_area(VERIFY_READ, sel, sizeof(*sel)))
+	  if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
 		return -EFAULT;
 	  __get_user(xs, &sel->xs);
 	  __get_user(ys, &sel->ys);
@@ -277,7 +275,7 @@ int set_selection(const struct tiocl_sel
  */
 int paste_selection(struct tty_struct *tty)
 {
-	struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
+	struct vc_data *vc = (struct vc_data *)tty->driver_data;
 	int	pasted = 0, count;
 	struct  tty_ldisc *ld;
 	DECLARE_WAITQUEUE(wait, current);
@@ -288,7 +286,7 @@ int paste_selection(struct tty_struct *t
 
 	ld = tty_ldisc_ref_wait(tty);
 	
-	add_wait_queue(&vt->paste_wait, &wait);
+	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (test_bit(TTY_THROTTLED, &tty->flags)) {
@@ -300,7 +298,7 @@ int paste_selection(struct tty_struct *t
 		tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count);
 		pasted += count;
 	}
-	remove_wait_queue(&vt->paste_wait, &wait);
+	remove_wait_queue(&vc->paste_wait, &wait);
 	current->state = TASK_RUNNING;
 
 	tty_ldisc_deref(ld);
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -192,8 +192,8 @@ scdrv_read(struct file *file, char __use
 		}
 
 		len = CHUNKSIZE;
-		add_wait_queue(&sd->sd_rq, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&sd->sd_rq, &wait);
 		spin_unlock_irqrestore(&sd->sd_rlock, flags);
 
 		schedule_timeout(SCDRV_TIMEOUT);
@@ -288,8 +288,8 @@ scdrv_write(struct file *file, const cha
 			return -EAGAIN;
 		}
 
-		add_wait_queue(&sd->sd_wq, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&sd->sd_wq, &wait);
 		spin_unlock_irqrestore(&sd->sd_wlock, flags);
 
 		schedule_timeout(SCDRV_TIMEOUT);
@@ -374,6 +374,7 @@ scdrv_init(void)
 	void *salbuf;
 	struct class_simple *snsc_class;
 	dev_t first_dev, dev;
+	nasid_t event_nasid = ia64_sn_get_console_nasid();
 
 	if (alloc_chrdev_region(&first_dev, 0, numionodes,
 				SYSCTL_BASENAME) < 0) {
@@ -441,6 +442,13 @@ scdrv_init(void)
 			ia64_sn_irtr_intr_enable(scd->scd_nasid,
 						 0 /*ignored */ ,
 						 SAL_IROUTER_INTR_RECV);
+
+                        /* on the console nasid, prepare to receive
+                         * system controller environmental events
+                         */
+                        if(scd->scd_nasid == event_nasid) {
+                                scdrv_event_init(scd);
+                        }
 	}
 	return 0;
 }
diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h
--- a/drivers/char/snsc.h
+++ b/drivers/char/snsc.h
@@ -47,4 +47,44 @@ struct sysctl_data_s {
 	nasid_t scd_nasid;	/* Node on which subchannels are opened. */
 };
 
+
+/* argument types */
+#define IR_ARG_INT              0x00    /* 4-byte integer (big-endian)  */
+#define IR_ARG_ASCII            0x01    /* null-terminated ASCII string */
+#define IR_ARG_UNKNOWN          0x80    /* unknown data type.  The low
+                                         * 7 bits will contain the data
+                                         * length.                      */
+#define IR_ARG_UNKNOWN_LENGTH_MASK	0x7f
+
+
+/* system controller event codes */
+#define EV_CLASS_MASK		0xf000ul
+#define EV_SEVERITY_MASK	0x0f00ul
+#define EV_COMPONENT_MASK	0x00fful
+
+#define EV_CLASS_POWER		0x1000ul
+#define EV_CLASS_FAN		0x2000ul
+#define EV_CLASS_TEMP		0x3000ul
+#define EV_CLASS_ENV		0x4000ul
+#define EV_CLASS_TEST_FAULT	0x5000ul
+#define EV_CLASS_TEST_WARNING	0x6000ul
+#define EV_CLASS_PWRD_NOTIFY	0x8000ul
+
+#define EV_SEVERITY_POWER_STABLE	0x0000ul
+#define EV_SEVERITY_POWER_LOW_WARNING	0x0100ul
+#define EV_SEVERITY_POWER_HIGH_WARNING	0x0200ul
+#define EV_SEVERITY_POWER_HIGH_FAULT	0x0300ul
+#define EV_SEVERITY_POWER_LOW_FAULT	0x0400ul
+
+#define EV_SEVERITY_FAN_STABLE		0x0000ul
+#define EV_SEVERITY_FAN_WARNING		0x0100ul
+#define EV_SEVERITY_FAN_FAULT		0x0200ul
+
+#define EV_SEVERITY_TEMP_STABLE		0x0000ul
+#define EV_SEVERITY_TEMP_ADVISORY	0x0100ul
+#define EV_SEVERITY_TEMP_CRITICAL	0x0200ul
+#define EV_SEVERITY_TEMP_FAULT		0x0300ul
+
+void scdrv_event_init(struct sysctl_data_s *);
+
 #endif /* _SN_SYSCTL_H_ */
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/snsc_event.c
@@ -0,0 +1,304 @@
+/*
+ * SN Platform system controller communication support
+ *
+ * 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) 2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * System controller event handler
+ *
+ * These routines deal with environmental events arriving from the
+ * system controllers.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/byteorder/generic.h>
+#include <asm/sn/sn_sal.h>
+#include "snsc.h"
+
+static struct subch_data_s *event_sd;
+
+void scdrv_event(unsigned long);
+DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
+
+/*
+ * scdrv_event_interrupt
+ *
+ * Pull incoming environmental events off the physical link to the
+ * system controller and put them in a temporary holding area in SAL.
+ * Schedule scdrv_event() to move them along to their ultimate
+ * destination.
+ */
+static irqreturn_t
+scdrv_event_interrupt(int irq, void *subch_data, struct pt_regs *regs)
+{
+	struct subch_data_s *sd = subch_data;
+	unsigned long flags;
+	int status;
+
+	spin_lock_irqsave(&sd->sd_rlock, flags);
+	status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
+
+	if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) {
+		tasklet_schedule(&sn_sysctl_event);
+	}
+	spin_unlock_irqrestore(&sd->sd_rlock, flags);
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * scdrv_parse_event
+ *
+ * Break an event (as read from SAL) into useful pieces so we can decide
+ * what to do with it.
+ */
+static int
+scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
+{
+	char *desc_end;
+
+	/* record event source address */
+	*src = be32_to_cpup((__be32 *)event);
+	event += 4; 			/* move on to event code */
+
+	/* record the system controller's event code */
+	*code = be32_to_cpup((__be32 *)event);
+	event += 4;			/* move on to event arguments */
+
+	/* how many arguments are in the packet? */
+	if (*event++ != 2) {
+		/* if not 2, give up */
+		return -1;
+	}
+
+	/* parse out the ESP code */
+	if (*event++ != IR_ARG_INT) {
+		/* not an integer argument, so give up */
+		return -1;
+	}
+	*esp_code = be32_to_cpup((__be32 *)event);
+	event += 4;
+
+	/* parse out the event description */
+	if (*event++ != IR_ARG_ASCII) {
+		/* not an ASCII string, so give up */
+		return -1;
+	}
+	event[CHUNKSIZE-1] = '\0';	/* ensure this string ends! */
+	event += 2; 			/* skip leading CR/LF */
+	desc_end = desc + sprintf(desc, "%s", event);
+
+	/* strip trailing CR/LF (if any) */
+	for (desc_end--;
+	     (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa));
+	     desc_end--) {
+		*desc_end = '\0';
+	}
+
+	return 0;
+}
+
+
+/*
+ * scdrv_event_severity
+ *
+ * Figure out how urgent a message we should write to the console/syslog
+ * via printk.
+ */
+static char *
+scdrv_event_severity(int code)
+{
+	int ev_class = (code & EV_CLASS_MASK);
+	int ev_severity = (code & EV_SEVERITY_MASK);
+	char *pk_severity = KERN_NOTICE;
+
+	switch (ev_class) {
+	case EV_CLASS_POWER:
+		switch (ev_severity) {
+		case EV_SEVERITY_POWER_LOW_WARNING:
+		case EV_SEVERITY_POWER_HIGH_WARNING:
+			pk_severity = KERN_WARNING;
+			break;
+		case EV_SEVERITY_POWER_HIGH_FAULT:
+		case EV_SEVERITY_POWER_LOW_FAULT:
+			pk_severity = KERN_ALERT;
+			break;
+		}
+		break;
+	case EV_CLASS_FAN:
+		switch (ev_severity) {
+		case EV_SEVERITY_FAN_WARNING:
+			pk_severity = KERN_WARNING;
+			break;
+		case EV_SEVERITY_FAN_FAULT:
+			pk_severity = KERN_CRIT;
+			break;
+		}
+		break;
+	case EV_CLASS_TEMP:
+		switch (ev_severity) {
+		case EV_SEVERITY_TEMP_ADVISORY:
+			pk_severity = KERN_WARNING;
+			break;
+		case EV_SEVERITY_TEMP_CRITICAL:
+			pk_severity = KERN_CRIT;
+			break;
+		case EV_SEVERITY_TEMP_FAULT:
+			pk_severity = KERN_ALERT;
+			break;
+		}
+		break;
+	case EV_CLASS_ENV:
+		pk_severity = KERN_ALERT;
+		break;
+	case EV_CLASS_TEST_FAULT:
+		pk_severity = KERN_ALERT;
+		break;
+	case EV_CLASS_TEST_WARNING:
+		pk_severity = KERN_WARNING;
+		break;
+	case EV_CLASS_PWRD_NOTIFY:
+		pk_severity = KERN_ALERT;
+		break;
+	}
+
+	return pk_severity;
+}
+
+
+/*
+ * scdrv_dispatch_event
+ *
+ * Do the right thing with an incoming event.  That's often nothing
+ * more than printing it to the system log.  For power-down notifications
+ * we start a graceful shutdown.
+ */
+static void
+scdrv_dispatch_event(char *event, int len)
+{
+	int code, esp_code, src;
+	char desc[CHUNKSIZE];
+	char *severity;
+
+	if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) {
+		/* ignore uninterpretible event */
+		return;
+	}
+
+	/* how urgent is the message? */
+	severity = scdrv_event_severity(code);
+
+	if ((code & EV_CLASS_MASK) == EV_CLASS_PWRD_NOTIFY) {
+		struct task_struct *p;
+
+		/* give a SIGPWR signal to init proc */
+
+		/* first find init's task */
+		read_lock(&tasklist_lock);
+		for_each_process(p) {
+			if (p->pid == 1)
+				break;
+		}
+		if (p) { /* we found init's task */
+			printk(KERN_EMERG "Power off indication received. Initiating power fail sequence...\n");
+			force_sig(SIGPWR, p);
+		} else { /* failed to find init's task - just give message(s) */
+			printk(KERN_WARNING "Failed to find init proc to handle power off!\n");
+			printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
+		}
+		read_unlock(&tasklist_lock);
+	} else {
+		/* print to system log */
+		printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
+	}
+}
+
+
+/*
+ * scdrv_event
+ *
+ * Called as a tasklet when an event arrives from the L1.  Read the event
+ * from where it's temporarily stored in SAL and call scdrv_dispatch_event()
+ * to send it on its way.  Keep trying to read events until SAL indicates
+ * that there are no more immediately available.
+ */
+void
+scdrv_event(unsigned long dummy)
+{
+	int status;
+	int len;
+	unsigned long flags;
+	struct subch_data_s *sd = event_sd;
+
+	/* anything to read? */
+	len = CHUNKSIZE;
+	spin_lock_irqsave(&sd->sd_rlock, flags);
+	status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
+				   sd->sd_rb, &len);
+
+	while (!(status < 0)) {
+		spin_unlock_irqrestore(&sd->sd_rlock, flags);
+		scdrv_dispatch_event(sd->sd_rb, len);
+		len = CHUNKSIZE;
+		spin_lock_irqsave(&sd->sd_rlock, flags);
+		status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
+					   sd->sd_rb, &len);
+	}
+	spin_unlock_irqrestore(&sd->sd_rlock, flags);
+}
+
+
+/*
+ * scdrv_event_init
+ *
+ * Sets up a system controller subchannel to begin receiving event
+ * messages. This is sort of a specialized version of scdrv_open()
+ * in drivers/char/sn_sysctl.c.
+ */
+void
+scdrv_event_init(struct sysctl_data_s *scd)
+{
+	int rv;
+
+	event_sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL);
+	if (event_sd == NULL) {
+		printk(KERN_WARNING "%s: couldn't allocate subchannel info"
+		       " for event monitoring\n", __FUNCTION__);
+		return;
+	}
+
+	/* initialize subch_data_s fields */
+	memset(event_sd, 0, sizeof (struct subch_data_s));
+	event_sd->sd_nasid = scd->scd_nasid;
+	spin_lock_init(&event_sd->sd_rlock);
+
+	/* ask the system controllers to send events to this node */
+	event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid);
+
+	if (event_sd->sd_subch < 0) {
+		kfree(event_sd);
+		printk(KERN_WARNING "%s: couldn't open event subchannel\n",
+		       __FUNCTION__);
+		return;
+	}
+
+	/* hook event subchannel up to the system controller interrupt */
+	rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
+			 SA_SHIRQ | SA_INTERRUPT,
+			 "system controller events", event_sd);
+	if (rv) {
+		printk(KERN_WARNING "%s: irq request failed (%d)\n",
+		       __FUNCTION__, rv);
+		ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
+		kfree(event_sd);
+		return;
+	}
+}
+
+
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1021,11 +1021,11 @@ static int sonypi_misc_ioctl(struct inod
 			ret = -EIO;
 			break;
 		}
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+		if (copy_to_user(argp, &val8, sizeof(val8)))
 			ret = -EFAULT;
 		break;
 	case SONYPI_IOCSFAN:
-		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+		if (copy_from_user(&val8, argp, sizeof(val8))) {
 			ret = -EFAULT;
 			break;
 		}
@@ -1038,7 +1038,7 @@ static int sonypi_misc_ioctl(struct inod
 			ret = -EIO;
 			break;
 		}
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+		if (copy_to_user(argp, &val8, sizeof(val8)))
 			ret = -EFAULT;
 		break;
 	default:
@@ -1103,7 +1103,7 @@ static int sonypi_disable(void)
 #ifdef CONFIG_PM
 static int old_camera_power;
 
-static int sonypi_suspend(struct device *dev, u32 state, u32 level)
+static int sonypi_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_DISABLE) {
 		old_camera_power = sonypi_device.camera_power;
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -66,7 +66,7 @@
  * 
  */
 
-#define VERSION "1.10"
+#define VERSION "1.11"
 
 
 /*
@@ -99,6 +99,44 @@
 #include "cd1865.h"
 
 
+/*
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile...
+*/
+#define DEBUG
+
+static int sx_debug;
+static int sx_rxfifo = SPECIALIX_RXFIFO;
+
+#ifdef DEBUG
+#define dprintk(f, str...) if (sx_debug & f) printk (str)
+#else
+#define dprintk(f, str...) /* nothing */
+#endif
+
+#define SX_DEBUG_FLOW    0x0001
+#define SX_DEBUG_DATA    0x0002
+#define SX_DEBUG_PROBE   0x0004
+#define SX_DEBUG_CHAN    0x0008
+#define SX_DEBUG_INIT    0x0010
+#define SX_DEBUG_RX      0x0020
+#define SX_DEBUG_TX      0x0040
+#define SX_DEBUG_IRQ     0x0080
+#define SX_DEBUG_OPEN    0x0100
+#define SX_DEBUG_TERMIOS 0x0200
+#define SX_DEBUG_SIGNALS 0x0400
+#define SX_DEBUG_FIFO    0x0800
+
+
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
+#define func_exit()  dprintk (SX_DEBUG_FLOW, "io8: exit  %s\n", __FUNCTION__)
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
 
 /* Configurable options: */
 
@@ -110,6 +148,12 @@
    requiring attention, the timer doesn't help either. */
 #undef SPECIALIX_TIMER
 
+#ifdef SPECIALIX_TIMER
+static int sx_poll = HZ;
+#endif
+
+
+
 /* 
  * The following defines are mostly for testing purposes. But if you need
  * some nice reporting in your syslog, you can define them also.
@@ -254,11 +298,17 @@ static inline void sx_out_off(struct spe
 /* Wait for Channel Command Register ready */
 static inline void sx_wait_CCR(struct specialix_board  * bp)
 {
-	unsigned long delay;
+	unsigned long delay, flags;
+	unsigned char ccr;
 
-	for (delay = SX_CCR_TIMEOUT; delay; delay--) 
-		if (!sx_in(bp, CD186x_CCR))
+	for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+		spin_lock_irqsave(&bp->lock, flags);
+		ccr = sx_in(bp, CD186x_CCR);
+		spin_unlock_irqrestore(&bp->lock, flags);
+		if (!ccr)
 			return;
+		udelay (1);
+	}
 	
 	printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
 }
@@ -268,10 +318,17 @@ static inline void sx_wait_CCR(struct sp
 static inline void sx_wait_CCR_off(struct specialix_board  * bp)
 {
 	unsigned long delay;
+	unsigned char crr;
+	unsigned long flags;
 
-	for (delay = SX_CCR_TIMEOUT; delay; delay--) 
-		if (!sx_in_off(bp, CD186x_CCR))
+	for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+		spin_lock_irqsave(&bp->lock, flags);
+		crr = sx_in_off(bp, CD186x_CCR);
+		spin_unlock_irqrestore(&bp->lock, flags);
+		if (!crr)
 			return;
+		udelay (1);
+	}
 	
 	printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
 }
@@ -315,10 +372,11 @@ static inline void sx_long_delay(unsigne
 
 
 /* Set the IRQ using the RTS lines that run to the PAL on the board.... */
-int sx_set_irq ( struct specialix_board *bp)
+static int sx_set_irq ( struct specialix_board *bp)
 {
 	int virq;
 	int i;
+	unsigned long flags;
 
 	if (bp->flags & SX_BOARD_IS_PCI) 
 		return 1;
@@ -331,11 +389,12 @@ int sx_set_irq ( struct specialix_board 
 	default: printk (KERN_ERR "Speclialix: cannot set irq to %d.\n", bp->irq);
 	         return 0;
 	}
-
+	spin_lock_irqsave(&bp->lock, flags);
 	for (i=0;i<2;i++) {
 		sx_out(bp, CD186x_CAR, i);
 		sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
 	}
+	spin_unlock_irqrestore(&bp->lock, flags);
 	return 1;
 }
 
@@ -346,14 +405,14 @@ static int sx_init_CD186x(struct special
 	unsigned long flags;
 	int scaler;
 	int rv = 1;
-	
-	save_flags(flags); cli();
 
+	func_enter();
 	sx_wait_CCR_off(bp);			   /* Wait for CCR ready        */
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out_off(bp, CD186x_CCR, CCR_HARDRESET);      /* Reset CD186x chip          */
-	sti();
+	spin_unlock_irqrestore(&bp->lock, flags);
 	sx_long_delay(HZ/20);                      /* Delay 0.05 sec            */
-	cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out_off(bp, CD186x_GIVR, SX_ID);             /* Set ID for this chip      */
 	sx_out_off(bp, CD186x_GICR, 0);                 /* Clear all bits            */
 	sx_out_off(bp, CD186x_PILR1, SX_ACK_MINT);      /* Prio for modem intr       */
@@ -367,6 +426,7 @@ static int sx_init_CD186x(struct special
 
 	sx_out_off(bp, CD186x_PPRH, scaler >> 8);
 	sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
+	spin_unlock_irqrestore(&bp->lock, flags);
 
 	if (!sx_set_irq (bp)) {
 		/* Figure out how to pass this along... */
@@ -374,21 +434,25 @@ static int sx_init_CD186x(struct special
 		rv = 0;
 	}
 
-	restore_flags(flags);
+	func_exit();
 	return rv;
 }
 
 
-int read_cross_byte (struct specialix_board *bp, int reg, int bit)
+static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
 {
 	int i;
 	int t;
+	unsigned long flags;
 
+	spin_lock_irqsave(&bp->lock, flags);
 	for (i=0, t=0;i<8;i++) {
 		sx_out_off (bp, CD186x_CAR, i);
 		if (sx_in_off (bp, reg) & bit) 
 			t |= 1 << i;
 	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+
 	return t;
 }
 
@@ -396,15 +460,22 @@ int read_cross_byte (struct specialix_bo
 #ifdef SPECIALIX_TIMER
 void missed_irq (unsigned long data)
 {
-	if (sx_in ((struct specialix_board *)data, CD186x_SRSR) &  
+	unsigned char irq;
+	unsigned long flags;
+	struct specialix_board  *bp = (struct specialix_board *)data;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	irq = sx_in ((struct specialix_board *)data, CD186x_SRSR) &
 	                                            (SRSR_RREQint |
 	                                             SRSR_TREQint |
-	                                             SRSR_MREQint)) {
+	                                             SRSR_MREQint);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	if (irq) {
 		printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
 		sx_interrupt (((struct specialix_board *)data)->irq, 
-		              NULL, NULL);
+		              (void*)data, NULL);
 	}
-	missed_irq_timer.expires = jiffies + HZ;
+	missed_irq_timer.expires = jiffies + sx_poll;
 	add_timer (&missed_irq_timer);
 }
 #endif
@@ -422,8 +493,12 @@ static int sx_probe(struct specialix_boa
 	int rev;
 	int chip;
 
-	if (sx_check_io_range(bp)) 
+	func_enter();
+
+	if (sx_check_io_range(bp)) {
+		func_exit();
 		return 1;
+	}
 
 	/* Are the I/O ports here ? */
 	sx_out_off(bp, CD186x_PPRL, 0x5a);
@@ -438,6 +513,7 @@ static int sx_probe(struct specialix_boa
 	if ((val1 != 0x5a) || (val2 != 0xa5)) {
 		printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
 		       board_No(bp), bp->base);
+		func_exit();
 		return 1;
 	}
 
@@ -445,10 +521,9 @@ static int sx_probe(struct specialix_boa
 	   identification */
 	val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);
 	val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);
-#ifdef SPECIALIX_DEBUG
-	printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n", 
+	dprintk (SX_DEBUG_INIT, "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
 	        board_No(bp),  val1, val2);
-#endif
+
 	/* They managed to switch the bit order between the docs and
 	   the IO8+ card. The new PCI card now conforms to old docs.
 	   They changed the PCI docs to reflect the situation on the
@@ -457,6 +532,7 @@ static int sx_probe(struct specialix_boa
 	if (val1 != val2) {
 		printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
 		       board_No(bp), val2, bp->base, val1);
+		func_exit();
 		return 1;
 	}
 
@@ -473,21 +549,19 @@ static int sx_probe(struct specialix_boa
 		sx_long_delay(HZ/20);	       		
 		irqs = probe_irq_off(irqs);
 
-#if SPECIALIX_DEBUG > 2
-		printk (KERN_DEBUG "SRSR = %02x, ",  sx_in(bp, CD186x_SRSR));
-		printk (           "TRAR = %02x, ",  sx_in(bp, CD186x_TRAR));
-		printk (           "GIVR = %02x, ",  sx_in(bp, CD186x_GIVR));
-		printk (           "GICR = %02x, ",  sx_in(bp, CD186x_GICR));
-		printk (           "\n");
-#endif
+		dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
+		dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
+		dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
+		dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));
+		dprintk (SX_DEBUG_INIT, "\n");
+
 		/* Reset CD186x again      */
 		if (!sx_init_CD186x(bp)) {
 			/* Hmmm. This is dead code anyway. */
 		}
-#if SPECIALIX_DEBUG > 2
-		printk (KERN_DEBUG "val1 = %02x, val2 = %02x, val3 = %02x.\n", 
+
+		dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",
 		        val1, val2, val3); 
-#endif
 	
 	}
 	
@@ -495,6 +569,7 @@ static int sx_probe(struct specialix_boa
 	if (irqs <= 0) {
 		printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",
 		       board_No(bp), bp->base);
+		func_exit();
 		return 1;
 	}
 #endif
@@ -504,6 +579,7 @@ static int sx_probe(struct specialix_boa
 #endif
 	/* Reset CD186x again  */
 	if (!sx_init_CD186x(bp)) {
+		func_exit();
 		return -EIO;
 	}
 
@@ -528,15 +604,13 @@ static int sx_probe(struct specialix_boa
 	default:chip=-1;rev='x';
 	}
 
-#if SPECIALIX_DEBUG > 2
-	printk (KERN_DEBUG " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
-#endif
+	dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
 
 #ifdef SPECIALIX_TIMER
 	init_timer (&missed_irq_timer);
 	missed_irq_timer.function = missed_irq;
 	missed_irq_timer.data = (unsigned long) bp;
-	missed_irq_timer.expires = jiffies + HZ;
+	missed_irq_timer.expires = jiffies + sx_poll;
 	add_timer (&missed_irq_timer);
 #endif
 
@@ -545,6 +619,7 @@ static int sx_probe(struct specialix_boa
 	       bp->base, bp->irq,
 	       chip, rev);
 
+	func_exit();
 	return 0;
 }
 
@@ -555,8 +630,12 @@ static int sx_probe(struct specialix_boa
 
 static inline void sx_mark_event(struct specialix_port * port, int event)
 {
+	func_enter();
+
 	set_bit(event, &port->event);
 	schedule_work(&port->tqueue);
+
+	func_exit();
 }
 
 
@@ -564,12 +643,17 @@ static inline struct specialix_port * sx
 					       unsigned char const * what)
 {
 	unsigned char channel;
-	struct specialix_port * port;
-	
+	struct specialix_port * port = NULL;
+
 	channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
+	dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
 	if (channel < CD186x_NCH) {
 		port = &sx_port[board_No(bp) * SX_NPORT + channel];
+		dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel,  port, port->flags & ASYNC_INITIALIZED);
+
 		if (port->flags & ASYNC_INITIALIZED) {
+			dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
+			func_exit();
 			return port;
 		}
 	}
@@ -586,43 +670,51 @@ static inline void sx_receive_exc(struct
 	unsigned char status;
 	unsigned char ch;
 
-	if (!(port = sx_get_port(bp, "Receive")))
-		return;
+	func_enter();
 
-	tty = port->tty;
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-		printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",
-		       board_No(bp), port_No(port));
+	port = sx_get_port(bp, "Receive");
+	if (!port) {
+		dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+		func_exit();
 		return;
 	}
+	tty = port->tty;
+	dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n",
+		 port,  tty->flip.count, TTY_FLIPBUF_SIZE);
 	
-#ifdef SX_REPORT_OVERRUN	
 	status = sx_in(bp, CD186x_RCSR);
+
+	dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);
 	if (status & RCSR_OE) {
 		port->overrun++;
-#if SPECIALIX_DEBUG 
-		printk(KERN_DEBUG "sx%d: port %d: Overrun. Total %ld overruns.\n", 
+		dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",
 		       board_No(bp), port_No(port), port->overrun);
-#endif		
 	}
 	status &= port->mark_mask;
-#else	
-	status = sx_in(bp, CD186x_RCSR) & port->mark_mask;
-#endif	
+
+	/* This flip buffer check needs to be below the reading of the
+	   status register to reset the chip's IRQ.... */
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+		dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
+		       board_No(bp), port_No(port));
+		func_exit();
+		return;
+	}
+
 	ch = sx_in(bp, CD186x_RDR);
 	if (!status) {
+		func_exit();
 		return;
 	}
 	if (status & RCSR_TOUT) {
 		printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n", 
 		       board_No(bp), port_No(port));
+		func_exit();
 		return;
 		
 	} else if (status & RCSR_BREAK) {
-#ifdef SPECIALIX_DEBUG
-		printk(KERN_DEBUG "sx%d: port %d: Handling break...\n",
+		dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
 		       board_No(bp), port_No(port));
-#endif
 		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
 		if (port->flags & ASYNC_SAK)
 			do_SAK(tty);
@@ -642,6 +734,8 @@ static inline void sx_receive_exc(struct
 	*tty->flip.char_buf_ptr++ = ch;
 	tty->flip.count++;
 	schedule_delayed_work(&tty->flip.work, 1);
+
+	func_exit();
 }
 
 
@@ -650,17 +744,19 @@ static inline void sx_receive(struct spe
 	struct specialix_port *port;
 	struct tty_struct *tty;
 	unsigned char count;
+
+	func_enter();
 	
-	if (!(port = sx_get_port(bp, "Receive")))
+	if (!(port = sx_get_port(bp, "Receive"))) {
+		dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+		func_exit();
 		return;
-	
+	}
 	tty = port->tty;
 	
 	count = sx_in(bp, CD186x_RDCR);
-	
-#ifdef SX_REPORT_FIFO
+	dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
 	port->hits[count > 8 ? 9 : count]++;
-#endif	
 	
 	while (count--) {
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -673,6 +769,8 @@ static inline void sx_receive(struct spe
 		tty->flip.count++;
 	}
 	schedule_delayed_work(&tty->flip.work, 1);
+
+	func_exit();
 }
 
 
@@ -681,11 +779,13 @@ static inline void sx_transmit(struct sp
 	struct specialix_port *port;
 	struct tty_struct *tty;
 	unsigned char count;
-	
-	
-	if (!(port = sx_get_port(bp, "Transmit")))
+
+	func_enter();
+	if (!(port = sx_get_port(bp, "Transmit"))) {
+		func_exit();
 		return;
-	
+	}
+	dprintk (SX_DEBUG_TX, "port: %p\n", port);
 	tty = port->tty;
 	
 	if (port->IER & IER_TXEMPTY) {
@@ -693,6 +793,7 @@ static inline void sx_transmit(struct sp
 		sx_out(bp, CD186x_CAR, port_No(port));
 		port->IER &= ~IER_TXEMPTY;
 		sx_out(bp, CD186x_IER, port->IER);
+		func_exit();
 		return;
 	}
 	
@@ -701,6 +802,7 @@ static inline void sx_transmit(struct sp
 		sx_out(bp, CD186x_CAR, port_No(port));
 		port->IER &= ~IER_TXRDY;
 		sx_out(bp, CD186x_IER, port->IER);
+		func_exit();
 		return;
 	}
 	
@@ -725,6 +827,8 @@ static inline void sx_transmit(struct sp
 			sx_out(bp, CD186x_CCR, CCR_CORCHG2);
 			port->break_length = 0;
 		}
+
+		func_exit();
 		return;
 	}
 	
@@ -743,6 +847,8 @@ static inline void sx_transmit(struct sp
 	}
 	if (port->xmit_cnt <= port->wakeup_chars)
 		sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+
+	func_exit();
 }
 
 
@@ -751,10 +857,9 @@ static inline void sx_check_modem(struct
 	struct specialix_port *port;
 	struct tty_struct *tty;
 	unsigned char mcr;
+	int msvr_cd;
 
-#ifdef SPECIALIX_DEBUG
-	printk (KERN_DEBUG "Modem intr. ");
-#endif
+	dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");
 	if (!(port = sx_get_port(bp, "Modem")))
 		return;
 	
@@ -764,18 +869,13 @@ static inline void sx_check_modem(struct
 	printk ("mcr = %02x.\n", mcr);
 
 	if ((mcr & MCR_CDCHG)) {
-#ifdef SPECIALIX_DEBUG 
-		printk (KERN_DEBUG "CD just changed... ");
-#endif
-		if (sx_in(bp, CD186x_MSVR) & MSVR_CD) {
-#ifdef SPECIALIX_DEBUG
-			printk ( "Waking up guys in open.\n");
-#endif
+		dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");
+		msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
+		if (msvr_cd) {
+			dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
 			wake_up_interruptible(&port->open_wait);
 		} else {
-#ifdef SPECIALIX_DEBUG
-			printk ( "Sending HUP.\n");
-#endif
+			dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
 			schedule_work(&port->tqueue_hangup);
 		}
 	}
@@ -820,13 +920,18 @@ static irqreturn_t sx_interrupt(int irq,
 	struct specialix_board *bp;
 	unsigned long loop = 0;
 	int saved_reg;
+	unsigned long flags;
+
+	func_enter();
 
 	bp = dev_id;
-	
+	spin_lock_irqsave(&bp->lock, flags);
+
+	dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
 	if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
-#ifdef SPECIALIX_DEBUG 
-		printk (KERN_DEBUG "sx: False interrupt. irq %d.\n", irq);
-#endif
+		dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
+		spin_unlock_irqrestore(&bp->lock, flags);
+		func_exit();
 		return IRQ_NONE;
 	}
 
@@ -844,8 +949,8 @@ static irqreturn_t sx_interrupt(int irq,
 			else if (ack == (SX_ID | GIVR_IT_REXC))
 				sx_receive_exc(bp);
 			else
-				printk(KERN_ERR "sx%d: Bad receive ack 0x%02x.\n",
-				       board_No(bp), ack);
+				printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
+				       board_No(bp), status, ack);
 		
 		} else if (status & SRSR_TREQint) {
 			ack = sx_in(bp, CD186x_TRAR);
@@ -853,16 +958,16 @@ static irqreturn_t sx_interrupt(int irq,
 			if (ack == (SX_ID | GIVR_IT_TX))
 				sx_transmit(bp);
 			else
-				printk(KERN_ERR "sx%d: Bad transmit ack 0x%02x.\n",
-				       board_No(bp), ack);
+				printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
+				       board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));
 		} else if (status & SRSR_MREQint) {
 			ack = sx_in(bp, CD186x_MRAR);
 
 			if (ack == (SX_ID | GIVR_IT_MODEM)) 
 				sx_check_modem(bp);
 			else
-				printk(KERN_ERR "sx%d: Bad modem ack 0x%02x.\n",
-				       board_No(bp), ack);
+				printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
+				       board_No(bp), status, ack);
 		
 		} 
 
@@ -870,6 +975,8 @@ static irqreturn_t sx_interrupt(int irq,
 	}
 	bp->reg = saved_reg;
 	outb (bp->reg, bp->base + SX_ADDR_REG);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	func_exit();
 	return IRQ_HANDLED;
 }
 
@@ -878,23 +985,39 @@ static irqreturn_t sx_interrupt(int irq,
  *  Routines for open & close processing.
  */
 
-void turn_ints_off (struct specialix_board *bp)
+static void turn_ints_off (struct specialix_board *bp)
 {
+	unsigned long flags;
+
+	func_enter();
 	if (bp->flags & SX_BOARD_IS_PCI) {
 		/* This was intended for enabeling the interrupt on the
 		 * PCI card. However it seems that it's already enabled
 		 * and as PCI interrupts can be shared, there is no real
 		 * reason to have to turn it off. */
 	}
+
+	spin_lock_irqsave(&bp->lock, flags);
 	(void) sx_in_off (bp, 0); /* Turn off interrupts. */
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	func_exit();
 }
 
-void turn_ints_on (struct specialix_board *bp)
+static void turn_ints_on (struct specialix_board *bp)
 {
+	unsigned long flags;
+
+	func_enter();
+
 	if (bp->flags & SX_BOARD_IS_PCI) {
 		/* play with the PCI chip. See comment above. */
 	}
+	spin_lock_irqsave(&bp->lock, flags);
 	(void) sx_in (bp, 0); /* Turn ON interrupts. */
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	func_exit();
 }
 
 
@@ -924,18 +1047,23 @@ static inline int sx_setup_board(struct 
 /* Called with disabled interrupts */
 static inline void sx_shutdown_board(struct specialix_board *bp)
 {
-	if (!(bp->flags & SX_BOARD_ACTIVE))
+	func_enter();
+
+	if (!(bp->flags & SX_BOARD_ACTIVE)) {
+		func_exit();
 		return;
-	
+	}
+
 	bp->flags &= ~SX_BOARD_ACTIVE;
 	
-#if SPECIALIX_DEBUG > 2
-	printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
-#endif
+	dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
+		 bp->irq, board_No (bp));
 	free_irq(bp->irq, bp);
 
 	turn_ints_off (bp);
 
+
+	func_exit();
 }
 
 
@@ -951,13 +1079,19 @@ static void sx_change_speed(struct speci
 	unsigned char cor1 = 0, cor3 = 0;
 	unsigned char mcor1 = 0, mcor2 = 0;
 	static unsigned long again;
-	
-	if (!(tty = port->tty) || !tty->termios)
+	unsigned long flags;
+
+	func_enter();
+
+	if (!(tty = port->tty) || !tty->termios) {
+		func_exit();
 		return;
+	}
 
 	port->IER  = 0;
 	port->COR2 = 0;
 	/* Select port on the board */
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 
 	/* The Specialix board doens't implement the RTS lines.
@@ -966,9 +1100,8 @@ static void sx_change_speed(struct speci
 		port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
 	else
 		port->MSVR =  (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
-#ifdef DEBUG_SPECIALIX
-	printk (KERN_DEBUG "sx: got MSVR=%02x.\n", port->MSVR);
-#endif
+	spin_unlock_irqrestore(&bp->lock, flags);
+	dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
 	baud = C_BAUD(tty);
 	
 	if (baud & CBAUDEX) {
@@ -988,17 +1121,15 @@ static void sx_change_speed(struct speci
 	
 	if (!baud_table[baud]) {
 		/* Drop DTR & exit */
-#ifdef SPECIALIX_DEBUG
-		printk (KERN_DEBUG "Dropping DTR...  Hmm....\n");
-#endif
+		dprintk (SX_DEBUG_TERMIOS, "Dropping DTR...  Hmm....\n");
 		if (!SX_CRTSCTS (tty)) {
 			port -> MSVR &= ~ MSVR_DTR;
+			spin_lock_irqsave(&bp->lock, flags);
 			sx_out(bp, CD186x_MSVR, port->MSVR );
+			spin_unlock_irqrestore(&bp->lock, flags);
 		} 
-#ifdef DEBUG_SPECIALIX
 		else
-			printk (KERN_DEBUG "Can't drop DTR: no DTR.\n");
-#endif
+			dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
 		return;
 	} else {
 		/* Set DTR on */
@@ -1037,12 +1168,12 @@ static void sx_change_speed(struct speci
 			        port_No (port), tmp);
 		}
 	}
-
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff); 
 	sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff); 
 	sx_out(bp, CD186x_RBPRL, tmp & 0xff); 
 	sx_out(bp, CD186x_TBPRL, tmp & 0xff);
-
+	spin_unlock_irqrestore(&bp->lock, flags);
 	if (port->custom_divisor) {
 		baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
 		baud = ( baud + 5 ) / 10;
@@ -1057,8 +1188,9 @@ static void sx_change_speed(struct speci
 	/* Receiver timeout will be transmission time for 1.5 chars */
 	tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud;
 	tmp = (tmp > 0xff) ? 0xff : tmp;
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_RTPR, tmp);
-	
+	spin_unlock_irqrestore(&bp->lock, flags);
 	switch (C_CSIZE(tty)) {
 	 case CS5:
 		cor1 |= COR1_5BITS;
@@ -1105,7 +1237,9 @@ static void sx_change_speed(struct speci
 		port->IER |= IER_DSR | IER_CTS;
 		mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
 		mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
+		spin_lock_irqsave(&bp->lock, flags);
 		tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR));
+		spin_unlock_irqrestore(&bp->lock, flags);
 #else
 		port->COR2 |= COR2_CTSAE; 
 #endif
@@ -1117,10 +1251,12 @@ static void sx_change_speed(struct speci
 		cor3 |= (COR3_FCT | COR3_SCDE);
 		if (I_IXANY(tty))
 			port->COR2 |= COR2_IXM;
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_SCHR1, START_CHAR(tty));
 		sx_out(bp, CD186x_SCHR2, STOP_CHAR(tty));
 		sx_out(bp, CD186x_SCHR3, START_CHAR(tty));
 		sx_out(bp, CD186x_SCHR4, STOP_CHAR(tty));
+		spin_unlock_irqrestore(&bp->lock, flags);
 	}
 	if (!C_CLOCAL(tty)) {
 		/* Enable CD check */
@@ -1134,27 +1270,33 @@ static void sx_change_speed(struct speci
 		port->IER |= IER_RXD;
 	
 	/* Set input FIFO size (1-8 bytes) */
-	cor3 |= SPECIALIX_RXFIFO; 
+	cor3 |= sx_rxfifo;
 	/* Setting up CD186x channel registers */
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_COR1, cor1);
 	sx_out(bp, CD186x_COR2, port->COR2);
 	sx_out(bp, CD186x_COR3, cor3);
+	spin_unlock_irqrestore(&bp->lock, flags);
 	/* Make CD186x know about registers change */
 	sx_wait_CCR(bp);
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
 	/* Setting up modem option registers */
-#ifdef DEBUG_SPECIALIX
-	printk ("Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
-#endif
+	dprintk (SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
 	sx_out(bp, CD186x_MCOR1, mcor1);
 	sx_out(bp, CD186x_MCOR2, mcor2);
+	spin_unlock_irqrestore(&bp->lock, flags);
 	/* Enable CD186x transmitter & receiver */
 	sx_wait_CCR(bp);
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN);
 	/* Enable interrupts */
 	sx_out(bp, CD186x_IER, port->IER);
 	/* And finally set the modem lines... */
 	sx_out(bp, CD186x_MSVR, port->MSVR);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1162,37 +1304,44 @@ static void sx_change_speed(struct speci
 static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port)
 {
 	unsigned long flags;
-	
-	if (port->flags & ASYNC_INITIALIZED)
+
+	func_enter();
+
+	if (port->flags & ASYNC_INITIALIZED) {
+		func_exit();
 		return 0;
+	}
 	
 	if (!port->xmit_buf) {
 		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 		
-		if (!(tmp = get_zeroed_page(GFP_KERNEL)))
+		if (!(tmp = get_zeroed_page(GFP_KERNEL))) {
+			func_exit();
 			return -ENOMEM;
+		}
 
 		if (port->xmit_buf) {
 			free_page(tmp);
+			func_exit();
 			return -ERESTARTSYS;
 		}
 		port->xmit_buf = (unsigned char *) tmp;
 	}
 		
-	save_flags(flags); cli();
-		
+	spin_lock_irqsave(&port->lock, flags);
+
 	if (port->tty) 
 		clear_bit(TTY_IO_ERROR, &port->tty->flags);
-		
-	if (port->count == 1) 
-		bp->count++;
-		
+
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	sx_change_speed(bp, port);
 	port->flags |= ASYNC_INITIALIZED;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
 		
-	restore_flags(flags);
+	func_exit();
 	return 0;
 }
 
@@ -1201,62 +1350,54 @@ static int sx_setup_port(struct speciali
 static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *port)
 {
 	struct tty_struct *tty;
+	int i;
+	unsigned long flags;
 	
-	if (!(port->flags & ASYNC_INITIALIZED)) 
+	func_enter();
+
+	if (!(port->flags & ASYNC_INITIALIZED)) {
+		func_exit();
 		return;
+	}
 	
-#ifdef SX_REPORT_OVERRUN
-	printk(KERN_INFO "sx%d: port %d: Total %ld overruns were detected.\n",
-	       board_No(bp), port_No(port), port->overrun);
-#endif	
-#ifdef SX_REPORT_FIFO
-	{
-		int i;
-		
-		printk(KERN_INFO "sx%d: port %d: FIFO hits [ ",
-		       board_No(bp), port_No(port));
+	if (sx_debug & SX_DEBUG_FIFO) {
+		dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ",
+			board_No(bp), port_No(port), port->overrun);
 		for (i = 0; i < 10; i++) {
-			printk("%ld ", port->hits[i]);
+			dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
 		}
-		printk("].\n");
+		dprintk(SX_DEBUG_FIFO, "].\n");
 	}
-#endif	
+
 	if (port->xmit_buf) {
 		free_page((unsigned long) port->xmit_buf);
 		port->xmit_buf = NULL;
 	}
 
 	/* Select port */
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 
 	if (!(tty = port->tty) || C_HUPCL(tty)) {
 		/* Drop DTR */
 		sx_out(bp, CD186x_MSVDTR, 0);
 	}
-	
+	spin_unlock_irqrestore(&bp->lock, flags);
 	/* Reset port */
 	sx_wait_CCR(bp);
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CCR, CCR_SOFTRESET);
 	/* Disable all interrupts from this port */
 	port->IER = 0;
 	sx_out(bp, CD186x_IER, port->IER);
-	
+	spin_unlock_irqrestore(&bp->lock, flags);
 	if (tty)
 		set_bit(TTY_IO_ERROR, &tty->flags);
 	port->flags &= ~ASYNC_INITIALIZED;
 	
-	if (--bp->count < 0) {
-		printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d\n",
-		       board_No(bp), bp->count);
-		bp->count = 0;
-	}
-	
-	/*
-	 * If this is the last opened port on the board
-	 * shutdown whole board
-	 */
 	if (!bp->count) 
 		sx_shutdown_board(bp);
+	func_exit();
 }
 
 	
@@ -1268,6 +1409,9 @@ static int block_til_ready(struct tty_st
 	int    retval;
 	int    do_clocal = 0;
 	int    CD;
+	unsigned long flags;
+
+	func_enter();
 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -1275,10 +1419,13 @@ static int block_til_ready(struct tty_st
 	 */
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
 		interruptible_sleep_on(&port->close_wait);
-		if (port->flags & ASYNC_HUP_NOTIFY)
+		if (port->flags & ASYNC_HUP_NOTIFY) {
+			func_exit();
 			return -EAGAIN;
-		else
+		} else {
+			func_exit();
 			return -ERESTARTSYS;
+		}
 	}
 	
 	/*
@@ -1288,6 +1435,7 @@ static int block_til_ready(struct tty_st
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
 		port->flags |= ASYNC_NORMAL_ACTIVE;
+		func_exit();
 		return 0;
 	}
 
@@ -1303,13 +1451,14 @@ static int block_til_ready(struct tty_st
 	 */
 	retval = 0;
 	add_wait_queue(&port->open_wait, &wait);
-	cli();
-	if (!tty_hung_up_p(filp))
+	spin_lock_irqsave(&port->lock, flags);
+	if (!tty_hung_up_p(filp)) {
 		port->count--;
-	sti();
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
 	port->blocked_open++;
 	while (1) {
-		cli();
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CAR, port_No(port));
 		CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
 		if (SX_CRTSCTS (tty)) {
@@ -1320,8 +1469,8 @@ static int block_til_ready(struct tty_st
 			/* Activate DTR */
 			port->MSVR |= MSVR_DTR;
 			sx_out (bp, CD186x_MSVR, port->MSVR);
-		} 
-		sti();
+		}
+		spin_unlock_irqrestore(&bp->lock, flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
 		    !(port->flags & ASYNC_INITIALIZED)) {
@@ -1340,15 +1489,22 @@ static int block_til_ready(struct tty_st
 		}
 		schedule();
 	}
-	current->state = TASK_RUNNING;
+
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
+	spin_lock_irqsave(&port->lock, flags);
+	if (!tty_hung_up_p(filp)) {
 		port->count++;
+	}
 	port->blocked_open--;
-	if (retval)
+	spin_unlock_irqrestore(&port->lock, flags);
+	if (retval) {
+		func_exit();
 		return retval;
-	
+	}
+
 	port->flags |= ASYNC_NORMAL_ACTIVE;
+	func_exit();
 	return 0;
 }	
 
@@ -1359,36 +1515,55 @@ static int sx_open(struct tty_struct * t
 	int error;
 	struct specialix_port * port;
 	struct specialix_board * bp;
-	
+	int i;
+	unsigned long flags;
+
+	func_enter();
+
 	board = SX_BOARD(tty->index);
 
-	if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT))
+	if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) {
+		func_exit();
 		return -ENODEV;
+	}
 	
 	bp = &sx_board[board];
 	port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
+	port->overrun = 0;
+	for (i = 0; i < 10; i++)
+		port->hits[i]=0;
 
-#ifdef DEBUG_SPECIALIX
-	printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n", 
+	dprintk (SX_DEBUG_OPEN, "Board = %d, bp = %p, port = %p, portno = %d.\n",
 	        board, bp, port, SX_PORT(tty->index));
-#endif
 
-	if (sx_paranoia_check(port, tty->name, "sx_open"))
+	if (sx_paranoia_check(port, tty->name, "sx_open")) {
+		func_enter();
 		return -ENODEV;
+	}
 
-	if ((error = sx_setup_board(bp)))
+	if ((error = sx_setup_board(bp))) {
+		func_exit();
 		return error;
+	}
 
+	spin_lock_irqsave(&bp->lock, flags);
 	port->count++;
+	bp->count++;
 	tty->driver_data = port;
 	port->tty = tty;
+	spin_unlock_irqrestore(&bp->lock, flags);
 
-	if ((error = sx_setup_port(bp, port))) 
+	if ((error = sx_setup_port(bp, port))) {
+		func_enter();
 		return error;
+	}
 	
-	if ((error = block_til_ready(tty, filp, port)))
+	if ((error = block_til_ready(tty, filp, port))) {
+		func_enter();
 		return error;
+	}
 
+	func_exit();
 	return 0;
 }
 
@@ -1400,12 +1575,16 @@ static void sx_close(struct tty_struct *
 	unsigned long flags;
 	unsigned long timeout;
 	
-	if (!port || sx_paranoia_check(port, tty->name, "close"))
+	func_enter();
+	if (!port || sx_paranoia_check(port, tty->name, "close")) {
+		func_exit();
 		return;
-	
-	save_flags(flags); cli();
+	}
+	spin_lock_irqsave(&port->lock, flags);
+
 	if (tty_hung_up_p(filp)) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&port->lock, flags);
+		func_exit();
 		return;
 	}
 	
@@ -1416,13 +1595,14 @@ static void sx_close(struct tty_struct *
 		       board_No(bp), port->count);
 		port->count = 1;
 	}
-	if (--port->count < 0) {
-		printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
-		       board_No(bp), port_No(port), port->count);
-		port->count = 0;
-	}
-	if (port->count) {
-		restore_flags(flags);
+
+	if (port->count > 1) {
+		port->count--;
+		bp->count--;
+
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		func_exit();
 		return;
 	}
 	port->flags |= ASYNC_CLOSING;
@@ -1431,20 +1611,26 @@ static void sx_close(struct tty_struct *
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+	spin_unlock_irqrestore(&port->lock, flags);
+	dprintk (SX_DEBUG_OPEN, "Closing\n");
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
 		tty_wait_until_sent(tty, port->closing_wait);
+	}
 	/*
 	 * 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.
 	 */
+	dprintk (SX_DEBUG_OPEN, "Closed\n");
 	port->IER &= ~IER_RXD;
 	if (port->flags & ASYNC_INITIALIZED) {
 		port->IER &= ~IER_TXRDY;
 		port->IER |= IER_TXEMPTY;
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CAR, port_No(port));
 		sx_out(bp, CD186x_IER, port->IER);
+		spin_unlock_irqrestore(&bp->lock, flags);
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -1452,6 +1638,7 @@ static void sx_close(struct tty_struct *
 		 */
 		timeout = jiffies+HZ;
 		while(port->IER & IER_TXEMPTY) {
+			set_current_state (TASK_INTERRUPTIBLE);
 			msleep_interruptible(jiffies_to_msecs(port->timeout));
 			if (time_after(jiffies, timeout)) {
 				printk (KERN_INFO "Timeout waiting for close\n");
@@ -1460,13 +1647,27 @@ static void sx_close(struct tty_struct *
 		}
 
 	}
+
+	if (--bp->count < 0) {
+		printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
+		       board_No(bp), bp->count, tty->index);
+		bp->count = 0;
+	}
+	if (--port->count < 0) {
+		printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
+		       board_No(bp), port_No(port), port->count);
+		port->count = 0;
+	}
+
 	sx_shutdown_port(bp, port);
 	if (tty->driver->flush_buffer)
 		tty->driver->flush_buffer(tty);
 	tty_ldisc_flush(tty);
+	spin_lock_irqsave(&port->lock, flags);
 	tty->closing = 0;
 	port->event = 0;
 	port->tty = NULL;
+	spin_unlock_irqrestore(&port->lock, flags);
 	if (port->blocked_open) {
 		if (port->close_delay) {
 			msleep_interruptible(jiffies_to_msecs(port->close_delay));
@@ -1475,7 +1676,8 @@ static void sx_close(struct tty_struct *
 	}
 	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
-	restore_flags(flags);
+
+	func_exit();
 }
 
 
@@ -1486,42 +1688,48 @@ static int sx_write(struct tty_struct * 
 	struct specialix_board *bp;
 	int c, total = 0;
 	unsigned long flags;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_write"))
+
+	func_enter();
+	if (sx_paranoia_check(port, tty->name, "sx_write")) {
+		func_exit();
 		return 0;
+	}
 	
 	bp = port_Board(port);
 
-	if (!tty || !port->xmit_buf || !tmp_buf)
+	if (!tty || !port->xmit_buf || !tmp_buf) {
+		func_exit();
 		return 0;
+	}
 
-	save_flags(flags);
 	while (1) {
-		cli();
+		spin_lock_irqsave(&port->lock, flags);
 		c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
 				   SERIAL_XMIT_SIZE - port->xmit_head));
 		if (c <= 0) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&port->lock, flags);
 			break;
 		}
 		memcpy(port->xmit_buf + port->xmit_head, buf, c);
 		port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
 		port->xmit_cnt += c;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&port->lock, flags);
 
 		buf += c;
 		count -= c;
 		total += c;
 	}
 
-	cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
 	    !(port->IER & IER_TXRDY)) {
 		port->IER |= IER_TXRDY;
 		sx_out(bp, CD186x_CAR, port_No(port));
 		sx_out(bp, CD186x_IER, port->IER);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	func_exit();
+
 	return total;
 }
 
@@ -1530,24 +1738,36 @@ static void sx_put_char(struct tty_struc
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	unsigned long flags;
+	struct specialix_board  * bp;
 
-	if (sx_paranoia_check(port, tty->name, "sx_put_char"))
-		return;
+	func_enter();
 
-	if (!tty || !port->xmit_buf)
+	if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
+		func_exit();
 		return;
-
-	save_flags(flags); cli();
-	
-	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-		restore_flags(flags);
+	}
+	dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
+	if (!tty || !port->xmit_buf) {
+		func_exit();
 		return;
 	}
+	bp = port_Board(port);
+	spin_lock_irqsave(&port->lock, flags);
 
+	dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf);
+	if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) {
+		spin_unlock_irqrestore(&port->lock, flags);
+		dprintk (SX_DEBUG_TX, "Exit size\n");
+		func_exit();
+		return;
+	}
+	dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
 	port->xmit_buf[port->xmit_head++] = ch;
 	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
 	port->xmit_cnt++;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1555,19 +1775,26 @@ static void sx_flush_chars(struct tty_st
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	unsigned long flags;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_flush_chars"))
+	struct specialix_board  * bp = port_Board(port);
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) {
+		func_exit();
 		return;
-	
+	}
 	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !port->xmit_buf)
+	    !port->xmit_buf) {
+		func_exit();
 		return;
-
-	save_flags(flags); cli();
+	}
+	spin_lock_irqsave(&bp->lock, flags);
 	port->IER |= IER_TXRDY;
 	sx_out(port_Board(port), CD186x_CAR, port_No(port));
 	sx_out(port_Board(port), CD186x_IER, port->IER);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1575,13 +1802,19 @@ static int sx_write_room(struct tty_stru
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	int	ret;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_write_room"))
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_write_room")) {
+		func_exit();
 		return 0;
+	}
 
 	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
 	if (ret < 0)
 		ret = 0;
+
+	func_exit();
 	return ret;
 }
 
@@ -1589,10 +1822,14 @@ static int sx_write_room(struct tty_stru
 static int sx_chars_in_buffer(struct tty_struct *tty)
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer"))
-		return 0;
+
+	func_enter();
 	
+	if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) {
+		func_exit();
+		return 0;
+	}
+	func_exit();
 	return port->xmit_cnt;
 }
 
@@ -1601,16 +1838,22 @@ static void sx_flush_buffer(struct tty_s
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	unsigned long flags;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_flush_buffer"))
+	struct specialix_board  * bp;
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+		func_exit();
 		return;
+	}
 
-	save_flags(flags); cli();
+	bp = port_Board(port);
+	spin_lock_irqsave(&port->lock, flags);
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-	restore_flags(flags);
-	
+	spin_unlock_irqrestore(&port->lock, flags);
 	tty_wakeup(tty);
-	wake_up_interruptible(&tty->write_wait);
+
+	func_exit();
 }
 
 
@@ -1622,19 +1865,21 @@ static int sx_tiocmget(struct tty_struct
 	unsigned int result;
 	unsigned long flags;
 
-	if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+		func_exit();
 		return -ENODEV;
+	}
 
 	bp = port_Board(port);
-	save_flags(flags); cli();
+	spin_lock_irqsave (&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 	status = sx_in(bp, CD186x_MSVR);
-	restore_flags(flags);
-#ifdef DEBUG_SPECIALIX
-	printk (KERN_DEBUG "Got msvr[%d] = %02x, car = %d.\n", 
+	spin_unlock_irqrestore(&bp->lock, flags);
+	dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
 		port_No(port), status, sx_in (bp, CD186x_CAR));
-	printk (KERN_DEBUG "sx_port = %p, port = %p\n", sx_port, port);
-#endif
+	dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
 	if (SX_CRTSCTS(port->tty)) {
 		result  = /*   (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ 
 		          |   ((status & MSVR_DTR) ? TIOCM_RTS : 0)
@@ -1649,6 +1894,8 @@ static int sx_tiocmget(struct tty_struct
 		          |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);
 	}
 
+	func_exit();
+
 	return result;
 }
 
@@ -1660,12 +1907,16 @@ static int sx_tiocmset(struct tty_struct
 	unsigned long flags;
 	struct specialix_board *bp;
 
-	if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+		func_exit();
 		return -ENODEV;
+	}
 
 	bp = port_Board(port);
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&port->lock, flags);
    /*	if (set & TIOCM_RTS)
 		port->MSVR |= MSVR_RTS; */
    /*   if (set & TIOCM_DTR)
@@ -1690,10 +1941,12 @@ static int sx_tiocmset(struct tty_struct
 		if (clear & TIOCM_DTR)
 			port->MSVR &= ~MSVR_DTR;
 	}
-
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 	sx_out(bp, CD186x_MSVR, port->MSVR);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+	func_exit();
 	return 0;
 }
 
@@ -1703,17 +1956,25 @@ static inline void sx_send_break(struct 
 	struct specialix_board *bp = port_Board(port);
 	unsigned long flags;
 	
-	save_flags(flags); cli();
+	func_enter();
+
+	spin_lock_irqsave (&port->lock, flags);
 	port->break_length = SPECIALIX_TPS / HZ * length;
 	port->COR2 |= COR2_ETC;
 	port->IER  |= IER_TXRDY;
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 	sx_out(bp, CD186x_COR2, port->COR2);
 	sx_out(bp, CD186x_IER, port->IER);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	spin_unlock_irqrestore (&port->lock, flags);
 	sx_wait_CCR(bp);
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CCR, CCR_CORCHG2);
+	spin_unlock_irqrestore(&bp->lock, flags);
 	sx_wait_CCR(bp);
-	restore_flags(flags);
+
+	func_exit();
 }
 
 
@@ -1723,10 +1984,18 @@ static inline int sx_set_serial_info(str
 	struct serial_struct tmp;
 	struct specialix_board *bp = port_Board(port);
 	int change_speed;
-	unsigned long flags;
-	
-	if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+
+	func_enter();
+	/*
+	if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
+		func_exit();
 		return -EFAULT;
+	}
+	*/
+	if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
+		func_enter();
+		return -EFAULT;
+	}
 	
 #if 0	
 	if ((tmp.irq != bp->irq) ||
@@ -1735,8 +2004,10 @@ static inline int sx_set_serial_info(str
 	    (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
 	    (tmp.custom_divisor != 0) ||
 	    (tmp.xmit_fifo_size != CD186x_NFIFO) ||
-	    (tmp.flags & ~SPECIALIX_LEGAL_FLAGS))
+	    (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
+		func_exit();
 		return -EINVAL;
+	}
 #endif	
 
 	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
@@ -1747,8 +2018,10 @@ static inline int sx_set_serial_info(str
 		if ((tmp.close_delay != port->close_delay) ||
 		    (tmp.closing_wait != port->closing_wait) ||
 		    ((tmp.flags & ~ASYNC_USR_MASK) !=
-		     (port->flags & ~ASYNC_USR_MASK)))
+		     (port->flags & ~ASYNC_USR_MASK))) {
+			func_exit();
 			return -EPERM;
+		}
 		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
 		                  (tmp.flags & ASYNC_USR_MASK));
 		port->custom_divisor = tmp.custom_divisor;
@@ -1760,10 +2033,9 @@ static inline int sx_set_serial_info(str
 		port->custom_divisor = tmp.custom_divisor;
 	}
 	if (change_speed) {
-		save_flags(flags); cli();
 		sx_change_speed(bp, port);
-		restore_flags(flags);
 	}
+	func_exit();
 	return 0;
 }
 
@@ -1774,6 +2046,13 @@ static inline int sx_get_serial_info(str
 	struct serial_struct tmp;
 	struct specialix_board *bp = port_Board(port);
 	
+	func_enter();
+
+	/*
+	if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
+		return -EFAULT;
+	*/
+
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = PORT_CIRRUS;
 	tmp.line = port - sx_port;
@@ -1785,8 +2064,12 @@ static inline int sx_get_serial_info(str
 	tmp.closing_wait = port->closing_wait * HZ/100;
 	tmp.custom_divisor =  port->custom_divisor;
 	tmp.xmit_fifo_size = CD186x_NFIFO;
-	if (copy_to_user(retinfo, &tmp, sizeof(tmp)))
+	if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
+		func_exit();
 		return -EFAULT;
+	}
+
+	func_exit();
 	return 0;
 }
 
@@ -1797,44 +2080,63 @@ static int sx_ioctl(struct tty_struct * 
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	int retval;
 	void __user *argp = (void __user *)arg;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_ioctl"))
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_ioctl")) {
+		func_exit();
 		return -ENODEV;
+	}
 	
 	switch (cmd) {
 	 case TCSBRK:	/* SVID version: non-zero arg --> no break */
 		retval = tty_check_change(tty);
-		if (retval)
+		if (retval) {
+			func_exit();
 			return retval;
+		}
 		tty_wait_until_sent(tty, 0);
 		if (!arg)
 			sx_send_break(port, HZ/4);	/* 1/4 second */
 		return 0;
 	 case TCSBRKP:	/* support for POSIX tcsendbreak() */
 		retval = tty_check_change(tty);
-		if (retval)
+		if (retval) {
+			func_exit();
 			return retval;
+		}
 		tty_wait_until_sent(tty, 0);
 		sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
+		func_exit();
 		return 0;
 	 case TIOCGSOFTCAR:
-		if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp))
-			return -EFAULT;
+		 if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
+			 func_exit();
+			 return -EFAULT;
+		 }
+		 func_exit();
 		return 0;
 	 case TIOCSSOFTCAR:
-		if (get_user(arg, (unsigned long __user *) argp))
-			return -EFAULT;
+		 if (get_user(arg, (unsigned long __user *) argp)) {
+			 func_exit();
+			 return -EFAULT;
+		 }
 		tty->termios->c_cflag =
 			((tty->termios->c_cflag & ~CLOCAL) |
 			(arg ? CLOCAL : 0));
+		func_exit();
 		return 0;
-	 case TIOCGSERIAL:	
+	 case TIOCGSERIAL:
+		 func_exit();
 		return sx_get_serial_info(port, argp);
 	 case TIOCSSERIAL:	
+		 func_exit();
 		return sx_set_serial_info(port, argp);
 	 default:
+		 func_exit();
 		return -ENOIOCTLCMD;
 	}
+	func_exit();
 	return 0;
 }
 
@@ -1844,14 +2146,16 @@ static void sx_throttle(struct tty_struc
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board *bp;
 	unsigned long flags;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_throttle"))
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_throttle")) {
+		func_exit();
 		return;
+	}
 	
 	bp = port_Board(port);
 	
-	save_flags(flags); cli();
-
 	/* Use DTR instead of RTS ! */
 	if (SX_CRTSCTS (tty)) 
 		port->MSVR &= ~MSVR_DTR;
@@ -1863,14 +2167,22 @@ static void sx_throttle(struct tty_struc
 		printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",
 	                 port_No (port));
 	}
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
+	spin_unlock_irqrestore(&bp->lock, flags);
 	if (I_IXOFF(tty)) {
+		spin_unlock_irqrestore(&bp->lock, flags);
 		sx_wait_CCR(bp);
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CCR, CCR_SSCH2);
+		spin_unlock_irqrestore(&bp->lock, flags);
 		sx_wait_CCR(bp);
 	}
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_MSVR, port->MSVR);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1879,26 +2191,39 @@ static void sx_unthrottle(struct tty_str
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board *bp;
 	unsigned long flags;
+
+	func_enter();
 				
-	if (sx_paranoia_check(port, tty->name, "sx_unthrottle"))
+	if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {
+		func_exit();
 		return;
+	}
 	
 	bp = port_Board(port);
 	
-	save_flags(flags); cli();
+	spin_lock_irqsave(&port->lock, flags);
 	/* XXXX Use DTR INSTEAD???? */
 	if (SX_CRTSCTS(tty)) {
 		port->MSVR |= MSVR_DTR;
 	} /* Else clause: see remark in "sx_throttle"... */
-
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
+	spin_unlock_irqrestore(&bp->lock, flags);
 	if (I_IXOFF(tty)) {
+		spin_unlock_irqrestore(&port->lock, flags);
 		sx_wait_CCR(bp);
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CCR, CCR_SSCH1);
+		spin_unlock_irqrestore(&bp->lock, flags);
 		sx_wait_CCR(bp);
+		spin_lock_irqsave(&port->lock, flags);
 	}
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_MSVR, port->MSVR);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1907,17 +2232,25 @@ static void sx_stop(struct tty_struct * 
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board *bp;
 	unsigned long flags;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_stop"))
-		return;
+
+	func_enter();
 	
+	if (sx_paranoia_check(port, tty->name, "sx_stop")) {
+		func_exit();
+		return;
+	}
+
 	bp = port_Board(port);
 	
-	save_flags(flags); cli();
+	spin_lock_irqsave(&port->lock, flags);
 	port->IER &= ~IER_TXRDY;
+	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 	sx_out(bp, CD186x_IER, port->IER);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1926,19 +2259,27 @@ static void sx_start(struct tty_struct *
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board *bp;
 	unsigned long flags;
+
+	func_enter();
 				
-	if (sx_paranoia_check(port, tty->name, "sx_start"))
+	if (sx_paranoia_check(port, tty->name, "sx_start")) {
+		func_exit();
 		return;
+	}
 	
 	bp = port_Board(port);
 	
-	save_flags(flags); cli();
+	spin_lock_irqsave(&port->lock, flags);
 	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
 		port->IER |= IER_TXRDY;
+		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CAR, port_No(port));
 		sx_out(bp, CD186x_IER, port->IER);
+		spin_unlock_irqrestore(&bp->lock, flags);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	func_exit();
 }
 
 
@@ -1956,9 +2297,13 @@ static void do_sx_hangup(void *private_)
 	struct specialix_port	*port = (struct specialix_port *) private_;
 	struct tty_struct	*tty;
 	
+	func_enter();
+
 	tty = port->tty;
 	if (tty)
 		tty_hangup(tty);	/* FIXME: module removal race here */
+
+	func_exit();
 }
 
 
@@ -1966,18 +2311,33 @@ static void sx_hangup(struct tty_struct 
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board *bp;
-				
-	if (sx_paranoia_check(port, tty->name, "sx_hangup"))
+	unsigned long flags;
+
+	func_enter();
+
+	if (sx_paranoia_check(port, tty->name, "sx_hangup")) {
+		func_exit();
 		return;
+	}
 	
 	bp = port_Board(port);
 	
 	sx_shutdown_port(bp, port);
+	spin_lock_irqsave(&port->lock, flags);
 	port->event = 0;
+	bp->count -= port->count;
+	if (bp->count < 0) {
+		printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
+			board_No(bp), bp->count, tty->index);
+		bp->count = 0;
+	}
 	port->count = 0;
 	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->tty = NULL;
+	spin_unlock_irqrestore(&port->lock, flags);
 	wake_up_interruptible(&port->open_wait);
+
+	func_exit();
 }
 
 
@@ -1985,6 +2345,7 @@ static void sx_set_termios(struct tty_st
 {
 	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	unsigned long flags;
+	struct specialix_board  * bp;
 				
 	if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
 		return;
@@ -1993,9 +2354,10 @@ static void sx_set_termios(struct tty_st
 	    tty->termios->c_iflag == old_termios->c_iflag)
 		return;
 
-	save_flags(flags); cli();
+	bp = port_Board(port);
+	spin_lock_irqsave(&port->lock, flags);
 	sx_change_speed(port_Board(port), port);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
@@ -2009,12 +2371,20 @@ static void do_softint(void *private_)
 {
 	struct specialix_port	*port = (struct specialix_port *) private_;
 	struct tty_struct	*tty;
-	
-	if(!(tty = port->tty)) 
+
+	func_enter();
+
+	if(!(tty = port->tty)) {
+		func_exit();
 		return;
+	}
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ 		tty_wakeup(tty);
+		//wake_up_interruptible(&tty->write_wait);
+	}
 
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
-		tty_wakeup(tty);
+	func_exit();
 }
 
 static struct tty_operations sx_ops = {
@@ -2042,15 +2412,19 @@ static int sx_init_drivers(void)
 	int error;
 	int i;
 
+	func_enter();
+
 	specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);
 	if (!specialix_driver) {
 		printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");
+		func_exit();
 		return 1;
 	}
 	
 	if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
 		printk(KERN_ERR "sx: Couldn't get free page.\n");
 		put_tty_driver(specialix_driver);
+		func_exit();
 		return 1;
 	}
 	specialix_driver->owner = THIS_MODULE;
@@ -2069,6 +2443,7 @@ static int sx_init_drivers(void)
 		free_page((unsigned long)tmp_buf);
 		printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
 		       error);
+		func_exit();
 		return 1;
 	}
 	memset(sx_port, 0, sizeof(sx_port));
@@ -2080,47 +2455,23 @@ static int sx_init_drivers(void)
 		sx_port[i].closing_wait = 3000 * HZ/100;
 		init_waitqueue_head(&sx_port[i].open_wait);
 		init_waitqueue_head(&sx_port[i].close_wait);
+		spin_lock_init(&sx_port[i].lock);
 	}
 	
+	func_exit();
 	return 0;
 }
 
-
 static void sx_release_drivers(void)
 {
+	func_enter();
+
 	free_page((unsigned long)tmp_buf);
 	tty_unregister_driver(specialix_driver);
 	put_tty_driver(specialix_driver);
+	func_exit();
 }
 
-
-#ifndef MODULE
-/*
- * Called at boot time.
- * 
- * You can specify IO base for up to SX_NBOARD cards,
- * using line "specialix=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there will be no probing at default
- * addresses in this case.
- *
- */ 
-void specialix_setup(char *str, int * ints)
-{
-	int i;
-        
-	for (i=0;i<SX_NBOARD;i++) {
-		sx_board[i].base = 0;
-	}
-
-	for (i = 1; i <= ints[0]; i++) {
-		if (i&1)
-			sx_board[i/2].base = ints[i];
-		else
-			sx_board[i/2 -1].irq = ints[i];
-	}
-}
-#endif
-
 /* 
  * This routine must be called by kernel at boot time 
  */
@@ -2129,6 +2480,8 @@ static int __init specialix_init(void)
 	int i;
 	int found = 0;
 
+	func_enter();
+
 	printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
 	printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
 #ifdef CONFIG_SPECIALIX_RTSCTS
@@ -2137,8 +2490,13 @@ static int __init specialix_init(void)
 	printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
 #endif
 	
-	if (sx_init_drivers()) 
+	for (i = 0; i < SX_NBOARD; i++)
+		sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+
+	if (sx_init_drivers()) {
+		func_exit();
 		return -EIO;
+	}
 
 	for (i = 0; i < SX_NBOARD; i++) 
 		if (sx_board[i].base && !sx_probe(&sx_board[i]))
@@ -2176,18 +2534,25 @@ static int __init specialix_init(void)
 	if (!found) {
 		sx_release_drivers();
 		printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
+		func_exit();
 		return -EIO;
 	}
 
+	func_exit();
 	return 0;
 }
 
-int iobase[SX_NBOARD]  = {0,};
+static int iobase[SX_NBOARD]  = {0,};
 
-int irq [SX_NBOARD] = {0,};
+static int irq [SX_NBOARD] = {0,};
 
 module_param_array(iobase, int, NULL, 0);
 module_param_array(irq, int, NULL, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_rxfifo, int, 0);
+#ifdef SPECIALIX_TIMER
+module_param(sx_poll, int, 0);
+#endif
 
 /*
  * You can setup up to 4 boards.
@@ -2202,13 +2567,20 @@ static int __init specialix_init_module(
 {
 	int i;
 
+	func_enter();
+
+	init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
+
 	if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
 		for(i = 0; i < SX_NBOARD; i++) {
 			sx_board[i].base = iobase[i];
 			sx_board[i].irq = irq[i];
+			sx_board[i].count= 0;
 		}
 	}
 
+	func_exit();
+
 	return specialix_init();
 }
 	
@@ -2216,6 +2588,8 @@ static void __exit specialix_exit_module
 {
 	int i;
 	
+	func_enter();
+
 	sx_release_drivers();
 	for (i = 0; i < SX_NBOARD; i++)
 		if (sx_board[i].flags & SX_BOARD_PRESENT) 
@@ -2223,7 +2597,8 @@ static void __exit specialix_exit_module
 #ifdef SPECIALIX_TIMER
 	del_timer (&missed_irq_timer);
 #endif
-	
+
+	func_exit();
 }
 
 module_init(specialix_init_module);
diff --git a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h
--- a/drivers/char/specialix_io8.h
+++ b/drivers/char/specialix_io8.h
@@ -93,9 +93,11 @@ struct specialix_board {
 	unsigned long   flags;
 	unsigned short	base;
 	unsigned char 	irq;
-	signed   char	count;
+	//signed   char	count;
+	int count;
 	unsigned char	DTR;
         int reg;
+	spinlock_t lock;
 };
 
 #define SX_BOARD_PRESENT	0x00000001
@@ -129,12 +131,9 @@ struct specialix_port {
 	unsigned char		IER;
 	unsigned char		MSVR;
 	unsigned char		COR2;
-#ifdef SX_REPORT_OVERRUN
 	unsigned long		overrun;
-#endif	
-#ifdef SX_REPORT_FIFO
 	unsigned long		hits[10];
-#endif
+	spinlock_t lock;
 };
 
 #endif /* __KERNEL__ */
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -174,14 +174,6 @@ static stlport_t	stl_dummyport;
  */
 static char		stl_unwanted[SC26198_RXFIFOSIZE];
 
-/*
- *	Keep track of what interrupts we have requested for us.
- *	We don't need to request an interrupt twice if it is being
- *	shared with another Stallion board.
- */
-static int	stl_gotintrs[STL_MAXBRDS];
-static int	stl_numintrs;
-
 /*****************************************************************************/
 
 static stlbrd_t		*stl_brds[STL_MAXBRDS];
@@ -240,13 +232,12 @@ static char	*stl_brdnames[] = {
 
 /*****************************************************************************/
 
-#ifdef MODULE
 /*
  *	Define some string labels for arguments passed from the module
  *	load line. These allow for easy board definitions, and easy
  *	modification of the io, memory and irq resoucres.
  */
-
+static int	stl_nargs = 0;
 static char	*board0[4];
 static char	*board1[4];
 static char	*board2[4];
@@ -307,17 +298,15 @@ MODULE_AUTHOR("Greg Ungerer");
 MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(board0, "1-4s");
+module_param_array(board0, charp, &stl_nargs, 0);
 MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board1, "1-4s");
+module_param_array(board1, charp, &stl_nargs, 0);
 MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board2, "1-4s");
+module_param_array(board2, charp, &stl_nargs, 0);
 MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board3, "1-4s");
+module_param_array(board3, charp, &stl_nargs, 0);
 MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]");
 
-#endif
-
 /*****************************************************************************/
 
 /*
@@ -472,14 +461,12 @@ static unsigned int	stl_baudrates[] = {
  *	Declare all those functions in this driver!
  */
 
-#ifdef MODULE
 static void	stl_argbrds(void);
 static int	stl_parsebrd(stlconf_t *confp, char **argp);
 
 static unsigned long stl_atol(char *str);
-#endif
 
-int		stl_init(void);
+static int	stl_init(void);
 static int	stl_open(struct tty_struct *tty, struct file *filp);
 static void	stl_close(struct tty_struct *tty, struct file *filp);
 static int	stl_write(struct tty_struct *tty, const unsigned char *buf, int count);
@@ -504,7 +491,6 @@ static int	stl_readproc(char *page, char
 
 static int	stl_brdinit(stlbrd_t *brdp);
 static int	stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int	stl_mapirq(int irq, char *name);
 static int	stl_getserial(stlport_t *portp, struct serial_struct __user *sp);
 static int	stl_setserial(stlport_t *portp, struct serial_struct __user *sp);
 static int	stl_getbrdstats(combrd_t __user *bp);
@@ -513,11 +499,11 @@ static int	stl_clrportstats(stlport_t *p
 static int	stl_getportstruct(stlport_t __user *arg);
 static int	stl_getbrdstruct(stlbrd_t __user *arg);
 static int	stl_waitcarrier(stlport_t *portp, struct file *filp);
-static void	stl_eiointr(stlbrd_t *brdp);
-static void	stl_echatintr(stlbrd_t *brdp);
-static void	stl_echmcaintr(stlbrd_t *brdp);
-static void	stl_echpciintr(stlbrd_t *brdp);
-static void	stl_echpci64intr(stlbrd_t *brdp);
+static int	stl_eiointr(stlbrd_t *brdp);
+static int	stl_echatintr(stlbrd_t *brdp);
+static int	stl_echmcaintr(stlbrd_t *brdp);
+static int	stl_echpciintr(stlbrd_t *brdp);
+static int	stl_echpci64intr(stlbrd_t *brdp);
 static void	stl_offintr(void *private);
 static void	*stl_memalloc(int len);
 static stlbrd_t *stl_allocbrd(void);
@@ -735,8 +721,6 @@ static struct file_operations	stl_fsiome
 
 static struct class_simple *stallion_class;
 
-#ifdef MODULE
-
 /*
  *	Loadable module initialization stuff.
  */
@@ -807,6 +791,9 @@ static void __exit stallion_module_exit(
 	for (i = 0; (i < stl_nrbrds); i++) {
 		if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
 			continue;
+
+		free_irq(brdp->irq, brdp);
+
 		for (j = 0; (j < STL_MAXPANELS); j++) {
 			panelp = brdp->panels[j];
 			if (panelp == (stlpanel_t *) NULL)
@@ -832,9 +819,6 @@ static void __exit stallion_module_exit(
 		stl_brds[i] = (stlbrd_t *) NULL;
 	}
 
-	for (i = 0; (i < stl_numintrs); i++)
-		free_irq(stl_gotintrs[i], NULL);
-
 	restore_flags(flags);
 }
 
@@ -851,15 +835,13 @@ static void stl_argbrds(void)
 {
 	stlconf_t	conf;
 	stlbrd_t	*brdp;
-	int		nrargs, i;
+	int		i;
 
 #ifdef DEBUG
 	printk("stl_argbrds()\n");
 #endif
 
-	nrargs = sizeof(stl_brdsp) / sizeof(char **);
-
-	for (i = stl_nrbrds; (i < nrargs); i++) {
+	for (i = stl_nrbrds; (i < stl_nargs); i++) {
 		memset(&conf, 0, sizeof(conf));
 		if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
 			continue;
@@ -959,8 +941,6 @@ static int stl_parsebrd(stlconf_t *confp
 	return(1);
 }
 
-#endif
-
 /*****************************************************************************/
 
 /*
@@ -1992,23 +1972,14 @@ stl_readdone:
 
 static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
-	stlbrd_t	*brdp;
-	int		i;
-	int handled = 0;
+	stlbrd_t	*brdp = (stlbrd_t *) dev_id;
 
 #ifdef DEBUG
-	printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);
+	printk("stl_intr(brdp=%x,irq=%d,regs=%x)\n", (int) brdp, irq,
+	    (int) regs);
 #endif
 
-	for (i = 0; (i < stl_nrbrds); i++) {
-		if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
-			continue;
-		if (brdp->state == 0)
-			continue;
-		handled = 1;
-		(* brdp->isr)(brdp);
-	}
-	return IRQ_RETVAL(handled);
+	return IRQ_RETVAL((* brdp->isr)(brdp));
 }
 
 /*****************************************************************************/
@@ -2017,15 +1988,19 @@ static irqreturn_t stl_intr(int irq, voi
  *	Interrupt service routine for EasyIO board types.
  */
 
-static void stl_eiointr(stlbrd_t *brdp)
+static int stl_eiointr(stlbrd_t *brdp)
 {
 	stlpanel_t	*panelp;
 	unsigned int	iobase;
+	int		handled = 0;
 
 	panelp = brdp->panels[0];
 	iobase = panelp->iobase;
-	while (inb(brdp->iostatus) & EIO_INTRPEND)
+	while (inb(brdp->iostatus) & EIO_INTRPEND) {
+		handled = 1;
 		(* panelp->isr)(panelp, iobase);
+	}
+	return handled;
 }
 
 /*****************************************************************************/
@@ -2034,15 +2009,17 @@ static void stl_eiointr(stlbrd_t *brdp)
  *	Interrupt service routine for ECH-AT board types.
  */
 
-static void stl_echatintr(stlbrd_t *brdp)
+static int stl_echatintr(stlbrd_t *brdp)
 {
 	stlpanel_t	*panelp;
 	unsigned int	ioaddr;
 	int		bnknr;
+	int		handled = 0;
 
 	outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
 
 	while (inb(brdp->iostatus) & ECH_INTRPEND) {
+		handled = 1;
 		for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
 			ioaddr = brdp->bnkstataddr[bnknr];
 			if (inb(ioaddr) & ECH_PNLINTRPEND) {
@@ -2053,6 +2030,8 @@ static void stl_echatintr(stlbrd_t *brdp
 	}
 
 	outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
+
+	return handled;
 }
 
 /*****************************************************************************/
@@ -2061,13 +2040,15 @@ static void stl_echatintr(stlbrd_t *brdp
  *	Interrupt service routine for ECH-MCA board types.
  */
 
-static void stl_echmcaintr(stlbrd_t *brdp)
+static int stl_echmcaintr(stlbrd_t *brdp)
 {
 	stlpanel_t	*panelp;
 	unsigned int	ioaddr;
 	int		bnknr;
+	int		handled = 0;
 
 	while (inb(brdp->iostatus) & ECH_INTRPEND) {
+		handled = 1;
 		for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
 			ioaddr = brdp->bnkstataddr[bnknr];
 			if (inb(ioaddr) & ECH_PNLINTRPEND) {
@@ -2076,6 +2057,7 @@ static void stl_echmcaintr(stlbrd_t *brd
 			}
 		}
 	}
+	return handled;
 }
 
 /*****************************************************************************/
@@ -2084,11 +2066,12 @@ static void stl_echmcaintr(stlbrd_t *brd
  *	Interrupt service routine for ECH-PCI board types.
  */
 
-static void stl_echpciintr(stlbrd_t *brdp)
+static int stl_echpciintr(stlbrd_t *brdp)
 {
 	stlpanel_t	*panelp;
 	unsigned int	ioaddr;
 	int		bnknr, recheck;
+	int		handled = 0;
 
 	while (1) {
 		recheck = 0;
@@ -2099,11 +2082,13 @@ static void stl_echpciintr(stlbrd_t *brd
 				panelp = brdp->bnk2panel[bnknr];
 				(* panelp->isr)(panelp, (ioaddr & 0xfffc));
 				recheck++;
+				handled = 1;
 			}
 		}
 		if (! recheck)
 			break;
 	}
+	return handled;
 }
 
 /*****************************************************************************/
@@ -2112,13 +2097,15 @@ static void stl_echpciintr(stlbrd_t *brd
  *	Interrupt service routine for ECH-8/64-PCI board types.
  */
 
-static void stl_echpci64intr(stlbrd_t *brdp)
+static int stl_echpci64intr(stlbrd_t *brdp)
 {
 	stlpanel_t	*panelp;
 	unsigned int	ioaddr;
 	int		bnknr;
+	int		handled = 0;
 
 	while (inb(brdp->ioctrl) & 0x1) {
+		handled = 1;
 		for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
 			ioaddr = brdp->bnkstataddr[bnknr];
 			if (inb(ioaddr) & ECH_PNLINTRPEND) {
@@ -2127,6 +2114,8 @@ static void stl_echpci64intr(stlbrd_t *b
 			}
 		}
 	}
+
+	return handled;
 }
 
 /*****************************************************************************/
@@ -2174,39 +2163,6 @@ static void stl_offintr(void *private)
 /*****************************************************************************/
 
 /*
- *	Map in interrupt vector to this driver. Check that we don't
- *	already have this vector mapped, we might be sharing this
- *	interrupt across multiple boards.
- */
-
-static int __init stl_mapirq(int irq, char *name)
-{
-	int	rc, i;
-
-#ifdef DEBUG
-	printk("stl_mapirq(irq=%d,name=%s)\n", irq, name);
-#endif
-
-	rc = 0;
-	for (i = 0; (i < stl_numintrs); i++) {
-		if (stl_gotintrs[i] == irq)
-			break;
-	}
-	if (i >= stl_numintrs) {
-		if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
-			printk("STALLION: failed to register interrupt "
-				"routine for %s irq=%d\n", name, irq);
-			rc = -ENODEV;
-		} else {
-			stl_gotintrs[stl_numintrs++] = irq;
-		}
-	}
-	return(rc);
-}
-
-/*****************************************************************************/
-
-/*
  *	Initialize all the ports on a panel.
  */
 
@@ -2389,7 +2345,13 @@ static inline int stl_initeio(stlbrd_t *
 	brdp->nrpanels = 1;
 	brdp->state |= BRD_FOUND;
 	brdp->hwid = status;
-	rc = stl_mapirq(brdp->irq, name);
+	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;
+	} else {
+		rc = 0;
+	}
 	return(rc);
 }
 
@@ -2594,7 +2556,14 @@ static inline int stl_initech(stlbrd_t *
 		outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
 
 	brdp->state |= BRD_FOUND;
-	i = stl_mapirq(brdp->irq, name);
+	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);
+		i = -ENODEV;
+	} else {
+		i = 0;
+	}
+
 	return(i);
 }
 
@@ -2807,9 +2776,7 @@ static inline int stl_initbrds(void)
  */
 	for (i = 0; (i < stl_nrbrds); i++) {
 		confp = &stl_brdconf[i];
-#ifdef MODULE
 		stl_parsebrd(confp, stl_brdsp[i]);
-#endif
 		if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
 			return(-ENOMEM);
 		brdp->brdnr = i;
@@ -2825,9 +2792,7 @@ static inline int stl_initbrds(void)
  *	Find any dynamically supported boards. That is via module load
  *	line options or auto-detected on the PCI bus.
  */
-#ifdef MODULE
 	stl_argbrds();
-#endif
 #ifdef CONFIG_PCI
 	stl_findpcibrds();
 #endif
@@ -3098,7 +3063,7 @@ static struct tty_operations stl_ops = {
 
 /*****************************************************************************/
 
-int __init stl_init(void)
+static int __init stl_init(void)
 {
 	int i;
 	printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -4,7 +4,7 @@
  *  This driver will also support the older SI, and XIO cards.
  *
  *
- *   (C) 1998 - 2000  R.E.Wolff@BitWizard.nl
+ *   (C) 1998 - 2004  R.E.Wolff@BitWizard.nl
  *
  *  Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
  *  version of this driver. Some fragments may have been copied. (none
@@ -354,13 +354,13 @@ static int si1_probe_addrs[]= { 0xd0000}
    Some architectures may need more. */
 static int sx_irqmask = -1;
 
-MODULE_PARM(sx_probe_addrs, "i");
-MODULE_PARM(si_probe_addrs, "i");
-MODULE_PARM(sx_poll, "i");
-MODULE_PARM(sx_slowpoll, "i");
-MODULE_PARM(sx_maxints, "i");
-MODULE_PARM(sx_debug, "i");
-MODULE_PARM(sx_irqmask, "i");
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+module_param(sx_poll, int, 0);
+module_param(sx_slowpoll, int, 0);
+module_param(sx_maxints, int, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_irqmask, int, 0);
 
 MODULE_LICENSE("GPL");
 
@@ -396,7 +396,7 @@ static struct real_driver sx_real_driver
 
 
 
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\b",__FUNCTION__)
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
 #define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  %s\n", __FUNCTION__)
 
 #define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
@@ -1158,7 +1158,6 @@ static inline void sx_check_modem_signal
 	if (hi_state & ST_BREAK) {
 		hi_state &= ~ST_BREAK;
 		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
-
 		sx_write_channel_byte (port, hi_state, hi_state);
 		gs_got_break (&port->gs);
 	}
@@ -1206,7 +1205,7 @@ static irqreturn_t sx_interrupt (int irq
 	struct sx_port *port;
 	int i;
 
-	/*   func_enter ();  */
+	func_enter ();
 	sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); 
 
 	/* AAargh! The order in which to do these things is essential and
@@ -1297,7 +1296,7 @@ static irqreturn_t sx_interrupt (int irq
 	clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
 
 	sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); 
-	/*  func_exit ();  */
+        func_exit ();
 	return IRQ_HANDLED;
 }
 
@@ -1428,6 +1427,7 @@ static int sx_open  (struct tty_struct *
 {
 	struct sx_port *port;
 	int retval, line;
+	unsigned long flags;
 
 	func_enter();
 
@@ -1449,9 +1449,12 @@ static int sx_open  (struct tty_struct *
 
 	sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
 
+	spin_lock_irqsave(&port->gs.driver_lock, flags);
+
 	tty->driver_data = port;
 	port->gs.tty = tty;
 	port->gs.count++;
+	spin_unlock_irqrestore(&port->gs.driver_lock, flags);
 
 	sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
 
@@ -1466,7 +1469,8 @@ static int sx_open  (struct tty_struct *
 	}
 
 	port->gs.flags |= GS_ACTIVE;
-	sx_setsignals (port, 1,1);
+	if (port->gs.count <= 1)
+		sx_setsignals (port, 1,1);
 
 #if 0
 	if (sx_debug & SX_DEBUG_OPEN)
@@ -1476,10 +1480,14 @@ static int sx_open  (struct tty_struct *
 		my_hd_io (port->board->base + port->ch_base, sizeof (*port));
 #endif
 
-	if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
-		printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
-		port->gs.count--;
-		return -EIO;
+	if (port->gs.count <= 1) {
+		if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+			printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+			spin_lock_irqsave(&port->gs.driver_lock, flags);
+			port->gs.count--;
+			spin_unlock_irqrestore(&port->gs.driver_lock, flags);
+			return -EIO;
+		}
 	}
 
 	retval = gs_block_til_ready(port, filp);
@@ -1497,6 +1505,7 @@ static int sx_open  (struct tty_struct *
 
 	port->c_dcd = sx_get_CD (port);
 	sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+
 	func_exit();
 	return 0;
 
@@ -1515,13 +1524,9 @@ static void sx_close (void *ptr)
 	sx_reconfigure_port(port);	
 	sx_send_command (port, HS_CLOSE, 0, 0);
 
-	while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout (1);
-		if (signal_pending (current))
-				break;
-	}
-	current->state = TASK_RUNNING;
+	while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED))
+		if (msleep_interruptible(10))
+			break;
 	if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
 		if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
 			printk (KERN_ERR 
@@ -1535,7 +1540,8 @@ static void sx_close (void *ptr)
 
 	if(port->gs.count) {
 		sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count);
-		port->gs.count = 0;
+		//printk ("%s SETTING port count to zero: %p count: %d\n", __FUNCTION__, port, port->gs.count);
+		//port->gs.count = 0;
 	}
 
 	func_exit ();
@@ -1751,12 +1757,16 @@ static void sx_break (struct tty_struct 
 	struct sx_port *port = tty->driver_data;
 	int rv;
 
+	func_enter ();
+
 	if (flag) 
 		rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
 	else 
 		rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
 	if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
 			read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+
+	func_exit ();
 }
 
 
@@ -2105,7 +2115,7 @@ static int probe_sx (struct sx_board *bo
 		}
 
 		if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
-			if (board->hw_base & 0x8000) {
+			if (((unsigned long)board->hw_base) & 0x8000) {
 				printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->hw_base);
 				printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
 			}
@@ -2154,6 +2164,7 @@ static int probe_si (struct sx_board *bo
 	    }
 		for (i=0;i<8;i++) {
 			if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
+				func_exit ();
 				return 0;
 			}
 		}
@@ -2168,11 +2179,13 @@ static int probe_si (struct sx_board *bo
 		/* This should be an SI1 board, which has this
 		   location writable... */
 		if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10)
+			func_exit ();
 			return 0; 
 	} else {
 		/* This should be an SI2 board, which has the bottom
 		   3 bits non-writable... */
 		if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10)
+			func_exit ();
 			return 0; 
 	}
 
@@ -2185,11 +2198,13 @@ static int probe_si (struct sx_board *bo
 		/* This should be an SI1 board, which has this
 		   location writable... */
 		if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10)
+			func_exit();
 			return 0; 
 	} else {
 		/* This should be an SI2 board, which has the bottom
 		   3 bits non-writable... */
 		if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10)
+			func_exit ();
 			return 0; 
 	}
 
@@ -2306,6 +2321,7 @@ static int sx_init_portstructs (int nboa
 #ifdef NEW_WRITE_LOCKING
 			port->gs.port_write_sem = MUTEX;
 #endif
+			port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
 			/*
 			 * Initializing wait queue
 			 */
@@ -2477,7 +2493,7 @@ static int __init sx_init(void) 
 			found++;
 			fix_sx_pci (pdev, board);
 		} else 
-			iounmap(board->base);
+			iounmap(board->base2);
 	}
 #endif
 
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1,5 +1,5 @@
 /*
- * $Id: synclinkmp.c,v 4.29 2004/08/27 20:06:41 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.34 2005/03/04 15:07:10 paulkf Exp $
  *
  * Device driver for Microgate SyncLink Multiport
  * high speed multiprotocol serial adapter.
@@ -487,7 +487,7 @@ module_param_array(maxframe, int, NULL, 
 module_param_array(dosyncppp, int, NULL, 0);
 
 static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.29 $";
+static char *driver_version = "$Revision: 4.34 $";
 
 static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
 static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -2313,7 +2313,7 @@ void isr_rxrdy(SLMP_INFO * info)
 		tty_flip_buffer_push(tty);
 }
 
-void isr_txeom(SLMP_INFO * info, unsigned char status)
+static void isr_txeom(SLMP_INFO * info, unsigned char status)
 {
 	if ( debug_level >= DEBUG_LEVEL_ISR )
 		printk("%s(%d):%s isr_txeom status=%02x\n",
@@ -3815,7 +3815,7 @@ void add_device(SLMP_INFO *info)
  *
  * Return Value:	pointer to SLMP_INFO if success, otherwise NULL
  */
-SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
+static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
 {
 	SLMP_INFO *info;
 
@@ -4528,7 +4528,7 @@ void async_mode(SLMP_INFO *info)
 	 * 07..05  Reserved, must be 0
 	 * 04..00  RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte
 	 */
-	write_reg(info, TRC0, 0x00);
+	write_reg(info, RRC, 0x00);
 
 	/* TRC0 Transmit Ready Control 0
 	 *
@@ -5205,7 +5205,7 @@ int irq_test(SLMP_INFO *info)
 
 /* initialize individual SCA device (2 ports)
  */
-int sca_init(SLMP_INFO *info)
+static 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 */
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -31,19 +31,16 @@
 #include <linux/suspend.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>		/* for fsync_bdev() */
-
+#include <linux/swap.h>
 #include <linux/spinlock.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
 
 #include <asm/ptrace.h>
 
-extern void reset_vc(unsigned int);
-
 /* Whether we react on sysrq keys or just ignore them */
 int sysrq_enabled = 1;
 
-/* Machine specific power off function */
-void (*sysrq_power_off)(void);
-
 /* Loglevel sysrq handler */
 static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
 				  struct tty_struct *tty) 
@@ -58,6 +55,7 @@ static struct sysrq_key_op sysrq_logleve
 	.handler	= sysrq_handle_loglevel,
 	.help_msg	= "loglevel0-8",
 	.action_msg	= "Changing Loglevel",
+	.enable_mask	= SYSRQ_ENABLE_LOG,
 };
 
 
@@ -68,12 +66,13 @@ static void sysrq_handle_SAK(int key, st
 {
 	if (tty)
 		do_SAK(tty);
-	reset_vc(fg_console);
+	reset_vc(vc_cons[fg_console].d);
 }
 static struct sysrq_key_op sysrq_SAK_op = {
 	.handler	= sysrq_handle_SAK,
 	.help_msg	= "saK",
 	.action_msg	= "SAK",
+	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
 };
 #endif
 
@@ -91,6 +90,7 @@ static struct sysrq_key_op sysrq_unraw_o
 	.handler	= sysrq_handle_unraw,
 	.help_msg	= "unRaw",
 	.action_msg	= "Keyboard mode set to XLATE",
+	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
 };
 #endif /* CONFIG_VT */
 
@@ -106,6 +106,7 @@ static struct sysrq_key_op sysrq_reboot_
 	.handler	= sysrq_handle_reboot,
 	.help_msg	= "reBoot",
 	.action_msg	= "Resetting",
+	.enable_mask	= SYSRQ_ENABLE_BOOT,
 };
 
 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
@@ -118,6 +119,7 @@ static struct sysrq_key_op sysrq_sync_op
 	.handler	= sysrq_handle_sync,
 	.help_msg	= "Sync",
 	.action_msg	= "Emergency Sync",
+	.enable_mask	= SYSRQ_ENABLE_SYNC,
 };
 
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
@@ -130,6 +132,7 @@ static struct sysrq_key_op sysrq_mountro
 	.handler	= sysrq_handle_mountro,
 	.help_msg	= "Unmount",
 	.action_msg	= "Emergency Remount R/O",
+	.enable_mask	= SYSRQ_ENABLE_REMOUNT,
 };
 
 /* END SYNC SYSRQ HANDLERS BLOCK */
@@ -147,6 +150,7 @@ static struct sysrq_key_op sysrq_showreg
 	.handler	= sysrq_handle_showregs,
 	.help_msg	= "showPc",
 	.action_msg	= "Show Regs",
+	.enable_mask	= SYSRQ_ENABLE_DUMP,
 };
 
 
@@ -159,6 +163,7 @@ static struct sysrq_key_op sysrq_showsta
 	.handler	= sysrq_handle_showstate,
 	.help_msg	= "showTasks",
 	.action_msg	= "Show State",
+	.enable_mask	= SYSRQ_ENABLE_DUMP,
 };
 
 
@@ -171,6 +176,7 @@ static struct sysrq_key_op sysrq_showmem
 	.handler	= sysrq_handle_showmem,
 	.help_msg	= "showMem",
 	.action_msg	= "Show Memory",
+	.enable_mask	= SYSRQ_ENABLE_DUMP,
 };
 
 /* SHOW SYSRQ HANDLERS BLOCK */
@@ -201,6 +207,25 @@ static struct sysrq_key_op sysrq_term_op
 	.handler	= sysrq_handle_term,
 	.help_msg	= "tErm",
 	.action_msg	= "Terminate All Tasks",
+	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
+};
+
+static void moom_callback(void *ignored)
+{
+	out_of_memory(GFP_KERNEL);
+}
+
+static DECLARE_WORK(moom_work, moom_callback, NULL);
+
+static void sysrq_handle_moom(int key, struct pt_regs *pt_regs,
+			      struct tty_struct *tty)
+{
+	schedule_work(&moom_work);
+}
+static struct sysrq_key_op sysrq_moom_op = {
+	.handler	= sysrq_handle_moom,
+	.help_msg	= "Full",
+	.action_msg	= "Manual OOM execution",
 };
 
 static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
@@ -213,6 +238,7 @@ static struct sysrq_key_op sysrq_kill_op
 	.handler	= sysrq_handle_kill,
 	.help_msg	= "kIll",
 	.action_msg	= "Kill All Tasks",
+	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
 };
 
 /* END SIGNAL SYSRQ HANDLERS BLOCK */
@@ -225,7 +251,8 @@ static void sysrq_handle_unrt(int key, s
 static struct sysrq_key_op sysrq_unrt_op = {
 	.handler	= sysrq_handle_unrt,
 	.help_msg	= "Nice",
-	.action_msg	= "Nice All RT Tasks"
+	.action_msg	= "Nice All RT Tasks",
+	.enable_mask	= SYSRQ_ENABLE_RTNICE,
 };
 
 /* Key Operations table and lock */
@@ -249,7 +276,7 @@ static struct sysrq_key_op *sysrq_key_ta
 /* c */ NULL,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
-/* f */	NULL,
+/* f */	&sysrq_moom_op,
 /* g */	NULL,
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
@@ -321,7 +348,7 @@ void __sysrq_put_key_op (int key, struct
  * as they are inside of the lock
  */
 
-void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, int check_mask)
 {
 	struct sysrq_key_op *op_p;
 	int orig_log_level;
@@ -335,9 +362,16 @@ void __handle_sysrq(int key, struct pt_r
 
         op_p = __sysrq_get_key_op(key);
         if (op_p) {
-		printk ("%s\n", op_p->action_msg);
-		console_loglevel = orig_log_level;
-		op_p->handler(key, pt_regs, tty);
+		/* Should we check for enabled operations (/proc/sysrq-trigger should not)
+		 * and is the invoked operation enabled? */
+		if (!check_mask || sysrq_enabled == 1 ||
+		    (sysrq_enabled & op_p->enable_mask)) {
+			printk ("%s\n", op_p->action_msg);
+			console_loglevel = orig_log_level;
+			op_p->handler(key, pt_regs, tty);
+		}
+		else
+			printk("This sysrq operation is disabled.\n");
 	} else {
 		printk("HELP : ");
 		/* Only print the help msg once per handler */
@@ -362,7 +396,7 @@ void handle_sysrq(int key, struct pt_reg
 {
 	if (!sysrq_enabled)
 		return;
-	__handle_sysrq(key, pt_regs, tty);
+	__handle_sysrq(key, pt_regs, tty, 1);
 }
 
 int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/tb0219.c
@@ -0,0 +1,347 @@
+/*
+ *  Driver for TANBAC TB0219 base board.
+ *
+ *  Copyright (C) 2005  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.
+ *
+ *  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/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/reboot.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
+MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
+MODULE_LICENSE("GPL");
+
+static int major;	/* default is dynamic major device number */
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+static void (*old_machine_restart)(char *command);
+static void __iomem *tb0219_base;
+static spinlock_t tb0219_lock;
+
+#define tb0219_read(offset)		readw(tb0219_base + (offset))
+#define tb0219_write(offset, value)	writew((value), tb0219_base + (offset))
+
+#define TB0219_START	0x0a000000UL
+#define TB0219_SIZE	0x20UL
+
+#define TB0219_LED			0x00
+#define TB0219_GPIO_INPUT		0x02
+#define TB0219_GPIO_OUTPUT		0x04
+#define TB0219_DIP_SWITCH		0x06
+#define TB0219_MISC			0x08
+#define TB0219_RESET			0x0e
+#define TB0219_PCI_SLOT1_IRQ_STATUS	0x10
+#define TB0219_PCI_SLOT2_IRQ_STATUS	0x12
+#define TB0219_PCI_SLOT3_IRQ_STATUS	0x14
+
+typedef enum {
+	TYPE_LED,
+	TYPE_GPIO_OUTPUT,
+} tb0219_type_t;
+
+/*
+ * Minor device number
+ *	 0 = 7 segment LED
+ *
+ *	16 = GPIO IN 0
+ *	17 = GPIO IN 1
+ *	18 = GPIO IN 2
+ *	19 = GPIO IN 3
+ *	20 = GPIO IN 4
+ *	21 = GPIO IN 5
+ *	22 = GPIO IN 6
+ *	23 = GPIO IN 7
+ *
+ *	32 = GPIO OUT 0
+ *	33 = GPIO OUT 1
+ *	34 = GPIO OUT 2
+ *	35 = GPIO OUT 3
+ *	36 = GPIO OUT 4
+ *	37 = GPIO OUT 5
+ *	38 = GPIO OUT 6
+ *	39 = GPIO OUT 7
+ *
+ *	48 = DIP switch 1
+ *	49 = DIP switch 2
+ *	50 = DIP switch 3
+ *	51 = DIP switch 4
+ *	52 = DIP switch 5
+ *	53 = DIP switch 6
+ *	54 = DIP switch 7
+ *	55 = DIP switch 8
+ */
+
+static inline char get_led(void)
+{
+	return (char)tb0219_read(TB0219_LED);
+}
+
+static inline char get_gpio_input_pin(unsigned int pin)
+{
+	uint16_t values;
+
+	values = tb0219_read(TB0219_GPIO_INPUT);
+	if (values & (1 << pin))
+		return '1';
+
+	return '0';
+}
+
+static inline char get_gpio_output_pin(unsigned int pin)
+{
+	uint16_t values;
+
+	values = tb0219_read(TB0219_GPIO_OUTPUT);
+	if (values & (1 << pin))
+		return '1';
+
+	return '0';
+}
+
+static inline char get_dip_switch(unsigned int pin)
+{
+	uint16_t values;
+
+	values = tb0219_read(TB0219_DIP_SWITCH);
+	if (values & (1 << pin))
+		return '1';
+
+	return '0';
+}
+
+static inline int set_led(char command)
+{
+	tb0219_write(TB0219_LED, command);
+
+	return 0;
+}
+
+static inline int set_gpio_output_pin(unsigned int pin, char command)
+{
+	unsigned long flags;
+	uint16_t value;
+
+	if (command != '0' && command != '1')
+		return -EINVAL;
+
+	spin_lock_irqsave(&tb0219_lock, flags);
+	value = tb0219_read(TB0219_GPIO_OUTPUT);
+	if (command == '0')
+		value &= ~(1 << pin);
+	else
+		value |= 1 << pin;
+	tb0219_write(TB0219_GPIO_OUTPUT, value);
+	spin_unlock_irqrestore(&tb0219_lock, flags);
+
+	return 0;
+
+}
+
+static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len,
+                                  loff_t *ppos)
+{
+	unsigned int minor;
+	char value;
+
+	minor = iminor(file->f_dentry->d_inode);
+	switch (minor) {
+	case 0:
+		value = get_led();
+		break;
+	case 16 ... 23:
+		value = get_gpio_input_pin(minor - 16);
+		break;
+	case 32 ... 39:
+		value = get_gpio_output_pin(minor - 32);
+		break;
+	case 48 ... 55:
+		value = get_dip_switch(minor - 48);
+		break;
+	default:
+		return -EBADF;
+	}
+
+	if (len <= 0)
+		return -EFAULT;
+
+	if (put_user(value, buf))
+		return -EFAULT;
+
+	return 1;
+}
+
+static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
+                                   size_t len, loff_t *ppos)
+{
+	unsigned int minor;
+	tb0219_type_t type;
+	size_t i;
+	int retval = 0;
+	char c;
+
+	minor = iminor(file->f_dentry->d_inode);
+	switch (minor) {
+	case 0:
+		type = TYPE_LED;
+		break;
+	case 32 ... 39:
+		type = TYPE_GPIO_OUTPUT;
+		break;
+	default:
+		return -EBADF;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (get_user(c, data + i))
+			return -EFAULT;
+
+		switch (type) {
+		case TYPE_LED:
+			retval = set_led(c);
+			break;
+		case TYPE_GPIO_OUTPUT:
+			retval = set_gpio_output_pin(minor - 32, c);
+			break;
+		}
+
+		if (retval < 0)
+			break;
+	}
+
+	return i;
+}
+
+static int tanbac_tb0219_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor;
+
+	minor = iminor(inode);
+	switch (minor) {
+	case 0:
+	case 16 ... 23:
+	case 32 ... 39:
+	case 48 ... 55:
+		return nonseekable_open(inode, file);
+	default:
+		break;
+	}
+
+	return -EBADF;
+}
+
+static int tanbac_tb0219_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations tb0219_fops = {
+	.owner		= THIS_MODULE,
+	.read		= tanbac_tb0219_read,
+	.write		= tanbac_tb0219_write,
+	.open		= tanbac_tb0219_open,
+	.release	= tanbac_tb0219_release,
+};
+
+static void tb0219_restart(char *command)
+{
+	tb0219_write(TB0219_RESET, 0);
+}
+
+static int tb0219_probe(struct device *dev)
+{
+	int retval;
+
+	if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL)
+		return -EBUSY;
+
+	tb0219_base = ioremap(TB0219_START, TB0219_SIZE);
+	if (tb0219_base == NULL) {
+		release_mem_region(TB0219_START, TB0219_SIZE);
+		return -ENOMEM;
+	}
+
+	retval = register_chrdev(major, "TB0219", &tb0219_fops);
+	if (retval < 0) {
+		iounmap(tb0219_base);
+		tb0219_base = NULL;
+		release_mem_region(TB0219_START, TB0219_SIZE);
+		return retval;
+	}
+
+	spin_lock_init(&tb0219_lock);
+
+	old_machine_restart = _machine_restart;
+	_machine_restart = tb0219_restart;
+
+	if (major == 0) {
+		major = retval;
+		printk(KERN_INFO "TB0219: major number %d\n", major);
+	}
+
+	return 0;
+}
+
+static int tb0219_remove(struct device *dev)
+{
+	_machine_restart = old_machine_restart;
+
+	iounmap(tb0219_base);
+	tb0219_base = NULL;
+
+	release_mem_region(TB0219_START, TB0219_SIZE);
+
+	return 0;
+}
+
+static struct platform_device *tb0219_platform_device;
+
+static struct device_driver tb0219_device_driver = {
+	.name		= "TB0219",
+	.bus		= &platform_bus_type,
+	.probe		= tb0219_probe,
+	.remove		= tb0219_remove,
+};
+
+static int __devinit tanbac_tb0219_init(void)
+{
+	int retval;
+
+	tb0219_platform_device = platform_device_register_simple("TB0219", -1, NULL, 0);
+	if (IS_ERR(tb0219_platform_device))
+		return PTR_ERR(tb0219_platform_device);
+
+	retval = driver_register(&tb0219_device_driver);
+	if (retval < 0)
+		platform_device_unregister(tb0219_platform_device);
+
+	return retval;
+}
+
+static void __devexit tanbac_tb0219_exit(void)
+{
+	driver_unregister(&tb0219_device_driver);
+
+	platform_device_unregister(tb0219_platform_device);
+}
+
+module_init(tanbac_tb0219_init);
+module_exit(tanbac_tb0219_exit);
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/Kconfig
@@ -0,0 +1,39 @@
+#
+# TPM device configuration
+#
+
+menu "TPM devices"
+
+config TCG_TPM
+	tristate "TPM Hardware Support"
+	depends on EXPERIMENTAL && PCI
+	---help---
+	  If you have a TPM security chip in your system, which
+	  implements the Trusted Computing Group's specification,
+	  say Yes and it will be accessible from within Linux.  For
+	  more information see <http://www.trustedcomputinggroup.org>. 
+	  An implementation of the Trusted Software Stack (TSS), the 
+	  userspace enablement piece of the specification, can be 
+	  obtained at: <http://sourceforge.net/projects/trousers>.  To 
+	  compile this driver as a module, choose M here; the module 
+	  will be called tpm. If unsure, say N.
+
+config TCG_NSC
+	tristate "National Semiconductor TPM Interface"
+	depends on TCG_TPM
+	---help---
+	  If you have a TPM security chip from National Semicondutor 
+	  say Yes and it will be accessible from within Linux.  To 
+	  compile this driver as a module, choose M here; the module 
+	  will be called tpm_nsc.
+
+config TCG_ATMEL
+	tristate "Atmel TPM Interface"
+	depends on TCG_TPM
+	---help---
+	  If you have a TPM security chip from Atmel say Yes and it 
+	  will be accessible from within Linux.  To compile this driver 
+	  as a module, choose M here; the module will be called tpm_atmel.
+
+endmenu
+
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the kernel tpm device drivers.
+#
+obj-$(CONFIG_TCG_TPM) += tpm.o
+obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
+obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
+
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/tpm.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
+ * License.
+ * 
+ * Note, the TPM chip is not interrupt driven (only polling)
+ * and can have very long timeouts (minutes!). Hence the unusual
+ * calls to schedule_timeout.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include "tpm.h"
+
+#define	TPM_MINOR			224	/* officially assigned */
+
+#define	TPM_BUFSIZE			2048
+
+/* PCI configuration addresses */
+#define	PCI_GEN_PMCON_1			0xA0
+#define	PCI_GEN1_DEC			0xE4
+#define	PCI_LPC_EN			0xE6
+#define	PCI_GEN2_DEC			0xEC
+
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+static int dev_mask[32];
+
+static void user_reader_timeout(unsigned long ptr)
+{
+	struct tpm_chip *chip = (struct tpm_chip *) ptr;
+
+	down(&chip->buffer_mutex);
+	atomic_set(&chip->data_pending, 0);
+	memset(chip->data_buffer, 0, TPM_BUFSIZE);
+	up(&chip->buffer_mutex);
+}
+
+void tpm_time_expired(unsigned long ptr)
+{
+	int *exp = (int *) ptr;
+	*exp = 1;
+}
+
+EXPORT_SYMBOL_GPL(tpm_time_expired);
+
+/*
+ * Initialize the LPC bus and enable the TPM ports
+ */
+int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base)
+{
+	u32 lpcenable, tmp;
+	int is_lpcm = 0;
+
+	switch (pci_dev->vendor) {
+	case PCI_VENDOR_ID_INTEL:
+		switch (pci_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801CA_12:
+		case PCI_DEVICE_ID_INTEL_82801DB_12:
+			is_lpcm = 1;
+			break;
+		}
+		/* init ICH (enable LPC) */
+		pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable);
+		lpcenable |= 0x20000000;
+		pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable);
+
+		if (is_lpcm) {
+			pci_read_config_dword(pci_dev, PCI_GEN1_DEC,
+					      &lpcenable);
+			if ((lpcenable & 0x20000000) == 0) {
+				dev_err(&pci_dev->dev,
+					"cannot enable LPC\n");
+				return -ENODEV;
+			}
+		}
+
+		/* initialize TPM registers */
+		pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp);
+
+		if (!is_lpcm)
+			tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0);
+		else
+			tmp =
+			    (tmp & 0xFFFF0000) | (base & 0xFFF0) |
+			    0x00000001;
+
+		pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp);
+
+		if (is_lpcm) {
+			pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1,
+					      &tmp);
+			tmp |= 0x00000004;	/* enable CLKRUN */
+			pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1,
+					       tmp);
+		}
+		tpm_write_index(0x0D, 0x55);	/* unlock 4F */
+		tpm_write_index(0x0A, 0x00);	/* int disable */
+		tpm_write_index(0x08, base);	/* base addr lo */
+		tpm_write_index(0x09, (base & 0xFF00) >> 8);	/* base addr hi */
+		tpm_write_index(0x0D, 0xAA);	/* lock 4F */
+		break;
+	case PCI_VENDOR_ID_AMD:
+		/* nothing yet */
+		break;
+	}
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_lpc_bus_init);
+
+/*
+ * Internal kernel interface to transmit TPM commands
+ */
+static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
+			    size_t bufsiz)
+{
+	ssize_t len;
+	u32 count;
+	__be32 *native_size;
+
+	native_size = (__force __be32 *) (buf + 2);
+	count = be32_to_cpu(*native_size);
+
+	if (count == 0)
+		return -ENODATA;
+	if (count > bufsiz) {
+		dev_err(&chip->pci_dev->dev,
+			"invalid count value %x %zx \n", count, bufsiz);
+		return -E2BIG;
+	}
+
+	down(&chip->tpm_mutex);
+
+	if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+		dev_err(&chip->pci_dev->dev,
+			"tpm_transmit: tpm_send: error %zd\n", len);
+		return len;
+	}
+
+	down(&chip->timer_manipulation_mutex);
+	chip->time_expired = 0;
+	init_timer(&chip->device_timer);
+	chip->device_timer.function = tpm_time_expired;
+	chip->device_timer.expires = jiffies + 2 * 60 * HZ;
+	chip->device_timer.data = (unsigned long) &chip->time_expired;
+	add_timer(&chip->device_timer);
+	up(&chip->timer_manipulation_mutex);
+
+	do {
+		u8 status = inb(chip->vendor->base + 1);
+		if ((status & chip->vendor->req_complete_mask) ==
+		    chip->vendor->req_complete_val) {
+			down(&chip->timer_manipulation_mutex);
+			del_singleshot_timer_sync(&chip->device_timer);
+			up(&chip->timer_manipulation_mutex);
+			goto out_recv;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(TPM_TIMEOUT);
+		rmb();
+	} while (!chip->time_expired);
+
+
+	chip->vendor->cancel(chip);
+	dev_err(&chip->pci_dev->dev, "Time expired\n");
+	up(&chip->tpm_mutex);
+	return -EIO;
+
+out_recv:
+	len = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+	if (len < 0)
+		dev_err(&chip->pci_dev->dev,
+			"tpm_transmit: tpm_recv: error %zd\n", len);
+	up(&chip->tpm_mutex);
+	return len;
+}
+
+#define TPM_DIGEST_SIZE 20
+#define CAP_PCR_RESULT_SIZE 18
+static u8 cap_pcr[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 22,		/* length */
+	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
+	0, 0, 0, 5,
+	0, 0, 0, 4,
+	0, 0, 1, 1
+};
+
+#define READ_PCR_RESULT_SIZE 30
+static u8 pcrread[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 14,		/* length */
+	0, 0, 0, 21,		/* TPM_ORD_PcrRead */
+	0, 0, 0, 0		/* PCR index */
+};
+
+static ssize_t show_pcrs(struct device *dev, char *buf)
+{
+	u8 data[READ_PCR_RESULT_SIZE];
+	ssize_t len;
+	int i, j, index, num_pcrs;
+	char *str = buf;
+
+	struct tpm_chip *chip =
+	    pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+	if (chip == NULL)
+		return -ENODEV;
+
+	memcpy(data, cap_pcr, sizeof(cap_pcr));
+	if ((len = tpm_transmit(chip, data, sizeof(data)))
+	    < CAP_PCR_RESULT_SIZE)
+		return len;
+
+	num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14)));
+
+	for (i = 0; i < num_pcrs; i++) {
+		memcpy(data, pcrread, sizeof(pcrread));
+		index = cpu_to_be32(i);
+		memcpy(data + 10, &index, 4);
+		if ((len = tpm_transmit(chip, data, sizeof(data)))
+		    < READ_PCR_RESULT_SIZE)
+			return len;
+		str += sprintf(str, "PCR-%02d: ", i);
+		for (j = 0; j < TPM_DIGEST_SIZE; j++)
+			str += sprintf(str, "%02X ", *(data + 10 + j));
+		str += sprintf(str, "\n");
+	}
+	return str - buf;
+}
+
+static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL);
+
+#define  READ_PUBEK_RESULT_SIZE 314
+static u8 readpubek[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 30,		/* length */
+	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
+};
+
+static ssize_t show_pubek(struct device *dev, char *buf)
+{
+	u8 data[READ_PUBEK_RESULT_SIZE];
+	ssize_t len;
+	__be32 *native_val;
+	int i;
+	char *str = buf;
+
+	struct tpm_chip *chip =
+	    pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+	if (chip == NULL)
+		return -ENODEV;
+
+	memcpy(data, readpubek, sizeof(readpubek));
+	memset(data + sizeof(readpubek), 0, 20);	/* zero nonce */
+
+	if ((len = tpm_transmit(chip, data, sizeof(data))) <
+	    READ_PUBEK_RESULT_SIZE)
+		return len;
+
+	/* 
+	   ignore header 10 bytes
+	   algorithm 32 bits (1 == RSA )
+	   encscheme 16 bits
+	   sigscheme 16 bits
+	   parameters (RSA 12->bytes: keybit, #primes, expbit)  
+	   keylenbytes 32 bits
+	   256 byte modulus
+	   ignore checksum 20 bytes
+	 */
+
+	native_val = (__force __be32 *) (data + 34);
+
+	str +=
+	    sprintf(str,
+		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+		    "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
+		    " %02X %02X %02X %02X %02X %02X %02X %02X\n"
+		    "Modulus length: %d\nModulus: \n",
+		    data[10], data[11], data[12], data[13], data[14],
+		    data[15], data[16], data[17], data[22], data[23],
+		    data[24], data[25], data[26], data[27], data[28],
+		    data[29], data[30], data[31], data[32], data[33],
+		    be32_to_cpu(*native_val)
+	    );
+
+	for (i = 0; i < 256; i++) {
+		str += sprintf(str, "%02X ", data[i + 39]);
+		if ((i + 1) % 16 == 0)
+			str += sprintf(str, "\n");
+	}
+	return str - buf;
+}
+
+static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL);
+
+#define CAP_VER_RESULT_SIZE 18
+static u8 cap_version[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 18,		/* length */
+	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
+	0, 0, 0, 6,
+	0, 0, 0, 0
+};
+
+#define CAP_MANUFACTURER_RESULT_SIZE 18
+static u8 cap_manufacturer[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 22,		/* length */
+	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
+	0, 0, 0, 5,
+	0, 0, 0, 4,
+	0, 0, 1, 3
+};
+
+static ssize_t show_caps(struct device *dev, char *buf)
+{
+	u8 data[READ_PUBEK_RESULT_SIZE];
+	ssize_t len;
+	char *str = buf;
+
+	struct tpm_chip *chip =
+	    pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+	if (chip == NULL)
+		return -ENODEV;
+
+	memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
+
+	if ((len = tpm_transmit(chip, data, sizeof(data))) <
+	    CAP_MANUFACTURER_RESULT_SIZE)
+		return len;
+
+	str += sprintf(str, "Manufacturer: 0x%x\n",
+		       be32_to_cpu(*(data + 14)));
+
+	memcpy(data, cap_version, sizeof(cap_version));
+
+	if ((len = tpm_transmit(chip, data, sizeof(data))) <
+	    CAP_VER_RESULT_SIZE)
+		return len;
+
+	str +=
+	    sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
+		    (int) data[14], (int) data[15], (int) data[16],
+		    (int) data[17]);
+
+	return str - buf;
+}
+
+static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL);
+
+/*
+ * Device file system interface to the TPM
+ */
+int tpm_open(struct inode *inode, struct file *file)
+{
+	int rc = 0, minor = iminor(inode);
+	struct tpm_chip *chip = NULL, *pos;
+
+	spin_lock(&driver_lock);
+
+	list_for_each_entry(pos, &tpm_chip_list, list) {
+		if (pos->vendor->miscdev.minor == minor) {
+			chip = pos;
+			break;
+		}
+	}
+
+	if (chip == NULL) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	if (chip->num_opens) {
+		dev_dbg(&chip->pci_dev->dev,
+			"Another process owns this TPM\n");
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	chip->num_opens++;
+	pci_dev_get(chip->pci_dev);
+
+	spin_unlock(&driver_lock);
+
+	chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+	if (chip->data_buffer == NULL) {
+		chip->num_opens--;
+		pci_dev_put(chip->pci_dev);
+		return -ENOMEM;
+	}
+
+	atomic_set(&chip->data_pending, 0);
+
+	file->private_data = chip;
+	return 0;
+
+err_out:
+	spin_unlock(&driver_lock);
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(tpm_open);
+
+int tpm_release(struct inode *inode, struct file *file)
+{
+	struct tpm_chip *chip = file->private_data;
+	
+	file->private_data = NULL;
+
+	spin_lock(&driver_lock);
+	chip->num_opens--;
+	spin_unlock(&driver_lock);
+
+	down(&chip->timer_manipulation_mutex);
+	if (timer_pending(&chip->user_read_timer))
+		del_singleshot_timer_sync(&chip->user_read_timer);
+	else if (timer_pending(&chip->device_timer))
+		del_singleshot_timer_sync(&chip->device_timer);
+	up(&chip->timer_manipulation_mutex);
+
+	kfree(chip->data_buffer);
+	atomic_set(&chip->data_pending, 0);
+
+	pci_dev_put(chip->pci_dev);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_release);
+
+ssize_t tpm_write(struct file * file, const char __user * buf,
+		  size_t size, loff_t * off)
+{
+	struct tpm_chip *chip = file->private_data;
+	int in_size = size, out_size;
+
+	/* cannot perform a write until the read has cleared
+	   either via tpm_read or a user_read_timer timeout */
+	while (atomic_read(&chip->data_pending) != 0) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(TPM_TIMEOUT);
+	}
+
+	down(&chip->buffer_mutex);
+
+	if (in_size > TPM_BUFSIZE)
+		in_size = TPM_BUFSIZE;
+
+	if (copy_from_user
+	    (chip->data_buffer, (void __user *) buf, in_size)) {
+		up(&chip->buffer_mutex);
+		return -EFAULT;
+	}
+
+	/* atomic tpm command send and result receive */
+	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
+
+	atomic_set(&chip->data_pending, out_size);
+	up(&chip->buffer_mutex);
+
+	/* Set a timeout by which the reader must come claim the result */
+	down(&chip->timer_manipulation_mutex);
+	init_timer(&chip->user_read_timer);
+	chip->user_read_timer.function = user_reader_timeout;
+	chip->user_read_timer.data = (unsigned long) chip;
+	chip->user_read_timer.expires = jiffies + (60 * HZ);
+	add_timer(&chip->user_read_timer);
+	up(&chip->timer_manipulation_mutex);
+
+	return in_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_write);
+
+ssize_t tpm_read(struct file * file, char __user * buf,
+		 size_t size, loff_t * off)
+{
+	struct tpm_chip *chip = file->private_data;
+	int ret_size = -ENODATA;
+
+	if (atomic_read(&chip->data_pending) != 0) {	/* Result available */
+		down(&chip->timer_manipulation_mutex);
+		del_singleshot_timer_sync(&chip->user_read_timer);
+		up(&chip->timer_manipulation_mutex);
+
+		down(&chip->buffer_mutex);
+
+		ret_size = atomic_read(&chip->data_pending);
+		atomic_set(&chip->data_pending, 0);
+
+		if (ret_size == 0)	/* timeout just occurred */
+			ret_size = -ETIME;
+		else if (ret_size > 0) {	/* relay data */
+			if (size < ret_size)
+				ret_size = size;
+
+			if (copy_to_user((void __user *) buf,
+					 chip->data_buffer, ret_size)) {
+				ret_size = -EFAULT;
+			}
+		}
+		up(&chip->buffer_mutex);
+	}
+
+	return ret_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_read);
+
+void __devexit tpm_remove(struct pci_dev *pci_dev)
+{
+	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+	if (chip == NULL) {
+		dev_err(&pci_dev->dev, "No device data found\n");
+		return;
+	}
+
+	spin_lock(&driver_lock);
+
+	list_del(&chip->list);
+
+	spin_unlock(&driver_lock);
+
+	pci_set_drvdata(pci_dev, NULL);
+	misc_deregister(&chip->vendor->miscdev);
+
+	device_remove_file(&pci_dev->dev, &dev_attr_pubek);
+	device_remove_file(&pci_dev->dev, &dev_attr_pcrs);
+	device_remove_file(&pci_dev->dev, &dev_attr_caps);
+
+	pci_disable_device(pci_dev);
+
+	dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32));
+
+	kfree(chip);
+
+	pci_dev_put(pci_dev);
+}
+
+EXPORT_SYMBOL_GPL(tpm_remove);
+
+static u8 savestate[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 10,		/* blob length (in bytes) */
+	0, 0, 0, 152		/* TPM_ORD_SaveState */
+};
+
+/*
+ * We are about to suspend. Save the TPM state
+ * so that it can be restored.
+ */
+int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state)
+{
+	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+	if (chip == NULL)
+		return -ENODEV;
+
+	tpm_transmit(chip, savestate, sizeof(savestate));
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_suspend);
+
+/*
+ * Resume from a power safe. The BIOS already restored
+ * the TPM state.
+ */
+int tpm_pm_resume(struct pci_dev *pci_dev)
+{
+	struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+	if (chip == NULL)
+		return -ENODEV;
+
+	spin_lock(&driver_lock);
+	tpm_lpc_bus_init(pci_dev, chip->vendor->base);
+	spin_unlock(&driver_lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_resume);
+
+/*
+ * Called from tpm_<specific>.c probe function only for devices 
+ * the driver has determined it should claim.  Prior to calling
+ * this function the specific probe function has called pci_enable_device
+ * upon errant exit from this function specific probe function should call
+ * pci_disable_device
+ */
+int tpm_register_hardware(struct pci_dev *pci_dev,
+			  struct tpm_vendor_specific *entry)
+{
+	char devname[7];
+	struct tpm_chip *chip;
+	int i, j;
+
+	/* Driver specific per-device data */
+	chip = kmalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	memset(chip, 0, sizeof(struct tpm_chip));
+
+	init_MUTEX(&chip->buffer_mutex);
+	init_MUTEX(&chip->tpm_mutex);
+	init_MUTEX(&chip->timer_manipulation_mutex);
+	INIT_LIST_HEAD(&chip->list);
+
+	chip->vendor = entry;
+
+	chip->dev_num = -1;
+
+	for (i = 0; i < 32; i++)
+		for (j = 0; j < 8; j++)
+			if ((dev_mask[i] & (1 << j)) == 0) {
+				chip->dev_num = i * 32 + j;
+				dev_mask[i] |= 1 << j;
+				goto dev_num_search_complete;
+			}
+
+dev_num_search_complete:
+	if (chip->dev_num < 0) {
+		dev_err(&pci_dev->dev,
+			"No available tpm device numbers\n");
+		kfree(chip);
+		return -ENODEV;
+	} else if (chip->dev_num == 0)
+		chip->vendor->miscdev.minor = TPM_MINOR;
+	else
+		chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
+
+	snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
+	chip->vendor->miscdev.name = devname;
+
+	chip->vendor->miscdev.dev = &(pci_dev->dev);
+	chip->pci_dev = pci_dev_get(pci_dev);
+
+	if (misc_register(&chip->vendor->miscdev)) {
+		dev_err(&chip->pci_dev->dev,
+			"unable to misc_register %s, minor %d\n",
+			chip->vendor->miscdev.name,
+			chip->vendor->miscdev.minor);
+		pci_dev_put(pci_dev);
+		kfree(chip);
+		dev_mask[i] &= !(1 << j);
+		return -ENODEV;
+	}
+
+	pci_set_drvdata(pci_dev, chip);
+
+	list_add(&chip->list, &tpm_chip_list);
+
+	device_create_file(&pci_dev->dev, &dev_attr_pubek);
+	device_create_file(&pci_dev->dev, &dev_attr_pcrs);
+	device_create_file(&pci_dev->dev, &dev_attr_caps);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
+
+static int __init init_tpm(void)
+{
+	return 0;
+}
+
+static void __exit cleanup_tpm(void)
+{
+
+}
+
+module_init(init_tpm);
+module_exit(cleanup_tpm);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/tpm.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
+ * License.
+ * 
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+#define TPM_TIMEOUT msecs_to_jiffies(5)
+
+/* TPM addresses */
+#define	TPM_ADDR			0x4E
+#define	TPM_DATA			0x4F
+
+struct tpm_chip;
+
+struct tpm_vendor_specific {
+	u8 req_complete_mask;
+	u8 req_complete_val;
+	u16 base;		/* TPM base address */
+
+	int (*recv) (struct tpm_chip *, u8 *, size_t);
+	int (*send) (struct tpm_chip *, u8 *, size_t);
+	void (*cancel) (struct tpm_chip *);
+	struct miscdevice miscdev;
+};
+
+struct tpm_chip {
+	struct pci_dev *pci_dev;	/* PCI device stuff */
+
+	int dev_num;		/* /dev/tpm# */
+	int num_opens;		/* only one allowed */
+	int time_expired;
+
+	/* Data passed to and from the tpm via the read/write calls */
+	u8 *data_buffer;
+	atomic_t data_pending;
+	struct semaphore buffer_mutex;
+
+	struct timer_list user_read_timer;	/* user needs to claim result */
+	struct semaphore tpm_mutex;	/* tpm is processing */
+	struct timer_list device_timer;	/* tpm is processing */
+	struct semaphore timer_manipulation_mutex;
+
+	struct tpm_vendor_specific *vendor;
+
+	struct list_head list;
+};
+
+static inline int tpm_read_index(int index)
+{
+	outb(index, TPM_ADDR);
+	return inb(TPM_DATA) & 0xFF;
+}
+
+static inline void tpm_write_index(int index, int value)
+{
+	outb(index, TPM_ADDR);
+	outb(value & 0xFF, TPM_DATA);
+}
+
+extern void tpm_time_expired(unsigned long);
+extern int tpm_lpc_bus_init(struct pci_dev *, u16);
+
+extern int tpm_register_hardware(struct pci_dev *,
+				 struct tpm_vendor_specific *);
+extern int tpm_open(struct inode *, struct file *);
+extern int tpm_release(struct inode *, struct file *);
+extern ssize_t tpm_write(struct file *, const char __user *, size_t,
+			 loff_t *);
+extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
+extern void __devexit tpm_remove(struct pci_dev *);
+extern int tpm_pm_suspend(struct pci_dev *, pm_message_t);
+extern int tpm_pm_resume(struct pci_dev *);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
+ * License.
+ * 
+ */
+
+#include "tpm.h"
+
+/* Atmel definitions */
+#define	TPM_ATML_BASE			0x400
+
+/* write status bits */
+#define	ATML_STATUS_ABORT		0x01
+#define	ATML_STATUS_LASTBYTE		0x04
+
+/* read status bits */
+#define	ATML_STATUS_BUSY		0x01
+#define	ATML_STATUS_DATA_AVAIL		0x02
+#define	ATML_STATUS_REWRITE		0x04
+
+
+static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+	u8 status, *hdr = buf;
+	u32 size;
+	int i;
+	__be32 *native_size;
+
+	/* start reading header */
+	if (count < 6)
+		return -EIO;
+
+	for (i = 0; i < 6; i++) {
+		status = inb(chip->vendor->base + 1);
+		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+			dev_err(&chip->pci_dev->dev,
+				"error reading header\n");
+			return -EIO;
+		}
+		*buf++ = inb(chip->vendor->base);
+	}
+
+	/* size of the data received */
+	native_size = (__force __be32 *) (hdr + 2);
+	size = be32_to_cpu(*native_size);
+
+	if (count < size) {
+		dev_err(&chip->pci_dev->dev,
+			"Recv size(%d) less than available space\n", size);
+		for (; i < size; i++) {	/* clear the waiting data anyway */
+			status = inb(chip->vendor->base + 1);
+			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+				dev_err(&chip->pci_dev->dev,
+					"error reading data\n");
+				return -EIO;
+			}
+		}
+		return -EIO;
+	}
+
+	/* read all the data available */
+	for (; i < size; i++) {
+		status = inb(chip->vendor->base + 1);
+		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+			dev_err(&chip->pci_dev->dev,
+				"error reading data\n");
+			return -EIO;
+		}
+		*buf++ = inb(chip->vendor->base);
+	}
+
+	/* make sure data available is gone */
+	status = inb(chip->vendor->base + 1);
+	if (status & ATML_STATUS_DATA_AVAIL) {
+		dev_err(&chip->pci_dev->dev, "data available is stuck\n");
+		return -EIO;
+	}
+
+	return size;
+}
+
+static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+	int i;
+
+	dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: ");
+	for (i = 0; i < count; i++) {
+		dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]);
+		outb(buf[i], chip->vendor->base);
+	}
+
+	return count;
+}
+
+static void tpm_atml_cancel(struct tpm_chip *chip)
+{
+	outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+}
+
+static struct file_operations atmel_ops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = tpm_open,
+	.read = tpm_read,
+	.write = tpm_write,
+	.release = tpm_release,
+};
+
+static struct tpm_vendor_specific tpm_atmel = {
+	.recv = tpm_atml_recv,
+	.send = tpm_atml_send,
+	.cancel = tpm_atml_cancel,
+	.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
+	.req_complete_val = ATML_STATUS_DATA_AVAIL,
+	.base = TPM_ATML_BASE,
+	.miscdev = { .fops = &atmel_ops, },
+};
+
+static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
+				   const struct pci_device_id *pci_id)
+{
+	u8 version[4];
+	int rc = 0;
+
+	if (pci_enable_device(pci_dev))
+		return -EIO;
+
+	if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
+		rc = -ENODEV;
+		goto out_err;
+	}
+
+	/* verify that it is an Atmel part */
+	if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
+	    || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
+		rc = -ENODEV;
+		goto out_err;
+	}
+
+	/* query chip for its version number */
+	if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
+		version[1] = tpm_read_index(0x01);
+		version[2] = tpm_read_index(0x02);
+		version[3] = tpm_read_index(0x03);
+	} else {
+		dev_info(&pci_dev->dev, "version query failed\n");
+		rc = -ENODEV;
+		goto out_err;
+	}
+
+	if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0)
+		goto out_err;
+
+	dev_info(&pci_dev->dev,
+		 "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1],
+		 version[2], version[3]);
+
+	return 0;
+out_err:
+	pci_disable_device(pci_dev);
+	return rc;
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver atmel_pci_driver = {
+	.name = "tpm_atmel",
+	.id_table = tpm_pci_tbl,
+	.probe = tpm_atml_init,
+	.remove = __devexit_p(tpm_remove),
+	.suspend = tpm_pm_suspend,
+	.resume = tpm_pm_resume,
+};
+
+static int __init init_atmel(void)
+{
+	return pci_register_driver(&atmel_pci_driver);
+}
+
+static void __exit cleanup_atmel(void)
+{
+	pci_unregister_driver(&atmel_pci_driver);
+}
+
+module_init(init_atmel);
+module_exit(cleanup_atmel);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
+ * License.
+ * 
+ */
+
+#include "tpm.h"
+
+/* National definitions */
+#define	TPM_NSC_BASE			0x360
+#define	TPM_NSC_IRQ			0x07
+
+#define	NSC_LDN_INDEX			0x07
+#define	NSC_SID_INDEX			0x20
+#define	NSC_LDC_INDEX			0x30
+#define	NSC_DIO_INDEX			0x60
+#define	NSC_CIO_INDEX			0x62
+#define	NSC_IRQ_INDEX			0x70
+#define	NSC_ITS_INDEX			0x71
+
+#define	NSC_STATUS			0x01
+#define	NSC_COMMAND			0x01
+#define	NSC_DATA			0x00
+
+/* status bits */
+#define	NSC_STATUS_OBF			0x01	/* output buffer full */
+#define	NSC_STATUS_IBF			0x02	/* input buffer full */
+#define	NSC_STATUS_F0			0x04	/* F0 */
+#define	NSC_STATUS_A2			0x08	/* A2 */
+#define	NSC_STATUS_RDY			0x10	/* ready to receive command */
+#define	NSC_STATUS_IBR			0x20	/* ready to receive data */
+
+/* command bits */
+#define	NSC_COMMAND_NORMAL		0x01	/* normal mode */
+#define	NSC_COMMAND_EOC			0x03
+#define	NSC_COMMAND_CANCEL		0x22
+
+/*
+ * Wait for a certain status to appear
+ */
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
+{
+	int expired = 0;
+	struct timer_list status_timer =
+	    TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ,
+			      (unsigned long) &expired);
+
+	/* status immediately available check */
+	*data = inb(chip->vendor->base + NSC_STATUS);
+	if ((*data & mask) == val)
+		return 0;
+
+	/* wait for status */
+	add_timer(&status_timer);
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(TPM_TIMEOUT);
+		*data = inb(chip->vendor->base + 1);
+		if ((*data & mask) == val) {
+			del_singleshot_timer_sync(&status_timer);
+			return 0;
+		}
+	}
+	while (!expired);
+
+	return -EBUSY;
+}
+
+static int nsc_wait_for_ready(struct tpm_chip *chip)
+{
+	int status;
+	int expired = 0;
+	struct timer_list status_timer =
+	    TIMER_INITIALIZER(tpm_time_expired, jiffies + 100,
+			      (unsigned long) &expired);
+
+	/* status immediately available check */
+	status = inb(chip->vendor->base + NSC_STATUS);
+	if (status & NSC_STATUS_OBF)
+		status = inb(chip->vendor->base + NSC_DATA);
+	if (status & NSC_STATUS_RDY)
+		return 0;
+
+	/* wait for status */
+	add_timer(&status_timer);
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(TPM_TIMEOUT);
+		status = inb(chip->vendor->base + NSC_STATUS);
+		if (status & NSC_STATUS_OBF)
+			status = inb(chip->vendor->base + NSC_DATA);
+		if (status & NSC_STATUS_RDY) {
+			del_singleshot_timer_sync(&status_timer);
+			return 0;
+		}
+	}
+	while (!expired);
+
+	dev_info(&chip->pci_dev->dev, "wait for ready failed\n");
+	return -EBUSY;
+}
+
+
+static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+	u8 *buffer = buf;
+	u8 data, *p;
+	u32 size;
+	__be32 *native_size;
+
+	if (count < 6)
+		return -EIO;
+
+	if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
+		dev_err(&chip->pci_dev->dev, "F0 timeout\n");
+		return -EIO;
+	}
+	if ((data =
+	     inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
+		dev_err(&chip->pci_dev->dev, "not in normal mode (0x%x)\n",
+			data);
+		return -EIO;
+	}
+
+	/* read the whole packet */
+	for (p = buffer; p < &buffer[count]; p++) {
+		if (wait_for_stat
+		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
+			dev_err(&chip->pci_dev->dev,
+				"OBF timeout (while reading data)\n");
+			return -EIO;
+		}
+		if (data & NSC_STATUS_F0)
+			break;
+		*p = inb(chip->vendor->base + NSC_DATA);
+	}
+
+	if ((data & NSC_STATUS_F0) == 0) {
+		dev_err(&chip->pci_dev->dev, "F0 not set\n");
+		return -EIO;
+	}
+	if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
+		dev_err(&chip->pci_dev->dev,
+			"expected end of command(0x%x)\n", data);
+		return -EIO;
+	}
+
+	native_size = (__force __be32 *) (buf + 2);
+	size = be32_to_cpu(*native_size);
+
+	if (count < size)
+		return -EIO;
+
+	return size;
+}
+
+static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+	u8 data;
+	int i;
+
+	/*
+	 * If we hit the chip with back to back commands it locks up
+	 * and never set IBF. Hitting it with this "hammer" seems to
+	 * fix it. Not sure why this is needed, we followed the flow
+	 * chart in the manual to the letter.
+	 */
+	outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+
+	if (nsc_wait_for_ready(chip) != 0)
+		return -EIO;
+
+	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+		dev_err(&chip->pci_dev->dev, "IBF timeout\n");
+		return -EIO;
+	}
+
+	outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
+	if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
+		dev_err(&chip->pci_dev->dev, "IBR timeout\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+			dev_err(&chip->pci_dev->dev,
+				"IBF timeout (while writing data)\n");
+			return -EIO;
+		}
+		outb(buf[i], chip->vendor->base + NSC_DATA);
+	}
+
+	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+		dev_err(&chip->pci_dev->dev, "IBF timeout\n");
+		return -EIO;
+	}
+	outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
+
+	return count;
+}
+
+static void tpm_nsc_cancel(struct tpm_chip *chip)
+{
+	outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+}
+
+static struct file_operations nsc_ops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = tpm_open,
+	.read = tpm_read,
+	.write = tpm_write,
+	.release = tpm_release,
+};
+
+static struct tpm_vendor_specific tpm_nsc = {
+	.recv = tpm_nsc_recv,
+	.send = tpm_nsc_send,
+	.cancel = tpm_nsc_cancel,
+	.req_complete_mask = NSC_STATUS_OBF,
+	.req_complete_val = NSC_STATUS_OBF,
+	.base = TPM_NSC_BASE,
+	.miscdev = { .fops = &nsc_ops, },
+	
+};
+
+static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
+				  const struct pci_device_id *pci_id)
+{
+	int rc = 0;
+
+	if (pci_enable_device(pci_dev))
+		return -EIO;
+
+	if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) {
+		rc = -ENODEV;
+		goto out_err;
+	}
+
+	/* verify that it is a National part (SID) */
+	if (tpm_read_index(NSC_SID_INDEX) != 0xEF) {
+		rc = -ENODEV;
+		goto out_err;
+	}
+
+	dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
+	dev_dbg(&pci_dev->dev,
+		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
+		tpm_read_index(0x07), tpm_read_index(0x20),
+		tpm_read_index(0x27));
+	dev_dbg(&pci_dev->dev,
+		"NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
+		tpm_read_index(0x21), tpm_read_index(0x25),
+		tpm_read_index(0x26), tpm_read_index(0x28));
+	dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
+		(tpm_read_index(0x60) << 8) | tpm_read_index(0x61));
+	dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
+		(tpm_read_index(0x62) << 8) | tpm_read_index(0x63));
+	dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
+		tpm_read_index(0x70));
+	dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
+		tpm_read_index(0x71));
+	dev_dbg(&pci_dev->dev,
+		"NSC DMA channel select0 0x%x, select1 0x%x\n",
+		tpm_read_index(0x74), tpm_read_index(0x75));
+	dev_dbg(&pci_dev->dev,
+		"NSC Config "
+		"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+		tpm_read_index(0xF0), tpm_read_index(0xF1),
+		tpm_read_index(0xF2), tpm_read_index(0xF3),
+		tpm_read_index(0xF4), tpm_read_index(0xF5),
+		tpm_read_index(0xF6), tpm_read_index(0xF7),
+		tpm_read_index(0xF8), tpm_read_index(0xF9));
+
+	dev_info(&pci_dev->dev,
+		 "NSC PC21100 TPM revision %d\n",
+		 tpm_read_index(0x27) & 0x1F);
+
+	if (tpm_read_index(NSC_LDC_INDEX) == 0)
+		dev_info(&pci_dev->dev, ": NSC TPM not active\n");
+
+	/* select PM channel 1 */
+	tpm_write_index(NSC_LDN_INDEX, 0x12);
+	tpm_read_index(NSC_LDN_INDEX);
+
+	/* disable the DPM module */
+	tpm_write_index(NSC_LDC_INDEX, 0);
+	tpm_read_index(NSC_LDC_INDEX);
+
+	/* set the data register base addresses */
+	tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8);
+	tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE);
+	tpm_read_index(NSC_DIO_INDEX);
+	tpm_read_index(NSC_DIO_INDEX + 1);
+
+	/* set the command register base addresses */
+	tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8);
+	tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1));
+	tpm_read_index(NSC_DIO_INDEX);
+	tpm_read_index(NSC_DIO_INDEX + 1);
+
+	/* set the interrupt number to be used for the host interface */
+	tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ);
+	tpm_write_index(NSC_ITS_INDEX, 0x00);
+	tpm_read_index(NSC_IRQ_INDEX);
+
+	/* enable the DPM module */
+	tpm_write_index(NSC_LDC_INDEX, 0x01);
+	tpm_read_index(NSC_LDC_INDEX);
+
+	if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	pci_disable_device(pci_dev);
+	return rc;
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver nsc_pci_driver = {
+	.name = "tpm_nsc",
+	.id_table = tpm_pci_tbl,
+	.probe = tpm_nsc_init,
+	.remove = __devexit_p(tpm_remove),
+	.suspend = tpm_pm_suspend,
+	.resume = tpm_pm_resume,
+};
+
+static int __init init_nsc(void)
+{
+	return pci_register_driver(&nsc_pci_driver);
+}
+
+static void __exit cleanup_nsc(void)
+{
+	pci_unregister_driver(&nsc_pci_driver);
+}
+
+module_init(init_nsc);
+module_exit(cleanup_nsc);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
deleted file mode 100644
--- a/drivers/char/tpqic02.c
+++ /dev/null
@@ -1,2812 +0,0 @@
-/* $Id: tpqic02.c,v 1.10 1997/01/26 07:13:20 davem Exp $
- *
- * Driver for tape drive support for Linux-i386
- *
- * Copyright (c) 1992--1996 by H. H. Bergman. All rights reserved.
- * Current e-mail address: hennus@cybercomm.nl
- *
- * Distribution of this program in executable form is only allowed if
- * all of the corresponding source files are made available through the same
- * medium at no extra cost.
- *
- * I will not accept any responsibility for damage caused directly or
- * indirectly by this program, or code derived from this program.
- *
- * Use this code at your own risk. Don't blame me if it destroys your data!
- * Make sure you have a backup before you try this code.
- *
- * If you make changes to my code and redistribute it in source or binary
- * form you must make it clear to even casual users of your code that you
- * have modified my code, clearly point out what the changes exactly are
- * (preferably in the form of a context diff file), how to undo your changes,
- * where the original can be obtained, and that complaints/requests about the
- * modified code should be directed to you instead of me.
- *
- * This driver was partially inspired by the 'wt' driver in the 386BSD
- * source distribution, which carries the following copyright notice:
- *
- *  Copyright (c) 1991 The Regents of the University of California.
- *  All rights reserved.
- *
- * You are not allowed to change this line nor the text above.
- *
- * 2001/02/26	Minor s/suser/capable/
- *
- * 1996/10/10   Emerald changes
- *
- * 1996/05/21	Misc changes+merges+cleanups + I/O reservations
- *
- * 1996/05/20	Module support patches submitted by Brian McCauley.
- *
- * 1994/05/03	Initial attempt at Mountain support for the Mountain 7150.
- * Based on patches provided by Erik Jacobson. Still incomplete, I suppose.
- *
- * 1994/02/07	Archive changes & some cleanups by Eddy Olk.
- *
- * 1994/01/19	Speed measuring stuff moved from aperf.h to delay.h.
- *		BogoMips (tm) introduced by Linus.
- *
- * 1993/01/25	Kernel udelay. Eof fixups.
- * 
- * 1992/09/19	Some changes based on patches by Eddy Olk to support
- * 		Archive SC402/SC499R controller cards.
- *
- * 1992/05/27	First release.
- *
- * 1992/05/26	Initial version. Copyright H. H. Bergman 1992
- */
-
-/* After the legalese, now the important bits:
- * 
- * This is a driver for the Wangtek 5150 tape drive with 
- * a QIC-02 controller for ISA-PC type computers.
- * Hopefully it will work with other QIC-02 tape drives as well.
- *
- * Make sure your setup matches the configuration parameters.
- * Also, be careful to avoid IO conflicts with other devices!
- */
-
-
-/*
-#define TDEBUG
-*/
-
-#define REALLY_SLOW_IO		/* it sure is ... */
-
-#include <linux/module.h>
-
-#include <linux/config.h>
-
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/mtio.h>
-#include <linux/fcntl.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/tpqic02.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/device.h>
-
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-/* check existence of required configuration parameters */
-#if !defined(QIC02_CMD_PORT) || !defined(QIC02_TAPE_IRQ) || !defined(QIC02_TAPE_DMA)
-# error qic02_tape configuration error
-#endif
-
-
-#define TPQIC02_NAME	"tpqic02"
-
-/* Linux outb() commands have (value,port) as parameters.
- * One might expect (port,value) instead, so beware!
- */
-
-#ifdef CONFIG_QIC02_DYNCONF
-/* This holds the dynamic configuration info for the interface
- * card+drive info if runtime configuration has been selected.
- */
-
-static struct mtconfiginfo qic02_tape_dynconf =	 {
-	/* user settable */
-	0, 0, BOGUS_IRQ, 0, 0, TPQD_DEFAULT_FLAGS, 
-};
-static struct qic02_ccb qic02_tape_ccb;	/* private stuff */
-
-#else
-
-static unsigned long qic02_tape_debug = TPQD_DEFAULT_FLAGS;
-
-# if ((QIC02_TAPE_IFC!=WANGTEK) && (QIC02_TAPE_IFC!=ARCHIVE) && (QIC02_TAPE_IFC!=MOUNTAIN))
-#  error No valid interface card specified
-# endif
-#endif				/* CONFIG_QIC02_DYNCONF */
-
-static int ctlbits;	/* control reg bits for tape interface */
-
-static wait_queue_head_t qic02_tape_transfer;	/* sync rw with interrupts */
-
-static struct mtget ioctl_status;	/* current generic status */
-
-static struct tpstatus tperror;	/* last drive status */
-
-static char rcs_revision[] = "$Revision: 1.10 $";
-static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $";
-
-/* Flag bits for status and outstanding requests.
- * (Could all be put in one bit-field-struct.)
- * Some variables need `volatile' because they may be modified
- * by an interrupt.
- */
-static flag status_dead = YES;	/* device is legally dead until proven alive */
-static flag status_zombie = YES;	/* it's `zombie' until irq/dma allocated */
-
-static flag status_bytes_wr = NO;	/* write FM at close or not */
-static flag status_bytes_rd = NO;	/* (rd|wr) used for rewinding */
-
-static volatile unsigned long status_cmd_pending;	/* cmd in progress */
-static flag status_expect_int = NO;	/* ready for interrupts */
-static flag status_timer_on = NO;	/* using time-out */
-static int status_error;	/* int handler may detect error */
-static flag status_eof_detected = NO;	/* end of file */
-static flag status_eom_detected = NO;	/* end of recorded media */
-static flag status_eot_detected = NO;	/* end of tape */
-static flag doing_read = NO;
-static flag doing_write = NO;
-
-static unsigned long dma_bytes_todo;
-static unsigned long dma_bytes_done;
-static volatile unsigned dma_mode;	/* !=0 also means DMA in use */
-static flag need_rewind = YES;
-
-static int current_type;
-static int extra_blocks_left = BLOCKS_BEYOND_EW;
-static struct timer_list tp_timer;
-
-static unsigned long tape_open;		/* Guard open one only */
-static DECLARE_MUTEX(tape_op);		/* Serialize tape operations */
-
-/* return_*_eof:
- *	NO:	not at EOF,
- *	YES:	tell app EOF was reached (return 0).
- *
- * return_*_eof==YES && reported_*_eof==NO  ==>
- *	return current buffer, next time(s) return EOF.
- *
- * return_*_eof==YES && reported_*_eof==YES  ==>
- *	at EOF and application knows it, so we can
- *	move on to the next file.
- *
- */
- 
-static flag return_read_eof = NO;	/* set to signal app EOF was reached */
-static flag return_write_eof = NO;
-static flag reported_read_eof = NO;	/* set when we've done that */
-static flag reported_write_eof = NO;
-
-
-/* This is for doing `mt seek <blocknr>' */
-static char seek_addr_buf[AR_SEEK_BUF_SIZE];
-
-
-/* In write mode, we have to write a File Mark after the last block written, 
- * when the tape device is closed. Tape repositioning and reading in write
- * mode is allowed as long as no actual writing has been done. After writing
- * the File Mark, repositioning and reading are allowed again.
- */
-static int mode_access;		/* access mode: READ or WRITE */
-
-static int qic02_get_resources(void);
-static void qic02_release_resources(void);
-
-/* This is a pointer to the actual kernel buffer where the interrupt routines
- * read from/write to. It is needed because the DMA channels 1 and 3 cannot
- * always access the user buffers. [The kernel buffer must reside in the
- * lower 16MBytes of system memory because of the DMA controller.] The user
- * must ensure that a large enough buffer is passed to the kernel, in order
- * to reduce tape repositioning wear and tear.
- */
-static void *buffaddr;		/* virtual address of buffer */
-
-/* This translates minor numbers to the corresponding recording format: */
-static const char *format_names[] = {
-	"not set",		/* for dumb drives unable to handle format selection */
-	"11",			/* extinct */
-	"24",
-	"120",
-	"150",
-	"300",			/* untested. */
-	"600"			/* untested. */
-};
-
-static struct class_simple *tpqic02_class;
-
-
-/* `exception_list' is needed for exception status reporting.
- * Exceptions 1..14 are defined by QIC-02 rev F.
- * The drive status is matched sequentially to each entry,
- * ignoring irrelevant bits, until a match is found. If no
- * match is found, exception number 0 is used. (That should of
- * course never happen...) The original table was based on the
- * "Exception Status Summary" in QIC-02 rev F, but some changes
- * were required to make it work with real-world drives.
- *
- * Exception 2 (CNI) is changed to also cover status 0x00e0 (mask USL),
- * Exception 4 (EOM) is changed to also cover status 0x8288 (mask EOR),
- * Exception 11 (FIL) is changed to also cover status 0x0089 (mask EOM).
- * Exception 15 (EOR) is added for seek-to-end-of-data (catch EOR),
- * Exception 16 (BOM) is added for beginning-of-media (catch BOM).
- *
- * Had to swap EXC_NDRV and EXC_NCART to ensure that extended EXC_NCART
- * (because of the incorrect Wangtek status code) doesn't catch the
- * EXC_NDRV first.
- */
-static struct exception_list_type {
-	unsigned short mask, code;
-	const char *msg;
-	/* EXC_nr attribute should match with tpqic02.h */
-} exception_list[] = {
-	{ 0, 0, "Unknown exception status code", /* extra: 0 */ },
-	{ ~(0), TP_ST0 | TP_CNI | TP_USL | TP_WRP, "Drive not online" /* 1 */ }, /* Drive presence goes before cartridge presence. */
-	{ ~(TP_WRP | TP_USL), TP_ST0 | TP_CNI,
-		    /* My Wangtek 5150EQ sometimes reports a status code
-		     * of 0x00e0, which is not a valid exception code, but
-		     * I think it should be recognized as "NO CARTRIDGE".
-		     */
-			"Cartridge not in place" /* 2 */ },
-	{ (unsigned short) ~(TP_ST1 | TP_BOM), (TP_ST0 | TP_WRP), "Write protected cartridge" /* 3 */ },
-	{ (unsigned short) ~(TP_ST1 | TP_EOR), (TP_ST0 | TP_EOM), "End of media" /* 4 */ },
-	{ ~TP_WRP, TP_ST0 | TP_UDA | TP_ST1 | TP_BOM, "Read or Write abort. Rewind tape." /* 5 */ },
-	{ ~TP_WRP, TP_ST0 | TP_UDA, "Read error. Bad block transferred." /* 6 */ },
-	{ ~TP_WRP, TP_ST0 | TP_UDA | TP_BNL, "Read error. Filler block transferred." /* 7 */ },
-	{ ~TP_WRP, TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT, "Read error. No data detected." /* 8 */ },
-	{ ~TP_WRP, TP_ST0 | TP_EOM | TP_UDA | TP_BNL | TP_ST1 | TP_NDT, "Read error. No data detected. EOM." /* 9 */ },
-	{ ~(TP_WRP | TP_MBD | TP_PAR | TP_EOR), TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT | TP_BOM, "Read error. No data detected. BOM." /* 10 */ },
-	{ ~(TP_WRP | TP_EOM), TP_ST0 | TP_FIL,
-		    /* Status 0x0089 (EOM & FM) is viewed as an FM,
-		     * because it can only happen during a read.
-		     * EOM is checked separately for an FM condition.
-		     */
-			"File mark detected" /* 11 */ },
-	{ ~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM), TP_ST1 | TP_ILL, "Illegal command" /* 12 */ },
-	{ ~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM), TP_ST1 | TP_POR, "Reset occurred" /* 13 */ },
-	{ ~TP_WRP, TP_ST0 | TP_FIL | TP_MBD,	/* NOTE: ST1 not set! */ "Marginal block detected" /* 14 */ },
-	{ ~(TP_ST0 | TP_WRP | TP_EOM | TP_UDA | TP_BNL | TP_FIL |  TP_NDT), TP_ST1 | TP_EOR,	/********** Is the extra TP_NDT really needed Eddy? **********/ "End of recorded media" /* extra: 15 */ },
-	    /* 15 is returned when SEEKEOD completes successfully */
-	{ ~(TP_WRP | TP_ST0), TP_ST1 | TP_BOM, "Beginning of media" /* extra: 16 */ }
-};
-
-#define NR_OF_EXC	(sizeof(exception_list)/sizeof(struct exception_list_type))
-
-/* Compare expected struct size and actual struct size. This
- * is useful to catch programs compiled with old #includes.
- */
-#define CHECK_IOC_SIZE(structure) \
-	if (_IOC_SIZE(iocmd) != sizeof(struct structure)) { \
-		tpqputs(TPQD_ALWAYS, "sizeof(struct " #structure \
-			") does not match!"); \
-		return -EFAULT; \
-	} \
-
-static void tpqputs(unsigned long flags, const char *s)
-{
-	if ((flags & TPQD_ALWAYS) || (flags & QIC02_TAPE_DEBUG))
-		printk(TPQIC02_NAME ": %s\n", s);
-}				/* tpqputs */
-
-
-/* Init control register bits on interface card.
- * For Archive, interrupts must be enabled explicitly.
- * Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R
- * cards keep it active all the time.
- */
-
-static void ifc_init(void)
-{
-	if (QIC02_TAPE_IFC == WANGTEK) {	/* || (QIC02_TAPE_IFC == EVEREX) */
-		ctlbits = WT_CTL_ONLINE;	/* online */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-	} else if (QIC02_TAPE_IFC == ARCHIVE) {
-		ctlbits = 0;	/* no interrupts yet */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-		outb_p(0, AR_RESET_DMA_PORT);	/* dummy write to reset DMA */
-	} else {		/* MOUNTAIN */
-
-		ctlbits = MTN_CTL_ONLINE;	/* online, and logic enabled */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-	}
-}				/* ifc_init */
-
-
-static void report_qic_exception(unsigned n)
-{
-	if (n >= NR_OF_EXC) {
-		tpqputs(TPQD_ALWAYS, "Oops -- report_qic_exception");
-		n = 0;
-	}
-	if (TPQDBG(SENSE_TEXT) || n == 0)
-		printk(TPQIC02_NAME ": sense: %s\n", exception_list[n].msg);
-}				/* report_qic_exception */
-
-
-/* Try to map the drive-exception bits `s' to a predefined "exception number",
- * by comparing the significant exception bits for each entry in the
- * exception table (`exception_list[]').
- * It is assumed that s!=0.
- */
-static int decode_qic_exception_nr(unsigned s)
-{
-	int i;
-
-	for (i = 1; i < NR_OF_EXC; i++) {
-		if ((s & exception_list[i].mask) == exception_list[i].code) {
-			return i;
-		}
-	}
-	printk(TPQIC02_NAME ": decode_qic_exception_nr: exception(%x) not recognized\n", s);
-	return 0;
-}				/* decode_qic_exception_nr */
-
-
-
-/* Perform appropriate action for certain exceptions.
- * should return a value to indicate stop/continue (in case of bad blocks)
- */
-static void handle_qic_exception(int exnr, int exbits)
-{
-	if (exnr == EXC_NCART) {
-		/* Cartridge was changed. Redo sense().
-		 * EXC_NCART should be handled in open().
-		 * It is not permitted to remove the tape while
-		 * the tape driver has open files. 
-		 */
-		need_rewind = YES;
-		status_eof_detected = NO;
-		status_eom_detected = NO;
-	} else if (exnr == EXC_XFILLER) {
-		tpqputs(TPQD_ALWAYS,
-			"[Bad block -- filler data transferred.]");
-	} else if (exnr == EXC_XBAD) {
-		tpqputs(TPQD_ALWAYS, "[CRC failed!]");
-	} else if (exnr == EXC_MARGINAL) {
-		/* A marginal block behaves much like a FM.
-		 * User may continue reading, if desired.
-		 */
-		tpqputs(TPQD_ALWAYS, "[Marginal block]");
-		doing_read = NO;
-	} else if (exnr == EXC_FM) {
-		doing_read = NO;
-	}
-}				/* handle_qic_exception */
-
-
-static inline int is_exception(void)
-{
-	return (inb(QIC02_STAT_PORT) & QIC02_STAT_EXCEPTION) == 0;
-}				/* is_exception */
-
-
-/* Reset the tape drive and controller.
- * When reset fails, it marks  the drive as dead and all
- * requests (except reset) are to be ignored (ENXIO).
- */
-static int tape_reset(int verbose)
-{
-	ifc_init();		/* reset interface card */
-
-	/* assert reset */
-	if (QIC02_TAPE_IFC == MOUNTAIN) {
-		outb_p(ctlbits & ~MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
-	} else {		/* WANGTEK, ARCHIVE */
-
-		outb_p(ctlbits | QIC02_CTL_RESET, QIC02_CTL_PORT);
-	}
-
-	/* Next, we need to wait >=25 usec. */
-	udelay(30);
-
-	/* after reset, we will be at BOT (modulo an automatic rewind) */
-	status_eof_detected = NO;
-	status_eom_detected = NO;
-	status_cmd_pending = 0;
-	need_rewind = YES;
-	doing_read = doing_write = NO;
-	ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
-
-	/* de-assert reset */
-	if (QIC02_TAPE_IFC == MOUNTAIN) {
-		outb_p(ctlbits | MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
-	} else {
-		outb_p(ctlbits & ~QIC02_CTL_RESET, QIC02_CTL_PORT);
-	}
-
-	/* KLUDGE FOR G++ BUG */
-	{
-		int stat = inb_p(QIC02_STAT_PORT);
-		status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL);
-	}
-	/* if successful, inb(STAT) returned RESETVAL */
-	if (status_dead == YES)
-		printk(TPQIC02_NAME ": reset failed!\n");
-	else if (verbose)
-		printk(TPQIC02_NAME ": reset successful\n");
-
-	return (status_dead == YES) ? TE_DEAD : TE_OK;
-}				/* tape_reset */
-
-
-
-/* Notify tape drive of a new command. It only waits for the
- * command to be accepted, not for the actual command to complete.
- *
- * Before calling this routine, QIC02_CMD_PORT must have been loaded
- * with the command to be executed.
- * After this routine, the exception bit must be checked.
- * This routine is also used by rdstatus(), so in that case, any exception
- * must be ignored (`ignore_ex' flag).
- */
-static int notify_cmd(char cmd, short ignore_ex)
-{
-	int i;
-
-	outb_p(cmd, QIC02_CMD_PORT);	/* output the command */
-
-	/* wait 1 usec before asserting /REQUEST */
-	udelay(1);
-
-	if ((!ignore_ex) && is_exception()) {
-		tpqputs(TPQD_ALWAYS, "*** exception detected in notify_cmd");
-		/** force a reset here **/
-		if (tape_reset(1) == TE_DEAD)
-			return TE_DEAD;
-		if (is_exception()) {
-			tpqputs(TPQD_ALWAYS, "exception persists after reset.");
-			tpqputs(TPQD_ALWAYS, " ^ exception ignored.");
-		}
-	}
-
-	outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* set request bit */
-	i = TAPE_NOTIFY_TIMEOUT;
-	/* The specs say this takes about 500 usec, but there is no upper limit!
-	 * If the drive were busy retensioning or something like that,
-	 * it could be *much* longer!
-	 */
-	while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) && (--i > 0))
-		udelay(1);
-	/* wait for ready */
-	if (i == 0) {
-		tpqputs(TPQD_ALWAYS, "timed out waiting for ready in notify_cmd");
-		status_dead = YES;
-		return TE_TIM;
-	}
-
-	outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* reset request bit */
-	i = TAPE_NOTIFY_TIMEOUT;
-	/* according to the specs this one should never time-out */
-	while (((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0) && (--i > 0))
-		udelay(1);
-	/* wait for not ready */
-	if (i == 0) {
-		tpqputs(TPQD_ALWAYS, "timed out waiting for !ready in notify_cmd");
-		status_dead = YES;
-		return TE_TIM;
-	}
-	/* command accepted */
-	return TE_OK;
-}				/* notify_cmd */
-
-
-
-/* Wait for a command to complete, with timeout */
-static int wait_for_ready(time_t timeout)
-{
-	int stat;
-	unsigned long spin_t;
-
-	/* Wait for ready or exception, without driving the loadavg up too much.
-	 * In most cases, the tape drive already has READY asserted,
-	 * so optimize for that case.
-	 *
-	 * First, busy wait a few usec:
-	 */
-	spin_t = 50;
-	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (--spin_t > 0))
-		udelay(1);
-	if ((stat & QIC02_STAT_READY) == 0)
-		return TE_OK;	/* covers 99.99% of all calls */
-
-	/* Then use schedule() a few times */
-	spin_t = 3;		/* max 0.03 sec busy waiting */
-	if (spin_t > timeout)
-		spin_t = timeout;
-	timeout -= spin_t;
-	spin_t += jiffies;
-
-	/* FIXME...*/
-	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)  && time_before(jiffies, spin_t))
-	{
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);	/* don't waste all the CPU time */
-	}
-	if ((stat & QIC02_STAT_READY) == 0)
-		return TE_OK;
-
-	/* If we reach this point, we probably need to wait much longer, or
-	 * an exception occurred. Either case is not very time-critical.
-	 * Check the status port only a few times every second.
-	 * A interval of less than 0.10 sec will not be noticed by the user,
-	 * more than 0.40 sec may give noticeable delays.
-	 */
-	spin_t += timeout;
-	TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})
-
-	    /* not ready and no exception && timeout not expired yet */
-	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t)) {
-		/* be `nice` to other processes on long operations... */
-		/* nap 0.30 sec between checks, */
-		/* but could be woken up earlier by signals... */
-		msleep_interruptible(300);
-	}
-
-	/* don't use jiffies for this test because it may have changed by now */
-	if ((stat & QIC02_STAT_MASK) == QIC02_STAT_MASK) {
-		tpqputs(TPQD_ALWAYS, "wait_for_ready() timed out");
-		return TE_TIM;
-	}
-
-	if ((stat & QIC02_STAT_EXCEPTION) == 0) {
-		tpqputs(TPQD_ALWAYS, "exception detected after waiting_for_ready");
-		return TE_EX;
-	} else {
-		return TE_OK;
-	}
-}				/* wait_for_ready */
-
-
-
-/* Send some data to the drive */
-static int send_qic02_data(char sb[], unsigned size, int ignore_ex)
-{
-	int i, stat;
-
-	for (i = 0; i < size; i++) {
-		stat = wait_for_ready(TIM_S);
-		if (stat != TE_OK)
-			return stat;
-
-		stat = notify_cmd(sb[i], ignore_ex);
-		if (stat != TE_OK)
-			return stat;
-	}
-	return TE_OK;
-
-}				/* send_qic02_data */
-
-
-/* Send a QIC-02 command (`cmd') to the tape drive, with
- * a time-out (`timeout').
- * This one is also used by tp_sense(), so we must have
- * a flag to disable exception checking (`ignore_ex'). 
- *
- * On entry, the controller is supposed to be READY.
- */
-static int send_qic02_cmd(int cmd, time_t timeout, int ignore_ex)
-{
-	int stat;
-
-	stat = inb_p(QIC02_STAT_PORT);
-	if ((stat & QIC02_STAT_EXCEPTION) == 0) {	/* if exception */
-		tpqputs(TPQD_ALWAYS, "send_qic02_cmd: Exception!");
-		return TE_EX;
-	}
-	if (stat & QIC02_STAT_READY) {	/* if not ready */
-		tpqputs(TPQD_ALWAYS, "send_qic02_cmd: not Ready!");
-		return TE_ERR;
-	}
-
-	/* assert(ready & !exception) */
-
-	/* Remember current command for later re-use with dma transfers.
-	 * (For reading/writing multiple blocks.)
-	 */
-	status_cmd_pending = cmd;
-
-	stat = notify_cmd(cmd, ignore_ex);	/* tell drive new command was loaded, */
-	/* inherit exception check. */
-	if (TP_HAVE_SEEK && (cmd == AR_QCMDV_SEEK_BLK)) {
-		/* This one needs to send 3 more bytes, MSB first */
-		stat = send_qic02_data(seek_addr_buf, sizeof(seek_addr_buf), ignore_ex);
-	}
-
-	if (stat != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "send_qic02_cmd failed");
-	}
-	return stat;
-}				/* send_qic02_cmd */
-
-
-
-/* Get drive status. Assume drive is ready or has exception set.
- * (or will be in <1000 usec.)
- * Extra parameters added because of 'Read Extended Status 3' command.
- */
-static int rdstatus(char *stp, unsigned size, char qcmd)
-{
-	int s, n;
-	char *q = stp;
-
-	/* Try to busy-wait a few (700) usec, after that de-schedule.
-	 *
-	 * The problem is, if we don't de-schedule, performance will
-	 * drop to zero when the drive is not responding and if we
-	 * de-schedule immediately, we waste a lot of time because a
-	 * task switch is much longer than we usually have to wait here.
-	 */
-	n = 700;
-	while ((n > 0) && ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK))
-	{
-		udelay(1);
-		n--;		/* wait for ready or exception or timeout */
-	}
-	if (n == 0) {
-		/* n (above) should be chosen such that on your machine
-		 * you rarely ever see the message below, and it should
-		 * be small enough to give reasonable response time.]
-		 */
-	 	/* FIXME */
-		tpqputs(TPQD_ALWAYS, "waiting looong in rdstatus() -- drive dead?");
-		while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)
-		{
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
-		tpqputs(TPQD_ALWAYS, "finished waiting in rdstatus()");
-	}
-
-	(void) notify_cmd(qcmd, 1);	/* send read status command */
-	/* ignore return code -- should always be ok, STAT may contain 
-	 * exception flag from previous exception which we are trying to clear.
-	 */
-
-	if (TP_DIAGS(current_type))
-		printk(TPQIC02_NAME ": reading status bytes: ");
-
-	for (q = stp; q < stp + size; q++) {
-		do
-			s = inb_p(QIC02_STAT_PORT);
-		while ((s & QIC02_STAT_MASK) == QIC02_STAT_MASK);	/* wait for ready or exception */
-
-		if ((s & QIC02_STAT_EXCEPTION) == 0) {	/* if exception */
-			tpqputs(TPQD_ALWAYS, "rdstatus: exception error");
-			ioctl_status.mt_erreg = 0;	/* dunno... */
-			return TE_NS;	/* error, shouldn't happen... */
-		}
-
-		*q = inb_p(QIC02_DATA_PORT);	/* read status byte */
-
-		if (TP_DIAGS(current_type))
-			printk("[%1zd]=0x%x  ", q - stp, (unsigned) (*q) & 0xff);
-
-		outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* set request */
-
-		while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0)
-			cpu_relax();	/* wait for not ready */
-
-		udelay(22);	/* delay >20 usec */
-
-		outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* un-set request */
-
-	}
-
-	/* Specs say we should wait for READY here.
-	 * My drive doesn't seem to need it here yet, but others do?
-	 */
-	while (inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY)
-		cpu_relax();
-	/* wait for ready */
-
-	if (TP_DIAGS(current_type))
-		printk("\n");
-
-	return TE_OK;
-}				/* rdstatus */
-
-
-
-/* Get standard status (6 bytes).
- * The `.dec' and `.urc' fields are in MSB-first byte-order,
- * so they have to be swapped first.
- */
-static int get_status(volatile struct tpstatus *stp)
-{
-	int stat = rdstatus((char *) stp, TPSTATSIZE, QCMD_RD_STAT);
-	stp->dec = be16_to_cpu(stp->dec);
-	stp->urc = be16_to_cpu(stp->urc);
-	return stat;
-}				/* get_status */
-
-
-#if 0
-/* This fails for my Wangtek drive */
-/* get "Extended Status Register 3" (64 bytes)
- *
- * If the meaning of the returned bytes were known, the MT_TYPE
- * identifier could be used to decode them, since they are
- * "vendor unique". :-(
- */
-static int get_ext_status3(void)
-{
-	char vus[64];		/* vendor unique status */
-	int stat, i;
-
-	tpqputs(TPQD_ALWAYS, "Attempting to read Extended Status 3...");
-	stat = rdstatus(vus, sizeof(vus), QCMD_RD_STAT_X3);
-	if (stat != TE_OK)
-		return stat;
-
-	tpqputs(TPQD_ALWAYS, "Returned status bytes:");
-	for (i = 0; i < sizeof(vus); i++) {
-		if (i % 8 == 0)
-			printk("\n" TPQIC02_NAME ": %2d:");
-		printk(" %2x", vus[i] & 0xff);
-	}
-	printk("\n");
-
-	return TE_OK;
-}				/* get_ext_status3 */
-#endif
-
-
-/* Read drive status and set generic status too.
- * NOTE: Once we do a tp_sense(), read/write transfers are killed.
- */
-static int tp_sense(int ignore)
-{
-	unsigned err = 0, exnr = 0, gs = 0;
-	static void finish_rw(int cmd);
-
-	if (TPQDBG(SENSE_TEXT))
-		printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n", ignore);
-
-	/* sense() is not allowed during a read or write cycle */
-	if (doing_write == YES)
-		tpqputs(TPQD_ALWAYS, "Warning: File Mark inserted because of sense() request");
-	/* The extra test is to avoid calling finish_rw during booting */
-	if ((doing_read != NO) || (doing_write != NO))
-		finish_rw(QCMD_RD_STAT);
-
-	if (get_status(&tperror) != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "tp_sense: could not read tape drive status");
-		return TE_ERR;
-	}
-
-	err = tperror.exs;	/* get exception status bits */
-	if (err & (TP_ST0 | TP_ST1))
-		printk(TPQIC02_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n",
-		       tperror.exs, tperror.dec, tperror.urc);
-	else if ((tperror.dec != 0) || (tperror.urc != 0) || TPQDBG(SENSE_CNTS))
-		printk(TPQIC02_NAME ": tp_sense: no hard errors, soft error count: %d, underruns: %d\n", tperror.dec, tperror.urc);
-
-	/* Set generic status. HP-UX defines these, but some extra would 
-	 * be useful. Problem is to remain compatible. [Do we want to be
-	 * compatible??]
-	 */
-	if (err & TP_ST0) {
-		if (err & TP_CNI)	/* no cartridge */
-			gs |= GMT_DR_OPEN(-1);
-		if (status_dead == NO)
-			gs |= GMT_ONLINE(-1);	/* always online */
-		if (err & TP_USL)	/* not online */
-			gs &= ~GMT_ONLINE(-1);
-		if (err & TP_WRP)
-			gs |= GMT_WR_PROT(-1);
-		if (err & TP_EOM) {	/* end of media */
-			gs |= GMT_EOT(-1);	/* not sure this is correct for writes */
-			status_eom_detected = YES;
-			/* I don't know whether drive always reports EOF at or before EOM. */
-			status_eof_detected = YES;
-		}
-		/** if (err & TP_UDA) "Unrecoverable data error" **/
-		/** if (err & TP_BNL) "Bad block not located" **/
-		if (err & TP_FIL) {
-			gs |= GMT_EOF(-1);
-			status_eof_detected = YES;
-		}
-	}
-	if (err & TP_ST1) {
-		/** if (err & TP_ILL) "Illegal command" **/
-		/** if (err & TP_NDT) "No data detected" **/
-		/** if (err & TP_MBD) "Marginal block detected" **/
-		if (err & TP_BOM)
-			gs |= GMT_BOT(-1);	/* beginning of tape */
-	}
-	ioctl_status.mt_gstat = gs;
-	ioctl_status.mt_dsreg = tperror.exs;	/* "drive status" */
-	ioctl_status.mt_erreg = tperror.dec;	/* "sense key error" */
-
-	if (err & (TP_ST0 | TP_ST1)) {
-		/* My Wangtek occasionally reports `status' 1212 which should be ignored. */
-		exnr = decode_qic_exception_nr(err);
-		handle_qic_exception(exnr, err);	/* update driver state wrt drive status */
-		report_qic_exception(exnr);
-	}
-	err &= ~ignore;		/* mask unwanted errors -- not the correct way, use exception nrs?? */
-	if (((err & TP_ST0) && (err & REPORT_ERR0)) ||
-	    ((err & TP_ST1) && (err & REPORT_ERR1)))
-		return TE_ERR;
-	return TE_OK;
-}				/* tp_sense */
-
-
-
-/* Wait for a wind or rewind operation to finish or
- * to time-out. (May take very long).
- */
-static int wait_for_rewind(time_t timeout)
-{
-	int stat;
-
-	stat = inb(QIC02_STAT_PORT) & QIC02_STAT_MASK;
-	if (TPQDBG(REWIND))
-		printk(TPQIC02_NAME ": Waiting for (re-)wind to finish: stat=0x%x\n", stat);
-
-	stat = wait_for_ready(timeout);
-
-	if (stat != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "(re-) winding failed\n");
-	}
-	return stat;
-}				/* wait_for_rewind */
-
-
-
-/* Perform a full QIC02 command, and wait for completion,
- * check status when done. Complain about exceptions.
- *
- * This function should return an OS error code when
- * something goes wrong, 0 otherwise.
- */
-static int ll_do_qic_cmd(int cmd, time_t timeout)
-{
-	int stat;
-
-	if (status_dead == YES) {
-		tpqputs(TPQD_ALWAYS, "Drive is dead. Do a `mt reset`.");
-		return -ENXIO;	/* User should do an MTRESET. */
-	}
-
-	stat = wait_for_ready(timeout);	/* wait for ready or exception */
-	if (stat == TE_EX) {
-		if (tp_sense(TP_WRP | TP_BOM | TP_EOM | TP_FIL) != TE_OK)
-			return -EIO;
-		/* else nothing to worry about, I hope */
-		stat = TE_OK;
-	}
-	if (stat != TE_OK) {
-		printk(TPQIC02_NAME ": ll_do_qic_cmd(%x, %ld) failed\n", cmd, (long) timeout);
-		return -EIO;
-	}
-#ifdef OBSOLETE
-	/* wait for ready since it may not be active immediately after reading status */
-	while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) != 0)
-		cpu_relax();
-#endif
-
-	stat = send_qic02_cmd(cmd, timeout, 0);	/* (checks for exceptions) */
-
-	if (cmd == QCMD_RD_FM) {
-		status_eof_detected = NO;
-		ioctl_status.mt_fileno++;
-		/* Should update block count as well, but can't.
-		 * Can do a `read address' for some drives, when MTNOP is done.
-		 */
-	} else if (cmd == QCMD_WRT_FM) {
-		status_eof_detected = NO;
-		ioctl_status.mt_fileno++;
-	} else if ((cmd == QCMD_REWIND) || (cmd == QCMD_ERASE)
-		   || (cmd == QCMD_RETEN)) {
-		status_eof_detected = NO;
-		status_eom_detected = NO;
-		status_eot_detected = NO;
-		need_rewind = NO;
-		ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
-		extra_blocks_left = BLOCKS_BEYOND_EW;
-		return_write_eof = NO;
-		return_read_eof = NO;
-		reported_read_eof = NO;
-		reported_write_eof = NO;
-	}
-	/* sense() will set eof/eom as required */
-	if (stat == TE_EX) {
-		if (tp_sense(TP_WRP | TP_BOM | TP_EOM | TP_FIL) != TE_OK) {
-			printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[1](%x, %ld)", cmd, (long) timeout);
-			status_dead = YES;
-			return -ENXIO;
-			/* if rdstatus fails too, we're in trouble */
-		}
-	} else if (stat != TE_OK) {
-		printk(TPQIC02_NAME ": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n", stat);
-		return -EIO;	/*** -EIO is probably not always appropriate */
-	}
-
-	if (timeout == TIM_R)
-		stat = wait_for_rewind(timeout);
-	else
-		stat = wait_for_ready(timeout);
-
-	if (stat == TE_EX) {
-		if (tp_sense((cmd == QCMD_SEEK_EOD ?		/*****************************/
-			      TP_EOR | TP_NDT | TP_UDA | TP_BNL | TP_WRP |
-			      TP_BOM | TP_EOM | TP_FIL : TP_WRP | TP_BOM |
-			      TP_EOM | TP_FIL)) != TE_OK) {
-			printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[2](%x, %ld)\n", cmd, (long) timeout);
-			if (cmd != QCMD_RD_FM)
-				status_dead = YES;
-			return -ENXIO;
-			/* if rdstatus fails too, we're in trouble */
-		}
-	} else if (stat != TE_OK) {
-		printk(TPQIC02_NAME ": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n", cmd, stat);
-		return -EIO;
-	}
-	return 0;
-}				/* ll_do_qic_cmd */
-
-
-/* 
- * Problem: What to do when the user cancels a read/write operation
- * in-progress?
- *
- * "Deactivating ONLINE during a READ also causes the"
- * "tape to be rewound to BOT." Ditto for WRITEs, except
- * a FM is written first. "The host may alternatively terminate
- * the READ/WRITE command by issuing a RFM/WFM command."
- *
- * For READs:
- * Neither option will leave the tape positioned where it was.
- * Another (better?) solution is to terminate the READ by two
- * subsequent sense() operations, the first to stop the current
- * READ cycle, the second to clear the `Illegal command' exception,
- * because the QIC-02 specs didn't anticipate this. This is
- * delayed until actually needed, so a tar listing can be aborted
- * by the user and continued later.
- * If anybody has a better solution, let me know! [Also, let me
- * know if your drive (mine is a Wangtek5150EQ) does not accept
- * this sequence for canceling the read-cycle.]
- *
- * For WRITEs it's simple: Just do a WRITE_FM, leaving the tape
- * positioned after the FM.
- */
-
-static void terminate_read(int cmd)
-{
-	if (doing_read != YES)
-		return;
-		
-	doing_read = NO;
-	
-	if (cmd == QCMD_RD_FM)
-		return;
-		
-	/* if the command is a RFM, there is no need to do this
-	 * because a RFM will legally terminate the read-cycle.
-	 */
-	tpqputs(TPQD_ALWAYS, "terminating pending read-cycle");
-
-	/* I'm not too sure about this part  -- hhb */
-	if (QIC02_TAPE_IFC == MOUNTAIN) {
-		/* Mountain reference says can terminate by de-asserting online */
-		ctlbits &= ~MTN_QIC02_CTL_ONLINE;
-	}
-
-	if (tp_sense(TP_FIL | TP_EOM | TP_WRP) != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "finish_rw[read1]: ignore the 2 lines above");
-		if (is_exception()) {
-			if (tp_sense(TP_ILL | TP_FIL | TP_EOM | TP_WRP) != TE_OK)
-				tpqputs(TPQD_ALWAYS,"finish_rw[read2]: read cycle error");
-		}
-	}
-}				/* terminate_read */
-
-
-static void terminate_write(int cmd)
-{
-	int stat;
-
-	if (doing_write != YES)
-		return;
-
-	doing_write = NO;
-	/* Finish writing by appending a FileMark at the end. */
-	if (cmd != QCMD_WRT_FM) {
-		/* finish off write cycle */
-		stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M);
-		if (stat != TE_OK)
-			tpqputs(TPQD_ALWAYS, "Couldn't finish write cycle properly");
-		(void) tp_sense(0);
-	}
-	/* If there is an EOF token waiting to be returned to
-	 * the (writing) application, discard it now.
-	 * We could be at EOT, so don't reset return_write_eof.
-	 */
-	reported_write_eof = YES;
-}				/* terminate_write */
-
-
-/* terminate read or write cycle because of command `cmd' */
-static void finish_rw(int cmd)
-{
-	if (wait_for_ready(TIM_S) != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "error: drive not ready in finish_rw() !");
-		return;
-	}
-	terminate_read(cmd);
-	terminate_write(cmd);
-}				/* finish_rw */
-
-
-/* Perform a QIC command through ll_do_qic_cmd().
- * If necessary, rewind the tape first.
- * Return an OS error code if something goes wrong, 0 if all is well.
- */
-static int do_qic_cmd(int cmd, time_t timeout)
-{
-	int stat;
-
-
-	finish_rw(cmd);
-
-	if (need_rewind) {
-		tpqputs(TPQD_REWIND, "Rewinding tape...");
-		stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R);
-		if (stat != 0) {
-			printk(TPQIC02_NAME ": rewind failed in do_qic_cmd(). stat=0x%2x", stat);
-			return stat;
-		}
-		need_rewind = NO;
-		if (cmd == QCMD_REWIND)	/* don't wind beyond BOT ;-) */
-			return 0;
-	}
-
-	return ll_do_qic_cmd(cmd, timeout);
-}				/* do_qic_cmd */
-
-
-/* Not all ioctls are supported for all drives. Some rely on
- * optional QIC-02 commands. Check tpqic02.h for configuration.
- * Some of these commands may require ONLINE to be active.
- */
-static int do_ioctl_cmd(int cmd)
-{
-	int stat;
-
-	/* It is not permitted to read or wind the tape after bytes have
-	 * been written. It is not permitted to write the tape while in
-	 * read mode.
-	 * We try to be kind and allow reading again after writing a FM...
-	 */
-
-	switch (cmd) {
-	case MTRESET:
-		/* reset verbose */
-		return (tape_reset(1) == TE_OK) ? 0 : -EIO;
-
-	case MTFSF:
-		tpqputs(TPQD_IOCTLS, "MTFSF forward searching filemark");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		return do_qic_cmd(QCMD_RD_FM, TIM_F);
-
-	case MTBSF:
-		if (TP_HAVE_BSF) {
-			tpqputs(TPQD_IOCTLS, "MTBSF backward searching filemark -- optional command");
-			if ((mode_access == WRITE) && status_bytes_wr)
-				return -EACCES;
-			stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F);
-		} else {
-			stat = -ENXIO;
-		}
-		status_eom_detected = status_eof_detected = NO;
-		return stat;
-
-	case MTFSR:
-		if (TP_HAVE_FSR) {	/* This is an optional QIC-02 command */
-			tpqputs(TPQD_IOCTLS, "MTFSR forward space record");
-			if ((mode_access == WRITE) && status_bytes_wr)
-				return -EACCES;
-			stat = do_qic_cmd(QCMD_SPACE_FWD, TIM_F);
-		} else {
-				/**** fake it by doing a read data block command? ******/
-			tpqputs(TPQD_IOCTLS, "MTFSR not supported");
-			stat = -ENXIO;
-		}
-		return stat;
-
-	case MTBSR:
-		if (TP_HAVE_BSR) {	/* This is an optional QIC-02 command */
-			/* we need this for appending files with GNU tar!! */
-			tpqputs(TPQD_IOCTLS, "MTFSR backward space record");
-			if ((mode_access == WRITE) && status_bytes_wr)
-				return -EACCES;
-			stat = do_qic_cmd(QCMD_SPACE_BCK, TIM_F);
-		} else {
-			tpqputs(TPQD_IOCTLS, "MTBSR not supported");
-			stat = -ENXIO;
-		}
-		status_eom_detected = status_eof_detected = NO;
-		return stat;
-
-	case MTWEOF:
-		tpqputs(TPQD_IOCTLS, "MTWEOF write eof mark");
-		/* Plain GNU mt(1) 2.2 uses read-only mode for writing FM. :-( */
-		if (mode_access == READ)
-			return -EACCES;
-
-		/* allow tape movement after writing FM */
-		status_bytes_rd = status_bytes_wr;	/* Kludge-O-Matic */
-		status_bytes_wr = NO;
-		return do_qic_cmd(QCMD_WRT_FM, TIM_M);
-		/* not sure what to do with status_bytes when WFM should fail */
-
-	case MTREW:
-		tpqputs(TPQD_IOCTLS, "MTREW rewinding tape");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		status_eom_detected = status_eof_detected = NO;
-		return do_qic_cmd(QCMD_REWIND, TIM_R);
-
-	case MTOFFL:
-		tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline");
-		/* Doing a drive select will clear (unlock) the current drive.
-		 * But that requires support for multiple drives and locking.
-		 */
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		status_eom_detected = status_eof_detected = NO;
-			/**** do rewind depending on minor bits??? ***/
-		stat = do_qic_cmd(QCMD_REWIND, TIM_R);
-		return stat;
-
-	case MTNOP:
-		tpqputs(TPQD_IOCTLS, "MTNOP setting status only");
-		/********** should do `read position' for drives that support it **********/
-		return (tp_sense(-1) == TE_OK) ? 0 : -EIO;	/**** check return codes ****/
-
-	case MTRETEN:
-		tpqputs(TPQD_IOCTLS, "MTRETEN retension tape");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		status_eom_detected = status_eof_detected = NO;
-		return do_qic_cmd(QCMD_RETEN, TIM_R);
-
-	case MTBSFM:
-		/* Think think is like MTBSF, except that
-		 * we shouldn't skip the FM. Tricky.
-		 * Maybe use RD_FM_BCK, then do a SPACE_FWD?
-		 */
-		tpqputs(TPQD_IOCTLS, "MTBSFM not supported");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		return -ENXIO;
-
-	case MTFSFM:
-		/* I think this is like MTFSF, except that
-		 * we shouldn't skip the FM. Tricky.
-		 * Maybe use QCMD_RD_DATA until we get a TP_FIL exception?
-		 * But then the FM will have been skipped...
-		 * Maybe use RD_FM, then RD_FM_BCK, but not all
-		 * drives will support that!
-		 */
-		tpqputs(TPQD_IOCTLS, "MTFSFM not supported");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		return -ENXIO;
-
-	case MTEOM:
-		/* This should leave the tape ready for appending
-		 * another file to the end, such that it would append
-		 * after the last FM on tape.
-		 */
-		tpqputs(TPQD_IOCTLS, "MTEOM search for End Of recorded Media");
-		if ((mode_access == WRITE) && status_bytes_wr)
-			return -EACCES;
-		if (TP_HAVE_EOD) {
-			/* Use faster seeking when possible.
-			 * This requires the absence of data beyond the EOM.
-			 * It seems that my drive does not always perform the
-			 * SEEK_EOD correctly, unless it is preceded by a
-			 * rewind command.
-			 */
-# if 0
-			status_eom_detected = status_eof_detected = NO;
-# endif
-			stat = do_qic_cmd(QCMD_REWIND, TIM_R);
-			if (stat)
-				return stat;
-			stat = do_qic_cmd(QCMD_SEEK_EOD, TIM_F);
-			/* After a successful seek, TP_EOR should be returned */
-		} else {
-			/* else just seek until the drive returns exception "No Data" */
-			stat = 0;
-			while ((stat == 0) && (!status_eom_detected)) {
-				stat = do_qic_cmd(QCMD_RD_FM, TIM_F);	      /***** should use MTFSFM here???? ******/
-			}
-			if (tperror.exs & TP_NDT)
-				return 0;
-		}
-		return stat;
-
-	case MTERASE:
-		tpqputs(TPQD_IOCTLS, "MTERASE -- ERASE TAPE !");
-		if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
-			tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
-			return -EACCES;
-		} else {
-			time_t t = jiffies;
-
-			/* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */
-			if (mode_access == READ)
-				return -EACCES;
-
-			/* FIXME */
-			/* give user a few seconds to pull out tape */
-			while (jiffies - t < 4 * HZ)
-				schedule();
-		}
-
-		/* don't bother writing filemark first */
-		status_eom_detected = status_eof_detected = NO;
-		return do_qic_cmd(QCMD_ERASE, TIM_R);
-
-	case MTRAS1:
-		if (TP_HAVE_RAS1) {
-			tpqputs(TPQD_IOCTLS, "MTRAS1: non-destructive self test");
-			stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R);
-			if (stat != 0) {
-				tpqputs(TPQD_ALWAYS, "RAS1 failed");
-				return stat;
-			}
-			return (tp_sense(0) == TE_OK) ? 0 : -EIO;	/* get_ext_status3(); */
-		}
-		tpqputs(TPQD_IOCTLS, "RAS1 not supported");
-		return -ENXIO;
-
-	case MTRAS2:
-		if (TP_HAVE_RAS2) {
-			tpqputs(TPQD_IOCTLS, "MTRAS2: destructive self test");
-			stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R);
-			if (stat != 0) {
-				tpqputs(TPQD_ALWAYS, "RAS2 failed");
-				return stat;
-			}
-			return (tp_sense(0) == TE_OK) ? 0 : -EIO;	/* get_ext_status3(); */
-		}
-		tpqputs(TPQD_IOCTLS, "RAS2 not supported");
-		return -ENXIO;
-
-	case MTSEEK:
-		if (TP_HAVE_SEEK && (QIC02_TAPE_IFC == ARCHIVE)) {
-			tpqputs(TPQD_IOCTLS, "MTSEEK seeking block");
-			if ((mode_access == WRITE) && status_bytes_wr)
-				return -EACCES;
-			/* NOTE: address (24 bits) is in seek_addr_buf[] */
-			return do_qic_cmd(AR_QCMDV_SEEK_BLK, TIM_F);
-		} else
-			return -ENOTTY;
-
-	default:
-		return -ENOTTY;
-	}
-}				/* do_ioctl_cmd */
-
-
-/* dma_transfer(): This routine is called for every 512 bytes to be read
- * from/written to the tape controller. Speed is important here!
- * (There must be enough time left for the hd controller!)
- * The dma lock protects the DMA controller
- *
- * This routine merely does the least possible to keep
- * the transfers going:
- *	- set the DMA count register for the next 512 bytes
- *	- adjust the DMA address and page registers
- *	- adjust the timeout
- *	- tell the tape controller to start transferring
- * We assume the dma address and mode are, and remain, valid.
- */
-static inline void dma_transfer(void)
-{
-	unsigned long flags;
-
-	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */
-		outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT);	/* back to normal */
-	else if (QIC02_TAPE_IFC == ARCHIVE)
-		outb_p(0, AR_RESET_DMA_PORT);
-	else			/* QIC02_TAPE_IFC == MOUNTAIN */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-
-
-	flags = claim_dma_lock();
-	clear_dma_ff(QIC02_TAPE_DMA);
-	set_dma_mode(QIC02_TAPE_DMA, dma_mode);
-	set_dma_addr(QIC02_TAPE_DMA, isa_virt_to_bus(buffaddr) + dma_bytes_done);
-	set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);
-
-	/* start tape DMA controller */
-	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */
-		outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC02_CTL_PORT);	/* trigger DMA transfer */
-
-	else if (QIC02_TAPE_IFC == ARCHIVE) {
-		outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC02_CTL_PORT);	/* enable interrupts again */
-		outb_p(0, AR_START_DMA_PORT);	/* start DMA transfer */
-		/* In dma_end() AR_RESET_DMA_PORT is written too. */
-
-	} else {		/* QIC02_TAPE_IFC == MOUNTAIN */
-
-		inb(MTN_R_DESELECT_DMA_PORT);
-		outb_p(ctlbits | (MTN_CTL_EXC_IEN | MTN_CTL_DNIEN),
-		       QIC02_CTL_PORT);
-		outb_p(0, MTN_W_SELECT_DMA_PORT);	/* start DMA transfer */
-		if (dma_mode == DMA_MODE_WRITE)
-			outb_p(0, MTN_W_DMA_WRITE_PORT);	/* start DMA transfer */
-	}
-
-	/* start computer DMA controller */
-	enable_dma(QIC02_TAPE_DMA);
-
-	release_dma_lock(flags);
-
-	/* block transfer should start now, jumping to the 
-	 * interrupt routine when done or an exception was detected.
-	 */
-}				/* dma_transfer */
-
-
-/* start_dma() sets a DMA transfer up between the tape controller and
- * the kernel qic02_tape_buf buffer.
- * Normally bytes_todo==dma_bytes_done at the end of a DMA transfer. If not,
- * a filemark was read, or an attempt to write beyond the End Of Tape 
- * was made. [Or some other bad thing happened.]
- * Must do a sense() before returning error.
- */
-static int start_dma(short mode, unsigned long bytes_todo)
-/* assume 'bytes_todo'>0 */
-{
-	int stat;
-
-	tpqputs(TPQD_DEBUG, "start_dma() enter");
-	TPQDEB( {printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n",
-		      doing_read, doing_write);})
-
-	dma_bytes_done = 0;
-	dma_bytes_todo = bytes_todo;
-	status_error = NO;
-	/* dma_mode!=0 indicates that the dma controller is in use */
-	dma_mode = (mode == WRITE) ? DMA_MODE_WRITE : DMA_MODE_READ;
-
-	/* Only give READ/WRITE DATA command to tape drive if we haven't
-	 * done that already. Otherwise the drive will rewind to the beginning
-	 * of the current file on tape. Any QIC command given other than
-	 * R/W FM will break the read/write transfer cycle.
-	 * do_qic_cmd() will terminate doing_{read,write}
-	 */
-	if ((doing_read == NO) && (doing_write == NO)) {
-		/* First, we have to clear the status -- maybe remove TP_FIL???
-		 */
-
-#if 0
-		/* Next dummy get status is to make sure CNI is valid,
-		   since we're only just starting a read/write it doesn't
-		   matter some exceptions are cleared by reading the status;
-		   we're only interested in CNI and WRP. -Eddy */
-		get_status(&tperror);
-#else
-		/* TP_CNI should now be handled in open(). -Hennus */
-#endif
-
-		stat = tp_sense(((mode == WRITE) ? 0 : TP_WRP) | TP_BOM | TP_FIL);
-		if (stat != TE_OK)
-			return stat;
-
-#ifdef OBSOLETE
-		/************* not needed iff rd_status() would wait for ready!!!!!! **********/
-		if (wait_for_ready(TIM_S) != TE_OK) {	/*** not sure this is needed ***/
-			tpqputs(TPQD_ALWAYS, "wait_for_ready failed in start_dma");
-			return -EIO;
-		}
-#endif
-
-		if (QIC02_TAPE_IFC == MOUNTAIN) {
-			/* Set control bits to select ONLINE during command */
-			ctlbits |= MTN_QIC02_CTL_ONLINE;
-		}
-
-		/* Tell the controller the data direction */
-
-		/* r/w, timeout medium, check exceptions, sets status_cmd_pending. */
-		stat = send_qic02_cmd((mode == WRITE) ? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);
-		if (stat != TE_OK) {
-			printk(TPQIC02_NAME ": start_dma: init %s failed\n", (mode == WRITE) ? "write" : "read");
-			(void) tp_sense(0);
-			return stat;
-		}
-
-		/* Do this last, because sense() will clear the doing_{read,write}
-		 * flags, causing trouble next time around.
-		 */
-		if (wait_for_ready(TIM_M) != TE_OK)
-			return -EIO;
-		switch (mode) {
-		case READ:
-			doing_read = YES;
-			break;
-		case WRITE:
-			doing_write = YES;
-			break;
-		default:
-			printk(TPQIC02_NAME ": requested unknown mode %d\n", mode);
-			panic(TPQIC02_NAME ": invalid mode in start_dma()");
-		}
-
-	} else if (is_exception()) {
-		/* This is for Archive drives, to handle reads with 0 bytes
-		 * left for the last read request.
-		 *
-		 * ******** this also affects EOF/EOT handling! ************
-		 */
-		tpqputs(TPQD_ALWAYS, "detected exception in start_dma() while transfer in progress");
-		status_error = YES;
-		return TE_END;
-	}
-
-
-	status_expect_int = YES;
-
-	/* This assumes tape is already positioned, but these
-	 * semi-'intelligent' drives are unpredictable...
-	 */
-	TIMERON(TIM_M * 2);
-
-	/* initiate first data block read from/write to the tape controller */
-
-	dma_transfer();
-
-	TPQPUTS("start_dma() end");
-	return TE_OK;
-}				/* start_dma */
-
-
-/* This cleans up after the dma transfer has completed
- * (or failed). If an exception occurred, a sense()
- * must be done. If the exception was caused by a FM,
- * sense() will set `status_eof_detected' and
- * `status_eom_detected', as required.
- */
-static void end_dma(unsigned long *bytes_done)
-{
-	int stat = TE_OK;
-	unsigned long flags;
-
-	TIMEROFF;
-
-	TPQPUTS("end_dma() enter");
-
-	flags = claim_dma_lock();
-
-	disable_dma(QIC02_TAPE_DMA);
-	clear_dma_ff(QIC02_TAPE_DMA);
-
-	release_dma_lock(flags);
-
-	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */
-		outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT);	/* back to normal */
-	else if (QIC02_TAPE_IFC == ARCHIVE)
-		outb_p(0, AR_RESET_DMA_PORT);
-	else {			/* QIC02_TAPE_IFC == MOUNTAIN */
-		/* Clear control bits, de-select ONLINE during tp_sense */
-		ctlbits &= ~MTN_QIC02_CTL_ONLINE;
-	}
-
-	stat = wait_for_ready(TIM_M);
-	if (status_error || (stat != TE_OK)) {
-		tpqputs(TPQD_DMAX, "DMA transfer exception");
-		stat = tp_sense((dma_mode == READ) ? TP_WRP : 0);
-		/* no return here -- got to clean up first! */
-	} else {		/* if (QIC02_TAPE_IFC == MOUNTAIN) */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-	}
-
-	if (QIC02_TAPE_IFC == MOUNTAIN)
-		inb(MTN_R_DESELECT_DMA_PORT);
-
-	/* take the tape controller offline */
-
-	/* finish off DMA stuff */
-
-
-	dma_mode = 0;
-	/* Note: The drive is left on-line, ready for the next
-	 * data transfer.
-	 * If the next command to the drive does not continue
-	 * the pending cycle, it must do 2 sense()s first.
-	 */
-
-	*bytes_done = dma_bytes_done;
-	status_expect_int = NO;
-	ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE);
-
-	TPQPUTS("end_dma() exit");
-	/*** could return stat here ***/
-}				/* end_dma */
-
-/*********** Below are the (public) OS-interface procedures ***********/
-
-
-/* qic02_tape_times_out() is called when a DMA transfer doesn't complete
- * quickly enough. Usually this means there is something seriously wrong
- * with the hardware/software, but it could just be that the controller
- * has decided to do a long rewind, just when I didn't expect it.
- * Just try again.
- */
-static void qic02_tape_times_out(unsigned long dummy)
-{
-	printk("time-out in %s driver\n", TPQIC02_NAME);
-	if ((status_cmd_pending > 0) || dma_mode) {
-		/* takes tooo long, shut it down */
-		status_dead = YES;
-		status_cmd_pending = 0;
-		status_timer_on = NO;
-		status_expect_int = NO;
-		status_error = YES;
-		if (dma_mode) {
-			dma_mode = 0;	/* signal end to read/write routine */
-			wake_up(&qic02_tape_transfer);
-		}
-	}
-}				/* qic02_tape_times_out */
-
-/*
- * Interrupt handling:
- *
- * 1) Interrupt is generated iff at the end of 
- *    a 512-DMA-block transfer.
- * 2) EXCEPTION is not raised unless something 
- *    is wrong or EOT/FM is detected.
- * 3) FM EXCEPTION is set *after* the last byte has
- *    been transferred by DMA. By the time the interrupt
- *    is handled, the EXCEPTION may already be set.
- *
- * So,
- * 1) On EXCEPTION, assume data has been transferred, so
- *    continue as usual, but set a flag to indicate the
- *    exception was detected.
- *    Do a sense status when the flag is found set.
- * 2) Do not attempt to continue a transfer after an exception.
- *    [??? What about marginal blocks???????]
- */
-
-
-/* qic02_tape_interrupt() is called when the tape controller completes 
- * a DMA transfer.
- * We are not allowed to sleep here! 
- *
- * Check if the transfer was successful, check if we need to transfer
- * more. If the buffer contains enough data/is empty enough, signal the
- * read/write() thread to copy to/from user space.
- * When we are finished, set flags to indicate end, disable timer.
- * NOTE: This *must* be fast! 
- */
-static irqreturn_t qic02_tape_interrupt(int irq, void *dev_id,
-				 struct pt_regs *regs)
-{
-	int stat, r, i;
-	unsigned long flags;
-
-	TIMEROFF;
-
-	if (status_expect_int) {
-#ifdef WANT_EXTRA_FULL_DEBUGGING
-		if (TP_DIAGS(current_type))
-			printk("@");
-#endif
-		stat = inb(QIC02_STAT_PORT);	/* Knock, knock */
-		if (QIC02_TAPE_IFC == ARCHIVE) {	/* "Who's there?" */
-			if (((stat & (AR_STAT_DMADONE)) == 0) &&
-			    ((stat & (QIC02_STAT_EXCEPTION)) != 0)) {
-				TIMERCONT;
-				return IRQ_NONE;/* "Linux with IRQ sharing" */
-			}
-		}
-
-		if ((stat & QIC02_STAT_EXCEPTION) == 0) {	/* exception occurred */
-			/* Possible causes for an exception during a transfer:
-			 *      - during a write-cycle: end of tape (EW) hole detected.
-			 *      - during a read-cycle: filemark or EOD detected.
-			 *      - something went wrong
-			 * So don't continue with the next block.
-			 */
-			tpqputs(TPQD_ALWAYS, "isr: exception on tape controller");
-			printk("      status %02x\n", stat);
-			status_error = TE_EX;
-
-			dma_bytes_done += TAPE_BLKSIZE;
-
-			dma_mode = 0;	/* wake up rw() */
-			status_expect_int = NO;
-			wake_up(&qic02_tape_transfer);
-			return IRQ_HANDLED;
-		}
-		/* return if tape controller not ready, or
-		 * if dma channel hasn't finished last byte yet.
-		 */
-		r = 0;
-
-		/* Skip next ready check for Archive controller because
-		 * it may be busy reading ahead. Weird. --hhb
-		 */
-		if (QIC02_TAPE_IFC == WANGTEK)	/* I think this is a drive-dependency, not IFC -- hhb */
-			if (stat & QIC02_STAT_READY) {	/* not ready */
-				tpqputs(TPQD_ALWAYS, "isr: ? Tape controller not ready");
-				r = 1;
-			}
-
-		flags = claim_dma_lock();
-
-		if ((i = get_dma_residue(QIC02_TAPE_DMA)) != 0) {
-			printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i);
-			r = 1;	/* big trouble, but can't do much about it... */
-		}
-
-		release_dma_lock(flags);
-
-		if (r)
-			return IRQ_HANDLED;
-
-		/* finish DMA cycle */
-
-		/* no errors detected, continue */
-		dma_bytes_done += TAPE_BLKSIZE;
-		if (dma_bytes_done >= dma_bytes_todo) {
-			/* finished! Wakeup rw() */
-			dma_mode = 0;
-			status_expect_int = NO;
-			TPQPUTS("isr: dma_bytes_done");
-			wake_up(&qic02_tape_transfer);
-		} else {
-			/* start next transfer, account for track-switching time */
-			mod_timer(&tp_timer, jiffies + 6 * HZ);
-			dma_transfer();
-		}
-	} else {
-		printk(TPQIC02_NAME ": Unexpected interrupt, stat == %x\n", inb(QIC02_STAT_PORT));
-	}
-	return IRQ_HANDLED;
-}				/* qic02_tape_interrupt */
-
-
-/* read/write routines:
- * This code copies between a kernel buffer and a user buffer. The 
- * actual data transfer is done using DMA and interrupts. Time-outs
- * are also used.
- *
- * When a filemark is read, we return '0 bytes read' and continue with the
- * next file after that.
- * When EOM is read, we return '0 bytes read' twice.
- * When the EOT marker is detected on writes, '0 bytes read' should be
- * returned twice. If user program does a MTNOP after that, 2 additional
- * blocks may be written.	------- FIXME: Implement this correctly  *************************************************
- *
- * Only read/writes in multiples of 512 bytes are accepted.
- * When no bytes are available, we sleep() until they are. The controller will
- * generate an interrupt, and we (should) get a wake_up() call.
- *
- * Simple buffering is used. User program should ensure that a large enough
- * buffer is used. Usually the drive does some buffering as well (something
- * like 4k or so).
- *
- * Scott S. Bertilson suggested to continue filling the user buffer, rather
- * than waste time on a context switch, when the kernel buffer fills up.
- */
-
-/*
- * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file
- * has been read, but the EOF token is never returned to tar(1), simply because
- * tar(1) knows it has already read all of the data it needs. So we must use
- * open/release to reset the `reported_read_eof' flag. If we don't, the next read
- * request would return the EOF flag for the previous file.
- */
-
-static ssize_t qic02_tape_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
-{
-	int type = iminor(filp->f_dentry->d_inode);
-	unsigned short flags = filp->f_flags;
-	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
-	int stat;
-
-	if (status_zombie == YES) {
-		tpqputs(TPQD_ALWAYS, "configs not set");
-		return -ENXIO;
-	}
-
-	if (TP_DIAGS(current_type))
-		printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%Lx, flags=%x\n", type, buf,
-		       (long) count, filp->f_pos, flags);
-
-	if (count % TAPE_BLKSIZE) {	/* Only allow mod 512 bytes at a time. */
-		tpqputs(TPQD_BLKSZ, "Wrong block size");
-		return -EINVAL;
-	}
-
-	/* Just assume everything is ok. Controller will scream if not. */
-
-	if (status_bytes_wr) {	/* Once written, no more reads, 'till after WFM. */
-		return -EACCES;
-	}
-
-	/* This is rather ugly because it has to implement a finite state
-	 * machine in order to handle the EOF situations properly.
-	 */
-	while ((signed) count >= 0) {
-		bytes_done = 0;
-		/* see how much fits in the kernel buffer */
-		bytes_todo = TPQBUF_SIZE;
-		if (bytes_todo > count) {
-			bytes_todo = count;
-		}
-
-		/* Must ensure that user program sees exactly one EOF token (==0) */
-		if (return_read_eof == YES) {
-			if (TPQDBG(DEBUG)) {
-				printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);
-			}
-
-			if (reported_read_eof == NO) {
-				/* have not yet returned EOF to user program */
-				if (total_bytes_done > 0) {
-					return total_bytes_done;	/* next time return EOF */
-				} else {
-					reported_read_eof = YES;	/* move on next time */
-					return 0;	/* return EOF */
-				}
-			} else {
-				/* Application program has already received EOF
-				 * (above), now continue with next file on tape,
-				 * if possible.
-				 * When the FM is reached, EXCEPTION is set,
-				 * causing a sense(). Subsequent read/writes will
-				 * continue after the FM.
-				 */
-		/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/
-				if (status_eom_detected) {
-					/* If EOM, nothing left to read, so keep returning EOFs.
-					 *** should probably set some flag to avoid clearing
-					 *** status_eom_detected through ioctls or something
-					 */
-					return 0;
-				} else {
-					/* just eof, there may be more files ahead... */
-					return_read_eof = NO;
-					reported_read_eof = NO;
-					status_eof_detected = NO;	/* reset this too */
-					/*fall through */
-				}
-			}
-		}
-
-		if (bytes_todo == 0) {
-			return total_bytes_done;
-		}
-
-		if (bytes_todo > 0) {
-			/* start reading data */
-			if (is_exception()) {
-				tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");
-			}
-
-/******************************************************************
- ***** if start_dma() fails because the head is positioned 0 bytes
- ***** before the FM, (causing EXCEPTION to be set) return_read_eof should
- ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO.
- ***** The app should recognize this as an EOF condition.
- ***************************************************************************/
-			stat = start_dma(READ, bytes_todo);
-			if (stat == TE_OK) {
-				/* Wait for transfer to complete, interrupt should wake us */
-				
-				wait_event(qic02_tape_transfer, dma_mode != 0);
-
-				if (status_error)
-					return_read_eof = YES;
-
-			} else if (stat != TE_END) {
-				/* should do sense() on error here */
-#if 0
-				return -ENXIO;
-#else
-				printk("Trouble: stat==%02x\n", stat);
-				return_read_eof = YES;
-		/*************** check EOF/EOT handling!!!!!! **/
-#endif
-			}
-			end_dma(&bytes_done);
-			if (bytes_done > bytes_todo) {
-				tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");
-				return -EIO;
-			}
-			/* copy buffer to user-space in one go */
-			if (bytes_done > 0) {
-				if (copy_to_user(buf, buffaddr, bytes_done))
-					return -EFAULT;
-			}
-#if 1
-			/* Checks Ton's patch below */
-			if ((return_read_eof == NO)  && (status_eof_detected == YES)) {
-				printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n",
-				       return_read_eof);
-			}
-#endif
-			if ((bytes_todo != bytes_done) || (status_eof_detected == YES)) {
-				/* EOF or EOM detected. return EOF next time. */
-				return_read_eof = YES;
-			}
-
-		}
-		/* else: ignore read request for 0 bytes */
-		if (bytes_done > 0) {
-			status_bytes_rd = YES;
-			buf += bytes_done;
-			*ppos += bytes_done;
-			total_bytes_done += bytes_done;
-			count -= bytes_done;
-		}
-	}
-	tpqputs(TPQD_ALWAYS, "read request for <0 bytes");
-	return -EINVAL;
-}				/* qic02_tape_read */
-
-
-
-/* The drive detects near-EOT by means of the holes in the tape.
- * When the holes are detected, there is some space left. The drive
- * reports this as a TP_EOM exception. After clearing the exception,
- * the drive should accept two extra blocks.
- *
- * It seems there are some archiver programs that would like to use the
- * extra space for writing a continuation marker. The driver should return
- * end-of-file to the user program on writes, when the holes are detected.
- * If the user-program wants to use the extra space, it should use the
- * MTNOP ioctl() to get the generic status register and may then continue
- * writing (max 1kB).	----------- doesn't work yet...............
- *
- * EOF behaviour on writes:
- * If there is enough room, write all of the data.
- * If there is insufficient room, write as much as will fit and
- * return the amount written. If the requested amount differs from the
- * written amount, the application program should recognize that as the
- * end of file. Subsequent writes will return -ENOSPC.
- * Unless the minor bits specify a rewind-on-close, the tape will not
- * be rewound when it is full. The user-program should do that, if desired.
- * If the driver were to do that automatically, a user-program could be 
- * confused about the EOT/BOT condition after re-opening the tape device.
- *
- * Multiple volume support: Tar closes the tape device before prompting for
- * the next tape. The user may then insert a new tape and tar will open the
- * tape device again. The driver will detect an exception status in (No Cartridge)
- * and force a rewind. After that tar may continue writing.
- */
-static ssize_t qic02_tape_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
-{
-	int type = iminor(filp->f_dentry->d_inode);
-	unsigned short flags = filp->f_flags;
-	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
-
-	if (status_zombie == YES) {
-		tpqputs(TPQD_ALWAYS, "configs not set");
-		return -ENXIO;
-	}
-
-	if (TP_DIAGS(current_type)) {
-		printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%Lx, flags=%x\n",
-		       type, buf, (long) count, filp->f_pos, flags);
-	}
-
-	if (count % TAPE_BLKSIZE) {	/* only allow mod 512 bytes at a time */
-		tpqputs(TPQD_BLKSZ, "Wrong block size");
-		return -EINVAL;
-	}
-
-	if (mode_access == READ) {
-		tpqputs(TPQD_ALWAYS, "Not in write mode");
-		return -EACCES;
-	}
-
-	/* open() does a sense() and we can assume the tape isn't changed
-	 * between open() and release(), so the tperror.exs bits will still
-	 * be valid.
-	 */
-	if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
-		tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
-		return -EACCES;	/* don't even try when write protected */
-	}
-
-	if (doing_read == YES) {
-		terminate_read(0);
-	}
-
-	while ((signed) count >= 0) {
-		/* see how much fits in the kernel buffer */
-		bytes_done = 0;
-		bytes_todo = TPQBUF_SIZE;
-		if (bytes_todo > count) {
-			bytes_todo = count;
-		}
-
-		if (return_write_eof == YES) {
-			/* return_write_eof should be reset on reverse tape movements. */
-
-			if (reported_write_eof == NO) {
-				if (bytes_todo > 0) {
-					tpqputs(TPQD_ALWAYS, "partial write");
-					/* partial write signals EOF to user program */
-				}
-				reported_write_eof = YES;
-				return total_bytes_done;
-			} else {
-				return -ENOSPC;	/* return error */
-			}
-		}
-
-		/* Quit when done. */
-		if (bytes_todo == 0) {
-			return total_bytes_done;
-		}
-
-		/* copy from user to DMA buffer and initiate transfer. */
-		if (bytes_todo > 0) {
-			if (copy_from_user(buffaddr, buf, bytes_todo))
-				return -EFAULT;
-
-/****************** similar problem with read() at FM could happen here at EOT.
- ******************/
-
-/***** if at EOT, 0 bytes can be written. start_dma() will
- ***** fail and write() will return ENXIO error
- *****/
-			if (start_dma(WRITE, bytes_todo) != TE_OK) {
-				tpqputs(TPQD_ALWAYS, "write: start_dma() failed");
-				/* should do sense() on error here */
-				return -ENXIO;
-				/*********** FIXTHIS **************/
-			}
-
-			/* Wait for write to complete, interrupt should wake us. */
-			wait_event(qic02_tape_transfer, (status_error == 0 && dma_mode != 0));
-
-			end_dma(&bytes_done);
-			if (bytes_done > bytes_todo) {
-				tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");
-				return -EIO;
-			}
-			/* If the dma-transfer was aborted because of an exception,
-			 * status_error will have been set in the interrupt handler.
-			 * Then end_dma() will do a sense().
-			 * If the exception was EXC_EOM, the EW-hole was encountered
-			 * and two more blocks could be written. For the time being we'll
-			 * just consider this to be the EOT.
-			 * Otherwise, something Bad happened, such as the maximum number
-			 * of block-rewrites was exceeded. [e.g. A very bad spot on tape was
-			 * encountered. Normally short dropouts are compensated for by
-			 * rewriting the block in error, up to 16 times. I'm not sure
-			 * QIC-24 drives can do this.]
-			 */
-			if (status_error) {
-				if (status_eom_detected == YES) {
-					tpqputs(TPQD_ALWAYS, "write: EW detected");
-					return_write_eof = YES;
-				} else {
-					/* probably EXC_RWA */
-					tpqputs(TPQD_ALWAYS, "write: dma: error in writing");
-					return -EIO;
-				}
-			}
-			if (bytes_todo != bytes_done) {
-				/* EOF or EOM detected. return EOT next time. */
-				return_write_eof = YES;
-			}
-		}
-		/* else: ignore write request for 0 bytes. */
-
-		if (bytes_done > 0) {
-			status_bytes_wr = YES;
-			buf += bytes_done;
-			*ppos += bytes_done;
-			total_bytes_done += bytes_done;
-			count -= bytes_done;
-		}
-	}
-
-	tpqputs(TPQD_ALWAYS, "write request for <0 bytes");
-	if (TPQDBG(DEBUG)) {
-		printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p"
-		       ", total_bytes_done %lx, count %lx\n",
-		       status_bytes_wr, buf, total_bytes_done,
-		       (long) count);
-	}
-	return -EINVAL;
-}				/* qic02_tape_write */
-
-
-
-/* qic02_tape_open()
- * We allow the device to be opened, even if it is marked 'dead' because
- * we want to be able to reset the tape device without rebooting.
- * Only one open tape file at a time, except when minor=255.
- * Minor 255 is only allowed for resetting and always returns <0.
- * 
- * The density command is only allowed when TP_BOM is set. Thus, remember
- * the most recently used minor bits. When they are different from the
- * remembered values, rewind the tape and set the required density.
- * Don't rewind if the minor bits specify density 0.
- */
-
-static int qic02_tape_open(struct inode *inode, struct file *filp)
-{
-	static int qic02_tape_open_no_use_count(struct inode *,
-						struct file *);
-	int open_error;
-
-	open_error = qic02_tape_open_no_use_count(inode, filp);
-	return open_error;
-}
-
-static int qic02_tape_open_no_use_count(struct inode *inode,
-					struct file *filp)
-{
-	int type = iminor(inode);
-	unsigned short flags = filp->f_flags;
-	unsigned short dens = 0;
-	int s;
-
-
-	if (TP_DIAGS(type)) {
-		printk("qic02_tape_open: dev=tpqic2(%d), flags=%x     ",
-			type, flags);
-	}
-
-	if (type == 255) {	/* special case for resetting */
-		if (capable(CAP_SYS_ADMIN)) {
-			return (tape_reset(1) == TE_OK) ? -EAGAIN : -ENXIO;
-		} else {
-			return -EPERM;
-		}
-	}
-
-	if (status_dead == YES) {
-		/* Allow `mt reset' ioctl() even when already open()ed. */
-		return 0;
-	}
-
-	if(test_and_set_bit(0, &tape_open))
-		return -EBUSY;
-		
-	if (status_zombie == YES) {
-		/* no irq/dma/port stuff allocated yet, no reset done
-		 * yet, so return until MTSETCONFIG has been done.
-		 */
-		return 0;
-	}
-
-	status_bytes_rd = NO;
-	status_bytes_wr = NO;
-
-	return_read_eof = NO;	/********????????????????*****/
-	return_write_eof = (status_eot_detected) ? YES : NO;
-
-	/* Clear this in case user app close()d before reading EOF token */
-	status_eof_detected = NO;
-
-	reported_read_eof = NO;
-	reported_write_eof = NO;
-
-
-	switch (flags & O_ACCMODE) {
-	case O_RDONLY:
-		mode_access = READ;
-		break;
-	case O_WRONLY:		/* Fallthru... Strictly speaking this is not correct... */
-	case O_RDWR:		/* Reads are allowed as long as nothing is written */
-		mode_access = WRITE;
-		break;
-	}
-
-	/* This is to avoid tape-changed problems (TP_CNI exception).
-	 *
-	 * Since removing the cartridge will not raise an exception,
-	 * we always do a tp_sense() to make sure we have the proper
-	 * CNI status, the 2150L may need an additional sense.... - Eddy
-	 */
-	s = tp_sense(TP_WRP | TP_EOM | TP_BOM | TP_CNI | TP_EOR);
-
-	if (s == TE_OK) {
-		/* Try to clear cartridge-changed status for Archive-2150L */
-		if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
-			s = tp_sense(TP_WRP | TP_EOM | TP_BOM | TP_CNI | TP_EOR);
-		}
-	}
-
-	if (s != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "open: sense() failed");
-		clear_bit(0, &tape_open);
-		return -EIO;
-	}
-
-	/* exception bits should be up-to-date now, so check for
-	 * tape presence and exit if absent.
-	 * Even `mt stat' will fail without a tape.
-	 */
-	if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
-		tpqputs(TPQD_ALWAYS, "No tape present.");
-		clear_bit(0, &tape_open);
-		return -EIO;
-	}
-
-	/* At this point we can assume that a tape is present and
-	 * that it will remain present until release() is called.
-	 */
-
-	/* not allowed to do QCMD_DENS_* unless tape is rewound */
-	if ((TP_DENS(type) != 0) && (TP_DENS(current_type) != TP_DENS(type))) {
-		/* force rewind if minor bits have changed,
-		 * i.e. user wants to use tape in different format.
-		 * [assuming single drive operation]
-		 */
-		if (TP_HAVE_DENS) {
-			tpqputs(TPQD_REWIND, "Density minor bits have changed. Forcing rewind.");
-			need_rewind = YES;
-		}
-	} else {
-		/* density bits still the same, but TP_DIAGS bit 
-		 * may have changed.
-		 */
-		current_type = type;
-	}
-
-	if (need_rewind == YES) {
-/***************** CHECK THIS!!!!!!!! **********/
-		s = do_qic_cmd(QCMD_REWIND, TIM_R);
-		if (s != 0) {
-			tpqputs(TPQD_ALWAYS, "open: rewind failed");
-			return -EIO;
-		}
-	}
-
-
-/* Note: After a reset command, the controller will rewind the tape
- *	 just before performing any tape movement operation! ************ SO SET need_rewind flag!!!!!
- */
-	if (status_dead == YES) {
-		tpqputs(TPQD_ALWAYS, "open: tape dead, attempting reset");
-		if (tape_reset(1) != TE_OK) {
-			return -ENXIO;
-		} else {
-			status_dead = NO;
-			if (tp_sense(~(TP_ST1 | TP_ILL)) != TE_OK) {
-				tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
-				status_dead = YES;	/* try reset next time */
-				return -EIO;
-			}
-		}
-	}
-
-	/* things should be ok, once we get here */
-
-
-	/* set density: only allowed when TP_BOM status bit is set,
-	 * so we must have done a rewind by now. If not, just skip over.
-	 * Only give set density command when minor bits have changed.
-	 */
-	if (TP_DENS(current_type) == TP_DENS(type)) {
-		return 0;
-	}
-
-	current_type = type;
-	need_rewind = NO;
-	if (TP_HAVE_DENS) {
-		dens = TP_DENS(type);
-	}
-
-	if (dens < sizeof(format_names) / sizeof(char *))
-		printk(TPQIC02_NAME ": format: %s%s\n", (dens != 0) ? "QIC-" : "", format_names[dens]);
-	else
-		tpqputs(TPQD_REWIND, "Wait for retensioning...");
-
-	switch (TP_DENS(type)) {
-	case 0:		/* Minor 0 is for drives without set-density support */
-		s = 0;
-		break;
-	case 1:
-		s = do_qic_cmd(QCMD_DENS_11, TIM_S);
-		break;
-	case 2:
-		s = do_qic_cmd(QCMD_DENS_24, TIM_S);
-		break;
-	case 3:
-		s = do_qic_cmd(QCMD_DENS_120, TIM_S);
-		break;
-	case 4:
-		s = do_qic_cmd(QCMD_DENS_150, TIM_S);
-		break;
-	case 5:
-		s = do_qic_cmd(QCMD_DENS_300, TIM_S);
-		break;
-	case 6:
-		s = do_qic_cmd(QCMD_DENS_600, TIM_S);
-		break;
-	default:		/* otherwise do a retension before anything else */
-		s = do_qic_cmd(QCMD_RETEN, TIM_R);
-	}
-	if (s != 0) {
-		status_dead = YES;	/* force reset */
-		current_type = 0;/* earlier 0xff80 */
-		return -EIO;
-	}
-
-	return 0;
-}				/* qic02_tape_open */
-
-
-static int qic02_tape_release(struct inode *inode, struct file *filp)
-{
-	int type = iminor(inode);
-
-	if (TP_DIAGS(type)) {
-		printk("qic02_tape_release: dev=tpqic2(%d)\n", type);
-	}
-
-	if (status_zombie == NO) {	/* don't rewind in zombie mode */
-		/* Terminate any pending write cycle. Terminating the read-cycle
-		 * is delayed until it is required to do so for a new command.
-		 */
-		terminate_write(-1);
-
-		if (status_dead == YES) {
-			tpqputs(TPQD_ALWAYS, "release: device dead!?");
-		}
-
-		/* Rewind only if minor number requires it AND 
-		 * read/writes have been done. ************* IS THIS CORRECT??????????
-		 */
-		if (TP_REWCLOSE(type) && (status_bytes_rd | status_bytes_wr)) {
-			tpqputs(TPQD_REWIND, "release: Doing rewind...");
-			(void) do_qic_cmd(QCMD_REWIND, TIM_R);
-		}
-	}
-	clear_bit(0, &tape_open);
-	return 0;
-}				/* qic02_tape_release */
-
-
-#ifdef CONFIG_QIC02_DYNCONF
-/* Set masks etc. based on the interface card type. */
-static int update_ifc_masks(int ifc)
-{
-	QIC02_TAPE_IFC = ifc;
-
-	if ((QIC02_TAPE_IFC == WANGTEK) || (QIC02_TAPE_IFC == EVEREX)) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_STAT_READY = WT_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION = WT_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = WT_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = WT_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = WT_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = WT_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = WT_QIC02_CTL_REQUEST;
-
-		if (QIC02_TAPE_DMA == 3) {
-			WT_CTL_DMA = WT_CTL_DMA3;
-		} else if (QIC02_TAPE_DMA == 1) {
-			WT_CTL_DMA = WT_CTL_DMA1;
-		} else {
-			tpqputs(TPQD_ALWAYS,
-				"Unsupported or incorrect DMA channel");
-			return -EIO;
-		}
-
-		if (QIC02_TAPE_IFC == EVEREX) {
-			/* Everex is a special case for Wangtek (actually
-			 * it's the other way 'round, but I saw Wangtek first)
-			 */
-			if (QIC02_TAPE_DMA == 3) {
-				WT_CTL_DMA = WT_CTL_DMA1;
-			}
-
-			/* Fixup the kernel copy of the IFC type to that
-			 * we don't have to distinguish between Wangtek and
-			 * and Everex at runtime.
-			 */
-			QIC02_TAPE_IFC = WANGTEK;
-		}
-	} else if (QIC02_TAPE_IFC == ARCHIVE) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT;
-		QIC02_STAT_READY = AR_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION = AR_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = AR_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = AR_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = AR_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = AR_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = AR_QIC02_CTL_REQUEST;
-
-		if (QIC02_TAPE_DMA > 3) {
-			tpqputs(TPQD_ALWAYS,
-				"Unsupported or incorrect DMA channel");
-			return -EIO;
-		}
-	} else if (QIC02_TAPE_IFC == MOUNTAIN) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT + 1;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT;
-
-		QIC02_STAT_READY = MTN_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION = MTN_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = MTN_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = MTN_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = MTN_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = MTN_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = MTN_QIC02_CTL_REQUEST;
-
-		if (QIC02_TAPE_DMA > 3) {
-			tpqputs(TPQD_ALWAYS,
-				"Unsupported or incorrect DMA channel");
-			return -EIO;
-		}
-	} else {
-		tpqputs(TPQD_ALWAYS, "Invalid interface type");
-		return -ENXIO;
-	}
-	return qic02_get_resources();
-}				/* update_ifc_masks */
-#endif
-
-
-/* ioctl allows user programs to rewind the tape and stuff like that */
-static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int iocmd, unsigned long ioarg)
-{
-	int error;
-	int c;
-	struct mtop operation;
-	unsigned char blk_addr[6];
-	struct mtpos ioctl_tell;
-	void __user *argp = (void __user *)ioarg;
-
-
-	if (TP_DIAGS(current_type))
-		printk(TPQIC02_NAME ": ioctl(%4x, %4lx)\n", iocmd, ioarg);
-
-	if (!inode)
-		return -EINVAL;
-
-	/* check iocmd first */
-
-	c = _IOC_NR(iocmd);
-
-#ifdef CONFIG_QIC02_DYNCONF
-	if (c == _IOC_NR(MTIOCGETCONFIG)) {
-		CHECK_IOC_SIZE(mtconfiginfo);
-
-		if (copy_to_user(argp, &qic02_tape_dynconf, sizeof(qic02_tape_dynconf)))
-			return -EFAULT;
-		return 0;
-	} else if (c == _IOC_NR(MTIOCSETCONFIG)) {
-		/* One should always do a MTIOCGETCONFIG first, then update
-		 * user-settings, then write back with MTIOCSETCONFIG.
-		 * The qic02conf program should re-open() the device before actual
-		 * use, to make sure everything is initialized.
-		 */
-
-		CHECK_IOC_SIZE(mtconfiginfo);
-
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-
-		if (doing_read != NO || doing_write != NO)
-			return -EBUSY;
-
-		if (status_zombie == NO)
-			qic02_release_resources();	/* and go zombie */
-
-		/* copy struct from user space to kernel space */
-		if (copy_from_user(&qic02_tape_dynconf, argp, sizeof(qic02_tape_dynconf)))
-			return -EFAULT;
-		
-		return update_ifc_masks(qic02_tape_dynconf.ifc_type);
-	}
-	if (status_zombie == YES) {
-		tpqputs(TPQD_ALWAYS, "Configs not set");
-		return -ENXIO;
-	}
-#endif
-	if (c == _IOC_NR(MTIOCTOP)) {
-		CHECK_IOC_SIZE(mtop);
-
-		/* copy mtop struct from user space to kernel space */
-		if (copy_from_user(&operation, argp, sizeof(operation)))
-			return -EFAULT;
-
-		/* ---note: mt_count is signed, negative seeks must be
-		 * ---      translated to seeks in opposite direction!
-		 * (only needed for Sun-programs, I think.)
-		 */
-		/* ---note: MTFSF with count 0 should position the
-		 * ---      tape at the beginning of the current file.
-		 */
-
-		if (TP_DIAGS(current_type))
-			printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
-
-		if (operation.mt_count < 0)
-			tpqputs(TPQD_ALWAYS, "Warning: negative mt_count ignored");
-
-		ioctl_status.mt_resid = operation.mt_count;
-		if (operation.mt_op == MTSEEK) {
-			if (!TP_HAVE_SEEK)
-				return -ENOTTY;
-
-			seek_addr_buf[0] = (operation.mt_count >> 16) & 0xff;
-			seek_addr_buf[1] = (operation.mt_count >> 8) & 0xff;
-			seek_addr_buf[2] = (operation.mt_count) & 0xff;
-			if (operation.mt_count >> 24)
-				return -EINVAL;
-			
-			if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
-				return error;
-
-			ioctl_status.mt_resid = 0;
-		} else {
-			while (operation.mt_count > 0) {
-				operation.mt_count--;
-				if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
-					return error;
-
-				ioctl_status.mt_resid = operation.mt_count;
-			}
-		}
-		return 0;
-
-	} else if (c == _IOC_NR(MTIOCGET)) {
-		if (TP_DIAGS(current_type))
-			printk("GET ");
-
-		CHECK_IOC_SIZE(mtget);
-
-		/* It appears (gmt(1)) that it is normal behaviour to
-		 * first set the status with MTNOP, and then to read
-		 * it out with MTIOCGET
-		 */
-
-		/* copy results to user space */
-		if (copy_to_user(argp, &ioctl_status, sizeof(ioctl_status)))
-			return -EFAULT;
-		return 0;
-	} else if (TP_HAVE_TELL && (c == _IOC_NR(MTIOCPOS))) {
-		if (TP_DIAGS(current_type))
-			printk("POS ");
-
-		CHECK_IOC_SIZE(mtpos);
-
-		tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
-		if (doing_read == YES || doing_write == YES)
-			finish_rw(AR_QCMDV_TELL_BLK);
-
-		c = rdstatus((char *) blk_addr, sizeof(blk_addr), AR_QCMDV_TELL_BLK);
-		if (c != TE_OK)
-			return -EIO;
-
-		ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
-
-		/* copy results to user space */
-		if (copy_to_user(argp, &ioctl_tell, sizeof(ioctl_tell)))
-			return -EFAULT;
-		return 0;
-
-	} else
-		return -ENOTTY;	/* Other cmds not supported. */
-}				/* qic02_tape_ioctl */
-
-
-static ssize_t qic02_do_tape_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
-{
-	int err;
-	
-	down(&tape_op);	
-	err = qic02_tape_read(filp, buf, count, ppos);
-	up(&tape_op);
-	
-	return err;
-}
-
-static ssize_t qic02_do_tape_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
-{
-	int err;
-
-	down(&tape_op);	
-	err = qic02_tape_write(filp, buf, count, ppos);
-	up(&tape_op);
-	
-	return err;
-}
-
-static int qic02_do_tape_ioctl(struct inode *inode, struct file *filp, unsigned int iocmd, unsigned long ioarg)
-{
-	int err;
-	
-	down(&tape_op);	
-	err = qic02_tape_ioctl(inode, filp,  iocmd, ioarg);
-	up(&tape_op);
-	
-	return err;
-}
-
-/* These are (most) of the interface functions: */
-static struct file_operations qic02_tape_fops = {
-	.owner = THIS_MODULE,
-	.llseek = no_llseek,
-	.read = qic02_do_tape_read,
-	.write = qic02_do_tape_write,
-	.ioctl = qic02_do_tape_ioctl,
-	.open = qic02_tape_open,
-	.release = qic02_tape_release,
-};
-
-
-static void qic02_release_resources(void)
-{
-	free_irq(QIC02_TAPE_IRQ, NULL);
-	free_dma(QIC02_TAPE_DMA);
-	release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
-	if (buffaddr)
-		free_pages((unsigned long) buffaddr, get_order(TPQBUF_SIZE));
-	buffaddr = NULL;	/* Better to cause a panic than overwite someone else */
-	status_zombie = YES;
-}				/* qic02_release_resources */
-
-
-static int qic02_get_resources(void)
-{
-	/* First perform some checks. If one of them fails,
-	 * the tape driver will not be registered to the system.
-	 */
-
-	/* for DYNCONF, allocating IO, DMA and IRQ should not be done until 
-	 * the config parameters have been set using MTSETCONFIG.
-	 */
-
-	/* Grab the IO region. */
-	if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME)) {
-		printk(TPQIC02_NAME ": IO space at 0x%x [%d ports] already reserved\n",
-		       QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
-		return -ENXIO;
-	}
-
-	/* get IRQ */
-	if (request_irq(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", NULL)) {
-		printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n", QIC02_TAPE_IRQ);
-		release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
-		return -EBUSY;
-	}
-
-	/* After IRQ, allocate DMA channel */
-	if (request_dma(QIC02_TAPE_DMA, "QIC-02")) {
-		printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n", QIC02_TAPE_DMA);
-		free_irq(QIC02_TAPE_IRQ, NULL);
-		release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
-		return -EBUSY;
-	}
-
-	/* Setup the page-address for the dma transfer. */
-	buffaddr = (void *) __get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
-	if (!buffaddr) {
-		qic02_release_resources();
-		return -EBUSY;	/* Not ideal, EAGAIN perhaps? */
-	}
-
-	memset(buffaddr, 0, TPQBUF_SIZE);
-
-	printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
-	       QIC02_TAPE_IRQ, QIC02_TAPE_DMA, ((QIC02_TAPE_IFC == ARCHIVE)
-						|| (QIC02_TAPE_IFC ==
-						    MOUNTAIN)) ?
-	       QIC02_CMD_PORT : QIC02_STAT_PORT,
-	       (QIC02_TAPE_IFC ==
-		MOUNTAIN) ? "Mountain" : ((QIC02_TAPE_IFC ==
-					   ARCHIVE) ? "Archive" :
-					  "Wangtek"));
-
-	if (tape_reset(0) != TE_OK || tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
-		/* No drive detected, so vanish */
-		tpqputs(TPQD_ALWAYS, "No drive detected -- releasing IO/IRQ/DMA.");
-		status_dead = YES;
-		qic02_release_resources();
-		return -EIO;
-	}
-
-	/* All should be ok now */
-	status_zombie = NO;
-	return 0;
-}				/* qic02_get_resources */
-
-int __init qic02_tape_init(void)
-{
-	if (TPSTATSIZE != 6) {
-		printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
-		return -ENODEV;
-	}
-	if ((TPQBUF_SIZE < 512) || (TPQBUF_SIZE >= 0x10000)) {
-		printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
-		return -ENODEV;
-	}
-
-	current_type = 0;
-
-#ifndef CONFIG_QIC02_DYNCONF
-	printk(TPQIC02_NAME ": IRQ %d, DMA %d, IO 0x%x, IFC %s, %s, %s\n",
-	       QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
-# if QIC02_TAPE_IFC == WANGTEK
-	       QIC02_STAT_PORT, "Wangtek",
-# elif QIC02_TAPE_IFC == ARCHIVE
-	       QIC02_CMD_PORT, "Archive",
-# elif QIC02_TAPE_IFC == MOUNTAIN
-	       QIC02_CMD_PORT, "Mountain",
-# else
-#  error
-# endif
-	       rcs_revision, rcs_date);
-	if (qic02_get_resources())
-		return -ENODEV;
-#else
-	printk(TPQIC02_NAME ": Runtime config, %s, %s\n", rcs_revision, rcs_date);
-#endif
-	printk(TPQIC02_NAME ": DMA buffers: %u blocks\n", NR_BLK_BUF);
-	/* If we got this far, install driver functions */
-	if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops)) 
-	{
-		printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
-#ifndef CONFIG_QIC02_DYNCONF
-		qic02_release_resources();
-#endif
-		return -ENODEV;
-	}
-
-	tpqic02_class = class_simple_create(THIS_MODULE, TPQIC02_NAME);
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 2), NULL, "ntpqic11");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 2),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic11");
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 3), NULL, "tpqic11");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 3),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic11");
-
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 4), NULL, "ntpqic24");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 4),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic24");
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 5), NULL, "tpqic24");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 5),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic24");
-
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 6), NULL, "ntpqic20");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 6),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic120");
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 7), NULL, "tpqic20");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 7),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic120");
-
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 8), NULL, "ntpqic50");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 8),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic150");
-	class_simple_device_add(tpqic02_class, MKDEV(QIC02_TAPE_MAJOR, 9), NULL, "tpqic50");
-	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 9),
-		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic150");
-
-	init_waitqueue_head(&qic02_tape_transfer);
-	/* prepare timer */
-	TIMEROFF;
-	init_timer(&tp_timer);
-	tp_timer.function = qic02_tape_times_out;
-
-#ifndef CONFIG_QIC02_DYNCONF
-	if (tape_reset(0) != TE_OK || tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
-		/* No drive detected, so vanish */
-		tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
-		qic02_release_resources();
-		status_dead = YES;
-		return -ENODEV;
-	} else {
-		if (is_exception()) {
-			tpqputs(TPQD_ALWAYS, "exception detected\n");
-			(void) tp_sense(TP_WRP | TP_POR | TP_CNI);
-		}
-	}
-#endif
-
-	/* initialize generic status for ioctl requests */
-
-	ioctl_status.mt_type = QIC02_TAPE_DRIVE;	/* MT_IS* id nr */
-
-	ioctl_status.mt_resid = 0;	/* ---residual count */
-	ioctl_status.mt_gstat = 0;	/* ---generic status */
-	ioctl_status.mt_erreg = 0;	/* not used */
-	ioctl_status.mt_fileno = 0;	/* number of current file on tape */
-	ioctl_status.mt_blkno = 0;	/* number of current (logical) block */
-
-	return 0;
-}				/* qic02_tape_init */
-
-static void qic02_module_exit(void)
-{
-	unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
-	if (status_zombie == NO)
-		qic02_release_resources();
-		
-	devfs_remove("ntpqic11");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 2));
-	devfs_remove("tpqic11");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 3));
-	devfs_remove("ntpqic24");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 4));
-	devfs_remove("tpqic24");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 5));
-	devfs_remove("ntpqic120");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 6));
-	devfs_remove("tpqic120");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 7));
-	devfs_remove("ntpqic150");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 8));
-	devfs_remove("tpqic150");
-	class_simple_device_remove(MKDEV(QIC02_TAPE_MAJOR, 9));
-
-	class_simple_destroy(tpqic02_class);
-}
-
-static int qic02_module_init(void)
-{
-	int retval;
-	retval = qic02_tape_init();
-# ifdef CONFIG_QIC02_DYNCONF
-	/* This allows the dynamic config program to setup the card
-	 * by presetting qic02_tape_dynconf via insmod
-	 */
-	if (!retval && qic02_tape_dynconf.ifc_type) {
-		retval = update_ifc_masks(qic02_tape_dynconf.ifc_type);
-		if (retval) {
-			qic02_module_exit();
-		}
-	}
-# endif
-	return retval;
-}
-
-MODULE_LICENSE("GPL");
-
-module_init(qic02_module_init);
-module_exit(qic02_module_exit);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -185,7 +185,7 @@ char *tty_name(struct tty_struct *tty, c
 
 EXPORT_SYMBOL(tty_name);
 
-inline int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
 			      const char *routine)
 {
 #ifdef TTY_PARANOIA_CHECK
@@ -1789,7 +1789,6 @@ retry_open:
 	}
 #ifdef CONFIG_VT
 	if (device == MKDEV(TTY_MAJOR,0)) {
-		extern int fg_console;
 		extern struct tty_driver *console_driver;
 		driver = console_driver;
 		index = fg_console;
@@ -2016,11 +2015,10 @@ static int tiocswinsz(struct tty_struct 
 		return 0;
 #ifdef CONFIG_VT
 	if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
-		unsigned int currcons = tty->index;
 		int rc;
 
 		acquire_console_sem();
-		rc = vc_resize(currcons, tmp_ws.ws_col, tmp_ws.ws_row);
+		rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
 		release_console_sem();
 		if (rc)
 			return -ENXIO;
@@ -2632,6 +2630,7 @@ static void initialize_tty_struct(struct
 	tty->magic = TTY_MAGIC;
 	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
 	tty->pgrp = -1;
+	tty->overrun_time = jiffies;
 	tty->flip.char_buf_ptr = tty->flip.char_buf;
 	tty->flip.flag_buf_ptr = tty->flip.flag_buf;
 	INIT_WORK(&tty->flip.work, flush_to_ldisc, tty);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -52,14 +52,17 @@ vcs_size(struct inode *inode)
 	int size;
 	int minor = iminor(inode);
 	int currcons = minor & 127;
+	struct vc_data *vc;
+
 	if (currcons == 0)
 		currcons = fg_console;
 	else
 		currcons--;
 	if (!vc_cons_allocated(currcons))
 		return -ENXIO;
+	vc = vc_cons[currcons].d;
 
-	size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_cols;
+	size = vc->vc_rows * vc->vc_cols;
 
 	if (minor & 128)
 		size = 2*size + HEADER_SIZE;
@@ -442,7 +445,7 @@ vcs_write(struct file *file, const char 
 		buf += orig_count;
 		pos += orig_count;
 		if (org0)
-			update_region(currcons, (unsigned long)(org0), org-org0);
+			update_region(vc, (unsigned long)(org0), org - org0);
 	}
 	*ppos += written;
 	ret = written;
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c
new file mode 100644
--- /dev/null
+++ b/drivers/char/vr41xx_rtc.c
@@ -0,0 +1,709 @@
+/*
+ *  Driver for NEC VR4100 series  Real Time Clock unit.
+ *
+ *  Copyright (C) 2003-2005  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.
+ *
+ *  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/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mc146818rtc.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <asm/div64.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/uaccess.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
+MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
+MODULE_LICENSE("GPL");
+
+#define RTC1_TYPE1_START	0x0b0000c0UL
+#define RTC1_TYPE1_END		0x0b0000dfUL
+#define RTC2_TYPE1_START	0x0b0001c0UL
+#define RTC2_TYPE1_END		0x0b0001dfUL
+
+#define RTC1_TYPE2_START	0x0f000100UL
+#define RTC1_TYPE2_END		0x0f00011fUL
+#define RTC2_TYPE2_START	0x0f000120UL
+#define RTC2_TYPE2_END		0x0f00013fUL
+
+#define RTC1_SIZE		0x20
+#define RTC2_SIZE		0x20
+
+/* RTC 1 registers */
+#define ETIMELREG		0x00
+#define ETIMEMREG		0x02
+#define ETIMEHREG		0x04
+/* RFU */
+#define ECMPLREG		0x08
+#define ECMPMREG		0x0a
+#define ECMPHREG		0x0c
+/* RFU */
+#define RTCL1LREG		0x10
+#define RTCL1HREG		0x12
+#define RTCL1CNTLREG		0x14
+#define RTCL1CNTHREG		0x16
+#define RTCL2LREG		0x18
+#define RTCL2HREG		0x1a
+#define RTCL2CNTLREG		0x1c
+#define RTCL2CNTHREG		0x1e
+
+/* RTC 2 registers */
+#define TCLKLREG		0x00
+#define TCLKHREG		0x02
+#define TCLKCNTLREG		0x04
+#define TCLKCNTHREG		0x06
+/* RFU */
+#define RTCINTREG		0x1e
+ #define TCLOCK_INT		0x08
+ #define RTCLONG2_INT		0x04
+ #define RTCLONG1_INT		0x02
+ #define ELAPSEDTIME_INT	0x01
+
+#define RTC_FREQUENCY		32768
+#define MAX_PERIODIC_RATE	6553
+#define MAX_USER_PERIODIC_RATE	64
+
+static void __iomem *rtc1_base;
+static void __iomem *rtc2_base;
+
+#define rtc1_read(offset)		readw(rtc1_base + (offset))
+#define rtc1_write(offset, value)	writew((value), rtc1_base + (offset))
+
+#define rtc2_read(offset)		readw(rtc2_base + (offset))
+#define rtc2_write(offset, value)	writew((value), rtc2_base + (offset))
+
+static unsigned long epoch = 1970;	/* Jan 1 1970 00:00:00 */
+
+static spinlock_t rtc_task_lock;
+static wait_queue_head_t rtc_wait;
+static unsigned long rtc_irq_data;
+static struct fasync_struct *rtc_async_queue;
+static rtc_task_t *rtc_callback;
+static char rtc_name[] = "RTC";
+static unsigned long periodic_frequency;
+static unsigned long periodic_count;
+
+typedef enum {
+	RTC_RELEASE,
+	RTC_OPEN,
+} rtc_status_t;
+
+static rtc_status_t rtc_status;
+
+typedef enum {
+	FUNCTION_RTC_IOCTL,
+	FUNCTION_RTC_CONTROL,
+} rtc_callfrom_t;
+
+struct resource rtc_resource[2] = {
+	{	.name	= rtc_name,
+		.flags	= IORESOURCE_MEM,	},
+	{	.name	= rtc_name,
+		.flags	= IORESOURCE_MEM,	},
+};
+
+#define RTC_NUM_RESOURCES	sizeof(rtc_resource) / sizeof(struct resource)
+
+static inline unsigned long read_elapsed_second(void)
+{
+	unsigned long first_low, first_mid, first_high;
+	unsigned long second_low, second_mid, second_high;
+
+	do {
+		first_low = rtc1_read(ETIMELREG);
+		first_mid = rtc1_read(ETIMEMREG);
+		first_high = rtc1_read(ETIMEHREG);
+		second_low = rtc1_read(ETIMELREG);
+		second_mid = rtc1_read(ETIMEMREG);
+		second_high = rtc1_read(ETIMEHREG);
+	} while (first_low != second_low || first_mid != second_mid ||
+	         first_high != second_high);
+
+	return (first_high << 17) | (first_mid << 1) | (first_low >> 15);
+}
+
+static inline void write_elapsed_second(unsigned long sec)
+{
+	spin_lock_irq(&rtc_lock);
+
+	rtc1_write(ETIMELREG, (uint16_t)(sec << 15));
+	rtc1_write(ETIMEMREG, (uint16_t)(sec >> 1));
+	rtc1_write(ETIMEHREG, (uint16_t)(sec >> 17));
+
+	spin_unlock_irq(&rtc_lock);
+}
+
+static void set_alarm(struct rtc_time *time)
+{
+	unsigned long alarm_sec;
+
+	alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+	                   time->tm_hour, time->tm_min, time->tm_sec);
+
+	spin_lock_irq(&rtc_lock);
+
+	rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
+	rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
+	rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
+
+	spin_unlock_irq(&rtc_lock);
+}
+
+static void read_alarm(struct rtc_time *time)
+{
+	unsigned long low, mid, high;
+
+	spin_lock_irq(&rtc_lock);
+
+	low = rtc1_read(ECMPLREG);
+	mid = rtc1_read(ECMPMREG);
+	high = rtc1_read(ECMPHREG);
+
+	spin_unlock_irq(&rtc_lock);
+
+	to_tm((high << 17) | (mid << 1) | (low >> 15), time);
+	time->tm_year -= 1900;
+}
+
+static void read_time(struct rtc_time *time)
+{
+	unsigned long epoch_sec, elapsed_sec;
+
+	epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
+	elapsed_sec = read_elapsed_second();
+
+	to_tm(epoch_sec + elapsed_sec, time);
+	time->tm_year -= 1900;
+}
+
+static void set_time(struct rtc_time *time)
+{
+	unsigned long epoch_sec, current_sec;
+
+	epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
+	current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+	                     time->tm_hour, time->tm_min, time->tm_sec);
+
+	write_elapsed_second(current_sec - epoch_sec);
+}
+
+static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long irq_data;
+	int retval = 0;
+
+	if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&rtc_wait, &wait);
+
+	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&rtc_lock);
+		irq_data = rtc_irq_data;
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+
+		if (irq_data != 0)
+			break;
+
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+	} while (1);
+
+	if (retval == 0) {
+		if (count == sizeof(unsigned int)) {
+			retval = put_user(irq_data, (unsigned int __user *)buf);
+			if (retval == 0)
+				retval = sizeof(unsigned int);
+		} else {
+			retval = put_user(irq_data, (unsigned long __user *)buf);
+			if (retval == 0)
+				retval = sizeof(unsigned long);
+		}
+
+	}
+
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rtc_wait, &wait);
+
+	return retval;
+}
+
+static unsigned int rtc_poll(struct file *file, struct poll_table_struct *table)
+{
+	poll_wait(file, &rtc_wait, table);
+
+	if (rtc_irq_data != 0)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from)
+{
+	struct rtc_time time;
+	unsigned long count;
+
+	switch (cmd) {
+	case RTC_AIE_ON:
+		enable_irq(ELAPSEDTIME_IRQ);
+		break;
+	case RTC_AIE_OFF:
+		disable_irq(ELAPSEDTIME_IRQ);
+		break;
+	case RTC_PIE_ON:
+		enable_irq(RTCLONG1_IRQ);
+		break;
+	case RTC_PIE_OFF:
+		disable_irq(RTCLONG1_IRQ);
+		break;
+	case RTC_ALM_SET:
+		if (copy_from_user(&time, (struct rtc_time __user *)arg,
+		                   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		set_alarm(&time);
+		break;
+	case RTC_ALM_READ:
+		memset(&time, 0, sizeof(struct rtc_time));
+		read_alarm(&time);
+		break;
+	case RTC_RD_TIME:
+		memset(&time, 0, sizeof(struct rtc_time));
+		read_time(&time);
+		if (copy_to_user((void __user *)arg, &time, sizeof(struct rtc_time)))
+			return -EFAULT;
+		break;
+	case RTC_SET_TIME:
+		if (capable(CAP_SYS_TIME) == 0)
+			return -EACCES;
+
+		if (copy_from_user(&time, (struct rtc_time __user *)arg,
+		                   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		set_time(&time);
+		break;
+	case RTC_IRQP_READ:
+		return put_user(periodic_frequency, (unsigned long __user *)arg);
+		break;
+	case RTC_IRQP_SET:
+		if (arg > MAX_PERIODIC_RATE)
+			return -EINVAL;
+
+		if (from == FUNCTION_RTC_IOCTL && arg > MAX_USER_PERIODIC_RATE &&
+		    capable(CAP_SYS_RESOURCE) == 0)
+			return -EACCES;
+
+		periodic_frequency = arg;
+
+		count = RTC_FREQUENCY;
+		do_div(count, arg);
+
+		periodic_count = count;
+
+		spin_lock_irq(&rtc_lock);
+
+		rtc1_write(RTCL1LREG, count);
+		rtc1_write(RTCL1HREG, count >> 16);
+
+		spin_unlock_irq(&rtc_lock);
+		break;
+	case RTC_EPOCH_READ:
+		return put_user(epoch, (unsigned long __user *)arg);
+	case RTC_EPOCH_SET:
+		/* Doesn't support before 1900 */
+		if (arg < 1900)
+			return -EINVAL;
+
+		if (capable(CAP_SYS_TIME) == 0)
+			return -EACCES;
+
+		epoch = arg;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                     unsigned long arg)
+{
+	return rtc_do_ioctl(cmd, arg, FUNCTION_RTC_IOCTL);
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	spin_lock_irq(&rtc_lock);
+
+	if (rtc_status == RTC_OPEN) {
+		spin_unlock_irq(&rtc_lock);
+		return -EBUSY;
+	}
+
+	rtc_status = RTC_OPEN;
+	rtc_irq_data = 0;
+
+	spin_unlock_irq(&rtc_lock);
+
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	if (file->f_flags & FASYNC)
+		(void)fasync_helper(-1, file, 0, &rtc_async_queue);
+
+	spin_lock_irq(&rtc_lock);
+
+	rtc1_write(ECMPLREG, 0);
+	rtc1_write(ECMPMREG, 0);
+	rtc1_write(ECMPHREG, 0);
+	rtc1_write(RTCL1LREG, 0);
+	rtc1_write(RTCL1HREG, 0);
+
+	rtc_status = RTC_RELEASE;
+
+	spin_unlock_irq(&rtc_lock);
+
+	disable_irq(ELAPSEDTIME_IRQ);
+	disable_irq(RTCLONG1_IRQ);
+
+	return 0;
+}
+
+static int rtc_fasync(int fd, struct file *file, int on)
+{
+	return fasync_helper(fd, file, on, &rtc_async_queue);
+}
+
+static struct file_operations rtc_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= rtc_read,
+	.poll		= rtc_poll,
+	.ioctl		= rtc_ioctl,
+	.open		= rtc_open,
+	.release	= rtc_release,
+	.fasync		= rtc_fasync,
+};
+
+static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	spin_lock(&rtc_lock);
+	rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
+
+	rtc_irq_data += 0x100;
+	rtc_irq_data &= ~0xff;
+	rtc_irq_data |= RTC_AF;
+	spin_unlock(&rtc_lock);
+
+	spin_lock(&rtc_lock);
+	if (rtc_callback)
+		rtc_callback->func(rtc_callback->private_data);
+	spin_unlock(&rtc_lock);
+
+	wake_up_interruptible(&rtc_wait);
+
+	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long count = periodic_count;
+
+	spin_lock(&rtc_lock);
+	rtc2_write(RTCINTREG, RTCLONG1_INT);
+
+	rtc1_write(RTCL1LREG, count);
+	rtc1_write(RTCL1HREG, count >> 16);
+
+	rtc_irq_data += 0x100;
+	rtc_irq_data &= ~0xff;
+	rtc_irq_data |= RTC_PF;
+	spin_unlock(&rtc_lock);
+
+	spin_lock(&rtc_task_lock);
+	if (rtc_callback)
+		rtc_callback->func(rtc_callback->private_data);
+	spin_unlock(&rtc_task_lock);
+
+	wake_up_interruptible(&rtc_wait);
+
+	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+
+	return IRQ_HANDLED;
+}
+
+int rtc_register(rtc_task_t *task)
+{
+	if (task == NULL || task->func == NULL)
+		return -EINVAL;
+
+	spin_lock_irq(&rtc_lock);
+	if (rtc_status == RTC_OPEN) {
+		spin_unlock_irq(&rtc_lock);
+		return -EBUSY;
+	}
+
+	spin_lock(&rtc_task_lock);
+	if (rtc_callback != NULL) {
+		spin_unlock(&rtc_task_lock);
+		spin_unlock_irq(&rtc_task_lock);
+		return -EBUSY;
+	}
+
+	rtc_callback = task;
+	spin_unlock(&rtc_task_lock);
+
+	rtc_status = RTC_OPEN;
+
+	spin_unlock_irq(&rtc_lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(rtc_register);
+
+int rtc_unregister(rtc_task_t *task)
+{
+	spin_lock_irq(&rtc_task_lock);
+	if (task == NULL || rtc_callback != task) {
+		spin_unlock_irq(&rtc_task_lock);
+		return -ENXIO;
+	}
+
+	spin_lock(&rtc_lock);
+
+	rtc1_write(ECMPLREG, 0);
+	rtc1_write(ECMPMREG, 0);
+	rtc1_write(ECMPHREG, 0);
+	rtc1_write(RTCL1LREG, 0);
+	rtc1_write(RTCL1HREG, 0);
+
+	rtc_status = RTC_RELEASE;
+
+	spin_unlock(&rtc_lock);
+
+	rtc_callback = NULL;
+
+	spin_unlock_irq(&rtc_task_lock);
+
+	disable_irq(ELAPSEDTIME_IRQ);
+	disable_irq(RTCLONG1_IRQ);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(rtc_unregister);
+
+int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	spin_lock_irq(&rtc_task_lock);
+
+	if (rtc_callback != task)
+		retval = -ENXIO;
+	else
+		rtc_do_ioctl(cmd, arg, FUNCTION_RTC_CONTROL);
+
+	spin_unlock_irq(&rtc_task_lock);
+
+	return retval;
+}
+
+EXPORT_SYMBOL_GPL(rtc_control);
+
+static struct miscdevice rtc_miscdevice = {
+	.minor	= RTC_MINOR,
+	.name	= rtc_name,
+	.fops	= &rtc_fops,
+};
+
+static int rtc_probe(struct device *dev)
+{
+	struct platform_device *pdev;
+	unsigned int irq;
+	int retval;
+
+	pdev = to_platform_device(dev);
+	if (pdev->num_resources != 2)
+		return -EBUSY;
+
+	rtc1_base = ioremap(pdev->resource[0].start, RTC1_SIZE);
+	if (rtc1_base == NULL)
+		return -EBUSY;
+
+	rtc2_base = ioremap(pdev->resource[1].start, RTC2_SIZE);
+	if (rtc2_base == NULL) {
+		iounmap(rtc1_base);
+		rtc1_base = NULL;
+		return -EBUSY;
+	}
+
+	retval = misc_register(&rtc_miscdevice);
+	if (retval < 0) {
+		iounmap(rtc1_base);
+		iounmap(rtc2_base);
+		rtc1_base = NULL;
+		rtc2_base = NULL;
+		return retval;
+	}
+
+	spin_lock_irq(&rtc_lock);
+
+	rtc1_write(ECMPLREG, 0);
+	rtc1_write(ECMPMREG, 0);
+	rtc1_write(ECMPHREG, 0);
+	rtc1_write(RTCL1LREG, 0);
+	rtc1_write(RTCL1HREG, 0);
+
+	rtc_status = RTC_RELEASE;
+	rtc_irq_data = 0;
+
+	spin_unlock_irq(&rtc_lock);
+
+	init_waitqueue_head(&rtc_wait);
+
+	irq = ELAPSEDTIME_IRQ;
+	retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
+	                     "elapsed_time", NULL);
+	if (retval == 0) {
+		irq = RTCLONG1_IRQ;
+		retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT,
+		                     "rtclong1", NULL);
+	}
+
+	if (retval < 0) {
+		printk(KERN_ERR "rtc: IRQ%d is busy\n", irq);
+		if (irq == RTCLONG1_IRQ)
+			free_irq(ELAPSEDTIME_IRQ, NULL);
+		iounmap(rtc1_base);
+		iounmap(rtc2_base);
+		rtc1_base = NULL;
+		rtc2_base = NULL;
+		return retval;
+	}
+
+	disable_irq(ELAPSEDTIME_IRQ);
+	disable_irq(RTCLONG1_IRQ);
+
+	spin_lock_init(&rtc_task_lock);
+
+	printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
+
+	return 0;
+}
+
+static int rtc_remove(struct device *dev)
+{
+	int retval;
+
+	retval = misc_deregister(&rtc_miscdevice);
+	if (retval < 0)
+		return retval;
+
+	free_irq(ELAPSEDTIME_IRQ, NULL);
+	free_irq(RTCLONG1_IRQ, NULL);
+	if (rtc1_base != NULL)
+		iounmap(rtc1_base);
+	if (rtc2_base != NULL)
+		iounmap(rtc2_base);
+
+	return 0;
+}
+
+static struct platform_device *rtc_platform_device;
+
+static struct device_driver rtc_device_driver = {
+	.name		= rtc_name,
+	.bus		= &platform_bus_type,
+	.probe		= rtc_probe,
+	.remove		= rtc_remove,
+};
+
+static int __devinit vr41xx_rtc_init(void)
+{
+	int retval;
+
+	switch (current_cpu_data.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		rtc_resource[0].start = RTC1_TYPE1_START;
+		rtc_resource[0].end = RTC1_TYPE1_END;
+		rtc_resource[1].start = RTC2_TYPE1_START;
+		rtc_resource[1].end = RTC2_TYPE1_END;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+	case CPU_VR4133:
+		rtc_resource[0].start = RTC1_TYPE2_START;
+		rtc_resource[0].end = RTC1_TYPE2_END;
+		rtc_resource[1].start = RTC2_TYPE2_START;
+		rtc_resource[1].end = RTC2_TYPE2_END;
+		break;
+	default:
+		return -ENODEV;
+		break;
+	}
+
+	rtc_platform_device = platform_device_register_simple("RTC", -1, rtc_resource, RTC_NUM_RESOURCES);
+	if (IS_ERR(rtc_platform_device))
+		return PTR_ERR(rtc_platform_device);
+
+	retval = driver_register(&rtc_device_driver);
+	if (retval < 0)
+		platform_device_unregister(rtc_platform_device);
+
+	return retval;
+}
+
+static void __devexit vr41xx_rtc_exit(void)
+{
+	driver_unregister(&rtc_device_driver);
+
+	platform_device_unregister(rtc_platform_device);
+}
+
+module_init(vr41xx_rtc_init);
+module_exit(vr41xx_rtc_exit);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -98,8 +98,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#include "console_macros.h"
-
 
 const struct consw *conswitchp;
 
@@ -135,17 +133,18 @@ static const struct consw *con_driver_ma
 #endif
 
 static int con_open(struct tty_struct *, struct file *);
-static void vc_init(unsigned int console, unsigned int rows,
+static void vc_init(struct vc_data *vc, unsigned int rows,
 		    unsigned int cols, int do_clear);
 static void gotoxy(struct vc_data *vc, int new_x, int new_y);
-static void save_cur(int currcons);
-static void reset_terminal(int currcons, int do_clear);
+static void save_cur(struct vc_data *vc);
+static void reset_terminal(struct vc_data *vc, int do_clear);
 static void con_flush_chars(struct tty_struct *tty);
 static void set_vesa_blanking(char __user *p);
 static void set_cursor(struct vc_data *vc);
 static void hide_cursor(struct vc_data *vc);
 static void console_callback(void *ignored);
 static void blank_screen_t(unsigned long dummy);
+static void set_palette(struct vc_data *vc);
 
 static int printable;		/* Is console ready for printing? */
 
@@ -214,22 +213,14 @@ enum {
  *	Low-Level Functions
  */
 
-#define IS_FG			(currcons == fg_console)
-#define IS_FG_VC(vc)		(vc == vc_cons[fg_console].d)
-
-#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
+#define IS_FG(vc)	((vc)->vc_num == fg_console)
 
 #ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE		0
-#define DO_UPDATE_VC(vc)	0
+#define DO_UPDATE(vc)	0
 #else
-#define DO_UPDATE 		IS_VISIBLE
-#define DO_UPDATE_VC(vc)	CON_IS_VISIBLE(vc)
+#define DO_UPDATE(vc)	CON_IS_VISIBLE(vc)
 #endif
 
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
-static struct pm_dev *pm_con;
-
 static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
 {
 	unsigned short *p;
@@ -254,39 +245,38 @@ void schedule_console_callback(void)
 	schedule_work(&console_work);
 }
 
-static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
+static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 {
 	unsigned short *d, *s;
 
 	if (t+nr >= b)
 		nr = b - t - 1;
-	if (b > vc_cons[currcons].d->vc_rows || t >= b || nr < 1)
+	if (b > vc->vc_rows || t >= b || nr < 1)
 		return;
-	if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
+	if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
 		return;
-	d = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*t);
-	s = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*(t+nr));
-	scr_memmovew(d, s, (b-t-nr) * vc_cons[currcons].d->vc_size_row);
-	scr_memsetw(d + (b-t-nr) * vc_cons[currcons].d->vc_cols, video_erase_char,
-			vc_cons[currcons].d->vc_size_row * nr);
+	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+	scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+	scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+		    vc->vc_size_row * nr);
 }
 
-static void
-scrdown(int currcons, unsigned int t, unsigned int b, int nr)
+static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 {
 	unsigned short *s;
 	unsigned int step;
 
 	if (t+nr >= b)
 		nr = b - t - 1;
-	if (b > vc_cons[currcons].d->vc_rows || t >= b || nr < 1)
+	if (b > vc->vc_rows || t >= b || nr < 1)
 		return;
-	if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+	if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
 		return;
-	s = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*t);
-	step = vc_cons[currcons].d->vc_cols * nr;
-	scr_memmovew(s + step, s, (b-t-nr)*vc_cons[currcons].d->vc_size_row);
-	scr_memsetw(s, video_erase_char, 2*step);
+	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+	step = vc->vc_cols * nr;
+	scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
+	scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
 }
 
 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -335,23 +325,23 @@ static void do_update_region(struct vc_d
 #endif
 }
 
-void update_region(int currcons, unsigned long start, int count)
+void update_region(struct vc_data *vc, unsigned long start, int count)
 {
 	WARN_CONSOLE_UNLOCKED();
 
-	if (DO_UPDATE) {
-		hide_cursor(vc_cons[currcons].d);
-		do_update_region(vc_cons[currcons].d, start, count);
-		set_cursor(vc_cons[currcons].d);
+	if (DO_UPDATE(vc)) {
+		hide_cursor(vc);
+		do_update_region(vc, start, count);
+		set_cursor(vc);
 	}
 }
 
 /* Structure of attributes is hardware-dependent */
 
-static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
 {
-	if (sw->con_build_attr)
-		return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
+	if (vc->vc_sw->con_build_attr)
+		return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse);
 
 #ifndef VT_BUF_VRAM_ONLY
 /*
@@ -365,23 +355,23 @@ static u8 build_attr(int currcons, u8 _c
  *  Bit 7   : blink
  */
 	{
-	u8 a = color;
-	if (!vc_cons[currcons].d->vc_can_do_color)
+	u8 a = vc->vc_color;
+	if (!vc->vc_can_do_color)
 		return _intensity |
 		       (_underline ? 4 : 0) |
 		       (_reverse ? 8 : 0) |
 		       (_blink ? 0x80 : 0);
 	if (_underline)
-		a = (a & 0xf0) | ulcolor;
+		a = (a & 0xf0) | vc->vc_ulcolor;
 	else if (_intensity == 0)
-		a = (a & 0xf0) | halfcolor;
+		a = (a & 0xf0) | vc->vc_ulcolor;
 	if (_reverse)
 		a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
 	if (_blink)
 		a ^= 0x80;
 	if (_intensity == 2)
 		a ^= 0x08;
-	if (hi_font_mask == 0x100)
+	if (vc->vc_hi_font_mask == 0x100)
 		a <<= 1;
 	return a;
 	}
@@ -390,10 +380,10 @@ static u8 build_attr(int currcons, u8 _c
 #endif
 }
 
-static void update_attr(int currcons)
+static void update_attr(struct vc_data *vc)
 {
-	attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
-	video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
+	vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm);
+	vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';
 }
 
 /* Note: inverting the screen twice should revert to the original state */
@@ -437,7 +427,7 @@ void invert_screen(struct vc_data *vc, i
 		}
 	}
 #endif
-	if (DO_UPDATE_VC(vc))
+	if (DO_UPDATE(vc))
 		do_update_region(vc, (unsigned long) p, count);
 }
 
@@ -452,7 +442,7 @@ void complement_pos(struct vc_data *vc, 
 
 	if (p) {
 		scr_writew(old, p);
-		if (DO_UPDATE_VC(vc))
+		if (DO_UPDATE(vc))
 			vc->vc_sw->con_putc(vc, old, oldy, oldx);
 	}
 	if (offset == -1)
@@ -463,7 +453,7 @@ void complement_pos(struct vc_data *vc, 
 		old = scr_readw(p);
 		new = old ^ vc->vc_complement_mask;
 		scr_writew(new, p);
-		if (DO_UPDATE_VC(vc)) {
+		if (DO_UPDATE(vc)) {
 			oldx = (offset >> 1) % vc->vc_cols;
 			oldy = (offset >> 1) / vc->vc_cols;
 			vc->vc_sw->con_putc(vc, new, oldy, oldx);
@@ -471,48 +461,46 @@ void complement_pos(struct vc_data *vc, 
 	}
 }
 
-static void insert_char(int currcons, unsigned int nr)
+static void insert_char(struct vc_data *vc, unsigned int nr)
 {
-	unsigned short *p, *q = (unsigned short *) pos;
+	unsigned short *p, *q = (unsigned short *)vc->vc_pos;
 
-	p = q + vc_cons[currcons].d->vc_cols - nr - x;
+	p = q + vc->vc_cols - nr - vc->vc_x;
 	while (--p >= q)
 		scr_writew(scr_readw(p), p + nr);
-	scr_memsetw(q, video_erase_char, nr*2);
-	need_wrap = 0;
-	if (DO_UPDATE) {
-		unsigned short oldattr = attr;
-		sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
-			      vc_cons[currcons].d->vc_cols-x-nr);
-		attr = video_erase_char >> 8;
+	scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+	vc->vc_need_wrap = 0;
+	if (DO_UPDATE(vc)) {
+		unsigned short oldattr = vc->vc_attr;
+		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
+				     vc->vc_cols - vc->vc_x - nr);
+		vc->vc_attr = vc->vc_video_erase_char >> 8;
 		while (nr--)
-			sw->con_putc(vc_cons[currcons].d,
-				     video_erase_char,y,x+nr);
-		attr = oldattr;
+			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
+		vc->vc_attr = oldattr;
 	}
 }
 
-static void delete_char(int currcons, unsigned int nr)
+static void delete_char(struct vc_data *vc, unsigned int nr)
 {
-	unsigned int i = x;
-	unsigned short *p = (unsigned short *) pos;
+	unsigned int i = vc->vc_x;
+	unsigned short *p = (unsigned short *)vc->vc_pos;
 
-	while (++i <= vc_cons[currcons].d->vc_cols - nr) {
+	while (++i <= vc->vc_cols - nr) {
 		scr_writew(scr_readw(p+nr), p);
 		p++;
 	}
-	scr_memsetw(p, video_erase_char, nr*2);
-	need_wrap = 0;
-	if (DO_UPDATE) {
-		unsigned short oldattr = attr;
-		sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
-			      vc_cons[currcons].d->vc_cols-x-nr);
-		attr = video_erase_char >> 8;
+	scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+	vc->vc_need_wrap = 0;
+	if (DO_UPDATE(vc)) {
+		unsigned short oldattr = vc->vc_attr;
+		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
+				     vc->vc_cols - vc->vc_x - nr);
+		vc->vc_attr = vc->vc_video_erase_char >> 8;
 		while (nr--)
-			sw->con_putc(vc_cons[currcons].d,
-				     video_erase_char, y,
-				     vc_cons[currcons].d->vc_cols-1-nr);
-		attr = oldattr;
+			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
+				     vc->vc_cols - 1 - nr);
+		vc->vc_attr = oldattr;
 	}
 }
 
@@ -531,7 +519,7 @@ static void add_softcursor(struct vc_dat
 	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
 	if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
 	scr_writew(i, (u16 *) vc->vc_pos);
-	if (DO_UPDATE_VC(vc))
+	if (DO_UPDATE(vc))
 		vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
 }
 
@@ -539,7 +527,7 @@ static void hide_softcursor(struct vc_da
 {
 	if (softcursor_original != -1) {
 		scr_writew(softcursor_original, (u16 *)vc->vc_pos);
-		if (DO_UPDATE_VC(vc))
+		if (DO_UPDATE(vc))
 			vc->vc_sw->con_putc(vc, softcursor_original,
 					vc->vc_y, vc->vc_x);
 		softcursor_original = -1;
@@ -556,8 +544,8 @@ static void hide_cursor(struct vc_data *
 
 static void set_cursor(struct vc_data *vc)
 {
-	if (!IS_FG_VC(vc) || console_blanked ||
-	    vc->vc_vt->vc_mode == KD_GRAPHICS)
+	if (!IS_FG(vc) || console_blanked ||
+	    vc->vc_mode == KD_GRAPHICS)
 		return;
 	if (vc->vc_deccm) {
 		if (vc == sel_cons)
@@ -569,98 +557,93 @@ static void set_cursor(struct vc_data *v
 		hide_cursor(vc);
 }
 
-static void set_origin(int currcons)
+static void set_origin(struct vc_data *vc)
 {
 	WARN_CONSOLE_UNLOCKED();
 
-	if (!IS_VISIBLE ||
-	    !sw->con_set_origin ||
-	    !sw->con_set_origin(vc_cons[currcons].d))
-		origin = (unsigned long) screenbuf;
-	visible_origin = origin;
-	scr_end = origin + screenbuf_size;
-	pos = origin + vc_cons[currcons].d->vc_size_row*y + 2*x;
+	if (!CON_IS_VISIBLE(vc) ||
+	    !vc->vc_sw->con_set_origin ||
+	    !vc->vc_sw->con_set_origin(vc))
+		vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+	vc->vc_visible_origin = vc->vc_origin;
+	vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+	vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
 }
 
-static inline void save_screen(int currcons)
+static inline void save_screen(struct vc_data *vc)
 {
 	WARN_CONSOLE_UNLOCKED();
 
-	if (sw->con_save_screen)
-		sw->con_save_screen(vc_cons[currcons].d);
+	if (vc->vc_sw->con_save_screen)
+		vc->vc_sw->con_save_screen(vc);
 }
 
 /*
  *	Redrawing of screen
  */
 
-static void clear_buffer_attributes(int currcons)
+static void clear_buffer_attributes(struct vc_data *vc)
 {
-	unsigned short *p = (unsigned short *) origin;
-	int count = screenbuf_size/2;
-	int mask = hi_font_mask | 0xff;
+	unsigned short *p = (unsigned short *)vc->vc_origin;
+	int count = vc->vc_screenbuf_size / 2;
+	int mask = vc->vc_hi_font_mask | 0xff;
 
 	for (; count > 0; count--, p++) {
-		scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
+		scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
 	}
 }
 
-void redraw_screen(int new_console, int is_switch)
+void redraw_screen(struct vc_data *vc, int is_switch)
 {
-	int redraw = 1;
-	int currcons, old_console;
+	int redraw = 0;
 
 	WARN_CONSOLE_UNLOCKED();
 
-	if (!vc_cons_allocated(new_console)) {
+	if (!vc) {
 		/* strange ... */
 		/* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
 		return;
 	}
 
 	if (is_switch) {
-		currcons = fg_console;
-		hide_cursor(vc_cons[currcons].d);
-		if (fg_console != new_console) {
-			struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
-			old_console = (*display) ? (*display)->vc_num : fg_console;
-			*display = vc_cons[new_console].d;
-			fg_console = new_console;
-			currcons = old_console;
-			if (!IS_VISIBLE) {
-				save_screen(currcons);
-				set_origin(currcons);
-			}
-			currcons = new_console;
-			if (old_console == new_console)
-				redraw = 0;
+		struct vc_data *old_vc = vc_cons[fg_console].d;
+		if (old_vc == vc)
+			return;
+		if (!CON_IS_VISIBLE(vc))
+			redraw = 1;
+		*vc->vc_display_fg = vc;
+		fg_console = vc->vc_num;
+		hide_cursor(old_vc);
+		if (!CON_IS_VISIBLE(old_vc)) {
+			save_screen(old_vc);
+			set_origin(old_vc);
 		}
 	} else {
-		currcons = new_console;
-		hide_cursor(vc_cons[currcons].d);
+		hide_cursor(vc);
+		redraw = 1;
 	}
 
 	if (redraw) {
 		int update;
-		int old_was_color = vc_cons[currcons].d->vc_can_do_color;
+		int old_was_color = vc->vc_can_do_color;
 
-		set_origin(currcons);
-		update = sw->con_switch(vc_cons[currcons].d);
-		set_palette(currcons);
+		set_origin(vc);
+		update = vc->vc_sw->con_switch(vc);
+		set_palette(vc);
 		/*
 		 * If console changed from mono<->color, the best we can do
 		 * is to clear the buffer attributes. As it currently stands,
 		 * rebuilding new attributes from the old buffer is not doable
 		 * without overly complex code.
 		 */
-		if (old_was_color != vc_cons[currcons].d->vc_can_do_color) {
-			update_attr(currcons);
-			clear_buffer_attributes(currcons);
+		if (old_was_color != vc->vc_can_do_color) {
+			update_attr(vc);
+			clear_buffer_attributes(vc);
 		}
-		if (update && vcmode != KD_GRAPHICS)
-			do_update_region(vc_cons[currcons].d, origin, screenbuf_size/2);
+		if (update && vc->vc_mode != KD_GRAPHICS)
+			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
 	}
-	set_cursor(vc_cons[currcons].d);
+	set_cursor(vc);
 	if (is_switch) {
 		set_leds();
 		compute_shiftstate();
@@ -676,31 +659,30 @@ int vc_cons_allocated(unsigned int i)
 	return (i < MAX_NR_CONSOLES && vc_cons[i].d);
 }
 
-static void visual_init(int currcons, int init)
+static void visual_init(struct vc_data *vc, int num, int init)
 {
-    /* ++Geert: sw->con_init determines console size */
-    if (sw)
-	module_put(sw->owner);
-    sw = conswitchp;
+	/* ++Geert: vc->vc_sw->con_init determines console size */
+	if (vc->vc_sw)
+		module_put(vc->vc_sw->owner);
+	vc->vc_sw = conswitchp;
 #ifndef VT_SINGLE_DRIVER
-    if (con_driver_map[currcons])
-	sw = con_driver_map[currcons];
+	if (con_driver_map[num])
+		vc->vc_sw = con_driver_map[num];
 #endif
-    __module_get(sw->owner);
-    cons_num = currcons;
-    display_fg = &master_display_fg;
-    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
-    vc_cons[currcons].d->vc_uni_pagedir = 0;
-    hi_font_mask = 0;
-    complement_mask = 0;
-    vc_cons[currcons].d->vc_can_do_color = 0;
-    sw->con_init(vc_cons[currcons].d, init);
-    if (!complement_mask)
-        complement_mask =
-		vc_cons[currcons].d->vc_can_do_color ? 0x7700 : 0x0800;
-    s_complement_mask = complement_mask;
-    vc_cons[currcons].d->vc_size_row = vc_cons[currcons].d->vc_cols<<1;
-    screenbuf_size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_size_row;
+	__module_get(vc->vc_sw->owner);
+	vc->vc_num = num;
+	vc->vc_display_fg = &master_display_fg;
+	vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
+	vc->vc_uni_pagedir = 0;
+	vc->vc_hi_font_mask = 0;
+	vc->vc_complement_mask = 0;
+	vc->vc_can_do_color = 0;
+	vc->vc_sw->con_init(vc, init);
+	if (!vc->vc_complement_mask)
+		vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+	vc->vc_s_complement_mask = vc->vc_complement_mask;
+	vc->vc_size_row = vc->vc_cols << 1;
+	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
 }
 
 int vc_allocate(unsigned int currcons)	/* return 0 on success */
@@ -710,7 +692,7 @@ int vc_allocate(unsigned int currcons)	/
 	if (currcons >= MAX_NR_CONSOLES)
 		return -ENXIO;
 	if (!vc_cons[currcons].d) {
-	    long p, q;
+	    struct vc_data *vc;
 
 	    /* prevent users from taking too much memory */
 	    if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
@@ -722,43 +704,33 @@ int vc_allocate(unsigned int currcons)	/
 	    /* although the numbers above are not valid since long ago, the
 	       point is still up-to-date and the comment still has its value
 	       even if only as a historical artifact.  --mj, July 1998 */
-	    p = (long) kmalloc(structsize, GFP_KERNEL);
-	    if (!p)
+	    vc = kmalloc(sizeof(struct vc_data), GFP_KERNEL);
+	    if (!vc)
 		return -ENOMEM;
-	    memset((void *)p, 0, structsize);
-	    vc_cons[currcons].d = (struct vc_data *)p;
-	    vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
-	    vc_cons[currcons].d->vc_vt = vt_cons[currcons];
-	    visual_init(currcons, 1);
-	    if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
-		con_set_default_unimap(currcons);
-	    q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
-	    if (!q) {
-		kfree((char *) p);
+	    memset(vc, 0, sizeof(*vc));
+	    vc_cons[currcons].d = vc;
+	    visual_init(vc, currcons, 1);
+	    if (!*vc->vc_uni_pagedir_loc)
+		con_set_default_unimap(vc);
+	    vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+	    if (!vc->vc_screenbuf) {
+		kfree(vc);
 		vc_cons[currcons].d = NULL;
-		vt_cons[currcons] = NULL;
 		return -ENOMEM;
 	    }
-	    screenbuf = (unsigned short *) q;
-	    kmalloced = 1;
-	    vc_init(currcons, vc_cons[currcons].d->vc_rows, vc_cons[currcons].d->vc_cols, 1);
-
-	    if (!pm_con) {
-		    pm_con = pm_register(PM_SYS_DEV,
-					 PM_SYS_VGA,
-					 pm_con_request);
-	    }
+	    vc->vc_kmalloced = 1;
+	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
 	}
 	return 0;
 }
 
-inline int resize_screen(int currcons, int width, int height)
+static inline int resize_screen(struct vc_data *vc, int width, int height)
 {
 	/* Resizes the resolution of the display adapater */
 	int err = 0;
 
-	if (vcmode != KD_GRAPHICS && sw->con_resize)
-		err = sw->con_resize(vc_cons[currcons].d, width, height);
+	if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
+		err = vc->vc_sw->con_resize(vc, width, height);
 	return err;
 }
 
@@ -769,7 +741,7 @@ inline int resize_screen(int currcons, i
  */
 #define VC_RESIZE_MAXCOL (32767)
 #define VC_RESIZE_MAXROW (32767)
-int vc_resize(int currcons, unsigned int cols, unsigned int lines)
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
 {
 	unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
 	unsigned int old_cols, old_rows, old_row_size, old_screen_size;
@@ -778,87 +750,87 @@ int vc_resize(int currcons, unsigned int
 
 	WARN_CONSOLE_UNLOCKED();
 
-	if (!vc_cons_allocated(currcons))
+	if (!vc)
 		return -ENXIO;
 
 	if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
 		return -EINVAL;
 
-	new_cols = (cols ? cols : vc_cons[currcons].d->vc_cols);
-	new_rows = (lines ? lines : vc_cons[currcons].d->vc_rows);
+	new_cols = (cols ? cols : vc->vc_cols);
+	new_rows = (lines ? lines : vc->vc_rows);
 	new_row_size = new_cols << 1;
 	new_screen_size = new_row_size * new_rows;
 
-	if (new_cols == vc_cons[currcons].d->vc_cols && new_rows == vc_cons[currcons].d->vc_rows)
+	if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
 		return 0;
 
 	newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER);
 	if (!newscreen)
 		return -ENOMEM;
 
-	old_rows = vc_cons[currcons].d->vc_rows;
-	old_cols = vc_cons[currcons].d->vc_cols;
-	old_row_size = vc_cons[currcons].d->vc_size_row;
-	old_screen_size = screenbuf_size;
+	old_rows = vc->vc_rows;
+	old_cols = vc->vc_cols;
+	old_row_size = vc->vc_size_row;
+	old_screen_size = vc->vc_screenbuf_size;
 
-	err = resize_screen(currcons, new_cols, new_rows);
+	err = resize_screen(vc, new_cols, new_rows);
 	if (err) {
 		kfree(newscreen);
 		return err;
 	}
 
-	vc_cons[currcons].d->vc_rows = new_rows;
-	vc_cons[currcons].d->vc_cols = new_cols;
-	vc_cons[currcons].d->vc_size_row = new_row_size;
-	screenbuf_size = new_screen_size;
+	vc->vc_rows = new_rows;
+	vc->vc_cols = new_cols;
+	vc->vc_size_row = new_row_size;
+	vc->vc_screenbuf_size = new_screen_size;
 
 	rlth = min(old_row_size, new_row_size);
 	rrem = new_row_size - rlth;
-	old_origin = origin;
+	old_origin = vc->vc_origin;
 	new_origin = (long) newscreen;
 	new_scr_end = new_origin + new_screen_size;
 	if (new_rows < old_rows)
 		old_origin += (old_rows - new_rows) * old_row_size;
 
-	update_attr(currcons);
+	update_attr(vc);
 
-	while (old_origin < scr_end) {
+	while (old_origin < vc->vc_scr_end) {
 		scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth);
 		if (rrem)
-			scr_memsetw((void *)(new_origin + rlth), video_erase_char, rrem);
+			scr_memsetw((void *)(new_origin + rlth), vc->vc_video_erase_char, rrem);
 		old_origin += old_row_size;
 		new_origin += new_row_size;
 	}
 	if (new_scr_end > new_origin)
-		scr_memsetw((void *) new_origin, video_erase_char, new_scr_end - new_origin);
-	if (kmalloced)
-		kfree(screenbuf);
-	screenbuf = newscreen;
-	kmalloced = 1;
-	screenbuf_size = new_screen_size;
-	set_origin(currcons);
+		scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin);
+	if (vc->vc_kmalloced)
+		kfree(vc->vc_screenbuf);
+	vc->vc_screenbuf = newscreen;
+	vc->vc_kmalloced = 1;
+	vc->vc_screenbuf_size = new_screen_size;
+	set_origin(vc);
 
 	/* do part of a reset_terminal() */
-	top = 0;
-	bottom = vc_cons[currcons].d->vc_rows;
-	gotoxy(vc_cons[currcons].d, x, y);
-	save_cur(currcons);
+	vc->vc_top = 0;
+	vc->vc_bottom = vc->vc_rows;
+	gotoxy(vc, vc->vc_x, vc->vc_y);
+	save_cur(vc);
 
-	if (vc_cons[currcons].d->vc_tty) {
-		struct winsize ws, *cws = &vc_cons[currcons].d->vc_tty->winsize;
+	if (vc->vc_tty) {
+		struct winsize ws, *cws = &vc->vc_tty->winsize;
 
 		memset(&ws, 0, sizeof(ws));
-		ws.ws_row = vc_cons[currcons].d->vc_rows;
-		ws.ws_col = vc_cons[currcons].d->vc_cols;
-		ws.ws_ypixel = video_scan_lines;
+		ws.ws_row = vc->vc_rows;
+		ws.ws_col = vc->vc_cols;
+		ws.ws_ypixel = vc->vc_scan_lines;
 		if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
-		    vc_cons[currcons].d->vc_tty->pgrp > 0)
-			kill_pg(vc_cons[currcons].d->vc_tty->pgrp, SIGWINCH, 1);
+		    vc->vc_tty->pgrp > 0)
+			kill_pg(vc->vc_tty->pgrp, SIGWINCH, 1);
 		*cws = ws;
 	}
 
-	if (IS_VISIBLE)
-		update_screen(currcons);
+	if (CON_IS_VISIBLE(vc))
+		update_screen(vc);
 	return err;
 }
 
@@ -868,12 +840,13 @@ void vc_disallocate(unsigned int currcon
 	WARN_CONSOLE_UNLOCKED();
 
 	if (vc_cons_allocated(currcons)) {
-	    sw->con_deinit(vc_cons[currcons].d);
-	    if (kmalloced)
-		kfree(screenbuf);
-	    if (currcons >= MIN_NR_CONSOLES)
-		kfree(vc_cons[currcons].d);
-	    vc_cons[currcons].d = NULL;
+		struct vc_data *vc = vc_cons[currcons].d;
+		vc->vc_sw->con_deinit(vc);
+		if (vc->vc_kmalloced)
+			kfree(vc->vc_screenbuf);
+		if (currcons >= MIN_NR_CONSOLES)
+			kfree(vc);
+		vc_cons[currcons].d = NULL;
 	}
 }
 
@@ -881,9 +854,9 @@ void vc_disallocate(unsigned int currcon
  *	VT102 emulator
  */
 
-#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
-#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
-#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
+#define set_kbd(vc, x)	set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define clr_kbd(vc, x)	clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define is_kbd(vc, x)	vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
 
 #define decarm		VC_REPEAT
 #define decckm		VC_CKMODE
@@ -943,272 +916,268 @@ static void gotoxy(struct vc_data *vc, i
 }
 
 /* for absolute user moves, when decom is set */
-static void gotoxay(int currcons, int new_x, int new_y)
+static void gotoxay(struct vc_data *vc, int new_x, int new_y)
 {
-	gotoxy(vc_cons[currcons].d, new_x, decom ? (top+new_y) : new_y);
+	gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
 }
 
-void scrollback(int lines)
+void scrollback(struct vc_data *vc, int lines)
 {
-	int currcons = fg_console;
-
 	if (!lines)
-		lines = vc_cons[currcons].d->vc_rows/2;
+		lines = vc->vc_rows / 2;
 	scrolldelta(-lines);
 }
 
-void scrollfront(int lines)
+void scrollfront(struct vc_data *vc, int lines)
 {
-	int currcons = fg_console;
-
 	if (!lines)
-		lines = vc_cons[currcons].d->vc_rows/2;
+		lines = vc->vc_rows / 2;
 	scrolldelta(lines);
 }
 
-static void lf(int currcons)
+static void lf(struct vc_data *vc)
 {
     	/* don't scroll if above bottom of scrolling region, or
 	 * if below scrolling region
 	 */
-    	if (y+1 == bottom)
-		scrup(currcons,top,bottom,1);
-	else if (y < vc_cons[currcons].d->vc_rows-1) {
-	    	y++;
-		pos += vc_cons[currcons].d->vc_size_row;
+    	if (vc->vc_y + 1 == vc->vc_bottom)
+		scrup(vc, vc->vc_top, vc->vc_bottom, 1);
+	else if (vc->vc_y < vc->vc_rows - 1) {
+	    	vc->vc_y++;
+		vc->vc_pos += vc->vc_size_row;
 	}
-	need_wrap = 0;
+	vc->vc_need_wrap = 0;
 }
 
-static void ri(int currcons)
+static void ri(struct vc_data *vc)
 {
     	/* don't scroll if below top of scrolling region, or
 	 * if above scrolling region
 	 */
-	if (y == top)
-		scrdown(currcons,top,bottom,1);
-	else if (y > 0) {
-		y--;
-		pos -= vc_cons[currcons].d->vc_size_row;
+	if (vc->vc_y == vc->vc_top)
+		scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
+	else if (vc->vc_y > 0) {
+		vc->vc_y--;
+		vc->vc_pos -= vc->vc_size_row;
 	}
-	need_wrap = 0;
+	vc->vc_need_wrap = 0;
 }
 
-static inline void cr(int currcons)
+static inline void cr(struct vc_data *vc)
 {
-	pos -= x<<1;
-	need_wrap = x = 0;
+	vc->vc_pos -= vc->vc_x << 1;
+	vc->vc_need_wrap = vc->vc_x = 0;
 }
 
-static inline void bs(int currcons)
+static inline void bs(struct vc_data *vc)
 {
-	if (x) {
-		pos -= 2;
-		x--;
-		need_wrap = 0;
+	if (vc->vc_x) {
+		vc->vc_pos -= 2;
+		vc->vc_x--;
+		vc->vc_need_wrap = 0;
 	}
 }
 
-static inline void del(int currcons)
+static inline void del(struct vc_data *vc)
 {
 	/* ignored */
 }
 
-static void csi_J(int currcons, int vpar)
+static void csi_J(struct vc_data *vc, int vpar)
 {
 	unsigned int count;
 	unsigned short * start;
 
 	switch (vpar) {
 		case 0:	/* erase from cursor to end of display */
-			count = (scr_end-pos)>>1;
-			start = (unsigned short *) pos;
-			if (DO_UPDATE) {
+			count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+			start = (unsigned short *)vc->vc_pos;
+			if (DO_UPDATE(vc)) {
 				/* do in two stages */
-				sw->con_clear(vc_cons[currcons].d, y, x, 1,
-					      vc_cons[currcons].d->vc_cols-x);
-				sw->con_clear(vc_cons[currcons].d, y+1, 0,
-					      vc_cons[currcons].d->vc_rows-y-1,
-					      vc_cons[currcons].d->vc_cols);
+				vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+					      vc->vc_cols - vc->vc_x);
+				vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
+					      vc->vc_rows - vc->vc_y - 1,
+					      vc->vc_cols);
 			}
 			break;
 		case 1:	/* erase from start to cursor */
-			count = ((pos-origin)>>1)+1;
-			start = (unsigned short *) origin;
-			if (DO_UPDATE) {
+			count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+			start = (unsigned short *)vc->vc_origin;
+			if (DO_UPDATE(vc)) {
 				/* do in two stages */
-				sw->con_clear(vc_cons[currcons].d, 0, 0, y,
-					      vc_cons[currcons].d->vc_cols);
-				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
-					      x + 1);
+				vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
+					      vc->vc_cols);
+				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+					      vc->vc_x + 1);
 			}
 			break;
 		case 2: /* erase whole display */
-			count = vc_cons[currcons].d->vc_cols * vc_cons[currcons].d->vc_rows;
-			start = (unsigned short *) origin;
-			if (DO_UPDATE)
-				sw->con_clear(vc_cons[currcons].d, 0, 0,
-					      vc_cons[currcons].d->vc_rows,
-					      vc_cons[currcons].d->vc_cols);
+			count = vc->vc_cols * vc->vc_rows;
+			start = (unsigned short *)vc->vc_origin;
+			if (DO_UPDATE(vc))
+				vc->vc_sw->con_clear(vc, 0, 0,
+					      vc->vc_rows,
+					      vc->vc_cols);
 			break;
 		default:
 			return;
 	}
-	scr_memsetw(start, video_erase_char, 2*count);
-	need_wrap = 0;
+	scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+	vc->vc_need_wrap = 0;
 }
 
-static void csi_K(int currcons, int vpar)
+static void csi_K(struct vc_data *vc, int vpar)
 {
 	unsigned int count;
 	unsigned short * start;
 
 	switch (vpar) {
 		case 0:	/* erase from cursor to end of line */
-			count = vc_cons[currcons].d->vc_cols-x;
-			start = (unsigned short *) pos;
-			if (DO_UPDATE)
-				sw->con_clear(vc_cons[currcons].d, y, x, 1,
-					      vc_cons[currcons].d->vc_cols-x);
+			count = vc->vc_cols - vc->vc_x;
+			start = (unsigned short *)vc->vc_pos;
+			if (DO_UPDATE(vc))
+				vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+						     vc->vc_cols - vc->vc_x);
 			break;
 		case 1:	/* erase from start of line to cursor */
-			start = (unsigned short *) (pos - (x<<1));
-			count = x+1;
-			if (DO_UPDATE)
-				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
-					      x + 1);
+			start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+			count = vc->vc_x + 1;
+			if (DO_UPDATE(vc))
+				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+						     vc->vc_x + 1);
 			break;
 		case 2: /* erase whole line */
-			start = (unsigned short *) (pos - (x<<1));
-			count = vc_cons[currcons].d->vc_cols;
-			if (DO_UPDATE)
-				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
-					      vc_cons[currcons].d->vc_cols);
+			start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+			count = vc->vc_cols;
+			if (DO_UPDATE(vc))
+				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+					      vc->vc_cols);
 			break;
 		default:
 			return;
 	}
-	scr_memsetw(start, video_erase_char, 2 * count);
-	need_wrap = 0;
+	scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+	vc->vc_need_wrap = 0;
 }
 
-static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
+static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
 {					  /* not vt100? */
 	int count;
 
 	if (!vpar)
 		vpar++;
-	count = (vpar > vc_cons[currcons].d->vc_cols-x) ? (vc_cons[currcons].d->vc_cols-x) : vpar;
+	count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
 
-	scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
-	if (DO_UPDATE)
-		sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
-	need_wrap = 0;
+	scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+	if (DO_UPDATE(vc))
+		vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+	vc->vc_need_wrap = 0;
 }
 
-static void default_attr(int currcons)
+static void default_attr(struct vc_data *vc)
 {
-	intensity = 1;
-	underline = 0;
-	reverse = 0;
-	blink = 0;
-	color = def_color;
+	vc->vc_intensity = 1;
+	vc->vc_underline = 0;
+	vc->vc_reverse = 0;
+	vc->vc_blink = 0;
+	vc->vc_color = vc->vc_def_color;
 }
 
 /* console_sem is held */
-static void csi_m(int currcons)
+static void csi_m(struct vc_data *vc)
 {
 	int i;
 
-	for (i=0;i<=npar;i++)
-		switch (par[i]) {
+	for (i = 0; i <= vc->vc_npar; i++)
+		switch (vc->vc_par[i]) {
 			case 0:	/* all attributes off */
-				default_attr(currcons);
+				default_attr(vc);
 				break;
 			case 1:
-				intensity = 2;
+				vc->vc_intensity = 2;
 				break;
 			case 2:
-				intensity = 0;
+				vc->vc_intensity = 0;
 				break;
 			case 4:
-				underline = 1;
+				vc->vc_underline = 1;
 				break;
 			case 5:
-				blink = 1;
+				vc->vc_blink = 1;
 				break;
 			case 7:
-				reverse = 1;
+				vc->vc_reverse = 1;
 				break;
 			case 10: /* ANSI X3.64-1979 (SCO-ish?)
 				  * Select primary font, don't display
 				  * control chars if defined, don't set
 				  * bit 8 on output.
 				  */
-				translate = set_translate(charset == 0
-						? G0_charset
-						: G1_charset,currcons);
-				disp_ctrl = 0;
-				toggle_meta = 0;
+				vc->vc_translate = set_translate(vc->vc_charset == 0
+						? vc->vc_G0_charset
+						: vc->vc_G1_charset, vc);
+				vc->vc_disp_ctrl = 0;
+				vc->vc_toggle_meta = 0;
 				break;
 			case 11: /* ANSI X3.64-1979 (SCO-ish?)
 				  * Select first alternate font, lets
 				  * chars < 32 be displayed as ROM chars.
 				  */
-				translate = set_translate(IBMPC_MAP,currcons);
-				disp_ctrl = 1;
-				toggle_meta = 0;
+				vc->vc_translate = set_translate(IBMPC_MAP, vc);
+				vc->vc_disp_ctrl = 1;
+				vc->vc_toggle_meta = 0;
 				break;
 			case 12: /* ANSI X3.64-1979 (SCO-ish?)
 				  * Select second alternate font, toggle
 				  * high bit before displaying as ROM char.
 				  */
-				translate = set_translate(IBMPC_MAP,currcons);
-				disp_ctrl = 1;
-				toggle_meta = 1;
+				vc->vc_translate = set_translate(IBMPC_MAP, vc);
+				vc->vc_disp_ctrl = 1;
+				vc->vc_toggle_meta = 1;
 				break;
 			case 21:
 			case 22:
-				intensity = 1;
+				vc->vc_intensity = 1;
 				break;
 			case 24:
-				underline = 0;
+				vc->vc_underline = 0;
 				break;
 			case 25:
-				blink = 0;
+				vc->vc_blink = 0;
 				break;
 			case 27:
-				reverse = 0;
+				vc->vc_reverse = 0;
 				break;
 			case 38: /* ANSI X3.64-1979 (SCO-ish?)
 				  * Enables underscore, white foreground
 				  * with white underscore (Linux - use
 				  * default foreground).
 				  */
-				color = (def_color & 0x0f) | background;
-				underline = 1;
+				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+				vc->vc_underline = 1;
 				break;
 			case 39: /* ANSI X3.64-1979 (SCO-ish?)
 				  * Disable underline option.
 				  * Reset colour to default? It did this
 				  * before...
 				  */
-				color = (def_color & 0x0f) | background;
-				underline = 0;
+				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+				vc->vc_underline = 0;
 				break;
 			case 49:
-				color = (def_color & 0xf0) | foreground;
+				vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
 				break;
 			default:
-				if (par[i] >= 30 && par[i] <= 37)
-					color = color_table[par[i]-30]
-						| background;
-				else if (par[i] >= 40 && par[i] <= 47)
-					color = (color_table[par[i]-40]<<4)
-						| foreground;
+				if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+					vc->vc_color = color_table[vc->vc_par[i] - 30]
+						| (vc->vc_color & 0xf0);
+				else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+					vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+						| (vc->vc_color & 0x0f);
 				break;
 		}
-	update_attr(currcons);
+	update_attr(vc);
 }
 
 static void respond_string(const char *p, struct tty_struct *tty)
@@ -1220,11 +1189,11 @@ static void respond_string(const char *p
 	con_schedule_flip(tty);
 }
 
-static void cursor_report(int currcons, struct tty_struct *tty)
+static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
 {
 	char buf[40];
 
-	sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
+	sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
 	respond_string(buf, tty);
 }
 
@@ -1250,130 +1219,132 @@ void mouse_report(struct tty_struct *tty
 /* invoked via ioctl(TIOCLINUX) and through set_selection */
 int mouse_reporting(void)
 {
-	int currcons = fg_console;
-
-	return report_mouse;
+	return vc_cons[fg_console].d->vc_report_mouse;
 }
 
 /* console_sem is held */
-static void set_mode(int currcons, int on_off)
+static void set_mode(struct vc_data *vc, int on_off)
 {
 	int i;
 
-	for (i=0; i<=npar; i++)
-		if (ques) switch(par[i]) {	/* DEC private modes set/reset */
+	for (i = 0; i <= vc->vc_npar; i++)
+		if (vc->vc_ques) {
+			switch(vc->vc_par[i]) {	/* DEC private modes set/reset */
 			case 1:			/* Cursor keys send ^[Ox/^[[x */
 				if (on_off)
-					set_kbd(decckm);
+					set_kbd(vc, decckm);
 				else
-					clr_kbd(decckm);
+					clr_kbd(vc, decckm);
 				break;
 			case 3:	/* 80/132 mode switch unimplemented */
-				deccolm = on_off;
+				vc->vc_deccolm = on_off;
 #if 0
-				(void) vc_resize(deccolm ? 132 : 80, vc_cons[currcons].d->vc_rows);
+				vc_resize(deccolm ? 132 : 80, vc->vc_rows);
 				/* this alone does not suffice; some user mode
 				   utility has to change the hardware regs */
 #endif
 				break;
 			case 5:			/* Inverted screen on/off */
-				if (decscnm != on_off) {
-					decscnm = on_off;
-					invert_screen(vc_cons[currcons].d, 0, screenbuf_size, 0);
-					update_attr(currcons);
+				if (vc->vc_decscnm != on_off) {
+					vc->vc_decscnm = on_off;
+					invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
+					update_attr(vc);
 				}
 				break;
 			case 6:			/* Origin relative/absolute */
-				decom = on_off;
-				gotoxay(currcons,0,0);
+				vc->vc_decom = on_off;
+				gotoxay(vc, 0, 0);
 				break;
 			case 7:			/* Autowrap on/off */
-				decawm = on_off;
+				vc->vc_decawm = on_off;
 				break;
 			case 8:			/* Autorepeat on/off */
 				if (on_off)
-					set_kbd(decarm);
+					set_kbd(vc, decarm);
 				else
-					clr_kbd(decarm);
+					clr_kbd(vc, decarm);
 				break;
 			case 9:
-				report_mouse = on_off ? 1 : 0;
+				vc->vc_report_mouse = on_off ? 1 : 0;
 				break;
 			case 25:		/* Cursor on/off */
-				deccm = on_off;
+				vc->vc_deccm = on_off;
 				break;
 			case 1000:
-				report_mouse = on_off ? 2 : 0;
+				vc->vc_report_mouse = on_off ? 2 : 0;
 				break;
-		} else switch(par[i]) {		/* ANSI modes set/reset */
+			}
+		} else {
+			switch(vc->vc_par[i]) {	/* ANSI modes set/reset */
 			case 3:			/* Monitor (display ctrls) */
-				disp_ctrl = on_off;
+				vc->vc_disp_ctrl = on_off;
 				break;
 			case 4:			/* Insert Mode on/off */
-				decim = on_off;
+				vc->vc_decim = on_off;
 				break;
 			case 20:		/* Lf, Enter == CrLf/Lf */
 				if (on_off)
-					set_kbd(lnm);
+					set_kbd(vc, lnm);
 				else
-					clr_kbd(lnm);
+					clr_kbd(vc, lnm);
 				break;
+			}
 		}
 }
 
 /* console_sem is held */
-static void setterm_command(int currcons)
+static void setterm_command(struct vc_data *vc)
 {
-	switch(par[0]) {
+	switch(vc->vc_par[0]) {
 		case 1:	/* set color for underline mode */
-			if (vc_cons[currcons].d->vc_can_do_color &&
-					par[1] < 16) {
-				ulcolor = color_table[par[1]];
-				if (underline)
-					update_attr(currcons);
+			if (vc->vc_can_do_color &&
+					vc->vc_par[1] < 16) {
+				vc->vc_ulcolor = color_table[vc->vc_par[1]];
+				if (vc->vc_underline)
+					update_attr(vc);
 			}
 			break;
 		case 2:	/* set color for half intensity mode */
-			if (vc_cons[currcons].d->vc_can_do_color &&
-					par[1] < 16) {
-				halfcolor = color_table[par[1]];
-				if (intensity == 0)
-					update_attr(currcons);
+			if (vc->vc_can_do_color &&
+					vc->vc_par[1] < 16) {
+				vc->vc_halfcolor = color_table[vc->vc_par[1]];
+				if (vc->vc_intensity == 0)
+					update_attr(vc);
 			}
 			break;
 		case 8:	/* store colors as defaults */
-			def_color = attr;
-			if (hi_font_mask == 0x100)
-				def_color >>= 1;
-			default_attr(currcons);
-			update_attr(currcons);
+			vc->vc_def_color = vc->vc_attr;
+			if (vc->vc_hi_font_mask == 0x100)
+				vc->vc_def_color >>= 1;
+			default_attr(vc);
+			update_attr(vc);
 			break;
 		case 9:	/* set blanking interval */
-			blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
 			poke_blanked_console();
 			break;
 		case 10: /* set bell frequency in Hz */
-			if (npar >= 1)
-				bell_pitch = par[1];
+			if (vc->vc_npar >= 1)
+				vc->vc_bell_pitch = vc->vc_par[1];
 			else
-				bell_pitch = DEFAULT_BELL_PITCH;
+				vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
 			break;
 		case 11: /* set bell duration in msec */
-			if (npar >= 1)
-				bell_duration = (par[1] < 2000) ?
-					par[1]*HZ/1000 : 0;
+			if (vc->vc_npar >= 1)
+				vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
+					vc->vc_par[1] * HZ / 1000 : 0;
 			else
-				bell_duration = DEFAULT_BELL_DURATION;
+				vc->vc_bell_duration = DEFAULT_BELL_DURATION;
 			break;
 		case 12: /* bring specified console to the front */
-			if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
-				set_console(par[1] - 1);
+			if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
+				set_console(vc->vc_par[1] - 1);
 			break;
 		case 13: /* unblank the screen */
 			poke_blanked_console();
 			break;
 		case 14: /* set vesa powerdown interval */
-			vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
 			break;
 		case 15: /* activate the previous console */
 			set_console(last_console);
@@ -1382,77 +1353,77 @@ static void setterm_command(int currcons
 }
 
 /* console_sem is held */
-static void csi_at(int currcons, unsigned int nr)
+static void csi_at(struct vc_data *vc, unsigned int nr)
 {
-	if (nr > vc_cons[currcons].d->vc_cols - x)
-		nr = vc_cons[currcons].d->vc_cols - x;
+	if (nr > vc->vc_cols - vc->vc_x)
+		nr = vc->vc_cols - vc->vc_x;
 	else if (!nr)
 		nr = 1;
-	insert_char(currcons, nr);
+	insert_char(vc, nr);
 }
 
 /* console_sem is held */
-static void csi_L(int currcons, unsigned int nr)
+static void csi_L(struct vc_data *vc, unsigned int nr)
 {
-	if (nr > vc_cons[currcons].d->vc_rows - y)
-		nr = vc_cons[currcons].d->vc_rows - y;
+	if (nr > vc->vc_rows - vc->vc_y)
+		nr = vc->vc_rows - vc->vc_y;
 	else if (!nr)
 		nr = 1;
-	scrdown(currcons,y,bottom,nr);
-	need_wrap = 0;
+	scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
+	vc->vc_need_wrap = 0;
 }
 
 /* console_sem is held */
-static void csi_P(int currcons, unsigned int nr)
+static void csi_P(struct vc_data *vc, unsigned int nr)
 {
-	if (nr > vc_cons[currcons].d->vc_cols - x)
-		nr = vc_cons[currcons].d->vc_cols - x;
+	if (nr > vc->vc_cols - vc->vc_x)
+		nr = vc->vc_cols - vc->vc_x;
 	else if (!nr)
 		nr = 1;
-	delete_char(currcons, nr);
+	delete_char(vc, nr);
 }
 
 /* console_sem is held */
-static void csi_M(int currcons, unsigned int nr)
+static void csi_M(struct vc_data *vc, unsigned int nr)
 {
-	if (nr > vc_cons[currcons].d->vc_rows - y)
-		nr = vc_cons[currcons].d->vc_rows - y;
+	if (nr > vc->vc_rows - vc->vc_y)
+		nr = vc->vc_rows - vc->vc_y;
 	else if (!nr)
 		nr=1;
-	scrup(currcons,y,bottom,nr);
-	need_wrap = 0;
+	scrup(vc, vc->vc_y, vc->vc_bottom, nr);
+	vc->vc_need_wrap = 0;
 }
 
 /* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(int currcons)
+static void save_cur(struct vc_data *vc)
 {
-	saved_x		= x;
-	saved_y		= y;
-	s_intensity	= intensity;
-	s_underline	= underline;
-	s_blink		= blink;
-	s_reverse	= reverse;
-	s_charset	= charset;
-	s_color		= color;
-	saved_G0	= G0_charset;
-	saved_G1	= G1_charset;
+	vc->vc_saved_x		= vc->vc_x;
+	vc->vc_saved_y		= vc->vc_y;
+	vc->vc_s_intensity	= vc->vc_intensity;
+	vc->vc_s_underline	= vc->vc_underline;
+	vc->vc_s_blink		= vc->vc_blink;
+	vc->vc_s_reverse	= vc->vc_reverse;
+	vc->vc_s_charset	= vc->vc_charset;
+	vc->vc_s_color		= vc->vc_color;
+	vc->vc_saved_G0		= vc->vc_G0_charset;
+	vc->vc_saved_G1		= vc->vc_G1_charset;
 }
 
 /* console_sem is held */
-static void restore_cur(int currcons)
+static void restore_cur(struct vc_data *vc)
 {
-	gotoxy(vc_cons[currcons].d,saved_x,saved_y);
-	intensity	= s_intensity;
-	underline	= s_underline;
-	blink		= s_blink;
-	reverse		= s_reverse;
-	charset		= s_charset;
-	color		= s_color;
-	G0_charset	= saved_G0;
-	G1_charset	= saved_G1;
-	translate	= set_translate(charset ? G1_charset : G0_charset,currcons);
-	update_attr(currcons);
-	need_wrap = 0;
+	gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
+	vc->vc_intensity	= vc->vc_s_intensity;
+	vc->vc_underline	= vc->vc_s_underline;
+	vc->vc_blink		= vc->vc_s_blink;
+	vc->vc_reverse		= vc->vc_s_reverse;
+	vc->vc_charset		= vc->vc_s_charset;
+	vc->vc_color		= vc->vc_s_color;
+	vc->vc_G0_charset	= vc->vc_saved_G0;
+	vc->vc_G1_charset	= vc->vc_saved_G1;
+	vc->vc_translate	= set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+	update_attr(vc);
+	vc->vc_need_wrap = 0;
 }
 
 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
@@ -1460,64 +1431,64 @@ enum { ESnormal, ESesc, ESsquare, ESgetp
 	ESpalette };
 
 /* console_sem is held (except via vc_init()) */
-static void reset_terminal(int currcons, int do_clear)
+static void reset_terminal(struct vc_data *vc, int do_clear)
 {
-	top		= 0;
-	bottom		= vc_cons[currcons].d->vc_rows;
-	vc_state	= ESnormal;
-	ques		= 0;
-	translate	= set_translate(LAT1_MAP,currcons);
-	G0_charset	= LAT1_MAP;
-	G1_charset	= GRAF_MAP;
-	charset		= 0;
-	need_wrap	= 0;
-	report_mouse	= 0;
-	utf             = 0;
-	utf_count       = 0;
-
-	disp_ctrl	= 0;
-	toggle_meta	= 0;
-
-	decscnm		= 0;
-	decom		= 0;
-	decawm		= 1;
-	deccm		= 1;
-	decim		= 0;
-
-	set_kbd(decarm);
-	clr_kbd(decckm);
-	clr_kbd(kbdapplic);
-	clr_kbd(lnm);
-	kbd_table[currcons].lockstate = 0;
-	kbd_table[currcons].slockstate = 0;
-	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
-	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
+	vc->vc_top		= 0;
+	vc->vc_bottom		= vc->vc_rows;
+	vc->vc_state		= ESnormal;
+	vc->vc_ques		= 0;
+	vc->vc_translate	= set_translate(LAT1_MAP, vc);
+	vc->vc_G0_charset	= LAT1_MAP;
+	vc->vc_G1_charset	= GRAF_MAP;
+	vc->vc_charset		= 0;
+	vc->vc_need_wrap	= 0;
+	vc->vc_report_mouse	= 0;
+	vc->vc_utf		= 0;
+	vc->vc_utf_count	= 0;
+
+	vc->vc_disp_ctrl	= 0;
+	vc->vc_toggle_meta	= 0;
+
+	vc->vc_decscnm		= 0;
+	vc->vc_decom		= 0;
+	vc->vc_decawm		= 1;
+	vc->vc_deccm		= 1;
+	vc->vc_decim		= 0;
+
+	set_kbd(vc, decarm);
+	clr_kbd(vc, decckm);
+	clr_kbd(vc, kbdapplic);
+	clr_kbd(vc, lnm);
+	kbd_table[vc->vc_num].lockstate = 0;
+	kbd_table[vc->vc_num].slockstate = 0;
+	kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
+	kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
 	/* do not do set_leds here because this causes an endless tasklet loop
 	   when the keyboard hasn't been initialized yet */
 
-	cursor_type = CUR_DEFAULT;
-	complement_mask = s_complement_mask;
+	vc->vc_cursor_type = CUR_DEFAULT;
+	vc->vc_complement_mask = vc->vc_s_complement_mask;
 
-	default_attr(currcons);
-	update_attr(currcons);
+	default_attr(vc);
+	update_attr(vc);
 
-	tab_stop[0]	= 0x01010100;
-	tab_stop[1]	=
-	tab_stop[2]	=
-	tab_stop[3]	=
-	tab_stop[4]	= 0x01010101;
+	vc->vc_tab_stop[0]	= 0x01010100;
+	vc->vc_tab_stop[1]	=
+	vc->vc_tab_stop[2]	=
+	vc->vc_tab_stop[3]	=
+	vc->vc_tab_stop[4]	= 0x01010101;
 
-	bell_pitch = DEFAULT_BELL_PITCH;
-	bell_duration = DEFAULT_BELL_DURATION;
+	vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+	vc->vc_bell_duration = DEFAULT_BELL_DURATION;
 
-	gotoxy(vc_cons[currcons].d, 0, 0);
-	save_cur(currcons);
+	gotoxy(vc, 0, 0);
+	save_cur(vc);
 	if (do_clear)
-	    csi_J(currcons,2);
+	    csi_J(vc, 2);
 }
 
 /* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 {
 	/*
 	 *  Control characters can be used in the _middle_
@@ -1527,360 +1498,371 @@ static void do_con_trol(struct tty_struc
 	case 0:
 		return;
 	case 7:
-		if (bell_duration)
-			kd_mksound(bell_pitch, bell_duration);
+		if (vc->vc_bell_duration)
+			kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
 		return;
 	case 8:
-		bs(currcons);
+		bs(vc);
 		return;
 	case 9:
-		pos -= (x << 1);
-		while (x < vc_cons[currcons].d->vc_cols - 1) {
-			x++;
-			if (tab_stop[x >> 5] & (1 << (x & 31)))
+		vc->vc_pos -= (vc->vc_x << 1);
+		while (vc->vc_x < vc->vc_cols - 1) {
+			vc->vc_x++;
+			if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
 				break;
 		}
-		pos += (x << 1);
+		vc->vc_pos += (vc->vc_x << 1);
 		return;
 	case 10: case 11: case 12:
-		lf(currcons);
-		if (!is_kbd(lnm))
+		lf(vc);
+		if (!is_kbd(vc, lnm))
 			return;
 	case 13:
-		cr(currcons);
+		cr(vc);
 		return;
 	case 14:
-		charset = 1;
-		translate = set_translate(G1_charset,currcons);
-		disp_ctrl = 1;
+		vc->vc_charset = 1;
+		vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+		vc->vc_disp_ctrl = 1;
 		return;
 	case 15:
-		charset = 0;
-		translate = set_translate(G0_charset,currcons);
-		disp_ctrl = 0;
+		vc->vc_charset = 0;
+		vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+		vc->vc_disp_ctrl = 0;
 		return;
 	case 24: case 26:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		return;
 	case 27:
-		vc_state = ESesc;
+		vc->vc_state = ESesc;
 		return;
 	case 127:
-		del(currcons);
+		del(vc);
 		return;
 	case 128+27:
-		vc_state = ESsquare;
+		vc->vc_state = ESsquare;
 		return;
 	}
-	switch(vc_state) {
+	switch(vc->vc_state) {
 	case ESesc:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		switch (c) {
 		case '[':
-			vc_state = ESsquare;
+			vc->vc_state = ESsquare;
 			return;
 		case ']':
-			vc_state = ESnonstd;
+			vc->vc_state = ESnonstd;
 			return;
 		case '%':
-			vc_state = ESpercent;
+			vc->vc_state = ESpercent;
 			return;
 		case 'E':
-			cr(currcons);
-			lf(currcons);
+			cr(vc);
+			lf(vc);
 			return;
 		case 'M':
-			ri(currcons);
+			ri(vc);
 			return;
 		case 'D':
-			lf(currcons);
+			lf(vc);
 			return;
 		case 'H':
-			tab_stop[x >> 5] |= (1 << (x & 31));
+			vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
 			return;
 		case 'Z':
 			respond_ID(tty);
 			return;
 		case '7':
-			save_cur(currcons);
+			save_cur(vc);
 			return;
 		case '8':
-			restore_cur(currcons);
+			restore_cur(vc);
 			return;
 		case '(':
-			vc_state = ESsetG0;
+			vc->vc_state = ESsetG0;
 			return;
 		case ')':
-			vc_state = ESsetG1;
+			vc->vc_state = ESsetG1;
 			return;
 		case '#':
-			vc_state = EShash;
+			vc->vc_state = EShash;
 			return;
 		case 'c':
-			reset_terminal(currcons,1);
+			reset_terminal(vc, 1);
 			return;
 		case '>':  /* Numeric keypad */
-			clr_kbd(kbdapplic);
+			clr_kbd(vc, kbdapplic);
 			return;
 		case '=':  /* Appl. keypad */
-			set_kbd(kbdapplic);
+			set_kbd(vc, kbdapplic);
 			return;
 		}
 		return;
 	case ESnonstd:
 		if (c=='P') {   /* palette escape sequence */
-			for (npar=0; npar<NPAR; npar++)
-				par[npar] = 0 ;
-			npar = 0 ;
-			vc_state = ESpalette;
+			for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+				vc->vc_par[vc->vc_npar] = 0;
+			vc->vc_npar = 0;
+			vc->vc_state = ESpalette;
 			return;
 		} else if (c=='R') {   /* reset palette */
-			reset_palette(currcons);
-			vc_state = ESnormal;
+			reset_palette(vc);
+			vc->vc_state = ESnormal;
 		} else
-			vc_state = ESnormal;
+			vc->vc_state = ESnormal;
 		return;
 	case ESpalette:
 		if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
-			par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
-			if (npar==7) {
-				int i = par[0]*3, j = 1;
-				palette[i] = 16*par[j++];
-				palette[i++] += par[j++];
-				palette[i] = 16*par[j++];
-				palette[i++] += par[j++];
-				palette[i] = 16*par[j++];
-				palette[i] += par[j];
-				set_palette(currcons);
-				vc_state = ESnormal;
+			vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0');
+			if (vc->vc_npar == 7) {
+				int i = vc->vc_par[0] * 3, j = 1;
+				vc->vc_palette[i] = 16 * vc->vc_par[j++];
+				vc->vc_palette[i++] += vc->vc_par[j++];
+				vc->vc_palette[i] = 16 * vc->vc_par[j++];
+				vc->vc_palette[i++] += vc->vc_par[j++];
+				vc->vc_palette[i] = 16 * vc->vc_par[j++];
+				vc->vc_palette[i] += vc->vc_par[j];
+				set_palette(vc);
+				vc->vc_state = ESnormal;
 			}
 		} else
-			vc_state = ESnormal;
+			vc->vc_state = ESnormal;
 		return;
 	case ESsquare:
-		for(npar = 0 ; npar < NPAR ; npar++)
-			par[npar] = 0;
-		npar = 0;
-		vc_state = ESgetpars;
+		for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+			vc->vc_par[vc->vc_npar] = 0;
+		vc->vc_npar = 0;
+		vc->vc_state = ESgetpars;
 		if (c == '[') { /* Function key */
-			vc_state=ESfunckey;
+			vc->vc_state=ESfunckey;
 			return;
 		}
-		ques = (c=='?');
-		if (ques)
+		vc->vc_ques = (c == '?');
+		if (vc->vc_ques)
 			return;
 	case ESgetpars:
-		if (c==';' && npar<NPAR-1) {
-			npar++;
+		if (c == ';' && vc->vc_npar < NPAR - 1) {
+			vc->vc_npar++;
 			return;
 		} else if (c>='0' && c<='9') {
-			par[npar] *= 10;
-			par[npar] += c-'0';
+			vc->vc_par[vc->vc_npar] *= 10;
+			vc->vc_par[vc->vc_npar] += c - '0';
 			return;
-		} else vc_state=ESgotpars;
+		} else
+			vc->vc_state = ESgotpars;
 	case ESgotpars:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		switch(c) {
 		case 'h':
-			set_mode(currcons,1);
+			set_mode(vc, 1);
 			return;
 		case 'l':
-			set_mode(currcons,0);
+			set_mode(vc, 0);
 			return;
 		case 'c':
-			if (ques) {
-				if (par[0])
-					cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+			if (vc->vc_ques) {
+				if (vc->vc_par[0])
+					vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
 				else
-					cursor_type = CUR_DEFAULT;
+					vc->vc_cursor_type = CUR_DEFAULT;
 				return;
 			}
 			break;
 		case 'm':
-			if (ques) {
+			if (vc->vc_ques) {
 				clear_selection();
-				if (par[0])
-					complement_mask = par[0]<<8 | par[1];
+				if (vc->vc_par[0])
+					vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
 				else
-					complement_mask = s_complement_mask;
+					vc->vc_complement_mask = vc->vc_s_complement_mask;
 				return;
 			}
 			break;
 		case 'n':
-			if (!ques) {
-				if (par[0] == 5)
+			if (!vc->vc_ques) {
+				if (vc->vc_par[0] == 5)
 					status_report(tty);
-				else if (par[0] == 6)
-					cursor_report(currcons,tty);
+				else if (vc->vc_par[0] == 6)
+					cursor_report(vc, tty);
 			}
 			return;
 		}
-		if (ques) {
-			ques = 0;
+		if (vc->vc_ques) {
+			vc->vc_ques = 0;
 			return;
 		}
 		switch(c) {
 		case 'G': case '`':
-			if (par[0]) par[0]--;
-			gotoxy(vc_cons[currcons].d, par[0], y);
+			if (vc->vc_par[0])
+				vc->vc_par[0]--;
+			gotoxy(vc, vc->vc_par[0], vc->vc_y);
 			return;
 		case 'A':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, x, y-par[0]);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
 			return;
 		case 'B': case 'e':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, x, y+par[0]);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
 			return;
 		case 'C': case 'a':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, x+par[0], y);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
 			return;
 		case 'D':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, x-par[0], y);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
 			return;
 		case 'E':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, 0, y+par[0]);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
 			return;
 		case 'F':
-			if (!par[0]) par[0]++;
-			gotoxy(vc_cons[currcons].d, 0, y-par[0]);
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
 			return;
 		case 'd':
-			if (par[0]) par[0]--;
-			gotoxay(currcons,x,par[0]);
+			if (vc->vc_par[0])
+				vc->vc_par[0]--;
+			gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
 			return;
 		case 'H': case 'f':
-			if (par[0]) par[0]--;
-			if (par[1]) par[1]--;
-			gotoxay(currcons,par[1],par[0]);
+			if (vc->vc_par[0])
+				vc->vc_par[0]--;
+			if (vc->vc_par[1])
+				vc->vc_par[1]--;
+			gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
 			return;
 		case 'J':
-			csi_J(currcons,par[0]);
+			csi_J(vc, vc->vc_par[0]);
 			return;
 		case 'K':
-			csi_K(currcons,par[0]);
+			csi_K(vc, vc->vc_par[0]);
 			return;
 		case 'L':
-			csi_L(currcons,par[0]);
+			csi_L(vc, vc->vc_par[0]);
 			return;
 		case 'M':
-			csi_M(currcons,par[0]);
+			csi_M(vc, vc->vc_par[0]);
 			return;
 		case 'P':
-			csi_P(currcons,par[0]);
+			csi_P(vc, vc->vc_par[0]);
 			return;
 		case 'c':
-			if (!par[0])
+			if (!vc->vc_par[0])
 				respond_ID(tty);
 			return;
 		case 'g':
-			if (!par[0])
-				tab_stop[x >> 5] &= ~(1 << (x & 31));
-			else if (par[0] == 3) {
-				tab_stop[0] =
-					tab_stop[1] =
-					tab_stop[2] =
-					tab_stop[3] =
-					tab_stop[4] = 0;
+			if (!vc->vc_par[0])
+				vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+			else if (vc->vc_par[0] == 3) {
+				vc->vc_tab_stop[0] =
+					vc->vc_tab_stop[1] =
+					vc->vc_tab_stop[2] =
+					vc->vc_tab_stop[3] =
+					vc->vc_tab_stop[4] = 0;
 			}
 			return;
 		case 'm':
-			csi_m(currcons);
+			csi_m(vc);
 			return;
 		case 'q': /* DECLL - but only 3 leds */
 			/* map 0,1,2,3 to 0,1,2,4 */
-			if (par[0] < 4)
-				setledstate(kbd_table + currcons,
-					    (par[0] < 3) ? par[0] : 4);
+			if (vc->vc_par[0] < 4)
+				setledstate(kbd_table + vc->vc_num,
+					    (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
 			return;
 		case 'r':
-			if (!par[0])
-				par[0]++;
-			if (!par[1])
-				par[1] = vc_cons[currcons].d->vc_rows;
+			if (!vc->vc_par[0])
+				vc->vc_par[0]++;
+			if (!vc->vc_par[1])
+				vc->vc_par[1] = vc->vc_rows;
 			/* Minimum allowed region is 2 lines */
-			if (par[0] < par[1] &&
-			    par[1] <= vc_cons[currcons].d->vc_rows) {
-				top=par[0]-1;
-				bottom=par[1];
-				gotoxay(currcons,0,0);
+			if (vc->vc_par[0] < vc->vc_par[1] &&
+			    vc->vc_par[1] <= vc->vc_rows) {
+				vc->vc_top = vc->vc_par[0] - 1;
+				vc->vc_bottom = vc->vc_par[1];
+				gotoxay(vc, 0, 0);
 			}
 			return;
 		case 's':
-			save_cur(currcons);
+			save_cur(vc);
 			return;
 		case 'u':
-			restore_cur(currcons);
+			restore_cur(vc);
 			return;
 		case 'X':
-			csi_X(currcons, par[0]);
+			csi_X(vc, vc->vc_par[0]);
 			return;
 		case '@':
-			csi_at(currcons,par[0]);
+			csi_at(vc, vc->vc_par[0]);
 			return;
 		case ']': /* setterm functions */
-			setterm_command(currcons);
+			setterm_command(vc);
 			return;
 		}
 		return;
 	case ESpercent:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		switch (c) {
 		case '@':  /* defined in ISO 2022 */
-			utf = 0;
+			vc->vc_utf = 0;
 			return;
 		case 'G':  /* prelim official escape code */
 		case '8':  /* retained for compatibility */
-			utf = 1;
+			vc->vc_utf = 1;
 			return;
 		}
 		return;
 	case ESfunckey:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		return;
 	case EShash:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 		if (c == '8') {
 			/* DEC screen alignment test. kludge :-) */
-			video_erase_char =
-				(video_erase_char & 0xff00) | 'E';
-			csi_J(currcons, 2);
-			video_erase_char =
-				(video_erase_char & 0xff00) | ' ';
-			do_update_region(vc_cons[currcons].d, origin, screenbuf_size/2);
+			vc->vc_video_erase_char =
+				(vc->vc_video_erase_char & 0xff00) | 'E';
+			csi_J(vc, 2);
+			vc->vc_video_erase_char =
+				(vc->vc_video_erase_char & 0xff00) | ' ';
+			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
 		}
 		return;
 	case ESsetG0:
 		if (c == '0')
-			G0_charset = GRAF_MAP;
+			vc->vc_G0_charset = GRAF_MAP;
 		else if (c == 'B')
-			G0_charset = LAT1_MAP;
+			vc->vc_G0_charset = LAT1_MAP;
 		else if (c == 'U')
-			G0_charset = IBMPC_MAP;
+			vc->vc_G0_charset = IBMPC_MAP;
 		else if (c == 'K')
-			G0_charset = USER_MAP;
-		if (charset == 0)
-			translate = set_translate(G0_charset,currcons);
-		vc_state = ESnormal;
+			vc->vc_G0_charset = USER_MAP;
+		if (vc->vc_charset == 0)
+			vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+		vc->vc_state = ESnormal;
 		return;
 	case ESsetG1:
 		if (c == '0')
-			G1_charset = GRAF_MAP;
+			vc->vc_G1_charset = GRAF_MAP;
 		else if (c == 'B')
-			G1_charset = LAT1_MAP;
+			vc->vc_G1_charset = LAT1_MAP;
 		else if (c == 'U')
-			G1_charset = IBMPC_MAP;
+			vc->vc_G1_charset = IBMPC_MAP;
 		else if (c == 'K')
-			G1_charset = USER_MAP;
-		if (charset == 1)
-			translate = set_translate(G1_charset,currcons);
-		vc_state = ESnormal;
+			vc->vc_G1_charset = USER_MAP;
+		if (vc->vc_charset == 1)
+			vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+		vc->vc_state = ESnormal;
 		return;
 	default:
-		vc_state = ESnormal;
+		vc->vc_state = ESnormal;
 	}
 }
 
@@ -1903,7 +1885,7 @@ static int do_con_write(struct tty_struc
 #define FLUSH do { } while(0);
 #else
 #define FLUSH if (draw_x >= 0) { \
-	sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
+	vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
 	draw_x = -1; \
 	}
 #endif
@@ -1911,7 +1893,7 @@ static int do_con_write(struct tty_struc
 	int c, tc, ok, n = 0, draw_x = -1;
 	unsigned int currcons;
 	unsigned long draw_from = 0, draw_to = 0;
-	struct vt_struct *vt;
+	struct vc_data *vc;
 	u16 himask, charmask;
 	const unsigned char *orig_buf = NULL;
 	int orig_count;
@@ -1922,14 +1904,14 @@ static int do_con_write(struct tty_struc
 	might_sleep();
 
 	acquire_console_sem();
-	vt = tty->driver_data;
-	if (vt == NULL) {
+	vc = tty->driver_data;
+	if (vc == NULL) {
 		printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
 		release_console_sem();
 		return 0;
 	}
 
-	currcons = vt->vc_num;
+	currcons = vc->vc_num;
 	if (!vc_cons_allocated(currcons)) {
 	    /* could this happen? */
 	    static int error = 0;
@@ -1954,19 +1936,19 @@ static int do_con_write(struct tty_struc
 
 	acquire_console_sem();
 
-	vt = tty->driver_data;
-	if (vt == NULL) {
+	vc = tty->driver_data;
+	if (vc == NULL) {
 		printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
 		release_console_sem();
 		goto out;
 	}
 
-	himask = hi_font_mask;
+	himask = vc->vc_hi_font_mask;
 	charmask = himask ? 0x1ff : 0xff;
 
 	/* undraw cursor first */
-	if (IS_FG)
-		hide_cursor(vc_cons[currcons].d);
+	if (IS_FG(vc))
+		hide_cursor(vc);
 
 	while (!tty->stopped && count) {
 		int orig = *buf;
@@ -1976,44 +1958,44 @@ static int do_con_write(struct tty_struc
 		count--;
 
 		/* Do no translation at all in control states */
-		if (vc_state != ESnormal) {
+		if (vc->vc_state != ESnormal) {
 			tc = c;
-		} else if (utf) {
+		} else if (vc->vc_utf) {
 		    /* Combine UTF-8 into Unicode */
 		    /* Incomplete characters silently ignored */
 		    if(c > 0x7f) {
-			if (utf_count > 0 && (c & 0xc0) == 0x80) {
-				utf_char = (utf_char << 6) | (c & 0x3f);
-				utf_count--;
-				if (utf_count == 0)
-				    tc = c = utf_char;
+			if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) {
+				vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+				vc->vc_utf_count--;
+				if (vc->vc_utf_count == 0)
+				    tc = c = vc->vc_utf_char;
 				else continue;
 			} else {
 				if ((c & 0xe0) == 0xc0) {
-				    utf_count = 1;
-				    utf_char = (c & 0x1f);
+				    vc->vc_utf_count = 1;
+				    vc->vc_utf_char = (c & 0x1f);
 				} else if ((c & 0xf0) == 0xe0) {
-				    utf_count = 2;
-				    utf_char = (c & 0x0f);
+				    vc->vc_utf_count = 2;
+				    vc->vc_utf_char = (c & 0x0f);
 				} else if ((c & 0xf8) == 0xf0) {
-				    utf_count = 3;
-				    utf_char = (c & 0x07);
+				    vc->vc_utf_count = 3;
+				    vc->vc_utf_char = (c & 0x07);
 				} else if ((c & 0xfc) == 0xf8) {
-				    utf_count = 4;
-				    utf_char = (c & 0x03);
+				    vc->vc_utf_count = 4;
+				    vc->vc_utf_char = (c & 0x03);
 				} else if ((c & 0xfe) == 0xfc) {
-				    utf_count = 5;
-				    utf_char = (c & 0x01);
+				    vc->vc_utf_count = 5;
+				    vc->vc_utf_char = (c & 0x01);
 				} else
-				    utf_count = 0;
+				    vc->vc_utf_count = 0;
 				continue;
 			      }
 		    } else {
 		      tc = c;
-		      utf_count = 0;
+		      vc->vc_utf_count = 0;
 		    }
 		} else {	/* no utf */
-		  tc = translate[toggle_meta ? (c|0x80) : c];
+		  tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
 		}
 
                 /* If the original code was a control character we
@@ -2027,18 +2009,18 @@ static int do_con_write(struct tty_struc
                  * direct-to-font zone in UTF-8 mode.
                  */
                 ok = tc && (c >= 32 ||
-                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
-                                         : CTRL_ACTION) >> c) & 1)))
-                        && (c != 127 || disp_ctrl)
+			    (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS
+						: CTRL_ACTION) >> c) & 1)))
+			&& (c != 127 || vc->vc_disp_ctrl)
 			&& (c != 128+27);
 
-		if (vc_state == ESnormal && ok) {
+		if (vc->vc_state == ESnormal && ok) {
 			/* Now try to find out how to display it */
-			tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
+			tc = conv_uni_to_pc(vc, tc);
 			if ( tc == -4 ) {
                                 /* If we got -4 (not found) then see if we have
                                    defined a replacement character (U+FFFD) */
-                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
+                                tc = conv_uni_to_pc(vc, 0xfffd);
 
 				/* One reason for the -4 can be that we just
 				   did a clear_unimap();
@@ -2052,33 +2034,33 @@ static int do_con_write(struct tty_struc
 			if (tc & ~charmask)
                                 continue; /* Conversion failed */
 
-			if (need_wrap || decim)
+			if (vc->vc_need_wrap || vc->vc_decim)
 				FLUSH
-			if (need_wrap) {
-				cr(currcons);
-				lf(currcons);
+			if (vc->vc_need_wrap) {
+				cr(vc);
+				lf(vc);
 			}
-			if (decim)
-				insert_char(currcons, 1);
+			if (vc->vc_decim)
+				insert_char(vc, 1);
 			scr_writew(himask ?
-				     ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-				     (attr << 8) + tc,
-				   (u16 *) pos);
-			if (DO_UPDATE && draw_x < 0) {
-				draw_x = x;
-				draw_from = pos;
-			}
-			if (x == vc_cons[currcons].d->vc_cols - 1) {
-				need_wrap = decawm;
-				draw_to = pos+2;
+				     ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+				     (vc->vc_attr << 8) + tc,
+				   (u16 *) vc->vc_pos);
+			if (DO_UPDATE(vc) && draw_x < 0) {
+				draw_x = vc->vc_x;
+				draw_from = vc->vc_pos;
+			}
+			if (vc->vc_x == vc->vc_cols - 1) {
+				vc->vc_need_wrap = vc->vc_decawm;
+				draw_to = vc->vc_pos + 2;
 			} else {
-				x++;
-				draw_to = (pos+=2);
+				vc->vc_x++;
+				draw_to = (vc->vc_pos += 2);
 			}
 			continue;
 		}
 		FLUSH
-		do_con_trol(tty, currcons, orig);
+		do_con_trol(tty, vc, orig);
 	}
 	FLUSH
 	console_conditional_schedule();
@@ -2106,7 +2088,7 @@ static void console_callback(void *ignor
 		if (want_console != fg_console &&
 		    vc_cons_allocated(want_console)) {
 			hide_cursor(vc_cons[fg_console].d);
-			change_console(want_console);
+			change_console(vc_cons[want_console].d);
 			/* we only changed when the console had already
 			   been allocated - a new console is not created
 			   in an interrupt routine */
@@ -2118,10 +2100,10 @@ static void console_callback(void *ignor
 		poke_blanked_console();
 	}
 	if (scrollback_delta) {
-		int currcons = fg_console;
+		struct vc_data *vc = vc_cons[fg_console].d;
 		clear_selection();
-		if (vcmode == KD_TEXT)
-			sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
+		if (vc->vc_mode == KD_TEXT)
+			vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
 		scrollback_delta = 0;
 	}
 	if (blank_timer_expired) {
@@ -2148,9 +2130,9 @@ struct tty_driver *console_driver;
  * The console must be locked when we get here.
  */
 
-void vt_console_print(struct console *co, const char *b, unsigned count)
+static void vt_console_print(struct console *co, const char *b, unsigned count)
 {
-	int currcons = fg_console;
+	struct vc_data *vc = vc_cons[fg_console].d;
 	unsigned char c;
 	static unsigned long printing;
 	const ushort *start;
@@ -2162,76 +2144,73 @@ void vt_console_print(struct console *co
 		return;
 
 	if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
-		currcons = kmsg_redirect - 1;
+		vc = vc_cons[kmsg_redirect - 1].d;
 
 	/* read `x' only after setting currcons properly (otherwise
 	   the `x' macro will read the x of the foreground console). */
-	myx = x;
+	myx = vc->vc_x;
 
-	if (!vc_cons_allocated(currcons)) {
+	if (!vc_cons_allocated(fg_console)) {
 		/* impossible */
 		/* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
 		goto quit;
 	}
 
-	if (vcmode != KD_TEXT)
+	if (vc->vc_mode != KD_TEXT)
 		goto quit;
 
 	/* undraw cursor first */
-	if (IS_FG)
-		hide_cursor(vc_cons[currcons].d);
+	if (IS_FG(vc))
+		hide_cursor(vc);
 
-	start = (ushort *)pos;
+	start = (ushort *)vc->vc_pos;
 
 	/* Contrived structure to try to emulate original need_wrap behaviour
 	 * Problems caused when we have need_wrap set on '\n' character */
 	while (count--) {
 		c = *b++;
-		if (c == 10 || c == 13 || c == 8 || need_wrap) {
+		if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
 			if (cnt > 0) {
-				if (IS_VISIBLE)
-					sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
-				x += cnt;
-				if (need_wrap)
-					x--;
+				if (CON_IS_VISIBLE(vc))
+					vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+				vc->vc_x += cnt;
+				if (vc->vc_need_wrap)
+					vc->vc_x--;
 				cnt = 0;
 			}
 			if (c == 8) {		/* backspace */
-				bs(currcons);
-				start = (ushort *)pos;
-				myx = x;
+				bs(vc);
+				start = (ushort *)vc->vc_pos;
+				myx = vc->vc_x;
 				continue;
 			}
 			if (c != 13)
-				lf(currcons);
-			cr(currcons);
-			start = (ushort *)pos;
-			myx = x;
+				lf(vc);
+			cr(vc);
+			start = (ushort *)vc->vc_pos;
+			myx = vc->vc_x;
 			if (c == 10 || c == 13)
 				continue;
 		}
-		scr_writew((attr << 8) + c, (unsigned short *) pos);
+		scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
 		cnt++;
-		if (myx == vc_cons[currcons].d->vc_cols - 1) {
-			need_wrap = 1;
+		if (myx == vc->vc_cols - 1) {
+			vc->vc_need_wrap = 1;
 			continue;
 		}
-		pos+=2;
+		vc->vc_pos += 2;
 		myx++;
 	}
 	if (cnt > 0) {
-		if (IS_VISIBLE)
-			sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
-		x += cnt;
-		if (x == vc_cons[currcons].d->vc_cols) {
-			x--;
-			need_wrap = 1;
+		if (CON_IS_VISIBLE(vc))
+			vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+		vc->vc_x += cnt;
+		if (vc->vc_x == vc->vc_cols) {
+			vc->vc_x--;
+			vc->vc_need_wrap = 1;
 		}
 	}
-	set_cursor(vc_cons[currcons].d);
-
-	if (!oops_in_progress)
-		poke_blanked_console();
+	set_cursor(vc);
 
 quit:
 	clear_bit(0, &printing);
@@ -2243,7 +2222,7 @@ static struct tty_driver *vt_console_dev
 	return console_driver;
 }
 
-struct console vt_console_driver = {
+static struct console vt_console_driver = {
 	.name		= "tty",
 	.write		= vt_console_print,
 	.device		= vt_console_device,
@@ -2333,7 +2312,7 @@ int tioclinux(struct tty_struct *tty, un
 			if (get_user(lines, (s32 __user *)(p+4))) {
 				ret = -EFAULT;
 			} else {
-				scrollfront(lines);
+				scrollfront(vc_cons[fg_console].d, lines);
 				ret = 0;
 			}
 			break;
@@ -2395,9 +2374,9 @@ static void con_throttle(struct tty_stru
 
 static void con_unthrottle(struct tty_struct *tty)
 {
-	struct vt_struct *vt = tty->driver_data;
+	struct vc_data *vc = tty->driver_data;
 
-	wake_up_interruptible(&vt->paste_wait);
+	wake_up_interruptible(&vc->paste_wait);
 }
 
 /*
@@ -2432,16 +2411,16 @@ static void con_start(struct tty_struct 
 
 static void con_flush_chars(struct tty_struct *tty)
 {
-	struct vt_struct *vt;
+	struct vc_data *vc;
 
 	if (in_interrupt())	/* from flush_to_ldisc */
 		return;
 
 	/* if we race with con_close(), vt may be null */
 	acquire_console_sem();
-	vt = tty->driver_data;
-	if (vt)
-		set_cursor(vc_cons[vt->vc_num].d);
+	vc = tty->driver_data;
+	if (vc)
+		set_cursor(vc);
 	release_console_sem();
 }
 
@@ -2457,9 +2436,9 @@ static int con_open(struct tty_struct *t
 	if (tty->count == 1) {
 		ret = vc_allocate(currcons);
 		if (ret == 0) {
-			vt_cons[currcons]->vc_num = currcons;
-			tty->driver_data = vt_cons[currcons];
-			vc_cons[currcons].d->vc_tty = tty;
+			struct vc_data *vc = vc_cons[currcons].d;
+			tty->driver_data = vc;
+			vc->vc_tty = tty;
 
 			if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 				tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
@@ -2486,11 +2465,10 @@ static void con_close(struct tty_struct 
 	down(&tty_sem);
 	acquire_console_sem();
 	if (tty && tty->count == 1) {
-		struct vt_struct *vt;
+		struct vc_data *vc = tty->driver_data;
 
-		vt = tty->driver_data;
-		if (vt)
-			vc_cons[vt->vc_num].d->vc_tty = NULL;
+		if (vc)
+			vc->vc_tty = NULL;
 		tty->driver_data = NULL;
 		release_console_sem();
 		vcs_remove_devfs(tty);
@@ -2505,29 +2483,29 @@ static void con_close(struct tty_struct 
 	up(&tty_sem);
 }
 
-static void vc_init(unsigned int currcons, unsigned int rows,
-			unsigned int cols, int do_clear)
+static void vc_init(struct vc_data *vc, unsigned int rows,
+		    unsigned int cols, int do_clear)
 {
 	int j, k ;
 
-	vc_cons[currcons].d->vc_cols = cols;
-	vc_cons[currcons].d->vc_rows = rows;
-	vc_cons[currcons].d->vc_size_row = cols<<1;
-	screenbuf_size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_size_row;
-
-	set_origin(currcons);
-	pos = origin;
-	reset_vc(currcons);
+	vc->vc_cols = cols;
+	vc->vc_rows = rows;
+	vc->vc_size_row = cols << 1;
+	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+
+	set_origin(vc);
+	vc->vc_pos = vc->vc_origin;
+	reset_vc(vc);
 	for (j=k=0; j<16; j++) {
-		vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
-		vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
-		vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
-	}
-	def_color       = 0x07;   /* white */
-	ulcolor		= 0x0f;   /* bold white */
-	halfcolor       = 0x08;   /* grey */
-	init_waitqueue_head(&vt_cons[currcons]->paste_wait);
-	reset_terminal(currcons, do_clear);
+		vc->vc_palette[k++] = default_red[j] ;
+		vc->vc_palette[k++] = default_grn[j] ;
+		vc->vc_palette[k++] = default_blu[j] ;
+	}
+	vc->vc_def_color       = 0x07;   /* white */
+	vc->vc_ulcolor		= 0x0f;   /* bold white */
+	vc->vc_halfcolor       = 0x08;   /* grey */
+	init_waitqueue_head(&vc->paste_wait);
+	reset_terminal(vc, do_clear);
 }
 
 /*
@@ -2539,6 +2517,7 @@ static void vc_init(unsigned int currcon
 static int __init con_init(void)
 {
 	const char *display_desc = NULL;
+	struct vc_data *vc;
 	unsigned int currcons = 0;
 
 	acquire_console_sem();
@@ -2562,27 +2541,23 @@ static int __init con_init(void)
 	 * kmalloc is not running yet - we use the bootmem allocator.
 	 */
 	for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
-		vc_cons[currcons].d = (struct vc_data *)
-				alloc_bootmem(sizeof(struct vc_data));
-		vt_cons[currcons] = (struct vt_struct *)
-				alloc_bootmem(sizeof(struct vt_struct));
-		vc_cons[currcons].d->vc_vt = vt_cons[currcons];
-		visual_init(currcons, 1);
-		screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
-		kmalloced = 0;
-		vc_init(currcons, vc_cons[currcons].d->vc_rows, vc_cons[currcons].d->vc_cols,
-			currcons || !sw->con_save_screen);
+		vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
+		visual_init(vc, currcons, 1);
+		vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
+		vc->vc_kmalloced = 0;
+		vc_init(vc, vc->vc_rows, vc->vc_cols,
+			currcons || !vc->vc_sw->con_save_screen);
 	}
 	currcons = fg_console = 0;
-	master_display_fg = vc_cons[currcons].d;
-	set_origin(currcons);
-	save_screen(currcons);
-	gotoxy(vc_cons[currcons].d, x, y);
-	csi_J(currcons, 0);
-	update_screen(fg_console);
+	master_display_fg = vc = vc_cons[currcons].d;
+	set_origin(vc);
+	save_screen(vc);
+	gotoxy(vc, vc->vc_x, vc->vc_y);
+	csi_J(vc, 0);
+	update_screen(vc);
 	printk("Console: %s %s %dx%d",
-		vc_cons[currcons].d->vc_can_do_color ? "colour" : "mono",
-		display_desc, vc_cons[currcons].d->vc_cols, vc_cons[currcons].d->vc_rows);
+		vc->vc_can_do_color ? "colour" : "mono",
+		display_desc, vc->vc_cols, vc->vc_rows);
 	printable = 1;
 	printk("\n");
 
@@ -2676,37 +2651,37 @@ int take_over_console(const struct consw
 
 	for (i = first; i <= last; i++) {
 		int old_was_color;
-		int currcons = i;
+		struct vc_data *vc = vc_cons[i].d;
 
 		if (con_driver_map[i])
 			module_put(con_driver_map[i]->owner);
 		__module_get(owner);
 		con_driver_map[i] = csw;
 
-		if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
+		if (!vc || !vc->vc_sw)
 			continue;
 
 		j = i;
-		if (IS_VISIBLE)
-			save_screen(i);
-		old_was_color = vc_cons[i].d->vc_can_do_color;
-		vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
-		origin = (unsigned long) screenbuf;
-		visible_origin = origin;
-		scr_end = origin + screenbuf_size;
-		pos = origin + vc_cons[currcons].d->vc_size_row*y + 2*x;
-		visual_init(i, 0);
-		update_attr(i);
+		if (CON_IS_VISIBLE(vc))
+			save_screen(vc);
+		old_was_color = vc->vc_can_do_color;
+		vc->vc_sw->con_deinit(vc);
+		vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+		vc->vc_visible_origin = vc->vc_origin;
+		vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+		vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
+		visual_init(vc, i, 0);
+		update_attr(vc);
 
 		/* If the console changed between mono <-> color, then
 		 * the attributes in the screenbuf will be wrong.  The
 		 * following resets all attributes to something sane.
 		 */
-		if (old_was_color != vc_cons[i].d->vc_can_do_color)
-			clear_buffer_attributes(i);
+		if (old_was_color != vc->vc_can_do_color)
+			clear_buffer_attributes(vc);
 
-		if (IS_VISIBLE)
-			update_screen(i);
+		if (CON_IS_VISIBLE(vc))
+			update_screen(vc);
 	}
 	printk("Console: switching ");
 	if (!deflt)
@@ -2773,7 +2748,7 @@ static void vesa_powerdown(void)
 
 void do_blank_screen(int entering_gfx)
 {
-	int currcons = fg_console;
+	struct vc_data *vc = vc_cons[fg_console].d;
 	int i;
 
 	WARN_CONSOLE_UNLOCKED();
@@ -2792,30 +2767,30 @@ void do_blank_screen(int entering_gfx)
 
 	/* entering graphics mode? */
 	if (entering_gfx) {
-		hide_cursor(vc_cons[currcons].d);
-		save_screen(currcons);
-		sw->con_blank(vc_cons[currcons].d, -1, 1);
+		hide_cursor(vc);
+		save_screen(vc);
+		vc->vc_sw->con_blank(vc, -1, 1);
 		console_blanked = fg_console + 1;
-		set_origin(currcons);
+		set_origin(vc);
 		return;
 	}
 
 	/* don't blank graphics */
-	if (vcmode != KD_TEXT) {
+	if (vc->vc_mode != KD_TEXT) {
 		console_blanked = fg_console + 1;
 		return;
 	}
 
-	hide_cursor(vc_cons[currcons].d);
+	hide_cursor(vc);
 	del_timer_sync(&console_timer);
 	blank_timer_expired = 0;
 
-	save_screen(currcons);
+	save_screen(vc);
 	/* In case we need to reset origin, blanking hook returns 1 */
-	i = sw->con_blank(vc_cons[currcons].d, 1, 0);
+	i = vc->vc_sw->con_blank(vc, 1, 0);
 	console_blanked = fg_console + 1;
 	if (i)
-		set_origin(currcons);
+		set_origin(vc);
 
 	if (console_blank_hook && console_blank_hook(1))
 		return;
@@ -2826,7 +2801,7 @@ void do_blank_screen(int entering_gfx)
 	}
 
     	if (vesa_blank_mode)
-		sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1, 0);
+		vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
 }
 EXPORT_SYMBOL(do_blank_screen);
 
@@ -2835,7 +2810,14 @@ EXPORT_SYMBOL(do_blank_screen);
  */
 void do_unblank_screen(int leaving_gfx)
 {
-	int currcons;
+	struct vc_data *vc;
+
+	/* This should now always be called from a "sane" (read: can schedule)
+	 * context for the sake of the low level drivers, except in the special
+	 * case of oops_in_progress
+	 */
+	if (!oops_in_progress)
+		might_sleep();
 
 	WARN_CONSOLE_UNLOCKED();
 
@@ -2847,8 +2829,8 @@ void do_unblank_screen(int leaving_gfx)
 		printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
 		return;
 	}
-	currcons = fg_console;
-	if (vcmode != KD_TEXT)
+	vc = vc_cons[fg_console].d;
+	if (vc->vc_mode != KD_TEXT)
 		return; /* but leave console_blanked != 0 */
 
 	if (blankinterval) {
@@ -2857,13 +2839,13 @@ void do_unblank_screen(int leaving_gfx)
 	}
 
 	console_blanked = 0;
-	if (sw->con_blank(vc_cons[currcons].d, 0, leaving_gfx))
+	if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
 		/* Low-level driver cannot restore -> do it ourselves */
-		update_screen(fg_console);
+		update_screen(vc);
 	if (console_blank_hook)
 		console_blank_hook(0);
-	set_palette(currcons);
-	set_cursor(vc_cons[fg_console].d);
+	set_palette(vc);
+	set_cursor(vc);
 }
 EXPORT_SYMBOL(do_unblank_screen);
 
@@ -2893,13 +2875,21 @@ void poke_blanked_console(void)
 {
 	WARN_CONSOLE_UNLOCKED();
 
+	/* Add this so we quickly catch whoever might call us in a non
+	 * safe context. Nowadays, unblank_screen() isn't to be called in
+	 * atomic contexts and is allowed to schedule (with the special case
+	 * of oops_in_progress, but that isn't of any concern for this
+	 * function. --BenH.
+	 */
+	might_sleep();
+
 	/* This isn't perfectly race free, but a race here would be mostly harmless,
 	 * at worse, we'll do a spurrious blank and it's unlikely
 	 */
 	del_timer(&console_timer);
 	blank_timer_expired = 0;
 
-	if (ignore_poke || !vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+	if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
 		return;
 	if (console_blanked)
 		unblank_screen();
@@ -2913,12 +2903,12 @@ void poke_blanked_console(void)
  *	Palettes
  */
 
-void set_palette(int currcons)
+static void set_palette(struct vc_data *vc)
 {
 	WARN_CONSOLE_UNLOCKED();
 
-	if (vcmode != KD_GRAPHICS)
-		sw->con_set_palette(vc_cons[currcons].d, color_table);
+	if (vc->vc_mode != KD_GRAPHICS)
+		vc->vc_sw->con_set_palette(vc, color_table);
 }
 
 static int set_get_cmap(unsigned char __user *arg, int set)
@@ -2945,7 +2935,7 @@ static int set_get_cmap(unsigned char __
 		    vc_cons[i].d->vc_palette[k++] = default_grn[j];
 		    vc_cons[i].d->vc_palette[k++] = default_blu[j];
 		}
-		set_palette(i);
+		set_palette(vc_cons[i].d);
 	    }
     }
     return 0;
@@ -2978,15 +2968,15 @@ int con_get_cmap(unsigned char __user *a
 	return rc;
 }
 
-void reset_palette(int currcons)
+void reset_palette(struct vc_data *vc)
 {
 	int j, k;
 	for (j=k=0; j<16; j++) {
-		palette[k++] = default_red[j];
-		palette[k++] = default_grn[j];
-		palette[k++] = default_blu[j];
+		vc->vc_palette[k++] = default_red[j];
+		vc->vc_palette[k++] = default_grn[j];
+		vc->vc_palette[k++] = default_blu[j];
 	}
-	set_palette(currcons);
+	set_palette(vc);
 }
 
 /*
@@ -3004,13 +2994,13 @@ void reset_palette(int currcons)
 
 #define max_font_size 65536
 
-int con_font_get(int currcons, struct console_font_op *op)
+static int con_font_get(struct vc_data *vc, struct console_font_op *op)
 {
 	struct console_font font;
 	int rc = -EINVAL;
 	int c;
 
-	if (vt_cons[currcons]->vc_mode != KD_TEXT)
+	if (vc->vc_mode != KD_TEXT)
 		return -EINVAL;
 
 	if (op->data) {
@@ -3021,8 +3011,8 @@ int con_font_get(int currcons, struct co
 		font.data = NULL;
 
 	acquire_console_sem();
-	if (sw->con_font_get)
-		rc = sw->con_font_get(vc_cons[currcons].d, &font);
+	if (vc->vc_sw->con_font_get)
+		rc = vc->vc_sw->con_font_get(vc, &font);
 	else
 		rc = -ENOSYS;
 	release_console_sem();
@@ -3059,13 +3049,13 @@ out:
 	return rc;
 }
 
-int con_font_set(int currcons, struct console_font_op *op)
+static int con_font_set(struct vc_data *vc, struct console_font_op *op)
 {
 	struct console_font font;
 	int rc = -EINVAL;
 	int size;
 
-	if (vt_cons[currcons]->vc_mode != KD_TEXT)
+	if (vc->vc_mode != KD_TEXT)
 		return -EINVAL;
 	if (!op->data)
 		return -EINVAL;
@@ -3107,8 +3097,8 @@ int con_font_set(int currcons, struct co
 		return -EFAULT;
 	}
 	acquire_console_sem();
-	if (sw->con_font_set)
-		rc = sw->con_font_set(vc_cons[currcons].d, &font, op->flags);
+	if (vc->vc_sw->con_font_set)
+		rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
 	else
 		rc = -ENOSYS;
 	release_console_sem();
@@ -3116,14 +3106,14 @@ int con_font_set(int currcons, struct co
 	return rc;
 }
 
-int con_font_default(int currcons, struct console_font_op *op)
+static int con_font_default(struct vc_data *vc, struct console_font_op *op)
 {
 	struct console_font font = {.width = op->width, .height = op->height};
 	char name[MAX_FONT_NAME];
 	char *s = name;
 	int rc;
 
-	if (vt_cons[currcons]->vc_mode != KD_TEXT)
+	if (vc->vc_mode != KD_TEXT)
 		return -EINVAL;
 
 	if (!op->data)
@@ -3134,8 +3124,8 @@ int con_font_default(int currcons, struc
 		name[MAX_FONT_NAME - 1] = 0;
 
 	acquire_console_sem();
-	if (sw->con_font_default)
-		rc = sw->con_font_default(vc_cons[currcons].d, &font, s);
+	if (vc->vc_sw->con_font_default)
+		rc = vc->vc_sw->con_font_default(vc, &font, s);
 	else
 		rc = -ENOSYS;
 	release_console_sem();
@@ -3146,40 +3136,38 @@ int con_font_default(int currcons, struc
 	return rc;
 }
 
-int con_font_copy(int currcons, struct console_font_op *op)
+static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
 {
 	int con = op->height;
-	struct vc_data *vc;
 	int rc;
 
-	if (vt_cons[currcons]->vc_mode != KD_TEXT)
+	if (vc->vc_mode != KD_TEXT)
 		return -EINVAL;
 
 	acquire_console_sem();
-	vc = vc_cons[currcons].d;
-	if (!sw->con_font_copy)
+	if (!vc->vc_sw->con_font_copy)
 		rc = -ENOSYS;
 	else if (con < 0 || !vc_cons_allocated(con))
 		rc = -ENOTTY;
 	else if (con == vc->vc_num)	/* nothing to do */
 		rc = 0;
 	else
-		rc = sw->con_font_copy(vc, con);
+		rc = vc->vc_sw->con_font_copy(vc, con);
 	release_console_sem();
 	return rc;
 }
 
-int con_font_op(int currcons, struct console_font_op *op)
+int con_font_op(struct vc_data *vc, struct console_font_op *op)
 {
 	switch (op->op) {
 	case KD_FONT_OP_SET:
-		return con_font_set(currcons, op);
+		return con_font_set(vc, op);
 	case KD_FONT_OP_GET:
-		return con_font_get(currcons, op);
+		return con_font_get(vc, op);
 	case KD_FONT_OP_SET_DEFAULT:
-		return con_font_default(currcons, op);
+		return con_font_default(vc, op);
 	case KD_FONT_OP_COPY:
-		return con_font_copy(currcons, op);
+		return con_font_copy(vc, op);
 	}
 	return -ENOSYS;
 }
@@ -3233,24 +3221,6 @@ void vcs_scr_writew(struct vc_data *vc, 
 	}
 }
 
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-	switch (rqst)
-	{
-	case PM_RESUME:
-		acquire_console_sem();
-		unblank_screen();
-		release_console_sem();
-		break;
-	case PM_SUSPEND:
-		acquire_console_sem();
-		do_blank_screen(0);
-		release_console_sem();
-		break;
-	}
-	return 0;
-}
-
 /*
  *	Visible symbols for modules
  */
@@ -3265,7 +3235,6 @@ EXPORT_SYMBOL(vc_resize);
 EXPORT_SYMBOL(fg_console);
 EXPORT_SYMBOL(console_blank_hook);
 EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vt_cons);
 EXPORT_SYMBOL(vc_cons);
 #ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -24,6 +24,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/console.h>
+#include <linux/signal.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -33,7 +34,7 @@
 #include <linux/kbd_diacr.h>
 #include <linux/selection.h>
 
-char vt_dont_switch;
+static char vt_dont_switch;
 extern struct tty_driver *console_driver;
 
 #define VT_IS_IN_USE(i)	(console_driver->ttys[i] && console_driver->ttys[i]->count)
@@ -52,17 +53,12 @@ extern struct tty_driver *console_driver
  * to the current console is done by the main ioctl code.
  */
 
-struct vt_struct *vt_cons[MAX_NR_CONSOLES];
-
-/* Keyboard type: Default is KB_101, but can be set by machine
- * specific code.
- */
-unsigned char keyboard_type = KB_101;
-
 #ifdef CONFIG_X86
 #include <linux/syscalls.h>
 #endif
 
+static void complete_change_console(struct vc_data *vc);
+
 /*
  * these are the valid i/o ports we're allowed to change. they map all the
  * video ports
@@ -311,7 +307,7 @@ do_fontx_ioctl(int cmd, struct consolefo
 		op->height = cfdarg.charheight;
 		op->charcount = cfdarg.charcount;
 		op->data = cfdarg.chardata;
-		return con_font_op(fg_console, op);
+		return con_font_op(vc_cons[fg_console].d, op);
 	case GIO_FONTX: {
 		op->op = KD_FONT_OP_GET;
 		op->flags = KD_FONT_FLAG_OLD;
@@ -319,7 +315,7 @@ do_fontx_ioctl(int cmd, struct consolefo
 		op->height = cfdarg.charheight;
 		op->charcount = cfdarg.charcount;
 		op->data = cfdarg.chardata;
-		i = con_font_op(fg_console, op);
+		i = con_font_op(vc_cons[fg_console].d, op);
 		if (i)
 			return i;
 		cfdarg.charheight = op->height;
@@ -333,27 +329,25 @@ do_fontx_ioctl(int cmd, struct consolefo
 }
 
 static inline int 
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, unsigned int console)
+do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
 {
 	struct unimapdesc tmp;
-	int i = 0; 
 
 	if (copy_from_user(&tmp, user_ud, sizeof tmp))
 		return -EFAULT;
-	if (tmp.entries) {
-		i = verify_area(VERIFY_WRITE, tmp.entries, 
-						tmp.entry_ct*sizeof(struct unipair));
-		if (i) return i;
-	}
+	if (tmp.entries)
+		if (!access_ok(VERIFY_WRITE, tmp.entries,
+				tmp.entry_ct*sizeof(struct unipair)))
+			return -EFAULT;
 	switch (cmd) {
 	case PIO_UNIMAP:
 		if (!perm)
 			return -EPERM;
-		return con_set_unimap(console, tmp.entry_ct, tmp.entries);
+		return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
 	case GIO_UNIMAP:
-		if (!perm && fg_console != console)
+		if (!perm && fg_console != vc->vc_num)
 			return -EPERM;
-		return con_get_unimap(console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
 	}
 	return 0;
 }
@@ -365,8 +359,7 @@ do_unimap_ioctl(int cmd, struct unimapde
 int vt_ioctl(struct tty_struct *tty, struct file * file,
 	     unsigned int cmd, unsigned long arg)
 {
-	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-	struct vc_data *vc = vc_cons[vt->vc_num].d;
+	struct vc_data *vc = (struct vc_data *)tty->driver_data;
 	struct console_font_op op;	/* used in multiple places here */
 	struct kbd_struct * kbd;
 	unsigned int console;
@@ -374,7 +367,7 @@ int vt_ioctl(struct tty_struct *tty, str
 	void __user *up = (void __user *)arg;
 	int i, perm;
 	
-	console = vt->vc_num;
+	console = vc->vc_num;
 
 	if (!vc_cons_allocated(console)) 	/* impossible? */
 		return -ENOIOCTLCMD;
@@ -419,7 +412,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		/*
 		 * this is naive.
 		 */
-		ucval = keyboard_type;
+		ucval = KB_101;
 		goto setchar;
 
 		/*
@@ -487,9 +480,9 @@ int vt_ioctl(struct tty_struct *tty, str
 		default:
 			return -EINVAL;
 		}
-		if (vt_cons[console]->vc_mode == (unsigned char) arg)
+		if (vc->vc_mode == (unsigned char) arg)
 			return 0;
-		vt_cons[console]->vc_mode = (unsigned char) arg;
+		vc->vc_mode = (unsigned char) arg;
 		if (console != fg_console)
 			return 0;
 		/*
@@ -504,7 +497,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		return 0;
 
 	case KDGETMODE:
-		ucval = vt_cons[console]->vc_mode;
+		ucval = vc->vc_mode;
 		goto setint;
 
 	case KDMAPDISP:
@@ -649,7 +642,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		extern int spawnpid, spawnsig;
 		if (!perm || !capable(CAP_KILL))
 		  return -EPERM;
-		if (arg < 1 || arg > _NSIG || arg == SIGKILL)
+		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
 		  return -EINVAL;
 		spawnpid = current->pid;
 		spawnsig = arg;
@@ -667,12 +660,12 @@ int vt_ioctl(struct tty_struct *tty, str
 		if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
 			return -EINVAL;
 		acquire_console_sem();
-		vt_cons[console]->vt_mode = tmp;
+		vc->vt_mode = tmp;
 		/* the frsig is ignored, so we set it to 0 */
-		vt_cons[console]->vt_mode.frsig = 0;
-		vt_cons[console]->vt_pid = current->pid;
+		vc->vt_mode.frsig = 0;
+		vc->vt_pid = current->pid;
 		/* no switch is required -- saw@shade.msu.ru */
-		vt_cons[console]->vt_newvt = -1; 
+		vc->vt_newvt = -1;
 		release_console_sem();
 		return 0;
 	}
@@ -683,7 +676,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		int rc;
 
 		acquire_console_sem();
-		memcpy(&tmp, &vt_cons[console]->vt_mode, sizeof(struct vt_mode));
+		memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
 		release_console_sem();
 
 		rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
@@ -761,31 +754,29 @@ int vt_ioctl(struct tty_struct *tty, str
 	case VT_RELDISP:
 		if (!perm)
 			return -EPERM;
-		if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
+		if (vc->vt_mode.mode != VT_PROCESS)
 			return -EINVAL;
 
 		/*
 		 * Switching-from response
 		 */
-		if (vt_cons[console]->vt_newvt >= 0)
-		{
+		if (vc->vt_newvt >= 0) {
 			if (arg == 0)
 				/*
 				 * Switch disallowed, so forget we were trying
 				 * to do it.
 				 */
-				vt_cons[console]->vt_newvt = -1;
+				vc->vt_newvt = -1;
 
-			else
-			{
+			else {
 				/*
 				 * The current vt has been released, so
 				 * complete the switch.
 				 */
 				int newvt;
 				acquire_console_sem();
-				newvt = vt_cons[console]->vt_newvt;
-				vt_cons[console]->vt_newvt = -1;
+				newvt = vc->vt_newvt;
+				vc->vt_newvt = -1;
 				i = vc_allocate(newvt);
 				if (i) {
 					release_console_sem();
@@ -796,7 +787,7 @@ int vt_ioctl(struct tty_struct *tty, str
 				 * make sure we are atomic with respect to
 				 * other console switches..
 				 */
-				complete_change_console(newvt);
+				complete_change_console(vc_cons[newvt].d);
 				release_console_sem();
 			}
 		}
@@ -852,7 +843,7 @@ int vt_ioctl(struct tty_struct *tty, str
 			return -EFAULT;
 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
 			acquire_console_sem();
-                        vc_resize(i, cc, ll);
+			vc_resize(vc_cons[i].d, cc, ll);
 			release_console_sem();
 		}
 		return 0;
@@ -864,7 +855,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		ushort ll,cc,vlin,clin,vcol,ccol;
 		if (!perm)
 			return -EPERM;
-		if (verify_area(VERIFY_READ, vtconsize,
+		if (!access_ok(VERIFY_READ, vtconsize,
 				sizeof(struct vt_consize)))
 			return -EFAULT;
 		__get_user(ll, &vtconsize->v_rows);
@@ -900,7 +891,7 @@ int vt_ioctl(struct tty_struct *tty, str
 				vc_cons[i].d->vc_scan_lines = vlin;
 			if (clin)
 				vc_cons[i].d->vc_font.height = clin;
-			vc_resize(i, cc, ll);
+			vc_resize(vc_cons[i].d, cc, ll);
 			release_console_sem();
 		}
   		return 0;
@@ -915,7 +906,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		op.height = 0;
 		op.charcount = 256;
 		op.data = up;
-		return con_font_op(fg_console, &op);
+		return con_font_op(vc_cons[fg_console].d, &op);
 	}
 
 	case GIO_FONT: {
@@ -925,7 +916,7 @@ int vt_ioctl(struct tty_struct *tty, str
 		op.height = 32;
 		op.charcount = 256;
 		op.data = up;
-		return con_font_op(fg_console, &op);
+		return con_font_op(vc_cons[fg_console].d, &op);
 	}
 
 	case PIO_CMAP:
@@ -953,9 +944,10 @@ int vt_ioctl(struct tty_struct *tty, str
 		{
 		op.op = KD_FONT_OP_SET_DEFAULT;
 		op.data = NULL;
-		i = con_font_op(fg_console, &op);
-		if (i) return i;
-		con_set_default_unimap(fg_console);
+		i = con_font_op(vc_cons[fg_console].d, &op);
+		if (i)
+			return i;
+		con_set_default_unimap(vc_cons[fg_console].d);
 		return 0;
 		}
 #endif
@@ -966,7 +958,7 @@ int vt_ioctl(struct tty_struct *tty, str
 			return -EFAULT;
 		if (!perm && op.op != KD_FONT_OP_GET)
 			return -EPERM;
-		i = con_font_op(console, &op);
+		i = con_font_op(vc, &op);
 		if (i) return i;
 		if (copy_to_user(up, &op, sizeof(op)))
 			return -EFAULT;
@@ -995,13 +987,13 @@ int vt_ioctl(struct tty_struct *tty, str
 			return -EPERM;
 		i = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		if (i) return -EFAULT;
-		con_clear_unimap(console, &ui);
+		con_clear_unimap(vc, &ui);
 		return 0;
 	      }
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
-		return do_unimap_ioctl(cmd, up, perm, console);
+		return do_unimap_ioctl(cmd, up, perm, vc);
 
 	case VT_LOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
@@ -1054,25 +1046,25 @@ int vt_waitactive(int vt)
 
 #define vt_wake_waitactive() wake_up(&vt_activate_queue)
 
-void reset_vc(unsigned int new_console)
+void reset_vc(struct vc_data *vc)
 {
-	vt_cons[new_console]->vc_mode = KD_TEXT;
-	kbd_table[new_console].kbdmode = VC_XLATE;
-	vt_cons[new_console]->vt_mode.mode = VT_AUTO;
-	vt_cons[new_console]->vt_mode.waitv = 0;
-	vt_cons[new_console]->vt_mode.relsig = 0;
-	vt_cons[new_console]->vt_mode.acqsig = 0;
-	vt_cons[new_console]->vt_mode.frsig = 0;
-	vt_cons[new_console]->vt_pid = -1;
-	vt_cons[new_console]->vt_newvt = -1;
+	vc->vc_mode = KD_TEXT;
+	kbd_table[vc->vc_num].kbdmode = VC_XLATE;
+	vc->vt_mode.mode = VT_AUTO;
+	vc->vt_mode.waitv = 0;
+	vc->vt_mode.relsig = 0;
+	vc->vt_mode.acqsig = 0;
+	vc->vt_mode.frsig = 0;
+	vc->vt_pid = -1;
+	vc->vt_newvt = -1;
 	if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
-		reset_palette(new_console) ;
+		reset_palette(vc);
 }
 
 /*
  * Performs the back end of a vt switch
  */
-void complete_change_console(unsigned int new_console)
+static void complete_change_console(struct vc_data *vc)
 {
 	unsigned char old_vc_mode;
 
@@ -1083,8 +1075,8 @@ void complete_change_console(unsigned in
 	 * KD_TEXT mode or vice versa, which means we need to blank or
 	 * unblank the screen later.
 	 */
-	old_vc_mode = vt_cons[fg_console]->vc_mode;
-	switch_screen(new_console);
+	old_vc_mode = vc_cons[fg_console].d->vc_mode;
+	switch_screen(vc);
 
 	/*
 	 * This can't appear below a successful kill_proc().  If it did,
@@ -1096,9 +1088,8 @@ void complete_change_console(unsigned in
 	 * To account for this we duplicate this code below only if the
 	 * controlling process is gone and we've called reset_vc.
 	 */
-	if (old_vc_mode != vt_cons[new_console]->vc_mode)
-	{
-		if (vt_cons[new_console]->vc_mode == KD_TEXT)
+	if (old_vc_mode != vc->vc_mode) {
+		if (vc->vc_mode == KD_TEXT)
 			do_unblank_screen(1);
 		else
 			do_blank_screen(1);
@@ -1109,17 +1100,13 @@ void complete_change_console(unsigned in
 	 * telling it that it has acquired. Also check if it has died and
 	 * clean up (similar to logic employed in change_console())
 	 */
-	if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
-	{
+	if (vc->vt_mode.mode == VT_PROCESS) {
 		/*
 		 * Send the signal as privileged - kill_proc() will
 		 * tell us if the process has gone or something else
 		 * is awry
 		 */
-		if (kill_proc(vt_cons[new_console]->vt_pid,
-			      vt_cons[new_console]->vt_mode.acqsig,
-			      1) != 0)
-		{
+		if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
 		/*
 		 * The controlling process has died, so we revert back to
 		 * normal operation. In this case, we'll also change back
@@ -1129,11 +1116,10 @@ void complete_change_console(unsigned in
 		 * this outside of VT_PROCESS but there is no single process
 		 * to account for and tracking tty count may be undesirable.
 		 */
-		        reset_vc(new_console);
+			reset_vc(vc);
 
-			if (old_vc_mode != vt_cons[new_console]->vc_mode)
-			{
-				if (vt_cons[new_console]->vc_mode == KD_TEXT)
+			if (old_vc_mode != vc->vc_mode) {
+				if (vc->vc_mode == KD_TEXT)
 					do_unblank_screen(1);
 				else
 					do_blank_screen(1);
@@ -1151,11 +1137,11 @@ void complete_change_console(unsigned in
 /*
  * Performs the front-end of a vt switch
  */
-void change_console(unsigned int new_console)
+void change_console(struct vc_data *new_vc)
 {
-        if ((new_console == fg_console) || (vt_dont_switch))
-                return;
-        if (!vc_cons_allocated(new_console))
+	struct vc_data *vc;
+
+	if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
 		return;
 
 	/*
@@ -1173,23 +1159,20 @@ void change_console(unsigned int new_con
 	 * the user waits just the right amount of time :-) and revert the
 	 * vt to auto control.
 	 */
-	if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
-	{
+	vc = vc_cons[fg_console].d;
+	if (vc->vt_mode.mode == VT_PROCESS) {
 		/*
 		 * Send the signal as privileged - kill_proc() will
 		 * tell us if the process has gone or something else
 		 * is awry
 		 */
-		if (kill_proc(vt_cons[fg_console]->vt_pid,
-			      vt_cons[fg_console]->vt_mode.relsig,
-			      1) == 0)
-		{
+		if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
 			/*
 			 * It worked. Mark the vt to switch to and
 			 * return. The process needs to send us a
 			 * VT_RELDISP ioctl to complete the switch.
 			 */
-			vt_cons[fg_console]->vt_newvt = new_console;
+			vc->vt_newvt = new_vc->vc_num;
 			return;
 		}
 
@@ -1202,7 +1185,7 @@ void change_console(unsigned int new_con
 		 * this outside of VT_PROCESS but there is no single process
 		 * to account for and tracking tty count may be undesirable.
 		 */
-		reset_vc(fg_console);
+		reset_vc(vc);
 
 		/*
 		 * Fall through to normal (VT_AUTO) handling of the switch...
@@ -1212,8 +1195,8 @@ void change_console(unsigned int new_con
 	/*
 	 * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
 	 */
-	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+	if (vc->vc_mode == KD_GRAPHICS)
 		return;
 
-	complete_change_console(new_console);
+	complete_change_console(new_vc);
 }
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -268,12 +268,12 @@ config SC1200_WDT
 
 config SCx200_WDT
 	tristate "National Semiconductor SCx200 Watchdog"
-	depends on WATCHDOG && X86 && PCI
+	depends on WATCHDOG && SCx200 && PCI
 	help
 	  Enable the built-in watchdog timer support on the National
 	  Semiconductor SCx200 processors.
 
-	  If compiled as a module, it will be called scx200_watchdog.
+	  If compiled as a module, it will be called scx200_wdt.
 
 config 60XX_WDT
 	tristate "SBC-60XX Watchdog Timer"
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -2,11 +2,6 @@
 # Makefile for the WatchDog device drivers.
 #
 
-# Only one watchdog can succeed. We probe the hardware watchdog
-# drivers first, then the softdog driver.  This means if your hardware
-# watchdog dies or is 'borrowed' for some reason the software watchdog
-# still gives you some cover.
-
 obj-$(CONFIG_PCWATCHDOG) += pcwd.o
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
@@ -24,7 +19,6 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
-obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
@@ -39,3 +33,10 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+
+# Only one watchdog can succeed. We probe the hardware watchdog
+# drivers first, then the softdog driver.  This means if your hardware
+# watchdog dies or is 'borrowed' for some reason the software watchdog
+# still gives you some cover.
+
+obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -382,6 +382,7 @@ static struct pci_device_id i8xx_tco_pci
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },			/* End of list */
 };
 MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -488,7 +488,7 @@ out:
 }
 
 
-void __exit zf_exit(void)
+static void __exit zf_exit(void)
 {
 	zf_timer_off();
 
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -48,8 +48,8 @@
 #include <asm/io.h>
 
 /* Module and version information */
-#define WATCHDOG_VERSION "1.00"
-#define WATCHDOG_DATE "12 Jun 2004"
+#define WATCHDOG_VERSION "1.01"
+#define WATCHDOG_DATE "15 Mar 2005"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
 #define PFX WATCHDOG_NAME ": "
@@ -659,7 +659,7 @@ static int __init pcipcwd_init_module(vo
 {
 	spin_lock_init (&pcipcwd_private.io_lock);
 
-	return pci_module_init(&pcipcwd_driver);
+	return pci_register_driver(&pcipcwd_driver);
 }
 
 static void __exit pcipcwd_cleanup_module(void)
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -56,8 +56,8 @@
 
 
 /* Module and Version Information */
-#define DRIVER_VERSION "1.00"
-#define DRIVER_DATE "12 Jun 2004"
+#define DRIVER_VERSION "1.01"
+#define DRIVER_DATE "15 Mar 2005"
 #define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
 #define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
 #define DRIVER_LICENSE "GPL"
@@ -227,7 +227,7 @@ static int usb_pcwd_send_command(struct 
 	if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
 			HID_REQ_SET_REPORT, HID_DT_REPORT,
 			0x0200, usb_pcwd->interface_number, buf, sizeof(buf),
-			HZ) != sizeof(buf)) {
+			USB_COMMAND_TIMEOUT) != sizeof(buf)) {
 		dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
 	}
 	/* wait till the usb card processed the command,
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -26,6 +26,10 @@
  *	05-Oct-2004	BJD	Added semaphore init to stop crashes on open
  *				Fixed tmr_count / wdt_count confusion
  *				Added configurable debug
+ *
+ *	11-Jan-2004	BJD	Fixed divide-by-2 in timeout code
+ *
+ *	10-Mar-2005	LCVR	Changed S3C2410_VA to S3C24XX_VA
 */
 
 #include <linux/module.h>
@@ -48,8 +52,8 @@
 #include <asm/arch/map.h>
 #include <asm/hardware/clock.h>
 
-#undef S3C2410_VA_WATCHDOG
-#define S3C2410_VA_WATCHDOG (0)
+#undef S3C24XX_VA_WATCHDOG
+#define S3C24XX_VA_WATCHDOG (0)
 
 #include <asm/arch/regs-watchdog.h>
 
@@ -163,11 +167,7 @@ static int s3c2410wdt_set_heartbeat(int 
 	if (timeout < 1)
 		return -EINVAL;
 
-	/* I think someone must have missed a divide-by-2 in the 2410,
-	 * as a divisor of 128 gives half the calculated delay...
-	 */
-
-	freq /= 128/2;
+	freq /= 128;
 	count = timeout * freq;
 
 	DBG("%s: count=%d, timeout=%d, freq=%d\n",
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -35,7 +35,7 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
-#define OSCR_FREQ		3686400
+#define OSCR_FREQ		CLOCK_TICK_RATE
 #define SA1100_CLOSE_MAGIC	(0x5afc4453)
 
 static unsigned long sa1100wdt_users;
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -74,9 +74,9 @@ static char banner[] __initdata = KERN_I
 static int timeout = 1;
 static int io = -1;
 static int io_len = 2;		/* for non plug and play */
-struct semaphore open_sem;
+static struct semaphore open_sem;
 static char expect_close;
-spinlock_t sc1200wdt_lock;	/* io port access serialisation */
+static spinlock_t sc1200wdt_lock;	/* io port access serialisation */
 
 #if defined CONFIG_PNP
 static int isapnp = 1;
@@ -335,7 +335,7 @@ static int __init sc1200wdt_probe(void)
 
 #if defined CONFIG_PNP
 
-struct pnp_device_id scl200wdt_pnp_devices[] = {
+static struct pnp_device_id scl200wdt_pnp_devices[] = {
 	/* National Semiconductor PC87307/PC97307 watchdog component */
 	{.id = "NSC0800", .driver_data = 0},
 	{.id = ""},
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -4,7 +4,7 @@
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
-   Som code taken from:
+   Some code taken from:
    National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
    (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
 
@@ -64,7 +64,7 @@ static char expect_close;
 
 static void scx200_wdt_ping(void)
 {
-	outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO);
 }
 
 static void scx200_wdt_update_margin(void)
@@ -78,9 +78,9 @@ static void scx200_wdt_enable(void)
 	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
 	       wdto_restart);
 
-	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
-	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
-	outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+	outw(0, scx200_cb_base + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
+	outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
 
 	scx200_wdt_ping();
 }
@@ -89,9 +89,9 @@ static void scx200_wdt_disable(void)
 {
 	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
 
-	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
-	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
-	outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+	outw(0, scx200_cb_base + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
+	outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
 }
 
 static int scx200_wdt_open(struct inode *inode, struct file *file)
@@ -217,28 +217,14 @@ static struct miscdevice scx200_wdt_misc
 static int __init scx200_wdt_init(void)
 {
 	int r;
-	static struct pci_device_id ns_sc[] = {
-		{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
-		{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
-		{ },
-	};
 
 	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
 
-	/*
-	 * First check that this really is a NatSemi SCx200 CPU or a Geode
-	 * SC1100 processor
-	 */
-	if (!pci_dev_present(ns_sc))
-		return -ENODEV;
-
-	/* More sanity checks, verify that the configuration block is there */
-	if (!scx200_cb_probe(SCx200_CB_BASE)) {
-		printk(KERN_WARNING NAME ": no configuration block found\n");
+	/* check that we have found the configuration block */
+	if (!scx200_cb_present())
 		return -ENODEV;
-	}
 
-	if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+	if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
 			    SCx200_WDT_SIZE,
 			    "NatSemi SCx200 Watchdog")) {
 		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
@@ -252,7 +238,7 @@ static int __init scx200_wdt_init(void)
 
 	r = misc_register(&scx200_wdt_miscdev);
 	if (r) {
-		release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 				SCx200_WDT_SIZE);
 		return r;
 	}
@@ -261,7 +247,7 @@ static int __init scx200_wdt_init(void)
 	if (r) {
 		printk(KERN_ERR NAME ": unable to register reboot notifier");
 		misc_deregister(&scx200_wdt_miscdev);
-		release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 				SCx200_WDT_SIZE);
 		return r;
 	}
@@ -273,7 +259,7 @@ static void __exit scx200_wdt_cleanup(vo
 {
 	unregister_reboot_notifier(&scx200_wdt_notifier);
 	misc_deregister(&scx200_wdt_miscdev);
-	release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+	release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 		       SCx200_WDT_SIZE);
 }
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -13,9 +13,13 @@ config CPU_FREQ
 
 	  If in doubt, say N.
 
+if CPU_FREQ
+
+config CPU_FREQ_TABLE
+       def_tristate m
+
 config CPU_FREQ_DEBUG
 	bool "Enable CPUfreq debugging"
-	depends on CPU_FREQ
 	help
 	  Say Y here to enable CPUfreq subsystem (including drivers)
 	  debugging. You will need to activate it via the kernel
@@ -29,7 +33,7 @@ config CPU_FREQ_DEBUG
 
 config CPU_FREQ_STAT
        tristate "CPU frequency translation statistics"
-       depends on CPU_FREQ && CPU_FREQ_TABLE
+       select CPU_FREQ_TABLE
        default y
        help
          This driver exports CPU frequency statistics information through sysfs
@@ -37,17 +41,19 @@ config CPU_FREQ_STAT
 
 config CPU_FREQ_STAT_DETAILS
        bool "CPU frequency translation statistics details"
-       depends on CPU_FREQ && CPU_FREQ_STAT
-       default n
+       depends on CPU_FREQ_STAT
        help
          This will show detail CPU frequency translation table in sysfs file
          system
 
+# Note that it is not currently possible to set the other governors (such as ondemand)
+# as the default, since if they fail to initialise, cpufreq will be
+# left in an undefined state.
+
 choice
 	prompt "Default CPUFreq governor"
-	depends on CPU_FREQ
-	default CPU_FREQ_DEFAULT_GOV_PERFORMANCE if !CPU_FREQ_SA1100 && !CPU_FREQ_SA1110
 	default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
+	default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
 	help
 	  This option sets which CPUFreq governor shall be loaded at
 	  startup. If in doubt, select 'performance'.
@@ -73,7 +79,6 @@ endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
        tristate "'performance' governor"
-       depends on CPU_FREQ
        help
 	  This cpufreq governor sets the frequency statically to the
 	  highest available CPU frequency.
@@ -82,7 +87,6 @@ config CPU_FREQ_GOV_PERFORMANCE
 
 config CPU_FREQ_GOV_POWERSAVE
        tristate "'powersave' governor"
-       depends on CPU_FREQ
        help
 	  This cpufreq governor sets the frequency statically to the
 	  lowest available CPU frequency.
@@ -91,7 +95,6 @@ config CPU_FREQ_GOV_POWERSAVE
 
 config CPU_FREQ_GOV_USERSPACE
        tristate "'userspace' governor for userspace frequency scaling"
-       depends on CPU_FREQ 
        help
 	  Enable this cpufreq governor when you either want to set the
 	  CPU frequency manually or when an userspace program shall
@@ -104,7 +107,6 @@ config CPU_FREQ_GOV_USERSPACE
 
 config CPU_FREQ_GOV_ONDEMAND
 	tristate "'ondemand' cpufreq policy governor"
-	depends on CPU_FREQ
 	help
 	  'ondemand' - This driver adds a dynamic cpufreq policy governor.
 	  The governor does a periodic polling and 
@@ -116,3 +118,25 @@ config CPU_FREQ_GOV_ONDEMAND
 	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
+
+config CPU_FREQ_GOV_CONSERVATIVE
+	tristate "'conservative' cpufreq governor"
+	depends on CPU_FREQ
+	help
+	  'conservative' - this driver is rather similar to the 'ondemand'
+	  governor both in its source code and its purpose, the difference is
+	  its optimisation for better suitability in a battery powered
+	  environment.  The frequency is gracefully increased and decreased
+	  rather than jumping to 100% when speed is required.
+
+	  If you have a desktop machine then you should really be considering
+	  the 'ondemand' governor instead, however if you are using a laptop,
+	  PDA or even an AMD64 based computer (due to the unacceptable
+	  step-by-step latency issues between the minimum and maximum frequency
+	  transitions in the CPU) you will probably want to use this governor.
+
+	  For details, take a look at linux/Documentation/cpu-freq.
+
+	  If in doubt, say N.
+
+endif	# CPU_FREQ
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE)	+
 obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)	+= cpufreq_powersave.o
 obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= cpufreq_userspace.o
 obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)	+= cpufreq_ondemand.o
+obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
 
 # CPUfreq cross-arch helpers
 obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -223,7 +223,7 @@ static inline void adjust_jiffies(unsign
 	}
 	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
 	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
-	    (val == CPUFREQ_RESUMECHANGE)) {
+	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
 		loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
 		dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new);
 	}
@@ -258,7 +258,7 @@ void cpufreq_notify_transition(struct cp
 			    (likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
 			    (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
 			{
-				printk(KERN_WARNING "Warning: CPU frequency is %u, "
+				dprintk(KERN_WARNING "Warning: CPU frequency is %u, "
 				       "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
 				freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
 			}
@@ -814,7 +814,7 @@ static void cpufreq_out_of_sync(unsigned
 {
 	struct cpufreq_freqs freqs;
 
-	printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
+	dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
 	       "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
 
 	freqs.cpu = cpu;
@@ -866,11 +866,90 @@ EXPORT_SYMBOL(cpufreq_get);
 
 
 /**
+ *	cpufreq_suspend - let the low level driver prepare for suspend
+ */
+
+static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+{
+	int cpu = sysdev->id;
+	unsigned int ret = 0;
+	unsigned int cur_freq = 0;
+	struct cpufreq_policy *cpu_policy;
+
+	dprintk("resuming cpu %u\n", cpu);
+
+	if (!cpu_online(cpu))
+		return 0;
+
+	/* we may be lax here as interrupts are off. Nonetheless
+	 * we need to grab the correct cpu policy, as to check
+	 * whether we really run on this CPU.
+	 */
+
+	cpu_policy = cpufreq_cpu_get(cpu);
+	if (!cpu_policy)
+		return -EINVAL;
+
+	/* only handle each CPU group once */
+	if (unlikely(cpu_policy->cpu != cpu)) {
+		cpufreq_cpu_put(cpu_policy);
+		return 0;
+	}
+
+	if (cpufreq_driver->suspend) {
+		ret = cpufreq_driver->suspend(cpu_policy, state);
+		if (ret) {
+			printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
+					"step on CPU %u\n", cpu_policy->cpu);
+			cpufreq_cpu_put(cpu_policy);
+			return ret;
+		}
+	}
+
+
+	if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
+		goto out;
+
+	if (cpufreq_driver->get)
+		cur_freq = cpufreq_driver->get(cpu_policy->cpu);
+
+	if (!cur_freq || !cpu_policy->cur) {
+		printk(KERN_ERR "cpufreq: suspend failed to assert current "
+		       "frequency is what timing core thinks it is.\n");
+		goto out;
+	}
+
+	if (unlikely(cur_freq != cpu_policy->cur)) {
+		struct cpufreq_freqs freqs;
+
+		if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+			dprintk(KERN_DEBUG "Warning: CPU frequency is %u, "
+			       "cpufreq assumed %u kHz.\n",
+			       cur_freq, cpu_policy->cur);
+
+		freqs.cpu = cpu;
+		freqs.old = cpu_policy->cur;
+		freqs.new = cur_freq;
+
+		notifier_call_chain(&cpufreq_transition_notifier_list,
+				    CPUFREQ_SUSPENDCHANGE, &freqs);
+		adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
+
+		cpu_policy->cur = cur_freq;
+	}
+
+ out:
+	cpufreq_cpu_put(cpu_policy);
+	return 0;
+}
+
+/**
  *	cpufreq_resume -  restore proper CPU frequency handling after resume
  *
  *	1.) resume CPUfreq hardware support (cpufreq_driver->resume())
  *	2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
- *	3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
+ *	3.) schedule call cpufreq_update_policy() ASAP as interrupts are
+ *	    restored.
  */
 static int cpufreq_resume(struct sys_device * sysdev)
 {
@@ -915,21 +994,26 @@ static int cpufreq_resume(struct sys_dev
 			cur_freq = cpufreq_driver->get(cpu_policy->cpu);
 
 		if (!cur_freq || !cpu_policy->cur) {
-			printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
+			printk(KERN_ERR "cpufreq: resume failed to assert "
+					"current frequency is what timing core "
+					"thinks it is.\n");
 			goto out;
 		}
 
 		if (unlikely(cur_freq != cpu_policy->cur)) {
 			struct cpufreq_freqs freqs;
 
-			printk(KERN_WARNING "Warning: CPU frequency is %u, "
-			       "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur);
+			if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+				dprintk(KERN_WARNING "Warning: CPU frequency"
+				       "is %u, cpufreq assumed %u kHz.\n",
+				       cur_freq, cpu_policy->cur);
 
 			freqs.cpu = cpu;
 			freqs.old = cpu_policy->cur;
 			freqs.new = cur_freq;
 
-			notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
+			notifier_call_chain(&cpufreq_transition_notifier_list,
+					CPUFREQ_RESUMECHANGE, &freqs);
 			adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
 
 			cpu_policy->cur = cur_freq;
@@ -945,6 +1029,7 @@ out:
 static struct sysdev_driver cpufreq_sysdev_driver = {
 	.add		= cpufreq_add_dev,
 	.remove		= cpufreq_remove_dev,
+	.suspend	= cpufreq_suspend,
 	.resume		= cpufreq_resume,
 };
 
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
new file mode 100644
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -0,0 +1,586 @@
+/*
+ *  drivers/cpufreq/cpufreq_conservative.c
+ *
+ *  Copyright (C)  2001 Russell King
+ *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
+ *                      Jun Nakajima <jun.nakajima@intel.com>
+ *            (C)  2004 Alexander Clouter <alex-kernel@digriz.org.uk>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/cpufreq.h>
+#include <linux/sysctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/kernel_stat.h>
+#include <linux/percpu.h>
+
+/*
+ * dbs is used in this file as a shortform for demandbased switching
+ * It helps to keep variable names smaller, simpler
+ */
+
+#define DEF_FREQUENCY_UP_THRESHOLD		(80)
+#define MIN_FREQUENCY_UP_THRESHOLD		(0)
+#define MAX_FREQUENCY_UP_THRESHOLD		(100)
+
+#define DEF_FREQUENCY_DOWN_THRESHOLD		(20)
+#define MIN_FREQUENCY_DOWN_THRESHOLD		(0)
+#define MAX_FREQUENCY_DOWN_THRESHOLD		(100)
+
+/* 
+ * The polling frequency of this governor depends on the capability of 
+ * the processor. Default polling frequency is 1000 times the transition
+ * latency of the processor. The governor will work on any processor with 
+ * transition latency <= 10mS, using appropriate sampling 
+ * rate.
+ * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work.
+ * All times here are in uS.
+ */
+static unsigned int 				def_sampling_rate;
+#define MIN_SAMPLING_RATE			(def_sampling_rate / 2)
+#define MAX_SAMPLING_RATE			(500 * def_sampling_rate)
+#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(100000)
+#define DEF_SAMPLING_DOWN_FACTOR		(5)
+#define TRANSITION_LATENCY_LIMIT		(10 * 1000)
+
+static void do_dbs_timer(void *data);
+
+struct cpu_dbs_info_s {
+	struct cpufreq_policy 	*cur_policy;
+	unsigned int 		prev_cpu_idle_up;
+	unsigned int 		prev_cpu_idle_down;
+	unsigned int 		enable;
+};
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+
+static unsigned int dbs_enable;	/* number of CPUs using this policy */
+
+static DECLARE_MUTEX 	(dbs_sem);
+static DECLARE_WORK	(dbs_work, do_dbs_timer, NULL);
+
+struct dbs_tuners {
+	unsigned int 		sampling_rate;
+	unsigned int		sampling_down_factor;
+	unsigned int		up_threshold;
+	unsigned int		down_threshold;
+	unsigned int		ignore_nice;
+	unsigned int		freq_step;
+};
+
+static struct dbs_tuners dbs_tuners_ins = {
+	.up_threshold 		= DEF_FREQUENCY_UP_THRESHOLD,
+	.down_threshold 	= DEF_FREQUENCY_DOWN_THRESHOLD,
+	.sampling_down_factor 	= DEF_SAMPLING_DOWN_FACTOR,
+};
+
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+	return	kstat_cpu(cpu).cpustat.idle +
+		kstat_cpu(cpu).cpustat.iowait +
+		( !dbs_tuners_ins.ignore_nice ? 
+		  kstat_cpu(cpu).cpustat.nice :
+		  0);
+}
+
+/************************** sysfs interface ************************/
+static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+{
+	return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+}
+
+static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+{
+	return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+}
+
+#define define_one_ro(_name) 					\
+static struct freq_attr _name =  				\
+__ATTR(_name, 0444, show_##_name, NULL)
+
+define_one_ro(sampling_rate_max);
+define_one_ro(sampling_rate_min);
+
+/* cpufreq_conservative Governor Tunables */
+#define show_one(file_name, object)					\
+static ssize_t show_##file_name						\
+(struct cpufreq_policy *unused, char *buf)				\
+{									\
+	return sprintf(buf, "%u\n", dbs_tuners_ins.object);		\
+}
+show_one(sampling_rate, sampling_rate);
+show_one(sampling_down_factor, sampling_down_factor);
+show_one(up_threshold, up_threshold);
+show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
+show_one(freq_step, freq_step);
+
+static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, 
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf (buf, "%u", &input);
+	if (ret != 1 )
+		return -EINVAL;
+
+	down(&dbs_sem);
+	dbs_tuners_ins.sampling_down_factor = input;
+	up(&dbs_sem);
+
+	return count;
+}
+
+static ssize_t store_sampling_rate(struct cpufreq_policy *unused, 
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf (buf, "%u", &input);
+
+	down(&dbs_sem);
+	if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
+		up(&dbs_sem);
+		return -EINVAL;
+	}
+
+	dbs_tuners_ins.sampling_rate = input;
+	up(&dbs_sem);
+
+	return count;
+}
+
+static ssize_t store_up_threshold(struct cpufreq_policy *unused, 
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf (buf, "%u", &input);
+
+	down(&dbs_sem);
+	if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
+			input < MIN_FREQUENCY_UP_THRESHOLD ||
+			input <= dbs_tuners_ins.down_threshold) {
+		up(&dbs_sem);
+		return -EINVAL;
+	}
+
+	dbs_tuners_ins.up_threshold = input;
+	up(&dbs_sem);
+
+	return count;
+}
+
+static ssize_t store_down_threshold(struct cpufreq_policy *unused, 
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf (buf, "%u", &input);
+
+	down(&dbs_sem);
+	if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || 
+			input < MIN_FREQUENCY_DOWN_THRESHOLD ||
+			input >= dbs_tuners_ins.up_threshold) {
+		up(&dbs_sem);
+		return -EINVAL;
+	}
+
+	dbs_tuners_ins.down_threshold = input;
+	up(&dbs_sem);
+
+	return count;
+}
+
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+
+	unsigned int j;
+	
+	ret = sscanf (buf, "%u", &input);
+	if ( ret != 1 )
+		return -EINVAL;
+
+	if ( input > 1 )
+		input = 1;
+	
+	down(&dbs_sem);
+	if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
+		up(&dbs_sem);
+		return count;
+	}
+	dbs_tuners_ins.ignore_nice = input;
+
+	/* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+	for_each_online_cpu(j) {
+		struct cpu_dbs_info_s *j_dbs_info;
+		j_dbs_info = &per_cpu(cpu_dbs_info, j);
+		j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+		j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+	}
+	up(&dbs_sem);
+
+	return count;
+}
+
+static ssize_t store_freq_step(struct cpufreq_policy *policy,
+		const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+
+	ret = sscanf (buf, "%u", &input);
+
+	if ( ret != 1 )
+		return -EINVAL;
+
+	if ( input > 100 )
+		input = 100;
+	
+	/* no need to test here if freq_step is zero as the user might actually
+	 * want this, they would be crazy though :) */
+	down(&dbs_sem);
+	dbs_tuners_ins.freq_step = input;
+	up(&dbs_sem);
+
+	return count;
+}
+
+#define define_one_rw(_name) \
+static struct freq_attr _name = \
+__ATTR(_name, 0644, show_##_name, store_##_name)
+
+define_one_rw(sampling_rate);
+define_one_rw(sampling_down_factor);
+define_one_rw(up_threshold);
+define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
+define_one_rw(freq_step);
+
+static struct attribute * dbs_attributes[] = {
+	&sampling_rate_max.attr,
+	&sampling_rate_min.attr,
+	&sampling_rate.attr,
+	&sampling_down_factor.attr,
+	&up_threshold.attr,
+	&down_threshold.attr,
+	&ignore_nice.attr,
+	&freq_step.attr,
+	NULL
+};
+
+static struct attribute_group dbs_attr_group = {
+	.attrs = dbs_attributes,
+	.name = "conservative",
+};
+
+/************************** sysfs end ************************/
+
+static void dbs_check_cpu(int cpu)
+{
+	unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
+	unsigned int freq_step;
+	unsigned int freq_down_sampling_rate;
+	static int down_skip[NR_CPUS];
+	static int requested_freq[NR_CPUS];
+	static unsigned short init_flag = 0;
+	struct cpu_dbs_info_s *this_dbs_info;
+	struct cpu_dbs_info_s *dbs_info;
+
+	struct cpufreq_policy *policy;
+	unsigned int j;
+
+	this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+	if (!this_dbs_info->enable)
+		return;
+
+	policy = this_dbs_info->cur_policy;
+
+	if ( init_flag == 0 ) {
+		for ( /* NULL */; init_flag < NR_CPUS; init_flag++ ) {
+			dbs_info = &per_cpu(cpu_dbs_info, init_flag);
+			requested_freq[cpu] = dbs_info->cur_policy->cur;
+		}
+		init_flag = 1;
+	}
+	
+	/* 
+	 * The default safe range is 20% to 80% 
+	 * Every sampling_rate, we check
+	 * 	- If current idle time is less than 20%, then we try to 
+	 * 	  increase frequency
+	 * Every sampling_rate*sampling_down_factor, we check
+	 * 	- If current idle time is more than 80%, then we try to
+	 * 	  decrease frequency
+	 *
+	 * Any frequency increase takes it to the maximum frequency. 
+	 * Frequency reduction happens at minimum steps of 
+	 * 5% (default) of max_frequency 
+	 */
+
+	/* Check for frequency increase */
+
+	idle_ticks = UINT_MAX;
+	for_each_cpu_mask(j, policy->cpus) {
+		unsigned int tmp_idle_ticks, total_idle_ticks;
+		struct cpu_dbs_info_s *j_dbs_info;
+
+		j_dbs_info = &per_cpu(cpu_dbs_info, j);
+		/* Check for frequency increase */
+		total_idle_ticks = get_cpu_idle_time(j);
+		tmp_idle_ticks = total_idle_ticks -
+			j_dbs_info->prev_cpu_idle_up;
+		j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+
+		if (tmp_idle_ticks < idle_ticks)
+			idle_ticks = tmp_idle_ticks;
+	}
+
+	/* Scale idle ticks by 100 and compare with up and down ticks */
+	idle_ticks *= 100;
+	up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
+		usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+	if (idle_ticks < up_idle_ticks) {
+		down_skip[cpu] = 0;
+		for_each_cpu_mask(j, policy->cpus) {
+			struct cpu_dbs_info_s *j_dbs_info;
+
+			j_dbs_info = &per_cpu(cpu_dbs_info, j);
+			j_dbs_info->prev_cpu_idle_down = 
+					j_dbs_info->prev_cpu_idle_up;
+		}
+		/* if we are already at full speed then break out early */
+		if (requested_freq[cpu] == policy->max)
+			return;
+		
+		freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
+
+		/* max freq cannot be less than 100. But who knows.... */
+		if (unlikely(freq_step == 0))
+			freq_step = 5;
+		
+		requested_freq[cpu] += freq_step;
+		if (requested_freq[cpu] > policy->max)
+			requested_freq[cpu] = policy->max;
+
+		__cpufreq_driver_target(policy, requested_freq[cpu], 
+			CPUFREQ_RELATION_H);
+		return;
+	}
+
+	/* Check for frequency decrease */
+	down_skip[cpu]++;
+	if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
+		return;
+
+	idle_ticks = UINT_MAX;
+	for_each_cpu_mask(j, policy->cpus) {
+		unsigned int tmp_idle_ticks, total_idle_ticks;
+		struct cpu_dbs_info_s *j_dbs_info;
+
+		j_dbs_info = &per_cpu(cpu_dbs_info, j);
+		total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
+		tmp_idle_ticks = total_idle_ticks -
+			j_dbs_info->prev_cpu_idle_down;
+		j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+
+		if (tmp_idle_ticks < idle_ticks)
+			idle_ticks = tmp_idle_ticks;
+	}
+
+	/* Scale idle ticks by 100 and compare with up and down ticks */
+	idle_ticks *= 100;
+	down_skip[cpu] = 0;
+
+	freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
+		dbs_tuners_ins.sampling_down_factor;
+	down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
+			usecs_to_jiffies(freq_down_sampling_rate);
+
+	if (idle_ticks > down_idle_ticks) {
+		/* if we are already at the lowest speed then break out early
+		 * or if we 'cannot' reduce the speed as the user might want
+		 * freq_step to be zero */
+		if (requested_freq[cpu] == policy->min
+				|| dbs_tuners_ins.freq_step == 0)
+			return;
+
+		freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
+
+		/* max freq cannot be less than 100. But who knows.... */
+		if (unlikely(freq_step == 0))
+			freq_step = 5;
+
+		requested_freq[cpu] -= freq_step;
+		if (requested_freq[cpu] < policy->min)
+			requested_freq[cpu] = policy->min;
+
+		__cpufreq_driver_target(policy,
+			requested_freq[cpu],
+			CPUFREQ_RELATION_H);
+		return;
+	}
+}
+
+static void do_dbs_timer(void *data)
+{ 
+	int i;
+	down(&dbs_sem);
+	for_each_online_cpu(i)
+		dbs_check_cpu(i);
+	schedule_delayed_work(&dbs_work, 
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+	up(&dbs_sem);
+} 
+
+static inline void dbs_timer_init(void)
+{
+	INIT_WORK(&dbs_work, do_dbs_timer, NULL);
+	schedule_delayed_work(&dbs_work,
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+	return;
+}
+
+static inline void dbs_timer_exit(void)
+{
+	cancel_delayed_work(&dbs_work);
+	return;
+}
+
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+				   unsigned int event)
+{
+	unsigned int cpu = policy->cpu;
+	struct cpu_dbs_info_s *this_dbs_info;
+	unsigned int j;
+
+	this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+	switch (event) {
+	case CPUFREQ_GOV_START:
+		if ((!cpu_online(cpu)) || 
+		    (!policy->cur))
+			return -EINVAL;
+
+		if (policy->cpuinfo.transition_latency >
+				(TRANSITION_LATENCY_LIMIT * 1000))
+			return -EINVAL;
+		if (this_dbs_info->enable) /* Already enabled */
+			break;
+		 
+		down(&dbs_sem);
+		for_each_cpu_mask(j, policy->cpus) {
+			struct cpu_dbs_info_s *j_dbs_info;
+			j_dbs_info = &per_cpu(cpu_dbs_info, j);
+			j_dbs_info->cur_policy = policy;
+		
+			j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+			j_dbs_info->prev_cpu_idle_down
+				= j_dbs_info->prev_cpu_idle_up;
+		}
+		this_dbs_info->enable = 1;
+		sysfs_create_group(&policy->kobj, &dbs_attr_group);
+		dbs_enable++;
+		/*
+		 * Start the timerschedule work, when this governor
+		 * is used for first time
+		 */
+		if (dbs_enable == 1) {
+			unsigned int latency;
+			/* policy latency is in nS. Convert it to uS first */
+
+			latency = policy->cpuinfo.transition_latency;
+			if (latency < 1000)
+				latency = 1000;
+
+			def_sampling_rate = (latency / 1000) *
+					DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
+			dbs_tuners_ins.sampling_rate = def_sampling_rate;
+			dbs_tuners_ins.ignore_nice = 0;
+			dbs_tuners_ins.freq_step = 5;
+
+			dbs_timer_init();
+		}
+		
+		up(&dbs_sem);
+		break;
+
+	case CPUFREQ_GOV_STOP:
+		down(&dbs_sem);
+		this_dbs_info->enable = 0;
+		sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+		dbs_enable--;
+		/*
+		 * Stop the timerschedule work, when this governor
+		 * is used for first time
+		 */
+		if (dbs_enable == 0) 
+			dbs_timer_exit();
+		
+		up(&dbs_sem);
+
+		break;
+
+	case CPUFREQ_GOV_LIMITS:
+		down(&dbs_sem);
+		if (policy->max < this_dbs_info->cur_policy->cur)
+			__cpufreq_driver_target(
+					this_dbs_info->cur_policy,
+				       	policy->max, CPUFREQ_RELATION_H);
+		else if (policy->min > this_dbs_info->cur_policy->cur)
+			__cpufreq_driver_target(
+					this_dbs_info->cur_policy,
+				       	policy->min, CPUFREQ_RELATION_L);
+		up(&dbs_sem);
+		break;
+	}
+	return 0;
+}
+
+static struct cpufreq_governor cpufreq_gov_dbs = {
+	.name		= "conservative",
+	.governor	= cpufreq_governor_dbs,
+	.owner		= THIS_MODULE,
+};
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+	return cpufreq_register_governor(&cpufreq_gov_dbs);
+}
+
+static void __exit cpufreq_gov_dbs_exit(void)
+{
+	/* Make sure that the scheduled work is indeed not running */
+	flush_scheduled_work();
+
+	cpufreq_unregister_governor(&cpufreq_gov_dbs);
+}
+
+
+MODULE_AUTHOR ("Alexander Clouter <alex-kernel@digriz.org.uk>");
+MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for "
+		"Low Latency Frequency Transition capable processors "
+		"optimised for use in a battery environment");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_gov_dbs_init);
+module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -34,13 +34,9 @@
  */
 
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
-#define MIN_FREQUENCY_UP_THRESHOLD		(0)
+#define MIN_FREQUENCY_UP_THRESHOLD		(11)
 #define MAX_FREQUENCY_UP_THRESHOLD		(100)
 
-#define DEF_FREQUENCY_DOWN_THRESHOLD		(20)
-#define MIN_FREQUENCY_DOWN_THRESHOLD		(0)
-#define MAX_FREQUENCY_DOWN_THRESHOLD		(100)
-
 /* 
  * The polling frequency of this governor depends on the capability of 
  * the processor. Default polling frequency is 1000 times the transition
@@ -55,9 +51,9 @@ static unsigned int 				def_sampling_rat
 #define MIN_SAMPLING_RATE			(def_sampling_rate / 2)
 #define MAX_SAMPLING_RATE			(500 * def_sampling_rate)
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
-#define DEF_SAMPLING_DOWN_FACTOR		(10)
+#define DEF_SAMPLING_DOWN_FACTOR		(1)
+#define MAX_SAMPLING_DOWN_FACTOR		(10)
 #define TRANSITION_LATENCY_LIMIT		(10 * 1000)
-#define sampling_rate_in_HZ(x)			(((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000)))
 
 static void do_dbs_timer(void *data);
 
@@ -78,15 +74,23 @@ struct dbs_tuners {
 	unsigned int 		sampling_rate;
 	unsigned int		sampling_down_factor;
 	unsigned int		up_threshold;
-	unsigned int		down_threshold;
+	unsigned int		ignore_nice;
 };
 
 static struct dbs_tuners dbs_tuners_ins = {
 	.up_threshold 		= DEF_FREQUENCY_UP_THRESHOLD,
-	.down_threshold 	= DEF_FREQUENCY_DOWN_THRESHOLD,
 	.sampling_down_factor 	= DEF_SAMPLING_DOWN_FACTOR,
 };
 
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+	return	kstat_cpu(cpu).cpustat.idle +
+		kstat_cpu(cpu).cpustat.iowait +
+		( !dbs_tuners_ins.ignore_nice ? 
+		  kstat_cpu(cpu).cpustat.nice :
+		  0);
+}
+
 /************************** sysfs interface ************************/
 static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
 {
@@ -115,7 +119,7 @@ static ssize_t show_##file_name						\
 show_one(sampling_rate, sampling_rate);
 show_one(sampling_down_factor, sampling_down_factor);
 show_one(up_threshold, up_threshold);
-show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
 
 static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, 
 		const char *buf, size_t count)
@@ -126,6 +130,9 @@ static ssize_t store_sampling_down_facto
 	if (ret != 1 )
 		return -EINVAL;
 
+	if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+		return -EINVAL;
+
 	down(&dbs_sem);
 	dbs_tuners_ins.sampling_down_factor = input;
 	up(&dbs_sem);
@@ -161,8 +168,7 @@ static ssize_t store_up_threshold(struct
 
 	down(&dbs_sem);
 	if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
-			input < MIN_FREQUENCY_UP_THRESHOLD ||
-			input <= dbs_tuners_ins.down_threshold) {
+			input < MIN_FREQUENCY_UP_THRESHOLD) {
 		up(&dbs_sem);
 		return -EINVAL;
 	}
@@ -173,22 +179,35 @@ static ssize_t store_up_threshold(struct
 	return count;
 }
 
-static ssize_t store_down_threshold(struct cpufreq_policy *unused, 
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
 		const char *buf, size_t count)
 {
 	unsigned int input;
 	int ret;
+
+	unsigned int j;
+	
 	ret = sscanf (buf, "%u", &input);
+	if ( ret != 1 )
+		return -EINVAL;
 
+	if ( input > 1 )
+		input = 1;
+	
 	down(&dbs_sem);
-	if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || 
-			input < MIN_FREQUENCY_DOWN_THRESHOLD ||
-			input >= dbs_tuners_ins.up_threshold) {
+	if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
 		up(&dbs_sem);
-		return -EINVAL;
+		return count;
 	}
+	dbs_tuners_ins.ignore_nice = input;
 
-	dbs_tuners_ins.down_threshold = input;
+	/* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+	for_each_online_cpu(j) {
+		struct cpu_dbs_info_s *j_dbs_info;
+		j_dbs_info = &per_cpu(cpu_dbs_info, j);
+		j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+		j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+	}
 	up(&dbs_sem);
 
 	return count;
@@ -201,7 +220,7 @@ __ATTR(_name, 0644, show_##_name, store_
 define_one_rw(sampling_rate);
 define_one_rw(sampling_down_factor);
 define_one_rw(up_threshold);
-define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
 
 static struct attribute * dbs_attributes[] = {
 	&sampling_rate_max.attr,
@@ -209,7 +228,7 @@ static struct attribute * dbs_attributes
 	&sampling_rate.attr,
 	&sampling_down_factor.attr,
 	&up_threshold.attr,
-	&down_threshold.attr,
+	&ignore_nice.attr,
 	NULL
 };
 
@@ -222,9 +241,8 @@ static struct attribute_group dbs_attr_g
 
 static void dbs_check_cpu(int cpu)
 {
-	unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
-	unsigned int total_idle_ticks;
-	unsigned int freq_down_step;
+	unsigned int idle_ticks, up_idle_ticks, total_ticks;
+	unsigned int freq_next;
 	unsigned int freq_down_sampling_rate;
 	static int down_skip[NR_CPUS];
 	struct cpu_dbs_info_s *this_dbs_info;
@@ -238,38 +256,25 @@ static void dbs_check_cpu(int cpu)
 
 	policy = this_dbs_info->cur_policy;
 	/* 
-	 * The default safe range is 20% to 80% 
-	 * Every sampling_rate, we check
-	 * 	- If current idle time is less than 20%, then we try to 
-	 * 	  increase frequency
-	 * Every sampling_rate*sampling_down_factor, we check
-	 * 	- If current idle time is more than 80%, then we try to
-	 * 	  decrease frequency
+	 * Every sampling_rate, we check, if current idle time is less
+	 * than 20% (default), then we try to increase frequency
+	 * Every sampling_rate*sampling_down_factor, we look for a the lowest
+	 * frequency which can sustain the load while keeping idle time over
+	 * 30%. If such a frequency exist, we try to decrease to this frequency.
 	 *
 	 * Any frequency increase takes it to the maximum frequency. 
 	 * Frequency reduction happens at minimum steps of 
-	 * 5% of max_frequency 
+	 * 5% (default) of current frequency 
 	 */
 
 	/* Check for frequency increase */
-	total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
-		kstat_cpu(cpu).cpustat.iowait;
-	idle_ticks = total_idle_ticks -
-		this_dbs_info->prev_cpu_idle_up;
-	this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
-	
-
+	idle_ticks = UINT_MAX;
 	for_each_cpu_mask(j, policy->cpus) {
-		unsigned int tmp_idle_ticks;
+		unsigned int tmp_idle_ticks, total_idle_ticks;
 		struct cpu_dbs_info_s *j_dbs_info;
 
-		if (j == cpu)
-			continue;
-
 		j_dbs_info = &per_cpu(cpu_dbs_info, j);
-		/* Check for frequency increase */
-		total_idle_ticks = kstat_cpu(j).cpustat.idle +
-			kstat_cpu(j).cpustat.iowait;
+		total_idle_ticks = get_cpu_idle_time(j);
 		tmp_idle_ticks = total_idle_ticks -
 			j_dbs_info->prev_cpu_idle_up;
 		j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
@@ -281,13 +286,23 @@ static void dbs_check_cpu(int cpu)
 	/* Scale idle ticks by 100 and compare with up and down ticks */
 	idle_ticks *= 100;
 	up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
-			sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
 
 	if (idle_ticks < up_idle_ticks) {
+		down_skip[cpu] = 0;
+		for_each_cpu_mask(j, policy->cpus) {
+			struct cpu_dbs_info_s *j_dbs_info;
+
+			j_dbs_info = &per_cpu(cpu_dbs_info, j);
+			j_dbs_info->prev_cpu_idle_down = 
+					j_dbs_info->prev_cpu_idle_up;
+		}
+		/* if we are already at full speed then break out early */
+		if (policy->cur == policy->max)
+			return;
+		
 		__cpufreq_driver_target(policy, policy->max, 
 			CPUFREQ_RELATION_H);
-		down_skip[cpu] = 0;
-		this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
 		return;
 	}
 
@@ -296,23 +311,14 @@ static void dbs_check_cpu(int cpu)
 	if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
 		return;
 
-	total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
-		kstat_cpu(cpu).cpustat.iowait;
-	idle_ticks = total_idle_ticks -
-		this_dbs_info->prev_cpu_idle_down;
-	this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
-
+	idle_ticks = UINT_MAX;
 	for_each_cpu_mask(j, policy->cpus) {
-		unsigned int tmp_idle_ticks;
+		unsigned int tmp_idle_ticks, total_idle_ticks;
 		struct cpu_dbs_info_s *j_dbs_info;
 
-		if (j == cpu)
-			continue;
-
 		j_dbs_info = &per_cpu(cpu_dbs_info, j);
-		/* Check for frequency increase */
-		total_idle_ticks = kstat_cpu(j).cpustat.idle +
-			kstat_cpu(j).cpustat.iowait;
+		/* Check for frequency decrease */
+		total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
 		tmp_idle_ticks = total_idle_ticks -
 			j_dbs_info->prev_cpu_idle_down;
 		j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
@@ -321,38 +327,37 @@ static void dbs_check_cpu(int cpu)
 			idle_ticks = tmp_idle_ticks;
 	}
 
-	/* Scale idle ticks by 100 and compare with up and down ticks */
-	idle_ticks *= 100;
 	down_skip[cpu] = 0;
+	/* if we cannot reduce the frequency anymore, break out early */
+	if (policy->cur == policy->min)
+		return;
 
+	/* Compute how many ticks there are between two measurements */
 	freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
 		dbs_tuners_ins.sampling_down_factor;
-	down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
-			sampling_rate_in_HZ(freq_down_sampling_rate);
+	total_ticks = usecs_to_jiffies(freq_down_sampling_rate);
 
-	if (idle_ticks > down_idle_ticks ) {
-		freq_down_step = (5 * policy->max) / 100;
-
-		/* max freq cannot be less than 100. But who knows.... */
-		if (unlikely(freq_down_step == 0))
-			freq_down_step = 5;
+	/*
+	 * The optimal frequency is the frequency that is the lowest that
+	 * can support the current CPU usage without triggering the up
+	 * policy. To be safe, we focus 10 points under the threshold.
+	 */
+	freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks;
+	freq_next = (freq_next * policy->cur) / 
+			(dbs_tuners_ins.up_threshold - 10);
 
-		__cpufreq_driver_target(policy,
-			policy->cur - freq_down_step, 
-			CPUFREQ_RELATION_H);
-		return;
-	}
+	if (freq_next <= ((policy->cur * 95) / 100))
+		__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
 }
 
 static void do_dbs_timer(void *data)
 { 
 	int i;
 	down(&dbs_sem);
-	for (i = 0; i < NR_CPUS; i++)
-		if (cpu_online(i))
-			dbs_check_cpu(i);
+	for_each_online_cpu(i)
+		dbs_check_cpu(i);
 	schedule_delayed_work(&dbs_work, 
-			sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
 	up(&dbs_sem);
 } 
 
@@ -360,7 +365,7 @@ static inline void dbs_timer_init(void)
 {
 	INIT_WORK(&dbs_work, do_dbs_timer, NULL);
 	schedule_delayed_work(&dbs_work,
-			sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
 	return;
 }
 
@@ -397,12 +402,9 @@ static int cpufreq_governor_dbs(struct c
 			j_dbs_info = &per_cpu(cpu_dbs_info, j);
 			j_dbs_info->cur_policy = policy;
 		
-			j_dbs_info->prev_cpu_idle_up = 
-				kstat_cpu(j).cpustat.idle +
-				kstat_cpu(j).cpustat.iowait;
-			j_dbs_info->prev_cpu_idle_down = 
-				kstat_cpu(j).cpustat.idle +
-				kstat_cpu(j).cpustat.iowait;
+			j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+			j_dbs_info->prev_cpu_idle_down
+				= j_dbs_info->prev_cpu_idle_up;
 		}
 		this_dbs_info->enable = 1;
 		sysfs_create_group(&policy->kobj, &dbs_attr_group);
@@ -422,6 +424,7 @@ static int cpufreq_governor_dbs(struct c
 			def_sampling_rate = (latency / 1000) *
 					DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
 			dbs_tuners_ins.sampling_rate = def_sampling_rate;
+			dbs_tuners_ins.ignore_nice = 0;
 
 			dbs_timer_init();
 		}
@@ -461,12 +464,11 @@ static int cpufreq_governor_dbs(struct c
 	return 0;
 }
 
-struct cpufreq_governor cpufreq_gov_dbs = {
+static struct cpufreq_governor cpufreq_gov_dbs = {
 	.name		= "ondemand",
 	.governor	= cpufreq_governor_dbs,
 	.owner		= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_dbs);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -19,6 +19,7 @@
 #include <linux/percpu.h>
 #include <linux/kobject.h>
 #include <linux/spinlock.h>
+#include <asm/cputime.h>
 
 static spinlock_t cpufreq_stats_lock;
 
@@ -29,20 +30,14 @@ static struct freq_attr _attr_##_name = 
 	.show = _show,\
 };
 
-static unsigned long
-delta_time(unsigned long old, unsigned long new)
-{
-	return (old > new) ? (old - new): (new + ~old + 1);
-}
-
 struct cpufreq_stats {
 	unsigned int cpu;
 	unsigned int total_trans;
-	unsigned long long last_time;
+	unsigned long long  last_time;
 	unsigned int max_state;
 	unsigned int state_num;
 	unsigned int last_index;
-	unsigned long long *time_in_state;
+	cputime64_t *time_in_state;
 	unsigned int *freq_table;
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 	unsigned int *trans_table;
@@ -60,12 +55,16 @@ static int
 cpufreq_stats_update (unsigned int cpu)
 {
 	struct cpufreq_stats *stat;
+	unsigned long long cur_time;
+
+	cur_time = get_jiffies_64();
 	spin_lock(&cpufreq_stats_lock);
 	stat = cpufreq_stats_table[cpu];
 	if (stat->time_in_state)
-		stat->time_in_state[stat->last_index] +=
-			delta_time(stat->last_time, jiffies);
-	stat->last_time = jiffies;
+		stat->time_in_state[stat->last_index] =
+			cputime64_add(stat->time_in_state[stat->last_index],
+				      cputime_sub(cur_time, stat->last_time));
+	stat->last_time = cur_time;
 	spin_unlock(&cpufreq_stats_lock);
 	return 0;
 }
@@ -90,8 +89,8 @@ show_time_in_state(struct cpufreq_policy
 		return 0;
 	cpufreq_stats_update(stat->cpu);
 	for (i = 0; i < stat->state_num; i++) {
-		len += sprintf(buf + len, "%u %llu\n",
-			stat->freq_table[i], stat->time_in_state[i]);
+		len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], 
+			(unsigned long long)cputime64_to_clock_t(stat->time_in_state[i]));
 	}
 	return len;
 }
@@ -107,16 +106,30 @@ show_trans_table(struct cpufreq_policy *
 	if(!stat)
 		return 0;
 	cpufreq_stats_update(stat->cpu);
+	len += snprintf(buf + len, PAGE_SIZE - len, "   From  :    To\n");
+	len += snprintf(buf + len, PAGE_SIZE - len, "         : ");
+	for (i = 0; i < stat->state_num; i++) {
+		if (len >= PAGE_SIZE)
+			break;
+		len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
+				stat->freq_table[i]);
+	}
+	if (len >= PAGE_SIZE)
+		return len;
+
+	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+
 	for (i = 0; i < stat->state_num; i++) {
 		if (len >= PAGE_SIZE)
 			break;
-		len += snprintf(buf + len, PAGE_SIZE - len, "%9u:\t",
+
+		len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
 				stat->freq_table[i]);
 
 		for (j = 0; j < stat->state_num; j++)   {
 			if (len >= PAGE_SIZE)
 				break;
-			len += snprintf(buf + len, PAGE_SIZE - len, "%u\t",
+			len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
 					stat->trans_table[i*stat->max_state+j]);
 		}
 		len += snprintf(buf + len, PAGE_SIZE - len, "\n");
@@ -197,7 +210,7 @@ cpufreq_stats_create_table (struct cpufr
 		count++;
 	}
 
-	alloc_size = count * sizeof(int) + count * sizeof(long long);
+	alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
 
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 	alloc_size += count * count * sizeof(int);
@@ -224,7 +237,7 @@ cpufreq_stats_create_table (struct cpufr
 	}
 	stat->state_num = j;
 	spin_lock(&cpufreq_stats_lock);
-	stat->last_time = jiffies;
+	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
 	spin_unlock(&cpufreq_stats_lock);
 	cpufreq_cpu_put(data);
diff --git a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c
deleted file mode 100644
diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c
--- a/drivers/eisa/pci_eisa.c
+++ b/drivers/eisa/pci_eisa.c
@@ -59,7 +59,8 @@ static struct pci_driver pci_eisa_driver
 
 static int __init pci_eisa_init_module (void)
 {
-	return pci_module_init (&pci_eisa_driver);
+	return pci_register_driver (&pci_eisa_driver);
 }
 
 device_initcall(pci_eisa_init_module);
+MODULE_DEVICE_TABLE(pci, pci_eisa_pci_tbl);
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -106,8 +106,8 @@ static void soc_reset(fc_channel *fc)
 static inline void soc_solicited (struct soc *s)
 {
 	fc_hdr fchdr;
-	soc_rsp *hwrsp;
-	soc_cq *sw_cq;
+	soc_rsp __iomem *hwrsp;
+	soc_cq_rsp *sw_cq;
 	int token;
 	int status;
 	fc_channel *fc;
@@ -115,12 +115,12 @@ static inline void soc_solicited (struct
 	sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q];
 
 	if (sw_cq->pool == NULL)
-		sw_cq->pool = (soc_req *)
+		sw_cq->pool = (soc_req __iomem *)
 			(s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address));
 	sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
 	SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last))
 	for (;;) {
-		hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out;
+		hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out;
 		token = xram_get_32low ((xram_p)&hwrsp->shdr.token);
 		status = xram_get_32low ((xram_p)&hwrsp->status);
 		fc = (fc_channel *)(&s->port[(token >> 11) & 1]);
@@ -185,8 +185,8 @@ static inline void soc_request (struct s
 
 static inline void soc_unsolicited (struct soc *s)
 {
-	soc_rsp *hwrsp, *hwrspc;
-	soc_cq *sw_cq;
+	soc_rsp __iomem *hwrsp, *hwrspc;
+	soc_cq_rsp *sw_cq;
 	int count;
 	int status;
 	int flags;
@@ -194,14 +194,14 @@ static inline void soc_unsolicited (stru
 
 	sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q];
 	if (sw_cq->pool == NULL)
-		sw_cq->pool = (soc_req *)
+		sw_cq->pool = (soc_req __iomem *)
 			(s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address)));
 
 	sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
 	SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last))
 	while (sw_cq->in != sw_cq->out) {
 		/* ...real work per entry here... */
-		hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out;
+		hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out;
 
 		hwrspc = NULL;
 		flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags);
@@ -239,7 +239,7 @@ static inline void soc_unsolicited (stru
 					return;
 			}
 			if (sw_cq->out == sw_cq->last)
-				hwrspc = (soc_rsp *)sw_cq->pool;
+				hwrspc = (soc_rsp __iomem *)sw_cq->pool;
 			else
 				hwrspc = hwrsp + 1;
 		}
@@ -359,7 +359,7 @@ static int soc_hw_enque (fc_channel *fc,
 	soc_port *port = (soc_port *)fc;
 	struct soc *s = port->s;
 	int qno;
-	soc_cq *sw_cq;
+	soc_cq_req *sw_cq;
 	int cq_next_in;
 	soc_req *request;
 	fc_hdr *fch;
diff --git a/drivers/fc4/soc.h b/drivers/fc4/soc.h
--- a/drivers/fc4/soc.h
+++ b/drivers/fc4/soc.h
@@ -261,18 +261,27 @@ typedef struct {
 
 typedef struct {
 	soc_hw_cq		__iomem *hw_cq;	/* Related XRAM cq */
+	soc_req			__iomem *pool;
+	u8			in;
+	u8			out;
+	u8			last;
+	u8			seqno;
+} soc_cq_rsp;
+
+typedef struct {
+	soc_hw_cq		__iomem *hw_cq;	/* Related XRAM cq */
 	soc_req			*pool;
 	u8			in;
 	u8			out;
 	u8			last;
 	u8			seqno;
-} soc_cq;
+} soc_cq_req;
 
 struct soc {
 	spinlock_t		lock;
 	soc_port		port[2]; /* Every SOC has one or two FC ports */
-	soc_cq			req[2]; /* Request CQs */
-	soc_cq			rsp[2]; /* Response CQs */
+	soc_cq_req		req[2]; /* Request CQs */
+	soc_cq_rsp		rsp[2]; /* Response CQs */
 	int			soc_no;
 	void __iomem		*regs;
 	xram_p			xram;
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -665,14 +665,22 @@ efivars_init(void)
 {
 	efi_status_t status = EFI_NOT_FOUND;
 	efi_guid_t vendor_guid;
-	efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
+	efi_char16_t *variable_name;
 	struct subsys_attribute *attr;
 	unsigned long variable_name_size = 1024;
-	int i, rc = 0, error = 0;
+	int i, error = 0;
 
 	if (!efi_enabled)
 		return -ENODEV;
 
+	variable_name = kmalloc(variable_name_size, GFP_KERNEL);
+	if (!variable_name) {
+		printk(KERN_ERR "efivars: Memory allocation failed.\n");
+		return -ENOMEM;
+	}
+
+	memset(variable_name, 0, variable_name_size);
+
 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
 	       EFIVARS_DATE);
 
@@ -680,21 +688,27 @@ efivars_init(void)
 	 * For now we'll register the efi subsys within this driver
 	 */
 
-	rc = firmware_register(&efi_subsys);
+	error = firmware_register(&efi_subsys);
 
-	if (rc)
-		return rc;
+	if (error) {
+		printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
+		goto out_free;
+	}
 
 	kset_set_kset_s(&vars_subsys, efi_subsys);
-	subsystem_register(&vars_subsys);
+
+	error = subsystem_register(&vars_subsys);
+
+	if (error) {
+		printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
+		goto out_firmware_unregister;
+	}
 
 	/*
 	 * Per EFI spec, the maximum storage allocated for both
 	 * the variable name and variable data is 1024 bytes.
 	 */
 
-	memset(variable_name, 0, 1024);
-
 	do {
 		variable_name_size = 1024;
 
@@ -734,8 +748,20 @@ efivars_init(void)
 			error = subsys_create_file(&efi_subsys, attr);
 	}
 
+	if (error)
+		printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
+	else
+		goto out_free;
+
+	subsystem_unregister(&vars_subsys);
+
+out_firmware_unregister:
+	firmware_unregister(&efi_subsys);
+
+out_free:
 	kfree(variable_name);
-	return 0;
+
+	return error;
 }
 
 static void __exit
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/config.h>
 #include <linux/acpi.h>
 #include <linux/console.h>
 #include <linux/efi.h>
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -490,7 +490,7 @@ static int iic_readbytes(struct i2c_adap
  * condition.
  */
 #if 0
-static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 
+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) 
 {
    int i;
    struct i2c_msg *pmsg;
@@ -600,7 +600,7 @@ static inline int iic_doAddress(struct i
  * verify that the bus is not busy or in some unknown state.
  */
 static int iic_xfer(struct i2c_adapter *i2c_adap,
-		    struct i2c_msg msgs[], 
+		    struct i2c_msg *msgs, 
 		    int num)
 {
 	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
@@ -713,14 +713,11 @@ static u32 iic_func(struct i2c_adapter *
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm iic_algo = {
-	"ITE IIC algorithm",
-	I2C_ALGO_IIC,
-	iic_xfer,		/* master_xfer	*/
-	NULL,				/* smbus_xfer	*/
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	iic_func,			/* functionality	*/
+	.name		= "ITE IIC algorithm",
+	.id		= I2C_ALGO_IIC,
+	.master_xfer	= iic_xfer,
+	.algo_control	= algo_control, /* ioctl */
+	.functionality	= iic_func,
 };
 
 
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -178,7 +178,7 @@ static void pca_reset(struct i2c_algo_pc
 }
 
 static int pca_xfer(struct i2c_adapter *i2c_adap,
-                    struct i2c_msg msgs[],
+                    struct i2c_msg *msgs,
                     int num)
 {
         struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
@@ -186,6 +186,7 @@ static int pca_xfer(struct i2c_adapter *
         int curmsg;
 	int numbytes = 0;
 	int state;
+	int ret;
 
 	state = pca_status(adap);
 	if ( state != 0xF8 ) {
@@ -218,6 +219,7 @@ static int pca_xfer(struct i2c_adapter *
 	}
 
 	curmsg = 0;
+	ret = -EREMOTEIO;
 	while (curmsg < num) {
 		state = pca_status(adap);
 
@@ -251,7 +253,7 @@ static int pca_xfer(struct i2c_adapter *
 		case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
 			DEB2("NOT ACK received after SLA+W\n");
 			pca_stop(adap);
-			return -EREMOTEIO;
+			goto out;
 
 		case 0x40: /* SLA+R has been transmitted; ACK has been received */
 			pca_rx_ack(adap, msg->len > 1);
@@ -263,7 +265,7 @@ static int pca_xfer(struct i2c_adapter *
 				numbytes++;
 				pca_rx_ack(adap, numbytes < msg->len - 1);
 				break;
-			} 
+			}
 			curmsg++; numbytes = 0;
 			if (curmsg == num)
 				pca_stop(adap);
@@ -274,15 +276,15 @@ static int pca_xfer(struct i2c_adapter *
 		case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
 			DEB2("NOT ACK received after SLA+R\n");
 			pca_stop(adap);
-			return -EREMOTEIO;
+			goto out;
 
 		case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
 			DEB2("NOT ACK received after data byte\n");
-			return -EREMOTEIO;
+			goto out;
 
 		case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
 			DEB2("Arbitration lost\n");
-			return -EREMOTEIO;
+			goto out;
 			
 		case 0x58: /* Data byte has been received; NOT ACK has been returned */
 			if ( numbytes == msg->len - 1 ) {
@@ -297,21 +299,21 @@ static int pca_xfer(struct i2c_adapter *
 				     "Not final byte. numbytes %d. len %d\n",
 				     numbytes, msg->len);
 				pca_stop(adap);
-				return -EREMOTEIO;
+				goto out;
 			}
 			break;
 		case 0x70: /* Bus error - SDA stuck low */
 			DEB2("BUS ERROR - SDA Stuck low\n");
 			pca_reset(adap);
-			return -EREMOTEIO;
+			goto out;
 		case 0x90: /* Bus error - SCL stuck low */
 			DEB2("BUS ERROR - SCL Stuck low\n");
 			pca_reset(adap);
-			return -EREMOTEIO;
+			goto out;
 		case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
 			DEB2("BUS ERROR - Illegal START or STOP\n");
 			pca_reset(adap);
-			return -EREMOTEIO;
+			goto out;
 		default:
 			printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state);
 			break;
@@ -319,11 +321,13 @@ static int pca_xfer(struct i2c_adapter *
 		
 	}
 
-	DEB1(KERN_CRIT "}}} transfered %d messages. "
+	ret = curmsg;
+ out:
+	DEB1(KERN_CRIT "}}} transfered %d/%d messages. "
 	     "status is %#04x. control is %#04x\n", 
-	     num, pca_status(adap),
+	     curmsg, num, pca_status(adap),
 	     pca_get_con(adap));
-	return curmsg;
+	return ret;
 }
 
 static u32 pca_func(struct i2c_adapter *adap)
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -78,7 +78,6 @@ static void i2c_stop(struct i2c_algo_pcf
 	set_pcf(adap, 1, I2C_PCF_STOP);
 }
 
-
 static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
 
 	int timeout = DEF_TIMEOUT;
@@ -109,6 +108,26 @@ static int wait_for_pin(struct i2c_algo_
 		adap->waitforpin();
 		*status = get_pcf(adap, 1);
 	}
+	if (*status & I2C_PCF_LAB) {
+		DEB2(printk(KERN_INFO 
+			"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+			 *status));
+		/* Cleanup from LAB-- reset and enable ESO.
+		 * This resets the PCF8584; since we've lost the bus, no
+		 * further attempts should be made by callers to clean up 
+		 * (no i2c_stop() etc.)
+		 */
+		set_pcf(adap, 1, I2C_PCF_PIN);
+		set_pcf(adap, 1, I2C_PCF_ESO);
+		/* TODO: we should pause for a time period sufficient for any
+		 * running I2C transaction to complete-- the arbitration
+		 * logic won't work properly until the next START is seen.
+		 */
+		DEB2(printk(KERN_INFO 
+			"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
+			get_pcf(adap,1)));
+		return(-EINTR);
+	}
 #endif
 	if (timeout <= 0)
 		return(-1);
@@ -188,16 +207,22 @@ static inline int try_address(struct i2c
 		       unsigned char addr, int retries)
 {
 	int i, status, ret = -1;
+	int wfp;
 	for (i=0;i<retries;i++) {
 		i2c_outb(adap, addr);
 		i2c_start(adap);
 		status = get_pcf(adap, 1);
-		if (wait_for_pin(adap, &status) >= 0) {
+		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
 			if ((status & I2C_PCF_LRB) == 0) { 
 				i2c_stop(adap);
 				break;	/* success! */
 			}
 		}
+		if (wfp == -EINTR) {
+			/* arbitration lost */
+			udelay(adap->udelay);
+			return -EINTR;
+		}
 		i2c_stop(adap);
 		udelay(adap->udelay);
 	}
@@ -219,6 +244,10 @@ static int pcf_sendbytes(struct i2c_adap
 		i2c_outb(adap, buf[wrcount]);
 		timeout = wait_for_pin(adap, &status);
 		if (timeout) {
+			if (timeout == -EINTR) {
+				/* arbitration lost */
+				return -EINTR;
+			}
 			i2c_stop(adap);
 			dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
 			return -EREMOTEIO; /* got a better one ?? */
@@ -247,11 +276,16 @@ static int pcf_readbytes(struct i2c_adap
 {
 	int i, status;
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+	int wfp;
 
 	/* increment number of bytes to read by one -- read dummy byte */
 	for (i = 0; i <= count; i++) {
 
-		if (wait_for_pin(adap, &status)) {
+		if ((wfp = wait_for_pin(adap, &status))) {
+			if (wfp == -EINTR) {
+				/* arbitration lost */
+				return -EINTR;
+			}
 			i2c_stop(adap);
 			dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
 			return (-1);
@@ -332,7 +366,7 @@ static inline int pcf_doAddress(struct i
 }
 
 static int pcf_xfer(struct i2c_adapter *i2c_adap,
-		    struct i2c_msg msgs[], 
+		    struct i2c_msg *msgs, 
 		    int num)
 {
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
@@ -366,6 +400,10 @@ static int pcf_xfer(struct i2c_adapter *
 		/* Wait for PIN (pending interrupt NOT) */
 		timeout = wait_for_pin(adap, &status);
 		if (timeout) {
+			if (timeout == -EINTR) {
+				/* arbitration lost */
+				return (-EINTR);
+			}
 			i2c_stop(adap);
 			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
 				    "for PIN(1) in pcf_xfer\n");)
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -131,7 +131,7 @@ static int i2c_write(struct i2c_algo_sgi
 	return 0;
 }
 
-static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
 		    int num)
 {
 	struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
--- a/drivers/i2c/algos/i2c-algo-sibyte.c
+++ b/drivers/i2c/algos/i2c-algo-sibyte.c
@@ -136,14 +136,11 @@ static u32 bit_func(struct i2c_adapter *
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm i2c_sibyte_algo = {
-	"SiByte algorithm",
-	I2C_ALGO_SIBYTE,
-	NULL,                           /* master_xfer          */
-	smbus_xfer,                   	/* smbus_xfer           */
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	bit_func,			/* functionality	*/
+	.name		= "SiByte algorithm",
+	.id		= I2C_ALGO_SIBYTE,
+	.smbus_xfer	= smbus_xfer,
+	.algo_control	= algo_control, /* ioctl */
+	.functionality	= bit_func,
 };
 
 /* 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -108,7 +108,7 @@ config I2C_HYDRA
 	  will be called i2c-hydra.
 
 config I2C_I801
-	tristate "Intel 801"
+	tristate "Intel 82801 (ICH)"
 	depends on I2C && PCI && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the Intel
@@ -119,10 +119,11 @@ config I2C_I801
 	    82801BA
 	    82801CA/CAM
 	    82801DB
-	    82801EB
+	    82801EB/ER (ICH5/ICH5R)
 	    6300ESB
 	    ICH6
 	    ICH7
+	    ESB2
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i801.
@@ -143,6 +144,23 @@ config I2C_I810
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i810.
 
+config I2C_PIIX4
+	tristate "Intel PIIX4"
+	depends on I2C && PCI
+	help
+	  If you say yes to this option, support will be included for the Intel
+	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
+	  versions of the chipset are supported:
+	    Intel PIIX4
+	    Intel 440MX
+	    Serverworks OSB4
+	    Serverworks CSB5
+	    Serverworks CSB6
+	    SMSC Victory66
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-piix4.
+
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
 	depends on IBM_OCP && I2C
@@ -219,7 +237,7 @@ config I2C_KEYWEST
 
 config I2C_MPC
 	tristate "MPC107/824x/85xx/52xx"
-	depends on I2C && PPC
+	depends on I2C && PPC32
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -285,23 +303,6 @@ config I2C_PARPORT_LIGHT
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-parport-light.
 
-config I2C_PIIX4
-	tristate "Intel PIIX4"
-	depends on I2C && PCI && EXPERIMENTAL && !64BIT
-	help
-	  If you say yes to this option, support will be included for the Intel
-	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
-	  versions of the chipset are supported:
-	    Intel PIIX4
-	    Intel 440MX
-	    Serverworks OSB4
-	    Serverworks CSB5
-	    Serverworks CSB6
-	    SMSC Victory66
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called i2c-piix4.
-
 config I2C_PROSAVAGE
 	tristate "S3/VIA (Pro)Savage"
 	depends on I2C && PCI && EXPERIMENTAL
@@ -486,4 +487,14 @@ config I2C_PCA_ISA
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-pca-isa.
 
+config I2C_MV64XXX
+	tristate "Marvell mv64xxx I2C Controller"
+	depends on I2C && MV64X60 && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the Marvell 64xxx line of host bridges.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mv64xxx.
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000
 obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
 obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
 obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -2,6 +2,7 @@
  *	i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
  *
  *	Copyright (C) 2004 Patrick Mochel
+ *		      2005 Rudolf Marek <r.marek@sh.cvut.cz>
  *
  *	The 1563 southbridge is deceptively similar to the 1533, with a
  *	few notable exceptions. One of those happens to be the fact they
@@ -57,10 +58,11 @@
 #define HST_CNTL2_BLOCK		0x05
 
 
+#define HST_CNTL2_SIZEMASK	0x38
 
 static unsigned short ali1563_smba;
 
-static int ali1563_transaction(struct i2c_adapter * a)
+static int ali1563_transaction(struct i2c_adapter * a, int size)
 {
 	u32 data;
 	int timeout;
@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2
 
 	data = inb_p(SMB_HST_STS);
 	if (data & HST_STS_BAD) {
-		dev_warn(&a->dev,"ali1563: Trying to reset busy device\n");
+		dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
 		outb_p(data | HST_STS_BAD,SMB_HST_STS);
 		data = inb_p(SMB_HST_STS);
 		if (data & HST_STS_BAD)
@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2
 
 	if (timeout && !(data & HST_STS_BAD))
 		return 0;
-	dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n",
-		timeout ? "Timeout " : "",
-		data & HST_STS_FAIL ? "Transaction Failed " : "",
-		data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
-		data & HST_STS_DEVERR ? "Device Error " : "",
-		!(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
 
-	if (!(data & HST_STS_DONE))
+	if (!timeout) {
+		dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
 		/* Issue 'kill' to host controller */
 		outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
-	else
-		/* Issue timeout to reset all devices on bus */
+		data = inb_p(SMB_HST_STS);
+ 	}
+
+	/* device error - no response, ignore the autodetection case */
+	if ((data & HST_STS_DEVERR) && (size != HST_CNTL2_QUICK)) {
+		dev_err(&a->dev, "Device error!\n");
+	}
+
+	/* bus collision */
+	if (data & HST_STS_BUSERR) {
+		dev_err(&a->dev, "Bus collision!\n");
+		/* Issue timeout, hoping it helps */
 		outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
+	}
+
+	if (data & HST_STS_FAIL) {
+		dev_err(&a->dev, "Cleaning fail after KILL!\n");
+		outb_p(0x0,SMB_HST_CNTL2);
+	}
+
 	return -1;
 }
 
@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2
 
 	if (timeout && !(data & HST_STS_BAD))
 		return 0;
-	dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n",
+	dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
 		timeout ? "Timeout " : "",
 		data & HST_STS_FAIL ? "Transaction Failed " : "",
 		data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
@@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_ada
 	}
 
 	outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
-	outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2);
+	outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
 
 	/* Write the command register */
+
 	switch(size) {
 	case HST_CNTL2_BYTE:
 		if (rw== I2C_SMBUS_WRITE)
-			outb_p(cmd, SMB_HST_CMD);
+			/* Beware it uses DAT0 register and not CMD! */
+			outb_p(cmd, SMB_HST_DAT0);
 		break;
 	case HST_CNTL2_BYTE_DATA:
 		outb_p(cmd, SMB_HST_CMD);
@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_ada
 		goto Done;
 	}
 
-	if ((error = ali1563_transaction(a)))
+	if ((error = ali1563_transaction(a, size)))
 		goto Done;
 
 	if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -253,7 +253,7 @@ i2c_write(struct i2c_au1550_data *adap, 
 }
 
 static int
-au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
 	struct i2c_au1550_data *adap = i2c_adap->algo_data;
 	struct i2c_msg *p;
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -110,22 +110,23 @@ static int pcf_isa_getclock(void *data)
 }
 
 static void pcf_isa_waitforpin(void) {
-
+	DEFINE_WAIT(wait);
 	int timeout = 2;
-	long flags;
+	unsigned long flags;
 
 	if (irq > 0) {
 		spin_lock_irqsave(&lock, flags);
 		if (pcf_pending == 0) {
 			spin_unlock_irqrestore(&lock, flags);
-			if (interruptible_sleep_on_timeout(&pcf_wait,
-								timeout*HZ)) {
+			prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
+			if (schedule_timeout(timeout*HZ)) {
 				spin_lock_irqsave(&lock, flags);
 				if (pcf_pending == 1) {
 					pcf_pending = 0;
 				}
 				spin_unlock_irqrestore(&lock, flags);
 			}
+			finish_wait(&pcf_wait, &wait);
 		} else {
 			pcf_pending = 0;
 			spin_unlock_irqrestore(&lock, flags);
@@ -183,6 +184,7 @@ static struct i2c_algo_pcf_data pcf_isa_
 
 static struct i2c_adapter pcf_isa_ops = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON,
 	.id		= I2C_HW_P_ELEK,
 	.algo_data	= &pcf_isa_data,
 	.name		= "PCF8584 ISA adapter",
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -31,6 +31,7 @@
     6300ESB		25A4
     ICH6		266A
     ICH7		27DA
+    ESB2		269B
     This driver supports several versions of Intel's I/O Controller Hubs (ICH).
     For SMBus support, they are similar to the PIIX4 and are part
     of Intel's '810' and other chipsets.
@@ -558,6 +559,7 @@ static struct pci_device_id i801_ids[] =
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
 	{ 0, }
 };
 
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -549,7 +549,7 @@ static inline int iic_address_neq(const 
  * Generic master transfer entrypoint. 
  * Returns the number of processed messages or error (<0)
  */
-static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
@@ -630,10 +630,6 @@ static struct i2c_algorithm iic_algo = {
 	.name 		= "IBM IIC algorithm",
 	.id   		= I2C_ALGO_OCP,
 	.master_xfer 	= iic_xfer,
-	.smbus_xfer	= NULL,
-	.slave_send	= NULL,
-	.slave_recv	= NULL,
-	.algo_control	= NULL,
 	.functionality	= iic_func
 };
 
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -361,7 +361,7 @@ iop3xx_i2c_handle_msg(struct i2c_adapter
  * master_xfer() - main read/write entry
  */
 static int 
-iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], 
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 
 				int num)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
--- a/drivers/i2c/busses/i2c-ite.c
+++ b/drivers/i2c/busses/i2c-ite.c
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/wait.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -107,7 +108,7 @@ static int iic_ite_getclock(void *data)
  * IIC controller interrupts.
  */
 static void iic_ite_waitforpin(void) {
-
+   DEFINE_WAIT(wait);
    int timeout = 2;
    long flags;
 
@@ -121,13 +122,15 @@ static void iic_ite_waitforpin(void) {
 	spin_lock_irqsave(&lock, flags);
 	if (iic_pending == 0) {
 		spin_unlock_irqrestore(&lock, flags);
-		if (interruptible_sleep_on_timeout(&iic_wait, timeout*HZ)) {
+		prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE);
+		if (schedule_timeout(timeout*HZ)) {
 			spin_lock_irqsave(&lock, flags);
 			if (iic_pending == 1) {
 				iic_pending = 0;
 			}
 			spin_unlock_irqrestore(&lock, flags);
 		}
+		finish_wait(&iic_wait, &wait);
 	} else {
 		iic_pending = 0;
 		spin_unlock_irqrestore(&lock, flags);
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -133,8 +133,8 @@ static int ixp4xx_i2c_probe(struct devic
 	drv_data->algo_data.mdelay = 10;
 	drv_data->algo_data.timeout = 100;
 
-	drv_data->adapter.id = I2C_HW_B_IXP4XX,
-	drv_data->adapter.algo_data = &drv_data->algo_data,
+	drv_data->adapter.id = I2C_HW_B_IXP4XX;
+	drv_data->adapter.algo_data = &drv_data->algo_data;
 
 	drv_data->adapter.dev.parent = &plat_dev->dev;
 
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
--- a/drivers/i2c/busses/i2c-keywest.c
+++ b/drivers/i2c/busses/i2c-keywest.c
@@ -399,7 +399,7 @@ keywest_smbus_xfer(	struct i2c_adapter*	
  */
 static int
 keywest_xfer(	struct i2c_adapter *adap,
-		struct i2c_msg msgs[], 
+		struct i2c_msg *msgs, 
 		int num)
 {
 	struct keywest_chan* chan = i2c_get_adapdata(adap);
@@ -516,6 +516,11 @@ create_iface(struct device_node *np, str
 	u32 *psteps, *prate;
 	int rc;
 
+	if (np->n_intrs < 1 || np->n_addrs < 1) {
+		printk(KERN_ERR "%s: Missing interrupt or address !\n",
+		       np->full_name);
+		return -ENODEV;
+	}
 	if (pmac_low_i2c_lock(np))
 		return -ENODEV;
 
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -55,7 +55,7 @@
 #define CSR_RXAK 0x01
 
 struct mpc_i2c {
-	char *base;
+	void __iomem *base;
 	u32 interrupt;
 	wait_queue_head_t queue;
 	struct i2c_adapter adap;
@@ -233,7 +233,7 @@ static int mpc_read(struct mpc_i2c *i2c,
 	return length;
 }
 
-static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
@@ -444,7 +444,7 @@ static int fsl_i2c_probe(struct device *
 
       fail_add:
 	if (i2c->irq != 0)
-		free_irq(i2c->irq, 0);
+		free_irq(i2c->irq, NULL);
       fail_irq:
 	iounmap(i2c->base);
       fail_map:
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -0,0 +1,598 @@
+/*
+ * drivers/i2c/busses/i2c-mv64xxx.c
+ * 
+ * Driver for the i2c controller on the Marvell line of host bridges for MIPS
+ * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mv643xx.h>
+#include <asm/io.h>
+
+/* Register defines */
+#define	MV64XXX_I2C_REG_SLAVE_ADDR			0x00
+#define	MV64XXX_I2C_REG_DATA				0x04
+#define	MV64XXX_I2C_REG_CONTROL				0x08
+#define	MV64XXX_I2C_REG_STATUS				0x0c
+#define	MV64XXX_I2C_REG_BAUD				0x0c
+#define	MV64XXX_I2C_REG_EXT_SLAVE_ADDR			0x10
+#define	MV64XXX_I2C_REG_SOFT_RESET			0x1c
+
+#define	MV64XXX_I2C_REG_CONTROL_ACK			0x00000004
+#define	MV64XXX_I2C_REG_CONTROL_IFLG			0x00000008
+#define	MV64XXX_I2C_REG_CONTROL_STOP			0x00000010
+#define	MV64XXX_I2C_REG_CONTROL_START			0x00000020
+#define	MV64XXX_I2C_REG_CONTROL_TWSIEN			0x00000040
+#define	MV64XXX_I2C_REG_CONTROL_INTEN			0x00000080
+
+/* Ctlr status values */
+#define	MV64XXX_I2C_STATUS_BUS_ERR			0x00
+#define	MV64XXX_I2C_STATUS_MAST_START			0x08
+#define	MV64XXX_I2C_STATUS_MAST_REPEAT_START		0x10
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK		0x18
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK		0x20
+#define	MV64XXX_I2C_STATUS_MAST_WR_ACK			0x28
+#define	MV64XXX_I2C_STATUS_MAST_WR_NO_ACK		0x30
+#define	MV64XXX_I2C_STATUS_MAST_LOST_ARB		0x38
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK		0x40
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK		0x48
+#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK		0x50
+#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK		0x58
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK		0xd0
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK	0xd8
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK		0xe0
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK	0xe8
+#define	MV64XXX_I2C_STATUS_NO_STATUS			0xf8
+
+/* Driver states */
+enum {
+	MV64XXX_I2C_STATE_INVALID,
+	MV64XXX_I2C_STATE_IDLE,
+	MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
+	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
+	MV64XXX_I2C_STATE_ABORTING,
+};
+
+/* Driver actions */
+enum {
+	MV64XXX_I2C_ACTION_INVALID,
+	MV64XXX_I2C_ACTION_CONTINUE,
+	MV64XXX_I2C_ACTION_SEND_START,
+	MV64XXX_I2C_ACTION_SEND_ADDR_1,
+	MV64XXX_I2C_ACTION_SEND_ADDR_2,
+	MV64XXX_I2C_ACTION_SEND_DATA,
+	MV64XXX_I2C_ACTION_RCV_DATA,
+	MV64XXX_I2C_ACTION_RCV_DATA_STOP,
+	MV64XXX_I2C_ACTION_SEND_STOP,
+};
+
+struct mv64xxx_i2c_data {
+	int			irq;
+	u32			state;
+	u32			action;
+	u32			cntl_bits;
+	void __iomem		*reg_base;
+	u32			reg_base_p;
+	u32			addr1;
+	u32			addr2;
+	u32			bytes_left;
+	u32			byte_posn;
+	u32			block;
+	int			rc;
+	u32			freq_m;
+	u32			freq_n;
+	wait_queue_head_t	waitq;
+	spinlock_t		lock;
+	struct i2c_msg		*msg;
+	struct i2c_adapter	adapter;
+};
+
+/*
+ *****************************************************************************
+ *
+ *	Finite State Machine & Interrupt Routines
+ *
+ *****************************************************************************
+ */
+static void
+mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
+{
+	/*
+	 * If state is idle, then this is likely the remnants of an old
+	 * operation that driver has given up on or the user has killed.
+	 * If so, issue the stop condition and go to idle.
+	 */
+	if (drv_data->state == MV64XXX_I2C_STATE_IDLE) {
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		return;
+	}
+
+	if (drv_data->state == MV64XXX_I2C_STATE_ABORTING) {
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		return;
+	}
+
+	/* The status from the ctlr [mostly] tells us what to do next */
+	switch (status) {
+	/* Start condition interrupt */
+	case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
+	case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+		break;
+
+	/* Performing a write */
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
+		if (drv_data->msg->flags & I2C_M_TEN) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
+	case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
+		if (drv_data->bytes_left > 0) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+			drv_data->bytes_left--;
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		}
+		break;
+
+	/* Performing a read */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
+		if (drv_data->msg->flags & I2C_M_TEN) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
+		if (drv_data->bytes_left == 0) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
+		if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
+			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+		else {
+			drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
+			drv_data->bytes_left--;
+		}
+		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+
+		if (drv_data->bytes_left == 1)
+			drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+		break;
+
+	case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
+		drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		break;
+
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
+	case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
+		/* Doesn't seem to be a device at other end */
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		drv_data->rc = -ENODEV;
+		break;
+
+	default:
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
+			"status: 0x%x, addr: 0x%x, flags: 0x%x\n",
+			 drv_data->state, status, drv_data->msg->addr,
+			 drv_data->msg->flags);
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		drv_data->rc = -EIO;
+	}
+}
+
+static void
+mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
+{
+	switch(drv_data->action) {
+	case MV64XXX_I2C_ACTION_CONTINUE:
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_START:
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_ADDR_1:
+		writel(drv_data->addr1,
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_ADDR_2:
+		writel(drv_data->addr2,
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_DATA:
+		writel(drv_data->msg->buf[drv_data->byte_posn++],
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_RCV_DATA:
+		drv_data->msg->buf[drv_data->byte_posn++] =
+			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
+		drv_data->msg->buf[drv_data->byte_posn++] =
+			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		drv_data->block = 0;
+		wake_up_interruptible(&drv_data->waitq);
+		break;
+
+	case MV64XXX_I2C_ACTION_INVALID:
+	default:
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx_i2c_do_action: Invalid action: %d\n",
+			drv_data->action);
+		drv_data->rc = -EIO;
+		/* FALLTHRU */
+	case MV64XXX_I2C_ACTION_SEND_STOP:
+		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		drv_data->block = 0;
+		wake_up_interruptible(&drv_data->waitq);
+		break;
+	}
+}
+
+static int
+mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mv64xxx_i2c_data	*drv_data = dev_id;
+	unsigned long	flags;
+	u32		status;
+	int		rc = IRQ_NONE;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
+						MV64XXX_I2C_REG_CONTROL_IFLG) {
+		status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
+		mv64xxx_i2c_fsm(drv_data, status);
+		mv64xxx_i2c_do_action(drv_data);
+		rc = IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	return rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ *	I2C Msg Execution Routines
+ *
+ *****************************************************************************
+ */
+static void
+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
+	struct i2c_msg *msg)
+{
+	u32	dir = 0;
+
+	drv_data->msg = msg;
+	drv_data->byte_posn = 0;
+	drv_data->bytes_left = msg->len;
+	drv_data->rc = 0;
+	drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
+		MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+	if (msg->flags & I2C_M_RD)
+		dir = 1;
+
+	if (msg->flags & I2C_M_REV_DIR_ADDR)
+		dir ^= 1;
+
+	if (msg->flags & I2C_M_TEN) {
+		drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
+		drv_data->addr2 = (u32)msg->addr & 0xff;
+	} else {
+		drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
+		drv_data->addr2 = 0;
+	}
+}
+
+static void
+mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
+{
+	long		time_left;
+	unsigned long	flags;
+	char		abort = 0;
+
+	time_left = wait_event_interruptible_timeout(drv_data->waitq,
+		!drv_data->block, msecs_to_jiffies(drv_data->adapter.timeout));
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	if (!time_left) { /* Timed out */
+		drv_data->rc = -ETIMEDOUT;
+		abort = 1;
+	} else if (time_left < 0) { /* Interrupted/Error */
+		drv_data->rc = time_left; /* errno value */
+		abort = 1;
+	}
+
+	if (abort && drv_data->block) {
+		drv_data->state = MV64XXX_I2C_STATE_ABORTING;
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+
+		time_left = wait_event_timeout(drv_data->waitq,
+			!drv_data->block,
+			msecs_to_jiffies(drv_data->adapter.timeout));
+
+		if (time_left <= 0) {
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			dev_err(&drv_data->adapter.dev,
+				"mv64xxx: I2C bus locked\n");
+		}
+	} else
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+static int
+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	mv64xxx_i2c_prepare_for_io(drv_data, msg);
+
+	if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
+		if (drv_data->msg->flags & I2C_M_RD) {
+			/* No action to do, wait for slave to send a byte */
+			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+			drv_data->bytes_left--;
+		}
+	} else {
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+	}
+
+	drv_data->block = 1;
+	mv64xxx_i2c_do_action(drv_data);
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	mv64xxx_i2c_wait_for_completion(drv_data);
+	return drv_data->rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ *	I2C Core Support Routines (Interface to higher level I2C code)
+ *
+ *****************************************************************************
+ */
+static u32
+mv64xxx_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+	int	i, rc = 0;
+
+	for (i=0; i<num; i++)
+		if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0)
+			break;
+
+	return rc;
+}
+
+static struct i2c_algorithm mv64xxx_i2c_algo = {
+	.name = MV64XXX_I2C_CTLR_NAME " algorithm",
+	.id = I2C_ALGO_MV64XXX,
+	.master_xfer = mv64xxx_i2c_xfer,
+	.functionality = mv64xxx_i2c_functionality,
+};
+
+/*
+ *****************************************************************************
+ *
+ *	Driver Interface & Early Init Routines
+ *
+ *****************************************************************************
+ */
+static void __devinit
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+	writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+		drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+	writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+		drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+	drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
+static int __devinit
+mv64xxx_i2c_map_regs(struct platform_device *pd,
+	struct mv64xxx_i2c_data *drv_data)
+{
+	struct resource	*r;
+
+	if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) &&
+		request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE,
+			drv_data->adapter.name)) {
+
+		drv_data->reg_base = ioremap(r->start,
+			MV64XXX_I2C_REG_BLOCK_SIZE);
+		drv_data->reg_base_p = r->start;
+	} else
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __devexit
+mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
+{
+	if (drv_data->reg_base) {
+		iounmap(drv_data->reg_base);
+		release_mem_region(drv_data->reg_base_p,
+			MV64XXX_I2C_REG_BLOCK_SIZE);
+	}
+
+	drv_data->reg_base = NULL;
+	drv_data->reg_base_p = 0;
+}
+
+static int __devinit
+mv64xxx_i2c_probe(struct device *dev)
+{
+	struct platform_device		*pd = to_platform_device(dev);
+	struct mv64xxx_i2c_data		*drv_data;
+	struct mv64xxx_i2c_pdata	*pdata = dev->platform_data;
+	int	rc;
+
+	if ((pd->id != 0) || !pdata)
+		return -ENODEV;
+
+	drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
+
+	if (!drv_data)
+		return -ENOMEM;
+
+	memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data));
+
+	if (mv64xxx_i2c_map_regs(pd, drv_data)) {
+		rc = -ENODEV;
+		goto exit_kfree;
+	}
+
+	strncpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
+		I2C_NAME_SIZE);
+
+	init_waitqueue_head(&drv_data->waitq);
+	spin_lock_init(&drv_data->lock);
+
+	drv_data->freq_m = pdata->freq_m;
+	drv_data->freq_n = pdata->freq_n;
+	drv_data->irq = platform_get_irq(pd, 0);
+	drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX;
+	drv_data->adapter.algo = &mv64xxx_i2c_algo;
+	drv_data->adapter.owner = THIS_MODULE;
+	drv_data->adapter.class = I2C_CLASS_HWMON;
+	drv_data->adapter.timeout = pdata->timeout;
+	drv_data->adapter.retries = pdata->retries;
+	dev_set_drvdata(dev, drv_data);
+	i2c_set_adapdata(&drv_data->adapter, drv_data);
+
+	if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
+		MV64XXX_I2C_CTLR_NAME, drv_data)) {
+
+		dev_err(dev, "mv64xxx: Can't register intr handler "
+			"irq: %d\n", drv_data->irq);
+		rc = -EINVAL;
+		goto exit_unmap_regs;
+	} else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) {
+		dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
+		goto exit_free_irq;
+	}
+
+	mv64xxx_i2c_hw_init(drv_data);
+
+	return 0;
+
+	exit_free_irq:
+		free_irq(drv_data->irq, drv_data);
+	exit_unmap_regs:
+		mv64xxx_i2c_unmap_regs(drv_data);
+	exit_kfree:
+		kfree(drv_data);
+	return rc;
+}
+
+static int __devexit
+mv64xxx_i2c_remove(struct device *dev)
+{
+	struct mv64xxx_i2c_data		*drv_data = dev_get_drvdata(dev);
+	int	rc;
+
+	rc = i2c_del_adapter(&drv_data->adapter);
+	free_irq(drv_data->irq, drv_data);
+	mv64xxx_i2c_unmap_regs(drv_data);
+	kfree(drv_data);
+
+	return rc;
+}
+
+static struct device_driver mv64xxx_i2c_driver = {
+	.name	= MV64XXX_I2C_CTLR_NAME,
+	.bus	= &platform_bus_type,
+	.probe	= mv64xxx_i2c_probe,
+	.remove	= mv64xxx_i2c_remove,
+};
+
+static int __init
+mv64xxx_i2c_init(void)
+{
+	return driver_register(&mv64xxx_i2c_driver);
+}
+
+static void __exit
+mv64xxx_i2c_exit(void)
+{
+	driver_unregister(&mv64xxx_i2c_driver);
+}
+
+module_init(mv64xxx_i2c_init);
+module_exit(mv64xxx_i2c_exit);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -29,9 +29,10 @@
     nForce2 Ultra 400 MCP	0084
     nForce3 Pro150 MCP		00D4
     nForce3 250Gb MCP		00E4
+    nForce4 MCP			0052
 
-    This driver supports the 2 SMBuses that are included in the MCP2 of the
-    nForce2 chipset.
+    This driver supports the 2 SMBuses that are included in the MCP of the
+    nForce2/3/4 chipsets.
 */
 
 /* Note: we assume there can only be one nForce2, with two SMBus interfaces */
@@ -295,6 +296,7 @@ static struct pci_device_id nforce2_ids[
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
 	{ 0 }
 };
 
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1,6 +1,6 @@
 /* linux/drivers/i2c/busses/i2c-s3c2410.c
  *
- * Copyright (C) 2004 Simtec Electronics
+ * Copyright (C) 2004,2005 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 I2C Controller
@@ -188,6 +188,9 @@ static void s3c24xx_i2c_message_start(st
 	} else
 		stat |= S3C2410_IICSTAT_MASTER_TX;
 
+	if (msg->flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+
 	// todo - check for wether ack wanted or not
 	s3c24xx_i2c_enable_ack(i2c);
 
@@ -287,7 +290,7 @@ static int i2s_s3c_irq_nextbyte(struct s
 		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			/* ack was not received... */
 
-			dev_err(i2c->dev, "ack was not received\n" );
+			dev_dbg(i2c->dev, "ack was not received\n");
 			s3c24xx_i2c_stop(i2c, -EREMOTEIO);
 			goto out_ack;
 		}
@@ -483,7 +486,7 @@ static int s3c24xx_i2c_set_master(struct
  * this starts an i2c transfer
 */
 
-static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num)
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num)
 {
 	unsigned long timeout;
 	int ret;
@@ -534,7 +537,7 @@ static int s3c24xx_i2c_doxfer(struct s3c
 */
 
 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[], int num)
+			struct i2c_msg *msgs, int num)
 {
 	struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
 	int retry;
@@ -555,11 +558,18 @@ static int s3c24xx_i2c_xfer(struct i2c_a
 	return -EREMOTEIO;
 }
 
+/* declare our i2c functionality */
+static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
 /* i2c bus registration info */
 
 static struct i2c_algorithm s3c24xx_i2c_algorithm = {
 	.name			= "S3C2410-I2C-Algorithm",
 	.master_xfer		= s3c24xx_i2c_xfer,
+	.functionality		= s3c24xx_i2c_func,
 };
 
 static struct s3c24xx_i2c s3c24xx_i2c = {
@@ -567,8 +577,10 @@ static struct s3c24xx_i2c s3c24xx_i2c = 
 	.wait	= __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
 	.adap	= {
 		.name			= "s3c2410-i2c",
+		.owner			= THIS_MODULE,
 		.algo			= &s3c24xx_i2c_algorithm,
 		.retries		= 2,
+		.class			= I2C_CLASS_HWMON,
 	},
 };
 
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -121,12 +121,12 @@ static int vt596_transaction(void)
 		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
-	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
 		dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
 				"Resetting...\n", temp);
 		
 		outb_p(temp, SMBHSTSTS);
-		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
 			dev_dbg(&vt596_adapter.dev, "Failed! (0x%02x)\n", temp);
 			
 			return -1;
@@ -168,13 +168,14 @@ static int vt596_transaction(void)
 		dev_dbg(&vt596_adapter.dev, "Error: no response!\n");
 	}
 
-	if (inb_p(SMBHSTSTS) != 0x00)
-		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-
-	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_dbg(&vt596_adapter.dev, "Failed reset at end of "
-			"transaction (%02x)\n", temp);
+	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+		outb_p(temp, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+			dev_warn(&vt596_adapter.dev, "Failed reset at end "
+				 "of transaction (%02x)\n", temp);
+		}
 	}
+
 	dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), 
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -63,7 +63,7 @@ config SENSORS_ASB100
 	  will be called asb100.
 
 config SENSORS_DS1621
-      	tristate "Dallas Semiconductor DS1621 and DS1625"
+	tristate "Dallas Semiconductor DS1621 and DS1625"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
 	help
@@ -84,6 +84,17 @@ config SENSORS_FSCHER
 	  This driver can also be built as a module.  If so, the module
 	  will be called fscher.
 
+config SENSORS_FSCPOS
+	tristate "FSC Poseidon"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for Fujitsu Siemens
+	  Computers Poseidon sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called fscpos.
+
 config SENSORS_GL518SM
 	tristate "Genesys Logic GL518SM"
 	depends on I2C && EXPERIMENTAL
@@ -95,6 +106,17 @@ config SENSORS_GL518SM
 	  This driver can also be built as a module.  If so, the module
 	  will be called gl518sm.
 
+config SENSORS_GL520SM
+	tristate "Genesys Logic GL520SM"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for Genesys Logic GL520SM
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gl520sm.
+
 config SENSORS_IT87
 	tristate "ITE IT87xx and compatibles"
 	depends on I2C && EXPERIMENTAL
@@ -211,9 +233,23 @@ config SENSORS_LM90
 	  LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
 	  MAX6658 sensor chips.
 
+	  The Analog Devices ADT7461 sensor chip is also supported, but only
+	  if found in ADM1032 compatibility mode.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm90.
 
+config SENSORS_LM92
+	tristate "National Semiconductor LM92 and compatibles"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for National Semiconductor LM92
+	  and Maxim MAX6635 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm92.
+
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
 	depends on I2C && EXPERIMENTAL
@@ -251,6 +287,18 @@ config SENSORS_SMSC47B397
 	  This driver can also be built as a module.  If so, the module
 	  will be called smsc47b397.
 
+config SENSORS_SIS5595
+	tristate "Silicon Integrated Systems Corp. SiS5595"
+	depends on I2C && PCI && EXPERIMENTAL
+	select I2C_SENSOR
+	select I2C_ISA
+	help
+	  If you say yes here you get support for the integrated sensors in
+	  SiS5595 South Bridges.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sis5595.
+
 config SENSORS_SMSC47M1
 	tristate "SMSC LPC47M10x and compatibles"
 	depends on I2C && EXPERIMENTAL
@@ -304,6 +352,7 @@ config SENSORS_W83627HF
 	tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
+	select I2C_ISA
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
 	  of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
@@ -316,6 +365,17 @@ endmenu
 menu "Other I2C Chip support"
 	depends on I2C
 
+config SENSORS_DS1337
+	tristate "Dallas Semiconductor DS1337 Real Time Clock"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS1337 real-time clock chips. 
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds1337.
+
 config SENSORS_EEPROM
 	tristate "EEPROM reader"
 	depends on I2C && EXPERIMENTAL
@@ -371,4 +431,13 @@ config ISP1301_OMAP
 	  This driver can also be built as a module.  If so, the module
 	  will be called isp1301_omap.
 
+config SENSORS_M41T00
+	tristate "ST M41T00 RTC chip"
+	depends on I2C && PPC32
+	help
+	  If you say yes here you get support for the ST M41T00 RTC chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called m41t00.
+
 endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -11,10 +11,13 @@ obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
 obj-$(CONFIG_SENSORS_ADM1026)	+= adm1026.o
 obj-$(CONFIG_SENSORS_ADM1031)	+= adm1031.o
+obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
 obj-$(CONFIG_SENSORS_FSCHER)	+= fscher.o
+obj-$(CONFIG_SENSORS_FSCPOS)	+= fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
+obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_LM63)	+= lm63.o
 obj-$(CONFIG_SENSORS_LM75)	+= lm75.o
@@ -25,11 +28,14 @@ obj-$(CONFIG_SENSORS_LM83)	+= lm83.o
 obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
 obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
+obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
+obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
 obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
+obj-$(CONFIG_SENSORS_SIS5595)	+= sis5595.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47m1.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
--- a/drivers/i2c/chips/adm1021.c
+++ b/drivers/i2c/chips/adm1021.c
@@ -23,22 +23,11 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
 
-/* Registers */
-#define ADM1021_SYSCTL_TEMP		1200
-#define ADM1021_SYSCTL_REMOTE_TEMP	1201
-#define ADM1021_SYSCTL_DIE_CODE		1202
-#define ADM1021_SYSCTL_ALARMS		1203
-
-#define ADM1021_ALARM_TEMP_HIGH		0x40
-#define ADM1021_ALARM_TEMP_LOW		0x20
-#define ADM1021_ALARM_RTEMP_HIGH	0x10
-#define ADM1021_ALARM_RTEMP_LOW		0x08
-#define ADM1021_ALARM_RTEMP_NA		0x04
-
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
 					0x29, 0x2a, 0x2b,
@@ -147,8 +136,6 @@ static struct i2c_driver adm1021_driver 
 	.detach_client	= adm1021_detach_client,
 };
 
-static int adm1021_id;
-
 #define show(value)	\
 static ssize_t show_##value(struct device *dev, char *buf)		\
 {									\
@@ -178,8 +165,10 @@ static ssize_t set_##value(struct device
 	struct adm1021_data *data = i2c_get_clientdata(client);	\
 	int temp = simple_strtoul(buf, NULL, 10);		\
 								\
+	down(&data->update_lock);				\
 	data->value = TEMP_TO_REG(temp);			\
 	adm1021_write_value(client, reg, data->value);		\
+	up(&data->update_lock);					\
 	return count;						\
 }
 set(temp_max, ADM1021_REG_TOS_W);
@@ -299,8 +288,6 @@ static int adm1021_detect(struct i2c_ada
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 	data->type = kind;
-
-	new_client->id = adm1021_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -373,8 +360,8 @@ static struct adm1021_data *adm1021_upda
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		dev_dbg(&client->dev, "Starting adm1021 update\n");
 
 		data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP);
@@ -383,7 +370,7 @@ static struct adm1021_data *adm1021_upda
 		data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
 		data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
 		data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
-		data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec;
+		data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
 		if (data->type == adm1021)
 			data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE);
 		if (data->type == adm1023) {
diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c
--- a/drivers/i2c/chips/adm1025.c
+++ b/drivers/i2c/chips/adm1025.c
@@ -49,6 +49,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -148,12 +149,6 @@ struct adm1025_data {
 };
 
 /*
- * Internal variables
- */
-
-static int adm1025_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -211,9 +206,12 @@ static ssize_t set_in##offset##_min(stru
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
 				  data->in_min[offset]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
@@ -222,9 +220,12 @@ static ssize_t set_in##offset##_max(stru
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
 				  data->in_max[offset]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
@@ -245,9 +246,12 @@ static ssize_t set_temp##offset##_min(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->temp_min[offset-1] = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
 				  data->temp_min[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
@@ -256,9 +260,12 @@ static ssize_t set_temp##offset##_max(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->temp_max[offset-1] = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
 				  data->temp_max[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
@@ -397,7 +404,6 @@ static int adm1025_detect(struct i2c_ada
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-	new_client->id = adm1025_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -512,9 +518,7 @@ static struct adm1025_data *adm1025_upda
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ * 2) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		int i;
 
 		dev_dbg(&client->dev, "Updating data.\n");
diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c
--- a/drivers/i2c/chips/adm1026.c
+++ b/drivers/i2c/chips/adm1026.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -313,8 +314,6 @@ static struct i2c_driver adm1026_driver 
 	.detach_client  = adm1026_detach_client,
 };
 
-static int adm1026_id;
-
 int adm1026_attach_adapter(struct i2c_adapter *adapter)
 {
 	if (!(adapter->class & I2C_CLASS_HWMON)) {
@@ -363,49 +362,47 @@ void adm1026_init_client(struct i2c_clie
 	int value, i;
 	struct adm1026_data *data = i2c_get_clientdata(client);
 
-        dev_dbg(&client->dev,"(%d): Initializing device\n", client->id);
+        dev_dbg(&client->dev, "Initializing device\n");
 	/* Read chip config */
 	data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
 	data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
 	data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
 
 	/* Inform user of chip config */
-	dev_dbg(&client->dev, "(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n",
-		client->id, data->config1);
+	dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
+		data->config1);
 	if ((data->config1 & CFG1_MONITOR) == 0) {
-		dev_dbg(&client->dev, "(%d): Monitoring not currently "
-			"enabled.\n", client->id);
+		dev_dbg(&client->dev, "Monitoring not currently "
+			"enabled.\n");
 	}
 	if (data->config1 & CFG1_INT_ENABLE) {
-		dev_dbg(&client->dev, "(%d): SMBALERT interrupts are "
-			"enabled.\n", client->id);
+		dev_dbg(&client->dev, "SMBALERT interrupts are "
+			"enabled.\n");
 	}
 	if (data->config1 & CFG1_AIN8_9) {
-		dev_dbg(&client->dev, "(%d): in8 and in9 enabled. "
-			"temp3 disabled.\n", client->id);
+		dev_dbg(&client->dev, "in8 and in9 enabled. "
+			"temp3 disabled.\n");
 	} else {
-		dev_dbg(&client->dev, "(%d): temp3 enabled.  in8 and "
-			"in9 disabled.\n", client->id);
+		dev_dbg(&client->dev, "temp3 enabled.  in8 and "
+			"in9 disabled.\n");
 	}
 	if (data->config1 & CFG1_THERM_HOT) {
-		dev_dbg(&client->dev, "(%d): Automatic THERM, PWM, "
-			"and temp limits enabled.\n", client->id);
+		dev_dbg(&client->dev, "Automatic THERM, PWM, "
+			"and temp limits enabled.\n");
 	}
 
 	value = data->config3;
 	if (data->config3 & CFG3_GPIO16_ENABLE) {
-		dev_dbg(&client->dev, "(%d): GPIO16 enabled.  THERM"
-			"pin disabled.\n", client->id);
+		dev_dbg(&client->dev, "GPIO16 enabled.  THERM"
+			"pin disabled.\n");
 	} else {
-		dev_dbg(&client->dev, "(%d): THERM pin enabled.  "
-			"GPIO16 disabled.\n", client->id);
+		dev_dbg(&client->dev, "THERM pin enabled.  "
+			"GPIO16 disabled.\n");
 	}
 	if (data->config3 & CFG3_VREF_250) {
-		dev_dbg(&client->dev, "(%d): Vref is 2.50 Volts.\n",
-			client->id);
+		dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
 	} else {
-		dev_dbg(&client->dev, "(%d): Vref is 1.82 Volts.\n",
-			client->id);
+		dev_dbg(&client->dev, "Vref is 1.82 Volts.\n");
 	}
 	/* Read and pick apart the existing GPIO configuration */
 	value = 0;
@@ -423,12 +420,11 @@ void adm1026_init_client(struct i2c_clie
 	adm1026_print_gpio(client);
 
 	/* If the user asks us to reprogram the GPIO config, then
-	 *   do it now.  But only if this is the first ADM1026.
+	 * do it now.
 	 */
-	if (client->id == 0
-	    && (gpio_input[0] != -1 || gpio_output[0] != -1
+	if (gpio_input[0] != -1 || gpio_output[0] != -1
 		|| gpio_inverted[0] != -1 || gpio_normal[0] != -1
-		|| gpio_fan[0] != -1)) {
+		|| gpio_fan[0] != -1) {
 		adm1026_fixup_gpio(client);
 	}
 
@@ -448,8 +444,7 @@ void adm1026_init_client(struct i2c_clie
 	value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
 	/* Set MONITOR, clear interrupt acknowledge and s/w reset */
 	value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET);
-	dev_dbg(&client->dev, "(%d): Setting CONFIG to: 0x%02x\n",
-		client->id, value);
+	dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value);
 	data->config1 = value;
 	adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
 
@@ -467,31 +462,30 @@ void adm1026_print_gpio(struct i2c_clien
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int  i;
 
-	dev_dbg(&client->dev, "(%d): GPIO config is:", client->id);
+	dev_dbg(&client->dev, "GPIO config is:");
 	for (i = 0;i <= 7;++i) {
 		if (data->config2 & (1 << i)) {
-			dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id,
+			dev_dbg(&client->dev, "\t%sGP%s%d\n",
 				data->gpio_config[i] & 0x02 ? "" : "!",
 				data->gpio_config[i] & 0x01 ? "OUT" : "IN",
 				i);
 		} else {
-			dev_dbg(&client->dev, "\t(%d): FAN%d\n",
-				client->id, i);
+			dev_dbg(&client->dev, "\tFAN%d\n", i);
 		}
 	}
 	for (i = 8;i <= 15;++i) {
-		dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id,
+		dev_dbg(&client->dev, "\t%sGP%s%d\n",
 			data->gpio_config[i] & 0x02 ? "" : "!",
 			data->gpio_config[i] & 0x01 ? "OUT" : "IN",
 			i);
 	}
 	if (data->config3 & CFG3_GPIO16_ENABLE) {
-		dev_dbg(&client->dev, "\t(%d): %sGP%s16\n", client->id,
+		dev_dbg(&client->dev, "\t%sGP%s16\n",
 			data->gpio_config[16] & 0x02 ? "" : "!",
 			data->gpio_config[16] & 0x01 ? "OUT" : "IN");
 	} else {
 		/* GPIO16 is THERM  */
-		dev_dbg(&client->dev, "\t(%d): THERM\n", client->id);
+		dev_dbg(&client->dev, "\tTHERM\n");
 	}
 }
 
@@ -580,10 +574,9 @@ static struct adm1026_data *adm1026_upda
 
 	down(&data->update_lock);
 	if (!data->valid
-	    || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL)) {
+	    || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) {
 		/* Things that change quickly */
-		dev_dbg(&client->dev,"(%d): Reading sensor values\n", 
-			client->id);
+		dev_dbg(&client->dev,"Reading sensor values\n");
 		for (i = 0;i <= 16;++i) {
 			data->in[i] =
 			    adm1026_read_value(client, ADM1026_REG_IN[i]);
@@ -628,11 +621,10 @@ static struct adm1026_data *adm1026_upda
 		data->last_reading = jiffies;
 	};  /* last_reading */
 
-	if (!data->valid || (jiffies - data->last_config > 
-		ADM1026_CONFIG_INTERVAL)) {
+	if (!data->valid ||
+	    time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) {
 		/* Things that don't change often */
-		dev_dbg(&client->dev, "(%d): Reading config values\n", 
-			client->id);
+		dev_dbg(&client->dev, "Reading config values\n");
 		for (i = 0;i <= 16;++i) {
 			data->in_min[i] = adm1026_read_value(client, 
 				ADM1026_REG_IN_MIN[i]);
@@ -712,8 +704,7 @@ static struct adm1026_data *adm1026_upda
 		data->last_config = jiffies;
 	};  /* last_config */
 
-	dev_dbg(&client->dev, "(%d): Setting VID from GPIO11-15.\n", 
-		client->id);
+	dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n");
 	data->vid = (data->gpio >> 11) & 0x1f;
 	data->valid = 1;
 	up(&data->update_lock);
@@ -735,10 +726,9 @@ static ssize_t set_in_min(struct device 
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_min[nr] = INS_TO_REG(nr, val);
 	adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]);
 	up(&data->update_lock);
@@ -754,10 +744,9 @@ static ssize_t set_in_max(struct device 
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_max[nr] = INS_TO_REG(nr, val);
 	adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]);
 	up(&data->update_lock);
@@ -827,10 +816,9 @@ static ssize_t set_in16_min(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
 	adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
 	up(&data->update_lock);
@@ -846,10 +834,9 @@ static ssize_t set_in16_max(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
 	adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]);
 	up(&data->update_lock);
@@ -882,10 +869,9 @@ static ssize_t set_fan_min(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]);
 	adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr),
 		data->fan_min[nr]);
@@ -1018,10 +1004,9 @@ static ssize_t set_temp_min(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr],
 		data->temp_min[nr]);
@@ -1038,10 +1023,9 @@ static ssize_t set_temp_max(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr],
 		data->temp_max[nr]);
@@ -1092,10 +1076,9 @@ static ssize_t set_temp_offset(struct de
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_offset[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr],
 		data->temp_offset[nr]);
@@ -1145,10 +1128,9 @@ static ssize_t set_temp_auto_point1_temp
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_tmin[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr],
 		data->temp_tmin[nr]);
@@ -1199,9 +1181,8 @@ static ssize_t set_temp_crit_enable(stru
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
-	val = simple_strtol(buf, NULL, 10);
 	if ((val == 1) || (val==0)) {
 		down(&data->update_lock);
 		data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
@@ -1232,10 +1213,9 @@ static ssize_t set_temp_crit(struct devi
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_crit[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr],
 		data->temp_crit[nr]);
@@ -1270,10 +1250,9 @@ static ssize_t set_analog_out_reg(struct
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->analog_out = DAC_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out);
 	up(&data->update_lock);
@@ -1326,11 +1305,10 @@ static ssize_t set_alarm_mask(struct dev
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 	unsigned long mask;
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->alarm_mask = val & 0x7fffffff;
 	mask = data->alarm_mask
 		| (data->gpio_mask & 0x10000 ? 0x80000000 : 0);
@@ -1363,11 +1341,10 @@ static ssize_t set_gpio(struct device *d
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 	long   gpio;
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->gpio = val & 0x1ffff;
 	gpio = data->gpio;
 	adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff);
@@ -1392,11 +1369,10 @@ static ssize_t set_gpio_mask(struct devi
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 	long   mask;
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->gpio_mask = val & 0x1ffff;
 	mask = data->gpio_mask;
 	adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff);
@@ -1420,11 +1396,11 @@ static ssize_t set_pwm_reg(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
 
 	if (data->pwm1.enable == 1) {
+		int val = simple_strtol(buf, NULL, 10);
+
 		down(&data->update_lock);
-		val = simple_strtol(buf, NULL, 10);
 		data->pwm1.pwm = PWM_TO_REG(val);
 		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
 		up(&data->update_lock);
@@ -1441,10 +1417,9 @@ static ssize_t set_auto_pwm_min(struct d
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255);
 	if (data->pwm1.enable == 2) { /* apply immediately */
 		data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
@@ -1468,10 +1443,9 @@ static ssize_t set_pwm_enable(struct dev
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int     val;
+	int val = simple_strtol(buf, NULL, 10);
 	int     old_enable;
 
-	val = simple_strtol(buf, NULL, 10);
 	if ((val >= 0) && (val < 3)) {
 		down(&data->update_lock);
 		old_enable = data->pwm1.enable;
@@ -1608,16 +1582,10 @@ int adm1026_detect(struct i2c_adapter *a
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 
 	/* Fill in the remaining client fields */
-	new_client->id = adm1026_id++;
 	data->type = kind;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
-	dev_dbg(&new_client->dev, "(%d): Assigning ID %d to %s at %d,0x%02x\n",
-		new_client->id, new_client->id, new_client->name,
-		i2c_adapter_id(new_client->adapter),
-		new_client->addr);
-
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
 		goto exitfree;
diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c
--- a/drivers/i2c/chips/adm1031.c
+++ b/drivers/i2c/chips/adm1031.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -110,8 +111,6 @@ static struct i2c_driver adm1031_driver 
 	.detach_client = adm1031_detach_client,
 };
 
-static int adm1031_id;
-
 static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
 {
 	return i2c_smbus_read_byte_data(client, reg);
@@ -255,7 +254,7 @@ set_fan_auto_channel(struct device *dev,
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 	u8 reg;
 	int ret;
 	u8 old_fan_mode;
@@ -263,7 +262,6 @@ set_fan_auto_channel(struct device *dev,
 	old_fan_mode = data->conf1;
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	
 	if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg))) {
 		up(&data->update_lock);
@@ -328,10 +326,9 @@ set_auto_temp_min(struct device *dev, co
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
 			    data->auto_temp[nr]);
@@ -349,10 +346,9 @@ set_auto_temp_max(struct device *dev, co
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]);
 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
 			    data->temp_max[nr]);
@@ -405,10 +401,10 @@ set_pwm(struct device *dev, const char *
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 	int reg;
+
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && 
 	    (((val>>4) & 0xf) != 5)) {
 		/* In automatic mode, the only PWM accepted is 33% */
@@ -512,10 +508,9 @@ set_fan_min(struct device *dev, const ch
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	if (val) {
 		data->fan_min[nr] = 
 			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
@@ -531,12 +526,11 @@ set_fan_div(struct device *dev, const ch
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1031_data *data = i2c_get_clientdata(client);
-	int val;
+	int val = simple_strtol(buf, NULL, 10);
 	u8 tmp;
-	int old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
+	int old_div;
 	int new_min;
 
-	val = simple_strtol(buf, NULL, 10);
 	tmp = val == 8 ? 0xc0 :
 	      val == 4 ? 0x80 :
 	      val == 2 ? 0x40 :	
@@ -544,7 +538,9 @@ set_fan_div(struct device *dev, const ch
 	      0xff;
 	if (tmp == 0xff)
 		return -EINVAL;
+	
 	down(&data->update_lock);
+	old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
 	data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]);
 	new_min = data->fan_min[nr] * old_div / 
 		FAN_DIV_FROM_REG(data->fan_div[nr]);
@@ -781,8 +777,6 @@ static int adm1031_detect(struct i2c_ada
 	data->chip_type = kind;
 
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	new_client->id = adm1031_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -888,8 +882,8 @@ static struct adm1031_data *adm1031_upda
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 
 		dev_dbg(&client->dev, "Starting adm1031 update\n");
 		for (chan = 0;
diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c
--- a/drivers/i2c/chips/asb100.c
+++ b/drivers/i2c/chips/asb100.c
@@ -36,17 +36,12 @@
     asb100	7	3	1	4	0x31	0x0694	yes	no
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
 #include <linux/init.h>
-#include <asm/errno.h>
-#include <asm/io.h>
 #include "lm75.h"
 
 /*
@@ -251,9 +246,12 @@ static ssize_t set_in_##reg(struct devic
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct asb100_data *data = i2c_get_clientdata(client); \
 	unsigned long val = simple_strtoul(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
 		data->in_##reg[nr]); \
+	up(&data->update_lock); \
 	return count; \
 }
 
@@ -334,8 +332,11 @@ static ssize_t set_fan_min(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct asb100_data *data = i2c_get_clientdata(client);
 	u32 val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -348,11 +349,14 @@ static ssize_t set_fan_div(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct asb100_data *data = i2c_get_clientdata(client);
-	unsigned long min = FAN_FROM_REG(data->fan_min[nr],
-			DIV_FROM_REG(data->fan_div[nr]));
+	unsigned long min;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int reg;
 	
+	down(&data->update_lock);
+
+	min = FAN_FROM_REG(data->fan_min[nr],
+			DIV_FROM_REG(data->fan_div[nr]));
 	data->fan_div[nr] = DIV_TO_REG(val);
 
 	switch(nr) {
@@ -378,6 +382,9 @@ static ssize_t set_fan_div(struct device
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
+
+	up(&data->update_lock);
+
 	return count;
 }
 
@@ -455,6 +462,8 @@ static ssize_t set_##reg(struct device *
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct asb100_data *data = i2c_get_clientdata(client); \
 	unsigned long val = simple_strtoul(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	switch (nr) { \
 	case 1: case 2: \
 		data->reg[nr] = LM75_TEMP_TO_REG(val); \
@@ -465,6 +474,7 @@ static ssize_t set_##reg(struct device *
 	} \
 	asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \
 			data->reg[nr]); \
+	up(&data->update_lock); \
 	return count; \
 }
 
@@ -565,9 +575,12 @@ static ssize_t set_pwm1(struct device *d
 	struct i2c_client *client = to_i2c_client(dev);
 	struct asb100_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->pwm &= 0x80; /* keep the enable bit */
 	data->pwm |= (0x0f & ASB100_PWM_TO_REG(val));
 	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -583,9 +596,12 @@ static ssize_t set_pwm_enable1(struct de
 	struct i2c_client *client = to_i2c_client(dev);
 	struct asb100_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->pwm &= 0x0f; /* keep the duty cycle bits */
 	data->pwm |= (val ? 0x80 : 0x00);
 	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -970,8 +986,8 @@ static struct asb100_data *asb100_update
 
 	down(&data->update_lock);
 
-	if (time_after(jiffies - data->last_updated, (unsigned long)(HZ+HZ/2))
-		|| time_before(jiffies, data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
 
 		dev_dbg(&client->dev, "starting device update...\n");
 
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/ds1337.c
@@ -0,0 +1,402 @@
+/*
+ *  linux/drivers/i2c/chips/ds1337.c
+ *
+ *  Copyright (C) 2005 James Chapman <jchapman@katalix.com>
+ *
+ *	based on linux/drivers/acron/char/pcf8583.c
+ *  Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ * Driver for Dallas Semiconductor DS1337 real time clock chip
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/string.h>
+#include <linux/rtc.h>		/* get the user-level API */
+#include <linux/bcd.h>
+#include <linux/list.h>
+
+/* Device registers */
+#define DS1337_REG_HOUR		2
+#define DS1337_REG_DAY		3
+#define DS1337_REG_DATE		4
+#define DS1337_REG_MONTH	5
+#define DS1337_REG_CONTROL	14
+#define DS1337_REG_STATUS	15
+
+/* FIXME - how do we export these interface constants? */
+#define DS1337_GET_DATE		0
+#define DS1337_SET_DATE		1
+
+/*
+ * Functions declaration
+ */
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+SENSORS_INSMOD_1(ds1337);
+
+static int ds1337_attach_adapter(struct i2c_adapter *adapter);
+static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
+static void ds1337_init_client(struct i2c_client *client);
+static int ds1337_detach_client(struct i2c_client *client);
+static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg);
+
+/*
+ * Driver data (common to all clients)
+ */
+static struct i2c_driver ds1337_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "ds1337",
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= ds1337_attach_adapter,
+	.detach_client	= ds1337_detach_client,
+	.command	= ds1337_command,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+struct ds1337_data {
+	struct i2c_client client;
+	struct list_head list;
+	int id;
+};
+
+/*
+ * Internal variables
+ */
+static int ds1337_id;
+static LIST_HEAD(ds1337_clients);
+
+static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
+{
+	s32 tmp = i2c_smbus_read_byte_data(client, reg);
+
+	if (tmp < 0)
+		return -EIO;
+
+	*value = tmp;
+
+	return 0;
+}
+
+/*
+ * Chip access functions
+ */
+static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+	struct ds1337_data *data = i2c_get_clientdata(client);
+	int result;
+	u8 buf[7];
+	u8 val;
+	struct i2c_msg msg[2];
+	u8 offs = 0;
+
+	if (!dt) {
+		dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
+			__FUNCTION__);
+
+		return -EINVAL;
+	}
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &offs;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = sizeof(buf);
+	msg[1].buf = &buf[0];
+
+	result = client->adapter->algo->master_xfer(client->adapter,
+						    &msg[0], 2);
+
+	dev_dbg(&client->adapter->dev,
+		"%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
+		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6]);
+
+	if (result >= 0) {
+		dt->tm_sec = BCD_TO_BIN(buf[0]);
+		dt->tm_min = BCD_TO_BIN(buf[1]);
+		val = buf[2] & 0x3f;
+		dt->tm_hour = BCD_TO_BIN(val);
+		dt->tm_wday = BCD_TO_BIN(buf[3]) - 1;
+		dt->tm_mday = BCD_TO_BIN(buf[4]);
+		val = buf[5] & 0x7f;
+		dt->tm_mon = BCD_TO_BIN(val);
+		dt->tm_year = 1900 + BCD_TO_BIN(buf[6]);
+		if (buf[5] & 0x80)
+			dt->tm_year += 100;
+
+		dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, "
+			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+			__FUNCTION__, dt->tm_sec, dt->tm_min,
+			dt->tm_hour, dt->tm_mday,
+			dt->tm_mon, dt->tm_year, dt->tm_wday);
+	} else {
+		dev_err(&client->adapter->dev, "ds1337[%d]: error reading "
+			"data! %d\n", data->id, result);
+		result = -EIO;
+	}
+
+	return result;
+}
+
+static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+	struct ds1337_data *data = i2c_get_clientdata(client);
+	int result;
+	u8 buf[8];
+	u8 val;
+	struct i2c_msg msg[1];
+
+	if (!dt) {
+		dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
+			__FUNCTION__);
+
+		return -EINVAL;
+	}
+
+	dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
+		dt->tm_sec, dt->tm_min, dt->tm_hour,
+		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+	buf[0] = 0;		/* reg offset */
+	buf[1] = BIN_TO_BCD(dt->tm_sec);
+	buf[2] = BIN_TO_BCD(dt->tm_min);
+	buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6);
+	buf[4] = BIN_TO_BCD(dt->tm_wday) + 1;
+	buf[5] = BIN_TO_BCD(dt->tm_mday);
+	buf[6] = BIN_TO_BCD(dt->tm_mon);
+	if (dt->tm_year >= 2000) {
+		val = dt->tm_year - 2000;
+		buf[6] |= (1 << 7);
+	} else {
+		val = dt->tm_year - 1900;
+	}
+	buf[7] = BIN_TO_BCD(val);
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = sizeof(buf);
+	msg[0].buf = &buf[0];
+
+	result = client->adapter->algo->master_xfer(client->adapter,
+						    &msg[0], 1);
+	if (result < 0) {
+		dev_err(&client->adapter->dev, "ds1337[%d]: error "
+			"writing data! %d\n", data->id, result);
+		result = -EIO;
+	} else {
+		result = 0;
+	}
+
+	return result;
+}
+
+static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg)
+{
+	dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
+
+	switch (cmd) {
+	case DS1337_GET_DATE:
+		return ds1337_get_datetime(client, arg);
+
+	case DS1337_SET_DATE:
+		return ds1337_set_datetime(client, arg);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * Public API for access to specific device. Useful for low-level
+ * RTC access from kernel code.
+ */
+int ds1337_do_command(int id, int cmd, void *arg)
+{
+	struct list_head *walk;
+	struct list_head *tmp;
+	struct ds1337_data *data;
+
+	list_for_each_safe(walk, tmp, &ds1337_clients) {
+		data = list_entry(walk, struct ds1337_data, list);
+		if (data->id == id)
+			return ds1337_command(&data->client, cmd, arg);
+	}
+
+	return -ENODEV;
+}
+
+static int ds1337_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, ds1337_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct ds1337_data *data;
+	int err = 0;
+	const char *name = "";
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_I2C))
+		goto exit;
+
+	if (!(data = kmalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct ds1337_data));
+	INIT_LIST_HEAD(&data->list);
+
+	/* The common I2C client data is placed right before the
+	 * DS1337-specific data. 
+	 */
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &ds1337_driver;
+	new_client->flags = 0;
+
+	/*
+	 * Now we do the remaining detection. A negative kind means that
+	 * the driver was loaded with no force parameter (default), so we
+	 * must both detect and identify the chip. A zero kind means that
+	 * the driver was loaded with the force parameter, the detection
+	 * step shall be skipped. A positive kind means that the driver
+	 * was loaded with the force parameter and a given kind of chip is
+	 * requested, so both the detection and the identification steps
+	 * are skipped.
+	 *
+	 * For detection, we read registers that are most likely to cause
+	 * detection failure, i.e. those that have more bits with fixed
+	 * or reserved values.
+	 */
+
+	/* Default to an DS1337 if forced */
+	if (kind == 0)
+		kind = ds1337;
+
+	if (kind < 0) {		/* detection and identification */
+		u8 data;
+
+		/* Check that status register bits 6-2 are zero */
+		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
+		    (data & 0x7c))
+			goto exit_free;
+
+		/* Check for a valid day register value */
+		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
+		    (data == 0) || (data & 0xf8))
+			goto exit_free;
+
+		/* Check for a valid date register value */
+		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
+		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
+		    (data >= 0x32))
+			goto exit_free;
+
+		/* Check for a valid month register value */
+		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
+		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
+		    ((data >= 0x13) && (data <= 0x19)))
+			goto exit_free;
+
+		/* Check that control register bits 6-5 are zero */
+		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
+		    (data & 0x60))
+			goto exit_free;
+
+		kind = ds1337;
+	}
+
+	if (kind == ds1337)
+		name = "ds1337";
+
+	/* We can fill in the remaining client fields */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the DS1337 chip */
+	ds1337_init_client(new_client);
+
+	/* Add client to local list */
+	data->id = ds1337_id++;
+	list_add(&data->list, &ds1337_clients);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static void ds1337_init_client(struct i2c_client *client)
+{
+	s32 val;
+
+	/* Ensure that device is set in 24-hour mode */
+	val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
+	if ((val >= 0) && (val & (1 << 6)) == 0)
+		i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
+					  val | (1 << 6));
+}
+
+static int ds1337_detach_client(struct i2c_client *client)
+{
+	int err;
+	struct ds1337_data *data = i2c_get_clientdata(client);
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	list_del(&data->list);
+	kfree(data);
+	return 0;
+}
+
+static int __init ds1337_init(void)
+{
+	return i2c_add_driver(&ds1337_driver);
+}
+
+static void __exit ds1337_exit(void)
+{
+	i2c_del_driver(&ds1337_driver);
+}
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("DS1337 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds1337_init);
+module_exit(ds1337_exit);
diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c
--- a/drivers/i2c/chips/ds1621.c
+++ b/drivers/i2c/chips/ds1621.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include "lm75.h"
@@ -95,8 +96,6 @@ static struct i2c_driver ds1621_driver =
 	.detach_client	= ds1621_detach_client,
 };
 
-static int ds1621_id;
-
 /* All registers are word-sized, except for the configuration register.
    DS1621 uses a high-byte first convention, which is exactly opposite to
    the usual practice. */
@@ -154,8 +153,12 @@ static ssize_t set_temp_##suffix(struct 
 {									\
 	struct i2c_client *client = to_i2c_client(dev);			\
 	struct ds1621_data *data = ds1621_update_client(dev);		\
-	data->value = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));	\
+	u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));	\
+									\
+	down(&data->update_lock);					\
+	data->value = val;						\
 	ds1621_write_value(client, reg, data->value);			\
+	up(&data->update_lock);						\
 	return count;							\
 }
 
@@ -236,8 +239,6 @@ int ds1621_detect(struct i2c_adapter *ad
 
 	/* Fill in remaining client fields and put it into the global list */
 	strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
-
-	new_client->id = ds1621_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -288,8 +289,8 @@ static struct ds1621_data *ds1621_update
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 
 		dev_dbg(&client->dev, "Starting ds1621 update\n");
 
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -86,8 +87,7 @@ static void eeprom_update_client(struct 
 	down(&data->update_lock);
 
 	if (!(data->valid & (1 << slice)) ||
-	    (jiffies - data->last_updated[slice] > 300 * HZ) ||
-	    (jiffies < data->last_updated[slice])) {
+	    time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
 		dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
 
 		if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
@@ -130,7 +130,8 @@ static ssize_t eeprom_read(struct kobjec
 
 	/* Hide Vaio security settings to regular users (16 first bytes) */
 	if (data->nature == VAIO && off < 16 && !capable(CAP_SYS_ADMIN)) {
-		int in_row1 = 16 - off;
+		size_t in_row1 = 16 - off;
+		in_row1 = min(in_row1, count);
 		memset(buf, 0, in_row1);
 		if (count - in_row1 > 0)
 			memcpy(buf + in_row1, &data->data[16], count - in_row1);
@@ -209,10 +210,11 @@ int eeprom_detect(struct i2c_adapter *ad
 		if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
 		 && i2c_smbus_read_byte(new_client) == 'C'
 		 && i2c_smbus_read_byte(new_client) == 'G'
-		 && i2c_smbus_read_byte(new_client) == '-')
+		 && i2c_smbus_read_byte(new_client) == '-') {
 			dev_info(&new_client->dev, "Vaio EEPROM detected, "
 				"enabling password protection\n");
 			data->nature = VAIO;
+		}
 	}
 
 	/* create the sysfs eeprom file */
diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c
--- a/drivers/i2c/chips/fscher.c
+++ b/drivers/i2c/chips/fscher.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -151,12 +152,6 @@ struct fscher_data {
 };
 
 /*
- * Internal variables
- */
-
-static int fscher_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -337,7 +332,6 @@ static int fscher_detect(struct i2c_adap
 	/* Fill in the remaining client fields and put it into the
 	 * global list */
 	strlcpy(new_client->name, "fscher", I2C_NAME_SIZE);
-	new_client->id = fscher_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -418,8 +412,7 @@ static struct fscher_data *fscher_update
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > 2 * HZ) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 
 		dev_dbg(&client->dev, "Starting fscher update\n");
 
@@ -471,9 +464,11 @@ static ssize_t set_fan_status(struct i2c
 {
 	/* bits 0..1, 3..7 reserved => mask with 0x04 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04;
+	
+	down(&data->update_lock);
 	data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v;
-
 	fscher_write_value(client, reg, v);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -487,9 +482,11 @@ static ssize_t set_pwm(struct i2c_client
 		       const char *buf, size_t count, int nr, int reg)
 {
 	unsigned long v = simple_strtoul(buf, NULL, 10);
-	data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v;
 
+	down(&data->update_lock);
+	data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v;
 	fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -514,11 +511,14 @@ static ssize_t set_fan_div(struct i2c_cl
 		return -EINVAL;
 	}
 
+	down(&data->update_lock);
+
 	/* bits 2..7 reserved => mask with 0x03 */
 	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03;
 	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v;
 
 	fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -544,9 +544,11 @@ static ssize_t set_temp_status(struct i2
 {
 	/* bits 2..7 reserved, 0 read only => mask with 0x02 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
-	data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v;
 
+	down(&data->update_lock);
+	data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v;
 	fscher_write_value(client, reg, v);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -599,9 +601,11 @@ static ssize_t set_control(struct i2c_cl
 {
 	/* bits 1..7 reserved => mask with 0x01 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01;
-	data->global_control &= ~v;
 
+	down(&data->update_lock);
+	data->global_control &= ~v;
 	fscher_write_value(client, reg, v);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -619,10 +623,12 @@ static ssize_t set_watchdog_control(stru
 {
 	/* bits 0..3 reserved => mask with 0xf0 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
+
+	down(&data->update_lock);
 	data->watchdog[2] &= ~0xf0;
 	data->watchdog[2] |= v;
-
 	fscher_write_value(client, reg, data->watchdog[2]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -637,9 +643,11 @@ static ssize_t set_watchdog_status(struc
 {
 	/* bits 0, 2..7 reserved => mask with 0x02 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
-	data->watchdog[1] &= ~v;
 
+	down(&data->update_lock);
+	data->watchdog[1] &= ~v;
 	fscher_write_value(client, reg, v);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -652,9 +660,12 @@ static ssize_t show_watchdog_status(stru
 static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data,
 				   const char *buf, size_t count, int nr, int reg)
 {
-	data->watchdog[0] = simple_strtoul(buf, NULL, 10) & 0xff;
-
+	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
+	
+	down(&data->update_lock);
+	data->watchdog[0] = v;
 	fscher_write_value(client, reg, data->watchdog[0]);
+	up(&data->update_lock);
 	return count;
 }
 
diff --git a/drivers/i2c/chips/fscpos.c b/drivers/i2c/chips/fscpos.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/fscpos.c
@@ -0,0 +1,641 @@
+/*
+	fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips
+	Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
+
+	This program is free software; you can redistribute it 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.
+*/
+
+/*
+	fujitsu siemens poseidon chip,
+	module based on the old fscpos module by Hermann Jung <hej@odn.de> and
+	the fscher module by Reinhard Nissl <rnissl@gmx.de>
+
+	original module based on lm80.c
+	Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+	and Philip Edelbrock <phil@netroedge.com>
+
+	Thanks to Jean Delvare for reviewing my code and suggesting a lot of
+	improvements.
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/init.h>
+
+/*
+ * Addresses to scan
+ */
+static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/*
+ * Insmod parameters
+ */
+SENSORS_INSMOD_1(fscpos);
+
+/*
+ * The FSCPOS registers
+ */
+
+/* chip identification */
+#define FSCPOS_REG_IDENT_0		0x00
+#define FSCPOS_REG_IDENT_1		0x01
+#define FSCPOS_REG_IDENT_2		0x02
+#define FSCPOS_REG_REVISION		0x03
+
+/* global control and status */
+#define FSCPOS_REG_EVENT_STATE		0x04
+#define FSCPOS_REG_CONTROL		0x05
+
+/* watchdog */
+#define FSCPOS_REG_WDOG_PRESET		0x28
+#define FSCPOS_REG_WDOG_STATE		0x23
+#define FSCPOS_REG_WDOG_CONTROL		0x21
+
+/* voltages */
+#define FSCPOS_REG_VOLT_12		0x45
+#define FSCPOS_REG_VOLT_5		0x42
+#define FSCPOS_REG_VOLT_BATT		0x48
+
+/* fans - the chip does not support minimum speed for fan2 */
+static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 };
+static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab };
+static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 };
+static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf };
+
+/* temperatures */
+static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 };
+static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 };
+
+/*
+ * Functions declaration
+ */
+static int fscpos_attach_adapter(struct i2c_adapter *adapter);
+static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind);
+static int fscpos_detach_client(struct i2c_client *client);
+
+static int fscpos_read_value(struct i2c_client *client, u8 register);
+static int fscpos_write_value(struct i2c_client *client, u8 register, u8 value);
+static struct fscpos_data *fscpos_update_device(struct device *dev);
+static void fscpos_init_client(struct i2c_client *client);
+
+static void reset_fan_alarm(struct i2c_client *client, int nr);
+
+/*
+ * Driver data (common to all clients)
+ */
+static struct i2c_driver fscpos_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "fscpos",
+	.id		= I2C_DRIVERID_FSCPOS,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= fscpos_attach_adapter,
+	.detach_client	= fscpos_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+struct fscpos_data {
+	struct i2c_client client;
+	struct semaphore update_lock;
+	char valid; 		/* 0 until following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* register values */
+	u8 revision;		/* revision of chip */
+	u8 global_event;	/* global event status */
+	u8 global_control;	/* global control register */
+	u8 wdog_control;	/* watchdog control */
+	u8 wdog_state;		/* watchdog status */
+	u8 wdog_preset;		/* watchdog preset */
+	u8 volt[3];		/* 12, 5, battery current */
+	u8 temp_act[3];		/* temperature */
+	u8 temp_status[3];	/* status of sensor */
+	u8 fan_act[3];		/* fans revolutions per second */
+	u8 fan_status[3];	/* fan status */
+	u8 pwm[2];		/* fan min value for rps */
+	u8 fan_ripple[3];	/* divider for rps */
+};
+
+/* Temperature */
+#define TEMP_FROM_REG(val)	(((val) - 128) * 1000)
+
+static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr)
+{
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1]));
+}
+
+static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr)
+{
+	/* bits 2..7 reserved => mask with 0x03 */
+	return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03);
+}
+
+static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr)
+{
+	return sprintf(buf, "1\n");
+}
+
+static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data
+			*data, const char *buf,	size_t count, int nr, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10);
+	if (v != 1) {
+		dev_err(&client->dev, "temp_reset value %ld not supported. "
+					"Use 1 to reset the alarm!\n", v);
+		return -EINVAL;
+	}
+
+	dev_info(&client->dev, "You used the temp_reset feature which has not "
+				"been proplerly tested. Please report your "
+				"experience to the module author.\n");
+
+	/* Supported value: 2 (clears the status) */
+	fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr], 2);
+	return count;
+}
+
+/* Fans */
+#define RPM_FROM_REG(val)	((val) * 60)
+
+static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr)
+{
+	/* bits 0..1, 3..7 reserved => mask with 0x04 */
+	return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04);
+}
+
+static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr)
+{
+	return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1]));
+}
+
+static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr)
+{
+	/* bits 2..7 reserved => mask with 0x03 */
+	return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03);
+}
+
+static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data
+			*data, const char *buf,	size_t count, int nr, int reg)
+{
+	/* supported values: 2, 4, 8 */
+	unsigned long v = simple_strtoul(buf, NULL, 10);
+
+	switch (v) {
+		case 2: v = 1; break;
+		case 4: v = 2; break;
+		case 8: v = 3; break;
+	default:
+		dev_err(&client->dev, "fan_ripple value %ld not supported. "
+					"Must be one of 2, 4 or 8!\n", v);
+		return -EINVAL;
+	}
+	
+	down(&data->update_lock);
+	/* bits 2..7 reserved => mask with 0x03 */
+	data->fan_ripple[nr - 1] &= ~0x03;
+	data->fan_ripple[nr - 1] |= v;
+	
+	fscpos_write_value(client, reg, data->fan_ripple[nr - 1]);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr)
+{
+	return sprintf(buf, "%u\n", data->pwm[nr - 1]);
+}
+
+static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data,
+				const char *buf, size_t count, int nr, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10);
+
+	/* Range: 0..255 */
+	if (v < 0) v = 0;
+	if (v > 255) v = 255;
+
+	down(&data->update_lock);
+	data->pwm[nr - 1] = v;
+	fscpos_write_value(client, reg, data->pwm[nr - 1]);
+	up(&data->update_lock);
+	return count;
+}
+
+static void reset_fan_alarm(struct i2c_client *client, int nr)
+{
+	fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4);
+}
+
+/* Volts */
+#define VOLT_FROM_REG(val, mult)	((val) * (mult) / 255)
+
+static ssize_t show_volt_12(struct device *dev, char *buf)
+{
+	struct fscpos_data *data = fscpos_update_device(dev);
+	return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200));
+}
+
+static ssize_t show_volt_5(struct device *dev, char *buf)
+{
+	struct fscpos_data *data = fscpos_update_device(dev);
+	return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600));
+}
+
+static ssize_t show_volt_batt(struct device *dev, char *buf)
+{
+	struct fscpos_data *data = fscpos_update_device(dev);
+	return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300));
+}
+
+/* Watchdog */
+static ssize_t show_wdog_control(struct fscpos_data *data, char *buf)
+{
+	/* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */
+	return sprintf(buf, "%u\n", data->wdog_control & 0xb0);
+}
+
+static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data
+				*data, const char *buf,	size_t count, int reg)
+{
+	/* bits 0..3 reserved => mask with 0xf0 */
+	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
+
+	down(&data->update_lock);
+	data->wdog_control &= ~0xf0;
+	data->wdog_control |= v;
+	fscpos_write_value(client, reg, data->wdog_control);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_wdog_state(struct fscpos_data *data, char *buf)
+{
+	/* bits 0, 2..7 reserved => mask with 0x02 */
+	return sprintf(buf, "%u\n", data->wdog_state & 0x02);
+}
+
+static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data
+				*data, const char *buf, size_t count, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
+
+	/* Valid values: 2 (clear) */
+	if (v != 2) {
+		dev_err(&client->dev, "wdog_state value %ld not supported. "
+					"Must be 2 to clear the state!\n", v);
+		return -EINVAL;
+	}
+
+	down(&data->update_lock);
+	data->wdog_state &= ~v;
+	fscpos_write_value(client, reg, v);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf)
+{
+	return sprintf(buf, "%u\n", data->wdog_preset);
+}
+
+static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data
+				*data, const char *buf,	size_t count, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
+
+	down(&data->update_lock);
+	data->wdog_preset = v;
+	fscpos_write_value(client, reg, data->wdog_preset);
+	up(&data->update_lock);
+	return count;
+}
+
+/* Event */
+static ssize_t show_event(struct device *dev, char *buf)
+{
+	/* bits 5..7 reserved => mask with 0x1f */
+	struct fscpos_data *data = fscpos_update_device(dev);
+	return sprintf(buf, "%u\n", data->global_event & 0x9b);
+}
+
+/*
+ * Sysfs stuff
+ */
+#define create_getter(kind, sub) \
+	static ssize_t sysfs_show_##kind##sub(struct device *dev, char *buf) \
+	{ \
+		struct fscpos_data *data = fscpos_update_device(dev); \
+		return show_##kind##sub(data, buf); \
+	}
+
+#define create_getter_n(kind, offset, sub) \
+	static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, char\
+								 	*buf) \
+	{ \
+		struct fscpos_data *data = fscpos_update_device(dev); \
+		return show_##kind##sub(data, buf, offset); \
+	}
+
+#define create_setter(kind, sub, reg) \
+	static ssize_t sysfs_set_##kind##sub (struct device *dev, const char \
+							*buf, size_t count) \
+	{ \
+		struct i2c_client *client = to_i2c_client(dev); \
+		struct fscpos_data *data = i2c_get_clientdata(client); \
+		return set_##kind##sub(client, data, buf, count, reg); \
+	}
+
+#define create_setter_n(kind, offset, sub, reg) \
+	static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, \
+					const char *buf, size_t count) \
+	{ \
+		struct i2c_client *client = to_i2c_client(dev); \
+		struct fscpos_data *data = i2c_get_clientdata(client); \
+		return set_##kind##sub(client, data, buf, count, offset, reg);\
+	}
+
+#define create_sysfs_device_ro(kind, sub, offset) \
+	static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \
+					sysfs_show_##kind##offset##sub, NULL);
+
+#define create_sysfs_device_rw(kind, sub, offset) \
+	static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \
+		sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub);
+
+#define sysfs_ro_n(kind, sub, offset) \
+	create_getter_n(kind, offset, sub); \
+	create_sysfs_device_ro(kind, sub, offset);
+
+#define sysfs_rw_n(kind, sub, offset, reg) \
+	create_getter_n(kind, offset, sub); \
+	create_setter_n(kind, offset, sub, reg); \
+	create_sysfs_device_rw(kind, sub, offset);
+
+#define sysfs_rw(kind, sub, reg) \
+	create_getter(kind, sub); \
+	create_setter(kind, sub, reg); \
+	create_sysfs_device_rw(kind, sub,);
+
+#define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \
+	sysfs_fan(offset, reg_status, reg_ripple); \
+	sysfs_rw_n(pwm,, offset, reg_min);
+
+#define sysfs_fan(offset, reg_status, reg_ripple) \
+	sysfs_ro_n(fan, _input, offset); \
+	sysfs_ro_n(fan, _status, offset); \
+	sysfs_rw_n(fan, _ripple, offset, reg_ripple);
+
+#define sysfs_temp(offset, reg_status) \
+	sysfs_ro_n(temp, _input, offset); \
+	sysfs_ro_n(temp, _status, offset); \
+	sysfs_rw_n(temp, _reset, offset, reg_status);
+
+#define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \
+	sysfs_rw(wdog, _control, reg_wdog_control); \
+	sysfs_rw(wdog, _preset, reg_wdog_preset); \
+	sysfs_rw(wdog, _state, reg_wdog_state);
+
+sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0],
+							FSCPOS_REG_PWM[0]);
+sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1],
+							FSCPOS_REG_PWM[1]);
+sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]);
+
+sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]);
+sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]);
+sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]);
+
+sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE,
+						FSCPOS_REG_WDOG_CONTROL);
+
+static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
+static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
+static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
+static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
+
+static int fscpos_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_detect(adapter, &addr_data, fscpos_detect);
+}
+
+int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct fscpos_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto exit;
+
+	/*
+	 * OK. For now, we presume we have a valid client. We now create the
+	 * client structure, even though we cannot fill it completely yet.
+	 * But it allows us to access fscpos_{read,write}_value.
+	 */
+
+	if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct fscpos_data));
+
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &fscpos_driver;
+	new_client->flags = 0;
+
+	/* Do the remaining detection unless force or force_fscpos parameter */
+	if (kind < 0) {
+		if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0)
+			!= 0x50) /* 'P' */
+		|| (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1)
+			!= 0x45) /* 'E' */
+		|| (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
+			!= 0x47))/* 'G' */
+		{
+			dev_dbg(&new_client->dev, "fscpos detection failed\n");
+			goto exit_free;
+		}
+	}
+
+	/* Fill in the remaining client fields and put it in the global list */
+	strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE);
+
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Inizialize the fscpos chip */
+	fscpos_init_client(new_client);
+
+	/* Announce that the chip was found */
+	dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_event);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_wdog_control);
+	device_create_file(&new_client->dev, &dev_attr_wdog_preset);
+	device_create_file(&new_client->dev, &dev_attr_wdog_state);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_status);
+	device_create_file(&new_client->dev, &dev_attr_temp1_reset);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_status);
+	device_create_file(&new_client->dev, &dev_attr_temp2_reset);
+	device_create_file(&new_client->dev, &dev_attr_temp3_input);
+	device_create_file(&new_client->dev, &dev_attr_temp3_status);
+	device_create_file(&new_client->dev, &dev_attr_temp3_reset);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_status);
+	device_create_file(&new_client->dev, &dev_attr_fan1_ripple);
+	device_create_file(&new_client->dev, &dev_attr_pwm1);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_status);
+	device_create_file(&new_client->dev, &dev_attr_fan2_ripple);
+	device_create_file(&new_client->dev, &dev_attr_pwm2);
+	device_create_file(&new_client->dev, &dev_attr_fan3_input);
+	device_create_file(&new_client->dev, &dev_attr_fan3_status);
+	device_create_file(&new_client->dev, &dev_attr_fan3_ripple);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int fscpos_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, client"
+							" not detached.\n");
+		return err;
+	}
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static int fscpos_read_value(struct i2c_client *client, u8 reg)
+{
+	dev_dbg(&client->dev, "Read reg 0x%02x\n", reg);
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value);
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* Called when we have found a new FSCPOS chip */
+static void fscpos_init_client(struct i2c_client *client)
+{
+	struct fscpos_data *data = i2c_get_clientdata(client);
+
+	/* read revision from chip */
+	data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION);
+}
+
+static struct fscpos_data *fscpos_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct fscpos_data *data = i2c_get_clientdata(client);
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > 2 * HZ) ||
+			(jiffies < data->last_updated) || !data->valid) {
+		int i;
+
+		dev_dbg(&client->dev, "Starting fscpos update\n");
+
+		for (i = 0; i < 3; i++) {
+			data->temp_act[i] = fscpos_read_value(client,
+						FSCPOS_REG_TEMP_ACT[i]);
+			data->temp_status[i] = fscpos_read_value(client,
+						FSCPOS_REG_TEMP_STATE[i]);
+			data->fan_act[i] = fscpos_read_value(client,
+						FSCPOS_REG_FAN_ACT[i]);
+			data->fan_status[i] = fscpos_read_value(client,
+						FSCPOS_REG_FAN_STATE[i]);
+			data->fan_ripple[i] = fscpos_read_value(client,
+						FSCPOS_REG_FAN_RIPPLE[i]);
+			if (i < 2) {
+				/* fan2_min is not supported by the chip */
+				data->pwm[i] = fscpos_read_value(client,
+							FSCPOS_REG_PWM[i]);
+			}
+			/* reset fan status if speed is back to > 0 */
+			if (data->fan_status[i] != 0 && data->fan_act[i] > 0) {
+				reset_fan_alarm(client, i);
+			}
+		}
+
+		data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12);
+		data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5);
+		data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT);
+
+		data->wdog_preset = fscpos_read_value(client,
+							FSCPOS_REG_WDOG_PRESET);
+		data->wdog_state = fscpos_read_value(client,
+							FSCPOS_REG_WDOG_STATE);
+		data->wdog_control = fscpos_read_value(client,
+						FSCPOS_REG_WDOG_CONTROL);
+
+		data->global_event = fscpos_read_value(client,
+						FSCPOS_REG_EVENT_STATE);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+	up(&data->update_lock);
+	return data;
+}
+
+static int __init sm_fscpos_init(void)
+{
+	return i2c_add_driver(&fscpos_driver);
+}
+
+static void __exit sm_fscpos_exit(void)
+{
+	i2c_del_driver(&fscpos_driver);
+}
+
+MODULE_AUTHOR("Stefan Ott <stefan@desire.ch> based on work from Hermann Jung "
+				"<hej@odn.de>, Frodo Looijaard <frodol@dds.nl>"
+				" and Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver");
+MODULE_LICENSE("GPL");
+
+module_init(sm_fscpos_init);
+module_exit(sm_fscpos_exit);
diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c
--- a/drivers/i2c/chips/gl518sm.c
+++ b/drivers/i2c/chips/gl518sm.c
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -159,12 +160,6 @@ static struct i2c_driver gl518_driver = 
 };
 
 /*
- * Internal variables
- */
-
-static int gl518_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -216,8 +211,11 @@ static ssize_t set_##suffix(struct devic
 	struct i2c_client *client = to_i2c_client(dev);			\
 	struct gl518_data *data = i2c_get_clientdata(client);		\
 	long val = simple_strtol(buf, NULL, 10);			\
+									\
+	down(&data->update_lock);					\
 	data->value = type##_TO_REG(val);				\
 	gl518_write_value(client, reg, data->value);			\
+	up(&data->update_lock);						\
 	return count;							\
 }
 
@@ -227,11 +225,15 @@ static ssize_t set_##suffix(struct devic
 {									\
 	struct i2c_client *client = to_i2c_client(dev);			\
 	struct gl518_data *data = i2c_get_clientdata(client);		\
-	int regvalue = gl518_read_value(client, reg);			\
+	int regvalue;							\
 	unsigned long val = simple_strtoul(buf, NULL, 10);		\
+									\
+	down(&data->update_lock);					\
+	regvalue = gl518_read_value(client, reg);			\
 	data->value = type##_TO_REG(val);				\
 	regvalue = (regvalue & ~mask) | (data->value << shift);		\
 	gl518_write_value(client, reg, regvalue);			\
+	up(&data->update_lock);						\
 	return count;							\
 }
 
@@ -260,9 +262,12 @@ static ssize_t set_fan_min1(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct gl518_data *data = i2c_get_clientdata(client);
-	int regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+	int regvalue;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	data->fan_min[0] = FAN_TO_REG(simple_strtoul(buf, NULL, 10),
+	down(&data->update_lock);
+	regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+	data->fan_min[0] = FAN_TO_REG(val,
 		DIV_FROM_REG(data->fan_div[0]));
 	regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8);
 	gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue);
@@ -275,6 +280,7 @@ static ssize_t set_fan_min1(struct devic
 	data->beep_mask &= data->alarm_mask;
 	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -282,9 +288,12 @@ static ssize_t set_fan_min2(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct gl518_data *data = i2c_get_clientdata(client);
-	int regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+	int regvalue;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	data->fan_min[1] = FAN_TO_REG(simple_strtoul(buf, NULL, 10),
+	down(&data->update_lock);
+	regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
+	data->fan_min[1] = FAN_TO_REG(val,
 		DIV_FROM_REG(data->fan_div[1]));
 	regvalue = (regvalue & 0xff00) | data->fan_min[1];
 	gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue);
@@ -297,6 +306,7 @@ static ssize_t set_fan_min2(struct devic
 	data->beep_mask &= data->alarm_mask;
 	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -396,7 +406,6 @@ static int gl518_detect(struct i2c_adapt
 
 	/* Fill in the remaining client fields */
 	strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE);
-	new_client->id = gl518_id++;
 	data->type = kind;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
@@ -512,8 +521,8 @@ static struct gl518_data *gl518_update_d
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		dev_dbg(&client->dev, "Starting gl518 update\n");
 
 		data->alarms = gl518_read_value(client, GL518_REG_INT);
diff --git a/drivers/i2c/chips/gl520sm.c b/drivers/i2c/chips/gl520sm.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/gl520sm.c
@@ -0,0 +1,769 @@
+/*
+    gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
+                monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
+                              Kyösti Mälkki <kmalkki@cc.hut.fi>
+    Copyright (c) 2005        Maarten Deprez <maartendeprez@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.
+
+    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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+/* Type of the extra sensor */
+static unsigned short extra_sensor_type;
+module_param(extra_sensor_type, ushort, 0);
+MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(gl520sm);
+
+/* Many GL520 constants specified below 
+One of the inputs can be configured as either temp or voltage.
+That's why _TEMP2 and _IN4 access the same register 
+*/
+
+/* The GL520 registers */
+#define GL520_REG_CHIP_ID		0x00
+#define GL520_REG_REVISION		0x01
+#define GL520_REG_CONF			0x03
+#define GL520_REG_MASK			0x11
+
+#define GL520_REG_VID_INPUT		0x02
+
+#define GL520_REG_IN0_INPUT		0x15
+#define GL520_REG_IN0_LIMIT		0x0c
+#define GL520_REG_IN0_MIN		GL520_REG_IN0_LIMIT
+#define GL520_REG_IN0_MAX		GL520_REG_IN0_LIMIT
+
+#define GL520_REG_IN1_INPUT		0x14
+#define GL520_REG_IN1_LIMIT		0x09
+#define GL520_REG_IN1_MIN		GL520_REG_IN1_LIMIT
+#define GL520_REG_IN1_MAX		GL520_REG_IN1_LIMIT
+
+#define GL520_REG_IN2_INPUT		0x13
+#define GL520_REG_IN2_LIMIT		0x0a
+#define GL520_REG_IN2_MIN		GL520_REG_IN2_LIMIT
+#define GL520_REG_IN2_MAX		GL520_REG_IN2_LIMIT
+
+#define GL520_REG_IN3_INPUT		0x0d
+#define GL520_REG_IN3_LIMIT		0x0b
+#define GL520_REG_IN3_MIN		GL520_REG_IN3_LIMIT
+#define GL520_REG_IN3_MAX		GL520_REG_IN3_LIMIT
+
+#define GL520_REG_IN4_INPUT		0x0e
+#define GL520_REG_IN4_MAX		0x17
+#define GL520_REG_IN4_MIN		0x18
+
+#define GL520_REG_TEMP1_INPUT		0x04
+#define GL520_REG_TEMP1_MAX		0x05
+#define GL520_REG_TEMP1_MAX_HYST	0x06
+
+#define GL520_REG_TEMP2_INPUT		0x0e
+#define GL520_REG_TEMP2_MAX		0x17
+#define GL520_REG_TEMP2_MAX_HYST	0x18
+
+#define GL520_REG_FAN_INPUT		0x07
+#define GL520_REG_FAN_MIN		0x08
+#define GL520_REG_FAN_DIV		0x0f
+#define GL520_REG_FAN_OFF		GL520_REG_FAN_DIV
+
+#define GL520_REG_ALARMS		0x12
+#define GL520_REG_BEEP_MASK		0x10
+#define GL520_REG_BEEP_ENABLE		GL520_REG_CONF
+
+/*
+ * Function declarations
+ */
+
+static int gl520_attach_adapter(struct i2c_adapter *adapter);
+static int gl520_detect(struct i2c_adapter *adapter, int address, int kind);
+static void gl520_init_client(struct i2c_client *client);
+static int gl520_detach_client(struct i2c_client *client);
+static int gl520_read_value(struct i2c_client *client, u8 reg);
+static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
+static struct gl520_data *gl520_update_device(struct device *dev);
+
+/* Driver data */
+static struct i2c_driver gl520_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "gl520sm",
+	.id		= I2C_DRIVERID_GL520,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= gl520_attach_adapter,
+	.detach_client	= gl520_detach_client,
+};
+
+/* Client data */
+struct gl520_data {
+	struct i2c_client client;
+	struct semaphore update_lock;
+	char valid;		/* zero until the following fields are valid */
+	unsigned long last_updated;	/* in jiffies */
+
+	u8 vid;
+	u8 vrm;
+	u8 in_input[5];		/* [0] = VVD */
+	u8 in_min[5];		/* [0] = VDD */
+	u8 in_max[5];		/* [0] = VDD */
+	u8 fan_input[2];
+	u8 fan_min[2];
+	u8 fan_div[2];
+	u8 fan_off;
+	u8 temp_input[2];
+	u8 temp_max[2];
+	u8 temp_max_hyst[2];
+	u8 alarms;
+	u8 beep_enable;
+	u8 beep_mask;
+	u8 alarm_mask;
+	u8 two_temps;
+};
+
+/*
+ * Sysfs stuff
+ */
+
+#define sysfs_r(type, n, item, reg) \
+static ssize_t get_##type##item (struct gl520_data *, char *, int); \
+static ssize_t get_##type##n##item (struct device *, char *); \
+static ssize_t get_##type##n##item (struct device *dev, char *buf) \
+{ \
+	struct gl520_data *data = gl520_update_device(dev); \
+	return get_##type##item(data, buf, (n)); \
+}
+
+#define sysfs_w(type, n, item, reg) \
+static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \
+static ssize_t set_##type##n##item (struct device *, const char *, size_t); \
+static ssize_t set_##type##n##item (struct device *dev, const char *buf, size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct gl520_data *data = i2c_get_clientdata(client); \
+	return set_##type##item(client, data, buf, count, (n), reg); \
+}
+
+#define sysfs_rw_n(type, n, item, reg) \
+sysfs_r(type, n, item, reg) \
+sysfs_w(type, n, item, reg) \
+static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item);
+
+#define sysfs_ro_n(type, n, item, reg) \
+sysfs_r(type, n, item, reg) \
+static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL);
+
+#define sysfs_rw(type, item, reg) \
+sysfs_r(type, 0, item, reg) \
+sysfs_w(type, 0, item, reg) \
+static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item);
+
+#define sysfs_ro(type, item, reg) \
+sysfs_r(type, 0, item, reg) \
+static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL);
+
+
+#define sysfs_vid(n) \
+sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
+
+#define device_create_file_vid(client, n) \
+device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
+
+#define sysfs_in(n) \
+sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
+sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
+sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
+
+#define device_create_file_in(client, n) \
+({device_create_file(&client->dev, &dev_attr_in##n##_input); \
+device_create_file(&client->dev, &dev_attr_in##n##_min); \
+device_create_file(&client->dev, &dev_attr_in##n##_max);})
+
+#define sysfs_fan(n) \
+sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
+sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
+sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
+
+#define device_create_file_fan(client, n) \
+({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
+device_create_file(&client->dev, &dev_attr_fan##n##_min); \
+device_create_file(&client->dev, &dev_attr_fan##n##_div);})
+
+#define sysfs_fan_off(n) \
+sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
+
+#define device_create_file_fan_off(client, n) \
+device_create_file(&client->dev, &dev_attr_fan##n##_off)
+
+#define sysfs_temp(n) \
+sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
+sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
+sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
+
+#define device_create_file_temp(client, n) \
+({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
+device_create_file(&client->dev, &dev_attr_temp##n##_max); \
+device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
+
+#define sysfs_alarms() \
+sysfs_ro(alarms, , GL520_REG_ALARMS) \
+sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
+sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
+
+#define device_create_file_alarms(client) \
+({device_create_file(&client->dev, &dev_attr_alarms); \
+device_create_file(&client->dev, &dev_attr_beep_enable); \
+device_create_file(&client->dev, &dev_attr_beep_mask);})
+
+
+sysfs_vid(0)
+
+sysfs_in(0)
+sysfs_in(1)
+sysfs_in(2)
+sysfs_in(3)
+sysfs_in(4)
+
+sysfs_fan(1)
+sysfs_fan(2)
+sysfs_fan_off(1)
+
+sysfs_temp(1)
+sysfs_temp(2)
+
+sysfs_alarms()
+
+
+static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+
+#define VDD_FROM_REG(val) (((val)*95+2)/4)
+#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
+
+#define IN_FROM_REG(val) ((val)*19)
+#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
+
+static ssize_t get_in_input(struct gl520_data *data, char *buf, int n)
+{
+	u8 r = data->in_input[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t get_in_min(struct gl520_data *data, char *buf, int n)
+{
+	u8 r = data->in_min[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t get_in_max(struct gl520_data *data, char *buf, int n)
+{
+	u8 r = data->in_max[n];
+
+	if (n == 0)
+		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
+	else
+		return sprintf(buf, "%d\n", IN_FROM_REG(r));
+}
+
+static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	long v = simple_strtol(buf, NULL, 10);
+	u8 r;
+
+	down(&data->update_lock);
+
+	if (n == 0)
+		r = VDD_TO_REG(v);
+	else
+		r = IN_TO_REG(v);
+
+	data->in_min[n] = r;
+
+	if (n < 4)
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r);
+	else
+		gl520_write_value(client, reg, r);
+
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	long v = simple_strtol(buf, NULL, 10);
+	u8 r;
+
+	if (n == 0)
+		r = VDD_TO_REG(v);
+	else
+		r = IN_TO_REG(v);
+
+	down(&data->update_lock);
+
+	data->in_max[n] = r;
+
+	if (n < 4)
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8));
+	else
+		gl520_write_value(client, reg, r);
+
+	up(&data->update_lock);
+	return count;
+}
+
+#define DIV_FROM_REG(val) (1 << (val))
+#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div))))
+#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255));
+
+static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1]));
+}
+
+static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1]));
+}
+
+static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1]));
+}
+
+static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", data->fan_off);
+}
+
+static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10);
+	u8 r;
+
+	down(&data->update_lock);
+	r = FAN_TO_REG(v, data->fan_div[n - 1]);
+	data->fan_min[n - 1] = r;
+
+	if (n == 1)
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8));
+	else
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r);
+
+	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+	if (data->fan_min[n - 1] == 0)
+		data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40;
+	else
+		data->alarm_mask |= (n == 1) ? 0x20 : 0x40;
+	data->beep_mask &= data->alarm_mask;
+	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
+
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	unsigned long v = simple_strtoul(buf, NULL, 10);
+	u8 r;
+
+	switch (v) {
+	case 1: r = 0; break;
+	case 2: r = 1; break;
+	case 4: r = 2; break;
+	case 8: r = 3; break;
+	default:
+		dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v);
+		return -EINVAL;
+	}
+
+	down(&data->update_lock);
+	data->fan_div[n - 1] = r;
+
+	if (n == 1)
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6));
+	else
+		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4));
+
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	u8 r = simple_strtoul(buf, NULL, 10)?1:0;
+
+	down(&data->update_lock);
+	data->fan_off = r;
+	gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2));
+	up(&data->update_lock);
+	return count;
+}
+
+#define TEMP_FROM_REG(val) (((val) - 130) * 1000)
+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255))
+
+static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1]));
+}
+
+static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1]));
+}
+
+static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1]));
+}
+
+static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	long v = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_max[n - 1] = TEMP_TO_REG(v);;
+	gl520_write_value(client, reg, data->temp_max[n - 1]);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	long v = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_max_hyst[n - 1] = TEMP_TO_REG(v);
+	gl520_write_value(client, reg, data->temp_max_hyst[n - 1]);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t get_alarms(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", data->beep_enable);
+}
+
+static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n)
+{
+	return sprintf(buf, "%d\n", data->beep_mask);
+}
+
+static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	u8 r = simple_strtoul(buf, NULL, 10)?0:1;
+
+	down(&data->update_lock);
+	data->beep_enable = !r;
+	gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2));
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+{
+	u8 r = simple_strtoul(buf, NULL, 10);
+	
+	down(&data->update_lock);
+	r &= data->alarm_mask;
+	data->beep_mask = r;
+	gl520_write_value(client, reg, r);
+	up(&data->update_lock);
+	return count;
+}
+
+
+/*
+ * Real code
+ */
+
+static int gl520_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_detect(adapter, &addr_data, gl520_detect);
+}
+
+static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct gl520_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access gl520_{read,write}_value. */
+
+	if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct gl520_data));
+
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &gl520_driver;
+	new_client->flags = 0;
+
+	/* Determine the chip type. */
+	if (kind < 0) {
+		if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) ||
+		    ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
+		    ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) {
+			dev_dbg(&new_client->dev, "Unknown chip type, skipping\n");
+			goto exit_free;
+		}
+	}
+
+	/* Fill in the remaining client fields */
+	strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE);
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the GL520SM chip */
+	gl520_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file_vid(new_client, 0);
+
+	device_create_file_in(new_client, 0);
+	device_create_file_in(new_client, 1);
+	device_create_file_in(new_client, 2);
+	device_create_file_in(new_client, 3);
+	if (!data->two_temps)
+		device_create_file_in(new_client, 4);
+
+	device_create_file_fan(new_client, 1);
+	device_create_file_fan(new_client, 2);
+	device_create_file_fan_off(new_client, 1);
+
+	device_create_file_temp(new_client, 1);
+	if (data->two_temps)
+		device_create_file_temp(new_client, 2);
+
+	device_create_file_alarms(new_client);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+
+/* Called when we have found a new GL520SM. */
+static void gl520_init_client(struct i2c_client *client)
+{
+	struct gl520_data *data = i2c_get_clientdata(client);
+	u8 oldconf, conf;
+
+	conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
+
+	data->alarm_mask = 0xff;
+	data->vrm = i2c_which_vrm();
+
+	if (extra_sensor_type == 1)
+		conf &= ~0x10;
+	else if (extra_sensor_type == 2)
+		conf |= 0x10;
+	data->two_temps = !(conf & 0x10);
+
+	/* If IRQ# is disabled, we can safely force comparator mode */
+	if (!(conf & 0x20))
+		conf &= 0xf7;
+
+	/* Enable monitoring if needed */
+	conf |= 0x40;
+
+	if (conf != oldconf)
+		gl520_write_value(client, GL520_REG_CONF, conf);
+
+	gl520_update_device(&(client->dev));
+
+	if (data->fan_min[0] == 0)
+		data->alarm_mask &= ~0x20;
+	if (data->fan_min[1] == 0)
+		data->alarm_mask &= ~0x40;
+
+	data->beep_mask &= data->alarm_mask;
+	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
+}
+
+static int gl520_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+
+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized 
+   GL520 uses a high-byte first convention */
+static int gl520_read_value(struct i2c_client *client, u8 reg)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return swab16(i2c_smbus_read_word_data(client, reg));
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if ((reg >= 0x07) && (reg <= 0x0c))
+		return i2c_smbus_write_word_data(client, reg, swab16(value));
+	else
+		return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+
+static struct gl520_data *gl520_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct gl520_data *data = i2c_get_clientdata(client);
+	int val;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > 2 * HZ) ||
+	    (jiffies < data->last_updated) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting gl520sm update\n");
+
+		data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
+		data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+		data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f;
+
+		val = gl520_read_value(client, GL520_REG_IN0_LIMIT);
+		data->in_min[0] = val & 0xff;
+		data->in_max[0] = (val >> 8) & 0xff;
+		val = gl520_read_value(client, GL520_REG_IN1_LIMIT);
+		data->in_min[1] = val & 0xff;
+		data->in_max[1] = (val >> 8) & 0xff;
+		val = gl520_read_value(client, GL520_REG_IN2_LIMIT);
+		data->in_min[2] = val & 0xff;
+		data->in_max[2] = (val >> 8) & 0xff;
+		val = gl520_read_value(client, GL520_REG_IN3_LIMIT);
+		data->in_min[3] = val & 0xff;
+		data->in_max[3] = (val >> 8) & 0xff;
+
+		val = gl520_read_value(client, GL520_REG_FAN_INPUT);
+		data->fan_input[0] = (val >> 8) & 0xff;
+		data->fan_input[1] = val & 0xff;
+
+		val = gl520_read_value(client, GL520_REG_FAN_MIN);
+		data->fan_min[0] = (val >> 8) & 0xff;
+		data->fan_min[1] = val & 0xff;
+
+		data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT);
+		data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX);
+		data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST);
+
+		val = gl520_read_value(client, GL520_REG_FAN_DIV);
+		data->fan_div[0] = (val >> 6) & 0x03;
+		data->fan_div[1] = (val >> 4) & 0x03;
+		data->fan_off = (val >> 2) & 0x01;
+
+		data->alarms &= data->alarm_mask;
+
+		val = gl520_read_value(client, GL520_REG_CONF);
+		data->beep_enable = !((val >> 2) & 1);
+
+		data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT);
+		data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT);
+		data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT);
+		data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT);
+
+		/* Temp1 and Vin4 are the same input */
+		if (data->two_temps) {
+			data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT);
+			data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX);
+			data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST);
+		} else {
+			data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT);
+			data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN);
+			data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX);
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+
+static int __init sensors_gl520sm_init(void)
+{
+	return i2c_add_driver(&gl520_driver);
+}
+
+static void __exit sensors_gl520sm_exit(void)
+{
+	i2c_del_driver(&gl520_driver);
+}
+
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
+	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
+MODULE_DESCRIPTION("GL520SM driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_gl520sm_init);
+module_exit(sensors_gl520sm_exit);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -1503,7 +1503,6 @@ static int isp1301_probe(struct i2c_adap
 	isp->client.addr = address;
 	i2c_set_clientdata(&isp->client, isp);
 	isp->client.adapter = bus;
-	isp->client.id = 1301;
 	isp->client.driver = &isp1301_driver;
 	strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
 	i2c = &isp->client;
diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
--- a/drivers/i2c/chips/it87.c
+++ b/drivers/i2c/chips/it87.c
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -104,6 +105,9 @@ superio_exit(void)
 /* Update battery voltage after every reading if true */
 static int update_vbat;
 
+/* Not all BIOSes properly configure the PWM registers */
+static int fix_pwm_polarity;
+
 /* Chip Type */
 
 static u16 chip_type;
@@ -224,6 +228,7 @@ static int it87_read_value(struct i2c_cl
 static int it87_write_value(struct i2c_client *client, u8 register,
 			u8 value);
 static struct it87_data *it87_update_device(struct device *dev);
+static int it87_check_pwm(struct i2c_client *client);
 static void it87_init_client(struct i2c_client *client, struct it87_data *data);
 
 
@@ -260,9 +265,12 @@ static ssize_t set_in_min(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MIN(nr), 
 			data->in_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_in_max(struct device *dev, const char *buf, 
@@ -271,9 +279,12 @@ static ssize_t set_in_max(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MAX(nr), 
 			data->in_max[nr]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -351,8 +362,11 @@ static ssize_t set_temp_max(struct devic
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_high[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_min(struct device *dev, const char *buf, 
@@ -361,8 +375,11 @@ static ssize_t set_temp_min(struct devic
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_low[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+	up(&data->update_lock);
 	return count;
 }
 #define show_temp_offset(offset)					\
@@ -403,9 +420,11 @@ show_temp_offset(3);
 static ssize_t show_sensor(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	if (data->sensor & (1 << nr))
+	u8 reg = data->sensor; /* In case the value is updated while we use it */
+	
+	if (reg & (1 << nr))
 		return sprintf(buf, "3\n");  /* thermal diode */
-	if (data->sensor & (8 << nr))
+	if (reg & (8 << nr))
 		return sprintf(buf, "2\n");  /* thermistor */
 	return sprintf(buf, "0\n");      /* disabled */
 }
@@ -416,6 +435,8 @@ static ssize_t set_sensor(struct device 
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	data->sensor &= ~(1 << nr);
 	data->sensor &= ~(8 << nr);
 	/* 3 = thermal diode; 2 = thermistor; 0 = disabled */
@@ -423,9 +444,12 @@ static ssize_t set_sensor(struct device 
 	    data->sensor |= 1 << nr;
 	else if (val == 2)
 	    data->sensor |= 8 << nr;
-	else if (val != 0)
+	else if (val != 0) {
+		up(&data->update_lock);
 		return -EINVAL;
+	}
 	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+	up(&data->update_lock);
 	return count;
 }
 #define show_sensor_offset(offset)					\
@@ -479,8 +503,11 @@ static ssize_t set_fan_min(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_fan_div(struct device *dev, const char *buf, 
@@ -490,7 +517,10 @@ static ssize_t set_fan_div(struct device
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 	int i, min[3];
-	u8 old = it87_read_value(client, IT87_REG_FAN_DIV);
+	u8 old;
+
+	down(&data->update_lock);
+	old = it87_read_value(client, IT87_REG_FAN_DIV);
 
 	for (i = 0; i < 3; i++)
 		min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
@@ -517,6 +547,7 @@ static ssize_t set_fan_div(struct device
 		data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
 		it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
 	}
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_pwm_enable(struct device *dev, const char *buf,
@@ -526,6 +557,8 @@ static ssize_t set_pwm_enable(struct dev
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	if (val == 0) {
 		int tmp;
 		/* make sure the fan is on when in on/off mode */
@@ -540,9 +573,12 @@ static ssize_t set_pwm_enable(struct dev
 		it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
 		/* set saved pwm value, clear FAN_CTLX PWM mode bit */
 		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
-	} else
+	} else {
+		up(&data->update_lock);
 		return -EINVAL;
+	}
 
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_pwm(struct device *dev, const char *buf,
@@ -555,10 +591,11 @@ static ssize_t set_pwm(struct device *de
 	if (val < 0 || val > 255)
 		return -EINVAL;
 
+	down(&data->update_lock);
 	data->manual_pwm_ctl[nr] = val;
 	if (data->fan_main_ctrl & (1 << nr))
 		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
-
+	up(&data->update_lock);
 	return count;
 }
 
@@ -631,7 +668,7 @@ static ssize_t show_alarms(struct device
 	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
 }
-static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
 static ssize_t
 show_vrm_reg(struct device *dev, char *buf)
@@ -718,7 +755,6 @@ int it87_detect(struct i2c_adapter *adap
 	const char *name = "";
 	int is_isa = i2c_is_isa_adapter(adapter);
 	int enable_pwm_interface;
-	int tmp;
 
 	if (!is_isa && 
 	    !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -730,10 +766,9 @@ int it87_detect(struct i2c_adapter *adap
 			goto ERROR0;
 
 	/* Probe whether there is anything available on this address. Already
-	   done for SMBus clients */
+	   done for SMBus and Super-I/O clients */
 	if (kind < 0) {
-		if (is_isa) {
-
+		if (is_isa && !chip_type) {
 #define REALLY_SLOW_IO
 			/* We need the timeouts for at least some IT87-like chips. But only
 			   if we read 'undefined' registers. */
@@ -822,20 +857,12 @@ int it87_detect(struct i2c_adapter *adap
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR2;
 
+	/* Check PWM configuration */
+	enable_pwm_interface = it87_check_pwm(new_client);
+
 	/* Initialize the IT87 chip */
 	it87_init_client(new_client, data);
 
-	/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
-	 * and polarity set to active low is sign that this is the case so we
-	 * disable pwm control to protect the user. */
-	enable_pwm_interface = 1;
-	tmp = it87_read_value(new_client, IT87_REG_FAN_CTL);
-	if ((tmp & 0x87) == 0) {
-		enable_pwm_interface = 0;
-		dev_info(&new_client->dev,
-			"detected broken BIOS defaults, disabling pwm interface");
-	}
-
 	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_in0_input);
 	device_create_file(&new_client->dev, &dev_attr_in1_input);
@@ -894,9 +921,9 @@ int it87_detect(struct i2c_adapter *adap
 	}
 
 	if (data->type == it8712) {
+		data->vrm = i2c_which_vrm();
 		device_create_file_vrm(new_client);
 		device_create_file_vid(new_client);
-		data->vrm = i2c_which_vrm();
 	}
 
 	return 0;
@@ -966,6 +993,56 @@ static int it87_write_value(struct i2c_c
 		return i2c_smbus_write_byte_data(client, reg, value);
 }
 
+/* Return 1 if and only if the PWM interface is safe to use */
+static int it87_check_pwm(struct i2c_client *client)
+{
+	/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
+	 * and polarity set to active low is sign that this is the case so we
+	 * disable pwm control to protect the user. */
+	int tmp = it87_read_value(client, IT87_REG_FAN_CTL);
+	if ((tmp & 0x87) == 0) {
+		if (fix_pwm_polarity) {
+			/* The user asks us to attempt a chip reconfiguration.
+			 * This means switching to active high polarity and
+			 * inverting all fan speed values. */
+			int i;
+			u8 pwm[3];
+
+			for (i = 0; i < 3; i++)
+				pwm[i] = it87_read_value(client,
+							 IT87_REG_PWM(i));
+
+			/* If any fan is in automatic pwm mode, the polarity
+			 * might be correct, as suspicious as it seems, so we
+			 * better don't change anything (but still disable the
+			 * PWM interface). */
+			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
+				dev_info(&client->dev, "Reconfiguring PWM to "
+					 "active high polarity\n");
+				it87_write_value(client, IT87_REG_FAN_CTL,
+						 tmp | 0x87);
+				for (i = 0; i < 3; i++)
+					it87_write_value(client,
+							 IT87_REG_PWM(i),
+							 0x7f & ~pwm[i]);
+				return 1;
+			}
+
+			dev_info(&client->dev, "PWM configuration is "
+				 "too broken to be fixed\n");
+		}
+
+		dev_info(&client->dev, "Detected broken BIOS "
+			 "defaults, disabling PWM interface\n");
+		return 0;
+	} else if (fix_pwm_polarity) {
+		dev_info(&client->dev, "PWM configuration looks "
+			 "sane, won't touch\n");
+	}
+
+	return 1;
+}
+
 /* Called when we have found a new IT87. */
 static void it87_init_client(struct i2c_client *client, struct it87_data *data)
 {
@@ -1038,8 +1115,8 @@ static struct it87_data *it87_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 
 		if (update_vbat) {
 			/* Cleared after each update, so reenable.  Value
@@ -1077,9 +1154,6 @@ static struct it87_data *it87_update_dev
 			    it87_read_value(client, IT87_REG_TEMP_LOW(i));
 		}
 
-		/* The 8705 does not have VID capability */
-		data->vid = 0x1f;
-
 		i = it87_read_value(client, IT87_REG_FAN_DIV);
 		data->fan_div[0] = i & 0x07;
 		data->fan_div[1] = (i >> 3) & 0x07;
@@ -1126,6 +1200,8 @@ MODULE_AUTHOR("Chris Gauthron <chrisg@0-
 MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
+module_param(fix_pwm_polarity, bool, 0);
+MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)");
 MODULE_LICENSE("GPL");
 
 module_init(sm_it87_init);
diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c
--- a/drivers/i2c/chips/lm63.c
+++ b/drivers/i2c/chips/lm63.c
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -190,11 +191,14 @@ static ssize_t set_fan1_low(struct devic
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm63_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan1_low = FAN_TO_REG(val);
 	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
 				  data->fan1_low & 0xFF);
 	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
 				  data->fan1_low >> 8);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -216,10 +220,12 @@ static ssize_t set_pwm1(struct device *d
 		return -EPERM;
 
 	val = simple_strtoul(buf, NULL, 10);
+	down(&data->update_lock);
 	data->pwm1_value = val <= 0 ? 0 :
 			   val >= 255 ? 2 * data->pwm1_freq :
 			   (val * data->pwm1_freq * 2 + 127) / 255;
 	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -255,8 +261,11 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm63_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->value = TEMP8_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
+	up(&data->update_lock); \
 	return count; \
 }
 #define set_temp11(value, reg_msb, reg_lsb) \
@@ -266,9 +275,12 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm63_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->value = TEMP11_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \
 	i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \
+	up(&data->update_lock); \
 	return count; \
 }
 set_temp8(temp1_high, LM63_REG_LOCAL_HIGH);
@@ -291,10 +303,14 @@ static ssize_t set_temp2_crit_hyst(struc
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm63_data *data = i2c_get_clientdata(client);
-	int hyst = TEMP8_FROM_REG(data->temp2_crit) -
-		   simple_strtol(buf, NULL, 10);
+	long val = simple_strtol(buf, NULL, 10);
+	long hyst;
+
+	down(&data->update_lock);
+	hyst = TEMP8_FROM_REG(data->temp2_crit) - val;
 	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
 				  HYST_TO_REG(hyst));
+	up(&data->update_lock);
 	return count;
 }
 
@@ -492,9 +508,7 @@ static struct lm63_data *lm63_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		if (data->config & 0x04) { /* tachometer enabled  */
 			/* order matters for fan1_input */
 			data->fan1_input = i2c_smbus_read_byte_data(client,
diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c
--- a/drivers/i2c/chips/lm75.c
+++ b/drivers/i2c/chips/lm75.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include "lm75.h"
@@ -73,8 +74,6 @@ static struct i2c_driver lm75_driver = {
 	.detach_client	= lm75_detach_client,
 };
 
-static int lm75_id;
-
 #define show(value)	\
 static ssize_t show_##value(struct device *dev, char *buf)		\
 {									\
@@ -91,8 +90,11 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev);		\
 	struct lm75_data *data = i2c_get_clientdata(client);	\
 	int temp = simple_strtoul(buf, NULL, 10);		\
+								\
+	down(&data->update_lock);				\
 	data->value = LM75_TEMP_TO_REG(temp);			\
 	lm75_write_value(client, reg, data->value);		\
+	up(&data->update_lock);					\
 	return count;						\
 }
 set(temp_max, LM75_REG_TEMP_OS);
@@ -196,8 +198,6 @@ static int lm75_detect(struct i2c_adapte
 
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	new_client->id = lm75_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -263,8 +263,8 @@ static struct lm75_data *lm75_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		dev_dbg(&client->dev, "Starting lm75 update\n");
 
 		data->temp_input = lm75_read_value(client, LM75_REG_TEMP);
diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c
--- a/drivers/i2c/chips/lm77.c
+++ b/drivers/i2c/chips/lm77.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -81,8 +82,6 @@ static struct i2c_driver lm77_driver = {
 	.detach_client	= lm77_detach_client,
 };
 
-static int lm77_id;
-
 /* straight from the datasheet */
 #define LM77_TEMP_MIN (-55000)
 #define LM77_TEMP_MAX 125000
@@ -139,8 +138,12 @@ static ssize_t set_##value(struct device
 {										\
 	struct i2c_client *client = to_i2c_client(dev);				\
 	struct lm77_data *data = i2c_get_clientdata(client);			\
-	data->value = simple_strtoul(buf, NULL, 10);				\
+	long val = simple_strtoul(buf, NULL, 10);				\
+										\
+	down(&data->update_lock);						\
+	data->value = val;				\
 	lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value));		\
+	up(&data->update_lock);							\
 	return count;								\
 }
 
@@ -153,9 +156,13 @@ static ssize_t set_temp_crit_hyst(struct
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm77_data *data = i2c_get_clientdata(client);
-	data->temp_hyst = data->temp_crit - simple_strtoul(buf, NULL, 10);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_hyst = data->temp_crit - val;
 	lm77_write_value(client, LM77_REG_TEMP_HYST,
 			 LM77_TEMP_TO_REG(data->temp_hyst));
+	up(&data->update_lock);
 	return count;
 }
 
@@ -164,13 +171,18 @@ static ssize_t set_temp_crit(struct devi
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm77_data *data = i2c_get_clientdata(client);
-	int oldcrithyst = data->temp_crit - data->temp_hyst;
-	data->temp_crit = simple_strtoul(buf, NULL, 10);
+	long val = simple_strtoul(buf, NULL, 10);
+	int oldcrithyst;
+	
+	down(&data->update_lock);
+	oldcrithyst = data->temp_crit - data->temp_hyst;
+	data->temp_crit = val;
 	data->temp_hyst = data->temp_crit - oldcrithyst;
 	lm77_write_value(client, LM77_REG_TEMP_CRIT,
 			 LM77_TEMP_TO_REG(data->temp_crit));
 	lm77_write_value(client, LM77_REG_TEMP_HYST,
 			 LM77_TEMP_TO_REG(data->temp_hyst));
+	up(&data->update_lock);
 	return count;
 }
 
@@ -295,8 +307,6 @@ static int lm77_detect(struct i2c_adapte
 
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	new_client->id = lm77_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -364,8 +374,8 @@ static struct lm77_data *lm77_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		dev_dbg(&client->dev, "Starting lm77 update\n");
 		data->temp_input =
 			LM77_TEMP_FROM_REG(lm77_read_value(client,
diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c
--- a/drivers/i2c/chips/lm78.c
+++ b/drivers/i2c/chips/lm78.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <asm/io.h>
@@ -81,9 +82,8 @@ static inline u8 IN_TO_REG(unsigned long
 
 static inline u8 FAN_TO_REG(long rpm, int div)
 {
-	if (rpm == 0)
+	if (rpm <= 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
@@ -94,15 +94,15 @@ static inline int FAN_FROM_REG(u8 val, i
 
 /* TEMP: mC (-128C to +127C)
    REG: 1C/bit, two's complement */
-static inline u8 TEMP_TO_REG(int val)
+static inline s8 TEMP_TO_REG(int val)
 {
 	int nval = SENSORS_LIMIT(val, -128000, 127000) ;
-	return nval<0 ? (nval-500)/1000+0x100 : (nval+500)/1000;
+	return nval<0 ? (nval-500)/1000 : (nval+500)/1000;
 }
 
-static inline int TEMP_FROM_REG(u8 val)
+static inline int TEMP_FROM_REG(s8 val)
 {
-	return (val>=0x80 ? val-0x100 : val) * 1000;
+	return val * 1000;
 }
 
 /* VID: mV
@@ -112,16 +112,6 @@ static inline int VID_FROM_REG(u8 val)
 	return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50;
 }
 
-/* ALARMS: chip-specific bitmask
-   REG: (same) */
-#define ALARMS_FROM_REG(val) (val)
-
-/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
-   REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
-static inline u8 DIV_TO_REG(int val)
-{
-	return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
-}
 #define DIV_FROM_REG(val) (1 << (val))
 
 /* There are some complications in a module like this. First off, LM78 chips
@@ -157,9 +147,9 @@ struct lm78_data {
 	u8 in_min[7];		/* Register value */
 	u8 fan[3];		/* Register value */
 	u8 fan_min[3];		/* Register value */
-	u8 temp;		/* Register value */
-	u8 temp_over;		/* Register value */
-	u8 temp_hyst;		/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_over;		/* Register value */
+	s8 temp_hyst;		/* Register value */
 	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 vid;			/* Register encoding, combined */
 	u16 alarms;		/* Register encoding, combined */
@@ -210,8 +200,11 @@ static ssize_t set_in_min(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
 	lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -221,8 +214,11 @@ static ssize_t set_in_max(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
 	lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]);
+	up(&data->update_lock);
 	return count;
 }
 	
@@ -285,8 +281,11 @@ static ssize_t set_temp_over(struct devi
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_over = TEMP_TO_REG(val);
 	lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -301,8 +300,11 @@ static ssize_t set_temp_hyst(struct devi
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_hyst = TEMP_TO_REG(val);
 	lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -333,8 +335,11 @@ static ssize_t set_fan_min(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -353,11 +358,27 @@ static ssize_t set_fan_div(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
-	unsigned long min = FAN_FROM_REG(data->fan_min[nr],
-			DIV_FROM_REG(data->fan_div[nr]));
 	unsigned long val = simple_strtoul(buf, NULL, 10);
-	int reg = lm78_read_value(client, LM78_REG_VID_FANDIV);
-	data->fan_div[nr] = DIV_TO_REG(val);
+	unsigned long min;
+	u8 reg;
+
+	down(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   DIV_FROM_REG(data->fan_div[nr]));
+
+	switch (val) {
+	case 1: data->fan_div[nr] = 0; break;
+	case 2: data->fan_div[nr] = 1; break;
+	case 4: data->fan_div[nr] = 2; break;
+	case 8: data->fan_div[nr] = 3; break;
+	default:
+		dev_err(&client->dev, "fan_div value %ld not "
+			"supported. Choose one of 1, 2, 4 or 8!\n", val);
+		up(&data->update_lock);
+		return -EINVAL;
+	}
+
+	reg = lm78_read_value(client, LM78_REG_VID_FANDIV);
 	switch (nr) {
 	case 0:
 		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
@@ -367,9 +388,12 @@ static ssize_t set_fan_div(struct device
 		break;
 	}
 	lm78_write_value(client, LM78_REG_VID_FANDIV, reg);
+
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
+
 	return count;
 }
 
@@ -430,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, sh
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
-	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
+	return sprintf(buf, "%u\n", data->alarms);
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
@@ -633,17 +657,15 @@ static int lm78_detach_client(struct i2c
 {
 	int err;
 
-	/* release ISA region first */
-	if(i2c_is_isa_client(client))
-		release_region(client->addr, LM78_EXTENT);
-
-	/* now it's safe to scrap the rest */
 	if ((err = i2c_detach_client(client))) {
 		dev_err(&client->dev,
 		    "Client deregistration failed, client not detached.\n");
 		return err;
 	}
 
+	if(i2c_is_isa_client(client))
+		release_region(client->addr, LM78_EXTENT);
+
 	kfree(i2c_get_clientdata(client));
 
 	return 0;
@@ -653,9 +675,7 @@ static int lm78_detach_client(struct i2c
    We don't want to lock the whole ISA bus, so we lock each client
    separately.
    We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
-   would slow down the LM78 access and should not be necessary. 
-   There are some ugly typecasts here, but the good new is - they should
-   nowhere else be necessary! */
+   would slow down the LM78 access and should not be necessary.  */
 static int lm78_read_value(struct i2c_client *client, u8 reg)
 {
 	int res;
@@ -709,8 +729,8 @@ static struct lm78_data *lm78_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 
 		dev_dbg(&client->dev, "Starting lm78 update\n");
 
diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c
--- a/drivers/i2c/chips/lm80.c
+++ b/drivers/i2c/chips/lm80.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -99,10 +100,7 @@ static inline long TEMP_FROM_REG(u16 tem
 #define TEMP_LIMIT_TO_REG(val)		SENSORS_LIMIT((val)<0?\
 					((val)-500)/1000:((val)+500)/1000,0,255)
 
-#define ALARMS_FROM_REG(val)		(val)
-
 #define DIV_FROM_REG(val)		(1 << (val))
-#define DIV_TO_REG(val)			((val)==8?3:(val)==4?2:(val)==1?0:1)
 
 /*
  * Client data (each client gets its own)
@@ -141,12 +139,6 @@ static int lm80_read_value(struct i2c_cl
 static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
 
 /*
- * Internal variables
- */
-
-static int lm80_id;
-
-/*
  * Driver data (common to all clients)
  */
 
@@ -198,8 +190,11 @@ static ssize_t set_in_##suffix(struct de
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock);\
 	data->value = IN_TO_REG(val); \
 	lm80_write_value(client, reg, data->value); \
+	up(&data->update_lock);\
 	return count; \
 }
 set_in(min0, in_min[0], LM80_REG_IN_MIN(0));
@@ -245,8 +240,11 @@ static ssize_t set_fan_##suffix(struct d
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtoul(buf, NULL, 10); \
+ \
+	down(&data->update_lock);\
 	data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \
 	lm80_write_value(client, reg, data->value); \
+	up(&data->update_lock);\
 	return count; \
 }
 set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]);
@@ -261,15 +259,25 @@ static ssize_t set_fan_div(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm80_data *data = i2c_get_clientdata(client);
-	unsigned long min, val;
+	unsigned long min, val = simple_strtoul(buf, NULL, 10);
 	u8 reg;
 
 	/* Save fan_min */
+	down(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   DIV_FROM_REG(data->fan_div[nr]));
 
-	val = simple_strtoul(buf, NULL, 10);
-	data->fan_div[nr] = DIV_TO_REG(val);
+	switch (val) {
+	case 1: data->fan_div[nr] = 0; break;
+	case 2: data->fan_div[nr] = 1; break;
+	case 4: data->fan_div[nr] = 2; break;
+	case 8: data->fan_div[nr] = 3; break;
+	default:
+		dev_err(&client->dev, "fan_div value %ld not "
+			"supported. Choose one of 1, 2, 4 or 8!\n", val);
+		up(&data->update_lock);
+		return -EINVAL;
+	}
 
 	reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1))))
 	    | (data->fan_div[nr] << (2 * (nr + 1)));
@@ -278,6 +286,7 @@ static ssize_t set_fan_div(struct device
 	/* Restore fan_min */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
+	up(&data->update_lock);
 
 	return count;
 }
@@ -315,8 +324,11 @@ static ssize_t set_temp_##suffix(struct 
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtoul(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->value = TEMP_LIMIT_TO_REG(val); \
 	lm80_write_value(client, reg, data->value); \
+	up(&data->update_lock); \
 	return count; \
 }
 set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
@@ -327,7 +339,7 @@ set_temp(os_hyst, temp_os_hyst, LM80_REG
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
 	struct lm80_data *data = lm80_update_device(dev);
-	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
+	return sprintf(buf, "%u\n", data->alarms);
 }
 
 static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0);
@@ -425,8 +437,6 @@ int lm80_detect(struct i2c_adapter *adap
 
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	new_client->id = lm80_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -530,9 +540,7 @@ static struct lm80_data *lm80_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > 2 * HZ) ||
-	    (jiffies < data->last_updated) || !data->valid) {
-
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 		dev_dbg(&client->dev, "Starting lm80 update\n");
 		for (i = 0; i <= 6; i++) {
 			data->in[i] =
diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c
--- a/drivers/i2c/chips/lm83.c
+++ b/drivers/i2c/chips/lm83.c
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -150,12 +151,6 @@ struct lm83_data {
 };
 
 /*
- * Internal variables
- */
-
-static int lm83_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -182,8 +177,11 @@ static ssize_t set_temp_##suffix(struct 
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm83_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->value = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
+	up(&data->update_lock); \
 	return count; \
 }
 set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH);
@@ -312,7 +310,6 @@ static int lm83_detect(struct i2c_adapte
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-	new_client->id = lm83_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -369,9 +366,7 @@ static struct lm83_data *lm83_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ * 2) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		int nr;
 
 		dev_dbg(&client->dev, "Updating lm83 data.\n");
diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c
--- a/drivers/i2c/chips/lm85.c
+++ b/drivers/i2c/chips/lm85.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -36,7 +37,7 @@ static unsigned short normal_i2c[] = { 0
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_5(lm85b, lm85c, adm1027, adt7463, emc6d100);
+SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 
 /* The LM85 registers */
 
@@ -73,8 +74,10 @@ SENSORS_INSMOD_5(lm85b, lm85c, adm1027, 
 #define	LM85_VERSTEP_LM85B		0x62
 #define	LM85_VERSTEP_ADM1027		0x60
 #define	LM85_VERSTEP_ADT7463		0x62
+#define	LM85_VERSTEP_ADT7463C		0x6A
 #define	LM85_VERSTEP_EMC6D100_A0        0x60
 #define	LM85_VERSTEP_EMC6D100_A1        0x61
+#define	LM85_VERSTEP_EMC6D102		0x65
 
 #define	LM85_REG_CONFIG			0x40
 
@@ -111,9 +114,13 @@ SENSORS_INSMOD_5(lm85b, lm85c, adm1027, 
 
 #define EMC6D100_REG_ALARM3             0x7d
 /* IN5, IN6 and IN7 */
-#define EMC6D100_REG_IN(nr)             (0x70 + ((nr)-5))
-#define EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr)-5) * 2)
-#define EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr)-5) * 2)
+#define	EMC6D100_REG_IN(nr)             (0x70 + ((nr)-5))
+#define	EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr)-5) * 2)
+#define	EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr)-5) * 2)
+#define	EMC6D102_REG_EXTEND_ADC1	0x85
+#define	EMC6D102_REG_EXTEND_ADC2	0x86
+#define	EMC6D102_REG_EXTEND_ADC3	0x87
+#define	EMC6D102_REG_EXTEND_ADC4	0x88
 
 #define	LM85_ALARM_IN0			0x0001
 #define	LM85_ALARM_IN1			0x0002
@@ -138,35 +145,36 @@ SENSORS_INSMOD_5(lm85b, lm85c, adm1027, 
    these macros are called: arguments may be evaluated more than once.
  */
 
-/* IN are scaled 1.000 == 0xc0, mag = 3 */
-#define IN_TO_REG(val)		(SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255))
-#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0)
-#define IN_FROM_REG(val)	(INEXT_FROM_REG(val,0))
-
 /* IN are scaled acording to built-in resistors */
 static int lm85_scaling[] = {  /* .001 Volts */
 		2500, 2250, 3300, 5000, 12000,
 		3300, 1500, 1800 /*EMC6D100*/
 	};
 #define SCALE(val,from,to)		(((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n,val)		(SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255))
-#define INSEXT_FROM_REG(n,val,ext)	(SCALE((val)*4 + (ext),192*4,lm85_scaling[n]))
-#define INS_FROM_REG(n,val)		(INSEXT_FROM_REG(n,val,0))
+
+#define INS_TO_REG(n,val)	\
+		SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
+
+#define INSEXT_FROM_REG(n,val,ext,scale)	\
+		SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+
+#define INS_FROM_REG(n,val)   INSEXT_FROM_REG(n,val,0,1)
 
 /* FAN speed is measured using 90kHz clock */
 #define FAN_TO_REG(val)		(SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
 #define FAN_FROM_REG(val)	((val)==0?-1:(val)==0xffff?0:5400000/(val))
 
 /* Temperature is reported in .001 degC increments */
-#define TEMP_TO_REG(val)		(SENSORS_LIMIT(((val)+500)/1000,-127,127))
-#define TEMPEXT_FROM_REG(val,ext)	((val)*1000 + (ext)*250)
-#define TEMP_FROM_REG(val)		(TEMPEXT_FROM_REG(val,0))
-#define EXTTEMP_TO_REG(val)		(SENSORS_LIMIT((val)/250,-127,127))
+#define TEMP_TO_REG(val)	\
+		SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
+#define TEMPEXT_FROM_REG(val,ext,scale)	\
+		SCALE((val)*scale + (ext),scale,1000)
+#define TEMP_FROM_REG(val)	\
+		TEMPEXT_FROM_REG(val,0,1)
 
 #define PWM_TO_REG(val)			(SENSORS_LIMIT(val,0,255))
 #define PWM_FROM_REG(val)		(val)
 
-#define EXT_FROM_REG(val,sensor)	(((val)>>(sensor * 2))&0x03)
 
 /* ZONEs have the following parameters:
  *    Limit (low) temp,           1. degC
@@ -354,7 +362,9 @@ struct lm85_data {
 	u8 pwm[3];		/* Register value */
 	u8 spinup_ctl;		/* Register encoding, combined */
 	u8 tach_mode;		/* Register encoding, combined */
-	u16 extend_adc;		/* Register value */
+	u8 temp_ext[3];		/* Decoded values */
+	u8 in_ext[8];		/* Decoded values */
+	u8 adc_scale;		/* ADC Extended bits scaling factor */
 	u8 fan_ppr;		/* Register value */
 	u8 smooth[3];		/* Register encoding */
 	u8 vid;			/* Register value */
@@ -389,9 +399,6 @@ static struct i2c_driver lm85_driver = {
 	.detach_client  = lm85_detach_client,
 };
 
-/* Unique ID assigned to each LM85 detected */
-static int lm85_id;
-
 
 /* 4 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
@@ -409,10 +416,9 @@ static ssize_t set_fan_min(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->fan_min[nr] = FAN_TO_REG(val);
 	lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]);
 	up(&data->update_lock);
@@ -492,10 +498,9 @@ static ssize_t set_pwm(struct device *de
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->pwm[nr] = PWM_TO_REG(val);
 	lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]);
 	up(&data->update_lock);
@@ -538,7 +543,10 @@ show_pwm_reg(3);
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]) );
+	return sprintf(	buf, "%d\n", INSEXT_FROM_REG(nr,
+						     data->in[nr],
+						     data->in_ext[nr],
+						     data->adc_scale) );
 }
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
@@ -550,10 +558,9 @@ static ssize_t set_in_min(struct device 
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_min[nr] = INS_TO_REG(nr, val);
 	lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]);
 	up(&data->update_lock);
@@ -569,10 +576,9 @@ static ssize_t set_in_max(struct device 
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->in_max[nr] = INS_TO_REG(nr, val);
 	lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]);
 	up(&data->update_lock);
@@ -619,7 +625,9 @@ show_in_reg(4);
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
 {
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]) );
+	return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
+						    data->temp_ext[nr],
+						    data->adc_scale) );
 }
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
 {
@@ -631,10 +639,9 @@ static ssize_t set_temp_min(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
 	up(&data->update_lock);
@@ -650,10 +657,9 @@ static ssize_t set_temp_max(struct devic
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int	val;
+	long val = simple_strtol(buf, NULL, 10);	
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
 	up(&data->update_lock);
@@ -706,10 +712,9 @@ static ssize_t set_pwm_auto_channels(str
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int     val;
+	long val = simple_strtol(buf, NULL, 10);   
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->autofan[nr].config = (data->autofan[nr].config & (~0xe0))
 		| ZONE_TO_REG(val) ;
 	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
@@ -727,10 +732,9 @@ static ssize_t set_pwm_auto_pwm_min(stru
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int     val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->autofan[nr].min_pwm = PWM_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr),
 		data->autofan[nr].min_pwm);
@@ -747,10 +751,9 @@ static ssize_t set_pwm_auto_pwm_minctl(s
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int     val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->autofan[nr].min_off = val;
 	lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0]
 		| data->syncpwm3
@@ -771,10 +774,9 @@ static ssize_t set_pwm_auto_pwm_freq(str
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int     val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->autofan[nr].freq = FREQ_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
 		(data->zone[nr].range << 4)
@@ -853,10 +855,10 @@ static ssize_t set_temp_auto_temp_off(st
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int    min, val;
+	int min;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	min = TEMP_FROM_REG(data->zone[nr].limit);
 	data->zone[nr].off_desired = TEMP_TO_REG(val);
 	data->zone[nr].hyst = HYST_TO_REG(min - val);
@@ -883,10 +885,9 @@ static ssize_t set_temp_auto_temp_min(st
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int    val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->zone[nr].limit = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
 		data->zone[nr].limit);
@@ -927,11 +928,11 @@ static ssize_t set_temp_auto_temp_max(st
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int    min, val;
+	int min;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
 	min = TEMP_FROM_REG(data->zone[nr].limit);
-	val = simple_strtol(buf, NULL, 10);
 	data->zone[nr].max_desired = TEMP_TO_REG(val);
 	data->zone[nr].range = RANGE_TO_REG(
 		val - min);
@@ -951,10 +952,9 @@ static ssize_t set_temp_auto_temp_crit(s
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
-	int     val;
+	long val = simple_strtol(buf, NULL, 10);
 
 	down(&data->update_lock);
-	val = simple_strtol(buf, NULL, 10);
 	data->zone[nr].critical = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
 		data->zone[nr].critical);
@@ -1091,7 +1091,8 @@ int lm85_detect(struct i2c_adapter *adap
 		    && verstep == LM85_VERSTEP_ADM1027 ) {
 			kind = adm1027 ;
 		} else if( company == LM85_COMPANY_ANALOG_DEV
-		    && verstep == LM85_VERSTEP_ADT7463 ) {
+		    && (verstep == LM85_VERSTEP_ADT7463
+			 || verstep == LM85_VERSTEP_ADT7463C) ) {
 			kind = adt7463 ;
 		} else if( company == LM85_COMPANY_ANALOG_DEV
 		    && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) {
@@ -1109,6 +1110,9 @@ int lm85_detect(struct i2c_adapter *adap
 			 */
 			kind = emc6d100 ;
 		} else if( company == LM85_COMPANY_SMSC
+		    && verstep == LM85_VERSTEP_EMC6D102) {
+			kind = emc6d102 ;
+		} else if( company == LM85_COMPANY_SMSC
 		    && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
 			dev_err(&adapter->dev, "lm85: Detected SMSC chip\n");
 			dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x"
@@ -1144,20 +1148,16 @@ int lm85_detect(struct i2c_adapter *adap
 		type_name = "adt7463";
 	} else if ( kind == emc6d100){
 		type_name = "emc6d100";
+	} else if ( kind == emc6d102 ) {
+		type_name = "emc6d102";
 	}
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 
 	/* Fill in the remaining client fields */
-	new_client->id = lm85_id++;
 	data->type = kind;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
-	dev_dbg(&adapter->dev, "Assigning ID %d to %s at %d,0x%02x\n",
-		new_client->id, new_client->name,
-		i2c_adapter_id(new_client->adapter),
-		new_client->addr);
-
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR1;
@@ -1267,7 +1267,6 @@ int lm85_read_value(struct i2c_client *c
 	case LM85_REG_FAN_MIN(2) :
 	case LM85_REG_FAN_MIN(3) :
 	case LM85_REG_ALARM1 :	/* Read both bytes at once */
-	case ADM1027_REG_EXTEND_ADC1 :  /* Read two bytes at once */
 		res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
 		res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ;
 		break ;
@@ -1363,7 +1362,7 @@ static struct lm85_data *lm85_update_dev
 	down(&data->update_lock);
 
 	if ( !data->valid ||
-	     (jiffies - data->last_reading > LM85_DATA_INTERVAL ) ) {
+	     time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) {
 		/* Things that change quickly */
 		dev_dbg(&client->dev, "Reading sensor values\n");
 		
@@ -1371,10 +1370,25 @@ static struct lm85_data *lm85_update_dev
 		 * more significant bits that are read later.
 		 */
 		if ( (data->type == adm1027) || (data->type == adt7463) ) {
-			data->extend_adc =
-			    lm85_read_value(client, ADM1027_REG_EXTEND_ADC1);
+			int ext1 = lm85_read_value(client,
+						   ADM1027_REG_EXTEND_ADC1);
+			int ext2 =  lm85_read_value(client,
+						    ADM1027_REG_EXTEND_ADC2);
+			int val = (ext1 << 8) + ext2;
+
+			for(i = 0; i <= 4; i++)
+				data->in_ext[i] = (val>>(i * 2))&0x03;
+
+			for(i = 0; i <= 2; i++)
+				data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
 		}
 
+		/* adc_scale is 2^(number of LSBs). There are 4 extra bits in
+		   the emc6d102 and 2 in the adt7463 and adm1027. In all
+		   other chips ext is always 0 and the value of scale is
+		   irrelevant. So it is left in 4*/
+		data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
+
 		for (i = 0; i <= 4; ++i) {
 			data->in[i] =
 			    lm85_read_value(client, LM85_REG_IN(i));
@@ -1411,13 +1425,35 @@ static struct lm85_data *lm85_update_dev
 			/* More alarm bits */
 			data->alarms |=
 				lm85_read_value(client, EMC6D100_REG_ALARM3) << 16;
+		} else if (data->type == emc6d102 ) {
+			/* Have to read LSB bits after the MSB ones because
+			   the reading of the MSB bits has frozen the
+			   LSBs (backward from the ADM1027).
+			 */
+			int ext1 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC1);
+			int ext2 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC2);
+			int ext3 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC3);
+			int ext4 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC4);
+			data->in_ext[0] = ext3 & 0x0f;
+			data->in_ext[1] = ext4 & 0x0f;
+			data->in_ext[2] = (ext4 >> 4) & 0x0f;
+			data->in_ext[3] = (ext3 >> 4) & 0x0f;
+			data->in_ext[4] = (ext2 >> 4) & 0x0f;
+
+			data->temp_ext[0] = ext1 & 0x0f;
+			data->temp_ext[1] = ext2 & 0x0f;
+			data->temp_ext[2] = (ext1 >> 4) & 0x0f;
 		}
 
 		data->last_reading = jiffies ;
 	};  /* last_reading */
 
 	if ( !data->valid ||
-	     (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) {
+	     time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) {
 		/* Things that don't change often */
 		dev_dbg(&client->dev, "Reading config values\n");
 
diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c
--- a/drivers/i2c/chips/lm87.c
+++ b/drivers/i2c/chips/lm87.c
@@ -56,6 +56,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -203,12 +204,6 @@ struct lm87_data {
 };
 
 /*
- * Internal variables
- */
-
-static int lm87_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -257,9 +252,12 @@ static void set_in_min(struct device *de
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
 	lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) :
 			 LM87_REG_AIN_MIN(nr-6), data->in_min[nr]);
+	up(&data->update_lock);
 }
 
 static void set_in_max(struct device *dev, const char *buf, int nr)
@@ -267,9 +265,12 @@ static void set_in_max(struct device *de
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
 	lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) :
 			 LM87_REG_AIN_MAX(nr-6), data->in_max[nr]);
+	up(&data->update_lock);
 }
 
 #define set_in(offset) \
@@ -322,20 +323,26 @@ show_temp(3);
 
 static void set_temp_low(struct device *dev, const char *buf, int nr)
 {
-    struct i2c_client *client = to_i2c_client(dev);
-    struct lm87_data *data = i2c_get_clientdata(client);
-    long val = simple_strtol(buf, NULL, 10);
-    data->temp_low[nr] = TEMP_TO_REG(val);
-    lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_low[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+	up(&data->update_lock);
 }
 
 static void set_temp_high(struct device *dev, const char *buf, int nr)
 {
-    struct i2c_client *client = to_i2c_client(dev);
-    struct lm87_data *data = i2c_get_clientdata(client);
-    long val = simple_strtol(buf, NULL, 10);
-    data->temp_high[nr] = TEMP_TO_REG(val);
-    lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_high[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+	up(&data->update_lock);
 }
 
 #define set_temp(offset) \
@@ -403,9 +410,12 @@ static void set_fan_min(struct device *d
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val,
 			    FAN_DIV_FROM_REG(data->fan_div[nr]));
 	lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
 }
 
 /* Note: we save and restore the fan minimum here, because its value is
@@ -418,16 +428,21 @@ static ssize_t set_fan_div(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
-	unsigned long min = FAN_FROM_REG(data->fan_min[nr],
-			    FAN_DIV_FROM_REG(data->fan_div[nr]));
+	unsigned long min;
 	u8 reg;
 
+	down(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			   FAN_DIV_FROM_REG(data->fan_div[nr]));
+
 	switch (val) {
 	case 1: data->fan_div[nr] = 0; break;
 	case 2: data->fan_div[nr] = 1; break;
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
-	default: return -EINVAL;
+	default:
+		up(&data->update_lock);
+		return -EINVAL;
 	}
 
 	reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
@@ -444,6 +459,8 @@ static ssize_t set_fan_div(struct device
 	data->fan_min[nr] = FAN_TO_REG(min, val);
 	lm87_write_value(client, LM87_REG_FAN_MIN(nr),
 			 data->fan_min[nr]);
+	up(&data->update_lock);
+
 	return count;
 }
 
@@ -504,8 +521,11 @@ static ssize_t set_aout(struct device *d
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->aout = AOUT_TO_REG(val);
 	lm87_write_value(client, LM87_REG_AOUT, data->aout);
+	up(&data->update_lock);
 	return count;
 }
 static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
@@ -569,7 +589,6 @@ static int lm87_detect(struct i2c_adapte
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, "lm87", I2C_NAME_SIZE);
-	new_client->id = lm87_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -720,9 +739,7 @@ static struct lm87_data *lm87_update_dev
 
 	down(&data->update_lock);
 
-	if (jiffies - data->last_updated > HZ
-	  || jiffies < data->last_updated
-	  || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		int i, j;
 
 		dev_dbg(&client->dev, "Updating data.\n");
diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c
--- a/drivers/i2c/chips/lm90.c
+++ b/drivers/i2c/chips/lm90.c
@@ -43,6 +43,14 @@
  * variants. The extra address and features of the MAX6659 are not
  * supported by this driver.
  *
+ * This driver also supports the ADT7461 chip from Analog Devices but
+ * only in its "compatability mode". If an ADT7461 chip is found but
+ * is configured in non-compatible mode (where its temperature
+ * register values are decoded differently) it is ignored by this
+ * driver. Complete datasheet can be obtained from Analog's website
+ * at:
+ *   http://products.analog.com/products/info.asp?product=ADT7461
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
@@ -66,6 +74,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -76,6 +85,7 @@
  * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c.
  * LM89-1, and LM99-1 have address 0x4d.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * ADT7461 always has address 0x4c.
  */
 
 static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
@@ -85,7 +95,7 @@ static unsigned int normal_isa[] = { I2C
  * Insmod parameters
  */
 
-SENSORS_INSMOD_5(lm90, adm1032, lm99, lm86, max6657);
+SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
 
 /*
  * The LM90 registers
@@ -147,6 +157,19 @@ SENSORS_INSMOD_5(lm90, adm1032, lm99, lm
 #define HYST_TO_REG(val)	((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \
 				 ((val) + 500) / 1000)
 
+/* 
+ * ADT7461 is almost identical to LM90 except that attempts to write
+ * values that are outside the range 0 < temp < 127 are treated as
+ * the boundary value. 
+ */
+
+#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \
+				 (val) >= 127000 ? 127 : \
+				 ((val) + 500) / 1000)
+#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \
+				 (val) >= 127750 ? 0x7FC0 : \
+				 ((val) + 125) / 250 * 64)
+
 /*
  * Functions declaration
  */
@@ -180,6 +203,7 @@ struct lm90_data {
 	struct semaphore update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
+	int kind;
 
 	/* registers values */
 	s8 temp_input1, temp_low1, temp_high1; /* local */
@@ -190,12 +214,6 @@ struct lm90_data {
 };
 
 /*
- * Internal variables
- */
-
-static int lm90_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -221,8 +239,14 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm90_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
-	data->value = TEMP1_TO_REG(val); \
+ \
+	down(&data->update_lock); \
+	if (data->kind == adt7461) \
+		data->value = TEMP1_TO_REG_ADT7461(val); \
+	else \
+		data->value = TEMP1_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
+	up(&data->update_lock); \
 	return count; \
 }
 #define set_temp2(value, regh, regl) \
@@ -232,9 +256,15 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm90_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
-	data->value = TEMP2_TO_REG(val); \
+ \
+	down(&data->update_lock); \
+	if (data->kind == adt7461) \
+		data->value = TEMP2_TO_REG_ADT7461(val); \
+	else \
+		data->value = TEMP2_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, regh, data->value >> 8); \
 	i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \
+	up(&data->update_lock); \
 	return count; \
 }
 set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW);
@@ -259,10 +289,14 @@ static ssize_t set_temp_hyst1(struct dev
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
-	int hyst = TEMP1_FROM_REG(data->temp_crit1) -
-		   simple_strtol(buf, NULL, 10);
+	long val = simple_strtol(buf, NULL, 10);
+	long hyst;
+
+	down(&data->update_lock);
+	hyst = TEMP1_FROM_REG(data->temp_crit1) - val;
 	i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
 				  HYST_TO_REG(hyst));
+	up(&data->update_lock);
 	return count;
 }
 
@@ -386,6 +420,12 @@ static int lm90_detect(struct i2c_adapte
 			 && (reg_config1 & 0x3F) == 0x00
 			 && reg_convrate <= 0x0A) {
 				kind = adm1032;
+			} else
+			if (address == 0x4c
+			 && chip_id == 0x51 /* ADT7461 */
+			 && (reg_config1 & 0x1F) == 0x00 /* check compat mode */
+			 && reg_convrate <= 0x0A) {
+				kind = adt7461;
 			}
 		} else
 		if (man_id == 0x4D) { /* Maxim */
@@ -423,12 +463,14 @@ static int lm90_detect(struct i2c_adapte
 		name = "lm86";
 	} else if (kind == max6657) {
 		name = "max6657";
+	} else if (kind == adt7461) {
+		name = "adt7461";
 	}
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-	new_client->id = lm90_id++;
 	data->valid = 0;
+	data->kind = kind;
 	init_MUTEX(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
@@ -495,9 +537,7 @@ static struct lm90_data *lm90_update_dev
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ * 2) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		u8 oldh, newh;
 
 		dev_dbg(&client->dev, "Updating lm90 data.\n");
diff --git a/drivers/i2c/chips/lm92.c b/drivers/i2c/chips/lm92.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/lm92.c
@@ -0,0 +1,429 @@
+/*
+ * lm92 - Hardware monitoring driver
+ * Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
+ *
+ * Based on the lm90 driver, with some ideas taken from the lm_sensors
+ * lm92 driver as well.
+ *
+ * The LM92 is a sensor chip made by National Semiconductor. It reports
+ * its own temperature with a 0.0625 deg resolution and a 0.33 deg
+ * accuracy. Complete datasheet can be obtained from National's website
+ * at:
+ *   http://www.national.com/pf/LM/LM92.html
+ *
+ * This driver also supports the MAX6635 sensor chip made by Maxim.
+ * This chip is compatible with the LM92, but has a lesser accuracy
+ * (1.0 deg). Complete datasheet can be obtained from Maxim's website
+ * at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
+ *
+ * Since the LM92 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * Support could easily be added for the National Semiconductor LM76
+ * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible
+ * with the LM92.
+ *
+ * This program is free software; you can redistribute it 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+
+/* The LM92 and MAX6635 have 2 two-state pins for address selection,
+   resulting in 4 possible addresses. */
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+				       I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(lm92);
+
+/* The LM92 registers */
+#define LM92_REG_CONFIG			0x01 /* 8-bit, RW */
+#define LM92_REG_TEMP			0x00 /* 16-bit, RO */
+#define LM92_REG_TEMP_HYST		0x02 /* 16-bit, RW */
+#define LM92_REG_TEMP_CRIT		0x03 /* 16-bit, RW */
+#define LM92_REG_TEMP_LOW		0x04 /* 16-bit, RW */
+#define LM92_REG_TEMP_HIGH		0x05 /* 16-bit, RW */
+#define LM92_REG_MAN_ID			0x07 /* 16-bit, RO, LM92 only */
+
+/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius,
+   left-justified in 16-bit registers. No rounding is done, with such
+   a resolution it's just not worth it. Note that the MAX6635 doesn't
+   make use of the 4 lower bits for limits (i.e. effective resolution
+   for limits is 1 degree Celsius). */
+static inline int TEMP_FROM_REG(s16 reg)
+{
+	return reg / 8 * 625 / 10;
+}
+
+static inline s16 TEMP_TO_REG(int val)
+{
+	if (val <= -60000)
+		return -60000 * 10 / 625 * 8;
+	if (val >= 160000)
+		return 160000 * 10 / 625 * 8;
+	return val * 10 / 625 * 8;
+}
+
+/* Alarm flags are stored in the 3 LSB of the temperature register */
+static inline u8 ALARMS_FROM_REG(s16 reg)
+{
+	return reg & 0x0007;
+}
+
+/* Driver data (common to all clients) */
+static struct i2c_driver lm92_driver;
+
+/* Client data (each client gets its own) */
+struct lm92_data {
+	struct i2c_client client;
+	struct semaphore update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst;
+};
+
+
+/*
+ * Sysfs attributes and callback functions
+ */
+
+static struct lm92_data *lm92_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm92_data *data = i2c_get_clientdata(client);
+
+	down(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ)
+	 || !data->valid) {
+		dev_dbg(&client->dev, "Updating lm92 data\n");
+		data->temp1_input = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP));
+		data->temp1_hyst = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_HYST));
+		data->temp1_crit = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_CRIT));
+		data->temp1_min = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_LOW));
+		data->temp1_max = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_HIGH));
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+#define show_temp(value) \
+static ssize_t show_##value(struct device *dev, char *buf) \
+{ \
+	struct lm92_data *data = lm92_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
+}
+show_temp(temp1_input);
+show_temp(temp1_crit);
+show_temp(temp1_min);
+show_temp(temp1_max);
+
+#define set_temp(value, reg) \
+static ssize_t set_##value(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm92_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
+	data->value = TEMP_TO_REG(val); \
+	i2c_smbus_write_word_data(client, reg, swab16(data->value)); \
+	up(&data->update_lock); \
+	return count; \
+}
+set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
+set_temp(temp1_min, LM92_REG_TEMP_LOW);
+set_temp(temp1_max, LM92_REG_TEMP_HIGH);
+
+static ssize_t show_temp1_crit_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit)
+		       - TEMP_FROM_REG(data->temp1_hyst));
+}
+static ssize_t show_temp1_max_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max)
+		       - TEMP_FROM_REG(data->temp1_hyst));
+}
+static ssize_t show_temp1_min_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min)
+		       + TEMP_FROM_REG(data->temp1_hyst));
+}
+
+static ssize_t set_temp1_crit_hyst(struct device *dev, const char *buf,
+	size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm92_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val;
+	i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST,
+				  swab16(TEMP_TO_REG(data->temp1_hyst)));
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
+static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit,
+	set_temp1_crit);
+static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst,
+	set_temp1_crit_hyst);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min,
+	set_temp1_min);
+static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max,
+	set_temp1_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+
+/*
+ * Detection and registration
+ */
+
+static void lm92_init_client(struct i2c_client *client)
+{
+	u8 config;
+
+	/* Start the conversions if needed */
+	config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	if (config & 0x01)
+		i2c_smbus_write_byte_data(client, LM92_REG_CONFIG,
+					  config & 0xFE);
+}
+
+/* The MAX6635 has no identification register, so we have to use tricks
+   to identify it reliably. This is somewhat slow.
+   Note that we do NOT rely on the 2 MSB of the configuration register
+   always reading 0, as suggested by the datasheet, because it was once
+   reported not to be true. */
+static int max6635_check(struct i2c_client *client)
+{
+	u16 temp_low, temp_high, temp_hyst, temp_crit;
+	u8 conf;
+	int i;
+
+	/* No manufacturer ID register, so a read from this address will
+	   always return the last read value. */
+	temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)
+		return 0;
+	temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high)
+		return 0;
+	
+	/* Limits are stored as integer values (signed, 9-bit). */
+	if ((temp_low & 0x7f00) || (temp_high & 0x7f00))
+		return 0;
+	temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST);
+	temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT);
+	if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
+		return 0;
+
+	/* Registers addresses were found to cycle over 16-byte boundaries.
+	   We don't test all registers with all offsets so as to save some
+	   reads and time, but this should still be sufficient to dismiss
+	   non-MAX6635 chips. */
+	conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	for (i=16; i<96; i*=2) {
+		if (temp_hyst != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_HYST + i - 16)
+		 || temp_crit != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_CRIT + i)
+		 || temp_low != i2c_smbus_read_word_data(client,
+				LM92_REG_TEMP_LOW + i + 16)
+		 || temp_high != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_HIGH + i + 32)
+		 || conf != i2c_smbus_read_byte_data(client,
+		 	    LM92_REG_CONFIG + i))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* The following function does more than just detection. If detection
+   succeeds, it also registers the new chip. */
+static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct lm92_data *data;
+	int err = 0;
+	char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+					    | I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct lm92_data));
+
+	/* Fill in enough client fields so that we can read from the chip,
+	   which is required for identication */
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &lm92_driver;
+	new_client->flags = 0;
+
+	/* A negative kind means that the driver was loaded with no force
+	   parameter (default), so we must identify the chip. */
+	if (kind < 0) {
+		u8 config = i2c_smbus_read_byte_data(new_client,
+			     LM92_REG_CONFIG);
+		u16 man_id = i2c_smbus_read_word_data(new_client,
+			     LM92_REG_MAN_ID);
+
+		if ((config & 0xe0) == 0x00
+		 && man_id == 0x0180) {
+			pr_info("lm92: Found National Semiconductor LM92 chip\n");
+	 		kind = lm92;
+		} else
+		if (max6635_check(new_client)) {
+			pr_info("lm92: Found Maxim MAX6635 chip\n");
+			kind = lm92; /* No separate prefix */
+		}
+		else
+			goto exit_free;
+	} else
+	if (kind == 0) /* Default to an LM92 if forced */
+		kind = lm92;
+
+	/* Give it the proper name */
+	if (kind == lm92) {
+		name = "lm92";
+	} else { /* Supposedly cannot happen */
+		dev_dbg(&new_client->dev, "Kind out of range?\n");
+		goto exit_free;
+	}
+
+	/* Fill in the remaining client fields */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the i2c subsystem a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the chipset */
+	lm92_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int lm92_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_detect(adapter, &addr_data, lm92_detect);
+}
+
+static int lm92_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+
+/*
+ * Module and driver stuff
+ */
+
+static struct i2c_driver lm92_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "lm92",
+	.id		= I2C_DRIVERID_LM92,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= lm92_attach_adapter,
+	.detach_client	= lm92_detach_client,
+};
+
+static int __init sensors_lm92_init(void)
+{
+	return i2c_add_driver(&lm92_driver);
+}
+
+static void __exit sensors_lm92_exit(void)
+{
+	i2c_del_driver(&lm92_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("LM92/MAX6635 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm92_init);
+module_exit(sensors_lm92_exit);
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/m41t00.c
@@ -0,0 +1,246 @@
+/*
+ * drivers/i2c/chips/m41t00.c
+ *
+ * I2C client/driver for the ST M41T00 Real-Time Clock chip.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+/*
+ * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
+ * interface and the SMBus interface of the i2c subsystem.
+ * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+ * recommened in .../Documentation/i2c/writing-clients section
+ * "Sending and receiving", using SMBus level communication is preferred.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/time.h>
+#include <asm/rtc.h>
+
+#define	M41T00_DRV_NAME		"m41t00"
+
+static DECLARE_MUTEX(m41t00_mutex);
+
+static struct i2c_driver m41t00_driver;
+static struct i2c_client *save_client;
+
+static unsigned short ignore[] = { I2C_CLIENT_END };
+static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+	.normal_i2c		= normal_addr,
+	.normal_i2c_range	= ignore,
+	.probe			= ignore,
+	.probe_range		= ignore,
+	.ignore			= ignore,
+	.ignore_range		= ignore,
+	.force			= ignore,
+};
+
+ulong
+m41t00_get_rtc_time(void)
+{
+	s32	sec, min, hour, day, mon, year;
+	s32	sec1, min1, hour1, day1, mon1, year1;
+	ulong	limit = 10;
+
+	sec = min = hour = day = mon = year = 0;
+	sec1 = min1 = hour1 = day1 = mon1 = year1 = 0;
+
+	down(&m41t00_mutex);
+	do {
+		if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0)
+			&& ((min = i2c_smbus_read_byte_data(save_client, 1))
+				>= 0)
+			&& ((hour = i2c_smbus_read_byte_data(save_client, 2))
+				>= 0)
+			&& ((day = i2c_smbus_read_byte_data(save_client, 4))
+				>= 0)
+			&& ((mon = i2c_smbus_read_byte_data(save_client, 5))
+				>= 0)
+			&& ((year = i2c_smbus_read_byte_data(save_client, 6))
+				>= 0)
+			&& ((sec == sec1) && (min == min1) && (hour == hour1)
+				&& (day == day1) && (mon == mon1)
+				&& (year == year1)))
+
+				break;
+
+		sec1 = sec;
+		min1 = min;
+		hour1 = hour;
+		day1 = day;
+		mon1 = mon;
+		year1 = year;
+	} while (--limit > 0);
+	up(&m41t00_mutex);
+
+	if (limit == 0) {
+		dev_warn(&save_client->dev,
+			"m41t00: can't read rtc chip\n");
+		sec = min = hour = day = mon = year = 0;
+	}
+
+	sec &= 0x7f;
+	min &= 0x7f;
+	hour &= 0x3f;
+	day &= 0x3f;
+	mon &= 0x1f;
+	year &= 0xff;
+
+	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 += 1900;
+	if (year < 1970)
+		year += 100;
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+static void
+m41t00_set_tlet(ulong arg)
+{
+	struct rtc_time	tm;
+	ulong	nowtime = *(ulong *)arg;
+
+	to_tm(nowtime, &tm);
+	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);
+
+	down(&m41t00_mutex);
+	if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0)
+		|| (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f)
+			< 0)
+		|| (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x7f)
+			< 0)
+		|| (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x7f)
+			< 0)
+		|| (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x7f)
+			< 0)
+		|| (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0x7f)
+			< 0))
+
+		dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n");
+
+	up(&m41t00_mutex);
+	return;
+}
+
+ulong	new_time;
+
+DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time);
+
+int
+m41t00_set_rtc_time(ulong nowtime)
+{
+	new_time = nowtime;
+
+	if (in_interrupt())
+		tasklet_schedule(&m41t00_tasklet);
+	else
+		m41t00_set_tlet((ulong)&new_time);
+
+	return 0;
+}
+
+/*
+ *****************************************************************************
+ *
+ *	Driver Interface
+ *
+ *****************************************************************************
+ */
+static int
+m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct i2c_client *client;
+	int rc;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
+
+	memset(client, 0, sizeof(struct i2c_client));
+	strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE);
+	client->flags = I2C_DF_NOTIFY;
+	client->addr = addr;
+	client->adapter = adap;
+	client->driver = &m41t00_driver;
+
+	if ((rc = i2c_attach_client(client)) != 0) {
+		kfree(client);
+		return rc;
+	}
+
+	save_client = client;
+	return 0;
+}
+
+static int
+m41t00_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, m41t00_probe);
+}
+
+static int
+m41t00_detach(struct i2c_client *client)
+{
+	int	rc;
+
+	if ((rc = i2c_detach_client(client)) == 0) {
+		kfree(i2c_get_clientdata(client));
+		tasklet_kill(&m41t00_tasklet);
+	}
+	return rc;
+}
+
+static struct i2c_driver m41t00_driver = {
+	.owner		= THIS_MODULE,
+	.name		= M41T00_DRV_NAME,
+	.id		= I2C_DRIVERID_STM41T00,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= m41t00_attach,
+	.detach_client	= m41t00_detach,
+};
+
+static int __init
+m41t00_init(void)
+{
+	return i2c_add_driver(&m41t00_driver);
+}
+
+static void __exit
+m41t00_exit(void)
+{
+	i2c_del_driver(&m41t00_driver);
+	return;
+}
+
+module_init(m41t00_init);
+module_exit(m41t00_exit);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c
--- a/drivers/i2c/chips/max1619.c
+++ b/drivers/i2c/chips/max1619.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -117,12 +118,6 @@ struct max1619_data {
 };
 
 /*
- * Internal variables
- */
-
-static int max1619_id;
-
-/*
  * Sysfs stuff
  */
 
@@ -146,8 +141,11 @@ static ssize_t set_##value(struct device
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct max1619_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->value = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
+	up(&data->update_lock); \
 	return count; \
 }
 
@@ -267,7 +265,6 @@ static int max1619_detect(struct i2c_ada
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-	new_client->id = max1619_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -331,10 +328,7 @@ static struct max1619_data *max1619_upda
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ * 2) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
-		
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		dev_dbg(&client->dev, "Updating max1619 data.\n");
 		data->temp_input1 = i2c_smbus_read_byte_data(client,
 					MAX1619_REG_R_LOCAL_TEMP);
diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c
--- a/drivers/i2c/chips/pc87360.c
+++ b/drivers/i2c/chips/pc87360.c
@@ -37,6 +37,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -258,6 +259,7 @@ static ssize_t set_fan_min(struct device
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long fan_min = simple_strtol(buf, NULL, 10);
 
+	down(&data->update_lock);
 	fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
 
 	/* If it wouldn't fit, change clock divisor */
@@ -274,6 +276,7 @@ static ssize_t set_fan_min(struct device
 	/* Write new divider, preserve alarm bits */
 	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
 			    data->fan_status[nr] & 0xF9);
+	up(&data->update_lock);
 
 	return count;
 }
@@ -335,10 +338,13 @@ static ssize_t set_pwm##offset(struct de
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->pwm[offset-1] = PWM_TO_REG(val, \
 			      FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
 	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
 			    data->pwm[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
@@ -377,9 +383,12 @@ static ssize_t set_in##offset##_min(stru
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
 	pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
 			    data->in_min[offset]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
@@ -388,10 +397,13 @@ static ssize_t set_in##offset##_max(stru
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_max[offset] = IN_TO_REG(val, \
 			       data->in_vref); \
 	pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
 			    data->in_max[offset]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
@@ -450,9 +462,12 @@ static ssize_t set_temp##offset##_min(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
 	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
 			    data->in_min[offset+7]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
@@ -461,9 +476,12 @@ static ssize_t set_temp##offset##_max(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
 	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
 			    data->in_max[offset+7]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
@@ -472,9 +490,12 @@ static ssize_t set_temp##offset##_crit(s
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
 	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
 			    data->in_crit[offset-4]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
@@ -551,9 +572,12 @@ static ssize_t set_temp##offset##_min(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->temp_min[offset-1] = TEMP_TO_REG(val); \
 	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
 			    data->temp_min[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
@@ -562,9 +586,12 @@ static ssize_t set_temp##offset##_max(st
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->temp_max[offset-1] = TEMP_TO_REG(val); \
 	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
 			    data->temp_max[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
@@ -573,9 +600,12 @@ static ssize_t set_temp##offset##_crit(s
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct pc87360_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
+ \
+	down(&data->update_lock); \
 	data->temp_crit[offset-1] = TEMP_TO_REG(val); \
 	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
 			    data->temp_crit[offset-1]); \
+	up(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
@@ -1174,8 +1204,7 @@ static struct pc87360_data *pc87360_upda
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ * 2)
-	 || (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		dev_dbg(&client->dev, "Data update\n");
 
 		/* Fans */
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -56,7 +56,6 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a);
 /* Each client has this additional data */
 struct pcf8574_data {
 	struct i2c_client client;
-	struct semaphore update_lock;
 
 	u8 read, write;			/* Register values */
 };
@@ -65,7 +64,6 @@ static int pcf8574_attach_adapter(struct
 static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind);
 static int pcf8574_detach_client(struct i2c_client *client);
 static void pcf8574_init_client(struct i2c_client *client);
-static struct pcf8574_data *pcf8574_update_client(struct device *dev);
 
 /* This is the driver that will be inserted */
 static struct i2c_driver pcf8574_driver = {
@@ -77,12 +75,12 @@ static struct i2c_driver pcf8574_driver 
 	.detach_client	= pcf8574_detach_client,
 };
 
-static int pcf8574_id;
-
 /* following are the sysfs callback functions */
 static ssize_t show_read(struct device *dev, char *buf)
 {
-	struct pcf8574_data *data = pcf8574_update_client(dev);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8574_data *data = i2c_get_clientdata(client);
+	data->read = i2c_smbus_read_byte(client); 
 	return sprintf(buf, "%u\n", data->read);
 }
 
@@ -99,7 +97,12 @@ static ssize_t set_write(struct device *
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pcf8574_data *data = i2c_get_clientdata(client);
-	data->write = simple_strtoul(buf, NULL, 10);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	if (val > 0xff)
+		return -EINVAL;
+
+	data->write = val;
 	i2c_smbus_write_byte(client, data->write);
 	return count;
 }
@@ -160,9 +163,6 @@ int pcf8574_detect(struct i2c_adapter *a
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
 
-	new_client->id = pcf8574_id++;
-	init_MUTEX(&data->update_lock);
-
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
 		goto exit_free;
@@ -206,19 +206,6 @@ static void pcf8574_init_client(struct i
 	i2c_smbus_write_byte(client, data->write);
 }
 
-static struct pcf8574_data *pcf8574_update_client(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pcf8574_data *data = i2c_get_clientdata(client);
-
-	down(&data->update_lock);
-	dev_dbg(&client->dev, "Starting pcf8574 update\n");
-	data->read = i2c_smbus_read_byte(client); 
-	up(&data->update_lock);
-	
-	return data;
-}
-
 static int __init pcf8574_init(void)
 {
 	return i2c_add_driver(&pcf8574_driver);
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -98,8 +98,6 @@ static struct i2c_driver pcf8591_driver 
 	.detach_client	= pcf8591_detach_client,
 };
 
-static int pcf8591_id;
-
 /* following are the sysfs callback functions */
 #define show_in_channel(channel)					\
 static ssize_t show_in##channel##_input(struct device *dev, char *buf)	\
@@ -146,11 +144,15 @@ static ssize_t set_out0_enable(struct de
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pcf8591_data *data = i2c_get_clientdata(client);
-	if (simple_strtoul(buf, NULL, 10))
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	if (val)
 		data->control |= PCF8591_CONTROL_AOEF;
 	else
 		data->control &= ~PCF8591_CONTROL_AOEF;
 	i2c_smbus_write_byte(client, data->control);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -201,8 +203,6 @@ int pcf8591_detect(struct i2c_adapter *a
 	/* Fill in the remaining client fields and put it into the global 
 	   list */
 	strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE);
-
-	new_client->id = pcf8591_id++;
 	init_MUTEX(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c
--- a/drivers/i2c/chips/rtc8564.c
+++ b/drivers/i2c/chips/rtc8564.c
@@ -89,7 +89,7 @@ static int rtc8564_read(struct i2c_clien
 
 	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len);
 
-	if (!buf || !client) {
+	if (!buf) {
 		ret = -EINVAL;
 		goto done;
 	}
@@ -111,7 +111,7 @@ static int rtc8564_write(struct i2c_clie
 	struct i2c_msg wr;
 	int i;
 
-	if (!client || !data || len > 15) {
+	if (!data || len > 15) {
 		ret = -EINVAL;
 		goto done;
 	}
@@ -163,14 +163,12 @@ static int rtc8564_attach(struct i2c_ada
 
 	strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
 	i2c_set_clientdata(new_client, d);
-	new_client->id = rtc8564_driver.id;
 	new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY;
 	new_client->addr = addr;
 	new_client->adapter = adap;
 	new_client->driver = &rtc8564_driver;
 
 	_DBG(1, "client=%p", new_client);
-	_DBG(1, "client.id=%d", new_client->id);
 
 	/* init ctrl1 reg */
 	data[0] = 0;
@@ -222,7 +220,7 @@ static int rtc8564_get_datetime(struct i
 
 	_DBG(1, "client=%p, dt=%p", client, dt);
 
-	if (!dt || !client)
+	if (!dt)
 		return -EINVAL;
 
 	memset(buf, 0, sizeof(buf));
@@ -256,7 +254,7 @@ rtc8564_set_datetime(struct i2c_client *
 
 	_DBG(1, "client=%p, dt=%p", client, dt);
 
-	if (!dt || !client)
+	if (!dt)
 		return -EINVAL;
 
 	_DBGRTCTM(2, *dt);
@@ -295,7 +293,7 @@ static int rtc8564_get_ctrl(struct i2c_c
 {
 	struct rtc8564_data *data = i2c_get_clientdata(client);
 
-	if (!ctrl || !client)
+	if (!ctrl)
 		return -1;
 
 	*ctrl = data->ctrl;
@@ -307,7 +305,7 @@ static int rtc8564_set_ctrl(struct i2c_c
 	struct rtc8564_data *data = i2c_get_clientdata(client);
 	unsigned char buf[2];
 
-	if (!ctrl || !client)
+	if (!ctrl)
 		return -1;
 
 	buf[0] = *ctrl & 0xff;
@@ -320,7 +318,7 @@ static int rtc8564_set_ctrl(struct i2c_c
 static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
 {
 
-	if (!mem || !client)
+	if (!mem)
 		return -EINVAL;
 
 	return rtc8564_read(client, mem->loc, mem->data, mem->nr);
@@ -329,7 +327,7 @@ static int rtc8564_read_mem(struct i2c_c
 static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
 {
 
-	if (!mem || !client)
+	if (!mem)
 		return -EINVAL;
 
 	return rtc8564_write(client, mem->loc, mem->data, mem->nr);
diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c
new file mode 100644
--- /dev/null
+++ b/drivers/i2c/chips/sis5595.c
@@ -0,0 +1,816 @@
+/*
+    sis5595.c - Part of lm_sensors, Linux kernel modules
+		for hardware monitoring
+
+    Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
+			Kyösti Mälkki <kmalkki@cc.hut.fi>, and
+			Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
+    the help of Jean Delvare <khali@linux-fr.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 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.
+*/
+
+/*
+   SiS southbridge has a LM78-like chip integrated on the same IC.
+   This driver is a customized copy of lm78.c
+   
+   Supports following revisions:
+	Version		PCI ID		PCI Revision
+	1		1039/0008	AF or less
+	2		1039/0008	B0 or greater
+
+   Note: these chips contain a 0008 device which is incompatible with the
+	 5595. We recognize these by the presence of the listed
+	 "blacklist" PCI ID and refuse to load.
+
+   NOT SUPPORTED	PCI ID		BLACKLIST PCI ID	
+	 540		0008		0540
+	 550		0008		0550
+	5513		0008		5511
+	5581		0008		5597
+	5582		0008		5597
+	5597		0008		5597
+	5598		0008		5597/5598
+	 630		0008		0630
+	 645		0008		0645
+	 730		0008		0730
+	 735		0008		0735
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the device at the given address. */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+
+/* Addresses to scan.
+   Note that we can't determine the ISA address until we have initialized
+   our module */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(sis5595);
+
+/* Many SIS5595 constants specified below */
+
+/* Length of ISA address segment */
+#define SIS5595_EXTENT 8
+/* PCI Config Registers */
+#define SIS5595_REVISION_REG 0x08
+#define SIS5595_BASE_REG 0x68
+#define SIS5595_PIN_REG 0x7A
+#define SIS5595_ENABLE_REG 0x7B
+
+/* Where are the ISA address/data registers relative to the base address */
+#define SIS5595_ADDR_REG_OFFSET 5
+#define SIS5595_DATA_REG_OFFSET 6
+
+/* The SIS5595 registers */
+#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
+#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
+#define SIS5595_REG_IN(nr) (0x20 + (nr))
+
+#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
+#define SIS5595_REG_FAN(nr) (0x28 + (nr))
+
+/* On the first version of the chip, the temp registers are separate.
+   On the second version,
+   TEMP pin is shared with IN4, configured in PCI register 0x7A.
+   The registers are the same as well.
+   OVER and HYST are really MAX and MIN. */
+
+#define REV2MIN	0xb0
+#define SIS5595_REG_TEMP 	(( data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN(4) : 0x27
+#define SIS5595_REG_TEMP_OVER	(( data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN_MAX(4) : 0x39
+#define SIS5595_REG_TEMP_HYST	(( data->revision) >= REV2MIN) ? \
+					SIS5595_REG_IN_MIN(4) : 0x3a
+
+#define SIS5595_REG_CONFIG 0x40
+#define SIS5595_REG_ALARM1 0x41
+#define SIS5595_REG_ALARM2 0x42
+#define SIS5595_REG_FANDIV 0x47
+
+/* Conversions. Limit checking is only done on the TO_REG
+   variants. */
+
+/* IN: mV, (0V to 4.08V)
+   REG: 16mV/bit */
+static inline u8 IN_TO_REG(unsigned long val)
+{
+	unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+	return (nval + 8) / 16;
+}
+#define IN_FROM_REG(val) ((val) *  16)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm <= 0)
+		return 255;
+	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+static inline int FAN_FROM_REG(u8 val, int div)
+{
+	return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
+}
+
+/* TEMP: mC (-54.12C to +157.53C)
+   REG: 0.83C/bit + 52.12, two's complement  */
+static inline int TEMP_FROM_REG(s8 val)
+{
+	return val * 830 + 52120;
+}
+static inline s8 TEMP_TO_REG(int val)
+{
+	int nval = SENSORS_LIMIT(val, -54120, 157530) ;
+	return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830;
+}
+
+/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
+   REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
+static inline u8 DIV_TO_REG(int val)
+{
+	return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
+}
+#define DIV_FROM_REG(val) (1 << (val))
+
+/* For the SIS5595, we need to keep some data in memory. That
+   data is pointed to by sis5595_list[NR]->data. The structure itself is
+   dynamically allocated, at the time when the new sis5595 client is
+   allocated. */
+struct sis5595_data {
+	struct i2c_client client;
+	struct semaphore lock;
+
+	struct semaphore update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
+	u8 revision;		/* Reg. value */
+
+	u8 in[5];		/* Register value */
+	u8 in_max[5];		/* Register value */
+	u8 in_min[5];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_over;		/* Register value */
+	s8 temp_hyst;		/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
+
+static int sis5595_attach_adapter(struct i2c_adapter *adapter);
+static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind);
+static int sis5595_detach_client(struct i2c_client *client);
+
+static int sis5595_read_value(struct i2c_client *client, u8 register);
+static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value);
+static struct sis5595_data *sis5595_update_device(struct device *dev);
+static void sis5595_init_client(struct i2c_client *client);
+
+static struct i2c_driver sis5595_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "sis5595",
+	.id		= I2C_DRIVERID_SIS5595,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= sis5595_attach_adapter,
+	.detach_client	= sis5595_detach_client,
+};
+
+/* 4 Voltages */
+static ssize_t show_in(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t set_in_min(struct device *dev, const char *buf,
+	       size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->in_min[nr] = IN_TO_REG(val);
+	sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t set_in_max(struct device *dev, const char *buf,
+	       size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->in_max[nr] = IN_TO_REG(val);
+	sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+#define show_in_offset(offset)					\
+static ssize_t							\
+	show_in##offset (struct device *dev, char *buf)		\
+{								\
+	return show_in(dev, buf, offset);			\
+}								\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, 		\
+		show_in##offset, NULL);				\
+static ssize_t							\
+	show_in##offset##_min (struct device *dev, char *buf)	\
+{								\
+	return show_in_min(dev, buf, offset);			\
+}								\
+static ssize_t							\
+	show_in##offset##_max (struct device *dev, char *buf)	\
+{								\
+	return show_in_max(dev, buf, offset);			\
+}								\
+static ssize_t set_in##offset##_min (struct device *dev,	\
+		const char *buf, size_t count)			\
+{								\
+	return set_in_min(dev, buf, count, offset);		\
+}								\
+static ssize_t set_in##offset##_max (struct device *dev,	\
+		const char *buf, size_t count)			\
+{								\
+	return set_in_max(dev, buf, count, offset);		\
+}								\
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_in##offset##_min, set_in##offset##_min);	\
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
+		show_in##offset##_max, set_in##offset##_max);
+
+show_in_offset(0);
+show_in_offset(1);
+show_in_offset(2);
+show_in_offset(3);
+show_in_offset(4);
+
+/* Temperature */
+static ssize_t show_temp(struct device *dev, char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
+}
+
+static ssize_t show_temp_over(struct device *dev, char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
+}
+
+static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_over = TEMP_TO_REG(val);
+	sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_hyst(struct device *dev, char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
+}
+
+static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->temp_hyst = TEMP_TO_REG(val);
+	sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		show_temp_over, set_temp_over);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		show_temp_hyst, set_temp_hyst);
+
+/* 2 Fans */
+static ssize_t show_fan(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+		DIV_FROM_REG(data->fan_div[nr])) );
+}
+
+static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
+		DIV_FROM_REG(data->fan_div[nr])) );
+}
+
+static ssize_t set_fan_min(struct device *dev, const char *buf,
+		size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan divisor.  This follows the principle of
+   least suprise; the user doesn't expect the fan minimum to change just
+   because the divisor changed. */
+static ssize_t set_fan_div(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	unsigned long min;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+	int reg;
+
+	down(&data->update_lock);
+	min = FAN_FROM_REG(data->fan_min[nr],
+			DIV_FROM_REG(data->fan_div[nr]));
+	reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
+
+	switch (val) {
+	case 1: data->fan_div[nr] = 0; break;
+	case 2: data->fan_div[nr] = 1; break;
+	case 4: data->fan_div[nr] = 2; break;
+	case 8: data->fan_div[nr] = 3; break;
+	default:
+		dev_err(&client->dev, "fan_div value %ld not "
+			"supported. Choose one of 1, 2, 4 or 8!\n", val);
+		up(&data->update_lock);
+		return -EINVAL;
+	}
+	
+	switch (nr) {
+	case 0:
+		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
+		break;
+	case 1:
+		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
+		break;
+	}
+	sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
+	data->fan_min[nr] =
+		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+#define show_fan_offset(offset)						\
+static ssize_t show_fan_##offset (struct device *dev, char *buf)	\
+{									\
+	return show_fan(dev, buf, offset - 1);			\
+}									\
+static ssize_t show_fan_##offset##_min (struct device *dev, char *buf)	\
+{									\
+	return show_fan_min(dev, buf, offset - 1);			\
+}									\
+static ssize_t show_fan_##offset##_div (struct device *dev, char *buf)	\
+{									\
+	return show_fan_div(dev, buf, offset - 1);			\
+}									\
+static ssize_t set_fan_##offset##_min (struct device *dev,		\
+		const char *buf, size_t count)				\
+{									\
+	return set_fan_min(dev, buf, count, offset - 1);		\
+}									\
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_##offset##_min, set_fan_##offset##_min);
+
+show_fan_offset(1);
+show_fan_offset(2);
+
+static ssize_t set_fan_1_div(struct device *dev, const char *buf,
+		size_t count)
+{
+	return set_fan_div(dev, buf, count, 0) ;
+}
+
+static ssize_t set_fan_2_div(struct device *dev, const char *buf,
+		size_t count)
+{
+	return set_fan_div(dev, buf, count, 1) ;
+}
+static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		show_fan_1_div, set_fan_1_div);
+static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		show_fan_2_div, set_fan_2_div);
+
+/* Alarms */
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+ 
+/* This is called when the module is loaded */
+static int sis5595_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_detect(adapter, &addr_data, sis5595_detect);
+}
+
+int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	int i;
+	struct i2c_client *new_client;
+	struct sis5595_data *data;
+	char val;
+	u16 a;
+
+	/* Make sure we are probing the ISA bus!!  */
+	if (!i2c_is_isa_adapter(adapter))
+		goto exit;
+
+	if (force_addr)
+		address = force_addr & ~(SIS5595_EXTENT - 1);
+	/* Reserve the ISA region */
+	if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) {
+		err = -EBUSY;
+		goto exit;
+	}
+	if (force_addr) {
+		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
+			goto exit_release;
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
+			goto exit_release;
+		if ((a & ~(SIS5595_EXTENT - 1)) != address)
+			/* doesn't work for some chips? */
+			goto exit_release;
+	}
+
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
+		goto exit_release;
+	}
+	if ((val & 0x80) == 0) {
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
+					  val | 0x80))
+			goto exit_release;
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
+			goto exit_release;
+		if ((val & 0x80) == 0) 
+			/* doesn't work for some chips! */
+			goto exit_release;
+	}
+
+	if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	memset(data, 0, sizeof(struct sis5595_data));
+
+	new_client = &data->client;
+	new_client->addr = address;
+	init_MUTEX(&data->lock);
+	i2c_set_clientdata(new_client, data);
+	new_client->adapter = adapter;
+	new_client->driver = &sis5595_driver;
+	new_client->flags = 0;
+
+	/* Check revision and pin registers to determine whether 4 or 5 voltages */
+	pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
+	/* 4 voltages, 1 temp */
+	data->maxins = 3;
+	if (data->revision >= REV2MIN) {
+		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
+		if (!(val & 0x80))
+			/* 5 voltages, no temps */
+			data->maxins = 4;
+	}
+	
+	/* Fill in the remaining client fields and put it into the global list */
+	strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
+
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+	
+	/* Initialize the SIS5595 chip */
+	sis5595_init_client(new_client);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 2; i++) {
+		data->fan_min[i] = sis5595_read_value(new_client,
+					SIS5595_REG_FAN_MIN(i));
+	}
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	if (data->maxins == 4) {
+		device_create_file(&new_client->dev, &dev_attr_in4_input);
+		device_create_file(&new_client->dev, &dev_attr_in4_min);
+		device_create_file(&new_client->dev, &dev_attr_in4_max);
+	}
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+	if (data->maxins == 3) {
+		device_create_file(&new_client->dev, &dev_attr_temp1_input);
+		device_create_file(&new_client->dev, &dev_attr_temp1_max);
+		device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	}
+	return 0;
+	
+exit_free:
+	kfree(data);
+exit_release:
+	release_region(address, SIS5595_EXTENT);
+exit:
+	return err;
+}
+
+static int sis5595_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev,
+		    "Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	if (i2c_is_isa_client(client))
+		release_region(client->addr, SIS5595_EXTENT);
+
+	kfree(i2c_get_clientdata(client));
+
+	return 0;
+}
+
+
+/* ISA access must be locked explicitly. */
+static int sis5595_read_value(struct i2c_client *client, u8 reg)
+{
+	int res;
+
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	down(&data->lock);
+	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
+	res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
+	up(&data->lock);
+	return res;
+}
+
+static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	down(&data->lock);
+	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
+	outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
+	up(&data->lock);
+	return 0;
+}
+
+/* Called when we have found a new SIS5595. */
+static void sis5595_init_client(struct i2c_client *client)
+{
+	u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
+	if (!(config & 0x01))
+		sis5595_write_value(client, SIS5595_REG_CONFIG,
+				(config & 0xf7) | 0x01);
+}
+
+static struct sis5595_data *sis5595_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sis5595_data *data = i2c_get_clientdata(client);
+	int i;
+
+	down(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+
+		for (i = 0; i <= data->maxins; i++) {
+			data->in[i] =
+			    sis5595_read_value(client, SIS5595_REG_IN(i));
+			data->in_min[i] =
+			    sis5595_read_value(client,
+					       SIS5595_REG_IN_MIN(i));
+			data->in_max[i] =
+			    sis5595_read_value(client,
+					       SIS5595_REG_IN_MAX(i));
+		}
+		for (i = 0; i < 2; i++) {
+			data->fan[i] =
+			    sis5595_read_value(client, SIS5595_REG_FAN(i));
+			data->fan_min[i] =
+			    sis5595_read_value(client,
+					       SIS5595_REG_FAN_MIN(i));
+		}
+		if (data->maxins == 3) {
+			data->temp =
+			    sis5595_read_value(client, SIS5595_REG_TEMP);
+			data->temp_over =
+			    sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
+			data->temp_hyst =
+			    sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
+		}
+		i = sis5595_read_value(client, SIS5595_REG_FANDIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = i >> 6;
+		data->alarms =
+		    sis5595_read_value(client, SIS5595_REG_ALARM1) |
+		    (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+static struct pci_device_id sis5595_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
+
+static int blacklist[] __devinitdata = {
+	PCI_DEVICE_ID_SI_540,
+	PCI_DEVICE_ID_SI_550,
+	PCI_DEVICE_ID_SI_630,
+	PCI_DEVICE_ID_SI_645,
+	PCI_DEVICE_ID_SI_730,
+	PCI_DEVICE_ID_SI_735,
+	PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
+				  that ID shows up in other chips so we
+				  use the 5511 ID for recognition */
+	PCI_DEVICE_ID_SI_5597,
+	PCI_DEVICE_ID_SI_5598,
+	0 };
+
+static int __devinit sis5595_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	u16 val;
+	int *i;
+	int addr = 0;
+
+	for (i = blacklist; *i != 0; i++) {
+		struct pci_dev *dev;
+		dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
+		if (dev) {
+			dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+			pci_dev_put(dev);
+			return -ENODEV;
+		}
+	}
+	
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_word(dev, SIS5595_BASE_REG, &val))
+		return -ENODEV;
+	
+	addr = val & ~(SIS5595_EXTENT - 1);
+	if (addr == 0 && force_addr == 0) {
+		dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+	if (force_addr)
+		addr = force_addr;	/* so detect will get called */
+
+	if (!addr) {
+		dev_err(&dev->dev,"No SiS 5595 sensors found.\n");
+		return -ENODEV;
+	}
+	normal_isa[0] = addr;
+
+	s_bridge = pci_dev_get(dev);
+	if (i2c_add_driver(&sis5595_driver)) {
+		pci_dev_put(s_bridge);
+		s_bridge = NULL;
+	}
+
+	/* Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+	return -ENODEV;
+}
+
+static struct pci_driver sis5595_pci_driver = {
+	.name            = "sis5595",
+	.id_table        = sis5595_pci_ids,
+	.probe           = sis5595_pci_probe,
+};
+
+static int __init sm_sis5595_init(void)
+{
+	return pci_register_driver(&sis5595_pci_driver);
+}
+
+static void __exit sm_sis5595_exit(void)
+{
+	pci_unregister_driver(&sis5595_pci_driver);
+	if (s_bridge != NULL) {
+		i2c_del_driver(&sis5595_driver);
+		pci_dev_put(s_bridge);
+		s_bridge = NULL;
+	}
+}
+
+MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
+MODULE_DESCRIPTION("SiS 5595 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(sm_sis5595_init);
+module_exit(sm_sis5595_exit);
diff --git a/drivers/i2c/chips/smsc47b397.c b/drivers/i2c/chips/smsc47b397.c
--- a/drivers/i2c/chips/smsc47b397.c
+++ b/drivers/i2c/chips/smsc47b397.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/init.h>
@@ -130,9 +131,7 @@ static struct smsc47b397_data *smsc47b39
 
 	down(&data->update_lock);
 
-	if (time_after(jiffies - data->last_updated, (unsigned long)HZ)
-		|| time_before(jiffies, data->last_updated) || !data->valid) {
-
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		dev_dbg(&client->dev, "starting device update...\n");
 
 		/* 4 temperature inputs, 4 fan inputs */
diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c
--- a/drivers/i2c/chips/smsc47m1.c
+++ b/drivers/i2c/chips/smsc47m1.c
@@ -28,6 +28,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/init.h>
@@ -108,7 +109,6 @@ superio_exit(void)
 struct smsc47m1_data {
 	struct i2c_client client;
 	struct semaphore lock;
-	int sysctl_id;
 
 	struct semaphore update_lock;
 	unsigned long last_updated;	/* In jiffies */
@@ -133,8 +133,6 @@ static struct smsc47m1_data *smsc47m1_up
 		int init);
 
 
-static int smsc47m1_id;
-
 static struct i2c_driver smsc47m1_driver = {
 	.owner		= THIS_MODULE,
 	.name		= "smsc47m1",
@@ -197,16 +195,20 @@ static ssize_t set_fan_min(struct device
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct smsc47m1_data *data = i2c_get_clientdata(client);
+	long rpmdiv, val = simple_strtol(buf, NULL, 10);
 
-	long rpmdiv = simple_strtol(buf, NULL, 10)
-		    * DIV_FROM_REG(data->fan_div[nr]);
+	down(&data->update_lock);
+	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
 
-	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040)
+	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
+		up(&data->update_lock);
 		return -EINVAL;
+	}
 
 	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
 	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
 			     data->fan_preload[nr]);
+	up(&data->update_lock);
 
 	return count;
 }
@@ -226,12 +228,16 @@ static ssize_t set_fan_div(struct device
 
 	if (new_div == old_div) /* No change */
 		return count;
+
+	down(&data->update_lock);
 	switch (new_div) {
 	case 1: data->fan_div[nr] = 0; break;
 	case 2: data->fan_div[nr] = 1; break;
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
-	default: return -EINVAL;
+	default:
+		up(&data->update_lock);
+		return -EINVAL;
 	}
 
 	tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F;
@@ -244,6 +250,7 @@ static ssize_t set_fan_div(struct device
 	data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
 	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
 			     data->fan_preload[nr]);
+	up(&data->update_lock);
 
 	return count;
 }
@@ -259,11 +266,13 @@ static ssize_t set_pwm(struct device *de
 	if (val < 0 || val > 255)
 		return -EINVAL;
 
+	down(&data->update_lock);
 	data->pwm[nr] &= 0x81; /* Preserve additional bits */
 	data->pwm[nr] |= PWM_TO_REG(val);
-
 	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
 			     data->pwm[nr]);
+	up(&data->update_lock);
+
 	return count;
 }
 
@@ -278,11 +287,12 @@ static ssize_t set_pwm_en(struct device 
 	if (val != 0 && val != 1)
 		return -EINVAL;
 
+	down(&data->update_lock);
 	data->pwm[nr] &= 0xFE; /* preserve the other bits */
 	data->pwm[nr] |= !val;
-
 	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
 			     data->pwm[nr]);
+	up(&data->update_lock);
 
 	return count;
 }
@@ -420,8 +430,6 @@ static int smsc47m1_detect(struct i2c_ad
 	new_client->flags = 0;
 
 	strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
-
-	new_client->id = smsc47m1_id++;
 	init_MUTEX(&data->update_lock);
 
 	/* If no function is properly configured, there's no point in
@@ -532,8 +540,7 @@ static struct smsc47m1_data *smsc47m1_up
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || init) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
 		int i;
 
 		for (i = 0; i < 2; i++) {
diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c
--- a/drivers/i2c/chips/via686a.c
+++ b/drivers/i2c/chips/via686a.c
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/init.h>
@@ -362,9 +363,12 @@ static ssize_t set_in_min(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val,nr);
 	via686a_write_value(client, VIA686A_REG_IN_MIN(nr), 
 			data->in_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_in_max(struct device *dev, const char *buf, 
@@ -372,9 +376,12 @@ static ssize_t set_in_max(struct device 
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val,nr);
 	via686a_write_value(client, VIA686A_REG_IN_MAX(nr), 
 			data->in_max[nr]);
+	up(&data->update_lock);
 	return count;
 }
 #define show_in_offset(offset)					\
@@ -433,8 +440,11 @@ static ssize_t set_temp_over(struct devi
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_over[nr] = TEMP_TO_REG(val);
 	via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_hyst(struct device *dev, const char *buf, 
@@ -442,8 +452,11 @@ static ssize_t set_temp_hyst(struct devi
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->temp_hyst[nr] = TEMP_TO_REG(val);
 	via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
+	up(&data->update_lock);
 	return count;
 }
 #define show_temp_offset(offset)					\
@@ -501,8 +514,11 @@ static ssize_t set_fan_min(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	up(&data->update_lock);
 	return count;
 }
 static ssize_t set_fan_div(struct device *dev, const char *buf, 
@@ -510,10 +526,14 @@ static ssize_t set_fan_div(struct device
 	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
-	int old = via686a_read_value(client, VIA686A_REG_FANDIV);
+	int old;
+
+	down(&data->update_lock);
+	old = via686a_read_value(client, VIA686A_REG_FANDIV);
 	data->fan_div[nr] = DIV_TO_REG(val);
 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
 	via686a_write_value(client, VIA686A_REG_FANDIV, old);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -554,7 +574,7 @@ static ssize_t show_alarms(struct device
 	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
 }
-static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
 /* The driver. I choose to use type i2c_driver, as at is identical to both
    smbus_driver and isa_driver, and clients could be of either kind */
@@ -631,10 +651,9 @@ static int via686a_detect(struct i2c_ada
 	new_client->adapter = adapter;
 	new_client->driver = &via686a_driver;
 	new_client->flags = 0;
-	new_client->dev.parent = &adapter->dev;
 
 	/* Fill in the remaining client fields and put into the global list */
-	snprintf(new_client->name, I2C_NAME_SIZE, client_name);
+	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
 
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
@@ -726,9 +745,8 @@ static struct via686a_data *via686a_upda
 
 	down(&data->update_lock);
 
-       if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-           (jiffies < data->last_updated) || !data->valid) {
-
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		for (i = 0; i <= 4; i++) {
 			data->in[i] =
 			    via686a_read_value(client, VIA686A_REG_IN(i));
diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c
--- a/drivers/i2c/chips/w83627hf.c
+++ b/drivers/i2c/chips/w83627hf.c
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -303,7 +304,6 @@ struct w83627hf_data {
 	u32 beep_mask;		/* Register encoding, combined */
 	u8 beep_enable;		/* Boolean */
 	u8 pwm[3];		/* Register value */
-	u8 pwmenable[3];	/* bool */
 	u16 sens[3];		/* 782D/783S only.
 				   1 = pentium diode; 2 = 3904 diode;
 				   3000-5000 = thermistor beta.
@@ -354,10 +354,13 @@ store_in_##reg (struct device *dev, cons
 	u32 val; \
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
+	 \
+	down(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
 			    data->in_##reg[nr]); \
 	 \
+	up(&data->update_lock); \
 	return count; \
 }
 store_in_reg(MIN, min)
@@ -442,6 +445,9 @@ static ssize_t store_regs_in_min0(struct
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+	
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf == data->type || w83637hf == data->type))
 
@@ -452,6 +458,7 @@ static ssize_t store_regs_in_min0(struct
 		data->in_min[0] = IN_TO_REG(val);
 
 	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -463,6 +470,9 @@ static ssize_t store_regs_in_max0(struct
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
+
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf == data->type || w83637hf == data->type))
 		
@@ -473,6 +483,7 @@ static ssize_t store_regs_in_max0(struct
 		data->in_max[0] = IN_TO_REG(val);
 
 	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
+	up(&data->update_lock);
 	return count;
 }
 
@@ -508,11 +519,14 @@ store_fan_min(struct device *dev, const 
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr - 1] =
 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
 	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
 			    data->fan_min[nr - 1]);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -574,6 +588,8 @@ store_temp_##reg (struct device *dev, co
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
 	 \
+	down(&data->update_lock); \
+	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
 		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
@@ -584,6 +600,7 @@ store_temp_##reg (struct device *dev, co
 			data->temp_##reg); \
 	} \
 	 \
+	up(&data->update_lock); \
 	return count; \
 }
 store_temp_reg(OVER, max);
@@ -692,6 +709,8 @@ store_beep_reg(struct device *dev, const
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
 		data->beep_mask = BEEP_MASK_TO_REG(val);
 		w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
@@ -708,6 +727,7 @@ store_beep_reg(struct device *dev, const
 	w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
 			    val2 | data->beep_enable << 7);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -752,12 +772,15 @@ store_fan_div_reg(struct device *dev, co
 	struct w83627hf_data *data = i2c_get_clientdata(client);
 	unsigned long min;
 	u8 reg;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 
 	/* Save fan_min */
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   DIV_FROM_REG(data->fan_div[nr]));
 
-	data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
+	data->fan_div[nr] = DIV_TO_REG(val);
 
 	reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
 	       & (nr==0 ? 0xcf : 0x3f))
@@ -773,6 +796,7 @@ store_fan_div_reg(struct device *dev, co
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -815,6 +839,8 @@ store_pwm_reg(struct device *dev, const 
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	if (data->type == w83627thf) {
 		/* bits 0-3 are reserved  in 627THF */
 		data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
@@ -830,6 +856,7 @@ store_pwm_reg(struct device *dev, const 
 				     data->pwm[nr - 1]);
 	}
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -871,6 +898,8 @@ store_sensor_reg(struct device *dev, con
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
 		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
@@ -903,6 +932,7 @@ store_sensor_reg(struct device *dev, con
 		break;
 	}
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -1316,11 +1346,28 @@ static void w83627hf_init_client(struct 
 			break;
 	}
 
-	data->pwmenable[0] = 1;
-	data->pwmenable[1] = 1;
-	data->pwmenable[2] = 1;
-
 	if(init) {
+		/* Enable temp2 */
+		tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG);
+		if (tmp & 0x01) {
+			dev_warn(&client->dev, "Enabling temp2, readings "
+				 "might not make sense\n");
+			w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG,
+				tmp & 0xfe);
+		}
+
+		/* Enable temp3 */
+		if (type != w83697hf) {
+			tmp = w83627hf_read_value(client,
+				W83781D_REG_TEMP3_CONFIG);
+			if (tmp & 0x01) {
+				dev_warn(&client->dev, "Enabling temp3, "
+					 "readings might not make sense\n");
+				w83627hf_write_value(client,
+					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+			}
+		}
+
 		if (type == w83627hf) {
 			/* enable PWM2 control (can't hurt since PWM reg
 		           should have been reset to 0xff) */
@@ -1350,8 +1397,8 @@ static struct w83627hf_data *w83627hf_up
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		for (i = 0; i <= 8; i++) {
 			/* skip missing sensors */
 			if (((data->type == w83697hf) && (i == 1)) ||
diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
--- a/drivers/i2c/chips/w83781d.c
+++ b/drivers/i2c/chips/w83781d.c
@@ -39,15 +39,13 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-/* RT Table support #defined so we can take it out if it gets bothersome */
-#define W83781D_RT			1
-
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
 					0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
@@ -257,9 +255,6 @@ struct w83781d_data {
 				   3000-5000 = thermistor beta.
 				   Default = 3435. 
 				   Other Betas unimplemented */
-#ifdef W83781D_RT
-	u8 rt[3][32];		/* Register value */
-#endif
 	u8 vrm;
 };
 
@@ -301,9 +296,12 @@ static ssize_t store_in_##reg (struct de
 	u32 val; \
 	 \
 	val = simple_strtoul(buf, NULL, 10) / 10; \
+	 \
+	down(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
 	 \
+	up(&data->update_lock); \
 	return count; \
 }
 store_in_reg(MIN, min);
@@ -368,11 +366,14 @@ store_fan_min(struct device *dev, const 
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
+
+	down(&data->update_lock);
 	data->fan_min[nr - 1] =
 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
 	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
 			    data->fan_min[nr - 1]);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -431,6 +432,8 @@ static ssize_t store_temp_##reg (struct 
 	 \
 	val = simple_strtol(buf, NULL, 10); \
 	 \
+	down(&data->update_lock); \
+	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
 		w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
@@ -441,6 +444,7 @@ static ssize_t store_temp_##reg (struct 
 			data->temp_##reg); \
 	} \
 	 \
+	up(&data->update_lock); \
 	return count; \
 }
 store_temp_reg(OVER, max);
@@ -553,6 +557,8 @@ store_beep_reg(struct device *dev, const
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
 		data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
 		w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
@@ -572,6 +578,7 @@ store_beep_reg(struct device *dev, const
 	w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
 			    val2 | data->beep_enable << 7);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -614,13 +621,15 @@ store_fan_div_reg(struct device *dev, co
 	struct w83781d_data *data = i2c_get_clientdata(client);
 	unsigned long min;
 	u8 reg;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+	
 	/* Save fan_min */
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   DIV_FROM_REG(data->fan_div[nr]));
 
-	data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
-				      data->type);
+	data->fan_div[nr] = DIV_TO_REG(val, data->type);
 
 	reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
 	       & (nr==0 ? 0xcf : 0x3f))
@@ -639,6 +648,7 @@ store_fan_div_reg(struct device *dev, co
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -685,9 +695,10 @@ store_pwm_reg(struct device *dev, const 
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
 	data->pwm[nr - 1] = PWM_TO_REG(val);
 	w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
-
+	up(&data->update_lock);
 	return count;
 }
 
@@ -700,6 +711,8 @@ store_pwmenable_reg(struct device *dev, 
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	switch (val) {
 	case 0:
 	case 1:
@@ -715,9 +728,11 @@ store_pwmenable_reg(struct device *dev, 
 		break;
 
 	default:
+		up(&data->update_lock);
 		return -EINVAL;
 	}
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -779,6 +794,8 @@ store_sensor_reg(struct device *dev, con
 
 	val = simple_strtoul(buf, NULL, 10);
 
+	down(&data->update_lock);
+
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
 		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -810,6 +827,7 @@ store_sensor_reg(struct device *dev, con
 		break;
 	}
 
+	up(&data->update_lock);
 	return count;
 }
 
@@ -833,66 +851,6 @@ do { \
 device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
 } while (0)
 
-#ifdef W83781D_RT
-static ssize_t
-show_rt_reg(struct device *dev, char *buf, int nr)
-{
-	struct w83781d_data *data = w83781d_update_device(dev);
-	int i, j = 0;
-
-	for (i = 0; i < 32; i++) {
-		if (i > 0)
-			j += sprintf(buf, " %ld", (long) data->rt[nr - 1][i]);
-		else
-			j += sprintf(buf, "%ld", (long) data->rt[nr - 1][i]);
-	}
-	j += sprintf(buf, "\n");
-
-	return j;
-}
-
-static ssize_t
-store_rt_reg(struct device *dev, const char *buf, size_t count, int nr)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-	u32 val, i;
-
-	for (i = 0; i < count; i++) {
-		val = simple_strtoul(buf + count, NULL, 10);
-
-		/* fixme: no bounds checking 0-255 */
-		data->rt[nr - 1][i] = val & 0xff;
-		w83781d_write_value(client, W83781D_REG_RT_IDX, i);
-		w83781d_write_value(client, W83781D_REG_RT_VAL,
-				    data->rt[nr - 1][i]);
-	}
-
-	return count;
-}
-
-#define sysfs_rt(offset) \
-static ssize_t show_regs_rt_##offset (struct device *dev, char *buf) \
-{ \
-	return show_rt_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size_t count) \
-{ \
-    return store_rt_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset);
-
-sysfs_rt(1);
-sysfs_rt(2);
-sysfs_rt(3);
-
-#define device_create_file_rt(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_rt##offset); \
-} while (0)
-
-#endif				/* ifdef W83781D_RT */
-
 /* This function is called when:
      * w83781d_driver is inserted (when this module is loaded), for each
        available adapter
@@ -1303,13 +1261,6 @@ w83781d_detect(struct i2c_adapter *adapt
 		if (kind != w83783s && kind != w83697hf)
 			device_create_file_sensor(new_client, 3);
 	}
-#ifdef W83781D_RT
-	if (kind == w83781d) {
-		device_create_file_rt(new_client, 1);
-		device_create_file_rt(new_client, 2);
-		device_create_file_rt(new_client, 3);
-	}
-#endif
 
 	return 0;
 
@@ -1534,39 +1485,29 @@ w83781d_init_client(struct i2c_client *c
 				break;
 		}
 	}
-#ifdef W83781D_RT
-/*
-   Fill up the RT Tables.
-   We assume that they are 32 bytes long, in order for temp 1-3.
-   Data sheet documentation is sparse.
-   We also assume that it is only for the 781D although I suspect
-   that the others support it as well....
-*/
-
-	if (init && type == w83781d) {
-		u16 k = 0;
-/*
-    Auto-indexing doesn't seem to work...
-    w83781d_write_value(client,W83781D_REG_RT_IDX,0);
-*/
-		for (i = 0; i < 3; i++) {
-			int j;
-			for (j = 0; j < 32; j++) {
-				w83781d_write_value(client,
-						    W83781D_REG_RT_IDX, k++);
-				data->rt[i][j] =
-				    w83781d_read_value(client,
-						       W83781D_REG_RT_VAL);
-			}
+
+	if (init && type != as99127f) {
+		/* Enable temp2 */
+		tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG);
+		if (tmp & 0x01) {
+			dev_warn(&client->dev, "Enabling temp2, readings "
+				 "might not make sense\n");
+			w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG,
+				tmp & 0xfe);
 		}
-	}
-#endif				/* W83781D_RT */
 
-	if (init) {
+		/* Enable temp3 */
 		if (type != w83783s && type != w83697hf) {
-			w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG,
-					    0x00);
+			tmp = w83781d_read_value(client,
+				W83781D_REG_TEMP3_CONFIG);
+			if (tmp & 0x01) {
+				dev_warn(&client->dev, "Enabling temp3, "
+					 "readings might not make sense\n");
+				w83781d_write_value(client,
+					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+			}
 		}
+
 		if (type != w83781d) {
 			/* enable comparator mode for temp2 and temp3 so
 			   alarm indication will work correctly */
@@ -1592,9 +1533,8 @@ static struct w83781d_data *w83781d_upda
 
 	down(&data->update_lock);
 
-	if (time_after
-	    (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2))
-	    || time_before(jiffies, data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
 		dev_dbg(dev, "Starting device update\n");
 
 		for (i = 0; i <= 8; i++) {
diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c
--- a/drivers/i2c/chips/w83l785ts.c
+++ b/drivers/i2c/chips/w83l785ts.c
@@ -35,6 +35,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 
@@ -114,12 +115,6 @@ struct w83l785ts_data {
 };
 
 /*
- * Internal variables
- */
-
-static int w83l785ts_id = 0;
-
-/*
  * Sysfs stuff
  */
 
@@ -229,7 +224,6 @@ static int w83l785ts_detect(struct i2c_a
 
 	/* We can fill in the remaining client fields. */
 	strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE);
-	new_client->id = w83l785ts_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
 
@@ -301,9 +295,7 @@ static struct w83l785ts_data *w83l785ts_
 
 	down(&data->update_lock);
 
-	if (!data->valid
-	 || (jiffies - data->last_updated > HZ * 2)
-	 || (jiffies < data->last_updated)) {
+	if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) {
 		dev_dbg(&client->dev, "Updating w83l785ts data.\n");
 		data->temp = w83l785ts_read_value(client,
 			     W83L785TS_REG_TEMP, data->temp);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -38,12 +38,43 @@ static LIST_HEAD(drivers);
 static DECLARE_MUTEX(core_lists);
 static DEFINE_IDR(i2c_adapter_idr);
 
-int i2c_device_probe(struct device *dev)
+/* match always succeeds, as we want the probe() to tell if we really accept this match */
+static int i2c_device_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static int i2c_bus_suspend(struct device * dev, pm_message_t state)
+{
+	int rc = 0;
+
+	if (dev->driver && dev->driver->suspend)
+		rc = dev->driver->suspend(dev,state,0);
+	return rc;
+}
+
+static int i2c_bus_resume(struct device * dev)
+{
+	int rc = 0;
+	
+	if (dev->driver && dev->driver->resume)
+		rc = dev->driver->resume(dev,0);
+	return rc;
+}
+
+static struct bus_type i2c_bus_type = {
+	.name =		"i2c",
+	.match =	i2c_device_match,
+	.suspend =      i2c_bus_suspend,
+	.resume =       i2c_bus_resume,
+};
+
+static int i2c_device_probe(struct device *dev)
 {
 	return -ENODEV;
 }
 
-int i2c_device_remove(struct device *dev)
+static int i2c_device_remove(struct device *dev)
 {
 	return 0;
 }
@@ -523,38 +554,6 @@ void i2c_clients_command(struct i2c_adap
        up(&adap->clist_lock);
 }
 
-
-/* match always succeeds, as we want the probe() to tell if we really accept this match */
-static int i2c_device_match(struct device *dev, struct device_driver *drv)
-{
-	return 1;
-}
-
-static int i2c_bus_suspend(struct device * dev, u32 state)
-{
-	int rc = 0;
-
-	if (dev->driver && dev->driver->suspend)
-		rc = dev->driver->suspend(dev,state,0);
-	return rc;
-}
-
-static int i2c_bus_resume(struct device * dev)
-{
-	int rc = 0;
-	
-	if (dev->driver && dev->driver->resume)
-		rc = dev->driver->resume(dev,0);
-	return rc;
-}
-
-struct bus_type i2c_bus_type = {
-	.name =		"i2c",
-	.match =	i2c_device_match,
-	.suspend =      i2c_bus_suspend,
-	.resume =       i2c_bus_resume,
-};
-
 static int __init i2c_init(void)
 {
 	int retval;
@@ -583,12 +582,18 @@ module_exit(i2c_exit);
  * ----------------------------------------------------
  */
 
-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 {
 	int ret;
 
 	if (adap->algo->master_xfer) {
- 	 	dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num);
+#ifdef DEBUG
+		for (ret = 0; ret < num; ret++) {
+			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+				"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
+				'R' : 'W', msgs[ret].addr, msgs[ret].len);
+		}
+#endif
 
 		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,msgs,num);
@@ -710,7 +715,7 @@ int i2c_probe(struct i2c_adapter *adapte
 		   at all */
 		found = 0;
 
-		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {
+		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) {
 			if (((adap_id == address_data->force[i]) || 
 			     (address_data->force[i] == ANY_I2C_BUS)) &&
 			     (addr == address_data->force[i+1])) {
@@ -860,7 +865,7 @@ crc8(u16 data)
 /* CRC over count bytes in the first array plus the bytes in the rest
    array if it is non-null. rest[0] is the (length of rest) - 1
    and is included. */
-u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
+static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
 {
 	int i;
 
@@ -872,7 +877,7 @@ u8 i2c_smbus_partial_pec(u8 crc, int cou
 	return crc;
 }
 
-u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
+static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
 {
 	return i2c_smbus_partial_pec(0, count, first, rest);
 }
@@ -880,8 +885,8 @@ u8 i2c_smbus_pec(int count, u8 *first, u
 /* Returns new "size" (transaction type)
    Note that we convert byte to byte_data and byte_data to word_data
    rather than invent new xxx_PEC transactions. */
-int i2c_smbus_add_pec(u16 addr, u8 command, int size,
-                      union i2c_smbus_data *data)
+static int i2c_smbus_add_pec(u16 addr, u8 command, int size,
+			     union i2c_smbus_data *data)
 {
 	u8 buf[3];
 
@@ -910,8 +915,8 @@ int i2c_smbus_add_pec(u16 addr, u8 comma
 	return size;	
 }
 
-int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
-                        union i2c_smbus_data *data)
+static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
+			       union i2c_smbus_data *data)
 {
 	u8 buf[3], rpec, cpec;
 
@@ -1231,22 +1236,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * 
 }
 
 
-/* You should always define `functionality'; the 'else' is just for
-   backward compatibility. */ 
-u32 i2c_get_functionality (struct i2c_adapter *adap)
-{
-	if (adap->algo->functionality)
-		return adap->algo->functionality(adap);
-	else
-		return 0xffffffff;
-}
-
-int i2c_check_functionality (struct i2c_adapter *adap, u32 func)
-{
-	u32 adap_func = i2c_get_functionality (adap);
-	return (func & adap_func) == func;
-}
-
 EXPORT_SYMBOL(i2c_add_adapter);
 EXPORT_SYMBOL(i2c_del_adapter);
 EXPORT_SYMBOL(i2c_add_driver);
@@ -1278,9 +1267,6 @@ EXPORT_SYMBOL(i2c_smbus_write_word_data)
 EXPORT_SYMBOL(i2c_smbus_write_block_data);
 EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
 
-EXPORT_SYMBOL(i2c_get_functionality);
-EXPORT_SYMBOL(i2c_check_functionality);
-
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
 MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -55,7 +55,7 @@ struct i2c_dev {
 static struct i2c_dev *i2c_dev_array[I2C_MINORS];
 static DEFINE_SPINLOCK(i2c_dev_array_lock);
 
-struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
 {
 	struct i2c_dev *i2c_dev;
 
@@ -65,7 +65,7 @@ struct i2c_dev *i2c_dev_get_by_minor(uns
 	return i2c_dev;
 }
 
-struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
+static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
 {
 	struct i2c_dev *i2c_dev = NULL;
 
@@ -108,13 +108,6 @@ static void return_i2c_dev(struct i2c_de
 	spin_unlock(&i2c_dev_array_lock);
 }
 
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
-	struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
-	return print_dev_t(buf, MKDEV(I2C_MAJOR, i2c_dev->minor));
-}
-static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-
 static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
 {
 	struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
@@ -173,8 +166,8 @@ static ssize_t i2cdev_write (struct file
 	return ret;
 }
 
-int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 
-                  unsigned long arg)
+static int i2cdev_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
 {
 	struct i2c_client *client = (struct i2c_client *)file->private_data;
 	struct i2c_rdwr_ioctl_data rdwr_arg;
@@ -451,11 +444,11 @@ static int i2cdev_attach_adapter(struct 
 	else
 		i2c_dev->class_dev.dev = adap->dev.parent;
 	i2c_dev->class_dev.class = &i2c_dev_class;
+	i2c_dev->class_dev.devt = MKDEV(I2C_MAJOR, i2c_dev->minor);
 	snprintf(i2c_dev->class_dev.class_id, BUS_ID_SIZE, "i2c-%d", i2c_dev->minor);
 	retval = class_device_register(&i2c_dev->class_dev);
 	if (retval)
 		goto error;
-	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_dev);
 	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_name);
 	return 0;
 error:
@@ -507,7 +500,6 @@ static struct i2c_driver i2cdev_driver =
 
 static struct i2c_client i2cdev_client_template = {
 	.name		= "I2C /dev entry",
-	.id		= 1,
 	.addr		= -1,
 	.driver		= &i2cdev_driver,
 };
diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c
--- a/drivers/i2c/i2c-sensor-detect.c
+++ b/drivers/i2c/i2c-sensor-detect.c
@@ -19,17 +19,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/sysctl.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
-#include <asm/uaccess.h>
 
 static unsigned short empty[] = {I2C_CLIENT_END};
 static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END};
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -150,7 +150,6 @@ config BLK_DEV_IDEDISK
 
 config IDEDISK_MULTI_MODE
 	bool "Use multi-mode by default"
-	depends on BLK_DEV_IDEDISK
 	help
 	  If you get this error, try to say Y here:
 
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -13,8 +13,7 @@ EXTRA_CFLAGS				+= -Idrivers/ide
 
 obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
 
-ide-core-y += ide.o ide-default.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
-	ide-taskfile.o
+ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
 
 ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
 
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -713,7 +713,7 @@ static int __devinit
 icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct icside_state *state;
-	void *idmem;
+	void __iomem *idmem;
 	int ret;
 
 	ret = ecard_request_resources(ec);
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -17,7 +17,7 @@
  * Something like this really should be in generic code, but isn't.
  */
 static ide_hwif_t *
-rapide_locate_hwif(void __iomem *base, void *ctrl, unsigned int sz, int irq)
+rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
 {
 	unsigned long port = (unsigned long)base;
 	ide_hwif_t *hwif;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -324,6 +324,34 @@
 
 #include "ide-cd.h"
 
+static DECLARE_MUTEX(idecd_ref_sem);
+
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref) 
+
+#define ide_cd_g(disk) \
+	container_of((disk)->private_data, struct cdrom_info, driver)
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+	struct cdrom_info *cd = NULL;
+
+	down(&idecd_ref_sem);
+	cd = ide_cd_g(disk);
+	if (cd)
+		kref_get(&cd->kref);
+	up(&idecd_ref_sem);
+	return cd;
+}
+
+static void ide_cd_release(struct kref *);
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+	down(&idecd_ref_sem);
+	kref_put(&cd->kref, ide_cd_release);
+	up(&idecd_ref_sem);
+}
+
 /****************************************************************************
  * Generic packet command support and error handling routines.
  */
@@ -529,10 +557,13 @@ void cdrom_analyze_sense_data(ide_drive_
 /*
  * Initialize a ide-cd packet command request
  */
-static void cdrom_prepare_request(struct request *rq)
+static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
 {
+	struct cdrom_info *cd = drive->driver_data;
+
 	ide_init_drive_cmd(rq);
 	rq->flags = REQ_PC;
+	rq->rq_disk = cd->disk;
 }
 
 static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
@@ -545,7 +576,7 @@ static void cdrom_queue_request_sense(id
 		sense = &info->sense_data;
 
 	/* stuff the sense request in front of our current request */
-	cdrom_prepare_request(rq);
+	cdrom_prepare_request(drive, rq);
 
 	rq->data = sense;
 	rq->cmd[0] = GPCMD_REQUEST_SENSE;
@@ -1829,7 +1860,7 @@ static ide_startstop_t cdrom_start_write
 static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g = info->disk;
 	unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
 	/*
@@ -1901,8 +1932,11 @@ static ide_startstop_t cdrom_do_block_pc
 
 		/*
 		 * check if dma is safe
+		 *
+		 * NOTE! The "len" and "addr" checks should possibly have
+		 * separate masks.
 		 */
-		if ((rq->data_len & mask) || (addr & mask))
+		if ((rq->data_len & 15) || (addr & mask))
 			info->dma = 0;
 	}
 
@@ -2021,7 +2055,7 @@ static int cdrom_check_status(ide_drive_
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.cmd[0] = GPCMD_TEST_UNIT_READY;
@@ -2053,7 +2087,7 @@ cdrom_lockdoor(ide_drive_t *drive, int l
 	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
 	} else {
-		cdrom_prepare_request(&req);
+		cdrom_prepare_request(drive, &req);
 		req.sense = sense;
 		req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		req.cmd[4] = lockflag ? 1 : 0;
@@ -2097,7 +2131,7 @@ static int cdrom_eject(ide_drive_t *driv
 	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
 		return 0;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	/* only tell drive to close tray if open, if it can do that */
 	if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
@@ -2121,7 +2155,7 @@ static int cdrom_read_capacity(ide_drive
 	int stat;
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
@@ -2144,7 +2178,7 @@ static int cdrom_read_tocentry(ide_drive
 {
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.data =  buf;
@@ -2201,7 +2235,7 @@ static int cdrom_read_toc(ide_drive_t *d
 	if (stat)
 		toc->capacity = 0x1fffff;
 
-	set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+	set_capacity(info->disk, toc->capacity * sectors_per_frame);
 	blk_queue_hardsect_size(drive->queue,
 				sectors_per_frame << SECTOR_BITS);
 
@@ -2321,7 +2355,7 @@ static int cdrom_read_toc(ide_drive_t *d
 	stat = cdrom_get_last_written(cdi, &last_written);
 	if (!stat && (last_written > toc->capacity)) {
 		toc->capacity = last_written;
-		set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+		set_capacity(info->disk, toc->capacity * sectors_per_frame);
 	}
 
 	/* Remember that we've read this stuff. */
@@ -2336,7 +2370,7 @@ static int cdrom_read_subchannel(ide_dri
 {
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.data = buf;
@@ -2356,7 +2390,7 @@ static int cdrom_select_speed(ide_drive_
 			      struct request_sense *sense)
 {
 	struct request req;
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	if (speed == 0)
@@ -2386,7 +2420,7 @@ static int cdrom_play_audio(ide_drive_t 
 	struct request_sense sense;
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = &sense;
 	req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
@@ -2436,7 +2470,7 @@ static int ide_cdrom_packet(struct cdrom
 	/* here we queue the commands from the uniform CD-ROM
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
 	if (cgc->sense)
 		memset(cgc->sense, 0, sizeof(struct request_sense));
@@ -2586,7 +2620,7 @@ int ide_cdrom_reset (struct cdrom_device
 	struct request req;
 	int ret;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 	req.flags = REQ_SPECIAL | REQ_QUIET;
 	ret = ide_do_drive_cmd(drive, &req, ide_wait);
 
@@ -2830,7 +2864,7 @@ static int ide_cdrom_register (ide_drive
 	if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
 		devinfo->mask |= CDC_MO_DRIVE;
 
-	devinfo->disk = drive->disk;
+	devinfo->disk = info->disk;
 	return register_cdrom(devinfo);
 }
 
@@ -3088,7 +3122,6 @@ int ide_cdrom_setup (ide_drive_t *drive)
 		drive->queue->unplug_delay = 1;
 
 	drive->special.all	= 0;
-	drive->ready_stat	= 0;
 
 	CDROM_STATE_FLAGS(drive)->media_changed = 1;
 	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
@@ -3193,6 +3226,9 @@ int ide_cdrom_setup (ide_drive_t *drive)
 	 */
 	blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
+	if (drive->autotune == IDE_TUNE_DEFAULT ||
+	    drive->autotune == IDE_TUNE_AUTO)
+		drive->dsc_overlap = (drive->next != drive);
 #if 0
 	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
 	if (HWIF(drive)->no_dsc) {
@@ -3222,18 +3258,27 @@ sector_t ide_cdrom_capacity (ide_drive_t
 	return capacity * sectors_per_frame;
 }
 
-static
-int ide_cdrom_cleanup(ide_drive_t *drive)
+static int ide_cd_remove(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	struct cdrom_info *info = drive->driver_data;
+
+	ide_unregister_subdriver(drive, info->driver);
+
+	del_gendisk(info->disk);
+
+	ide_cd_put(info);
+
+	return 0;
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+	struct cdrom_info *info = to_ide_cd(kref);
 	struct cdrom_device_info *devinfo = &info->devinfo;
-	struct gendisk *g = drive->disk;
+	ide_drive_t *drive = info->drive;
+	struct gendisk *g = info->disk;
 
-	if (ide_unregister_subdriver(drive)) {
-		printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n",
-			__FUNCTION__, drive->name);
-		return 1;
-	}
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
@@ -3241,77 +3286,67 @@ int ide_cdrom_cleanup(ide_drive_t *drive
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
 	if (devinfo->handle == drive && unregister_cdrom(devinfo))
-		printk(KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
-	kfree(info);
+		printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+				"driver.\n", __FUNCTION__, drive->name);
+	drive->dsc_overlap = 0;
 	drive->driver_data = NULL;
 	blk_queue_prep_rq(drive->queue, NULL);
-	del_gendisk(g);
-	g->fops = ide_fops;
-	return 0;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(info);
 }
 
-static int ide_cdrom_attach (ide_drive_t *drive);
-
-/*
- * Power Management state machine.
- *
- * We don't do much for CDs right now.
- */
-
-static void ide_cdrom_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
-{
-}
+static int ide_cd_probe(struct device *);
 
-static ide_startstop_t ide_cdrom_start_power_step (ide_drive_t *drive, struct request *rq)
+#ifdef CONFIG_PROC_FS
+static int proc_idecd_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_task_t *args = rq->special;
-
-	memset(args, 0, sizeof(*args));
-
-	switch (rq->pm->pm_step) {
-	case ide_pm_state_start_suspend:
-		break;
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
 
-	case ide_pm_state_start_resume:	/* Resume step 1 (restore DMA) */
-		/*
-		 * Right now, all we do is call hwif->ide_dma_check(drive),
-		 * we could be smarter and check for current xfer_speed
-		 * in struct drive etc...
-		 * Also, this step could be implemented as a generic helper
-		 * as most subdrivers will use it.
-		 */
-		if ((drive->id->capability & 1) == 0)
-			break;
-		if (HWIF(drive)->ide_dma_check == NULL)
-			break;
-		HWIF(drive)->ide_dma_check(drive);
-		break;
-	}
-	rq->pm->pm_step = ide_pm_state_completed;
-	return ide_stopped;
+	len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+static ide_proc_entry_t idecd_proc[] = {
+	{ "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#else
+# define idecd_proc	NULL
+#endif
+
 static ide_driver_t ide_cdrom_driver = {
 	.owner			= THIS_MODULE,
-	.name			= "ide-cdrom",
+	.gen_driver = {
+		.name		= "ide-cdrom",
+		.bus		= &ide_bus_type,
+		.probe		= ide_cd_probe,
+		.remove		= ide_cd_remove,
+	},
 	.version		= IDECD_VERSION,
 	.media			= ide_cdrom,
-	.busy			= 0,
 	.supports_dsc_overlap	= 1,
-	.cleanup		= ide_cdrom_cleanup,
 	.do_request		= ide_do_rw_cdrom,
-	.capacity		= ide_cdrom_capacity,
-	.attach			= ide_cdrom_attach,
-	.drives			= LIST_HEAD_INIT(ide_cdrom_driver.drives),
-	.start_power_step	= ide_cdrom_start_power_step,
-	.complete_power_step	= ide_cdrom_complete_power_step,
+	.end_request		= ide_end_request,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
+	.proc			= idecd_proc,
 };
 
 static int idecd_open(struct inode * inode, struct file * file)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct cdrom_info *info;
+	ide_drive_t *drive;
 	int rc = -ENOMEM;
+
+	if (!(info = ide_cd_get(disk)))
+		return -ENXIO;
+
+	drive = info->drive;
+
 	drive->usage++;
 
 	if (!info->buffer)
@@ -3319,16 +3354,24 @@ static int idecd_open(struct inode * ino
 					GFP_KERNEL|__GFP_REPEAT);
         if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
 		drive->usage--;
+
+	if (rc < 0)
+		ide_cd_put(info);
+
 	return rc;
 }
 
 static int idecd_release(struct inode * inode, struct file * file)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct cdrom_info *info = ide_cd_g(disk);
+	ide_drive_t *drive = info->drive;
 
 	cdrom_release (&info->devinfo, file);
 	drive->usage--;
+
+	ide_cd_put(info);
+
 	return 0;
 }
 
@@ -3336,27 +3379,27 @@ static int idecd_ioctl (struct inode *in
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
-	if (err == -EINVAL) {
-		struct cdrom_info *info = drive->driver_data;
+	struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+	int err;
+
+	err  = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+	if (err == -EINVAL)
 		err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
-	}
+
 	return err;
 }
 
 static int idecd_media_changed(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_info *info = ide_cd_g(disk);
 	return cdrom_media_changed(&info->devinfo);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
+	struct cdrom_info *info = ide_cd_g(disk);
 	struct request_sense sense;
-	cdrom_read_toc(drive, &sense);
+	cdrom_read_toc(info->drive, &sense);
 	return  0;
 }
 
@@ -3375,10 +3418,11 @@ static char *ignore = NULL;
 module_param(ignore, charp, 0400);
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cdrom_attach (ide_drive_t *drive)
+static int ide_cd_probe(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	struct cdrom_info *info;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g;
 	struct request_sense sense;
 
 	if (!strstr("ide-cdrom", drive->driver_req))
@@ -3403,15 +3447,27 @@ static int ide_cdrom_attach (ide_drive_t
 		printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
 		goto failed;
 	}
-	if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
-		printk(KERN_ERR "%s: Failed to register the driver with ide.c\n",
-			drive->name);
-		kfree(info);
-		goto failed;
-	}
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_cd;
+
+	ide_init_disk(g, drive);
+
+	ide_register_subdriver(drive, &ide_cdrom_driver);
+
 	memset(info, 0, sizeof (struct cdrom_info));
+
+	kref_init(&info->kref);
+
+	info->drive = drive;
+	info->driver = &ide_cdrom_driver;
+	info->disk = g;
+
+	g->private_data = &info->driver;
+
 	drive->driver_data = info;
-	DRIVER(drive)->busy++;
+
 	g->minors = 1;
 	snprintf(g->devfs_name, sizeof(g->devfs_name),
 			"%s/cd", drive->devfs_name);
@@ -3419,8 +3475,7 @@ static int ide_cdrom_attach (ide_drive_t
 	g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
 	if (ide_cdrom_setup(drive)) {
 		struct cdrom_device_info *devinfo = &info->devinfo;
-		DRIVER(drive)->busy--;
-		ide_unregister_subdriver(drive);
+		ide_unregister_subdriver(drive, &ide_cdrom_driver);
 		if (info->buffer != NULL)
 			kfree(info->buffer);
 		if (info->toc != NULL)
@@ -3433,26 +3488,27 @@ static int ide_cdrom_attach (ide_drive_t
 		drive->driver_data = NULL;
 		goto failed;
 	}
-	DRIVER(drive)->busy--;
 
 	cdrom_read_toc(drive, &sense);
 	g->fops = &idecd_ops;
 	g->flags |= GENHD_FL_REMOVABLE;
 	add_disk(g);
 	return 0;
+
+out_free_cd:
+	kfree(info);
 failed:
-	return 1;
+	return -ENODEV;
 }
 
 static void __exit ide_cdrom_exit(void)
 {
-	ide_unregister_driver(&ide_cdrom_driver);
+	driver_unregister(&ide_cdrom_driver.gen_driver);
 }
  
 static int ide_cdrom_init(void)
 {
-	ide_register_driver(&ide_cdrom_driver);
-	return 0;
+	return driver_register(&ide_cdrom_driver.gen_driver);
 }
 
 module_init(ide_cdrom_init);
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -460,6 +460,10 @@ struct atapi_changer_info {
 
 /* Extra per-device info for cdrom drives. */
 struct cdrom_info {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
 
 	/* Buffer for table of contents.  NULL if we haven't allocated
 	   a TOC buffer for this device yet. */
diff --git a/drivers/ide/ide-default.c b/drivers/ide/ide-default.c
deleted file mode 100644
--- a/drivers/ide/ide-default.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *	ide-default		-	Driver for unbound ide devices
- *
- *	This provides a clean way to bind a device to default operations
- *	by having an actual driver class that rather than special casing
- *	"no driver" all over the IDE code
- *
- *	Copyright (C) 2003, Red Hat <alan@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/unaligned.h>
-
-#define IDEDEFAULT_VERSION	"0.9.newide"
-/*
- *	Driver initialization.
- */
-
-static int idedefault_attach(ide_drive_t *drive);
-
-/*
- *	IDE subdriver functions, registered with ide.c
- */
-
-ide_driver_t idedefault_driver = {
-	.name		=	"ide-default",
-	.version	=	IDEDEFAULT_VERSION,
-	.attach		=	idedefault_attach,
-	.cleanup	=	ide_unregister_subdriver,
-	.drives		=	LIST_HEAD_INIT(idedefault_driver.drives)
-};
-
-static int idedefault_attach (ide_drive_t *drive)
-{
-	if (ide_register_subdriver(drive, &idedefault_driver)) {
-		printk(KERN_ERR "ide-default: %s: Failed to register the "
-			"driver with ide.c\n", drive->name);
-		return 1;
-	}
-	
-	/* For the sake of the request layer, we must make sure we have a
-	 * correct ready_stat value, that is 0 for ATAPI devices or we will
-	 * fail any request like Power Management
-	 */
-	if (drive->media != ide_disk)
-		drive->ready_stat = 0;
-
-	return 0;
-}
-
-MODULE_DESCRIPTION("IDE Default Driver");
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -71,6 +71,41 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 
+struct ide_disk_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+};
+
+static DECLARE_MUTEX(idedisk_ref_sem);
+
+#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
+
+#define ide_disk_g(disk) \
+	container_of((disk)->private_data, struct ide_disk_obj, driver)
+
+static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
+{
+	struct ide_disk_obj *idkp = NULL;
+
+	down(&idedisk_ref_sem);
+	idkp = ide_disk_g(disk);
+	if (idkp)
+		kref_get(&idkp->kref);
+	up(&idedisk_ref_sem);
+	return idkp;
+}
+
+static void ide_disk_release(struct kref *);
+
+static void ide_disk_put(struct ide_disk_obj *idkp)
+{
+	down(&idedisk_ref_sem);
+	kref_put(&idkp->kref, ide_disk_release);
+	up(&idedisk_ref_sem);
+}
+
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -133,6 +168,8 @@ static ide_startstop_t __ide_do_rw_disk(
 	if (hwif->no_lba48_dma && lba48 && dma) {
 		if (block + rq->nr_sectors > 1ULL << 28)
 			dma = 0;
+		else
+			lba48 = 0;
 	}
 
 	if (!dma) {
@@ -146,7 +183,7 @@ static ide_startstop_t __ide_do_rw_disk(
 	/* FIXME: SELECT_MASK(drive, 0) ? */
 
 	if (drive->select.b.lba) {
-		if (drive->addressing == 1) {
+		if (lba48) {
 			task_ioreg_t tasklets[10];
 
 			pr_debug("%s: LBA=0x%012llx\n", drive->name, block);
@@ -514,75 +551,6 @@ static sector_t idedisk_capacity (ide_dr
 	return drive->capacity64 - drive->sect0;
 }
 
-#define IS_PDC4030_DRIVE	0
-
-static ide_startstop_t idedisk_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-	if (s->b.set_geometry) {
-		s->b.set_geometry	= 0;
-		if (!IS_PDC4030_DRIVE) {
-			ide_task_t args;
-			memset(&args, 0, sizeof(ide_task_t));
-			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
-			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
-			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
-			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
-			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
-			args.command_type = IDE_DRIVE_TASK_NO_DATA;
-			args.handler	  = &set_geometry_intr;
-			do_rw_taskfile(drive, &args);
-		}
-	} else if (s->b.recalibrate) {
-		s->b.recalibrate = 0;
-		if (!IS_PDC4030_DRIVE) {
-			ide_task_t args;
-			memset(&args, 0, sizeof(ide_task_t));
-			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
-			args.command_type = IDE_DRIVE_TASK_NO_DATA;
-			args.handler	  = &recal_intr;
-			do_rw_taskfile(drive, &args);
-		}
-	} else if (s->b.set_multmode) {
-		s->b.set_multmode = 0;
-		if (drive->mult_req > drive->id->max_multsect)
-			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE) {
-			ide_task_t args;
-			memset(&args, 0, sizeof(ide_task_t));
-			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
-			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
-			args.command_type = IDE_DRIVE_TASK_NO_DATA;
-			args.handler	  = &set_multmode_intr;
-			do_rw_taskfile(drive, &args);
-		}
-	} else if (s->all) {
-		int special = s->all;
-		s->all = 0;
-		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
-		return ide_stopped;
-	}
-	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
-}
-
-static void idedisk_pre_reset (ide_drive_t *drive)
-{
-	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
-
-	drive->special.all = 0;
-	drive->special.b.set_geometry = legacy;
-	drive->special.b.recalibrate  = legacy;
-	if (OK_TO_RESET_CONTROLLER)
-		drive->mult_count = 0;
-	if (!drive->keep_settings && !drive->using_dma)
-		drive->mult_req = 0;
-	if (drive->mult_req != drive->mult_count)
-		drive->special.b.set_multmode = 1;
-}
-
 #ifdef CONFIG_PROC_FS
 
 static int smart_enable(ide_drive_t *drive)
@@ -646,6 +614,16 @@ static int proc_idedisk_read_cache
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+static int proc_idedisk_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
+
+	len = sprintf(page,"%llu\n", (long long)idedisk_capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
 static int proc_idedisk_read_smart_thresholds
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -686,6 +664,7 @@ static int proc_idedisk_read_smart_value
 
 static ide_proc_entry_t idedisk_proc[] = {
 	{ "cache",		S_IFREG|S_IRUGO,	proc_idedisk_read_cache,		NULL },
+	{ "capacity",		S_IFREG|S_IRUGO,	proc_idedisk_read_capacity,		NULL },
 	{ "geometry",		S_IFREG|S_IRUGO,	proc_ide_read_geometry,			NULL },
 	{ "smart_values",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_values,		NULL },
 	{ "smart_thresholds",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_thresholds,	NULL },
@@ -698,18 +677,51 @@ static ide_proc_entry_t idedisk_proc[] =
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
-			       sector_t *error_sector)
+static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq)
+{
+	ide_drive_t *drive = q->queuedata;
+	struct request *rq = flush_rq->end_io_data;
+	int good_sectors = rq->hard_nr_sectors;
+	int bad_sectors;
+	sector_t sector;
+
+	if (flush_rq->errors & ABRT_ERR) {
+		printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name);
+		blk_queue_ordered(drive->queue, QUEUE_ORDERED_NONE);
+		blk_queue_issue_flush_fn(drive->queue, NULL);
+		good_sectors = 0;
+	} else if (flush_rq->errors) {
+		good_sectors = 0;
+		if (blk_barrier_preflush(rq)) {
+			sector = ide_get_error_location(drive,flush_rq->buffer);
+			if ((sector >= rq->hard_sector) &&
+			    (sector < rq->hard_sector + rq->hard_nr_sectors))
+				good_sectors = sector - rq->hard_sector;
+		}
+	}
+
+	if (flush_rq->errors)
+		printk(KERN_ERR "%s: failed barrier write: "
+				"sector=%Lx(good=%d/bad=%d)\n",
+				drive->name, (unsigned long long)rq->sector,
+				good_sectors,
+				(int) (rq->hard_nr_sectors-good_sectors));
+
+	bad_sectors = rq->hard_nr_sectors - good_sectors;
+
+	if (good_sectors)
+		__ide_end_request(drive, rq, 1, good_sectors);
+	if (bad_sectors)
+		__ide_end_request(drive, rq, 0, bad_sectors);
+}
+
+static int idedisk_prepare_flush(request_queue_t *q, struct request *rq)
 {
 	ide_drive_t *drive = q->queuedata;
-	struct request *rq;
-	int ret;
 
 	if (!drive->wcache)
 		return 0;
 
-	rq = blk_get_request(q, WRITE, __GFP_WAIT);
-
 	memset(rq->cmd, 0, sizeof(rq->cmd));
 
 	if (ide_id_has_flush_cache_ext(drive->id) &&
@@ -721,6 +733,22 @@ static int idedisk_issue_flush(request_q
 
 	rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER;
 	rq->buffer = rq->cmd;
+	return 1;
+}
+
+static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	ide_drive_t *drive = q->queuedata;
+	struct request *rq;
+	int ret;
+
+	if (!drive->wcache)
+		return 0;
+
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+
+	idedisk_prepare_flush(q, rq);
 
 	ret = blk_execute_rq(q, disk, rq);
 
@@ -852,90 +880,6 @@ static void idedisk_add_settings(ide_dri
  	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
-/*
- * Power Management state machine. This one is rather trivial for now,
- * we should probably add more, like switching back to PIO on suspend
- * to help some BIOSes, re-do the door locking on resume, etc...
- */
-
-enum {
-	idedisk_pm_flush_cache	= ide_pm_state_start_suspend,
-	idedisk_pm_standby,
-
-	idedisk_pm_idle		= ide_pm_state_start_resume,
-	idedisk_pm_restore_dma,
-};
-
-static void idedisk_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
-{
-	switch (rq->pm->pm_step) {
-	case idedisk_pm_flush_cache:	/* Suspend step 1 (flush cache) complete */
-		if (rq->pm->pm_state == 4)
-			rq->pm->pm_step = ide_pm_state_completed;
-		else
-			rq->pm->pm_step = idedisk_pm_standby;
-		break;
-	case idedisk_pm_standby:	/* Suspend step 2 (standby) complete */
-		rq->pm->pm_step = ide_pm_state_completed;
-		break;
-	case idedisk_pm_idle:		/* Resume step 1 (idle) complete */
-		rq->pm->pm_step = idedisk_pm_restore_dma;
-		break;
-	}
-}
-
-static ide_startstop_t idedisk_start_power_step (ide_drive_t *drive, struct request *rq)
-{
-	ide_task_t *args = rq->special;
-
-	memset(args, 0, sizeof(*args));
-
-	switch (rq->pm->pm_step) {
-	case idedisk_pm_flush_cache:	/* Suspend step 1 (flush cache) */
-		/* Not supported? Switch to next step now. */
-		if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
-			idedisk_complete_power_step(drive, rq, 0, 0);
-			return ide_stopped;
-		}
-		if (ide_id_has_flush_cache_ext(drive->id))
-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
-		else
-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler	   = &task_no_data_intr;
-		return do_rw_taskfile(drive, args);
-
-	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler	   = &task_no_data_intr;
-		return do_rw_taskfile(drive, args);
-
-	case idedisk_pm_idle:		/* Resume step 1 (idle) */
-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler = task_no_data_intr;
-		return do_rw_taskfile(drive, args);
-
-	case idedisk_pm_restore_dma:	/* Resume step 2 (restore DMA) */
-		/*
-		 * Right now, all we do is call hwif->ide_dma_check(drive),
-		 * we could be smarter and check for current xfer_speed
-		 * in struct drive etc...
-		 * Also, this step could be implemented as a generic helper
-		 * as most subdrivers will use it
-		 */
-		if ((drive->id->capability & 1) == 0)
-			break;
-		if (HWIF(drive)->ide_dma_check == NULL)
-			break;
-		HWIF(drive)->ide_dma_check(drive);
-		break;
-	}
-	rq->pm->pm_step = ide_pm_state_completed;
-	return ide_stopped;
-}
-
 static void idedisk_setup (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -974,28 +918,6 @@ static void idedisk_setup (ide_drive_t *
 
 	printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2);
 
-	/* Extract geometry if we did not already have one for the drive */
-	if (!drive->cyl || !drive->head || !drive->sect) {
-		drive->cyl     = drive->bios_cyl  = id->cyls;
-		drive->head    = drive->bios_head = id->heads;
-		drive->sect    = drive->bios_sect = id->sectors;
-	}
-
-	/* Handle logical geometry translation by the drive */
-	if ((id->field_valid & 1) && id->cur_cyls &&
-	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
-		drive->cyl  = id->cur_cyls;
-		drive->head = id->cur_heads;
-		drive->sect = id->cur_sectors;
-	}
-
-	/* Use physical geometry if what we have still makes no sense */
-	if (drive->head > 16 && id->heads && id->heads <= 16) {
-		drive->cyl  = id->cyls;
-		drive->head = id->heads;
-		drive->sect = id->sectors;
-	}
-
 	/* calculate drive capacity, and select LBA if possible */
 	init_idedisk_capacity (drive);
 
@@ -1059,21 +981,6 @@ static void idedisk_setup (ide_drive_t *
 		ide_dma_verbose(drive);
 	printk("\n");
 
-	drive->mult_count = 0;
-	if (id->max_multsect) {
-#ifdef CONFIG_IDEDISK_MULTI_MODE
-		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
-		id->multsect_valid = id->multsect ? 1 : 0;
-		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
-		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
-#else	/* original, pre IDE-NFG, per request of AC */
-		drive->mult_req = INITIAL_MULT_COUNT;
-		if (drive->mult_req > id->max_multsect)
-			drive->mult_req = id->max_multsect;
-		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
-			drive->special.b.set_multmode = 1;
-#endif	/* CONFIG_IDEDISK_MULTI_MODE */
-	}
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
 
 	/* write cache enabled? */
@@ -1098,10 +1005,12 @@ static void idedisk_setup (ide_drive_t *
 			barrier = 0;
 	}
 
-	printk(KERN_DEBUG "%s: cache flushes %ssupported\n",
+	printk(KERN_INFO "%s: cache flushes %ssupported\n",
 		drive->name, barrier ? "" : "not ");
 	if (barrier) {
-		blk_queue_ordered(drive->queue, 1);
+		blk_queue_ordered(drive->queue, QUEUE_ORDERED_FLUSH);
+		drive->queue->prepare_flush_fn = idedisk_prepare_flush;
+		drive->queue->end_flush_fn = idedisk_end_flush;
 		blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);
 	}
 }
@@ -1115,19 +1024,37 @@ static void ide_cacheflush_p(ide_drive_t
 		printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
 }
 
-static int idedisk_cleanup (ide_drive_t *drive)
+static int ide_disk_remove(struct device *dev)
 {
-	struct gendisk *g = drive->disk;
+	ide_drive_t *drive = to_ide_device(dev);
+	struct ide_disk_obj *idkp = drive->driver_data;
+	struct gendisk *g = idkp->disk;
+
 	ide_cacheflush_p(drive);
-	if (ide_unregister_subdriver(drive))
-		return 1;
+
+	ide_unregister_subdriver(drive, idkp->driver);
+
 	del_gendisk(g);
-	drive->devfs_name[0] = '\0';
-	g->fops = ide_fops;
+
+	ide_disk_put(idkp);
+
 	return 0;
 }
 
-static int idedisk_attach(ide_drive_t *drive);
+static void ide_disk_release(struct kref *kref)
+{
+	struct ide_disk_obj *idkp = to_ide_disk(kref);
+	ide_drive_t *drive = idkp->drive;
+	struct gendisk *g = idkp->disk;
+
+	drive->driver_data = NULL;
+	drive->devfs_name[0] = '\0';
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(idkp);
+}
+
+static int ide_disk_probe(struct device *dev);
 
 static void ide_device_shutdown(struct device *dev)
 {
@@ -1154,37 +1081,39 @@ static void ide_device_shutdown(struct d
 	}
 
 	printk("Shutdown: %s\n", drive->name);
-	dev->bus->suspend(dev, PM_SUSPEND_STANDBY);
+	dev->bus->suspend(dev, PMSG_SUSPEND);
 }
 
-/*
- *      IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idedisk_driver = {
 	.owner			= THIS_MODULE,
 	.gen_driver = {
+		.name		= "ide-disk",
+		.bus		= &ide_bus_type,
+		.probe		= ide_disk_probe,
+		.remove		= ide_disk_remove,
 		.shutdown	= ide_device_shutdown,
 	},
-	.name			= "ide-disk",
 	.version		= IDEDISK_VERSION,
 	.media			= ide_disk,
-	.busy			= 0,
 	.supports_dsc_overlap	= 0,
-	.cleanup		= idedisk_cleanup,
 	.do_request		= ide_do_rw_disk,
-	.pre_reset		= idedisk_pre_reset,
-	.capacity		= idedisk_capacity,
-	.special		= idedisk_special,
+	.end_request		= ide_end_request,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
 	.proc			= idedisk_proc,
-	.attach			= idedisk_attach,
-	.drives			= LIST_HEAD_INIT(idedisk_driver.drives),
-	.start_power_step	= idedisk_start_power_step,
-	.complete_power_step	= idedisk_complete_power_step,
 };
 
 static int idedisk_open(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_disk_obj *idkp;
+	ide_drive_t *drive;
+
+	if (!(idkp = ide_disk_get(disk)))
+		return -ENXIO;
+
+	drive = idkp->drive;
+
 	drive->usage++;
 	if (drive->removable && drive->usage == 1) {
 		ide_task_t args;
@@ -1206,7 +1135,10 @@ static int idedisk_open(struct inode *in
 
 static int idedisk_release(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_disk_obj *idkp = ide_disk_g(disk);
+	ide_drive_t *drive = idkp->drive;
+
 	if (drive->usage == 1)
 		ide_cacheflush_p(drive);
 	if (drive->removable && drive->usage == 1) {
@@ -1219,6 +1151,9 @@ static int idedisk_release(struct inode 
 			drive->doorlocking = 0;
 	}
 	drive->usage--;
+
+	ide_disk_put(idkp);
+
 	return 0;
 }
 
@@ -1226,12 +1161,14 @@ static int idedisk_ioctl(struct inode *i
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	return generic_ide_ioctl(file, bdev, cmd, arg);
+	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+	return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg);
 }
 
 static int idedisk_media_changed(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
+	struct ide_disk_obj *idkp = ide_disk_g(disk);
+	ide_drive_t *drive = idkp->drive;
 
 	/* do not scan partitions twice if this is a removable device */
 	if (drive->attach) {
@@ -1244,8 +1181,8 @@ static int idedisk_media_changed(struct 
 
 static int idedisk_revalidate_disk(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	set_capacity(disk, idedisk_capacity(drive));
+	struct ide_disk_obj *idkp = ide_disk_g(disk);
+	set_capacity(disk, idedisk_capacity(idkp->drive));
 	return 0;
 }
 
@@ -1260,9 +1197,11 @@ static struct block_device_operations id
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-static int idedisk_attach(ide_drive_t *drive)
+static int ide_disk_probe(struct device *dev)
 {
-	struct gendisk *g = drive->disk;
+	ide_drive_t *drive = to_ide_device(dev);
+	struct ide_disk_obj *idkp;
+	struct gendisk *g;
 
 	/* strstr("foo", "") is non-NULL */
 	if (!strstr("ide-disk", drive->driver_req))
@@ -1272,11 +1211,30 @@ static int idedisk_attach(ide_drive_t *d
 	if (drive->media != ide_disk)
 		goto failed;
 
-	if (ide_register_subdriver(drive, &idedisk_driver)) {
-		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+	idkp = kmalloc(sizeof(*idkp), GFP_KERNEL);
+	if (!idkp)
 		goto failed;
-	}
-	DRIVER(drive)->busy++;
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_idkp;
+
+	ide_init_disk(g, drive);
+
+	ide_register_subdriver(drive, &idedisk_driver);
+
+	memset(idkp, 0, sizeof(*idkp));
+
+	kref_init(&idkp->kref);
+
+	idkp->drive = drive;
+	idkp->driver = &idedisk_driver;
+	idkp->disk = g;
+
+	g->private_data = &idkp->driver;
+
+	drive->driver_data = idkp;
+
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
@@ -1284,7 +1242,7 @@ static int idedisk_attach(ide_drive_t *d
 		drive->attach = 0;
 	} else
 		drive->attach = 1;
-	DRIVER(drive)->busy--;
+
 	g->minors = 1 << PARTN_BITS;
 	strcpy(g->devfs_name, drive->devfs_name);
 	g->driverfs_dev = &drive->gendev;
@@ -1293,18 +1251,21 @@ static int idedisk_attach(ide_drive_t *d
 	g->fops = &idedisk_ops;
 	add_disk(g);
 	return 0;
+
+out_free_idkp:
+	kfree(idkp);
 failed:
-	return 1;
+	return -ENODEV;
 }
 
 static void __exit idedisk_exit (void)
 {
-	ide_unregister_driver(&idedisk_driver);
+	driver_unregister(&idedisk_driver.gen_driver);
 }
 
 static int idedisk_init (void)
 {
-	return ide_register_driver(&idedisk_driver);
+	return driver_register(&idedisk_driver.gen_driver);
 }
 
 module_init(idedisk_init);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -176,7 +176,13 @@ ide_startstop_t ide_dma_intr (ide_drive_
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
 
-			DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
+			if (rq->rq_disk) {
+				ide_driver_t *drv;
+
+				drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+				drv->end_request(drive, 1, rq->nr_sectors);
+			} else
+				ide_end_request(drive, 1, rq->nr_sectors);
 			return ide_stopped;
 		}
 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -274,8 +274,11 @@ typedef struct {
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idefloppy_floppy_t, defined below.
  */
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_floppy_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
 
 	/* Current packet command */
 	idefloppy_pc_t *pc;
@@ -514,6 +517,34 @@ typedef struct {
 	u8		reserved[4];
 } idefloppy_mode_parameter_header_t;
 
+static DECLARE_MUTEX(idefloppy_ref_sem);
+
+#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
+
+#define ide_floppy_g(disk) \
+	container_of((disk)->private_data, struct ide_floppy_obj, driver)
+
+static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
+{
+	struct ide_floppy_obj *floppy = NULL;
+
+	down(&idefloppy_ref_sem);
+	floppy = ide_floppy_g(disk);
+	if (floppy)
+		kref_get(&floppy->kref);
+	up(&idefloppy_ref_sem);
+	return floppy;
+}
+
+static void ide_floppy_release(struct kref *);
+
+static void ide_floppy_put(struct ide_floppy_obj *floppy)
+{
+	down(&idefloppy_ref_sem);
+	kref_put(&floppy->kref, ide_floppy_release);
+	up(&idefloppy_ref_sem);
+}
+
 /*
  *	Too bad. The drive wants to send us data which we are not ready to accept.
  *	Just throw it away.
@@ -652,9 +683,12 @@ static void idefloppy_update_buffers (id
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
+	struct ide_floppy_obj *floppy = drive->driver_data;
+
 	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->flags = REQ_SPECIAL;	//rq->cmd = IDEFLOPPY_PC_RQ;
+	rq->rq_disk = floppy->disk;
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -1246,7 +1280,8 @@ static ide_startstop_t idefloppy_do_requ
 	unsigned long block = (unsigned long)block_s;
 
 	debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
-			rq->rq_status, rq->rq_disk->disk_name,
+			rq->rq_status,
+			rq->rq_disk ? rq->rq_disk->disk_name ? "?",
 			rq->flags, rq->errors);
 	debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
 			"current_nr_sectors: %d\n", (long)rq->sector,
@@ -1301,11 +1336,13 @@ static ide_startstop_t idefloppy_do_requ
  */
 static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
 {
+	struct ide_floppy_obj *floppy = drive->driver_data;
 	struct request rq;
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
 	rq.flags = REQ_SPECIAL;		//	rq.cmd = IDEFLOPPY_PC_RQ;
+	rq.rq_disk = floppy->disk;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1330,7 +1367,7 @@ static int idefloppy_get_flexible_disk_p
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
-	set_disk_ro(drive->disk, floppy->wp);
+	set_disk_ro(floppy->disk, floppy->wp);
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
 	page->transfer_rate = ntohs(page->transfer_rate);
@@ -1396,7 +1433,7 @@ static int idefloppy_get_capacity (ide_d
 	drive->bios_cyl = 0;
 	drive->bios_head = drive->bios_sect = 0;
 	floppy->blocks = floppy->bs_factor = 0;
-	set_capacity(drive->disk, 0);
+	set_capacity(floppy->disk, 0);
 
 	idefloppy_create_read_capacity_cmd(&pc);
 	if (idefloppy_queue_pc_tail(drive, &pc)) {
@@ -1470,7 +1507,7 @@ static int idefloppy_get_capacity (ide_d
 		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
-	set_capacity(drive->disk, floppy->blocks * floppy->bs_factor);
+	set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
 	return rc;
 }
 
@@ -1792,10 +1829,6 @@ static void idefloppy_setup (ide_drive_t
 	struct idefloppy_id_gcw gcw;
 
 	*((u16 *) &gcw) = drive->id->config;
-	drive->driver_data = floppy;
-	drive->ready_stat = 0;
-	memset(floppy, 0, sizeof(idefloppy_floppy_t));
-	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
 		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
@@ -1832,23 +1865,47 @@ static void idefloppy_setup (ide_drive_t
 	idefloppy_add_settings(drive);
 }
 
-static int idefloppy_cleanup (ide_drive_t *drive)
+static int ide_floppy_remove(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g = floppy->disk;
+
+	ide_unregister_subdriver(drive, floppy->driver);
 
-	if (ide_unregister_subdriver(drive))
-		return 1;
-	drive->driver_data = NULL;
-	kfree(floppy);
 	del_gendisk(g);
-	g->fops = ide_fops;
+
+	ide_floppy_put(floppy);
+
 	return 0;
 }
 
+static void ide_floppy_release(struct kref *kref)
+{
+	struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+	ide_drive_t *drive = floppy->drive;
+	struct gendisk *g = floppy->disk;
+
+	drive->driver_data = NULL;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(floppy);
+}
+
 #ifdef CONFIG_PROC_FS
 
+static int proc_idefloppy_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
+
+	len = sprintf(page,"%llu\n", (long long)idefloppy_capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
 static ide_proc_entry_t idefloppy_proc[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_idefloppy_read_capacity, NULL },
 	{ "geometry",	S_IFREG|S_IRUGO,	proc_ide_read_geometry,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
@@ -1859,37 +1916,43 @@ static ide_proc_entry_t idefloppy_proc[]
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_attach(ide_drive_t *drive);
+static int ide_floppy_probe(struct device *);
 
-/*
- *	IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idefloppy_driver = {
 	.owner			= THIS_MODULE,
-	.name			= "ide-floppy",
+	.gen_driver = {
+		.name		= "ide-floppy",
+		.bus		= &ide_bus_type,
+		.probe		= ide_floppy_probe,
+		.remove		= ide_floppy_remove,
+	},
 	.version		= IDEFLOPPY_VERSION,
 	.media			= ide_floppy,
-	.busy			= 0,
 	.supports_dsc_overlap	= 0,
-	.cleanup		= idefloppy_cleanup,
 	.do_request		= idefloppy_do_request,
 	.end_request		= idefloppy_do_end_request,
-	.capacity		= idefloppy_capacity,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
 	.proc			= idefloppy_proc,
-	.attach			= idefloppy_attach,
-	.drives			= LIST_HEAD_INIT(idefloppy_driver.drives),
 };
 
 static int idefloppy_open(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_floppy_obj *floppy;
+	ide_drive_t *drive;
 	idefloppy_pc_t pc;
+	int ret = 0;
 
-	drive->usage++;
-	
 	debug_log(KERN_INFO "Reached idefloppy_open\n");
 
+	if (!(floppy = ide_floppy_get(disk)))
+		return -ENXIO;
+
+	drive = floppy->drive;
+
+	drive->usage++;
+
 	if (drive->usage == 1) {
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
 		/* Just in case */
@@ -1909,13 +1972,15 @@ static int idefloppy_open(struct inode *
 		    */
 		    ) {
 			drive->usage--;
-			return -EIO;
+			ret = -EIO;
+			goto out_put_floppy;
 		}
 
 		if (floppy->wp && (filp->f_mode & 2)) {
 			drive->usage--;
-			return -EROFS;
-		}		
+			ret = -EROFS;
+			goto out_put_floppy;
+		}
 		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
@@ -1925,21 +1990,26 @@ static int idefloppy_open(struct inode *
 		check_disk_change(inode->i_bdev);
 	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out_put_floppy;
 	}
 	return 0;
+
+out_put_floppy:
+	ide_floppy_put(floppy);
+	return ret;
 }
 
 static int idefloppy_release(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	ide_drive_t *drive = floppy->drive;
 	idefloppy_pc_t pc;
 	
 	debug_log(KERN_INFO "Reached idefloppy_release\n");
 
 	if (drive->usage == 1) {
-		idefloppy_floppy_t *floppy = drive->driver_data;
-
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
 			idefloppy_create_prevent_cmd(&pc, 0);
@@ -1949,6 +2019,9 @@ static int idefloppy_release(struct inod
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
 	}
 	drive->usage--;
+
+	ide_floppy_put(floppy);
+
 	return 0;
 }
 
@@ -1956,10 +2029,10 @@ static int idefloppy_ioctl(struct inode 
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+	ide_drive_t *drive = floppy->drive;
 	void __user *argp = (void __user *)arg;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
+	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
 	int prevent = (arg) ? 1 : 0;
 	idefloppy_pc_t pc;
 	if (err != -EINVAL)
@@ -2020,8 +2093,8 @@ static int idefloppy_ioctl(struct inode 
 
 static int idefloppy_media_changed(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	ide_drive_t *drive = floppy->drive;
 
 	/* do not scan partitions twice if this is a removable device */
 	if (drive->attach) {
@@ -2033,8 +2106,8 @@ static int idefloppy_media_changed(struc
 
 static int idefloppy_revalidate_disk(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	set_capacity(disk, idefloppy_capacity(drive));
+	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	set_capacity(disk, idefloppy_capacity(floppy->drive));
 	return 0;
 }
 
@@ -2047,10 +2120,12 @@ static struct block_device_operations id
 	.revalidate_disk= idefloppy_revalidate_disk
 };
 
-static int idefloppy_attach (ide_drive_t *drive)
+static int ide_floppy_probe(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	idefloppy_floppy_t *floppy;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g;
+
 	if (!strstr("ide-floppy", drive->driver_req))
 		goto failed;
 	if (!drive->present)
@@ -2069,14 +2144,29 @@ static int idefloppy_attach (ide_drive_t
 		printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
 		goto failed;
 	}
-	if (ide_register_subdriver(drive, &idefloppy_driver)) {
-		printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (floppy);
-		goto failed;
-	}
-	DRIVER(drive)->busy++;
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_floppy;
+
+	ide_init_disk(g, drive);
+
+	ide_register_subdriver(drive, &idefloppy_driver);
+
+	memset(floppy, 0, sizeof(*floppy));
+
+	kref_init(&floppy->kref);
+
+	floppy->drive = drive;
+	floppy->driver = &idefloppy_driver;
+	floppy->disk = g;
+
+	g->private_data = &floppy->driver;
+
+	drive->driver_data = floppy;
+
 	idefloppy_setup (drive, floppy);
-	DRIVER(drive)->busy--;
+
 	g->minors = 1 << PARTN_BITS;
 	g->driverfs_dev = &drive->gendev;
 	strcpy(g->devfs_name, drive->devfs_name);
@@ -2085,15 +2175,18 @@ static int idefloppy_attach (ide_drive_t
 	drive->attach = 1;
 	add_disk(g);
 	return 0;
+
+out_free_floppy:
+	kfree(floppy);
 failed:
-	return 1;
+	return -ENODEV;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
 static void __exit idefloppy_exit (void)
 {
-	ide_unregister_driver(&idefloppy_driver);
+	driver_unregister(&idefloppy_driver.gen_driver);
 }
 
 /*
@@ -2102,8 +2195,7 @@ static void __exit idefloppy_exit (void)
 static int idefloppy_init (void)
 {
 	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
-	ide_register_driver(&idefloppy_driver);
-	return 0;
+	return driver_register(&idefloppy_driver.gen_driver);
 }
 
 module_init(idefloppy_init);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,62 +55,8 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq)
-{
-	char *buf = rq->cmd;
-
-	/*
-	 * reuse cdb space for ata command
-	 */
-	memset(buf, 0, sizeof(rq->cmd));
-
-	rq->flags |= REQ_DRIVE_TASK | REQ_STARTED;
-	rq->buffer = buf;
-	rq->buffer[0] = WIN_FLUSH_CACHE;
-
-	if (ide_id_has_flush_cache_ext(drive->id) &&
-	    (drive->capacity64 >= (1UL << 28)))
-		rq->buffer[0] = WIN_FLUSH_CACHE_EXT;
-}
-
-/*
- * preempt pending requests, and store this cache flush for immediate
- * execution
- */
-static struct request *ide_queue_flush_cmd(ide_drive_t *drive,
-					   struct request *rq, int post)
-{
-	struct request *flush_rq = &HWGROUP(drive)->wrq;
-
-	/*
-	 * write cache disabled, clear the barrier bit and treat it like
-	 * an ordinary write
-	 */
-	if (!drive->wcache) {
-		rq->flags |= REQ_BAR_PREFLUSH;
-		return rq;
-	}
-
-	ide_init_drive_cmd(flush_rq);
-	ide_fill_flush_cmd(drive, flush_rq);
-
-	flush_rq->special = rq;
-	flush_rq->nr_sectors = rq->nr_sectors;
-
-	if (!post) {
-		drive->doing_barrier = 1;
-		flush_rq->flags |= REQ_BAR_PREFLUSH;
-		blkdev_dequeue_request(rq);
-	} else
-		flush_rq->flags |= REQ_BAR_POSTFLUSH;
-
-	__elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0);
-	HWGROUP(drive)->rq = NULL;
-	return flush_rq;
-}
-
-static int __ide_end_request(ide_drive_t *drive, struct request *rq,
-			     int uptodate, int nr_sectors)
+int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
+		      int nr_sectors)
 {
 	int ret = 1;
 
@@ -148,6 +94,7 @@ static int __ide_end_request(ide_drive_t
 	}
 	return ret;
 }
+EXPORT_SYMBOL(__ide_end_request);
 
 /**
  *	ide_end_request		-	complete an IDE I/O
@@ -172,23 +119,109 @@ int ide_end_request (ide_drive_t *drive,
 	if (!nr_sectors)
 		nr_sectors = rq->hard_cur_sectors;
 
-	if (!blk_barrier_rq(rq) || !drive->wcache)
+	if (blk_complete_barrier_rq_locked(drive->queue, rq, nr_sectors))
+		ret = rq->nr_sectors != 0;
+	else
 		ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
-	else {
-		struct request *flush_rq = &HWGROUP(drive)->wrq;
-
-		flush_rq->nr_sectors -= nr_sectors;
-		if (!flush_rq->nr_sectors) {
-			ide_queue_flush_cmd(drive, rq, 1);
-			ret = 0;
-		}
-	}
 
 	spin_unlock_irqrestore(&ide_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(ide_end_request);
 
+/*
+ * Power Management state machine. This one is rather trivial for now,
+ * we should probably add more, like switching back to PIO on suspend
+ * to help some BIOSes, re-do the door locking on resume, etc...
+ */
+
+enum {
+	ide_pm_flush_cache	= ide_pm_state_start_suspend,
+	idedisk_pm_standby,
+
+	idedisk_pm_idle		= ide_pm_state_start_resume,
+	ide_pm_restore_dma,
+};
+
+static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	switch (rq->pm->pm_step) {
+	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) complete */
+		if (rq->pm->pm_state == 4)
+			rq->pm->pm_step = ide_pm_state_completed;
+		else
+			rq->pm->pm_step = idedisk_pm_standby;
+		break;
+	case idedisk_pm_standby:	/* Suspend step 2 (standby) complete */
+		rq->pm->pm_step = ide_pm_state_completed;
+		break;
+	case idedisk_pm_idle:		/* Resume step 1 (idle) complete */
+		rq->pm->pm_step = ide_pm_restore_dma;
+		break;
+	}
+}
+
+static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+
+	memset(args, 0, sizeof(*args));
+
+	if (drive->media != ide_disk) {
+		/* skip idedisk_pm_idle for ATAPI devices */
+		if (rq->pm->pm_step == idedisk_pm_idle)
+			rq->pm->pm_step = ide_pm_restore_dma;
+	}
+
+	switch (rq->pm->pm_step) {
+	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) */
+		if (drive->media != ide_disk)
+			break;
+		/* Not supported? Switch to next step now. */
+		if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
+			ide_complete_power_step(drive, rq, 0, 0);
+			return ide_stopped;
+		}
+		if (ide_id_has_flush_cache_ext(drive->id))
+			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
+		else
+			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
+		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+		args->handler	   = &task_no_data_intr;
+		return do_rw_taskfile(drive, args);
+
+	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
+		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
+		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+		args->handler	   = &task_no_data_intr;
+		return do_rw_taskfile(drive, args);
+
+	case idedisk_pm_idle:		/* Resume step 1 (idle) */
+		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
+		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+		args->handler = task_no_data_intr;
+		return do_rw_taskfile(drive, args);
+
+	case ide_pm_restore_dma:	/* Resume step 2 (restore DMA) */
+		/*
+		 * Right now, all we do is call hwif->ide_dma_check(drive),
+		 * we could be smarter and check for current xfer_speed
+		 * in struct drive etc...
+		 */
+		if ((drive->id->capability & 1) == 0)
+			break;
+		if (drive->hwif->ide_dma_check == NULL)
+			break;
+		drive->hwif->ide_dma_check(drive);
+		break;
+	}
+	rq->pm->pm_step = ide_pm_state_completed;
+	return ide_stopped;
+}
+
 /**
  *	ide_complete_pm_request - end the current Power Management request
  *	@drive: target drive
@@ -253,79 +286,6 @@ u64 ide_get_error_location(ide_drive_t *
 }
 EXPORT_SYMBOL(ide_get_error_location);
 
-static void ide_complete_barrier(ide_drive_t *drive, struct request *rq,
-				 int error)
-{
-	struct request *real_rq = rq->special;
-	int good_sectors, bad_sectors;
-	sector_t sector;
-
-	if (!error) {
-		if (blk_barrier_postflush(rq)) {
-			/*
-			 * this completes the barrier write
-			 */
-			__ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors);
-			drive->doing_barrier = 0;
-		} else {
-			/*
-			 * just indicate that we did the pre flush
-			 */
-			real_rq->flags |= REQ_BAR_PREFLUSH;
-			elv_requeue_request(drive->queue, real_rq);
-		}
-		/*
-		 * all is fine, return
-		 */
-		return;
-	}
-
-	/*
-	 * we need to end real_rq, but it's not on the queue currently.
-	 * put it back on the queue, so we don't have to special case
-	 * anything else for completing it
-	 */
-	if (!blk_barrier_postflush(rq))
-		elv_requeue_request(drive->queue, real_rq);
-
-	/*
-	 * drive aborted flush command, assume FLUSH_CACHE_* doesn't
-	 * work and disable barrier support
-	 */
-	if (error & ABRT_ERR) {
-		printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name);
-		__ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors);
-		blk_queue_ordered(drive->queue, 0);
-		blk_queue_issue_flush_fn(drive->queue, NULL);
-	} else {
-		/*
-		 * find out what part of the request failed
-		 */
-		good_sectors = 0;
-		if (blk_barrier_postflush(rq)) {
-			sector = ide_get_error_location(drive, rq->buffer);
-
-			if ((sector >= real_rq->hard_sector) &&
-			    (sector < real_rq->hard_sector + real_rq->hard_nr_sectors))
-				good_sectors = sector - real_rq->hard_sector;
-		} else
-			sector = real_rq->hard_sector;
-
-		bad_sectors = real_rq->hard_nr_sectors - good_sectors;
-		if (good_sectors)
-			__ide_end_request(drive, real_rq, 1, good_sectors);
-		if (bad_sectors)
-			__ide_end_request(drive, real_rq, 0, bad_sectors);
-
-		printk(KERN_ERR "%s: failed barrier write: "
-				"sector=%Lx(good=%d/bad=%d)\n",
-				drive->name, (unsigned long long)sector,
-				good_sectors, bad_sectors);
-	}
-
-	drive->doing_barrier = 0;
-}
-
 /**
  *	ide_end_drive_cmd	-	end an explicit drive command
  *	@drive: command 
@@ -409,7 +369,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
 		printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
 			drive->name, rq->pm->pm_step, stat, err);
 #endif
-		DRIVER(drive)->complete_power_step(drive, rq, stat, err);
+		ide_complete_power_step(drive, rq, stat, err);
 		if (rq->pm->pm_step == ide_pm_state_completed)
 			ide_complete_pm_request(drive, rq);
 		return;
@@ -417,11 +377,8 @@ void ide_end_drive_cmd (ide_drive_t *dri
 
 	spin_lock_irqsave(&ide_lock, flags);
 	blkdev_dequeue_request(rq);
-
-	if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq))
-		ide_complete_barrier(drive, rq, err);
-
 	HWGROUP(drive)->rq = NULL;
+	rq->errors = err;
 	end_that_request_last(rq);
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -453,6 +410,17 @@ static void try_to_flush_leftover_data (
 	}
 }
 
+static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
+{
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		drv->end_request(drive, 0, 0);
+	} else
+		ide_end_request(drive, 0, 0);
+}
+
 static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
 	ide_hwif_t *hwif = drive->hwif;
@@ -487,7 +455,7 @@ static ide_startstop_t ide_ata_error(ide
 		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
 
 	if (rq->errors >= ERROR_MAX || blk_noretry_request(rq))
-		drive->driver->end_request(drive, 0, 0);
+		ide_kill_rq(drive, rq);
 	else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -516,7 +484,7 @@ static ide_startstop_t ide_atapi_error(i
 		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
 
 	if (rq->errors >= ERROR_MAX) {
-		drive->driver->end_request(drive, 0, 0);
+		ide_kill_rq(drive, rq);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -536,6 +504,8 @@ __ide_error(ide_drive_t *drive, struct r
 	return ide_atapi_error(drive, rq, stat, err);
 }
 
+EXPORT_SYMBOL_GPL(__ide_error);
+
 /**
  *	ide_error	-	handle an error on the IDE
  *	@drive: drive the error occurred on
@@ -566,7 +536,13 @@ ide_startstop_t ide_error (ide_drive_t *
 		return ide_stopped;
 	}
 
-	return drive->driver->error(drive, rq, stat, err);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->error(drive, rq, stat, err);
+	} else
+		return __ide_error(drive, rq, stat, err);
 }
 
 EXPORT_SYMBOL_GPL(ide_error);
@@ -576,10 +552,13 @@ ide_startstop_t __ide_abort(ide_drive_t 
 	if (drive->media != ide_disk)
 		rq->errors |= ERROR_RESET;
 
-	DRIVER(drive)->end_request(drive, 0, 0);
+	ide_kill_rq(drive, rq);
+
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL_GPL(__ide_abort);
+
 /**
  *	ide_abort	-	abort pending IDE operatins
  *	@drive: drive the error occurred on
@@ -608,7 +587,13 @@ ide_startstop_t ide_abort(ide_drive_t *d
 		return ide_stopped;
 	}
 
-	return drive->driver->abort(drive, rq);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->abort(drive, rq);
+	} else
+		return __ide_abort(drive, rq);
 }
 
 /**
@@ -661,13 +646,72 @@ static ide_startstop_t drive_cmd_intr (i
 			udelay(100);
 	}
 
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT) && DRIVER(drive) != NULL)
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_error(drive, "drive_cmd", stat);
 		/* calls ide_end_drive_cmd */
 	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 	return ide_stopped;
 }
 
+static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+
+	task->handler = &set_geometry_intr;
+}
+
+static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+
+	task->handler = &recal_intr;
+}
+
+static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+
+	task->handler = &set_multmode_intr;
+}
+
+static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+
+	if (s->b.set_geometry) {
+		s->b.set_geometry = 0;
+		ide_init_specify_cmd(drive, &args);
+	} else if (s->b.recalibrate) {
+		s->b.recalibrate = 0;
+		ide_init_restore_cmd(drive, &args);
+	} else if (s->b.set_multmode) {
+		s->b.set_multmode = 0;
+		if (drive->mult_req > drive->id->max_multsect)
+			drive->mult_req = drive->id->max_multsect;
+		ide_init_setmult_cmd(drive, &args);
+	} else if (s->all) {
+		int special = s->all;
+		s->all = 0;
+		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+		return ide_stopped;
+	}
+
+	do_rw_taskfile(drive, &args);
+
+	return ide_started;
+}
+
 /**
  *	do_special		-	issue some special commands
  *	@drive: drive the command is for
@@ -689,9 +733,14 @@ static ide_startstop_t do_special (ide_d
 		if (HWIF(drive)->tuneproc != NULL)
 			HWIF(drive)->tuneproc(drive, drive->tune_req);
 		return ide_stopped;
+	} else {
+		if (drive->media == ide_disk)
+			return ide_disk_special(drive);
+
+		s->all = 0;
+		drive->mult_req = 0;
+		return ide_stopped;
 	}
-	else
-		return DRIVER(drive)->special(drive);
 }
 
 void ide_map_sg(ide_drive_t *drive, struct request *rq)
@@ -897,6 +946,8 @@ static ide_startstop_t start_request (id
 		return startstop;
 	}
 	if (!drive->special.all) {
+		ide_driver_t *drv;
+
 		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
 			return execute_drive_cmd(drive, rq);
 		else if (rq->flags & REQ_DRIVE_TASKFILE)
@@ -906,17 +957,19 @@ static ide_startstop_t start_request (id
 			printk("%s: start_power_step(step: %d)\n",
 				drive->name, rq->pm->pm_step);
 #endif
-			startstop = DRIVER(drive)->start_power_step(drive, rq);
+			startstop = ide_start_power_step(drive, rq);
 			if (startstop == ide_stopped &&
 			    rq->pm->pm_step == ide_pm_state_completed)
 				ide_complete_pm_request(drive, rq);
 			return startstop;
 		}
-		return (DRIVER(drive)->do_request(drive, rq, block));
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->do_request(drive, rq, block);
 	}
 	return do_special(drive);
 kill_rq:
-	DRIVER(drive)->end_request(drive, 0, 0);
+	ide_kill_rq(drive, rq);
 	return ide_stopped;
 }
 
@@ -963,7 +1016,7 @@ repeat:	
 	 * though that is 3 requests, it must be seen as a single transaction.
 	 * we must not preempt this drive until that is complete
 	 */
-	if (drive->doing_barrier) {
+	if (blk_queue_flushing(drive->queue)) {
 		/*
 		 * small race where queue could get replugged during
 		 * the 3-request flush cycle, just yank the plug since
@@ -1128,13 +1181,6 @@ static void ide_do_request (ide_hwgroup_
 		}
 
 		/*
-		 * if rq is a barrier write, issue pre cache flush if not
-		 * already done
-		 */
-		if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq))
-			rq = ide_queue_flush_cmd(drive, rq, 0);
-
-		/*
 		 * Sanity: don't accept a request that isn't a PM request
 		 * if we are currently power managed. This is very important as
 		 * blk_stop_queue() doesn't prevent the elv_next_request()
@@ -1598,8 +1644,6 @@ int ide_do_drive_cmd (ide_drive_t *drive
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
 
-	rq->rq_disk = drive->disk;
-
 	/*
 	 * we need to hold an extra reference to request for safe inspection
 	 * after completion
@@ -1607,6 +1651,7 @@ int ide_do_drive_cmd (ide_drive_t *drive
 	if (must_wait) {
 		rq->ref_count++;
 		rq->waiting = &wait;
+		rq->end_io = blk_end_sync_rq;
 	}
 
 	spin_lock_irqsave(&ide_lock, flags);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1107,9 +1107,27 @@ static void check_dma_crc(ide_drive_t *d
 #endif
 }
 
+static void ide_disk_pre_reset(ide_drive_t *drive)
+{
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
+	drive->special.all = 0;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
+	if (OK_TO_RESET_CONTROLLER)
+		drive->mult_count = 0;
+	if (!drive->keep_settings && !drive->using_dma)
+		drive->mult_req = 0;
+	if (drive->mult_req != drive->mult_count)
+		drive->special.b.set_multmode = 1;
+}
+
 static void pre_reset(ide_drive_t *drive)
 {
-	DRIVER(drive)->pre_reset(drive);
+	if (drive->media == ide_disk)
+		ide_disk_pre_reset(drive);
+	else
+		drive->post_reset = 1;
 
 	if (!drive->keep_settings) {
 		if (drive->using_dma) {
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -47,6 +47,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/pci.h>
@@ -74,7 +75,55 @@ static void generic_id(ide_drive_t *driv
 	drive->id->cur_heads = drive->head;
 	drive->id->cur_sectors = drive->sect;
 }
-		
+
+static void ide_disk_init_chs(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	/* Extract geometry if we did not already have one for the drive */
+	if (!drive->cyl || !drive->head || !drive->sect) {
+		drive->cyl  = drive->bios_cyl  = id->cyls;
+		drive->head = drive->bios_head = id->heads;
+		drive->sect = drive->bios_sect = id->sectors;
+	}
+
+	/* Handle logical geometry translation by the drive */
+	if ((id->field_valid & 1) && id->cur_cyls &&
+	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
+		drive->cyl  = id->cur_cyls;
+		drive->head = id->cur_heads;
+		drive->sect = id->cur_sectors;
+	}
+
+	/* Use physical geometry if what we have still makes no sense */
+	if (drive->head > 16 && id->heads && id->heads <= 16) {
+		drive->cyl  = id->cyls;
+		drive->head = id->heads;
+		drive->sect = id->sectors;
+	}
+}
+
+static void ide_disk_init_mult_count(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	drive->mult_count = 0;
+	if (id->max_multsect) {
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+		id->multsect_valid = id->multsect ? 1 : 0;
+		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else	/* original, pre IDE-NFG, per request of AC */
+		drive->mult_req = INITIAL_MULT_COUNT;
+		if (drive->mult_req > id->max_multsect)
+			drive->mult_req = id->max_multsect;
+		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+			drive->special.b.set_multmode = 1;
+#endif
+	}
+}
+
 /**
  *	drive_is_flashcard	-	check for compact flash
  *	@drive: drive to check
@@ -221,6 +270,8 @@ static inline void do_identify (ide_driv
 		}
 		printk (" drive\n");
 		drive->media = type;
+		/* an ATAPI device ignores DRDY */
+		drive->ready_stat = 0;
 		return;
 	}
 
@@ -588,8 +639,16 @@ static inline u8 probe_for_drive (ide_dr
 	if(!drive->present)
 		return 0;
 	/* The drive wasn't being helpful. Add generic info only */
-	if(!drive->id_read)
+	if (drive->id_read == 0) {
 		generic_id(drive);
+		return 1;
+	}
+
+	if (drive->media == ide_disk) {
+		ide_disk_init_chs(drive);
+		ide_disk_init_mult_count(drive);
+	}
+
 	return drive->present;
 }
 
@@ -638,13 +697,13 @@ static int wait_hwif_ready(ide_hwif_t *h
 	SELECT_DRIVE(&hwif->drives[0]);
 	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 	mdelay(2);
-	rc = ide_wait_not_busy(hwif, 10000);
+	rc = ide_wait_not_busy(hwif, 35000);
 	if (rc)
 		return rc;
 	SELECT_DRIVE(&hwif->drives[1]);
 	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 	mdelay(2);
-	rc = ide_wait_not_busy(hwif, 10000);
+	rc = ide_wait_not_busy(hwif, 35000);
 
 	/* Exit function with master reselected (let's be sane) */
 	SELECT_DRIVE(&hwif->drives[0]);
@@ -804,6 +863,13 @@ static void probe_hwif(ide_hwif_t *hwif)
 				drive->autotune == IDE_TUNE_AUTO)
 				/* auto-tune PIO mode */
 				hwif->tuneproc(drive, 255);
+
+			if (drive->autotune != IDE_TUNE_DEFAULT &&
+			    drive->autotune != IDE_TUNE_AUTO)
+				continue;
+
+			drive->nice1 = 1;
+
 			/*
 			 * MAJOR HACK BARF :-/
 			 *
@@ -813,9 +879,7 @@ static void probe_hwif(ide_hwif_t *hwif)
 			 * Move here to prevent module loading clashing.
 			 */
 	//		drive->autodma = hwif->autodma;
-			if ((hwif->ide_dma_check) &&
-				((drive->autotune == IDE_TUNE_DEFAULT) ||
-				(drive->autotune == IDE_TUNE_AUTO))) {
+			if (hwif->ide_dma_check) {
 				/*
 				 * Force DMAing for the beginning of the check.
 				 * Some chipsets appear to do interesting
@@ -855,7 +919,7 @@ int probe_hwif_init_with_fixup(ide_hwif_
 			   want them on default or a new "empty" class
 			   for hotplug reprobing ? */
 			if (drive->present) {
-				ata_attach(drive);
+				device_register(&drive->gendev);
 			}
 		}
 	}
@@ -948,10 +1012,8 @@ static int ide_init_queue(ide_drive_t *d
 	blk_queue_max_hw_segments(q, max_sg_entries);
 	blk_queue_max_phys_segments(q, max_sg_entries);
 
-	/* assign drive and gendisk queue */
+	/* assign drive queue */
 	drive->queue = q;
-	if (drive->disk)
-		drive->disk->queue = drive->queue;
 
 	/* needs drive->queue to be set */
 	ide_toggle_bounce(drive, 1);
@@ -1151,8 +1213,6 @@ static int ata_lock(dev_t dev, void *dat
 	return 0;
 }
 
-extern ide_driver_t idedefault_driver;
-
 static struct kobject *ata_probe(dev_t dev, int *part, void *data)
 {
 	ide_hwif_t *hwif = data;
@@ -1160,56 +1220,111 @@ static struct kobject *ata_probe(dev_t d
 	ide_drive_t *drive = &hwif->drives[unit];
 	if (!drive->present)
 		return NULL;
-	if (drive->driver == &idedefault_driver) {
-		if (drive->media == ide_disk)
-			(void) request_module("ide-disk");
-		if (drive->scsi)
-			(void) request_module("ide-scsi");
-		if (drive->media == ide_cdrom || drive->media == ide_optical)
-			(void) request_module("ide-cd");
-		if (drive->media == ide_tape)
-			(void) request_module("ide-tape");
-		if (drive->media == ide_floppy)
-			(void) request_module("ide-floppy");
-	}
-	if (drive->driver == &idedefault_driver)
-		return NULL;
+
+	if (drive->media == ide_disk)
+		request_module("ide-disk");
+	if (drive->scsi)
+		request_module("ide-scsi");
+	if (drive->media == ide_cdrom || drive->media == ide_optical)
+		request_module("ide-cd");
+	if (drive->media == ide_tape)
+		request_module("ide-tape");
+	if (drive->media == ide_floppy)
+		request_module("ide-floppy");
+
+	return NULL;
+}
+
+static struct kobject *exact_match(dev_t dev, int *part, void *data)
+{
+	struct gendisk *p = data;
 	*part &= (1 << PARTN_BITS) - 1;
-	return get_disk(drive->disk);
+	return &p->kobj;
 }
 
-static int alloc_disks(ide_hwif_t *hwif)
+static int exact_lock(dev_t dev, void *data)
 {
-	unsigned int unit;
-	struct gendisk *disks[MAX_DRIVES];
+	struct gendisk *p = data;
 
-	for (unit = 0; unit < MAX_DRIVES; unit++) {
-		disks[unit] = alloc_disk(1 << PARTN_BITS);
-		if (!disks[unit])
-			goto Enomem;
-	}
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-		struct gendisk *disk = disks[unit];
-		disk->major  = hwif->major;
-		disk->first_minor = unit << PARTN_BITS;
-		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
-		disk->fops = ide_fops;
-		disk->private_data = drive;
-		drive->disk = disk;
-	}
+	if (!get_disk(p))
+		return -1;
 	return 0;
-Enomem:
-	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
-	while (unit--)
-		put_disk(disks[unit]);
-	return -ENOMEM;
+}
+
+void ide_register_region(struct gendisk *disk)
+{
+	blk_register_region(MKDEV(disk->major, disk->first_minor),
+			    disk->minors, NULL, exact_match, exact_lock, disk);
+}
+
+EXPORT_SYMBOL_GPL(ide_register_region);
+
+void ide_unregister_region(struct gendisk *disk)
+{
+	blk_unregister_region(MKDEV(disk->major, disk->first_minor),
+			      disk->minors);
+}
+
+EXPORT_SYMBOL_GPL(ide_unregister_region);
+
+void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	unsigned int unit = (drive->select.all >> 4) & 1;
+
+	disk->major = hwif->major;
+	disk->first_minor = unit << PARTN_BITS;
+	sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
+	disk->queue = drive->queue;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_disk);
+
+static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+	if (drive == drive->next) {
+		/* special case: last drive from hwgroup. */
+		BUG_ON(hwgroup->drive != drive);
+		hwgroup->drive = NULL;
+	} else {
+		ide_drive_t *walk;
+
+		walk = hwgroup->drive;
+		while (walk->next != drive)
+			walk = walk->next;
+		walk->next = drive->next;
+		if (hwgroup->drive == drive) {
+			hwgroup->drive = drive->next;
+			hwgroup->hwif = hwgroup->drive->hwif;
+		}
+	}
+	BUG_ON(hwgroup->drive == drive);
 }
 
 static void drive_release_dev (struct device *dev)
 {
 	ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
 
+	spin_lock_irq(&ide_lock);
+	if (drive->devfs_name[0] != '\0') {
+		devfs_remove(drive->devfs_name);
+		drive->devfs_name[0] = '\0';
+	}
+	ide_remove_drive_from_hwgroup(drive);
+	if (drive->id != NULL) {
+		kfree(drive->id);
+		drive->id = NULL;
+	}
+	drive->present = 0;
+	/* Messed up locking ... */
+	spin_unlock_irq(&ide_lock);
+	blk_cleanup_queue(drive->queue);
+	spin_lock_irq(&ide_lock);
+	drive->queue = NULL;
+	spin_unlock_irq(&ide_lock);
+
 	up(&drive->gendev_rel_sem);
 }
 
@@ -1233,7 +1348,6 @@ static void init_gendisk (ide_hwif_t *hw
 		drive->gendev.driver_data = drive;
 		drive->gendev.release = drive_release_dev;
 		if (drive->present) {
-			device_register(&drive->gendev);
 			sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
 				(hwif->channel && hwif->mate) ?
 				hwif->mate->index : hwif->index,
@@ -1246,7 +1360,7 @@ static void init_gendisk (ide_hwif_t *hw
 
 static int hwif_init(ide_hwif_t *hwif)
 {
-	int old_irq, unit;
+	int old_irq;
 
 	/* Return success if no device is connected */
 	if (!hwif->present)
@@ -1282,9 +1396,6 @@ static int hwif_init(ide_hwif_t *hwif)
 		printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
 		goto out;
 	}
-
-	if (alloc_disks(hwif) < 0)
-		goto out;
 	
 	if (init_irq(hwif) == 0)
 		goto done;
@@ -1297,12 +1408,12 @@ static int hwif_init(ide_hwif_t *hwif)
 	if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
 		printk("%s: Disabled unable to get IRQ %d.\n",
 			hwif->name, old_irq);
-		goto out_disks;
+		goto out;
 	}
 	if (init_irq(hwif)) {
 		printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 			hwif->name, old_irq, hwif->irq);
-		goto out_disks;
+		goto out;
 	}
 	printk("%s: probed IRQ %d failed, using default.\n",
 		hwif->name, hwif->irq);
@@ -1312,12 +1423,6 @@ done:
 	hwif->present = 1;	/* success */
 	return 1;
 
-out_disks:
-	for (unit = 0; unit < MAX_DRIVES; unit++) {
-		struct gendisk *disk = hwif->drives[unit].disk;
-		hwif->drives[unit].disk = NULL;
-		put_disk(disk);
-	}
 out:
 	unregister_blkdev(hwif->major, hwif->name);
 	return 0;
@@ -1348,7 +1453,7 @@ int ideprobe_init (void)
 				hwif->chipset = ide_generic;
 			for (unit = 0; unit < MAX_DRIVES; ++unit)
 				if (hwif->drives[unit].present)
-					ata_attach(&hwif->drives[unit]);
+					device_register(&hwif->drives[unit].gendev);
 		}
 	}
 	return 0;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -107,8 +107,6 @@ static int proc_ide_read_identify
 	if (drive) {
 		unsigned short *val = (unsigned short *) page;
 
-		BUG_ON(!drive->driver);
-
 		err = taskfile_lib_get_identify(drive, page);
 		if (!err) {
 			char *out = ((char *)page) + (SECTOR_WORDS * 4);
@@ -269,14 +267,12 @@ parse_error:
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_drive_t	*drive = (ide_drive_t *) data;
-	int		len;
-
-	len = sprintf(page,"%llu\n",
-		      (long long) (DRIVER(drive)->capacity(drive)));
+	int len = sprintf(page,"%llu\n", (long long)0x7fffffff);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -311,14 +307,41 @@ static int proc_ide_read_driver
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
-	ide_driver_t	*driver = drive->driver;
+	struct device	*dev = &drive->gendev;
+	ide_driver_t	*ide_drv;
 	int		len;
 
-	len = sprintf(page, "%s version %s\n",
-			driver->name, driver->version);
+	down_read(&dev->bus->subsys.rwsem);
+	if (dev->driver) {
+		ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
+		len = sprintf(page, "%s version %s\n",
+				dev->driver->name, ide_drv->version);
+	} else
+		len = sprintf(page, "ide-default version 0.9.newide\n");
+	up_read(&dev->bus->subsys.rwsem);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
+{
+	struct device *dev = &drive->gendev;
+	int ret = 1;
+
+	down_write(&dev->bus->subsys.rwsem);
+	device_release_driver(dev);
+	/* FIXME: device can still be in use by previous driver */
+	strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
+	device_attach(dev);
+	drive->driver_req[0] = 0;
+	if (dev->driver == NULL)
+		device_attach(dev);
+	if (dev->driver && !strcmp(dev->driver->name, driver))
+		ret = 0;
+	up_write(&dev->bus->subsys.rwsem);
+
+	return ret;
+}
+
 static int proc_ide_write_driver
 	(struct file *file, const char __user *buffer, unsigned long count, void *data)
 {
@@ -423,10 +446,7 @@ static void create_proc_ide_drives(ide_h
 
 static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	ide_driver_t *driver = drive->driver;
-
 	if (drive->proc) {
-		ide_remove_proc_entries(drive->proc, driver->proc);
 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
 		remove_proc_entry(drive->name, proc_ide_root);
 		remove_proc_entry(drive->name, hwif->proc);
@@ -492,16 +512,32 @@ void destroy_proc_ide_interface(ide_hwif
 	}
 }
 
-extern struct seq_operations ide_drivers_op;
+static int proc_print_driver(struct device_driver *drv, void *data)
+{
+	ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver);
+	struct seq_file *s = data;
+
+	seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
+
+	return 0;
+}
+
+static int ide_drivers_show(struct seq_file *s, void *p)
+{
+	bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
+	return 0;
+}
+
 static int ide_drivers_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &ide_drivers_op);
+	return single_open(file, &ide_drivers_show, NULL);
 }
+
 static struct file_operations ide_drivers_operations = {
 	.open		= ide_drivers_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= seq_release,
+	.release	= single_release,
 };
 
 void proc_ide_create(void)
@@ -520,6 +556,6 @@ void proc_ide_create(void)
 
 void proc_ide_destroy(void)
 {
-	remove_proc_entry("ide/drivers", proc_ide_root);
+	remove_proc_entry("drivers", proc_ide_root);
 	remove_proc_entry("ide", NULL);
 }
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -781,8 +781,12 @@ typedef struct {
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idetape_tape_t, defined below.
  */
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_tape_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+
 	/*
 	 *	Since a typical character device operation requires more
 	 *	than one packet command, we provide here enough memory
@@ -1007,6 +1011,34 @@ typedef struct {
          int debug_level; 
 } idetape_tape_t;
 
+static DECLARE_MUTEX(idetape_ref_sem);
+
+#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
+
+#define ide_tape_g(disk) \
+	container_of((disk)->private_data, struct ide_tape_obj, driver)
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+	struct ide_tape_obj *tape = NULL;
+
+	down(&idetape_ref_sem);
+	tape = ide_tape_g(disk);
+	if (tape)
+		kref_get(&tape->kref);
+	up(&idetape_ref_sem);
+	return tape;
+}
+
+static void ide_tape_release(struct kref *);
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+	down(&idetape_ref_sem);
+	kref_put(&tape->kref, ide_tape_release);
+	up(&idetape_ref_sem);
+}
+
 /*
  *	Tape door status
  */
@@ -1093,15 +1125,6 @@ enum {
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	idetape_chrdev_t provides the link between out character device
- *	interface and our block device interface and the corresponding
- *	ide_drive_t structure.
- */
-typedef struct {
-	ide_drive_t *drive;
-} idetape_chrdev_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -1257,7 +1280,21 @@ typedef struct {
  *	The variables below are used for the character device interface.
  *	Additional state variables are defined in our ide_drive_t structure.
  */
-static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
+
+#define ide_tape_f(file) ((file)->private_data)
+
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
+{
+	struct ide_tape_obj *tape = NULL;
+
+	down(&idetape_ref_sem);
+	tape = idetape_devs[i];
+	if (tape)
+		kref_get(&tape->kref);
+	up(&idetape_ref_sem);
+	return tape;
+}
 
 /*
  *      Function declarations
@@ -1509,6 +1546,7 @@ static void idetape_active_next_stage (i
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
+	rq->rq_disk = tape->disk;
 	rq->buffer = NULL;
 	rq->special = (void *)stage->bh;
 	tape->active_data_request = rq;
@@ -1761,8 +1799,11 @@ static void idetape_init_rq(struct reque
  */
 static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
+
 	idetape_init_rq(rq, REQ_IDETAPE_PC1);
 	rq->buffer = (char *) pc;
+	rq->rq_disk = tape->disk;
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -2428,6 +2469,11 @@ static ide_startstop_t idetape_do_reques
 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
+	if (drive->post_reset == 1) {
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+		drive->post_reset = 0;
+	}
+
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
 	if (time_after(jiffies, tape->insert_time))
@@ -2720,6 +2766,7 @@ static void idetape_wait_for_request (id
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	spin_unlock_irq(&tape->spinlock);
 	wait_for_completion(&wait);
 	/* The stage and its struct request have been deallocated */
@@ -2812,10 +2859,12 @@ static void idetape_create_test_unit_rea
  */
 static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
 	struct request rq;
 
 	idetape_init_rq(&rq, REQ_IDETAPE_PC1);
 	rq.buffer = (char *) pc;
+	rq.rq_disk = tape->disk;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
@@ -3039,6 +3088,7 @@ static int idetape_queue_rw_tail(ide_dri
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	idetape_init_rq(&rq, cmd);
+	rq.rq_disk = tape->disk;
 	rq.special = (void *)bh;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
@@ -3558,16 +3608,6 @@ static int idetape_blkdev_ioctl(ide_driv
 }
 
 /*
- *	idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
-static void idetape_pre_reset (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	if (tape != NULL)
-		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-}
-
-/*
  *	idetape_space_over_filemarks is now a bit more complicated than just
  *	passing the command to the tape since we may have crossed some
  *	filemarks during our pipelined read-ahead mode.
@@ -3673,8 +3713,8 @@ static int idetape_space_over_filemarks 
 static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
 				    size_t count, loff_t *ppos)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
 #if IDETAPE_DEBUG_LOG
@@ -3732,8 +3772,8 @@ finish:
 static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
 				     size_t count, loff_t *ppos)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	ssize_t retval, actually_written = 0;
 
 	/* The drive is write protected. */
@@ -4035,8 +4075,8 @@ static int idetape_mtioctop (ide_drive_t
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	struct mtop mtop;
 	struct mtget mtget;
 	struct mtpos mtpos;
@@ -4100,24 +4140,37 @@ static int idetape_chrdev_open (struct i
 	idetape_pc_t pc;
 	int retval;
 
-	nonseekable_open(inode, filp);
+	/*
+	 * We really want to do nonseekable_open(inode, filp); here, but some
+	 * versions of tar incorrectly call lseek on tapes and bail out if that
+	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+	 */
+	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
 #if IDETAPE_DEBUG_LOG
 	printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	
 	if (i >= MAX_HWIFS * MAX_DRIVES)
 		return -ENXIO;
-	drive = idetape_chrdevs[i].drive;
-	tape = drive->driver_data;
-	filp->private_data = drive;
 
-	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
-		return -EBUSY;
+	if (!(tape = ide_tape_chrdev_get(i)))
+		return -ENXIO;
+
+	drive = tape->drive;
+
+	filp->private_data = tape;
+
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) {
+		retval = -EBUSY;
+		goto out_put_tape;
+	}
+
 	retval = idetape_wait_ready(drive, 60 * HZ);
 	if (retval) {
 		clear_bit(IDETAPE_BUSY, &tape->flags);
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
-		return retval;
+		goto out_put_tape;
 	}
 
 	idetape_read_position(drive);
@@ -4141,7 +4194,8 @@ static int idetape_chrdev_open (struct i
 		if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
 		    (filp->f_flags & O_ACCMODE) == O_RDWR) {
 			clear_bit(IDETAPE_BUSY, &tape->flags);
-			return -EROFS;
+			retval = -EROFS;
+			goto out_put_tape;
 		}
 	}
 
@@ -4159,6 +4213,10 @@ static int idetape_chrdev_open (struct i
 	idetape_restart_speed_control(drive);
 	tape->restart_speed_control_req = 0;
 	return 0;
+
+out_put_tape:
+	ide_tape_put(tape);
+	return retval;
 }
 
 static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
@@ -4182,8 +4240,8 @@ static void idetape_write_release (ide_d
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = filp->private_data;
-	idetape_tape_t *tape;
+	struct ide_tape_obj *tape = ide_tape_f(filp);
+	ide_drive_t *drive = tape->drive;
 	idetape_pc_t pc;
 	unsigned int minor = iminor(inode);
 
@@ -4217,6 +4275,7 @@ static int idetape_chrdev_release (struc
 		}
 	}
 	clear_bit(IDETAPE_BUSY, &tape->flags);
+	ide_tape_put(tape);
 	unlock_kernel();
 	return 0;
 }
@@ -4527,11 +4586,7 @@ static void idetape_setup (ide_drive_t *
 	int stage_size;
 	struct sysinfo si;
 
-	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
-	drive->driver_data = tape;
-	/* An ATAPI device ignores DRDY */
-	drive->ready_stat = 0;
 	drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	if (HWIF(drive)->pci_dev != NULL) {
@@ -4549,7 +4604,6 @@ static void idetape_setup (ide_drive_t *
 	/* Seagate Travan drives do not support DSC overlap. */
 	if (strstr(drive->id->model, "Seagate STT3401"))
 		drive->dsc_overlap = 0;
-	tape->drive = drive;
 	tape->minor = minor;
 	tape->name[0] = 'h';
 	tape->name[1] = 't';
@@ -4627,29 +4681,37 @@ static void idetape_setup (ide_drive_t *
 	idetape_add_settings(drive);
 }
 
-static int idetape_cleanup (ide_drive_t *drive)
+static int ide_tape_remove(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	idetape_tape_t *tape = drive->driver_data;
-	int minor = tape->minor;
-	unsigned long flags;
 
-	spin_lock_irqsave(&ide_lock, flags);
-	if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
-	    tape->first_stage != NULL || tape->merge_stage_size) {
-		spin_unlock_irqrestore(&ide_lock, flags);
-		return 1;
-	}
-	idetape_chrdevs[minor].drive = NULL;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver(drive);
+	ide_unregister_subdriver(drive, tape->driver);
+
+	ide_unregister_region(tape->disk);
+
+	ide_tape_put(tape);
+
+	return 0;
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+	struct ide_tape_obj *tape = to_ide_tape(kref);
+	ide_drive_t *drive = tape->drive;
+	struct gendisk *g = tape->disk;
+
+	BUG_ON(tape->first_stage != NULL || tape->merge_stage_size);
+
+	drive->dsc_overlap = 0;
 	drive->driver_data = NULL;
 	devfs_remove("%s/mt", drive->devfs_name);
 	devfs_remove("%s/mtn", drive->devfs_name);
-	devfs_unregister_tape(drive->disk->number);
-	kfree (tape);
-	drive->disk->fops = ide_fops;
-	return 0;
+	devfs_unregister_tape(g->number);
+	idetape_devs[tape->minor] = NULL;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(tape);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -4667,6 +4729,7 @@ static int proc_idetape_read_name
 }
 
 static ide_proc_entry_t idetape_proc[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity, NULL },
 	{ "name",	S_IFREG|S_IRUGO,	proc_idetape_read_name,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
@@ -4677,25 +4740,24 @@ static ide_proc_entry_t idetape_proc[] =
 
 #endif
 
-static int idetape_attach(ide_drive_t *drive);
+static int ide_tape_probe(struct device *);
 
-/*
- *	IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idetape_driver = {
 	.owner			= THIS_MODULE,
-	.name			= "ide-tape",
+	.gen_driver = {
+		.name		= "ide-tape",
+		.bus		= &ide_bus_type,
+		.probe		= ide_tape_probe,
+		.remove		= ide_tape_remove,
+	},
 	.version		= IDETAPE_VERSION,
 	.media			= ide_tape,
-	.busy			= 1,
 	.supports_dsc_overlap 	= 1,
-	.cleanup		= idetape_cleanup,
 	.do_request		= idetape_do_request,
 	.end_request		= idetape_end_request,
-	.pre_reset		= idetape_pre_reset,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
 	.proc			= idetape_proc,
-	.attach			= idetape_attach,
-	.drives			= LIST_HEAD_INIT(idetape_driver.drives),
 };
 
 /*
@@ -4712,15 +4774,30 @@ static struct file_operations idetape_fo
 
 static int idetape_open(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_tape_obj *tape;
+	ide_drive_t *drive;
+
+	if (!(tape = ide_tape_get(disk)))
+		return -ENXIO;
+
+	drive = tape->drive;
+
 	drive->usage++;
+
 	return 0;
 }
 
 static int idetape_release(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_tape_obj *tape = ide_tape_g(disk);
+	ide_drive_t *drive = tape->drive;
+
 	drive->usage--;
+
+	ide_tape_put(tape);
+
 	return 0;
 }
 
@@ -4728,8 +4805,9 @@ static int idetape_ioctl(struct inode *i
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
+	struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+	ide_drive_t *drive = tape->drive;
+	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
 	if (err == -EINVAL)
 		err = idetape_blkdev_ioctl(drive, cmd, arg);
 	return err;
@@ -4742,9 +4820,11 @@ static struct block_device_operations id
 	.ioctl		= idetape_ioctl,
 };
 
-static int idetape_attach (ide_drive_t *drive)
+static int ide_tape_probe(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	idetape_tape_t *tape;
+	struct gendisk *g;
 	int minor;
 
 	if (!strstr("ide-tape", drive->driver_req))
@@ -4770,15 +4850,34 @@ static int idetape_attach (ide_drive_t *
 		printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
 		goto failed;
 	}
-	if (ide_register_subdriver(drive, &idetape_driver)) {
-		printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree(tape);
-		goto failed;
-	}
-	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++)
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_tape;
+
+	ide_init_disk(g, drive);
+
+	ide_register_subdriver(drive, &idetape_driver);
+
+	memset(tape, 0, sizeof(*tape));
+
+	kref_init(&tape->kref);
+
+	tape->drive = drive;
+	tape->driver = &idetape_driver;
+	tape->disk = g;
+
+	g->private_data = &tape->driver;
+
+	drive->driver_data = tape;
+
+	down(&idetape_ref_sem);
+	for (minor = 0; idetape_devs[minor]; minor++)
 		;
+	idetape_devs[minor] = tape;
+	up(&idetape_ref_sem);
+
 	idetape_setup(drive, tape, minor);
-	idetape_chrdevs[minor].drive = drive;
 
 	devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
 			S_IFCHR | S_IRUGO | S_IWUGO,
@@ -4787,11 +4886,16 @@ static int idetape_attach (ide_drive_t *
 			S_IFCHR | S_IRUGO | S_IWUGO,
 			"%s/mtn", drive->devfs_name);
 
-	drive->disk->number = devfs_register_tape(drive->devfs_name);
-	drive->disk->fops = &idetape_block_ops;
+	g->number = devfs_register_tape(drive->devfs_name);
+	g->fops = &idetape_block_ops;
+	ide_register_region(g);
+
 	return 0;
+
+out_free_tape:
+	kfree(tape);
 failed:
-	return 1;
+	return -ENODEV;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -4799,7 +4903,7 @@ MODULE_LICENSE("GPL");
 
 static void __exit idetape_exit (void)
 {
-	ide_unregister_driver(&idetape_driver);
+	driver_unregister(&idetape_driver.gen_driver);
 	unregister_chrdev(IDETAPE_MAJOR, "ht");
 }
 
@@ -4812,8 +4916,7 @@ static int idetape_init (void)
 		printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
 		return -EBUSY;
 	}
-	ide_register_driver(&idetape_driver);
-	return 0;
+	return driver_register(&idetape_driver.gen_driver);
 }
 
 module_init(idetape_init);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -181,8 +181,6 @@ ide_startstop_t set_multmode_intr (ide_d
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(set_multmode_intr);
-
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
@@ -207,8 +205,6 @@ ide_startstop_t set_geometry_intr (ide_d
 	return ide_started;
 }
 
-EXPORT_SYMBOL(set_geometry_intr);
-
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
@@ -222,8 +218,6 @@ ide_startstop_t recal_intr (ide_drive_t 
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(recal_intr);
-
 /*
  * Handler for commands without a data phase
  */
@@ -360,8 +354,12 @@ static ide_startstop_t task_error(ide_dr
 			break;
 		}
 
-		if (sectors > 0)
-			drive->driver->end_request(drive, 1, sectors);
+		if (sectors > 0) {
+			ide_driver_t *drv;
+
+			drv = *(ide_driver_t **)rq->rq_disk->private_data;
+			drv->end_request(drive, 1, sectors);
+		}
 	}
 	return ide_error(drive, s, stat);
 }
@@ -377,7 +375,8 @@ static void task_end_request(ide_drive_t
 			return;
 		}
 	}
-	drive->driver->end_request(drive, 1, rq->hard_nr_sectors);
+
+	ide_end_request(drive, 1, rq->hard_nr_sectors);
 }
 
 /*
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -196,9 +196,6 @@ ide_hwif_t ide_hwifs[MAX_HWIFS];	/* mast
 
 EXPORT_SYMBOL(ide_hwifs);
 
-extern ide_driver_t idedefault_driver;
-static void setup_driver_defaults(ide_driver_t *driver);
-
 /*
  * Do not even *think* about calling this!
  */
@@ -246,7 +243,6 @@ static void init_hwif_data(ide_hwif_t *h
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
 		drive->using_dma		= 0;
 		drive->is_flash			= 0;
-		drive->driver			= &idedefault_driver;
 		drive->vdma			= 0;
 		INIT_LIST_HEAD(&drive->list);
 		sema_init(&drive->gendev_rel_sem, 0);
@@ -301,8 +297,6 @@ static void __init init_ide_data (void)
 		return;		/* already initialized */
 	magic_cookie = 0;
 
-	setup_driver_defaults(&idedefault_driver);
-
 	/* Initialise all interface structures */
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		hwif = &ide_hwifs[index];
@@ -362,66 +356,8 @@ static int ide_system_bus_speed(void)
 	return system_bus_speed;
 }
 
-static int ide_open (struct inode * inode, struct file * filp)
-{
-	return -ENXIO;
-}
-
-/*
- *	drives_lock protects the list of drives, drivers_lock the
- *	list of drivers.  Currently nobody takes both at once.
- */
-
-static DEFINE_SPINLOCK(drives_lock);
-static DEFINE_SPINLOCK(drivers_lock);
-static LIST_HEAD(drivers);
-
-/* Iterator for the driver list. */
-
-static void *m_start(struct seq_file *m, loff_t *pos)
-{
-	struct list_head *p;
-	loff_t l = *pos;
-	spin_lock(&drivers_lock);
-	list_for_each(p, &drivers)
-		if (!l--)
-			return list_entry(p, ide_driver_t, drivers);
-	return NULL;
-}
-
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	struct list_head *p = ((ide_driver_t *)v)->drivers.next;
-	(*pos)++;
-	return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
-}
-
-static void m_stop(struct seq_file *m, void *v)
-{
-	spin_unlock(&drivers_lock);
-}
-
-static int show_driver(struct seq_file *m, void *v)
-{
-	ide_driver_t *driver = v;
-	seq_printf(m, "%s version %s\n", driver->name, driver->version);
-	return 0;
-}
-
-struct seq_operations ide_drivers_op = {
-	.start	= m_start,
-	.next	= m_next,
-	.stop	= m_stop,
-	.show	= show_driver
-};
-
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry *proc_ide_root;
-
-static ide_proc_entry_t generic_subdriver_entries[] = {
-	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
 #endif
 
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
@@ -644,7 +580,7 @@ void ide_unregister(unsigned int index)
 	ide_hwif_t *hwif, *g;
 	static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
 	ide_hwgroup_t *hwgroup;
-	int irq_count = 0, unit, i;
+	int irq_count = 0, unit;
 
 	BUG_ON(index >= MAX_HWIFS);
 
@@ -657,23 +593,22 @@ void ide_unregister(unsigned int index)
 		goto abort;
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
-		if (!drive->present)
+		if (!drive->present) {
+			if (drive->devfs_name[0] != '\0') {
+				devfs_remove(drive->devfs_name);
+				drive->devfs_name[0] = '\0';
+			}
 			continue;
-		if (drive->usage || DRIVER(drive)->busy)
-			goto abort;
-		drive->dead = 1;
+		}
+		spin_unlock_irq(&ide_lock);
+		device_unregister(&drive->gendev);
+		down(&drive->gendev_rel_sem);
+		spin_lock_irq(&ide_lock);
 	}
 	hwif->present = 0;
 
 	spin_unlock_irq(&ide_lock);
 
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		drive = &hwif->drives[unit];
-		if (!drive->present)
-			continue;
-		DRIVER(drive)->cleanup(drive);
-	}
-
 	destroy_proc_ide_interface(hwif);
 
 	hwgroup = hwif->hwgroup;
@@ -701,44 +636,6 @@ void ide_unregister(unsigned int index)
 	 * Remove us from the hwgroup, and free
 	 * the hwgroup if we were the only member
 	 */
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		drive = &hwif->drives[i];
-		if (drive->devfs_name[0] != '\0') {
-			devfs_remove(drive->devfs_name);
-			drive->devfs_name[0] = '\0';
-		}
-		if (!drive->present)
-			continue;
-		if (drive == drive->next) {
-			/* special case: last drive from hwgroup. */
-			BUG_ON(hwgroup->drive != drive);
-			hwgroup->drive = NULL;
-		} else {
-			ide_drive_t *walk;
-
-			walk = hwgroup->drive;
-			while (walk->next != drive)
-				walk = walk->next;
-			walk->next = drive->next;
-			if (hwgroup->drive == drive) {
-				hwgroup->drive = drive->next;
-				hwgroup->hwif = HWIF(hwgroup->drive);
-			}
-		}
-		BUG_ON(hwgroup->drive == drive);
-		if (drive->id != NULL) {
-			kfree(drive->id);
-			drive->id = NULL;
-		}
-		drive->present = 0;
-		/* Messed up locking ... */
-		spin_unlock_irq(&ide_lock);
-		blk_cleanup_queue(drive->queue);
-		device_unregister(&drive->gendev);
-		down(&drive->gendev_rel_sem);
-		spin_lock_irq(&ide_lock);
-		drive->queue = NULL;
-	}
 	if (hwif->next == hwif) {
 		BUG_ON(hwgroup->hwif != hwif);
 		kfree(hwgroup);
@@ -771,11 +668,6 @@ void ide_unregister(unsigned int index)
 	 * Remove us from the kernel's knowledge
 	 */
 	blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
-	for (i = 0; i < MAX_DRIVES; i++) {
-		struct gendisk *disk = hwif->drives[i].disk;
-		hwif->drives[i].disk = NULL;
-		put_disk(disk);
-	}
 	kfree(hwif->sg_table);
 	unregister_blkdev(hwif->major, hwif->name);
 	spin_lock_irq(&ide_lock);
@@ -939,7 +831,7 @@ EXPORT_SYMBOL(ide_register_hw);
 DECLARE_MUTEX(ide_setting_sem);
 
 /**
- *	ide_add_setting	-	add an ide setting option
+ *	__ide_add_setting	-	add an ide setting option
  *	@drive: drive to use
  *	@name: setting name
  *	@rw: true if the function is read write
@@ -952,6 +844,7 @@ DECLARE_MUTEX(ide_setting_sem);
  *	@div_factor: divison scale
  *	@data: private data field
  *	@set: setting
+ *	@auto_remove: setting auto removal flag
  *
  *	Removes the setting named from the device if it is present.
  *	The function takes the settings_lock to protect against 
@@ -963,8 +856,8 @@ DECLARE_MUTEX(ide_setting_sem);
  *	a driver is attached we assume the driver settings are auto
  *	remove.
  */
- 
-int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
@@ -989,7 +882,7 @@ int ide_add_setting (ide_drive_t *drive,
 	setting->set = set;
 	
 	setting->next = *p;
-	if (drive->driver != &idedefault_driver)
+	if (auto_remove)
 		setting->auto_remove = 1;
 	*p = setting;
 	up(&ide_setting_sem);
@@ -1001,6 +894,11 @@ abort:
 	return -1;
 }
 
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+	return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
 EXPORT_SYMBOL(ide_add_setting);
 
 /**
@@ -1290,17 +1188,17 @@ static int set_xfer_rate (ide_drive_t *d
 void ide_add_generic_settings (ide_drive_t *drive)
 {
 /*
- *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
+ *			  drive		setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
  */
-	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
-	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
-	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
-	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
-	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
-	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
-	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
+	__ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
+	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL,		0);
+	__ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
+	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
+	__ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL,		0);
+	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
+	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
+	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
+	__ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
 }
 
 /**
@@ -1317,73 +1215,6 @@ int system_bus_clock (void)
 
 EXPORT_SYMBOL(system_bus_clock);
 
-/*
- *	Locking is badly broken here - since way back.  That sucker is
- * root-only, but that's not an excuse...  The real question is what
- * exclusion rules do we want here.
- */
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->usage || drive->dead)
-		goto abort;
-	if (DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
-	if (ata_attach(drive)) {
-		spin_lock(&drives_lock);
-		list_del_init(&drive->list);
-		spin_unlock(&drives_lock);
-		drive->driver_req[0] = 0;
-		ata_attach(drive);
-	} else {
-		drive->driver_req[0] = 0;
-	}
-	if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
-/**
- *	ata_attach		-	attach an ATA/ATAPI device
- *	@drive: drive to attach
- *
- *	Takes a drive that is as yet not assigned to any midlayer IDE
- *	driver (or is assigned to the default driver) and figures out
- *	which driver would like to own it. If nobody claims the drive
- *	then it is automatically attached to the default driver used for
- *	unclaimed objects.
- *
- *	A return of zero indicates attachment to a driver, of one
- *	attachment to the default driver.
- *
- *	Takes drivers_lock.
- */
-
-int ata_attach(ide_drive_t *drive)
-{
-	struct list_head *p;
-	spin_lock(&drivers_lock);
-	list_for_each(p, &drivers) {
-		ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
-		if (!try_module_get(driver->owner))
-			continue;
-		spin_unlock(&drivers_lock);
-		if (driver->attach(drive) == 0) {
-			module_put(driver->owner);
-			drive->gendev.driver = &driver->gen_driver;
-			return 0;
-		}
-		spin_lock(&drivers_lock);
-		module_put(driver->owner);
-	}
-	drive->gendev.driver = &idedefault_driver.gen_driver;
-	spin_unlock(&drivers_lock);
-	if(idedefault_driver.attach(drive) != 0)
-		panic("ide: default attach failed");
-	return 1;
-}
-
 static int generic_ide_suspend(struct device *dev, pm_message_t state)
 {
 	ide_drive_t *drive = dev->driver_data;
@@ -1422,11 +1253,11 @@ static int generic_ide_resume(struct dev
 	return ide_do_drive_cmd(drive, &rq, ide_head_wait);
 }
 
-int generic_ide_ioctl(struct file *file, struct block_device *bdev,
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
 			unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = bdev->bd_disk->private_data;
 	ide_settings_t *setting;
+	ide_driver_t *drv;
 	int err = 0;
 	void __user *p = (void __user *)arg;
 
@@ -1526,7 +1357,8 @@ int generic_ide_ioctl(struct file *file,
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-			if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+			drv = *(ide_driver_t **)bdev->bd_disk->private_data;
+			if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
 				drive->dsc_overlap = 0;
 				return -EPERM;
 			}
@@ -1751,6 +1583,8 @@ static int __init ide_setup(char *s)
 			case -4: /* "cdrom" */
 				drive->present = 1;
 				drive->media = ide_cdrom;
+				/* an ATAPI device ignores DRDY */
+				drive->ready_stat = 0;
 				hwif->noprobe = 0;
 				goto done;
 			case -5: /* "serialize" */
@@ -1777,6 +1611,7 @@ static int __init ide_setup(char *s)
 				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
+				drive->ready_stat = READY_STAT;
 				drive->cyl	= drive->bios_cyl  = vals[0];
 				drive->head	= drive->bios_head = vals[1];
 				drive->sect	= drive->bios_sect = vals[2];
@@ -2022,99 +1857,11 @@ static void __init probe_for_hwifs (void
 #endif
 }
 
-static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
+void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
 {
-	ide_end_request(drive, 0, 0);
-	return ide_stopped;
-}
-
-static int default_end_request (ide_drive_t *drive, int uptodate, int nr_sects)
-{
-	return ide_end_request(drive, uptodate, nr_sects);
-}
-
-static ide_startstop_t
-default_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
-{
-	return __ide_error(drive, rq, stat, err);
-}
-
-static void default_pre_reset (ide_drive_t *drive)
-{
-}
-
-static sector_t default_capacity (ide_drive_t *drive)
-{
-	return 0x7fffffff;
-}
-
-static ide_startstop_t default_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-	s->all = 0;
-	drive->mult_req = 0;
-	return ide_stopped;
-}
-
-static ide_startstop_t default_abort(ide_drive_t *drive, struct request *rq)
-{
-	return __ide_abort(drive, rq);
-}
-
-static ide_startstop_t default_start_power_step(ide_drive_t *drive,
-						struct request *rq)
-{
-	rq->pm->pm_step = ide_pm_state_completed;
-	return ide_stopped;
-}
-
-static void setup_driver_defaults (ide_driver_t *d)
-{
-	BUG_ON(d->attach == NULL || d->cleanup == NULL);
-
-	if (d->do_request == NULL)	d->do_request = default_do_request;
-	if (d->end_request == NULL)	d->end_request = default_end_request;
-	if (d->error == NULL)		d->error = default_error;
-	if (d->abort == NULL)		d->abort = default_abort;
-	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
-	if (d->capacity == NULL)	d->capacity = default_capacity;
-	if (d->special == NULL)		d->special = default_special;
-	if (d->start_power_step == NULL)
-		d->start_power_step = default_start_power_step;
-}
-
-int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-	unsigned long flags;
-
-	BUG_ON(!drive->driver);
-
-	spin_lock_irqsave(&ide_lock, flags);
-	if (!drive->present || drive->driver != &idedefault_driver ||
-	    drive->usage || drive->dead) {
-		spin_unlock_irqrestore(&ide_lock, flags);
-		return 1;
-	}
-	drive->driver = driver;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	spin_lock(&drives_lock);
-	list_add_tail(&drive->list, &driver->drives);
-	spin_unlock(&drives_lock);
-//	printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
-	if ((drive->autotune == IDE_TUNE_DEFAULT) ||
-		(drive->autotune == IDE_TUNE_AUTO)) {
-		/* DMA timings and setup moved to ide-probe.c */
-		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
-		drive->nice1 = 1;
-	}
 #ifdef CONFIG_PROC_FS
-	if (drive->driver != &idedefault_driver) {
-		ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
-		ide_add_proc_entries(drive->proc, driver->proc, drive);
-	}
+	ide_add_proc_entries(drive->proc, driver->proc, drive);
 #endif
-	return 0;
 }
 
 EXPORT_SYMBOL(ide_register_subdriver);
@@ -2122,146 +1869,51 @@ EXPORT_SYMBOL(ide_register_subdriver);
 /**
  *	ide_unregister_subdriver	-	disconnect drive from driver
  *	@drive: drive to unplug
+ *	@driver: driver
  *
  *	Disconnect a drive from the driver it was attached to and then
  *	clean up the various proc files and other objects attached to it.
  *
- *	Takes ide_setting_sem, ide_lock and drives_lock.
+ *	Takes ide_setting_sem and ide_lock.
  *	Caller must hold none of the locks.
- *
- *	No locking versus subdriver unload because we are moving to the
- *	default driver anyway. Wants double checking.
  */
 
-int ide_unregister_subdriver (ide_drive_t *drive)
+void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
 {
 	unsigned long flags;
 	
 	down(&ide_setting_sem);
 	spin_lock_irqsave(&ide_lock, flags);
-	if (drive->usage || drive->driver == &idedefault_driver || DRIVER(drive)->busy) {
-		spin_unlock_irqrestore(&ide_lock, flags);
-		up(&ide_setting_sem);
-		return 1;
-	}
 #ifdef CONFIG_PROC_FS
-	ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
-	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
+	ide_remove_proc_entries(drive->proc, driver->proc);
 #endif
 	auto_remove_settings(drive);
-	drive->driver = &idedefault_driver;
 	spin_unlock_irqrestore(&ide_lock, flags);
 	up(&ide_setting_sem);
-	spin_lock(&drives_lock);
-	list_del_init(&drive->list);
-	spin_unlock(&drives_lock);
-	/* drive will be added to &idedefault_driver->drives in ata_attach() */
-	return 0;
 }
 
 EXPORT_SYMBOL(ide_unregister_subdriver);
 
-static int ide_drive_remove(struct device * dev)
-{
-	ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
-	DRIVER(drive)->cleanup(drive);
-	return 0;
-}
-
-/**
- *	ide_register_driver	-	register IDE device driver
- *	@driver: the IDE device driver
- *
- *	Register a new device driver and then scan the devices
- *	on the IDE bus in case any should be attached to the
- *	driver we have just registered.  If so attach them.
- *
- *	Takes drivers_lock and drives_lock.
- */
-
-int ide_register_driver(ide_driver_t *driver)
-{
-	struct list_head list;
-	struct list_head *list_loop;
-	struct list_head *tmp_storage;
-
-	setup_driver_defaults(driver);
-
-	spin_lock(&drivers_lock);
-	list_add(&driver->drivers, &drivers);
-	spin_unlock(&drivers_lock);
-
-	INIT_LIST_HEAD(&list);
-	spin_lock(&drives_lock);
-	list_splice_init(&idedefault_driver.drives, &list);
-	spin_unlock(&drives_lock);
-
-	list_for_each_safe(list_loop, tmp_storage, &list) {
-		ide_drive_t *drive = container_of(list_loop, ide_drive_t, list);
-		list_del_init(&drive->list);
-		if (drive->present)
-			ata_attach(drive);
-	}
-	driver->gen_driver.name = (char *) driver->name;
-	driver->gen_driver.bus = &ide_bus_type;
-	driver->gen_driver.remove = ide_drive_remove;
-	return driver_register(&driver->gen_driver);
-}
-
-EXPORT_SYMBOL(ide_register_driver);
-
-/**
- *	ide_unregister_driver	-	unregister IDE device driver
- *	@driver: the IDE device driver
- *
- *	Called when a driver module is being unloaded. We reattach any
- *	devices to whatever driver claims them next (typically the default
- *	driver).
- *
- *	Takes drivers_lock and called functions will take ide_setting_sem.
- */
-
-void ide_unregister_driver(ide_driver_t *driver)
-{
-	ide_drive_t *drive;
-
-	spin_lock(&drivers_lock);
-	list_del(&driver->drivers);
-	spin_unlock(&drivers_lock);
-
-	driver_unregister(&driver->gen_driver);
-
-	while(!list_empty(&driver->drives)) {
-		drive = list_entry(driver->drives.next, ide_drive_t, list);
-		if (driver->cleanup(drive)) {
-			printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
-			BUG();
-		}
-		ata_attach(drive);
-	}
-}
-
-EXPORT_SYMBOL(ide_unregister_driver);
-
-struct block_device_operations ide_fops[] = {{
-	.owner		= THIS_MODULE,
-	.open		= ide_open,
-}};
-
-EXPORT_SYMBOL(ide_fops);
-
 /*
  * Probe module
  */
 
 EXPORT_SYMBOL(ide_lock);
 
+static int ide_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
 struct bus_type ide_bus_type = {
 	.name		= "ide",
+	.match		= ide_bus_match,
 	.suspend	= generic_ide_suspend,
 	.resume		= generic_ide_resume,
 };
 
+EXPORT_SYMBOL_GPL(ide_bus_type);
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -851,7 +851,7 @@ Enomem:
 	goto out;
 }
 
-static int parse_hd_setup (char *line) {
+static int __init parse_hd_setup (char *line) {
 	int ints[6];
 
 	(void) get_options(line, ARRAY_SIZE(ints), ints);
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -72,6 +72,7 @@ static struct amd_ide_chip {
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	0x50, AMD_UDMA_133 },
+	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,	0x50, AMD_UDMA_133 },
 	{ 0 }
 };
 
@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets
 	/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
 	/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
 	/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
+	/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
 };
 
 static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_
 #endif
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -47,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -227,7 +228,7 @@ static int __devinit cs5520_init_one(str
 		return 1;
 	}
 	pci_set_master(dev);
-	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
+	if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "cs5520: No suitable DMA available.\n");
 		return -ENODEV;
 	}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -134,6 +134,7 @@ static u8 piix_ratemask (ide_drive_t *dr
 		case PCI_DEVICE_ID_INTEL_ESB_2:
 		case PCI_DEVICE_ID_INTEL_ICH6_19:
 		case PCI_DEVICE_ID_INTEL_ICH7_21:
+		case PCI_DEVICE_ID_INTEL_ESB2_18:
 			mode = 3;
 			break;
 		/* UDMA 66 capable */
@@ -447,6 +448,7 @@ static unsigned int __devinit init_chips
 		case PCI_DEVICE_ID_INTEL_ESB_2:
 		case PCI_DEVICE_ID_INTEL_ICH6_19:
 		case PCI_DEVICE_ID_INTEL_ICH7_21:
+		case PCI_DEVICE_ID_INTEL_ESB2_18:
 		{
 			unsigned int extra = 0;
 			pci_read_config_dword(dev, 0x54, &extra);
@@ -572,6 +574,7 @@ static ide_pci_device_t piix_pci_info[] 
 	/* 20 */ DECLARE_PIIX_DEV("ICH6"),
 	/* 21 */ DECLARE_PIIX_DEV("ICH7"),
 	/* 22 */ DECLARE_PIIX_DEV("ICH4"),
+	/* 23 */ DECLARE_PIIX_DEV("ESB2"),
 };
 
 /**
@@ -647,6 +650,7 @@ static struct pci_device_id piix_pci_tbl
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23},
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -346,7 +346,7 @@ typedef struct sc1200_saved_state_s {
 } sc1200_saved_state_t;
 
 
-static int sc1200_suspend (struct pci_dev *dev, u32 state)
+static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 {
 	ide_hwif_t		*hwif = NULL;
 
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -341,7 +341,7 @@ static int svwks_ide_dma_end (ide_drive_
 	return __ide_dma_end(drive);
 }
 
-static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name)
 {
 	unsigned int reg;
 	u8 btr;
@@ -508,7 +508,7 @@ static unsigned int __init ata66_svwks (
 }
 
 #undef CAN_SW_DMA
-static void __init init_hwif_svwks (ide_hwif_t *hwif)
+static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
 	u8 dma_stat = 0;
 
@@ -556,7 +556,7 @@ static void __init init_hwif_svwks (ide_
 /*
  * We allow the BM-DMA driver to only work on enabled interfaces.
  */
-static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 
@@ -568,7 +568,7 @@ static void __init init_dma_svwks (ide_h
 	ide_setup_dma(hwif, dmabase, 8);
 }
 
-static int __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	return ide_setup_pci_device(dev, d);
 }
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -34,6 +34,7 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/ioc4_common.h>
 #include <asm/io.h>
 
 #include <linux/ide.h>
@@ -684,23 +685,14 @@ pci_init_sgiioc4(struct pci_dev *dev, id
 	unsigned int class_rev;
 	int ret;
 
-	ret = pci_enable_device(dev);
-	if (ret < 0) {
-		printk(KERN_ERR
-		       "Failed to enable device %s at slot %s\n",
-		       d->name, dev->slot_name);
-		goto out;
-	}
-	pci_set_master(dev);
-
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 	printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
-			d->name, dev->slot_name, class_rev);
+			d->name, pci_name(dev), class_rev);
 	if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
 		printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
 			"firmware is obsolete - please upgrade to revision"
-			"46 or higher\n", d->name, dev->slot_name);
+			"46 or higher\n", d->name, pci_name(dev));
 		ret = -EAGAIN;
 		goto out;
 	}
@@ -722,34 +714,15 @@ static ide_pci_device_t sgiioc4_chipsets
 	}
 };
 
-static int __devinit
-sgiioc4_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+int
+ioc4_ide_attach_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]);
-	return 0;
+	return pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]);
 }
 
-static struct pci_device_id sgiioc4_pci_tbl[] = {
-	{PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
-	 PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0},
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl);
-
-static struct pci_driver __devinitdata driver = {
-	.name = "SGI-IOC4_IDE",
-	.id_table = sgiioc4_pci_tbl,
-	.probe = sgiioc4_init_one,
-};
-
-static int __devinit
-sgiioc4_ide_init(void)
-{
-	return ide_pci_register_driver(&driver);
-}
-
-module_init(sgiioc4_ide_init);
 
 MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
-MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
 MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc4_ide_attach_one);
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -726,7 +726,7 @@ static int sis5513_config_xfer_rate (ide
 */
 
 /* Chip detection and general config */
-static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
 	int i = 0;
@@ -879,7 +879,7 @@ static unsigned int __init init_chipset_
 	return 0;
 }
 
-static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_sis5513 (ide_hwif_t *hwif)
 {
 	u8 ata66 = 0;
 
@@ -897,7 +897,7 @@ static unsigned int __init ata66_sis5513
         return ata66;
 }
 
-static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
 {
 	hwif->autodma = 0;
 
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -332,11 +332,8 @@ static int via_set_drive(ide_drive_t *dr
 	struct ide_timing t, p;
 	unsigned int T, UT;
 
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't "
-				"accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
+	if (speed != XFER_PIO_SLOW)
+		ide_config_drive_speed(drive, speed);
 
 	T = 1000000000 / via_clock;
 
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -68,6 +68,7 @@ typedef struct pmac_ide_hwif {
 	struct device_node*		node;
 	struct macio_dev		*mdev;
 	u32				timings[4];
+	volatile u32 __iomem *		*kauai_fcr;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* Those fields are duplicating what is in hwif. We currently
 	 * can't use the hwif ones because of some assumptions that are
@@ -89,7 +90,8 @@ enum {
 	controller_kl_ata3,	/* KeyLargo ATA-3 */
 	controller_kl_ata4,	/* KeyLargo ATA-4 */
 	controller_un_ata6,	/* UniNorth2 ATA-6 */
-	controller_k2_ata6	/* K2 ATA-6 */
+	controller_k2_ata6,	/* K2 ATA-6 */
+	controller_sh_ata6,	/* Shasta ATA-6 */
 };
 
 static const char* model_name[] = {
@@ -99,6 +101,7 @@ static const char* model_name[] = {
 	"KeyLargo ATA-4",	/* KeyLargo ATA-4 (UDMA/66) */
 	"UniNorth ATA-6",	/* UniNorth2 ATA-6 (UDMA/100) */
 	"K2 ATA-6",		/* K2 ATA-6 (UDMA/100) */
+	"Shasta ATA-6",		/* Shasta ATA-6 (UDMA/133) */
 };
 
 /*
@@ -122,6 +125,15 @@ static const char* model_name[] = {
 #define IDE_SYSCLK_NS		30	/* 33Mhz cell */
 #define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
 
+/* 133Mhz cell, found in shasta.
+ * See comments about 100 Mhz Uninorth 2...
+ * Note that PIO_MASK and MDMA_MASK seem to overlap
+ */
+#define TR_133_PIOREG_PIO_MASK		0xff000fff
+#define TR_133_PIOREG_MDMA_MASK		0x00fff800
+#define TR_133_UDMAREG_UDMA_MASK	0x0003ffff
+#define TR_133_UDMAREG_UDMA_EN		0x00000001
+
 /* 100Mhz cell, found in Uninorth 2. I don't have much infos about
  * this one yet, it appears as a pci device (106b/0033) on uninorth
  * internal PCI bus and it's clock is controlled like gem or fw. It
@@ -209,6 +221,13 @@ static const char* model_name[] = {
 #define IDE_INTR_DMA			0x80000000
 #define IDE_INTR_DEVICE			0x40000000
 
+/*
+ * FCR Register on Kauai. Not sure what bit 0x4 is  ...
+ */
+#define KAUAI_FCR_UATA_MAGIC		0x00000004
+#define KAUAI_FCR_UATA_RESET_N		0x00000002
+#define KAUAI_FCR_UATA_ENABLE		0x00000001
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
 /* Rounded Multiword DMA timings
@@ -322,6 +341,48 @@ static struct kauai_timing	kauai_udma_ti
 	{ 0	, 0 },
 };
 
+static struct kauai_timing	shasta_pio_timings[] __pmacdata =
+{
+	{ 930	, 0x08000fff },
+	{ 600	, 0x0A000c97 },
+	{ 383	, 0x07000712 },
+	{ 360	, 0x040003cd },
+	{ 330	, 0x040003cd },
+	{ 300	, 0x040003cd },
+	{ 270	, 0x040003cd },
+	{ 240	, 0x040003cd },
+	{ 239	, 0x040003cd },
+	{ 180	, 0x0400028b },
+	{ 120	, 0x0400010a }
+};
+
+static struct kauai_timing	shasta_mdma_timings[] __pmacdata =
+{
+	{ 1260	, 0x00fff000 },
+	{ 480	, 0x00820800 },
+	{ 360	, 0x00820800 },
+	{ 270	, 0x00820800 },
+	{ 240	, 0x00820800 },
+	{ 210	, 0x00820800 },
+	{ 180	, 0x00820800 },
+	{ 150	, 0x0028b000 },
+	{ 120	, 0x001ca000 },
+	{ 0	, 0 },
+};
+
+static struct kauai_timing	shasta_udma133_timings[] __pmacdata =
+{
+	{ 120   , 0x00035901, },
+	{ 90    , 0x000348b1, },
+	{ 60    , 0x00033881, },
+	{ 45    , 0x00033861, },
+	{ 30    , 0x00033841, },
+	{ 20    , 0x00033031, },
+	{ 15    , 0x00033021, },
+	{ 0	, 0 },
+};
+
+
 static inline u32
 kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
 {
@@ -547,7 +608,9 @@ pmac_ide_do_update_timings(ide_drive_t *
 	if (pmif == NULL)
 		return;
 
-	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+	if (pmif->kind == controller_sh_ata6 ||
+	    pmif->kind == controller_un_ata6 ||
+	    pmif->kind == controller_k2_ata6)
 		pmac_ide_kauai_selectproc(drive);
 	else
 		pmac_ide_selectproc(drive);
@@ -665,6 +728,14 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8
 	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
 
 	switch (pmif->kind) {
+	case controller_sh_ata6: {
+		/* 133Mhz cell */
+		u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+		if (tr == 0)
+			return;
+		*timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
+		break;
+		}
 	case controller_un_ata6:
 	case controller_k2_ata6: {
 		/* 100Mhz cell */
@@ -776,6 +847,26 @@ set_timings_udma_ata6(u32 *pio_timings, 
 }
 
 /*
+ * Calculate Shasta ATA/133 UDMA timings
+ */
+static int __pmac
+set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
+{
+	struct ide_timing *t = ide_timing_find_mode(speed);
+	u32 tr;
+
+	if (speed > XFER_UDMA_6 || t == NULL)
+		return 1;
+	tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
+	if (tr == 0)
+		return 1;
+	*ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
+	*ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
+
+	return 0;
+}
+
+/*
  * Calculate MDMA timings for all cells
  */
 static int __pmac
@@ -803,6 +894,7 @@ set_timings_mdma(ide_drive_t *drive, int
 		cycleTime = 150;
 	/* Get the proper timing array for this controller */
 	switch(intf_type) {
+	        case controller_sh_ata6:
 		case controller_un_ata6:
 		case controller_k2_ata6:
 			break;
@@ -836,6 +928,14 @@ set_timings_mdma(ide_drive_t *drive, int
 #endif
 	}
 	switch(intf_type) {
+	case controller_sh_ata6: {
+		/* 133Mhz cell */
+		u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
+		if (tr == 0)
+			return 1;
+		*timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
+		*timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
+		}
 	case controller_un_ata6:
 	case controller_k2_ata6: {
 		/* 100Mhz cell */
@@ -930,9 +1030,13 @@ pmac_ide_tune_chipset (ide_drive_t *driv
 	
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		case XFER_UDMA_6:
+		        if (pmif->kind != controller_sh_ata6)
+				return 1;
 		case XFER_UDMA_5:
 			if (pmif->kind != controller_un_ata6 &&
-			    pmif->kind != controller_k2_ata6)
+			    pmif->kind != controller_k2_ata6 &&
+			    pmif->kind != controller_sh_ata6)
 				return 1;
 		case XFER_UDMA_4:
 		case XFER_UDMA_3:
@@ -946,6 +1050,8 @@ pmac_ide_tune_chipset (ide_drive_t *driv
 			else if (pmif->kind == controller_un_ata6
 				 || pmif->kind == controller_k2_ata6)
 				ret = set_timings_udma_ata6(timings, timings2, speed);
+			else if (pmif->kind == controller_sh_ata6)
+				ret = set_timings_udma_shasta(timings, timings2, speed);
 			else
 				ret = 1;		
 			break;
@@ -992,6 +1098,10 @@ sanitize_timings(pmac_ide_hwif_t *pmif)
 	unsigned int value, value2 = 0;
 	
 	switch(pmif->kind) {
+		case controller_sh_ata6:
+			value = 0x0a820c97;
+			value2 = 0x00033031;
+			break;
 		case controller_un_ata6:
 		case controller_k2_ata6:
 			value = 0x08618a92;
@@ -1094,12 +1204,22 @@ pmac_ide_do_suspend(ide_hwif_t *hwif)
 	}
 #endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
 
+	disable_irq(pmif->irq);
+
 	/* The media bay will handle itself just fine */
 	if (pmif->mediabay)
 		return 0;
 	
-	/* Disable the bus */
-	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 0);
+	/* Kauai has bus control FCRs directly here */
+	if (pmif->kauai_fcr) {
+		u32 fcr = readl(pmif->kauai_fcr);
+		fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
+		writel(fcr, pmif->kauai_fcr);
+	}
+
+	/* Disable the bus on older machines and the cell on kauai */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id,
+			    0);
 
 	return 0;
 }
@@ -1118,12 +1238,22 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
 		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
 		msleep(10);
 		ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
+
+		/* Kauai has it different */
+		if (pmif->kauai_fcr) {
+			u32 fcr = readl(pmif->kauai_fcr);
+			fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE;
+			writel(fcr, pmif->kauai_fcr);
+		}
+
 		msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
 	}
 
 	/* Sanitize drive timings */
 	sanitize_timings(pmif);
 
+	enable_irq(pmif->irq);
+
 	return 0;
 }
 
@@ -1142,7 +1272,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 
 	pmif->cable_80 = 0;
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
-	if (device_is_compatible(np, "kauai-ata"))
+	if (device_is_compatible(np, "shasta-ata"))
+		pmif->kind = controller_sh_ata6;
+	else if (device_is_compatible(np, "kauai-ata"))
 		pmif->kind = controller_un_ata6;
 	else if (device_is_compatible(np, "K2-UATA"))
 		pmif->kind = controller_k2_ata6;
@@ -1163,11 +1295,25 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 
 	/* Get cable type from device-tree */
 	if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
-	    || pmif->kind == controller_k2_ata6) {
+	    || pmif->kind == controller_k2_ata6
+	    || pmif->kind == controller_sh_ata6) {
 		char* cable = get_property(np, "cable-type", NULL);
 		if (cable && !strncmp(cable, "80-", 3))
 			pmif->cable_80 = 1;
 	}
+	/* G5's seem to have incorrect cable type in device-tree. Let's assume
+	 * they have a 80 conductor cable, this seem to be always the case unless
+	 * the user mucked around
+	 */
+	if (device_is_compatible(np, "K2-UATA") ||
+	    device_is_compatible(np, "shasta-ata"))
+		pmif->cable_80 = 1;
+
+	/* On Kauai-type controllers, we make sure the FCR is correct */
+	if (pmif->kauai_fcr)
+		writel(KAUAI_FCR_UATA_MAGIC |
+		       KAUAI_FCR_UATA_RESET_N |
+		       KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
 
 	pmif->mediabay = 0;
 	
@@ -1217,7 +1363,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	hwif->drives[0].unmask = 1;
 	hwif->drives[1].unmask = 1;
 	hwif->tuneproc = pmac_ide_tuneproc;
-	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+	if (pmif->kind == controller_un_ata6
+	    || pmif->kind == controller_k2_ata6
+	    || pmif->kind == controller_sh_ata6)
 		hwif->selectproc = pmac_ide_kauai_selectproc;
 	else
 		hwif->selectproc = pmac_ide_selectproc;
@@ -1327,6 +1475,7 @@ pmac_ide_macio_attach(struct macio_dev *
 	pmif->node = mdev->ofdev.node;
 	pmif->regbase = regbase;
 	pmif->irq = irq;
+	pmif->kauai_fcr = NULL;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	if (macio_resource_count(mdev) >= 2) {
 		if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
@@ -1440,13 +1589,9 @@ pmac_ide_pci_attach(struct pci_dev *pdev
 	pmif->regbase = (unsigned long) base + 0x2000;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	pmif->dma_regs = base + 0x1000;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */	
-
-	/* We use the OF node irq mapping */
-	if (np->n_intrs == 0)
-		pmif->irq = pdev->irq;
-	else
-		pmif->irq = np->intrs[0].line;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+	pmif->kauai_fcr = base;
+	pmif->irq = pdev->irq;
 
 	pci_set_drvdata(pdev, hwif);
 
@@ -1530,6 +1675,8 @@ static struct pci_device_id pmac_ide_pci
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVIEC_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 };
 
 static struct pci_driver pmac_ide_pci_driver = {
@@ -1539,6 +1686,7 @@ static struct pci_driver pmac_ide_pci_dr
 	.suspend	= pmac_ide_pci_suspend,
 	.resume		= pmac_ide_pci_resume,
 };
+MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
 
 void __init
 pmac_ide_probe(void)
@@ -1737,10 +1885,15 @@ pmac_ide_udma_enable(ide_drive_t *drive,
 	timing_local[1] = *timings2;
 	
 	/* Calculate timings for interface */
-	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+	if (pmif->kind == controller_un_ata6
+	    || pmif->kind == controller_k2_ata6)
 		ret = set_timings_udma_ata6(	&timing_local[0],
 						&timing_local[1],
 						mode);
+	else if (pmif->kind == controller_sh_ata6)
+		ret = set_timings_udma_shasta(	&timing_local[0],
+						&timing_local[1],
+						mode);
 	else
 		ret = set_timings_udma_ata4(&timing_local[0], mode);
 	if (ret)
@@ -1791,14 +1944,19 @@ pmac_ide_dma_check(ide_drive_t *drive)
 		short mode;
 		
 		map = XFER_MWDMA;
-		if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
-		    || pmif->kind == controller_k2_ata6) {
+		if (pmif->kind == controller_kl_ata4
+		    || pmif->kind == controller_un_ata6
+		    || pmif->kind == controller_k2_ata6
+		    || pmif->kind == controller_sh_ata6) {
 			map |= XFER_UDMA;
 			if (pmif->cable_80) {
 				map |= XFER_UDMA_66;
 				if (pmif->kind == controller_un_ata6 ||
-				    pmif->kind == controller_k2_ata6)
+				    pmif->kind == controller_k2_ata6 ||
+				    pmif->kind == controller_sh_ata6)
 					map |= XFER_UDMA_100;
+				if (pmif->kind == controller_sh_ata6)
+					map |= XFER_UDMA_133;
 			}
 		}
 		mode = ide_find_best_mode(drive, map);
@@ -2028,6 +2186,11 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif
 
 	hwif->atapi_dma = 1;
 	switch(pmif->kind) {
+		case controller_sh_ata6:
+			hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
+			hwif->mwdma_mask = 0x07;
+			hwif->swdma_mask = 0x00;
+			break;
 		case controller_un_ata6:
 		case controller_k2_ata6:
 			hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -5,6 +5,7 @@ menu "IEEE 1394 (FireWire) support"
 config IEEE1394
 	tristate "IEEE 1394 (FireWire) support"
 	depends on PCI || BROKEN
+	select NET
 	help
 	  IEEE 1394 describes a high performance serial bus, which is also
 	  known as FireWire(tm) or i.Link(tm) and is used for connecting all
@@ -83,11 +84,6 @@ config IEEE1394_PCILYNX
 	  To compile this driver as a module, say M here: the
 	  module will be called pcilynx.
 
-# Non-maintained pcilynx options
-# if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
-#     bool '    Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
-#     bool '    Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
-# fi
 config IEEE1394_OHCI1394
 	tristate "OHCI-1394 support"
 	depends on PCI && IEEE1394
diff --git a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c
--- a/drivers/ieee1394/amdtp.c
+++ b/drivers/ieee1394/amdtp.c
@@ -286,7 +286,7 @@ static struct hpsb_highlevel amdtp_highl
 #define OHCI1394_CONTEXT_DEAD        0x00000800
 #define OHCI1394_CONTEXT_ACTIVE      0x00000400
 
-void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx,
+static void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx,
 			   dma_addr_t first_cmd, int z, int cycle_match)
 {
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx);
@@ -298,13 +298,13 @@ void ohci1394_start_it_ctx(struct ti_ohc
 		  OHCI1394_CONTEXT_RUN);
 }
 
-void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx)
+static void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx)
 {
 	reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16,
 		  OHCI1394_CONTEXT_WAKE);
 }
 
-void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous)
+static void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous)
 {
 	u32 control;
 	int wait;
@@ -530,7 +530,7 @@ static __inline__ int fraction_ceil(stru
 	return frac->integer + (frac->numerator > 0 ? 1 : 0);
 }
 
-void packet_initialize(struct packet *p, struct packet *next)
+static void packet_initialize(struct packet *p, struct packet *next)
 {
 	/* Here we initialize the dma descriptor block for
 	 * transferring one iso packet.  We use two descriptors per
@@ -559,7 +559,7 @@ void packet_initialize(struct packet *p,
 	p->db->payload_desc.status = 0;
 }
 
-struct packet_list *packet_list_alloc(struct stream *s)
+static struct packet_list *packet_list_alloc(struct stream *s)
 {
 	int i;
 	struct packet_list *pl;
@@ -588,7 +588,7 @@ struct packet_list *packet_list_alloc(st
 	return pl;
 }
 
-void packet_list_free(struct packet_list *pl, struct stream *s)
+static void packet_list_free(struct packet_list *pl, struct stream *s)
 {
 	int i;
 
@@ -1010,7 +1010,7 @@ static int stream_configure(struct strea
 	return 0;
 }
 
-struct stream *stream_alloc(struct amdtp_host *host)
+static struct stream *stream_alloc(struct amdtp_host *host)
 {
 	struct stream *s;
 	unsigned long flags;
@@ -1062,7 +1062,7 @@ struct stream *stream_alloc(struct amdtp
 	return s;
 }
 
-void stream_free(struct stream *s)
+static void stream_free(struct stream *s)
 {
 	unsigned long flags;
 
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
--- a/drivers/ieee1394/config_roms.c
+++ b/drivers/ieee1394/config_roms.c
@@ -67,8 +67,8 @@ int hpsb_default_host_entry(struct hpsb_
 	ret = csr1212_associate_keyval(vend_id, text);
 	csr1212_release_keyval(text);
 	ret |= csr1212_attach_keyval_to_directory(root, vend_id);
+	csr1212_release_keyval(vend_id);
 	if (ret != CSR1212_SUCCESS) {
-		csr1212_release_keyval(vend_id);
 		csr1212_destroy_csr(host->csr.rom);
 		return -ENOMEM;
 	}
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -87,7 +87,8 @@ static const u_int8_t csr1212_key_id_typ
 
 static inline void free_keyval(struct csr1212_keyval *kv)
 {
-	if (kv->key.type == CSR1212_KV_TYPE_LEAF)
+	if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
+	    (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
 		CSR1212_FREE(kv->value.leaf.data);
 
 	CSR1212_FREE(kv);
@@ -155,7 +156,7 @@ static inline struct csr1212_keyval *csr
 {
 	struct csr1212_keyval *kv;
 
-	for (kv = kv_list; kv != NULL; kv = kv->next) {
+	for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) {
 		if (kv->offset == offset)
 			return kv;
 	}
@@ -181,9 +182,9 @@ struct csr1212_csr *csr1212_create_csr(s
 		return NULL;
 	}
 
-        /* The keyval key id is not used for the root node, but a valid key id
-         * that can be used for a directory needs to be passed to
-         * csr1212_new_directory(). */
+	/* The keyval key id is not used for the root node, but a valid key id
+	 * that can be used for a directory needs to be passed to
+	 * csr1212_new_directory(). */
 	csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
 	if (!csr->root_kv) {
 		CSR1212_FREE(csr->cache_head);
@@ -709,7 +710,7 @@ void _csr1212_destroy_keyval(struct csr1
 					tail->next = k->value.directory.dentries_head;
 					k->value.directory.dentries_head->prev = tail;
 					tail = k->value.directory.dentries_tail;
-                                }
+				}
 			}
 			free_keyval(k);
 			k = a;
@@ -796,7 +797,8 @@ static int csr1212_append_new_cache(stru
 		return CSR1212_ENOMEM;
 	}
 	cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
-	cache->ext_rom->value.leaf.len = 0;
+	cache->ext_rom->value.leaf.len = -1;
+	cache->ext_rom->value.leaf.data = cache->data;
 
 	/* Add cache to tail of cache list */
 	cache->prev = csr->cache_tail;
@@ -864,20 +866,20 @@ static int csr1212_generate_layout_subdi
 			default:
 			case CSR1212_KV_TYPE_IMMEDIATE:
 			case CSR1212_KV_TYPE_CSR_OFFSET:
-				continue;
+				break;
 			case CSR1212_KV_TYPE_LEAF:
 			case CSR1212_KV_TYPE_DIRECTORY:
 				/* Remove from list */
-				if (dkv->prev)
+				if (dkv->prev && (dkv->prev->next == dkv))
 					dkv->prev->next = dkv->next;
-				if (dkv->next)
+				if (dkv->next && (dkv->next->prev == dkv))
 					dkv->next->prev = dkv->prev;
-				if (dkv == *layout_tail)
-					*layout_tail = dkv->prev;
+				//if (dkv == *layout_tail)
+				//	*layout_tail = dkv->prev;
 
 				/* Special case: Extended ROM leafs */
 				if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
-					dkv->value.leaf.len = 0; /* initialize to zero */
+					dkv->value.leaf.len = -1;
 					/* Don't add Extended ROM leafs in the layout list,
 					 * they are handled differently. */
 					break;
@@ -919,8 +921,8 @@ size_t csr1212_generate_layout_order(str
 }
 
 struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
-                                                  struct csr1212_keyval *start_kv,
-                                                  int start_pos)
+						  struct csr1212_keyval *start_kv,
+						  int start_pos)
 {
 	struct csr1212_keyval *kv = start_kv;
 	struct csr1212_keyval *okv = start_kv;
@@ -930,7 +932,10 @@ struct csr1212_keyval *csr1212_generate_
 	cache->layout_head = kv;
 
 	while(kv && pos < cache->size) {
-		kv->offset = cache->offset + pos;
+		/* Special case: Extended ROM leafs */
+		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
+			kv->offset = cache->offset + pos;
+		}
 
 		switch(kv->key.type) {
 		case CSR1212_KV_TYPE_LEAF:
@@ -1090,6 +1095,9 @@ int csr1212_generate_csr_image(struct cs
 	bi->crc_length = bi->length;
 	bi->crc = csr1212_crc16(bi->data, bi->crc_length);
 
+	csr->root_kv->next = NULL;
+	csr->root_kv->prev = NULL;
+
 	agg_size = csr1212_generate_layout_order(csr->root_kv);
 
 	init_offset = csr->bus_info_len;
@@ -1158,6 +1166,17 @@ int csr1212_generate_csr_image(struct cs
 
 		/* Copy the data into the cache buffer */
 		csr1212_fill_cache(cache);
+
+		if (cache != csr->cache_head) {
+			/* Set the length and CRC of the extended ROM. */
+			struct csr1212_keyval_img *kvi =
+				(struct csr1212_keyval_img*)cache->data;
+
+			kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1);
+			kvi->crc = csr1212_crc16(kvi->data,
+						 bytes_to_quads(cache->len) - 1);
+
+		}
 	}
 
 	return CSR1212_SUCCESS;
@@ -1174,11 +1193,6 @@ int csr1212_read(struct csr1212_csr *csr
 			       &cache->data[bytes_to_quads(offset - cache->offset)],
 			       len);
 			return CSR1212_SUCCESS;
-		} else if (((offset < cache->offset) &&
-			    ((offset + len) >= cache->offset)) ||
-			   ((offset >= cache->offset) &&
-			    ((offset + len) > (cache->offset + cache->size)))) {
-			return CSR1212_EINVAL;
 		}
 	}
 	return CSR1212_ENOENT;
@@ -1227,8 +1241,8 @@ static int csr1212_parse_bus_info_block(
 		return CSR1212_EINVAL;
 
 #if 0
-        /* Apparently there are too many differnt wrong implementations of the
-         * CRC algorithm that verifying them is moot. */
+	/* Apparently there are too many differnt wrong implementations of the
+	 * CRC algorithm that verifying them is moot. */
 	if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
 	    (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
 		return CSR1212_EINVAL;
@@ -1249,10 +1263,9 @@ static int csr1212_parse_bus_info_block(
 	return CSR1212_SUCCESS;
 }
 
-static inline int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
-					  csr1212_quad_t ki,
-					  u_int32_t kv_pos,
-					  struct csr1212_csr_rom_cache *cache)
+static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
+				   csr1212_quad_t ki,
+				   u_int32_t kv_pos)
 {
 	int ret = CSR1212_SUCCESS;
 	struct csr1212_keyval *k = NULL;
@@ -1291,7 +1304,7 @@ static inline int csr1212_parse_dir_entr
 			goto fail;
 		}
 
-		k = csr1212_find_keyval_offset(cache->layout_head, offset);
+		k = csr1212_find_keyval_offset(dir, offset);
 
 		if (k)
 			break;		/* Found it. */
@@ -1309,11 +1322,10 @@ static inline int csr1212_parse_dir_entr
 		k->valid = 0;	/* Contents not read yet so it's not valid. */
 		k->offset = offset;
 
-		k->prev = cache->layout_tail;
-		k->next = NULL;
-		if (cache->layout_tail)
-			cache->layout_tail->next = k;
-		cache->layout_tail = k;
+		k->prev = dir;
+		k->next = dir->next;
+		dir->next->prev = k;
+		dir->next = k;
 	}
 	ret = csr1212_attach_keyval_to_directory(dir, k);
 
@@ -1325,6 +1337,7 @@ fail:
 	return ret;
 }
 
+
 int csr1212_parse_keyval(struct csr1212_keyval *kv,
 			 struct csr1212_csr_rom_cache *cache)
 {
@@ -1338,8 +1351,8 @@ int csr1212_parse_keyval(struct csr1212_
 	kvi_len = CSR1212_BE16_TO_CPU(kvi->length);
 
 #if 0
-        /* Apparently there are too many differnt wrong implementations of the
-         * CRC algorithm that verifying them is moot. */
+	/* Apparently there are too many differnt wrong implementations of the
+	 * CRC algorithm that verifying them is moot. */
 	if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
 	    (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
 		ret = CSR1212_EINVAL;
@@ -1353,22 +1366,19 @@ int csr1212_parse_keyval(struct csr1212_
 			csr1212_quad_t ki = kvi->data[i];
 
 			/* Some devices put null entries in their unit
-			 * directories.  If we come across such and entry,
+			 * directories.  If we come across such an entry,
 			 * then skip it. */
 			if (ki == 0x0)
 				continue;
 			ret = csr1212_parse_dir_entry(kv, ki,
 						      (kv->offset +
-						       quads_to_bytes(i + 1)),
-						      cache);
+						       quads_to_bytes(i + 1)));
 		}
 		kv->value.directory.len = kvi_len;
 		break;
 
 	case CSR1212_KV_TYPE_LEAF:
-		if (kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
-			kv->value.leaf.data = cache->data;
-		} else {
+		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
 			kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
 			if (!kv->value.leaf.data)
 			{
@@ -1399,7 +1409,6 @@ int _csr1212_read_keyval(struct csr1212_
 	u_int32_t *cache_ptr;
 	u_int16_t kv_len = 0;
 
-
 	if (!csr || !kv)
 		return CSR1212_EINVAL;
 
@@ -1413,7 +1422,7 @@ int _csr1212_read_keyval(struct csr1212_
 
 	if (!cache) {
 		csr1212_quad_t q;
-		struct csr1212_csr_rom_cache *nc;
+		u_int32_t cache_size;
 
 		/* Only create a new cache for Extended ROM leaves. */
 		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
@@ -1425,12 +1434,20 @@ int _csr1212_read_keyval(struct csr1212_
 			return CSR1212_EIO;
 		}
 
-		kv->value.leaf.len = quads_to_bytes(CSR1212_BE32_TO_CPU(q)>>16);
+		kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16;
+
+		cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
+			      (csr->max_rom - 1)) & ~(csr->max_rom - 1);
 
-		nc = csr1212_rom_cache_malloc(kv->offset, kv->value.leaf.len);
-		cache->next = nc;
-		nc->prev = cache;
-		csr->cache_tail = nc;
+		cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
+		if (!cache)
+			return CSR1212_ENOMEM;
+
+		kv->value.leaf.data = &cache->data[1];
+		csr->cache_tail->next = cache;
+		cache->prev = csr->cache_tail;
+		cache->next = NULL;
+		csr->cache_tail = cache;
 		cache->filled_head =
 			CSR1212_MALLOC(sizeof(struct csr1212_cache_region));
 		if (!cache->filled_head) {
@@ -1443,6 +1460,10 @@ int _csr1212_read_keyval(struct csr1212_
 		cache->filled_head->next = NULL;
 		cache->filled_head->prev = NULL;
 		cache->data[0] = q;
+
+		/* Don't read the entire extended ROM now.  Pieces of it will
+		 * be read when entries inside it are read. */
+		return csr1212_parse_keyval(kv, cache);
 	}
 
 	cache_index = kv->offset - cache->offset;
@@ -1548,6 +1569,7 @@ int _csr1212_read_keyval(struct csr1212_
 int csr1212_parse_csr(struct csr1212_csr *csr)
 {
 	static const int mr_map[] = { 4, 64, 1024, 0 };
+	struct csr1212_dentry *dentry;
 	int ret;
 
 	if (!csr || !csr->ops->bus_read)
@@ -1570,7 +1592,21 @@ int csr1212_parse_csr(struct csr1212_csr
 		csr->bus_info_len;
 
 	csr->root_kv->valid = 0;
+	csr->root_kv->next = csr->root_kv;
+	csr->root_kv->prev = csr->root_kv;
 	csr1212_get_keyval(csr, csr->root_kv);
 
+	/* Scan through the Root directory finding all extended ROM regions
+	 * and make cache regions for them */
+	for (dentry = csr->root_kv->value.directory.dentries_head;
+	     dentry; dentry = dentry->next) {
+		if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
+			csr1212_get_keyval(csr, dentry->kv);
+
+			if (ret != CSR1212_SUCCESS)
+				return ret;
+		}
+	}
+
 	return CSR1212_SUCCESS;
 }
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -127,16 +127,12 @@ void dma_region_free(struct dma_region *
 		dma->dev = NULL;
 	}
 
-	if (dma->sglist) {
-		vfree(dma->sglist);
-		dma->sglist = NULL;
-	}
+	vfree(dma->sglist);
+	dma->sglist = NULL;
 
-	if (dma->kvirt) {
-		vfree(dma->kvirt);
-		dma->kvirt = NULL;
-		dma->n_pages = 0;
-	}
+	vfree(dma->kvirt);
+	dma->kvirt = NULL;
+	dma->n_pages = 0;
 }
 
 /* find the scatterlist index and remaining offset corresponding to a
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -1277,7 +1277,7 @@ static void do_dv1394_shutdown(struct vi
 	error-prone code in dv1394.
 */
 
-int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
+static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct video_card *video = file_to_video_card(file);
 	int retval = -EINVAL;
@@ -2343,6 +2343,8 @@ static void dv1394_remove_host (struct h
 			dv1394_un_init(video);
 	} while (video != NULL);
 
+	class_simple_device_remove(MKDEV(
+		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
 	devfs_remove("ieee1394/dv/host%d/NTSC", id);
 	devfs_remove("ieee1394/dv/host%d/PAL", id);
 	devfs_remove("ieee1394/dv/host%d", id);
@@ -2359,6 +2361,9 @@ static void dv1394_add_host (struct hpsb
 
 	ohci = (struct ti_ohci *)host->hostdata;
 
+	class_simple_device_add(hpsb_protocol_class, MKDEV(
+		IEEE1394_MAJOR,	IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), 
+		NULL, "dv1394-%d", id);
 	devfs_mk_dir("ieee1394/dv/host%d", id);
 	devfs_mk_dir("ieee1394/dv/host%d/NTSC", id);
 	devfs_mk_dir("ieee1394/dv/host%d/PAL", id);
@@ -2526,7 +2531,7 @@ static int handle_dv1394_init(struct fil
 	mm_segment_t old_fs;
 	int ret;
 
-	if (file->f_op->ioctl != dv1394_ioctl)
+	if (file->f_op->unlocked_ioctl != dv1394_ioctl)
 		return -EFAULT;
 
 	if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
@@ -2542,8 +2547,7 @@ static int handle_dv1394_init(struct fil
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	ret = dv1394_ioctl(file,
-			   DV1394_IOC_INIT, (unsigned long)&dv);
+	ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
 	set_fs(old_fs);
 
 	return ret;
@@ -2556,13 +2560,12 @@ static int handle_dv1394_get_status(stru
 	mm_segment_t old_fs;
 	int ret;
 
-	if (file->f_op->ioctl != dv1394_ioctl)
+	if (file->f_op->unlocked_ioctl != dv1394_ioctl)
 		return -EFAULT;
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	ret = dv1394_ioctl(file,
-			   DV1394_IOC_GET_STATUS, (unsigned long)&dv);
+	ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
 	set_fs(old_fs);
 
 	if (!ret) {
@@ -2590,7 +2593,6 @@ static int handle_dv1394_get_status(stru
 static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
 			       unsigned long arg)
 {
-	int err;
 	switch (cmd) {
 	case DV1394_IOC_SHUTDOWN:
 	case DV1394_IOC_SUBMIT_FRAMES:
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -89,7 +89,7 @@
 #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
 
 static char version[] __devinitdata =
-	"$Rev: 1224 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1247 $ Ben Collins <bcollins@debian.org>";
 
 struct fragment_info {
 	struct list_head list;
@@ -165,8 +165,7 @@ MODULE_LICENSE("GPL");
 /* The max_partial_datagrams parameter is the maximum number of fragmented
  * datagrams per node that eth1394 will keep in memory.  Providing an upper
  * bound allows us to limit the amount of memory that partial datagrams
- * consume in the event that some partial datagrams are never completed.  This
- * should probably change to a sysctl item or the like if possible.
+ * consume in the event that some partial datagrams are never completed.
  */
 static int max_partial_datagrams = 25;
 module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);
@@ -186,7 +185,7 @@ static void ether1394_header_cache_updat
 					  unsigned char * haddr);
 static int ether1394_mac_addr(struct net_device *dev, void *p);
 
-static inline void purge_partial_datagram(struct list_head *old);
+static void purge_partial_datagram(struct list_head *old);
 static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
@@ -289,7 +288,7 @@ static int ether1394_change_mtu(struct n
 	return 0;
 }
 
-static inline void purge_partial_datagram(struct list_head *old)
+static void purge_partial_datagram(struct list_head *old)
 {
 	struct partial_datagram *pd = list_entry(old, struct partial_datagram, list);
 	struct list_head *lh, *n;
@@ -449,7 +448,7 @@ static int eth1394_update(struct unit_di
 		if (!node_info) {
 			kfree(node);
 			return -ENOMEM;
-                }
+		}
 
 		spin_lock_init(&node_info->pdg.lock);
 		INIT_LIST_HEAD(&node_info->pdg.list);
@@ -626,7 +625,7 @@ static void ether1394_add_host (struct h
 		goto out;
 	}
 
-	ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n",
+	ETH1394_PRINT (KERN_INFO, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n",
 		       host->id);
 
 	hi->host = host;
@@ -1187,7 +1186,7 @@ static int ether1394_data_handler(struct
 		lh = find_partial_datagram(pdgl, dgl);
 
 		if (lh == NULL) {
-			if (pdg->sz == max_partial_datagrams) {
+			while (pdg->sz >= max_partial_datagrams) {
 				/* remove the oldest */
 				purge_partial_datagram(pdgl->prev);
 				pdg->sz--;
@@ -1583,7 +1582,7 @@ static inline void ether1394_dg_complete
 	struct sk_buff *skb = ptask->skb;
 	struct net_device *dev = skb->dev;
 	struct eth1394_priv *priv = netdev_priv(dev);
-        unsigned long flags;
+	unsigned long flags;
 
 	/* Statistics */
 	spin_lock_irqsave(&priv->lock, flags);
@@ -1771,7 +1770,7 @@ fail:
 static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	strcpy (info->driver, driver_name);
-	strcpy (info->version, "$Rev: 1224 $");
+	strcpy (info->version, "$Rev: 1247 $");
 	/* FIXME XXX provide sane businfo */
 	strcpy (info->bus_info, "ieee1394");
 }
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -173,18 +173,6 @@ void hpsb_set_hostinfo_key(struct hpsb_h
 }
 
 
-unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
-	struct hl_host_info *hi;
-
-	hi = hl_get_hostinfo(hl, host);
-	if (hi)
-		return hi->key;
-
-	return 0;
-}
-
-
 void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
 {
 	struct hl_host_info *hi;
@@ -206,26 +194,6 @@ void *hpsb_get_hostinfo_bykey(struct hps
 }
 
 
-struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key)
-{
-	struct hl_host_info *hi;
-	struct hpsb_host *host = NULL;
-
-	if (!hl)
-		return NULL;
-
-	read_lock(&hl->host_info_lock);
-	list_for_each_entry(hi, &hl->host_info_list, list) {
-		if (hi->key == key) {
-			host = hi->host;
-			break;
-		}
-	}
-	read_unlock(&hl->host_info_lock);
-
-	return host;
-}
-
 static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
 {
 	struct hpsb_highlevel *hl = __data;
@@ -416,7 +384,7 @@ int hpsb_register_addrspace(struct hpsb_
         }
 
         as = (struct hpsb_address_serve *)
-                kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
+                kmalloc(sizeof(struct hpsb_address_serve), GFP_ATOMIC);
         if (as == NULL) {
                 return 0;
         }
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -77,6 +77,30 @@ extern const char *hpsb_speedto_str[];
 #define SELFID_PORT_NONE         0x0
 
 
+/* 1394a PHY bitmasks */
+#define PHY_00_PHYSICAL_ID       0xFC
+#define PHY_00_R                 0x02 /* Root */
+#define PHY_00_PS                0x01 /* Power Status*/
+#define PHY_01_RHB               0x80 /* Root Hold-Off */
+#define PHY_01_IBR               0x80 /* Initiate Bus Reset */
+#define PHY_01_GAP_COUNT         0x3F
+#define PHY_02_EXTENDED          0xE0 /* 0x7 for 1394a-compliant PHY */
+#define PHY_02_TOTAL_PORTS       0x1F
+#define PHY_03_MAX_SPEED         0xE0
+#define PHY_03_DELAY             0x0F
+#define PHY_04_LCTRL             0x80 /* Link Active Report Control */
+#define PHY_04_CONTENDER         0x40
+#define PHY_04_JITTER            0x38
+#define PHY_04_PWR_CLASS         0x07 /* Power Class */
+#define PHY_05_WATCHDOG          0x80
+#define PHY_05_ISBR              0x40 /* Initiate Short Bus Reset */
+#define PHY_05_LOOP              0x20 /* Loop Detect */
+#define PHY_05_PWR_FAIL          0x10 /* Cable Power Failure Detect */
+#define PHY_05_TIMEOUT           0x08 /* Arbitration State Machine Timeout */
+#define PHY_05_PORT_EVENT        0x04 /* Port Event Detect */
+#define PHY_05_ENAB_ACCEL        0x02 /* Enable Arbitration Acceleration */
+#define PHY_05_ENAB_MULTI        0x01 /* Ena. Multispeed Packet Concatenation */
+
 #include <asm/byteorder.h>
 
 #ifdef __BIG_ENDIAN_BITFIELD
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -56,11 +56,18 @@ static int disable_nodemgr = 0;
 module_param(disable_nodemgr, int, 0444);
 MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 
+/* Disable Isochronous Resource Manager functionality */
+int hpsb_disable_irm = 0;
+module_param_named(disable_irm, hpsb_disable_irm, bool, 0);
+MODULE_PARM_DESC(disable_irm,
+		 "Disable Isochronous Resource Manager functionality.");
+
 /* We are GPL, so treat us special */
 MODULE_LICENSE("GPL");
 
 /* Some globals used */
 const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
+struct class_simple *hpsb_protocol_class;
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 static void dump_packet(const char *text, quadlet_t *data, int size)
@@ -79,6 +86,7 @@ static void dump_packet(const char *text
 #define dump_packet(x,y,z)
 #endif
 
+static void abort_requests(struct hpsb_host *host);
 static void queue_packet_complete(struct hpsb_packet *packet);
 
 
@@ -512,6 +520,7 @@ int hpsb_send_packet(struct hpsb_packet 
 
 	if (!packet->no_waiter || packet->expect_response) {
 		atomic_inc(&packet->refcnt);
+		packet->sendtime = jiffies + 10 * HZ;
 		skb_queue_tail(&host->pending_packet_queue, packet->skb);
 	}
 
@@ -939,7 +948,7 @@ void hpsb_packet_received(struct hpsb_ho
 }
 
 
-void abort_requests(struct hpsb_host *host)
+static void abort_requests(struct hpsb_host *host)
 {
 	struct hpsb_packet *packet;
 	struct sk_buff *skb;
@@ -1002,7 +1011,7 @@ void abort_timedouts(unsigned long __opa
  * the stack. */
 static int khpsbpkt_pid = -1, khpsbpkt_kill;
 static DECLARE_COMPLETION(khpsbpkt_complete);
-struct sk_buff_head hpsbpkt_queue;
+static struct sk_buff_head hpsbpkt_queue;
 static DECLARE_MUTEX_LOCKED(khpsbpkt_sig);
 
 
@@ -1030,15 +1039,19 @@ static int hpsbpkt_thread(void *__hi)
 
 	daemonize("khpsbpkt");
 
-	while (!down_interruptible(&khpsbpkt_sig)) {
-		if (khpsbpkt_kill)
+	while (1) {
+		if (down_interruptible(&khpsbpkt_sig)) {
+			if (current->flags & PF_FREEZE) {
+				refrigerator(0);
+				continue;
+			}
+			printk("khpsbpkt: received unexpected signal?!\n" );
 			break;
-
-		if (current->flags & PF_FREEZE) {
-			refrigerator(0);
-			continue;
 		}
 
+		if (khpsbpkt_kill)
+			break;
+
 		while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
 			packet = (struct hpsb_packet *)skb->data;
 
@@ -1054,7 +1067,6 @@ static int hpsbpkt_thread(void *__hi)
 	complete_and_exit(&khpsbpkt_complete, 0);
 }
 
-
 static int __init ieee1394_init(void)
 {
 	int i, ret;
@@ -1109,18 +1121,33 @@ static int __init ieee1394_init(void)
 	if (ret < 0)
 		goto release_all_bus;
 
+	hpsb_protocol_class = class_simple_create(THIS_MODULE, "ieee1394_protocol");
+	if (IS_ERR(hpsb_protocol_class)) {
+		ret = PTR_ERR(hpsb_protocol_class);
+		goto release_class_host;
+	}
+
 	ret = init_csr();
 	if (ret) {
 		HPSB_INFO("init csr failed");
 		ret = -ENOMEM;
-		goto release_class;
+		goto release_class_protocol;
 	}
 
 	if (disable_nodemgr) {
-		HPSB_INFO("nodemgr functionality disabled");
+		HPSB_INFO("nodemgr and IRM functionality disabled");
+		/* We shouldn't contend for IRM with nodemgr disabled, since
+		   nodemgr implements functionality required of ieee1394a-2000
+		   IRMs */
+		hpsb_disable_irm = 1;
+                      
 		return 0;
 	}
 
+	if (hpsb_disable_irm) {
+		HPSB_INFO("IRM functionality disabled");
+	}
+
 	ret = init_ieee1394_nodemgr();
 	if (ret < 0) {
 		HPSB_INFO("init nodemgr failed");
@@ -1131,7 +1158,9 @@ static int __init ieee1394_init(void)
 
 cleanup_csr:
 	cleanup_csr();
-release_class:
+release_class_protocol:
+	class_simple_destroy(hpsb_protocol_class);
+release_class_host:
 	class_unregister(&hpsb_host_class);
 release_all_bus:
 	for (i = 0; fw_bus_attrs[i]; i++)
@@ -1160,6 +1189,7 @@ static void __exit ieee1394_cleanup(void
 
 	cleanup_csr();
 
+	class_simple_destroy(hpsb_protocol_class);
 	class_unregister(&hpsb_host_class);
 	for (i = 0; fw_bus_attrs[i]; i++)
 		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
@@ -1191,6 +1221,7 @@ EXPORT_SYMBOL(hpsb_update_config_rom_ima
 
 /** ieee1394_core.c **/
 EXPORT_SYMBOL(hpsb_speedto_str);
+EXPORT_SYMBOL(hpsb_protocol_class);
 EXPORT_SYMBOL(hpsb_set_packet_complete_task);
 EXPORT_SYMBOL(hpsb_alloc_packet);
 EXPORT_SYMBOL(hpsb_free_packet);
@@ -1203,6 +1234,7 @@ EXPORT_SYMBOL(hpsb_selfid_received);
 EXPORT_SYMBOL(hpsb_selfid_complete);
 EXPORT_SYMBOL(hpsb_packet_sent);
 EXPORT_SYMBOL(hpsb_packet_received);
+EXPORT_SYMBOL_GPL(hpsb_disable_irm);
 
 /** ieee1394_transactions.c **/
 EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1216,9 +1248,6 @@ EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_make_isopacket);
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-EXPORT_SYMBOL(hpsb_lock64);
-EXPORT_SYMBOL(hpsb_send_gasp);
 EXPORT_SYMBOL(hpsb_packet_success);
 
 /** highlevel.c **/
@@ -1230,28 +1259,18 @@ EXPORT_SYMBOL(hpsb_allocate_and_register
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(hpsb_get_hostinfo);
-EXPORT_SYMBOL(hpsb_get_host_bykey);
 EXPORT_SYMBOL(hpsb_create_hostinfo);
 EXPORT_SYMBOL(hpsb_destroy_hostinfo);
 EXPORT_SYMBOL(hpsb_set_hostinfo_key);
-EXPORT_SYMBOL(hpsb_get_hostinfo_key);
 EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
 EXPORT_SYMBOL(hpsb_set_hostinfo);
-EXPORT_SYMBOL(highlevel_read);
-EXPORT_SYMBOL(highlevel_write);
-EXPORT_SYMBOL(highlevel_lock);
-EXPORT_SYMBOL(highlevel_lock64);
 EXPORT_SYMBOL(highlevel_add_host);
 EXPORT_SYMBOL(highlevel_remove_host);
 EXPORT_SYMBOL(highlevel_host_reset);
 
 /** nodemgr.c **/
-EXPORT_SYMBOL(hpsb_guid_get_entry);
-EXPORT_SYMBOL(hpsb_nodeid_get_entry);
 EXPORT_SYMBOL(hpsb_node_fill_packet);
-EXPORT_SYMBOL(hpsb_node_read);
 EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(hpsb_node_lock);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(ieee1394_bus_type);
@@ -1295,27 +1314,14 @@ EXPORT_SYMBOL(hpsb_iso_recv_flush);
 EXPORT_SYMBOL(csr1212_create_csr);
 EXPORT_SYMBOL(csr1212_init_local_csr);
 EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_new_leaf);
-EXPORT_SYMBOL(csr1212_new_csr_offset);
 EXPORT_SYMBOL(csr1212_new_directory);
 EXPORT_SYMBOL(csr1212_associate_keyval);
 EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_new_extended_immediate);
-EXPORT_SYMBOL(csr1212_new_extended_leaf);
-EXPORT_SYMBOL(csr1212_new_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_new_textual_descriptor_leaf);
 EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_new_icon_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_new_modifiable_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_new_keyword_leaf);
 EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_disassociate_keyval);
 EXPORT_SYMBOL(csr1212_release_keyval);
 EXPORT_SYMBOL(csr1212_destroy_csr);
 EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_generate_positions);
-EXPORT_SYMBOL(csr1212_generate_layout_order);
-EXPORT_SYMBOL(csr1212_fill_cache);
 EXPORT_SYMBOL(csr1212_generate_csr_image);
 EXPORT_SYMBOL(csr1212_parse_keyval);
 EXPORT_SYMBOL(csr1212_parse_csr);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -89,7 +89,6 @@ static inline struct hpsb_packet *driver
 }
 
 void abort_timedouts(unsigned long __opaque);
-void abort_requests(struct hpsb_host *host);
 
 struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
 void hpsb_free_packet(struct hpsb_packet *packet);
@@ -219,9 +218,11 @@ static inline unsigned char ieee1394_fil
 	return file->f_dentry->d_inode->i_cindex;
 }
 
+extern int hpsb_disable_irm;
 
 /* Our sysfs bus entry */
 extern struct bus_type ieee1394_bus_type;
 extern struct class hpsb_host_class;
+extern struct class_simple *hpsb_protocol_class;
 
 #endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -535,6 +535,7 @@ hpsb_write_fail:
         return retval;
 }
 
+#if 0
 
 int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
@@ -566,34 +567,6 @@ hpsb_lock_fail:
         return retval;
 }
 
-int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-		u64 addr, int extcode, octlet_t *data, octlet_t arg)
-{
-	struct hpsb_packet *packet;
-	int retval = 0;
-
-	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
-
-	packet = hpsb_make_lock64packet(host, node, addr, extcode, data, arg);
-	if (!packet)
-		return -ENOMEM;
-
-	packet->generation = generation;
-	retval = hpsb_send_packet_and_wait(packet);
-	if (retval < 0)
-		goto hpsb_lock64_fail;
-
-	retval = hpsb_packet_success(packet);
-
-	if (retval == 0)
-		*data = (u64)packet->data[1] << 32 | packet->data[0];
-
-hpsb_lock64_fail:
-	hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-
-        return retval;
-}
 
 int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
 		   quadlet_t *buffer, size_t length, u32 specifier_id,
@@ -627,3 +600,5 @@ int hpsb_send_gasp(struct hpsb_host *hos
 
 	return retval;
 }
+
+#endif  /*  0  */
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -53,12 +53,5 @@ int hpsb_read(struct hpsb_host *host, no
 	      u64 addr, quadlet_t *buffer, size_t length);
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	       u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-		u64 addr, int extcode, octlet_t *data, octlet_t arg);
-int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
-                   quadlet_t *buffer, size_t length, u32 specifier_id,
-                   unsigned int version);
 
 #endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -23,6 +23,7 @@
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
+#include "ieee1394_core.h"
 #include "hosts.h"
 #include "ieee1394_transactions.h"
 #include "highlevel.h"
@@ -146,7 +147,7 @@ static void ne_cls_release(struct class_
 	put_device(&container_of((class_dev), struct node_entry, class_dev)->device);
 }
 
-struct class nodemgr_ne_class = {
+static struct class nodemgr_ne_class = {
 	.name		= "ieee1394_node",
 	.release	= ne_cls_release,
 };
@@ -158,7 +159,7 @@ static void ud_cls_release(struct class_
 
 /* The name here is only so that unit directory hotplug works with old
  * style hotplug, which only ever did unit directories anyway. */
-struct class nodemgr_ud_class = {
+static struct class nodemgr_ud_class = {
 	.name		= "ieee1394",
 	.release	= ud_cls_release,
 	.hotplug	= nodemgr_hotplug,
@@ -831,6 +832,31 @@ static struct node_entry *find_entry_by_
 }
 
 
+static void nodemgr_register_device(struct node_entry *ne, 
+	struct unit_directory *ud, struct device *parent)
+{
+	memcpy(&ud->device, &nodemgr_dev_template_ud,
+	       sizeof(ud->device));
+
+	ud->device.parent = parent;
+
+	snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
+		 ne->device.bus_id, ud->id);
+
+	ud->class_dev.dev = &ud->device;
+	ud->class_dev.class = &nodemgr_ud_class;
+	snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
+		 ne->device.bus_id, ud->id);
+
+	device_register(&ud->device);
+	class_device_register(&ud->class_dev);
+	get_device(&ud->device);
+
+	if (ud->vendor_oui)
+		device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
+	nodemgr_create_ud_dev_files(ud);
+}	
+
 
 /* This implementation currently only scans the config rom and its
  * immediate unit directories looking for software_id and
@@ -840,7 +866,7 @@ static struct unit_directory *nodemgr_pr
 	 unsigned int *id, struct unit_directory *parent)
 {
 	struct unit_directory *ud;
-	struct unit_directory *ud_temp = NULL;
+	struct unit_directory *ud_child = NULL;
 	struct csr1212_dentry *dentry;
 	struct csr1212_keyval *kv;
 	u8 last_key_id = 0;
@@ -907,42 +933,61 @@ static struct unit_directory *nodemgr_pr
 			break;
 
 		case CSR1212_KV_ID_DEPENDENT_INFO:
-			if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
+			/* Logical Unit Number */
+			if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
+				if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
+					ud_child = kmalloc(sizeof(struct unit_directory), GFP_KERNEL);
+					if (!ud_child)
+						goto unit_directory_error;
+					memcpy(ud_child, ud, sizeof(struct unit_directory));
+					nodemgr_register_device(ne, ud_child, &ne->device);
+					ud_child = NULL;
+					
+					ud->id = (*id)++;
+				}
+				ud->lun = kv->value.immediate;
+				ud->flags |= UNIT_DIRECTORY_HAS_LUN;
+
+			/* Logical Unit Directory */
+			} else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
 				/* This should really be done in SBP2 as this is
-				 * doing SBP2 specific parsing. */
+				 * doing SBP2 specific parsing.
+				 */
+				
+				/* first register the parent unit */
 				ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
-				ud_temp = nodemgr_process_unit_directory(hi, ne, kv, id,
-									 parent);
+				if (ud->device.bus != &ieee1394_bus_type)
+					nodemgr_register_device(ne, ud, &ne->device);
+				
+				/* process the child unit */
+				ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud);
 
-				if (ud_temp == NULL)
+				if (ud_child == NULL)
 					break;
-
-				/* inherit unspecified values */
-				if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) &&
-				    !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))
-				{
-					ud_temp->flags |=  UNIT_DIRECTORY_VENDOR_ID;
-					ud_temp->vendor_id = ud->vendor_id;
-					ud_temp->vendor_oui = ud->vendor_oui;
-				}
+				
+				/* inherit unspecified values so hotplug picks it up */
 				if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
-				    !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))
+				    !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
 				{
-					ud_temp->flags |=  UNIT_DIRECTORY_MODEL_ID;
-					ud_temp->model_id = ud->model_id;
+					ud_child->flags |=  UNIT_DIRECTORY_MODEL_ID;
+					ud_child->model_id = ud->model_id;
 				}
 				if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
-				    !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))
+				    !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
 				{
-					ud_temp->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
-					ud_temp->specifier_id = ud->specifier_id;
+					ud_child->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
+					ud_child->specifier_id = ud->specifier_id;
 				}
 				if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
-				    !(ud_temp->flags & UNIT_DIRECTORY_VERSION))
+				    !(ud_child->flags & UNIT_DIRECTORY_VERSION))
 				{
-					ud_temp->flags |=  UNIT_DIRECTORY_VERSION;
-					ud_temp->version = ud->version;
+					ud_child->flags |=  UNIT_DIRECTORY_VERSION;
+					ud_child->version = ud->version;
 				}
+				
+				/* register the child unit */
+				ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
+				nodemgr_register_device(ne, ud_child, &ud->device);
 			}
 
 			break;
@@ -952,37 +997,15 @@ static struct unit_directory *nodemgr_pr
 		}
 		last_key_id = kv->key.id;
 	}
-
-	memcpy(&ud->device, &nodemgr_dev_template_ud,
-	       sizeof(ud->device));
-
-	if (parent) {
-		ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
-		ud->device.parent = &parent->device;
-	} else
-		ud->device.parent = &ne->device;
-
-	snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
-		 ne->device.bus_id, ud->id);
-
-	ud->class_dev.dev = &ud->device;
-	ud->class_dev.class = &nodemgr_ud_class;
-	snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
-		 ne->device.bus_id, ud->id);
-
-	device_register(&ud->device);
-	class_device_register(&ud->class_dev);
-	get_device(&ud->device);
-
-	if (ud->vendor_oui)
-		device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
-	nodemgr_create_ud_dev_files(ud);
+	
+	/* do not process child units here and only if not already registered */
+	if (!parent && ud->device.bus != &ieee1394_bus_type)
+		nodemgr_register_device(ne, ud, &ne->device);
 
 	return ud;
 
 unit_directory_error:
-	if (ud != NULL)
-		kfree(ud);
+	kfree(ud);
 	return NULL;
 }
 
@@ -1141,6 +1164,13 @@ static void nodemgr_update_node(struct n
 
 		/* Mark the node as new, so it gets re-probed */
 		ne->needs_probe = 1;
+	} else {
+		/* old cache is valid, so update its generation */
+		struct nodemgr_csr_info *ci = ne->csr->private;
+		ci->generation = generation;
+		/* free the partially filled now unneeded new cache */
+		kfree(csr->private);
+		csr1212_destroy_csr(csr);
 	}
 
 	if (ne->in_limbo)
@@ -1253,7 +1283,7 @@ static void nodemgr_suspend_ne(struct no
 
 		if (ud->device.driver &&
 		    (!ud->device.driver->suspend ||
-		      ud->device.driver->suspend(&ud->device, 0, 0)))
+		      ud->device.driver->suspend(&ud->device, PMSG_SUSPEND, 0)))
 			device_release_driver(&ud->device);
 	}
 	up_write(&ne->device.bus->subsys.rwsem);
@@ -1431,7 +1461,7 @@ static int nodemgr_check_irm_capability(
 	quadlet_t bc;
 	int status;
 
-	if (host->is_irm)
+	if (hpsb_disable_irm || host->is_irm)
 		return 1;
 
 	status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
@@ -1553,29 +1583,6 @@ caught_signal:
 	complete_and_exit(&hi->exited, 0);
 }
 
-struct node_entry *hpsb_guid_get_entry(u64 guid)
-{
-        struct node_entry *ne;
-
-	down(&nodemgr_serialize);
-        ne = find_entry_by_guid(guid);
-	up(&nodemgr_serialize);
-
-        return ne;
-}
-
-struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid)
-{
-	struct node_entry *ne;
-
-	down(&nodemgr_serialize);
-	ne = find_entry_by_nodeid(host, nodeid);
-	up(&nodemgr_serialize);
-
-	return ne;
-}
-
-
 int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
 {
 	struct class *class = &hpsb_host_class;
@@ -1618,16 +1625,6 @@ void hpsb_node_fill_packet(struct node_e
         pkt->node_id = ne->nodeid;
 }
 
-int hpsb_node_read(struct node_entry *ne, u64 addr,
-		   quadlet_t *buffer, size_t length)
-{
-	unsigned int generation = ne->generation;
-
-	barrier();
-	return hpsb_read(ne->host, ne->nodeid, generation,
-			 addr, buffer, length);
-}
-
 int hpsb_node_write(struct node_entry *ne, u64 addr,
 		    quadlet_t *buffer, size_t length)
 {
@@ -1638,16 +1635,6 @@ int hpsb_node_write(struct node_entry *n
 			  addr, buffer, length);
 }
 
-int hpsb_node_lock(struct node_entry *ne, u64 addr,
-		   int extcode, quadlet_t *data, quadlet_t arg)
-{
-	unsigned int generation = ne->generation;
-
-	barrier();
-	return hpsb_lock(ne->host, ne->nodeid, generation,
-			 addr, extcode, data, arg);
-}
-
 static void nodemgr_add_host(struct hpsb_host *host)
 {
 	struct host_info *hi;
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -51,6 +51,7 @@ struct bus_options {
 #define UNIT_DIRECTORY_VERSION			0x08
 #define UNIT_DIRECTORY_HAS_LUN_DIRECTORY	0x10
 #define UNIT_DIRECTORY_LUN_DIRECTORY		0x20
+#define UNIT_DIRECTORY_HAS_LUN			0x40
 
 /*
  * A unit directory corresponds to a protocol supported by the
@@ -82,6 +83,7 @@ struct unit_directory {
 	struct class_device class_dev;
 
 	struct csr1212_keyval *ud_kv;
+	u32 lun;                /* logical unit number immediate value */
 };
 
 struct node_entry {
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_
 printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 1223 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1250 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 static int phys_dma = 1;
@@ -482,7 +482,9 @@ static void ohci_initialize(struct ti_oh
 
 	/* Put some defaults to these undefined bus options */
 	buf = reg_read(ohci, OHCI1394_BusOptions);
-	buf |=  0xE0000000; /* Enable IRMC, CMC and ISC */
+	buf |=  0x60000000; /* Enable CMC and ISC */
+	if (!hpsb_disable_irm)
+		buf |=  0x80000000; /* Enable IRMC */
 	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
 	buf &= ~0x18000000; /* Disable PMC and BMC */
 	reg_write(ohci, OHCI1394_BusOptions, buf);
@@ -497,10 +499,12 @@ static void ohci_initialize(struct ti_oh
 	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
 
 	/* Enable cycle timer and cycle master and set the IRM
-	 * contender bit in our self ID packets. */
-	reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_CycleTimerEnable |
+	 * contender bit in our self ID packets if appropriate. */
+	reg_write(ohci, OHCI1394_LinkControlSet,
+		  OHCI1394_LinkControl_CycleTimerEnable |
 		  OHCI1394_LinkControl_CycleMaster);
-	set_phy_reg_mask(ohci, 4, 0xc0);
+	set_phy_reg_mask(ohci, 4, PHY_04_LCTRL |
+			 (hpsb_disable_irm ? 0 : PHY_04_CONTENDER));
 
 	/* Set up self-id dma buffer */
 	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
@@ -515,12 +519,6 @@ static void ohci_initialize(struct ti_oh
 	/* Now get our max packet size */
 	ohci->max_packet_size =
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-
-	if (ohci->max_packet_size < 512) {
-		HPSB_ERR("warning: Invalid max packet size of %d, setting to 512",
-			     ohci->max_packet_size);
-		ohci->max_packet_size = 512;
-	}
 		
 	/* Don't accept phy packets into AR request context */
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -540,6 +538,9 @@ static void ohci_initialize(struct ti_oh
 	/* Initialize AT dma */
 	initialize_dma_trm_ctx(&ohci->at_req_context);
 	initialize_dma_trm_ctx(&ohci->at_resp_context);
+	
+	/* Initialize IR Legacy DMA channel mask */
+	ohci->ir_legacy_channels = 0;
 
 	/*
 	 * Accept AT requests from all nodes. This probably
@@ -1029,6 +1030,8 @@ static int ohci_devctl(struct hpsb_host 
 	case ISO_LISTEN_CHANNEL:
         {
 		u64 mask;
+		struct dma_rcv_ctx *d = &ohci->ir_legacy_context;
+		int ir_legacy_active;
 
 		if (arg<0 || arg>63) {
 			PRINT(KERN_ERR,
@@ -1037,22 +1040,6 @@ static int ohci_devctl(struct hpsb_host 
 			return -EFAULT;
 		}
 
-		/* activate the legacy IR context */
-		if (ohci->ir_legacy_context.ohci == NULL) {
-			if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
-					      DMA_CTX_ISO, 0, IR_NUM_DESC,
-					      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-					      OHCI1394_IsoRcvContextBase) < 0) {
-				PRINT(KERN_ERR, "%s: failed to allocate an IR context",
-				      __FUNCTION__);
-				return -ENOMEM;
-			}
-			ohci->ir_legacy_channels = 0;
-			initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
-
-			DBGMSG("ISO receive legacy context activated");
-		}
-
 		mask = (u64)0x1<<arg;
 
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
@@ -1065,9 +1052,37 @@ static int ohci_devctl(struct hpsb_host 
 			return -EFAULT;
 		}
 
+		ir_legacy_active = ohci->ir_legacy_channels;
+
 		ohci->ISO_channel_usage |= mask;
 		ohci->ir_legacy_channels |= mask;
 
+                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
+
+		if (!ir_legacy_active) {
+			if (ohci1394_register_iso_tasklet(ohci,
+					  &ohci->ir_legacy_tasklet) < 0) {
+				PRINT(KERN_ERR, "No IR DMA context available");
+				return -EBUSY;
+			}
+
+			/* the IR context can be assigned to any DMA context
+			 * by ohci1394_register_iso_tasklet */
+			d->ctx = ohci->ir_legacy_tasklet.context;
+			d->ctrlSet = OHCI1394_IsoRcvContextControlSet +
+				32*d->ctx;
+			d->ctrlClear = OHCI1394_IsoRcvContextControlClear +
+				32*d->ctx;
+			d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx;
+			d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx;
+
+			initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
+
+			PRINT(KERN_ERR, "IR legacy activated");
+		}
+
+                spin_lock_irqsave(&ohci->IR_channel_lock, flags);
+
 		if (arg>31)
 			reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet,
 				  1<<(arg-32));
@@ -1117,9 +1132,9 @@ static int ohci_devctl(struct hpsb_host 
 
 		if (ohci->ir_legacy_channels == 0) {
 			stop_dma_rcv_ctx(&ohci->ir_legacy_context);
-			free_dma_rcv_ctx(&ohci->ir_legacy_context);
-			DBGMSG("ISO receive legacy context deactivated");
+			DBGMSG("ISO legacy receive context stopped");
 		}
+
                 break;
         }
 	default:
@@ -1289,8 +1304,10 @@ static int ohci_iso_recv_init(struct hps
 				                       OHCI_ISO_RECEIVE,
 				  ohci_iso_recv_task, (unsigned long) iso);
 
-	if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0)
+	if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
+		ret = -EBUSY;
 		goto err;
+	}
 
 	recv->task_active = 1;
 
@@ -1915,8 +1932,10 @@ static int ohci_iso_xmit_init(struct hps
 	ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
 				  ohci_iso_xmit_task, (unsigned long) iso);
 
-	if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0)
+	if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
+		ret = -EBUSY;
 		goto err;
+	}
 
 	xmit->task_active = 1;
 
@@ -2545,6 +2564,10 @@ static void insert_dma_buffer(struct dma
 	idx = (idx + d->num_desc - 1 ) % d->num_desc;
 	d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
 
+	/* To avoid a race, ensure 1394 interface hardware sees the inserted
+	 * context program descriptors before it sees the wakeup bit set. */
+	wmb();
+	
 	/* wake up the dma context if necessary */
 	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
 		PRINT(KERN_INFO,
@@ -2706,7 +2729,7 @@ static void dma_rcv_tasklet (unsigned lo
 				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
 				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
 				tcode, length, d->ctx,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f);
+				(cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f);
 
 			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
 				== 0x11) ? 1 : 0;
@@ -2769,7 +2792,7 @@ static void dma_trm_tasklet (unsigned lo
 				       d->ctx);
 			else
 				DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-				       "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d",
+				       "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
 				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
 				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
 				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
@@ -2778,7 +2801,7 @@ static void dma_trm_tasklet (unsigned lo
 				       d->ctx);
 		else
 			DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-			       "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d",
+			       "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
                                         >>16)&0x3f,
                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
@@ -2908,7 +2931,7 @@ static void free_dma_rcv_ctx(struct dma_
 		kfree(d->prg_cpu);
 		kfree(d->prg_bus);
 	}
-	if (d->spb) kfree(d->spb);
+	kfree(d->spb);
 
 	/* Mark this context as freed. */
 	d->ohci = NULL;
@@ -2919,7 +2942,9 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, 
 		  enum context_type type, int ctx, int num_desc,
 		  int buf_size, int split_buf_size, int context_base)
 {
-	int i;
+	int i, len;
+	static int num_allocs;
+	static char pool_name[20];
 
 	d->ohci = ohci;
 	d->type = type;
@@ -2963,9 +2988,19 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, 
 		free_dma_rcv_ctx(d);
 		return -ENOMEM;
 	}
-
-	d->prg_pool = pci_pool_create("ohci1394 rcv prg", ohci->dev,
+	
+	len = sprintf(pool_name, "ohci1394_rcv_prg");
+	sprintf(pool_name+len, "%d", num_allocs);
+	d->prg_pool = pci_pool_create(pool_name, ohci->dev,
 				sizeof(struct dma_cmd), 4, 0);
+	if(d->prg_pool == NULL)
+	{
+		PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
+		free_dma_rcv_ctx(d);
+		return -ENOMEM;
+	}
+	num_allocs++;
+
 	OHCI_DMA_ALLOC("dma_rcv prg pool");
 
 	for (i=0; i<d->num_desc; i++) {
@@ -3002,20 +3037,6 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, 
 		ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet,
 					  OHCI_ISO_MULTICHANNEL_RECEIVE,
 					  dma_rcv_tasklet, (unsigned long) d);
-		if (ohci1394_register_iso_tasklet(ohci,
-						  &ohci->ir_legacy_tasklet) < 0) {
-			PRINT(KERN_ERR, "No IR DMA context available");
-			free_dma_rcv_ctx(d);
-			return -EBUSY;
-		}
-
-		/* the IR context can be assigned to any DMA context
-		 * by ohci1394_register_iso_tasklet */
-		d->ctx = ohci->ir_legacy_tasklet.context;
-		d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx;
-		d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx;
-		d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx;
-		d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx;
 	} else {
 		d->ctrlSet = context_base + OHCI1394_ContextControlSet;
 		d->ctrlClear = context_base + OHCI1394_ContextControlClear;
@@ -3058,7 +3079,9 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, 
 		  enum context_type type, int ctx, int num_desc,
 		  int context_base)
 {
-	int i;
+	int i, len;
+	static char pool_name[20];
+	static int num_allocs=0;
 
 	d->ohci = ohci;
 	d->type = type;
@@ -3080,8 +3103,17 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, 
 	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));
 
-	d->prg_pool = pci_pool_create("ohci1394 trm prg", ohci->dev,
+	len = sprintf(pool_name, "ohci1394_trm_prg");
+	sprintf(pool_name+len, "%d", num_allocs);
+	d->prg_pool = pci_pool_create(pool_name, ohci->dev,
 				sizeof(struct at_dma_prg), 4, 0);
+	if (d->prg_pool == NULL) {
+		PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
+		free_dma_trm_ctx(d);
+		return -ENOMEM;
+	}
+	num_allocs++;
+
 	OHCI_DMA_ALLOC("dma_rcv prg pool");
 
 	for (i = 0; i < d->num_desc; i++) {
@@ -3353,10 +3385,19 @@ static int __devinit ohci1394_pci_probe(
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
-	/* the IR DMA context is allocated on-demand; mark it inactive */
-	ohci->ir_legacy_context.ohci = NULL;
+	/* Allocate the IR DMA context right here so we don't have
+	 * to do it in interrupt path - note that this doesn't
+	 * waste much memory and avoids the jugglery required to
+	 * allocate it in IRQ path. */
+	if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
+			      DMA_CTX_ISO, 0, IR_NUM_DESC,
+			      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+			      OHCI1394_IsoRcvContextBase) < 0) {
+		FAIL(-ENOMEM, "Cannot allocate IR Legacy DMA context");
+	}
 
-	/* same for the IT DMA context */
+	/* We hopefully don't have to pre-allocate IT DMA like we did
+	 * for IR DMA above. Allocate it on-demand and mark inactive. */
 	ohci->it_legacy_context.ohci = NULL;
 
 	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
@@ -3445,6 +3486,10 @@ static void ohci1394_pci_remove(struct p
 		/* Free IT dma */
 		free_dma_trm_ctx(&ohci->it_legacy_context);
 
+		/* Free IR legacy dma */
+		free_dma_rcv_ctx(&ohci->ir_legacy_context);
+
+
 	case OHCI_INIT_HAVE_SELFID_BUFFER:
 		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
 				    ohci->selfid_buf_cpu,
@@ -3510,7 +3555,7 @@ static int ohci1394_pci_resume (struct p
 }
 
 
-static int ohci1394_pci_suspend (struct pci_dev *pdev, u32 state)
+static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 #ifdef CONFIG_PMAC_PBOOK
 	{
@@ -3676,7 +3721,7 @@ static void __exit ohci1394_cleanup (voi
 
 static int __init ohci1394_init(void)
 {
-	return pci_module_init(&ohci1394_pci_driver);
+	return pci_register_driver(&ohci1394_pci_driver);
 }
 
 module_init(ohci1394_init);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -236,6 +236,9 @@ struct ti_ohci {
 
 static inline int cross_bound(unsigned long addr, unsigned int size)
 {
+	if (size == 0)
+		return 0;
+
 	if (size > PAGE_SIZE)
 		return 1;
 
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1,5 +1,5 @@
 /*
- * ti_pcilynx.c - Texas Instruments PCILynx driver
+ * pcilynx.c - Texas Instruments PCILynx driver
  * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
  *                         Stephan Linz <linz@mazet.de>
  *                         Manfred Weihs <weihs@ict.tuwien.ac.at>
@@ -43,6 +43,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -384,7 +385,8 @@ static quadlet_t generate_own_selfid(str
         lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
         lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
         lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
-        lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
+	if (!hpsb_disable_irm)
+		lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
         /* lsid |= 1 << 11; *//* set contender (hack) */
         lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
 
@@ -500,7 +502,7 @@ static void send_next(struct ti_lynx *ly
         pcl.async_error_next = PCL_NEXT_INVALID;
         pcl.pcl_status = 0;
         pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
-#ifdef __BIG_ENDIAN
+#ifndef __BIG_ENDIAN
         pcl.buffer[0].control |= PCL_BIGENDIAN;
 #endif
         pcl.buffer[0].pointer = d->header_dma;
@@ -833,327 +835,6 @@ static int lynx_devctl(struct hpsb_host 
  * IEEE-1394 functionality section END *
  ***************************************/
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-/* VFS functions for local bus / aux device access.  Access to those
- * is implemented as a character device instead of block devices
- * because buffers are not wanted for this.  Therefore llseek (from
- * VFS) can be used for these char devices with obvious effects.
- */
-static int mem_open(struct inode*, struct file*);
-static int mem_release(struct inode*, struct file*);
-static unsigned int aux_poll(struct file*, struct poll_table_struct*);
-static loff_t mem_llseek(struct file*, loff_t, int);
-static ssize_t mem_read (struct file*, char*, size_t, loff_t*);
-static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
-
-
-static struct file_operations aux_ops = {
-	.owner =	THIS_MODULE,
-        .read =         mem_read,
-        .write =        mem_write,
-        .poll =         aux_poll,
-        .llseek =       mem_llseek,
-        .open =         mem_open,
-        .release =      mem_release,
-};
-
-
-static void aux_setup_pcls(struct ti_lynx *lynx)
-{
-        struct ti_pcl pcl;
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.user_data = pcl_bus(lynx, lynx->dmem_pcl);
-        put_pcl(lynx, lynx->dmem_pcl, &pcl);
-}
-
-static int mem_open(struct inode *inode, struct file *file)
-{
-        int cid = iminor(inode);
-        enum { t_rom, t_aux, t_ram } type;
-        struct memdata *md;
-
-        if (cid < PCILYNX_MINOR_AUX_START) {
-                /* just for completeness */
-                return -ENXIO;
-        } else if (cid < PCILYNX_MINOR_ROM_START) {
-                cid -= PCILYNX_MINOR_AUX_START;
-                if (cid >= num_of_cards || !cards[cid].aux_port)
-                        return -ENXIO;
-                type = t_aux;
-        } else if (cid < PCILYNX_MINOR_RAM_START) {
-                cid -= PCILYNX_MINOR_ROM_START;
-                if (cid >= num_of_cards || !cards[cid].local_rom)
-                        return -ENXIO;
-                type = t_rom;
-        } else {
-                /* WARNING: Know what you are doing when opening RAM.
-                 * It is currently used inside the driver! */
-                cid -= PCILYNX_MINOR_RAM_START;
-                if (cid >= num_of_cards || !cards[cid].local_ram)
-                        return -ENXIO;
-                type = t_ram;
-        }
-
-        md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
-        if (md == NULL)
-                return -ENOMEM;
-
-        md->lynx = &cards[cid];
-        md->cid = cid;
-
-        switch (type) {
-        case t_rom:
-                md->type = rom;
-                break;
-        case t_ram:
-                md->type = ram;
-                break;
-        case t_aux:
-                atomic_set(&md->aux_intr_last_seen,
-                           atomic_read(&cards[cid].aux_intr_seen));
-                md->type = aux;
-                break;
-        }
-
-        file->private_data = md;
-
-        return 0;
-}
-
-static int mem_release(struct inode *inode, struct file *file)
-{
-        kfree(file->private_data);
-        return 0;
-}
-
-static unsigned int aux_poll(struct file *file, poll_table *pt)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-        int cid = md->cid;
-        unsigned int mask;
-
-        /* reading and writing is always allowed */
-        mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
-
-        if (md->type == aux) {
-                poll_wait(file, &cards[cid].aux_intr_wait, pt);
-
-                if (atomic_read(&md->aux_intr_last_seen)
-                    != atomic_read(&cards[cid].aux_intr_seen)) {
-                        mask |= POLLPRI;
-                        atomic_inc(&md->aux_intr_last_seen);
-                }
-        }
-
-        return mask;
-}
-
-loff_t mem_llseek(struct file *file, loff_t offs, int orig)
-{
-        loff_t newoffs;
-
-        switch (orig) {
-        case 0:
-                newoffs = offs;
-                break;
-        case 1:
-                newoffs = offs + file->f_pos;
-                break;
-        case 2:
-                newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
-
-        file->f_pos = newoffs;
-        return newoffs;
-}
-
-/*
- * do not DMA if count is too small because this will have a serious impact
- * on performance - the value 2400 was found by experiment and may not work
- * everywhere as good as here - use mem_mindma option for modules to change
- */
-static short mem_mindma = 2400;
-module_param(mem_mindma, short, 0444);
-MODULE_PARM_DESC(mem_mindma, "Minimum amount of data required to use DMA");
-
-static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count,
-                           int offset)
-{
-        pcltmp_t pcltmp;
-        struct ti_pcl *pcl;
-        size_t retval;
-        int i;
-        DECLARE_WAITQUEUE(wait, current);
-
-        count &= ~3;
-        count = min(count, 53196);
-        retval = count;
-
-        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-            & DMA_CHAN_CTRL_BUSY) {
-                PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!");
-        }
-
-        reg_write(md->lynx, LBUS_ADDR, md->type | offset);
-
-        pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);
-        pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | min(count, 4092);
-        pcl->buffer[0].pointer = physbuf;
-        count -= 4092;
-
-        i = 0;
-        while (count > 0) {
-                i++;
-                pcl->buffer[i].control = min(count, 4092);
-                pcl->buffer[i].pointer = physbuf + i * 4092;
-                count -= 4092;
-        }
-        pcl->buffer[i].control |= PCL_LAST_BUFF;
-        commit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);
-
-        set_current_state(TASK_INTERRUPTIBLE);
-        add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
-        run_sub_pcl(md->lynx, md->lynx->dmem_pcl, 2, CHANNEL_LOCALBUS);
-
-        schedule();
-        while (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-               & DMA_CHAN_CTRL_BUSY) {
-                if (signal_pending(current)) {
-                        retval = -EINTR;
-                        break;
-                }
-                schedule();
-        }
-
-        reg_write(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS), 0);
-        remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
-
-        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-            & DMA_CHAN_CTRL_BUSY) {
-                PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!");
-        }
-
-        return retval;
-}
-
-static ssize_t mem_read(struct file *file, char *buffer, size_t count,
-                        loff_t *offset)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-        ssize_t bcount;
-        size_t alignfix;
-	loff_t off = *offset; /* avoid useless 64bit-arithmetic */
-        ssize_t retval;
-        void *membase;
-
-        if ((off + count) > PCILYNX_MAX_MEMORY+1) {
-                count = PCILYNX_MAX_MEMORY+1 - off;
-        }
-        if (count == 0 || off > PCILYNX_MAX_MEMORY) {
-                return -ENOSPC;
-        }
-
-        switch (md->type) {
-        case rom:
-                membase = md->lynx->local_rom;
-                break;
-        case ram:
-                membase = md->lynx->local_ram;
-                break;
-        case aux:
-                membase = md->lynx->aux_port;
-                break;
-        default:
-                panic("pcilynx%d: unsupported md->type %d in %s",
-                      md->lynx->id, md->type, __FUNCTION__);
-        }
-
-        down(&md->lynx->mem_dma_mutex);
-
-        if (count < mem_mindma) {
-                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count);
-                goto out;
-        }
-
-        bcount = count;
-        alignfix = 4 - (off % 4);
-        if (alignfix != 4) {
-                if (bcount < alignfix) {
-                        alignfix = bcount;
-                }
-                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off,
-                              alignfix);
-                if (bcount == alignfix) {
-                        goto out;
-                }
-                bcount -= alignfix;
-                off += alignfix;
-        }
-
-        while (bcount >= 4) {
-                retval = mem_dmaread(md, md->lynx->mem_dma_buffer_dma
-                                     + count - bcount, bcount, off);
-                if (retval < 0) return retval;
-
-                bcount -= retval;
-                off += retval;
-        }
-
-        if (bcount) {
-                memcpy_fromio(md->lynx->mem_dma_buffer + count - bcount,
-                              membase+off, bcount);
-        }
-
- out:
-        retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count);
-        up(&md->lynx->mem_dma_mutex);
-
-	if (retval) return -EFAULT;
-        *offset += count;
-        return count;
-}
-
-
-static ssize_t mem_write(struct file *file, const char *buffer, size_t count,
-                         loff_t *offset)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-
-        if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) {
-                count = PCILYNX_MAX_MEMORY+1 - *offset;
-        }
-        if (count == 0 || *offset > PCILYNX_MAX_MEMORY) {
-                return -ENOSPC;
-        }
-
-        /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */
-        switch (md->type) {
-        case aux:
-		if (copy_from_user(md->lynx->aux_port+(*offset), buffer, count))
-			return -EFAULT;
-                break;
-        case ram:
-		if (copy_from_user(md->lynx->local_ram+(*offset), buffer, count))
-			return -EFAULT;
-                break;
-        case rom:
-                /* the ROM may be writeable */
-		if (copy_from_user(md->lynx->local_rom+(*offset), buffer, count))
-			return -EFAULT;
-                break;
-        }
-
-        file->f_pos += count;
-        return count;
-}
-#endif /* CONFIG_IEEE1394_PCILYNX_PORTS */
-
 
 /********************************************************
  * Global stuff (interrupt handler, init/shutdown code) *
@@ -1180,18 +861,6 @@ static irqreturn_t lynx_irq_handler(int 
         reg_write(lynx, LINK_INT_STATUS, linkint);
         reg_write(lynx, PCI_INT_STATUS, intmask);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (intmask & PCI_INT_AUX_INT) {
-                atomic_inc(&lynx->aux_intr_seen);
-                wake_up_interruptible(&lynx->aux_intr_wait);
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) {
-                wake_up_interruptible(&lynx->mem_dma_intr_wait);
-        }
-#endif
-
-
         if (intmask & PCI_INT_1394) {
                 if (linkint & LINK_INT_PHY_TIMEOUT) {
                         PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
@@ -1483,15 +1152,9 @@ static void remove_card(struct pci_dev *
                 pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
                                     lynx->rcv_page_dma);
         case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
-                                    lynx->mem_dma_buffer_dma);
-#endif
         case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
                 pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
                                     lynx->pcl_mem_dma);
-#endif
         case clear:
                 /* do nothing - already freed */
                 ;
@@ -1521,13 +1184,9 @@ static int __devinit add_card(struct pci
         int i;
         int error;
 
-        /* needed for i2c communication with serial eeprom */
-        struct i2c_adapter i2c_adapter;
-        struct i2c_algo_bit_data i2c_adapter_data;
-
         error = -ENXIO;
 
-        if (pci_set_dma_mask(dev, 0xffffffff))
+        if (pci_set_dma_mask(dev, DMA_32BIT_MASK))
                 FAIL("DMA address limits not supported for PCILynx hardware");
         if (pci_enable_device(dev))
                 FAIL("failed to enable PCILynx hardware");
@@ -1549,7 +1208,6 @@ static int __devinit add_card(struct pci
         spin_lock_init(&lynx->lock);
         spin_lock_init(&lynx->phy_reg_lock);
 
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
         lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
                                              &lynx->pcl_mem_dma);
 
@@ -1561,16 +1219,6 @@ static int __devinit add_card(struct pci
         } else {
                 FAIL("failed to allocate PCL memory area");
         }
-#endif
-
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536,
-                                                    &lynx->mem_dma_buffer_dma);
-        if (lynx->mem_dma_buffer == NULL) {
-                FAIL("failed to allocate DMA buffer for aux");
-        }
-        lynx->state = have_aux_buf;
-#endif
 
         lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
                                               &lynx->rcv_page_dma);
@@ -1600,13 +1248,6 @@ static int __devinit add_card(struct pci
                 FAIL("failed to remap registers - card not accessible");
         }
 
-#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-        if (lynx->local_ram == NULL) {
-                FAIL("failed to remap local RAM which is required for "
-                     "operation");
-        }
-#endif
-
         reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
         /* Fix buggy cards with autoboot pin not tied low: */
         reg_write(lynx, DMA0_CHAN_CTRL, 0);
@@ -1627,13 +1268,6 @@ static int __devinit add_card(struct pci
 
         /* alloc_pcl return values are not checked, it is expected that the
          * provided PCL space is sufficient for the initial allocations */
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (lynx->aux_port != NULL) {
-                lynx->dmem_pcl = alloc_pcl(lynx);
-                aux_setup_pcls(lynx);
-                sema_init(&lynx->mem_dma_mutex, 1);
-        }
-#endif
         lynx->rcv_pcl = alloc_pcl(lynx);
         lynx->rcv_pcl_start = alloc_pcl(lynx);
         lynx->async.pcl = alloc_pcl(lynx);
@@ -1650,12 +1284,6 @@ static int __devinit add_card(struct pci
 
         reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT);
-        init_waitqueue_head(&lynx->mem_dma_intr_wait);
-        init_waitqueue_head(&lynx->aux_intr_wait);
-#endif
-
 	tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
 		     (unsigned long)lynx);
 
@@ -1697,7 +1325,7 @@ static int __devinit add_card(struct pci
         pcl.async_error_next = PCL_NEXT_INVALID;
 
         pcl.buffer[0].control = PCL_CMD_RCV | 16;
-#ifdef __BIG_ENDIAN
+#ifndef __BIG_ENDIAN
 	pcl.buffer[0].control |= PCL_BIGENDIAN;
 #endif
 	pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
@@ -1779,26 +1407,40 @@ static int __devinit add_card(struct pci
                   | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
                   | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
 
-        if (!lynx->phyic.reg_1394a) {
-                /* attempt to enable contender bit -FIXME- would this work
-                 * elsewhere? */
-                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
-                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
-        } else {
-                /* set the contender and LCtrl bit in the extended PHY register
-                 * set. (Should check that bis 0,1,2 (=0xE0) is set
-                 * in register 2?)
-                 */
-                i = get_phy_reg(lynx, 4);
-                if (i != -1) set_phy_reg(lynx, 4, i | 0xc0);
-        }
-
-
+	if (!lynx->phyic.reg_1394a) {
+		if (!hpsb_disable_irm) {
+			/* attempt to enable contender bit -FIXME- would this
+			 * work elsewhere? */
+			reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+			reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
+		}
+	} else {
+		/* set the contender (if appropriate) and LCtrl bit in the
+		 * extended PHY register set. (Should check that PHY_02_EXTENDED
+		 * is set in register 2?)
+		 */
+		i = get_phy_reg(lynx, 4);
+		i |= PHY_04_LCTRL;
+		if (hpsb_disable_irm)
+			i &= !PHY_04_CONTENDER;
+		else
+			i |= PHY_04_CONTENDER;
+		if (i != -1) set_phy_reg(lynx, 4, i);
+	}
+	
         if (!skip_eeprom)
         {
-                i2c_adapter = bit_ops;
+        	/* needed for i2c communication with serial eeprom */
+        	struct i2c_adapter *i2c_ad;
+        	struct i2c_algo_bit_data i2c_adapter_data;
+
+        	error = -ENOMEM;
+		i2c_ad = kmalloc(sizeof(struct i2c_adapter), SLAB_KERNEL);
+        	if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
+
+		memcpy(i2c_ad, &bit_ops, sizeof(struct i2c_adapter));
                 i2c_adapter_data = bit_data;
-                i2c_adapter.algo_data = &i2c_adapter_data;
+                i2c_ad->algo_data = &i2c_adapter_data;
                 i2c_adapter_data.data = lynx;
 
 		PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
@@ -1808,8 +1450,9 @@ static int __devinit add_card(struct pci
         	lynx->i2c_driven_state = 0x00000070;
         	reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
 
-        	if (i2c_bit_add_bus(&i2c_adapter) < 0)
+        	if (i2c_bit_add_bus(i2c_ad) < 0)
         	{
+			kfree(i2c_ad);
 			error = -ENXIO;
 			FAIL("unable to register i2c");
         	}
@@ -1825,13 +1468,13 @@ static int __devinit add_card(struct pci
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
                         union i2c_smbus_data data;
 
-                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
+                        if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
                                 PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");
                         else
                         {
                                 u16 addr;
                                 for (addr=0x00; addr < 0x100; addr++) {
-                                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
+                                        if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
                                                 PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);
                                                 break;
                                         }
@@ -1843,7 +1486,7 @@ static int __devinit add_card(struct pci
 
                         /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
                            do it more efficiently in one transaction rather then using several reads */
-                        if (i2c_transfer(&i2c_adapter, msg, 2) < 0) {
+                        if (i2c_transfer(i2c_ad, msg, 2) < 0) {
                                 PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
                         } else {
                                 int i;
@@ -1863,13 +1506,15 @@ static int __devinit add_card(struct pci
                                 {
                                         PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
                                 } else {
+					kfree(i2c_ad);
 					error = -ENXIO;
 					FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
                                 }
 
                         }
 
-                        i2c_bit_del_bus(&i2c_adapter);
+                        i2c_bit_del_bus(i2c_ad);
+			kfree(i2c_ad);
                 }
         }
 
@@ -1930,37 +1575,18 @@ static int __init pcilynx_init(void)
 {
         int ret;
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
-                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
-                        PCILYNX_MAJOR);
-                return -EBUSY;
-        }
-#endif
-
-        ret = pci_module_init(&lynx_pci_driver);
+        ret = pci_register_driver(&lynx_pci_driver);
         if (ret < 0) {
                 PRINT_G(KERN_ERR, "PCI module init failed");
-                goto free_char_dev;
+                return ret;
         }
 
         return 0;
-
- free_char_dev:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
-
-        return ret;
 }
 
 static void __exit pcilynx_cleanup(void)
 {
         pci_unregister_driver(&lynx_pci_driver);
-
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
 }
 
 
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -55,16 +55,6 @@ struct ti_lynx {
         void __iomem *aux_port;
 	quadlet_t bus_info_block[5];
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        atomic_t aux_intr_seen;
-        wait_queue_head_t aux_intr_wait;
-
-        void *mem_dma_buffer;
-        dma_addr_t mem_dma_buffer_dma;
-        struct semaphore mem_dma_mutex;
-        wait_queue_head_t mem_dma_intr_wait;
-#endif
-
         /*
          * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
          * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
@@ -72,11 +62,9 @@ struct ti_lynx {
          */
         u8 pcl_bmap[LOCALRAM_SIZE / 1024];
 
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
 	/* point to PCLs memory area if needed */
 	void *pcl_mem;
         dma_addr_t pcl_mem_dma;
-#endif
 
         /* PCLs for local mem / aux transfers */
         pcl_t dmem_pcl;
@@ -378,39 +366,6 @@ struct ti_pcl {
 #define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
 
 
-#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           const struct ti_pcl *pcl)
-{
-        int i;
-        u32 *in = (u32 *)pcl;
-        u32 *out = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
-
-        for (i = 0; i < 32; i++, out++, in++) {
-                writel(*in, out);
-        }
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           struct ti_pcl *pcl)
-{
-        int i;
-        u32 *out = (u32 *)pcl;
-        u32 *in = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
-
-        for (i = 0; i < 32; i++, out++, in++) {
-                *out = readl(in);
-        }
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        return pci_resource_start(lynx->dev, 1) + pclid * sizeof(struct ti_pcl);
-}
-
-#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
-
 static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
                            const struct ti_pcl *pcl)
 {
@@ -431,10 +386,8 @@ static inline u32 pcl_bus(const struct t
         return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
 }
 
-#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
-
 
-#if defined (CONFIG_IEEE1394_PCILYNX_LOCALRAM) || defined (__BIG_ENDIAN)
+#if defined (__BIG_ENDIAN)
 typedef struct ti_pcl pcltmp_t;
 
 static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -75,58 +75,60 @@ static DEFINE_SPINLOCK(host_info_lock);
 static atomic_t internal_generation = ATOMIC_INIT(0);
 
 static atomic_t iso_buffer_size;
-static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
+static const int iso_buffer_max = 4 * 1024 * 1024;	/* 4 MB */
 
 static struct hpsb_highlevel raw1394_highlevel;
 
-static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-		     u64 addr, size_t length, u16 flags);
-static int arm_write (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
-             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
-static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
-               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
+		    u64 addr, size_t length, u16 flags);
+static int arm_write(struct hpsb_host *host, int nodeid, int destid,
+		     quadlet_t * data, u64 addr, size_t length, u16 flags);
+static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
+		    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
+		    u16 flags);
+static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
+		      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
+		      u16 flags);
 static struct hpsb_address_ops arm_ops = {
-	.read	= arm_read,
-	.write	= arm_write,
-	.lock	= arm_lock,
-	.lock64	= arm_lock64,
+	.read = arm_read,
+	.write = arm_write,
+	.lock = arm_lock,
+	.lock64 = arm_lock64,
 };
 
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
 {
-        struct pending_request *req;
+	struct pending_request *req;
 
-        req = (struct pending_request *)kmalloc(sizeof(struct pending_request),
-                                                flags);
-        if (req != NULL) {
-                memset(req, 0, sizeof(struct pending_request));
-                INIT_LIST_HEAD(&req->list);
-        }
+	req = (struct pending_request *)kmalloc(sizeof(struct pending_request),
+						flags);
+	if (req != NULL) {
+		memset(req, 0, sizeof(struct pending_request));
+		INIT_LIST_HEAD(&req->list);
+	}
 
-        return req;
+	return req;
 }
 
 static inline struct pending_request *alloc_pending_request(void)
 {
-        return __alloc_pending_request(SLAB_KERNEL);
+	return __alloc_pending_request(SLAB_KERNEL);
 }
 
 static void free_pending_request(struct pending_request *req)
 {
-        if (req->ibs) {
-                if (atomic_dec_and_test(&req->ibs->refcount)) {
-                        atomic_sub(req->ibs->data_size, &iso_buffer_size);
-                        kfree(req->ibs);
-                }
-        } else if (req->free_data) {
-                kfree(req->data);
-        }
-        hpsb_free_packet(req->packet);
-        kfree(req);
+	if (req->ibs) {
+		if (atomic_dec_and_test(&req->ibs->refcount)) {
+			atomic_sub(req->ibs->data_size, &iso_buffer_size);
+			kfree(req->ibs);
+		}
+	} else if (req->free_data) {
+		kfree(req->data);
+	}
+	hpsb_free_packet(req->packet);
+	kfree(req);
 }
 
 /* fi->reqlists_lock must be taken */
@@ -134,494 +136,505 @@ static void __queue_complete_req(struct 
 {
 	struct file_info *fi = req->file_info;
 	list_del(&req->list);
-        list_add_tail(&req->list, &fi->req_complete);
+	list_add_tail(&req->list, &fi->req_complete);
 
 	up(&fi->complete_sem);
-        wake_up_interruptible(&fi->poll_wait_complete);
+	wake_up_interruptible(&fi->poll_wait_complete);
 }
 
 static void queue_complete_req(struct pending_request *req)
 {
-        unsigned long flags;
-        struct file_info *fi = req->file_info;
+	unsigned long flags;
+	struct file_info *fi = req->file_info;
 
-        spin_lock_irqsave(&fi->reqlists_lock, flags);
+	spin_lock_irqsave(&fi->reqlists_lock, flags);
 	__queue_complete_req(req);
-        spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
 }
 
 static void queue_complete_cb(struct pending_request *req)
 {
-        struct hpsb_packet *packet = req->packet;
-        int rcode = (packet->header[1] >> 12) & 0xf;
+	struct hpsb_packet *packet = req->packet;
+	int rcode = (packet->header[1] >> 12) & 0xf;
+
+	switch (packet->ack_code) {
+	case ACKX_NONE:
+	case ACKX_SEND_ERROR:
+		req->req.error = RAW1394_ERROR_SEND_ERROR;
+		break;
+	case ACKX_ABORTED:
+		req->req.error = RAW1394_ERROR_ABORTED;
+		break;
+	case ACKX_TIMEOUT:
+		req->req.error = RAW1394_ERROR_TIMEOUT;
+		break;
+	default:
+		req->req.error = (packet->ack_code << 16) | rcode;
+		break;
+	}
 
-        switch (packet->ack_code) {
-        case ACKX_NONE:
-        case ACKX_SEND_ERROR:
-                req->req.error = RAW1394_ERROR_SEND_ERROR;
-                break;
-        case ACKX_ABORTED:
-                req->req.error = RAW1394_ERROR_ABORTED;
-                break;
-        case ACKX_TIMEOUT:
-                req->req.error = RAW1394_ERROR_TIMEOUT;
-                break;
-        default:
-                req->req.error = (packet->ack_code << 16) | rcode;
-                break;
-        }
-
-        if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
-                req->req.length = 0;
-        }
+	if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
+		req->req.length = 0;
+	}
 
-        if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
+	if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
 	    (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
 	    (req->req.type == RAW1394_REQ_ASYNC_STREAM) ||
 	    (req->req.type == RAW1394_REQ_LOCK) ||
 	    (req->req.type == RAW1394_REQ_LOCK64))
-                hpsb_free_tlabel(packet);
+		hpsb_free_tlabel(packet);
 
-        queue_complete_req(req);
+	queue_complete_req(req);
 }
 
-
 static void add_host(struct hpsb_host *host)
 {
-        struct host_info *hi;
-        unsigned long flags;
+	struct host_info *hi;
+	unsigned long flags;
 
-        hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL);
+	hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL);
 
-        if (hi != NULL) {
-                INIT_LIST_HEAD(&hi->list);
-                hi->host = host;
-                INIT_LIST_HEAD(&hi->file_info_list);
-
-                spin_lock_irqsave(&host_info_lock, flags);
-                list_add_tail(&hi->list, &host_info_list);
-                host_count++;
-                spin_unlock_irqrestore(&host_info_lock, flags);
-        }
+	if (hi != NULL) {
+		INIT_LIST_HEAD(&hi->list);
+		hi->host = host;
+		INIT_LIST_HEAD(&hi->file_info_list);
+
+		spin_lock_irqsave(&host_info_lock, flags);
+		list_add_tail(&hi->list, &host_info_list);
+		host_count++;
+		spin_unlock_irqrestore(&host_info_lock, flags);
+	}
 
-        atomic_inc(&internal_generation);
+	atomic_inc(&internal_generation);
 }
 
-
 static struct host_info *find_host_info(struct hpsb_host *host)
 {
-        struct host_info *hi;
+	struct host_info *hi;
 
-        list_for_each_entry(hi, &host_info_list, list)
-                if (hi->host == host)
-                        return hi;
+	list_for_each_entry(hi, &host_info_list, list)
+	    if (hi->host == host)
+		return hi;
 
-        return NULL;
+	return NULL;
 }
 
 static void remove_host(struct hpsb_host *host)
 {
-        struct host_info *hi;
-        unsigned long flags;
+	struct host_info *hi;
+	unsigned long flags;
 
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(host);
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(host);
 
-        if (hi != NULL) {
-                list_del(&hi->list);
-                host_count--;
-                /*
-                   FIXME: address ranges should be removed
-                   and fileinfo states should be initialized
-                   (including setting generation to
-                   internal-generation ...)
-                */
-        }
-        spin_unlock_irqrestore(&host_info_lock, flags);
-
-        if (hi == NULL) {
-                printk(KERN_ERR "raw1394: attempt to remove unknown host "
-                       "0x%p\n", host);
-                return;
-        }
+	if (hi != NULL) {
+		list_del(&hi->list);
+		host_count--;
+		/*
+		   FIXME: address ranges should be removed
+		   and fileinfo states should be initialized
+		   (including setting generation to
+		   internal-generation ...)
+		 */
+	}
+	spin_unlock_irqrestore(&host_info_lock, flags);
 
-        kfree(hi);
+	if (hi == NULL) {
+		printk(KERN_ERR "raw1394: attempt to remove unknown host "
+		       "0x%p\n", host);
+		return;
+	}
+
+	kfree(hi);
 
-        atomic_inc(&internal_generation);
+	atomic_inc(&internal_generation);
 }
 
 static void host_reset(struct hpsb_host *host)
 {
-        unsigned long flags;
-        struct host_info *hi;
-        struct file_info *fi;
-        struct pending_request *req;
-
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(host);
-
-        if (hi != NULL) {
-                list_for_each_entry(fi, &hi->file_info_list, list) {
-                        if (fi->notification == RAW1394_NOTIFY_ON) {
-                                req = __alloc_pending_request(SLAB_ATOMIC);
-
-                                if (req != NULL) {
-                                        req->file_info = fi;
-                                        req->req.type = RAW1394_REQ_BUS_RESET;
-                                        req->req.generation = get_hpsb_generation(host);
-                                        req->req.misc = (host->node_id << 16)
-                                                | host->node_count;
-                                        if (fi->protocol_version > 3) {
-                                                req->req.misc |= (NODEID_TO_NODE(host->irm_id)
-                                                                  << 8);
-                                        }
-
-                                        queue_complete_req(req);
-                                }
-                        }
-                }
-        }
-        spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
-                        size_t length)
-{
-        unsigned long flags;
-        struct host_info *hi;
-        struct file_info *fi;
-        struct pending_request *req, *req_next;
-        struct iso_block_store *ibs = NULL;
-        LIST_HEAD(reqs);
-
-        if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
-                HPSB_INFO("dropped iso packet");
-                return;
-        }
+	unsigned long flags;
+	struct host_info *hi;
+	struct file_info *fi;
+	struct pending_request *req;
 
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(host);
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(host);
 
-        if (hi != NULL) {
+	if (hi != NULL) {
 		list_for_each_entry(fi, &hi->file_info_list, list) {
-                        if (!(fi->listen_channels & (1ULL << channel)))
-                                continue;
+			if (fi->notification == RAW1394_NOTIFY_ON) {
+				req = __alloc_pending_request(SLAB_ATOMIC);
 
-                        req = __alloc_pending_request(SLAB_ATOMIC);
-                        if (!req) break;
+				if (req != NULL) {
+					req->file_info = fi;
+					req->req.type = RAW1394_REQ_BUS_RESET;
+					req->req.generation =
+					    get_hpsb_generation(host);
+					req->req.misc = (host->node_id << 16)
+					    | host->node_count;
+					if (fi->protocol_version > 3) {
+						req->req.misc |=
+						    (NODEID_TO_NODE
+						     (host->irm_id)
+						     << 8);
+					}
 
-                        if (!ibs) {
-                                ibs = kmalloc(sizeof(struct iso_block_store)
-                                              + length, SLAB_ATOMIC);
-                                if (!ibs) {
-                                        kfree(req);
-                                        break;
-                                }
-
-                                atomic_add(length, &iso_buffer_size);
-                                atomic_set(&ibs->refcount, 0);
-                                ibs->data_size = length;
-                                memcpy(ibs->data, data, length);
-                        }
-
-                        atomic_inc(&ibs->refcount);
-
-                        req->file_info = fi;
-                        req->ibs = ibs;
-                        req->data = ibs->data;
-                        req->req.type = RAW1394_REQ_ISO_RECEIVE;
-                        req->req.generation = get_hpsb_generation(host);
-                        req->req.misc = 0;
-                        req->req.recvb = ptr2int(fi->iso_buffer);
-                        req->req.length = min(length, fi->iso_buffer_length);
-
-                        list_add_tail(&req->list, &reqs);
-                }
-        }
-        spin_unlock_irqrestore(&host_info_lock, flags);
+					queue_complete_req(req);
+				}
+			}
+		}
+	}
+	spin_unlock_irqrestore(&host_info_lock, flags);
+}
+
+static void iso_receive(struct hpsb_host *host, int channel, quadlet_t * data,
+			size_t length)
+{
+	unsigned long flags;
+	struct host_info *hi;
+	struct file_info *fi;
+	struct pending_request *req, *req_next;
+	struct iso_block_store *ibs = NULL;
+	LIST_HEAD(reqs);
+
+	if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+		HPSB_INFO("dropped iso packet");
+		return;
+	}
+
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(host);
+
+	if (hi != NULL) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+			if (!(fi->listen_channels & (1ULL << channel)))
+				continue;
+
+			req = __alloc_pending_request(SLAB_ATOMIC);
+			if (!req)
+				break;
+
+			if (!ibs) {
+				ibs = kmalloc(sizeof(struct iso_block_store)
+					      + length, SLAB_ATOMIC);
+				if (!ibs) {
+					kfree(req);
+					break;
+				}
+
+				atomic_add(length, &iso_buffer_size);
+				atomic_set(&ibs->refcount, 0);
+				ibs->data_size = length;
+				memcpy(ibs->data, data, length);
+			}
+
+			atomic_inc(&ibs->refcount);
+
+			req->file_info = fi;
+			req->ibs = ibs;
+			req->data = ibs->data;
+			req->req.type = RAW1394_REQ_ISO_RECEIVE;
+			req->req.generation = get_hpsb_generation(host);
+			req->req.misc = 0;
+			req->req.recvb = ptr2int(fi->iso_buffer);
+			req->req.length = min(length, fi->iso_buffer_length);
+
+			list_add_tail(&req->list, &reqs);
+		}
+	}
+	spin_unlock_irqrestore(&host_info_lock, flags);
 
 	list_for_each_entry_safe(req, req_next, &reqs, list)
-                queue_complete_req(req);
+	    queue_complete_req(req);
 }
 
 static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
-			int cts, u8 *data, size_t length)
+			int cts, u8 * data, size_t length)
 {
-        unsigned long flags;
-        struct host_info *hi;
-        struct file_info *fi;
-        struct pending_request *req, *req_next;
-        struct iso_block_store *ibs = NULL;
-        LIST_HEAD(reqs);
-
-        if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
-                HPSB_INFO("dropped fcp request");
-                return;
-        }
+	unsigned long flags;
+	struct host_info *hi;
+	struct file_info *fi;
+	struct pending_request *req, *req_next;
+	struct iso_block_store *ibs = NULL;
+	LIST_HEAD(reqs);
+
+	if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+		HPSB_INFO("dropped fcp request");
+		return;
+	}
 
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(host);
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(host);
 
-        if (hi != NULL) {
+	if (hi != NULL) {
 		list_for_each_entry(fi, &hi->file_info_list, list) {
-                        if (!fi->fcp_buffer)
-                                continue;
+			if (!fi->fcp_buffer)
+				continue;
+
+			req = __alloc_pending_request(SLAB_ATOMIC);
+			if (!req)
+				break;
+
+			if (!ibs) {
+				ibs = kmalloc(sizeof(struct iso_block_store)
+					      + length, SLAB_ATOMIC);
+				if (!ibs) {
+					kfree(req);
+					break;
+				}
 
-                        req = __alloc_pending_request(SLAB_ATOMIC);
-                        if (!req) break;
+				atomic_add(length, &iso_buffer_size);
+				atomic_set(&ibs->refcount, 0);
+				ibs->data_size = length;
+				memcpy(ibs->data, data, length);
+			}
 
-                        if (!ibs) {
-                                ibs = kmalloc(sizeof(struct iso_block_store)
-                                              + length, SLAB_ATOMIC);
-                                if (!ibs) {
-                                        kfree(req);
-                                        break;
-                                }
-
-                                atomic_add(length, &iso_buffer_size);
-                                atomic_set(&ibs->refcount, 0);
-                                ibs->data_size = length;
-                                memcpy(ibs->data, data, length);
-                        }
-
-                        atomic_inc(&ibs->refcount);
-
-                        req->file_info = fi;
-                        req->ibs = ibs;
-                        req->data = ibs->data;
-                        req->req.type = RAW1394_REQ_FCP_REQUEST;
-                        req->req.generation = get_hpsb_generation(host);
-                        req->req.misc = nodeid | (direction << 16);
-                        req->req.recvb = ptr2int(fi->fcp_buffer);
-                        req->req.length = length;
-
-                        list_add_tail(&req->list, &reqs);
-                }
-        }
-        spin_unlock_irqrestore(&host_info_lock, flags);
+			atomic_inc(&ibs->refcount);
+
+			req->file_info = fi;
+			req->ibs = ibs;
+			req->data = ibs->data;
+			req->req.type = RAW1394_REQ_FCP_REQUEST;
+			req->req.generation = get_hpsb_generation(host);
+			req->req.misc = nodeid | (direction << 16);
+			req->req.recvb = ptr2int(fi->fcp_buffer);
+			req->req.length = length;
+
+			list_add_tail(&req->list, &reqs);
+		}
+	}
+	spin_unlock_irqrestore(&host_info_lock, flags);
 
 	list_for_each_entry_safe(req, req_next, &reqs, list)
-                queue_complete_req(req);
+	    queue_complete_req(req);
 }
 
-
-static ssize_t raw1394_read(struct file *file, char __user *buffer, size_t count,
-                    loff_t *offset_is_ignored)
+static ssize_t raw1394_read(struct file *file, char __user * buffer,
+			    size_t count, loff_t * offset_is_ignored)
 {
-        struct file_info *fi = (struct file_info *)file->private_data;
-        struct list_head *lh;
-        struct pending_request *req;
-
-        if (count != sizeof(struct raw1394_request)) {
-                return -EINVAL;
-        }
-
-        if (!access_ok(VERIFY_WRITE, buffer, count)) {
-                return -EFAULT;
-        }
-
-        if (file->f_flags & O_NONBLOCK) {
-                if (down_trylock(&fi->complete_sem)) {
-                        return -EAGAIN;
-                }
-        } else {
-                if (down_interruptible(&fi->complete_sem)) {
-                        return -ERESTARTSYS;
-                }
-        }
-
-        spin_lock_irq(&fi->reqlists_lock);
-        lh = fi->req_complete.next;
-        list_del(lh);
-        spin_unlock_irq(&fi->reqlists_lock);
-
-        req = list_entry(lh, struct pending_request, list);
-
-        if (req->req.length) {
-                if (copy_to_user(int2ptr(req->req.recvb), req->data,
-                                 req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                }
-        }
-        __copy_to_user(buffer, &req->req, sizeof(req->req));
+	struct file_info *fi = (struct file_info *)file->private_data;
+	struct list_head *lh;
+	struct pending_request *req;
+	ssize_t ret;
 
-        free_pending_request(req);
-        return sizeof(struct raw1394_request);
-}
+	if (count != sizeof(struct raw1394_request)) {
+		return -EINVAL;
+	}
 
+	if (!access_ok(VERIFY_WRITE, buffer, count)) {
+		return -EFAULT;
+	}
+
+	if (file->f_flags & O_NONBLOCK) {
+		if (down_trylock(&fi->complete_sem)) {
+			return -EAGAIN;
+		}
+	} else {
+		if (down_interruptible(&fi->complete_sem)) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	spin_lock_irq(&fi->reqlists_lock);
+	lh = fi->req_complete.next;
+	list_del(lh);
+	spin_unlock_irq(&fi->reqlists_lock);
+
+	req = list_entry(lh, struct pending_request, list);
+
+	if (req->req.length) {
+		if (copy_to_user(int2ptr(req->req.recvb), req->data,
+				 req->req.length)) {
+			req->req.error = RAW1394_ERROR_MEMFAULT;
+		}
+	}
+	if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = (ssize_t) sizeof(struct raw1394_request);
+      out:
+	free_pending_request(req);
+	return ret;
+}
 
 static int state_opened(struct file_info *fi, struct pending_request *req)
 {
-        if (req->req.type == RAW1394_REQ_INITIALIZE) {
-                switch (req->req.misc) {
-                case RAW1394_KERNELAPI_VERSION:
-                case 3:
-                        fi->state = initialized;
-                        fi->protocol_version = req->req.misc;
-                        req->req.error = RAW1394_ERROR_NONE;
-                        req->req.generation = atomic_read(&internal_generation);
-                        break;
-
-                default:
-                        req->req.error = RAW1394_ERROR_COMPAT;
-                        req->req.misc = RAW1394_KERNELAPI_VERSION;
-                }
-        } else {
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        req->req.length = 0;
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
+	if (req->req.type == RAW1394_REQ_INITIALIZE) {
+		switch (req->req.misc) {
+		case RAW1394_KERNELAPI_VERSION:
+		case 3:
+			fi->state = initialized;
+			fi->protocol_version = req->req.misc;
+			req->req.error = RAW1394_ERROR_NONE;
+			req->req.generation = atomic_read(&internal_generation);
+			break;
+
+		default:
+			req->req.error = RAW1394_ERROR_COMPAT;
+			req->req.misc = RAW1394_KERNELAPI_VERSION;
+		}
+	} else {
+		req->req.error = RAW1394_ERROR_STATE_ORDER;
+	}
+
+	req->req.length = 0;
+	queue_complete_req(req);
+	return sizeof(struct raw1394_request);
 }
 
 static int state_initialized(struct file_info *fi, struct pending_request *req)
 {
-        struct host_info *hi;
-        struct raw1394_khost_list *khl;
+	struct host_info *hi;
+	struct raw1394_khost_list *khl;
+
+	if (req->req.generation != atomic_read(&internal_generation)) {
+		req->req.error = RAW1394_ERROR_GENERATION;
+		req->req.generation = atomic_read(&internal_generation);
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	switch (req->req.type) {
+	case RAW1394_REQ_LIST_CARDS:
+		spin_lock_irq(&host_info_lock);
+		khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count,
+			      SLAB_ATOMIC);
+
+		if (khl != NULL) {
+			req->req.misc = host_count;
+			req->data = (quadlet_t *) khl;
 
-        if (req->req.generation != atomic_read(&internal_generation)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = atomic_read(&internal_generation);
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        switch (req->req.type) {
-        case RAW1394_REQ_LIST_CARDS:
-                spin_lock_irq(&host_info_lock);
-                khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count,
-                              SLAB_ATOMIC);
-
-                if (khl != NULL) {
-                        req->req.misc = host_count;
-                        req->data = (quadlet_t *)khl;
-
-                        list_for_each_entry(hi, &host_info_list, list) {
-                                khl->nodes = hi->host->node_count;
-                                strcpy(khl->name, hi->host->driver->name);
-                                khl++;
-                        }
-                }
-                spin_unlock_irq(&host_info_lock);
-
-                if (khl != NULL) {
-                        req->req.error = RAW1394_ERROR_NONE;
-                        req->req.length = min(req->req.length,
-                                              (u32)(sizeof(struct raw1394_khost_list)
-                                              * req->req.misc));
-                        req->free_data = 1;
-                } else {
-                        return -ENOMEM;
-                }
-                break;
-
-        case RAW1394_REQ_SET_CARD:
-                spin_lock_irq(&host_info_lock);
-                if (req->req.misc < host_count) {
+			list_for_each_entry(hi, &host_info_list, list) {
+				khl->nodes = hi->host->node_count;
+				strcpy(khl->name, hi->host->driver->name);
+				khl++;
+			}
+		}
+		spin_unlock_irq(&host_info_lock);
+
+		if (khl != NULL) {
+			req->req.error = RAW1394_ERROR_NONE;
+			req->req.length = min(req->req.length,
+					      (u32) (sizeof
+						     (struct raw1394_khost_list)
+						     * req->req.misc));
+			req->free_data = 1;
+		} else {
+			return -ENOMEM;
+		}
+		break;
+
+	case RAW1394_REQ_SET_CARD:
+		spin_lock_irq(&host_info_lock);
+		if (req->req.misc < host_count) {
 			list_for_each_entry(hi, &host_info_list, list) {
 				if (!req->req.misc--)
 					break;
 			}
-			get_device(&hi->host->device); // XXX Need to handle failure case
-                        list_add_tail(&fi->list, &hi->file_info_list);
-                        fi->host = hi->host;
-                        fi->state = connected;
-
-                        req->req.error = RAW1394_ERROR_NONE;
-                        req->req.generation = get_hpsb_generation(fi->host);
-                        req->req.misc = (fi->host->node_id << 16)
-                                | fi->host->node_count;
-                        if (fi->protocol_version > 3) {
-                                req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
-                        }
-                } else {
-                        req->req.error = RAW1394_ERROR_INVALID_ARG;
-                }
+			get_device(&hi->host->device);	// XXX Need to handle failure case
+			list_add_tail(&fi->list, &hi->file_info_list);
+			fi->host = hi->host;
+			fi->state = connected;
+
+			req->req.error = RAW1394_ERROR_NONE;
+			req->req.generation = get_hpsb_generation(fi->host);
+			req->req.misc = (fi->host->node_id << 16)
+			    | fi->host->node_count;
+			if (fi->protocol_version > 3) {
+				req->req.misc |=
+				    NODEID_TO_NODE(fi->host->irm_id) << 8;
+			}
+		} else {
+			req->req.error = RAW1394_ERROR_INVALID_ARG;
+		}
 		spin_unlock_irq(&host_info_lock);
 
-                req->req.length = 0;
-                break;
+		req->req.length = 0;
+		break;
 
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-                req->req.length = 0;
-                break;
-        }
+	default:
+		req->req.error = RAW1394_ERROR_STATE_ORDER;
+		req->req.length = 0;
+		break;
+	}
 
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
+	queue_complete_req(req);
+	return sizeof(struct raw1394_request);
 }
 
 static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
 {
-        int channel = req->req.misc;
+	int channel = req->req.misc;
 
-        spin_lock_irq(&host_info_lock);
-        if ((channel > 63) || (channel < -64)) {
-                req->req.error = RAW1394_ERROR_INVALID_ARG;
-        } else if (channel >= 0) {
-                /* allocate channel req.misc */
-                if (fi->listen_channels & (1ULL << channel)) {
-                        req->req.error = RAW1394_ERROR_ALREADY;
-                } else {
-                        if (hpsb_listen_channel(&raw1394_highlevel, fi->host, channel)) {
+	spin_lock_irq(&host_info_lock);
+	if ((channel > 63) || (channel < -64)) {
+		req->req.error = RAW1394_ERROR_INVALID_ARG;
+	} else if (channel >= 0) {
+		/* allocate channel req.misc */
+		if (fi->listen_channels & (1ULL << channel)) {
+			req->req.error = RAW1394_ERROR_ALREADY;
+		} else {
+			if (hpsb_listen_channel
+			    (&raw1394_highlevel, fi->host, channel)) {
 				req->req.error = RAW1394_ERROR_ALREADY;
 			} else {
 				fi->listen_channels |= 1ULL << channel;
 				fi->iso_buffer = int2ptr(req->req.recvb);
 				fi->iso_buffer_length = req->req.length;
 			}
-                }
-        } else {
-                /* deallocate channel (one's complement neg) req.misc */
-                channel = ~channel;
-
-                if (fi->listen_channels & (1ULL << channel)) {
-                        hpsb_unlisten_channel(&raw1394_highlevel, fi->host, channel);
-                        fi->listen_channels &= ~(1ULL << channel);
-                } else {
-                        req->req.error = RAW1394_ERROR_INVALID_ARG;
-                }
-        }
-
-        req->req.length = 0;
-        queue_complete_req(req);
-        spin_unlock_irq(&host_info_lock);
+		}
+	} else {
+		/* deallocate channel (one's complement neg) req.misc */
+		channel = ~channel;
+
+		if (fi->listen_channels & (1ULL << channel)) {
+			hpsb_unlisten_channel(&raw1394_highlevel, fi->host,
+					      channel);
+			fi->listen_channels &= ~(1ULL << channel);
+		} else {
+			req->req.error = RAW1394_ERROR_INVALID_ARG;
+		}
+	}
+
+	req->req.length = 0;
+	queue_complete_req(req);
+	spin_unlock_irq(&host_info_lock);
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
 {
-        if (req->req.misc) {
-                if (fi->fcp_buffer) {
-                        req->req.error = RAW1394_ERROR_ALREADY;
-                } else {
-                        fi->fcp_buffer = int2ptr(req->req.recvb);
-                }
-        } else {
-                if (!fi->fcp_buffer) {
-                        req->req.error = RAW1394_ERROR_ALREADY;
-                } else {
-                        fi->fcp_buffer = NULL;
-                }
-        }
+	if (req->req.misc) {
+		if (fi->fcp_buffer) {
+			req->req.error = RAW1394_ERROR_ALREADY;
+		} else {
+			fi->fcp_buffer = int2ptr(req->req.recvb);
+		}
+	} else {
+		if (!fi->fcp_buffer) {
+			req->req.error = RAW1394_ERROR_ALREADY;
+		} else {
+			fi->fcp_buffer = NULL;
+		}
+	}
 
-        req->req.length = 0;
-        queue_complete_req(req);
+	req->req.length = 0;
+	queue_complete_req(req);
 }
 
-
 static int handle_async_request(struct file_info *fi,
-                                struct pending_request *req, int node)
+				struct pending_request *req, int node)
 {
-        struct hpsb_packet *packet = NULL;
-        u64 addr = req->req.address & 0xffffffffffffULL;
+	struct hpsb_packet *packet = NULL;
+	u64 addr = req->req.address & 0xffffffffffffULL;
 
-        switch (req->req.type) {
-        case RAW1394_REQ_ASYNC_READ:
+	switch (req->req.type) {
+	case RAW1394_REQ_ASYNC_READ:
 		DBGMSG("read_request called");
-		packet = hpsb_make_readpacket(fi->host, node, addr, req->req.length);
+		packet =
+		    hpsb_make_readpacket(fi->host, node, addr, req->req.length);
 
 		if (!packet)
 			return -ENOMEM;
@@ -631,7 +644,7 @@ static int handle_async_request(struct f
 		else
 			req->data = packet->data;
 
-                break;
+		break;
 
 	case RAW1394_REQ_ASYNC_WRITE:
 		DBGMSG("write_request called");
@@ -642,1105 +655,1207 @@ static int handle_async_request(struct f
 			return -ENOMEM;
 
 		if (req->req.length == 4) {
-			if (copy_from_user(&packet->header[3], int2ptr(req->req.sendb),
-					req->req.length))
+			if (copy_from_user
+			    (&packet->header[3], int2ptr(req->req.sendb),
+			     req->req.length))
 				req->req.error = RAW1394_ERROR_MEMFAULT;
 		} else {
-			if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-					req->req.length))
+			if (copy_from_user
+			    (packet->data, int2ptr(req->req.sendb),
+			     req->req.length))
 				req->req.error = RAW1394_ERROR_MEMFAULT;
 		}
 
 		req->req.length = 0;
-	    break;
+		break;
 
 	case RAW1394_REQ_ASYNC_STREAM:
 		DBGMSG("stream_request called");
 
-		packet = hpsb_make_streampacket(fi->host, NULL, req->req.length, node & 0x3f/*channel*/,
-                                        (req->req.misc >> 16) & 0x3, req->req.misc & 0xf);
+		packet =
+		    hpsb_make_streampacket(fi->host, NULL, req->req.length,
+					   node & 0x3f /*channel */ ,
+					   (req->req.misc >> 16) & 0x3,
+					   req->req.misc & 0xf);
 		if (!packet)
 			return -ENOMEM;
 
 		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-		                   req->req.length))
+				   req->req.length))
 			req->req.error = RAW1394_ERROR_MEMFAULT;
 
 		req->req.length = 0;
 		break;
 
-        case RAW1394_REQ_LOCK:
-                DBGMSG("lock_request called");
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 4) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-
-                packet = hpsb_make_lockpacket(fi->host, node, addr,
-                                              req->req.misc, NULL, 0);
-                if (!packet) return -ENOMEM;
-
-                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->data = packet->data;
-                req->req.length = 4;
-                break;
-
-        case RAW1394_REQ_LOCK64:
-                DBGMSG("lock64_request called");
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 16) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-                packet = hpsb_make_lock64packet(fi->host, node, addr,
-                                                req->req.misc, NULL, 0);
-                if (!packet) return -ENOMEM;
-
-                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->data = packet->data;
-                req->req.length = 8;
-                break;
-
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        req->packet = packet;
-
-        if (req->req.error) {
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-	hpsb_set_packet_complete_task(packet, (void(*)(void*))queue_complete_cb, req);
-
-        spin_lock_irq(&fi->reqlists_lock);
-        list_add_tail(&req->list, &fi->req_pending);
-        spin_unlock_irq(&fi->reqlists_lock);
+	case RAW1394_REQ_LOCK:
+		DBGMSG("lock_request called");
+		if ((req->req.misc == EXTCODE_FETCH_ADD)
+		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+			if (req->req.length != 4) {
+				req->req.error = RAW1394_ERROR_INVALID_ARG;
+				break;
+			}
+		} else {
+			if (req->req.length != 8) {
+				req->req.error = RAW1394_ERROR_INVALID_ARG;
+				break;
+			}
+		}
+
+		packet = hpsb_make_lockpacket(fi->host, node, addr,
+					      req->req.misc, NULL, 0);
+		if (!packet)
+			return -ENOMEM;
+
+		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+				   req->req.length)) {
+			req->req.error = RAW1394_ERROR_MEMFAULT;
+			break;
+		}
+
+		req->data = packet->data;
+		req->req.length = 4;
+		break;
+
+	case RAW1394_REQ_LOCK64:
+		DBGMSG("lock64_request called");
+		if ((req->req.misc == EXTCODE_FETCH_ADD)
+		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+			if (req->req.length != 8) {
+				req->req.error = RAW1394_ERROR_INVALID_ARG;
+				break;
+			}
+		} else {
+			if (req->req.length != 16) {
+				req->req.error = RAW1394_ERROR_INVALID_ARG;
+				break;
+			}
+		}
+		packet = hpsb_make_lock64packet(fi->host, node, addr,
+						req->req.misc, NULL, 0);
+		if (!packet)
+			return -ENOMEM;
+
+		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+				   req->req.length)) {
+			req->req.error = RAW1394_ERROR_MEMFAULT;
+			break;
+		}
+
+		req->data = packet->data;
+		req->req.length = 8;
+		break;
+
+	default:
+		req->req.error = RAW1394_ERROR_STATE_ORDER;
+	}
+
+	req->packet = packet;
+
+	if (req->req.error) {
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	hpsb_set_packet_complete_task(packet,
+				      (void (*)(void *))queue_complete_cb, req);
+
+	spin_lock_irq(&fi->reqlists_lock);
+	list_add_tail(&req->list, &fi->req_pending);
+	spin_unlock_irq(&fi->reqlists_lock);
 
 	packet->generation = req->req.generation;
 
-        if (hpsb_send_packet(packet) < 0) {
-                req->req.error = RAW1394_ERROR_SEND_ERROR;
-                req->req.length = 0;
-                hpsb_free_tlabel(packet);
-                queue_complete_req(req);
-        }
-        return sizeof(struct raw1394_request);
+	if (hpsb_send_packet(packet) < 0) {
+		req->req.error = RAW1394_ERROR_SEND_ERROR;
+		req->req.length = 0;
+		hpsb_free_tlabel(packet);
+		queue_complete_req(req);
+	}
+	return sizeof(struct raw1394_request);
 }
 
 static int handle_iso_send(struct file_info *fi, struct pending_request *req,
-                           int channel)
+			   int channel)
 {
-        struct hpsb_packet *packet;
+	struct hpsb_packet *packet;
 
 	packet = hpsb_make_isopacket(fi->host, req->req.length, channel & 0x3f,
-				     (req->req.misc >> 16) & 0x3, req->req.misc & 0xf);
+				     (req->req.misc >> 16) & 0x3,
+				     req->req.misc & 0xf);
 	if (!packet)
 		return -ENOMEM;
 
-        packet->speed_code = req->req.address & 0x3;
+	packet->speed_code = req->req.address & 0x3;
 
 	req->packet = packet;
 
-        if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                           req->req.length)) {
-                req->req.error = RAW1394_ERROR_MEMFAULT;
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        req->req.length = 0;
-	hpsb_set_packet_complete_task(packet, (void (*)(void*))queue_complete_req, req);
-
-        spin_lock_irq(&fi->reqlists_lock);
-        list_add_tail(&req->list, &fi->req_pending);
-        spin_unlock_irq(&fi->reqlists_lock);
+	if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+			   req->req.length)) {
+		req->req.error = RAW1394_ERROR_MEMFAULT;
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	req->req.length = 0;
+	hpsb_set_packet_complete_task(packet,
+				      (void (*)(void *))queue_complete_req,
+				      req);
+
+	spin_lock_irq(&fi->reqlists_lock);
+	list_add_tail(&req->list, &fi->req_pending);
+	spin_unlock_irq(&fi->reqlists_lock);
 
 	/* Update the generation of the packet just before sending. */
 	packet->generation = req->req.generation;
 
-        if (hpsb_send_packet(packet) < 0) {
-                req->req.error = RAW1394_ERROR_SEND_ERROR;
-                queue_complete_req(req);
-        }
+	if (hpsb_send_packet(packet) < 0) {
+		req->req.error = RAW1394_ERROR_SEND_ERROR;
+		queue_complete_req(req);
+	}
+
+	return sizeof(struct raw1394_request);
+}
+
+static int handle_async_send(struct file_info *fi, struct pending_request *req)
+{
+	struct hpsb_packet *packet;
+	int header_length = req->req.misc & 0xffff;
+	int expect_response = req->req.misc >> 16;
+
+	if ((header_length > req->req.length) || (header_length < 12)) {
+		req->req.error = RAW1394_ERROR_INVALID_ARG;
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	packet = hpsb_alloc_packet(req->req.length - header_length);
+	req->packet = packet;
+	if (!packet)
+		return -ENOMEM;
+
+	if (copy_from_user(packet->header, int2ptr(req->req.sendb),
+			   header_length)) {
+		req->req.error = RAW1394_ERROR_MEMFAULT;
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	if (copy_from_user
+	    (packet->data, int2ptr(req->req.sendb) + header_length,
+	     packet->data_size)) {
+		req->req.error = RAW1394_ERROR_MEMFAULT;
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	packet->type = hpsb_async;
+	packet->node_id = packet->header[0] >> 16;
+	packet->tcode = (packet->header[0] >> 4) & 0xf;
+	packet->tlabel = (packet->header[0] >> 10) & 0x3f;
+	packet->host = fi->host;
+	packet->expect_response = expect_response;
+	packet->header_size = header_length;
+	packet->data_size = req->req.length - header_length;
+
+	req->req.length = 0;
+	hpsb_set_packet_complete_task(packet,
+				      (void (*)(void *))queue_complete_cb, req);
+
+	spin_lock_irq(&fi->reqlists_lock);
+	list_add_tail(&req->list, &fi->req_pending);
+	spin_unlock_irq(&fi->reqlists_lock);
+
+	/* Update the generation of the packet just before sending. */
+	packet->generation = req->req.generation;
+
+	if (hpsb_send_packet(packet) < 0) {
+		req->req.error = RAW1394_ERROR_SEND_ERROR;
+		queue_complete_req(req);
+	}
+
+	return sizeof(struct raw1394_request);
+}
+
+static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
+		    u64 addr, size_t length, u16 flags)
+{
+	struct pending_request *req;
+	struct host_info *hi;
+	struct file_info *fi = NULL;
+	struct list_head *entry;
+	struct arm_addr *arm_addr = NULL;
+	struct arm_request *arm_req = NULL;
+	struct arm_response *arm_resp = NULL;
+	int found = 0, size = 0, rcode = -1;
+	struct arm_request_response *arm_req_resp = NULL;
+
+	DBGMSG("arm_read  called by node: %X"
+	       "addr: %4.4x %8.8x length: %Zu", nodeid,
+	       (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+	       length);
+	spin_lock(&host_info_lock);
+	hi = find_host_info(host);	/* search address-entry */
+	if (hi != NULL) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+			entry = fi->addr_list.next;
+			while (entry != &(fi->addr_list)) {
+				arm_addr =
+				    list_entry(entry, struct arm_addr,
+					       addr_list);
+				if (((arm_addr->start) <= (addr))
+				    && ((arm_addr->end) >= (addr + length))) {
+					found = 1;
+					break;
+				}
+				entry = entry->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+	}
+	rcode = -1;
+	if (!found) {
+		printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
+		       " -> rcode_address_error\n");
+		spin_unlock(&host_info_lock);
+		return (RCODE_ADDRESS_ERROR);
+	} else {
+		DBGMSG("arm_read addr_entry FOUND");
+	}
+	if (arm_addr->rec_length < length) {
+		DBGMSG("arm_read blocklength too big -> rcode_data_error");
+		rcode = RCODE_DATA_ERROR;	/* hardware error, data is unavailable */
+	}
+	if (rcode == -1) {
+		if (arm_addr->access_rights & ARM_READ) {
+			if (!(arm_addr->client_transactions & ARM_READ)) {
+				memcpy(buffer,
+				       (arm_addr->addr_space_buffer) + (addr -
+									(arm_addr->
+									 start)),
+				       length);
+				DBGMSG("arm_read -> (rcode_complete)");
+				rcode = RCODE_COMPLETE;
+			}
+		} else {
+			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+			DBGMSG("arm_read -> rcode_type_error (access denied)");
+		}
+	}
+	if (arm_addr->notification_options & ARM_READ) {
+		DBGMSG("arm_read -> entering notification-section");
+		req = __alloc_pending_request(SLAB_ATOMIC);
+		if (!req) {
+			DBGMSG("arm_read -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		if (rcode == RCODE_COMPLETE) {
+			size =
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response) +
+			    length * sizeof(byte_t) +
+			    sizeof(struct arm_request_response);
+		} else {
+			size =
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response) +
+			    sizeof(struct arm_request_response);
+		}
+		req->data = kmalloc(size, SLAB_ATOMIC);
+		if (!(req->data)) {
+			free_pending_request(req);
+			DBGMSG("arm_read -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		req->free_data = 1;
+		req->file_info = fi;
+		req->req.type = RAW1394_REQ_ARM;
+		req->req.generation = get_hpsb_generation(host);
+		req->req.misc =
+		    (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
+		req->req.tag = arm_addr->arm_tag;
+		req->req.recvb = arm_addr->recvb;
+		req->req.length = size;
+		arm_req_resp = (struct arm_request_response *)(req->data);
+		arm_req = (struct arm_request *)((byte_t *) (req->data) +
+						 (sizeof
+						  (struct
+						   arm_request_response)));
+		arm_resp =
+		    (struct arm_response *)((byte_t *) (arm_req) +
+					    (sizeof(struct arm_request)));
+		arm_req->buffer = NULL;
+		arm_resp->buffer = NULL;
+		if (rcode == RCODE_COMPLETE) {
+			byte_t *buf =
+			    (byte_t *) arm_resp + sizeof(struct arm_response);
+			memcpy(buf,
+			       (arm_addr->addr_space_buffer) + (addr -
+								(arm_addr->
+								 start)),
+			       length);
+			arm_resp->buffer =
+			    int2ptr((arm_addr->recvb) +
+				    sizeof(struct arm_request_response) +
+				    sizeof(struct arm_request) +
+				    sizeof(struct arm_response));
+		}
+		arm_resp->buffer_length =
+		    (rcode == RCODE_COMPLETE) ? length : 0;
+		arm_resp->response_code = rcode;
+		arm_req->buffer_length = 0;
+		arm_req->generation = req->req.generation;
+		arm_req->extended_transaction_code = 0;
+		arm_req->destination_offset = addr;
+		arm_req->source_nodeid = nodeid;
+		arm_req->destination_nodeid = host->node_id;
+		arm_req->tlabel = (flags >> 10) & 0x3f;
+		arm_req->tcode = (flags >> 4) & 0x0f;
+		arm_req_resp->request = int2ptr((arm_addr->recvb) +
+						sizeof(struct
+						       arm_request_response));
+		arm_req_resp->response =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request));
+		queue_complete_req(req);
+	}
+	spin_unlock(&host_info_lock);
+	return (rcode);
+}
+
+static int arm_write(struct hpsb_host *host, int nodeid, int destid,
+		     quadlet_t * data, u64 addr, size_t length, u16 flags)
+{
+	struct pending_request *req;
+	struct host_info *hi;
+	struct file_info *fi = NULL;
+	struct list_head *entry;
+	struct arm_addr *arm_addr = NULL;
+	struct arm_request *arm_req = NULL;
+	struct arm_response *arm_resp = NULL;
+	int found = 0, size = 0, rcode = -1, length_conflict = 0;
+	struct arm_request_response *arm_req_resp = NULL;
+
+	DBGMSG("arm_write called by node: %X"
+	       "addr: %4.4x %8.8x length: %Zu", nodeid,
+	       (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+	       length);
+	spin_lock(&host_info_lock);
+	hi = find_host_info(host);	/* search address-entry */
+	if (hi != NULL) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+			entry = fi->addr_list.next;
+			while (entry != &(fi->addr_list)) {
+				arm_addr =
+				    list_entry(entry, struct arm_addr,
+					       addr_list);
+				if (((arm_addr->start) <= (addr))
+				    && ((arm_addr->end) >= (addr + length))) {
+					found = 1;
+					break;
+				}
+				entry = entry->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+	}
+	rcode = -1;
+	if (!found) {
+		printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
+		       " -> rcode_address_error\n");
+		spin_unlock(&host_info_lock);
+		return (RCODE_ADDRESS_ERROR);
+	} else {
+		DBGMSG("arm_write addr_entry FOUND");
+	}
+	if (arm_addr->rec_length < length) {
+		DBGMSG("arm_write blocklength too big -> rcode_data_error");
+		length_conflict = 1;
+		rcode = RCODE_DATA_ERROR;	/* hardware error, data is unavailable */
+	}
+	if (rcode == -1) {
+		if (arm_addr->access_rights & ARM_WRITE) {
+			if (!(arm_addr->client_transactions & ARM_WRITE)) {
+				memcpy((arm_addr->addr_space_buffer) +
+				       (addr - (arm_addr->start)), data,
+				       length);
+				DBGMSG("arm_write -> (rcode_complete)");
+				rcode = RCODE_COMPLETE;
+			}
+		} else {
+			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+			DBGMSG("arm_write -> rcode_type_error (access denied)");
+		}
+	}
+	if (arm_addr->notification_options & ARM_WRITE) {
+		DBGMSG("arm_write -> entering notification-section");
+		req = __alloc_pending_request(SLAB_ATOMIC);
+		if (!req) {
+			DBGMSG("arm_write -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request my be retried */
+		}
+		size =
+		    sizeof(struct arm_request) + sizeof(struct arm_response) +
+		    (length) * sizeof(byte_t) +
+		    sizeof(struct arm_request_response);
+		req->data = kmalloc(size, SLAB_ATOMIC);
+		if (!(req->data)) {
+			free_pending_request(req);
+			DBGMSG("arm_write -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		req->free_data = 1;
+		req->file_info = fi;
+		req->req.type = RAW1394_REQ_ARM;
+		req->req.generation = get_hpsb_generation(host);
+		req->req.misc =
+		    (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
+		req->req.tag = arm_addr->arm_tag;
+		req->req.recvb = arm_addr->recvb;
+		req->req.length = size;
+		arm_req_resp = (struct arm_request_response *)(req->data);
+		arm_req = (struct arm_request *)((byte_t *) (req->data) +
+						 (sizeof
+						  (struct
+						   arm_request_response)));
+		arm_resp =
+		    (struct arm_response *)((byte_t *) (arm_req) +
+					    (sizeof(struct arm_request)));
+		arm_resp->buffer = NULL;
+		memcpy((byte_t *) arm_resp + sizeof(struct arm_response),
+		       data, length);
+		arm_req->buffer = int2ptr((arm_addr->recvb) +
+					  sizeof(struct arm_request_response) +
+					  sizeof(struct arm_request) +
+					  sizeof(struct arm_response));
+		arm_req->buffer_length = length;
+		arm_req->generation = req->req.generation;
+		arm_req->extended_transaction_code = 0;
+		arm_req->destination_offset = addr;
+		arm_req->source_nodeid = nodeid;
+		arm_req->destination_nodeid = destid;
+		arm_req->tlabel = (flags >> 10) & 0x3f;
+		arm_req->tcode = (flags >> 4) & 0x0f;
+		arm_resp->buffer_length = 0;
+		arm_resp->response_code = rcode;
+		arm_req_resp->request = int2ptr((arm_addr->recvb) +
+						sizeof(struct
+						       arm_request_response));
+		arm_req_resp->response =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request));
+		queue_complete_req(req);
+	}
+	spin_unlock(&host_info_lock);
+	return (rcode);
+}
+
+static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
+		    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
+		    u16 flags)
+{
+	struct pending_request *req;
+	struct host_info *hi;
+	struct file_info *fi = NULL;
+	struct list_head *entry;
+	struct arm_addr *arm_addr = NULL;
+	struct arm_request *arm_req = NULL;
+	struct arm_response *arm_resp = NULL;
+	int found = 0, size = 0, rcode = -1;
+	quadlet_t old, new;
+	struct arm_request_response *arm_req_resp = NULL;
+
+	if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+	    ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+		DBGMSG("arm_lock  called by node: %X "
+		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
+		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
+		       (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
+		       be32_to_cpu(data));
+	} else {
+		DBGMSG("arm_lock  called by node: %X "
+		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
+		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
+		       (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
+		       be32_to_cpu(data), be32_to_cpu(arg));
+	}
+	spin_lock(&host_info_lock);
+	hi = find_host_info(host);	/* search address-entry */
+	if (hi != NULL) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+			entry = fi->addr_list.next;
+			while (entry != &(fi->addr_list)) {
+				arm_addr =
+				    list_entry(entry, struct arm_addr,
+					       addr_list);
+				if (((arm_addr->start) <= (addr))
+				    && ((arm_addr->end) >=
+					(addr + sizeof(*store)))) {
+					found = 1;
+					break;
+				}
+				entry = entry->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+	}
+	rcode = -1;
+	if (!found) {
+		printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
+		       " -> rcode_address_error\n");
+		spin_unlock(&host_info_lock);
+		return (RCODE_ADDRESS_ERROR);
+	} else {
+		DBGMSG("arm_lock addr_entry FOUND");
+	}
+	if (rcode == -1) {
+		if (arm_addr->access_rights & ARM_LOCK) {
+			if (!(arm_addr->client_transactions & ARM_LOCK)) {
+				memcpy(&old,
+				       (arm_addr->addr_space_buffer) + (addr -
+									(arm_addr->
+									 start)),
+				       sizeof(old));
+				switch (ext_tcode) {
+				case (EXTCODE_MASK_SWAP):
+					new = data | (old & ~arg);
+					break;
+				case (EXTCODE_COMPARE_SWAP):
+					if (old == arg) {
+						new = data;
+					} else {
+						new = old;
+					}
+					break;
+				case (EXTCODE_FETCH_ADD):
+					new =
+					    cpu_to_be32(be32_to_cpu(data) +
+							be32_to_cpu(old));
+					break;
+				case (EXTCODE_LITTLE_ADD):
+					new =
+					    cpu_to_le32(le32_to_cpu(data) +
+							le32_to_cpu(old));
+					break;
+				case (EXTCODE_BOUNDED_ADD):
+					if (old != arg) {
+						new =
+						    cpu_to_be32(be32_to_cpu
+								(data) +
+								be32_to_cpu
+								(old));
+					} else {
+						new = old;
+					}
+					break;
+				case (EXTCODE_WRAP_ADD):
+					if (old != arg) {
+						new =
+						    cpu_to_be32(be32_to_cpu
+								(data) +
+								be32_to_cpu
+								(old));
+					} else {
+						new = data;
+					}
+					break;
+				default:
+					rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+					printk(KERN_ERR
+					       "raw1394: arm_lock FAILED "
+					       "ext_tcode not allowed -> rcode_type_error\n");
+					break;
+				}	/*switch */
+				if (rcode == -1) {
+					DBGMSG("arm_lock -> (rcode_complete)");
+					rcode = RCODE_COMPLETE;
+					memcpy(store, &old, sizeof(*store));
+					memcpy((arm_addr->addr_space_buffer) +
+					       (addr - (arm_addr->start)),
+					       &new, sizeof(*store));
+				}
+			}
+		} else {
+			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+			DBGMSG("arm_lock -> rcode_type_error (access denied)");
+		}
+	}
+	if (arm_addr->notification_options & ARM_LOCK) {
+		byte_t *buf1, *buf2;
+		DBGMSG("arm_lock -> entering notification-section");
+		req = __alloc_pending_request(SLAB_ATOMIC);
+		if (!req) {
+			DBGMSG("arm_lock -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);	/* maximum */
+		req->data = kmalloc(size, SLAB_ATOMIC);
+		if (!(req->data)) {
+			free_pending_request(req);
+			DBGMSG("arm_lock -> rcode_conflict_error");
+			spin_unlock(&host_info_lock);
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		req->free_data = 1;
+		arm_req_resp = (struct arm_request_response *)(req->data);
+		arm_req = (struct arm_request *)((byte_t *) (req->data) +
+						 (sizeof
+						  (struct
+						   arm_request_response)));
+		arm_resp =
+		    (struct arm_response *)((byte_t *) (arm_req) +
+					    (sizeof(struct arm_request)));
+		buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
+		buf2 = buf1 + 2 * sizeof(*store);
+		if ((ext_tcode == EXTCODE_FETCH_ADD) ||
+		    (ext_tcode == EXTCODE_LITTLE_ADD)) {
+			arm_req->buffer_length = sizeof(*store);
+			memcpy(buf1, &data, sizeof(*store));
 
-        return sizeof(struct raw1394_request);
+		} else {
+			arm_req->buffer_length = 2 * sizeof(*store);
+			memcpy(buf1, &arg, sizeof(*store));
+			memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
+		}
+		if (rcode == RCODE_COMPLETE) {
+			arm_resp->buffer_length = sizeof(*store);
+			memcpy(buf2, &old, sizeof(*store));
+		} else {
+			arm_resp->buffer_length = 0;
+		}
+		req->file_info = fi;
+		req->req.type = RAW1394_REQ_ARM;
+		req->req.generation = get_hpsb_generation(host);
+		req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
+				 (ARM_LOCK & 0xFF));
+		req->req.tag = arm_addr->arm_tag;
+		req->req.recvb = arm_addr->recvb;
+		req->req.length = size;
+		arm_req->generation = req->req.generation;
+		arm_req->extended_transaction_code = ext_tcode;
+		arm_req->destination_offset = addr;
+		arm_req->source_nodeid = nodeid;
+		arm_req->destination_nodeid = host->node_id;
+		arm_req->tlabel = (flags >> 10) & 0x3f;
+		arm_req->tcode = (flags >> 4) & 0x0f;
+		arm_resp->response_code = rcode;
+		arm_req_resp->request = int2ptr((arm_addr->recvb) +
+						sizeof(struct
+						       arm_request_response));
+		arm_req_resp->response =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request));
+		arm_req->buffer =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response));
+		arm_resp->buffer =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response) + 2 * sizeof(*store));
+		queue_complete_req(req);
+	}
+	spin_unlock(&host_info_lock);
+	return (rcode);
 }
 
-static int handle_async_send(struct file_info *fi, struct pending_request *req)
+static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
+		      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
+		      u16 flags)
 {
-        struct hpsb_packet *packet;
-        int header_length = req->req.misc & 0xffff;
-        int expect_response = req->req.misc >> 16;
-
-        if ((header_length > req->req.length) ||
-            (header_length  < 12)) {
-                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        packet = hpsb_alloc_packet(req->req.length-header_length);
-        req->packet = packet;
-        if (!packet) return -ENOMEM;
-
-        if (copy_from_user(packet->header, int2ptr(req->req.sendb),
-                           header_length)) {
-                req->req.error = RAW1394_ERROR_MEMFAULT;
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        if (copy_from_user(packet->data, int2ptr(req->req.sendb) + header_length,
-                           packet->data_size)) {
-                req->req.error = RAW1394_ERROR_MEMFAULT;
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        packet->type = hpsb_async;
-        packet->node_id = packet->header[0] >> 16;
-        packet->tcode = (packet->header[0] >> 4) & 0xf;
-        packet->tlabel = (packet->header[0] >> 10) &0x3f;
-        packet->host = fi->host;
-        packet->expect_response = expect_response;
-        packet->header_size=header_length;
-        packet->data_size=req->req.length-header_length;
-
-        req->req.length = 0;
-        hpsb_set_packet_complete_task(packet, (void(*)(void*))queue_complete_cb, req);
-
-        spin_lock_irq(&fi->reqlists_lock);
-        list_add_tail(&req->list, &fi->req_pending);
-        spin_unlock_irq(&fi->reqlists_lock);
-
-        /* Update the generation of the packet just before sending. */
-        packet->generation = req->req.generation;
-
-        if (hpsb_send_packet(packet) < 0) {
-                req->req.error = RAW1394_ERROR_SEND_ERROR;
-                queue_complete_req(req);
-        }
-
-        return sizeof(struct raw1394_request);
-}
-
-static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-		     u64 addr, size_t length, u16 flags)
-{
-        struct pending_request *req;
-        struct host_info *hi;
-        struct file_info *fi = NULL;
-        struct list_head *entry;
-        struct arm_addr  *arm_addr = NULL;
-        struct arm_request  *arm_req = NULL;
-        struct arm_response *arm_resp = NULL;
-        int found=0, size=0, rcode=-1;
-        struct arm_request_response *arm_req_resp = NULL;
-
-        DBGMSG("arm_read  called by node: %X"
-              "addr: %4.4x %8.8x length: %Zu", nodeid,
-              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-              length);
-        spin_lock(&host_info_lock);
-        hi = find_host_info(host); /* search address-entry */
-        if (hi != NULL) {
-                list_for_each_entry(fi, &hi->file_info_list, list) {
-                        entry = fi->addr_list.next;
-                        while (entry != &(fi->addr_list)) {
-                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                                if (((arm_addr->start) <= (addr)) &&
-                                        ((arm_addr->end) >= (addr+length))) {
-                                        found = 1;
-                                        break;
-                                }
-                                entry = entry->next;
-                        }
-                        if (found) {
-                                break;
-                        }
-                }
-        }
-        rcode = -1;
-        if (!found) {
-                printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
-                " -> rcode_address_error\n");
-                spin_unlock(&host_info_lock);
-                return (RCODE_ADDRESS_ERROR);
-        } else {
-                DBGMSG("arm_read addr_entry FOUND");
-        }
-        if (arm_addr->rec_length < length) {
-                DBGMSG("arm_read blocklength too big -> rcode_data_error");
-                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
-        }
-        if (rcode == -1) {
-                if (arm_addr->access_rights & ARM_READ) {
-                        if (!(arm_addr->client_transactions & ARM_READ)) {
-                                memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
-                                       length);
-                                DBGMSG("arm_read -> (rcode_complete)");
-                                rcode = RCODE_COMPLETE;
-                        }
-                } else {
-                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                        DBGMSG("arm_read -> rcode_type_error (access denied)");
-                }
-        }
-        if (arm_addr->notification_options & ARM_READ) {
-                DBGMSG("arm_read -> entering notification-section");
-                req = __alloc_pending_request(SLAB_ATOMIC);
-                if (!req) {
-                        DBGMSG("arm_read -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                if (rcode == RCODE_COMPLETE) {
-                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
-                                length * sizeof(byte_t) +
-                                sizeof (struct arm_request_response);
-                } else {
-                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
-                                sizeof (struct arm_request_response);
-                }
-                req->data = kmalloc(size, SLAB_ATOMIC);
-                if (!(req->data)) {
-                        free_pending_request(req);
-                        DBGMSG("arm_read -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                req->free_data=1;
-                req->file_info = fi;
-                req->req.type = RAW1394_REQ_ARM;
-                req->req.generation = get_hpsb_generation(host);
-                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
-                req->req.tag  = arm_addr->arm_tag;
-                req->req.recvb = arm_addr->recvb;
-                req->req.length = size;
-                arm_req_resp = (struct arm_request_response *) (req->data);
-                arm_req  = (struct arm_request *) ((byte_t *)(req->data) +
-                        (sizeof (struct arm_request_response)));
-                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) +
-                        (sizeof(struct arm_request)));
-                arm_req->buffer  = NULL;
-                arm_resp->buffer = NULL;
-                if (rcode == RCODE_COMPLETE) {
-                        byte_t *buf = (byte_t *)arm_resp + sizeof(struct arm_response);
-                        memcpy (buf,
-                                (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
-                                length);
-                        arm_resp->buffer = int2ptr((arm_addr->recvb) +
-                                sizeof (struct arm_request_response) +
-                                sizeof (struct arm_request) +
-                                sizeof (struct arm_response));
-                }
-                arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0;
-                arm_resp->response_code = rcode;
-                arm_req->buffer_length = 0;
-                arm_req->generation = req->req.generation;
-                arm_req->extended_transaction_code = 0;
-                arm_req->destination_offset = addr;
-                arm_req->source_nodeid = nodeid;
-                arm_req->destination_nodeid = host->node_id;
-                arm_req->tlabel = (flags >> 10) & 0x3f;
-                arm_req->tcode = (flags >> 4) & 0x0f;
-                arm_req_resp->request  = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response));
-                arm_req_resp->response = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request));
-                queue_complete_req(req);
-        }
-        spin_unlock(&host_info_lock);
-        return(rcode);
-}
-
-static int arm_write (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
-        struct pending_request *req;
-        struct host_info *hi;
-        struct file_info *fi = NULL;
-        struct list_head *entry;
-        struct arm_addr  *arm_addr = NULL;
-        struct arm_request  *arm_req = NULL;
-        struct arm_response *arm_resp = NULL;
-        int found=0, size=0, rcode=-1, length_conflict=0;
-        struct arm_request_response *arm_req_resp = NULL;
-
-        DBGMSG("arm_write called by node: %X"
-              "addr: %4.4x %8.8x length: %Zu", nodeid,
-              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-              length);
-        spin_lock(&host_info_lock);
-        hi = find_host_info(host); /* search address-entry */
-        if (hi != NULL) {
-                list_for_each_entry(fi, &hi->file_info_list, list) {
-                        entry = fi->addr_list.next;
-                        while (entry != &(fi->addr_list)) {
-                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                                if (((arm_addr->start) <= (addr)) &&
-                                        ((arm_addr->end) >= (addr+length))) {
-                                        found = 1;
-                                        break;
-                                }
-                                entry = entry->next;
-                        }
-                        if (found) {
-                                break;
-                        }
-                }
-        }
-        rcode = -1;
-        if (!found) {
-                printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
-                " -> rcode_address_error\n");
-                spin_unlock(&host_info_lock);
-                return (RCODE_ADDRESS_ERROR);
-        } else {
-                DBGMSG("arm_write addr_entry FOUND");
-        }
-        if (arm_addr->rec_length < length) {
-                DBGMSG("arm_write blocklength too big -> rcode_data_error");
-                length_conflict = 1;
-                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
-        }
-        if (rcode == -1) {
-                if (arm_addr->access_rights & ARM_WRITE) {
-                        if (!(arm_addr->client_transactions & ARM_WRITE)) {
-                                memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
-                                        data, length);
-                                DBGMSG("arm_write -> (rcode_complete)");
-                                rcode = RCODE_COMPLETE;
-                        }
-                } else {
-                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                        DBGMSG("arm_write -> rcode_type_error (access denied)");
-                }
-        }
-        if (arm_addr->notification_options & ARM_WRITE) {
-                DBGMSG("arm_write -> entering notification-section");
-                req = __alloc_pending_request(SLAB_ATOMIC);
-                if (!req) {
-                        DBGMSG("arm_write -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request my be retried */
-                }
-                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
-                        (length) * sizeof(byte_t) +
-                        sizeof (struct arm_request_response);
-                req->data = kmalloc(size, SLAB_ATOMIC);
-                if (!(req->data)) {
-                        free_pending_request(req);
-                        DBGMSG("arm_write -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                req->free_data=1;
-                req->file_info = fi;
-                req->req.type = RAW1394_REQ_ARM;
-                req->req.generation = get_hpsb_generation(host);
-                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
-                req->req.tag  = arm_addr->arm_tag;
-                req->req.recvb = arm_addr->recvb;
-                req->req.length = size;
-                arm_req_resp = (struct arm_request_response *) (req->data);
-                arm_req  = (struct arm_request *) ((byte_t *)(req->data) +
-                        (sizeof (struct arm_request_response)));
-                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) +
-                        (sizeof(struct arm_request)));
-                arm_resp->buffer = NULL;
-                memcpy ((byte_t *)arm_resp + sizeof(struct arm_response),
-			data, length);
-                arm_req->buffer = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request) +
-                        sizeof (struct arm_response));
-                arm_req->buffer_length = length;
-                arm_req->generation = req->req.generation;
-                arm_req->extended_transaction_code = 0;
-                arm_req->destination_offset = addr;
-                arm_req->source_nodeid = nodeid;
-                arm_req->destination_nodeid = destid;
-                arm_req->tlabel = (flags >> 10) & 0x3f;
-                arm_req->tcode = (flags >> 4) & 0x0f;
-                arm_resp->buffer_length = 0;
-                arm_resp->response_code = rcode;
-                arm_req_resp->request  = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response));
-                arm_req_resp->response = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request));
-                queue_complete_req(req);
-        }
-        spin_unlock(&host_info_lock);
-        return(rcode);
-}
-
-static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
-             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
-{
-        struct pending_request *req;
-        struct host_info *hi;
-        struct file_info *fi = NULL;
-        struct list_head *entry;
-        struct arm_addr  *arm_addr = NULL;
-        struct arm_request  *arm_req = NULL;
-        struct arm_response *arm_resp = NULL;
-        int found=0, size=0, rcode=-1;
-        quadlet_t old, new;
-        struct arm_request_response *arm_req_resp = NULL;
-
-        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-                DBGMSG("arm_lock  called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
-                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF , be32_to_cpu(data));
-        } else {
-                DBGMSG("arm_lock  called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
-                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg));
-        }
-        spin_lock(&host_info_lock);
-        hi = find_host_info(host); /* search address-entry */
-        if (hi != NULL) {
-                list_for_each_entry(fi, &hi->file_info_list, list) {
-                        entry = fi->addr_list.next;
-                        while (entry != &(fi->addr_list)) {
-                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                                if (((arm_addr->start) <= (addr)) &&
-                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
-                                        found = 1;
-                                        break;
-                                }
-                                entry = entry->next;
-                        }
-                        if (found) {
-                                break;
-                        }
-                }
-        }
-        rcode = -1;
-        if (!found) {
-                printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
-                " -> rcode_address_error\n");
-                spin_unlock(&host_info_lock);
-                return (RCODE_ADDRESS_ERROR);
-        } else {
-                DBGMSG("arm_lock addr_entry FOUND");
-        }
-        if (rcode == -1) {
-                if (arm_addr->access_rights & ARM_LOCK) {
-                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
-                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
-                                        sizeof(old));
-                                switch (ext_tcode) {
-                                        case (EXTCODE_MASK_SWAP):
-                                                new = data | (old & ~arg);
-                                                break;
-                                        case (EXTCODE_COMPARE_SWAP):
-                                                if (old == arg) {
-                                                        new = data;
-                                                } else {
-                                                        new = old;
-                                                }
-                                                break;
-                                        case (EXTCODE_FETCH_ADD):
-                                                new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old));
-                                                break;
-                                        case (EXTCODE_LITTLE_ADD):
-                                                new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old));
-                                                break;
-                                        case (EXTCODE_BOUNDED_ADD):
-                                                if (old != arg) {
-                                                        new = cpu_to_be32(be32_to_cpu(data) +
-                                                                be32_to_cpu(old));
-                                                } else {
-                                                        new = old;
-                                                }
-                                                break;
-                                        case (EXTCODE_WRAP_ADD):
-                                                if (old != arg) {
-                                                        new = cpu_to_be32(be32_to_cpu(data) +
-                                                                be32_to_cpu(old));
-                                                } else {
-                                                        new = data;
-                                                }
-                                                break;
-                                        default:
-                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                                                printk(KERN_ERR "raw1394: arm_lock FAILED "
-                                                "ext_tcode not allowed -> rcode_type_error\n");
-                                                break;
-                                } /*switch*/
-                                if (rcode == -1) {
-                                        DBGMSG("arm_lock -> (rcode_complete)");
-                                        rcode = RCODE_COMPLETE;
-                                        memcpy (store, &old, sizeof(*store));
-                                        memcpy ((arm_addr->addr_space_buffer)+
-                                                (addr-(arm_addr->start)),
-                                                &new, sizeof(*store));
-                                }
-                        }
-                } else {
-                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                        DBGMSG("arm_lock -> rcode_type_error (access denied)");
-                }
-        }
-        if (arm_addr->notification_options & ARM_LOCK) {
+	struct pending_request *req;
+	struct host_info *hi;
+	struct file_info *fi = NULL;
+	struct list_head *entry;
+	struct arm_addr *arm_addr = NULL;
+	struct arm_request *arm_req = NULL;
+	struct arm_response *arm_resp = NULL;
+	int found = 0, size = 0, rcode = -1;
+	octlet_t old, new;
+	struct arm_request_response *arm_req_resp = NULL;
+
+	if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+	    ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+		DBGMSG("arm_lock64 called by node: %X "
+		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
+		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
+		       (u32) (addr & 0xFFFFFFFF),
+		       ext_tcode & 0xFF,
+		       (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
+		       (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
+	} else {
+		DBGMSG("arm_lock64 called by node: %X "
+		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
+		       "%8.8X %8.8X ",
+		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
+		       (u32) (addr & 0xFFFFFFFF),
+		       ext_tcode & 0xFF,
+		       (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
+		       (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
+		       (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF),
+		       (u32) (be64_to_cpu(arg) & 0xFFFFFFFF));
+	}
+	spin_lock(&host_info_lock);
+	hi = find_host_info(host);	/* search addressentry in file_info's for host */
+	if (hi != NULL) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+			entry = fi->addr_list.next;
+			while (entry != &(fi->addr_list)) {
+				arm_addr =
+				    list_entry(entry, struct arm_addr,
+					       addr_list);
+				if (((arm_addr->start) <= (addr))
+				    && ((arm_addr->end) >=
+					(addr + sizeof(*store)))) {
+					found = 1;
+					break;
+				}
+				entry = entry->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+	}
+	rcode = -1;
+	if (!found) {
+		printk(KERN_ERR
+		       "raw1394: arm_lock64 FAILED addr_entry not found"
+		       " -> rcode_address_error\n");
+		spin_unlock(&host_info_lock);
+		return (RCODE_ADDRESS_ERROR);
+	} else {
+		DBGMSG("arm_lock64 addr_entry FOUND");
+	}
+	if (rcode == -1) {
+		if (arm_addr->access_rights & ARM_LOCK) {
+			if (!(arm_addr->client_transactions & ARM_LOCK)) {
+				memcpy(&old,
+				       (arm_addr->addr_space_buffer) + (addr -
+									(arm_addr->
+									 start)),
+				       sizeof(old));
+				switch (ext_tcode) {
+				case (EXTCODE_MASK_SWAP):
+					new = data | (old & ~arg);
+					break;
+				case (EXTCODE_COMPARE_SWAP):
+					if (old == arg) {
+						new = data;
+					} else {
+						new = old;
+					}
+					break;
+				case (EXTCODE_FETCH_ADD):
+					new =
+					    cpu_to_be64(be64_to_cpu(data) +
+							be64_to_cpu(old));
+					break;
+				case (EXTCODE_LITTLE_ADD):
+					new =
+					    cpu_to_le64(le64_to_cpu(data) +
+							le64_to_cpu(old));
+					break;
+				case (EXTCODE_BOUNDED_ADD):
+					if (old != arg) {
+						new =
+						    cpu_to_be64(be64_to_cpu
+								(data) +
+								be64_to_cpu
+								(old));
+					} else {
+						new = old;
+					}
+					break;
+				case (EXTCODE_WRAP_ADD):
+					if (old != arg) {
+						new =
+						    cpu_to_be64(be64_to_cpu
+								(data) +
+								be64_to_cpu
+								(old));
+					} else {
+						new = data;
+					}
+					break;
+				default:
+					printk(KERN_ERR
+					       "raw1394: arm_lock64 FAILED "
+					       "ext_tcode not allowed -> rcode_type_error\n");
+					rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+					break;
+				}	/*switch */
+				if (rcode == -1) {
+					DBGMSG
+					    ("arm_lock64 -> (rcode_complete)");
+					rcode = RCODE_COMPLETE;
+					memcpy(store, &old, sizeof(*store));
+					memcpy((arm_addr->addr_space_buffer) +
+					       (addr - (arm_addr->start)),
+					       &new, sizeof(*store));
+				}
+			}
+		} else {
+			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
+			DBGMSG
+			    ("arm_lock64 -> rcode_type_error (access denied)");
+		}
+	}
+	if (arm_addr->notification_options & ARM_LOCK) {
 		byte_t *buf1, *buf2;
-                DBGMSG("arm_lock -> entering notification-section");
-                req = __alloc_pending_request(SLAB_ATOMIC);
-                if (!req) {
-                        DBGMSG("arm_lock -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
-                        3 * sizeof(*store) +
-                        sizeof (struct arm_request_response);  /* maximum */
-                req->data = kmalloc(size, SLAB_ATOMIC);
-                if (!(req->data)) {
-                        free_pending_request(req);
-                        DBGMSG("arm_lock -> rcode_conflict_error");
-                        spin_unlock(&host_info_lock);
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                req->free_data=1;
-                arm_req_resp = (struct arm_request_response *) (req->data);
-                arm_req  = (struct arm_request *) ((byte_t *)(req->data) +
-                        (sizeof (struct arm_request_response)));
-                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) +
-                        (sizeof(struct arm_request)));
-                buf1 = (byte_t *)arm_resp + sizeof(struct arm_response);
+		DBGMSG("arm_lock64 -> entering notification-section");
+		req = __alloc_pending_request(SLAB_ATOMIC);
+		if (!req) {
+			spin_unlock(&host_info_lock);
+			DBGMSG("arm_lock64 -> rcode_conflict_error");
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);	/* maximum */
+		req->data = kmalloc(size, SLAB_ATOMIC);
+		if (!(req->data)) {
+			free_pending_request(req);
+			spin_unlock(&host_info_lock);
+			DBGMSG("arm_lock64 -> rcode_conflict_error");
+			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
+							   The request may be retried */
+		}
+		req->free_data = 1;
+		arm_req_resp = (struct arm_request_response *)(req->data);
+		arm_req = (struct arm_request *)((byte_t *) (req->data) +
+						 (sizeof
+						  (struct
+						   arm_request_response)));
+		arm_resp =
+		    (struct arm_response *)((byte_t *) (arm_req) +
+					    (sizeof(struct arm_request)));
+		buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
 		buf2 = buf1 + 2 * sizeof(*store);
-                if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
-                        arm_req->buffer_length = sizeof(*store);
-                        memcpy (buf1, &data, sizeof(*store));
-
-                } else {
-                        arm_req->buffer_length = 2 * sizeof(*store);
-                        memcpy (buf1, &arg,  sizeof(*store));
-                        memcpy (buf1 + sizeof(*store), &data, sizeof(*store));
-                }
-                if (rcode == RCODE_COMPLETE) {
-                        arm_resp->buffer_length = sizeof(*store);
-                        memcpy (buf2, &old, sizeof(*store));
-                } else {
-                        arm_resp->buffer_length = 0;
-                }
-                req->file_info = fi;
-                req->req.type = RAW1394_REQ_ARM;
-                req->req.generation = get_hpsb_generation(host);
-                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) |
-                        (ARM_LOCK & 0xFF));
-                req->req.tag  = arm_addr->arm_tag;
-                req->req.recvb = arm_addr->recvb;
-                req->req.length = size;
-                arm_req->generation = req->req.generation;
-                arm_req->extended_transaction_code = ext_tcode;
-                arm_req->destination_offset = addr;
-                arm_req->source_nodeid = nodeid;
-                arm_req->destination_nodeid = host->node_id;
-                arm_req->tlabel = (flags >> 10) & 0x3f;
-                arm_req->tcode = (flags >> 4) & 0x0f;
-                arm_resp->response_code = rcode;
-                arm_req_resp->request  = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response));
-                arm_req_resp->response = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request));
-                arm_req->buffer = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request) +
-                        sizeof (struct arm_response));
-                arm_resp->buffer = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request) +
-                        sizeof (struct arm_response) +
-                        2* sizeof (*store));
-                queue_complete_req(req);
-        }
-        spin_unlock(&host_info_lock);
-        return(rcode);
-}
-
-static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
-               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
-{
-        struct pending_request *req;
-        struct host_info *hi;
-        struct file_info *fi = NULL;
-        struct list_head *entry;
-        struct arm_addr  *arm_addr = NULL;
-        struct arm_request  *arm_req = NULL;
-        struct arm_response *arm_resp = NULL;
-        int found=0, size=0, rcode=-1;
-        octlet_t old, new;
-        struct arm_request_response *arm_req_resp = NULL;
-
-        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-                DBGMSG("arm_lock64 called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
-                      nodeid, (u16) ((addr >>32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF ,
-                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
-        } else {
-                DBGMSG("arm_lock64 called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
-                      "%8.8X %8.8X ",
-                      nodeid, (u16) ((addr >>32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF ,
-                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
-                      (u32) ((be64_to_cpu(arg)  >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(arg)  & 0xFFFFFFFF));
-        }
-        spin_lock(&host_info_lock);
-        hi = find_host_info(host); /* search addressentry in file_info's for host */
-        if (hi != NULL) {
-                list_for_each_entry(fi, &hi->file_info_list, list) {
-                        entry = fi->addr_list.next;
-                        while (entry != &(fi->addr_list)) {
-                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                                if (((arm_addr->start) <= (addr)) &&
-                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
-                                        found = 1;
-                                        break;
-                                }
-                                entry = entry->next;
-                        }
-                        if (found) {
-                                break;
-                        }
-                }
-        }
-        rcode = -1;
-        if (!found) {
-                printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found"
-                " -> rcode_address_error\n");
-                spin_unlock(&host_info_lock);
-                return (RCODE_ADDRESS_ERROR);
-        } else {
-                DBGMSG("arm_lock64 addr_entry FOUND");
-        }
-        if (rcode == -1) {
-                if (arm_addr->access_rights & ARM_LOCK) {
-                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
-                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
-                                        sizeof(old));
-                                switch (ext_tcode) {
-                                        case (EXTCODE_MASK_SWAP):
-                                                new = data | (old & ~arg);
-                                                break;
-                                        case (EXTCODE_COMPARE_SWAP):
-                                                if (old == arg) {
-                                                        new = data;
-                                                } else {
-                                                        new = old;
-                                                }
-                                                break;
-                                        case (EXTCODE_FETCH_ADD):
-                                                new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old));
-                                                break;
-                                        case (EXTCODE_LITTLE_ADD):
-                                                new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old));
-                                                break;
-                                        case (EXTCODE_BOUNDED_ADD):
-                                                if (old != arg) {
-                                                        new = cpu_to_be64(be64_to_cpu(data) +
-                                                                be64_to_cpu(old));
-                                                } else {
-                                                        new = old;
-                                                }
-                                                break;
-                                        case (EXTCODE_WRAP_ADD):
-                                                if (old != arg) {
-                                                        new = cpu_to_be64(be64_to_cpu(data) +
-                                                                be64_to_cpu(old));
-                                                } else {
-                                                        new = data;
-                                                }
-                                                break;
-                                        default:
-                                                printk(KERN_ERR "raw1394: arm_lock64 FAILED "
-                                                "ext_tcode not allowed -> rcode_type_error\n");
-                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                                                break;
-                                } /*switch*/
-                                if (rcode == -1) {
-                                        DBGMSG("arm_lock64 -> (rcode_complete)");
-                                        rcode = RCODE_COMPLETE;
-                                        memcpy (store, &old, sizeof(*store));
-                                        memcpy ((arm_addr->addr_space_buffer)+
-                                                (addr-(arm_addr->start)),
-                                                &new, sizeof(*store));
-                                }
-                        }
-                } else {
-                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
-                        DBGMSG("arm_lock64 -> rcode_type_error (access denied)");
-                }
-        }
-        if (arm_addr->notification_options & ARM_LOCK) {
-		byte_t *buf1, *buf2;
-                DBGMSG("arm_lock64 -> entering notification-section");
-                req = __alloc_pending_request(SLAB_ATOMIC);
-                if (!req) {
-                        spin_unlock(&host_info_lock);
-                        DBGMSG("arm_lock64 -> rcode_conflict_error");
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
-                        3 * sizeof(*store) +
-                        sizeof (struct arm_request_response); /* maximum */
-                req->data = kmalloc(size, SLAB_ATOMIC);
-                if (!(req->data)) {
-                        free_pending_request(req);
-                        spin_unlock(&host_info_lock);
-                        DBGMSG("arm_lock64 -> rcode_conflict_error");
-                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
-                                                        The request may be retried */
-                }
-                req->free_data=1;
-                arm_req_resp = (struct arm_request_response *) (req->data);
-                arm_req  = (struct arm_request *) ((byte_t *)(req->data) +
-                        (sizeof (struct arm_request_response)));
-                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) +
-                        (sizeof(struct arm_request)));
-                buf1 = (byte_t *)arm_resp + sizeof(struct arm_response);
-                buf2 = buf1 + 2 * sizeof(*store);
-                if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
-                        arm_req->buffer_length = sizeof(*store);
-                        memcpy (buf1, &data, sizeof(*store));
-
-                } else {
-                        arm_req->buffer_length = 2 * sizeof(*store);
-                        memcpy (buf1, &arg,  sizeof(*store));
-                        memcpy (buf1 + sizeof(*store), &data, sizeof(*store));
-                }
-                if (rcode == RCODE_COMPLETE) {
-                        arm_resp->buffer_length = sizeof(*store);
-                        memcpy (buf2, &old, sizeof(*store));
-                } else {
-                        arm_resp->buffer_length = 0;
-                }
-                req->file_info = fi;
-                req->req.type = RAW1394_REQ_ARM;
-                req->req.generation = get_hpsb_generation(host);
-                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) |
-                        (ARM_LOCK & 0xFF));
-                req->req.tag  = arm_addr->arm_tag;
-                req->req.recvb = arm_addr->recvb;
-                req->req.length = size;
-                arm_req->generation = req->req.generation;
-                arm_req->extended_transaction_code = ext_tcode;
-                arm_req->destination_offset = addr;
-                arm_req->source_nodeid = nodeid;
-                arm_req->destination_nodeid = host->node_id;
-                arm_req->tlabel = (flags >> 10) & 0x3f;
-                arm_req->tcode = (flags >> 4) & 0x0f;
-                arm_resp->response_code = rcode;
-                arm_req_resp->request  = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response));
-                arm_req_resp->response = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request));
-                arm_req->buffer = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request) +
-                        sizeof (struct arm_response));
-                arm_resp->buffer = int2ptr((arm_addr->recvb) +
-                        sizeof (struct arm_request_response) +
-                        sizeof (struct arm_request) +
-                        sizeof (struct arm_response) +
-                        2* sizeof (*store));
-                queue_complete_req(req);
-        }
-        spin_unlock(&host_info_lock);
-        return(rcode);
+		if ((ext_tcode == EXTCODE_FETCH_ADD) ||
+		    (ext_tcode == EXTCODE_LITTLE_ADD)) {
+			arm_req->buffer_length = sizeof(*store);
+			memcpy(buf1, &data, sizeof(*store));
+
+		} else {
+			arm_req->buffer_length = 2 * sizeof(*store);
+			memcpy(buf1, &arg, sizeof(*store));
+			memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
+		}
+		if (rcode == RCODE_COMPLETE) {
+			arm_resp->buffer_length = sizeof(*store);
+			memcpy(buf2, &old, sizeof(*store));
+		} else {
+			arm_resp->buffer_length = 0;
+		}
+		req->file_info = fi;
+		req->req.type = RAW1394_REQ_ARM;
+		req->req.generation = get_hpsb_generation(host);
+		req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
+				 (ARM_LOCK & 0xFF));
+		req->req.tag = arm_addr->arm_tag;
+		req->req.recvb = arm_addr->recvb;
+		req->req.length = size;
+		arm_req->generation = req->req.generation;
+		arm_req->extended_transaction_code = ext_tcode;
+		arm_req->destination_offset = addr;
+		arm_req->source_nodeid = nodeid;
+		arm_req->destination_nodeid = host->node_id;
+		arm_req->tlabel = (flags >> 10) & 0x3f;
+		arm_req->tcode = (flags >> 4) & 0x0f;
+		arm_resp->response_code = rcode;
+		arm_req_resp->request = int2ptr((arm_addr->recvb) +
+						sizeof(struct
+						       arm_request_response));
+		arm_req_resp->response =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request));
+		arm_req->buffer =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response));
+		arm_resp->buffer =
+		    int2ptr((arm_addr->recvb) +
+			    sizeof(struct arm_request_response) +
+			    sizeof(struct arm_request) +
+			    sizeof(struct arm_response) + 2 * sizeof(*store));
+		queue_complete_req(req);
+	}
+	spin_unlock(&host_info_lock);
+	return (rcode);
 }
 
 static int arm_register(struct file_info *fi, struct pending_request *req)
 {
-        int retval;
-        struct arm_addr *addr;
-        struct host_info *hi;
-        struct file_info *fi_hlp = NULL;
-        struct list_head *entry;
-        struct arm_addr  *arm_addr = NULL;
-        int same_host, another_host;
-        unsigned long flags;
-
-        DBGMSG("arm_register called "
-              "addr(Offset): %8.8x %8.8x length: %u "
-              "rights: %2.2X notify: %2.2X "
-              "max_blk_len: %4.4X",
-              (u32) ((req->req.address >>32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF),
-              req->req.length, ((req->req.misc >> 8) & 0xFF),
-              (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF));
-        /* check addressrange */
-        if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
-                (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) != 0)) {
-                req->req.length = 0;
-                return (-EINVAL);
-        }
-        /* addr-list-entry for fileinfo */
-        addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL);
-        if (!addr) {
-                req->req.length = 0;
-                return (-ENOMEM);
-        }
-        /* allocation of addr_space_buffer */
-        addr->addr_space_buffer = (u8 *)vmalloc(req->req.length);
-        if (!(addr->addr_space_buffer)) {
-                kfree(addr);
-                req->req.length = 0;
-                return (-ENOMEM);
-        }
-        /* initialization of addr_space_buffer */
-        if ((req->req.sendb)== (unsigned long)NULL) {
-                /* init: set 0 */
-                memset(addr->addr_space_buffer, 0,req->req.length);
-        } else {
-                /* init: user -> kernel */
-                if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb),
-                        req->req.length)) {
-                        vfree(addr->addr_space_buffer);
-                        kfree(addr);
-                        return (-EFAULT);
-                }
-        }
-        INIT_LIST_HEAD(&addr->addr_list);
-        addr->arm_tag   = req->req.tag;
-        addr->start     = req->req.address;
-        addr->end       = req->req.address + req->req.length;
-        addr->access_rights = (u8) (req->req.misc & 0x0F);
-        addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
-        addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
-        addr->access_rights |= addr->client_transactions;
-        addr->notification_options |= addr->client_transactions;
-        addr->recvb     = req->req.recvb;
-        addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(fi->host);
-        same_host = 0;
-        another_host = 0;
-        /* same host with address-entry containing same addressrange ? */
-        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                entry = fi_hlp->addr_list.next;
-                while (entry != &(fi_hlp->addr_list)) {
-                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                        if ( (arm_addr->start == addr->start) &&
-                                (arm_addr->end == addr->end)) {
-                                DBGMSG("same host ownes same "
-                                        "addressrange -> EALREADY");
-                                same_host = 1;
-                                break;
-                        }
-                        entry = entry->next;
-                }
-                if (same_host) {
-                        break;
-                }
-        }
-        if (same_host) {
-                /* addressrange occupied by same host */
-                vfree(addr->addr_space_buffer);
-                kfree(addr);
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return (-EALREADY);
-        }
-        /* another host with valid address-entry containing same addressrange */
-        list_for_each_entry(hi, &host_info_list, list) {
-                if (hi->host != fi->host) {
-                        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                                entry = fi_hlp->addr_list.next;
-                                while (entry != &(fi_hlp->addr_list)) {
-                                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
-                                        if ( (arm_addr->start == addr->start) &&
-                                                (arm_addr->end == addr->end)) {
-                                                DBGMSG("another host ownes same "
-                                                "addressrange");
-                                                another_host = 1;
-                                                break;
-                                        }
-                                        entry = entry->next;
-                                }
-                                if (another_host) {
-                                        break;
-                                }
-                        }
-                }
-        }
-        if (another_host) {
-                DBGMSG("another hosts entry is valid -> SUCCESS");
-                if (copy_to_user(int2ptr(req->req.recvb),
-                        &addr->start,sizeof(u64))) {
-                        printk(KERN_ERR "raw1394: arm_register failed "
-                              " address-range-entry is invalid -> EFAULT !!!\n");
-                        vfree(addr->addr_space_buffer);
-                        kfree(addr);
-                        spin_unlock_irqrestore(&host_info_lock, flags);
-                        return (-EFAULT);
-                }
-                free_pending_request(req); /* immediate success or fail */
-                /* INSERT ENTRY */
-                list_add_tail(&addr->addr_list, &fi->addr_list);
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return sizeof(struct raw1394_request);
-        }
-        retval = hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops, req->req.address,
-                req->req.address + req->req.length);
-        if (retval) {
-               /* INSERT ENTRY */
-               list_add_tail(&addr->addr_list, &fi->addr_list);
-        } else {
-                DBGMSG("arm_register failed errno: %d \n",retval);
-                vfree(addr->addr_space_buffer);
-                kfree(addr);
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return (-EALREADY);
-        }
-        spin_unlock_irqrestore(&host_info_lock, flags);
-        free_pending_request(req); /* immediate success or fail */
-        return sizeof(struct raw1394_request);
+	int retval;
+	struct arm_addr *addr;
+	struct host_info *hi;
+	struct file_info *fi_hlp = NULL;
+	struct list_head *entry;
+	struct arm_addr *arm_addr = NULL;
+	int same_host, another_host;
+	unsigned long flags;
+
+	DBGMSG("arm_register called "
+	       "addr(Offset): %8.8x %8.8x length: %u "
+	       "rights: %2.2X notify: %2.2X "
+	       "max_blk_len: %4.4X",
+	       (u32) ((req->req.address >> 32) & 0xFFFF),
+	       (u32) (req->req.address & 0xFFFFFFFF),
+	       req->req.length, ((req->req.misc >> 8) & 0xFF),
+	       (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF));
+	/* check addressrange */
+	if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
+	    (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) !=
+	     0)) {
+		req->req.length = 0;
+		return (-EINVAL);
+	}
+	/* addr-list-entry for fileinfo */
+	addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL);
+	if (!addr) {
+		req->req.length = 0;
+		return (-ENOMEM);
+	}
+	/* allocation of addr_space_buffer */
+	addr->addr_space_buffer = (u8 *) vmalloc(req->req.length);
+	if (!(addr->addr_space_buffer)) {
+		kfree(addr);
+		req->req.length = 0;
+		return (-ENOMEM);
+	}
+	/* initialization of addr_space_buffer */
+	if ((req->req.sendb) == (unsigned long)NULL) {
+		/* init: set 0 */
+		memset(addr->addr_space_buffer, 0, req->req.length);
+	} else {
+		/* init: user -> kernel */
+		if (copy_from_user
+		    (addr->addr_space_buffer, int2ptr(req->req.sendb),
+		     req->req.length)) {
+			vfree(addr->addr_space_buffer);
+			kfree(addr);
+			return (-EFAULT);
+		}
+	}
+	INIT_LIST_HEAD(&addr->addr_list);
+	addr->arm_tag = req->req.tag;
+	addr->start = req->req.address;
+	addr->end = req->req.address + req->req.length;
+	addr->access_rights = (u8) (req->req.misc & 0x0F);
+	addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
+	addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
+	addr->access_rights |= addr->client_transactions;
+	addr->notification_options |= addr->client_transactions;
+	addr->recvb = req->req.recvb;
+	addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(fi->host);
+	same_host = 0;
+	another_host = 0;
+	/* same host with address-entry containing same addressrange ? */
+	list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
+		entry = fi_hlp->addr_list.next;
+		while (entry != &(fi_hlp->addr_list)) {
+			arm_addr =
+			    list_entry(entry, struct arm_addr, addr_list);
+			if ((arm_addr->start == addr->start)
+			    && (arm_addr->end == addr->end)) {
+				DBGMSG("same host ownes same "
+				       "addressrange -> EALREADY");
+				same_host = 1;
+				break;
+			}
+			entry = entry->next;
+		}
+		if (same_host) {
+			break;
+		}
+	}
+	if (same_host) {
+		/* addressrange occupied by same host */
+		vfree(addr->addr_space_buffer);
+		kfree(addr);
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return (-EALREADY);
+	}
+	/* another host with valid address-entry containing same addressrange */
+	list_for_each_entry(hi, &host_info_list, list) {
+		if (hi->host != fi->host) {
+			list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
+				entry = fi_hlp->addr_list.next;
+				while (entry != &(fi_hlp->addr_list)) {
+					arm_addr =
+					    list_entry(entry, struct arm_addr,
+						       addr_list);
+					if ((arm_addr->start == addr->start)
+					    && (arm_addr->end == addr->end)) {
+						DBGMSG
+						    ("another host ownes same "
+						     "addressrange");
+						another_host = 1;
+						break;
+					}
+					entry = entry->next;
+				}
+				if (another_host) {
+					break;
+				}
+			}
+		}
+	}
+	if (another_host) {
+		DBGMSG("another hosts entry is valid -> SUCCESS");
+		if (copy_to_user(int2ptr(req->req.recvb),
+				 &addr->start, sizeof(u64))) {
+			printk(KERN_ERR "raw1394: arm_register failed "
+			       " address-range-entry is invalid -> EFAULT !!!\n");
+			vfree(addr->addr_space_buffer);
+			kfree(addr);
+			spin_unlock_irqrestore(&host_info_lock, flags);
+			return (-EFAULT);
+		}
+		free_pending_request(req);	/* immediate success or fail */
+		/* INSERT ENTRY */
+		list_add_tail(&addr->addr_list, &fi->addr_list);
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return sizeof(struct raw1394_request);
+	}
+	retval =
+	    hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
+				    req->req.address,
+				    req->req.address + req->req.length);
+	if (retval) {
+		/* INSERT ENTRY */
+		list_add_tail(&addr->addr_list, &fi->addr_list);
+	} else {
+		DBGMSG("arm_register failed errno: %d \n", retval);
+		vfree(addr->addr_space_buffer);
+		kfree(addr);
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return (-EALREADY);
+	}
+	spin_unlock_irqrestore(&host_info_lock, flags);
+	free_pending_request(req);	/* immediate success or fail */
+	return sizeof(struct raw1394_request);
 }
 
 static int arm_unregister(struct file_info *fi, struct pending_request *req)
 {
-        int found  = 0;
-        int retval = 0;
-        struct list_head *entry;
-        struct arm_addr  *addr = NULL;
-        struct host_info *hi;
-        struct file_info *fi_hlp = NULL;
-        struct arm_addr  *arm_addr = NULL;
-        int another_host;
-        unsigned long flags;
-
-        DBGMSG("arm_Unregister called addr(Offset): "
-              "%8.8x %8.8x",
-              (u32) ((req->req.address >>32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF));
-        spin_lock_irqsave(&host_info_lock, flags);
-        /* get addr */
-        entry = fi->addr_list.next;
-        while (entry != &(fi->addr_list)) {
-                addr = list_entry(entry, struct arm_addr, addr_list);
-                if (addr->start == req->req.address) {
-                        found = 1;
-                        break;
-                }
-                entry = entry->next;
-        }
-        if (!found) {
-                DBGMSG("arm_Unregister addr not found");
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return (-EINVAL);
-        }
-        DBGMSG("arm_Unregister addr found");
-        another_host = 0;
-        /* another host with valid address-entry containing
-           same addressrange */
-        list_for_each_entry(hi, &host_info_list, list) {
-                if (hi->host != fi->host) {
-                        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                                entry = fi_hlp->addr_list.next;
-                                while (entry != &(fi_hlp->addr_list)) {
-                                        arm_addr = list_entry(entry,
-                                                struct arm_addr, addr_list);
-                                        if (arm_addr->start ==
-                                                addr->start) {
-                                                DBGMSG("another host ownes "
-                                                "same addressrange");
-                                                another_host = 1;
-                                                break;
-                                        }
-                                        entry = entry->next;
-                                }
-                                if (another_host) {
-                                        break;
-                                }
-                        }
-                }
-        }
-        if (another_host) {
-                DBGMSG("delete entry from list -> success");
-                list_del(&addr->addr_list);
-                vfree(addr->addr_space_buffer);
-                kfree(addr);
-                free_pending_request(req); /* immediate success or fail */
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return sizeof(struct raw1394_request);
-        }
-        retval = hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, addr->start);
-        if (!retval) {
-                printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
-                spin_unlock_irqrestore(&host_info_lock, flags);
-                return (-EINVAL);
-        }
-        DBGMSG("delete entry from list -> success");
-        list_del(&addr->addr_list);
-        spin_unlock_irqrestore(&host_info_lock, flags);
-        vfree(addr->addr_space_buffer);
-        kfree(addr);
-        free_pending_request(req); /* immediate success or fail */
-        return sizeof(struct raw1394_request);
+	int found = 0;
+	int retval = 0;
+	struct list_head *entry;
+	struct arm_addr *addr = NULL;
+	struct host_info *hi;
+	struct file_info *fi_hlp = NULL;
+	struct arm_addr *arm_addr = NULL;
+	int another_host;
+	unsigned long flags;
+
+	DBGMSG("arm_Unregister called addr(Offset): "
+	       "%8.8x %8.8x",
+	       (u32) ((req->req.address >> 32) & 0xFFFF),
+	       (u32) (req->req.address & 0xFFFFFFFF));
+	spin_lock_irqsave(&host_info_lock, flags);
+	/* get addr */
+	entry = fi->addr_list.next;
+	while (entry != &(fi->addr_list)) {
+		addr = list_entry(entry, struct arm_addr, addr_list);
+		if (addr->start == req->req.address) {
+			found = 1;
+			break;
+		}
+		entry = entry->next;
+	}
+	if (!found) {
+		DBGMSG("arm_Unregister addr not found");
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return (-EINVAL);
+	}
+	DBGMSG("arm_Unregister addr found");
+	another_host = 0;
+	/* another host with valid address-entry containing
+	   same addressrange */
+	list_for_each_entry(hi, &host_info_list, list) {
+		if (hi->host != fi->host) {
+			list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
+				entry = fi_hlp->addr_list.next;
+				while (entry != &(fi_hlp->addr_list)) {
+					arm_addr = list_entry(entry,
+							      struct arm_addr,
+							      addr_list);
+					if (arm_addr->start == addr->start) {
+						DBGMSG("another host ownes "
+						       "same addressrange");
+						another_host = 1;
+						break;
+					}
+					entry = entry->next;
+				}
+				if (another_host) {
+					break;
+				}
+			}
+		}
+	}
+	if (another_host) {
+		DBGMSG("delete entry from list -> success");
+		list_del(&addr->addr_list);
+		vfree(addr->addr_space_buffer);
+		kfree(addr);
+		free_pending_request(req);	/* immediate success or fail */
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return sizeof(struct raw1394_request);
+	}
+	retval =
+	    hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
+				      addr->start);
+	if (!retval) {
+		printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
+		spin_unlock_irqrestore(&host_info_lock, flags);
+		return (-EINVAL);
+	}
+	DBGMSG("delete entry from list -> success");
+	list_del(&addr->addr_list);
+	spin_unlock_irqrestore(&host_info_lock, flags);
+	vfree(addr->addr_space_buffer);
+	kfree(addr);
+	free_pending_request(req);	/* immediate success or fail */
+	return sizeof(struct raw1394_request);
 }
 
 /* Copy data from ARM buffer(s) to user buffer. */
 static int arm_get_buf(struct file_info *fi, struct pending_request *req)
 {
-	struct arm_addr  *arm_addr = NULL;
+	struct arm_addr *arm_addr = NULL;
 	unsigned long flags;
 	unsigned long offset;
 
@@ -1749,8 +1864,7 @@ static int arm_get_buf(struct file_info 
 	DBGMSG("arm_get_buf "
 	       "addr(Offset): %04X %08X length: %u",
 	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF),
-	       (u32) req->req.length);
+	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
 
 	spin_lock_irqsave(&host_info_lock, flags);
 	entry = fi->addr_list.next;
@@ -1761,13 +1875,18 @@ static int arm_get_buf(struct file_info 
 			if (req->req.address + req->req.length <= arm_addr->end) {
 				offset = req->req.address - arm_addr->start;
 
-				DBGMSG("arm_get_buf copy_to_user( %08X, %p, %u )",
-				       (u32) req->req.recvb,
-				       arm_addr->addr_space_buffer+offset,
-				       (u32) req->req.length);
-
-				if (copy_to_user(int2ptr(req->req.recvb), arm_addr->addr_space_buffer+offset, req->req.length)) {
-					spin_unlock_irqrestore(&host_info_lock, flags);
+				DBGMSG
+				    ("arm_get_buf copy_to_user( %08X, %p, %u )",
+				     (u32) req->req.recvb,
+				     arm_addr->addr_space_buffer + offset,
+				     (u32) req->req.length);
+
+				if (copy_to_user
+				    (int2ptr(req->req.recvb),
+				     arm_addr->addr_space_buffer + offset,
+				     req->req.length)) {
+					spin_unlock_irqrestore(&host_info_lock,
+							       flags);
 					return (-EFAULT);
 				}
 
@@ -1789,11 +1908,10 @@ static int arm_get_buf(struct file_info 
 	return (-EINVAL);
 }
 
-
 /* Copy data from user buffer to ARM buffer(s). */
 static int arm_set_buf(struct file_info *fi, struct pending_request *req)
 {
-	struct arm_addr  *arm_addr = NULL;
+	struct arm_addr *arm_addr = NULL;
 	unsigned long flags;
 	unsigned long offset;
 
@@ -1802,9 +1920,7 @@ static int arm_set_buf(struct file_info 
 	DBGMSG("arm_set_buf "
 	       "addr(Offset): %04X %08X length: %u",
 	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF),
-	       (u32) req->req.length);
-
+	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
 
 	spin_lock_irqsave(&host_info_lock, flags);
 	entry = fi->addr_list.next;
@@ -1815,18 +1931,23 @@ static int arm_set_buf(struct file_info 
 			if (req->req.address + req->req.length <= arm_addr->end) {
 				offset = req->req.address - arm_addr->start;
 
-				DBGMSG("arm_set_buf copy_from_user( %p, %08X, %u )",
-				       arm_addr->addr_space_buffer+offset,
-				       (u32) req->req.sendb,
-				       (u32) req->req.length);
-
-				if (copy_from_user(arm_addr->addr_space_buffer+offset, int2ptr(req->req.sendb), req->req.length)) {
-					spin_unlock_irqrestore(&host_info_lock, flags);
+				DBGMSG
+				    ("arm_set_buf copy_from_user( %p, %08X, %u )",
+				     arm_addr->addr_space_buffer + offset,
+				     (u32) req->req.sendb,
+				     (u32) req->req.length);
+
+				if (copy_from_user
+				    (arm_addr->addr_space_buffer + offset,
+				     int2ptr(req->req.sendb),
+				     req->req.length)) {
+					spin_unlock_irqrestore(&host_info_lock,
+							       flags);
 					return (-EFAULT);
 				}
 
 				spin_unlock_irqrestore(&host_info_lock, flags);
-				free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+				free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
 				return sizeof(struct raw1394_request);
 			} else {
 				DBGMSG("arm_set_buf request exceeded mapping");
@@ -1842,96 +1963,100 @@ static int arm_set_buf(struct file_info 
 
 static int reset_notification(struct file_info *fi, struct pending_request *req)
 {
-        DBGMSG("reset_notification called - switch %s ",
-                (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON");
-        if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
-                (req->req.misc == RAW1394_NOTIFY_ON)) {
-                fi->notification=(u8)req->req.misc;
-                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                return sizeof(struct raw1394_request);
-        }
-        /* error EINVAL (22) invalid argument */
-        return (-EINVAL);
+	DBGMSG("reset_notification called - switch %s ",
+	       (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
+	if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
+	    (req->req.misc == RAW1394_NOTIFY_ON)) {
+		fi->notification = (u8) req->req.misc;
+		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
+		return sizeof(struct raw1394_request);
+	}
+	/* error EINVAL (22) invalid argument */
+	return (-EINVAL);
 }
 
 static int write_phypacket(struct file_info *fi, struct pending_request *req)
 {
-        struct hpsb_packet *packet = NULL;
-        int retval=0;
-        quadlet_t data;
-
-        data = be32_to_cpu((u32)req->req.sendb);
-        DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data);
-        packet = hpsb_make_phypacket (fi->host, data);
-        if (!packet) return -ENOMEM;
-        req->req.length=0;
-        req->packet=packet;
-        hpsb_set_packet_complete_task(packet, (void(*)(void*))queue_complete_cb, req);
-        spin_lock_irq(&fi->reqlists_lock);
-        list_add_tail(&req->list, &fi->req_pending);
-        spin_unlock_irq(&fi->reqlists_lock);
-        packet->generation = req->req.generation;
-        retval = hpsb_send_packet(packet);
-        DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
-        if (retval < 0) {
-                req->req.error = RAW1394_ERROR_SEND_ERROR;
-                req->req.length = 0;
-                queue_complete_req(req);
-        }
-        return sizeof(struct raw1394_request);
+	struct hpsb_packet *packet = NULL;
+	int retval = 0;
+	quadlet_t data;
+
+	data = be32_to_cpu((u32) req->req.sendb);
+	DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
+	packet = hpsb_make_phypacket(fi->host, data);
+	if (!packet)
+		return -ENOMEM;
+	req->req.length = 0;
+	req->packet = packet;
+	hpsb_set_packet_complete_task(packet,
+				      (void (*)(void *))queue_complete_cb, req);
+	spin_lock_irq(&fi->reqlists_lock);
+	list_add_tail(&req->list, &fi->req_pending);
+	spin_unlock_irq(&fi->reqlists_lock);
+	packet->generation = req->req.generation;
+	retval = hpsb_send_packet(packet);
+	DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
+	if (retval < 0) {
+		req->req.error = RAW1394_ERROR_SEND_ERROR;
+		req->req.length = 0;
+		queue_complete_req(req);
+	}
+	return sizeof(struct raw1394_request);
 }
 
 static int get_config_rom(struct file_info *fi, struct pending_request *req)
 {
-        int ret=sizeof(struct raw1394_request);
-        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
-        int status;
-
-        if (!data) return -ENOMEM;
-
-	status = csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
-			      data, req->req.length);
-        if (copy_to_user(int2ptr(req->req.recvb), data,
-                req->req.length))
-                ret = -EFAULT;
-	if (copy_to_user(int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
-			 sizeof(fi->host->csr.rom->cache_head->len)))
-                ret = -EFAULT;
+	int ret = sizeof(struct raw1394_request);
+	quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+	int status;
+
+	if (!data)
+		return -ENOMEM;
+
+	status =
+	    csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
+			 data, req->req.length);
+	if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
+		ret = -EFAULT;
+	if (copy_to_user
+	    (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
+	     sizeof(fi->host->csr.rom->cache_head->len)))
+		ret = -EFAULT;
 	if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
 			 sizeof(fi->host->csr.generation)))
-                ret = -EFAULT;
-        if (copy_to_user(int2ptr(req->req.sendb), &status,
-                sizeof(status)))
-                ret = -EFAULT;
-        kfree(data);
-        if (ret >= 0) {
-                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
-        }
-        return ret;
+		ret = -EFAULT;
+	if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
+		ret = -EFAULT;
+	kfree(data);
+	if (ret >= 0) {
+		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
+	}
+	return ret;
 }
 
 static int update_config_rom(struct file_info *fi, struct pending_request *req)
 {
-        int ret=sizeof(struct raw1394_request);
-        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
-        if (!data) return -ENOMEM;
-        if (copy_from_user(data,int2ptr(req->req.sendb),
-                req->req.length)) {
-                ret= -EFAULT;
-        } else {
-                int status = hpsb_update_config_rom(fi->host,
-                        data, req->req.length,
-                        (unsigned char) req->req.misc);
-                if (copy_to_user(int2ptr(req->req.recvb),
-                        &status, sizeof(status)))
-                        ret = -ENOMEM;
-        }
-        kfree(data);
-        if (ret >= 0) {
-                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+	int ret = sizeof(struct raw1394_request);
+	quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
+		ret = -EFAULT;
+	} else {
+		int status = hpsb_update_config_rom(fi->host,
+						    data, req->req.length,
+						    (unsigned char)req->req.
+						    misc);
+		if (copy_to_user
+		    (int2ptr(req->req.recvb), &status, sizeof(status)))
+			ret = -ENOMEM;
+	}
+	kfree(data);
+	if (ret >= 0) {
+		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
 		fi->cfgrom_upd = 1;
-        }
-        return ret;
+	}
+	return ret;
 }
 
 static int modify_config_rom(struct file_info *fi, struct pending_request *req)
@@ -1943,23 +2068,32 @@ static int modify_config_rom(struct file
 	int ret = 0;
 
 	if (req->req.misc == ~0) {
-		if (req->req.length == 0) return -EINVAL;
+		if (req->req.length == 0)
+			return -EINVAL;
 
 		/* Find an unused slot */
-		for (dr = 0; dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr]; dr++);
+		for (dr = 0;
+		     dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
+		     dr++) ;
 
-		if (dr == RAW1394_MAX_USER_CSR_DIRS) return -ENOMEM;
+		if (dr == RAW1394_MAX_USER_CSR_DIRS)
+			return -ENOMEM;
 
-		fi->csr1212_dirs[dr] = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
-		if (!fi->csr1212_dirs[dr]) return -ENOMEM;
+		fi->csr1212_dirs[dr] =
+		    csr1212_new_directory(CSR1212_KV_ID_VENDOR);
+		if (!fi->csr1212_dirs[dr])
+			return -ENOMEM;
 	} else {
 		dr = req->req.misc;
-		if (!fi->csr1212_dirs[dr]) return -EINVAL;
+		if (!fi->csr1212_dirs[dr])
+			return -EINVAL;
 
 		/* Delete old stuff */
-		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		for (dentry =
+		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
 		     dentry; dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv,
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
+							     root_kv,
 							     dentry->kv);
 		}
 
@@ -1980,7 +2114,8 @@ static int modify_config_rom(struct file
 		return -ENOMEM;
 	}
 
-	cache->filled_head = kmalloc(sizeof(struct csr1212_cache_region), GFP_KERNEL);
+	cache->filled_head =
+	    kmalloc(sizeof(struct csr1212_cache_region), GFP_KERNEL);
 	if (!cache->filled_head) {
 		csr1212_release_keyval(fi->csr1212_dirs[dr]);
 		fi->csr1212_dirs[dr] = NULL;
@@ -1994,11 +2129,11 @@ static int modify_config_rom(struct file
 		csr1212_release_keyval(fi->csr1212_dirs[dr]);
 		fi->csr1212_dirs[dr] = NULL;
 		CSR1212_FREE(cache);
-		ret= -EFAULT;
+		ret = -EFAULT;
 	} else {
 		cache->len = req->req.length;
 		cache->filled_head->offset_start = 0;
-		cache->filled_head->offset_end = cache->size -1;
+		cache->filled_head->offset_end = cache->size - 1;
 
 		cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
 
@@ -2010,17 +2145,20 @@ static int modify_config_rom(struct file
 		}
 
 		/* attach top level items to the root directory */
-		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		for (dentry =
+		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
 		     ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
-			ret = csr1212_attach_keyval_to_directory(fi->host->csr.rom->root_kv,
-								 dentry->kv);
+			ret =
+			    csr1212_attach_keyval_to_directory(fi->host->csr.
+							       rom->root_kv,
+							       dentry->kv);
 		}
 
 		if (ret == CSR1212_SUCCESS) {
 			ret = hpsb_update_config_rom_image(fi->host);
 
 			if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
-						    &dr, sizeof(dr))) {
+						     &dr, sizeof(dr))) {
 				ret = -ENOMEM;
 			}
 		}
@@ -2034,9 +2172,11 @@ static int modify_config_rom(struct file
 		free_pending_request(req);
 		return sizeof(struct raw1394_request);
 	} else {
-		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		for (dentry =
+		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
 		     dentry; dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv,
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
+							     root_kv,
 							     dentry->kv);
 		}
 		csr1212_release_keyval(fi->csr1212_dirs[dr]);
@@ -2047,133 +2187,132 @@ static int modify_config_rom(struct file
 
 static int state_connected(struct file_info *fi, struct pending_request *req)
 {
-        int node = req->req.address >> 48;
+	int node = req->req.address >> 48;
+
+	req->req.error = RAW1394_ERROR_NONE;
+
+	switch (req->req.type) {
+
+	case RAW1394_REQ_ECHO:
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+
+	case RAW1394_REQ_ISO_SEND:
+		return handle_iso_send(fi, req, node);
 
-        req->req.error = RAW1394_ERROR_NONE;
+	case RAW1394_REQ_ARM_REGISTER:
+		return arm_register(fi, req);
 
-        switch (req->req.type) {
+	case RAW1394_REQ_ARM_UNREGISTER:
+		return arm_unregister(fi, req);
 
-        case RAW1394_REQ_ECHO:
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-
-        case RAW1394_REQ_ISO_SEND:
-                return handle_iso_send(fi, req, node);
-
-        case RAW1394_REQ_ARM_REGISTER:
-                return arm_register(fi, req);
-
-        case RAW1394_REQ_ARM_UNREGISTER:
-                return arm_unregister(fi, req);
-
-        case RAW1394_REQ_ARM_SET_BUF:
-                return arm_set_buf(fi, req);
-
-        case RAW1394_REQ_ARM_GET_BUF:
-                return arm_get_buf(fi, req);
-
-        case RAW1394_REQ_RESET_NOTIFY:
-                return reset_notification(fi, req);
-
-        case RAW1394_REQ_ISO_LISTEN:
-                handle_iso_listen(fi, req);
-                return sizeof(struct raw1394_request);
-
-        case RAW1394_REQ_FCP_LISTEN:
-                handle_fcp_listen(fi, req);
-                return sizeof(struct raw1394_request);
-
-        case RAW1394_REQ_RESET_BUS:
-                if (req->req.misc == RAW1394_LONG_RESET) {
-                        DBGMSG("busreset called (type: LONG)");
-                        hpsb_reset_bus(fi->host, LONG_RESET);
-                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                        return sizeof(struct raw1394_request);
-                }
-                if (req->req.misc == RAW1394_SHORT_RESET) {
-                        DBGMSG("busreset called (type: SHORT)");
-                        hpsb_reset_bus(fi->host, SHORT_RESET);
-                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                        return sizeof(struct raw1394_request);
-                }
-                /* error EINVAL (22) invalid argument */
-                return (-EINVAL);
-        case RAW1394_REQ_GET_ROM:
-                return get_config_rom(fi, req);
+	case RAW1394_REQ_ARM_SET_BUF:
+		return arm_set_buf(fi, req);
 
-        case RAW1394_REQ_UPDATE_ROM:
-                return update_config_rom(fi, req);
+	case RAW1394_REQ_ARM_GET_BUF:
+		return arm_get_buf(fi, req);
+
+	case RAW1394_REQ_RESET_NOTIFY:
+		return reset_notification(fi, req);
+
+	case RAW1394_REQ_ISO_LISTEN:
+		handle_iso_listen(fi, req);
+		return sizeof(struct raw1394_request);
+
+	case RAW1394_REQ_FCP_LISTEN:
+		handle_fcp_listen(fi, req);
+		return sizeof(struct raw1394_request);
+
+	case RAW1394_REQ_RESET_BUS:
+		if (req->req.misc == RAW1394_LONG_RESET) {
+			DBGMSG("busreset called (type: LONG)");
+			hpsb_reset_bus(fi->host, LONG_RESET);
+			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
+			return sizeof(struct raw1394_request);
+		}
+		if (req->req.misc == RAW1394_SHORT_RESET) {
+			DBGMSG("busreset called (type: SHORT)");
+			hpsb_reset_bus(fi->host, SHORT_RESET);
+			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
+			return sizeof(struct raw1394_request);
+		}
+		/* error EINVAL (22) invalid argument */
+		return (-EINVAL);
+	case RAW1394_REQ_GET_ROM:
+		return get_config_rom(fi, req);
+
+	case RAW1394_REQ_UPDATE_ROM:
+		return update_config_rom(fi, req);
 
 	case RAW1394_REQ_MODIFY_ROM:
 		return modify_config_rom(fi, req);
-        }
+	}
+
+	if (req->req.generation != get_hpsb_generation(fi->host)) {
+		req->req.error = RAW1394_ERROR_GENERATION;
+		req->req.generation = get_hpsb_generation(fi->host);
+		req->req.length = 0;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	switch (req->req.type) {
+	case RAW1394_REQ_PHYPACKET:
+		return write_phypacket(fi, req);
+	case RAW1394_REQ_ASYNC_SEND:
+		return handle_async_send(fi, req);
+	}
+
+	if (req->req.length == 0) {
+		req->req.error = RAW1394_ERROR_INVALID_ARG;
+		queue_complete_req(req);
+		return sizeof(struct raw1394_request);
+	}
+
+	return handle_async_request(fi, req, node);
+}
+
+static ssize_t raw1394_write(struct file *file, const char __user * buffer,
+			     size_t count, loff_t * offset_is_ignored)
+{
+	struct file_info *fi = (struct file_info *)file->private_data;
+	struct pending_request *req;
+	ssize_t retval = 0;
+
+	if (count != sizeof(struct raw1394_request)) {
+		return -EINVAL;
+	}
+
+	req = alloc_pending_request();
+	if (req == NULL) {
+		return -ENOMEM;
+	}
+	req->file_info = fi;
 
-        if (req->req.generation != get_hpsb_generation(fi->host)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = get_hpsb_generation(fi->host);
-                req->req.length = 0;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        switch (req->req.type) {
-        case RAW1394_REQ_PHYPACKET:
-                return write_phypacket(fi, req);
-        case RAW1394_REQ_ASYNC_SEND:
-                return handle_async_send(fi, req);
-        }
-
-        if (req->req.length == 0) {
-                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                queue_complete_req(req);
-                return sizeof(struct raw1394_request);
-        }
-
-        return handle_async_request(fi, req, node);
-}
-
-
-static ssize_t raw1394_write(struct file *file, const char __user *buffer, size_t count,
-                     loff_t *offset_is_ignored)
-{
-        struct file_info *fi = (struct file_info *)file->private_data;
-        struct pending_request *req;
-        ssize_t retval = 0;
-
-        if (count != sizeof(struct raw1394_request)) {
-                return -EINVAL;
-        }
-
-        req = alloc_pending_request();
-        if (req == NULL) {
-                return -ENOMEM;
-        }
-        req->file_info = fi;
-
-        if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
-                free_pending_request(req);
-                return -EFAULT;
-        }
-
-        switch (fi->state) {
-        case opened:
-                retval = state_opened(fi, req);
-                break;
-
-        case initialized:
-                retval = state_initialized(fi, req);
-                break;
-
-        case connected:
-                retval = state_connected(fi, req);
-                break;
-        }
-
-        if (retval < 0) {
-                free_pending_request(req);
-        }
+	if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
+		free_pending_request(req);
+		return -EFAULT;
+	}
+
+	switch (fi->state) {
+	case opened:
+		retval = state_opened(fi, req);
+		break;
+
+	case initialized:
+		retval = state_initialized(fi, req);
+		break;
+
+	case connected:
+		retval = state_connected(fi, req);
+		break;
+	}
+
+	if (retval < 0) {
+		free_pending_request(req);
+	}
 
-        return retval;
+	return retval;
 }
 
 /* rawiso operations */
@@ -2185,8 +2324,8 @@ static inline int __rawiso_event_in_queu
 	struct pending_request *req;
 
 	list_for_each_entry(req, &fi->req_complete, list)
-		if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
-			return 1;
+	    if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
+		return 1;
 
 	return 0;
 }
@@ -2200,7 +2339,8 @@ static void queue_rawiso_event(struct fi
 
 	/* only one ISO activity event may be in the queue */
 	if (!__rawiso_event_in_queue(fi)) {
-		struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC);
+		struct pending_request *req =
+		    __alloc_pending_request(SLAB_ATOMIC);
 
 		if (req) {
 			req->file_info = fi;
@@ -2220,11 +2360,11 @@ static void queue_rawiso_event(struct fi
 static void rawiso_activity_cb(struct hpsb_iso *iso)
 {
 	unsigned long flags;
-        struct host_info *hi;
+	struct host_info *hi;
 	struct file_info *fi;
 
-        spin_lock_irqsave(&host_info_lock, flags);
-        hi = find_host_info(iso->host);
+	spin_lock_irqsave(&host_info_lock, flags);
+	hi = find_host_info(iso->host);
 
 	if (hi != NULL) {
 		list_for_each_entry(fi, &hi->file_info_list, list) {
@@ -2237,7 +2377,8 @@ static void rawiso_activity_cb(struct hp
 }
 
 /* helper function - gather all the kernel iso status bits for returning to user-space */
-static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat)
+static void raw1394_iso_fill_status(struct hpsb_iso *iso,
+				    struct raw1394_iso_status *stat)
 {
 	stat->config.data_buf_size = iso->buf_size;
 	stat->config.buf_packets = iso->buf_packets;
@@ -2249,7 +2390,7 @@ static void raw1394_iso_fill_status(stru
 	stat->xmit_cycle = iso->xmit_cycle;
 }
 
-static int raw1394_iso_xmit_init(struct file_info *fi, void __user *uaddr)
+static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr)
 {
 	struct raw1394_iso_status stat;
 
@@ -2281,7 +2422,7 @@ static int raw1394_iso_xmit_init(struct 
 	return 0;
 }
 
-static int raw1394_iso_recv_init(struct file_info *fi, void __user *uaddr)
+static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr)
 {
 	struct raw1394_iso_status stat;
 
@@ -2295,7 +2436,7 @@ static int raw1394_iso_recv_init(struct 
 					    stat.config.data_buf_size,
 					    stat.config.buf_packets,
 					    stat.config.channel,
- 					    stat.config.dma_mode,
+					    stat.config.dma_mode,
 					    stat.config.irq_interval,
 					    rawiso_activity_cb);
 	if (!fi->iso_handle)
@@ -2309,7 +2450,7 @@ static int raw1394_iso_recv_init(struct 
 	return 0;
 }
 
-static int raw1394_iso_get_status(struct file_info *fi, void __user *uaddr)
+static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
 {
 	struct raw1394_iso_status stat;
 	struct hpsb_iso *iso = fi->iso_handle;
@@ -2325,7 +2466,7 @@ static int raw1394_iso_get_status(struct
 }
 
 /* copy N packet_infos out of the ringbuffer into user-supplied array */
-static int raw1394_iso_recv_packets(struct file_info *fi, void __user *uaddr)
+static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr)
 {
 	struct raw1394_iso_packets upackets;
 	unsigned int packet = fi->iso_handle->first_packet;
@@ -2338,15 +2479,16 @@ static int raw1394_iso_recv_packets(stru
 		return -EINVAL;
 
 	/* ensure user-supplied buffer is accessible and big enough */
-	if (verify_area(VERIFY_WRITE, upackets.infos,
-		       upackets.n_packets * sizeof(struct raw1394_iso_packet_info)))
+	if (!access_ok(VERIFY_WRITE, upackets.infos,
+			upackets.n_packets *
+			sizeof(struct raw1394_iso_packet_info)))
 		return -EFAULT;
 
 	/* copy the packet_infos out */
 	for (i = 0; i < upackets.n_packets; i++) {
 		if (__copy_to_user(&upackets.infos[i],
-				  &fi->iso_handle->infos[packet],
-				  sizeof(struct raw1394_iso_packet_info)))
+				   &fi->iso_handle->infos[packet],
+				   sizeof(struct raw1394_iso_packet_info)))
 			return -EFAULT;
 
 		packet = (packet + 1) % fi->iso_handle->buf_packets;
@@ -2356,7 +2498,7 @@ static int raw1394_iso_recv_packets(stru
 }
 
 /* copy N packet_infos from user to ringbuffer, and queue them for transmission */
-static int raw1394_iso_send_packets(struct file_info *fi, void __user *uaddr)
+static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
 {
 	struct raw1394_iso_packets upackets;
 	int i, rv;
@@ -2368,8 +2510,9 @@ static int raw1394_iso_send_packets(stru
 		return -EINVAL;
 
 	/* ensure user-supplied buffer is accessible and big enough */
-	if (verify_area(VERIFY_READ, upackets.infos,
-		       upackets.n_packets * sizeof(struct raw1394_iso_packet_info)))
+	if (!access_ok(VERIFY_READ, upackets.infos,
+			upackets.n_packets *
+			sizeof(struct raw1394_iso_packet_info)))
 		return -EFAULT;
 
 	/* copy the infos structs in and queue the packets */
@@ -2377,7 +2520,7 @@ static int raw1394_iso_send_packets(stru
 		struct raw1394_iso_packet_info info;
 
 		if (__copy_from_user(&info, &upackets.infos[i],
-				    sizeof(struct raw1394_iso_packet_info)))
+				     sizeof(struct raw1394_iso_packet_info)))
 			return -EFAULT;
 
 		rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
@@ -2410,14 +2553,15 @@ static int raw1394_mmap(struct file *fil
 }
 
 /* ioctl is only used for rawiso operations */
-static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int raw1394_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
 {
 	struct file_info *fi = file->private_data;
 	void __user *argp = (void __user *)arg;
 
-	switch(fi->iso_state) {
+	switch (fi->iso_state) {
 	case RAW1394_ISO_INACTIVE:
-		switch(cmd) {
+		switch (cmd) {
 		case RAW1394_IOC_ISO_XMIT_INIT:
 			return raw1394_iso_xmit_init(fi, argp);
 		case RAW1394_IOC_ISO_RECV_INIT:
@@ -2427,34 +2571,42 @@ static int raw1394_ioctl(struct inode *i
 		}
 		break;
 	case RAW1394_ISO_RECV:
-		switch(cmd) {
-		case RAW1394_IOC_ISO_RECV_START: {
-			/* copy args from user-space */
-			int args[3];
-			if (copy_from_user(&args[0], argp, sizeof(args)))
-				return -EFAULT;
-			return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]);
-		}
+		switch (cmd) {
+		case RAW1394_IOC_ISO_RECV_START:{
+				/* copy args from user-space */
+				int args[3];
+				if (copy_from_user
+				    (&args[0], argp, sizeof(args)))
+					return -EFAULT;
+				return hpsb_iso_recv_start(fi->iso_handle,
+							   args[0], args[1],
+							   args[2]);
+			}
 		case RAW1394_IOC_ISO_XMIT_RECV_STOP:
 			hpsb_iso_stop(fi->iso_handle);
 			return 0;
 		case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-			return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
+			return hpsb_iso_recv_listen_channel(fi->iso_handle,
+							    arg);
 		case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-			return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
-		case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: {
-			/* copy the u64 from user-space */
-			u64 mask;
-			if (copy_from_user(&mask, argp, sizeof(mask)))
-				return -EFAULT;
-			return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask);
-		}
+			return hpsb_iso_recv_unlisten_channel(fi->iso_handle,
+							      arg);
+		case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
+				/* copy the u64 from user-space */
+				u64 mask;
+				if (copy_from_user(&mask, argp, sizeof(mask)))
+					return -EFAULT;
+				return hpsb_iso_recv_set_channel_mask(fi->
+								      iso_handle,
+								      mask);
+			}
 		case RAW1394_IOC_ISO_GET_STATUS:
 			return raw1394_iso_get_status(fi, argp);
 		case RAW1394_IOC_ISO_RECV_PACKETS:
 			return raw1394_iso_recv_packets(fi, argp);
 		case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-			return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
+			return hpsb_iso_recv_release_packets(fi->iso_handle,
+							     arg);
 		case RAW1394_IOC_ISO_RECV_FLUSH:
 			return hpsb_iso_recv_flush(fi->iso_handle);
 		case RAW1394_IOC_ISO_SHUTDOWN:
@@ -2466,14 +2618,16 @@ static int raw1394_ioctl(struct inode *i
 		}
 		break;
 	case RAW1394_ISO_XMIT:
-		switch(cmd) {
-		case RAW1394_IOC_ISO_XMIT_START: {
-			/* copy two ints from user-space */
-			int args[2];
-			if (copy_from_user(&args[0], argp, sizeof(args)))
-				return -EFAULT;
-			return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]);
-		}
+		switch (cmd) {
+		case RAW1394_IOC_ISO_XMIT_START:{
+				/* copy two ints from user-space */
+				int args[2];
+				if (copy_from_user
+				    (&args[0], argp, sizeof(args)))
+					return -EFAULT;
+				return hpsb_iso_xmit_start(fi->iso_handle,
+							   args[0], args[1]);
+			}
 		case RAW1394_IOC_ISO_XMIT_SYNC:
 			return hpsb_iso_xmit_sync(fi->iso_handle);
 		case RAW1394_IOC_ISO_XMIT_RECV_STOP:
@@ -2498,270 +2652,304 @@ static int raw1394_ioctl(struct inode *i
 	return -EINVAL;
 }
 
-static unsigned int raw1394_poll(struct file *file, poll_table *pt)
+static unsigned int raw1394_poll(struct file *file, poll_table * pt)
 {
-        struct file_info *fi = file->private_data;
-        unsigned int mask = POLLOUT | POLLWRNORM;
+	struct file_info *fi = file->private_data;
+	unsigned int mask = POLLOUT | POLLWRNORM;
 
-        poll_wait(file, &fi->poll_wait_complete, pt);
+	poll_wait(file, &fi->poll_wait_complete, pt);
 
-        spin_lock_irq(&fi->reqlists_lock);
-        if (!list_empty(&fi->req_complete)) {
-                mask |= POLLIN | POLLRDNORM;
-        }
-        spin_unlock_irq(&fi->reqlists_lock);
+	spin_lock_irq(&fi->reqlists_lock);
+	if (!list_empty(&fi->req_complete)) {
+		mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irq(&fi->reqlists_lock);
 
-        return mask;
+	return mask;
 }
 
 static int raw1394_open(struct inode *inode, struct file *file)
 {
-        struct file_info *fi;
+	struct file_info *fi;
+
+	fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
+	if (fi == NULL)
+		return -ENOMEM;
+
+	memset(fi, 0, sizeof(struct file_info));
+	fi->notification = (u8) RAW1394_NOTIFY_ON;	/* busreset notification */
 
-        fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
-        if (fi == NULL)
-                return -ENOMEM;
-
-        memset(fi, 0, sizeof(struct file_info));
-        fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
-
-        INIT_LIST_HEAD(&fi->list);
-        fi->state = opened;
-        INIT_LIST_HEAD(&fi->req_pending);
-        INIT_LIST_HEAD(&fi->req_complete);
-        sema_init(&fi->complete_sem, 0);
-        spin_lock_init(&fi->reqlists_lock);
-        init_waitqueue_head(&fi->poll_wait_complete);
-        INIT_LIST_HEAD(&fi->addr_list);
+	INIT_LIST_HEAD(&fi->list);
+	fi->state = opened;
+	INIT_LIST_HEAD(&fi->req_pending);
+	INIT_LIST_HEAD(&fi->req_complete);
+	sema_init(&fi->complete_sem, 0);
+	spin_lock_init(&fi->reqlists_lock);
+	init_waitqueue_head(&fi->poll_wait_complete);
+	INIT_LIST_HEAD(&fi->addr_list);
 
-        file->private_data = fi;
+	file->private_data = fi;
 
-        return 0;
+	return 0;
 }
 
 static int raw1394_release(struct inode *inode, struct file *file)
 {
-        struct file_info *fi = file->private_data;
-        struct list_head *lh;
-        struct pending_request *req;
-        int done = 0, i, fail = 0;
-        int retval = 0;
-        struct list_head *entry;
-        struct arm_addr  *addr = NULL;
-        struct host_info *hi;
-        struct file_info *fi_hlp = NULL;
-        struct arm_addr  *arm_addr = NULL;
-        int another_host;
+	struct file_info *fi = file->private_data;
+	struct list_head *lh;
+	struct pending_request *req;
+	int done = 0, i, fail = 0;
+	int retval = 0;
+	struct list_head *entry;
+	struct arm_addr *addr = NULL;
+	struct host_info *hi;
+	struct file_info *fi_hlp = NULL;
+	struct arm_addr *arm_addr = NULL;
+	int another_host;
 	int csr_mod = 0;
 
 	if (fi->iso_state != RAW1394_ISO_INACTIVE)
 		raw1394_iso_shutdown(fi);
 
-        for (i = 0; i < 64; i++) {
-                if (fi->listen_channels & (1ULL << i)) {
-                        hpsb_unlisten_channel(&raw1394_highlevel, fi->host, i);
-                }
-        }
-
-        spin_lock_irq(&host_info_lock);
-        fi->listen_channels = 0;
-        spin_unlock_irq(&host_info_lock);
-
-        fail = 0;
-        /* set address-entries invalid */
-        spin_lock_irq(&host_info_lock);
-
-        while (!list_empty(&fi->addr_list)) {
-                another_host = 0;
-                lh = fi->addr_list.next;
-                addr = list_entry(lh, struct arm_addr, addr_list);
-                /* another host with valid address-entry containing
-                   same addressrange? */
-                list_for_each_entry(hi, &host_info_list, list) {
-                        if (hi->host != fi->host) {
-                                list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                                        entry = fi_hlp->addr_list.next;
-                                        while (entry != &(fi_hlp->addr_list)) {
-                                                arm_addr = list_entry(entry,
-                                                        struct arm_addr, addr_list);
-                                                if (arm_addr->start ==
-                                                        addr->start) {
-                                                        DBGMSG("raw1394_release: "
-                                                        "another host ownes "
-                                                        "same addressrange");
-                                                        another_host = 1;
-                                                        break;
-                                                }
-                                                entry = entry->next;
-                                        }
-                                        if (another_host) {
-                                                break;
-                                        }
-                                }
-                        }
-                }
-                if (!another_host) {
-                        DBGMSG("raw1394_release: call hpsb_arm_unregister");
-                        retval = hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, addr->start);
-                        if (!retval) {
-                                ++fail;
-                                printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
-                        }
-                }
-                DBGMSG("raw1394_release: delete addr_entry from list");
-                list_del(&addr->addr_list);
-                vfree(addr->addr_space_buffer);
-                kfree(addr);
-        } /* while */
-        spin_unlock_irq(&host_info_lock);
-        if (fail > 0) {
-                printk(KERN_ERR "raw1394: during addr_list-release "
-                        "error(s) occurred \n");
-        }
-
-        while (!done) {
-                spin_lock_irq(&fi->reqlists_lock);
-
-                while (!list_empty(&fi->req_complete)) {
-                        lh = fi->req_complete.next;
-                        list_del(lh);
-
-                        req = list_entry(lh, struct pending_request, list);
-
-                        free_pending_request(req);
-                }
+	for (i = 0; i < 64; i++) {
+		if (fi->listen_channels & (1ULL << i)) {
+			hpsb_unlisten_channel(&raw1394_highlevel, fi->host, i);
+		}
+	}
+
+	spin_lock_irq(&host_info_lock);
+	fi->listen_channels = 0;
+	spin_unlock_irq(&host_info_lock);
+
+	fail = 0;
+	/* set address-entries invalid */
+	spin_lock_irq(&host_info_lock);
+
+	while (!list_empty(&fi->addr_list)) {
+		another_host = 0;
+		lh = fi->addr_list.next;
+		addr = list_entry(lh, struct arm_addr, addr_list);
+		/* another host with valid address-entry containing
+		   same addressrange? */
+		list_for_each_entry(hi, &host_info_list, list) {
+			if (hi->host != fi->host) {
+				list_for_each_entry(fi_hlp, &hi->file_info_list,
+						    list) {
+					entry = fi_hlp->addr_list.next;
+					while (entry != &(fi_hlp->addr_list)) {
+						arm_addr = list_entry(entry,
+								      struct
+								      arm_addr,
+								      addr_list);
+						if (arm_addr->start ==
+						    addr->start) {
+							DBGMSG
+							    ("raw1394_release: "
+							     "another host ownes "
+							     "same addressrange");
+							another_host = 1;
+							break;
+						}
+						entry = entry->next;
+					}
+					if (another_host) {
+						break;
+					}
+				}
+			}
+		}
+		if (!another_host) {
+			DBGMSG("raw1394_release: call hpsb_arm_unregister");
+			retval =
+			    hpsb_unregister_addrspace(&raw1394_highlevel,
+						      fi->host, addr->start);
+			if (!retval) {
+				++fail;
+				printk(KERN_ERR
+				       "raw1394_release arm_Unregister failed\n");
+			}
+		}
+		DBGMSG("raw1394_release: delete addr_entry from list");
+		list_del(&addr->addr_list);
+		vfree(addr->addr_space_buffer);
+		kfree(addr);
+	}			/* while */
+	spin_unlock_irq(&host_info_lock);
+	if (fail > 0) {
+		printk(KERN_ERR "raw1394: during addr_list-release "
+		       "error(s) occurred \n");
+	}
+
+	while (!done) {
+		spin_lock_irq(&fi->reqlists_lock);
 
-                if (list_empty(&fi->req_pending)) done = 1;
+		while (!list_empty(&fi->req_complete)) {
+			lh = fi->req_complete.next;
+			list_del(lh);
 
-                spin_unlock_irq(&fi->reqlists_lock);
+			req = list_entry(lh, struct pending_request, list);
 
-                if (!done) down_interruptible(&fi->complete_sem);
-        }
+			free_pending_request(req);
+		}
+
+		if (list_empty(&fi->req_pending))
+			done = 1;
+
+		spin_unlock_irq(&fi->reqlists_lock);
+
+		if (!done)
+			down_interruptible(&fi->complete_sem);
+	}
 
 	/* Remove any sub-trees left by user space programs */
 	for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
 		struct csr1212_dentry *dentry;
-		if (!fi->csr1212_dirs[i]) continue;
-		for (dentry = fi->csr1212_dirs[i]->value.directory.dentries_head;
-		     dentry; dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv, dentry->kv);
+		if (!fi->csr1212_dirs[i])
+			continue;
+		for (dentry =
+		     fi->csr1212_dirs[i]->value.directory.dentries_head; dentry;
+		     dentry = dentry->next) {
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
+							     root_kv,
+							     dentry->kv);
 		}
 		csr1212_release_keyval(fi->csr1212_dirs[i]);
 		fi->csr1212_dirs[i] = NULL;
 		csr_mod = 1;
 	}
 
-	if ((csr_mod || fi->cfgrom_upd) && hpsb_update_config_rom_image(fi->host) < 0)
-		HPSB_ERR("Failed to generate Configuration ROM image for host %d", fi->host->id);
-
-        if (fi->state == connected) {
-                spin_lock_irq(&host_info_lock);
-                list_del(&fi->list);
-                spin_unlock_irq(&host_info_lock);
+	if ((csr_mod || fi->cfgrom_upd)
+	    && hpsb_update_config_rom_image(fi->host) < 0)
+		HPSB_ERR
+		    ("Failed to generate Configuration ROM image for host %d",
+		     fi->host->id);
+
+	if (fi->state == connected) {
+		spin_lock_irq(&host_info_lock);
+		list_del(&fi->list);
+		spin_unlock_irq(&host_info_lock);
 
 		put_device(&fi->host->device);
-        }
+	}
 
-        kfree(fi);
+	kfree(fi);
 
-        return 0;
+	return 0;
 }
 
-
 /*** HOTPLUG STUFF **********************************************************/
 /*
  * Export information about protocols/devices supported by this driver.
  */
 static struct ieee1394_device_id raw1394_id_table[] = {
 	{
-		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
-		.version	= AVC_SW_VERSION_ENTRY & 0xffffff
-	},
+	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+	 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+	 .version = AVC_SW_VERSION_ENTRY & 0xffffff},
+	{
+	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+	 .version = CAMERA_SW_VERSION_ENTRY & 0xffffff},
 	{
-		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-		.specifier_id	= CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-		.version	= CAMERA_SW_VERSION_ENTRY & 0xffffff
-	},
-	{ }
+	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+	 .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff},
+	{
+	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+	 .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff},
+	{}
 };
 
 MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
 
 static struct hpsb_protocol_driver raw1394_driver = {
-	.name		= "raw1394 Driver",
-	.id_table	= raw1394_id_table,
-	.driver		= {
-		.name	= "raw1394",
-		.bus	= &ieee1394_bus_type,
-	},
+	.name = "raw1394 Driver",
+	.id_table = raw1394_id_table,
+	.driver = {
+		   .name = "raw1394",
+		   .bus = &ieee1394_bus_type,
+		   },
 };
 
-
 /******************************************************************************/
 
-
 static struct hpsb_highlevel raw1394_highlevel = {
-	.name =		RAW1394_DEVICE_NAME,
-        .add_host =    add_host,
-        .remove_host = remove_host,
-        .host_reset =  host_reset,
-        .iso_receive = iso_receive,
-        .fcp_request = fcp_request,
+	.name = RAW1394_DEVICE_NAME,
+	.add_host = add_host,
+	.remove_host = remove_host,
+	.host_reset = host_reset,
+	.iso_receive = iso_receive,
+	.fcp_request = fcp_request,
 };
 
 static struct cdev raw1394_cdev;
 static struct file_operations raw1394_fops = {
-	.owner =	THIS_MODULE,
-        .read =		raw1394_read,
-        .write =	raw1394_write,
-	.mmap =         raw1394_mmap,
-	.ioctl =        raw1394_ioctl,
-        .poll =		raw1394_poll,
-        .open =		raw1394_open,
-        .release =	raw1394_release,
+	.owner = THIS_MODULE,
+	.read = raw1394_read,
+	.write = raw1394_write,
+	.mmap = raw1394_mmap,
+	.ioctl = raw1394_ioctl,
+	.poll = raw1394_poll,
+	.open = raw1394_open,
+	.release = raw1394_release,
 };
 
 static int __init init_raw1394(void)
 {
-	int ret;
+	int ret = 0;
 
 	hpsb_register_highlevel(&raw1394_highlevel);
 
-        devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
-			S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
+	if (IS_ERR(class_simple_device_add(hpsb_protocol_class, MKDEV(
+		IEEE1394_MAJOR,	IEEE1394_MINOR_BLOCK_RAW1394 * 16), 
+		NULL, RAW1394_DEVICE_NAME))) {
+		ret = -EFAULT;
+		goto out_unreg;
+	}
+	
+	devfs_mk_cdev(MKDEV(
+		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
+		S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
 
 	cdev_init(&raw1394_cdev, &raw1394_fops);
 	raw1394_cdev.owner = THIS_MODULE;
 	kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
 	ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
 	if (ret) {
-                HPSB_ERR("raw1394 failed to register minor device block");
-                devfs_remove(RAW1394_DEVICE_NAME);
-                hpsb_unregister_highlevel(&raw1394_highlevel);
-                return ret;
-        }
+		HPSB_ERR("raw1394 failed to register minor device block");
+		goto out_dev;
+	}
 
-        HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
+	HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
 
 	ret = hpsb_register_protocol(&raw1394_driver);
 	if (ret) {
 		HPSB_ERR("raw1394: failed to register protocol");
 		cdev_del(&raw1394_cdev);
-		devfs_remove(RAW1394_DEVICE_NAME);
-		hpsb_unregister_highlevel(&raw1394_highlevel);
-		return ret;
+		goto out_dev;
 	}
 
-        return 0;
+	goto out;
+
+out_dev:
+	devfs_remove(RAW1394_DEVICE_NAME);
+	class_simple_device_remove(MKDEV(
+		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+out_unreg:
+	hpsb_unregister_highlevel(&raw1394_highlevel);
+out:
+	return ret;
 }
 
 static void __exit cleanup_raw1394(void)
 {
-	hpsb_unregister_protocol(&raw1394_driver);
+	class_simple_device_remove(MKDEV(
+		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
 	cdev_del(&raw1394_cdev);
-        devfs_remove(RAW1394_DEVICE_NAME);
-        hpsb_unregister_highlevel(&raw1394_highlevel);
+	devfs_remove(RAW1394_DEVICE_NAME);
+	hpsb_unregister_highlevel(&raw1394_highlevel);
+	hpsb_unregister_protocol(&raw1394_driver);
 }
 
 module_init(init_raw1394);
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -64,7 +64,10 @@
 #include <asm/system.h>
 #include <asm/scatterlist.h>
 
-#include "../scsi/scsi.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 
 #include "csr1212.h"
@@ -224,12 +227,12 @@ static void sbp2scsi_complete_all_comman
 					   u32 status);
 
 static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
-				      u32 scsi_status, Scsi_Cmnd *SCpnt,
-				      void (*done)(Scsi_Cmnd *));
+				      u32 scsi_status, struct scsi_cmnd *SCpnt,
+				      void (*done)(struct scsi_cmnd *));
 
-static Scsi_Host_Template scsi_driver_template;
+static struct scsi_host_template scsi_driver_template;
 
-const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
+static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
 
 static void sbp2_host_reset(struct hpsb_host *host);
 
@@ -373,7 +376,7 @@ static void sbp2_free_packet(struct hpsb
 /* This is much like hpsb_node_write(), except it ignores the response
  * subaction and returns immediately. Can be used from interrupts.
  */
-int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
+static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
 				quadlet_t *buffer, size_t length)
 {
 	struct hpsb_packet *packet;
@@ -520,8 +523,8 @@ static struct sbp2_command_info *sbp2uti
  */
 static struct sbp2_command_info *sbp2util_allocate_command_orb(
 		struct scsi_id_instance_data *scsi_id,
-		Scsi_Cmnd *Current_SCpnt,
-		void (*Current_done)(Scsi_Cmnd *))
+		struct scsi_cmnd *Current_SCpnt,
+		void (*Current_done)(struct scsi_cmnd *))
 {
 	struct list_head *lh;
 	struct sbp2_command_info *command = NULL;
@@ -742,7 +745,8 @@ static struct scsi_id_instance_data *sbp
 	list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids);
 
 	/* Register our host with the SCSI stack. */
-	scsi_host = scsi_host_alloc(&scsi_driver_template, 0);
+	scsi_host = scsi_host_alloc(&scsi_driver_template,
+				    sizeof (unsigned long));
 	if (!scsi_host) {
 		SBP2_ERR("failed to register scsi host");
 		goto failed_alloc;
@@ -902,9 +906,13 @@ alloc_fail:
 	 * connected to the sbp2 device being removed. That host would
 	 * have a certain amount of time to relogin before the sbp2 device
 	 * allows someone else to login instead. One second makes sense. */
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(HZ);
-
+	msleep_interruptible(1000);
+	if (signal_pending(current)) {
+		SBP2_WARN("aborting sbp2_start_device due to event");
+		sbp2_remove_device(scsi_id);
+		return -EINTR;
+	}
+	
 	/*
 	 * Login to the sbp-2 device
 	 */
@@ -1521,8 +1529,9 @@ static void sbp2_parse_unit_directory(st
 
 				SBP2_DEBUG("sbp2_management_agent_addr = %x",
 					   (unsigned int) management_agent_addr);
-			} else
+			} else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
 				scsi_id->sbp2_device_type_and_lun = kv->value.immediate;
+			}
 			break;
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
@@ -1613,6 +1622,8 @@ static void sbp2_parse_unit_directory(st
 		scsi_id->sbp2_unit_characteristics = unit_characteristics;
 		scsi_id->sbp2_firmware_revision = firmware_revision;
 		scsi_id->workarounds = workarounds;
+		if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
+			scsi_id->sbp2_device_type_and_lun = ud->lun;
 	}
 }
 
@@ -1700,14 +1711,14 @@ static int sbp2_create_command_orb(struc
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
 				   void *scsi_request_buffer,
-				   unsigned char scsi_dir)
+				   enum dma_data_direction dma_dir)
+
 {
 	struct sbp2scsi_host_info *hi = scsi_id->hi;
 	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
 	struct sbp2_command_orb *command_orb = &command->command_orb;
 	struct sbp2_unrestricted_page_table *scatter_gather_element =
 		&command->scatter_gather_element[0];
-	int dma_dir = scsi_to_pci_dma_dir (scsi_dir);
 	u32 sg_count, sg_len, orb_direction;
 	dma_addr_t sg_addr;
 	int i;
@@ -1730,22 +1741,22 @@ static int sbp2_create_command_orb(struc
 	 * Get the direction of the transfer. If the direction is unknown, then use our
 	 * goofy table as a back-up.
 	 */
-	switch (scsi_dir) {
-		case SCSI_DATA_NONE:
+	switch (dma_dir) {
+		case DMA_NONE:
 			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
 			break;
-		case SCSI_DATA_WRITE:
+		case DMA_TO_DEVICE:
 			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
 			break;
-		case SCSI_DATA_READ:
+		case DMA_FROM_DEVICE:
 			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
 			break;
-		case SCSI_DATA_UNKNOWN:
+		case DMA_BIDIRECTIONAL:
 		default:
 			SBP2_ERR("SCSI data transfer direction not specified. "
 				 "Update the SBP2 direction table in sbp2.h if "
 				 "necessary for your application");
-			print_command (scsi_cmd);
+			__scsi_print_command(scsi_cmd);
 			orb_direction = sbp2scsi_direction_table[*scsi_cmd];
 			break;
 	}
@@ -2031,7 +2042,8 @@ static int sbp2_link_orb_command(struct 
  * This function is called in order to begin a regular SBP-2 command.
  */
 static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
-			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+			     struct scsi_cmnd *SCpnt,
+			     void (*done)(struct scsi_cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
 	unsigned int request_bufflen = SCpnt->request_bufflen;
@@ -2040,7 +2052,7 @@ static int sbp2_send_command(struct scsi
 	SBP2_DEBUG("sbp2_send_command");
 #if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
 	printk("[scsi command]\n   ");
-	print_command (cmd);
+	scsi_print_command(SCpnt);
 #endif
 	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
 	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
@@ -2233,7 +2245,7 @@ static unsigned int sbp2_status_to_sense
  * response data translations for the SCSI stack
  */
 static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, 
-				     Scsi_Cmnd *SCpnt)
+				     struct scsi_cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
 	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
@@ -2312,7 +2324,7 @@ static int sbp2_handle_status_write(stru
 	struct sbp2scsi_host_info *hi;
 	struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
 	u32 id;
-	Scsi_Cmnd *SCpnt = NULL;
+	struct scsi_cmnd *SCpnt = NULL;
 	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
 	struct sbp2_command_info *command;
 
@@ -2454,7 +2466,8 @@ static int sbp2_handle_status_write(stru
  * This routine is the main request entry routine for doing I/O. It is
  * called from the scsi stack directly.
  */
-static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
+				 void (*done)(struct scsi_cmnd *))
 {
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
@@ -2550,9 +2563,8 @@ static void sbp2scsi_complete_all_comman
 					    PCI_DMA_BIDIRECTIONAL);
 		sbp2util_mark_command_completed(scsi_id, command);
 		if (command->Current_SCpnt) {
-			void (*done)(Scsi_Cmnd *) = command->Current_done;
 			command->Current_SCpnt->result = status << 16;
-			done (command->Current_SCpnt);
+			command->Current_done(command->Current_SCpnt);
 		}
 	}
 
@@ -2565,8 +2577,8 @@ static void sbp2scsi_complete_all_comman
  * This can be called in interrupt context.
  */
 static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
-				      u32 scsi_status, Scsi_Cmnd *SCpnt,
-				      void (*done)(Scsi_Cmnd *))
+				      u32 scsi_status, struct scsi_cmnd *SCpnt,
+				      void (*done)(struct scsi_cmnd *))
 {
 	unsigned long flags;
 
@@ -2611,8 +2623,8 @@ static void sbp2scsi_complete_command(st
 			 * Debug stuff
 			 */
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 1
-			print_command (SCpnt->cmnd);
-			print_sense("bh", SCpnt);
+			scsi_print_command(SCpnt);
+			scsi_print_sense("bh", SCpnt);
 #endif
 
 			break;
@@ -2620,7 +2632,7 @@ static void sbp2scsi_complete_command(st
 		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
 			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
 			SCpnt->result = DID_NO_CONNECT << 16;
-			print_command (SCpnt->cmnd);
+			scsi_print_command(SCpnt);
 			break;
 
 		case SBP2_SCSI_STATUS_CONDITION_MET:
@@ -2628,7 +2640,7 @@ static void sbp2scsi_complete_command(st
 		case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
 			SBP2_ERR("Bad SCSI status = %x", scsi_status);
 			SCpnt->result = DID_ERROR << 16;
-			print_command (SCpnt->cmnd);
+			scsi_print_command(SCpnt);
 			break;
 
 		default:
@@ -2688,7 +2700,7 @@ static int sbp2scsi_slave_configure (str
  * Called by scsi stack when something has really gone wrong.  Usually
  * called when a command has timed-out for some reason.
  */
-static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
+static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
 {
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
@@ -2696,7 +2708,7 @@ static int sbp2scsi_abort (Scsi_Cmnd *SC
 	struct sbp2_command_info *command;
 
 	SBP2_ERR("aborting sbp2 command");
-	print_command (SCpnt->cmnd);
+	scsi_print_command(SCpnt);
 
 	if (scsi_id) {
 
@@ -2717,9 +2729,8 @@ static int sbp2scsi_abort (Scsi_Cmnd *SC
 						    PCI_DMA_BIDIRECTIONAL);
 			sbp2util_mark_command_completed(scsi_id, command);
 			if (command->Current_SCpnt) {
-				void (*done)(Scsi_Cmnd *) = command->Current_done;
 				command->Current_SCpnt->result = DID_ABORT << 16;
-				done (command->Current_SCpnt);
+				command->Current_done(command->Current_SCpnt);
 			}
 		}
 
@@ -2736,7 +2747,7 @@ static int sbp2scsi_abort (Scsi_Cmnd *SC
 /*
  * Called by scsi stack when something has really gone wrong.
  */
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
+static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
 {
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
@@ -2789,7 +2800,7 @@ MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME
 MODULE_LICENSE("GPL");
 
 /* SCSI host template */
-static Scsi_Host_Template scsi_driver_template = {
+static struct scsi_host_template scsi_driver_template = {
 	.module =			THIS_MODULE,
 	.name =				"SBP-2 IEEE-1394",
 	.proc_name =			SBP2_DEVICE_NAME,
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -324,8 +324,8 @@ struct sbp2_command_info {
 	struct list_head list;
 	struct sbp2_command_orb command_orb ____cacheline_aligned;
 	dma_addr_t command_orb_dma ____cacheline_aligned;
-	Scsi_Cmnd *Current_SCpnt;
-	void (*Current_done)(Scsi_Cmnd *);
+	struct scsi_cmnd *Current_SCpnt;
+	void (*Current_done)(struct scsi_cmnd *);
 
 	/* Also need s/g structure for each sbp2 command */
 	struct sbp2_unrestricted_page_table scatter_gather_element[SG_ALL] ____cacheline_aligned;
@@ -434,8 +434,8 @@ static void sbp2util_remove_command_orb_
 static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb);
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt);
 static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id,
-							  Scsi_Cmnd *Current_SCpnt,
-							  void (*Current_done)(Scsi_Cmnd *));
+							  struct scsi_cmnd *Current_SCpnt,
+							  void (*Current_done)(struct scsi_cmnd *));
 static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id,
 		struct sbp2_command_info *command);
 
@@ -466,14 +466,16 @@ static int sbp2_create_command_orb(struc
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
 				   void *scsi_request_buffer,
-				   unsigned char scsi_dir);
+				   enum dma_data_direction dma_dir);
 static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
 				 struct sbp2_command_info *command);
 static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
-			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+			     struct scsi_cmnd *SCpnt,
+			     void (*done)(struct scsi_cmnd *));
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
-static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
+static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
+				     struct scsi_cmnd *SCpnt);
 static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
 				      struct unit_directory *ud);
 static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id);
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -16,14 +16,30 @@
  * You 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.
+ *
+ * NOTES:
+ *
+ * jds -- add private data to file to keep track of iso contexts associated
+ * with each open -- so release won't kill all iso transfers.
+ * 
+ * Damien Douxchamps: Fix failure when the number of DMA pages per frame is
+ * one.
+ * 
+ * ioctl return codes:
+ * EFAULT is only for invalid address for the argp
+ * EINVAL for out of range values
+ * EBUSY when trying to use an already used resource
+ * ESRCH when trying to free/stop a not used resource
+ * EAGAIN for resource allocation failure that could perhaps succeed later
+ * ENOTTY for unsupported ioctl request
+ *
  */
 
-/* jds -- add private data to file to keep track of iso contexts associated
-   with each open -- so release won't kill all iso transfers */
-
-/* Damien Douxchamps: Fix failure when the number of DMA pages per frame is
-   one */
-
+/* Markus Tavenrath <speedygoo@speedygoo.de> :
+   - fixed checks for valid buffer-numbers in video1394_icotl
+   - changed the ways the dma prg's are used, now it's possible to use
+     even a single dma buffer
+*/
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -101,6 +117,7 @@ struct dma_iso_ctx {
 	struct it_dma_prg **it_prg;
 
 	unsigned int *buffer_status;
+	unsigned int *buffer_prg_assignment;
         struct timeval *buffer_time; /* time when the buffer was received */
 	unsigned int *last_used_cmd; /* For ISO Transmit with
 					variable sized packets only ! */
@@ -146,8 +163,8 @@ printk(level "video1394: " fmt "\n" , ##
 #define PRINT(level, card, fmt, args...) \
 printk(level "video1394_%d: " fmt "\n" , card , ## args)
 
-void wakeup_dma_ir_ctx(unsigned long l);
-void wakeup_dma_it_ctx(unsigned long l);
+static void wakeup_dma_ir_ctx(unsigned long l);
+static void wakeup_dma_it_ctx(unsigned long l);
 
 static struct hpsb_highlevel video1394_highlevel;
 
@@ -169,23 +186,14 @@ static int free_dma_iso_ctx(struct dma_i
 		kfree(d->prg_reg);
 	}
 
-	if (d->ir_prg)
-		kfree(d->ir_prg);
-
-	if (d->it_prg)
-		kfree(d->it_prg);
-
-	if (d->buffer_status)
-		kfree(d->buffer_status);
-	if (d->buffer_time)
-		kfree(d->buffer_time);
-	if (d->last_used_cmd)
-		kfree(d->last_used_cmd);
-	if (d->next_buffer)
-		kfree(d->next_buffer);
-
+	kfree(d->ir_prg);
+	kfree(d->it_prg);
+	kfree(d->buffer_status);
+	kfree(d->buffer_prg_assignment);
+	kfree(d->buffer_time);
+	kfree(d->last_used_cmd);
+	kfree(d->next_buffer);
 	list_del(&d->link);
-
 	kfree(d);
 
 	return 0;
@@ -219,7 +227,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, 
 	/* Init the regions for easy cleanup */
 	dma_region_init(&d->dma);
 
-	if (dma_region_alloc(&d->dma, d->num_desc * d->buf_size, ohci->dev,
+	if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
 			     PCI_DMA_BIDIRECTIONAL)) {
 		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
 		free_dma_iso_ctx(d);
@@ -331,6 +339,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, 
 
 	d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
 				   GFP_KERNEL);
+	d->buffer_prg_assignment = kmalloc(d->num_desc * sizeof(unsigned int),
+				   GFP_KERNEL);
 	d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval),
 				   GFP_KERNEL);
 	d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int),
@@ -343,6 +353,11 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, 
 		free_dma_iso_ctx(d);
 		return NULL;
 	}
+	if (d->buffer_prg_assignment == NULL) {
+		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_prg_assignment");
+		free_dma_iso_ctx(d);
+		return NULL;
+	}
 	if (d->buffer_time == NULL) {
 		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_time");
 		free_dma_iso_ctx(d);
@@ -359,6 +374,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, 
 		return NULL;
 	}
 	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
+	memset(d->buffer_prg_assignment, 0, d->num_desc * sizeof(unsigned int));
 	memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval));
 	memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int));
 	memset(d->next_buffer, -1, d->num_desc * sizeof(int));
@@ -368,7 +384,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, 
 	PRINT(KERN_INFO, ohci->host->id, "Iso %s DMA: %d buffers "
 	      "of size %d allocated for a frame size %d, each with %d prgs",
 	      (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
-	      d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
+	      d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
 
 	return d;
 }
@@ -383,11 +399,36 @@ static void reset_ir_status(struct dma_i
 	d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
 }
 
+static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
+{
+	struct dma_cmd *ir_prg = d->ir_prg[n];
+	unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
+	int i;
+
+	d->buffer_prg_assignment[n] = buffer;
+
+	ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
+  	                        (unsigned long)d->dma.kvirt));
+	ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+				(buf + 4) - (unsigned long)d->dma.kvirt));
+
+	for (i=2;i<d->nb_cmd-1;i++) {
+		ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+						(buf+(i-1)*PAGE_SIZE) -
+						(unsigned long)d->dma.kvirt));
+	}
+
+	ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+				  DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
+	ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+				  (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
+}
+
 static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
 {
 	struct dma_cmd *ir_prg = d->ir_prg[n];
 	struct dma_prog_region *ir_reg = &d->prg_reg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
+	unsigned long buf = (unsigned long)d->dma.kvirt;
 	int i;
 
 	/* the first descriptor will read only 4 bytes */
@@ -487,7 +528,7 @@ find_ctx(struct list_head *list, int typ
 	return NULL;
 }
 
-void wakeup_dma_ir_ctx(unsigned long l)
+static void wakeup_dma_ir_ctx(unsigned long l)
 {
 	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
 	int i;
@@ -497,7 +538,7 @@ void wakeup_dma_ir_ctx(unsigned long l)
 	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;
+			d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
 			do_gettimeofday(&d->buffer_time[i]);
 		}
 	}
@@ -560,7 +601,7 @@ static inline void put_timestamp(struct 
 #endif
 }
 
-void wakeup_dma_it_ctx(unsigned long l)
+static void wakeup_dma_it_ctx(unsigned long l)
 {
 	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
 	struct ti_ohci *ohci = d->ohci;
@@ -574,7 +615,7 @@ void wakeup_dma_it_ctx(unsigned long l)
 			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;
+			d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
 		}
 	}
 
@@ -584,11 +625,25 @@ void wakeup_dma_it_ctx(unsigned long l)
 		wake_up_interruptible(&d->waitq);
 }
 
+static void reprogram_dma_it_prg(struct dma_iso_ctx  *d, int n, int buffer)
+{
+	struct it_dma_prg *it_prg = d->it_prg[n];
+	unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
+	int i;
+
+	d->buffer_prg_assignment[n] = buffer;
+	for (i=0;i<d->nb_cmd;i++) {
+	  it_prg[i].end.address =
+		cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+			(buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
+	}
+}
+
 static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
 {
 	struct it_dma_prg *it_prg = d->it_prg[n];
 	struct dma_prog_region *it_reg = &d->prg_reg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
+	unsigned long buf = (unsigned long)d->dma.kvirt;
 	int i;
 	d->last_used_cmd[n] = d->nb_cmd - 1;
 	for (i=0;i<d->nb_cmd;i++) {
@@ -699,6 +754,17 @@ static void initialize_dma_it_ctx(struct
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
 }
 
+static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
+					      unsigned int buffer)
+{
+	unsigned long flags;
+	unsigned int ret;
+	spin_lock_irqsave(&d->lock, flags);
+	ret = d->buffer_status[buffer];
+	spin_unlock_irqrestore(&d->lock, flags);
+	return ret;
+}
+
 static int __video1394_ioctl(struct file *file,
 			     unsigned int cmd, unsigned long arg)
 {
@@ -723,7 +789,12 @@ static int __video1394_ioctl(struct file
 		/* if channel < 0, find lowest available one */
 		if (v.channel < 0) {
 		    mask = (u64)0x1;
-		    for (i=0; i<ISO_CHANNELS; i++) {
+		    for (i=0; ; i++) {
+			if (i == ISO_CHANNELS) {
+			    PRINT(KERN_ERR, ohci->host->id, 
+				  "No free channel found");
+			    return EAGAIN;
+			}
 			if (!(ohci->ISO_channel_usage & mask)) {
 			    v.channel = i;
 			    PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
@@ -731,53 +802,51 @@ static int __video1394_ioctl(struct file
 			}
 			mask = mask << 1;
 		    }
-		}
-
-		if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
+		} else if (v.channel >= ISO_CHANNELS) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Iso channel %d out of bounds", v.channel);
-			return -EFAULT;
+			return -EINVAL;
+		} else {
+			mask = (u64)0x1<<v.channel;
 		}
-		mask = (u64)0x1<<v.channel;
-		printk("mask: %08X%08X usage: %08X%08X\n",
-		       (u32)(mask>>32),(u32)(mask&0xffffffff),
-		       (u32)(ohci->ISO_channel_usage>>32),
-		       (u32)(ohci->ISO_channel_usage&0xffffffff));
+		PRINT(KERN_INFO, ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
+			(u32)(mask>>32),(u32)(mask&0xffffffff),
+			(u32)(ohci->ISO_channel_usage>>32),
+			(u32)(ohci->ISO_channel_usage&0xffffffff));
 		if (ohci->ISO_channel_usage & mask) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Channel %d is already taken", v.channel);
-			return -EFAULT;
+			return -EBUSY;
 		}
-		ohci->ISO_channel_usage |= mask;
 
 		if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Invalid %d length buffer requested",v.buf_size);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Invalid %d buffers requested",v.nb_buffers);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "%d buffers of size %d bytes is too big",
 			      v.nb_buffers, v.buf_size);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
 			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
-					      v.nb_buffers, v.buf_size,
+					      v.nb_buffers + 1, v.buf_size,
 					      v.channel, 0);
 
 			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->host->id,
 				      "Couldn't allocate ir context");
-				return -EFAULT;
+				return -EAGAIN;
 			}
 			initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
 
@@ -792,13 +861,13 @@ static int __video1394_ioctl(struct file
 		}
 		else {
 			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
-					      v.nb_buffers, v.buf_size,
+					      v.nb_buffers + 1, v.buf_size,
 					      v.channel, v.packet_size);
 
 			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->host->id,
 				      "Couldn't allocate it context");
-				return -EFAULT;
+				return -EAGAIN;
 			}
 			initialize_dma_it_ctx(d, v.sync_tag,
 					      v.syt_offset, v.flags);
@@ -814,8 +883,12 @@ static int __video1394_ioctl(struct file
 			      v.channel);
 		}
 
-		if (copy_to_user(argp, &v, sizeof(v)))
+		if (copy_to_user((void *)arg, &v, sizeof(v))) {
+			/* FIXME : free allocated dma resources */
 			return -EFAULT;
+		}
+		
+		ohci->ISO_channel_usage |= mask;
 
 		return 0;
 	}
@@ -829,16 +902,16 @@ static int __video1394_ioctl(struct file
 		if (copy_from_user(&channel, argp, sizeof(int)))
 			return -EFAULT;
 
-		if (channel<0 || channel>(ISO_CHANNELS-1)) {
+		if (channel < 0 || channel >= ISO_CHANNELS) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Iso channel %d out of bound", channel);
-			return -EFAULT;
+			return -EINVAL;
 		}
 		mask = (u64)0x1<<channel;
 		if (!(ohci->ISO_channel_usage & mask)) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Channel %d is not being used", channel);
-			return -EFAULT;
+			return -ESRCH;
 		}
 
 		/* Mark this channel as unused */
@@ -849,7 +922,7 @@ static int __video1394_ioctl(struct file
 		else
 			d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
 
-		if (d == NULL) return -EFAULT;
+		if (d == NULL) return -ESRCH;
 		PRINT(KERN_INFO, ohci->host->id, "Iso context %d "
 		      "stop talking on channel %d", d->ctx, channel);
 		free_dma_iso_ctx(d);
@@ -860,6 +933,7 @@ static int __video1394_ioctl(struct file
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
+		int next_prg;
 
 		if (copy_from_user(&v, argp, sizeof(v)))
 			return -EFAULT;
@@ -867,10 +941,10 @@ static int __video1394_ioctl(struct file
 		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
 		if (d == NULL) return -EFAULT;
 
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+		if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d out of range",v.buffer);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		spin_lock_irqsave(&d->lock,flags);
@@ -879,17 +953,19 @@ static int __video1394_ioctl(struct file
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d is already used",v.buffer);
 			spin_unlock_irqrestore(&d->lock,flags);
-			return -EFAULT;
+			return -EBUSY;
 		}
 
 		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
 
+		next_prg = (d->last_buffer + 1) % d->num_desc;
 		if (d->last_buffer>=0)
 			d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0)
+				cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
 					& 0xfffffff0) | 0x1);
 
-		d->last_buffer = v.buffer;
+		d->last_buffer = next_prg;
+		reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
 
 		d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
 
@@ -901,7 +977,7 @@ static int __video1394_ioctl(struct file
 
 			/* Tell the controller where the first program is */
 			reg_write(ohci, d->cmdPtr,
-				dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1);
+				  dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
 
 			/* Run IR context */
 			reg_write(ohci, d->ctrlSet, 0x8000);
@@ -922,7 +998,7 @@ static int __video1394_ioctl(struct file
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
-		int i;
+		int i = 0;
 
 		if (copy_from_user(&v, argp, sizeof(v)))
 			return -EFAULT;
@@ -930,10 +1006,10 @@ static int __video1394_ioctl(struct file
 		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
 		if (d == NULL) return -EFAULT;
 
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+		if ((v.buffer<0) || (v.buffer>d->num_desc - 1)) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d out of range",v.buffer);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		/*
@@ -952,31 +1028,20 @@ static int __video1394_ioctl(struct file
 			    return -EINTR;
 			}
 
-#if 1
-			while (d->buffer_status[v.buffer]!=
-			      VIDEO1394_BUFFER_READY) {
-				spin_unlock_irqrestore(&d->lock, flags);
-				interruptible_sleep_on(&d->waitq);
-				spin_lock_irqsave(&d->lock, flags);
-				if (signal_pending(current)) {
-					spin_unlock_irqrestore(&d->lock,flags);
-					return -EINTR;
-				}
-			}
-#else
-			if (wait_event_interruptible(d->waitq,
-						     d->buffer_status[v.buffer]
-						     == VIDEO1394_BUFFER_READY)
-			    == -ERESTARTSYS)
-				return -EINTR;
-#endif
+			spin_unlock_irqrestore(&d->lock, flags);
+			wait_event_interruptible(d->waitq,
+					video1394_buffer_state(d, v.buffer) ==
+					 VIDEO1394_BUFFER_READY);
+			if (signal_pending(current))
+                                return -EINTR;
+			spin_lock_irqsave(&d->lock, flags);
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			break;
 		default:
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d is not queued",v.buffer);
 			spin_unlock_irqrestore(&d->lock, flags);
-			return -EFAULT;
+			return -ESRCH;
 		}
 
 		/* set time of buffer */
@@ -987,9 +1052,9 @@ static int __video1394_ioctl(struct file
 		 * Look ahead to see how many more buffers have been received
 		 */
 		i=0;
-		while (d->buffer_status[(v.buffer+1)%d->num_desc]==
+		while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
 		       VIDEO1394_BUFFER_READY) {
-			v.buffer=(v.buffer+1)%d->num_desc;
+			v.buffer=(v.buffer+1)%(d->num_desc - 1);
 			i++;
 		}
 		spin_unlock_irqrestore(&d->lock, flags);
@@ -1005,6 +1070,7 @@ static int __video1394_ioctl(struct file
 		struct video1394_wait v;
 		unsigned int *psizes = NULL;
 		struct dma_iso_ctx *d;
+		int next_prg;
 
 		if (copy_from_user(&v, argp, sizeof(v)))
 			return -EFAULT;
@@ -1012,10 +1078,10 @@ static int __video1394_ioctl(struct file
 		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
 		if (d == NULL) return -EFAULT;
 
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+		if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d out of range",v.buffer);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
@@ -1038,19 +1104,19 @@ static int __video1394_ioctl(struct file
 
 		spin_lock_irqsave(&d->lock,flags);
 
+		// last_buffer is last_prg
+		next_prg = (d->last_buffer + 1) % d->num_desc;
 		if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d is already used",v.buffer);
 			spin_unlock_irqrestore(&d->lock,flags);
-			if (psizes)
-				kfree(psizes);
-			return -EFAULT;
+			kfree(psizes);
+			return -EBUSY;
 		}
 
 		if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
 			initialize_dma_it_prg_var_packet_queue(
-				d, v.buffer, psizes,
-				ohci);
+				d, next_prg, psizes, ohci);
 		}
 
 		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
@@ -1058,16 +1124,17 @@ static int __video1394_ioctl(struct file
 		if (d->last_buffer >= 0) {
 			d->it_prg[d->last_buffer]
 				[ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
-					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
 						0) & 0xfffffff0) | 0x3);
 
 			d->it_prg[d->last_buffer]
 				[ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
-					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
 						0) & 0xfffffff0) | 0x3);
-			d->next_buffer[d->last_buffer] = v.buffer;
+			d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
 		}
-		d->last_buffer = v.buffer;
+		d->last_buffer = next_prg;
+		reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
 		d->next_buffer[d->last_buffer] = -1;
 
 		d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
@@ -1082,7 +1149,7 @@ static int __video1394_ioctl(struct file
 
 			/* Tell the controller where the first program is */
 			reg_write(ohci, d->cmdPtr,
-				dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3);
+				dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
 
 			/* Run IT context */
 			reg_write(ohci, d->ctrlSet, 0x8000);
@@ -1098,9 +1165,7 @@ static int __video1394_ioctl(struct file
 			}
 		}
 
-		if (psizes)
-			kfree(psizes);
-
+		kfree(psizes);
 		return 0;
 
 	}
@@ -1115,10 +1180,10 @@ static int __video1394_ioctl(struct file
 		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
 		if (d == NULL) return -EFAULT;
 
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+		if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) {
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d out of range",v.buffer);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		switch(d->buffer_status[v.buffer]) {
@@ -1126,29 +1191,20 @@ static int __video1394_ioctl(struct file
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			return 0;
 		case VIDEO1394_BUFFER_QUEUED:
-#if 1
-			while (d->buffer_status[v.buffer]!=
-			      VIDEO1394_BUFFER_READY) {
-				interruptible_sleep_on(&d->waitq);
-				if (signal_pending(current)) return -EINTR;
-			}
-#else
-			if (wait_event_interruptible(d->waitq,
-						     d->buffer_status[v.buffer]
-						     == VIDEO1394_BUFFER_READY)
-			    == -ERESTARTSYS)
+			wait_event_interruptible(d->waitq,
+					(d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
+			if (signal_pending(current))
 				return -EINTR;
-#endif
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			return 0;
 		default:
 			PRINT(KERN_ERR, ohci->host->id,
 			      "Buffer %d is not queued",v.buffer);
-			return -EFAULT;
+			return -ESRCH;
 		}
 	}
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 }
 
@@ -1170,7 +1226,7 @@ static long video1394_ioctl(struct file 
  *    But e.g. pte_alloc() does not work in modules ... :-(
  */
 
-int video1394_mmap(struct file *file, struct vm_area_struct *vma)
+static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
 	int res = -EINVAL;
@@ -1269,6 +1325,16 @@ static struct ieee1394_device_id video13
 		.specifier_id	= CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
 		.version	= CAMERA_SW_VERSION_ENTRY & 0xffffff
 	},
+        {
+                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+                .version        = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
+        },
+        {
+                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+                .version        = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
+        },
 	{ }
 };
 
@@ -1304,6 +1370,9 @@ static void video1394_add_host (struct h
 	hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
 
 	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
+	class_simple_device_add(hpsb_protocol_class, MKDEV(
+		IEEE1394_MAJOR,	minor), 
+		NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
 	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
 		       S_IFCHR | S_IRUSR | S_IWUSR,
 		       "%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
@@ -1314,9 +1383,12 @@ static void video1394_remove_host (struc
 {
 	struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
 
-	if (ohci)
+	if (ohci) {
+		class_simple_device_remove(MKDEV(IEEE1394_MAJOR, 
+			IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
 		devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-
+	}
+	
 	return;
 }
 
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -45,14 +45,11 @@
 #include "smi.h"
 #include "agent_priv.h"
 #include "mad_priv.h"
-
+#include "agent.h"
 
 spinlock_t ib_agent_port_list_lock;
 static LIST_HEAD(ib_agent_port_list);
 
-extern kmem_cache_t *ib_mad_cache;
-
-
 /*
  * Caller must hold ib_agent_port_list_lock
  */
@@ -66,14 +63,13 @@ __ib_get_agent_port(struct ib_device *de
 
 	if (device) {
 		list_for_each_entry(entry, &ib_agent_port_list, port_list) {
-			if (entry->dr_smp_agent->device == device &&
+			if (entry->smp_agent->device == device &&
 			    entry->port_num == port_num)
 				return entry;
 		}
 	} else {
 		list_for_each_entry(entry, &ib_agent_port_list, port_list) {
-			if ((entry->dr_smp_agent == mad_agent) ||
-			    (entry->lr_smp_agent == mad_agent) ||
+			if ((entry->smp_agent == mad_agent) ||
 			    (entry->perf_mgmt_agent == mad_agent))
 				return entry;
 		}
@@ -111,7 +107,7 @@ int smi_check_local_dr_smp(struct ib_smp
 		return 1;
 	}
 
-	return smi_check_local_smp(port_priv->dr_smp_agent, smp);
+	return smi_check_local_smp(port_priv->smp_agent, smp);
 }
 
 static int agent_mad_send(struct ib_mad_agent *mad_agent,
@@ -133,7 +129,6 @@ static int agent_mad_send(struct ib_mad_
 		goto out;
 	agent_send_wr->mad = mad_priv;
 
-	/* PCI mapping */
 	gather_list.addr = dma_map_single(mad_agent->device->dma_device,
 					  &mad_priv->mad,
 					  sizeof(mad_priv->mad),
@@ -231,10 +226,8 @@ int agent_send(struct ib_mad_private *ma
 	/* Get mad agent based on mgmt_class in MAD */
 	switch (mad->mad.mad.mad_hdr.mgmt_class) {
 		case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
-			mad_agent = port_priv->dr_smp_agent;
-			break;
 		case IB_MGMT_CLASS_SUBN_LID_ROUTED:
-			mad_agent = port_priv->lr_smp_agent;
+			mad_agent = port_priv->smp_agent;
 			break;
 		case IB_MGMT_CLASS_PERF_MGMT:
 			mad_agent = port_priv->perf_mgmt_agent;
@@ -267,7 +260,6 @@ static void agent_send_handler(struct ib
 	list_del(&agent_send_wr->send_list);
 	spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
 
-	/* Unmap PCI */
 	dma_unmap_single(mad_agent->device->dma_device,
 			 pci_unmap_addr(agent_send_wr, mapping),
 			 sizeof(agent_send_wr->mad->mad),
@@ -284,7 +276,6 @@ int ib_agent_port_open(struct ib_device 
 {
 	int ret;
 	struct ib_agent_port_private *port_priv;
-	struct ib_mad_reg_req reg_req;
 	unsigned long flags;
 
 	/* First, check if port already open for SMI */
@@ -308,35 +299,19 @@ int ib_agent_port_open(struct ib_device 
 	spin_lock_init(&port_priv->send_list_lock);
 	INIT_LIST_HEAD(&port_priv->send_posted_list);
 
-	/* Obtain MAD agent for directed route SM class */
-	reg_req.mgmt_class = IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE;
-	reg_req.mgmt_class_version = 1;
-
-	port_priv->dr_smp_agent = ib_register_mad_agent(device, port_num,
-							IB_QPT_SMI,
-							NULL, 0,
-						       &agent_send_handler,
-							NULL, NULL);
+	/* Obtain send only MAD agent for SM class (SMI QP) */
+	port_priv->smp_agent = ib_register_mad_agent(device, port_num,
+						     IB_QPT_SMI,
+						     NULL, 0,
+						    &agent_send_handler,
+						     NULL, NULL);
 
-	if (IS_ERR(port_priv->dr_smp_agent)) {
-		ret = PTR_ERR(port_priv->dr_smp_agent);
+	if (IS_ERR(port_priv->smp_agent)) {
+		ret = PTR_ERR(port_priv->smp_agent);
 		goto error2;
 	}
 
-	/* Obtain MAD agent for LID routed SM class */
-	reg_req.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	port_priv->lr_smp_agent = ib_register_mad_agent(device, port_num,
-							IB_QPT_SMI,
-							NULL, 0,
-						       &agent_send_handler,
-							NULL, NULL);
-	if (IS_ERR(port_priv->lr_smp_agent)) {
-		ret = PTR_ERR(port_priv->lr_smp_agent);
-		goto error3;
-	}
-
-	/* Obtain MAD agent for PerfMgmt class */
-	reg_req.mgmt_class = IB_MGMT_CLASS_PERF_MGMT;
+	/* Obtain send only MAD agent for PerfMgmt class (GSI QP) */
 	port_priv->perf_mgmt_agent = ib_register_mad_agent(device, port_num,
 							   IB_QPT_GSI,
 							   NULL, 0,
@@ -344,15 +319,15 @@ int ib_agent_port_open(struct ib_device 
 							   NULL, NULL);
 	if (IS_ERR(port_priv->perf_mgmt_agent)) {
 		ret = PTR_ERR(port_priv->perf_mgmt_agent);
-		goto error4;
+		goto error3;
 	}
 
-	port_priv->mr = ib_get_dma_mr(port_priv->dr_smp_agent->qp->pd,
+	port_priv->mr = ib_get_dma_mr(port_priv->smp_agent->qp->pd,
 				      IB_ACCESS_LOCAL_WRITE);
 	if (IS_ERR(port_priv->mr)) {
 		printk(KERN_ERR SPFX "Couldn't get DMA MR\n");
 		ret = PTR_ERR(port_priv->mr);
-		goto error5;
+		goto error4;
 	}
 
 	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
@@ -361,12 +336,10 @@ int ib_agent_port_open(struct ib_device 
 
 	return 0;
 
-error5:
-	ib_unregister_mad_agent(port_priv->perf_mgmt_agent);
 error4:
-	ib_unregister_mad_agent(port_priv->lr_smp_agent);
+	ib_unregister_mad_agent(port_priv->perf_mgmt_agent);
 error3:
-	ib_unregister_mad_agent(port_priv->dr_smp_agent);
+	ib_unregister_mad_agent(port_priv->smp_agent);
 error2:
 	kfree(port_priv);
 error1:
@@ -391,8 +364,7 @@ int ib_agent_port_close(struct ib_device
 	ib_dereg_mr(port_priv->mr);
 
 	ib_unregister_mad_agent(port_priv->perf_mgmt_agent);
-	ib_unregister_mad_agent(port_priv->lr_smp_agent);
-	ib_unregister_mad_agent(port_priv->dr_smp_agent);
+	ib_unregister_mad_agent(port_priv->smp_agent);
 	kfree(port_priv);
 
 	return 0;
diff --git a/drivers/infiniband/core/agent_priv.h b/drivers/infiniband/core/agent_priv.h
--- a/drivers/infiniband/core/agent_priv.h
+++ b/drivers/infiniband/core/agent_priv.h
@@ -55,8 +55,7 @@ struct ib_agent_port_private {
 	struct list_head send_posted_list;
 	spinlock_t send_list_lock;
 	int port_num;
-	struct ib_mad_agent *dr_smp_agent;    /* DR SM class */
-	struct ib_mad_agent *lr_smp_agent;    /* LR SM class */
+	struct ib_mad_agent *smp_agent;	      /* SM class */
 	struct ib_mad_agent *perf_mgmt_agent; /* PerfMgmt class */
 	struct ib_mr *mr;
 };
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -37,6 +37,8 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
+#include <ib_cache.h>
+
 #include "core_priv.h"
 
 struct ib_pkey_cache {
@@ -112,7 +114,7 @@ int ib_find_cached_gid(struct ib_device 
 		cache = device->cache.gid_cache[p];
 		for (i = 0; i < cache->table_len; ++i) {
 			if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
-				*port_num = p;
+				*port_num = p + start_port(device);
 				if (index)
 					*index = i;
 				ret = 0;
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -103,9 +103,8 @@ struct ib_fmr_pool {
 
 static inline u32 ib_fmr_hash(u64 first_page)
 {
-	return jhash_2words((u32) first_page,
-			    (u32) (first_page >> 32),
-			    0);
+	return jhash_2words((u32) first_page, (u32) (first_page >> 32), 0) &
+		(IB_FMR_HASH_SIZE - 1);
 }
 
 /* Caller must hold pool_lock */
@@ -443,7 +442,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys
 		list_add(&fmr->list, &pool->free_list);
 		spin_unlock_irqrestore(&pool->pool_lock, flags);
 
-		printk(KERN_WARNING "fmr_map returns %d",
+		printk(KERN_WARNING "fmr_map returns %d\n",
 		       result);
 
 		return ERR_PTR(result);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -33,15 +33,11 @@
  */
 
 #include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-
-#include <ib_mad.h>
 
 #include "mad_priv.h"
 #include "smi.h"
 #include "agent.h"
 
-
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("kernel IB MAD API");
 MODULE_AUTHOR("Hal Rosenstock");
@@ -69,6 +65,7 @@ static void cancel_mads(struct ib_mad_ag
 static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
 				    struct ib_mad_send_wc *mad_send_wc);
 static void timeout_sends(void *data);
+static void cancel_sends(void *data);
 static void local_completions(void *data);
 static int solicited_mad(struct ib_mad *mad);
 static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
@@ -342,6 +339,8 @@ struct ib_mad_agent *ib_register_mad_age
 	INIT_LIST_HEAD(&mad_agent_priv->local_list);
 	INIT_WORK(&mad_agent_priv->local_work, local_completions,
 		   mad_agent_priv);
+	INIT_LIST_HEAD(&mad_agent_priv->canceled_list);
+	INIT_WORK(&mad_agent_priv->canceled_work, cancel_sends, mad_agent_priv);
 	atomic_set(&mad_agent_priv->refcount, 1);
 	init_waitqueue_head(&mad_agent_priv->wait);
 
@@ -490,6 +489,7 @@ static void unregister_mad_agent(struct 
 	cancel_mads(mad_agent_priv);
 
 	port_priv = mad_agent_priv->qp_info->port_priv;
+
 	cancel_delayed_work(&mad_agent_priv->timed_work);
 	flush_workqueue(port_priv->wq);
 
@@ -643,7 +643,7 @@ static int handle_outgoing_dr_smp(struct
 				  struct ib_smp *smp,
 				  struct ib_send_wr *send_wr)
 {
-	int ret, alloc_flags, solicited;
+	int ret, solicited;
 	unsigned long flags;
 	struct ib_mad_local_private *local;
 	struct ib_mad_private *mad_priv;
@@ -663,11 +663,7 @@ static int handle_outgoing_dr_smp(struct
 	if (!ret || !device->process_mad)
 		goto out;
 
-	if (in_atomic() || irqs_disabled())
-		alloc_flags = GFP_ATOMIC;
-	else
-		alloc_flags = GFP_KERNEL;
-	local = kmalloc(sizeof *local, alloc_flags);
+	local = kmalloc(sizeof *local, GFP_ATOMIC);
 	if (!local) {
 		ret = -ENOMEM;
 		printk(KERN_ERR PFX "No memory for ib_mad_local_private\n");
@@ -675,7 +671,7 @@ static int handle_outgoing_dr_smp(struct
 	}
 	local->mad_priv = NULL;
 	local->recv_mad_agent = NULL;
-	mad_priv = kmem_cache_alloc(ib_mad_cache, alloc_flags);
+	mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_ATOMIC);
 	if (!mad_priv) {
 		ret = -ENOMEM;
 		printk(KERN_ERR PFX "No memory for local response MAD\n");
@@ -857,9 +853,7 @@ int ib_post_send_mad(struct ib_mad_agent
 		}
 
 		/* Allocate MAD send WR tracking structure */
-		mad_send_wr = kmalloc(sizeof *mad_send_wr,
-				      (in_atomic() || irqs_disabled()) ?
-				      GFP_ATOMIC : GFP_KERNEL);
+		mad_send_wr = kmalloc(sizeof *mad_send_wr, GFP_ATOMIC);
 		if (!mad_send_wr) {
 			printk(KERN_ERR PFX "No memory for "
 			       "ib_mad_send_wr_private\n");
@@ -1266,12 +1260,12 @@ static void remove_mad_reg_req(struct ib
 	}
 
 	port_priv = agent_priv->qp_info->port_priv;
+	mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class);
 	class = port_priv->version[
 			agent_priv->reg_req->mgmt_class_version].class;
 	if (!class)
 		goto vendor_check;
 
-	mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class);
 	method = class->method_table[mgmt_class];
 	if (method) {
 		/* Remove any methods for this mad agent */
@@ -1293,16 +1287,21 @@ static void remove_mad_reg_req(struct ib
 	}
 
 vendor_check:
+	if (!is_vendor_class(mgmt_class))
+		goto out;
+
+	/* normalize mgmt_class to vendor range 2 */
+	mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class);
 	vendor = port_priv->version[
 			agent_priv->reg_req->mgmt_class_version].vendor;
+
 	if (!vendor)
 		goto out;
 
-	mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class);
 	vendor_class = vendor->vendor_class[mgmt_class];
 	if (vendor_class) {
 		index = find_vendor_oui(vendor_class, agent_priv->reg_req->oui);
-		if (index == -1)
+		if (index < 0)
 			goto out;
 		method = vendor_class->method_table[index];
 		if (method) {
@@ -1598,7 +1597,8 @@ static void ib_mad_recv_done_handler(str
 			 DMA_FROM_DEVICE);
 
 	/* Setup MAD receive work completion from "normal" work completion */
-	recv->header.recv_wc.wc = wc;
+	recv->header.wc = *wc;
+	recv->header.recv_wc.wc = &recv->header.wc;
 	recv->header.recv_wc.mad_len = sizeof(struct ib_mad);
 	recv->header.recv_wc.recv_buf.mad = &recv->mad.mad;
 	recv->header.recv_wc.recv_buf.grh = &recv->grh;
@@ -1999,12 +1999,44 @@ find_send_by_wr_id(struct ib_mad_agent_p
 	return NULL;
 }
 
+void cancel_sends(void *data)
+{
+	struct ib_mad_agent_private *mad_agent_priv;
+	struct ib_mad_send_wr_private *mad_send_wr;
+	struct ib_mad_send_wc mad_send_wc;
+	unsigned long flags;
+
+	mad_agent_priv = data;
+
+	mad_send_wc.status = IB_WC_WR_FLUSH_ERR;
+	mad_send_wc.vendor_err = 0;
+
+	spin_lock_irqsave(&mad_agent_priv->lock, flags);
+	while (!list_empty(&mad_agent_priv->canceled_list)) {
+		mad_send_wr = list_entry(mad_agent_priv->canceled_list.next,
+					 struct ib_mad_send_wr_private,
+					 agent_list);
+
+		list_del(&mad_send_wr->agent_list);
+		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+
+		mad_send_wc.wr_id = mad_send_wr->wr_id;
+		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
+						   &mad_send_wc);
+
+		kfree(mad_send_wr);
+		if (atomic_dec_and_test(&mad_agent_priv->refcount))
+			wake_up(&mad_agent_priv->wait);
+		spin_lock_irqsave(&mad_agent_priv->lock, flags);
+	}
+	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+}
+
 void ib_cancel_mad(struct ib_mad_agent *mad_agent,
 		  u64 wr_id)
 {
 	struct ib_mad_agent_private *mad_agent_priv;
 	struct ib_mad_send_wr_private *mad_send_wr;
-	struct ib_mad_send_wc mad_send_wc;
 	unsigned long flags;
 
 	mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
@@ -2026,19 +2058,12 @@ void ib_cancel_mad(struct ib_mad_agent *
 	}
 
 	list_del(&mad_send_wr->agent_list);
+	list_add_tail(&mad_send_wr->agent_list, &mad_agent_priv->canceled_list);
 	adjust_timeout(mad_agent_priv);
 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 
-	mad_send_wc.status = IB_WC_WR_FLUSH_ERR;
-	mad_send_wc.vendor_err = 0;
-	mad_send_wc.wr_id = mad_send_wr->wr_id;
-	mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
-					   &mad_send_wc);
-
-	kfree(mad_send_wr);
-	if (atomic_dec_and_test(&mad_agent_priv->refcount))
-		wake_up(&mad_agent_priv->wait);
-
+	queue_work(mad_agent_priv->qp_info->port_priv->wq,
+		   &mad_agent_priv->canceled_work);
 out:
 	return;
 }
@@ -2186,7 +2211,6 @@ static int ib_mad_post_receive_mads(stru
 	recv_wr.next = NULL;
 	recv_wr.sg_list = &sg_list;
 	recv_wr.num_sge = 1;
-	recv_wr.recv_flags = IB_RECV_SIGNALED;
 
 	do {
 		/* Allocate and map receive buffer */
@@ -2259,7 +2283,6 @@ static void cleanup_recv_queue(struct ib
 		/* Remove from posted receive MAD list */
 		list_del(&mad_list->list);
 
-		/* Undo PCI mapping */
 		dma_unmap_single(qp_info->port_priv->device->dma_device,
 				 pci_unmap_addr(&recv->header, mapping),
 				 sizeof(struct ib_mad_private) -
@@ -2381,7 +2404,6 @@ static int create_mad_qp(struct ib_mad_q
 	qp_init_attr.send_cq = qp_info->port_priv->cq;
 	qp_init_attr.recv_cq = qp_info->port_priv->cq;
 	qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
-	qp_init_attr.rq_sig_type = IB_SIGNAL_ALL_WR;
 	qp_init_attr.cap.max_send_wr = IB_MAD_QP_SEND_SIZE;
 	qp_init_attr.cap.max_recv_wr = IB_MAD_QP_RECV_SIZE;
 	qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG;
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -58,8 +58,8 @@
 #define MAX_MGMT_CLASS		80
 #define MAX_MGMT_VERSION	8
 #define MAX_MGMT_OUI		8
-#define MAX_MGMT_VENDOR_RANGE2	IB_MGMT_CLASS_VENDOR_RANGE2_END - \
-				IB_MGMT_CLASS_VENDOR_RANGE2_START + 1
+#define MAX_MGMT_VENDOR_RANGE2	(IB_MGMT_CLASS_VENDOR_RANGE2_END - \
+				IB_MGMT_CLASS_VENDOR_RANGE2_START + 1)
 
 struct ib_mad_list_head {
 	struct list_head list;
@@ -69,6 +69,7 @@ struct ib_mad_list_head {
 struct ib_mad_private_header {
 	struct ib_mad_list_head mad_list;
 	struct ib_mad_recv_wc recv_wc;
+	struct ib_wc wc;
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 } __attribute__ ((packed));
 
@@ -95,6 +96,8 @@ struct ib_mad_agent_private {
 	unsigned long timeout;
 	struct list_head local_list;
 	struct work_struct local_work;
+	struct list_head canceled_list;
+	struct work_struct canceled_work;
 
 	atomic_t refcount;
 	wait_queue_head_t wait;
@@ -192,4 +195,6 @@ struct ib_mad_port_private {
 	struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE];
 };
 
+extern kmem_cache_t *ib_mad_cache;
+
 #endif	/* __IB_MAD_PRIV_H__ */
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -587,7 +587,7 @@ int ib_sa_path_rec_get(struct ib_device 
 
 	init_mad(query->sa_query.mad, agent);
 
-	query->sa_query.callback              = ib_sa_path_rec_callback;
+	query->sa_query.callback              = callback ? ib_sa_path_rec_callback : NULL;
 	query->sa_query.release               = ib_sa_path_rec_release;
 	query->sa_query.port                  = port;
 	query->sa_query.mad->mad_hdr.method   = IB_MGMT_METHOD_GET;
@@ -663,7 +663,7 @@ int ib_sa_mcmember_rec_query(struct ib_d
 
 	init_mad(query->sa_query.mad, agent);
 
-	query->sa_query.callback              = ib_sa_mcmember_rec_callback;
+	query->sa_query.callback              = callback ? ib_sa_mcmember_rec_callback : NULL;
 	query->sa_query.release               = ib_sa_mcmember_rec_release;
 	query->sa_query.port                  = port;
 	query->sa_query.mad->mad_hdr.method   = method;
@@ -698,20 +698,21 @@ static void send_handler(struct ib_mad_a
 	if (!query)
 		return;
 
-	switch (mad_send_wc->status) {
-	case IB_WC_SUCCESS:
-		/* No callback -- already got recv */
-		break;
-	case IB_WC_RESP_TIMEOUT_ERR:
-		query->callback(query, -ETIMEDOUT, NULL);
-		break;
-	case IB_WC_WR_FLUSH_ERR:
-		query->callback(query, -EINTR, NULL);
-		break;
-	default:
-		query->callback(query, -EIO, NULL);
-		break;
-	}
+	if (query->callback)
+		switch (mad_send_wc->status) {
+		case IB_WC_SUCCESS:
+			/* No callback -- already got recv */
+			break;
+		case IB_WC_RESP_TIMEOUT_ERR:
+			query->callback(query, -ETIMEDOUT, NULL);
+			break;
+		case IB_WC_WR_FLUSH_ERR:
+			query->callback(query, -EINTR, NULL);
+			break;
+		default:
+			query->callback(query, -EIO, NULL);
+			break;
+		}
 
 	dma_unmap_single(agent->device->dma_device,
 			 pci_unmap_addr(query, mapping),
@@ -736,7 +737,7 @@ static void recv_handler(struct ib_mad_a
 	query = idr_find(&query_idr, mad_recv_wc->wc->wr_id);
 	spin_unlock_irqrestore(&idr_lock, flags);
 
-	if (query) {
+	if (query && query->callback) {
 		if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
 			query->callback(query,
 					mad_recv_wc->recv_buf.mad->mad_hdr.status ?
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
--- a/drivers/infiniband/core/smi.c
+++ b/drivers/infiniband/core/smi.c
@@ -37,7 +37,7 @@
  */
 
 #include <ib_smi.h>
-
+#include "smi.h"
 
 /*
  * Fixup a directed route SMP for sending
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -389,15 +389,17 @@ static int ib_umad_reg_agent(struct ib_u
 	goto out;
 
 found:
-	req.mgmt_class         = ureq.mgmt_class;
-	req.mgmt_class_version = ureq.mgmt_class_version;
-	memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask);
-	memcpy(req.oui,         ureq.oui,         sizeof req.oui);
+	if (ureq.mgmt_class) {
+		req.mgmt_class         = ureq.mgmt_class;
+		req.mgmt_class_version = ureq.mgmt_class_version;
+		memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask);
+		memcpy(req.oui,         ureq.oui,         sizeof req.oui);
+	}
 
 	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
 				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
-				      &req, 0, send_handler, recv_handler,
-				      file);
+				      ureq.mgmt_class ? &req : NULL,
+				      0, send_handler, recv_handler, file);
 	if (IS_ERR(agent)) {
 		ret = PTR_ERR(agent);
 		goto out;
@@ -497,6 +499,7 @@ static int ib_umad_open(struct inode *in
 static int ib_umad_close(struct inode *inode, struct file *filp)
 {
 	struct ib_umad_file *file = filp->private_data;
+	struct ib_umad_packet *packet, *tmp;
 	int i;
 
 	for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
@@ -505,6 +508,9 @@ static int ib_umad_close(struct inode *i
 			ib_unregister_mad_agent(file->agent[i]);
 		}
 
+	list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
+		kfree(packet);
+
 	kfree(file);
 
 	return 0;
diff --git a/drivers/infiniband/hw/mthca/Makefile b/drivers/infiniband/hw/mthca/Makefile
--- a/drivers/infiniband/hw/mthca/Makefile
+++ b/drivers/infiniband/hw/mthca/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mth
 ib_mthca-y :=	mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \
 		mthca_allocator.o mthca_eq.o mthca_pd.o mthca_cq.o \
 		mthca_mr.o mthca_qp.o mthca_av.o mthca_mcg.o mthca_mad.o \
-		mthca_provider.o mthca_memfree.o
+		mthca_provider.o mthca_memfree.o mthca_uar.o
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -60,29 +60,36 @@ int mthca_create_ah(struct mthca_dev *de
 	u32 index = -1;
 	struct mthca_av *av = NULL;
 
-	ah->on_hca = 0;
+	ah->type = MTHCA_AH_PCI_POOL;
 
-	if (!atomic_read(&pd->sqp_count) &&
-	    !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
+	if (mthca_is_memfree(dev)) {
+		ah->av   = kmalloc(sizeof *ah->av, GFP_ATOMIC);
+		if (!ah->av)
+			return -ENOMEM;
+
+		ah->type = MTHCA_AH_KMALLOC;
+		av       = ah->av;
+	} else if (!atomic_read(&pd->sqp_count) &&
+		 !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
 		index = mthca_alloc(&dev->av_table.alloc);
 
 		/* fall back to allocate in host memory */
 		if (index == -1)
-			goto host_alloc;
+			goto on_hca_fail;
 
-		av = kmalloc(sizeof *av, GFP_KERNEL);
+		av = kmalloc(sizeof *av, GFP_ATOMIC);
 		if (!av)
-			goto host_alloc;
+			goto on_hca_fail;
 
-		ah->on_hca = 1;
+		ah->type = MTHCA_AH_ON_HCA;
 		ah->avdma  = dev->av_table.ddr_av_base +
 			index * MTHCA_AV_SIZE;
 	}
 
- host_alloc:
-	if (!ah->on_hca) {
+on_hca_fail:
+	if (ah->type == MTHCA_AH_PCI_POOL) {
 		ah->av = pci_pool_alloc(dev->av_table.pool,
-					SLAB_KERNEL, &ah->avdma);
+					SLAB_ATOMIC, &ah->avdma);
 		if (!ah->av)
 			return -ENOMEM;
 
@@ -123,7 +130,7 @@ int mthca_create_ah(struct mthca_dev *de
 			       j * 4, be32_to_cpu(((u32 *) av)[j]));
 	}
 
-	if (ah->on_hca) {
+	if (ah->type == MTHCA_AH_ON_HCA) {
 		memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE,
 			    av, MTHCA_AV_SIZE);
 		kfree(av);
@@ -134,12 +141,21 @@ int mthca_create_ah(struct mthca_dev *de
 
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
 {
-	if (ah->on_hca)
+	switch (ah->type) {
+	case MTHCA_AH_ON_HCA:
 		mthca_free(&dev->av_table.alloc,
  			   (ah->avdma - dev->av_table.ddr_av_base) /
 			   MTHCA_AV_SIZE);
-	else
+		break;
+
+	case MTHCA_AH_PCI_POOL:
 		pci_pool_free(dev->av_table.pool, ah->av, ah->avdma);
+		break;
+
+	case MTHCA_AH_KMALLOC:
+		kfree(ah->av);
+		break;
+	}
 
 	return 0;
 }
@@ -147,7 +163,7 @@ int mthca_destroy_ah(struct mthca_dev *d
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
 		  struct ib_ud_header *header)
 {
-	if (ah->on_hca)
+	if (ah->type == MTHCA_AH_ON_HCA)
 		return -EINVAL;
 
 	header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
@@ -176,6 +192,9 @@ int __devinit mthca_init_av_table(struct
 {
 	int err;
 
+	if (mthca_is_memfree(dev))
+		return 0;
+
 	err = mthca_alloc_init(&dev->av_table.alloc,
 			       dev->av_table.num_ddr_avs,
 			       dev->av_table.num_ddr_avs - 1,
@@ -212,6 +231,9 @@ int __devinit mthca_init_av_table(struct
 
 void __devexit mthca_cleanup_av_table(struct mthca_dev *dev)
 {
+	if (mthca_is_memfree(dev))
+		return;
+
 	if (dev->av_table.av_map)
 		iounmap(dev->av_table.av_map);
 	pci_pool_destroy(dev->av_table.pool);
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -651,7 +651,7 @@ int mthca_QUERY_FW(struct mthca_dev *dev
 	mthca_dbg(dev, "FW version %012llx, max commands %d\n",
 		  (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
 
-	if (dev->hca_type == ARBEL_NATIVE) {
+	if (mthca_is_memfree(dev)) {
 		MTHCA_GET(dev->fw.arbel.fw_pages,       outbox, QUERY_FW_SIZE_OFFSET);
 		MTHCA_GET(dev->fw.arbel.clr_int_base,   outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
 		MTHCA_GET(dev->fw.arbel.eq_arm_base,    outbox, QUERY_FW_EQ_ARM_BASE_OFFSET);
@@ -984,11 +984,11 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev
 
 	mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags);
 
-	if (dev->hca_type == ARBEL_NATIVE) {
+	if (mthca_is_memfree(dev)) {
 		MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET);
 		dev_lim->hca.arbel.resize_srq = field & 1;
-		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MTT_ENTRY_SZ_OFFSET);
-		dev_lim->mtt_seg_sz = size;
+		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET);
+		dev_lim->max_sg = min_t(int, field, dev_lim->max_sg);
 		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET);
 		dev_lim->mpt_entry_sz = size;
 		MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET);
@@ -1016,7 +1016,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev
 	} else {
 		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET);
 		dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f);
-		dev_lim->mtt_seg_sz   = MTHCA_MTT_SEG_SIZE;
 		dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE;
 	}
 
@@ -1149,7 +1148,7 @@ int mthca_INIT_HCA(struct mthca_dev *dev
 	/* TPT attributes */
 
 	MTHCA_PUT(inbox, param->mpt_base,   INIT_HCA_MPT_BASE_OFFSET);
-	if (dev->hca_type != ARBEL_NATIVE)
+	if (!mthca_is_memfree(dev))
 		MTHCA_PUT(inbox, param->mtt_seg_sz, INIT_HCA_MTT_SEG_SZ_OFFSET);
 	MTHCA_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
 	MTHCA_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
@@ -1162,7 +1161,7 @@ int mthca_INIT_HCA(struct mthca_dev *dev
 
 	MTHCA_PUT(inbox, param->uar_scratch_base, INIT_HCA_UAR_SCATCH_BASE_OFFSET);
 
-	if (dev->hca_type == ARBEL_NATIVE) {
+	if (mthca_is_memfree(dev)) {
 		MTHCA_PUT(inbox, param->log_uarc_sz, INIT_HCA_UARC_SZ_OFFSET);
 		MTHCA_PUT(inbox, param->log_uar_sz,  INIT_HCA_LOG_UAR_SZ_OFFSET);
 		MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
@@ -1290,21 +1289,24 @@ int mthca_MAP_ICM_page(struct mthca_dev 
 		return -ENOMEM;
 
 	inbox[0] = cpu_to_be64(virt);
-	inbox[1] = cpu_to_be64(dma_addr | (PAGE_SHIFT - 12));
+	inbox[1] = cpu_to_be64(dma_addr);
 
 	err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
 
 	pci_free_consistent(dev->pdev, 16, inbox, indma);
 
 	if (!err)
-		mthca_dbg(dev, "Mapped page at %llx for ICM.\n",
-			  (unsigned long long) virt);
+		mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
+			  (unsigned long long) dma_addr, (unsigned long long) virt);
 
 	return err;
 }
 
 int mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count, u8 *status)
 {
+	mthca_dbg(dev, "Unmapping %d pages at %llx from ICM.\n",
+		  page_count, (unsigned long long) virt);
+
 	return mthca_cmd(dev, virt, page_count, 0, CMD_UNMAP_ICM, CMD_TIME_CLASS_B, status);
 }
 
@@ -1401,6 +1403,11 @@ int mthca_WRITE_MTT(struct mthca_dev *de
 	return err;
 }
 
+int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
+{
+	return mthca_cmd(dev, 0, 0, 0, CMD_SYNC_TPT, CMD_TIME_CLASS_B, status);
+}
+
 int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 		 int eq_num, u8 *status)
 {
@@ -1538,10 +1545,10 @@ int mthca_MODIFY_QP(struct mthca_dev *de
 		if (0) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk(" %08x\n", be32_to_cpup(qp_context));
+			printk("  opt param mask: %08x\n", be32_to_cpup(qp_context));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
-					printk("[%02x] ", i * 4);
+					printk("  [%02x] ", i * 4);
 				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
 				if ((i + 1) % 8 == 0)
 					printk("\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -95,7 +95,21 @@ enum {
 };
 
 enum {
-	DEV_LIM_FLAG_SRQ = 1 << 6
+	DEV_LIM_FLAG_RC                 = 1 << 0,
+	DEV_LIM_FLAG_UC                 = 1 << 1,
+	DEV_LIM_FLAG_UD                 = 1 << 2,
+	DEV_LIM_FLAG_RD                 = 1 << 3,
+	DEV_LIM_FLAG_RAW_IPV6           = 1 << 4,
+	DEV_LIM_FLAG_RAW_ETHER          = 1 << 5,
+	DEV_LIM_FLAG_SRQ                = 1 << 6,
+	DEV_LIM_FLAG_BAD_PKEY_CNTR      = 1 << 8,
+	DEV_LIM_FLAG_BAD_QKEY_CNTR      = 1 << 9,
+	DEV_LIM_FLAG_MW                 = 1 << 16,
+	DEV_LIM_FLAG_AUTO_PATH_MIG      = 1 << 17,
+	DEV_LIM_FLAG_ATOMIC             = 1 << 18,
+	DEV_LIM_FLAG_RAW_MULTI          = 1 << 19,
+	DEV_LIM_FLAG_UD_AV_PORT_ENFORCE = 1 << 20,
+	DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 };
 
 struct mthca_dev_lim {
@@ -148,7 +162,6 @@ struct mthca_dev_lim {
 	int cqc_entry_sz;
 	int srq_entry_sz;
 	int uar_scratch_entry_sz;
-	int mtt_seg_sz;
 	int mpt_entry_sz;
 	union {
 		struct {
@@ -263,6 +276,7 @@ int mthca_HW2SW_MPT(struct mthca_dev *de
 		    int mpt_index, u8 *status);
 int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
 		    int num_mtt, u8 *status);
+int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 		 int eq_num, u8 *status);
 int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
diff --git a/drivers/infiniband/hw/mthca/mthca_config_reg.h b/drivers/infiniband/hw/mthca/mthca_config_reg.h
--- a/drivers/infiniband/hw/mthca/mthca_config_reg.h
+++ b/drivers/infiniband/hw/mthca/mthca_config_reg.h
@@ -46,5 +46,6 @@
 #define MTHCA_MAP_ECR_SIZE     (MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE)
 #define MTHCA_CLR_INT_BASE     0xf00d8
 #define MTHCA_CLR_INT_SIZE     0x00008
+#define MTHCA_EQ_SET_CI_SIZE   (8 * 32)
 
 #endif /* MTHCA_CONFIG_REG_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -33,11 +33,13 @@
  */
 
 #include <linux/init.h>
+#include <linux/hardirq.h>
 
 #include <ib_pack.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
+#include "mthca_memfree.h"
 
 enum {
 	MTHCA_MAX_DIRECT_CQ_SIZE = 4 * PAGE_SIZE
@@ -54,7 +56,7 @@ struct mthca_cq_context {
 	u32 flags;
 	u64 start;
 	u32 logsize_usrpage;
-	u32 error_eqn;
+	u32 error_eqn;		/* Tavor only */
 	u32 comp_eqn;
 	u32 pd;
 	u32 lkey;
@@ -63,7 +65,9 @@ struct mthca_cq_context {
 	u32 consumer_index;
 	u32 producer_index;
 	u32 cqn;
-	u32 reserved[3];
+	u32 ci_db;		/* Arbel only */
+	u32 state_db;		/* Arbel only */
+	u32 reserved;
 } __attribute__((packed));
 
 #define MTHCA_CQ_STATUS_OK          ( 0 << 28)
@@ -132,11 +136,15 @@ struct mthca_err_cqe {
 #define MTHCA_CQ_ENTRY_OWNER_SW      (0 << 7)
 #define MTHCA_CQ_ENTRY_OWNER_HW      (1 << 7)
 
-#define MTHCA_CQ_DB_INC_CI       (1 << 24)
-#define MTHCA_CQ_DB_REQ_NOT      (2 << 24)
-#define MTHCA_CQ_DB_REQ_NOT_SOL  (3 << 24)
-#define MTHCA_CQ_DB_SET_CI       (4 << 24)
-#define MTHCA_CQ_DB_REQ_NOT_MULT (5 << 24)
+#define MTHCA_TAVOR_CQ_DB_INC_CI       (1 << 24)
+#define MTHCA_TAVOR_CQ_DB_REQ_NOT      (2 << 24)
+#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL  (3 << 24)
+#define MTHCA_TAVOR_CQ_DB_SET_CI       (4 << 24)
+#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24)
+
+#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL  (1 << 24)
+#define MTHCA_ARBEL_CQ_DB_REQ_NOT      (2 << 24)
+#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
 
 static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
 {
@@ -147,54 +155,58 @@ static inline struct mthca_cqe *get_cqe(
 			+ (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
 }
 
-static inline int cqe_sw(struct mthca_cq *cq, int i)
+static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i)
 {
-	return !(MTHCA_CQ_ENTRY_OWNER_HW &
-		 get_cqe(cq, i)->owner);
+	struct mthca_cqe *cqe = get_cqe(cq, i);
+	return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
 }
 
-static inline int next_cqe_sw(struct mthca_cq *cq)
+static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
 {
-	return cqe_sw(cq, cq->cons_index);
+	return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe);
 }
 
-static inline void set_cqe_hw(struct mthca_cq *cq, int entry)
+static inline void set_cqe_hw(struct mthca_cqe *cqe)
 {
-	get_cqe(cq, entry)->owner = MTHCA_CQ_ENTRY_OWNER_HW;
+	cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 }
 
-static inline void inc_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
-				  int nent)
+/*
+ * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
+ * should be correct before calling update_cons_index().
+ */
+static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
+				     int incr)
 {
 	u32 doorbell[2];
 
-	doorbell[0] = cpu_to_be32(MTHCA_CQ_DB_INC_CI | cq->cqn);
-	doorbell[1] = cpu_to_be32(nent - 1);
+	if (mthca_is_memfree(dev)) {
+		*cq->set_ci_db = cpu_to_be32(cq->cons_index);
+		wmb();
+	} else {
+		doorbell[0] = cpu_to_be32(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn);
+		doorbell[1] = cpu_to_be32(incr - 1);
 
-	mthca_write64(doorbell,
-		      dev->kar + MTHCA_CQ_DOORBELL,
-		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+		mthca_write64(doorbell,
+			      dev->kar + MTHCA_CQ_DOORBELL,
+			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+	}
 }
 
 void mthca_cq_event(struct mthca_dev *dev, u32 cqn)
 {
 	struct mthca_cq *cq;
 
-	spin_lock(&dev->cq_table.lock);
 	cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
-	if (cq)
-		atomic_inc(&cq->refcount);
-	spin_unlock(&dev->cq_table.lock);
 
 	if (!cq) {
 		mthca_warn(dev, "Completion event for bogus CQ %08x\n", cqn);
 		return;
 	}
 
-	cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+	++cq->arm_sn;
 
-	if (atomic_dec_and_test(&cq->refcount))
-		wake_up(&cq->wait);
+	cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
 }
 
 void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn)
@@ -250,8 +262,8 @@ void mthca_cq_clean(struct mthca_dev *de
 
 	if (nfreed) {
 		wmb();
-		inc_cons_index(dev, cq, nfreed);
-		cq->cons_index = (cq->cons_index + nfreed) & cq->ibcq.cqe;
+		cq->cons_index += nfreed;
+		update_cons_index(dev, cq, nfreed);
 	}
 
 	spin_unlock_irq(&cq->lock);
@@ -344,7 +356,7 @@ static int handle_error_cqe(struct mthca
 		break;
 	}
 
-	err = mthca_free_err_wqe(qp, is_send, wqe_index, &dbd, &new_wqe);
+	err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
 	if (err)
 		return err;
 
@@ -383,12 +395,13 @@ static inline int mthca_poll_one(struct 
 	struct mthca_wq *wq;
 	struct mthca_cqe *cqe;
 	int wqe_index;
-	int is_error = 0;
+	int is_error;
 	int is_send;
 	int free_cqe = 1;
 	int err = 0;
 
-	if (!next_cqe_sw(cq))
+	cqe = next_cqe_sw(cq);
+	if (!cqe)
 		return -EAGAIN;
 
 	/*
@@ -397,8 +410,6 @@ static inline int mthca_poll_one(struct 
 	 */
 	rmb();
 
-	cqe = get_cqe(cq, cq->cons_index);
-
 	if (0) {
 		mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
 			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
@@ -407,39 +418,25 @@ static inline int mthca_poll_one(struct 
 		dump_cqe(cqe);
 	}
 
-	if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
-	    MTHCA_ERROR_CQE_OPCODE_MASK) {
-		is_error = 1;
-		is_send = cqe->opcode & 1;
-	} else
-		is_send = cqe->is_send & 0x80;
+	is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
+		MTHCA_ERROR_CQE_OPCODE_MASK;
+	is_send  = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80;
 
 	if (!*cur_qp || be32_to_cpu(cqe->my_qpn) != (*cur_qp)->qpn) {
-		if (*cur_qp) {
-			if (*freed) {
-				wmb();
-				inc_cons_index(dev, cq, *freed);
-				*freed = 0;
-			}
-			spin_unlock(&(*cur_qp)->lock);
-		}
-
-		spin_lock(&dev->qp_table.lock);
+		/*
+		 * We do not have to take the QP table lock here,
+		 * because CQs will be locked while QPs are removed
+		 * from the table.
+		 */
 		*cur_qp = mthca_array_get(&dev->qp_table.qp,
 					  be32_to_cpu(cqe->my_qpn) &
 					  (dev->limits.num_qps - 1));
-		if (*cur_qp)
-			atomic_inc(&(*cur_qp)->refcount);
-		spin_unlock(&dev->qp_table.lock);
-
 		if (!*cur_qp) {
 			mthca_warn(dev, "CQ entry for unknown QP %06x\n",
 				   be32_to_cpu(cqe->my_qpn) & 0xffffff);
 			err = -EINVAL;
 			goto out;
 		}
-
-		spin_lock(&(*cur_qp)->lock);
 	}
 
 	entry->qp_num = (*cur_qp)->qpn;
@@ -457,9 +454,9 @@ static inline int mthca_poll_one(struct 
 	}
 
 	if (wq->last_comp < wqe_index)
-		wq->cur -= wqe_index - wq->last_comp;
+		wq->tail += wqe_index - wq->last_comp;
 	else
-		wq->cur -= wq->max - wq->last_comp + wqe_index;
+		wq->tail += wqe_index + wq->max - wq->last_comp;
 
 	wq->last_comp = wqe_index;
 
@@ -476,7 +473,41 @@ static inline int mthca_poll_one(struct 
 	}
 
 	if (is_send) {
-		entry->opcode = IB_WC_SEND; /* XXX */
+		entry->wc_flags = 0;
+		switch (cqe->opcode) {
+		case MTHCA_OPCODE_RDMA_WRITE:
+			entry->opcode    = IB_WC_RDMA_WRITE;
+			break;
+		case MTHCA_OPCODE_RDMA_WRITE_IMM:
+			entry->opcode    = IB_WC_RDMA_WRITE;
+			entry->wc_flags |= IB_WC_WITH_IMM;
+			break;
+		case MTHCA_OPCODE_SEND:
+			entry->opcode    = IB_WC_SEND;
+			break;
+		case MTHCA_OPCODE_SEND_IMM:
+			entry->opcode    = IB_WC_SEND;
+			entry->wc_flags |= IB_WC_WITH_IMM;
+			break;
+		case MTHCA_OPCODE_RDMA_READ:
+			entry->opcode    = IB_WC_RDMA_READ;
+			entry->byte_len  = be32_to_cpu(cqe->byte_cnt);
+			break;
+		case MTHCA_OPCODE_ATOMIC_CS:
+			entry->opcode    = IB_WC_COMP_SWAP;
+			entry->byte_len  = be32_to_cpu(cqe->byte_cnt);
+			break;
+		case MTHCA_OPCODE_ATOMIC_FA:
+			entry->opcode    = IB_WC_FETCH_ADD;
+			entry->byte_len  = be32_to_cpu(cqe->byte_cnt);
+			break;
+		case MTHCA_OPCODE_BIND_MW:
+			entry->opcode    = IB_WC_BIND_MW;
+			break;
+		default:
+			entry->opcode    = MTHCA_OPCODE_INVALID;
+			break;
+		}
 	} else {
 		entry->byte_len = be32_to_cpu(cqe->byte_cnt);
 		switch (cqe->opcode & 0x1f) {
@@ -509,10 +540,10 @@ static inline int mthca_poll_one(struct 
 	entry->status = IB_WC_SUCCESS;
 
  out:
-	if (free_cqe) {
-		set_cqe_hw(cq, cq->cons_index);
+	if (likely(free_cqe)) {
+		set_cqe_hw(cqe);
 		++(*freed);
-		cq->cons_index = (cq->cons_index + 1) & cq->ibcq.cqe;
+		++cq->cons_index;
 	}
 
 	return err;
@@ -540,63 +571,101 @@ int mthca_poll_cq(struct ib_cq *ibcq, in
 
 	if (freed) {
 		wmb();
-		inc_cons_index(dev, cq, freed);
+		update_cons_index(dev, cq, freed);
 	}
 
-	if (qp) {
-		spin_unlock(&qp->lock);
-		if (atomic_dec_and_test(&qp->refcount))
-			wake_up(&qp->wait);
-	}
-
-
 	spin_unlock_irqrestore(&cq->lock, flags);
 
 	return err == 0 || err == -EAGAIN ? npolled : err;
 }
 
-void mthca_arm_cq(struct mthca_dev *dev, struct mthca_cq *cq,
-		  int solicited)
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
 {
 	u32 doorbell[2];
 
-	doorbell[0] =  cpu_to_be32((solicited ?
-				    MTHCA_CQ_DB_REQ_NOT_SOL :
-				    MTHCA_CQ_DB_REQ_NOT)      |
-				   cq->cqn);
+	doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ?
+				   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
+				   MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
+				  to_mcq(cq)->cqn);
 	doorbell[1] = 0xffffffff;
 
 	mthca_write64(doorbell,
-		      dev->kar + MTHCA_CQ_DOORBELL,
-		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+		      to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
+		      MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock));
+
+	return 0;
 }
 
-int mthca_init_cq(struct mthca_dev *dev, int nent,
-		  struct mthca_cq *cq)
+int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+{
+	struct mthca_cq *cq = to_mcq(ibcq);
+	u32 doorbell[2];
+	u32 sn;
+	u32 ci;
+
+	sn = cq->arm_sn & 3;
+	ci = cpu_to_be32(cq->cons_index);
+
+	doorbell[0] = ci;
+	doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
+				  (notify == IB_CQ_SOLICITED ? 1 : 2));
+
+	mthca_write_db_rec(doorbell, cq->arm_db);
+
+	/*
+	 * Make sure that the doorbell record in host memory is
+	 * written before ringing the doorbell via PCI MMIO.
+	 */
+	wmb();
+
+	doorbell[0] = cpu_to_be32((sn << 28)                       |
+				  (notify == IB_CQ_SOLICITED ?
+				   MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
+				   MTHCA_ARBEL_CQ_DB_REQ_NOT)      |
+				  cq->cqn);
+	doorbell[1] = ci;
+
+	mthca_write64(doorbell,
+		      to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL,
+		      MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock));
+
+	return 0;
+}
+
+static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
 {
-	int size = nent * MTHCA_CQ_ENTRY_SIZE;
-	dma_addr_t t;
-	void *mailbox = NULL;
-	int npages, shift;
-	u64 *dma_list = NULL;
-	struct mthca_cq_context *cq_context;
-	int err = -ENOMEM;
-	u8 status;
 	int i;
+	int size;
 
-	might_sleep();
+	if (cq->is_direct)
+		pci_free_consistent(dev->pdev,
+				    (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+				    cq->queue.direct.buf,
+				    pci_unmap_addr(&cq->queue.direct,
+						   mapping));
+	else {
+		size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
+		for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
+			if (cq->queue.page_list[i].buf)
+				pci_free_consistent(dev->pdev, PAGE_SIZE,
+						    cq->queue.page_list[i].buf,
+						    pci_unmap_addr(&cq->queue.page_list[i],
+								   mapping));
 
-	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
-		goto err_out;
+		kfree(cq->queue.page_list);
+	}
+}
 
-	cq_context = MAILBOX_ALIGN(mailbox);
+static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
+			      struct mthca_cq *cq)
+{
+	int err = -ENOMEM;
+	int npages, shift;
+	u64 *dma_list = NULL;
+	dma_addr_t t;
+	int i;
 
 	if (size <= MTHCA_MAX_DIRECT_CQ_SIZE) {
-		if (0)
-			mthca_dbg(dev, "Creating direct CQ of size %d\n", size);
-
 		cq->is_direct = 1;
 		npages        = 1;
 		shift         = get_order(size) + PAGE_SHIFT;
@@ -604,7 +673,7 @@ int mthca_init_cq(struct mthca_dev *dev,
 		cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
 							    size, &t);
 		if (!cq->queue.direct.buf)
-			goto err_out;
+			return -ENOMEM;
 
 		pci_unmap_addr_set(&cq->queue.direct, mapping, t);
 
@@ -617,7 +686,7 @@ int mthca_init_cq(struct mthca_dev *dev,
 
 		dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
 		if (!dma_list)
-			goto err_out_free;
+			goto err_free;
 
 		for (i = 0; i < npages; ++i)
 			dma_list[i] = t + i * (1 << shift);
@@ -626,12 +695,9 @@ int mthca_init_cq(struct mthca_dev *dev,
 		npages        = (size + PAGE_SIZE - 1) / PAGE_SIZE;
 		shift         = PAGE_SHIFT;
 
-		if (0)
-			mthca_dbg(dev, "Creating indirect CQ with %d pages\n", npages);
-
 		dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
 		if (!dma_list)
-			goto err_out;
+			return -ENOMEM;
 
 		cq->queue.page_list = kmalloc(npages * sizeof *cq->queue.page_list,
 					      GFP_KERNEL);
@@ -645,7 +711,7 @@ int mthca_init_cq(struct mthca_dev *dev,
 			cq->queue.page_list[i].buf =
 				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
 			if (!cq->queue.page_list[i].buf)
-				goto err_out_free;
+				goto err_free;
 
 			dma_list[i] = t;
 			pci_unmap_addr_set(&cq->queue.page_list[i], mapping, t);
@@ -654,13 +720,6 @@ int mthca_init_cq(struct mthca_dev *dev,
 		}
 	}
 
-	for (i = 0; i < nent; ++i)
-		set_cqe_hw(cq, i);
-
-	cq->cqn = mthca_alloc(&dev->cq_table.alloc);
-	if (cq->cqn == -1)
-		goto err_out_free;
-
 	err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
 				  dma_list, shift, npages,
 				  0, size,
@@ -668,7 +727,72 @@ int mthca_init_cq(struct mthca_dev *dev,
 				  MTHCA_MPT_FLAG_LOCAL_READ,
 				  &cq->mr);
 	if (err)
-		goto err_out_free_cq;
+		goto err_free;
+
+	kfree(dma_list);
+
+	return 0;
+
+err_free:
+	mthca_free_cq_buf(dev, cq);
+
+err_out:
+	kfree(dma_list);
+
+	return err;
+}
+
+int mthca_init_cq(struct mthca_dev *dev, int nent,
+		  struct mthca_cq *cq)
+{
+	int size = nent * MTHCA_CQ_ENTRY_SIZE;
+	void *mailbox = NULL;
+	struct mthca_cq_context *cq_context;
+	int err = -ENOMEM;
+	u8 status;
+	int i;
+
+	might_sleep();
+
+	cq->ibcq.cqe = nent - 1;
+
+	cq->cqn = mthca_alloc(&dev->cq_table.alloc);
+	if (cq->cqn == -1)
+		return -ENOMEM;
+
+	if (mthca_is_memfree(dev)) {
+		cq->arm_sn = 1;
+
+		err = mthca_table_get(dev, dev->cq_table.table, cq->cqn);
+		if (err)
+			goto err_out;
+
+		err = -ENOMEM;
+
+		cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
+						     cq->cqn, &cq->set_ci_db);
+		if (cq->set_ci_db_index < 0)
+			goto err_out_icm;
+
+		cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
+						  cq->cqn, &cq->arm_db);
+		if (cq->arm_db_index < 0)
+			goto err_out_ci;
+	}
+
+	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
+			  GFP_KERNEL);
+	if (!mailbox)
+		goto err_out_mailbox;
+
+	cq_context = MAILBOX_ALIGN(mailbox);
+
+	err = mthca_alloc_cq_buf(dev, size, cq);
+	if (err)
+		goto err_out_mailbox;
+
+	for (i = 0; i < nent; ++i)
+		set_cqe_hw(get_cqe(cq, i));
 
 	spin_lock_init(&cq->lock);
 	atomic_set(&cq->refcount, 1);
@@ -680,13 +804,18 @@ int mthca_init_cq(struct mthca_dev *dev,
 						  MTHCA_CQ_FLAG_TR);
 	cq_context->start           = cpu_to_be64(0);
 	cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 |
-						  MTHCA_KAR_PAGE);
+						  dev->driver_uar.index);
 	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
 	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
 	cq_context->pd              = cpu_to_be32(dev->driver_pd.pd_num);
 	cq_context->lkey            = cpu_to_be32(cq->mr.ibmr.lkey);
 	cq_context->cqn             = cpu_to_be32(cq->cqn);
 
+	if (mthca_is_memfree(dev)) {
+		cq_context->ci_db    = cpu_to_be32(cq->set_ci_db_index);
+		cq_context->state_db = cpu_to_be32(cq->arm_db_index);
+	}
+
 	err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
 	if (err) {
 		mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
@@ -711,36 +840,29 @@ int mthca_init_cq(struct mthca_dev *dev,
 
 	cq->cons_index = 0;
 
-	kfree(dma_list);
 	kfree(mailbox);
 
 	return 0;
 
- err_out_free_mr:
+err_out_free_mr:
 	mthca_free_mr(dev, &cq->mr);
+	mthca_free_cq_buf(dev, cq);
 
- err_out_free_cq:
-	mthca_free(&dev->cq_table.alloc, cq->cqn);
+err_out_mailbox:
+	kfree(mailbox);
 
- err_out_free:
-	if (cq->is_direct)
-		pci_free_consistent(dev->pdev, size,
-				    cq->queue.direct.buf,
-				    pci_unmap_addr(&cq->queue.direct, mapping));
-	else {
-		for (i = 0; i < npages; ++i)
-			if (cq->queue.page_list[i].buf)
-				pci_free_consistent(dev->pdev, PAGE_SIZE,
-						    cq->queue.page_list[i].buf,
-						    pci_unmap_addr(&cq->queue.page_list[i],
-								   mapping));
+	if (mthca_is_memfree(dev))
+		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 
-		kfree(cq->queue.page_list);
-	}
+err_out_ci:
+	if (mthca_is_memfree(dev))
+		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
 
- err_out:
-	kfree(dma_list);
-	kfree(mailbox);
+err_out_icm:
+	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
+
+err_out:
+	mthca_free(&dev->cq_table.alloc, cq->cqn);
 
 	return err;
 }
@@ -773,7 +895,7 @@ void mthca_free_cq(struct mthca_dev *dev
 		int j;
 
 		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
-		       cq->cqn, cq->cons_index, next_cqe_sw(cq));
+		       cq->cqn, cq->cons_index, !!next_cqe_sw(cq));
 		for (j = 0; j < 16; ++j)
 			printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j]));
 	}
@@ -783,30 +905,21 @@ void mthca_free_cq(struct mthca_dev *dev
 			  cq->cqn & (dev->limits.num_cqs - 1));
 	spin_unlock_irq(&dev->cq_table.lock);
 
+	if (dev->mthca_flags & MTHCA_FLAG_MSI_X)
+		synchronize_irq(dev->eq_table.eq[MTHCA_EQ_COMP].msi_x_vector);
+	else
+		synchronize_irq(dev->pdev->irq);
+
 	atomic_dec(&cq->refcount);
 	wait_event(cq->wait, !atomic_read(&cq->refcount));
 
 	mthca_free_mr(dev, &cq->mr);
+	mthca_free_cq_buf(dev, cq);
 
-	if (cq->is_direct)
-		pci_free_consistent(dev->pdev,
-				    (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-				    cq->queue.direct.buf,
-				    pci_unmap_addr(&cq->queue.direct,
-						   mapping));
-	else {
-		int i;
-
-		for (i = 0;
-		     i < ((cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE + PAGE_SIZE - 1) /
-			     PAGE_SIZE;
-		     ++i)
-			pci_free_consistent(dev->pdev, PAGE_SIZE,
-					    cq->queue.page_list[i].buf,
-					    pci_unmap_addr(&cq->queue.page_list[i],
-							   mapping));
-
-		kfree(cq->queue.page_list);
+	if (mthca_is_memfree(dev)) {
+		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
+		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+		mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 	}
 
 	mthca_free(&dev->cq_table.alloc, cq->cqn);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -49,23 +49,18 @@
 #define DRV_VERSION	"0.06-pre"
 #define DRV_RELDATE	"November 8, 2004"
 
-/* Types of supported HCA */
-enum {
-	TAVOR,			/* MT23108                        */
-	ARBEL_COMPAT,		/* MT25208 in Tavor compat mode   */
-	ARBEL_NATIVE		/* MT25208 with extended features */
-};
-
 enum {
 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
 	MTHCA_FLAG_SRQ        = 1 << 2,
 	MTHCA_FLAG_MSI        = 1 << 3,
 	MTHCA_FLAG_MSI_X      = 1 << 4,
-	MTHCA_FLAG_NO_LAM     = 1 << 5
+	MTHCA_FLAG_NO_LAM     = 1 << 5,
+	MTHCA_FLAG_FMR        = 1 << 6,
+	MTHCA_FLAG_MEMFREE    = 1 << 7,
+	MTHCA_FLAG_PCIE       = 1 << 8
 };
 
 enum {
-	MTHCA_KAR_PAGE  = 1,
 	MTHCA_MAX_PORTS = 2
 };
 
@@ -89,6 +84,19 @@ enum {
 	MTHCA_NUM_EQ
 };
 
+enum {
+	MTHCA_OPCODE_NOP            = 0x00,
+	MTHCA_OPCODE_RDMA_WRITE     = 0x08,
+	MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09,
+	MTHCA_OPCODE_SEND           = 0x0a,
+	MTHCA_OPCODE_SEND_IMM       = 0x0b,
+	MTHCA_OPCODE_RDMA_READ      = 0x10,
+	MTHCA_OPCODE_ATOMIC_CS      = 0x11,
+	MTHCA_OPCODE_ATOMIC_FA      = 0x12,
+	MTHCA_OPCODE_BIND_MW        = 0x18,
+	MTHCA_OPCODE_INVALID        = 0xff
+};
+
 struct mthca_cmd {
 	int                       use_events;
 	struct semaphore          hcr_sem;
@@ -108,6 +116,7 @@ struct mthca_limits {
 	int      gid_table_len;
 	int      pkey_table_len;
 	int      local_ca_ack_delay;
+	int      num_uars;
 	int      max_sg;
 	int      num_qps;
 	int      reserved_qps;
@@ -121,7 +130,7 @@ struct mthca_limits {
 	int      reserved_eqs;
 	int      num_mpts;
 	int      num_mtt_segs;
-	int      mtt_seg_size;
+	int      fmr_reserved_mtts;
 	int      reserved_mtts;
 	int      reserved_mrws;
 	int      reserved_uars;
@@ -148,23 +157,42 @@ struct mthca_array {
 	} *page_list;
 };
 
+struct mthca_uar_table {
+	struct mthca_alloc alloc;
+	u64                uarc_base;
+	int                uarc_size;
+};
+
 struct mthca_pd_table {
 	struct mthca_alloc alloc;
 };
 
+struct mthca_buddy {
+	unsigned long **bits;
+	int             max_order;
+	spinlock_t      lock;
+};
+
 struct mthca_mr_table {
 	struct mthca_alloc      mpt_alloc;
-	int                     max_mtt_order;
-	unsigned long         **mtt_buddy;
+	struct mthca_buddy      mtt_buddy;
+	struct mthca_buddy     *fmr_mtt_buddy;
 	u64                     mtt_base;
+	u64                     mpt_base;
 	struct mthca_icm_table *mtt_table;
 	struct mthca_icm_table *mpt_table;
+	struct {
+		void __iomem   *mpt_base;
+		void __iomem   *mtt_base;
+		struct mthca_buddy mtt_buddy;
+	} tavor_fmr;
 };
 
 struct mthca_eq_table {
 	struct mthca_alloc alloc;
 	void __iomem      *clr_int;
 	u32                clr_mask;
+	u32                arm_mask;
 	struct mthca_eq    eq[MTHCA_NUM_EQ];
 	u64                icm_virt;
 	struct page       *icm_page;
@@ -189,6 +217,7 @@ struct mthca_qp_table {
 	struct mthca_array     	qp;
 	struct mthca_icm_table *qp_table;
 	struct mthca_icm_table *eqp_table;
+	struct mthca_icm_table *rdb_table;
 };
 
 struct mthca_av_table {
@@ -200,8 +229,9 @@ struct mthca_av_table {
 };
 
 struct mthca_mcg_table {
-	struct semaphore   sem;
-	struct mthca_alloc alloc;
+	struct semaphore   	sem;
+	struct mthca_alloc 	alloc;
+	struct mthca_icm_table *table;
 };
 
 struct mthca_dev {
@@ -210,6 +240,7 @@ struct mthca_dev {
 
 	int          	 hca_type;
 	unsigned long	 mthca_flags;
+	unsigned long    device_cap_flags;
 
 	u32              rev_id;
 
@@ -237,13 +268,22 @@ struct mthca_dev {
 	struct semaphore cap_mask_mutex;
 
 	void __iomem    *hcr;
-	void __iomem    *ecr_base;
-	void __iomem    *clr_base;
 	void __iomem    *kar;
+	void __iomem    *clr_base;
+	union {
+		struct {
+			void __iomem *ecr_base;
+		} tavor;
+		struct {
+			void __iomem *eq_arm;
+			void __iomem *eq_set_ci_base;
+		} arbel;
+	} eq_regs;
 
 	struct mthca_cmd    cmd;
 	struct mthca_limits limits;
 
+	struct mthca_uar_table uar_table;
 	struct mthca_pd_table  pd_table;
 	struct mthca_mr_table  mr_table;
 	struct mthca_eq_table  eq_table;
@@ -252,8 +292,10 @@ struct mthca_dev {
 	struct mthca_av_table  av_table;
 	struct mthca_mcg_table mcg_table;
 
-	struct mthca_pd       driver_pd;
-	struct mthca_mr       driver_mr;
+	struct mthca_uar       driver_uar;
+	struct mthca_db_table *db_tab;
+	struct mthca_pd        driver_pd;
+	struct mthca_mr        driver_mr;
 
 	struct ib_mad_agent  *send_agent[MTHCA_MAX_PORTS][2];
 	struct ib_ah         *sm_ah[MTHCA_MAX_PORTS];
@@ -310,6 +352,7 @@ void mthca_array_clear(struct mthca_arra
 int mthca_array_init(struct mthca_array *array, int nent);
 void mthca_array_cleanup(struct mthca_array *array, int nent);
 
+int mthca_init_uar_table(struct mthca_dev *dev);
 int mthca_init_pd_table(struct mthca_dev *dev);
 int mthca_init_mr_table(struct mthca_dev *dev);
 int mthca_init_eq_table(struct mthca_dev *dev);
@@ -318,6 +361,7 @@ int mthca_init_qp_table(struct mthca_dev
 int mthca_init_av_table(struct mthca_dev *dev);
 int mthca_init_mcg_table(struct mthca_dev *dev);
 
+void mthca_cleanup_uar_table(struct mthca_dev *dev);
 void mthca_cleanup_pd_table(struct mthca_dev *dev);
 void mthca_cleanup_mr_table(struct mthca_dev *dev);
 void mthca_cleanup_eq_table(struct mthca_dev *dev);
@@ -329,6 +373,9 @@ void mthca_cleanup_mcg_table(struct mthc
 int mthca_register_device(struct mthca_dev *dev);
 void mthca_unregister_device(struct mthca_dev *dev);
 
+int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
+void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
+
 int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 
@@ -338,15 +385,25 @@ int mthca_mr_alloc_phys(struct mthca_dev
 			u64 *buffer_list, int buffer_size_shift,
 			int list_len, u64 iova, u64 total_size,
 			u32 access, struct mthca_mr *mr);
-void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr);
+void mthca_free_mr(struct mthca_dev *dev,  struct mthca_mr *mr);
+
+int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
+		    u32 access, struct mthca_fmr *fmr);
+int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+			     int list_len, u64 iova);
+void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr);
+int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+			     int list_len, u64 iova);
+void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr);
+int mthca_free_fmr(struct mthca_dev *dev,  struct mthca_fmr *fmr);
 
 int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt);
 void mthca_unmap_eq_icm(struct mthca_dev *dev);
 
 int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 		  struct ib_wc *entry);
-void mthca_arm_cq(struct mthca_dev *dev, struct mthca_cq *cq,
-		  int solicited);
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
+int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 		  struct mthca_cq *cq);
 void mthca_free_cq(struct mthca_dev *dev,
@@ -357,11 +414,15 @@ void mthca_cq_clean(struct mthca_dev *de
 void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
 		    enum ib_event_type event_type);
 int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
-int mthca_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
-		    struct ib_send_wr **bad_wr);
-int mthca_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
-		       struct ib_recv_wr **bad_wr);
-int mthca_free_err_wqe(struct mthca_qp *qp, int is_send,
+int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+			  struct ib_send_wr **bad_wr);
+int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+			     struct ib_recv_wr **bad_wr);
+int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+			  struct ib_send_wr **bad_wr);
+int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+			     struct ib_recv_wr **bad_wr);
+int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
 		       int index, int *dbd, u32 *new_wqe);
 int mthca_alloc_qp(struct mthca_dev *dev,
 		   struct mthca_pd *pd,
@@ -369,14 +430,12 @@ int mthca_alloc_qp(struct mthca_dev *dev
 		   struct mthca_cq *recv_cq,
 		   enum ib_qp_type type,
 		   enum ib_sig_type send_policy,
-		   enum ib_sig_type recv_policy,
 		   struct mthca_qp *qp);
 int mthca_alloc_sqp(struct mthca_dev *dev,
 		    struct mthca_pd *pd,
 		    struct mthca_cq *send_cq,
 		    struct mthca_cq *recv_cq,
 		    enum ib_sig_type send_policy,
-		    enum ib_sig_type recv_policy,
 		    int qpn,
 		    int port,
 		    struct mthca_sqp *sqp);
@@ -407,4 +466,9 @@ static inline struct mthca_dev *to_mdev(
 	return container_of(ibdev, struct mthca_dev, ib_dev);
 }
 
+static inline int mthca_is_memfree(struct mthca_dev *dev)
+{
+	return dev->mthca_flags & MTHCA_FLAG_MEMFREE;
+}
+
 #endif /* MTHCA_DEV_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_doorbell.h b/drivers/infiniband/hw/mthca/mthca_doorbell.h
--- a/drivers/infiniband/hw/mthca/mthca_doorbell.h
+++ b/drivers/infiniband/hw/mthca/mthca_doorbell.h
@@ -51,12 +51,22 @@
 #define MTHCA_INIT_DOORBELL_LOCK(ptr)    do { } while (0)
 #define MTHCA_GET_DOORBELL_LOCK(ptr)      (NULL)
 
+static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
+{
+	__raw_writeq((__force u64) val, dest);
+}
+
 static inline void mthca_write64(u32 val[2], void __iomem *dest,
 				 spinlock_t *doorbell_lock)
 {
 	__raw_writeq(*(u64 *) val, dest);
 }
 
+static inline void mthca_write_db_rec(u32 val[2], u32 *db)
+{
+	*(u64 *) db = *(u64 *) val;
+}
+
 #else
 
 /*
@@ -69,6 +79,12 @@ static inline void mthca_write64(u32 val
 #define MTHCA_INIT_DOORBELL_LOCK(ptr)     spin_lock_init(ptr)
 #define MTHCA_GET_DOORBELL_LOCK(ptr)      (ptr)
 
+static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
+{
+	__raw_writel(((__force u32 *) &val)[0], dest);
+	__raw_writel(((__force u32 *) &val)[1], dest + 4);
+}
+
 static inline void mthca_write64(u32 val[2], void __iomem *dest,
 				 spinlock_t *doorbell_lock)
 {
@@ -80,4 +96,11 @@ static inline void mthca_write64(u32 val
 	spin_unlock_irqrestore(doorbell_lock, flags);
 }
 
+static inline void mthca_write_db_rec(u32 val[2], u32 *db)
+{
+	db[0] = val[0];
+	wmb();
+	db[1] = val[1];
+}
+
 #endif
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -54,10 +54,10 @@ struct mthca_eq_context {
 	u32 flags;
 	u64 start;
 	u32 logsize_usrpage;
-	u32 pd;
+	u32 tavor_pd;		/* reserved for Arbel */
 	u8  reserved1[3];
 	u8  intr;
-	u32 lost_count;
+	u32 arbel_pd;		/* lost_count for Tavor */
 	u32 lkey;
 	u32 reserved2[2];
 	u32 consumer_index;
@@ -75,6 +75,7 @@ struct mthca_eq_context {
 #define MTHCA_EQ_STATE_ARMED        ( 1 <<  8)
 #define MTHCA_EQ_STATE_FIRED        ( 2 <<  8)
 #define MTHCA_EQ_STATE_ALWAYS_ARMED ( 3 <<  8)
+#define MTHCA_EQ_STATE_ARBEL        ( 8 <<  8)
 
 enum {
 	MTHCA_EVENT_TYPE_COMP       	    = 0x00,
@@ -164,19 +165,46 @@ static inline u64 async_mask(struct mthc
 		MTHCA_ASYNC_EVENT_MASK;
 }
 
-static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
+static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
 {
 	u32 doorbell[2];
 
 	doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eq->eqn);
 	doorbell[1] = cpu_to_be32(ci & (eq->nent - 1));
 
+	/*
+	 * This barrier makes sure that all updates to ownership bits
+	 * done by set_eqe_hw() hit memory before the consumer index
+	 * is updated.  set_eq_ci() allows the HCA to possibly write
+	 * more EQ entries, and we want to avoid the exceedingly
+	 * unlikely possibility of the HCA writing an entry and then
+	 * having set_eqe_hw() overwrite the owner field.
+	 */
+	wmb();
 	mthca_write64(doorbell,
 		      dev->kar + MTHCA_EQ_DOORBELL,
 		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 }
 
-static inline void eq_req_not(struct mthca_dev *dev, int eqn)
+static inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
+{
+	/* See comment in tavor_set_eq_ci() above. */
+	wmb();
+	__raw_writel(cpu_to_be32(ci), dev->eq_regs.arbel.eq_set_ci_base +
+		     eq->eqn * 8);
+	/* We still want ordering, just not swabbing, so add a barrier */
+	mb();
+}
+
+static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
+{
+	if (mthca_is_memfree(dev))
+		arbel_set_eq_ci(dev, eq, ci);
+	else
+		tavor_set_eq_ci(dev, eq, ci);
+}
+
+static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)
 {
 	u32 doorbell[2];
 
@@ -188,16 +216,23 @@ static inline void eq_req_not(struct mth
 		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 }
 
+static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)
+{
+	writel(eqn_mask, dev->eq_regs.arbel.eq_arm);
+}
+
 static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
 {
-	u32 doorbell[2];
+	if (!mthca_is_memfree(dev)) {
+		u32 doorbell[2];
 
-	doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_DISARM_CQ | eqn);
-	doorbell[1] = cpu_to_be32(cqn);
+		doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_DISARM_CQ | eqn);
+		doorbell[1] = cpu_to_be32(cqn);
 
-	mthca_write64(doorbell,
-		      dev->kar + MTHCA_EQ_DOORBELL,
-		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+		mthca_write64(doorbell,
+			      dev->kar + MTHCA_EQ_DOORBELL,
+			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+	}
 }
 
 static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry)
@@ -232,7 +267,7 @@ static void port_change(struct mthca_dev
 	ib_dispatch_event(&record);
 }
 
-static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
+static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
 {
 	struct mthca_eqe *eqe;
 	int disarm_cqn;
@@ -309,10 +344,10 @@ static void mthca_eq_int(struct mthca_de
 			break;
 
 		case MTHCA_EVENT_TYPE_CQ_ERROR:
-			mthca_warn(dev, "CQ %s on CQN %08x\n",
+			mthca_warn(dev, "CQ %s on CQN %06x\n",
 				   eqe->event.cq_err.syndrome == 1 ?
 				   "overrun" : "access violation",
-				   be32_to_cpu(eqe->event.cq_err.cqn));
+				   be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff);
 			break;
 
 		case MTHCA_EVENT_TYPE_EQ_OVERFLOW:
@@ -333,60 +368,93 @@ static void mthca_eq_int(struct mthca_de
 		++eq->cons_index;
 		eqes_found = 1;
 
-		if (set_ci) {
-			wmb(); /* see comment below */
+		if (unlikely(set_ci)) {
+			/*
+			 * Conditional on hca_type is OK here because
+			 * this is a rare case, not the fast path.
+			 */
 			set_eq_ci(dev, eq, eq->cons_index);
 			set_ci = 0;
 		}
 	}
 
 	/*
-	 * This barrier makes sure that all updates to
-	 * ownership bits done by set_eqe_hw() hit memory
-	 * before the consumer index is updated.  set_eq_ci()
-	 * allows the HCA to possibly write more EQ entries,
-	 * and we want to avoid the exceedingly unlikely
-	 * possibility of the HCA writing an entry and then
-	 * having set_eqe_hw() overwrite the owner field.
+	 * Rely on caller to set consumer index so that we don't have
+	 * to test hca_type in our interrupt handling fast path.
 	 */
-	if (likely(eqes_found)) {
-		wmb();
-		set_eq_ci(dev, eq, eq->cons_index);
-	}
-	eq_req_not(dev, eq->eqn);
+	return eqes_found;
 }
 
-static irqreturn_t mthca_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
+static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
 {
 	struct mthca_dev *dev = dev_ptr;
 	u32 ecr;
-	int work = 0;
 	int i;
 
 	if (dev->eq_table.clr_mask)
 		writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
 
-	if ((ecr = readl(dev->ecr_base + 4)) != 0) {
-		work = 1;
-
-		writel(ecr, dev->ecr_base +
+	ecr = readl(dev->eq_regs.tavor.ecr_base + 4);
+	if (ecr) {
+		writel(ecr, dev->eq_regs.tavor.ecr_base +
 		       MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4);
 
 		for (i = 0; i < MTHCA_NUM_EQ; ++i)
-			if (ecr & dev->eq_table.eq[i].ecr_mask)
-				mthca_eq_int(dev, &dev->eq_table.eq[i]);
+			if (ecr & dev->eq_table.eq[i].eqn_mask &&
+			    mthca_eq_int(dev, &dev->eq_table.eq[i])) {
+				tavor_set_eq_ci(dev, &dev->eq_table.eq[i],
+						dev->eq_table.eq[i].cons_index);
+				tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
+			}
 	}
 
-	return IRQ_RETVAL(work);
+	return IRQ_RETVAL(ecr);
 }
 
-static irqreturn_t mthca_msi_x_interrupt(int irq, void *eq_ptr,
+static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr,
 					 struct pt_regs *regs)
 {
 	struct mthca_eq  *eq  = eq_ptr;
 	struct mthca_dev *dev = eq->dev;
 
 	mthca_eq_int(dev, eq);
+	tavor_set_eq_ci(dev, eq, eq->cons_index);
+	tavor_eq_req_not(dev, eq->eqn);
+
+	/* MSI-X vectors always belong to us */
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
+{
+	struct mthca_dev *dev = dev_ptr;
+	int work = 0;
+	int i;
+
+	if (dev->eq_table.clr_mask)
+		writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
+
+	for (i = 0; i < MTHCA_NUM_EQ; ++i)
+		if (mthca_eq_int(dev, &dev->eq_table.eq[i])) {
+			work = 1;
+			arbel_set_eq_ci(dev, &dev->eq_table.eq[i],
+					dev->eq_table.eq[i].cons_index);
+		}
+
+	arbel_eq_req_not(dev, dev->eq_table.arm_mask);
+
+	return IRQ_RETVAL(work);
+}
+
+static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr,
+					       struct pt_regs *regs)
+{
+	struct mthca_eq  *eq  = eq_ptr;
+	struct mthca_dev *dev = eq->dev;
+
+	mthca_eq_int(dev, eq);
+	arbel_set_eq_ci(dev, eq, eq->cons_index);
+	arbel_eq_req_not(dev, eq->eqn_mask);
 
 	/* MSI-X vectors always belong to us */
 	return IRQ_HANDLED;
@@ -467,10 +535,16 @@ static int __devinit mthca_create_eq(str
 						  MTHCA_EQ_OWNER_HW    |
 						  MTHCA_EQ_STATE_ARMED |
 						  MTHCA_EQ_FLAG_TR);
-	eq_context->start           = cpu_to_be64(0);
-	eq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 |
-						  MTHCA_KAR_PAGE);
-	eq_context->pd              = cpu_to_be32(dev->driver_pd.pd_num);
+	if (mthca_is_memfree(dev))
+		eq_context->flags  |= cpu_to_be32(MTHCA_EQ_STATE_ARBEL);
+
+	eq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
+	if (mthca_is_memfree(dev)) {
+		eq_context->arbel_pd = cpu_to_be32(dev->driver_pd.pd_num);
+	} else {
+		eq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
+		eq_context->tavor_pd         = cpu_to_be32(dev->driver_pd.pd_num);
+	}
 	eq_context->intr            = intr;
 	eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 
@@ -489,10 +563,10 @@ static int __devinit mthca_create_eq(str
 	kfree(dma_list);
 	kfree(mailbox);
 
-	eq->ecr_mask   = swab32(1 << eq->eqn);
+	eq->eqn_mask   = swab32(1 << eq->eqn);
 	eq->cons_index = 0;
 
-	eq_req_not(dev, eq->eqn);
+	dev->eq_table.arm_mask |= eq->eqn_mask;
 
 	mthca_dbg(dev, "Allocated EQ %d with %d entries\n",
 		  eq->eqn, nent);
@@ -544,6 +618,8 @@ static void mthca_free_eq(struct mthca_d
 		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
 			   status);
 
+	dev->eq_table.arm_mask &= ~eq->eqn_mask;
+
 	if (0) {
 		mthca_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
 		for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
@@ -555,7 +631,6 @@ static void mthca_free_eq(struct mthca_d
 		}
 	}
 
-
 	mthca_free_mr(dev, &eq->mr);
 	for (i = 0; i < npages; ++i)
 		pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -578,6 +653,129 @@ static void mthca_free_irqs(struct mthca
 				 dev->eq_table.eq + i);
 }
 
+static int __devinit mthca_map_reg(struct mthca_dev *dev,
+				   unsigned long offset, unsigned long size,
+				   void __iomem **map)
+{
+	unsigned long base = pci_resource_start(dev->pdev, 0);
+
+	if (!request_mem_region(base + offset, size, DRV_NAME))
+		return -EBUSY;
+
+	*map = ioremap(base + offset, size);
+	if (!*map) {
+		release_mem_region(base + offset, size);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset,
+			    unsigned long size, void __iomem *map)
+{
+	unsigned long base = pci_resource_start(dev->pdev, 0);
+
+	release_mem_region(base + offset, size);
+	iounmap(map);
+}
+
+static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
+{
+	unsigned long mthca_base;
+
+	mthca_base = pci_resource_start(dev->pdev, 0);
+
+	if (mthca_is_memfree(dev)) {
+		/*
+		 * We assume that the EQ arm and EQ set CI registers
+		 * fall within the first BAR.  We can't trust the
+		 * values firmware gives us, since those addresses are
+		 * valid on the HCA's side of the PCI bus but not
+		 * necessarily the host side.
+		 */
+		if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+				  dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
+				  &dev->clr_base)) {
+			mthca_err(dev, "Couldn't map interrupt clear register, "
+				  "aborting.\n");
+			return -ENOMEM;
+		}
+
+		/*
+		 * Add 4 because we limit ourselves to EQs 0 ... 31,
+		 * so we only need the low word of the register.
+		 */
+		if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
+					dev->fw.arbel.eq_arm_base) + 4, 4,
+				  &dev->eq_regs.arbel.eq_arm)) {
+			mthca_err(dev, "Couldn't map interrupt clear register, "
+				  "aborting.\n");
+			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
+					dev->clr_base);
+			return -ENOMEM;
+		}
+
+		if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+				  dev->fw.arbel.eq_set_ci_base,
+				  MTHCA_EQ_SET_CI_SIZE,
+				  &dev->eq_regs.arbel.eq_set_ci_base)) {
+			mthca_err(dev, "Couldn't map interrupt clear register, "
+				  "aborting.\n");
+			mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
+					      dev->fw.arbel.eq_arm_base) + 4, 4,
+					dev->eq_regs.arbel.eq_arm);
+			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
+					dev->clr_base);
+			return -ENOMEM;
+		}
+	} else {
+		if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
+				  &dev->clr_base)) {
+			mthca_err(dev, "Couldn't map interrupt clear register, "
+				  "aborting.\n");
+			return -ENOMEM;
+		}
+
+		if (mthca_map_reg(dev, MTHCA_ECR_BASE,
+				  MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,
+				  &dev->eq_regs.tavor.ecr_base)) {
+			mthca_err(dev, "Couldn't map ecr register, "
+				  "aborting.\n");
+			mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
+					dev->clr_base);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+
+}
+
+static void __devexit mthca_unmap_eq_regs(struct mthca_dev *dev)
+{
+	if (mthca_is_memfree(dev)) {
+		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+				dev->fw.arbel.eq_set_ci_base,
+				MTHCA_EQ_SET_CI_SIZE,
+				dev->eq_regs.arbel.eq_set_ci_base);
+		mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
+				      dev->fw.arbel.eq_arm_base) + 4, 4,
+				dev->eq_regs.arbel.eq_arm);
+		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
+				dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
+				dev->clr_base);
+	} else {
+		mthca_unmap_reg(dev, MTHCA_ECR_BASE,
+				MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,
+				dev->eq_regs.tavor.ecr_base);
+		mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
+				dev->clr_base);
+	}
+}
+
 int __devinit mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)
 {
 	int ret;
@@ -636,6 +834,10 @@ int __devinit mthca_init_eq_table(struct
 	if (err)
 		return err;
 
+	err = mthca_map_eq_regs(dev);
+	if (err)
+		goto err_out_free;
+
 	if (dev->mthca_flags & MTHCA_FLAG_MSI ||
 	    dev->mthca_flags & MTHCA_FLAG_MSI_X) {
 		dev->eq_table.clr_mask = 0;
@@ -646,6 +848,8 @@ int __devinit mthca_init_eq_table(struct
 			(dev->eq_table.inta_pin < 31 ? 4 : 0);
 	}
 
+	dev->eq_table.arm_mask = 0;
+
 	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
 		128 : dev->eq_table.inta_pin;
 
@@ -653,7 +857,7 @@ int __devinit mthca_init_eq_table(struct
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
 			      &dev->eq_table.eq[MTHCA_EQ_COMP]);
 	if (err)
-		goto err_out_free;
+		goto err_out_unmap;
 
 	err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE,
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,
@@ -676,15 +880,20 @@ int __devinit mthca_init_eq_table(struct
 
 		for (i = 0; i < MTHCA_NUM_EQ; ++i) {
 			err = request_irq(dev->eq_table.eq[i].msi_x_vector,
-					  mthca_msi_x_interrupt, 0,
-					  eq_name[i], dev->eq_table.eq + i);
+					  mthca_is_memfree(dev) ?
+					  mthca_arbel_msi_x_interrupt :
+					  mthca_tavor_msi_x_interrupt,
+					  0, eq_name[i], dev->eq_table.eq + i);
 			if (err)
 				goto err_out_cmd;
 			dev->eq_table.eq[i].have_irq = 1;
 		}
 	} else {
-		err = request_irq(dev->pdev->irq, mthca_interrupt, SA_SHIRQ,
-				  DRV_NAME, dev);
+		err = request_irq(dev->pdev->irq,
+				  mthca_is_memfree(dev) ?
+				  mthca_arbel_interrupt :
+				  mthca_tavor_interrupt,
+				  SA_SHIRQ, DRV_NAME, dev);
 		if (err)
 			goto err_out_cmd;
 		dev->eq_table.have_irq = 1;
@@ -708,6 +917,12 @@ int __devinit mthca_init_eq_table(struct
 		mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n",
 			   dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status);
 
+	for (i = 0; i < MTHCA_EQ_CMD; ++i)
+		if (mthca_is_memfree(dev))
+			arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
+		else
+			tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
+
 	return 0;
 
 err_out_cmd:
@@ -720,6 +935,9 @@ err_out_async:
 err_out_comp:
 	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]);
 
+err_out_unmap:
+	mthca_unmap_eq_regs(dev);
+
 err_out_free:
 	mthca_alloc_cleanup(&dev->eq_table.alloc);
 	return err;
@@ -740,5 +958,7 @@ void __devexit mthca_cleanup_eq_table(st
 	for (i = 0; i < MTHCA_NUM_EQ; ++i)
 		mthca_free_eq(dev, &dev->eq_table.eq[i]);
 
+	mthca_unmap_eq_regs(dev);
+
 	mthca_alloc_cleanup(&dev->eq_table.alloc);
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -73,14 +73,15 @@ static const char mthca_version[] __devi
 	DRV_VERSION " (" DRV_RELDATE ")\n";
 
 static struct mthca_profile default_profile = {
-	.num_qp     = 1 << 16,
-	.rdb_per_qp = 4,
-	.num_cq     = 1 << 16,
-	.num_mcg    = 1 << 13,
-	.num_mpt    = 1 << 17,
-	.num_mtt    = 1 << 20,
-	.num_udav   = 1 << 15,	/* Tavor only */
-	.uarc_size  = 1 << 18,	/* Arbel only */
+	.num_qp		   = 1 << 16,
+	.rdb_per_qp	   = 4,
+	.num_cq		   = 1 << 16,
+	.num_mcg	   = 1 << 13,
+	.num_mpt	   = 1 << 17,
+	.num_mtt	   = 1 << 20,
+	.num_udav	   = 1 << 15,	/* Tavor only */
+	.fmr_reserved_mtts = 1 << 18,	/* Tavor only */
+	.uarc_size	   = 1 << 18,	/* Arbel only */
 };
 
 static int __devinit mthca_tune_pci(struct mthca_dev *mdev)
@@ -102,7 +103,7 @@ static int __devinit mthca_tune_pci(stru
 				  "aborting.\n");
 			return -ENODEV;
 		}
-	} else if (mdev->hca_type == TAVOR)
+	} else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE))
 		mthca_info(mdev, "No PCI-X capability, not setting RBC.\n");
 
 	cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
@@ -118,8 +119,7 @@ static int __devinit mthca_tune_pci(stru
 				  "register, aborting.\n");
 			return -ENODEV;
 		}
-	} else if (mdev->hca_type == ARBEL_NATIVE ||
-		   mdev->hca_type == ARBEL_COMPAT)
+	} else if (mdev->mthca_flags & MTHCA_FLAG_PCIE)
 		mthca_info(mdev, "No PCI Express capability, "
 			   "not setting Max Read Request Size.\n");
 
@@ -171,6 +171,33 @@ static int __devinit mthca_dev_lim(struc
 	mdev->limits.reserved_uars      = dev_lim->reserved_uars;
 	mdev->limits.reserved_pds       = dev_lim->reserved_pds;
 
+	/* IB_DEVICE_RESIZE_MAX_WR not supported by driver.
+	   May be doable since hardware supports it for SRQ.
+
+	   IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.
+
+	   IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not
+	   supported by driver. */
+	mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |
+		IB_DEVICE_PORT_ACTIVE_EVENT |
+		IB_DEVICE_SYS_IMAGE_GUID |
+		IB_DEVICE_RC_RNR_NAK_GEN;
+
+	if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)
+		mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
+
+	if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)
+		mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
+
+	if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)
+		mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;
+
+	if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)
+		mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
+
+	if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)
+		mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
+
 	if (dev_lim->flags & DEV_LIM_FLAG_SRQ)
 		mdev->mthca_flags |= MTHCA_FLAG_SRQ;
 
@@ -363,10 +390,9 @@ static int __devinit mthca_init_icm(stru
 	}
 
 	mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,
-							 mdev->limits.num_mtt_segs *
-							 init_hca->mtt_seg_sz,
-							 mdev->limits.reserved_mtts *
-							 init_hca->mtt_seg_sz, 1);
+							 MTHCA_MTT_SEG_SIZE,
+							 mdev->limits.num_mtt_segs,
+							 mdev->limits.reserved_mtts, 1);
 	if (!mdev->mr_table.mtt_table) {
 		mthca_err(mdev, "Failed to map MTT context memory, aborting.\n");
 		err = -ENOMEM;
@@ -374,10 +400,9 @@ static int __devinit mthca_init_icm(stru
 	}
 
 	mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,
-							 mdev->limits.num_mpts *
 							 dev_lim->mpt_entry_sz,
-							 mdev->limits.reserved_mrws *
-							 dev_lim->mpt_entry_sz, 1);
+							 mdev->limits.num_mpts,
+							 mdev->limits.reserved_mrws, 1);
 	if (!mdev->mr_table.mpt_table) {
 		mthca_err(mdev, "Failed to map MPT context memory, aborting.\n");
 		err = -ENOMEM;
@@ -385,10 +410,9 @@ static int __devinit mthca_init_icm(stru
 	}
 
 	mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,
-							mdev->limits.num_qps *
 							dev_lim->qpc_entry_sz,
-							mdev->limits.reserved_qps *
-							dev_lim->qpc_entry_sz, 1);
+							mdev->limits.num_qps,
+							mdev->limits.reserved_qps, 0);
 	if (!mdev->qp_table.qp_table) {
 		mthca_err(mdev, "Failed to map QP context memory, aborting.\n");
 		err = -ENOMEM;
@@ -396,29 +420,62 @@ static int __devinit mthca_init_icm(stru
 	}
 
 	mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,
-							 mdev->limits.num_qps *
 							 dev_lim->eqpc_entry_sz,
-							 mdev->limits.reserved_qps *
-							 dev_lim->eqpc_entry_sz, 1);
+							 mdev->limits.num_qps,
+							 mdev->limits.reserved_qps, 0);
 	if (!mdev->qp_table.eqp_table) {
 		mthca_err(mdev, "Failed to map EQP context memory, aborting.\n");
 		err = -ENOMEM;
 		goto err_unmap_qp;
 	}
 
-	mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
-						     mdev->limits.num_cqs *
+	mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,
+							 MTHCA_RDB_ENTRY_SIZE,
+							 mdev->limits.num_qps <<
+							 mdev->qp_table.rdb_shift,
+							 0, 0);
+	if (!mdev->qp_table.rdb_table) {
+		mthca_err(mdev, "Failed to map RDB context memory, aborting\n");
+		err = -ENOMEM;
+		goto err_unmap_eqp;
+	}
+
+       mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
 						     dev_lim->cqc_entry_sz,
-						     mdev->limits.reserved_cqs *
-						     dev_lim->cqc_entry_sz, 1);
+						     mdev->limits.num_cqs,
+						     mdev->limits.reserved_cqs, 0);
 	if (!mdev->cq_table.table) {
 		mthca_err(mdev, "Failed to map CQ context memory, aborting.\n");
 		err = -ENOMEM;
-		goto err_unmap_eqp;
+		goto err_unmap_rdb;
+	}
+
+	/*
+	 * It's not strictly required, but for simplicity just map the
+	 * whole multicast group table now.  The table isn't very big
+	 * and it's a lot easier than trying to track ref counts.
+	 */
+	mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,
+						      MTHCA_MGM_ENTRY_SIZE,
+						      mdev->limits.num_mgms +
+						      mdev->limits.num_amgms,
+						      mdev->limits.num_mgms +
+						      mdev->limits.num_amgms,
+						      0);
+	if (!mdev->mcg_table.table) {
+		mthca_err(mdev, "Failed to map MCG context memory, aborting.\n");
+		err = -ENOMEM;
+		goto err_unmap_cq;
 	}
 
 	return 0;
 
+err_unmap_cq:
+	mthca_free_icm_table(mdev, mdev->cq_table.table);
+
+err_unmap_rdb:
+	mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
+
 err_unmap_eqp:
 	mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
 
@@ -535,6 +592,7 @@ static int __devinit mthca_init_arbel(st
 
 err_free_icm:
 	mthca_free_icm_table(mdev, mdev->cq_table.table);
+	mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
 	mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
 	mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
 	mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
@@ -557,7 +615,7 @@ err_disable:
 
 static int __devinit mthca_init_hca(struct mthca_dev *mdev)
 {
-	if (mdev->hca_type == ARBEL_NATIVE)
+	if (mthca_is_memfree(mdev))
 		return mthca_init_arbel(mdev);
 	else
 		return mthca_init_tavor(mdev);
@@ -570,11 +628,33 @@ static int __devinit mthca_setup_hca(str
 
 	MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock);
 
+	err = mthca_init_uar_table(dev);
+	if (err) {
+		mthca_err(dev, "Failed to initialize "
+			  "user access region table, aborting.\n");
+		return err;
+	}
+
+	err = mthca_uar_alloc(dev, &dev->driver_uar);
+	if (err) {
+		mthca_err(dev, "Failed to allocate driver access region, "
+			  "aborting.\n");
+		goto err_uar_table_free;
+	}
+
+	dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+	if (!dev->kar) {
+		mthca_err(dev, "Couldn't map kernel access region, "
+			  "aborting.\n");
+		err = -ENOMEM;
+		goto err_uar_free;
+	}
+
 	err = mthca_init_pd_table(dev);
 	if (err) {
 		mthca_err(dev, "Failed to initialize "
 			  "protection domain table, aborting.\n");
-		return err;
+		goto err_kar_unmap;
 	}
 
 	err = mthca_init_mr_table(dev);
@@ -591,13 +671,6 @@ static int __devinit mthca_setup_hca(str
 		goto err_mr_table_free;
 	}
 
-	if (dev->hca_type == ARBEL_NATIVE) {
-		mthca_warn(dev, "Sorry, native MT25208 mode support is not done, "
-			   "aborting.\n");
-		err = -ENODEV;
-		goto err_pd_free;
-	}
-
 	err = mthca_init_eq_table(dev);
 	if (err) {
 		mthca_err(dev, "Failed to initialize "
@@ -614,15 +687,19 @@ static int __devinit mthca_setup_hca(str
 
 	err = mthca_NOP(dev, &status);
 	if (err || status) {
-		mthca_err(dev, "NOP command failed to generate interrupt, aborting.\n");
+		mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n",
+			  dev->mthca_flags & MTHCA_FLAG_MSI_X ?
+			  dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
+			  dev->pdev->irq);
 		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))
 			mthca_err(dev, "Try again with MSI/MSI-X disabled.\n");
 		else
 			mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n");
 
 		goto err_cmd_poll;
-	} else
-		mthca_dbg(dev, "NOP command IRQ test passed\n");
+	}
+
+	mthca_dbg(dev, "NOP command IRQ test passed\n");
 
 	err = mthca_init_cq_table(dev);
 	if (err) {
@@ -677,6 +754,15 @@ err_mr_table_free:
 
 err_pd_table_free:
 	mthca_cleanup_pd_table(dev);
+
+err_kar_unmap:
+	iounmap(dev->kar);
+
+err_uar_free:
+	mthca_uar_free(dev, &dev->driver_uar);
+
+err_uar_table_free:
+	mthca_cleanup_uar_table(dev);
 	return err;
 }
 
@@ -686,37 +772,18 @@ static int __devinit mthca_request_regio
 	int err;
 
 	/*
-	 * We request our first BAR in two chunks, since the MSI-X
-	 * vector table is right in the middle.
+	 * We can't just use pci_request_regions() because the MSI-X
+	 * table is right in the middle of the first BAR.  If we did
+	 * pci_request_region and grab all of the first BAR, then
+	 * setting up MSI-X would fail, since the PCI core wants to do
+	 * request_mem_region on the MSI-X vector table.
 	 *
-	 * This is why we can't just use pci_request_regions() -- if
-	 * we did then setting up MSI-X would fail, since the PCI core
-	 * wants to do request_mem_region on the MSI-X vector table.
+	 * So just request what we need right now, and request any
+	 * other regions we need when setting up EQs.
 	 */
-	if (!request_mem_region(pci_resource_start(pdev, 0) +
-				MTHCA_HCR_BASE,
-				MTHCA_HCR_SIZE,
-				DRV_NAME)) {
-		err = -EBUSY;
-		goto err_hcr_failed;
-	}
-
-	if (!request_mem_region(pci_resource_start(pdev, 0) +
-				MTHCA_ECR_BASE,
-				MTHCA_MAP_ECR_SIZE,
-				DRV_NAME)) {
-		err = -EBUSY;
-		goto err_ecr_failed;
-	}
-
-	if (!request_mem_region(pci_resource_start(pdev, 0) +
-				MTHCA_CLR_INT_BASE,
-				MTHCA_CLR_INT_SIZE,
-				DRV_NAME)) {
-		err = -EBUSY;
-		goto err_int_failed;
-	}
-
+	if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
+				MTHCA_HCR_SIZE, DRV_NAME))
+		return -EBUSY;
 
 	err = pci_request_region(pdev, 2, DRV_NAME);
 	if (err)
@@ -731,24 +798,11 @@ static int __devinit mthca_request_regio
 	return 0;
 
 err_bar4_failed:
-
 	pci_release_region(pdev, 2);
-err_bar2_failed:
 
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_CLR_INT_BASE,
-			   MTHCA_CLR_INT_SIZE);
-err_int_failed:
-
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_ECR_BASE,
-			   MTHCA_MAP_ECR_SIZE);
-err_ecr_failed:
-
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_HCR_BASE,
+err_bar2_failed:
+	release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
 			   MTHCA_HCR_SIZE);
-err_hcr_failed:
 
 	return err;
 }
@@ -761,16 +815,7 @@ static void mthca_release_regions(struct
 
 	pci_release_region(pdev, 2);
 
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_CLR_INT_BASE,
-			   MTHCA_CLR_INT_SIZE);
-
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_ECR_BASE,
-			   MTHCA_MAP_ECR_SIZE);
-
-	release_mem_region(pci_resource_start(pdev, 0) +
-			   MTHCA_HCR_BASE,
+	release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
 			   MTHCA_HCR_SIZE);
 }
 
@@ -804,8 +849,9 @@ static void mthca_close_hca(struct mthca
 
 	mthca_CLOSE_HCA(mdev, 0, &status);
 
-	if (mdev->hca_type == ARBEL_NATIVE) {
+	if (mthca_is_memfree(mdev)) {
 		mthca_free_icm_table(mdev, mdev->cq_table.table);
+		mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
 		mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
 		mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
 		mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
@@ -824,13 +870,34 @@ static void mthca_close_hca(struct mthca
 		mthca_SYS_DIS(mdev, &status);
 }
 
+/* Types of supported HCA */
+enum {
+	TAVOR,			/* MT23108                        */
+	ARBEL_COMPAT,		/* MT25208 in Tavor compat mode   */
+	ARBEL_NATIVE,		/* MT25208 with extended features */
+	SINAI			/* MT25204 */
+};
+
+#define MTHCA_FW_VER(major, minor, subminor) \
+	(((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))
+
+static struct {
+	u64 latest_fw;
+	int is_memfree;
+	int is_pcie;
+} mthca_hca_table[] = {
+	[TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 3, 2), .is_memfree = 0, .is_pcie = 0 },
+	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 6, 2), .is_memfree = 0, .is_pcie = 1 },
+	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 0, 1), .is_memfree = 1, .is_pcie = 1 },
+	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 1), .is_memfree = 1, .is_pcie = 1 }
+};
+
 static int __devinit mthca_init_one(struct pci_dev *pdev,
 				    const struct pci_device_id *id)
 {
 	static int mthca_version_printed = 0;
 	int ddr_hidden = 0;
 	int err;
-	unsigned long mthca_base;
 	struct mthca_dev *mdev;
 
 	if (!mthca_version_printed) {
@@ -841,6 +908,12 @@ static int __devinit mthca_init_one(stru
 	printk(KERN_INFO PFX "Initializing %s (%s)\n",
 	       pci_pretty_name(pdev), pci_name(pdev));
 
+	if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {
+		printk(KERN_ERR PFX "%s (%s) has invalid driver data %lx\n",
+		       pci_pretty_name(pdev), pci_name(pdev), id->driver_data);
+		return -ENODEV;
+	}
+
 	err = pci_enable_device(pdev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot enable PCI device, "
@@ -905,11 +978,14 @@ static int __devinit mthca_init_one(stru
 		goto err_free_res;
 	}
 
-	mdev->pdev     = pdev;
-	mdev->hca_type = id->driver_data;
+	mdev->pdev = pdev;
 
 	if (ddr_hidden)
 		mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
+	if (mthca_hca_table[id->driver_data].is_memfree)
+		mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
+	if (mthca_hca_table[id->driver_data].is_pcie)
+		mdev->mthca_flags |= MTHCA_FLAG_PCIE;
 
 	/*
 	 * Now reset the HCA before we touch the PCI capabilities or
@@ -932,8 +1008,7 @@ static int __devinit mthca_init_one(stru
 	sema_init(&mdev->cmd.poll_sem, 1);
 	mdev->cmd.use_events = 0;
 
-	mthca_base = pci_resource_start(pdev, 0);
-	mdev->hcr = ioremap(mthca_base + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
+	mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
 	if (!mdev->hcr) {
 		mthca_err(mdev, "Couldn't map command register, "
 			  "aborting.\n");
@@ -941,40 +1016,23 @@ static int __devinit mthca_init_one(stru
 		goto err_free_dev;
 	}
 
-	mdev->clr_base = ioremap(mthca_base + MTHCA_CLR_INT_BASE,
-				 MTHCA_CLR_INT_SIZE);
-	if (!mdev->clr_base) {
-		mthca_err(mdev, "Couldn't map interrupt clear register, "
-			  "aborting.\n");
-		err = -ENOMEM;
-		goto err_iounmap;
-	}
-
-	mdev->ecr_base = ioremap(mthca_base + MTHCA_ECR_BASE,
-				 MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE);
-	if (!mdev->ecr_base) {
-		mthca_err(mdev, "Couldn't map ecr register, "
-			  "aborting.\n");
-		err = -ENOMEM;
-		goto err_iounmap_clr;
-	}
-
-	mthca_base = pci_resource_start(pdev, 2);
-	mdev->kar = ioremap(mthca_base + PAGE_SIZE * MTHCA_KAR_PAGE, PAGE_SIZE);
-	if (!mdev->kar) {
-		mthca_err(mdev, "Couldn't map kernel access region, "
-			  "aborting.\n");
-		err = -ENOMEM;
-		goto err_iounmap_ecr;
-	}
-
 	err = mthca_tune_pci(mdev);
 	if (err)
-		goto err_iounmap_kar;
+		goto err_iounmap;
 
 	err = mthca_init_hca(mdev);
 	if (err)
-		goto err_iounmap_kar;
+		goto err_iounmap;
+
+	if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
+		mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
+			   (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
+			   (int) (mdev->fw_ver & 0xffff),
+			   (int) (mthca_hca_table[id->driver_data].latest_fw >> 32),
+			   (int) (mthca_hca_table[id->driver_data].latest_fw >> 16) & 0xffff,
+			   (int) (mthca_hca_table[id->driver_data].latest_fw & 0xffff));
+		mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
+	}
 
 	err = mthca_setup_hca(mdev);
 	if (err)
@@ -1007,19 +1065,11 @@ err_cleanup:
 
 	mthca_cleanup_mr_table(mdev);
 	mthca_cleanup_pd_table(mdev);
+	mthca_cleanup_uar_table(mdev);
 
 err_close:
 	mthca_close_hca(mdev);
 
-err_iounmap_kar:
-	iounmap(mdev->kar);
-
-err_iounmap_ecr:
-	iounmap(mdev->ecr_base);
-
-err_iounmap_clr:
-	iounmap(mdev->clr_base);
-
 err_iounmap:
 	iounmap(mdev->hcr);
 
@@ -1065,11 +1115,13 @@ static void __devexit mthca_remove_one(s
 		mthca_cleanup_mr_table(mdev);
 		mthca_cleanup_pd_table(mdev);
 
+		iounmap(mdev->kar);
+		mthca_uar_free(mdev, &mdev->driver_uar);
+		mthca_cleanup_uar_table(mdev);
+
 		mthca_close_hca(mdev);
 
 		iounmap(mdev->hcr);
-		iounmap(mdev->ecr_base);
-		iounmap(mdev->clr_base);
 
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 			pci_disable_msix(pdev);
@@ -1097,6 +1149,14 @@ static struct pci_device_id mthca_pci_ta
 	  .driver_data = ARBEL_NATIVE },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL),
 	  .driver_data = ARBEL_NATIVE },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI),
+	  .driver_data = SINAI },
+	{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI),
+	  .driver_data = SINAI },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD),
+	  .driver_data = SINAI },
+	{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD),
+	  .driver_data = SINAI },
 	{ 0, }
 };
 
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -32,6 +32,8 @@
  * $Id$
  */
 
+#include <linux/mm.h>
+
 #include "mthca_memfree.h"
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
@@ -79,6 +81,7 @@ struct mthca_icm *mthca_alloc_icm(struct
 	if (!icm)
 		return icm;
 
+	icm->refcount = 0;
 	INIT_LIST_HEAD(&icm->chunk_list);
 
 	cur_order = get_order(MTHCA_ICM_ALLOC_SIZE);
@@ -138,9 +141,128 @@ fail:
 	return NULL;
 }
 
+int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
+{
+	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+	int ret = 0;
+	u8 status;
+
+	down(&table->mutex);
+
+	if (table->icm[i]) {
+		++table->icm[i]->refcount;
+		goto out;
+	}
+
+	table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
+					(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
+					__GFP_NOWARN);
+	if (!table->icm[i]) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
+			  &status) || status) {
+		mthca_free_icm(dev, table->icm[i]);
+		table->icm[i] = NULL;
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	++table->icm[i]->refcount;
+
+out:
+	up(&table->mutex);
+	return ret;
+}
+
+void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
+{
+	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+	u8 status;
+
+	down(&table->mutex);
+
+	if (--table->icm[i]->refcount == 0) {
+		mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
+				MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+		mthca_free_icm(dev, table->icm[i]);
+		table->icm[i] = NULL;
+	}
+
+	up(&table->mutex);
+}
+
+void *mthca_table_find(struct mthca_icm_table *table, int obj)
+{
+	int idx, offset, i;
+	struct mthca_icm_chunk *chunk;
+	struct mthca_icm *icm;
+	struct page *page = NULL;
+
+	if (!table->lowmem)
+		return NULL;
+
+	down(&table->mutex);
+
+	idx = (obj & (table->num_obj - 1)) * table->obj_size;
+	icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE];
+	offset = idx % MTHCA_TABLE_CHUNK_SIZE;
+
+	if (!icm)
+		goto out;
+
+	list_for_each_entry(chunk, &icm->chunk_list, list) {
+		for (i = 0; i < chunk->npages; ++i) {
+			if (chunk->mem[i].length >= offset) {
+				page = chunk->mem[i].page;
+				break;
+			}
+			offset -= chunk->mem[i].length;
+		}
+	}
+
+out:
+	up(&table->mutex);
+	return page ? lowmem_page_address(page) + offset : NULL;
+}
+
+int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table,
+			  int start, int end)
+{
+	int inc = MTHCA_TABLE_CHUNK_SIZE / table->obj_size;
+	int i, err;
+
+	for (i = start; i <= end; i += inc) {
+		err = mthca_table_get(dev, table, i);
+		if (err)
+			goto fail;
+	}
+
+	return 0;
+
+fail:
+	while (i > start) {
+		i -= inc;
+		mthca_table_put(dev, table, i);
+	}
+
+	return err;
+}
+
+void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
+			   int start, int end)
+{
+	int i;
+
+	for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
+		mthca_table_put(dev, table, i);
+}
+
 struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
-					      u64 virt, unsigned size,
-					      unsigned reserved,
+					      u64 virt, int obj_size,
+					      int nobj, int reserved,
 					      int use_lowmem)
 {
 	struct mthca_icm_table *table;
@@ -148,20 +270,23 @@ struct mthca_icm_table *mthca_alloc_icm_
 	int i;
 	u8 status;
 
-	num_icm = size / MTHCA_TABLE_CHUNK_SIZE;
+	num_icm = obj_size * nobj / MTHCA_TABLE_CHUNK_SIZE;
 
 	table = kmalloc(sizeof *table + num_icm * sizeof *table->icm, GFP_KERNEL);
 	if (!table)
 		return NULL;
 
-	table->virt    = virt;
-	table->num_icm = num_icm;
-	init_MUTEX(&table->sem);
+	table->virt     = virt;
+	table->num_icm  = num_icm;
+	table->num_obj  = nobj;
+	table->obj_size = obj_size;
+	table->lowmem   = use_lowmem;
+	init_MUTEX(&table->mutex);
 
 	for (i = 0; i < num_icm; ++i)
 		table->icm[i] = NULL;
 
-	for (i = 0; i < (reserved + MTHCA_TABLE_CHUNK_SIZE - 1) / MTHCA_TABLE_CHUNK_SIZE; ++i) {
+	for (i = 0; i * MTHCA_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
 		table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
 						(use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
 						__GFP_NOWARN);
@@ -173,6 +298,12 @@ struct mthca_icm_table *mthca_alloc_icm_
 			table->icm[i] = NULL;
 			goto err;
 		}
+
+		/*
+		 * Add a reference to this ICM chunk so that it never
+		 * gets freed (since it contains reserved firmware objects).
+		 */
+		++table->icm[i]->refcount;
 	}
 
 	return table;
@@ -204,3 +335,200 @@ void mthca_free_icm_table(struct mthca_d
 
 	kfree(table);
 }
+
+static u64 mthca_uarc_virt(struct mthca_dev *dev, int page)
+{
+	return dev->uar_table.uarc_base +
+		dev->driver_uar.index * dev->uar_table.uarc_size +
+		page * 4096;
+}
+
+int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
+{
+	int group;
+	int start, end, dir;
+	int i, j;
+	struct mthca_db_page *page;
+	int ret = 0;
+	u8 status;
+
+	down(&dev->db_tab->mutex);
+
+	switch (type) {
+	case MTHCA_DB_TYPE_CQ_ARM:
+	case MTHCA_DB_TYPE_SQ:
+		group = 0;
+		start = 0;
+		end   = dev->db_tab->max_group1;
+		dir   = 1;
+		break;
+
+	case MTHCA_DB_TYPE_CQ_SET_CI:
+	case MTHCA_DB_TYPE_RQ:
+	case MTHCA_DB_TYPE_SRQ:
+		group = 1;
+		start = dev->db_tab->npages - 1;
+		end   = dev->db_tab->min_group2;
+		dir   = -1;
+		break;
+
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	for (i = start; i != end; i += dir)
+		if (dev->db_tab->page[i].db_rec &&
+		    !bitmap_full(dev->db_tab->page[i].used,
+				 MTHCA_DB_REC_PER_PAGE)) {
+			page = dev->db_tab->page + i;
+			goto found;
+		}
+
+	if (dev->db_tab->max_group1 >= dev->db_tab->min_group2 - 1) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	page = dev->db_tab->page + end;
+	page->db_rec = dma_alloc_coherent(&dev->pdev->dev, 4096,
+					  &page->mapping, GFP_KERNEL);
+	if (!page->db_rec) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(page->db_rec, 0, 4096);
+
+	ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status);
+	if (!ret && status)
+		ret = -EINVAL;
+	if (ret) {
+		dma_free_coherent(&dev->pdev->dev, 4096,
+				  page->db_rec, page->mapping);
+		goto out;
+	}
+
+	bitmap_zero(page->used, MTHCA_DB_REC_PER_PAGE);
+	if (group == 0)
+		++dev->db_tab->max_group1;
+	else
+		--dev->db_tab->min_group2;
+
+found:
+	j = find_first_zero_bit(page->used, MTHCA_DB_REC_PER_PAGE);
+	set_bit(j, page->used);
+
+	if (group == 1)
+		j = MTHCA_DB_REC_PER_PAGE - 1 - j;
+
+	ret = i * MTHCA_DB_REC_PER_PAGE + j;
+
+	page->db_rec[j] = cpu_to_be64((qn << 8) | (type << 5));
+
+	*db = (u32 *) &page->db_rec[j];
+
+out:
+	up(&dev->db_tab->mutex);
+
+	return ret;
+}
+
+void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
+{
+	int i, j;
+	struct mthca_db_page *page;
+	u8 status;
+
+	i = db_index / MTHCA_DB_REC_PER_PAGE;
+	j = db_index % MTHCA_DB_REC_PER_PAGE;
+
+	page = dev->db_tab->page + i;
+
+	down(&dev->db_tab->mutex);
+
+	page->db_rec[j] = 0;
+	if (i >= dev->db_tab->min_group2)
+		j = MTHCA_DB_REC_PER_PAGE - 1 - j;
+	clear_bit(j, page->used);
+
+	if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
+	    i >= dev->db_tab->max_group1 - 1) {
+		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+
+		dma_free_coherent(&dev->pdev->dev, 4096,
+				  page->db_rec, page->mapping);
+		page->db_rec = NULL;
+
+		if (i == dev->db_tab->max_group1) {
+			--dev->db_tab->max_group1;
+			/* XXX may be able to unmap more pages now */
+		}
+		if (i == dev->db_tab->min_group2)
+			++dev->db_tab->min_group2;
+	}
+
+	up(&dev->db_tab->mutex);
+}
+
+int mthca_init_db_tab(struct mthca_dev *dev)
+{
+	int i;
+
+	if (!mthca_is_memfree(dev))
+		return 0;
+
+	dev->db_tab = kmalloc(sizeof *dev->db_tab, GFP_KERNEL);
+	if (!dev->db_tab)
+		return -ENOMEM;
+
+	init_MUTEX(&dev->db_tab->mutex);
+
+	dev->db_tab->npages     = dev->uar_table.uarc_size / 4096;
+	dev->db_tab->max_group1 = 0;
+	dev->db_tab->min_group2 = dev->db_tab->npages - 1;
+
+	dev->db_tab->page = kmalloc(dev->db_tab->npages *
+				    sizeof *dev->db_tab->page,
+				    GFP_KERNEL);
+	if (!dev->db_tab->page) {
+		kfree(dev->db_tab);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->db_tab->npages; ++i)
+		dev->db_tab->page[i].db_rec = NULL;
+
+	return 0;
+}
+
+void mthca_cleanup_db_tab(struct mthca_dev *dev)
+{
+	int i;
+	u8 status;
+
+	if (!mthca_is_memfree(dev))
+		return;
+
+	/*
+	 * Because we don't always free our UARC pages when they
+	 * become empty to make mthca_free_db() simpler we need to
+	 * make a sweep through the doorbell pages and free any
+	 * leftover pages now.
+	 */
+	for (i = 0; i < dev->db_tab->npages; ++i) {
+		if (!dev->db_tab->page[i].db_rec)
+			continue;
+
+		if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
+			mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
+
+		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+
+		dma_free_coherent(&dev->pdev->dev, 4096,
+				  dev->db_tab->page[i].db_rec,
+				  dev->db_tab->page[i].mapping);
+	}
+
+	kfree(dev->db_tab->page);
+	kfree(dev->db_tab);
+}
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -53,12 +53,16 @@ struct mthca_icm_chunk {
 
 struct mthca_icm {
 	struct list_head chunk_list;
+	int              refcount;
 };
 
 struct mthca_icm_table {
 	u64               virt;
 	int               num_icm;
-	struct semaphore  sem;
+	int               num_obj;
+	int               obj_size;
+	int               lowmem;
+	struct semaphore  mutex;
 	struct mthca_icm *icm[0];
 };
 
@@ -75,10 +79,17 @@ struct mthca_icm *mthca_alloc_icm(struct
 void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm);
 
 struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
-					      u64 virt, unsigned size,
-					      unsigned reserved,
+					      u64 virt, int obj_size,
+					      int nobj, int reserved,
 					      int use_lowmem);
 void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table);
+int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj);
+void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj);
+void *mthca_table_find(struct mthca_icm_table *table, int obj);
+int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table,
+			  int start, int end);
+void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
+			   int start, int end);
 
 static inline void mthca_icm_first(struct mthca_icm *icm,
 				   struct mthca_icm_iter *iter)
@@ -119,4 +130,37 @@ static inline unsigned long mthca_icm_si
 	return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
 }
 
+enum {
+	MTHCA_DB_REC_PER_PAGE = 4096 / 8
+};
+
+struct mthca_db_page {
+	DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE);
+	u64       *db_rec;
+	dma_addr_t mapping;
+};
+
+struct mthca_db_table {
+	int 	       	      npages;
+	int 	       	      max_group1;
+	int 	       	      min_group2;
+	struct mthca_db_page *page;
+	struct semaphore      mutex;
+};
+
+enum {
+	MTHCA_DB_TYPE_INVALID   = 0x0,
+	MTHCA_DB_TYPE_CQ_SET_CI = 0x1,
+	MTHCA_DB_TYPE_CQ_ARM    = 0x2,
+	MTHCA_DB_TYPE_SQ        = 0x3,
+	MTHCA_DB_TYPE_RQ        = 0x4,
+	MTHCA_DB_TYPE_SRQ       = 0x5,
+	MTHCA_DB_TYPE_GROUP_SEP = 0x7
+};
+
+int mthca_init_db_tab(struct mthca_dev *dev);
+void mthca_cleanup_db_tab(struct mthca_dev *dev);
+int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db);
+void mthca_free_db(struct mthca_dev *dev, int type, int db_index);
+
 #endif /* MTHCA_MEMFREE_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -38,6 +38,7 @@
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
+#include "mthca_memfree.h"
 
 /*
  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
@@ -53,7 +54,8 @@ struct mthca_mpt_entry {
 	u32 window_count;
 	u32 window_count_limit;
 	u64 mtt_seg;
-	u32 reserved[3];
+	u32 mtt_sz;		/* Arbel only */
+	u32 reserved[2];
 } __attribute__((packed));
 
 #define MTHCA_MPT_FLAG_SW_OWNS       (0xfUL << 28)
@@ -64,84 +66,205 @@ struct mthca_mpt_entry {
 
 #define MTHCA_MTT_FLAG_PRESENT       1
 
+#define MTHCA_MPT_STATUS_SW 0xF0
+#define MTHCA_MPT_STATUS_HW 0x00
+
 /*
  * Buddy allocator for MTT segments (currently not very efficient
  * since it doesn't keep a free list and just searches linearly
  * through the bitmaps)
  */
 
-static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order)
+static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order)
 {
 	int o;
 	int m;
 	u32 seg;
 
-	spin_lock(&dev->mr_table.mpt_alloc.lock);
+	spin_lock(&buddy->lock);
 
-	for (o = order; o <= dev->mr_table.max_mtt_order; ++o) {
-		m = 1 << (dev->mr_table.max_mtt_order - o);
-		seg = find_first_bit(dev->mr_table.mtt_buddy[o], m);
+	for (o = order; o <= buddy->max_order; ++o) {
+		m = 1 << (buddy->max_order - o);
+		seg = find_first_bit(buddy->bits[o], m);
 		if (seg < m)
 			goto found;
 	}
 
-	spin_unlock(&dev->mr_table.mpt_alloc.lock);
+	spin_unlock(&buddy->lock);
 	return -1;
 
  found:
-	clear_bit(seg, dev->mr_table.mtt_buddy[o]);
+	clear_bit(seg, buddy->bits[o]);
 
 	while (o > order) {
 		--o;
 		seg <<= 1;
-		set_bit(seg ^ 1, dev->mr_table.mtt_buddy[o]);
+		set_bit(seg ^ 1, buddy->bits[o]);
 	}
 
-	spin_unlock(&dev->mr_table.mpt_alloc.lock);
+	spin_unlock(&buddy->lock);
 
 	seg <<= order;
 
 	return seg;
 }
 
-static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order)
+static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order)
 {
 	seg >>= order;
 
-	spin_lock(&dev->mr_table.mpt_alloc.lock);
+	spin_lock(&buddy->lock);
 
-	while (test_bit(seg ^ 1, dev->mr_table.mtt_buddy[order])) {
-		clear_bit(seg ^ 1, dev->mr_table.mtt_buddy[order]);
+	while (test_bit(seg ^ 1, buddy->bits[order])) {
+		clear_bit(seg ^ 1, buddy->bits[order]);
 		seg >>= 1;
 		++order;
 	}
 
-	set_bit(seg, dev->mr_table.mtt_buddy[order]);
+	set_bit(seg, buddy->bits[order]);
+
+	spin_unlock(&buddy->lock);
+}
+
+static int __devinit mthca_buddy_init(struct mthca_buddy *buddy, int max_order)
+{
+	int i, s;
+
+	buddy->max_order = max_order;
+	spin_lock_init(&buddy->lock);
+
+	buddy->bits = kmalloc((buddy->max_order + 1) * sizeof (long *),
+			      GFP_KERNEL);
+	if (!buddy->bits)
+		goto err_out;
+
+	memset(buddy->bits, 0, (buddy->max_order + 1) * sizeof (long *));
+
+	for (i = 0; i <= buddy->max_order; ++i) {
+		s = BITS_TO_LONGS(1 << (buddy->max_order - i));
+		buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
+		if (!buddy->bits[i])
+			goto err_out_free;
+		bitmap_zero(buddy->bits[i],
+			    1 << (buddy->max_order - i));
+	}
+
+	set_bit(0, buddy->bits[buddy->max_order]);
+
+	return 0;
+
+err_out_free:
+	for (i = 0; i <= buddy->max_order; ++i)
+		kfree(buddy->bits[i]);
 
-	spin_unlock(&dev->mr_table.mpt_alloc.lock);
+	kfree(buddy->bits);
+
+err_out:
+	return -ENOMEM;
+}
+
+static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
+{
+	int i;
+
+	for (i = 0; i <= buddy->max_order; ++i)
+		kfree(buddy->bits[i]);
+
+	kfree(buddy->bits);
+}
+
+static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
+			   struct mthca_buddy *buddy)
+{
+	u32 seg = mthca_buddy_alloc(buddy, order);
+
+	if (seg == -1)
+		return -1;
+
+	if (mthca_is_memfree(dev))
+		if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg,
+					  seg + (1 << order) - 1)) {
+			mthca_buddy_free(buddy, seg, order);
+			seg = -1;
+		}
+
+	return seg;
+}
+
+static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
+			   struct mthca_buddy* buddy)
+{
+	mthca_buddy_free(buddy, seg, order);
+
+	if (mthca_is_memfree(dev))
+		mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
+				      seg + (1 << order) - 1);
+}
+
+static inline u32 tavor_hw_index_to_key(u32 ind)
+{
+	return ind;
+}
+
+static inline u32 tavor_key_to_hw_index(u32 key)
+{
+	return key;
+}
+
+static inline u32 arbel_hw_index_to_key(u32 ind)
+{
+	return (ind >> 24) | (ind << 8);
+}
+
+static inline u32 arbel_key_to_hw_index(u32 key)
+{
+	return (key << 24) | (key >> 8);
+}
+
+static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind)
+{
+	if (mthca_is_memfree(dev))
+		return arbel_hw_index_to_key(ind);
+	else
+		return tavor_hw_index_to_key(ind);
+}
+
+static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
+{
+	if (mthca_is_memfree(dev))
+		return arbel_key_to_hw_index(key);
+	else
+		return tavor_key_to_hw_index(key);
 }
 
 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 			   u32 access, struct mthca_mr *mr)
 {
-	void *mailbox;
+	void *mailbox = NULL;
 	struct mthca_mpt_entry *mpt_entry;
+	u32 key;
 	int err;
 	u8 status;
 
 	might_sleep();
 
 	mr->order = -1;
-	mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);
-	if (mr->ibmr.lkey == -1)
+	key = mthca_alloc(&dev->mr_table.mpt_alloc);
+	if (key == -1)
 		return -ENOMEM;
-	mr->ibmr.rkey = mr->ibmr.lkey;
+	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
+
+	if (mthca_is_memfree(dev)) {
+		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
+		if (err)
+			goto err_out_mpt_free;
+	}
 
 	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
 			  GFP_KERNEL);
 	if (!mailbox) {
-		mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto err_out_table;
 	}
 	mpt_entry = MAILBOX_ALIGN(mailbox);
 
@@ -151,7 +274,7 @@ int mthca_mr_alloc_notrans(struct mthca_
 				       MTHCA_MPT_FLAG_REGION      |
 				       access);
 	mpt_entry->page_size = 0;
-	mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);
+	mpt_entry->key       = cpu_to_be32(key);
 	mpt_entry->pd        = cpu_to_be32(pd);
 	mpt_entry->start     = 0;
 	mpt_entry->length    = ~0ULL;
@@ -160,18 +283,29 @@ int mthca_mr_alloc_notrans(struct mthca_
 	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 
 	err = mthca_SW2HW_MPT(dev, mpt_entry,
-			      mr->ibmr.lkey & (dev->limits.num_mpts - 1),
+			      key & (dev->limits.num_mpts - 1),
 			      &status);
-	if (err)
+	if (err) {
 		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
-	else if (status) {
+		goto err_out_table;
+	} else if (status) {
 		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 			   status);
 		err = -EINVAL;
+		goto err_out_table;
 	}
 
 	kfree(mailbox);
 	return err;
+
+err_out_table:
+	if (mthca_is_memfree(dev))
+		mthca_table_put(dev, dev->mr_table.mpt_table, key);
+
+err_out_mpt_free:
+	mthca_free(&dev->mr_table.mpt_alloc, key);
+	kfree(mailbox);
+	return err;
 }
 
 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
@@ -182,6 +316,7 @@ int mthca_mr_alloc_phys(struct mthca_dev
 	void *mailbox;
 	u64 *mtt_entry;
 	struct mthca_mpt_entry *mpt_entry;
+	u32 key;
 	int err = -ENOMEM;
 	u8 status;
 	int i;
@@ -189,19 +324,26 @@ int mthca_mr_alloc_phys(struct mthca_dev
 	might_sleep();
 	WARN_ON(buffer_size_shift >= 32);
 
-	mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);
-	if (mr->ibmr.lkey == -1)
+	key = mthca_alloc(&dev->mr_table.mpt_alloc);
+	if (key == -1)
 		return -ENOMEM;
-	mr->ibmr.rkey = mr->ibmr.lkey;
+	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
 
-	for (i = dev->limits.mtt_seg_size / 8, mr->order = 0;
+	if (mthca_is_memfree(dev)) {
+		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
+		if (err)
+			goto err_out_mpt_free;
+	}
+
+	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
 	     i < list_len;
 	     i <<= 1, ++mr->order)
 		; /* nothing */
 
-	mr->first_seg = mthca_alloc_mtt(dev, mr->order);
+	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
+				       	&dev->mr_table.mtt_buddy);
 	if (mr->first_seg == -1)
-		goto err_out_mpt_free;
+		goto err_out_table;
 
 	/*
 	 * If list_len is odd, we add one more dummy entry for
@@ -217,7 +359,7 @@ int mthca_mr_alloc_phys(struct mthca_dev
 	mtt_entry = MAILBOX_ALIGN(mailbox);
 
 	mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
-				   mr->first_seg * dev->limits.mtt_seg_size);
+				   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 	mtt_entry[1] = 0;
 	for (i = 0; i < list_len; ++i)
 		mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
@@ -254,14 +396,14 @@ int mthca_mr_alloc_phys(struct mthca_dev
 				       access);
 
 	mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
-	mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);
+	mpt_entry->key       = cpu_to_be32(key);
 	mpt_entry->pd        = cpu_to_be32(pd);
 	mpt_entry->start     = cpu_to_be64(iova);
 	mpt_entry->length    = cpu_to_be64(total_size);
 	memset(&mpt_entry->lkey, 0,
 	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
-					   mr->first_seg * dev->limits.mtt_seg_size);
+					   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 
 	if (0) {
 		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -275,7 +417,7 @@ int mthca_mr_alloc_phys(struct mthca_dev
 	}
 
 	err = mthca_SW2HW_MPT(dev, mpt_entry,
-			      mr->ibmr.lkey & (dev->limits.num_mpts - 1),
+			      key & (dev->limits.num_mpts - 1),
 			      &status);
 	if (err)
 		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
@@ -288,17 +430,35 @@ int mthca_mr_alloc_phys(struct mthca_dev
 	kfree(mailbox);
 	return err;
 
- err_out_mailbox_free:
+err_out_mailbox_free:
 	kfree(mailbox);
 
- err_out_free_mtt:
-	mthca_free_mtt(dev, mr->first_seg, mr->order);
+err_out_free_mtt:
+	mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
 
- err_out_mpt_free:
-	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
+err_out_table:
+	if (mthca_is_memfree(dev))
+		mthca_table_put(dev, dev->mr_table.mpt_table, key);
+
+err_out_mpt_free:
+	mthca_free(&dev->mr_table.mpt_alloc, key);
 	return err;
 }
 
+/* Free mr or fmr */
+static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
+			      u32 first_seg, struct mthca_buddy *buddy)
+{
+	if (order >= 0)
+		mthca_free_mtt(dev, first_seg, order, buddy);
+
+	if (mthca_is_memfree(dev))
+		mthca_table_put(dev, dev->mr_table.mpt_table,
+				arbel_key_to_hw_index(lkey));
+
+	mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
+}
+
 void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
 {
 	int err;
@@ -307,7 +467,8 @@ void mthca_free_mr(struct mthca_dev *dev
 	might_sleep();
 
 	err = mthca_HW2SW_MPT(dev, NULL,
-			      mr->ibmr.lkey & (dev->limits.num_mpts - 1),
+			      key_to_hw_index(dev, mr->ibmr.lkey) &
+			      (dev->limits.num_mpts - 1),
 			      &status);
 	if (err)
 		mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err);
@@ -315,16 +476,288 @@ void mthca_free_mr(struct mthca_dev *dev
 		mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
 			   status);
 
-	if (mr->order >= 0)
-		mthca_free_mtt(dev, mr->first_seg, mr->order);
+	mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
+			  &dev->mr_table.mtt_buddy);
+}
+
+int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
+		    u32 access, struct mthca_fmr *mr)
+{
+	struct mthca_mpt_entry *mpt_entry;
+	void *mailbox;
+	u64 mtt_seg;
+	u32 key, idx;
+	u8 status;
+	int list_len = mr->attr.max_pages;
+	int err = -ENOMEM;
+	int i;
+
+	might_sleep();
+
+	if (mr->attr.page_size < 12 || mr->attr.page_size >= 32)
+		return -EINVAL;
+
+	/* For Arbel, all MTTs must fit in the same page. */
+	if (mthca_is_memfree(dev) &&
+	    mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE)
+		return -EINVAL;
 
+	mr->maps = 0;
+
+	key = mthca_alloc(&dev->mr_table.mpt_alloc);
+	if (key == -1)
+		return -ENOMEM;
+
+	idx = key & (dev->limits.num_mpts - 1);
+	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
+
+	if (mthca_is_memfree(dev)) {
+		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
+		if (err)
+			goto err_out_mpt_free;
+
+		mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key);
+		BUG_ON(!mr->mem.arbel.mpt);
+	} else
+		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
+		       	sizeof *(mr->mem.tavor.mpt) * idx;
+
+	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
+	     i < list_len;
+	     i <<= 1, ++mr->order)
+		; /* nothing */
+
+	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
+				       	dev->mr_table.fmr_mtt_buddy);
+	if (mr->first_seg == -1)
+		goto err_out_table;
+
+	mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
+
+	if (mthca_is_memfree(dev)) {
+		mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
+						      mr->first_seg);
+		BUG_ON(!mr->mem.arbel.mtts);
+	} else
+		mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
+
+	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
+			  GFP_KERNEL);
+	if (!mailbox)
+		goto err_out_free_mtt;
+
+	mpt_entry = MAILBOX_ALIGN(mailbox);
+
+	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
+				       MTHCA_MPT_FLAG_MIO         |
+				       MTHCA_MPT_FLAG_REGION      |
+				       access);
+
+	mpt_entry->page_size = cpu_to_be32(mr->attr.page_size - 12);
+	mpt_entry->key       = cpu_to_be32(key);
+	mpt_entry->pd        = cpu_to_be32(pd);
+	memset(&mpt_entry->start, 0,
+	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start));
+	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base + mtt_seg);
+
+	if (0) {
+		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
+		for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) {
+			if (i % 4 == 0)
+				printk("[%02x] ", i * 4);
+			printk(" %08x", be32_to_cpu(((u32 *) mpt_entry)[i]));
+			if ((i + 1) % 4 == 0)
+				printk("\n");
+		}
+	}
+
+	err = mthca_SW2HW_MPT(dev, mpt_entry,
+			      key & (dev->limits.num_mpts - 1),
+			      &status);
+	if (err) {
+		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
+		goto err_out_mailbox_free;
+	}
+	if (status) {
+		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
+			   status);
+		err = -EINVAL;
+		goto err_out_mailbox_free;
+	}
+
+	kfree(mailbox);
+	return 0;
+
+err_out_mailbox_free:
+	kfree(mailbox);
+
+err_out_free_mtt:
+	mthca_free_mtt(dev, mr->first_seg, mr->order,
+		       dev->mr_table.fmr_mtt_buddy);
+
+err_out_table:
+	if (mthca_is_memfree(dev))
+		mthca_table_put(dev, dev->mr_table.mpt_table, key);
+
+err_out_mpt_free:
 	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
+	return err;
+}
+
+int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
+{
+	if (fmr->maps)
+		return -EBUSY;
+
+	mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
+			  dev->mr_table.fmr_mtt_buddy);
+	return 0;
+}
+
+static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list,
+				  int list_len, u64 iova)
+{
+	int i, page_mask;
+
+	if (list_len > fmr->attr.max_pages)
+		return -EINVAL;
+
+	page_mask = (1 << fmr->attr.page_size) - 1;
+
+	/* We are getting page lists, so va must be page aligned. */
+	if (iova & page_mask)
+		return -EINVAL;
+
+	/* Trust the user not to pass misaligned data in page_list */
+	if (0)
+		for (i = 0; i < list_len; ++i) {
+			if (page_list[i] & ~page_mask)
+				return -EINVAL;
+		}
+
+	if (fmr->maps >= fmr->attr.max_maps)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+			     int list_len, u64 iova)
+{
+	struct mthca_fmr *fmr = to_mfmr(ibfmr);
+	struct mthca_dev *dev = to_mdev(ibfmr->device);
+	struct mthca_mpt_entry mpt_entry;
+	u32 key;
+	int i, err;
+
+	err = mthca_check_fmr(fmr, page_list, list_len, iova);
+	if (err)
+		return err;
+
+	++fmr->maps;
+
+	key = tavor_key_to_hw_index(fmr->ibmr.lkey);
+	key += dev->limits.num_mpts;
+	fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
+
+	writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
+
+	for (i = 0; i < list_len; ++i) {
+		__be64 mtt_entry = cpu_to_be64(page_list[i] |
+					       MTHCA_MTT_FLAG_PRESENT);
+		mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i);
+	}
+
+	mpt_entry.lkey   = cpu_to_be32(key);
+	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	mpt_entry.start  = cpu_to_be64(iova);
+
+	writel(mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
+	memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start,
+		    offsetof(struct mthca_mpt_entry, window_count) -
+		    offsetof(struct mthca_mpt_entry, start));
+
+	writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt);
+
+	return 0;
+}
+
+int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+			     int list_len, u64 iova)
+{
+	struct mthca_fmr *fmr = to_mfmr(ibfmr);
+	struct mthca_dev *dev = to_mdev(ibfmr->device);
+	u32 key;
+	int i, err;
+
+	err = mthca_check_fmr(fmr, page_list, list_len, iova);
+	if (err)
+		return err;
+
+	++fmr->maps;
+
+	key = arbel_key_to_hw_index(fmr->ibmr.lkey);
+	key += dev->limits.num_mpts;
+	fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
+
+	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
+
+	wmb();
+
+	for (i = 0; i < list_len; ++i)
+		fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] |
+						     MTHCA_MTT_FLAG_PRESENT);
+
+	fmr->mem.arbel.mpt->key    = cpu_to_be32(key);
+	fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);
+	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	fmr->mem.arbel.mpt->start  = cpu_to_be64(iova);
+
+	wmb();
+
+	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW;
+
+	wmb();
+
+	return 0;
+}
+
+void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
+{
+	u32 key;
+
+	if (!fmr->maps)
+		return;
+
+	key = tavor_key_to_hw_index(fmr->ibmr.lkey);
+	key &= dev->limits.num_mpts - 1;
+	fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
+
+	fmr->maps = 0;
+
+	writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
+}
+
+void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
+{
+	u32 key;
+
+	if (!fmr->maps)
+		return;
+
+	key = arbel_key_to_hw_index(fmr->ibmr.lkey);
+	key &= dev->limits.num_mpts - 1;
+	fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
+
+	fmr->maps = 0;
+
+	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
 }
 
 int __devinit mthca_init_mr_table(struct mthca_dev *dev)
 {
-	int err;
-	int i, s;
+	int err, i;
 
 	err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
 			       dev->limits.num_mpts,
@@ -332,53 +765,94 @@ int __devinit mthca_init_mr_table(struct
 	if (err)
 		return err;
 
-	err = -ENOMEM;
+	if (!mthca_is_memfree(dev) &&
+	    (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN))
+		dev->limits.fmr_reserved_mtts = 0;
+	else
+		dev->mthca_flags |= MTHCA_FLAG_FMR;
 
-	for (i = 1, dev->mr_table.max_mtt_order = 0;
-	     i < dev->limits.num_mtt_segs;
-	     i <<= 1, ++dev->mr_table.max_mtt_order)
-		; /* nothing */
+	err = mthca_buddy_init(&dev->mr_table.mtt_buddy,
+			       fls(dev->limits.num_mtt_segs - 1));
 
-	dev->mr_table.mtt_buddy = kmalloc((dev->mr_table.max_mtt_order + 1) *
-					  sizeof (long *),
-					  GFP_KERNEL);
-	if (!dev->mr_table.mtt_buddy)
-		goto err_out;
+	if (err)
+		goto err_mtt_buddy;
 
-	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
-		dev->mr_table.mtt_buddy[i] = NULL;
+	dev->mr_table.tavor_fmr.mpt_base = NULL;
+	dev->mr_table.tavor_fmr.mtt_base = NULL;
 
-	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) {
-		s = BITS_TO_LONGS(1 << (dev->mr_table.max_mtt_order - i));
-		dev->mr_table.mtt_buddy[i] = kmalloc(s * sizeof (long),
-						     GFP_KERNEL);
-		if (!dev->mr_table.mtt_buddy[i])
-			goto err_out_free;
-		bitmap_zero(dev->mr_table.mtt_buddy[i],
-			    1 << (dev->mr_table.max_mtt_order - i));
-	}
+	if (dev->limits.fmr_reserved_mtts) {
+		i = fls(dev->limits.fmr_reserved_mtts - 1);
 
-	set_bit(0, dev->mr_table.mtt_buddy[dev->mr_table.max_mtt_order]);
+		if (i >= 31) {
+			mthca_warn(dev, "Unable to reserve 2^31 FMR MTTs.\n");
+			err = -EINVAL;
+			goto err_fmr_mpt;
+		}
 
-	for (i = 0; i < dev->mr_table.max_mtt_order; ++i)
-		if (1 << i >= dev->limits.reserved_mtts)
-			break;
+		dev->mr_table.tavor_fmr.mpt_base =
+		       	ioremap(dev->mr_table.mpt_base,
+				(1 << i) * sizeof (struct mthca_mpt_entry));
+
+		if (!dev->mr_table.tavor_fmr.mpt_base) {
+			mthca_warn(dev, "MPT ioremap for FMR failed.\n");
+			err = -ENOMEM;
+			goto err_fmr_mpt;
+		}
 
-	if (i == dev->mr_table.max_mtt_order) {
-		mthca_err(dev, "MTT table of order %d is "
-			  "too small.\n", i);
-		goto err_out_free;
-	}
+		dev->mr_table.tavor_fmr.mtt_base =
+			ioremap(dev->mr_table.mtt_base,
+				(1 << i) * MTHCA_MTT_SEG_SIZE);
+		if (!dev->mr_table.tavor_fmr.mtt_base) {
+			mthca_warn(dev, "MTT ioremap for FMR failed.\n");
+			err = -ENOMEM;
+			goto err_fmr_mtt;
+		}
 
-	(void) mthca_alloc_mtt(dev, i);
+		err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, i);
+		if (err)
+			goto err_fmr_mtt_buddy;
+
+		/* Prevent regular MRs from using FMR keys */
+		err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, i);
+		if (err)
+			goto err_reserve_fmr;
+
+		dev->mr_table.fmr_mtt_buddy =
+		       	&dev->mr_table.tavor_fmr.mtt_buddy;
+	} else
+		dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
+
+	/* FMR table is always the first, take reserved MTTs out of there */
+	if (dev->limits.reserved_mtts) {
+		i = fls(dev->limits.reserved_mtts - 1);
+
+		if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
+			mthca_warn(dev, "MTT table of order %d is too small.\n",
+				  dev->mr_table.fmr_mtt_buddy->max_order);
+			err = -ENOMEM;
+			goto err_reserve_mtts;
+		}
+	}
 
 	return 0;
 
- err_out_free:
-	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
-		kfree(dev->mr_table.mtt_buddy[i]);
+err_reserve_mtts:
+err_reserve_fmr:
+	if (dev->limits.fmr_reserved_mtts)
+		mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);
+
+err_fmr_mtt_buddy:
+	if (dev->mr_table.tavor_fmr.mtt_base)
+		iounmap(dev->mr_table.tavor_fmr.mtt_base);
+
+err_fmr_mtt:
+	if (dev->mr_table.tavor_fmr.mpt_base)
+		iounmap(dev->mr_table.tavor_fmr.mpt_base);
+
+err_fmr_mpt:
+	mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);
 
- err_out:
+err_mtt_buddy:
 	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
 
 	return err;
@@ -386,11 +860,16 @@ int __devinit mthca_init_mr_table(struct
 
 void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev)
 {
-	int i;
-
 	/* XXX check if any MRs are still allocated? */
-	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
-		kfree(dev->mr_table.mtt_buddy[i]);
-	kfree(dev->mr_table.mtt_buddy);
+	if (dev->limits.fmr_reserved_mtts)
+		mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);
+
+	mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);
+
+	if (dev->mr_table.tavor_fmr.mtt_base)
+		iounmap(dev->mr_table.tavor_fmr.mtt_base);
+	if (dev->mr_table.tavor_fmr.mpt_base)
+		iounmap(dev->mr_table.tavor_fmr.mpt_base);
+
 	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c
--- a/drivers/infiniband/hw/mthca/mthca_profile.c
+++ b/drivers/infiniband/hw/mthca/mthca_profile.c
@@ -95,7 +95,7 @@ u64 mthca_make_profile(struct mthca_dev 
 	profile[MTHCA_RES_RDB].size  = MTHCA_RDB_ENTRY_SIZE;
 	profile[MTHCA_RES_MCG].size  = MTHCA_MGM_ENTRY_SIZE;
 	profile[MTHCA_RES_MPT].size  = dev_lim->mpt_entry_sz;
-	profile[MTHCA_RES_MTT].size  = dev_lim->mtt_seg_sz;
+	profile[MTHCA_RES_MTT].size  = MTHCA_MTT_SEG_SIZE;
 	profile[MTHCA_RES_UAR].size  = dev_lim->uar_scratch_entry_sz;
 	profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE;
 	profile[MTHCA_RES_UARC].size = request->uarc_size;
@@ -116,11 +116,11 @@ u64 mthca_make_profile(struct mthca_dev 
 		profile[i].type     = i;
 		profile[i].log_num  = max(ffs(profile[i].num) - 1, 0);
 		profile[i].size    *= profile[i].num;
-		if (dev->hca_type == ARBEL_NATIVE)
+		if (mthca_is_memfree(dev))
 			profile[i].size = max(profile[i].size, (u64) PAGE_SIZE);
 	}
 
-	if (dev->hca_type == ARBEL_NATIVE) {
+	if (mthca_is_memfree(dev)) {
 		mem_base  = 0;
 		mem_avail = dev_lim->hca.arbel.max_icm_sz;
 	} else {
@@ -165,7 +165,7 @@ u64 mthca_make_profile(struct mthca_dev 
 				  (unsigned long long) profile[i].size);
 	}
 
-	if (dev->hca_type == ARBEL_NATIVE)
+	if (mthca_is_memfree(dev))
 		mthca_dbg(dev, "HCA context memory: reserving %d KB\n",
 			  (int) (total_size >> 10));
 	else
@@ -208,8 +208,7 @@ u64 mthca_make_profile(struct mthca_dev 
 			break;
 		case MTHCA_RES_RDB:
 			for (dev->qp_table.rdb_shift = 0;
-			     profile[MTHCA_RES_QP].num << dev->qp_table.rdb_shift <
-				     profile[i].num;
+			     request->num_qp << dev->qp_table.rdb_shift < profile[i].num;
 			     ++dev->qp_table.rdb_shift)
 				; /* nothing */
 			dev->qp_table.rdb_base    = (u32) profile[i].start;
@@ -224,27 +223,32 @@ u64 mthca_make_profile(struct mthca_dev 
 			init_hca->mc_hash_sz      = 1 << (profile[i].log_num - 1);
 			break;
 		case MTHCA_RES_MPT:
-			dev->limits.num_mpts = profile[i].num;
-			init_hca->mpt_base   = profile[i].start;
-			init_hca->log_mpt_sz = profile[i].log_num;
+			dev->limits.num_mpts   = profile[i].num;
+			dev->mr_table.mpt_base = profile[i].start;
+			init_hca->mpt_base     = profile[i].start;
+			init_hca->log_mpt_sz   = profile[i].log_num;
 			break;
 		case MTHCA_RES_MTT:
 			dev->limits.num_mtt_segs = profile[i].num;
-			dev->limits.mtt_seg_size = dev_lim->mtt_seg_sz;
 			dev->mr_table.mtt_base   = profile[i].start;
 			init_hca->mtt_base       = profile[i].start;
-			init_hca->mtt_seg_sz     = ffs(dev_lim->mtt_seg_sz) - 7;
+			init_hca->mtt_seg_sz     = ffs(MTHCA_MTT_SEG_SIZE) - 7;
 			break;
 		case MTHCA_RES_UAR:
+			dev->limits.num_uars       = profile[i].num;
 			init_hca->uar_scratch_base = profile[i].start;
 			break;
 		case MTHCA_RES_UDAV:
 			dev->av_table.ddr_av_base = profile[i].start;
 			dev->av_table.num_ddr_avs = profile[i].num;
+			break;
 		case MTHCA_RES_UARC:
-			init_hca->uarc_base   = profile[i].start;
-			init_hca->log_uarc_sz = ffs(request->uarc_size) - 13;
-			init_hca->log_uar_sz  = ffs(request->num_uar) - 1;
+			dev->uar_table.uarc_size = request->uarc_size;
+			dev->uar_table.uarc_base = profile[i].start;
+			init_hca->uarc_base   	 = profile[i].start;
+			init_hca->log_uarc_sz 	 = ffs(request->uarc_size) - 13;
+			init_hca->log_uar_sz  	 = ffs(request->num_uar) - 1;
+			break;
 		default:
 			break;
 		}
@@ -256,6 +260,18 @@ u64 mthca_make_profile(struct mthca_dev 
 	 */
 	dev->limits.num_pds = MTHCA_NUM_PDS;
 
+	/*
+	 * For Tavor, FMRs use ioremapped PCI memory. For 32 bit
+	 * systems it may use too much vmalloc space to map all MTT
+	 * memory, so we reserve some MTTs for FMR access, taking them
+	 * out of the MR pool. They don't use additional memory, but
+	 * we assign them as part of the HCA profile anyway.
+	 */
+	if (mthca_is_memfree(dev))
+		dev->limits.fmr_reserved_mtts = 0;
+	else
+		dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts;
+
 	kfree(profile);
 	return total_size;
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_profile.h b/drivers/infiniband/hw/mthca/mthca_profile.h
--- a/drivers/infiniband/hw/mthca/mthca_profile.h
+++ b/drivers/infiniband/hw/mthca/mthca_profile.h
@@ -48,6 +48,7 @@ struct mthca_profile {
 	int num_udav;
 	int num_uar;
 	int uarc_size;
+	int fmr_reserved_mtts;
 };
 
 u64 mthca_make_profile(struct mthca_dev *mdev,
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -43,6 +43,8 @@ static int mthca_query_device(struct ib_
 	struct ib_smp *in_mad  = NULL;
 	struct ib_smp *out_mad = NULL;
 	int err = -ENOMEM;
+	struct mthca_dev* mdev = to_mdev(ibdev);
+
 	u8 status;
 
 	in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
@@ -50,7 +52,9 @@ static int mthca_query_device(struct ib_
 	if (!in_mad || !out_mad)
 		goto out;
 
-	props->fw_ver        = to_mdev(ibdev)->fw_ver;
+	memset(props, 0, sizeof props);
+
+	props->fw_ver              = mdev->fw_ver;
 
 	memset(in_mad, 0, sizeof *in_mad);
 	in_mad->base_version       = 1;
@@ -59,7 +63,7 @@ static int mthca_query_device(struct ib_
 	in_mad->method         	   = IB_MGMT_METHOD_GET;
 	in_mad->attr_id   	   = IB_SMP_ATTR_NODE_INFO;
 
-	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
+	err = mthca_MAD_IFC(mdev, 1, 1,
 			    1, NULL, NULL, in_mad, out_mad,
 			    &status);
 	if (err)
@@ -69,13 +73,26 @@ static int mthca_query_device(struct ib_
 		goto out;
 	}
 
-	props->vendor_id      = be32_to_cpup((u32 *) (out_mad->data + 36)) &
+	props->device_cap_flags    = mdev->device_cap_flags;
+	props->vendor_id           = be32_to_cpup((u32 *) (out_mad->data + 36)) &
 		0xffffff;
-	props->vendor_part_id = be16_to_cpup((u16 *) (out_mad->data + 30));
-	props->hw_ver         = be16_to_cpup((u16 *) (out_mad->data + 32));
+	props->vendor_part_id      = be16_to_cpup((u16 *) (out_mad->data + 30));
+	props->hw_ver              = be16_to_cpup((u16 *) (out_mad->data + 32));
 	memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
 	memcpy(&props->node_guid,      out_mad->data + 12, 8);
 
+	props->max_mr_size         = ~0ull;
+	props->max_qp              = mdev->limits.num_qps - mdev->limits.reserved_qps;
+	props->max_qp_wr           = 0xffff;
+	props->max_sge             = mdev->limits.max_sg;
+	props->max_cq              = mdev->limits.num_cqs - mdev->limits.reserved_cqs;
+	props->max_cqe             = 0xffff;
+	props->max_mr              = mdev->limits.num_mpts - mdev->limits.reserved_mrws;
+	props->max_pd              = mdev->limits.num_pds - mdev->limits.reserved_pds;
+	props->max_qp_rd_atom      = 1 << mdev->qp_table.rdb_shift;
+	props->max_qp_init_rd_atom = 1 << mdev->qp_table.rdb_shift;
+	props->local_ca_ack_delay  = mdev->limits.local_ca_ack_delay;
+
 	err = 0;
  out:
 	kfree(in_mad);
@@ -298,7 +315,7 @@ static struct ib_ah *mthca_ah_create(str
 	int err;
 	struct mthca_ah *ah;
 
-	ah = kmalloc(sizeof *ah, GFP_KERNEL);
+	ah = kmalloc(sizeof *ah, GFP_ATOMIC);
 	if (!ah)
 		return ERR_PTR(-ENOMEM);
 
@@ -343,7 +360,7 @@ static struct ib_qp *mthca_create_qp(str
 				     to_mcq(init_attr->send_cq),
 				     to_mcq(init_attr->recv_cq),
 				     init_attr->qp_type, init_attr->sq_sig_type,
-				     init_attr->rq_sig_type, qp);
+				     qp);
 		qp->ibqp.qp_num = qp->qpn;
 		break;
 	}
@@ -364,7 +381,7 @@ static struct ib_qp *mthca_create_qp(str
 		err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),
 				      to_mcq(init_attr->send_cq),
 				      to_mcq(init_attr->recv_cq),
-				      init_attr->sq_sig_type, init_attr->rq_sig_type,
+				      init_attr->sq_sig_type,
 				      qp->ibqp.qp_num, init_attr->port_num,
 				      to_msqp(qp));
 		break;
@@ -408,8 +425,7 @@ static struct ib_cq *mthca_create_cq(str
 	if (err) {
 		kfree(cq);
 		cq = ERR_PTR(err);
-	} else
-		cq->ibcq.cqe = nent - 1;
+	}
 
 	return &cq->ibcq;
 }
@@ -422,13 +438,6 @@ static int mthca_destroy_cq(struct ib_cq
 	return 0;
 }
 
-static int mthca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify notify)
-{
-	mthca_arm_cq(to_mdev(cq->device), to_mcq(cq),
-		     notify == IB_CQ_SOLICITED);
-	return 0;
-}
-
 static inline u32 convert_access(int acc)
 {
 	return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC       : 0) |
@@ -485,7 +494,7 @@ static struct ib_mr *mthca_reg_phys_mr(s
 	mask = 0;
 	total_size = 0;
 	for (i = 0; i < num_phys_buf; ++i) {
-		if (buffer_list[i].addr & ~PAGE_MASK)
+		if (i != 0 && buffer_list[i].addr & ~PAGE_MASK)
 			return ERR_PTR(-EINVAL);
 		if (i != 0 && i != num_phys_buf - 1 &&
 		    (buffer_list[i].size & ~PAGE_MASK))
@@ -559,8 +568,77 @@ static struct ib_mr *mthca_reg_phys_mr(s
 
 static int mthca_dereg_mr(struct ib_mr *mr)
 {
-	mthca_free_mr(to_mdev(mr->device), to_mmr(mr));
-	kfree(mr);
+	struct mthca_mr *mmr = to_mmr(mr);
+	mthca_free_mr(to_mdev(mr->device), mmr);
+	kfree(mmr);
+	return 0;
+}
+
+static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
+				      struct ib_fmr_attr *fmr_attr)
+{
+	struct mthca_fmr *fmr;
+	int err;
+
+	fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
+	if (!fmr)
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr);
+	err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num,
+			     convert_access(mr_access_flags), fmr);
+
+	if (err) {
+		kfree(fmr);
+		return ERR_PTR(err);
+	}
+
+	return &fmr->ibmr;
+}
+
+static int mthca_dealloc_fmr(struct ib_fmr *fmr)
+{
+	struct mthca_fmr *mfmr = to_mfmr(fmr);
+	int err;
+
+	err = mthca_free_fmr(to_mdev(fmr->device), mfmr);
+	if (err)
+		return err;
+
+	kfree(mfmr);
+	return 0;
+}
+
+static int mthca_unmap_fmr(struct list_head *fmr_list)
+{
+	struct ib_fmr *fmr;
+	int err;
+	u8 status;
+	struct mthca_dev *mdev = NULL;
+
+	list_for_each_entry(fmr, fmr_list, list) {
+		if (mdev && to_mdev(fmr->device) != mdev)
+			return -EINVAL;
+		mdev = to_mdev(fmr->device);
+	}
+
+	if (!mdev)
+		return 0;
+
+	if (mthca_is_memfree(mdev)) {
+		list_for_each_entry(fmr, fmr_list, list)
+			mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr));
+
+		wmb();
+	} else
+		list_for_each_entry(fmr, fmr_list, list)
+			mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr));
+
+	err = mthca_SYNC_TPT(mdev, &status);
+	if (err)
+		return err;
+	if (status)
+		return -EINVAL;
 	return 0;
 }
 
@@ -581,11 +659,18 @@ static ssize_t show_fw_ver(struct class_
 static ssize_t show_hca(struct class_device *cdev, char *buf)
 {
 	struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev);
-	switch (dev->hca_type) {
-	case TAVOR:        return sprintf(buf, "MT23108\n");
-	case ARBEL_COMPAT: return sprintf(buf, "MT25208 (MT23108 compat mode)\n");
-	case ARBEL_NATIVE: return sprintf(buf, "MT25208\n");
-	default:           return sprintf(buf, "unknown\n");
+	switch (dev->pdev->device) {
+	case PCI_DEVICE_ID_MELLANOX_TAVOR:
+		return sprintf(buf, "MT23108\n");
+	case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT:
+		return sprintf(buf, "MT25208 (MT23108 compat mode)\n");
+	case PCI_DEVICE_ID_MELLANOX_ARBEL:
+		return sprintf(buf, "MT25208\n");
+	case PCI_DEVICE_ID_MELLANOX_SINAI:
+	case PCI_DEVICE_ID_MELLANOX_SINAI_OLD:
+		return sprintf(buf, "MT25204\n");
+	default:
+		return sprintf(buf, "unknown\n");
 	}
 }
 
@@ -621,19 +706,37 @@ int mthca_register_device(struct mthca_d
 	dev->ib_dev.create_qp            = mthca_create_qp;
 	dev->ib_dev.modify_qp            = mthca_modify_qp;
 	dev->ib_dev.destroy_qp           = mthca_destroy_qp;
-	dev->ib_dev.post_send            = mthca_post_send;
-	dev->ib_dev.post_recv            = mthca_post_receive;
 	dev->ib_dev.create_cq            = mthca_create_cq;
 	dev->ib_dev.destroy_cq           = mthca_destroy_cq;
 	dev->ib_dev.poll_cq              = mthca_poll_cq;
-	dev->ib_dev.req_notify_cq        = mthca_req_notify_cq;
 	dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;
 	dev->ib_dev.reg_phys_mr          = mthca_reg_phys_mr;
 	dev->ib_dev.dereg_mr             = mthca_dereg_mr;
+
+	if (dev->mthca_flags & MTHCA_FLAG_FMR) {
+		dev->ib_dev.alloc_fmr            = mthca_alloc_fmr;
+		dev->ib_dev.unmap_fmr            = mthca_unmap_fmr;
+		dev->ib_dev.dealloc_fmr          = mthca_dealloc_fmr;
+		if (mthca_is_memfree(dev))
+			dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr;
+		else
+			dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr;
+	}
+
 	dev->ib_dev.attach_mcast         = mthca_multicast_attach;
 	dev->ib_dev.detach_mcast         = mthca_multicast_detach;
 	dev->ib_dev.process_mad          = mthca_process_mad;
 
+	if (mthca_is_memfree(dev)) {
+		dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq;
+		dev->ib_dev.post_send     = mthca_arbel_post_send;
+		dev->ib_dev.post_recv     = mthca_arbel_post_receive;
+	} else {
+		dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq;
+		dev->ib_dev.post_send     = mthca_tavor_post_send;
+		dev->ib_dev.post_recv     = mthca_tavor_post_receive;
+	}
+
 	init_MUTEX(&dev->cap_mask_mutex);
 
 	ret = ib_register_device(&dev->ib_dev);
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -49,12 +49,35 @@ struct mthca_buf_list {
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+struct mthca_uar {
+	unsigned long pfn;
+	int           index;
+};
+
 struct mthca_mr {
 	struct ib_mr ibmr;
 	int order;
 	u32 first_seg;
 };
 
+struct mthca_fmr {
+	struct ib_fmr ibmr;
+	struct ib_fmr_attr attr;
+	int order;
+	u32 first_seg;
+	int maps;
+	union {
+		struct {
+			struct mthca_mpt_entry __iomem *mpt;
+			u64 __iomem *mtts;
+		} tavor;
+		struct {
+			struct mthca_mpt_entry *mpt;
+			__be64 *mtts;
+		} arbel;
+	} mem;
+};
+
 struct mthca_pd {
 	struct ib_pd    ibpd;
 	u32             pd_num;
@@ -65,7 +88,7 @@ struct mthca_pd {
 struct mthca_eq {
 	struct mthca_dev      *dev;
 	int                    eqn;
-	u32                    ecr_mask;
+	u32                    eqn_mask;
 	u32                    cons_index;
 	u16                    msi_x_vector;
 	u16                    msi_x_entry;
@@ -77,12 +100,18 @@ struct mthca_eq {
 
 struct mthca_av;
 
+enum mthca_ah_type {
+	MTHCA_AH_ON_HCA,
+	MTHCA_AH_PCI_POOL,
+	MTHCA_AH_KMALLOC
+};
+
 struct mthca_ah {
-	struct ib_ah     ibah;
-	int              on_hca;
-	u32              key;
-	struct mthca_av *av;
-	dma_addr_t       avdma;
+	struct ib_ah       ibah;
+	enum mthca_ah_type type;
+	u32                key;
+	struct mthca_av   *av;
+	dma_addr_t         avdma;
 };
 
 /*
@@ -136,8 +165,16 @@ struct mthca_cq {
 	spinlock_t             lock;
 	atomic_t               refcount;
 	int                    cqn;
-	int                    cons_index;
+	u32                    cons_index;
 	int                    is_direct;
+
+	/* Next fields are Arbel only */
+	int                    set_ci_db_index;
+	u32                   *set_ci_db;
+	int                    arm_db_index;
+	u32                   *arm_db;
+	int                    arm_sn;
+
 	union {
 		struct mthca_buf_list direct;
 		struct mthca_buf_list *page_list;
@@ -147,19 +184,22 @@ struct mthca_cq {
 };
 
 struct mthca_wq {
-	int   max;
-	int   cur;
-	int   next;
-	int   last_comp;
-	void *last;
-	int   max_gs;
-	int   wqe_shift;
-	enum ib_sig_type policy;
+	spinlock_t lock;
+	int        max;
+	unsigned   next_ind;
+	unsigned   last_comp;
+	unsigned   head;
+	unsigned   tail;
+	void      *last;
+	int        max_gs;
+	int        wqe_shift;
+
+	int        db_index;	/* Arbel only */
+	u32       *db;
 };
 
 struct mthca_qp {
 	struct ib_qp           ibqp;
-	spinlock_t             lock;
 	atomic_t               refcount;
 	u32                    qpn;
 	int                    is_direct;
@@ -172,6 +212,7 @@ struct mthca_qp {
 
 	struct mthca_wq        rq;
 	struct mthca_wq        sq;
+	enum ib_sig_type       sq_policy;
 	int                    send_wqe_offset;
 
 	u64                   *wrid;
@@ -195,6 +236,11 @@ struct mthca_sqp {
 	dma_addr_t      header_dma;
 };
 
+static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr)
+{
+	return container_of(ibmr, struct mthca_fmr, ibmr);
+}
+
 static inline struct mthca_mr *to_mmr(struct ib_mr *ibmr)
 {
 	return container_of(ibmr, struct mthca_mr, ibmr);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -40,6 +40,7 @@
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
+#include "mthca_memfree.h"
 
 enum {
 	MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE,
@@ -105,8 +106,11 @@ struct mthca_qp_path {
 
 struct mthca_qp_context {
 	u32 flags;
-	u32 sched_queue;
-	u32 mtu_msgmax;
+	u32 tavor_sched_queue;	/* Reserved on Arbel */
+	u8  mtu_msgmax;
+	u8  rq_size_stride;	/* Reserved on Tavor */
+	u8  sq_size_stride;	/* Reserved on Tavor */
+	u8  rlkey_arbel_sched_queue;	/* Reserved on Tavor */
 	u32 usr_page;
 	u32 local_qpn;
 	u32 remote_qpn;
@@ -121,18 +125,22 @@ struct mthca_qp_context {
 	u32 reserved2;
 	u32 next_send_psn;
 	u32 cqn_snd;
-	u32 next_snd_wqe[2];
+	u32 snd_wqe_base_l;	/* Next send WQE on Tavor */
+	u32 snd_db_index;	/* (debugging only entries) */
 	u32 last_acked_psn;
 	u32 ssn;
 	u32 params2;
 	u32 rnr_nextrecvpsn;
 	u32 ra_buff_indx;
 	u32 cqn_rcv;
-	u32 next_rcv_wqe[2];
+	u32 rcv_wqe_base_l;	/* Next recv WQE on Tavor */
+	u32 rcv_db_index;	/* (debugging only entries) */
 	u32 qkey;
 	u32 srqn;
 	u32 rmsn;
-	u32 reserved3[19];
+	u16 rq_wqe_counter;	/* reserved on Tavor */
+	u16 sq_wqe_counter;	/* reserved on Tavor */
+	u32 reserved3[18];
 } __attribute__((packed));
 
 struct mthca_qp_param {
@@ -163,19 +171,6 @@ enum {
 };
 
 enum {
-	MTHCA_OPCODE_NOP            = 0x00,
-	MTHCA_OPCODE_RDMA_WRITE     = 0x08,
-	MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09,
-	MTHCA_OPCODE_SEND           = 0x0a,
-	MTHCA_OPCODE_SEND_IMM       = 0x0b,
-	MTHCA_OPCODE_RDMA_READ      = 0x10,
-	MTHCA_OPCODE_ATOMIC_CS      = 0x11,
-	MTHCA_OPCODE_ATOMIC_FA      = 0x12,
-	MTHCA_OPCODE_BIND_MW        = 0x18,
-	MTHCA_OPCODE_INVALID        = 0xff
-};
-
-enum {
 	MTHCA_NEXT_DBD       = 1 << 7,
 	MTHCA_NEXT_FENCE     = 1 << 6,
 	MTHCA_NEXT_CQ_UPDATE = 1 << 3,
@@ -186,6 +181,10 @@ enum {
 	MTHCA_MLX_SLR        = 1 << 16
 };
 
+enum {
+	MTHCA_INVAL_LKEY = 0x100
+};
+
 struct mthca_next_seg {
 	u32 nda_op;		/* [31:6] next WQE [4:0] next opcode */
 	u32 ee_nds;		/* [31:8] next EE  [7] DBD [6] F [5:0] next WQE size */
@@ -193,7 +192,7 @@ struct mthca_next_seg {
 	u32 imm;		/* immediate data */
 };
 
-struct mthca_ud_seg {
+struct mthca_tavor_ud_seg {
 	u32 reserved1;
 	u32 lkey;
 	u64 av_addr;
@@ -203,6 +202,13 @@ struct mthca_ud_seg {
 	u32 reserved3[2];
 };
 
+struct mthca_arbel_ud_seg {
+	u32 av[8];
+	u32 dqpn;
+	u32 qkey;
+	u32 reserved[2];
+};
+
 struct mthca_bind_seg {
 	u32 flags;		/* [31] Atomic [30] rem write [29] rem read */
 	u32 reserved;
@@ -238,6 +244,16 @@ struct mthca_mlx_seg {
 	u16 vcrc;
 };
 
+static const u8 mthca_opcode[] = {
+	[IB_WR_SEND]                 = MTHCA_OPCODE_SEND,
+	[IB_WR_SEND_WITH_IMM]        = MTHCA_OPCODE_SEND_IMM,
+	[IB_WR_RDMA_WRITE]           = MTHCA_OPCODE_RDMA_WRITE,
+	[IB_WR_RDMA_WRITE_WITH_IMM]  = MTHCA_OPCODE_RDMA_WRITE_IMM,
+	[IB_WR_RDMA_READ]            = MTHCA_OPCODE_RDMA_READ,
+	[IB_WR_ATOMIC_CMP_AND_SWP]   = MTHCA_OPCODE_ATOMIC_CS,
+	[IB_WR_ATOMIC_FETCH_AND_ADD] = MTHCA_OPCODE_ATOMIC_FA,
+};
+
 static int is_sqp(struct mthca_dev *dev, struct mthca_qp *qp)
 {
 	return qp->qpn >= dev->qp_table.sqp_start &&
@@ -552,9 +568,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 		else
 			cur_state = attr->cur_qp_state;
 	} else {
-		spin_lock_irq(&qp->lock);
+		spin_lock_irq(&qp->sq.lock);
+		spin_lock(&qp->rq.lock);
 		cur_state = qp->state;
-		spin_unlock_irq(&qp->lock);
+		spin_unlock(&qp->rq.lock);
+		spin_unlock_irq(&qp->sq.lock);
 	}
 
 	if (attr_mask & IB_QP_STATE) {
@@ -617,15 +635,24 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 			break;
 		}
 	}
-	/* leave sched_queue as 0 */
+
+	/* leave tavor_sched_queue as 0 */
+
 	if (qp->transport == MLX || qp->transport == UD)
-		qp_context->mtu_msgmax = cpu_to_be32((IB_MTU_2048 << 29) |
-						     (11 << 24));
-	else if (attr_mask & IB_QP_PATH_MTU) {
-		qp_context->mtu_msgmax = cpu_to_be32((attr->path_mtu << 29) |
-						     (31 << 24));
+		qp_context->mtu_msgmax = (IB_MTU_2048 << 5) | 11;
+	else if (attr_mask & IB_QP_PATH_MTU)
+		qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31;
+
+	if (mthca_is_memfree(dev)) {
+		qp_context->rq_size_stride =
+			((ffs(qp->rq.max) - 1) << 3) | (qp->rq.wqe_shift - 4);
+		qp_context->sq_size_stride =
+			((ffs(qp->sq.max) - 1) << 3) | (qp->sq.wqe_shift - 4);
 	}
-	qp_context->usr_page   = cpu_to_be32(MTHCA_KAR_PAGE);
+
+	/* leave arbel_sched_queue as 0 */
+
+	qp_context->usr_page   = cpu_to_be32(dev->driver_uar.index);
 	qp_context->local_qpn  = cpu_to_be32(qp->qpn);
 	if (attr_mask & IB_QP_DEST_QPN) {
 		qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
@@ -690,7 +717,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 					     MTHCA_QP_BIT_SRE           |
 					     MTHCA_QP_BIT_SWE           |
 					     MTHCA_QP_BIT_SAE);
-	if (qp->sq.policy == IB_SIGNAL_ALL_WR)
+	if (qp->sq_policy == IB_SIGNAL_ALL_WR)
 		qp_context->params1 |= cpu_to_be32(MTHCA_QP_BIT_SSC);
 	if (attr_mask & IB_QP_RETRY_CNT) {
 		qp_context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
@@ -708,6 +735,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 		qp_context->next_send_psn = cpu_to_be32(attr->sq_psn);
 	qp_context->cqn_snd = cpu_to_be32(to_mcq(ibqp->send_cq)->cqn);
 
+	if (mthca_is_memfree(dev)) {
+		qp_context->snd_wqe_base_l = cpu_to_be32(qp->send_wqe_offset);
+		qp_context->snd_db_index   = cpu_to_be32(qp->sq.db_index);
+	}
+
 	if (attr_mask & IB_QP_ACCESS_FLAGS) {
 		/*
 		 * Only enable RDMA/atomics if we have responder
@@ -778,8 +810,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 		qp->resp_depth = attr->max_rd_atomic;
 	}
 
-	if (qp->rq.policy == IB_SIGNAL_ALL_WR)
-		qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
+	qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
+
 	if (attr_mask & IB_QP_MIN_RNR_TIMER) {
 		qp_context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_TIMEOUT);
@@ -787,12 +819,16 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 	if (attr_mask & IB_QP_RQ_PSN)
 		qp_context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
 
-	qp_context->ra_buff_indx = dev->qp_table.rdb_base +
-		((qp->qpn & (dev->limits.num_qps - 1)) * MTHCA_RDB_ENTRY_SIZE <<
-		 dev->qp_table.rdb_shift);
+	qp_context->ra_buff_indx =
+		cpu_to_be32(dev->qp_table.rdb_base +
+			    ((qp->qpn & (dev->limits.num_qps - 1)) * MTHCA_RDB_ENTRY_SIZE <<
+			     dev->qp_table.rdb_shift));
 
 	qp_context->cqn_rcv = cpu_to_be32(to_mcq(ibqp->recv_cq)->cqn);
 
+	if (mthca_is_memfree(dev))
+		qp_context->rcv_db_index   = cpu_to_be32(qp->rq.db_index);
+
 	if (attr_mask & IB_QP_QKEY) {
 		qp_context->qkey = cpu_to_be32(attr->qkey);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_Q_KEY);
@@ -860,12 +896,20 @@ static int mthca_alloc_wqe_buf(struct mt
 
 	size = sizeof (struct mthca_next_seg) +
 		qp->sq.max_gs * sizeof (struct mthca_data_seg);
-	if (qp->transport == MLX)
+	switch (qp->transport) {
+	case MLX:
 		size += 2 * sizeof (struct mthca_data_seg);
-	else if (qp->transport == UD)
-		size += sizeof (struct mthca_ud_seg);
-	else /* bind seg is as big as atomic + raddr segs */
+		break;
+	case UD:
+		if (mthca_is_memfree(dev))
+			size += sizeof (struct mthca_arbel_ud_seg);
+		else
+			size += sizeof (struct mthca_tavor_ud_seg);
+		break;
+	default:
+		/* bind seg is as big as atomic + raddr segs */
 		size += sizeof (struct mthca_bind_seg);
+	}
 
 	for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size;
 	     qp->sq.wqe_shift++)
@@ -942,7 +986,6 @@ static int mthca_alloc_wqe_buf(struct mt
 
 	err = mthca_mr_alloc_phys(dev, pd->pd_num, dma_list, shift,
 				  npages, 0, size,
-				  MTHCA_MPT_FLAG_LOCAL_WRITE |
 				  MTHCA_MPT_FLAG_LOCAL_READ,
 				  &qp->mr);
 	if (err)
@@ -972,34 +1015,154 @@ static int mthca_alloc_wqe_buf(struct mt
 	return err;
 }
 
+static int mthca_alloc_memfree(struct mthca_dev *dev,
+			       struct mthca_qp *qp)
+{
+	int ret = 0;
+
+	if (mthca_is_memfree(dev)) {
+		ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn);
+		if (ret)
+			return ret;
+
+		ret = mthca_table_get(dev, dev->qp_table.eqp_table, qp->qpn);
+		if (ret)
+			goto err_qpc;
+
+		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+				      qp->qpn << dev->qp_table.rdb_shift);
+		if (ret)
+			goto err_eqpc;
+
+		qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
+						 qp->qpn, &qp->rq.db);
+		if (qp->rq.db_index < 0) {
+			ret = -ENOMEM;
+			goto err_rdb;
+		}
+
+		qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
+						 qp->qpn, &qp->sq.db);
+		if (qp->sq.db_index < 0) {
+			ret = -ENOMEM;
+			goto err_rq_db;
+		}
+	}
+
+	return 0;
+
+err_rq_db:
+	mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+
+err_rdb:
+	mthca_table_put(dev, dev->qp_table.rdb_table,
+			qp->qpn << dev->qp_table.rdb_shift);
+
+err_eqpc:
+	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+
+err_qpc:
+	mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
+
+	return ret;
+}
+
+static void mthca_free_memfree(struct mthca_dev *dev,
+			       struct mthca_qp *qp)
+{
+	if (mthca_is_memfree(dev)) {
+		mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
+		mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+		mthca_table_put(dev, dev->qp_table.rdb_table,
+				qp->qpn << dev->qp_table.rdb_shift);
+		mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+		mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
+	}
+}
+
+static void mthca_wq_init(struct mthca_wq* wq)
+{
+	spin_lock_init(&wq->lock);
+	wq->next_ind  = 0;
+	wq->last_comp = wq->max - 1;
+	wq->head      = 0;
+	wq->tail      = 0;
+	wq->last      = NULL;
+}
+
 static int mthca_alloc_qp_common(struct mthca_dev *dev,
 				 struct mthca_pd *pd,
 				 struct mthca_cq *send_cq,
 				 struct mthca_cq *recv_cq,
 				 enum ib_sig_type send_policy,
-				 enum ib_sig_type recv_policy,
 				 struct mthca_qp *qp)
 {
-	int err;
+	int ret;
+	int i;
 
-	spin_lock_init(&qp->lock);
 	atomic_set(&qp->refcount, 1);
 	qp->state    	 = IB_QPS_RESET;
 	qp->atomic_rd_en = 0;
 	qp->resp_depth   = 0;
-	qp->sq.policy    = send_policy;
-	qp->rq.policy    = recv_policy;
-	qp->rq.cur       = 0;
-	qp->sq.cur       = 0;
-	qp->rq.next      = 0;
-	qp->sq.next      = 0;
-	qp->rq.last_comp = qp->rq.max - 1;
-	qp->sq.last_comp = qp->sq.max - 1;
-	qp->rq.last      = NULL;
-	qp->sq.last      = NULL;
+	qp->sq_policy    = send_policy;
+	mthca_wq_init(&qp->sq);
+	mthca_wq_init(&qp->rq);
+
+	ret = mthca_alloc_memfree(dev, qp);
+	if (ret)
+		return ret;
+
+	ret = mthca_alloc_wqe_buf(dev, pd, qp);
+	if (ret) {
+		mthca_free_memfree(dev, qp);
+		return ret;
+	}
+
+	if (mthca_is_memfree(dev)) {
+		struct mthca_next_seg *next;
+		struct mthca_data_seg *scatter;
+		int size = (sizeof (struct mthca_next_seg) +
+			    qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16;
+
+		for (i = 0; i < qp->rq.max; ++i) {
+			next = get_recv_wqe(qp, i);
+			next->nda_op = cpu_to_be32(((i + 1) & (qp->rq.max - 1)) <<
+						   qp->rq.wqe_shift);
+			next->ee_nds = cpu_to_be32(size);
+
+			for (scatter = (void *) (next + 1);
+			     (void *) scatter < (void *) next + (1 << qp->rq.wqe_shift);
+			     ++scatter)
+				scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+		}
+
+		for (i = 0; i < qp->sq.max; ++i) {
+			next = get_send_wqe(qp, i);
+			next->nda_op = cpu_to_be32((((i + 1) & (qp->sq.max - 1)) <<
+						    qp->sq.wqe_shift) +
+						   qp->send_wqe_offset);
+		}
+	}
 
-	err = mthca_alloc_wqe_buf(dev, pd, qp);
-	return err;
+	return 0;
+}
+
+static void mthca_align_qp_size(struct mthca_dev *dev, struct mthca_qp *qp)
+{
+	int i;
+
+	if (!mthca_is_memfree(dev))
+		return;
+
+	for (i = 0; 1 << i < qp->rq.max; ++i)
+		; /* nothing */
+
+	qp->rq.max = 1 << i;
+
+	for (i = 0; 1 << i < qp->sq.max; ++i)
+		; /* nothing */
+
+	qp->sq.max = 1 << i;
 }
 
 int mthca_alloc_qp(struct mthca_dev *dev,
@@ -1008,11 +1171,12 @@ int mthca_alloc_qp(struct mthca_dev *dev
 		   struct mthca_cq *recv_cq,
 		   enum ib_qp_type type,
 		   enum ib_sig_type send_policy,
-		   enum ib_sig_type recv_policy,
 		   struct mthca_qp *qp)
 {
 	int err;
 
+	mthca_align_qp_size(dev, qp);
+
 	switch (type) {
 	case IB_QPT_RC: qp->transport = RC; break;
 	case IB_QPT_UC: qp->transport = UC; break;
@@ -1025,7 +1189,7 @@ int mthca_alloc_qp(struct mthca_dev *dev
 		return -ENOMEM;
 
 	err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq,
-				    send_policy, recv_policy, qp);
+				    send_policy, qp);
 	if (err) {
 		mthca_free(&dev->qp_table.alloc, qp->qpn);
 		return err;
@@ -1044,7 +1208,6 @@ int mthca_alloc_sqp(struct mthca_dev *de
 		    struct mthca_cq *send_cq,
 		    struct mthca_cq *recv_cq,
 		    enum ib_sig_type send_policy,
-		    enum ib_sig_type recv_policy,
 		    int qpn,
 		    int port,
 		    struct mthca_sqp *sqp)
@@ -1052,6 +1215,8 @@ int mthca_alloc_sqp(struct mthca_dev *de
 	int err = 0;
 	u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
 
+	mthca_align_qp_size(dev, &sqp->qp);
+
 	sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE;
 	sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size,
 					     &sqp->header_dma, GFP_KERNEL);
@@ -1073,8 +1238,7 @@ int mthca_alloc_sqp(struct mthca_dev *de
 	sqp->qp.transport = MLX;
 
 	err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq,
-				    send_policy, recv_policy,
-				    &sqp->qp);
+				    send_policy, &sqp->qp);
 	if (err)
 		goto err_out_free;
 
@@ -1083,9 +1247,21 @@ int mthca_alloc_sqp(struct mthca_dev *de
 	return 0;
 
  err_out_free:
-	spin_lock_irq(&dev->qp_table.lock);
+	/*
+	 * Lock CQs here, so that CQ polling code can do QP lookup
+	 * without taking a lock.
+	 */
+	spin_lock_irq(&send_cq->lock);
+	if (send_cq != recv_cq)
+		spin_lock(&recv_cq->lock);
+
+	spin_lock(&dev->qp_table.lock);
 	mthca_array_clear(&dev->qp_table.qp, mqpn);
-	spin_unlock_irq(&dev->qp_table.lock);
+	spin_unlock(&dev->qp_table.lock);
+
+	if (send_cq != recv_cq)
+		spin_unlock(&recv_cq->lock);
+	spin_unlock_irq(&send_cq->lock);
 
  err_out:
 	dma_free_coherent(&dev->pdev->dev, sqp->header_buf_size,
@@ -1100,11 +1276,28 @@ void mthca_free_qp(struct mthca_dev *dev
 	u8 status;
 	int size;
 	int i;
+	struct mthca_cq *send_cq;
+	struct mthca_cq *recv_cq;
 
-	spin_lock_irq(&dev->qp_table.lock);
+	send_cq = to_mcq(qp->ibqp.send_cq);
+	recv_cq = to_mcq(qp->ibqp.recv_cq);
+
+	/*
+	 * Lock CQs here, so that CQ polling code can do QP lookup
+	 * without taking a lock.
+	 */
+	spin_lock_irq(&send_cq->lock);
+	if (send_cq != recv_cq)
+		spin_lock(&recv_cq->lock);
+
+	spin_lock(&dev->qp_table.lock);
 	mthca_array_clear(&dev->qp_table.qp,
 			  qp->qpn & (dev->limits.num_qps - 1));
-	spin_unlock_irq(&dev->qp_table.lock);
+	spin_unlock(&dev->qp_table.lock);
+
+	if (send_cq != recv_cq)
+		spin_unlock(&recv_cq->lock);
+	spin_unlock_irq(&send_cq->lock);
 
 	atomic_dec(&qp->refcount);
 	wait_event(qp->wait, !atomic_read(&qp->refcount));
@@ -1136,14 +1329,15 @@ void mthca_free_qp(struct mthca_dev *dev
 
 	kfree(qp->wrid);
 
+	mthca_free_memfree(dev, qp);
+
 	if (is_sqp(dev, qp)) {
 		atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count));
 		dma_free_coherent(&dev->pdev->dev,
 				  to_msqp(qp)->header_buf_size,
 				  to_msqp(qp)->header_buf,
 				  to_msqp(qp)->header_dma);
-	}
-	else
+	} else
 		mthca_free(&dev->qp_table.alloc, qp->qpn);
 }
 
@@ -1216,8 +1410,26 @@ static int build_mlx_header(struct mthca
 	return 0;
 }
 
-int mthca_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
-		    struct ib_send_wr **bad_wr)
+static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq,
+				    struct ib_cq *ib_cq)
+{
+	unsigned cur;
+	struct mthca_cq *cq;
+
+	cur = wq->head - wq->tail;
+	if (likely(cur + nreq < wq->max))
+		return 0;
+
+	cq = to_mcq(ib_cq);
+	spin_lock(&cq->lock);
+	cur = wq->head - wq->tail;
+	spin_unlock(&cq->lock);
+
+	return cur + nreq >= wq->max;
+}
+
+int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+			  struct ib_send_wr **bad_wr)
 {
 	struct mthca_dev *dev = to_mdev(ibqp->device);
 	struct mthca_qp *qp = to_mqp(ibqp);
@@ -1233,26 +1445,18 @@ int mthca_post_send(struct ib_qp *ibqp, 
 	int ind;
 	u8 op0 = 0;
 
-	static const u8 opcode[] = {
-		[IB_WR_SEND]                 = MTHCA_OPCODE_SEND,
-		[IB_WR_SEND_WITH_IMM]        = MTHCA_OPCODE_SEND_IMM,
-		[IB_WR_RDMA_WRITE]           = MTHCA_OPCODE_RDMA_WRITE,
-		[IB_WR_RDMA_WRITE_WITH_IMM]  = MTHCA_OPCODE_RDMA_WRITE_IMM,
-		[IB_WR_RDMA_READ]            = MTHCA_OPCODE_RDMA_READ,
-		[IB_WR_ATOMIC_CMP_AND_SWP]   = MTHCA_OPCODE_ATOMIC_CS,
-		[IB_WR_ATOMIC_FETCH_AND_ADD] = MTHCA_OPCODE_ATOMIC_FA,
-	};
-
-	spin_lock_irqsave(&qp->lock, flags);
+	spin_lock_irqsave(&qp->sq.lock, flags);
 
 	/* XXX check that state is OK to post send */
 
-	ind = qp->sq.next;
+	ind = qp->sq.next_ind;
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
-		if (qp->sq.cur + nreq >= qp->sq.max) {
-			mthca_err(dev, "SQ full (%d posted, %d max, %d nreq)\n",
-				  qp->sq.cur, qp->sq.max, nreq);
+		if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
+			mthca_err(dev, "SQ %06x full (%u head, %u tail,"
+					" %d max, %d nreq)\n", qp->qpn,
+					qp->sq.head, qp->sq.tail,
+					qp->sq.max, nreq);
 			err = -ENOMEM;
 			*bad_wr = wr;
 			goto out;
@@ -1272,7 +1476,7 @@ int mthca_post_send(struct ib_qp *ibqp, 
 			cpu_to_be32(1);
 		if (wr->opcode == IB_WR_SEND_WITH_IMM ||
 		    wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM)
-			((struct mthca_next_seg *) wqe)->flags = wr->imm_data;
+			((struct mthca_next_seg *) wqe)->imm = wr->imm_data;
 
 		wqe += sizeof (struct mthca_next_seg);
 		size = sizeof (struct mthca_next_seg) / 16;
@@ -1326,17 +1530,17 @@ int mthca_post_send(struct ib_qp *ibqp, 
 			break;
 
 		case UD:
-			((struct mthca_ud_seg *) wqe)->lkey =
+			((struct mthca_tavor_ud_seg *) wqe)->lkey =
 				cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
-			((struct mthca_ud_seg *) wqe)->av_addr =
+			((struct mthca_tavor_ud_seg *) wqe)->av_addr =
 				cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
-			((struct mthca_ud_seg *) wqe)->dqpn =
+			((struct mthca_tavor_ud_seg *) wqe)->dqpn =
 				cpu_to_be32(wr->wr.ud.remote_qpn);
-			((struct mthca_ud_seg *) wqe)->qkey =
+			((struct mthca_tavor_ud_seg *) wqe)->qkey =
 				cpu_to_be32(wr->wr.ud.remote_qkey);
 
-			wqe += sizeof (struct mthca_ud_seg);
-			size += sizeof (struct mthca_ud_seg) / 16;
+			wqe += sizeof (struct mthca_tavor_ud_seg);
+			size += sizeof (struct mthca_tavor_ud_seg) / 16;
 			break;
 
 		case MLX:
@@ -1381,7 +1585,7 @@ int mthca_post_send(struct ib_qp *ibqp, 
 
 		qp->wrid[ind + qp->rq.max] = wr->wr_id;
 
-		if (wr->opcode >= ARRAY_SIZE(opcode)) {
+		if (wr->opcode >= ARRAY_SIZE(mthca_opcode)) {
 			mthca_err(dev, "opcode invalid\n");
 			err = -EINVAL;
 			*bad_wr = wr;
@@ -1392,15 +1596,15 @@ int mthca_post_send(struct ib_qp *ibqp, 
 			((struct mthca_next_seg *) prev_wqe)->nda_op =
 				cpu_to_be32(((ind << qp->sq.wqe_shift) +
 					     qp->send_wqe_offset) |
-					    opcode[wr->opcode]);
-			smp_wmb();
+					    mthca_opcode[wr->opcode]);
+			wmb();
 			((struct mthca_next_seg *) prev_wqe)->ee_nds =
 				cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size);
 		}
 
 		if (!size0) {
 			size0 = size;
-			op0   = opcode[wr->opcode];
+			op0   = mthca_opcode[wr->opcode];
 		}
 
 		++ind;
@@ -1409,10 +1613,10 @@ int mthca_post_send(struct ib_qp *ibqp, 
 	}
 
 out:
-	if (nreq) {
+	if (likely(nreq)) {
 		u32 doorbell[2];
 
-		doorbell[0] = cpu_to_be32(((qp->sq.next << qp->sq.wqe_shift) +
+		doorbell[0] = cpu_to_be32(((qp->sq.next_ind << qp->sq.wqe_shift) +
 					   qp->send_wqe_offset) | f0 | op0);
 		doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
 
@@ -1423,15 +1627,15 @@ out:
 			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 	}
 
-	qp->sq.cur += nreq;
-	qp->sq.next = ind;
+	qp->sq.next_ind = ind;
+	qp->sq.head    += nreq;
 
-	spin_unlock_irqrestore(&qp->lock, flags);
+	spin_unlock_irqrestore(&qp->sq.lock, flags);
 	return err;
 }
 
-int mthca_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
-		       struct ib_recv_wr **bad_wr)
+int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+			     struct ib_recv_wr **bad_wr)
 {
 	struct mthca_dev *dev = to_mdev(ibqp->device);
 	struct mthca_qp *qp = to_mqp(ibqp);
@@ -1445,15 +1649,18 @@ int mthca_post_receive(struct ib_qp *ibq
 	void *wqe;
 	void *prev_wqe;
 
-	spin_lock_irqsave(&qp->lock, flags);
+	spin_lock_irqsave(&qp->rq.lock, flags);
 
 	/* XXX check that state is OK to post receive */
 
-	ind = qp->rq.next;
+	ind = qp->rq.next_ind;
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
-		if (qp->rq.cur + nreq >= qp->rq.max) {
-			mthca_err(dev, "RQ %06x full\n", qp->qpn);
+		if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
+			mthca_err(dev, "RQ %06x full (%u head, %u tail,"
+					" %d max, %d nreq)\n", qp->qpn,
+					qp->rq.head, qp->rq.tail,
+					qp->rq.max, nreq);
 			err = -ENOMEM;
 			*bad_wr = wr;
 			goto out;
@@ -1466,14 +1673,12 @@ int mthca_post_receive(struct ib_qp *ibq
 		((struct mthca_next_seg *) wqe)->nda_op = 0;
 		((struct mthca_next_seg *) wqe)->ee_nds =
 			cpu_to_be32(MTHCA_NEXT_DBD);
-		((struct mthca_next_seg *) wqe)->flags =
-			(wr->recv_flags & IB_RECV_SIGNALED) ?
-			cpu_to_be32(MTHCA_NEXT_CQ_UPDATE) : 0;
+		((struct mthca_next_seg *) wqe)->flags = 0;
 
 		wqe += sizeof (struct mthca_next_seg);
 		size = sizeof (struct mthca_next_seg) / 16;
 
-		if (wr->num_sge > qp->rq.max_gs) {
+		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
 			err = -EINVAL;
 			*bad_wr = wr;
 			goto out;
@@ -1492,10 +1697,10 @@ int mthca_post_receive(struct ib_qp *ibq
 
 		qp->wrid[ind] = wr->wr_id;
 
-		if (prev_wqe) {
+		if (likely(prev_wqe)) {
 			((struct mthca_next_seg *) prev_wqe)->nda_op =
 				cpu_to_be32((ind << qp->rq.wqe_shift) | 1);
-			smp_wmb();
+			wmb();
 			((struct mthca_next_seg *) prev_wqe)->ee_nds =
 				cpu_to_be32(MTHCA_NEXT_DBD | size);
 		}
@@ -1509,10 +1714,10 @@ int mthca_post_receive(struct ib_qp *ibq
 	}
 
 out:
-	if (nreq) {
+	if (likely(nreq)) {
 		u32 doorbell[2];
 
-		doorbell[0] = cpu_to_be32((qp->rq.next << qp->rq.wqe_shift) | size0);
+		doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
 		doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq);
 
 		wmb();
@@ -1522,14 +1727,305 @@ out:
 			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 	}
 
-	qp->rq.cur += nreq;
-	qp->rq.next = ind;
+	qp->rq.next_ind = ind;
+	qp->rq.head    += nreq;
 
-	spin_unlock_irqrestore(&qp->lock, flags);
+	spin_unlock_irqrestore(&qp->rq.lock, flags);
 	return err;
 }
 
-int mthca_free_err_wqe(struct mthca_qp *qp, int is_send,
+int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+			  struct ib_send_wr **bad_wr)
+{
+	struct mthca_dev *dev = to_mdev(ibqp->device);
+	struct mthca_qp *qp = to_mqp(ibqp);
+	void *wqe;
+	void *prev_wqe;
+	unsigned long flags;
+	int err = 0;
+	int nreq;
+	int i;
+	int size;
+	int size0 = 0;
+	u32 f0 = 0;
+	int ind;
+	u8 op0 = 0;
+
+	spin_lock_irqsave(&qp->sq.lock, flags);
+
+	/* XXX check that state is OK to post send */
+
+	ind = qp->sq.head & (qp->sq.max - 1);
+
+	for (nreq = 0; wr; ++nreq, wr = wr->next) {
+		if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
+			mthca_err(dev, "SQ %06x full (%u head, %u tail,"
+					" %d max, %d nreq)\n", qp->qpn,
+					qp->sq.head, qp->sq.tail,
+					qp->sq.max, nreq);
+			err = -ENOMEM;
+			*bad_wr = wr;
+			goto out;
+		}
+
+		wqe = get_send_wqe(qp, ind);
+		prev_wqe = qp->sq.last;
+		qp->sq.last = wqe;
+
+		((struct mthca_next_seg *) wqe)->flags =
+			((wr->send_flags & IB_SEND_SIGNALED) ?
+			 cpu_to_be32(MTHCA_NEXT_CQ_UPDATE) : 0) |
+			((wr->send_flags & IB_SEND_SOLICITED) ?
+			 cpu_to_be32(MTHCA_NEXT_SOLICIT) : 0)   |
+			cpu_to_be32(1);
+		if (wr->opcode == IB_WR_SEND_WITH_IMM ||
+		    wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM)
+			((struct mthca_next_seg *) wqe)->imm = wr->imm_data;
+
+		wqe += sizeof (struct mthca_next_seg);
+		size = sizeof (struct mthca_next_seg) / 16;
+
+		switch (qp->transport) {
+		case RC:
+			switch (wr->opcode) {
+			case IB_WR_ATOMIC_CMP_AND_SWP:
+			case IB_WR_ATOMIC_FETCH_AND_ADD:
+				((struct mthca_raddr_seg *) wqe)->raddr =
+					cpu_to_be64(wr->wr.atomic.remote_addr);
+				((struct mthca_raddr_seg *) wqe)->rkey =
+					cpu_to_be32(wr->wr.atomic.rkey);
+				((struct mthca_raddr_seg *) wqe)->reserved = 0;
+
+				wqe += sizeof (struct mthca_raddr_seg);
+
+				if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+					((struct mthca_atomic_seg *) wqe)->swap_add =
+						cpu_to_be64(wr->wr.atomic.swap);
+					((struct mthca_atomic_seg *) wqe)->compare =
+						cpu_to_be64(wr->wr.atomic.compare_add);
+				} else {
+					((struct mthca_atomic_seg *) wqe)->swap_add =
+						cpu_to_be64(wr->wr.atomic.compare_add);
+					((struct mthca_atomic_seg *) wqe)->compare = 0;
+				}
+
+				wqe += sizeof (struct mthca_atomic_seg);
+				size += sizeof (struct mthca_raddr_seg) / 16 +
+					sizeof (struct mthca_atomic_seg);
+				break;
+
+			case IB_WR_RDMA_WRITE:
+			case IB_WR_RDMA_WRITE_WITH_IMM:
+			case IB_WR_RDMA_READ:
+				((struct mthca_raddr_seg *) wqe)->raddr =
+					cpu_to_be64(wr->wr.rdma.remote_addr);
+				((struct mthca_raddr_seg *) wqe)->rkey =
+					cpu_to_be32(wr->wr.rdma.rkey);
+				((struct mthca_raddr_seg *) wqe)->reserved = 0;
+				wqe += sizeof (struct mthca_raddr_seg);
+				size += sizeof (struct mthca_raddr_seg) / 16;
+				break;
+
+			default:
+				/* No extra segments required for sends */
+				break;
+			}
+
+			break;
+
+		case UD:
+			memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
+			       to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+			((struct mthca_arbel_ud_seg *) wqe)->dqpn =
+				cpu_to_be32(wr->wr.ud.remote_qpn);
+			((struct mthca_arbel_ud_seg *) wqe)->qkey =
+				cpu_to_be32(wr->wr.ud.remote_qkey);
+
+			wqe += sizeof (struct mthca_arbel_ud_seg);
+			size += sizeof (struct mthca_arbel_ud_seg) / 16;
+			break;
+
+		case MLX:
+			err = build_mlx_header(dev, to_msqp(qp), ind, wr,
+					       wqe - sizeof (struct mthca_next_seg),
+					       wqe);
+			if (err) {
+				*bad_wr = wr;
+				goto out;
+			}
+			wqe += sizeof (struct mthca_data_seg);
+			size += sizeof (struct mthca_data_seg) / 16;
+			break;
+		}
+
+		if (wr->num_sge > qp->sq.max_gs) {
+			mthca_err(dev, "too many gathers\n");
+			err = -EINVAL;
+			*bad_wr = wr;
+			goto out;
+		}
+
+		for (i = 0; i < wr->num_sge; ++i) {
+			((struct mthca_data_seg *) wqe)->byte_count =
+				cpu_to_be32(wr->sg_list[i].length);
+			((struct mthca_data_seg *) wqe)->lkey =
+				cpu_to_be32(wr->sg_list[i].lkey);
+			((struct mthca_data_seg *) wqe)->addr =
+				cpu_to_be64(wr->sg_list[i].addr);
+			wqe += sizeof (struct mthca_data_seg);
+			size += sizeof (struct mthca_data_seg) / 16;
+		}
+
+		/* Add one more inline data segment for ICRC */
+		if (qp->transport == MLX) {
+			((struct mthca_data_seg *) wqe)->byte_count =
+				cpu_to_be32((1 << 31) | 4);
+			((u32 *) wqe)[1] = 0;
+			wqe += sizeof (struct mthca_data_seg);
+			size += sizeof (struct mthca_data_seg) / 16;
+		}
+
+		qp->wrid[ind + qp->rq.max] = wr->wr_id;
+
+		if (wr->opcode >= ARRAY_SIZE(mthca_opcode)) {
+			mthca_err(dev, "opcode invalid\n");
+			err = -EINVAL;
+			*bad_wr = wr;
+			goto out;
+		}
+
+		if (likely(prev_wqe)) {
+			((struct mthca_next_seg *) prev_wqe)->nda_op =
+				cpu_to_be32(((ind << qp->sq.wqe_shift) +
+					     qp->send_wqe_offset) |
+					    mthca_opcode[wr->opcode]);
+			wmb();
+			((struct mthca_next_seg *) prev_wqe)->ee_nds =
+				cpu_to_be32(MTHCA_NEXT_DBD | size);
+		}
+
+		if (!size0) {
+			size0 = size;
+			op0   = mthca_opcode[wr->opcode];
+		}
+
+		++ind;
+		if (unlikely(ind >= qp->sq.max))
+			ind -= qp->sq.max;
+	}
+
+out:
+	if (likely(nreq)) {
+		u32 doorbell[2];
+
+		doorbell[0] = cpu_to_be32((nreq << 24)                  |
+					  ((qp->sq.head & 0xffff) << 8) |
+					  f0 | op0);
+		doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
+
+		qp->sq.head += nreq;
+
+		/*
+		 * Make sure that descriptors are written before
+		 * doorbell record.
+		 */
+		wmb();
+		*qp->sq.db = cpu_to_be32(qp->sq.head & 0xffff);
+
+		/*
+		 * Make sure doorbell record is written before we
+		 * write MMIO send doorbell.
+		 */
+		wmb();
+		mthca_write64(doorbell,
+			      dev->kar + MTHCA_SEND_DOORBELL,
+			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+	}
+
+	spin_unlock_irqrestore(&qp->sq.lock, flags);
+	return err;
+}
+
+int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+			     struct ib_recv_wr **bad_wr)
+{
+	struct mthca_dev *dev = to_mdev(ibqp->device);
+	struct mthca_qp *qp = to_mqp(ibqp);
+	unsigned long flags;
+	int err = 0;
+	int nreq;
+	int ind;
+	int i;
+	void *wqe;
+
+ 	spin_lock_irqsave(&qp->rq.lock, flags);
+
+	/* XXX check that state is OK to post receive */
+
+	ind = qp->rq.head & (qp->rq.max - 1);
+
+	for (nreq = 0; wr; ++nreq, wr = wr->next) {
+		if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
+			mthca_err(dev, "RQ %06x full (%u head, %u tail,"
+					" %d max, %d nreq)\n", qp->qpn,
+					qp->rq.head, qp->rq.tail,
+					qp->rq.max, nreq);
+			err = -ENOMEM;
+			*bad_wr = wr;
+			goto out;
+		}
+
+		wqe = get_recv_wqe(qp, ind);
+
+		((struct mthca_next_seg *) wqe)->flags = 0;
+
+		wqe += sizeof (struct mthca_next_seg);
+
+		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
+			err = -EINVAL;
+			*bad_wr = wr;
+			goto out;
+		}
+
+		for (i = 0; i < wr->num_sge; ++i) {
+			((struct mthca_data_seg *) wqe)->byte_count =
+				cpu_to_be32(wr->sg_list[i].length);
+			((struct mthca_data_seg *) wqe)->lkey =
+				cpu_to_be32(wr->sg_list[i].lkey);
+			((struct mthca_data_seg *) wqe)->addr =
+				cpu_to_be64(wr->sg_list[i].addr);
+			wqe += sizeof (struct mthca_data_seg);
+		}
+
+		if (i < qp->rq.max_gs) {
+			((struct mthca_data_seg *) wqe)->byte_count = 0;
+			((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+			((struct mthca_data_seg *) wqe)->addr = 0;
+		}
+
+		qp->wrid[ind] = wr->wr_id;
+
+		++ind;
+		if (unlikely(ind >= qp->rq.max))
+			ind -= qp->rq.max;
+	}
+out:
+	if (likely(nreq)) {
+		qp->rq.head += nreq;
+
+		/*
+		 * Make sure that descriptors are written before
+		 * doorbell record.
+		 */
+		wmb();
+		*qp->rq.db = cpu_to_be32(qp->rq.head & 0xffff);
+	}
+
+	spin_unlock_irqrestore(&qp->rq.lock, flags);
+	return err;
+}
+
+int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
 		       int index, int *dbd, u32 *new_wqe)
 {
 	struct mthca_next_seg *next;
@@ -1539,7 +2035,10 @@ int mthca_free_err_wqe(struct mthca_qp *
 	else
 		next = get_recv_wqe(qp, index);
 
-	*dbd = !!(next->ee_nds & cpu_to_be32(MTHCA_NEXT_DBD));
+	if (mthca_is_memfree(dev))
+		*dbd = 1;
+	else
+		*dbd = !!(next->ee_nds & cpu_to_be32(MTHCA_NEXT_DBD));
 	if (next->ee_nds & cpu_to_be32(0x3f))
 		*new_wqe = (next->nda_op & cpu_to_be32(~0x3f)) |
 			(next->ee_nds & cpu_to_be32(0x3f));
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c
--- a/drivers/infiniband/hw/mthca/mthca_reset.c
+++ b/drivers/infiniband/hw/mthca/mthca_reset.c
@@ -50,7 +50,7 @@ int mthca_reset(struct mthca_dev *mdev)
 	struct pci_dev *bridge = NULL;
 
 #define MTHCA_RESET_OFFSET 0xf0010
-#define MTHCA_RESET_VALUE  cpu_to_be32(1)
+#define MTHCA_RESET_VALUE  swab32(1)
 
 	/*
 	 * Reset the chip.  This is somewhat ugly because we have to
@@ -63,7 +63,7 @@ int mthca_reset(struct mthca_dev *mdev)
 	 * header as well.
 	 */
 
-	if (mdev->hca_type == TAVOR) {
+	if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) {
 		/* Look for the bridge -- its device ID will be 2 more
 		   than HCA's device ID. */
 		while ((bridge = pci_get_device(mdev->pdev->vendor,
diff --git a/drivers/infiniband/hw/mthca/mthca_uar.c b/drivers/infiniband/hw/mthca/mthca_uar.c
new file mode 100644
--- /dev/null
+++ b/drivers/infiniband/hw/mthca/mthca_uar.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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 THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "mthca_dev.h"
+#include "mthca_memfree.h"
+
+int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar)
+{
+	uar->index = mthca_alloc(&dev->uar_table.alloc);
+	if (uar->index == -1)
+		return -ENOMEM;
+
+	uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index;
+
+	return 0;
+}
+
+void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar)
+{
+	mthca_free(&dev->uar_table.alloc, uar->index);
+}
+
+int mthca_init_uar_table(struct mthca_dev *dev)
+{
+	int ret;
+
+	ret = mthca_alloc_init(&dev->uar_table.alloc,
+			       dev->limits.num_uars,
+			       dev->limits.num_uars - 1,
+			       dev->limits.reserved_uars);
+	if (ret)
+		return ret;
+
+	ret = mthca_init_db_tab(dev);
+	if (ret)
+		mthca_alloc_cleanup(&dev->uar_table.alloc);
+
+	return ret;
+}
+
+void mthca_cleanup_uar_table(struct mthca_dev *dev)
+{
+	mthca_cleanup_db_tab(dev);
+
+	/* XXX check if any UARs are still allocated? */
+	mthca_alloc_cleanup(&dev->uar_table.alloc);
+}
diff --git a/drivers/infiniband/include/ib_sa.h b/drivers/infiniband/include/ib_sa.h
--- a/drivers/infiniband/include/ib_sa.h
+++ b/drivers/infiniband/include/ib_sa.h
@@ -147,7 +147,7 @@ struct ib_sa_path_rec {
 	/* reserved */
 	u8           sl;
 	u8           mtu_selector;
-	enum ib_mtu  mtu;
+	u8           mtu;
 	u8           rate_selector;
 	u8           rate;
 	u8           packet_life_time_selector;
@@ -180,7 +180,7 @@ struct ib_sa_mcmember_rec {
 	u32          qkey;
 	u16          mlid;
 	u8           mtu_selector;
-	enum         ib_mtu mtu;
+	u8           mtu;
 	u8           traffic_class;
 	u16          pkey;
 	u8 	     rate_selector;
diff --git a/drivers/infiniband/include/ib_verbs.h b/drivers/infiniband/include/ib_verbs.h
--- a/drivers/infiniband/include/ib_verbs.h
+++ b/drivers/infiniband/include/ib_verbs.h
@@ -73,7 +73,6 @@ enum ib_device_cap_flags {
 	IB_DEVICE_RC_RNR_NAK_GEN	= (1<<12),
 	IB_DEVICE_SRQ_RESIZE		= (1<<13),
 	IB_DEVICE_N_NOTIFY_CQ		= (1<<14),
-	IB_DEVICE_RQ_SIG_TYPE		= (1<<15)
 };
 
 enum ib_atomic_cap {
@@ -408,7 +407,6 @@ struct ib_qp_init_attr {
 	struct ib_srq	       *srq;
 	struct ib_qp_cap	cap;
 	enum ib_sig_type	sq_sig_type;
-	enum ib_sig_type	rq_sig_type;
 	enum ib_qp_type		qp_type;
 	u8			port_num; /* special QP types only */
 };
@@ -533,10 +531,6 @@ enum ib_send_flags {
 	IB_SEND_INLINE		= (1<<3)
 };
 
-enum ib_recv_flags {
-	IB_RECV_SIGNALED	= 1
-};
-
 struct ib_sge {
 	u64	addr;
 	u32	length;
@@ -579,7 +573,6 @@ struct ib_recv_wr {
 	u64			wr_id;
 	struct ib_sge	       *sg_list;
 	int			num_sge;
-	int			recv_flags;
 };
 
 enum ib_access_flags {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -308,11 +308,11 @@ static inline void ipoib_unregister_debu
 
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
-extern int debug_level;
+extern int ipoib_debug_level;
 
 #define ipoib_dbg(priv, format, arg...)			\
 	do {					        \
-		if (debug_level > 0)			\
+		if (ipoib_debug_level > 0)			\
 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
 	} while (0)
 #define ipoib_dbg_mcast(priv, format, arg...)		\
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -32,19 +32,16 @@
  * $Id: ipoib_fs.c 1389 2004-12-27 22:56:47Z roland $
  */
 
-#include <linux/pagemap.h>
+#include <linux/err.h>
 #include <linux/seq_file.h>
 
-#include "ipoib.h"
+struct file_operations;
 
-enum {
-	IPOIB_MAGIC = 0x49504942 /* "IPIB" */
-};
+#include <linux/debugfs.h>
+
+#include "ipoib.h"
 
-static DECLARE_MUTEX(ipoib_fs_mutex);
 static struct dentry *ipoib_root;
-static struct super_block *ipoib_sb;
-static LIST_HEAD(ipoib_device_list);
 
 static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
 {
@@ -145,143 +142,34 @@ static struct file_operations ipoib_fops
 	.release = seq_release
 };
 
-static struct inode *ipoib_get_inode(void)
-{
-	struct inode *inode = new_inode(ipoib_sb);
-
-	if (inode) {
-		inode->i_mode 	 = S_IFREG | S_IRUGO;
-		inode->i_uid 	 = 0;
-		inode->i_gid 	 = 0;
-		inode->i_blksize = PAGE_CACHE_SIZE;
-		inode->i_blocks  = 0;
-		inode->i_atime 	 = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		inode->i_fop     = &ipoib_fops;
-	}
-
-	return inode;
-}
-
-static int __ipoib_create_debug_file(struct net_device *dev)
+int ipoib_create_debug_file(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	struct dentry *dentry;
-	struct inode *inode;
 	char name[IFNAMSIZ + sizeof "_mcg"];
 
 	snprintf(name, sizeof name, "%s_mcg", dev->name);
 
-	dentry = d_alloc_name(ipoib_root, name);
-	if (!dentry)
-		return -ENOMEM;
-
-	inode = ipoib_get_inode();
-	if (!inode) {
-		dput(dentry);
-		return -ENOMEM;
-	}
-
-	inode->u.generic_ip = dev;
-	priv->mcg_dentry = dentry;
-
-	d_add(dentry, inode);
-
-	return 0;
-}
-
-int ipoib_create_debug_file(struct net_device *dev)
-{
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-
-	down(&ipoib_fs_mutex);
-
-	list_add_tail(&priv->fs_list, &ipoib_device_list);
-
-	if (!ipoib_sb) {
-		up(&ipoib_fs_mutex);
-		return 0;
-	}
-
-	up(&ipoib_fs_mutex);
+	priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					       ipoib_root, dev, &ipoib_fops);
 
-	return __ipoib_create_debug_file(dev);
+	return priv->mcg_dentry ? 0 : -ENOMEM;
 }
 
 void ipoib_delete_debug_file(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-	down(&ipoib_fs_mutex);
-	list_del(&priv->fs_list);
-	if (!ipoib_sb) {
-		up(&ipoib_fs_mutex);
-		return;
-	}
-	up(&ipoib_fs_mutex);
-
-	if (priv->mcg_dentry) {
-		d_drop(priv->mcg_dentry);
-		simple_unlink(ipoib_root->d_inode, priv->mcg_dentry);
-	}
-}
-
-static int ipoib_fill_super(struct super_block *sb, void *data, int silent)
-{
-	static struct tree_descr ipoib_files[] = {
-		{ "" }
-	};
-	struct ipoib_dev_priv *priv;
-	int ret;
-
-	ret = simple_fill_super(sb, IPOIB_MAGIC, ipoib_files);
-	if (ret)
-		return ret;
-
-	ipoib_root = sb->s_root;
-
-	down(&ipoib_fs_mutex);
-
-	ipoib_sb = sb;
-
-	list_for_each_entry(priv, &ipoib_device_list, fs_list) {
-		ret = __ipoib_create_debug_file(priv->dev);
-		if (ret)
-			break;
-	}
-
-	up(&ipoib_fs_mutex);
-
-	return ret;
-}
-
-static struct super_block *ipoib_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
-{
-	return get_sb_single(fs_type, flags, data, ipoib_fill_super);
+	if (priv->mcg_dentry)
+		debugfs_remove(priv->mcg_dentry);
 }
 
-static void ipoib_kill_sb(struct super_block *sb)
-{
-	down(&ipoib_fs_mutex);
-	ipoib_sb = NULL;
-	up(&ipoib_fs_mutex);
-
-	kill_litter_super(sb);
-}
-
-static struct file_system_type ipoib_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "ipoib_debugfs",
-	.get_sb		= ipoib_get_sb,
-	.kill_sb	= ipoib_kill_sb,
-};
-
 int ipoib_register_debugfs(void)
 {
-	return register_filesystem(&ipoib_fs_type);
+	ipoib_root = debugfs_create_dir("ipoib", NULL);
+	return ipoib_root ? 0 : -ENOMEM;
 }
 
 void ipoib_unregister_debugfs(void)
 {
-	unregister_filesystem(&ipoib_fs_type);
+	debugfs_remove(ipoib_root);
 }
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -40,7 +40,7 @@
 #include "ipoib.h"
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
-int data_debug_level;
+static int data_debug_level;
 
 module_param(data_debug_level, int, 0644);
 MODULE_PARM_DESC(data_debug_level,
@@ -105,7 +105,6 @@ static inline int ipoib_ib_receive(struc
 		.wr_id 	    = wr_id | IPOIB_OP_RECV,
 		.sg_list    = &list,
 		.num_sge    = 1,
-		.recv_flags = IB_RECV_SIGNALED
 	};
 	struct ib_recv_wr *bad_wr;
 
@@ -137,6 +136,9 @@ static int ipoib_ib_post_receive(struct 
 	if (ret) {
 		ipoib_warn(priv, "ipoib_ib_receive failed for buf %d (%d)\n",
 			   id, ret);
+		dma_unmap_single(priv->ca->dma_device, addr,
+				 IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+		dev_kfree_skb_any(skb);
 		priv->rx_ring[id].skb = NULL;
 	}
 
@@ -199,7 +201,7 @@ static void ipoib_ib_handle_wc(struct ne
 			if (wc->slid != priv->local_lid ||
 			    wc->src_qp != priv->qp->qp_num) {
 				skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-
+				skb->mac.raw = skb->data;
 				skb_pull(skb, IPOIB_ENCAP_LEN);
 
 				dev->last_rx = jiffies;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -51,9 +51,9 @@ MODULE_DESCRIPTION("IP-over-InfiniBand n
 MODULE_LICENSE("Dual BSD/GPL");
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
-int debug_level;
+int ipoib_debug_level;
 
-module_param(debug_level, int, 0644);
+module_param_named(debug_level, ipoib_debug_level, int, 0644);
 MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
 #endif
 
@@ -215,16 +215,25 @@ static int __path_add(struct net_device 
 	return 0;
 }
 
-static void __path_free(struct net_device *dev, struct ipoib_path *path)
+static void path_free(struct net_device *dev, struct ipoib_path *path)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh, *tn;
 	struct sk_buff *skb;
+	unsigned long flags;
 
 	while ((skb = __skb_dequeue(&path->queue)))
 		dev_kfree_skb_irq(skb);
 
+	spin_lock_irqsave(&priv->lock, flags);
+
 	list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) {
+		/*
+		 * It's safe to call ipoib_put_ah() inside priv->lock
+		 * here, because we know that path->ah will always
+		 * hold one more reference, so ipoib_put_ah() will
+		 * never do more than decrement the ref count.
+		 */
 		if (neigh->ah)
 			ipoib_put_ah(neigh->ah);
 		*to_ipoib_neigh(neigh->neighbour) = NULL;
@@ -232,11 +241,11 @@ static void __path_free(struct net_devic
 		kfree(neigh);
 	}
 
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	if (path->ah)
 		ipoib_put_ah(path->ah);
 
-	rb_erase(&path->rb_node, &priv->path_tree);
-	list_del(&path->list);
 	kfree(path);
 }
 
@@ -248,15 +257,20 @@ void ipoib_flush_paths(struct net_device
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
+
 	list_splice(&priv->path_list, &remove_list);
 	INIT_LIST_HEAD(&priv->path_list);
+
+	list_for_each_entry(path, &remove_list, list)
+		rb_erase(&path->rb_node, &priv->path_tree);
+
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	list_for_each_entry_safe(path, tp, &remove_list, list) {
 		if (path->query)
 			ib_sa_cancel_query(path->query_id, path->query);
 		wait_for_completion(&path->done);
-		__path_free(dev, path);
+		path_free(dev, path);
 	}
 }
 
@@ -288,11 +302,10 @@ static void path_rec_completion(int stat
 			.sl 	       = pathrec->sl,
 			.port_num      = priv->port
 		};
+		int path_rate = ib_sa_rate_enum_to_int(pathrec->rate);
 
-		if (ib_sa_rate_enum_to_int(pathrec->rate) > 0)
-			av.static_rate = (2 * priv->local_rate -
-					  ib_sa_rate_enum_to_int(pathrec->rate) - 1) /
-				(priv->local_rate ? priv->local_rate : 1);
+		if (path_rate > 0 && priv->local_rate > path_rate)
+			av.static_rate = (priv->local_rate - 1) / path_rate;
 
 		ipoib_dbg(priv, "static_rate %d for local port %dX, path %dX\n",
 			  av.static_rate, priv->local_rate,
@@ -346,8 +359,9 @@ static struct ipoib_path *path_rec_creat
 	if (!path)
 		return NULL;
 
-	path->dev = dev;
+	path->dev          = dev;
 	path->pathrec.dlid = 0;
+	path->ah           = NULL;
 
 	skb_queue_head_init(&path->queue);
 
@@ -360,8 +374,6 @@ static struct ipoib_path *path_rec_creat
 	path->pathrec.pkey      = cpu_to_be16(priv->pkey);
 	path->pathrec.numb_path = 1;
 
-	__path_add(dev, path);
-
 	return path;
 }
 
@@ -421,6 +433,8 @@ static void neigh_add_path(struct sk_buf
 				       (union ib_gid *) (skb->dst->neighbour->ha + 4));
 		if (!path)
 			goto err;
+
+		__path_add(dev, path);
 	}
 
 	list_add_tail(&neigh->list, &path->neigh_list);
@@ -450,8 +464,8 @@ static void neigh_add_path(struct sk_buf
 err:
 	*to_ipoib_neigh(skb->dst->neighbour) = NULL;
 	list_del(&neigh->list);
-	kfree(neigh);
 	neigh->neighbour->ops->destructor = NULL;
+	kfree(neigh);
 
 	++priv->stats.tx_dropped;
 	dev_kfree_skb_any(skb);
@@ -496,8 +510,12 @@ static void unicast_arp_send(struct sk_b
 			skb_push(skb, sizeof *phdr);
 			__skb_queue_tail(&path->queue, skb);
 
-			if (path_rec_start(dev, path))
-				__path_free(dev, path);
+			if (path_rec_start(dev, path)) {
+				spin_unlock(&priv->lock);
+				path_free(dev, path);
+				return;
+			} else
+				__path_add(dev, path);
 		} else {
 			++priv->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
@@ -657,9 +675,10 @@ static void ipoib_set_mcast_list(struct 
 
 static void ipoib_neigh_destructor(struct neighbour *n)
 {
-	struct ipoib_neigh *neigh = *to_ipoib_neigh(n);
+	struct ipoib_neigh *neigh;
 	struct ipoib_dev_priv *priv = netdev_priv(n->dev);
 	unsigned long flags;
+	struct ipoib_ah *ah = NULL;
 
 	ipoib_dbg(priv,
 		  "neigh_destructor for %06x " IPOIB_GID_FMT "\n",
@@ -668,15 +687,19 @@ static void ipoib_neigh_destructor(struc
 
 	spin_lock_irqsave(&priv->lock, flags);
 
+	neigh = *to_ipoib_neigh(n);
 	if (neigh) {
 		if (neigh->ah)
-			ipoib_put_ah(neigh->ah);
+			ah = neigh->ah;
 		list_del(&neigh->list);
 		*to_ipoib_neigh(n) = NULL;
 		kfree(neigh);
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (ah)
+		ipoib_put_ah(ah);
 }
 
 static int ipoib_neigh_setup(struct neighbour *neigh)
@@ -1059,19 +1082,19 @@ static int __init ipoib_init_module(void
 
 	return 0;
 
-err_fs:
-	ipoib_unregister_debugfs();
-
 err_wq:
 	destroy_workqueue(ipoib_workqueue);
 
+err_fs:
+	ipoib_unregister_debugfs();
+
 	return ret;
 }
 
 static void __exit ipoib_cleanup_module(void)
 {
-	ipoib_unregister_debugfs();
 	ib_unregister_client(&ipoib_client);
+	ipoib_unregister_debugfs();
 	destroy_workqueue(ipoib_workqueue);
 }
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -93,6 +93,8 @@ static void ipoib_mcast_free(struct ipoi
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh, *tmp;
 	unsigned long flags;
+	LIST_HEAD(ah_list);
+	struct ipoib_ah *ah, *tah;
 
 	ipoib_dbg_mcast(netdev_priv(dev),
 			"deleting multicast group " IPOIB_GID_FMT "\n",
@@ -101,7 +103,8 @@ static void ipoib_mcast_free(struct ipoi
 	spin_lock_irqsave(&priv->lock, flags);
 
 	list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
-		ipoib_put_ah(neigh->ah);
+		if (neigh->ah)
+			list_add_tail(&neigh->ah->list, &ah_list);
 		*to_ipoib_neigh(neigh->neighbour) = NULL;
 		neigh->neighbour->ops->destructor = NULL;
 		kfree(neigh);
@@ -109,6 +112,9 @@ static void ipoib_mcast_free(struct ipoi
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	list_for_each_entry_safe(ah, tah, &ah_list, list)
+		ipoib_put_ah(ah);
+
 	if (mcast->ah)
 		ipoib_put_ah(mcast->ah);
 
@@ -252,13 +258,12 @@ static int ipoib_mcast_join_finish(struc
 				.traffic_class = mcast->mcmember.traffic_class
 			}
 		};
+		int path_rate = ib_sa_rate_enum_to_int(mcast->mcmember.rate);
 
 		av.grh.dgid = mcast->mcmember.mgid;
 
-		if (ib_sa_rate_enum_to_int(mcast->mcmember.rate) > 0)
-			av.static_rate = (2 * priv->local_rate -
-					  ib_sa_rate_enum_to_int(mcast->mcmember.rate) - 1) /
-				(priv->local_rate ? priv->local_rate : 1);
+		if (path_rate > 0 && priv->local_rate > path_rate)
+			av.static_rate = (priv->local_rate - 1) / path_rate;
 
 		ipoib_dbg_mcast(priv, "static_rate %d for local port %dX, mcmember %dX\n",
 				av.static_rate, priv->local_rate,
@@ -790,7 +795,7 @@ void ipoib_mcast_dev_flush(struct net_de
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	list_for_each_entry(mcast, &remove_list, list) {
+	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
 		ipoib_mcast_leave(dev, mcast);
 		ipoib_mcast_free(mcast);
 	}
@@ -902,7 +907,7 @@ void ipoib_mcast_restart_task(void *dev_
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* We have to cancel outside of the spinlock */
-	list_for_each_entry(mcast, &remove_list, list) {
+	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
 		ipoib_mcast_leave(mcast->dev, mcast);
 		ipoib_mcast_free(mcast);
 	}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -165,7 +165,6 @@ int ipoib_transport_dev_init(struct net_
 			.max_recv_sge = 1
 		},
 		.sq_sig_type = IB_SIGNAL_ALL_WR,
-		.rq_sig_type = IB_SIGNAL_ALL_WR,
 		.qp_type     = IB_QPT_UD
 	};
 
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -5,7 +5,7 @@
 menu "Input device support"
 
 config INPUT
-	tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED
+	tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
 	default y
 	---help---
 	  Say Y here if you have any input device (mouse, keyboard, tablet,
@@ -22,12 +22,13 @@ config INPUT
 	  To compile this driver as a module, choose M here: the
 	  module will be called input.
 
+if INPUT
+
 comment "Userland interfaces"
 
 config INPUT_MOUSEDEV
 	tristate "Mouse interface" if EMBEDDED
 	default y
-	depends on INPUT
 	---help---
 	  Say Y here if you want your mouse to be accessible as char devices
 	  13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
@@ -74,7 +75,6 @@ config INPUT_MOUSEDEV_SCREEN_Y
 
 config INPUT_JOYDEV
 	tristate "Joystick interface"
-	depends on INPUT
 	---help---
 	  Say Y here if you want your joystick or gamepad to be
 	  accessible as char device 13:0+ - /dev/input/jsX device.
@@ -88,7 +88,6 @@ config INPUT_JOYDEV
 
 config INPUT_TSDEV
 	tristate "Touchscreen interface"
-	depends on INPUT
 	---help---
 	  Say Y here if you have an application that only can understand the
 	  Compaq touchscreen protocol for absolute pointer data. This is
@@ -111,7 +110,6 @@ config INPUT_TSDEV_SCREEN_Y
 
 config INPUT_EVDEV
 	tristate "Event interface"
-	depends on INPUT
 	help
 	  Say Y here if you want your input device events be accessible
 	  under char device 13:64+ - /dev/input/eventX in a generic way.
@@ -121,7 +119,6 @@ config INPUT_EVDEV
 
 config INPUT_EVBUG
 	tristate "Event debugging"
-	depends on INPUT
 	---help---
 	  Say Y here if you have a problem with the input subsystem and
 	  want all events (keypresses, mouse movements), to be output to
@@ -134,12 +131,6 @@ config INPUT_EVBUG
 	  To compile this driver as a module, choose M here: the
 	  module will be called evbug.
 
-comment "Input I/O drivers"
-
-source "drivers/input/gameport/Kconfig"
-
-source "drivers/input/serio/Kconfig"
-
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
@@ -152,5 +143,15 @@ source "drivers/input/touchscreen/Kconfi
 
 source "drivers/input/misc/Kconfig"
 
+endif
+
+menu "Hardware I/O ports"
+
+source "drivers/input/serio/Kconfig"
+
+source "drivers/input/gameport/Kconfig"
+
+endmenu
+
 endmenu
 
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -88,13 +88,13 @@ static struct input_handler evbug_handle
 	.id_table =	evbug_ids,
 };
 
-int __init evbug_init(void)
+static int __init evbug_init(void)
 {
 	input_register_handler(&evbug_handler);
 	return 0;
 }
 
-void __exit evbug_exit(void)
+static void __exit evbug_exit(void)
 {
 	input_unregister_handler(&evbug_handler);
 }
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -169,6 +169,9 @@ static ssize_t evdev_read(struct file * 
 	struct evdev_list *list = file->private_data;
 	int retval;
 
+	if (count < sizeof(struct input_event))
+		return -EINVAL;
+
 	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
@@ -196,9 +199,8 @@ static unsigned int evdev_poll(struct fi
 {
 	struct evdev_list *list = file->private_data;
 	poll_wait(file, &list->evdev->wait, wait);
-	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -223,14 +225,15 @@ static int evdev_ioctl(struct inode *ino
 
 		case EVIOCGKEYCODE:
 			if (get_user(t, ip)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
 			if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT;
 			return 0;
 
 		case EVIOCSKEYCODE:
 			if (get_user(t, ip)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
 			if (get_user(v, ip + 1)) return -EFAULT;
+			if (v < 0 || v > KEY_MAX) return -EINVAL;
 			u = SET_INPUT_KEYCODE(dev, t, v);
 			clear_bit(u, dev->keybit);
 			set_bit(v, dev->keybit);
@@ -438,6 +441,7 @@ static struct input_handle *evdev_connec
 static void evdev_disconnect(struct input_handle *handle)
 {
 	struct evdev *evdev = handle->private;
+	struct evdev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 	devfs_remove("input/event%d", evdev->minor);
@@ -446,6 +450,8 @@ static void evdev_disconnect(struct inpu
 	if (evdev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&evdev->wait);
+		list_for_each_entry(list, &evdev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else
 		evdev_free(evdev);
 }
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -19,30 +19,10 @@ config GAMEPORT
 	  To compile this driver as a module, choose M here: the
 	  module will be called gameport.
 
-
-# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
-# in every .config. Please don't touch it. It is here to handle an
-# unusual dependency between GAMEPORT and sound drivers.
-#
-# Some sound drivers call gameport functions. If GAMEPORT is
-# not selected, empty stubs are provided for the functions and all is
-# well.
-# If GAMEPORT is built in, everything is fine.
-# If GAMEPORT is a module, however, it would need to be loaded for the
-# sound driver to be able to link properly. Therefore, the sound
-# driver must be a module as well in that case. Since there's no way
-# to express that directly in Kconfig, we use SOUND_GAMEPORT to
-# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
-# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
-# GAMEPORT is 'y' or 'n', it can be anything".
-config SOUND_GAMEPORT
-	tristate
-	default y if GAMEPORT!=m
-	default m if GAMEPORT=m
+if GAMEPORT
 
 config GAMEPORT_NS558
 	tristate "Classic ISA and PnP gameport support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have an ISA or PnP gameport.
 
@@ -53,7 +33,6 @@ config GAMEPORT_NS558
 
 config GAMEPORT_L4
 	tristate "PDPI Lightning 4 gamecard support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have a PDPI Lightning 4 gamecard.
 
@@ -62,7 +41,7 @@ config GAMEPORT_L4
 
 config GAMEPORT_EMU10K1
 	tristate "SB Live and Audigy gameport support"
-	depends on GAMEPORT
+	depends on PCI
 	help
 	  Say Y here if you have a SoundBlaster Live! or SoundBlaster
 	  Audigy card and want to use its gameport.
@@ -72,7 +51,7 @@ config GAMEPORT_EMU10K1
 
 config GAMEPORT_VORTEX
 	tristate "Aureal Vortex, Vortex 2 gameport support"
-	depends on GAMEPORT
+	depends on PCI
 	help
 	  Say Y here if you have an Aureal Vortex 1 or 2  card and want
 	  to use its gameport.
@@ -82,9 +61,10 @@ config GAMEPORT_VORTEX
 
 config GAMEPORT_FM801
 	tristate "ForteMedia FM801 gameport support"
-	depends on GAMEPORT
+	depends on PCI
 
 config GAMEPORT_CS461X
 	tristate "Crystal SoundFusion gameport support"
-	depends on GAMEPORT
+	depends on PCI
 
+endif
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
--- a/drivers/input/gameport/cs461x.c
+++ b/drivers/input/gameport/cs461x.c
@@ -16,7 +16,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 
-MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+MODULE_AUTHOR("Victor Krapivin");
 MODULE_LICENSE("GPL");
 
 /*
@@ -120,9 +120,6 @@ MODULE_LICENSE("GPL");
 static unsigned long ba0_addr;
 static unsigned int __iomem *ba0;
 
-static char phys[32];
-static char name[] = "CS416x Gameport";
-
 #ifdef CS461X_FULL_MAP
 static unsigned long ba1_addr;
 static union ba1_t {
@@ -160,10 +157,10 @@ static unsigned int cs461x_peekBA0(unsig
 static int cs461x_free(struct pci_dev *pdev)
 {
 	struct gameport *port = pci_get_drvdata(pdev);
-	if(port){
+
+	if (port)
 	    gameport_unregister_port(port);
-	    kfree(port);
-	}
+
 	if (ba0) iounmap(ba0);
 #ifdef CS461X_FULL_MAP
 	if (ba1.name.data0) iounmap(ba1.name.data0);
@@ -267,18 +264,17 @@ static int __devinit cs461x_pci_probe(st
                 return -ENOMEM;
         }
 #else
-	if (ba0 == NULL){
+	if (ba0 == NULL) {
 		cs461x_free(pdev);
 		return -ENOMEM;
 	}
 #endif
 
-	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
+	if (!(port = gameport_allocate_port())) {
+		printk(KERN_ERR "cs461x: Memory allocation failed\n");
 		cs461x_free(pdev);
 		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct gameport));
 
 	pci_set_drvdata(pdev, port);
 
@@ -287,22 +283,15 @@ static int __devinit cs461x_pci_probe(st
 	port->read = cs461x_gameport_read;
 	port->cooked_read = cs461x_gameport_cooked_read;
 
-	sprintf(phys, "pci%s/gameport0", pci_name(pdev));
-
-	port->name = name;
-	port->phys = phys;
-	port->id.bustype = BUS_PCI;
-	port->id.vendor = pdev->vendor;
-	port->id.product = pdev->device;
+	gameport_set_name(port, "CS416x");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
+	port->dev.parent = &pdev->dev;
 
 	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
 	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
 
 	gameport_register_port(port);
 
-	printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n",
-		name, pci_name(pdev), port->speed);
-
 	return 0;
 }
 
@@ -318,12 +307,12 @@ static struct pci_driver cs461x_pci_driv
         .remove =       __devexit_p(cs461x_pci_remove),
 };
 
-int __init cs461x_init(void)
+static int __init cs461x_init(void)
 {
-        return pci_module_init(&cs461x_pci_driver);
+        return pci_register_driver(&cs461x_pci_driver);
 }
 
-void __exit cs461x_exit(void)
+static void __exit cs461x_exit(void)
 {
         pci_unregister_driver(&cs461x_pci_driver);
 }
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -44,13 +44,13 @@ MODULE_LICENSE("GPL");
 
 struct emu {
 	struct pci_dev *dev;
-	struct gameport gameport;
+	struct gameport *gameport;
+	int io;
 	int size;
-	char phys[32];
 };
 
 static struct pci_device_id emu_tbl[] = {
- 
+
 	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
 	{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
 	{ 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
@@ -64,6 +64,7 @@ static int __devinit emu_probe(struct pc
 {
 	int ioport, iolen;
 	struct emu *emu;
+	struct gameport *port;
 
 	if (pci_enable_device(pdev))
 		return -EBUSY;
@@ -74,31 +75,29 @@ static int __devinit emu_probe(struct pc
 	if (!request_region(ioport, iolen, "emu10k1-gp"))
 		return -EBUSY;
 
-	if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
-		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
+	emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!emu || !port) {
+		printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
 		release_region(ioport, iolen);
+		kfree(emu);
+		gameport_free_port(port);
 		return -ENOMEM;
 	}
-	memset(emu, 0, sizeof(struct emu));
-
-	sprintf(emu->phys, "pci%s/gameport0", pci_name(pdev));
 
+	emu->io = ioport;
 	emu->size = iolen;
 	emu->dev = pdev;
+	emu->gameport = port;
 
-	emu->gameport.io = ioport;
-	emu->gameport.name = pci_name(pdev);
-	emu->gameport.phys = emu->phys;
-	emu->gameport.id.bustype = BUS_PCI;
-	emu->gameport.id.vendor = pdev->vendor;
-	emu->gameport.id.product = pdev->device;
+	gameport_set_name(port, "EMU10K1");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
+	port->dev.parent = &pdev->dev;
+	port->io = ioport;
 
 	pci_set_drvdata(pdev, emu);
 
-	gameport_register_port(&emu->gameport);
-
-	printk(KERN_INFO "gameport: pci%s speed %d kHz\n",
-		pci_name(pdev), emu->gameport.speed);
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -106,8 +105,9 @@ static int __devinit emu_probe(struct pc
 static void __devexit emu_remove(struct pci_dev *pdev)
 {
 	struct emu *emu = pci_get_drvdata(pdev);
-	gameport_unregister_port(&emu->gameport);
-	release_region(emu->gameport.io, emu->size);
+
+	gameport_unregister_port(emu->gameport);
+	release_region(emu->io, emu->size);
 	kfree(emu);
 }
 
@@ -118,12 +118,12 @@ static struct pci_driver emu_driver = {
         .remove =       __devexit_p(emu_remove),
 };
 
-int __init emu_init(void)
+static int __init emu_init(void)
 {
-	return pci_module_init(&emu_driver);
+	return pci_register_driver(&emu_driver);
 }
 
-void __exit emu_exit(void)
+static void __exit emu_exit(void)
 {
 	pci_unregister_driver(&emu_driver);
 }
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -37,10 +37,8 @@
 #define HAVE_COOKED
 
 struct fm801_gp {
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct resource *res_port;
-	char phys[32];
-	char name[32];
 };
 
 #ifdef HAVE_COOKED
@@ -83,40 +81,42 @@ static int fm801_gp_open(struct gameport
 static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
 	struct fm801_gp *gp;
+	struct gameport *port;
 
-	if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
-		printk("cannot malloc for fm801-gp\n");
-		return -1;
+	gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!gp || !port) {
+		printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
+		kfree(gp);
+		gameport_free_port(port);
+		return -ENOMEM;
 	}
-	memset(gp, 0, sizeof(*gp));
 
-	gp->gameport.open = fm801_gp_open;
+	pci_enable_device(pci);
+
+	port->open = fm801_gp_open;
 #ifdef HAVE_COOKED
-	gp->gameport.cooked_read = fm801_gp_cooked_read;
+	port->cooked_read = fm801_gp_cooked_read;
 #endif
-
-	pci_enable_device(pci);
-	gp->gameport.io = pci_resource_start(pci, 0);
-	if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
-		printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
+	gameport_set_name(port, "FM801");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pci));
+	port->dev.parent = &pci->dev;
+	port->io = pci_resource_start(pci, 0);
+
+	gp->gameport = port;
+	gp->res_port = request_region(port->io, 0x10, "FM801 GP");
+	if (!gp->res_port) {
 		kfree(gp);
-		return -1;
+		gameport_free_port(port);
+		printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
+			port->io, port->io + 0x0f);
+		return -EBUSY;
 	}
 
-	gp->gameport.phys = gp->phys;
-	gp->gameport.name = gp->name;
-	gp->gameport.id.bustype = BUS_PCI;
-	gp->gameport.id.vendor = pci->vendor;
-	gp->gameport.id.product = pci->device;
-
 	pci_set_drvdata(pci, gp);
 
-	outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
-
-	gameport_register_port(&gp->gameport);
-
-	printk(KERN_INFO "gameport: at pci%s speed %d kHz\n",
-		pci_name(pci), gp->gameport.speed);
+	outb(0x60, port->io + 0x0d); /* enable joystick 1 and 2 */
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -124,8 +124,9 @@ static int __devinit fm801_gp_probe(stru
 static void __devexit fm801_gp_remove(struct pci_dev *pci)
 {
 	struct fm801_gp *gp = pci_get_drvdata(pci);
+
 	if (gp) {
-		gameport_unregister_port(&gp->gameport);
+		gameport_unregister_port(gp->gameport);
 		release_resource(gp->res_port);
 		kfree(gp);
 	}
@@ -143,12 +144,12 @@ static struct pci_driver fm801_gp_driver
 	.remove =	__devexit_p(fm801_gp_remove),
 };
 
-int __init fm801_gp_init(void)
+static int __init fm801_gp_init(void)
 {
-	return pci_module_init(&fm801_gp_driver);
+	return pci_register_driver(&fm801_gp_driver);
 }
 
-void __exit fm801_gp_exit(void)
+static void __exit fm801_gp_exit(void)
 {
 	pci_unregister_driver(&fm801_gp_driver);
 }
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -2,6 +2,7 @@
  * Generic gameport layer
  *
  * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2005 Dmitry Torokhov
  */
 
 /*
@@ -10,32 +11,55 @@
  * the Free Software Foundation.
  */
 
-#include <asm/io.h>
+#include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/slab.h>
-#include <linux/stddef.h>
 #include <linux/delay.h>
 
+/*#include <asm/io.h>*/
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Generic gameport layer");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(gameport_register_port);
+EXPORT_SYMBOL(__gameport_register_port);
 EXPORT_SYMBOL(gameport_unregister_port);
-EXPORT_SYMBOL(gameport_register_device);
-EXPORT_SYMBOL(gameport_unregister_device);
+EXPORT_SYMBOL(__gameport_register_driver);
+EXPORT_SYMBOL(gameport_unregister_driver);
 EXPORT_SYMBOL(gameport_open);
 EXPORT_SYMBOL(gameport_close);
 EXPORT_SYMBOL(gameport_rescan);
 EXPORT_SYMBOL(gameport_cooked_read);
+EXPORT_SYMBOL(gameport_set_name);
+EXPORT_SYMBOL(gameport_set_phys);
+EXPORT_SYMBOL(gameport_start_polling);
+EXPORT_SYMBOL(gameport_stop_polling);
+
+/*
+ * gameport_sem protects entire gameport subsystem and is taken
+ * every time gameport port or driver registrered or unregistered.
+ */
+static DECLARE_MUTEX(gameport_sem);
 
 static LIST_HEAD(gameport_list);
-static LIST_HEAD(gameport_dev_list);
 
-#ifdef __i386__
+static struct bus_type gameport_bus = {
+	.name =	"gameport",
+};
+
+static void gameport_add_port(struct gameport *gameport);
+static void gameport_destroy_port(struct gameport *gameport);
+static void gameport_reconnect_port(struct gameport *gameport);
+static void gameport_disconnect_port(struct gameport *gameport);
+
+#if defined(__i386__)
 
 #define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))
 #define GET_TIME(x)     do { x = get_time_pit(); } while (0)
@@ -57,13 +81,15 @@ static unsigned int get_time_pit(void)
 
 #endif
 
+
+
 /*
  * gameport_measure_speed() measures the gameport i/o speed.
  */
 
 static int gameport_measure_speed(struct gameport *gameport)
 {
-#ifdef __i386__
+#if defined(__i386__)
 
 	unsigned int i, t, t1, t2, t3, tx;
 	unsigned long flags;
@@ -76,7 +102,7 @@ static int gameport_measure_speed(struct
 	for(i = 0; i < 50; i++) {
 		local_irq_save(flags);
 		GET_TIME(t1);
-		for(t = 0; t < 50; t++) gameport_read(gameport);
+		for (t = 0; t < 50; t++) gameport_read(gameport);
 		GET_TIME(t2);
 		GET_TIME(t3);
 		local_irq_restore(flags);
@@ -87,10 +113,36 @@ static int gameport_measure_speed(struct
 	gameport_close(gameport);
 	return 59659 / (tx < 1 ? 1 : tx);
 
+#elif defined (__x86_64__)
+
+	unsigned int i, t;
+	unsigned long tx, t1, t2, flags;
+
+	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+		return 0;
+
+	tx = 1 << 30;
+
+	for(i = 0; i < 50; i++) {
+		local_irq_save(flags);
+		rdtscl(t1);
+		for (t = 0; t < 50; t++) gameport_read(gameport);
+		rdtscl(t2);
+		local_irq_restore(flags);
+		udelay(i * 10);
+		if (t2 - t1 < tx) tx = t2 - t1;
+	}
+
+	gameport_close(gameport);
+	return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
+
 #else
 
 	unsigned int j, t = 0;
 
+	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+		return 0;
+
 	j = jiffies; while (j == jiffies);
 	j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
 
@@ -100,81 +152,646 @@ static int gameport_measure_speed(struct
 #endif
 }
 
-static void gameport_find_dev(struct gameport *gameport)
+void gameport_start_polling(struct gameport *gameport)
+{
+	spin_lock(&gameport->timer_lock);
+
+	if (!gameport->poll_cnt++) {
+		BUG_ON(!gameport->poll_handler);
+		BUG_ON(!gameport->poll_interval);
+		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
+	}
+
+	spin_unlock(&gameport->timer_lock);
+}
+
+void gameport_stop_polling(struct gameport *gameport)
+{
+	spin_lock(&gameport->timer_lock);
+
+	if (!--gameport->poll_cnt)
+		del_timer(&gameport->poll_timer);
+
+	spin_unlock(&gameport->timer_lock);
+}
+
+static void gameport_run_poll_handler(unsigned long d)
+{
+	struct gameport *gameport = (struct gameport *)d;
+
+	gameport->poll_handler(gameport);
+	if (gameport->poll_cnt)
+		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
+}
+
+/*
+ * Basic gameport -> driver core mappings
+ */
+
+static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+
+	gameport->dev.driver = &drv->driver;
+	if (drv->connect(gameport, drv)) {
+		gameport->dev.driver = NULL;
+		goto out;
+	}
+	device_bind_driver(&gameport->dev);
+out:
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+static void gameport_release_driver(struct gameport *gameport)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+	device_release_driver(&gameport->dev);
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+static void gameport_find_driver(struct gameport *gameport)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+	device_attach(&gameport->dev);
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+
+/*
+ * Gameport event processing.
+ */
+
+enum gameport_event_type {
+	GAMEPORT_RESCAN,
+	GAMEPORT_RECONNECT,
+	GAMEPORT_REGISTER_PORT,
+	GAMEPORT_REGISTER_DRIVER,
+};
+
+struct gameport_event {
+	enum gameport_event_type type;
+	void *object;
+	struct module *owner;
+	struct list_head node;
+};
+
+static DEFINE_SPINLOCK(gameport_event_lock);	/* protects gameport_event_list */
+static LIST_HEAD(gameport_event_list);
+static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
+static DECLARE_COMPLETION(gameport_exited);
+static int gameport_pid;
+
+static void gameport_queue_event(void *object, struct module *owner,
+			      enum gameport_event_type event_type)
 {
-        struct gameport_dev *dev;
+	unsigned long flags;
+	struct gameport_event *event;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
 
-        list_for_each_entry(dev, &gameport_dev_list, node) {
-		if (gameport->dev)
+	/*
+ 	 * Scan event list for the other events for the same gameport port,
+	 * starting with the most recent one. If event is the same we
+	 * do not need add new one. If event is of different type we
+	 * need to add this event and should not look further because
+	 * we need to preseve sequence of distinct events.
+ 	 */
+	list_for_each_entry_reverse(event, &gameport_event_list, node) {
+		if (event->object == object) {
+			if (event->type == event_type)
+				goto out;
 			break;
-		if (dev->connect)
-                	dev->connect(gameport, dev);
-        }
+		}
+	}
+
+	if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
+		if (!try_module_get(owner)) {
+			printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
+			goto out;
+		}
+
+		event->type = event_type;
+		event->object = object;
+		event->owner = owner;
+
+		list_add_tail(&event->node, &gameport_event_list);
+		wake_up(&gameport_wait);
+	} else {
+		printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);
+	}
+out:
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
 }
 
-void gameport_rescan(struct gameport *gameport)
+static void gameport_free_event(struct gameport_event *event)
 {
-	gameport_close(gameport);
-	gameport_find_dev(gameport);
+	module_put(event->owner);
+	kfree(event);
 }
 
-void gameport_register_port(struct gameport *gameport)
+static void gameport_remove_duplicate_events(struct gameport_event *event)
 {
-	list_add_tail(&gameport->node, &gameport_list);
+	struct list_head *node, *next;
+	struct gameport_event *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_safe(node, next, &gameport_event_list) {
+		e = list_entry(node, struct gameport_event, node);
+		if (event->object == e->object) {
+			/*
+			 * If this event is of different type we should not
+			 * look further - we only suppress duplicate events
+			 * that were sent back-to-back.
+			 */
+			if (event->type != e->type)
+				break;
+
+			list_del_init(node);
+			gameport_free_event(e);
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+}
+
+
+static struct gameport_event *gameport_get_event(void)
+{
+	struct gameport_event *event;
+	struct list_head *node;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	if (list_empty(&gameport_event_list)) {
+		spin_unlock_irqrestore(&gameport_event_lock, flags);
+		return NULL;
+	}
+
+	node = gameport_event_list.next;
+	event = list_entry(node, struct gameport_event, node);
+	list_del_init(node);
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+
+	return event;
+}
+
+static void gameport_handle_events(void)
+{
+	struct gameport_event *event;
+	struct gameport_driver *gameport_drv;
+
+	down(&gameport_sem);
+
+	while ((event = gameport_get_event())) {
+
+		switch (event->type) {
+			case GAMEPORT_REGISTER_PORT:
+				gameport_add_port(event->object);
+				break;
+
+			case GAMEPORT_RECONNECT:
+				gameport_reconnect_port(event->object);
+				break;
+
+			case GAMEPORT_RESCAN:
+				gameport_disconnect_port(event->object);
+				gameport_find_driver(event->object);
+				break;
+
+			case GAMEPORT_REGISTER_DRIVER:
+				gameport_drv = event->object;
+				driver_register(&gameport_drv->driver);
+				break;
+
+			default:
+				break;
+		}
+
+		gameport_remove_duplicate_events(event);
+		gameport_free_event(event);
+	}
+
+	up(&gameport_sem);
+}
+
+/*
+ * Remove all events that have been submitted for a given gameport port.
+ */
+static void gameport_remove_pending_events(struct gameport *gameport)
+{
+	struct list_head *node, *next;
+	struct gameport_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_safe(node, next, &gameport_event_list) {
+		event = list_entry(node, struct gameport_event, node);
+		if (event->object == gameport) {
+			list_del_init(node);
+			gameport_free_event(event);
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+}
+
+/*
+ * Destroy child gameport port (if any) that has not been fully registered yet.
+ *
+ * Note that we rely on the fact that port can have only one child and therefore
+ * only one child registration request can be pending. Additionally, children
+ * are registered by driver's connect() handler so there can't be a grandchild
+ * pending registration together with a child.
+ */
+static struct gameport *gameport_get_pending_child(struct gameport *parent)
+{
+	struct gameport_event *event;
+	struct gameport *gameport, *child = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_entry(event, &gameport_event_list, node) {
+		if (event->type == GAMEPORT_REGISTER_PORT) {
+			gameport = event->object;
+			if (gameport->parent == parent) {
+				child = gameport;
+				break;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+	return child;
+}
+
+static int gameport_thread(void *nothing)
+{
+	lock_kernel();
+	daemonize("kgameportd");
+	allow_signal(SIGTERM);
+
+	do {
+		gameport_handle_events();
+		wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+		try_to_freeze(PF_FREEZE);
+	} while (!signal_pending(current));
+
+	printk(KERN_DEBUG "gameport: kgameportd exiting\n");
+
+	unlock_kernel();
+	complete_and_exit(&gameport_exited, 0);
+}
+
+
+/*
+ * Gameport port operations
+ */
+
+static ssize_t gameport_show_description(struct device *dev, char *buf)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	return sprintf(buf, "%s\n", gameport->name);
+}
+
+static ssize_t gameport_rebind_driver(struct device *dev, const char *buf, size_t count)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct device_driver *drv;
+	int retval;
+
+	retval = down_interruptible(&gameport_sem);
+	if (retval)
+		return retval;
+
+	retval = count;
+	if (!strncmp(buf, "none", count)) {
+		gameport_disconnect_port(gameport);
+	} else if (!strncmp(buf, "reconnect", count)) {
+		gameport_reconnect_port(gameport);
+	} else if (!strncmp(buf, "rescan", count)) {
+		gameport_disconnect_port(gameport);
+		gameport_find_driver(gameport);
+	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
+		gameport_disconnect_port(gameport);
+		gameport_bind_driver(gameport, to_gameport_driver(drv));
+		put_driver(drv);
+	} else {
+		retval = -EINVAL;
+	}
+
+	up(&gameport_sem);
+
+	return retval;
+}
+
+static struct device_attribute gameport_device_attrs[] = {
+	__ATTR(description, S_IRUGO, gameport_show_description, NULL),
+	__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),
+	__ATTR_NULL
+};
+
+static void gameport_release_port(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+
+	kfree(gameport);
+	module_put(THIS_MODULE);
+}
+
+void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);
+	va_end(args);
+}
+
+/*
+ * Prepare gameport port for registration.
+ */
+static void gameport_init_port(struct gameport *gameport)
+{
+	static atomic_t gameport_no = ATOMIC_INIT(0);
+
+	__module_get(THIS_MODULE);
+
+	init_MUTEX(&gameport->drv_sem);
+	device_initialize(&gameport->dev);
+	snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
+		 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+	gameport->dev.bus = &gameport_bus;
+	gameport->dev.release = gameport_release_port;
+	if (gameport->parent)
+		gameport->dev.parent = &gameport->parent->dev;
+
+	spin_lock_init(&gameport->timer_lock);
+	init_timer(&gameport->poll_timer);
+	gameport->poll_timer.function = gameport_run_poll_handler;
+	gameport->poll_timer.data = (unsigned long)gameport;
+}
+
+/*
+ * Complete gameport port registration.
+ * Driver core will attempt to find appropriate driver for the port.
+ */
+static void gameport_add_port(struct gameport *gameport)
+{
+	if (gameport->parent)
+		gameport->parent->child = gameport;
+
 	gameport->speed = gameport_measure_speed(gameport);
-	gameport_find_dev(gameport);
+
+	list_add_tail(&gameport->node, &gameport_list);
+
+	if (gameport->io)
+		printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
+			gameport->name, gameport->phys, gameport->io, gameport->speed);
+	else
+		printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
+			gameport->name, gameport->phys, gameport->speed);
+
+	device_add(&gameport->dev);
+	gameport->registered = 1;
+}
+
+/*
+ * gameport_destroy_port() completes deregistration process and removes
+ * port from the system
+ */
+static void gameport_destroy_port(struct gameport *gameport)
+{
+	struct gameport *child;
+
+	child = gameport_get_pending_child(gameport);
+	if (child) {
+		gameport_remove_pending_events(child);
+		put_device(&child->dev);
+	}
+
+	if (gameport->parent) {
+		gameport->parent->child = NULL;
+		gameport->parent = NULL;
+	}
+
+	if (gameport->registered) {
+		device_del(&gameport->dev);
+		list_del_init(&gameport->node);
+		gameport->registered = 0;
+	}
+
+	gameport_remove_pending_events(gameport);
+	put_device(&gameport->dev);
+}
+
+/*
+ * Reconnect gameport port and all its children (re-initialize attached devices)
+ */
+static void gameport_reconnect_port(struct gameport *gameport)
+{
+	do {
+		if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {
+			gameport_disconnect_port(gameport);
+			gameport_find_driver(gameport);
+			/* Ok, old children are now gone, we are done */
+			break;
+		}
+		gameport = gameport->child;
+	} while (gameport);
+}
+
+/*
+ * gameport_disconnect_port() unbinds a port from its driver. As a side effect
+ * all child ports are unbound and destroyed.
+ */
+static void gameport_disconnect_port(struct gameport *gameport)
+{
+	struct gameport *s, *parent;
+
+	if (gameport->child) {
+		/*
+		 * Children ports should be disconnected and destroyed
+		 * first, staring with the leaf one, since we don't want
+		 * to do recursion
+		 */
+		for (s = gameport; s->child; s = s->child)
+			/* empty */;
+
+		do {
+			parent = s->parent;
+
+			gameport_release_driver(s);
+			gameport_destroy_port(s);
+		} while ((s = parent) != gameport);
+	}
+
+	/*
+	 * Ok, no children left, now disconnect this port
+	 */
+	gameport_release_driver(gameport);
+}
+
+void gameport_rescan(struct gameport *gameport)
+{
+	gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN);
+}
+
+void gameport_reconnect(struct gameport *gameport)
+{
+	gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT);
 }
 
+/*
+ * Submits register request to kgameportd for subsequent execution.
+ * Note that port registration is always asynchronous.
+ */
+void __gameport_register_port(struct gameport *gameport, struct module *owner)
+{
+	gameport_init_port(gameport);
+	gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);
+}
+
+/*
+ * Synchronously unregisters gameport port.
+ */
 void gameport_unregister_port(struct gameport *gameport)
 {
-	list_del_init(&gameport->node);
-	if (gameport->dev && gameport->dev->disconnect)
-		gameport->dev->disconnect(gameport);
+	down(&gameport_sem);
+	gameport_disconnect_port(gameport);
+	gameport_destroy_port(gameport);
+	up(&gameport_sem);
 }
 
-void gameport_register_device(struct gameport_dev *dev)
+
+/*
+ * Gameport driver operations
+ */
+
+static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)
 {
-	struct gameport *gameport;
+	struct gameport_driver *driver = to_gameport_driver(drv);
+	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
+}
+
+static struct driver_attribute gameport_driver_attrs[] = {
+	__ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),
+	__ATTR_NULL
+};
+
+static int gameport_driver_probe(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct gameport_driver *drv = to_gameport_driver(dev->driver);
 
-	list_add_tail(&dev->node, &gameport_dev_list);
-	list_for_each_entry(gameport, &gameport_list, node)
-		if (!gameport->dev && dev->connect)
-			dev->connect(gameport, dev);
+	drv->connect(gameport, drv);
+	return gameport->drv ? 0 : -ENODEV;
 }
 
-void gameport_unregister_device(struct gameport_dev *dev)
+static int gameport_driver_remove(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct gameport_driver *drv = to_gameport_driver(dev->driver);
+
+	drv->disconnect(gameport);
+	return 0;
+}
+
+void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
+{
+	drv->driver.bus = &gameport_bus;
+	drv->driver.probe = gameport_driver_probe;
+	drv->driver.remove = gameport_driver_remove;
+	gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
+}
+
+void gameport_unregister_driver(struct gameport_driver *drv)
 {
 	struct gameport *gameport;
 
-	list_del_init(&dev->node);
+	down(&gameport_sem);
+	drv->ignore = 1;	/* so gameport_find_driver ignores it */
+
+start_over:
 	list_for_each_entry(gameport, &gameport_list, node) {
-		if (gameport->dev == dev && dev->disconnect)
-			dev->disconnect(gameport);
-		gameport_find_dev(gameport);
+		if (gameport->drv == drv) {
+			gameport_disconnect_port(gameport);
+			gameport_find_driver(gameport);
+			/* we could've deleted some ports, restart */
+			goto start_over;
+		}
 	}
+
+	driver_unregister(&drv->driver);
+	up(&gameport_sem);
 }
 
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
+static int gameport_bus_match(struct device *dev, struct device_driver *drv)
 {
+	struct gameport_driver *gameport_drv = to_gameport_driver(drv);
+
+	return !gameport_drv->ignore;
+}
+
+static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
+{
+	down(&gameport->drv_sem);
+	gameport->drv = drv;
+	up(&gameport->drv_sem);
+}
+
+int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
+{
+
 	if (gameport->open) {
-		if (gameport->open(gameport, mode))
+		if (gameport->open(gameport, mode)) {
 			return -1;
+		}
 	} else {
 		if (mode != GAMEPORT_MODE_RAW)
 			return -1;
 	}
 
-	if (gameport->dev)
-		return -1;
-
-	gameport->dev = dev;
-
+	gameport_set_drv(gameport, drv);
 	return 0;
 }
 
 void gameport_close(struct gameport *gameport)
 {
-	gameport->dev = NULL;
+	del_timer_sync(&gameport->poll_timer);
+	gameport->poll_handler = NULL;
+	gameport->poll_interval = 0;
+	gameport_set_drv(gameport, NULL);
 	if (gameport->close)
 		gameport->close(gameport);
 }
+
+static int __init gameport_init(void)
+{
+	if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+		printk(KERN_ERR "gameport: Failed to start kgameportd\n");
+		return -1;
+	}
+
+	gameport_bus.dev_attrs = gameport_device_attrs;
+	gameport_bus.drv_attrs = gameport_driver_attrs;
+	gameport_bus.match = gameport_bus_match;
+	bus_register(&gameport_bus);
+
+	return 0;
+}
+
+static void __exit gameport_exit(void)
+{
+	bus_unregister(&gameport_bus);
+	kill_proc(gameport_pid, SIGTERM, 1);
+	wait_for_completion(&gameport_exited);
+}
+
+module_init(gameport_init);
+module_exit(gameport_exit);
diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
--- a/drivers/input/gameport/lightning.c
+++ b/drivers/input/gameport/lightning.c
@@ -54,12 +54,11 @@ MODULE_DESCRIPTION("PDPI Lightning 4 gam
 MODULE_LICENSE("GPL");
 
 struct l4 {
-	struct gameport gameport;
+	struct gameport *gameport;
 	unsigned char port;
-	char phys[32];
-} *l4_port[8];
+};
 
-char l4_name[] = "PDPI Lightning 4";
+static struct l4 l4_ports[8];
 
 /*
  * l4_wait_ready() waits for the L4 to become ready.
@@ -67,10 +66,10 @@ char l4_name[] = "PDPI Lightning 4";
 
 static int l4_wait_ready(void)
 {
-	unsigned int t;
-	t = L4_TIMEOUT;
+	unsigned int t = L4_TIMEOUT;
+
 	while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
-	return -(t<=0);
+	return -(t <= 0);
 }
 
 /*
@@ -79,7 +78,7 @@ static int l4_wait_ready(void)
 
 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
 	unsigned char status;
 	int i, result = -1;
 
@@ -112,7 +111,8 @@ fail:	outb(L4_SELECT_ANALOG, L4_PORT);
 
 static int l4_open(struct gameport *gameport, int mode)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
+
         if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	outb(L4_SELECT_ANALOG, L4_PORT);
@@ -129,24 +129,29 @@ static int l4_getcal(int port, int *cal)
 
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+	if (inb(L4_PORT) & L4_BUSY)
+		goto out;
 
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
 	outb(L4_CMD_GETCAL, L4_PORT);
+	if (l4_wait_ready())
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
+	if (l4_wait_ready())
+		goto out;
         outb(port & 3, L4_PORT);
 
 	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
+		if (l4_wait_ready())
+			goto out;
 		cal[i] = inb(L4_PORT);
 	}
 
 	result = 0;
 
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+out:	outb(L4_SELECT_ANALOG, L4_PORT);
 	return result;
 }
 
@@ -160,24 +165,29 @@ static int l4_setcal(int port, int *cal)
 
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+	if (inb(L4_PORT) & L4_BUSY)
+		goto out;
 
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
 	outb(L4_CMD_SETCAL, L4_PORT);
+	if (l4_wait_ready())
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
+	if (l4_wait_ready())
+		goto out;
         outb(port & 3, L4_PORT);
 
 	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
+		if (l4_wait_ready())
+			goto out;
 		outb(cal[i], L4_PORT);
 	}
 
 	result = 0;
 
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+out:	outb(L4_SELECT_ANALOG, L4_PORT);
 	return result;
 }
 
@@ -190,7 +200,7 @@ static int l4_calibrate(struct gameport 
 {
 	int i, t;
 	int cal[4];
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
 
 	if (l4_getcal(l4->port, cal))
 		return -1;
@@ -209,73 +219,102 @@ static int l4_calibrate(struct gameport 
 	return 0;
 }
 
-static int __init l4_init(void)
+static int __init l4_create_ports(int card_no)
 {
-	int cal[4] = {255,255,255,255};
-	int i, j, rev, cards = 0;
-	struct gameport *gameport;
 	struct l4 *l4;
+	struct gameport *port;
+	int i, idx;
 
-	if (!request_region(L4_PORT, 1, "lightning"))
-		return -1;
+	for (i = 0; i < 4; i++) {
 
-	for (i = 0; i < 2; i++) {
+		idx = card_no * 4 + i;
+		l4 = &l4_ports[idx];
 
-		outb(L4_SELECT_ANALOG, L4_PORT);
-		outb(L4_SELECT_DIGITAL + i, L4_PORT);
+		if (!(l4->gameport = port = gameport_allocate_port())) {
+			printk(KERN_ERR "lightning: Memory allocation failed\n");
+			while (--i >= 0) {
+				gameport_free_port(l4->gameport);
+				l4->gameport = NULL;
+			}
+			return -ENOMEM;
+		}
+		l4->port = idx;
 
-		if (inb(L4_PORT) & L4_BUSY) continue;
-		outb(L4_CMD_ID, L4_PORT);
+		port->port_data = l4;
+		port->open = l4_open;
+		port->cooked_read = l4_cooked_read;
+		port->calibrate = l4_calibrate;
 
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
+		gameport_set_name(port, "PDPI Lightning 4");
+		gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
 
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_ID) continue;
+		if (idx == 0)
+			port->io = L4_PORT;
+	}
 
-		if (l4_wait_ready()) continue;
-		rev = inb(L4_PORT);
+	return 0;
+}
 
-		if (!rev) continue;
+static int __init l4_add_card(int card_no)
+{
+	int cal[4] = { 255, 255, 255, 255 };
+	int i, rev, result;
+	struct l4 *l4;
 
-		if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
-			printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
-			continue;
-		}
-		memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
 
-		for (j = 0; j < 4; j++) {
+	if (inb(L4_PORT) & L4_BUSY)
+		return -1;
+	outb(L4_CMD_ID, L4_PORT);
 
-			l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
-			l4->port = i * 4 + j;
+	if (l4_wait_ready())
+		return -1;
 
-			sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j);
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
+		return -1;
 
-			gameport = &l4->gameport;
-			gameport->driver = l4;
-			gameport->open = l4_open;
-			gameport->cooked_read = l4_cooked_read;
-			gameport->calibrate = l4_calibrate;
+	if (l4_wait_ready())
+		return -1;
+	if (inb(L4_PORT) != L4_ID)
+		return -1;
 
-			gameport->name = l4_name;
-			gameport->phys = l4->phys;
-			gameport->id.bustype = BUS_ISA;
+	if (l4_wait_ready())
+		return -1;
+	rev = inb(L4_PORT);
 
-			if (!i && !j)
-				gameport->io = L4_PORT;
+	if (!rev)
+		return -1;
 
-			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
-				l4_setcal(l4->port, cal);
+	result = l4_create_ports(card_no);
+	if (result)
+		return result;
 
-			gameport_register_port(gameport);
-		}
+	printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
+		card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
 
-		printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
-			i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
+	for (i = 0; i < 4; i++) {
+		l4 = &l4_ports[card_no * 4 + i];
 
-		cards++;
+		if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
+			l4_setcal(l4->port, cal);
+		gameport_register_port(l4->gameport);
 	}
 
+	return 0;
+}
+
+static int __init l4_init(void)
+{
+	int i, cards = 0;
+
+	if (!request_region(L4_PORT, 1, "lightning"))
+		return -1;
+
+	for (i = 0; i < 2; i++)
+		if (l4_add_card(i) == 0)
+			cards++;
+
 	outb(L4_SELECT_ANALOG, L4_PORT);
 
 	if (!cards) {
@@ -289,13 +328,14 @@ static int __init l4_init(void)
 static void __exit l4_exit(void)
 {
 	int i;
-	int cal[4] = {59, 59, 59, 59};
+	int cal[4] = { 59, 59, 59, 59 };
 
 	for (i = 0; i < 8; i++)
-		if (l4_port[i]) {
-			l4_setcal(l4_port[i]->port, cal);
-			gameport_unregister_port(&l4_port[i]->gameport);
+		if (l4_ports[i].gameport) {
+			l4_setcal(l4_ports[i].port, cal);
+			gameport_unregister_port(l4_ports[i].gameport);
 		}
+
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	release_region(L4_PORT, 1);
 }
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -44,20 +44,16 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@u
 MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
 MODULE_LICENSE("GPL");
 
-#define NS558_ISA	1
-#define NS558_PNP	2
-
 static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
 				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
 
 struct ns558 {
 	int type;
+	int io;
 	int size;
 	struct pnp_dev *dev;
+	struct gameport *gameport;
 	struct list_head node;
-	struct gameport gameport;
-	char phys[32];
-	char name[32];
 };
 
 static LIST_HEAD(ns558_list);
@@ -68,18 +64,19 @@ static LIST_HEAD(ns558_list);
  * A joystick must be attached for this to work.
  */
 
-static void ns558_isa_probe(int io)
+static int ns558_isa_probe(int io)
 {
 	int i, j, b;
 	unsigned char c, u, v;
-	struct ns558 *port;
+	struct ns558 *ns558;
+	struct gameport *port;
 
 /*
  * No one should be using this address.
  */
 
 	if (!request_region(io, 1, "ns558-isa"))
-		return;
+		return -EBUSY;
 
 /*
  * We must not be able to write arbitrary values to the port.
@@ -90,8 +87,8 @@ static void ns558_isa_probe(int io)
 	outb(~c & ~3, io);
 	if (~(u = v = inb(io)) & 3) {
 		outb(c, io);
-		i = 0;
-		goto out;
+		release_region(io, 1);
+		return -ENODEV;
 	}
 /*
  * After a trigger, there must be at least some bits changing.
@@ -101,8 +98,8 @@ static void ns558_isa_probe(int io)
 
 	if (u == v) {
 		outb(c, io);
-		i = 0;
-		goto out;
+		release_region(io, 1);
+		return -ENODEV;
 	}
 	msleep(3);
 /*
@@ -113,8 +110,8 @@ static void ns558_isa_probe(int io)
 	for (i = 0; i < 1000; i++)
 		if ((u ^ inb(io)) & 0xf) {
 			outb(c, io);
-			i = 0;
-			goto out;
+			release_region(io, 1);
+			return -ENODEV;
 		}
 /*
  * And now find the number of mirrors of the port.
@@ -122,17 +119,17 @@ static void ns558_isa_probe(int io)
 
 	for (i = 1; i < 5; i++) {
 
-		release_region(io & (-1 << (i-1)), (1 << (i-1)));
+		release_region(io & (-1 << (i - 1)), (1 << (i - 1)));
 
-		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))	/* Don't disturb anyone */
-			break;
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
+			break;				/* Don't disturb anyone */
 
 		outb(0xff, io & (-1 << i));
 		for (j = b = 0; j < 1000; j++)
 			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
 		msleep(3);
 
-		if (b > 300) {					/* We allow 30% difference */
+		if (b > 300) {				/* We allow 30% difference */
 			release_region(io & (-1 << i), (1 << i));
 			break;
 		}
@@ -142,35 +139,33 @@ static void ns558_isa_probe(int io)
 
 	if (i != 4) {
 		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
-			return;
+			return -EBUSY;
 	}
 
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+	ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!ns558 || !port) {
 		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		goto out;
+		release_region(io & (-1 << i), (1 << i));
+		kfree(ns558);
+		gameport_free_port(port);
+		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct ns558));
 
-	port->type = NS558_ISA;
-	port->size = (1 << i);
-	port->gameport.io = io;
-	port->gameport.phys = port->phys;
-	port->gameport.name = port->name;
-	port->gameport.id.bustype = BUS_ISA;
-
-	sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
-	sprintf(port->name, "NS558 ISA");
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
-	if (port->size > 1) printk(" size %d", port->size);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	list_add(&port->node, &ns558_list);
-	return;
-out:
-	release_region(io & (-1 << i), (1 << i));
+	memset(ns558, 0, sizeof(struct ns558));
+	ns558->io = io;
+	ns558->size = 1 << i;
+	ns558->gameport = port;
+
+	port->io = io;
+	gameport_set_name(port, "NS558 ISA Gameport");
+	gameport_set_phys(port, "isa%04x/gameport0", io & (-1 << i));
+
+	gameport_register_port(port);
+
+	list_add(&ns558->node, &ns558_list);
+
+	return 0;
 }
 
 #ifdef CONFIG_PNP
@@ -206,46 +201,42 @@ MODULE_DEVICE_TABLE(pnp, pnp_devids);
 static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 {
 	int ioport, iolen;
-	struct ns558 *port;
+	struct ns558 *ns558;
+	struct gameport *port;
 
 	if (!pnp_port_valid(dev, 0)) {
 		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
 		return -ENODEV;
 	}
 
-	ioport = pnp_port_start(dev,0);
-	iolen = pnp_port_len(dev,0);
+	ioport = pnp_port_start(dev, 0);
+	iolen = pnp_port_len(dev, 0);
 
 	if (!request_region(ioport, iolen, "ns558-pnp"))
 		return -EBUSY;
 
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "ns558: Memory allocation failed.\n");
+	ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!ns558 || !port) {
+		printk(KERN_ERR "ns558: Memory allocation failed\n");
+		kfree(ns558);
+		gameport_free_port(port);
 		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct ns558));
 
-	port->type = NS558_PNP;
-	port->size = iolen;
-	port->dev = dev;
+	ns558->io = ioport;
+	ns558->size = iolen;
+	ns558->dev = dev;
+	ns558->gameport = port;
+
+	gameport_set_name(port, "NS558 PnP Gameport");
+	gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id);
+	port->dev.parent = &dev->dev;
+	port->io = ioport;
 
-	port->gameport.io = ioport;
-	port->gameport.phys = port->phys;
-	port->gameport.name = port->name;
-	port->gameport.id.bustype = BUS_ISAPNP;
-	port->gameport.id.version = 0x100;
+	gameport_register_port(port);
 
-	sprintf(port->phys, "pnp%s/gameport0", dev->dev.bus_id);
-	sprintf(port->name, "%s", "NS558 PnP Gameport");
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport: NS558 PnP at pnp%s io %#x",
-		dev->dev.bus_id, port->gameport.io);
-	if (iolen > 1) printk(" size %d", iolen);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	list_add_tail(&port->node, &ns558_list);
+	list_add_tail(&ns558->node, &ns558_list);
 	return 0;
 }
 
@@ -261,43 +252,39 @@ static struct pnp_driver ns558_pnp_drive
 
 #endif
 
-int __init ns558_init(void)
+static int pnp_registered = 0;
+
+static int __init ns558_init(void)
 {
 	int i = 0;
 
 /*
- * Probe for ISA ports.
+ * Probe ISA ports first so that PnP gets to choose free port addresses
+ * not occupied by the ISA ports.
  */
 
 	while (ns558_isa_portlist[i])
 		ns558_isa_probe(ns558_isa_portlist[i++]);
 
-	pnp_register_driver(&ns558_pnp_driver);
-	return list_empty(&ns558_list) ? -ENODEV : 0;
-}
+	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+		pnp_registered = 1;
 
-void __exit ns558_exit(void)
-{
-	struct ns558 *port;
 
-	list_for_each_entry(port, &ns558_list, node) {
-		gameport_unregister_port(&port->gameport);
-		switch (port->type) {
+	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
+}
 
-#ifdef CONFIG_PNP
-			case NS558_PNP:
-				/* fall through */
-#endif
-			case NS558_ISA:
-				release_region(port->gameport.io & ~(port->size - 1), port->size);
-				kfree(port);
-				break;
+static void __exit ns558_exit(void)
+{
+	struct ns558 *ns558;
 
-			default:
-				break;
-		}
+	list_for_each_entry(ns558, &ns558_list, node) {
+		gameport_unregister_port(ns558->gameport);
+		release_region(ns558->io & ~(ns558->size - 1), ns558->size);
+		kfree(ns558);
 	}
-	pnp_unregister_driver(&ns558_pnp_driver);
+
+	if (pnp_registered)
+		pnp_unregister_driver(&ns558_pnp_driver);
 }
 
 module_init(ns558_init);
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
--- a/drivers/input/gameport/vortex.c
+++ b/drivers/input/gameport/vortex.c
@@ -53,28 +53,27 @@ MODULE_LICENSE("GPL");
 #define VORTEX_DATA_WAIT	20	/* 20 ms */
 
 struct vortex {
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct pci_dev *dev;
-        unsigned char __iomem *base;
-        unsigned char __iomem *io;
-	char phys[32];
+	unsigned char __iomem *base;
+	unsigned char __iomem *io;
 };
 
 static unsigned char vortex_read(struct gameport *gameport)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	return readb(vortex->io + VORTEX_LEG);
 }
 
 static void vortex_trigger(struct gameport *gameport)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	writeb(0xff, vortex->io + VORTEX_LEG);
 }
 
 static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	int i;
 
 	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
@@ -89,7 +88,7 @@ static int vortex_cooked_read(struct gam
 
 static int vortex_open(struct gameport *gameport, int mode)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -109,30 +108,17 @@ static int vortex_open(struct gameport *
 static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	struct vortex *vortex;
+	struct gameport *port;
 	int i;
 
-	if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
-		return -1;
-        memset(vortex, 0, sizeof(struct vortex));
-
-	vortex->dev = dev;
-	sprintf(vortex->phys, "pci%s/gameport0", pci_name(dev));
-
-	pci_set_drvdata(dev, vortex);
-
-	vortex->gameport.driver = vortex;
-	vortex->gameport.fuzz = 64;
-
-	vortex->gameport.read = vortex_read;
-	vortex->gameport.trigger = vortex_trigger;
-	vortex->gameport.cooked_read = vortex_cooked_read;
-	vortex->gameport.open = vortex_open;
-
-	vortex->gameport.name = pci_name(dev);
-	vortex->gameport.phys = vortex->phys;
-	vortex->gameport.id.bustype = BUS_PCI;
-	vortex->gameport.id.vendor = dev->vendor;
-	vortex->gameport.id.product = dev->device;
+	vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!vortex || !port) {
+		printk(KERN_ERR "vortex: Memory allocation failed.\n");
+		kfree(vortex);
+		gameport_free_port(port);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < 6; i++)
 		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
@@ -140,14 +126,26 @@ static int __devinit vortex_probe(struct
 
 	pci_enable_device(dev);
 
+	vortex->dev = dev;
+	vortex->gameport = port;
 	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
 				pci_resource_len(vortex->dev, i));
 	vortex->io = vortex->base + id->driver_data;
 
-	gameport_register_port(&vortex->gameport);
+	pci_set_drvdata(dev, vortex);
+
+	port->port_data = vortex;
+	port->fuzz = 64;
 
-	printk(KERN_INFO "gameport at pci%s speed %d kHz\n",
-		pci_name(dev), vortex->gameport.speed);
+	gameport_set_name(port, "AU88x0");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
+	port->dev.parent = &dev->dev;
+	port->read = vortex_read;
+	port->trigger = vortex_trigger;
+	port->cooked_read = vortex_cooked_read;
+	port->open = vortex_open;
+
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -155,15 +153,17 @@ static int __devinit vortex_probe(struct
 static void __devexit vortex_remove(struct pci_dev *dev)
 {
 	struct vortex *vortex = pci_get_drvdata(dev);
-	gameport_unregister_port(&vortex->gameport);
+
+	gameport_unregister_port(vortex->gameport);
 	iounmap(vortex->base);
 	kfree(vortex);
 }
 
-static struct pci_device_id vortex_id_table[] =
-{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
- { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
- { 0 }};
+static struct pci_device_id vortex_id_table[] = {
+	{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
+	{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
+	{ 0 }
+};
 
 static struct pci_driver vortex_driver = {
 	.name =		"vortex_gameport",
@@ -172,12 +172,12 @@ static struct pci_driver vortex_driver =
 	.remove =	__devexit_p(vortex_remove),
 };
 
-int __init vortex_init(void)
+static int __init vortex_init(void)
 {
-	return pci_module_init(&vortex_driver);
+	return pci_register_driver(&vortex_driver);
 }
 
-void __exit vortex_exit(void)
+static void __exit vortex_exit(void)
 {
 	pci_unregister_driver(&vortex_driver);
 }
diff --git a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -50,18 +50,10 @@ static struct input_handler *input_table
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_bus_input_dir;
-DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
+static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
 static int input_devices_state;
 #endif
 
-static inline unsigned int ms_to_jiffies(unsigned int ms)
-{
-        unsigned int j;
-        j = (ms * HZ + 500) / 1000;
-        return (j > 0) ? j : 1;
-}
-
-
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct input_handle *handle;
@@ -96,9 +88,9 @@ void input_event(struct input_dev *dev, 
 
 			change_bit(code, dev->key);
 
-			if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->timer.data && value) {
+			if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
 				dev->repeat_key = code;
-				mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_DELAY]));
+				mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
 			}
 
 			break;
@@ -198,7 +190,8 @@ static void input_repeat_key(unsigned lo
 	input_event(dev, EV_KEY, dev->repeat_key, 2);
 	input_sync(dev);
 
-	mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_PERIOD]));
+	if (dev->rep[REP_PERIOD])
+		mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
 }
 
 int input_accept_process(struct input_handle *handle, struct file *file)
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -47,15 +47,15 @@ struct joydev {
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	struct list_head list;
-	struct js_corr corr[ABS_MAX];
+	struct js_corr corr[ABS_MAX + 1];
 	struct JS_DATA_SAVE_TYPE glue;
 	int nabs;
 	int nkey;
-	__u16 keymap[KEY_MAX - BTN_MISC];
-	__u16 keypam[KEY_MAX - BTN_MISC];
-	__u8 absmap[ABS_MAX];
-	__u8 abspam[ABS_MAX];
-	__s16 abs[ABS_MAX];
+	__u16 keymap[KEY_MAX - BTN_MISC + 1];
+	__u16 keypam[KEY_MAX - BTN_MISC + 1];
+	__u8 absmap[ABS_MAX + 1];
+	__u8 abspam[ABS_MAX + 1];
+	__s16 abs[ABS_MAX + 1];
 };
 
 struct joydev_list {
@@ -281,9 +281,8 @@ static unsigned int joydev_poll(struct f
 {
 	struct joydev_list *list = file->private_data;
 	poll_wait(file, &list->joydev->wait, wait);
-	if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? 
+		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -338,7 +337,7 @@ static int joydev_ioctl(struct inode *in
 			return copy_to_user(argp, joydev->corr,
 						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
 		case JSIOCSAXMAP:
-			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * ABS_MAX))
+			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nabs; i++) {
 				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
@@ -347,9 +346,9 @@ static int joydev_ioctl(struct inode *in
 			return 0;
 		case JSIOCGAXMAP:
 			return copy_to_user(argp, joydev->abspam,
-						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
+						sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
 		case JSIOCSBTNMAP:
-			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nkey; i++) {
 				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
@@ -358,7 +357,7 @@ static int joydev_ioctl(struct inode *in
 			return 0;
 		case JSIOCGBTNMAP:
 			return copy_to_user(argp, joydev->keypam,
-						sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
+						sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
 		default:
 			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
 				int len;
@@ -409,14 +408,14 @@ static struct input_handle *joydev_conne
 	joydev->handle.private = joydev;
 	sprintf(joydev->name, "js%d", minor);
 
-	for (i = 0; i < ABS_MAX; i++)
+	for (i = 0; i < ABS_MAX + 1; i++)
 		if (test_bit(i, dev->absbit)) {
 			joydev->absmap[i] = joydev->nabs;
 			joydev->abspam[joydev->nabs] = i;
 			joydev->nabs++;
 		}
 
-	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
+	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++)
 		if (test_bit(i + BTN_MISC, dev->keybit)) {
 			joydev->keymap[i] = joydev->nkey;
 			joydev->keypam[joydev->nkey] = i + BTN_MISC;
@@ -463,14 +462,18 @@ static struct input_handle *joydev_conne
 static void joydev_disconnect(struct input_handle *handle)
 {
 	struct joydev *joydev = handle->private;
+	struct joydev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
 	devfs_remove("input/js%d", joydev->minor);
 	joydev->exist = 0;
 
-	if (joydev->open)
+	if (joydev->open) {
 		input_close_device(handle);
-	else
+		wake_up_interruptible(&joydev->wait);
+		list_for_each_entry(list, &joydev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	} else
 		joydev_free(joydev);
 }
 
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -1,9 +1,8 @@
 #
 # Joystick driver configuration
 #
-config INPUT_JOYSTICK
+menuconfig INPUT_JOYSTICK
 	bool "Joysticks"
-	depends on INPUT
 	help
 	  If you have a joystick, 6dof controller, gamepad, steering wheel,
 	  weapon control system or something like that you can say Y here
@@ -13,9 +12,11 @@ config INPUT_JOYSTICK
 	  Please read the file <file:Documentation/input/joystick.txt> which
 	  contains more information.
 
+if INPUT_JOYSTICK
+
 config JOYSTICK_ANALOG
 	tristate "Classic PC analog joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	---help---
 	  Say Y here if you have a joystick that connects to the PC
 	  gameport. In addition to the usual PC analog joystick, this driver
@@ -32,7 +33,7 @@ config JOYSTICK_ANALOG
 
 config JOYSTICK_A3D
 	tristate "Assasin 3D and MadCatz Panther devices"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have an FPGaming or MadCatz controller using the
 	  A3D protocol over the PC gameport.
@@ -42,7 +43,7 @@ config JOYSTICK_A3D
 
 config JOYSTICK_ADI
 	tristate "Logitech ADI digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Logitech controller using the ADI
 	  protocol over the PC gameport.
@@ -52,7 +53,7 @@ config JOYSTICK_ADI
 
 config JOYSTICK_COBRA
 	tristate "Creative Labs Blaster Cobra gamepad"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Creative Labs Blaster Cobra gamepad.
 
@@ -61,7 +62,7 @@ config JOYSTICK_COBRA
 
 config JOYSTICK_GF2K
 	tristate "Genius Flight2000 Digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Genius Flight2000 or MaxFighter digitally
 	  communicating joystick or gamepad.
@@ -71,7 +72,7 @@ config JOYSTICK_GF2K
 
 config JOYSTICK_GRIP
 	tristate "Gravis GrIP joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Gravis controller using the GrIP protocol
 	  over the PC gameport.
@@ -81,7 +82,7 @@ config JOYSTICK_GRIP
 
 config JOYSTICK_GRIP_MP
 	tristate "Gravis GrIP MultiPort"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have the original Gravis GrIP MultiPort, a hub
 	  that connects to the gameport and you connect gamepads to it.
@@ -91,7 +92,7 @@ config JOYSTICK_GRIP_MP
 
 config JOYSTICK_GUILLEMOT
 	tristate "Guillemot joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Guillemot joystick using a digital
 	  protocol over the PC gameport.
@@ -101,7 +102,7 @@ config JOYSTICK_GUILLEMOT
 
 config JOYSTICK_INTERACT
 	tristate "InterAct digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have an InterAct gameport or joystick
 	  communicating digitally over the gameport.
@@ -111,7 +112,7 @@ config JOYSTICK_INTERACT
 
 config JOYSTICK_SIDEWINDER
 	tristate "Microsoft SideWinder digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Microsoft controller using the Digital
 	  Overdrive protocol over PC gameport.
@@ -121,7 +122,7 @@ config JOYSTICK_SIDEWINDER
 
 config JOYSTICK_TMDC
 	tristate "ThrustMaster DirectConnect joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a ThrustMaster controller using the
 	  DirectConnect (BSP) protocol over the PC gameport.
@@ -133,7 +134,6 @@ source "drivers/input/joystick/iforce/Kc
 
 config JOYSTICK_WARRIOR
 	tristate "Logitech WingMan Warrior joystick"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Logitech WingMan Warrior joystick connected
@@ -144,7 +144,6 @@ config JOYSTICK_WARRIOR
 
 config JOYSTICK_MAGELLAN
 	tristate "LogiCad3d Magellan/SpaceMouse 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Magellan or Space Mouse 6DOF controller
@@ -155,7 +154,6 @@ config JOYSTICK_MAGELLAN
 
 config JOYSTICK_SPACEORB
 	tristate "SpaceTec SpaceOrb/Avenger 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
@@ -166,7 +164,6 @@ config JOYSTICK_SPACEORB
 
 config JOYSTICK_SPACEBALL
 	tristate "SpaceTec SpaceBall 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX
@@ -178,7 +175,6 @@ config JOYSTICK_SPACEBALL
 
 config JOYSTICK_STINGER
 	tristate "Gravis Stinger gamepad"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Gravis Stinger connected to one of your
@@ -187,9 +183,8 @@ config JOYSTICK_STINGER
 	  To compile this driver as a module, choose M here: the
 	  module will be called stinger.
 
-config JOYSTICK_TWIDDLER
+config JOYSTICK_TWIDJOY
 	tristate "Twiddler as a joystick"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Handykey Twiddler connected to your
@@ -200,7 +195,7 @@ config JOYSTICK_TWIDDLER
 
 config JOYSTICK_DB9
 	tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you have a Sega Master System gamepad, Sega Genesis
 	  gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
@@ -213,7 +208,7 @@ config JOYSTICK_DB9
 
 config JOYSTICK_GAMECON
 	tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you have a Nintendo Entertainment System gamepad,
 	  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
@@ -227,7 +222,7 @@ config JOYSTICK_GAMECON
 
 config JOYSTICK_TURBOGRAFX
 	tristate "Multisystem joysticks via TurboGraFX device"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	help
 	  Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
 	  and want to use it with Multisystem -- Atari, Amiga, Commodore,
@@ -239,7 +234,7 @@ config JOYSTICK_TURBOGRAFX
 
 config JOYSTICK_AMIGA
 	tristate "Amiga joysticks"
-	depends on AMIGA && INPUT && INPUT_JOYSTICK
+	depends on AMIGA
 	help
 	  Say Y here if you have an Amiga with a digital joystick connected
 	  to it.
@@ -249,7 +244,7 @@ config JOYSTICK_AMIGA
 
 config JOYSTICK_JOYDUMP
 	tristate "Gameport data dumper"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you want to dump data from your joystick into the system
 	  log for debugging purposes. Say N if you are making a production
@@ -258,3 +253,4 @@ config JOYSTICK_JOYDUMP
 	  To compile this driver as a module, choose M here: the
 	  module will be called joydump.
 
+endif
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -35,38 +35,35 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"FP-Gaming Assasin 3D joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define A3D_MAX_START		400	/* 400 us */
-#define A3D_MAX_STROBE		60	/* 40 us */
-#define A3D_DELAY_READ		3	/* 3 ms */
+#define A3D_MAX_START		600	/* 600 us */
+#define A3D_MAX_STROBE		80	/* 80 us */
 #define A3D_MAX_LENGTH		40	/* 40*3 bits */
-#define A3D_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define A3D_MODE_A3D		1	/* Assassin 3D */
 #define A3D_MODE_PAN		2	/* Panther */
 #define A3D_MODE_OEM		3	/* Panther OEM version */
 #define A3D_MODE_PXL		4	/* Panther XL */
 
-char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
+static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
 			"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
 
 struct a3d {
 	struct gameport *gameport;
-	struct gameport adc;
+	struct gameport *adc;
 	struct input_dev dev;
-	struct timer_list timer;
 	int axes[4];
 	int buttons;
 	int mode;
 	int length;
-	int used;
 	int reads;
 	int bads;
 	char phys[32];
-	char adcphys[32];
 };
 
 /*
@@ -109,7 +106,9 @@ static int a3d_read_packet(struct gamepo
 static int a3d_csum(char *data, int count)
 {
 	int i, csum = 0;
-	for (i = 0; i < count - 2; i++) csum += data[i];
+
+	for (i = 0; i < count - 2; i++)
+		csum += data[i];
 	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
 }
 
@@ -139,7 +138,7 @@ static void a3d_read(struct a3d *a3d, un
 
 			a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
 
-			return;
+			break;
 
 		case A3D_MODE_PXL:
 
@@ -169,24 +168,26 @@ static void a3d_read(struct a3d *a3d, un
 
 			input_sync(dev);
 
-			return;
+			break;
 	}
 }
 
 
 /*
- * a3d_timer() reads and analyzes A3D joystick data.
+ * a3d_poll() reads and analyzes A3D joystick data.
  */
 
-static void a3d_timer(unsigned long private)
+static void a3d_poll(struct gameport *gameport)
 {
-	struct a3d *a3d = (void *) private;
+	struct a3d *a3d = gameport_get_drvdata(gameport);
 	unsigned char data[A3D_MAX_LENGTH];
+
 	a3d->reads++;
-	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
-		|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
-	 	a3d->bads++; else a3d_read(a3d, data);
-	mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
+	    data[0] != a3d->mode || a3d_csum(data, a3d->length))
+	 	a3d->bads++;
+	else
+		a3d_read(a3d, data);
 }
 
 /*
@@ -195,10 +196,11 @@ static void a3d_timer(unsigned long priv
  * call this more than 50 times a second, which would use too much CPU.
  */
 
-int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->port_data;
 	int i;
+
 	for (i = 0; i < 4; i++)
 		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
 	*buttons = a3d->buttons;
@@ -210,13 +212,14 @@ int a3d_adc_cooked_read(struct gameport 
  * any but cooked data.
  */
 
-int a3d_adc_open(struct gameport *gameport, int mode)
+static int a3d_adc_open(struct gameport *gameport, int mode)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->port_data;
+
 	if (mode != GAMEPORT_MODE_COOKED)
 		return -1;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+
+	gameport_start_polling(a3d->gameport);
 	return 0;
 }
 
@@ -226,9 +229,9 @@ int a3d_adc_open(struct gameport *gamepo
 
 static void a3d_adc_close(struct gameport *gameport)
 {
-	struct a3d *a3d = gameport->driver;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
+	struct a3d *a3d = gameport->port_data;
+
+	gameport_stop_polling(a3d->gameport);
 }
 
 /*
@@ -238,8 +241,8 @@ static void a3d_adc_close(struct gamepor
 static int a3d_open(struct input_dev *dev)
 {
 	struct a3d *a3d = dev->private;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+
+	gameport_start_polling(a3d->gameport);
 	return 0;
 }
 
@@ -250,49 +253,53 @@ static int a3d_open(struct input_dev *de
 static void a3d_close(struct input_dev *dev)
 {
 	struct a3d *a3d = dev->private;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
+
+	gameport_stop_polling(a3d->gameport);
 }
 
 /*
  * a3d_connect() probes for A3D joysticks.
  */
 
-static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct a3d *a3d;
+	struct gameport *adc;
 	unsigned char data[A3D_MAX_LENGTH];
 	int i;
+	int err;
 
-	if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
-		return;
-	memset(a3d, 0, sizeof(struct a3d));
-
-	gameport->private = a3d;
+	if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL)))
+		return -ENOMEM;
 
 	a3d->gameport = gameport;
-	init_timer(&a3d->timer);
-	a3d->timer.data = (long) a3d;
-	a3d->timer.function = a3d_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, a3d);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
 
-	if (!i || a3d_csum(data, i))
+	if (!i || a3d_csum(data, i)) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 	a3d->mode = data[0];
 
 	if (!a3d->mode || a3d->mode > 5) {
 		printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
 			"(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, a3d_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(a3d->phys, "%s/input0", gameport->phys);
-	sprintf(a3d->adcphys, "%s/gameport0", gameport->phys);
 
 	if (a3d->mode == A3D_MODE_PXL) {
 
@@ -315,16 +322,11 @@ static void a3d_connect(struct gameport 
 		a3d_read(a3d, data);
 
 		for (i = 0; i < 4; i++) {
-			if (i < 2) {
-				a3d->dev.absmin[axes[i]] = 48;
-				a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
-				a3d->dev.absflat[axes[i]] = 8;
-			} else {
-				a3d->dev.absmin[axes[i]] = 2;
-				a3d->dev.absmax[axes[i]] = 253;
-			}
-			a3d->dev.absmin[ABS_HAT0X + i] = -1;
-			a3d->dev.absmax[ABS_HAT0X + i] = 1;
+			if (i < 2)
+				input_set_abs_params(&a3d->dev, axes[i], 48, a3d->dev.abs[axes[i]] * 2 - 48, 0, 8);
+			else
+				input_set_abs_params(&a3d->dev, axes[i], 2, 253, 0, 0);
+			input_set_abs_params(&a3d->dev, ABS_HAT0X + i, -1, 1, 0, 0);
 		}
 
 	} else {
@@ -336,23 +338,23 @@ static void a3d_connect(struct gameport 
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
 		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
 
-		a3d->adc.driver = a3d;
-		a3d->adc.open = a3d_adc_open;
-		a3d->adc.close = a3d_adc_close;
-		a3d->adc.cooked_read = a3d_adc_cooked_read;
-		a3d->adc.fuzz = 1;
-
-		a3d->adc.name = a3d_names[a3d->mode];
-		a3d->adc.phys = a3d->adcphys;
-		a3d->adc.id.bustype = BUS_GAMEPORT;
-		a3d->adc.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
-		a3d->adc.id.product = a3d->mode;
-		a3d->adc.id.version = 0x0100;
-
 		a3d_read(a3d, data);
 
-		gameport_register_port(&a3d->adc);
-		printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys);
+		if (!(a3d->adc = adc = gameport_allocate_port()))
+			printk(KERN_ERR "a3d: Not enough memory for ADC port\n");
+		else {
+			adc->port_data = a3d;
+			adc->open = a3d_adc_open;
+			adc->close = a3d_adc_close;
+			adc->cooked_read = a3d_adc_cooked_read;
+			adc->fuzz = 1;
+
+			gameport_set_name(adc, a3d_names[a3d->mode]);
+			gameport_set_phys(adc, "%s/gameport0", gameport->phys);
+			adc->dev.parent = &gameport->dev;
+
+			gameport_register_port(adc);
+		}
 	}
 
 	a3d->dev.private = a3d;
@@ -369,36 +371,46 @@ static void a3d_connect(struct gameport 
 	input_register_device(&a3d->dev);
 	printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(a3d);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(a3d);
+	return err;
 }
 
 static void a3d_disconnect(struct gameport *gameport)
 {
+	struct a3d *a3d = gameport_get_drvdata(gameport);
 
-	struct a3d *a3d = gameport->private;
 	input_unregister_device(&a3d->dev);
-	if (a3d->mode < A3D_MODE_PXL)
-		gameport_unregister_port(&a3d->adc);
+	if (a3d->adc) {
+		gameport_unregister_port(a3d->adc);
+		a3d->adc = NULL;
+	}
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(a3d);
 }
 
-static struct gameport_dev a3d_dev = {
-	.connect =	a3d_connect,
-	.disconnect =	a3d_disconnect,
+static struct gameport_driver a3d_drv = {
+	.driver		= {
+		.name	= "adc",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= a3d_connect,
+	.disconnect	= a3d_disconnect,
 };
 
-int __init a3d_init(void)
+static int __init a3d_init(void)
 {
-	gameport_register_device(&a3d_dev);
+	gameport_register_driver(&a3d_drv);
 	return 0;
 }
 
-void __exit a3d_exit(void)
+static void __exit a3d_exit(void)
 {
-	gameport_unregister_device(&a3d_dev);
+	gameport_unregister_driver(&a3d_drv);
 }
 
 module_init(a3d_init);
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -1,7 +1,5 @@
 /*
- * $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *  Copyright (c) 1998-2005 Vojtech Pavlik
  */
 
 /*
@@ -37,8 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/init.h>
 
+#define DRIVER_DESC	"Logitech ADI joystick family driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Logitech ADI joystick family driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -47,7 +47,6 @@ MODULE_LICENSE("GPL");
 
 #define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
 #define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
-#define ADI_REFRESH_TIME	HZ/50	/* How often to poll the joystick [20 ms] */
 #define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
 #define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
 
@@ -57,7 +56,7 @@ MODULE_LICENSE("GPL");
 #define ADI_MIN_ID_LENGTH	66
 #define ADI_MAX_NAME_LENGTH	48
 #define ADI_MAX_CNAME_LENGTH	16
-#define ADI_MAX_PHYS_LENGTH	32
+#define ADI_MAX_PHYS_LENGTH	64
 
 #define ADI_FLAG_HAT		0x04
 #define ADI_FLAG_10BIT		0x08
@@ -127,11 +126,9 @@ struct adi {
 
 struct adi_port {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct adi adi[2];
 	int bad;
 	int reads;
-	int used;
 };
 
 /*
@@ -275,15 +272,15 @@ static int adi_read(struct adi_port *por
 }
 
 /*
- * adi_timer() repeatedly polls the Logitech joysticks.
+ * adi_poll() repeatedly polls the Logitech joysticks.
  */
 
-static void adi_timer(unsigned long data)
+static void adi_poll(struct gameport *gameport)
 {
-	struct adi_port *port = (void *) data;
+	struct adi_port *port = gameport_get_drvdata(gameport);
+
 	port->bad -= adi_read(port);
 	port->reads++;
-	mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
 }
 
 /*
@@ -293,8 +290,8 @@ static void adi_timer(unsigned long data
 static int adi_open(struct input_dev *dev)
 {
 	struct adi_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+
+	gameport_start_polling(port->gameport);
 	return 0;
 }
 
@@ -305,8 +302,8 @@ static int adi_open(struct input_dev *de
 static void adi_close(struct input_dev *dev)
 {
 	struct adi_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
+
+	gameport_stop_polling(port->gameport);
 }
 
 /*
@@ -316,13 +313,16 @@ static void adi_close(struct input_dev *
 
 static void adi_init_digital(struct gameport *gameport)
 {
-	int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
+	int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
 	int i;
 
 	for (i = 0; seq[i]; i++) {
 		gameport_trigger(gameport);
 		if (seq[i] > 0) msleep(seq[i]);
-		if (seq[i] < 0) mdelay(-seq[i]);
+		if (seq[i] < 0) {
+			mdelay(-seq[i]);
+			udelay(-seq[i]*14);	/* It looks like mdelay() is off by approx 1.4% */
+		}
 	}
 }
 
@@ -408,9 +408,9 @@ static void adi_init_input(struct adi *a
 
 	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
 
-	sprintf(buf, adi_names[t], adi->id);
-	sprintf(adi->name, "Logitech %s", buf);
-	sprintf(adi->phys, "%s/input%d", port->gameport->phys, half);
+	snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id);
+	snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf);
+	snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half);
 
 	adi->abs = adi_abs[t];
 	adi->key = adi_key[t];
@@ -439,35 +439,23 @@ static void adi_init_center(struct adi *
 {
 	int i, t, x;
 
-	if (!adi->length) return;
+	if (!adi->length)
+		return;
 
 	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
 
 		t = adi->abs[i];
 		x = adi->dev.abs[t];
 
-		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
-			if (i < adi->axes10) x = 512; else x = 128;
-		}
-
-		if (i < adi->axes10) {
-			adi->dev.absmax[t] = x * 2 - 64;
-			adi->dev.absmin[t] = 64;
-			adi->dev.absfuzz[t] = 2;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
+		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE)
+			x = i < adi->axes10 ? 512 : 128;
 
-		if (i < adi->axes10 + adi->axes8) {
-			adi->dev.absmax[t] = x * 2 - 48;
-			adi->dev.absmin[t] = 48;
-			adi->dev.absfuzz[t] = 1;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
-
-		adi->dev.absmax[t] = 1;
-		adi->dev.absmin[t] = -1;
+		if (i < adi->axes10)
+			input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16);
+		else if (i < adi->axes10 + adi->axes8)
+			input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16);
+		else
+			input_set_abs_params(&adi->dev, t, -1, 1, 0, 0);
 	}
 }
 
@@ -475,25 +463,23 @@ static void adi_init_center(struct adi *
  * adi_connect() probes for Logitech ADI joysticks.
  */
 
-static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct adi_port *port;
 	int i;
+	int err;
 
-	if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct adi_port));
-
-	gameport->private = port;
+	if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
+		return -ENOMEM;
 
 	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = adi_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	gameport_set_drvdata(gameport, port);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err) {
 		kfree(port);
-		return;
+		return err;
 	}
 
 	adi_init_digital(gameport);
@@ -510,9 +496,12 @@ static void adi_connect(struct gameport 
 	if (!port->adi[0].length && !port->adi[1].length) {
 		gameport_close(gameport);
 		kfree(port);
-		return;
+		return -ENODEV;
 	}
 
+	gameport_set_poll_handler(gameport, adi_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	msleep(ADI_INIT_DELAY);
 	if (adi_read(port)) {
 		msleep(ADI_DATA_DELAY);
@@ -526,17 +515,20 @@ static void adi_connect(struct gameport 
 			printk(KERN_INFO "input: %s [%s] on %s\n",
 				port->adi[i].name, port->adi[i].cname, gameport->phys);
 		}
+
+	return 0;
 }
 
 static void adi_disconnect(struct gameport *gameport)
 {
 	int i;
+	struct adi_port *port = gameport_get_drvdata(gameport);
 
-	struct adi_port *port = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (port->adi[i].length > 0)
 			input_unregister_device(&port->adi[i].dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(port);
 }
 
@@ -544,20 +536,24 @@ static void adi_disconnect(struct gamepo
  * The gameport device structure.
  */
 
-static struct gameport_dev adi_dev = {
-	.connect =	adi_connect,
-	.disconnect =	adi_disconnect,
+static struct gameport_driver adi_drv = {
+	.driver		= {
+		.name	= "adi",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= adi_connect,
+	.disconnect	= adi_disconnect,
 };
 
-int __init adi_init(void)
+static int __init adi_init(void)
 {
-	gameport_register_device(&adi_dev);
+	gameport_register_driver(&adi_drv);
 	return 0;
 }
 
-void __exit adi_exit(void)
+static void __exit adi_exit(void)
 {
-	gameport_unregister_device(&adi_dev);
+	gameport_unregister_driver(&adi_drv);
 }
 
 module_init(adi_init);
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -40,8 +40,10 @@
 #include <linux/gameport.h>
 #include <asm/timex.h>
 
+#define DRIVER_DESC	"Analog joystick and gamepad driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Analog joystick and gamepad driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -88,7 +90,6 @@ __obsolete_setup("js=");
 
 #define ANALOG_MAX_TIME		3	/* 3 ms */
 #define ANALOG_LOOP_TIME	2000	/* 2 * loop */
-#define ANALOG_REFRESH_TIME	HZ/100	/* 10 ms */
 #define ANALOG_SAITEK_DELAY	200	/* 200 us */
 #define ANALOG_SAITEK_TIME	2000	/* 2000 us */
 #define ANALOG_AXIS_TIME	2	/* 2 * refresh */
@@ -119,7 +120,6 @@ struct analog {
 
 struct analog_port {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct analog analog[2];
 	unsigned char mask;
 	char saitek;
@@ -132,7 +132,6 @@ struct analog_port {
 	int axes[4];
 	int buttons;
 	int initial[4];
-	int used;
 	int axtime;
 };
 
@@ -305,12 +304,12 @@ static int analog_button_read(struct ana
 }
 
 /*
- * analog_timer() repeatedly polls the Analog joysticks.
+ * analog_poll() repeatedly polls the Analog joysticks.
  */
 
-static void analog_timer(unsigned long data)
+static void analog_poll(struct gameport *gameport)
 {
-	struct analog_port *port = (void *) data;
+	struct analog_port *port = gameport_get_drvdata(gameport);
 	int i;
 
 	char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
@@ -336,8 +335,6 @@ static void analog_timer(unsigned long d
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
-
-	mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
 }
 
 /*
@@ -347,8 +344,8 @@ static void analog_timer(unsigned long d
 static int analog_open(struct input_dev *dev)
 {
 	struct analog_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+
+	gameport_start_polling(port->gameport);
 	return 0;
 }
 
@@ -359,8 +356,8 @@ static int analog_open(struct input_dev 
 static void analog_close(struct input_dev *dev)
 {
 	struct analog_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
+
+	gameport_stop_polling(port->gameport);
 }
 
 /*
@@ -379,7 +376,7 @@ static void analog_calibrate_timer(struc
 #ifdef FAKE_TIME
 	analog_faketime += 830;
 #endif
-	udelay(1000);
+	mdelay(1);
 	GET_TIME(t2);
 	GET_TIME(t3);
 	local_irq_restore(flags);
@@ -587,17 +584,15 @@ static int analog_init_masks(struct anal
 	return -!(analog[0].mask || analog[1].mask);
 }
 
-static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
+static int analog_init_port(struct gameport *gameport, struct gameport_driver *drv, struct analog_port *port)
 {
 	int i, t, u, v;
 
-	gameport->private = port;
 	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = analog_timer;
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	gameport_set_drvdata(gameport, port);
+
+	if (!gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) {
 
 		analog_calibrate_timer(port);
 
@@ -608,7 +603,8 @@ static int analog_init_port(struct gamep
 		port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
 
 		for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
-			if (!analog_cooked_read(port)) break;
+			if (!analog_cooked_read(port))
+				break;
 			msleep(ANALOG_MAX_TIME);
 		}
 
@@ -617,11 +613,13 @@ static int analog_init_port(struct gamep
 		msleep(ANALOG_MAX_TIME);
 		t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
+		while ((gameport_read(port->gameport) & port->mask) && (u < t))
+			u++;
 		udelay(ANALOG_SAITEK_DELAY);
 		t = gameport_time(gameport, ANALOG_SAITEK_TIME);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
+		while ((gameport_read(port->gameport) & port->mask) && (v < t))
+			v++;
 
 		if (v < (u >> 1)) { /* FIXME - more than one port */
 			analog_options[0] |= /* FIXME - more than one port */
@@ -632,59 +630,66 @@ static int analog_init_port(struct gamep
 		gameport_close(gameport);
 	}
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+	if (!gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) {
 
 		for (i = 0; i < ANALOG_INIT_RETRIES; i++)
 			if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
 				break;
 		for (i = 0; i < 4; i++)
-			if (port->axes[i] != -1) port->mask |= 1 << i;
+			if (port->axes[i] != -1)
+				port->mask |= 1 << i;
 
 		port->fuzz = gameport->fuzz;
 		port->cooked = 1;
 		return 0;
 	}
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		return 0;
-
-	return -1;
+	return gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
 }
 
-static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int analog_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct analog_port *port;
 	int i;
+	int err;
 
-	if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct analog_port));
+	if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL)))
+		return - ENOMEM;
 
-	if (analog_init_port(gameport, dev, port)) {
+	err = analog_init_port(gameport, drv, port);
+	if (err) {
 		kfree(port);
-		return;
+		return err;
 	}
 
-	if (analog_init_masks(port)) {
+	err = analog_init_masks(port);
+	if (err) {
 		gameport_close(gameport);
+		gameport_set_drvdata(gameport, NULL);
 		kfree(port);
-		return;
+		return err;
 	}
 
+	gameport_set_poll_handler(gameport, analog_poll);
+	gameport_set_poll_interval(gameport, 10);
+
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			analog_init_device(port, port->analog + i, i);
+
+	return 0;
 }
 
 static void analog_disconnect(struct gameport *gameport)
 {
 	int i;
+	struct analog_port *port = gameport_get_drvdata(gameport);
 
-	struct analog_port *port = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			input_unregister_device(&port->analog[i].dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n",
 		port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
 		port->gameport->phys);
@@ -696,7 +701,7 @@ struct analog_types {
 	int value;
 };
 
-struct analog_types analog_types[] = {
+static struct analog_types analog_types[] = {
 	{ "none",	0x00000000 },
 	{ "auto",	0x000000ff },
 	{ "2btn",	0x0000003f },
@@ -741,21 +746,26 @@ static void analog_parse_options(void)
  * The gameport device structure.
  */
 
-static struct gameport_dev analog_dev = {
-	.connect =	analog_connect,
-	.disconnect =	analog_disconnect,
+static struct gameport_driver analog_drv = {
+	.driver		= {
+		.name	= "analog",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= analog_connect,
+	.disconnect	= analog_disconnect,
 };
 
-int __init analog_init(void)
+static int __init analog_init(void)
 {
 	analog_parse_options();
-	gameport_register_device(&analog_dev);
+	gameport_register_driver(&analog_drv);
+
 	return 0;
 }
 
-void __exit analog_exit(void)
+static void __exit analog_exit(void)
 {
-	gameport_unregister_device(&analog_dev);
+	gameport_unregister_driver(&analog_drv);
 }
 
 module_init(analog_init);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -35,12 +35,13 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Creative Labs Blaster GamePad Cobra driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
-#define COBRA_REFRESH_TIME	HZ/50	/* 20 ms between reads */
 #define COBRA_LENGTH		36
 
 static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
@@ -49,9 +50,7 @@ static int cobra_btn[] = { BTN_START, BT
 
 struct cobra {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
-	int used;
 	int reads;
 	int bads;
 	unsigned char exists;
@@ -112,18 +111,19 @@ static unsigned char cobra_read_packet(s
 	return ret;
 }
 
-static void cobra_timer(unsigned long private)
+static void cobra_poll(struct gameport *gameport)
 {
-	struct cobra *cobra = (void *) private;
+	struct cobra *cobra = gameport_get_drvdata(gameport);
 	struct input_dev *dev;
 	unsigned int data[2];
 	int i, j, r;
 
 	cobra->reads++;
 
-	if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
+	if ((r = cobra_read_packet(gameport, data)) != cobra->exists) {
 		cobra->bads++;
-	else
+		return;
+	}
 
 	for (i = 0; i < 2; i++)
 		if (cobra->exists & r & (1 << i)) {
@@ -139,43 +139,39 @@ static void cobra_timer(unsigned long pr
 			input_sync(dev);
 
 		}
-
-	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
 }
 
 static int cobra_open(struct input_dev *dev)
 {
 	struct cobra *cobra = dev->private;
-	if (!cobra->used++)
-		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+
+	gameport_start_polling(cobra->gameport);
 	return 0;
 }
 
 static void cobra_close(struct input_dev *dev)
 {
 	struct cobra *cobra = dev->private;
-	if (!--cobra->used)
-		del_timer(&cobra->timer);
+
+	gameport_stop_polling(cobra->gameport);
 }
 
-static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct cobra *cobra;
 	unsigned int data[2];
 	int i, j;
+	int err;
 
-	if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
-		return;
-	memset(cobra, 0, sizeof(struct cobra));
-
-	gameport->private = cobra;
+	if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL)))
+		return -ENOMEM;
 
 	cobra->gameport = gameport;
-	init_timer(&cobra->timer);
-	cobra->timer.data = (long) cobra;
-	cobra->timer.function = cobra_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, cobra);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	cobra->exists = cobra_read_packet(gameport, data);
@@ -187,8 +183,13 @@ static void cobra_connect(struct gamepor
 			cobra->exists &= ~(1 << i);
 		}
 
-	if (!cobra->exists)
+	if (!cobra->exists) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, cobra_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & 1) {
@@ -207,49 +208,56 @@ static void cobra_connect(struct gamepor
 			cobra->dev[i].id.version = 0x0100;
 
 			cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-			cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+			input_set_abs_params(&cobra->dev[i], ABS_X, -1, 1, 0, 0);
+			input_set_abs_params(&cobra->dev[i], ABS_Y, -1, 1, 0, 0);
 
 			for (j = 0; cobra_btn[j]; j++)
 				set_bit(cobra_btn[j], cobra->dev[i].keybit);
 
-			cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
-			cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
-
-			input_register_device(cobra->dev + i);
+			input_register_device(&cobra->dev[i]);
 			printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(cobra);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(cobra);
+	return err;
 }
 
 static void cobra_disconnect(struct gameport *gameport)
 {
+	struct cobra *cobra = gameport_get_drvdata(gameport);
 	int i;
 
-	struct cobra *cobra = gameport->private;
 	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & 1)
 			input_unregister_device(cobra->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(cobra);
 }
 
-static struct gameport_dev cobra_dev = {
-	.connect =	cobra_connect,
-	.disconnect =	cobra_disconnect,
+static struct gameport_driver cobra_drv = {
+	.driver		= {
+		.name	= "cobra",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= cobra_connect,
+	.disconnect	= cobra_disconnect,
 };
 
-int __init cobra_init(void)
+static int __init cobra_init(void)
 {
-	gameport_register_device(&cobra_dev);
+	gameport_register_driver(&cobra_drv);
 	return 0;
 }
 
-void __exit cobra_exit(void)
+static void __exit cobra_exit(void)
 {
-	gameport_unregister_device(&cobra_dev);
+	gameport_unregister_driver(&cobra_drv);
 }
 
 module_init(cobra_init);
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -619,7 +619,7 @@ static struct db9 __init *db9_probe(int 
 	return db9;
 }
 
-int __init db9_init(void)
+static int __init db9_init(void)
 {
 	db9_base[0] = db9_probe(db9, db9_nargs);
 	db9_base[1] = db9_probe(db9_2, db9_nargs_2);
@@ -631,7 +631,7 @@ int __init db9_init(void)
 	return -ENODEV;
 }
 
-void __exit db9_exit(void)
+static void __exit db9_exit(void)
 {
 	int i, j;
 
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -227,7 +227,8 @@ static void gc_multi_read_packet(struct 
  */
 
 #define GC_PSX_DELAY	25		/* 25 usec */
-#define GC_PSX_LENGTH	8		/* talk to the controller in bytes */
+#define GC_PSX_LENGTH	8		/* talk to the controller in bits */
+#define GC_PSX_BYTES	6		/* the maximum number of bytes to read off the controller */
 
 #define GC_PSX_MOUSE	1		/* Mouse */
 #define GC_PSX_NEGCON	2		/* NegCon */
@@ -241,7 +242,7 @@ static void gc_multi_read_packet(struct 
 #define GC_PSX_SELECT	0x02		/* Pin 3 */
 
 #define GC_PSX_ID(x)	((x) >> 4)	/* High nibble is device type */
-#define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
+#define GC_PSX_LEN(x)	(((x) & 0xf) << 1)	/* Low nibble is length in bytes/2 */
 
 static int gc_psx_delay = GC_PSX_DELAY;
 module_param_named(psx_delay, gc_psx_delay, uint, 0);
@@ -259,13 +260,13 @@ static short gc_psx_ddr_btn[] = { BTN_0,
  * the psx pad.
  */
 
-static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH])
+static void gc_psx_command(struct gc *gc, int b, unsigned char data[5])
 {
 	int i, j, cmd, read;
 	for (i = 0; i < 5; i++)
 		data[i] = 0;
 
-	for (i = 0; i < 8; i++, b >>= 1) {
+	for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
 		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
 		parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
 		udelay(gc_psx_delay);
@@ -282,7 +283,7 @@ static void gc_psx_command(struct gc *gc
  * device identifier code.
  */
 
-static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5])
+static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_BYTES], unsigned char id[5])
 {
 	int i, j, max_len = 0;
 	unsigned long flags;
@@ -300,10 +301,12 @@ static void gc_psx_read_packet(struct gc
 	gc_psx_command(gc, 0, data2);							/* Dump status */
 
 	for (i =0; i < 5; i++)								/* Find the longest pad */
-		if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && (GC_PSX_LEN(id[i]) > max_len))
+		if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
+			&& (GC_PSX_LEN(id[i]) > max_len)
+			&& (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
 			max_len = GC_PSX_LEN(id[i]);
 
-	for (i = 0; i < max_len * 2; i++) {						/* Read in all the data */
+	for (i = 0; i < max_len; i++) {						/* Read in all the data */
 		gc_psx_command(gc, 0, data2);
 		for (j = 0; j < 5; j++)
 			data[j][i] = data2[j];
@@ -328,7 +331,7 @@ static void gc_timer(unsigned long priva
 	struct gc *gc = (void *) private;
 	struct input_dev *dev = gc->dev;
 	unsigned char data[GC_MAX_LENGTH];
-	unsigned char data_psx[5][GC_PSX_LENGTH];
+	unsigned char data_psx[5][GC_PSX_BYTES];
 	int i, j, s;
 
 /*
@@ -665,7 +668,7 @@ static struct gc __init *gc_probe(int *c
 	return gc;
 }
 
-int __init gc_init(void)
+static int __init gc_init(void)
 {
 	gc_base[0] = gc_probe(gc, gc_nargs);
 	gc_base[1] = gc_probe(gc_2, gc_nargs_2);
@@ -677,7 +680,7 @@ int __init gc_init(void)
 	return -ENODEV;
 }
 
-void __exit gc_exit(void)
+static void __exit gc_exit(void)
 {
 	int i, j;
 
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -36,15 +36,16 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+#define DRIVER_DESC	"Genius Flight 2000 joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Genius Flight 2000 joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GF2K_START		400	/* The time we wait for the first bit [400 us] */
 #define GF2K_STROBE		40	/* The time we wait for the first bit [40 us] */
 #define GF2K_TIMEOUT		4	/* Wait for everything to settle [4 ms] */
 #define GF2K_LENGTH		80	/* Max number of triplets in a packet */
-#define GF2K_REFRESH		HZ/50	/* Time between joystick polls [20 ms] */
 
 /*
  * Genius joystick ids ...
@@ -80,11 +81,9 @@ static short gf2k_seq_digital[] = { 590,
 
 struct gf2k {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev;
 	int reads;
 	int bads;
-	int used;
 	unsigned char id;
 	unsigned char length;
 	char phys[32];
@@ -202,60 +201,56 @@ static void gf2k_read(struct gf2k *gf2k,
 }
 
 /*
- * gf2k_timer() reads and analyzes Genius joystick data.
+ * gf2k_poll() reads and analyzes Genius joystick data.
  */
 
-static void gf2k_timer(unsigned long private)
+static void gf2k_poll(struct gameport *gameport)
 {
-	struct gf2k *gf2k = (void *) private;
+	struct gf2k *gf2k = gameport_get_drvdata(gameport);
 	unsigned char data[GF2K_LENGTH];
 
 	gf2k->reads++;
 
-	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
+	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id])
 		gf2k->bads++;
-	} else gf2k_read(gf2k, data);
-
-	mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+	else
+		gf2k_read(gf2k, data);
 }
 
 static int gf2k_open(struct input_dev *dev)
 {
 	struct gf2k *gf2k = dev->private;
-	if (!gf2k->used++)
-		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+
+	gameport_start_polling(gf2k->gameport);
 	return 0;
 }
 
 static void gf2k_close(struct input_dev *dev)
 {
 	struct gf2k *gf2k = dev->private;
-	if (!--gf2k->used)
-		del_timer(&gf2k->timer);
+
+	gameport_stop_polling(gf2k->gameport);
 }
 
 /*
  * gf2k_connect() probes for Genius id joysticks.
  */
 
-static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct gf2k *gf2k;
 	unsigned char data[GF2K_LENGTH];
-	int i;
-
-	if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
-		return;
-	memset(gf2k, 0, sizeof(struct gf2k));
+	int i, err;
 
-	gameport->private = gf2k;
+	if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL)))
+		return -ENOMEM;
 
 	gf2k->gameport = gameport;
-	init_timer(&gf2k->timer);
-	gf2k->timer.data = (long) gf2k;
-	gf2k->timer.function = gf2k_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, gf2k);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	gf2k_trigger_seq(gameport, gf2k_seq_reset);
@@ -266,16 +261,22 @@ static void gf2k_connect(struct gameport
 
 	msleep(GF2K_TIMEOUT);
 
-	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
+	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
-	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
+	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 #ifdef RESET_WORKS
 	if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
-	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
+	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) {
+		err = -ENODEV;
 		goto fail2;
+	}
 #else
 	gf2k->id = 6;
 #endif
@@ -283,9 +284,13 @@ static void gf2k_connect(struct gameport
 	if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
 		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n",
 			gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, gf2k_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(gf2k->phys, "%s/input0", gameport->phys);
 
 	gf2k->length = gf2k_lens[gf2k->id];
@@ -333,33 +338,42 @@ static void gf2k_connect(struct gameport
 	input_register_device(&gf2k->dev);
 	printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(gf2k);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(gf2k);
+	return err;
 }
 
 static void gf2k_disconnect(struct gameport *gameport)
 {
-	struct gf2k *gf2k = gameport->private;
+	struct gf2k *gf2k = gameport_get_drvdata(gameport);
+
 	input_unregister_device(&gf2k->dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(gf2k);
 }
 
-static struct gameport_dev gf2k_dev = {
-	.connect =	gf2k_connect,
-	.disconnect =	gf2k_disconnect,
+static struct gameport_driver gf2k_drv = {
+	.driver		= {
+		.name	= "gf2k",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= gf2k_connect,
+	.disconnect	= gf2k_disconnect,
 };
 
-int __init gf2k_init(void)
+static int __init gf2k_init(void)
 {
-	gameport_register_device(&gf2k_dev);
+	gameport_register_driver(&gf2k_drv);
 	return 0;
 }
 
-void __exit gf2k_exit(void)
+static void __exit gf2k_exit(void)
 {
-	gameport_unregister_device(&gf2k_dev);
+	gameport_unregister_driver(&gf2k_drv);
 }
 
 module_init(gf2k_init);
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -35,8 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Gravis GrIP protocol joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GRIP_MODE_GPP		1
@@ -51,14 +53,10 @@ MODULE_LICENSE("GPL");
 #define GRIP_MAX_CHUNKS_XT	10
 #define GRIP_MAX_BITS_XT	30
 
-#define GRIP_REFRESH_TIME	HZ/50	/* 20 ms */
-
 struct grip {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
 	unsigned char mode[2];
-	int used;
 	int reads;
 	int bads;
 	char phys[2][32];
@@ -183,9 +181,9 @@ static int grip_xt_read_packet(struct ga
  * grip_timer() repeatedly polls the joysticks and generates events.
  */
 
-static void grip_timer(unsigned long private)
+static void grip_poll(struct gameport *gameport)
 {
-	struct grip *grip = (void*) private;
+	struct grip *grip = gameport_get_drvdata(gameport);
 	unsigned int data[GRIP_LENGTH_XT];
 	struct input_dev *dev;
 	int i, j;
@@ -279,43 +277,39 @@ static void grip_timer(unsigned long pri
 
 		input_sync(dev);
 	}
-
-	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
 }
 
 static int grip_open(struct input_dev *dev)
 {
 	struct grip *grip = dev->private;
-	if (!grip->used++)
-		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+
+	gameport_start_polling(grip->gameport);
 	return 0;
 }
 
 static void grip_close(struct input_dev *dev)
 {
 	struct grip *grip = dev->private;
-	if (!--grip->used)
-		del_timer(&grip->timer);
+
+	gameport_stop_polling(grip->gameport);
 }
 
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct grip *grip;
 	unsigned int data[GRIP_LENGTH_XT];
 	int i, j, t;
+	int err;
 
-	if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
-		return;
-	memset(grip, 0, sizeof(struct grip));
-
-	gameport->private = grip;
+	if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL)))
+		return -ENOMEM;
 
 	grip->gameport = gameport;
-	init_timer(&grip->timer);
-	grip->timer.data = (long) grip;
-	grip->timer.function = grip_timer;
 
-	 if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, grip);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	for (i = 0; i < 2; i++) {
@@ -337,8 +331,13 @@ static void grip_connect(struct gameport
 		}
 	}
 
-	if (!grip->mode[0] && !grip->mode[1])
+	if (!grip->mode[0] && !grip->mode[1]) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, grip_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (i = 0; i < 2; i++)
 		if (grip->mode[i]) {
@@ -361,68 +360,62 @@ static void grip_connect(struct gameport
 
 			for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
 
-				set_bit(t, grip->dev[i].absbit);
-
-				if (j < grip_cen[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 14;
-					grip->dev[i].absmax[t] = 52;
-					grip->dev[i].absfuzz[t] = 1;
-					grip->dev[i].absflat[t] = 2;
-					continue;
-				}
-
-				if (j < grip_anx[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 3;
-					grip->dev[i].absmax[t] = 57;
-					grip->dev[i].absfuzz[t] = 1;
-					continue;
-				}
-
-				grip->dev[i].absmin[t] = -1;
-				grip->dev[i].absmax[t] = 1;
+				if (j < grip_cen[grip->mode[i]])
+					input_set_abs_params(&grip->dev[i], t, 14, 52, 1, 2);
+				else if (j < grip_anx[grip->mode[i]])
+					input_set_abs_params(&grip->dev[i], t, 3, 57, 1, 0);
+				else
+					input_set_abs_params(&grip->dev[i], t, -1, 1, 0, 0);
 			}
 
 			for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
 				if (t > 0)
 					set_bit(t, grip->dev[i].keybit);
 
-			input_register_device(grip->dev + i);
-
 			printk(KERN_INFO "input: %s on %s\n",
 				grip_name[grip->mode[i]], gameport->phys);
+			input_register_device(grip->dev + i);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(grip);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(grip);
+	return err;
 }
 
 static void grip_disconnect(struct gameport *gameport)
 {
+	struct grip *grip = gameport_get_drvdata(gameport);
 	int i;
 
-	struct grip *grip = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (grip->mode[i])
 			input_unregister_device(grip->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(grip);
 }
 
-static struct gameport_dev grip_dev = {
-	.connect =	grip_connect,
-	.disconnect =	grip_disconnect,
+static struct gameport_driver grip_drv = {
+	.driver		= {
+		.name	= "grip",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= grip_connect,
+	.disconnect	= grip_disconnect,
 };
 
-int __init grip_init(void)
+static int __init grip_init(void)
 {
-	gameport_register_device(&grip_dev);
+	gameport_register_driver(&grip_drv);
 	return 0;
 }
 
-void __exit grip_exit(void)
+static void __exit grip_exit(void)
 {
-	gameport_unregister_device(&grip_dev);
+	gameport_unregister_driver(&grip_drv);
 }
 
 module_init(grip_init);
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -20,8 +20,10 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 
+#define DRIVER_DESC	"Gravis Grip Multiport driver"
+
 MODULE_AUTHOR("Brian Bonnlander");
-MODULE_DESCRIPTION("Gravis Grip Multiport driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #ifdef GRIP_DEBUG
@@ -36,11 +38,9 @@ MODULE_LICENSE("GPL");
 
 struct grip_mp {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[4];
 	int mode[4];
 	int registered[4];
-	int used;
 	int reads;
 	int bads;
 
@@ -79,7 +79,6 @@ struct grip_mp {
  */
 
 #define GRIP_INIT_DELAY         2000          /*  2 ms */
-#define GRIP_REFRESH_TIME       HZ/50	      /* 20 ms */
 
 #define GRIP_MODE_NONE		0
 #define GRIP_MODE_RESET         1
@@ -477,9 +476,9 @@ static int multiport_init(struct grip_mp
 	}
 
 	if (dig_mode)
-		dbg("multiport_init(): digital mode achieved.\n");
+		dbg("multiport_init(): digital mode activated.\n");
 	else {
-		dbg("multiport_init(): unable to achieve digital mode.\n");
+		dbg("multiport_init(): unable to activate digital mode.\n");
 		return 0;
 	}
 
@@ -524,8 +523,9 @@ static void report_slot(struct grip_mp *
  * Get the multiport state.
  */
 
-static void get_and_report_mp_state(struct grip_mp *grip)
+static void grip_poll(struct gameport *gameport)
 {
+	struct grip_mp *grip = gameport_get_drvdata(gameport);
 	int i, npkts, flags;
 
 	for (npkts = 0; npkts < 4; npkts++) {
@@ -551,8 +551,8 @@ static void get_and_report_mp_state(stru
 static int grip_open(struct input_dev *dev)
 {
 	struct grip_mp *grip = dev->private;
-	if (!grip->used++)
-		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+
+	gameport_start_polling(grip->gameport);
 	return 0;
 }
 
@@ -563,8 +563,8 @@ static int grip_open(struct input_dev *d
 static void grip_close(struct input_dev *dev)
 {
 	struct grip_mp *grip = dev->private;
-	if (!--grip->used)
-		del_timer(&grip->timer);
+
+	gameport_start_polling(grip->gameport);
 }
 
 /*
@@ -585,11 +585,8 @@ static void register_slot(int slot, stru
 	grip->dev[slot].id.version = 0x0100;
 	grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) {
-		set_bit(t, grip->dev[slot].absbit);
-		grip->dev[slot].absmin[t] = -1;
-		grip->dev[slot].absmax[t] = 1;
-	}
+	for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++)
+		input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0);
 
 	for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++)
 		if (t > 0)
@@ -605,69 +602,75 @@ static void register_slot(int slot, stru
 	       grip_name[grip->mode[slot]], slot);
 }
 
-/*
- * Repeatedly polls the multiport and generates events.
- */
-
-static void grip_timer(unsigned long private)
-{
-	struct grip_mp *grip = (void*) private;
-	get_and_report_mp_state(grip);
-	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
-}
-
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct grip_mp *grip;
+	int err;
+
+	if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (!(grip = kmalloc(sizeof(struct grip_mp), GFP_KERNEL)))
-		return;
-	memset(grip, 0, sizeof(struct grip_mp));
-	gameport->private = grip;
 	grip->gameport = gameport;
-	init_timer(&grip->timer);
-	grip->timer.data = (long) grip;
-	grip->timer.function = grip_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, grip);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
-	if (!multiport_init(grip))
+
+	gameport_set_poll_handler(gameport, grip_poll);
+	gameport_set_poll_interval(gameport, 20);
+
+	if (!multiport_init(grip)) {
+		err = -ENODEV;
 		goto fail2;
-	if (!grip->mode[0] && !grip->mode[1] &&   /* nothing plugged in */
-	    !grip->mode[2] && !grip->mode[3])
+	}
+
+	if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) {
+		/* nothing plugged in */
+		err = -ENODEV;
 		goto fail2;
-	return;
+	}
+
+	return 0;
 
 fail2:	gameport_close(gameport);
-fail1:	kfree(grip);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(grip);
+	return err;
 }
 
 static void grip_disconnect(struct gameport *gameport)
 {
+	struct grip_mp *grip = gameport_get_drvdata(gameport);
 	int i;
 
-	struct grip_mp *grip = gameport->private;
 	for (i = 0; i < 4; i++)
 		if (grip->registered[i])
 			input_unregister_device(grip->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(grip);
 }
 
-static struct gameport_dev grip_dev = {
+static struct gameport_driver grip_drv = {
+	.driver		= {
+		.name	= "grip_mp",
+	},
+	.description	= DRIVER_DESC,
 	.connect	= grip_connect,
 	.disconnect	= grip_disconnect,
 };
 
-static int grip_init(void)
+static int __init grip_init(void)
 {
-	gameport_register_device(&grip_dev);
+	gameport_register_driver(&grip_drv);
 	return 0;
 }
 
-static void grip_exit(void)
+static void __exit grip_exit(void)
 {
-	gameport_unregister_device(&grip_dev);
+	gameport_unregister_driver(&grip_drv);
 }
 
 module_init(grip_init);
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -36,14 +36,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Guillemot Digital joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Guillemot Digital joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GUILLEMOT_MAX_START	600	/* 600 us */
 #define GUILLEMOT_MAX_STROBE	60	/* 60 us */
 #define GUILLEMOT_MAX_LENGTH	17	/* 17 bytes */
-#define GUILLEMOT_REFRESH_TIME	HZ/50	/* 20 ms */
 
 static short guillemot_abs_pad[] =
 	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
@@ -67,8 +68,6 @@ struct guillemot_type {
 struct guillemot {
 	struct gameport *gameport;
 	struct input_dev dev;
-	struct timer_list timer;
-	int used;
 	int bads;
 	int reads;
 	struct guillemot_type *type;
@@ -118,12 +117,12 @@ static int guillemot_read_packet(struct 
 }
 
 /*
- * guillemot_timer() reads and analyzes Guillemot joystick data.
+ * guillemot_poll() reads and analyzes Guillemot joystick data.
  */
 
-static void guillemot_timer(unsigned long private)
+static void guillemot_poll(struct gameport *gameport)
 {
-	struct guillemot *guillemot = (struct guillemot *) private;
+	struct guillemot *guillemot = gameport_get_drvdata(gameport);
 	struct input_dev *dev = &guillemot->dev;
 	u8 data[GUILLEMOT_MAX_LENGTH];
 	int i;
@@ -148,8 +147,6 @@ static void guillemot_timer(unsigned lon
 	}
 
 	input_sync(dev);
-
-	mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
 }
 
 /*
@@ -159,8 +156,8 @@ static void guillemot_timer(unsigned lon
 static int guillemot_open(struct input_dev *dev)
 {
 	struct guillemot *guillemot = dev->private;
-	if (!guillemot->used++)
-		mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
+
+	gameport_start_polling(guillemot->gameport);
 	return 0;
 }
 
@@ -171,38 +168,38 @@ static int guillemot_open(struct input_d
 static void guillemot_close(struct input_dev *dev)
 {
 	struct guillemot *guillemot = dev->private;
-	if (!--guillemot->used)
-		del_timer(&guillemot->timer);
+
+	gameport_stop_polling(guillemot->gameport);
 }
 
 /*
  * guillemot_connect() probes for Guillemot joysticks.
  */
 
-static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct guillemot *guillemot;
 	u8 data[GUILLEMOT_MAX_LENGTH];
 	int i, t;
+	int err;
 
-	if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
-		return;
-	memset(guillemot, 0, sizeof(struct guillemot));
-
-	gameport->private = guillemot;
+	if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL)))
+		return -ENOMEM;
 
 	guillemot->gameport = gameport;
-	init_timer(&guillemot->timer);
-	guillemot->timer.data = (long) guillemot;
-	guillemot->timer.function = guillemot_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, guillemot);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = guillemot_read_packet(gameport, data);
 
-	if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
+	if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 	for (i = 0; guillemot_type[i].name; i++)
 		if (guillemot_type[i].id == data[11])
@@ -211,9 +208,13 @@ static void guillemot_connect(struct gam
 	if (!guillemot_type[i].name) {
 		printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
 			gameport->phys, data[12], data[13], data[11], data[14], data[15]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, guillemot_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(guillemot->phys, "%s/input0", gameport->phys);
 
 	guillemot->type = guillemot_type + i;
@@ -231,19 +232,13 @@ static void guillemot_connect(struct gam
 
 	guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
-		set_bit(t, guillemot->dev.absbit);
-		guillemot->dev.absmin[t] = 0;
-		guillemot->dev.absmax[t] = 255;
-	}
+	for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++)
+		input_set_abs_params(&guillemot->dev, t, 0, 255, 0, 0);
 
-	if (guillemot->type->hat)
-		for (i = 0; i < 2; i++) {
-			t = ABS_HAT0X + i;
-			set_bit(t, guillemot->dev.absbit);
-			guillemot->dev.absmin[t] = -1;
-			guillemot->dev.absmax[t] = 1;
-		}
+	if (guillemot->type->hat) {
+		input_set_abs_params(&guillemot->dev, ABS_HAT0X, -1, 1, 0, 0);
+		input_set_abs_params(&guillemot->dev, ABS_HAT0Y, -1, 1, 0, 0);
+	}
 
 	for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
 		set_bit(t, guillemot->dev.keybit);
@@ -252,34 +247,42 @@ static void guillemot_connect(struct gam
 	printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
 		guillemot->type->name, data[14], data[15], gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(guillemot);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(guillemot);
+	return err;
 }
 
 static void guillemot_disconnect(struct gameport *gameport)
 {
-	struct guillemot *guillemot = gameport->private;
+	struct guillemot *guillemot = gameport_get_drvdata(gameport);
+
 	printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
 	input_unregister_device(&guillemot->dev);
 	gameport_close(gameport);
 	kfree(guillemot);
 }
 
-static struct gameport_dev guillemot_dev = {
-	.connect =	guillemot_connect,
-	.disconnect =	guillemot_disconnect,
+static struct gameport_driver guillemot_drv = {
+	.driver		= {
+		.name	= "guillemot",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= guillemot_connect,
+	.disconnect	= guillemot_disconnect,
 };
 
-int __init guillemot_init(void)
+static int __init guillemot_init(void)
 {
-	gameport_register_device(&guillemot_dev);
+	gameport_register_driver(&guillemot_drv);
 	return 0;
 }
 
-void __exit guillemot_exit(void)
+static void __exit guillemot_exit(void)
 {
-	gameport_unregister_device(&guillemot_dev);
+	gameport_unregister_driver(&guillemot_drv);
 }
 
 module_init(guillemot_init);
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -75,13 +75,15 @@ again:
 
 static void iforce_serio_write_wakeup(struct serio *serio)
 {
-	iforce_serial_xmit((struct iforce *)serio->private);
+	struct iforce *iforce = serio_get_drvdata(serio);
+
+	iforce_serial_xmit(iforce);
 }
 
 static irqreturn_t iforce_serio_irq(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct iforce* iforce = serio->private;
+	struct iforce *iforce = serio_get_drvdata(serio);
 
 	if (!iforce->pkt) {
 		if (data == 0x2b)
@@ -124,45 +126,66 @@ out:
 	return IRQ_HANDLED;
 }
 
-static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
+static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct iforce *iforce;
-	if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
-		return;
+	int err;
+
+	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
 	memset(iforce, 0, sizeof(struct iforce));
 
 	iforce->bus = IFORCE_232;
 	iforce->serio = serio;
-	serio->private = iforce;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, iforce);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(iforce);
-		return;
+		return err;
 	}
 
 	if (iforce_init_device(iforce)) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(iforce);
-		return;
+		return -ENODEV;
 	}
+
+	return 0;
 }
 
 static void iforce_serio_disconnect(struct serio *serio)
 {
-	struct iforce* iforce = serio->private;
+	struct iforce *iforce = serio_get_drvdata(serio);
 
 	input_unregister_device(&iforce->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(iforce);
 }
 
+static struct serio_device_id iforce_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_IFORCE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
+
 struct serio_driver iforce_serio_drv = {
 	.driver		= {
 		.name	= "iforce",
 	},
 	.description	= "RS232 I-Force joysticks and wheels driver",
+	.id_table	= iforce_serio_ids,
 	.write_wakeup	= iforce_serio_write_wakeup,
 	.interrupt	= iforce_serio_irq,
 	.connect	= iforce_serio_connect,
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -39,14 +39,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"InterAct digital joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("InterAct digital joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define INTERACT_MAX_START	400	/* 400 us */
-#define INTERACT_MAX_STROBE	40	/* 40 us */
+#define INTERACT_MAX_START	600	/* 400 us */
+#define INTERACT_MAX_STROBE	60	/* 40 us */
 #define INTERACT_MAX_LENGTH	32	/* 32 bits */
-#define INTERACT_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define INTERACT_TYPE_HHFX	0	/* HammerHead/FX */
 #define INTERACT_TYPE_PP8D	1	/* ProPad 8 */
@@ -54,8 +55,6 @@ MODULE_LICENSE("GPL");
 struct interact {
 	struct gameport *gameport;
 	struct input_dev dev;
-	struct timer_list timer;
-	int used;
 	int bads;
 	int reads;
 	unsigned char type;
@@ -125,12 +124,12 @@ static int interact_read_packet(struct g
 }
 
 /*
- * interact_timer() reads and analyzes InterAct joystick data.
+ * interact_poll() reads and analyzes InterAct joystick data.
  */
 
-static void interact_timer(unsigned long private)
+static void interact_poll(struct gameport *gameport)
 {
-	struct interact *interact = (struct interact *) private;
+	struct interact *interact = gameport_get_drvdata(gameport);
 	struct input_dev *dev = &interact->dev;
 	u32 data[3];
 	int i;
@@ -177,9 +176,6 @@ static void interact_timer(unsigned long
 	}
 
 	input_sync(dev);
-
-	mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
-
 }
 
 /*
@@ -189,8 +185,8 @@ static void interact_timer(unsigned long
 static int interact_open(struct input_dev *dev)
 {
 	struct interact *interact = dev->private;
-	if (!interact->used++)
-		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+
+	gameport_start_polling(interact->gameport);
 	return 0;
 }
 
@@ -201,37 +197,36 @@ static int interact_open(struct input_de
 static void interact_close(struct input_dev *dev)
 {
 	struct interact *interact = dev->private;
-	if (!--interact->used)
-		del_timer(&interact->timer);
+
+	gameport_stop_polling(interact->gameport);
 }
 
 /*
  * interact_connect() probes for InterAct joysticks.
  */
 
-static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int interact_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct interact *interact;
 	__u32 data[3];
 	int i, t;
+	int err;
 
-	if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
-		return;
-	memset(interact, 0, sizeof(struct interact));
-
-	gameport->private = interact;
+	if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL)))
+		return -ENOMEM;
 
 	interact->gameport = gameport;
-	init_timer(&interact->timer);
-	interact->timer.data = (long) interact;
-	interact->timer.function = interact_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, interact);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
 
 	if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
+		err = -ENODEV;
 		goto fail2;
 	}
 
@@ -242,9 +237,13 @@ static void interact_connect(struct game
 	if (!interact_type[i].length) {
 		printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
 			gameport->phys, i, data[0], data[1], data[2]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, interact_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(interact->phys, "%s/input0", gameport->phys);
 
 	interact->type = i;
@@ -281,33 +280,42 @@ static void interact_connect(struct game
 	printk(KERN_INFO "input: %s on %s\n",
 		interact_type[interact->type].name, gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(interact);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(interact);
+	return err;
 }
 
 static void interact_disconnect(struct gameport *gameport)
 {
-	struct interact *interact = gameport->private;
+	struct interact *interact = gameport_get_drvdata(gameport);
+
 	input_unregister_device(&interact->dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(interact);
 }
 
-static struct gameport_dev interact_dev = {
-	.connect =	interact_connect,
-	.disconnect =	interact_disconnect,
+static struct gameport_driver interact_drv = {
+	.driver		= {
+		.name	= "interact",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= interact_connect,
+	.disconnect	= interact_disconnect,
 };
 
-int __init interact_init(void)
+static int __init interact_init(void)
 {
-	gameport_register_device(&interact_dev);
+	gameport_register_driver(&interact_drv);
 	return 0;
 }
 
-void __exit interact_exit(void)
+static void __exit interact_exit(void)
 {
-	gameport_unregister_device(&interact_dev);
+	gameport_unregister_driver(&interact_drv);
 }
 
 module_init(interact_init);
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
--- a/drivers/input/joystick/joydump.c
+++ b/drivers/input/joystick/joydump.c
@@ -35,8 +35,10 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 
+#define DRIVER_DESC	"Gameport data dumper module"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Gameport data dumper module");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define BUF_SIZE 256
@@ -46,38 +48,46 @@ struct joydump {
 	unsigned char data;
 };
 
-static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int joydump_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
-	struct joydump buf[BUF_SIZE];
+	struct joydump *buf;	/* all entries */
+	struct joydump *dump, *prev;	/* one entry each */
 	int axes[4], buttons;
 	int i, j, t, timeout;
 	unsigned long flags;
 	unsigned char u;
 
-	printk(KERN_INFO "joydump: ,------------------- START ------------------.\n");
-	printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys);
-	printk(KERN_INFO "joydump: | Speed: %4d kHz.                            |\n", gameport->speed);
+	printk(KERN_INFO "joydump: ,------------------ START ----------------.\n");
+	printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys);
+	printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed);
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) {
 
 		printk(KERN_INFO "joydump: | Raw mode not available - trying cooked.    |\n");
 
-		if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+		if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) {
 
-			printk(KERN_INFO "joydump: | Cooked not available either. Failing.      |\n");
-			printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
-			return;
+			printk(KERN_INFO "joydump: | Cooked not available either. Failing.   |\n");
+			printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
+			return -ENODEV;
 		}
 
 		gameport_cooked_read(gameport, axes, &buttons);
 
 		for (i = 0; i < 4; i++)
-			printk(KERN_INFO "joydump: | Axis %d: %4d.                              |\n", i, axes[i]);
-		printk(KERN_INFO "joydump: | Buttons %02x.                                |\n", buttons);
-		printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+			printk(KERN_INFO "joydump: | Axis %d: %4d.                           |\n", i, axes[i]);
+		printk(KERN_INFO "joydump: | Buttons %02x.                             |\n", buttons);
+		printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
 	}
 
 	timeout = gameport_time(gameport, 10000); /* 10 ms */
+
+	buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_INFO "joydump: no memory for testing\n");
+		goto jd_end;
+	}
+	dump = buf;
 	t = 0;
 	i = 1;
 
@@ -85,19 +95,21 @@ static void __devinit joydump_connect(st
 
 	u = gameport_read(gameport);
 
-	buf[0].data = u;
-	buf[0].time = t;
+	dump->data = u;
+	dump->time = t;
+	dump++;
 
 	gameport_trigger(gameport);
 
 	while (i < BUF_SIZE && t < timeout) {
 
-		buf[i].data = gameport_read(gameport);
+		dump->data = gameport_read(gameport);
 
-		if (buf[i].data ^ u) {
-			u = buf[i].data;
-			buf[i].time = t;
+		if (dump->data ^ u) {
+			u = dump->data;
+			dump->time = t;
 			i++;
+			dump++;
 		}
 		t++;
 	}
@@ -109,42 +121,54 @@ static void __devinit joydump_connect(st
  */
 
 	t = i;
+	dump = buf;
+	prev = dump;
 
-	printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n");
-	printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0);
+	printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n");
+	printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0);
 	for (j = 7; j >= 0; j--)
-		printk("%d",(buf[0].data >> j) & 1);
+		printk("%d", (dump->data >> j) & 1);
 	printk(" |\n");
-	for (i = 1; i < t; i++) {
+	dump++;
+
+	for (i = 1; i < t; i++, dump++, prev++) {
 		printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
-			i, buf[i].time - buf[i-1].time);
+			i, dump->time - prev->time);
 		for (j = 7; j >= 0; j--)
-			printk("%d",(buf[i].data >> j) & 1);
-		printk("    |\n");
+			printk("%d", (dump->data >> j) & 1);
+		printk(" |\n");
 	}
+	kfree(buf);
+
+jd_end:
+	printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
 
-	printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+	return 0;
 }
 
-static void __devexit joydump_disconnect(struct gameport *gameport)
+static void joydump_disconnect(struct gameport *gameport)
 {
 	gameport_close(gameport);
 }
 
-static struct gameport_dev joydump_dev = {
-	.connect =	joydump_connect,
-	.disconnect =	joydump_disconnect,
+static struct gameport_driver joydump_drv = {
+	.driver		= {
+		.name	= "joydump",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= joydump_connect,
+	.disconnect	= joydump_disconnect,
 };
 
 static int __init joydump_init(void)
 {
-	gameport_register_device(&joydump_dev);
+	gameport_register_driver(&joydump_drv);
 	return 0;
 }
 
 static void __exit joydump_exit(void)
 {
-	gameport_unregister_device(&joydump_dev);
+	gameport_unregister_driver(&joydump_drv);
 }
 
 module_init(joydump_init);
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -118,7 +118,7 @@ static void magellan_process_packet(stru
 static irqreturn_t magellan_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct magellan* magellan = serio->private;
+	struct magellan* magellan = serio_get_drvdata(serio);
 
 	if (data == '\r') {
 		magellan_process_packet(magellan, regs);
@@ -136,28 +136,28 @@ static irqreturn_t magellan_interrupt(st
 
 static void magellan_disconnect(struct serio *serio)
 {
-	struct magellan* magellan = serio->private;
+	struct magellan* magellan = serio_get_drvdata(serio);
+
 	input_unregister_device(&magellan->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(magellan);
 }
 
 /*
  * magellan_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
+ * new serio device that supports Magellan protocol and registers it as
+ * an input device.
  */
 
-static void magellan_connect(struct serio *serio, struct serio_driver *drv)
+static int magellan_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct magellan *magellan;
 	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
-		return;
+	int err;
 
 	if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(magellan, 0, sizeof(struct magellan));
 
@@ -185,28 +185,44 @@ static void magellan_connect(struct seri
 	magellan->dev.id.version = 0x0100;
 	magellan->dev.dev = &serio->dev;
 
-	serio->private = magellan;
+	serio_set_drvdata(serio, magellan);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(magellan);
-		return;
+		return err;
 	}
 
 	input_register_device(&magellan->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
 
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id magellan_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MAGELLAN,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, magellan_serio_ids);
+
 static struct serio_driver magellan_drv = {
 	.driver		= {
 		.name	= "magellan",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= magellan_serio_ids,
 	.interrupt	= magellan_interrupt,
 	.connect	= magellan_connect,
 	.disconnect	= magellan_disconnect,
@@ -216,13 +232,13 @@ static struct serio_driver magellan_drv 
  * The functions for inserting/removing us as a module.
  */
 
-int __init magellan_init(void)
+static int __init magellan_init(void)
 {
 	serio_register_driver(&magellan_drv);
 	return 0;
 }
 
-void __exit magellan_exit(void)
+static void __exit magellan_exit(void)
 {
 	serio_unregister_driver(&magellan_drv);
 }
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -1,7 +1,5 @@
 /*
- * $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *  Copyright (c) 1998-2005 Vojtech Pavlik
  */
 
 /*
@@ -36,8 +34,10 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+#define DRIVER_DESC	"Microsoft SideWinder joystick family driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -45,18 +45,18 @@ MODULE_LICENSE("GPL");
  * as well as break everything.
  */
 
-/* #define SW_DEBUG */
+#undef SW_DEBUG
+#undef SW_DEBUG_DATA
 
-#define SW_START	400	/* The time we wait for the first bit [400 us] */
-#define SW_STROBE	45	/* Max time per bit [45 us] */
-#define SW_TIMEOUT	4000	/* Wait for everything to settle [4 ms] */
+#define SW_START	600	/* The time we wait for the first bit [600 us] */
+#define SW_STROBE	60	/* Max time per bit [60 us] */
+#define SW_TIMEOUT	6	/* Wait for everything to settle [6 ms] */
 #define SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
 #define SW_END		8	/* Number of bits before end of packet to kick */
 #define SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
 #define SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
 #define SW_OK		64	/* Number of packet read successes to switch optimization back on */
 #define SW_LENGTH	512	/* Max number of bits in a packet */
-#define SW_REFRESH	HZ/50	/* Time to wait between updates of joystick data [20 ms] */
 
 #ifdef SW_DEBUG
 #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
@@ -113,7 +113,6 @@ static struct {
 
 struct sw {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[4];
 	char name[64];
 	char phys[4][32];
@@ -125,7 +124,6 @@ struct sw {
 	int ok;
 	int reads;
 	int bads;
-	int used;
 };
 
 /*
@@ -141,7 +139,7 @@ static int sw_read_packet(struct gamepor
 	unsigned char pending, u, v;
 
 	i = -id;						/* Don't care about data, only want ID */
-	timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0;	/* Set up global timeout for ID packet */
+	timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */
 	kick = id ? gameport_time(gameport, SW_KICK) : 0;	/* Set up kick timeout for ID packet */
 	start = gameport_time(gameport, SW_START);
 	strobe = gameport_time(gameport, SW_STROBE);
@@ -160,7 +158,8 @@ static int sw_read_packet(struct gamepor
 		v = gameport_read(gameport);
 	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */
 
-	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */
+	if (bitout > 0)
+		bitout = strobe;				/* Extend time if not timed out */
 
 	while ((timeout > 0 || bitout > 0) && (i < length)) {
 
@@ -194,7 +193,7 @@ static int sw_read_packet(struct gamepor
 
 	local_irq_restore(flags);					/* Done - relax */
 
-#ifdef SW_DEBUG
+#ifdef SW_DEBUG_DATA
 	{
 		int j;
 		printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
@@ -249,7 +248,7 @@ static void sw_init_digital(struct gamep
 	i = 0;
         do {
                 gameport_trigger(gameport);			/* Trigger */
-		t = gameport_time(gameport, SW_TIMEOUT);
+		t = gameport_time(gameport, SW_TIMEOUT * 1000);
 		while ((gameport_read(gameport) & 1) && t) t--;	/* Wait for axis to fall back to 0 */
                 udelay(seq[i]);					/* Delay magic time */
         } while (seq[++i]);
@@ -266,6 +265,7 @@ static void sw_init_digital(struct gamep
 static int sw_parity(__u64 t)
 {
 	int x = t ^ (t >> 32);
+
 	x ^= x >> 16;
 	x ^= x >> 8;
 	x ^= x >> 4;
@@ -307,7 +307,8 @@ static int sw_parse(unsigned char *buf, 
 
 		case SW_ID_3DP:
 
-			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        (GB( 3,3) << 7) | GB(16,7));
 			input_report_abs(dev, ABS_Y,        (GB( 0,3) << 7) | GB(24,7));
@@ -331,7 +332,8 @@ static int sw_parse(unsigned char *buf, 
 
 			for (i = 0; i < sw->number; i ++) {
 
-				if (sw_parity(GB(i*15,15))) return -1;
+				if (sw_parity(GB(i*15,15)))
+					return -1;
 
 				input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
 				input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
@@ -347,7 +349,8 @@ static int sw_parse(unsigned char *buf, 
 		case SW_ID_PP:
 		case SW_ID_FFP:
 
-			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        GB( 9,10));
 			input_report_abs(dev, ABS_Y,        GB(19,10));
@@ -366,7 +369,8 @@ static int sw_parse(unsigned char *buf, 
 
 		case SW_ID_FSP:
 
-			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        GB( 0,10));
 			input_report_abs(dev, ABS_Y,        GB(16,10));
@@ -389,7 +393,8 @@ static int sw_parse(unsigned char *buf, 
 
 		case SW_ID_FFW:
 
-			if (!sw_parity(GB(0,33))) return -1;
+			if (!sw_parity(GB(0,33)))
+				return -1;
 
 			input_report_abs(dev, ABS_RX,       GB( 0,10));
 			input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
@@ -466,19 +471,20 @@ static int sw_read(struct sw *sw)
 		sw->length = 66;
 	}
 
-	if (sw->fail < SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
+	if (sw->fail < SW_FAIL)
+		return -1;							/* Not enough, don't reinitialize yet */
 
 	printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
 		" - reinitializing joystick.\n", sw->gameport->phys);
 
 	if (!i && sw->type == SW_ID_3DP) {					/* 3D Pro can be in analog mode */
-		udelay(3 * SW_TIMEOUT);
+		mdelay(3 * SW_TIMEOUT);
 		sw_init_digital(sw->gameport);
 	}
 
-	udelay(SW_TIMEOUT);
+	mdelay(SW_TIMEOUT);
 	i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);			/* Read normal data packet */
-	udelay(SW_TIMEOUT);
+	mdelay(SW_TIMEOUT);
 	sw_read_packet(sw->gameport, buf, SW_LENGTH, i);			/* Read ID packet, this initializes the stick */
 
 	sw->fail = SW_FAIL;
@@ -486,28 +492,28 @@ static int sw_read(struct sw *sw)
 	return -1;
 }
 
-static void sw_timer(unsigned long private)
+static void sw_poll(struct gameport *gameport)
 {
-	struct sw *sw = (void *) private;
+	struct sw *sw = gameport_get_drvdata(gameport);
 
 	sw->reads++;
-	if (sw_read(sw)) sw->bads++;
-	mod_timer(&sw->timer, jiffies + SW_REFRESH);
+	if (sw_read(sw))
+		sw->bads++;
 }
 
 static int sw_open(struct input_dev *dev)
 {
 	struct sw *sw = dev->private;
-	if (!sw->used++)
-		mod_timer(&sw->timer, jiffies + SW_REFRESH);
+
+	gameport_start_polling(sw->gameport);
 	return 0;
 }
 
 static void sw_close(struct input_dev *dev)
 {
 	struct sw *sw = dev->private;
-	if (!--sw->used)
-		del_timer(&sw->timer);
+
+	gameport_stop_polling(sw->gameport);
 }
 
 /*
@@ -561,7 +567,10 @@ static int sw_guess_mode(unsigned char *
 {
 	int i;
 	unsigned char xor = 0;
-	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+
+	for (i = 1; i < len; i++)
+		xor |= (buf[i - 1] ^ buf[i]) & 6;
+
 	return !!xor * 2 + 1;
 }
 
@@ -569,10 +578,11 @@ static int sw_guess_mode(unsigned char *
  * sw_connect() probes for SideWinder type joysticks.
  */
 
-static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct sw *sw;
 	int i, j, k, l;
+	int err;
 	unsigned char *buf = NULL;	/* [SW_LENGTH] */
 	unsigned char *idbuf = NULL;	/* [SW_LENGTH] */
 	unsigned char m = 1;
@@ -580,50 +590,55 @@ static void sw_connect(struct gameport *
 
 	comment[0] = 0;
 
-	if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
-	memset(sw, 0, sizeof(struct sw));
-
+	sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
 	buf = kmalloc(SW_LENGTH, GFP_KERNEL);
 	idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
-	if (!buf || !idbuf)
+	if (!sw || !buf || !idbuf) {
+		err = -ENOMEM;
 		goto fail1;
-
-	gameport->private = sw;
+	}
 
 	sw->gameport = gameport;
-	init_timer(&sw->timer);
-	sw->timer.data = (long) sw;
-	sw->timer.function = sw_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, sw);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	dbg("Init 0: Opened %s, io %#x, speed %d",
 		gameport->phys, gameport->io, gameport->speed);
 
 	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
-	udelay(SW_TIMEOUT);
+	msleep(SW_TIMEOUT);
 	dbg("Init 1: Mode %d. Length %d.", m , i);
 
 	if (!i) {							/* No data. 3d Pro analog mode? */
 		sw_init_digital(gameport);				/* Switch to digital */
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		dbg("Init 1b: Length %d.", i);
-		if (!i) goto fail2;					/* No data -> FAIL */
+		if (!i) {						/* No data -> FAIL */
+			err = -ENODEV;
+			goto fail2;
+		}
 	}
 
 	j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);		/* Read ID. This initializes the stick */
 	m |= sw_guess_mode(idbuf, j);					/* ID packet should carry mode info [3DP] */
-	dbg("Init 2: Mode %d. ID Length %d.", m , j);
+	dbg("Init 2: Mode %d. ID Length %d.", m, j);
 
-	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
-		udelay(SW_TIMEOUT);
+	if (j <= 0) {							/* Read ID failed. Happens in 1-bit mode on PP */
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
+		m |= sw_guess_mode(buf, i);
 		dbg("Init 2b: Mode %d. Length %d.", m, i);
-		if (!i) goto fail2;
-		udelay(SW_TIMEOUT);
+		if (!i) {
+			err = -ENODEV;
+			goto fail2;
+		}
+		msleep(SW_TIMEOUT);
 		j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);	/* Retry reading ID */
 		dbg("Init 2c: ID Length %d.", j);
 	}
@@ -634,7 +649,7 @@ static void sw_connect(struct gameport *
 
 	do {
 		k--;
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Read data packet */
 		dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
 
@@ -686,13 +701,14 @@ static void sw_connect(struct gameport *
 			}
 		}
 
-	} while (k && (sw->type == -1));
+	} while (k && sw->type == -1);
 
 	if (sw->type == -1) {
 		printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
 			"on %s, contact <vojtech@ucw.cz>\n", gameport->phys);
 		sw_print_packet("ID", j * 3, idbuf, 3);
 		sw_print_packet("Data", i * m, buf, m);
+		err = -ENODEV;
 		goto fail2;
 	}
 
@@ -701,6 +717,9 @@ static void sw_connect(struct gameport *
 	sw_print_packet("Data", i * m, buf, m);
 #endif
 
+	gameport_set_poll_handler(gameport, sw_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	k = i;
 	l = j;
 
@@ -742,38 +761,46 @@ static void sw_connect(struct gameport *
 			sw->name, comment, gameport->phys, m, l, k);
 	}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(sw);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(sw);
 	kfree(buf);
 	kfree(idbuf);
+	return err;
 }
 
 static void sw_disconnect(struct gameport *gameport)
 {
+	struct sw *sw = gameport_get_drvdata(gameport);
 	int i;
 
-	struct sw *sw = gameport->private;
 	for (i = 0; i < sw->number; i++)
 		input_unregister_device(sw->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(sw);
 }
 
-static struct gameport_dev sw_dev = {
-	.connect =	sw_connect,
-	.disconnect =	sw_disconnect,
+static struct gameport_driver sw_drv = {
+	.driver		= {
+		.name	= "sidewinder",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= sw_connect,
+	.disconnect	= sw_disconnect,
 };
 
-int __init sw_init(void)
+static int __init sw_init(void)
 {
-	gameport_register_device(&sw_dev);
+	gameport_register_driver(&sw_drv);
 	return 0;
 }
 
-void __exit sw_exit(void)
+static void __exit sw_exit(void)
 {
-	gameport_unregister_device(&sw_dev);
+	gameport_unregister_driver(&sw_drv);
 }
 
 module_init(sw_init);
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -154,7 +154,7 @@ static void spaceball_process_packet(str
 static irqreturn_t spaceball_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct spaceball *spaceball = serio->private;
+	struct spaceball *spaceball = serio_get_drvdata(serio);
 
 	switch (data) {
 		case 0xd:
@@ -191,31 +191,32 @@ static irqreturn_t spaceball_interrupt(s
 
 static void spaceball_disconnect(struct serio *serio)
 {
-	struct spaceball* spaceball = serio->private;
+	struct spaceball* spaceball = serio_get_drvdata(serio);
+
 	input_unregister_device(&spaceball->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(spaceball);
 }
 
 /*
  * spaceball_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
+ * new serio device that supports Spaceball protocol and registers it as
+ * an input device.
  */
 
-static void spaceball_connect(struct serio *serio, struct serio_driver *drv)
+static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct spaceball *spaceball;
 	int i, t, id;
+	int err;
 
-	if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL))
-		return;
-
-	if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID)
-		return;
+	if ((id = serio->id.id) > SPACEBALL_MAX_ID)
+		return -ENODEV;
 
 	if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
-		return;
+		return - ENOMEM;
+
 	memset(spaceball, 0, sizeof(struct spaceball));
 
 	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
@@ -255,28 +256,45 @@ static void spaceball_connect(struct ser
 	spaceball->dev.id.version = 0x0100;
 	spaceball->dev.dev = &serio->dev;
 
-	serio->private = spaceball;
+	serio_set_drvdata(serio, spaceball);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(spaceball);
-		return;
+		return err;
 	}
 
 	input_register_device(&spaceball->dev);
 
 	printk(KERN_INFO "input: %s on serio%s\n",
 		spaceball_names[id], serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id spaceball_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SPACEBALL,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, spaceball_serio_ids);
+
 static struct serio_driver spaceball_drv = {
 	.driver		= {
 		.name	= "spaceball",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= spaceball_serio_ids,
 	.interrupt	= spaceball_interrupt,
 	.connect	= spaceball_connect,
 	.disconnect	= spaceball_disconnect,
@@ -286,13 +304,13 @@ static struct serio_driver spaceball_drv
  * The functions for inserting/removing us as a module.
  */
 
-int __init spaceball_init(void)
+static int __init spaceball_init(void)
 {
 	serio_register_driver(&spaceball_drv);
 	return 0;
 }
 
-void __exit spaceball_exit(void)
+static void __exit spaceball_exit(void)
 {
 	serio_unregister_driver(&spaceball_drv);
 }
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -116,7 +116,7 @@ static void spaceorb_process_packet(stru
 
 		case 'K':				/* Button data */
 			if (spaceorb->idx != 5) return;
-			for (i = 0; i < 7; i++)
+			for (i = 0; i < 6; i++)
 				input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
 
 			break;
@@ -135,7 +135,7 @@ static void spaceorb_process_packet(stru
 static irqreturn_t spaceorb_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct spaceorb* spaceorb = serio->private;
+	struct spaceorb* spaceorb = serio_get_drvdata(serio);
 
 	if (~data & 0x80) {
 		if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs);
@@ -152,28 +152,29 @@ static irqreturn_t spaceorb_interrupt(st
 
 static void spaceorb_disconnect(struct serio *serio)
 {
-	struct spaceorb* spaceorb = serio->private;
+	struct spaceorb* spaceorb = serio_get_drvdata(serio);
+
 	input_unregister_device(&spaceorb->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(spaceorb);
 }
 
 /*
  * spaceorb_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
+ * new serio device that supports SpaceOrb/Avenger protocol and registers
  * it as an input device.
  */
 
-static void spaceorb_connect(struct serio *serio, struct serio_driver *drv)
+static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct spaceorb *spaceorb;
 	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
-		return;
+	int err;
 
 	if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
+
 	memset(spaceorb, 0, sizeof(struct spaceorb));
 
 	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
@@ -202,25 +203,42 @@ static void spaceorb_connect(struct seri
 	spaceorb->dev.id.version = 0x0100;
 	spaceorb->dev.dev = &serio->dev;
 
-	serio->private = spaceorb;
+	serio_set_drvdata(serio, spaceorb);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(spaceorb);
-		return;
+		return err;
 	}
 
 	input_register_device(&spaceorb->dev);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id spaceorb_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SPACEORB,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, spaceorb_serio_ids);
+
 static struct serio_driver spaceorb_drv = {
 	.driver		= {
 		.name	= "spaceorb",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= spaceorb_serio_ids,
 	.interrupt	= spaceorb_interrupt,
 	.connect	= spaceorb_connect,
 	.disconnect	= spaceorb_disconnect,
@@ -230,13 +248,13 @@ static struct serio_driver spaceorb_drv 
  * The functions for inserting/removing us as a module.
  */
 
-int __init spaceorb_init(void)
+static int __init spaceorb_init(void)
 {
 	serio_register_driver(&spaceorb_drv);
 	return 0;
 }
 
-void __exit spaceorb_exit(void)
+static void __exit spaceorb_exit(void)
 {
 	serio_unregister_driver(&spaceorb_drv);
 }
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -103,7 +103,7 @@ static void stinger_process_packet(struc
 static irqreturn_t stinger_interrupt(struct serio *serio,
 	unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct stinger* stinger = serio->private;
+	struct stinger *stinger = serio_get_drvdata(serio);
 
 	/* All Stinger packets are 4 bytes */
 
@@ -124,28 +124,28 @@ static irqreturn_t stinger_interrupt(str
 
 static void stinger_disconnect(struct serio *serio)
 {
-	struct stinger* stinger = serio->private;
+	struct stinger *stinger = serio_get_drvdata(serio);
+
 	input_unregister_device(&stinger->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(stinger);
 }
 
 /*
  * stinger_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Stinger, and if found, registers
- * it as an input device.
+ * new serio device that supports Stinger protocol and registers it as
+ * an input device.
  */
 
-static void stinger_connect(struct serio *serio, struct serio_driver *drv)
+static int stinger_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct stinger *stinger;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_STINGER))
-		return;
+	int err;
 
 	if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(stinger, 0, sizeof(struct stinger));
 
@@ -173,28 +173,45 @@ static void stinger_connect(struct serio
 	}
 
 	stinger->dev.private = stinger;
-	serio->private = stinger;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, stinger);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(stinger);
-		return;
+		return err;
 	}
 
 	input_register_device(&stinger->dev);
 
 	printk(KERN_INFO "input: %s on %s\n",  stinger_name, serio->phys);
 
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id stinger_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_STINGER,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, stinger_serio_ids);
+
 static struct serio_driver stinger_drv = {
 	.driver		= {
 		.name	= "stinger",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= stinger_serio_ids,
 	.interrupt	= stinger_interrupt,
 	.connect	= stinger_connect,
 	.disconnect	= stinger_disconnect,
@@ -204,13 +221,13 @@ static struct serio_driver stinger_drv =
  * The functions for inserting/removing us as a module.
  */
 
-int __init stinger_init(void)
+static int __init stinger_init(void)
 {
 	serio_register_driver(&stinger_drv);
 	return 0;
 }
 
-void __exit stinger_exit(void)
+static void __exit stinger_exit(void)
 {
 	serio_unregister_driver(&stinger_drv);
 }
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -39,14 +39,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"ThrustMaster DirectConnect joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define TMDC_MAX_START		400	/* 400 us */
-#define TMDC_MAX_STROBE		45	/* 45 us */
+#define TMDC_MAX_START		600	/* 600 us */
+#define TMDC_MAX_STROBE		60	/* 60 us */
 #define TMDC_MAX_LENGTH		13
-#define TMDC_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define TMDC_MODE_M3DI		1
 #define TMDC_MODE_3DRP		3
@@ -92,7 +93,6 @@ static struct {
 
 struct tmdc {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
 	char name[2][64];
 	char phys[2][32];
@@ -102,7 +102,6 @@ struct tmdc {
 	unsigned char absc[2];
 	unsigned char btnc[2][4];
 	unsigned char btno[2][4];
-	int used;
 	int reads;
 	int bads;
 	unsigned char exists;
@@ -158,13 +157,13 @@ static int tmdc_read_packet(struct gamep
 }
 
 /*
- * tmdc_read() reads and analyzes ThrustMaster joystick data.
+ * tmdc_poll() reads and analyzes ThrustMaster joystick data.
  */
 
-static void tmdc_timer(unsigned long private)
+static void tmdc_poll(struct gameport *gameport)
 {
 	unsigned char data[2][TMDC_MAX_LENGTH];
-	struct tmdc *tmdc = (void *) private;
+	struct tmdc *tmdc = gameport_get_drvdata(gameport);
 	struct input_dev *dev;
 	unsigned char r, bad = 0;
 	int i, j, k, l;
@@ -219,32 +218,30 @@ static void tmdc_timer(unsigned long pri
 	}
 
 	tmdc->bads += bad;
-
-	mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
 }
 
 static int tmdc_open(struct input_dev *dev)
 {
 	struct tmdc *tmdc = dev->private;
-	if (!tmdc->used++)
-		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
+
+	gameport_start_polling(tmdc->gameport);
 	return 0;
 }
 
 static void tmdc_close(struct input_dev *dev)
 {
 	struct tmdc *tmdc = dev->private;
-	if (!--tmdc->used)
-		del_timer(&tmdc->timer);
+
+	gameport_stop_polling(tmdc->gameport);
 }
 
 /*
  * tmdc_probe() probes for ThrustMaster type joysticks.
  */
 
-static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
-	struct models {
+	static struct models {
 		unsigned char id;
 		char *name;
 		char abs;
@@ -263,23 +260,26 @@ static void tmdc_connect(struct gameport
 	unsigned char data[2][TMDC_MAX_LENGTH];
 	struct tmdc *tmdc;
 	int i, j, k, l, m;
+	int err;
 
-	if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
-		return;
-	memset(tmdc, 0, sizeof(struct tmdc));
-
-	gameport->private = tmdc;
+	if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL)))
+		return -ENOMEM;
 
 	tmdc->gameport = gameport;
-	init_timer(&tmdc->timer);
-	tmdc->timer.data = (long) tmdc;
-	tmdc->timer.function = tmdc_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, tmdc);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
-	if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
+	if (!(tmdc->exists = tmdc_read_packet(gameport, data))) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, tmdc_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (j = 0; j < 2; j++)
 		if (tmdc->exists & (1 << j)) {
@@ -321,20 +321,13 @@ static void tmdc_connect(struct gameport
 
 			tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
-				if (tmdc->abs[j][i] < 0) continue;
-				set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
-				tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
-				tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
-				tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
-			}
+			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++)
+				if (tmdc->abs[j][i] >= 0)
+					input_set_abs_params(&tmdc->dev[j], tmdc->abs[j][i], 8, 248, 2, 4);
+
+			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++)
+				input_set_abs_params(&tmdc->dev[j], tmdc_abs_hat[i], -1, 1, 0, 0);
 
-			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
-				set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
-				tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
-			}
 
 			for (k = l = 0; k < 4; k++) {
 				for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
@@ -346,36 +339,45 @@ static void tmdc_connect(struct gameport
 			printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(tmdc);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(tmdc);
+	return err;
 }
 
 static void tmdc_disconnect(struct gameport *gameport)
 {
-	struct tmdc *tmdc = gameport->private;
+	struct tmdc *tmdc = gameport_get_drvdata(gameport);
 	int i;
+
 	for (i = 0; i < 2; i++)
 		if (tmdc->exists & (1 << i))
 			input_unregister_device(tmdc->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(tmdc);
 }
 
-static struct gameport_dev tmdc_dev = {
-	.connect =	tmdc_connect,
-	.disconnect =	tmdc_disconnect,
+static struct gameport_driver tmdc_drv = {
+	.driver		= {
+		.name	= "tmdc",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= tmdc_connect,
+	.disconnect	= tmdc_disconnect,
 };
 
-int __init tmdc_init(void)
+static int __init tmdc_init(void)
 {
-	gameport_register_device(&tmdc_dev);
+	gameport_register_driver(&tmdc_drv);
 	return 0;
 }
 
-void __exit tmdc_exit(void)
+static void __exit tmdc_exit(void)
 {
-	gameport_unregister_device(&tmdc_dev);
+	gameport_unregister_driver(&tmdc_drv);
 }
 
 module_init(tmdc_init);
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -77,7 +77,7 @@ __obsolete_setup("tgfx_3=");
 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
 static char *tgfx_name = "TurboGraFX Multisystem joystick";
 
-struct tgfx {
+static struct tgfx {
 	struct pardevice *pd;
 	struct timer_list timer;
 	struct input_dev dev[7];
@@ -229,7 +229,7 @@ static struct tgfx __init *tgfx_probe(in
 	return tgfx;
 }
 
-int __init tgfx_init(void)
+static int __init tgfx_init(void)
 {
 	tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs);
 	tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2);
@@ -241,7 +241,7 @@ int __init tgfx_init(void)
 	return -ENODEV;
 }
 
-void __exit tgfx_exit(void)
+static void __exit tgfx_exit(void)
 {
 	int i, j;
 
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -58,7 +58,9 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
-MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
+#define DRIVER_DESC	"Handykey Twiddler keyboard as a joystick driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -147,7 +149,7 @@ static void twidjoy_process_packet(struc
 
 static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct twidjoy *twidjoy = serio->private;
+	struct twidjoy *twidjoy = serio_get_drvdata(serio);
 
 	/* All Twiddler packets are 5 bytes. The fact that the first byte
 	 * has a MSB of 0 and all other bytes have a MSB of 1 can be used
@@ -175,9 +177,11 @@ static irqreturn_t twidjoy_interrupt(str
 
 static void twidjoy_disconnect(struct serio *serio)
 {
-	struct twidjoy *twidjoy = serio->private;
+	struct twidjoy *twidjoy = serio_get_drvdata(serio);
+
 	input_unregister_device(&twidjoy->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(twidjoy);
 }
 
@@ -187,17 +191,15 @@ static void twidjoy_disconnect(struct se
  * it as an input device.
  */
 
-static void twidjoy_connect(struct serio *serio, struct serio_driver *drv)
+static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct twidjoy_button_spec *bp;
 	struct twidjoy *twidjoy;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY))
-		return;
+	int err;
 
 	if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(twidjoy, 0, sizeof(struct twidjoy));
 
@@ -231,27 +233,45 @@ static void twidjoy_connect(struct serio
 	}
 
 	twidjoy->dev.private = twidjoy;
-	serio->private = twidjoy;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, twidjoy);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(twidjoy);
-		return;
+		return err;
 	}
 
 	input_register_device(&twidjoy->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id twidjoy_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TWIDJOY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, twidjoy_serio_ids);
+
 static struct serio_driver twidjoy_drv = {
 	.driver		= {
 		.name	= "twidjoy",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= twidjoy_serio_ids,
 	.interrupt	= twidjoy_interrupt,
 	.connect	= twidjoy_connect,
 	.disconnect	= twidjoy_disconnect,
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -104,7 +104,7 @@ static void warrior_process_packet(struc
 static irqreturn_t warrior_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct warrior* warrior = serio->private;
+	struct warrior *warrior = serio_get_drvdata(serio);
 
 	if (data & 0x80) {
 		if (warrior->idx) warrior_process_packet(warrior, regs);
@@ -129,9 +129,11 @@ static irqreturn_t warrior_interrupt(str
 
 static void warrior_disconnect(struct serio *serio)
 {
-	struct warrior* warrior = serio->private;
+	struct warrior *warrior = serio_get_drvdata(serio);
+
 	input_unregister_device(&warrior->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(warrior);
 }
 
@@ -141,16 +143,14 @@ static void warrior_disconnect(struct se
  * it as an input device.
  */
 
-static void warrior_connect(struct serio *serio, struct serio_driver *drv)
+static int warrior_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct warrior *warrior;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
-		return;
+	int err;
 
 	if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(warrior, 0, sizeof(struct warrior));
 
@@ -186,27 +186,44 @@ static void warrior_connect(struct serio
 
 	warrior->dev.private = warrior;
 
-	serio->private = warrior;
+	serio_set_drvdata(serio, warrior);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(warrior);
-		return;
+		return err;
 	}
 
 	input_register_device(&warrior->dev);
 
 	printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id warrior_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_WARRIOR,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, warrior_serio_ids);
+
 static struct serio_driver warrior_drv = {
 	.driver		= {
 		.name	= "warrior",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= warrior_serio_ids,
 	.interrupt	= warrior_interrupt,
 	.connect	= warrior_connect,
 	.disconnect	= warrior_disconnect,
@@ -216,13 +233,13 @@ static struct serio_driver warrior_drv =
  * The functions for inserting/removing us as a module.
  */
 
-int __init warrior_init(void)
+static int __init warrior_init(void)
 {
 	serio_register_driver(&warrior_drv);
 	return 0;
 }
 
-void __exit warrior_exit(void)
+static void __exit warrior_exit(void)
 {
 	serio_unregister_driver(&warrior_drv);
 }
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -1,20 +1,20 @@
 #
 # Input core configuration
 #
-config INPUT_KEYBOARD
+menuconfig INPUT_KEYBOARD
 	bool "Keyboards" if EMBEDDED || !X86
 	default y
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported keyboards will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_KEYBOARD
+
 config KEYBOARD_ATKBD
-	tristate "AT keyboard support" if !PC
+	tristate "AT keyboard" if !PC
 	default y
-	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
@@ -30,9 +30,46 @@ config KEYBOARD_ATKBD
 	  To compile this driver as a module, choose M here: the
 	  module will be called atkbd.
 
+config KEYBOARD_ATKBD_HP_KEYCODES
+	bool "Use HP keyboard scancodes"
+	depends on PARISC && KEYBOARD_ATKBD
+	default y
+	help
+	  Say Y here if you have a PA-RISC machine and want to use an AT or
+	  PS/2 keyboard, and your keyboard uses keycodes that are specific to
+	  PA-RISC keyboards.
+
+	  Say N if you use a standard keyboard.
+
+config KEYBOARD_ATKBD_RDI_KEYCODES
+	bool "Use PrecisionBook keyboard scancodes"
+	depends on KEYBOARD_ATKBD_HP_KEYCODES
+	default n
+	help
+	  If you have an RDI PrecisionBook, say Y here if you want to use its
+	  built-in keyboard (as opposed to an external keyboard).
+
+	  The PrecisionBook has five keys that conflict with those used by most
+	  AT and PS/2 keyboards. These are as follows:
+
+	    PrecisionBook    Standard AT or PS/2
+
+	    F1               F12
+	    Left Ctrl        Left Alt
+	    Caps Lock        Left Ctrl
+	    Right Ctrl       Caps Lock
+	    Left             102nd key (the key to the right of Left Shift)
+
+	  If you say N here, and use the PrecisionBook keyboard, then each key
+	  in the left-hand column will be interpreted as the corresponding key
+	  in the right-hand column.
+
+	  If you say Y here, and use an external keyboard, then each key in the
+	  right-hand column will be interpreted as the key shown in the
+	  left-hand column.
+
 config KEYBOARD_SUNKBD
-	tristate "Sun Type 4 and Type 5 keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "Sun Type 4 and Type 5 keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
@@ -43,8 +80,7 @@ config KEYBOARD_SUNKBD
 	  module will be called sunkbd.
 
 config KEYBOARD_LKKBD
-	tristate "DECstation/VAXstation LK201/LK401 keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "DECstation/VAXstation LK201/LK401 keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use a LK201 or LK401 style serial
@@ -55,9 +91,17 @@ config KEYBOARD_LKKBD
 	  To compile this driver as a module, choose M here: the
 	  module will be called lkkbd.
 
+config KEYBOARD_LOCOMO
+	tristate "LoCoMo Keyboard Support"
+	depends on SHARP_LOCOMO
+	help
+	  Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called locomokbd.
+
 config KEYBOARD_XTKBD
-	tristate "XT Keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "XT keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use the old IBM PC/XT keyboard (or
@@ -70,7 +114,6 @@ config KEYBOARD_XTKBD
 
 config KEYBOARD_NEWTON
 	tristate "Newton keyboard"
-	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	help
 	  Say Y here if you have a Newton keyboard on a serial port.
@@ -78,9 +121,20 @@ config KEYBOARD_NEWTON
 	  To compile this driver as a module, choose M here: the
 	  module will be called newtonkbd.
 
+config KEYBOARD_CORGI
+	tristate "Corgi keyboard"
+	depends on PXA_SHARPSL
+	default y	
+	help
+	  Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx 
+	  series of PDAs.
+
+	  To compile this driver as a module, choose M here: the 
+	  module will be called corgikbd.
+
 config KEYBOARD_MAPLE
-	tristate "Maple bus keyboard support"
-	depends on SH_DREAMCAST && INPUT && INPUT_KEYBOARD && MAPLE
+	tristate "Maple bus keyboard"
+	depends on SH_DREAMCAST && MAPLE
 	help
 	  Say Y here if you have a DreamCast console running Linux and have
 	  a keyboard attached to its Maple bus.
@@ -90,10 +144,42 @@ config KEYBOARD_MAPLE
 
 config KEYBOARD_AMIGA
 	tristate "Amiga keyboard"
-	depends on AMIGA && INPUT && INPUT_KEYBOARD
+	depends on AMIGA
 	help
 	  Say Y here if you are running Linux on any AMIGA and have a keyboard
 	  attached.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
+
+config KEYBOARD_HIL_OLD
+	tristate "HP HIL keyboard support (simple driver)"
+	depends on GSC
+	default y
+	help
+	  The "Human Interface Loop" is a older, 8-channel USB-like
+	  controller used in several Hewlett Packard models. This driver
+	  was adapted from the one written for m68k/hp300, and implements
+	  support for a keyboard attached to the HIL port, but not for
+	  any other types of HIL input devices like mice or tablets.
+	  However, it has been thoroughly tested and is stable.
+
+	  If you want full HIL support including support for multiple
+	  keyboards, mices and tablets, you have to enable the
+	  "HP System Device Controller i8042 Support" in the input/serio
+	  submenu.
+
+config KEYBOARD_HIL
+	tristate "HP HIL keyboard support"
+	depends on GSC
+	default y
+	select HP_SDC
+	select HIL_MLC
+	select SERIO
+	help
+	  The "Human Interface Loop" is a older, 8-channel USB-like
+	  controller used in several Hewlett Packard models.
+	  This driver implements support for HIL-keyboards attached
+	  to your machine, so normally you should say Y here.
+
+endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -10,5 +10,10 @@ obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd
 obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
+obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_98KBD)		+= 98kbd.o
+obj-$(CONFIG_KEYBOARD_CORGI)		+= corgikbd.o
+obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
+obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
+
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -54,7 +54,7 @@ static int atkbd_softraw = 1;
 module_param_named(softraw, atkbd_softraw, bool, 0);
 MODULE_PARM_DESC(softraw, "Use software generated rawmode");
 
-static int atkbd_scroll;
+static int atkbd_scroll = 0;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
 
@@ -71,12 +71,15 @@ __obsolete_setup("atkbd_softrepeat=");
  * are loadable via an userland utility.
  */
 
-#if defined(__hppa__)
-#include "hpps2atkbd.h"
-#else
-
 static unsigned char atkbd_set2_keycode[512] = {
 
+#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
+
+/* XXX: need a more general approach */
+
+#include "hpps2atkbd.h"	/* include the keyboard scancodes */
+
+#else
 	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
 	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
 	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
@@ -96,9 +99,8 @@ static unsigned char atkbd_set2_keycode[
 	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
 
 	  0,  0,  0, 65, 99,
-};
-
 #endif
+};
 
 static unsigned char atkbd_set3_keycode[512] = {
 
@@ -141,7 +143,6 @@ static unsigned char atkbd_unxlate_table
 #define ATKBD_CMD_EX_SETLEDS	0x20eb
 #define ATKBD_CMD_OK_GETID	0x02e8
 
-
 #define ATKBD_RET_ACK		0xfa
 #define ATKBD_RET_NAK		0xfe
 #define ATKBD_RET_BAT		0xaa
@@ -160,15 +161,22 @@ static unsigned char atkbd_unxlate_table
 #define ATKBD_SCR_4		252
 #define ATKBD_SCR_8		251
 #define ATKBD_SCR_CLICK		250
+#define ATKBD_SCR_LEFT		249
+#define ATKBD_SCR_RIGHT		248
 
-#define ATKBD_SPECIAL		250
+#define ATKBD_SPECIAL		248
 
-static unsigned char atkbd_scroll_keys[5][2] = {
-	{ ATKBD_SCR_1,     0x45 },
-	{ ATKBD_SCR_2,     0x29 },
-	{ ATKBD_SCR_4,     0x36 },
-	{ ATKBD_SCR_8,     0x27 },
-	{ ATKBD_SCR_CLICK, 0x60 },
+static struct {
+	unsigned char keycode;
+	unsigned char set2;
+} atkbd_scroll_keys[] = {
+	{ ATKBD_SCR_1,     0xc5 },
+	{ ATKBD_SCR_2,     0x9d },
+	{ ATKBD_SCR_4,     0xa4 },
+	{ ATKBD_SCR_8,     0x9b },
+	{ ATKBD_SCR_CLICK, 0xe0 },
+	{ ATKBD_SCR_LEFT,  0xcb },
+	{ ATKBD_SCR_RIGHT, 0xd2 },
 };
 
 /*
@@ -249,9 +257,9 @@ static void atkbd_report_key(struct inpu
 static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 			unsigned int flags, struct pt_regs *regs)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	unsigned int code = data;
-	int scroll = 0, click = -1;
+	int scroll = 0, hscroll = 0, click = -1;
 	int value;
 
 #ifdef ATKBD_DEBUG
@@ -370,6 +378,12 @@ static irqreturn_t atkbd_interrupt(struc
 		case ATKBD_SCR_CLICK:
 			click = !atkbd->release;
 			break;
+		case ATKBD_SCR_LEFT:
+			hscroll = -1;
+			break;
+		case ATKBD_SCR_RIGHT:
+			hscroll = 1;
+			break;
 		default:
 			value = atkbd->release ? 0 :
 				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
@@ -380,7 +394,7 @@ static irqreturn_t atkbd_interrupt(struc
 					break;
 				case 1:
 					atkbd->last = code;
-					atkbd->time = jiffies + (atkbd->dev.rep[REP_DELAY] * HZ + 500) / 1000 / 2;
+					atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2;
 					break;
 				case 2:
 					if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
@@ -391,10 +405,12 @@ static irqreturn_t atkbd_interrupt(struc
 			atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
 	}
 
-	if (scroll || click != -1) {
+	if (atkbd->scroll) {
 		input_regs(&atkbd->dev, regs);
-		input_report_key(&atkbd->dev, BTN_MIDDLE, click);
+		if (click != -1)
+			input_report_key(&atkbd->dev, BTN_MIDDLE, click);
 		input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
+		input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll);
 		input_sync(&atkbd->dev);
 	}
 
@@ -403,7 +419,6 @@ out:
 	return IRQ_HANDLED;
 }
 
-
 /*
  * Event callback from the input module. Events that change the state of
  * the hardware are processed here.
@@ -450,8 +465,10 @@ static int atkbd_event(struct input_dev 
 			if (atkbd->softrepeat) return 0;
 
 			i = j = 0;
-			while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
-			while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++;
+			while (i < 31 && period[i] < dev->rep[REP_PERIOD])
+				i++;
+			while (j < 3 && delay[j] < dev->rep[REP_DELAY])
+				j++;
 			dev->rep[REP_PERIOD] = period[i];
 			dev->rep[REP_DELAY] = delay[j];
 			param[0] = i | (j << 5);
@@ -647,7 +664,7 @@ static int atkbd_activate(struct atkbd *
 
 static void atkbd_cleanup(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
 }
 
@@ -658,12 +675,12 @@ static void atkbd_cleanup(struct serio *
 
 static void atkbd_disconnect(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 
 	atkbd_disable(atkbd);
 
 	/* make sure we don't have a command in flight */
-	synchronize_kernel();
+	synchronize_sched();  /* Allow atkbd_interrupt()s to complete. */
 	flush_scheduled_work();
 
 	device_remove_file(&serio->dev, &atkbd_attr_extra);
@@ -674,6 +691,7 @@ static void atkbd_disconnect(struct seri
 
 	input_unregister_device(&atkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(atkbd);
 }
 
@@ -694,12 +712,9 @@ static void atkbd_set_keycode_table(stru
 			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
 			if (atkbd->scroll)
-				for (j = 0; i < 5; i++) {
-					if (atkbd_unxlate_table[i] == atkbd_scroll_keys[j][1])
-						atkbd->keycode[i] = atkbd_scroll_keys[j][0];
-					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j][1])
-						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j][0];
-				}
+				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
+					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
+						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
 		}
 	} else if (atkbd->set == 3) {
 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
@@ -707,8 +722,8 @@ static void atkbd_set_keycode_table(stru
 		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
 
 		if (atkbd->scroll)
-			for (i = 0; i < 5; i++)
-				atkbd->keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
+				atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
 	}
 }
 
@@ -754,7 +769,7 @@ static void atkbd_set_device_attrs(struc
 
 	if (atkbd->scroll) {
 		atkbd->dev.evbit[0] |= BIT(EV_REL);
-		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
+		atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL);
 		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
 	}
 
@@ -768,23 +783,25 @@ static void atkbd_set_device_attrs(struc
 }
 
 /*
- * atkbd_connect() is called when the serio module finds and interface
+ * atkbd_connect() is called when the serio module finds an interface
  * that isn't handled yet by an appropriate device driver. We check if
  * there is an AT keyboard out there and if yes, we register ourselves
  * to the input module.
  */
 
-static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct atkbd *atkbd;
+	int err;
 
 	if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
-		return;
+		return - ENOMEM;
+
 	memset(atkbd, 0, sizeof(struct atkbd));
 
 	ps2_init(&atkbd->ps2dev, serio);
 
-	switch (serio->type & SERIO_TYPE) {
+	switch (serio->id.type) {
 
 		case SERIO_8042_XL:
 			atkbd->translated = 1;
@@ -792,12 +809,6 @@ static void atkbd_connect(struct serio *
 			if (serio->write)
 				atkbd->write = 1;
 			break;
-		case SERIO_RS232:
-			if ((serio->type & SERIO_PROTO) == SERIO_PS2SER)
-				break;
-		default:
-			kfree(atkbd);
-			return;
 	}
 
 	atkbd->softraw = atkbd_softraw;
@@ -810,20 +821,22 @@ static void atkbd_connect(struct serio *
 	if (atkbd->softrepeat)
 		atkbd->softraw = 1;
 
-	serio->private = atkbd;
+	serio_set_drvdata(serio, atkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(atkbd);
-		return;
+		return err;
 	}
 
 	if (atkbd->write) {
 
 		if (atkbd_probe(atkbd)) {
 			serio_close(serio);
-			serio->private = NULL;
+			serio_set_drvdata(serio, NULL);
 			kfree(atkbd);
-			return;
+			return -ENODEV;
 		}
 
 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
@@ -856,6 +869,8 @@ static void atkbd_connect(struct serio *
 	atkbd_enable(atkbd);
 
 	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -865,7 +880,7 @@ static void atkbd_connect(struct serio *
 
 static int atkbd_reconnect(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	struct serio_driver *drv = serio->drv;
 	unsigned char param[1];
 
@@ -897,11 +912,36 @@ static int atkbd_reconnect(struct serio 
 	return 0;
 }
 
+static struct serio_device_id atkbd_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_8042_XL,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_PS2SER,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
+
 static struct serio_driver atkbd_drv = {
 	.driver		= {
 		.name	= "atkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= atkbd_serio_ids,
 	.interrupt	= atkbd_interrupt,
 	.connect	= atkbd_connect,
 	.reconnect	= atkbd_reconnect,
@@ -924,7 +964,7 @@ static ssize_t atkbd_attr_show_helper(st
 		goto out;
 	}
 
-	retval = handler((struct atkbd *)serio->private, buf);
+	retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
 
 out:
 	serio_unpin_driver(serio);
@@ -947,7 +987,7 @@ static ssize_t atkbd_attr_set_helper(str
 		goto out;
 	}
 
-	atkbd = serio->private;
+	atkbd = serio_get_drvdata(serio);
 	atkbd_disable(atkbd);
 	retval = handler(atkbd, buf, count);
 	atkbd_enable(atkbd);
@@ -1095,13 +1135,13 @@ static ssize_t atkbd_set_softraw(struct 
 }
 
 
-int __init atkbd_init(void)
+static int __init atkbd_init(void)
 {
 	serio_register_driver(&atkbd_drv);
 	return 0;
 }
 
-void __exit atkbd_exit(void)
+static void __exit atkbd_exit(void)
 {
 	serio_unregister_driver(&atkbd_drv);
 }
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/keyboard/corgikbd.c
@@ -0,0 +1,361 @@
+/*
+ *  Keyboard driver for Sharp Corgi models (SL-C7xx)
+ *
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *
+ *  Based on xtkbd.c/locomkbd.c
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+
+#define KB_ROWS				8
+#define KB_COLS				12
+#define KB_ROWMASK(r)		(1 << (r))
+#define SCANCODE(r,c)		( ((r)<<4) + (c) + 1 )
+/* zero code, 124 scancodes + 3 hinge combinations */
+#define	NR_SCANCODES		( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
+#define SCAN_INTERVAL		(HZ/10)
+#define CORGIKBD_PRESSED	1
+
+#define HINGE_SCAN_INTERVAL		(HZ/4)
+
+#define CORGI_KEY_CALENDER	KEY_F1
+#define CORGI_KEY_ADDRESS	KEY_F2
+#define CORGI_KEY_FN		KEY_F3
+#define CORGI_KEY_OFF		KEY_SUSPEND
+#define CORGI_KEY_EXOK		KEY_F5
+#define CORGI_KEY_EXCANCEL	KEY_F6
+#define CORGI_KEY_EXJOGDOWN	KEY_F7
+#define CORGI_KEY_EXJOGUP	KEY_F8
+#define CORGI_KEY_JAP1		KEY_LEFTCTRL
+#define CORGI_KEY_JAP2		KEY_LEFTALT
+#define CORGI_KEY_OK		KEY_F11
+#define CORGI_KEY_MENU		KEY_F12
+#define CORGI_HINGE_0		KEY_KP0
+#define CORGI_HINGE_1		KEY_KP1
+#define CORGI_HINGE_2		KEY_KP2
+
+static unsigned char corgikbd_keycode[NR_SCANCODES] = {
+	0,                                                                                                                /* 0 */
+	0, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, 0, 0, 0, 0, 0, 0, 0, 	                      /* 1-16 */
+	0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, 0, 0, 0, 0, 0, 0, 0,                                   /* 17-32 */
+	KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
+	CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
+	CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
+	KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
+	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
+	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
+	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
+};
+
+
+struct corgikbd {
+	unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)];
+	struct input_dev input;
+	char phys[32];
+
+	unsigned char state[ARRAY_SIZE(corgikbd_keycode)];
+	spinlock_t lock;
+
+	struct timer_list timer;
+	struct timer_list htimer;
+};
+
+static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data)
+{
+	if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) {
+		corgikbd_data->state[scancode] |= CORGIKBD_PRESSED;
+		input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1);
+		if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
+			input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
+	} else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) {
+		corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED;
+		input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0);
+	}
+}
+
+#define KB_DISCHARGE_DELAY	10
+#define KB_ACTIVATE_DELAY	10
+
+/* Helper functions for reading the keyboard matrix
+ * Note: We should really be using pxa_gpio_mode to alter GPDR but it
+ *       requires a function call per GPIO bit which is excessive
+ *       when we need to access 12 bits at once multiple times.
+ * These functions must be called within local_irq_save()/local_irq_restore()
+ * or similar.
+ */
+static inline void corgikbd_discharge_all(void)
+{
+	// STROBE All HiZ
+	GPCR2  = CORGI_GPIO_ALL_STROBE_BIT;
+	GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
+}
+
+static inline void corgikbd_activate_all(void)
+{
+	// STROBE ALL -> High
+	GPSR2  = CORGI_GPIO_ALL_STROBE_BIT;
+	GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
+
+	udelay(KB_DISCHARGE_DELAY);
+
+	// Clear any interrupts we may have triggered when altering the GPIO lines
+	GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
+	GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
+}
+
+static inline void corgikbd_activate_col(int col)
+{
+	// STROBE col -> High, not col -> HiZ
+	GPSR2 = CORGI_GPIO_STROBE_BIT(col);
+	GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
+}
+
+static inline void corgikbd_reset_col(int col)
+{
+	// STROBE col -> Low
+	GPCR2 = CORGI_GPIO_STROBE_BIT(col);
+	// STROBE col -> out, not col -> HiZ
+	GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
+}
+
+#define GET_ROWS_STATUS(c)	(((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT))
+
+/*
+ * The corgi keyboard only generates interrupts when a key is pressed.
+ * When a key is pressed, we enable a timer which then scans the
+ * keyboard to detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
+{
+	unsigned int row, col, rowd, scancode;
+	unsigned long flags;
+	unsigned int num_pressed;
+
+	spin_lock_irqsave(&corgikbd_data->lock, flags);
+
+	if (regs)
+		input_regs(&corgikbd_data->input, regs);
+
+	num_pressed = 0;
+	for (col = 0; col < KB_COLS; col++) {
+		/*
+		 * Discharge the output driver capacitatance
+		 * in the keyboard matrix. (Yes it is significant..)
+		 */
+
+		corgikbd_discharge_all();
+		udelay(KB_DISCHARGE_DELAY);
+
+		corgikbd_activate_col(col);
+		udelay(KB_ACTIVATE_DELAY);
+
+		rowd = GET_ROWS_STATUS(col);
+		for (row = 0; row < KB_ROWS; row++) {
+			scancode = SCANCODE(row, col);
+			handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data);
+			if (rowd & KB_ROWMASK(row))
+				num_pressed++;
+		}
+		corgikbd_reset_col(col);
+	}
+
+	corgikbd_activate_all();
+
+	input_sync(&corgikbd_data->input);
+
+	/* if any keys are pressed, enable the timer */
+	if (num_pressed)
+		mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL);
+
+	spin_unlock_irqrestore(&corgikbd_data->lock, flags);
+}
+
+/*
+ * corgi keyboard interrupt handler.
+ */
+static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct corgikbd *corgikbd_data = dev_id;
+
+	if (!timer_pending(&corgikbd_data->timer)) {
+		/** wait chattering delay **/
+		udelay(20);
+		corgikbd_scankeyboard(corgikbd_data, regs);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * corgi timer checking for released keys
+ */
+static void corgikbd_timer_callback(unsigned long data)
+{
+	struct corgikbd *corgikbd_data = (struct corgikbd *) data;
+	corgikbd_scankeyboard(corgikbd_data, NULL);
+}
+
+/*
+ * The hinge switches generate no interrupt so they need to be
+ * monitored by a timer.
+ *
+ * When we detect changes, we debounce it and then pass the three
+ * positions the system can take as keypresses to the input system.
+ */
+
+#define HINGE_STABLE_COUNT 2
+static int sharpsl_hinge_state;
+static int hinge_count;
+
+static void corgikbd_hinge_timer(unsigned long data)
+{
+	struct corgikbd *corgikbd_data = (struct corgikbd *) data;
+	unsigned long gprr;
+	unsigned long flags;
+
+	gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+	if (gprr != sharpsl_hinge_state) {
+		hinge_count = 0;
+		sharpsl_hinge_state = gprr;
+	} else if (hinge_count < HINGE_STABLE_COUNT) {
+		hinge_count++;
+		if (hinge_count >= HINGE_STABLE_COUNT) {
+			spin_lock_irqsave(&corgikbd_data->lock, flags);
+
+			handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */
+			handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */
+			handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed  */
+			input_sync(&corgikbd_data->input);
+
+			spin_unlock_irqrestore(&corgikbd_data->lock, flags);
+		}
+	}
+	mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
+}
+
+static int __init corgikbd_probe(struct device *dev)
+{
+	int i;
+	struct corgikbd *corgikbd;
+
+	corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL);
+	if (!corgikbd)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev,corgikbd);
+	strcpy(corgikbd->phys, "corgikbd/input0");
+
+	spin_lock_init(corgikbd->lock);
+
+	/* Init Keyboard rescan timer */
+	init_timer(&corgikbd->timer);
+	corgikbd->timer.function = corgikbd_timer_callback;
+	corgikbd->timer.data = (unsigned long) corgikbd;
+
+	/* Init Hinge Timer */
+	init_timer(&corgikbd->htimer);
+	corgikbd->htimer.function = corgikbd_hinge_timer;
+	corgikbd->htimer.data = (unsigned long) corgikbd;
+
+	init_input_dev(&corgikbd->input);
+	corgikbd->input.private = corgikbd;
+	corgikbd->input.name = "Corgi Keyboard";
+	corgikbd->input.dev = dev;
+	corgikbd->input.phys = corgikbd->phys;
+	corgikbd->input.id.bustype = BUS_HOST;
+	corgikbd->input.id.vendor = 0x0001;
+	corgikbd->input.id.product = 0x0001;
+	corgikbd->input.id.version = 0x0100;
+	corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR);
+	corgikbd->input.keycode = corgikbd->keycode;
+	corgikbd->input.keycodesize = sizeof(unsigned char);
+	corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode);
+
+	memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode));
+	for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
+		set_bit(corgikbd->keycode[i], corgikbd->input.keybit);
+	clear_bit(0, corgikbd->input.keybit);
+
+	input_register_device(&corgikbd->input);
+	mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
+
+	/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
+	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
+		pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN);
+		if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt,
+						SA_INTERRUPT, "corgikbd", corgikbd))
+			printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i);
+		else
+			set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING);
+	}
+
+	/* Set Strobe lines as outputs - set high */
+	for (i = 0; i < CORGI_KEY_STROBE_NUM; i++)
+		pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
+
+	printk(KERN_INFO "input: Corgi Keyboard Registered\n");
+
+	return 0;
+}
+
+static int corgikbd_remove(struct device *dev)
+{
+	int i;
+	struct corgikbd *corgikbd = dev_get_drvdata(dev);
+
+	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++)
+		free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd);
+
+	del_timer_sync(&corgikbd->htimer);
+	del_timer_sync(&corgikbd->timer);
+
+	input_unregister_device(&corgikbd->input);
+
+	kfree(corgikbd);
+
+	return 0;
+}
+
+static struct device_driver corgikbd_driver = {
+	.name		= "corgi-keyboard",
+	.bus		= &platform_bus_type,
+	.probe		= corgikbd_probe,
+	.remove		= corgikbd_remove,
+};
+
+static int __devinit corgikbd_init(void)
+{
+	return driver_register(&corgikbd_driver);
+}
+
+static void __exit corgikbd_exit(void)
+{
+	driver_unregister(&corgikbd_driver);
+}
+
+module_init(corgikbd_init);
+module_exit(corgikbd_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -0,0 +1,375 @@
+/*
+ * 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>
+#include <linux/pci_ids.h>
+
+#define PREFIX "HIL KEYB: "
+#define HIL_GENERIC_NAME "HIL keyboard"
+
+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 unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = 
+	{ HIL_KEYCODES_SET1 };
+
+#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 unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
+	{ HIL_KEYCODES_SET3 };
+
+static char hil_language[][16] = { 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 = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
+			if (key != KEY_RESERVED)
+				input_report_key(dev, 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)
+				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 = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
+			if (key != KEY_RESERVED)
+				input_report_key(dev, 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);
+}
+
+static irqreturn_t hil_kbd_interrupt(struct serio *serio, 
+	      unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct hil_kbd *kbd;
+	hil_packet packet;
+	int idx;
+
+	kbd = (struct hil_kbd *)serio->private;
+	if (kbd == NULL) {
+		BUG();
+		return IRQ_HANDLED;
+	}
+
+	if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_kbd_process_err(kbd);
+		return IRQ_HANDLED;
+	}
+	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 IRQ_HANDLED;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_kbd_process_err(kbd);
+		return IRQ_HANDLED;
+	}
+	if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
+	return IRQ_HANDLED;
+}
+
+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_driver *drv)
+{
+	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, drv)) 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.evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
+	kbd->dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	kbd->dev.keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
+	kbd->dev.keycodesize	= sizeof(hil_kbd_set1[0]);
+	kbd->dev.keycode	= hil_kbd_set1;
+	kbd->dev.name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
+	kbd->dev.phys		= "hpkbd/input0";	/* XXX */
+
+	kbd->dev.id.bustype	= BUS_HIL;
+	kbd->dev.id.vendor	= PCI_VENDOR_ID_HP;
+	kbd->dev.id.product	= 0x0001; /* TODO: get from kbd->rsc */
+	kbd->dev.id.version	= 0x0100; /* TODO: get from kbd->rsc */
+	kbd->dev.dev		= &serio->dev;
+
+	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);
+
+	input_register_device(&kbd->dev);
+	printk(KERN_INFO "input: %s, ID: %d\n",
+		kbd->dev.name, did);
+
+	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);
+}
+
+
+struct serio_driver hil_kbd_serio_drv = {
+	.driver		= {
+		.name	= "hil_kbd",
+	},
+	.description	= "HP HIL keyboard driver",
+	.connect 	= hil_kbd_connect,
+	.disconnect 	= hil_kbd_disconnect,
+	.interrupt 	= hil_kbd_interrupt
+};
+
+static int __init hil_kbd_init(void)
+{
+	serio_register_driver(&hil_kbd_serio_drv);
+        return 0;
+}
+                
+static void __exit hil_kbd_exit(void)
+{
+	serio_unregister_driver(&hil_kbd_serio_drv);
+}
+                        
+module_init(hil_kbd_init);
+module_exit(hil_kbd_exit);
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/keyboard/hilkbd.c
@@ -0,0 +1,343 @@
+/*
+ *  linux/drivers/hil/hilkbd.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
+ *  Copyright (C) 1999-2003 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>
+#include <linux/spinlock.h>
+
+
+MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
+MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)");
+MODULE_LICENSE("GPL v2");
+
+
+#if defined(CONFIG_PARISC)
+
+ #include <asm/io.h>
+ #include <asm/hardware.h>
+ #include <asm/parisc-device.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_READKBDSADR	 	0xF9
+#define	HIL_WRITEKBDSADR 	0xE9
+
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = 
+	{ HIL_KEYCODES_SET1 };
+
+/* 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;
+	spinlock_t lock;
+
+	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 = hphilkeyb_keycode[scode];
+		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 irqreturn_t 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;
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hil_dev.lock, flags);
+	while (hil_busy())
+		/* wait */;
+	hil_command(cmd);
+	while (len--) {
+		while (hil_busy())
+			/* wait */;
+		hil_write_data(*(data++));
+	}
+	spin_unlock_irqrestore(&hil_dev.lock, flags);
+}
+
+
+/*
+ * Initialise HIL. 
+ */
+
+static int __init
+hil_keyb_init(void)
+{
+	unsigned char c;
+	unsigned int i, kbid;
+	wait_queue_head_t hil_wait;
+
+	if (hil_dev.dev.id.bustype) {
+		return -ENODEV; /* already initialized */
+	}
+	
+#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);
+
+	init_waitqueue_head(&hil_wait);
+	wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
+	if (!hil_dev.valid) {
+		printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n");
+	}
+
+	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);
+	
+	init_input_dev(&hil_dev.dev);
+
+	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
+		if (hphilkeyb_keycode[i] != KEY_RESERVED)
+			set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit);
+
+	hil_dev.dev.evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
+	hil_dev.dev.ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	hil_dev.dev.keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
+        hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]);
+	hil_dev.dev.keycode     = hphilkeyb_keycode;
+	hil_dev.dev.name 	= "HIL keyboard";
+	hil_dev.dev.phys 	= "hpkbd/input0";
+
+	hil_dev.dev.id.bustype	= BUS_HIL;
+	hil_dev.dev.id.vendor	= PCI_VENDOR_ID_HP;
+	hil_dev.dev.id.product	= 0x0001;
+	hil_dev.dev.id.version	= 0x0010;
+
+	input_register_device(&hil_dev.dev);
+	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
+		hil_dev.dev.name, kbid, HILBASE, HIL_IRQ);
+
+	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 bus at 0x%08lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	hil_base = dev->hpa;
+	hil_irq  = dev->irq;
+	hil_dev.dev_id = dev;
+	
+	printk(KERN_INFO "Found HIL bus at 0x%08lx, 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);
+	}
+
+	/* Turn off interrupts */
+	hil_do(HIL_INTOFF, NULL, 0);
+
+	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 --git a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h
--- a/drivers/input/keyboard/hpps2atkbd.h
+++ b/drivers/input/keyboard/hpps2atkbd.h
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2004 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
- * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
  * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
  *
  * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops
@@ -14,10 +14,8 @@
  */
 
 
-/* undefine if you have a RDI PRECISIONBOOK */
-#define STANDARD_KEYBOARD
-
-#if defined(STANDARD_KEYBOARD)
+/* Is the keyboard an RDI PrecisionBook? */
+#ifndef CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES
 # define CONFLICT(x,y) x
 #else
 # define CONFLICT(x,y) y
@@ -50,10 +48,10 @@
 /* 60 */  KEY_DOWN,     C_61,          KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
 /* 68 */  KEY_RESERVED, KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
 /* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
+/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_102ND,
 /* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
-/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_SYSRQ,     KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  255,           KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_CAPSLOCK, KEY_RESERVED,  KEY_LEFTMETA,
 /* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RIGHTMETA,
 /* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_COMPOSE,
@@ -103,7 +101,6 @@
 /* f0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED
 
-#undef STANDARD_KEYBOARD
 #undef CONFLICT
 #undef C_07
 #undef C_11
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -14,14 +14,14 @@
  * DISCLAIMER: This works for _me_. If you break anything by using the
  * information given below, I will _not_ be liable!
  *
- * RJ11 pinout:		To DE9:		Or DB25:
+ * RJ10 pinout:		To DE9:		Or DB25:
  * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
  * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
  * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
  * 	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
  *
  * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
- * RJ11, it's like this:
+ * RJ10, it's like this:
  *
  *      __=__	Hold the plug in front of you, cable downwards,
  *     /___/|	nose is hidden behind the plug. Now, pin 1 is at
@@ -417,7 +417,7 @@ static irqreturn_t
 lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
 		struct pt_regs *regs)
 {
-	struct lkkbd *lk = serio->private;
+	struct lkkbd *lk = serio_get_drvdata (serio);
 	int i;
 
 	DBG (KERN_INFO "Got byte 0x%02x\n", data);
@@ -623,19 +623,16 @@ lkkbd_reinit (void *data)
 /*
  * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
  */
-static void
+static int
 lkkbd_connect (struct serio *serio, struct serio_driver *drv)
 {
 	struct lkkbd *lk;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-	if ((serio->type & SERIO_PROTO) != SERIO_LKKBD)
-		return;
+	int err;
 
 	if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
+
 	memset (lk, 0, sizeof (struct lkkbd));
 
 	init_input_dev (&lk->dev);
@@ -665,11 +662,13 @@ lkkbd_connect (struct serio *serio, stru
 	lk->dev.event = lkkbd_event;
 	lk->dev.private = lk;
 
-	serio->private = lk;
+	serio_set_drvdata (serio, lk);
 
-	if (serio_open (serio, drv)) {
+	err = serio_open (serio, drv);
+	if (err) {
+		serio_set_drvdata (serio, NULL);
 		kfree (lk);
-		return;
+		return err;
 	}
 
 	sprintf (lk->name, "DEC LK keyboard");
@@ -691,6 +690,8 @@ lkkbd_connect (struct serio *serio, stru
 
 	printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys);
 	lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+
+	return 0;
 }
 
 /*
@@ -699,18 +700,32 @@ lkkbd_connect (struct serio *serio, stru
 static void
 lkkbd_disconnect (struct serio *serio)
 {
-	struct lkkbd *lk = serio->private;
+	struct lkkbd *lk = serio_get_drvdata (serio);
 
 	input_unregister_device (&lk->dev);
 	serio_close (serio);
+	serio_set_drvdata (serio, NULL);
 	kfree (lk);
 }
 
+static struct serio_device_id lkkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_LKKBD,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, lkkbd_serio_ids);
+
 static struct serio_driver lkkbd_drv = {
 	.driver		= {
 		.name	= "lkkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= lkkbd_serio_ids,
 	.connect	= lkkbd_connect,
 	.disconnect	= lkkbd_disconnect,
 	.interrupt	= lkkbd_interrupt,
@@ -719,14 +734,14 @@ static struct serio_driver lkkbd_drv = {
 /*
  * The functions for insering/removing us as a module.
  */
-int __init
+static int __init
 lkkbd_init (void)
 {
 	serio_register_driver(&lkkbd_drv);
 	return 0;
 }
 
-void __exit
+static void __exit
 lkkbd_exit (void)
 {
 	serio_unregister_driver(&lkkbd_drv);
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/keyboard/locomokbd.c
@@ -0,0 +1,309 @@
+/*
+ *  Copyright (c) 2005 John Lenz
+ *
+ * Based on from xtkbd.c
+ */
+
+/*
+ * LoCoMo keyboard driver for Linux/ARM
+ */
+
+/*
+ * This program is free software; you can redistribute it 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/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware/locomo.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_DESCRIPTION("LoCoMo keyboard driver");
+MODULE_LICENSE("GPL");
+
+#define LOCOMOKBD_NUMKEYS 	128
+
+#define KEY_ACTIVITY		KEY_F16
+#define KEY_CONTACT		KEY_F18
+#define KEY_CENTER		KEY_F15
+
+static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
+	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
+	0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,			/* 10 - 19 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,						/* 20 - 29 */
+	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
+	KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,		/* 50 - 59 */
+	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,			/* 60 - 69 */
+	KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,	/* 70 - 79 */
+	0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,		/* 80 - 89 */
+	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
+	0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
+	KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
+	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 		/* 120 - 128 */
+};
+
+#define KB_ROWS			16
+#define KB_COLS			8
+#define KB_ROWMASK(r)		(1 << (r))
+#define SCANCODE(c,r)		( ((c)<<4) + (r) + 1 )
+#define	NR_SCANCODES		128
+
+#define KB_DELAY		8
+#define SCAN_INTERVAL		(HZ/10)
+#define LOCOMOKBD_PRESSED	1
+
+struct locomokbd {
+	unsigned char keycode[LOCOMOKBD_NUMKEYS];
+	struct input_dev input;
+	char phys[32];
+
+	struct locomo_dev *ldev;
+	unsigned long base;
+	spinlock_t lock;
+	
+	struct timer_list timer;
+};
+
+/* helper functions for reading the keyboard matrix */
+static inline void locomokbd_charge_all(unsigned long membase)
+{
+	locomo_writel(0x00FF, membase + LOCOMO_KSC);
+}
+
+static inline void locomokbd_activate_all(unsigned long membase)
+{
+	unsigned long r;
+	
+	locomo_writel(0, membase + LOCOMO_KSC);
+	r = locomo_readl(membase + LOCOMO_KIC);
+	r &= 0xFEFF;
+	locomo_writel(r, membase + LOCOMO_KIC);
+}
+
+static inline void locomokbd_activate_col(unsigned long membase, int col)
+{
+	unsigned short nset;
+	unsigned short nbset;
+
+	nset = 0xFF & ~(1 << col);
+	nbset = (nset << 8) + nset;
+	locomo_writel(nbset, membase + LOCOMO_KSC);
+}
+
+static inline void locomokbd_reset_col(unsigned long membase, int col)
+{
+	unsigned short nbset;
+
+	nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
+	locomo_writel(nbset, membase + LOCOMO_KSC);
+}
+
+/*
+ * The LoCoMo keyboard only generates interrupts when a key is pressed.
+ * So when a key is pressed, we enable a timer.  This timer scans the
+ * keyboard, and this is how we detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) 
+{
+	unsigned int row, col, rowd, scancode;
+	unsigned long flags;
+	unsigned int num_pressed;
+	unsigned long membase = locomokbd->base;
+
+	spin_lock_irqsave(&locomokbd->lock, flags);
+
+	if (regs)
+		input_regs(&locomokbd->input, regs);
+	
+	locomokbd_charge_all(membase);
+
+	num_pressed = 0;
+	for (col = 0; col < KB_COLS; col++) {
+
+		locomokbd_activate_col(membase, col);
+		udelay(KB_DELAY);
+		 
+		rowd = ~locomo_readl(membase + LOCOMO_KIB);
+		for (row = 0; row < KB_ROWS; row++ ) {
+			scancode = SCANCODE(col, row);
+			if (rowd & KB_ROWMASK(row)) {
+				num_pressed += 1;
+				input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 1);
+			} else {
+				input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 0);
+			}
+		}
+		locomokbd_reset_col(membase, col);
+	}
+	locomokbd_activate_all(membase);
+
+	input_sync(&locomokbd->input);
+
+	/* if any keys are pressed, enable the timer */
+	if (num_pressed)
+		mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
+
+	spin_unlock_irqrestore(&locomokbd->lock, flags);
+}
+
+/* 
+ * LoCoMo keyboard interrupt handler.
+ */
+static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct locomokbd *locomokbd = dev_id;
+	/** wait chattering delay **/
+	udelay(100);
+
+	locomokbd_scankeyboard(locomokbd, regs);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * LoCoMo timer checking for released keys
+ */
+static void locomokbd_timer_callback(unsigned long data)
+{
+	struct locomokbd *locomokbd = (struct locomokbd *) data;
+	locomokbd_scankeyboard(locomokbd, NULL);
+}
+
+static int locomokbd_probe(struct locomo_dev *dev)
+{
+	struct locomokbd *locomokbd;
+	int i, ret;
+
+	locomokbd = kmalloc(sizeof(struct locomokbd), GFP_KERNEL);
+	if (!locomokbd)
+		return -ENOMEM;
+
+	memset(locomokbd, 0, sizeof(struct locomokbd));
+
+	/* try and claim memory region */
+	if (!request_mem_region((unsigned long) dev->mapbase, 
+				dev->length, 
+				LOCOMO_DRIVER_NAME(dev))) {
+		ret = -EBUSY;
+		printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
+		goto free;
+	}
+
+	locomokbd->ldev = dev;
+	locomo_set_drvdata(dev, locomokbd);
+
+	locomokbd->base = (unsigned long) dev->mapbase;
+
+	spin_lock_init(&locomokbd->lock);
+
+	init_timer(&locomokbd->timer);
+	locomokbd->timer.function = locomokbd_timer_callback;
+	locomokbd->timer.data = (unsigned long) locomokbd;
+
+	locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	
+	init_input_dev(&locomokbd->input);
+	locomokbd->input.keycode = locomokbd->keycode;
+	locomokbd->input.keycodesize = sizeof(unsigned char);
+	locomokbd->input.keycodemax = ARRAY_SIZE(locomokbd_keycode);
+	locomokbd->input.private = locomokbd;
+
+	memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
+	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
+		set_bit(locomokbd->keycode[i], locomokbd->input.keybit);
+	clear_bit(0, locomokbd->input.keybit);
+
+	strcpy(locomokbd->phys, "locomokbd/input0");
+
+	locomokbd->input.name = "LoCoMo keyboard";
+	locomokbd->input.phys = locomokbd->phys;
+	locomokbd->input.id.bustype = BUS_XTKBD;
+	locomokbd->input.id.vendor = 0x0001;
+	locomokbd->input.id.product = 0x0001;
+	locomokbd->input.id.version = 0x0100;
+
+	/* attempt to get the interrupt */
+	ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+	if (ret) {
+		printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
+		goto out;
+	}
+
+	input_register_device(&locomokbd->input);
+
+	printk(KERN_INFO "input: LoCoMo keyboard on locomokbd\n");
+
+	return 0;
+
+out:
+	release_mem_region((unsigned long) dev->mapbase, dev->length);
+	locomo_set_drvdata(dev, NULL);
+free:
+	kfree(locomokbd);
+
+	return ret;
+}
+
+static int locomokbd_remove(struct locomo_dev *dev)
+{
+	struct locomokbd *locomokbd = locomo_get_drvdata(dev);
+	
+	free_irq(dev->irq[0], locomokbd);
+
+	del_timer_sync(&locomokbd->timer);
+	
+	input_unregister_device(&locomokbd->input);
+	locomo_set_drvdata(dev, NULL);
+
+	release_mem_region((unsigned long) dev->mapbase, dev->length);
+
+	kfree(locomokbd);
+
+	return 0;
+}
+
+static struct locomo_driver keyboard_driver = {
+	.drv = {
+		.name = "locomokbd"
+	},
+	.devid	= LOCOMO_DEVID_KEYBOARD,
+	.probe	= locomokbd_probe,
+	.remove	= locomokbd_remove,
+};
+
+static int __init locomokbd_init(void)
+{
+	return locomo_driver_register(&keyboard_driver);
+}
+
+static void __exit locomokbd_exit(void)
+{
+	locomo_driver_unregister(&keyboard_driver);
+}
+
+module_init(locomokbd_init);
+module_exit(locomokbd_exit);
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -66,10 +66,10 @@ struct nkbd {
 	char phys[32];
 };
 
-irqreturn_t nkbd_interrupt(struct serio *serio,
+static irqreturn_t nkbd_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct nkbd *nkbd = serio->private;
+	struct nkbd *nkbd = serio_get_drvdata(serio);
 
 	/* invalid scan codes are probably the init sequence, so we ignore them */
 	if (nkbd->keycode[data & NKBD_KEY]) {
@@ -84,16 +84,14 @@ irqreturn_t nkbd_interrupt(struct serio 
 
 }
 
-void nkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct nkbd *nkbd;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_NEWTON))
-		return;
+	int err;
 
 	if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(nkbd, 0, sizeof(struct nkbd));
 
@@ -106,11 +104,14 @@ void nkbd_connect(struct serio *serio, s
 	nkbd->dev.keycodesize = sizeof(unsigned char);
 	nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode);
 	nkbd->dev.private = nkbd;
-	serio->private = nkbd;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, nkbd);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(nkbd);
-		return;
+		return err;
 	}
 
 	memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
@@ -131,33 +132,50 @@ void nkbd_connect(struct serio *serio, s
 	input_register_device(&nkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
+
+	return 0;
 }
 
-void nkbd_disconnect(struct serio *serio)
+static void nkbd_disconnect(struct serio *serio)
 {
-	struct nkbd *nkbd = serio->private;
+	struct nkbd *nkbd = serio_get_drvdata(serio);
+
 	input_unregister_device(&nkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(nkbd);
 }
 
-struct serio_driver nkbd_drv = {
+static struct serio_device_id nkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_NEWTON,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, nkbd_serio_ids);
+
+static struct serio_driver nkbd_drv = {
 	.driver		= {
 		.name	= "newtonkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= nkbd_serio_ids,
 	.interrupt	= nkbd_interrupt,
 	.connect	= nkbd_connect,
 	.disconnect	= nkbd_disconnect,
 };
 
-int __init nkbd_init(void)
+static int __init nkbd_init(void)
 {
 	serio_register_driver(&nkbd_drv);
 	return 0;
 }
 
-void __exit nkbd_exit(void)
+static void __exit nkbd_exit(void)
 {
 	serio_unregister_driver(&nkbd_drv);
 }
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -95,7 +95,7 @@ struct sunkbd {
 static irqreturn_t sunkbd_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct sunkbd* sunkbd = serio->private;
+	struct sunkbd* sunkbd = serio_get_drvdata(serio);
 
 	if (sunkbd->reset <= -1) {		/* If cp[i] is 0xff, sunkbd->reset will stay -1. */
 		sunkbd->reset = data;		/* The keyboard sends 0xff 0xff 0xID on powerup */
@@ -223,19 +223,14 @@ static void sunkbd_reinit(void *data)
  * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
  */
 
-static void sunkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct sunkbd *sunkbd;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-
-	if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
-		return;
+	int err;
 
 	if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(sunkbd, 0, sizeof(struct sunkbd));
 
@@ -257,17 +252,20 @@ static void sunkbd_connect(struct serio 
 	sunkbd->dev.event = sunkbd_event;
 	sunkbd->dev.private = sunkbd;
 
-	serio->private = sunkbd;
+	serio_set_drvdata(serio, sunkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(sunkbd);
-		return;
+		return err;
 	}
 
 	if (sunkbd_initialize(sunkbd) < 0) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(sunkbd);
-		return;
+		return -ENODEV;
 	}
 
 	sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
@@ -290,6 +288,8 @@ static void sunkbd_connect(struct serio 
 	input_register_device(&sunkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -298,17 +298,37 @@ static void sunkbd_connect(struct serio 
 
 static void sunkbd_disconnect(struct serio *serio)
 {
-	struct sunkbd *sunkbd = serio->private;
+	struct sunkbd *sunkbd = serio_get_drvdata(serio);
 	input_unregister_device(&sunkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(sunkbd);
 }
 
+static struct serio_device_id sunkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SUNKBD,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_UNKNOWN, /* sunkbd does probe */
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
+
 static struct serio_driver sunkbd_drv = {
 	.driver		= {
 		.name	= "sunkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= sunkbd_serio_ids,
 	.interrupt	= sunkbd_interrupt,
 	.connect	= sunkbd_connect,
 	.disconnect	= sunkbd_disconnect,
@@ -318,13 +338,13 @@ static struct serio_driver sunkbd_drv = 
  * The functions for insering/removing us as a module.
  */
 
-int __init sunkbd_init(void)
+static int __init sunkbd_init(void)
 {
 	serio_register_driver(&sunkbd_drv);
 	return 0;
 }
 
-void __exit sunkbd_exit(void)
+static void __exit sunkbd_exit(void)
 {
 	serio_unregister_driver(&sunkbd_drv);
 }
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -65,10 +65,10 @@ struct xtkbd {
 	char phys[32];
 };
 
-irqreturn_t xtkbd_interrupt(struct serio *serio,
+static irqreturn_t xtkbd_interrupt(struct serio *serio,
 	unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct xtkbd *xtkbd = serio->private;
+	struct xtkbd *xtkbd = serio_get_drvdata(serio);
 
 	switch (data) {
 		case XTKBD_EMUL0:
@@ -88,16 +88,14 @@ irqreturn_t xtkbd_interrupt(struct serio
 	return IRQ_HANDLED;
 }
 
-void xtkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct xtkbd *xtkbd;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_XT)
-		return;
+	int err;
 
 	if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(xtkbd, 0, sizeof(struct xtkbd));
 
@@ -111,11 +109,13 @@ void xtkbd_connect(struct serio *serio, 
 	xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode);
 	xtkbd->dev.private = xtkbd;
 
-	serio->private = xtkbd;
+	serio_set_drvdata(serio, xtkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(xtkbd);
-		return;
+		return err;
 	}
 
 	memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
@@ -136,33 +136,50 @@ void xtkbd_connect(struct serio *serio, 
 	input_register_device(&xtkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys);
+
+	return 0;
 }
 
-void xtkbd_disconnect(struct serio *serio)
+static void xtkbd_disconnect(struct serio *serio)
 {
-	struct xtkbd *xtkbd = serio->private;
+	struct xtkbd *xtkbd = serio_get_drvdata(serio);
+
 	input_unregister_device(&xtkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(xtkbd);
 }
 
-struct serio_driver xtkbd_drv = {
+static struct serio_device_id xtkbd_serio_ids[] = {
+	{
+		.type	= SERIO_XT,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, xtkbd_serio_ids);
+
+static struct serio_driver xtkbd_drv = {
 	.driver		= {
 		.name	= "xtkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= xtkbd_serio_ids,
 	.interrupt	= xtkbd_interrupt,
 	.connect	= xtkbd_connect,
 	.disconnect	= xtkbd_disconnect,
 };
 
-int __init xtkbd_init(void)
+static int __init xtkbd_init(void)
 {
 	serio_register_driver(&xtkbd_drv);
 	return 0;
 }
 
-void __exit xtkbd_exit(void)
+static void __exit xtkbd_exit(void)
 {
 	serio_unregister_driver(&xtkbd_drv);
 }
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -1,9 +1,8 @@
 #
 # Input misc drivers configuration
 #
-config INPUT_MISC
-	bool "Misc"
-	depends on INPUT
+menuconfig INPUT_MISC
+	bool "Miscellaneous devices"
 	help
 	  Say Y here, and a list of miscellaneous input drivers will be displayed.
 	  Everything that didn't fit into the other categories is here. This option
@@ -11,9 +10,11 @@ config INPUT_MISC
 
 	  If unsure, say Y.
 
+if INPUT_MISC
+
 config INPUT_PCSPKR
 	tristate "PC Speaker support"
-	depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC
+	depends on ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
 	help
 	  Say Y here if you want the standard PC Speaker to be used for
 	  bells and whistles.
@@ -25,7 +26,7 @@ config INPUT_PCSPKR
 
 config INPUT_SPARCSPKR
 	tristate "SPARC Speaker support"
-	depends on (SPARC32 || SPARC64) && INPUT && INPUT_MISC && PCI
+	depends on PCI && (SPARC32 || SPARC64)
 	help
 	  Say Y here if you want the standard Speaker on Sparc PCI systems
 	  to be used for bells and whistles.
@@ -37,11 +38,10 @@ config INPUT_SPARCSPKR
 
 config INPUT_M68K_BEEP
 	tristate "M68k Beeper support"
-	depends on M68K && INPUT && INPUT_MISC
+	depends on M68K
 
 config INPUT_UINPUT
 	tristate "User level driver support"
-	depends on INPUT && INPUT_MISC
 	help
 	  Say Y here if you want to support user level drivers for input
 	  subsystem accessible under char device 10:223 - /dev/input/uinput.
@@ -49,3 +49,12 @@ config INPUT_UINPUT
 	  To compile this driver as a module, choose M here: the
 	  module will be called uinput.
 
+config HP_SDC_RTC
+	tristate "HP SDC Real Time Clock"       
+	depends on GSC
+	select HP_SDC
+	help
+	  Say Y here if you want to support the built-in real time clock
+	  of the HP SDC controller.
+
+endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_98SPKR)		+= 98spkr.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -0,0 +1,724 @@
+/*
+ * 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)
+{
+        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);
+        }
+
+        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: %ld.%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: %ld.%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: %ld.%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: %ld.%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: %ld.%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;
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+
+		wtime.tm_hour = ttime.tv_sec / 3600;  ttime.tv_sec %= 3600;
+		wtime.tm_min  = ttime.tv_sec / 60;    ttime.tv_sec %= 60;
+		wtime.tm_sec  = ttime.tv_sec;
+                
+		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_HIL",
+        .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 --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -27,7 +27,7 @@ static char pcspkr_name[] = "PC Speaker"
 static char pcspkr_phys[] = "isa0061/input0";
 static struct input_dev pcspkr_dev;
 
-DEFINE_SPINLOCK(i8253_beep_lock);
+static DEFINE_SPINLOCK(i8253_beep_lock);
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -89,6 +89,8 @@ static int __init pcspkr_init(void)
 static void __exit pcspkr_exit(void)
 {
         input_unregister_device(&pcspkr_dev);
+	/* turn off the speaker */
+	pcspkr_event(NULL, EV_SND, SND_BELL, 0);
 }
 
 module_init(pcspkr_init);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -20,6 +20,9 @@
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
  *
  * Changes/Revisions:
+ *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
+ *		- added force feedback support
+ *              - added UI_SET_PHYS
  *	0.1	20/06/2002
  *		- first public version
  */
@@ -47,7 +50,7 @@ static int uinput_dev_event(struct input
 {
 	struct uinput_device	*udev;
 
-	udev = (struct uinput_device *)dev->private;
+	udev = dev->private;
 
 	udev->buff[udev->head].type = type;
 	udev->buff[udev->head].code = code;
@@ -60,14 +63,93 @@ static int uinput_dev_event(struct input
 	return 0;
 }
 
+static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request)
+{
+	/* Atomically allocate an ID for the given request. Returns 0 on success. */
+	struct uinput_device *udev = dev->private;
+	int id;
+
+	down(&udev->requests_sem);
+	for (id=0; id<UINPUT_NUM_REQUESTS; id++)
+		if (!udev->requests[id]) {
+			udev->requests[id] = request;
+			request->id = id;
+			up(&udev->requests_sem);
+			return 0;
+		}
+	up(&udev->requests_sem);
+	return -1;
+}
+
+static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id)
+{
+	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
+	if (id >= UINPUT_NUM_REQUESTS || id < 0)
+		return NULL;
+	if (udev->requests[id]->completed)
+		return NULL;
+	return udev->requests[id];
+}
+
+static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code)
+{
+	struct uinput_device *udev = dev->private;
+
+	memset(request, 0, sizeof(struct uinput_request));
+	request->code = code;
+	init_waitqueue_head(&request->waitq);
+
+	/* Allocate an ID. If none are available right away, wait. */
+	request->retval = wait_event_interruptible(udev->requests_waitq,
+				       !uinput_request_alloc_id(dev, request));
+}
+
+static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+{
+	struct uinput_device *udev = dev->private;
+	int retval;
+
+	/* Tell our userspace app about this new request by queueing an input event */
+	uinput_dev_event(dev, EV_UINPUT, request->code, request->id);
+
+	/* Wait for the request to complete */
+	retval = wait_event_interruptible(request->waitq, request->completed);
+	if (retval)
+		request->retval = retval;
+
+	/* Release this request's ID, let others know it's available */
+	udev->requests[request->id] = NULL;
+	wake_up_interruptible(&udev->requests_waitq);
+}
+
 static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
 {
-	return 0;
+	struct uinput_request request;
+
+	if (!test_bit(EV_FF, dev->evbit))
+		return -ENOSYS;
+
+	uinput_request_init(dev, &request, UI_FF_UPLOAD);
+	if (request.retval)
+		return request.retval;
+	request.u.effect = effect;
+	uinput_request_submit(dev, &request);
+	return request.retval;
 }
 
 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
 {
-	return 0;
+	struct uinput_request request;
+
+	if (!test_bit(EV_FF, dev->evbit))
+		return -ENOSYS;
+
+	uinput_request_init(dev, &request, UI_FF_ERASE);
+	if (request.retval)
+		return request.retval;
+	request.u.effect_id = effect_id;
+	uinput_request_submit(dev, &request);
+	return request.retval;
 }
 
 static int uinput_create_device(struct uinput_device *udev)
@@ -116,6 +198,8 @@ static int uinput_open(struct inode *ino
 	if (!newdev)
 		goto error;
 	memset(newdev, 0, sizeof(struct uinput_device));
+	init_MUTEX(&newdev->requests_sem);
+	init_waitqueue_head(&newdev->requests_waitq);
 
 	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
 	if (!newinput)
@@ -138,12 +222,11 @@ static int uinput_validate_absbits(struc
 	unsigned int cnt;
 	int retval = 0;
 
-	for (cnt = 0; cnt < ABS_MAX; cnt++) {
+	for (cnt = 0; cnt < ABS_MAX + 1; cnt++) {
 		if (!test_bit(cnt, dev->absbit))
 			continue;
 
-		if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
-		    (dev->absmax[cnt] <= dev->absmin[cnt])) {
+		if ((dev->absmax[cnt] <= dev->absmin[cnt])) {
 			printk(KERN_DEBUG
 				"%s: invalid abs[%02x] min:%d max:%d\n",
 				UINPUT_NAME, cnt,
@@ -152,8 +235,7 @@ static int uinput_validate_absbits(struc
 			break;
 		}
 
-		if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
-		    (dev->absflat[cnt] > dev->absmax[cnt])) {
+		if (dev->absflat[cnt] > (dev->absmax[cnt] - dev->absmin[cnt])) {
 			printk(KERN_DEBUG
 				"%s: absflat[%02x] out of range: %d "
 				"(min:%d/max:%d)\n",
@@ -176,7 +258,7 @@ static int uinput_alloc_device(struct fi
 
 	retval = count;
 
-	udev = (struct uinput_device *)file->private_data;
+	udev = file->private_data;
 	dev = udev->dev;
 
 	user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
@@ -228,7 +310,7 @@ exit:
 
 static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct uinput_device	*udev = file->private_data;
+	struct uinput_device *udev = file->private_data;
 
 	if (test_bit(UIST_CREATED, &(udev->state))) {
 		struct input_event	ev;
@@ -279,9 +361,6 @@ static unsigned int uinput_poll(struct f
 {
 	struct uinput_device *udev = file->private_data;
 
-	if (!test_bit(UIST_CREATED, &(udev->state)))
-		return 0;
-
 	poll_wait(file, &udev->waitq, wait);
 
 	if (udev->head != udev->tail)
@@ -295,6 +374,11 @@ static int uinput_burn_device(struct uin
 	if (test_bit(UIST_CREATED, &(udev->state)))
 		uinput_destroy_device(udev);
 
+	if (NULL != udev->dev->name)
+		kfree(udev->dev->name);
+	if (NULL != udev->dev->phys)
+		kfree(udev->dev->phys);
+
 	kfree(udev->dev);
 	kfree(udev);
 
@@ -303,19 +387,35 @@ static int uinput_burn_device(struct uin
 
 static int uinput_close(struct inode *inode, struct file *file)
 {
-	return uinput_burn_device((struct uinput_device *)file->private_data);
+	return uinput_burn_device(file->private_data);
 }
 
 static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int			retval = 0;
 	struct uinput_device	*udev;
+	void __user             *p = (void __user *)arg;
+	struct uinput_ff_upload ff_up;
+	struct uinput_ff_erase  ff_erase;
+	struct uinput_request   *req;
+	int                     length;
 
-	udev = (struct uinput_device *)file->private_data;
+	udev = file->private_data;
 
 	/* device attributes can not be changed after the device is created */
-	if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
-		return -EINVAL;
+	switch (cmd) {
+		case UI_SET_EVBIT:
+		case UI_SET_KEYBIT:
+		case UI_SET_RELBIT:
+		case UI_SET_ABSBIT:
+		case UI_SET_MSCBIT:
+		case UI_SET_LEDBIT:
+		case UI_SET_SNDBIT:
+		case UI_SET_FFBIT:
+		case UI_SET_PHYS:
+			if (test_bit(UIST_CREATED, &(udev->state)))
+				return -EINVAL;
+	}
 
 	switch (cmd) {
 		case UI_DEV_CREATE:
@@ -390,13 +490,102 @@ static int uinput_ioctl(struct inode *in
 			set_bit(arg, udev->dev->ffbit);
 			break;
 
+		case UI_SET_PHYS:
+			length = strnlen_user(p, 1024);
+			if (length <= 0) {
+				retval = -EFAULT;
+				break;
+			}
+			if (NULL != udev->dev->phys)
+				kfree(udev->dev->phys);
+			udev->dev->phys = kmalloc(length, GFP_KERNEL);
+			if (!udev->dev->phys) {
+				retval = -ENOMEM;
+				break;
+			}
+			if (copy_from_user(udev->dev->phys, p, length)) {
+				retval = -EFAULT;
+				kfree(udev->dev->phys);
+				udev->dev->phys = NULL;
+				break;
+			}
+			udev->dev->phys[length-1] = '\0';
+			break;
+
+		case UI_BEGIN_FF_UPLOAD:
+			if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+				retval = -EINVAL;
+				break;
+			}
+			ff_up.retval = 0;
+			memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
+			if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			break;
+
+		case UI_BEGIN_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!(req && req->code==UI_FF_ERASE)) {
+				retval = -EINVAL;
+				break;
+			}
+			ff_erase.retval = 0;
+			ff_erase.effect_id = req->u.effect_id;
+			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			break;
+
+		case UI_END_FF_UPLOAD:
+			if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+				retval = -EINVAL;
+				break;
+			}
+			req->retval = ff_up.retval;
+			memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
+			req->completed = 1;
+			wake_up_interruptible(&req->waitq);
+			break;
+
+		case UI_END_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!(req && req->code==UI_FF_ERASE)) {
+				retval = -EINVAL;
+				break;
+			}
+			req->retval = ff_erase.retval;
+			req->completed = 1;
+			wake_up_interruptible(&req->waitq);
+			break;
+
 		default:
-			retval = -EFAULT;
+			retval = -EINVAL;
 	}
 	return retval;
 }
 
-struct file_operations uinput_fops = {
+static struct file_operations uinput_fops = {
 	.owner =	THIS_MODULE,
 	.open =		uinput_open,
 	.release =	uinput_close,
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -1,20 +1,20 @@
 #
 # Mouse driver configuration
 #
-config INPUT_MOUSE
-	bool "Mice"
+menuconfig INPUT_MOUSE
+	bool "Mouse"
 	default y
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported mice will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_MOUSE
+
 config MOUSE_PS2
 	tristate "PS/2 mouse"
 	default y
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
@@ -39,7 +39,6 @@ config MOUSE_PS2
 
 config MOUSE_SERIAL
 	tristate "Serial mouse"
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	---help---
 	  Say Y here if you have a serial (RS-232, COM port) mouse connected
@@ -53,7 +52,7 @@ config MOUSE_SERIAL
 
 config MOUSE_INPORT
 	tristate "InPort/MS/ATIXL busmouse"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
 	  They are rather rare these days.
@@ -69,7 +68,7 @@ config MOUSE_ATIXL
 
 config MOUSE_LOGIBM
 	tristate "Logitech busmouse"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y here if you have a Logitech busmouse.
 	  They are rather rare these days.
@@ -79,7 +78,7 @@ config MOUSE_LOGIBM
 
 config MOUSE_PC110PAD
 	tristate "IBM PC110 touchpad"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y if you have the IBM PC-110 micro-notebook and want its
 	  touchpad supported.
@@ -89,7 +88,7 @@ config MOUSE_PC110PAD
 
 config MOUSE_MAPLE
 	tristate "Maple bus mouse"
-	depends on SH_DREAMCAST && INPUT && INPUT_MOUSE && MAPLE
+	depends on SH_DREAMCAST && MAPLE
 	help
 	  Say Y if you have a DreamCast console and a mouse attached to
 	  its Maple bus.
@@ -99,7 +98,7 @@ config MOUSE_MAPLE
 
 config MOUSE_AMIGA
 	tristate "Amiga mouse"
-	depends on AMIGA && INPUT && INPUT_MOUSE
+	depends on AMIGA
 	help
 	  Say Y here if you have an Amiga and want its native mouse
 	  supported by the kernel.
@@ -109,7 +108,7 @@ config MOUSE_AMIGA
 
 config MOUSE_RISCPC
 	tristate "Acorn RiscPC mouse"
-	depends on ARCH_ACORN && INPUT && INPUT_MOUSE
+	depends on ARCH_ACORN
 	help
 	  Say Y here if you have the Acorn RiscPC computer and want its
 	  native mouse supported.
@@ -119,7 +118,6 @@ config MOUSE_RISCPC
 
 config MOUSE_VSXXXAA
 	tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet"
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	help
 	  Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
@@ -129,3 +127,12 @@ config MOUSE_VSXXXAA
 	  described in the source file). This driver also works with the
 	  digitizer (VSXXX-AB) DEC produced.
 
+config MOUSE_HIL
+	tristate "HIL pointers (mice etc)."     
+	depends on GSC
+	select HP_SDC
+	select HIL_MLC
+	help
+	  Say Y here to support HIL pointers.
+
+endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.
 obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
 obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
+obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
 psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
  * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
  * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
  *
  * ALPS detection, tap switching and status querying info is taken from
  * tpconfig utility (by C. Scott Ananian and Bruce Kall).
@@ -27,102 +28,122 @@
 #define dbg(format, arg...) do {} while (0)
 #endif
 
-#define ALPS_MODEL_GLIDEPOINT	1
-#define ALPS_MODEL_DUALPOINT	2
-
-struct alps_model_info {
-	unsigned char signature[3];
-	unsigned char model;
-} alps_model_data[] = {
-/*	{ { 0x33, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },	*/
-	{ { 0x53, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x53, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x73, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x73, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x28 },	ALPS_MODEL_GLIDEPOINT },
-/*	{ { 0x63, 0x02, 0x3c },	ALPS_MODEL_GLIDEPOINT },	*/
-/*	{ { 0x63, 0x02, 0x50 },	ALPS_MODEL_GLIDEPOINT },	*/
-	{ { 0x63, 0x02, 0x64 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x20, 0x02, 0x0e },	ALPS_MODEL_DUALPOINT },
-	{ { 0x22, 0x02, 0x0a },	ALPS_MODEL_DUALPOINT },
-	{ { 0x22, 0x02, 0x14 }, ALPS_MODEL_DUALPOINT },
-	{ { 0x63, 0x03, 0xc8 },	ALPS_MODEL_DUALPOINT },
+#define ALPS_DUALPOINT	0x01
+#define ALPS_WHEEL	0x02
+#define ALPS_FW_BK	0x04
+#define ALPS_4BTN	0x08
+#define ALPS_OLDPROTO	0x10
+#define ALPS_PASS	0x20
+
+static struct alps_model_info alps_model_data[] = {
+	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
+	{ { 0x53, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x53, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
+	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK },		/* NEC Versa L320 */
+	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
+	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
+	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
+	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 };
 
 /*
- * ALPS abolute Mode
- * byte 0:  1    1    1    1    1  mid0 rig0 lef0
+ * XXX - this entry is suspicious. First byte has zero lower nibble,
+ * which is what a normal mouse would report. Also, the value 0x0e
+ * isn't valid per PS/2 spec.
+ */
+
+/*
+ * ALPS abolute Mode - new format
+ * 
+ * byte 0:  1    ?    ?    ?    1    ?    ?    ? 
  * byte 1:  0   x6   x5   x4   x3   x2   x1   x0
- * byte 2:  0   x10  x9   x8   x7  up1  fin  ges
- * byte 3:  0   y9   y8   y7    1  mid1 rig1 lef1
+ * byte 2:  0   x10  x9   x8   x7    ?  fin  ges
+ * byte 3:  0   y9   y8   y7    1    M    R    L 
  * byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  * byte 5:  0   z6   z5   z4   z3   z2   z1   z0
  *
- * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad.
- * We just 'or' them together for now.
- *
- * We used to send 'ges'tures as BTN_TOUCH but this made it impossible
- * to disable tap events in the synaptics driver since the driver
- * was unable to distinguish a gesture tap from an actual button click.
- * A tap gesture now creates an emulated touch that the synaptics
- * driver can interpret as a tap event, if MaxTapTime=0 and
- * MaxTapMove=0 then the driver will ignore taps.
- *
- * The touchpad on an 'Acer Aspire' has 4 buttons:
- *   left,right,up,down.
- * This device always sets {mid,rig,lef}0 to 1 and
- * reflects left,right,down,up in lef1,rig1,mid1,up1.
+ * ?'s can have different meanings on different models,
+ * such as wheel rotation, extra buttons, stick buttons
+ * on a dualpoint, etc.
  */
 
 static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 {
+	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = &psmouse->dev;
-	int x, y, z;
-	int left = 0, right = 0, middle = 0;
+	struct input_dev *dev2 = &priv->dev2;
+	int x, y, z, ges, fin, left, right, middle;
 
 	input_regs(dev, regs);
 
 	if ((packet[0] & 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
-		x = packet[1];
-		if (packet[0] & 0x10)
-			x = x - 256;
-		y = packet[2];
-		if (packet[0] & 0x20)
-			y = y - 256;
-		left  = (packet[0]     ) & 1;
-		right = (packet[0] >> 1) & 1;
-
-		input_report_rel(dev, REL_X, x);
-		input_report_rel(dev, REL_Y, -y);
-		input_report_key(dev, BTN_A, left);
-		input_report_key(dev, BTN_B, right);
-		input_sync(dev);
+		input_report_key(dev2, BTN_LEFT,   packet[0] & 1);    
+		input_report_key(dev2, BTN_RIGHT,  packet[0] & 2);
+		input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
+		input_report_rel(dev2, REL_X,
+			packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
+		input_report_rel(dev2, REL_Y,
+			packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
+		input_sync(dev2);
 		return;
 	}
 
-	x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3));
-	y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4));
-	z = packet[5];
-
-	if (z == 127) {	/* DualPoint stick is relative, not absolute */
-		if (x > 383)
-			x = x - 768;
-		if (y > 255)
-			y = y - 512;
-		left  = packet[3] & 1;
-		right = (packet[3] >> 1) & 1;
-
-		input_report_rel(dev, REL_X, x);
-		input_report_rel(dev, REL_Y, -y);
-		input_report_key(dev, BTN_LEFT, left);
-		input_report_key(dev, BTN_RIGHT, right);
+	if (priv->i->flags & ALPS_OLDPROTO) {
+		left = packet[2] & 0x08;
+		right = packet[2] & 0x10;
+		middle = 0;
+		x = packet[1] | ((packet[0] & 0x07) << 7);
+		y = packet[4] | ((packet[3] & 0x07) << 7);
+		z = packet[5];
+	} else {
+		left = packet[3] & 1;
+		right = packet[3] & 2;
+		middle = packet[3] & 4;
+		x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
+		y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
+		z = packet[5];
+	}
+
+	ges = packet[2] & 1;
+	fin = packet[2] & 2;
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+	input_report_key(dev, BTN_MIDDLE, middle);
+
+	if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) {
+		input_report_rel(dev2, REL_X,  (x > 383 ? (x - 768) : x));
+		input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
 		input_sync(dev);
+		input_sync(dev2);
 		return;
 	}
 
+	/* Convert hardware tap to a reasonable Z value */
+	if (ges && !fin) z = 40;
+
+	/*
+	 * A "tap and drag" operation is reported by the hardware as a transition
+	 * from (!fin && ges) to (fin && ges). This should be translated to the
+	 * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually.
+	 */
+	if (ges && fin && !priv->prev_fin) {
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, 0);
+		input_report_key(dev, BTN_TOOL_FINGER, 0);
+		input_sync(dev);
+	}
+	priv->prev_fin = fin;
+
 	if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
 	if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
 
@@ -130,38 +151,26 @@ static void alps_process_packet(struct p
 		input_report_abs(dev, ABS_X, x);
 		input_report_abs(dev, ABS_Y, y);
 	}
+
 	input_report_abs(dev, ABS_PRESSURE, z);
 	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
-	left  |= (packet[2]     ) & 1;
-	left  |= (packet[3]     ) & 1;
-	right |= (packet[3] >> 1) & 1;
-	if (packet[0] == 0xff) {
-		int back    = (packet[3] >> 2) & 1;
-		int forward = (packet[2] >> 2) & 1;
-		if (back && forward) {
-			middle = 1;
-			back = 0;
-			forward = 0;
-		}
-		input_report_key(dev, BTN_BACK,    back);
-		input_report_key(dev, BTN_FORWARD, forward);
-	} else {
-		left   |= (packet[0]     ) & 1;
-		right  |= (packet[0] >> 1) & 1;
-		middle |= (packet[0] >> 2) & 1;
-		middle |= (packet[3] >> 2) & 1;
-	}
 
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
-	input_report_key(dev, BTN_MIDDLE, middle);
+	if (priv->i->flags & ALPS_WHEEL)
+		input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
+
+	if (priv->i->flags & ALPS_FW_BK) {
+		input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
+		input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+	}
 
 	input_sync(dev);
 }
 
 static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
+	struct alps_data *priv = psmouse->private;
+
 	if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
 		if (psmouse->pktcnt == 3) {
 			alps_process_packet(psmouse, regs);
@@ -170,13 +179,12 @@ static psmouse_ret_t alps_process_byte(s
 		return PSMOUSE_GOOD_DATA;
 	}
 
-	/* ALPS absolute mode packets start with 0b11111mrl */
-	if ((psmouse->packet[0] & 0xf8) != 0xf8)
+	if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0)
 		return PSMOUSE_BAD_DATA;
 
 	/* Bytes 2 - 6 should have 0 in the highest bit */
 	if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
-	    (psmouse->packet[psmouse->pktcnt-1] & 0x80))
+	    (psmouse->packet[psmouse->pktcnt - 1] & 0x80))
 		return PSMOUSE_BAD_DATA;
 
 	if (psmouse->pktcnt == 6) {
@@ -187,51 +195,58 @@ static psmouse_ret_t alps_process_byte(s
 	return PSMOUSE_GOOD_DATA;
 }
 
-int alps_get_model(struct psmouse *psmouse)
+static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
 	unsigned char param[4];
 	int i;
 
 	/*
 	 * First try "E6 report".
-	 * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
+	 * ALPS should return 0,0,10 or 0,0,100
 	 */
 	param[0] = 0;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11))
-		return -1;
+		return NULL;
 
 	param[0] = param[1] = param[2] = 0xff;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return -1;
+		return NULL;
 
 	dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
 
-	if (param[0] != 0x00 || param[1] != 0x00 || (param[2] != 0x0a && param[2] != 0x64))
-		return -1;
+	if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
+		return NULL;
 
-	/* Now try "E7 report". ALPS should return 0x33 in byte 1 */
+	/*
+	 * Now try "E7 report". Allowed responses are in
+	 * alps_model_data[].signature
+	 */
 	param[0] = 0;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21))
-		return -1;
+		return NULL;
 
 	param[0] = param[1] = param[2] = 0xff;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return -1;
+		return NULL;
 
 	dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
 
+	for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++);
+	*version = (param[0] << 8) | (param[1] << 4) | i;
+
 	for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
 		if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature)))
-			return alps_model_data[i].model;
+			return alps_model_data + i;
 
-	return -1;
+	return NULL;
 }
 
 /*
@@ -322,27 +337,30 @@ static int alps_tap_mode(struct psmouse 
 
 static int alps_reconnect(struct psmouse *psmouse)
 {
-	int model;
+	struct alps_data *priv = psmouse->private;
 	unsigned char param[4];
+	int version;
+
+	psmouse_reset(psmouse);
 
-	if ((model = alps_get_model(psmouse)) < 0)
+	if (!(priv->i = alps_get_model(psmouse, &version)))
 		return -1;
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
+	if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1))
 		return -1;
 
 	if (alps_get_status(psmouse, param))
 		return -1;
 
-	if (param[0] & 0x04)
-		alps_tap_mode(psmouse, 0);
+	if (!(param[0] & 0x04))
+		alps_tap_mode(psmouse, 1);
 
 	if (alps_absolute_mode(psmouse)) {
 		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
 		return -1;
 	}
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
+	if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0))
 		return -1;
 
 	return 0;
@@ -350,57 +368,83 @@ static int alps_reconnect(struct psmouse
 
 static void alps_disconnect(struct psmouse *psmouse)
 {
+	struct alps_data *priv = psmouse->private;
 	psmouse_reset(psmouse);
+	input_unregister_device(&priv->dev2);
+	kfree(priv);
 }
 
 int alps_init(struct psmouse *psmouse)
 {
+	struct alps_data *priv;
 	unsigned char param[4];
-	int model;
+	int version;
 
-	if ((model = alps_get_model(psmouse)) < 0)
-		return -1;
+	psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL);
+	if (!priv)
+		goto init_fail;
+	memset(priv, 0, sizeof(struct alps_data));
 
-	printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
-		model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
+	if (!(priv->i = alps_get_model(psmouse, &version)))
+		goto init_fail;
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
-		return -1;
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
+		goto init_fail;
 
 	if (alps_get_status(psmouse, param)) {
 		printk(KERN_ERR "alps.c: touchpad status report request failed\n");
-		return -1;
+		goto init_fail;
 	}
 
 	if (param[0] & 0x04) {
-		printk(KERN_INFO "  Disabling hardware tapping\n");
-		if (alps_tap_mode(psmouse, 0))
-			printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
+		printk(KERN_INFO "alps.c: Enabling hardware tapping\n");
+		if (alps_tap_mode(psmouse, 1))
+			printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
 	}
 
 	if (alps_absolute_mode(psmouse)) {
 		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
-		return -1;
+		goto init_fail;
 	}
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
-		return -1;
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
+		goto init_fail;
 
-	psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
-	psmouse->dev.relbit[LONG(REL_X)] |= BIT(REL_X);
-	psmouse->dev.relbit[LONG(REL_Y)] |= BIT(REL_Y);
-	psmouse->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A);
-	psmouse->dev.keybit[LONG(BTN_B)] |= BIT(BTN_B);
+	psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
+	psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
+	psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 
 	psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
 	input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0);
-	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1023, 0, 0);
+	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0);
 	input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
 
-	psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
-	psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
-	psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
-	psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+	if (priv->i->flags & ALPS_WHEEL) {
+		psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
+		psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
+	}
+
+	if (priv->i->flags & ALPS_FW_BK) {
+		psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
+		psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+	}
+
+	sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys);
+	priv->dev2.phys = priv->phys;
+	priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
+	priv->dev2.id.bustype = BUS_I8042;
+	priv->dev2.id.vendor = 0x0002;
+	priv->dev2.id.product = PSMOUSE_ALPS;
+	priv->dev2.id.version = 0x0000; 
+	
+	priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
+	priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+
+	input_register_device(&priv->dev2);
+
+	printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys);
 
 	psmouse->protocol_handler = alps_process_byte;
 	psmouse->disconnect = alps_disconnect;
@@ -408,16 +452,27 @@ int alps_init(struct psmouse *psmouse)
 	psmouse->pktsize = 6;
 
 	return 0;
+
+init_fail:
+	kfree(priv);
+	return -1;
 }
 
 int alps_detect(struct psmouse *psmouse, int set_properties)
 {
-	if (alps_get_model(psmouse) < 0)
+	int version;
+	struct alps_model_info *model; 
+
+	if (!(model = alps_get_model(psmouse, &version)))
 		return -1;
 
 	if (set_properties) {
 		psmouse->vendor = "ALPS";
-		psmouse->name = "TouchPad";
+		if (model->flags & ALPS_DUALPOINT) 
+			psmouse->name = "DualPoint TouchPad";
+		else
+			psmouse->name = "GlidePoint";
+		psmouse->model = version;
 	}
 	return 0;
 }
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -2,6 +2,7 @@
  * ALPS touchpad PS/2 mouse driver
  *
  * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
  *
  * 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
@@ -14,4 +15,18 @@
 int alps_detect(struct psmouse *psmouse, int set_properties);
 int alps_init(struct psmouse *psmouse);
 
+struct alps_model_info {
+        unsigned char signature[3];
+        unsigned char byte0, mask0;
+        unsigned char flags;
+};
+
+struct alps_data {
+	struct input_dev dev2;		/* Relative device */
+	char name[32];			/* Name */
+	char phys[32];			/* Phys */
+	struct alps_model_info *i; 	/* Info */
+	int prev_fin;			/* Finger bit from previous packet */
+};
+
 #endif
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/mouse/hil_ptr.c
@@ -0,0 +1,414 @@
+/*
+ * 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>
+#include <linux/pci_ids.h>
+
+#define PREFIX "HIL PTR: "
+#define HIL_GENERIC_NAME "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);
+	}
+	input_sync(dev);
+ 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 irqreturn_t hil_ptr_interrupt(struct serio *serio, 
+        unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct hil_ptr *ptr;
+	hil_packet packet;
+	int idx;
+
+	ptr = (struct hil_ptr *)serio->private;
+	if (ptr == NULL) {
+		BUG();
+		return IRQ_HANDLED;
+	}
+
+	if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_ptr_process_err(ptr);
+		return IRQ_HANDLED;
+	}
+	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 IRQ_HANDLED;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_ptr_process_err(ptr);
+		return IRQ_HANDLED;
+	}
+	if (packet & HIL_PKT_CMD) 
+		hil_ptr_process_record(ptr);
+	return IRQ_HANDLED;
+}
+
+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_driver *driver)
+{
+	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, driver)) 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));
+
+	init_input_dev(&ptr->dev);
+	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.id.bustype	= BUS_HIL;
+	ptr->dev.id.vendor	= PCI_VENDOR_ID_HP;
+	ptr->dev.id.product	= 0x0001; /* TODO: get from ptr->rsc */
+	ptr->dev.id.version	= 0x0100; /* TODO: get from ptr->rsc */
+	ptr->dev.dev		= &serio->dev;
+
+	input_register_device(&ptr->dev);
+	printk(KERN_INFO "input: %s (%s), ID: %d\n",
+                ptr->dev.name, 
+		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
+		did);
+
+	return;
+ bail1:
+	serio_close(serio);
+ bail0:
+	kfree(ptr);
+	return;
+}
+
+
+static struct serio_driver hil_ptr_serio_driver = {
+	.driver		= {
+		.name	= "hil_ptr",
+	},
+	.description	= "HP HIL mouse/tablet driver",
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
+};
+
+static int __init hil_ptr_init(void)
+{
+	serio_register_driver(&hil_ptr_serio_driver);
+        return 0;
+}
+                
+static void __exit hil_ptr_exit(void)
+{
+	serio_unregister_driver(&hil_ptr_serio_driver);
+}
+                        
+module_init(hil_ptr_init);
+module_exit(hil_ptr_exit);
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -202,6 +202,9 @@ static struct ps2pp_info *get_model_info
 	static struct ps2pp_info ps2pp_list[] = {
 		{ 12,	0,			PS2PP_SIDE_BTN},
 		{ 13,	0,			0 },
+		{ 15,	PS2PP_KIND_MX,					/* MX1000 */
+				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
 		{ 40,	0,			PS2PP_SIDE_BTN },
 		{ 41,	0,			PS2PP_SIDE_BTN },
 		{ 42,	0,			PS2PP_SIDE_BTN },
@@ -210,9 +213,9 @@ static struct ps2pp_info *get_model_info
 		{ 51,	0,			0 },
 		{ 52,	PS2PP_KIND_WHEEL,	PS2PP_SIDE_BTN | PS2PP_WHEEL },
 		{ 53,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
-		{ 61,	PS2PP_KIND_MX,
+		{ 61,	PS2PP_KIND_MX,					/* MX700 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX700 */
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
 		{ 73,	0,			PS2PP_SIDE_BTN },
 		{ 75,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
 		{ 76,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
@@ -222,15 +225,17 @@ static struct ps2pp_info *get_model_info
 		{ 88,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
 		{ 96,	0,			0 },
 		{ 97,	PS2PP_KIND_TP3,		PS2PP_WHEEL | PS2PP_HWHEEL },
-		{ 100,	PS2PP_KIND_MX,
+		{ 100,	PS2PP_KIND_MX,					/* MX510 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX510 */
-		{ 112,	PS2PP_KIND_MX,
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+		{ 111,  PS2PP_KIND_MX,					/* MX300 */
+				PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
+		{ 112,	PS2PP_KIND_MX,					/* MX500 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX500 */
-		{ 114,	PS2PP_KIND_MX,
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+		{ 114,	PS2PP_KIND_MX,					/* MX310 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN |
-				PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },	/* M310 */
+				PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
 		{ }
 	};
 	int i;
@@ -238,6 +243,8 @@ static struct ps2pp_info *get_model_info
 	for (i = 0; ps2pp_list[i].model; i++)
 		if (model == ps2pp_list[i].model)
 			return &ps2pp_list[i];
+
+	printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
 	return NULL;
 }
 
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -31,25 +31,30 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@s
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static char *psmouse_proto;
 static unsigned int psmouse_max_proto = -1U;
-module_param_named(proto, psmouse_proto, charp, 0);
-MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps). Useful for KVM switches.");
+static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
+static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
+static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
+#define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
+#define param_set_proto_abbrev			psmouse_set_maxproto
+#define param_get_proto_abbrev			psmouse_get_maxproto
+module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
+MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
 
 static unsigned int psmouse_resolution = 200;
-module_param_named(resolution, psmouse_resolution, uint, 0);
+module_param_named(resolution, psmouse_resolution, uint, 0644);
 MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
 
 static unsigned int psmouse_rate = 100;
-module_param_named(rate, psmouse_rate, uint, 0);
+module_param_named(rate, psmouse_rate, uint, 0644);
 MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
 
 static unsigned int psmouse_smartscroll = 1;
-module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
+module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
 static unsigned int psmouse_resetafter;
-module_param_named(resetafter, psmouse_resetafter, uint, 0);
+module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
 PSMOUSE_DEFINE_ATTR(rate);
@@ -142,7 +147,7 @@ static psmouse_ret_t psmouse_process_byt
 static irqreturn_t psmouse_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 	psmouse_ret_t rc;
 
 	if (psmouse->state == PSMOUSE_IGNORE)
@@ -423,7 +428,7 @@ static int psmouse_extensions(struct psm
  * upsets the thinkingmouse).
  */
 
-	if (max_proto > PSMOUSE_PS2 && thinking_detect(psmouse, set_properties) == 0)
+	if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_THINKPS;
 
 /*
@@ -513,13 +518,16 @@ static int psmouse_probe(struct psmouse 
 /*
  * First, we check if it's a mouse. It should send 0x00 or 0x03
  * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent
+ * ID queries, probably due to a firmware bug.
  */
 
 	param[0] = 0xa5;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
 		return -1;
 
-	if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+	if (param[0] != 0x00 && param[0] != 0x03 &&
+	    param[0] != 0x04 && param[0] != 0xff)
 		return -1;
 
 /*
@@ -634,7 +642,7 @@ static void psmouse_deactivate(struct ps
 
 static void psmouse_cleanup(struct serio *serio)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 
 	psmouse_reset(psmouse);
 }
@@ -651,11 +659,11 @@ static void psmouse_disconnect(struct se
 	device_remove_file(&serio->dev, &psmouse_attr_resolution);
 	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 
-	psmouse = serio->private;
+	psmouse = serio_get_drvdata(serio);
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		if (parent->pt_deactivate)
 			parent->pt_deactivate(parent);
 	}
@@ -667,6 +675,7 @@ static void psmouse_disconnect(struct se
 
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(psmouse);
 }
 
@@ -674,29 +683,29 @@ static void psmouse_disconnect(struct se
  * psmouse_connect() is a callback from the serio module when
  * an unhandled serio port is found.
  */
-static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
+static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct psmouse *psmouse, *parent = NULL;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
-	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
-		return;
+	int retval;
 
 	/*
 	 * If this is a pass-through port deactivate parent so the device
 	 * connected to this port can be successfully identified
 	 */
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 
-	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
+	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+		retval = -ENOMEM;
 		goto out;
+	}
 
 	memset(psmouse, 0, sizeof(struct psmouse));
 
 	ps2_init(&psmouse->ps2dev, serio);
+	sprintf(psmouse->phys, "%s/input0", serio->phys);
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
@@ -704,17 +713,20 @@ static void psmouse_connect(struct serio
 	psmouse->dev.dev = &serio->dev;
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
-	serio->private = psmouse;
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, psmouse);
+
+	retval = serio_open(serio, drv);
+	if (retval) {
+		serio_set_drvdata(serio, NULL);
 		kfree(psmouse);
-		serio->private = NULL;
 		goto out;
 	}
 
 	if (psmouse_probe(psmouse) < 0) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(psmouse);
-		serio->private = NULL;
+		retval = -ENODEV;
 		goto out;
 	}
 
@@ -731,8 +743,6 @@ static void psmouse_connect(struct serio
 
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-	sprintf(psmouse->phys, "%s/input0",
-		serio->phys);
 
 	psmouse->dev.name = psmouse->devname;
 	psmouse->dev.phys = psmouse->phys;
@@ -756,26 +766,22 @@ static void psmouse_connect(struct serio
 	device_create_file(&serio->dev, &psmouse_attr_resolution);
 	device_create_file(&serio->dev, &psmouse_attr_resetafter);
 
-	if (serio->child) {
-		/*
-		 * Nothing to be done here, serio core will detect that
-		 * the driver set serio->child and will register it for us.
-		 */
-		printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys);
-	}
-
 	psmouse_activate(psmouse);
 
+	retval = 0;
+
 out:
 	/* If this is a pass-through port the parent awaits to be activated */
 	if (parent)
 		psmouse_activate(parent);
+
+	return retval;
 }
 
 
 static int psmouse_reconnect(struct serio *serio)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 	struct psmouse *parent = NULL;
 	struct serio_driver *drv = serio->drv;
 	int rc = -1;
@@ -785,8 +791,8 @@ static int psmouse_reconnect(struct seri
 		return -1;
 	}
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 
@@ -820,12 +826,30 @@ out:
 	return rc;
 }
 
+static struct serio_device_id psmouse_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_PS_PSTHRU,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, psmouse_serio_ids);
 
 static struct serio_driver psmouse_drv = {
 	.driver		= {
 		.name	= "psmouse",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= psmouse_serio_ids,
 	.interrupt	= psmouse_interrupt,
 	.connect	= psmouse_connect,
 	.reconnect	= psmouse_reconnect,
@@ -848,7 +872,7 @@ ssize_t psmouse_attr_show_helper(struct 
 		goto out;
 	}
 
-	retval = handler(serio->private, buf);
+	retval = handler(serio_get_drvdata(serio), buf);
 
 out:
 	serio_unpin_driver(serio);
@@ -859,7 +883,8 @@ ssize_t psmouse_attr_set_helper(struct d
 				ssize_t (*handler)(struct psmouse *, const char *, size_t))
 {
 	struct serio *serio = to_serio_port(dev);
-	struct psmouse *psmouse = serio->private, *parent = NULL;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
+	struct psmouse *parent = NULL;
 	int retval;
 
 	retval = serio_pin_driver(serio);
@@ -871,8 +896,8 @@ ssize_t psmouse_attr_set_helper(struct d
 		goto out;
 	}
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 	psmouse_deactivate(psmouse);
@@ -942,28 +967,45 @@ static ssize_t psmouse_attr_set_resetaft
 	return count;
 }
 
-static inline void psmouse_parse_proto(void)
+static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 {
-	if (psmouse_proto) {
-		if (!strcmp(psmouse_proto, "bare"))
-			psmouse_max_proto = PSMOUSE_PS2;
-		else if (!strcmp(psmouse_proto, "imps"))
-			psmouse_max_proto = PSMOUSE_IMPS;
-		else if (!strcmp(psmouse_proto, "exps"))
-			psmouse_max_proto = PSMOUSE_IMEX;
-		else
-			printk(KERN_ERR "psmouse: unknown protocol type '%s'\n", psmouse_proto);
+	int i;
+
+	if (!val)
+		return -EINVAL;
+
+	if (!strncmp(val, "any", 3)) {
+		*((unsigned int *)kp->arg) = -1U;
+		return 0;
 	}
+
+	for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
+		if (!psmouse_proto_abbrev[i])
+			continue;
+
+		if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
+			*((unsigned int *)kp->arg) = i;
+			return 0;
+		}
+	}
+
+	return -EINVAL;					\
+}
+
+static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+{
+	return sprintf(buffer, "%s\n",
+			psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
+				psmouse_proto_abbrev[psmouse_max_proto] : "any");
 }
 
-int __init psmouse_init(void)
+static int __init psmouse_init(void)
 {
-	psmouse_parse_proto();
 	serio_register_driver(&psmouse_drv);
 	return 0;
 }
 
-void __exit psmouse_exit(void)
+static void __exit psmouse_exit(void)
 {
 	serio_unregister_driver(&psmouse_drv);
 }
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -44,7 +44,7 @@ struct psmouse {
 	unsigned char pktcnt;
 	unsigned char pktsize;
 	unsigned char type;
-	unsigned char model;
+	unsigned int model;
 	unsigned long last;
 	unsigned long out_of_sync;
 	enum psmouse_state state;
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -209,7 +209,7 @@ static void sermouse_process_ms(struct s
 static irqreturn_t sermouse_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct sermouse *sermouse = serio->private;
+	struct sermouse *sermouse = serio_get_drvdata(serio);
 
 	if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
 	sermouse->last = jiffies;
@@ -228,9 +228,11 @@ static irqreturn_t sermouse_interrupt(st
 
 static void sermouse_disconnect(struct serio *serio)
 {
-	struct sermouse *sermouse = serio->private;
+	struct sermouse *sermouse = serio_get_drvdata(serio);
+
 	input_unregister_device(&sermouse->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(sermouse);
 }
 
@@ -239,19 +241,17 @@ static void sermouse_disconnect(struct s
  * an unhandled serio port is found.
  */
 
-static void sermouse_connect(struct serio *serio, struct serio_driver *drv)
+static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct sermouse *sermouse;
 	unsigned char c;
+	int err;
 
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-
-	if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
-		return;
+	if (!serio->id.proto || serio->id.proto > SERIO_MZPP)
+		return -ENODEV;
 
 	if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(sermouse, 0, sizeof(struct sermouse));
 
@@ -261,10 +261,8 @@ static void sermouse_connect(struct seri
 	sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 	sermouse->dev.private = sermouse;
 
-	serio->private = sermouse;
-
-	sermouse->type = serio->type & SERIO_PROTO;
-	c = (serio->type & SERIO_EXTRA) >> 16;
+	sermouse->type = serio->id.proto;
+	c = serio->id.extra;
 
 	if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
 	if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
@@ -282,33 +280,88 @@ static void sermouse_connect(struct seri
 	sermouse->dev.id.version = 0x0100;
 	sermouse->dev.dev = &serio->dev;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, sermouse);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(sermouse);
-		return;
+		return err;
 	}
 
 	input_register_device(&sermouse->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
+
+	return 0;
 }
 
+static struct serio_device_id sermouse_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MSC,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SUN,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MS,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZ,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZPP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
+
 static struct serio_driver sermouse_drv = {
 	.driver		= {
 		.name	= "sermouse",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= sermouse_serio_ids,
 	.interrupt	= sermouse_interrupt,
 	.connect	= sermouse_connect,
 	.disconnect	= sermouse_disconnect,
 };
 
-int __init sermouse_init(void)
+static int __init sermouse_init(void)
 {
 	serio_register_driver(&sermouse_drv);
 	return 0;
 }
 
-void __exit sermouse_exit(void)
+static void __exit sermouse_exit(void)
 {
 	serio_unregister_driver(&sermouse_drv);
 }
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -143,39 +143,6 @@ static int synaptics_identify(struct psm
 	return -1;
 }
 
-static void print_ident(struct synaptics_data *priv)
-{
-	printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
-	printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
-	       SYN_ID_MINOR(priv->identity));
-	if (SYN_MODEL_ROT180(priv->model_id))
-		printk(KERN_INFO " 180 degree mounted touchpad\n");
-	if (SYN_MODEL_PORTRAIT(priv->model_id))
-		printk(KERN_INFO " portrait touchpad\n");
-	printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
-	if (SYN_MODEL_NEWABS(priv->model_id))
-		printk(KERN_INFO " new absolute packet format\n");
-	if (SYN_MODEL_PEN(priv->model_id))
-		printk(KERN_INFO " pen detection\n");
-
-	if (SYN_CAP_EXTENDED(priv->capabilities)) {
-		printk(KERN_INFO " Touchpad has extended capability bits\n");
-		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
-			printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
-			       (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
-		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
-			printk(KERN_INFO " -> middle button\n");
-		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
-			printk(KERN_INFO " -> four buttons\n");
-		if (SYN_CAP_MULTIFINGER(priv->capabilities))
-			printk(KERN_INFO " -> multifinger detection\n");
-		if (SYN_CAP_PALMDETECT(priv->capabilities))
-			printk(KERN_INFO " -> palm detection\n");
-		if (SYN_CAP_PASS_THROUGH(priv->capabilities))
-			printk(KERN_INFO " -> pass-through port\n");
-	}
-}
-
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
 	int retries = 0;
@@ -229,7 +196,7 @@ static void synaptics_set_rate(struct ps
  ****************************************************************************/
 static int synaptics_pt_write(struct serio *serio, unsigned char c)
 {
-	struct psmouse *parent = serio->parent->private;
+	struct psmouse *parent = serio_get_drvdata(serio->parent);
 	char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 
 	if (psmouse_sliced_command(parent, c))
@@ -246,7 +213,7 @@ static inline int synaptics_is_pt_packet
 
 static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
 {
-	struct psmouse *child = ptport->private;
+	struct psmouse *child = serio_get_drvdata(ptport);
 
 	if (child && child->state == PSMOUSE_ACTIVATED) {
 		serio_interrupt(ptport, packet[1], 0, NULL);
@@ -260,7 +227,8 @@ static void synaptics_pass_pt_packet(str
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-	struct psmouse *child = psmouse->ps2dev.serio->child->private;
+	struct serio *ptport = psmouse->ps2dev.serio->child;
+	struct psmouse *child = serio_get_drvdata(ptport);
 	struct synaptics_data *priv = psmouse->private;
 
 	/* adjust the touchpad to child's choice of protocol */
@@ -287,7 +255,7 @@ static void synaptics_pt_create(struct p
 
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type = SERIO_PS_PSTHRU;
+	serio->id.type = SERIO_PS_PSTHRU;
 	strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
 	strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
 	serio->write = synaptics_pt_write;
@@ -295,7 +263,8 @@ static void synaptics_pt_create(struct p
 
 	psmouse->pt_activate = synaptics_pt_activate;
 
-	psmouse->ps2dev.serio->child = serio;
+	printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
+	serio_register_port(serio);
 }
 
 /*****************************************************************************
@@ -322,8 +291,11 @@ static void synaptics_parse_hw_state(uns
 		hw->left  = (buf[0] & 0x01) ? 1 : 0;
 		hw->right = (buf[0] & 0x02) ? 1 : 0;
 
-		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
 			hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+			if (hw->w == 2)
+				hw->scroll = (signed char)(buf[1]);
+		}
 
 		if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
 			hw->up   = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
@@ -379,6 +351,26 @@ static void synaptics_process_packet(str
 
 	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
+	if (hw.scroll) {
+		priv->scroll += hw.scroll;
+
+		while (priv->scroll >= 4) {
+			input_report_key(dev, BTN_BACK, !hw.down);
+			input_sync(dev);
+			input_report_key(dev, BTN_BACK, hw.down);
+			input_sync(dev);
+			priv->scroll -= 4;
+		}
+		while (priv->scroll <= -4) {
+			input_report_key(dev, BTN_FORWARD, !hw.up);
+			input_sync(dev);
+			input_report_key(dev, BTN_FORWARD, hw.up);
+			input_sync(dev);
+			priv->scroll += 4;
+		}
+		return;
+	}
+
 	if (hw.z > 0) {
 		num_fingers = 1;
 		finger_width = 5;
@@ -528,7 +520,8 @@ static void set_input_params(struct inpu
 	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
 		set_bit(BTN_MIDDLE, dev->keybit);
 
-	if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+	if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
+	    SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
 		set_bit(BTN_FORWARD, dev->keybit);
 		set_bit(BTN_BACK, dev->keybit);
 	}
@@ -551,6 +544,7 @@ static void synaptics_disconnect(struct 
 {
 	synaptics_reset(psmouse);
 	kfree(psmouse->private);
+	psmouse->private = NULL;
 }
 
 static int synaptics_reconnect(struct psmouse *psmouse)
@@ -604,6 +598,20 @@ int synaptics_detect(struct psmouse *psm
 	return 0;
 }
 
+#if defined(__i386__)
+#include <linux/dmi.h>
+static struct dmi_system_id toshiba_dmi_table[] = {
+	{
+		.ident = "Toshiba Satellite",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"),
+		},
+	},
+	{ }
+};
+#endif
+
 int synaptics_init(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv;
@@ -625,10 +633,11 @@ int synaptics_init(struct psmouse *psmou
 
 	priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
 
-	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
-		synaptics_pt_create(psmouse);
+	printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+		SYN_ID_MODEL(priv->identity),
+		SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
+		priv->model_id, priv->capabilities, priv->ext_cap);
 
-	print_ident(priv);
 	set_input_params(&psmouse->dev, priv);
 
 	psmouse->protocol_handler = synaptics_process_byte;
@@ -637,6 +646,21 @@ int synaptics_init(struct psmouse *psmou
 	psmouse->reconnect = synaptics_reconnect;
 	psmouse->pktsize = 6;
 
+	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+		synaptics_pt_create(psmouse);
+
+#if defined(__i386__)
+	/*
+	 * Toshiba's KBC seems to have trouble handling data from
+	 * Synaptics as full rate, switch to lower rate which is roughly
+	 * thye same as rate of standard PS/2 mouse.
+	 */
+	if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
+		printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n");
+		psmouse->rate = 40;
+	}
+#endif
+
 	return 0;
 
  init_fail:
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -92,6 +92,7 @@ struct synaptics_hw_state {
 	unsigned int up:1;
 	unsigned int down:1;
 	unsigned char ext_buttons;
+	signed char scroll;
 };
 
 struct synaptics_data {
@@ -103,6 +104,7 @@ struct synaptics_data {
 
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
+	int scroll;
 };
 
 #endif /* _SYNAPTICS_H */
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -470,7 +470,7 @@ static irqreturn_t
 vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
 		struct pt_regs *regs)
 {
-	struct vsxxxaa *mouse = serio->private;
+	struct vsxxxaa *mouse = serio_get_drvdata (serio);
 
 	vsxxxaa_queue_byte (mouse, data);
 	vsxxxaa_parse_buffer (mouse, regs);
@@ -481,25 +481,22 @@ vsxxxaa_interrupt (struct serio *serio, 
 static void
 vsxxxaa_disconnect (struct serio *serio)
 {
-	struct vsxxxaa *mouse = serio->private;
+	struct vsxxxaa *mouse = serio_get_drvdata (serio);
 
 	input_unregister_device (&mouse->dev);
 	serio_close (serio);
+	serio_set_drvdata (serio, NULL);
 	kfree (mouse);
 }
 
-static void
+static int
 vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
 {
 	struct vsxxxaa *mouse;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-	if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA)
-		return;
+	int err;
 
 	if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset (mouse, 0, sizeof (struct vsxxxaa));
 
@@ -522,7 +519,6 @@ vsxxxaa_connect (struct serio *serio, st
 	mouse->dev.absmax[ABS_Y] = 1023;
 
 	mouse->dev.private = mouse;
-	serio->private = mouse;
 
 	sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
 	sprintf (mouse->phys, "%s/input0", serio->phys);
@@ -532,9 +528,13 @@ vsxxxaa_connect (struct serio *serio, st
 	mouse->dev.dev = &serio->dev;
 	mouse->serio = serio;
 
-	if (serio_open (serio, drv)) {
+	serio_set_drvdata (serio, mouse);
+
+	err = serio_open (serio, drv);
+	if (err) {
+		serio_set_drvdata (serio, NULL);
 		kfree (mouse);
-		return;
+		return err;
 	}
 
 	/*
@@ -546,26 +546,41 @@ vsxxxaa_connect (struct serio *serio, st
 	input_register_device (&mouse->dev);
 
 	printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys);
+
+	return 0;
 }
 
+static struct serio_device_id vsxxaa_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_VSXXXAA,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, vsxxaa_serio_ids);
+
 static struct serio_driver vsxxxaa_drv = {
 	.driver		= {
 		.name	= "vsxxxaa",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= vsxxaa_serio_ids,
 	.connect	= vsxxxaa_connect,
 	.interrupt	= vsxxxaa_interrupt,
 	.disconnect	= vsxxxaa_disconnect,
 };
 
-int __init
+static int __init
 vsxxxaa_init (void)
 {
 	serio_register_driver(&vsxxxaa_drv);
 	return 0;
 }
 
-void __exit
+static void __exit
 vsxxxaa_exit (void)
 {
 	serio_unregister_driver(&vsxxxaa_drv);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -71,6 +71,7 @@ struct mousedev {
 	struct mousedev_hw_data packet;
 	unsigned int pkt_count;
 	int old_x[4], old_y[4];
+	int frac_dx, frac_dy;
 	unsigned long touch;
 };
 
@@ -100,6 +101,7 @@ struct mousedev_list {
 	unsigned char ready, buffer, bufsiz;
 	unsigned char imexseq, impsseq;
 	enum mousedev_emul mode;
+	unsigned long last_buttons;
 };
 
 #define MOUSEDEV_SEQ_LEN	6
@@ -117,24 +119,31 @@ static struct mousedev mousedev_mix;
 
 static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
 {
-	int size;
+	int size, tmp;
+	enum { FRACTION_DENOM = 128 };
 
 	if (mousedev->touch) {
+		size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+		if (size == 0) size = 256 * 2;
 		switch (code) {
 			case ABS_X:
-				size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
-				if (size == 0) size = xres;
 				fx(0) = value;
-				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) * xres / (size * 2);
+				if (mousedev->pkt_count >= 2) {
+					tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+					tmp += mousedev->frac_dx;
+					mousedev->packet.dx = tmp / FRACTION_DENOM;
+					mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+				}
 				break;
 
 			case ABS_Y:
-				size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
-				if (size == 0) size = yres;
 				fy(0) = value;
-				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) * yres / (size * 2);
+				if (mousedev->pkt_count >= 2) {
+					tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+					tmp += mousedev->frac_dy;
+					mousedev->packet.dy = tmp / FRACTION_DENOM;
+					mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+				}
 				break;
 		}
 	}
@@ -216,7 +225,7 @@ static void mousedev_notify_readers(stru
 		spin_lock_irqsave(&list->packet_lock, flags);
 
 		p = &list->packets[list->head];
-		if (list->ready && p->buttons != packet->buttons) {
+		if (list->ready && p->buttons != mousedev->packet.buttons) {
 			unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
 			if (new_head != list->tail) {
 				p = &list->packets[list->head = new_head];
@@ -241,10 +250,13 @@ static void mousedev_notify_readers(stru
 		p->dz += packet->dz;
 		p->buttons = mousedev->packet.buttons;
 
-		list->ready = 1;
+		if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
+			list->ready = 1;
 
 		spin_unlock_irqrestore(&list->packet_lock, flags);
-		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+
+		if (list->ready)
+			kill_fasync(&list->fasync, SIGIO, POLL_IN);
 	}
 
 	wake_up_interruptible(&mousedev->wait);
@@ -268,6 +280,8 @@ static void mousedev_touchpad_touch(stru
 			clear_bit(0, &mousedev_mix.packet.buttons);
 		}
 		mousedev->touch = mousedev->pkt_count = 0;
+		mousedev->frac_dx = 0;
+		mousedev->frac_dy = 0;
 	}
 	else
 		if (!mousedev->touch)
@@ -445,7 +459,7 @@ static void mousedev_packet(struct mouse
 
 	switch (list->mode) {
 		case MOUSEDEV_EMUL_EXPS:
-			ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+			ps2_data[3] = mousedev_limit_delta(p->dz, 7);
 			p->dz -= ps2_data[3];
 			ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
 			list->bufsiz = 4;
@@ -467,9 +481,10 @@ static void mousedev_packet(struct mouse
 	}
 
 	if (!p->dx && !p->dy && !p->dz) {
-		if (list->tail == list->head)
+		if (list->tail == list->head) {
 			list->ready = 0;
-		else
+			list->last_buttons = p->buttons;
+		} else
 			list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
 	}
 
@@ -585,12 +600,11 @@ static unsigned int mousedev_poll(struct
 {
 	struct mousedev_list *list = file->private_data;
 	poll_wait(file, &list->mousedev->wait, wait);
-	if (list->ready || list->buffer)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
+		(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-struct file_operations mousedev_fops = {
+static struct file_operations mousedev_fops = {
 	.owner =	THIS_MODULE,
 	.read =		mousedev_read,
 	.write =	mousedev_write,
@@ -643,6 +657,7 @@ static struct input_handle *mousedev_con
 static void mousedev_disconnect(struct input_handle *handle)
 {
 	struct mousedev *mousedev = handle->private;
+	struct mousedev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	devfs_remove("input/mouse%d", mousedev->minor);
@@ -650,6 +665,9 @@ static void mousedev_disconnect(struct i
 
 	if (mousedev->open) {
 		input_close_device(handle);
+		wake_up_interruptible(&mousedev->wait);
+		list_for_each_entry(list, &mousedev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else {
 		if (mousedev_mix.open)
 			input_close_device(handle);
diff --git a/drivers/input/power.c b/drivers/input/power.c
--- a/drivers/input/power.c
+++ b/drivers/input/power.c
@@ -58,8 +58,6 @@ static void power_event(struct input_han
 
 	printk("Entering power_event\n");
 
-	if (type != EV_KEY || type != EV_PWR) return;
-
 	if (type == EV_PWR) {
 		switch (code) {
 			case KEY_SUSPEND:
@@ -76,7 +74,9 @@ static void power_event(struct input_han
 			default:
 				return;
 		}
-	} else {
+	}
+
+	if (type == EV_KEY) {
 		switch (code) {
 			case KEY_SUSPEND:
 				printk("Powering down input device\n");
@@ -103,12 +103,6 @@ static struct input_handle *power_connec
 {
 	struct input_handle *handle;
 
-	if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
-		return NULL;
-
-	if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
-		return NULL;
-
 	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
 		return NULL;
 	memset(handle, 0, sizeof(struct input_handle));
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -2,11 +2,11 @@
 # Input core configuration
 #
 config SERIO
-	tristate "Serial i/o support" if EMBEDDED || !X86
+	tristate "Serial I/O support" if EMBEDDED || !X86
 	default y
 	---help---
 	  Say Yes here if you have any input device that uses serial I/O to
-	  communicate with the system. This includes the 
+	  communicate with the system. This includes the
 	  		* standard AT keyboard and PS/2 mouse *
 	  as well as serial mice, Sun keyboards, some joysticks and 6dof
 	  devices and more.
@@ -16,10 +16,11 @@ config SERIO
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio.
 
+if SERIO
+
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
-	select SERIO
 	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
 	---help---
 	  i8042 is the chip over which the standard AT keyboard and PS/2
@@ -34,7 +35,6 @@ config SERIO_I8042
 config SERIO_SERPORT
 	tristate "Serial port line discipline"
 	default y
-	depends on SERIO
 	---help---
 	  Say Y here if you plan to use an input device (mouse, joystick,
 	  tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -48,8 +48,7 @@ config SERIO_SERPORT
 
 config SERIO_CT82C710
 	tristate "ct82c710 Aux port controller"
-	depends on SERIO
-	depends on !PARISC
+	depends on X86
 	---help---
 	  Say Y here if you have a Texas Instruments TravelMate notebook
 	  equipped with the ct82c710 chip and want to use a mouse connected
@@ -62,11 +61,11 @@ config SERIO_CT82C710
 
 config SERIO_Q40KBD
 	tristate "Q40 keyboard controller"
-	depends on Q40 && SERIO
+	depends on Q40
 
 config SERIO_PARKBD
 	tristate "Parallel port keyboard adapter"
-	depends on SERIO && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you built a simple parallel port adapter to attach
 	  an additional AT keyboard, XT keyboard or PS/2 mouse.
@@ -80,7 +79,7 @@ config SERIO_PARKBD
 
 config SERIO_RPCKBD
 	tristate "Acorn RiscPC keyboard controller"
-	depends on (ARCH_ACORN || ARCH_CLPS7500) && SERIO
+	depends on ARCH_ACORN || ARCH_CLPS7500
 	default y
 	help
 	  Say Y here if you have the Acorn RiscPC and want to use an AT
@@ -91,15 +90,15 @@ config SERIO_RPCKBD
 
 config SERIO_AMBAKMI
 	tristate "AMBA KMI keyboard controller"
-	depends on ARM_AMBA && SERIO
+	depends on ARM_AMBA
 
 config SERIO_SA1111
 	tristate "Intel SA1111 keyboard controller"
-	depends on SA1111 && SERIO
+	depends on SA1111
 
 config SERIO_GSCPS2
 	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
-	depends on GSC && SERIO
+	depends on GSC
 	default y
 	help
 	  This driver provides support for the PS/2 ports on PA-RISC machines
@@ -111,9 +110,35 @@ config SERIO_GSCPS2
 	  To compile this driver as a module, choose M here: the
 	  module will be called gscps2.
 
+config HP_SDC
+	tristate "HP System Device Controller i8042 Support"
+	depends on GSC && SERIO
+	default y
+	---help---
+	  This option enables supports for the the "System Device
+	  Controller", an i8042 carrying microcode to manage a
+	  few miscellanous devices on some Hewlett Packard systems.
+	  The SDC itself contains a 10ms resolution timer/clock capable
+	  of delivering interrupts on a periodic and one-shot basis.
+	  The SDC may also be connected to a battery-backed real-time
+	  clock, a basic audio waveform generator, and an HP-HIL Master
+	  Link Controller serving up to seven input devices.
+
+	  By itself this option is rather useless, but enabling it will
+	  enable selection of drivers for the abovementioned devices.
+	  It is, however, incompatible with the old, reliable HIL keyboard
+	  driver, and the new HIL driver is experimental, so if you plan
+	  to use a HIL keyboard as your primary keyboard, you may wish
+	  to keep using that driver until the new HIL drivers have had
+	  more testing.
+
+config HIL_MLC
+	tristate "HIL MLC Support (needed for HIL input devices)"
+	depends on HP_SDC
+
 config SERIO_PCIPS2
 	tristate "PCI PS/2 keyboard and PS/2 mouse controller"
-	depends on PCI && SERIO
+	depends on PCI
 	help
 	  Say Y here if you have a Mobility Docking station with PS/2
 	  keyboard and mice ports.
@@ -123,7 +148,7 @@ config SERIO_PCIPS2
 
 config SERIO_MACEPS2
 	tristate "SGI O2 MACE PS/2 controller"
-	depends on SGI_IP32 && SERIO
+	depends on SGI_IP32
 	help
 	  Say Y here if you have SGI O2 workstation and want to use its
 	  PS/2 ports.
@@ -133,7 +158,6 @@ config SERIO_MACEPS2
 
 config SERIO_LIBPS2
 	tristate "PS/2 driver library" if EMBEDDED
-	depends on SERIO
 	help
 	  Say Y here if you are using a driver for device connected
 	  to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
@@ -143,7 +167,6 @@ config SERIO_LIBPS2
 
 config SERIO_RAW
 	tristate "Raw access to serio ports"
-	depends on SERIO
 	help
 	  Say Y here if you want to have raw access to serio ports, such as
 	  AUX ports on i8042 keyboard controller. Each serio port that is
@@ -156,3 +179,5 @@ config SERIO_RAW
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio_raw.
+
+endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -15,6 +15,8 @@ obj-$(CONFIG_SERIO_AMBAKMI)	+= ambakmi.o
 obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 obj-$(CONFIG_SERIO_98KBD)	+= 98kbd-io.o
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
+obj-$(CONFIG_HP_SDC)		+= hp_sdc.o
+obj-$(CONFIG_HIL_MLC)		+= hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -134,7 +134,7 @@ static int amba_kmi_probe(struct amba_de
 	memset(kmi, 0, sizeof(struct amba_kmi_port));
 	memset(io, 0, sizeof(struct serio));
 
-	io->type	= SERIO_8042;
+	io->id.type	= SERIO_8042;
 	io->write	= amba_kmi_write;
 	io->open	= amba_kmi_open;
 	io->close	= amba_kmi_close;
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -181,7 +181,7 @@ static struct serio * __init ct82c710_al
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type = SERIO_8042;
+		serio->id.type = SERIO_8042;
 		serio->open = ct82c710_open;
 		serio->close = ct82c710_close;
 		serio->write = ct82c710_write;
@@ -193,7 +193,7 @@ static struct serio * __init ct82c710_al
 	return serio;
 }
 
-int __init ct82c710_init(void)
+static int __init ct82c710_init(void)
 {
 	if (ct82c710_probe())
 		return -ENODEV;
@@ -215,7 +215,7 @@ int __init ct82c710_init(void)
 	return 0;
 }
 
-void __exit ct82c710_exit(void)
+static void __exit ct82c710_exit(void)
 {
 	serio_unregister_port(ct82c710_port);
 	platform_device_unregister(ct82c710_device);
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2004 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
- * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
  *
  * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
  * 	Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca>
@@ -37,8 +37,8 @@
 #include <asm/io.h>
 #include <asm/parisc-device.h>
 
-MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>, Helge Deller <deller@gmx.de>");
-MODULE_DESCRIPTION("HP GSC PS/2 port driver");
+MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP GSC PS2 port driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
 
@@ -363,11 +363,7 @@ static int __init gscps2_probe(struct pa
 	snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
 		 (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
 	strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
-	serio->idbus		= BUS_GSC;
-	serio->idvendor		= PCI_VENDOR_ID_HP;
-	serio->idproduct	= 0x0001;
-	serio->idversion	= 0x0010;
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= gscps2_write;
 	serio->open		= gscps2_open;
 	serio->close		= gscps2_close;
@@ -448,7 +444,7 @@ static struct parisc_device_id gscps2_de
 };
 
 static struct parisc_driver parisc_ps2_driver = {
-	.name		= "GSC PS/2",
+	.name		= "GSC PS2",
 	.id_table	= gscps2_device_tbl,
 	.probe		= gscps2_probe,
 	.remove		= gscps2_remove,
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/serio/hil_mlc.c
@@ -0,0 +1,949 @@
+/*
+ * 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 tasklet 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 DEFINE_RWLOCK(hil_mlcs_lock);
+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_driver *drv;
+
+	i = cnt = 0;
+	did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8;
+	serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL;
+	drv = (serio != NULL) ? serio->drv : NULL;
+
+	while (mlc->icount < 15 - i) {
+		hil_packet p;
+		p = mlc->ipacket[i];
+		if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
+			if (drv == NULL || drv->interrupt == NULL) goto skip;
+
+			drv->interrupt(serio, 0, 0, NULL);
+			drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+			drv->interrupt(serio, HIL_PKT_CMD >> 8,  0, NULL);
+			drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL);
+		skip:
+			did = (p & HIL_PKT_ADDR_MASK) >> 8;
+			serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
+			drv = (serio != NULL) ? serio->drv : NULL;
+			cnt = 0;
+		}
+		cnt++; i++;
+		if (drv == NULL || drv->interrupt == NULL) continue;
+		drv->interrupt(serio, (p >> 24), 0, NULL);
+		drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL);
+		drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL);
+		drv->interrupt(serio, p & 0xff, 0, NULL);
+	}
+}
+
+/*************************** 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_driver *drv;
+	uint8_t *idx, *last;
+
+	map = serio->port_data;
+	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:
+	drv = serio->drv;
+	if (drv == NULL) {
+		BUG();
+		return -EIO;
+	}
+	last = idx + 15;
+	while ((last != idx) && (*last == 0)) last--;
+
+	while (idx != last) {
+		drv->interrupt(serio, 0, 0, NULL);
+		drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+		drv->interrupt(serio, 0, 0, NULL);
+		drv->interrupt(serio, *idx, 0, NULL);
+		idx++;
+	}
+	drv->interrupt(serio, 0, 0, NULL);
+	drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+	drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
+	drv->interrupt(serio, *idx, 0, NULL);
+	
+	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->port_data;
+	if (map == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void hil_mlc_serio_close(struct serio *serio) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+
+	map = serio->port_data;
+	if (map == NULL) {
+		BUG();
+		return;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return;
+	}
+
+	serio->private = NULL;
+	serio->drv = NULL;
+	/* TODO wake up interruptable */
+}
+
+int hil_mlc_register(hil_mlc *mlc) {
+	int i;
+        unsigned long flags;
+
+	if (mlc == NULL) {
+		return -EINVAL;
+	}
+
+	mlc->istarted = 0;
+        mlc->ostarted = 0;
+
+        rwlock_init(&mlc->lock);
+        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++) {
+		struct serio *mlc_serio;
+		hil_mlc_copy_di_scratch(mlc, i);
+		mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL);
+		mlc->serio[i] = mlc_serio;
+		memset(mlc_serio, 0, sizeof(*mlc_serio));
+		mlc_serio->type			= SERIO_HIL | SERIO_HIL_MLC;
+		mlc_serio->write		= hil_mlc_serio_write;
+		mlc_serio->open			= hil_mlc_serio_open;
+		mlc_serio->close		= hil_mlc_serio_close;
+		mlc_serio->port_data		= &(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);
+	}
+
+	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);
+
+	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
+		serio_unregister_port(mlc->serio[i]);
+		mlc->serio[i] = NULL;
+	}
+
+	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 --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/serio/hp_sdc.c
@@ -0,0 +1,1054 @@
+/*
+ * 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>
+
+/* Machine-specific abstraction */
+
+#if defined(__hppa__)
+# include <asm/parisc-device.h>
+# define sdc_readb(p)		gsc_readb(p)
+# define sdc_writeb(v,p)	gsc_writeb((v),(p))
+#elif defined(__mc68000__)
+# include <asm/uaccess.h>
+# define sdc_readb(p)		in_8(p)
+# define sdc_writeb(v,p)	out_8((p),(v))
+#else
+# error "HIL is not supported on this platform"
+#endif
+
+#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 = sdc_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 sdc_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;
+	sdc_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;
+	sdc_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 (sdc_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 irqreturn_t 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 IRQ_HANDLED;
+	}
+
+	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;
+	}
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t 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
+	return IRQ_HANDLED;
+}
+
+
+/***************** 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) {
+	unsigned long flags;
+	int i;
+
+	if (this == NULL) {
+		tasklet_schedule(&hp_sdc.task);
+		return -EINVAL;
+	};
+
+	write_lock_irqsave(&hp_sdc.lock, flags);
+
+	/* 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;
+			write_unlock_irqrestore(&hp_sdc.lock, flags);
+			tasklet_schedule(&hp_sdc.task);
+			return 0;
+		}
+	}
+	write_unlock_irqrestore(&hp_sdc.lock, flags);
+	printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
+	return -EBUSY;
+
+ fail:
+	write_unlock_irqrestore(&hp_sdc.lock,flags);
+	printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
+	return -EINVAL;
+}
+
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
+	unsigned long flags;
+	int i;
+
+	write_lock_irqsave(&hp_sdc.lock, flags);
+
+	/* 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_irqrestore(&hp_sdc.lock, flags);
+	return 0;
+}
+
+
+
+/********************** User context functions **************************/
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.timer != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		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) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.hil != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EBUSY;
+	}
+
+	hp_sdc.hil = callback;
+	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+	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) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.cooked != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EBUSY;
+	}
+
+	/* Enable interrupts from the HIL MLC */
+	hp_sdc.cooked = callback;
+	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+	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);
+
+	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_IM_RESET);
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	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_IM_RESET);
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	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 ***************************/
+
+#if defined(__hppa__)
+
+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_hppa(struct parisc_device *d);
+
+static struct parisc_driver hp_sdc_driver = {
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init_hppa,
+};
+
+#endif /* __hppa__ */
+
+static int __init hp_sdc_init(void)
+{
+	int i;
+	char *errstr;
+	hp_sdc_transaction t_sync;
+	uint8_t ts_sync[6];
+	struct semaphore s_sync;
+
+  	rwlock_init(&hp_sdc.lock);
+  	rwlock_init(&hp_sdc.ibf_lock);
+  	rwlock_init(&hp_sdc.rtq_lock);
+  	rwlock_init(&hp_sdc.hook_lock);
+
+	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;
+
+#if defined(__hppa__)
+	errstr = "IO not available for";
+        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
+#endif	
+
+	errstr = "IRQ not available for";
+        if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
+		       (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 *) hp_sdc.base_io)) 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;
+}
+
+#if defined(__hppa__)
+
+static int __init hp_sdc_init_hppa(struct parisc_device *d)
+{
+	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;
+	hp_sdc.nmi		= d->aux_irq;
+	hp_sdc.base_io		= d->hpa;
+	hp_sdc.data_io		= d->hpa + 0x800;
+	hp_sdc.status_io	= d->hpa + 0x801;
+
+	return hp_sdc_init();
+}
+
+#endif /* __hppa__ */
+
+#if !defined(__mc68000__) /* Link error on m68k! */
+static void __exit hp_sdc_exit(void)
+#else
+static void hp_sdc_exit(void)
+#endif
+{
+	write_lock_irq(&hp_sdc.lock);
+
+	/* Turn off all maskable "sub-function" irq's. */
+	hp_sdc_spin_ibf();
+	sdc_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 defined(__hppa__)
+	if (unregister_parisc_driver(&hp_sdc_driver)) 
+		printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
+#endif
+}
+
+static int __init hp_sdc_register(void)
+{
+	hp_sdc_transaction tq_init;
+	uint8_t tq_init_seq[5];
+	struct semaphore tq_init_sem;
+#if defined(__mc68000__)
+	mm_segment_t fs;
+	unsigned char i;
+#endif
+	
+	hp_sdc.dev = NULL;
+	hp_sdc.dev_err = 0;
+#if defined(__hppa__)
+	if (register_parisc_driver(&hp_sdc_driver)) {
+		printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");
+		return -ENODEV;
+	}
+#elif defined(__mc68000__)
+	if (!MACH_IS_HP300)
+	    return -ENODEV;
+
+	hp_sdc.irq	 = 1;
+	hp_sdc.nmi	 = 7;
+	hp_sdc.base_io	 = (unsigned long) 0xf0428000;
+	hp_sdc.data_io	 = (unsigned long) hp_sdc.base_io + 1;
+	hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3;
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (!get_user(i, (unsigned char *)hp_sdc.data_io))
+		hp_sdc.dev = (void *)1;
+	set_fs(fs);
+	hp_sdc.dev_err   = hp_sdc_init();
+#endif
+	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 --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -0,0 +1,358 @@
+/*
+ * 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 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;
+
+	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 --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -67,7 +67,7 @@ static inline void i8042_write_command(i
 
 #include <linux/dmi.h>
 
-static struct dmi_system_id __initdata i8042_dmi_table[] = {
+static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
 	{
 		.ident = "Compaq Proliant 8500",
 		.matches = {
@@ -86,186 +86,228 @@ static struct dmi_system_id __initdata i
 	},
 	{ }
 };
+
+/*
+ * Some Fujitsu notebooks are having trouble with touchpads if
+ * active multiplexing mode is activated. Luckily they don't have
+ * external PS/2 ports so we can safely disable it.
+ * ... apparently some Toshibas don't like MUX mode either and
+ * die horrible death on reboot.
+ */
+static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
+	{
+		.ident = "Fujitsu Lifebook P7010/P7010D",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+		},
+	},
+	{
+		.ident = "Fujitsu Lifebook P5020D",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
+		},
+	},
+	{
+		.ident = "Fujitsu Lifebook S2000",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
+		},
+	},
+	{
+		.ident = "Fujitsu Lifebook S6230",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
+		},
+	},
+	{
+		.ident = "Fujitsu T70H",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
+		},
+	},
+	{
+		.ident = "Toshiba P10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
+		},
+	},
+	{ }
+};
+
+
+
 #endif
 
-#ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-
-struct i8042_acpi_resources {
-	unsigned int port1;
-	unsigned int port2;
-	unsigned int irq;
-};
-
-static int i8042_acpi_kbd_registered;
-static int i8042_acpi_aux_registered;
-
-static acpi_status i8042_acpi_parse_resource(struct acpi_resource *res, void *data)
-{
-	struct i8042_acpi_resources *i8042_res = data;
-	struct acpi_resource_io *io;
-	struct acpi_resource_fixed_io *fixed_io;
-	struct acpi_resource_irq *irq;
-	struct acpi_resource_ext_irq *ext_irq;
-
-	switch (res->id) {
-		case ACPI_RSTYPE_IO:
-			io = &res->data.io;
-			if (io->range_length) {
-				if (!i8042_res->port1)
-					i8042_res->port1 = io->min_base_address;
-				else
-					i8042_res->port2 = io->min_base_address;
-			}
-			break;
-
-		case ACPI_RSTYPE_FIXED_IO:
-			fixed_io = &res->data.fixed_io;
-			if (fixed_io->range_length) {
-				if (!i8042_res->port1)
-					i8042_res->port1 = fixed_io->base_address;
-				else
-					i8042_res->port2 = fixed_io->base_address;
-			}
-			break;
-
-		case ACPI_RSTYPE_IRQ:
-			irq = &res->data.irq;
-			if (irq->number_of_interrupts > 0)
-				i8042_res->irq =
-					acpi_register_gsi(irq->interrupts[0],
-							  irq->edge_level,
-							  irq->active_high_low);
-			break;
-
-		case ACPI_RSTYPE_EXT_IRQ:
-			ext_irq = &res->data.extended_irq;
-			if (ext_irq->number_of_interrupts > 0)
-				i8042_res->irq =
-					acpi_register_gsi(ext_irq->interrupts[0],
-							  ext_irq->edge_level,
-							  ext_irq->active_high_low);
-			break;
-	}
-	return AE_OK;
-}
-
-static int i8042_acpi_kbd_add(struct acpi_device *device)
-{
-	struct i8042_acpi_resources kbd_res;
-	acpi_status status;
-
-	memset(&kbd_res, 0, sizeof(kbd_res));
-	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-				     i8042_acpi_parse_resource, &kbd_res);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
 
-	if (kbd_res.port1)
-		i8042_data_reg = kbd_res.port1;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no data port; default is 0x%x\n",
-			acpi_device_bid(device), i8042_data_reg);
-
-	if (kbd_res.port2)
-		i8042_command_reg = kbd_res.port2;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no command port; default is 0x%x\n",
-			acpi_device_bid(device), i8042_command_reg);
-
-	if (kbd_res.irq)
-		i8042_kbd_irq = kbd_res.irq;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
-			acpi_device_bid(device), i8042_kbd_irq);
-
-	strncpy(acpi_device_name(device), "PS/2 Keyboard Controller",
-		sizeof(acpi_device_name(device)));
-	printk("ACPI: %s [%s] at I/O 0x%x, 0x%x, irq %d\n",
-		acpi_device_name(device), acpi_device_bid(device),
-		i8042_data_reg, i8042_command_reg, i8042_kbd_irq);
+#ifdef CONFIG_PNP
+#include <linux/pnp.h>
+
+static int i8042_pnp_kbd_registered;
+static int i8042_pnp_aux_registered;
+
+static int i8042_pnp_command_reg;
+static int i8042_pnp_data_reg;
+static int i8042_pnp_kbd_irq;
+static int i8042_pnp_aux_irq;
+
+static char i8042_pnp_kbd_name[32];
+static char i8042_pnp_aux_name[32];
+
+static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
+{
+	if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+		i8042_pnp_data_reg = pnp_port_start(dev,0);
+
+	if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+		i8042_pnp_command_reg = pnp_port_start(dev, 1);
+
+	if (pnp_irq_valid(dev,0))
+		i8042_pnp_kbd_irq = pnp_irq(dev, 0);
+
+	strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name));
+	if (strlen(pnp_dev_name(dev))) {
+		strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));
+		strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
+	}
 
 	return 0;
 }
 
-static int i8042_acpi_aux_add(struct acpi_device *device)
+static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 {
-	struct i8042_acpi_resources aux_res;
-	acpi_status status;
+	if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+		i8042_pnp_data_reg = pnp_port_start(dev,0);
 
-	memset(&aux_res, 0, sizeof(aux_res));
-	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-				     i8042_acpi_parse_resource, &aux_res);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+		i8042_pnp_command_reg = pnp_port_start(dev, 1);
 
-	if (aux_res.irq)
-		i8042_aux_irq = aux_res.irq;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
-			acpi_device_bid(device), i8042_aux_irq);
-
-	strncpy(acpi_device_name(device), "PS/2 Mouse Controller",
-		sizeof(acpi_device_name(device)));
-	printk("ACPI: %s [%s] at irq %d\n",
-		acpi_device_name(device), acpi_device_bid(device), i8042_aux_irq);
+	if (pnp_irq_valid(dev, 0))
+		i8042_pnp_aux_irq = pnp_irq(dev, 0);
+
+	strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name));
+	if (strlen(pnp_dev_name(dev))) {
+		strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));
+		strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
+	}
 
 	return 0;
 }
 
-static struct acpi_driver i8042_acpi_kbd_driver = {
-	.name		= "i8042",
-	.ids		= "PNP0303,PNP030B",
-	.ops		= {
-		.add		= i8042_acpi_kbd_add,
-	},
+static struct pnp_device_id pnp_kbd_devids[] = {
+	{ .id = "PNP0303", .driver_data = 0 },
+	{ .id = "PNP030b", .driver_data = 0 },
+	{ .id = "", },
 };
 
-static struct acpi_driver i8042_acpi_aux_driver = {
-	.name		= "i8042",
-	.ids		= "PNP0F03,PNP0F0B,PNP0F0E,PNP0F12,PNP0F13,SYN0801",
-	.ops		= {
-		.add		= i8042_acpi_aux_add,
-	},
+static struct pnp_driver i8042_pnp_kbd_driver = {
+	.name           = "i8042 kbd",
+	.id_table       = pnp_kbd_devids,
+	.probe          = i8042_pnp_kbd_probe,
 };
 
-static int i8042_acpi_init(void)
+static struct pnp_device_id pnp_aux_devids[] = {
+	{ .id = "PNP0f03", .driver_data = 0 },
+	{ .id = "PNP0f0b", .driver_data = 0 },
+	{ .id = "PNP0f0e", .driver_data = 0 },
+	{ .id = "PNP0f12", .driver_data = 0 },
+	{ .id = "PNP0f13", .driver_data = 0 },
+	{ .id = "PNP0f19", .driver_data = 0 },
+	{ .id = "PNP0f1c", .driver_data = 0 },
+	{ .id = "SYN0801", .driver_data = 0 },
+	{ .id = "", },
+};
+
+static struct pnp_driver i8042_pnp_aux_driver = {
+	.name           = "i8042 aux",
+	.id_table       = pnp_aux_devids,
+	.probe          = i8042_pnp_aux_probe,
+};
+
+static void i8042_pnp_exit(void)
+{
+	if (i8042_pnp_kbd_registered) {
+		i8042_pnp_kbd_registered = 0;
+		pnp_unregister_driver(&i8042_pnp_kbd_driver);
+	}
+
+	if (i8042_pnp_aux_registered) {
+		i8042_pnp_aux_registered = 0;
+		pnp_unregister_driver(&i8042_pnp_aux_driver);
+	}
+}
+
+static int i8042_pnp_init(void)
 {
-	int result;
+	int result_kbd, result_aux;
 
-	if (acpi_disabled || i8042_noacpi) {
-		printk("i8042: ACPI detection disabled\n");
+	if (i8042_nopnp) {
+		printk(KERN_INFO "i8042: PNP detection disabled\n");
 		return 0;
 	}
 
-	result = acpi_bus_register_driver(&i8042_acpi_kbd_driver);
-	if (result < 0)
-		return result;
+	if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0)
+		i8042_pnp_kbd_registered = 1;
+	if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0)
+		i8042_pnp_aux_registered = 1;
 
-	if (result == 0) {
-		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+	if (result_kbd <= 0 && result_aux <= 0) {
+		i8042_pnp_exit();
+#if defined(__ia64__)
 		return -ENODEV;
+#else
+		printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
+		return 0;
+#endif
+	}
+
+	if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
+	      i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
+		printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+			i8042_pnp_data_reg, i8042_data_reg);
+		i8042_pnp_data_reg = i8042_data_reg;
+	}
+
+	if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
+	      i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
+		printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+			i8042_pnp_command_reg, i8042_command_reg);
+		i8042_pnp_command_reg = i8042_command_reg;
+	}
+
+	if (!i8042_pnp_kbd_irq) {
+		printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq);
+		i8042_pnp_kbd_irq = i8042_kbd_irq;
 	}
-	i8042_acpi_kbd_registered = 1;
 
-	result = acpi_bus_register_driver(&i8042_acpi_aux_driver);
-	if (result >= 0)
-		i8042_acpi_aux_registered = 1;
-	if (result == 0)
+	if (!i8042_pnp_aux_irq) {
+		printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq);
+		i8042_pnp_aux_irq = i8042_aux_irq;
+	}
+
+#if defined(__ia64__)
+	if (result_aux <= 0)
 		i8042_noaux = 1;
+#endif
+
+	i8042_data_reg = i8042_pnp_data_reg;
+	i8042_command_reg = i8042_pnp_command_reg;
+	i8042_kbd_irq = i8042_pnp_kbd_irq;
+	i8042_aux_irq = i8042_pnp_aux_irq;
+
+	printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n",
+		i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name,
+		i8042_data_reg, i8042_command_reg, i8042_kbd_irq,
+		(result_aux > 0) ? "," : "", i8042_aux_irq);
 
 	return 0;
 }
 
-static void i8042_acpi_exit(void)
-{
-	if (i8042_acpi_kbd_registered)
-		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
-
-	if (i8042_acpi_aux_registered)
-		acpi_bus_unregister_driver(&i8042_acpi_aux_driver);
-}
 #endif
 
 static inline int i8042_platform_init(void)
@@ -281,8 +323,8 @@ static inline int i8042_platform_init(vo
 	i8042_kbd_irq = I8042_MAP_IRQ(1);
 	i8042_aux_irq = I8042_MAP_IRQ(12);
 
-#ifdef CONFIG_ACPI
-	if (i8042_acpi_init())
+#ifdef CONFIG_PNP
+	if (i8042_pnp_init())
 		return -1;
 #endif
 
@@ -291,8 +333,11 @@ static inline int i8042_platform_init(vo
 #endif
 
 #if defined(__i386__)
-	if (dmi_check_system(i8042_dmi_table))
+	if (dmi_check_system(i8042_dmi_noloop_table))
 		i8042_noloop = 1;
+
+	if (dmi_check_system(i8042_dmi_nomux_table))
+		i8042_nomux = 1;
 #endif
 
 	return 0;
@@ -300,8 +345,8 @@ static inline int i8042_platform_init(vo
 
 static inline void i8042_platform_exit(void)
 {
-#ifdef CONFIG_ACPI
-	i8042_acpi_exit();
+#ifdef CONFIG_PNP
+	i8042_pnp_exit();
 #endif
 }
 
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/serio.h>
 #include <linux/err.h>
+#include <linux/rcupdate.h>
 
 #include <asm/io.h>
 
@@ -52,12 +53,16 @@ MODULE_PARM_DESC(dumbkbd, "Pretend that 
 
 static unsigned int i8042_noloop;
 module_param_named(noloop, i8042_noloop, bool, 0);
-MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port");
+MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
 
-#ifdef CONFIG_ACPI
-static int i8042_noacpi;
-module_param_named(noacpi, i8042_noacpi, bool, 0);
-MODULE_PARM_DESC(noacpi, "Do not use ACPI to detect controller settings");
+static unsigned int i8042_blink_frequency = 500;
+module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
+MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
+
+#ifdef CONFIG_PNP
+static int i8042_nopnp;
+module_param_named(nopnp, i8042_nopnp, bool, 0);
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
 #endif
 
 #define DEBUG
@@ -76,9 +81,10 @@ __obsolete_setup("i8042_dumbkbd");
 
 #include "i8042.h"
 
-DEFINE_SPINLOCK(i8042_lock);
+static DEFINE_SPINLOCK(i8042_lock);
 
-struct i8042_values {
+struct i8042_port {
+	struct serio *serio;
 	int irq;
 	unsigned char disable;
 	unsigned char irqen;
@@ -87,25 +93,25 @@ struct i8042_values {
 	char name[8];
 };
 
-static struct i8042_values i8042_kbd_values = {
-	.disable	= I8042_CTR_KBDDIS,
-	.irqen 		= I8042_CTR_KBDINT,
-	.mux		= -1,
-	.name		= "KBD",
-};
-
-static struct i8042_values i8042_aux_values = {
-	.disable	= I8042_CTR_AUXDIS,
-	.irqen		= I8042_CTR_AUXINT,
-	.mux		= -1,
-	.name		= "AUX",
+#define I8042_KBD_PORT_NO	0
+#define I8042_AUX_PORT_NO	1
+#define I8042_MUX_PORT_NO	2
+#define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
+static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
+	{
+		.disable	= I8042_CTR_KBDDIS,
+		.irqen 		= I8042_CTR_KBDINT,
+		.mux		= -1,
+		.name		= "KBD",
+	},
+	{
+		.disable	= I8042_CTR_AUXDIS,
+		.irqen		= I8042_CTR_AUXINT,
+		.mux		= -1,
+		.name		= "AUX",
+	}
 };
 
-static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS];
-
-static struct serio *i8042_kbd_port;
-static struct serio *i8042_aux_port;
-static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS];
 static unsigned char i8042_initial_ctr;
 static unsigned char i8042_ctr;
 static unsigned char i8042_mux_open;
@@ -113,6 +119,7 @@ static unsigned char i8042_mux_present;
 static struct timer_list i8042_timer;
 static struct platform_device *i8042_platform_device;
 
+
 /*
  * Shared IRQ's require a device pointer, but this driver doesn't support
  * multiple devices
@@ -155,16 +162,17 @@ static int i8042_wait_write(void)
 static int i8042_flush(void)
 {
 	unsigned long flags;
-	unsigned char data;
+	unsigned char data, str;
 	int i = 0;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) {
+	while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
 		udelay(50);
 		data = i8042_read_data();
+		i++;
 		dbg("%02x <- i8042 (flush, %s)", data,
-			i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd");
+			str & I8042_STR_AUXDATA ? "aux" : "kbd");
 	}
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -246,19 +254,19 @@ static int i8042_kbd_write(struct serio 
  * i8042_aux_write() sends a byte out through the aux interface.
  */
 
-static int i8042_aux_write(struct serio *port, unsigned char c)
+static int i8042_aux_write(struct serio *serio, unsigned char c)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 	int retval;
 
 /*
  * Send the byte out.
  */
 
-	if (values->mux == -1)
+	if (port->mux == -1)
 		retval = i8042_command(&c, I8042_CMD_AUX_SEND);
 	else
-		retval = i8042_command(&c, I8042_CMD_MUX_SEND + values->mux);
+		retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux);
 
 /*
  * Make sure the interrupt happens and the character is received even
@@ -274,9 +282,10 @@ static int i8042_aux_write(struct serio 
  * i8042_activate_port() enables port on a chip.
  */
 
-static int i8042_activate_port(struct serio *port)
+static int i8042_activate_port(struct i8042_port *port)
 {
-	struct i8042_values *values = port->port_data;
+	if (!port->serio)
+		return -1;
 
 	i8042_flush();
 
@@ -284,12 +293,12 @@ static int i8042_activate_port(struct se
 	 * Enable port again here because it is disabled if we are
 	 * resuming (normally it is enabled already).
 	 */
-	i8042_ctr &= ~values->disable;
+	i8042_ctr &= ~port->disable;
 
-	i8042_ctr |= values->irqen;
+	i8042_ctr |= port->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		i8042_ctr &= ~values->irqen;
+		i8042_ctr &= ~port->irqen;
 		return -1;
 	}
 
@@ -302,22 +311,22 @@ static int i8042_activate_port(struct se
  * It allocates the interrupt and calls i8042_enable_port.
  */
 
-static int i8042_open(struct serio *port)
+static int i8042_open(struct serio *serio)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 
-	if (values->mux != -1)
+	if (port->mux != -1)
 		if (i8042_mux_open++)
 			return 0;
 
-	if (request_irq(values->irq, i8042_interrupt,
+	if (request_irq(port->irq, i8042_interrupt,
 			SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
-		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
+		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
 		goto irq_fail;
 	}
 
 	if (i8042_activate_port(port)) {
-		printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", values->name);
+		printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name);
 		goto activate_fail;
 	}
 
@@ -326,11 +335,10 @@ static int i8042_open(struct serio *port
 	return 0;
 
 activate_fail:
-	free_irq(values->irq, i8042_request_irq_cookie);
+	free_irq(port->irq, i8042_request_irq_cookie);
 
 irq_fail:
-	values->exists = 0;
-	serio_unregister_port_delayed(port);
+	serio_unregister_port_delayed(serio);
 
 	return -1;
 }
@@ -341,27 +349,58 @@ irq_fail:
  * the BIOS could have used the AUX interrupt for PCI.
  */
 
-static void i8042_close(struct serio *port)
+static void i8042_close(struct serio *serio)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 
-	if (values->mux != -1)
+	if (port->mux != -1)
 		if (--i8042_mux_open)
 			return;
 
-	i8042_ctr &= ~values->irqen;
+	i8042_ctr &= ~port->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
-		return;
+		printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name);
+/*
+ * We still want to continue and free IRQ so if more data keeps coming in
+ * kernel will just ignore the irq.
+ */
 	}
 
-	free_irq(values->irq, i8042_request_irq_cookie);
+	free_irq(port->irq, i8042_request_irq_cookie);
 
 	i8042_flush();
 }
 
 /*
+ * i8042_start() is called by serio core when port is about to finish
+ * registering. It will mark port as existing so i8042_interrupt can
+ * start sending data through it.
+ */
+static int i8042_start(struct serio *serio)
+{
+	struct i8042_port *port = serio->port_data;
+
+	port->exists = 1;
+	mb();
+	return 0;
+}
+
+/*
+ * i8042_stop() marks serio port as non-existing so i8042_interrupt
+ * will not try to send data to the port that is about to go away.
+ * The function is called by serio core as part of unregister procedure.
+ */
+static void i8042_stop(struct serio *serio)
+{
+	struct i8042_port *port = serio->port_data;
+
+	port->exists = 0;
+	synchronize_kernel();
+	port->serio = NULL;
+}
+
+/*
  * i8042_interrupt() is the most important function in this driver -
  * it handles the interrupts from the i8042, and sends incoming bytes
  * to the upper layers.
@@ -369,25 +408,25 @@ static void i8042_close(struct serio *po
 
 static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct i8042_port *port;
 	unsigned long flags;
-	unsigned char str, data = 0;
+	unsigned char str, data;
 	unsigned int dfl;
-	unsigned int aux_idx;
+	unsigned int port_no;
 	int ret;
 
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
 	spin_lock_irqsave(&i8042_lock, flags);
 	str = i8042_read_status();
-	if (str & I8042_STR_OBF)
-		data = i8042_read_data();
-	spin_unlock_irqrestore(&i8042_lock, flags);
-
-	if (~str & I8042_STR_OBF) {
+	if (unlikely(~str & I8042_STR_OBF)) {
+		spin_unlock_irqrestore(&i8042_lock, flags);
 		if (irq) dbg("Interrupt %d, without any data", irq);
 		ret = 0;
 		goto out;
 	}
+	data = i8042_read_data();
+	spin_unlock_irqrestore(&i8042_lock, flags);
 
 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
 		static unsigned long last_transmit;
@@ -419,39 +458,28 @@ static irqreturn_t i8042_interrupt(int i
 			}
 		}
 
-		aux_idx = (str >> 6) & 3;
-
-		dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
-			data, aux_idx, irq,
-			dfl & SERIO_PARITY ? ", bad parity" : "",
-			dfl & SERIO_TIMEOUT ? ", timeout" : "");
-
-		if (likely(i8042_mux_values[aux_idx].exists))
-			serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs);
-
+		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
 		last_str = str;
 		last_transmit = jiffies;
-		goto irq_ret;
+	} else {
+
+		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
+		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+
+		port_no = (str & I8042_STR_AUXDATA) ?
+				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
 	}
 
-	dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
-	      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+	port = &i8042_ports[port_no];
 
 	dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
-		data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
-		dfl & SERIO_PARITY ? ", bad parity" : "",
-		dfl & SERIO_TIMEOUT ? ", timeout" : "");
+	    data, port->name, irq,
+	    dfl & SERIO_PARITY ? ", bad parity" : "",
+	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
+	if (likely(port->exists))
+		serio_interrupt(port->serio, data, dfl, regs);
 
-	if (str & I8042_STR_AUXDATA) {
-		if (likely(i8042_aux_values.exists))
-			serio_interrupt(i8042_aux_port, data, dfl, regs);
-	} else {
-		if (likely(i8042_kbd_values.exists))
-			serio_interrupt(i8042_kbd_port, data, dfl, regs);
-	}
-
-irq_ret:
 	ret = 1;
 out:
 	return IRQ_RETVAL(ret);
@@ -500,7 +528,7 @@ static int i8042_set_mux_mode(unsigned i
  * the controller has been switched into Multiplexed mode
  */
 
-static int i8042_enable_mux_ports(struct i8042_values *values)
+static int i8042_enable_mux_ports(void)
 {
 	unsigned char param;
 	int i;
@@ -535,7 +563,7 @@ static int i8042_enable_mux_ports(struct
  * LCS/Telegraphics.
  */
 
-static int __init i8042_check_mux(struct i8042_values *values)
+static int __init i8042_check_mux(void)
 {
 	unsigned char mux_version;
 
@@ -550,7 +578,7 @@ static int __init i8042_check_mux(struct
 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
 		(mux_version >> 4) & 0xf, mux_version & 0xf);
 
-	if (i8042_enable_mux_ports(values))
+	if (i8042_enable_mux_ports())
 		return -1;
 
 	i8042_mux_present = 1;
@@ -563,7 +591,7 @@ static int __init i8042_check_mux(struct
  * the presence of an AUX interface.
  */
 
-static int __init i8042_check_aux(struct i8042_values *values)
+static int __init i8042_check_aux(void)
 {
 	unsigned char param;
 	static int i8042_check_aux_cookie;
@@ -573,10 +601,10 @@ static int __init i8042_check_aux(struct
  * in trying to detect AUX presence.
  */
 
-	if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
-				"i8042", &i8042_check_aux_cookie))
+	if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
+			SA_SHIRQ, "i8042", &i8042_check_aux_cookie))
                 return -1;
-	free_irq(values->irq, &i8042_check_aux_cookie);
+	free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);
 
 /*
  * Get rid of bytes in the queue.
@@ -641,27 +669,25 @@ static int __init i8042_check_aux(struct
  * registers it, and reports to the user.
  */
 
-static int __init i8042_port_register(struct serio *port)
+static int __init i8042_port_register(struct i8042_port *port)
 {
-	struct i8042_values *values = port->port_data;
-
-	values->exists = 1;
-
-	i8042_ctr &= ~values->disable;
+	i8042_ctr &= ~port->disable;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
-		values->exists = 0;
+		kfree(port->serio);
+		port->serio = NULL;
+		i8042_ctr |= port->disable;
 		return -1;
 	}
 
 	printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
-	       values->name,
+	       port->name,
 	       (unsigned long) I8042_DATA_REG,
 	       (unsigned long) I8042_COMMAND_REG,
-	       values->irq);
+	       port->irq);
 
-	serio_register_port(port);
+	serio_register_port(port->serio);
 
 	return 0;
 }
@@ -672,6 +698,26 @@ static void i8042_timer_func(unsigned lo
 	i8042_interrupt(0, NULL, NULL);
 }
 
+static int i8042_ctl_test(void)
+{
+	unsigned char param;
+
+	if (!i8042_reset)
+		return 0;
+
+	if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
+		printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+		return -1;
+	}
+
+	if (param != I8042_RET_CTL_TEST) {
+		printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
+			 param, I8042_RET_CTL_TEST);
+		return -1;
+	}
+
+	return 0;
+}
 
 /*
  * i8042_controller init initializes the i8042 controller, and,
@@ -688,24 +734,14 @@ static int i8042_controller_init(void)
  * before doing anything else.
  */
 
-	i8042_flush();
-
-	if (i8042_reset) {
-
-		unsigned char param;
-
-		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
-			printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
-			return -1;
-		}
-
-		if (param != I8042_RET_CTL_TEST) {
-			printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
-				 param, I8042_RET_CTL_TEST);
-			return -1;
-		}
+	if (i8042_flush() == I8042_BUFFER_SIZE) {
+		printk(KERN_ERR "i8042.c: No controller found.\n");
+		return -1;
 	}
 
+	if (i8042_ctl_test())
+		return -1;
+
 /*
  * Save the CTR for restoral on unload / reboot.
  */
@@ -771,17 +807,13 @@ static int i8042_controller_init(void)
 /*
  * Reset the controller.
  */
-void i8042_controller_reset(void)
+static void i8042_controller_reset(void)
 {
-	unsigned char param;
-
 /*
  * Reset the controller if requested.
  */
 
-	if (i8042_reset)
-		if (i8042_command(&param, I8042_CMD_CTL_TEST))
-			printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
+	i8042_ctl_test();
 
 /*
  * Disable MUX mode if present.
@@ -806,7 +838,7 @@ void i8042_controller_reset(void)
  * able to talk to the hardware when rebooting.
  */
 
-void i8042_controller_cleanup(void)
+static void i8042_controller_cleanup(void)
 {
 	int i;
 
@@ -816,39 +848,41 @@ void i8042_controller_cleanup(void)
  * Reset anything that is connected to the ports.
  */
 
-	if (i8042_kbd_values.exists)
-		serio_cleanup(i8042_kbd_port);
-
-	if (i8042_aux_values.exists)
-		serio_cleanup(i8042_aux_port);
-
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists)
-			serio_cleanup(i8042_mux_port[i]);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		if (i8042_ports[i].exists)
+			serio_cleanup(i8042_ports[i].serio);
 
 	i8042_controller_reset();
 }
 
 
-static int blink_frequency = 500;
-module_param_named(panicblink, blink_frequency, int, 0600);
+/*
+ * i8042_panic_blink() will flash the keyboard LEDs and is called when
+ * kernel panics. Flashing LEDs is useful for users running X who may
+ * not see the console and will help distingushing panics from "real"
+ * lockups.
+ *
+ * Note that DELAY has a limit of 10ms so we will not get stuck here
+ * waiting for KBC to free up even if KBD interrupt is off
+ */
 
-/* Catch the case when the kbd interrupt is off */
 #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
 
-/* Tell the user who may be running in X and not see the console that we have
-   panic'ed. This is to distingush panics from "real" lockups.  */
 static long i8042_panic_blink(long count)
 {
 	long delay = 0;
 	static long last_blink;
 	static char led;
-	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is
-	   different. */
-	if (!blink_frequency)
+
+	/*
+	 * We expect frequency to be about 1/2s. KDB uses about 1s.
+	 * Make sure they are different.
+	 */
+	if (!i8042_blink_frequency)
 		return 0;
-	if (count - last_blink < blink_frequency)
+	if (count - last_blink < i8042_blink_frequency)
 		return 0;
+
 	led ^= 0x01 | 0x04;
 	while (i8042_read_status() & I8042_STR_IBF)
 		DELAY;
@@ -869,7 +903,7 @@ static long i8042_panic_blink(long count
  * Here we try to restore the original BIOS settings
  */
 
-static int i8042_suspend(struct device *dev, u32 state, u32 level)
+static int i8042_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_DISABLE) {
 		del_timer_sync(&i8042_timer);
@@ -891,30 +925,25 @@ static int i8042_resume(struct device *d
 	if (level != RESUME_ENABLE)
 		return 0;
 
-	if (i8042_controller_init()) {
-		printk(KERN_ERR "i8042: resume failed\n");
+	if (i8042_ctl_test())
+		return -1;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		printk(KERN_ERR "i8042: Can't write CTR\n");
 		return -1;
 	}
 
 	if (i8042_mux_present)
-		if (i8042_set_mux_mode(1, NULL) ||
-		    i8042_enable_mux_ports(&i8042_aux_values)) {
+		if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
 			printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
-		}
 
 /*
- * Reconnect anything that was connected to the ports.
+ * Activate all ports.
  */
 
-	if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0)
-		serio_reconnect(i8042_kbd_port);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		i8042_activate_port(&i8042_ports[i]);
 
-	if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0)
-		serio_reconnect(i8042_aux_port);
-
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0)
-			serio_reconnect(i8042_mux_port[i]);
 /*
  * Restart timer (for polling "stuck" data)
  */
@@ -944,72 +973,83 @@ static struct device_driver i8042_driver
 	.shutdown	= i8042_shutdown,
 };
 
-static struct serio * __init i8042_allocate_kbd_port(void)
+static void __init i8042_create_kbd_port(void)
 {
 	struct serio *serio;
+	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
 
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL,
-		serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write,
-		serio->open		= i8042_open,
-		serio->close		= i8042_close,
-		serio->port_data	= &i8042_kbd_values,
+		serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
+		serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
+		serio->open		= i8042_open;
+		serio->close		= i8042_close;
+		serio->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
 		strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
-	}
 
-	return serio;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-static struct serio * __init i8042_allocate_aux_port(void)
+static void __init i8042_create_aux_port(void)
 {
 	struct serio *serio;
+	struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
 
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= i8042_aux_write;
 		serio->open		= i8042_open;
 		serio->close		= i8042_close;
-		serio->port_data	= &i8042_aux_values,
+		serio->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
-	}
 
-	return serio;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-static struct serio * __init i8042_allocate_mux_port(int index)
+static void __init i8042_create_mux_port(int index)
 {
 	struct serio *serio;
-	struct i8042_values *values = &i8042_mux_values[index];
+	struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
 
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
-		*values = i8042_aux_values;
-		snprintf(values->name, sizeof(values->name), "AUX%d", index);
-		values->mux = index;
-
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= i8042_aux_write;
 		serio->open		= i8042_open;
 		serio->close		= i8042_close;
-		serio->port_data	= values;
+		serio->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);
 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);
-	}
 
-	return serio;
+		*port = i8042_ports[I8042_AUX_PORT_NO];
+		port->exists = 0;
+		snprintf(port->name, sizeof(port->name), "AUX%d", index);
+		port->mux = index;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-int __init i8042_init(void)
+static int __init i8042_init(void)
 {
 	int i;
 	int err;
@@ -1022,60 +1062,51 @@ int __init i8042_init(void)
 	if (i8042_platform_init())
 		return -EBUSY;
 
-	i8042_aux_values.irq = I8042_AUX_IRQ;
-	i8042_kbd_values.irq = I8042_KBD_IRQ;
+	i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
+	i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
 
-	if (i8042_controller_init())
+	if (i8042_controller_init()) {
+		i8042_platform_exit();
 		return -ENODEV;
+	}
 
 	err = driver_register(&i8042_driver);
-	if (err)
+	if (err) {
+		i8042_platform_exit();
 		return err;
+	}
 
 	i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0);
 	if (IS_ERR(i8042_platform_device)) {
 		driver_unregister(&i8042_driver);
+		i8042_platform_exit();
 		return PTR_ERR(i8042_platform_device);
 	}
 
-	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) {
-		if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
-			for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
-				i8042_mux_port[i] = i8042_allocate_mux_port(i);
-				if (i8042_mux_port[i])
-					i8042_port_register(i8042_mux_port[i]);
-			}
-		else {
-			i8042_aux_port = i8042_allocate_aux_port();
-			if (i8042_aux_port)
-				i8042_port_register(i8042_aux_port);
-		}
+	if (!i8042_noaux && !i8042_check_aux()) {
+		if (!i8042_nomux && !i8042_check_mux())
+			for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
+				i8042_create_mux_port(i);
+		else
+			i8042_create_aux_port();
 	}
 
-	i8042_kbd_port = i8042_allocate_kbd_port();
-	if (i8042_kbd_port)
-		i8042_port_register(i8042_kbd_port);
+	i8042_create_kbd_port();
 
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
 	return 0;
 }
 
-void __exit i8042_exit(void)
+static void __exit i8042_exit(void)
 {
 	int i;
 
 	i8042_controller_cleanup();
 
-	if (i8042_kbd_values.exists)
-		serio_unregister_port(i8042_kbd_port);
-
-	if (i8042_aux_values.exists)
-		serio_unregister_port(i8042_aux_port);
-
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists)
-			serio_unregister_port(i8042_mux_port[i]);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		if (i8042_ports[i].exists)
+			serio_unregister_port(i8042_ports[i].serio);
 
 	del_timer_sync(&i8042_timer);
 
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -100,10 +100,10 @@
 
 /*
  * Expected maximum internal i8042 buffer size. This is used for flushing
- * the i8042 buffers. 32 should be more than enough.
+ * the i8042 buffers.
  */
 
-#define I8042_BUFFER_SIZE	32
+#define I8042_BUFFER_SIZE	16
 
 /*
  * Number of AUX ports on controllers supporting active multiplexing
@@ -117,13 +117,13 @@
  */
 
 #ifdef DEBUG
-static unsigned long i8042_start;
-#define dbg_init() do { i8042_start = jiffies; } while (0)
+static unsigned long i8042_start_time;
+#define dbg_init() do { i8042_start_time = jiffies; } while (0)
 #define dbg(format, arg...) 							\
 	do { 									\
 		if (i8042_debug)						\
 			printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,	\
-	 			## arg, (int) (jiffies - i8042_start));		\
+	 			## arg, (int) (jiffies - i8042_start_time));	\
 	} while (0)
 #else
 #define dbg_init() do { } while (0)
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -125,7 +125,7 @@ static struct serio * __init maceps2_all
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= maceps2_write;
 		serio->open		= maceps2_open;
 		serio->close		= maceps2_close;
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -1,31 +1,47 @@
 /*
- * $Id: parkbd.c,v 1.10 2002/03/13 10:09:20 vojtech Exp $
+ *  Parallel port to Keyboard port adapter driver for Linux
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *  Copyright (c) 1999-2004 Vojtech Pavlik
  */
 
 /*
- *  Parallel port to Keyboard port adapter driver for Linux
+ * 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 free software; you can redistribute it 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.
+ * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter
+ * can be made:
+ * 
+ *  Parallel port            Keyboard port
  *
- * 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.
+ *     +5V --------------------- +5V (4)
+ *  
+ *                 ______
+ *     +5V -------|______|--.
+ *                          |
+ *     ACK (10) ------------|
+ *                          |--- KBD CLOCK (5)
+ *     STROBE (1) ---|<|----'
+ *     
+ *                 ______
+ *     +5V -------|______|--.
+ *                          |
+ *     BUSY (11) -----------|
+ *                          |--- KBD DATA (1)
+ *     AUTOFD (14) --|<|----'
  *
- * You 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
+ *     GND (18-25) ------------- GND (3)
+ *     
+ * The diodes can be fairly any type, and the resistors should be somewhere
+ * around 5 kOhm, but the adapter will likely work without the resistors,
+ * too.
  *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * The +5V source can be taken either from USB, from mouse or keyboard ports,
+ * or from a joystick port. Unfortunately, the parallel port of a PC doesn't
+ * have a +5V pin, and feeding the keyboard from signal pins is out of question
+ * with 300 mA power reqirement of a typical AT keyboard.
  */
 
 #include <linux/module.h>
@@ -158,7 +174,7 @@ static struct serio * __init parkbd_allo
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type = parkbd_mode;
+		serio->id.type = parkbd_mode;
 		serio->write = parkbd_write,
 		strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
 		snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name);
@@ -167,7 +183,7 @@ static struct serio * __init parkbd_allo
 	return serio;
 }
 
-int __init parkbd_init(void)
+static int __init parkbd_init(void)
 {
 	int err;
 
@@ -191,7 +207,7 @@ int __init parkbd_init(void)
 	return 0;
 }
 
-void __exit parkbd_exit(void)
+static void __exit parkbd_exit(void)
 {
 	parport_release(parkbd_dev);
 	serio_unregister_port(parkbd_port);
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -150,7 +150,7 @@ static int __devinit pcips2_probe(struct
 	memset(ps2if, 0, sizeof(struct pcips2_data));
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= pcips2_write;
 	serio->open		= pcips2_open;
 	serio->close		= pcips2_close;
@@ -217,7 +217,7 @@ static struct pci_driver pcips2_driver =
 
 static int __init pcips2_init(void)
 {
-	return pci_module_init(&pcips2_driver);
+	return pci_register_driver(&pcips2_driver);
 }
 
 static void __exit pcips2_exit(void)
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -122,7 +122,7 @@ static struct serio * __init q40kbd_allo
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->open		= q40kbd_open;
 		serio->close		= q40kbd_close;
 		serio->dev.parent	= &q40kbd_device->dev;
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -115,7 +115,7 @@ static int __devinit rpckbd_probe(struct
 		return -ENOMEM;
 
 	memset(serio, 0, sizeof(struct serio));
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= rpckbd_write;
 	serio->open		= rpckbd_open;
 	serio->close		= rpckbd_close;
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -245,7 +245,7 @@ static int ps2_probe(struct sa1111_dev *
 	memset(ps2if, 0, sizeof(struct ps2if));
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= ps2_write;
 	serio->open		= ps2_open;
 	serio->close		= ps2_close;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -41,76 +41,98 @@ MODULE_DESCRIPTION("Serio abstraction co
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_interrupt);
-EXPORT_SYMBOL(serio_register_port);
-EXPORT_SYMBOL(serio_register_port_delayed);
+EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_unregister_port_delayed);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_unregister_port_delayed);
+EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
 EXPORT_SYMBOL(serio_rescan);
 EXPORT_SYMBOL(serio_reconnect);
 
-static DECLARE_MUTEX(serio_sem);	/* protects serio_list and serio_diriver_list */
+/*
+ * serio_sem protects entire serio subsystem and is taken every time
+ * serio port or driver registrered or unregistered.
+ */
+static DECLARE_MUTEX(serio_sem);
+
 static LIST_HEAD(serio_list);
-static LIST_HEAD(serio_driver_list);
-static unsigned int serio_no;
 
-struct bus_type serio_bus = {
+static struct bus_type serio_bus = {
 	.name =	"serio",
 };
 
-static void serio_find_driver(struct serio *serio);
-static void serio_create_port(struct serio *serio);
+static void serio_add_port(struct serio *serio);
 static void serio_destroy_port(struct serio *serio);
-static void serio_connect_port(struct serio *serio, struct serio_driver *drv);
 static void serio_reconnect_port(struct serio *serio);
 static void serio_disconnect_port(struct serio *serio);
 
-static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
 {
-	get_driver(&drv->driver);
+	while (ids->type || ids->proto) {
+		if ((ids->type == SERIO_ANY || ids->type == serio->id.type) &&
+		    (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) &&
+		    (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) &&
+		    (ids->id == SERIO_ANY || ids->id == serio->id.id))
+			return 1;
+		ids++;
+	}
+	return 0;
+}
 
-	drv->connect(serio, drv);
-	if (serio->drv) {
-		down_write(&serio_bus.subsys.rwsem);
+/*
+ * Basic serio -> driver core mappings
+ */
+
+static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+{
+	down_write(&serio_bus.subsys.rwsem);
+
+	if (serio_match_port(drv->id_table, serio)) {
 		serio->dev.driver = &drv->driver;
+		if (drv->connect(serio, drv)) {
+			serio->dev.driver = NULL;
+			goto out;
+		}
 		device_bind_driver(&serio->dev);
-		up_write(&serio_bus.subsys.rwsem);
-		return 1;
 	}
+out:
+	up_write(&serio_bus.subsys.rwsem);
+}
 
-	put_driver(&drv->driver);
-	return 0;
+static void serio_release_driver(struct serio *serio)
+{
+	down_write(&serio_bus.subsys.rwsem);
+	device_release_driver(&serio->dev);
+	up_write(&serio_bus.subsys.rwsem);
 }
 
-/* serio_find_driver() must be called with serio_sem down.  */
 static void serio_find_driver(struct serio *serio)
 {
-	struct serio_driver *drv;
-
-	list_for_each_entry(drv, &serio_driver_list, node)
-		if (!drv->manual_bind)
-			if (serio_bind_driver(serio, drv))
-				break;
+	down_write(&serio_bus.subsys.rwsem);
+	device_attach(&serio->dev);
+	up_write(&serio_bus.subsys.rwsem);
 }
 
+
 /*
  * Serio event processing.
  */
 
-struct serio_event {
-	int type;
-	struct serio *serio;
-	struct list_head node;
-};
-
 enum serio_event_type {
 	SERIO_RESCAN,
 	SERIO_RECONNECT,
 	SERIO_REGISTER_PORT,
 	SERIO_UNREGISTER_PORT,
+	SERIO_REGISTER_DRIVER,
+};
+
+struct serio_event {
+	enum serio_event_type type;
+	void *object;
+	struct module *owner;
+	struct list_head node;
 };
 
 static DEFINE_SPINLOCK(serio_event_lock);	/* protects serio_event_list */
@@ -119,24 +141,82 @@ static DECLARE_WAIT_QUEUE_HEAD(serio_wai
 static DECLARE_COMPLETION(serio_exited);
 static int serio_pid;
 
-static void serio_queue_event(struct serio *serio, int event_type)
+static void serio_queue_event(void *object, struct module *owner,
+			      enum serio_event_type event_type)
 {
 	unsigned long flags;
 	struct serio_event *event;
 
 	spin_lock_irqsave(&serio_event_lock, flags);
 
+	/*
+ 	 * Scan event list for the other events for the same serio port,
+	 * starting with the most recent one. If event is the same we
+	 * do not need add new one. If event is of different type we
+	 * need to add this event and should not look further because
+	 * we need to preseve sequence of distinct events.
+ 	 */
+	list_for_each_entry_reverse(event, &serio_event_list, node) {
+		if (event->object == object) {
+			if (event->type == event_type)
+				goto out;
+			break;
+		}
+	}
+
 	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
+		if (!try_module_get(owner)) {
+			printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
+			goto out;
+		}
+
 		event->type = event_type;
-		event->serio = serio;
+		event->object = object;
+		event->owner = owner;
 
 		list_add_tail(&event->node, &serio_event_list);
 		wake_up(&serio_wait);
+	} else {
+		printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type);
+	}
+out:
+	spin_unlock_irqrestore(&serio_event_lock, flags);
+}
+
+static void serio_free_event(struct serio_event *event)
+{
+	module_put(event->owner);
+	kfree(event);
+}
+
+static void serio_remove_duplicate_events(struct serio_event *event)
+{
+	struct list_head *node, *next;
+	struct serio_event *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_event_lock, flags);
+
+	list_for_each_safe(node, next, &serio_event_list) {
+		e = list_entry(node, struct serio_event, node);
+		if (event->object == e->object) {
+			/*
+			 * If this event is of different type we should not
+			 * look further - we only suppress duplicate events
+			 * that were sent back-to-back.
+			 */
+			if (event->type != e->type)
+				break;
+
+			list_del_init(node);
+			serio_free_event(e);
+		}
 	}
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
+
 static struct serio_event *serio_get_event(void)
 {
 	struct serio_event *event;
@@ -151,7 +231,7 @@ static struct serio_event *serio_get_eve
 	}
 
 	node = serio_event_list.next;
-	event = container_of(node, struct serio_event, node);
+	event = list_entry(node, struct serio_event, node);
 	list_del_init(node);
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
@@ -162,39 +242,50 @@ static struct serio_event *serio_get_eve
 static void serio_handle_events(void)
 {
 	struct serio_event *event;
+	struct serio_driver *serio_drv;
 
-	while ((event = serio_get_event())) {
+	down(&serio_sem);
 
-		down(&serio_sem);
+	while ((event = serio_get_event())) {
 
 		switch (event->type) {
-			case SERIO_REGISTER_PORT :
-				serio_create_port(event->serio);
-				serio_connect_port(event->serio, NULL);
+			case SERIO_REGISTER_PORT:
+				serio_add_port(event->object);
+				break;
+
+			case SERIO_UNREGISTER_PORT:
+				serio_disconnect_port(event->object);
+				serio_destroy_port(event->object);
 				break;
 
-			case SERIO_UNREGISTER_PORT :
-				serio_disconnect_port(event->serio);
-				serio_destroy_port(event->serio);
+			case SERIO_RECONNECT:
+				serio_reconnect_port(event->object);
 				break;
 
-			case SERIO_RECONNECT :
-				serio_reconnect_port(event->serio);
+			case SERIO_RESCAN:
+				serio_disconnect_port(event->object);
+				serio_find_driver(event->object);
 				break;
 
-			case SERIO_RESCAN :
-				serio_disconnect_port(event->serio);
-				serio_connect_port(event->serio, NULL);
+			case SERIO_REGISTER_DRIVER:
+				serio_drv = event->object;
+				driver_register(&serio_drv->driver);
 				break;
+
 			default:
 				break;
 		}
 
-		up(&serio_sem);
-		kfree(event);
+		serio_remove_duplicate_events(event);
+		serio_free_event(event);
 	}
+
+	up(&serio_sem);
 }
 
+/*
+ * Remove all events that have been submitted for a given serio port.
+ */
 static void serio_remove_pending_events(struct serio *serio)
 {
 	struct list_head *node, *next;
@@ -204,16 +295,45 @@ static void serio_remove_pending_events(
 	spin_lock_irqsave(&serio_event_lock, flags);
 
 	list_for_each_safe(node, next, &serio_event_list) {
-		event = container_of(node, struct serio_event, node);
-		if (event->serio == serio) {
+		event = list_entry(node, struct serio_event, node);
+		if (event->object == serio) {
 			list_del_init(node);
-			kfree(event);
+			serio_free_event(event);
 		}
 	}
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
+/*
+ * Destroy child serio port (if any) that has not been fully registered yet.
+ *
+ * Note that we rely on the fact that port can have only one child and therefore
+ * only one child registration request can be pending. Additionally, children
+ * are registered by driver's connect() handler so there can't be a grandchild
+ * pending registration together with a child.
+ */
+static struct serio *serio_get_pending_child(struct serio *parent)
+{
+	struct serio_event *event;
+	struct serio *serio, *child = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_event_lock, flags);
+
+	list_for_each_entry(event, &serio_event_list, node) {
+		if (event->type == SERIO_REGISTER_PORT) {
+			serio = event->object;
+			if (serio->parent == parent) {
+				child = serio;
+				break;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&serio_event_lock, flags);
+	return child;
+}
 
 static int serio_thread(void *nothing)
 {
@@ -244,6 +364,48 @@ static ssize_t serio_show_description(st
 	return sprintf(buf, "%s\n", serio->name);
 }
 
+static ssize_t serio_show_id_type(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.type);
+}
+
+static ssize_t serio_show_id_proto(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.proto);
+}
+
+static ssize_t serio_show_id_id(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.id);
+}
+
+static ssize_t serio_show_id_extra(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.extra);
+}
+
+static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
+static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
+static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
+static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
+
+static struct attribute *serio_device_id_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_proto.attr,
+	&dev_attr_id.attr,
+	&dev_attr_extra.attr,
+	NULL
+};
+
+static struct attribute_group serio_id_attr_group = {
+	.name	= "id",
+	.attrs	= serio_device_id_attrs,
+};
+
 static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
 {
 	struct serio *serio = to_serio_port(dev);
@@ -261,10 +423,10 @@ static ssize_t serio_rebind_driver(struc
 		serio_reconnect_port(serio);
 	} else if (!strncmp(buf, "rescan", count)) {
 		serio_disconnect_port(serio);
-		serio_connect_port(serio, NULL);
+		serio_find_driver(serio);
 	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
 		serio_disconnect_port(serio);
-		serio_connect_port(serio, to_serio_driver(drv));
+		serio_bind_driver(serio, to_serio_driver(drv));
 		put_driver(drv);
 	} else {
 		retval = -EINVAL;
@@ -314,95 +476,90 @@ static void serio_release_port(struct de
 	module_put(THIS_MODULE);
 }
 
-static void serio_create_port(struct serio *serio)
+/*
+ * Prepare serio port for registration.
+ */
+static void serio_init_port(struct serio *serio)
 {
-	try_module_get(THIS_MODULE);
+	static atomic_t serio_no = ATOMIC_INIT(0);
+
+	__module_get(THIS_MODULE);
 
 	spin_lock_init(&serio->lock);
 	init_MUTEX(&serio->drv_sem);
-	list_add_tail(&serio->node, &serio_list);
-	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++);
+	device_initialize(&serio->dev);
+	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
+		 "serio%ld", (long)atomic_inc_return(&serio_no) - 1);
 	serio->dev.bus = &serio_bus;
 	serio->dev.release = serio_release_port;
 	if (serio->parent)
 		serio->dev.parent = &serio->parent->dev;
-	device_register(&serio->dev);
 }
 
 /*
- * serio_destroy_port() completes deregistration process and removes
- * port from the system
+ * Complete serio port registration.
+ * Driver core will attempt to find appropriate driver for the port.
  */
-static void serio_destroy_port(struct serio *serio)
+static void serio_add_port(struct serio *serio)
 {
-	struct serio_driver *drv = serio->drv;
-	unsigned long flags;
-
-	serio_remove_pending_events(serio);
-	list_del_init(&serio->node);
-
-	if (drv) {
-		drv->disconnect(serio);
-		down_write(&serio_bus.subsys.rwsem);
-		device_release_driver(&serio->dev);
-		up_write(&serio_bus.subsys.rwsem);
-		put_driver(&drv->driver);
-	}
-
 	if (serio->parent) {
-		spin_lock_irqsave(&serio->parent->lock, flags);
-		serio->parent->child = NULL;
-		spin_unlock_irqrestore(&serio->parent->lock, flags);
+		serio_pause_rx(serio->parent);
+		serio->parent->child = serio;
+		serio_continue_rx(serio->parent);
 	}
 
-	device_unregister(&serio->dev);
+	list_add_tail(&serio->node, &serio_list);
+	if (serio->start)
+		serio->start(serio);
+	device_add(&serio->dev);
+	sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
+	serio->registered = 1;
 }
 
 /*
- * serio_connect_port() tries to bind the port and possible all its
- * children to appropriate drivers. If driver passed in the function will not
- * try otehr drivers when binding parent port.
+ * serio_destroy_port() completes deregistration process and removes
+ * port from the system
  */
-static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
+static void serio_destroy_port(struct serio *serio)
 {
-	WARN_ON(serio->drv);
-	WARN_ON(serio->child);
+	struct serio *child;
 
-	if (drv)
-		serio_bind_driver(serio, drv);
-	else if (!serio->manual_bind)
-		serio_find_driver(serio);
-
-	/* Ok, now bind children, if any */
-	while (serio->child) {
-		serio = serio->child;
+	child = serio_get_pending_child(serio);
+	if (child) {
+		serio_remove_pending_events(child);
+		put_device(&child->dev);
+	}
 
-		WARN_ON(serio->drv);
-		WARN_ON(serio->child);
+	if (serio->stop)
+		serio->stop(serio);
 
-		serio_create_port(serio);
+	if (serio->parent) {
+		serio_pause_rx(serio->parent);
+		serio->parent->child = NULL;
+		serio_continue_rx(serio->parent);
+		serio->parent = NULL;
+	}
 
-		if (!serio->manual_bind) {
-			/*
-			 * With children we just _prefer_ passed in driver,
-			 * but we will try other options in case preferred
-			 * is not the one
-			 */
-			if (!drv || !serio_bind_driver(serio, drv))
-				serio_find_driver(serio);
-		}
+	if (serio->registered) {
+		sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
+		device_del(&serio->dev);
+		list_del_init(&serio->node);
+		serio->registered = 0;
 	}
+
+	serio_remove_pending_events(serio);
+	put_device(&serio->dev);
 }
 
 /*
- *
+ * Reconnect serio port and all its children (re-initialize attached devices)
  */
 static void serio_reconnect_port(struct serio *serio)
 {
 	do {
 		if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
 			serio_disconnect_port(serio);
-			serio_connect_port(serio, NULL);
+			serio_find_driver(serio);
 			/* Ok, old children are now gone, we are done */
 			break;
 		}
@@ -416,8 +573,7 @@ static void serio_reconnect_port(struct 
  */
 static void serio_disconnect_port(struct serio *serio)
 {
-	struct serio_driver *drv = serio->drv;
-	struct serio *s;
+	struct serio *s, *parent;
 
 	if (serio->child) {
 		/*
@@ -425,56 +581,46 @@ static void serio_disconnect_port(struct
 		 * first, staring with the leaf one, since we don't want
 		 * to do recursion
 		 */
+		for (s = serio; s->child; s = s->child)
+			/* empty */;
+
 		do {
-			s = serio->child;
-		} while (s->child);
+			parent = s->parent;
 
-		while (s != serio) {
-			s = s->parent;
-			serio_destroy_port(s->child);
-		}
+			serio_release_driver(s);
+			serio_destroy_port(s);
+		} while ((s = parent) != serio);
 	}
 
 	/*
 	 * Ok, no children left, now disconnect this port
 	 */
-	if (drv) {
-		drv->disconnect(serio);
-		down_write(&serio_bus.subsys.rwsem);
-		device_release_driver(&serio->dev);
-		up_write(&serio_bus.subsys.rwsem);
-		put_driver(&drv->driver);
-	}
+	serio_release_driver(serio);
 }
 
 void serio_rescan(struct serio *serio)
 {
-	serio_queue_event(serio, SERIO_RESCAN);
+	serio_queue_event(serio, NULL, SERIO_RESCAN);
 }
 
 void serio_reconnect(struct serio *serio)
 {
-	serio_queue_event(serio, SERIO_RECONNECT);
-}
-
-void serio_register_port(struct serio *serio)
-{
-	down(&serio_sem);
-	serio_create_port(serio);
-	serio_connect_port(serio, NULL);
-	up(&serio_sem);
+	serio_queue_event(serio, NULL, SERIO_RECONNECT);
 }
 
 /*
  * Submits register request to kseriod for subsequent execution.
- * Can be used when it is not obvious whether the serio_sem is
- * taken or not and when delayed execution is feasible.
+ * Note that port registration is always asynchronous.
  */
-void serio_register_port_delayed(struct serio *serio)
+void __serio_register_port(struct serio *serio, struct module *owner)
 {
-	serio_queue_event(serio, SERIO_REGISTER_PORT);
+	serio_init_port(serio);
+	serio_queue_event(serio, owner, SERIO_REGISTER_PORT);
 }
 
+/*
+ * Synchronously unregisters serio port.
+ */
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
@@ -484,13 +630,13 @@ void serio_unregister_port(struct serio 
 }
 
 /*
- * Submits unregister request to kseriod for subsequent execution.
+ * Submits register request to kseriod for subsequent execution.
  * Can be used when it is not obvious whether the serio_sem is
  * taken or not and when delayed execution is feasible.
  */
-void serio_unregister_port_delayed(struct serio *serio)
+void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
 {
-	serio_queue_event(serio, SERIO_UNREGISTER_PORT);
+	serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT);
 }
 
 
@@ -535,35 +681,30 @@ static struct driver_attribute serio_dri
 	__ATTR_NULL
 };
 
-void serio_register_driver(struct serio_driver *drv)
+static int serio_driver_probe(struct device *dev)
 {
-	struct serio *serio;
-
-	down(&serio_sem);
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *drv = to_serio_driver(dev->driver);
 
-	list_add_tail(&drv->node, &serio_driver_list);
+	return drv->connect(serio, drv);
+}
 
-	drv->driver.bus = &serio_bus;
-	driver_register(&drv->driver);
+static int serio_driver_remove(struct device *dev)
+{
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *drv = to_serio_driver(dev->driver);
 
-	if (drv->manual_bind)
-		goto out;
+	drv->disconnect(serio);
+	return 0;
+}
 
-start_over:
-	list_for_each_entry(serio, &serio_list, node) {
-		if (!serio->drv) {
-			serio_connect_port(serio, drv);
-			/*
-			 * if new child appeared then the list is changed,
-			 * we need to start over
-			 */
-			if (serio->child)
-				goto start_over;
-		}
-	}
+void __serio_register_driver(struct serio_driver *drv, struct module *owner)
+{
+	drv->driver.bus = &serio_bus;
+	drv->driver.probe = serio_driver_probe;
+	drv->driver.remove = serio_driver_remove;
 
-out:
-	up(&serio_sem);
+	serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
 }
 
 void serio_unregister_driver(struct serio_driver *drv)
@@ -571,21 +712,19 @@ void serio_unregister_driver(struct seri
 	struct serio *serio;
 
 	down(&serio_sem);
-
-	list_del_init(&drv->node);
+	drv->manual_bind = 1;	/* so serio_find_driver ignores it */
 
 start_over:
 	list_for_each_entry(serio, &serio_list, node) {
 		if (serio->drv == drv) {
 			serio_disconnect_port(serio);
-			serio_connect_port(serio, NULL);
+			serio_find_driver(serio);
 			/* we could've deleted some ports, restart */
 			goto start_over;
 		}
 	}
 
 	driver_unregister(&drv->driver);
-
 	up(&serio_sem);
 }
 
@@ -598,6 +737,74 @@ static void serio_set_drv(struct serio *
 	up(&serio->drv_sem);
 }
 
+static int serio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *serio_drv = to_serio_driver(drv);
+
+	if (serio->manual_bind || serio_drv->manual_bind)
+		return 0;
+
+	return serio_match_port(serio_drv->id_table, serio);
+}
+
+#ifdef CONFIG_HOTPLUG
+
+#define PUT_ENVP(fmt, val) 						\
+do {									\
+	envp[i++] = buffer;						\
+	length += snprintf(buffer, buffer_size - length, fmt, val);	\
+	if (buffer_size - length <= 0 || i >= num_envp)			\
+		return -ENOMEM;						\
+	length++;							\
+	buffer += length;						\
+} while (0)
+static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	struct serio *serio;
+	int i = 0;
+	int length = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	serio = to_serio_port(dev);
+
+	PUT_ENVP("SERIO_TYPE=%02x", serio->id.type);
+	PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto);
+	PUT_ENVP("SERIO_ID=%02x", serio->id.id);
+	PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra);
+
+	envp[i] = NULL;
+
+	return 0;
+}
+#undef PUT_ENVP
+
+#else
+
+static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_HOTPLUG */
+
+static int serio_resume(struct device *dev)
+{
+	struct serio *serio = to_serio_port(dev);
+
+	if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+		/*
+		 * Driver re-probing can take a while, so better let kseriod
+		 * deal with it.
+		 */
+		serio_rescan(serio);
+	}
+
+	return 0;
+}
+
 /* called from serio_driver->connect/disconnect methods under serio_sem */
 int serio_open(struct serio *serio, struct serio_driver *drv)
 {
@@ -629,14 +836,9 @@ irqreturn_t serio_interrupt(struct serio
 
         if (likely(serio->drv)) {
                 ret = serio->drv->interrupt(serio, data, dfl, regs);
-	} else {
-		if (!dfl) {
-			if ((serio->type != SERIO_8042 &&
-			     serio->type != SERIO_8042_XL) || (data == 0xaa)) {
-				serio_rescan(serio);
-				ret = IRQ_HANDLED;
-			}
-		}
+	} else if (!dfl && serio->registered) {
+		serio_rescan(serio);
+		ret = IRQ_HANDLED;
 	}
 
 	spin_unlock_irqrestore(&serio->lock, flags);
@@ -647,12 +849,15 @@ irqreturn_t serio_interrupt(struct serio
 static int __init serio_init(void)
 {
 	if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
-		printk(KERN_WARNING "serio: Failed to start kseriod\n");
+		printk(KERN_ERR "serio: Failed to start kseriod\n");
 		return -1;
 	}
 
 	serio_bus.dev_attrs = serio_device_attrs;
 	serio_bus.drv_attrs = serio_driver_attrs;
+	serio_bus.match = serio_bus_match;
+	serio_bus.hotplug = serio_hotplug;
+	serio_bus.resume = serio_resume;
 	bus_register(&serio_bus);
 
 	return 0;
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -235,7 +235,7 @@ static unsigned int serio_raw_poll(struc
 	return 0;
 }
 
-struct file_operations serio_raw_fops = {
+static struct file_operations serio_raw_fops = {
 	.owner =	THIS_MODULE,
 	.open =		serio_raw_open,
 	.release =	serio_raw_release,
@@ -253,7 +253,7 @@ struct file_operations serio_raw_fops = 
 static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
 					unsigned int dfl, struct pt_regs *regs)
 {
-	struct serio_raw *serio_raw = serio->private;
+	struct serio_raw *serio_raw = serio_get_drvdata(serio);
 	struct serio_raw_list *list;
 	unsigned int head = serio_raw->head;
 
@@ -270,17 +270,14 @@ static irqreturn_t serio_raw_interrupt(s
 	return IRQ_HANDLED;
 }
 
-static void serio_raw_connect(struct serio *serio, struct serio_driver *drv)
+static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct serio_raw *serio_raw;
 	int err;
 
-	if ((serio->type & SERIO_TYPE) != SERIO_8042)
-		return;
-
 	if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
 		printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
-		return;
+		return -ENOMEM;
 	}
 
 	down(&serio_raw_sem);
@@ -292,8 +289,10 @@ static void serio_raw_connect(struct ser
 	INIT_LIST_HEAD(&serio_raw->list);
 	init_waitqueue_head(&serio_raw->wait);
 
-	serio->private = serio_raw;
-	if (serio_open(serio, drv))
+	serio_set_drvdata(serio, serio_raw);
+
+	err = serio_open(serio, drv);
+	if (err)
 		goto out_free;
 
 	list_add_tail(&serio_raw->node, &serio_raw_list);
@@ -322,15 +321,16 @@ out_close:
 	serio_close(serio);
 	list_del_init(&serio_raw->node);
 out_free:
-	serio->private = NULL;
+	serio_set_drvdata(serio, NULL);
 	kfree(serio_raw);
 out:
 	up(&serio_raw_sem);
+	return err;
 }
 
 static int serio_raw_reconnect(struct serio *serio)
 {
-	struct serio_raw *serio_raw = serio->private;
+	struct serio_raw *serio_raw = serio_get_drvdata(serio);
 	struct serio_driver *drv = serio->drv;
 
 	if (!drv || !serio_raw) {
@@ -351,10 +351,10 @@ static void serio_raw_disconnect(struct 
 
 	down(&serio_raw_sem);
 
-	serio_raw = serio->private;
+	serio_raw = serio_get_drvdata(serio);
 
 	serio_close(serio);
-	serio->private = NULL;
+	serio_set_drvdata(serio, NULL);
 
 	serio_raw->serio = NULL;
 	if (!serio_raw_cleanup(serio_raw))
@@ -363,11 +363,24 @@ static void serio_raw_disconnect(struct 
 	up(&serio_raw_sem);
 }
 
+static struct serio_device_id serio_raw_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids);
+
 static struct serio_driver serio_raw_drv = {
 	.driver		= {
 		.name	= "serio_raw",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= serio_raw_serio_ids,
 	.interrupt	= serio_raw_interrupt,
 	.connect	= serio_raw_connect,
 	.reconnect	= serio_raw_reconnect,
@@ -375,13 +388,13 @@ static struct serio_driver serio_raw_drv
 	.manual_bind	= 1,
 };
 
-int __init serio_raw_init(void)
+static int __init serio_raw_init(void)
 {
 	serio_register_driver(&serio_raw_drv);
 	return 0;
 }
 
-void __exit serio_raw_exit(void)
+static void __exit serio_raw_exit(void)
 {
 	serio_unregister_driver(&serio_raw_drv);
 }
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -27,11 +27,15 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_MOUSE);
 
 #define SERPORT_BUSY	1
+#define SERPORT_ACTIVE	2
+#define SERPORT_DEAD	3
 
 struct serport {
 	struct tty_struct *tty;
 	wait_queue_head_t wait;
 	struct serio *serio;
+	struct serio_device_id id;
+	spinlock_t lock;
 	unsigned long flags;
 };
 
@@ -45,11 +49,29 @@ static int serport_serio_write(struct se
 	return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
 }
 
+static int serport_serio_open(struct serio *serio)
+{
+	struct serport *serport = serio->port_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serport->lock, flags);
+	set_bit(SERPORT_ACTIVE, &serport->flags);
+	spin_unlock_irqrestore(&serport->lock, flags);
+
+	return 0;
+}
+
+
 static void serport_serio_close(struct serio *serio)
 {
 	struct serport *serport = serio->port_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serport->lock, flags);
+	clear_bit(SERPORT_ACTIVE, &serport->flags);
+	set_bit(SERPORT_DEAD, &serport->flags);
+	spin_unlock_irqrestore(&serport->lock, flags);
 
-	serport->serio->type = 0;
 	wake_up_interruptible(&serport->wait);
 }
 
@@ -61,36 +83,21 @@ static void serport_serio_close(struct s
 static int serport_ldisc_open(struct tty_struct *tty)
 {
 	struct serport *serport;
-	struct serio *serio;
-	char name[64];
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
-	if (unlikely(!serport || !serio)) {
-		kfree(serport);
-		kfree(serio);
+	serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+	if (!serport)
 		return -ENOMEM;
-	}
 
-	memset(serport, 0, sizeof(struct serport));
-	serport->serio = serio;
-	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	serport->tty = tty;
-	tty->disc_data = serport;
-
-	memset(serio, 0, sizeof(struct serio));
-	strlcpy(serio->name, "Serial port", sizeof(serio->name));
-	snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
-	serio->type = SERIO_RS232;
-	serio->write = serport_serio_write;
-	serio->close = serport_serio_close;
-	serio->port_data = serport;
-
+	spin_lock_init(&serport->lock);
 	init_waitqueue_head(&serport->wait);
 
+	tty->disc_data = serport;
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
 	return 0;
 }
 
@@ -100,7 +107,8 @@ static int serport_ldisc_open(struct tty
 
 static void serport_ldisc_close(struct tty_struct *tty)
 {
-	struct serport *serport = (struct serport*) tty->disc_data;
+	struct serport *serport = (struct serport *) tty->disc_data;
+
 	kfree(serport);
 }
 
@@ -116,9 +124,19 @@ static void serport_ldisc_close(struct t
 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
+	unsigned long flags;
 	int i;
+
+	spin_lock_irqsave(&serport->lock, flags);
+
+	if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+		goto out;
+
 	for (i = 0; i < count; i++)
 		serio_interrupt(serport->serio, cp[i], 0, NULL);
+
+out:
+	spin_unlock_irqrestore(&serport->lock, flags);
 }
 
 /*
@@ -141,16 +159,33 @@ static int serport_ldisc_room(struct tty
 static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
+	struct serio *serio;
 	char name[64];
 
 	if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
 		return -EBUSY;
 
+	serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+	if (!serio)
+		return -ENOMEM;
+
+	strlcpy(serio->name, "Serial port", sizeof(serio->name));
+	snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
+	serio->id = serport->id;
+	serio->id.type = SERIO_RS232;
+	serio->write = serport_serio_write;
+	serio->open = serport_serio_open;
+	serio->close = serport_serio_close;
+	serio->port_data = serport;
+
 	serio_register_port(serport->serio);
 	printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
-	wait_event_interruptible(serport->wait, !serport->serio->type);
+
+	wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
 	serio_unregister_port(serport->serio);
+	serport->serio = NULL;
 
+	clear_bit(SERPORT_DEAD, &serport->flags);
 	clear_bit(SERPORT_BUSY, &serport->flags);
 
 	return 0;
@@ -163,18 +198,31 @@ static ssize_t serport_ldisc_read(struct
 static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
+	unsigned long type;
+
+	if (cmd == SPIOCSTYPE) {
+		if (get_user(type, (unsigned long __user *) arg))
+			return -EFAULT;
 
-	if (cmd == SPIOCSTYPE)
-		return get_user(serport->serio->type, (unsigned long __user *) arg);
+		serport->id.proto = type & 0x000000ff;
+		serport->id.id	  = (type & 0x0000ff00) >> 8;
+		serport->id.extra = (type & 0x00ff0000) >> 16;
+
+		return 0;
+	}
 
 	return -EINVAL;
 }
 
 static void serport_ldisc_write_wakeup(struct tty_struct * tty)
 {
-	struct serport *sp = (struct serport *) tty->disc_data;
+	struct serport *serport = (struct serport *) tty->disc_data;
+	unsigned long flags;
 
-	serio_drv_write_wakeup(sp->serio);
+	spin_lock_irqsave(&serport->lock, flags);
+	if (test_bit(SERPORT_ACTIVE, &serport->flags))
+		serio_drv_write_wakeup(serport->serio);
+	spin_unlock_irqrestore(&serport->lock, flags);
 }
 
 /*
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1,18 +1,19 @@
 #
 # Mouse driver configuration
 #
-config INPUT_TOUCHSCREEN
+menuconfig INPUT_TOUCHSCREEN
 	bool "Touchscreens"
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported touchscreens will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_TOUCHSCREEN
+
 config TOUCHSCREEN_BITSY
-	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen input driver"
-	depends on SA1100_BITSY && INPUT && INPUT_TOUCHSCREEN
+	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
+	depends on SA1100_BITSY
 	select SERIO
 	help
 	  Say Y here if you have the h3600 (Bitsy) touchscreen.
@@ -22,9 +23,21 @@ config TOUCHSCREEN_BITSY
 	  To compile this driver as a module, choose M here: the
 	  module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CORGI
+	tristate "Corgi touchscreen (for Sharp SL-C7xx)"
+	depends on PXA_SHARPSL
+	default y	
+	help
+	  Say Y here to enable the driver for the touchscreen on the 
+	  Sharp SL-C7xx series of PDAs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ads7846_ts.
+
 config TOUCHSCREEN_GUNZE
 	tristate "Gunze AHL-51S touchscreen"
-	depends on INPUT && INPUT_TOUCHSCREEN
 	select SERIO
 	help
 	  Say Y here if you have the Gunze AHL-51 touchscreen connected to
@@ -35,3 +48,51 @@ config TOUCHSCREEN_GUNZE
 	  To compile this driver as a module, choose M here: the
 	  module will be called gunze.
 
+config TOUCHSCREEN_ELO
+	tristate "Elo serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have an Elo serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gunze.
+
+config TOUCHSCREEN_MTOUCH
+	tristate "MicroTouch serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mtouch.
+
+config TOUCHSCREEN_MK712
+	tristate "ICS MicroClock MK712 touchscreen"
+	help
+	  Say Y here if you have the ICS MicroClock MK712 touchscreen
+	  controller chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mk712.
+
+config TOUCHSCREEN_HP600
+	tristate "HP Jornada 680/690 touchscreen"
+	depends on SH_HP600 && SH_ADC
+	help
+	  Say Y here if you have a HP Jornada 680 or 690 and want to
+          support the built-in touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hp680_ts_input.
+
+endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -5,4 +5,9 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_TOUCHSCREEN_BITSY)	+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CORGI)	+= corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
+obj-$(CONFIG_TOUCHSCREEN_ELO)	+= elo.o
+obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
+obj-$(CONFIG_TOUCHSCREEN_MK712)	+= mk712.o
+obj-$(CONFIG_TOUCHSCREEN_HP600)	+= hp680_ts_input.o
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -0,0 +1,380 @@
+/*
+ *  Touchscreen driver for Sharp Corgi models (SL-C7xx)
+ *
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+
+#define PWR_MODE_ACTIVE		0
+#define PWR_MODE_SUSPEND	1
+
+#define X_AXIS_MAX		3830
+#define X_AXIS_MIN		150
+#define Y_AXIS_MAX		3830
+#define Y_AXIS_MIN		190
+#define PRESSURE_MIN		0
+#define PRESSURE_MAX		15000
+
+struct ts_event {
+	short pressure;
+	short x;
+	short y;
+};
+
+struct corgi_ts {
+	char phys[32];
+	struct input_dev input;
+	struct timer_list timer;
+	struct ts_event tc;
+	int pendown;
+	int power_mode;
+};
+
+#define STATUS_HSYNC		(GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
+
+#define SyncHS()	while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
+#define CCNT(a)		asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
+#define CCNT_ON()	{int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
+#define CCNT_OFF()	{int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
+
+#define WAIT_HS_400_VGA		7013U	// 17.615us
+#define WAIT_HS_400_QVGA	16622U	// 41.750us
+
+
+/* ADS7846 Touch Screen Controller bit definitions */
+#define ADSCTRL_PD0		(1u << 0)	/* PD0 */
+#define ADSCTRL_PD1		(1u << 1)	/* PD1 */
+#define ADSCTRL_DFR		(1u << 2)	/* SER/DFR */
+#define ADSCTRL_MOD		(1u << 3)	/* Mode */
+#define ADSCTRL_ADR_SH	4	/* Address setting */
+#define ADSCTRL_STS		(1u << 7)	/* Start Bit */
+
+/* External Functions */
+extern int w100fb_get_xres(void);
+extern int w100fb_get_blanking(void);
+extern int w100fb_get_fastsysclk(void);
+extern unsigned int get_clk_frequency_khz(int info);
+
+static unsigned long calc_waittime(void)
+{
+	int w100fb_xres = w100fb_get_xres();
+	unsigned int waittime = 0;
+
+	if (w100fb_xres == 480 || w100fb_xres == 640) {
+		waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
+
+		if (w100fb_get_fastsysclk() == 100)
+			waittime = waittime * 75 / 100;
+
+		if (w100fb_xres == 640)
+			waittime *= 3;
+
+		return waittime;
+	}
+
+	return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
+}
+
+static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
+{
+	int pos = 0;
+	unsigned long timer1 = 0, timer2;
+	int dosleep;
+
+	dosleep = !w100fb_get_blanking();
+
+	if (dosleep && doSend) {
+		CCNT_ON();
+		/* polling HSync */
+		SyncHS();
+		/* get CCNT */
+		CCNT(timer1);
+	}
+
+	if (doRecive)
+		pos = corgi_ssp_ads7846_get();
+
+	if (doSend) {
+		int cmd = ADSCTRL_PD0 | ADSCTRL_PD1 | (address << ADSCTRL_ADR_SH) | ADSCTRL_STS;
+		/* dummy command */
+		corgi_ssp_ads7846_put(cmd);
+		corgi_ssp_ads7846_get();
+
+		if (dosleep) {
+			/* Wait after HSync */
+			CCNT(timer2);
+			if (timer2-timer1 > wait_time) {
+				/* timeout */
+				SyncHS();
+				/* get OSCR */
+				CCNT(timer1);
+				/* Wait after HSync */
+				CCNT(timer2);
+			}
+			while (timer2 - timer1 < wait_time)
+				CCNT(timer2);
+		}
+		corgi_ssp_ads7846_put(cmd);
+		if (dosleep)
+			CCNT_OFF();
+	}
+	return pos;
+}
+
+static int read_xydata(struct corgi_ts *corgi_ts)
+{
+	unsigned int x, y, z1, z2;
+	unsigned long flags, wait_time;
+
+	/* critical section */
+	local_irq_save(flags);
+	corgi_ssp_ads7846_lock();
+	wait_time=calc_waittime();
+
+	/* Y-axis */
+	sync_receive_data_send_cmd(0, 1, 1u, wait_time);
+
+	/* Y-axis */
+	sync_receive_data_send_cmd(1, 1, 1u, wait_time);
+
+	/* X-axis */
+	y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
+
+	/* Z1 */
+	x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
+
+	/* Z2 */
+	z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
+	z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
+
+	/* Power-Down Enable */
+	corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	corgi_ssp_ads7846_get();
+
+	corgi_ssp_ads7846_unlock();
+	local_irq_restore(flags);
+
+	if (x== 0 || y == 0 || z1 == 0 || (x * (z2 - z1) / z1) >= 15000) {
+		corgi_ts->tc.pressure = 0;
+		return 0;
+	}
+
+	corgi_ts->tc.x = x;
+	corgi_ts->tc.y = y;
+	corgi_ts->tc.pressure = (x * (z2 - z1)) / z1;
+	return 1;
+}
+
+static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
+{
+	if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
+		return;
+
+	if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
+		return;
+
+	if (regs)
+		input_regs(&corgi_ts->input, regs);
+
+	input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x);
+	input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y);
+	input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
+	input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0));
+	input_sync(&corgi_ts->input);
+}
+
+static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
+{
+	if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
+		/* Disable Interrupt */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
+		if (read_xydata(corgi_ts)) {
+			corgi_ts->pendown = 1;
+			new_data(corgi_ts, regs);
+		}
+		mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
+	} else {
+		if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) {
+			mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
+			corgi_ts->pendown++;
+			return;
+		}
+
+		if (corgi_ts->pendown) {
+			corgi_ts->tc.pressure = 0;
+			new_data(corgi_ts, regs);
+		}
+
+		/* Enable Falling Edge */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+		corgi_ts->pendown = 0;
+	}
+}
+
+static void corgi_ts_timer(unsigned long data)
+{
+	struct corgi_ts *corgits_data = (struct corgi_ts *) data;
+	ts_interrupt_main(corgits_data, 1, NULL);
+}
+
+static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct corgi_ts *corgits_data = dev_id;
+	ts_interrupt_main(corgits_data, 0, regs);
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
+{
+	if (level == SUSPEND_POWER_DOWN) {
+		struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+		if (corgi_ts->pendown) {
+			del_timer_sync(&corgi_ts->timer);
+			corgi_ts->tc.pressure = 0;
+			new_data(corgi_ts, NULL);
+			corgi_ts->pendown = 0;
+		}
+		corgi_ts->power_mode = PWR_MODE_SUSPEND;
+
+		corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	}
+	return 0;
+}
+
+static int corgits_resume(struct device *dev, uint32_t level)
+{
+	if (level == RESUME_POWER_ON) {
+		struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+		corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+		/* Enable Falling Edge */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+		corgi_ts->power_mode = PWR_MODE_ACTIVE;
+	}
+	return 0;
+}
+#else
+#define corgits_suspend		NULL
+#define corgits_resume		NULL
+#endif
+
+static int __init corgits_probe(struct device *dev)
+{
+	struct corgi_ts *corgi_ts;
+
+	if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, corgi_ts);
+
+	memset(corgi_ts, 0, sizeof(struct corgi_ts));
+
+	init_input_dev(&corgi_ts->input);
+	corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+	input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+	input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
+
+	strcpy(corgi_ts->phys, "corgits/input0");
+
+	corgi_ts->input.private = corgi_ts;
+	corgi_ts->input.name = "Corgi Touchscreen";
+	corgi_ts->input.dev = dev;
+	corgi_ts->input.phys = corgi_ts->phys;
+	corgi_ts->input.id.bustype = BUS_HOST;
+	corgi_ts->input.id.vendor = 0x0001;
+	corgi_ts->input.id.product = 0x0002;
+	corgi_ts->input.id.version = 0x0100;
+
+	pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
+	pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+
+	/* Initiaize ADS7846 Difference Reference mode */
+	corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+
+	init_timer(&corgi_ts->timer);
+	corgi_ts->timer.data = (unsigned long) corgi_ts;
+	corgi_ts->timer.function = corgi_ts_timer;
+
+	input_register_device(&corgi_ts->input);
+	corgi_ts->power_mode = PWR_MODE_ACTIVE;
+
+	if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
+		input_unregister_device(&corgi_ts->input);
+		kfree(corgi_ts);
+		return -EBUSY;
+	}
+
+	/* Enable Falling Edge */
+	set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+
+	printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
+
+	return 0;
+}
+
+static int corgits_remove(struct device *dev)
+{
+	struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+	free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
+	del_timer_sync(&corgi_ts->timer);
+	input_unregister_device(&corgi_ts->input);
+	kfree(corgi_ts);
+	return 0;
+}
+
+static struct device_driver corgits_driver = {
+	.name		= "corgi-ts",
+	.bus		= &platform_bus_type,
+	.probe		= corgits_probe,
+	.remove		= corgits_remove,
+	.suspend	= corgits_suspend,
+	.resume		= corgits_resume,
+};
+
+static int __devinit corgits_init(void)
+{
+	return driver_register(&corgits_driver);
+}
+
+static void __exit corgits_exit(void)
+{
+	driver_unregister(&corgits_driver);
+}
+
+module_init(corgits_init);
+module_exit(corgits_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/touchscreen/elo.c
@@ -0,0 +1,315 @@
+/*
+ * Elo serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * 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 can handle serial Elo touchscreens using either the Elo standard
+ * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo
+ * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Elo serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	ELO_MAX_LENGTH	10
+
+static char *elo_name = "Elo Serial TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct elo {
+	struct input_dev dev;
+	struct serio *serio;
+	int id;
+	int idx;
+	unsigned char csum;
+	unsigned char data[ELO_MAX_LENGTH];
+	char phys[32];
+};
+
+static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->csum += elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0:
+			if (data != 'U') {
+				elo->idx = 0;
+				elo->csum = 0;
+			}
+			break;
+
+		case 1:
+			if (data != 'T') {
+				elo->idx = 0;
+				elo->csum = 0;
+			}
+			break;
+
+		case 9:
+			if (elo->csum) {
+				input_regs(dev, regs);
+				input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+				input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+				input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
+				input_report_key(dev, BTN_TOUCH, elo->data[2] & 3);
+				input_sync(dev);
+			}
+			elo->idx = 0;
+			elo->csum = 0;
+			break;
+	}
+}
+
+static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
+		case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
+		case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
+
+		case 3:
+			if (data & 0xc0) {
+				elo->idx = 0;
+				break;
+			}
+
+			input_regs(dev, regs);
+			input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+			input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+
+			if (elo->id == 2) {
+				input_report_key(dev, BTN_TOUCH, 1);
+				input_sync(dev);
+				elo->idx = 0;
+			}
+
+			break;
+
+		case 4:
+			if (data) {
+				input_sync(dev);
+				elo->idx = 0;
+			}
+			break;
+
+		case 5:
+			if ((data & 0xf0) == 0) {
+				input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+				input_report_key(dev, BTN_TOUCH, elo->data[5]);
+			}
+			input_sync(dev);
+			elo->idx = 0;
+			break;
+	}
+}
+
+static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0:
+			if ((data & 0x7f) != 0x01)
+				elo->idx = 0;
+			break;
+		case 2:
+			input_regs(dev, regs);
+			input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+			input_report_abs(dev, ABS_X, elo->data[1]);
+			input_report_abs(dev, ABS_Y, elo->data[2]);
+			input_sync(dev);
+			elo->idx = 0;
+			break;
+	}
+}
+
+static irqreturn_t elo_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct elo* elo = serio_get_drvdata(serio);
+
+	switch(elo->id) {
+		case 0:
+			elo_process_data_10(elo, data, regs);
+			break;
+
+		case 1:
+		case 2:
+			elo_process_data_6(elo, data, regs);
+			break;
+
+		case 3:
+			elo_process_data_3(elo, data, regs);
+			break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * elo_disconnect() is the opposite of elo_connect()
+ */
+
+static void elo_disconnect(struct serio *serio)
+{
+	struct elo* elo = serio_get_drvdata(serio);
+
+	input_unregister_device(&elo->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	kfree(elo);
+}
+
+/*
+ * elo_connect() is the routine that is called when someone adds a
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
+ */
+
+static int elo_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct elo *elo;
+	int err;
+
+	if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(elo, 0, sizeof(struct elo));
+
+	init_input_dev(&elo->dev);
+	elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	elo->id = serio->id.id;
+
+	switch (elo->id) {
+
+		case 0: /* 10-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
+			break;
+		
+		case 1: /* 6-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
+
+		case 2: /* 4-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
+			break;
+
+		case 3: /* 3-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0);
+			break;
+	}
+
+	elo->serio = serio;
+
+	sprintf(elo->phys, "%s/input0", serio->phys);
+
+	elo->dev.private = elo;
+	elo->dev.name = elo_name;
+	elo->dev.phys = elo->phys;
+	elo->dev.id.bustype = BUS_RS232;
+	elo->dev.id.vendor = SERIO_ELO;
+	elo->dev.id.product = elo->id;
+	elo->dev.id.version = 0x0100;
+
+	serio_set_drvdata(serio, elo);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
+		kfree(elo);
+		return err;
+	}
+
+	input_register_device(&elo->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys);
+
+	return 0;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id elo_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_ELO,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, elo_serio_ids);
+
+static struct serio_driver elo_drv = {
+	.driver		= {
+		.name	= "elo",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= elo_serio_ids,
+	.interrupt	= elo_interrupt,
+	.connect	= elo_connect,
+	.disconnect	= elo_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init elo_init(void)
+{
+	serio_register_driver(&elo_drv);
+	return 0;
+}
+
+static void __exit elo_exit(void)
+{
+	serio_unregister_driver(&elo_drv);
+}
+
+module_init(elo_init);
+module_exit(elo_exit);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -68,14 +68,13 @@ static void gunze_process_packet(struct 
 
 	if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
 		(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
-		gunze->data[10] = 0;
-		printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
+		printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
 		return;
 	}
 
 	input_regs(dev, regs);
-	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
-	input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
+	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
+	input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
 	input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
 	input_sync(dev);
 }
@@ -83,7 +82,7 @@ static void gunze_process_packet(struct 
 static irqreturn_t gunze_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct gunze* gunze = serio->private;
+	struct gunze* gunze = serio_get_drvdata(serio);
 
 	if (data == '\r') {
 		gunze_process_packet(gunze, regs);
@@ -101,38 +100,37 @@ static irqreturn_t gunze_interrupt(struc
 
 static void gunze_disconnect(struct serio *serio)
 {
-	struct gunze* gunze = serio->private;
+	struct gunze* gunze = serio_get_drvdata(serio);
+
 	input_unregister_device(&gunze->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(gunze);
 }
 
 /*
  * gunze_connect() is the routine that is called when someone adds a
- * new serio device. It looks whether it was registered as a Gunze touchscreen
- * and if yes, registers it as an input device.
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
  */
 
-static void gunze_connect(struct serio *serio, struct serio_driver *drv)
+static int gunze_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct gunze *gunze;
-
-	if (serio->type != (SERIO_RS232 | SERIO_GUNZE))
-		return;
+	int err;
 
 	if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(gunze, 0, sizeof(struct gunze));
 
 	init_input_dev(&gunze->dev);
 	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
-	input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
+	input_set_abs_params(&gunze->dev, ABS_X, 24, 1000, 0, 0);
+	input_set_abs_params(&gunze->dev, ABS_Y, 24, 1000, 0, 0);
 
 	gunze->serio = serio;
-	serio->private = gunze;
 
 	sprintf(gunze->phys, "%s/input0", serio->phys);
 
@@ -144,25 +142,44 @@ static void gunze_connect(struct serio *
 	gunze->dev.id.product = 0x0051;
 	gunze->dev.id.version = 0x0100;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, gunze);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(gunze);
-		return;
+		return err;
 	}
 
 	input_register_device(&gunze->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id gunze_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_GUNZE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, gunze_serio_ids);
+
 static struct serio_driver gunze_drv = {
 	.driver		= {
 		.name	= "gunze",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= gunze_serio_ids,
 	.interrupt	= gunze_interrupt,
 	.connect	= gunze_connect,
 	.disconnect	= gunze_disconnect,
@@ -172,13 +189,13 @@ static struct serio_driver gunze_drv = {
  * The functions for inserting/removing us as a module.
  */
 
-int __init gunze_init(void)
+static int __init gunze_init(void)
 {
 	serio_register_driver(&gunze_drv);
 	return 0;
 }
 
-void __exit gunze_exit(void)
+static void __exit gunze_exit(void)
 {
 	serio_unregister_driver(&gunze_drv);
 }
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -102,6 +102,7 @@ struct h3600_dev {
 	struct input_dev dev;
 	struct pm_dev *pm_dev;
 	struct serio *serio;
+	struct pm_dev *pm_dev;
 	unsigned char event;	/* event ID from packet */
 	unsigned char chksum;
 	unsigned char len;
@@ -331,7 +332,7 @@ static int state;
 static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
                                      unsigned int flags, struct pt_regs *regs)
 {
-        struct h3600_dev *ts = serio->private;
+        struct h3600_dev *ts = serio_get_drvdata(serio);
 
 	/*
          * We have a new frame coming in.
@@ -373,18 +374,16 @@ static irqreturn_t h3600ts_interrupt(str
 
 /*
  * h3600ts_connect() is the routine that is called when someone adds a
- * new serio device. It looks whether it was registered as a H3600 touchscreen
- * and if yes, registers it as an input device.
+ * new serio device that supports H3600 protocol and registers it as
+ * an input device.
  */
-static void h3600ts_connect(struct serio *serio, struct serio_driver *drv)
+static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct h3600_dev *ts;
-
-	if (serio->type != (SERIO_RS232 | SERIO_H3600))
-		return;
+	int err;
 
 	if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(ts, 0, sizeof(struct h3600_dev));
 
@@ -399,7 +398,7 @@ static void h3600ts_connect(struct serio
 			"h3600_action", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 		kfree(ts);
-		return;
+		return -EBUSY;
 	}
 
         if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
@@ -408,7 +407,7 @@ static void h3600ts_connect(struct serio
 		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
 		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
 		kfree(ts);
-		return;
+		return -EBUSY;
 	}
 
 	/* Now we have things going we setup our input device */
@@ -431,7 +430,6 @@ static void h3600ts_connect(struct serio
 	ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
 
 	ts->serio = serio;
-	serio->private = ts;
 
 	sprintf(ts->phys, "%s/input0", serio->phys);
 
@@ -444,11 +442,15 @@ static void h3600ts_connect(struct serio
 	ts->dev.id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
 	ts->dev.id.version = 0x0100;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, ts);
+
+	err = serio_open(serio, drv);
+	if (err) {
         	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
         	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+		serio_set_drvdata(serio, NULL);
 		kfree(ts);
-		return;
+		return err;
 	}
 
 	//h3600_flite_control(1, 25);     /* default brightness */
@@ -460,6 +462,8 @@ static void h3600ts_connect(struct serio
 	input_register_device(&ts->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -468,24 +472,38 @@ static void h3600ts_connect(struct serio
 
 static void h3600ts_disconnect(struct serio *serio)
 {
-	struct h3600_dev *ts = serio->private;
+	struct h3600_dev *ts = serio_get_drvdata(serio);
 
-        free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
-        free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
+	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
 	input_unregister_device(&ts->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(ts);
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id h3600ts_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_H3600,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);
+
 static struct serio_driver h3600ts_drv = {
 	.driver		= {
 		.name	= "h3600ts",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= h3600ts_serio_ids,
 	.interrupt	= h3600ts_interrupt,
 	.connect	= h3600ts_connect,
 	.disconnect	= h3600ts_disconnect,
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -0,0 +1,135 @@
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/adc.h>
+#include <asm/hp6xx/hp6xx.h>
+
+#define MODNAME "hp680_ts_input"
+
+#define HP680_TS_ABS_X_MIN	40
+#define HP680_TS_ABS_X_MAX	950
+#define HP680_TS_ABS_Y_MIN	80
+#define HP680_TS_ABS_Y_MAX	910
+
+#define	SCPCR	0xa4000116
+#define	PHDR	0xa400012e
+#define SCPDR	0xa4000136
+
+static void do_softint(void *data);
+
+static struct input_dev hp680_ts_dev;
+static DECLARE_WORK(work, do_softint, 0);
+static char *hp680_ts_name = "HP Jornada touchscreen";
+static char *hp680_ts_phys = "input0";
+
+static void do_softint(void *data)
+{
+	int absx = 0, absy = 0;
+	u8 scpdr;
+	int touched = 0;
+
+	if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) {
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_ENABLE;
+		scpdr &= ~SCPDR_TS_SCAN_Y;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(30);
+
+		absy = adc_single(ADC_CHANNEL_TS_Y);
+
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_Y;
+		scpdr &= ~SCPDR_TS_SCAN_X;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(30);
+
+		absx = adc_single(ADC_CHANNEL_TS_X);
+
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_X;
+		scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(100);
+		touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN;
+	}
+
+	if (touched) {
+		input_report_key(&hp680_ts_dev, BTN_TOUCH, 1);
+		input_report_abs(&hp680_ts_dev, ABS_X, absx);
+		input_report_abs(&hp680_ts_dev, ABS_Y, absy);
+	} else {
+		input_report_key(&hp680_ts_dev, BTN_TOUCH, 0);
+	}
+
+	input_sync(&hp680_ts_dev);
+	enable_irq(HP680_TS_IRQ);
+}
+
+static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	disable_irq_nosync(irq);
+	schedule_delayed_work(&work, HZ / 20);
+
+	return IRQ_HANDLED;
+}
+
+static int __init hp680_ts_init(void)
+{
+	u8 scpdr;
+	u16 scpcr;
+
+	scpdr = ctrl_inb(SCPDR);
+	scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
+	scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+	ctrl_outb(scpdr, SCPDR);
+
+	scpcr = ctrl_inw(SCPCR);
+	scpcr &= ~SCPCR_TS_MASK;
+	scpcr |= SCPCR_TS_ENABLE;
+	ctrl_outw(scpcr, SCPCR);
+
+	memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev));
+	init_input_dev(&hp680_ts_dev);
+
+	hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+	hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN;
+	hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN;
+	hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX;
+	hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX;
+
+	hp680_ts_dev.name = hp680_ts_name;
+	hp680_ts_dev.phys = hp680_ts_phys;
+	input_register_device(&hp680_ts_dev);
+
+	if (request_irq
+	    (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) {
+		printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n",
+		       HP680_TS_IRQ);
+		input_unregister_device(&hp680_ts_dev);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void __exit hp680_ts_exit(void)
+{
+	free_irq(HP680_TS_IRQ, 0);
+	cancel_delayed_work(&work);
+	flush_scheduled_work();
+	input_unregister_device(&hp680_ts_dev);
+}
+
+module_init(hp680_ts_init);
+module_exit(hp680_ts_exit);
+
+MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
+MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/touchscreen/mk712.c
@@ -0,0 +1,222 @@
+/*
+ * ICS MK712 touchscreen controller driver
+ *
+ * Copyright (c) 1999-2002 Transmeta Corporation
+ * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ */
+
+/*
+ * 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 supports the ICS MicroClock MK712 TouchScreen controller,
+ * found in Gateway AOL Connected Touchpad computers.
+ *
+ * Documentation for ICS MK712 can be found at:
+ * 	http://www.icst.com/pdf/mk712.pdf
+ */
+
+/*
+ * 1999-12-18: original version, Daniel Quinlan
+ * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
+ *             to use queue_empty, Nathan Laredo
+ * 1999-12-20: improved random point rejection, Nathan Laredo
+ * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
+ *             queue code, added module options, other fixes, Daniel Quinlan
+ * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
+ *             Fixed multi open race, fixed memory checks, fixed resource
+ *             allocation, fixed close/powerdown bug, switched to new init
+ * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
+ * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
+MODULE_LICENSE("GPL");
+
+static unsigned int mk712_io = 0x260;	/* Also 0x200, 0x208, 0x300 */
+module_param_named(io, mk712_io, uint, 0);
+MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
+
+static unsigned int mk712_irq = 10;	/* Also 12, 14, 15 */
+module_param_named(irq, mk712_irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
+
+/* eight 8-bit registers */
+#define MK712_STATUS		0
+#define MK712_X			2
+#define MK712_Y			4
+#define MK712_CONTROL		6
+#define MK712_RATE		7
+
+/* status */
+#define	MK712_STATUS_TOUCH			0x10
+#define	MK712_CONVERSION_COMPLETE		0x80
+
+/* control */
+#define MK712_ENABLE_INT			0x01
+#define MK712_INT_ON_CONVERSION_COMPLETE	0x02
+#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS	0x04
+#define MK712_ENABLE_PERIODIC_CONVERSIONS	0x10
+#define MK712_READ_ONE_POINT			0x20
+#define MK712_POWERUP				0x40
+
+static int mk712_used = 0;
+static struct input_dev mk712_dev;
+static DEFINE_SPINLOCK(mk712_lock);
+
+static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned char status;
+	static int debounce = 1;
+	static unsigned short last_x;
+	static unsigned short last_y;
+
+	spin_lock(&mk712_lock);
+	input_regs(&mk712_dev, regs);
+
+	status = inb(mk712_io + MK712_STATUS);
+
+	if (~status & MK712_CONVERSION_COMPLETE) {
+		debounce = 1;
+		goto end;
+	}
+
+	if (~status & MK712_STATUS_TOUCH)
+	{
+		debounce = 1;
+		input_report_key(&mk712_dev, BTN_TOUCH, 0);
+		goto end;
+	}
+
+	if (debounce)
+	{
+		debounce = 0;
+		goto end;
+	}
+
+	input_report_key(&mk712_dev, BTN_TOUCH, 1);
+	input_report_abs(&mk712_dev, ABS_X, last_x);
+	input_report_abs(&mk712_dev, ABS_Y, last_y);
+
+end:
+
+	last_x = inw(mk712_io + MK712_X) & 0x0fff;
+	last_y = inw(mk712_io + MK712_Y) & 0x0fff;
+	input_sync(&mk712_dev);
+	spin_unlock(&mk712_lock);
+	return IRQ_HANDLED;
+}
+
+static int mk712_open(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	if (!mk712_used++) {
+
+		outb(0, mk712_io + MK712_CONTROL); /* Reset */
+
+		outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+			MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+			MK712_ENABLE_PERIODIC_CONVERSIONS |
+			MK712_POWERUP, mk712_io + MK712_CONTROL);
+
+		outb(10, mk712_io + MK712_RATE); /* 187 points per second */
+	}
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+
+	return 0;
+}
+
+static void mk712_close(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	if (!--mk712_used)
+		outb(0, mk712_io + MK712_CONTROL);
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+}
+
+static struct input_dev mk712_dev = {
+	.evbit   = { BIT(EV_KEY) | BIT(EV_ABS) },
+	.keybit  = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+	.absbit  = { BIT(ABS_X) | BIT(ABS_Y) },
+	.open    = mk712_open,
+	.close   = mk712_close,
+	.name    = "ICS MicroClock MK712 TouchScreen",
+	.phys    = "isa0260/input0",
+	.absmin  = { [ABS_X] = 0, [ABS_Y] = 0 },
+	.absmax  = { [ABS_X] = 0xfff, [ABS_Y] = 0xfff },
+	.absfuzz = { [ABS_X] = 88, [ABS_Y] = 88 },
+	.id      = {
+		.bustype = BUS_ISA,
+		.vendor  = 0x0005,
+		.product = 0x0001,
+		.version = 0x0100,
+	},
+};
+
+int __init mk712_init(void)
+{
+
+	if(!request_region(mk712_io, 8, "mk712"))
+	{
+		printk(KERN_WARNING "mk712: unable to get IO region\n");
+		return -ENODEV;
+	}
+
+	outb(0, mk712_io + MK712_CONTROL);
+
+	if ((inw(mk712_io + MK712_X) & 0xf000) ||	/* Sanity check */
+	    (inw(mk712_io + MK712_Y) & 0xf000) ||
+	    (inw(mk712_io + MK712_STATUS) & 0xf333)) {
+		printk(KERN_WARNING "mk712: device not present\n");
+		release_region(mk712_io, 8);
+		return -ENODEV;
+	}
+
+	if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712", &mk712_dev))
+	{
+		printk(KERN_WARNING "mk712: unable to get IRQ\n");
+		release_region(mk712_io, 8);
+		return -EBUSY;
+	}
+
+	input_register_device(&mk712_dev);
+
+	printk(KERN_INFO "input: ICS MicroClock MK712 TouchScreen at %#x irq %d\n", mk712_io, mk712_irq);
+
+	return 0;
+}
+
+static void __exit mk712_exit(void)
+{
+	input_unregister_device(&mk712_dev);
+	free_irq(mk712_irq, &mk712_dev);
+	release_region(mk712_io, 8);
+}
+
+module_init(mk712_init);
+module_exit(mk712_exit);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
new file mode 100644
--- /dev/null
+++ b/drivers/input/touchscreen/mtouch.c
@@ -0,0 +1,219 @@
+/*
+ * MicroTouch (3M) serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 2005/02/19 Dan Streetman <ddstreet@ieee.org>
+ *   Copied elo.c and edited for MicroTouch protocol
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"MicroTouch serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80
+#define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40
+#define MTOUCH_FORMAT_TABLET_LENGTH 5
+#define MTOUCH_RESPONSE_BEGIN_BYTE 0x01
+#define MTOUCH_RESPONSE_END_BYTE 0x0d
+
+/* todo: check specs for max length of all responses */
+#define MTOUCH_MAX_LENGTH 16
+
+#define MTOUCH_MIN_XC 0
+#define MTOUCH_MAX_XC 0x3fff
+#define MTOUCH_MIN_YC 0
+#define MTOUCH_MAX_YC 0x3fff
+
+#define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1])
+#define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3])
+#define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0])
+
+static char *mtouch_name = "MicroTouch Serial TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct mtouch {
+	struct input_dev dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[MTOUCH_MAX_LENGTH];
+	char phys[32];
+};
+
+static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs)
+{
+	struct input_dev *dev = &mtouch->dev;
+
+	if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
+		input_regs(dev, regs);
+		input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
+		input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
+		input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
+		input_sync(dev);
+
+		mtouch->idx = 0;
+	}
+}
+
+static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
+{
+	if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
+		/* FIXME - process response */
+		mtouch->idx = 0;
+	} else if (MTOUCH_MAX_LENGTH == mtouch->idx) {
+		printk(KERN_ERR "mtouch.c: too many response bytes\n");
+		mtouch->idx = 0;
+	}
+}
+
+static irqreturn_t mtouch_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	mtouch->data[mtouch->idx] = data;
+
+	if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
+		mtouch_process_format_tablet(mtouch, regs);
+	else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
+		mtouch_process_response(mtouch, regs);
+	else
+		printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * mtouch_disconnect() is the opposite of mtouch_connect()
+ */
+
+static void mtouch_disconnect(struct serio *serio)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	input_unregister_device(&mtouch->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	kfree(mtouch);
+}
+
+/*
+ * mtouch_connect() is the routine that is called when someone adds a
+ * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as
+ * an input device.
+ */
+
+static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct mtouch *mtouch;
+	int err;
+
+	if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(mtouch, 0, sizeof(*mtouch));
+
+	init_input_dev(&mtouch->dev);
+	mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
+	input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
+
+	mtouch->serio = serio;
+
+	sprintf(mtouch->phys, "%s/input0", serio->phys);
+
+	mtouch->dev.private = mtouch;
+	mtouch->dev.name = mtouch_name;
+	mtouch->dev.phys = mtouch->phys;
+	mtouch->dev.id.bustype = BUS_RS232;
+	mtouch->dev.id.vendor = SERIO_MICROTOUCH;
+	mtouch->dev.id.product = 0;
+	mtouch->dev.id.version = 0x0100;
+
+	serio_set_drvdata(serio, mtouch);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
+		kfree(mtouch);
+		return err;
+	}
+
+	input_register_device(&mtouch->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys);
+
+	return 0;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id mtouch_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MICROTOUCH,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
+
+static struct serio_driver mtouch_drv = {
+	.driver		= {
+		.name	= "mtouch",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= mtouch_serio_ids,
+	.interrupt	= mtouch_interrupt,
+	.connect	= mtouch_connect,
+	.disconnect	= mtouch_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init mtouch_init(void)
+{
+	serio_register_driver(&mtouch_drv);
+	return 0;
+}
+
+static void __exit mtouch_exit(void)
+{
+	serio_unregister_driver(&mtouch_drv);
+}
+
+module_init(mtouch_init);
+module_exit(mtouch_exit);
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -232,11 +232,9 @@ static ssize_t tsdev_read(struct file *f
 static unsigned int tsdev_poll(struct file *file, poll_table * wait)
 {
 	struct tsdev_list *list = file->private_data;
-
 	poll_wait(file, &list->tsdev->wait, wait);
-	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int tsdev_ioctl(struct inode *inode, struct file *file,
@@ -265,7 +263,7 @@ static int tsdev_ioctl(struct inode *ino
 	return retval;
 }
 
-struct file_operations tsdev_fops = {
+static struct file_operations tsdev_fops = {
 	.owner =	THIS_MODULE,
 	.open =		tsdev_open,
 	.release =	tsdev_release,
@@ -426,6 +424,7 @@ static struct input_handle *tsdev_connec
 static void tsdev_disconnect(struct input_handle *handle)
 {
 	struct tsdev *tsdev = handle->private;
+	struct tsdev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
 	devfs_remove("input/ts%d", tsdev->minor);
@@ -435,6 +434,8 @@ static void tsdev_disconnect(struct inpu
 	if (tsdev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&tsdev->wait);
+		list_for_each_entry(list, &tsdev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else
 		tsdev_free(tsdev);
 }
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -13,4 +13,3 @@ obj-$(CONFIG_ISDN_DRV_SC)		+= sc/
 obj-$(CONFIG_ISDN_DRV_LOOP)		+= isdnloop/
 obj-$(CONFIG_ISDN_DRV_ACT2000)		+= act2000/
 obj-$(CONFIG_HYSDN)			+= hysdn/
-obj-$(CONFIG_ISDN_DRV_TPAM)		+= tpam/
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -401,7 +401,6 @@ int
 act2000_isa_download(act2000_card * card, act2000_ddef __user * cb)
 {
         unsigned int length;
-        int ret;
         int l;
         int c;
         long timeout;
@@ -413,12 +412,12 @@ act2000_isa_download(act2000_card * card
         if (!act2000_isa_reset(card->port))
                 return -ENXIO;
         msleep_interruptible(500);
-        if(copy_from_user(&cblock, cb, sizeof(cblock)))
+        if (copy_from_user(&cblock, cb, sizeof(cblock)))
         	return -EFAULT;
         length = cblock.length;
         p = cblock.buffer;
-        if ((ret = verify_area(VERIFY_READ, p, length)))
-                return ret;
+        if (!access_ok(VERIFY_READ, p, length))
+                return -EFAULT;
         buf = (u_char *) kmalloc(1024, GFP_KERNEL);
         if (!buf)
                 return -ENOMEM;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -60,12 +60,12 @@ MODULE_LICENSE("GPL");
 
 static struct class_simple *capi_class;
 
-int capi_major = 68;		/* allocated */
+static int capi_major = 68;		/* allocated */
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 #define CAPINC_NR_PORTS	32
 #define CAPINC_MAX_PORTS	256
-int capi_ttymajor = 191;
-int capi_ttyminors = CAPINC_NR_PORTS;
+static int capi_ttymajor = 191;
+static int capi_ttyminors = CAPINC_NR_PORTS;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
 module_param_named(major, capi_major, uint, 0);
@@ -268,7 +268,7 @@ static void capiminor_free(struct capimi
 	kfree(mp);
 }
 
-struct capiminor *capiminor_find(unsigned int minor)
+static struct capiminor *capiminor_find(unsigned int minor)
 {
 	struct list_head *l;
 	struct capiminor *p = NULL;
@@ -1166,7 +1166,7 @@ static int capinc_tty_write_room(struct 
 	return room;
 }
 
-int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	struct capiminor *mp = (struct capiminor *)tty->driver_data;
 	if (!mp || !mp->nccip) {
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -89,14 +89,14 @@ static int contrstats_show(struct seq_fi
 	return 0;
 }
 
-struct seq_operations seq_controller_ops = {
+static struct seq_operations seq_controller_ops = {
 	.start	= controller_start,
 	.next	= controller_next,
 	.stop	= controller_stop,
 	.show	= controller_show,
 };
 
-struct seq_operations seq_contrstats_ops = {
+static struct seq_operations seq_contrstats_ops = {
 	.start	= controller_start,
 	.next	= controller_next,
 	.stop	= controller_stop,
@@ -192,14 +192,14 @@ applstats_show(struct seq_file *seq, voi
 	return 0;
 }
 
-struct seq_operations seq_applications_ops = {
+static struct seq_operations seq_applications_ops = {
 	.start	= applications_start,
 	.next	= applications_next,
 	.stop	= applications_stop,
 	.show	= applications_show,
 };
 
-struct seq_operations seq_applstats_ops = {
+static struct seq_operations seq_applstats_ops = {
 	.start	= applications_start,
 	.next	= applications_next,
 	.stop	= applications_stop,
@@ -287,7 +287,7 @@ static int capi_driver_show(struct seq_f
 	return 0;
 }
 
-struct seq_operations seq_capi_driver_ops = {
+static struct seq_operations seq_capi_driver_ops = {
 	.start	= capi_driver_start,
 	.next	= capi_driver_next,
 	.stop	= capi_driver_stop,
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -383,7 +383,7 @@ divert_rule *getruleptr(int idx)
 /*************************************************/
 /* called from common module on an incoming call */
 /*************************************************/
-int isdn_divert_icall(isdn_ctrl *ic)
+static int isdn_divert_icall(isdn_ctrl *ic)
 { int retval = 0;
   unsigned long flags;
   struct call_struc *cs = NULL; 
@@ -552,7 +552,7 @@ void deleteprocs(void)
 /****************************************************/
 /* put a address including address type into buffer */
 /****************************************************/
-int put_address(char *st, u_char *p, int len)
+static int put_address(char *st, u_char *p, int len)
 { u_char retval = 0;
   u_char adr_typ = 0; /* network standard */
 
@@ -595,7 +595,7 @@ int put_address(char *st, u_char *p, int
 /*************************************/
 /* report a succesfull interrogation */
 /*************************************/
-int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
+static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
 { char *src = ic->parm.dss1_io.data;
   int restlen = ic->parm.dss1_io.datalen;
   int cnt = 1;
@@ -689,7 +689,7 @@ int interrogate_success(isdn_ctrl *ic, s
 /*********************************************/
 /* callback for protocol specific extensions */
 /*********************************************/
-int prot_stat_callback(isdn_ctrl *ic)
+static int prot_stat_callback(isdn_ctrl *ic)
 { struct call_struc *cs, *cs1;
   int i;
   unsigned long flags;
@@ -781,7 +781,7 @@ int prot_stat_callback(isdn_ctrl *ic)
 /***************************/
 /* status callback from HL */
 /***************************/
-int isdn_divert_stat_callback(isdn_ctrl *ic)
+static int isdn_divert_stat_callback(isdn_ctrl *ic)
 { struct call_struc *cs, *cs1;
   unsigned long flags;
   int retval;
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
--- a/drivers/isdn/hardware/avm/b1pci.c
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -391,7 +391,7 @@ static int __init b1pci_init(void)
 		strcpy(rev, "1.0");
 
 
-	err = pci_module_init(&b1pci_pci_driver);
+	err = pci_register_driver(&b1pci_pci_driver);
 	if (!err) {
 		strlcpy(capi_driver_b1pci.revision, rev, 32);
 		register_capi_driver(&capi_driver_b1pci);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -1288,7 +1288,7 @@ static int __init c4_init(void)
 	} else
 		strcpy(rev, "1.0");
 
-	err = pci_module_init(&c4_pci_driver);
+	err = pci_register_driver(&c4_pci_driver);
 	if (!err) {
 		strlcpy(capi_driver_c2.revision, rev, 32);
 		register_capi_driver(&capi_driver_c2);
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
--- a/drivers/isdn/hardware/avm/t1pci.c
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -241,7 +241,7 @@ static int __init t1pci_init(void)
 	} else
 		strcpy(rev, "1.0");
 
-	err = pci_module_init(&t1pci_pci_driver);
+	err = pci_register_driver(&t1pci_pci_driver);
 	if (!err) {
 		strlcpy(capi_driver_t1pci.revision, rev, 32);
 		register_capi_driver(&capi_driver_t1pci);
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -411,6 +411,12 @@ config HISAX_HFCUSB
 	help
 	  This enables the driver for HFC USB based ISDN modems.
 
+config HISAX_HFC4S8S
+	tristate "HFC-4S/8S based ISDN cards (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  This enables the driver for HFC-4S/8S based ISDN cards.
+
 config HISAX_FRITZ_PCIPNP
 	tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
 	depends on PCI && EXPERIMENTAL
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_HISAX_AVM_A1_CS)		+= avma1_
 obj-$(CONFIG_HISAX_TELES_CS)		+= teles_cs.o
 obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o
 obj-$(CONFIG_HISAX_HFCUSB)		+= hfc_usb.o
+obj-$(CONFIG_HISAX_HFC4S8S)		+= hfc4s8s_l1.o
 obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_isac.o hisax_fcpcipnp.o
 
 ifdef CONFIG_HISAX_HDLC
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -838,7 +838,7 @@ static 	struct pci_dev *dev_qs1000 __dev
 static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id elsa_ids[] __initdata = {
+static struct isapnp_device_id elsa_ids[] __devinitdata = {
 	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
 	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), 
 	  (unsigned long) "Elsa QS1000" },
@@ -848,7 +848,7 @@ static struct isapnp_device_id elsa_ids[
 	{ 0, }
 };
 
-static struct isapnp_device_id *ipid __initdata = &elsa_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
new file mode 100644
--- /dev/null
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -0,0 +1,1715 @@
+/*************************************************************************/
+/* $Id: hfc4s8s_l1.c,v 1.10 2005/02/09 16:31:09 martinb1 Exp $           */
+/* HFC-4S/8S low layer interface for Cologne Chip HFC-4S/8S isdn chips   */
+/* The low layer (L1) is implemented as a loadable module for usage with */
+/* the HiSax isdn driver for passive cards.                              */
+/*                                                                       */
+/* Author: Werner Cornelius                                              */
+/* (C) 2003 Cornelius Consult (werner@cornelius-consult.de)              */
+/*                                                                       */
+/* Driver maintained by Cologne Chip                                     */
+/*   - Martin Bachem, support@colognechip.com                            */
+/*                                                                       */
+/* This driver only works with chip revisions >= 1, older revision 0     */
+/* engineering samples (only first manufacturer sample cards) will not   */
+/* work and are rejected by the driver.                                  */
+/*                                                                       */
+/* This file distributed under the GNU GPL.                              */
+/*                                                                       */
+/* See Version History at the end of this file                           */
+/*                                                                       */
+/*************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include "hisax_if.h"
+#include "hfc4s8s_l1.h"
+
+static const char hfc4s8s_rev[] = "Revision: 1.10";
+
+/***************************************************************/
+/* adjustable transparent mode fifo threshold                  */
+/* The value defines the used fifo threshold with the equation */
+/*                                                             */
+/* notify number of bytes = 2 * 2 ^ TRANS_FIFO_THRES           */
+/*                                                             */
+/* The default value is 5 which results in a buffer size of 64 */
+/* and an interrupt rate of 8ms.                               */
+/* The maximum value is 7 due to fifo size restrictions.       */
+/* Values below 3-4 are not recommended due to high interrupt  */
+/* load of the processor. For non critical applications the    */
+/* value should be raised to 7 to reduce any interrupt overhead*/
+/***************************************************************/
+#define TRANS_FIFO_THRES 5
+
+/*************/
+/* constants */
+/*************/
+#define CLOCKMODE_0     0	/* ext. 24.576 MhZ clk freq, int. single clock mode */
+#define CLOCKMODE_1     1	/* ext. 49.576 MhZ clk freq, int. single clock mode */
+#define CHIP_ID_SHIFT   4
+#define HFC_MAX_ST 8
+#define MAX_D_FRAME_SIZE 270
+#define MAX_B_FRAME_SIZE 1536
+#define TRANS_TIMER_MODE (TRANS_FIFO_THRES & 0xf)
+#define TRANS_FIFO_BYTES (2 << TRANS_FIFO_THRES)
+#define MAX_F_CNT 0x0f
+
+#define CLKDEL_NT 0x6c
+#define CLKDEL_TE 0xf
+#define CTRL0_NT  4
+#define CTRL0_TE  0
+
+#define L1_TIMER_T4 2		/* minimum in jiffies */
+#define L1_TIMER_T3 (7 * HZ)	/* activation timeout */
+#define L1_TIMER_T1 ((120 * HZ) / 1000)	/* NT mode deactivation timeout */
+
+
+/******************/
+/* types and vars */
+/******************/
+static int card_cnt;
+
+/* private driver_data */
+typedef struct {
+	int chip_id;
+	int clock_mode;
+	int max_st_ports;
+	char *device_name;
+} hfc4s8s_param;
+
+static struct pci_device_id hfc4s8s_ids[] = {
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = PCI_DEVICE_ID_4S,
+	 .subvendor = 0x1397,
+	 .subdevice = 0x08b4,
+	 .driver_data =
+	 (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_0, 4,
+					    "HFC-4S Evaluation Board"}),
+	 },
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = PCI_DEVICE_ID_8S,
+	 .subvendor = 0x1397,
+	 .subdevice = 0x16b8,
+	 .driver_data =
+	 (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_0, 8,
+					    "HFC-8S Evaluation Board"}),
+	 },
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = PCI_DEVICE_ID_4S,
+	 .subvendor = 0x1397,
+	 .subdevice = 0xb520,
+	 .driver_data =
+	 (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_1, 4,
+					    "IOB4ST"}),
+	 },
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = PCI_DEVICE_ID_8S,
+	 .subvendor = 0x1397,
+	 .subdevice = 0xb522,
+	 .driver_data =
+	 (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_1, 8,
+					    "IOB8ST"}),
+	 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(pci, hfc4s8s_ids);
+
+MODULE_AUTHOR("Werner Cornelius, werner@cornelius-consult.de");
+MODULE_DESCRIPTION("ISDN layer 1 for Cologne Chip HFC-4S/8S chips");
+MODULE_LICENSE("GPL");
+
+/***********/
+/* layer 1 */
+/***********/
+struct hfc4s8s_btype {
+	spinlock_t lock;
+	struct hisax_b_if b_if;
+	struct hfc4s8s_l1 *l1p;
+	struct sk_buff_head tx_queue;
+	struct sk_buff *tx_skb;
+	struct sk_buff *rx_skb;
+	__u8 *rx_ptr;
+	int tx_cnt;
+	int bchan;
+	int mode;
+};
+
+struct _hfc4s8s_hw;
+
+struct hfc4s8s_l1 {
+	spinlock_t lock;
+	struct _hfc4s8s_hw *hw;	/* pointer to hardware area */
+	int l1_state;		/* actual l1 state */
+	struct timer_list l1_timer;	/* layer 1 timer structure */
+	int nt_mode;		/* set to nt mode */
+	int st_num;		/* own index */
+	int enabled;		/* interface is enabled */
+	struct sk_buff_head d_tx_queue;	/* send queue */
+	int tx_cnt;		/* bytes to send */
+	struct hisax_d_if d_if;	/* D-channel interface */
+	struct hfc4s8s_btype b_ch[2];	/* B-channel data */
+	struct hisax_b_if *b_table[2];
+};
+
+/**********************/
+/* hardware structure */
+/**********************/
+typedef struct _hfc4s8s_hw {
+	spinlock_t lock;
+
+	int cardnum;
+	int ifnum;
+	int iobase;
+	int nt_mode;
+	u_char *membase;
+	u_char *hw_membase;
+	void *pdev;
+	int max_fifo;
+	hfc4s8s_param driver_data;
+	int irq;
+	int fifo_sched_cnt;
+	struct work_struct tqueue;
+	struct hfc4s8s_l1 l1[HFC_MAX_ST];
+	char card_name[60];
+	struct {
+		u_char r_irq_ctrl;
+		u_char r_ctrl0;
+		volatile u_char r_irq_statech;	/* active isdn l1 status */
+		u_char r_irqmsk_statchg;	/* enabled isdn status ints */
+		u_char r_irq_fifo_blx[8];	/* fifo status registers */
+		u_char fifo_rx_trans_enables[8];	/* mask for enabled transparent rx fifos */
+		u_char fifo_slow_timer_service[8];	/* mask for fifos needing slower timer service */
+		volatile u_char r_irq_oview;	/* contents of overview register */
+		volatile u_char timer_irq;
+		int timer_usg_cnt;	/* number of channels using timer */
+	} mr;
+} hfc4s8s_hw;
+
+
+
+/***************************/
+/* inline function defines */
+/***************************/
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM	/* inline functions mempry mapped */
+
+/* memory write and dummy IO read to avoid PCI byte merge problems */
+#define Write_hfc8(a,b,c) {(*((volatile u_char *)(a->membase+b)) = c); inb(a->iobase+4);}
+/* memory write without dummy IO access for fifo data access */
+#define fWrite_hfc8(a,b,c) (*((volatile u_char *)(a->membase+b)) = c)
+#define Read_hfc8(a,b) (*((volatile u_char *)(a->membase+b)))
+#define Write_hfc16(a,b,c) (*((volatile unsigned short *)(a->membase+b)) = c)
+#define Read_hfc16(a,b) (*((volatile unsigned short *)(a->membase+b)))
+#define Write_hfc32(a,b,c) (*((volatile unsigned long *)(a->membase+b)) = c)
+#define Read_hfc32(a,b) (*((volatile unsigned long *)(a->membase+b)))
+#define wait_busy(a) {while ((Read_hfc8(a, R_STATUS) & M_BUSY));}
+#define PCI_ENA_MEMIO	0x03
+
+#else
+
+/* inline functions io mapped */
+static inline void
+SetRegAddr(hfc4s8s_hw * a, u_char b)
+{
+	outb(b, (a->iobase) + 4);
+}
+
+static inline u_char
+GetRegAddr(hfc4s8s_hw * a)
+{
+	return (inb((volatile u_int) (a->iobase + 4)));
+}
+
+
+static inline void
+Write_hfc8(hfc4s8s_hw * a, u_char b, u_char c)
+{
+	SetRegAddr(a, b);
+	outb(c, a->iobase);
+}
+
+static inline void
+fWrite_hfc8(hfc4s8s_hw * a, u_char c)
+{
+	outb(c, a->iobase);
+}
+
+static inline void
+Write_hfc16(hfc4s8s_hw * a, u_char b, u_short c)
+{
+	SetRegAddr(a, b);
+	outw(c, a->iobase);
+}
+
+static inline void
+Write_hfc32(hfc4s8s_hw * a, u_char b, u_long c)
+{
+	SetRegAddr(a, b);
+	outl(c, a->iobase);
+}
+
+static inline void
+fWrite_hfc32(hfc4s8s_hw * a, u_long c)
+{
+	outl(c, a->iobase);
+}
+
+static inline u_char
+Read_hfc8(hfc4s8s_hw * a, u_char b)
+{
+	SetRegAddr(a, b);
+	return (inb((volatile u_int) a->iobase));
+}
+
+static inline u_char
+fRead_hfc8(hfc4s8s_hw * a)
+{
+	return (inb((volatile u_int) a->iobase));
+}
+
+
+static inline u_short
+Read_hfc16(hfc4s8s_hw * a, u_char b)
+{
+	SetRegAddr(a, b);
+	return (inw((volatile u_int) a->iobase));
+}
+
+static inline u_long
+Read_hfc32(hfc4s8s_hw * a, u_char b)
+{
+	SetRegAddr(a, b);
+	return (inl((volatile u_int) a->iobase));
+}
+
+static inline u_long
+fRead_hfc32(hfc4s8s_hw * a)
+{
+	return (inl((volatile u_int) a->iobase));
+}
+
+static inline void
+wait_busy(hfc4s8s_hw * a)
+{
+	SetRegAddr(a, R_STATUS);
+	while (inb((volatile u_int) a->iobase) & M_BUSY);
+}
+
+#define PCI_ENA_REGIO	0x01
+
+#endif				/* CONFIG_HISAX_HFC4S8S_PCIMEM */
+
+/******************************************************/
+/* function to read critical counter registers that   */
+/* may be udpated by the chip during read             */
+/******************************************************/
+static volatile u_char
+Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
+{
+	u_char ref8;
+	u_char in8;
+	ref8 = Read_hfc8(hw, reg);
+	while (((in8 = Read_hfc8(hw, reg)) != ref8)) {
+		ref8 = in8;
+	}
+	return in8;
+}
+
+static volatile int
+Read_hfc16_stable(hfc4s8s_hw * hw, int reg)
+{
+	int ref16;
+	int in16;
+
+	ref16 = Read_hfc16(hw, reg);
+	while (((in16 = Read_hfc16(hw, reg)) != ref16)) {
+		ref16 = in16;
+	}
+	return in16;
+}
+
+/*****************************/
+/* D-channel call from HiSax */
+/*****************************/
+static void
+dch_l2l1(struct hisax_d_if *iface, int pr, void *arg)
+{
+	struct hfc4s8s_l1 *l1 = iface->ifc.priv;
+	struct sk_buff *skb = (struct sk_buff *) arg;
+	u_long flags;
+
+	switch (pr) {
+
+		case (PH_DATA | REQUEST):
+			if (!l1->enabled) {
+				dev_kfree_skb(skb);
+				break;
+			}
+			spin_lock_irqsave(&l1->lock, flags);
+			skb_queue_tail(&l1->d_tx_queue, skb);
+			if ((skb_queue_len(&l1->d_tx_queue) == 1) &&
+			    (l1->tx_cnt <= 0)) {
+				l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
+				    0x10;
+				spin_unlock_irqrestore(&l1->lock, flags);
+				schedule_work(&l1->hw->tqueue);
+			} else
+				spin_unlock_irqrestore(&l1->lock, flags);
+			break;
+
+		case (PH_ACTIVATE | REQUEST):
+			if (!l1->enabled)
+				break;
+			if (!l1->nt_mode) {
+				if (l1->l1_state < 6) {
+					spin_lock_irqsave(&l1->lock,
+							  flags);
+
+					Write_hfc8(l1->hw, R_ST_SEL,
+						   l1->st_num);
+					Write_hfc8(l1->hw, A_ST_WR_STA,
+						   0x60);
+					mod_timer(&l1->l1_timer,
+						  jiffies + L1_TIMER_T3);
+					spin_unlock_irqrestore(&l1->lock,
+							       flags);
+				} else if (l1->l1_state == 7)
+					l1->d_if.ifc.l1l2(&l1->d_if.ifc,
+							  PH_ACTIVATE |
+							  INDICATION,
+							  NULL);
+			} else {
+				if (l1->l1_state != 3) {
+					spin_lock_irqsave(&l1->lock,
+							  flags);
+					Write_hfc8(l1->hw, R_ST_SEL,
+						   l1->st_num);
+					Write_hfc8(l1->hw, A_ST_WR_STA,
+						   0x60);
+					spin_unlock_irqrestore(&l1->lock,
+							       flags);
+				} else if (l1->l1_state == 3)
+					l1->d_if.ifc.l1l2(&l1->d_if.ifc,
+							  PH_ACTIVATE |
+							  INDICATION,
+							  NULL);
+			}
+			break;
+
+		default:
+			printk(KERN_INFO
+			       "HFC-4S/8S: Unknown D-chan cmd 0x%x received, ignored\n",
+			       pr);
+			break;
+	}
+	if (!l1->enabled)
+		l1->d_if.ifc.l1l2(&l1->d_if.ifc,
+				  PH_DEACTIVATE | INDICATION, NULL);
+}				/* dch_l2l1 */
+
+/*****************************/
+/* B-channel call from HiSax */
+/*****************************/
+static void
+bch_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+	struct hfc4s8s_btype *bch = ifc->priv;
+	struct hfc4s8s_l1 *l1 = bch->l1p;
+	struct sk_buff *skb = (struct sk_buff *) arg;
+	int mode = (int) arg;
+	u_long flags;
+
+	switch (pr) {
+
+		case (PH_DATA | REQUEST):
+			if (!l1->enabled || (bch->mode == L1_MODE_NULL)) {
+				dev_kfree_skb(skb);
+				break;
+			}
+			spin_lock_irqsave(&l1->lock, flags);
+			skb_queue_tail(&bch->tx_queue, skb);
+			if (!bch->tx_skb && (bch->tx_cnt <= 0)) {
+				l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
+				    ((bch->bchan == 1) ? 1 : 4);
+				spin_unlock_irqrestore(&l1->lock, flags);
+				schedule_work(&l1->hw->tqueue);
+			} else
+				spin_unlock_irqrestore(&l1->lock, flags);
+			break;
+
+		case (PH_ACTIVATE | REQUEST):
+		case (PH_DEACTIVATE | REQUEST):
+			if (!l1->enabled)
+				break;
+			if (pr == (PH_DEACTIVATE | REQUEST))
+				mode = L1_MODE_NULL;
+
+			switch (mode) {
+				case L1_MODE_HDLC:
+					spin_lock_irqsave(&l1->lock,
+							  flags);
+					l1->hw->mr.timer_usg_cnt++;
+					l1->hw->mr.
+					    fifo_slow_timer_service[l1->
+								    st_num]
+					    |=
+					    ((bch->bchan ==
+					      1) ? 0x2 : 0x8);
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 0 : 2)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_CON_HDLC, 0xc);	/* HDLC mode, flag fill, connect ST */
+					Write_hfc8(l1->hw, A_SUBCH_CFG, 0);	/* 8 bits */
+					Write_hfc8(l1->hw, A_IRQ_MSK, 1);	/* enable TX interrupts for hdlc */
+					Write_hfc8(l1->hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+					wait_busy(l1->hw);
+
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 1 : 3)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_CON_HDLC, 0xc);	/* HDLC mode, flag fill, connect ST */
+					Write_hfc8(l1->hw, A_SUBCH_CFG, 0);	/* 8 bits */
+					Write_hfc8(l1->hw, A_IRQ_MSK, 1);	/* enable RX interrupts for hdlc */
+					Write_hfc8(l1->hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+
+					Write_hfc8(l1->hw, R_ST_SEL,
+						   l1->st_num);
+					l1->hw->mr.r_ctrl0 |=
+					    (bch->bchan & 3);
+					Write_hfc8(l1->hw, A_ST_CTRL0,
+						   l1->hw->mr.r_ctrl0);
+					bch->mode = L1_MODE_HDLC;
+					spin_unlock_irqrestore(&l1->lock,
+							       flags);
+
+					bch->b_if.ifc.l1l2(&bch->b_if.ifc,
+							   PH_ACTIVATE |
+							   INDICATION,
+							   NULL);
+					break;
+
+				case L1_MODE_TRANS:
+					spin_lock_irqsave(&l1->lock,
+							  flags);
+					l1->hw->mr.
+					    fifo_rx_trans_enables[l1->
+								  st_num]
+					    |=
+					    ((bch->bchan ==
+					      1) ? 0x2 : 0x8);
+					l1->hw->mr.timer_usg_cnt++;
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 0 : 2)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_CON_HDLC, 0xf);	/* Transparent mode, 1 fill, connect ST */
+					Write_hfc8(l1->hw, A_SUBCH_CFG, 0);	/* 8 bits */
+					Write_hfc8(l1->hw, A_IRQ_MSK, 0);	/* disable TX interrupts */
+					Write_hfc8(l1->hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+					wait_busy(l1->hw);
+
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 1 : 3)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_CON_HDLC, 0xf);	/* Transparent mode, 1 fill, connect ST */
+					Write_hfc8(l1->hw, A_SUBCH_CFG, 0);	/* 8 bits */
+					Write_hfc8(l1->hw, A_IRQ_MSK, 0);	/* disable RX interrupts */
+					Write_hfc8(l1->hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+
+					Write_hfc8(l1->hw, R_ST_SEL,
+						   l1->st_num);
+					l1->hw->mr.r_ctrl0 |=
+					    (bch->bchan & 3);
+					Write_hfc8(l1->hw, A_ST_CTRL0,
+						   l1->hw->mr.r_ctrl0);
+					bch->mode = L1_MODE_TRANS;
+					spin_unlock_irqrestore(&l1->lock,
+							       flags);
+
+					bch->b_if.ifc.l1l2(&bch->b_if.ifc,
+							   PH_ACTIVATE |
+							   INDICATION,
+							   NULL);
+					break;
+
+				default:
+					if (bch->mode == L1_MODE_NULL)
+						break;
+					spin_lock_irqsave(&l1->lock,
+							  flags);
+					l1->hw->mr.
+					    fifo_slow_timer_service[l1->
+								    st_num]
+					    &=
+					    ~((bch->bchan ==
+					       1) ? 0x3 : 0xc);
+					l1->hw->mr.
+					    fifo_rx_trans_enables[l1->
+								  st_num]
+					    &=
+					    ~((bch->bchan ==
+					       1) ? 0x3 : 0xc);
+					l1->hw->mr.timer_usg_cnt--;
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 0 : 2)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_IRQ_MSK, 0);	/* disable TX interrupts */
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, R_FIFO,
+						   (l1->st_num * 8 +
+						    ((bch->bchan ==
+						      1) ? 1 : 3)));
+					wait_busy(l1->hw);
+					Write_hfc8(l1->hw, A_IRQ_MSK, 0);	/* disable RX interrupts */
+					Write_hfc8(l1->hw, R_ST_SEL,
+						   l1->st_num);
+					l1->hw->mr.r_ctrl0 &=
+					    ~(bch->bchan & 3);
+					Write_hfc8(l1->hw, A_ST_CTRL0,
+						   l1->hw->mr.r_ctrl0);
+					spin_unlock_irqrestore(&l1->lock,
+							       flags);
+
+					bch->mode = L1_MODE_NULL;
+					bch->b_if.ifc.l1l2(&bch->b_if.ifc,
+							   PH_DEACTIVATE |
+							   INDICATION,
+							   NULL);
+					if (bch->tx_skb) {
+						dev_kfree_skb(bch->tx_skb);
+						bch->tx_skb = NULL;
+					}
+					if (bch->rx_skb) {
+						dev_kfree_skb(bch->rx_skb);
+						bch->rx_skb = NULL;
+					}
+					skb_queue_purge(&bch->tx_queue);
+					bch->tx_cnt = 0;
+					bch->rx_ptr = NULL;
+					break;
+			}
+
+			/* timer is only used when at least one b channel */
+			/* is set up to transparent mode */
+			if (l1->hw->mr.timer_usg_cnt) {
+				Write_hfc8(l1->hw, R_IRQMSK_MISC,
+					   M_TI_IRQMSK);
+			} else {
+				Write_hfc8(l1->hw, R_IRQMSK_MISC, 0);
+			}
+
+			break;
+
+		default:
+			printk(KERN_INFO
+			       "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n",
+			       pr);
+			break;
+	}
+	if (!l1->enabled)
+		bch->b_if.ifc.l1l2(&bch->b_if.ifc,
+				   PH_DEACTIVATE | INDICATION, NULL);
+}				/* bch_l2l1 */
+
+/**************************/
+/* layer 1 timer function */
+/**************************/
+static void
+hfc_l1_timer(struct hfc4s8s_l1 *l1)
+{
+	u_long flags;
+
+	if (!l1->enabled)
+		return;
+
+	spin_lock_irqsave(&l1->lock, flags);
+	if (l1->nt_mode) {
+		l1->l1_state = 1;
+		Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
+		Write_hfc8(l1->hw, A_ST_WR_STA, 0x11);
+		spin_unlock_irqrestore(&l1->lock, flags);
+		l1->d_if.ifc.l1l2(&l1->d_if.ifc,
+				  PH_DEACTIVATE | INDICATION, NULL);
+		spin_lock_irqsave(&l1->lock, flags);
+		l1->l1_state = 1;
+		Write_hfc8(l1->hw, A_ST_WR_STA, 0x1);
+		spin_unlock_irqrestore(&l1->lock, flags);
+	} else {
+		/* activation timed out */
+		Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
+		Write_hfc8(l1->hw, A_ST_WR_STA, 0x13);
+		spin_unlock_irqrestore(&l1->lock, flags);
+		l1->d_if.ifc.l1l2(&l1->d_if.ifc,
+				  PH_DEACTIVATE | INDICATION, NULL);
+		spin_lock_irqsave(&l1->lock, flags);
+		Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
+		Write_hfc8(l1->hw, A_ST_WR_STA, 0x3);
+		spin_unlock_irqrestore(&l1->lock, flags);
+	}
+}				/* hfc_l1_timer */
+
+/****************************************/
+/* a complete D-frame has been received */
+/****************************************/
+static void
+rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
+{
+	int z1, z2;
+	u_char f1, f2, df;
+	struct sk_buff *skb;
+	u_char *cp;
+
+
+	if (!l1p->enabled)
+		return;
+	do {
+		/* E/D RX fifo */
+		Write_hfc8(l1p->hw, R_FIFO,
+			   (l1p->st_num * 8 + ((ech) ? 7 : 5)));
+		wait_busy(l1p->hw);
+
+		f1 = Read_hfc8_stable(l1p->hw, A_F1);
+		f2 = Read_hfc8(l1p->hw, A_F2);
+		df = f1 - f2;
+		if ((f1 - f2) < 0)
+			df = f1 - f2 + MAX_F_CNT + 1;
+
+
+		if (!df) {
+			return;	/* no complete frame in fifo */
+		}
+
+		z1 = Read_hfc16_stable(l1p->hw, A_Z1);
+		z2 = Read_hfc16(l1p->hw, A_Z2);
+
+		z1 = z1 - z2 + 1;
+		if (z1 < 0)
+			z1 += 384;
+
+		if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) {
+			printk(KERN_INFO
+			       "HFC-4S/8S: Could not allocate D/E "
+			       "channel receive buffer");
+			Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
+			wait_busy(l1p->hw);
+			return;
+		}
+
+		if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) {
+			if (skb)
+				dev_kfree_skb(skb);
+			/* remove errornous D frame */
+			if (df == 1) {
+				/* reset fifo */
+				Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
+				wait_busy(l1p->hw);
+				return;
+			} else {
+				/* read errornous D frame */
+
+#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+				SetRegAddr(l1p->hw, A_FIFO_DATA0);
+#endif
+
+				while (z1 >= 4) {
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+					Read_hfc32(l1p->hw, A_FIFO_DATA0);
+#else
+					fRead_hfc32(l1p->hw);
+#endif
+					z1 -= 4;
+				}
+
+				while (z1--)
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+					Read_hfc8(l1p->hw, A_FIFO_DATA0);
+#else
+					fRead_hfc8(l1p->hw);
+#endif
+
+				Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);
+				wait_busy(l1p->hw);
+				return;
+			}
+		}
+
+		cp = skb->data;
+
+#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+		SetRegAddr(l1p->hw, A_FIFO_DATA0);
+#endif
+
+		while (z1 >= 4) {
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			*((unsigned long *) cp) =
+			    Read_hfc32(l1p->hw, A_FIFO_DATA0);
+#else
+			*((unsigned long *) cp) = fRead_hfc32(l1p->hw);
+#endif
+			cp += 4;
+			z1 -= 4;
+		}
+
+		while (z1--)
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			*cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0);
+#else
+			*cp++ = fRead_hfc8(l1p->hw);
+#endif
+
+		Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);	/* increment f counter */
+		wait_busy(l1p->hw);
+
+		if (*(--cp)) {
+			dev_kfree_skb(skb);
+		} else {
+			skb->len = (cp - skb->data) - 2;
+			if (ech)
+				l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
+						   PH_DATA_E | INDICATION,
+						   skb);
+			else
+				l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
+						   PH_DATA | INDICATION,
+						   skb);
+		}
+	} while (1);
+}				/* rx_d_frame */
+
+/*************************************************************/
+/* a B-frame has been received (perhaps not fully completed) */
+/*************************************************************/
+static void
+rx_b_frame(struct hfc4s8s_btype *bch)
+{
+	int z1, z2, hdlc_complete;
+	u_char f1, f2;
+	struct hfc4s8s_l1 *l1 = bch->l1p;
+	struct sk_buff *skb;
+
+	if (!l1->enabled || (bch->mode == L1_MODE_NULL))
+		return;
+
+	do {
+		/* RX Fifo */
+		Write_hfc8(l1->hw, R_FIFO,
+			   (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3)));
+		wait_busy(l1->hw);
+
+		if (bch->mode == L1_MODE_HDLC) {
+			f1 = Read_hfc8_stable(l1->hw, A_F1);
+			f2 = Read_hfc8(l1->hw, A_F2);
+			hdlc_complete = ((f1 ^ f2) & MAX_F_CNT);
+		} else
+			hdlc_complete = 0;
+		z1 = Read_hfc16_stable(l1->hw, A_Z1);
+		z2 = Read_hfc16(l1->hw, A_Z2);
+		z1 = (z1 - z2);
+		if (hdlc_complete)
+			z1++;
+		if (z1 < 0)
+			z1 += 384;
+
+		if (!z1)
+			break;
+
+		if (!(skb = bch->rx_skb)) {
+			if (!
+			    (skb =
+			     dev_alloc_skb((bch->mode ==
+					    L1_MODE_TRANS) ? z1
+					   : (MAX_B_FRAME_SIZE + 3)))) {
+				printk(KERN_ERR
+				       "HFC-4S/8S: Could not allocate B "
+				       "channel receive buffer");
+				return;
+			}
+			bch->rx_ptr = skb->data;
+			bch->rx_skb = skb;
+		}
+
+		skb->len = (bch->rx_ptr - skb->data) + z1;
+
+		/* HDLC length check */
+		if ((bch->mode == L1_MODE_HDLC) &&
+		    ((hdlc_complete && (skb->len < 4)) ||
+		     (skb->len > (MAX_B_FRAME_SIZE + 3)))) {
+
+			skb->len = 0;
+			bch->rx_ptr = skb->data;
+			Write_hfc8(l1->hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+			wait_busy(l1->hw);
+			return;
+		}
+#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+		SetRegAddr(l1->hw, A_FIFO_DATA0);
+#endif
+
+		while (z1 >= 4) {
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			*((unsigned long *) bch->rx_ptr) =
+			    Read_hfc32(l1->hw, A_FIFO_DATA0);
+#else
+			*((unsigned long *) bch->rx_ptr) =
+			    fRead_hfc32(l1->hw);
+#endif
+			bch->rx_ptr += 4;
+			z1 -= 4;
+		}
+
+		while (z1--)
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			*(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0);
+#else
+			*(bch->rx_ptr++) = fRead_hfc8(l1->hw);
+#endif
+
+		if (hdlc_complete) {
+			/* increment f counter */
+			Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
+			wait_busy(l1->hw);
+
+			/* hdlc crc check */
+			bch->rx_ptr--;
+			if (*bch->rx_ptr) {
+				skb->len = 0;
+				bch->rx_ptr = skb->data;
+				continue;
+			}
+			skb->len -= 3;
+		}
+		if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) {
+			bch->rx_skb = NULL;
+			bch->rx_ptr = NULL;
+			bch->b_if.ifc.l1l2(&bch->b_if.ifc,
+					   PH_DATA | INDICATION, skb);
+		}
+
+	} while (1);
+}				/* rx_b_frame */
+
+/********************************************/
+/* a D-frame has been/should be transmitted */
+/********************************************/
+static void
+tx_d_frame(struct hfc4s8s_l1 *l1p)
+{
+	struct sk_buff *skb;
+	u_char f1, f2;
+	u_char *cp;
+	int cnt;
+
+	if (l1p->l1_state != 7)
+		return;
+
+	/* TX fifo */
+	Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4));
+	wait_busy(l1p->hw);
+
+	f1 = Read_hfc8(l1p->hw, A_F1);
+	f2 = Read_hfc8_stable(l1p->hw, A_F2);
+
+	if ((f1 ^ f2) & MAX_F_CNT)
+		return;		/* fifo is still filled */
+
+	if (l1p->tx_cnt > 0) {
+		cnt = l1p->tx_cnt;
+		l1p->tx_cnt = 0;
+		l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM,
+				   (void *) cnt);
+	}
+
+	if ((skb = skb_dequeue(&l1p->d_tx_queue))) {
+		cp = skb->data;
+		cnt = skb->len;
+#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+		SetRegAddr(l1p->hw, A_FIFO_DATA0);
+#endif
+
+		while (cnt >= 4) {
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			fWrite_hfc32(l1p->hw, A_FIFO_DATA0,
+				     *(unsigned long *) cp);
+#else
+			SetRegAddr(l1p->hw, A_FIFO_DATA0);
+			fWrite_hfc32(l1p->hw, *(unsigned long *) cp);
+#endif
+			cp += 4;
+			cnt -= 4;
+		}
+
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+		while (cnt--)
+			fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++);
+#else
+		while (cnt--)
+			fWrite_hfc8(l1p->hw, *cp++);
+#endif
+
+		l1p->tx_cnt = skb->truesize;
+		Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);	/* increment f counter */
+		wait_busy(l1p->hw);
+
+		dev_kfree_skb(skb);
+	}
+}				/* tx_d_frame */
+
+/******************************************************/
+/* a B-frame may be transmitted (or is not completed) */
+/******************************************************/
+static void
+tx_b_frame(struct hfc4s8s_btype *bch)
+{
+	struct sk_buff *skb;
+	struct hfc4s8s_l1 *l1 = bch->l1p;
+	u_char *cp;
+	int cnt, max, hdlc_num, ack_len = 0;
+
+	if (!l1->enabled || (bch->mode == L1_MODE_NULL))
+		return;
+
+	/* TX fifo */
+	Write_hfc8(l1->hw, R_FIFO,
+		   (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2)));
+	wait_busy(l1->hw);
+	do {
+
+		if (bch->mode == L1_MODE_HDLC) {
+			hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT;
+			hdlc_num -=
+			    (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT);
+			if (hdlc_num < 0)
+				hdlc_num += 16;
+			if (hdlc_num >= 15)
+				break;	/* fifo still filled up with hdlc frames */
+		} else
+			hdlc_num = 0;
+
+		if (!(skb = bch->tx_skb)) {
+			if (!(skb = skb_dequeue(&bch->tx_queue))) {
+				l1->hw->mr.fifo_slow_timer_service[l1->
+								   st_num]
+				    &= ~((bch->bchan == 1) ? 1 : 4);
+				break;	/* list empty */
+			}
+			bch->tx_skb = skb;
+			bch->tx_cnt = 0;
+		}
+
+		if (!hdlc_num)
+			l1->hw->mr.fifo_slow_timer_service[l1->st_num] |=
+			    ((bch->bchan == 1) ? 1 : 4);
+		else
+			l1->hw->mr.fifo_slow_timer_service[l1->st_num] &=
+			    ~((bch->bchan == 1) ? 1 : 4);
+
+		max = Read_hfc16_stable(l1->hw, A_Z2);
+		max -= Read_hfc16(l1->hw, A_Z1);
+		if (max <= 0)
+			max += 384;
+		max--;
+
+		if (max < 16)
+			break;	/* don't write to small amounts of bytes */
+
+		cnt = skb->len - bch->tx_cnt;
+		if (cnt > max)
+			cnt = max;
+		cp = skb->data + bch->tx_cnt;
+		bch->tx_cnt += cnt;
+
+#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+		SetRegAddr(l1->hw, A_FIFO_DATA0);
+#endif
+		while (cnt >= 4) {
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			fWrite_hfc32(l1->hw, A_FIFO_DATA0,
+				     *(unsigned long *) cp);
+#else
+			fWrite_hfc32(l1->hw, *(unsigned long *) cp);
+#endif
+			cp += 4;
+			cnt -= 4;
+		}
+
+		while (cnt--)
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+			fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++);
+#else
+			fWrite_hfc8(l1->hw, *cp++);
+#endif
+
+		if (bch->tx_cnt >= skb->len) {
+			if (bch->mode == L1_MODE_HDLC) {
+				/* increment f counter */
+				Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
+			}
+			ack_len += skb->truesize;
+			bch->tx_skb = 0;
+			bch->tx_cnt = 0;
+			dev_kfree_skb(skb);
+		} else
+			/* Re-Select */
+			Write_hfc8(l1->hw, R_FIFO,
+				   (l1->st_num * 8 +
+				    ((bch->bchan == 1) ? 0 : 2)));
+		wait_busy(l1->hw);
+	} while (1);
+
+	if (ack_len)
+		bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if,
+				   PH_DATA | CONFIRM, (void *) ack_len);
+}				/* tx_b_frame */
+
+/*************************************/
+/* bottom half handler for interrupt */
+/*************************************/
+static void
+hfc4s8s_bh(hfc4s8s_hw * hw)
+{
+	u_char b;
+	struct hfc4s8s_l1 *l1p;
+	volatile u_char *fifo_stat;
+	int idx;
+
+	/* handle layer 1 state changes */
+	b = 1;
+	l1p = hw->l1;
+	while (b) {
+		if ((b & hw->mr.r_irq_statech)) {
+			/* reset l1 event */
+			hw->mr.r_irq_statech &= ~b;
+			if (l1p->enabled) {
+				if (l1p->nt_mode) {
+					u_char oldstate = l1p->l1_state;
+
+					Write_hfc8(l1p->hw, R_ST_SEL,
+						   l1p->st_num);
+					l1p->l1_state =
+					    Read_hfc8(l1p->hw,
+						      A_ST_RD_STA) & 0xf;
+
+					if ((oldstate == 3)
+					    && (l1p->l1_state != 3))
+						l1p->d_if.ifc.l1l2(&l1p->
+								   d_if.
+								   ifc,
+								   PH_DEACTIVATE
+								   |
+								   INDICATION,
+								   NULL);
+
+					if (l1p->l1_state != 2) {
+						del_timer(&l1p->l1_timer);
+						if (l1p->l1_state == 3) {
+							l1p->d_if.ifc.
+							    l1l2(&l1p->
+								 d_if.ifc,
+								 PH_ACTIVATE
+								 |
+								 INDICATION,
+								 NULL);
+						}
+					} else {
+						/* allow transition */
+						Write_hfc8(hw, A_ST_WR_STA,
+							   M_SET_G2_G3);
+						mod_timer(&l1p->l1_timer,
+							  jiffies +
+							  L1_TIMER_T1);
+					}
+					printk(KERN_INFO
+					       "HFC-4S/8S: NT ch %d l1 state %d -> %d\n",
+					       l1p->st_num, oldstate,
+					       l1p->l1_state);
+				} else {
+					u_char oldstate = l1p->l1_state;
+
+					Write_hfc8(l1p->hw, R_ST_SEL,
+						   l1p->st_num);
+					l1p->l1_state =
+					    Read_hfc8(l1p->hw,
+						      A_ST_RD_STA) & 0xf;
+
+					if (((l1p->l1_state == 3) &&
+					     ((oldstate == 7) ||
+					      (oldstate == 8))) ||
+					    ((timer_pending
+					      (&l1p->l1_timer))
+					     && (l1p->l1_state == 8))) {
+						mod_timer(&l1p->l1_timer,
+							  L1_TIMER_T4 +
+							  jiffies);
+					} else {
+						if (l1p->l1_state == 7) {
+							del_timer(&l1p->
+								  l1_timer);
+							l1p->d_if.ifc.
+							    l1l2(&l1p->
+								 d_if.ifc,
+								 PH_ACTIVATE
+								 |
+								 INDICATION,
+								 NULL);
+							tx_d_frame(l1p);
+						}
+						if (l1p->l1_state == 3) {
+							if (oldstate != 3)
+								l1p->d_if.
+								    ifc.
+								    l1l2
+								    (&l1p->
+								     d_if.
+								     ifc,
+								     PH_DEACTIVATE
+								     |
+								     INDICATION,
+								     NULL);
+						}
+					}
+					printk(KERN_INFO
+					       "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n",
+					       l1p->hw->cardnum,
+					       l1p->st_num, oldstate,
+					       l1p->l1_state);
+				}
+			}
+		}
+		b <<= 1;
+		l1p++;
+	}
+
+	/* now handle the fifos */
+	idx = 0;
+	fifo_stat = hw->mr.r_irq_fifo_blx;
+	l1p = hw->l1;
+	while (idx < hw->driver_data.max_st_ports) {
+
+		if (hw->mr.timer_irq) {
+			*fifo_stat |= hw->mr.fifo_rx_trans_enables[idx];
+			if (hw->fifo_sched_cnt <= 0) {
+				*fifo_stat |=
+				    hw->mr.fifo_slow_timer_service[l1p->
+								   st_num];
+			}
+		}
+		/* ignore fifo 6 (TX E fifo) */
+		*fifo_stat &= 0xff - 0x40;
+
+		while (*fifo_stat) {
+
+			if (!l1p->nt_mode) {
+				/* RX Fifo has data to read */
+				if ((*fifo_stat & 0x20)) {
+					*fifo_stat &= ~0x20;
+					rx_d_frame(l1p, 0);
+				}
+				/* E Fifo has data to read */
+				if ((*fifo_stat & 0x80)) {
+					*fifo_stat &= ~0x80;
+					rx_d_frame(l1p, 1);
+				}
+				/* TX Fifo completed send */
+				if ((*fifo_stat & 0x10)) {
+					*fifo_stat &= ~0x10;
+					tx_d_frame(l1p);
+				}
+			}
+			/* B1 RX Fifo has data to read */
+			if ((*fifo_stat & 0x2)) {
+				*fifo_stat &= ~0x2;
+				rx_b_frame(l1p->b_ch);
+			}
+			/* B1 TX Fifo has send completed */
+			if ((*fifo_stat & 0x1)) {
+				*fifo_stat &= ~0x1;
+				tx_b_frame(l1p->b_ch);
+			}
+			/* B2 RX Fifo has data to read */
+			if ((*fifo_stat & 0x8)) {
+				*fifo_stat &= ~0x8;
+				rx_b_frame(l1p->b_ch + 1);
+			}
+			/* B2 TX Fifo has send completed */
+			if ((*fifo_stat & 0x4)) {
+				*fifo_stat &= ~0x4;
+				tx_b_frame(l1p->b_ch + 1);
+			}
+		}
+		fifo_stat++;
+		l1p++;
+		idx++;
+	}
+
+	if (hw->fifo_sched_cnt <= 0)
+		hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE));
+	hw->mr.timer_irq = 0;	/* clear requested timer irq */
+}				/* hfc4s8s_bh */
+
+/*********************/
+/* interrupt handler */
+/*********************/
+static irqreturn_t
+hfc4s8s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	hfc4s8s_hw *hw = dev_id;
+	u_char b, ovr;
+	volatile u_char *ovp;
+	int idx;
+	u_char old_ioreg;
+
+	if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN))
+		return IRQ_NONE;
+
+#ifndef	CONFIG_HISAX_HFC4S8S_PCIMEM
+	/* read current selected regsister */
+	old_ioreg = GetRegAddr(hw);
+#endif
+
+	/* Layer 1 State change */
+	hw->mr.r_irq_statech |=
+	    (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg);
+	if (!
+	    (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA)))
+&& !hw->mr.r_irq_statech) {
+#ifndef	CONFIG_HISAX_HFC4S8S_PCIMEM
+		SetRegAddr(hw, old_ioreg);
+#endif
+		return IRQ_NONE;
+	}
+
+	/* timer event */
+	if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) {
+		hw->mr.timer_irq = 1;
+		hw->fifo_sched_cnt--;
+	}
+
+	/* FIFO event */
+	if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) {
+		hw->mr.r_irq_oview |= ovr;
+		idx = R_IRQ_FIFO_BL0;
+		ovp = hw->mr.r_irq_fifo_blx;
+		while (ovr) {
+			if ((ovr & 1)) {
+				*ovp |= Read_hfc8(hw, idx);
+			}
+			ovp++;
+			idx++;
+			ovr >>= 1;
+		}
+	}
+
+	/* queue the request to allow other cards to interrupt */
+	schedule_work(&hw->tqueue);
+
+#ifndef	CONFIG_HISAX_HFC4S8S_PCIMEM
+	SetRegAddr(hw, old_ioreg);
+#endif
+	return IRQ_HANDLED;
+}				/* hfc4s8s_interrupt */
+
+/***********************************************************************/
+/* reset the complete chip, don't release the chips irq but disable it */
+/***********************************************************************/
+static void
+chipreset(hfc4s8s_hw * hw)
+{
+	u_long flags;
+
+	spin_lock_irqsave(&hw->lock, flags);
+	Write_hfc8(hw, R_CTRL, 0);	/* use internal RAM */
+	Write_hfc8(hw, R_RAM_MISC, 0);	/* 32k*8 RAM */
+	Write_hfc8(hw, R_FIFO_MD, 0);	/* fifo mode 386 byte/fifo simple mode */
+	Write_hfc8(hw, R_CIRM, M_SRES);	/* reset chip */
+	hw->mr.r_irq_ctrl = 0;	/* interrupt is inactive */
+	spin_unlock_irqrestore(&hw->lock, flags);
+
+	udelay(3);
+	Write_hfc8(hw, R_CIRM, 0);	/* disable reset */
+	wait_busy(hw);
+
+	Write_hfc8(hw, R_PCM_MD0, M_PCM_MD);	/* master mode */
+	Write_hfc8(hw, R_RAM_MISC, M_FZ_MD);	/* transmit fifo option */
+	if (hw->driver_data.clock_mode == 1)
+		Write_hfc8(hw, R_BRG_PCM_CFG, M_PCM_CLK);	/* PCM clk / 2 */
+	Write_hfc8(hw, R_TI_WD, TRANS_TIMER_MODE);	/* timer interval */
+
+	memset(&hw->mr, 0, sizeof(hw->mr));
+}				/* chipreset */
+
+/********************************************/
+/* disable/enable hardware in nt or te mode */
+/********************************************/
+void
+hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
+{
+	u_long flags;
+	char if_name[40];
+	int i;
+
+	if (enable) {
+		/* save system vars */
+		hw->nt_mode = nt_mode;
+
+		/* enable fifo and state irqs, but not global irq enable */
+		hw->mr.r_irq_ctrl = M_FIFO_IRQ;
+		Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
+		hw->mr.r_irqmsk_statchg = 0;
+		Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
+		Write_hfc8(hw, R_PWM_MD, 0x80);
+		Write_hfc8(hw, R_PWM1, 26);
+		if (!nt_mode)
+			Write_hfc8(hw, R_ST_SYNC, M_AUTO_SYNC);
+
+		/* enable the line interfaces and fifos */
+		for (i = 0; i < hw->driver_data.max_st_ports; i++) {
+			hw->mr.r_irqmsk_statchg |= (1 << i);
+			Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
+			Write_hfc8(hw, R_ST_SEL, i);
+			Write_hfc8(hw, A_ST_CLK_DLY,
+				   ((nt_mode) ? CLKDEL_NT : CLKDEL_TE));
+			hw->mr.r_ctrl0 = ((nt_mode) ? CTRL0_NT : CTRL0_TE);
+			Write_hfc8(hw, A_ST_CTRL0, hw->mr.r_ctrl0);
+			Write_hfc8(hw, A_ST_CTRL2, 3);
+			Write_hfc8(hw, A_ST_WR_STA, 0);	/* enable state machine */
+
+			hw->l1[i].enabled = 1;
+			hw->l1[i].nt_mode = nt_mode;
+
+			if (!nt_mode) {
+				/* setup E-fifo */
+				Write_hfc8(hw, R_FIFO, i * 8 + 7);	/* E fifo */
+				wait_busy(hw);
+				Write_hfc8(hw, A_CON_HDLC, 0x11);	/* HDLC mode, 1 fill, connect ST */
+				Write_hfc8(hw, A_SUBCH_CFG, 2);	/* only 2 bits */
+				Write_hfc8(hw, A_IRQ_MSK, 1);	/* enable interrupt */
+				Write_hfc8(hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+				wait_busy(hw);
+
+				/* setup D RX-fifo */
+				Write_hfc8(hw, R_FIFO, i * 8 + 5);	/* RX fifo */
+				wait_busy(hw);
+				Write_hfc8(hw, A_CON_HDLC, 0x11);	/* HDLC mode, 1 fill, connect ST */
+				Write_hfc8(hw, A_SUBCH_CFG, 2);	/* only 2 bits */
+				Write_hfc8(hw, A_IRQ_MSK, 1);	/* enable interrupt */
+				Write_hfc8(hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+				wait_busy(hw);
+
+				/* setup D TX-fifo */
+				Write_hfc8(hw, R_FIFO, i * 8 + 4);	/* TX fifo */
+				wait_busy(hw);
+				Write_hfc8(hw, A_CON_HDLC, 0x11);	/* HDLC mode, 1 fill, connect ST */
+				Write_hfc8(hw, A_SUBCH_CFG, 2);	/* only 2 bits */
+				Write_hfc8(hw, A_IRQ_MSK, 1);	/* enable interrupt */
+				Write_hfc8(hw, A_INC_RES_FIFO, 2);	/* reset fifo */
+				wait_busy(hw);
+			}
+
+			sprintf(if_name, "hfc4s8s_%d%d_", hw->cardnum, i);
+
+			if (hisax_register
+			    (&hw->l1[i].d_if, hw->l1[i].b_table, if_name,
+			     ((nt_mode) ? 3 : 2))) {
+
+				hw->l1[i].enabled = 0;
+				hw->mr.r_irqmsk_statchg &= ~(1 << i);
+				Write_hfc8(hw, R_SCI_MSK,
+					   hw->mr.r_irqmsk_statchg);
+				printk(KERN_INFO
+				       "HFC-4S/8S: Unable to register S/T device %s, break\n",
+				       if_name);
+				break;
+			}
+		}
+		spin_lock_irqsave(&hw->lock, flags);
+		hw->mr.r_irq_ctrl |= M_GLOB_IRQ_EN;
+		Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
+		spin_unlock_irqrestore(&hw->lock, flags);
+	} else {
+		/* disable hardware */
+		spin_lock_irqsave(&hw->lock, flags);
+		hw->mr.r_irq_ctrl &= ~M_GLOB_IRQ_EN;
+		Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
+		spin_unlock_irqrestore(&hw->lock, flags);
+
+		for (i = hw->driver_data.max_st_ports - 1; i >= 0; i--) {
+			hw->l1[i].enabled = 0;
+			hisax_unregister(&hw->l1[i].d_if);
+			del_timer(&hw->l1[i].l1_timer);
+			skb_queue_purge(&hw->l1[i].d_tx_queue);
+			skb_queue_purge(&hw->l1[i].b_ch[0].tx_queue);
+			skb_queue_purge(&hw->l1[i].b_ch[1].tx_queue);
+		}
+		chipreset(hw);
+	}
+}				/* hfc_hardware_enable */
+
+/******************************************/
+/* disable memory mapped ports / io ports */
+/******************************************/
+void
+release_pci_ports(hfc4s8s_hw * hw)
+{
+	pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+	if (hw->membase)
+		iounmap((void *) hw->membase);
+#else
+	if (hw->iobase)
+		release_region(hw->iobase, 8);
+#endif
+}
+
+/*****************************************/
+/* enable memory mapped ports / io ports */
+/*****************************************/
+void
+enable_pci_ports(hfc4s8s_hw * hw)
+{
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+	pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
+#else
+	pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO);
+#endif
+}
+
+/*************************************/
+/* initialise the HFC-4s/8s hardware */
+/* return 0 on success.              */
+/*************************************/
+static int __devinit
+setup_instance(hfc4s8s_hw * hw)
+{
+	int err = -EIO;
+	int i;
+
+	for (i = 0; i < HFC_MAX_ST; i++) {
+		struct hfc4s8s_l1 *l1p;
+
+		l1p = hw->l1 + i;
+		spin_lock_init(&l1p->lock);
+		l1p->hw = hw;
+		l1p->l1_timer.function = (void *) hfc_l1_timer;
+		l1p->l1_timer.data = (long) (l1p);
+		init_timer(&l1p->l1_timer);
+		l1p->st_num = i;
+		skb_queue_head_init(&l1p->d_tx_queue);
+		l1p->d_if.ifc.priv = hw->l1 + i;
+		l1p->d_if.ifc.l2l1 = (void *) dch_l2l1;
+
+		spin_lock_init(&l1p->b_ch[0].lock);
+		l1p->b_ch[0].b_if.ifc.l2l1 = (void *) bch_l2l1;
+		l1p->b_ch[0].b_if.ifc.priv = (void *) &l1p->b_ch[0];
+		l1p->b_ch[0].l1p = hw->l1 + i;
+		l1p->b_ch[0].bchan = 1;
+		l1p->b_table[0] = &l1p->b_ch[0].b_if;
+		skb_queue_head_init(&l1p->b_ch[0].tx_queue);
+
+		spin_lock_init(&l1p->b_ch[1].lock);
+		l1p->b_ch[1].b_if.ifc.l2l1 = (void *) bch_l2l1;
+		l1p->b_ch[1].b_if.ifc.priv = (void *) &l1p->b_ch[1];
+		l1p->b_ch[1].l1p = hw->l1 + i;
+		l1p->b_ch[1].bchan = 2;
+		l1p->b_table[1] = &l1p->b_ch[1].b_if;
+		skb_queue_head_init(&l1p->b_ch[1].tx_queue);
+	}
+
+	enable_pci_ports(hw);
+	chipreset(hw);
+
+	i = Read_hfc8(hw, R_CHIP_ID) >> CHIP_ID_SHIFT;
+	if (i != hw->driver_data.chip_id) {
+		printk(KERN_INFO
+		       "HFC-4S/8S: invalid chip id 0x%x instead of 0x%x, card ignored\n",
+		       i, hw->driver_data.chip_id);
+		goto out;
+	}
+
+	i = Read_hfc8(hw, R_CHIP_RV) & 0xf;
+	if (!i) {
+		printk(KERN_INFO
+		       "HFC-4S/8S: chip revision 0 not supported, card ignored\n");
+		goto out;
+	}
+
+	INIT_WORK(&hw->tqueue, (void *) (void *) hfc4s8s_bh, hw);
+
+	if (request_irq
+	    (hw->irq, hfc4s8s_interrupt, SA_SHIRQ, hw->card_name, hw)) {
+		printk(KERN_INFO
+		       "HFC-4S/8S: unable to alloc irq %d, card ignored\n",
+		       hw->irq);
+		goto out;
+	}
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+	printk(KERN_INFO
+	       "HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n",
+	       hw->hw_membase, hw->irq);
+#else
+	printk(KERN_INFO
+	       "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n",
+	       hw->iobase, hw->irq);
+#endif
+
+	hfc_hardware_enable(hw, 1, 0);
+
+	return (0);
+
+      out:
+	hw->irq = 0;
+	release_pci_ports(hw);
+	kfree(hw);
+	return (err);
+}
+
+/*****************************************/
+/* PCI hotplug interface: probe new card */
+/*****************************************/
+static int __devinit
+hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = -ENOMEM;
+	hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data;
+	hfc4s8s_hw *hw;
+
+	if (!(hw = kmalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for HFC-4S/8S card\n");
+		return (err);
+	}
+	memset(hw, 0, sizeof(hfc4s8s_hw));
+
+	hw->pdev = pdev;
+	err = pci_enable_device(pdev);
+
+	if (err)
+		goto out;
+
+	hw->cardnum = card_cnt;
+	sprintf(hw->card_name, "hfc4s8s_%d", hw->cardnum);
+	printk(KERN_INFO "HFC-4S/8S: found adapter %s (%s) at %s\n",
+	       driver_data->device_name, hw->card_name, pci_name(pdev));
+
+	spin_lock_init(&hw->lock);
+
+	hw->driver_data = *driver_data;
+	hw->irq = pdev->irq;
+	hw->iobase = pci_resource_start(pdev, 0);
+
+#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+	hw->hw_membase = (u_char *) pci_resource_start(pdev, 1);
+	hw->membase = ioremap((ulong) hw->hw_membase, 256);
+#else
+	if (!request_region(hw->iobase, 8, hw->card_name)) {
+		printk(KERN_INFO
+		       "HFC-4S/8S: failed to rquest address space at 0x%04x\n",
+		       hw->iobase);
+		goto out;
+	}
+#endif
+
+	pci_set_drvdata(pdev, hw);
+	err = setup_instance(hw);
+	if (!err)
+		card_cnt++;
+	return (err);
+
+      out:
+	kfree(hw);
+	return (err);
+}
+
+/**************************************/
+/* PCI hotplug interface: remove card */
+/**************************************/
+static void __devexit
+hfc4s8s_remove(struct pci_dev *pdev)
+{
+	hfc4s8s_hw *hw = pci_get_drvdata(pdev);
+
+	printk(KERN_INFO "HFC-4S/8S: removing card %d\n", hw->cardnum);
+	hfc_hardware_enable(hw, 0, 0);
+
+	if (hw->irq)
+		free_irq(hw->irq, hw);
+	hw->irq = 0;
+	release_pci_ports(hw);
+
+	card_cnt--;
+	pci_disable_device(pdev);
+	kfree(hw);
+	return;
+}
+
+static struct pci_driver hfc4s8s_driver = {
+      name:"hfc4s8s_l1",
+      probe:hfc4s8s_probe,
+      remove:__devexit_p(hfc4s8s_remove),
+      id_table:hfc4s8s_ids,
+};
+
+/**********************/
+/* driver Module init */
+/**********************/
+static int __init
+hfc4s8s_module_init(void)
+{
+	int err;
+
+	printk(KERN_INFO
+	       "HFC-4S/8S: Layer 1 driver module for HFC-4S/8S isdn chips, %s\n",
+	       hfc4s8s_rev);
+	printk(KERN_INFO
+	       "HFC-4S/8S: (C) 2003 Cornelius Consult, www.cornelius-consult.de\n");
+
+	card_cnt = 0;
+
+	err = pci_register_driver(&hfc4s8s_driver);
+	if (err < 0) {
+		goto out;
+	}
+	printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt);
+
+#if !defined(CONFIG_HOTPLUG)
+	if (err == 0) {
+		err = -ENODEV;
+		pci_unregister_driver(&hfc4s8s_driver);
+		goto out;
+	}
+#endif
+
+	return 0;
+      out:
+	return (err);
+}				/* hfc4s8s_init_hw */
+
+/*************************************/
+/* driver module exit :              */
+/* release the HFC-4s/8s hardware    */
+/*************************************/
+static void
+hfc4s8s_module_exit(void)
+{
+	pci_unregister_driver(&hfc4s8s_driver);
+	printk(KERN_INFO "HFC-4S/8S: module removed\n");
+}				/* hfc4s8s_release_hw */
+
+module_init(hfc4s8s_module_init);
+module_exit(hfc4s8s_module_exit);
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h
new file mode 100644
--- /dev/null
+++ b/drivers/isdn/hisax/hfc4s8s_l1.h
@@ -0,0 +1,88 @@
+/***************************************************************/
+/*  $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */
+/*                                                             */
+/*  This file is a minimal required extraction of hfc48scu.h   */
+/*  (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S)   */
+/*                                                             */
+/*  To get this complete register description contact          */
+/*  Cologne Chip AG :                                          */
+/*  Internet:  http://www.colognechip.com/                     */
+/*  E-Mail:    info@colognechip.com                            */
+/***************************************************************/
+
+#ifndef _HFC4S8S_L1_H_
+#define _HFC4S8S_L1_H_
+
+
+/*
+*  include Genero generated HFC-4S/8S header file hfc48scu.h
+*  for comlete register description. This will define _HFC48SCU_H_
+*  to prevent redefinitions
+*/
+
+// #include "hfc48scu.h"
+
+#ifndef _HFC48SCU_H_
+#define _HFC48SCU_H_
+
+#ifndef PCI_VENDOR_ID_CCD
+#define PCI_VENDOR_ID_CCD	0x1397
+#endif
+
+#define CHIP_ID_4S		0x0C
+#define CHIP_ID_8S		0x08
+#define PCI_DEVICE_ID_4S	0x08B4
+#define PCI_DEVICE_ID_8S	0x16B8
+
+#define R_IRQ_MISC	0x11
+#define M_TI_IRQ	0x02
+#define A_ST_RD_STA	0x30
+#define A_ST_WR_STA	0x30
+#define M_SET_G2_G3	0x80
+#define A_ST_CTRL0	0x31
+#define A_ST_CTRL2	0x33
+#define A_ST_CLK_DLY	0x37
+#define A_Z1		0x04
+#define A_Z2		0x06
+#define R_CIRM		0x00
+#define M_SRES		0x08
+#define R_CTRL		0x01
+#define R_BRG_PCM_CFG	0x02
+#define M_PCM_CLK	0x20
+#define R_RAM_MISC	0x0C
+#define M_FZ_MD		0x80
+#define R_FIFO_MD	0x0D
+#define A_INC_RES_FIFO	0x0E
+#define R_FIFO		0x0F
+#define A_F1		0x0C
+#define A_F2		0x0D
+#define R_IRQ_OVIEW	0x10
+#define R_CHIP_ID	0x16
+#define R_STATUS	0x1C
+#define M_BUSY		0x01
+#define M_MISC_IRQSTA	0x40
+#define M_FR_IRQSTA	0x80
+#define R_CHIP_RV	0x1F
+#define R_IRQ_CTRL	0x13
+#define M_FIFO_IRQ	0x01
+#define M_GLOB_IRQ_EN	0x08
+#define R_PCM_MD0	0x14
+#define M_PCM_MD	0x01
+#define A_FIFO_DATA0	0x80
+#define R_TI_WD		0x1A
+#define R_PWM1		0x39
+#define R_PWM_MD	0x46
+#define R_IRQ_FIFO_BL0	0xC8
+#define A_CON_HDLC	0xFA
+#define A_SUBCH_CFG	0xFB
+#define A_IRQ_MSK	0xFF
+#define R_SCI_MSK	0x12
+#define R_ST_SEL	0x16
+#define R_ST_SYNC	0x17
+#define M_AUTO_SYNC	0x08
+#define R_SCI		0x12
+#define R_IRQMSK_MISC	0x11
+#define M_TI_IRQMSK	0x02
+
+#endif	/* _HFC4S8S_L1_H_ */
+#endif	/* _HFC48SCU_H_ */
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1382,14 +1382,14 @@ hfcsx_card_msg(struct IsdnCardState *cs,
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __initdata = {
+static struct isapnp_device_id hfc_ids[] __devinitdata = {
 	{ 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 *ipid __initdata = &hfc_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1,11 +1,15 @@
 /*
  * hfc_usb.c
  *
- * modular HiSax ISDN driver for Colognechip HFC-USB chip
+ * $Id: hfc_usb.c,v 4.34 2005/01/26 17:25:53 martinb1 Exp $
  *
- * Authors : Peter Sprenger  (sprenger@moving-byters.de)
+ * modular HiSax ISDN driver for Colognechip HFC-S USB chip
+ *
+ * Authors : Peter Sprenger  (sprenger@moving-bytes.de)
  *           Martin Bachem   (info@colognechip.com)
- *           based on the first hfc_usb driver of Werner Cornelius (werner@isdn-development.de)
+ *
+ *           based on the first hfc_usb driver of
+ *           Werner Cornelius (werner@isdn-development.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
@@ -21,249 +25,229 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * See Version Histroy at the bottom of this file
+ *
 */
 
-
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/timer.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#include "hisax.h"
 #include <linux/module.h>
 #include <linux/kernel_stat.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
+#include "hisax.h"
 #include "hisax_if.h"
-
-static const char *hfcusb_revision = "4.0";
+#include "hfc_usb.h"
 
 /*
-	to enable much mire debug messages in this driver, define
-			VERBOSE_USB_DEBUG and VERBOSE_ISDN_DEBUG
-	below
+* Version Information
+* (do not modify the CVS Makros $Revision: 4.34 $ and $Date: 2005/01/26 17:25:53 $ !)
 */
+static const char *hfcusb_revision =
+    "Revision: 4.34 $ Date: 2005/01/26 17:25:53 $ ";
 
-#define VERBOSE_USB_DEBUG
-#define VERBOSE_ISDN_DEBUG
-
-#define INCLUDE_INLINE_FUNCS
-
-#define TRUE  1
-#define FALSE 0
-
-
-/***********/
-/* defines */
-/***********/
-#define HFC_CTRL_TIMEOUT	20  //(HZ * USB_CTRL_GET_TIMEOUT)
-/* 5ms timeout writing/reading regs */
-#define HFC_TIMER_T3     8000      /* timeout for l1 activation timer */
-#define HFC_TIMER_T4     500       /* time for state change interval */
-
-#define HFCUSB_L1_STATECHANGE   0  /* L1 state changed */
-#define HFCUSB_L1_DRX           1  /* D-frame received */
-#define HFCUSB_L1_ERX           2  /* E-frame received */
-#define HFCUSB_L1_DTX           4  /* D-frames completed */
-
-#define MAX_BCH_SIZE        2048   /* allowed B-channel packet size */
-
-#define HFCUSB_RX_THRESHOLD 64     /* threshold for fifo report bit rx */
-#define HFCUSB_TX_THRESHOLD 64     /* threshold for fifo report bit tx */
-
-#define HFCUSB_CHIP_ID    0x16     /* Chip ID register index */
-#define HFCUSB_CIRM       0x00     /* cirm register index */
-#define HFCUSB_USB_SIZE   0x07     /* int length register */
-#define HFCUSB_USB_SIZE_I 0x06     /* iso length register */
-#define HFCUSB_F_CROSS    0x0b     /* bit order register */
-#define HFCUSB_CLKDEL     0x37     /* bit delay register */
-#define HFCUSB_CON_HDLC   0xfa     /* channel connect register */
-#define HFCUSB_HDLC_PAR   0xfb
-#define HFCUSB_SCTRL      0x31     /* S-bus control register (tx) */
-#define HFCUSB_SCTRL_E    0x32     /* same for E and special funcs */
-#define HFCUSB_SCTRL_R    0x33     /* S-bus control register (rx) */
-#define HFCUSB_F_THRES    0x0c     /* threshold register */
-#define HFCUSB_FIFO       0x0f     /* fifo select register */
-#define HFCUSB_F_USAGE    0x1a     /* fifo usage register */
-#define HFCUSB_MST_MODE0  0x14
-#define HFCUSB_MST_MODE1  0x15
-#define HFCUSB_P_DATA     0x1f
-#define HFCUSB_INC_RES_F  0x0e
-#define HFCUSB_STATES     0x30
-
-#define HFCUSB_CHIPID 0x40         /* ID value of HFC-USB */
-
-/******************/
-/* fifo registers */
-/******************/
-#define HFCUSB_NUM_FIFOS   8       /* maximum number of fifos */
-#define HFCUSB_B1_TX       0       /* index for B1 transmit bulk/int */
-#define HFCUSB_B1_RX       1       /* index for B1 receive bulk/int */
-#define HFCUSB_B2_TX       2
-#define HFCUSB_B2_RX       3
-#define HFCUSB_D_TX        4
-#define HFCUSB_D_RX        5
-#define HFCUSB_PCM_TX      6
-#define HFCUSB_PCM_RX      7
-
-/*
-* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
-* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+/* Hisax debug support
+* use "modprobe debug=x" where x is bitfield of USB_DBG & ISDN_DBG
 */
-#define USB_INT		0
-#define USB_BULK	1
-#define USB_ISOC	2
-
-#define ISOC_PACKETS_D	8
-#define ISOC_PACKETS_B	8
-#define ISO_BUFFER_SIZE	128
-
-// ISO send definitions
-#define SINK_MAX	68
-#define SINK_MIN	48
-#define SINK_DMIN	12
-#define SINK_DMAX	18
-#define BITLINE_INF	(-64*8)
-
-
-
-
-/**********/
-/* macros */
-/**********/
-#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT)
-#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
-
-/*************************************************/
-/* entry and size of output/input control buffer */
-/*************************************************/
-#define HFC_CTRL_BUFSIZE 32
-typedef struct
-{
-	__u8 hfc_reg;		/* register number */
-	__u8 reg_val;		/* value to be written (or read) */
-	int action;         /* data for action handler */
+#ifdef CONFIG_HISAX_DEBUG
+#include <linux/moduleparam.h>
+#define __debug_variable hfc_debug
+#include "hisax_debug.h"
+static u_int debug;
+module_param(debug, uint, 0);
+int hfc_debug;
+#endif
 
-} ctrl_buft;
 
-typedef struct
-{
-	int vendor;         // vendor id
-	int prod_id;	    // product id
-	char *vend_name;    // vendor string
-	__u8 led_scheme;    // led display scheme
-	__u8 led_invert;    // invert led aux port settings
-	__u8 led_bits[8];   // array of 8 possible LED bitmask settings
+/****************************************/
+/* data defining the devices to be used */
+/****************************************/
+static struct usb_device_id hfc_usb_idtab[] = {
+	{USB_DEVICE(0x0959, 0x2bd0)},	/* Colognechip USB eval TA */
+	{USB_DEVICE(0x0675, 0x1688)},	/* DrayTek miniVigor 128 USB ISDN TA */
+	{USB_DEVICE(0x07b0, 0x0007)},	/* Billion USB TA 2 */
+	{USB_DEVICE(0x0742, 0x2008)},	/* Stollmann USB TA */
+	{USB_DEVICE(0x0742, 0x2009)},	/* Aceex USB ISDN TA */
+	{USB_DEVICE(0x0742, 0x200A)},	/* OEM USB ISDN TA */
+	{USB_DEVICE(0x08e3, 0x0301)},	/* OliTec ISDN USB */
+	{USB_DEVICE(0x07fa, 0x0846)},	/* Bewan ISDN USB TA */
+	{USB_DEVICE(0x07fa, 0x0847)},	/* Djinn Numeris USB */
+	{USB_DEVICE(0x07b0, 0x0006)},	/* Twister ISDN USB TA */
+	{}			/* end with an all-zeroes entry */
+};
 
-} vendor_data;
+/* driver internal device specific data:
+*   VendorID, ProductID, Devicename, LED_SCHEME,
+*   LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2
+*/
+vendor_data vdata[] = {
+	/* CologneChip Eval TA */
+	{0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)",
+	 LED_OFF, {4, 0, 2, 1}
+	 }
+	,
+	/* DrayTek miniVigor 128 USB ISDN TA */
+	{0x0675, 0x1688, "DrayTek miniVigor 128 USB ISDN TA",
+	 LED_SCHEME1, {1, 2, 0, 0}
+	 }
+	,
+	/* Billion TA */
+	{0x07b0, 0x0007, "Billion tiny USB ISDN TA 128",
+	 LED_SCHEME1, {0x80, -64, -32, -16}
+	 }
+	,
+	/* Stollmann TA */
+	{0x0742, 0x2008, "Stollmann USB TA",
+	 LED_SCHEME1, {4, 0, 2, 1}
+	 }
+	,
+	/* Aceex USB ISDN TA */
+	{0x0742, 0x2009, "Aceex USB ISDN TA",
+	 LED_SCHEME1, {4, 0, 2, 1}
+	 }
+	,
+	/* OEM USB ISDN TA */
+	{0x0742, 0x200A, "OEM USB ISDN TA",
+	 LED_SCHEME1, {4, 0, 2, 1}
+	 }
+	,
+	/* Olitec TA  */
+	{0x08e3, 0x0301, "Olitec USB RNIS",
+	 LED_SCHEME1, {2, 0, 1, 4}
+	 }
+	,
+	/* Bewan TA   */
+	{0x07fa, 0x0846, "Bewan Modem RNIS USB",
+	 LED_SCHEME1, {0x80, -64, -32, -16}
+	 }
+	,
+	/* Bewan TA   */
+	{0x07fa, 0x0847, "Djinn Numeris USB",
+	 LED_SCHEME1, {0x80, -64, -32, -16}
+	 }
+	,
+	/* Twister ISDN TA   */
+	{0x07b0, 0x0006, "Twister ISDN TA",
+	 LED_SCHEME1, {0x80, -64, -32, -16}
+	 }
+	,
+	{0, 0, 0}		/* EOL element */
+};
 
 /***************************************************************/
 /* structure defining input+output fifos (interrupt/bulk mode) */
 /***************************************************************/
-
-struct usb_fifo;			/* forward definition */
-typedef struct iso_urb_struct
-{
+struct usb_fifo;		/* forward definition */
+typedef struct iso_urb_struct {
 	struct urb *purb;
 	__u8 buffer[ISO_BUFFER_SIZE];	/* buffer incoming/outgoing data */
-	struct usb_fifo *owner_fifo;	// pointer to owner fifo
+	struct usb_fifo *owner_fifo;	/* pointer to owner fifo */
 } iso_urb_struct;
 
 
-struct hfcusb_data;			/* forward definition */
-typedef struct usb_fifo
-{
-	int fifonum;			/* fifo index attached to this structure */
-	int active;			/* fifo is currently active */
+struct hfcusb_data;		/* forward definition */
+typedef struct usb_fifo {
+	int fifonum;		/* fifo index attached to this structure */
+	int active;		/* fifo is currently active */
 	struct hfcusb_data *hfc;	/* pointer to main structure */
-	int pipe;			/* address of endpoint */
-	__u8 usb_packet_maxlen;		/* maximum length for usb transfer */
-	unsigned int max_size;		/* maximum size of receive/send packet */
-	__u8 intervall;			/* interrupt interval */
-	struct sk_buff *skbuff; 	/* actual used buffer */
-	struct urb *urb;		/* transfer structure for usb routines */
-	__u8 buffer[128];		/* buffer incoming/outgoing data */
-	int bit_line;			/* how much bits are in the fifo? */
-
-	volatile __u8 usb_transfer_mode;/* switched between ISO and INT */
-	iso_urb_struct iso[2];		/* need two urbs to have one always for pending */
-	struct hisax_if *hif;		/* hisax interface */
-	int delete_flg;			/* only delete skbuff once */
-	int last_urblen;		/* remember length of last packet */
+	int pipe;		/* address of endpoint */
+	__u8 usb_packet_maxlen;	/* maximum length for usb transfer */
+	unsigned int max_size;	/* maximum size of receive/send packet */
+	__u8 intervall;		/* interrupt interval */
+	struct sk_buff *skbuff;	/* actual used buffer */
+	struct urb *urb;	/* transfer structure for usb routines */
+	__u8 buffer[128];	/* buffer incoming/outgoing data */
+	int bit_line;		/* how much bits are in the fifo? */
+
+	volatile __u8 usb_transfer_mode;	/* switched between ISO and INT */
+	iso_urb_struct iso[2];	/* need two urbs to have one always for pending */
+	struct hisax_if *hif;	/* hisax interface */
+	int delete_flg;		/* only delete skbuff once */
+	int last_urblen;	/* remember length of last packet */
 
 } usb_fifo;
 
-
 /*********************************************/
 /* structure holding all data for one device */
 /*********************************************/
-typedef struct hfcusb_data
-{
-	// HiSax Interface for loadable Layer1 drivers
-	struct hisax_d_if d_if;			/* see hisax_if.h */
-	struct hisax_b_if b_if[2];		/* see hisax_if.h */
+typedef struct hfcusb_data {
+	/* HiSax Interface for loadable Layer1 drivers */
+	struct hisax_d_if d_if;	/* see hisax_if.h */
+	struct hisax_b_if b_if[2];	/* see hisax_if.h */
 	int protocol;
-	
-	struct usb_device *dev;			/* our device */
-	int if_used;				/* used interface number */
-	int alt_used;				/* used alternate config */
-	int ctrl_paksize;			/* control pipe packet size */
-	int ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */
-	int cfg_used;				/* configuration index used */
-	int vend_idx;				// vendor found
-
-	int b_mode[2];				// B-channel mode
-
-	int l1_activated;			// layer 1 activated
 
-	int packet_size,iso_packet_size;	
+	struct usb_device *dev;	/* our device */
+	int if_used;		/* used interface number */
+	int alt_used;		/* used alternate config */
+	int ctrl_paksize;	/* control pipe packet size */
+	int ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */
+	int cfg_used;		/* configuration index used */
+	int vend_idx;		/* vendor found */
+	int b_mode[2];		/* B-channel mode */
+	int l1_activated;	/* layer 1 activated */
+	int disc_flag;		/* TRUE if device was disonnected to avoid some USB actions */
+	int packet_size, iso_packet_size;
 
 	/* control pipe background handling */
 	ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE];	/* buffer holding queued data */
-	volatile int ctrl_in_idx, ctrl_out_idx,
-		ctrl_cnt;			/* input/output pointer + count */
-	struct urb *ctrl_urb;			/* transfer structure for control channel */
+	volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt;	/* input/output pointer + count */
+	struct urb *ctrl_urb;	/* transfer structure for control channel */
 
 	struct usb_ctrlrequest ctrl_write;	/* buffer for control write request */
 	struct usb_ctrlrequest ctrl_read;	/* same for read request */
 
-	__u8 led_state,led_new_data,led_b_active;
+	__u8 old_led_state, led_state, led_new_data, led_b_active;
 
-	volatile __u8 threshold_mask;		/* threshold actually reported */
-	volatile __u8 bch_enables;		/* or mask for sctrl_r and sctrl register values */
+	volatile __u8 threshold_mask;	/* threshold actually reported */
+	volatile __u8 bch_enables;	/* or mask for sctrl_r and sctrl register values */
 
 	usb_fifo fifos[HFCUSB_NUM_FIFOS];	/* structure holding all fifo data */
 
-	volatile __u8 l1_state;			/* actual l1 state */
-	struct timer_list t3_timer;		/* timer 3 for activation/deactivation */
-	struct timer_list t4_timer;		/* timer 4 for activation/deactivation */
-	struct timer_list led_timer;		/* timer flashing leds */
+	volatile __u8 l1_state;	/* actual l1 state */
+	struct timer_list t3_timer;	/* timer 3 for activation/deactivation */
+	struct timer_list t4_timer;	/* timer 4 for activation/deactivation */
+	struct timer_list led_timer;	/* timer flashing leds */
 
 } hfcusb_data;
 
 
-static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish);
+static void collect_rx_frame(usb_fifo * fifo, __u8 * data, int len,
+			     int finish);
+
 
+static inline const char *
+symbolic(struct hfcusb_symbolic_list list[], const int num)
+{
+	int i;
+	for (i = 0; list[i].name != NULL; i++)
+		if (list[i].num == num)
+			return (list[i].name);
+	return "<unkown>";
+}
 
 
 /******************************************************/
 /* start next background transfer for control channel */
 /******************************************************/
-static void ctrl_start_transfer(hfcusb_data * hfc)
+static void
+ctrl_start_transfer(hfcusb_data * hfc)
 {
-	int err;
-	if(hfc->ctrl_cnt)
-	{
+	if (hfc->ctrl_cnt) {
 		hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
 		hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write;
 		hfc->ctrl_urb->transfer_buffer = NULL;
 		hfc->ctrl_urb->transfer_buffer_length = 0;
-		hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
-		hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
-		err = usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC);	/* start transfer */
-		printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err);
+		hfc->ctrl_write.wIndex =
+		    hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
+		hfc->ctrl_write.wValue =
+		    hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
+
+		usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC);	/* start transfer */
 	}
 }				/* ctrl_start_transfer */
 
@@ -271,271 +255,284 @@ static void ctrl_start_transfer(hfcusb_d
 /* queue a control transfer request */
 /* return 0 on success.             */
 /************************************/
-static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action)
+static int
+queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val, int action)
 {
 	ctrl_buft *buf;
 
-#ifdef VERBOSE_USB_DEBUG
-	printk ("HFC_USB: queue_control_request reg: %x, val: %x\n", reg, val);
-#endif
-
-	if(hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)  return(1);	   /* no space left */
+	if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
+		return (1);	/* no space left */
 	buf = &hfc->ctrl_buff[hfc->ctrl_in_idx];	/* pointer to new index */
 	buf->hfc_reg = reg;
 	buf->reg_val = val;
-	buf->action=action;
+	buf->action = action;
 	if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
 		hfc->ctrl_in_idx = 0;	/* pointer wrap */
 	if (++hfc->ctrl_cnt == 1)
 		ctrl_start_transfer(hfc);
-	return(0);
-}		/* queue_control_request */
+	return (0);
+}				/* queue_control_request */
 
-
-static int control_action_handler(hfcusb_data *hfc,int reg,int val,int action)
+static int
+control_action_handler(hfcusb_data * hfc, int reg, int val, int action)
 {
-	if(!action) return(1);  // no action defined
-
-	return(0);
+	if (!action)
+		return (1);	/* no action defined */
+	return (0);
 }
 
-
 /***************************************************************/
 /* control completion routine handling background control cmds */
 /***************************************************************/
-static void ctrl_complete(struct urb *urb, struct pt_regs *regs)
+static void
+ctrl_complete(struct urb *urb, struct pt_regs *regs)
 {
 	hfcusb_data *hfc = (hfcusb_data *) urb->context;
 	ctrl_buft *buf;
 
-	printk(KERN_DEBUG "ctrl_complete cnt %d\n", hfc->ctrl_cnt);
 	urb->dev = hfc->dev;
-	if(hfc->ctrl_cnt)
-	{
-		buf=&hfc->ctrl_buff[hfc->ctrl_out_idx];
-		control_action_handler(hfc,buf->hfc_reg,buf->reg_val,buf->action);
+	if (hfc->ctrl_cnt) {
+		buf = &hfc->ctrl_buff[hfc->ctrl_out_idx];
+		control_action_handler(hfc, buf->hfc_reg, buf->reg_val,
+				       buf->action);
 
 		hfc->ctrl_cnt--;	/* decrement actual count */
-		if(++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0;	/* pointer wrap */
+		if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
+			hfc->ctrl_out_idx = 0;	/* pointer wrap */
 
 		ctrl_start_transfer(hfc);	/* start next transfer */
 	}
 }				/* ctrl_complete */
 
-
-
-#define LED_OFF      0   // no LED support
-#define LED_SCHEME1  1	 // LED standard scheme
-#define LED_SCHEME2  2	 // not used yet...
-
-#define LED_POWER_ON	1
-#define LED_POWER_OFF	2
-#define LED_S0_ON		3
-#define LED_S0_OFF		4
-#define LED_B1_ON		5
-#define LED_B1_OFF		6
-#define LED_B1_DATA		7
-#define LED_B2_ON		8
-#define LED_B2_OFF		9
-#define LED_B2_DATA	   10
-
-#define LED_NORMAL   0	 // LEDs are normal
-#define LED_INVERTED 1   // LEDs are inverted
-
-// time for LED flashing
-#define LED_TIME      250
-
-vendor_data vdata[]=
-{
-    {0x959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF,LED_NORMAL,{4,0,2,1}},     /* CologneChip Eval TA */
-	{0x7b0, 0x0007, "Billion tiny USB ISDN TA 128", LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Billion TA */
-	{0x742, 0x2008, "Stollmann USB TA",             LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Stollmann TA */
-	{0x8e3, 0x0301, "Olitec USB RNIS",              LED_SCHEME1,  LED_NORMAL,   {2,0,1,4}},           /* Olitec TA  */
-	{0x675, 0x1688, "DrayTec USB ISDN TA",          LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Draytec TA */
-	{0x7fa, 0x0846, "Bewan Modem RNIS USB",         LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Bewan TA   */
-	{0}			   // EOL element
-};
-										
 /***************************************************/
 /* write led data to auxport & invert if necessary */
 /***************************************************/
-static void write_led(hfcusb_data * hfc,__u8 led_state)
+static void
+write_led(hfcusb_data * hfc, __u8 led_state)
 {
-	if(led_state!=hfc->led_state)
-	{
-		hfc->led_state=led_state;
-		queue_control_request(hfc, HFCUSB_P_DATA,(vdata[hfc->vend_idx].led_invert) ? ~led_state : led_state,1);
+	if (led_state != hfc->old_led_state) {
+		hfc->old_led_state = led_state;
+		queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1);
+	}
+}
+
+/**************************/
+/* handle LED bits        */
+/**************************/
+static void
+set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
+{
+	if (unset) {
+		if (led_bits < 0)
+			hfc->led_state |= abs(led_bits);
+		else
+			hfc->led_state &= ~led_bits;
+	} else {
+		if (led_bits < 0)
+			hfc->led_state &= ~abs(led_bits);
+		else
+			hfc->led_state |= led_bits;
 	}
 }
 
 /******************************************/
 /* invert B-channel LEDs if data is sent  */
 /******************************************/
-static void led_timer(hfcusb_data * hfc)
+static void
+led_timer(hfcusb_data * hfc)
 {
-   	static int cnt=0;
-	__u8 led_state=hfc->led_state;
+	static int cnt = 0;
 
-	if(cnt)
-	{
-		if(hfc->led_b_active&1) led_state|=vdata[hfc->vend_idx].led_bits[2];
-		if(hfc->led_b_active&2) led_state|=vdata[hfc->vend_idx].led_bits[3];
-	}
-	else
-	{
-		if(!(hfc->led_b_active&1) || hfc->led_new_data&1) led_state&=~vdata[hfc->vend_idx].led_bits[2];
-		if(!(hfc->led_b_active&2) || hfc->led_new_data&2) led_state&=~vdata[hfc->vend_idx].led_bits[3];
+	if (cnt) {
+		if (hfc->led_b_active & 1)
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
+				    0);
+		if (hfc->led_b_active & 2)
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
+				    0);
+	} else {
+		if (!(hfc->led_b_active & 1) || hfc->led_new_data & 1)
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
+				    1);
+		if (!(hfc->led_b_active & 2) || hfc->led_new_data & 2)
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
+				    1);
+	}
+
+	write_led(hfc, hfc->led_state);
+	hfc->led_new_data = 0;
+
+	cnt = !cnt;
+
+	/* restart 4 hz timer */
+	if (!timer_pending(&hfc->led_timer)) {
+		add_timer(&hfc->led_timer);
+		hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
 	}
-
-	write_led(hfc,led_state);
-	hfc->led_new_data=0;
-
-	cnt=!cnt;
-	// restart 4 hz timer
-	hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
-	if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
 }
 
 /**************************/
 /* handle LED requests    */
 /**************************/
-static void handle_led(hfcusb_data * hfc,int event)
+static void
+handle_led(hfcusb_data * hfc, int event)
 {
-	__u8 led_state=hfc->led_state;
-
-	// if no scheme -> no LED action
-   	if(vdata[hfc->vend_idx].led_scheme==LED_OFF) return;
+	/* if no scheme -> no LED action */
+	if (vdata[hfc->vend_idx].led_scheme == LED_OFF)
+		return;
 
-	switch(event)
-	{
+	switch (event) {
 		case LED_POWER_ON:
-				   led_state|=vdata[hfc->vend_idx].led_bits[0];
-				break;
-		case LED_POWER_OFF: // no Power off handling
-				break;
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[0],
+				    0);
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
+				    1);
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
+				    1);
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
+				    1);
+			break;
+		case LED_POWER_OFF:	/* no Power off handling */
+			break;
 		case LED_S0_ON:
-				   led_state|=vdata[hfc->vend_idx].led_bits[1];
-				break;
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
+				    0);
+			break;
 		case LED_S0_OFF:
-				   led_state&=~vdata[hfc->vend_idx].led_bits[1];
-				break;
+			set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
+				    1);
+			break;
 		case LED_B1_ON:
-					hfc->led_b_active|=1;
-				break;
+			hfc->led_b_active |= 1;
+			break;
 		case LED_B1_OFF:
-					hfc->led_b_active&=~1;
-				break;
+			hfc->led_b_active &= ~1;
+			break;
 		case LED_B1_DATA:
-				   hfc->led_new_data|=1;
-				break;
+			hfc->led_new_data |= 1;
+			break;
 		case LED_B2_ON:
-				   hfc->led_b_active|=2;
-				break;
+			hfc->led_b_active |= 2;
+			break;
 		case LED_B2_OFF:
-					hfc->led_b_active&=~2;
-				break;
+			hfc->led_b_active &= ~2;
+			break;
 		case LED_B2_DATA:
-				   hfc->led_new_data|=2;
-				break;
+			hfc->led_new_data |= 2;
+			break;
 	}
-	
-	write_led(hfc,led_state);
+
+	write_led(hfc, hfc->led_state);
 }
 
 /********************************/
 /* called when timer t3 expires */
 /********************************/
-static void l1_timer_expire_t3(hfcusb_data * hfc)
+static void
+l1_timer_expire_t3(hfcusb_data * hfc)
 {
-    //printk (KERN_INFO "HFC-USB: l1_timer_expire_t3\n");
-
-	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
-#ifdef VERBOSE_USB_DEBUG
-	printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
-#endif
-	hfc->l1_activated=FALSE;
-	handle_led(hfc,LED_S0_OFF);
+	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
+			   NULL);
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(ISDN_DBG,
+	    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
+#endif
+	hfc->l1_activated = FALSE;
+	handle_led(hfc, LED_S0_OFF);
+	/* deactivate : */
+	queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
+	queue_control_request(hfc, HFCUSB_STATES, 3, 1);
 }
 
 /********************************/
 /* called when timer t4 expires */
 /********************************/
-static void l1_timer_expire_t4(hfcusb_data * hfc)
+static void
+l1_timer_expire_t4(hfcusb_data * hfc)
 {
-    //printk (KERN_INFO "HFC-USB: l1_timer_expire_t4\n");
-
-	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
-#ifdef VERBOSE_USB_DEBUG
-	printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
+	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
+			   NULL);
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(ISDN_DBG,
+	    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
 #endif
-	hfc->l1_activated=FALSE;
-	handle_led(hfc,LED_S0_OFF);
+	hfc->l1_activated = FALSE;
+	handle_led(hfc, LED_S0_OFF);
 }
 
 /*****************************/
 /* handle S0 state changes   */
 /*****************************/
-static void state_handler(hfcusb_data * hfc,__u8 state)
+static void
+state_handler(hfcusb_data * hfc, __u8 state)
 {
 	__u8 old_state;
 
-	old_state=hfc->l1_state;
-
-	// range check
-	if(state==old_state || state<1 || state>8) return;
+	old_state = hfc->l1_state;
+	if (state == old_state || state < 1 || state > 8)
+		return;
 
-#ifdef VERBOSE_ISDN_DEBUG
-	printk(KERN_INFO "HFC-USB: new S0 state:%d old_state:%d\n",state,old_state);
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(ISDN_DBG, "HFC-S USB: new S0 state:%d old_state:%d", state,
+	    old_state);
+#endif
+	if (state < 4 || state == 7 || state == 8) {
+		if (timer_pending(&hfc->t3_timer))
+			del_timer(&hfc->t3_timer);
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(ISDN_DBG, "HFC-S USB: T3 deactivated");
+#endif
+	}
+	if (state >= 7) {
+		if (timer_pending(&hfc->t4_timer))
+			del_timer(&hfc->t4_timer);
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(ISDN_DBG, "HFC-S USB: T4 deactivated");
 #endif
+	}
 
-	if(state<4 || state==7 || state==8)
-	{
-        if(timer_pending(&hfc->t3_timer)) del_timer(&hfc->t3_timer);
-		//printk(KERN_INFO "HFC-USB: T3 deactivated\n");
-	}
-
-	if(state>=7)
-	{
-        if(timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer);
-		//printk(KERN_INFO "HFC-USB: T4 deactivated\n");
-	}
-
-	if(state==7 && !hfc->l1_activated)
-	{
-		hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_ACTIVATE | INDICATION,NULL);
-		//printk(KERN_INFO "HFC-USB: PH_ACTIVATE | INDICATION sent\n");
-		hfc->l1_activated=TRUE;
-		handle_led(hfc,LED_S0_ON);
-	}
-	else
-	if(state<=3 /* && activated*/)
-	{
-		if(old_state==7 || old_state==8)
-		{
-			//printk(KERN_INFO "HFC-USB: T4 activated\n");
-			hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000;
-			if(!timer_pending(&hfc->t4_timer)) add_timer(&hfc->t4_timer);
-		}
-		else
-		{
-			hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
-			//printk(KERN_INFO "HFC-USB: PH_DEACTIVATE | INDICATION sent\n");
-			hfc->l1_activated=FALSE;
-			handle_led(hfc,LED_S0_OFF);
+	if (state == 7 && !hfc->l1_activated) {
+		hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
+				   PH_ACTIVATE | INDICATION, NULL);
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
+#endif
+		hfc->l1_activated = TRUE;
+		handle_led(hfc, LED_S0_ON);
+	} else if (state <= 3 /* && activated */ ) {
+		if (old_state == 7 || old_state == 8) {
+#ifdef CONFIG_HISAX_DEBUG
+			DBG(ISDN_DBG, "HFC-S USB: T4 activated");
+#endif
+			if (!timer_pending(&hfc->t4_timer)) {
+				hfc->t4_timer.expires =
+				    jiffies + (HFC_TIMER_T4 * HZ) / 1000;
+				add_timer(&hfc->t4_timer);
+			}
+		} else {
+			hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
+					   PH_DEACTIVATE | INDICATION,
+					   NULL);
+#ifdef CONFIG_HISAX_DEBUG
+			DBG(ISDN_DBG,
+			    "HFC-S USB: PH_DEACTIVATE | INDICATION sent");
+#endif
+			hfc->l1_activated = FALSE;
+			handle_led(hfc, LED_S0_OFF);
 		}
 	}
-
-	hfc->l1_state=state;
+	hfc->l1_state = state;
 }
 
-
 /* prepare iso urb */
-static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf,
-	int num_packets, int packet_size, int interval, usb_complete_t complete, void *context)
+static void
+fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
+	      void *buf, int num_packets, int packet_size, int interval,
+	      usb_complete_t complete, void *context)
 {
 	int k;
 
-	spin_lock_init(&urb->lock);	// do we really need spin_lock_init ?
+	spin_lock_init(&urb->lock);
 	urb->dev = dev;
 	urb->pipe = pipe;
 	urb->complete = complete;
@@ -543,7 +540,6 @@ static void fill_isoc_urb(struct urb *ur
 	urb->transfer_buffer_length = packet_size * num_packets;
 	urb->context = context;
 	urb->transfer_buffer = buf;
-	urb->transfer_flags = 0;
 	urb->transfer_flags = URB_ISO_ASAP;
 	urb->actual_length = 0;
 	urb->interval = interval;
@@ -554,67 +550,80 @@ static void fill_isoc_urb(struct urb *ur
 	}
 }
 
-/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */
-static int start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,usb_complete_t complete,int packet_size)
+/* allocs urbs and start isoc transfer with two pending urbs to avoid
+   gaps in the transfer chain */
+static int
+start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
+		 usb_complete_t complete, int packet_size)
 {
 	int i, k, errcode;
 
-#ifdef VERBOSE_USB_DEBUG
-	printk(KERN_INFO "HFC-USB: starting ISO-chain for Fifo %i\n",  fifo->fifonum);
-#endif
-
+	printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n",
+	       fifo->fifonum);
 
-	// allocate Memory for Iso out Urbs
+	/* allocate Memory for Iso out Urbs */
 	for (i = 0; i < 2; i++) {
 		if (!(fifo->iso[i].purb)) {
-			fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
+			fifo->iso[i].purb =
+			    usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
+			if (!(fifo->iso[i].purb)) {
+				printk(KERN_INFO
+				       "alloc urb for fifo %i failed!!!",
+				       fifo->fifonum);
+			}
 			fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
 
-			// Init the first iso
-			if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb))
-			{
-
-				fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer,
-					num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall,
-					complete, &fifo->iso[i]);
-
-				memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer));
-
-				// defining packet delimeters in fifo->buffer
-				for(k = 0; k < num_packets_per_urb; k++)
-				{
-					fifo->iso[i].purb->iso_frame_desc[k].offset = k*packet_size;
-					fifo->iso[i].purb->iso_frame_desc[k].length = packet_size;
+			/* Init the first iso */
+			if (ISO_BUFFER_SIZE >=
+			    (fifo->usb_packet_maxlen *
+			     num_packets_per_urb)) {
+				fill_isoc_urb(fifo->iso[i].purb,
+					      fifo->hfc->dev, fifo->pipe,
+					      fifo->iso[i].buffer,
+					      num_packets_per_urb,
+					      fifo->usb_packet_maxlen,
+					      fifo->intervall, complete,
+					      &fifo->iso[i]);
+				memset(fifo->iso[i].buffer, 0,
+				       sizeof(fifo->iso[i].buffer));
+				/* defining packet delimeters in fifo->buffer */
+				for (k = 0; k < num_packets_per_urb; k++) {
+					fifo->iso[i].purb->
+					    iso_frame_desc[k].offset =
+					    k * packet_size;
+					fifo->iso[i].purb->
+					    iso_frame_desc[k].length =
+					    packet_size;
 				}
+			} else {
+				printk(KERN_INFO
+				       "HFC-S USB: ISO Buffer size to small!\n");
 			}
 		}
-
 		fifo->bit_line = BITLINE_INF;
 
 		errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
 		fifo->active = (errcode >= 0) ? 1 : 0;
-		if(errcode < 0)
-		{
-			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i.%i \n",  errcode, i);
+		if (errcode < 0) {
+			printk(KERN_INFO "HFC-S USB: %s  URB nr:%d\n",
+			       symbolic(urb_errlist, errcode), i);
 		};
-
 	}
-
-	// errcode = (usb_submit_urb(fifo->iso[0].purb, GFP_KERNEL));
-	return(fifo->active);
+	return (fifo->active);
 }
 
 /* stops running iso chain and frees their pending urbs */
-static void stop_isoc_chain(usb_fifo * fifo)
+static void
+stop_isoc_chain(usb_fifo * fifo)
 {
 	int i;
 
-	for(i = 0; i < 2; i++)
-	{
-		if(fifo->iso[i].purb)
-		{
-#ifdef VERBOSE_USB_DEBUG
-			printk(KERN_INFO "HFC-USB: Stopping iso chain for fifo %i.%i\n", fifo->fifonum, i);
+	for (i = 0; i < 2; i++) {
+		if (fifo->iso[i].purb) {
+#ifdef CONFIG_HISAX_DEBUG
+			DBG(USB_DBG,
+			    "HFC-S USB: Stopping iso chain for fifo %i.%i",
+			    fifo->fifonum, i);
 #endif
 			usb_unlink_urb(fifo->iso[i].purb);
 			usb_free_urb(fifo->iso[i].purb);
@@ -629,554 +638,653 @@ static void stop_isoc_chain(usb_fifo * f
 	fifo->active = 0;
 }
 
-// defines how much ISO packets are handled in one URB
-static int iso_packets[8]={ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,
-	                       ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D};
+/* defines how much ISO packets are handled in one URB */
+static int iso_packets[8] =
+    { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
+	ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
+};
 
 /*****************************************************/
 /* transmit completion routine for all ISO tx fifos */
 /*****************************************************/
-static void tx_iso_complete(struct urb *urb, struct pt_regs *regs)
+static void
+tx_iso_complete(struct urb *urb, struct pt_regs *regs)
 {
 	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
 	usb_fifo *fifo = context_iso_urb->owner_fifo;
 	hfcusb_data *hfc = fifo->hfc;
-	int k, tx_offset, num_isoc_packets, sink, len, current_len,errcode,frame_complete,transp_mode,fifon;
+	int k, tx_offset, num_isoc_packets, sink, len, current_len,
+	    errcode;
+	int frame_complete, transp_mode, fifon, status;
 	__u8 threshbit;
-	__u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+	__u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
 
-	fifon=fifo->fifonum;
-	tx_offset=0;
-	// very weird error code when using ohci drivers, for now : ignore this error ...  (MB)
-	if(urb->status == -EOVERFLOW)
-	{
-		urb->status = 0;
-#ifdef VERBOSE_USB_DEBUG
-		printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",fifon);
-#endif
-	}
+	fifon = fifo->fifonum;
+	status = urb->status;
 
-	if(fifo->active && !urb->status)
-	{
-		transp_mode=0;
-		if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
-
-		threshbit = threshtable[fifon] & hfc->threshold_mask;	// is threshold set for our channel?
-		num_isoc_packets=iso_packets[fifon];
-
-		if(fifon >= HFCUSB_D_TX)
-		{
-			sink = (threshbit) ? SINK_DMIN : SINK_DMAX;	// how much bit go to the sink for D-channel?
-		}
-		else
-		{
-			sink = (threshbit) ? SINK_MIN : SINK_MAX;	// how much bit go to the sink for B-channel?
-		}
+	tx_offset = 0;
+
+	if (fifo->active && !status) {
+		transp_mode = 0;
+		if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
+			transp_mode = TRUE;
 
-		// prepare ISO Urb
-		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
-			fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context);
-		memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer));
-
-		frame_complete=FALSE;
-
-		// Generate Iso Packets
-		for(k = 0; k < num_isoc_packets; ++k)
-		{
-			if(fifo->skbuff)
-			{
-				len = fifo->skbuff->len;	// remaining length
+		/* is FifoFull-threshold set for our channel? */
+		threshbit = threshtable[fifon] & hfc->threshold_mask;
+		num_isoc_packets = iso_packets[fifon];
 
-				fifo->bit_line -= sink;	// we lower data margin every msec
+		/* predict dataflow to avoid fifo overflow */
+		if (fifon >= HFCUSB_D_TX) {
+			sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
+		} else {
+			sink = (threshbit) ? SINK_MIN : SINK_MAX;
+		}
+		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
+			      context_iso_urb->buffer, num_isoc_packets,
+			      fifo->usb_packet_maxlen, fifo->intervall,
+			      tx_iso_complete, urb->context);
+		memset(context_iso_urb->buffer, 0,
+		       sizeof(context_iso_urb->buffer));
+		frame_complete = FALSE;
+		/* Generate next Iso Packets */
+		for (k = 0; k < num_isoc_packets; ++k) {
+			if (fifo->skbuff) {
+				len = fifo->skbuff->len;
+				/* we lower data margin every msec */
+				fifo->bit_line -= sink;
 				current_len = (0 - fifo->bit_line) / 8;
-				if(current_len > 14) current_len = 14;	// maximum 15 byte for every ISO packet makes our life easier
-				current_len = (len <= current_len) ? len : current_len;
-				fifo->bit_line += current_len * 8;	// how much bit do we put on the line?
+				/* maximum 15 byte for every ISO packet makes our life easier */
+				if (current_len > 14)
+					current_len = 14;
+				current_len =
+				    (len <=
+				     current_len) ? len : current_len;
+				/* how much bit do we put on the line? */
+				fifo->bit_line += current_len * 8;
 
 				context_iso_urb->buffer[tx_offset] = 0;
-				if(current_len == len)
-				{
-					if(!transp_mode)
-					{
-						context_iso_urb->buffer[tx_offset] = 1;	// here frame completion
-						fifo->bit_line += 32;	// add 2 byte flags and 16bit CRC at end of ISDN frame
+				if (current_len == len) {
+					if (!transp_mode) {
+						/* here frame completion */
+						context_iso_urb->
+						    buffer[tx_offset] = 1;
+						/* add 2 byte flags and 16bit CRC at end of ISDN frame */
+						fifo->bit_line += 32;
 					}
 					frame_complete = TRUE;
 				}
 
-				// copy bytes from buffer into ISO_URB
-				memcpy(context_iso_urb->buffer+tx_offset+1,fifo->skbuff->data,current_len);
-				skb_pull(fifo->skbuff,current_len);
+				memcpy(context_iso_urb->buffer +
+				       tx_offset + 1, fifo->skbuff->data,
+				       current_len);
+				skb_pull(fifo->skbuff, current_len);
 
-				// define packet delimeters within the URB buffer
+				/* define packet delimeters within the URB buffer */
 				urb->iso_frame_desc[k].offset = tx_offset;
-				urb->iso_frame_desc[k].length = current_len + 1;
+				urb->iso_frame_desc[k].length =
+				    current_len + 1;
 
 				tx_offset += (current_len + 1);
-				// printk(KERN_INFO "HFC-USB: fifonum:%d,%d bytes to send, %d bytes ISO packet,bitline:%d,sink:%d,threshbit:%d,threshmask:%x\n",fifon,len,current_len,fifo->bit_line,sink,threshbit,hfc->threshold_mask);
-				if(!transp_mode)
-				{
-					if(fifon==HFCUSB_B1_TX) handle_led(hfc,LED_B1_DATA);
-					if(fifon==HFCUSB_B2_TX) handle_led(hfc,LED_B2_DATA);
+				if (!transp_mode) {
+					if (fifon == HFCUSB_B1_TX)
+						handle_led(hfc,
+							   LED_B1_DATA);
+					if (fifon == HFCUSB_B2_TX)
+						handle_led(hfc,
+							   LED_B2_DATA);
 				}
-			}
-			else
-			{
-				// we have no more data - generate 1 byte ISO packets
-				urb->iso_frame_desc[k].offset = tx_offset++;
+			} else {
+				urb->iso_frame_desc[k].offset =
+				    tx_offset++;
 
 				urb->iso_frame_desc[k].length = 1;
-				fifo->bit_line -= sink;	// we lower data margin every msec
+				fifo->bit_line -= sink;	/* we lower data margin every msec */
 
-				if(fifo->bit_line < BITLINE_INF)
-				{
+				if (fifo->bit_line < BITLINE_INF) {
 					fifo->bit_line = BITLINE_INF;
-					//printk (KERN_INFO "HFC-USB: BITLINE_INF underrun\n");
 				}
 			}
 
-			if(frame_complete)
-			{
-				// delete the buffer only once, here or in hfc_usb_l2l1() in a PH_DATA|REQUEST
-				fifo->delete_flg=TRUE;
-
-				fifo->hif->l1l2(fifo->hif,PH_DATA|CONFIRM,(void*)fifo->skbuff->truesize);
-
-				if(fifo->skbuff && fifo->delete_flg)
-				{
+			if (frame_complete) {
+				fifo->delete_flg = TRUE;
+				fifo->hif->l1l2(fifo->hif,
+						PH_DATA | CONFIRM,
+						(void *) fifo->skbuff->
+						truesize);
+				if (fifo->skbuff && fifo->delete_flg) {
 					dev_kfree_skb_any(fifo->skbuff);
-					//printk(KERN_INFO "HFC-USB: skbuff=NULL on fifo:%d\n",fifo->fifonum);
 					fifo->skbuff = NULL;
-					fifo->delete_flg=FALSE;
+					fifo->delete_flg = FALSE;
 				}
-
-				frame_complete=FALSE;
+				frame_complete = FALSE;
 			}
-        }
-
+		}
 		errcode = usb_submit_urb(urb, GFP_ATOMIC);
-		if(errcode < 0)
-		{
-			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
+		if (errcode < 0) {
+			printk(KERN_INFO
+			       "HFC-S USB: error submitting ISO URB: %d \n",
+			       errcode);
 		}
-	}
-	else
-	{
-		if(urb->status)
-		{
-			printk(KERN_INFO "HFC-USB: tx_iso_complete : urb->status %i, fifonum %i\n",  urb->status,fifon);
+	} else {
+		if (status && !hfc->disc_flag) {
+			printk(KERN_INFO
+			       "HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n",
+			       symbolic(urb_errlist, status), status,
+			       fifon);
 		}
 	}
-
 }				/* tx_iso_complete */
 
 /*****************************************************/
 /* receive completion routine for all ISO tx fifos   */
 /*****************************************************/
-static void rx_iso_complete(struct urb *urb, struct pt_regs *regs)
+static void
+rx_iso_complete(struct urb *urb, struct pt_regs *regs)
 {
 	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
 	usb_fifo *fifo = context_iso_urb->owner_fifo;
 	hfcusb_data *hfc = fifo->hfc;
-	int k, len, errcode, offset, num_isoc_packets,fifon;
+	int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
+	    status;
+	unsigned int iso_status;
 	__u8 *buf;
-
-	fifon=fifo->fifonum;
-	// very weird error code when using ohci drivers, for now : ignore this error ...  (MB)
-	if(urb->status == -EOVERFLOW)
-	{
-		urb->status = 0;
-#ifdef VERBOSE_USB_DEBUG
-		printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",fifon);
+	static __u8 eof[8];
+#ifdef CONFIG_HISAX_DEBUG
+	__u8 i;
+#endif
+
+	fifon = fifo->fifonum;
+	status = urb->status;
+
+	if (urb->status == -EOVERFLOW) {
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(USB_DBG,
+		    "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",
+		    fifon);
+#endif
+		status = 0;
+	}
+	if (fifo->active && !status) {
+		num_isoc_packets = iso_packets[fifon];
+		maxlen = fifo->usb_packet_maxlen;
+		for (k = 0; k < num_isoc_packets; ++k) {
+			len = urb->iso_frame_desc[k].actual_length;
+			offset = urb->iso_frame_desc[k].offset;
+			buf = context_iso_urb->buffer + offset;
+			iso_status = urb->iso_frame_desc[k].status;
+#ifdef CONFIG_HISAX_DEBUG
+			if (iso_status && !hfc->disc_flag)
+				DBG(USB_DBG,
+				    "HFC-S USB: ISO packet failure - status:%x",
+				    iso_status);
+
+			if ((fifon == 5) && (debug > 1)) {
+				printk(KERN_INFO
+				       "HFC-S USB: ISO-D-RX lst_urblen:%2d "
+				       "act_urblen:%2d max-urblen:%2d "
+				       "EOF:0x%0x DATA: ",
+				       fifo->last_urblen, len, maxlen,
+				       eof[5]);
+				for (i = 0; i < len; i++)
+					printk("%.2x ", buf[i]);
+				printk("\n");
+			}
 #endif
-	}
-
-	if(fifo->active && !urb->status)
-	{
-		num_isoc_packets=iso_packets[fifon];
-
-		// Generate D-Channel Iso Packets
-		for(k = 0; k < num_isoc_packets; ++k)
-		{
-			len=urb->iso_frame_desc[k].actual_length;
-			offset=urb->iso_frame_desc[k].offset;
-			buf=context_iso_urb->buffer+offset;
-
-			if(fifo->last_urblen!=fifo->usb_packet_maxlen)
-			{
-				// the threshold mask is in the 2nd status byte
-				hfc->threshold_mask=buf[1];
-				// the S0 state is in the upper half of the 1st status byte
-				state_handler(hfc,buf[0] >> 4);
-				// if we have more than the 2 status bytes -> collect data
-				if(len>2) collect_rx_frame(fifo,buf+2,len-2,buf[0]&1);
+			if (fifo->last_urblen != maxlen) {
+				/* the threshold mask is in the 2nd status byte */
+				hfc->threshold_mask = buf[1];
+				/* care for L1 state only for D-Channel
+				   to avoid overlapped iso completions */
+				if (fifon == 5) {
+					/* the S0 state is in the upper half
+					   of the 1st status byte */
+					state_handler(hfc, buf[0] >> 4);
+				}
+				eof[fifon] = buf[0] & 1;
+				if (len > 2)
+					collect_rx_frame(fifo, buf + 2,
+							 len - 2,
+							 (len <
+							  maxlen) ?
+							 eof[fifon] : 0);
+			} else {
+				collect_rx_frame(fifo, buf, len,
+						 (len <
+						  maxlen) ? eof[fifon] :
+						 0);
 			}
-			else collect_rx_frame(fifo,buf,len,0);
-
-			fifo->last_urblen=len;
-
-        }
-
-		// prepare ISO Urb
-		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
-			fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context);
+			fifo->last_urblen = len;
+		}
 
+		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
+			      context_iso_urb->buffer, num_isoc_packets,
+			      fifo->usb_packet_maxlen, fifo->intervall,
+			      rx_iso_complete, urb->context);
 		errcode = usb_submit_urb(urb, GFP_ATOMIC);
-		if(errcode < 0)
-		{
-			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
+		if (errcode < 0) {
+			printk(KERN_INFO
+			       "HFC-S USB: error submitting ISO URB: %d \n",
+			       errcode);
 		}
-	}
-	else
-	{
-		if(urb->status)
-		{
-			printk(KERN_INFO "HFC-USB: rx_iso_complete : urb->status %i, fifonum %i\n",  urb->status,fifon);
+	} else {
+		if (status && !hfc->disc_flag) {
+			printk(KERN_INFO
+			       "HFC-S USB: rx_iso_complete : "
+			       "urb->status %d, fifonum %d\n",
+			       status, fifon);
 		}
 	}
 }				/* rx_iso_complete */
 
-
 /*****************************************************/
 /* collect data from interrupt or isochron in        */
 /*****************************************************/
-static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish)
+static void
+collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
 {
 	hfcusb_data *hfc = fifo->hfc;
-	int transp_mode,fifon;
-
-	fifon=fifo->fifonum;
-	transp_mode=0;
-	if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
-
-	//printk(KERN_INFO "HFC-USB: got %d bytes finish:%d max_size:%d fifo:%d\n",len,finish,fifo->max_size,fifon);
-	if(!fifo->skbuff)
-	{
-		// allocate sk buffer
-		fifo->skbuff=dev_alloc_skb(fifo->max_size + 3);
-		if(!fifo->skbuff)
-		{
-			printk(KERN_INFO "HFC-USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",fifon);
+	int transp_mode, fifon;
+#ifdef CONFIG_HISAX_DEBUG
+	int i;
+#endif
+	fifon = fifo->fifonum;
+	transp_mode = 0;
+	if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
+		transp_mode = TRUE;
+
+	if (!fifo->skbuff) {
+		fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
+		if (!fifo->skbuff) {
+			printk(KERN_INFO
+			       "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",
+			       fifon);
 			return;
 		}
-		
 	}
-
-	if(len && fifo->skbuff->len+len<fifo->max_size)
-	{
-		memcpy(skb_put(fifo->skbuff,len),data,len);
+	if (len) {
+		if (fifo->skbuff->len + len < fifo->max_size) {
+			memcpy(skb_put(fifo->skbuff, len), data, len);
+		} else {
+#ifdef CONFIG_HISAX_DEBUG
+			printk(KERN_INFO "HFC-S USB: ");
+			for (i = 0; i < 15; i++)
+				printk("%.2x ",
+				       fifo->skbuff->data[fifo->skbuff->
+							  len - 15 + i]);
+			printk("\n");
+#endif
+			printk(KERN_INFO
+			       "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n",
+			       fifo->max_size, fifon);
+		}
 	}
-	else printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d\n",fifo->max_size);
-
-	// give transparent data up, when 128 byte are available
-	if(transp_mode && fifo->skbuff->len>=128)
-	{
-		fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
-		fifo->skbuff = NULL;  // buffer was freed from upper layer
+	if (transp_mode && fifo->skbuff->len >= 128) {
+		fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION,
+				fifo->skbuff);
+		fifo->skbuff = NULL;
 		return;
 	}
-
-	// we have a complete hdlc packet
-	if(finish)
-	{
-		if(!fifo->skbuff->data[fifo->skbuff->len-1])
-		{
-			skb_trim(fifo->skbuff,fifo->skbuff->len-3);  // remove CRC & status
-
-			//printk(KERN_INFO "HFC-USB: got frame %d bytes on fifo:%d\n",fifo->skbuff->len,fifon);
-
-			if(fifon==HFCUSB_PCM_RX) fifo->hif->l1l2(fifo->hif,PH_DATA_E | INDICATION,fifo->skbuff);
-			else fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
-
-			fifo->skbuff = NULL;  // buffer was freed from upper layer
-		}
-		else
-		{
-			printk(KERN_INFO "HFC-USB: got frame %d bytes but CRC ERROR!!!\n",fifo->skbuff->len);
-
-			skb_trim(fifo->skbuff,0);  // clear whole buffer
+	/* we have a complete hdlc packet */
+	if (finish) {
+		if ((!fifo->skbuff->data[fifo->skbuff->len - 1])
+		    && (fifo->skbuff->len > 3)) {
+			/* remove CRC & status */
+			skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
+			if (fifon == HFCUSB_PCM_RX) {
+				fifo->hif->l1l2(fifo->hif,
+						PH_DATA_E | INDICATION,
+						fifo->skbuff);
+			} else
+				fifo->hif->l1l2(fifo->hif,
+						PH_DATA | INDICATION,
+						fifo->skbuff);
+			fifo->skbuff = NULL;	/* buffer was freed from upper layer */
+		} else {
+			if (fifo->skbuff->len > 3) {
+				printk(KERN_INFO
+				       "HFC-S USB: got frame %d bytes but CRC ERROR on fifo:%d!!!\n",
+				       fifo->skbuff->len, fifon);
+#ifdef CONFIG_HISAX_DEBUG
+				if (debug > 1) {
+					printk(KERN_INFO "HFC-S USB: ");
+					for (i = 0; i < 15; i++)
+						printk("%.2x ",
+						       fifo->skbuff->
+						       data[fifo->skbuff->
+							    len - 15 + i]);
+					printk("\n");
+				}
+#endif
+			}
+#ifdef CONFIG_HISAX_DEBUG
+			else {
+				printk(KERN_INFO
+				       "HFC-S USB: frame to small (%d bytes)!!!\n",
+				       fifo->skbuff->len);
+			}
+#endif
+			skb_trim(fifo->skbuff, 0);
 		}
 	}
 
-	// LED flashing only in HDLC mode
-	if(!transp_mode)
-	{
-		if(fifon==HFCUSB_B1_RX) handle_led(hfc,LED_B1_DATA);
-		if(fifon==HFCUSB_B2_RX) handle_led(hfc,LED_B2_DATA);
+	/* LED flashing only in HDLC mode */
+	if (!transp_mode) {
+		if (fifon == HFCUSB_B1_RX)
+			handle_led(hfc, LED_B1_DATA);
+		if (fifon == HFCUSB_B2_RX)
+			handle_led(hfc, LED_B2_DATA);
 	}
 }
 
 /***********************************************/
 /* receive completion routine for all rx fifos */
 /***********************************************/
-static void rx_complete(struct urb *urb, struct pt_regs *regs)
+static void
+rx_complete(struct urb *urb, struct pt_regs *regs)
 {
 	int len;
-	__u8 *buf;
-	usb_fifo *fifo = (usb_fifo *) urb->context;	/* pointer to our fifo */
+	int status;
+	__u8 *buf, maxlen, fifon;
+	usb_fifo *fifo = (usb_fifo *) urb->context;
 	hfcusb_data *hfc = fifo->hfc;
+	static __u8 eof[8];
+#ifdef CONFIG_HISAX_DEBUG
+	__u8 i;
+#endif
 
 	urb->dev = hfc->dev;	/* security init */
 
-	if((!fifo->active) || (urb->status)) {
-#ifdef VERBOSE_USB_DEBUG
-		printk(KERN_INFO "HFC-USB: RX-Fifo %i is going down (%i)\n", fifo->fifonum, urb->status);
+	fifon = fifo->fifonum;
+	if ((!fifo->active) || (urb->status)) {
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(USB_DBG, "HFC-S USB: RX-Fifo %i is going down (%i)",
+		    fifon, urb->status);
 #endif
 		fifo->urb->interval = 0;	/* cancel automatic rescheduling */
-		if(fifo->skbuff) {
+		if (fifo->skbuff) {
 			dev_kfree_skb_any(fifo->skbuff);
 			fifo->skbuff = NULL;
 		}
 		return;
 	}
+	len = urb->actual_length;
+	buf = fifo->buffer;
+	maxlen = fifo->usb_packet_maxlen;
+
+#ifdef CONFIG_HISAX_DEBUG
+	if ((fifon == 5) && (debug > 1)) {
+		printk(KERN_INFO
+		       "HFC-S USB: INT-D-RX lst_urblen:%2d act_urblen:%2d max-urblen:%2d EOF:0x%0x DATA: ",
+		       fifo->last_urblen, len, maxlen, eof[5]);
+		for (i = 0; i < len; i++)
+			printk("%.2x ", buf[i]);
+		printk("\n");
+	}
+#endif
 
-	len=urb->actual_length;
-	buf=fifo->buffer;
-
-	if(fifo->last_urblen!=fifo->usb_packet_maxlen) {
-		// the threshold mask is in the 2nd status byte
-		hfc->threshold_mask=buf[1];
-		// the S0 state is in the upper half of the 1st status byte
-		state_handler(hfc,buf[0] >> 4);
-		// if we have more than the 2 status bytes -> collect data
-		if(len>2) collect_rx_frame(fifo,buf+2,urb->actual_length-2,buf[0]&1);
-	} else
-		collect_rx_frame(fifo,buf,urb->actual_length,0);
-
-	fifo->last_urblen=urb->actual_length;
-
-
-}	/* rx_complete */
-
-
+	if (fifo->last_urblen != fifo->usb_packet_maxlen) {
+		/* the threshold mask is in the 2nd status byte */
+		hfc->threshold_mask = buf[1];
+		/* the S0 state is in the upper half of the 1st status byte */
+		state_handler(hfc, buf[0] >> 4);
+		eof[fifon] = buf[0] & 1;
+		/* if we have more than the 2 status bytes -> collect data */
+		if (len > 2)
+			collect_rx_frame(fifo, buf + 2,
+					 urb->actual_length - 2,
+					 (len < maxlen) ? eof[fifon] : 0);
+	} else {
+		collect_rx_frame(fifo, buf, urb->actual_length,
+				 (len < maxlen) ? eof[fifon] : 0);
+	}
+	fifo->last_urblen = urb->actual_length;
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		printk(KERN_INFO
+		       "HFC-S USB: error resubmitting URN at rx_complete...\n");
+	}
+}				/* rx_complete */
 
 /***************************************************/
 /* start the interrupt transfer for the given fifo */
 /***************************************************/
-static void start_int_fifo(usb_fifo * fifo)
+static void
+start_int_fifo(usb_fifo * fifo)
 {
 	int errcode;
 
-#ifdef VERBOSE_USB_DEBUG
-	printk(KERN_INFO "HFC-USB: starting intr IN fifo:%d\n", fifo->fifonum);
-#endif
+	printk(KERN_INFO "HFC-S USB: starting intr IN fifo:%d\n",
+	       fifo->fifonum);
+
 	if (!fifo->urb) {
 		fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!fifo->urb)
 			return;
 	}
-	usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer,
-				 fifo->usb_packet_maxlen, rx_complete, fifo, fifo->intervall);
-	fifo->active = 1;		/* must be marked active */
+	usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
+			 fifo->buffer, fifo->usb_packet_maxlen,
+			 rx_complete, fifo, fifo->intervall);
+	fifo->active = 1;	/* must be marked active */
 	errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
-
-	if(errcode)
-	{
-		printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n",   errcode);
+	if (errcode) {
+		printk(KERN_INFO
+		       "HFC-S USB: submit URB error(start_int_info): status:%i\n",
+		       errcode);
 		fifo->active = 0;
 		fifo->skbuff = NULL;
 	}
-} /* start_int_fifo */
+}				/* start_int_fifo */
 
 /*****************************/
 /* set the B-channel mode    */
 /*****************************/
-static void set_hfcmode(hfcusb_data *hfc,int channel,int mode)
+static void
+set_hfcmode(hfcusb_data * hfc, int channel, int mode)
 {
-	__u8 val,idx_table[2]={0,2};
-
-#ifdef VERBOSE_ISDN_DEBUG
-  printk (KERN_INFO "HFC-USB: setting channel %d to mode %d\n",channel,mode);
-#endif
-
-	hfc->b_mode[channel]=mode;
-
-	// setup CON_HDLC
-	val=0;
-	if(mode!=L1_MODE_NULL) val=8;    // enable fifo?
-	if(mode==L1_MODE_TRANS) val|=2;  // set transparent bit
-
-	queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel],1); // set FIFO to transmit register
-	queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
-	queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo
-
-	queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel]+1,1); // set FIFO to receive register
-	queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
-	queue_control_request(hfc,HFCUSB_INC_RES_F,2,1);  // reset fifo
+	__u8 val, idx_table[2] = { 0, 2 };
 
-	val=0x40;
-	if(hfc->b_mode[0]) val|=1;
-	if(hfc->b_mode[1]) val|=2;
-	queue_control_request(hfc,HFCUSB_SCTRL,val,1);
-
-	val=0;
-	if(hfc->b_mode[0]) val|=1;
-	if(hfc->b_mode[1]) val|=2;
-	queue_control_request(hfc,HFCUSB_SCTRL_R,val,1);
-
-	if(mode==L1_MODE_NULL)
-	{
-		if(channel) handle_led(hfc,LED_B2_OFF);
-		else handle_led(hfc,LED_B1_OFF);
+	if (hfc->disc_flag) {
+		return;
 	}
-	else
-	{
-		if(channel) handle_led(hfc,LED_B2_ON);
-		else handle_led(hfc,LED_B1_ON);
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(ISDN_DBG, "HFC-S USB: setting channel %d to mode %d", channel,
+	    mode);
+#endif
+	hfc->b_mode[channel] = mode;
+
+	/* setup CON_HDLC */
+	val = 0;
+	if (mode != L1_MODE_NULL)
+		val = 8;	/* enable fifo? */
+	if (mode == L1_MODE_TRANS)
+		val |= 2;	/* set transparent bit */
+
+	/* set FIFO to transmit register */
+	queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1);
+	queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
+	/* reset fifo */
+	queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
+	/* set FIFO to receive register */
+	queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1);
+	queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
+	/* reset fifo */
+	queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
+
+	val = 0x40;
+	if (hfc->b_mode[0])
+		val |= 1;
+	if (hfc->b_mode[1])
+		val |= 2;
+	queue_control_request(hfc, HFCUSB_SCTRL, val, 1);
+
+	val = 0;
+	if (hfc->b_mode[0])
+		val |= 1;
+	if (hfc->b_mode[1])
+		val |= 2;
+	queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1);
+
+	if (mode == L1_MODE_NULL) {
+		if (channel)
+			handle_led(hfc, LED_B2_OFF);
+		else
+			handle_led(hfc, LED_B1_OFF);
+	} else {
+		if (channel)
+			handle_led(hfc, LED_B2_ON);
+		else
+			handle_led(hfc, LED_B1_ON);
 	}
 }
 
-/*
-   --------------------------------------------------------------------------------------
-   from here : hisax_if callback routines :
-     - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) {
-
-   l1 to l2 routines :
-     - static void hfc_usb_l1l2(hfcusb_data * hfc)
-
-*/
-
-void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
+void
+hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
 {
-    usb_fifo *fifo = my_hisax_if->priv;
+	usb_fifo *fifo = my_hisax_if->priv;
 	hfcusb_data *hfc = fifo->hfc;
 
-    switch (pr) {
+	switch (pr) {
 		case PH_ACTIVATE | REQUEST:
-				if(fifo->fifonum==HFCUSB_D_TX)
-				{
-#ifdef VERBOSE_ISDN_DEBUG
-					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST\n");
-#endif
-					queue_control_request(hfc, HFCUSB_STATES,0x60,1);	/* make activation */
-					hfc->t3_timer.expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000;
-					if(!timer_pending(&hfc->t3_timer)) add_timer(&hfc->t3_timer);
-				}
-				else
-				{
-#ifdef VERBOSE_ISDN_DEBUG
-					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST\n");
-#endif
-					set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)arg);
-					fifo->hif->l1l2(fifo->hif,PH_ACTIVATE | INDICATION, NULL);
-				}
-                break;
-        case PH_DEACTIVATE | REQUEST:
-				if(fifo->fifonum==HFCUSB_D_TX)
-				{
-#ifdef VERBOSE_ISDN_DEBUG
-					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST\n");
-#endif
-					printk (KERN_INFO "HFC-USB: ISDN TE device should not deativate...\n");
-				}
-				else
-				{
-#ifdef VERBOSE_ISDN_DEBUG
-					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST\n");
-#endif
-					set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)L1_MODE_NULL);
-					fifo->hif->l1l2(fifo->hif,PH_DEACTIVATE | INDICATION, NULL);
+			if (fifo->fifonum == HFCUSB_D_TX) {
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(ISDN_DBG,
+				    "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
+#endif
+				if (hfc->l1_state != 3
+				    && hfc->l1_state != 7) {
+					hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
+							   PH_DEACTIVATE |
+							   INDICATION,
+							   NULL);
+#ifdef CONFIG_HISAX_DEBUG
+					DBG(ISDN_DBG,
+					    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
+#endif
+				} else {
+					if (hfc->l1_state == 7) {	/* l1 already active */
+						hfc->d_if.ifc.l1l2(&hfc->
+								   d_if.
+								   ifc,
+								   PH_ACTIVATE
+								   |
+								   INDICATION,
+								   NULL);
+#ifdef CONFIG_HISAX_DEBUG
+						DBG(ISDN_DBG,
+						    "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
+#endif
+					} else {
+						/* force sending sending INFO1 */
+						queue_control_request(hfc,
+								      HFCUSB_STATES,
+								      0x14,
+								      1);
+						mdelay(1);
+						/* start l1 activation */
+						queue_control_request(hfc,
+								      HFCUSB_STATES,
+								      0x04,
+								      1);
+						if (!timer_pending
+						    (&hfc->t3_timer)) {
+							hfc->t3_timer.
+							    expires =
+							    jiffies +
+							    (HFC_TIMER_T3 *
+							     HZ) / 1000;
+							add_timer(&hfc->
+								  t3_timer);
+						}
+					}
 				}
-                break;
+			} else {
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(ISDN_DBG,
+				    "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST");
+#endif
+				set_hfcmode(hfc,
+					    (fifo->fifonum ==
+					     HFCUSB_B1_TX) ? 0 : 1,
+					    (int) arg);
+				fifo->hif->l1l2(fifo->hif,
+						PH_ACTIVATE | INDICATION,
+						NULL);
+			}
+			break;
+		case PH_DEACTIVATE | REQUEST:
+			if (fifo->fifonum == HFCUSB_D_TX) {
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(ISDN_DBG,
+				    "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
+#endif
+				printk(KERN_INFO
+				       "HFC-S USB: ISDN TE device should not deativate...\n");
+			} else {
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(ISDN_DBG,
+				    "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
+#endif
+				set_hfcmode(hfc,
+					    (fifo->fifonum ==
+					     HFCUSB_B1_TX) ? 0 : 1,
+					    (int) L1_MODE_NULL);
+				fifo->hif->l1l2(fifo->hif,
+						PH_DEACTIVATE | INDICATION,
+						NULL);
+			}
+			break;
 		case PH_DATA | REQUEST:
-				if(fifo->skbuff && fifo->delete_flg)
-				{
-					dev_kfree_skb_any(fifo->skbuff);
-					//printk(KERN_INFO "skbuff=NULL on fifo:%d\n",fifo->fifonum);
-					fifo->skbuff = NULL;
-					fifo->delete_flg=FALSE;
-				}
-
-				fifo->skbuff=arg; // we have a new buffer
-
-				//if(fifo->fifonum==HFCUSB_D_TX) printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DATA | REQUEST\n");
-				//else printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DATA | REQUEST\n");
-                break;
-        default:
-                printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n", pr);
-                break;
-    }
+			if (fifo->skbuff && fifo->delete_flg) {
+				dev_kfree_skb_any(fifo->skbuff);
+				fifo->skbuff = NULL;
+				fifo->delete_flg = FALSE;
+			}
+			fifo->skbuff = arg;	/* we have a new buffer */
+			break;
+		default:
+			printk(KERN_INFO
+			       "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n",
+			       pr);
+			break;
+	}
 }
 
-// valid configurations
-#define CNF_4INT3ISO  1      // 4 INT IN, 3 ISO OUT
-#define CNF_3INT3ISO  2      // 3 INT IN, 3 ISO OUT
-#define CNF_4ISO3ISO  3      // 4 ISO IN, 3 ISO OUT
-#define CNF_3ISO3ISO  4 	 // 3 ISO IN, 3 ISO OUT
-
-
-/*
-   --------------------------------------------------------------------------------------
-   From here on USB initialization and deactivation related routines are implemented :
-
-   - hfc_usb_init :
-      is the main Entry Point for the USB Subsystem when the device get plugged
-      in. This function calls usb_register with usb_driver as parameter.
-      Here, further entry points for probing (hfc_usb_probe) and disconnecting
-      the device (hfc_usb_disconnect) are published, as the id_table
-
-   - hfc_usb_probe
-      this function is called by the usb subsystem, and steps through the alternate
-      settings of the currently plugged in device to detect all Endpoints needed to
-      run an ISDN TA.
-      Needed EndPoints are
-      3 (+1) IntIn EndPoints   (D-in,  E-in, B1-in, B2-in, (E-in)) or
-      3 (+1) Isochron In Endpoints (D-out, B1-out, B2-out) and 3 IsoOut Endpoints
-      The currently used transfer mode of on the Out-Endpoints will be stored in
-      hfc->usb_transfer_mode and is either USB_INT or USB_ISO
-      When a valid alternate setting could be found, the usb_init (see blow)
-      function is called
-
-   - usb_init
-      Here, the HFC_USB Chip itself gets initialized and the USB framework to send/receive
-      Data to/from the several EndPoints are initialized:
-       The E- and D-Channel Int-In chain gets started
-       The IsoChain for the Iso-Out traffic get started
-
-   - hfc_usb_disconnect
-      this function is called by the usb subsystem and has to free all resources
-      and stop all usb traffic to allow a proper hotplugging disconnect.
-
-*/
-
 /***************************************************************************/
 /* usb_init is called once when a new matching device is detected to setup */
-/* main parameters. It registers the driver at the main hisax module.       */
+/* main parameters. It registers the driver at the main hisax module.      */
 /* on success 0 is returned.                                               */
 /***************************************************************************/
-static int usb_init(hfcusb_data * hfc)
+static int
+usb_init(hfcusb_data * hfc)
 {
 	usb_fifo *fifo;
 	int i, err;
 	u_char b;
 	struct hisax_b_if *p_b_if[2];
-	
+
 	/* check the chip id */
-	printk(KERN_INFO "HFCUSB_CHIP_ID begin\n");
 	if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
 		printk(KERN_INFO "HFC-USB: cannot read chip id\n");
-		return(1); 
+		return (1);
 	}
-	printk(KERN_INFO "HFCUSB_CHIP_ID %x\n", b);
 	if (b != HFCUSB_CHIPID) {
-		printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b);
-		return(1);
+		printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);
+		return (1);
 	}
 
 	/* first set the needed config, interface and alternate */
-	printk(KERN_INFO "usb_init 1\n");
-//	usb_set_configuration(hfc->dev, 1);
-	printk(KERN_INFO "usb_init 2\n");
 	err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
-	printk(KERN_INFO "usb_init usb_set_interface return %d\n", err);
-	/* now we initialize the chip */
-	write_usb(hfc, HFCUSB_CIRM, 8);	    // do reset
-	write_usb(hfc, HFCUSB_CIRM, 0x10);	// aux = output, reset off
 
-	// set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers
-	write_usb(hfc, HFCUSB_USB_SIZE,(hfc->packet_size/8) | ((hfc->packet_size/8) << 4));
+	/* do Chip reset */
+	write_usb(hfc, HFCUSB_CIRM, 8);
+	/* aux = output, reset off */
+	write_usb(hfc, HFCUSB_CIRM, 0x10);
+
+	/* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+	write_usb(hfc, HFCUSB_USB_SIZE,
+		  (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
 
-	// set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers
+	/* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
 	write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
 
 	/* enable PCM/GCI master mode */
@@ -1184,412 +1292,447 @@ static int usb_init(hfcusb_data * hfc)
 	write_usb(hfc, HFCUSB_MST_MODE0, 1);	/* enable master mode */
 
 	/* init the fifos */
-	write_usb(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD/8) |((HFCUSB_RX_THRESHOLD/8) << 4));
+	write_usb(hfc, HFCUSB_F_THRES,
+		  (HFCUSB_TX_THRESHOLD /
+		   8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
 
 	fifo = hfc->fifos;
-	for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
-	{
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
 		write_usb(hfc, HFCUSB_FIFO, i);	/* select the desired fifo */
 		fifo[i].skbuff = NULL;	/* init buffer pointer */
-		fifo[i].max_size = (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
-		fifo[i].last_urblen=0;
-		write_usb(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2));	    // set 2 bit for D- & E-channel
-		write_usb(hfc, HFCUSB_CON_HDLC, ((i==HFCUSB_D_TX) ? 0x09 : 0x08));	// rx hdlc, enable IFF for D-channel
+		fifo[i].max_size =
+		    (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
+		fifo[i].last_urblen = 0;
+		/* set 2 bit for D- & E-channel */
+		write_usb(hfc, HFCUSB_HDLC_PAR,
+			  ((i <= HFCUSB_B2_RX) ? 0 : 2));
+		/* rx hdlc, enable IFF for D-channel */
+		write_usb(hfc, HFCUSB_CON_HDLC,
+			  ((i == HFCUSB_D_TX) ? 0x09 : 0x08));
 		write_usb(hfc, HFCUSB_INC_RES_F, 2);	/* reset the fifo */
 	}
 
-	write_usb(hfc, HFCUSB_CLKDEL, 0x0f);	 /* clock delay value */
-	write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
-	write_usb(hfc, HFCUSB_STATES, 3);	     /* enable state machine */
-
-	write_usb(hfc, HFCUSB_SCTRL_R, 0);	     /* disable both B receivers */
-	write_usb(hfc, HFCUSB_SCTRL, 0x40);	     /* disable B transmitters + capacitive mode */
-
-	// set both B-channel to not connected
-	hfc->b_mode[0]=L1_MODE_NULL;
-	hfc->b_mode[1]=L1_MODE_NULL;
-
-	hfc->l1_activated=FALSE;
-	hfc->led_state=0;
-	hfc->led_new_data=0;
+	write_usb(hfc, HFCUSB_CLKDEL, 0x0f);	/* clock delay value */
+	write_usb(hfc, HFCUSB_STATES, 3 | 0x10);	/* set deactivated mode */
+	write_usb(hfc, HFCUSB_STATES, 3);	/* enable state machine */
+
+	write_usb(hfc, HFCUSB_SCTRL_R, 0);	/* disable both B receivers */
+	write_usb(hfc, HFCUSB_SCTRL, 0x40);	/* disable B transmitters + capacitive mode */
+
+	/* set both B-channel to not connected */
+	hfc->b_mode[0] = L1_MODE_NULL;
+	hfc->b_mode[1] = L1_MODE_NULL;
+
+	hfc->l1_activated = FALSE;
+	hfc->disc_flag = FALSE;
+	hfc->led_state = 0;
+	hfc->led_new_data = 0;
+	hfc->old_led_state = 0;
 
 	/* init the t3 timer */
 	init_timer(&hfc->t3_timer);
 	hfc->t3_timer.data = (long) hfc;
 	hfc->t3_timer.function = (void *) l1_timer_expire_t3;
+
 	/* init the t4 timer */
 	init_timer(&hfc->t4_timer);
 	hfc->t4_timer.data = (long) hfc;
 	hfc->t4_timer.function = (void *) l1_timer_expire_t4;
+
 	/* init the led timer */
 	init_timer(&hfc->led_timer);
 	hfc->led_timer.data = (long) hfc;
 	hfc->led_timer.function = (void *) led_timer;
-	// trigger 4 hz led timer
-	hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
-	if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
 
-	// init the background machinery for control requests
+	/* trigger 4 hz led timer */
+	if (!timer_pending(&hfc->led_timer)) {
+		hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
+		add_timer(&hfc->led_timer);
+	}
+
+	/* init the background machinery for control requests */
 	hfc->ctrl_read.bRequestType = 0xc0;
 	hfc->ctrl_read.bRequest = 1;
 	hfc->ctrl_read.wLength = 1;
 	hfc->ctrl_write.bRequestType = 0x40;
 	hfc->ctrl_write.bRequest = 0;
 	hfc->ctrl_write.wLength = 0;
-	usb_fill_control_urb(hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,(u_char *) & hfc->ctrl_write, NULL, 0, ctrl_complete, hfc);
-					
+	usb_fill_control_urb(hfc->ctrl_urb,
+			     hfc->dev,
+			     hfc->ctrl_out_pipe,
+			     (u_char *) & hfc->ctrl_write,
+			     NULL, 0, ctrl_complete, hfc);
 	/* Init All Fifos */
-	for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
-	{
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
 		hfc->fifos[i].iso[0].purb = NULL;
 		hfc->fifos[i].iso[1].purb = NULL;
 		hfc->fifos[i].active = 0;
 	}
-
-	// register like Germaschewski :
+	/* register Modul to upper Hisax Layers */
 	hfc->d_if.owner = THIS_MODULE;
 	hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
 	hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
-
-	for (i=0; i<2; i++)
-	{
-		hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX+i*2];
+	for (i = 0; i < 2; i++) {
+		hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2];
 		hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
 		p_b_if[i] = &hfc->b_if[i];
 	}
-	
-	hfc->protocol = 2;  /* default EURO ISDN, should be a module_param */
+	/* default Prot: EURO ISDN, should be a module_param */
+	hfc->protocol = 2;
 	hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
-	
-	for (i=0; i<4; i++)
-		hfc->fifos[i].hif=&p_b_if[i/2]->ifc;
-	for (i=4; i<8; i++)
-		hfc->fifos[i].hif=&hfc->d_if.ifc;
-
-	// 3 (+1) INT IN + 3 ISO OUT
-	if(hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO)
-	{
-		start_int_fifo(hfc->fifos + HFCUSB_D_RX);	// Int IN D-fifo
-		if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);	// E-fifo
-		start_int_fifo(hfc->fifos + HFCUSB_B1_RX);	// Int IN B1-fifo
-		start_int_fifo(hfc->fifos + HFCUSB_B2_RX);	// Int IN B2-fifo
-	}
-
-	// 3 (+1) ISO IN + 3 ISO OUT
-	if(hfc->cfg_used==CNF_3ISO3ISO || hfc->cfg_used==CNF_4ISO3ISO)
-	{
-		start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, rx_iso_complete,16);
-		if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, ISOC_PACKETS_D, rx_iso_complete,16);
-		start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, rx_iso_complete,16);
-		start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, rx_iso_complete,16);
-	}
-
-	start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, tx_iso_complete,1);
-	start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, tx_iso_complete,1);
-	start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, tx_iso_complete,1);
-
-	handle_led(hfc,LED_POWER_ON);
-
-	return(0);
-}	/* usb_init */
-
-
-/****************************************/
-/* data defining the devices to be used */
-/****************************************/
-// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {
-static struct usb_device_id hfc_usb_idtab[] = {
-	{USB_DEVICE(0x7b0, 0x0007)},	/* Billion USB TA 2 */
-	{USB_DEVICE(0x742, 0x2008)},	/* Stollmann USB TA */
-	{USB_DEVICE(0x959, 0x2bd0)},	/* Colognechip USB eval TA */
-	{USB_DEVICE(0x8e3, 0x0301)},	/* OliTec ISDN USB */
-	{USB_DEVICE(0x675, 0x1688)},	/* DrayTec ISDN USB */
-	{USB_DEVICE(0x7fa, 0x0846)},    /* Bewan ISDN USB TA */
-	{}				/* end with an all-zeroes entry */
-};
 
-MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)");
-MODULE_DESCRIPTION("HFC I4L USB driver");
-MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_HISAX_DEBUG
+	hfc_debug = debug;
+#endif
 
-#define EP_NUL 1    // Endpoint at this position not allowed
-#define EP_NOP 2	// all type of endpoints allowed at this position
-#define EP_ISO 3	// Isochron endpoint mandatory at this position
-#define EP_BLK 4	// Bulk endpoint mandatory at this position
-#define EP_INT 5	// Interrupt endpoint mandatory at this position
-
-// this array represents all endpoints possible in the HCF-USB
-// the last 2 entries are the configuration number and the minimum interval for Interrupt endpoints
-int validconf[][18]=
-{
-	// INT in, ISO out config
-	{EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2},
-	{EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2},
-	// ISO in, ISO out config
-	{EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2},
-	{EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2},
-	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}       // EOL element
-};
+	for (i = 0; i < 4; i++)
+		hfc->fifos[i].hif = &p_b_if[i / 2]->ifc;
+	for (i = 4; i < 8; i++)
+		hfc->fifos[i].hif = &hfc->d_if.ifc;
+
+	/* 3 (+1) INT IN + 3 ISO OUT */
+	if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) {
+		start_int_fifo(hfc->fifos + HFCUSB_D_RX);
+		if (hfc->fifos[HFCUSB_PCM_RX].pipe)
+			start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);
+		start_int_fifo(hfc->fifos + HFCUSB_B1_RX);
+		start_int_fifo(hfc->fifos + HFCUSB_B2_RX);
+	}
+	/* 3 (+1) ISO IN + 3 ISO OUT */
+	if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) {
+		start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,
+				 rx_iso_complete, 16);
+		if (hfc->fifos[HFCUSB_PCM_RX].pipe)
+			start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX,
+					 ISOC_PACKETS_D, rx_iso_complete,
+					 16);
+		start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B,
+				 rx_iso_complete, 16);
+		start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B,
+				 rx_iso_complete, 16);
+	}
+
+	start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,
+			 tx_iso_complete, 1);
+	start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,
+			 tx_iso_complete, 1);
+	start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,
+			 tx_iso_complete, 1);
 
-// string description of chosen config
-char *conf_str[]=
-{
-	"4 Interrupt IN + 3 Isochron OUT",
-	"3 Interrupt IN + 3 Isochron OUT",
-	"4 Isochron IN + 3 Isochron OUT",
-	"3 Isochron IN + 3 Isochron OUT"
-};
+	handle_led(hfc, LED_POWER_ON);
 
+	return (0);
+}				/* usb_init */
 
 /*************************************************/
 /* function called to probe a new plugged device */
 /*************************************************/
-static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int
+hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-	struct usb_device *dev= interface_to_usbdev(intf);
+	struct usb_device *dev = interface_to_usbdev(intf);
 	hfcusb_data *context;
 	struct usb_host_interface *iface = intf->cur_altsetting;
 	struct usb_host_interface *iface_used = NULL;
 	struct usb_host_endpoint *ep;
 	int ifnum = iface->desc.bInterfaceNumber;
-	int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
-	int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0;
-
-//        usb_show_device(dev);
-//	usb_show_device_descriptor(&dev->descriptor);
-//	usb_show_interface_descriptor(&iface->desc);
-	vend_idx=0xffff;
-	for(i=0;vdata[i].vendor;i++) {
-		if (le16_to_cpu(dev->descriptor.idVendor) == vdata[i].vendor && 
-		    le16_to_cpu(dev->descriptor.idProduct) == vdata[i].prod_id)
+	int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,
+	    attr, cfg_found, cidx, ep_addr;
+	int cmptbl[16], small_match, iso_packet_size, packet_size,
+	    alt_used = 0;
+
+	vend_idx = 0xffff;
+	for (i = 0; vdata[i].vendor; i++) {
+		if (dev->descriptor.idVendor == vdata[i].vendor
+		    && dev->descriptor.idProduct == vdata[i].prod_id)
 			vend_idx = i;
 	}
-	
-
-#ifdef VERBOSE_USB_DEBUG	
-	printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n",
-		ifnum, iface->desc.bAlternateSetting, intf->minor);
-#endif
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(USB_DBG,
+	    "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum,
+	    iface->desc.bAlternateSetting, intf->minor);
+#endif
+	printk(KERN_INFO
+	       "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
+	       ifnum, iface->desc.bAlternateSetting, intf->minor);
 
 	if (vend_idx != 0xffff) {
-#ifdef VERBOSE_USB_DEBUG
-		printk(KERN_INFO "HFC-USB: found vendor idx:%d  name:%s\n",vend_idx,vdata[vend_idx].vend_name);
+#ifdef CONFIG_HISAX_DEBUG
+		DBG(USB_DBG, "HFC-S USB: found vendor idx:%d  name:%s",
+		    vend_idx, vdata[vend_idx].vend_name);
 #endif
-		/* if vendor and product ID is OK, start probing a matching alternate setting ... */
+		/* if vendor and product ID is OK, start probing alternate settings */
 		alt_idx = 0;
-		small_match=0xffff;
-		// default settings
-		iso_packet_size=16;
-		packet_size=64;
+		small_match = 0xffff;
+
+		/* default settings */
+		iso_packet_size = 16;
+		packet_size = 64;
 
 		while (alt_idx < intf->num_altsetting) {
 			iface = intf->altsetting + alt_idx;
 			probe_alt_setting = iface->desc.bAlternateSetting;
-			cfg_used=0;
+			cfg_used = 0;
 
-#ifdef VERBOSE_USB_DEBUG
-			printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting);
-#endif
-			// check for config EOL element
+			/* check for config EOL element */
 			while (validconf[cfg_used][0]) {
-				cfg_found=TRUE;
-				vcf=validconf[cfg_used];
-				ep = iface->endpoint;	/* first endpoint descriptor */
-
-#ifdef VERBOSE_USB_DEBUG
-				printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n",
-					ifnum, probe_alt_setting, cfg_used);
-#endif
-				// copy table
-				memcpy(cmptbl,vcf,16*sizeof(int));
-
-				// check for all endpoints in this alternate setting
-				for (i=0; i < iface->desc.bNumEndpoints; i++) {
-					ep_addr = ep->desc.bEndpointAddress;
-					idx = ((ep_addr & 0x7f)-1)*2;	/* get endpoint base */
+				cfg_found = TRUE;
+				vcf = validconf[cfg_used];
+				/* first endpoint descriptor */
+				ep = iface->endpoint;
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(USB_DBG,
+				    "HFC-S USB: (if=%d alt=%d cfg_used=%d)\n",
+				    ifnum, probe_alt_setting, cfg_used);
+#endif
+				memcpy(cmptbl, vcf, 16 * sizeof(int));
+
+				/* check for all endpoints in this alternate setting */
+				for (i = 0; i < iface->desc.bNumEndpoints;
+				     i++) {
+					ep_addr =
+					    ep->desc.bEndpointAddress;
+					/* get endpoint base */
+					idx = ((ep_addr & 0x7f) - 1) * 2;
 					if (ep_addr & 0x80)
 						idx++;
 					attr = ep->desc.bmAttributes;
-
 					if (cmptbl[idx] == EP_NUL) {
-						printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d  attr:%d  cmptbl[%d]:%d\n",
-							idx, attr, idx, cmptbl[idx]);
 						cfg_found = FALSE;
 					}
-
-					if (attr == USB_ENDPOINT_XFER_INT && cmptbl[idx] == EP_INT)
+					if (attr == USB_ENDPOINT_XFER_INT
+					    && cmptbl[idx] == EP_INT)
 						cmptbl[idx] = EP_NUL;
-					if (attr == USB_ENDPOINT_XFER_BULK && cmptbl[idx] == EP_BLK)
+					if (attr == USB_ENDPOINT_XFER_BULK
+					    && cmptbl[idx] == EP_BLK)
 						cmptbl[idx] = EP_NUL;
-					if (attr == USB_ENDPOINT_XFER_ISOC && cmptbl[idx] == EP_ISO)
+					if (attr == USB_ENDPOINT_XFER_ISOC
+					    && cmptbl[idx] == EP_ISO)
 						cmptbl[idx] = EP_NUL;
 
-					// check if all INT endpoints match minimum interval
-					if (attr == USB_ENDPOINT_XFER_INT && ep->desc.bInterval < vcf[17]) {
-#ifdef VERBOSE_USB_DEBUG
+					/* check if all INT endpoints match minimum interval */
+					if (attr == USB_ENDPOINT_XFER_INT
+					    && ep->desc.bInterval <
+					    vcf[17]) {
+#ifdef CONFIG_HISAX_DEBUG
 						if (cfg_found)
-							printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n",
-								vcf[17]);
+							DBG(USB_DBG,
+							    "HFC-S USB: Interrupt Endpoint interval < %d found - skipping config",
+							    vcf[17]);
 #endif
 						cfg_found = FALSE;
 					}
-
 					ep++;
 				}
-
 				for (i = 0; i < 16; i++) {
-					// printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[i]);
-
-					// all entries must be EP_NOP or EP_NUL for a valid config
-					if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
+					/* all entries must be EP_NOP or EP_NUL for a valid config */
+					if (cmptbl[i] != EP_NOP
+					    && cmptbl[i] != EP_NUL)
 						cfg_found = FALSE;
 				}
-
-				// we check for smallest match, to provide configuration priority
-				// configurations with smaller index have higher priority
 				if (cfg_found) {
 					if (cfg_used < small_match) {
 						small_match = cfg_used;
-						alt_used = probe_alt_setting;
+						alt_used =
+						    probe_alt_setting;
 						iface_used = iface;
 					}
-#ifdef VERBOSE_USB_DEBUG
-					printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);
+#ifdef CONFIG_HISAX_DEBUG
+					DBG(USB_DBG,
+					    "HFC-USB: small_match=%x %x\n",
+					    small_match, alt_used);
 #endif
 				}
-
 				cfg_used++;
 			}
-
 			alt_idx++;
 		}		/* (alt_idx < intf->num_altsetting) */
-#ifdef VERBOSE_USB_DEBUG
-		printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);
-#endif
-		// yiipiee, we found a valid config
+
+		/* found a valid USB Ta Endpint config */
 		if (small_match != 0xffff) {
 			iface = iface_used;
+			if (!
+			    (context =
+			     kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+				return (-ENOMEM);	/* got no mem */
+			memset(context, 0, sizeof(hfcusb_data));
 
-			if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
-				return(-ENOMEM);  /* got no mem */
-			memset(context, 0, sizeof(hfcusb_data));	/* clear the structure */
-
-			ep = iface->endpoint;	/* first endpoint descriptor */
+			ep = iface->endpoint;
 			vcf = validconf[small_match];
 
 			for (i = 0; i < iface->desc.bNumEndpoints; i++) {
 				ep_addr = ep->desc.bEndpointAddress;
-				idx = ((ep_addr & 0x7f)-1)*2;	/* get endpoint base */
+				/* get endpoint base */
+				idx = ((ep_addr & 0x7f) - 1) * 2;
 				if (ep_addr & 0x80)
 					idx++;
 				cidx = idx & 7;
 				attr = ep->desc.bmAttributes;
 
-				// only initialize used endpoints
-				if (vcf[idx] != EP_NOP && vcf[idx] != EP_NUL) {
+				/* init Endpoints */
+				if (vcf[idx] != EP_NOP
+				    && vcf[idx] != EP_NUL) {
 					switch (attr) {
 						case USB_ENDPOINT_XFER_INT:
-							context->fifos[cidx].pipe = usb_rcvintpipe(dev, ep->desc.bEndpointAddress);
-							context->fifos[cidx].usb_transfer_mode = USB_INT;
-							packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); // remember max packet size
-#ifdef VERBOSE_USB_DEBUG
-							printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n",
-								ep->desc.bInterval, idx, cidx);
-#endif
+							context->
+							    fifos[cidx].
+							    pipe =
+							    usb_rcvintpipe
+							    (dev,
+							     ep->desc.
+							     bEndpointAddress);
+							context->
+							    fifos[cidx].
+							    usb_transfer_mode
+							    = USB_INT;
+							packet_size =
+							    ep->desc.
+							    wMaxPacketSize;
 							break;
 						case USB_ENDPOINT_XFER_BULK:
 							if (ep_addr & 0x80)
-								context->fifos[cidx].pipe = usb_rcvbulkpipe(dev, ep->desc.bEndpointAddress);
+								context->
+								    fifos
+								    [cidx].
+								    pipe =
+								    usb_rcvbulkpipe
+								    (dev,
+								     ep->
+								     desc.
+								     bEndpointAddress);
 							else
-								context->fifos[cidx].pipe = usb_sndbulkpipe(dev, ep->desc.bEndpointAddress);
-							context->fifos[cidx].usb_transfer_mode = USB_BULK;
-							packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); // remember max packet size
-#ifdef VERBOSE_USB_DEBUG
-							printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n",
-								idx, cidx);
-#endif
+								context->
+								    fifos
+								    [cidx].
+								    pipe =
+								    usb_sndbulkpipe
+								    (dev,
+								     ep->
+								     desc.
+								     bEndpointAddress);
+							context->
+							    fifos[cidx].
+							    usb_transfer_mode
+							    = USB_BULK;
+							packet_size =
+							    ep->desc.
+							    wMaxPacketSize;
 							break;
 						case USB_ENDPOINT_XFER_ISOC:
 							if (ep_addr & 0x80)
-								context->fifos[cidx].pipe = usb_rcvisocpipe(dev, ep->desc.bEndpointAddress);
+								context->
+								    fifos
+								    [cidx].
+								    pipe =
+								    usb_rcvisocpipe
+								    (dev,
+								     ep->
+								     desc.
+								     bEndpointAddress);
 							else
-								context->fifos[cidx].pipe = usb_sndisocpipe(dev, ep->desc.bEndpointAddress);
-							context->fifos[cidx].usb_transfer_mode = USB_ISOC;
-							iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); // remember max packet size
-#ifdef VERBOSE_USB_DEBUG
-							printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n",
-								idx, cidx);
-#endif
+								context->
+								    fifos
+								    [cidx].
+								    pipe =
+								    usb_sndisocpipe
+								    (dev,
+								     ep->
+								     desc.
+								     bEndpointAddress);
+							context->
+							    fifos[cidx].
+							    usb_transfer_mode
+							    = USB_ISOC;
+							iso_packet_size =
+							    ep->desc.
+							    wMaxPacketSize;
 							break;
 						default:
-							context->fifos[cidx].pipe = 0;	/* reset data */
+							context->
+							    fifos[cidx].
+							    pipe = 0;
 					}	/* switch attribute */
 
 					if (context->fifos[cidx].pipe) {
-						context->fifos[cidx].fifonum = cidx;
-						context->fifos[cidx].hfc = context;
-						context->fifos[cidx].usb_packet_maxlen = le16_to_cpu(ep->desc.wMaxPacketSize);
-						context->fifos[cidx].intervall = ep->desc.bInterval;
-						context->fifos[cidx].skbuff = NULL;
-#ifdef VERBOSE_USB_DEBUG
-						printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n",
-							context->fifos[cidx].fifonum,
-							context->fifos[cidx].usb_packet_maxlen,
-							context->fifos[cidx].intervall);
-#endif
+						context->fifos[cidx].
+						    fifonum = cidx;
+						context->fifos[cidx].hfc =
+						    context;
+						context->fifos[cidx].
+						    usb_packet_maxlen =
+						    ep->desc.
+						    wMaxPacketSize;
+						context->fifos[cidx].
+						    intervall =
+						    ep->desc.bInterval;
+						context->fifos[cidx].
+						    skbuff = NULL;
 					}
 				}
-
 				ep++;
 			}
-
-			// now share our luck
-			context->dev = dev;						/* save device */
-			context->if_used = ifnum;					/* save used interface */
-			context->alt_used = alt_used;					/* and alternate config */
+			context->dev = dev;	/* save device */
+			context->if_used = ifnum;	/* save used interface */
+			context->alt_used = alt_used;	/* and alternate config */
 			context->ctrl_paksize = dev->descriptor.bMaxPacketSize0;	/* control size */
-			context->cfg_used=vcf[16];					// store used config
-			context->vend_idx=vend_idx;					// store found vendor
-			context->packet_size=packet_size;
-			context->iso_packet_size=iso_packet_size;
+			context->cfg_used = vcf[16];	/* store used config */
+			context->vend_idx = vend_idx;	/* store found vendor */
+			context->packet_size = packet_size;
+			context->iso_packet_size = iso_packet_size;
 
 			/* create the control pipes needed for register access */
-			context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0);
-			context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0);
+			context->ctrl_in_pipe =
+			    usb_rcvctrlpipe(context->dev, 0);
+			context->ctrl_out_pipe =
+			    usb_sndctrlpipe(context->dev, 0);
 			context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
 
-			printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n",
-				vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used);
-
+			printk(KERN_INFO
+			       "HFC-S USB: detected \"%s\"\n",
+			       vdata[vend_idx].vend_name);
+#ifdef CONFIG_HISAX_DEBUG
+			DBG(USB_DBG,
+			    "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n",
+			    conf_str[small_match], context->if_used,
+			    context->alt_used);
+			printk(KERN_INFO
+			       "HFC-S USB: E-channel (\"ECHO:\") logging ");
+			if (validconf[small_match][18])
+				printk(" possible\n");
+			else
+				printk("NOT possible\n");
+#endif
 			/* init the chip and register the driver */
-			if (usb_init(context))
-			{
+			if (usb_init(context)) {
 				if (context->ctrl_urb) {
 					usb_unlink_urb(context->ctrl_urb);
 					usb_free_urb(context->ctrl_urb);
 					context->ctrl_urb = NULL;
 				}
 				kfree(context);
-				return(-EIO);
+				return (-EIO);
 			}
 			usb_set_intfdata(intf, context);
-			return(0);
-		} 
+			return (0);
+		}
+	} else {
+		printk(KERN_INFO
+		       "HFC-S USB: no valid vendor found in USB descriptor\n");
 	}
-	return(-EIO);
+	return (-EIO);
 }
 
 /****************************************************/
 /* function called when an active device is removed */
 /****************************************************/
-static void hfc_usb_disconnect(struct usb_interface *intf)
+static void
+hfc_usb_disconnect(struct usb_interface
+		   *intf)
 {
 	hfcusb_data *context = usb_get_intfdata(intf);
 	int i;
-
-	printk(KERN_INFO "HFC-USB: device disconnect\n");
-	
+	printk(KERN_INFO "HFC-S USB: device disconnect\n");
+	context->disc_flag = TRUE;
 	usb_set_intfdata(intf, NULL);
 	if (!context)
 		return;
@@ -1599,23 +1742,24 @@ static void hfc_usb_disconnect(struct us
 		del_timer(&context->t4_timer);
 	if (timer_pending(&context->led_timer))
 		del_timer(&context->led_timer);
-
-	hisax_unregister(&context->d_if);
-
 	/* tell all fifos to terminate */
-	for(i = 0; i < HFCUSB_NUM_FIFOS; i++) {
-		if(context->fifos[i].usb_transfer_mode == USB_ISOC) {
-			if(context->fifos[i].active > 0) {
-	    			stop_isoc_chain(&context->fifos[i]);
-#ifdef VERBOSE_USB_DEBUG
-		    		printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i);
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+		if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
+			if (context->fifos[i].active > 0) {
+				stop_isoc_chain(&context->fifos[i]);
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(USB_DBG,
+				    "HFC-S USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i",
+				    i);
 #endif
- 			}
+			}
 		} else {
-			if(context->fifos[i].active > 0) {
+			if (context->fifos[i].active > 0) {
 				context->fifos[i].active = 0;
-#ifdef VERBOSE_USB_DEBUG
-				printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i);
+#ifdef CONFIG_HISAX_DEBUG
+				DBG(USB_DBG,
+				    "HFC-S USB: hfc_usb_disconnect: unlinking URB for Fifo no %i",
+				    i);
 #endif
 			}
 			if (context->fifos[i].urb) {
@@ -1626,46 +1770,59 @@ static void hfc_usb_disconnect(struct us
 		}
 		context->fifos[i].active = 0;
 	}
+	/* wait for all URBS to terminate */
+	mdelay(10);
 	if (context->ctrl_urb) {
 		usb_unlink_urb(context->ctrl_urb);
 		usb_free_urb(context->ctrl_urb);
 		context->ctrl_urb = NULL;
 	}
+	hisax_unregister(&context->d_if);
 	kfree(context);		/* free our structure again */
 }				/* hfc_usb_disconnect */
 
-
 /************************************/
 /* our driver information structure */
 /************************************/
 static struct usb_driver hfc_drv = {
-	.owner =	THIS_MODULE,
-	.name =		"hfc_usb",
-	.id_table = 	hfc_usb_idtab,
-	.probe =	hfc_usb_probe,
-	.disconnect =	hfc_usb_disconnect,
+	.owner = THIS_MODULE,.name =
+	    "hfc_usb",.id_table = hfc_usb_idtab,.probe =
+	    hfc_usb_probe,.disconnect = hfc_usb_disconnect,
 };
-
-static void __exit hfc_usb_exit(void)
+static void __exit
+hfc_usb_exit(void)
 {
-#ifdef VERBOSE_USB_DEBUG
-	printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n");
+#ifdef CONFIG_HISAX_DEBUG
+	DBG(USB_DBG, "HFC-S USB: calling \"hfc_usb_exit\" ...");
 #endif
 	usb_deregister(&hfc_drv);	/* release our driver */
-	printk(KERN_INFO "HFC-USB module removed\n");
+	printk(KERN_INFO "HFC-S USB: module removed\n");
 }
 
-static int __init hfc_usb_init(void)
+static int __init
+hfc_usb_init(void)
 {
-	printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision);
-
-	if(usb_register(&hfc_drv))
-	{
-		printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n");
-		return(-1);		   /* unable to register */
+#ifndef CONFIG_HISAX_DEBUG
+	unsigned int debug = -1;
+#endif
+	char revstr[30], datestr[30], dummy[30];
+	sscanf(hfcusb_revision,
+	       "%s %s $ %s %s %s $ ", dummy, revstr,
+	       dummy, datestr, dummy);
+	printk(KERN_INFO
+	       "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n",
+	       revstr, datestr, debug);
+	if (usb_register(&hfc_drv)) {
+		printk(KERN_INFO
+		       "HFC-S USB: Unable to register HFC-S USB module at usb stack\n");
+		return (-1);	/* unable to register */
 	}
-	return(0);
+	return (0);
 }
 
 module_init(hfc_usb_init);
 module_exit(hfc_usb_exit);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
new file mode 100644
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -0,0 +1,228 @@
+/*
+* hfc_usb.h
+*
+* $Id: hfc_usb.h,v 4.1 2005/01/26 17:25:53 martinb1 Exp $
+*/
+
+#ifndef __HFC_USB_H__
+#define __HFC_USB_H__
+
+#define DRIVER_AUTHOR   "Peter Sprenger (sprenger@moving-byters.de)"
+#define DRIVER_DESC     "HFC-S USB based HiSAX ISDN driver"
+
+#define VERBOSE_USB_DEBUG
+
+#define TRUE  1
+#define FALSE 0
+
+
+/***********/
+/* defines */
+/***********/
+#define HFC_CTRL_TIMEOUT 20	/* 5ms timeout writing/reading regs */
+#define HFC_TIMER_T3 8000	/* timeout for l1 activation timer */
+#define HFC_TIMER_T4 500	/* time for state change interval */
+
+#define HFCUSB_L1_STATECHANGE 0	/* L1 state changed */
+#define HFCUSB_L1_DRX 1		/* D-frame received */
+#define HFCUSB_L1_ERX 2		/* E-frame received */
+#define HFCUSB_L1_DTX 4		/* D-frames completed */
+
+#define MAX_BCH_SIZE 2048	/* allowed B-channel packet size */
+
+#define HFCUSB_RX_THRESHOLD 64	/* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD 64	/* threshold for fifo report bit tx */
+
+#define HFCUSB_CHIP_ID		0x16	/* Chip ID register index */
+#define HFCUSB_CIRM		0x00	/* cirm register index */
+#define HFCUSB_USB_SIZE		0x07	/* int length register */
+#define HFCUSB_USB_SIZE_I	0x06	/* iso length register */
+#define HFCUSB_F_CROSS		0x0b	/* bit order register */
+#define HFCUSB_CLKDEL		0x37	/* bit delay register */
+#define HFCUSB_CON_HDLC		0xfa	/* channel connect register */
+#define HFCUSB_HDLC_PAR		0xfb
+#define HFCUSB_SCTRL		0x31	/* S-bus control register (tx) */
+#define HFCUSB_SCTRL_E		0x32	/* same for E and special funcs */
+#define HFCUSB_SCTRL_R		0x33	/* S-bus control register (rx) */
+#define HFCUSB_F_THRES		0x0c	/* threshold register */
+#define HFCUSB_FIFO		0x0f	/* fifo select register */
+#define HFCUSB_F_USAGE		0x1a	/* fifo usage register */
+#define HFCUSB_MST_MODE0	0x14
+#define HFCUSB_MST_MODE1	0x15
+#define HFCUSB_P_DATA		0x1f
+#define HFCUSB_INC_RES_F	0x0e
+#define HFCUSB_STATES		0x30
+
+#define HFCUSB_CHIPID		0x40	/* ID value of HFC-S USB */
+
+/******************/
+/* fifo registers */
+/******************/
+#define HFCUSB_NUM_FIFOS	8	/* maximum number of fifos */
+#define HFCUSB_B1_TX		0	/* index for B1 transmit bulk/int */
+#define HFCUSB_B1_RX		1	/* index for B1 receive bulk/int */
+#define HFCUSB_B2_TX		2
+#define HFCUSB_B2_RX		3
+#define HFCUSB_D_TX		4
+#define HFCUSB_D_RX		5
+#define HFCUSB_PCM_TX		6
+#define HFCUSB_PCM_RX		7
+
+/*
+* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
+* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+*/
+#define USB_INT		0
+#define USB_BULK	1
+#define USB_ISOC	2
+
+#define ISOC_PACKETS_D	8
+#define ISOC_PACKETS_B	8
+#define ISO_BUFFER_SIZE	128
+
+// ISO send definitions
+#define SINK_MAX	68
+#define SINK_MIN	48
+#define SINK_DMIN	12
+#define SINK_DMAX	18
+#define BITLINE_INF	(-64*8)
+
+
+/**********/
+/* macros */
+/**********/
+#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
+#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
+
+
+/*******************/
+/* Debugging Flags */
+/*******************/
+#define USB_DBG   1
+#define ISDN_DBG  2
+
+
+/* *********************/
+/* USB related defines */
+/***********************/
+#define HFC_CTRL_BUFSIZE 32
+
+
+
+/*************************************************/
+/* entry and size of output/input control buffer */
+/*************************************************/
+typedef struct {
+	__u8 hfc_reg;		/* register number */
+	__u8 reg_val;		/* value to be written (or read) */
+	int action;		/* data for action handler */
+} ctrl_buft;
+
+
+/********************/
+/* URB error codes: */
+/********************/
+/* Used to represent a list of values and their respective symbolic names */
+struct hfcusb_symbolic_list {
+	const int num;
+	const char *name;
+};
+
+static struct hfcusb_symbolic_list urb_errlist[] = {
+	{-ENOMEM, "No memory for allocation of internal structures"},
+	{-ENOSPC, "The host controller's bandwidth is already consumed"},
+	{-ENOENT, "URB was canceled by unlink_urb"},
+	{-EXDEV, "ISO transfer only partially completed"},
+	{-EAGAIN, "Too match scheduled for the future"},
+	{-ENXIO, "URB already queued"},
+	{-EFBIG, "Too much ISO frames requested"},
+	{-ENOSR, "Buffer error (overrun)"},
+	{-EPIPE, "Specified endpoint is stalled (device not responding)"},
+	{-EOVERFLOW, "Babble (bad cable?)"},
+	{-EPROTO, "Bit-stuff error (bad cable?)"},
+	{-EILSEQ, "CRC/Timeout"},
+	{-ETIMEDOUT, "NAK (device does not respond)"},
+	{-ESHUTDOWN, "Device unplugged"},
+	{-1, NULL}
+};
+
+
+/*****************************************************/
+/* device dependant information to support different */
+/* ISDN Ta's using the HFC-S USB chip                */
+/*****************************************************/
+
+/* USB descriptor need to contain one of the following EndPoint combination: */
+#define CNF_4INT3ISO	1	// 4 INT IN, 3 ISO OUT
+#define CNF_3INT3ISO	2	// 3 INT IN, 3 ISO OUT
+#define CNF_4ISO3ISO	3	// 4 ISO IN, 3 ISO OUT
+#define CNF_3ISO3ISO	4	// 3 ISO IN, 3 ISO OUT
+
+#define EP_NUL 1		// Endpoint at this position not allowed
+#define EP_NOP 2		// all type of endpoints allowed at this position
+#define EP_ISO 3		// Isochron endpoint mandatory at this position
+#define EP_BLK 4		// Bulk endpoint mandatory at this position
+#define EP_INT 5		// Interrupt endpoint mandatory at this position
+
+/* this array represents all endpoints possible in the HCF-USB the last
+* 3 entries are the configuration number, the minimum interval for
+* Interrupt endpoints & boolean if E-channel logging possible
+*/
+int validconf[][19] = {
+	// INT in, ISO out config
+	{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
+	 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+	 CNF_4INT3ISO, 2, 1},
+	{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
+	 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+	 CNF_3INT3ISO, 2, 0},
+	// ISO in, ISO out config
+	{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
+	 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
+	 CNF_4ISO3ISO, 2, 1},
+	{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
+	 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
+	 CNF_3ISO3ISO, 2, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}	// EOL element
+};
+
+// string description of chosen config
+char *conf_str[] = {
+	"4 Interrupt IN + 3 Isochron OUT",
+	"3 Interrupt IN + 3 Isochron OUT",
+	"4 Isochron IN + 3 Isochron OUT",
+	"3 Isochron IN + 3 Isochron OUT"
+};
+
+
+typedef struct {
+	int vendor;		// vendor id
+	int prod_id;		// product id
+	char *vend_name;	// vendor string
+	__u8 led_scheme;	// led display scheme
+	signed short led_bits[8];	// array of 8 possible LED bitmask settings
+} vendor_data;
+
+#define LED_OFF      0		// no LED support
+#define LED_SCHEME1  1		// LED standard scheme
+#define LED_SCHEME2  2		// not used yet...
+
+#define LED_POWER_ON	1
+#define LED_POWER_OFF	2
+#define LED_S0_ON	3
+#define LED_S0_OFF	4
+#define LED_B1_ON	5
+#define LED_B1_OFF	6
+#define LED_B1_DATA	7
+#define LED_B2_ON	8
+#define LED_B2_OFF	9
+#define LED_B2_DATA	10
+
+#define LED_NORMAL   0		// LEDs are normal
+#define LED_INVERTED 1		// LEDs are inverted
+
+/* time in ms to perform a Flashing LED when B-Channel has traffic */
+#define LED_TIME      250
+
+
+#endif				// __HFC_USB_H__
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -902,7 +902,7 @@ static int __devinit fcpci_probe(struct 
 	adapter->irq = pdev->irq;
 
 	printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
-	       (char *) ent->driver_data, pdev->slot_name);
+	       (char *) ent->driver_data, pci_name(pdev));
 
 	retval = fcpcipnp_setup(adapter);
 	if (retval)
@@ -1010,12 +1010,6 @@ static int __init hisax_fcpcipnp_init(vo
 #endif
 	return 0;
 
-#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
- out_unregister_isapnp:
-#ifdef __ISAPNP__
-	pnp_unregister_driver(&fcpnp_driver);
-#endif
-#endif
  out_unregister_pci:
 	pci_unregister_driver(&fcpci_driver);
  out:
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -516,7 +516,7 @@ Sedl_card_msg(struct IsdnCardState *cs, 
 static struct pci_dev *dev_sedl __devinitdata = NULL;
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id sedl_ids[] __initdata = {
+static struct isapnp_device_id sedl_ids[] __devinitdata = {
 	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
 	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), 
 	  (unsigned long) "Speed win" },
@@ -526,7 +526,7 @@ static struct isapnp_device_id sedl_ids[
 	{ 0, }
 };
 
-static struct isapnp_device_id *ipid __initdata = &sedl_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -254,7 +254,7 @@ Teles_card_msg(struct IsdnCardState *cs,
 
 #ifdef __ISAPNP__
 
-static struct isapnp_device_id teles_ids[] __initdata = {
+static struct isapnp_device_id teles_ids[] __devinitdata = {
 	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
 	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
 	  (unsigned long) "Teles 16.3 PnP" },
@@ -267,7 +267,7 @@ static struct isapnp_device_id teles_ids
 	{ 0, }
 };
 
-static struct isapnp_device_id *ipid __initdata = &teles_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &teles_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -49,7 +49,7 @@ static char *W6692Ver[] __initdata =
 {"W6692 V00", "W6692 V01", "W6692 V10",
  "W6692 V11"};
 
-static void
+static void __init
 W6692Version(struct IsdnCardState *cs, char *s)
 {
 	int val;
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -135,8 +135,6 @@ source "drivers/isdn/sc/Kconfig"
 
 source "drivers/isdn/act2000/Kconfig"
 
-source "drivers/isdn/tpam/Kconfig"
-
 source "drivers/isdn/hysdn/Kconfig"
 
 endmenu
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1180,9 +1180,9 @@ isdn_ioctl(struct inode *inode, struct f
 				if (arg) {
 					ulong __user *p = argp;
 					int i;
-					if ((ret = verify_area(VERIFY_WRITE, p,
-							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-						return ret;
+					if (!access_ok(VERIFY_WRITE, p,
+							sizeof(ulong) * ISDN_MAX_CHANNELS * 2))
+						return -EFAULT;
 					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 						put_user(dev->ibytes[i], p++);
 						put_user(dev->obytes[i], p++);
@@ -1420,10 +1420,10 @@ isdn_ioctl(struct inode *inode, struct f
 					char __user *p = argp;
 					int i;
 
-					if ((ret = verify_area(VERIFY_WRITE, argp,
+					if (!access_ok(VERIFY_WRITE, argp,
 					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
+						   * ISDN_MAX_CHANNELS))
+						return -EFAULT;
 
 					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
@@ -1447,10 +1447,10 @@ isdn_ioctl(struct inode *inode, struct f
 					char __user *p = argp;
 					int i;
 
-					if ((ret = verify_area(VERIFY_READ, argp,
+					if (!access_ok(VERIFY_READ, argp,
 					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
+						   * ISDN_MAX_CHANNELS))
+						return -EFAULT;
 
 					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 						if (copy_from_user(dev->mdm.info[i].emu.profile, p,
@@ -1496,8 +1496,8 @@ isdn_ioctl(struct inode *inode, struct f
 							int j = 0;
 
 							while (1) {
-								if ((ret = verify_area(VERIFY_READ, p, 1)))
-									return ret;
+								if (!access_ok(VERIFY_READ, p, 1))
+									return -EFAULT;
 								get_user(bname[j], p++);
 								switch (bname[j]) {
 									case '\0':
@@ -1563,9 +1563,9 @@ isdn_ioctl(struct inode *inode, struct f
 						drvidx = 0;
 					if (drvidx == -1)
 						return -ENODEV;
-					if ((ret = verify_area(VERIFY_WRITE, argp,
-					     sizeof(isdn_ioctl_struct))))
-						return ret;
+					if (!access_ok(VERIFY_WRITE, argp,
+					     sizeof(isdn_ioctl_struct)))
+						return -EFAULT;
 					c.driver = drvidx;
 					c.command = ISDN_CMD_IOCTL;
 					c.arg = cmd;
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1786,6 +1786,7 @@ isdn_net_receive(struct net_device *ndev
 		lp->stats.rx_bytes += skb->len;
 	}
 	skb->dev = ndev;
+	skb->input_dev = ndev;
 	skb->pkt_type = PACKET_HOST;
 	skb->mac.raw = skb->data;
 #ifdef ISDN_DEBUG_NET_DUMP
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -764,7 +764,6 @@ isdn_ppp_read(int min, struct file *file
 {
 	struct ippp_struct *is;
 	struct ippp_buf_queue *b;
-	int r;
 	u_long flags;
 	u_char *save_buf;
 
@@ -773,8 +772,8 @@ isdn_ppp_read(int min, struct file *file
 	if (!(is->state & IPPP_OPEN))
 		return 0;
 
-	if ((r = verify_area(VERIFY_WRITE, buf, count)))
-		return r;
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
 
 	spin_lock_irqsave(&is->buflock, flags);
 	b = is->first->next;
@@ -985,7 +984,7 @@ void isdn_ppp_receive(isdn_net_dev * net
 		BUG(); // we're called with the master device always
 
 	slot = lp->ppp_slot;
-	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
 			lp->ppp_slot);
 		kfree_skb(skb);
@@ -1040,7 +1039,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_
 	int slot;
 
 	slot = lp->ppp_slot;
-	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
 			lp->ppp_slot);
 		goto drop_packet;
@@ -1152,7 +1151,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_
 	{
 		u_int16_t *p = (u_int16_t *) skb->data;
 
-		*p = 0;	/* indicate inbound in DLT_LINUX_SLL */
+		*p = 0;	/* indicate inbound */
 	}
 
 	if (is->pass_filter
@@ -1178,6 +1177,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_
 		mlp->huptimer = 0;
 #endif /* CONFIG_IPPP_FILTER */
 	skb->dev = dev;
+	skb->input_dev = dev;
 	skb->mac.raw = skb->data;
 	netif_rx(skb);
 	/* net_dev->local->stats.rx_packets++; done in isdn_net.c */
@@ -1234,7 +1234,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struc
 	nd = mlp->netdev;       /* get master lp */
 
 	slot = mlp->ppp_slot;
-	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
 			mlp->ppp_slot);
 		kfree_skb(skb);
@@ -1293,12 +1293,12 @@ isdn_ppp_xmit(struct sk_buff *skb, struc
 	/* check if we should pass this packet
 	 * the filter instructions are constructed assuming
 	 * a four-byte PPP header on each packet */
-	skb_push(skb, 4);
+	*skb_push(skb, 4) = 1; /* indicate outbound */
 
 	{
 		u_int16_t *p = (u_int16_t *) skb->data;
 
-		*p++ = htons(4); /* indicate outbound in DLT_LINUX_SLL */
+		p++;
 		*p   = htons(proto);
 	}
 
@@ -1491,12 +1491,12 @@ int isdn_ppp_autodial_filter(struct sk_b
 	 * temporarily remove part of the fake header stuck on
 	 * earlier.
 	 */
-	skb_pull(skb, IPPP_MAX_HEADER - 4);
+	*skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
 
 	{
 		u_int16_t *p = (u_int16_t *) skb->data;
 
-		*p++ = htons(4);	/* indicate outbound in DLT_LINUX_SLL */
+		p++;
 		*p   = htons(proto);
 	}
 	
@@ -1578,7 +1578,7 @@ static int isdn_ppp_mp_init( isdn_net_lo
 		lp->next = lp->last = lp;	/* nobody else in a queue */
 		lp->netdev->pb->frags = NULL;
 		lp->netdev->pb->frames = 0;
-		lp->netdev->pb->seq = LONG_MAX;
+		lp->netdev->pb->seq = UINT_MAX;
 	}
 	lp->netdev->pb->ref_ct++;
 	
@@ -1882,7 +1882,7 @@ void isdn_ppp_mp_reassembly( isdn_net_de
 	struct sk_buff * skb;
 	unsigned int tot_len;
 
-	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 "%s: lp->ppp_slot(%d) out of range\n",
 			__FUNCTION__, lp->ppp_slot);
 		return;
@@ -1995,12 +1995,9 @@ isdn_ppp_dev_ioctl_stats(int slot, struc
 	struct ppp_stats __user *res = ifr->ifr_data;
 	struct ppp_stats t;
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
-	int err;
-
-	err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));
 
-	if (err)
-		return err;
+	if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
+		return -EFAULT;
 
 	/* build a temporary stat struct and copy it to user space */
 
@@ -2834,7 +2831,7 @@ static void isdn_ppp_send_ccp(isdn_net_d
 
 	if(!skb || skb->len < 3)
 		return;
-	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
 			__FUNCTION__, slot);
 		return;
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -908,14 +908,13 @@ icn_loadproto(u_char __user * buffer, ic
 	uint left = ICN_CODE_STAGE2;
 	uint cnt;
 	int timer;
-	int ret;
 	unsigned long flags;
 
 #ifdef BOOT_DEBUG
 	printk(KERN_DEBUG "icn_loadproto called\n");
 #endif
-	if ((ret = verify_area(VERIFY_READ, buffer, ICN_CODE_STAGE2)))
-		return ret;
+	if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
+		return -EFAULT;
 	timer = 0;
 	spin_lock_irqsave(&dev.devlock, flags);
 	if (card->secondhalf) {
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1146,8 +1146,8 @@ isdnloop_command(isdn_ctrl * c, isdnloop
 				case ISDNLOOP_IOCTL_DEBUGVAR:
 					return (ulong) card;
 				case ISDNLOOP_IOCTL_STARTUP:
-					if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef))))
-						return i;
+					if (!access_ok(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef)))
+						return -EFAULT;
 					return (isdnloop_start(card, (isdnloop_sdef *) a));
 					break;
 				case ISDNLOOP_IOCTL_ADDCARD:
diff --git a/drivers/isdn/tpam/Kconfig b/drivers/isdn/tpam/Kconfig
deleted file mode 100644
--- a/drivers/isdn/tpam/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Config.in for Auvertech TurboPAM ISDN driver
-#
-config ISDN_DRV_TPAM
-	tristate "Auvertech TurboPAM support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && ISDN_I4L && PCI
-	select CRC_CCITT
-	help
-	  This enables support for the Auvertech TurboPAM ISDN-card.
-	  For running this card, additional firmware is necessary, which has
-	  to be downloaded into the card using a utility which is distributed
-	  separately from the Auvertech's web site: <http://www.auvertech.fr/>.
-
-	  Please redirect all support questions to <support@auvertech.fr>.
-
diff --git a/drivers/isdn/tpam/Makefile b/drivers/isdn/tpam/Makefile
deleted file mode 100644
--- a/drivers/isdn/tpam/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Makefile for the TurboPAM ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_TPAM)	+= tpam.o
-
-# Multipart objects.
-
-tpam-y				:= tpam_main.o tpam_nco.o tpam_memory.o \
-				   tpam_commands.o tpam_queues.o tpam_hdlc.o \
-				   tpam_crcpc.o
diff --git a/drivers/isdn/tpam/tpam.h b/drivers/isdn/tpam/tpam.h
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/* $Id: tpam.h,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#ifndef _TPAM_PRIV_H_
-#define _TPAM_PRIV_H_
-
-//#define DEBUG /* uncomment if you want debugging output */
-#include <linux/kernel.h>
-#include <linux/isdnif.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-/* Maximum number of channels for this board */
-#define TPAM_NBCHANNEL		30
-/* Maximum size of data */
-#define TPAM_MAXBUFSIZE		2032
-/* Size of a page of board memory */
-#define TPAM_PAGE_SIZE		0x003ffffc	/* 4 MB */
-/* Magic number present if the board was successfully started */
-#define TPAM_MAGICNUMBER	0x2a343242
-
-/* Registers in the PCI BAR0 */
-#define TPAM_PAGE_REGISTER	0x00400000	/* Select page */
-#define TPAM_DSPINT_REGISTER	0x00400004	/* Interrupt board */
-#define TPAM_RESETPAM_REGISTER	0x00400008	/* Reset board */
-#define TPAM_HINTACK_REGISTER	0x0040000c	/* Ack interrupt */
-#define TPAM_HPIC_REGISTER	0x00400014	/* Board ready */
-
-/* Registers in the board memory */
-#define TPAM_MAGICNUMBER_REGISTER	0x80008000 /* Magic number */
-#define TPAM_EXID_REGISTER		0x80008004 /* EXID - not used */
-#define TPAM_UPLOADPTR_REGISTER		0x80008008 /* Upload data ptr */
-#define TPAM_DOWNLOADPTR_REGISTER	0x8000800c /* Download data ptr */
-#define TPAM_ACKUPLOAD_REGISTER		0x80008010 /* Ack upload */
-#define TPAM_ACKDOWNLOAD_REGISTER	0x80008014 /* Ack download */
-#define TPAM_INTERRUPTACK_REGISTER	0x80008018 /* Ack interrupt */
-
-/* Reserved areas in the board memory */
-#define	TPAM_RESERVEDAREA1_START	0x00000000
-#define TPAM_RESERVEDAREA1_END		0x003FFFFF
-#define TPAM_RESERVEDAREA2_START	0x01C00000
-#define TPAM_RESERVEDAREA2_END		0x01FFFFFF
-#define TPAM_RESERVEDAREA3_START	0x04000000
-#define TPAM_RESERVEDAREA3_END		0x7FFFFFFF
-#define TPAM_RESERVEDAREA4_START	0x80010000
-#define TPAM_RESERVEDAREA4_END		0xFFFFFFFF
-
-/* NCO ID invalid */
-#define TPAM_NCOID_INVALID	0xffff
-/* channel number invalid */
-#define TPAM_CHANNEL_INVALID	0xffff
-
-/* Channel structure */
-typedef struct tpam_channel {
-	int num;			/* channel number */
-	struct tpam_card *card;		/* channel's card */
-	u32 ncoid;			/* ncoid */
-	u8  hdlc;			/* hdlc mode (set by user level) */
-	u8  realhdlc;			/* hdlc mode (negociated with peer) */
-	u32 hdlcshift;			/* hdlc shift */
-	u8  readytoreceive;		/* channel ready to receive data */
-	struct sk_buff_head sendq;	/* Send queue */
-} tpam_channel;
-
-/* Card structure */
-typedef struct tpam_card {
-	struct tpam_card *next;		/* next card in list */
-	unsigned int irq;		/* IRQ used by this board */
-	void __iomem *bar0;		/* ioremapped bar0 */
-	int id;				/* id of the board */
-	isdn_if interface;		/* isdn link-level pointer */
-	int channels_used;		/* number of channels actually used */
-	int channels_tested;		/* number of channels being tested */
-	u8 loopmode;			/* board in looptest mode */
-	tpam_channel channels[TPAM_NBCHANNEL];/* channels tab */
-	int running;			/* card is running */
-	int busy;			/* waiting for ack from card */
-	int roundrobin;			/* round robin between channels */
-	struct sk_buff_head sendq;	/* send queue */
-	struct sk_buff_head recvq;	/* receive queue */
-	struct work_struct send_tq;	/* send task queue */
-	struct work_struct recv_tq;	/* receive task queue */
-	spinlock_t lock;		/* lock for the card */
-} tpam_card;
-
-/* Timeout waiting for signature to become available */
-#define SIGNATURE_TIMEOUT	(5*HZ)
-/* Timeout waiting for receiving all the ACreateNCOCnf */
-#define NCOCREATE_TIMEOUT	(30*HZ)
-
-/* Maximum size of the TLV block */
-#define MPB_MAXIMUMBLOCKTLVSIZE	 128
-/* Maximum size of the data block */
-#define MPB_MAXIMUMDATASIZE	4904
-/* Maximum size of a phone number */
-#define PHONE_MAXIMUMSIZE	  32
-
-/* Header for a sk_buff structure */
-typedef struct skb_header {
-	u16 size;		/* size of pci_mpb block + size of tlv block */
-	u16 data_size;		/* size of the data block */
-	u16 ack;		/* packet needs to send ack upon send */
-	u16 ack_size;		/* size of data to be acknowledged upon send */
-} skb_header;
-
-/* PCI message header structure */
-typedef struct pci_mpb {
-	u16 exID;			/* exID - not used */
-	u16 flags;			/* flags - not used */
-	u32 errorCode;			/* errorCode - not used */
-	u16 messageID;			/* message ID - one of ID_XXX */
-	u16 maximumBlockTLVSize;	/* MPB_MAXIMUMBLOCKTLVSIZE */
-	u16 actualBlockTLVSize;		/* size of the tlv block */
-	u16 maximumDataSize;		/* MPB_MAXIMUMDATASIZE */
-	u16 actualDataSize;		/* size of the data block */
-	u16 dummy;			/* padding */
-} pci_mpb;
-
-/* Types of PCI messages */
-#define ID_ACreateNCOReq	101
-#define ID_ACreateNCOCnf	102
-#define ID_ADestroyNCOReq	103
-#define ID_ADestroyNCOCnf	104
-#define ID_CConnectReq		203
-#define ID_CConnectInd		204
-#define ID_CConnectRsp		205
-#define ID_CConnectCnf		206
-#define ID_CDisconnectReq	207
-#define ID_CDisconnectInd	208
-#define ID_CDisconnectRsp	209
-#define ID_CDisconnectCnf	210
-#define ID_U3DataReq		307
-#define ID_U3DataInd		308
-#define ID_U3ReadyToReceiveInd	318
-
-/* Parameters for the PCI message TLV block */
-#define PAR_BearerCap		3
-#define PAR_CalledNumber	7
-#define PAR_CallingNumber	11
-#define PAR_CauseToPUF		15
-#define PAR_Cdirection		16
-#define PAR_CompletionStatus	19
-#define PAR_Facility		30
-#define PAR_HLC			34
-#define PAR_NCOID		49
-#define PAR_NCOType		50
-#define PAR_ReadyFlag		55
-#define PAR_U3Protocol		62
-#define PAR_Udirection		64
-
-/* Delayed statcallb structure */
-typedef struct tpam_statcallb_data {
-	tpam_card *card;		/* card issuing the statcallb */
-	struct timer_list *timer;	/* timer launching the statcallb */
-	isdn_ctrl ctrl;			/* isdn command */
-} tpam_statcallb_data;
-
-/* Function prototypes from tpam_main.c */
-extern tpam_card *tpam_findcard(int);
-extern u32 tpam_findchannel(tpam_card *, u32);
-
-/* Function prototypes from tpam_memory.c */
-extern void copy_to_pam_dword(tpam_card *, u32, u32);
-extern void copy_to_pam(tpam_card *, u32, const void *, u32);
-extern u32 copy_from_pam_dword(tpam_card *, u32);
-extern void copy_from_pam(tpam_card *, void *, u32, u32);
-extern int copy_from_pam_to_user(tpam_card *, void __user *, u32, u32);
-extern int copy_from_user_to_pam(tpam_card *, u32, const void __user *, u32);
-extern int tpam_verify_area(u32, u32);
-
-/* Function prototypes from tpam_nco.c */
-extern struct sk_buff *build_ACreateNCOReq(const u8 *);
-extern struct sk_buff *build_ADestroyNCOReq(u32);
-extern struct sk_buff *build_CConnectReq(u32, const u8 *, u8);
-extern struct sk_buff *build_CConnectRsp(u32);
-extern struct sk_buff *build_CDisconnectReq(u32);
-extern struct sk_buff *build_CDisconnectRsp(u32);
-extern struct sk_buff *build_U3DataReq(u32, void *, u16, u16, u16);
-extern int parse_ACreateNCOCnf(struct sk_buff *, u8 *, u32 *);
-extern int parse_ADestroyNCOCnf(struct sk_buff *, u8 *, u32 *);
-extern int parse_CConnectCnf(struct sk_buff *, u32 *);
-extern int parse_CConnectInd(struct sk_buff *, u32 *, u8 *, u8 *, 
-			     u8 *, u8 *, u8 *);
-extern int parse_CDisconnectCnf(struct sk_buff *, u32 *, u32 *);
-extern int parse_CDisconnectInd(struct sk_buff *, u32 *, u32 *);
-extern int parse_U3ReadyToReceiveInd(struct sk_buff *, u32 *, u8 *);
-extern int parse_U3DataInd(struct sk_buff *, u32 *, u8 **, u16 *);
-
-/* Function prototypes from tpam_queues.c */
-extern void tpam_enqueue(tpam_card *, struct sk_buff *);
-extern void tpam_enqueue_data(tpam_channel *, struct sk_buff *);
-extern irqreturn_t tpam_irq(int, void *, struct pt_regs *);
-extern void tpam_recv_tq(tpam_card *);
-extern void tpam_send_tq(tpam_card *);
-
-/* Function prototypes from tpam_commands.c */
-extern int tpam_command(isdn_ctrl *);
-extern int tpam_writebuf_skb(int, int, int, struct sk_buff *);
-extern void tpam_recv_ACreateNCOCnf(tpam_card *, struct sk_buff *);
-extern void tpam_recv_ADestroyNCOCnf(tpam_card *, struct sk_buff *);
-extern void tpam_recv_CConnectCnf(tpam_card *, struct sk_buff *);
-extern void tpam_recv_CConnectInd(tpam_card *, struct sk_buff *);
-extern void tpam_recv_CDisconnectInd(tpam_card *, struct sk_buff *);
-extern void tpam_recv_CDisconnectCnf(tpam_card *, struct sk_buff *);
-extern void tpam_recv_U3DataInd(tpam_card *, struct sk_buff *);
-extern void tpam_recv_U3ReadyToReceiveInd(tpam_card *, struct sk_buff *);
-
-/* Function prototypes from tpam_hdlc.c */
-extern u32 tpam_hdlc_encode(u8 *, u8 *, u32 *, u32);
-extern u32 tpam_hdlc_decode(u8 *, u8 *, u32);
-
-/* Function prototypes from tpam_crcpc.c */
-extern void init_CRC(void);
-extern void hdlc_encode_modem(u8 *, u32, u8 *, u32 *);
-extern void hdlc_no_accm_encode(u8 *, u32, u8 *, u32 *);
-extern u32 hdlc_no_accm_decode(u8 *, u32);
-
-#endif /* _TPAM_H_ */
diff --git a/drivers/isdn/tpam/tpam_commands.c b/drivers/isdn/tpam/tpam_commands.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_commands.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/* $Id: tpam_commands.c,v 1.1.2.4 2001/11/06 20:58:30 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include <linux/isdn/tpam.h>
-#include "tpam.h"
-
-/* Local functions prototypes */
-static int tpam_command_ioctl_dspload(tpam_card *, unsigned long);
-static int tpam_command_ioctl_dspsave(tpam_card *, unsigned long);
-static int tpam_command_ioctl_dsprun(tpam_card *);
-static int tpam_command_ioctl_loopmode(tpam_card *, u8);
-static int tpam_command_dial(tpam_card *, u32, u8 *);
-static int tpam_command_setl2(tpam_card *, u32, u8);
-static int tpam_command_acceptd(tpam_card *, u32);
-static int tpam_command_acceptb(tpam_card *, u32);
-static int tpam_command_hangup(tpam_card *, u32);
-static int tpam_command_proceed(tpam_card *, u32);
-static void tpam_statcallb_run(unsigned long);
-static void tpam_statcallb(tpam_card *, isdn_ctrl);
-
-/*
- * Function called when the ISDN link level send a command to the driver.
- *
- * 	c: ISDN command.
- *
- * Return: 0 if OK, <0 on errors.
- */
-int tpam_command(isdn_ctrl *c) {
-	tpam_card *card;
-	unsigned long argp;
-
-	pr_debug("TurboPAM(tpam_command) card=%d, command=%d\n",
-		c->driver, c->command);	
-
-	/* search for the board */
-	if (!(card = tpam_findcard(c->driver))) {
-		printk(KERN_ERR "TurboPAM(tpam_command): invalid driverId %d\n",
-		       c->driver);	
-		return -ENODEV;
-	}
-
-	/* dispatch the command */
-	switch (c->command) {
-		case ISDN_CMD_IOCTL:
-			argp = c->parm.userdata;
-			switch (c->arg) {
-				case TPAM_CMD_DSPLOAD:
-					return tpam_command_ioctl_dspload(card,
-									  argp);
-				case TPAM_CMD_DSPSAVE:
-					return tpam_command_ioctl_dspsave(card,
-									  argp);
-				case TPAM_CMD_DSPRUN:
-					return tpam_command_ioctl_dsprun(card);
-				case TPAM_CMD_LOOPMODEON:
-					return tpam_command_ioctl_loopmode(card,
-									   1);
-				case TPAM_CMD_LOOPMODEOFF:
-					return tpam_command_ioctl_loopmode(card,
-									   0);
-				default:
-					pr_debug("TurboPAM(tpam_command): "
-						"invalid tpam ioctl %ld\n", 
-						c->arg);	
-					return -EINVAL;
-			}
-		case ISDN_CMD_DIAL:
-			return tpam_command_dial(card, c->arg, 
-						 c->parm.setup.phone);
-		case ISDN_CMD_ACCEPTD:
-			return tpam_command_acceptd(card, c->arg);
-		case ISDN_CMD_ACCEPTB:
-			return tpam_command_acceptb(card, c->arg);
-		case ISDN_CMD_HANGUP:
-			return tpam_command_hangup(card, c->arg);
-		case ISDN_CMD_SETL2:
-			return tpam_command_setl2(card, c->arg & 0xff, 
-						  c->arg >> 8);
-		case ISDN_CMD_PROCEED:
-			return tpam_command_proceed(card, c->arg);
-		default:
-			pr_debug("TurboPAM(tpam_command): "
-				"unknown or unused isdn ioctl %d\n", 
-				c->command);	
-			return -EINVAL;
-	}
-
-	/* not reached */
-	return -EINVAL;
-}
-
-/*
- * Load some data into the board's memory.
- *
- * 	card: the board
- * 	arg: IOCTL argument containing the user space address of 
- * 		the tpam_dsp_ioctl structure describing the IOCTL.
- *
- * Return: 0 if OK, <0 on errors.
- */
-static int tpam_command_ioctl_dspload(tpam_card *card, unsigned long arg) {
-	tpam_dsp_ioctl tdl;
-
-	pr_debug("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id);
-
-	/* get the IOCTL parameter from userspace */
-	if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl)))
-		return -EFAULT;
-
-	/* if the board's firmware was started, protect against writes
-	 * to unallowed memory areas. If the board's firmware wasn't started,
-	 * all is allowed. */
-	if (card->running && tpam_verify_area(tdl.address, tdl.data_len)) 
-		return -EPERM;
-
-	/* write the data in the board's memory */
-	return copy_from_user_to_pam(card, tdl.address, 
-				     (void __user *)arg + sizeof(tpam_dsp_ioctl), 
-				     tdl.data_len);
-}
-
-/*
- * Extract some data from the board's memory.
- *
- * 	card: the board
- * 	arg: IOCTL argument containing the user space address of 
- * 		the tpam_dsp_ioctl structure describing the IOCTL.
- *
- * Return: 0 if OK, <0 on errors.
- */
-static int tpam_command_ioctl_dspsave(tpam_card *card, unsigned long arg) {
-	tpam_dsp_ioctl tdl;
-
-	pr_debug("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id);
-
-	/* get the IOCTL parameter from userspace */
-	if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl)))
-		return -EFAULT;
-
-	/* protect against read from unallowed memory areas */
-	if (tpam_verify_area(tdl.address, tdl.data_len)) 
-		return -EPERM;
-
-	/* read the data from the board's memory */
-	return copy_from_pam_to_user(card, (void __user *)arg + sizeof(tpam_dsp_ioctl),
-				     tdl.address, tdl.data_len);
-}
-
-/*
- * Launch the board's firmware. This function must be called after the 
- * firmware was loaded into the board's memory using TPAM_CMD_DSPLOAD 
- * IOCTL commands. After launching the firmware, this function creates
- * the NCOs and waits for their creation.
- *
- * 	card: the board
- *
- * Return: 0 if OK, <0 on errors.
- */
-static int tpam_command_ioctl_dsprun(tpam_card *card) {
-	u32 signature = 0, i;
-	unsigned long timeout;
-	isdn_ctrl ctrl;
-	struct sk_buff *skb;
-
-	pr_debug("TurboPAM(tpam_command_ioctl_dsprun): card=%d\n", card->id);
-
-	/* board must _not_ be running */
-	if (card->running)
-		return -EBUSY;
-
-	/* reset the board */
-	spin_lock_irq(&card->lock);
-	copy_to_pam_dword(card, TPAM_MAGICNUMBER_REGISTER, 0xdeadface);
-	readl(card->bar0 + TPAM_DSPINT_REGISTER);
-	readl(card->bar0 + TPAM_HINTACK_REGISTER);
-	spin_unlock_irq(&card->lock);
-	
-	/* wait for the board signature */
-	timeout = jiffies + SIGNATURE_TIMEOUT;
-	while (time_before(jiffies, timeout)) {
-		spin_lock_irq(&card->lock);
-		signature = copy_from_pam_dword(card, 
-						TPAM_MAGICNUMBER_REGISTER);
-		spin_unlock_irq(&card->lock);
-		if (signature == TPAM_MAGICNUMBER)
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(2);
-	}
-
-	/* signature not present -> board not started */
-	if (signature != TPAM_MAGICNUMBER) {
-		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
-		       "card=%d, signature 0x%lx, expected 0x%lx\n", 
-		       card->id, (unsigned long)signature, 
-		       (unsigned long)TPAM_MAGICNUMBER);
-		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
-		       "card=%d, firmware not started\n", card->id);
-		return -EIO;
-	}
-
-	/* the firmware is started */
-	printk(KERN_INFO "TurboPAM: card=%d, firmware started\n", card->id);
-
-	/* init the CRC routines */
-	init_CRC();
-
-	/* create all the NCOs */
-	for (i = 0; i < TPAM_NBCHANNEL; ++i)
-		if ((skb = build_ACreateNCOReq("")))
-			tpam_enqueue(card, skb);
-
-	/* wait for NCO creation confirmation */
-	timeout = jiffies + NCOCREATE_TIMEOUT;
-	while (time_before(jiffies, timeout)) {
-		if (card->channels_tested == TPAM_NBCHANNEL)
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(2);
-	}
-
-	card->running = 1;
-
-	if (card->channels_tested != TPAM_NBCHANNEL)
-		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
-		       "card=%d, tried to init %d channels, "
-		       "got reply from only %d channels\n", card->id, 
-		       TPAM_NBCHANNEL, card->channels_tested);
-
-	/* if all the channels were not initialized, signal to the ISDN
-	 * link layer that fact that some channels are not usable */
-	if (card->channels_used != TPAM_NBCHANNEL)
-		for (i = card->channels_used; i < TPAM_NBCHANNEL; ++i) {
-			ctrl.driver = card->id;
-			ctrl.command = ISDN_STAT_DISCH;
-			ctrl.arg = i;
-			ctrl.parm.num[0] = 0;
-			(* card->interface.statcallb)(&ctrl);
-		}
-
-	printk(KERN_INFO "TurboPAM: card=%d, ready, %d channels available\n", 
-	       card->id, card->channels_used);
-
-	/* let's rock ! */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_RUN;
-	ctrl.arg = 0;
-	tpam_statcallb(card, ctrl);
-
-	return 0;
-}
-
-/* 
- * Set/reset the board's looptest mode.
- *
- * 	card: the board
- * 	mode: if 1, sets the board's looptest mode, if 0 resets it.
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_ioctl_loopmode(tpam_card *card, u8 mode) {
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	card->loopmode = mode;
-	return 0;
-}
-
-/*
- * Issue a dial command. This function builds and sends a CConnectReq.
- * 
- * 	card: the board
- * 	channel: the channel number
- * 	phone: the remote phone number (EAZ)
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_dial(tpam_card *card, u32 channel, u8 *phone) {
-	struct sk_buff *skb;
-	isdn_ctrl ctrl;
-
-	pr_debug("TurboPAM(tpam_command_dial): card=%d, channel=%lu, phone=%s\n",
-		card->id, (unsigned long)channel, phone);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* initialize channel parameters */
-	card->channels[channel].realhdlc = card->channels[channel].hdlc;
-	card->channels[channel].hdlcshift = 0;
-	card->channels[channel].readytoreceive = 0;
-
-	/* build and send a CConnectReq */
-	skb = build_CConnectReq(card->channels[channel].ncoid, phone, 
-				card->channels[channel].realhdlc);
-	if (!skb)
-		return -ENOMEM;
-	tpam_enqueue(card, skb);
-
-	/* making a connection in modem mode is slow and causes the ISDN
-	 * link layer to hangup the connection before even it gets a chance
-	 * to establish... All we can do is simulate a successful connection
-	 * for now, and send a DHUP later if the connection fails */
-	if (!card->channels[channel].realhdlc) {
-		ctrl.driver = card->id;
-		ctrl.command = ISDN_STAT_DCONN;
-		ctrl.arg = channel;
-		tpam_statcallb(card, ctrl);
-	}
-	
-	return 0;
-}
-
-/*
- * Set the level2 protocol (modem or HDLC).
- *
- * 	card: the board
- * 	channel: the channel number
- * 	proto: the level2 protocol (one of ISDN_PROTO_L2*)
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_setl2(tpam_card *card, u32 channel, u8 proto) {
-
-	pr_debug("TurboPAM(tpam_command_setl2): card=%d, channel=%lu, proto=%d\n",
-		card->id, (unsigned long)channel, proto);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* set the hdlc/modem mode */
-	switch (proto) {
-		case ISDN_PROTO_L2_HDLC:
-			card->channels[channel].hdlc = 1;
-			break;
-		case ISDN_PROTO_L2_MODEM:
-			card->channels[channel].hdlc = 0;
-			break;
-		default:
-			return -EINVAL;
-	}
-	return 0;
-}
-
-/*
- * Accept a D-channel connection (incoming connection). This function
- * builds and sends a CConnectRsp message and signals DCONN to the ISDN
- * link level.
- *
- * 	card: the board
- * 	channel: the channel number
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_acceptd(tpam_card *card, u32 channel) {
-	isdn_ctrl ctrl;
-	struct sk_buff *skb;
-
-	pr_debug("TurboPAM(tpam_command_acceptd): card=%d, channel=%lu\n",
-		card->id, (unsigned long)channel);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* build and send a CConnectRsp */
-	skb = build_CConnectRsp(card->channels[channel].ncoid);
-	if (!skb)
-		return -ENOMEM;
-	tpam_enqueue(card, skb);
-
-	/* issue DCONN to the ISDN link level */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_DCONN;
-	ctrl.arg = channel;
-	tpam_statcallb(card, ctrl);
-	return 0;
-}
-
-/*
- * Accepts a B-channel connection. This is not used by the driver, 
- * since the TurboPAM is an active card hiding its B-channels from
- * us. We just signal BCONN to the ISDN link layer.
- *
- * 	card: the board
- * 	channel: the channel number
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_acceptb(tpam_card *card, u32 channel) {
-	isdn_ctrl ctrl;
-
-	pr_debug("TurboPAM(tpam_command_acceptb): card=%d, channel=%lu\n",
-		card->id, (unsigned long)channel);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* issue BCONN to the ISDN link level */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_BCONN;
-	ctrl.arg = channel;
-	ctrl.parm.num[0] = '\0';
-	tpam_statcallb(card, ctrl);
-	return 0;
-}
-
-/*
- * Hang up a connection. This function builds and sends a CDisconnectReq.
- *
- * 	card: the board
- * 	channel: the channel number.
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_hangup(tpam_card *card, u32 channel) {
-	struct sk_buff *skb;
-
-	pr_debug("TurboPAM(tpam_command_hangup): card=%d, channel=%lu\n",
-		card->id, (unsigned long)channel);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* build and send a CDisconnectReq */
-	skb = build_CDisconnectReq(card->channels[channel].ncoid);
-	if (!skb)
-		return -ENOMEM;
-	tpam_enqueue(card, skb);
-	return 0;
-}
-
-/*
- * Proceed with an incoming connection. This function builds and sends a 
- * CConnectRsp.
- *
- * 	card: the board
- * 	channel: the channel number.
- *
- * Return: 0 if OK, <0 if error.
- */
-static int tpam_command_proceed(tpam_card *card, u32 channel) {
-	struct sk_buff *skb;
-
-	pr_debug("TurboPAM(tpam_command_proceed): card=%d, channel=%lu\n",
-		card->id, (unsigned long)channel);
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* build and send a CConnectRsp */
-	skb = build_CConnectRsp(card->channels[channel].ncoid);
-	if (!skb)
-		return -ENOMEM;
-	tpam_enqueue(card, skb);
-	return 0;
-}
-
-/*
- * Send data through the board. This function encodes the data depending
- * on the connection type (modem or HDLC), then builds and sends a U3DataReq.
- *
- * 	driverId: the driver id (really meaning here the board)
- * 	channel: the channel number
- * 	ack: data needs to be acknowledged upon send
- * 	skb: sk_buff containing the data
- *
- * Return: size of data send if OK, <0 if error.
- */
-int tpam_writebuf_skb(int driverId, int channel, int ack, struct sk_buff *skb) {
-	tpam_card *card;
-	int orig_size = skb->len;
-	void *finaldata;
-	u32 finallen;
-
-	pr_debug("TurboPAM(tpam_writebuf_skb): "
-		"card=%d, channel=%ld, ack=%d, data size=%d\n", 
-		driverId, (unsigned long)channel, ack, skb->len);
-
-	/* find the board based on its driver ID */
-	if (!(card = tpam_findcard(driverId))) {
-		printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
-		       "invalid driverId %d\n", driverId);	
-		return -ENODEV;
-	}
-
-	/* board must be running */
-	if (!card->running)
-		return -ENODEV;
-
-	/* allocate some temporary memory */
-	if (!(finaldata = (void *)__get_free_page(GFP_ATOMIC))) {
-		printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
-		       "get_free_page failed\n");
-		return -ENOMEM;
-	}
-
-	/* encode the data */
-	if (!card->channels[channel].realhdlc) {
-		/* modem mode */
-		hdlc_encode_modem(skb->data, skb->len, finaldata, &finallen);
-	}
-	else {
-		/* HDLC mode */
-		void *tempdata;
-		u32 templen;
-
-		if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
-			       "get_free_page failed\n");
-			free_page((unsigned long)finaldata);
-			return -ENOMEM;
-		}
-		hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen);
-		finallen = tpam_hdlc_encode(tempdata, finaldata, 
-				       &card->channels[channel].hdlcshift, 
-				       templen);
-		free_page((unsigned long)tempdata);
-	}
-
-	/* free the old sk_buff */
-	kfree_skb(skb);
-
-	/* build and send a U3DataReq */
-	skb = build_U3DataReq(card->channels[channel].ncoid, finaldata, 
-			      finallen, ack, orig_size);
-	if (!skb) {
-		free_page((unsigned long)finaldata);
-		return -ENOMEM;
-	}
-	tpam_enqueue_data(&card->channels[channel], skb);
-
-	/* free the temporary memory */
-	free_page((unsigned long)finaldata);
-	return orig_size;
-}
-
-/*
- * Treat a received ACreateNCOCnf message.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_ACreateNCOCnf(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u8 status;
-	u32 channel;
-
-	pr_debug("TurboPAM(tpam_recv_ACreateNCOCnf): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_ACreateNCOCnf(skb, &status, &ncoid))
-		return;
-
-	/* if the card is alreay running, it means that this message
-	 * arrives too late... */
-	if (card->running) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
-		       "ACreateNCOCnf received too late, status=%d\n", status);
-		return;
-	}
-
-	/* the NCO creation failed, the corresponding channel will
-	 * be unused */
-	if (status) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
-		       "ACreateNCO failed, status=%d\n", status);
-		card->channels_tested++;
-		return;
-	}
-
-	/* find the first free channel and assign the nco ID to it */
-	if ((channel = tpam_findchannel(card, TPAM_NCOID_INVALID)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
-		       "All channels are assigned\n");
-		return;
-	}
-	card->channels[channel].ncoid = ncoid;
-	card->channels_tested++;
-	card->channels_used++;
-}
-
-/*
- * Treat a received ADestroyNCOCnf message. Not used by the driver.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_ADestroyNCOCnf(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u8 status;
-	u32 channel;
-
-	pr_debug("TurboPAM(tpam_recv_ADestroyNCOCnf): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_ADestroyNCOCnf(skb, &status, &ncoid))
-		return;
-	
-	if (status) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): "
-		       "ADestroyNCO failed, status=%d\n", status);
-		return;
-	}
-
-	/* clears the channel's nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	card->channels[channel].ncoid = TPAM_NCOID_INVALID;
-}
-
-/*
- * Treat a received CConnectCnf message.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_CConnectCnf(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	isdn_ctrl ctrl;
-
-	pr_debug("TurboPAM(tpam_recv_CConnectCnf): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_CConnectCnf(skb, &ncoid))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_CConnectCnf): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* issue a DCONN command to the ISDN link layer if we are in HDLC mode.
-	 * In modem mode, we alreay did it - the ISDN timer kludge */
-	if (card->channels[channel].realhdlc) {
-		ctrl.driver = card->id;
-		ctrl.command = ISDN_STAT_DCONN;
-		ctrl.arg = channel;
-		(* card->interface.statcallb)(&ctrl);
-	}
-}
-
-/*
- * Treat a received CConnectInd message. This function signals a ICALL
- * to the ISDN link layer.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_CConnectInd(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	u8 hdlc, plan, screen;
-	u8 calling[PHONE_MAXIMUMSIZE], called[PHONE_MAXIMUMSIZE];
-	isdn_ctrl ctrl;
-	int status;
-
-	pr_debug("TurboPAM(tpam_recv_CConnectInd): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_CConnectInd(skb, &ncoid, &hdlc, calling, called, &plan, &screen))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_CConnectInd): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* initialize the channel parameters */
-	card->channels[channel].realhdlc = hdlc;
-	card->channels[channel].hdlcshift = 0;
-	card->channels[channel].readytoreceive = 0;
-
-	/* issue a ICALL command to the ISDN link layer */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_ICALL;
-	ctrl.arg = channel;
-	memcpy(ctrl.parm.setup.phone, calling, 32);
-	memcpy(ctrl.parm.setup.eazmsn, called, 32);
-	ctrl.parm.setup.si1 = 7;	/* data capability */
-	ctrl.parm.setup.si2 = 0;
-	ctrl.parm.setup.plan = plan;
-	ctrl.parm.setup.screen = screen;
-
-	status = (* card->interface.statcallb)(&ctrl);
-	switch (status) {
-		case 1:
-		case 4:
-			/* call accepted, link layer will send us a ACCEPTD 
-			 * command later */
-			pr_debug("TurboPAM(tpam_recv_CConnectInd): "
-				"card=%d, channel=%d, icall waiting, status=%d\n", 
-				card->id, channel, status);
-			break;
-		default:
-			/* call denied, we build and send a CDisconnectReq */
-			pr_debug("TurboPAM(tpam_recv_CConnectInd): "
-				"card=%d, channel=%d, icall denied, status=%d\n", 
-				card->id, channel, status);
-			skb = build_CDisconnectReq(ncoid);
-			if (!skb)
-				return;
-			tpam_enqueue(card, skb);
-	}
-}
-
-/*
- * Treat a received CDisconnectInd message. This function signals a DHUP and
- * a BHUP to the ISDN link layer.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_CDisconnectInd(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	u32 cause;
-	isdn_ctrl ctrl;
-
-	pr_debug("TurboPAM(tpam_recv_CDisconnectInd): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_CDisconnectInd(skb, &ncoid, &cause))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectInd): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* build and send a CDisconnectRsp */
-	skb = build_CDisconnectRsp(ncoid);
-	if (!skb)
-		return;
-	tpam_enqueue(card, skb);
-
-	/* issue a DHUP to the ISDN link layer */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_DHUP;
-	ctrl.arg = channel;
-	(* card->interface.statcallb)(&ctrl);
-
-	/* issue a BHUP to the ISDN link layer */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_BHUP;
-	ctrl.arg = channel;
-	(* card->interface.statcallb)(&ctrl);
-}
-
-/*
- * Treat a received CDisconnectCnf message. This function signals a DHUP and
- * a BHUP to the ISDN link layer.
- *
- * 	card: the board
- * 	skb: the received message
- */
-void tpam_recv_CDisconnectCnf(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	u32 cause;
-	isdn_ctrl ctrl;
-
-	pr_debug("TurboPAM(tpam_recv_CDisconnectCnf): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_CDisconnectCnf(skb, &ncoid, &cause))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectCnf): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* issue a DHUP to the ISDN link layer */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_DHUP;
-	ctrl.arg = channel;
-	(* card->interface.statcallb)(&ctrl);
-
-	/* issue a BHUP to the ISDN link layer */
-	ctrl.driver = card->id;
-	ctrl.command = ISDN_STAT_BHUP;
-	ctrl.arg = channel;
-	(* card->interface.statcallb)(&ctrl);
-}
-
-/*
- * Treat a received U3DataInd message. This function decodes the data
- * depending on the connection type (modem or HDLC) and passes it to the
- * ISDN link layer by using rcvcallb_skb.
- *
- * 	card: the board
- * 	skb: the received message + data
- */
-void tpam_recv_U3DataInd(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	u8 *data;
-	u16 len;
-	struct sk_buff *result;
-
-	pr_debug("TurboPAM(tpam_recv_U3DataInd): card=%d, datalen=%d\n",
-		card->id, skb->len);
-
-	/* parse the message contents */
-	if (parse_U3DataInd(skb, &ncoid, &data, &len))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* decode the data */
-	if (card->channels[ncoid].realhdlc) {
-		/* HDLC mode */
-		u8 *tempdata;
-		u32 templen;
-
-		if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
-			       "get_free_page failed\n");
-			return;
-		}
-		templen = tpam_hdlc_decode(data, tempdata, len);
-		templen = hdlc_no_accm_decode(tempdata, templen);
-		if (!(result = alloc_skb(templen, GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
-			       "alloc_skb failed\n");
-			free_page((unsigned long)tempdata);
-			return;
-		}
-		memcpy(skb_put(result, templen), tempdata, templen);
-		free_page((unsigned long)tempdata);
-	}
-	else {
-		/* modem mode */
-		if (!(result = alloc_skb(len, GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
-			       "alloc_skb failed\n");
-			return;
-		}
-		memcpy(skb_put(result, len), data, len);
-	}
-
-	/* In loop mode, resend the data immediately */
-	if (card->loopmode) {
-		struct sk_buff *loopskb;
-
-		if (!(loopskb = alloc_skb(skb->len, GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
-			       "alloc_skb failed\n");
-			kfree_skb(result);
-			return;
-		}
-		memcpy(skb_put(loopskb, result->len), result->data, 
-		       result->len);
-		if (tpam_writebuf_skb(card->id, channel, 0, loopskb) < 0)
-			kfree_skb(loopskb);
-	}
-
-	/* pass the data to the ISDN link layer */
-	(* card->interface.rcvcallb_skb)(card->id, channel, result);
-}
-
-/*
- * Treat a received U3ReadyToReceiveInd message. This function sets the
- * channel ready flag and triggers the send of data if the channel becomed
- * ready.
- *
- * 	card: the board
- * 	skb: the received message + data
- */
-void tpam_recv_U3ReadyToReceiveInd(tpam_card *card, struct sk_buff *skb) {
-	u32 ncoid;
-	u32 channel;
-	u8 ready;
-
-	pr_debug("TurboPAM(tpam_recv_U3ReadyToReceiveInd): card=%d\n", card->id);
-
-	/* parse the message contents */
-	if (parse_U3ReadyToReceiveInd(skb, &ncoid, &ready))
-		return;
-
-	/* find the channel by its nco ID */
-	if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
-		printk(KERN_ERR "TurboPAM(tpam_recv_U3ReadyToReceiveInd): "
-		       "ncoid invalid %lu\n", (unsigned long)ncoid);
-		return;
-	}
-
-	/* set the readytoreceive flag */
-	card->channels[channel].readytoreceive = ready;
-
-	/* if the channel just becomed ready, trigger the send of queued data */
-	if (ready)
-		tpam_enqueue_data(&card->channels[channel], NULL);
-}
-
-/*
- * Runs the delayed statcallb when its timer expires.
- *
- * 	parm: pointer to the tpam_statcallb_data statcallb argument.
- */
-static void tpam_statcallb_run(unsigned long parm) {
-	tpam_statcallb_data *ds = (tpam_statcallb_data *)parm;
-
-	pr_debug("TurboPAM(tpam_statcallb_run)\n");
-
-	(* ds->card->interface.statcallb)(&ds->ctrl);
-
-	kfree(ds->timer);
-	kfree(ds);
-}
-
-/*
- * Queues a statcallb call for delayed invocation.
- *
- * 	card: the board
- * 	ctrl: the statcallb argument
- */
-static void tpam_statcallb(tpam_card *card, isdn_ctrl ctrl) {
-	struct timer_list *timer;
-	tpam_statcallb_data *ds;
-
-	pr_debug("TurboPAM(tpam_statcallb): card=%d\n", card->id);
-
-	if (!(timer = (struct timer_list *) kmalloc(sizeof(struct timer_list), 
-						    GFP_ATOMIC))) {
-		printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
-		return;
-	}
-
-	if (!(ds = (tpam_statcallb_data *) kmalloc(sizeof(tpam_statcallb_data),
-						   GFP_ATOMIC))) {
-		printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
-		kfree(timer);
-		return;
-	}
-	ds->card = card;
-	ds->timer = timer;
-	memcpy(&ds->ctrl, &ctrl, sizeof(isdn_ctrl));
-
-	init_timer(timer);
-	timer->function = tpam_statcallb_run;
-	timer->data = (unsigned long)ds;
-	timer->expires = jiffies + HZ / 10;   /* 0.1 second */
-	add_timer(timer);
-}
diff --git a/drivers/isdn/tpam/tpam_crcpc.c b/drivers/isdn/tpam/tpam_crcpc.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_crcpc.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* $Id: tpam_crcpc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding)
- *
- * Copyright 1998-2000 AUVERTECH Télécom
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Module Name:
-
-    crcpc.c
-
-Abstract:
-
-    Modem HDLC coding
-    Software HDLC coding / decoding
-
-Revision History:
-
----------------------------------------------------------------------------*/
-
-#include <linux/crc-ccitt.h>
-#include "tpam.h"
-
-#define  HDLC_CTRL_CHAR_CMPL_MASK	0x20	/* HDLC control character complement mask */
-#define  HDLC_FLAG			0x7E	/* HDLC flag */
-#define  HDLC_CTRL_ESC			0x7D	/* HDLC control escapr character */
-#define  HDLC_LIKE_FCS_INIT_VAL		0xFFFF	/* FCS initial value (0xFFFF for new equipment or 0) */
-#define  HDLC_FCS_OK			0xF0B8	/* This value is the only valid value of FCS */
-
-#define TRUE	1
-#define FALSE	0
-
-static u8 ap_t_ctrl_char_complemented[256]; /* list of characters to complement */
-
-static void ap_hdlc_like_ctrl_char_list (u32 ctrl_char) {
-	int i;
-
-	for (i = 0; i < 256; ++i)
-		ap_t_ctrl_char_complemented[i] = FALSE;
-	for (i = 0; i < 32; ++i)
-		if ((ctrl_char >> i) & 0x0001)
-			ap_t_ctrl_char_complemented [i] = TRUE;
-	ap_t_ctrl_char_complemented[HDLC_FLAG] = TRUE;
-	ap_t_ctrl_char_complemented[HDLC_CTRL_ESC] = TRUE;
-		
-}
-
-void init_CRC(void) {
-	ap_hdlc_like_ctrl_char_list(0xffffffff);
-}
-
-void hdlc_encode_modem(u8 *buffer_in, u32 lng_in,
-		       u8 *buffer_out, u32 *lng_out) {
-	u16 fcs;
-	register u8 data;
-	register u8 *p_data_out = buffer_out;
-
-	fcs = HDLC_LIKE_FCS_INIT_VAL;
-
-	/*
-	 *   Insert HDLC flag at the beginning of the frame
-	 */
-	*p_data_out++ = HDLC_FLAG;
-
-#define ESCAPE_CHAR(data_out, data) \
-	if (ap_t_ctrl_char_complemented[data]) { \
-		*data_out++ = HDLC_CTRL_ESC; \
-		*data_out++ = data ^ 0x20; \
-	} \
-	else \
-		*data_out++ = data;
-
-	while (lng_in--) {
-		data = *buffer_in++;
-
-		/*
-		 *   FCS calculation
-		 */
-		fcs = crc_ccitt_byte(fcs, data);
-
-		ESCAPE_CHAR(p_data_out, data);
-	}
-
-	/*
-	 *  Add FCS and closing flag
-	 */
-	fcs ^= 0xFFFF;  // Complement
-
-	data = (u8)(fcs & 0xff);	/* LSB */
-	ESCAPE_CHAR(p_data_out, data);
-
-	data = (u8)((fcs >> 8));	/* MSB */
-	ESCAPE_CHAR(p_data_out, data);
-#undef ESCAPE_CHAR
-
-	*p_data_out++ = HDLC_FLAG;
-
-	*lng_out = (u32)(p_data_out - buffer_out);
-}
-
-void hdlc_no_accm_encode(u8 *buffer_in, u32 lng_in, 
-			 u8 *buffer_out, u32 *lng_out) {
-	u16 fcs;
-	register u8 data;
-	register u8 *p_data_out = buffer_out;
-
-	/*
-	 *   Insert HDLC flag at the beginning of the frame
-	 */
-	fcs = HDLC_LIKE_FCS_INIT_VAL;
-
-	while (lng_in--) {
-		data = *buffer_in++;
-		/* calculate FCS */
-		fcs = crc_ccitt_byte(fcs, data);
-		*p_data_out++ = data;
-	}
-
-	/*
-	 *  Add FCS and closing flag
-	 */
-	fcs ^= 0xFFFF;  // Complement
-	data = (u8)(fcs);    
-	*p_data_out++ = data;
-
-	data =(u8)((fcs >> 8));   // revense MSB / LSB
-	*p_data_out++ = data;
- 
-	*lng_out = (u32)(p_data_out - buffer_out);
-}
-
-u32 hdlc_no_accm_decode(u8 *buffer_in, u32 lng_in) {
-	u16 fcs;
-	u32 lng = lng_in;
-	register u8 data;
-
-	/*
-	 *   Insert HDLC flag at the beginning of the frame
-	 */
-	fcs = HDLC_LIKE_FCS_INIT_VAL;
-
-	while (lng_in--) {
-		data = *buffer_in++;
-		/* calculate FCS */
-		fcs = crc_ccitt_byte(fcs, data);
-	}
-
-	if (fcs == HDLC_FCS_OK) 
-		return (lng-2);
-	else 
-		return 0;
-}
-
diff --git a/drivers/isdn/tpam/tpam_hdlc.c b/drivers/isdn/tpam/tpam_hdlc.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_hdlc.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/* $Id: tpam_hdlc.c,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding)
- *
- * Copyright 1998-2000 AUVERTECH Télécom
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Module Name:
-
-    hdlc.c
-
-Abstract:
-
-    stuff0 : array necessary for the bit stuffing algorithm
-    stuff1 : array necessary for the bit stuffing algorithm
-    stuff2 : array necessary for the bit stuffing algorithm
-    stuff3 : array necessary for the bit stuffing algorithm
-    stuff4 : array necessary for the bit stuffing algorithm
-    stuff5 : array necessary for the bit stuffing algorithm
-    stuffs[] : array conaining the previous 6 arrays
-    destuff0 : array necessary for the bit destuffing algorithm
-    destuff1 : array necessary for the bit destuffing algorithm
-    destuff2 : array necessary for the bit destuffing algorithm
-    destuff3 : array necessary for the bit destuffing algorithm
-    destuff4 : array necessary for the bit destuffing algorithm
-    destuff5 : array necessary for the bit destuffing algorithm
-    destuffs[] : array conaining the previous 6 arrays
-
-    tpam_hdlc_encode : bit stuffing of a byte array, with the addition 
-                  of a start and end flag, using the bit shift given in 
-		  parameter (which is updated at the end of encoding).
-    tpam_hdlc_decode : bit de-stuffing of a byte array with detection of 
-                  possible ABORTs.
-
-Revision History:
-
----------------------------------------------------------------------------*/
-
-/* The arrays are used as follows:
-
-  For the bit stuffing :
-	
-  stuff0 = used if the previous byte ended with '0'
-  stuff1 = used if the previous byte ended with '10'
-  stuff2 = used if the previous byte ended with '110'
-  stuff3 = used if the previous byte ended with '1110'
-  stuff4 = used if the previous byte ended with '11110'
-  stuff5 = used if the previous byte ended with '111110'
-  
-  those arrays are indexed by the byte to stuff.
-  
-  the data of those arrays are of the form (in binary):
-  "bbbbaaaa cccccccc"
-  with "cccccccc" : byte stuffed
-       "aaaa" : "0000" --> no insertion of '0'
-	            "0100" --> 1 '0' inserted, carry = '0'
-                "0101" --> 1 '0' inserted, carry = '1'
-                "1000" --> 2 '0' inserted, carry = '00'
-                "1001" --> 2 '0' inserted, carry = '01'
-                "1010" --> 2 '0' inserted, carry = '10'
-                "1011" --> 2 '0' inserted, carry = '11'
-       "bbbb" : count of '1' at the end of "cccccccc"
-
-
-  
-  For the bit de-stuffing :
-
-  destuff0 = used if the previous byte ended with '0'
-  destuff1 = used if the previous byte ended with '10'
-  destuff2 = used if the previous byte ended with '110'
-  destuff3 = used if the previous byte ended with '1110'
-  destuff4 = used if the previous byte ended with '11110'
-  destuff5 = used if the previous byte ended with '111110'
-
-  those arrays are indexed by the byte to de-stuff.
-
-  the data of those arrays are of the form (in binary):
-  "dbbbaaaa cccccccc"
-  with "cccccccc" : byte destuffed
-       "aaaa" : count of '1' at the end of the byte non destuffed
-       "bbb" : count of bits to use in the destuffed byte (8 less the count
-               of '0' deleted) less 1 (can be only 7, 6 or 5)
-	   "d" : '1' if the byte non destuffed has more than 5 consecutive '1' 
-	         (flag or abort)
-*/
-
-#include <linux/types.h>
-#include "tpam.h"
-
-typedef u8	BYTE;
-typedef u16	WORD;
-typedef u32	DWORD;
-typedef u8	BOOL;
-
-#define	TRUE			1
-#define FALSE			0
-
-static WORD stuff0[] =
-{
-	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 
-	0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 
-	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 
-	0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x041F, 
-	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 
-	0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 
-	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 
-	0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x045F, 
-	0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 
-	0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 
-	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 
-	0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x149F, 
-	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 
-	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 
-	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 
-	0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x24DF, 
-	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 
-	0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, 
-	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 
-	0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x051F, 
-	0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x10A7, 
-	0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x10AF, 
-	0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x10B7, 
-	0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x055F, 
-	0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 
-	0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, 
-	0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 
-	0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x159F, 
-	0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 
-	0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, 
-	0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x40F7, 
-	0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x25DF, 
-};
-
-
-static WORD stuff1[] =
-{
-	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 
-	0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x040F, 
-	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 
-	0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x042F, 
-	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 
-	0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x044F, 
-	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 
-	0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x046F, 
-	0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 
-	0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x148F, 
-	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 
-	0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x14AF, 
-	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 
-	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x24CF, 
-	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 
-	0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x34EF, 
-	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 
-	0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x050F, 
-	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 
-	0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x052F, 
-	0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x10A7, 
-	0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x054F, 
-	0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x10B7, 
-	0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x056F, 
-	0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 
-	0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x158F, 
-	0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 
-	0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x15AF, 
-	0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 
-	0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x25CF, 
-	0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x40F7, 
-	0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x35EF, 
-};
-
-
-static WORD stuff2[] =
-{
-	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0407, 
-	0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0417, 
-	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0427, 
-	0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x0437, 
-	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0447, 
-	0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x0457, 
-	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0467, 
-	0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x0477, 
-	0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x1487, 
-	0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x1497, 
-	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x14A7, 
-	0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x14B7, 
-	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x24C7, 
-	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x24D7, 
-	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x34E7, 
-	0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x44F7, 
-	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x0507, 
-	0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x0517, 
-	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x0527, 
-	0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x0537, 
-	0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x0547, 
-	0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x0557, 
-	0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x0567, 
-	0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x0577, 
-	0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x1587, 
-	0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x1597, 
-	0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x15A7, 
-	0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x15B7, 
-	0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x25C7, 
-	0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x25D7, 
-	0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x35E7, 
-	0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x45F7, 
-};
-
-
-static WORD stuff3[] =
-{
-	0x0000, 0x0001, 0x0002, 0x0403, 0x0004, 0x0005, 0x0006, 0x040B, 
-	0x0008, 0x0009, 0x000A, 0x0413, 0x000C, 0x000D, 0x000E, 0x041B, 
-	0x0010, 0x0011, 0x0012, 0x0423, 0x0014, 0x0015, 0x0016, 0x042B, 
-	0x0018, 0x0019, 0x001A, 0x0433, 0x001C, 0x001D, 0x001E, 0x043B, 
-	0x0020, 0x0021, 0x0022, 0x0443, 0x0024, 0x0025, 0x0026, 0x044B, 
-	0x0028, 0x0029, 0x002A, 0x0453, 0x002C, 0x002D, 0x002E, 0x045B, 
-	0x0030, 0x0031, 0x0032, 0x0463, 0x0034, 0x0035, 0x0036, 0x046B, 
-	0x0038, 0x0039, 0x003A, 0x0473, 0x003C, 0x003D, 0x043E, 0x047B, 
-	0x0040, 0x0041, 0x0042, 0x1483, 0x0044, 0x0045, 0x0046, 0x148B, 
-	0x0048, 0x0049, 0x004A, 0x1493, 0x004C, 0x004D, 0x004E, 0x149B, 
-	0x0050, 0x0051, 0x0052, 0x14A3, 0x0054, 0x0055, 0x0056, 0x14AB, 
-	0x0058, 0x0059, 0x005A, 0x14B3, 0x005C, 0x005D, 0x005E, 0x14BB, 
-	0x0060, 0x0061, 0x0062, 0x24C3, 0x0064, 0x0065, 0x0066, 0x24CB, 
-	0x0068, 0x0069, 0x006A, 0x24D3, 0x006C, 0x006D, 0x006E, 0x24DB, 
-	0x0070, 0x0071, 0x0072, 0x34E3, 0x0074, 0x0075, 0x0076, 0x34EB, 
-	0x0078, 0x0079, 0x007A, 0x44F3, 0x047C, 0x047D, 0x14BE, 0x54FB, 
-	0x1080, 0x1081, 0x1082, 0x0503, 0x1084, 0x1085, 0x1086, 0x050B, 
-	0x1088, 0x1089, 0x108A, 0x0513, 0x108C, 0x108D, 0x108E, 0x051B, 
-	0x1090, 0x1091, 0x1092, 0x0523, 0x1094, 0x1095, 0x1096, 0x052B, 
-	0x1098, 0x1099, 0x109A, 0x0533, 0x109C, 0x109D, 0x109E, 0x053B, 
-	0x10A0, 0x10A1, 0x10A2, 0x0543, 0x10A4, 0x10A5, 0x10A6, 0x054B, 
-	0x10A8, 0x10A9, 0x10AA, 0x0553, 0x10AC, 0x10AD, 0x10AE, 0x055B, 
-	0x10B0, 0x10B1, 0x10B2, 0x0563, 0x10B4, 0x10B5, 0x10B6, 0x056B, 
-	0x10B8, 0x10B9, 0x10BA, 0x0573, 0x10BC, 0x10BD, 0x053E, 0x057B, 
-	0x20C0, 0x20C1, 0x20C2, 0x1583, 0x20C4, 0x20C5, 0x20C6, 0x158B, 
-	0x20C8, 0x20C9, 0x20CA, 0x1593, 0x20CC, 0x20CD, 0x20CE, 0x159B, 
-	0x20D0, 0x20D1, 0x20D2, 0x15A3, 0x20D4, 0x20D5, 0x20D6, 0x15AB, 
-	0x20D8, 0x20D9, 0x20DA, 0x15B3, 0x20DC, 0x20DD, 0x20DE, 0x15BB, 
-	0x30E0, 0x30E1, 0x30E2, 0x25C3, 0x30E4, 0x30E5, 0x30E6, 0x25CB, 
-	0x30E8, 0x30E9, 0x30EA, 0x25D3, 0x30EC, 0x30ED, 0x30EE, 0x25DB, 
-	0x40F0, 0x40F1, 0x40F2, 0x35E3, 0x40F4, 0x40F5, 0x40F6, 0x35EB, 
-	0x50F8, 0x50F9, 0x50FA, 0x45F3, 0x057C, 0x057D, 0x15BE, 0x55FB, 
-};
-
-
-static WORD stuff4[] =
-{
-	0x0000, 0x0401, 0x0002, 0x0405, 0x0004, 0x0409, 0x0006, 0x040D, 
-	0x0008, 0x0411, 0x000A, 0x0415, 0x000C, 0x0419, 0x000E, 0x041D, 
-	0x0010, 0x0421, 0x0012, 0x0425, 0x0014, 0x0429, 0x0016, 0x042D, 
-	0x0018, 0x0431, 0x001A, 0x0435, 0x001C, 0x0439, 0x001E, 0x043D, 
-	0x0020, 0x0441, 0x0022, 0x0445, 0x0024, 0x0449, 0x0026, 0x044D, 
-	0x0028, 0x0451, 0x002A, 0x0455, 0x002C, 0x0459, 0x002E, 0x045D, 
-	0x0030, 0x0461, 0x0032, 0x0465, 0x0034, 0x0469, 0x0036, 0x046D, 
-	0x0038, 0x0471, 0x003A, 0x0475, 0x003C, 0x0479, 0x043E, 0x087D, 
-	0x0040, 0x1481, 0x0042, 0x1485, 0x0044, 0x1489, 0x0046, 0x148D, 
-	0x0048, 0x1491, 0x004A, 0x1495, 0x004C, 0x1499, 0x004E, 0x149D, 
-	0x0050, 0x14A1, 0x0052, 0x14A5, 0x0054, 0x14A9, 0x0056, 0x14AD, 
-	0x0058, 0x14B1, 0x005A, 0x14B5, 0x005C, 0x14B9, 0x005E, 0x14BD, 
-	0x0060, 0x24C1, 0x0062, 0x24C5, 0x0064, 0x24C9, 0x0066, 0x24CD, 
-	0x0068, 0x24D1, 0x006A, 0x24D5, 0x006C, 0x24D9, 0x006E, 0x24DD, 
-	0x0070, 0x34E1, 0x0072, 0x34E5, 0x0074, 0x34E9, 0x0076, 0x34ED, 
-	0x0078, 0x44F1, 0x007A, 0x44F5, 0x047C, 0x54F9, 0x14BE, 0x097D, 
-	0x1080, 0x0501, 0x1082, 0x0505, 0x1084, 0x0509, 0x1086, 0x050D, 
-	0x1088, 0x0511, 0x108A, 0x0515, 0x108C, 0x0519, 0x108E, 0x051D, 
-	0x1090, 0x0521, 0x1092, 0x0525, 0x1094, 0x0529, 0x1096, 0x052D, 
-	0x1098, 0x0531, 0x109A, 0x0535, 0x109C, 0x0539, 0x109E, 0x053D, 
-	0x10A0, 0x0541, 0x10A2, 0x0545, 0x10A4, 0x0549, 0x10A6, 0x054D, 
-	0x10A8, 0x0551, 0x10AA, 0x0555, 0x10AC, 0x0559, 0x10AE, 0x055D, 
-	0x10B0, 0x0561, 0x10B2, 0x0565, 0x10B4, 0x0569, 0x10B6, 0x056D, 
-	0x10B8, 0x0571, 0x10BA, 0x0575, 0x10BC, 0x0579, 0x053E, 0x0A7D, 
-	0x20C0, 0x1581, 0x20C2, 0x1585, 0x20C4, 0x1589, 0x20C6, 0x158D, 
-	0x20C8, 0x1591, 0x20CA, 0x1595, 0x20CC, 0x1599, 0x20CE, 0x159D, 
-	0x20D0, 0x15A1, 0x20D2, 0x15A5, 0x20D4, 0x15A9, 0x20D6, 0x15AD, 
-	0x20D8, 0x15B1, 0x20DA, 0x15B5, 0x20DC, 0x15B9, 0x20DE, 0x15BD, 
-	0x30E0, 0x25C1, 0x30E2, 0x25C5, 0x30E4, 0x25C9, 0x30E6, 0x25CD, 
-	0x30E8, 0x25D1, 0x30EA, 0x25D5, 0x30EC, 0x25D9, 0x30EE, 0x25DD, 
-	0x40F0, 0x35E1, 0x40F2, 0x35E5, 0x40F4, 0x35E9, 0x40F6, 0x35ED, 
-	0x50F8, 0x45F1, 0x50FA, 0x45F5, 0x057C, 0x55F9, 0x15BE, 0x0B7D, 
-};
-
-
-static WORD stuff5[] =
-{
-	0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E, 
-	0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, 0x041E, 
-	0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, 0x042E, 
-	0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, 0x083E, 
-	0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, 0x044E, 
-	0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, 0x045E, 
-	0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, 0x046E, 
-	0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x087C, 0x18BE, 
-	0x1480, 0x1482, 0x1484, 0x1486, 0x1488, 0x148A, 0x148C, 0x148E, 
-	0x1490, 0x1492, 0x1494, 0x1496, 0x1498, 0x149A, 0x149C, 0x149E, 
-	0x14A0, 0x14A2, 0x14A4, 0x14A6, 0x14A8, 0x14AA, 0x14AC, 0x14AE, 
-	0x14B0, 0x14B2, 0x14B4, 0x14B6, 0x14B8, 0x14BA, 0x14BC, 0x093E, 
-	0x24C0, 0x24C2, 0x24C4, 0x24C6, 0x24C8, 0x24CA, 0x24CC, 0x24CE, 
-	0x24D0, 0x24D2, 0x24D4, 0x24D6, 0x24D8, 0x24DA, 0x24DC, 0x24DE, 
-	0x34E0, 0x34E2, 0x34E4, 0x34E6, 0x34E8, 0x34EA, 0x34EC, 0x34EE, 
-	0x44F0, 0x44F2, 0x44F4, 0x44F6, 0x54F8, 0x54FA, 0x097C, 0x19BE, 
-	0x0500, 0x0502, 0x0504, 0x0506, 0x0508, 0x050A, 0x050C, 0x050E, 
-	0x0510, 0x0512, 0x0514, 0x0516, 0x0518, 0x051A, 0x051C, 0x051E, 
-	0x0520, 0x0522, 0x0524, 0x0526, 0x0528, 0x052A, 0x052C, 0x052E, 
-	0x0530, 0x0532, 0x0534, 0x0536, 0x0538, 0x053A, 0x053C, 0x0A3E, 
-	0x0540, 0x0542, 0x0544, 0x0546, 0x0548, 0x054A, 0x054C, 0x054E, 
-	0x0550, 0x0552, 0x0554, 0x0556, 0x0558, 0x055A, 0x055C, 0x055E, 
-	0x0560, 0x0562, 0x0564, 0x0566, 0x0568, 0x056A, 0x056C, 0x056E, 
-	0x0570, 0x0572, 0x0574, 0x0576, 0x0578, 0x057A, 0x0A7C, 0x1ABE, 
-	0x1580, 0x1582, 0x1584, 0x1586, 0x1588, 0x158A, 0x158C, 0x158E, 
-	0x1590, 0x1592, 0x1594, 0x1596, 0x1598, 0x159A, 0x159C, 0x159E, 
-	0x15A0, 0x15A2, 0x15A4, 0x15A6, 0x15A8, 0x15AA, 0x15AC, 0x15AE, 
-	0x15B0, 0x15B2, 0x15B4, 0x15B6, 0x15B8, 0x15BA, 0x15BC, 0x0B3E, 
-	0x25C0, 0x25C2, 0x25C4, 0x25C6, 0x25C8, 0x25CA, 0x25CC, 0x25CE, 
-	0x25D0, 0x25D2, 0x25D4, 0x25D6, 0x25D8, 0x25DA, 0x25DC, 0x25DE, 
-	0x35E0, 0x35E2, 0x35E4, 0x35E6, 0x35E8, 0x35EA, 0x35EC, 0x35EE, 
-	0x45F0, 0x45F2, 0x45F4, 0x45F6, 0x55F8, 0x55FA, 0x0B7C, 0x1BBE, 
-};
-
-static WORD destuff0[] =
-{
-	0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x7007, 
-	0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0x700F, 
-	0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x7017, 
-	0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0x601F, 
-	0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x7027, 
-	0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0x702F, 
-	0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x7037, 
-	0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, 
-	0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x7047, 
-	0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0x704F, 
-	0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x7057, 
-	0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0x603F, 
-	0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x7067, 
-	0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0x706F, 
-	0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x7077, 
-	0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, 
-	0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x7187, 
-	0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0x718F, 
-	0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x7197, 
-	0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0x615F, 
-	0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x71A7, 
-	0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0x71AF, 
-	0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x71B7, 
-	0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, 
-	0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x72C7, 
-	0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0x72CF, 
-	0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x72D7, 
-	0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0x627F, 
-	0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x73E7, 
-	0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0x73EF, 
-	0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x74F7, 
-	0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xF8FF, 
-};
-
-
-static WORD destuff1[] =
-{
-	0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x7007, 
-	0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0x600F, 
-	0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x7017, 
-	0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0xF01F, 
-	0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x7027, 
-	0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0x601F, 
-	0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x7037, 
-	0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, 
-	0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x7047, 
-	0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0x602F, 
-	0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x7057, 
-	0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0xF05F, 
-	0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x7067, 
-	0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0x603F, 
-	0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x7077, 
-	0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, 
-	0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x7187, 
-	0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0x614F, 
-	0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x7197, 
-	0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0xF19F, 
-	0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x71A7, 
-	0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0x615F, 
-	0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x71B7, 
-	0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, 
-	0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x72C7, 
-	0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0x626F, 
-	0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x72D7, 
-	0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, 
-	0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x73E7, 
-	0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0x637F, 
-	0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x74F7, 
-	0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xF9FF, 
-};
-
-
-static WORD destuff2[] =
-{
-	0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x6007, 
-	0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0xF00F, 
-	0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x600F, 
-	0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0xF01F, 
-	0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x6017, 
-	0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0xF02F, 
-	0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x601F, 
-	0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, 
-	0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x6027, 
-	0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0xF04F, 
-	0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x602F, 
-	0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0xF05F, 
-	0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x6037, 
-	0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0xF06F, 
-	0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x603F, 
-	0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, 
-	0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x6147, 
-	0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0xF18F, 
-	0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x614F, 
-	0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0xF19F, 
-	0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x6157, 
-	0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0xF1AF, 
-	0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x615F, 
-	0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, 
-	0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x6267, 
-	0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0xF2CF, 
-	0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x626F, 
-	0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, 
-	0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x6377, 
-	0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0xF3EF, 
-	0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x647F, 
-	0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xFAFF, 
-};
-
-
-static WORD destuff3[] =
-{
-	0x7000, 0x7001, 0x7002, 0x6003, 0x7004, 0x7005, 0x7006, 0xF007, 
-	0x7008, 0x7009, 0x700A, 0x6007, 0x700C, 0x700D, 0x700E, 0xF00F, 
-	0x7010, 0x7011, 0x7012, 0x600B, 0x7014, 0x7015, 0x7016, 0xF017, 
-	0x7018, 0x7019, 0x701A, 0x600F, 0x701C, 0x701D, 0x701E, 0xF01F, 
-	0x7020, 0x7021, 0x7022, 0x6013, 0x7024, 0x7025, 0x7026, 0xF027, 
-	0x7028, 0x7029, 0x702A, 0x6017, 0x702C, 0x702D, 0x702E, 0xF02F, 
-	0x7030, 0x7031, 0x7032, 0x601B, 0x7034, 0x7035, 0x7036, 0xF037, 
-	0x7038, 0x7039, 0x703A, 0x601F, 0x703C, 0x703D, 0x603E, 0xF03F, 
-	0x7040, 0x7041, 0x7042, 0x6023, 0x7044, 0x7045, 0x7046, 0xF047, 
-	0x7048, 0x7049, 0x704A, 0x6027, 0x704C, 0x704D, 0x704E, 0xF04F, 
-	0x7050, 0x7051, 0x7052, 0x602B, 0x7054, 0x7055, 0x7056, 0xF057, 
-	0x7058, 0x7059, 0x705A, 0x602F, 0x705C, 0x705D, 0x705E, 0xF05F, 
-	0x7060, 0x7061, 0x7062, 0x6033, 0x7064, 0x7065, 0x7066, 0xF067, 
-	0x7068, 0x7069, 0x706A, 0x6037, 0x706C, 0x706D, 0x706E, 0xF06F, 
-	0x7070, 0x7071, 0x7072, 0x603B, 0x7074, 0x7075, 0x7076, 0xF077, 
-	0x7078, 0x7079, 0x707A, 0x603F, 0x607C, 0x607D, 0xF07E, 0xF07F, 
-	0x7180, 0x7181, 0x7182, 0x6143, 0x7184, 0x7185, 0x7186, 0xF187, 
-	0x7188, 0x7189, 0x718A, 0x6147, 0x718C, 0x718D, 0x718E, 0xF18F, 
-	0x7190, 0x7191, 0x7192, 0x614B, 0x7194, 0x7195, 0x7196, 0xF197, 
-	0x7198, 0x7199, 0x719A, 0x614F, 0x719C, 0x719D, 0x719E, 0xF19F, 
-	0x71A0, 0x71A1, 0x71A2, 0x6153, 0x71A4, 0x71A5, 0x71A6, 0xF1A7, 
-	0x71A8, 0x71A9, 0x71AA, 0x6157, 0x71AC, 0x71AD, 0x71AE, 0xF1AF, 
-	0x71B0, 0x71B1, 0x71B2, 0x615B, 0x71B4, 0x71B5, 0x71B6, 0xF1B7, 
-	0x71B8, 0x71B9, 0x71BA, 0x615F, 0x71BC, 0x71BD, 0x617E, 0xF1BF, 
-	0x72C0, 0x72C1, 0x72C2, 0x6263, 0x72C4, 0x72C5, 0x72C6, 0xF2C7, 
-	0x72C8, 0x72C9, 0x72CA, 0x6267, 0x72CC, 0x72CD, 0x72CE, 0xF2CF, 
-	0x72D0, 0x72D1, 0x72D2, 0x626B, 0x72D4, 0x72D5, 0x72D6, 0xF2D7, 
-	0x72D8, 0x72D9, 0x72DA, 0x626F, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, 
-	0x73E0, 0x73E1, 0x73E2, 0x6373, 0x73E4, 0x73E5, 0x73E6, 0xF3E7, 
-	0x73E8, 0x73E9, 0x73EA, 0x6377, 0x73EC, 0x73ED, 0x73EE, 0xF3EF, 
-	0x74F0, 0x74F1, 0x74F2, 0x647B, 0x74F4, 0x74F5, 0x74F6, 0xF4F7, 
-	0x75F8, 0x75F9, 0x75FA, 0x657F, 0xF6FC, 0xF6FD, 0xF7FE, 0xFBFF, 
-};
-
-
-static WORD destuff4[] =
-{
-	0x7000, 0x6001, 0x7002, 0xF003, 0x7004, 0x6003, 0x7006, 0xF007, 
-	0x7008, 0x6005, 0x700A, 0xF00B, 0x700C, 0x6007, 0x700E, 0xF00F, 
-	0x7010, 0x6009, 0x7012, 0xF013, 0x7014, 0x600B, 0x7016, 0xF017, 
-	0x7018, 0x600D, 0x701A, 0xF01B, 0x701C, 0x600F, 0x701E, 0xF01F, 
-	0x7020, 0x6011, 0x7022, 0xF023, 0x7024, 0x6013, 0x7026, 0xF027, 
-	0x7028, 0x6015, 0x702A, 0xF02B, 0x702C, 0x6017, 0x702E, 0xF02F, 
-	0x7030, 0x6019, 0x7032, 0xF033, 0x7034, 0x601B, 0x7036, 0xF037, 
-	0x7038, 0x601D, 0x703A, 0xF03B, 0x703C, 0x601F, 0x603E, 0xF03F, 
-	0x7040, 0x6021, 0x7042, 0xF043, 0x7044, 0x6023, 0x7046, 0xF047, 
-	0x7048, 0x6025, 0x704A, 0xF04B, 0x704C, 0x6027, 0x704E, 0xF04F, 
-	0x7050, 0x6029, 0x7052, 0xF053, 0x7054, 0x602B, 0x7056, 0xF057, 
-	0x7058, 0x602D, 0x705A, 0xF05B, 0x705C, 0x602F, 0x705E, 0xF05F, 
-	0x7060, 0x6031, 0x7062, 0xF063, 0x7064, 0x6033, 0x7066, 0xF067, 
-	0x7068, 0x6035, 0x706A, 0xF06B, 0x706C, 0x6037, 0x706E, 0xF06F, 
-	0x7070, 0x6039, 0x7072, 0xF073, 0x7074, 0x603B, 0x7076, 0xF077, 
-	0x7078, 0x603D, 0x707A, 0xF07B, 0x607C, 0x503F, 0xF07E, 0xF07F, 
-	0x7180, 0x6141, 0x7182, 0xF183, 0x7184, 0x6143, 0x7186, 0xF187, 
-	0x7188, 0x6145, 0x718A, 0xF18B, 0x718C, 0x6147, 0x718E, 0xF18F, 
-	0x7190, 0x6149, 0x7192, 0xF193, 0x7194, 0x614B, 0x7196, 0xF197, 
-	0x7198, 0x614D, 0x719A, 0xF19B, 0x719C, 0x614F, 0x719E, 0xF19F, 
-	0x71A0, 0x6151, 0x71A2, 0xF1A3, 0x71A4, 0x6153, 0x71A6, 0xF1A7, 
-	0x71A8, 0x6155, 0x71AA, 0xF1AB, 0x71AC, 0x6157, 0x71AE, 0xF1AF, 
-	0x71B0, 0x6159, 0x71B2, 0xF1B3, 0x71B4, 0x615B, 0x71B6, 0xF1B7, 
-	0x71B8, 0x615D, 0x71BA, 0xF1BB, 0x71BC, 0x615F, 0x617E, 0xF1BF, 
-	0x72C0, 0x6261, 0x72C2, 0xF2C3, 0x72C4, 0x6263, 0x72C6, 0xF2C7, 
-	0x72C8, 0x6265, 0x72CA, 0xF2CB, 0x72CC, 0x6267, 0x72CE, 0xF2CF, 
-	0x72D0, 0x6269, 0x72D2, 0xF2D3, 0x72D4, 0x626B, 0x72D6, 0xF2D7, 
-	0x72D8, 0x626D, 0x72DA, 0xF2DB, 0x72DC, 0x626F, 0x72DE, 0xF2DF, 
-	0x73E0, 0x6371, 0x73E2, 0xF3E3, 0x73E4, 0x6373, 0x73E6, 0xF3E7, 
-	0x73E8, 0x6375, 0x73EA, 0xF3EB, 0x73EC, 0x6377, 0x73EE, 0xF3EF, 
-	0x74F0, 0x6479, 0x74F2, 0xF4F3, 0x74F4, 0x647B, 0x74F6, 0xF4F7, 
-	0x75F8, 0x657D, 0x75FA, 0xF5FB, 0xF6FC, 0xE67F, 0xF7FE, 0xFCFF, 
-};
-
-
-static WORD destuff5[] =
-{
-	0x6000, 0xF001, 0x6001, 0xF003, 0x6002, 0xF005, 0x6003, 0xF007, 
-	0x6004, 0xF009, 0x6005, 0xF00B, 0x6006, 0xF00D, 0x6007, 0xF00F, 
-	0x6008, 0xF011, 0x6009, 0xF013, 0x600A, 0xF015, 0x600B, 0xF017, 
-	0x600C, 0xF019, 0x600D, 0xF01B, 0x600E, 0xF01D, 0x600F, 0xF01F, 
-	0x6010, 0xF021, 0x6011, 0xF023, 0x6012, 0xF025, 0x6013, 0xF027, 
-	0x6014, 0xF029, 0x6015, 0xF02B, 0x6016, 0xF02D, 0x6017, 0xF02F, 
-	0x6018, 0xF031, 0x6019, 0xF033, 0x601A, 0xF035, 0x601B, 0xF037, 
-	0x601C, 0xF039, 0x601D, 0xF03B, 0x601E, 0xF03D, 0x501F, 0xF03F, 
-	0x6020, 0xF041, 0x6021, 0xF043, 0x6022, 0xF045, 0x6023, 0xF047, 
-	0x6024, 0xF049, 0x6025, 0xF04B, 0x6026, 0xF04D, 0x6027, 0xF04F, 
-	0x6028, 0xF051, 0x6029, 0xF053, 0x602A, 0xF055, 0x602B, 0xF057, 
-	0x602C, 0xF059, 0x602D, 0xF05B, 0x602E, 0xF05D, 0x602F, 0xF05F, 
-	0x6030, 0xF061, 0x6031, 0xF063, 0x6032, 0xF065, 0x6033, 0xF067, 
-	0x6034, 0xF069, 0x6035, 0xF06B, 0x6036, 0xF06D, 0x6037, 0xF06F, 
-	0x6038, 0xF071, 0x6039, 0xF073, 0x603A, 0xF075, 0x603B, 0xF077, 
-	0x603C, 0xF079, 0x603D, 0xF07B, 0x503E, 0xE07D, 0xE03F, 0xF07F, 
-	0x6140, 0xF181, 0x6141, 0xF183, 0x6142, 0xF185, 0x6143, 0xF187, 
-	0x6144, 0xF189, 0x6145, 0xF18B, 0x6146, 0xF18D, 0x6147, 0xF18F, 
-	0x6148, 0xF191, 0x6149, 0xF193, 0x614A, 0xF195, 0x614B, 0xF197, 
-	0x614C, 0xF199, 0x614D, 0xF19B, 0x614E, 0xF19D, 0x614F, 0xF19F, 
-	0x6150, 0xF1A1, 0x6151, 0xF1A3, 0x6152, 0xF1A5, 0x6153, 0xF1A7, 
-	0x6154, 0xF1A9, 0x6155, 0xF1AB, 0x6156, 0xF1AD, 0x6157, 0xF1AF, 
-	0x6158, 0xF1B1, 0x6159, 0xF1B3, 0x615A, 0xF1B5, 0x615B, 0xF1B7, 
-	0x615C, 0xF1B9, 0x615D, 0xF1BB, 0x615E, 0xF1BD, 0x513F, 0xF1BF, 
-	0x6260, 0xF2C1, 0x6261, 0xF2C3, 0x6262, 0xF2C5, 0x6263, 0xF2C7, 
-	0x6264, 0xF2C9, 0x6265, 0xF2CB, 0x6266, 0xF2CD, 0x6267, 0xF2CF, 
-	0x6268, 0xF2D1, 0x6269, 0xF2D3, 0x626A, 0xF2D5, 0x626B, 0xF2D7, 
-	0x626C, 0xF2D9, 0x626D, 0xF2DB, 0x626E, 0xF2DD, 0x626F, 0xF2DF, 
-	0x6370, 0xF3E1, 0x6371, 0xF3E3, 0x6372, 0xF3E5, 0x6373, 0xF3E7, 
-	0x6374, 0xF3E9, 0x6375, 0xF3EB, 0x6376, 0xF3ED, 0x6377, 0xF3EF, 
-	0x6478, 0xF4F1, 0x6479, 0xF4F3, 0x647A, 0xF4F5, 0x647B, 0xF4F7, 
-	0x657C, 0xF5F9, 0x657D, 0xF5FB, 0xE67E, 0xF6FD, 0xE77F, 0xFDFF, 
-};
-
-
-static WORD * stuffs[] = { stuff0, stuff1, stuff2, stuff3, stuff4, stuff5 };
-WORD * destuffs[] = { destuff0, destuff1, destuff2, destuff3, destuff4, destuff5 };
-
-
-/*- AuverTech Telecom -------------------------------------------------------+
- |                                                                           |
- | @Function  : tpam_hdlc_encode                                             |
- | @Author    : Cyrille Boudon                                               |
- |                                                                           |
- +---------------------------------------------------------------------------+
- |                                                                           |
- | @Param     : BYTE *pbyBuffIn        IN,    array of bytes to encode       |
- | @Param     : BYTE *pbyBuffOut       OUT,   array of bytes encoded         |
- | @Param     : DWORD *pdwInitialShift INOUT, initial shift                  |
- | @Param     : DWORD dwLength         IN,    count of bytes to encode       |
- |                                                                           |
- | @Return    : DWORD                  count of bytes encoded                |
- |                                                                           |
- +------------------------------- @Abstract ---------------------------------+
- |                                                                           |
- | Bit stuffing of thz array pbyBuffIn with the insertion of a flag at the   |
- | beginning and the end, using the initial shift (due to the emission of    |
- | previous frames). The last byte can be used to insert flags (by outputting|
- | the flag N times) before the next frame. The initial shift is updated at  |
- | the end of the algorithm for the next frame. Its signification is: for the|
- | flags shifted like  "1100111111001111" *pdwInitialShift = 3. At the       |
- | beginning (for the first frame), the shift must be initialized to 0.      |
- |                                                                           |
- +---------------------------------------------------------------------------*/
-DWORD tpam_hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut,
-		       DWORD *pdwInitialShift, DWORD dwLength)
-{
-	DWORD	dwShifter;     // temporary variable
-	DWORD	dwShiftNb;     // shift due to the insertion of '0'
-	DWORD	dwState;       // count of '1' at the end of the current byte
-	DWORD	dwNb;          // length of the encoded array
-	BYTE	byCarry;       // carry due to the shift
-	BYTE	byNewCarry;    // temporary variable
-	BYTE	byCharIn;      // byte being encoded
-	BYTE	byCarryMSB;    // lost bit of the carry if dwShiftNb=7 and 2 '0' inserted
-	WORD	woDecal;       // temporary variable
-	WORD	woInfo;        // data read in the arrays
-	BOOL	bContinue;     // true until the two last bytes
-	BOOL	bContinue2;    // true until the last byte
-
-	bContinue = TRUE;
-	bContinue2 = TRUE;
-	dwShiftNb = 0;
-	byCarry = 0;
-	dwState = 0;
-	woDecal = 0x7E;
-	byCarryMSB = 0xFF;
-	dwNb = 1; // length to 1 to account for the first flag
-	
-	/*-----------------------------
-	 | insert the flag using the
-	 | shift given by
-	 | *pdwInitialShift)
-	 +-----------------------------*/
-	* pbyBuffOut ++ = 0x7E7E >> *pdwInitialShift;
-
-	/*-----------------------------
-	 | main loop
-	 +-----------------------------*/
-	while (dwLength--)
-	{
-		byCharIn = *pbyBuffIn ++;
-		
-/*-----------------------------
- | go back here to treat the
- | carry when its length
- | is over 7 and for the first
- | byte (with flag)
- +-----------------------------*/
-carry:
-
-		dwNb ++;
-
-		/*-----------------------------
-		 | shift the byte to get the
-		 | byte to encode (without
-		 | taking into account the
-		 | initial shift)
-		 +-----------------------------*/
-		if (dwShiftNb)
-		{
-			dwShifter = byCharIn << dwShiftNb;
-			byNewCarry = dwShifter >> 8;
-			byCharIn = dwShifter | byCarry;
-			byCarry = byNewCarry;
-		}
-
-		/*-----------------------------
-		 | get the data from the arrays
-		 | and take into account the
-		 | initial shift for the byte
-		 | to encode
-		 +-----------------------------*/
-		woInfo = stuffs[dwState][byCharIn];
-		woDecal |= (woInfo & 0x00FF) << 8;
-		* pbyBuffOut ++ = woDecal >> *pdwInitialShift;
-		woDecal = woInfo & 0x00FF;
-		dwState = woInfo >> 12;
-
-		/*-----------------------------
-		 | treat the lost bit if we had
-		 | a carry overflow
-		 +-----------------------------*/
-		if (byCarryMSB != 0xFF)
-		{
-			if (!dwShiftNb)
-			{
-				if(byCarryMSB)
-					byCarry = 1;
-				dwShiftNb = 1;
-			}
-			byCarryMSB = 0xFF;
-		}
-
-		/*-----------------------------
-		 | if one '0' get inserted, we
-		 | have to calculate the new
-		 | carry and the new shift
-		 +-----------------------------*/
-		if (woInfo & 0x0F00)
-		{
-			byCarryMSB = byCarry & 0x40;
-			byCarry <<= (woInfo & 0x0C00) >> 10;
-			byCarry |= (woInfo & 0x0300) >> 8;
-			dwShiftNb += (woInfo & 0x0C00) >> 10;
-		}
-
-		/*-----------------------------
-		 | if the carry is a whole byte
-		 | we use it as a byte to encode
-		 +-----------------------------*/
-		if (dwShiftNb > 7)
-		{
-			if (dwShiftNb == 8)
-				byCarryMSB = 0xFF;
-			dwShiftNb = 0;
-			byCharIn = byCarry;
-			byCarry = 0;
-			goto carry;
-		}
-
-		/*-----------------------------
-		 | at the end of the array
-		 +-----------------------------*/
-		if (!dwLength)
-		{
-			/*-----------------------------
-			 | take into account the bits
-			 | set in the carry
-			 +-----------------------------*/
-			if (bContinue)
-			{
-				bContinue = FALSE;
-				byCharIn = 0;
-				goto carry;
-			}
-			
-			/*-----------------------------
-			 | treat the last byte if we
-			 | had a carry overflow
-			 +-----------------------------*/
-			if (bContinue2 && ((8 - *pdwInitialShift) + dwShiftNb) > 7)
-			{
-				bContinue2 = FALSE;
-				byCharIn = 0;
-				goto carry;
-			}
-
-			/*-----------------------------
-			 | Calculate the new shift
-			 +-----------------------------*/
-			*pdwInitialShift = ((8 - *pdwInitialShift) + dwShiftNb)%8;
-
-			/*-----------------------------
-			 | Add a flag at the end of the
-			 | carry and a full flag
-			 +-----------------------------*/
-			pbyBuffOut--;
-			*pbyBuffOut++ |= 0x7E << *pdwInitialShift;
-			byCarry = 0x7E7E >> (8 - *pdwInitialShift);
-			*pbyBuffOut++ = byCarry;
-			*pbyBuffOut++ = byCarry;
-			dwNb += 2;
-		}
-	}
-
-	/*-------------------------------
-	 | Pad the array to a multiple
-	 | of 64 bytes.
-	 +-------------------------------*/
-	for(;dwNb%64;dwNb++)
-		*pbyBuffOut ++ = byCarry;
-
-	*pdwInitialShift = (8 - *pdwInitialShift)%8;
-
-	return dwNb;
-}
-
-
-
-/*- AuverTech Telecom -------------------------------------------------------+
- |                                                                           |
- | @Function  : tpam_hdlc_decode                                             |
- | @Author    : Cyrille Boudon                                               |
- |                                                                           |
- +---------------------------------------------------------------------------+
- |                                                                           |
- | @Param     : BYTE * pbyBuffIn  IN,  array of bytes to decode              |
- | @Param     : BYTE * pbyBuffOut OUT, array of decoded bytes                |
- | @Param     : DWORD dwLength    IN,  count of bytes to decode              |
- |                                                                           |
- | @Return    : DWORD             count of decoded bytes                     |
- |                                                                           |
- +------------------------------- @Abstract ---------------------------------+
- |                                                                           |
- | Bit de-stuffing of the array pbyBuffIn. There has to be at least 1 full   |
- | flag at the beginning. At the end there has to be a flag or an abort (more|
- | than 6 consecutive '1').                                                  |
- | If an abort is encountered, the returned count is '0'.                    |
- |                                                                           |
- +---------------------------------------------------------------------------*/
-DWORD tpam_hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength)
-{
-	BYTE	byCharIn;    // byte being decoded
-	BYTE	byCarry;     // current carry
-	WORD	woInfo;      // data read in the arrays
-	WORD	woNb1;       // count of '1' at the end of the previous byte
-	BYTE	byShift;     // shift of the first flag
-	DWORD	dwInit;      // temporary variable
-	DWORD	dwLengthOut; // count of the decoded bytes
-	BYTE	byLgCarry;   // count of used bits in the carry
-	BYTE	byLgByte;    // count of used bits in the decoded byte
-
-	/*-----------------------------
-	 | Find the 1st flag. At the end
-	 | of the loop dwShift is the count
-	 | of bits to reach the 1st bit
-	 | of the 1st flag.
-	 +-----------------------------*/
-	dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8) | (*(pbyBuffIn+2)<<16);
-	for (byShift=0;byShift<17;byShift++)
-	{
-		if (!(((dwInit>>byShift)&0xFF)^0x7E))
-		{
-			break;
-		}
-	}
-
-	/*-----------------------------
-	 | If at the end of the previous
-	 | loop dwShift = 17, it means
-	 | that no flag was found in the
-	 | first 3 bytes (normally
-	 | impossible impossible with the
-	 | DSP algorithm)
-	 +-----------------------------*/
-	if (byShift == 17)
-		return 0;
-
-	/*-----------------------------
-	 | Plase the array pointer after
-	 | the first flag. Update the
-	 | shift.
-	 +-----------------------------*/
-	pbyBuffIn += byShift/8 + 1;
-	dwLength -= byShift/8 + 1;
-	byShift %= 8;
-	
-	/*-----------------------------
-	 | Walk through the frame to
-	 | find the first data byte
-	 +-----------------------------*/
-	dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8);
-	while (!(((dwInit>>byShift)&0xFF)^0x7E))
-	{
-		pbyBuffIn ++;
-		dwLength --;
-		dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8);
-	}
-
-	dwLengthOut = 0;
-	byCarry = 0;
-	byLgCarry = 0;
-	byLgByte = 0;
-
-	/*-------------------------------
-	 | Treat the first byte
-	 +-------------------------------*/	
-	byCharIn = (*pbyBuffIn >> byShift) << byShift;
-	woInfo = destuffs[0][byCharIn];
-	byLgByte = ((woInfo & 0x7000) >> 12) + 1;
-	woNb1 = (woInfo & 0x0F00) >> 8;
-	dwLength --;
-	pbyBuffIn++;
-
-	if (woNb1 > 5)
-		return 0;
-
-	if (byLgByte - byShift == 8)
-	{
-		*pbyBuffOut ++ = woInfo;
-		dwLengthOut ++;
-	}
-	else
-	{
-		byCarry = woInfo << (8 - byLgByte);
-		byLgCarry = byLgByte - byShift;
-	}
-
-	/*-------------------------------
-	 | main loop
-	 +-------------------------------*/
-	while(dwLength --)
-	{
-		byCharIn = *pbyBuffIn ++;
-
-		woInfo = destuffs[woNb1][byCharIn];
-		byLgByte = ((woInfo & 0x7000) >> 12) + 1;
-		
-		/*-------------------------------
-		 | if the used bits in the carry
-		 | and the current byte makes
-		 | possible to output a full byte
-		 +-------------------------------*/
-		if (byLgByte + byLgCarry >= 8)
-		{
-			*pbyBuffOut ++ = ( (woInfo << 8) | byCarry) >> (8 - byLgCarry);
-			dwLengthOut ++;
-			byLgCarry += byLgByte - 8;
-			byCarry = woInfo << (8-byLgByte);
-		}
-		/*-------------------------------
-		 | if the used bits in the carry
-		 | and the current byte doesn't
-		 | make possible to output a full 
-		 | byte
-		 +-------------------------------*/
-		else
-		{
-			dwInit = (woInfo << 8) | byCarry;
-			byLgCarry += byLgByte;
-			byCarry = dwInit >> byLgByte;
-		}
-
-		woNb1 = (woInfo & 0x0F00) >> 8;
-
-		/*-------------------------------
-		 | if the current byte contains
-		 | six or more consecutive '1'
-		 +-------------------------------*/
-		if (woInfo & 0x8000)
-		{
-			byCarry = ((byCharIn << 8) | *(pbyBuffIn-2)) >> (8 - byLgCarry);
-			if (byCarry == 0x7E)
-				return dwLengthOut-1;
-			else
-				if (woNb1 > 6)
-					return 0;
-				else
-					if ((!(*pbyBuffIn & 1)) && (byLgCarry == 7))
-						return dwLengthOut;
-					else
-						return 0;
-		}
-	}
-
-	return dwLengthOut;
-}
-
diff --git a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_main.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* $Id: tpam_main.c,v 1.1.2.3 2001/09/23 22:25:03 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include "tpam.h"
-
-/* Local functions prototypes */
-static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit tpam_unregister_card(struct pci_dev *, tpam_card *);
-static void __devexit tpam_remove(struct pci_dev *);
-static int __init tpam_init(void);
-static void __exit tpam_exit(void);
-
-/* List of boards */
-static tpam_card *cards; /* = NULL; */
-/* Number of cards */
-static int cards_num;
-/* Configurable id of the driver */
-static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for TurboPAM ISDN cards");
-MODULE_AUTHOR("Stelian Pop");
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(id,"ID-String of the driver");
-module_param(id, charp, 0);
-
-/*
- * Finds a board by its driver ID.
- *
- * 	driverId: driver ID (as referenced by the IDSN link layer)
- *
- * Return: the tpam_card structure if found, NULL on error.
- */
-tpam_card *tpam_findcard(int driverid) {
-	tpam_card *p = cards;
-
-	while (p) {
-		if (p->id == driverid)
-			return p;
-		p = p->next;
-	}
-	return NULL;
-}
-
-/*
- * Finds a channel number by its ncoid.
- *
- * 	card: the board
- * 	ncoid: the NCO id
- *
- * Return: the channel number if found, TPAM_CHANNEL_INVALID if not.
- */
-u32 tpam_findchannel(tpam_card *card, u32 ncoid) {
-	int i;
-
-	for (i = 0; i < TPAM_NBCHANNEL; ++i)
-		if (card->channels[i].ncoid == ncoid)
-			return card->channels[i].num;
-	return TPAM_CHANNEL_INVALID;
-}
-
-/*
- * Initializes and registers a new TurboPAM card.
- *
- * 	dev: the PCI device
- * 	num: the board number
- *
- * Return: 0 if OK, <0 if error
- */
-static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
-	tpam_card *card, *c;
-	int i, err;
-
-	if ((err = pci_enable_device(dev))) {
-		printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
-			pci_name(dev));
-		return err;
-	}
-
-	/* allocate memory for the board structure */
-	if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) {
-		printk(KERN_ERR "TurboPAM: tpam_register_card: "
-		       "kmalloc failed!\n");
-		err = -ENOMEM;
-		goto err_out_disable_dev;
-	}
-
-	memset((char *)card, 0, sizeof(tpam_card));
-
-	card->irq = dev->irq;
-	spin_lock_init(&card->lock);
-	sprintf(card->interface.id, "%s%d", id, cards_num);
-
-	/* request interrupt */
-	if (request_irq(card->irq, &tpam_irq, SA_INTERRUPT | SA_SHIRQ, 
-			card->interface.id, card)) {
-		printk(KERN_ERR "TurboPAM: tpam_register_card: "
-		       "could not request irq %d\n", card->irq);
-		err = -EIO;
-		goto err_out_free_card;
-	}
-
-	/* remap board memory */
-	if (!(card->bar0 = ioremap(pci_resource_start(dev, 0),
-						   0x800000))) {
-		printk(KERN_ERR "TurboPAM: tpam_register_card: "
-		       "unable to remap bar0\n");
-		err = -EIO;
-		goto err_out_free_irq;
-	}
-
-	/* reset the board */
-	readl(card->bar0 + TPAM_RESETPAM_REGISTER);
-
-	/* initialisation magic :-( */
-	copy_to_pam_dword(card, 0x01800008, 0x00000030);
-	copy_to_pam_dword(card, 0x01800010, 0x00000030);
-	copy_to_pam_dword(card, 0x01800014, 0x42240822);
-	copy_to_pam_dword(card, 0x01800018, 0x07114000);
-	copy_to_pam_dword(card, 0x0180001c, 0x00000400);
-	copy_to_pam_dword(card, 0x01840070, 0x00000010);
-
-	/* fill the ISDN link layer structure */
-	card->interface.owner = THIS_MODULE;
-	card->interface.channels = TPAM_NBCHANNEL;
-	card->interface.maxbufsize = TPAM_MAXBUFSIZE;
-	card->interface.features = 
-		ISDN_FEATURE_P_EURO |
-		ISDN_FEATURE_L2_HDLC |
-		ISDN_FEATURE_L2_MODEM |
-		ISDN_FEATURE_L3_TRANS;
-	card->interface.hl_hdrlen = 0;
-	card->interface.command = tpam_command;
-	card->interface.writebuf_skb = tpam_writebuf_skb;
-	card->interface.writecmd = NULL;
-	card->interface.readstat = NULL;
-
-	/* register wrt the ISDN link layer */
-	if (!register_isdn(&card->interface)) {
-		printk(KERN_ERR "TurboPAM: tpam_register_card: "
-		       "unable to register %s\n", card->interface.id);
-		err = -EIO;
-		goto err_out_iounmap;
-	}
-	card->id = card->interface.channels;
-
-	/* initialize all channels */
-	for (i = 0; i < TPAM_NBCHANNEL; ++i) {
-		card->channels[i].num = i;
-		card->channels[i].card = card;
-		card->channels[i].ncoid = TPAM_NCOID_INVALID;
-		card->channels[i].hdlc = 0;
-		card->channels[i].realhdlc = 0;
-		card->channels[i].hdlcshift = 0;
-		skb_queue_head_init(&card->channels[i].sendq);
-	}
-
-	/* initialize the rest of board structure */
-	card->channels_used = 0;
-	card->channels_tested = 0;
-	card->running = 0;
-	card->busy = 0;
-	card->roundrobin = 0;
-	card->loopmode = 0;
-	skb_queue_head_init(&card->sendq);
-	skb_queue_head_init(&card->recvq);
-	INIT_WORK(&card->recv_tq, (void *) (void *) tpam_recv_tq, card);
-	INIT_WORK(&card->send_tq, (void *) (void *) tpam_send_tq, card);
-
-	/* add the board at the end of the list of boards */
-	card->next = NULL;
-	if (cards) {
-		c = cards;
-		while (c->next)
-			c = c->next;
-		c->next = card;
-	}
-	else
-		cards = card;
-
-	++cards_num;
-	pci_set_drvdata(dev, card);
-
-	return 0;
-
-err_out_iounmap:
-	iounmap(card->bar0);
-
-err_out_free_irq:
-	free_irq(card->irq, card);
-
-err_out_free_card:
-	kfree(card);
-
-err_out_disable_dev:
-	pci_disable_device(dev);
-	return err;
-}
-
-/*
- * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc).
- *
- * 	card: the board.
- */
-static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *card) {
-	isdn_ctrl cmd;
-
-	/* prevent the ISDN link layer that the driver will be unloaded */
-	cmd.command = ISDN_STAT_UNLOAD;
-	cmd.driver = card->id;
-	(* card->interface.statcallb)(&cmd);
-
-	/* release interrupt */
-	free_irq(card->irq, card);
-
-	/* release mapped memory */
-	iounmap(card->bar0);
-
-	pci_disable_device(pcidev);
-}
-
-/*
- * Stops the driver.
- */
-static void __devexit tpam_remove(struct pci_dev *pcidev) {
-	tpam_card *card = pci_get_drvdata(pcidev);
-	tpam_card *c;
-
-	/* remove from the list of cards */
-	if (card == cards)
-		cards = cards->next;
-	else {
-		c = cards;
-		while (c->next != card) 
-			c = c->next;
-		c->next = c->next->next;
-	}
-	
-	/* unregister each board */
-	tpam_unregister_card(pcidev, card);
-	
-	/* and free the board structure itself */
-	kfree(card);
-}
-
-static struct pci_device_id tpam_pci_tbl[] = {
-	{ PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_TURBOPAM,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
-
-static struct pci_driver tpam_driver = {
-	.name		= "tpam",
-	.id_table	= tpam_pci_tbl,
-	.probe		= tpam_probe,
-	.remove		= __devexit_p(tpam_remove),
-};
-
-static int __init tpam_init(void) {
-	int ret;
-	
-	ret = pci_module_init(&tpam_driver);
-	if (ret)
-		return ret;
-	printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n", 
-	       cards_num, (cards_num > 1) ? "s" : "");
-	return 0;
-}
-
-static void __exit tpam_exit(void) {
-	pci_unregister_driver(&tpam_driver);
-	printk(KERN_INFO "TurboPAM: driver unloaded\n");
-}
-
-/* Module entry points */
-module_init(tpam_init);
-module_exit(tpam_exit);
-
diff --git a/drivers/isdn/tpam/tpam_memory.c b/drivers/isdn/tpam/tpam_memory.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_memory.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* $Id: tpam_memory.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "tpam.h"
-
-/*
- * Write a DWORD into the board memory.
- *
- * 	card: the board
- * 	addr: the address (in the board memory)
- * 	val: the value to put into the memory.
- */
-void copy_to_pam_dword(tpam_card *card, u32 addr, u32 val) {
-
-	/* set the page register */
-	writel(addr | TPAM_PAGE_SIZE, 
-	       card->bar0 + TPAM_PAGE_REGISTER);
-
-	/* write the value */
-	writel(val, card->bar0 + (addr & TPAM_PAGE_SIZE));
-}
-
-/*
- * Write n bytes into the board memory. The count of bytes will be rounded
- * up to a multiple of 4.
- *
- * 	card: the board
- * 	to: the destination address (in the board memory)
- * 	from: the source address (in the kernel memory)
- * 	n: number of bytes
- */
-void copy_to_pam(tpam_card *card, u32 to, const void *from, u32 n) {
-	u32 page, offset, count;
-
-	/* need to write in dword ! */
-	while (n & 3) n++;
-
-	while (n) {
-		page = to | TPAM_PAGE_SIZE;
-		offset = to & TPAM_PAGE_SIZE;
-		count = n < TPAM_PAGE_SIZE - offset
-				? n
-				: TPAM_PAGE_SIZE - offset;
-
-		/* set the page register */
-		writel(page, card->bar0 + TPAM_PAGE_REGISTER);
-
-		/* copy the data */
-		memcpy_toio(card->bar0 + offset, from, count);
-		
-		from += count;
-		to += count;
-		n -= count;
-	}
-}
-
-/*
- * Read a DWORD from the board memory.
- *
- * 	card: the board
- * 	addr: the address (in the board memory)
- *
- * Return: the value read into the memory.
- */
-u32 copy_from_pam_dword(tpam_card *card, u32 addr) {
-
-	/* set the page register */
-	writel(((u32)addr) | TPAM_PAGE_SIZE, 
-	       card->bar0 + TPAM_PAGE_REGISTER);
-
-	/* read the data */
-	return readl(card->bar0 + (addr & TPAM_PAGE_SIZE));
-}
-
-/*
- * Read n bytes from the board memory.
- *
- * 	card: the board
- * 	to: the destination address (in the kernel memory)
- * 	from: the source address (in the board memory)
- * 	n: number of bytes
- */
-void copy_from_pam(tpam_card *card, void *to, u32 from, u32 n) {
-	u32 page, offset, count;
-
-	while (n) {
-		page = from | TPAM_PAGE_SIZE;
-		offset = from & TPAM_PAGE_SIZE;
-		count = n < TPAM_PAGE_SIZE - offset 
-				? n 
-				: TPAM_PAGE_SIZE - offset;
-
-		/* set the page register */
-		writel(page, card->bar0 + TPAM_PAGE_REGISTER);
-
-		/* read the data */
-		memcpy_fromio(to, card->bar0 + offset, count);
-		
-		from += count;
-		to += count;
-		n -= count;
-	}
-}
-
-/*
- * Read n bytes from the board memory and writes them into the user memory.
- *
- * 	card: the board
- * 	to: the destination address (in the userspace memory)
- * 	from: the source address (in the board memory)
- * 	n: number of bytes
- *
- * Return: 0 if OK, <0 if error.
- */
-int copy_from_pam_to_user(tpam_card *card, void __user *to, u32 from, u32 n) {
-	void *page;
-	u32 count;
-
-	/* allocate a free page for the data transfer */
-	if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
-		printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): "
-		       "get_free_page failed\n");
-		return -ENOMEM;
-	}
-
-	while (n) {
-		count = n < PAGE_SIZE ? n : PAGE_SIZE;
-
-		/* copy data from the board into the kernel memory */
-		spin_lock_irq(&card->lock);
-		copy_from_pam(card, page, from, count);
-		spin_unlock_irq(&card->lock);
-
-		/* copy it from the kernel memory into the user memory */
-		if (copy_to_user(to, page, count)) {
-			
-			/* this can fail... */
-			free_page((unsigned long)page);
-			return -EFAULT;
-		}
-		from += count;
-		to += count;
-		n -= count;
-	}
-
-	/* release allocated memory */
-	free_page((unsigned long)page);
-	return 0;
-}
-
-/*
- * Read n bytes from the user memory and writes them into the board memory.
- *
- * 	card: the board
- * 	to: the destination address (in the board memory)
- * 	from: the source address (in the userspace memory)
- * 	n: number of bytes
- *
- * Return: 0 if OK, <0 if error.
- */
-int copy_from_user_to_pam(tpam_card *card, u32 to, const void __user *from, u32 n) {
-	void *page;
-	u32 count;
-
-	/* allocate a free page for the data transfer */
-	if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
-		printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): "
-		       "get_free_page failed\n");
-		return -ENOMEM;
-	}
-
-	while (n) {
-		count = n < PAGE_SIZE ? n : PAGE_SIZE;
-
-		/* copy data from the user memory into the kernel memory */
-		if (copy_from_user(page, from, count)) {
-			/* this can fail... */
-			free_page((unsigned long)page);
-			return -EFAULT;
-		}
-
-		/* copy it from the kernel memory into the board memory */
-		spin_lock_irq(&card->lock);
-		copy_to_pam(card, to, page, count);
-		spin_unlock_irq(&card->lock);
-
-		from += count;
-		to += count;
-		n -= count;
-	}
-
-	/* release allocated memory */
-	free_page((unsigned long)page);
-	return 0;
-}
-
-/*
- * Verify if we have the permission to read or writes len bytes at the
- * address address from/to the board memory.
- *
- * 	address: the start address (in the board memory)
- * 	len: number of bytes
- *
- * Return: 0 if OK, <0 if error.
- */
-int tpam_verify_area(u32 address, u32 len) {
-
-	if (address < TPAM_RESERVEDAREA1_START)
-		return (address + len <= TPAM_RESERVEDAREA1_START) ? 0 : -1;
-
-	if (address <= TPAM_RESERVEDAREA1_END)
-		return -1;
-
-	if (address < TPAM_RESERVEDAREA2_START)
-		return (address + len <= TPAM_RESERVEDAREA2_START) ? 0 : -1;
-
-	if (address <= TPAM_RESERVEDAREA2_END)
-		return -1;
-
-	if (address < TPAM_RESERVEDAREA3_START)
-		return (address + len <= TPAM_RESERVEDAREA3_START) ? 0 : -1;
-
-	if (address <= TPAM_RESERVEDAREA3_END)
-		return -1;
-
-	if (address < TPAM_RESERVEDAREA4_START)
-		return (address + len <= TPAM_RESERVEDAREA4_START) ? 0 : -1;
-
-	if (address <= TPAM_RESERVEDAREA4_END)
-		return -1;
-
-	return 0;
-}
-
diff --git a/drivers/isdn/tpam/tpam_nco.c b/drivers/isdn/tpam/tpam_nco.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_nco.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/* $Id: tpam_nco.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. 
- * (Kernel Driver - Low Level NCO Manipulation)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "tpam.h"
-
-/* Local function prototypes */
-static struct sk_buff *build_NCOpacket(u16, u16, u16, u16, u16);
-static int extract_NCOParameter(struct sk_buff *, u8, void *, u16);
-
-/*
- * Build a NCO packet (PCI message).
- *
- * 	messageID: the message type (ID_*)
- * 	size: size of the TLV block
- * 	data_size: size of the data block
- * 	ack: packet needs to send ack upon send
- * 	ack_size: size of data to be acknowledged upon send
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-static struct sk_buff *build_NCOpacket(u16 messageID, u16 size, 
-				       u16 data_size, u16 ack, 
-				       u16 ack_size) {
-	struct sk_buff *skb;
-	skb_header *h;
-	pci_mpb *p;
-	u16 finalsize;
-
-	/* reserve enough space for the sk_buff header, the pci * header, 
-	 * size bytes for the TLV block, size bytes for the data and 4 more
-	 * bytes in order to make sure we can write dwords to the board. */
-	finalsize = sizeof(skb_header) + sizeof(pci_mpb) + size + data_size + 4;
-
-	/* allocate the sk_buff */
-	if (!(skb = alloc_skb(finalsize, GFP_ATOMIC))) {
-		printk(KERN_ERR "TurboPAM(make_NCOpacket): alloc_skb failed\n");
-		return NULL;
-	}
-
-	/* construct the skb_header */
-	h = (skb_header *)skb_put(skb, sizeof(skb_header));
-	h->size = sizeof(pci_mpb) + size;
-	h->data_size = data_size;
-	h->ack = ack;
-	h->ack_size = ack_size;
-
-	/* construct the pci_mpb */
-	p = (pci_mpb *)skb_put(skb, sizeof(pci_mpb));
-	p->exID = 0;
-	p->flags = 0;
-	p->errorCode = 0;
-	p->messageID = messageID;
-	p->maximumBlockTLVSize = MPB_MAXIMUMBLOCKTLVSIZE;
-	p->actualBlockTLVSize = size;
-	p->maximumDataSize = MPB_MAXIMUMDATASIZE;
-	p->actualDataSize = data_size;
-	return skb;
-}
-
-/*
- * Build a ACreateNCOReq message.
- *
- * 	phone: the local phone number.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_ACreateNCOReq(const u8 *phone) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_ACreateNCOReq): phone=%s\n", phone);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0))) 
-		return NULL;
-
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 3);
-	*tlv = PAR_NCOType; 
-	*(tlv+1) = 1;
-	*(tlv+2) = 5;	/* mistery value... */
-
-	tlv = (u8 *)skb_put(skb, 4);
-	*tlv = PAR_U3Protocol;
-	*(tlv+1) = 2;
-	*(tlv+2) = 4;	/* no level 3 protocol */
-	*(tlv+3) = 1;	/* HDLC in level 2 */
-
-	tlv = (u8 *)skb_put(skb, 3);
-	*tlv = PAR_Cdirection;
-	*(tlv+1) = 1;
-	*(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
-
-	tlv = (u8 *)skb_put(skb, 3);
-	*tlv = PAR_Udirection;
-	*(tlv+1) = 1;
-	*(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
-
-	tlv = (u8 *)skb_put(skb, 4);
-	*tlv = PAR_BearerCap;
-	*(tlv+1) = 2;
-	*(tlv+2) = 0x88;
-	*(tlv+3) = 0x90;
-
-	tlv = (u8 *)skb_put(skb, 6 + strlen(phone));
-	*tlv = PAR_CallingNumber;
-	*(tlv+1) = strlen(phone) + 4;
-	*(tlv+2) = 0x01; /* international */
-	*(tlv+3) = 0x01; /* isdn */
-	*(tlv+4) = 0x00;
-	*(tlv+5) = 0x00;
-	memcpy(tlv + 6, phone, strlen(phone));
-
-	return skb;
-}
-
-/*
- * Build a ADestroyNCOReq message.
- *
- * 	ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_ADestroyNCOReq(u32 ncoid) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_ADestroyNCOReq): ncoid=%lu\n",
-		(unsigned long)ncoid);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_ADestroyNCOReq, 6, 0, 0, 0)))
-		return NULL;
-	
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	return skb;
-}
-
-/*
- * Build a CConnectReq message.
- *
- * 	ncoid: the NCO id.
- * 	called: the destination phone number
- * 	hdlc: type of connection: 1 (HDLC) or 0(modem)
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%d\n",
-		(unsigned long)ncoid, called, hdlc);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_CConnectReq, 20 + strlen(called), 0, 0, 0)))
-		return NULL;
-	
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	tlv = (u8 *)skb_put(skb, 4 + strlen(called));
-	*tlv = PAR_CalledNumber;
-	*(tlv+1) = strlen(called) + 2;
-	*(tlv+2) = 0x01; /* international */
-	*(tlv+3) = 0x01; /* isdn */
-	memcpy(tlv + 4, called, strlen(called));
-
-	tlv = (u8 *)skb_put(skb, 3);
-	*tlv = PAR_BearerCap;
-	*(tlv+1) = 1;
-	*(tlv+2) = hdlc ? 0x88 /* HDLC */ : 0x80 /* MODEM */;
-
-	tlv = (u8 *)skb_put(skb, 4);
-	*tlv = PAR_HLC;
-	*(tlv+1) = 2;
-	*(tlv+2) = 0x2;
-	*(tlv+3) = 0x7f;
-
-	tlv = (u8 *)skb_put(skb, 3);
-	*tlv = PAR_Facility;
-	*(tlv+1) = 1;
-	*(tlv+2) = 2;
-
-	return skb;
-}
-
-/*
- * Build a CConnectRsp message.
- *
- * 	ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_CConnectRsp(u32 ncoid) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_CConnectRsp): ncoid=%lu\n",
-		(unsigned long)ncoid);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_CConnectRsp, 6, 0, 0, 0)))
-		return NULL;
-
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	return skb;
-}
-
-/*
- * Build a CDisconnectReq message.
- *
- * 	ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_CDisconnectReq(u32 ncoid) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_CDisconnectReq): ncoid=%lu\n",
-		(unsigned long)ncoid);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_CDisconnectReq, 6, 0, 0, 0)))
-		return NULL;
-
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	return skb;
-}
-
-/*
- * Build a CDisconnectRsp message.
- *
- * 	ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_CDisconnectRsp(u32 ncoid) {
-	struct sk_buff *skb;
-	u8 *tlv;
-
-	pr_debug("TurboPAM(build_CDisconnectRsp): ncoid=%lu\n",
-		(unsigned long)ncoid);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_CDisconnectRsp, 6, 0, 0, 0)))
-		return NULL;
-
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	return skb;
-}
-
-/*
- * Build a U3DataReq message.
- *
- * 	ncoid: the NCO id.
- * 	data: the data to be send
- * 	len: length of the data
- * 	ack: send ack upon send
- * 	ack_size: size of data to be acknowledged upon send
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
-struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len,
-				u16 ack, u16 ack_size) {
-	struct sk_buff *skb;
-	u8 *tlv;
-	void *p;
-
-	pr_debug("TurboPAM(build_U3DataReq): "
-		"ncoid=%lu, len=%d, ack=%d, ack_size=%d\n", 
-		(unsigned long)ncoid, len, ack, ack_size);
-
-	/* build the NCO packet */
-	if (!(skb = build_NCOpacket(ID_U3DataReq, 6, len, ack, ack_size)))
-		return NULL;
-
-	/* add the parameters */
-	tlv = (u8 *)skb_put(skb, 6);
-	*tlv = PAR_NCOID;
-	*(tlv+1) = 4;
-	*((u32 *)(tlv+2)) = ncoid;
-
-	p = skb_put(skb, len);
-	memcpy(p, data, len);
-
-	return skb;
-}
-
-/*
- * Extract a parameter from a TLV block.
- *
- * 	skb: sk_buff containing the PCI message
- * 	type: parameter to search for (PARAM_*)
- * 	value: to be filled with the value of the parameter
- * 	len: maximum length of the parameter value
- *
- * Return: 0 if OK, <0 if error.
- */
-static int extract_NCOParameter(struct sk_buff *skb, u8 type, 
-				void *value, u16 len) {
-	void *buffer = (void *)skb->data;
-	pci_mpb *p;
-	void * bufferend;
-	u8 valtype;
-	u16 vallen;
-
-	/* calculate the start and end of the TLV block */
-	buffer += sizeof(skb_header);
-	p = (pci_mpb *)buffer;
-	buffer += sizeof(pci_mpb);
-	bufferend = buffer + p->actualBlockTLVSize;
-
-	/* walk through the parameters */
-	while (buffer < bufferend) {
-
-		/* parameter type */
-		valtype = *((u8 *)buffer++);
-		/* parameter length */
-		vallen = *((u8 *)buffer++);
-		if (vallen == 0xff) {
-			/* parameter length is on 2 bytes */
-			vallen = *((u8 *)buffer++);
-			vallen <<= 8;
-			vallen |= *((u8 *)buffer++);
-		}
-		/* got the right parameter */
-		if (valtype == type) {
-			/* not enough space for returning the value */
-			if (vallen > len)
-				return -1;
-			/* OK, return it */
-			memcpy(value, buffer, vallen);
-			return 0;
-		}
-		buffer += vallen;
-	}
-	return -1;
-}
-
-/*
- * Parse a ACreateNCOCnf message.
- *
- * 	skb: the sk_buff containing the message
- * 	status: to be filled with the status field value
- * 	ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
-
-	/* extract the status */
-	if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
-		printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
-		       "CompletionStatus not found\n");
-		return -1;
-	}
-
-	if (*status) {
-		pr_debug("TurboPAM(parse_ACreateNCOCnf): status=%d\n", *status);
-		return 0;
-	}
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	pr_debug("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%d\n",
-		(unsigned long)*ncoid, *status);
-	return 0;
-}
-
-/*
- * Parse a ADestroyNCOCnf message. Not used in the driver.
- *
- * 	skb: the sk_buff containing the message
- * 	status: to be filled with the status field value
- * 	ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
-
-	/* extract the status */
-	if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
-		printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
-		       "CompletionStatus not found\n");
-		return -1;
-	}
-
-	if (*status) {
-		pr_debug("TurboPAM(parse_ADestroyNCOCnf): status=%d\n", *status);
-		return 0;
-	}
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	pr_debug("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%d\n",
-		(unsigned long)*ncoid, *status);
-	return 0;
-}
-
-/*
- * Parse a CConnectCnf message.
- *
- * 	skb: the sk_buff containing the message
- * 	ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) {
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CConnectCnf): "
-		       "NCOID not found\n");
-		return -1;
-	}
-	pr_debug("TurboPAM(parse_CConnectCnf): ncoid=%lu\n",
-		(unsigned long)*ncoid);
-	return 0;
-}
-
-/*
- * Parse a CConnectInd message.
- *
- * 	skb: the sk_buff containing the message
- * 	ncoid: to be filled with the ncoid field value
- * 	hdlc: to be filled with 1 if the incoming connection is a HDLC one,
- * 		with 0 if the incoming connection is a modem one
- * 	calling: to be filled with the calling phone number value
- * 	called: to be filled with the called phone number value
- * 	plan: to be filled with the plan value
- * 	screen: to be filled with the screen value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc, 
-		      u8 *calling, u8 *called, u8 *plan, u8 *screen) {
-	u8 phone[PHONE_MAXIMUMSIZE + 4];
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	/* extract the bearer capability field */
-	if (extract_NCOParameter(skb, PAR_BearerCap, hdlc, 1)) {
-		printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
-		       "BearerCap not found\n");
-		return -1;
-	}
-	*hdlc = (*hdlc == 0x88) ? 1 : 0;
-
-	/* extract the calling number / plan / screen */
-	if (extract_NCOParameter(skb, PAR_CallingNumber, phone, 
-				 PHONE_MAXIMUMSIZE + 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
-		       "CallingNumber not found\n");
-		return -1;
-	}
-	memcpy(calling, phone + 4, PHONE_MAXIMUMSIZE);
-	*plan = phone[1];
-	*screen = phone[3];
-
-	/* extract the called number */
-	if (extract_NCOParameter(skb, PAR_CalledNumber, phone, 
-				 PHONE_MAXIMUMSIZE + 2)) {
-		printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
-		       "CalledNumber not found\n");
-		return -1;
-	}
-	memcpy(called, phone + 2, PHONE_MAXIMUMSIZE);
-
-	pr_debug("TurboPAM(parse_CConnectInd): "
-		"ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%s\n",
-		(unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called);
-	return 0;
-}
-
-/*
- * Parse a CDisconnectCnf message.
- *
- * 	skb: the sk_buff containing the message
- * 	ncoid: to be filled with the ncoid field value
- * 	causetopuf: to be filled with the cause field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	/* extract the cause of disconnection */
-	if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
-		       "CauseToPUF not found\n");
-		return -1;
-	}
-
-	pr_debug("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lu\n",
-		(unsigned long)*ncoid, (unsigned long)*causetopuf);
-	return 0;
-}
-
-/*
- * Parse a CDisconnectInd message.
- *
- * 	skb: the sk_buff containing the message
- * 	ncoid: to be filled with the ncoid field value
- * 	causetopuf: to be filled with the cause field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	/* extract the cause of disconnection */
-	if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
-		       "CauseToPUF not found\n");
-		return -1;
-	}
-
-	pr_debug("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lu\n",
-		(unsigned long)*ncoid, (unsigned long)*causetopuf);
-	return 0;
-}
-
-/*
- * Parse a U3ReadyToReceiveInd message.
- *
- * 	skb: the sk_buff containing the message
- * 	ncoid: to be filled with the ncoid field value
- * 	ready: to be filled with the ready field value
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) {
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
-		printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
-		       "NCOID not found\n");
-		return -1;
-	}
-
-	/* extract the ready flag */
-	if (extract_NCOParameter(skb, PAR_ReadyFlag, ready, 1)) {
-		printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
-		       "ReadyFlag not found\n");
-		return -1;
-	}
-
-	pr_debug("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%d\n",
-		(unsigned long)*ncoid, *ready);
-	return 0;
-}
-
-/*
- * Parse a U3DataInd message.
- *
- * 	skb: the sk_buff containing the message + data
- * 	ncoid: to be filled with the ncoid field value
- * 	data: to be filled with the data 
- * 	ready: to be filled with the data length
- *
- * Return: 0 if OK, <0 if error.
- */
-int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) {
-	pci_mpb *p;
-
-	/* extract the ncoid */
-	if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4) == -1) {
-		printk(KERN_ERR "TurboPAM(parse_U3DataInd): NCOID not found\n");
-		return -1;
-	}
-
-	/* get a pointer to the beginning of the data block and its length */
-	p = (pci_mpb *)(skb->data + sizeof(skb_header));
-	*len = p->actualDataSize;
-	skb_pull(skb, 
-		 sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize);
-	*data = skb->data;
-
-	pr_debug("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%d\n",
-		(unsigned long)*ncoid, *len);
-	return 0;
-}
-
diff --git a/drivers/isdn/tpam/tpam_queues.c b/drivers/isdn/tpam/tpam_queues.c
deleted file mode 100644
--- a/drivers/isdn/tpam/tpam_queues.c
+++ /dev/null
@@ -1,401 +0,0 @@
-/* $Id: tpam_queues.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "tpam.h"
-
-/* Local function prototype */
-static int tpam_sendpacket(tpam_card *card, tpam_channel *channel);
-
-/*
- * Queue a message to be send to the card when possible.
- *
- * 	card: the board
- * 	skb: the sk_buff containing the message.
- */
-void tpam_enqueue(tpam_card *card, struct sk_buff *skb) {
-
-	pr_debug("TurboPAM(tpam_enqueue): card=%d\n", card->id);
-
-	/* queue the sk_buff on the board's send queue */
-	skb_queue_tail(&card->sendq, skb);
-
-	/* queue the board's send task struct for immediate treatment */
-	schedule_work(&card->send_tq);
-}
-
-/*
- * Queue a data message to be send to the card when possible.
- *
- * 	card: the board
- * 	skb: the sk_buff containing the message and the data. This parameter
- * 		can be NULL if we want just to trigger the send of queued 
- * 		messages.
- */
-void tpam_enqueue_data(tpam_channel *channel, struct sk_buff *skb) {
-	
-	pr_debug("TurboPAM(tpam_enqueue_data): card=%d, channel=%d\n",
-		channel->card->id, channel->num);
-
-	/* if existant, queue the sk_buff on the channel's send queue */
-	if (skb)
-		skb_queue_tail(&channel->sendq, skb);
-
-	/* queue the channel's send task struct for immediate treatment */
-	schedule_work(&channel->card->send_tq);
-}
-
-/*
- * IRQ handler.
- *
- * If a message comes from the board we read it, construct a sk_buff containing
- * the message and we queue the sk_buff on the board's receive queue, and we
- * trigger the execution of the board's receive task queue.
- *
- * If a message ack comes from the board we can go on and send a new message,
- * so we trigger the execution of the board's send task queue.
- *
- * 	irq: the irq number
- * 	dev_id: the registered board to the irq
- * 	regs: not used.
- */
-irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	tpam_card *card = (tpam_card *)dev_id;
-	u32 ackupload, uploadptr;
-	u32 waiting_too_long;
-	u32 hpic;
-	struct sk_buff *skb;
-	pci_mpb mpb;
-	skb_header *skbh;
-
-	pr_debug("TurboPAM(tpam_irq): IRQ received, card=%d\n", card->id);
-
-	/* grab the board lock */
-	spin_lock(&card->lock);
-
-	/* get the message type */
-	ackupload = copy_from_pam_dword(card, TPAM_ACKUPLOAD_REGISTER);
-
-	/* acknowledge the interrupt */
-	copy_to_pam_dword(card, TPAM_INTERRUPTACK_REGISTER, 0);
-	readl(card->bar0 + TPAM_HINTACK_REGISTER);
-
-	if (!ackupload) {
-		/* it is a new message from the board */
-		
-		pr_debug("TurboPAM(tpam_irq): message received, card=%d\n",
-			card->id);
-
-		/* get the upload pointer */
-		uploadptr = copy_from_pam_dword(card, 
-					    TPAM_UPLOADPTR_REGISTER);
-		
-		/* get the beginning of the message (pci_mpb part) */
-		copy_from_pam(card, &mpb, uploadptr, sizeof(pci_mpb));
-
-		/* allocate the sk_buff */
-		if (!(skb = alloc_skb(sizeof(skb_header) + sizeof(pci_mpb) + 
-				      mpb.actualBlockTLVSize + 
-				      mpb.actualDataSize, GFP_ATOMIC))) {
-			printk(KERN_ERR "TurboPAM(tpam_irq): "
-			       "alloc_skb failed\n");
-			spin_unlock(&card->lock);
-			return IRQ_HANDLED;
-		}
-
-		/* build the skb_header */
-		skbh = (skb_header *)skb_put(skb, sizeof(skb_header));
-		skbh->size = sizeof(pci_mpb) + mpb.actualBlockTLVSize;
-		skbh->data_size = mpb.actualDataSize;
-		skbh->ack = 0;
-		skbh->ack_size = 0;
-
-		/* copy the pci_mpb into the sk_buff */
-		memcpy(skb_put(skb, sizeof(pci_mpb)), &mpb, sizeof(pci_mpb));
-
-		/* copy the TLV block into the sk_buff */
-		copy_from_pam(card, skb_put(skb, mpb.actualBlockTLVSize),
-			      uploadptr + sizeof(pci_mpb), 
-			      mpb.actualBlockTLVSize);
-
-		/* if existent, copy the data block into the sk_buff */
-		if (mpb.actualDataSize)
-			copy_from_pam(card, skb_put(skb, mpb.actualDataSize),
-				uploadptr + sizeof(pci_mpb) + 4096, 
-				mpb.actualDataSize);
-
-		/* wait for the board to become ready */
-		waiting_too_long = 0;
-		do {
-			hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
-			if (waiting_too_long++ > 0xfffffff) {
-				kfree_skb(skb); 
-				spin_unlock(&card->lock);
-				printk(KERN_ERR "TurboPAM(tpam_irq): "
-						"waiting too long...\n");
-				return IRQ_HANDLED;
-			}
-		} while (hpic & 0x00000002);
-
-		/* acknowledge the message */
-        	copy_to_pam_dword(card, TPAM_ACKDOWNLOAD_REGISTER, 
-				  0xffffffff);
-        	readl(card->bar0 + TPAM_DSPINT_REGISTER);
-
-		/* release the board lock */
-		spin_unlock(&card->lock);
-	
-		if (mpb.messageID == ID_U3ReadyToReceiveInd) {
-			/* this message needs immediate treatment */
-			tpam_recv_U3ReadyToReceiveInd(card, skb);
-			kfree_skb(skb);
-		}
-		else {
-			/* put the message in the receive queue */
-			skb_queue_tail(&card->recvq, skb);
-			schedule_work(&card->recv_tq);
-		}
-		return IRQ_HANDLED;
-	}
-	else {
-		/* it is a ack from the board */
-
-		pr_debug("TurboPAM(tpam_irq): message acknowledged, card=%d\n",
-			card->id);
-
-		/* board is not busy anymore */
-		card->busy = 0;
-		
-		/* release the lock */
-		spin_unlock(&card->lock);
-
-		/* schedule the send queue for execution */
-		schedule_work(&card->send_tq);
-	}
-	return IRQ_HANDLED;
-}
-
-/*
- * Run the board's receive task queue, dispatching each message on the queue,
- * to its treatment function.
- *
- * 	card: the board.
- */
-void tpam_recv_tq(tpam_card *card) {
-	pci_mpb *p;
-	struct sk_buff *skb;
-
-	/* for each message on the receive queue... */
-        while ((skb = skb_dequeue(&card->recvq))) {
-
-		/* point to the pci_mpb block */
-		p = (pci_mpb *)(skb->data + sizeof(skb_header));
-
-		/* dispatch the message */
-		switch (p->messageID) {
-			case ID_ACreateNCOCnf:
-				tpam_recv_ACreateNCOCnf(card, skb);
-				break;
-			case ID_ADestroyNCOCnf:
-				tpam_recv_ADestroyNCOCnf(card, skb);
-				break;
-			case ID_CConnectCnf:
-				tpam_recv_CConnectCnf(card, skb);
-				break;
-			case ID_CConnectInd:
-				tpam_recv_CConnectInd(card, skb);
-				break;
-			case ID_CDisconnectInd:
-				tpam_recv_CDisconnectInd(card, skb);
-				break;
-			case ID_CDisconnectCnf:
-				tpam_recv_CDisconnectCnf(card, skb);
-				break;
-			case ID_U3DataInd:
-				tpam_recv_U3DataInd(card, skb);
-				break;
-			default:
-				pr_debug("TurboPAM(tpam_recv_tq): "
-					"unknown messageID %d, card=%d\n", 
-					p->messageID, card->id);
-				break;
-		}
-		/* free the sk_buff */
-		kfree_skb(skb);
-	}
-}
-
-/*
- * Run the board's send task queue. If there is a message in the board's send
- * queue, it gets sended. If not, it examines each channel (one at the time,
- * using a round robin algorithm). For each channel, if there is a message
- * in the channel's send queue, it gets sended. This function sends only one
- * message, it does not consume all the queue.
- */
-void tpam_send_tq(tpam_card *card) {
-	int i;
-
-	/* first, try to send a packet from the board's send queue */
-	if (tpam_sendpacket(card, NULL))
-		return;
-
-	/* then, try each channel, in a round-robin manner */
-	for (i=card->roundrobin; i<card->roundrobin+card->channels_used; i++) {
-		if (tpam_sendpacket(card, 
-				    &card->channels[i % card->channels_used])) {
-			card->roundrobin = (i + 1) % card->channels_used;
-			return;
-		}
-	}
-}
-
-/*
- * Try to send a packet from the board's send queue or from the channel's
- * send queue.
- *
- * 	card: the board.
- * 	channel: the channel (if NULL, the packet will be taken from the 
- * 		board's send queue. If not, it will be taken from the 
- * 		channel's send queue.
- *
- * Return: 0 if tpam_send_tq must try another card/channel combination
- * 	(meaning that no packet has been send), 1 if no more packets
- * 	can be send at that time (a packet has been send or the card is
- * 	still busy from a previous send).
- */
-static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
-        struct sk_buff *skb;
-	u32 hpic;
-        u32 downloadptr;
-	skb_header *skbh;
-	u32 waiting_too_long;
-
-	pr_debug("TurboPAM(tpam_sendpacket), card=%d, channel=%d\n",
-		card->id, channel ? channel->num : -1);
-
-	if (channel) {
-		/* dequeue a packet from the channel's send queue */
-		if (!(skb = skb_dequeue(&channel->sendq))) {
-			pr_debug("TurboPAM(tpam_sendpacket): "
-				"card=%d, channel=%d, no packet\n", 
-				card->id, channel->num);
-			return 0;
-		}
-
-		/* if the channel is not ready to receive, requeue the packet
-		 * and return 0 to give a chance to another channel */
-		if (!channel->readytoreceive) {
-			pr_debug("TurboPAM(tpam_sendpacket): "
-				"card=%d, channel=%d, channel not ready\n",
-				card->id, channel->num);
-			skb_queue_head(&channel->sendq, skb);
-			return 0;
-		}
-
-		/* grab the board lock */
-		spin_lock_irq(&card->lock);
-
-		/* if the board is busy, requeue the packet and return 1 since
-		 * there is no need to try another channel */
-		if (card->busy) {
-			pr_debug("TurboPAM(tpam_sendpacket): "
-				"card=%d, channel=%d, card busy\n",
-				card->id, channel->num);
-			skb_queue_head(&channel->sendq, skb);
-			spin_unlock_irq(&card->lock);
-			return 1;
-		}
-	}
-	else {
-		/* dequeue a packet from the board's send queue */
-		if (!(skb = skb_dequeue(&card->sendq))) {
-			pr_debug("TurboPAM(tpam_sendpacket): "
-				"card=%d, no packet\n", card->id);
-			return 0;
-		}
-
-		/* grab the board lock */
-		spin_lock_irq(&card->lock);
-
-		/* if the board is busy, requeue the packet and return 1 since
-		 * there is no need to try another channel */
-		if (card->busy) {
-			pr_debug("TurboPAM(tpam_sendpacket): "
-				"card=%d, card busy\n", card->id);
-			skb_queue_head(&card->sendq, skb);
-			spin_unlock_irq(&card->lock);
-			return 1;
-		}
-	}
-
-	/* wait for the board to become ready */
-	waiting_too_long = 0;
-	do {
-		hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
-		if (waiting_too_long++ > 0xfffffff) {
-			spin_unlock_irq(&card->lock);
-			printk(KERN_ERR "TurboPAM(tpam_sendpacket): "
-					"waiting too long...\n");
-			return 1;
-		}
-	} while (hpic & 0x00000002);
-
-	skbh = (skb_header *)skb->data;
-	pr_debug("TurboPAM(tpam_sendpacket): "
-		"card=%d, card ready, sending %d/%d bytes\n", 
-		card->id, skbh->size, skbh->data_size);
-
-	/* get the board's download pointer */
-       	downloadptr = copy_from_pam_dword(card, TPAM_DOWNLOADPTR_REGISTER);
-
-	/* copy the packet to the board at the downloadptr location */
-       	copy_to_pam(card, downloadptr, skb->data + sizeof(skb_header), 
-		    skbh->size);
-	if (skbh->data_size)
-		/* if there is some data in the packet, copy it too */
-		copy_to_pam(card, downloadptr + sizeof(pci_mpb) + 4096,
-			    skb->data + sizeof(skb_header) + skbh->size, 
-			    skbh->data_size);
-
-	/* card will become busy right now */
-	card->busy = 1;
-
-	/* interrupt the board */
-	copy_to_pam_dword(card, TPAM_ACKDOWNLOAD_REGISTER, 0);
-	readl(card->bar0 + TPAM_DSPINT_REGISTER);
-
-	/* release the lock */
-	spin_unlock_irq(&card->lock);
-
-	/* if a data ack was requested by the ISDN link layer, send it now */
-	if (skbh->ack) {
-		isdn_ctrl ctrl;
-		ctrl.driver = card->id;
-		ctrl.command = ISDN_STAT_BSENT;
-		ctrl.arg = channel->num;
-		ctrl.parm.length = skbh->ack_size;
-		(* card->interface.statcallb)(&ctrl);
-	}
-
-	/* free the sk_buff */
-	kfree_skb(skb);
-
-	return 1;
-}
-
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -78,6 +78,14 @@ config ADB_PMU
 	  this device; you should do so if your machine is one of those
 	  mentioned above.
 
+config PMAC_SMU
+	bool "Support for SMU  based PowerMacs"
+	depends on PPC_PMAC64
+	help
+	  This option adds support for the newer G5 iMacs and PowerMacs based
+	  on the "SMU" system control chip which replaces the old PMU.
+	  If you don't know, say Y.
+
 config PMAC_PBOOK
 	bool "Power management support for PowerBooks"
 	depends on ADB_PMU
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
 obj-$(CONFIG_ADB_PMU)		+= via-pmu.o
 obj-$(CONFIG_ADB_CUDA)		+= via-cuda.o
 obj-$(CONFIG_PMAC_APM_EMU)	+= apm_emu.o
+obj-$(CONFIG_PMAC_SMU)		+= smu.o
 
 obj-$(CONFIG_ADB)		+= adb.o
 obj-$(CONFIG_ADB_MACII)		+= via-macii.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -755,7 +755,7 @@ static int adb_release(struct inode *ino
 static ssize_t adb_read(struct file *file, char __user *buf,
 			size_t count, loff_t *ppos)
 {
-	int ret;
+	int ret = 0;
 	struct adbdev_state *state = file->private_data;
 	struct adb_request *req;
 	wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait,current);
@@ -765,9 +765,8 @@ static ssize_t adb_read(struct file *fil
 		return -EINVAL;
 	if (count > sizeof(req->reply))
 		count = sizeof(req->reply);
-	ret = verify_area(VERIFY_WRITE, buf, count);
-	if (ret)
-		return ret;
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
 
 	req = NULL;
 	spin_lock_irqsave(&state->lock, flags);
@@ -824,9 +823,8 @@ static ssize_t adb_write(struct file *fi
 		return -EINVAL;
 	if (adb_controller == NULL)
 		return -ENXIO;
-	ret = verify_area(VERIFY_READ, buf, count);
-	if (ret)
-		return ret;
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
 
 	req = (struct adb_request *) kmalloc(sizeof(struct adb_request),
 					     GFP_KERNEL);
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -555,6 +555,42 @@ adbhid_buttons_input(unsigned char *data
 #endif /* CONFIG_PMAC_BACKLIGHT */
 			input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down);
 			break;
+
+		case 0xc:	/* videomode switch */
+			input_report_key(&adbhid[id]->input, KEY_SWITCHVIDEOMODE, down);
+			break;
+
+		case 0xd:	/* keyboard illumination toggle */
+			input_report_key(&adbhid[id]->input, KEY_KBDILLUMTOGGLE, down);
+			break;
+
+		case 0xe:	/* keyboard illumination decrease */
+			input_report_key(&adbhid[id]->input, KEY_KBDILLUMDOWN, down);
+			break;
+
+		case 0xf:
+			switch (data[1]) {
+			case 0x8f:
+			case 0x0f:
+				/* keyboard illumination increase */
+				input_report_key(&adbhid[id]->input, KEY_KBDILLUMUP, down);
+				break;
+
+			case 0x7f:
+			case 0xff:
+				/* keypad overlay toogle */
+				break;
+
+			default:
+				printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+				       data[0], data[1], data[2], data[3]);
+				break;
+			}
+			break;
+		default:
+			printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+			       data[0], data[1], data[2], data[3]);
+			break;
 		}
 	  }
 	  break;
@@ -775,6 +811,10 @@ adbhid_input_register(int id, int defaul
 			set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit);
 			set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit);
 			set_bit(KEY_EJECTCD, adbhid[id]->input.keybit);
+			set_bit(KEY_SWITCHVIDEOMODE, adbhid[id]->input.keybit);
+			set_bit(KEY_KBDILLUMTOGGLE, adbhid[id]->input.keybit);
+			set_bit(KEY_KBDILLUMDOWN, adbhid[id]->input.keybit);
+			set_bit(KEY_KBDILLUMUP, adbhid[id]->input.keybit);
 			break;
 		}
 		if (adbhid[id]->name[0])
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -61,7 +61,7 @@ anslcd_write( struct file * file, const 
 	printk(KERN_DEBUG "LCD: write\n");
 #endif
 
-	if ( verify_area(VERIFY_READ, buf, count) )
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 	for ( i = *ppos; count > 0; ++i, ++p, --count ) 
 	{
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -106,7 +106,7 @@ static void macio_device_shutdown(struct
 		drv->shutdown(macio_dev);
 }
 
-static int macio_device_suspend(struct device *dev, u32 state)
+static int macio_device_suspend(struct device *dev, pm_message_t state)
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
 	struct macio_driver * drv = to_macio_driver(dev->driver);
@@ -617,7 +617,7 @@ static int __init macio_module_init (voi
 #ifdef CONFIG_PCI
 	int rc;
 
-	rc = pci_module_init(&macio_pci_driver);
+	rc = pci_register_driver(&macio_pci_driver);
 	if (rc)
 		return rc;
 #endif /* CONFIG_PCI */
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
--- a/drivers/macintosh/macserial.c
+++ b/drivers/macintosh/macserial.c
@@ -155,7 +155,7 @@ static void dbdma_flush(volatile struct 
 static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
 static void dma_init(struct mac_serial * info);
-static void rxdma_start(struct mac_serial * info, int current);
+static void rxdma_start(struct mac_serial * info, int curr);
 static void rxdma_to_tty(struct mac_serial * info);
 
 /*
@@ -762,10 +762,10 @@ static int startup(struct mac_serial * i
 	return 0;
 }
 
-static _INLINE_ void rxdma_start(struct mac_serial * info, int current)
+static _INLINE_ void rxdma_start(struct mac_serial * info, int curr)
 {
 	volatile struct dbdma_regs *rd = &info->rx->dma;
-	volatile struct dbdma_cmd *cd = info->rx_cmds[current];
+	volatile struct dbdma_cmd *cd = info->rx_cmds[curr];
 
 //printk(KERN_DEBUG "SCC: rxdma_start\n");
 
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -98,11 +98,6 @@ int media_bay_count = 0;
 #define MB_IDE_READY(i)	((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
 #endif
 
-/* Note: All delays are not in milliseconds and converted to HZ relative
- * values by the macro below
- */
-#define MS_TO_HZ(ms)	((ms * HZ + 999) / 1000)
-
 /*
  * Wait that number of ms between each step in normal polling mode
  */
@@ -384,7 +379,7 @@ static inline void __pmac set_mb_power(s
 		bay->state = mb_powering_down;
 		MBDBG("mediabay%d: powering down\n", bay->index);
 	}
-	bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+	bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
 }
 
 static void __pmac poll_media_bay(struct media_bay_info* bay)
@@ -393,8 +388,8 @@ static void __pmac poll_media_bay(struct
 
 	if (id == bay->last_value) {
 		if (id != bay->content_id) {
-			bay->value_count += MS_TO_HZ(MB_POLL_DELAY);
-			if (bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
+			bay->value_count += msecs_to_jiffies(MB_POLL_DELAY);
+			if (bay->value_count >= msecs_to_jiffies(MB_STABLE_DELAY)) {
 				/* If the device type changes without going thru
 				 * "MB_NO", we force a pass by "MB_NO" to make sure
 				 * things are properly reset
@@ -504,7 +499,7 @@ static void __pmac media_bay_step(int i)
 
 	/* If timer expired or polling IDE busy, run state machine */
 	if ((bay->state != mb_ide_waiting) && (bay->timer != 0)) {
-		bay->timer -= MS_TO_HZ(MB_POLL_DELAY);
+		bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);
 		if (bay->timer > 0)
 			return;
 		bay->timer = 0;
@@ -517,13 +512,13 @@ static void __pmac media_bay_step(int i)
 	    		set_mb_power(bay, 0);
 	    		break;
 	    	}
-	    	bay->timer = MS_TO_HZ(MB_RESET_DELAY);
+	    	bay->timer = msecs_to_jiffies(MB_RESET_DELAY);
 	    	bay->state = mb_enabling_bay;
 		MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
 		break;
 	case mb_enabling_bay:
 		bay->ops->un_reset(bay);
-	    	bay->timer = MS_TO_HZ(MB_SETUP_DELAY);
+	    	bay->timer = msecs_to_jiffies(MB_SETUP_DELAY);
 	    	bay->state = mb_resetting;
 		MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
 	    	break;
@@ -537,7 +532,7 @@ static void __pmac media_bay_step(int i)
 #ifdef CONFIG_BLK_DEV_IDE
 		MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
 		bay->ops->un_reset_ide(bay);
-	    	bay->timer = MS_TO_HZ(MB_IDE_WAIT);
+	    	bay->timer = msecs_to_jiffies(MB_IDE_WAIT);
 	    	bay->state = mb_ide_resetting;
 #else
 		printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
@@ -547,7 +542,7 @@ static void __pmac media_bay_step(int i)
 	    
 #ifdef CONFIG_BLK_DEV_IDE
 	case mb_ide_resetting:
-	    	bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT);
+	    	bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);
 	    	bay->state = mb_ide_waiting;
 		MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
 	    	break;
@@ -583,7 +578,7 @@ static void __pmac media_bay_step(int i)
 			}
 			break;
 	    	} else if (bay->timer > 0)
-			bay->timer -= MS_TO_HZ(MB_POLL_DELAY);
+			bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);
 	    	if (bay->timer <= 0) {
 			printk("\nIDE Timeout in bay %d !, IDE state is: 0x%02x\n",
 			       i, readb(bay->cd_base + 0x70));
@@ -641,8 +636,7 @@ static int __pmac media_bay_task(void *x
 			up(&media_bays[i].lock);
 		}
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(MS_TO_HZ(MB_POLL_DELAY));
+		msleep_interruptible(MB_POLL_DELAY);
 		if (signal_pending(current))
 			return 0;
 	}
@@ -691,7 +685,7 @@ static int __devinit media_bay_attach(st
 	msleep(MB_POWER_DELAY);
 	bay->content_id = MB_NO;
 	bay->last_value = bay->ops->content(bay);
-	bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
 	bay->state = mb_empty;
 	do {
 		msleep(MB_POLL_DELAY);
@@ -710,7 +704,7 @@ static int __devinit media_bay_attach(st
 
 }
 
-static int __pmac media_bay_suspend(struct macio_dev *mdev, u32 state)
+static int __pmac media_bay_suspend(struct macio_dev *mdev, pm_message_t state)
 {
 	struct media_bay_info	*bay = macio_get_drvdata(mdev);
 
@@ -747,8 +741,8 @@ static int __pmac media_bay_resume(struc
 		}
 	       	set_mb_power(bay, 1);
 	       	bay->last_value = bay->content_id;
-	       	bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
-	       	bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+	       	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
+	       	bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
 #ifdef CONFIG_BLK_DEV_IDE
 	       	bay->cd_retry = 0;
 #endif
diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c
--- a/drivers/macintosh/nvram.c
+++ b/drivers/macintosh/nvram.c
@@ -45,7 +45,7 @@ static ssize_t read_nvram(struct file *f
 	unsigned int i;
 	char __user *p = buf;
 
-	if (verify_area(VERIFY_WRITE, buf, count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 	if (*ppos >= NVRAM_SIZE)
 		return 0;
@@ -63,7 +63,7 @@ static ssize_t write_nvram(struct file *
 	const char __user *p = buf;
 	char c;
 
-	if (verify_area(VERIFY_READ, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
 	if (*ppos >= NVRAM_SIZE)
 		return 0;
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
new file mode 100644
--- /dev/null
+++ b/drivers/macintosh/smu.c
@@ -0,0 +1,364 @@
+/*
+ * PowerMac G5 SMU driver
+ *
+ * Copyright 2004 J. Mayer <l_indien@magic.fr>
+ * Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+/*
+ * For now, this driver includes:
+ * - RTC get & set
+ * - reboot & shutdown commands
+ * all synchronous with IRQ disabled (ugh)
+ *
+ * TODO:
+ *   rework in a way the PMU driver works, that is asynchronous
+ *   with a queue of commands. I'll do that as soon as I have an
+ *   SMU based machine at hand. Some more cleanup is needed too,
+ *   like maybe fitting it into a platform device, etc...
+ *   Also check what's up with cache coherency, and if we really
+ *   can't do better than flushing the cache, maybe build a table
+ *   of command len/reply len like the PMU driver to only flush
+ *   what is actually necessary.
+ *   --BenH.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/bootmem.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/smu.h>
+#include <asm/sections.h>
+#include <asm/abs_addr.h>
+
+#define DEBUG_SMU 1
+
+#ifdef DEBUG_SMU
+#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
+#else
+#define DPRINTK(fmt, args...) do { } while (0)
+#endif
+
+/*
+ * This is the command buffer passed to the SMU hardware
+ */
+struct smu_cmd_buf {
+	u8 cmd;
+	u8 length;
+	u8 data[0x0FFE];
+};
+
+struct smu_device {
+	spinlock_t		lock;
+	struct device_node	*of_node;
+	int			db_ack;		/* doorbell ack GPIO */
+	int			db_req;		/* doorbell req GPIO */
+	u32 __iomem		*db_buf;	/* doorbell buffer */
+	struct smu_cmd_buf	*cmd_buf;	/* command buffer virtual */
+	u32			cmd_buf_abs;	/* command buffer absolute */
+};
+
+/*
+ * I don't think there will ever be more than one SMU, so
+ * for now, just hard code that
+ */
+static struct smu_device	*smu;
+
+/*
+ * SMU low level communication stuff
+ */
+static inline int smu_cmd_stat(struct smu_cmd_buf *cmd_buf, u8 cmd_ack)
+{
+	rmb();
+	return cmd_buf->cmd == cmd_ack && cmd_buf->length != 0;
+}
+
+static inline u8 smu_save_ack_cmd(struct smu_cmd_buf *cmd_buf)
+{
+	return (~cmd_buf->cmd) & 0xff;
+}
+
+static void smu_send_cmd(struct smu_device *dev)
+{
+	/* SMU command buf is currently cacheable, we need a physical
+	 * address. This isn't exactly a DMA mapping here, I suspect
+	 * the SMU is actually communicating with us via i2c to the
+	 * northbridge or the CPU to access RAM.
+	 */
+	writel(dev->cmd_buf_abs, dev->db_buf);
+
+	/* Ring the SMU doorbell */
+	pmac_do_feature_call(PMAC_FTR_WRITE_GPIO, NULL, dev->db_req, 4);
+	pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, dev->db_req, 4);
+}
+
+static int smu_cmd_done(struct smu_device *dev)
+{
+	unsigned long wait = 0;
+	int gpio;
+
+	/* Check the SMU doorbell */
+	do  {
+		gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO,
+					    NULL, dev->db_ack);
+		if ((gpio & 7) == 7)
+			return 0;
+		udelay(100);
+	} while(++wait < 10000);
+
+	printk(KERN_ERR "SMU timeout !\n");
+	return -ENXIO;
+}
+
+static int smu_do_cmd(struct smu_device *dev)
+{
+	int rc;
+	u8 cmd_ack;
+
+	DPRINTK("SMU do_cmd %02x len=%d %02x\n",
+		dev->cmd_buf->cmd, dev->cmd_buf->length,
+		dev->cmd_buf->data[0]);
+
+	cmd_ack = smu_save_ack_cmd(dev->cmd_buf);
+
+	/* Clear cmd_buf cache lines */
+	flush_inval_dcache_range((unsigned long)dev->cmd_buf,
+				 ((unsigned long)dev->cmd_buf) +
+				 sizeof(struct smu_cmd_buf));
+	smu_send_cmd(dev);
+	rc = smu_cmd_done(dev);
+	if (rc == 0)
+		rc = smu_cmd_stat(dev->cmd_buf, cmd_ack) ? 0 : -1;
+
+	DPRINTK("SMU do_cmd %02x len=%d %02x => %d (%02x)\n",
+		dev->cmd_buf->cmd, dev->cmd_buf->length,
+		dev->cmd_buf->data[0], rc, cmd_ack);
+
+	return rc;
+}
+
+/* RTC low level commands */
+static inline int bcd2hex (int n)
+{
+	return (((n & 0xf0) >> 4) * 10) + (n & 0xf);
+}
+
+static inline int hex2bcd (int n)
+{
+	return ((n / 10) << 4) + (n % 10);
+}
+
+#if 0
+static inline void smu_fill_set_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
+{
+	cmd_buf->cmd = 0x8e;
+	cmd_buf->length = 8;
+	cmd_buf->data[0] = 0x00;
+	memset(cmd_buf->data + 1, 0, 7);
+}
+
+static inline void smu_fill_get_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
+{
+	cmd_buf->cmd = 0x8e;
+	cmd_buf->length = 1;
+	cmd_buf->data[0] = 0x01;
+}
+
+static inline void smu_fill_dis_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
+{
+	cmd_buf->cmd = 0x8e;
+	cmd_buf->length = 1;
+	cmd_buf->data[0] = 0x02;
+}
+#endif
+
+static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf,
+					struct rtc_time *time)
+{
+	cmd_buf->cmd = 0x8e;
+	cmd_buf->length = 8;
+	cmd_buf->data[0] = 0x80;
+	cmd_buf->data[1] = hex2bcd(time->tm_sec);
+	cmd_buf->data[2] = hex2bcd(time->tm_min);
+	cmd_buf->data[3] = hex2bcd(time->tm_hour);
+	cmd_buf->data[4] = time->tm_wday;
+	cmd_buf->data[5] = hex2bcd(time->tm_mday);
+	cmd_buf->data[6] = hex2bcd(time->tm_mon) + 1;
+	cmd_buf->data[7] = hex2bcd(time->tm_year - 100);
+}
+
+static inline void smu_fill_get_rtc_cmd(struct smu_cmd_buf *cmd_buf)
+{
+	cmd_buf->cmd = 0x8e;
+	cmd_buf->length = 1;
+	cmd_buf->data[0] = 0x81;
+}
+
+static void smu_parse_get_rtc_reply(struct smu_cmd_buf *cmd_buf,
+				    struct rtc_time *time)
+{
+	time->tm_sec = bcd2hex(cmd_buf->data[0]);
+	time->tm_min = bcd2hex(cmd_buf->data[1]);
+	time->tm_hour = bcd2hex(cmd_buf->data[2]);
+	time->tm_wday = bcd2hex(cmd_buf->data[3]);
+	time->tm_mday = bcd2hex(cmd_buf->data[4]);
+	time->tm_mon = bcd2hex(cmd_buf->data[5]) - 1;
+	time->tm_year = bcd2hex(cmd_buf->data[6]) + 100;
+}
+
+int smu_get_rtc_time(struct rtc_time *time)
+{
+	unsigned long flags;
+	int rc;
+
+	if (smu == NULL)
+		return -ENODEV;
+
+	memset(time, 0, sizeof(struct rtc_time));
+	spin_lock_irqsave(&smu->lock, flags);
+	smu_fill_get_rtc_cmd(smu->cmd_buf);
+	rc = smu_do_cmd(smu);
+	if (rc == 0)
+		smu_parse_get_rtc_reply(smu->cmd_buf, time);
+	spin_unlock_irqrestore(&smu->lock, flags);
+
+	return rc;
+}
+
+int smu_set_rtc_time(struct rtc_time *time)
+{
+	unsigned long flags;
+	int rc;
+
+	if (smu == NULL)
+		return -ENODEV;
+
+	spin_lock_irqsave(&smu->lock, flags);
+	smu_fill_set_rtc_cmd(smu->cmd_buf, time);
+	rc = smu_do_cmd(smu);
+	spin_unlock_irqrestore(&smu->lock, flags);
+
+	return rc;
+}
+
+void smu_shutdown(void)
+{
+	const unsigned char *command = "SHUTDOWN";
+	unsigned long flags;
+
+	if (smu == NULL)
+		return;
+
+	spin_lock_irqsave(&smu->lock, flags);
+	smu->cmd_buf->cmd = 0xaa;
+	smu->cmd_buf->length = strlen(command);
+	strcpy(smu->cmd_buf->data, command);
+	smu_do_cmd(smu);
+	for (;;)
+		;
+	spin_unlock_irqrestore(&smu->lock, flags);
+}
+
+void smu_restart(void)
+{
+	const unsigned char *command = "RESTART";
+	unsigned long flags;
+
+	if (smu == NULL)
+		return;
+
+	spin_lock_irqsave(&smu->lock, flags);
+	smu->cmd_buf->cmd = 0xaa;
+	smu->cmd_buf->length = strlen(command);
+	strcpy(smu->cmd_buf->data, command);
+	smu_do_cmd(smu);
+	for (;;)
+		;
+	spin_unlock_irqrestore(&smu->lock, flags);
+}
+
+int smu_present(void)
+{
+	return smu != NULL;
+}
+
+
+int smu_init (void)
+{
+	struct device_node *np;
+	u32 *data;
+
+        np = of_find_node_by_type(NULL, "smu");
+        if (np == NULL)
+		return -ENODEV;
+
+	if (smu_cmdbuf_abs == 0) {
+		printk(KERN_ERR "SMU: Command buffer not allocated !\n");
+		return -EINVAL;
+	}
+
+	smu = alloc_bootmem(sizeof(struct smu_device));
+	if (smu == NULL)
+		return -ENOMEM;
+	memset(smu, 0, sizeof(*smu));
+
+	spin_lock_init(&smu->lock);
+	smu->of_node = np;
+	/* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
+	 * 32 bits value safely
+	 */
+	smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
+	smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs);
+
+	np = of_find_node_by_name(NULL, "smu-doorbell");
+	if (np == NULL) {
+		printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
+		goto fail;
+	}
+	data = (u32 *)get_property(np, "reg", NULL);
+	of_node_put(np);
+	if (data == NULL) {
+		printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n");
+		goto fail;
+	}
+
+	/* Current setup has one doorbell GPIO that does both doorbell
+	 * and ack. GPIOs are at 0x50, best would be to find that out
+	 * in the device-tree though.
+	 */
+	smu->db_req = 0x50 + *data;
+	smu->db_ack = 0x50 + *data;
+
+	/* Doorbell buffer is currently hard-coded, I didn't find a proper
+	 * device-tree entry giving the address. Best would probably to use
+	 * an offset for K2 base though, but let's do it that way for now.
+	 */
+	smu->db_buf = ioremap(0x8000860c, 0x1000);
+	if (smu->db_buf == NULL) {
+		printk(KERN_ERR "SMU: Can't map doorbell buffer pointer !\n");
+		goto fail;
+	}
+
+	sys_ctrler = SYS_CTRLER_SMU;
+	return 0;
+
+ fail:
+	smu = NULL;
+	return -ENXIO;
+
+}
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -39,15 +39,16 @@
 #define MANUAL_MASK  0xe0
 #define AUTO_MASK    0x20
 
-static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, cpu, gpu */
-static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */
+static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */
+static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */
 static u8 MANUAL_MODE[2] = {0x5c, 0x5d};       
 static u8 REM_CONTROL[2] = {0x00, 0x40};
 static u8 FAN_SPEED[2]   = {0x28, 0x2a};
 static u8 FAN_SPD_SET[2] = {0x30, 0x31};
 
-static u8 default_limits_local[3] = {70, 50, 70};    /* local, cpu, gpu */
-static u8 default_limits_chip[3] = {80, 65, 80};    /* local, cpu, gpu */
+static u8 default_limits_local[3] = {70, 50, 70};    /* local, sensor1, sensor2 */
+static u8 default_limits_chip[3] = {80, 65, 80};    /* local, sensor1, sensor2 */
+static char *sensor_location[3] = {NULL, NULL, NULL};
 
 static int limit_adjust = 0;
 static int fan_speed = -1;
@@ -58,7 +59,7 @@ MODULE_DESCRIPTION("Driver for ADT746x t
 MODULE_LICENSE("GPL");
 
 module_param(limit_adjust, int, 0644);
-MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 cpu, 70 gpu) "
+MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 sensor1, 70 sensor2) "
 		 "by N degrees.");
 
 module_param(fan_speed, int, 0644);
@@ -213,10 +214,10 @@ static void write_fan_speed(struct therm
 	if (th->last_speed[fan] != speed) {
 		if (speed == -1)
 			printk(KERN_DEBUG "adt746x: Setting speed to automatic "
-				"for %s fan.\n", fan?"GPU":"CPU");
+				"for %s fan.\n", sensor_location[fan+1]);
 		else
 			printk(KERN_DEBUG "adt746x: Setting speed to %d "
-				"for %s fan.\n", speed, fan?"GPU":"CPU");
+				"for %s fan.\n", speed, sensor_location[fan+1]);
 	} else
 		return;
 	
@@ -300,11 +301,11 @@ static void update_fans_speed (struct th
 			printk(KERN_DEBUG "adt746x: setting fans speed to %d "
 					 "(limit exceeded by %d on %s) \n",
 					new_speed, var,
-					fan_number?"GPU/pwr":"CPU");
+					sensor_location[fan_number+1]);
 			write_both_fan_speed(th, new_speed);
 			th->last_var[fan_number] = var;
 		} else if (var < -2) {
-			/* don't stop fan if GPU/power is cold and CPU is not
+			/* don't stop fan if sensor2 is cold and sensor1 is not
 			 * so cold (lastvar >= -1) */
 			if (i == 2 && lastvar < -1) {
 				if (th->last_speed[fan_number] != 0)
@@ -318,7 +319,7 @@ static void update_fans_speed (struct th
 
 		if (started)
 			return; /* we don't want to re-stop the fan
-				* if CPU is heating and GPU/power is not */
+				* if sensor1 is heating and sensor2 is not */
 	}
 }
 
@@ -353,7 +354,7 @@ static int monitor_task(void *arg)
 
 static void set_limit(struct thermostat *th, int i)
 {
-		/* Set CPU limit higher to avoid powerdowns */ 
+		/* Set sensor1 limit higher to avoid powerdowns */
 		th->limits[i] = default_limits_chip[i] + limit_adjust;
 		write_reg(th, LIMIT_REG[i], th->limits[i]);
 		
@@ -461,6 +462,12 @@ static ssize_t show_##name(struct device
 	return sprintf(buf, "%d\n", data);			\
 }
 
+#define BUILD_SHOW_FUNC_STR(name, data)				\
+static ssize_t show_##name(struct device *dev, char *buf)	\
+{								\
+	return sprintf(buf, "%s\n", data);			\
+}
+
 #define BUILD_SHOW_FUNC_FAN(name, data)				\
 static ssize_t show_##name(struct device *dev, char *buf)       \
 {								\
@@ -476,7 +483,7 @@ static ssize_t store_##name(struct devic
 	int val;						\
 	int i;							\
 	val = simple_strtol(buf, NULL, 10);			\
-	printk(KERN_INFO "Adjusting limits by %d°C\n", val);	\
+	printk(KERN_INFO "Adjusting limits by %d degrees\n", val);	\
 	limit_adjust = val;					\
 	for (i=0; i < 3; i++)					\
 		set_limit(thermostat, i);			\
@@ -495,35 +502,41 @@ static ssize_t store_##name(struct devic
 	return n;						\
 }
 
-BUILD_SHOW_FUNC_INT(cpu_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(gpu_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(cpu_limit,		 thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(gpu_limit,		 thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit,		 thermostat->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit,		 thermostat->limits[2])
+BUILD_SHOW_FUNC_STR(sensor1_location,		 sensor_location[1])
+BUILD_SHOW_FUNC_STR(sensor2_location,		 sensor_location[2])
 
 BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
-BUILD_SHOW_FUNC_FAN(cpu_fan_speed,	 0)
-BUILD_SHOW_FUNC_FAN(gpu_fan_speed,	 1)
+BUILD_SHOW_FUNC_FAN(sensor1_fan_speed,	 0)
+BUILD_SHOW_FUNC_FAN(sensor2_fan_speed,	 1)
 
 BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
 BUILD_SHOW_FUNC_INT(limit_adjust,	 limit_adjust)
 BUILD_STORE_FUNC_DEG(limit_adjust,	 thermostat)
 		
-static DEVICE_ATTR(cpu_temperature,	S_IRUGO,
-		   show_cpu_temperature,NULL);
-static DEVICE_ATTR(gpu_temperature,	S_IRUGO,
-		   show_gpu_temperature,NULL);
-static DEVICE_ATTR(cpu_limit,		S_IRUGO,
-		   show_cpu_limit,	NULL);
-static DEVICE_ATTR(gpu_limit,		S_IRUGO,
-		   show_gpu_limit,	NULL);
+static DEVICE_ATTR(sensor1_temperature,	S_IRUGO,
+		   show_sensor1_temperature,NULL);
+static DEVICE_ATTR(sensor2_temperature,	S_IRUGO,
+		   show_sensor2_temperature,NULL);
+static DEVICE_ATTR(sensor1_limit, S_IRUGO,
+		   show_sensor1_limit,	NULL);
+static DEVICE_ATTR(sensor2_limit, S_IRUGO,
+		   show_sensor2_limit,	NULL);
+static DEVICE_ATTR(sensor1_location, S_IRUGO,
+		   show_sensor1_location, NULL);
+static DEVICE_ATTR(sensor2_location, S_IRUGO,
+		   show_sensor2_location, NULL);
 
 static DEVICE_ATTR(specified_fan_speed,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
 		   show_specified_fan_speed,store_specified_fan_speed);
 
-static DEVICE_ATTR(cpu_fan_speed,	S_IRUGO,
-		   show_cpu_fan_speed,	NULL);
-static DEVICE_ATTR(gpu_fan_speed,	S_IRUGO,
-		   show_gpu_fan_speed,	NULL);
+static DEVICE_ATTR(sensor1_fan_speed,	S_IRUGO,
+		   show_sensor1_fan_speed,	NULL);
+static DEVICE_ATTR(sensor2_fan_speed,	S_IRUGO,
+		   show_sensor2_fan_speed,	NULL);
 
 static DEVICE_ATTR(limit_adjust,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
 		   show_limit_adjust,	store_limit_adjust);
@@ -534,6 +547,7 @@ thermostat_init(void)
 {
 	struct device_node* np;
 	u32 *prop;
+	int i = 0, offset = 0;
 	
 	np = of_find_node_by_name(NULL, "fan");
 	if (!np)
@@ -545,16 +559,47 @@ thermostat_init(void)
 	else
 		return -ENODEV;
 
+	prop = (u32 *)get_property(np, "hwsensor-params-version", NULL);
+	printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
+			 (*prop == 1)?"":"un");
+	if (*prop != 1)
+		return -ENODEV;
+
 	prop = (u32 *)get_property(np, "reg", NULL);
 	if (!prop)
 		return -ENODEV;
-	therm_bus = ((*prop) >> 8) & 0x0f;
+
+	/* look for bus either by path or using "reg" */
+	if (strstr(np->full_name, "/i2c-bus@") != NULL) {
+		const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
+		therm_bus = tmp_bus[0]-'0';
+	} else {
+		therm_bus = ((*prop) >> 8) & 0x0f;
+	}
+
 	therm_address = ((*prop) & 0xff) >> 1;
 
 	printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
 			 "limit_adjust: %d, fan_speed: %d\n",
 			 therm_bus, therm_address, limit_adjust, fan_speed);
 
+	if (get_property(np, "hwsensor-location", NULL)) {
+		for (i = 0; i < 3; i++) {
+			sensor_location[i] = get_property(np,
+					"hwsensor-location", NULL) + offset;
+
+			if (sensor_location[i] == NULL)
+				sensor_location[i] = "";
+
+			printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
+			offset += strlen(sensor_location[i]) + 1;
+		}
+	} else {
+		sensor_location[0] = "?";
+		sensor_location[1] = "?";
+		sensor_location[2] = "?";
+	}
+
 	of_dev = of_platform_device_create(np, "temperatures");
 	
 	if (of_dev == NULL) {
@@ -562,15 +607,17 @@ thermostat_init(void)
 		return -ENODEV;
 	}
 	
-	device_create_file(&of_dev->dev, &dev_attr_cpu_temperature);
-	device_create_file(&of_dev->dev, &dev_attr_gpu_temperature);
-	device_create_file(&of_dev->dev, &dev_attr_cpu_limit);
-	device_create_file(&of_dev->dev, &dev_attr_gpu_limit);
+	device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
+	device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
+	device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
+	device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
 	device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
 	device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-	device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
+	device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
 	if(therm_type == ADT7460)
-		device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
+		device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
 
 #ifndef CONFIG_I2C_KEYWEST
 	request_module("i2c-keywest");
@@ -583,17 +630,19 @@ static void __exit
 thermostat_exit(void)
 {
 	if (of_dev) {
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_gpu_limit);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
 		device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
 		device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
+		device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
 
 		if(therm_type == ADT7460)
 			device_remove_file(&of_dev->dev,
-					   &dev_attr_gpu_fan_speed);
+					   &dev_attr_sensor2_fan_speed);
 
 		of_device_unregister(of_dev);
 	}
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -47,8 +47,11 @@
  *          decisions, like slewing down CPUs
  *	  - Deal with fan and i2c failures in a better way
  *	  - Maybe do a generic PID based on params used for
- *	    U3 and Drives ?
- *        - Add RackMac3,1 support (XServe g5)
+ *	    U3 and Drives ? Definitely need to factor code a bit
+ *          bettter... also make sensor detection more robust using
+ *          the device-tree to probe for them
+ *        - Figure out how to get the slots consumption and set the
+ *          slots fan accordingly
  *
  * History:
  *
@@ -85,6 +88,13 @@
  *	- Add new CPU cooling algorithm for machines with liquid cooling
  *	- Workaround for some PowerMac7,3 with empty "fan" node in the devtree
  *	- Fix a signed/unsigned compare issue in some PID loops
+ *
+ *  Mar. 10, 2005 : 1.2
+ *	- Add basic support for Xserve G5
+ *	- Retreive pumps min/max from EEPROM image in device-tree (broken)
+ *	- Use min/max macros here or there
+ *	- Latest darwin updated U3H min fan speed to 20% PWM
+ *
  */
 
 #include <linux/config.h>
@@ -113,7 +123,7 @@
 
 #include "therm_pm72.h"
 
-#define VERSION "1.1"
+#define VERSION "1.2b2"
 
 #undef DEBUG
 
@@ -131,21 +141,26 @@
 static struct of_device *		of_dev;
 static struct i2c_adapter *		u3_0;
 static struct i2c_adapter *		u3_1;
+static struct i2c_adapter *		k2;
 static struct i2c_client *		fcu;
 static struct cpu_pid_state		cpu_state[2];
 static struct basckside_pid_params	backside_params;
 static struct backside_pid_state	backside_state;
 static struct drives_pid_state		drives_state;
+static struct dimm_pid_state		dimms_state;
 static int				state;
 static int				cpu_count;
 static int				cpu_pid_type;
 static pid_t				ctrl_task;
 static struct completion		ctrl_complete;
 static int				critical_state;
+static int				rackmac;
+static s32				dimm_output_clamp;
+
 static DECLARE_MUTEX(driver_lock);
 
 /*
- * We have 2 types of CPU PID control. One is "split" old style control
+ * We have 3 types of CPU PID control. One is "split" old style control
  * for intake & exhaust fans, the other is "combined" control for both
  * CPUs that also deals with the pumps when present. To be "compatible"
  * with OS X at this point, we only use "COMBINED" on the machines that
@@ -155,6 +170,7 @@ static DECLARE_MUTEX(driver_lock);
  */
 #define CPU_PID_TYPE_SPLIT	0
 #define CPU_PID_TYPE_COMBINED	1
+#define CPU_PID_TYPE_RACKMAC	2
 
 /*
  * This table describes all fans in the FCU. The "id" and "type" values
@@ -177,7 +193,7 @@ struct fcu_fan_table
 
 struct fcu_fan_table	fcu_fans[] = {
 	[BACKSIDE_FAN_PWM_INDEX] = {
-		.loc	= "BACKSIDE",
+		.loc	= "BACKSIDE,SYS CTRLR FAN",
 		.type	= FCU_FAN_PWM,
 		.id	= BACKSIDE_FAN_PWM_DEFAULT_ID,
 	},
@@ -187,7 +203,7 @@ struct fcu_fan_table	fcu_fans[] = {
 		.id	= DRIVES_FAN_RPM_DEFAULT_ID,
 	},
 	[SLOTS_FAN_PWM_INDEX] = {
-		.loc	= "SLOT",
+		.loc	= "SLOT,PCI FAN",
 		.type	= FCU_FAN_PWM,
 		.id	= SLOTS_FAN_PWM_DEFAULT_ID,
 	},
@@ -224,6 +240,37 @@ struct fcu_fan_table	fcu_fans[] = {
 		.type	= FCU_FAN_RPM,
 		.id	= FCU_FAN_ABSENT_ID,
 	},
+	/* Xserve fans */
+	[CPU_A1_FAN_RPM_INDEX] = {
+		.loc	= "CPU A 1",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
+	[CPU_A2_FAN_RPM_INDEX] = {
+		.loc	= "CPU A 2",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
+	[CPU_A3_FAN_RPM_INDEX] = {
+		.loc	= "CPU A 3",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
+	[CPU_B1_FAN_RPM_INDEX] = {
+		.loc	= "CPU B 1",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
+	[CPU_B2_FAN_RPM_INDEX] = {
+		.loc	= "CPU B 2",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
+	[CPU_B3_FAN_RPM_INDEX] = {
+		.loc	= "CPU B 3",
+		.type	= FCU_FAN_RPM,
+		.id	= FCU_FAN_ABSENT_ID,
+	},
 };
 
 /*
@@ -251,7 +298,9 @@ static struct i2c_client *attach_i2c_chi
 	struct i2c_client *clt;
 	struct i2c_adapter *adap;
 
-	if (id & 0x100)
+	if (id & 0x200)
+		adap = k2;
+	else if (id & 0x100)
 		adap = u3_1;
 	else
 		adap = u3_0;
@@ -361,6 +410,31 @@ static int read_smon_adc(struct cpu_pid_
 	}
 }
 
+static int read_lm87_reg(struct i2c_client * chip, int reg)
+{
+	int rc, tries = 0;
+	u8 buf;
+
+	for (;;) {
+		/* Set address */
+		buf = (u8)reg;
+		rc = i2c_master_send(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		rc = i2c_master_recv(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		return (int)buf;
+	error:
+		DBG("Error reading LM87, retrying...\n");
+		if (++tries > 10) {
+			printk(KERN_ERR "therm_pm72: Error reading LM87 !\n");
+			return -1;
+		}
+		msleep(10);
+	}
+}
+
 static int fan_read_reg(int reg, unsigned char *buf, int nb)
 {
 	int tries, nr, nw;
@@ -570,6 +644,38 @@ static int read_eeprom(int cpu, struct m
 	return 0;
 }
 
+static void fetch_cpu_pumps_minmax(void)
+{
+	struct cpu_pid_state *state0 = &cpu_state[0];
+	struct cpu_pid_state *state1 = &cpu_state[1];
+	u16 pump_min = 0, pump_max = 0xffff;
+	u16 tmp[4];
+
+	/* Try to fetch pumps min/max infos from eeprom */
+
+	memcpy(&tmp, &state0->mpu.processor_part_num, 8);
+	if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+		pump_min = max(pump_min, tmp[0]);
+		pump_max = min(pump_max, tmp[1]);
+	}
+	if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+		pump_min = max(pump_min, tmp[2]);
+		pump_max = min(pump_max, tmp[3]);
+	}
+
+	/* Double check the values, this _IS_ needed as the EEPROM on
+	 * some dual 2.5Ghz G5s seem, at least, to have both min & max
+	 * same to the same value ... (grrrr)
+	 */
+	if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+		pump_min = CPU_PUMP_OUTPUT_MIN;
+		pump_max = CPU_PUMP_OUTPUT_MAX;
+	}
+
+	state0->pump_min = state1->pump_min = pump_min;
+	state0->pump_max = state1->pump_max = pump_max;
+}
+
 /* 
  * Now, unfortunately, sysfs doesn't give us a nice void * we could
  * pass around to the attribute functions, so we don't really have
@@ -611,6 +717,8 @@ BUILD_SHOW_FUNC_INT(backside_fan_pwm, ba
 BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
 BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
 
+BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)
+
 static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
 static DEVICE_ATTR(cpu0_voltage,S_IRUGO,show_cpu0_voltage,NULL);
 static DEVICE_ATTR(cpu0_current,S_IRUGO,show_cpu0_current,NULL);
@@ -629,6 +737,8 @@ static DEVICE_ATTR(backside_fan_pwm,S_IR
 static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
 static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
 
+static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);
+
 /*
  * CPUs fans control loop
  */
@@ -636,17 +746,21 @@ static DEVICE_ATTR(drives_fan_rpm,S_IRUG
 static int do_read_one_cpu_values(struct cpu_pid_state *state, s32 *temp, s32 *power)
 {
 	s32 ltemp, volts, amps;
-	int rc = 0;
+	int index, rc = 0;
 
 	/* Default (in case of error) */
 	*temp = state->cur_temp;
 	*power = state->cur_power;
 
-	/* Read current fan status */
-	if (state->index == 0)
-		rc = get_rpm_fan(CPUA_EXHAUST_FAN_RPM_INDEX, !RPM_PID_USE_ACTUAL_SPEED);
+	if (cpu_pid_type == CPU_PID_TYPE_RACKMAC)
+		index = (state->index == 0) ?
+			CPU_A1_FAN_RPM_INDEX : CPU_B1_FAN_RPM_INDEX;
 	else
-		rc = get_rpm_fan(CPUB_EXHAUST_FAN_RPM_INDEX, !RPM_PID_USE_ACTUAL_SPEED);
+		index = (state->index == 0) ?
+			CPUA_EXHAUST_FAN_RPM_INDEX : CPUB_EXHAUST_FAN_RPM_INDEX;
+
+	/* Read current fan status */
+	rc = get_rpm_fan(index, !RPM_PID_USE_ACTUAL_SPEED);
 	if (rc < 0) {
 		/* XXX What do we do now ? Nothing for now, keep old value, but
 		 * return error upstream
@@ -777,11 +891,6 @@ static void do_cpu_pid(struct cpu_pid_st
 
 	DBG("   sum: %d\n", (int)sum);
 	state->rpm += (s32)sum;
-
-	if (state->rpm < (int)state->mpu.rminn_exhaust_fan)
-		state->rpm = state->mpu.rminn_exhaust_fan;
-	if (state->rpm > (int)state->mpu.rmaxn_exhaust_fan)
-		state->rpm = state->mpu.rmaxn_exhaust_fan;
 }
 
 static void do_monitor_cpu_combined(void)
@@ -823,28 +932,28 @@ static void do_monitor_cpu_combined(void
 	if (state0->overtemp > 0) {
 		state0->rpm = state0->mpu.rmaxn_exhaust_fan;
 		state0->intake_rpm = intake = state0->mpu.rmaxn_intake_fan;
-		pump = CPU_PUMP_OUTPUT_MAX;
+		pump = state0->pump_min;
 		goto do_set_fans;
 	}
 
 	/* Do the PID */
 	do_cpu_pid(state0, temp_combi, power_combi);
 
+	/* Range check */
+	state0->rpm = max(state0->rpm, (int)state0->mpu.rminn_exhaust_fan);
+	state0->rpm = min(state0->rpm, (int)state0->mpu.rmaxn_exhaust_fan);
+
 	/* Calculate intake fan speed */
 	intake = (state0->rpm * CPU_INTAKE_SCALE) >> 16;
-	if (intake < (int)state0->mpu.rminn_intake_fan)
-		intake = state0->mpu.rminn_intake_fan;
-	if (intake > (int)state0->mpu.rmaxn_intake_fan)
-		intake = state0->mpu.rmaxn_intake_fan;
+	intake = max(intake, (int)state0->mpu.rminn_intake_fan);
+	intake = min(intake, (int)state0->mpu.rmaxn_intake_fan);
 	state0->intake_rpm = intake;
 
 	/* Calculate pump speed */
-	pump = (state0->rpm * CPU_PUMP_OUTPUT_MAX) /
+	pump = (state0->rpm * state0->pump_max) /
 		state0->mpu.rmaxn_exhaust_fan;
-	if (pump > CPU_PUMP_OUTPUT_MAX)
-		pump = CPU_PUMP_OUTPUT_MAX;
-	if (pump < CPU_PUMP_OUTPUT_MIN)
-		pump = CPU_PUMP_OUTPUT_MIN;
+	pump = min(pump, state0->pump_max);
+	pump = max(pump, state0->pump_min);
 	
  do_set_fans:
 	/* We copy values from state 0 to state 1 for /sysfs */
@@ -904,11 +1013,14 @@ static void do_monitor_cpu_split(struct 
 	/* Do the PID */
 	do_cpu_pid(state, temp, power);
 
+	/* Range check */
+	state->rpm = max(state->rpm, (int)state->mpu.rminn_exhaust_fan);
+	state->rpm = min(state->rpm, (int)state->mpu.rmaxn_exhaust_fan);
+
+	/* Calculate intake fan */
 	intake = (state->rpm * CPU_INTAKE_SCALE) >> 16;
-	if (intake < (int)state->mpu.rminn_intake_fan)
-		intake = state->mpu.rminn_intake_fan;
-	if (intake > (int)state->mpu.rmaxn_intake_fan)
-		intake = state->mpu.rmaxn_intake_fan;
+	intake = max(intake, (int)state->mpu.rminn_intake_fan);
+	intake = min(intake, (int)state->mpu.rmaxn_intake_fan);
 	state->intake_rpm = intake;
 
  do_set_fans:
@@ -929,6 +1041,67 @@ static void do_monitor_cpu_split(struct 
 	}
 }
 
+static void do_monitor_cpu_rack(struct cpu_pid_state *state)
+{
+	s32 temp, power, fan_min;
+	int rc;
+
+	/* Read current fan status */
+	rc = do_read_one_cpu_values(state, &temp, &power);
+	if (rc < 0) {
+		/* XXX What do we do now ? */
+	}
+
+	/* Check tmax, increment overtemp if we are there. At tmax+8, we go
+	 * full blown immediately and try to trigger a shutdown
+	 */
+	if (temp >= ((state->mpu.tmax + 8) << 16)) {
+		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum"
+		       " (%d) !\n",
+		       state->index, temp >> 16);
+		state->overtemp = CPU_MAX_OVERTEMP;
+	} else if (temp > (state->mpu.tmax << 16))
+		state->overtemp++;
+	else
+		state->overtemp = 0;
+	if (state->overtemp >= CPU_MAX_OVERTEMP)
+		critical_state = 1;
+	if (state->overtemp > 0) {
+		state->rpm = state->intake_rpm = state->mpu.rmaxn_intake_fan;
+		goto do_set_fans;
+	}
+
+	/* Do the PID */
+	do_cpu_pid(state, temp, power);
+
+	/* Check clamp from dimms */
+	fan_min = dimm_output_clamp;
+	fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);
+
+	state->rpm = max(state->rpm, (int)fan_min);
+	state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
+	state->intake_rpm = state->rpm;
+
+ do_set_fans:
+	DBG("** CPU %d RPM: %d overtemp: %d\n",
+	    state->index, (int)state->rpm, state->overtemp);
+
+	/* We should check for errors, shouldn't we ? But then, what
+	 * do we do once the error occurs ? For FCU notified fan
+	 * failures (-EFAULT) we probably want to notify userland
+	 * some way...
+	 */
+	if (state->index == 0) {
+		set_rpm_fan(CPU_A1_FAN_RPM_INDEX, state->rpm);
+		set_rpm_fan(CPU_A2_FAN_RPM_INDEX, state->rpm);
+		set_rpm_fan(CPU_A3_FAN_RPM_INDEX, state->rpm);
+	} else {
+		set_rpm_fan(CPU_B1_FAN_RPM_INDEX, state->rpm);
+		set_rpm_fan(CPU_B2_FAN_RPM_INDEX, state->rpm);
+		set_rpm_fan(CPU_B3_FAN_RPM_INDEX, state->rpm);
+	}
+}
+
 /*
  * Initialize the state structure for one CPU control loop
  */
@@ -936,7 +1109,7 @@ static int init_cpu_state(struct cpu_pid
 {
 	state->index = index;
 	state->first = 1;
-	state->rpm = 1000;
+	state->rpm = (cpu_pid_type == CPU_PID_TYPE_RACKMAC) ? 4000 : 1000;
 	state->overtemp = 0;
 	state->adc_config = 0x00;
 
@@ -1012,13 +1185,13 @@ static void dispose_cpu_state(struct cpu
  */
 static void do_monitor_backside(struct backside_pid_state *state)
 {
-	s32 temp, integral, derivative;
+	s32 temp, integral, derivative, fan_min;
 	s64 integ_p, deriv_p, prop_p, sum; 
 	int i, rc;
 
 	if (--state->ticks != 0)
 		return;
-	state->ticks = BACKSIDE_PID_INTERVAL;
+	state->ticks = backside_params.interval;
 
 	DBG("backside:\n");
 
@@ -1059,7 +1232,7 @@ static void do_monitor_backside(struct b
 	integral = 0;
 	for (i = 0; i < BACKSIDE_PID_HISTORY_SIZE; i++)
 		integral += state->error_history[i];
-	integral *= BACKSIDE_PID_INTERVAL;
+	integral *= backside_params.interval;
 	DBG("  integral: %08x\n", integral);
 	integ_p = ((s64)backside_params.G_r) * (s64)integral;
 	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
@@ -1069,7 +1242,7 @@ static void do_monitor_backside(struct b
 	derivative = state->error_history[state->cur_sample] -
 		state->error_history[(state->cur_sample + BACKSIDE_PID_HISTORY_SIZE - 1)
 				    % BACKSIDE_PID_HISTORY_SIZE];
-	derivative /= BACKSIDE_PID_INTERVAL;
+	derivative /= backside_params.interval;
 	deriv_p = ((s64)backside_params.G_d) * (s64)derivative;
 	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
 	sum += deriv_p;
@@ -1083,11 +1256,17 @@ static void do_monitor_backside(struct b
 	sum >>= 36;
 
 	DBG("   sum: %d\n", (int)sum);
-	state->pwm += (s32)sum;
-	if (state->pwm < backside_params.output_min)
-		state->pwm = backside_params.output_min;
-	if (state->pwm > backside_params.output_max)
-		state->pwm = backside_params.output_max;
+	if (backside_params.additive)
+		state->pwm += (s32)sum;
+	else
+		state->pwm = sum;
+
+	/* Check for clamp */
+	fan_min = (dimm_output_clamp * 100) / 14000;
+	fan_min = max(fan_min, backside_params.output_min);
+
+	state->pwm = max(state->pwm, fan_min);
+	state->pwm = min(state->pwm, backside_params.output_max);
 
 	DBG("** BACKSIDE PWM: %d\n", (int)state->pwm);
 	set_pwm_fan(BACKSIDE_FAN_PWM_INDEX, state->pwm);
@@ -1114,17 +1293,33 @@ static int init_backside_state(struct ba
 		of_node_put(u3);
 	}
 
-	backside_params.G_p = BACKSIDE_PID_G_p;
-	backside_params.G_r = BACKSIDE_PID_G_r;
-	backside_params.output_max = BACKSIDE_PID_OUTPUT_MAX;
-	if (u3h) {
+	if (rackmac) {
+		backside_params.G_d = BACKSIDE_PID_RACK_G_d;
+		backside_params.input_target = BACKSIDE_PID_RACK_INPUT_TARGET;
+		backside_params.output_min = BACKSIDE_PID_U3H_OUTPUT_MIN;
+		backside_params.interval = BACKSIDE_PID_RACK_INTERVAL;
+		backside_params.G_p = BACKSIDE_PID_RACK_G_p;
+		backside_params.G_r = BACKSIDE_PID_G_r;
+		backside_params.output_max = BACKSIDE_PID_OUTPUT_MAX;
+		backside_params.additive = 0;
+	} else if (u3h) {
 		backside_params.G_d = BACKSIDE_PID_U3H_G_d;
 		backside_params.input_target = BACKSIDE_PID_U3H_INPUT_TARGET;
 		backside_params.output_min = BACKSIDE_PID_U3H_OUTPUT_MIN;
+		backside_params.interval = BACKSIDE_PID_INTERVAL;
+		backside_params.G_p = BACKSIDE_PID_G_p;
+		backside_params.G_r = BACKSIDE_PID_G_r;
+		backside_params.output_max = BACKSIDE_PID_OUTPUT_MAX;
+		backside_params.additive = 1;
 	} else {
 		backside_params.G_d = BACKSIDE_PID_U3_G_d;
 		backside_params.input_target = BACKSIDE_PID_U3_INPUT_TARGET;
 		backside_params.output_min = BACKSIDE_PID_U3_OUTPUT_MIN;
+		backside_params.interval = BACKSIDE_PID_INTERVAL;
+		backside_params.G_p = BACKSIDE_PID_G_p;
+		backside_params.G_r = BACKSIDE_PID_G_r;
+		backside_params.output_max = BACKSIDE_PID_OUTPUT_MAX;
+		backside_params.additive = 1;
 	}
 
 	state->ticks = 1;
@@ -1233,10 +1428,9 @@ static void do_monitor_drives(struct dri
 
 	DBG("   sum: %d\n", (int)sum);
 	state->rpm += (s32)sum;
-	if (state->rpm < DRIVES_PID_OUTPUT_MIN)
-		state->rpm = DRIVES_PID_OUTPUT_MIN;
-	if (state->rpm > DRIVES_PID_OUTPUT_MAX)
-		state->rpm = DRIVES_PID_OUTPUT_MAX;
+
+	state->rpm = max(state->rpm, DRIVES_PID_OUTPUT_MIN);
+	state->rpm = min(state->rpm, DRIVES_PID_OUTPUT_MAX);
 
 	DBG("** DRIVES RPM: %d\n", (int)state->rpm);
 	set_rpm_fan(DRIVES_FAN_RPM_INDEX, state->rpm);
@@ -1276,6 +1470,126 @@ static void dispose_drives_state(struct 
 	state->monitor = NULL;
 }
 
+/*
+ * DIMMs temp control loop
+ */
+static void do_monitor_dimms(struct dimm_pid_state *state)
+{
+	s32 temp, integral, derivative, fan_min;
+	s64 integ_p, deriv_p, prop_p, sum;
+	int i;
+
+	if (--state->ticks != 0)
+		return;
+	state->ticks = DIMM_PID_INTERVAL;
+
+	DBG("DIMM:\n");
+
+	DBG("  current value: %d\n", state->output);
+
+	temp = read_lm87_reg(state->monitor, LM87_INT_TEMP);
+	if (temp < 0)
+		return;
+	temp <<= 16;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+	    FIX32TOPRINT(DIMM_PID_INPUT_TARGET));
+
+	/* Store temperature and error in history array */
+	state->cur_sample = (state->cur_sample + 1) % DIMM_PID_HISTORY_SIZE;
+	state->sample_history[state->cur_sample] = temp;
+	state->error_history[state->cur_sample] = temp - DIMM_PID_INPUT_TARGET;
+
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (DIMM_PID_HISTORY_SIZE - 1); i++) {
+			state->cur_sample = (state->cur_sample + 1) %
+				DIMM_PID_HISTORY_SIZE;
+			state->sample_history[state->cur_sample] = temp;
+			state->error_history[state->cur_sample] =
+				temp - DIMM_PID_INPUT_TARGET;
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < DIMM_PID_HISTORY_SIZE; i++)
+		integral += state->error_history[i];
+	integral *= DIMM_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+	integ_p = ((s64)DIMM_PID_G_r) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
+	sum += integ_p;
+
+	/* Calculate the derivative term */
+	derivative = state->error_history[state->cur_sample] -
+		state->error_history[(state->cur_sample + DIMM_PID_HISTORY_SIZE - 1)
+				    % DIMM_PID_HISTORY_SIZE];
+	derivative /= DIMM_PID_INTERVAL;
+	deriv_p = ((s64)DIMM_PID_G_d) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	prop_p = ((s64)DIMM_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->output = (s32)sum;
+	state->output = max(state->output, DIMM_PID_OUTPUT_MIN);
+	state->output = min(state->output, DIMM_PID_OUTPUT_MAX);
+	dimm_output_clamp = state->output;
+
+	DBG("** DIMM clamp value: %d\n", (int)state->output);
+
+	/* Backside PID is only every 5 seconds, force backside fan clamping now */
+	fan_min = (dimm_output_clamp * 100) / 14000;
+	fan_min = max(fan_min, backside_params.output_min);
+	if (backside_state.pwm < fan_min) {
+		backside_state.pwm = fan_min;
+		DBG(" -> applying clamp to backside fan now: %d  !\n", fan_min);
+		set_pwm_fan(BACKSIDE_FAN_PWM_INDEX, fan_min);
+	}
+}
+
+/*
+ * Initialize the state structure for the DIMM temp control loop
+ */
+static int init_dimms_state(struct dimm_pid_state *state)
+{
+	state->ticks = 1;
+	state->first = 1;
+	state->output = 4000;
+
+	state->monitor = attach_i2c_chip(XSERVE_DIMMS_LM87, "dimms_temp");
+	if (state->monitor == NULL)
+		return -ENODEV;
+
+       	device_create_file(&of_dev->dev, &dev_attr_dimms_temperature);
+
+	return 0;
+}
+
+/*
+ * Dispose of the state data for the drives control loop
+ */
+static void dispose_dimms_state(struct dimm_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature);
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+
 static int call_critical_overtemp(void)
 {
 	char *argv[] = { critical_overtemp_path, NULL };
@@ -1321,15 +1635,29 @@ static int main_control_loop(void *x)
 		start = jiffies;
 
 		down(&driver_lock);
+
+		/* First, we always calculate the new DIMMs state on an Xserve */
+		if (rackmac)
+			do_monitor_dimms(&dimms_state);
+
+		/* Then, the CPUs */
 		if (cpu_pid_type == CPU_PID_TYPE_COMBINED)
 			do_monitor_cpu_combined();
-		else {
+		else if (cpu_pid_type == CPU_PID_TYPE_RACKMAC) {
+			do_monitor_cpu_rack(&cpu_state[0]);
+			if (cpu_state[1].monitor != NULL)
+				do_monitor_cpu_rack(&cpu_state[1]);
+			// better deal with UP
+		} else {
 			do_monitor_cpu_split(&cpu_state[0]);
 			if (cpu_state[1].monitor != NULL)
 				do_monitor_cpu_split(&cpu_state[1]);
+			// better deal with UP
 		}
+		/* Then, the rest */
 		do_monitor_backside(&backside_state);
-		do_monitor_drives(&drives_state);
+		if (!rackmac)
+			do_monitor_drives(&drives_state);
 		up(&driver_lock);
 
 		if (critical_state == 1) {
@@ -1369,9 +1697,9 @@ static void dispose_control_loops(void)
 {
 	dispose_cpu_state(&cpu_state[0]);
 	dispose_cpu_state(&cpu_state[1]);
-
 	dispose_backside_state(&backside_state);
 	dispose_drives_state(&drives_state);
+	dispose_dimms_state(&dimms_state);
 }
 
 /*
@@ -1395,7 +1723,9 @@ static int create_control_loops(void)
 	 * the pumps, though that may not be the best way, that is good enough
 	 * for now
 	 */
-	if (machine_is_compatible("PowerMac7,3")
+	if (rackmac)
+		cpu_pid_type = CPU_PID_TYPE_RACKMAC;
+	else if (machine_is_compatible("PowerMac7,3")
 	    && (cpu_count > 1)
 	    && fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID
 	    && fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) {
@@ -1409,11 +1739,16 @@ static int create_control_loops(void)
 	 */
 	if (init_cpu_state(&cpu_state[0], 0))
 		goto fail;
+	if (cpu_pid_type == CPU_PID_TYPE_COMBINED)
+		fetch_cpu_pumps_minmax();
+
 	if (cpu_count > 1 && init_cpu_state(&cpu_state[1], 1))
 		goto fail;
 	if (init_backside_state(&backside_state))
 		goto fail;
-	if (init_drives_state(&drives_state))
+	if (rackmac && init_dimms_state(&dimms_state))
+		goto fail;
+	if (!rackmac && init_drives_state(&drives_state))
 		goto fail;
 
 	DBG("all control loops up !\n");
@@ -1492,17 +1827,24 @@ static int therm_pm72_attach(struct i2c_
 	/* Check if we are looking for one of these */
 	if (u3_0 == NULL && !strcmp(adapter->name, "u3 0")) {
 		u3_0 = adapter;
-		DBG("found U3-0, creating control loops\n");
-		if (create_control_loops())
-			u3_0 = NULL;
+		DBG("found U3-0\n");
+		if (k2 || !rackmac)
+			if (create_control_loops())
+				u3_0 = NULL;
 	} else if (u3_1 == NULL && !strcmp(adapter->name, "u3 1")) {
 		u3_1 = adapter;
 		DBG("found U3-1, attaching FCU\n");
 		if (attach_fcu())
 			u3_1 = NULL;
+	} else if (k2 == NULL && !strcmp(adapter->name, "mac-io 0")) {
+		k2 = adapter;
+		DBG("Found K2\n");
+		if (u3_0 && rackmac)
+			if (create_control_loops())
+				k2 = NULL;
 	}
 	/* We got all we need, start control loops */
-	if (u3_0 != NULL && u3_1 != NULL) {
+	if (u3_0 != NULL && u3_1 != NULL && (k2 || !rackmac)) {
 		DBG("everything up, starting control loops\n");
 		state = state_attached;
 		start_control_loops();
@@ -1548,6 +1890,27 @@ static int therm_pm72_detach(struct i2c_
 	return 0;
 }
 
+static int fan_check_loc_match(const char *loc, int fan)
+{
+	char	tmp[64];
+	char	*c, *e;
+
+	strlcpy(tmp, fcu_fans[fan].loc, 64);
+
+	c = tmp;
+	for (;;) {
+		e = strchr(c, ',');
+		if (e)
+			*e = 0;
+		if (strcmp(loc, c) == 0)
+			return 1;
+		if (e == NULL)
+			break;
+		c = e + 1;
+	}
+	return 0;
+}
+
 static void fcu_lookup_fans(struct device_node *fcu_node)
 {
 	struct device_node *np = NULL;
@@ -1589,7 +1952,7 @@ static void fcu_lookup_fans(struct devic
 		for (i = 0; i < FCU_FAN_COUNT; i++) {
 			int fan_id;
 
-			if (strcmp(loc, fcu_fans[i].loc))
+			if (!fan_check_loc_match(loc, i))
 				continue;
 			DBG(" location match, index: %d\n", i);
 			fcu_fans[i].id = FCU_FAN_ABSENT_ID;
@@ -1671,8 +2034,11 @@ static int __init therm_pm72_init(void)
 {
 	struct device_node *np;
 
+	rackmac = machine_is_compatible("RackMac3,1");
+
 	if (!machine_is_compatible("PowerMac7,2") &&
-	    !machine_is_compatible("PowerMac7,3"))
+	    !machine_is_compatible("PowerMac7,3") &&
+	    !rackmac)
 	    	return -ENODEV;
 
 	printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION);
@@ -1709,6 +2075,6 @@ module_init(therm_pm72_init);
 module_exit(therm_pm72_exit);
 
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for Apple's PowerMac7,2 G5 thermal control");
+MODULE_DESCRIPTION("Driver for Apple's PowerMac G5 thermal control");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h
--- a/drivers/macintosh/therm_pm72.h
+++ b/drivers/macintosh/therm_pm72.h
@@ -52,7 +52,7 @@ struct mpu_data
 	u16	rmaxn_intake_fan;	/* 0x4e - Intake fan max RPM */
 	u16	rminn_exhaust_fan;	/* 0x50 - Exhaust fan min RPM */
 	u16	rmaxn_exhaust_fan;	/* 0x52 - Exhaust fan max RPM */
-	u8	processor_part_num[8];	/* 0x54 - Processor part number */
+	u8	processor_part_num[8];	/* 0x54 - Processor part number XX pumps min/max */
 	u32	processor_lot_num;	/* 0x5c - Processor lot number */
 	u8	orig_card_sernum[0x10];	/* 0x60 - Card original serial number */
 	u8	curr_card_sernum[0x10];	/* 0x70 - Card current serial number */
@@ -94,19 +94,25 @@ static char * critical_overtemp_path = "
  * of the driver, though I would accept any clean patch
  * doing a better use of the device-tree without turning the
  * while i2c registration mecanism into a racy mess
+ *
+ * Note: Xserve changed this. We have some bits on the K2 bus,
+ * which I arbitrarily set to 0x200. Ultimately, we really want
+ * too lookup these in the device-tree though
  */
 #define FAN_CTRLER_ID		0x15e
 #define SUPPLY_MONITOR_ID      	0x58
 #define SUPPLY_MONITORB_ID     	0x5a
 #define DRIVES_DALLAS_ID	0x94
 #define BACKSIDE_MAX_ID		0x98
+#define XSERVE_DIMMS_LM87	0x25a
 
 /*
- * Some MAX6690 & DS1775 register definitions
+ * Some MAX6690, DS1775, LM87 register definitions
  */
 #define MAX6690_INT_TEMP	0
 #define MAX6690_EXT_TEMP	1
 #define DS1775_TEMP		0
+#define LM87_INT_TEMP		0x27
 
 /*
  * Scaling factors for the AD7417 ADC converters (except
@@ -126,14 +132,18 @@ static char * critical_overtemp_path = "
 #define BACKSIDE_FAN_PWM_INDEX		0
 #define BACKSIDE_PID_U3_G_d		0x02800000
 #define BACKSIDE_PID_U3H_G_d		0x01400000
+#define BACKSIDE_PID_RACK_G_d		0x00500000
 #define BACKSIDE_PID_G_p		0x00500000
+#define BACKSIDE_PID_RACK_G_p		0x0004cccc
 #define BACKSIDE_PID_G_r		0x00000000
 #define BACKSIDE_PID_U3_INPUT_TARGET	0x00410000
 #define BACKSIDE_PID_U3H_INPUT_TARGET	0x004b0000
+#define BACKSIDE_PID_RACK_INPUT_TARGET	0x00460000
 #define BACKSIDE_PID_INTERVAL		5
+#define BACKSIDE_PID_RACK_INTERVAL	1
 #define BACKSIDE_PID_OUTPUT_MAX		100
 #define BACKSIDE_PID_U3_OUTPUT_MIN	20
-#define BACKSIDE_PID_U3H_OUTPUT_MIN	30
+#define BACKSIDE_PID_U3H_OUTPUT_MIN	20
 #define BACKSIDE_PID_HISTORY_SIZE	2
 
 struct basckside_pid_params
@@ -144,6 +154,8 @@ struct basckside_pid_params
 	s32			input_target;
 	s32			output_min;
 	s32			output_max;
+	s32			interval;
+	int			additive;
 };
 
 struct backside_pid_state
@@ -188,25 +200,34 @@ struct drives_pid_state
 #define SLOTS_FAN_PWM_INDEX		2
 #define	SLOTS_FAN_DEFAULT_PWM		50 /* Do better here ! */
 
+
 /*
- * IDs in Darwin for the sensors & fans
- *
- * CPU A AD7417_TEMP	10	(CPU A ambient temperature)
- * CPU A AD7417_AD1	11	(CPU A diode temperature)
- * CPU A AD7417_AD2	12	(CPU A 12V current)
- * CPU A AD7417_AD3	13	(CPU A voltage)
- * CPU A AD7417_AD4	14	(CPU A current)
- *
- * CPU A FAKE POWER	48	(I_V_inputs: 13, 14)
- *
- * CPU B AD7417_TEMP	15	(CPU B ambient temperature)
- * CPU B AD7417_AD1	16	(CPU B diode temperature)
- * CPU B AD7417_AD2	17	(CPU B 12V current)
- * CPU B AD7417_AD3	18	(CPU B voltage)
- * CPU B AD7417_AD4	19	(CPU B current)
- *
- * CPU B FAKE POWER	49	(I_V_inputs: 18, 19)
+ * PID factors for the Xserve DIMM control loop
  */
+#define DIMM_PID_G_d			0
+#define DIMM_PID_G_p			0
+#define DIMM_PID_G_r			0x6553600
+#define DIMM_PID_INPUT_TARGET		3276800
+#define DIMM_PID_INTERVAL    		1
+#define DIMM_PID_OUTPUT_MAX		14000
+#define DIMM_PID_OUTPUT_MIN		4000
+#define DIMM_PID_HISTORY_SIZE		20
+
+struct dimm_pid_state
+{
+	int			ticks;
+	struct i2c_client *	monitor;
+	s32	       		sample_history[DIMM_PID_HISTORY_SIZE];
+	s32			error_history[DIMM_PID_HISTORY_SIZE];
+	int			cur_sample;
+	s32			last_temp;
+	int			first;
+	int			output;
+};
+
+
+
+/* Desktops */
 
 #define CPUA_INTAKE_FAN_RPM_DEFAULT_ID	3
 #define CPUA_EXHAUST_FAN_RPM_DEFAULT_ID	4
@@ -226,8 +247,17 @@ struct drives_pid_state
 
 #define CPUA_PUMP_RPM_INDEX		7
 #define CPUB_PUMP_RPM_INDEX		8
-#define CPU_PUMP_OUTPUT_MAX		3700
-#define CPU_PUMP_OUTPUT_MIN		1000
+#define CPU_PUMP_OUTPUT_MAX		3200
+#define CPU_PUMP_OUTPUT_MIN		1250
+
+/* Xserve */
+#define CPU_A1_FAN_RPM_INDEX		9
+#define CPU_A2_FAN_RPM_INDEX		10
+#define CPU_A3_FAN_RPM_INDEX		11
+#define CPU_B1_FAN_RPM_INDEX		12
+#define CPU_B2_FAN_RPM_INDEX		13
+#define CPU_B3_FAN_RPM_INDEX		14
+
 
 struct cpu_pid_state
 {
@@ -249,6 +279,8 @@ struct cpu_pid_state
 	s32			last_power;
 	int			first;
 	u8			adc_config;
+	s32			pump_min;
+	s32			pump_max;
 };
 
 /*
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -47,8 +47,6 @@
 #define LOG_TEMP		0			/* continously log temperature */
 
 #define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
-#define THERMOSTAT_CLIENT_ID	1
-#define FAN_CLIENT_ID		2
 
 static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
 
@@ -372,7 +370,6 @@ attach_fan( struct i2c_client *cl )
 		goto out;
 	printk("ADM1030 fan controller [@%02x]\n", cl->addr );
 
-	cl->id = FAN_CLIENT_ID;
 	strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
 
 	if( !i2c_attach_client(cl) )
@@ -412,7 +409,6 @@ attach_thermostat( struct i2c_client *cl
 	x.overheat_temp = os_temp;
 	x.overheat_hyst = hyst_temp;
 	
-	cl->id = THERMOSTAT_CLIENT_ID;
 	strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
 
 	if( !i2c_attach_client(cl) )
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/cpu.h>
@@ -367,9 +368,7 @@ find_via_pmu(void)
 	printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
 	       PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
 	       
-#ifndef CONFIG_PPC64
 	sys_ctrler = SYS_CTRLER_PMU;
-#endif
 	
 	return 1;
 }
@@ -1745,6 +1744,9 @@ pmu_restart(void)
 {
 	struct adb_request req;
 
+	if (via == NULL)
+		return;
+
 	local_irq_disable();
 
 	drop_interrupts = 1;
@@ -1767,6 +1769,9 @@ pmu_shutdown(void)
 {
 	struct adb_request req;
 
+	if (via == NULL)
+		return;
+
 	local_irq_disable();
 
 	drop_interrupts = 1;
@@ -2326,7 +2331,7 @@ pmac_suspend_devices(void)
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
 	 * nobody is dirtying any new buffers while we wait. That
-	 * could be acheived using the refrigerator for processes
+	 * could be achieved using the refrigerator for processes
 	 * that swsusp uses
 	 */
 	sys_sync();
@@ -2339,13 +2344,17 @@ pmac_suspend_devices(void)
 	}
 
 	/* Send suspend call to devices, hold the device core's dpm_sem */
-	ret = device_suspend(PM_SUSPEND_MEM);
+	ret = device_suspend(PMSG_SUSPEND);
 	if (ret) {
 		broadcast_wake();
 		printk(KERN_ERR "Driver sleep failed\n");
 		return -EBUSY;
 	}
 
+	/* Disable clock spreading on some machines */
+	pmac_tweak_clock_spreading(0);
+
+	/* Stop preemption */
 	preempt_disable();
 
 	/* Make sure the decrementer won't interrupt us */
@@ -2366,7 +2375,7 @@ pmac_suspend_devices(void)
 	 * use this but still... This will take care of sysdev's as well, so
 	 * we exit from here with local irqs disabled and PIC off.
 	 */
-	ret = device_power_down(PM_SUSPEND_MEM);
+	ret = device_power_down(PMSG_SUSPEND);
 	if (ret) {
 		wakeup_decrementer();
 		local_irq_enable();
@@ -2379,7 +2388,6 @@ pmac_suspend_devices(void)
 
 	/* Wait for completion of async backlight requests */
 	while (!bright_req_1.complete || !bright_req_2.complete ||
-
 			!batt_req.complete)
 		pmu_poll();
 
@@ -2389,7 +2397,7 @@ pmac_suspend_devices(void)
 	enable_kernel_fp();
 
 #ifdef CONFIG_ALTIVEC
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		enable_kernel_altivec();
 #endif /* CONFIG_ALTIVEC */
 
@@ -2413,11 +2421,12 @@ pmac_wakeup_devices(void)
 
 	/* Re-enable local CPU interrupts */
 	local_irq_enable();
-
-	mdelay(100);
-
+	mdelay(10);
 	preempt_enable();
 
+	/* Re-enable clock spreading on some machines */
+	pmac_tweak_clock_spreading(1);
+
 	/* Resume devices */
 	device_resume();
 
@@ -2540,7 +2549,9 @@ powerbook_sleep_Core99(void)
 		return ret;
 	}
 
-	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+	/* Stop environment and ADB interrupts */
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+	pmu_wait_complete(&req);
 
 	/* Tell PMU what events will wake us up */
 	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
@@ -2582,6 +2593,9 @@ powerbook_sleep_Core99(void)
 	/* Restore VIA */
 	restore_via_state();
 
+	/* tweak LPJ before cpufreq is there */
+	loops_per_jiffy *= 2;
+
 	/* Restore video */
 	pmac_call_early_video_resume();
 
@@ -2602,7 +2616,8 @@ powerbook_sleep_Core99(void)
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
 	pmu_wait_complete(&req);
 
-	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
+	/* Restore LPJ, cpufreq will adjust the cpu frequency */
+	loops_per_jiffy /= 2;
 
 	pmac_wakeup_devices();
 
@@ -2770,13 +2785,12 @@ pmu_read(struct file *file, char __user 
 	struct pmu_private *pp = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
-	int ret;
+	int ret = 0;
 
 	if (count < 1 || pp == 0)
 		return -EINVAL;
-	ret = verify_area(VERIFY_WRITE, buf, count);
-	if (ret)
-		return ret;
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
 
 	spin_lock_irqsave(&pp->lock, flags);
 	add_wait_queue(&pp->wait, &wait);
@@ -3040,6 +3054,88 @@ pmu_polled_request(struct adb_request *r
 }
 #endif /* DEBUG_SLEEP */
 
+
+/* FIXME: This is a temporary set of callbacks to enable us
+ * to do suspend-to-disk.
+ */
+
+#ifdef CONFIG_PM
+
+static int pmu_sys_suspended = 0;
+
+static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
+{
+	if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+		return 0;
+
+	/* Suspend PMU event interrupts */
+	pmu_suspend();
+
+	pmu_sys_suspended = 1;
+	return 0;
+}
+
+static int pmu_sys_resume(struct sys_device *sysdev)
+{
+	struct adb_request req;
+
+	if (!pmu_sys_suspended)
+		return 0;
+
+	/* Tell PMU we are ready */
+	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+	pmu_wait_complete(&req);
+
+	/* Resume PMU event interrupts */
+	pmu_resume();
+
+	pmu_sys_suspended = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmu_sysclass = {
+	set_kset_name("pmu"),
+};
+
+static struct sys_device device_pmu = {
+	.id		= 0,
+	.cls		= &pmu_sysclass,
+};
+
+static struct sysdev_driver driver_pmu = {
+#ifdef CONFIG_PM
+	.suspend	= &pmu_sys_suspend,
+	.resume		= &pmu_sys_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmu_sysfs(void)
+{
+	int rc;
+
+	rc = sysdev_class_register(&pmu_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&device_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys device\n");
+		return -ENODEV;
+	}
+	rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys driver\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_pmu_sysfs);
+
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -93,7 +93,7 @@ config MD_RAID10
 	  mirroring (RAID-1) with easier configuration and more flexable
 	  layout.
 	  Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to
-	  be the same size (or atleast, only as much as the smallest device
+	  be the same size (or at least, only as much as the smallest device
 	  will be used).
 	  RAID-10 provides a variety of layouts that provide different levels
 	  of redundancy and performance.
@@ -102,6 +102,7 @@ config MD_RAID10
 
 	  ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/
 
+	  If unsure, say Y.
 
 config MD_RAID5
 	tristate "RAID-4/RAID-5 mode"
@@ -120,20 +121,16 @@ config MD_RAID5
 	  <http://www.tldp.org/docs.html#howto>. There you will also
 	  learn where to get the supporting user space utilities raidtools.
 
-	  If you want to use such a RAID-4/RAID-5 set, say Y.  To compile
-	  this code as a module, choose M here: the module will be called raid5.
+	  If you want to use such a RAID-4/RAID-5 set, say Y.  To
+	  compile this code as a module, choose M here: the module
+	  will be called raid5.
 
 	  If unsure, say Y.
 
 config MD_RAID6
-	tristate "RAID-6 mode (EXPERIMENTAL)"
-	depends on BLK_DEV_MD && EXPERIMENTAL
+	tristate "RAID-6 mode"
+	depends on BLK_DEV_MD
 	---help---
-	  WARNING: RAID-6 is currently highly experimental.  If you
-	  use it, there is no guarantee whatsoever that it won't
-	  destroy your data, eat your disk drives, insult your mother,
-	  or re-appoint George W. Bush.
-
 	  A RAID-6 set of N drives with a capacity of C MB per drive
 	  provides the capacity of C * (N - 2) MB, and protects
 	  against a failure of any two drives. For a given sector
@@ -150,7 +147,7 @@ config MD_RAID6
 	  this code as a module, choose M here: the module will be
 	  called raid6.
 
-	  If unsure, say N.
+	  If unsure, say Y.
 
 config MD_MULTIPATH
 	tristate "Multipath I/O support"
@@ -227,5 +224,17 @@ config DM_ZERO
 	  A target that discards writes, and returns all zeroes for
 	  reads.  Useful in some recovery situations.
 
+config DM_MULTIPATH
+	tristate "Multipath target (EXPERIMENTAL)"
+	depends on BLK_DEV_DM && EXPERIMENTAL
+	---help---
+	  Allow volume managers to support multipath hardware.
+
+config DM_MULTIPATH_EMC
+	tristate "EMC CX/AX multipath support (EXPERIMENTAL)"
+	depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+	---help---
+	  Multipath support for EMC CX/AX series hardware.
+
 endmenu
 
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -4,6 +4,7 @@
 
 dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
 		   dm-ioctl.o dm-io.o kcopyd.o
+dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
 dm-snapshot-objs := dm-snap.o dm-exception-store.o
 dm-mirror-objs	:= dm-log.o dm-raid1.o
 raid6-objs	:= raid6main.o raid6algos.o raid6recov.o raid6tables.o \
@@ -30,6 +31,8 @@ obj-$(CONFIG_MD_FAULTY)		+= faulty.o
 obj-$(CONFIG_BLK_DEV_MD)	+= md.o
 obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
+obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o
+obj-$(CONFIG_DM_MULTIPATH_EMC)	+= dm-emc.o
 obj-$(CONFIG_DM_SNAPSHOT)	+= dm-snapshot.o
 obj-$(CONFIG_DM_MIRROR)		+= dm-mirror.o
 obj-$(CONFIG_DM_ZERO)		+= dm-zero.o
diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-bio-record.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_BIO_RECORD_H
+#define DM_BIO_RECORD_H
+
+#include <linux/bio.h>
+
+/*
+ * There are lots of mutable fields in the bio struct that get
+ * changed by the lower levels of the block layer.  Some targets,
+ * such as multipath, may wish to resubmit a bio on error.  The
+ * functions in this file help the target record and restore the
+ * original bio state.
+ */
+struct dm_bio_details {
+	sector_t bi_sector;
+	struct block_device *bi_bdev;
+	unsigned int bi_size;
+	unsigned short bi_idx;
+	unsigned long bi_flags;
+};
+
+static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
+{
+	bd->bi_sector = bio->bi_sector;
+	bd->bi_bdev = bio->bi_bdev;
+	bd->bi_size = bio->bi_size;
+	bd->bi_idx = bio->bi_idx;
+	bd->bi_flags = bio->bi_flags;
+}
+
+static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
+{
+	bio->bi_sector = bd->bi_sector;
+	bio->bi_bdev = bd->bi_bdev;
+	bio->bi_size = bd->bi_size;
+	bio->bi_idx = bd->bi_idx;
+	bio->bi_flags = bd->bi_flags;
+}
+
+#endif
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -96,7 +96,7 @@ static kmem_cache_t *_crypt_io_pool;
 /*
  * Mempool alloc and free functions for the page
  */
-static void *mempool_alloc_page(int gfp_mask, void *data)
+static void *mempool_alloc_page(unsigned int __nocast gfp_mask, void *data)
 {
 	return alloc_page(gfp_mask);
 }
@@ -331,25 +331,19 @@ crypt_alloc_buffer(struct crypt_config *
 	struct bio *bio;
 	unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
-	unsigned long flags = current->flags;
 	unsigned int i;
 
 	/*
-	 * Tell VM to act less aggressively and fail earlier.
-	 * This is not necessary but increases throughput.
+	 * Use __GFP_NOMEMALLOC to tell the VM to act less aggressively and
+	 * to fail earlier.  This is not necessary but increases throughput.
 	 * FIXME: Is this really intelligent?
 	 */
-	current->flags &= ~PF_MEMALLOC;
-
 	if (base_bio)
-		bio = bio_clone(base_bio, GFP_NOIO);
+		bio = bio_clone(base_bio, GFP_NOIO|__GFP_NOMEMALLOC);
 	else
-		bio = bio_alloc(GFP_NOIO, nr_iovecs);
-	if (!bio) {
-		if (flags & PF_MEMALLOC)
-			current->flags |= PF_MEMALLOC;
+		bio = bio_alloc(GFP_NOIO|__GFP_NOMEMALLOC, nr_iovecs);
+	if (!bio)
 		return NULL;
-	}
 
 	/* if the last bio was not complete, continue where that one ended */
 	bio->bi_idx = *bio_vec_idx;
@@ -386,9 +380,6 @@ crypt_alloc_buffer(struct crypt_config *
 		size -= bv->bv_len;
 	}
 
-	if (flags & PF_MEMALLOC)
-		current->flags |= PF_MEMALLOC;
-
 	if (!bio->bi_size) {
 		bio_put(bio);
 		return NULL;
@@ -869,7 +860,6 @@ static int crypt_status(struct dm_target
 			char *result, unsigned int maxlen)
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
-	char buffer[32];
 	const char *cipher;
 	const char *chainmode = NULL;
 	unsigned int sz = 0;
@@ -910,9 +900,8 @@ static int crypt_status(struct dm_target
 			result[sz++] = '-';
 		}
 
-		format_dev_t(buffer, cc->dev->bdev->bd_dev);
 		DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
-		       cc->iv_offset, buffer, cc->start);
+		       cc->iv_offset, cc->dev->name, cc->start);
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-emc.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2004 SUSE LINUX Products GmbH. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ *
+ * Multipath support for EMC CLARiiON AX/CX-series hardware.
+ */
+
+#include "dm.h"
+#include "dm-hw-handler.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+struct emc_handler {
+	spinlock_t lock;
+
+	/* Whether we should send the short trespass command (FC-series)
+	 * or the long version (default for AX/CX CLARiiON arrays). */
+	unsigned short_trespass;
+	/* Whether or not to honor SCSI reservations when initiating a
+	 * switch-over. Default: Don't. */
+	unsigned hr;
+
+	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+};
+
+#define TRESPASS_PAGE 0x22
+#define EMC_FAILOVER_TIMEOUT (60 * HZ)
+
+/* Code borrowed from dm-lsi-rdac by Mike Christie */
+
+static inline void free_bio(struct bio *bio)
+{
+	__free_page(bio->bi_io_vec[0].bv_page);
+	bio_put(bio);
+}
+
+static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
+{
+	struct path *path = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
+
+	/* We also need to look at the sense keys here whether or not to
+	 * switch to the next PG etc.
+	 *
+	 * For now simple logic: either it works or it doesn't.
+	 */
+	if (error)
+		dm_pg_init_complete(path, MP_FAIL_PATH);
+	else
+		dm_pg_init_complete(path, 0);
+
+	/* request is freed in block layer */
+	free_bio(bio);
+
+	return 0;
+}
+
+static struct bio *get_failover_bio(struct path *path, unsigned data_size)
+{
+	struct bio *bio;
+	struct page *page;
+
+	bio = bio_alloc(GFP_ATOMIC, 1);
+	if (!bio) {
+		DMERR("dm-emc: get_failover_bio: bio_alloc() failed.");
+		return NULL;
+	}
+
+	bio->bi_rw |= (1 << BIO_RW);
+	bio->bi_bdev = path->dev->bdev;
+	bio->bi_sector = 0;
+	bio->bi_private = path;
+	bio->bi_end_io = emc_endio;
+
+	page = alloc_page(GFP_ATOMIC);
+	if (!page) {
+		DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+		bio_put(bio);
+		return NULL;
+	}
+
+	if (bio_add_page(bio, page, data_size, 0) != data_size) {
+		DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+		__free_page(page);
+		bio_put(bio);
+		return NULL;
+	}
+
+	return bio;
+}
+
+static struct request *get_failover_req(struct emc_handler *h,
+					struct bio *bio, struct path *path)
+{
+	struct request *rq;
+	struct block_device *bdev = bio->bi_bdev;
+	struct request_queue *q = bdev_get_queue(bdev);
+
+	/* FIXME: Figure out why it fails with GFP_ATOMIC. */
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	if (!rq) {
+		DMERR("dm-emc: get_failover_req: blk_get_request failed");
+		return NULL;
+	}
+
+	rq->bio = rq->biotail = bio;
+	blk_rq_bio_prep(q, rq, bio);
+
+	rq->rq_disk = bdev->bd_contains->bd_disk;
+
+	/* bio backed don't set data */
+	rq->buffer = rq->data = NULL;
+	/* rq data_len used for pc cmd's request_bufflen */
+	rq->data_len = bio->bi_size;
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = 0;
+
+	memset(&rq->cmd, 0, BLK_MAX_CDB);
+
+	rq->timeout = EMC_FAILOVER_TIMEOUT;
+	rq->flags |= (REQ_BLOCK_PC | REQ_FAILFAST | REQ_NOMERGE);
+
+	return rq;
+}
+
+static struct request *emc_trespass_get(struct emc_handler *h,
+					struct path *path)
+{
+	struct bio *bio;
+	struct request *rq;
+	unsigned char *page22;
+	unsigned char long_trespass_pg[] = {
+		0, 0, 0, 0,
+		TRESPASS_PAGE,        /* Page code */
+		0x09,                 /* Page length - 2 */
+		h->hr ? 0x01 : 0x81,  /* Trespass code + Honor reservation bit */
+		0xff, 0xff,           /* Trespass target */
+		0, 0, 0, 0, 0, 0      /* Reserved bytes / unknown */
+		};
+	unsigned char short_trespass_pg[] = {
+		0, 0, 0, 0,
+		TRESPASS_PAGE,        /* Page code */
+		0x02,                 /* Page length - 2 */
+		h->hr ? 0x01 : 0x81,  /* Trespass code + Honor reservation bit */
+		0xff,                 /* Trespass target */
+		};
+	unsigned data_size = h->short_trespass ? sizeof(short_trespass_pg) :
+				sizeof(long_trespass_pg);
+
+	/* get bio backing */
+	if (data_size > PAGE_SIZE)
+		/* this should never happen */
+		return NULL;
+
+	bio = get_failover_bio(path, data_size);
+	if (!bio) {
+		DMERR("dm-emc: emc_trespass_get: no bio");
+		return NULL;
+	}
+
+	page22 = (unsigned char *)bio_data(bio);
+	memset(page22, 0, data_size);
+
+	memcpy(page22, h->short_trespass ?
+		short_trespass_pg : long_trespass_pg, data_size);
+
+	/* get request for block layer packet command */
+	rq = get_failover_req(h, bio, path);
+	if (!rq) {
+		DMERR("dm-emc: emc_trespass_get: no rq");
+		free_bio(bio);
+		return NULL;
+	}
+
+	/* Prepare the command. */
+	rq->cmd[0] = MODE_SELECT;
+	rq->cmd[1] = 0x10;
+	rq->cmd[4] = data_size;
+	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+
+	return rq;
+}
+
+static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed,
+			struct path *path)
+{
+	struct request *rq;
+	struct request_queue *q = bdev_get_queue(path->dev->bdev);
+
+	/*
+	 * We can either blindly init the pg (then look at the sense),
+	 * or we can send some commands to get the state here (then
+	 * possibly send the fo cmnd), or we can also have the
+	 * initial state passed into us and then get an update here.
+	 */
+	if (!q) {
+		DMINFO("dm-emc: emc_pg_init: no queue");
+		goto fail_path;
+	}
+
+	/* FIXME: The request should be pre-allocated. */
+	rq = emc_trespass_get(hwh->context, path);
+	if (!rq) {
+		DMERR("dm-emc: emc_pg_init: no rq");
+		goto fail_path;
+	}
+
+	DMINFO("dm-emc: emc_pg_init: sending switch-over command");
+	elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
+	return;
+
+fail_path:
+	dm_pg_init_complete(path, MP_FAIL_PATH);
+}
+
+static struct emc_handler *alloc_emc_handler(void)
+{
+	struct emc_handler *h = kmalloc(sizeof(*h), GFP_KERNEL);
+
+	if (h) {
+		memset(h, 0, sizeof(*h));
+		spin_lock_init(&h->lock);
+	}
+
+	return h;
+}
+
+static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv)
+{
+	struct emc_handler *h;
+	unsigned hr, short_trespass;
+
+	if (argc == 0) {
+		/* No arguments: use defaults */
+		hr = 0;
+		short_trespass = 0;
+	} else if (argc != 2) {
+		DMWARN("dm-emc hwhandler: incorrect number of arguments");
+		return -EINVAL;
+	} else {
+		if ((sscanf(argv[0], "%u", &short_trespass) != 1)
+			|| (short_trespass > 1)) {
+			DMWARN("dm-emc: invalid trespass mode selected");
+			return -EINVAL;
+		}
+
+		if ((sscanf(argv[1], "%u", &hr) != 1)
+			|| (hr > 1)) {
+			DMWARN("dm-emc: invalid honor reservation flag selected");
+			return -EINVAL;
+		}
+	}
+
+	h = alloc_emc_handler();
+	if (!h)
+		return -ENOMEM;
+
+	hwh->context = h;
+
+	if ((h->short_trespass = short_trespass))
+		DMWARN("dm-emc: short trespass command will be send");
+	else
+		DMWARN("dm-emc: long trespass command will be send");
+
+	if ((h->hr = hr))
+		DMWARN("dm-emc: honor reservation bit will be set");
+	else
+		DMWARN("dm-emc: honor reservation bit will not be set (default)");
+
+	return 0;
+}
+
+static void emc_destroy(struct hw_handler *hwh)
+{
+	struct emc_handler *h = (struct emc_handler *) hwh->context;
+
+	kfree(h);
+	hwh->context = NULL;
+}
+
+static unsigned emc_error(struct hw_handler *hwh, struct bio *bio)
+{
+	/* FIXME: Patch from axboe still missing */
+#if 0
+	int sense;
+
+	if (bio->bi_error & BIO_SENSE) {
+		sense = bio->bi_error & 0xffffff; /* sense key / asc / ascq */
+
+		if (sense == 0x020403) {
+			/* LUN Not Ready - Manual Intervention Required
+			 * indicates this is a passive path.
+			 *
+			 * FIXME: However, if this is seen and EVPD C0
+			 * indicates that this is due to a NDU in
+			 * progress, we should set FAIL_PATH too.
+			 * This indicates we might have to do a SCSI
+			 * inquiry in the end_io path. Ugh. */
+			return MP_BYPASS_PG | MP_RETRY_IO;
+		} else if (sense == 0x052501) {
+			/* An array based copy is in progress. Do not
+			 * fail the path, do not bypass to another PG,
+			 * do not retry. Fail the IO immediately.
+			 * (Actually this is the same conclusion as in
+			 * the default handler, but lets make sure.) */
+			return 0;
+		} else if (sense == 0x062900) {
+			/* Unit Attention Code. This is the first IO
+			 * to the new path, so just retry. */
+			return MP_RETRY_IO;
+		}
+	}
+#endif
+
+	/* Try default handler */
+	return dm_scsi_err_handler(hwh, bio);
+}
+
+static struct hw_handler_type emc_hwh = {
+	.name = "emc",
+	.module = THIS_MODULE,
+	.create = emc_create,
+	.destroy = emc_destroy,
+	.pg_init = emc_pg_init,
+	.error = emc_error,
+};
+
+static int __init dm_emc_init(void)
+{
+	int r = dm_register_hw_handler(&emc_hwh);
+
+	if (r < 0)
+		DMERR("emc: register failed %d", r);
+
+	DMINFO("dm-emc version 0.0.3 loaded");
+
+	return r;
+}
+
+static void __exit dm_emc_exit(void)
+{
+	int r = dm_unregister_hw_handler(&emc_hwh);
+
+	if (r < 0)
+		DMERR("emc: unregister failed %d", r);
+}
+
+module_init(dm_emc_init);
+module_exit(dm_emc_exit);
+
+MODULE_DESCRIPTION(DM_NAME " EMC CX/AX/FC-family multipath");
+MODULE_AUTHOR("Lars Marowsky-Bree <lmb@suse.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-hw-handler.c b/drivers/md/dm-hw-handler.c
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-hw-handler.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ *
+ * Multipath hardware handler registration.
+ */
+
+#include "dm.h"
+#include "dm-hw-handler.h"
+
+#include <linux/slab.h>
+
+struct hwh_internal {
+	struct hw_handler_type hwht;
+
+	struct list_head list;
+	long use;
+};
+
+#define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht)
+
+static LIST_HEAD(_hw_handlers);
+static DECLARE_RWSEM(_hwh_lock);
+
+static struct hwh_internal *__find_hw_handler_type(const char *name)
+{
+	struct hwh_internal *hwhi;
+
+	list_for_each_entry(hwhi, &_hw_handlers, list) {
+		if (!strcmp(name, hwhi->hwht.name))
+			return hwhi;
+	}
+
+	return NULL;
+}
+
+static struct hwh_internal *get_hw_handler(const char *name)
+{
+	struct hwh_internal *hwhi;
+
+	down_read(&_hwh_lock);
+	hwhi = __find_hw_handler_type(name);
+	if (hwhi) {
+		if ((hwhi->use == 0) && !try_module_get(hwhi->hwht.module))
+			hwhi = NULL;
+		else
+			hwhi->use++;
+	}
+	up_read(&_hwh_lock);
+
+	return hwhi;
+}
+
+struct hw_handler_type *dm_get_hw_handler(const char *name)
+{
+	struct hwh_internal *hwhi;
+
+	if (!name)
+		return NULL;
+
+	hwhi = get_hw_handler(name);
+	if (!hwhi) {
+		request_module("dm-%s", name);
+		hwhi = get_hw_handler(name);
+	}
+
+	return hwhi ? &hwhi->hwht : NULL;
+}
+
+void dm_put_hw_handler(struct hw_handler_type *hwht)
+{
+	struct hwh_internal *hwhi;
+
+	if (!hwht)
+		return;
+
+	down_read(&_hwh_lock);
+	hwhi = __find_hw_handler_type(hwht->name);
+	if (!hwhi)
+		goto out;
+
+	if (--hwhi->use == 0)
+		module_put(hwhi->hwht.module);
+
+	if (hwhi->use < 0)
+		BUG();
+
+      out:
+	up_read(&_hwh_lock);
+}
+
+static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht)
+{
+	struct hwh_internal *hwhi = kmalloc(sizeof(*hwhi), GFP_KERNEL);
+
+	if (hwhi) {
+		memset(hwhi, 0, sizeof(*hwhi));
+		hwhi->hwht = *hwht;
+	}
+
+	return hwhi;
+}
+
+int dm_register_hw_handler(struct hw_handler_type *hwht)
+{
+	int r = 0;
+	struct hwh_internal *hwhi = _alloc_hw_handler(hwht);
+
+	if (!hwhi)
+		return -ENOMEM;
+
+	down_write(&_hwh_lock);
+
+	if (__find_hw_handler_type(hwht->name)) {
+		kfree(hwhi);
+		r = -EEXIST;
+	} else
+		list_add(&hwhi->list, &_hw_handlers);
+
+	up_write(&_hwh_lock);
+
+	return r;
+}
+
+int dm_unregister_hw_handler(struct hw_handler_type *hwht)
+{
+	struct hwh_internal *hwhi;
+
+	down_write(&_hwh_lock);
+
+	hwhi = __find_hw_handler_type(hwht->name);
+	if (!hwhi) {
+		up_write(&_hwh_lock);
+		return -EINVAL;
+	}
+
+	if (hwhi->use) {
+		up_write(&_hwh_lock);
+		return -ETXTBSY;
+	}
+
+	list_del(&hwhi->list);
+
+	up_write(&_hwh_lock);
+
+	kfree(hwhi);
+
+	return 0;
+}
+
+unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio)
+{
+#if 0
+	int sense_key, asc, ascq;
+
+	if (bio->bi_error & BIO_SENSE) {
+		/* FIXME: This is just an initial guess. */
+		/* key / asc / ascq */
+		sense_key = (bio->bi_error >> 16) & 0xff;
+		asc = (bio->bi_error >> 8) & 0xff;
+		ascq = bio->bi_error & 0xff;
+
+		switch (sense_key) {
+			/* This block as a whole comes from the device.
+			 * So no point retrying on another path. */
+		case 0x03:	/* Medium error */
+		case 0x05:	/* Illegal request */
+		case 0x07:	/* Data protect */
+		case 0x08:	/* Blank check */
+		case 0x0a:	/* copy aborted */
+		case 0x0c:	/* obsolete - no clue ;-) */
+		case 0x0d:	/* volume overflow */
+		case 0x0e:	/* data miscompare */
+		case 0x0f:	/* reserved - no idea either. */
+			return MP_ERROR_IO;
+
+			/* For these errors it's unclear whether they
+			 * come from the device or the controller.
+			 * So just lets try a different path, and if
+			 * it eventually succeeds, user-space will clear
+			 * the paths again... */
+		case 0x02:	/* Not ready */
+		case 0x04:	/* Hardware error */
+		case 0x09:	/* vendor specific */
+		case 0x0b:	/* Aborted command */
+			return MP_FAIL_PATH;
+
+		case 0x06:	/* Unit attention - might want to decode */
+			if (asc == 0x04 && ascq == 0x01)
+				/* "Unit in the process of
+				 * becoming ready" */
+				return 0;
+			return MP_FAIL_PATH;
+
+			/* FIXME: For Unit Not Ready we may want
+			 * to have a generic pg activation
+			 * feature (START_UNIT). */
+
+			/* Should these two ever end up in the
+			 * error path? I don't think so. */
+		case 0x00:	/* No sense */
+		case 0x01:	/* Recovered error */
+			return 0;
+		}
+	}
+#endif
+
+	/* We got no idea how to decode the other kinds of errors ->
+	 * assume generic error condition. */
+	return MP_FAIL_PATH;
+}
+
+EXPORT_SYMBOL_GPL(dm_register_hw_handler);
+EXPORT_SYMBOL_GPL(dm_unregister_hw_handler);
+EXPORT_SYMBOL_GPL(dm_scsi_err_handler);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-hw-handler.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ *
+ * Multipath hardware handler registration.
+ */
+
+#ifndef	DM_HW_HANDLER_H
+#define	DM_HW_HANDLER_H
+
+#include <linux/device-mapper.h>
+
+#include "dm-mpath.h"
+
+struct hw_handler_type;
+struct hw_handler {
+	struct hw_handler_type *type;
+	void *context;
+};
+
+/*
+ * Constructs a hardware handler object, takes custom arguments
+ */
+/* Information about a hardware handler type */
+struct hw_handler_type {
+	char *name;
+	struct module *module;
+
+	int (*create) (struct hw_handler *handler, unsigned int argc,
+		       char **argv);
+	void (*destroy) (struct hw_handler *hwh);
+
+	void (*pg_init) (struct hw_handler *hwh, unsigned bypassed,
+			 struct path *path);
+	unsigned (*error) (struct hw_handler *hwh, struct bio *bio);
+	int (*status) (struct hw_handler *hwh, status_type_t type,
+		       char *result, unsigned int maxlen);
+};
+
+/* Register a hardware handler */
+int dm_register_hw_handler(struct hw_handler_type *type);
+
+/* Unregister a hardware handler */
+int dm_unregister_hw_handler(struct hw_handler_type *type);
+
+/* Returns a registered hardware handler type */
+struct hw_handler_type *dm_get_hw_handler(const char *name);
+
+/* Releases a hardware handler  */
+void dm_put_hw_handler(struct hw_handler_type *hwht);
+
+/* Default err function */
+unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio);
+
+/* Error flags for err and dm_pg_init_complete */
+#define MP_FAIL_PATH 1
+#define MP_BYPASS_PG 2
+#define MP_ERROR_IO  4	/* Don't retry this I/O */
+
+#endif
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -12,191 +12,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-#define BIO_POOL_SIZE 256
-
-
-/*-----------------------------------------------------------------
- * Bio set, move this to bio.c
- *---------------------------------------------------------------*/
-#define BV_NAME_SIZE 16
-struct biovec_pool {
-	int nr_vecs;
-	char name[BV_NAME_SIZE];
-	kmem_cache_t *slab;
-	mempool_t *pool;
-	atomic_t allocated;	/* FIXME: debug */
-};
-
-#define BIOVEC_NR_POOLS 6
-struct bio_set {
-	char name[BV_NAME_SIZE];
-	kmem_cache_t *bio_slab;
-	mempool_t *bio_pool;
-	struct biovec_pool pools[BIOVEC_NR_POOLS];
-};
-
-static void bio_set_exit(struct bio_set *bs)
-{
-	unsigned i;
-	struct biovec_pool *bp;
-
-	if (bs->bio_pool)
-		mempool_destroy(bs->bio_pool);
-
-	if (bs->bio_slab)
-		kmem_cache_destroy(bs->bio_slab);
-
-	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-		bp = bs->pools + i;
-		if (bp->pool)
-			mempool_destroy(bp->pool);
-
-		if (bp->slab)
-			kmem_cache_destroy(bp->slab);
-	}
-}
-
-static void mk_name(char *str, size_t len, const char *prefix, unsigned count)
-{
-	snprintf(str, len, "%s-%u", prefix, count);
-}
-
-static int bio_set_init(struct bio_set *bs, const char *slab_prefix,
-			 unsigned pool_entries, unsigned scale)
-{
-	/* FIXME: this must match bvec_index(), why not go the
-	 * whole hog and have a pool per power of 2 ? */
-	static unsigned _vec_lengths[BIOVEC_NR_POOLS] = {
-		1, 4, 16, 64, 128, BIO_MAX_PAGES
-	};
-
-
-	unsigned i, size;
-	struct biovec_pool *bp;
-
-	/* zero the bs so we can tear down properly on error */
-	memset(bs, 0, sizeof(*bs));
-
-	/*
-	 * Set up the bio pool.
-	 */
-	snprintf(bs->name, sizeof(bs->name), "%s-bio", slab_prefix);
-
-	bs->bio_slab = kmem_cache_create(bs->name, sizeof(struct bio), 0,
-					 SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!bs->bio_slab) {
-		DMWARN("can't init bio slab");
-		goto bad;
-	}
-
-	bs->bio_pool = mempool_create(pool_entries, mempool_alloc_slab,
-				      mempool_free_slab, bs->bio_slab);
-	if (!bs->bio_pool) {
-		DMWARN("can't init bio pool");
-		goto bad;
-	}
-
-	/*
-	 * Set up the biovec pools.
-	 */
-	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-		bp = bs->pools + i;
-		bp->nr_vecs = _vec_lengths[i];
-		atomic_set(&bp->allocated, 1); /* FIXME: debug */
-
-
-		size = bp->nr_vecs * sizeof(struct bio_vec);
-
-		mk_name(bp->name, sizeof(bp->name), slab_prefix, i);
-		bp->slab = kmem_cache_create(bp->name, size, 0,
-					     SLAB_HWCACHE_ALIGN, NULL, NULL);
-		if (!bp->slab) {
-			DMWARN("can't init biovec slab cache");
-			goto bad;
-		}
-
-		if (i >= scale)
-			pool_entries >>= 1;
-
-		bp->pool = mempool_create(pool_entries, mempool_alloc_slab,
-					  mempool_free_slab, bp->slab);
-		if (!bp->pool) {
-			DMWARN("can't init biovec mempool");
-			goto bad;
-		}
-	}
-
-	return 0;
-
- bad:
-	bio_set_exit(bs);
-	return -ENOMEM;
-}
-
-/* FIXME: blech */
-static inline unsigned bvec_index(unsigned nr)
-{
-	switch (nr) {
-	case 1:		return 0;
-	case 2 ... 4: 	return 1;
-	case 5 ... 16:	return 2;
-	case 17 ... 64:	return 3;
-	case 65 ... 128:return 4;
-	case 129 ... BIO_MAX_PAGES: return 5;
-	}
-
-	BUG();
-	return 0;
-}
-
-static unsigned _bio_count = 0;
-struct bio *bio_set_alloc(struct bio_set *bs, int gfp_mask, int nr_iovecs)
-{
-	struct biovec_pool *bp;
-	struct bio_vec *bv = NULL;
-	unsigned long idx;
-	struct bio *bio;
-
-	bio = mempool_alloc(bs->bio_pool, gfp_mask);
-	if (unlikely(!bio))
-		return NULL;
-
-	bio_init(bio);
-
-	if (likely(nr_iovecs)) {
-		idx = bvec_index(nr_iovecs);
-		bp = bs->pools + idx;
-		bv = mempool_alloc(bp->pool, gfp_mask);
-		if (!bv) {
-			mempool_free(bio, bs->bio_pool);
-			return NULL;
-		}
-
-		memset(bv, 0, bp->nr_vecs * sizeof(*bv));
-		bio->bi_flags |= idx << BIO_POOL_OFFSET;
-		bio->bi_max_vecs = bp->nr_vecs;
-		atomic_inc(&bp->allocated);
-	}
-
-	bio->bi_io_vec = bv;
-	return bio;
-}
-
-static void bio_set_free(struct bio_set *bs, struct bio *bio)
-{
-	struct biovec_pool *bp = bs->pools + BIO_POOL_IDX(bio);
-
-	if (atomic_dec_and_test(&bp->allocated))
-		BUG();
-
-	mempool_free(bio->bi_io_vec, bp->pool);
-	mempool_free(bio, bs->bio_pool);
-}
-
-/*-----------------------------------------------------------------
- * dm-io proper
- *---------------------------------------------------------------*/
-static struct bio_set _bios;
+static struct bio_set *_bios;
 
 /* FIXME: can we shrink this ? */
 struct io {
@@ -216,7 +32,7 @@ struct io {
 static unsigned _num_ios;
 static mempool_t *_io_pool;
 
-static void *alloc_io(int gfp_mask, void *pool_data)
+static void *alloc_io(unsigned int __nocast gfp_mask, void *pool_data)
 {
 	return kmalloc(sizeof(struct io), gfp_mask);
 }
@@ -240,7 +56,7 @@ static int resize_pool(unsigned int new_
 			/* free off the pool */
 			mempool_destroy(_io_pool);
 			_io_pool = NULL;
-			bio_set_exit(&_bios);
+			bioset_free(_bios);
 
 		} else {
 			/* resize the pool */
@@ -253,10 +69,11 @@ static int resize_pool(unsigned int new_
 		if (!_io_pool)
 			return -ENOMEM;
 
-		r = bio_set_init(&_bios, "dm-io", 512, 1);
-		if (r) {
+		_bios = bioset_create(16, 16, 4);
+		if (!_bios) {
 			mempool_destroy(_io_pool);
 			_io_pool = NULL;
+			return -ENOMEM;
 		}
 	}
 
@@ -280,6 +97,7 @@ void dm_io_put(unsigned int num_pages)
  * We need to keep track of which region a bio is doing io for.
  * In order to save a memory allocation we store this the last
  * bvec which we know is unused (blech).
+ * XXX This is ugly and can OOPS with some configs... find another way.
  *---------------------------------------------------------------*/
 static inline void bio_set_region(struct bio *bio, unsigned region)
 {
@@ -315,21 +133,6 @@ static void dec_count(struct io *io, uns
 	}
 }
 
-/* FIXME Move this to bio.h? */
-static void zero_fill_bio(struct bio *bio)
-{
-	unsigned long flags;
-	struct bio_vec *bv;
-	int i;
-
-	bio_for_each_segment(bv, bio, i) {
-		char *data = bvec_kmap_irq(bv, &flags);
-		memset(data, 0, bv->bv_len);
-		flush_dcache_page(bv->bv_page);
-		bvec_kunmap_irq(data, &flags);
-	}
-}
-
 static int endio(struct bio *bio, unsigned int done, int error)
 {
 	struct io *io = (struct io *) bio->bi_private;
@@ -347,12 +150,6 @@ static int endio(struct bio *bio, unsign
 	return 0;
 }
 
-static void bio_dtr(struct bio *bio)
-{
-	_bio_count--;
-	bio_set_free(&_bios, bio);
-}
-
 /*-----------------------------------------------------------------
  * These little objects provide an abstraction for getting a new
  * destination page for io.
@@ -461,13 +258,11 @@ static void do_region(int rw, unsigned i
 		 * bvec for bio_get/set_region().
 		 */
 		num_bvecs = (remaining / (PAGE_SIZE >> 9)) + 2;
-		_bio_count++;
-		bio = bio_set_alloc(&_bios, GFP_NOIO, num_bvecs);
+		bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
 		bio->bi_sector = where->sector + (where->count - remaining);
 		bio->bi_bdev = where->bdev;
 		bio->bi_end_io = endio;
 		bio->bi_private = io;
-		bio->bi_destructor = bio_dtr;
 		bio_set_region(bio, region);
 
 		/*
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -80,7 +80,6 @@ static int linear_status(struct dm_targe
 			 char *result, unsigned int maxlen)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
-	char buffer[32];
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -88,8 +87,8 @@ static int linear_status(struct dm_targe
 		break;
 
 	case STATUSTYPE_TABLE:
-		format_dev_t(buffer, lc->dev->bdev->bd_dev);
-		snprintf(result, maxlen, "%s " SECTOR_FORMAT, buffer, lc->start);
+		snprintf(result, maxlen, "%s " SECTOR_FORMAT, lc->dev->name,
+			 lc->start);
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-mpath.c
@@ -0,0 +1,1317 @@
+/*
+ * Copyright (C) 2003 Sistina Software Limited.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+#include "dm-hw-handler.h"
+#include "dm-bio-list.h"
+#include "dm-bio-record.h"
+
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+#define MESG_STR(x) x, sizeof(x)
+
+/* Path properties */
+struct pgpath {
+	struct list_head list;
+
+	struct priority_group *pg;	/* Owning PG */
+	unsigned fail_count;		/* Cumulative failure count */
+
+	struct path path;
+};
+
+#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
+
+/*
+ * Paths are grouped into Priority Groups and numbered from 1 upwards.
+ * Each has a path selector which controls which path gets used.
+ */
+struct priority_group {
+	struct list_head list;
+
+	struct multipath *m;		/* Owning multipath instance */
+	struct path_selector ps;
+
+	unsigned pg_num;		/* Reference number */
+	unsigned bypassed;		/* Temporarily bypass this PG? */
+
+	unsigned nr_pgpaths;		/* Number of paths in PG */
+	struct list_head pgpaths;
+};
+
+/* Multipath context */
+struct multipath {
+	struct list_head list;
+	struct dm_target *ti;
+
+	spinlock_t lock;
+
+	struct hw_handler hw_handler;
+	unsigned nr_priority_groups;
+	struct list_head priority_groups;
+	unsigned pg_init_required;	/* pg_init needs calling? */
+
+	unsigned nr_valid_paths;	/* Total number of usable paths */
+	struct pgpath *current_pgpath;
+	struct priority_group *current_pg;
+	struct priority_group *next_pg;	/* Switch to this PG if set */
+	unsigned repeat_count;		/* I/Os left before calling PS again */
+
+	unsigned queue_io;		/* Must we queue all I/O? */
+	unsigned queue_if_no_path;	/* Queue I/O if last path fails? */
+	unsigned suspended;		/* Has dm core suspended our I/O? */
+
+	struct work_struct process_queued_ios;
+	struct bio_list queued_ios;
+	unsigned queue_size;
+
+	struct work_struct trigger_event;
+
+	/*
+	 * We must use a mempool of mpath_io structs so that we
+	 * can resubmit bios on error.
+	 */
+	mempool_t *mpio_pool;
+};
+
+/*
+ * Context information attached to each bio we process.
+ */
+struct mpath_io {
+	struct pgpath *pgpath;
+	struct dm_bio_details details;
+};
+
+typedef int (*action_fn) (struct pgpath *pgpath);
+
+#define MIN_IOS 256	/* Mempool size */
+
+static kmem_cache_t *_mpio_cache;
+
+struct workqueue_struct *kmultipathd;
+static void process_queued_ios(void *data);
+static void trigger_event(void *data);
+
+
+/*-----------------------------------------------
+ * Allocation routines
+ *-----------------------------------------------*/
+
+static struct pgpath *alloc_pgpath(void)
+{
+	struct pgpath *pgpath = kmalloc(sizeof(*pgpath), GFP_KERNEL);
+
+	if (pgpath) {
+		memset(pgpath, 0, sizeof(*pgpath));
+		pgpath->path.is_active = 1;
+	}
+
+	return pgpath;
+}
+
+static inline void free_pgpath(struct pgpath *pgpath)
+{
+	kfree(pgpath);
+}
+
+static struct priority_group *alloc_priority_group(void)
+{
+	struct priority_group *pg;
+
+	pg = kmalloc(sizeof(*pg), GFP_KERNEL);
+	if (!pg)
+		return NULL;
+
+	memset(pg, 0, sizeof(*pg));
+	INIT_LIST_HEAD(&pg->pgpaths);
+
+	return pg;
+}
+
+static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
+{
+	struct pgpath *pgpath, *tmp;
+
+	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
+		list_del(&pgpath->list);
+		dm_put_device(ti, pgpath->path.dev);
+		free_pgpath(pgpath);
+	}
+}
+
+static void free_priority_group(struct priority_group *pg,
+				struct dm_target *ti)
+{
+	struct path_selector *ps = &pg->ps;
+
+	if (ps->type) {
+		ps->type->destroy(ps);
+		dm_put_path_selector(ps->type);
+	}
+
+	free_pgpaths(&pg->pgpaths, ti);
+	kfree(pg);
+}
+
+static struct multipath *alloc_multipath(void)
+{
+	struct multipath *m;
+
+	m = kmalloc(sizeof(*m), GFP_KERNEL);
+	if (m) {
+		memset(m, 0, sizeof(*m));
+		INIT_LIST_HEAD(&m->priority_groups);
+		spin_lock_init(&m->lock);
+		m->queue_io = 1;
+		INIT_WORK(&m->process_queued_ios, process_queued_ios, m);
+		INIT_WORK(&m->trigger_event, trigger_event, m);
+		m->mpio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
+					      mempool_free_slab, _mpio_cache);
+		if (!m->mpio_pool) {
+			kfree(m);
+			return NULL;
+		}
+	}
+
+	return m;
+}
+
+static void free_multipath(struct multipath *m)
+{
+	struct priority_group *pg, *tmp;
+	struct hw_handler *hwh = &m->hw_handler;
+
+	list_for_each_entry_safe(pg, tmp, &m->priority_groups, list) {
+		list_del(&pg->list);
+		free_priority_group(pg, m->ti);
+	}
+
+	if (hwh->type) {
+		hwh->type->destroy(hwh);
+		dm_put_hw_handler(hwh->type);
+	}
+
+	mempool_destroy(m->mpio_pool);
+	kfree(m);
+}
+
+
+/*-----------------------------------------------
+ * Path selection
+ *-----------------------------------------------*/
+
+static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
+{
+	struct hw_handler *hwh = &m->hw_handler;
+
+	m->current_pg = pgpath->pg;
+
+	/* Must we initialise the PG first, and queue I/O till it's ready? */
+	if (hwh->type && hwh->type->pg_init) {
+		m->pg_init_required = 1;
+		m->queue_io = 1;
+	} else {
+		m->pg_init_required = 0;
+		m->queue_io = 0;
+	}
+}
+
+static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
+{
+	struct path *path;
+
+	path = pg->ps.type->select_path(&pg->ps, &m->repeat_count);
+	if (!path)
+		return -ENXIO;
+
+	m->current_pgpath = path_to_pgpath(path);
+
+	if (m->current_pg != pg)
+		__switch_pg(m, m->current_pgpath);
+
+	return 0;
+}
+
+static void __choose_pgpath(struct multipath *m)
+{
+	struct priority_group *pg;
+	unsigned bypassed = 1;
+
+	if (!m->nr_valid_paths)
+		goto failed;
+
+	/* Were we instructed to switch PG? */
+	if (m->next_pg) {
+		pg = m->next_pg;
+		m->next_pg = NULL;
+		if (!__choose_path_in_pg(m, pg))
+			return;
+	}
+
+	/* Don't change PG until it has no remaining paths */
+	if (m->current_pg && !__choose_path_in_pg(m, m->current_pg))
+		return;
+
+	/*
+	 * Loop through priority groups until we find a valid path.
+	 * First time we skip PGs marked 'bypassed'.
+	 * Second time we only try the ones we skipped.
+	 */
+	do {
+		list_for_each_entry(pg, &m->priority_groups, list) {
+			if (pg->bypassed == bypassed)
+				continue;
+			if (!__choose_path_in_pg(m, pg))
+				return;
+		}
+	} while (bypassed--);
+
+failed:
+	m->current_pgpath = NULL;
+	m->current_pg = NULL;
+}
+
+static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
+		  unsigned was_queued)
+{
+	int r = 1;
+	unsigned long flags;
+	struct pgpath *pgpath;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	/* Do we need to select a new pgpath? */
+	if (!m->current_pgpath ||
+	    (!m->queue_io && (m->repeat_count && --m->repeat_count == 0)))
+		__choose_pgpath(m);
+
+	pgpath = m->current_pgpath;
+
+	if (was_queued)
+		m->queue_size--;
+
+	if ((pgpath && m->queue_io) ||
+	    (!pgpath && m->queue_if_no_path && !m->suspended)) {
+		/* Queue for the daemon to resubmit */
+		bio_list_add(&m->queued_ios, bio);
+		m->queue_size++;
+		if (m->pg_init_required || !m->queue_io)
+			queue_work(kmultipathd, &m->process_queued_ios);
+		pgpath = NULL;
+		r = 0;
+	} else if (!pgpath)
+		r = -EIO;		/* Failed */
+	else
+		bio->bi_bdev = pgpath->path.dev->bdev;
+
+	mpio->pgpath = pgpath;
+
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	return r;
+}
+
+/*
+ * If we run out of usable paths, should we queue I/O or error it?
+ */
+static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	m->queue_if_no_path = queue_if_no_path;
+	if (!m->queue_if_no_path)
+		queue_work(kmultipathd, &m->process_queued_ios);
+
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * The multipath daemon is responsible for resubmitting queued ios.
+ *---------------------------------------------------------------*/
+
+static void dispatch_queued_ios(struct multipath *m)
+{
+	int r;
+	unsigned long flags;
+	struct bio *bio = NULL, *next;
+	struct mpath_io *mpio;
+	union map_info *info;
+
+	spin_lock_irqsave(&m->lock, flags);
+	bio = bio_list_get(&m->queued_ios);
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	while (bio) {
+		next = bio->bi_next;
+		bio->bi_next = NULL;
+
+		info = dm_get_mapinfo(bio);
+		mpio = info->ptr;
+
+		r = map_io(m, bio, mpio, 1);
+		if (r < 0)
+			bio_endio(bio, bio->bi_size, r);
+		else if (r == 1)
+			generic_make_request(bio);
+
+		bio = next;
+	}
+}
+
+static void process_queued_ios(void *data)
+{
+	struct multipath *m = (struct multipath *) data;
+	struct hw_handler *hwh = &m->hw_handler;
+	struct pgpath *pgpath;
+	unsigned init_required, must_queue = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	if (!m->current_pgpath)
+		__choose_pgpath(m);
+
+	pgpath = m->current_pgpath;
+
+	if ((pgpath && m->queue_io) ||
+	    (!pgpath && m->queue_if_no_path && !m->suspended))
+		must_queue = 1;
+
+	init_required = m->pg_init_required;
+	if (init_required)
+		m->pg_init_required = 0;
+
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	if (init_required)
+		hwh->type->pg_init(hwh, pgpath->pg->bypassed, &pgpath->path);
+
+	if (!must_queue)
+		dispatch_queued_ios(m);
+}
+
+/*
+ * An event is triggered whenever a path is taken out of use.
+ * Includes path failure and PG bypass.
+ */
+static void trigger_event(void *data)
+{
+	struct multipath *m = (struct multipath *) data;
+
+	dm_table_event(m->ti->table);
+}
+
+/*-----------------------------------------------------------------
+ * Constructor/argument parsing:
+ * <#multipath feature args> [<arg>]*
+ * <#hw_handler args> [hw_handler [<arg>]*]
+ * <#priority groups>
+ * <initial priority group>
+ *     [<selector> <#selector args> [<arg>]*
+ *      <#paths> <#per-path selector args>
+ *         [<path> [<arg>]* ]+ ]+
+ *---------------------------------------------------------------*/
+struct param {
+	unsigned min;
+	unsigned max;
+	char *error;
+};
+
+#define ESTR(s) ("dm-multipath: " s)
+
+static int read_param(struct param *param, char *str, unsigned *v, char **error)
+{
+	if (!str ||
+	    (sscanf(str, "%u", v) != 1) ||
+	    (*v < param->min) ||
+	    (*v > param->max)) {
+		*error = param->error;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct arg_set {
+	unsigned argc;
+	char **argv;
+};
+
+static char *shift(struct arg_set *as)
+{
+	char *r;
+
+	if (as->argc) {
+		as->argc--;
+		r = *as->argv;
+		as->argv++;
+		return r;
+	}
+
+	return NULL;
+}
+
+static void consume(struct arg_set *as, unsigned n)
+{
+	BUG_ON (as->argc < n);
+	as->argc -= n;
+	as->argv += n;
+}
+
+static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
+			       struct dm_target *ti)
+{
+	int r;
+	struct path_selector_type *pst;
+	unsigned ps_argc;
+
+	static struct param _params[] = {
+		{0, 1024, ESTR("invalid number of path selector args")},
+	};
+
+	pst = dm_get_path_selector(shift(as));
+	if (!pst) {
+		ti->error = ESTR("unknown path selector type");
+		return -EINVAL;
+	}
+
+	r = read_param(_params, shift(as), &ps_argc, &ti->error);
+	if (r)
+		return -EINVAL;
+
+	r = pst->create(&pg->ps, ps_argc, as->argv);
+	if (r) {
+		dm_put_path_selector(pst);
+		ti->error = ESTR("path selector constructor failed");
+		return r;
+	}
+
+	pg->ps.type = pst;
+	consume(as, ps_argc);
+
+	return 0;
+}
+
+static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
+			       struct dm_target *ti)
+{
+	int r;
+	struct pgpath *p;
+
+	/* we need at least a path arg */
+	if (as->argc < 1) {
+		ti->error = ESTR("no device given");
+		return NULL;
+	}
+
+	p = alloc_pgpath();
+	if (!p)
+		return NULL;
+
+	r = dm_get_device(ti, shift(as), ti->begin, ti->len,
+			  dm_table_get_mode(ti->table), &p->path.dev);
+	if (r) {
+		ti->error = ESTR("error getting device");
+		goto bad;
+	}
+
+	r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
+	if (r) {
+		dm_put_device(ti, p->path.dev);
+		goto bad;
+	}
+
+	return p;
+
+ bad:
+	free_pgpath(p);
+	return NULL;
+}
+
+static struct priority_group *parse_priority_group(struct arg_set *as,
+						   struct multipath *m,
+						   struct dm_target *ti)
+{
+	static struct param _params[] = {
+		{1, 1024, ESTR("invalid number of paths")},
+		{0, 1024, ESTR("invalid number of selector args")}
+	};
+
+	int r;
+	unsigned i, nr_selector_args, nr_params;
+	struct priority_group *pg;
+
+	if (as->argc < 2) {
+		as->argc = 0;
+		ti->error = ESTR("not enough priority group aruments");
+		return NULL;
+	}
+
+	pg = alloc_priority_group();
+	if (!pg) {
+		ti->error = ESTR("couldn't allocate priority group");
+		return NULL;
+	}
+	pg->m = m;
+
+	r = parse_path_selector(as, pg, ti);
+	if (r)
+		goto bad;
+
+	/*
+	 * read the paths
+	 */
+	r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error);
+	if (r)
+		goto bad;
+
+	r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error);
+	if (r)
+		goto bad;
+
+	nr_params = 1 + nr_selector_args;
+	for (i = 0; i < pg->nr_pgpaths; i++) {
+		struct pgpath *pgpath;
+		struct arg_set path_args;
+
+		if (as->argc < nr_params)
+			goto bad;
+
+		path_args.argc = nr_params;
+		path_args.argv = as->argv;
+
+		pgpath = parse_path(&path_args, &pg->ps, ti);
+		if (!pgpath)
+			goto bad;
+
+		pgpath->pg = pg;
+		list_add_tail(&pgpath->list, &pg->pgpaths);
+		consume(as, nr_params);
+	}
+
+	return pg;
+
+ bad:
+	free_priority_group(pg, ti);
+	return NULL;
+}
+
+static int parse_hw_handler(struct arg_set *as, struct multipath *m,
+			    struct dm_target *ti)
+{
+	int r;
+	struct hw_handler_type *hwht;
+	unsigned hw_argc;
+
+	static struct param _params[] = {
+		{0, 1024, ESTR("invalid number of hardware handler args")},
+	};
+
+	r = read_param(_params, shift(as), &hw_argc, &ti->error);
+	if (r)
+		return -EINVAL;
+
+	if (!hw_argc)
+		return 0;
+
+	hwht = dm_get_hw_handler(shift(as));
+	if (!hwht) {
+		ti->error = ESTR("unknown hardware handler type");
+		return -EINVAL;
+	}
+
+	r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
+	if (r) {
+		dm_put_hw_handler(hwht);
+		ti->error = ESTR("hardware handler constructor failed");
+		return r;
+	}
+
+	m->hw_handler.type = hwht;
+	consume(as, hw_argc - 1);
+
+	return 0;
+}
+
+static int parse_features(struct arg_set *as, struct multipath *m,
+			  struct dm_target *ti)
+{
+	int r;
+	unsigned argc;
+
+	static struct param _params[] = {
+		{0, 1, ESTR("invalid number of feature args")},
+	};
+
+	r = read_param(_params, shift(as), &argc, &ti->error);
+	if (r)
+		return -EINVAL;
+
+	if (!argc)
+		return 0;
+
+	if (!strnicmp(shift(as), MESG_STR("queue_if_no_path")))
+		return queue_if_no_path(m, 1);
+	else {
+		ti->error = "Unrecognised multipath feature request";
+		return -EINVAL;
+	}
+}
+
+static int multipath_ctr(struct dm_target *ti, unsigned int argc,
+			 char **argv)
+{
+	/* target parameters */
+	static struct param _params[] = {
+		{1, 1024, ESTR("invalid number of priority groups")},
+		{1, 1024, ESTR("invalid initial priority group number")},
+	};
+
+	int r;
+	struct multipath *m;
+	struct arg_set as;
+	unsigned pg_count = 0;
+	unsigned next_pg_num;
+
+	as.argc = argc;
+	as.argv = argv;
+
+	m = alloc_multipath();
+	if (!m) {
+		ti->error = ESTR("can't allocate multipath");
+		return -EINVAL;
+	}
+
+	r = parse_features(&as, m, ti);
+	if (r)
+		goto bad;
+
+	r = parse_hw_handler(&as, m, ti);
+	if (r)
+		goto bad;
+
+	r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error);
+	if (r)
+		goto bad;
+
+	r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error);
+	if (r)
+		goto bad;
+
+	/* parse the priority groups */
+	while (as.argc) {
+		struct priority_group *pg;
+
+		pg = parse_priority_group(&as, m, ti);
+		if (!pg) {
+			r = -EINVAL;
+			goto bad;
+		}
+
+		m->nr_valid_paths += pg->nr_pgpaths;
+		list_add_tail(&pg->list, &m->priority_groups);
+		pg_count++;
+		pg->pg_num = pg_count;
+		if (!--next_pg_num)
+			m->next_pg = pg;
+	}
+
+	if (pg_count != m->nr_priority_groups) {
+		ti->error = ESTR("priority group count mismatch");
+		r = -EINVAL;
+		goto bad;
+	}
+
+	ti->private = m;
+	m->ti = ti;
+
+	return 0;
+
+ bad:
+	free_multipath(m);
+	return r;
+}
+
+static void multipath_dtr(struct dm_target *ti)
+{
+	struct multipath *m = (struct multipath *) ti->private;
+	free_multipath(m);
+}
+
+/*
+ * Map bios, recording original fields for later in case we have to resubmit
+ */
+static int multipath_map(struct dm_target *ti, struct bio *bio,
+			 union map_info *map_context)
+{
+	int r;
+	struct mpath_io *mpio;
+	struct multipath *m = (struct multipath *) ti->private;
+
+	mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
+	dm_bio_record(&mpio->details, bio);
+
+	map_context->ptr = mpio;
+	bio->bi_rw |= (1 << BIO_RW_FAILFAST);
+	r = map_io(m, bio, mpio, 0);
+	if (r < 0)
+		mempool_free(mpio, m->mpio_pool);
+
+	return r;
+}
+
+/*
+ * Take a path out of use.
+ */
+static int fail_path(struct pgpath *pgpath)
+{
+	unsigned long flags;
+	struct multipath *m = pgpath->pg->m;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	if (!pgpath->path.is_active)
+		goto out;
+
+	DMWARN("dm-multipath: Failing path %s.", pgpath->path.dev->name);
+
+	pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
+	pgpath->path.is_active = 0;
+	pgpath->fail_count++;
+
+	m->nr_valid_paths--;
+
+	if (pgpath == m->current_pgpath)
+		m->current_pgpath = NULL;
+
+	queue_work(kmultipathd, &m->trigger_event);
+
+out:
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	return 0;
+}
+
+/*
+ * Reinstate a previously-failed path
+ */
+static int reinstate_path(struct pgpath *pgpath)
+{
+	int r = 0;
+	unsigned long flags;
+	struct multipath *m = pgpath->pg->m;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	if (pgpath->path.is_active)
+		goto out;
+
+	if (!pgpath->pg->ps.type) {
+		DMWARN("Reinstate path not supported by path selector %s",
+		       pgpath->pg->ps.type->name);
+		r = -EINVAL;
+		goto out;
+	}
+
+	r = pgpath->pg->ps.type->reinstate_path(&pgpath->pg->ps, &pgpath->path);
+	if (r)
+		goto out;
+
+	pgpath->path.is_active = 1;
+
+	m->current_pgpath = NULL;
+	if (!m->nr_valid_paths++)
+		queue_work(kmultipathd, &m->process_queued_ios);
+
+	queue_work(kmultipathd, &m->trigger_event);
+
+out:
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	return r;
+}
+
+/*
+ * Fail or reinstate all paths that match the provided struct dm_dev.
+ */
+static int action_dev(struct multipath *m, struct dm_dev *dev,
+		      action_fn action)
+{
+	int r = 0;
+	struct pgpath *pgpath;
+	struct priority_group *pg;
+
+	list_for_each_entry(pg, &m->priority_groups, list) {
+		list_for_each_entry(pgpath, &pg->pgpaths, list) {
+			if (pgpath->path.dev == dev)
+				r = action(pgpath);
+		}
+	}
+
+	return r;
+}
+
+/*
+ * Temporarily try to avoid having to use the specified PG
+ */
+static void bypass_pg(struct multipath *m, struct priority_group *pg,
+		      int bypassed)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	pg->bypassed = bypassed;
+	m->current_pgpath = NULL;
+	m->current_pg = NULL;
+
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	queue_work(kmultipathd, &m->trigger_event);
+}
+
+/*
+ * Switch to using the specified PG from the next I/O that gets mapped
+ */
+static int switch_pg_num(struct multipath *m, const char *pgstr)
+{
+	struct priority_group *pg;
+	unsigned pgnum;
+	unsigned long flags;
+
+	if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+	    (pgnum > m->nr_priority_groups)) {
+		DMWARN("invalid PG number supplied to switch_pg_num");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&m->lock, flags);
+	list_for_each_entry(pg, &m->priority_groups, list) {
+		pg->bypassed = 0;
+		if (--pgnum)
+			continue;
+
+		m->current_pgpath = NULL;
+		m->current_pg = NULL;
+		m->next_pg = pg;
+	}
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	queue_work(kmultipathd, &m->trigger_event);
+	return 0;
+}
+
+/*
+ * Set/clear bypassed status of a PG.
+ * PGs are numbered upwards from 1 in the order they were declared.
+ */
+static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
+{
+	struct priority_group *pg;
+	unsigned pgnum;
+
+	if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+	    (pgnum > m->nr_priority_groups)) {
+		DMWARN("invalid PG number supplied to bypass_pg");
+		return -EINVAL;
+	}
+
+	list_for_each_entry(pg, &m->priority_groups, list) {
+		if (!--pgnum)
+			break;
+	}
+
+	bypass_pg(m, pg, bypassed);
+	return 0;
+}
+
+/*
+ * pg_init must call this when it has completed its initialisation
+ */
+void dm_pg_init_complete(struct path *path, unsigned err_flags)
+{
+	struct pgpath *pgpath = path_to_pgpath(path);
+	struct priority_group *pg = pgpath->pg;
+	struct multipath *m = pg->m;
+	unsigned long flags;
+
+	/* We insist on failing the path if the PG is already bypassed. */
+	if (err_flags && pg->bypassed)
+		err_flags |= MP_FAIL_PATH;
+
+	if (err_flags & MP_FAIL_PATH)
+		fail_path(pgpath);
+
+	if (err_flags & MP_BYPASS_PG)
+		bypass_pg(m, pg, 1);
+
+	spin_lock_irqsave(&m->lock, flags);
+	if (!err_flags)
+		m->queue_io = 0;
+	else {
+		m->current_pgpath = NULL;
+		m->current_pg = NULL;
+	}
+	queue_work(kmultipathd, &m->process_queued_ios);
+	spin_unlock_irqrestore(&m->lock, flags);
+}
+
+/*
+ * end_io handling
+ */
+static int do_end_io(struct multipath *m, struct bio *bio,
+		     int error, struct mpath_io *mpio)
+{
+	struct hw_handler *hwh = &m->hw_handler;
+	unsigned err_flags = MP_FAIL_PATH;	/* Default behavior */
+
+	if (!error)
+		return 0;	/* I/O complete */
+
+	if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
+		return error;
+
+	spin_lock(&m->lock);
+	if (!m->nr_valid_paths) {
+		if (!m->queue_if_no_path || m->suspended) {
+			spin_unlock(&m->lock);
+			return -EIO;
+		} else {
+			spin_unlock(&m->lock);
+			goto requeue;
+		}
+	}
+	spin_unlock(&m->lock);
+
+	if (hwh->type && hwh->type->error)
+		err_flags = hwh->type->error(hwh, bio);
+
+	if (mpio->pgpath) {
+		if (err_flags & MP_FAIL_PATH)
+			fail_path(mpio->pgpath);
+
+		if (err_flags & MP_BYPASS_PG)
+			bypass_pg(m, mpio->pgpath->pg, 1);
+	}
+
+	if (err_flags & MP_ERROR_IO)
+		return -EIO;
+
+      requeue:
+	dm_bio_restore(&mpio->details, bio);
+
+	/* queue for the daemon to resubmit or fail */
+	spin_lock(&m->lock);
+	bio_list_add(&m->queued_ios, bio);
+	m->queue_size++;
+	if (!m->queue_io)
+		queue_work(kmultipathd, &m->process_queued_ios);
+	spin_unlock(&m->lock);
+
+	return 1;	/* io not complete */
+}
+
+static int multipath_end_io(struct dm_target *ti, struct bio *bio,
+			    int error, union map_info *map_context)
+{
+	struct multipath *m = (struct multipath *) ti->private;
+	struct mpath_io *mpio = (struct mpath_io *) map_context->ptr;
+	struct pgpath *pgpath = mpio->pgpath;
+	struct path_selector *ps;
+	int r;
+
+	r  = do_end_io(m, bio, error, mpio);
+	if (pgpath) {
+		ps = &pgpath->pg->ps;
+		if (ps->type->end_io)
+			ps->type->end_io(ps, &pgpath->path);
+	}
+	if (r <= 0)
+		mempool_free(mpio, m->mpio_pool);
+
+	return r;
+}
+
+/*
+ * Suspend can't complete until all the I/O is processed so if
+ * the last path failed we will now error any queued I/O.
+ */
+static void multipath_presuspend(struct dm_target *ti)
+{
+	struct multipath *m = (struct multipath *) ti->private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->lock, flags);
+	m->suspended = 1;
+	if (m->queue_if_no_path)
+		queue_work(kmultipathd, &m->process_queued_ios);
+	spin_unlock_irqrestore(&m->lock, flags);
+}
+
+static void multipath_resume(struct dm_target *ti)
+{
+	struct multipath *m = (struct multipath *) ti->private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&m->lock, flags);
+	m->suspended = 0;
+	spin_unlock_irqrestore(&m->lock, flags);
+}
+
+/*
+ * Info output has the following format:
+ * num_multipath_feature_args [multipath_feature_args]*
+ * num_handler_status_args [handler_status_args]*
+ * num_groups init_group_number
+ *            [A|D|E num_ps_status_args [ps_status_args]*
+ *             num_paths num_selector_args
+ *             [path_dev A|F fail_count [selector_args]* ]+ ]+
+ *
+ * Table output has the following format (identical to the constructor string):
+ * num_feature_args [features_args]*
+ * num_handler_args hw_handler [hw_handler_args]*
+ * num_groups init_group_number
+ *     [priority selector-name num_ps_args [ps_args]*
+ *      num_paths num_selector_args [path_dev [selector_args]* ]+ ]+
+ */
+static int multipath_status(struct dm_target *ti, status_type_t type,
+			    char *result, unsigned int maxlen)
+{
+	int sz = 0;
+	unsigned long flags;
+	struct multipath *m = (struct multipath *) ti->private;
+	struct hw_handler *hwh = &m->hw_handler;
+	struct priority_group *pg;
+	struct pgpath *p;
+	unsigned pg_num;
+	char state;
+
+	spin_lock_irqsave(&m->lock, flags);
+
+	/* Features */
+	if (type == STATUSTYPE_INFO)
+		DMEMIT("1 %u ", m->queue_size);
+	else if (m->queue_if_no_path)
+		DMEMIT("1 queue_if_no_path ");
+	else
+		DMEMIT("0 ");
+
+	if (hwh->type && hwh->type->status)
+		sz += hwh->type->status(hwh, type, result + sz, maxlen - sz);
+	else if (!hwh->type || type == STATUSTYPE_INFO)
+		DMEMIT("0 ");
+	else
+		DMEMIT("1 %s ", hwh->type->name);
+
+	DMEMIT("%u ", m->nr_priority_groups);
+
+	if (m->next_pg)
+		pg_num = m->next_pg->pg_num;
+	else if (m->current_pg)
+		pg_num = m->current_pg->pg_num;
+	else
+			pg_num = 1;
+
+	DMEMIT("%u ", pg_num);
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		list_for_each_entry(pg, &m->priority_groups, list) {
+			if (pg->bypassed)
+				state = 'D';	/* Disabled */
+			else if (pg == m->current_pg)
+				state = 'A';	/* Currently Active */
+			else
+				state = 'E';	/* Enabled */
+
+			DMEMIT("%c ", state);
+
+			if (pg->ps.type->status)
+				sz += pg->ps.type->status(&pg->ps, NULL, type,
+							  result + sz,
+							  maxlen - sz);
+			else
+				DMEMIT("0 ");
+
+			DMEMIT("%u %u ", pg->nr_pgpaths,
+			       pg->ps.type->info_args);
+
+			list_for_each_entry(p, &pg->pgpaths, list) {
+				DMEMIT("%s %s %u ", p->path.dev->name,
+				       p->path.is_active ? "A" : "F",
+				       p->fail_count);
+				if (pg->ps.type->status)
+					sz += pg->ps.type->status(&pg->ps,
+					      &p->path, type, result + sz,
+					      maxlen - sz);
+			}
+		}
+		break;
+
+	case STATUSTYPE_TABLE:
+		list_for_each_entry(pg, &m->priority_groups, list) {
+			DMEMIT("%s ", pg->ps.type->name);
+
+			if (pg->ps.type->status)
+				sz += pg->ps.type->status(&pg->ps, NULL, type,
+							  result + sz,
+							  maxlen - sz);
+			else
+				DMEMIT("0 ");
+
+			DMEMIT("%u %u ", pg->nr_pgpaths,
+			       pg->ps.type->table_args);
+
+			list_for_each_entry(p, &pg->pgpaths, list) {
+				DMEMIT("%s ", p->path.dev->name);
+				if (pg->ps.type->status)
+					sz += pg->ps.type->status(&pg->ps,
+					      &p->path, type, result + sz,
+					      maxlen - sz);
+			}
+		}
+		break;
+	}
+
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	return 0;
+}
+
+static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+	int r;
+	struct dm_dev *dev;
+	struct multipath *m = (struct multipath *) ti->private;
+	action_fn action;
+
+	if (argc == 1) {
+		if (!strnicmp(argv[0], MESG_STR("queue_if_no_path")))
+			return queue_if_no_path(m, 1);
+		else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path")))
+			return queue_if_no_path(m, 0);
+	}
+
+	if (argc != 2)
+		goto error;
+
+	if (!strnicmp(argv[0], MESG_STR("disable_group")))
+		return bypass_pg_num(m, argv[1], 1);
+	else if (!strnicmp(argv[0], MESG_STR("enable_group")))
+		return bypass_pg_num(m, argv[1], 0);
+	else if (!strnicmp(argv[0], MESG_STR("switch_group")))
+		return switch_pg_num(m, argv[1]);
+	else if (!strnicmp(argv[0], MESG_STR("reinstate_path")))
+		action = reinstate_path;
+	else if (!strnicmp(argv[0], MESG_STR("fail_path")))
+		action = fail_path;
+	else
+		goto error;
+
+	r = dm_get_device(ti, argv[1], ti->begin, ti->len,
+			  dm_table_get_mode(ti->table), &dev);
+	if (r) {
+		DMWARN("dm-multipath message: error getting device %s",
+		       argv[1]);
+		return -EINVAL;
+	}
+
+	r = action_dev(m, dev, action);
+
+	dm_put_device(ti, dev);
+
+	return r;
+
+error:
+	DMWARN("Unrecognised multipath message received.");
+	return -EINVAL;
+}
+
+/*-----------------------------------------------------------------
+ * Module setup
+ *---------------------------------------------------------------*/
+static struct target_type multipath_target = {
+	.name = "multipath",
+	.version = {1, 0, 4},
+	.module = THIS_MODULE,
+	.ctr = multipath_ctr,
+	.dtr = multipath_dtr,
+	.map = multipath_map,
+	.end_io = multipath_end_io,
+	.presuspend = multipath_presuspend,
+	.resume = multipath_resume,
+	.status = multipath_status,
+	.message = multipath_message,
+};
+
+static int __init dm_multipath_init(void)
+{
+	int r;
+
+	/* allocate a slab for the dm_ios */
+	_mpio_cache = kmem_cache_create("dm_mpath", sizeof(struct mpath_io),
+					0, 0, NULL, NULL);
+	if (!_mpio_cache)
+		return -ENOMEM;
+
+	r = dm_register_target(&multipath_target);
+	if (r < 0) {
+		DMERR("%s: register failed %d", multipath_target.name, r);
+		kmem_cache_destroy(_mpio_cache);
+		return -EINVAL;
+	}
+
+	kmultipathd = create_workqueue("kmpathd");
+	if (!kmultipathd) {
+		DMERR("%s: failed to create workqueue kmpathd",
+				multipath_target.name);
+		dm_unregister_target(&multipath_target);
+		kmem_cache_destroy(_mpio_cache);
+		return -ENOMEM;
+	}
+
+	DMINFO("dm-multipath version %u.%u.%u loaded",
+	       multipath_target.version[0], multipath_target.version[1],
+	       multipath_target.version[2]);
+
+	return r;
+}
+
+static void __exit dm_multipath_exit(void)
+{
+	int r;
+
+	destroy_workqueue(kmultipathd);
+
+	r = dm_unregister_target(&multipath_target);
+	if (r < 0)
+		DMERR("%s: target unregister failed %d",
+		      multipath_target.name, r);
+	kmem_cache_destroy(_mpio_cache);
+}
+
+EXPORT_SYMBOL_GPL(dm_pg_init_complete);
+
+module_init(dm_multipath_init);
+module_exit(dm_multipath_exit);
+
+MODULE_DESCRIPTION(DM_NAME " multipath target");
+MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-mpath.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ *
+ * Multipath.
+ */
+
+#ifndef	DM_MPATH_H
+#define	DM_MPATH_H
+
+struct dm_dev;
+
+struct path {
+	struct dm_dev *dev;	/* Read-only */
+	unsigned is_active;	/* Read-only */
+
+	void *pscontext;	/* For path-selector use */
+	void *hwhcontext;	/* For hw-handler use */
+};
+
+/* Callback for hwh_pg_init_fn to use when complete */
+void dm_pg_init_complete(struct path *path, unsigned err_flags);
+
+#endif
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-path-selector.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2003 Sistina Software.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * Module Author: Heinz Mauelshagen
+ *
+ * This file is released under the GPL.
+ *
+ * Path selector registration.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+
+struct ps_internal {
+	struct path_selector_type pst;
+
+	struct list_head list;
+	long use;
+};
+
+#define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
+
+static LIST_HEAD(_path_selectors);
+static DECLARE_RWSEM(_ps_lock);
+
+static struct ps_internal *__find_path_selector_type(const char *name)
+{
+	struct ps_internal *psi;
+
+	list_for_each_entry(psi, &_path_selectors, list) {
+		if (!strcmp(name, psi->pst.name))
+			return psi;
+	}
+
+	return NULL;
+}
+
+static struct ps_internal *get_path_selector(const char *name)
+{
+	struct ps_internal *psi;
+
+	down_read(&_ps_lock);
+	psi = __find_path_selector_type(name);
+	if (psi) {
+		if ((psi->use == 0) && !try_module_get(psi->pst.module))
+			psi = NULL;
+		else
+			psi->use++;
+	}
+	up_read(&_ps_lock);
+
+	return psi;
+}
+
+struct path_selector_type *dm_get_path_selector(const char *name)
+{
+	struct ps_internal *psi;
+
+	if (!name)
+		return NULL;
+
+	psi = get_path_selector(name);
+	if (!psi) {
+		request_module("dm-%s", name);
+		psi = get_path_selector(name);
+	}
+
+	return psi ? &psi->pst : NULL;
+}
+
+void dm_put_path_selector(struct path_selector_type *pst)
+{
+	struct ps_internal *psi;
+
+	if (!pst)
+		return;
+
+	down_read(&_ps_lock);
+	psi = __find_path_selector_type(pst->name);
+	if (!psi)
+		goto out;
+
+	if (--psi->use == 0)
+		module_put(psi->pst.module);
+
+	if (psi->use < 0)
+		BUG();
+
+out:
+	up_read(&_ps_lock);
+}
+
+static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
+{
+	struct ps_internal *psi = kmalloc(sizeof(*psi), GFP_KERNEL);
+
+	if (psi) {
+		memset(psi, 0, sizeof(*psi));
+		psi->pst = *pst;
+	}
+
+	return psi;
+}
+
+int dm_register_path_selector(struct path_selector_type *pst)
+{
+	int r = 0;
+	struct ps_internal *psi = _alloc_path_selector(pst);
+
+	if (!psi)
+		return -ENOMEM;
+
+	down_write(&_ps_lock);
+
+	if (__find_path_selector_type(pst->name)) {
+		kfree(psi);
+		r = -EEXIST;
+	} else
+		list_add(&psi->list, &_path_selectors);
+
+	up_write(&_ps_lock);
+
+	return r;
+}
+
+int dm_unregister_path_selector(struct path_selector_type *pst)
+{
+	struct ps_internal *psi;
+
+	down_write(&_ps_lock);
+
+	psi = __find_path_selector_type(pst->name);
+	if (!psi) {
+		up_write(&_ps_lock);
+		return -EINVAL;
+	}
+
+	if (psi->use) {
+		up_write(&_ps_lock);
+		return -ETXTBSY;
+	}
+
+	list_del(&psi->list);
+
+	up_write(&_ps_lock);
+
+	kfree(psi);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(dm_register_path_selector);
+EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
diff --git a/drivers/md/dm-path-selector.h b/drivers/md/dm-path-selector.h
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-path-selector.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2003 Sistina Software.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * Module Author: Heinz Mauelshagen
+ *
+ * This file is released under the GPL.
+ *
+ * Path-Selector registration.
+ */
+
+#ifndef	DM_PATH_SELECTOR_H
+#define	DM_PATH_SELECTOR_H
+
+#include <linux/device-mapper.h>
+
+#include "dm-mpath.h"
+
+/*
+ * We provide an abstraction for the code that chooses which path
+ * to send some io down.
+ */
+struct path_selector_type;
+struct path_selector {
+	struct path_selector_type *type;
+	void *context;
+};
+
+/* Information about a path selector type */
+struct path_selector_type {
+	char *name;
+	struct module *module;
+
+	unsigned int table_args;
+	unsigned int info_args;
+
+	/*
+	 * Constructs a path selector object, takes custom arguments
+	 */
+	int (*create) (struct path_selector *ps, unsigned argc, char **argv);
+	void (*destroy) (struct path_selector *ps);
+
+	/*
+	 * Add an opaque path object, along with some selector specific
+	 * path args (eg, path priority).
+	 */
+	int (*add_path) (struct path_selector *ps, struct path *path,
+			 int argc, char **argv, char **error);
+
+	/*
+	 * Chooses a path for this io, if no paths are available then
+	 * NULL will be returned.
+	 *
+	 * repeat_count is the number of times to use the path before
+	 * calling the function again.  0 means don't call it again unless
+	 * the path fails.
+	 */
+	struct path *(*select_path) (struct path_selector *ps,
+				     unsigned *repeat_count);
+
+	/*
+	 * Notify the selector that a path has failed.
+	 */
+	void (*fail_path) (struct path_selector *ps, struct path *p);
+
+	/*
+	 * Ask selector to reinstate a path.
+	 */
+	int (*reinstate_path) (struct path_selector *ps, struct path *p);
+
+	/*
+	 * Table content based on parameters added in ps_add_path_fn
+	 * or path selector status
+	 */
+	int (*status) (struct path_selector *ps, struct path *path,
+		       status_type_t type, char *result, unsigned int maxlen);
+
+	int (*end_io) (struct path_selector *ps, struct path *path);
+};
+
+/* Register a path selector */
+int dm_register_path_selector(struct path_selector_type *type);
+
+/* Unregister a path selector */
+int dm_unregister_path_selector(struct path_selector_type *type);
+
+/* Returns a registered path selector type */
+struct path_selector_type *dm_get_path_selector(const char *name);
+
+/* Releases a path selector  */
+void dm_put_path_selector(struct path_selector_type *pst);
+
+#endif
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -122,7 +122,7 @@ static inline sector_t region_to_sector(
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
-static void *region_alloc(int gfp_mask, void *pool_data)
+static void *region_alloc(unsigned int __nocast gfp_mask, void *pool_data)
 {
 	return kmalloc(sizeof(struct region), gfp_mask);
 }
@@ -1182,7 +1182,6 @@ static void mirror_resume(struct dm_targ
 static int mirror_status(struct dm_target *ti, status_type_t type,
 			 char *result, unsigned int maxlen)
 {
-	char buffer[32];
 	unsigned int m, sz;
 	struct mirror_set *ms = (struct mirror_set *) ti->private;
 
@@ -1191,10 +1190,8 @@ static int mirror_status(struct dm_targe
 	switch (type) {
 	case STATUSTYPE_INFO:
 		DMEMIT("%d ", ms->nr_mirrors);
-		for (m = 0; m < ms->nr_mirrors; m++) {
-			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
-			DMEMIT("%s ", buffer);
-		}
+		for (m = 0; m < ms->nr_mirrors; m++)
+			DMEMIT("%s ", ms->mirror[m].dev->name);
 
 		DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT,
 		       ms->rh.log->type->get_sync_count(ms->rh.log),
@@ -1203,11 +1200,9 @@ static int mirror_status(struct dm_targe
 
 	case STATUSTYPE_TABLE:
 		DMEMIT("%d ", ms->nr_mirrors);
-		for (m = 0; m < ms->nr_mirrors; m++) {
-			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
+		for (m = 0; m < ms->nr_mirrors; m++)
 			DMEMIT("%s " SECTOR_FORMAT " ",
-			       buffer, ms->mirror[m].offset);
-		}
+			       ms->mirror[m].dev->name, ms->mirror[m].offset);
 	}
 
 	return 0;
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
new file mode 100644
--- /dev/null
+++ b/drivers/md/dm-round-robin.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2003 Sistina Software.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * Module Author: Heinz Mauelshagen
+ *
+ * This file is released under the GPL.
+ *
+ * Round-robin path selector.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+
+/*-----------------------------------------------------------------
+ * Path-handling code, paths are held in lists
+ *---------------------------------------------------------------*/
+struct path_info {
+	struct list_head list;
+	struct path *path;
+	unsigned repeat_count;
+};
+
+static void free_paths(struct list_head *paths)
+{
+	struct path_info *pi, *next;
+
+	list_for_each_entry_safe(pi, next, paths, list) {
+		list_del(&pi->list);
+		kfree(pi);
+	}
+}
+
+/*-----------------------------------------------------------------
+ * Round-robin selector
+ *---------------------------------------------------------------*/
+
+#define RR_MIN_IO		1000
+
+struct selector {
+	struct list_head valid_paths;
+	struct list_head invalid_paths;
+};
+
+static struct selector *alloc_selector(void)
+{
+	struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (s) {
+		INIT_LIST_HEAD(&s->valid_paths);
+		INIT_LIST_HEAD(&s->invalid_paths);
+	}
+
+	return s;
+}
+
+static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
+{
+	struct selector *s;
+
+	s = alloc_selector();
+	if (!s)
+		return -ENOMEM;
+
+	ps->context = s;
+	return 0;
+}
+
+static void rr_destroy(struct path_selector *ps)
+{
+	struct selector *s = (struct selector *) ps->context;
+
+	free_paths(&s->valid_paths);
+	free_paths(&s->invalid_paths);
+	kfree(s);
+	ps->context = NULL;
+}
+
+static int rr_status(struct path_selector *ps, struct path *path,
+		     status_type_t type, char *result, unsigned int maxlen)
+{
+	struct path_info *pi;
+	int sz = 0;
+
+	if (!path)
+		DMEMIT("0 ");
+	else {
+		switch(type) {
+		case STATUSTYPE_INFO:
+			break;
+		case STATUSTYPE_TABLE:
+			pi = path->pscontext;
+			DMEMIT("%u ", pi->repeat_count);
+			break;
+		}
+	}
+
+	return sz;
+}
+
+/*
+ * Called during initialisation to register each path with an
+ * optional repeat_count.
+ */
+static int rr_add_path(struct path_selector *ps, struct path *path,
+		       int argc, char **argv, char **error)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi;
+	unsigned repeat_count = RR_MIN_IO;
+
+	if (argc > 1) {
+		*error = "round-robin ps: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+	/* First path argument is number of I/Os before switching path */
+	if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+		*error = "round-robin ps: invalid repeat count";
+		return -EINVAL;
+	}
+
+	/* allocate the path */
+	pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+	if (!pi) {
+		*error = "round-robin ps: Error allocating path context";
+		return -ENOMEM;
+	}
+
+	pi->path = path;
+	pi->repeat_count = repeat_count;
+
+	path->pscontext = pi;
+
+	list_add(&pi->list, &s->valid_paths);
+
+	return 0;
+}
+
+static void rr_fail_path(struct path_selector *ps, struct path *p)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = p->pscontext;
+
+	list_move(&pi->list, &s->invalid_paths);
+}
+
+static int rr_reinstate_path(struct path_selector *ps, struct path *p)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = p->pscontext;
+
+	list_move(&pi->list, &s->valid_paths);
+
+	return 0;
+}
+
+static struct path *rr_select_path(struct path_selector *ps,
+				   unsigned *repeat_count)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = NULL;
+
+	if (!list_empty(&s->valid_paths)) {
+		pi = list_entry(s->valid_paths.next, struct path_info, list);
+		list_move_tail(&pi->list, &s->valid_paths);
+		*repeat_count = pi->repeat_count;
+	}
+
+	return pi ? pi->path : NULL;
+}
+
+static struct path_selector_type rr_ps = {
+	.name = "round-robin",
+	.module = THIS_MODULE,
+	.table_args = 1,
+	.info_args = 0,
+	.create = rr_create,
+	.destroy = rr_destroy,
+	.status = rr_status,
+	.add_path = rr_add_path,
+	.fail_path = rr_fail_path,
+	.reinstate_path = rr_reinstate_path,
+	.select_path = rr_select_path,
+};
+
+static int __init dm_rr_init(void)
+{
+	int r = dm_register_path_selector(&rr_ps);
+
+	if (r < 0)
+		DMERR("round-robin: register failed %d", r);
+
+	DMINFO("dm-round-robin version 1.0.0 loaded");
+
+	return r;
+}
+
+static void __exit dm_rr_exit(void)
+{
+	int r = dm_unregister_path_selector(&rr_ps);
+
+	if (r < 0)
+		DMERR("round-robin: unregister failed %d", r);
+}
+
+module_init(dm_rr_init);
+module_exit(dm_rr_exit);
+
+MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
+MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -864,8 +864,6 @@ static int snapshot_status(struct dm_tar
 			   char *result, unsigned int maxlen)
 {
 	struct dm_snapshot *snap = (struct dm_snapshot *) ti->private;
-	char cow[32];
-	char org[32];
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -892,9 +890,8 @@ static int snapshot_status(struct dm_tar
 		 * to make private copies if the output is to
 		 * make sense.
 		 */
-		format_dev_t(cow, snap->cow->bdev->bd_dev);
-		format_dev_t(org, snap->origin->bdev->bd_dev);
-		snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT, org, cow,
+		snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT,
+			 snap->origin->name, snap->cow->name,
 			 snap->type, snap->chunk_size);
 		break;
 	}
@@ -1082,7 +1079,6 @@ static int origin_status(struct dm_targe
 			 unsigned int maxlen)
 {
 	struct dm_dev *dev = (struct dm_dev *) ti->private;
-	char buffer[32];
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -1090,8 +1086,7 @@ static int origin_status(struct dm_targe
 		break;
 
 	case STATUSTYPE_TABLE:
-		format_dev_t(buffer, dev->bdev->bd_dev);
-		snprintf(result, maxlen, "%s", buffer);
+		snprintf(result, maxlen, "%s", dev->name);
 		break;
 	}
 
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -188,7 +188,6 @@ static int stripe_status(struct dm_targe
 	struct stripe_c *sc = (struct stripe_c *) ti->private;
 	unsigned int sz = 0;
 	unsigned int i;
-	char buffer[32];
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -197,11 +196,9 @@ static int stripe_status(struct dm_targe
 
 	case STATUSTYPE_TABLE:
 		DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1);
-		for (i = 0; i < sc->stripes; i++) {
-			format_dev_t(buffer, sc->stripe[i].dev->bdev->bd_dev);
-			DMEMIT(" %s " SECTOR_FORMAT, buffer,
+		for (i = 0; i < sc->stripes; i++)
+			DMEMIT(" %s " SECTOR_FORMAT, sc->stripe[i].dev->name,
 			       sc->stripe[i].physical_start);
-		}
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -242,7 +242,7 @@ static void free_devices(struct list_hea
 	}
 }
 
-void table_destroy(struct dm_table *t)
+static void table_destroy(struct dm_table *t)
 {
 	unsigned int i;
 
@@ -455,6 +455,8 @@ static int __table_get_device(struct dm_
 			return r;
 		}
 
+		format_dev_t(dd->name, dev);
+
 		atomic_set(&dd->count, 0);
 		list_add(&dd->list, &t->devices);
 
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -24,23 +24,6 @@ static int zero_ctr(struct dm_target *ti
 }
 
 /*
- * Fills the bio pages with zeros
- */
-static void zero_fill_bio(struct bio *bio)
-{
-	unsigned long flags;
-	struct bio_vec *bv;
-	int i;
-
-	bio_for_each_segment(bv, bio, i) {
-		char *data = bvec_kmap_irq(bv, &flags);
-		memset(data, 0, bv->bv_len);
-		flush_dcache_page(bv->bv_page);
-		bvec_kunmap_irq(data, &flags);
-	}
-}
-
-/*
  * Return zeros only on reads
  */
 static int zero_map(struct dm_target *ti, struct bio *bio,
@@ -72,7 +55,7 @@ static struct target_type zero_target = 
 	.map    = zero_map,
 };
 
-int __init dm_zero_init(void)
+static int __init dm_zero_init(void)
 {
 	int r = dm_register_target(&zero_target);
 
@@ -82,7 +65,7 @@ int __init dm_zero_init(void)
 	return r;
 }
 
-void __exit dm_zero_exit(void)
+static void __exit dm_zero_exit(void)
 {
 	int r = dm_unregister_target(&zero_target);
 
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -43,6 +43,13 @@ struct target_io {
 	union map_info info;
 };
 
+union map_info *dm_get_mapinfo(struct bio *bio)
+{
+        if (bio && bio->bi_private)
+                return &((struct target_io *)bio->bi_private)->info;
+        return NULL;
+}
+
 /*
  * Bits for the md->flags field.
  */
@@ -90,16 +97,23 @@ struct mapped_device {
 	 * freeze/thaw support require holding onto a super block
 	 */
 	struct super_block *frozen_sb;
+	struct block_device *frozen_bdev;
 };
 
 #define MIN_IOS 256
 static kmem_cache_t *_io_cache;
 static kmem_cache_t *_tio_cache;
 
+static struct bio_set *dm_set;
+
 static int __init local_init(void)
 {
 	int r;
 
+	dm_set = bioset_create(16, 16, 4);
+	if (!dm_set)
+		return -ENOMEM;
+
 	/* allocate a slab for the dm_ios */
 	_io_cache = kmem_cache_create("dm_io",
 				      sizeof(struct dm_io), 0, 0, NULL, NULL);
@@ -133,6 +147,8 @@ static void local_exit(void)
 	kmem_cache_destroy(_tio_cache);
 	kmem_cache_destroy(_io_cache);
 
+	bioset_free(dm_set);
+
 	if (unregister_blkdev(_major, _name) < 0)
 		DMERR("devfs_unregister_blkdev failed");
 
@@ -393,7 +409,7 @@ static struct bio *split_bvec(struct bio
 	struct bio *clone;
 	struct bio_vec *bv = bio->bi_io_vec + idx;
 
-	clone = bio_alloc(GFP_NOIO, 1);
+	clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
 	*clone->bi_io_vec = *bv;
 
 	clone->bi_sector = sector;
@@ -975,44 +991,50 @@ int dm_swap_table(struct mapped_device *
  */
 static int __lock_fs(struct mapped_device *md)
 {
-	struct block_device *bdev;
+	int error = -ENOMEM;
 
 	if (test_and_set_bit(DMF_FS_LOCKED, &md->flags))
 		return 0;
 
-	bdev = bdget_disk(md->disk, 0);
-	if (!bdev) {
+	md->frozen_bdev = bdget_disk(md->disk, 0);
+	if (!md->frozen_bdev) {
 		DMWARN("bdget failed in __lock_fs");
-		return -ENOMEM;
+		goto out;
 	}
 
 	WARN_ON(md->frozen_sb);
-	md->frozen_sb = freeze_bdev(bdev);
+
+	md->frozen_sb = freeze_bdev(md->frozen_bdev);
+	if (IS_ERR(md->frozen_sb)) {
+		error = PTR_ERR(md->frozen_sb);
+		goto out_bdput;
+	}
+
 	/* don't bdput right now, we don't want the bdev
 	 * to go away while it is locked.  We'll bdput
 	 * in __unlock_fs
 	 */
 	return 0;
+
+out_bdput:
+	bdput(md->frozen_bdev);
+	md->frozen_sb = NULL;
+	md->frozen_bdev = NULL;
+out:
+	clear_bit(DMF_FS_LOCKED, &md->flags);
+	return error;
 }
 
-static int __unlock_fs(struct mapped_device *md)
+static void __unlock_fs(struct mapped_device *md)
 {
-	struct block_device *bdev;
-
 	if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags))
-		return 0;
+		return;
 
-	bdev = bdget_disk(md->disk, 0);
-	if (!bdev) {
-		DMWARN("bdget failed in __unlock_fs");
-		return -ENOMEM;
-	}
+	thaw_bdev(md->frozen_bdev, md->frozen_sb);
+	bdput(md->frozen_bdev);
 
-	thaw_bdev(bdev, md->frozen_sb);
 	md->frozen_sb = NULL;
-	bdput(bdev);
-	bdput(bdev);
-	return 0;
+	md->frozen_bdev = NULL;
 }
 
 /*
@@ -1026,37 +1048,37 @@ int dm_suspend(struct mapped_device *md)
 {
 	struct dm_table *map;
 	DECLARE_WAITQUEUE(wait, current);
+	int error = -EINVAL;
 
 	/* Flush I/O to the device. */
 	down_read(&md->lock);
-	if (test_bit(DMF_BLOCK_IO, &md->flags)) {
-		up_read(&md->lock);
-		return -EINVAL;
-	}
+	if (test_bit(DMF_BLOCK_IO, &md->flags))
+		goto out_read_unlock;
+
+	error = __lock_fs(md);
+	if (error)
+		goto out_read_unlock;
 
 	map = dm_get_table(md);
 	if (map)
 		dm_table_presuspend_targets(map);
-	__lock_fs(md);
 
 	up_read(&md->lock);
 
 	/*
-	 * First we set the BLOCK_IO flag so no more ios will be
-	 * mapped.
+	 * First we set the BLOCK_IO flag so no more ios will be mapped.
+	 *
+	 * If the flag is already set we know another thread is trying to
+	 * suspend as well, so we leave the fs locked for this thread.
 	 */
+	error = -EINVAL;
 	down_write(&md->lock);
-	if (test_bit(DMF_BLOCK_IO, &md->flags)) {
-		/*
-		 * If we get here we know another thread is
-		 * trying to suspend as well, so we leave the fs
-		 * locked for this thread.
-		 */
-		up_write(&md->lock);
-		return -EINVAL;
+	if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) {
+		if (map)
+			dm_table_put(map);
+		goto out_write_unlock;
 	}
 
-	set_bit(DMF_BLOCK_IO, &md->flags);
 	add_wait_queue(&md->wait, &wait);
 	up_write(&md->lock);
 
@@ -1084,12 +1106,9 @@ int dm_suspend(struct mapped_device *md)
 	remove_wait_queue(&md->wait, &wait);
 
 	/* were we interrupted ? */
-	if (atomic_read(&md->pending)) {
-		__unlock_fs(md);
-		clear_bit(DMF_BLOCK_IO, &md->flags);
-		up_write(&md->lock);
-		return -EINTR;
-	}
+	error = -EINTR;
+	if (atomic_read(&md->pending))
+		goto out_unfreeze;
 
 	set_bit(DMF_SUSPENDED, &md->flags);
 
@@ -1100,6 +1119,18 @@ int dm_suspend(struct mapped_device *md)
 	up_write(&md->lock);
 
 	return 0;
+
+out_unfreeze:
+	/* FIXME Undo dm_table_presuspend_targets */
+	__unlock_fs(md);
+	clear_bit(DMF_BLOCK_IO, &md->flags);
+out_write_unlock:
+	up_write(&md->lock);
+	return error;
+
+out_read_unlock:
+	up_read(&md->lock);
+	return error;
 }
 
 int dm_resume(struct mapped_device *md)
@@ -1164,6 +1195,8 @@ static struct block_device_operations dm
 	.owner = THIS_MODULE
 };
 
+EXPORT_SYMBOL(dm_get_mapinfo);
+
 /*
  * module hooks
  */
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -44,6 +44,7 @@ struct dm_dev {
 	atomic_t count;
 	int mode;
 	struct block_device *bdev;
+	char name[16];
 };
 
 struct dm_table;
@@ -189,5 +190,6 @@ int dm_stripe_init(void);
 void dm_stripe_exit(void);
 
 void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
+union map_info *dm_get_mapinfo(struct bio *bio);
 
 #endif
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -269,9 +269,8 @@ static int linear_make_request (request_
 		 * split it.
 		 */
 		struct bio_pair *bp;
-		bp = bio_split(bio, bio_split_pool, 
-			       (bio->bi_sector + (bio->bi_size >> 9) -
-				(tmp_dev->offset + tmp_dev->size))<<1);
+		bp = bio_split(bio, bio_split_pool,
+			       ((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector);
 		if (linear_make_request(q, &bp->bio1))
 			generic_make_request(&bp->bio1);
 		if (linear_make_request(q, &bp->bio2))
diff --git a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -332,7 +332,7 @@ static int bi_complete(struct bio *bio, 
 static int sync_page_io(struct block_device *bdev, sector_t sector, int size,
 		   struct page *page, int rw)
 {
-	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	struct bio *bio = bio_alloc(GFP_NOIO, 1);
 	struct completion event;
 	int ret;
 
@@ -527,7 +527,7 @@ static int super_90_load(mdk_rdev_t *rde
 	rdev->preferred_minor = sb->md_minor;
 	rdev->data_offset = 0;
 
-	if (sb->level == MULTIPATH)
+	if (sb->level == LEVEL_MULTIPATH)
 		rdev->desc_nr = -1;
 	else
 		rdev->desc_nr = sb->this_disk.number;
@@ -940,7 +940,7 @@ static void super_1_sync(mddev_t *mddev,
 	
 	sb->max_dev = cpu_to_le32(max_dev);
 	for (i=0; i<max_dev;i++)
-		sb->dev_roles[max_dev] = cpu_to_le16(0xfffe);
+		sb->dev_roles[i] = cpu_to_le16(0xfffe);
 	
 	ITERATE_RDEV(mddev,rdev2,tmp) {
 		i = rdev2->desc_nr;
@@ -957,7 +957,7 @@ static void super_1_sync(mddev_t *mddev,
 }
 
 
-struct super_type super_types[] = {
+static struct super_type super_types[] = {
 	[0] = {
 		.name	= "0.90.0",
 		.owner	= THIS_MODULE,
@@ -1387,7 +1387,7 @@ abort_free:
  */
 
 
-static int analyze_sbs(mddev_t * mddev)
+static void analyze_sbs(mddev_t * mddev)
 {
 	int i;
 	struct list_head *tmp;
@@ -1435,14 +1435,12 @@ static int analyze_sbs(mddev_t * mddev)
 
 
 
-	if ((mddev->recovery_cp != MaxSector) &&
-	    ((mddev->level == 1) ||
-	     ((mddev->level >= 4) && (mddev->level <= 6))))
+	if (mddev->recovery_cp != MaxSector &&
+	    mddev->level >= 1)
 		printk(KERN_ERR "md: %s: raid array is not clean"
 		       " -- starting background reconstruction\n",
 		       mdname(mddev));
 
-	return 0;
 }
 
 int mdp_major = 0;
@@ -1509,10 +1507,9 @@ static int do_md_run(mddev_t * mddev)
 	struct gendisk *disk;
 	char b[BDEVNAME_SIZE];
 
-	if (list_empty(&mddev->disks)) {
-		MD_BUG();
+	if (list_empty(&mddev->disks))
+		/* cannot run an array with no devices.. */
 		return -EINVAL;
-	}
 
 	if (mddev->pers)
 		return -EBUSY;
@@ -1520,10 +1517,8 @@ static int do_md_run(mddev_t * mddev)
 	/*
 	 * Analyze all RAID superblock(s)
 	 */
-	if (!mddev->raid_disks && analyze_sbs(mddev)) {
-		MD_BUG();
-		return -EINVAL;
-	}
+	if (!mddev->raid_disks)
+		analyze_sbs(mddev);
 
 	chunk_size = mddev->chunk_size;
 	pnum = level_to_pers(mddev->level);
@@ -1549,7 +1544,7 @@ static int do_md_run(mddev_t * mddev)
 		 * chunk-size has to be a power of 2 and multiples of PAGE_SIZE
 		 */
 		if ( (1 << ffz(~chunk_size)) != chunk_size) {
-			MD_BUG();
+			printk(KERN_ERR "chunk_size of %d not valid\n", chunk_size);
 			return -EINVAL;
 		}
 		if (chunk_size < PAGE_SIZE) {
@@ -1574,11 +1569,6 @@ static int do_md_run(mddev_t * mddev)
 		}
 	}
 
-	if (pnum >= MAX_PERSONALITY) {
-		MD_BUG();
-		return -EINVAL;
-	}
-
 #ifdef CONFIG_KMOD
 	if (!pers[pnum])
 	{
@@ -1763,10 +1753,8 @@ static void autorun_array(mddev_t *mddev
 	struct list_head *tmp;
 	int err;
 
-	if (list_empty(&mddev->disks)) {
-		MD_BUG();
+	if (list_empty(&mddev->disks))
 		return;
-	}
 
 	printk(KERN_INFO "md: running: ");
 
@@ -2752,7 +2740,7 @@ static struct block_device_operations md
 	.revalidate_disk= md_revalidate,
 };
 
-int md_thread(void * arg)
+static int md_thread(void * arg)
 {
 	mdk_thread_t *thread = arg;
 
@@ -2841,16 +2829,6 @@ mdk_thread_t *md_register_thread(void (*
 	return thread;
 }
 
-static void md_interrupt_thread(mdk_thread_t *thread)
-{
-	if (!thread->tsk) {
-		MD_BUG();
-		return;
-	}
-	dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid);
-	send_sig(SIGKILL, thread->tsk, 1);
-}
-
 void md_unregister_thread(mdk_thread_t *thread)
 {
 	struct completion event;
@@ -2858,9 +2836,15 @@ void md_unregister_thread(mdk_thread_t *
 	init_completion(&event);
 
 	thread->event = &event;
+
+	/* As soon as ->run is set to NULL, the task could disappear,
+	 * so we need to hold tasklist_lock until we have sent the signal
+	 */
+	dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid);
+	read_lock(&tasklist_lock);
 	thread->run = NULL;
-	thread->name = NULL;
-	md_interrupt_thread(thread);
+	send_sig(SIGKILL, thread->tsk, 1);
+	read_unlock(&tasklist_lock);
 	wait_for_completion(&event);
 	kfree(thread);
 }
@@ -3133,7 +3117,6 @@ int register_md_personality(int pnum, md
 	spin_lock(&pers_lock);
 	if (pers[pnum]) {
 		spin_unlock(&pers_lock);
-		MD_BUG();
 		return -EBUSY;
 	}
 
@@ -3145,10 +3128,8 @@ int register_md_personality(int pnum, md
 
 int unregister_md_personality(int pnum)
 {
-	if (pnum >= MAX_PERSONALITY) {
-		MD_BUG();
+	if (pnum >= MAX_PERSONALITY)
 		return -EINVAL;
-	}
 
 	printk(KERN_INFO "md: %s personality unregistered\n", pers[pnum]->name);
 	spin_lock(&pers_lock);
@@ -3251,7 +3232,7 @@ void md_handle_safemode(mddev_t *mddev)
 }
 
 
-DECLARE_WAIT_QUEUE_HEAD(resync_wait);
+static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
 
 #define SYNC_MARKS	10
 #define	SYNC_MARK_STEP	(3*HZ)
@@ -3545,18 +3526,18 @@ void md_check_recovery(mddev_t *mddev)
 
 		/* no recovery is running.
 		 * remove any failed drives, then
-		 * add spares if possible
+		 * add spares if possible.
+		 * Spare are also removed and re-added, to allow
+		 * the personality to fail the re-add.
 		 */
-		ITERATE_RDEV(mddev,rdev,rtmp) {
+		ITERATE_RDEV(mddev,rdev,rtmp)
 			if (rdev->raid_disk >= 0 &&
-			    rdev->faulty &&
+			    (rdev->faulty || ! rdev->in_sync) &&
 			    atomic_read(&rdev->nr_pending)==0) {
 				if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0)
 					rdev->raid_disk = -1;
 			}
-			if (!rdev->faulty && rdev->raid_disk >= 0 && !rdev->in_sync)
-				spares++;
-		}
+
 		if (mddev->degraded) {
 			ITERATE_RDEV(mddev,rdev,rtmp)
 				if (rdev->raid_disk < 0
@@ -3594,8 +3575,8 @@ void md_check_recovery(mddev_t *mddev)
 	}
 }
 
-int md_notify_reboot(struct notifier_block *this,
-					unsigned long code, void *x)
+static int md_notify_reboot(struct notifier_block *this,
+			    unsigned long code, void *x)
 {
 	struct list_head *tmp;
 	mddev_t *mddev;
@@ -3618,7 +3599,7 @@ int md_notify_reboot(struct notifier_blo
 	return NOTIFY_DONE;
 }
 
-struct notifier_block md_notifier = {
+static struct notifier_block md_notifier = {
 	.notifier_call	= md_notify_reboot,
 	.next		= NULL,
 	.priority	= INT_MAX, /* before any real devices */
@@ -3635,7 +3616,7 @@ static void md_geninit(void)
 		p->proc_fops = &md_seq_fops;
 }
 
-int __init md_init(void)
+static int __init md_init(void)
 {
 	int minor;
 
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -38,7 +38,7 @@
 static mdk_personality_t multipath_personality;
 
 
-static void *mp_pool_alloc(int gfp_flags, void *data)
+static void *mp_pool_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	struct multipath_bh *mpb;
 	mpb = kmalloc(sizeof(*mpb), gfp_flags);
@@ -103,7 +103,8 @@ static void multipath_end_bh_io (struct 
 	mempool_free(mp_bh, conf->pool);
 }
 
-int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error)
+static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
+				 int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
@@ -355,7 +356,7 @@ static int multipath_remove_disk(mddev_t
 			goto abort;
 		}
 		p->rdev = NULL;
-		synchronize_kernel();
+		synchronize_rcu();
 		if (atomic_read(&rdev->nr_pending)) {
 			/* lost the race, try later */
 			err = -EBUSY;
@@ -461,10 +462,6 @@ static int multipath_run (mddev_t *mddev
 	}
 	memset(conf->multipaths, 0, sizeof(struct multipath_info)*mddev->raid_disks);
 
-	mddev->queue->unplug_fn = multipath_unplug;
-
-	mddev->queue->issue_flush_fn = multipath_issue_flush;
-
 	conf->working_disks = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		disk_idx = rdev->raid_disk;
@@ -527,6 +524,10 @@ static int multipath_run (mddev_t *mddev
 	 * Ok, everything is just fine now
 	 */
 	mddev->array_size = mddev->size;
+
+	mddev->queue->unplug_fn = multipath_unplug;
+	mddev->queue->issue_flush_fn = multipath_issue_flush;
+
 	return 0;
 
 out_free_conf:
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -34,7 +34,7 @@ static mdk_personality_t raid1_personali
 static void unplug_slaves(mddev_t *mddev);
 
 
-static void * r1bio_pool_alloc(int gfp_flags, void *data)
+static void * r1bio_pool_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	struct pool_info *pi = data;
 	r1bio_t *r1_bio;
@@ -61,7 +61,7 @@ static void r1bio_pool_free(void *r1_bio
 #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
 #define RESYNC_WINDOW (2048*1024)
 
-static void * r1buf_pool_alloc(int gfp_flags, void *data)
+static void * r1buf_pool_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	struct pool_info *pi = data;
 	struct page *page;
@@ -338,6 +338,7 @@ static int read_balance(conf_t *conf, r1
 	int new_disk = conf->last_used, disk = new_disk;
 	const int sectors = r1_bio->sectors;
 	sector_t new_distance, current_distance;
+	mdk_rdev_t *new_rdev, *rdev;
 
 	rcu_read_lock();
 	/*
@@ -345,13 +346,14 @@ static int read_balance(conf_t *conf, r1
 	 * device if no resync is going on, or below the resync window.
 	 * We take the first readable disk when above the resync window.
 	 */
+ retry:
 	if (conf->mddev->recovery_cp < MaxSector &&
 	    (this_sector + sectors >= conf->next_resync)) {
 		/* Choose the first operation device, for consistancy */
 		new_disk = 0;
 
-		while (!conf->mirrors[new_disk].rdev ||
-		       !conf->mirrors[new_disk].rdev->in_sync) {
+		while ((new_rdev=conf->mirrors[new_disk].rdev) == NULL ||
+		       !new_rdev->in_sync) {
 			new_disk++;
 			if (new_disk == conf->raid_disks) {
 				new_disk = -1;
@@ -363,8 +365,8 @@ static int read_balance(conf_t *conf, r1
 
 
 	/* make sure the disk is operational */
-	while (!conf->mirrors[new_disk].rdev ||
-	       !conf->mirrors[new_disk].rdev->in_sync) {
+	while ((new_rdev=conf->mirrors[new_disk].rdev) == NULL ||
+	       !new_rdev->in_sync) {
 		if (new_disk <= 0)
 			new_disk = conf->raid_disks;
 		new_disk--;
@@ -393,18 +395,20 @@ static int read_balance(conf_t *conf, r1
 			disk = conf->raid_disks;
 		disk--;
 
-		if (!conf->mirrors[disk].rdev ||
-		    !conf->mirrors[disk].rdev->in_sync)
+		if ((rdev=conf->mirrors[disk].rdev) == NULL ||
+		    !rdev->in_sync)
 			continue;
 
-		if (!atomic_read(&conf->mirrors[disk].rdev->nr_pending)) {
+		if (!atomic_read(&rdev->nr_pending)) {
 			new_disk = disk;
+			new_rdev = rdev;
 			break;
 		}
 		new_distance = abs(this_sector - conf->mirrors[disk].head_position);
 		if (new_distance < current_distance) {
 			current_distance = new_distance;
 			new_disk = disk;
+			new_rdev = rdev;
 		}
 	} while (disk != conf->last_used);
 
@@ -414,7 +418,14 @@ rb_out:
 	if (new_disk >= 0) {
 		conf->next_seq_sect = this_sector + sectors;
 		conf->last_used = new_disk;
-		atomic_inc(&conf->mirrors[new_disk].rdev->nr_pending);
+		atomic_inc(&new_rdev->nr_pending);
+		if (!new_rdev->in_sync) {
+			/* cannot risk returning a device that failed
+			 * before we inc'ed nr_pending
+			 */
+			atomic_dec(&new_rdev->nr_pending);
+			goto retry;
+		}
 	}
 	rcu_read_unlock();
 
@@ -512,6 +523,7 @@ static int make_request(request_queue_t 
 	r1bio_t *r1_bio;
 	struct bio *read_bio;
 	int i, disks;
+	mdk_rdev_t *rdev;
 
 	/*
 	 * Register the new request and wait if the reconstruction
@@ -585,10 +597,14 @@ static int make_request(request_queue_t 
 	disks = conf->raid_disks;
 	rcu_read_lock();
 	for (i = 0;  i < disks; i++) {
-		if (conf->mirrors[i].rdev &&
-		    !conf->mirrors[i].rdev->faulty) {
-			atomic_inc(&conf->mirrors[i].rdev->nr_pending);
-			r1_bio->bios[i] = bio;
+		if ((rdev=conf->mirrors[i].rdev) != NULL &&
+		    !rdev->faulty) {
+			atomic_inc(&rdev->nr_pending);
+			if (rdev->faulty) {
+				atomic_dec(&rdev->nr_pending);
+				r1_bio->bios[i] = NULL;
+			} else
+				r1_bio->bios[i] = bio;
 		} else
 			r1_bio->bios[i] = NULL;
 	}
@@ -781,7 +797,7 @@ static int raid1_remove_disk(mddev_t *md
 			goto abort;
 		}
 		p->rdev = NULL;
-		synchronize_kernel();
+		synchronize_rcu();
 		if (atomic_read(&rdev->nr_pending)) {
 			/* lost the race, try later */
 			err = -EBUSY;
@@ -1181,10 +1197,6 @@ static int run(mddev_t *mddev)
 	if (!conf->r1bio_pool)
 		goto out_no_mem;
 
-	mddev->queue->unplug_fn = raid1_unplug;
-
-	mddev->queue->issue_flush_fn = raid1_issue_flush;
-
 	ITERATE_RDEV(mddev, rdev, tmp) {
 		disk_idx = rdev->raid_disk;
 		if (disk_idx >= mddev->raid_disks
@@ -1266,6 +1278,9 @@ static int run(mddev_t *mddev)
 	 */
 	mddev->array_size = mddev->size;
 
+	mddev->queue->unplug_fn = raid1_unplug;
+	mddev->queue->issue_flush_fn = raid1_issue_flush;
+
 	return 0;
 
 out_no_mem:
@@ -1346,7 +1361,7 @@ static int raid1_reshape(mddev_t *mddev,
 		if (conf->mirrors[d].rdev)
 			return -EBUSY;
 
-	newpoolinfo = kmalloc(sizeof(newpoolinfo), GFP_KERNEL);
+	newpoolinfo = kmalloc(sizeof(*newpoolinfo), GFP_KERNEL);
 	if (!newpoolinfo)
 		return -ENOMEM;
 	newpoolinfo->mddev = mddev;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -47,7 +47,7 @@
 
 static void unplug_slaves(mddev_t *mddev);
 
-static void * r10bio_pool_alloc(int gfp_flags, void *data)
+static void * r10bio_pool_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	conf_t *conf = data;
 	r10bio_t *r10_bio;
@@ -81,7 +81,7 @@ static void r10bio_pool_free(void *r10_b
  * one for write (we recover only one drive per r10buf)
  *
  */
-static void * r10buf_pool_alloc(int gfp_flags, void *data)
+static void * r10buf_pool_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	conf_t *conf = data;
 	struct page *page;
@@ -977,7 +977,7 @@ static int raid10_remove_disk(mddev_t *m
 			goto abort;
 		}
 		p->rdev = NULL;
-		synchronize_kernel();
+		synchronize_rcu();
 		if (atomic_read(&rdev->nr_pending)) {
 			/* lost the race, try later */
 			err = -EBUSY;
@@ -1639,9 +1639,6 @@ static int run(mddev_t *mddev)
 			mdname(mddev));
 		goto out_free_conf;
 	}
-	mddev->queue->unplug_fn = raid10_unplug;
-
-	mddev->queue->issue_flush_fn = raid10_issue_flush;
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
 		disk_idx = rdev->raid_disk;
@@ -1713,6 +1710,9 @@ static int run(mddev_t *mddev)
 	mddev->array_size = size/2;
 	mddev->resync_max_sectors = size;
 
+	mddev->queue->unplug_fn = raid10_unplug;
+	mddev->queue->issue_flush_fn = raid10_issue_flush;
+
 	/* Calculate max read-ahead size.
 	 * We need to readahead at least twice a whole stripe....
 	 * maybe...
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1493,6 +1493,15 @@ static int sync_request (mddev_t *mddev,
 		unplug_slaves(mddev);
 		return 0;
 	}
+	/* if there is 1 or more failed drives and we are trying
+	 * to resync, then assert that we are finished, because there is
+	 * nothing we can do.
+	 */
+	if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+		int rv = (mddev->size << 1) - sector_nr;
+		md_done_sync(mddev, rv, 1);
+		return rv;
+	}
 
 	x = sector_nr;
 	chunk_offset = sector_div(x, sectors_per_chunk);
@@ -1611,9 +1620,6 @@ static int run (mddev_t *mddev)
 	atomic_set(&conf->active_stripes, 0);
 	atomic_set(&conf->preread_active_stripes, 0);
 
-	mddev->queue->unplug_fn = raid5_unplug_device;
-	mddev->queue->issue_flush_fn = raid5_issue_flush;
-
 	PRINTK("raid5: run(%s) called.\n", mdname(mddev));
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
@@ -1719,6 +1725,10 @@ memory = conf->max_nr_stripes * (sizeof(
 	}
 
 	/* Ok, everything is just fine now */
+
+	mddev->queue->unplug_fn = raid5_unplug_device;
+	mddev->queue->issue_flush_fn = raid5_issue_flush;
+
 	mddev->array_size =  mddev->size * (mddev->raid_disks - 1);
 	return 0;
 abort:
@@ -1864,7 +1874,7 @@ static int raid5_remove_disk(mddev_t *md
 			goto abort;
 		}
 		p->rdev = NULL;
-		synchronize_kernel();
+		synchronize_rcu();
 		if (atomic_read(&rdev->nr_pending)) {
 			/* lost the race, try later */
 			err = -EBUSY;
@@ -1884,6 +1894,10 @@ static int raid5_add_disk(mddev_t *mddev
 	int disk;
 	struct disk_info *p;
 
+	if (mddev->degraded > 1)
+		/* no point adding a device */
+		return 0;
+
 	/*
 	 * find the disk ...
 	 */
diff --git a/drivers/md/raid6altivec.uc b/drivers/md/raid6altivec.uc
--- a/drivers/md/raid6altivec.uc
+++ b/drivers/md/raid6altivec.uc
@@ -108,7 +108,7 @@ int raid6_have_altivec(void);
 int raid6_have_altivec(void)
 {
 	/* This assumes either all CPUs have Altivec or none does */
-	return cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC;
+	return cpu_has_feature(CPU_FTR_ALTIVEC);
 }
 #endif
 
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -1652,6 +1652,15 @@ static int sync_request (mddev_t *mddev,
 		unplug_slaves(mddev);
 		return 0;
 	}
+	/* if there are 2 or more failed drives and we are trying
+	 * to resync, then assert that we are finished, because there is
+	 * nothing we can do.
+	 */
+	if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+		int rv = (mddev->size << 1) - sector_nr;
+		md_done_sync(mddev, rv, 1);
+		return rv;
+	}
 
 	x = sector_nr;
 	chunk_offset = sector_div(x, sectors_per_chunk);
@@ -1770,9 +1779,6 @@ static int run (mddev_t *mddev)
 	atomic_set(&conf->active_stripes, 0);
 	atomic_set(&conf->preread_active_stripes, 0);
 
-	mddev->queue->unplug_fn = raid6_unplug_device;
-	mddev->queue->issue_flush_fn = raid6_issue_flush;
-
 	PRINTK("raid6: run(%s) called.\n", mdname(mddev));
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
@@ -1886,6 +1892,9 @@ static int run (mddev_t *mddev)
 
 	/* Ok, everything is just fine now */
 	mddev->array_size =  mddev->size * (mddev->raid_disks - 2);
+
+	mddev->queue->unplug_fn = raid6_unplug_device;
+	mddev->queue->issue_flush_fn = raid6_issue_flush;
 	return 0;
 abort:
 	if (conf) {
@@ -2029,7 +2038,7 @@ static int raid6_remove_disk(mddev_t *md
 			goto abort;
 		}
 		p->rdev = NULL;
-		synchronize_kernel();
+		synchronize_rcu();
 		if (atomic_read(&rdev->nr_pending)) {
 			/* lost the race, try later */
 			err = -EBUSY;
@@ -2050,6 +2059,9 @@ static int raid6_add_disk(mddev_t *mddev
 	int disk;
 	struct disk_info *p;
 
+	if (mddev->degraded > 2)
+		/* no point adding a device */
+		return 0;
 	/*
 	 * find the disk ...
 	 */
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-common.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: ir-common.c,v 1.8 2005/02/22 12:28:40 kraxel Exp $
  *
  * some common structs and functions to handle infrared remotes via
  * input layer ...
@@ -23,7 +23,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-
 #include <media/ir-common.h>
 
 /* -------------------------------------------------------------------------- */
@@ -45,6 +44,7 @@ module_param(debug, int, 0644);
 
 /* generic RC5 keytable                                          */
 /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
+/* used by old (black) Hauppauge remotes                         */
 IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
 	[ 0x00 ] = KEY_KP0,             // 0
 	[ 0x01 ] = KEY_KP1,             // 1
@@ -117,12 +117,102 @@ IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB
 };
 EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
 
+/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
+IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+	[  5 ] = KEY_KP1,
+	[  6 ] = KEY_KP2,
+	[  7 ] = KEY_KP3,
+	[  9 ] = KEY_KP4,
+	[ 10 ] = KEY_KP5,
+	[ 11 ] = KEY_KP6,
+	[ 13 ] = KEY_KP7,
+	[ 14 ] = KEY_KP8,
+	[ 15 ] = KEY_KP9,
+	[ 18 ] = KEY_KP0,
+
+	[  0 ] = KEY_POWER,
+	[ 27 ] = KEY_LANGUAGE,  //MTS button
+	[  2 ] = KEY_TUNER,     // TV/FM
+	[ 30 ] = KEY_VIDEO,
+	[ 22 ] = KEY_INFO,      //display button
+	[  4 ] = KEY_VOLUMEUP,
+	[  8 ] = KEY_VOLUMEDOWN,
+	[ 12 ] = KEY_CHANNELUP,
+	[ 16 ] = KEY_CHANNELDOWN,
+	[  3 ] = KEY_ZOOM,      // fullscreen
+	[ 31 ] = KEY_SUBTITLE,  // closed caption/teletext
+	[ 32 ] = KEY_SLEEP,
+	[ 41 ] = KEY_SEARCH,    //boss key
+	[ 20 ] = KEY_MUTE,
+	[ 43 ] = KEY_RED,
+	[ 44 ] = KEY_GREEN,
+	[ 45 ] = KEY_YELLOW,
+	[ 46 ] = KEY_BLUE,
+	[ 24 ] = KEY_KPPLUS,    //fine tune +
+	[ 25 ] = KEY_KPMINUS,   //fine tune -
+	[ 42 ] = KEY_ANGLE,     //picture in picture
+	[ 33 ] = KEY_KPDOT,
+	[ 19 ] = KEY_KPENTER,
+	[ 17 ] = KEY_AGAIN,     //recall
+	[ 34 ] = KEY_BACK,
+	[ 35 ] = KEY_PLAYPAUSE,
+	[ 36 ] = KEY_NEXT,
+	[ 37 ] = KEY_T,         //time shifting
+	[ 38 ] = KEY_STOP,
+	[ 39 ] = KEY_RECORD,
+	[ 40 ] = KEY_SHUFFLE    //snapshot
+};
+EXPORT_SYMBOL_GPL(ir_codes_winfast);
+
 /* empty keytable, can be used as placeholder for not-yet created keytables */
 IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
 	[ 42 ] = KEY_COFFEE,
 };
 EXPORT_SYMBOL_GPL(ir_codes_empty);
 
+/* Hauppauge: the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ * almost rc5 coding, but some non-standard keys */
+IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_KP0,             // 0
+	[ 0x01 ] = KEY_KP1,             // 1
+	[ 0x02 ] = KEY_KP2,             // 2
+	[ 0x03 ] = KEY_KP3,             // 3
+	[ 0x04 ] = KEY_KP4,             // 4
+	[ 0x05 ] = KEY_KP5,             // 5
+	[ 0x06 ] = KEY_KP6,             // 6
+	[ 0x07 ] = KEY_KP7,             // 7
+	[ 0x08 ] = KEY_KP8,             // 8
+	[ 0x09 ] = KEY_KP9,             // 9
+	[ 0x0b ] = KEY_RED,             // red button
+	[ 0x0c ] = KEY_OPTION,          // black key without text
+	[ 0x0d ] = KEY_MENU,            // menu
+	[ 0x0f ] = KEY_MUTE,            // mute
+	[ 0x10 ] = KEY_VOLUMEUP,        // volume +
+	[ 0x11 ] = KEY_VOLUMEDOWN,      // volume -
+	[ 0x1e ] = KEY_NEXT,            // skip >|
+	[ 0x1f ] = KEY_EXIT,            // back/exit
+	[ 0x20 ] = KEY_CHANNELUP,       // channel / program +
+	[ 0x21 ] = KEY_CHANNELDOWN,     // channel / program -
+	[ 0x22 ] = KEY_CHANNEL,         // source (old black remote)
+	[ 0x24 ] = KEY_PREVIOUS,        // replay |<
+	[ 0x25 ] = KEY_ENTER,           // OK
+	[ 0x26 ] = KEY_SLEEP,           // minimize (old black remote)
+	[ 0x29 ] = KEY_BLUE,            // blue key
+	[ 0x2e ] = KEY_GREEN,           // green button
+	[ 0x30 ] = KEY_PAUSE,           // pause
+	[ 0x32 ] = KEY_REWIND,          // backward <<
+	[ 0x34 ] = KEY_FASTFORWARD,     // forward >>
+	[ 0x35 ] = KEY_PLAY,            // play
+	[ 0x36 ] = KEY_STOP,            // stop
+	[ 0x37 ] = KEY_RECORD,          // recording
+	[ 0x38 ] = KEY_YELLOW,          // yellow key
+	[ 0x3b ] = KEY_SELECT,          // top right button
+	[ 0x3c ] = KEY_ZOOM,            // full
+	[ 0x3d ] = KEY_POWER,           // system power (green button)
+};
+EXPORT_SYMBOL(ir_codes_hauppauge_new);
+
 /* -------------------------------------------------------------------------- */
 
 static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
@@ -192,6 +282,8 @@ void ir_input_keydown(struct input_dev *
 #endif
 }
 
+/* -------------------------------------------------------------------------- */
+
 u32 ir_extract_bits(u32 data, u32 mask)
 {
 	int mbit, vbit;
@@ -209,10 +301,78 @@ u32 ir_extract_bits(u32 data, u32 mask)
 	return value;
 }
 
+static int inline getbit(u32 *samples, int bit)
+{
+	return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
+}
+
+/* sump raw samples for visual debugging ;) */
+int ir_dump_samples(u32 *samples, int count)
+{
+	int i, bit, start;
+
+	printk(KERN_DEBUG "ir samples: ");
+	start = 0;
+	for (i = 0; i < count * 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			start = 1;
+		if (0 == start)
+			continue;
+		printk("%s", bit ? "#" : "_");
+	}
+	printk("\n");
+	return 0;
+}
+
+/* decode raw samples, biphase coding, used by rc5 for example */
+int ir_decode_biphase(u32 *samples, int count, int low, int high)
+{
+	int i,last,bit,len,flips;
+	u32 value;
+
+	/* find start bit (1) */
+	for (i = 0; i < 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			break;
+	}
+
+	/* go decoding */
+	len   = 0;
+	flips = 0;
+	value = 1;
+	for (; i < count * 32; i++) {
+		if (len > high)
+			break;
+		if (flips > 1)
+			break;
+		last = bit;
+		bit  = getbit(samples,i);
+		if (last == bit) {
+			len++;
+			continue;
+		}
+		if (len < low) {
+			len++;
+			flips++;
+			continue;
+		}
+		value <<= 1;
+		value |= bit;
+		flips = 0;
+		len   = 1;
+	}
+	return value;
+}
+
 EXPORT_SYMBOL_GPL(ir_input_init);
 EXPORT_SYMBOL_GPL(ir_input_nokey);
 EXPORT_SYMBOL_GPL(ir_input_keydown);
+
 EXPORT_SYMBOL_GPL(ir_extract_bits);
+EXPORT_SYMBOL_GPL(ir_dump_samples);
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
 
 /*
  * Local variables:
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -20,14 +20,12 @@
 
 #include <media/saa7146.h>
 
-/* global variables */
-struct list_head saa7146_devices;
-struct semaphore saa7146_devices_lock;
+LIST_HEAD(saa7146_devices);
+DECLARE_MUTEX(saa7146_devices_lock);
 
-static int initialized = 0;
-static int saa7146_num = 0;
+static int saa7146_num;
 
-unsigned int saa7146_debug = 0;
+unsigned int saa7146_debug;
 
 module_param(saa7146_debug, int, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
@@ -48,21 +46,15 @@ static void dump_registers(struct saa714
  * gpio and debi helper functions
  ****************************************************************************/
 
-/* write "data" to the gpio-pin "pin" -- unused */
-void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
+void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
 {
 	u32 value = 0;
 
-	/* sanity check */
-	if(pin > 3)
-		return;
-
-	/* read old register contents */
-	value = saa7146_read(dev, GPIO_CTRL );
-	
-	value &= ~(0xff << (8*pin));
-	value |= (data << (8*pin));
+	BUG_ON(port > 3);
 
+	value = saa7146_read(dev, GPIO_CTRL);
+	value &= ~(0xff << (8*port));
+	value |= (data << (8*port));
 	saa7146_write(dev, GPIO_CTRL, value);
 }
 
@@ -105,7 +97,7 @@ int saa7146_wait_for_debi_done(struct sa
  * general helper functions
  ****************************************************************************/
 
-/* this is videobuf_vmalloc_to_sg() from video-buf.c 
+/* this is videobuf_vmalloc_to_sg() from video-buf.c
    make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
    may be triggered on highmem machines */
 static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
@@ -128,7 +120,7 @@ static struct scatterlist* vmalloc_to_sg
 		sglist[i].length = PAGE_SIZE;
 	}
 	return sglist;
-	
+
  err:
 	kfree(sglist);
 	return NULL;
@@ -158,7 +150,7 @@ char *saa7146_vmalloc_build_pgtable(stru
 		vfree(mem);
 		return NULL;
 	}
-	
+
 	slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE);
 	if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) {
 		return NULL;
@@ -198,13 +190,13 @@ int saa7146_pgtable_alloc(struct pci_dev
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
 	struct scatterlist *list, int sglen  )
 {
-	u32   *ptr, fill;
+	u32 *ptr, fill;
 	int nr_pages = 0;
-	int   i,p;
+	int i,p;
 
-	BUG_ON( 0 == sglen);
+	BUG_ON(0 == sglen);
 	BUG_ON(list->offset > PAGE_SIZE);
-	
+
 	/* if we have a user buffer, the first page may not be
 	   aligned to a page boundary. */
 	pt->offset = list->offset;
@@ -238,19 +230,6 @@ int saa7146_pgtable_build_single(struct 
 }
 
 /********************************************************************************/
-/* gpio functions */
-
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
-{
-	u32 val = 0;
-
-        val=saa7146_read(dev,GPIO_CTRL);
-        val&=~(0xff << (8*(port)));
-        val|=(data)<<(8*(port));
-        saa7146_write(dev, GPIO_CTRL, val);
-}
-
-/********************************************************************************/
 /* interrupt handler */
 static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -322,10 +301,10 @@ static irqreturn_t interrupt_hw(int irq,
 static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
 {
 	struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
-	struct saa7146_extension* ext = pci_ext->ext;
+	struct saa7146_extension *ext = pci_ext->ext;
 	struct saa7146_dev *dev;
 	int err = -ENOMEM;
-	
+
 	dev = kmalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
 	if (!dev) {
 		ERR(("out of memory.\n"));
@@ -394,7 +373,7 @@ static int saa7146_init_one(struct pci_d
 		goto err_unmap;
 	}
 
-		err = -ENOMEM;
+	err = -ENOMEM;
 
 	/* get memory for various stuff */
 	dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
@@ -423,7 +402,7 @@ static int saa7146_init_one(struct pci_d
 	INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
 	dev->ext = ext;
 
-	pci_set_drvdata(pci,dev);
+	pci_set_drvdata(pci, dev);
 
         init_MUTEX(&dev->lock);
 	spin_lock_init(&dev->int_slock);
@@ -435,11 +414,11 @@ static int saa7146_init_one(struct pci_d
 	init_waitqueue_head(&dev->i2c_wq);
 
 	/* set some sane pci arbitrition values */
-	saa7146_write(dev, PCI_BT_V1, 0x1c00101f); 
+	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 
 	/* TODO: use the status code of the callback */
 
-			err = -ENODEV;
+	err = -ENODEV;
 
 	if (ext->probe && ext->probe(dev)) {
 		DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
@@ -460,7 +439,7 @@ out:
 	return err;
 
 err_unprobe:
-	pci_set_drvdata(pci,NULL);
+	pci_set_drvdata(pci, NULL);
 err_free_i2c:
 	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
 			    dev->d_i2c.dma_handle);
@@ -527,12 +506,6 @@ int saa7146_register_extension(struct sa
 {
 	DEB_EE(("ext:%p\n",ext));
 
-	if( 0 == initialized ) {
-		INIT_LIST_HEAD(&saa7146_devices);
-		init_MUTEX(&saa7146_devices_lock);
-		initialized = 1;
-	}
-
 	ext->driver.name = ext->name;
 	ext->driver.id_table = ext->pci_tbl;
 	ext->driver.probe = saa7146_init_one;
@@ -550,23 +523,6 @@ int saa7146_unregister_extension(struct 
 	return 0;
 }
 
-static int __init saa7146_init_module(void)
-{
-	if( 0 == initialized ) {
-		INIT_LIST_HEAD(&saa7146_devices);
-		init_MUTEX(&saa7146_devices_lock);
-		initialized = 1;
-	}
-	return 0;
-}
-
-static void __exit saa7146_cleanup_module(void)
-{
-}
-
-module_init(saa7146_init_module);
-module_exit(saa7146_cleanup_module);
-
 EXPORT_SYMBOL_GPL(saa7146_register_extension);
 EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
 
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -444,7 +444,7 @@ int saa7146_vv_init(struct saa7146_dev* 
 	memset(vv, 0x0, sizeof(*vv));
 
 	DEB_EE(("dev:%p\n",dev));
-	
+
 	/* set default values for video parts of the saa7146 */
 	saa7146_write(dev, BCS_CTRL, 0x80400040);
 
@@ -497,7 +497,7 @@ int saa7146_register_device(struct video
 	struct video_device *vfd;
 
 	DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
- 
+
 	// released by vfd->release
  	vfd = video_device_alloc();
 	if (vfd == NULL)
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -4,7 +4,7 @@
 static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
 {
 	/* clear out the necessary bits */
-	*clip_format &= 0x0000ffff;	
+	*clip_format &= 0x0000ffff;
 	/* set these bits new */
 	*clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
 }
@@ -21,7 +21,7 @@ static void calculate_hxo_and_hyo(struct
 
 	hyo = vv->standard->v_offset;
 	hxo = vv->standard->h_offset;
-				
+
 	*hps_h_scale	&= ~(MASK_B0 | 0xf00);
 	*hps_h_scale	|= (hxo <<  0);
 
@@ -40,7 +40,7 @@ static void calculate_hxo_and_hyo(struct
 static struct {
 	u16 hps_coeff;
 	u16 weight_sum;
-} hps_h_coeff_tab [] = { 
+} hps_h_coeff_tab [] = {
 	{0x00,   2}, {0x02,   4}, {0x00,   4}, {0x06,   8}, {0x02,   8},
 	{0x08,   8}, {0x00,   8}, {0x1E,  16}, {0x0E,   8}, {0x26,   8},
 	{0x06,   8}, {0x42,   8}, {0x02,   8}, {0x80,   8}, {0x00,   8},
@@ -65,11 +65,11 @@ static int calculate_h_scale_registers(s
 	u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
 {
 	/* horizontal prescaler */
-	u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;	
+	u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
 	/* horizontal scaler */
-	u32 xim = 0, xp = 0, xsci =0;				
+	u32 xim = 0, xp = 0, xsci =0;
 	/* vertical scale & gain */
-	u32 pfuv = 0;						
+	u32 pfuv = 0;
 
 	/* helper variables */
 	u32 h_atten = 0, i = 0;
@@ -77,29 +77,29 @@ static int calculate_h_scale_registers(s
 	if ( 0 == out_x ) {
 		return -EINVAL;
 	}
-	
+
 	/* mask out vanity-bit */
 	*hps_ctrl &= ~MASK_29;
-		
+
 	/* calculate prescale-(xspc)-value:	[n   .. 1/2) : 1
-				    		[1/2 .. 1/3) : 2
-				    		[1/3 .. 1/4) : 3
-						... 		*/
+						[1/2 .. 1/3) : 2
+						[1/3 .. 1/4) : 3
+						...		*/
 	if (in_x > out_x) {
 		xpsc = in_x / out_x;
 	}
 	else {
 		/* zooming */
-		xpsc = 1;						
+		xpsc = 1;
 	}
-	
+
 	/* if flip_lr-bit is set, number of pixels after
 	   horizontal prescaling must be < 384 */
 	if ( 0 != flip_lr ) {
-	
+
 		/* set vanity bit */
 		*hps_ctrl |= MASK_29;
-	
+
 		while (in_x / xpsc >= 384 )
 			xpsc++;
 	}
@@ -109,35 +109,35 @@ static int calculate_h_scale_registers(s
 		while ( in_x / xpsc >= 768 )
 			xpsc++;
 	}
-	
+
 	/* maximum prescale is 64 (p.69) */
 	if ( xpsc > 64 )
 		xpsc = 64;
 
 	/* keep xacm clear*/
 	xacm = 0;
-	
+
 	/* set horizontal filter parameters (CXY = CXUV) */
 	cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;
 	cxuv = cxy;
-	
+
 	/* calculate and set horizontal fine scale (xsci) */
-	
+
 	/* bypass the horizontal scaler ? */
 	if ( (in_x == out_x) && ( 1 == xpsc ) )
 		xsci = 0x400;
-	else	
+	else
 		xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
 
-	/* set start phase for horizontal fine scale (xp) to 0 */	
+	/* set start phase for horizontal fine scale (xp) to 0 */
 	xp = 0;
-	
+
 	/* set xim, if we bypass the horizontal scaler */
 	if ( 0x400 == xsci )
 		xim = 1;
 	else
 		xim = 0;
-		
+
 	/* if the prescaler is bypassed, enable horizontal
 	   accumulation mode (xacm) and clear dcgx */
 	if( 1 == xpsc ) {
@@ -148,12 +148,12 @@ static int calculate_h_scale_registers(s
 		/* get best match in the table of attenuations
 		   for horizontal scaling */
 		h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;
-	
+
 		for (i = 0; h_attenuation[i] != 0; i++) {
 			if (h_attenuation[i] >= h_atten)
 				break;
 		}
-	
+
 		dcgx = i;
 	}
 
@@ -171,11 +171,11 @@ static int calculate_h_scale_registers(s
 	else
 		pfuv = 0x33;
 
-	
+
 	*hps_v_gain  &= MASK_W0|MASK_B2;
-	*hps_v_gain  |= (pfuv << 24);	
+	*hps_v_gain  |= (pfuv << 24);
 
-	*hps_h_scale 	&= ~(MASK_W1 | 0xf000);
+	*hps_h_scale	&= ~(MASK_W1 | 0xf000);
 	*hps_h_scale	|= (xim << 31) | (xp << 24) | (xsci << 12);
 
 	*hps_h_prescale	|= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
@@ -186,7 +186,7 @@ static int calculate_h_scale_registers(s
 static struct {
 	u16 hps_coeff;
 	u16 weight_sum;
-} hps_v_coeff_tab [] = { 
+} hps_v_coeff_tab [] = {
  {0x0100,   2},  {0x0102,   4},  {0x0300,   4},  {0x0106,   8},  {0x0502,   8},
  {0x0708,   8},  {0x0F00,   8},  {0x011E,  16},  {0x110E,  16},  {0x1926,  16},
  {0x3906,  16},  {0x3D42,  16},  {0x7D02,  16},  {0x7F80,  16},  {0xFF00,  16},
@@ -210,14 +210,14 @@ static int calculate_v_scale_registers(s
 	int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain)
 {
 	int lpi = 0;
-	
+
 	/* vertical scaling */
 	u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0;
 	/* vertical scale & gain */
 	u32 dcgy = 0, cya_cyb = 0;
-				
+
 	/* helper variables */
-	u32 v_atten = 0, i = 0;	
+	u32 v_atten = 0, i = 0;
 
 	/* error, if vertical zooming */
 	if ( in_y < out_y ) {
@@ -245,7 +245,7 @@ static int calculate_v_scale_registers(s
 		yacm = 0;
 		yacl = 0;
 		cya_cyb = 0x00ff;
-		
+
 		/* calculate scaling increment */
 		if ( in_y > out_y )
 			ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
@@ -257,9 +257,9 @@ static int calculate_v_scale_registers(s
 		/* calculate ype and ypo */
 		ype = ysci / 16;
 		ypo = ype + (ysci / 64);
-		
+
 	} else {
-		yacm = 1;	
+		yacm = 1;
 
 		/* calculate scaling increment */
 		ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
@@ -269,7 +269,7 @@ static int calculate_v_scale_registers(s
 
 		/* the sequence length interval (yacl) has to be set according
 		   to the prescale value, e.g.	[n   .. 1/2) : 0
-		   				[1/2 .. 1/3) : 1
+						[1/2 .. 1/3) : 1
 						[1/3 .. 1/4) : 2
 						... */
 		if ( ysci < 512) {
@@ -278,7 +278,7 @@ static int calculate_v_scale_registers(s
 			yacl = ( ysci / (1024 - ysci) );
 		}
 
-		/* get filter coefficients for cya, cyb from table hps_v_coeff_tab */	
+		/* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
 		cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;
 
 		/* get best match in the table of attenuations for vertical scaling */
@@ -288,7 +288,7 @@ static int calculate_v_scale_registers(s
 			if (v_attenuation[i] >= v_atten)
 				break;
 		}
-	
+
 		dcgy = i;
 	}
 
@@ -306,12 +306,12 @@ static int sort_and_eliminate(u32* value
 {
 	int low = 0, high = 0, top = 0, temp = 0;
 	int cur = 0, next = 0;
-	
+
 	/* sanity checks */
 	if( (0 > *count) || (NULL == values) ) {
 		return -EINVAL;
 	}
-	
+
 	/* bubble sort the first ´count´ items of the array ´values´ */
 	for( top = *count; top > 0; top--) {
 		for( low = 0, high = 1; high < top; low++, high++) {
@@ -328,9 +328,9 @@ static int sort_and_eliminate(u32* value
 		if( values[cur] != values[next])
 			values[++cur] = values[next];
 	}
-	
+
 	*count = cur + 1;
-	 
+
 	return 0;
 }
 
@@ -343,8 +343,8 @@ static void calculate_clipping_registers
 	int width = fh->ov.win.w.width;
 	int height =  fh->ov.win.w.height;
 	int clipcount = fh->ov.nclips;
-	
-	u32 line_list[32];			
+
+	u32 line_list[32];
 	u32 pixel_list[32];
 	int numdwords = 0;
 
@@ -361,12 +361,12 @@ static void calculate_clipping_registers
 	/* fill the line and pixel-lists */
 	for(i = 0; i < clipcount; i++) {
 		int l = 0, r = 0, t = 0, b = 0;
-		
+
 		x[i] = fh->ov.clips[i].c.left;
 		y[i] = fh->ov.clips[i].c.top;
 		w[i] = fh->ov.clips[i].c.width;
 		h[i] = fh->ov.clips[i].c.height;
-		
+
 		if( w[i] < 0) {
 			x[i] += w[i]; w[i] = -w[i];
 		}
@@ -378,7 +378,7 @@ static void calculate_clipping_registers
 		}
 		if( y[i] < 0) {
 			h[i] += y[i]; y[i] = 0;
-		}	
+		}
 		if( 0 != vv->vflip ) {
 			y[i] = height - y[i] - h[i];
 		}
@@ -387,7 +387,7 @@ static void calculate_clipping_registers
 		r = x[i]+w[i];
 		t = y[i];
 		b = y[i]+h[i];
-		
+
 		/* insert left/right coordinates */
 		pixel_list[ 2*i   ] = min_t(int, l, width);
 		pixel_list[(2*i)+1] = min_t(int, r, width);
@@ -423,7 +423,7 @@ static void calculate_clipping_registers
 				x[j] = 0;
 
 			if( pixel_list[i] < (x[j] + w[j])) {
-			
+
 				if ( pixel_list[i] >= x[j] ) {
 					clipping[2*i] |= cpu_to_le32(1 << j);
 				}
@@ -445,8 +445,8 @@ static void calculate_clipping_registers
 
 	/* adjust arbitration control register */
 	*arbtr_ctrl &= 0xffff00ff;
-	*arbtr_ctrl |= 0x00001c00;	
-	
+	*arbtr_ctrl |= 0x00001c00;
+
 	vdma2->base_even	= vv->d_clipping.dma_handle;
 	vdma2->base_odd		= vv->d_clipping.dma_handle;
 	vdma2->prot_addr	= vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
@@ -473,9 +473,9 @@ static void saa7146_disable_clipping(str
 
 	/* upload clipping-registers*/
 	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
- 	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
- 
- 	/* disable video dma2 */
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+
+	/* disable video dma2 */
 	saa7146_write(dev, MC1, MASK_21);
 }
 
@@ -509,10 +509,10 @@ static void saa7146_set_clipping_rect(st
 	saa7146_write(dev, BASE_PAGE2,		vdma2.base_page);
 	saa7146_write(dev, PITCH2,		vdma2.pitch);
 	saa7146_write(dev, NUM_LINE_BYTE2,	vdma2.num_line_byte);
-	
+
 	/* prepare the rest */
 	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
-	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);	
+	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
 
 	/* upload clip_control-register, clipping-registers, enable video dma2 */
 	saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
@@ -530,11 +530,11 @@ static void saa7146_set_window(struct sa
 
 	/* set vertical scale */
 	hps_v_scale = 0; /* all bits get set by the function-call */
-	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ 
+	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
 	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
 
 	/* set horizontal scale */
-	hps_ctrl 	= 0;
+	hps_ctrl	= 0;
 	hps_h_prescale	= 0; /* all bits get set in the function */
 	hps_h_scale	= 0;
 	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
@@ -542,43 +542,43 @@ static void saa7146_set_window(struct sa
 	/* set hyo and hxo */
 	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
 	calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);
-	
+
 	/* write out new register contents */
 	saa7146_write(dev, HPS_V_SCALE,	hps_v_scale);
 	saa7146_write(dev, HPS_V_GAIN,	hps_v_gain);
 	saa7146_write(dev, HPS_CTRL,	hps_ctrl);
 	saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);
 	saa7146_write(dev, HPS_H_SCALE,	hps_h_scale);
-	
+
 	/* upload shadow-ram registers */
-      	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
+	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
 }
 
 /* calculate the new memory offsets for a desired position */
 static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
-{	
+{
 	struct saa7146_vv *vv = dev->vv_data;
 	struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
 
 	int b_depth = vv->ov_fmt->depth;
 	int b_bpl = vv->ov_fb.fmt.bytesperline;
 	u32 base = (u32)vv->ov_fb.base;
-	
+
 	struct	saa7146_video_dma vdma1;
 
 	/* calculate memory offsets for picture, look if we shall top-down-flip */
 	vdma1.pitch	= 2*b_bpl;
 	if ( 0 == vv->vflip ) {
-		vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); 
+		vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
 		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
 		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
 	}
 	else {
-		vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); 
+		vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
 		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
 		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
 	}
-	
+
 	if (V4L2_FIELD_HAS_BOTH(field)) {
 	} else if (field == V4L2_FIELD_ALTERNATE) {
 		/* fixme */
@@ -596,7 +596,7 @@ static void saa7146_set_position(struct 
 	if ( 0 != vv->vflip ) {
 		vdma1.pitch *= -1;
 	}
-		
+
 	vdma1.base_page = sfmt->swap;
 	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
 
@@ -606,13 +606,13 @@ static void saa7146_set_position(struct 
 static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
 {
 	u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
-	
+
 	/* call helper function */
 	calculate_output_format_register(dev,palette,&clip_format);
 
 	/* update the hps registers */
 	saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
-      	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
 }
 
 /* select input-source */
@@ -630,10 +630,10 @@ void saa7146_set_hps_source_and_sync(str
 	/* write back & upload register */
 	saa7146_write(dev, HPS_CTRL, hps_ctrl);
 	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
-	
+
 	vv->current_hps_source = source;
 	vv->current_hps_sync = sync;
-} 
+}
 
 int saa7146_enable_overlay(struct saa7146_fh *fh)
 {
@@ -655,31 +655,31 @@ void saa7146_disable_overlay(struct saa7
 	struct saa7146_dev *dev = fh->dev;
 
 	/* disable clipping + video dma1 */
- 	saa7146_disable_clipping(dev);
+	saa7146_disable_clipping(dev);
 	saa7146_write(dev, MC1, MASK_22);
-}		
+}
 
-void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) 
+void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
 {
 	int where = 0;
-	
+
 	if( which < 1 || which > 3) {
 		return;
 	}
-	
+
 	/* calculate starting address */
 	where  = (which-1)*0x18;
 
-		saa7146_write(dev, where, 	vdma->base_odd);
-		saa7146_write(dev, where+0x04, 	vdma->base_even);
-	saa7146_write(dev, where+0x08, 	vdma->prot_addr);
-	saa7146_write(dev, where+0x0c, 	vdma->pitch);
-	saa7146_write(dev, where+0x10, 	vdma->base_page);
+	saa7146_write(dev, where,	vdma->base_odd);
+	saa7146_write(dev, where+0x04,	vdma->base_even);
+	saa7146_write(dev, where+0x08,	vdma->prot_addr);
+	saa7146_write(dev, where+0x0c,	vdma->pitch);
+	saa7146_write(dev, where+0x10,	vdma->base_page);
 	saa7146_write(dev, where+0x14,	vdma->num_line_byte);
-	
+
 	/* upload */
-	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));		
-/*		
+	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));
+/*
 	printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);
 	printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);
 	printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);
@@ -688,6 +688,7 @@ void saa7146_write_out_dma(struct saa714
 	printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
 */
 }
+
 static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
 {
 	struct saa7146_vv *vv = dev->vv_data;
@@ -708,11 +709,11 @@ static int calculate_video_dma_grab_pack
 	if( bytesperline != 0) {
 		vdma1.pitch = bytesperline*2;
 	} else {
-	vdma1.pitch		= (width*depth*2)/8;
+		vdma1.pitch = (width*depth*2)/8;
 	}
 	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
 	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;
-	
+
 	if( 0 != vv->vflip ) {
 		vdma1.prot_addr	= buf->pt[0].offset;
 		vdma1.base_even	= buf->pt[0].offset+(vdma1.pitch/2)*height;
@@ -745,7 +746,7 @@ static int calculate_video_dma_grab_pack
 
 	if( 0 != vv->vflip ) {
 		vdma1.pitch *= -1;
-	}	
+	}
 
 	saa7146_write_out_dma(dev, 1, &vdma1);
 	return 0;
@@ -769,12 +770,11 @@ static int calc_planar_422(struct saa714
 		vdma3->prot_addr	= buf->pt[2].offset;
 		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[2].offset;
 		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
-
 	} else {
 		vdma3->base_even	= buf->pt[2].offset;
 		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch/2);
 		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
-		
+
 		vdma2->base_even	= buf->pt[1].offset;
 		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch/2);
 		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
@@ -812,7 +812,6 @@ static int calc_planar_420(struct saa714
 	return 0;
 }
 
-
 static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
 {
 	struct saa7146_vv *vv = dev->vv_data;
@@ -905,7 +904,7 @@ static int calculate_video_dma_grab_plan
 		vdma1.pitch *= -1;
 		vdma2.pitch *= -1;
 		vdma3.pitch *= -1;
-	}	
+	}
 
 	saa7146_write_out_dma(dev, 1, &vdma1);
 	if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
@@ -931,32 +930,32 @@ static void program_capture_engine(struc
 	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
 
 	/* set rps register 0 */
-	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); 	
+	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
 	WRITE_RPS0(MASK_27 | MASK_11);
-	
+
 	/* turn on video-dma1 */
-	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		
-	WRITE_RPS0(MASK_06 | MASK_22);	    		/* => mask */
+	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+	WRITE_RPS0(MASK_06 | MASK_22);			/* => mask */
 	WRITE_RPS0(MASK_06 | MASK_22);			/* => values */
 	if( 0 != planar ) {
 		/* turn on video-dma2 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		
-		WRITE_RPS0(MASK_05 | MASK_21);	    		/* => mask */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
 		WRITE_RPS0(MASK_05 | MASK_21);			/* => values */
 
 		/* turn on video-dma3 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		
-		WRITE_RPS0(MASK_04 | MASK_20);	    		/* => mask */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
 		WRITE_RPS0(MASK_04 | MASK_20);			/* => values */
 	}
-	
+
 	/* wait for o_fid_a/b / e_fid_a/b toggle */
 	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
 		WRITE_RPS0(CMD_PAUSE | o_wait);
-	WRITE_RPS0(CMD_PAUSE | e_wait);
+		WRITE_RPS0(CMD_PAUSE | e_wait);
 	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
 		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
-	WRITE_RPS0(CMD_PAUSE | o_wait);
+		WRITE_RPS0(CMD_PAUSE | o_wait);
 	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
 		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
 		WRITE_RPS0(CMD_PAUSE | e_wait);
@@ -964,25 +963,25 @@ static void program_capture_engine(struc
 
 	/* turn off video-dma1 */
 	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-	WRITE_RPS0(MASK_22 | MASK_06);	    		/* => mask */
-	WRITE_RPS0(MASK_22);					/* => values */
+	WRITE_RPS0(MASK_22 | MASK_06);			/* => mask */
+	WRITE_RPS0(MASK_22);				/* => values */
 	if( 0 != planar ) {
 		/* turn off video-dma2 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		
-		WRITE_RPS0(MASK_05 | MASK_21);	    		/* => mask */
-		WRITE_RPS0(MASK_21);					/* => values */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
+		WRITE_RPS0(MASK_21);				/* => values */
 
 		/* turn off video-dma3 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		
-		WRITE_RPS0(MASK_04 | MASK_20);	    		/* => mask */
-		WRITE_RPS0(MASK_20);					/* => values */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
+		WRITE_RPS0(MASK_20);				/* => values */
 	}
 
 	/* generate interrupt */
-	WRITE_RPS0(CMD_INTERRUPT);					
+	WRITE_RPS0(CMD_INTERRUPT);
 
 	/* stop */
-	WRITE_RPS0(CMD_STOP);					
+	WRITE_RPS0(CMD_STOP);
 }
 
 void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
@@ -1033,6 +1032,5 @@ void saa7146_set_capture(struct saa7146_
 	saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
 
 	/* turn on rps */
-	saa7146_write(dev, MC1, (MASK_12 | MASK_28));	
+	saa7146_write(dev, MC1, (MASK_12 | MASK_28));
 }
-
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -12,7 +12,7 @@ static u32 saa7146_i2c_func(struct i2c_a
 }
 
 /* this function returns the status-register of our i2c-device */
-static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) 
+static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
 {
 	u32 iicsta = saa7146_read(dev, I2C_STATUS);
 /*
@@ -22,10 +22,10 @@ static inline u32 saa7146_i2c_status(str
 }
 
 /* this function runs through the i2c-messages and prepares the data to be
-   sent through the saa7146. have a look at the specifications p. 122 ff 
+   sent through the saa7146. have a look at the specifications p. 122 ff
    to understand this. it returns the number of u32s to send, or -1
    in case of an error. */
-static int saa7146_i2c_msg_prepare(const struct i2c_msg m[], int num, u32 *op)
+static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
 {
 	int h1, h2;
 	int i, j, addr;
@@ -56,7 +56,7 @@ static int saa7146_i2c_msg_prepare(const
 		/* insert the address of the i2c-slave.
 		   note: we get 7 bit i2c-addresses,
 		   so we have to perform a translation */
-		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); 
+		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
 		h1 = op_count/3; h2 = op_count%3;
 		op[h1] |= (	    (u8)addr << ((3-h2)*8));
 		op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
@@ -70,8 +70,8 @@ static int saa7146_i2c_msg_prepare(const
 			op[h1] |= (       SAA7146_I2C_CONT << ((3-h2)*2));
 			op_count++;
 		}
-		
-	}			
+
+	}
 
 	/* have a look at the last byte inserted:
 	  if it was: ...CONT change it to ...STOP */
@@ -81,7 +81,7 @@ static int saa7146_i2c_msg_prepare(const
 		op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
 	}
 
-	/* return the number of u32s to send */	
+	/* return the number of u32s to send */
 	return mem;
 }
 
@@ -89,7 +89,7 @@ static int saa7146_i2c_msg_prepare(const
    which bytes were read through the adapter and write them back to the corresponding
    i2c-message. but instead, we simply write back all bytes.
    fixme: this could be improved. */
-static int saa7146_i2c_msg_cleanup(const struct i2c_msg m[], int num, u32 *op)
+static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
 {
 	int i, j;
 	int op_count = 0;
@@ -106,16 +106,16 @@ static int saa7146_i2c_msg_cleanup(const
 			op_count++;
 		}
 	}
-	
+
 	return 0;
 }
 
 /* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
-static int saa7146_i2c_reset(struct saa7146_dev *dev) 
+static int saa7146_i2c_reset(struct saa7146_dev *dev)
 {
 	/* get current status */
 	u32 status = saa7146_i2c_status(dev);
-	
+
 	/* clear registers for sure */
 	saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 	saa7146_write(dev, I2C_TRANSFER, 0);
@@ -135,7 +135,7 @@ static int saa7146_i2c_reset(struct saa7
 		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 		msleep(SAA7146_I2C_DELAY);
- 	}
+	}
 
 	/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
 	status = saa7146_i2c_status(dev);
@@ -160,7 +160,7 @@ static int saa7146_i2c_reset(struct saa7
 		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 		msleep(SAA7146_I2C_DELAY);
-     	}
+	}
 
 	/* if any error is still present, a fatal error has occured ... */
 	status = saa7146_i2c_status(dev);
@@ -272,21 +272,21 @@ static int saa7146_i2c_writeout(struct s
 	return 0;
 }
 
-int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], int num, int retries)
+int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 {
 	int i = 0, count = 0;
 	u32* buffer = dev->d_i2c.cpu_addr;
 	int err = 0;
         int address_err = 0;
         int short_delay = 0;
-	
+
 	if (down_interruptible (&dev->i2c_lock))
 		return -ERESTARTSYS;
 
 	for(i=0;i<num;i++) {
 		DEB_I2C(("msg:%d/%d\n",i+1,num));
 	}
-	
+
 	/* prepare the message(s), get number of u32s to transfer */
 	count = saa7146_i2c_msg_prepare(msgs, num, buffer);
 	if ( 0 > count ) {
@@ -296,14 +296,14 @@ int saa7146_i2c_transfer(struct saa7146_
 
 	if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
 		short_delay = 1;
-  
+
 	do {
 		/* reset the i2c-device if necessary */
 		err = saa7146_i2c_reset(dev);
 		if ( 0 > err ) {
 			DEB_I2C(("could not reset i2c-device.\n"));
 			goto out;
-		}	
+		}
 
 		/* write out the u32s one after another */
 		for(i = 0; i < count; i++) {
@@ -314,10 +314,10 @@ int saa7146_i2c_transfer(struct saa7146_
 				   thinks that an address error occured. in that case, the
 				   transaction should be retrying, even if an address error
 				   occured. analog saa7146 based cards extensively rely on
-				   i2c address probing, however, and address errors indicate that a 
+				   i2c address probing, however, and address errors indicate that a
 				   device is really *not* there. retrying in that case
 				   increases the time the device needs to probe greatly, so
-				   it should be avoided. because of the fact, that only 
+				   it should be avoided. because of the fact, that only
 				   analog based cards use irq based i2c transactions (for dvb
 				   cards, this screwes up other interrupt sources), we bail out
 				   completely for analog cards after an address error and trust
@@ -336,17 +336,17 @@ int saa7146_i2c_transfer(struct saa7146_
 			err = num;
 			break;
 		}
-	        
+
 	        /* delay a bit before retrying */
 	        msleep(10);
-		
+
 	} while (err != num && retries--);
 
         /* if every retry had an address error, exit right away */
         if (address_err == retries) {
 	        goto out;
 	}
-      
+
 	/* if any things had to be read, get the results */
 	if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
 		DEB_I2C(("could not cleanup i2c-message.\n"));
@@ -358,7 +358,7 @@ int saa7146_i2c_transfer(struct saa7146_
 	DEB_I2C(("transmission successful. (msg:%d).\n",err));
 out:
 	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
-	   uploads, so we better clear them out before continueing */	
+	   uploads, so we better clear them out before continueing */
 	if( 0 == dev->revision ) {
 		u32 zero = 0;
 		saa7146_i2c_reset(dev);
@@ -368,14 +368,14 @@ out:
 	}
 
 	up(&dev->i2c_lock);
-	return err;	
+	return err;
 }
 
 /* utility functions */
-static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num)
+static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
 {
 	struct saa7146_dev* dev = i2c_get_adapdata(adapter);
-	
+
 	/* use helper function to transfer data */
 	return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
 }
@@ -396,7 +396,7 @@ static struct i2c_algorithm saa7146_algo
 int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
 {
 	DEB_EE(("bitrate: 0x%08x\n",bitrate));
-	
+
 	/* enable i2c-port pins */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24));
 
@@ -412,10 +412,10 @@ int saa7146_i2c_adapter_prepare(struct s
 #endif
 		i2c_adapter->algo	   = &saa7146_algo;
 		i2c_adapter->algo_data     = NULL;
-		i2c_adapter->id 	   = I2C_ALGO_SAA7146;
+		i2c_adapter->id		   = I2C_ALGO_SAA7146;
 		i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
 		i2c_adapter->retries = SAA7146_I2C_RETRIES;
 	}
-	
+
 	return 0;
 }
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -8,14 +8,14 @@ static int vbi_workaround(struct saa7146
 
         u32          *cpu;
         dma_addr_t   dma_addr;
-	
+
 	int count = 0;
 	int i;
 
 	DECLARE_WAITQUEUE(wait, current);
-	
+
 	DEB_VBI(("dev:%p\n",dev));
-	
+
 	/* once again, a bug in the saa7146: the brs acquisition
 	   is buggy and especially the BXO-counter does not work
 	   as specified. there is this workaround, but please
@@ -29,15 +29,15 @@ static int vbi_workaround(struct saa7146
 	saa7146_write(dev, BASE_EVEN3,	dma_addr);
 	saa7146_write(dev, BASE_ODD3,	dma_addr+vbi_pixel_to_capture);
 	saa7146_write(dev, PROT_ADDR3,	dma_addr+4096);
-	saa7146_write(dev, PITCH3, 	vbi_pixel_to_capture);
+	saa7146_write(dev, PITCH3,	vbi_pixel_to_capture);
 	saa7146_write(dev, BASE_PAGE3,	0x0);
 	saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
 	saa7146_write(dev, MC2, MASK_04|MASK_20);
 
-		/* load brs-control register */
-		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-		/* BXO = 1h, BRS to outbound */
-		WRITE_RPS1(0xc000008c);   
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* BXO = 1h, BRS to outbound */
+	WRITE_RPS1(0xc000008c);
 	/* wait for vbi_a or vbi_b*/
 	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
 		DEB_D(("...using port b\n"));
@@ -50,36 +50,36 @@ static int vbi_workaround(struct saa7146
 		DEB_D(("...using port a\n"));
 		WRITE_RPS1(CMD_PAUSE | MASK_10);
 	}
-		/* upload brs */
-		WRITE_RPS1(CMD_UPLOAD | MASK_08);
-		/* load brs-control register */
-		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-		/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
-		WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
-		/* wait for brs_done */
-		WRITE_RPS1(CMD_PAUSE | MASK_08);
-		/* upload brs */
-		WRITE_RPS1(CMD_UPLOAD | MASK_08);
-		/* load video-dma3 NumLines3 and NumBytes3 */
-		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
-		/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
-		WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
-		/* load brs-control register */
-		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-		/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
-		WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start  
-		/* wait for brs_done */
-		WRITE_RPS1(CMD_PAUSE | MASK_08);
-		/* upload brs and video-dma3*/
-		WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
-		/* load mc2 register: enable dma3 */
-		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
-		WRITE_RPS1(MASK_20 | MASK_04);
-		/* generate interrupt */
-		WRITE_RPS1(CMD_INTERRUPT);
-		/* stop rps1 */
-		WRITE_RPS1(CMD_STOP);
-	
+	/* upload brs */
+	WRITE_RPS1(CMD_UPLOAD | MASK_08);
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
+	WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
+	/* wait for brs_done */
+	WRITE_RPS1(CMD_PAUSE | MASK_08);
+	/* upload brs */
+	WRITE_RPS1(CMD_UPLOAD | MASK_08);
+	/* load video-dma3 NumLines3 and NumBytes3 */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
+	/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
+	WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
+	WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
+	/* wait for brs_done */
+	WRITE_RPS1(CMD_PAUSE | MASK_08);
+	/* upload brs and video-dma3*/
+	WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
+	/* load mc2 register: enable dma3 */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
+	WRITE_RPS1(MASK_20 | MASK_04);
+	/* generate interrupt */
+	WRITE_RPS1(CMD_INTERRUPT);
+	/* stop rps1 */
+	WRITE_RPS1(CMD_STOP);
+
 	/* we have to do the workaround twice to be sure that
 	   everything is ok */
 	for(i = 0; i < 2; i++) {
@@ -89,7 +89,7 @@ static int vbi_workaround(struct saa7146
 
 		saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
 		saa7146_write(dev, MC2, MASK_04|MASK_20);
-	
+
 		/* enable rps1 irqs */
 		SAA7146_IER_ENABLE(dev,MASK_28);
 
@@ -99,12 +99,12 @@ static int vbi_workaround(struct saa7146
 
 		/* start rps1 to enable workaround */
 		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-		saa7146_write(dev, MC1, (MASK_13 | MASK_29));	
-		
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
 		schedule();
 
 		DEB_VBI(("brs bug workaround %d/1.\n",i));
-	
+
 		remove_wait_queue(&vv->vbi_wq, &wait);
 		current->state = TASK_RUNNING;
 
@@ -115,7 +115,7 @@ static int vbi_workaround(struct saa7146
 		saa7146_write(dev, MC1, MASK_20);
 
 		if(signal_pending(current)) {
-		
+
 			DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));
 
 			/* stop rps1 for sure */
@@ -154,6 +154,7 @@ static void saa7146_set_vbi_capture(stru
 	vdma3.pitch	= vbi_pixel_to_capture;
 	vdma3.base_page	= buf->pt[2].dma | ME1;
 	vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
+
 	saa7146_write_out_dma(dev, 3, &vdma3);
 
 	/* write beginning of rps-program */
@@ -165,29 +166,29 @@ static void saa7146_set_vbi_capture(stru
 	   capture and might cause that the first buffer is only half filled (with only
 	   one field). but since this is some sort of streaming data, this is not that negative.
 	   but by doing this, we can use the whole engine from video-buf.c... */
-	
+
 /*
 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
 */
 	/* set bit 1 */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4)); 	
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
 	WRITE_RPS1(MASK_28 | MASK_12);
-	
+
 	/* turn on video-dma3 */
-	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));		
-	WRITE_RPS1(MASK_04 | MASK_20);	    		/* => mask */
+	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
+	WRITE_RPS1(MASK_04 | MASK_20);			/* => mask */
 	WRITE_RPS1(MASK_04 | MASK_20);			/* => values */
-	
+
 	/* wait for o_fid_a/b / e_fid_a/b toggle */
 	WRITE_RPS1(CMD_PAUSE | o_wait);
 	WRITE_RPS1(CMD_PAUSE | e_wait);
 
 	/* generate interrupt */
-	WRITE_RPS1(CMD_INTERRUPT);					
+	WRITE_RPS1(CMD_INTERRUPT);
 
 	/* stop */
-	WRITE_RPS1(CMD_STOP);					
+	WRITE_RPS1(CMD_STOP);
 
 	/* enable rps1 irqs */
 	SAA7146_IER_ENABLE(dev, MASK_28);
@@ -196,7 +197,7 @@ static void saa7146_set_vbi_capture(stru
 	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
 
 	/* turn on rps */
-	saa7146_write(dev, MC1, (MASK_13 | MASK_29));	
+	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
 }
 
 static int buffer_activate(struct saa7146_dev *dev,
@@ -228,12 +229,12 @@ static int buffer_prepare(struct videobu
 	size = lines * llength;
 
 	DEB_VBI(("vb:%p\n",vb));
-	
+
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
 		DEB_VBI(("size mismatch.\n"));
 		return -EINVAL;
 	}
-	
+
 	if (buf->vb.size != size)
 		saa7146_dma_free(dev,buf);
 
@@ -246,7 +247,7 @@ static int buffer_prepare(struct videobu
 		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
 		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
 
-		err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+		err = videobuf_iolock(dev->pci,&buf->vb, NULL);
 		if (err)
 			goto oops;
 		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
@@ -268,7 +269,7 @@ static int buffer_prepare(struct videobu
 static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
 	int llength,lines;
-	
+
 	lines   = 16 * 2 ; /* 2 fields */
 	llength = vbi_pixel_to_capture;
 
@@ -287,7 +288,7 @@ static void buffer_queue(struct videobuf
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-	
+
 	DEB_VBI(("vb:%p\n",vb));
 	saa7146_buffer_queue(dev,&vv->vbi_q,buf);
 }
@@ -298,7 +299,7 @@ static void buffer_release(struct videob
 	struct saa7146_fh *fh   = file->private_data;
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-	
+
 	DEB_VBI(("vb:%p\n",vb));
 	saa7146_dma_free(dev,buf);
 }
@@ -318,7 +319,7 @@ static void vbi_stop(struct saa7146_fh *
 	struct saa7146_vv *vv = dev->vv_data;
 	unsigned long flags;
 	DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
-	
+
 	spin_lock_irqsave(&dev->slock,flags);
 
 	/* disable rps1  */
@@ -349,7 +350,7 @@ static void vbi_read_timeout(unsigned lo
 	struct file *file = (struct file*)data;
 	struct saa7146_fh *fh = file->private_data;
 	struct saa7146_dev *dev = fh->dev;
-	
+
 	DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
 
 	vbi_stop(fh, file);
@@ -372,10 +373,10 @@ static void vbi_init(struct saa7146_dev 
 static int vbi_open(struct saa7146_dev *dev, struct file *file)
 {
 	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
-	
+
 	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
 	int ret = 0;
-	
+
 	DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
 
 	ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
@@ -388,12 +389,12 @@ static int vbi_open(struct saa7146_dev *
 	arbtr_ctrl &= ~0x1f0000;
 	arbtr_ctrl |=  0x1d0000;
 	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
-	saa7146_write(dev, MC2, (MASK_04|MASK_20));		
-	
+	saa7146_write(dev, MC2, (MASK_04|MASK_20));
+
 	memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));
 
 	fh->vbi_fmt.sampling_rate	= 27000000;
-	fh->vbi_fmt.offset		= 248; /* todo */ 
+	fh->vbi_fmt.offset		= 248; /* todo */
 	fh->vbi_fmt.samples_per_line	= vbi_pixel_to_capture;
 	fh->vbi_fmt.sample_format	= V4L2_PIX_FMT_GREY;
 
@@ -428,7 +429,7 @@ static int vbi_open(struct saa7146_dev *
 	}
 
 	/* upload brs register */
-	saa7146_write(dev, MC2, (MASK_08|MASK_24));		
+	saa7146_write(dev, MC2, (MASK_08|MASK_24));
 	return 0;
 }
 
@@ -471,7 +472,7 @@ static ssize_t vbi_read(struct file *fil
 	ssize_t ret = 0;
 
 	DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
-	
+
 	if( NULL == vv->vbi_streaming ) {
 		// fixme: check if dma3 is available
 		// fixme: activate vbi engine here if necessary. (really?)
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -14,64 +14,64 @@ MODULE_PARM_DESC(max_memory, "maximum me
 /* format descriptions for capture and preview */
 static struct saa7146_format formats[] = {
 	{
-		.name 		= "RGB-8 (3-3-2)",
+		.name		= "RGB-8 (3-3-2)",
 		.pixelformat	= V4L2_PIX_FMT_RGB332,
-		.trans 		= RGB08_COMPOSED,
+		.trans		= RGB08_COMPOSED,
 		.depth		= 8,
 		.flags		= 0,
 	}, {
-		.name 		= "RGB-16 (5/B-6/G-5/R)",
+		.name		= "RGB-16 (5/B-6/G-5/R)",
 		.pixelformat	= V4L2_PIX_FMT_RGB565,
-		.trans 		= RGB16_COMPOSED,
+		.trans		= RGB16_COMPOSED,
 		.depth		= 16,
 		.flags		= 0,
 	}, {
-		.name 		= "RGB-24 (B-G-R)",
+		.name		= "RGB-24 (B-G-R)",
 		.pixelformat	= V4L2_PIX_FMT_BGR24,
-		.trans 		= RGB24_COMPOSED,
+		.trans		= RGB24_COMPOSED,
 		.depth		= 24,
 		.flags		= 0,
 	}, {
-		.name 		= "RGB-32 (B-G-R)",
+		.name		= "RGB-32 (B-G-R)",
 		.pixelformat	= V4L2_PIX_FMT_BGR32,
-		.trans 		= RGB32_COMPOSED,
+		.trans		= RGB32_COMPOSED,
 		.depth		= 32,
 		.flags		= 0,
 	}, {
-		.name 		= "RGB-32 (R-G-B)",
+		.name		= "RGB-32 (R-G-B)",
 		.pixelformat	= V4L2_PIX_FMT_RGB32,
-		.trans 		= RGB32_COMPOSED,
+		.trans		= RGB32_COMPOSED,
 		.depth		= 32,
 		.flags		= 0,
 		.swap		= 0x2,
 	}, {
-		.name 		= "Greyscale-8",
+		.name		= "Greyscale-8",
 		.pixelformat	= V4L2_PIX_FMT_GREY,
-		.trans 		= Y8,
+		.trans		= Y8,
 		.depth		= 8,
 		.flags		= 0,
 	}, {
-		.name 		= "YUV 4:2:2 planar (Y-Cb-Cr)",
+		.name		= "YUV 4:2:2 planar (Y-Cb-Cr)",
 		.pixelformat	= V4L2_PIX_FMT_YUV422P,
-		.trans 		= YUV422_DECOMPOSED,
+		.trans		= YUV422_DECOMPOSED,
 		.depth		= 16,
 		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
 	}, {
-		.name 		= "YVU 4:2:0 planar (Y-Cb-Cr)",
+		.name		= "YVU 4:2:0 planar (Y-Cb-Cr)",
 		.pixelformat	= V4L2_PIX_FMT_YVU420,
-		.trans 		= YUV420_DECOMPOSED,
+		.trans		= YUV420_DECOMPOSED,
 		.depth		= 12,
 		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
 	}, {
-		.name 		= "YUV 4:2:0 planar (Y-Cb-Cr)",
+		.name		= "YUV 4:2:0 planar (Y-Cb-Cr)",
 		.pixelformat	= V4L2_PIX_FMT_YUV420,
-		.trans 		= YUV420_DECOMPOSED,
+		.trans		= YUV420_DECOMPOSED,
 		.depth		= 12,
 		.flags		= FORMAT_IS_PLANAR,
 	}, {
-		.name 		= "YUV 4:2:2 (U-Y-V-Y)",
+		.name		= "YUV 4:2:2 (U-Y-V-Y)",
 		.pixelformat	= V4L2_PIX_FMT_UYVY,
-		.trans 		= YUV422_COMPOSED,
+		.trans		= YUV422_COMPOSED,
 		.depth		= 16,
 		.flags		= 0,
 	}
@@ -80,19 +80,19 @@ static struct saa7146_format formats[] =
 /* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
    due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
    (like V4L2_PIX_FMT_YUYV) ... 8-( */
-   
+
 static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
 
 struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
 {
 	int i, j = NUM_FORMATS;
-	
+
 	for (i = 0; i < j; i++) {
 		if (formats[i].pixelformat == fourcc) {
 			return formats+i;
 		}
 	}
-	
+
 	DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc));
 	return NULL;
 }
@@ -182,7 +182,7 @@ static int try_fmt(struct saa7146_fh *fh
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 	int err;
-	
+
 	switch (f->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	{
@@ -201,7 +201,7 @@ static int try_fmt(struct saa7146_fh *fh
 		field = f->fmt.pix.field;
 		maxw  = vv->standard->h_max_out;
 		maxh  = vv->standard->v_max_out;
-		
+
 		if (V4L2_FIELD_ANY == field) {
 			field = (f->fmt.pix.height > maxh/2)
 				? V4L2_FIELD_INTERLACED
@@ -237,10 +237,10 @@ static int try_fmt(struct saa7146_fh *fh
 
 		if (f->fmt.pix.bytesperline < calc_bpl)
 			f->fmt.pix.bytesperline = calc_bpl;
-			
+
 		if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */
 			f->fmt.pix.bytesperline = calc_bpl;
-			
+
 		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
 		DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));
 
@@ -277,36 +277,36 @@ int saa7146_start_preview(struct saa7146
 	if (IS_CAPTURE_ACTIVE(fh) != 0) {
 		DEB_D(("streaming capture is active.\n"));
 		return -EBUSY;
-		}
+	}
 
 	/* check if overlay is running */
-	if (IS_OVERLAY_ACTIVE(fh) != 0) {		
+	if (IS_OVERLAY_ACTIVE(fh) != 0) {
 		if (vv->video_fh == fh) {
-		DEB_D(("overlay is already active.\n"));
-		return 0;
-	}
+			DEB_D(("overlay is already active.\n"));
+			return 0;
+		}
 		DEB_D(("overlay is already active in another open.\n"));
 		return -EBUSY;
 	}
-	
+
 	if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
 		DEB_D(("cannot get necessary overlay resources\n"));
 		return -EBUSY;
-	}	
-	
+	}
+
 	err = try_win(dev,&fh->ov.win);
 	if (0 != err) {
 		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
 		return -EBUSY;
 	}
-	
+
 	vv->ov_data = &fh->ov;
 
 	DEB_D(("%dx%d+%d+%d %s field=%s\n",
 		fh->ov.win.w.width,fh->ov.win.w.height,
 		fh->ov.win.w.left,fh->ov.win.w.top,
 		vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
-	
+
 	if (0 != (ret = saa7146_enable_overlay(fh))) {
 		DEB_D(("enabling overlay failed: %d\n",ret));
 		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
@@ -333,7 +333,7 @@ int saa7146_stop_preview(struct saa7146_
 	}
 
 	/* check if overlay is running at all */
-	if ((vv->video_status & STATUS_OVERLAY) == 0) {		
+	if ((vv->video_status & STATUS_OVERLAY) == 0) {
 		DEB_D(("no active overlay.\n"));
 		return 0;
 	}
@@ -347,7 +347,7 @@ int saa7146_stop_preview(struct saa7146_
 	vv->video_fh = NULL;
 
 	saa7146_disable_overlay(fh);
-	
+
 	saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
 
 	return 0;
@@ -359,7 +359,7 @@ static int s_fmt(struct saa7146_fh *fh, 
 	struct saa7146_vv *vv = dev->vv_data;
 
 	int err;
-	
+
 	switch (f->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
@@ -387,7 +387,7 @@ static int s_fmt(struct saa7146_fh *fh, 
 			up(&dev->lock);
 			return -EFAULT;
 		}
-		
+
 		/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
 		fh->ov.fh = fh;
 
@@ -395,8 +395,8 @@ static int s_fmt(struct saa7146_fh *fh, 
 
 		/* check if our current overlay is active */
 		if (IS_OVERLAY_ACTIVE(fh) != 0) {
-				saa7146_stop_preview(fh);
-				saa7146_start_preview(fh);
+			saa7146_stop_preview(fh);
+			saa7146_start_preview(fh);
 		}
 		return 0;
 	default:
@@ -454,7 +454,7 @@ static int NUM_CONTROLS = sizeof(control
 static struct v4l2_queryctrl* ctrl_by_id(int id)
 {
 	int i;
-	
+
 	for (i = 0; i < NUM_CONTROLS; i++)
 		if (controls[i].id == id)
 			return controls+i;
@@ -515,7 +515,7 @@ static int set_control(struct saa7146_fh
 		DEB_D(("unknown control %d\n",c->id));
 		return -EINVAL;
 	}
-	
+
 	down(&dev->lock);
 
 	switch (ctrl->type) {
@@ -578,10 +578,10 @@ static int set_control(struct saa7146_fh
 	}
 	}
 	up(&dev->lock);
-	
+
 	if (IS_OVERLAY_ACTIVE(fh) != 0) {
-				saa7146_stop_preview(fh);
-				saa7146_start_preview(fh);
+		saa7146_stop_preview(fh);
+		saa7146_start_preview(fh);
 	}
 	return 0;
 }
@@ -633,7 +633,7 @@ static int saa7146_pgtable_build(struct 
 				return -1;
 			}
 		}
-		
+
 		ptr1 = pt1->cpu;
 		ptr2 = pt2->cpu;
 		ptr3 = pt3->cpu;
@@ -649,14 +649,14 @@ static int saa7146_pgtable_build(struct 
 		for(j=0;j<40;j++) {
 			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
 		}
-*/		
+*/
 
 		/* if we have a user buffer, the first page may not be
 		   aligned to a page boundary. */
 		pt1->offset = buf->vb.dma.sglist->offset;
 		pt2->offset = pt1->offset+o1;
 		pt3->offset = pt1->offset+o2;
-		
+
 		/* create video-dma2 page table */
 		ptr1 = pt1->cpu;
 		for(i = m1; i <= m2 ; i++, ptr2++) {
@@ -675,7 +675,7 @@ static int saa7146_pgtable_build(struct 
 		for(;i<1024;i++,ptr3++) {
 			*ptr3 = fill;
 		}
-		/* finally: finish up video-dma1 page table */		
+		/* finally: finish up video-dma1 page table */
 		ptr1 = pt1->cpu+m1;
 		fill = pt1->cpu[m1];
 		for(i=m1;i<1024;i++,ptr1++) {
@@ -694,7 +694,7 @@ static int saa7146_pgtable_build(struct 
 		for(j=0;j<40;j++) {
 			printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
 		}
-*/				
+*/
 	} else {
 		struct saa7146_pgtable *pt = &buf->pt[0];
 		return saa7146_pgtable_build_single(pci, pt, list, length);
@@ -719,9 +719,9 @@ static int video_begin(struct saa7146_fh
 
 	if ((vv->video_status & STATUS_CAPTURE) != 0) {
 		if (vv->video_fh == fh) {
-		DEB_S(("already capturing.\n"));
+			DEB_S(("already capturing.\n"));
 			return 0;
-	}
+		}
 		DEB_S(("already capturing in another open.\n"));
 		return -EBUSY;
 	}
@@ -735,7 +735,7 @@ static int video_begin(struct saa7146_fh
 			return err;
 		}
 	}
-	
+
 	fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
 	/* we need to have a valid format set here */
 	BUG_ON(NULL == fmt);
@@ -811,7 +811,7 @@ static int video_end(struct saa7146_fh *
 	saa7146_write(dev, MC1, dmas);
 
 	spin_unlock_irqrestore(&dev->slock, flags);
-	
+
 	vv->video_fh = NULL;
 	vv->video_status = 0;
 
@@ -820,7 +820,7 @@ static int video_end(struct saa7146_fh *
 	if (vv->ov_suspend != NULL) {
 		saa7146_start_preview(vv->ov_suspend);
 		vv->ov_suspend = NULL;
-}
+	}
 
 	return 0;
 }
@@ -847,7 +847,7 @@ int saa7146_video_do_ioctl(struct inode 
 		if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
 			break;
 	}
-	
+
 	if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
 		DEB_D(("extension handles ioctl exclusive.\n"));
 		result = dev->ext_vv_data->ioctl(fh, cmd, arg);
@@ -860,7 +860,7 @@ int saa7146_video_do_ioctl(struct inode 
 			return result;
 		}
 	}
-	
+
 	/* fixme: add handle "after" case (is it still needed?) */
 
 	switch (fh->type) {
@@ -880,21 +880,21 @@ int saa7146_video_do_ioctl(struct inode 
 	}
 
 	switch (cmd) {
- 	case VIDIOC_QUERYCAP:
+	case VIDIOC_QUERYCAP:
 	{
 		struct v4l2_capability *cap = arg;
 		memset(cap,0,sizeof(*cap));
 
 		DEB_EE(("VIDIOC_QUERYCAP\n"));
-		
+
                 strcpy(cap->driver, "saa7146 v4l2");
 		strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
-		sprintf(cap->bus_info,"PCI:%s",dev->pci->slot_name);
+		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
 		cap->version = SAA7146_VERSION_CODE;
 		cap->capabilities =
 			V4L2_CAP_VIDEO_CAPTURE |
 			V4L2_CAP_VIDEO_OVERLAY |
-			V4L2_CAP_READWRITE | 
+			V4L2_CAP_READWRITE |
 			V4L2_CAP_STREAMING;
 		cap->capabilities |= dev->ext_vv_data->capabilities;
 		return 0;
@@ -925,18 +925,18 @@ int saa7146_video_do_ioctl(struct inode 
 		if (NULL == fmt) {
 			return -EINVAL;
 		}
-		
+
 		/* planar formats are not allowed for overlay video, clipping and video dma would clash */
 		if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
 			DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
 		}
 
 		/* check if overlay is running */
-		if (IS_OVERLAY_ACTIVE(fh) != 0) {		
+		if (IS_OVERLAY_ACTIVE(fh) != 0) {
 			if (vv->video_fh != fh) {
 				DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
 				return -EBUSY;
-		}
+			}
 		}
 
 		down(&dev->lock);
@@ -971,7 +971,7 @@ int saa7146_video_do_ioctl(struct inode 
 			break;
 		}
 		default:
-			return -EINVAL;	
+			return -EINVAL;
 		}
 
 		DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));
@@ -987,12 +987,12 @@ int saa7146_video_do_ioctl(struct inode 
 		    (c->id <  V4L2_CID_PRIVATE_BASE ||
 		     c->id >= V4L2_CID_PRIVATE_LASTP1))
 			return -EINVAL;
-			
+
 		ctrl = ctrl_by_id(c->id);
 		if( NULL == ctrl ) {
 			return -EINVAL;
 /*
-			c->flags = V4L2_CTRL_FLAG_DISABLED;	
+			c->flags = V4L2_CTRL_FLAG_DISABLED;
 			return 0;
 */
 		}
@@ -1006,10 +1006,6 @@ int saa7146_video_do_ioctl(struct inode 
 		return get_control(fh,arg);
 	}
 	case VIDIOC_S_CTRL:
-
-
-
-
 	{
 		DEB_EE(("VIDIOC_S_CTRL\n"));
 		err = set_control(fh,arg);
@@ -1073,7 +1069,7 @@ int saa7146_video_do_ioctl(struct inode 
 		v4l2_std_id *id = arg;
 		int found = 0;
 		int i, err;
-						
+
 		DEB_EE(("VIDIOC_S_STD\n"));
 
 		if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
@@ -1091,7 +1087,7 @@ int saa7146_video_do_ioctl(struct inode 
 		}
 
 		down(&dev->lock);
-		
+
 		for(i = 0; i < dev->ext_vv_data->num_stds; i++)
 			if (*id & dev->ext_vv_data->stds[i].id)
 				break;
@@ -1164,8 +1160,8 @@ int saa7146_video_do_ioctl(struct inode 
 
 		err = video_begin(fh);
 		if( 0 != err) {
-				return err;
-			}
+			return err;
+		}
 		err = videobuf_streamon(q);
 		return err;
 	}
@@ -1190,7 +1186,7 @@ int saa7146_video_do_ioctl(struct inode 
 		err = videobuf_streamoff(q);
 		if (0 != err) {
 			DEB_D(("warning: videobuf_streamoff() failed.\n"));
-		video_end(fh, file);
+			video_end(fh, file);
 		} else {
 			err = video_end(fh, file);
 		}
@@ -1203,9 +1199,9 @@ int saa7146_video_do_ioctl(struct inode 
 		int i;
 
 		/* fixme: number of capture buffers and sizes for v4l apps */
-		int gbuffers = 2; 
+		int gbuffers = 2;
 		int gbufsize = 768*576*4;
-		
+
 		DEB_D(("VIDIOCGMBUF \n"));
 
 		q = &fh->video_q;
@@ -1242,7 +1238,7 @@ static int buffer_activate (struct saa71
 
 	buf->vb.state = STATE_ACTIVE;
 	saa7146_set_capture(dev,buf,next);
-	
+
 	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
 	return 0;
 }
@@ -1273,7 +1269,7 @@ static int buffer_prepare(struct videobu
 		DEB_D(("size mismatch.\n"));
 		return -EINVAL;
 	}
-	
+
 	DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
 		fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field]));
 	if (buf->vb.width  != fh->video_fmt.width  ||
@@ -1288,7 +1284,7 @@ static int buffer_prepare(struct videobu
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
 		struct saa7146_format *sfmt;
-		
+
 		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
 		buf->vb.width  = fh->video_fmt.width;
 		buf->vb.height = fh->video_fmt.height;
@@ -1296,9 +1292,9 @@ static int buffer_prepare(struct videobu
 		buf->vb.field  = field;
 		buf->fmt       = &fh->video_fmt;
 		buf->vb.field  = fh->video_fmt.field;
-		
+
 		sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
-			
+
 		if( 0 != IS_PLANAR(sfmt->trans)) {
 			saa7146_pgtable_free(dev->pci, &buf->pt[0]);
 			saa7146_pgtable_free(dev->pci, &buf->pt[1]);
@@ -1311,7 +1307,7 @@ static int buffer_prepare(struct videobu
 			saa7146_pgtable_free(dev->pci, &buf->pt[0]);
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
 		}
-		
+
 		err = videobuf_iolock(dev->pci,&buf->vb, &vv->ov_fb);
 		if (err)
 			goto oops;
@@ -1345,7 +1341,7 @@ static int buffer_setup(struct videobuf_
 	if( (*count * *size) > (max_memory*1048576) ) {
 		*count = (max_memory*1048576) / *size;
 	}
-	
+
 	DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size));
 
 	return 0;
@@ -1358,7 +1354,7 @@ static void buffer_queue(struct videobuf
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-	
+
 	DEB_CAP(("vbuf:%p\n",vb));
 	saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
 }
@@ -1370,7 +1366,7 @@ static void buffer_release(struct videob
 	struct saa7146_fh *fh = file->private_data;
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-	
+
 	DEB_CAP(("vbuf:%p\n",vb));
 	saa7146_dma_free(dev,buf);
 }
@@ -1434,13 +1430,13 @@ static void video_close(struct saa7146_d
 	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
 	struct saa7146_vv *vv = dev->vv_data;
 	int err;
-	
+
 	if (IS_CAPTURE_ACTIVE(fh) != 0) {
-		err = video_end(fh, file);		
+		err = video_end(fh, file);
 	} else if (IS_OVERLAY_ACTIVE(fh) != 0) {
 		err = saa7146_stop_preview(fh);
 	}
-	
+
 	/* hmm, why is this function declared void? */
 	/* return err */
 }
@@ -1450,7 +1446,7 @@ static void video_irq_done(struct saa714
 {
 	struct saa7146_vv *vv = dev->vv_data;
 	struct saa7146_dmaqueue *q = &vv->video_q;
-	
+
 	spin_lock(&dev->slock);
 	DEB_CAP(("called.\n"));
 
@@ -1473,11 +1469,11 @@ static ssize_t video_read(struct file *f
 	DEB_EE(("called.\n"));
 
 	if ((vv->video_status & STATUS_CAPTURE) != 0) {
-	/* fixme: should we allow read() captures while streaming capture? */
+		/* fixme: should we allow read() captures while streaming capture? */
 		if (vv->video_fh == fh) {
-		DEB_S(("already capturing.\n"));
-		return -EBUSY;
-	}
+			DEB_S(("already capturing.\n"));
+			return -EBUSY;
+		}
 		DEB_S(("already capturing in another open.\n"));
 		return -EBUSY;
 	}
@@ -1487,10 +1483,10 @@ static ssize_t video_read(struct file *f
 		goto out;
 	}
 
-	ret = videobuf_read_one(&fh->video_q, data, count, ppos,
+	ret = videobuf_read_one(&fh->video_q , data, count, ppos,
 				file->f_flags & O_NONBLOCK);
 	if (ret != 0) {
-	video_end(fh, file);
+		video_end(fh, file);
 	} else {
 		ret = video_end(fh, file);
 	}
@@ -1500,7 +1496,7 @@ out:
 		saa7146_start_preview(vv->ov_suspend);
 		vv->ov_suspend = NULL;
 	}
-	
+
 	return ret;
 }
 
diff --git a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c
--- a/drivers/media/common/saa7146_vv_ksyms.c
+++ b/drivers/media/common/saa7146_vv_ksyms.c
@@ -1,9 +1,6 @@
 #include <linux/module.h>
 #include <media/saa7146_vv.h>
 
-EXPORT_SYMBOL_GPL(saa7146_vbi_uops);
-EXPORT_SYMBOL_GPL(saa7146_video_uops);
-
 EXPORT_SYMBOL_GPL(saa7146_start_preview);
 EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -8,13 +8,13 @@ config DVB
 	bool "DVB For Linux"
 	depends on NET && INET
 	---help---
-	  Support Digital Video Broadcasting hardware.  Enable this if you 
-	  own a DVB adapter and want to use it or if you compile Linux for 
+	  Support Digital Video Broadcasting hardware.  Enable this if you
+	  own a DVB adapter and want to use it or if you compile Linux for
 	  a digital SetTopBox.
 
 	  API specs and user tools are available from <http://www.linuxtv.org/>.
 
-	  Please report problems regarding this driver to the LinuxDVB 
+	  Please report problems regarding this driver to the LinuxDVB
 	  mailing list.
 
 	  If unsure say N.
@@ -33,7 +33,7 @@ source "drivers/media/dvb/dibusb/Kconfig
 source "drivers/media/dvb/cinergyT2/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
-	depends on DVB_CORE && PCI
+	depends on DVB_CORE && (PCI || USB)
 source "drivers/media/dvb/b2c2/Kconfig"
 
 comment "Supported BT878 Adapters"
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,26 +1,50 @@
-config DVB_B2C2_SKYSTAR
-	tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
-	depends on DVB_CORE && PCI
+config DVB_B2C2_FLEXCOP
+	tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
+	depends on DVB_CORE
 	select DVB_STV0299
 	select DVB_MT352
 	select DVB_MT312
 	select DVB_NXT2002
+	select DVB_STV0297
 	help
-	  Support for the Skystar2 PCI DVB card by Technisat, which
-	  is equipped with the FlexCopII chipset by B2C2, and
-	  for the B2C2/BBTI Air2PC-ATSC card.
+	  Support for the digital TV receiver chip made by B2C2 Inc. included in
+	  Technisats PCI cards and USB boxes.
 
 	  Say Y if you own such a device and want to use it.
 
-config DVB_B2C2_USB
-	tristate "B2C2/Technisat Air/Sky/Cable2PC USB"
-	depends on DVB_CORE && USB && EXPERIMENTAL
+config DVB_B2C2_FLEXCOP_PCI
+	tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
+	depends on DVB_B2C2_FLEXCOP && PCI
+	help
+	  Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_USB
+	tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
+	depends on DVB_B2C2_FLEXCOP && USB
+	help
+	  Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_DEBUG
+	bool "Enable debug for the B2C2 FlexCop drivers"
+	depends on DVB_B2C2_FLEXCOP
+	help
+	  Say Y if you want to enable the module option to control debug messages
+	  of all B2C2 FlexCop drivers.
+
+config DVB_B2C2_SKYSTAR
+	tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
+	depends on DVB_CORE && PCI
 	select DVB_STV0299
 	select DVB_MT352
+	select DVB_MT312
+	select DVB_NXT2002
 	help
-	  Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently
-	  the does nothing, but providing basic function for the used usb 
-	  protocol.
+	  Support for the Skystar2 PCI DVB card by Technisat, which
+	  is equipped with the FlexCopII chipset by B2C2, and
+	  for the B2C2/BBTI Air2PC-ATSC card.
 
 	  Say Y if you own such a device and want to use it.
-
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -1,6 +1,14 @@
-obj-b2c2-usb = b2c2-usb-core.o b2c2-common.o
+b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
+	flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \
+	flexcop-dma.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+b2c2-flexcop-pci-objs = flexcop-pci.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
+
+b2c2-flexcop-usb-objs = flexcop-usb.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
 obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-obj-$(CONFIG_DVB_B2C2_USB) + = b2c2-usb.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/b2c2-common.c b/drivers/media/dvb/b2c2/b2c2-common.c
deleted file mode 100644
--- a/drivers/media/dvb/b2c2/b2c2-common.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * b2c2-common.c - common methods for the B2C2/Technisat SkyStar2 PCI DVB card and
- *                 for the B2C2/Technisat Sky/Cable/AirStar USB devices
- *                 based on the FlexCopII/FlexCopIII by B2C2, Inc.
- *
- * Copyright (C) 2003  Vadim Catana, skystar@moldova.cc
- *
- * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
- *     Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
- * Converted to Linux coding style
- * Misc reorganization, polishing, restyling
- *     Roberto Ragusa, r.ragusa at libero.it
- *
- * Added hardware filtering support,
- *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
- *
- * This program 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.
- *
- * 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 Lesser 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 "stv0299.h"
-#include "mt352.h"
-#include "mt312.h"
-
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg (fe, 0x13, aclk);
-	stv0299_writereg (fe, 0x14, bclk);
-	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-//	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	div = params->frequency / 125;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x84;  // 0xC4
-	buf[3] = 0x08;
-
-	if (params->frequency < 1500000) buf[3] |= 0x10;
-
-//	if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
-	     0x01, 0x15,
-	     0x02, 0x30,
-	     0x03, 0x00,
-	     0x04, 0x7D,
-	     0x05, 0x35,
-	     0x06, 0x02,
-	     0x07, 0x00,
-	     0x08, 0xC3,
-	     0x0C, 0x00,
-	     0x0D, 0x81,
-	     0x0E, 0x23,
-	     0x0F, 0x12,
-	     0x10, 0x7E,
-	     0x11, 0x84,
-	     0x12, 0xB9,
-	     0x13, 0x88,
-	     0x14, 0x89,
-	     0x15, 0xC9,
-	     0x16, 0x00,
-	     0x17, 0x5C,
-	     0x18, 0x00,
-	     0x19, 0x00,
-	     0x1A, 0x00,
-	     0x1C, 0x00,
-	     0x1D, 0x00,
-	     0x1E, 0x00,
-	     0x1F, 0x3A,
-	     0x20, 0x2E,
-	     0x21, 0x80,
-	     0x22, 0xFF,
-	     0x23, 0xC1,
-	     0x28, 0x00,
-	     0x29, 0x1E,
-	     0x2A, 0x14,
-	     0x2B, 0x0F,
-	     0x2C, 0x09,
-	     0x2D, 0x05,
-	     0x31, 0x1F,
-	     0x32, 0x19,
-	     0x33, 0xFE,
-	     0x34, 0x93,
-	     0xff, 0xff,
-};
-
-static struct stv0299_config samsung_tbmu24112_config = {
-	.demod_address = 0x68,
-	.inittab = samsung_tbmu24112_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.enhanced_tuning = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_LK,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-   	.pll_set = samsung_tbmu24112_pll_set,
-};
-
-
-
-
-
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
-	static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
-	static u8 mt352_reset [] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-	return 0;
-}
-
-int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
-{
-	u32 div;
-	unsigned char bs = 0;
-
-	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
-	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
-	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
-
-	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
-	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = 0xcc;
-   	pllbuf[4] = bs;
-
-	return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-
-	.demod_address = 0x0f,
-	.demod_init = samsung_tdtc9251dh0_demod_init,
-   	.pll_set = samsung_tdtc9251dh0_pll_set,
-};
-
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-//	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	div = (params->frequency + (125/2)) / 125;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = (div >> 0) & 0xff;
-	buf[2] = 0x84 | ((div >> 10) & 0x60);
-	buf[3] = 0x80;
-
-	if (params->frequency < 1550000)
-		buf[3] |= 0x02;
-
-	//if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
-	.demod_address = 0x0e,
-   	.pll_set = skystar23_samsung_tbdu18132_pll_set,
-};
diff --git a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c
deleted file mode 100644
--- a/drivers/media/dvb/b2c2/b2c2-usb-core.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * Copyright (C) 2004 Patrick Boettcher <patrick.boettcher@desy.de>,
- *                    Luca Bertagnolio <>,
- *
- * based on information provided by John Jurrius from BBTI, 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, version 2.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/version.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-#include "dvb_frontend.h"
-
-/* debug */
-#define dprintk(level,args...) \
-	    do { if ((debug & level)) { printk(args); } } while (0)
-#define debug_dump(b,l) if (debug) {\
-	int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
-	for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
-	deb_xfer("\n");\
-}
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able)).");
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_ts(args...)   dprintk(0x02,args)
-#define deb_ctrl(args...) dprintk(0x04,args)
-
-/* Version information */
-#define DRIVER_VERSION "0.0"
-#define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-/* transfer parameters */
-#define B2C2_USB_FRAMES_PER_ISO		4
-#define B2C2_USB_NUM_ISO_URB		4    /* TODO check out a good value */
-
-#define B2C2_USB_CTRL_PIPE_IN		usb_rcvctrlpipe(b2c2->udev,0)
-#define B2C2_USB_CTRL_PIPE_OUT		usb_sndctrlpipe(b2c2->udev,0)
-#define B2C2_USB_DATA_PIPE			usb_rcvisocpipe(b2c2->udev,0x81)
-
-struct usb_b2c2_usb {
-	struct usb_device *udev;
-	struct usb_interface *uintf;
-
-	u8 *iso_buffer;
-	int buffer_size;
-	dma_addr_t iso_dma_handle;
-	struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
-};
-
-
-/*
- * USB
- * 10 90 34 12 78 56 04 00
- * usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- * 0x90,
- * 0x10,
- * 0x1234,
- * 0x5678,
- * buf,
- * 4,
- * 5*HZ);
- *
- * 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);
- *
- */
-
-/* request types */
-typedef enum {
-
-/* something is wrong with this part
-	RTYPE_READ_DW         = (1 << 6),
-	RTYPE_WRITE_DW_1      = (3 << 6),
-	RTYPE_READ_V8_MEMORY  = (6 << 6),
-	RTYPE_WRITE_V8_MEMORY = (7 << 6),
-	RTYPE_WRITE_V8_FLASH  = (8 << 6),
-	RTYPE_GENERIC         = (9 << 6),
-*/
-	RTYPE_READ_DW = (3 << 6),
-	RTYPE_WRITE_DW_1 = (1 << 6),
-	
-	RTYPE_READ_V8_MEMORY  = (6 << 6),
-	RTYPE_WRITE_V8_MEMORY = (7 << 6),
-	RTYPE_WRITE_V8_FLASH  = (8 << 6),
-	RTYPE_GENERIC         = (9 << 6),
-} b2c2_usb_request_type_t;
-
-/* request */
-typedef enum {
-	B2C2_USB_WRITE_V8_MEM = 0x04,
-	B2C2_USB_READ_V8_MEM  = 0x05,
-	B2C2_USB_READ_REG     = 0x08,
-	B2C2_USB_WRITE_REG    = 0x0A,
-/*	B2C2_USB_WRITEREGLO   = 0x0A, */
-	B2C2_USB_WRITEREGHI   = 0x0B,
-	B2C2_USB_FLASH_BLOCK  = 0x10,
-	B2C2_USB_I2C_REQUEST  = 0x11,
-	B2C2_USB_UTILITY      = 0x12,
-} b2c2_usb_request_t;
-
-/* function definition for I2C_REQUEST */
-typedef enum {
-	USB_FUNC_I2C_WRITE       = 0x01,
-	USB_FUNC_I2C_MULTIWRITE  = 0x02,
-	USB_FUNC_I2C_READ        = 0x03,
-	USB_FUNC_I2C_REPEATWRITE = 0x04,
-	USB_FUNC_GET_DESCRIPTOR  = 0x05,
-	USB_FUNC_I2C_REPEATREAD  = 0x06,
-/* DKT 020208 - add this to support special case of DiSEqC */
-	USB_FUNC_I2C_CHECKWRITE  = 0x07,
-	USB_FUNC_I2C_CHECKRESULT = 0x08,
-} b2c2_usb_i2c_function_t;
-
-/*
- * function definition for UTILITY request 0x12
- * DKT 020304 - new utility function
- */
-typedef enum {
-	UTILITY_SET_FILTER          = 0x01,
-	UTILITY_DATA_ENABLE         = 0x02,
-	UTILITY_FLEX_MULTIWRITE     = 0x03,
-	UTILITY_SET_BUFFER_SIZE     = 0x04,
-	UTILITY_FLEX_OPERATOR       = 0x05,
-	UTILITY_FLEX_RESET300_START = 0x06,
-	UTILITY_FLEX_RESET300_STOP  = 0x07,
-	UTILITY_FLEX_RESET300       = 0x08,
-	UTILITY_SET_ISO_SIZE        = 0x09,
-	UTILITY_DATA_RESET          = 0x0A,
-	UTILITY_GET_DATA_STATUS     = 0x10,
-	UTILITY_GET_V8_REG          = 0x11,
-/* DKT 020326 - add function for v1.14 */
-	UTILITY_SRAM_WRITE          = 0x12,
-	UTILITY_SRAM_READ           = 0x13,
-	UTILITY_SRAM_TESTFILL       = 0x14,
-	UTILITY_SRAM_TESTSET        = 0x15,
-	UTILITY_SRAM_TESTVERIFY     = 0x16,
-} b2c2_usb_utility_function_t;
-
-#define B2C2_WAIT_FOR_OPERATION_RW  1  // 1 s
-#define B2C2_WAIT_FOR_OPERATION_RDW 3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_WDW 1  // 1 s
-
-#define B2C2_WAIT_FOR_OPERATION_V8READ   3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_V8WRITE  3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_V8FLASH  3  // 3 s
-
-/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
- * in the IBI address, to make the V8 code simpler.
- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
- *                  in general: 0000 0HHH 000L LL00
- * IBI ADDRESS FORMAT:                    RHHH BLLL
- *
- * where R is the read(1)/write(0) bit, B is the busy bit
- * and HHH and LLL are the two sets of three bits from the PCI address.
- */
-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
-
-/*
- * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register
- * deal with DWORD or 4 bytes, that should be should from now on
- */
-static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI)
-{
-	u32 val;
-	u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080;
-	int len = usb_control_msg(b2c2->udev,
-			B2C2_USB_CTRL_PIPE_IN,
-			B2C2_USB_READ_REG,
-			RTYPE_READ_DW,
-			wAddress,
-			0,
-			&val,
-			sizeof(u32),
-			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
-
-	if (len != sizeof(u32)) {
-		err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
-		return -EIO;
-	} else
-		return val;
-}
-
-/*
- * DKT 020228 - from now on, we don't support anything older than firm 1.00
- * I eliminated the write register as a 2 trip of writing hi word and lo word
- * and force this to write only 4 bytes at a time.
- * NOTE: this should work with all the firmware from 1.00 and newer
- */
-static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val)
-{
-	u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI);
-	int len = usb_control_msg(b2c2->udev,
-			B2C2_USB_CTRL_PIPE_OUT,
-			B2C2_USB_WRITE_REG,
-			RTYPE_WRITE_DW_1,
-			wAddress,
-			0,
-			&val,
-			sizeof(u32),
-			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
-
-	if (len != sizeof(u32)) {
-		err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
-		return -EIO;
-	} else
-		return 0;
-}
-
-/*
- * DKT 010817 - add support for V8 memory read/write and flash update
- */
-static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2,
-		b2c2_usb_request_t req, u8 page, u16 wAddress,
-		u16 buflen, u8 *pbBuffer)
-{
-	u8 dwRequestType;
-	u16 wIndex;
-	int nWaitTime,pipe,len;
-
-	wIndex = page << 8;
-
-	switch (req) {
-		case B2C2_USB_READ_V8_MEM:
-			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
-			dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
-			pipe = B2C2_USB_CTRL_PIPE_IN;
-		break;
-		case B2C2_USB_WRITE_V8_MEM:
-			wIndex |= pbBuffer[0];
-			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
-			dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
-			pipe = B2C2_USB_CTRL_PIPE_OUT;
-		break;
-		case B2C2_USB_FLASH_BLOCK:
-			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
-			dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
-			pipe = B2C2_USB_CTRL_PIPE_OUT;
-		break;
-		default:
-			deb_info("unsupported request for v8_mem_req %x.\n",req);
-		return -EINVAL;
-	}
-	len = usb_control_msg(b2c2->udev,pipe,
-			req,
-			dwRequestType,
-			wAddress,
-			wIndex,
-			pbBuffer,
-			buflen,
-			nWaitTime * HZ);
-	return len == buflen ? 0 : -EIO;
-}
-
-static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2,
-		b2c2_usb_request_t req, b2c2_usb_i2c_function_t func,
-		u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf)
-{
-	u16 wValue, wIndex;
-	int nWaitTime,pipe,len;
-	u8 dwRequestType;
-
-	switch (func) {
-		case USB_FUNC_I2C_WRITE:
-		case USB_FUNC_I2C_MULTIWRITE:
-		case USB_FUNC_I2C_REPEATWRITE:
-		/* DKT 020208 - add this to support special case of DiSEqC */
-		case USB_FUNC_I2C_CHECKWRITE:
-			pipe = B2C2_USB_CTRL_PIPE_OUT;
-			nWaitTime = 2;
-			dwRequestType = (u8) RTYPE_GENERIC;
-		break;
-		case USB_FUNC_I2C_READ:
-		case USB_FUNC_I2C_REPEATREAD:
-			pipe = B2C2_USB_CTRL_PIPE_IN;
-			nWaitTime = 2;
-			dwRequestType = (u8) RTYPE_GENERIC;
-		break;
-		default:
-			deb_info("unsupported function for i2c_req %x\n",func);
-			return -EINVAL;
-	}
-	wValue = (func << 8 ) | port;
-	wIndex = (chipaddr << 8 ) | addr;
-
-	len = usb_control_msg(b2c2->udev,pipe,
-			req,
-			dwRequestType,
-			addr,
-			wIndex,
-			buf,
-			buflen,
-			nWaitTime * HZ);
-	return len == buflen ? 0 : -EIO;
-}
-
-int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set,
-		b2c2_usb_utility_function_t func, u8 extra, u16 wIndex,
-		u16 buflen, u8 *pvBuffer)
-{
-	u16 wValue;
-	int nWaitTime = 2,
-		pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
-		len;
-
-	wValue = (func << 8) | extra;
-
-	len = usb_control_msg(b2c2->udev,pipe,
-			B2C2_USB_UTILITY,
-			(u8) RTYPE_GENERIC,
-			wValue,
-			wIndex,
-			pvBuffer,
-			buflen,
-			nWaitTime * HZ);
-	return len == buflen ? 0 : -EIO;
-}
-
-
-
-static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs)
-{
-	u32 r0,r1,r2,r3;
-	r0 = r1 = r2 = r3 = 0;
-	r0 = b2c2_usb_read_dw(b2c2,offs);
-	r1 = b2c2_usb_read_dw(b2c2,offs + 0x04);
-	r2 = b2c2_usb_read_dw(b2c2,offs + 0x08);
-	r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c);
-	deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3);
-}
-
-static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
-	struct usb_b2c2_usb *b2c2 = urb->context;
-	deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length);
-
-//	urb_submit_urb(urb,GFP_ATOMIC); enable for real action
-}
-
-static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2)
-{
-	int i;
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-		if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */
-			deb_info("unlinking/killing urb no. %d\n",i);
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
-			usb_unlink_urb(b2c2->iso_urb[i]);
-#else
-			usb_kill_urb(b2c2->iso_urb[i]);
-#endif
-			usb_free_urb(b2c2->iso_urb[i]);
-		}
-
-	if (b2c2->iso_buffer != NULL)
-		pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle);
-
-}
-
-static int b2c2_init_usb(struct usb_b2c2_usb *b2c2)
-{
-	u16 frame_size = le16_to_cpu(b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
-	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
-	int buffer_offset = 0;
-
-	deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
-			B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
-
-	b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle);
-	if (b2c2->iso_buffer == NULL)
-		return -ENOMEM;
-	memset(b2c2->iso_buffer, 0, bufsize);
-	b2c2->buffer_size = bufsize;
-
-	/* creating iso urbs */
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-		if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
-			ret = -ENOMEM;
-			goto urb_error;
-		}
-	/* initialising and submitting iso urbs */
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
-		int frame_offset = 0;
-		struct urb *urb = b2c2->iso_urb[i];
-		deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
-
-		urb->dev = b2c2->udev;
-		urb->context = b2c2;
-		urb->complete = b2c2_urb_complete;
-		urb->pipe = B2C2_USB_DATA_PIPE;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->interval = 1;
-		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
-		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
-		urb->transfer_buffer = b2c2->iso_buffer + buffer_offset;
-
-		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
-		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
-			deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
-			urb->iso_frame_desc[j].offset = frame_offset;
-			urb->iso_frame_desc[j].length = frame_size;
-			frame_offset += frame_size;
-		}
-
-		if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) {
-			err("submitting urb %d failed with %d.",i,ret);
-			goto urb_error;
-		}
-		deb_info("submitted urb no. %d.\n",i);
-	}
-
-	ret = 0;
-	goto success;
-urb_error:
-	b2c2_exit_usb(b2c2);
-success:
-	return ret;
-}
-
-static int b2c2_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_b2c2_usb *b2c2 = NULL;
-	int ret;
-
-	b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL);
-	if (b2c2 == NULL) {
-		err("no memory");
-		return -ENOMEM;
-	}
-	b2c2->udev = udev;
-	b2c2->uintf = intf;
-
-	/* use the alternate setting with the larges buffer */
-	usb_set_interface(udev,0,1);
-
-	if ((ret = b2c2_init_usb(b2c2)))
-		goto usb_init_error;
-
-	usb_set_intfdata(intf,b2c2);
-
-	switch (udev->speed) {
-		case USB_SPEED_LOW:
-			err("cannot handle USB speed because it is to sLOW.");
-			break;
-		case USB_SPEED_FULL:
-			info("running at FULL speed.");
-			break;
-		case USB_SPEED_HIGH:
-			info("running at HIGH speed.");
-			break;
-		case USB_SPEED_UNKNOWN: /* fall through */
-		default:
-			err("cannot handle USB speed because it is unkown.");
-		break;
-	}
-
-	b2c2_dumpfourreg(b2c2,0x200);
-	b2c2_dumpfourreg(b2c2,0x300);
-	b2c2_dumpfourreg(b2c2,0x400);
-	b2c2_dumpfourreg(b2c2,0x700);
-
-
-	if (ret == 0)
-		info("%s successfully initialized and connected.",DRIVER_DESC);
-	else
-		info("%s error while loading driver (%d)",DRIVER_DESC,ret);
-
-	ret = 0;
-	goto success;
-
-usb_init_error:
-	kfree(b2c2);
-success:
-	return ret;
-}
-
-static void b2c2_usb_disconnect(struct usb_interface *intf)
-{
-	struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf);
-	usb_set_intfdata(intf,NULL);
-	if (b2c2 != NULL) {
-		b2c2_exit_usb(b2c2);
-		kfree(b2c2);
-	}
-	info("%s successfully deinitialized and disconnected.",DRIVER_DESC);
-
-}
-
-static struct usb_device_id b2c2_usb_table [] = {
-	    { USB_DEVICE(0x0af7, 0x0101) }
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver b2c2_usb_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "dvb_b2c2_usb",
-	.probe 		= b2c2_usb_probe,
-	.disconnect = b2c2_usb_disconnect,
-	.id_table 	= b2c2_usb_table,
-};
-
-/* module stuff */
-static int __init b2c2_usb_init(void)
-{
-	int result;
-	if ((result = usb_register(&b2c2_usb_driver))) {
-		err("usb_register failed. Error number %d",result);
-		return result;
-	}
-
-	return 0;
-}
-
-static void __exit b2c2_usb_exit(void)
-{
-	/* deregister this driver from the USB subsystem */
-	usb_deregister(&b2c2_usb_driver);
-}
-
-module_init (b2c2_usb_init);
-module_exit (b2c2_usb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -0,0 +1,164 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-common.h - common header file for device-specific source files also.
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_COMMON_H__
+#define __FLEXCOP_COMMON_H__
+
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#include "flexcop-reg.h"
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#define FC_MAX_FEED 256
+
+#ifndef FC_LOG_PREFIX
+#warning please define a log prefix for your file, using a default one
+#define FC_LOG_PREFIX "b2c2-undef"
+#endif
+
+/* Steal from usb.h */
+#undef err
+#define err(format,  arg...) printk(KERN_ERR     FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+
+struct flexcop_dma {
+	struct pci_dev *pdev;
+
+	u8 *cpu_addr0;
+	dma_addr_t dma_addr0;
+	u8 *cpu_addr1;
+	dma_addr_t dma_addr1;
+	u32 size; /* size of each address in bytes */
+};
+
+/* Control structure for data definitions that are common to
+ * the B2C2-based PCI and USB devices.
+ */
+struct flexcop_device {
+	/* general */
+	struct device *dev; /* for firmware_class */
+
+#define FC_STATE_DVB_INIT 0x01
+#define FC_STATE_I2C_INIT 0x02
+#define FC_STATE_FE_INIT  0x04
+	int init_state;
+
+	/* device information */
+	int has_32_hw_pid_filter;
+	flexcop_revision_t rev;
+	flexcop_device_type_t dev_type;
+	flexcop_bus_t bus_type;
+
+	/* dvb stuff */
+	struct dvb_adapter dvb_adapter;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	int (*fe_sleep) (struct dvb_frontend *);
+
+	struct i2c_adapter i2c_adap;
+	struct semaphore i2c_sem;
+
+	struct module *owner;
+
+	/* options and status */
+	int extra_feedcount;
+	int feedcount;
+	int pid_filtering;
+	int fullts_streaming_state;
+
+	/* bus specific callbacks */
+	flexcop_ibi_value (*read_ibi_reg)  (struct flexcop_device *, flexcop_ibi_register);
+	int               (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
+
+
+	int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+	int (*stream_control) (struct flexcop_device*, int);
+
+	int (*get_mac_addr) (struct flexcop_device *fc, int extended);
+
+	void *bus_specific;
+};
+
+/* exported prototypes */
+
+/* from flexcop.c */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
+void flexcop_device_kfree(struct flexcop_device*);
+
+int  flexcop_device_initialize(struct flexcop_device*);
+void flexcop_device_exit(struct flexcop_device *fc);
+
+/* from flexcop-dma.c */
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
+void flexcop_dma_free(struct flexcop_dma *dma);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
+
+/* from flexcop-eeprom.c */
+/* the PCI part uses this call to get the MAC address, the USB part has its own */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
+
+/* from flexcop-i2c.c */
+/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
+ * one. We have it in flexcop-i2c.c, because it is going via the actual
+ * I2C-channel of the flexcop.
+ */
+int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
+		        flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+
+/* from flexcop-sram.c */
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
+
+/* global prototypes for the flexcop-chip */
+/* from flexcop-fe-tuner.c */
+int flexcop_frontend_init(struct flexcop_device *card);
+void flexcop_frontend_exit(struct flexcop_device *fc);
+
+/* from flexcop-i2c.c */
+int flexcop_i2c_init(struct flexcop_device *fc);
+void flexcop_i2c_exit(struct flexcop_device *fc);
+
+/* from flexcop-sram.c */
+int flexcop_sram_init(struct flexcop_device *fc);
+
+/* from flexcop-misc.c */
+void flexcop_determine_revision(struct flexcop_device *fc);
+void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+
+/* from flexcop-hw-filter.c */
+int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
+void flexcop_hw_filter_init(struct flexcop_device *fc);
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
+{
+	u8 *tcpu;
+	dma_addr_t tdma;
+
+	if (size % 2) {
+		err("dma buffersize has to be even.");
+		return -EINVAL;
+	}
+
+	if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+		dma->pdev = pdev;
+		dma->cpu_addr0 = tcpu;
+		dma->dma_addr0 = tdma;
+		dma->cpu_addr1 = tcpu + size/2;
+		dma->dma_addr1 = tdma + size/2;
+		dma->size = size/2;
+		return 0;
+	}
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(flexcop_dma_allocate);
+
+void flexcop_dma_free(struct flexcop_dma *dma)
+{
+	pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
+	memset(dma,0,sizeof(struct flexcop_dma));
+}
+EXPORT_SYMBOL(flexcop_dma_free);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_size_irq);
+
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+{
+
+	flexcop_ibi_value v0x0,v0x4,v0xc;
+	v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+	v0x0.dma_0x0.dma_address0        = dma->dma_addr0 >> 2;
+	v0xc.dma_0xc.dma_address1        = dma->dma_addr1 >> 2;
+	v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+	if (index & FC_DMA_SUBADDR_0)
+		v0x0.dma_0x0.dma_0start = 1;
+
+	if (index & FC_DMA_SUBADDR_1)
+		v0xc.dma_0xc.dma_1start = 1;
+
+	if (dma_idx & FC_DMA_1) {
+		fc->write_ibi_reg(fc,dma1_000,v0x0);
+		fc->write_ibi_reg(fc,dma1_004,v0x4);
+		fc->write_ibi_reg(fc,dma1_00c,v0xc);
+	} else { /* (dma_idx & FC_DMA_2) */
+		fc->write_ibi_reg(fc,dma2_010,v0x0);
+		fc->write_ibi_reg(fc,dma2_014,v0x4);
+		fc->write_ibi_reg(fc,dma2_01c,v0xc);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config);
+
+static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+	v.dma_0xc.remap_enable = onoff;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+	flexcop_dma_remap(fc,dma_idx,0);
+
+	v.dma_0x4_write.dmatimer = cycles >> 1;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+	flexcop_dma_remap(fc,dma_idx,1);
+
+	v.dma_0x4_remap.DMA_maxpackets = packets;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_packet_count);
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c
@@ -0,0 +1,153 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#if 0
+/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
+static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+{
+	return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
+{
+	int i;
+
+	for (i = 0; i < retries; i++) {
+		if (eeprom_write(adapter, addr, wbuf, len) == len) {
+			if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* These functions could be used to unlock SkyStar2 cards. */
+
+static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+{
+	u8 rbuf[20];
+	u8 wbuf[20];
+
+	if (len != 16)
+		return 0;
+
+	memcpy(wbuf, key, len);
+
+	wbuf[16] = 0;
+	wbuf[17] = 0;
+	wbuf[18] = 0;
+	wbuf[19] = calc_lrc(wbuf, 19);
+
+	return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+}
+
+static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+{
+	u8 buf[20];
+
+	if (len != 16)
+		return 0;
+
+	if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
+		return 0;
+
+	memcpy(key, buf, len);
+
+	return 1;
+}
+
+static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+{
+	u8 tmp[8];
+
+	if (type != 0) {
+		tmp[0] = mac[0];
+		tmp[1] = mac[1];
+		tmp[2] = mac[2];
+		tmp[3] = mac[5];
+		tmp[4] = mac[6];
+		tmp[5] = mac[7];
+
+	} else {
+
+		tmp[0] = mac[0];
+		tmp[1] = mac[1];
+		tmp[2] = mac[2];
+		tmp[3] = mac[3];
+		tmp[4] = mac[4];
+		tmp[5] = mac[5];
+	}
+
+	tmp[6] = 0;
+	tmp[7] = calc_lrc(tmp, 7);
+
+	if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+		return 1;
+
+	return 0;
+}
+
+static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
+{
+	return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+}
+
+#endif
+
+static u8 calc_lrc(u8 *buf, int len)
+{
+	int i;
+	u8 sum = 0;
+	for (i = 0; i < len; i++)
+		sum = sum ^ buf[i];
+	return sum;
+}
+
+static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+{
+	int i,ret = 0;
+	u8 chipaddr =  0x50 | ((addr >> 8) & 3);
+	for (i = 0; i < retries; i++)
+		if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+			break;
+	return ret;
+}
+
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
+{
+	int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+	if (ret == 0)
+		if (calc_lrc(buf, len - 1) != buf[len - 1])
+			ret = -EINVAL;
+	return ret;
+}
+
+/* JJ's comment about extended == 1: it is not presently used anywhere but was
+ * added to the low-level functions for possible support of EUI64
+ */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+{
+	u8 buf[8];
+	int ret = 0;
+
+	if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+		if (extended != 0) {
+			err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
+			ret = -EINVAL;
+/*			memcpy(fc->dvb_adapter.proposed_mac,buf,3);
+			mac[3] = 0xfe;
+			mac[4] = 0xff;
+			memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
+		} else
+			memcpy(fc->dvb_adapter.proposed_mac,buf,6);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#include "stv0299.h"
+#include "mt352.h"
+#include "nxt2002.h"
+#include "stv0297.h"
+#include "mt312.h"
+
+/* lnb control */
+
+static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	flexcop_ibi_value v;
+	deb_tuner("polarity/voltage = %u\n", voltage);
+
+	v = fc->read_ibi_reg(fc, misc_204);
+	switch (voltage) {
+		case SEC_VOLTAGE_OFF:
+			v.misc_204.ACPI1_sig = 1;
+			break;
+		case SEC_VOLTAGE_13:
+			v.misc_204.ACPI1_sig = 0;
+			v.misc_204.LNB_L_H_sig = 0;
+			break;
+		case SEC_VOLTAGE_18:
+			v.misc_204.ACPI1_sig = 0;
+			v.misc_204.LNB_L_H_sig = 1;
+			break;
+		default:
+			err("unknown SEC_VOLTAGE value");
+			return -EINVAL;
+	}
+	return fc->write_ibi_reg(fc, misc_204, v);
+}
+
+static int flexcop_sleep(struct dvb_frontend* fe)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+/*	flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
+
+	if (fc->fe_sleep)
+		return fc->fe_sleep(fe);
+
+/*	v.misc_204.ACPI3_sig = 1;
+	fc->write_ibi_reg(fc,misc_204,v);*/
+
+	return 0;
+}
+
+static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+	struct flexcop_device *fc = fe->dvb->priv;
+	flexcop_ibi_value v;
+	u16 ax;
+	v.raw = 0;
+
+	deb_tuner("tone = %u\n",tone);
+
+	switch (tone) {
+		case SEC_TONE_ON:
+			ax = 0x01ff;
+			break;
+		case SEC_TONE_OFF:
+			ax = 0;
+			break;
+		default:
+			err("unknown SEC_TONE value");
+			return -EINVAL;
+	}
+
+	v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
+
+	v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
+	v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
+
+	return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
+}
+
+static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
+{
+	flexcop_set_tone(fe, SEC_TONE_ON);
+	udelay(data ? 500 : 1000);
+	flexcop_set_tone(fe, SEC_TONE_OFF);
+	udelay(data ? 1000 : 500);
+}
+
+static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
+{
+	int i, par = 1, d;
+
+	for (i = 7; i >= 0; i--) {
+		d = (data >> i) & 1;
+		par ^= d;
+		flexcop_diseqc_send_bit(fe, d);
+	}
+
+	flexcop_diseqc_send_bit(fe, par);
+}
+
+static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+{
+	int i;
+
+	flexcop_set_tone(fe, SEC_TONE_OFF);
+	mdelay(16);
+
+	for (i = 0; i < len; i++)
+		flexcop_diseqc_send_byte(fe,msg[i]);
+
+	mdelay(16);
+
+	if (burst != -1) {
+		if (burst)
+			flexcop_diseqc_send_byte(fe, 0xff);
+		else {
+			flexcop_set_tone(fe, SEC_TONE_ON);
+			udelay(12500);
+			flexcop_set_tone(fe, SEC_TONE_OFF);
+		}
+		msleep(20);
+	}
+	return 0;
+}
+
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
+}
+
+static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
+}
+
+/* dvb-s stv0299 */
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+	stv0299_writereg (fe, 0x13, aclk);
+	stv0299_writereg (fe, 0x14, bclk);
+	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+
+	return 0;
+}
+
+static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct flexcop_device *fc = fe->dvb->priv;
+
+	div = params->frequency / 125;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x84;  /* 0xC4 */
+	buf[3] = 0x08;
+
+	if (params->frequency < 1500000) buf[3] |= 0x10;
+
+	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static u8 samsung_tbmu24112_inittab[] = {
+	     0x01, 0x15,
+	     0x02, 0x30,
+	     0x03, 0x00,
+	     0x04, 0x7D,
+	     0x05, 0x35,
+	     0x06, 0x02,
+	     0x07, 0x00,
+	     0x08, 0xC3,
+	     0x0C, 0x00,
+	     0x0D, 0x81,
+	     0x0E, 0x23,
+	     0x0F, 0x12,
+	     0x10, 0x7E,
+	     0x11, 0x84,
+	     0x12, 0xB9,
+	     0x13, 0x88,
+	     0x14, 0x89,
+	     0x15, 0xC9,
+	     0x16, 0x00,
+	     0x17, 0x5C,
+	     0x18, 0x00,
+	     0x19, 0x00,
+	     0x1A, 0x00,
+	     0x1C, 0x00,
+	     0x1D, 0x00,
+	     0x1E, 0x00,
+	     0x1F, 0x3A,
+	     0x20, 0x2E,
+	     0x21, 0x80,
+	     0x22, 0xFF,
+	     0x23, 0xC1,
+	     0x28, 0x00,
+	     0x29, 0x1E,
+	     0x2A, 0x14,
+	     0x2B, 0x0F,
+	     0x2C, 0x09,
+	     0x2D, 0x05,
+	     0x31, 0x1F,
+	     0x32, 0x19,
+	     0x33, 0xFE,
+	     0x34, 0x93,
+	     0xff, 0xff,
+};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+	.demod_address = 0x68,
+	.inittab = samsung_tbmu24112_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_LK,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+	.pll_set = samsung_tbmu24112_pll_set,
+};
+
+/* dvb-t mt352 */
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+	u32 div;
+	unsigned char bs = 0;
+
+	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
+	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
+	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+
+	pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+	pllbuf[1] = div >> 8;
+	pllbuf[2] = div & 0xff;
+	pllbuf[3] = 0xcc;
+	pllbuf[4] = bs;
+
+	return 0;
+}
+
+static struct mt352_config samsung_tdtc9251dh0_config = {
+
+	.demod_address = 0x0f,
+	.demod_init = samsung_tdtc9251dh0_demod_init,
+	.pll_set = samsung_tdtc9251dh0_pll_set,
+};
+
+static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	return request_firmware(fw, name, fc->dev);
+}
+
+static struct nxt2002_config samsung_tbmv_config = {
+	.demod_address = 0x0a,
+	.request_firmware = nxt2002_request_firmware,
+};
+
+static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct flexcop_device *fc = fe->dvb->priv;
+
+	div = (params->frequency + (125/2)) / 125;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+	buf[2] = 0x84 | ((div >> 10) & 0x60);
+	buf[3] = 0x80;
+
+	if (params->frequency < 1550000)
+		buf[3] |= 0x02;
+
+	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+
+	.demod_address = 0x0e,
+	.pll_set = skystar23_samsung_tbdu18132_pll_set,
+};
+
+static struct stv0297_config alps_tdee4_stv0297_config = {
+	.demod_address = 0x1c,
+//	.invert = 1,
+//	.pll_set = alps_tdee4_stv0297_pll_set,
+};
+
+/* try to figure out the frontend, each card/box can have on of the following list */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
+	if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+		fc->fe->ops->set_voltage = flexcop_set_voltage;
+
+		fc->fe_sleep             = fc->fe->ops->sleep;
+		fc->fe->ops->sleep       = flexcop_sleep;
+
+		fc->dev_type          = FC_SKY;
+		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
+	} else
+	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
+	if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
+		fc->dev_type          = FC_AIR_DVB;
+		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
+	} else
+	/* try the air atsc (nxt2002) */
+	if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
+		fc->dev_type          = FC_AIR_ATSC;
+		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
+	} else
+	/* try the cable dvb (stv0297) */
+	if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
+		fc->dev_type                        = FC_CABLE;
+		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
+	} else
+	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
+	if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+		fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+		fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+		fc->fe->ops->set_tone               = flexcop_set_tone;
+		fc->fe->ops->set_voltage            = flexcop_set_voltage;
+
+		fc->fe_sleep                        = fc->fe->ops->sleep;
+		fc->fe->ops->sleep                  = flexcop_sleep;
+
+		fc->dev_type                        = FC_SKY_OLD;
+		info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
+	}
+
+	if (fc->fe == NULL) {
+		err("no frontend driver found for this B2C2/FlexCop adapter");
+		return -ENODEV;
+	} else {
+		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+			err("frontend registration failed!");
+			if (fc->fe->ops->release != NULL)
+				fc->fe->ops->release(fc->fe);
+			fc->fe = NULL;
+			return -EINVAL;
+		}
+	}
+	fc->init_state |= FC_STATE_FE_INIT;
+	return 0;
+}
+
+void flexcop_frontend_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_FE_INIT)
+		dvb_unregister_frontend(fc->fe);
+
+	fc->init_state &= ~FC_STATE_FE_INIT;
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
@@ -0,0 +1,204 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+}
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
+}
+
+void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
+}
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+{
+	flexcop_ibi_value v418,v41c;
+	v41c = fc->read_ibi_reg(fc,mac_address_41c);
+
+	v418.mac_address_418.MAC1 = mac[0];
+	v418.mac_address_418.MAC2 = mac[1];
+	v418.mac_address_418.MAC3 = mac[2];
+	v418.mac_address_418.MAC6 = mac[3];
+	v41c.mac_address_41c.MAC7 = mac[4];
+	v41c.mac_address_41c.MAC8 = mac[5];
+
+	fc->write_ibi_reg(fc,mac_address_418,v418);
+	fc->write_ibi_reg(fc,mac_address_41c,v41c);
+}
+
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
+}
+
+static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
+{
+	/* index_reg_310.extra_index_reg need to 0 or 7 to work */
+	flexcop_ibi_value v30c;
+	v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
+	v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
+	fc->write_ibi_reg(fc,pid_filter_30c,v30c);
+}
+
+static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
+}
+
+/* this fancy define reduces the code size of the quite similar PID controlling of
+ * the first 6 PIDs
+ */
+
+#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
+	flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
+					  v208 = fc->read_ibi_reg(fc, ctrl_208); \
+\
+	vpid.vregname.field = onoff ? pid : 0x1fff; \
+	vpid.vregname.trans_field = transval; \
+	v208.ctrl_208.enablefield = onoff; \
+\
+	fc->write_ibi_reg(fc,vregname,vpid); \
+	fc->write_ibi_reg(fc,ctrl_208,v208);
+
+static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
+}
+
+static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
+}
+
+static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
+}
+
+static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
+}
+
+static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
+}
+
+static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
+}
+
+static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
+{
+	if (pid == 0x2000)
+		return;
+
+	deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
+
+	/* We could use bit magic here to reduce source code size.
+	 * I decided against it, but to use the real register names */
+	switch (index) {
+		case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
+		case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
+		case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
+		case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
+		case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
+		case 5:	flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
+		default:
+			if (fc->has_32_hw_pid_filter && index < 38) {
+				flexcop_ibi_value vpid,vid;
+
+				/* set the index */
+				vid = fc->read_ibi_reg(fc,index_reg_310);
+				vid.index_reg_310.index_reg = index - 6;
+				fc->write_ibi_reg(fc,index_reg_310, vid);
+
+				vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
+				vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+				vpid.pid_n_reg_314.PID_enable_bit = onoff;
+				fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
+			}
+			break;
+	}
+}
+
+static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
+{
+	if (fc->fullts_streaming_state != onoff) {
+		deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
+		flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
+		flexcop_pid_group_filter_ctrl(fc,onoff);
+		fc->fullts_streaming_state = onoff;
+	}
+	return 0;
+}
+
+int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
+
+	fc->feedcount += onoff ? 1 : -1;
+	if (dvbdmxfeed->index >= max_pid_filter)
+		fc->extra_feedcount += onoff ? 1 : -1;
+
+	/* toggle complete-TS-streaming when:
+	 * - pid_filtering is not enabled and it is the first or last feed requested
+	 * - pid_filtering is enabled,
+	 *   - but the number of requested feeds is exceeded
+	 *   - or the requested pid is 0x2000 */
+
+	if (!fc->pid_filtering && fc->feedcount == onoff)
+		flexcop_toggle_fullts_streaming(fc,onoff);
+
+	if (fc->pid_filtering) {
+		flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+		if (fc->extra_feedcount > 0)
+			flexcop_toggle_fullts_streaming(fc,1);
+		else if (dvbdmxfeed->pid == 0x2000)
+			flexcop_toggle_fullts_streaming(fc,onoff);
+		else
+			flexcop_toggle_fullts_streaming(fc,0);
+	}
+
+	/* if it was the first or last feed request change the stream-status */
+	if (fc->feedcount == onoff) {
+		flexcop_rcv_data_ctrl(fc,onoff);
+		if (fc->stream_control)
+			fc->stream_control(fc,onoff);
+	}
+
+	return 0;
+}
+
+void flexcop_hw_filter_init(struct flexcop_device *fc)
+{
+	int i;
+	flexcop_ibi_value v;
+	for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
+		flexcop_pid_control(fc,i,0x1fff,0);
+
+	flexcop_pid_group_filter(fc, 0, 0x1fe0);
+	flexcop_pid_group_filter_ctrl(fc,0);
+
+	v = fc->read_ibi_reg(fc,pid_filter_308);
+	v.pid_filter_308.EMM_filter_4 = 1;
+	v.pid_filter_308.EMM_filter_6 = 0;
+	fc->write_ibi_reg(fc,pid_filter_308,v);
+
+	flexcop_null_filter_ctrl(fc, 1);
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -0,0 +1,210 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#define FC_MAX_I2C_RETRIES 100000
+
+static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
+{
+	int i;
+	flexcop_ibi_value r;
+
+	r100->tw_sm_c_100.working_start = 1;
+	deb_i2c("r100 before: %08x\n",r100->raw);
+
+	fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
+	fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
+
+	for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
+		r = fc->read_ibi_reg(fc, tw_sm_c_100);
+
+		if (!r.tw_sm_c_100.no_base_addr_ack_error) {
+			if (r.tw_sm_c_100.st_done) {  /* && !r.tw_sm_c_100.working_start */
+				*r100 = r;
+				deb_i2c("i2c success\n");
+				return 0;
+			}
+		} else {
+			deb_i2c("suffering from an i2c ack_error\n");
+			return -EREMOTEIO;
+		}
+	}
+	deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
+	return -EREMOTEIO;
+}
+
+static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+{
+	flexcop_ibi_value r104;
+	int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
+		ret;
+
+	if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
+		/* The Cablestar needs a different kind of i2c-transfer (does not
+		 * support "Repeat Start"):
+		 * wait for the ACK failure,
+		 * and do a subsequent read with the Bit 30 enabled
+		 */
+		r100.tw_sm_c_100.no_base_addr_ack_error = 1;
+		if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
+			deb_i2c("no_base_addr read failed. %d\n",ret);
+			return ret;
+		}
+	}
+
+	buf[0] = r100.tw_sm_c_100.data1_reg;
+
+	if (len > 0) {
+		r104 = fc->read_ibi_reg(fc,tw_sm_c_104);
+		deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+
+		/* there is at least one more byte, otherwise we wouldn't be here */
+		buf[1] = r104.tw_sm_c_104.data2_reg;
+		if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
+		if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
+	}
+
+	return 0;
+}
+
+static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+{
+	flexcop_ibi_value r104;
+	int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
+	r104.raw = 0;
+
+	/* there is at least one byte, otherwise we wouldn't be here */
+	r100.tw_sm_c_100.data1_reg = buf[0];
+
+	r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
+	r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
+	r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
+
+	deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+
+	/* write the additional i2c data before doing the actual i2c operation */
+	fc->write_ibi_reg(fc,tw_sm_c_104,r104);
+	return flexcop_i2c_operation(fc,&r100);
+}
+
+int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
+		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+{
+	int ret;
+	u16 bytes_to_transfer;
+	flexcop_ibi_value r100;
+
+	deb_i2c("op = %d\n",op);
+	r100.raw = 0;
+	r100.tw_sm_c_100.chipaddr = chipaddr;
+	r100.tw_sm_c_100.twoWS_rw = op;
+	r100.tw_sm_c_100.twoWS_port_reg = port;
+
+	while (len != 0) {
+		bytes_to_transfer = len > 4 ? 4 : len;
+
+		r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
+		r100.tw_sm_c_100.baseaddr = addr;
+
+		if (op == FC_READ)
+			ret = flexcop_i2c_read4(fc, r100, buf);
+		else
+			ret = flexcop_i2c_write4(fc,r100, buf);
+
+		if (ret < 0)
+			return ret;
+
+		buf  += bytes_to_transfer;
+		addr += bytes_to_transfer;
+		len  -= bytes_to_transfer;
+	};
+
+	return 0;
+}
+/* exported for PCI i2c */
+EXPORT_SYMBOL(flexcop_i2c_request);
+
+/* master xfer callback for demodulator */
+static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+	struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
+	int i, ret = 0;
+
+	if (down_interruptible(&fc->i2c_sem))
+		return -ERESTARTSYS;
+
+	/* reading */
+	if (num == 2 &&
+		msgs[0].flags == 0 &&
+		msgs[1].flags == I2C_M_RD &&
+		msgs[0].buf != NULL &&
+		msgs[1].buf != NULL) {
+
+		ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
+
+	} else for (i = 0; i < num; i++) { /* writing command */
+		if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) {
+			ret = -EINVAL;
+			break;
+		}
+
+		ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
+	}
+
+	if (ret < 0)
+		err("i2c master_xfer failed");
+	else
+		ret = num;
+
+	up(&fc->i2c_sem);
+
+	return ret;
+}
+
+static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm flexcop_algo = {
+	.name			= "FlexCop I2C algorithm",
+	.id				= I2C_ALGO_BIT,
+	.master_xfer	= flexcop_master_xfer,
+	.functionality	= flexcop_i2c_func,
+};
+
+int flexcop_i2c_init(struct flexcop_device *fc)
+{
+	int ret;
+
+	sema_init(&fc->i2c_sem,1);
+
+	memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
+	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
+
+	i2c_set_adapdata(&fc->i2c_adap,fc);
+
+	fc->i2c_adap.class	    = I2C_CLASS_TV_DIGITAL;
+	fc->i2c_adap.algo       = &flexcop_algo;
+	fc->i2c_adap.algo_data  = NULL;
+	fc->i2c_adap.id         = I2C_ALGO_BIT;
+
+	if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
+		return ret;
+
+	fc->init_state |= FC_STATE_I2C_INIT;
+	return 0;
+}
+
+void flexcop_i2c_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_I2C_INIT)
+		i2c_del_adapter(&fc->i2c_adap);
+
+	fc->init_state &= ~FC_STATE_I2C_INIT;
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-misc.c - miscellaneous functions.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+void flexcop_determine_revision(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
+
+	switch (v.misc_204.Rev_N_sig_revision_hi) {
+		case 0x2:
+			deb_info("found a FlexCopII.\n");
+			fc->rev = FLEXCOP_II;
+			break;
+		case 0x3:
+			deb_info("found a FlexCopIIb.\n");
+			fc->rev = FLEXCOP_IIB;
+			break;
+		case 0x0:
+			deb_info("found a FlexCopIII.\n");
+			fc->rev = FLEXCOP_III;
+			break;
+		default:
+			err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
+			break;
+	}
+
+	if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
+		deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
+	else
+		deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
+	/* bus parts have to decide if hw pid filtering is used or not. */
+}
+
+const char *flexcop_revision_names[] = {
+	"Unkown chip",
+	"FlexCopII",
+	"FlexCopIIb",
+	"FlexCopIII",
+};
+
+const char *flexcop_device_names[] = {
+	"Unkown device",
+	"AirStar 2 DVB-T",
+	"AirStar 2 ATSC",
+	"SkyStar 2 DVB-S",
+	"SkyStar 2 DVB-S (old version)",
+	"CableStar 2 DVB-C",
+};
+
+const char *flexcop_bus_names[] = {
+	"USB",
+	"PCI",
+};
+
+void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
+		char *suffix)
+{
+	info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix,
+			flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
+			flexcop_revision_names[fc->rev],suffix);
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -0,0 +1,381 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-pci.c - covers the PCI part including DMA transfers.
+ *
+ * see flexcop.c for copyright information.
+ */
+
+#define FC_LOG_PREFIX "flexcop-pci"
+#include "flexcop-common.h"
+
+static int enable_pid_filtering = 1;
+module_param(enable_pid_filtering, int, 0444);
+MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
+
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	do { if ((debug & level)) printk(args); } while (0)
+#define DEBSTATUS ""
+#else
+#define dprintk(level,args...)
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+#define deb_info(args...)  dprintk(0x01,args)
+#define deb_reg(args...)   dprintk(0x02,args)
+#define deb_ts(args...)    dprintk(0x04,args)
+#define deb_irq(args...)   dprintk(0x08,args)
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+
+struct flexcop_pci {
+	struct pci_dev *pdev;
+
+#define FC_PCI_INIT     0x01
+#define FC_PCI_DMA_INIT 0x02
+	int init_state;
+
+	void __iomem *io_mem;
+	u32 irq;
+/* buffersize (at least for DMA1, need to be % 188 == 0,
+ * this logic is required */
+#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
+#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
+	struct flexcop_dma dma[2];
+
+	int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
+	u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
+	int count;
+
+	spinlock_t irq_lock;
+
+	struct flexcop_device *fc_dev;
+};
+
+static int lastwreg,lastwval,lastrreg,lastrval;
+
+static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+	flexcop_ibi_value v;
+	v.raw = readl(fc_pci->io_mem + r);
+
+	if (lastrreg != r || lastrval != v.raw) {
+		lastrreg = r; lastrval = v.raw;
+		deb_reg("new rd: %3x: %08x\n",r,v.raw);
+	}
+
+	return v;
+}
+
+static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+
+	if (lastwreg != r || lastwval != v.raw) {
+		lastwreg = r; lastwval = v.raw;
+		deb_reg("new wr: %3x: %08x\n",r,v.raw);
+	}
+
+	writel(v.raw, fc_pci->io_mem + r);
+	return 0;
+}
+
+/* When PID filtering is turned on, we use the timer IRQ, because small amounts
+ * of data need to be passed to the user space instantly as well. When PID
+ * filtering is turned off, we use the page-change-IRQ */
+static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct flexcop_pci *fc_pci = dev_id;
+	struct flexcop_device *fc = fc_pci->fc_dev;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c);
+	irqreturn_t ret = IRQ_HANDLED;
+
+	spin_lock_irq(&fc_pci->irq_lock);
+
+	if (v.irq_20c.DMA1_IRQ_Status == 1) {
+		if (fc_pci->active_dma1_addr == 0)
+			flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
+		else
+			flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188);
+
+		deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
+		fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
+	} else if (v.irq_20c.DMA1_Timer_Status == 1) {
+		/* for the timer IRQ we only can use buffer dmx feeding, because we don't have
+		 * complete TS packets when reading from the DMA memory */
+		dma_addr_t cur_addr =
+			fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
+		u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
+
+		deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
+				v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+
+		/* buffer end was reached, restarted from the beginning
+		 * pass the data from last_cur_pos to the buffer end to the demux
+		 */
+		if (cur_pos < fc_pci->last_dma1_cur_pos) {
+			deb_irq(" end was reached: passing %d bytes ",(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos);
+			flexcop_pass_dmx_data(fc_pci->fc_dev,
+					fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
+					(fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
+			fc_pci->last_dma1_cur_pos = 0;
+			fc_pci->count = 0;
+		}
+
+		if (cur_pos > fc_pci->last_dma1_cur_pos) {
+			deb_irq(" passing %d bytes ",cur_pos - fc_pci->last_dma1_cur_pos);
+			flexcop_pass_dmx_data(fc_pci->fc_dev,
+					fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
+					cur_pos - fc_pci->last_dma1_cur_pos);
+		}
+		deb_irq("\n");
+
+		fc_pci->last_dma1_cur_pos = cur_pos;
+	} else
+		ret = IRQ_NONE;
+
+	spin_unlock_irq(&fc_pci->irq_lock);
+
+/* packet count would be ideal for hw filtering, but it isn't working. Either
+ * the data book is wrong, or I'm unable to read it correctly */
+
+/*	if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
+
+	return ret;
+}
+
+static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+	if (onoff) {
+		flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
+		flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
+		flexcop_dma_config_timer(fc,FC_DMA_1,1);
+
+		if (fc_pci->fc_dev->pid_filtering) {
+			fc_pci->last_dma1_cur_pos = 0;
+			flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
+		} else {
+			fc_pci->active_dma1_addr = 0;
+			flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
+		}
+
+/*		flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0);
+		flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */
+
+		deb_irq("irqs enabled\n");
+	} else {
+		if (fc_pci->fc_dev->pid_filtering)
+			flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
+		else
+			flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+
+//		flexcop_dma_control_packet_irq(fc,FC_DMA_1,0);
+		deb_irq("irqs disabled\n");
+	}
+
+	return 0;
+}
+
+static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
+{
+	int ret;
+	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
+		return ret;
+
+	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
+		goto dma1_free;
+
+	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
+	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
+
+	fc_pci->init_state |= FC_PCI_DMA_INIT;
+	goto success;
+dma1_free:
+	flexcop_dma_free(&fc_pci->dma[0]);
+
+success:
+	return ret;
+}
+
+static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
+{
+	if (fc_pci->init_state & FC_PCI_DMA_INIT) {
+		flexcop_dma_free(&fc_pci->dma[0]);
+		flexcop_dma_free(&fc_pci->dma[1]);
+	}
+	fc_pci->init_state &= ~FC_PCI_DMA_INIT;
+}
+
+static int flexcop_pci_init(struct flexcop_pci *fc_pci)
+{
+	int ret;
+	u8 card_rev;
+
+	pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
+	info("card revision %x", card_rev);
+
+	if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
+		return ret;
+
+	pci_set_master(fc_pci->pdev);
+
+	/* enable interrupts */
+	// pci_write_config_dword(pdev, 0x6c, 0x8000);
+
+	if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
+		goto err_pci_disable_device;
+
+	fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
+
+	if (!fc_pci->io_mem) {
+		err("cannot map io memory\n");
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	pci_set_drvdata(fc_pci->pdev, fc_pci);
+
+	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq,
+					SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
+		goto err_pci_iounmap;
+
+	spin_lock_init(&fc_pci->irq_lock);
+
+	fc_pci->init_state |= FC_PCI_INIT;
+	goto success;
+
+err_pci_iounmap:
+	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
+	pci_set_drvdata(fc_pci->pdev, NULL);
+err_pci_release_regions:
+	pci_release_regions(fc_pci->pdev);
+err_pci_disable_device:
+	pci_disable_device(fc_pci->pdev);
+
+success:
+	return ret;
+}
+
+static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
+{
+	if (fc_pci->init_state & FC_PCI_INIT) {
+		free_irq(fc_pci->pdev->irq, fc_pci);
+		pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
+		pci_set_drvdata(fc_pci->pdev, NULL);
+		pci_release_regions(fc_pci->pdev);
+		pci_disable_device(fc_pci->pdev);
+	}
+	fc_pci->init_state &= ~FC_PCI_INIT;
+}
+
+
+static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct flexcop_device *fc;
+	struct flexcop_pci *fc_pci;
+	int ret = -ENOMEM;
+
+	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) {
+		err("out of memory\n");
+		return -ENOMEM;
+	}
+
+/* general flexcop init */
+	fc_pci = fc->bus_specific;
+	fc_pci->fc_dev = fc;
+
+	fc->read_ibi_reg = flexcop_pci_read_ibi_reg;
+	fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
+	fc->i2c_request = flexcop_i2c_request;
+	fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
+
+	fc->stream_control = flexcop_pci_stream_control;
+
+	if (enable_pid_filtering)
+		info("will use the HW PID filter.");
+	else
+		info("will pass the complete TS to the demuxer.");
+
+	fc->pid_filtering = enable_pid_filtering;
+	fc->bus_type = FC_PCI;
+
+	fc->dev = &pdev->dev;
+	fc->owner = THIS_MODULE;
+
+/* bus specific part */
+	fc_pci->pdev = pdev;
+	if ((ret = flexcop_pci_init(fc_pci)) != 0)
+		goto err_kfree;
+
+/* init flexcop */
+	if ((ret = flexcop_device_initialize(fc)) != 0)
+		goto err_pci_exit;
+
+/* init dma */
+	if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
+		goto err_fc_exit;
+
+	goto success;
+err_fc_exit:
+	flexcop_device_exit(fc);
+err_pci_exit:
+	flexcop_pci_exit(fc_pci);
+err_kfree:
+	flexcop_device_kfree(fc);
+success:
+	return ret;
+}
+
+/* in theory every _exit function should be called exactly two times,
+ * here and in the bail-out-part of the _init-function
+ */
+static void flexcop_pci_remove(struct pci_dev *pdev)
+{
+	struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
+
+	flexcop_pci_dma_exit(fc_pci);
+	flexcop_device_exit(fc_pci->fc_dev);
+	flexcop_pci_exit(fc_pci);
+	flexcop_device_kfree(fc_pci->fc_dev);
+}
+
+static struct pci_device_id flexcop_pci_tbl[] = {
+	{ PCI_DEVICE(0x13d0, 0x2103) },
+/*	{ PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
+
+static struct pci_driver flexcop_pci_driver = {
+	.name = "Technisat/B2C2 FlexCop II/IIb/III PCI",
+	.id_table = flexcop_pci_tbl,
+	.probe = flexcop_pci_probe,
+	.remove = flexcop_pci_remove,
+};
+
+static int __init flexcop_pci_module_init(void)
+{
+	return pci_register_driver(&flexcop_pci_driver);
+}
+
+static void __exit flexcop_pci_module_exit(void)
+{
+	pci_unregister_driver(&flexcop_pci_driver);
+}
+
+module_init(flexcop_pci_module_init);
+module_exit(flexcop_pci_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -0,0 +1,701 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_REG_H__
+#define __FLEXCOP_REG_H__
+
+
+typedef enum {
+	FLEXCOP_UNK = 0,
+	FLEXCOP_II,
+	FLEXCOP_IIB,
+	FLEXCOP_III,
+} flexcop_revision_t;
+
+extern const char *flexcop_revision_names[];
+
+typedef enum {
+	FC_UNK = 0,
+	FC_AIR_DVB,
+	FC_AIR_ATSC,
+	FC_SKY,
+	FC_SKY_OLD,
+	FC_CABLE,
+} flexcop_device_type_t;
+
+typedef enum {
+	FC_USB = 0,
+	FC_PCI,
+} flexcop_bus_t;
+
+extern const char *flexcop_device_names[];
+
+/* FlexCop IBI Registers */
+
+/* flexcop_ibi_reg - a huge union representing the register structure */
+typedef union {
+	u32 raw;
+
+/* DMA 0x000 to 0x01c
+ * DMA1 0x000 to 0x00c
+ * DMA2 0x010 to 0x01c
+ */
+	struct {
+		u32 dma_0start        : 1;   /* set: data will be delivered to dma1_address0 */
+        u32 dma_0No_update    : 1;   /* set: dma1_cur_address will be updated, unset: no update */
+        u32 dma_address0      :30;   /* physical/virtual host memory address0 DMA */
+	} dma_0x0;
+
+	struct {
+		u32 DMA_maxpackets    : 8;   /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
+										is able to be read and written while bit(1) of register
+										0x00c (remap_enable) is set. This variable represents
+										the number of packets that will be transmitted to the PCI
+										host using PCI DMA1 before an interrupt to the PCI is
+										asserted. This functionality may be enabled using bit(20)
+										of register 0x208. N=0 disables the IRQ. */
+		u32 dma_addr_size     :24;   /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
+	} dma_0x4_remap;
+
+	struct {
+		u32 dma1timer         : 7;   /* reading PCI DMA1 timer ... when remap_enable is 0 */
+		u32 unused            : 1;
+		u32 dma_addr_size     :24;
+	} dma_0x4_read;
+
+	struct {
+		u32 unused            : 1;
+		u32 dmatimer          : 7;   /* writing PCI DMA1 timer ... when remap_enable is 0 */
+		u32 dma_addr_size     :24;
+	} dma_0x4_write;
+
+	struct {
+		u32 unused            : 2;
+		u32 dma_cur_addr      :30;   /* current physical host memory address pointer for DMA */
+	} dma_0x8;
+
+	struct {
+		u32 dma_1start        : 1;   /* set: data will be delivered to dma_address1, when dma_address0 is full */
+		u32 remap_enable      : 1;   /* remap enable for 0x0x4(7:0) */
+		u32 dma_address1      :30;   /* Physical/virtual address 1 on DMA */
+	} dma_0xc;
+
+/* Two-wire Serial Master and Clock 0x100-0x110 */
+	struct {
+//		u32 slave_transmitter : 1;   /* ???*/
+		u32 chipaddr          : 7;   /* two-line serial address of the target slave */
+		u32 reserved1         : 1;
+		u32 baseaddr          : 8;   /* address of the location of the read/write operation */
+		u32 data1_reg         : 8;   /* first byte in two-line serial read/write operation */
+		u32 working_start     : 1;  /* when doing a write operation this indicator is 0 when ready
+									  * set to 1 when doing a write operation */
+		u32 twoWS_rw          : 1;   /* read/write indicator (1 = read, 0 write) */
+		u32 total_bytes       : 2;   /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
+		u32 twoWS_port_reg    : 2;   /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
+		u32 no_base_addr_ack_error : 1;   /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
+									  * preceding address assignment write frame
+									  * ACK_ERROR = 1 when no ACK from slave in the last transaction */
+		u32 st_done           : 1;   /* indicator for transaction is done */
+	} tw_sm_c_100;
+
+	struct {
+		u32 data2_reg         : 8;   /* 2nd data byte */
+		u32 data3_reg         : 8;   /* 3rd data byte */
+		u32 data4_reg         : 8;   /* 4th data byte */
+		u32 exlicit_stops     : 1;   /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
+		u32 force_stop        : 1;   /* isolated stop flag */
+		u32 unused            : 6;
+	} tw_sm_c_104;
+
+/* Clock. The register allows the FCIII to convert an incoming Master clock
+ * (MCLK) signal into a lower frequency clock through the use of a LowCounter
+ * (TLO) and a High- Counter (THI). The time counts for THI and TLO are
+ * measured in MCLK; each count represents 4 MCLK input clock cycles.
+ *
+ * The default output for port #1 is set for Front End Demod communication. (0x108)
+ * The default output for port #2 is set for EEPROM communication. (0x10c)
+ * The default output for port #3 is set for Tuner communication. (0x110)
+ */
+	struct {
+		u32 thi1              : 6;   /* Thi for port #1 (def: 100110b; 38) */
+		u32 reserved1         : 2;
+		u32 tlo1              : 5;   /* Tlo for port #1 (def: 11100b; 28) */
+		u32 reserved2         :19;
+	} tw_sm_c_108;
+
+	struct {
+		u32 thi1              : 6;   /* Thi for port #2 (def: 111001b; 57) */
+		u32 reserved1         : 2;
+		u32 tlo1              : 5;   /* Tlo for port #2 (def: 11100b; 28) */
+		u32 reserved2         :19;
+	} tw_sm_c_10c;
+
+	struct {
+		u32 thi1              : 6;   /* Thi for port #3 (def: 111001b; 57) */
+		u32 reserved1         : 2;
+		u32 tlo1              : 5;   /* Tlo for port #3 (def: 11100b; 28) */
+		u32 reserved2         :19;
+	} tw_sm_c_110;
+
+/* LNB Switch Frequency 0x200
+ * Clock that creates the LNB switch tone. The default is set to have a fixed
+ * low output (not oscillating) to the LNB_CTL line.
+ */
+	struct {
+		u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
+		u32 LNB_CTLLowCount_sig  :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
+										Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
+		u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
+	} lnb_switch_freq_200;
+
+/* ACPI, Peripheral Reset, LNB Polarity
+ * ACPI power conservation mode, LNB polarity selection (low or high voltage),
+ * and peripheral reset.
+ */
+	struct {
+		u32 ACPI1_sig         : 1;   /* turn of the power of tuner and LNB, not implemented in FCIII */
+		u32 ACPI3_sig         : 1;   /* turn of power of the complete satelite receiver board (except FCIII) */
+		u32 LNB_L_H_sig       : 1;   /* low or high voltage for LNB. (0 = low, 1 = high) */
+		u32 Per_reset_sig     : 1;   /* misc. init reset (default: 1), to reset set to low and back to high */
+		u32 reserved          :20;
+		u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
+		u32 Rev_N_sig_reserved1 : 2;
+		u32 Rev_N_sig_caps    : 1;   /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
+		u32 Rev_N_sig_reserved2 : 1;
+	} misc_204;
+
+/* Control and Status 0x208 to 0x21c */
+/* Gross enable and disable control */
+	struct {
+		u32 Stream1_filter_sig : 1;  /* Stream1 PID filtering */
+		u32 Stream2_filter_sig : 1;  /* Stream2 PID filtering */
+		u32 PCR_filter_sig    : 1;   /* PCR PID filter */
+		u32 PMT_filter_sig    : 1;   /* PMT PID filter */
+
+		u32 EMM_filter_sig    : 1;   /* EMM PID filter */
+		u32 ECM_filter_sig    : 1;   /* ECM PID filter */
+		u32 Null_filter_sig   : 1;   /* Filters null packets, PID=0x1fff. */
+		u32 Mask_filter_sig   : 1;   /* mask PID filter */
+
+		u32 WAN_Enable_sig    : 1;   /* WAN output line through V8 memory space is activated. */
+		u32 WAN_CA_Enable_sig : 1;   /* not in FCIII */
+		u32 CA_Enable_sig     : 1;   /* not in FCIII */
+		u32 SMC_Enable_sig    : 1;   /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
+
+		u32 Per_CA_Enable_sig : 1;   /* not in FCIII */
+		u32 Multi2_Enable_sig : 1;   /* ? */
+		u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
+		u32 Rcv_Data_sig      : 1;   /* PID filtering module enable. When this bit is a one, the PID filter will
+										examine and process packets according to all other (individual) PID
+										filtering controls. If it a zero, no packet processing of any kind will
+										take place. All data from the tuner will be thrown away. */
+
+		u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
+									  * interrupt after the specified count for filling the buffer. */
+		u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
+											after a specified amount of time. */
+		u32 DMA2_IRQ_Enable_sig : 1;   /* same as DMA1_IRQ_Enable_sig but for DMA2 */
+		u32 DMA2_Timer_Enable_sig : 1;   /* same as DMA1_Timer_Enable_sig but for DMA2 */
+
+		u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
+		u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet	count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
+		u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
+											PCI host to indicate that mailbox data is available. */
+
+		u32 unused            : 9;
+	} ctrl_208;
+
+/* General status. When a PCI interrupt occurs, this register is read to
+ * discover the reason for the interrupt.
+ */
+	struct {
+		u32 DMA1_IRQ_Status   : 1;   /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
+		u32 DMA1_Timer_Status : 1;   /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
+		u32 DMA2_IRQ_Status   : 1;   /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
+		u32 DMA2_Timer_Status : 1;   /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
+		u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
+		u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
+		u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
+		u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
+		u32 Continuity_error_flag : 1;   /* 1 indicates a continuity error in the TS stream. */
+		u32 LLC_SNAP_FLAG_set : 1;   /* 1 indicates that the LCC_SNAP_FLAG was set. */
+		u32 Transport_Error   : 1;   /*  When set indicates that an unexpected packet was received. */
+		u32 reserved          :21;
+	} irq_20c;
+
+
+/* Software reset register */
+	struct {
+		u32 reset_blocks      : 8;   /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
+										Each bit location represents a 0x100 block of registers. Writing
+										a one in a bit location resets that block of registers and the logic
+										that it controls. */
+		u32 Block_reset_enable : 8;  /* This variable is set to 0xB2 when the register is written. */
+		u32 Special_controls  :16;   /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
+										Turns off pci encryption => 0xC259 Note: pci_encryption default
+										at power-up is ON. */
+	} sw_reset_210;
+
+	struct {
+		u32 vuart_oe_sig      : 1;   /* When clear, the V8 processor has sole control of the serial UART
+										(RS-232 Smart Card interface). When set, the IBI interface
+										defined by register 0x600 controls the serial UART. */
+		u32 v2WS_oe_sig       : 1;   /* When clear, the V8 processor has direct control of the Two-line
+										Serial Master EEPROM target. When set, the Two-line Serial Master
+										EEPROM target interface is controlled by IBI register 0x100. */
+		u32 halt_V8_sig       : 1;   /* When set, contiguous wait states are applied to the V8-space
+										bus masters. Once this signal is cleared, normal V8-space
+										operations resume. */
+		u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
+										  to process section packed transport streams. */
+		u32 s2p_sel_sig       : 1;   /* Serial to parallel conversion. When set, polarized transport data
+										within the FlexCop3 front end circuitry is converted from a serial
+										stream into parallel data before downstream processing otherwise
+										interprets the data. */
+		u32 unused1           : 3;
+		u32 polarity_PS_CLK_sig: 1;  /* This signal is used to invert the input polarity of the tranport
+										stream CLOCK signal before any processing occurs on the transport
+										stream within FlexCop3. */
+		u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
+										stream VALID signal before any processing occurs on the transport
+										stream within FlexCop3. */
+		u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
+										stream SYNC signal before any processing occurs on the transport
+										stream within FlexCop3. */
+		u32 polarity_PS_ERR_sig: 1;  /* This signal is used to invert the input polarity of the tranport
+										stream ERROR signal before any processing occurs on the transport
+										stream within FlexCop3. */
+		u32 unused2           :20;
+	} misc_214;
+
+/* Mailbox from V8 to host */
+	struct {
+		u32 Mailbox_from_V8   :32;   /* When this register is written by either the V8 processor or by an
+										end host, an interrupt is generated to the PCI host to indicate
+										that mailbox data is available. Reading register 20c will clear
+										the IRQ. */
+	} mbox_v8_to_host_218;
+
+/* Mailbox from host to v8 Mailbox_to_V8
+ * Mailbox_to_V8 mailbox storage register
+ * used to send messages from PCI to V8. Writing to this register will send an
+ * IRQ to the V8. Then it can read the data from here. Reading this register
+ * will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
+ * then this register is used instead as a direct interface to access the
+ * V8space memory.
+ */
+	struct {
+		u32 sysramaccess_data : 8;   /* Data byte written or read from the specified address in V8 SysRAM. */
+		u32 sysramaccess_addr :15;   /* 15 bit address used to access V8 Sys-RAM. */
+		u32 unused            : 7;
+		u32 sysramaccess_write: 1;   /* Write flag used to latch data into the V8 SysRAM. */
+		u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
+										  this IBI register interface to directly drive the V8-space memory. */
+	} mbox_host_to_v8_21c;
+
+
+/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
+	struct {
+		u32 Stream1_PID       :13;   /* Primary use is receiving Net data, so these 13 bits normally
+										hold the PID value for the desired network stream. */
+		u32 Stream1_trans     : 1;   /* When set, Net translation will take place for Net data ferried in TS packets. */
+		u32 MAC_Multicast_filter : 1;   /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
+		u32 debug_flag_pid_saved : 1;
+		u32 Stream2_PID       :13;   /* 13 bits for Stream 2 PID filter value. General use. */
+		u32 Stream2_trans     : 1;   /* When set Tables/CAI translation will take place for the data ferried in
+										Stream2_PID TS packets. */
+		u32 debug_flag_write_status00 : 1;
+		u32 debug_fifo_problem : 1;
+	} pid_filter_300;
+
+	struct {
+		u32 PCR_PID           :13;   /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
+		u32 PCR_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
+		u32 debug_overrun3    : 1;
+		u32 debug_overrun2    : 1;
+		u32 PMT_PID           :13;   /* stream PID filter value. Primary use is Program Management Table segment filtering. */
+		u32 PMT_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
+		u32 reserved          : 2;
+	} pid_filter_304;
+
+	struct {
+		u32 EMM_PID           :13;   /* EMM PID filter value. Primary use is Entitlement Management Messaging for
+										conditional access-related data. */
+		u32 EMM_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
+		u32 EMM_filter_4      : 1;   /* When set will pass only EMM data possessing the same ID code as the
+										first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
+		u32 EMM_filter_6      : 1;   /* When set will pass only EMM data possessing the same 6-byte code as the end-users
+										complete 6-byte Smart Card ID number. */
+		u32 ECM_PID           :13;   /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
+										access-related data. */
+		u32 ECM_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
+		u32 reserved          : 2;
+	} pid_filter_308;
+
+	struct {
+		u32 Group_PID     :13;   /* PID value for group filtering. */
+		u32 Group_trans   : 1;   /* When set, Tables/CAI translation will take place for these packets. */
+		u32 unused1       : 2;
+		u32 Group_mask    :13;   /* Mask value used in logical "and" equation that defines group filtering */
+		u32 unused2       : 3;
+	} pid_filter_30c_ext_ind_0_7;
+
+	struct {
+		u32 net_master_read :17;
+		u32 unused        :15;
+	} pid_filter_30c_ext_ind_1;
+
+	struct {
+		u32 net_master_write :17;
+		u32 unused        :15;
+	} pid_filter_30c_ext_ind_2;
+
+	struct {
+		u32 next_net_master_write :17;
+		u32 unused        :15;
+	} pid_filter_30c_ext_ind_3;
+
+	struct {
+		u32 unused1       : 1;
+		u32 state_write   :10;
+		u32 reserved1     : 6;   /* default: 000100 */
+		u32 stack_read    :10;
+		u32 reserved2     : 5;   /* default: 00100 */
+	} pid_filter_30c_ext_ind_4;
+
+	struct {
+		u32 stack_cnt     :10;
+		u32 unused        :22;
+	} pid_filter_30c_ext_ind_5;
+
+	struct {
+		u32 pid_fsm_save_reg0 : 2;
+		u32 pid_fsm_save_reg1 : 2;
+		u32 pid_fsm_save_reg2 : 2;
+		u32 pid_fsm_save_reg3 : 2;
+		u32 pid_fsm_save_reg4 : 2;
+		u32 pid_fsm_save_reg300 : 2;
+		u32 write_status1 : 2;
+		u32 write_status4 : 2;
+		u32 data_size_reg :12;
+		u32 unused        : 4;
+	} pid_filter_30c_ext_ind_6;
+
+	struct {
+		u32 index_reg         : 5;   /* (Index pointer) Points at an internal PIDn register. A binary code
+										representing one of 32 internal PIDn registers as well as its
+										corresponding internal MAC_lown register. */
+		u32 extra_index_reg   : 3;   /* This vector is used to select between sets of debug signals routed to register 0x30c. */
+		u32 AB_select         : 1;   /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
+										0=MAC_highB register, 1=MAC_highA */
+		u32 pass_alltables    : 1;   /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
+										All types of networks (DVB, ATSC, ISDB) are passed. */
+		u32 unused            :22;
+	} index_reg_310;
+
+	struct {
+		u32 PID               :13;   /* PID value */
+		u32 PID_trans         : 1;   /* translation will take place for packets filtered */
+		u32 PID_enable_bit    : 1;   /* When set this PID filter is enabled */
+		u32 reserved          :17;
+	} pid_n_reg_314;
+
+	struct {
+		u32 A4_byte           : 8;
+		u32 A5_byte           : 8;
+		u32 A6_byte           : 8;
+		u32 Enable_bit        : 1;   /* enabled (1) or disabled (1) */
+		u32 HighAB_bit        : 1;   /* use MAC_highA (1) or MAC_highB (0) as MSB */
+		u32 reserved          : 6;
+	} mac_low_reg_318;
+
+	struct {
+		u32 A1_byte           : 8;
+		u32 A2_byte           : 8;
+		u32 A3_byte           : 8;
+		u32 reserved          : 8;
+	} mac_high_reg_31c;
+
+/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
+	struct {
+		u32 reserved          :16;
+#define fc_data_Tag_ID_DVB  0x3e
+#define fc_data_Tag_ID_ATSC 0x3f
+#define fc_data_Tag_ID_IDSB 0x8b
+		u32 data_Tag_ID       :16;
+	} data_tag_400;
+
+	struct {
+		u32 Card_IDbyte6      : 8;
+		u32 Card_IDbyte5      : 8;
+		u32 Card_IDbyte4      : 8;
+		u32 Card_IDbyte3      : 8;
+	} card_id_408;
+
+	struct {
+		u32 Card_IDbyte2      : 8;
+		u32 Card_IDbyte1      : 8;
+	} card_id_40c;
+
+	/* holding the unique mac address of the receiver which houses the FlexCopIII */
+	struct {
+		u32 MAC1              : 8;
+		u32 MAC2              : 8;
+		u32 MAC3              : 8;
+		u32 MAC6              : 8;
+	} mac_address_418;
+
+	struct {
+		u32 MAC7              : 8;
+		u32 MAC8              : 8;
+		u32 reserved          : 16;
+	} mac_address_41c;
+
+	struct {
+		u32 transmitter_data_byte : 8;
+		u32 ReceiveDataReady  : 1;
+		u32 ReceiveByteFrameError: 1;
+		u32 txbuffempty       : 1;
+		u32 reserved          :21;
+	} ci_600;
+
+	struct {
+		u32 pi_d              : 8;
+		u32 pi_ha             :20;
+		u32 pi_rw             : 1;
+		u32 pi_component_reg  : 3;
+	} pi_604;
+
+	struct {
+		u32 serialReset       : 1;
+		u32 oncecycle_read    : 1;
+		u32 Timer_Read_req    : 1;
+		u32 Timer_Load_req    : 1;
+		u32 timer_data        : 7;
+		u32 unused            : 1; /* ??? not mentioned in data book */
+		u32 Timer_addr        : 5;
+		u32 reserved          : 3;
+		u32 pcmcia_a_mod_pwr_n : 1;
+		u32 pcmcia_b_mod_pwr_n : 1;
+		u32 config_Done_stat  : 1;
+		u32 config_Init_stat  : 1;
+		u32 config_Prog_n     : 1;
+		u32 config_wr_n       : 1;
+		u32 config_cs_n       : 1;
+		u32 config_cclk       : 1;
+		u32 pi_CiMax_IRQ_n    : 1;
+		u32 pi_timeout_status : 1;
+		u32 pi_wait_n         : 1;
+		u32 pi_busy_n         : 1;
+	} pi_608;
+
+	struct {
+		u32 PID               :13;
+		u32 key_enable        : 1;
+#define fc_key_code_default 0x1
+#define fc_key_code_even    0x2
+#define fc_key_code_odd     0x3
+		u32 key_code          : 2;
+		u32 key_array_col     : 3;
+		u32 key_array_row     : 5;
+		u32 dvb_en            : 1; /* 0=TS bypasses the Descrambler */
+		u32 rw_flag           : 1;
+		u32 reserved          : 6;
+	} dvb_reg_60c;
+
+/* SRAM and Output Destination 0x700 to 0x714 */
+	struct {
+		u32 sram_addr         :15;
+		u32 sram_rw           : 1;   /* 0=write, 1=read */
+		u32 sram_data         : 8;
+		u32 sc_xfer_bit       : 1;
+		u32 reserved1         : 3;
+		u32 oe_pin_reg        : 1;
+		u32 ce_pin_reg        : 1;
+		u32 reserved2         : 1;
+		u32 start_sram_ibi    : 1;
+	} sram_ctrl_reg_700;
+
+	struct {
+		u32 net_addr_read     :16;
+		u32 net_addr_write    :16;
+	} net_buf_reg_704;
+
+	struct {
+		u32 cai_read          :11;
+		u32 reserved1         : 5;
+		u32 cai_write         :11;
+		u32 reserved2         : 6;
+		u32 cai_cnt           : 4;
+	} cai_buf_reg_708;
+
+	struct {
+		u32 cao_read          :11;
+		u32 reserved1         : 5;
+		u32 cap_write         :11;
+		u32 reserved2         : 6;
+		u32 cao_cnt           : 4;
+	} cao_buf_reg_70c;
+
+	struct {
+		u32 media_read        :11;
+		u32 reserved1         : 5;
+		u32 media_write       :11;
+		u32 reserved2         : 6;
+		u32 media_cnt         : 4;
+	} media_buf_reg_710;
+
+	struct {
+		u32 NET_Dest          : 2;
+		u32 CAI_Dest          : 2;
+		u32 CAO_Dest          : 2;
+		u32 MEDIA_Dest        : 2;
+		u32 net_ovflow_error  : 1;
+		u32 media_ovflow_error : 1;
+		u32 cai_ovflow_error  : 1;
+		u32 cao_ovflow_error  : 1;
+		u32 ctrl_usb_wan      : 1;
+		u32 ctrl_sramdma      : 1;
+		u32 ctrl_maximumfill  : 1;
+		u32 reserved          :17;
+	} sram_dest_reg_714;
+
+	struct {
+		u32 net_cnt           :12;
+		u32 reserved1         : 4;
+		u32 net_addr_read     : 1;
+		u32 reserved2         : 3;
+		u32 net_addr_write    : 1;
+		u32 reserved3         :11;
+	} net_buf_reg_718;
+
+	struct {
+		u32 wan_speed_sig     : 2;
+		u32 reserved1         : 6;
+		u32 wan_wait_state    : 8;
+		u32 sram_chip         : 2;
+		u32 sram_memmap       : 2;
+		u32 reserved2         : 4;
+		u32 wan_pkt_frame     : 4;
+		u32 reserved3         : 4;
+	} wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+extern flexcop_ibi_value ibi_zero;
+
+typedef enum {
+	FC_I2C_PORT_DEMOD  = 1,
+	FC_I2C_PORT_EEPROM = 2,
+	FC_I2C_PORT_TUNER  = 3,
+} flexcop_i2c_port_t;
+
+typedef enum {
+	FC_WRITE = 0,
+	FC_READ  = 1,
+} flexcop_access_op_t;
+
+typedef enum {
+	FC_SRAM_DEST_NET   = 1,
+	FC_SRAM_DEST_CAI   = 2,
+	FC_SRAM_DEST_CAO   = 4,
+	FC_SRAM_DEST_MEDIA = 8
+} flexcop_sram_dest_t;
+
+typedef enum {
+	FC_SRAM_DEST_TARGET_WAN_USB = 0,
+	FC_SRAM_DEST_TARGET_DMA1    = 1,
+	FC_SRAM_DEST_TARGET_DMA2    = 2,
+	FC_SRAM_DEST_TARGET_FC3_CA  = 3
+} flexcop_sram_dest_target_t;
+
+typedef enum {
+	FC_SRAM_2_32KB  = 0, /*  64KB */
+	FC_SRAM_1_32KB  = 1, /*  32KB - default fow FCII */
+	FC_SRAM_1_128KB = 2, /* 128KB */
+	FC_SRAM_1_48KB  = 3, /*  48KB - default for FCIII */
+} flexcop_sram_type_t;
+
+typedef enum {
+	FC_WAN_SPEED_4MBITS  = 0,
+	FC_WAN_SPEED_8MBITS  = 1,
+	FC_WAN_SPEED_12MBITS = 2,
+	FC_WAN_SPEED_16MBITS = 3,
+} flexcop_wan_speed_t;
+
+typedef enum {
+	FC_DMA_1 = 1,
+	FC_DMA_2 = 2,
+} flexcop_dma_index_t;
+
+typedef enum {
+	FC_DMA_SUBADDR_0 = 1,
+	FC_DMA_SUBADDR_1 = 2,
+} flexcop_dma_addr_index_t;
+
+/* names of the particular registers */
+typedef enum {
+	dma1_000            = 0x000,
+	dma1_004            = 0x004,
+	dma1_008            = 0x008,
+	dma1_00c            = 0x00c,
+	dma2_010            = 0x010,
+	dma2_014            = 0x014,
+	dma2_018            = 0x018,
+	dma2_01c            = 0x01c,
+
+	tw_sm_c_100         = 0x100,
+	tw_sm_c_104         = 0x104,
+	tw_sm_c_108         = 0x108,
+	tw_sm_c_10c         = 0x10c,
+	tw_sm_c_110         = 0x110,
+
+	lnb_switch_freq_200 = 0x200,
+	misc_204            = 0x204,
+	ctrl_208            = 0x208,
+	irq_20c             = 0x20c,
+	sw_reset_210        = 0x210,
+	misc_214            = 0x214,
+	mbox_v8_to_host_218 = 0x218,
+	mbox_host_to_v8_21c = 0x21c,
+
+	pid_filter_300      = 0x300,
+	pid_filter_304      = 0x304,
+	pid_filter_308      = 0x308,
+	pid_filter_30c      = 0x30c,
+	index_reg_310       = 0x310,
+	pid_n_reg_314       = 0x314,
+	mac_low_reg_318     = 0x318,
+	mac_high_reg_31c    = 0x31c,
+
+	data_tag_400        = 0x400,
+	card_id_408         = 0x408,
+	card_id_40c         = 0x40c,
+	mac_address_418     = 0x418,
+	mac_address_41c     = 0x41c,
+
+	ci_600              = 0x600,
+	pi_604              = 0x604,
+	pi_608              = 0x608,
+	dvb_reg_60c         = 0x60c,
+
+	sram_ctrl_reg_700   = 0x700,
+	net_buf_reg_704     = 0x704,
+	cai_buf_reg_708     = 0x708,
+	cao_buf_reg_70c     = 0x70c,
+	media_buf_reg_710   = 0x710,
+	sram_dest_reg_714   = 0x714,
+	net_buf_reg_718     = 0x718,
+	wan_ctrl_reg_71c    = 0x71c,
+} flexcop_ibi_register;
+
+#define flexcop_set_ibi_value(reg,attr,val) { \
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
+	v.reg.attr = val; \
+	fc->write_ibi_reg(fc,reg,v); \
+}
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-sram.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-sram.c - functions for controlling the SRAM.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
+{
+	flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
+}
+
+int flexcop_sram_init(struct flexcop_device *fc)
+{
+	switch (fc->rev) {
+		case FLEXCOP_II:
+		case FLEXCOP_IIB:
+			flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
+			break;
+		case FLEXCOP_III:
+			flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
+{
+	flexcop_ibi_value v;
+
+	v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+
+	if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
+		err("SRAM destination target to available on FlexCopII(b)\n");
+		return -EINVAL;
+	}
+
+	deb_sram("sram dest: %x target: %x\n",dest, target);
+
+	if (dest & FC_SRAM_DEST_NET)
+		v.sram_dest_reg_714.NET_Dest = target;
+	if (dest & FC_SRAM_DEST_CAI)
+		v.sram_dest_reg_714.CAI_Dest = target;
+	if (dest & FC_SRAM_DEST_CAO)
+		v.sram_dest_reg_714.CAO_Dest = target;
+	if (dest & FC_SRAM_DEST_MEDIA)
+		v.sram_dest_reg_714.MEDIA_Dest = target;
+
+	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+	udelay(1000); /* TODO delay really necessary */
+
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_sram_set_dest);
+
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
+{
+	flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
+}
+EXPORT_SYMBOL(flexcop_wan_set_speed);
+
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+	v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
+	v.sram_dest_reg_714.ctrl_sramdma = sramdma;
+	v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
+	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+}
+EXPORT_SYMBOL(flexcop_sram_ctrl);
+
+#if 0
+static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+	int i, retries;
+	u32 command;
+
+	for (i = 0; i < len; i++) {
+		command = bank | addr | 0x04000000 | (*buf << 0x10);
+
+		retries = 2;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __FUNCTION__);
+
+		write_reg_dw(adapter, 0x700, command);
+
+		buf++;
+		addr++;
+	}
+}
+
+static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+	int i, retries;
+	u32 command, value;
+
+	for (i = 0; i < len; i++) {
+		command = bank | addr | 0x04008000;
+
+		retries = 10000;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __FUNCTION__);
+
+		write_reg_dw(adapter, 0x700, command);
+
+		retries = 10000;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __FUNCTION__);
+
+		value = read_reg_dw(adapter, 0x700) >> 0x10;
+
+		*buf = (value & 0xff);
+
+		addr++;
+		buf++;
+	}
+}
+
+static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+	u32 bank;
+
+	bank = 0;
+
+	if (adapter->dw_sram_type == 0x20000) {
+		bank = (addr & 0x18000) << 0x0d;
+	}
+
+	if (adapter->dw_sram_type == 0x00000) {
+		if ((addr >> 0x0f) == 0)
+			bank = 0x20000000;
+		else
+			bank = 0x10000000;
+	}
+
+	flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+	u32 bank;
+
+	bank = 0;
+
+	if (adapter->dw_sram_type == 0x20000) {
+		bank = (addr & 0x18000) << 0x0d;
+	}
+
+	if (adapter->dw_sram_type == 0x00000) {
+		if ((addr >> 0x0f) == 0)
+			bank = 0x20000000;
+		else
+			bank = 0x10000000;
+	}
+
+	flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+	u32 length;
+
+	while (len != 0) {
+		length = len;
+
+		// check if the address range belongs to the same
+		// 32K memory chip. If not, the data is read from
+		// one chip at a time.
+		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+		}
+
+		sram_read_chunk(adapter, addr, buf, length);
+
+		addr = addr + length;
+		buf = buf + length;
+		len = len - length;
+	}
+}
+
+static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+	u32 length;
+
+	while (len != 0) {
+		length = len;
+
+		// check if the address range belongs to the same
+		// 32K memory chip. If not, the data is written to
+		// one chip at a time.
+		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+		}
+
+		sram_write_chunk(adapter, addr, buf, length);
+
+		addr = addr + length;
+		buf = buf + length;
+		len = len - length;
+	}
+}
+
+static void sram_set_size(struct adapter *adapter, u32 mask)
+{
+	write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
+}
+
+static void sram_init(struct adapter *adapter)
+{
+	u32 tmp;
+
+	tmp = read_reg_dw(adapter, 0x71c);
+
+	write_reg_dw(adapter, 0x71c, 1);
+
+	if (read_reg_dw(adapter, 0x71c) != 0) {
+		write_reg_dw(adapter, 0x71c, tmp);
+
+		adapter->dw_sram_type = tmp & 0x30000;
+
+		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+
+	} else {
+
+		adapter->dw_sram_type = 0x10000;
+
+		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+	}
+
+	/* return value is never used? */
+/*	return adapter->dw_sram_type; */
+}
+
+static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+{
+	u8 tmp1, tmp2;
+
+	dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
+
+	sram_set_size(adapter, mask);
+	sram_init(adapter);
+
+	tmp2 = 0xa5;
+	tmp1 = 0x4f;
+
+	sram_write(adapter, addr, &tmp2, 1);
+	sram_write(adapter, addr + 4, &tmp1, 1);
+
+	tmp2 = 0;
+
+	mdelay(20);
+
+	sram_read(adapter, addr, &tmp2, 1);
+	sram_read(adapter, addr, &tmp2, 1);
+
+	dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
+
+	if (tmp2 != 0xa5)
+		return 0;
+
+	tmp2 = 0x5a;
+	tmp1 = 0xf4;
+
+	sram_write(adapter, addr, &tmp2, 1);
+	sram_write(adapter, addr + 4, &tmp1, 1);
+
+	tmp2 = 0;
+
+	mdelay(20);
+
+	sram_read(adapter, addr, &tmp2, 1);
+	sram_read(adapter, addr, &tmp2, 1);
+
+	dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
+
+	if (tmp2 != 0x5a)
+		return 0;
+
+	return 1;
+}
+
+static u32 sram_length(struct adapter *adapter)
+{
+	if (adapter->dw_sram_type == 0x10000)
+		return 32768;	//  32K
+	if (adapter->dw_sram_type == 0x00000)
+		return 65536;	//  64K
+	if (adapter->dw_sram_type == 0x20000)
+		return 131072;	// 128K
+
+	return 32768;		// 32K
+}
+
+/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
+    - for 128K there are 4x32K chips at bank 0,1,2,3.
+    - for  64K there are 2x32K chips at bank 1,2.
+    - for  32K there is one 32K chip at bank 0.
+
+   FlexCop works only with one bank at a time. The bank is selected
+   by bits 28-29 of the 0x700 register.
+
+   bank 0 covers addresses 0x00000-0x07fff
+   bank 1 covers addresses 0x08000-0x0ffff
+   bank 2 covers addresses 0x10000-0x17fff
+   bank 3 covers addresses 0x18000-0x1ffff
+*/
+
+static int flexcop_sram_detect(struct flexcop_device *fc)
+{
+	flexcop_ibi_value r208,r71c_0,vr71c_1;
+
+	r208 = fc->read_ibi_reg(fc, ctrl_208);
+	fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
+
+	r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
+
+	write_reg_dw(adapter, 0x71c, 1);
+
+	tmp3 = read_reg_dw(adapter, 0x71c);
+
+	dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
+
+	write_reg_dw(adapter, 0x71c, tmp2);
+
+	// check for internal SRAM ???
+	tmp3--;
+	if (tmp3 != 0) {
+		sram_set_size(adapter, 0x10000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+
+		dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+		return 32;
+	}
+
+	if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
+		sram_set_size(adapter, 0x20000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+
+		dprintk("%s: sram size = 128K\n", __FUNCTION__);
+
+		return 128;
+	}
+
+	if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
+		sram_set_size(adapter, 0x00000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+
+		dprintk("%s: sram size = 64K\n", __FUNCTION__);
+
+		return 64;
+	}
+
+	if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
+		sram_set_size(adapter, 0x10000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+
+		dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+		return 32;
+	}
+
+	sram_set_size(adapter, 0x10000);
+	sram_init(adapter);
+	write_reg_dw(adapter, 0x208, tmp);
+
+	dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
+
+	return 0;
+}
+
+static void sll_detect_sram_size(struct adapter *adapter)
+{
+	sram_detect_for_flex2(adapter);
+}
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -0,0 +1,577 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-usb.c - covers the USB part.
+ *
+ * see flexcop.c for copyright information.
+ */
+
+#define FC_LOG_PREFIX "flexcop_usb"
+#include "flexcop-usb.h"
+#include "flexcop-common.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	    do { if ((debug & level)) { printk(args); } } while (0)
+#define debug_dump(b,l,method) {\
+	int i; \
+	for (i = 0; i < l; i++) method("%02x ", b[i]); \
+	method("\n");\
+}
+
+#define DEBSTATUS ""
+#else
+#define dprintk(level,args...)
+#define debug_dump(b,l,method)
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+#undef DEBSTATUS
+
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_ts(args...)   dprintk(0x02,args)
+#define deb_ctrl(args...) dprintk(0x04,args)
+#define deb_i2c(args...)  dprintk(0x08,args)
+#define deb_v8(args...)   dprintk(0x10,args)
+
+/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
+ * in the IBI address, to make the V8 code simpler.
+ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
+ *                  in general: 0000 0HHH 000L LL00
+ * IBI ADDRESS FORMAT:                    RHHH BLLL
+ *
+ * where R is the read(1)/write(0) bit, B is the busy bit
+ * and HHH and LLL are the two sets of three bits from the PCI address.
+ */
+#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+
+/*
+ * DKT 020228
+ * - forget about this VENDOR_BUFFER_SIZE, read and write register
+ *   deal with DWORD or 4 bytes, that should be should from now on
+ * - from now on, we don't support anything older than firm 1.00
+ *   I eliminated the write register as a 2 trip of writing hi word and lo word
+ *   and force this to write only 4 bytes at a time.
+ *   NOTE: this should work with all the firmware from 1.00 and newer
+ */
+static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
+{
+	struct flexcop_usb *fc_usb = fc->bus_specific;
+	u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
+	u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
+	u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0);
+
+	int len = usb_control_msg(fc_usb->udev,
+			read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
+			request,
+			request_type,  /* 0xc0 read or 0x40 write*/
+			wAddress,
+			0,
+			val,
+			sizeof(u32),
+			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+	if (len != sizeof(u32)) {
+		err("error while %s dword from %d (%d).",read ? "reading" : "writing",
+			wAddress,wRegOffsPCI);
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * DKT 010817 - add support for V8 memory read/write and flash update
+ */
+static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
+		flexcop_usb_request_t req, u8 page, u16 wAddress,
+		u8 *pbBuffer,u32 buflen)
+{
+//	u8 dwRequestType;
+	u8 request_type = USB_TYPE_VENDOR;
+	u16 wIndex;
+	int nWaitTime,pipe,len;
+
+	wIndex = page << 8;
+
+	switch (req) {
+		case B2C2_USB_READ_V8_MEM:
+			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+			request_type |= USB_DIR_IN;
+//			dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
+			pipe = B2C2_USB_CTRL_PIPE_IN;
+		break;
+		case B2C2_USB_WRITE_V8_MEM:
+			wIndex |= pbBuffer[0];
+			request_type |= USB_DIR_OUT;
+			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+//			dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
+			pipe = B2C2_USB_CTRL_PIPE_OUT;
+		break;
+		case B2C2_USB_FLASH_BLOCK:
+			request_type |= USB_DIR_OUT;
+			nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+//			dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
+			pipe = B2C2_USB_CTRL_PIPE_OUT;
+		break;
+		default:
+			deb_info("unsupported request for v8_mem_req %x.\n",req);
+		return -EINVAL;
+	}
+	deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req,
+			wAddress,wIndex,buflen);
+
+	len = usb_control_msg(fc_usb->udev,pipe,
+			req,
+			request_type,
+			wAddress,
+			wIndex,
+			pbBuffer,
+			buflen,
+			nWaitTime * HZ);
+
+	debug_dump(pbBuffer,len,deb_v8);
+
+	return len == buflen ? 0 : -EIO;
+}
+
+#define bytes_left_to_read_on_page(paddr,buflen) \
+			((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
+			? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
+
+static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req,
+		flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len)
+{
+	int i,ret = 0;
+	u16 wMax;
+	u32 pagechunk = 0;
+
+	switch(req) {
+		case B2C2_USB_READ_V8_MEM:  wMax = USB_MEM_READ_MAX; break;
+		case B2C2_USB_WRITE_V8_MEM:	wMax = USB_MEM_WRITE_MAX; break;
+		case B2C2_USB_FLASH_BLOCK:  wMax = USB_FLASH_MAX; break;
+		default:
+			return -EINVAL;
+		break;
+	}
+	for (i = 0; i < len;) {
+		pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len);
+		deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended));
+		if ((ret = flexcop_usb_v8_memory_req(fc_usb,req,
+				page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */
+				(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended),
+				&buf[i],pagechunk)) < 0)
+			return ret;
+
+		addr += pagechunk;
+		len -= pagechunk;
+	}
+	return 0;
+}
+
+static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
+{
+	return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,
+			V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->dvb_adapter.proposed_mac,6);
+}
+
+#if 0
+static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
+		flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
+		u16 buflen, u8 *pvBuffer)
+{
+	u16 wValue;
+	u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
+//	u8 dwRequestType = (u8) RTYPE_GENERIC,
+	int nWaitTime = 2,
+		pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
+		len;
+
+	wValue = (func << 8) | extra;
+
+	len = usb_control_msg(fc_usb->udev,pipe,
+			B2C2_USB_UTILITY,
+			request_type,
+			wValue,
+			wIndex,
+			pvBuffer,
+			buflen,
+			nWaitTime * HZ);
+	return len == buflen ? 0 : -EIO;
+}
+#endif
+
+/* usb i2c stuff */
+static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
+		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
+		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
+{
+	u16 wValue, wIndex;
+	int nWaitTime,pipe,len;
+//	u8 dwRequestType;
+	u8 request_type = USB_TYPE_VENDOR;
+
+	switch (func) {
+		case USB_FUNC_I2C_WRITE:
+		case USB_FUNC_I2C_MULTIWRITE:
+		case USB_FUNC_I2C_REPEATWRITE:
+		/* DKT 020208 - add this to support special case of DiSEqC */
+		case USB_FUNC_I2C_CHECKWRITE:
+			pipe = B2C2_USB_CTRL_PIPE_OUT;
+			nWaitTime = 2;
+//			dwRequestType = (u8) RTYPE_GENERIC;
+			request_type |= USB_DIR_OUT;
+		break;
+		case USB_FUNC_I2C_READ:
+		case USB_FUNC_I2C_REPEATREAD:
+			pipe = B2C2_USB_CTRL_PIPE_IN;
+			nWaitTime = 2;
+//			dwRequestType = (u8) RTYPE_GENERIC;
+			request_type |= USB_DIR_IN;
+		break;
+		default:
+			deb_info("unsupported function for i2c_req %x\n",func);
+			return -EINVAL;
+	}
+	wValue = (func << 8 ) | (port << 4);
+	wIndex = (chipaddr << 8 ) | addr;
+
+	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
+			((wValue && 0xff) << 8),wValue >> 8,((wIndex && 0xff) << 8),wIndex >> 8);
+
+	len = usb_control_msg(fc_usb->udev,pipe,
+			req,
+			request_type,
+			wValue,
+			wIndex,
+			buf,
+			buflen,
+			nWaitTime * HZ);
+
+	return len == buflen ? 0 : -EREMOTEIO;
+}
+
+/* actual bus specific access functions, make sure prototype are/will be equal to pci */
+static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg)
+{
+	flexcop_ibi_value val;
+	val.raw = 0;
+	flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1);
+	return val;
+}
+
+static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val)
+{
+	return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
+}
+
+static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
+		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+{
+	if (op == FC_READ)
+		return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len);
+	else
+		return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len);
+}
+
+static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
+{
+	u8 *b;
+	int l;
+
+	deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", fc_usb->tmp_buffer_length, buffer_length);
+
+	if (fc_usb->tmp_buffer_length > 0) {
+		memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, buffer_length);
+		fc_usb->tmp_buffer_length += buffer_length;
+		b = fc_usb->tmp_buffer;
+		l = fc_usb->tmp_buffer_length;
+	} else {
+		b=buffer;
+		l=buffer_length;
+	}
+
+	while (l >= 190) {
+		if (*b == 0xff)
+			switch (*(b+1) & 0x03) {
+				case 0x01: /* media packet */
+					if ( *(b+2) == 0x47 )
+						flexcop_pass_dmx_packets(fc_usb->fc_dev, b+2, 1);
+					else
+						deb_ts("not ts packet %02x %02x %02x %02x \n", *(b+2), *(b+3), *(b+4), *(b+5) );
+
+					b += 190;
+					l -= 190;
+				break;
+				default:
+					deb_ts("wrong packet type\n");
+					l = 0;
+				break;
+			}
+		else {
+			deb_ts("wrong header\n");
+			l = 0;
+		}
+	}
+
+	if (l>0)
+		memcpy(fc_usb->tmp_buffer, b, l);
+	fc_usb->tmp_buffer_length = l;
+}
+
+static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+	struct flexcop_usb *fc_usb = urb->context;
+	int i;
+
+	if (urb->actual_length > 0)
+		deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status);
+		} else
+			if (urb->iso_frame_desc[i].actual_length > 0) {
+				deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length);
+
+				flexcop_usb_process_frame(fc_usb,
+					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+		}
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+
+	usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
+{
+	/* submit/kill iso packets */
+	return 0;
+}
+
+static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
+{
+	int i;
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+		if (fc_usb->iso_urb[i] != NULL) {
+			deb_ts("unlinking/killing urb no. %d\n",i);
+			usb_kill_urb(fc_usb->iso_urb[i]);
+			usb_free_urb(fc_usb->iso_urb[i]);
+		}
+
+	if (fc_usb->iso_buffer != NULL)
+		pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr);
+}
+
+static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
+{
+	u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
+	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
+	int buffer_offset = 0;
+
+	deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
+			B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
+
+	fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr);
+	if (fc_usb->iso_buffer == NULL)
+		return -ENOMEM;
+	memset(fc_usb->iso_buffer, 0, bufsize);
+	fc_usb->buffer_size = bufsize;
+
+	/* creating iso urbs */
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+		if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
+			ret = -ENOMEM;
+			goto urb_error;
+		}
+	/* initialising and submitting iso urbs */
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+		int frame_offset = 0;
+		struct urb *urb = fc_usb->iso_urb[i];
+		deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
+
+		urb->dev = fc_usb->udev;
+		urb->context = fc_usb;
+		urb->complete = flexcop_usb_urb_complete;
+		urb->pipe = B2C2_USB_DATA_PIPE;
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->interval = 1;
+		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
+		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
+		urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
+
+		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
+		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
+			deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = frame_size;
+			frame_offset += frame_size;
+		}
+
+		if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+			err("submitting urb %d failed with %d.",i,ret);
+			goto urb_error;
+		}
+		deb_ts("submitted urb no. %d.\n",i);
+	}
+
+/* SRAM */
+
+	flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET |
+			FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB);
+	flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
+	flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
+
+	ret = 0;
+	goto success;
+urb_error:
+	flexcop_usb_transfer_exit(fc_usb);
+success:
+	return ret;
+}
+
+static int flexcop_usb_init(struct flexcop_usb *fc_usb)
+{
+	/* use the alternate setting with the larges buffer */
+	usb_set_interface(fc_usb->udev,0,1);
+	switch (fc_usb->udev->speed) {
+		case USB_SPEED_LOW:
+			err("cannot handle USB speed because it is to sLOW.");
+			return -ENODEV;
+			break;
+		case USB_SPEED_FULL:
+			info("running at FULL speed.");
+			break;
+		case USB_SPEED_HIGH:
+			info("running at HIGH speed.");
+			break;
+		case USB_SPEED_UNKNOWN: /* fall through */
+		default:
+			err("cannot handle USB speed because it is unkown.");
+			return -ENODEV;
+	}
+	usb_set_intfdata(fc_usb->uintf, fc_usb);
+	return 0;
+}
+
+static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
+{
+	usb_set_intfdata(fc_usb->uintf, NULL);
+}
+
+static int flexcop_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct flexcop_usb *fc_usb = NULL;
+	struct flexcop_device *fc = NULL;
+	int ret;
+
+	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
+		err("out of memory\n");
+		return -ENOMEM;
+	}
+
+/* general flexcop init */
+	fc_usb = fc->bus_specific;
+	fc_usb->fc_dev = fc;
+
+	fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
+	fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
+	fc->i2c_request = flexcop_usb_i2c_request;
+	fc->get_mac_addr = flexcop_usb_get_mac_addr;
+
+	fc->stream_control = flexcop_usb_stream_control;
+
+	fc->pid_filtering = 1;
+	fc->bus_type = FC_USB;
+
+	fc->dev = &udev->dev;
+	fc->owner = THIS_MODULE;
+
+/* bus specific part */
+	fc_usb->udev = udev;
+	fc_usb->uintf = intf;
+	if ((ret = flexcop_usb_init(fc_usb)) != 0)
+		goto err_kfree;
+
+/* init flexcop */
+	if ((ret = flexcop_device_initialize(fc)) != 0)
+		goto err_usb_exit;
+
+/* xfer init */
+	if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
+		goto err_fc_exit;
+
+	info("%s successfully initialized and connected.",DRIVER_NAME);
+	ret = 0;
+	goto success;
+err_fc_exit:
+	flexcop_device_exit(fc);
+err_usb_exit:
+	flexcop_usb_exit(fc_usb);
+err_kfree:
+	flexcop_device_kfree(fc);
+success:
+	return ret;
+}
+
+static void flexcop_usb_disconnect(struct usb_interface *intf)
+{
+	struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
+	flexcop_usb_transfer_exit(fc_usb);
+	flexcop_device_exit(fc_usb->fc_dev);
+	flexcop_usb_exit(fc_usb);
+	flexcop_device_kfree(fc_usb->fc_dev);
+	info("%s successfully deinitialized and disconnected.",DRIVER_NAME);
+}
+
+static struct usb_device_id flexcop_usb_table [] = {
+	    { USB_DEVICE(0x0af7, 0x0101) },
+	    { }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver flexcop_usb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "Technisat/B2C2 FlexCop II/IIb/III USB",
+	.probe		= flexcop_usb_probe,
+	.disconnect = flexcop_usb_disconnect,
+	.id_table	= flexcop_usb_table,
+};
+
+/* module stuff */
+static int __init flexcop_usb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&flexcop_usb_driver))) {
+		err("usb_register failed. (%d)",result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit flexcop_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&flexcop_usb_driver);
+}
+
+module_init(flexcop_usb_module_init);
+module_exit(flexcop_usb_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-usb.h
@@ -0,0 +1,119 @@
+#ifndef __FLEXCOP_USB_H_INCLUDED__
+#define __FLEXCOP_USB_H_INCLUDED__
+
+#include <linux/usb.h>
+
+/* transfer parameters */
+#define B2C2_USB_FRAMES_PER_ISO		4
+#define B2C2_USB_NUM_ISO_URB		4
+
+#define B2C2_USB_CTRL_PIPE_IN		usb_rcvctrlpipe(fc_usb->udev,0)
+#define B2C2_USB_CTRL_PIPE_OUT		usb_sndctrlpipe(fc_usb->udev,0)
+#define B2C2_USB_DATA_PIPE			usb_rcvisocpipe(fc_usb->udev,0x81)
+
+struct flexcop_usb {
+	struct usb_device *udev;
+	struct usb_interface *uintf;
+
+	u8 *iso_buffer;
+	int buffer_size;
+	dma_addr_t dma_addr;
+	struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+
+	struct flexcop_device *fc_dev;
+
+	u8 tmp_buffer[1023+190];
+	int tmp_buffer_length;
+};
+
+#if 0
+/* request types TODO What is its use?*/
+typedef enum {
+
+/* something is wrong with this part
+	RTYPE_READ_DW         = (1 << 6),
+	RTYPE_WRITE_DW_1      = (3 << 6),
+	RTYPE_READ_V8_MEMORY  = (6 << 6),
+	RTYPE_WRITE_V8_MEMORY = (7 << 6),
+	RTYPE_WRITE_V8_FLASH  = (8 << 6),
+	RTYPE_GENERIC         = (9 << 6),
+*/
+} flexcop_usb_request_type_t;
+#endif
+
+/* request */
+typedef enum {
+	B2C2_USB_WRITE_V8_MEM = 0x04,
+	B2C2_USB_READ_V8_MEM  = 0x05,
+	B2C2_USB_READ_REG     = 0x08,
+	B2C2_USB_WRITE_REG    = 0x0A,
+/*	B2C2_USB_WRITEREGLO   = 0x0A, */
+	B2C2_USB_WRITEREGHI   = 0x0B,
+	B2C2_USB_FLASH_BLOCK  = 0x10,
+	B2C2_USB_I2C_REQUEST  = 0x11,
+	B2C2_USB_UTILITY      = 0x12,
+} flexcop_usb_request_t;
+
+/* function definition for I2C_REQUEST */
+typedef enum {
+	USB_FUNC_I2C_WRITE       = 0x01,
+	USB_FUNC_I2C_MULTIWRITE  = 0x02,
+	USB_FUNC_I2C_READ        = 0x03,
+	USB_FUNC_I2C_REPEATWRITE = 0x04,
+	USB_FUNC_GET_DESCRIPTOR  = 0x05,
+	USB_FUNC_I2C_REPEATREAD  = 0x06,
+/* DKT 020208 - add this to support special case of DiSEqC */
+	USB_FUNC_I2C_CHECKWRITE  = 0x07,
+	USB_FUNC_I2C_CHECKRESULT = 0x08,
+} flexcop_usb_i2c_function_t;
+
+/*
+ * function definition for UTILITY request 0x12
+ * DKT 020304 - new utility function
+ */
+typedef enum {
+	UTILITY_SET_FILTER          = 0x01,
+	UTILITY_DATA_ENABLE         = 0x02,
+	UTILITY_FLEX_MULTIWRITE     = 0x03,
+	UTILITY_SET_BUFFER_SIZE     = 0x04,
+	UTILITY_FLEX_OPERATOR       = 0x05,
+	UTILITY_FLEX_RESET300_START = 0x06,
+	UTILITY_FLEX_RESET300_STOP  = 0x07,
+	UTILITY_FLEX_RESET300       = 0x08,
+	UTILITY_SET_ISO_SIZE        = 0x09,
+	UTILITY_DATA_RESET          = 0x0A,
+	UTILITY_GET_DATA_STATUS     = 0x10,
+	UTILITY_GET_V8_REG          = 0x11,
+/* DKT 020326 - add function for v1.14 */
+	UTILITY_SRAM_WRITE          = 0x12,
+	UTILITY_SRAM_READ           = 0x13,
+	UTILITY_SRAM_TESTFILL       = 0x14,
+	UTILITY_SRAM_TESTSET        = 0x15,
+	UTILITY_SRAM_TESTVERIFY     = 0x16,
+} flexcop_usb_utility_function_t;
+
+#define B2C2_WAIT_FOR_OPERATION_RW  1*HZ       /* 1 s */
+#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ       /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ       /* 1 s */
+
+#define B2C2_WAIT_FOR_OPERATION_V8READ   3*HZ  /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE  3*HZ  /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH  3*HZ  /* 3 s */
+
+typedef enum {
+	V8_MEMORY_PAGE_DVB_CI = 0x20,
+	V8_MEMORY_PAGE_DVB_DS = 0x40,
+	V8_MEMORY_PAGE_MULTI2 = 0x60,
+	V8_MEMORY_PAGE_FLASH  = 0x80
+} flexcop_usb_mem_page_t;
+
+#define V8_MEMORY_EXTENDED      (1 << 15)
+
+#define USB_MEM_READ_MAX                32
+#define USB_MEM_WRITE_MAX               1
+#define USB_FLASH_MAX                   8
+
+#define V8_MEMORY_PAGE_SIZE     0x8000      // 32K
+#define V8_MEMORY_PAGE_MASK     0x7FFF
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -0,0 +1,286 @@
+/*
+ * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * based on the skystar2-driver
+ * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
+ *
+ * Acknowledgements:
+ *     John Jurrius from BBTI, Inc. for extensive support with
+ *         code examples and data books
+ *
+ *     Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
+ *
+ * Contributions to the skystar2-driver have been done by
+ *     Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
+ *     Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
+ *     Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering)
+ *
+ *
+ * This program 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.
+ *
+ * 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 Lesser 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 "flexcop.h"
+
+#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
+
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define DEBSTATUS ""
+#else
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+int b2c2_flexcop_debug;
+module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS);
+#undef DEBSTATUS
+
+/* global zero for ibi values */
+flexcop_ibi_value ibi_zero;
+
+static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+	return flexcop_pid_feed_control(fc,dvbdmxfeed,1);
+}
+
+static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+	return flexcop_pid_feed_control(fc,dvbdmxfeed,0);
+}
+
+static int flexcop_dvb_init(struct flexcop_device *fc)
+{
+	int ret;
+	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+		err("error registering DVB adapter");
+		return ret;
+	}
+	fc->dvb_adapter.priv = fc;
+
+	fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	fc->demux.priv = fc;
+
+	fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
+
+	fc->demux.start_feed = flexcop_dvb_start_feed;
+	fc->demux.stop_feed = flexcop_dvb_stop_feed;
+	fc->demux.write_to_decoder = NULL;
+
+	if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
+		err("dvb_dmx failed: error %d",ret);
+		goto err_dmx;
+	}
+
+	fc->hw_frontend.source = DMX_FRONTEND_0;
+
+	fc->dmxdev.filternum = fc->demux.feednum;
+	fc->dmxdev.demux = &fc->demux.dmx;
+	fc->dmxdev.capabilities = 0;
+	if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
+		err("dvb_dmxdev_init failed: error %d",ret);
+		goto err_dmx_dev;
+	}
+
+	if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+		err("adding hw_frontend to dmx failed: error %d",ret);
+		goto err_dmx_add_hw_frontend;
+	}
+
+	fc->mem_frontend.source = DMX_MEMORY_FE;
+	if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
+		err("adding mem_frontend to dmx failed: error %d",ret);
+		goto err_dmx_add_mem_frontend;
+	}
+
+	if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+		err("connect frontend failed: error %d",ret);
+		goto err_connect_frontend;
+	}
+
+	dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+
+	fc->init_state |= FC_STATE_DVB_INIT;
+	goto success;
+
+err_connect_frontend:
+	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
+err_dmx_add_mem_frontend:
+	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
+err_dmx_add_hw_frontend:
+	dvb_dmxdev_release(&fc->dmxdev);
+err_dmx_dev:
+	dvb_dmx_release(&fc->demux);
+err_dmx:
+	dvb_unregister_adapter(&fc->dvb_adapter);
+	return ret;
+
+success:
+	return 0;
+}
+
+static void flexcop_dvb_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_DVB_INIT) {
+		dvb_net_release(&fc->dvbnet);
+
+		fc->demux.dmx.close(&fc->demux.dmx);
+		fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
+		fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
+		dvb_dmxdev_release(&fc->dmxdev);
+		dvb_dmx_release(&fc->demux);
+		dvb_unregister_adapter(&fc->dvb_adapter);
+
+		deb_info("deinitialized dvb stuff\n");
+	}
+	fc->init_state &= ~FC_STATE_DVB_INIT;
+}
+
+/* these methods are necessary to achieve the long-term-goal of hiding the
+ * struct flexcop_device from the bus-parts */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
+{
+	dvb_dmx_swfilter(&fc->demux, buf, len);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_data);
+
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
+{
+	dvb_dmx_swfilter_packets(&fc->demux, buf, no);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_packets);
+
+static void flexcop_reset(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v210,v204;
+
+/* reset the flexcop itself */
+	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+	v210.raw = 0;
+	v210.sw_reset_210.reset_blocks = 0xff;
+	v210.sw_reset_210.Block_reset_enable = 0xb2;
+	fc->write_ibi_reg(fc,sw_reset_210,v210);
+
+/* reset the periphical devices */
+
+	v204 = fc->read_ibi_reg(fc,misc_204);
+	v204.misc_204.Per_reset_sig = 0;
+	fc->write_ibi_reg(fc,misc_204,v204);
+	v204.misc_204.Per_reset_sig = 1;
+	fc->write_ibi_reg(fc,misc_204,v204);
+}
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
+{
+	void *bus;
+	struct flexcop_device *fc = kmalloc(sizeof(struct flexcop_device), GFP_KERNEL);
+	if (!fc) {
+		err("no memory");
+		return NULL;
+	}
+	memset(fc, 0, sizeof(struct flexcop_device));
+
+	bus = kmalloc(bus_specific_len, GFP_KERNEL);
+	if (!bus) {
+		err("no memory");
+		kfree(fc);
+		return NULL;
+	}
+	memset(bus, 0, bus_specific_len);
+
+	fc->bus_specific = bus;
+
+	return fc;
+}
+EXPORT_SYMBOL(flexcop_device_kmalloc);
+
+void flexcop_device_kfree(struct flexcop_device *fc)
+{
+	kfree(fc->bus_specific);
+	kfree(fc);
+}
+EXPORT_SYMBOL(flexcop_device_kfree);
+
+int flexcop_device_initialize(struct flexcop_device *fc)
+{
+	int ret;
+	ibi_zero.raw = 0;
+
+	flexcop_reset(fc);
+	flexcop_determine_revision(fc);
+	flexcop_sram_init(fc);
+	flexcop_hw_filter_init(fc);
+
+	flexcop_smc_ctrl(fc, 0);
+
+	if ((ret = flexcop_dvb_init(fc)))
+		goto error;
+
+	/* do the MAC address reading after initializing the dvb_adapter */
+	if (fc->get_mac_addr(fc, 0) == 0) {
+		u8 *b = fc->dvb_adapter.proposed_mac;
+		info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]);
+		flexcop_set_mac_filter(fc,b);
+		flexcop_mac_filter_ctrl(fc,1);
+	} else
+		warn("reading of MAC address failed.\n");
+
+
+	if ((ret = flexcop_i2c_init(fc)))
+		goto error;
+
+	if ((ret = flexcop_frontend_init(fc)))
+		goto error;
+
+	flexcop_device_name(fc,"initialization of","complete");
+
+	ret = 0;
+	goto success;
+error:
+	flexcop_device_exit(fc);
+success:
+	return ret;
+}
+EXPORT_SYMBOL(flexcop_device_initialize);
+
+void flexcop_device_exit(struct flexcop_device *fc)
+{
+	flexcop_frontend_exit(fc);
+	flexcop_i2c_exit(fc);
+	flexcop_dvb_exit(fc);
+}
+EXPORT_SYMBOL(flexcop_device_exit);
+
+static int flexcop_module_init(void)
+{
+	info(DRIVER_NAME " loaded successfully");
+	return 0;
+}
+
+static void flexcop_module_cleanup(void)
+{
+	info(DRIVER_NAME " unloaded successfully");
+}
+
+module_init(flexcop_module_init);
+module_exit(flexcop_module_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop.h - private header file for all flexcop-chip-source files.
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_H__
+#define __FLEXCOP_H___
+
+#define FC_LOG_PREFIX "b2c2-flexcop"
+#include "flexcop-common.h"
+
+extern int b2c2_flexcop_debug;
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
+#else
+#define dprintk(level,args...)
+#endif
+
+#define deb_info(args...)  dprintk(0x01,args)
+#define deb_tuner(args...) dprintk(0x02,args)
+#define deb_i2c(args...)   dprintk(0x04,args)
+#define deb_ts(args...)    dprintk(0x08,args)
+#define deb_sram(args...)  dprintk(0x10,args)
+
+#endif
diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c
--- a/drivers/media/dvb/b2c2/skystar2.c
+++ b/drivers/media/dvb/b2c2/skystar2.c
@@ -5,14 +5,14 @@
  * Copyright (C) 2003  Vadim Catana, skystar@moldova.cc
  *
  * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped 
+ * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
  *     Vincenzo Di Massa, hawk.it at tiscalinet.it
- * 	
+ *
  * Converted to Linux coding style
  * Misc reorganization, polishing, restyling
- *     Roberto Ragusa, r.ragusa at libero.it
- *       
- * Added hardware filtering support, 
+ *     Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it
+ *
+ * Added hardware filtering support,
  *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
  *
  *
@@ -97,7 +97,7 @@ struct adapter {
 	u8 mac_addr[8];
 	u32 dw_sram_type;
 
-	struct dvb_adapter *dvb_adapter;
+	struct dvb_adapter dvb_adapter;
 	struct dvb_demux demux;
 	struct dmxdev dmxdev;
 	struct dmx_frontend hw_frontend;
@@ -231,8 +231,8 @@ static void fixchipaddr(u32 device, u32 
 {
 	if (device == 0x20000000)
 		*ret = bus | ((addr >> 8) & 3);
-
-	*ret = bus;
+	else
+		*ret = bus;
 }
 
 static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
@@ -293,7 +293,7 @@ static u32 flex_i2c_write(struct adapter
 	return buf - start;
 }
 
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int num)
+static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num)
 {
 	struct adapter *tmp = i2c_get_adapdata(adapter);
 	int i, ret = 0;
@@ -1968,7 +1968,7 @@ static int driver_initialize(struct pci_
 		ctrl_enable_mac(adapter, 1);
 	}
 
-	adapter->lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&adapter->lock);
 
 out:
 	return ret;
@@ -1996,10 +1996,6 @@ static void driver_halt(struct pci_dev *
 	free_adapter_object(adapter);
 
 	pci_set_drvdata(pdev, NULL);
-
-	pci_disable_device(pdev);
-	pci_release_region(pdev, 1);
-	pci_release_region(pdev, 0);
 }
 
 static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
@@ -2356,7 +2352,7 @@ static int samsung_tdtc9251dh0_demod_ini
 	return 0;
 }
 
-int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
 {
 	u32 div;
 	unsigned char bs = 0;
@@ -2465,7 +2461,7 @@ static void frontend_init(struct adapter
 		       skystar2->pdev->subsystem_vendor,
 		       skystar2->pdev->subsystem_device);
 	} else {
-		if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) {
+		if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) {
 			printk("skystar2: Frontend registration failed!\n");
 			if (skystar2->fe->ops->release)
 				skystar2->fe->ops->release(skystar2->fe);
@@ -2490,17 +2486,17 @@ static int skystar2_probe(struct pci_dev
 	if (ret < 0)
 		goto out;
 
-	ret = dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name,
+	adapter = pci_get_drvdata(pdev);
+	dvb_adapter = &adapter->dvb_adapter;
+
+	ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name,
 				   THIS_MODULE);
 	if (ret < 0) {
 		printk("%s: Error registering DVB adapter\n", __FUNCTION__);
 		goto err_halt;
 	}
 
-	adapter = pci_get_drvdata(pdev);
-
 	dvb_adapter->priv = adapter;
-	adapter->dvb_adapter = dvb_adapter;
 
 
 	init_MUTEX(&adapter->i2c_sem);
@@ -2545,7 +2541,7 @@ static int skystar2_probe(struct pci_dev
 	adapter->dmxdev.demux = dmx;
 	adapter->dmxdev.capabilities = 0;
 
-	ret = dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter);
+	ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter);
 	if (ret < 0)
 		goto err_dmx_release;
 
@@ -2563,7 +2559,7 @@ static int skystar2_probe(struct pci_dev
 	if (ret < 0)
 		goto err_remove_mem_frontend;
 
-	dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
+	dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
 
 	frontend_init(adapter);
 out:
@@ -2580,7 +2576,7 @@ err_dmx_release:
 err_i2c_del:
 	i2c_del_adapter(&adapter->i2c_adap);
 err_dvb_unregister:
-	dvb_unregister_adapter(adapter->dvb_adapter);
+	dvb_unregister_adapter(&adapter->dvb_adapter);
 err_halt:
 	driver_halt(pdev);
 	goto out;
@@ -2609,7 +2605,7 @@ static void skystar2_remove(struct pci_d
 	if (adapter->fe != NULL)
 		dvb_unregister_frontend(adapter->fe);
 
-	dvb_unregister_adapter(adapter->dvb_adapter);
+	dvb_unregister_adapter(&adapter->dvb_adapter);
 
 			i2c_del_adapter(&adapter->i2c_adap);
 
@@ -2633,7 +2629,7 @@ static struct pci_driver skystar2_pci_dr
 
 static int skystar2_init(void)
 {
-	return pci_module_init(&skystar2_pci_driver);
+	return pci_register_driver(&skystar2_pci_driver);
 }
 
 static void skystar2_cleanup(void)
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -5,13 +5,14 @@ config DVB_BT8XX
 	select DVB_SP887X
 	select DVB_NXT6000
 	select DVB_CX24110
+	select DVB_OR51211
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
-	  the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
+	  the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and
+	  pcHDTV HD2000 cards.
 
-          Since these cards have no MPEG decoder onboard, they transmit
+	  Since these cards have no MPEG decoder onboard, they transmit
 	  only compressed MPEG data over the PCI bus, so you need
 	  an external software decoder to watch TV on your computer.
 
 	  Say Y if you own such a device and want to use it.
-
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,5 +1,3 @@
-
-obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o
+obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
-
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -4,27 +4,27 @@
  * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de>
  *
  * large parts based on the bttv driver
- * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
- *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@metzlerbros.de)
+ *                        & Marcus Metzler (mocm@metzlerbros.de)
  * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.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.
- * 
+ *
 
  * 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  */
 
 #include <linux/module.h>
@@ -55,10 +55,10 @@ static unsigned int bt878_verbose = 1;
 static unsigned int bt878_debug;
 
 module_param_named(verbose, bt878_verbose, int, 0444);
-MODULE_PARM_DESC(bt878_verbose,
+MODULE_PARM_DESC(verbose,
 		 "verbose startup messages, default is 1 (yes)");
 module_param_named(debug, bt878_debug, int, 0644);
-MODULE_PARM_DESC(bt878_debug, "Turn on/off debugging (default:off).");
+MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
 
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
@@ -128,21 +128,21 @@ static int bt878_mem_alloc(struct bt878 
 }
 
 /* RISC instructions */
-#define RISC_WRITE        	(0x01 << 28)
-#define RISC_JUMP         	(0x07 << 28)
-#define RISC_SYNC         	(0x08 << 28)
+#define RISC_WRITE		(0x01 << 28)
+#define RISC_JUMP		(0x07 << 28)
+#define RISC_SYNC		(0x08 << 28)
 
 /* RISC bits */
-#define RISC_WR_SOL       	(1 << 27)
-#define RISC_WR_EOL       	(1 << 26)
-#define RISC_IRQ          	(1 << 24)
+#define RISC_WR_SOL		(1 << 27)
+#define RISC_WR_EOL		(1 << 26)
+#define RISC_IRQ		(1 << 24)
 #define RISC_STATUS(status)	((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
-#define RISC_SYNC_RESYNC  	(1 << 15)
-#define RISC_SYNC_FM1     	0x06
-#define RISC_SYNC_VRO     	0x0C
+#define RISC_SYNC_RESYNC	(1 << 15)
+#define RISC_SYNC_FM1		0x06
+#define RISC_SYNC_VRO		0x0C
 
 #define RISC_FLUSH()		bt->risc_pos = 0
-#define RISC_INSTR(instr) 	bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
+#define RISC_INSTR(instr)	bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
 
 static int bt878_make_risc(struct bt878 *bt)
 {
@@ -173,7 +173,7 @@ static void bt878_risc_program(struct bt
 	RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
 	RISC_INSTR(0);
 
-	dprintk("bt878: risc len lines %u, bytes per line %u\n", 
+	dprintk("bt878: risc len lines %u, bytes per line %u\n",
 			bt->line_count, bt->line_bytes);
 	for (line = 0; line < bt->line_count; line++) {
 		// At the beginning of every block we issue an IRQ with previous (finished) block number set
@@ -228,14 +228,14 @@ void bt878_start(struct bt878 *bt, u32 c
 	 * Hacked for DST to:
 	 * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
 	 */
-	int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | 
-		BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | 
+	int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
+		BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
 		BT878_AFBUS | BT878_ARISCI;
 
 
 	/* ignore pesky bits */
 	int_mask &= ~irq_err_ignore;
-	
+
 	btwrite(int_mask, BT878_AINT_MASK);
 	btwrite(controlreg, BT878_AGPIO_DMA_CTL);
 }
@@ -381,21 +381,6 @@ bt878_device_control(struct bt878 *bt, u
 
 EXPORT_SYMBOL(bt878_device_control);
 
-struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adapter)
-{
-	unsigned int card_nr;
-	
-	printk("bt878 find by dvb adap: checking \"%s\"\n",adapter->name);
-	for (card_nr = 0; card_nr < bt878_num; card_nr++) {
-		if (bt878[card_nr].adapter == adapter)
-			return &bt878[card_nr];
-	}
-	printk("bt878 find by dvb adap: NOT found \"%s\"\n",adapter->name);
-	return NULL;
-}
-
-EXPORT_SYMBOL(bt878_find_by_i2c_adap);
-
 /***********************/
 /* PCI device handling */
 /***********************/
@@ -476,9 +461,9 @@ static int __devinit bt878_probe(struct 
 	pci_set_drvdata(dev, bt);
 
 /*        if(init_bt878(btv) < 0) {
-                bt878_remove(dev);
-                return -EIO;
-        }
+		bt878_remove(dev);
+		return -EIO;
+	}
 */
 
 	if ((result = bt878_mem_alloc(bt))) {
@@ -551,10 +536,10 @@ static struct pci_device_id bt878_pci_tb
 MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
 
 static struct pci_driver bt878_pci_driver = {
-      .name 	= "bt878",
+      .name	= "bt878",
       .id_table = bt878_pci_tbl,
-      .probe 	= bt878_probe,
-      .remove 	= bt878_remove,
+      .probe	= bt878_probe,
+      .remove	= bt878_remove,
 };
 
 static int bt878_pci_driver_registered = 0;
@@ -573,12 +558,12 @@ static int bt878_init_module(void)
 	       (BT878_VERSION_CODE >> 8) & 0xff,
 	       BT878_VERSION_CODE & 0xff);
 /*
-        bt878_check_chipset();
+	bt878_check_chipset();
 */
 	/* later we register inside of bt878_find_audio_dma()
 	 * because we may want to ignore certain cards */
 	bt878_pci_driver_registered = 1;
-	return pci_module_init(&bt878_pci_driver);
+	return pci_register_driver(&bt878_pci_driver);
 }
 
 static void bt878_cleanup_module(void)
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -1,4 +1,4 @@
-/* 
+/*
     bt878.h - Bt878 audio module (register offsets)
 
     Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de>
@@ -89,7 +89,6 @@
 #define BT878_RISC_SYNC_MASK	(1 << 15)
 
 extern int bt878_num;
-extern struct bt878 bt878[BT878_MAX];
 
 struct bt878 {
 	struct semaphore  gpio_lock;
@@ -121,12 +120,14 @@ struct bt878 {
 	u32 risc_pos;
 
 	struct tasklet_struct tasklet;
-	int shutdown;	
+	int shutdown;
 };
 
+extern struct bt878 bt878[BT878_MAX];
+
 void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
 		u32 irq_err_ignore);
-void bt878_stop(struct bt878 *bt);	     
+void bt878_stop(struct bt878 *bt);
 
 #if defined(__powerpc__)	/* big-endian */
 extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1,25 +1,25 @@
 /*
-    Frontend-driver for TwinHan DST Frontend
-
-    Copyright (C) 2003 Jamie Honan
-
-    This program is free software; you can redistribute it 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.
 
+	Frontend/Card driver for TwinHan DST Frontend
+	Copyright (C) 2003 Jamie Honan
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -31,59 +31,22 @@
 
 #include "dvb_frontend.h"
 #include "dst_priv.h"
-#include "dst.h"
+#include "dst_common.h"
 
-struct dst_state {
 
-	struct i2c_adapter* i2c;
+static unsigned int verbose = 1;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
 
-	struct bt878* bt;
+static unsigned int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug messages, default is 0 (yes)");
 
-	struct dvb_frontend_ops ops;
-
-	/* configuration settings */
-	const struct dst_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* private demodulator data */
-	u8 tx_tuna[10];
-	u8 rx_tuna[10];
-	u8 rxbuffer[10];
-	u8 diseq_flags;
-	u8 dst_type;
-	u32 type_flags;
-	u32 frequency;		/* intermediate frequency in kHz for QPSK */
-	fe_spectral_inversion_t inversion;
-	u32 symbol_rate;	/* symbol rate in Symbols per second */
-	fe_code_rate_t fec;
-	fe_sec_voltage_t voltage;
-	fe_sec_tone_mode_t tone;
-	u32 decode_freq;
-	u8 decode_lock;
-	u16 decode_strength;
-	u16 decode_snr;
-	unsigned long cur_jiff;
-	u8 k22;
-	fe_bandwidth_t bandwidth;
-};
+static unsigned int dst_addons;
+module_param(dst_addons, int, 0644);
+MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 
-static unsigned int dst_verbose = 0;
-module_param(dst_verbose, int, 0644);
-MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
-static unsigned int dst_debug = 0;
-module_param(dst_debug, int, 0644);
-MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
-
-#define dprintk	if (dst_debug) printk
-
-#define DST_TYPE_IS_SAT		0
-#define DST_TYPE_IS_TERR	1
-#define DST_TYPE_IS_CABLE	2
-
-#define DST_TYPE_HAS_NEWTUNE	1
-#define DST_TYPE_HAS_TS204	2
-#define DST_TYPE_HAS_SYMDIV	4
+#define dprintk	if (debug) printk
 
 #define HAS_LOCK	1
 #define ATTEMPT_TUNE	2
@@ -97,7 +60,7 @@ static void dst_packsize(struct dst_stat
 	bt878_device_control(state->bt, DST_IG_TS, &bits);
 }
 
-static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh)
+int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay)
 {
 	union dst_gpio_packet enb;
 	union dst_gpio_packet bits;
@@ -105,26 +68,33 @@ static int dst_gpio_outb(struct dst_stat
 
 	enb.enb.mask = mask;
 	enb.enb.enable = enbb;
+	if (verbose > 4)
+		dprintk("%s: mask=[%04x], enbb=[%04x], outhigh=[%04x]\n", __FUNCTION__, mask, enbb, outhigh);
+
 	if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
-		dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
+		dprintk("%s: dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", __FUNCTION__, err, mask, enbb);
 		return -EREMOTEIO;
 	}
-
+	udelay(1000);
 	/* because complete disabling means no output, no need to do output packet */
 	if (enbb == 0)
 		return 0;
 
+	if (delay)
+		msleep(10);
+
 	bits.outp.mask = enbb;
 	bits.outp.highvals = outhigh;
 
 	if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
-		dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
+		dprintk("%s: dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n", __FUNCTION__, err, enbb, outhigh);
 		return -EREMOTEIO;
 	}
 	return 0;
 }
+EXPORT_SYMBOL(dst_gpio_outb);
 
-static int dst_gpio_inb(struct dst_state *state, u8 * result)
+int dst_gpio_inb(struct dst_state *state, u8 * result)
 {
 	union dst_gpio_packet rd_packet;
 	int err;
@@ -139,143 +109,225 @@ static int dst_gpio_inb(struct dst_state
 	*result = (u8) rd_packet.rd.value;
 	return 0;
 }
+EXPORT_SYMBOL(dst_gpio_inb);
 
-#define DST_I2C_ENABLE	1
-#define DST_8820  	2
-
-static int dst_reset8820(struct dst_state *state)
+int rdc_reset_state(struct dst_state *state)
 {
-	int retval;
-	/* pull 8820 gpio pin low, wait, high, wait, then low */
-	// dprintk ("%s: reset 8820\n", __FUNCTION__);
-	retval = dst_gpio_outb(state, DST_8820, DST_8820, 0);
-	if (retval < 0)
-		return retval;
+	if (verbose > 1)
+		dprintk("%s: Resetting state machine\n", __FUNCTION__);
+
+	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		return -1;
+	}
+
 	msleep(10);
-	retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820);
-	if (retval < 0)
-		return retval;
-	/* wait for more feedback on what works here *
-	   msleep(10);
-	   retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
-	   if (retval < 0)
-	   return retval;
-	 */
+
+	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		msleep(10);
+		return -1;
+	}
+
 	return 0;
 }
+EXPORT_SYMBOL(rdc_reset_state);
 
-static int dst_i2c_enable(struct dst_state *state)
+int rdc_8820_reset(struct dst_state *state)
 {
-	int retval;
-	/* pull I2C enable gpio pin low, wait */
-	// dprintk ("%s: i2c enable\n", __FUNCTION__);
-	retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0);
-	if (retval < 0)
-		return retval;
-	// dprintk ("%s: i2c enable delay\n", __FUNCTION__);
-	msleep(33);
+	if (verbose > 1)
+		dprintk("%s: Resetting DST\n", __FUNCTION__);
+
+	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		return -1;
+	}
+	udelay(1000);
+	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		return -1;
+	}
+
 	return 0;
 }
+EXPORT_SYMBOL(rdc_8820_reset);
 
-static int dst_i2c_disable(struct dst_state *state)
+int dst_pio_enable(struct dst_state *state)
 {
-	int retval;
-	/* release I2C enable gpio pin, wait */
-	// dprintk ("%s: i2c disable\n", __FUNCTION__);
-	retval = dst_gpio_outb(state, ~0, 0, 0);
-	if (retval < 0)
-		return retval;
-	// dprintk ("%s: i2c disable delay\n", __FUNCTION__);
-	msleep(33);
+	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		return -1;
+	}
+	udelay(1000);
 	return 0;
 }
+EXPORT_SYMBOL(dst_pio_enable);
 
-static int dst_wait_dst_ready(struct dst_state *state)
+int dst_pio_disable(struct dst_state *state)
+{
+	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) {
+		dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__);
+		return -1;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		udelay(1000);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_pio_disable);
+
+int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode)
 {
 	u8 reply;
-	int retval;
 	int i;
+
 	for (i = 0; i < 200; i++) {
-		retval = dst_gpio_inb(state, &reply);
-		if (retval < 0)
-			return retval;
-		if ((reply & DST_I2C_ENABLE) == 0) {
-			dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
+		if (dst_gpio_inb(state, &reply) < 0) {
+			dprintk("%s: dst_gpio_inb ERROR !\n", __FUNCTION__);
+			return -1;
+		}
+
+		if ((reply & RDC_8820_PIO_0_ENABLE) == 0) {
+			if (verbose > 4)
+				dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
 			return 1;
 		}
 		msleep(10);
 	}
-	dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
+	if (verbose > 1)
+		dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
+
 	return 0;
 }
+EXPORT_SYMBOL(dst_wait_dst_ready);
 
-static int write_dst(struct dst_state *state, u8 * data, u8 len)
+int dst_error_recovery(struct dst_state *state)
+{
+	dprintk("%s: Trying to return from previous errors...\n", __FUNCTION__);
+	dst_pio_disable(state);
+	msleep(10);
+	dst_pio_enable(state);
+	msleep(10);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_error_recovery);
+
+int dst_error_bailout(struct dst_state *state)
+{
+	dprintk("%s: Trying to bailout from previous error...\n", __FUNCTION__);
+	rdc_8820_reset(state);
+	dst_pio_disable(state);
+	msleep(10);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_error_bailout);
+
+
+int dst_comm_init(struct dst_state* state)
+{
+	if (verbose > 1)
+		dprintk ("%s: Initializing DST..\n", __FUNCTION__);
+	if ((dst_pio_enable(state)) < 0) {
+		dprintk("%s: PIO Enable Failed.\n", __FUNCTION__);
+		return -1;
+	}
+	if ((rdc_reset_state(state)) < 0) {
+		dprintk("%s: RDC 8820 State RESET Failed.\n", __FUNCTION__);
+		return -1;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		msleep(100);
+	else
+		msleep(5);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_comm_init);
+
+
+int write_dst(struct dst_state *state, u8 *data, u8 len)
 {
 	struct i2c_msg msg = {
 		.addr = state->config->demod_address,.flags = 0,.buf = data,.len = len
 	};
+
 	int err;
 	int cnt;
-
-	if (dst_debug && dst_verbose) {
+	if (debug && (verbose > 4)) {
 		u8 i;
-		dprintk("%s writing", __FUNCTION__);
-		for (i = 0; i < len; i++) {
-			dprintk(" 0x%02x", data[i]);
+		if (verbose > 4) {
+			dprintk("%s writing", __FUNCTION__);
+			for (i = 0; i < len; i++)
+				dprintk(" %02x", data[i]);
+			dprintk("\n");
 		}
-		dprintk("\n");
 	}
-	msleep(30);
-	for (cnt = 0; cnt < 4; cnt++) {
+	for (cnt = 0; cnt < 2; cnt++) {
 		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
-			dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
-			dst_i2c_disable(state);
-			msleep(500);
-			dst_i2c_enable(state);
-			msleep(500);
+			dprintk("%s: _write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
+			dst_error_recovery(state);
 			continue;
 		} else
 			break;
 	}
-	if (cnt >= 4)
-		return -EREMOTEIO;
+
+	if (cnt >= 2) {
+		if (verbose > 1)
+			printk("%s: RDC 8820 RESET...\n", __FUNCTION__);
+		dst_error_bailout(state);
+
+		return -1;
+	}
+
 	return 0;
 }
+EXPORT_SYMBOL(write_dst);
 
-static int read_dst(struct dst_state *state, u8 * ret, u8 len)
+int read_dst(struct dst_state *state, u8 * ret, u8 len)
 {
 	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len };
 	int err;
 	int cnt;
 
-	for (cnt = 0; cnt < 4; cnt++) {
+	for (cnt = 0; cnt < 2; cnt++) {
 		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+
 			dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
-			dst_i2c_disable(state);
-			dst_i2c_enable(state);
+			dst_error_recovery(state);
+
 			continue;
 		} else
 			break;
 	}
-	if (cnt >= 4)
-		return -EREMOTEIO;
-	dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
-	if (dst_debug && dst_verbose) {
+	if (cnt >= 2) {
+		if (verbose > 1)
+			printk("%s: RDC 8820 RESET...\n", __FUNCTION__);
+		dst_error_bailout(state);
+
+		return -1;
+	}
+	if (debug && (verbose > 4)) {
+		dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
 		for (err = 1; err < len; err++)
 			dprintk(" 0x%x", ret[err]);
 		if (err > 1)
 			dprintk("\n");
 	}
+
 	return 0;
 }
+EXPORT_SYMBOL(read_dst);
 
 static int dst_set_freq(struct dst_state *state, u32 freq)
 {
 	u8 *val;
 
 	state->frequency = freq;
+	if (debug > 4)
+		dprintk("%s: set Frequency %u\n", __FUNCTION__, freq);
 
-	// dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
 	if (state->dst_type == DST_TYPE_IS_SAT) {
 		freq = freq / 1000;
 		if (freq < 950 || freq > 2150)
@@ -398,7 +450,8 @@ static int dst_set_symbolrate(struct dst
 	if (state->dst_type == DST_TYPE_IS_TERR) {
 		return 0;
 	}
-	// dprintk("%s: set srate %u\n", __FUNCTION__, srate);
+	if (debug > 4)
+		dprintk("%s: set symrate %u\n", __FUNCTION__, srate);
 	srate /= 1000;
 	val = &state->tx_tuna[0];
 
@@ -407,7 +460,10 @@ static int dst_set_symbolrate(struct dst
 		sval <<= 20;
 		do_div(sval, 88000);
 		symcalc = (u32) sval;
-		// dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
+
+		if (debug > 4)
+			dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
+
 		val[5] = (u8) (symcalc >> 12);
 		val[6] = (u8) (symcalc >> 4);
 		val[7] = (u8) (symcalc << 4);
@@ -422,7 +478,7 @@ static int dst_set_symbolrate(struct dst
 	return 0;
 }
 
-static u8 dst_check_sum(u8 * buf, u32 len)
+u8 dst_check_sum(u8 * buf, u32 len)
 {
 	u32 i;
 	u8 val = 0;
@@ -433,28 +489,7 @@ static u8 dst_check_sum(u8 * buf, u32 le
 	}
 	return ((~val) + 1);
 }
-
-struct dst_types {
-	char *mstr;
-	int offs;
-	u8 dst_type;
-	u32 type_flags;
-};
-
-static struct dst_types dst_tlist[] = {
-	{"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
-	{"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
-	{"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
-	{"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
-	{"DST-CI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
-	{"DSTMCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
-	{"DSTFCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
-	{"DCTNEW",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
-	{"DCT-CI",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
-	{"DTTDIG",  1, DST_TYPE_IS_TERR, 0}
-};
-
-/* DCTNEW and DCT-CI are guesses */
+EXPORT_SYMBOL(dst_check_sum);
 
 static void dst_type_flags_print(u32 type_flags)
 {
@@ -465,93 +500,270 @@ static void dst_type_flags_print(u32 typ
 		printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
 	if (type_flags & DST_TYPE_HAS_SYMDIV)
 		printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
+	if (type_flags & DST_TYPE_HAS_FW_1)
+		printk(" 0x%x firmware version = 1", DST_TYPE_HAS_FW_1);
+	if (type_flags & DST_TYPE_HAS_FW_2)
+		printk(" 0x%x firmware version = 2", DST_TYPE_HAS_FW_2);
+	if (type_flags & DST_TYPE_HAS_FW_3)
+		printk(" 0x%x firmware version = 3", DST_TYPE_HAS_FW_3);
+//	if ((type_flags & DST_TYPE_HAS_FW_BUILD) && new_fw)
+
 	printk("\n");
 }
 
-static int dst_type_print(u8 type)
+
+static int dst_type_print (u8 type)
 {
 	char *otype;
 	switch (type) {
 	case DST_TYPE_IS_SAT:
 		otype = "satellite";
 		break;
+
 	case DST_TYPE_IS_TERR:
 		otype = "terrestrial";
 		break;
+
 	case DST_TYPE_IS_CABLE:
 		otype = "cable";
 		break;
+
 	default:
 		printk("%s: invalid dst type %d\n", __FUNCTION__, type);
 		return -EINVAL;
 	}
 	printk("DST type : %s\n", otype);
+
 	return 0;
 }
 
-static int dst_check_ci(struct dst_state *state)
+/*
+	Known cards list
+	Satellite
+	-------------------
+		  200103A
+	VP-1020   DST-MOT	LG(old), TS=188
+
+	VP-1020   DST-03T	LG(new), TS=204
+	VP-1022   DST-03T	LG(new), TS=204
+	VP-1025   DST-03T	LG(new), TS=204
+
+	VP-1030   DSTMCI,	LG(new), TS=188
+	VP-1032   DSTMCI,	LG(new), TS=188
+
+	Cable
+	-------------------
+	VP-2030   DCT-CI,	Samsung, TS=204
+	VP-2021   DCT-CI,	Unknown, TS=204
+	VP-2031   DCT-CI,	Philips, TS=188
+	VP-2040   DCT-CI,	Philips, TS=188, with CA daughter board
+	VP-2040   DCT-CI,	Philips, TS=204, without CA daughter board
+
+	Terrestrial
+	-------------------
+	VP-3050  DTTNXT			 TS=188
+	VP-3040  DTT-CI,	Philips, TS=188
+	VP-3040  DTT-CI,	Philips, TS=204
+
+	ATSC
+	-------------------
+	VP-3220  ATSCDI,		 TS=188
+	VP-3250  ATSCAD,		 TS=188
+
+*/
+
+struct dst_types dst_tlist[] = {
+	{
+		.device_id = "200103A",
+		.offset = 0,
+		.dst_type =  DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-020",
+		.offset = 0,
+		.dst_type =  DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-030",
+		.offset =  0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-03T",
+		.offset = 0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
+		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
+							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+	 },
+
+	{
+		.device_id = "DST-MOT",
+		.offset =  0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
+		.dst_feature = DST_TYPE_HAS_CA
+	},	/*	An OEM board	*/
+
+	{
+		.device_id = "DSTMCI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
+							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+	},
+
+	{
+		.device_id = "DSTFCI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0
+	},	/* unknown to vendor	*/
+
+	{
+		.device_id = "DCT-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_CABLE,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
+							| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = DST_TYPE_HAS_CA
+	},
+
+	{
+		.device_id = "DCTNEW",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_CABLE,
+		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3,
+		.dst_feature = 0
+	},
+
+	{
+		.device_id = "DTT-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = 0
+	},
+
+	{
+		.device_id = "DTTDIG",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = 0
+	},
+
+	{
+		.device_id = "DTTNXT",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = DST_TYPE_HAS_ANALOG
+	},
+
+	{
+		.device_id = "ATSCDI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_ATSC,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = 0
+	},
+
+	{
+		.device_id = "ATSCAD",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_ATSC,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = 0
+	},
+
+	{ }
+
+};
+
+
+static int dst_get_device_id(struct dst_state *state)
 {
-	u8 txbuf[8];
-	u8 rxbuf[8];
-	int retval;
+	u8 reply;
+
 	int i;
-	struct dst_types *dsp;
-	u8 use_dst_type;
-	u32 use_type_flags;
-
-	memset(txbuf, 0, sizeof(txbuf));
-	txbuf[1] = 6;
-	txbuf[7] = dst_check_sum(txbuf, 7);
-
-	dst_i2c_enable(state);
-	dst_reset8820(state);
-	retval = write_dst(state, txbuf, 8);
-	if (retval < 0) {
-		dst_i2c_disable(state);
-		dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
-		return retval;
-	}
-	msleep(3);
-	retval = read_dst(state, rxbuf, 1);
-	dst_i2c_disable(state);
-	if (retval < 0) {
-		dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
-		return retval;
-	}
-	if (rxbuf[0] != 0xff) {
-		dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
-		return retval;
-	}
-	if (!dst_wait_dst_ready(state))
-		return 0;
-	// dst_i2c_enable(i2c); Dimitri
-	retval = read_dst(state, rxbuf, 8);
-	dst_i2c_disable(state);
-	if (retval < 0) {
-		dprintk("%s: read not successful\n", __FUNCTION__);
-		return retval;
+	struct dst_types *p_dst_type;
+	u8 use_dst_type = 0;
+	u32 use_type_flags = 0;
+
+	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+
+	device_type[7] = dst_check_sum(device_type, 7);
+
+	if (write_dst(state, device_type, FIXED_COMM))
+		return -1;		/*	Write failed		*/
+
+	if ((dst_pio_disable(state)) < 0)
+		return -1;
+
+	if (read_dst(state, &reply, GET_ACK))
+		return -1;		/*	Read failure		*/
+
+	if (reply != ACK) {
+		dprintk("%s: Write not Acknowledged! [Reply=0x%02x]\n", __FUNCTION__, reply);
+		return -1;		/*	Unack'd write		*/
 	}
-	if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
-		dprintk("%s: checksum failure\n", __FUNCTION__);
-		return retval;
+
+	if (!dst_wait_dst_ready(state, DEVICE_INIT))
+		return -1;		/*	DST not ready yet	*/
+
+	if (read_dst(state, state->rxbuffer, FIXED_COMM))
+		return -1;
+
+	dst_pio_disable(state);
+
+	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+		dprintk("%s: Checksum failure! \n", __FUNCTION__);
+		return -1;		/*	Checksum failure	*/
 	}
-	rxbuf[7] = '\0';
-	for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
-		if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
-			use_type_flags = dsp->type_flags;
-			use_dst_type = dsp->dst_type;
-			printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
+
+	state->rxbuffer[7] = '\0';
+
+	for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE (dst_tlist); i++, p_dst_type++) {
+		if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) {
+			use_type_flags = p_dst_type->type_flags;
+			use_dst_type = p_dst_type->dst_type;
+
+			/*	Card capabilities	*/
+			state->dst_hw_cap = p_dst_type->dst_feature;
+			printk ("%s: Recognise [%s]\n", __FUNCTION__, p_dst_type->device_id);
+
 			break;
 		}
 	}
-	if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
-		printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
-		printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
+
+	if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) {
+		printk("%s: Unable to recognize %s or %s\n", __FUNCTION__, &state->rxbuffer[0], &state->rxbuffer[1]);
+		printk("%s: please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
 		use_dst_type = DST_TYPE_IS_SAT;
 		use_type_flags = DST_TYPE_HAS_SYMDIV;
 	}
-	dst_type_print(use_dst_type);
 
+	dst_type_print(use_dst_type);
 	state->type_flags = use_type_flags;
 	state->dst_type = use_dst_type;
 	dst_type_flags_print(state->type_flags);
@@ -559,50 +771,102 @@ static int dst_check_ci(struct dst_state
 	if (state->type_flags & DST_TYPE_HAS_TS204) {
 		dst_packsize(state, 204);
 	}
+
 	return 0;
 }
 
-static int dst_command(struct dst_state* state, u8 * data, u8 len)
+static int dst_probe(struct dst_state *state)
+{
+	if ((rdc_8820_reset(state)) < 0) {
+		dprintk("%s: RDC 8820 RESET Failed.\n", __FUNCTION__);
+		return -1;
+	}
+	if (dst_addons & DST_TYPE_HAS_CA)
+		msleep(4000);
+	else
+		msleep(100);
+
+	if ((dst_comm_init(state)) < 0) {
+		dprintk("%s: DST Initialization Failed.\n", __FUNCTION__);
+		return -1;
+	}
+	msleep(100);
+	if (dst_get_device_id(state) < 0) {
+		dprintk("%s: unknown device.\n", __FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
+
+int dst_command(struct dst_state* state, u8 * data, u8 len)
 {
-	int retval;
 	u8 reply;
+	if ((dst_comm_init(state)) < 0) {
+		dprintk("%s: DST Communication Initialization Failed.\n", __FUNCTION__);
+		return -1;
+	}
 
-	dst_i2c_enable(state);
-	dst_reset8820(state);
-	retval = write_dst(state, data, len);
-	if (retval < 0) {
-		dst_i2c_disable(state);
-		dprintk("%s: write not successful\n", __FUNCTION__);
-		return retval;
+	if (write_dst(state, data, len)) {
+		if (verbose > 1)
+			dprintk("%s: Tring to recover.. \n", __FUNCTION__);
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk("%s: Recovery Failed.\n", __FUNCTION__);
+			return -1;
+		}
+		return -1;
 	}
-	msleep(33);
-	retval = read_dst(state, &reply, 1);
-	dst_i2c_disable(state);
-	if (retval < 0) {
-		dprintk("%s: read verify  not successful\n", __FUNCTION__);
-		return retval;
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk("%s: PIO Disable Failed.\n", __FUNCTION__);
+		return -1;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		udelay(3000);
+
+	if (read_dst(state, &reply, GET_ACK)) {
+		if (verbose > 1)
+			dprintk("%s: Trying to recover.. \n", __FUNCTION__);
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk("%s: Recovery Failed.\n", __FUNCTION__);
+			return -1;
+		}
+		return -1;
 	}
-	if (reply != 0xff) {
-		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
-		return 0;
+
+	if (reply != ACK) {
+		dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply);
+		return -1;
 	}
 	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
 		return 0;
-	if (!dst_wait_dst_ready(state))
-		return 0;
-	// dst_i2c_enable(i2c); Per dimitri
-	retval = read_dst(state, state->rxbuffer, 8);
-	dst_i2c_disable(state);
-	if (retval < 0) {
-		dprintk("%s: read not successful\n", __FUNCTION__);
-		return 0;
+
+//	udelay(3000);
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		udelay(3000);
+	else
+		udelay(2000);
+
+	if (!dst_wait_dst_ready(state, NO_DELAY))
+		return -1;
+
+	if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
+		if (verbose > 1)
+			dprintk("%s: Trying to recover.. \n", __FUNCTION__);
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk("%s: Recovery failed.\n", __FUNCTION__);
+			return -1;
+		}
+		return -1;
 	}
+
 	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
 		dprintk("%s: checksum failure\n", __FUNCTION__);
-		return 0;
+		return -1;
 	}
+
 	return 0;
 }
+EXPORT_SYMBOL(dst_command);
 
 static int dst_get_signal(struct dst_state* state)
 {
@@ -642,37 +906,38 @@ static int dst_tone_power_cmd(struct dst
 	if (state->dst_type == DST_TYPE_IS_TERR)
 		return 0;
 
-	if (state->voltage == SEC_VOLTAGE_OFF)
-		paket[4] = 0;
-	else
-		paket[4] = 1;
-	if (state->tone == SEC_TONE_ON)
-		paket[2] = state->k22;
-	else
-		paket[2] = 0;
-	paket[7] = dst_check_sum(&paket[0], 7);
+	paket[4] = state->tx_tuna[4];
+	paket[2] = state->tx_tuna[2];
+	paket[3] = state->tx_tuna[3];
+	paket[7] = dst_check_sum (paket, 7);
 	dst_command(state, paket, 8);
+
 	return 0;
 }
 
 static int dst_get_tuna(struct dst_state* state)
 {
 	int retval;
+
 	if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
 		return 0;
+
 	state->diseq_flags &= ~(HAS_LOCK);
-	if (!dst_wait_dst_ready(state))
+	if (!dst_wait_dst_ready(state, NO_DELAY))
 		return 0;
+
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
 		/* how to get variable length reply ???? */
 		retval = read_dst(state, state->rx_tuna, 10);
 	} else {
-		retval = read_dst(state, &state->rx_tuna[2], 8);
+		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
 	}
+
 	if (retval < 0) {
 		dprintk("%s: read not successful\n", __FUNCTION__);
 		return 0;
 	}
+
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
 			dprintk("%s: checksum failure?\n", __FUNCTION__);
@@ -705,11 +970,13 @@ static int dst_set_voltage(struct dvb_fr
 
 static int dst_write_tuna(struct dvb_frontend* fe)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 	int retval;
 	u8 reply;
 
-	dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
+	if (debug > 4)
+		dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
+
 	state->decode_freq = 0;
 	state->decode_lock = state->decode_strength = state->decode_snr = 0;
 	if (state->dst_type == DST_TYPE_IS_SAT) {
@@ -717,32 +984,41 @@ static int dst_write_tuna(struct dvb_fro
 			dst_set_voltage(fe, SEC_VOLTAGE_13);
 	}
 	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-	dst_i2c_enable(state);
+
+	if ((dst_comm_init(state)) < 0) {
+		dprintk("%s: DST Communication initialization failed.\n", __FUNCTION__);
+		return -1;
+	}
+
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
-		dst_reset8820(state);
 		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
 		retval = write_dst(state, &state->tx_tuna[0], 10);
+
 	} else {
 		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
-		retval = write_dst(state, &state->tx_tuna[2], 8);
+		retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM);
 	}
 	if (retval < 0) {
-		dst_i2c_disable(state);
+		dst_pio_disable(state);
 		dprintk("%s: write not successful\n", __FUNCTION__);
 		return retval;
 	}
-	msleep(3);
-	retval = read_dst(state, &reply, 1);
-	dst_i2c_disable(state);
-	if (retval < 0) {
-		dprintk("%s: read verify  not successful\n", __FUNCTION__);
-		return retval;
+
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk("%s: DST PIO disable failed !\n", __FUNCTION__);
+		return -1;
+	}
+
+	if ((read_dst(state, &reply, GET_ACK) < 0)) {
+		dprintk("%s: read verify not successful.\n", __FUNCTION__);
+		return -1;
 	}
-	if (reply != 0xff) {
-		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+	if (reply != ACK) {
+		dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply);
 		return 0;
 	}
 	state->diseq_flags |= ATTEMPT_TUNE;
+
 	return dst_get_tuna(state);
 }
 
@@ -762,10 +1038,10 @@ static int dst_write_tuna(struct dvb_fro
 
 static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 	u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
 
-	if (state->dst_type == DST_TYPE_IS_TERR)
+	if (state->dst_type != DST_TYPE_IS_SAT)
 		return 0;
 
 	if (cmd->msg_len == 0 || cmd->msg_len > 4)
@@ -778,73 +1054,91 @@ static int dst_set_diseqc(struct dvb_fro
 
 static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-	u8 *val;
 	int need_cmd;
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	state->voltage = voltage;
 
-	if (state->dst_type == DST_TYPE_IS_TERR)
+	if (state->dst_type != DST_TYPE_IS_SAT)
 		return 0;
 
 	need_cmd = 0;
-	val = &state->tx_tuna[0];
-	val[8] &= ~0x40;
 	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		if ((state->diseq_flags & HAS_POWER) == 0)
-			need_cmd = 1;
-		state->diseq_flags |= HAS_POWER;
-		break;
-	case SEC_VOLTAGE_18:
-		if ((state->diseq_flags & HAS_POWER) == 0)
+		case SEC_VOLTAGE_13:
+		case SEC_VOLTAGE_18:
+			if ((state->diseq_flags & HAS_POWER) == 0)
+				need_cmd = 1;
+			state->diseq_flags |= HAS_POWER;
+			state->tx_tuna[4] = 0x01;
+			break;
+
+		case SEC_VOLTAGE_OFF:
 			need_cmd = 1;
-		state->diseq_flags |= HAS_POWER;
-		val[8] |= 0x40;
-		break;
-	case SEC_VOLTAGE_OFF:
-		need_cmd = 1;
-		state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
-		break;
-	default:
-		return -EINVAL;
+			state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+			state->tx_tuna[4] = 0x00;
+			break;
+
+		default:
+			return -EINVAL;
 	}
-	if (need_cmd) {
+	if (need_cmd)
 		dst_tone_power_cmd(state);
-	}
+
 	return 0;
 }
 
 static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-	u8 *val;
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	state->tone = tone;
 
-	if (state->dst_type == DST_TYPE_IS_TERR)
+	if (state->dst_type != DST_TYPE_IS_SAT)
 		return 0;
 
-	val = &state->tx_tuna[0];
+	switch (tone) {
+		case SEC_TONE_OFF:
+			state->tx_tuna[2] = 0xff;
+			break;
 
-	val[8] &= ~0x1;
+		case SEC_TONE_ON:
+			state->tx_tuna[2] = 0x02;
+			break;
 
-	switch (tone) {
-	case SEC_TONE_OFF:
-		break;
-	case SEC_TONE_ON:
-		val[8] |= 1;
-		break;
-	default:
-		return -EINVAL;
+		default:
+			return -EINVAL;
 	}
 	dst_tone_power_cmd(state);
+
 	return 0;
 }
 
+static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return 0;
+
+	state->minicmd = minicmd;
+
+	switch (minicmd) {
+		case SEC_MINI_A:
+			state->tx_tuna[3] = 0x02;
+			break;
+		case SEC_MINI_B:
+			state->tx_tuna[3] = 0xff;
+			break;
+	}
+	dst_tone_power_cmd(state);
+
+	return 0;
+}
+
+
 static int dst_init(struct dvb_frontend* fe)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 	static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
 	static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
 	static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
@@ -876,7 +1170,7 @@ static int dst_init(struct dvb_frontend*
 
 static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	*status = 0;
 	if (state->diseq_flags & HAS_LOCK) {
@@ -890,7 +1184,7 @@ static int dst_read_status(struct dvb_fr
 
 static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	dst_get_signal(state);
 	*strength = state->decode_strength;
@@ -900,7 +1194,7 @@ static int dst_read_signal_strength(stru
 
 static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	dst_get_signal(state);
 	*snr = state->decode_snr;
@@ -910,13 +1204,19 @@ static int dst_read_snr(struct dvb_front
 
 static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	dst_set_freq(state, p->frequency);
+	if (verbose > 4)
+		dprintk("Set Frequency = [%d]\n", p->frequency);
+
 	dst_set_inversion(state, p->inversion);
 	if (state->dst_type == DST_TYPE_IS_SAT) {
 		dst_set_fec(state, p->u.qpsk.fec_inner);
 		dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+		if (verbose > 4)
+			dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate);
+
 	} else if (state->dst_type == DST_TYPE_IS_TERR) {
 		dst_set_bandwidth(state, p->u.ofdm.bandwidth);
 	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
@@ -930,7 +1230,7 @@ static int dst_set_frontend(struct dvb_f
 
 static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 
 	p->frequency = state->decode_freq;
 	p->inversion = state->inversion;
@@ -950,7 +1250,7 @@ static int dst_get_frontend(struct dvb_f
 
 static void dst_release(struct dvb_frontend* fe)
 {
-	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	struct dst_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -958,50 +1258,47 @@ static struct dvb_frontend_ops dst_dvbt_
 static struct dvb_frontend_ops dst_dvbs_ops;
 static struct dvb_frontend_ops dst_dvbc_ops;
 
-struct dvb_frontend* dst_attach(const struct dst_config* config,
-				struct i2c_adapter* i2c,
-				struct bt878 *bt)
-{
-	struct dst_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->bt = bt;
+struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
+{
 
-	/* check if the demod is there */
-	if (dst_check_ci(state) < 0) goto error;
+	/* check if the ASIC is there */
+	if (dst_probe(state) < 0) {
+		if (state)
+			kfree(state);
 
+		return NULL;
+	}
 	/* determine settings based on type */
 	switch (state->dst_type) {
 	case DST_TYPE_IS_TERR:
 		memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
 		break;
+
 	case DST_TYPE_IS_CABLE:
 		memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
 		break;
+
 	case DST_TYPE_IS_SAT:
 		memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
 		break;
+
 	default:
-		printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
-		goto error;
+		printk("%s: unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n", __FUNCTION__);
+		if (state)
+			kfree(state);
+
+		return NULL;
 	}
 
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
-	return &state->frontend;
 
-error:
-	if (state) kfree(state);
-	return NULL;
+	return state;				/*	Manu (DST is a card not a frontend)	*/
 }
 
+EXPORT_SYMBOL(dst_attach);
+
 static struct dvb_frontend_ops dst_dvbt_ops = {
 
 	.info = {
@@ -1036,7 +1333,7 @@ static struct dvb_frontend_ops dst_dvbs_
 		.frequency_tolerance = 29500,
 		.symbol_rate_min = 1000000,
 		.symbol_rate_max = 45000000,
-	/*     . symbol_rate_tolerance	= 	???,*/
+	/*     . symbol_rate_tolerance	=	???,*/
 		.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
 	},
 
@@ -1051,6 +1348,7 @@ static struct dvb_frontend_ops dst_dvbs_
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
 
+	.diseqc_send_burst = dst_send_burst,
 	.diseqc_send_master_cmd = dst_set_diseqc,
 	.set_voltage = dst_set_voltage,
 	.set_tone = dst_set_tone,
@@ -1066,7 +1364,7 @@ static struct dvb_frontend_ops dst_dvbc_
 		.frequency_max = 858000000,
 		.symbol_rate_min = 1000000,
 		.symbol_rate_max = 45000000,
-	/*     . symbol_rate_tolerance	= 	???,*/
+	/*     . symbol_rate_tolerance	=	???,*/
 		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
 	},
 
@@ -1082,8 +1380,7 @@ static struct dvb_frontend_ops dst_dvbc_
 	.read_snr = dst_read_snr,
 };
 
+
 MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
-MODULE_AUTHOR("Jamie Honan");
+MODULE_AUTHOR("Jamie Honan, Manu Abraham");
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dst_attach);
diff --git a/drivers/media/dvb/bt8xx/dst.h b/drivers/media/dvb/bt8xx/dst.h
deleted file mode 100644
--- a/drivers/media/dvb/bt8xx/dst.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-    Frontend-driver for TwinHan DST Frontend
-
-    Copyright (C) 2003 Jamie Honan
-
-    This program is free software; you can redistribute it 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.
-
-*/
-
-#ifndef DST_H
-#define DST_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/device.h>
-#include "bt878.h"
-
-struct dst_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-extern struct dvb_frontend* dst_attach(const struct dst_config* config,
-				       struct i2c_adapter* i2c,
-				       struct bt878 *bt);
-
-#endif // DST_H
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -0,0 +1,861 @@
+/*
+	CA-driver for TwinHan DST Frontend/Card
+
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <linux/dvb/ca.h>
+#include "dvbdev.h"
+#include "dvb_frontend.h"
+
+#include "dst_ca.h"
+#include "dst_common.h"
+
+static unsigned int verbose = 1;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static unsigned int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug messages, default is 1 (yes)");
+
+#define dprintk if (debug) printk
+
+/*	Need some more work	*/
+static int ca_set_slot_descr(void)
+{
+	/*	We could make this more graceful ?	*/
+	return -EOPNOTSUPP;
+}
+
+/*	Need some more work	*/
+static int ca_set_pid(void)
+{
+	/*	We could make this more graceful ?	*/
+	return -EOPNOTSUPP;
+}
+
+
+static int put_checksum(u8 *check_string, int length)
+{
+	u8 i = 0, checksum = 0;
+
+	if (verbose > 3) {
+		dprintk("%s: ========================= Checksum calculation ===========================\n", __FUNCTION__);
+		dprintk("%s: String Length=[0x%02x]\n", __FUNCTION__, length);
+
+		dprintk("%s: String=[", __FUNCTION__);
+	}
+	while (i < length) {
+		if (verbose > 3)
+			dprintk(" %02x", check_string[i]);
+		checksum += check_string[i];
+		i++;
+	}
+	if (verbose > 3) {
+		dprintk(" ]\n");
+		dprintk("%s: Sum=[%02x]\n", __FUNCTION__, checksum);
+	}
+	check_string[length] = ~checksum + 1;
+	if (verbose > 3) {
+		dprintk("%s: Checksum=[%02x]\n", __FUNCTION__, check_string[length]);
+		dprintk("%s: ==========================================================================\n", __FUNCTION__);
+	}
+
+	return 0;
+}
+
+static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
+{
+	u8 reply;
+
+	dst_comm_init(state);
+	msleep(65);
+
+	if (write_dst(state, data, len)) {
+		dprintk("%s: Write not successful, trying to recover\n", __FUNCTION__);
+		dst_error_recovery(state);
+		return -1;
+	}
+
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk("%s: DST PIO disable failed.\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (read_dst(state, &reply, GET_ACK) < 0) {
+		dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__);
+		dst_error_recovery(state);
+		return -1;
+	}
+
+	if (read) {
+		if (! dst_wait_dst_ready(state, LONG_DELAY)) {
+			dprintk("%s: 8820 not ready\n", __FUNCTION__);
+			return -1;
+		}
+
+		if (read_dst(state, ca_string, 128) < 0) {	/*	Try to make this dynamic	*/
+			dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__);
+			dst_error_recovery(state);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
+{
+	u8 dst_ca_comm_err = 0;
+
+	while (dst_ca_comm_err < RETRIES) {
+		dst_comm_init(state);
+		if (verbose > 2)
+			dprintk("%s: Put Command\n", __FUNCTION__);
+		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
+			dst_error_recovery(state);
+			dst_ca_comm_err++; // work required here.
+		}
+		break;
+	}
+
+	return 0;
+}
+
+
+
+static int ca_get_app_info(struct dst_state *state)
+{
+	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
+
+	put_checksum(&command[0], command[0]);
+	if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
+		dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
+		return -1;
+	}
+	if (verbose > 1) {
+		dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
+
+		dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__);
+		dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n",
+			__FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9],
+			(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
+		dprintk("%s: ==================================================================================================\n", __FUNCTION__);
+	}
+
+	return 0;
+}
+
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
+{
+	int i;
+	u8 slot_cap[256];
+	static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
+
+	put_checksum(&slot_command[0], slot_command[0]);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
+		dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
+		return -1;
+	}
+	if (verbose > 1)
+		dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
+
+	/*	Will implement the rest soon		*/
+
+	if (verbose > 1) {
+		dprintk("%s: Slot cap = [%d]\n", __FUNCTION__, slot_cap[7]);
+		dprintk("===================================\n");
+		for (i = 0; i < 8; i++)
+			dprintk(" %d", slot_cap[i]);
+		dprintk("\n");
+	}
+
+	p_ca_caps->slot_num = 1;
+	p_ca_caps->slot_type = 1;
+	p_ca_caps->descr_num = slot_cap[7];
+	p_ca_caps->descr_type = 1;
+
+
+	if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) {
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*	Need some more work	*/
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+{
+	return -EOPNOTSUPP;
+}
+
+
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
+{
+	int i;
+	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+
+	u8 *slot_info = state->rxbuffer;
+
+	put_checksum(&slot_command[0], 7);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
+		dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
+		return -1;
+	}
+	if (verbose > 1)
+		dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
+
+	/*	Will implement the rest soon		*/
+
+	if (verbose > 1) {
+		dprintk("%s: Slot info = [%d]\n", __FUNCTION__, slot_info[3]);
+		dprintk("===================================\n");
+		for (i = 0; i < 8; i++)
+			dprintk(" %d", slot_info[i]);
+		dprintk("\n");
+	}
+
+	if (slot_info[4] & 0x80) {
+		p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
+		p_ca_slot_info->num = 1;
+		p_ca_slot_info->type = CA_CI;
+	}
+	else if (slot_info[4] & 0x40) {
+		p_ca_slot_info->flags = CA_CI_MODULE_READY;
+		p_ca_slot_info->num = 1;
+		p_ca_slot_info->type = CA_CI;
+	}
+	else {
+		p_ca_slot_info->flags = 0;
+	}
+
+	if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) {
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+
+
+
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+{
+	u8 i = 0;
+	u32 command = 0;
+
+	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
+		return -EFAULT;
+
+
+	if (p_ca_message->msg) {
+		if (verbose > 3)
+			dprintk("Message = [%02x %02x %02x]\n", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
+
+		for (i = 0; i < 3; i++) {
+			command = command | p_ca_message->msg[i];
+			if (i < 2)
+				command = command << 8;
+		}
+		if (verbose > 3)
+			dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command);
+
+		switch (command) {
+			case CA_APP_INFO:
+				memcpy(p_ca_message->msg, state->messages, 128);
+				if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
+					return -EFAULT;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+{
+	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
+		hw_buffer->msg[2] = p_ca_message->msg[1];		/*		MSB			*/
+		hw_buffer->msg[3] = p_ca_message->msg[2];		/*		LSB			*/
+	}
+	else {
+		hw_buffer->msg[2] = 0x03;
+		hw_buffer->msg[3] = 0x00;
+	}
+	return 0;
+}
+
+static int debug_8820_buffer(struct ca_msg *hw_buffer)
+{
+	unsigned int i;
+
+	dprintk("%s:Debug=[", __FUNCTION__);
+	for (i = 0; i < (hw_buffer->msg[0] + 1); i++)
+		dprintk(" %02x", hw_buffer->msg[i]);
+	dprintk("]\n");
+
+	return 0;
+}
+
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply)
+{
+	if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) {
+		dprintk("%s: DST-CI Command failed.\n", __FUNCTION__);
+		dprintk("%s: Resetting DST.\n", __FUNCTION__);
+		rdc_reset_state(state);
+		return -1;
+	}
+	if (verbose > 2)
+		dprintk("%s: DST-CI Command succes.\n", __FUNCTION__);
+
+	return 0;
+}
+
+
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+	u32 hw_offset, buf_offset, i, k;
+	u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0;
+	u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0;
+
+	if (verbose > 3)
+		dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length );
+
+	handle_en50221_tag(state, p_ca_message, hw_buffer);			/*	EN50221 tag		*/
+
+	/*	Handle the length field (variable)	*/
+	if (!(p_ca_message->msg[3] & 0x80)) {				/*	Length = 1		*/
+		length = p_ca_message->msg[3] & 0x7f;
+		words = 0;						/*	domi's suggestion	*/
+	}
+	else {								/*	Length = words		*/
+		words = p_ca_message->msg[3] & 0x7f;
+		for (i = 0; i < words; i++) {
+			length = length << 8;
+			length = length | p_ca_message->msg[4 + i];
+		}
+	}
+	if (verbose > 4) {
+		dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words);
+
+		/*	Debug Input string		*/
+		for (i = 0; i < length; i++)
+			dprintk(" %02x", p_ca_message->msg[i]);
+		dprintk("]\n");
+	}
+
+	hw_offset = 7;
+	buf_offset = words + 4;
+
+	/*		Program Header			*/
+	if (verbose > 4)
+		dprintk("\n%s:Program Header=[", __FUNCTION__);
+	for (i = 0; i < 6; i++) {
+		hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
+		if (verbose > 4)
+			dprintk(" %02x", p_ca_message->msg[buf_offset]);
+		hw_offset++, buf_offset++, hw_buffer_length++;
+	}
+	if (verbose > 4)
+		dprintk("]\n");
+
+	program_info_length = 0;
+	program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9];
+	if (verbose > 4)
+		dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n",
+			__FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset);
+
+	if (program_info_length && (program_info_length < 256)) {	/*	If program_info_length		*/
+		hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f;		/*	req only 4 bits			*/
+		hw_buffer->msg[12] = hw_buffer->msg[12] + 1;		/*	increment! ASIC bug!		*/
+
+		if (p_ca_message->msg[buf_offset + 1] == 0x09) {	/*	Check CA descriptor		*/
+			found_prog_ca_desc = 1;
+			if (verbose > 4)
+				dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__);
+		}
+
+		if (found_prog_ca_desc) {				/*	Command only if CA descriptor	*/
+			hw_buffer->msg[13] = p_ca_message->msg[buf_offset];	/*	CA PMT command ID	*/
+			hw_offset++, buf_offset++, hw_buffer_length++;
+		}
+
+		/*			Program descriptors				*/
+		if (verbose > 4) {
+			dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
+			dprintk("%s:Program descriptors=[", __FUNCTION__);
+		}
+		while (program_info_length && !error_condition) {		/*	Copy prog descriptors	*/
+			if (program_info_length > p_ca_message->length) {	/*	Error situation		*/
+				dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n",
+								__FUNCTION__, __LINE__, program_info_length);
+				dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
+				error_condition = 1;
+				break;
+			}
+
+			hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
+			dprintk(" %02x", p_ca_message->msg[buf_offset]);
+			hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--;
+		}
+		if (verbose > 4) {
+			dprintk("]\n");
+			dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
+		}
+		if (found_prog_ca_desc) {
+			if (!reply) {
+				hw_buffer->msg[13] = 0x01;		/*	OK descrambling			*/
+				if (verbose > 1)
+					dprintk("CA PMT Command = OK Descrambling\n");
+			}
+			else {
+				hw_buffer->msg[13] = 0x02;		/*	Ok MMI				*/
+				if (verbose > 1)
+					dprintk("CA PMT Command = Ok MMI\n");
+			}
+			if (query) {
+				hw_buffer->msg[13] = 0x03;		/*	Query				*/
+				if (verbose > 1)
+					dprintk("CA PMT Command = CA PMT query\n");
+			}
+		}
+	}
+	else {
+		hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0;		/*	Don't write to ASIC		*/
+		hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00;
+	}
+	if (verbose > 4)
+		dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n",
+					__FUNCTION__, p_ca_message->length, buf_offset, hw_offset);
+
+	while ((buf_offset  < p_ca_message->length)  && !error_condition) {
+		/*	Bail out in case of an indefinite loop		*/
+		if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
+			dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n",
+							__FUNCTION__, __LINE__, program_info_length, buf_offset);
+
+			dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
+			error_condition = 1;
+			break;
+		}
+
+		/*		Stream Header				*/
+
+		for (k = 0; k < 5; k++) {
+			hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k];
+		}
+
+		es_info_length = 0;
+		es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4];
+
+		if (verbose > 4) {
+			dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__,
+				p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1],
+				p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3],
+				p_ca_message->msg[buf_offset + 4]);
+
+			dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__,
+				p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length,
+				p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset);
+		}
+
+		hw_buffer->msg[hw_offset + 3] &= 0x0f;			/*	req only 4 bits			*/
+
+		if (found_prog_ca_desc) {
+			hw_buffer->msg[hw_offset + 3] = 0x00;
+			hw_buffer->msg[hw_offset + 4] = 0x00;
+		}
+
+		hw_offset += 5, buf_offset += 5, hw_buffer_length += 5;
+
+		/*		Check for CA descriptor			*/
+		if (p_ca_message->msg[buf_offset + 1] == 0x09) {
+			if (verbose > 4)
+				dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__);
+			found_stream_ca_desc = 1;
+		}
+
+		/*		ES descriptors				*/
+
+		if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) {
+//			if (!ca_pmt_done) {
+				hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];	/*	CA PMT cmd(es)	*/
+				if (verbose > 4)
+					printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]);
+//				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1;
+				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
+//			}
+			if (verbose > 4)
+				dprintk("%s:----->ES descriptors=[", __FUNCTION__);
+
+			while (es_info_length && !error_condition) {	/*	ES descriptors			*/
+				if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
+					if (verbose > 4) {
+						dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n",
+										__FUNCTION__, __LINE__, es_info_length, buf_offset);
+
+						dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
+					}
+					error_condition = 1;
+					break;
+				}
+
+				hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
+				if (verbose > 3)
+					dprintk("%02x ", hw_buffer->msg[hw_offset]);
+				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
+			}
+			found_stream_ca_desc = 0;			/*	unset for new streams		*/
+			dprintk("]\n");
+		}
+	}
+
+	/*		MCU Magic words					*/
+
+	hw_buffer_length += 7;
+	hw_buffer->msg[0] = hw_buffer_length;
+	hw_buffer->msg[1] = 64;
+	hw_buffer->msg[4] = 3;
+	hw_buffer->msg[5] = hw_buffer->msg[0] - 7;
+	hw_buffer->msg[6] = 0;
+
+
+	/*      Fix length      */
+	hw_buffer->length = hw_buffer->msg[0];
+
+	put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]);
+	/*      Do the actual write     */
+	if (verbose > 4) {
+		dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__);
+		dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length);
+	}
+	/*      Only for debugging!     */
+	if (verbose > 2)
+		debug_8820_buffer(hw_buffer);
+	if (verbose > 3)
+		dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply);
+	write_to_8820(state, hw_buffer, reply);
+
+	return 0;
+}
+
+/*	Board supports CA PMT reply ?		*/
+static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+{
+	int ca_pmt_reply_test = 0;
+
+	/*	Do test board			*/
+	/*	Not there yet but soon		*/
+
+
+	/*	CA PMT Reply capable		*/
+	if (ca_pmt_reply_test) {
+		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
+			dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__);
+			return -1;
+		}
+
+	/*	Process CA PMT Reply		*/
+	/*	will implement soon		*/
+		dprintk("%s: Not there yet\n", __FUNCTION__);
+	}
+	/*	CA PMT Reply not capable	*/
+	if (!ca_pmt_reply_test) {
+		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
+			dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__);
+			return -1;
+		}
+		if (verbose > 3)
+			dprintk("%s: ca_set_pmt.. success !\n", __FUNCTION__);
+	/*	put a dummy message		*/
+
+	}
+	return 0;
+}
+
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+{
+	int i = 0;
+	unsigned int ca_message_header_len;
+
+	u32 command = 0;
+	struct ca_msg *hw_buffer;
+
+	if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
+		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+	if (verbose > 3)
+		dprintk("%s\n", __FUNCTION__);
+
+	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
+		return -EFAULT;
+
+	if (p_ca_message->msg) {
+		ca_message_header_len = p_ca_message->length;	/*	Restore it back when you are done	*/
+		/*	EN50221 tag	*/
+		command = 0;
+
+		for (i = 0; i < 3; i++) {
+			command = command | p_ca_message->msg[i];
+			if (i < 2)
+				command = command << 8;
+		}
+		if (verbose > 3)
+			dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command);
+
+		switch (command) {
+			case CA_PMT:
+				if (verbose > 3)
+					dprintk("Command = SEND_CA_PMT\n");
+				if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+					dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__);
+					return -1;
+				}
+				if (verbose > 3)
+					dprintk("%s: -->CA_PMT Success !\n", __FUNCTION__);
+//				retval = dummy_set_pmt(state, p_ca_message, hw_buffer, 0, 0);
+
+				break;
+
+			case CA_PMT_REPLY:
+				if (verbose > 3)
+					dprintk("Command = CA_PMT_REPLY\n");
+				/*      Have to handle the 2 basic types of cards here  */
+				if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
+					dprintk("%s: -->CA_PMT_REPLY Failed !\n", __FUNCTION__);
+					return -1;
+				}
+				if (verbose > 3)
+					dprintk("%s: -->CA_PMT_REPLY Success !\n", __FUNCTION__);
+
+				/*      Certain boards do behave different ?            */
+//				retval = ca_set_pmt(state, p_ca_message, hw_buffer, 1, 1);
+
+			case CA_APP_INFO_ENQUIRY:		// only for debugging
+				if (verbose > 3)
+					dprintk("%s: Getting Cam Application information\n", __FUNCTION__);
+
+				if ((ca_get_app_info(state)) < 0) {
+					dprintk("%s: -->CA_APP_INFO_ENQUIRY Failed !\n", __FUNCTION__);
+					return -1;
+				}
+				if (verbose > 3)
+					printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
+
+				break;
+		}
+	}
+	return 0;
+}
+
+static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+{
+	struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
+	struct dst_state* state = (struct dst_state*) dvbdev->priv;
+	struct ca_slot_info *p_ca_slot_info;
+	struct ca_caps *p_ca_caps;
+	struct ca_msg *p_ca_message;
+
+	if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
+		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
+		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
+	switch (cmd) {
+		case CA_SEND_MSG:
+			if (verbose > 1)
+				dprintk("%s: Sending message\n", __FUNCTION__);
+			if ((ca_send_message(state, p_ca_message, arg)) < 0) {
+				dprintk("%s: -->CA_SEND_MSG Failed !\n", __FUNCTION__);
+				return -1;
+			}
+
+			break;
+
+		case CA_GET_MSG:
+			if (verbose > 1)
+				dprintk("%s: Getting message\n", __FUNCTION__);
+			if ((ca_get_message(state, p_ca_message, arg)) < 0) {
+				dprintk("%s: -->CA_GET_MSG Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_GET_MSG Success !\n", __FUNCTION__);
+
+			break;
+
+		case CA_RESET:
+			if (verbose > 1)
+				dprintk("%s: Resetting DST\n", __FUNCTION__);
+			dst_error_bailout(state);
+			msleep(4000);
+
+			break;
+
+		case CA_GET_SLOT_INFO:
+			if (verbose > 1)
+				dprintk("%s: Getting Slot info\n", __FUNCTION__);
+			if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
+				dprintk("%s: -->CA_GET_SLOT_INFO Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_GET_SLOT_INFO Success !\n", __FUNCTION__);
+
+			break;
+
+		case CA_GET_CAP:
+			if (verbose > 1)
+				dprintk("%s: Getting Slot capabilities\n", __FUNCTION__);
+			if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
+				dprintk("%s: -->CA_GET_CAP Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_GET_CAP Success !\n", __FUNCTION__);
+
+			break;
+
+		case CA_GET_DESCR_INFO:
+			if (verbose > 1)
+				dprintk("%s: Getting descrambler description\n", __FUNCTION__);
+			if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
+				dprintk("%s: -->CA_GET_DESCR_INFO Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_GET_DESCR_INFO Success !\n", __FUNCTION__);
+
+			break;
+
+		case CA_SET_DESCR:
+			if (verbose > 1)
+				dprintk("%s: Setting descrambler\n", __FUNCTION__);
+			if ((ca_set_slot_descr()) < 0) {
+				dprintk("%s: -->CA_SET_DESCR Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_SET_DESCR Success !\n", __FUNCTION__);
+
+			break;
+
+		case CA_SET_PID:
+			if (verbose > 1)
+				dprintk("%s: Setting PID\n", __FUNCTION__);
+			if ((ca_set_pid()) < 0) {
+				dprintk("%s: -->CA_SET_PID Failed !\n", __FUNCTION__);
+				return -1;
+			}
+			if (verbose > 1)
+				dprintk("%s: -->CA_SET_PID Success !\n", __FUNCTION__);
+
+		default:
+			return -EOPNOTSUPP;
+		};
+
+	return 0;
+}
+
+static int dst_ca_open(struct inode *inode, struct file *file)
+{
+	if (verbose > 4)
+		dprintk("%s:Device opened [%p]\n", __FUNCTION__, file);
+	try_module_get(THIS_MODULE);
+
+	return 0;
+}
+
+static int dst_ca_release(struct inode *inode, struct file *file)
+{
+	if (verbose > 4)
+		dprintk("%s:Device closed.\n", __FUNCTION__);
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+static int dst_ca_read(struct file *file, char __user * buffer, size_t length, loff_t * offset)
+{
+	int bytes_read = 0;
+
+	if (verbose > 4)
+		dprintk("%s:Device read.\n", __FUNCTION__);
+
+	return bytes_read;
+}
+
+static int dst_ca_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset)
+{
+	if (verbose > 4)
+		dprintk("%s:Device write.\n", __FUNCTION__);
+
+	return 0;
+}
+
+static struct file_operations dst_ca_fops = {
+	.owner = THIS_MODULE,
+	.ioctl = (void *)dst_ca_ioctl,
+	.open = dst_ca_open,
+	.release = dst_ca_release,
+	.read = dst_ca_read,
+	.write = dst_ca_write
+};
+
+static struct dvb_device dvbdev_ca = {
+	.priv = NULL,
+	.users = 1,
+	.readers = 1,
+	.writers = 1,
+	.fops = &dst_ca_fops
+};
+
+int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+{
+	struct dvb_device *dvbdev;
+	if (verbose > 4)
+		dprintk("%s:registering DST-CA device\n", __FUNCTION__);
+	dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
+	return 0;
+}
+
+EXPORT_SYMBOL(dst_ca_attach);
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/dvb/bt8xx/dst_ca.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/bt8xx/dst_ca.h
@@ -0,0 +1,58 @@
+/*
+	CA-driver for TwinHan DST Frontend/Card
+
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DST_CA_H_
+#define _DST_CA_H_
+
+#define RETRIES			5
+
+
+#define	CA_APP_INFO_ENQUIRY	0x9f8020
+#define	CA_APP_INFO		0x9f8021
+#define	CA_ENTER_MENU		0x9f8022
+#define CA_INFO_ENQUIRY		0x9f8030
+#define	CA_INFO			0x9f8031
+#define CA_PMT			0x9f8032
+#define CA_PMT_REPLY		0x9f8033
+
+#define CA_CLOSE_MMI		0x9f8800
+#define CA_DISPLAY_CONTROL	0x9f8801
+#define CA_DISPLAY_REPLY	0x9f8802
+#define CA_TEXT_LAST		0x9f8803
+#define CA_TEXT_MORE		0x9f8804
+#define CA_KEYPAD_CONTROL	0x9f8805
+#define CA_KEYPRESS		0x9f8806
+
+#define CA_ENQUIRY		0x9f8807
+#define CA_ANSWER		0x9f8808
+#define CA_MENU_LAST		0x9f8809
+#define CA_MENU_MORE		0x9f880a
+#define CA_MENU_ANSWER		0x9f880b
+#define CA_LIST_LAST		0x9f880c
+#define CA_LIST_MORE		0x9f880d
+
+
+struct dst_ca_private {
+	struct dst_state *dst;
+	struct dvb_device *dvbdev;
+};
+
+
+#endif
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -0,0 +1,153 @@
+/*
+	Frontend-driver for TwinHan DST Frontend
+
+	Copyright (C) 2003 Jamie Honan
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef DST_COMMON_H
+#define DST_COMMON_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/device.h>
+#include "bt878.h"
+
+#include "dst_ca.h"
+
+
+#define NO_DELAY		0
+#define LONG_DELAY		1
+#define DEVICE_INIT		2
+
+#define DELAY			1
+
+#define DST_TYPE_IS_SAT		0
+#define DST_TYPE_IS_TERR	1
+#define DST_TYPE_IS_CABLE	2
+#define DST_TYPE_IS_ATSC	3
+
+#define DST_TYPE_HAS_NEWTUNE	1
+#define DST_TYPE_HAS_TS204	2
+#define DST_TYPE_HAS_SYMDIV	4
+#define DST_TYPE_HAS_FW_1	8
+#define DST_TYPE_HAS_FW_2	16
+#define DST_TYPE_HAS_FW_3	32
+#define DST_TYPE_HAS_FW_BUILD	64
+
+/*	Card capability list	*/
+
+#define DST_TYPE_HAS_MAC	1
+#define DST_TYPE_HAS_DISEQC3	2
+#define DST_TYPE_HAS_DISEQC4	4
+#define DST_TYPE_HAS_DISEQC5	8
+#define DST_TYPE_HAS_MOTO	16
+#define DST_TYPE_HAS_CA		32
+#define	DST_TYPE_HAS_ANALOG	64	/*	Analog inputs	*/
+#define DST_TYPE_HAS_SESSION	128
+
+
+#define RDC_8820_PIO_0_DISABLE	0
+#define RDC_8820_PIO_0_ENABLE	1
+#define RDC_8820_INT		2
+#define RDC_8820_RESET		4
+
+/*	DST Communication	*/
+#define GET_REPLY		1
+#define NO_REPLY		0
+
+#define GET_ACK			1
+#define FIXED_COMM		8
+
+#define ACK			0xff
+
+struct dst_state {
+
+	struct i2c_adapter* i2c;
+
+	struct bt878* bt;
+
+	struct dvb_frontend_ops ops;
+
+	/* configuration settings */
+	const struct dst_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* private ASIC data */
+	u8 tx_tuna[10];
+	u8 rx_tuna[10];
+	u8 rxbuffer[10];
+	u8 diseq_flags;
+	u8 dst_type;
+	u32 type_flags;
+	u32 frequency;		/* intermediate frequency in kHz for QPSK */
+	fe_spectral_inversion_t inversion;
+	u32 symbol_rate;	/* symbol rate in Symbols per second */
+	fe_code_rate_t fec;
+	fe_sec_voltage_t voltage;
+	fe_sec_tone_mode_t tone;
+	u32 decode_freq;
+	u8 decode_lock;
+	u16 decode_strength;
+	u16 decode_snr;
+	unsigned long cur_jiff;
+	u8 k22;
+	fe_bandwidth_t bandwidth;
+	u32 dst_hw_cap;
+	u8 dst_fw_version;
+	fe_sec_mini_cmd_t minicmd;
+	u8 messages[256];
+};
+
+struct dst_types {
+	char *device_id;
+	int offset;
+	u8 dst_type;
+	u32 type_flags;
+	u32 dst_feature;
+};
+
+
+
+struct dst_config
+{
+	/* the ASIC i2c address */
+	u8 demod_address;
+};
+
+
+int rdc_reset_state(struct dst_state *state);
+int rdc_8820_reset(struct dst_state *state);
+
+int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
+int dst_pio_enable(struct dst_state *state);
+int dst_pio_disable(struct dst_state *state);
+int dst_error_recovery(struct dst_state* state);
+int dst_error_bailout(struct dst_state *state);
+int dst_comm_init(struct dst_state* state);
+
+int write_dst(struct dst_state *state, u8 * data, u8 len);
+int read_dst(struct dst_state *state, u8 * ret, u8 len);
+u8 dst_check_sum(u8 * buf, u32 len);
+struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
+int dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
+
+int dst_command(struct dst_state* state, u8 * data, u8 len);
+
+
+#endif // DST_COMMON_H
diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h
--- a/drivers/media/dvb/bt8xx/dst_priv.h
+++ b/drivers/media/dvb/bt8xx/dst_priv.h
@@ -33,5 +33,3 @@ union dst_gpio_packet {
 struct bt878;
 
 int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
-
-struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -1,5 +1,5 @@
 /*
- * Bt8xx based DVB adapter driver 
+ * Bt8xx based DVB adapter driver
  *
  * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
  *
@@ -71,7 +71,7 @@ static int dvb_bt8xx_start_feed(struct d
 	int rc;
 
 	dprintk("dvb_bt8xx: start_feed\n");
-	
+
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
 
@@ -91,10 +91,10 @@ static int dvb_bt8xx_stop_feed(struct dv
 	struct dvb_bt8xx_card *card = dvbdmx->priv;
 
 	dprintk("dvb_bt8xx: stop_feed\n");
-	
+
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
-		
+
 	down(&card->lock);
 	card->nfeeds--;
 	if (card->nfeeds == 0)
@@ -117,7 +117,7 @@ static int is_pci_slot_eq(struct pci_dev
 static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
 {
 	unsigned int card_nr;
-	
+
 	/* Hmm, n squared. Hope n is small */
 	for (card_nr = 0; card_nr < bt878_num; card_nr++) {
 		if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
@@ -133,7 +133,7 @@ static int thomson_dtt7579_demod_init(st
 	static u8 mt352_reset [] = { 0x50, 0x80 };
 	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
 	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
-	static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 };
+	static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
 	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
 
 	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
@@ -142,7 +142,7 @@ static int thomson_dtt7579_demod_init(st
 	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
 
 	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-        mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
+	mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
 	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
 
 	return 0;
@@ -161,15 +161,15 @@ static int thomson_dtt7579_pll_set(struc
 	else if (params->frequency < 771000000) cp = 0xbc;
 	else cp = 0xf4;
 
-        if (params->frequency == 0) bs = 0x03;
+	if (params->frequency == 0) bs = 0x03;
 	else if (params->frequency < 443250000) bs = 0x02;
 	else bs = 0x08;
 
 	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
 	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = cp;
-   	pllbuf[4] = bs;
+	pllbuf[2] = div & 0xff;
+	pllbuf[3] = cp;
+	pllbuf[4] = bs;
 
 	return 0;
 }
@@ -184,50 +184,50 @@ static struct mt352_config thomson_dtt75
 static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
    u32 freq = params->frequency;
-   
-   int i, a, n, pump; 
+
+   int i, a, n, pump;
    u32 band, pll;
-   
-   
+
+
    u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
-               1576000,1718000,1856000,2036000,2150000};
+	       1576000,1718000,1856000,2036000,2150000};
    u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
-               0x00102000,0x00104000,0x00108000,0x00110000,
-               0x00120000,0x00140000};
-   
+	       0x00102000,0x00104000,0x00108000,0x00110000,
+	       0x00120000,0x00140000};
+
 #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
-        printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
-        
-        /* This is really the bit driving the tuner chip cx24108 */
-        
-        if(freq<950000) freq=950000; /* kHz */
-        if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */
-        
-        /* decide which VCO to use for the input frequency */
-        for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
-        printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
-        band=bandsel[i];
-        /* the gain values must be set by SetSymbolrate */
-        /* compute the pll divider needed, from Conexant data sheet,
-           resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
-           depending on the divider bit. It is set to /4 on the 2 lowest 
-           bands  */
-        n=((i<=2?2:1)*freq*10L)/(XTAL/100);
-        a=n%32; n/=32; if(a==0) n--;
-        pump=(freq<(osci[i-1]+osci[i])/2);
-        pll=0xf8000000|
-            ((pump?1:2)<<(14+11))|
-            ((n&0x1ff)<<(5+11))|
-            ((a&0x1f)<<11);
-        /* everything is shifted left 11 bits to left-align the bits in the
-           32bit word. Output to the tuner goes MSB-aligned, after all */
-        printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
-        cx24110_pll_write(fe,band);
-        /* set vga and vca to their widest-band settings, as a precaution.
-           SetSymbolrate might not be called to set this up */
-        cx24110_pll_write(fe,0x500c0000);
-        cx24110_pll_write(fe,0x83f1f800);
-        cx24110_pll_write(fe,pll);
+	printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
+
+	/* This is really the bit driving the tuner chip cx24108 */
+
+	if(freq<950000) freq=950000; /* kHz */
+	if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */
+
+	/* decide which VCO to use for the input frequency */
+	for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
+	printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
+	band=bandsel[i];
+	/* the gain values must be set by SetSymbolrate */
+	/* compute the pll divider needed, from Conexant data sheet,
+	   resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
+	   depending on the divider bit. It is set to /4 on the 2 lowest
+	   bands  */
+	n=((i<=2?2:1)*freq*10L)/(XTAL/100);
+	a=n%32; n/=32; if(a==0) n--;
+	pump=(freq<(osci[i-1]+osci[i])/2);
+	pll=0xf8000000|
+	    ((pump?1:2)<<(14+11))|
+	    ((n&0x1ff)<<(5+11))|
+	    ((a&0x1f)<<11);
+	/* everything is shifted left 11 bits to left-align the bits in the
+	   32bit word. Output to the tuner goes MSB-aligned, after all */
+	printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
+	cx24110_pll_write(fe,band);
+	/* set vga and vca to their widest-band settings, as a precaution.
+	   SetSymbolrate might not be called to set this up */
+	cx24110_pll_write(fe,0x500c0000);
+	cx24110_pll_write(fe,0x83f1f800);
+	cx24110_pll_write(fe,pll);
 /*        writereg(client,0x56,0x7f);*/
 
 	return 0;
@@ -299,7 +299,7 @@ static int advbt771_samsung_tdtc9251dh0_
 	static u8 mt352_reset [] = { 0x50, 0x80 };
 	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
 	static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
-	                               0x00, 0xFF, 0x00, 0x40, 0x40 };
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
 	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
 	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
 
@@ -348,9 +348,9 @@ static int advbt771_samsung_tdtc9251dh0_
 
 	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
 	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = cp;
-   	pllbuf[4] = bs;
+	pllbuf[2] = div & 0xff;
+	pllbuf[3] = cp;
+	pllbuf[4] = bs;
 
 	return 0;
 }
@@ -369,6 +369,63 @@ static struct dst_config dst_config = {
 };
 
 
+static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+static void or51211_setmode(struct dvb_frontend * fe, int mode)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+	bttv_write_gpio(bt->bttv_nr, 0x0002, mode);   /* Reset */
+	msleep(20);
+}
+
+static void or51211_reset(struct dvb_frontend * fe)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+
+	/* RESET DEVICE
+	 * reset is controled by GPIO-0
+	 * when set to 0 causes reset and when to 1 for normal op
+	 * must remain reset for 128 clock cycles on a 50Mhz clock
+	 * also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4
+	 * We assume that the reset has be held low long enough or we
+	 * have been reset by a power on.  When the driver is unloaded
+	 * reset set to 0 so if reloaded we have been reset.
+	 */
+	/* reset & PRM1,2&4 are outputs */
+	int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
+	if (ret != 0) {
+		printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR "
+		       "(%i)\n", ret);
+	}
+	bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000);   /* Reset */
+	msleep(20);
+	/* Now set for normal operation */
+	bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
+	/* wait for operation to begin */
+	msleep(500);
+}
+
+static void or51211_sleep(struct dvb_frontend * fe)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+	bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
+}
+
+static struct or51211_config or51211_config = {
+
+	.demod_address = 0x15,
+	.request_firmware = or51211_request_firmware,
+	.setmode = or51211_setmode,
+	.reset = or51211_reset,
+	.sleep = or51211_sleep,
+};
+
+
 static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
@@ -406,6 +463,9 @@ static struct nxt6000_config vp3021_alps
 
 static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 {
+	int ret;
+	struct dst_state* state = NULL;
+
 	switch(type) {
 #ifdef BTTV_DVICO_DVBT_LITE
 	case BTTV_DVICO_DVBT_LITE:
@@ -446,18 +506,43 @@ static void frontend_init(struct dvb_bt8
 		break;
 
 	case BTTV_TWINHAN_DST:
-		card->fe = dst_attach(&dst_config, card->i2c_adapter, card->bt);
+		/*	DST is not a frontend driver !!!		*/
+		state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
+		/*	Setup the Card					*/
+		state->config = &dst_config;
+		state->i2c = card->i2c_adapter;
+		state->bt = card->bt;
+
+		/*	DST is not a frontend, attaching the ASIC	*/
+		if ((dst_attach(state, &card->dvb_adapter)) == NULL) {
+			printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
+			break;
+		}
+		card->fe = &state->frontend;
+
+		/*	Attach other DST peripherals if any		*/
+		/*	Conditional Access device			*/
+		if (state->dst_hw_cap & DST_TYPE_HAS_CA) {
+			ret = dst_ca_attach(state, &card->dvb_adapter);
+		}
 		if (card->fe != NULL) {
 			break;
 		}
 		break;
-	
+
 	case BTTV_PINNACLESAT:
 		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			break;
 		}
 		break;
+
+	case BTTV_PC_HDTV:
+		card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			break;
+		}
+		break;
 	}
 
 	if (card->fe == NULL) {
@@ -467,7 +552,7 @@ static void frontend_init(struct dvb_bt8
 		       card->bt->dev->subsystem_vendor,
 		       card->bt->dev->subsystem_device);
 	} else {
-		if (dvb_register_frontend(card->dvb_adapter, card->fe)) {
+		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
 			printk("dvb-bt8xx: Frontend registration failed!\n");
 			if (card->fe->ops->release)
 				card->fe->ops->release(card->fe);
@@ -484,9 +569,9 @@ static int __init dvb_bt8xx_load_card(st
 					   THIS_MODULE)) < 0) {
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		return result;
-		
+
 	}
-	card->dvb_adapter->priv = card;
+	card->dvb_adapter.priv = card;
 
 	card->bt->adapter = card->i2c_adapter;
 
@@ -500,23 +585,23 @@ static int __init dvb_bt8xx_load_card(st
 	card->demux.start_feed = dvb_bt8xx_start_feed;
 	card->demux.stop_feed = dvb_bt8xx_stop_feed;
 	card->demux.write_to_decoder = NULL;
-	
+
 	if ((result = dvb_dmx_init(&card->demux)) < 0) {
 		printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
 
-		dvb_unregister_adapter(card->dvb_adapter);
+		dvb_unregister_adapter(&card->dvb_adapter);
 		return result;
 	}
 
 	card->dmxdev.filternum = 256;
 	card->dmxdev.demux = &card->demux.dmx;
 	card->dmxdev.capabilities = 0;
-	
-	if ((result = dvb_dmxdev_init(&card->dmxdev, card->dvb_adapter)) < 0) {
+
+	if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) {
 		printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
 
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_adapter(card->dvb_adapter);
+		dvb_unregister_adapter(&card->dvb_adapter);
 		return result;
 	}
 
@@ -527,10 +612,10 @@ static int __init dvb_bt8xx_load_card(st
 
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_adapter(card->dvb_adapter);
+		dvb_unregister_adapter(&card->dvb_adapter);
 		return result;
 	}
-	
+
 	card->fe_mem.source = DMX_MEMORY_FE;
 
 	if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) {
@@ -539,7 +624,7 @@ static int __init dvb_bt8xx_load_card(st
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_adapter(card->dvb_adapter);
+		dvb_unregister_adapter(&card->dvb_adapter);
 		return result;
 	}
 
@@ -550,14 +635,14 @@ static int __init dvb_bt8xx_load_card(st
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_adapter(card->dvb_adapter);
+		dvb_unregister_adapter(&card->dvb_adapter);
 		return result;
 	}
 
-	dvb_net_init(card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+	dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
 
 	tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
-	
+
 	frontend_init(card, type);
 
 	return 0;
@@ -584,21 +669,21 @@ static int dvb_bt8xx_probe(struct device
 	case BTTV_PINNACLESAT:
 		card->gpio_mode = 0x0400c060;
 		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
-		              BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
+			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
 		break;
-		
+
 #ifdef BTTV_DVICO_DVBT_LITE
 	case BTTV_DVICO_DVBT_LITE:
 #endif
 		card->gpio_mode = 0x0400C060;
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
-				/* 26, 15, 14, 6, 5 
+		/* 26, 15, 14, 6, 5
 		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
-				 * DA_APP(parallel) */
-				break;
+		 * DA_APP(parallel) */
+		break;
 
 #ifdef BTTV_TWINHAN_VP3021
 	case BTTV_TWINHAN_VP3021:
@@ -609,40 +694,46 @@ static int dvb_bt8xx_probe(struct device
 		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
-				/* A_PWRDN DA_SBR DA_APP (high speed serial) */
-				break;
+		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
+		break;
 
 	case BTTV_AVDVBT_771: //case 0x07711461:
 		card->gpio_mode = 0x0400402B;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
 		card->irq_err_ignore = 0;
 		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
-				break;
+		break;
 
 	case BTTV_TWINHAN_DST:
 		card->gpio_mode = 0x2204f2c;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
 		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
 				       BT878_APPERR | BT878_AFBUS;
-				/* 25,21,14,11,10,9,8,3,2 then
-				 * 0x33 = 5,4,1,0
-				 * A_SEL=SML, DA_MLB, DA_SBR, 
-				 * DA_SDR=f, fifo trigger = 32 DWORDS
-				 * IOM = 0 == audio A/D
-				 * DPM = 0 == digital audio mode
-				 * == async data parallel port
-				 * then 0x33 (13 is set by start_capture)
-				 * DA_APP = async data parallel port, 
-				 * ACAP_EN = 1,
-				 * RISC+FIFO ENABLE */
-				break;
+		/* 25,21,14,11,10,9,8,3,2 then
+		 * 0x33 = 5,4,1,0
+		 * A_SEL=SML, DA_MLB, DA_SBR,
+		 * DA_SDR=f, fifo trigger = 32 DWORDS
+		 * IOM = 0 == audio A/D
+		 * DPM = 0 == digital audio mode
+		 * == async data parallel port
+		 * then 0x33 (13 is set by start_capture)
+		 * DA_APP = async data parallel port,
+		 * ACAP_EN = 1,
+		 * RISC+FIFO ENABLE */
+		break;
 
-			default:
+	case BTTV_PC_HDTV:
+		card->gpio_mode = 0x0100EC7B;
+		card->op_sync_orin = 0;
+		card->irq_err_ignore = 0;
+		break;
+
+	default:
 		printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
 				sub->core->type);
 		kfree(card);
 		return -ENODEV;
-		}
+	}
 
 	dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
 
@@ -661,7 +752,7 @@ static int dvb_bt8xx_probe(struct device
 		kfree(card);
 		return -EFAULT;
 
-}
+	}
 
 	init_MUTEX(&card->bt->gpio_lock);
 	card->bt->bttv_nr = sub->core->nr;
@@ -678,23 +769,23 @@ static int dvb_bt8xx_probe(struct device
 static int dvb_bt8xx_remove(struct device *dev)
 {
 	struct dvb_bt8xx_card *card = dev_get_drvdata(dev);
-		
-		dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
 
-		bt878_stop(card->bt);
-		tasklet_kill(&card->bt->tasklet);
-		dvb_net_release(&card->dvbnet);
-		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
-		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
-		dvb_dmxdev_release(&card->dmxdev);
-		dvb_dmx_release(&card->demux);
+	dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
+
+	bt878_stop(card->bt);
+	tasklet_kill(&card->bt->tasklet);
+	dvb_net_release(&card->dvbnet);
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+	dvb_dmxdev_release(&card->dmxdev);
+	dvb_dmx_release(&card->demux);
 	if (card->fe) dvb_unregister_frontend(card->fe);
-		dvb_unregister_adapter(card->dvb_adapter);
-		
-		kfree(card);
+	dvb_unregister_adapter(&card->dvb_adapter);
+
+	kfree(card);
 
 	return 0;
-	}
+}
 
 static struct bttv_sub_driver driver = {
 	.drv = {
@@ -721,7 +812,7 @@ static void __exit dvb_bt8xx_exit(void)
 
 module_init(dvb_bt8xx_init);
 module_exit(dvb_bt8xx_exit);
+
 MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
 MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -1,5 +1,5 @@
 /*
- * Bt8xx based DVB adapter driver 
+ * Bt8xx based DVB adapter driver
  *
  * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
  * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de>
@@ -31,15 +31,16 @@
 #include "bttv.h"
 #include "mt352.h"
 #include "sp887x.h"
-#include "dst.h"
+#include "dst_common.h"
 #include "nxt6000.h"
 #include "cx24110.h"
+#include "or51211.h"
 
 struct dvb_bt8xx_card {
 	struct semaphore lock;
 	int nfeeds;
 	char card_name[32];
-	struct dvb_adapter *dvb_adapter;
+	struct dvb_adapter dvb_adapter;
 	struct bt878 *bt;
 	unsigned int bttv_nr;
 	struct dvb_demux demux;
@@ -51,7 +52,7 @@ struct dvb_bt8xx_card {
 	u32 irq_err_ignore;
 	struct i2c_adapter *i2c_adapter;
 	struct dvb_net dvbnet;
-				
+
 	struct dvb_frontend* fe;
 };
 
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -37,13 +37,6 @@
 #include "dvb_net.h"
 
 
-
-
-
-
-
-
-
 #ifdef CONFIG_DVB_CINERGYT2_TUNING
 	#define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
 	#define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
@@ -66,7 +59,7 @@ static int debug;
 module_param_named(debug, debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-#define dprintk(level, args...) \
+#define dprintk(level, args...)						\
 do {									\
 	if ((debug & level)) {						\
 		printk("%s: %s(): ", __stringify(KBUILD_MODNAME),	\
@@ -77,8 +70,8 @@ do {									\
 enum cinergyt2_ep1_cmd {
 	CINERGYT2_EP1_PID_TABLE_RESET		= 0x01,
 	CINERGYT2_EP1_PID_SETUP			= 0x02,
-	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER 	= 0x03,
-	CINERGYT2_EP1_SET_TUNER_PARAMETERS 	= 0x04,
+	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER	= 0x03,
+	CINERGYT2_EP1_SET_TUNER_PARAMETERS	= 0x04,
 	CINERGYT2_EP1_GET_TUNER_STATUS		= 0x05,
 	CINERGYT2_EP1_START_SCAN		= 0x06,
 	CINERGYT2_EP1_CONTINUE_SCAN		= 0x07,
@@ -126,7 +119,7 @@ struct cinergyt2 {
 	struct dvb_demux demux;
 	struct usb_device *udev;
 	struct semaphore sem;
-	struct dvb_adapter *adapter;
+	struct dvb_adapter adapter;
 	struct dvb_device *fedev;
 	struct dmxdev dmxdev;
 	struct dvb_net dvbnet;
@@ -143,7 +136,7 @@ struct cinergyt2 {
 
 	void *streambuf;
 	dma_addr_t streambuf_dmahandle;
-	struct urb *stream_urb[STREAM_URB_COUNT];
+	struct urb *stream_urb [STREAM_URB_COUNT];
 
 #ifdef ENABLE_RC
 	struct input_dev rc_input_dev;
@@ -164,47 +157,47 @@ struct cinergyt2_rc_event {
 } __attribute__((packed));
 
 static const uint32_t rc_keys [] = {
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xfe01eb04,	KEY_POWER,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xfd02eb04,	KEY_1,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xfc03eb04,	KEY_2,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xfb04eb04,	KEY_3,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xfa05eb04,	KEY_4,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf906eb04,	KEY_5,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf807eb04,	KEY_6,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf708eb04,	KEY_7,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf609eb04,	KEY_8,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf50aeb04,	KEY_9,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf30ceb04,	KEY_0,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfe01eb04,	KEY_POWER,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfd02eb04,	KEY_1,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfc03eb04,	KEY_2,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfb04eb04,	KEY_3,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfa05eb04,	KEY_4,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf906eb04,	KEY_5,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf807eb04,	KEY_6,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf708eb04,	KEY_7,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf609eb04,	KEY_8,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf50aeb04,	KEY_9,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf30ceb04,	KEY_0,
 	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf40beb04,	KEY_VIDEO,
 	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf20deb04,	KEY_REFRESH,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf10eeb04,	KEY_SELECT,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xf00feb04,	KEY_EPG,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xef10eb04,	KEY_UP,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xeb14eb04,	KEY_DOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xee11eb04,	KEY_LEFT,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xec13eb04,	KEY_RIGHT,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xed12eb04,	KEY_OK,	
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xea15eb04,	KEY_TEXT,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe916eb04,	KEY_INFO,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe817eb04,	KEY_RED,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe718eb04,	KEY_GREEN,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe619eb04,	KEY_YELLOW,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe51aeb04,	KEY_BLUE,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe31ceb04,	KEY_VOLUMEUP,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe11eeb04,	KEY_VOLUMEDOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe21deb04,	KEY_MUTE,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe41beb04,	KEY_CHANNELUP,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xe01feb04,	KEY_CHANNELDOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xbf40eb04,	KEY_PAUSE,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xb34ceb04,	KEY_PLAY,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xa758eb04,	KEY_RECORD,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xab54eb04,	KEY_PREVIOUS,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xb748eb04,	KEY_STOP,
-	CINERGYT2_RC_EVENT_TYPE_NEC, 	0xa35ceb04,	KEY_NEXT
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf10eeb04,	KEY_SELECT,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf00feb04,	KEY_EPG,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xef10eb04,	KEY_UP,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xeb14eb04,	KEY_DOWN,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xee11eb04,	KEY_LEFT,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xec13eb04,	KEY_RIGHT,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xed12eb04,	KEY_OK,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xea15eb04,	KEY_TEXT,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe916eb04,	KEY_INFO,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe817eb04,	KEY_RED,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe718eb04,	KEY_GREEN,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe619eb04,	KEY_YELLOW,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe51aeb04,	KEY_BLUE,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe31ceb04,	KEY_VOLUMEUP,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe11eeb04,	KEY_VOLUMEDOWN,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe21deb04,	KEY_MUTE,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe41beb04,	KEY_CHANNELUP,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe01feb04,	KEY_CHANNELDOWN,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xbf40eb04,	KEY_PAUSE,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xb34ceb04,	KEY_PLAY,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xa758eb04,	KEY_RECORD,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xab54eb04,	KEY_PREVIOUS,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xb748eb04,	KEY_STOP,
+	CINERGYT2_RC_EVENT_TYPE_NEC,	0xa35ceb04,	KEY_NEXT
 };
 
 static int cinergyt2_command (struct cinergyt2 *cinergyt2,
-		    char *send_buf, int send_buf_len,
+			      char *send_buf, int send_buf_len,
 			      char *recv_buf, int recv_buf_len)
 {
 	int actual_len;
@@ -212,7 +205,7 @@ static int cinergyt2_command (struct cin
 	int ret;
 
 	ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
-			   send_buf, send_buf_len, &actual_len, HZ);
+			   send_buf, send_buf_len, &actual_len, 1000);
 
 	if (ret)
 		dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
@@ -221,7 +214,7 @@ static int cinergyt2_command (struct cin
 		recv_buf = &dummy;
 
 	ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
-			   recv_buf, recv_buf_len, &actual_len, HZ);
+			   recv_buf, recv_buf_len, &actual_len, 1000);
 
 	if (ret)
 		dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
@@ -232,13 +225,13 @@ static int cinergyt2_command (struct cin
 static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
 {
 	char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-  	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
+	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
 }
 
 static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
 {
 	char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
-  	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
+	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
 	cinergyt2->sleeping = sleep;
 }
 
@@ -290,7 +283,7 @@ static int cinergyt2_alloc_stream_urbs (
 {
 	int i;
 
-	cinergyt2->streambuf = pci_alloc_consistent(NULL, 
+	cinergyt2->streambuf = pci_alloc_consistent(NULL,
 					      STREAM_URB_COUNT*STREAM_BUF_SIZE,
 					      &cinergyt2->streambuf_dmahandle);
 	if (!cinergyt2->streambuf) {
@@ -301,7 +294,7 @@ static int cinergyt2_alloc_stream_urbs (
 	memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
 
 	for (i=0; i<STREAM_URB_COUNT; i++) {
-		struct urb *urb;	
+		struct urb *urb;
 
 		if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
 			dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
@@ -352,9 +345,9 @@ static int cinergyt2_start_feed(struct d
 
 	if (down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
-	
+
 	if (cinergyt2->streaming == 0)
-	       	cinergyt2_start_stream_xfer(cinergyt2);
+		cinergyt2_start_stream_xfer(cinergyt2);
 
 	cinergyt2->streaming++;
 	up(&cinergyt2->sem);
@@ -364,7 +357,7 @@ static int cinergyt2_start_feed(struct d
 static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct dvb_demux *demux = dvbdmxfeed->demux;
-	struct cinergyt2 *cinergyt2 = demux->priv;	
+	struct cinergyt2 *cinergyt2 = demux->priv;
 
 	if (down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
@@ -497,7 +490,7 @@ static int cinergyt2_open (struct inode 
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 		cinergyt2_sleep(cinergyt2, 0);
 		schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-}
+	}
 
 	up(&cinergyt2->sem);
 	return 0;
@@ -520,20 +513,20 @@ static int cinergyt2_release (struct ino
 	up(&cinergyt2->sem);
 
 	return dvb_generic_release(inode, file);
-	}
+}
 
 static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
-	{
+{
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 	return (POLLIN | POLLRDNORM | POLLPRI);
-	}
+}
 
 
 static int cinergyt2_ioctl (struct inode *inode, struct file *file,
 		     unsigned cmd, unsigned long arg)
-	{
+{
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 	struct dvbt_get_status_msg *stat = &cinergyt2->status;
@@ -574,7 +567,7 @@ static int cinergyt2_ioctl (struct inode
 		/* UNC are already converted to host byte order... */
 		return put_user(stat->uncorrected_block_count,
 				(__u32 __user *) arg);
-	
+
 	case FE_SET_FRONTEND:
 	{
 		struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -611,7 +604,7 @@ static int cinergyt2_ioctl (struct inode
 	case FE_GET_FRONTEND:
 		/**
 		 *  trivial to implement (see struct dvbt_get_status_msg).
-		 *  equivalent to FE_READ ioctls, but needs 
+		 *  equivalent to FE_READ ioctls, but needs
 		 *  TPS -> linux-dvb parameter set conversion. Feel free
 		 *  to implement this and send us a patch if you need this
 		 *  functionality.
@@ -661,7 +654,7 @@ static int cinergyt2_mmap(struct file *f
 		goto bailout;
 	}
 
-        vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
 	vma->vm_file = file;
 
 	ret = remap_pfn_range(vma, vma->vm_start,
@@ -700,7 +693,7 @@ static void cinergyt2_query_rc (void *da
 	if (down_interruptible(&cinergyt2->sem))
 		return;
 
-	len = cinergyt2_command(cinergyt2, buf, sizeof(buf), 
+	len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
 			     (char *) rc_events, sizeof(rc_events));
 
 	for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
@@ -712,7 +705,7 @@ static void cinergyt2_query_rc (void *da
 			/**
 			 * keyrepeat bit. If we would handle this properly
 			 * we would need to emit down events as long the
-			 * keyrepeat goes, a up event if no further 
+			 * keyrepeat goes, a up event if no further
 			 * repeat bits occur. Would need a timer to implement
 			 * and no other driver does this, so we simply
 			 * emit the last key up/down sequence again.
@@ -733,7 +726,7 @@ static void cinergyt2_query_rc (void *da
 			input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1);
 			input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0);
 			input_sync(&cinergyt2->rc_input_dev);
-	    	}
+		}
 	}
 
 	schedule_delayed_work(&cinergyt2->rc_query_work,
@@ -793,7 +786,7 @@ static int cinergyt2_probe (struct usb_i
 
 	cinergyt2->udev = interface_to_usbdev(intf);
 	cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-	
+
 	if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
 		dprintk(1, "unable to allocate stream urbs\n");
 		kfree(cinergyt2);
@@ -808,8 +801,8 @@ static int cinergyt2_probe (struct usb_i
 	cinergyt2->demux.start_feed = cinergyt2_start_feed;
 	cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
 	cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
-					 DMX_SECTION_FILTERING |
-					 DMX_MEMORY_BASED_FILTERING;
+					    DMX_SECTION_FILTERING |
+					    DMX_MEMORY_BASED_FILTERING;
 
 	if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
 		dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
@@ -820,20 +813,20 @@ static int cinergyt2_probe (struct usb_i
 	cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
 	cinergyt2->dmxdev.capabilities = 0;
 
-	if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, cinergyt2->adapter)) < 0) {
+	if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) {
 		dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
 		goto bailout;
 	}
 
-	if (dvb_net_init(cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
+	if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
 		dprintk(1, "dvb_net_init() failed!\n");
 
-	dvb_register_device(cinergyt2->adapter, &cinergyt2->fedev,
+	dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev,
 			    &cinergyt2_fe_template, cinergyt2,
 			    DVB_DEVICE_FRONTEND);
 
 #ifdef ENABLE_RC
-	init_input_dev(&cinergyt2->rc_input_dev);			
+	init_input_dev(&cinergyt2->rc_input_dev);
 
 	cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY);
 	cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char);
@@ -846,7 +839,7 @@ static int cinergyt2_probe (struct usb_i
 	input_register_device(&cinergyt2->rc_input_dev);
 
 	cinergyt2->rc_input_event = KEY_MAX;
-	
+
 	INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2);
 	schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
 #endif
@@ -855,7 +848,7 @@ static int cinergyt2_probe (struct usb_i
 bailout:
 	dvb_dmxdev_release(&cinergyt2->dmxdev);
 	dvb_dmx_release(&cinergyt2->demux);
-	dvb_unregister_adapter (cinergyt2->adapter);
+	dvb_unregister_adapter (&cinergyt2->adapter);
 	cinergyt2_free_stream_urbs (cinergyt2);
 	kfree(cinergyt2);
 	return -ENOMEM;
@@ -878,16 +871,15 @@ static void cinergyt2_disconnect (struct
 	dvb_net_release(&cinergyt2->dvbnet);
 	dvb_dmxdev_release(&cinergyt2->dmxdev);
 	dvb_dmx_release(&cinergyt2->demux);
-
 	dvb_unregister_device(cinergyt2->fedev);
-	dvb_unregister_adapter(cinergyt2->adapter);
+	dvb_unregister_adapter(&cinergyt2->adapter);
 
 	cinergyt2_free_stream_urbs(cinergyt2);
 	up(&cinergyt2->sem);
 	kfree(cinergyt2);
 }
 
-static int cinergyt2_suspend (struct usb_interface *intf, u32 state)
+static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
@@ -901,7 +893,7 @@ static int cinergyt2_suspend (struct usb
 #endif
 		cancel_delayed_work(&cinergyt2->query_work);
 		if (cinergyt2->streaming)
-		       	cinergyt2_stop_stream_xfer(cinergyt2);
+			cinergyt2_stop_stream_xfer(cinergyt2);
 		flush_scheduled_work();
 		cinergyt2_sleep(cinergyt2, 1);
 	}
@@ -922,7 +914,7 @@ static int cinergyt2_resume (struct usb_
 		cinergyt2_sleep(cinergyt2, 0);
 		cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
 		if (cinergyt2->streaming)
-		       	cinergyt2_start_stream_xfer(cinergyt2);
+			cinergyt2_start_stream_xfer(cinergyt2);
 		schedule_delayed_work(&cinergyt2->query_work, HZ/2);
 	}
 
@@ -941,13 +933,13 @@ static const struct usb_device_id cinerg
 MODULE_DEVICE_TABLE(usb, cinergyt2_table);
 
 static struct usb_driver cinergyt2_driver = {
-	.owner 		= THIS_MODULE,
+	.owner	= THIS_MODULE,
 	.name	= "cinergyT2",
-	.probe 		= cinergyt2_probe,
-	.disconnect 	= cinergyt2_disconnect,
+	.probe	= cinergyt2_probe,
+	.disconnect	= cinergyt2_disconnect,
 	.suspend	= cinergyt2_suspend,
 	.resume		= cinergyt2_resume,
-	.id_table 	= cinergyt2_table
+	.id_table	= cinergyt2_table
 };
 
 static int __init cinergyt2_init (void)
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
--- a/drivers/media/dvb/dibusb/Kconfig
+++ b/drivers/media/dvb/dibusb/Kconfig
@@ -13,7 +13,7 @@ config DVB_DIBUSB
 
 	    TwinhanDTV USB-Ter (VP7041)
 		TwinhanDTV Magic Box (VP7041e)
-	    KWorld V-Stream XPERT DTV - DVB-T USB
+	    KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
 	    Hama DVB-T USB-Box
 	    DiBcom reference devices (non-public)
 	    Ultima Electronic/Artec T1 USB TVBOX
@@ -23,6 +23,7 @@ config DVB_DIBUSB
 	    Artec T1 USB1.1 and USB2.0 boxes
 	    Yakumo/Typhoon DVB-T USB2.0
 	    Hanftek UMT-010 USB2.0
+	    Hauppauge WinTV NOVA-T USB2
 
 	  The VP7041 seems to be identical to "CTS Portable" (Chinese
 	  Television System).
diff --git a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile
--- a/drivers/media/dvb/dibusb/Makefile
+++ b/drivers/media/dvb/dibusb/Makefile
@@ -4,7 +4,7 @@ dvb-dibusb-objs = dvb-dibusb-core.o \
 	dvb-dibusb-firmware.o \
 	dvb-dibusb-remote.o \
 	dvb-dibusb-usb.o \
-	dvb-dibusb-pid.o
+	dvb-fe-dtt200u.o
 
 obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
 
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-core.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
@@ -42,11 +42,16 @@ static int pid_parse;
 module_param(pid_parse, int, 0644);
 MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
 
-static int rc_query_interval;
+static int rc_query_interval = 100;
 module_param(rc_query_interval, int, 0644);
 MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
 
+static int rc_key_repeat_count = 2;
+module_param(rc_key_repeat_count, int, 0644);
+MODULE_PARM_DESC(rc_key_repeat_count, "how many key repeats will be dropped before passing the key event again (default: 2)");
+
 /* Vendor IDs */
+#define USB_VID_ADSTECH						0x06e1
 #define USB_VID_ANCHOR						0x0547
 #define USB_VID_AVERMEDIA					0x14aa
 #define USB_VID_COMPRO						0x185b
@@ -55,13 +60,16 @@ MODULE_PARM_DESC(rc_query_interval, "int
 #define USB_VID_DIBCOM						0x10b8
 #define USB_VID_EMPIA						0xeb1a
 #define USB_VID_GRANDTEC					0x5032
-#define USB_VID_HYPER_PALTEK				0x1025
 #define USB_VID_HANFTEK						0x15f4
+#define USB_VID_HAUPPAUGE					0x2040
+#define USB_VID_HYPER_PALTEK				0x1025
 #define USB_VID_IMC_NETWORKS				0x13d3
 #define USB_VID_TWINHAN						0x1822
 #define USB_VID_ULTIMA_ELECTRONIC			0x05d8
 
 /* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD			0xa333
+#define USB_PID_ADSTECH_USB2_WARM			0xa334
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD		0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM		0x0002
 #define USB_PID_COMPRO_DVBU2000_COLD		0xd000
@@ -90,9 +98,11 @@ MODULE_PARM_DESC(rc_query_interval, "int
 #define USB_PID_UNK_HYPER_PALTEK_COLD		0x005e
 #define USB_PID_UNK_HYPER_PALTEK_WARM		0x005f
 #define USB_PID_HANFTEK_UMT_010_COLD		0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM		0x0025
+#define USB_PID_HANFTEK_UMT_010_WARM		0x0015
 #define USB_PID_YAKUMO_DTT200U_COLD			0x0201
 #define USB_PID_YAKUMO_DTT200U_WARM			0x0301
+#define USB_PID_WINTV_NOVA_T_USB2_COLD		0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM		0x9301
 
 /* USB Driver stuff
  * table of devices that this driver is working with
@@ -109,10 +119,6 @@ static struct usb_device_id dib_table []
 /* 00 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_COLD)},
 /* 01 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_WARM)},
 /* 02 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_COLD) },
-
-/* the following device is actually not supported, but when loading the 
- * correct firmware (ie. its usb ids will change) everything works fine then 
- */
 /* 03 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_WARM) },
 
 /* 04 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
@@ -143,16 +149,20 @@ static struct usb_device_id dib_table []
 /* 28 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_COLD) },
 /* 29 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_WARM) },
 
+/* 30 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,		USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 31 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,		USB_PID_WINTV_NOVA_T_USB2_WARM) },
+/* 32 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
+/* 33 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
 /* 
  * activate the following define when you have one of the devices and want to 
  * build it from build-2.6 in dvb-kernel
  */
-// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES 
+// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
 #ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-/* 31 */	{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
-/* 32 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
-/* 33 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_DIBCOM_ANCHOR_2135_COLD) },
+/* 34 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 35 */	{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
+/* 36 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
+/* 37 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_DIBCOM_ANCHOR_2135_COLD) },
 #endif
 			{ }		/* Terminating entry */
 };
@@ -193,13 +203,17 @@ static struct dibusb_demod dibusb_demod[
 	  254,
 	  { 0xf, 0 }, 
 	},
+	{ DTT200U_FE,
+	  8,
+	  { 0xff,0 }, /* there is no i2c bus in this device */
+	}
 };
 
 static struct dibusb_device_class dibusb_device_classes[] = {
 	{ .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
 	  .firmware = "dvb-dibusb-5.0.0.11.fw",
 	  .pipe_cmd = 0x01, .pipe_data = 0x02, 
-	  .urb_count = 3, .urb_buffer_size = 4096,
+	  .urb_count = 7, .urb_buffer_size = 4096,
 	  DIBUSB_RC_NEC_PROTOCOL,
 	  &dibusb_demod[DIBUSB_DIB3000MB],
 	  &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
@@ -207,7 +221,7 @@ static struct dibusb_device_class dibusb
 	{ DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
 	  "dvb-dibusb-an2235-1.fw",
 	  0x01, 0x02, 
-	  3, 4096,
+	  7, 4096,
 	  DIBUSB_RC_NEC_PROTOCOL,
 	  &dibusb_demod[DIBUSB_DIB3000MB],
 	  &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
@@ -215,20 +229,43 @@ static struct dibusb_device_class dibusb
 	{ DIBUSB2_0,&dibusb_usb_ctrl[2],
 	  "dvb-dibusb-6.0.0.5.fw",
 	  0x01, 0x06, 
-	  3, 188*210,
+	  7, 4096,
 	  DIBUSB_RC_NEC_PROTOCOL,
 	  &dibusb_demod[DIBUSB_DIB3000MC],
 	  &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
 	},
 	{ UMT2_0, &dibusb_usb_ctrl[2],
-	  "dvb-dibusb-umt-1.fw",
-	  0x01, 0x02, 
-	  15, 188*21,
+	  "dvb-dibusb-umt-2.fw",
+	  0x01, 0x06,
+	  20, 512,
 	  DIBUSB_RC_NO,
 	  &dibusb_demod[DIBUSB_MT352],
-//	  &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5],
 	  &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
 	},
+	{ DIBUSB2_0B,&dibusb_usb_ctrl[2],
+	  "dvb-dibusb-adstech-usb2-1.fw",
+	  0x01, 0x06,
+	  7, 4096,
+	  DIBUSB_RC_NEC_PROTOCOL,
+	  &dibusb_demod[DIBUSB_DIB3000MB],
+	  &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+	},
+	{ NOVAT_USB2,&dibusb_usb_ctrl[2],
+	  "dvb-dibusb-nova-t-1.fw",
+	  0x01, 0x06,
+	  7, 4096,
+	  DIBUSB_RC_HAUPPAUGE_PROTO,
+	  &dibusb_demod[DIBUSB_DIB3000MC],
+	  &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
+	},
+	{ DTT200U,&dibusb_usb_ctrl[2],
+	  "dvb-dtt200u-1.fw",
+	  0x01, 0x02,
+	  7, 4096,
+	  DIBUSB_RC_NO,
+	  &dibusb_demod[DTT200U_FE],
+	  NULL, /* no explicit tuner/pll-programming necessary (it has the ENV57H1XD5) */
+	},
 };
 
 static struct dibusb_usb_device dibusb_devices[] = {
@@ -287,30 +324,40 @@ static struct dibusb_usb_device dibusb_d
 		{ &dib_table[27], NULL },
 		{ NULL },
 	},
-	{	"AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0",
-		&dibusb_device_classes[UMT2_0],
+	{	"Hauppauge WinTV NOVA-T USB2",
+		&dibusb_device_classes[NOVAT_USB2],
+		{ &dib_table[30], NULL },
+		{ &dib_table[31], NULL },
+	},
+	{	"DTT200U (Yakumo/Hama/Typhoon) DVB-T USB2.0",
+		&dibusb_device_classes[DTT200U],
 		{ &dib_table[2], NULL },
-		{ NULL },
+		{ &dib_table[3], NULL },
 	},	
 	{	"Hanftek UMT-010 DVB-T USB2.0",
 		&dibusb_device_classes[UMT2_0],
 		{ &dib_table[28], NULL },
 		{ &dib_table[29], NULL },
 	},	
+	{	"KWorld/ADSTech Instant DVB-T USB 2.0",
+		&dibusb_device_classes[DIBUSB2_0B],
+		{ &dib_table[32], NULL },
+		{ &dib_table[33], NULL }, /* device ID with default DIBUSB2_0-firmware */
+	},
 #ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
 	{	"Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
 		&dibusb_device_classes[DIBUSB1_1_AN2235],
-		{ &dib_table[30], NULL },
+		{ &dib_table[34], NULL },
 		{ NULL },
 	},
 	{	"Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
-		&dibusb_device_classes[DIBUSB2_0],
-		{ &dib_table[31], NULL },
-		{ &dib_table[32], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
+		&dibusb_device_classes[DTT200U],
+		{ &dib_table[35], NULL },
+		{ &dib_table[36], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
 	},
 	{	"DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
 		&dibusb_device_classes[DIBUSB1_1],
-		{ &dib_table[33], NULL },
+		{ &dib_table[37], NULL },
 		{ NULL },
 	},
 #endif
@@ -322,7 +369,6 @@ static int dibusb_exit(struct usb_dibusb
 	dibusb_remote_exit(dib);
 	dibusb_fe_exit(dib);
 	dibusb_i2c_exit(dib);
-	dibusb_pid_list_exit(dib);
 	dibusb_dvb_exit(dib);
 	dibusb_urb_exit(dib);
 	deb_info("init_state should be zero now: %x\n",dib->init_state);
@@ -341,7 +387,6 @@ static int dibusb_init(struct usb_dibusb
 	
 	if ((ret = dibusb_urb_init(dib)) ||
 		(ret = dibusb_dvb_init(dib)) || 
-		(ret = dibusb_pid_list_init(dib)) ||
 		(ret = dibusb_i2c_init(dib))) {
 		dibusb_exit(dib);
 		return ret;
@@ -356,30 +401,62 @@ static int dibusb_init(struct usb_dibusb
 	return 0;
 }
 
+static struct dibusb_usb_device * dibusb_device_class_quirk(struct usb_device *udev, struct dibusb_usb_device *dev)
+{
+	int i;
+
+	/* Quirk for the Kworld/ADSTech Instant USB2.0 device. It has the same USB
+	 * IDs like the USB1.1 KWorld after loading the firmware. Which is a bad
+	 * idea and make this quirk necessary.
+	 */
+	if (dev->dev_cl->id == DIBUSB1_1 && udev->speed == USB_SPEED_HIGH) {
+		info("this seems to be the Kworld/ADSTech Instant USB2.0 device or equal.");
+		for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
+			if (dibusb_devices[i].dev_cl->id == DIBUSB2_0B) {
+				dev = &dibusb_devices[i];
+				break;
+			}
+		}
+	}
+
+	return dev;
+}
+
 static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
 {
 	int i,j;
+	struct dibusb_usb_device *dev = NULL;
 	*cold = -1;
+
 	for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
 		for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
 			deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
 			if (dibusb_devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
 				dibusb_devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
 				*cold = 1;
-				return &dibusb_devices[i];
+				dev = &dibusb_devices[i];
+				break;
 			}
 		}
 
+		if (dev != NULL)
+			break;
+
 		for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
 			deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
 			if (dibusb_devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
 				dibusb_devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
 				*cold = 0;
-				return &dibusb_devices[i];
+				dev = &dibusb_devices[i];
+				break;
 			}
 		}
 	}
-	return NULL;
+
+	if (dev != NULL)
+		dev = dibusb_device_class_quirk(udev,dev);
+
+	return dev;
 }
 
 /*
@@ -418,6 +495,7 @@ static int dibusb_probe(struct usb_inter
 		/* store parameters to structures */
 		dib->rc_query_interval = rc_query_interval;
 		dib->pid_parse = pid_parse;
+		dib->rc_key_repeat_count = rc_key_repeat_count;
 
 		usb_set_intfdata(intf, dib);
 		
@@ -446,7 +524,7 @@ static void dibusb_disconnect(struct usb
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
-struct usb_driver dibusb_driver = {
+static struct usb_driver dibusb_driver = {
 	.owner		= THIS_MODULE,
 	.name		= DRIVER_DESC,
 	.probe 		= dibusb_probe,
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
@@ -22,46 +22,34 @@ static u32 urb_compl_count;
 void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
 {
 	struct usb_dibusb *dib = urb->context;
-	int ret;
 
 	deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
 			urb->actual_length);
 
 	urb_compl_count++;
-	if (urb_compl_count % 500 == 0)
+	if (urb_compl_count % 1000 == 0)
 		deb_info("%d urbs completed so far.\n",urb_compl_count);
 
 	switch (urb->status) {
 		case 0:         /* success */
 		case -ETIMEDOUT:    /* NAK */
 			break;
-		case -ECONNRESET:   /* unlink */
+		case -ECONNRESET:   /* kill */
 		case -ENOENT:
 		case -ESHUTDOWN:
 			return;
 		default:        /* error */
-			warn("urb completition error %d.", urb->status);
+			deb_ts("urb completition error %d.", urb->status);
+			break;
 	}
 
-	if (dib->feedcount > 0) {
-		deb_ts("URB return len: %d\n",urb->actual_length);
-		if (urb->actual_length % 188) 
-			deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
-
-		/* Francois recommends to drop not full-filled packets, even if they may 
-		 * contain valid TS packets, at least for USB1.1
-		 *
-		 * if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) */
+	if (dib->feedcount > 0 && urb->actual_length > 0) {
 		if (dib->init_state & DIBUSB_STATE_DVB)
 			dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
-		else
-			deb_ts("URB dropped because of the " 
-					"actual_length or !dvb_is_ready (%d).\n",dib->init_state & DIBUSB_STATE_DVB);
 	} else 
 		deb_ts("URB dropped because of feedcount.\n");
 
-	ret = usb_submit_urb(urb,GFP_ATOMIC);
-	deb_ts("urb resubmitted, (%d)\n",ret);
+	usb_submit_urb(urb,GFP_ATOMIC);
 }
 
 static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) 
@@ -77,7 +65,6 @@ static int dibusb_ctrl_feed(struct dvb_d
 	/* 
 	 * stop feed before setting a new pid if there will be no pid anymore 
 	 */
-//	if ((dib->dibdev->parm->firmware_bug && dib->feedcount) || 
 	if (newfeedcount == 0) {
 		deb_ts("stop feeding\n");
 		if (dib->xfer_ops.fifo_ctrl != NULL) {
@@ -86,23 +73,20 @@ static int dibusb_ctrl_feed(struct dvb_d
 				return -ENODEV;
 			}
 		}
+		dibusb_streaming(dib,0);
 	}
 	
 	dib->feedcount = newfeedcount;
 
-	/* get a free pid from the list and activate it on the device
-	 * specific pid_filter
-	 */
-	if (dib->pid_parse)
-		dibusb_ctrl_pid(dib,dvbdmxfeed,onoff);
+	/* activate the pid on the device specific pid_filter */
+	deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
+	if (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
+		dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
 
 	/* 
-	 * start the feed, either if there is the firmware bug or 
-	 * if this was the first pid to set and there is still a pid for 
-	 * reception.
+	 * start the feed if this was the first pid to set and there is still a pid
+	 * for reception.
 	 */
-	
-//	if ((dib->dibdev->parm->firmware_bug)
 	if (dib->feedcount == onoff && dib->feedcount > 0) {
 
 		deb_ts("controlling pid parser\n");
@@ -142,16 +126,12 @@ int dibusb_dvb_init(struct usb_dibusb *d
 
 	urb_compl_count = 0;
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
-    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) {
-#else
-    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC , 
+	if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
 			THIS_MODULE)) < 0) {
-#endif
 		deb_info("dvb_register_adapter failed: error %d", ret);
 		goto err;
 	}
-	dib->adapter->priv = dib;
+	dib->adapter.priv = dib;
 	
 /* i2c is done in dibusb_i2c_init */
 	
@@ -171,18 +151,18 @@ int dibusb_dvb_init(struct usb_dibusb *d
 	dib->dmxdev.filternum = dib->demux.filternum;
 	dib->dmxdev.demux = &dib->demux.dmx;
 	dib->dmxdev.capabilities = 0;
-	if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) {
+	if ((ret = dvb_dmxdev_init(&dib->dmxdev, &dib->adapter)) < 0) {
 		err("dvb_dmxdev_init failed: error %d",ret);
 		goto err_dmx_dev;
 	}
 
-	dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx);
+	dvb_net_init(&dib->adapter, &dib->dvb_net, &dib->demux.dmx);
 
 	goto success;
 err_dmx_dev:
 	dvb_dmx_release(&dib->demux);
 err_dmx:
-	dvb_unregister_adapter(dib->adapter);
+	dvb_unregister_adapter(&dib->adapter);
 err:
 	return ret;
 success:
@@ -199,7 +179,7 @@ int dibusb_dvb_exit(struct usb_dibusb *d
 		dib->demux.dmx.close(&dib->demux.dmx);
 		dvb_dmxdev_release(&dib->dmxdev);
 		dvb_dmx_release(&dib->demux);
-		dvb_unregister_adapter(dib->adapter);
+		dvb_unregister_adapter(&dib->adapter);
 	}
 	return 0;
 }
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
@@ -1,5 +1,5 @@
 /*
- * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices 
+ * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices
  * based on reference design made by DiBcom (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
@@ -8,47 +8,47 @@
  *
  * This file contains functions for attaching, initializing of an appropriate
  * demodulator/frontend. I2C-stuff is also located here.
- * 
+ *
  */
 #include "dvb-dibusb.h"
 
 #include <linux/usb.h>
 
-int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, 
-		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
+			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
 	u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
 	/* write only ? */
-	int wo = (rbuf == NULL || rlen == 0), 
+	int wo = (rbuf == NULL || rlen == 0),
 		len = 2 + wlen + (wo ? 0 : 2);
-	
+
 	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
 	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
 
 	memcpy(&sndbuf[2],wbuf,wlen);
-	
+
 	if (!wo) {
 		sndbuf[wlen+2] = (rlen >> 8) & 0xff;
 		sndbuf[wlen+3] = rlen & 0xff;
 	}
-	
+
 	return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen);
 }
 
 /*
  * I2C master xfer function
  */
-static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
 {
 	struct usb_dibusb *dib = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&dib->i2c_sem) < 0) 
+	if (down_interruptible(&dib->i2c_sem) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
 		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-	
+
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
@@ -56,13 +56,13 @@ static int dibusb_i2c_xfer(struct i2c_ad
 						msg[i+1].buf,msg[i+1].len) < 0)
 				break;
 			i++;
-		} else 
+		} else
 			if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
 				break;
 	}
-	
+
 	up(&dib->i2c_sem);
-	return i;	
+	return i;
 }
 
 static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
@@ -80,16 +80,16 @@ static struct i2c_algorithm dibusb_algo 
 static int dibusb_general_demod_init(struct dvb_frontend *fe);
 static u8 dibusb_general_pll_addr(struct dvb_frontend *fe);
 static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]);
-static int dibusb_general_pll_set(struct dvb_frontend *fe, 
+static int dibusb_general_pll_set(struct dvb_frontend *fe,
 		struct dvb_frontend_parameters* params, u8 pll_buf[5]);
 
 static struct mt352_config mt352_hanftek_umt_010_config = {
 	.demod_address = 0x1e,
 	.demod_init = dibusb_general_demod_init,
-   	.pll_set = dibusb_general_pll_set,
+	.pll_set = dibusb_general_pll_set,
 };
 
-static int dibusb_tuner_quirk(struct usb_dibusb *dib) 
+static int dibusb_tuner_quirk(struct usb_dibusb *dib)
 {
 	switch (dib->dibdev->dev_cl->id) {
 		case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */
@@ -100,11 +100,11 @@ static int dibusb_tuner_quirk(struct usb
 				{ .flags = 0, .buf = b, .len = 2 },
 				{ .flags = I2C_M_RD, .buf = b2, .len = 1},
 			};
-			
+
 			t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5];
-			
+
 			msg[0].addr = msg[1].addr = t->pll_addr;
-		
+
 			if (dib->xfer_ops.tuner_pass_ctrl != NULL)
 				dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr);
 			dibusb_i2c_xfer(&dib->i2c_adap,msg,2);
@@ -117,7 +117,7 @@ static int dibusb_tuner_quirk(struct usb
 				dib->tuner = t;
 				info("this device has the Panasonic ENV77H11D5 onboard.");
 			}
-			break;	
+			break;
 		}
 		default:
 			break;
@@ -125,34 +125,13 @@ static int dibusb_tuner_quirk(struct usb
 	return 0;
 }
 
-/* there is a ugly pid_filter in the firmware of the umt devices, it is accessible 
- * by i2c address 0x8. Don't know how to deactivate it and how many rows it has.
- */
-static int dibusb_umt_pid_control(struct dvb_frontend *fe, int index, int pid, int onoff)
-{
-	struct usb_dibusb *dib = fe->dvb->priv;
-	u8 b[3];
-	b[0] = index;
-	if (onoff) {
-		b[1] = (pid >> 8) & 0xff;
-		b[2] = pid & 0xff;
-	} else {
-		b[1] = 0;
-		b[2] = 0;
-	}
-	dibusb_i2c_msg(dib, 0x8, b, 3, NULL,0);
-	dibusb_set_streaming_mode(dib,0);
-	dibusb_set_streaming_mode(dib,1);
-	return 0;
-}
-
 int dibusb_fe_init(struct usb_dibusb* dib)
 {
 	struct dib3000_config demod_cfg;
 	int i;
-	
-	if (dib->init_state & DIBUSB_STATE_I2C) { 
-		for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) && 
+
+	if (dib->init_state & DIBUSB_STATE_I2C) {
+		for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) &&
 				dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) {
 
 			demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
@@ -160,6 +139,8 @@ int dibusb_fe_init(struct usb_dibusb* di
 			demod_cfg.pll_set = dibusb_general_pll_set;
 			demod_cfg.pll_init = dibusb_general_pll_init;
 
+			deb_info("demod id: %d %d\n",dib->dibdev->dev_cl->demod->id,DTT200U_FE);
+
 			switch (dib->dibdev->dev_cl->demod->id) {
 				case DIBUSB_DIB3000MB:
 					dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
@@ -170,7 +151,9 @@ int dibusb_fe_init(struct usb_dibusb* di
 				case DIBUSB_MT352:
 					mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
 					dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
-					dib->xfer_ops.pid_ctrl = dibusb_umt_pid_control;
+				break;
+				case DTT200U_FE:
+					dib->fe = dtt200u_fe_attach(dib,&dib->xfer_ops);
 				break;
 			}
 			if (dib->fe != NULL) {
@@ -178,26 +161,29 @@ int dibusb_fe_init(struct usb_dibusb* di
 				break;
 			}
 		}
-		if (dib->fe->ops->sleep != NULL)
-			dib->fe_sleep = dib->fe->ops->sleep;
-		dib->fe->ops->sleep = dibusb_hw_sleep;
-
-		if (dib->fe->ops->init != NULL ) 
-			dib->fe_init = dib->fe->ops->init;
-		dib->fe->ops->init = dibusb_hw_wakeup;
-	
-		/* setting the default tuner */ 
-		dib->tuner = dib->dibdev->dev_cl->tuner;
+		/* if a frontend was found */
+		if (dib->fe != NULL) {
+			if (dib->fe->ops->sleep != NULL)
+				dib->fe_sleep = dib->fe->ops->sleep;
+			dib->fe->ops->sleep = dibusb_hw_sleep;
+
+			if (dib->fe->ops->init != NULL )
+				dib->fe_init = dib->fe->ops->init;
+			dib->fe->ops->init = dibusb_hw_wakeup;
 
-		/* check which tuner is mounted on this device, in case this is unsure */
-		dibusb_tuner_quirk(dib);
+			/* setting the default tuner */
+			dib->tuner = dib->dibdev->dev_cl->tuner;
+
+			/* check which tuner is mounted on this device, in case this is unsure */
+			dibusb_tuner_quirk(dib);
+		}
 	}
 	if (dib->fe == NULL) {
 		err("A frontend driver was not found for device '%s'.",
 		       dib->dibdev->name);
 		return -ENODEV;
 	} else {
-		if (dvb_register_frontend(dib->adapter, dib->fe)) {
+		if (dvb_register_frontend(&dib->adapter, dib->fe)) {
 			err("Frontend registration failed.");
 			if (dib->fe->ops->release)
 				dib->fe->ops->release(dib->fe);
@@ -205,6 +191,7 @@ int dibusb_fe_init(struct usb_dibusb* di
 			return -ENODEV;
 		}
 	}
+
 	return 0;
 }
 
@@ -219,7 +206,7 @@ int dibusb_i2c_init(struct usb_dibusb *d
 {
 	int ret = 0;
 
-	dib->adapter->priv = dib;
+	dib->adapter.priv = dib;
 
 	strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE);
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
@@ -227,15 +214,15 @@ int dibusb_i2c_init(struct usb_dibusb *d
 #else
 	dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
 #endif
-	dib->i2c_adap.algo 		= &dibusb_algo;
+	dib->i2c_adap.algo		= &dibusb_algo;
 	dib->i2c_adap.algo_data = NULL;
 	dib->i2c_adap.id		= I2C_ALGO_BIT;
-	
+
 	i2c_set_adapdata(&dib->i2c_adap, dib);
-	
+
 	if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0)
 		err("could not add i2c adapter");
-	
+
 	dib->init_state |= DIBUSB_STATE_I2C;
 
 	return ret;
@@ -267,21 +254,21 @@ static int thomson_cable_eu_pll_set(stru
 
 	pllbuf[0] = (tfreq >> 8) & 0x7f;
 	pllbuf[1] = tfreq & 0xff;
-   	pllbuf[2] = 0x8e;
-   	pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
+	pllbuf[2] = 0x8e;
+	pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
 	return 0;
 }
 
 static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
 {
-	u32 freq = fep->frequency;
-	u32 tfreq = ((freq + 36125000)*6 + 500000) / 1000000;
+	u32 freq_khz = fep->frequency / 1000;
+	u32 tfreq = ((freq_khz + 36125)*6 + 500) / 1000;
 	u8 TA, T210, R210, ctrl1, cp210, p4321;
-	if (freq > 858000000) {
+	if (freq_khz > 858000) {
 		err("frequency cannot be larger than 858 MHz.");
 		return -EINVAL;
 	}
-	
+
 	// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
 	TA = 1;
 	T210 = 0;
@@ -289,19 +276,19 @@ static int panasonic_cofdm_env57h1xd5_pl
 	ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
 
 // ********    CHARGE PUMP CONFIG vs RF FREQUENCIES     *****************
-	if (freq < 470000000) 
+	if (freq_khz < 470000)
 		cp210 = 2;  // VHF Low and High band ch E12 to E4 to E12
-	else if (freq < 526000000) 
+	else if (freq_khz < 526000)
 		cp210 = 4;  // UHF band Ch E21 to E27
-	else // if (freq < 862000000) 
+	else // if (freq < 862000000)
 		cp210 = 5;  // UHF band ch E28 to E69
 
 //*********************    BW select  *******************************
-	if (freq < 153000000) 
+	if (freq_khz < 153000)
 		p4321  = 1; // BW selected for VHF low
-	else if (freq < 470000000) 
+	else if (freq_khz < 470000)
 		p4321  = 2; // BW selected for VHF high E5 to E12
-	else // if (freq < 862000000) 
+	else // if (freq < 862000000)
 		p4321  = 4; // BW selection for UHF E21 to E69
 
 	pllbuf[0] = (tfreq >> 8) & 0xff;
@@ -313,7 +300,7 @@ static int panasonic_cofdm_env57h1xd5_pl
 }
 
 /*
- *            	            7	6		5	4	3	2	1	0
+ *			    7	6		5	4	3	2	1	0
  * Address Byte             1	1		0	0	0	MA1	MA0	R/~W=0
  *
  * Program divider byte 1   0	n14		n13	n12	n11	n10	n9	n8
@@ -321,14 +308,14 @@ static int panasonic_cofdm_env57h1xd5_pl
  *
  * Control byte 1           1	T/A=1	T2	T1	T0	R2	R1	R0
  *                          1	T/A=0	0	0	ATC	AL2	AL1	AL0
- * 
+ *
  * Control byte 2           CP2	CP1		CP0	BS5	BS4	BS3	BS2	BS1
- * 
+ *
  * MA0/1 = programmable address bits
  * R/~W  = read/write bit (0 for writing)
  * N14-0 = programmable LO frequency
- * 
- * T/A   = test AGC bit (0 = next 6 bits AGC setting, 
+ *
+ * T/A   = test AGC bit (0 = next 6 bits AGC setting,
  *                       1 = next 6 bits test and reference divider ratio settings)
  * T2-0  = test bits
  * R2-0  = reference divider ratio and programmable frequency step
@@ -341,8 +328,6 @@ static int panasonic_cofdm_env57h1xd5_pl
  *             BSn = 0 corresponding port is off, high-impedance state (at power-on)
  *             BSn = 1 corresponding port is on
  */
-
-
 static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4])
 {
 	pllbuf[0] = 0x0b;
@@ -420,14 +405,14 @@ static int panasonic_cofdm_env77h11d5_td
 }
 
 /*
- *            	            7	6	5	4	3	2	1	0
+ *			    7	6	5	4	3	2	1	0
  * Address Byte             1	1	0	0	0	MA1	MA0	R/~W=0
  *
  * Program divider byte 1   0	n14	n13	n12	n11	n10	n9	n8
  * Program divider byte 2	n7	n6	n5	n4	n3	n2	n1	n0
  *
  * Control byte             1	CP	T2	T1	T0	RSA	RSB	OS
- * 
+ *
  * Band Switch byte         X	X	X	P4	P3	P2	P1	P0
  *
  * Auxiliary byte           ATC	AL2	AL1	AL0	0	0	0	0
@@ -437,72 +422,71 @@ static int panasonic_cofdm_env77h11d5_td
  *          0	1	c2 (always valid)
  *          1	0	c4
  *          1	1	c6
- *
- *
- * 
  */
-
-static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4]) 
+static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4])
 {
 	u32 div;
-	u8 p3210, p4;
+	u8 p210, p3;
 
 #define TUNER_MUL 62500
 
 	div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+//	div = ((fep->frequency/1000 + 36166) * 6) / 1000;
 
-	if (fep->frequency < 174500000) 
-		p3210 = 1; // not supported by the tdtp_e102p
+	if (fep->frequency < 174500000)
+		p210 = 1; // not supported by the tdtp_e102p
 	else if (fep->frequency < 230000000) // VHF
-		p3210 = 2;
-	else 
-		p3210 = 4;
+		p210 = 2;
+	else
+		p210 = 4;
 
 	if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
-		p4 = 0;
-	else 
-		p4 = 1;
-		
+		p3 = 0;
+	else
+		p3 = 1;
+
 	pllbuf[0] = (div >> 8) & 0x7f;
 	pllbuf[1] = div & 0xff;
 	pllbuf[2] = 0xce;
-	pllbuf[3] = (p4 << 4) | p3210;
+//	pllbuf[2] = 0xcc;
+	pllbuf[3] = (p3 << 3) | p210;
 
 	return 0;
 }
 
 static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
 {
-	static u8 mt352_clock_config[] = { 0x89, 0xb0, 0x2d };
+	static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
 	static u8 mt352_reset[] = { 0x50, 0x80 };
 	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
 	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg[] = { 0x67, 0x14, 0x22 };
-	static u8 mt352_sec_agc_cfg[] = { 0x69, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x40, 0x40 };
+	static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
 
-	static u8 mt352_unk [] = { 0xb5, 0x7a };
+	static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
+	static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
+	static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
+	static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
+	static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
 
-	static u8 mt352_acq_ctl[] = { 0x53, 0x5f };
-	static u8 mt352_input_freq_1[] = { 0x56, 0xf1, 0x05 };
-	
-//	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+	static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+	static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
 
 	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
 	udelay(2000);
 	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
 	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
-	
+
 	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
 	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
 
-	mt352_write(fe, mt352_sec_agc_cfg, sizeof(mt352_sec_agc_cfg));
+	mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
+	mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
+	mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
+	mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
+	mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
 
-	mt352_write(fe, mt352_unk, sizeof(mt352_unk));
-	
 	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
 	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-	
-//	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
 
 	return 0;
 }
@@ -528,11 +512,11 @@ static u8 dibusb_general_pll_addr(struct
 static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4])
 {
 	if (pll_buf == NULL) {
-		struct i2c_msg msg = { 
-			.addr = dib->tuner->pll_addr, 
-			.flags = 0, 
-			.buf = buf, 
-			.len = sizeof(buf) 
+		struct i2c_msg msg = {
+			.addr = dib->tuner->pll_addr,
+			.flags = 0,
+			.buf = buf,
+			.len = sizeof(buf)
 		};
 		if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
 			return -EIO;
@@ -545,7 +529,7 @@ static int dibusb_pll_i2c_helper(struct 
 	return 0;
 }
 
-static int dibusb_general_pll_init(struct dvb_frontend *fe, 
+static int dibusb_general_pll_init(struct dvb_frontend *fe,
 		u8 pll_buf[5])
 {
 	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
@@ -558,14 +542,14 @@ static int dibusb_general_pll_init(struc
 		default:
 			break;
 	}
-	
+
 	if (ret)
 		return ret;
 
 	return dibusb_pll_i2c_helper(dib,pll_buf,buf);
 }
 
-static int dibusb_general_pll_set(struct dvb_frontend *fe, 
+static int dibusb_general_pll_set(struct dvb_frontend *fe,
 		struct dvb_frontend_parameters *fep, u8 pll_buf[5])
 {
 	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
@@ -573,14 +557,14 @@ static int dibusb_general_pll_set(struct
 	int ret=0;
 
 	switch (dib->tuner->id) {
-		case DIBUSB_TUNER_CABLE_THOMSON: 
-			ret = thomson_cable_eu_pll_set(fep, buf); 
+		case DIBUSB_TUNER_CABLE_THOMSON:
+			ret = thomson_cable_eu_pll_set(fep, buf);
 			break;
 		case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5:
 			ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf);
 			break;
 		case DIBUSB_TUNER_CABLE_LG_TDTP_E102P:
-			ret = lg_tdtp_e102p_tua6034(fep, buf); 
+			ret = lg_tdtp_e102p_tua6034(fep, buf);
 			break;
 		case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
 			ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf);
@@ -590,9 +574,9 @@ static int dibusb_general_pll_set(struct
 			ret = -ENODEV;
 			break;
 	}
-	
+
 	if (ret)
 		return ret;
-	
+
 	return dibusb_pll_i2c_helper(dib,pll_buf,buf);
 }
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
@@ -19,7 +19,7 @@
 static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
 {
 	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
 }
 
 int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
@@ -30,11 +30,13 @@ int dibusb_loadfirmware(struct usb_devic
 	int ret = 0,i;
 	
 	if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
-		err("did not find a valid firmware file. (%s) "
+		err("did not find the firmware file. (%s) "
 			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
 			dibdev->dev_cl->firmware);
 		return ret;
 	}
+
+	info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware);
 	
 	p = kmalloc(fw->size,GFP_KERNEL);	
 	if (p != NULL) {
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-pid.c b/drivers/media/dvb/dibusb/dvb-dibusb-pid.c
deleted file mode 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-pid.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * dvb-dibusb-pid.c is part of the driver for mobile USB Budget DVB-T devices 
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the internal
- * pid-list. This pid-list mirrors the information currently stored in the
- * devices pid-list.
- */
-#include "dvb-dibusb.h"
-
-int dibusb_pid_list_init(struct usb_dibusb *dib)
-{
-	int i;
-	dib->pid_list = kmalloc(sizeof(struct dibusb_pid) * dib->dibdev->dev_cl->demod->pid_filter_count,GFP_KERNEL);
-	if (dib->pid_list == NULL)
-		return -ENOMEM;
-
-	deb_xfer("initializing %d pids for the pid_list.\n",dib->dibdev->dev_cl->demod->pid_filter_count);
-	
-	dib->pid_list_lock = SPIN_LOCK_UNLOCKED;
-	memset(dib->pid_list,0,dib->dibdev->dev_cl->demod->pid_filter_count*(sizeof(struct dibusb_pid)));
-	for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++) {
-		dib->pid_list[i].index = i;
-		dib->pid_list[i].pid = 0;
-		dib->pid_list[i].active = 0;
-	}
-
-	dib->init_state |= DIBUSB_STATE_PIDLIST;
-	return 0;
-}
-
-void dibusb_pid_list_exit(struct usb_dibusb *dib)
-{
-	if (dib->init_state & DIBUSB_STATE_PIDLIST)
-		kfree(dib->pid_list);
-	dib->init_state &= ~DIBUSB_STATE_PIDLIST;
-}
-
-/* fetch a pid from pid_list and set it on or off */
-int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff)
-{
-	int i,ret = -1;
-	unsigned long flags;
-	u16 pid = dvbdmxfeed->pid;
-
-	if (onoff) {
-		spin_lock_irqsave(&dib->pid_list_lock,flags);
-		for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++)
-			if (!dib->pid_list[i].active) {
-				dib->pid_list[i].pid = pid;
-				dib->pid_list[i].active = 1;
-				ret = i;
-				break;
-			}
-		dvbdmxfeed->priv = &dib->pid_list[ret];
-		spin_unlock_irqrestore(&dib->pid_list_lock,flags);
-		
-		if (dib->xfer_ops.pid_ctrl != NULL) 
-			dib->xfer_ops.pid_ctrl(dib->fe,dib->pid_list[ret].index,dib->pid_list[ret].pid,1);
-	} else {
-		struct dibusb_pid *dpid = dvbdmxfeed->priv;
-		
-		if (dib->xfer_ops.pid_ctrl != NULL) 
-			dib->xfer_ops.pid_ctrl(dib->fe,dpid->index,0,0);
-		
-		dpid->pid = 0;
-		dpid->active = 0;
-		ret = dpid->index;
-	}
-	
-	/* a free pid from the list */
-	deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
-
-	return ret;
-}
-
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
@@ -13,7 +13,7 @@
 
 /* Table to map raw key codes to key events.  This should not be hard-wired
    into the kernel.  */
-static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
+static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] =
 {
 	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
 	{ 0x00, 0xff, 0x16, KEY_POWER },
@@ -83,18 +83,58 @@ static const struct { u8 c0, c1, c2; uin
 	{ 0x86, 0x6b, 0x1b, KEY_RIGHT },
 };
 
-/*
- * Read the remote control and feed the appropriate event.
- * NEC protocol is used for remote controls
- */
-static int dibusb_read_remote_control(struct usb_dibusb *dib)
+/* Hauppauge NOVA-T USB2 keys */
+static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = {
+	{ 0xddf, KEY_GOTO },
+	{ 0xdef, KEY_POWER },
+	{ 0xce7, KEY_TV },
+	{ 0xcc7, KEY_VIDEO },
+	{ 0xccf, KEY_AUDIO },
+	{ 0xcd7, KEY_MEDIA },
+	{ 0xcdf, KEY_EPG },
+	{ 0xca7, KEY_UP },
+	{ 0xc67, KEY_RADIO },
+	{ 0xcb7, KEY_LEFT },
+	{ 0xd2f, KEY_OK },
+	{ 0xcbf, KEY_RIGHT },
+	{ 0xcff, KEY_BACK },
+	{ 0xcaf, KEY_DOWN },
+	{ 0xc6f, KEY_MENU },
+	{ 0xc87, KEY_VOLUMEUP },
+	{ 0xc8f, KEY_VOLUMEDOWN },
+	{ 0xc97, KEY_CHANNEL },
+	{ 0xc7f, KEY_MUTE },
+	{ 0xd07, KEY_CHANNELUP },
+	{ 0xd0f, KEY_CHANNELDOWN },
+	{ 0xdbf, KEY_RECORD },
+	{ 0xdb7, KEY_STOP },
+	{ 0xd97, KEY_REWIND },
+	{ 0xdaf, KEY_PLAY },
+	{ 0xda7, KEY_FASTFORWARD },
+	{ 0xd27, KEY_LAST }, /* Skip backwards */
+	{ 0xd87, KEY_PAUSE },
+	{ 0xcf7, KEY_NEXT },
+	{ 0xc07, KEY_0 },
+	{ 0xc0f, KEY_1 },
+	{ 0xc17, KEY_2 },
+	{ 0xc1f, KEY_3 },
+	{ 0xc27, KEY_4 },
+	{ 0xc2f, KEY_5 },
+	{ 0xc37, KEY_6 },
+	{ 0xc3f, KEY_7 },
+	{ 0xc47, KEY_8 },
+	{ 0xc4f, KEY_9 },
+	{ 0xc57, KEY_KPASTERISK },
+	{ 0xc77, KEY_GRAVE }, /* # */
+	{ 0xc5f, KEY_RED },
+	{ 0xd77, KEY_GREEN },
+	{ 0xdc7, KEY_YELLOW },
+	{ 0xd4f, KEY_BLUE},
+};
+
+static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5])
 {
-	u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
-	int ret;
 	int i;
-	if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
-		return ret;
-
 	switch (rb[0]) {
 		case DIBUSB_RC_NEC_KEY_PRESSED:
 			/* rb[1-3] is the actual key, rb[4] is a checksum */
@@ -107,30 +147,100 @@ static int dibusb_read_remote_control(st
 			}
 
 			/* See if we can match the raw key code. */
-			for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) {
-				if (rc_keys[i].c0 == rb[1] &&
-					rc_keys[i].c1 == rb[2] &&
-				    rc_keys[i].c2 == rb[3]) {
-					dib->rc_input_event = rc_keys[i].key;
-					deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
-					/* Signal down and up events for this key. */
-					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
-					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
-					input_sync(&dib->rc_input_dev);
-					break;
+			for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) {
+				if (nec_rc_keys[i].c0 == rb[1] &&
+					nec_rc_keys[i].c1 == rb[2] &&
+					nec_rc_keys[i].c2 == rb[3]) {
+
+					dib->last_event = nec_rc_keys[i].key;
+					return 1;
 				}
 			}
 			break;
-		case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
-			break;
 		case DIBUSB_RC_NEC_KEY_REPEATED:
 			/* rb[1]..rb[4] are always zero.*/
 			/* Repeats often seem to occur so for the moment just ignore this. */
-			deb_rc("Key repeat\n");
+			return 0;
+		case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
+		default:
+			break;
+	}
+	return -1;
+}
+
+static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4])
+{
+	u16 raw;
+	int i,state;
+	switch (rb[0]) {
+		case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
+			raw = ((rb[1] & 0x0f) << 8) | rb[2];
+
+			state = !!(rb[1] & 0x40);
+
+			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state);
+			for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) {
+				if (haupp_rc_keys[i].raw == raw) {
+					if (dib->last_event == haupp_rc_keys[i].key &&
+						dib->last_state == state) {
+						deb_rc("key repeat\n");
+						return 0;
+					} else {
+						dib->last_event = haupp_rc_keys[i].key;
+						dib->last_state = state;
+						return 1;
+					}
+				}
+			}
+
 			break;
+		case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
 		default:
 			break;
 	}
+	return -1;
+}
+
+/*
+ * Read the remote control and feed the appropriate event.
+ * NEC protocol is used for remote controls
+ */
+static int dibusb_read_remote_control(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
+	int ret,event = 0;
+
+	if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
+		return ret;
+
+	switch (dib->dibdev->dev_cl->remote_type) {
+		case DIBUSB_RC_NEC_PROTOCOL:
+			event = dibusb_key2event_nec(dib,rb);
+			break;
+		case DIBUSB_RC_HAUPPAUGE_PROTO:
+			event = dibusb_key2event_hauppauge(dib,rb);
+		default:
+			break;
+	}
+
+	/* key repeat */
+	if (event == 0)
+		if (++dib->repeat_key_count < dib->rc_key_repeat_count) {
+			deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count);
+			event = -1; /* skip this key repeat */
+		}
+
+	if (event == 1 || event == 0) {
+		deb_rc("Translated key 0x%04x\n",event);
+
+		/* Signal down and up events for this key. */
+		input_report_key(&dib->rc_input_dev, dib->last_event, 1);
+		input_report_key(&dib->rc_input_dev, dib->last_event, 0);
+		input_sync(&dib->rc_input_dev);
+
+		if (event == 1)
+			dib->repeat_key_count = 0;
+	}
 	return 0;
 }
 
@@ -161,12 +271,21 @@ int dibusb_remote_init(struct usb_dibusb
 	dib->rc_input_dev.keycodemax = KEY_MAX;
 	dib->rc_input_dev.name = DRIVER_DESC " remote control";
 
-	for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
-		set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
+	switch (dib->dibdev->dev_cl->remote_type) {
+		case DIBUSB_RC_NEC_PROTOCOL:
+			for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++)
+				set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit);
+			break;
+		case DIBUSB_RC_HAUPPAUGE_PROTO:
+			for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++)
+				set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit);
+			break;
+		default:
+			break;
+	}
 
-	input_register_device(&dib->rc_input_dev);
 
-	dib->rc_input_event = KEY_MAX;
+	input_register_device(&dib->rc_input_dev);
 
 	INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
 
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
--- a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
@@ -1,12 +1,12 @@
 /*
- * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices 
+ * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
  * based on reference design made by DiBcom (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * see dvb-dibusb-core.c for more copyright details.
  *
- * This file contains functions for initializing and handling the 
+ * This file contains functions for initializing and handling the
  * usb specific stuff.
  */
 #include "dvb-dibusb.h"
@@ -25,18 +25,12 @@ int dibusb_readwrite_usb(struct usb_dibu
 	if ((ret = down_interruptible(&dib->usb_sem)))
 		return ret;
 
-	if (dib->feedcount && 
-		wbuf[0] == DIBUSB_REQ_I2C_WRITE && 
-		dib->dibdev->dev_cl->id == DIBUSB1_1)
-		deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
-				"(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
-			
 	debug_dump(wbuf,wlen);
 
 	ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
 			dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
 			DIBUSB_I2C_TIMEOUT);
-		
+
 	if (ret)
 		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
 	else
@@ -55,7 +49,7 @@ int dibusb_readwrite_usb(struct usb_dibu
 			debug_dump(rbuf,actlen);
 		}
 	}
-	
+
 	up(&dib->usb_sem);
 	return ret;
 }
@@ -63,15 +57,18 @@ int dibusb_readwrite_usb(struct usb_dibu
 /*
  * Cypress controls
  */
+int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+	return dibusb_readwrite_usb(dib,buf,len,NULL,0);
+}
 
 #if 0
-/* 
- * #if 0'ing the following functions as they are not in use _now_, 
+/*
+ * #if 0'ing the following functions as they are not in use _now_,
  * but probably will be sometime.
  */
-
 /*
- * do not use this, just a workaround for a bug, 
+ * do not use this, just a workaround for a bug,
  * which will hopefully never occur :).
  */
 int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
@@ -79,15 +76,10 @@ int dibusb_interrupt_read_loop(struct us
 	u8 b[1] = { DIBUSB_REQ_INTR_READ };
 	return dibusb_write_usb(dib,b,1);
 }
-
-#endif 
-static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
-	return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
+#endif
 
 /*
- * ioctl for the firmware 
+ * ioctl for the firmware
  */
 static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
 {
@@ -111,11 +103,18 @@ int dibusb_hw_wakeup(struct dvb_frontend
 	struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
 	u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
 	deb_info("dibusb-device is getting up.\n");
-	dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-	
+
+	switch (dib->dibdev->dev_cl->id) {
+		case DTT200U:
+			break;
+		default:
+			dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+			break;
+	}
+
 	if (dib->fe_init)
 		return dib->fe_init(fe);
-	
+
 	return 0;
 }
 
@@ -124,11 +123,19 @@ int dibusb_hw_sleep(struct dvb_frontend 
 	struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
 	u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
 	deb_info("dibusb-device is going to bed.\n");
-	dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-
+	/* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
+	switch (dib->dibdev->dev_cl->id) {
+		case DIBUSB1_1:
+		case NOVAT_USB2:
+		case DTT200U:
+			break;
+		default:
+			dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+			break;
+	}
 	if (dib->fe_sleep)
 		return dib->fe_sleep(fe);
-	
+
 	return 0;
 }
 
@@ -138,18 +145,57 @@ int dibusb_set_streaming_mode(struct usb
 	return dibusb_readwrite_usb(dib,b,2,NULL,0);
 }
 
+static int dibusb_urb_kill(struct usb_dibusb *dib)
+{
+	int i;
+deb_info("trying to kill urbs\n");
+	if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
+		for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+			deb_info("killing URB no. %d.\n",i);
+
+			/* stop the URB */
+			usb_kill_urb(dib->urb_list[i]);
+		}
+	} else
+	deb_info(" URBs not killed.\n");
+	dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
+	return 0;
+}
+
+static int dibusb_urb_submit(struct usb_dibusb *dib)
+{
+	int i,ret;
+	if (dib->init_state & DIBUSB_STATE_URB_INIT) {
+		for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+			deb_info("submitting URB no. %d\n",i);
+			if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
+				err("could not submit buffer urb no. %d - get them all back\n",i);
+				dibusb_urb_kill(dib);
+				return ret;
+			}
+			dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+		}
+	}
+	return 0;
+}
+
 int dibusb_streaming(struct usb_dibusb *dib,int onoff)
 {
+	if (onoff)
+		dibusb_urb_submit(dib);
+	else
+		dibusb_urb_kill(dib);
+
 	switch (dib->dibdev->dev_cl->id) {
 		case DIBUSB2_0:
+		case DIBUSB2_0B:
+		case NOVAT_USB2:
+		case UMT2_0:
 			if (onoff)
 				return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
 			else
 				return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
 			break;
-		case UMT2_0: 
-			return dibusb_set_streaming_mode(dib,onoff);
-			break;
 		default:
 			break;
 	}
@@ -158,10 +204,10 @@ int dibusb_streaming(struct usb_dibusb *
 
 int dibusb_urb_init(struct usb_dibusb *dib)
 {
-	int ret,i,bufsize,def_pid_parse = 1;
-	
+	int i,bufsize,def_pid_parse = 1;
+
 	/*
-	 * when reloading the driver w/o replugging the device 
+	 * when reloading the driver w/o replugging the device
 	 * a timeout occures, this helps
 	 */
 	usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
@@ -175,7 +221,7 @@ int dibusb_urb_init(struct usb_dibusb *d
 	memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
 
 	dib->init_state |= DIBUSB_STATE_URB_LIST;
-	
+
 	bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
 	deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
 	/* allocate the actual buffer for the URBs */
@@ -185,7 +231,7 @@ int dibusb_urb_init(struct usb_dibusb *d
 	}
 	deb_info("allocation complete\n");
 	memset(dib->buffer,0,bufsize);
-	
+
 	dib->init_state |= DIBUSB_STATE_URB_BUF;
 
 	/* allocate and submit the URBs */
@@ -193,55 +239,49 @@ int dibusb_urb_init(struct usb_dibusb *d
 		if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
 			return -ENOMEM;
 		}
-		deb_info("submitting URB no. %d\n",i);
-		
-		usb_fill_bulk_urb( dib->urb_list[i], dib->udev, 
+
+		usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
 				usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
-				&dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], 
-				dib->dibdev->dev_cl->urb_buffer_size, 
+				&dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
+				dib->dibdev->dev_cl->urb_buffer_size,
 				dibusb_urb_complete, dib);
-		
+
 		dib->urb_list[i]->transfer_flags = 0;
 
-		if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
-			err("could not submit buffer urb no. %d\n",i);
-			return ret;
-		}
-		dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+		dib->init_state |= DIBUSB_STATE_URB_INIT;
 	}
 
 	/* dib->pid_parse here contains the value of the module parameter */
 	/* decide if pid parsing can be deactivated:
-	 * is possible (by speed) and wanted (by user)
+	 * is possible (by device type) and wanted (by user)
 	 */
 	switch (dib->dibdev->dev_cl->id) {
 		case DIBUSB2_0:
+		case DIBUSB2_0B:
 			if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
 				def_pid_parse = 0;
 				info("running at HIGH speed, will deliver the complete TS.");
 			} else
 				info("will use pid_parsing.");
 			break;
-		default: 
+		default:
 			break;
 	}
 	/* from here on it contains the device and user decision */
 	dib->pid_parse = def_pid_parse;
-	
+
 	return 0;
 }
 
 int dibusb_urb_exit(struct usb_dibusb *dib)
 {
 	int i;
+
+	dibusb_urb_kill(dib);
+
 	if (dib->init_state & DIBUSB_STATE_URB_LIST) {
 		for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
 			if (dib->urb_list[i] != NULL) {
-				deb_info("killing URB no. %d.\n",i);
-
-				/* stop the URBs */
-				usb_kill_urb(dib->urb_list[i]);
-				
 				deb_info("freeing URB no. %d.\n",i);
 				/* free the URBs */
 				usb_free_urb(dib->urb_list[i]);
@@ -249,7 +289,6 @@ int dibusb_urb_exit(struct usb_dibusb *d
 		}
 		/* free the urb array */
 		kfree(dib->urb_list);
-		dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
 		dib->init_state &= ~DIBUSB_STATE_URB_LIST;
 	}
 
@@ -259,5 +298,6 @@ int dibusb_urb_exit(struct usb_dibusb *d
 			dib->buffer,dib->dma_handle);
 
 	dib->init_state &= ~DIBUSB_STATE_URB_BUF;
+	dib->init_state &= ~DIBUSB_STATE_URB_INIT;
 	return 0;
 }
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
--- a/drivers/media/dvb/dibusb/dvb-dibusb.h
+++ b/drivers/media/dvb/dibusb/dvb-dibusb.h
@@ -44,7 +44,7 @@ extern int dvb_dibusb_debug;
 
 /* Version information */
 #define DRIVER_VERSION "0.3"
-#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
+#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
 #define deb_info(args...) dprintk(0x01,args)
@@ -55,9 +55,12 @@ extern int dvb_dibusb_debug;
 #define deb_rc(args...)   dprintk(0x20,args)
 
 /* generic log methods - taken from usb.h */
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     "dvb-dibusb: " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    "dvb-dibusb: " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg)
 
 struct dibusb_usb_controller {
 	const char *name;       /* name of the usb controller */
@@ -69,6 +72,9 @@ typedef enum {
 	DIBUSB1_1_AN2235,
 	DIBUSB2_0,
 	UMT2_0,
+	DIBUSB2_0B,
+	NOVAT_USB2,
+	DTT200U,
 } dibusb_class_t;
 
 typedef enum {
@@ -82,11 +88,13 @@ typedef enum {
 	DIBUSB_DIB3000MB = 0,
 	DIBUSB_DIB3000MC,
 	DIBUSB_MT352,
+	DTT200U_FE,
 } dibusb_demodulator_t;
 
 typedef enum {
 	DIBUSB_RC_NO = 0,
-	DIBUSB_RC_NEC_PROTOCOL = 1,
+	DIBUSB_RC_NEC_PROTOCOL,
+	DIBUSB_RC_HAUPPAUGE_PROTO,
 } dibusb_remote_t;
 
 struct dibusb_tuner {
@@ -113,7 +121,7 @@ struct dibusb_device_class {
 
 	int pipe_cmd;                                 /* command pipe (read/write) */
 	int pipe_data;                                /* data pipe */
-	
+
 	int urb_count;                                /* number of data URBs to be submitted */
 	int urb_buffer_size;                          /* the size of the buffer for each URB */
 
@@ -149,11 +157,11 @@ struct usb_dibusb {
 #define DIBUSB_STATE_INIT       0x000
 #define DIBUSB_STATE_URB_LIST   0x001
 #define DIBUSB_STATE_URB_BUF    0x002
-#define DIBUSB_STATE_URB_SUBMIT 0x004 
+#define DIBUSB_STATE_URB_INIT	0x004
 #define DIBUSB_STATE_DVB        0x008
 #define DIBUSB_STATE_I2C        0x010
 #define DIBUSB_STATE_REMOTE		0x020
-#define DIBUSB_STATE_PIDLIST    0x040
+#define DIBUSB_STATE_URB_SUBMIT 0x040
 	int init_state;
 
 	int feedcount;
@@ -172,12 +180,8 @@ struct usb_dibusb {
 	struct semaphore usb_sem;
 	struct semaphore i2c_sem;
 
-	/* pid filtering */
-	spinlock_t pid_list_lock;
-	struct dibusb_pid *pid_list;
-	
 	/* dvb */
-	struct dvb_adapter *adapter;
+	struct dvb_adapter adapter;
 	struct dmxdev dmxdev;
 	struct dvb_demux demux;
 	struct dvb_net dvb_net;
@@ -189,7 +193,10 @@ struct usb_dibusb {
 	/* remote control */
 	struct input_dev rc_input_dev;
 	struct work_struct rc_query_work;
-	int rc_input_event;
+	int last_event;
+	int last_state; /* for Hauppauge RC protocol */
+	int repeat_key_count;
+	int rc_key_repeat_count; /* module parameter */
 
 	/* module parameters */
 	int pid_parse;
@@ -206,8 +213,6 @@ int dibusb_remote_exit(struct usb_dibusb
 int dibusb_remote_init(struct usb_dibusb *dib);
 
 /* dvb-dibusb-fe-i2c.c */
-int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, 
-		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen);
 int dibusb_fe_init(struct usb_dibusb* dib);
 int dibusb_fe_exit(struct usb_dibusb *dib);
 int dibusb_i2c_init(struct usb_dibusb *dib);
@@ -221,6 +226,7 @@ int dibusb_dvb_exit(struct usb_dibusb *d
 /* dvb-dibusb-usb.c */
 int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
 	u16 rlen);
+int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len);
 
 int dibusb_hw_wakeup(struct dvb_frontend *);
 int dibusb_hw_sleep(struct dvb_frontend *);
@@ -230,19 +236,17 @@ int dibusb_streaming(struct usb_dibusb *
 int dibusb_urb_init(struct usb_dibusb *);
 int dibusb_urb_exit(struct usb_dibusb *);
 
-/* dvb-dibusb-pid.c */
-int dibusb_pid_list_init(struct usb_dibusb *dib);
-void dibusb_pid_list_exit(struct usb_dibusb *dib);
-int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff);
+/* dvb-fe-dtt200u.c */
+struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *);
 
 /* i2c and transfer stuff */
-#define DIBUSB_I2C_TIMEOUT				HZ*5
+#define DIBUSB_I2C_TIMEOUT				5000
 
-/* 
+/*
  * protocol of all dibusb related devices
  */
 
-/* 
+/*
  * bulk msg to/from endpoint 0x01
  *
  * general structure:
@@ -252,23 +256,23 @@ int dibusb_ctrl_pid(struct usb_dibusb *d
 #define DIBUSB_REQ_START_READ			0x00
 #define DIBUSB_REQ_START_DEMOD			0x01
 
-/* 
- * i2c read 
+/*
+ * i2c read
  * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
  * bulk read:  byte_buffer (length_word bytes)
  */
-#define DIBUSB_REQ_I2C_READ  			0x02
- 
+#define DIBUSB_REQ_I2C_READ			0x02
+
 /*
  * i2c write
  * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
  */
-#define DIBUSB_REQ_I2C_WRITE 			0x03
+#define DIBUSB_REQ_I2C_WRITE			0x03
 
-/* 
- * polling the value of the remote control 
+/*
+ * polling the value of the remote control
  * bulk write: 0x04
- * bulk read:  byte_buffer (5 bytes) 
+ * bulk read:  byte_buffer (5 bytes)
  *
  * first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
  */
@@ -278,27 +282,31 @@ int dibusb_ctrl_pid(struct usb_dibusb *d
 #define DIBUSB_RC_NEC_KEY_PRESSED		0x01
 #define DIBUSB_RC_NEC_KEY_REPEATED		0x02
 
+/* additional status values for Hauppauge Remote Control Protocol */
+#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED	0x01
+#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY	0x03
+
 /* streaming mode:
- * bulk write: 0x05 mode_byte 
+ * bulk write: 0x05 mode_byte
  *
  * mode_byte is mostly 0x00
  */
 #define DIBUSB_REQ_SET_STREAMING_MODE	0x05
 
 /* interrupt the internal read loop, when blocking */
-#define DIBUSB_REQ_INTR_READ		   	0x06
+#define DIBUSB_REQ_INTR_READ			0x06
 
 /* io control
  * 0x07 cmd_byte param_bytes
  *
  * param_bytes can be up to 32 bytes
  *
- * cmd_byte function    parameter name 
+ * cmd_byte function    parameter name
  * 0x00     power mode
  *                      0x00      sleep
  *                      0x01      wakeup
  *
- * 0x01     enable streaming 
+ * 0x01     enable streaming
  * 0x02     disable streaming
  *
  *
diff --git a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
@@ -0,0 +1,263 @@
+/*
+ * dvb-dtt200u-fe.c is a driver which implements the frontend-part of the
+ * Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as
+ * it uses the usb-transfer functions directly (maybe creating a
+ * generic-dvb-usb-lib for all usb-drivers will be reduce some more code.)
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * see dvb-dibusb-core.c for copyright details.
+ */
+
+/* guessed protocol description (reverse engineered):
+ * read
+ *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
+ *  81 - <TS_LOCK> <current frequency divided by 250000>
+ *  82 - crash - do not touch
+ *  83 - crash - do not touch
+ *  84 - remote control
+ *  85 - crash - do not touch (OK, stop testing here)
+ *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
+ *  89 - noise-to-signal
+ *	8a - unkown 1 byte - signal_strength
+ *  8c - ber ???
+ *  8d - ber
+ *  8e - unc
+ *
+ * write
+ *  02 - bandwidth
+ *  03 - frequency (divided by 250000)
+ *  04 - pid table (index pid(7:0) pid(12:8))
+ *  05 - reset the pid table
+ *  08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ */
+
+#include "dvb-dibusb.h"
+#include "dvb_frontend.h"
+
+struct dtt200u_fe_state {
+	struct usb_dibusb *dib;
+
+	struct dvb_frontend_parameters fep;
+	struct dvb_frontend frontend;
+};
+
+#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
+
+static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw[1] = { 0x81 };
+	u8 br[3] = { 0 };
+//	u8 bdeb[5] = { 0 };
+
+	dibusb_readwrite_usb(state->dib,bw,1,br,3);
+	switch (br[0]) {
+		case 0x01:
+			*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			break;
+		case 0x00:
+			*stat = 0;
+			break;
+		default:
+			moan("br[0]",0x81);
+			break;
+	}
+
+//	bw[0] = 0x88;
+//	dibusb_readwrite_usb(state->dib,bw,1,bdeb,5);
+
+//	deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
+
+	return 0;
+}
+static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw[1] = { 0x8d };
+	*ber = 0;
+	dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3);
+	return 0;
+}
+
+static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw[1] = { 0x8c };
+	*unc = 0;
+	dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3);
+	return 0;
+}
+
+static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw[1] = { 0x8a };
+	u8 b;
+	dibusb_readwrite_usb(state->dib,bw,1,&b, 1);
+	*strength = (b << 8) | b;
+	return 0;
+}
+
+static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw[1] = { 0x89 };
+	u8 br[1] = { 0 };
+	dibusb_readwrite_usb(state->dib,bw,1,br,1);
+	*snr = ((0xff - br[0]) << 8) | (0xff - br[0]);
+	return 0;
+}
+
+static int dtt200u_fe_init(struct dvb_frontend* fe)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 b[] = { 0x01 };
+	return dibusb_write_usb(state->dib,b,1);
+}
+
+static int dtt200u_fe_sleep(struct dvb_frontend* fe)
+{
+	return dtt200u_fe_init(fe);
+}
+
+static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1500;
+	tune->step_size = 166667;
+	tune->max_drift = 166667 * 2;
+	return 0;
+}
+
+static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u16 freq = fep->frequency / 250000;
+	u8 bw,bwbuf[2] = { 0x03, 0 }, freqbuf[3] = { 0x02, 0, 0 };
+
+	switch (fep->u.ofdm.bandwidth) {
+		case BANDWIDTH_8_MHZ: bw = 8; break;
+		case BANDWIDTH_7_MHZ: bw = 7; break;
+		case BANDWIDTH_6_MHZ: bw = 6; break;
+		case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+		default:
+			return -EINVAL;
+	}
+	deb_info("set_frontend\n");
+
+	bwbuf[1] = bw;
+	dibusb_write_usb(state->dib,bwbuf,2);
+
+	freqbuf[1] = freq & 0xff;
+	freqbuf[2] = (freq >> 8) & 0xff;
+	dibusb_write_usb(state->dib,freqbuf,3);
+
+	memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+
+	return 0;
+}
+
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
+	return 0;
+}
+
+static void dtt200u_fe_release(struct dvb_frontend* fe)
+{
+	struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
+{
+	struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+	u8 b_pid[4];
+	pid = onoff ? pid : 0;
+
+	b_pid[0] = 0x04;
+	b_pid[1] = index;
+	b_pid[2] = pid & 0xff;
+	b_pid[3] = (pid >> 8) & 0xff;
+
+	dibusb_write_usb(state->dib,b_pid,4);
+	return 0;
+}
+
+static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+	struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+	u8 b_streaming[2] = { 0x08, onoff };
+	u8 b_rst_pid[1] = { 0x05 };
+
+	dibusb_write_usb(state->dib,b_streaming,2);
+
+	if (!onoff)
+		dibusb_write_usb(state->dib,b_rst_pid,1);
+	return 0;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops;
+
+struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops)
+{
+	struct dtt200u_fe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+	memset(state,0,sizeof(struct dtt200u_fe_state));
+
+	deb_info("attaching frontend dtt200u\n");
+
+	state->dib = dib;
+
+	state->frontend.ops = &dtt200u_fe_ops;
+	state->frontend.demodulator_priv = state;
+
+	xfer_ops->fifo_ctrl = dtt200u_fifo_control;
+	xfer_ops->pid_ctrl = dtt200u_pid_control;
+
+	goto success;
+error:
+	return NULL;
+success:
+	return &state->frontend;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops = {
+	.info = {
+		.name			= "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 250000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = dtt200u_fe_release,
+
+	.init = dtt200u_fe_init,
+	.sleep = dtt200u_fe_sleep,
+
+	.set_frontend = dtt200u_fe_set_frontend,
+	.get_frontend = dtt200u_fe_get_frontend,
+	.get_tune_settings = dtt200u_fe_get_tune_settings,
+
+	.read_status = dtt200u_fe_read_status,
+	.read_ber = dtt200u_fe_read_ber,
+	.read_signal_strength = dtt200u_fe_read_signal_strength,
+	.read_snr = dtt200u_fe_read_snr,
+	.read_ucblocks = dtt200u_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -1,8 +1,8 @@
-/* 
- * demux.h 
+/*
+ * demux.h
  *
  * Copyright (c) 2002 Convergence GmbH
- * 
+ *
  * based on code:
  * Copyright (c) 2000 Nokia Research Center
  *                    Tampere, FINLAND
@@ -23,56 +23,56 @@
  *
  */
 
-#ifndef __DEMUX_H 
-#define __DEMUX_H 
+#ifndef __DEMUX_H
+#define __DEMUX_H
 
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/list.h> 
-#include <linux/time.h> 
+#include <linux/list.h>
+#include <linux/time.h>
 
-/*--------------------------------------------------------------------------*/ 
-/* Common definitions */ 
-/*--------------------------------------------------------------------------*/ 
+/*--------------------------------------------------------------------------*/
+/* Common definitions */
+/*--------------------------------------------------------------------------*/
 
 /*
  * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
- */ 
+ */
 
-#ifndef DMX_MAX_FILTER_SIZE 
+#ifndef DMX_MAX_FILTER_SIZE
 #define DMX_MAX_FILTER_SIZE 18
-#endif 
+#endif
 
 /*
  * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
- */ 
+ */
 
-#ifndef DMX_MAX_SECFEED_SIZE 
+#ifndef DMX_MAX_SECFEED_SIZE
 #define DMX_MAX_SECFEED_SIZE 4096
-#endif 
+#endif
 
 
 /*
- * enum dmx_success: Success codes for the Demux Callback API. 
- */ 
+ * enum dmx_success: Success codes for the Demux Callback API.
+ */
 
-enum dmx_success { 
-  DMX_OK = 0, /* Received Ok */ 
-  DMX_LENGTH_ERROR, /* Incorrect length */ 
-  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ 
-  DMX_CRC_ERROR, /* Incorrect CRC */ 
-  DMX_FRAME_ERROR, /* Frame alignment error */ 
-  DMX_FIFO_ERROR, /* Receiver FIFO overrun */ 
-  DMX_MISSED_ERROR /* Receiver missed packet */ 
-} ; 
+enum dmx_success {
+  DMX_OK = 0, /* Received Ok */
+  DMX_LENGTH_ERROR, /* Incorrect length */
+  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
+  DMX_CRC_ERROR, /* Incorrect CRC */
+  DMX_FRAME_ERROR, /* Frame alignment error */
+  DMX_FIFO_ERROR, /* Receiver FIFO overrun */
+  DMX_MISSED_ERROR /* Receiver missed packet */
+} ;
 
-/*--------------------------------------------------------------------------*/ 
-/* TS packet reception */ 
+/*--------------------------------------------------------------------------*/
+/* TS packet reception */
 /*--------------------------------------------------------------------------*/
 
 /* TS filter type for set() */
 
-#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */ 
+#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */
 #define	TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
 			       payload (<=184 bytes per packet) to callback */
 #define TS_DECODER      4   /* send stream to built-in decoder (if present) */
@@ -116,38 +116,38 @@ enum dmx_ts_pes
 #define DMX_TS_PES_PCR      DMX_TS_PES_PCR0
 
 
-struct dmx_ts_feed { 
+struct dmx_ts_feed {
         int is_filtering; /* Set to non-zero when filtering in progress */
         struct dmx_demux *parent; /* Back-pointer */
-        void *priv; /* Pointer to private data of the API client */ 
-        int (*set) (struct dmx_ts_feed *feed, 
+        void *priv; /* Pointer to private data of the API client */
+        int (*set) (struct dmx_ts_feed *feed,
 		    u16 pid,
-		    int type, 
+		    int type,
 		    enum dmx_ts_pes pes_type,
-		    size_t callback_length, 
-		    size_t circular_buffer_size, 
-		    int descramble, 
-		    struct timespec timeout); 
-        int (*start_filtering) (struct dmx_ts_feed* feed); 
-        int (*stop_filtering) (struct dmx_ts_feed* feed); 
+		    size_t callback_length,
+		    size_t circular_buffer_size,
+		    int descramble,
+		    struct timespec timeout);
+        int (*start_filtering) (struct dmx_ts_feed* feed);
+        int (*stop_filtering) (struct dmx_ts_feed* feed);
 };
 
-/*--------------------------------------------------------------------------*/ 
-/* Section reception */ 
-/*--------------------------------------------------------------------------*/ 
-
-struct dmx_section_filter { 
-        u8 filter_value [DMX_MAX_FILTER_SIZE]; 
-        u8 filter_mask [DMX_MAX_FILTER_SIZE]; 
-        u8 filter_mode [DMX_MAX_FILTER_SIZE]; 
-        struct dmx_section_feed* parent; /* Back-pointer */ 
-        void* priv; /* Pointer to private data of the API client */ 
+/*--------------------------------------------------------------------------*/
+/* Section reception */
+/*--------------------------------------------------------------------------*/
+
+struct dmx_section_filter {
+        u8 filter_value [DMX_MAX_FILTER_SIZE];
+        u8 filter_mask [DMX_MAX_FILTER_SIZE];
+        u8 filter_mode [DMX_MAX_FILTER_SIZE];
+        struct dmx_section_feed* parent; /* Back-pointer */
+        void* priv; /* Pointer to private data of the API client */
 };
 
-struct dmx_section_feed { 
-        int is_filtering; /* Set to non-zero when filtering in progress */ 
+struct dmx_section_feed {
+        int is_filtering; /* Set to non-zero when filtering in progress */
         struct dmx_demux* parent; /* Back-pointer */
-        void* priv; /* Pointer to private data of the API client */ 
+        void* priv; /* Pointer to private data of the API client */
 
         int check_crc;
 	u32 crc_val;
@@ -156,42 +156,42 @@ struct dmx_section_feed { 
         u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
         u16 secbufp, seclen, tsfeedp;
 
-        int (*set) (struct dmx_section_feed* feed, 
-		    u16 pid, 
-		    size_t circular_buffer_size, 
-		    int descramble, 
-		    int check_crc); 
-        int (*allocate_filter) (struct dmx_section_feed* feed, 
-				struct dmx_section_filter** filter); 
-        int (*release_filter) (struct dmx_section_feed* feed, 
-			       struct dmx_section_filter* filter); 
-        int (*start_filtering) (struct dmx_section_feed* feed); 
-        int (*stop_filtering) (struct dmx_section_feed* feed); 
+        int (*set) (struct dmx_section_feed* feed,
+		    u16 pid,
+		    size_t circular_buffer_size,
+		    int descramble,
+		    int check_crc);
+        int (*allocate_filter) (struct dmx_section_feed* feed,
+				struct dmx_section_filter** filter);
+        int (*release_filter) (struct dmx_section_feed* feed,
+			       struct dmx_section_filter* filter);
+        int (*start_filtering) (struct dmx_section_feed* feed);
+        int (*stop_filtering) (struct dmx_section_feed* feed);
 };
 
-/*--------------------------------------------------------------------------*/ 
-/* Callback functions */ 
-/*--------------------------------------------------------------------------*/ 
+/*--------------------------------------------------------------------------*/
+/* Callback functions */
+/*--------------------------------------------------------------------------*/
 
-typedef int (*dmx_ts_cb) ( const u8 * buffer1, 
+typedef int (*dmx_ts_cb) ( const u8 * buffer1,
 			   size_t buffer1_length,
-			   const u8 * buffer2, 
+			   const u8 * buffer2,
 			   size_t buffer2_length,
-			   struct dmx_ts_feed* source, 
-			   enum dmx_success success); 
+			   struct dmx_ts_feed* source,
+			   enum dmx_success success);
 
 typedef int (*dmx_section_cb) (	const u8 * buffer1,
 				size_t buffer1_len,
-				const u8 * buffer2, 
+				const u8 * buffer2,
 				size_t buffer2_len,
-			       	struct dmx_section_filter * source,
-			       	enum dmx_success success);
+				struct dmx_section_filter * source,
+				enum dmx_success success);
 
-/*--------------------------------------------------------------------------*/ 
+/*--------------------------------------------------------------------------*/
 /* DVB Front-End */
-/*--------------------------------------------------------------------------*/ 
+/*--------------------------------------------------------------------------*/
 
-enum dmx_frontend_source { 
+enum dmx_frontend_source {
 	DMX_MEMORY_FE,
 	DMX_FRONTEND_0,
 	DMX_FRONTEND_1,
@@ -201,106 +201,101 @@ enum dmx_frontend_source { 
 	DMX_STREAM_1,
 	DMX_STREAM_2,
 	DMX_STREAM_3
-}; 
+};
 
-struct dmx_frontend { 
-        struct list_head connectivity_list; /* List of front-ends that can 
-					       be connected to a particular 
-					       demux */ 
-        void* priv;     /* Pointer to private data of the API client */ 
+struct dmx_frontend {
+        struct list_head connectivity_list; /* List of front-ends that can
+					       be connected to a particular
+					       demux */
+        void* priv;     /* Pointer to private data of the API client */
         enum dmx_frontend_source source;
 };
 
-/*--------------------------------------------------------------------------*/ 
-/* MPEG-2 TS Demux */ 
-/*--------------------------------------------------------------------------*/ 
-
-/* 
- * Flags OR'ed in the capabilites field of struct dmx_demux. 
- */ 
-
-#define DMX_TS_FILTERING                        1 
-#define DMX_PES_FILTERING                       2 
-#define DMX_SECTION_FILTERING                   4 
-#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */ 
-#define DMX_CRC_CHECKING                        16 
-#define DMX_TS_DESCRAMBLING                     32 
-#define DMX_SECTION_PAYLOAD_DESCRAMBLING        64 
-#define DMX_MAC_ADDRESS_DESCRAMBLING            128 
-
-/* 
- * Demux resource type identifier. 
-*/ 
+/*--------------------------------------------------------------------------*/
+/* MPEG-2 TS Demux */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Flags OR'ed in the capabilites field of struct dmx_demux.
+ */
+
+#define DMX_TS_FILTERING                        1
+#define DMX_PES_FILTERING                       2
+#define DMX_SECTION_FILTERING                   4
+#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */
+#define DMX_CRC_CHECKING                        16
+#define DMX_TS_DESCRAMBLING                     32
+#define DMX_SECTION_PAYLOAD_DESCRAMBLING        64
+#define DMX_MAC_ADDRESS_DESCRAMBLING            128
+
+/*
+ * Demux resource type identifier.
+*/
 
-/* 
- * DMX_FE_ENTRY(): Casts elements in the list of registered 
+/*
+ * DMX_FE_ENTRY(): Casts elements in the list of registered
  * front-ends from the generic type struct list_head
  * to the type * struct dmx_frontend
- *. 
+ *.
 */
 
-#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list) 
+#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
 
-struct dmx_demux { 
-        u32 capabilities;            /* Bitfield of capability flags */ 
-        struct dmx_frontend* frontend;    /* Front-end connected to the demux */ 
+struct dmx_demux {
+        u32 capabilities;            /* Bitfield of capability flags */
+        struct dmx_frontend* frontend;    /* Front-end connected to the demux */
         struct list_head reg_list;   /* List of registered demuxes */
-        void* priv;                  /* Pointer to private data of the API client */ 
+        void* priv;                  /* Pointer to private data of the API client */
         int users;                   /* Number of users */
-        int (*open) (struct dmx_demux* demux); 
-        int (*close) (struct dmx_demux* demux); 
-        int (*write) (struct dmx_demux* demux, const char* buf, size_t count); 
-        int (*allocate_ts_feed) (struct dmx_demux* demux, 
-				 struct dmx_ts_feed** feed, 
-				 dmx_ts_cb callback); 
-        int (*release_ts_feed) (struct dmx_demux* demux, 
-				struct dmx_ts_feed* feed); 
-        int (*allocate_section_feed) (struct dmx_demux* demux, 
-				      struct dmx_section_feed** feed, 
-				      dmx_section_cb callback); 
+        int (*open) (struct dmx_demux* demux);
+        int (*close) (struct dmx_demux* demux);
+        int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
+        int (*allocate_ts_feed) (struct dmx_demux* demux,
+				 struct dmx_ts_feed** feed,
+				 dmx_ts_cb callback);
+        int (*release_ts_feed) (struct dmx_demux* demux,
+				struct dmx_ts_feed* feed);
+        int (*allocate_section_feed) (struct dmx_demux* demux,
+				      struct dmx_section_feed** feed,
+				      dmx_section_cb callback);
         int (*release_section_feed) (struct dmx_demux* demux,
-				     struct dmx_section_feed* feed); 
-        int (*descramble_mac_address) (struct dmx_demux* demux, 
-				       u8* buffer1, 
-				       size_t buffer1_length, 
-				       u8* buffer2, 
+				     struct dmx_section_feed* feed);
+        int (*descramble_mac_address) (struct dmx_demux* demux,
+				       u8* buffer1,
+				       size_t buffer1_length,
+				       u8* buffer2,
 				       size_t buffer2_length,
-				       u16 pid); 
+				       u16 pid);
         int (*descramble_section_payload) (struct dmx_demux* demux,
-					   u8* buffer1, 
+					   u8* buffer1,
 					   size_t buffer1_length,
 					   u8* buffer2, size_t buffer2_length,
-					   u16 pid); 
-        int (*add_frontend) (struct dmx_demux* demux, 
-			     struct dmx_frontend* frontend); 
+					   u16 pid);
+        int (*add_frontend) (struct dmx_demux* demux,
+			     struct dmx_frontend* frontend);
         int (*remove_frontend) (struct dmx_demux* demux,
-				struct dmx_frontend* frontend); 
-        struct list_head* (*get_frontends) (struct dmx_demux* demux); 
-        int (*connect_frontend) (struct dmx_demux* demux, 
-				 struct dmx_frontend* frontend); 
-        int (*disconnect_frontend) (struct dmx_demux* demux); 
+				struct dmx_frontend* frontend);
+        struct list_head* (*get_frontends) (struct dmx_demux* demux);
+        int (*connect_frontend) (struct dmx_demux* demux,
+				 struct dmx_frontend* frontend);
+        int (*disconnect_frontend) (struct dmx_demux* demux);
 
         int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
 
         int (*get_stc) (struct dmx_demux* demux, unsigned int num,
 			u64 *stc, unsigned int *base);
-}; 
+};
 
-/*--------------------------------------------------------------------------*/ 
-/* Demux directory */ 
-/*--------------------------------------------------------------------------*/ 
+/*--------------------------------------------------------------------------*/
+/* Demux directory */
+/*--------------------------------------------------------------------------*/
 
-/* 
- * DMX_DIR_ENTRY(): Casts elements in the list of registered 
+/*
+ * DMX_DIR_ENTRY(): Casts elements in the list of registered
  * demuxes from the generic type struct list_head* to the type struct dmx_demux
- *. 
- */ 
+ *.
+ */
 
 #define DMX_DIR_ENTRY(list) list_entry(list, struct dmx_demux, reg_list)
 
-int dmx_register_demux (struct dmx_demux* demux); 
-int dmx_unregister_demux (struct dmx_demux* demux); 
-struct list_head* dmx_get_demuxes (void); 
-
 #endif /* #ifndef __DEMUX_H */
-
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1,5 +1,5 @@
-/* 
- * dmxdev.c - DVB demultiplexer device 
+/*
+ * dmxdev.c - DVB demultiplexer device
  *
  * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
  *		  & Marcus Metzler <marcus@convergence.de>
@@ -48,7 +48,7 @@ dvb_dmxdev_file_to_filter(struct file *f
 	return (struct dmxdev_filter *) file->private_data;
 }
 
-static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) 
+static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
 {
 	buffer->data=NULL;
 	buffer->size=8192;
@@ -58,7 +58,7 @@ static inline void dvb_dmxdev_buffer_ini
 	init_waitqueue_head(&buffer->queue);
 }
 
-static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len) 
+static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len)
 {
 	int split;
 	int free;
@@ -68,7 +68,7 @@ static inline int dvb_dmxdev_buffer_writ
 		return 0;
 	if (!buf->data)
 		return 0;
-	
+
 	free=buf->pread-buf->pwrite;
 	split=0;
 	if (free<=0) {
@@ -97,14 +97,14 @@ static ssize_t dvb_dmxdev_buffer_read(st
 {
 	unsigned long todo=count;
 	int split, avail, error;
-	
+
 	if (!src->data)
 		return 0;
 
 	if ((error=src->error)) {
 		src->pwrite=src->pread;
 		src->error=0;
-		return error; 
+		return error;
 	}
 
 	if (non_blocking && (src->pwrite==src->pread))
@@ -122,9 +122,9 @@ static ssize_t dvb_dmxdev_buffer_read(st
 		if ((error=src->error)) {
 			src->pwrite=src->pread;
 			src->error=0;
-			return error; 
+			return error;
 		}
-		
+
 		split=src->size;
 		avail=src->pwrite - src->pread;
 		if (avail<0) {
@@ -162,7 +162,7 @@ static struct dmx_frontend * get_fe(stru
 	list_for_each(pos, head)
 		if (DMX_FE_ENTRY(pos)->source==type)
 			return DMX_FE_ENTRY(pos);
-	
+
 	return NULL;
 }
 
@@ -175,15 +175,15 @@ static inline void dvb_dmxdev_dvr_state_
 
 static int dvb_dvr_open(struct inode *inode, struct file *file)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmx_frontend *front;
 
 	dprintk ("function : %s\n", __FUNCTION__);
 
 	if (down_interruptible (&dmxdev->mutex))
 		return -ERESTARTSYS;
-	
+
 	if ((file->f_flags&O_ACCMODE)==O_RDWR) {
 		if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
 			up(&dmxdev->mutex);
@@ -203,20 +203,20 @@ static int dvb_dvr_open(struct inode *in
 
 	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
 		dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
-		
+
 		if (!dmxdev->demux->write) {
 			up(&dmxdev->mutex);
 			return -EOPNOTSUPP;
 		}
-		
+
 		front=get_fe(dmxdev->demux, DMX_MEMORY_FE);
-		
+
 		if (!front) {
 			up(&dmxdev->mutex);
 			return -EINVAL;
 		}
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);	
-		dmxdev->demux->connect_frontend(dmxdev->demux, front);	
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux, front);
 	}
 	up(&dmxdev->mutex);
 	return 0;
@@ -224,15 +224,15 @@ static int dvb_dvr_open(struct inode *in
 
 static int dvb_dvr_release(struct inode *inode, struct file *file)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 
 	if (down_interruptible (&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);	
-		dmxdev->demux->connect_frontend(dmxdev->demux, 
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux,
 						dmxdev->dvr_orig_fe);
 	}
 	if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
@@ -252,8 +252,8 @@ static int dvb_dvr_release(struct inode 
 static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
 		size_t count, loff_t *ppos)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 	int ret;
 
 	if (!dmxdev->demux->write)
@@ -270,13 +270,13 @@ static ssize_t dvb_dvr_write(struct file
 static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 		loff_t *ppos)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 	int ret;
 
 	//down(&dmxdev->mutex);
-	ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, 
-			      file->f_flags&O_NONBLOCK, 
+	ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+			      file->f_flags&O_NONBLOCK,
 			      buf, count, ppos);
 	//up(&dmxdev->mutex);
 	return ret;
@@ -302,11 +302,10 @@ static int dvb_dmxdev_set_buffer_size(st
 	mem=buf->data;
 	buf->data=NULL;
 	buf->size=size;
-	buf->pwrite=buf->pread=0;    
+	buf->pwrite=buf->pread=0;
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
-	if (mem) 
-		vfree(mem);
-		
+	vfree(mem);
+
 	if (buf->size) {
 		mem=vmalloc(dmxdevfilter->buffer.size);
 		if (!mem)
@@ -321,7 +320,7 @@ static int dvb_dmxdev_set_buffer_size(st
 static void dvb_dmxdev_filter_timeout(unsigned long data)
 {
 	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data;
-	
+
 	dmxdevfilter->buffer.error=-ETIMEDOUT;
 	spin_lock_irq(&dmxdevfilter->dev->lock);
 	dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;
@@ -332,7 +331,7 @@ static void dvb_dmxdev_filter_timeout(un
 static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
 {
 	struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
-  
+
 	del_timer(&dmxdevfilter->timer);
 	if (para->timeout) {
 		dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;
@@ -346,9 +345,9 @@ static int dvb_dmxdev_section_callback(c
 			    const u8 *buffer2, size_t buffer2_len,
 			    struct dmx_section_filter *filter, enum dmx_success success)
 {
-	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) filter->priv;
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
 	int ret;
-	
+
 	if (dmxdevfilter->buffer.error) {
 		wake_up(&dmxdevfilter->buffer.queue);
 		return 0;
@@ -359,16 +358,16 @@ static int dvb_dmxdev_section_callback(c
 		return 0;
 	}
 	del_timer(&dmxdevfilter->timer);
-	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", 
-		buffer1[0], buffer1[1], 
-		buffer1[2], buffer1[3], 
+	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
+		buffer1[0], buffer1[1],
+		buffer1[2], buffer1[3],
 		buffer1[4], buffer1[5]);
 	ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
 	if (ret==buffer1_len) {
 		ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
 	}
 	if (ret<0) {
-		dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;    
+		dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;
 		dmxdevfilter->buffer.error=-EOVERFLOW;
 	}
 	if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)
@@ -382,10 +381,10 @@ static int dvb_dmxdev_ts_callback(const 
 		       const u8 *buffer2, size_t buffer2_len,
 		       struct dmx_ts_feed *feed, enum dmx_success success)
 {
-	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) feed->priv;
+	struct dmxdev_filter *dmxdevfilter = feed->priv;
 	struct dmxdev_buffer *buffer;
 	int ret;
-	
+
 	spin_lock(&dmxdevfilter->dev->lock);
 	if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {
 		spin_unlock(&dmxdevfilter->dev->lock);
@@ -402,10 +401,10 @@ static int dvb_dmxdev_ts_callback(const 
 		return 0;
 	}
 	ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-	if (ret==buffer1_len) 
+	if (ret==buffer1_len)
 		ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
 	if (ret<0) {
-		buffer->pwrite=buffer->pread;    
+		buffer->pwrite=buffer->pread;
 		buffer->error=-EOVERFLOW;
 	}
 	spin_unlock(&dmxdevfilter->dev->lock);
@@ -456,7 +455,7 @@ static int dvb_dmxdev_feed_start(struct 
 }
 
 
-/* restart section feed if it has filters left associated with it, 
+/* restart section feed if it has filters left associated with it,
    otherwise release the feed */
 
 static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
@@ -464,15 +463,15 @@ static int dvb_dmxdev_feed_restart(struc
 	int i;
 	struct dmxdev *dmxdev = filter->dev;
 	u16 pid = filter->params.sec.pid;
-	
-	for (i=0; i<dmxdev->filternum; i++) 
+
+	for (i=0; i<dmxdev->filternum; i++)
 		if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
 		    dmxdev->filter[i].type==DMXDEV_TYPE_SEC &&
 		    dmxdev->filter[i].pid==pid) {
 			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
 			return 0;
 		}
-	
+
 	filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
 
 	return 0;
@@ -480,7 +479,7 @@ static int dvb_dmxdev_feed_restart(struc
 
 static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
 {
-	if (dmxdevfilter->state<DMXDEV_STATE_GO) 
+	if (dmxdevfilter->state<DMXDEV_STATE_GO)
 		return 0;
 
 	switch (dmxdevfilter->type) {
@@ -505,17 +504,17 @@ static int dvb_dmxdev_filter_stop(struct
 		dmxdevfilter->feed.ts=NULL;
 		break;
 	default:
-		if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) 
+		if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED)
 			return 0;
 		return -EINVAL;
 	}
-	dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;    
+	dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;
 	return 0;
 }
 
 static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
 {
-	if (dmxdevfilter->state<DMXDEV_STATE_SET) 
+	if (dmxdevfilter->state<DMXDEV_STATE_SET)
 		return 0;
 
 	dmxdevfilter->type=DMXDEV_TYPE_NONE;
@@ -530,11 +529,11 @@ static int dvb_dmxdev_filter_start(struc
 	void *mem;
 	int ret, i;
 
-	if (filter->state < DMXDEV_STATE_SET) 
+	if (filter->state < DMXDEV_STATE_SET)
 		return -EINVAL;
 
 	if (filter->state >= DMXDEV_STATE_GO)
-		dvb_dmxdev_filter_stop(filter); 
+		dvb_dmxdev_filter_stop(filter);
 
 	if (!(mem = filter->buffer.data)) {
 		mem = vmalloc(filter->buffer.size);
@@ -560,27 +559,27 @@ static int dvb_dmxdev_filter_start(struc
 		/* find active filter/feed with same PID */
 		for (i=0; i<dmxdev->filternum; i++) {
 			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-			    dmxdev->filter[i].pid == para->pid && 
+			    dmxdev->filter[i].pid == para->pid &&
 			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
 				*secfeed = dmxdev->filter[i].feed.sec;
 				break;
 			}
 		}
 
-		/* if no feed found, try to allocate new one */ 
+		/* if no feed found, try to allocate new one */
 		if (!*secfeed) {
-			ret=dmxdev->demux->allocate_section_feed(dmxdev->demux, 
-								 secfeed, 
+			ret=dmxdev->demux->allocate_section_feed(dmxdev->demux,
+								 secfeed,
 						   dvb_dmxdev_section_callback);
 			if (ret<0) {
 				printk ("DVB (%s): could not alloc feed\n",
 					__FUNCTION__);
 				return ret;
 			}
-			
-			ret=(*secfeed)->set(*secfeed, para->pid, 32768, 0, 
+
+			ret=(*secfeed)->set(*secfeed, para->pid, 32768, 0,
 					    (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-			
+
 			if (ret<0) {
 				printk ("DVB (%s): could not set feed\n",
 					__FUNCTION__);
@@ -590,7 +589,7 @@ static int dvb_dmxdev_filter_start(struc
 		} else {
 			dvb_dmxdev_feed_stop(filter);
 		}
-			
+
 		ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
 
 		if (ret < 0) {
@@ -602,11 +601,11 @@ static int dvb_dmxdev_filter_start(struc
 
 		(*secfilter)->priv = filter;
 
-		memcpy(&((*secfilter)->filter_value[3]), 
+		memcpy(&((*secfilter)->filter_value[3]),
 		       &(para->filter.filter[1]), DMX_FILTER_SIZE-1);
-		memcpy(&(*secfilter)->filter_mask[3], 
+		memcpy(&(*secfilter)->filter_mask[3],
 		       &para->filter.mask[1], DMX_FILTER_SIZE-1);
-		memcpy(&(*secfilter)->filter_mode[3], 
+		memcpy(&(*secfilter)->filter_mode[3],
 		       &para->filter.mode[1], DMX_FILTER_SIZE-1);
 
 		(*secfilter)->filter_value[0]=para->filter.filter[0];
@@ -614,7 +613,7 @@ static int dvb_dmxdev_filter_start(struc
 		(*secfilter)->filter_mode[0]=para->filter.mode[0];
 		(*secfilter)->filter_mask[1]=0;
 		(*secfilter)->filter_mask[2]=0;
-		
+
 		filter->todo = 0;
 
 		ret = filter->feed.sec->start_filtering (filter->feed.sec);
@@ -626,7 +625,7 @@ static int dvb_dmxdev_filter_start(struc
 		break;
 	}
 
-	case DMXDEV_TYPE_PES: 
+	case DMXDEV_TYPE_PES:
 	{
 		struct timespec timeout = { 0 };
 		struct dmx_pes_filter_params *para = &filter->params.pes;
@@ -635,27 +634,27 @@ static int dvb_dmxdev_filter_start(struc
 		int ts_type;
 		enum dmx_ts_pes ts_pes;
 		struct dmx_ts_feed **tsfeed = &filter->feed.ts;
-		
+
 		filter->feed.ts = NULL;
 		otype=para->output;
-		
+
 		ts_pes=(enum dmx_ts_pes) para->pes_type;
-		
-		if (ts_pes<DMX_PES_OTHER) 
+
+		if (ts_pes<DMX_PES_OTHER)
 			ts_type=TS_DECODER;
 		else
 			ts_type=0;
-		
-		if (otype == DMX_OUT_TS_TAP) 
+
+		if (otype == DMX_OUT_TS_TAP)
 			ts_type |= TS_PACKET;
-		
-		if (otype == DMX_OUT_TAP) 
+
+		if (otype == DMX_OUT_TAP)
 			ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
-		
-		ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, 
-						    tsfeed, 
+
+		ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
+						    tsfeed,
 						    dvb_dmxdev_ts_callback);
-		if (ret<0) 
+		if (ret<0)
 			return ret;
 
 		(*tsfeed)->priv = (void *) filter;
@@ -685,8 +684,8 @@ static int dvb_dmxdev_filter_start(struc
 
 static int dvb_demux_open(struct inode *inode, struct file *file)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 	int i;
 	struct dmxdev_filter *dmxdevfilter;
 
@@ -730,13 +729,13 @@ static int dvb_dmxdev_filter_free(struct
 		up(&dmxdev->mutex);
 		return -ERESTARTSYS;
 	}
-	
+
 	dvb_dmxdev_filter_stop(dmxdevfilter);
 	dvb_dmxdev_filter_reset(dmxdevfilter);
-	
+
 	if (dmxdevfilter->buffer.data) {
 		void *mem=dmxdevfilter->buffer.data;
-		
+
 		spin_lock_irq(&dmxdev->lock);
 		dmxdevfilter->buffer.data=NULL;
 		spin_unlock_irq(&dmxdev->lock);
@@ -759,22 +758,22 @@ static inline void invert_mode(dmx_filte
 }
 
 
-static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, 
-		struct dmxdev_filter *dmxdevfilter, 
+static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
+		struct dmxdev_filter *dmxdevfilter,
 		struct dmx_sct_filter_params *params)
 {
 	dprintk ("function : %s\n", __FUNCTION__);
 
 	dvb_dmxdev_filter_stop(dmxdevfilter);
-	
+
 	dmxdevfilter->type=DMXDEV_TYPE_SEC;
 	dmxdevfilter->pid=params->pid;
-	memcpy(&dmxdevfilter->params.sec, 
+	memcpy(&dmxdevfilter->params.sec,
 	       params, sizeof(struct dmx_sct_filter_params));
 	invert_mode(&dmxdevfilter->params.sec.filter);
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-		
-	if (params->flags&DMX_IMMEDIATE_START) 
+
+	if (params->flags&DMX_IMMEDIATE_START)
 		return dvb_dmxdev_filter_start(dmxdevfilter);
 
 	return 0;
@@ -795,7 +794,7 @@ static int dvb_dmxdev_pes_filter_set(str
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
-	if (params->flags&DMX_IMMEDIATE_START) 
+	if (params->flags&DMX_IMMEDIATE_START)
 		return dvb_dmxdev_filter_start(dmxdevfilter);
 
 	return 0;
@@ -806,18 +805,18 @@ static ssize_t dvb_dmxdev_read_sec(struc
 {
 	int result, hcount;
 	int done=0;
-	
+
 	if (dfil->todo<=0) {
 		hcount=3+dfil->todo;
 		if (hcount>count)
 			hcount=count;
-		result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, 
+		result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
 					buf, hcount, ppos);
 		if (result<0) {
 			dfil->todo=0;
 			return result;
 		}
-		if (copy_from_user(dfil->secheader-dfil->todo, buf, result)) 
+		if (copy_from_user(dfil->secheader-dfil->todo, buf, result))
 			return -EFAULT;
 		buf+=result;
 		done=result;
@@ -831,7 +830,7 @@ static ssize_t dvb_dmxdev_read_sec(struc
 	}
 	if (count>dfil->todo)
 		count=dfil->todo;
-	result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, 
+	result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
 				buf, count, ppos);
 	if (result<0)
 		return result;
@@ -852,8 +851,8 @@ dvb_demux_read(struct file *file, char _
 	if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
 		ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
 	else
-		ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, 
-				     file->f_flags&O_NONBLOCK, 
+		ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+				     file->f_flags&O_NONBLOCK,
 				     buf, count, ppos);
 
 	up(&dmxdevfilter->mutex);
@@ -868,7 +867,7 @@ static int dvb_demux_do_ioctl(struct ino
 	struct dmxdev *dmxdev=dmxdevfilter->dev;
 	unsigned long arg=(unsigned long) parg;
 	int ret=0;
-  
+
 	if (down_interruptible (&dmxdev->mutex))
 		return -ERESTARTSYS;
 
@@ -894,27 +893,27 @@ static int dvb_demux_do_ioctl(struct ino
 		up(&dmxdevfilter->mutex);
 		break;
 
-	case DMX_SET_FILTER: 
+	case DMX_SET_FILTER:
 		if (down_interruptible(&dmxdevfilter->mutex)) {
 			up(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, 
+		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
 				    (struct dmx_sct_filter_params *)parg);
 		up(&dmxdevfilter->mutex);
 		break;
 
-	case DMX_SET_PES_FILTER: 
+	case DMX_SET_PES_FILTER:
 		if (down_interruptible(&dmxdevfilter->mutex)) {
 			up(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, 
+		ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
 					       (struct dmx_pes_filter_params *)parg);
 		up(&dmxdevfilter->mutex);
 		break;
 
-	case DMX_SET_BUFFER_SIZE: 
+	case DMX_SET_BUFFER_SIZE:
 		if (down_interruptible(&dmxdevfilter->mutex)) {
 			up(&dmxdev->mutex);
 			return -ERESTARTSYS;
@@ -922,11 +921,11 @@ static int dvb_demux_do_ioctl(struct ino
 		ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
 		up(&dmxdevfilter->mutex);
 		break;
-	
-	case DMX_GET_EVENT: 
+
+	case DMX_GET_EVENT:
 		break;
-		
-	case DMX_GET_PES_PIDS: 
+
+	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
 			ret=-EINVAL;
 			break;
@@ -992,6 +991,7 @@ static int dvb_demux_release(struct inod
 	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
 }
 
+
 static struct file_operations dvb_demux_fops = {
 	.owner		= THIS_MODULE,
 	.read		= dvb_demux_read,
@@ -1001,6 +1001,7 @@ static struct file_operations dvb_demux_
 	.poll		= dvb_demux_poll,
 };
 
+
 static struct dvb_device dvbdev_demux = {
 	.priv		= NULL,
 	.users		= 1,
@@ -1008,11 +1009,12 @@ static struct dvb_device dvbdev_demux = 
 	.fops		= &dvb_demux_fops
 };
 
+
 static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
-			    unsigned int cmd, void *parg)
+		     unsigned int cmd, void *parg)
 {
-	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 
 	int ret=0;
 
@@ -1020,11 +1022,11 @@ static int dvb_dvr_do_ioctl(struct inode
 		return -ERESTARTSYS;
 
 	switch (cmd) {
-	case DMX_SET_BUFFER_SIZE: 
+	case DMX_SET_BUFFER_SIZE:
 		// FIXME: implement
 		ret=0;
 		break;
-		
+
 	default:
 		ret=-EINVAL;
 	}
@@ -1032,8 +1034,9 @@ static int dvb_dvr_do_ioctl(struct inode
 	return ret;
 }
 
+
 static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
+		  unsigned int cmd, unsigned long arg)
 {
 	return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
 }
@@ -1041,8 +1044,8 @@ static int dvb_dvr_ioctl(struct inode *i
 
 static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
 {
-	struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-	struct dmxdev *dmxdev = (struct dmxdev *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
 	unsigned int mask = 0;
 
 	dprintk ("function : %s\n", __FUNCTION__);
@@ -1055,7 +1058,7 @@ static unsigned int dvb_dvr_poll (struct
 
 		if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
 			mask |= (POLLIN | POLLRDNORM | POLLPRI);
-	} else 
+	} else
 		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
 
 	return mask;
@@ -1079,14 +1082,14 @@ static struct dvb_device dvbdev_dvr = {
 	.fops		= &dvb_dvr_fops
 };
 
-int 
+int
 dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
 	int i;
 
-	if (dmxdev->demux->open(dmxdev->demux)<0)
+	if (dmxdev->demux->open(dmxdev->demux) < 0)
 		return -EUSERS;
-	
+
 	dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter));
 	if (!dmxdev->filter)
 		return -ENOMEM;
@@ -1109,6 +1112,7 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, s
 		dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
 		dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
 	}
+
 	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX);
 	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
 
@@ -1118,20 +1122,16 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, s
 }
 EXPORT_SYMBOL(dvb_dmxdev_init);
 
-void 
+void
 dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
 	dvb_unregister_device(dmxdev->dvbdev);
 	dvb_unregister_device(dmxdev->dvr_dvbdev);
-	if (dmxdev->filter) {
-		vfree(dmxdev->filter);
-		dmxdev->filter=NULL;
-	}
-	if (dmxdev->dvr) {
-		vfree(dmxdev->dvr);
-		dmxdev->dvr=NULL;
-	}
+
+	vfree(dmxdev->filter);
+	dmxdev->filter=NULL;
+	vfree(dmxdev->dvr);
+	dmxdev->dvr=NULL;
 	dmxdev->demux->close(dmxdev->demux);
 }
 EXPORT_SYMBOL(dvb_dmxdev_release);
-
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * dmxdev.h
  *
  * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -61,19 +61,19 @@ MODULE_PARM_DESC(cam_debug, "enable verb
 #define CTRLIF_SIZE_LOW  2
 #define CTRLIF_SIZE_HIGH 3
 
-#define CMDREG_HC        1 /* Host control */
-#define CMDREG_SW        2 /* Size write */
-#define CMDREG_SR        4 /* Size read */
-#define CMDREG_RS        8 /* Reset interface */
-#define CMDREG_FRIE   0x40 /* Enable FR interrupt */
-#define CMDREG_DAIE   0x80 /* Enable DA interrupt */
+#define CMDREG_HC        1	/* Host control */
+#define CMDREG_SW        2	/* Size write */
+#define CMDREG_SR        4	/* Size read */
+#define CMDREG_RS        8	/* Reset interface */
+#define CMDREG_FRIE   0x40	/* Enable FR interrupt */
+#define CMDREG_DAIE   0x80	/* Enable DA interrupt */
 #define IRQEN (CMDREG_DAIE)
 
-#define STATUSREG_RE     1 /* read error */
-#define STATUSREG_WE     2 /* write error */
-#define STATUSREG_FR  0x40 /* module free */
-#define STATUSREG_DA  0x80 /* data available */
-#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */
+#define STATUSREG_RE     1	/* read error */
+#define STATUSREG_WE     2	/* write error */
+#define STATUSREG_FR  0x40	/* module free */
+#define STATUSREG_DA  0x80	/* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)	/* general transfer error */
 
 
 #define DVB_CA_SLOTSTATE_NONE           0
@@ -89,83 +89,83 @@ MODULE_PARM_DESC(cam_debug, "enable verb
 /* Information on a CA slot */
 struct dvb_ca_slot {
 
-        /* current state of the CAM */
-        int slot_state;
+	/* current state of the CAM */
+	int slot_state;
 
-        /* Number of CAMCHANGES that have occurred since last processing */
-        atomic_t camchange_count;
+	/* Number of CAMCHANGES that have occurred since last processing */
+	atomic_t camchange_count;
 
-        /* Type of last CAMCHANGE */
-        int camchange_type;
+	/* Type of last CAMCHANGE */
+	int camchange_type;
 
-        /* base address of CAM config */
-        u32 config_base;
+	/* base address of CAM config */
+	u32 config_base;
 
-        /* value to write into Config Control register */
-        u8 config_option;
+	/* value to write into Config Control register */
+	u8 config_option;
 
-        /* if 1, the CAM supports DA IRQs */
-        u8 da_irq_supported:1;
+	/* if 1, the CAM supports DA IRQs */
+	u8 da_irq_supported:1;
 
-        /* size of the buffer to use when talking to the CAM */
-        int link_buf_size;
+	/* size of the buffer to use when talking to the CAM */
+	int link_buf_size;
 
-        /* semaphore for syncing access to slot structure */
-        struct rw_semaphore sem;
+	/* semaphore for syncing access to slot structure */
+	struct rw_semaphore sem;
 
-        /* buffer for incoming packets */
-        struct dvb_ringbuffer rx_buffer;
+	/* buffer for incoming packets */
+	struct dvb_ringbuffer rx_buffer;
 
-        /* timer used during various states of the slot */
-        unsigned long timeout;
+	/* timer used during various states of the slot */
+	unsigned long timeout;
 };
 
 /* Private CA-interface information */
 struct dvb_ca_private {
 
-        /* pointer back to the public data structure */
-        struct dvb_ca_en50221* pub;
+	/* pointer back to the public data structure */
+	struct dvb_ca_en50221 *pub;
 
-        /* the DVB device */
-        struct dvb_device *dvbdev;
+	/* the DVB device */
+	struct dvb_device *dvbdev;
 
-        /* Flags describing the interface (DVB_CA_FLAG_*) */
-        u32 flags;
+	/* Flags describing the interface (DVB_CA_FLAG_*) */
+	u32 flags;
 
-        /* number of slots supported by this CA interface */
-        unsigned int slot_count;
+	/* number of slots supported by this CA interface */
+	unsigned int slot_count;
 
-        /* information on each slot */
-        struct dvb_ca_slot* slot_info;
+	/* information on each slot */
+	struct dvb_ca_slot *slot_info;
 
-        /* wait queues for read() and write() operations */
-        wait_queue_head_t wait_queue;
+	/* wait queues for read() and write() operations */
+	wait_queue_head_t wait_queue;
 
-        /* PID of the monitoring thread */
-        pid_t thread_pid;
+	/* PID of the monitoring thread */
+	pid_t thread_pid;
 
-        /* Wait queue used when shutting thread down */
-        wait_queue_head_t thread_queue;
+	/* Wait queue used when shutting thread down */
+	wait_queue_head_t thread_queue;
 
-        /* Flag indicating when thread should exit */
-        int exit:1;
+	/* Flag indicating when thread should exit */
+	unsigned int exit:1;
 
-        /* Flag indicating if the CA device is open */
-        int open:1;
+	/* Flag indicating if the CA device is open */
+	unsigned int open:1;
 
-        /* Flag indicating the thread should wake up now */
-        int wakeup:1;
+	/* Flag indicating the thread should wake up now */
+	unsigned int wakeup:1;
 
-        /* Delay the main thread should use */
-        unsigned long delay;
+	/* Delay the main thread should use */
+	unsigned long delay;
 
-        /* Slot to start looking for data to read from in the next user-space read operation */
-        int next_read_slot;
+	/* Slot to start looking for data to read from in the next user-space read operation */
+	int next_read_slot;
 };
 
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca);
-static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount);
-static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount);
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
 
 
 /**
@@ -177,19 +177,19 @@ static int dvb_ca_en50221_write_data(str
  * @param nlen Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
-static u8* findstr(u8* haystack, int hlen, u8* needle, int nlen)
+static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
 {
-        int i;
+	int i;
 
 	if (hlen < nlen)
 		return NULL;
 
-        for(i=0; i<= hlen - nlen; i++) {
+	for (i = 0; i <= hlen - nlen; i++) {
 		if (!strncmp(haystack + i, needle, nlen))
 			return haystack + i;
-        }
+	}
 
-        return NULL;
+	return NULL;
 }
 
 
@@ -201,43 +201,43 @@ static u8* findstr(u8* haystack, int hle
 /**
  * Check CAM status.
  */
-static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
 {
-        int slot_status;
-        int cam_present_now;
-        int cam_changed;
-
-        /* IRQ mode */
-        if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
-                return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
-        }
+	int slot_status;
+	int cam_present_now;
+	int cam_changed;
+
+	/* IRQ mode */
+	if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
+		return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
+	}
 
-        /* poll mode */
+	/* poll mode */
 	slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
 
-        cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0;
-        cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0;
-        if (!cam_changed) {
-                int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
-                cam_changed = (cam_present_now != cam_present_old);
-        }
-
-        if (cam_changed) {
-                if (!cam_present_now) {
-                        ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-                } else {
-                        ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
-                }
-                atomic_set(&ca->slot_info[slot].camchange_count, 1);
-        } else {
-                if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
-                    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
-                        // move to validate state if reset is completed
-                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-                }
-        }
+	cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
+	cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
+	if (!cam_changed) {
+		int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
+		cam_changed = (cam_present_now != cam_present_old);
+	}
+
+	if (cam_changed) {
+		if (!cam_present_now) {
+			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+		} else {
+			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+		}
+		atomic_set(&ca->slot_info[slot].camchange_count, 1);
+	} else {
+		if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
+		    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+			// move to validate state if reset is completed
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+		}
+	}
 
-        return cam_changed;
+	return cam_changed;
 }
 
 
@@ -255,39 +255,39 @@ static int dvb_ca_en50221_check_camstatu
 static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
 					 u8 waitfor, int timeout_hz)
 {
-        unsigned long timeout;
-        unsigned long start;
+	unsigned long timeout;
+	unsigned long start;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* loop until timeout elapsed */
-        start = jiffies;
-        timeout = jiffies + timeout_hz;
-        while(1) {
-                /* read the status and check for error */
-                int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+	/* loop until timeout elapsed */
+	start = jiffies;
+	timeout = jiffies + timeout_hz;
+	while (1) {
+		/* read the status and check for error */
+		int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
 		if (res < 0)
 			return -EIO;
 
-                /* if we got the flags, it was successful! */
-                if (res & waitfor) {
-                        dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);
-                        return 0;
-                }
-
-                /* check for timeout */
-                if (time_after(jiffies, timeout)) {
-                        break;
-                }
-
-                /* wait for a bit */
-                msleep(1);
-        }
+		/* if we got the flags, it was successful! */
+		if (res & waitfor) {
+			dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);
+			return 0;
+		}
+
+		/* check for timeout */
+		if (time_after(jiffies, timeout)) {
+			break;
+		}
+
+		/* wait for a bit */
+		msleep(1);
+	}
 
-        dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
+	dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
 
-        /* if we get here, we've timed out */
-        return -ETIMEDOUT;
+	/* if we get here, we've timed out */
+	return -ETIMEDOUT;
 }
 
 
@@ -299,22 +299,22 @@ static int dvb_ca_en50221_wait_if_status
  *
  * @return 0 on success, nonzero on failure.
  */
-static int dvb_ca_en50221_link_init(struct dvb_ca_private* ca, int slot)
+static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
 {
-        int ret;
-        int buf_size;
-        u8 buf[2];
+	int ret;
+	int buf_size;
+	u8 buf[2];
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* we'll be determining these during this function */
-        ca->slot_info[slot].da_irq_supported = 0;
+	/* we'll be determining these during this function */
+	ca->slot_info[slot].da_irq_supported = 0;
 
-        /* set the host link buffer size temporarily. it will be overwritten with the
-         * real negotiated size later. */
-        ca->slot_info[slot].link_buf_size = 2;
+	/* set the host link buffer size temporarily. it will be overwritten with the
+	 * real negotiated size later. */
+	ca->slot_info[slot].link_buf_size = 2;
 
-        /* read the buffer size from the CAM */
+	/* read the buffer size from the CAM */
 	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
 		return ret;
 	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
@@ -324,16 +324,16 @@ static int dvb_ca_en50221_link_init(stru
 	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
 		return ret;
 
-        /* store it, and choose the minimum of our buffer and the CAM's buffer size */
-        buf_size = (buf[0] << 8) | buf[1];
+	/* store it, and choose the minimum of our buffer and the CAM's buffer size */
+	buf_size = (buf[0] << 8) | buf[1];
 	if (buf_size > HOST_LINK_BUF_SIZE)
 		buf_size = HOST_LINK_BUF_SIZE;
-        ca->slot_info[slot].link_buf_size = buf_size;
-        buf[0] = buf_size >> 8;
-        buf[1] = buf_size & 0xff;
-        dprintk("Chosen link buffer size of %i\n", buf_size);
+	ca->slot_info[slot].link_buf_size = buf_size;
+	buf[0] = buf_size >> 8;
+	buf[1] = buf_size & 0xff;
+	dprintk("Chosen link buffer size of %i\n", buf_size);
 
-        /* write the buffer size to the CAM */
+	/* write the buffer size to the CAM */
 	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
 		return ret;
 	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
@@ -343,8 +343,8 @@ static int dvb_ca_en50221_link_init(stru
 	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
 		return ret;
 
-        /* success */
-        return 0;
+	/* success */
+	return 0;
 }
 
 /**
@@ -359,44 +359,44 @@ static int dvb_ca_en50221_link_init(stru
  *
  * @return 0 on success, nonzero on error.
  */
-static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot,
-                                     int* address, int* tupleType, int* tupleLength, u8* tuple)
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
+				     int *address, int *tupleType, int *tupleLength, u8 * tuple)
 {
-        int i;
-        int _tupleType;
-        int _tupleLength;
-        int _address = *address;
+	int i;
+	int _tupleType;
+	int _tupleLength;
+	int _address = *address;
 
-        /* grab the next tuple length and type */
+	/* grab the next tuple length and type */
 	if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
 		return _tupleType;
-        if (_tupleType == 0xff) {
-                dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
-                *address += 2;
-                *tupleType = _tupleType;
-                *tupleLength = 0;
-                return 0;
-        }
+	if (_tupleType == 0xff) {
+		dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+		*address += 2;
+		*tupleType = _tupleType;
+		*tupleLength = 0;
+		return 0;
+	}
 	if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
 		return _tupleLength;
-        _address += 4;
+	_address += 4;
 
-        dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+	dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
 
-        /* read in the whole tuple */
-        for(i=0; i< _tupleLength; i++) {
-                tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i*2));
+	/* read in the whole tuple */
+	for (i = 0; i < _tupleLength; i++) {
+		tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
 		dprintk("  0x%02x: 0x%02x %c\n",
 			i, tuple[i] & 0xff,
 			((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
-        }
-        _address += (_tupleLength*2);
+	}
+	_address += (_tupleLength * 2);
 
-        // success
-        *tupleType = _tupleType;
-        *tupleLength = _tupleLength;
-        *address = _address;
-        return 0;
+	// success
+	*tupleType = _tupleType;
+	*tupleLength = _tupleLength;
+	*address = _address;
+	return 0;
 }
 
 
@@ -409,23 +409,23 @@ static int dvb_ca_en50221_read_tuple(str
  *
  * @return 0 on success, <0 on failure.
  */
-static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
 {
-        int address = 0;
-        int tupleLength;
-        int tupleType;
-        u8 tuple[257];
-        char* dvb_str;
-        int rasz;
-        int status;
-        int got_cftableentry = 0;
-        int end_chain = 0;
-        int i;
-        u16 manfid = 0;
-        u16 devid = 0;
+	int address = 0;
+	int tupleLength;
+	int tupleType;
+	u8 tuple[257];
+	char *dvb_str;
+	int rasz;
+	int status;
+	int got_cftableentry = 0;
+	int end_chain = 0;
+	int i;
+	u16 manfid = 0;
+	u16 devid = 0;
 
 
-        // CISTPL_DEVICE_0A
+	// CISTPL_DEVICE_0A
 	if ((status =
 	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
 		return status;
@@ -434,7 +434,7 @@ static int dvb_ca_en50221_parse_attribut
 
 
 
-        // CISTPL_DEVICE_0C
+	// CISTPL_DEVICE_0C
 	if ((status =
 	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
 		return status;
@@ -443,7 +443,7 @@ static int dvb_ca_en50221_parse_attribut
 
 
 
-        // CISTPL_VERS_1
+	// CISTPL_VERS_1
 	if ((status =
 	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
 		return status;
@@ -452,7 +452,7 @@ static int dvb_ca_en50221_parse_attribut
 
 
 
-        // CISTPL_MANFID
+	// CISTPL_MANFID
 	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
 						&tupleLength, tuple)) < 0)
 		return status;
@@ -460,12 +460,12 @@ static int dvb_ca_en50221_parse_attribut
 		return -EINVAL;
 	if (tupleLength != 4)
 		return -EINVAL;
-        manfid = (tuple[1] << 8) | tuple[0];
-        devid = (tuple[3] << 8) | tuple[2];
+	manfid = (tuple[1] << 8) | tuple[0];
+	devid = (tuple[3] << 8) | tuple[2];
 
 
 
-        // CISTPL_CONFIG
+	// CISTPL_CONFIG
 	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
 						&tupleLength, tuple)) < 0)
 		return status;
@@ -474,76 +474,76 @@ static int dvb_ca_en50221_parse_attribut
 	if (tupleLength < 3)
 		return -EINVAL;
 
-        /* extract the configbase */
-        rasz = tuple[0] & 3;
+	/* extract the configbase */
+	rasz = tuple[0] & 3;
 	if (tupleLength < (3 + rasz + 14))
 		return -EINVAL;
-        ca->slot_info[slot].config_base = 0;
-        for(i=0; i< rasz+1; i++) {
-                ca->slot_info[slot].config_base |= (tuple[2+i] << (8*i));
-        }
+	ca->slot_info[slot].config_base = 0;
+	for (i = 0; i < rasz + 1; i++) {
+		ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
+	}
 
-        /* check it contains the correct DVB string */
-        dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+	/* check it contains the correct DVB string */
+	dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
 	if (dvb_str == NULL)
 		return -EINVAL;
 	if (tupleLength < ((dvb_str - (char *) tuple) + 12))
 		return -EINVAL;
 
-        /* is it a version we support? */
-        if (strncmp(dvb_str + 8, "1.00", 4)) {
-                printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
+	/* is it a version we support? */
+	if (strncmp(dvb_str + 8, "1.00", 4)) {
+		printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
 		       ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
-                return -EINVAL;
-        }
+		return -EINVAL;
+	}
 
-        /* process the CFTABLE_ENTRY tuples, and any after those */
-        while((!end_chain) && (address < 0x1000)) {
+	/* process the CFTABLE_ENTRY tuples, and any after those */
+	while ((!end_chain) && (address < 0x1000)) {
 		if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
 						        &tupleLength, tuple)) < 0)
 			return status;
-                switch(tupleType) {
-                case 0x1B: // CISTPL_CFTABLE_ENTRY
+		switch (tupleType) {
+		case 0x1B:	// CISTPL_CFTABLE_ENTRY
 			if (tupleLength < (2 + 11 + 17))
 				break;
 
-                        /* if we've already parsed one, just use it */
+			/* if we've already parsed one, just use it */
 			if (got_cftableentry)
 				break;
 
-                        /* get the config option */
-                        ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+			/* get the config option */
+			ca->slot_info[slot].config_option = tuple[0] & 0x3f;
 
-                        /* OK, check it contains the correct strings */
-                        if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+			/* OK, check it contains the correct strings */
+			if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
 			    (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
 				break;
 
-                        got_cftableentry = 1;
-                        break;
+			got_cftableentry = 1;
+			break;
 
-                case 0x14: // CISTPL_NO_LINK
-                        break;
+		case 0x14:	// CISTPL_NO_LINK
+			break;
 
-                case 0xFF: // CISTPL_END
-                        end_chain = 1;
-                        break;
+		case 0xFF:	// CISTPL_END
+			end_chain = 1;
+			break;
 
-                default: /* Unknown tuple type - just skip this tuple and move to the next one */
+		default:	/* Unknown tuple type - just skip this tuple and move to the next one */
 			dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
 				tupleLength);
-                        break;
-                }
-        }
+			break;
+		}
+	}
 
 	if ((address > 0x1000) || (!got_cftableentry))
 		return -EINVAL;
 
-        dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+	dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
 		manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
 
-        // success!
-        return 0;
+	// success!
+	return 0;
 }
 
 
@@ -553,24 +553,24 @@ static int dvb_ca_en50221_parse_attribut
  * @param ca CA instance.
  * @param slot Slot containing the CAM.
  */
-static int dvb_ca_en50221_set_configoption(struct dvb_ca_private* ca, int slot)
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
 {
-        int configoption;
+	int configoption;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* set the config option */
+	/* set the config option */
 	ca->pub->write_attribute_mem(ca->pub, slot,
 				     ca->slot_info[slot].config_base,
 				     ca->slot_info[slot].config_option);
 
-        /* check it */
-        configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
-        dprintk("Set configoption 0x%x, read configoption 0x%x\n", 
+	/* check it */
+	configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
+	dprintk("Set configoption 0x%x, read configoption 0x%x\n",
 		ca->slot_info[slot].config_option, configoption & 0x3f);
 
-        /* fine! */
-        return 0;
+	/* fine! */
+	return 0;
 
 }
 
@@ -588,17 +588,17 @@ static int dvb_ca_en50221_set_configopti
  *
  * @return Number of bytes read, or < 0 on error
  */
-static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount)
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
 {
-        int bytes_read;
-        int status;
-        u8 buf[HOST_LINK_BUF_SIZE];
-        int i;
+	int bytes_read;
+	int status;
+	u8 buf[HOST_LINK_BUF_SIZE];
+	int i;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* check if we have space for a link buf in the rx_buffer */
-        if (ebuf == NULL) {
+	/* check if we have space for a link buf in the rx_buffer */
+	if (ebuf == NULL) {
 		int buf_free;
 
 		down_read(&ca->slot_info[slot].sem);
@@ -610,99 +610,98 @@ static int dvb_ca_en50221_read_data(stru
 		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
 		up_read(&ca->slot_info[slot].sem);
 
-                if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
-                        status = -EAGAIN;
-                        goto exit;
-                }
-        }
+		if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+			status = -EAGAIN;
+			goto exit;
+		}
+	}
 
-        /* check if there is data available */
+	/* check if there is data available */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
 		goto exit;
-        if (!(status & STATUSREG_DA)) {
-                /* no data */
-                status = 0;
-                goto exit;
-        }
+	if (!(status & STATUSREG_DA)) {
+		/* no data */
+		status = 0;
+		goto exit;
+	}
 
-        /* read the amount of data */
+	/* read the amount of data */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
 		goto exit;
-        bytes_read = status << 8;
+	bytes_read = status << 8;
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
 		goto exit;
-        bytes_read |= status;
+	bytes_read |= status;
 
-        /* check it will fit */
-        if (ebuf == NULL) {
-                if (bytes_read > ca->slot_info[slot].link_buf_size) {
+	/* check it will fit */
+	if (ebuf == NULL) {
+		if (bytes_read > ca->slot_info[slot].link_buf_size) {
 			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
 			       ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
-                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                        status = -EIO;
-                        goto exit;
-                }
-                if (bytes_read < 2) {
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+			status = -EIO;
+			goto exit;
+		}
+		if (bytes_read < 2) {
 			printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
 			       ca->dvbdev->adapter->num);
-                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                        status = -EIO;
-                        goto exit;
-                }
-        } else {
-                if (bytes_read > ecount) {
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+			status = -EIO;
+			goto exit;
+		}
+	} else {
+		if (bytes_read > ecount) {
 			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
 			       ca->dvbdev->adapter->num);
-                        status = -EIO;
-                        goto exit;
-                }
-        }
-
-        /* fill the buffer */
-        for(i=0; i < bytes_read; i++) {
-                /* read byte and check */
+			status = -EIO;
+			goto exit;
+		}
+	}
+
+	/* fill the buffer */
+	for (i = 0; i < bytes_read; i++) {
+		/* read byte and check */
 		if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
 			goto exit;
 
-                /* OK, store it in the buffer */
-                buf[i] = status;
-        }
+		/* OK, store it in the buffer */
+		buf[i] = status;
+	}
 
-        /* check for read error (RE should now be 0) */
+	/* check for read error (RE should now be 0) */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
 		goto exit;
-        if (status & STATUSREG_RE) {
+	if (status & STATUSREG_RE) {
 		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                status = -EIO;
-                goto exit;
-        }
+		status = -EIO;
+		goto exit;
+	}
 
-        /* OK, add it to the receive buffer, or copy into external buffer if supplied */
-        if (ebuf == NULL) {
+	/* OK, add it to the receive buffer, or copy into external buffer if supplied */
+	if (ebuf == NULL) {
 		down_read(&ca->slot_info[slot].sem);
 		if (ca->slot_info[slot].rx_buffer.data == NULL) {
 			up_read(&ca->slot_info[slot].sem);
 			status = -EIO;
 			goto exit;
 		}
-                dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
+		dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
 		up_read(&ca->slot_info[slot].sem);
-        } else {
-                memcpy(ebuf, buf, bytes_read);
-        }
+	} else {
+		memcpy(ebuf, buf, bytes_read);
+	}
 
 	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
 		buf[0], (buf[1] & 0x80) == 0, bytes_read);
 
-        /* wake up readers when a last_fragment is received */
-        if ((buf[1] & 0x80) == 0x00) {
-                wake_up_interruptible(&ca->wait_queue);
-        }
-
-        status = bytes_read;
+	/* wake up readers when a last_fragment is received */
+	if ((buf[1] & 0x80) == 0x00) {
+		wake_up_interruptible(&ca->wait_queue);
+	}
+	status = bytes_read;
 
 exit:
-        return status;
+	return status;
 }
 
 
@@ -718,71 +717,71 @@ exit:
  *
  * @return Number of bytes written, or < 0 on error.
  */
-static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* buf, int bytes_write)
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
 {
-        int status;
-        int i;
+	int status;
+	int i;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
 
-        // sanity check
+	// sanity check
 	if (bytes_write > ca->slot_info[slot].link_buf_size)
 		return -EINVAL;
 
-        /* check if interface is actually waiting for us to read from it, or if a read is in progress */
+	/* check if interface is actually waiting for us to read from it, or if a read is in progress */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
 		goto exitnowrite;
-        if (status & (STATUSREG_DA|STATUSREG_RE)) {
-                status = -EAGAIN;
-                goto exitnowrite;
-        }
+	if (status & (STATUSREG_DA | STATUSREG_RE)) {
+		status = -EAGAIN;
+		goto exitnowrite;
+	}
 
-        /* OK, set HC bit */
+	/* OK, set HC bit */
 	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
 						 IRQEN | CMDREG_HC)) != 0)
 		goto exit;
 
-        /* check if interface is still free */
+	/* check if interface is still free */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
 		goto exit;
-        if (!(status & STATUSREG_FR)) {
-                /* it wasn't free => try again later */
-                status = -EAGAIN;
-                goto exit;
-        }
+	if (!(status & STATUSREG_FR)) {
+		/* it wasn't free => try again later */
+		status = -EAGAIN;
+		goto exit;
+	}
 
-        /* send the amount of data */
+	/* send the amount of data */
 	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
 		goto exit;
 	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
 						 bytes_write & 0xff)) != 0)
 		goto exit;
 
-        /* send the buffer */
-        for(i=0; i < bytes_write; i++) {
+	/* send the buffer */
+	for (i = 0; i < bytes_write; i++) {
 		if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
 			goto exit;
-        }
+	}
 
-        /* check for write error (WE should now be 0) */
+	/* check for write error (WE should now be 0) */
 	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
 		goto exit;
-        if (status & STATUSREG_WE) {
+	if (status & STATUSREG_WE) {
 		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                status = -EIO;
-                goto exit;
-        }
-        status = bytes_write;
+		status = -EIO;
+		goto exit;
+	}
+	status = bytes_write;
 
 	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
 		buf[0], (buf[1] & 0x80) == 0, bytes_write);
 
 exit:
-        ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
+	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
 
 exitnowrite:
-        return status;
+	return status;
 }
 EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
 
@@ -798,26 +797,25 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_i
  * @param ca CA instance.
  * @param slot Slot to shut down.
  */
-static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
 {
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
+
+	down_write(&ca->slot_info[slot].sem);
+	ca->pub->slot_shutdown(ca->pub, slot);
+	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+	vfree(ca->slot_info[slot].rx_buffer.data);
+	ca->slot_info[slot].rx_buffer.data = NULL;
+	up_write(&ca->slot_info[slot].sem);
 
-        down_write(&ca->slot_info[slot].sem);
-        ca->pub->slot_shutdown(ca->pub, slot);
-        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-	if (ca->slot_info[slot].rx_buffer.data)
-		vfree(ca->slot_info[slot].rx_buffer.data);
-        ca->slot_info[slot].rx_buffer.data = NULL;
-        up_write(&ca->slot_info[slot].sem);
-
-        /* need to wake up all processes to check if they're now
-           trying to write to a defunct CAM */
-        wake_up_interruptible(&ca->wait_queue);
+	/* need to wake up all processes to check if they're now
+	   trying to write to a defunct CAM */
+	wake_up_interruptible(&ca->wait_queue);
 
-        dprintk("Slot %i shutdown\n", slot);
+	dprintk("Slot %i shutdown\n", slot);
 
-        /* success */
-        return 0;
+	/* success */
+	return 0;
 }
 EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
 
@@ -829,24 +827,24 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_ir
  * @param slot Slot concerned.
  * @param change_type One of the DVB_CA_CAMCHANGE_* values.
  */
-void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type)
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
 {
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+	struct dvb_ca_private *ca = pubca->private;
 
-        dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+	dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
 
-        switch(change_type) {
-        case DVB_CA_EN50221_CAMCHANGE_REMOVED:
-        case DVB_CA_EN50221_CAMCHANGE_INSERTED:
-                break;
+	switch (change_type) {
+	case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+	case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+		break;
 
-        default:
-                return;
-        }
+	default:
+		return;
+	}
 
-        ca->slot_info[slot].camchange_type = change_type;
-        atomic_inc(&ca->slot_info[slot].camchange_count);
-        dvb_ca_en50221_thread_wakeup(ca);
+	ca->slot_info[slot].camchange_type = change_type;
+	atomic_inc(&ca->slot_info[slot].camchange_count);
+	dvb_ca_en50221_thread_wakeup(ca);
 }
 EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
 
@@ -857,16 +855,16 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
  * @param ca CA instance.
  * @param slot Slot concerned.
  */
-void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot)
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
 {
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+	struct dvb_ca_private *ca = pubca->private;
 
-        dprintk("CAMREADY IRQ slot:%i\n", slot);
+	dprintk("CAMREADY IRQ slot:%i\n", slot);
 
-        if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
-                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-                dvb_ca_en50221_thread_wakeup(ca);
-        }
+	if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+		dvb_ca_en50221_thread_wakeup(ca);
+	}
 }
 
 
@@ -876,27 +874,27 @@ void dvb_ca_en50221_camready_irq(struct 
  * @param ca CA instance.
  * @param slot Slot concerned.
  */
-void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot)
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
 {
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
-        int flags;
+	struct dvb_ca_private *ca = pubca->private;
+	int flags;
 
-        dprintk("FR/DA IRQ slot:%i\n", slot);
+	dprintk("FR/DA IRQ slot:%i\n", slot);
 
-        switch(ca->slot_info[slot].slot_state) {
-        case DVB_CA_SLOTSTATE_LINKINIT:
-                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
-                if (flags & STATUSREG_DA) {
-                        dprintk("CAM supports DA IRQ\n");
-                        ca->slot_info[slot].da_irq_supported = 1;
+	switch (ca->slot_info[slot].slot_state) {
+	case DVB_CA_SLOTSTATE_LINKINIT:
+		flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+		if (flags & STATUSREG_DA) {
+			dprintk("CAM supports DA IRQ\n");
+			ca->slot_info[slot].da_irq_supported = 1;
 		}
-                break;
+		break;
 
-        case DVB_CA_SLOTSTATE_RUNNING:
+	case DVB_CA_SLOTSTATE_RUNNING:
 		if (ca->open)
 			dvb_ca_en50221_read_data(ca, slot, NULL, 0);
-                break;
-        }
+		break;
+	}
 }
 
 
@@ -909,14 +907,14 @@ void dvb_ca_en50221_frda_irq(struct dvb_
  *
  * @param ca CA instance.
  */
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca)
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 {
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        ca->wakeup = 1;
-        mb();
-        wake_up_interruptible(&ca->thread_queue);
+	ca->wakeup = 1;
+	mb();
+	wake_up_interruptible(&ca->thread_queue);
 }
 
 /**
@@ -924,16 +922,16 @@ static void dvb_ca_en50221_thread_wakeup
  *
  * @param ca CA instance.
  */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca)
+static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
 {
-        if (ca->wakeup) {
-                ca->wakeup = 0;
-                return 1;
-        }
+	if (ca->wakeup) {
+		ca->wakeup = 0;
+		return 1;
+	}
 	if (ca->exit)
 		return 1;
-   
-        return 0;
+
+	return 0;
 }
 
 
@@ -942,50 +940,50 @@ static int dvb_ca_en50221_thread_should_
  *
  * @param ca CA instance.
  */
-static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca)
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
 {
-        int delay;
-        int curdelay = 100000000;
-        int slot;
-
-        for(slot=0; slot < ca->slot_count; slot++) {
-                switch(ca->slot_info[slot].slot_state) {
-                default:
-                case DVB_CA_SLOTSTATE_NONE:
-                case DVB_CA_SLOTSTATE_INVALID:
-                        delay = HZ*60;
-                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-                                delay = HZ/10;
-                        }
-                        break;
-
-                case DVB_CA_SLOTSTATE_UNINITIALISED:
-                case DVB_CA_SLOTSTATE_WAITREADY:
-                case DVB_CA_SLOTSTATE_VALIDATE:
-                case DVB_CA_SLOTSTATE_WAITFR:
-                case DVB_CA_SLOTSTATE_LINKINIT:
-                        delay = HZ/10;
-                        break;
-
-                case DVB_CA_SLOTSTATE_RUNNING:
-                        delay = HZ*60;
-                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-                                delay = HZ/10;
-                        }
-                        if (ca->open) {
-                                if ((!ca->slot_info[slot].da_irq_supported) ||
-                                    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
-                                        delay = HZ/100;
-                                }
-                        }
-                        break;
-                }
+	int delay;
+	int curdelay = 100000000;
+	int slot;
+
+	for (slot = 0; slot < ca->slot_count; slot++) {
+		switch (ca->slot_info[slot].slot_state) {
+		default:
+		case DVB_CA_SLOTSTATE_NONE:
+		case DVB_CA_SLOTSTATE_INVALID:
+			delay = HZ * 60;
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+				delay = HZ / 10;
+			}
+			break;
+
+		case DVB_CA_SLOTSTATE_UNINITIALISED:
+		case DVB_CA_SLOTSTATE_WAITREADY:
+		case DVB_CA_SLOTSTATE_VALIDATE:
+		case DVB_CA_SLOTSTATE_WAITFR:
+		case DVB_CA_SLOTSTATE_LINKINIT:
+			delay = HZ / 10;
+			break;
+
+		case DVB_CA_SLOTSTATE_RUNNING:
+			delay = HZ * 60;
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+				delay = HZ / 10;
+			}
+			if (ca->open) {
+				if ((!ca->slot_info[slot].da_irq_supported) ||
+				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
+					delay = HZ / 10;
+				}
+			}
+			break;
+		}
 
 		if (delay < curdelay)
 			curdelay = delay;
-        }
+	}
 
-        ca->delay = curdelay;
+	ca->delay = curdelay;
 }
 
 
@@ -993,160 +991,159 @@ static void dvb_ca_en50221_thread_update
 /**
  * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
  */
-static int dvb_ca_en50221_thread(void* data)
+static int dvb_ca_en50221_thread(void *data)
 {
-        struct dvb_ca_private *ca = (struct dvb_ca_private*) data;
-        char name[15];
-        int slot;
-        int flags;
+	struct dvb_ca_private *ca = data;
+	char name[15];
+	int slot;
+	int flags;
 	int status;
-        int pktcount;
-        void* rxbuf;
+	int pktcount;
+	void *rxbuf;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* setup kernel thread */
-        snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
+	/* setup kernel thread */
+	snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
 
-        lock_kernel ();
-        daemonize (name);
-        sigfillset (&current->blocked);
-        unlock_kernel ();
-
-        /* choose the correct initial delay */
-        dvb_ca_en50221_thread_update_delay(ca);
-
-        /* main loop */
-        while(!ca->exit) {
-                /* sleep for a bit */
-                if (!ca->wakeup) {
+	lock_kernel();
+	daemonize(name);
+	sigfillset(&current->blocked);
+	unlock_kernel();
+
+	/* choose the correct initial delay */
+	dvb_ca_en50221_thread_update_delay(ca);
+
+	/* main loop */
+	while (!ca->exit) {
+		/* sleep for a bit */
+		if (!ca->wakeup) {
 			flags = wait_event_interruptible_timeout(ca->thread_queue,
 								 dvb_ca_en50221_thread_should_wakeup(ca),
 								 ca->delay);
-                        if ((flags == -ERESTARTSYS) || ca->exit) {
-                                /* got signal or quitting */
-                                break;
-                        }
-                }
-                ca->wakeup = 0;
-
-                /* go through all the slots processing them */
-                for(slot=0; slot < ca->slot_count; slot++) {
-
-                        // check the cam status + deal with CAMCHANGEs
-                        while(dvb_ca_en50221_check_camstatus(ca, slot)) {
-                                /* clear down an old CI slot if necessary */
+			if ((flags == -ERESTARTSYS) || ca->exit) {
+				/* got signal or quitting */
+				break;
+			}
+		}
+		ca->wakeup = 0;
+
+		/* go through all the slots processing them */
+		for (slot = 0; slot < ca->slot_count; slot++) {
+
+			// check the cam status + deal with CAMCHANGEs
+			while (dvb_ca_en50221_check_camstatus(ca, slot)) {
+				/* clear down an old CI slot if necessary */
 				if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
 					dvb_ca_en50221_slot_shutdown(ca, slot);
 
-                                /* if a CAM is NOW present, initialise it */
-                                if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
-                                }
-
-                                /* we've handled one CAMCHANGE */
-                                dvb_ca_en50221_thread_update_delay(ca);
-                                atomic_dec(&ca->slot_info[slot].camchange_count);
-                        }
-
-                        // CAM state machine
-                        switch(ca->slot_info[slot].slot_state) {
-                        case DVB_CA_SLOTSTATE_NONE:
-                        case DVB_CA_SLOTSTATE_INVALID:
-                                // no action needed
-                                break;
-
-                        case DVB_CA_SLOTSTATE_UNINITIALISED:
-                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
-                                ca->pub->slot_reset(ca->pub, slot);
-                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-                                break;
+				/* if a CAM is NOW present, initialise it */
+				if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
+				}
+
+				/* we've handled one CAMCHANGE */
+				dvb_ca_en50221_thread_update_delay(ca);
+				atomic_dec(&ca->slot_info[slot].camchange_count);
+			}
+
+			// CAM state machine
+			switch (ca->slot_info[slot].slot_state) {
+			case DVB_CA_SLOTSTATE_NONE:
+			case DVB_CA_SLOTSTATE_INVALID:
+				// no action needed
+				break;
 
-                        case DVB_CA_SLOTSTATE_WAITREADY:
-                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+			case DVB_CA_SLOTSTATE_UNINITIALISED:
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+				ca->pub->slot_reset(ca->pub, slot);
+				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+				break;
+
+			case DVB_CA_SLOTSTATE_WAITREADY:
+				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
 					printk("dvb_ca adaptor %d: PC card did not respond :(\n",
 					       ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-				        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
-                                // no other action needed; will automatically change state when ready
-                                break;
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				// no other action needed; will automatically change state when ready
+				break;
 
-                        case DVB_CA_SLOTSTATE_VALIDATE:
+			case DVB_CA_SLOTSTATE_VALIDATE:
 				if (dvb_ca_en50221_parse_attributes(ca, slot)
 				    != 0) {
 					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
 					       ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
-                                if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
 					printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
 					       ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-				        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
 				if (ca->pub->write_cam_control(ca->pub, slot,
 							       CTRLIF_COMMAND, CMDREG_RS) != 0) {
 					printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
 					       ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-				        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
-
-                                dprintk("DVB CAM validated successfully\n");
-
-                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
-                                ca->wakeup = 1;
-                                break;
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				dprintk("DVB CAM validated successfully\n");
 
-                        case DVB_CA_SLOTSTATE_WAITFR:
-                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+				ca->wakeup = 1;
+				break;
+
+			case DVB_CA_SLOTSTATE_WAITFR:
+				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
 					printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
 					       ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-				        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
-
-                                flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
-                                if (flags & STATUSREG_FR) {
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                                        ca->wakeup = 1;
-                                }
-                                break;
-
-                        case DVB_CA_SLOTSTATE_LINKINIT:
-                                if (dvb_ca_en50221_link_init(ca, slot) != 0) {
-                                        printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-			                dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
-
-                                rxbuf = vmalloc(RX_BUFFER_SIZE);
-                                if (rxbuf == NULL) {
-                                        printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
-                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-				        dvb_ca_en50221_thread_update_delay(ca);
-                                        break;
-                                }
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+
+				flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+				if (flags & STATUSREG_FR) {
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+					ca->wakeup = 1;
+				}
+				break;
+
+			case DVB_CA_SLOTSTATE_LINKINIT:
+				if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+
+				rxbuf = vmalloc(RX_BUFFER_SIZE);
+				if (rxbuf == NULL) {
+					printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
 				down_write(&ca->slot_info[slot].sem);
-                                dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
+				dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
 				up_write(&ca->slot_info[slot].sem);
 
-                                ca->pub->slot_ts_enable(ca->pub, slot);
-                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
-                                dvb_ca_en50221_thread_update_delay(ca);
-                                printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
-                                break;
+				ca->pub->slot_ts_enable(ca->pub, slot);
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+				dvb_ca_en50221_thread_update_delay(ca);
+				printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
+				break;
 
-                        case DVB_CA_SLOTSTATE_RUNNING:
+			case DVB_CA_SLOTSTATE_RUNNING:
 				if (!ca->open)
 					continue;
 
@@ -1155,35 +1152,35 @@ static int dvb_ca_en50221_thread(void* d
 					break;
 
 				// poll mode
-                                pktcount = 0;
+				pktcount = 0;
 				while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
 					if (!ca->open)
 						break;
 
-                                        /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
-                                        if (dvb_ca_en50221_check_camstatus(ca, slot)) {
-                                                // we dont want to sleep on the next iteration so we can handle the cam change
-                                                ca->wakeup = 1;
-                                                break;
-                                        }
-
-                                        /* check if we've hit our limit this time */
-                                        if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
-                                                // dont sleep; there is likely to be more data to read
-                                                ca->wakeup = 1;
-                                                break;
-                                        }
-                                }
-                                break;
-                        }
-                }
-        }
-
-        /* completed */
-        ca->thread_pid = 0;
-        mb();
-        wake_up_interruptible (&ca->thread_queue);
-        return 0;
+					/* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
+					if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+						// we dont want to sleep on the next iteration so we can handle the cam change
+						ca->wakeup = 1;
+						break;
+					}
+
+					/* check if we've hit our limit this time */
+					if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+						// dont sleep; there is likely to be more data to read
+						ca->wakeup = 1;
+						break;
+					}
+				}
+				break;
+			}
+		}
+	}
+
+	/* completed */
+	ca->thread_pid = 0;
+	mb();
+	wake_up_interruptible(&ca->thread_queue);
+	return 0;
 }
 
 
@@ -1205,62 +1202,62 @@ static int dvb_ca_en50221_thread(void* d
 static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file,
 				      unsigned int cmd, void *parg)
 {
-        struct dvb_device* dvbdev=(struct dvb_device*) file->private_data;
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;
-        int err=0;
-        int slot;
-
-        dprintk ("%s\n", __FUNCTION__);
-
-        switch (cmd) {
-        case CA_RESET:
-                for(slot = 0; slot < ca->slot_count; slot++) {
-                        if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
-                                dvb_ca_en50221_slot_shutdown(ca, slot);
-                                if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int err = 0;
+	int slot;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case CA_RESET:
+		for (slot = 0; slot < ca->slot_count; slot++) {
+			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
+				dvb_ca_en50221_slot_shutdown(ca, slot);
+				if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
 					dvb_ca_en50221_camchange_irq(ca->pub,
 								     slot,
 								     DVB_CA_EN50221_CAMCHANGE_INSERTED);
-                        }
-                }
-                ca->next_read_slot = 0;
-                dvb_ca_en50221_thread_wakeup(ca);
-                break;
+			}
+		}
+		ca->next_read_slot = 0;
+		dvb_ca_en50221_thread_wakeup(ca);
+		break;
 
 	case CA_GET_CAP: {
-                struct ca_caps *caps = (struct ca_caps*) parg;
+		struct ca_caps *caps = parg;
 
-                caps->slot_num=ca->slot_count;
-                caps->slot_type=CA_CI_LINK;
-                caps->descr_num=0;
-                caps->descr_type=0;
-                break;
-        }
+		caps->slot_num = ca->slot_count;
+		caps->slot_type = CA_CI_LINK;
+		caps->descr_num = 0;
+		caps->descr_type = 0;
+		break;
+	}
 
 	case CA_GET_SLOT_INFO: {
-                struct ca_slot_info *info=(struct ca_slot_info *)parg;
+		struct ca_slot_info *info = parg;
 
-                if ((info->num > ca->slot_count) || (info->num < 0))
-                        return -EINVAL;
+		if ((info->num > ca->slot_count) || (info->num < 0))
+			return -EINVAL;
 
-                info->type = CA_CI_LINK;
-                info->flags = 0;
+		info->type = CA_CI_LINK;
+		info->flags = 0;
 		if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
 			&& (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
-                        info->flags = CA_CI_MODULE_PRESENT;
-                }
-                if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-                        info->flags |= CA_CI_MODULE_READY;
-                }
-                break;
-        }
-
-        default:
-                err=-EINVAL;
-                break;
-        }
+			info->flags = CA_CI_MODULE_PRESENT;
+		}
+		if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+			info->flags |= CA_CI_MODULE_READY;
+		}
+		break;
+	}
+
+	default:
+		err = -EINVAL;
+		break;
+	}
 
-        return err;
+	return err;
 }
 
 
@@ -1277,7 +1274,7 @@ static int dvb_ca_en50221_io_do_ioctl(st
 static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file,
 				   unsigned int cmd, unsigned long arg)
 {
-        return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+	return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
 }
 
 
@@ -1294,127 +1291,127 @@ static int dvb_ca_en50221_io_ioctl(struc
 static ssize_t dvb_ca_en50221_io_write(struct file *file,
 				       const char __user * buf, size_t count, loff_t * ppos)
 {
-        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
-        u8 slot, connection_id;
-        int status;
-        char fragbuf[HOST_LINK_BUF_SIZE];
-        int fragpos = 0;
-        int fraglen;
-        unsigned long timeout;
-        int written;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	u8 slot, connection_id;
+	int status;
+	char fragbuf[HOST_LINK_BUF_SIZE];
+	int fragpos = 0;
+	int fraglen;
+	unsigned long timeout;
+	int written;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+	/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
 	if (count < 2)
 		return -EINVAL;
 
-        /* extract slot & connection id */
+	/* extract slot & connection id */
 	if (copy_from_user(&slot, buf, 1))
 		return -EFAULT;
 	if (copy_from_user(&connection_id, buf + 1, 1))
 		return -EFAULT;
-        buf+=2;
-        count-=2;
+	buf += 2;
+	count -= 2;
 
-        /* check if the slot is actually running */
+	/* check if the slot is actually running */
 	if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
 		return -EINVAL;
 
-        /* fragment the packets & store in the buffer */
-        while(fragpos < count) {
-                fraglen = ca->slot_info[slot].link_buf_size - 2;
+	/* fragment the packets & store in the buffer */
+	while (fragpos < count) {
+		fraglen = ca->slot_info[slot].link_buf_size - 2;
 		if ((count - fragpos) < fraglen)
 			fraglen = count - fragpos;
 
-                fragbuf[0] = connection_id;
-                fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+		fragbuf[0] = connection_id;
+		fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
 		if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
 			goto exit;
 
-		timeout = jiffies + HZ/2;
-	        written = 0;
-                while(!time_after(jiffies, timeout)) {
+		timeout = jiffies + HZ / 2;
+		written = 0;
+		while (!time_after(jiffies, timeout)) {
 			/* check the CAM hasn't been removed/reset in the meantime */
 			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
 				status = -EIO;
 				goto exit;
 			}
 
-                        status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2);
-		        if (status == (fraglen+2)) {
-			       written = 1;
-			       break;
+			status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
+			if (status == (fraglen + 2)) {
+				written = 1;
+				break;
 			}
 			if (status != -EAGAIN)
 				goto exit;
 
-                        msleep(1);
-                }
-	        if (!written) {
-		        status = -EIO;
-		        goto exit;
+			msleep(1);
+		}
+		if (!written) {
+			status = -EIO;
+			goto exit;
 		}
 
-                fragpos += fraglen;
-        }
-        status = count + 2;
+		fragpos += fraglen;
+	}
+	status = count + 2;
 
 exit:
-        return status;
+	return status;
 }
 
 
 /**
  * Condition for waking up in dvb_ca_en50221_io_read_condition
  */
-static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* result, int* _slot)
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *result, int *_slot)
 {
-        int slot;
-        int slot_count = 0;
-        int idx;
-        int fraglen;
-        int connection_id = -1;
-        int found = 0;
-        u8 hdr[2];
+	int slot;
+	int slot_count = 0;
+	int idx;
+	int fraglen;
+	int connection_id = -1;
+	int found = 0;
+	u8 hdr[2];
 
-        slot = ca->next_read_slot;
-        while((slot_count < ca->slot_count) && (!found)) {
+	slot = ca->next_read_slot;
+	while ((slot_count < ca->slot_count) && (!found)) {
 		if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
 			goto nextslot;
 
-                down_read(&ca->slot_info[slot].sem);
+		down_read(&ca->slot_info[slot].sem);
 
 		if (ca->slot_info[slot].rx_buffer.data == NULL) {
 			up_read(&ca->slot_info[slot].sem);
 			return 0;
 		}
 
-                idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-                while(idx != -1) {
-                        dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+		while (idx != -1) {
+			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
 			if (connection_id == -1)
 				connection_id = hdr[0];
-                        if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
-                                *_slot = slot;
-                                found = 1;
-                                break;
-                        }
+			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
+				*_slot = slot;
+				found = 1;
+				break;
+			}
 
-                        idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
-                }
+			idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+		}
 
 		if (!found)
 			up_read(&ca->slot_info[slot].sem);
 
-nextslot:
-                slot = (slot + 1) % ca->slot_count;
-                slot_count++;
-        }
+	      nextslot:
+		slot = (slot + 1) % ca->slot_count;
+		slot_count++;
+	}
 
-        ca->next_read_slot = slot;
-        return found;
+	ca->next_read_slot = slot;
+	return found;
 }
 
 
@@ -1431,91 +1428,91 @@ nextslot:
 static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
 				      size_t count, loff_t * ppos)
 {
-        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
-        int status;
-        int result = 0;
-        u8 hdr[2];
-        int slot;
-        int connection_id = -1;
-        size_t idx, idx2;
-        int last_fragment = 0;
-        size_t fraglen;
-        int pktlen;
-        int dispose = 0;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int status;
+	int result = 0;
+	u8 hdr[2];
+	int slot;
+	int connection_id = -1;
+	size_t idx, idx2;
+	int last_fragment = 0;
+	size_t fraglen;
+	int pktlen;
+	int dispose = 0;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+	/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
 	if (count < 2)
 		return -EINVAL;
 
-        /* wait for some data */
-        if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
+	/* wait for some data */
+	if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
 
-                /* if we're in nonblocking mode, exit immediately */
+		/* if we're in nonblocking mode, exit immediately */
 		if (file->f_flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 
-                /* wait for some data */
+		/* wait for some data */
 		status = wait_event_interruptible(ca->wait_queue,
 						  dvb_ca_en50221_io_read_condition
 						  (ca, &result, &slot));
-        }
-        if ((status < 0) || (result < 0)) {
+	}
+	if ((status < 0) || (result < 0)) {
 		if (result)
 			return result;
-                return status;
-        }
+		return status;
+	}
 
-        idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-        pktlen = 2;
-        do {
-                if (idx == -1) {
-                        printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
-                        status = -EIO;
-                        goto exit;
-                }
+	idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+	pktlen = 2;
+	do {
+		if (idx == -1) {
+			printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
+			status = -EIO;
+			goto exit;
+		}
 
-                dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
 		if (connection_id == -1)
 			connection_id = hdr[0];
-                if (hdr[0] == connection_id) {
-                        if (pktlen < count) {
-                                if ((pktlen + fraglen - 2) > count) {
-                                        fraglen = count - pktlen;
-                                } else {
-                                        fraglen -= 2;
-                                }
+		if (hdr[0] == connection_id) {
+			if (pktlen < count) {
+				if ((pktlen + fraglen - 2) > count) {
+					fraglen = count - pktlen;
+				} else {
+					fraglen -= 2;
+				}
 
 				if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
 								      buf + pktlen, fraglen, 1)) < 0) {
-                                        goto exit;
-                                }
-                                pktlen += fraglen;
-                        }
+					goto exit;
+				}
+				pktlen += fraglen;
+			}
 
 			if ((hdr[1] & 0x80) == 0)
 				last_fragment = 1;
-                        dispose = 1;
-                }
+			dispose = 1;
+		}
 
-                idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+		idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
 		if (dispose)
 			dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
-                idx = idx2;
-                dispose = 0;
-        } while (!last_fragment);
+		idx = idx2;
+		dispose = 0;
+	} while (!last_fragment);
 
-        hdr[0] = slot;
-        hdr[1] = connection_id;
+	hdr[0] = slot;
+	hdr[1] = connection_id;
 	if ((status = copy_to_user(buf, hdr, 2)) != 0)
 		goto exit;
-        status = pktlen;
+	status = pktlen;
 
-exit:
-        up_read(&ca->slot_info[slot].sem);
-        return status;
+      exit:
+	up_read(&ca->slot_info[slot].sem);
+	return status;
 }
 
 
@@ -1529,36 +1526,36 @@ exit:
  */
 static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
 {
-        struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-        struct dvb_ca_private *ca = (struct dvb_ca_private*) dvbdev->priv;
-        int err;
-        int i;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int err;
+	int i;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
 	if (!try_module_get(ca->pub->owner))
 		return -EIO;
 
-        err=dvb_generic_open(inode, file);
-        if (err<0)
-                return err;
+	err = dvb_generic_open(inode, file);
+	if (err < 0)
+		return err;
 
-        for(i=0; i< ca->slot_count; i++) {
+	for (i = 0; i < ca->slot_count; i++) {
 
-                if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-		        down_write(&ca->slot_info[i].sem);
+		if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+			down_write(&ca->slot_info[i].sem);
 			if (ca->slot_info[i].rx_buffer.data != NULL) {
-                        dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+				dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
 			}
-		        up_write(&ca->slot_info[i].sem);
-                }
-        }
-
-        ca->open = 1;
-        dvb_ca_en50221_thread_update_delay(ca);
-        dvb_ca_en50221_thread_wakeup(ca);
+			up_write(&ca->slot_info[i].sem);
+		}
+	}
 
-        return 0;
+	ca->open = 1;
+	dvb_ca_en50221_thread_update_delay(ca);
+	dvb_ca_en50221_thread_wakeup(ca);
+
+	return 0;
 }
 
 
@@ -1572,21 +1569,21 @@ static int dvb_ca_en50221_io_open(struct
  */
 static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 {
-        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
-        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
 	int err = 0;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* mark the CA device as closed */
-        ca->open = 0;
-        dvb_ca_en50221_thread_update_delay(ca);
+	/* mark the CA device as closed */
+	ca->open = 0;
+	dvb_ca_en50221_thread_update_delay(ca);
 
-        err=dvb_generic_release(inode, file);
+	err = dvb_generic_release(inode, file);
 
 	module_put(ca->pub->owner);
 
-        return 0;
+	return 0;
 }
 
 
@@ -1598,56 +1595,57 @@ static int dvb_ca_en50221_io_release(str
  *
  * @return Standard poll mask.
  */
-static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
 {
-        struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;
-        unsigned int mask=0;
-        int slot;
-        int result = 0;
-
-        dprintk ("%s\n", __FUNCTION__);
-
-        if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-                up_read(&ca->slot_info[slot].sem);
-                mask |= POLLIN;
-        }
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	unsigned int mask = 0;
+	int slot;
+	int result = 0;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+		up_read(&ca->slot_info[slot].sem);
+		mask |= POLLIN;
+	}
 
-        /* if there is something, return now */
+	/* if there is something, return now */
 	if (mask)
 		return mask;
 
-        /* wait for something to happen */
-        poll_wait(file, &ca->wait_queue, wait);
+	/* wait for something to happen */
+	poll_wait(file, &ca->wait_queue, wait);
 
-        if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-                up_read(&ca->slot_info[slot].sem);
-                mask |= POLLIN;
-        }
+	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+		up_read(&ca->slot_info[slot].sem);
+		mask |= POLLIN;
+	}
 
-        return mask;
+	return mask;
 }
 EXPORT_SYMBOL(dvb_ca_en50221_init);
 
 
 static struct file_operations dvb_ca_fops = {
-	.owner	= THIS_MODULE,
-	.read	= dvb_ca_en50221_io_read,
-	.write	= dvb_ca_en50221_io_write,
-	.ioctl	= dvb_ca_en50221_io_ioctl,
-	.open	= dvb_ca_en50221_io_open,
-	.release= dvb_ca_en50221_io_release,
-	.poll	= dvb_ca_en50221_io_poll,
+	.owner = THIS_MODULE,
+	.read = dvb_ca_en50221_io_read,
+	.write = dvb_ca_en50221_io_write,
+	.ioctl = dvb_ca_en50221_io_ioctl,
+	.open = dvb_ca_en50221_io_open,
+	.release = dvb_ca_en50221_io_release,
+	.poll = dvb_ca_en50221_io_poll,
 };
 
 static struct dvb_device dvbdev_ca = {
-        .priv	= NULL,
-	.users	= 1,
-	.readers= 1,
-	.writers= 1,
-	.fops	= &dvb_ca_fops,
+	.priv = NULL,
+	.users = 1,
+	.readers = 1,
+	.writers = 1,
+	.fops = &dvb_ca_fops,
 };
 
+
 /* ******************************************************************************** */
 /* Initialisation/shutdown functions */
 
@@ -1665,79 +1663,80 @@ static struct dvb_device dvbdev_ca = {
 int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
 			struct dvb_ca_en50221 *pubca, int flags, int slot_count)
 {
-        int ret;
-        struct dvb_ca_private* ca = NULL;
-        int i;
+	int ret;
+	struct dvb_ca_private *ca = NULL;
+	int i;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
 	if (slot_count < 1)
 		return -EINVAL;
 
-        /* initialise the system data */
+	/* initialise the system data */
 	if ((ca =
 	     (struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private),
 					       GFP_KERNEL)) == NULL) {
-                ret = -ENOMEM;
-                goto error;
-        }
-        memset(ca, 0, sizeof(struct dvb_ca_private));
-        ca->pub = pubca;
-        ca->flags = flags;
-        ca->slot_count = slot_count;
-        if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) {
-                ret = -ENOMEM;
-                goto error;
-        }
-        memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count);
-        init_waitqueue_head(&ca->wait_queue);
-        ca->thread_pid = 0;
-        init_waitqueue_head(&ca->thread_queue);
-        ca->exit = 0;
-        ca->open = 0;
-        ca->wakeup = 0;
-        ca->next_read_slot = 0;
-        pubca->private = ca;
+		ret = -ENOMEM;
+		goto error;
+	}
+	memset(ca, 0, sizeof(struct dvb_ca_private));
+	ca->pub = pubca;
+	ca->flags = flags;
+	ca->slot_count = slot_count;
+	if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count);
+	init_waitqueue_head(&ca->wait_queue);
+	ca->thread_pid = 0;
+	init_waitqueue_head(&ca->thread_queue);
+	ca->exit = 0;
+	ca->open = 0;
+	ca->wakeup = 0;
+	ca->next_read_slot = 0;
+	pubca->private = ca;
 
-        /* register the DVB device */
-        ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
+	/* register the DVB device */
+	ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
 	if (ret)
 		goto error;
 
-        /* now initialise each slot */
-        for(i=0; i< slot_count; i++) {
-                memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
-                ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
-                atomic_set(&ca->slot_info[i].camchange_count, 0);
-                ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-                init_rwsem(&ca->slot_info[i].sem);
-        }
-
-        if (signal_pending(current)) {
-                ret = -EINTR;
-                goto error;
-        }
-        mb();
-
-        /* create a kthread for monitoring this CA device */
-        ret = kernel_thread (dvb_ca_en50221_thread, ca, 0);
-        if (ret < 0) {
-                printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
-                goto error;
-        }
-        ca->thread_pid = ret;
-        return 0;
+	/* now initialise each slot */
+	for (i = 0; i < slot_count; i++) {
+		memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+		ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+		atomic_set(&ca->slot_info[i].camchange_count, 0);
+		ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+		init_rwsem(&ca->slot_info[i].sem);
+	}
+
+	if (signal_pending(current)) {
+		ret = -EINTR;
+		goto error;
+	}
+	mb();
+
+	/* create a kthread for monitoring this CA device */
+
+	ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
+
+	if (ret < 0) {
+		printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+		goto error;
+	}
+	ca->thread_pid = ret;
+	return 0;
 
-error:
-        if (ca != NULL) {
+      error:
+	if (ca != NULL) {
 		if (ca->dvbdev != NULL)
 			dvb_unregister_device(ca->dvbdev);
-		if (ca->slot_info != NULL)
-			kfree(ca->slot_info);
-                kfree(ca);
-        }
-        pubca->private = NULL;
-        return ret;
+		kfree(ca->slot_info);
+		kfree(ca);
+	}
+	pubca->private = NULL;
+	return ret;
 }
 EXPORT_SYMBOL(dvb_ca_en50221_release);
 
@@ -1749,32 +1748,31 @@ EXPORT_SYMBOL(dvb_ca_en50221_release);
  * @param ca_dev The dvb_device_t instance for the CA device.
  * @param ca The associated dvb_ca instance.
  */
-void dvb_ca_en50221_release(struct dvb_ca_en50221* pubca)
+void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 {
-        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
-        int i;
+	struct dvb_ca_private *ca = pubca->private;
+	int i;
 
-        dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
-        /* shutdown the thread if there was one */
-        if (ca->thread_pid) {
-                if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
+	/* shutdown the thread if there was one */
+	if (ca->thread_pid) {
+		if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
 			printk("dvb_ca_release adapter %d: thread PID %d already died\n",
 			       ca->dvbdev->adapter->num, ca->thread_pid);
-                } else {
-                        ca->exit = 1;
-                        mb();
-                        dvb_ca_en50221_thread_wakeup(ca);
-                        wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
-                }
-        }
-
-        for(i=0; i< ca->slot_count; i++) {
-                dvb_ca_en50221_slot_shutdown(ca, i);
-        }
-        kfree(ca->slot_info);
-        dvb_unregister_device(ca->dvbdev);
-        kfree(ca);
-        pubca->private = NULL;
-}
+		} else {
+			ca->exit = 1;
+			mb();
+			dvb_ca_en50221_thread_wakeup(ca);
+			wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
+		}
+	}
 
+	for (i = 0; i < ca->slot_count; i++) {
+		dvb_ca_en50221_slot_shutdown(ca, i);
+	}
+	kfree(ca->slot_info);
+	dvb_unregister_device(ca->dvbdev);
+	kfree(ca);
+	pubca->private = NULL;
+}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvb_demux.c - DVB kernel demux API
  *
  * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
@@ -27,29 +27,29 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/string.h>
-	#include <linux/crc32.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 
 #include "dvb_demux.h"
 
-#define NOBUFS  
-/* 
+#define NOBUFS
+/*
 ** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
 
-LIST_HEAD(dmx_muxs);
+static LIST_HEAD(dmx_muxs);
 
 
-int dmx_register_demux(struct dmx_demux *demux) 
+static int dmx_register_demux(struct dmx_demux *demux)
 {
 	demux->users = 0;
 	list_add(&demux->reg_list, &dmx_muxs);
 	return 0;
 }
 
-int dmx_unregister_demux(struct dmx_demux* demux)
+static int dmx_unregister_demux(struct dmx_demux* demux)
 {
 	struct list_head *pos, *n, *head=&dmx_muxs;
 
@@ -66,14 +66,6 @@ int dmx_unregister_demux(struct dmx_demu
 }
 
 
-struct list_head *dmx_get_demuxes(void)
-{
-	if (list_empty(&dmx_muxs))
-		return NULL;
-
-	return &dmx_muxs;
-}
-
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -93,10 +85,10 @@ static inline u16 ts_pid(const u8 *buf)
 
 static inline u8 payload(const u8 *tsp)
 {
-	if (!(tsp[3]&0x10)) // no payload?
+	if (!(tsp[3] & 0x10)) // no payload?
 		return 0;
-	if (tsp[3]&0x20) {  // adaptation field?
-		if (tsp[4]>183)    // corrupted data?
+	if (tsp[3] & 0x20) {  // adaptation field?
+		if (tsp[4] > 183)    // corrupted data?
 			return 0;
 		else
 			return 184-1-tsp[4];
@@ -105,19 +97,6 @@ static inline u8 payload(const u8 *tsp)
 }
 
 
-void dvb_set_crc32(u8 *data, int length)
-{
-	u32 crc;
-
-	crc = crc32_be(~0, data, length);
-
-	data[length]   = (crc >> 24) & 0xff;
-	data[length+1] = (crc >> 16) & 0xff;
-	data[length+2] = (crc >>  8) & 0xff;
-	data[length+3] = (crc)       & 0xff;
-}
-
-
 static u32 dvb_dmx_crc32 (struct dvb_demux_feed *f, const u8 *src, size_t len)
 {
 	return (f->feed.sec.crc_val = crc32_be (f->feed.sec.crc_val, src, len));
@@ -134,7 +113,7 @@ static void dvb_dmx_memcopy (struct dvb_
  * Software filter functions
  ******************************************************************************/
 
-static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf) 
+static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf)
 {
 	int count = payload(buf);
 	int p;
@@ -159,11 +138,11 @@ static inline int dvb_dmx_swfilter_paylo
 
 	feed->peslen += count;
 
-	return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); 
+	return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
 }
 
 
-static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed, 
+static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed,
 				    struct dvb_demux_filter *f)
 {
 	u8 neq = 0;
@@ -181,8 +160,8 @@ static int dvb_dmx_swfilter_sectionfilte
 	if (f->doneq && !neq)
 		return 0;
 
-	return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen, 
-			     NULL, 0, &f->filter, DMX_OK); 
+	return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen,
+			     NULL, 0, &f->filter, DMX_OK);
 }
 
 
@@ -203,7 +182,7 @@ static inline int dvb_dmx_swfilter_secti
 		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
 		if (section_syntax_indicator &&
 		    demux->check_crc32(feed, sec->secbuf, sec->seclen))
-		return -1;
+			return -1;
 	}
 
 	do {
@@ -232,27 +211,27 @@ static void dvb_dmx_swfilter_section_new
 		*/
 		if(sec->secbuf[0] != 0xff || sec->secbuf[n-1] != 0xff)
 		{
-			printk("dvb_demux.c section ts padding loss: %d/%d\n", 
+			printk("dvb_demux.c section ts padding loss: %d/%d\n",
 			       n, sec->tsfeedp);
 			printk("dvb_demux.c pad data:");
 			for(i = 0; i < n; i++)
 				printk(" %02x", sec->secbuf[i]);
 			printk("\n");
-			}
-			}
+		}
+	}
 #endif
 
 	sec->tsfeedp = sec->secbufp = sec->seclen = 0;
 	sec->secbuf = sec->secbuf_base;
-		}
+}
 
-/* 
+/*
 ** Losless Section Demux 1.4.1 by Emard
 ** Valsecchi Patrick:
 **  - middle of section A  (no PUSI)
-**  - end of section A and start of section B 
+**  - end of section A and start of section B
 **    (with PUSI pointing to the start of the second section)
-**  
+**
 **  In this case, without feed->pusi_seen you'll receive a garbage section
 **  consisting of the end of section A. Basically because tsfeedp
 **  is incemented and the use=0 condition is not raised
@@ -276,7 +255,7 @@ static int dvb_dmx_swfilter_section_copy
 	if(sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE)
 	{
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
-		printk("dvb_demux.c section buffer full loss: %d/%d\n", 
+		printk("dvb_demux.c section buffer full loss: %d/%d\n",
 		       sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE);
 #endif
 		len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
@@ -302,38 +281,38 @@ static int dvb_dmx_swfilter_section_copy
 	for(n = 0; sec->secbufp + 2 < limit; n++)
 	{
 		seclen = section_length(sec->secbuf);
-		if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE 
+		if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE
 		   || seclen + sec->secbufp > limit)
 			return 0;
 		sec->seclen = seclen;
 		sec->crc_val = ~0;
 		/* dump [secbuf .. secbuf+seclen) */
 		if(feed->pusi_seen)
-		dvb_dmx_swfilter_section_feed(feed);
+			dvb_dmx_swfilter_section_feed(feed);
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
 		else
 			printk("dvb_demux.c pusi not seen, discarding section data\n");
 #endif
 		sec->secbufp += seclen; /* secbufp and secbuf moving together is */
 		sec->secbuf += seclen; /* redundand but saves pointer arithmetic */
-		}
-
-		return 0;
 	}
 
+	return 0;
+}
+
 
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf)
 {
 	u8 p, count;
 	int ccok, dc_i = 0;
 	u8 cc;
 
 	count = payload(buf);
-		
+
 	if (count == 0)  /* count == 0 if no payload or out of range */
-			return -1;
+		return -1;
 
-	p = 188-count; /* payload start */
+	p = 188 - count; /* payload start */
 
 	cc = buf[3] & 0x0f;
 	ccok = ((feed->cc + 1) & 0x0f) == cc;
@@ -376,7 +355,7 @@ static int dvb_dmx_swfilter_section_pack
 		}
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
 		else
-			if(count > 0)
+			if (count > 0)
 				printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
 #endif
 	} else {
@@ -400,9 +379,9 @@ static inline void dvb_dmx_swfilter_pack
 			if (feed->ts_type & TS_PAYLOAD_ONLY)
 				dvb_dmx_swfilter_payload(feed, buf);
 			else
-				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); 
+				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
 		}
-		if (feed->ts_type & TS_DECODER) 
+		if (feed->ts_type & TS_DECODER)
 			if (feed->demux->write_to_decoder)
 				feed->demux->write_to_decoder(feed, buf, 188);
 		break;
@@ -424,7 +403,7 @@ static inline void dvb_dmx_swfilter_pack
 	((f)->feed.ts.is_filtering) &&					\
 	(((f)->ts_type & (TS_PACKET|TS_PAYLOAD_ONLY)) == TS_PACKET))
 
-void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 {
 	struct dvb_demux_feed *feed;
 	struct list_head *pos, *head=&demux->feed_list;
@@ -443,7 +422,7 @@ void dvb_dmx_swfilter_packet(struct dvb_
 			continue;
 
 		if (feed->pid == pid) {
-			dvb_dmx_swfilter_packet_type (feed, buf);
+			dvb_dmx_swfilter_packet_type(feed, buf);
 			if (DVR_FEED(feed))
 				continue;
 		}
@@ -452,15 +431,14 @@ void dvb_dmx_swfilter_packet(struct dvb_
 			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
 	}
 }
-EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
 	spin_lock(&demux->lock);
 
 	while (count--) {
-               	if(buf[0] == 0x47) {
-		dvb_dmx_swfilter_packet(demux, buf);
+		if(buf[0] == 0x47) {
+		        dvb_dmx_swfilter_packet(demux, buf);
 		}
 		buf += 188;
 	}
@@ -472,8 +450,8 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	int p = 0,i, j;
-	
+	int p = 0, i, j;
+
 	spin_lock(&demux->lock);
 
 	if ((i = demux->tsbufp)) {
@@ -484,7 +462,7 @@ void dvb_dmx_swfilter(struct dvb_demux *
 		}
 		memcpy(&demux->tsbuf[i], buf, j);
 		if (demux->tsbuf[0] == 0x47)
-		dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+			dvb_dmx_swfilter_packet(demux, demux->tsbuf);
 		demux->tsbufp = 0;
 		p += j;
 	}
@@ -500,7 +478,7 @@ void dvb_dmx_swfilter(struct dvb_demux *
 				demux->tsbufp=i;
 				goto bailout;
 			}
-		} else 
+		} else
 			p++;
 	}
 
@@ -544,7 +522,7 @@ void dvb_dmx_swfilter_204(struct dvb_dem
 				demux->tsbufp=i;
 				goto bailout;
 			}
-		} else { 
+		} else {
 			p++;
 		}
 	}
@@ -595,8 +573,8 @@ static int dvb_demux_feed_find(struct dv
 		if (entry == feed)
 			return 1;
 
-		return 0;
-		}
+	return 0;
+}
 
 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
 {
@@ -619,16 +597,16 @@ static void dvb_demux_feed_del(struct dv
 		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
 				__FUNCTION__, feed->type, feed->state, feed->pid);
 		goto out;
-}
+	}
 
 	list_del(&feed->list_head);
 out:
 	spin_unlock_irq(&feed->demux->lock);
 }
 
-static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, 
-		     enum dmx_ts_pes pes_type, size_t callback_length, 
-		     size_t circular_buffer_size, int descramble, 
+static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type,
+		     enum dmx_ts_pes pes_type, size_t callback_length,
+		     size_t circular_buffer_size, int descramble,
 		     struct timespec timeout)
 {
 	struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
@@ -636,7 +614,7 @@ static int dmx_ts_feed_set (struct dmx_t
 
 	if (pid > DMX_MAX_PID)
 		return -EINVAL;
-	
+
 	if (down_interruptible (&demux->mutex))
 		return -ERESTARTSYS;
 
@@ -646,7 +624,7 @@ static int dmx_ts_feed_set (struct dmx_t
 			return -EINVAL;
 		}
 
-		if (demux->pesfilter[pes_type] && 
+		if (demux->pesfilter[pes_type] &&
 		    demux->pesfilter[pes_type] != feed) {
 			up(&demux->mutex);
 			return -EINVAL;
@@ -682,7 +660,7 @@ static int dmx_ts_feed_set (struct dmx_t
 		}
 #endif
 	}
-	
+
 	feed->state = DMX_STATE_READY;
 	up(&demux->mutex);
 
@@ -722,7 +700,7 @@ static int dmx_ts_feed_start_filtering(s
 
 	return 0;
 }
- 
+
 static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed* ts_feed)
 {
 	struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
@@ -732,7 +710,7 @@ static int dmx_ts_feed_stop_filtering(st
 	if (down_interruptible (&demux->mutex))
 		return -ERESTARTSYS;
 
-	if (feed->state<DMX_STATE_GO) {
+	if (feed->state < DMX_STATE_GO) {
 		up(&demux->mutex);
 		return -EINVAL;
 	}
@@ -742,7 +720,7 @@ static int dmx_ts_feed_stop_filtering(st
 		return -ENODEV;
 	}
 
-	ret = demux->stop_feed(feed); 
+	ret = demux->stop_feed(feed);
 
 	spin_lock_irq(&demux->lock);
 	ts_feed->is_filtering = 0;
@@ -753,7 +731,7 @@ static int dmx_ts_feed_stop_filtering(st
 	return ret;
 }
 
-static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed **ts_feed, 
+static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed **ts_feed,
 			     dmx_ts_cb callback)
 {
 	struct dvb_demux *demux = (struct dvb_demux *) dmx;
@@ -792,7 +770,7 @@ static int dvbdmx_allocate_ts_feed (stru
 	feed->filter->type = DMX_TYPE_TS;
 	feed->filter->feed = feed;
 	feed->filter->state = DMX_STATE_READY;
-	
+
 	up(&demux->mutex);
 
 	return 0;
@@ -812,8 +790,8 @@ static int dvbdmx_release_ts_feed(struct
 	}
 
 #ifndef NOBUFS
-		vfree(feed->buffer);
-		feed->buffer=0;
+	vfree(feed->buffer);
+	feed->buffer=0;
 #endif
 
 	feed->state = DMX_STATE_FREE;
@@ -821,8 +799,8 @@ static int dvbdmx_release_ts_feed(struct
 
 	dvb_demux_feed_del(feed);
 
-		feed->pid = 0xffff;
-	
+	feed->pid = 0xffff;
+
 	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
 		demux->pesfilter[feed->pes_type] = NULL;
 
@@ -835,64 +813,65 @@ static int dvbdmx_release_ts_feed(struct
  * dmx_section_feed API calls
  ******************************************************************************/
 
-static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, 
-				     struct dmx_section_filter** filter) 
+static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed,
+				     struct dmx_section_filter** filter)
 {
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdemux=dvbdmxfeed->demux;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
 	struct dvb_demux_filter *dvbdmxfilter;
 
 	if (down_interruptible (&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
-	dvbdmxfilter=dvb_dmx_filter_alloc(dvbdemux);
+	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
 	if (!dvbdmxfilter) {
 		up(&dvbdemux->mutex);
 		return -EBUSY;
 	}
 
 	spin_lock_irq(&dvbdemux->lock);
-	*filter=&dvbdmxfilter->filter;
-	(*filter)->parent=feed;
-	(*filter)->priv=NULL;
-	dvbdmxfilter->feed=dvbdmxfeed;
-	dvbdmxfilter->type=DMX_TYPE_SEC;
-	dvbdmxfilter->state=DMX_STATE_READY;
-
-	dvbdmxfilter->next=dvbdmxfeed->filter;
-	dvbdmxfeed->filter=dvbdmxfilter;
+	*filter = &dvbdmxfilter->filter;
+	(*filter)->parent = feed;
+	(*filter)->priv = NULL;
+	dvbdmxfilter->feed = dvbdmxfeed;
+	dvbdmxfilter->type = DMX_TYPE_SEC;
+	dvbdmxfilter->state = DMX_STATE_READY;
+	dvbdmxfilter->next = dvbdmxfeed->filter;
+	dvbdmxfeed->filter = dvbdmxfilter;
 	spin_unlock_irq(&dvbdemux->lock);
+
 	up(&dvbdemux->mutex);
 	return 0;
 }
 
 
-static int dmx_section_feed_set(struct dmx_section_feed* feed, 
-		     u16 pid, size_t circular_buffer_size, 
-		     int descramble, int check_crc) 
+static int dmx_section_feed_set(struct dmx_section_feed* feed,
+			 u16 pid, size_t circular_buffer_size,
+			 int descramble, int check_crc)
 {
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
-	if (pid>0x1fff)
+	if (pid > 0x1fff)
 		return -EINVAL;
 
 	if (down_interruptible (&dvbdmx->mutex))
 		return -ERESTARTSYS;
-	
+
 	dvb_demux_feed_add(dvbdmxfeed);
 
 	dvbdmxfeed->pid = pid;
-	dvbdmxfeed->buffer_size=circular_buffer_size;
-	dvbdmxfeed->descramble=descramble;
+	dvbdmxfeed->buffer_size = circular_buffer_size;
+	dvbdmxfeed->descramble = descramble;
 	if (dvbdmxfeed->descramble) {
 		up(&dvbdmx->mutex);
 		return -ENOSYS;
 	}
 
-	dvbdmxfeed->feed.sec.check_crc=check_crc;
+	dvbdmxfeed->feed.sec.check_crc = check_crc;
+
 #ifdef NOBUFS
-	dvbdmxfeed->buffer=NULL;
+	dvbdmxfeed->buffer = NULL;
 #else
 	dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
 	if (!dvbdmxfeed->buffer) {
@@ -900,47 +879,50 @@ static int dmx_section_feed_set(struct d
 		return -ENOMEM;
 	}
 #endif
-	dvbdmxfeed->state=DMX_STATE_READY;
+
+	dvbdmxfeed->state = DMX_STATE_READY;
 	up(&dvbdmx->mutex);
 	return 0;
 }
 
+
 static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
 {
 	int i;
 	struct dvb_demux_filter *f;
 	struct dmx_section_filter *sf;
 	u8 mask, mode, doneq;
-		
+
 	if (!(f=dvbdmxfeed->filter))
 		return;
 	do {
-		sf=&f->filter;
-		doneq=0;
+		sf = &f->filter;
+		doneq = 0;
 		for (i=0; i<DVB_DEMUX_MASK_MAX; i++) {
-			mode=sf->filter_mode[i];
-			mask=sf->filter_mask[i];
-			f->maskandmode[i]=mask&mode;
-			doneq|=f->maskandnotmode[i]=mask&~mode;
+			mode = sf->filter_mode[i];
+			mask = sf->filter_mask[i];
+			f->maskandmode[i] = mask & mode;
+			doneq |= f->maskandnotmode[i] = mask & ~mode;
 		}
-		f->doneq=doneq ? 1 : 0;
-	} while ((f=f->next));
+		f->doneq = doneq ? 1 : 0;
+	} while ((f = f->next));
 }
 
 
 static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
 {
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
 	if (down_interruptible (&dvbdmx->mutex))
 		return -ERESTARTSYS;
-	
+
 	if (feed->is_filtering) {
 		up(&dvbdmx->mutex);
 		return -EBUSY;
 	}
+
 	if (!dvbdmxfeed->filter) {
 		up(&dvbdmx->mutex);
 		return -EINVAL;
@@ -948,9 +930,9 @@ static int dmx_section_feed_start_filter
 
 	dvbdmxfeed->feed.sec.tsfeedp = 0;
 	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
-	dvbdmxfeed->feed.sec.secbufp=0;
-	dvbdmxfeed->feed.sec.seclen=0;
-	
+	dvbdmxfeed->feed.sec.secbufp = 0;
+	dvbdmxfeed->feed.sec.seclen = 0;
+
 	if (!dvbdmx->start_feed) {
 		up(&dvbdmx->mutex);
 		return -ENODEV;
@@ -964,9 +946,10 @@ static int dmx_section_feed_start_filter
 	}
 
 	spin_lock_irq(&dvbdmx->lock);
-	feed->is_filtering=1;
-	dvbdmxfeed->state=DMX_STATE_GO;
+	feed->is_filtering = 1;
+	dvbdmxfeed->state = DMX_STATE_GO;
 	spin_unlock_irq(&dvbdmx->lock);
+
 	up(&dvbdmx->mutex);
 	return 0;
 }
@@ -974,8 +957,8 @@ static int dmx_section_feed_start_filter
 
 static int dmx_section_feed_stop_filtering(struct dmx_section_feed* feed)
 {
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
 	if (down_interruptible (&dvbdmx->mutex))
@@ -985,93 +968,99 @@ static int dmx_section_feed_stop_filteri
 		up(&dvbdmx->mutex);
 		return -ENODEV;
 	}
-	ret=dvbdmx->stop_feed(dvbdmxfeed); 
+
+	ret = dvbdmx->stop_feed(dvbdmxfeed);
+
 	spin_lock_irq(&dvbdmx->lock);
-	dvbdmxfeed->state=DMX_STATE_READY;
-	feed->is_filtering=0;
+	dvbdmxfeed->state = DMX_STATE_READY;
+	feed->is_filtering = 0;
 	spin_unlock_irq(&dvbdmx->lock);
+
 	up(&dvbdmx->mutex);
 	return ret;
 }
 
 
-static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, 
+static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
 				struct dmx_section_filter* filter)
 {
-	struct dvb_demux_filter *dvbdmxfilter=(struct dvb_demux_filter *) filter, *f;
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
+	struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *) filter, *f;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
 	if (down_interruptible (&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
-	if (dvbdmxfilter->feed!=dvbdmxfeed) {
+	if (dvbdmxfilter->feed != dvbdmxfeed) {
 		up(&dvbdmx->mutex);
 		return -EINVAL;
 	}
-	if (feed->is_filtering) 
+
+	if (feed->is_filtering)
 		feed->stop_filtering(feed);
-	
+
 	spin_lock_irq(&dvbdmx->lock);
-	f=dvbdmxfeed->filter;
+	f = dvbdmxfeed->filter;
 
 	if (f == dvbdmxfilter) {
-		dvbdmxfeed->filter=dvbdmxfilter->next;
+		dvbdmxfeed->filter = dvbdmxfilter->next;
 	} else {
-		while(f->next!=dvbdmxfilter)
-			f=f->next;
-		f->next=f->next->next;
+		while(f->next != dvbdmxfilter)
+			f = f->next;
+		f->next = f->next->next;
 	}
-	dvbdmxfilter->state=DMX_STATE_FREE;
+
+	dvbdmxfilter->state = DMX_STATE_FREE;
 	spin_unlock_irq(&dvbdmx->lock);
 	up(&dvbdmx->mutex);
 	return 0;
 }
 
-static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, 
+static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
 					struct dmx_section_feed **feed,
 					dmx_section_cb callback)
 {
-	struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdmx = (struct dvb_demux *) demux;
 	struct dvb_demux_feed *dvbdmxfeed;
 
 	if (down_interruptible (&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
-	if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) {
+	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
 		up(&dvbdmx->mutex);
 		return -EBUSY;
 	}
-	dvbdmxfeed->type=DMX_TYPE_SEC;
-	dvbdmxfeed->cb.sec=callback;
-	dvbdmxfeed->demux=dvbdmx;
-	dvbdmxfeed->pid=0xffff;
+
+	dvbdmxfeed->type = DMX_TYPE_SEC;
+	dvbdmxfeed->cb.sec = callback;
+	dvbdmxfeed->demux = dvbdmx;
+	dvbdmxfeed->pid = 0xffff;
 	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
 	dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
 	dvbdmxfeed->feed.sec.tsfeedp = 0;
-	dvbdmxfeed->filter=NULL;
-	dvbdmxfeed->buffer=NULL;
+	dvbdmxfeed->filter = NULL;
+	dvbdmxfeed->buffer = NULL;
 
 	(*feed)=&dvbdmxfeed->feed.sec;
-	(*feed)->is_filtering=0;
-	(*feed)->parent=demux;
-	(*feed)->priv=NULL;
-
-	(*feed)->set=dmx_section_feed_set;
-	(*feed)->allocate_filter=dmx_section_feed_allocate_filter;
-	(*feed)->start_filtering=dmx_section_feed_start_filtering;
-	(*feed)->stop_filtering=dmx_section_feed_stop_filtering;
+	(*feed)->is_filtering = 0;
+	(*feed)->parent = demux;
+	(*feed)->priv = NULL;
+
+	(*feed)->set = dmx_section_feed_set;
+	(*feed)->allocate_filter = dmx_section_feed_allocate_filter;
+	(*feed)->start_filtering = dmx_section_feed_start_filtering;
+	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
 	(*feed)->release_filter = dmx_section_feed_release_filter;
 
 	up(&dvbdmx->mutex);
 	return 0;
 }
 
-static int dvbdmx_release_section_feed(struct dmx_demux *demux, 
+static int dvbdmx_release_section_feed(struct dmx_demux *demux,
 				       struct dmx_section_feed *feed)
 {
-	struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
-	struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed;
+	struct dvb_demux *dvbdmx = (struct dvb_demux *) demux;
 
 	if (down_interruptible (&dvbdmx->mutex))
 		return -ERESTARTSYS;
@@ -1081,14 +1070,14 @@ static int dvbdmx_release_section_feed(s
 		return -EINVAL;
 	}
 #ifndef NOBUFS
-		vfree(dvbdmxfeed->buffer);
-		dvbdmxfeed->buffer=0;
+	vfree(dvbdmxfeed->buffer);
+	dvbdmxfeed->buffer=0;
 #endif
 	dvbdmxfeed->state=DMX_STATE_FREE;
 
 	dvb_demux_feed_del(dvbdmxfeed);
 
-		dvbdmxfeed->pid = 0xffff;
+	dvbdmxfeed->pid = 0xffff;
 
 	up(&dvbdmx->mutex);
 	return 0;
@@ -1101,10 +1090,11 @@ static int dvbdmx_release_section_feed(s
 
 static int dvbdmx_open(struct dmx_demux *demux)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
-	if (dvbdemux->users>=MAX_DVB_DEMUX_USERS)
+	if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
 		return -EUSERS;
+
 	dvbdemux->users++;
 	return 0;
 }
@@ -1112,10 +1102,11 @@ static int dvbdmx_open(struct dmx_demux 
 
 static int dvbdmx_close(struct dmx_demux *demux)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
-	if (dvbdemux->users==0)
+	if (dvbdemux->users == 0)
 		return -ENODEV;
+
 	dvbdemux->users--;
 	//FIXME: release any unneeded resources if users==0
 	return 0;
@@ -1142,7 +1133,7 @@ static int dvbdmx_write(struct dmx_demux
 
 static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 	struct list_head *head = &dvbdemux->frontend_list;
 
 	list_add(&(frontend->connectivity_list), head);
@@ -1153,8 +1144,8 @@ static int dvbdmx_add_frontend(struct dm
 
 static int dvbdmx_remove_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
-	struct list_head *pos, *n, *head=&dvbdemux->frontend_list;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
+	struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
 
 	list_for_each_safe (pos, n, head) {
 		if (DMX_FE_ENTRY(pos) == frontend) {
@@ -1162,13 +1153,14 @@ static int dvbdmx_remove_frontend(struct
 			return 0;
 		}
 	}
+
 	return -ENODEV;
 }
 
 
 static struct list_head * dvbdmx_get_frontends(struct dmx_demux *demux)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
 	if (list_empty(&dvbdemux->frontend_list))
 		return NULL;
@@ -1176,40 +1168,38 @@ static struct list_head * dvbdmx_get_fro
 }
 
 
-int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
+static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
 	if (demux->frontend)
 		return -EINVAL;
-	
+
 	if (down_interruptible (&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
-	demux->frontend=frontend;
+	demux->frontend = frontend;
 	up(&dvbdemux->mutex);
 	return 0;
 }
-EXPORT_SYMBOL(dvbdmx_connect_frontend);
 
 
-int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
+static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
 	if (down_interruptible (&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
-	demux->frontend=NULL;
+	demux->frontend = NULL;
 	up(&dvbdemux->mutex);
 	return 0;
 }
-EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
 
 static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
 {
-	struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
 
 	memcpy(pids, dvbdemux->pids, 5*sizeof(u16));
 	return 0;
@@ -1221,35 +1211,38 @@ int dvb_dmx_init(struct dvb_demux *dvbde
 	int i, err;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
-	dvbdemux->users=0;
-	dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter));
+	dvbdemux->users = 0;
+	dvbdemux->filter = vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter));
+
 	if (!dvbdemux->filter)
 		return -ENOMEM;
 
-	dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed));
+	dvbdemux->feed = vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed));
 	if (!dvbdemux->feed) {
 		vfree(dvbdemux->filter);
 		return -ENOMEM;
 	}
 	for (i=0; i<dvbdemux->filternum; i++) {
-		dvbdemux->filter[i].state=DMX_STATE_FREE;
-		dvbdemux->filter[i].index=i;
+		dvbdemux->filter[i].state = DMX_STATE_FREE;
+		dvbdemux->filter[i].index = i;
+	}
+	for (i=0; i<dvbdemux->feednum; i++) {
+		dvbdemux->feed[i].state = DMX_STATE_FREE;
+		dvbdemux->feed[i].index = i;
 	}
-	for (i=0; i<dvbdemux->feednum; i++)
-		dvbdemux->feed[i].state=DMX_STATE_FREE;
 	dvbdemux->frontend_list.next=
 	  dvbdemux->frontend_list.prev=
 	    &dvbdemux->frontend_list;
 	for (i=0; i<DMX_TS_PES_OTHER; i++) {
-		dvbdemux->pesfilter[i]=NULL;
-		dvbdemux->pids[i]=0xffff;
+		dvbdemux->pesfilter[i] = NULL;
+		dvbdemux->pids[i] = 0xffff;
 	}
 
 	INIT_LIST_HEAD(&dvbdemux->feed_list);
 
 	dvbdemux->playing = 0;
 	dvbdemux->recording = 0;
-	dvbdemux->tsbufp=0;
+	dvbdemux->tsbufp = 0;
 
 	if (!dvbdemux->check_crc32)
 		dvbdemux->check_crc32 = dvb_dmx_crc32;
@@ -1257,30 +1250,31 @@ int dvb_dmx_init(struct dvb_demux *dvbde
 	 if (!dvbdemux->memcopy)
 		 dvbdemux->memcopy = dvb_dmx_memcopy;
 
-	dmx->frontend=NULL;
+	dmx->frontend = NULL;
 	dmx->reg_list.prev = dmx->reg_list.next = &dmx->reg_list;
-	dmx->priv=(void *) dvbdemux;
-	dmx->open=dvbdmx_open;
-	dmx->close=dvbdmx_close;
-	dmx->write=dvbdmx_write;
-	dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed;
-	dmx->release_ts_feed=dvbdmx_release_ts_feed;
-	dmx->allocate_section_feed=dvbdmx_allocate_section_feed;
-	dmx->release_section_feed=dvbdmx_release_section_feed;
-
-	dmx->descramble_mac_address=NULL;
-	dmx->descramble_section_payload=NULL;
-	
-	dmx->add_frontend=dvbdmx_add_frontend;
-	dmx->remove_frontend=dvbdmx_remove_frontend;
-	dmx->get_frontends=dvbdmx_get_frontends;
-	dmx->connect_frontend=dvbdmx_connect_frontend;
-	dmx->disconnect_frontend=dvbdmx_disconnect_frontend;
-	dmx->get_pes_pids=dvbdmx_get_pes_pids;
+	dmx->priv = (void *) dvbdemux;
+	dmx->open = dvbdmx_open;
+	dmx->close = dvbdmx_close;
+	dmx->write = dvbdmx_write;
+	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
+	dmx->release_ts_feed = dvbdmx_release_ts_feed;
+	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
+	dmx->release_section_feed = dvbdmx_release_section_feed;
+
+	dmx->descramble_mac_address = NULL;
+	dmx->descramble_section_payload = NULL;
+
+	dmx->add_frontend = dvbdmx_add_frontend;
+	dmx->remove_frontend = dvbdmx_remove_frontend;
+	dmx->get_frontends = dvbdmx_get_frontends;
+	dmx->connect_frontend = dvbdmx_connect_frontend;
+	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
+	dmx->get_pes_pids = dvbdmx_get_pes_pids;
+
 	sema_init(&dvbdemux->mutex, 1);
 	spin_lock_init(&dvbdemux->lock);
 
-	if ((err = dmx_register_demux(dmx)) < 0) 
+	if ((err = dmx_register_demux(dmx)) < 0)
 		return err;
 
 	return 0;
@@ -1293,9 +1287,8 @@ int dvb_dmx_release(struct dvb_demux *dv
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
 	dmx_unregister_demux(dmx);
-		vfree(dvbdemux->filter);
-		vfree(dvbdemux->feed);
+	vfree(dvbdemux->filter);
+	vfree(dvbdemux->feed);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_dmx_release);
-
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvb_demux.h: DVB kernel demux API
  *
  * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
@@ -45,10 +45,10 @@
 
 struct dvb_demux_filter {
         struct dmx_section_filter filter;
-        u8 maskandmode    [DMX_MAX_FILTER_SIZE]; 
-        u8 maskandnotmode [DMX_MAX_FILTER_SIZE]; 
+        u8 maskandmode    [DMX_MAX_FILTER_SIZE];
+        u8 maskandnotmode [DMX_MAX_FILTER_SIZE];
 	int doneq;
-		
+
         struct dvb_demux_filter *next;
         struct dvb_demux_feed *feed;
         int index;
@@ -85,10 +85,10 @@ struct dvb_demux_feed {
         int buffer_size;
         int descramble;
 
-        struct timespec timeout; 
+        struct timespec timeout;
         struct dvb_demux_filter *filter;
         int cb_length;
-  
+
         int ts_type;
         enum dmx_ts_pes pes_type;
 
@@ -98,6 +98,7 @@ struct dvb_demux_feed {
         u16 peslen;
 
 	struct list_head list_head;
+		int index; /* a unique index for each feed (can be used as hardware pid filter index) */
 };
 
 struct dvb_demux {
@@ -113,7 +114,7 @@ struct dvb_demux {
 			    const u8 *buf, size_t len);
 	void (*memcopy) (struct dvb_demux_feed *feed, u8 *dst,
 			 const u8 *src, size_t len);
-  
+
         int users;
 #define MAX_DVB_DEMUX_USERS 10
         struct dvb_demux_filter *filter;
@@ -123,8 +124,8 @@ struct dvb_demux {
 
         struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
         u16 pids[DMX_TS_PES_OTHER];
-        int playing; 
-        int recording; 
+        int playing;
+        int recording;
 
 #define DMX_MAX_PID 0x2000
 	struct list_head feed_list;
@@ -138,13 +139,8 @@ struct dvb_demux {
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
 int dvb_dmx_release(struct dvb_demux *dvbdemux);
-void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf);
 void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count);
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count);
 
-int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend);
-int dvbdmx_disconnect_frontend(struct dmx_demux *demux);
-
 #endif /* _DVB_DEMUX_H_ */
-
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ b/drivers/media/dvb/dvb-core/dvb_filter.c
@@ -22,12 +22,12 @@ static u32 ac3_frames[3][32] =
      {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
       1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
      {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
-      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; 
+      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 
 
 
 #if 0
-static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, 
+static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
 		  void (*pes_write)(u8 *buf, int count, void *data),
 		  void *priv)
 {
@@ -72,7 +72,7 @@ static int read_picture_header(u8 *headr
 	u8 pct;
 
 	if (pr) printk( "Pic header: ");
-        pic->temporal_reference[field] = (( headr[0] << 2 ) | 
+        pic->temporal_reference[field] = (( headr[0] << 2 ) |
 					  (headr[1] & 0x03) )& 0x03ff;
 	if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
 
@@ -93,31 +93,31 @@ static int read_picture_header(u8 *headr
 	}
 
 
-        pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) | 
+        pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) |
 				 ( (headr[3] & 0x1F) << 11) ) & 0xffff;
 
 	if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
 
-        pic->picture_header_parameter = ( headr[3] & 0xe0 ) | 
+        pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
 		((headr[4] & 0x80) >> 3);
 
         if ( pct == B_FRAME ){
                 pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
         }
-	if (pr) printk( " pic head param: 0x%x", 
+	if (pr) printk( " pic head param: 0x%x",
 			pic->picture_header_parameter);
 
 	return pct;
-} 
+}
 #endif
 
 #if 0
 /* needs 4 byte input */
 static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
 {
-	if (pr) printk("GOP header: "); 
+	if (pr) printk("GOP header: ");
 
-	pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) | 
+	pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) |
 			   ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
 
 	if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
@@ -129,14 +129,14 @@ static int read_gop_header(u8 *headr, st
         } else {
                 pic->closed_gop = 0;
         }
-	if (pr) printk("closed: %d", pic->closed_gop); 
+	if (pr) printk("closed: %d", pic->closed_gop);
 
         if ( ( headr[3] & 0x20 ) != 0 ){
                 pic->broken_link = 1;
         } else {
                 pic->broken_link = 0;
         }
-	if (pr) printk(" broken: %d\n", pic->broken_link); 
+	if (pr) printk(" broken: %d\n", pic->broken_link);
 
 	return 0;
 }
@@ -153,39 +153,39 @@ static int read_sequence_header(u8 *head
 
 	vi->horizontal_size	= ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
 	vi->vertical_size	= ((headr[1] &0x0F) << 8) | (headr[2]);
-    
+
         sw = (int)((headr[3]&0xF0) >> 4) ;
 
         switch( sw ){
 	case 1:
 		if (pr)
 			printk("Videostream: ASPECT: 1:1");
-		vi->aspect_ratio = 100;        
+		vi->aspect_ratio = 100;
 		break;
 	case 2:
 		if (pr)
 			printk("Videostream: ASPECT: 4:3");
-                vi->aspect_ratio = 133;        
+                vi->aspect_ratio = 133;
 		break;
 	case 3:
 		if (pr)
 			printk("Videostream: ASPECT: 16:9");
-                vi->aspect_ratio = 177;        
+                vi->aspect_ratio = 177;
 		break;
 	case 4:
 		if (pr)
 			printk("Videostream: ASPECT: 2.21:1");
-                vi->aspect_ratio = 221;        
+                vi->aspect_ratio = 221;
 		break;
 
         case 5 ... 15:
 		if (pr)
 			printk("Videostream: ASPECT: reserved");
-                vi->aspect_ratio = 0;        
+                vi->aspect_ratio = 0;
 		break;
 
         default:
-                vi->aspect_ratio = 0;        
+                vi->aspect_ratio = 0;
                 return -1;
 	}
 
@@ -240,7 +240,7 @@ static int read_sequence_header(u8 *head
 	}
 
 	vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
-	
+
         vi->vbv_buffer_size
                 = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
 
@@ -303,7 +303,7 @@ static int get_ainfo(u8 *mbuf, int count
 		else {
 			c++;
 		}
-	}	
+	}
 
 	if (!found) return -1;
 
@@ -333,8 +333,8 @@ static int get_ainfo(u8 *mbuf, int count
 		if (ai->frequency == 3)
 			printk("  Freq: reserved\n");
 		else
-			printk("  Freq: %d kHz\n",ai->frequency); 
-			       
+			printk("  Freq: %d kHz\n",ai->frequency);
+
 	}
 	ai->off = c;
 	return 0;
@@ -349,7 +349,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int
 	int c = 0;
 	u8 frame = 0;
 	int fr = 0;
-	
+
 	while ( !found  && c < count){
 		u8 *b = mbuf+c;
 
@@ -358,7 +358,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int
 		else {
 			c++;
 		}
-	}	
+	}
 
 	if (!found) return -1;
 	if (pr)
@@ -402,7 +402,7 @@ static u8 *skip_pes_header(u8 **bufp)
         int skip = 0;
 
 	static const int mpeg1_skip_table[16] = {
-        	1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
+		1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
 	        0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
 	};
 
@@ -479,9 +479,9 @@ static void initialize_mpg_picture(struc
 
         pic->picture_display_extension_flag[0] = 0;
         pic->picture_display_extension_flag[1] = 0;
-        pic->sequence_header_flag = 0;      
-	pic->gop_flag = 0;              
-        pic->sequence_end_flag = 0;	
+        pic->sequence_header_flag = 0;
+	pic->gop_flag = 0;
+        pic->sequence_end_flag = 0;
 }
 #endif
 
@@ -553,7 +553,7 @@ static void init_mpg_picture( struct mpg
 }
 #endif
 
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, 
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
 			    dvb_filter_pes2ts_cb_t *cb, void *priv)
 {
 	unsigned char *buf=p2ts->buf;
@@ -572,11 +572,11 @@ int dvb_filter_pes2ts(struct dvb_filter_
 {
 	unsigned char *buf=p2ts->buf;
 	int ret=0, rest;
-	
+
 	//len=6+((pes[4]<<8)|pes[5]);
 
 	if (payload_start)
-	buf[1]|=0x40;
+		buf[1]|=0x40;
 	else
 		buf[1]&=~0x40;
 	while (len>=184) {
@@ -601,4 +601,3 @@ int dvb_filter_pes2ts(struct dvb_filter_
 	return p2ts->cb(p2ts->priv, buf);
 }
 EXPORT_SYMBOL(dvb_filter_pes2ts);
-
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.h b/drivers/media/dvb/dvb-core/dvb_filter.h
--- a/drivers/media/dvb/dvb-core/dvb_filter.h
+++ b/drivers/media/dvb/dvb-core/dvb_filter.h
@@ -34,8 +34,8 @@ struct dvb_filter_pes2ts {
 	void *priv;
 };
 
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, 
-		 	    dvb_filter_pes2ts_cb_t *cb, void *priv);
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
+			    dvb_filter_pes2ts_cb_t *cb, void *priv);
 
 int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
 		      int len, int payload_start);
@@ -70,8 +70,8 @@ int dvb_filter_pes2ts(struct dvb_filter_
 #define QUANT_MATRIX_EXTENSION       0x03
 #define PICTURE_DISPLAY_EXTENSION    0x07
 
-#define I_FRAME 0x01 
-#define B_FRAME 0x02 
+#define I_FRAME 0x01
+#define B_FRAME 0x02
 #define P_FRAME 0x03
 
 /* Initialize sequence_data */
@@ -92,7 +92,7 @@ int dvb_filter_pes2ts(struct dvb_filter_
 #define PES_CRC_FLAG     0x02
 #define PES_EXT_FLAG     0x01
 
-//pts_dts flags 
+//pts_dts flags
 #define PTS_ONLY         0x80
 #define PTS_DTS          0xC0
 
@@ -165,7 +165,7 @@ struct dvb_video_info {
         s16 vbv_delay;
 	u32 CSPF;
 	u32 off;
-};            
+};
 
 #define OFF_SIZE 4
 #define FIRST_FIELD 0
@@ -181,10 +181,10 @@ struct mpg_picture {
         int       low_delay;
         int       closed_gop;
         int       broken_link;
-        int       sequence_header_flag;      
-        int       gop_flag;              
+        int       sequence_header_flag;
+        int       gop_flag;
         int       sequence_end_flag;
-                                                                
+
         u8        profile_and_level;
         s32       picture_coding_parameter;
         u32       matrix[32];
@@ -211,26 +211,26 @@ struct mpg_picture {
         int       forward_bank;
         int       backward_bank;
         int       compress;
-        s16       frame_centre_horizontal_offset[OFF_SIZE];                   
+        s16       frame_centre_horizontal_offset[OFF_SIZE];
                   /* [0-2] 1st field, [3] 2nd field */
         s16       frame_centre_vertical_offset[OFF_SIZE];
                   /* [0-2] 1st field, [3] 2nd field */
-        s16       temporal_reference[2];                               
+        s16       temporal_reference[2];
                   /* [0] 1st field, [1] 2nd field */
 
         s8        picture_coding_type[2];
-                 /* [0] 1st field, [1] 2nd field */
+                  /* [0] 1st field, [1] 2nd field */
         s8        picture_structure[2];
-                 /* [0] 1st field, [1] 2nd field */
+                  /* [0] 1st field, [1] 2nd field */
         s8        picture_display_extension_flag[2];
-                 /* [0] 1st field, [1] 2nd field */
-                 /* picture_display_extenion() 0:no 1:exit*/
+                  /* [0] 1st field, [1] 2nd field */
+                  /* picture_display_extenion() 0:no 1:exit*/
         s8        pts_flag[2];
-                 /* [0] 1st field, [1] 2nd field */
+                  /* [0] 1st field, [1] 2nd field */
 };
 
 struct dvb_audio_info {
-	int layer               ;
+	int layer;
 	u32 bit_rate;
 	u32 frequency;
 	u32 mode;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -3,9 +3,9 @@
  *
  *
  * Copyright (C) 1999-2001 Ralph  Metzler
- *                         Marcus Metzler
- *                         Holger Waechtler 
- *                                    for convergence integrated media GmbH
+ *			   Marcus Metzler
+ *			   Holger Waechtler
+ *				      for convergence integrated media GmbH
  *
  * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
  *
@@ -16,7 +16,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
@@ -48,7 +48,7 @@ static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
 
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
-MODULE_PARM_DESC(dvb_frontend_debug, "Turn on/off frontend core debugging (default:off).");
+MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
 module_param(dvb_shutdown_timeout, int, 0444);
 MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
 module_param(dvb_force_auto_inversion, int, 0444);
@@ -117,7 +117,7 @@ struct dvb_frontend_private {
 
 static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct dvb_fe_events *events = &fepriv->events;
 	struct dvb_frontend_event *e;
 	int wp;
@@ -155,45 +155,45 @@ static void dvb_frontend_add_event(struc
 static int dvb_frontend_get_event(struct dvb_frontend *fe,
 			    struct dvb_frontend_event *event, int flags)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct dvb_fe_events *events = &fepriv->events;
 
 	dprintk ("%s\n", __FUNCTION__);
 
 	if (events->overflow) {
-                events->overflow = 0;
-                return -EOVERFLOW;
-        }
+		events->overflow = 0;
+		return -EOVERFLOW;
+	}
 
-        if (events->eventw == events->eventr) {
+	if (events->eventw == events->eventr) {
 		int ret;
 
-                if (flags & O_NONBLOCK)
-                        return -EWOULDBLOCK;
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
 
 		up(&fepriv->sem);
 
-                ret = wait_event_interruptible (events->wait_queue,
-                                                events->eventw != events->eventr);
+		ret = wait_event_interruptible (events->wait_queue,
+						events->eventw != events->eventr);
 
 		if (down_interruptible (&fepriv->sem))
 			return -ERESTARTSYS;
 
-                if (ret < 0)
-                        return ret;
-        }
+		if (ret < 0)
+			return ret;
+	}
 
-        if (down_interruptible (&events->sem))
+	if (down_interruptible (&events->sem))
 		return -ERESTARTSYS;
 
-       	memcpy (event, &events->events[events->eventr],
+	memcpy (event, &events->events[events->eventr],
 		sizeof(struct dvb_frontend_event));
 
-        events->eventr = (events->eventr + 1) % MAX_EVENT;
+	events->eventr = (events->eventr + 1) % MAX_EVENT;
 
-       	up (&events->sem);
+	up (&events->sem);
 
-        return 0;
+	return 0;
 }
 
 static void dvb_frontend_init(struct dvb_frontend *fe)
@@ -206,26 +206,26 @@ static void dvb_frontend_init(struct dvb
 		fe->ops->init(fe);
 }
 
-static void update_delay (int *quality, int *delay, int min_delay, int locked)
+static void update_delay(int *quality, int *delay, int min_delay, int locked)
 {
-	int q2;
+	    int q2;
 
-	dprintk ("%s\n", __FUNCTION__);
+	    dprintk ("%s\n", __FUNCTION__);
 
-	if (locked)
-		(*quality) = (*quality * 220 + 36*256) / 256;
-	else
-		(*quality) = (*quality * 220 + 0) / 256;
+	    if (locked)
+		      (*quality) = (*quality * 220 + 36*256) / 256;
+	    else
+		      (*quality) = (*quality * 220 + 0) / 256;
 
-	q2 = *quality - 128;
-	q2 *= q2;
+	    q2 = *quality - 128;
+	    q2 *= q2;
 
 	    *delay = min_delay + q2 * HZ / (128*128);
 }
 
 /**
  * Performs automatic twiddling of frontend parameters.
- * 
+ *
  * @param fe The frontend concerned.
  * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
  * @returns Number of complete iterations that have been performed.
@@ -234,7 +234,7 @@ static int dvb_frontend_autotune(struct 
 {
 	int autoinversion;
 	int ready = 0;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int original_inversion = fepriv->parameters.inversion;
 	u32 original_frequency = fepriv->parameters.frequency;
 
@@ -270,26 +270,26 @@ static int dvb_frontend_autotune(struct 
 
 		case 2:
 			if (fepriv->lnb_drift == 0) break;
-		    
+
 			fepriv->lnb_drift = -fepriv->lnb_drift;
 			ready = 1;
 			break;
-	    
+
 		case 3:
 			if (fepriv->lnb_drift == 0) break;
 			if (!autoinversion) break;
-		    
+
 			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
 			fepriv->lnb_drift = -fepriv->lnb_drift;
 			ready = 1;
 			break;
-		    
+
 		default:
 			fepriv->auto_step++;
 			fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
 			break;
 		}
-	    
+
 		if (!ready) fepriv->auto_sub_step++;
 	}
 
@@ -298,13 +298,13 @@ static int dvb_frontend_autotune(struct 
 	if ((fepriv->auto_step == fepriv->started_auto_step) &&
 	    (fepriv->auto_sub_step == 0) && check_wrapped) {
 		return 1;
-		}
+	}
 
 	dprintk("%s: drift:%i inversion:%i auto_step:%i "
 		"auto_sub_step:%i started_auto_step:%i\n",
 		__FUNCTION__, fepriv->lnb_drift, fepriv->inversion,
 		fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
-    
+
 	/* set the frontend itself */
 	fepriv->parameters.frequency += fepriv->lnb_drift;
 	if (autoinversion)
@@ -321,7 +321,7 @@ static int dvb_frontend_autotune(struct 
 
 static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	if (fepriv->exit)
 		return 1;
@@ -335,7 +335,7 @@ static int dvb_frontend_is_exiting(struc
 
 static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	if (fepriv->wakeup) {
 		fepriv->wakeup = 0;
@@ -346,7 +346,7 @@ static int dvb_frontend_should_wakeup(st
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	fepriv->wakeup = 1;
 	wake_up_interruptible(&fepriv->wait_queue);
@@ -355,27 +355,27 @@ static void dvb_frontend_wakeup(struct d
 /*
  * FIXME: use linux/kthread.h
  */
-static int dvb_frontend_thread (void *data)
+static int dvb_frontend_thread(void *data)
 {
-	struct dvb_frontend *fe = (struct dvb_frontend *) data;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend *fe = data;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	unsigned long timeout;
 	char name [15];
 	int quality = 0, delay = 3*HZ;
 	fe_status_t s;
 	int check_wrapped = 0;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk("%s\n", __FUNCTION__);
 
 	snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
 
-        lock_kernel ();
-        daemonize (name);
-        sigfillset (&current->blocked);
-        unlock_kernel ();
+        lock_kernel();
+        daemonize(name);
+        sigfillset(&current->blocked);
+        unlock_kernel();
 
 	fepriv->status = 0;
-	dvb_frontend_init (fe);
+	dvb_frontend_init(fe);
 	fepriv->wakeup = 0;
 
 	while (1) {
@@ -384,7 +384,7 @@ static int dvb_frontend_thread (void *da
 		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
 							   dvb_frontend_should_wakeup(fe),
 							   delay);
-		if (0 != dvb_frontend_is_exiting (fe)) {
+		if (0 != dvb_frontend_is_exiting(fe)) {
 			/* got signal or quitting */
 			break;
 		}
@@ -409,7 +409,7 @@ static int dvb_frontend_thread (void *da
 			if (fe->ops->read_status)
 				fe->ops->read_status(fe, &s);
 			if (s != fepriv->status) {
-			dvb_frontend_add_event (fe, s);
+				dvb_frontend_add_event(fe, s);
 				fepriv->status = s;
 			}
 		}
@@ -447,16 +447,16 @@ static int dvb_frontend_thread (void *da
 		if ((fepriv->state & FESTATE_LOSTLOCK) &&
 		    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
 			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-						continue;
-				}
-	    
+			continue;
+		}
+
 		/* don't do anything if we're in the DISEQC state, since this
 		 * might be someone with a motorized dish controlled by DISEQC.
 		 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
 		if (fepriv->state & FESTATE_DISEQC) {
 			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
 			continue;
-				}
+		}
 
 		/* if we're in the RETUNE state, set everything up for a brand
 		 * new scan, keeping the current inversion setting, as the next
@@ -495,7 +495,7 @@ static int dvb_frontend_thread (void *da
 		/* slow zigzag */
 		if (fepriv->state & FESTATE_SEARCHING_SLOW) {
 			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-		    
+
 			/* Note: don't bother checking for wrapping; we stay in this
 			 * state until we get a lock */
 			dvb_frontend_autotune(fe, 0);
@@ -520,7 +520,7 @@ static int dvb_frontend_thread (void *da
 static void dvb_frontend_stop(struct dvb_frontend *fe)
 {
 	unsigned long ret;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -559,7 +559,7 @@ static void dvb_frontend_stop(struct dvb
 static int dvb_frontend_start(struct dvb_frontend *fe)
 {
 	int ret;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -567,7 +567,7 @@ static int dvb_frontend_start(struct dvb
 		if (!fepriv->exit)
 			return 0;
 		else
-		dvb_frontend_stop (fe);
+			dvb_frontend_stop (fe);
 	}
 
 	if (signal_pending(current))
@@ -592,13 +592,12 @@ static int dvb_frontend_start(struct dvb
 	return 0;
 }
 
-
-static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, void *parg)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int err = -EOPNOTSUPP;
 
 	dprintk ("%s\n", __FUNCTION__);
@@ -616,7 +615,7 @@ static int dvb_frontend_ioctl (struct in
 
 	switch (cmd) {
 	case FE_GET_INFO: {
-		struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg;
+		struct dvb_frontend_info* info = parg;
 		memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
@@ -712,14 +711,14 @@ static int dvb_frontend_ioctl (struct in
 
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
-	    
+
 		memcpy (&fepriv->parameters, parg,
 			sizeof (struct dvb_frontend_parameters));
 
 		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
 		memcpy(&fetunesettings.parameters, parg,
 		       sizeof (struct dvb_frontend_parameters));
-		    
+
 		/* force auto frequency inversion if requested */
 		if (dvb_force_auto_inversion) {
 			fepriv->parameters.inversion = INVERSION_AUTO;
@@ -745,14 +744,14 @@ static int dvb_frontend_ioctl (struct in
 				fepriv->min_delay = HZ/20;
 				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
 				fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
-		break;
-			    
+				break;
+
 			case FE_QAM:
 				fepriv->min_delay = HZ/20;
 				fepriv->step_size = 0; /* no zigzag */
 				fepriv->max_drift = 0;
 				break;
-			    
+
 			case FE_OFDM:
 				fepriv->min_delay = HZ/20;
 				fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
@@ -768,7 +767,7 @@ static int dvb_frontend_ioctl (struct in
 
 		fepriv->state = FESTATE_RETUNE;
 		dvb_frontend_wakeup(fe);
-		dvb_frontend_add_event (fe, 0);	    
+		dvb_frontend_add_event(fe, 0);
 		fepriv->status = 0;
 		err = 0;
 		break;
@@ -790,12 +789,11 @@ static int dvb_frontend_ioctl (struct in
 	return err;
 }
 
-
-static unsigned int dvb_frontend_poll (struct file *file, struct poll_table_struct *wait)
+static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -807,12 +805,11 @@ static unsigned int dvb_frontend_poll (s
 	return 0;
 }
 
-
-static int dvb_frontend_open (struct inode *inode, struct file *file)
+static int dvb_frontend_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int ret;
 
 	dprintk ("%s\n", __FUNCTION__);
@@ -828,16 +825,15 @@ static int dvb_frontend_open (struct ino
 		/*  empty event queue */
 		fepriv->events.eventr = fepriv->events.eventw = 0;
 	}
-	
+
 	return ret;
 }
 
-
-static int dvb_frontend_release (struct inode *inode, struct file *file)
+static int dvb_frontend_release(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -847,7 +843,6 @@ static int dvb_frontend_release (struct 
 	return dvb_generic_release (inode, file);
 }
 
-
 static struct file_operations dvb_frontend_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= dvb_generic_ioctl,
@@ -878,7 +873,7 @@ int dvb_register_frontend(struct dvb_ada
 		up(&frontend_mutex);
 		return -ENOMEM;
 	}
-	fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	fepriv = fe->frontend_priv;
 	memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private));
 
 	init_MUTEX (&fepriv->sem);
@@ -902,19 +897,18 @@ EXPORT_SYMBOL(dvb_register_frontend);
 
 int dvb_unregister_frontend(struct dvb_frontend* fe)
 {
-	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	dprintk ("%s\n", __FUNCTION__);
 
 	down (&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
-			dvb_frontend_stop (fe);
+	dvb_frontend_stop (fe);
 	if (fe->ops->release)
 		fe->ops->release(fe);
 	else
 		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
 	/* fe is invalid now */
-	if (fepriv)
-		kfree(fepriv);
+	kfree(fepriv);
 	up (&frontend_mutex);
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvb_frontend.h
  *
  * Copyright (C) 2001 convergence integrated media GmbH
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvb_net.c
  *
  * Copyright (C) 2001 Convergence integrated media GmbH
@@ -9,8 +9,8 @@
  * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH.
  *                      and Department of Scientific Computing
  *                          Paris Lodron University of Salzburg.
- *                    Hilmar Linder <hlinder@cosy.sbg.ac.at>
- *                and Wolfram Stering <wstering@cosy.sbg.ac.at>
+ *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
+ *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
  *
  * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
  *
@@ -18,12 +18,12 @@
  * 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.
@@ -122,10 +122,10 @@ static void hexdump( const unsigned char
 
 struct dvb_net_priv {
 	int in_use;
-        struct net_device_stats stats;
+	struct net_device_stats stats;
 	u16 pid;
 	struct dvb_net *host;
-        struct dmx_demux *demux;
+	struct dmx_demux *demux;
 	struct dmx_section_feed *secfeed;
 	struct dmx_section_filter *secfilter;
 	struct dmx_ts_feed *tsfeed;
@@ -156,7 +156,7 @@ struct dvb_net_priv {
 
 
 /**
- *	Determine the packet's protocol ID. The rule here is that we 
+ *	Determine the packet's protocol ID. The rule here is that we
  *	assume 802.3 if the type field is short enough to be a length.
  *	This is normal practice and works for any 'now in use' protocol.
  *
@@ -168,7 +168,7 @@ static unsigned short dvb_net_eth_type_t
 {
 	struct ethhdr *eth;
 	unsigned char *rawp;
-	
+
 	skb->mac.raw=skb->data;
 	skb_pull(skb,dev->hard_header_len);
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)
@@ -176,19 +176,19 @@ static unsigned short dvb_net_eth_type_t
 #else
 	eth = eth_hdr(skb);
 #endif
-	
+
 	if (*eth->h_dest & 1) {
 		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
 			skb->pkt_type=PACKET_BROADCAST;
 		else
 			skb->pkt_type=PACKET_MULTICAST;
 	}
-	
+
 	if (ntohs(eth->h_proto) >= 1536)
 		return eth->h_proto;
-		
+
 	rawp = skb->data;
-	
+
 	/**
 	 *	This is a magic hack to spot IPX packets. Older Novell breaks
 	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC
@@ -197,7 +197,7 @@ static unsigned short dvb_net_eth_type_t
 	 */
 	if (*(unsigned short *)rawp == 0xFFFF)
 		return htons(ETH_P_802_3);
-		
+
 	/**
 	 *	Real 802.2 LLC
 	 */
@@ -217,12 +217,12 @@ static unsigned short dvb_net_eth_type_t
 #define ULE_TEST	0
 #define ULE_BRIDGED	1
 
-int ule_test_sndu( struct dvb_net_priv *p )
+static int ule_test_sndu( struct dvb_net_priv *p )
 {
 	return -1;
 }
 
-int ule_bridged_sndu( struct dvb_net_priv *p )
+static int ule_bridged_sndu( struct dvb_net_priv *p )
 {
 	/* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
 	 * This has to be the last extension header, otherwise it won't work.
@@ -236,7 +236,7 @@ int ule_bridged_sndu( struct dvb_net_pri
 /** Handle ULE extension headers.
  *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
  *  Returns: >= 0: nr. of bytes consumed by next extension header
- *  	     -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
+ *	     -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
  */
 static int handle_one_ule_extension( struct dvb_net_priv *p )
 {
@@ -315,7 +315,7 @@ static inline void reset_ule( struct dvb
  */
 static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv *)dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 	unsigned long skipped = 0L;
 	u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
 	struct ethhdr *ethh = NULL;
@@ -345,7 +345,7 @@ static void dvb_net_ule( struct net_devi
 			if (ule_dump) {
 				hexdump( ule_where, TS_SZ );
 				ule_dump = 0;
-		}
+			}
 			ule_where += TS_SZ;
 #endif
 
@@ -586,9 +586,9 @@ static void dvb_net_ule( struct net_devi
 
 			ule_crc = iov_crc32(ule_crc, iov, 3);
 			expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 |
-				*((u8 *)priv->ule_skb->tail - 3) << 16 |
-				*((u8 *)priv->ule_skb->tail - 2) << 8 |
-				*((u8 *)priv->ule_skb->tail - 1);
+				       *((u8 *)priv->ule_skb->tail - 3) << 16 |
+				       *((u8 *)priv->ule_skb->tail - 2) << 8 |
+				       *((u8 *)priv->ule_skb->tail - 1);
 			if (ule_crc != expected_crc) {
 				printk(KERN_WARNING "%lu: CRC32 check FAILED: %#lx / %#lx, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
 				       priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
@@ -709,7 +709,7 @@ static int dvb_net_ts_callback(const u8 
 			       const u8 *buffer2, size_t buffer2_len,
 			       struct dmx_ts_feed *feed, enum dmx_success success)
 {
-	struct net_device *dev = (struct net_device *)feed->priv;
+	struct net_device *dev = feed->priv;
 
 	if (buffer2 != 0)
 		printk(KERN_WARNING "buffer2 not 0: %p.\n", buffer2);
@@ -727,6 +727,7 @@ static void dvb_net_sec(struct net_devic
         u8 *eth;
         struct sk_buff *skb;
 	struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats);
+	int snap = 0;
 
 	/* note: pkt_len includes a 32bit checksum */
 	if (pkt_len < 16) {
@@ -750,9 +751,12 @@ static void dvb_net_sec(struct net_devic
 		return;
 	}
 	if (pkt[5] & 0x02) {
-		//FIXME: handle LLC/SNAP
-                stats->rx_dropped++;
-                return;
+		/* handle LLC/SNAP, see rfc-1042 */
+		if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) {
+			stats->rx_dropped++;
+			return;
+		}
+		snap = 8;
         }
 	if (pkt[7]) {
 		/* FIXME: assemble datagram from multiple sections */
@@ -762,9 +766,9 @@ static void dvb_net_sec(struct net_devic
 	}
 
 	/* we have 14 byte ethernet header (ip header follows);
-	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment
+	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
 	 */
-	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2))) {
+	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
 		//printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
 		stats->rx_dropped++;
 		return;
@@ -773,8 +777,8 @@ static void dvb_net_sec(struct net_devic
 	skb->dev = dev;
 
 	/* copy L3 payload */
-	eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14);
-	memcpy(eth + 14, pkt + 12, pkt_len - 12 - 4);
+	eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap);
+	memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap);
 
 	/* create ethernet header: */
         eth[0]=pkt[0x0b];
@@ -786,22 +790,35 @@ static void dvb_net_sec(struct net_devic
 
         eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
 
-	eth[12] = 0x08;	/* ETH_P_IP */
-	eth[13] = 0x00;
+	if (snap) {
+		eth[12] = pkt[18];
+		eth[13] = pkt[19];
+	} else {
+		/* protocol numbers are from rfc-1700 or
+		 * http://www.iana.org/assignments/ethernet-numbers
+		 */
+		if (pkt[12] >> 4 == 6) { /* version field from IP header */
+			eth[12] = 0x86;	/* IPv6 */
+			eth[13] = 0xdd;
+		} else {
+			eth[12] = 0x08;	/* IPv4 */
+			eth[13] = 0x00;
+		}
+	}
 
 	skb->protocol = dvb_net_eth_type_trans(skb, dev);
-        
+
 	stats->rx_packets++;
 	stats->rx_bytes+=skb->len;
         netif_rx(skb);
 }
- 
+
 static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
 		 const u8 *buffer2, size_t buffer2_len,
 		 struct dmx_section_filter *filter,
 		 enum dmx_success success)
 {
-        struct net_device *dev=(struct net_device *) filter->priv;
+        struct net_device *dev = filter->priv;
 
 	/**
 	 * we rely on the DVB API definition where exactly one complete
@@ -826,7 +843,7 @@ static int dvb_net_filter_sec_set(struct
 		   struct dmx_section_filter **secfilter,
 		   u8 *mac, u8 *mac_mask)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 	int ret;
 
 	*secfilter=NULL;
@@ -870,10 +887,10 @@ static int dvb_net_filter_sec_set(struct
 static int dvb_net_feed_start(struct net_device *dev)
 {
 	int ret, i;
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
         struct dmx_demux *demux = priv->demux;
         unsigned char *mac = (unsigned char *) dev->dev_addr;
-		
+
 	dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 		printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
@@ -883,51 +900,51 @@ static int dvb_net_feed_start(struct net
 	priv->tsfeed = NULL;
 
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-	dprintk("%s: alloc secfeed\n", __FUNCTION__);
-	ret=demux->allocate_section_feed(demux, &priv->secfeed, 
+		dprintk("%s: alloc secfeed\n", __FUNCTION__);
+		ret=demux->allocate_section_feed(demux, &priv->secfeed,
 					 dvb_net_sec_callback);
-	if (ret<0) {
-		printk("%s: could not allocate section feed\n", dev->name);
-		return ret;
-	}
+		if (ret<0) {
+			printk("%s: could not allocate section feed\n", dev->name);
+			return ret;
+		}
 
-	ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1);
+		ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1);
 
-	if (ret<0) {
-		printk("%s: could not set section feed\n", dev->name);
-		priv->demux->release_section_feed(priv->demux, priv->secfeed);
-		priv->secfeed=NULL;
-		return ret;
-	}
+		if (ret<0) {
+			printk("%s: could not set section feed\n", dev->name);
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed=NULL;
+			return ret;
+		}
 
-	if (priv->rx_mode != RX_MODE_PROMISC) {
-		dprintk("%s: set secfilter\n", __FUNCTION__);
+		if (priv->rx_mode != RX_MODE_PROMISC) {
+			dprintk("%s: set secfilter\n", __FUNCTION__);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
-	}
+		}
 
-	switch (priv->rx_mode) {
-	case RX_MODE_MULTI:
-		for (i = 0; i < priv->multi_num; i++) {
-			dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
+		switch (priv->rx_mode) {
+		case RX_MODE_MULTI:
+			for (i = 0; i < priv->multi_num; i++) {
+				dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
 				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
-					   priv->multi_macs[i], mask_normal);
-		}
-		break;
-	case RX_MODE_ALL_MULTI:
-		priv->multi_num=1;
-		dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
+						       priv->multi_macs[i], mask_normal);
+			}
+			break;
+		case RX_MODE_ALL_MULTI:
+			priv->multi_num=1;
+			dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
 			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
-				   mac_allmulti, mask_allmulti);
-		break;
-	case RX_MODE_PROMISC:
-		priv->multi_num=0;
-		dprintk("%s: set secfilter\n", __FUNCTION__);
+					       mac_allmulti, mask_allmulti);
+			break;
+		case RX_MODE_PROMISC:
+			priv->multi_num=0;
+			dprintk("%s: set secfilter\n", __FUNCTION__);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
-		break;
-	}
-	
-	dprintk("%s: start filtering\n", __FUNCTION__);
-	priv->secfeed->start_filtering(priv->secfeed);
+			break;
+		}
+
+		dprintk("%s: start filtering\n", __FUNCTION__);
+		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		struct timespec timeout = { 0, 30000000 }; // 30 msec
 
@@ -965,38 +982,38 @@ static int dvb_net_feed_start(struct net
 
 static int dvb_net_feed_stop(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 	int i;
 
 	dprintk("%s\n", __FUNCTION__);
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-        if (priv->secfeed) {
-		if (priv->secfeed->is_filtering) {
-			dprintk("%s: stop secfeed\n", __FUNCTION__);
-		        priv->secfeed->stop_filtering(priv->secfeed);
-		}
+		if (priv->secfeed) {
+			if (priv->secfeed->is_filtering) {
+				dprintk("%s: stop secfeed\n", __FUNCTION__);
+				priv->secfeed->stop_filtering(priv->secfeed);
+			}
 
-		if (priv->secfilter) {
-			dprintk("%s: release secfilter\n", __FUNCTION__);
-			priv->secfeed->release_filter(priv->secfeed,
-					       priv->secfilter);
-		priv->secfilter=NULL;
-		}
+			if (priv->secfilter) {
+				dprintk("%s: release secfilter\n", __FUNCTION__);
+				priv->secfeed->release_filter(priv->secfeed,
+							      priv->secfilter);
+				priv->secfilter=NULL;
+			}
 
-		for (i=0; i<priv->multi_num; i++) {
-			if (priv->multi_secfilter[i]) {
+			for (i=0; i<priv->multi_num; i++) {
+				if (priv->multi_secfilter[i]) {
 					dprintk("%s: release multi_filter[%d]\n",
 						__FUNCTION__, i);
-				priv->secfeed->release_filter(priv->secfeed,
-						       priv->multi_secfilter[i]);
-			priv->multi_secfilter[i]=NULL;
-		}
-		}
+					priv->secfeed->release_filter(priv->secfeed,
+								      priv->multi_secfilter[i]);
+					priv->multi_secfilter[i] = NULL;
+				}
+			}
 
-		priv->demux->release_section_feed(priv->demux, priv->secfeed);
-		priv->secfeed=NULL;
-	} else
-		printk("%s: no feed to stop\n", dev->name);
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed = NULL;
+		} else
+			printk("%s: no feed to stop\n", dev->name);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		if (priv->tsfeed) {
 			if (priv->tsfeed->is_filtering) {
@@ -1016,7 +1033,7 @@ static int dvb_net_feed_stop(struct net_
 
 static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 
 	if (priv->multi_num == DVB_NET_MULTICAST_MAX)
 		return -ENOMEM;
@@ -1031,13 +1048,13 @@ static int dvb_set_mc_filter (struct net
 static void wq_set_multicast_list (void *data)
 {
 	struct net_device *dev = data;
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 
 	dvb_net_feed_stop(dev);
 
 	priv->rx_mode = RX_MODE_UNI;
-	
-	if(dev->flags & IFF_PROMISC) {
+
+	if (dev->flags & IFF_PROMISC) {
 		dprintk("%s: promiscuous mode\n", dev->name);
 		priv->rx_mode = RX_MODE_PROMISC;
 	} else if ((dev->flags & IFF_ALLMULTI)) {
@@ -1053,20 +1070,20 @@ static void wq_set_multicast_list (void 
 		priv->rx_mode = RX_MODE_MULTI;
 		priv->multi_num = 0;
 
-		for (mci = 0, mc=dev->mc_list; 
+		for (mci = 0, mc=dev->mc_list;
 		     mci < dev->mc_count;
 		     mc = mc->next, mci++) {
 			dvb_set_mc_filter(dev, mc);
 		}
 	}
 
-		dvb_net_feed_start(dev);
-	}
+	dvb_net_feed_start(dev);
+}
 
 
 static void dvb_net_set_multicast_list (struct net_device *dev)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 	schedule_work(&priv->set_multicast_list_wq);
 }
 
@@ -1084,7 +1101,7 @@ static void wq_restart_net_feed (void *d
 
 static int dvb_net_set_mac (struct net_device *dev, void *p)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 	struct sockaddr *addr=p;
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1098,7 +1115,7 @@ static int dvb_net_set_mac (struct net_d
 
 static int dvb_net_open(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 
 	priv->in_use++;
 	dvb_net_feed_start(dev);
@@ -1108,7 +1125,7 @@ static int dvb_net_open(struct net_devic
 
 static int dvb_net_stop(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+	struct dvb_net_priv *priv = dev->priv;
 
 	priv->in_use--;
         return dvb_net_feed_stop(dev);
@@ -1119,7 +1136,6 @@ static struct net_device_stats * dvb_net
         return &((struct dvb_net_priv*) dev->priv)->stats;
 }
 
-
 static void dvb_net_setup(struct net_device *dev)
 {
 	ether_setup(dev);
@@ -1133,7 +1149,6 @@ static void dvb_net_setup(struct net_dev
 	dev->mtu		= 4096;
 	dev->mc_count           = 0;
 	dev->hard_header_cache  = NULL;
-
 	dev->flags |= IFF_NOARP;
 }
 
@@ -1154,11 +1169,11 @@ static int get_if(struct dvb_net *dvbnet
 
 static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
 {
-        struct net_device *net;
+	struct net_device *net;
 	struct dvb_net_priv *priv;
 	int result;
 	int if_num;
- 
+
 	if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
 		return -EINVAL;
 	if ((if_num = get_if(dvbnet)) < 0)
@@ -1167,7 +1182,7 @@ static int dvb_net_add_if(struct dvb_net
 	net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
 	if (!net)
 		return -ENOMEM;
-	
+
 	if (dvbnet->dvbdev->id)
 		snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
 			 dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
@@ -1176,14 +1191,14 @@ static int dvb_net_add_if(struct dvb_net
 		snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
 			 dvbnet->dvbdev->adapter->num, if_num);
 
-	net->addr_len  		= 6;
+	net->addr_len = 6;
 	memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
 
 	dvbnet->device[if_num] = net;
-	
+
 	priv = net->priv;
-        priv->demux = dvbnet->demux;
-        priv->pid = pid;
+	priv->demux = dvbnet->demux;
+	priv->pid = pid;
 	priv->rx_mode = RX_MODE_UNI;
 	priv->need_pusi = 1;
 	priv->tscc = 0;
@@ -1193,8 +1208,8 @@ static int dvb_net_add_if(struct dvb_net
 	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
 	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
 
-        net->base_addr = pid;
-                
+	net->base_addr = pid;
+
 	if ((result = register_netdev(net)) < 0) {
 		dvbnet->device[if_num] = NULL;
 		free_netdev(net);
@@ -1202,10 +1217,9 @@ static int dvb_net_add_if(struct dvb_net
 	}
 	printk("dvb_net: created network interface %s\n", net->name);
 
-        return if_num;
+	return if_num;
 }
 
-
 static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
 {
 	struct net_device *net = dvbnet->device[num];
@@ -1220,7 +1234,7 @@ static int dvb_net_remove_if(struct dvb_
 	dvb_net_stop(net);
 	flush_scheduled_work();
 	printk("dvb_net: removed network interface %s\n", net->name);
-        unregister_netdev(net);
+	unregister_netdev(net);
 	dvbnet->state[num]=0;
 	dvbnet->device[num] = NULL;
 	free_netdev(net);
@@ -1228,22 +1242,21 @@ static int dvb_net_remove_if(struct dvb_
 	return 0;
 }
 
-
 static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
 		  unsigned int cmd, void *parg)
 {
-	struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-	struct dvb_net *dvbnet = (struct dvb_net *) dvbdev->priv;
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_net *dvbnet = dvbdev->priv;
 
 	if (((file->f_flags&O_ACCMODE)==O_RDONLY))
 		return -EPERM;
-	
+
 	switch (cmd) {
 	case NET_ADD_IF:
 	{
-		struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;
+		struct dvb_net_if *dvbnetif = parg;
 		int result;
-		
+
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 
@@ -1262,14 +1275,15 @@ static int dvb_net_do_ioctl(struct inode
 	{
 		struct net_device *netdev;
 		struct dvb_net_priv *priv_data;
-		struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;
+		struct dvb_net_if *dvbnetif = parg;
 
 		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
 		    !dvbnet->state[dvbnetif->if_num])
 			return -EINVAL;
 
 		netdev = dvbnet->device[dvbnetif->if_num];
-		priv_data=(struct dvb_net_priv*)netdev->priv;
+
+		priv_data = netdev->priv;
 		dvbnetif->pid=priv_data->pid;
 		dvbnetif->feedtype=priv_data->feedtype;
 		break;
@@ -1291,7 +1305,7 @@ static int dvb_net_do_ioctl(struct inode
 	/* binary compatiblity cruft */
 	case __NET_ADD_IF_OLD:
 	{
-		struct __dvb_net_if_old *dvbnetif=(struct __dvb_net_if_old *)parg;
+		struct __dvb_net_if_old *dvbnetif = parg;
 		int result;
 
 		if (!capable(CAP_SYS_ADMIN))
@@ -1312,14 +1326,15 @@ static int dvb_net_do_ioctl(struct inode
 	{
 		struct net_device *netdev;
 		struct dvb_net_priv *priv_data;
-		struct __dvb_net_if_old *dvbnetif=(struct __dvb_net_if_old *)parg;
+		struct __dvb_net_if_old *dvbnetif = parg;
 
 		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
 		    !dvbnet->state[dvbnetif->if_num])
-		return -EINVAL;
+			return -EINVAL;
 
 		netdev = dvbnet->device[dvbnetif->if_num];
-		priv_data=(struct dvb_net_priv*)netdev->priv;
+
+		priv_data = netdev->priv;
 		dvbnetif->pid=priv_data->pid;
 		break;
 	}
@@ -1369,7 +1384,7 @@ int dvb_net_init (struct dvb_adapter *ad
 		  struct dmx_demux *dmx)
 {
 	int i;
-		
+
 	dvbnet->demux = dmx;
 
 	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/drivers/media/dvb/dvb-core/dvb_net.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvb_net.h
  *
  * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
@@ -44,4 +44,3 @@ void dvb_net_release(struct dvb_net *);
 int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
 
 #endif
-
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -2,9 +2,9 @@
  *
  * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
  *
- * Copyright (C) 2003 Oliver Endriss 
+ * Copyright (C) 2003 Oliver Endriss
  * Copyright (C) 2004 Andrew de Quincey
- * 
+ *
  * based on code originally found in av7110.c & dvb_ci.c:
  * Copyright (C) 1999-2003 Ralph  Metzler
  *                       & Marcus Metzler for convergence integrated media GmbH
@@ -13,7 +13,7 @@
  * 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.
- * 
+ *
  * 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
@@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ring
 ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
 {
         ssize_t free;
-  
+
         free = rbuf->pread - rbuf->pwrite;
         if (free <= 0)
                 free += rbuf->size;
@@ -75,7 +75,7 @@ ssize_t dvb_ringbuffer_free(struct dvb_r
 ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
 {
         ssize_t avail;
-  
+
         avail = rbuf->pwrite - rbuf->pread;
         if (avail < 0)
                 avail += rbuf->size;
@@ -137,19 +137,19 @@ ssize_t dvb_ringbuffer_write(struct dvb_
 {
         size_t todo = len;
         size_t split;
-    
+
         split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
 
         if (split > 0) {
-		memcpy(rbuf->data+rbuf->pwrite, buf, split);
+                memcpy(rbuf->data+rbuf->pwrite, buf, split);
                 buf += split;
                 todo -= split;
                 rbuf->pwrite = 0;
         }
-	memcpy(rbuf->data+rbuf->pwrite, buf, todo);
+        memcpy(rbuf->data+rbuf->pwrite, buf, todo);
         rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
 
-	return len;
+        return len;
 }
 
 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -2,9 +2,9 @@
  *
  * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
  *
- * Copyright (C) 2003 Oliver Endriss 
+ * Copyright (C) 2003 Oliver Endriss
  * Copyright (C) 2004 Andrew de Quincey
- * 
+ *
  * based on code originally found in av7110.c & dvb_ci.c:
  * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
  *                         for convergence integrated media GmbH
@@ -13,12 +13,12 @@
  * 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.
- * 
+ *
  * 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 Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser 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.
@@ -52,7 +52,7 @@ struct dvb_ringbuffer {
 **
 **     *** write <buflen> bytes ***
 **     free = dvb_ringbuffer_free(rbuf);
-**     if (free >= buflen) 
+**     if (free >= buflen)
 **         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
 **     else
 **         ...
@@ -64,7 +64,7 @@ struct dvb_ringbuffer {
 **     else
 **         ...
 **
-** (2) If there is exactly one reader and one writer, there is no need 
+** (2) If there is exactly one reader and one writer, there is no need
 **     to lock read or write operations.
 **     Two or more readers must be locked against each other.
 **     Flushing the buffer counts as a read operation.
@@ -99,13 +99,13 @@ extern void dvb_ringbuffer_flush_spinloc
 /* advance read ptr by <num> bytes */
 #define DVB_RINGBUFFER_SKIP(rbuf,num)	\
 			(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
- 
+
 /*
-** read <len> bytes from ring buffer into <buf> 
+** read <len> bytes from ring buffer into <buf>
 ** <usermem> specifies whether <buf> resides in user space
 ** returns number of bytes transferred or -EFAULT
 */
-extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, 
+extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
                                    size_t len, int usermem);
 
 
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvbdev.c
  *
  * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
@@ -51,10 +51,10 @@ static const char * const dnames[] = {
 	"net", "osd"
 };
 
-
-#define DVB_MAX_IDS              6
-#define nums2minor(num,type,id)  ((num << 6) | (id << 4) | type)
-#define MAX_DVB_MINORS           (DVB_MAX_IDS*64)
+#define DVB_MAX_ADAPTERS	8
+#define DVB_MAX_IDS		4
+#define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
+#define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
 
 struct class_simple *dvb_class;
 EXPORT_SYMBOL(dvb_class);
@@ -82,7 +82,7 @@ static struct dvb_device* dvbdev_find_de
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev;
-	
+
 	dvbdev = dvbdev_find_device (iminor(inode));
 
 	if (dvbdev && dvbdev->fops) {
@@ -111,7 +111,6 @@ static struct file_operations dvb_device
 	.open =		dvb_device_open,
 };
 
-
 static struct cdev dvb_device_cdev = {
 	.kobj   = {.name = "dvb", },
 	.owner  =       THIS_MODULE,
@@ -166,7 +165,7 @@ int dvb_generic_ioctl(struct inode *inod
 		      unsigned int cmd, unsigned long arg)
 {
         struct dvb_device *dvbdev = file->private_data;
-	
+
         if (!dvbdev)
 	        return -ENODEV;
 
@@ -198,7 +197,7 @@ skip:
 }
 
 
-int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, 
+int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 			const struct dvb_device *template, void *priv, int type)
 {
 	struct dvb_device *dvbdev;
@@ -222,7 +221,7 @@ int dvb_register_device(struct dvb_adapt
 	}
 
 	up (&dvbdev_register_lock);
-	
+
 	memcpy(dvbdev, template, sizeof(struct dvb_device));
 	dvbdev->type = type;
 	dvbdev->id = id;
@@ -254,15 +253,15 @@ void dvb_unregister_device(struct dvb_de
 	if (!dvbdev)
 		return;
 
-		devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
-				dnames[dvbdev->type], dvbdev->id);
+	devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
+			dnames[dvbdev->type], dvbdev->id);
 
 	class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
 					dvbdev->type, dvbdev->id)));
 
-		list_del(&dvbdev->list_head);
-		kfree(dvbdev);
-	}
+	list_del (&dvbdev->list_head);
+	kfree (dvbdev);
+}
 EXPORT_SYMBOL(dvb_unregister_device);
 
 
@@ -270,7 +269,7 @@ static int dvbdev_get_free_adapter_num (
 {
 	int num = 0;
 
-	while (1) {
+	while (num < DVB_MAX_ADAPTERS) {
 		struct list_head *entry;
 		list_for_each (entry, &dvb_adapter_list) {
 			struct dvb_adapter *adap;
@@ -287,9 +286,8 @@ skip:
 }
 
 
-int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
 {
-	struct dvb_adapter *adap;
 	int num;
 
 	if (down_interruptible (&dvbdev_register_lock))
@@ -300,18 +298,12 @@ int dvb_register_adapter(struct dvb_adap
 		return -ENFILE;
 	}
 
-	if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) {
-		up(&dvbdev_register_lock);
-		return -ENOMEM;
-	}
-
 	memset (adap, 0, sizeof(struct dvb_adapter));
 	INIT_LIST_HEAD (&adap->device_list);
 
 	printk ("DVB: registering new adapter (%s).\n", name);
-	
-	devfs_mk_dir("dvb/adapter%d", num);
 
+	devfs_mk_dir("dvb/adapter%d", num);
 	adap->num = num;
 	adap->name = name;
 	adap->module = module;
@@ -333,7 +325,6 @@ int dvb_unregister_adapter(struct dvb_ad
 		return -ERESTARTSYS;
 	list_del (&adap->list_head);
 	up (&dvbdev_register_lock);
-	kfree (adap);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_unregister_adapter);
@@ -399,9 +390,7 @@ int dvb_usercopy(struct inode *inode, st
         }
 
 out:
-        if (mbuf)
-                kfree(mbuf);
-
+        kfree(mbuf);
         return err;
 }
 
@@ -451,4 +440,3 @@ module_exit(exit_dvbdev);
 MODULE_DESCRIPTION("DVB Core Driver");
 MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * dvbdev.h
  *
  * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
@@ -58,9 +58,6 @@ struct dvb_adapter {
 struct dvb_device {
 	struct list_head list_head;
 	struct file_operations *fops;
- 
- 
- 
 	struct dvb_adapter *adapter;
 	int type;
 	u32 id;
@@ -79,11 +76,11 @@ struct dvb_device {
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
-				struct dvb_device **pdvbdev, 
+				struct dvb_device **pdvbdev,
 				const struct dvb_device *template,
 				void *priv,
 				int type);
@@ -105,4 +102,3 @@ extern int dvb_usercopy(struct inode *in
 			    unsigned int cmd, void *arg));
 
 #endif /* #ifndef _DVBDEV_H_ */
-
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -12,10 +12,10 @@ config DVB_STV0299
 
 config DVB_CX24110
 	tristate "Conexant CX24110 based"
- 	depends on DVB_CORE
- 	help
+	depends on DVB_CORE
+	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
- 
+
 config DVB_TDA8083
 	tristate "Philips TDA8083 based"
 	depends on DVB_CORE
@@ -108,14 +108,14 @@ config DVB_MT352
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_DIB3000MB
-	tristate "DiBcom 3000-MB"
+	tristate "DiBcom 3000M-B"
 	depends on DVB_CORE
 	help
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
 	  to support this frontend.
 
 config DVB_DIB3000MC
-	tristate "DiBcom 3000-MC/P"
+	tristate "DiBcom 3000P/M-C"
 	depends on DVB_CORE
 	help
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
@@ -127,8 +127,8 @@ comment "DVB-C (cable) frontends"
 config DVB_ATMEL_AT76C651
 	tristate "Atmel AT76C651 based"
 	depends on DVB_CORE
-        help
- 	  A DVB-C tuner module. Say Y when you want to support this frontend.
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_VES1820
 	tristate "VLSI VES1820 based"
@@ -154,7 +154,23 @@ comment "ATSC (North American/Korean Ter
 config DVB_NXT2002
 	tristate "Nxt2002 based"
 	depends on DVB_CORE
+	select FW_LOADER
 	help
 	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+config DVB_OR51211
+	tristate "or51211 based (pcHDTV HD2000 card)"
+	depends on DVB_CORE
+	select FW_LOADER
+	help
+	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+
+config DVB_OR51132
+	tristate "OR51132 based (pcHDTV HD3000 card)"
+	depends on DVB_CORE
+	select FW_LOADER
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -4,6 +4,7 @@
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
 
+obj-$(CONFIG_DVB_CORE) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
 obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
@@ -25,4 +26,5 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
-
+obj-$(CONFIG_DVB_OR51211) += or51211.o
+obj-$(CONFIG_DVB_OR51132) += or51132.o
diff --git a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c
--- a/drivers/media/dvb/frontends/at76c651.c
+++ b/drivers/media/dvb/frontends/at76c651.c
@@ -1,6 +1,6 @@
 /*
  * at76c651.c
- * 
+ *
  * Atmel DVB-C Frontend Driver (at76c651/tua6010xs)
  *
  * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
@@ -150,7 +150,7 @@ static int at76c651_set_auto_config(stru
 	if (state->revision == 0x11) {
 		at76c651_writereg(state, 0x2E, 0x38);
 		at76c651_writereg(state, 0x2F, 0x13);
-}
+	}
 
 	at76c651_disable_interrupts(state);
 
@@ -255,19 +255,11 @@ static int at76c651_set_inversion(struct
 	return at76c651_writereg(state, 0x60, feciqinv);
 }
 
-
-
-
-
-
-
-
-
 static int at76c651_set_parameters(struct dvb_frontend* fe,
-			struct dvb_frontend_parameters *p)
+				   struct dvb_frontend_parameters *p)
 {
 	int ret;
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	at76c651_writereg(state, 0x0c, 0xc3);
 	state->config->pll_set(fe, p);
@@ -284,7 +276,7 @@ static int at76c651_set_parameters(struc
 
 static int at76c651_set_defaults(struct dvb_frontend* fe)
 {
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	at76c651_set_symbol_rate(state, 6900000);
 	at76c651_set_qam(state, QAM_64);
@@ -295,55 +287,51 @@ static int at76c651_set_defaults(struct 
 		at76c651_writereg(state, 0x0c, 0xc3);
 		state->config->pll_init(fe);
 		at76c651_writereg(state, 0x0c, 0xc2);
-}
+	}
 
 	return 0;
 }
 
 static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status)
-		{
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
-			u8 sync;
-
-			/*
-			 * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) 
-			 */
-	sync = at76c651_readreg(state, 0x80);
-			*status = 0;
-
-			if (sync & (0x04 | 0x10))	/* AGC1 || TIM */
-				*status |= FE_HAS_SIGNAL;
-
-			if (sync & 0x10)	/* TIM */
-				*status |= FE_HAS_CARRIER;
-
-			if (sync & 0x80)	/* FEC */
-				*status |= FE_HAS_VITERBI;
+{
+	struct at76c651_state* state = fe->demodulator_priv;
+	u8 sync;
 
-			if (sync & 0x40)	/* CAR */
-				*status |= FE_HAS_SYNC;
+	/*
+	 * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0)
+	 */
+	sync = at76c651_readreg(state, 0x80);
+	*status = 0;
 
-			if ((sync & 0xF0) == 0xF0)	/* TIM && EQU && CAR && FEC */
-				*status |= FE_HAS_LOCK;
+	if (sync & (0x04 | 0x10))	/* AGC1 || TIM */
+		*status |= FE_HAS_SIGNAL;
+	if (sync & 0x10)		/* TIM */
+		*status |= FE_HAS_CARRIER;
+	if (sync & 0x80)		/* FEC */
+		*status |= FE_HAS_VITERBI;
+	if (sync & 0x40)		/* CAR */
+		*status |= FE_HAS_SYNC;
+	if ((sync & 0xF0) == 0xF0)	/* TIM && EQU && CAR && FEC */
+		*status |= FE_HAS_LOCK;
 
 	return 0;
-		}
+}
 
 static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber)
-		{
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+{
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	*ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16;
 	*ber |= at76c651_readreg(state, 0x82) << 8;
 	*ber |= at76c651_readreg(state, 0x83);
-			*ber *= 10;
+	*ber *= 10;
 
 	return 0;
-		}
+}
 
 static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-		{
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+{
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	u8 gain = ~at76c651_readreg(state, 0x91);
 	*strength = (gain << 8) | gain;
@@ -353,19 +341,18 @@ static int at76c651_read_signal_strength
 
 static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	*snr = 0xFFFF -
 	    ((at76c651_readreg(state, 0x8F) << 8) |
 	     at76c651_readreg(state, 0x90));
 
-
 	return 0;
 }
 
 static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-	{
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+{
+	struct at76c651_state* state = fe->demodulator_priv;
 
 	*ucblocks = at76c651_readreg(state, 0x82);
 
@@ -378,13 +365,13 @@ static int at76c651_get_tune_settings(st
         fesettings->step_size = 0;
         fesettings->max_drift = 0;
 	return 0;
-	}
+}
 
 static void at76c651_release(struct dvb_frontend* fe)
 {
-	struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
-		kfree(state);
-	}
+	struct at76c651_state* state = fe->demodulator_priv;
+	kfree(state);
+}
 
 static struct dvb_frontend_ops at76c651_ops;
 
@@ -394,7 +381,7 @@ struct dvb_frontend* at76c651_attach(con
 	struct at76c651_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -415,7 +402,7 @@ struct dvb_frontend* at76c651_attach(con
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -230,19 +230,9 @@ static int cx22700_get_tps (struct cx227
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
 static int cx22700_init (struct dvb_frontend* fe)
 
-{	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+{	struct cx22700_state* state = fe->demodulator_priv;
 	int i;
 
 	dprintk("cx22700_init: init chip\n");
@@ -268,7 +258,7 @@ static int cx22700_init (struct dvb_fron
 
 static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
 		   | (cx22700_readreg (state, 0x0e) << 1);
@@ -296,7 +286,7 @@ static int cx22700_read_status(struct dv
 
 static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	*ber = cx22700_readreg (state, 0x0c) & 0x7f;
 	cx22700_writereg (state, 0x0c, 0x00);
@@ -306,7 +296,7 @@ static int cx22700_read_ber(struct dvb_f
 
 static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
 		   | (cx22700_readreg (state, 0x0e) << 1);
@@ -317,7 +307,7 @@ static int cx22700_read_signal_strength(
 
 static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
 		   | (cx22700_readreg (state, 0x0e) << 1);
@@ -328,7 +318,7 @@ static int cx22700_read_snr(struct dvb_f
 
 static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	*ucblocks = cx22700_readreg (state, 0x0f);
 	cx22700_writereg (state, 0x0f, 0x00);
@@ -338,7 +328,7 @@ static int cx22700_read_ucblocks(struct 
 
 static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 
 	cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
 	cx22700_writereg (state, 0x00, 0x00);
@@ -356,7 +346,7 @@ static int cx22700_set_frontend(struct d
 
 static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 	u8 reg09 = cx22700_readreg (state, 0x09);
 
 	p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
@@ -373,7 +363,7 @@ static int cx22700_get_tune_settings(str
 
 static void cx22700_release(struct dvb_frontend* fe)
 {
-	struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+	struct cx22700_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -385,7 +375,7 @@ struct dvb_frontend* cx22700_attach(cons
 	struct cx22700_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct cx22700_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -402,18 +392,18 @@ struct dvb_frontend* cx22700_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
 static struct dvb_frontend_ops cx22700_ops = {
 
 	.info = {
-		.name 			= "Conexant CX22700 DVB-T",
-		.type 			= FE_OFDM,
-		.frequency_min 		= 470000000,
-		.frequency_max 		= 860000000,
-		.frequency_stepsize 	= 166667,
+		.name			= "Conexant CX22700 DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 470000000,
+		.frequency_max		= 860000000,
+		.frequency_stepsize	= 166667,
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
+#include "dvb-pll.h"
 #include "cx22702.h"
 
 
@@ -186,7 +187,7 @@ static int cx22702_get_tps (struct cx227
 		case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
 		case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
 		case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
-}
+	}
 	switch( val&0x03 ) {
 		case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
 		case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
@@ -195,27 +196,27 @@ static int cx22702_get_tps (struct cx227
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
 	u8 val;
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	/* set PLL */
         cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
-	state->config->pll_set(fe, p);
+	if (state->config->pll_set) {
+		state->config->pll_set(fe, p);
+	} else if (state->config->pll_desc) {
+		u8 pllbuf[4];
+		struct i2c_msg msg = { .addr = state->config->pll_address,
+				       .buf = pllbuf, .len = 4 };
+		dvb_pll_configure(state->config->pll_desc, pllbuf,
+				  p->frequency,
+				  p->u.ofdm.bandwidth);
+		i2c_transfer(state->i2c, &msg, 1);
+	} else {
+		BUG();
+	}
         cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
 
 	/* set inversion */
@@ -259,7 +260,7 @@ static int cx22702_set_tps (struct dvb_f
 		return 0;
 	}
 
-   	/* manually programmed values */
+	/* manually programmed values */
 	val=0;
 	switch(p->u.ofdm.constellation) {
 		case   QPSK: val = (val&0xe7); break;
@@ -332,13 +333,12 @@ static int cx22702_set_tps (struct dvb_f
 	return 0;
 }
 
-
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 static int cx22702_init (struct dvb_frontend* fe)
 {
 	int i;
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	cx22702_writereg (state, 0x00, 0x02);
 
@@ -360,53 +360,53 @@ static int cx22702_init (struct dvb_fron
 
 static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 	u8 reg0A;
 	u8 reg23;
 
-			*status = 0;
+	*status = 0;
 
 	reg0A = cx22702_readreg (state, 0x0A);
 	reg23 = cx22702_readreg (state, 0x23);
 
-			dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
-				,__FUNCTION__,reg0A,reg23);
+	dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
+		,__FUNCTION__,reg0A,reg23);
 
-			if(reg0A & 0x10) {
-				*status |= FE_HAS_LOCK;
-				*status |= FE_HAS_VITERBI;
-				*status |= FE_HAS_SYNC;
-			}
+	if(reg0A & 0x10) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+	}
 
-			if(reg0A & 0x20)
-				*status |= FE_HAS_CARRIER;
+	if(reg0A & 0x20)
+		*status |= FE_HAS_CARRIER;
 
-			if(reg23 < 0xf0)
-				*status |= FE_HAS_SIGNAL;
+	if(reg23 < 0xf0)
+		*status |= FE_HAS_SIGNAL;
 
 	return 0;
-			}
+}
 
 static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
-		{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+{
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	if(cx22702_readreg (state, 0xE4) & 0x02) {
-				/* Realtime statistics */
+		/* Realtime statistics */
 		*ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
 			| (cx22702_readreg (state, 0xDF)&0x7F);
-			} else {
+	} else {
 		/* Averagtine statistics */
 		*ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
 			| cx22702_readreg (state, 0xDF);
-		}
+	}
 
 	return 0;
-		}
+}
 
 static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-		{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+{
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	*signal_strength = cx22702_readreg (state, 0x23);
 
@@ -415,7 +415,7 @@ static int cx22702_read_signal_strength(
 
 static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	u16 rs_ber=0;
 	if(cx22702_readreg (state, 0xE4) & 0x02) {
@@ -434,7 +434,7 @@ static int cx22702_read_snr(struct dvb_f
 
 static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	u8 _ucblocks;
 
@@ -449,7 +449,7 @@ static int cx22702_read_ucblocks(struct 
 
 static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state* state = fe->demodulator_priv;
 
 	u8 reg0C = cx22702_readreg (state, 0x0C);
 
@@ -459,9 +459,9 @@ static int cx22702_get_frontend(struct d
 
 static void cx22702_release(struct dvb_frontend* fe)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-		kfree(state);
-	}
+	struct cx22702_state* state = fe->demodulator_priv;
+	kfree(state);
+}
 
 static struct dvb_frontend_ops cx22702_ops;
 
@@ -471,7 +471,7 @@ struct dvb_frontend* cx22702_attach(cons
 	struct cx22702_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -489,7 +489,7 @@ struct dvb_frontend* cx22702_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -36,6 +36,9 @@ struct cx22702_config
 	u8 demod_address;
 
 	/* PLL maintenance */
+	u8 pll_address;
+	struct dvb_pll_desc *pll_desc;
+
 	int (*pll_init)(struct dvb_frontend* fe);
 	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -131,7 +131,6 @@ static int cx24110_writereg (struct cx24
         return 0;
 }
 
-
 static int cx24110_readreg (struct cx24110_state* state, u8 reg)
 {
 	int ret;
@@ -181,7 +180,6 @@ static int cx24110_set_inversion (struct
 	return 0;
 }
 
-
 static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
 {
 /* fixme (low): error handling */
@@ -227,7 +225,6 @@ static int cx24110_set_fec (struct cx241
 	return 0;
 }
 
-
 static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
 {
 	int i;
@@ -244,7 +241,6 @@ static fe_code_rate_t cx24110_get_fec (s
 	}
 }
 
-
 static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 {
 /* fixme (low): add error handling */
@@ -317,20 +313,9 @@ dprintk("cx24110 debug: entering %s(%d)\
 
 }
 
-
-
-
-
-
-
-
-
-
-
-
 int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
 {
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 
 /* tuner data is 21 bits long, must be left-aligned in data */
 /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
@@ -369,11 +354,9 @@ int cx24110_pll_write (struct dvb_fronte
         return 0;
 }
 
-
-
 static int cx24110_initfe(struct dvb_frontend* fe)
 {
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 /* fixme (low): error handling */
         int i;
 
@@ -388,10 +371,9 @@ static int cx24110_initfe(struct dvb_fro
 	return 0;
 }
 
-
 static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -403,15 +385,41 @@ static int cx24110_set_voltage (struct d
 	};
 }
 
+static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	int rv, bit, i;
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	if (burst == SEC_MINI_A)
+		bit = 0x00;
+	else if (burst == SEC_MINI_B)
+		bit = 0x08;
+	else
+		return -EINVAL;
+
+	rv = cx24110_readreg(state, 0x77);
+	cx24110_writereg(state, 0x77, rv|0x04);
+
+	rv = cx24110_readreg(state, 0x76);
+	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
+	for (i = 500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40) ; )
+              ; /* wait for LNB ready */
+
+	return 0;
+}
+
 static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd *cmd)
+				   struct dvb_diseqc_master_cmd *cmd)
 {
 	int i, rv;
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 
 	for (i = 0; i < cmd->msg_len; i++)
 		cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
 
+	rv = cx24110_readreg(state, 0x77);
+	cx24110_writereg(state, 0x77, rv|0x04);
+
 	rv = cx24110_readreg(state, 0x76);
 
 	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
@@ -423,37 +431,37 @@ static int cx24110_send_diseqc_msg(struc
 
 static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 
 	int sync = cx24110_readreg (state, 0x55);
 
-		*status = 0;
+	*status = 0;
 
-		if (sync & 0x10)
-			*status |= FE_HAS_SIGNAL;
+	if (sync & 0x10)
+		*status |= FE_HAS_SIGNAL;
 
-		if (sync & 0x08)
-			*status |= FE_HAS_CARRIER;
+	if (sync & 0x08)
+		*status |= FE_HAS_CARRIER;
 
 	sync = cx24110_readreg (state, 0x08);
 
-		if (sync & 0x40)
-			*status |= FE_HAS_VITERBI;
+	if (sync & 0x40)
+		*status |= FE_HAS_VITERBI;
 
-		if (sync & 0x20)
-			*status |= FE_HAS_SYNC;
+	if (sync & 0x20)
+		*status |= FE_HAS_SYNC;
 
-		if ((sync & 0x60) == 0x60)
-			*status |= FE_HAS_LOCK;
+	if ((sync & 0x60) == 0x60)
+		*status |= FE_HAS_LOCK;
 
 	return 0;
-	}
+}
 
 static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
-	{
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
 
-/* fixme (maybe): value range is 16 bit. Scale? */
+	/* fixme (maybe): value range is 16 bit. Scale? */
 	if(cx24110_readreg(state,0x24)&0x10) {
 		/* the Viterbi error counter has finished one counting window */
 		cx24110_writereg(state,0x24,0x04); /* select the ber reg */
@@ -465,24 +473,24 @@ static int cx24110_read_ber(struct dvb_f
 	*ber = state->lastber;
 
 	return 0;
-	}
+}
 
 static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-	{
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
 
 /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
 	u8 signal = cx24110_readreg (state, 0x27)+128;
 	*signal_strength = (signal << 8) | signal;
 
 	return 0;
-	}
+}
 
 static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
-	{
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
 
-/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
+	/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
 	if(cx24110_readreg(state,0x6a)&0x80) {
 		/* the Es/N0 error counter has finished one counting window */
 		state->lastesn0=cx24110_readreg(state,0x69)|
@@ -492,11 +500,11 @@ static int cx24110_read_snr(struct dvb_f
 	*snr = state->lastesn0;
 
 	return 0;
-	}
+}
 
 static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-	{
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
 	u32 lastbyer;
 
 	if(cx24110_readreg(state,0x10)&0x40) {
@@ -517,8 +525,8 @@ static int cx24110_read_ucblocks(struct 
 }
 
 static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
-        {
-	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
 
 	state->config->pll_set(fe, p);
 	cx24110_set_inversion (state, p->inversion);
@@ -527,46 +535,46 @@ static int cx24110_set_frontend(struct d
 	cx24110_writereg(state,0x04,0x05); /* start aquisition */
 
 	return 0;
-        }
+}
 
 static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
-	{
-   	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
-		s32 afc; unsigned sclk;
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+	s32 afc; unsigned sclk;
 
 /* cannot read back tuner settings (freq). Need to have some private storage */
 
 	sclk = cx24110_readreg (state, 0x07) & 0x03;
 /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
  * Need 64 bit arithmetic. Is thiss possible in the kernel? */
-		if (sclk==0) sclk=90999000L/2L;
-		else if (sclk==1) sclk=60666000L;
-		else if (sclk==2) sclk=80888000L;
-		else sclk=90999000L;
-		sclk>>=8;
+	if (sclk==0) sclk=90999000L/2L;
+	else if (sclk==1) sclk=60666000L;
+	else if (sclk==2) sclk=80888000L;
+	else sclk=90999000L;
+	sclk>>=8;
 	afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
 	      ((sclk*cx24110_readreg (state, 0x45))>>8)+
 	      ((sclk*cx24110_readreg (state, 0x46))>>16);
 
-		p->frequency += afc;
+	p->frequency += afc;
 	p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
-					INVERSION_ON : INVERSION_OFF;
+				INVERSION_ON : INVERSION_OFF;
 	p->u.qpsk.fec_inner = cx24110_get_fec (state);
 
-        return 0;
+	return 0;
 }
 
 static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-   	struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+	struct cx24110_state *state = fe->demodulator_priv;
 
 	return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
 }
 
 static void cx24110_release(struct dvb_frontend* fe)
 {
-	struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv;
-		kfree(state);
+	struct cx24110_state* state = fe->demodulator_priv;
+	kfree(state);
 }
 
 static struct dvb_frontend_ops cx24110_ops;
@@ -578,7 +586,7 @@ struct dvb_frontend* cx24110_attach(cons
 	int ret;
 
 	/* allocate memory for the internal state */
-	state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -587,7 +595,7 @@ struct dvb_frontend* cx24110_attach(cons
 	memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
 	state->lastbler = 0;
-   	state->lastesn0 = 0;
+	state->lastesn0 = 0;
 
 	/* check if the demod is there */
 	ret = cx24110_readreg(state, 0x00);
@@ -599,7 +607,7 @@ struct dvb_frontend* cx24110_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -634,6 +642,7 @@ static struct dvb_frontend_ops cx24110_o
 	.diseqc_send_master_cmd = cx24110_send_diseqc_msg,
 	.set_tone = cx24110_set_tone,
 	.set_voltage = cx24110_set_voltage,
+	.diseqc_send_burst = cx24110_diseqc_send_burst,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
--- a/drivers/media/dvb/frontends/dib3000-common.c
+++ b/drivers/media/dvb/frontends/dib3000-common.c
@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] =     /* fft,gu
 	};
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(dib3000_seq);
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -1,6 +1,6 @@
 /*
  * .h-files for the common use of the frontend drivers made by DiBcom
- * DiBcom 3000-MB/MC/P
+ * DiBcom 3000M-B/C, 3000P
  *
  * DiBcom (http://www.dibcom.fr/)
  *
@@ -30,9 +30,9 @@
 #include "dib3000.h"
 
 /* info and err, taken from usb.h, if there is anything available like by default. */
-#define err(format, arg...) printk(KERN_ERR "dib3000mX: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO "dib3000mX: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "dib3000mX: " format "\n" , ## arg)
+#define err(format, arg...)  printk(KERN_ERR     "dib3000: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO    "dib3000: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
 
 /* frontend state */
 struct dib3000_state {
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -1,6 +1,6 @@
 /*
  * public header file of the frontend drivers for mobile DVB-T demodulators
- * DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/)
+ * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -1,5 +1,5 @@
 /*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
  * DiBcom (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
@@ -35,7 +35,7 @@
 
 /* Version information */
 #define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
+#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -54,14 +54,14 @@ static int dib3000mb_get_frontend(struct
 				  struct dvb_frontend_parameters *fep);
 
 static int dib3000mb_set_frontend(struct dvb_frontend* fe,
-		struct dvb_frontend_parameters *fep, int tuner)
+				  struct dvb_frontend_parameters *fep, int tuner)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	fe_code_rate_t fe_cr = FEC_NONE;
-	int search_state,seq;
+	int search_state, seq;
 
-	if (tuner) {
+	if (tuner && state->config.pll_addr && state->config.pll_set) {
 		dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
 		state->config.pll_set(fe, fep, NULL);
 		dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
@@ -70,18 +70,18 @@ static int dib3000mb_set_frontend(struct
 		switch (ofdm->bandwidth) {
 			case BANDWIDTH_8_MHZ:
 				deb_setf("8 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
-				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
 				break;
 			case BANDWIDTH_7_MHZ:
 				deb_setf("7 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[1]);
-				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_7mhz);
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
 				break;
 			case BANDWIDTH_6_MHZ:
 				deb_setf("6 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[0]);
-				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_6mhz);
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
 				break;
 			case BANDWIDTH_AUTO:
 				return -EOPNOTSUPP;
@@ -90,7 +90,7 @@ static int dib3000mb_set_frontend(struct
 				return -EINVAL;
 		}
 	}
-	wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
 
 	deb_setf("transmission mode: ");
 	switch (ofdm->transmission_mode) {
@@ -170,25 +170,25 @@ static int dib3000mb_set_frontend(struct
 		default:
 			return -EINVAL;
 	}
-	deb_setf("hierachy: ");	
+	deb_setf("hierachy: ");
 	switch (ofdm->hierarchy_information) {
 		case HIERARCHY_NONE:
 			deb_setf("none ");
 			/* fall through */
 		case HIERARCHY_1:
-			deb_setf("alpha=1\n");	
+			deb_setf("alpha=1\n");
 			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1);
 			break;
 		case HIERARCHY_2:
-			deb_setf("alpha=2\n");	
+			deb_setf("alpha=2\n");
 			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2);
 			break;
 		case HIERARCHY_4:
-			deb_setf("alpha=4\n");	
+			deb_setf("alpha=4\n");
 			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4);
 			break;
 		case HIERARCHY_AUTO:
-			deb_setf("alpha=auto\n");	
+			deb_setf("alpha=auto\n");
 			break;
 		default:
 			return -EINVAL;
@@ -243,39 +243,39 @@ static int dib3000mb_set_frontend(struct
 		[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
 		[fep->inversion == INVERSION_AUTO];
 
-	deb_setf("seq? %d\n",seq);
+	deb_setf("seq? %d\n", seq);
 
-	wr(DIB3000MB_REG_SEQ,seq);
+	wr(DIB3000MB_REG_SEQ, seq);
 
-	wr(DIB3000MB_REG_ISI,seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
+	wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
 
 	if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
 		if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
-			wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_2K_1_8);
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
 		} else {
-			wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_DEFAULT);
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
 		}
 
-		wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_2K);
+		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K);
 	} else {
-		wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_DEFAULT);
+		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT);
 	}
 
-	wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_OFF);
-	wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
-	wr(DIB3000MB_REG_MOBILE_MODE,DIB3000MB_MOBILE_MODE_OFF);
+	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF);
 
-	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_high);
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high);
 
-	wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_ACTIVATE);
+	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE);
 
-	wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AGC+DIB3000MB_RESTART_CTRL);
-	wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL);
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
 
 	/* wait for AGC lock */
 	msleep(70);
 
-	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
 
 	/* something has to be auto searched */
 	if (ofdm->constellation == QAM_AUTO ||
@@ -284,12 +284,12 @@ static int dib3000mb_set_frontend(struct
 		fep->inversion == INVERSION_AUTO) {
 		int as_count=0;
 
-		deb_setf("autosearch enabled.\n");	
+		deb_setf("autosearch enabled.\n");
 
-		wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
+		wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
 
-		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH);
-		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
 
 		while ((search_state =
 				dib3000_search_status(
@@ -297,7 +297,7 @@ static int dib3000mb_set_frontend(struct
 					rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
 			msleep(1);
 
-		deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+		deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
 
 		if (search_state == 1) {
 			struct dvb_frontend_parameters feps;
@@ -308,8 +308,8 @@ static int dib3000mb_set_frontend(struct
 		}
 
 	} else {
-		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
-		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
 	}
 
 	return 0;
@@ -317,76 +317,77 @@ static int dib3000mb_set_frontend(struct
 
 static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
-	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
+	deb_info("dib3000mb is getting up.\n");
+	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP);
 
 	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
 
-	wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE);
-	wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE_RST);
+	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE);
+	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST);
 
-	wr(DIB3000MB_REG_CLOCK,DIB3000MB_CLOCK_DEFAULT);
+	wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT);
 
-	wr(DIB3000MB_REG_ELECT_OUT_MODE,DIB3000MB_ELECT_OUT_MODE_ON);
+	wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON);
 
-	wr(DIB3000MB_REG_DDS_FREQ_MSB,DIB3000MB_DDS_FREQ_MSB);
-	wr(DIB3000MB_REG_DDS_FREQ_LSB,DIB3000MB_DDS_FREQ_LSB);
+	wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB);
+	wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB);
 
-	wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+	wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
 
 	wr_foreach(dib3000mb_reg_impulse_noise,
 			dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
 
-	wr_foreach(dib3000mb_reg_agc_gain,dib3000mb_default_agc_gain);
+	wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain);
 
-	wr(DIB3000MB_REG_PHASE_NOISE,DIB3000MB_PHASE_NOISE_DEFAULT);
+	wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT);
 
 	wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
 
-	wr_foreach(dib3000mb_reg_lock_duration,dib3000mb_default_lock_duration);
+	wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration);
 
-	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
 
-	wr(DIB3000MB_REG_LOCK0_MASK,DIB3000MB_LOCK0_DEFAULT);
-	wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
-	wr(DIB3000MB_REG_LOCK2_MASK,DIB3000MB_LOCK2_DEFAULT);
+	wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT);
+	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
+	wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT);
 	wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]);
 
-	wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+	wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
 
-	wr(DIB3000MB_REG_UNK_68,DIB3000MB_UNK_68);
-	wr(DIB3000MB_REG_UNK_69,DIB3000MB_UNK_69);
-	wr(DIB3000MB_REG_UNK_71,DIB3000MB_UNK_71);
-	wr(DIB3000MB_REG_UNK_77,DIB3000MB_UNK_77);
-	wr(DIB3000MB_REG_UNK_78,DIB3000MB_UNK_78);
-	wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
-	wr(DIB3000MB_REG_UNK_92,DIB3000MB_UNK_92);
-	wr(DIB3000MB_REG_UNK_96,DIB3000MB_UNK_96);
-	wr(DIB3000MB_REG_UNK_97,DIB3000MB_UNK_97);
-	wr(DIB3000MB_REG_UNK_106,DIB3000MB_UNK_106);
-	wr(DIB3000MB_REG_UNK_107,DIB3000MB_UNK_107);
-	wr(DIB3000MB_REG_UNK_108,DIB3000MB_UNK_108);
-	wr(DIB3000MB_REG_UNK_122,DIB3000MB_UNK_122);
-	wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
-	wr(DIB3000MB_REG_BERLEN,DIB3000MB_BERLEN_DEFAULT);
-
-	wr_foreach(dib3000mb_reg_filter_coeffs,dib3000mb_filter_coeffs);
-
-	wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_ON);
-	wr(DIB3000MB_REG_MULTI_DEMOD_MSB,DIB3000MB_MULTI_DEMOD_MSB);
-	wr(DIB3000MB_REG_MULTI_DEMOD_LSB,DIB3000MB_MULTI_DEMOD_LSB);
+	wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68);
+	wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69);
+	wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71);
+	wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77);
+	wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78);
+	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
+	wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92);
+	wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96);
+	wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97);
+	wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106);
+	wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107);
+	wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108);
+	wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT);
+
+	wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs);
+
+	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON);
+	wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB);
+	wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB);
 
-	wr(DIB3000MB_REG_OUTPUT_MODE,DIB3000MB_OUTPUT_MODE_SLAVE);
+	wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE);
 
-	wr(DIB3000MB_REG_FIFO_142,DIB3000MB_FIFO_142);
-	wr(DIB3000MB_REG_MPEG2_OUT_MODE,DIB3000MB_MPEG2_OUT_MODE_188);
+	wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142);
+	wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188);
 	wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE);
-	wr(DIB3000MB_REG_FIFO,DIB3000MB_FIFO_INHIBIT);
-	wr(DIB3000MB_REG_FIFO_146,DIB3000MB_FIFO_146);
-	wr(DIB3000MB_REG_FIFO_147,DIB3000MB_FIFO_147);
+	wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
+	wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146);
+	wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147);
 
-	wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
+	wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
 	if (state->config.pll_init) {
 		dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
@@ -400,7 +401,7 @@ static int dib3000mb_fe_init(struct dvb_
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	fe_code_rate_t *cr;
 	u16 tps_val;
@@ -451,7 +452,7 @@ static int dib3000mb_get_frontend(struct
 		default:
 			err("Unexpected constellation returned by TPS (%d)", tps_val);
 			break;
- 	}
+	}
 	deb_getf("TPS: %d\n", tps_val);
 
 	if (rd(DIB3000MB_REG_TPS_HRCH)) {
@@ -561,7 +562,7 @@ static int dib3000mb_get_frontend(struct
 
 static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
 	*stat = 0;
 
@@ -574,16 +575,9 @@ static int dib3000mb_read_status(struct 
 	if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
 		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
 
-	deb_info("actual status is %2x\n",*stat);
+	deb_getf("actual status is %2x\n",*stat);
 
-	deb_getf("tps %x %x %x %x %x\n",
-			rd(DIB3000MB_REG_TPS_1),
-			rd(DIB3000MB_REG_TPS_2),
-			rd(DIB3000MB_REG_TPS_3),
-			rd(DIB3000MB_REG_TPS_4),
-			rd(DIB3000MB_REG_TPS_5));
-	
-	deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
+	deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
 			rd(DIB3000MB_REG_TPS_LOCK),
 			rd(DIB3000MB_REG_TPS_QAM),
 			rd(DIB3000MB_REG_TPS_HRCH),
@@ -600,80 +594,34 @@ static int dib3000mb_read_status(struct 
 
 static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
-	*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
+	*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB));
 	return 0;
 }
-/*
- * Amaury:
- * signal strength is measured with dBm (power compared to mW)
- * the standard range is -90dBm(low power) to -10 dBm (strong power),
- * but the calibration is done for -100 dBm to 0dBm
- */
 
-#define DIB3000MB_AGC_REF_dBm		-14
-#define DIB3000MB_GAIN_SLOPE_dBm	100
-#define DIB3000MB_GAIN_DELTA_dBm	-2
+/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */
 static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
-/* TODO log10 
-	u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER), 
-		n_agc_power = rd(DIB3000MB_REG_AGC_POWER),
-		rf_power = rd(DIB3000MB_REG_RF_POWER);
-	double rf_power_dBm, ad_power_dBm, minar_power_dBm;
-	
-	if (n_agc_power == 0 )
-		n_agc_power = 1 ;
-
-	ad_power_dBm    = 10 * log10 ( (float)n_agc_power / (float)(1<<16) );
-	minor_power_dBm = ad_power_dBm - DIB3000MB_AGC_REF_dBm;
-	rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) + 
-			DIB3000MB_GAIN_DELTA_dBm) + minor_power_dBm;
-	// relative rf_power 
-	*strength = (u16) ((rf_power_dBm + 100) / 100 * 0xffff);
-*/
 	*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
 	return 0;
 }
 
-/*
- * Amaury: 
- * snr is the signal quality measured in dB.
- * snr = 10*log10(signal power / noise power)
- * the best quality is near 35dB (cable transmission & good modulator)
- * the minimum without errors depend of transmission parameters
- * some indicative values are given in en300744 Annex A
- * ex : 16QAM 2/3 (Gaussian)  = 11.1 dB
- *
- * If SNR is above 20dB, BER should be always 0.
- * choose 0dB as the minimum
- */
 static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
 	int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
 		rd(DIB3000MB_REG_NOISE_POWER_LSB);
-/*
-	float snr_dBm=0;
-
-	if (sigpow > 0 && icipow > 0)
-		snr_dBm = 10.0 * log10( (float) (sigpow<<8) / (float)icipow )  ;
-	else if (sigpow > 0)
-		snr_dBm = 35;
-	
-	*snr = (u16) ((snr_dBm / 35) * 0xffff);
-*/
 	*snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
 	return 0;
 }
 
 static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
 	*unc = rd(DIB3000MB_REG_UNC);
 	return 0;
@@ -681,9 +629,9 @@ static int dib3000mb_read_unc_blocks(str
 
 static int dib3000mb_sleep(struct dvb_frontend* fe)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
-
-	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
+	struct dib3000_state* state = fe->demodulator_priv;
+	deb_info("dib3000mb is going to bed.\n");
+	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN);
 	return 0;
 }
 
@@ -691,8 +639,8 @@ static int dib3000mb_fe_get_tune_setting
 {
 	tune->min_delay_ms = 800;
 	tune->step_size = 166667;
-	tune->max_drift = 166667*2;
-					
+	tune->max_drift = 166667 * 2;
+
 	return 0;
 }
 
@@ -708,7 +656,7 @@ static int dib3000mb_set_frontend_and_tu
 
 static void dib3000mb_release(struct dvb_frontend* fe)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -717,13 +665,13 @@ static int dib3000mb_pid_control(struct 
 {
 	struct dib3000_state *state = fe->demodulator_priv;
 	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-		wr(index+DIB3000MB_REG_FIRST_PID,pid);
+	wr(index+DIB3000MB_REG_FIRST_PID,pid);
 	return 0;
 }
 
 static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 
 	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
 	if (onoff) {
@@ -732,18 +680,19 @@ static int dib3000mb_fifo_control(struct
 		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
 	}
 	return 0;
-	}
+}
 
 static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
 {
-	//struct dib3000_state *state = fe->demodulator_priv;
-	/* switch it off and on */
+	struct dib3000_state *state = fe->demodulator_priv;
+	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
+	wr(DIB3000MB_REG_PID_PARSE,onoff);
 	return 0;
-	}
+}
 
 static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 	if (onoff) {
 		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
 	} else {
@@ -760,9 +709,10 @@ struct dvb_frontend* dib3000mb_attach(co
 	struct dib3000_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
+	memset(state,0,sizeof(struct dib3000_state));
 
 	/* setup the state */
 	state->i2c = i2c;
@@ -789,18 +739,17 @@ struct dvb_frontend* dib3000mb_attach(co
 	return &state->frontend;
 
 error:
-	if (state)
 	kfree(state);
 	return NULL;
-	}
+}
 
 static struct dvb_frontend_ops dib3000mb_ops = {
 
 	.info = {
-		.name			= "DiBcom 3000-MB DVB-T",
-		.type 			= FE_OFDM,
-		.frequency_min 		= 44250000,
-		.frequency_max 		= 867250000,
+		.name			= "DiBcom 3000M-B DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
 		.frequency_stepsize	= 62500,
 		.caps = FE_CAN_INVERSION_AUTO |
 				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,5 +1,5 @@
 /*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C
  * DiBcom (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
@@ -34,7 +34,7 @@
 
 /* Version information */
 #define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver"
+#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"
 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -189,13 +189,13 @@ static int dib3000mc_init_auto_scan(stru
 static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con)
 {
 	switch (con) {
-		case QAM_64: 
+		case QAM_64:
 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]);
 			break;
-		case QAM_16: 
+		case QAM_16:
 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
 			break;
-		case QPSK: 
+		case QPSK:
 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]);
 			break;
 		case QAM_AUTO:
@@ -223,13 +223,13 @@ static int dib3000mc_set_general_cfg(str
 	switch (ofdm->guard_interval) {
 		case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
 		case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
-		case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
-		case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
+		case GUARD_INTERVAL_1_8:  guard = DIB3000_GUARD_TIME_1_8; break;
+		case GUARD_INTERVAL_1_4:  guard = DIB3000_GUARD_TIME_1_4; break;
 		case GUARD_INTERVAL_AUTO: break;
 		default: return -EINVAL;
 	}
 	switch (ofdm->constellation) {
-		case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
+		case QPSK:   qam = DIB3000_CONSTELLATION_QPSK; break;
 		case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
 		case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
 		case QAM_AUTO: break;
@@ -244,13 +244,13 @@ static int dib3000mc_set_general_cfg(str
 		default: return -EINVAL;
 	}
 	if (ofdm->hierarchy_information == HIERARCHY_NONE) {
-		hrch = DIB3000_HRCH_OFF;
+		hrch   = DIB3000_HRCH_OFF;
 		sel_hp = DIB3000_SELECT_HP;
-		fe_cr = ofdm->code_rate_HP;
+		fe_cr  = ofdm->code_rate_HP;
 	} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
-		hrch = DIB3000_HRCH_ON;
+		hrch   = DIB3000_HRCH_ON;
 		sel_hp = DIB3000_SELECT_LP;
-		fe_cr = ofdm->code_rate_LP;
+		fe_cr  = ofdm->code_rate_LP;
 	}
 	switch (fe_cr) {
 		case FEC_1_2: cr = DIB3000_FEC_1_2; break;
@@ -286,10 +286,10 @@ static int dib3000mc_set_general_cfg(str
 	deb_setf("seq? %d\n", seq);
 	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
 	*auto_val = ofdm->constellation == QAM_AUTO ||
-		ofdm->hierarchy_information == HIERARCHY_AUTO ||
-		ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
-		ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
-		fe_cr == FEC_AUTO ||
+			ofdm->hierarchy_information == HIERARCHY_AUTO ||
+			ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
+			ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
+			fe_cr == FEC_AUTO ||
 			fep->inversion == INVERSION_AUTO;
 	return 0;
 }
@@ -297,7 +297,7 @@ static int dib3000mc_set_general_cfg(str
 static int dib3000mc_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	fe_code_rate_t *cr;
 	u16 tps_val,cr_val;
@@ -334,7 +334,7 @@ static int dib3000mc_get_frontend(struct
 
 	fep->frequency = state->last_tuned_freq;
 	fep->u.ofdm.bandwidth= state->last_tuned_bw;
-	
+
 	tps_val = rd(DIB3000MC_REG_TUNING_PARM);
 
 	switch (DIB3000MC_TP_QAM(tps_val)) {
@@ -353,7 +353,7 @@ static int dib3000mc_get_frontend(struct
 		default:
 			err("Unexpected constellation returned by TPS (%d)", tps_val);
 			break;
- 	}
+	}
 
 	if (DIB3000MC_TP_HRCH(tps_val)) {
 		deb_getf("HRCH ON ");
@@ -458,16 +458,16 @@ static int dib3000mc_get_frontend(struct
 static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep, int tuner)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	int search_state,auto_val;
 	u16 val;
-	
-	if (tuner) { /* initial call from dvb */
+
+	if (tuner && state->config.pll_addr && state->config.pll_set) { /* initial call from dvb */
 		dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
 		state->config.pll_set(fe,fep,NULL);
 		dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
-		
+
 		state->last_tuned_freq = fep->frequency;
 	//	if (!scanboost) {
 			dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
@@ -477,7 +477,7 @@ static int dib3000mc_set_frontend(struct
 			wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
 			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
 			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-			
+
 			/* Default cfg isi offset adp */
 			wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
 
@@ -495,7 +495,7 @@ static int dib3000mc_set_frontend(struct
 			auto_val = 0;
 			dib3000mc_set_general_cfg(state,fep,&auto_val);
 			dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-		
+
 			val = rd(DIB3000MC_REG_DEMOD_PARM);
 			wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
 			wr(DIB3000MC_REG_DEMOD_PARM,val);
@@ -507,17 +507,17 @@ static int dib3000mc_set_frontend(struct
 			int as_count=0;
 
 			deb_setf("autosearch enabled.\n");
-			
+
 			val = rd(DIB3000MC_REG_DEMOD_PARM);
 			wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
 			wr(DIB3000MC_REG_DEMOD_PARM,val);
 
 			while ((search_state = dib3000_search_status(
-						rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) 
+						rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
 				msleep(10);
-			
+
 			deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
-			
+
 			if (search_state == 1) {
 				struct dvb_frontend_parameters feps;
 				if (dib3000mc_get_frontend(fe, &feps) == 0) {
@@ -529,33 +529,33 @@ static int dib3000mc_set_frontend(struct
 			dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth);
 			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
 			dib3000mc_set_adp_cfg(state,ofdm->constellation);
-			
+
 			/* set_offset_cfg */
 			wr_foreach(dib3000mc_reg_offset,
 					dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
 		}
 	} else { /* second call, after autosearch (fka: set_WithKnownParams) */
 //		dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
-		
+
 		auto_val = 0;
 		dib3000mc_set_general_cfg(state,fep,&auto_val);
 		if (auto_val)
 			deb_info("auto_val is true, even though an auto search was already performed.\n");
 
 		dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-		
+
 		val = rd(DIB3000MC_REG_DEMOD_PARM);
 		wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
 		wr(DIB3000MC_REG_DEMOD_PARM,val);
-		
+
 		msleep(30);
-		
+
 		wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
 			dib3000mc_set_adp_cfg(state,ofdm->constellation);
 		wr_foreach(dib3000mc_reg_offset,
 				dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
-		
-				
+
+
 	}
 	return 0;
 }
@@ -569,26 +569,26 @@ static int dib3000mc_fe_init(struct dvb_
 	state = fe->demodulator_priv;
 	state->timing_offset = 0;
 	state->timing_offset_comp_done = 0;
-	
+
 	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
 	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
 	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
 	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
 	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
 	wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
-	
+
 	wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
 	wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
 
 	wr(33,5);
 	wr(36,81);
-	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);				  
-	
+	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
+
 	wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
 	wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
 
 	/* mobile mode - portable reception */
-	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); 
+	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
 
 /* TUNER_PANASONIC_ENV57H12D5: */
 	wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
@@ -601,24 +601,24 @@ static int dib3000mc_fe_init(struct dvb_
 	wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
 	wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
 	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
-	
+
 	wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
 	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
-	
+
 	wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
 
 	wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
 	wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
 
-	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); 
+	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
 //	wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
-	
+
 	wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
 	wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
 	wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
-	
+
 	wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
-	
+
 	dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
 
 /* output mode control, just the MPEG2_SLAVE */
@@ -634,13 +634,13 @@ static int dib3000mc_fe_init(struct dvb_
 			rd(DIB3000MC_REG_OUTMODE)));
 
 	wr(DIB3000MC_REG_SMO_MODE,
-			DIB3000MC_SMO_MODE_DEFAULT | 
+			DIB3000MC_SMO_MODE_DEFAULT |
 			DIB3000MC_SMO_MODE_188);
 
 	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
 	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
 */
-	
+
 /* diversity */
 	wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
 	wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
@@ -659,7 +659,7 @@ static int dib3000mc_fe_init(struct dvb_
 }
 static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	u16 lock = rd(DIB3000MC_REG_LOCKING);
 
 	*stat = 0;
@@ -679,14 +679,14 @@ static int dib3000mc_read_status(struct 
 
 static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	*ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
 	return 0;
 }
 
 static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
 	*unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
 	return 0;
@@ -695,7 +695,7 @@ static int dib3000mc_read_unc_blocks(str
 /* see dib3000mb.c for calculation comments */
 static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
 	*strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
 
@@ -706,7 +706,7 @@ static int dib3000mc_read_signal_strengt
 /* see dib3000mb.c for calculation comments */
 static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB),
 		val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB);
 	u16 sig,noise;
@@ -726,7 +726,7 @@ static int dib3000mc_read_snr(struct dvb
 
 static int dib3000mc_sleep(struct dvb_frontend* fe)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state* state = fe->demodulator_priv;
 
 	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
 	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
@@ -756,7 +756,7 @@ static int dib3000mc_set_frontend_and_tu
 
 static void dib3000mc_release(struct dvb_frontend* fe)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -765,17 +765,17 @@ static int dib3000mc_pid_control(struct 
 {
 	struct dib3000_state *state = fe->demodulator_priv;
 	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-		wr(index+DIB3000MC_REG_FIRST_PID,pid);
+	wr(index+DIB3000MC_REG_FIRST_PID,pid);
 	return 0;
 }
 
 static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-	
+
 	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
-	
+
 	if (onoff) {
 		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
@@ -790,14 +790,12 @@ static int dib3000mc_pid_parse(struct dv
 {
 	struct dib3000_state *state = fe->demodulator_priv;
 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-	
+
 	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
-	
+
 	if (onoff) {
-		deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_PID_PARSE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
 		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
 	} else {
-		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
 	}
 	return 0;
@@ -805,7 +803,7 @@ static int dib3000mc_pid_parse(struct dv
 
 static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
 {
-	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dib3000_state *state = fe->demodulator_priv;
 	if (onoff) {
 		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
 	} else {
@@ -814,7 +812,7 @@ static int dib3000mc_tuner_pass_ctrl(str
 	return 0;
 }
 
-static int dib3000mc_demod_init(struct dib3000_state *state) 
+static int dib3000mc_demod_init(struct dib3000_state *state)
 {
 	u16 default_addr = 0x0a;
 	/* first init */
@@ -822,13 +820,13 @@ static int dib3000mc_demod_init(struct d
 		deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr);
 		wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
 		wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
-		
+
 		wr(DIB3000MC_REG_RST_I2C_ADDR,
 			DIB3000MC_DEMOD_ADDR(default_addr) |
 			DIB3000MC_DEMOD_ADDR_ON);
-	
+
 		state->config.demod_address = default_addr;
-		
+
 		wr(DIB3000MC_REG_RST_I2C_ADDR,
 			DIB3000MC_DEMOD_ADDR(default_addr));
 	} else
@@ -846,9 +844,10 @@ struct dvb_frontend* dib3000mc_attach(co
 	u16 devid;
 
 	/* allocate memory for the internal state */
-	state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
+	memset(state,0,sizeof(struct dib3000_state));
 
 	/* setup the state */
 	state->i2c = i2c;
@@ -865,10 +864,10 @@ struct dvb_frontend* dib3000mc_attach(co
 
 	switch (devid) {
 		case DIB3000MC_DEVICE_ID:
-			info("Found a DiBcom 3000-MC, interesting...");
+			info("Found a DiBcom 3000M-C, interesting...");
 			break;
 		case DIB3000P_DEVICE_ID:
-			info("Found a DiBcom 3000-P.");
+			info("Found a DiBcom 3000P.");
 			break;
 	}
 
@@ -887,18 +886,17 @@ struct dvb_frontend* dib3000mc_attach(co
 	return &state->frontend;
 
 error:
-	if (state)
-		kfree(state);
+	kfree(state);
 	return NULL;
 }
 
 static struct dvb_frontend_ops dib3000mc_ops = {
 
 	.info = {
-		.name			= "DiBcom 3000-MC/P DVB-T",
-		.type 			= FE_OFDM,
-		.frequency_min 		= 44250000,
-		.frequency_max 		= 867250000,
+		.name			= "DiBcom 3000P/M-C DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
 		.frequency_stepsize	= 62500,
 		.caps = FE_CAN_INVERSION_AUTO |
 				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
--- a/drivers/media/dvb/frontends/dib3000mc_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mc_priv.h
@@ -187,7 +187,7 @@ static u16 dib3000mc_reg_agc_bandwidth_g
 static u16 dib3000mc_agc_bandwidth_general[] =
 	{ 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
 
-#define DIB3000MC_REG_IMP_NOISE_55 		(    55)
+#define DIB3000MC_REG_IMP_NOISE_55		(    55)
 #define DIB3000MC_IMP_NEW_ALGO(w)		(w | (1<<10))
 
 /* Impulse noise params */
@@ -209,14 +209,14 @@ static u16 dib3000mc_fft_modes[][29] = {
 	{	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
 		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
 		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
-	  	0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
-	  	0x3ffe, 0x5b3, 0x3feb, 0x76,   0x0, 0xd
+		0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+		0x3ffe, 0x5b3, 0x3feb, 0x76,   0x0, 0xd
 	}, /* fft mode 0 */
 	{	0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
 		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
 		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
-	  	0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
-	  	0x3ffe, 0x5b3, 0x3feb, 0x0,  0x8200, 0xd
+		0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+		0x3ffe, 0x5b3, 0x3feb, 0x0,  0x8200, 0xd
 	}, /* fft mode 1 */
 };
 
@@ -299,7 +299,7 @@ static u16 dib3000mc_mobile_mode[][5] = 
  *              |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
  *              |||+------ pid_parse (1 = enabled, 0 = disabled)
  *              ||+------- outp_188  (1 = TS packet size 188, 0 = packet size 204)
- *              |+-------- unk 
+ *              |+-------- unk
  *              +--------- unk
  */
 
@@ -320,7 +320,7 @@ static u16 dib3000mc_mobile_mode[][5] = 
  * pidfilter
  * it is not a hardware pidfilter but a filter which drops all pids
  * except the ones set. When connected to USB1.1 bandwidth this is important.
- * DiB3000-MC/P can filter up to 32 PIDs
+ * DiB3000P/M-C can filter up to 32 PIDs
  */
 #define DIB3000MC_REG_FIRST_PID			(   212)
 #define DIB3000MC_NUM_PIDS				(    32)
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -0,0 +1,168 @@
+/*
+ * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $
+ *
+ * descriptions + helper functions for simple dvb plls.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it 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.
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "dvb-pll.h"
+
+/* ----------------------------------------------------------- */
+/* descriptions                                                */
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+	.name  = "Thomson dtt7579",
+	.min   = 177000000,
+	.max   = 858000000,
+	.count = 5,
+	.entries = {
+		{          0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */
+		{  443250000, 36166667, 166666, 0xb4, 0x02 },
+		{  542000000, 36166667, 166666, 0xb4, 0x08 },
+		{  771000000, 36166667, 166666, 0xbc, 0x08 },
+		{  999999999, 36166667, 166666, 0xf4, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+	.name  = "Thomson dtt7610",
+	.min   =  44000000,
+	.max   = 958000000,
+	.count = 3,
+	.entries = {
+		{ 157250000, 44000000, 62500, 0x8e, 0x39 },
+		{ 454000000, 44000000, 62500, 0x8e, 0x3a },
+		{ 999999999, 44000000, 62500, 0x8e, 0x3c },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
+
+static void thomson_dtt759x_bw(u8 *buf, int bandwidth)
+{
+	if (BANDWIDTH_7_MHZ == bandwidth)
+		buf[3] |= 0x10;
+}
+
+struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+	.name  = "Thomson dtt759x",
+	.min   = 177000000,
+	.max   = 896000000,
+	.setbw = thomson_dtt759x_bw,
+	.count = 6,
+	.entries = {
+		{          0, 36166667, 166666, 0x84, 0x03 },
+		{  264000000, 36166667, 166666, 0xb4, 0x02 },
+		{  470000000, 36166667, 166666, 0xbc, 0x02 },
+		{  735000000, 36166667, 166666, 0xbc, 0x08 },
+		{  835000000, 36166667, 166666, 0xf4, 0x08 },
+		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
+
+struct dvb_pll_desc dvb_pll_lg_z201 = {
+	.name  = "LG z201",
+	.min   = 174000000,
+	.max   = 862000000,
+	.count = 5,
+	.entries = {
+		{          0, 36166667, 166666, 0xbc, 0x03 },
+		{  443250000, 36166667, 166666, 0xbc, 0x01 },
+		{  542000000, 36166667, 166666, 0xbc, 0x02 },
+		{  830000000, 36166667, 166666, 0xf4, 0x02 },
+		{  999999999, 36166667, 166666, 0xfc, 0x02 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_lg_z201);
+
+struct dvb_pll_desc dvb_pll_unknown_1 = {
+	.name  = "unknown 1", /* used by dntv live dvb-t */
+	.min   = 174000000,
+	.max   = 862000000,
+	.count = 9,
+	.entries = {
+		{  150000000, 36166667, 166666, 0xb4, 0x01 },
+		{  173000000, 36166667, 166666, 0xbc, 0x01 },
+		{  250000000, 36166667, 166666, 0xb4, 0x02 },
+		{  400000000, 36166667, 166666, 0xbc, 0x02 },
+		{  420000000, 36166667, 166666, 0xf4, 0x02 },
+		{  470000000, 36166667, 166666, 0xfc, 0x02 },
+		{  600000000, 36166667, 166666, 0xbc, 0x08 },
+		{  730000000, 36166667, 166666, 0xf4, 0x08 },
+		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_unknown_1);
+
+/* ----------------------------------------------------------- */
+/* code                                                        */
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+		      u32 freq, int bandwidth)
+{
+	u32 div;
+	int i;
+
+	if (freq != 0 && (freq < desc->min || freq > desc->max))
+	    return -EINVAL;
+
+	for (i = 0; i < desc->count; i++) {
+		if (freq > desc->entries[i].limit)
+			continue;
+		break;
+	}
+	if (debug)
+		printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
+		       desc->name, freq, bandwidth, i, desc->count);
+	BUG_ON(i == desc->count);
+
+	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
+	buf[0] = div >> 8;
+	buf[1] = div & 0xff;
+	buf[2] = desc->entries[i].cb1;
+	buf[3] = desc->entries[i].cb2;
+
+	if (desc->setbw)
+		desc->setbw(buf, bandwidth);
+
+	if (debug)
+		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+		       desc->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_pll_configure);
+
+MODULE_DESCRIPTION("dvb pll library");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -0,0 +1,32 @@
+/*
+ * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $
+ */
+
+#ifndef __DVB_PLL_H__
+#define __DVB_PLL_H__
+
+struct dvb_pll_desc {
+	char *name;
+	u32  min;
+	u32  max;
+	void (*setbw)(u8 *buf, int bandwidth);
+	int  count;
+	struct {
+		u32 limit;
+		u32 offset;
+		u32 stepsize;
+		u8  cb1;
+		u8  cb2;
+	} entries[9];
+};
+
+extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
+extern struct dvb_pll_desc dvb_pll_lg_z201;
+extern struct dvb_pll_desc dvb_pll_unknown_1;
+
+int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+		      u32 freq, int bandwidth);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -1,5 +1,5 @@
-/* 
- *  Driver for Dummy Frontend 
+/*
+ *  Driver for Dummy Frontend
  *
  *  Written by Emard <emard@softhome.net>
  *
@@ -17,7 +17,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., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */    
+ */
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,52 +27,50 @@
 #include "dvb_dummy_fe.h"
 
 
-
 struct dvb_dummy_fe_state {
-
 	struct dvb_frontend_ops ops;
-
 	struct dvb_frontend frontend;
 };
 
+
 static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
-	{
-		*status = FE_HAS_SIGNAL
-			| FE_HAS_CARRIER
-			| FE_HAS_VITERBI
-			| FE_HAS_SYNC
-			| FE_HAS_LOCK;
+{
+	*status = FE_HAS_SIGNAL
+		| FE_HAS_CARRIER
+		| FE_HAS_VITERBI
+		| FE_HAS_SYNC
+		| FE_HAS_LOCK;
 
 	return 0;
-	}
+}
 
 static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber)
-	{
-		*ber = 0;
+{
+	*ber = 0;
 	return 0;
-	}
+}
 
 static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-	{
+{
 	*strength = 0;
 	return 0;
-	}
+}
 
 static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr)
-	{
+{
 	*snr = 0;
 	return 0;
-	}
+}
 
 static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
 	*ucblocks = 0;
-		return 0;
+	return 0;
 }
 
 static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-		return 0;
+	return 0;
 }
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
@@ -82,18 +80,18 @@ static int dvb_dummy_fe_set_frontend(str
 
 static int dvb_dummy_fe_sleep(struct dvb_frontend* fe)
 {
-		return 0;
+	return 0;
 }
 
 static int dvb_dummy_fe_init(struct dvb_frontend* fe)
 {
 	return 0;
-        }
+}
 
 static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-        return 0;
-} 
+	return 0;
+}
 
 static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
@@ -102,7 +100,7 @@ static int dvb_dummy_fe_set_voltage(stru
 
 static void dvb_dummy_fe_release(struct dvb_frontend* fe)
 {
-	struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv;
+	struct dvb_dummy_fe_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -113,7 +111,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_a
 	struct dvb_dummy_fe_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -125,7 +123,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_a
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -136,7 +134,7 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_a
 	struct dvb_dummy_fe_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -159,7 +157,7 @@ struct dvb_frontend* dvb_dummy_fe_qam_at
 	struct dvb_dummy_fe_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -179,9 +177,9 @@ static struct dvb_frontend_ops dvb_dummy
 
 	.info = {
 		.name			= "Dummy DVB-T",
-		.type 			= FE_OFDM,
-		.frequency_min 		= 0,
-		.frequency_max 		= 863250000,
+		.type			= FE_OFDM,
+		.frequency_min		= 0,
+		.frequency_max		= 863250000,
 		.frequency_stepsize	= 62500,
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 				FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
@@ -211,12 +209,12 @@ static struct dvb_frontend_ops dvb_dummy
 
 	.info = {
 		.name			= "Dummy DVB-C",
-		.type 			= FE_QAM,
+		.type			= FE_QAM,
 		.frequency_stepsize	= 62500,
-		.frequency_min 		= 51000000,
-		.frequency_max 		= 858000000,
-		.symbol_rate_min 	= (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
-		.symbol_rate_max 	= (57840000/2)/4,      /* SACLK/4 */
+		.frequency_min		= 51000000,
+		.frequency_max		= 858000000,
+		.symbol_rate_min	= (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
+		.symbol_rate_max	= (57840000/2)/4,      /* SACLK/4 */
 		.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
 			FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
@@ -240,14 +238,14 @@ static struct dvb_frontend_ops dvb_dummy
 static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
 
 	.info = {
-		.name 			= "Dummy DVB-S",
-		.type 			= FE_QPSK,
-		.frequency_min 		= 950000,
-		.frequency_max 		= 2150000,
-		.frequency_stepsize 	= 250,           /* kHz for QPSK frontends */
-		.frequency_tolerance 	= 29500,
-		.symbol_rate_min 	= 1000000,
-		.symbol_rate_max 	= 45000000,
+		.name			= "Dummy DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 250,           /* kHz for QPSK frontends */
+		.frequency_tolerance	= 29500,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
 		.caps = FE_CAN_INVERSION_AUTO |
 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
@@ -269,7 +267,7 @@ static struct dvb_frontend_ops dvb_dummy
 	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
 
 	.set_voltage = dvb_dummy_fe_set_voltage,
-     	.set_tone = dvb_dummy_fe_set_tone,
+	.set_tone = dvb_dummy_fe_set_tone,
 };
 
 MODULE_DESCRIPTION("DVB DUMMY Frontend");
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -1,9 +1,8 @@
 /*
     driver for LSI L64781 COFDM demodulator
 
-    Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
-                       for Convergence Integrated Media GmbH
-                       Marko Kohtala <marko.kohtala@nokia.com>
+    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+                       Marko Kohtala <marko.kohtala@luukku.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
@@ -32,17 +31,13 @@
 
 
 struct l64781_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	const struct l64781_config* config;
-
 	struct dvb_frontend frontend;
 
 	/* private demodulator data */
-   	int first:1;
+	int first:1;
 };
 
 #define dprintk(args...) \
@@ -126,7 +121,7 @@ static int reset_and_configure (struct l
 
 static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
 	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
 	/* QPSK, QAM_16, QAM_64 */
@@ -239,7 +234,7 @@ static int apply_frontend_param (struct 
 
 static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 	int tmp;
 
 
@@ -357,7 +352,7 @@ static int get_frontend(struct dvb_front
 
 static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 	int sync = l64781_readreg (state, 0x32);
 	int gain = l64781_readreg (state, 0x0e);
 
@@ -386,7 +381,7 @@ static int l64781_read_status(struct dvb
 
 static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
 	/*   XXX FIXME: set up counting period (reg 0x26...0x28)
 	 */
@@ -398,7 +393,7 @@ static int l64781_read_ber(struct dvb_fr
 
 static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
 	u8 gain = l64781_readreg (state, 0x0e);
 	*signal_strength = (gain << 8) | gain;
@@ -408,7 +403,7 @@ static int l64781_read_signal_strength(s
 
 static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
 	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
 	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
@@ -418,7 +413,7 @@ static int l64781_read_snr(struct dvb_fr
 
 static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
 	*ucblocks = l64781_readreg (state, 0x37)
 	   | (l64781_readreg (state, 0x38) << 8);
@@ -428,7 +423,7 @@ static int l64781_read_ucblocks(struct d
 
 static int l64781_sleep(struct dvb_frontend* fe)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
 	/* Power down */
 	return l64781_writereg (state, 0x3e, 0x5a);
@@ -436,7 +431,7 @@ static int l64781_sleep(struct dvb_front
 
 static int l64781_init(struct dvb_frontend* fe)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 
         reset_and_configure (state);
 
@@ -489,7 +484,7 @@ static int l64781_get_tune_settings(stru
 
 static void l64781_release(struct dvb_frontend* fe)
 {
-	struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+	struct l64781_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -506,7 +501,7 @@ struct dvb_frontend* l64781_attach(const
 			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
 	/* allocate memory for the internal state */
-	state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -544,7 +539,7 @@ struct dvb_frontend* l64781_attach(const
 
 	/* Responds to all reads with 0 */
 	if (l64781_readreg(state, 0x1a) != 0) {
- 	        dprintk("Read 1 returned unexpcted value\n");
+	        dprintk("Read 1 returned unexpcted value\n");
 		goto error;
 	}
 
@@ -553,7 +548,7 @@ struct dvb_frontend* l64781_attach(const
 
 	/* Responds with register default value */
 	if (l64781_readreg(state, 0x1a) != 0xa1) {
- 	        dprintk("Read 2 returned unexpcted value\n");
+	        dprintk("Read 2 returned unexpcted value\n");
 		goto error;
 	}
 
@@ -564,7 +559,7 @@ struct dvb_frontend* l64781_attach(const
 
 error:
 	if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -581,10 +576,10 @@ static struct dvb_frontend_ops l64781_op
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
 		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-        	      FE_CAN_MUTE_TS
+		      FE_CAN_MUTE_TS
 	},
 
-     	.release = l64781_release,
+	.release = l64781_release,
 
 	.init = l64781_init,
 	.sleep = l64781_sleep,
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -1,9 +1,8 @@
 /*
     driver for LSI L64781 COFDM demodulator
 
-    Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
-                       for Convergence Integrated Media GmbH
-                       Marko Kohtala <marko.kohtala@nokia.com>
+    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+                       Marko Kohtala <marko.kohtala@luukku.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
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -1,4 +1,4 @@
-/* 
+/*
     Driver for Zarlink VP310/MT312 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
@@ -36,14 +36,10 @@
 
 
 struct mt312_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct mt312_config* config;
-
 	struct dvb_frontend frontend;
 
 	u8 id;
@@ -128,7 +124,7 @@ static int mt312_write(struct mt312_stat
 }
 
 static inline int mt312_readreg(struct mt312_state* state,
-				const enum mt312_reg_addr reg, u8 * val)
+				const enum mt312_reg_addr reg, u8 *val)
 {
 	return mt312_read(state, reg, val, 1);
 }
@@ -181,7 +177,7 @@ static int mt312_get_symbol_rate(struct 
 			return ret;
 
 		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
-		return ret;
+			return ret;
 
 		monitor = (buf[0] << 8) | buf[1];
 
@@ -206,7 +202,7 @@ static int mt312_get_symbol_rate(struct 
 		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
 		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
 			2) - dec_ratio);
-}
+	}
 
 	return 0;
 }
@@ -226,25 +222,11 @@ static int mt312_get_code_rate(struct mt
 	*cr = fec_tab[(fec_status >> 4) & 0x07];
 
 	return 0;
-	}
-
-
-
-
-
-
-
-
-	
-
-
-
-
-
+}
 
 static int mt312_initfe(struct dvb_frontend* fe)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
@@ -305,7 +287,7 @@ static int mt312_initfe(struct dvb_front
 static int mt312_send_master_cmd(struct dvb_frontend* fe,
 				 struct dvb_diseqc_master_cmd *c)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 diseqc_mode;
 
@@ -336,7 +318,7 @@ static int mt312_send_master_cmd(struct 
 
 static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	const u8 mini_tab[2] = { 0x02, 0x03 };
 
 	int ret;
@@ -358,7 +340,7 @@ static int mt312_send_burst(struct dvb_f
 
 static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	const u8 tone_tab[2] = { 0x01, 0x00 };
 
 	int ret;
@@ -380,7 +362,7 @@ static int mt312_set_tone(struct dvb_fro
 
 static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
 
 	if (v > SEC_VOLTAGE_OFF)
@@ -391,7 +373,7 @@ static int mt312_set_voltage(struct dvb_
 
 static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 status[3];
 
@@ -418,7 +400,7 @@ static int mt312_read_status(struct dvb_
 
 static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[3];
 
@@ -432,7 +414,7 @@ static int mt312_read_ber(struct dvb_fro
 
 static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[3];
 	u16 agc;
@@ -453,7 +435,7 @@ static int mt312_read_signal_strength(st
 
 static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
@@ -467,7 +449,7 @@ static int mt312_read_snr(struct dvb_fro
 
 static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
@@ -482,7 +464,7 @@ static int mt312_read_ucblocks(struct dv
 static int mt312_set_frontend(struct dvb_frontend* fe,
 			      struct dvb_frontend_parameters *p)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[5], config_val;
 	u16 sr;
@@ -525,7 +507,7 @@ static int mt312_set_frontend(struct dvb
 				state->frequency = 90;
 				if ((ret = mt312_initfe(fe)) < 0)
 					return ret;
-		}
+			}
 		}
 		else
 		{
@@ -533,7 +515,7 @@ static int mt312_set_frontend(struct dvb
 				state->frequency = 60;
 				if ((ret = mt312_initfe(fe)) < 0)
 					return ret;
-		}
+			}
 		}
 		break;
 
@@ -578,7 +560,7 @@ static int mt312_set_frontend(struct dvb
 static int mt312_get_frontend(struct dvb_frontend* fe,
 			      struct dvb_frontend_parameters *p)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 
 	if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
@@ -595,7 +577,7 @@ static int mt312_get_frontend(struct dvb
 
 static int mt312_sleep(struct dvb_frontend* fe)
 {
-	struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 config;
 
@@ -614,16 +596,16 @@ static int mt312_sleep(struct dvb_fronte
 }
 
 static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-	{
-	        fesettings->min_delay_ms = 50;
-	        fesettings->step_size = 0;
-	        fesettings->max_drift = 0;
-	        return 0;
-	}	    
+{
+	fesettings->min_delay_ms = 50;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
 
 static void mt312_release(struct dvb_frontend* fe)
 {
-	struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv;
+	struct mt312_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -635,7 +617,7 @@ struct dvb_frontend* vp310_attach(const 
 	struct mt312_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
 
@@ -653,14 +635,13 @@ struct dvb_frontend* vp310_attach(const 
 	}
 
 	/* create dvb_frontend */
-		state->frequency = 90;
+	state->frequency = 90;
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
 error:
-	if (state)
-		kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -670,7 +651,7 @@ struct dvb_frontend* mt312_attach(const 
 	struct mt312_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
 
@@ -685,7 +666,7 @@ struct dvb_frontend* mt312_attach(const 
 		goto error;
 	if (state->id != ID_MT312) {
 		goto error;
-}
+	}
 
 	/* create dvb_frontend */
 	state->frequency = 60;
@@ -716,7 +697,7 @@ static struct dvb_frontend_ops vp310_mt3
 	            FE_CAN_RECOVER
 	},
 
-     	.release = mt312_release,
+	.release = mt312_release,
 
 	.init = mt312_initfe,
 	.sleep = mt312_sleep,
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -1,4 +1,4 @@
-/* 
+/*
     Driver for Zarlink MT312 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -41,96 +41,134 @@
 #include "mt352.h"
 
 struct mt352_state {
-
 	struct i2c_adapter* i2c;
-
+	struct dvb_frontend frontend;
 	struct dvb_frontend_ops ops;
 
 	/* configuration settings */
-	const struct mt352_config* config;
-
-	struct dvb_frontend frontend;
+	struct mt352_config config;
 };
 
 static int debug;
 #define dprintk(args...) \
-do {									\
+	do { \
 		if (debug) printk(KERN_DEBUG "mt352: " args); \
-} while (0)
+	} while (0)
 
 static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0,
+	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
 			       .buf = buf, .len = 2 };
 	int err = i2c_transfer(state->i2c, &msg, 1);
 	if (err != 1) {
-		dprintk("mt352_write() to reg %x failed (err = %d)!\n", reg, err);
+		printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err);
 		return err;
-}
-	return 0; 
+	}
+	return 0;
 }
 
 int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
 {
 	int err,i;
 	for (i=0; i < ilen-1; i++)
-		if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) 
+		if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1])))
 			return err;
 
 	return 0;
 }
 
-static u8 mt352_read_register(struct mt352_state* state, u8 reg)
+static int mt352_read_register(struct mt352_state* state, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
 	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address,
+	struct i2c_msg msg [] = { { .addr = state->config.demod_address,
 				    .flags = 0,
 				    .buf = b0, .len = 1 },
-				  { .addr = state->config->demod_address,
+				  { .addr = state->config.demod_address,
 				    .flags = I2C_M_RD,
 				    .buf = b1, .len = 1 } };
 
 	ret = i2c_transfer(state->i2c, msg, 2);
 
-	if (ret != 2)
-		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+	if (ret != 2) {
+		printk("%s: readreg error (reg=%d, ret==%i)\n",
+		       __FUNCTION__, reg, ret);
+		return ret;
+	}
 
 	return b1[0];
 }
 
-u8 mt352_read(struct dvb_frontend *fe, u8 reg)
-{
-	return mt352_read_register(fe->demodulator_priv,reg);
-}
-
-
-
-
-
-
-
-
 static int mt352_sleep(struct dvb_frontend* fe)
 {
 	static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
 
 	mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
-
 	return 0;
 }
 
+static void mt352_calc_nominal_rate(struct mt352_state* state,
+				    enum fe_bandwidth bandwidth,
+				    unsigned char *buf)
+{
+	u32 adc_clock = 20480; /* 20.340 MHz */
+	u32 bw,value;
+
+	switch (bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		bw = 6;
+		break;
+	case BANDWIDTH_7_MHZ:
+		bw = 7;
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		bw = 8;
+		break;
+	}
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+
+	value = 64 * bw * (1<<16) / (7 * 8);
+	value = value * 1000 / adc_clock;
+	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+		__FUNCTION__, bw, adc_clock, value);
+	buf[0] = msb(value);
+	buf[1] = lsb(value);
+}
+
+static void mt352_calc_input_freq(struct mt352_state* state,
+				  unsigned char *buf)
+{
+	int adc_clock = 20480; /* 20.480000 MHz */
+	int if2       = 36167; /* 36.166667 MHz */
+	int ife,value;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+	if (state->config.if2)
+		if2 = state->config.if2;
+
+	ife = (2*adc_clock - if2);
+	value = -16374 * ife / adc_clock;
+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
+	buf[0] = msb(value);
+	buf[1] = lsb(value);
+}
+
 static int mt352_set_parameters(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *param)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
-	unsigned char buf[14];
+	struct mt352_state* state = fe->demodulator_priv;
+	unsigned char buf[13];
+	static unsigned char tuner_go[] = { 0x5d, 0x01 };
+	static unsigned char fsm_go[]   = { 0x5e, 0x01 };
 	unsigned int tps = 0;
 	struct dvb_ofdm_parameters *op = &param->u.ofdm;
-	int i;
 
 	switch (op->code_rate_HP) {
 		case FEC_2_3:
@@ -241,46 +279,28 @@ static int mt352_set_parameters(struct d
 	buf[1] = msb(tps);      /* TPS_GIVEN_(1|0) */
 	buf[2] = lsb(tps);
 
-	buf[3] = 0x50;
-
-	/**
-	 *  these settings assume 20.48MHz f_ADC, for other tuners you might
-	 *  need other values. See p. 33 in the MT352 Design Manual.
-	 */
-	if (op->bandwidth == BANDWIDTH_8_MHZ) {
-		buf[4] = 0x72;  /* TRL_NOMINAL_RATE_(1|0) */
-		buf[5] = 0x49;
-	} else if (op->bandwidth == BANDWIDTH_7_MHZ) {
-		buf[4] = 0x64;
-		buf[5] = 0x00;
-	} else {		/* 6MHz */
-		buf[4] = 0x55;
-		buf[5] = 0xb7;
-	}
-
-	buf[6] = 0x31;  /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */
-	buf[7] = 0x05;  /* see MT352 Design Manual page 32 for details */
-
-	state->config->pll_set(fe, param, buf+8);
-
-	buf[13] = 0x01; /* TUNER_GO!! */
-
-	/* Only send the tuning request if the tuner doesn't have the requested
-	 * parameters already set.  Enhances tuning time and prevents stream
-	 * breakup when retuning the same transponder. */
-	for (i = 1; i < 13; i++)
-		if (buf[i] != mt352_read_register(state, i + 0x50)) {
-			mt352_write(fe, buf, sizeof(buf));
-			break;
-		}
+	buf[3] = 0x50;  // old
+//	buf[3] = 0xf4;  // pinnacle
 
+	mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
+	mt352_calc_input_freq(state, buf+6);
+	state->config.pll_set(fe, param, buf+8);
+
+	mt352_write(fe, buf, sizeof(buf));
+	if (state->config.no_tuner) {
+		/* start decoding */
+		mt352_write(fe, fsm_go, 2);
+	} else {
+		/* start tuning */
+		mt352_write(fe, tuner_go, 2);
+	}
 	return 0;
 }
 
 static int mt352_get_parameters(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *param)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 	u16 tps;
 	u16 div;
 	u8 trl;
@@ -298,9 +318,7 @@ static int mt352_get_parameters(struct d
 	};
 
 	if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
-	{
 		return -EINVAL;
-	}
 
 	/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
 	 * the mt352 sometimes works with the wrong parameters
@@ -371,17 +389,11 @@ static int mt352_get_parameters(struct d
 	param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
 
 	if (trl == 0x72)
-	{
 		op->bandwidth = BANDWIDTH_8_MHZ;
-	}
 	else if (trl == 0x64)
-	{
 		op->bandwidth = BANDWIDTH_7_MHZ;
-	}
 	else
-	{
 		op->bandwidth = BANDWIDTH_6_MHZ;
-	}
 
 
 	if (mt352_read_register(state, STATUS_2) & 0x02)
@@ -394,25 +406,39 @@ static int mt352_get_parameters(struct d
 
 static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
-	u8 r;
+	struct mt352_state* state = fe->demodulator_priv;
+	int s0, s1, s3;
+
+	/* FIXME:
+	 *
+	 * The MT352 design manual from Zarlink states (page 46-47):
+	 *
+	 * Notes about the TUNER_GO register:
+	 *
+	 * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status
+	 * byte is copied from the tuner to the STATUS_3 register and
+	 * completion of the read operation is indicated by bit-5 of the
+	 * INTERRUPT_3 register.
+	 */
 
-		*status = 0;
-	r = mt352_read_register (state, STATUS_0);
-		if (r & (1 << 4))
-			*status = FE_HAS_CARRIER;
-		if (r & (1 << 1))
-			*status |= FE_HAS_VITERBI;
-		if (r & (1 << 5))
-			*status |= FE_HAS_LOCK;
-
-	r = mt352_read_register (state, STATUS_1);
-		if (r & (1 << 1))
-			*status |= FE_HAS_SYNC;
-
-	r = mt352_read_register (state, STATUS_3);
-		if (r & (1 << 6))
-			*status |= FE_HAS_SIGNAL;
+	if ((s0 = mt352_read_register(state, STATUS_0)) < 0)
+		return -EREMOTEIO;
+	if ((s1 = mt352_read_register(state, STATUS_1)) < 0)
+		return -EREMOTEIO;
+	if ((s3 = mt352_read_register(state, STATUS_3)) < 0)
+		return -EREMOTEIO;
+
+	*status = 0;
+	if (s0 & (1 << 4))
+		*status |= FE_HAS_CARRIER;
+	if (s0 & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+	if (s0 & (1 << 5))
+		*status |= FE_HAS_LOCK;
+	if (s1 & (1 << 1))
+		*status |= FE_HAS_SYNC;
+	if (s3 & (1 << 6))
+		*status |= FE_HAS_SIGNAL;
 
 	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
 		      (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
@@ -423,21 +449,21 @@ static int mt352_read_status(struct dvb_
 
 static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 
 	*ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
 	       (mt352_read_register (state, RS_ERR_CNT_1) << 8) |
 	       (mt352_read_register (state, RS_ERR_CNT_0));
 
-			return 0;
-	}
+	return 0;
+}
 
 static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 
-	u16 signal = (mt352_read_register (state, AGC_GAIN_3) << 8) |
-		     (mt352_read_register (state, AGC_GAIN_2));
+	u16 signal = ((mt352_read_register(state, AGC_GAIN_1) << 8) & 0x0f) |
+		      (mt352_read_register(state, AGC_GAIN_0));
 
 	*strength = ~signal;
 	return 0;
@@ -445,7 +471,7 @@ static int mt352_read_signal_strength(st
 
 static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 
 	u8 _snr = mt352_read_register (state, SNR);
 	*snr = (_snr << 8) | _snr;
@@ -455,13 +481,13 @@ static int mt352_read_snr(struct dvb_fro
 
 static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 
 	*ucblocks = (mt352_read_register (state,  RS_UBC_1) << 8) |
 		    (mt352_read_register (state,  RS_UBC_0));
 
 	return 0;
-	}
+}
 
 static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
 {
@@ -470,30 +496,32 @@ static int mt352_get_tune_settings(struc
 	fe_tune_settings->max_drift = 0;
 
 	return 0;
-	}
+}
 
 static int mt352_init(struct dvb_frontend* fe)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	struct mt352_state* state = fe->demodulator_priv;
 
 	static u8 mt352_reset_attach [] = { RESET, 0xC0 };
 
+	dprintk("%s: hello\n",__FUNCTION__);
+
 	if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
 	    (mt352_read_register(state, CONFIG) & 0x20) == 0) {
 
-	/* Do a "hard" reset */
+		/* Do a "hard" reset */
 		mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
-		return state->config->demod_init(fe);
+		return state->config.demod_init(fe);
 	}
 
 	return 0;
-	}
+}
 
 static void mt352_release(struct dvb_frontend* fe)
 {
-	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
-		kfree(state);
-	}
+	struct mt352_state* state = fe->demodulator_priv;
+	kfree(state);
+}
 
 static struct dvb_frontend_ops mt352_ops;
 
@@ -503,12 +531,13 @@ struct dvb_frontend* mt352_attach(const 
 	struct mt352_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
 	if (state == NULL) goto error;
+	memset(state,0,sizeof(*state));
 
 	/* setup the state */
-	state->config = config;
 	state->i2c = i2c;
+	memcpy(&state->config,config,sizeof(struct mt352_config));
 	memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
@@ -520,7 +549,7 @@ struct dvb_frontend* mt352_attach(const 
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -567,4 +596,3 @@ MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(mt352_attach);
 EXPORT_SYMBOL(mt352_write);
-EXPORT_SYMBOL(mt352_read);
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -40,6 +40,13 @@ struct mt352_config
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
+	/* frequencies in kHz */
+	int adc_clock;  // default: 20480
+	int if2;        // default: 36166
+
+	/* set if no pll is connected to the secondary i2c bus */
+	int no_tuner;
+
 	/* Initialise the demodulator and PLL. Cannot be NULL */
 	int (*demod_init)(struct dvb_frontend* fe);
 
@@ -54,6 +61,5 @@ extern struct dvb_frontend* mt352_attach
 					 struct i2c_adapter* i2c);
 
 extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
-extern u8 mt352_read(struct dvb_frontend *fe, u8 reg);
 
 #endif // MT352_H
diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c
--- a/drivers/media/dvb/frontends/nxt2002.c
+++ b/drivers/media/dvb/frontends/nxt2002.c
@@ -1,5 +1,5 @@
 /*
-    Support for B2C2/BBTI Technisat Air2PC - ATSC  
+    Support for B2C2/BBTI Technisat Air2PC - ATSC
 
     Copyright (C) 2004 Taylor Jacob <rtjacob@earthlink.net>
 
@@ -59,7 +59,7 @@ static int i2c_writebytes (struct nxt200
 	u8 buf2 [256],x;
 	int err;
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
-       
+
 	buf2[0] = reg;
 	for (x = 0 ; x < len ; x++)
 		buf2[x+1] = buf[x];
@@ -91,12 +91,12 @@ static u8 i2c_readbytes (struct nxt2002_
 	return 0;
 }
 
-static u16 nxt2002_crc(u16 crc, u8 c) 
+static u16 nxt2002_crc(u16 crc, u8 c)
 {
 
 	u8 i;
 	u16 input = (u16) c & 0xFF;
-  
+
 	input<<=8;
 	for(i=0 ;i<8 ;i++) {
 		if((crc ^ input) & 0x8000)
@@ -130,7 +130,7 @@ static int nxt2002_writereg_multibyte (s
 
 	if ((buf & 0x02) == 0)
 		return 0;
- 
+
 	dprintk("Error writing multireg register %02X\n",reg);
 
 	return 0;
@@ -162,16 +162,16 @@ static void nxt2002_microcontroller_stop
 	buf[0] = 0x80;
 	i2c_writebytes(state,0x22,buf,1);
 
-	while (counter < 20) { 
+	while (counter < 20) {
 		i2c_readbytes(state,0x31,buf,1);
-		if (buf[0] & 0x40) 
+		if (buf[0] & 0x40)
 			return;
 		msleep(10);
 		counter++;
 	}
 
 	dprintk("Timeout waiting for micro to stop.. This is ok after firmware upload\n");
-	return; 
+	return;
 }
 
 static void nxt2002_microcontroller_start (struct nxt2002_state* state)
@@ -211,7 +211,7 @@ static int nxt2002_writetuner (struct nx
 	/* write UC Opmode to begin transfer */
 	buf = 0x80;
 	i2c_writebytes(state,0x21,&buf,1);
- 
+
 	while (count < 20) {
 		i2c_readbytes(state,0x21,&buf,1);
 		if ((buf & 0x80)== 0x00)
@@ -241,9 +241,9 @@ static void nxt2002_agc_reset(struct nxt
 static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
 {
 
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 buf[256],written = 0,chunkpos = 0;
-	u16 rambase,position,crc = 0;  
+	u16 rambase,position,crc = 0;
 
 	dprintk("%s\n", __FUNCTION__);
 	dprintk("Firmware is %zu bytes\n",fw->size);
@@ -251,7 +251,6 @@ static int nxt2002_load_firmware (struct
 	/* Get the RAM base for this nxt2002 */
 	i2c_readbytes(state,0x10,buf,1);
 
-	
 	if (buf[0] & 0x10)
 		rambase = 0x1000;
 	else
@@ -263,7 +262,6 @@ static int nxt2002_load_firmware (struct
 	buf[0] = 0x80;
 	i2c_writebytes(state,0x2B,buf,1);
 
-        
 	for (position = 0; position < fw->size ; position++) {
 		if (written == 0) {
 			crc = 0;
@@ -274,7 +272,7 @@ static int nxt2002_load_firmware (struct
 			/* write starting address */
 			i2c_writebytes(state,0x29,buf,3);
 		}
-		written++;          
+		written++;
 		chunkpos++;
 
 		if ((written % 4) == 0)
@@ -282,7 +280,6 @@ static int nxt2002_load_firmware (struct
 
 		crc = nxt2002_crc(crc,fw->data[position]);
 
-            
 		if ((written == 255) || (position+1 == fw->size)) {
 			/* write remaining bytes of firmware */
 			i2c_writebytes(state, chunkpos+4-(written %4),
@@ -290,7 +287,7 @@ static int nxt2002_load_firmware (struct
 				written %4);
 			buf[0] = crc << 8;
 			buf[1] = crc & 0xFF;
-               
+
 			/* write crc */
 			i2c_writebytes(state,0x2C,buf,2);
 
@@ -309,24 +306,23 @@ static int nxt2002_load_firmware (struct
 	return 0;
 };
 
-
 static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe,
 					     struct dvb_frontend_parameters *p)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u32 freq = 0;
-	u16 tunerfreq = 0; 
+	u16 tunerfreq = 0;
 	u8 buf[4];
 
-	freq = 44000 + ( p->frequency / 1000 ); 
+	freq = 44000 + ( p->frequency / 1000 );
 
 	dprintk("freq = %d      p->frequency = %d\n",freq,p->frequency);
 
 	tunerfreq = freq * 24/4000;
- 
+
 	buf[0] = (tunerfreq >> 8) & 0x7F;
 	buf[1] = (tunerfreq & 0xFF);
-        
+
 	if (p->frequency <= 214000000) {
 		buf[2] = 0x84 + (0x06 << 3);
 		buf[3] = (p->frequency <= 172000000) ? 0x01 : 0x02;
@@ -337,7 +333,7 @@ static int nxt2002_setup_frontend_parame
 		buf[2] = 0x84 + (0x0E << 3);
 		buf[3] = 0x08;
 	} else {
-		buf[2] = 0x84 + (0x0F << 3);         
+		buf[2] = 0x84 + (0x0F << 3);
 		buf[3] = 0x02;
 	}
 
@@ -348,7 +344,18 @@ static int nxt2002_setup_frontend_parame
 	nxt2002_agc_reset(state);
 
 	/* set target power level */
-	buf[0] = 0x70;
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+		case QAM_256:
+				buf[0] = 0x74;
+				break;
+		case VSB_8:
+				buf[0] = 0x70;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
 	i2c_writebytes(state,0x42,buf,1);
 
 	/* configure sdm */
@@ -361,7 +368,20 @@ static int nxt2002_setup_frontend_parame
 	nxt2002_writereg_multibyte(state,0x58,buf,2);
 
 	/* write sdmx input */
-	buf[0] = 0x60;
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+				buf[0] = 0x68;
+				break;
+		case QAM_256:
+				buf[0] = 0x64;
+				break;
+		case VSB_8:
+				buf[0] = 0x60;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
 	buf[1] = 0x00;
 	nxt2002_writereg_multibyte(state,0x5C,buf,2);
 
@@ -391,7 +411,20 @@ static int nxt2002_setup_frontend_parame
 	i2c_writebytes(state,0x41,buf,1);
 
 	/* write agc ucgp0 */
-	buf[0] = 0x00;
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+				buf[0] = 0x02;
+				break;
+		case QAM_256:
+				buf[0] = 0x03;
+				break;
+		case VSB_8:
+				buf[0] = 0x00;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
 	i2c_writebytes(state,0x30,buf,1);
 
 	/* write agc control reg */
@@ -410,7 +443,7 @@ static int nxt2002_setup_frontend_parame
 
 	nxt2002_microcontroller_start(state);
 
-	/* adjacent channel detection should be done here, but I don't 
+	/* adjacent channel detection should be done here, but I don't
 	have any stations with this need so I cannot test it */
 
 	return 0;
@@ -418,7 +451,7 @@ static int nxt2002_setup_frontend_parame
 
 static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 lock;
 	i2c_readbytes(state,0x31,&lock,1);
 
@@ -427,7 +460,7 @@ static int nxt2002_read_status(struct dv
 		*status |= FE_HAS_SIGNAL;
 		*status |= FE_HAS_CARRIER;
 		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;                
+		*status |= FE_HAS_SYNC;
 		*status |= FE_HAS_LOCK;
 	}
 	return 0;
@@ -435,19 +468,19 @@ static int nxt2002_read_status(struct dv
 
 static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 b[3];
 
-	nxt2002_readreg_multibyte(state,0xE6,b,3);        
+	nxt2002_readreg_multibyte(state,0xE6,b,3);
 
 	*ber = ((b[0] << 8) + b[1]) * 8;
- 
+
 	return 0;
 }
 
 static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 b[2];
 	u16 temp = 0;
 
@@ -456,7 +489,7 @@ static int nxt2002_read_signal_strength(
 	i2c_writebytes(state,0xA1,b,1);
 
 	/* get multreg val */
-	nxt2002_readreg_multibyte(state,0xA6,b,2);        
+	nxt2002_readreg_multibyte(state,0xA6,b,2);
 
 	temp = (b[0] << 8) | b[1];
 	*strength = ((0x7FFF - temp) & 0x0FFF) * 16;
@@ -467,7 +500,7 @@ static int nxt2002_read_signal_strength(
 static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 b[2];
 	u16 temp = 0, temp2;
 	u32 snrdb = 0;
@@ -477,7 +510,7 @@ static int nxt2002_read_snr(struct dvb_f
 	i2c_writebytes(state,0xA1,b,1);
 
 	/* get multreg val from 0xA6 */
-	nxt2002_readreg_multibyte(state,0xA6,b,2);        
+	nxt2002_readreg_multibyte(state,0xA6,b,2);
 
 	temp = (b[0] << 8) | b[1];
 	temp2 = 0x7FFF - temp;
@@ -501,11 +534,10 @@ static int nxt2002_read_snr(struct dvb_f
 
 static int nxt2002_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	u8 b[3];
- 
-	nxt2002_readreg_multibyte(state,0xE6,b,3);
 
+	nxt2002_readreg_multibyte(state,0xE6,b,3);
 	*ucblocks = b[2];
 
 	return 0;
@@ -518,14 +550,14 @@ static int nxt2002_sleep(struct dvb_fron
 
 static int nxt2002_init(struct dvb_frontend* fe)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	const struct firmware *fw;
 	int ret;
 	u8 buf[2];
 
 	if (!state->initialised) {
 		/* request the firmware, this will block until someone uploads it */
-		printk("nxt2002: Waiting for firmware upload...\n");
+		printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
 		ret = state->config->request_firmware(fe, &fw, NXT2002_DEFAULT_FIRMWARE);
 		printk("nxt2002: Waiting for firmware upload(2)...\n");
 		if (ret) {
@@ -539,10 +571,11 @@ static int nxt2002_init(struct dvb_front
 			release_firmware(fw);
 			return ret;
 		}
+		printk("nxt2002: firmware upload complete\n");
 
 		/* Put the micro into reset */
 		nxt2002_microcontroller_stop(state);
- 
+
 		/* ensure transfer is complete */
 		buf[0]=0;
 		i2c_writebytes(state,0x2B,buf,1);
@@ -557,11 +590,11 @@ static int nxt2002_init(struct dvb_front
 		i2c_writebytes(state,0x08,buf,1);
 
 		/* write agc sdm configure */
-		buf[0] = 0xF1;		
+		buf[0] = 0xF1;
 		i2c_writebytes(state,0x57,buf,1);
 
 		/* write mod output format */
-		buf[0] = 0x20;		
+		buf[0] = 0x20;
 		i2c_writebytes(state,0x09,buf,1);
 
 		/* write fec mpeg mode */
@@ -589,7 +622,7 @@ static int nxt2002_get_tune_settings(str
 
 static void nxt2002_release(struct dvb_frontend* fe)
 {
-	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	struct nxt2002_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -602,7 +635,7 @@ struct dvb_frontend* nxt2002_attach(cons
 	u8 buf [] = {0,0,0,0,0};
 
 	/* allocate memory for the internal state */
-	state = (struct nxt2002_state*) kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -614,11 +647,11 @@ struct dvb_frontend* nxt2002_attach(cons
         /* Check the first 5 registers to ensure this a revision we can handle */
 
 	i2c_readbytes(state, 0x00, buf, 5);
-	if (buf[0] != 0x04) goto error; 		/* device id */
-	if (buf[1] != 0x02) goto error; 		/* fab id */
-	if (buf[2] != 0x11) goto error; 		/* month */
-	if (buf[3] != 0x20) goto error; 		/* year msb */
-	if (buf[4] != 0x00) goto error; 		/* year lsb */
+	if (buf[0] != 0x04) goto error;		/* device id */
+	if (buf[1] != 0x02) goto error;		/* fab id */
+	if (buf[2] != 0x11) goto error;		/* month */
+	if (buf[3] != 0x20) goto error;		/* year msb */
+	if (buf[4] != 0x00) goto error;		/* year lsb */
 
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
@@ -626,7 +659,7 @@ struct dvb_frontend* nxt2002_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -636,12 +669,12 @@ static struct dvb_frontend_ops nxt2002_o
 		.name = "Nextwave nxt2002 VSB/QAM frontend",
 		.type = FE_ATSC,
 		.frequency_min =  54000000,
-		.frequency_max = 803000000,
+		.frequency_max = 860000000,
                 /* stepsize is just a guess */
-		.frequency_stepsize = 166666,	
+		.frequency_stepsize = 166666,
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_8VSB 
+			FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
 	},
 
 	.release = nxt2002_release,
diff --git a/drivers/media/dvb/frontends/nxt2002.h b/drivers/media/dvb/frontends/nxt2002.h
--- a/drivers/media/dvb/frontends/nxt2002.h
+++ b/drivers/media/dvb/frontends/nxt2002.h
@@ -18,6 +18,6 @@ struct nxt2002_config
 };
 
 extern struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config,
-					  struct i2c_adapter* i2c);
+					   struct i2c_adapter* i2c);
 
 #endif // NXT2002_H
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -1,6 +1,6 @@
-/* 
+/*
 	NxtWave Communications - NXT6000 demodulator driver
-	
+
     Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
     Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
 
@@ -17,8 +17,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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/    
+*/
 
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -33,16 +32,11 @@
 
 
 struct nxt6000_state {
-
-	struct i2c_adapter *i2c;
-
+	struct i2c_adapter* i2c;
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct nxt6000_config* config;
-
 	struct dvb_frontend frontend;
-
 };
 
 static int debug = 0;
@@ -50,10 +44,10 @@ static int debug = 0;
 
 static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
 {
-	u8 buf[] = {reg, data};
+	u8 buf[] = { reg, data };
 	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
 	int ret;
-	
+
 	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
 		dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
 
@@ -63,18 +57,18 @@ static int nxt6000_writereg(struct nxt60
 static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
 {
 	int ret;
-	u8 b0[] = {reg};
-	u8 b1[] = {0};
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
 	struct i2c_msg msgs[] = {
 		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
 		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
 	};
 
 	ret = i2c_transfer(state->i2c, msgs, 2);
-	
+
 	if (ret != 2)
 		dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret);
-	
+
 	return b1[0];
 }
 
@@ -83,7 +77,7 @@ static void nxt6000_reset(struct nxt6000
 	u8 val;
 
 	val = nxt6000_readreg(state, OFDM_COR_CTL);
-	
+
 	nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT);
 	nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
 }
@@ -93,71 +87,65 @@ static int nxt6000_set_bandwidth(struct 
 	u16 nominal_rate;
 	int result;
 
-	switch(bandwidth) {
-	
-		case BANDWIDTH_6_MHZ:
-		
-			nominal_rate = 0x55B7;
-			
-			break;
-
-		case BANDWIDTH_7_MHZ:
-
-			nominal_rate = 0x6400;
-			
-			break;
-
-		case BANDWIDTH_8_MHZ:
-
-			nominal_rate = 0x7249;
-			
-			break;
+	switch (bandwidth) {
+
+	case BANDWIDTH_6_MHZ:
+		nominal_rate = 0x55B7;
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		nominal_rate = 0x6400;
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		nominal_rate = 0x7249;
+		break;
 
-		default:
-			return -EINVAL;
+	default:
+		return -EINVAL;
 	}
 
 	if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
 		return result;
-		
+
 	return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
 }
 
 static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval)
 {
-	switch(guard_interval) {
-	
-		case GUARD_INTERVAL_1_32:
+	switch (guard_interval) {
+
+	case GUARD_INTERVAL_1_32:
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
-		case GUARD_INTERVAL_1_16:
+	case GUARD_INTERVAL_1_16:
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
-		case GUARD_INTERVAL_AUTO:
-		case GUARD_INTERVAL_1_8:
+	case GUARD_INTERVAL_AUTO:
+	case GUARD_INTERVAL_1_8:
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
-		case GUARD_INTERVAL_1_4:
+	case GUARD_INTERVAL_1_4:
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
-			
-		default:
-			return -EINVAL;
+
+	default:
+		return -EINVAL;
 	}
 }
 
 static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion)
 {
-	switch(inversion) {
-	
-		case INVERSION_OFF:
+	switch (inversion) {
+
+	case INVERSION_OFF:
 		return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00);
-			
-		case INVERSION_ON:
+
+	case INVERSION_ON:
 		return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV);
 
-		default:
-			return -EINVAL;	
-	
+	default:
+		return -EINVAL;
+
 	}
 }
 
@@ -165,34 +153,39 @@ static int nxt6000_set_transmission_mode
 {
 	int result;
 
-	switch(transmission_mode) {
+	switch (transmission_mode) {
 
-		case TRANSMISSION_MODE_2K:	
+	case TRANSMISSION_MODE_2K:
 		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
-				return result;
-				
+			return result;
+
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
 
-		case TRANSMISSION_MODE_8K:	
-		case TRANSMISSION_MODE_AUTO:	
+	case TRANSMISSION_MODE_8K:
+	case TRANSMISSION_MODE_AUTO:
 		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
-				return result;
+			return result;
 
 		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
 
-		default:
-			return -EINVAL;
-	
+	default:
+		return -EINVAL;
+
 	}
 }
 
 static void nxt6000_setup(struct dvb_frontend* fe)
 {
-	struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
-	
+	struct nxt6000_state* state = fe->demodulator_priv;
+
 	nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM);
 	nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
-	nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC);
+	nxt6000_writereg(state, VIT_BERTIME_2, 0x00);  // BER Timer = 0x000200 * 256 = 131072 bits
+	nxt6000_writereg(state, VIT_BERTIME_1, 0x02);  //
+	nxt6000_writereg(state, VIT_BERTIME_0, 0x00);  //
+	nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts
+	nxt6000_writereg(state, VIT_COR_CTL, 0x82);   // Enable BER measurement
+	nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 );
 	nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F));
 	nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
 	nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
@@ -214,7 +207,7 @@ static void nxt6000_setup(struct dvb_fro
 		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
 
 	nxt6000_writereg(state, TS_FORMAT, 0);
-		
+
 	if (state->config->pll_init) {
 		nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);	/* open i2c bus switch */
 		state->config->pll_init(fe);
@@ -241,7 +234,7 @@ static void nxt6000_dump_status(struct n
 	printk("NXT6000 status:");
 
 	val = nxt6000_readreg(state, RS_COR_STAT);
-	
+
 	printk(" DATA DESCR LOCK: %d,", val & 0x01);
 	printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
 
@@ -249,91 +242,73 @@ static void nxt6000_dump_status(struct n
 
 	printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
 
-	switch((val >> 4) & 0x07) {
-	
-		case 0x00: 
-		
-			printk(" VITERBI CODERATE: 1/2,");
-			
-			break;
-	
-		case 0x01: 
-		
-			printk(" VITERBI CODERATE: 2/3,");
-			
-			break;
-	
-		case 0x02: 
-		
-			printk(" VITERBI CODERATE: 3/4,");
-			
-			break;
-	
-		case 0x03: 
-			printk(" VITERBI CODERATE: 5/6,");
-		break;
-
-		case 0x04: 
-			printk(" VITERBI CODERATE: 7/8,");
-			break;
-
-		default: 
-		
-			printk(" VITERBI CODERATE: Reserved,");
-			
+	switch ((val >> 4) & 0x07) {
+
+	case 0x00:
+		printk(" VITERBI CODERATE: 1/2,");
+		break;
+
+	case 0x01:
+		printk(" VITERBI CODERATE: 2/3,");
+		break;
+
+	case 0x02:
+		printk(" VITERBI CODERATE: 3/4,");
+		break;
+
+	case 0x03:
+		printk(" VITERBI CODERATE: 5/6,");
+		break;
+
+	case 0x04:
+		printk(" VITERBI CODERATE: 7/8,");
+		break;
+
+	default:
+		printk(" VITERBI CODERATE: Reserved,");
+
 	}
 
 	val = nxt6000_readreg(state, OFDM_COR_STAT);
-	
+
 	printk(" CHCTrack: %d,", (val >> 7) & 0x01);
 	printk(" TPSLock: %d,", (val >> 6) & 0x01);
 	printk(" SYRLock: %d,", (val >> 5) & 0x01);
 	printk(" AGCLock: %d,", (val >> 4) & 0x01);
 
-	switch(val & 0x0F) {
-	
-		case 0x00:
-		
-			printk(" CoreState: IDLE,");
-			
-			break;
-	
-		case 0x02:
-		
-			printk(" CoreState: WAIT_AGC,");
-			
-			break;
-	
-		case 0x03:
-		
-			printk(" CoreState: WAIT_SYR,");
-			
-			break;
-	
-		case 0x04:
-			printk(" CoreState: WAIT_PPM,");
-		break;
-
-		case 0x01:
-			printk(" CoreState: WAIT_TRL,");
-			break;
-
-		case 0x05:
-		
-			printk(" CoreState: WAIT_TPS,");
-			
-			break;
-
-		case 0x06:
-		
-			printk(" CoreState: MONITOR_TPS,");
-			
-			break;
-
-		default: 
-		
-			printk(" CoreState: Reserved,");
-			
+	switch (val & 0x0F) {
+
+	case 0x00:
+		printk(" CoreState: IDLE,");
+		break;
+
+	case 0x02:
+		printk(" CoreState: WAIT_AGC,");
+		break;
+
+	case 0x03:
+		printk(" CoreState: WAIT_SYR,");
+		break;
+
+	case 0x04:
+		printk(" CoreState: WAIT_PPM,");
+		break;
+
+	case 0x01:
+		printk(" CoreState: WAIT_TRL,");
+		break;
+
+	case 0x05:
+		printk(" CoreState: WAIT_TPS,");
+		break;
+
+	case 0x06:
+		printk(" CoreState: MONITOR_TPS,");
+		break;
+
+	default:
+		printk(" CoreState: Reserved,");
+
 	}
 
 	val = nxt6000_readreg(state, OFDM_SYR_STAT);
@@ -341,230 +316,224 @@ static void nxt6000_dump_status(struct n
 	printk(" SYRLock: %d,", (val >> 4) & 0x01);
 	printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
 
-	switch((val >> 4) & 0x03) {
-	
-		case 0x00: 
-		
-			printk(" SYRGuard: 1/32,");
-			
-			break;
-	
-		case 0x01: 
-		
-			printk(" SYRGuard: 1/16,");
-			
-			break;
-	
-		case 0x02: 
-		
-			printk(" SYRGuard: 1/8,");
-			
-			break;
-	
-		case 0x03: 
-			printk(" SYRGuard: 1/4,");
-			break;
+	switch ((val >> 4) & 0x03) {
+
+	case 0x00:
+		printk(" SYRGuard: 1/32,");
+		break;
+
+	case 0x01:
+		printk(" SYRGuard: 1/16,");
+		break;
+
+	case 0x02:
+		printk(" SYRGuard: 1/8,");
+		break;
+
+	case 0x03:
+		printk(" SYRGuard: 1/4,");
+		break;
 	}
 
 	val = nxt6000_readreg(state, OFDM_TPS_RCVD_3);
-	
-	switch((val >> 4) & 0x07) {
-	
-		case 0x00: 
-		
-			printk(" TPSLP: 1/2,");
-			
-			break;
-	
-		case 0x01: 
-		
-			printk(" TPSLP: 2/3,");
-			
-			break;
-	
-		case 0x02: 
-		
-			printk(" TPSLP: 3/4,");
-			
-			break;
-	
-		case 0x03: 
-			printk(" TPSLP: 5/6,");
-		break;
-
-		case 0x04: 
-			printk(" TPSLP: 7/8,");
-			break;
-
-		default: 
-		
-			printk(" TPSLP: Reserved,");
-			
-	}
-
-	switch(val & 0x07) {
-	
-		case 0x00: 
-		
-			printk(" TPSHP: 1/2,");
-			
-			break;
-	
-		case 0x01: 
-		
-			printk(" TPSHP: 2/3,");
-			
-			break;
-	
-		case 0x02: 
-		
-			printk(" TPSHP: 3/4,");
-			
-			break;
-	
-		case 0x03: 
-			printk(" TPSHP: 5/6,");
-		break;
-
-		case 0x04: 
-			printk(" TPSHP: 7/8,");
-			break;
-
-		default: 
-		
-			printk(" TPSHP: Reserved,");
-			
-	}
 
-	val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
-	
-	printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
-	
-	switch((val >> 4) & 0x03) {
-	
-		case 0x00: 
-		
-			printk(" TPSGuard: 1/32,");
-			
-			break;
-	
-		case 0x01: 
-		
-			printk(" TPSGuard: 1/16,");
-			
-			break;
-	
-		case 0x02: 
-		
-			printk(" TPSGuard: 1/8,");
-			
-			break;
-	
-		case 0x03: 
-		
-			printk(" TPSGuard: 1/4,");
-			
-			break;
-			
+	switch ((val >> 4) & 0x07) {
+
+	case 0x00:
+		printk(" TPSLP: 1/2,");
+		break;
+
+	case 0x01:
+		printk(" TPSLP: 2/3,");
+		break;
+
+	case 0x02:
+		printk(" TPSLP: 3/4,");
+		break;
+
+	case 0x03:
+		printk(" TPSLP: 5/6,");
+		break;
+
+	case 0x04:
+		printk(" TPSLP: 7/8,");
+		break;
+
+	default:
+		printk(" TPSLP: Reserved,");
+
 	}
-	
-	/* Strange magic required to gain access to RF_AGC_STATUS */
-	nxt6000_readreg(state, RF_AGC_VAL_1);
-	val = nxt6000_readreg(state, RF_AGC_STATUS);
-	val = nxt6000_readreg(state, RF_AGC_STATUS);
 
-	printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
-	printk("\n");
-}
+	switch (val & 0x07) {
 
+	case 0x00:
+		printk(" TPSHP: 1/2,");
+		break;
 
+	case 0x01:
+		printk(" TPSHP: 2/3,");
+		break;
 
+	case 0x02:
+		printk(" TPSHP: 3/4,");
+		break;
 
+	case 0x03:
+		printk(" TPSHP: 5/6,");
+		break;
 
+	case 0x04:
+		printk(" TPSHP: 7/8,");
+		break;
+
+	default:
+		printk(" TPSHP: Reserved,");
+
+	}
+
+	val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
 
+	printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
 
+	switch ((val >> 4) & 0x03) {
 
+	case 0x00:
+		printk(" TPSGuard: 1/32,");
+		break;
 
+	case 0x01:
+		printk(" TPSGuard: 1/16,");
+		break;
 
+	case 0x02:
+		printk(" TPSGuard: 1/8,");
+		break;
+
+	case 0x03:
+		printk(" TPSGuard: 1/4,");
+		break;
+
+	}
+
+	/* Strange magic required to gain access to RF_AGC_STATUS */
+	nxt6000_readreg(state, RF_AGC_VAL_1);
+	val = nxt6000_readreg(state, RF_AGC_STATUS);
+	val = nxt6000_readreg(state, RF_AGC_STATUS);
+
+	printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
+	printk("\n");
+}
 
 static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-			u8 core_status;
-	struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+	u8 core_status;
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*status = 0;
 
-			*status = 0;
-			
 	core_status = nxt6000_readreg(state, OFDM_COR_STAT);
 
-			if (core_status & AGCLOCKED)
-				*status |= FE_HAS_SIGNAL;
+	if (core_status & AGCLOCKED)
+		*status |= FE_HAS_SIGNAL;
 
 	if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK)
-				*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_CARRIER;
 
 	if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC)
-				*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_VITERBI;
 
 	if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS)
-				*status |= FE_HAS_SYNC;
-				
-			if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
-				*status |= FE_HAS_LOCK;
-				
-			if (debug)
+		*status |= FE_HAS_SYNC;
+
+	if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
+		*status |= FE_HAS_LOCK;
+
+	if (debug)
 		nxt6000_dump_status(state);
 
-			return 0;
-		}
-	
+	return 0;
+}
+
 static int nxt6000_init(struct dvb_frontend* fe)
-		{
-	struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
 
 	nxt6000_reset(state);
 	nxt6000_setup(fe);
-	
-			return 0;
-		}
-	
+
+	return 0;
+}
 
 static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
-		{
-	struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
-			int result;
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+	int result;
 
 	nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);	/* open i2c bus switch */
 	state->config->pll_set(fe, param);
 	nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);	/* close i2c bus switch */
 
 	if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
-						return result;
+		return result;
 	if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0)
-				return result;
+		return result;
 	if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0)
-				return result;
+		return result;
 	if ((result = nxt6000_set_inversion(state, param->inversion)) < 0)
-				return result;
+		return result;
 
 	return 0;
-} 
-
+}
 
 static void nxt6000_release(struct dvb_frontend* fe)
 {
-	struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+	struct nxt6000_state* state = fe->demodulator_priv;
 	kfree(state);
-	}
-	
+}
+
+static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8;
+
+	return 0;
+}
+
+static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 );
+
+	*ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) |
+		nxt6000_readreg( state, VIT_BER_0 );
+
+	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts
+
+	return 0;
+}
+
+static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*signal_strength = (short) (511 -
+		(nxt6000_readreg(state, AGC_GAIN_1) +
+		((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8)));
+
+	return 0;
+}
+
 static struct dvb_frontend_ops nxt6000_ops;
-	
+
 struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
 				    struct i2c_adapter* i2c)
 {
 	struct nxt6000_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -581,9 +550,9 @@ struct dvb_frontend* nxt6000_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
-	}
+}
 
 static struct dvb_frontend_ops nxt6000_ops = {
 
@@ -608,10 +577,13 @@ static struct dvb_frontend_ops nxt6000_o
 	.release = nxt6000_release,
 
 	.init = nxt6000_init,
-	
+
 	.set_frontend = nxt6000_set_frontend,
-	
+
 	.read_status = nxt6000_read_status,
+	.read_ber = nxt6000_read_ber,
+	.read_signal_strength = nxt6000_read_signal_strength,
+	.read_snr = nxt6000_read_snr,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h
--- a/drivers/media/dvb/frontends/nxt6000_priv.h
+++ b/drivers/media/dvb/frontends/nxt6000_priv.h
@@ -65,12 +65,27 @@
 #define BER_DONE               (0x08)
 #define BER_OVERFLOW           (0x10)
 
+/* 0x38 VIT_BERTIME_2 */
+#define VIT_BERTIME_2      (0x38)
+
+/* 0x39 VIT_BERTIME_1 */
+#define VIT_BERTIME_1      (0x39)
+
+/* 0x3A VIT_BERTIME_0 */
+#define VIT_BERTIME_0      (0x3a)
+
 			     /* 0x38 OFDM_BERTimer *//* Use the alias registers */
 #define A_VIT_BER_TIMER_0      (0x1D)
 
 			     /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
 #define A_VIT_BER_0            (0x1B)
 
+/* 0x3B VIT_BER_1 */
+#define VIT_BER_1              (0x3b)
+
+/* 0x3C VIT_BER_0 */
+#define VIT_BER_0              (0x3c)
+
 /* 0x40 OFDM_COR_CTL */
 #define OFDM_COR_CTL           (0x40)
 #define COREACT                (0x20)
@@ -117,6 +132,12 @@
 #define OFDM_ITB_CTL           (0x4B)
 #define ITBINV                 (0x01)
 
+/* 0x49 AGC_GAIN_1 */
+#define AGC_GAIN_1             (0x49)
+
+/* 0x4A AGC_GAIN_2 */
+#define AGC_GAIN_2             (0x4A)
+
 /* 0x4C OFDM_ITB_FREQ_1 */
 #define OFDM_ITB_FREQ_1        (0x4C)
 
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -0,0 +1,628 @@
+/*
+ *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    Based on code from Jack Kelliher (kelliher@xmission.com)
+ *                           Copyright (C) 2002 & pcHDTV, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * This driver needs two external firmware files. Please copy
+ * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw"
+#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "or51132.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "or51132: " args); \
+	} while (0)
+
+
+struct or51132_state
+{
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+
+	/* Configuration settings */
+	const struct or51132_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* Demodulator private data */
+	fe_modulation_t current_modulation;
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr  = reg;
+	msg.flags = 0;
+	msg.len   = len;
+	msg.buf   = buf;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr   = reg;
+	msg.flags = I2C_M_RD;
+	msg.len = len;
+	msg.buf = buf;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	static u8 run_buf[] = {0x7F,0x01};
+	static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
+	u8 rec_buf[14];
+	u8 cmd_buf[14];
+	u32 firmwareAsize, firmwareBsize;
+	int i,ret;
+
+	dprintk("Firmware is %Zd bytes\n",fw->size);
+
+	/* Get size of firmware A and B */
+	firmwareAsize = le32_to_cpu(*((u32*)fw->data));
+	dprintk("FirmwareA is %i bytes\n",firmwareAsize);
+	firmwareBsize = le32_to_cpu(*((u32*)(fw->data+4)));
+	dprintk("FirmwareB is %i bytes\n",firmwareBsize);
+
+	/* Upload firmware */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 &fw->data[8],firmwareAsize))) {
+		printk(KERN_WARNING "or51132: load_firmware error 1\n");
+		return ret;
+	}
+	msleep(1); /* 1ms */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 &fw->data[8+firmwareAsize],firmwareBsize))) {
+		printk(KERN_WARNING "or51132: load_firmware error 2\n");
+		return ret;
+	}
+	msleep(1); /* 1ms */
+
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 run_buf,2))) {
+		printk(KERN_WARNING "or51132: load_firmware error 3\n");
+		return ret;
+	}
+
+	/* Wait at least 5 msec */
+	msleep(20); /* 10ms */
+
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 run_buf,2))) {
+		printk(KERN_WARNING "or51132: load_firmware error 4\n");
+		return ret;
+	}
+
+	/* 50ms for operation to begin */
+	msleep(50);
+
+	/* Read back ucode version to besure we loaded correctly and are really up and running */
+	/* Get uCode version */
+	cmd_buf[0] = 0x10;
+	cmd_buf[1] = 0x10;
+	cmd_buf[2] = 0x00;
+	cmd_buf[3] = 0x00;
+	msleep(20); /* 20ms */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 cmd_buf,3))) {
+		printk(KERN_WARNING "or51132: load_firmware error a\n");
+		return ret;
+	}
+
+	cmd_buf[0] = 0x04;
+	cmd_buf[1] = 0x17;
+	cmd_buf[2] = 0x00;
+	cmd_buf[3] = 0x00;
+	msleep(20); /* 20ms */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 cmd_buf,2))) {
+		printk(KERN_WARNING "or51132: load_firmware error b\n");
+		return ret;
+	}
+
+	cmd_buf[0] = 0x00;
+	cmd_buf[1] = 0x00;
+	cmd_buf[2] = 0x00;
+	cmd_buf[3] = 0x00;
+	msleep(20); /* 20ms */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 cmd_buf,2))) {
+		printk(KERN_WARNING "or51132: load_firmware error c\n");
+		return ret;
+	}
+
+	for(i=0;i<4;i++) {
+		msleep(20); /* 20ms */
+		get_ver_buf[4] = i+1;
+		if ((ret = i2c_readbytes(state,state->config->demod_address,
+					&rec_buf[i*2],2))) {
+			printk(KERN_WARNING
+			       "or51132: load_firmware error d - %d\n",i);
+			return ret;
+		}
+	}
+
+	printk(KERN_WARNING
+	       "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n",
+	       rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2],
+	       rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6],
+	       rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f,
+	       rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f);
+
+	cmd_buf[0] = 0x10;
+	cmd_buf[1] = 0x00;
+	cmd_buf[2] = 0x00;
+	cmd_buf[3] = 0x00;
+	msleep(20); /* 20ms */
+	if ((ret = i2c_writebytes(state,state->config->demod_address,
+				 cmd_buf,3))) {
+		printk(KERN_WARNING "or51132: load_firmware error e\n");
+		return ret;
+	}
+	return 0;
+};
+
+static int or51132_init(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51132_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static int or51132_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51132_setmode(struct dvb_frontend* fe)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	unsigned char cmd_buf[4];
+
+	dprintk("setmode %d\n",(int)state->current_modulation);
+	/* set operation mode in Receiver 1 register; */
+	cmd_buf[0] = 0x04;
+	cmd_buf[1] = 0x01;
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+	case QAM_AUTO:
+		/* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/
+		cmd_buf[2] = 0x5F;
+		break;
+	case VSB_8:
+		/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/
+		cmd_buf[2] = 0x50;
+		break;
+	default:
+		printk("setmode:Modulation set to unsupported value\n");
+	};
+	cmd_buf[3] = 0x00;
+	if (i2c_writebytes(state,state->config->demod_address,
+			   cmd_buf,3)) {
+		printk(KERN_WARNING "or51132: set_mode error 1\n");
+		return -1;
+	}
+	dprintk("or51132: set #1 to %02x\n", cmd_buf[2]);
+
+	/* Set operation mode in Receiver 6 register */
+	cmd_buf[0] = 0x1C;
+	switch (state->current_modulation) {
+	case QAM_AUTO:
+		/* REC MODE Normal Carrier Lock */
+		cmd_buf[1] = 0x00;
+		/* Channel MODE Auto QAM64/256 */
+		cmd_buf[2] = 0x4f;
+		break;
+	case QAM_256:
+		/* REC MODE Normal Carrier Lock */
+		cmd_buf[1] = 0x00;
+		/* Channel MODE QAM256 */
+		cmd_buf[2] = 0x45;
+		break;
+	case QAM_64:
+		/* REC MODE Normal Carrier Lock */
+		cmd_buf[1] = 0x00;
+		/* Channel MODE QAM64 */
+		cmd_buf[2] = 0x43;
+		break;
+	case VSB_8:
+		 /* REC MODE inv IF spectrum, Normal */
+		cmd_buf[1] = 0x03;
+		/* Channel MODE ATSC/VSB8 */
+		cmd_buf[2] = 0x06;
+		break;
+	default:
+		printk("setmode: Modulation set to unsupported value\n");
+	};
+	cmd_buf[3] = 0x00;
+	msleep(20); /* 20ms */
+	if (i2c_writebytes(state,state->config->demod_address,
+			   cmd_buf,3)) {
+		printk(KERN_WARNING "or51132: set_mode error 2\n");
+		return -1;
+	}
+	dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]);
+
+	return 0;
+}
+
+static int or51132_set_parameters(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *param)
+{
+	int ret;
+	u8 buf[4];
+	struct or51132_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+
+	/* Change only if we are actually changing the modulation */
+	if (state->current_modulation != param->u.vsb.modulation) {
+		switch(param->u.vsb.modulation) {
+		case VSB_8:
+			dprintk("set_parameters VSB MODE\n");
+			printk("or51132: Waiting for firmware upload(%s)...\n",
+			       OR51132_VSB_FIRMWARE);
+			ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
+					       &state->i2c->dev);
+			if (ret){
+				printk(KERN_WARNING "or51132: No firmware up"
+				       "loaded(timeout or file not found?)\n");
+				return ret;
+			}
+			/* Set non-punctured clock for VSB */
+			state->config->set_ts_params(fe, 0);
+			break;
+		case QAM_AUTO:
+		case QAM_64:
+		case QAM_256:
+			dprintk("set_parameters QAM MODE\n");
+			printk("or51132: Waiting for firmware upload(%s)...\n",
+			       OR51132_QAM_FIRMWARE);
+			ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
+					       &state->i2c->dev);
+			if (ret){
+				printk(KERN_WARNING "or51132: No firmware up"
+				       "loaded(timeout or file not found?)\n");
+				return ret;
+			}
+			/* Set punctured clock for QAM */
+			state->config->set_ts_params(fe, 1);
+			break;
+		default:
+			printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+			       param->u.vsb.modulation);
+			return -1;
+		};
+		ret = or51132_load_firmware(fe, fw);
+		release_firmware(fw);
+		if (ret) {
+			printk(KERN_WARNING "or51132: Writing firmware to "
+			       "device failed!\n");
+			return ret;
+		}
+		printk("or51132: Firmware upload complete.\n");
+
+		state->current_modulation = param->u.vsb.modulation;
+		or51132_setmode(fe);
+	}
+
+	/* Change only if we are actually changing the channel */
+	if (state->current_frequency != param->frequency) {
+		dvb_pll_configure(state->config->pll_desc, buf,
+				  param->frequency, 0);
+		dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
+			"0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
+		if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
+			printk(KERN_WARNING "or51132: set_parameters error "
+			       "writing to tuner\n");
+
+		/* Set to current mode */
+		or51132_setmode(fe);
+
+		/* Update current frequency */
+		state->current_frequency = param->frequency;
+	}
+	return 0;
+}
+
+static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	unsigned char rec_buf[2];
+	unsigned char snd_buf[2];
+	*status = 0;
+
+	/* Receiver Status */
+	snd_buf[0]=0x04;
+	snd_buf[1]=0x00;
+	msleep(30); /* 30ms */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status write error\n");
+		return -1;
+	}
+	msleep(30); /* 30ms */
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status read error\n");
+		return -1;
+	}
+	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+
+	if (rec_buf[1] & 0x01) { /* Receiver Lock */
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+/* log10-1 table at .5 increments from 1 to 100.5 */
+static unsigned int i100x20log10[] = {
+     0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
+  1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
+  2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
+  2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
+  2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
+  2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
+  2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
+  3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
+  3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
+  3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
+  3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
+  3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
+  3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
+  3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
+  3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
+  3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
+  3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
+  3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
+  3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
+  3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
+};
+
+static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+
+static unsigned int i20Log10(unsigned short val)
+{
+	unsigned int rntval = 100;
+	unsigned int tmp = val;
+	unsigned int exp = 1;
+
+	while(tmp > 100) {tmp /= 100; exp++;}
+
+	val = (2 * val)/denom[exp];
+	if (exp > 1) rntval = 2000*exp;
+
+	rntval += i100x20log10[val];
+	return rntval;
+}
+
+static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	unsigned char rec_buf[2];
+	unsigned char snd_buf[2];
+	u8 rcvr_stat;
+	u16 snr_equ;
+	int usK;
+
+	snd_buf[0]=0x04;
+	snd_buf[1]=0x02; /* SNR after Equalizer */
+	msleep(30); /* 30ms */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status write error\n");
+		return -1;
+	}
+	msleep(30); /* 30ms */
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status read error\n");
+		return -1;
+	}
+	snr_equ = rec_buf[0] | (rec_buf[1] << 8);
+	dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+
+	/* Receiver Status */
+	snd_buf[0]=0x04;
+	snd_buf[1]=0x00;
+	msleep(30); /* 30ms */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
+		printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n");
+		return -1;
+	}
+	msleep(30); /* 30ms */
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n");
+		return -1;
+	}
+	dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]);
+	rcvr_stat = rec_buf[1];
+	usK = (rcvr_stat & 0x10) ? 3 : 0;
+
+        /* The value reported back from the frontend will be FFFF=100% 0000=0% */
+	*strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+	dprintk("read_signal_strength %i\n",*strength);
+
+	return 0;
+}
+
+static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	unsigned char rec_buf[2];
+	unsigned char snd_buf[2];
+	u16 snr_equ;
+
+	snd_buf[0]=0x04;
+	snd_buf[1]=0x02; /* SNR after Equalizer */
+	msleep(30); /* 30ms */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
+		printk(KERN_WARNING "or51132: read_snr write error\n");
+		return -1;
+	}
+	msleep(30); /* 30ms */
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_snr dvr read error\n");
+		return -1;
+	}
+	snr_equ = rec_buf[0] | (rec_buf[1] << 8);
+	dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+
+	*snr = 0xFFFF - snr_equ;
+	dprintk("read_snr %i\n",*snr);
+
+	return 0;
+}
+
+static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 500;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static void or51132_release(struct dvb_frontend* fe)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops or51132_ops;
+
+struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct or51132_state* state = NULL;
+
+	/* Allocate memory for the internal state */
+	state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
+	state->current_frequency = -1;
+	state->current_modulation = -1;
+
+	/* Create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state)
+		kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops or51132_ops = {
+
+	.info = {
+		.name			= "Oren OR51132 VSB/QAM Frontend",
+		.type 			= FE_ATSC,
+		.frequency_min		= 44000000,
+		.frequency_max		= 958000000,
+		.frequency_stepsize	= 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
+			FE_CAN_8VSB
+	},
+
+	.release = or51132_release,
+
+	.init = or51132_init,
+	.sleep = or51132_sleep,
+
+	.set_frontend = or51132_set_parameters,
+	.get_tune_settings = or51132_get_tune_settings,
+
+	.read_status = or51132_read_status,
+	.read_ber = or51132_read_ber,
+	.read_signal_strength = or51132_read_signal_strength,
+	.read_snr = or51132_read_snr,
+	.read_ucblocks = or51132_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(or51132_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -0,0 +1,48 @@
+/*
+ *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef OR51132_H
+#define OR51132_H
+
+#include <linux/firmware.h>
+#include <linux/dvb/frontend.h>
+
+struct or51132_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+	u8 pll_address;
+	struct dvb_pll_desc *pll_desc;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+					   struct i2c_adapter* i2c);
+
+#endif // OR51132_H
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -0,0 +1,631 @@
+/*
+ *    Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    Based on code from Jack Kelliher (kelliher@xmission.com)
+ *                           Copyright (C) 2002 & pcHDTV, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ */
+#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "or51211.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "or51211: " args); \
+	} while (0)
+
+static u8 run_buf[] = {0x7f,0x01};
+static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
+
+struct or51211_state {
+
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+
+	/* Configuration settings */
+	const struct or51211_config* config;
+
+	struct dvb_frontend frontend;
+	struct bt878* bt;
+
+	/* Demodulator private data */
+	u8 initialized:1;
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+static int i2c_writebytes (struct or51211_state* state, u8 reg, u8 *buf,
+			   int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr	= reg;
+	msg.flags	= 0;
+	msg.len		= len;
+	msg.buf		= buf;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51211: i2c_writebytes error "
+		       "(addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr	= reg;
+	msg.flags	= I2C_M_RD;
+	msg.len		= len;
+	msg.buf		= buf;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51211: i2c_readbytes error "
+		       "(addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int or51211_load_firmware (struct dvb_frontend* fe,
+				  const struct firmware *fw)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 tudata[585];
+	int i;
+
+	dprintk("Firmware is %d bytes\n",fw->size);
+
+	/* Get eprom data */
+	tudata[0] = 17;
+	if (i2c_writebytes(state,0x50,tudata,1)) {
+		printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
+		return -1;
+	}
+	if (i2c_readbytes(state,0x50,&tudata[145],192)) {
+		printk(KERN_WARNING "or51211: load_firmware error eprom\n");
+		return -1;
+	}
+
+	/* Create firmware buffer */
+	for (i = 0; i < 145; i++)
+		tudata[i] = fw->data[i];
+
+	for (i = 0; i < 248; i++)
+		tudata[i+337] = fw->data[145+i];
+
+	state->config->reset(fe);
+
+	if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
+		printk(KERN_WARNING "or51211: load_firmware error 1\n");
+		return -1;
+	}
+	msleep(1);
+
+	if (i2c_writebytes(state,state->config->demod_address,
+			   &fw->data[393],8125)) {
+		printk(KERN_WARNING "or51211: load_firmware error 2\n");
+		return -1;
+	}
+	msleep(1);
+
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: load_firmware error 3\n");
+		return -1;
+	}
+
+	/* Wait at least 5 msec */
+	msleep(10);
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: load_firmware error 4\n");
+		return -1;
+	}
+	msleep(10);
+
+	printk("or51211: Done.\n");
+	return 0;
+};
+
+static int or51211_setmode(struct dvb_frontend* fe, int mode)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 rec_buf[14];
+
+	state->config->setmode(fe, mode);
+
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: setmode error 1\n");
+		return -1;
+	}
+
+	/* Wait at least 5 msec */
+	msleep(10);
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: setmode error 2\n");
+		return -1;
+	}
+
+	msleep(10);
+
+	/* Set operation mode in Receiver 1 register;
+	 * type 1:
+	 * data 0x50h  Automatic sets receiver channel conditions
+	 *             Automatic NTSC rejection filter
+	 *             Enable  MPEG serial data output
+	 *             MPEG2tr
+	 *             High tuner phase noise
+	 *             normal +/-150kHz Carrier acquisition range
+	 */
+	if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
+		printk(KERN_WARNING "or51211: setmode error 3\n");
+		return -1;
+	}
+
+	rec_buf[0] = 0x04;
+	rec_buf[1] = 0x00;
+	rec_buf[2] = 0x03;
+	rec_buf[3] = 0x00;
+	msleep(20);
+	if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
+		printk(KERN_WARNING "or51211: setmode error 5\n");
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
+		printk(KERN_WARNING "or51211: setmode error 6");
+		return -1;
+	}
+	dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
+
+	return 0;
+}
+
+static int or51211_set_parameters(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u32 freq = 0;
+	u16 tunerfreq = 0;
+	u8 buf[4];
+
+	/* Change only if we are actually changing the channel */
+	if (state->current_frequency != param->frequency) {
+		freq = 44000 + (param->frequency/1000);
+		tunerfreq = freq * 16/1000;
+
+		dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
+			param->frequency,tunerfreq);
+
+		buf[0] = (tunerfreq >> 8) & 0x7F;
+		buf[1] = (tunerfreq & 0xFF);
+		buf[2] = 0x8E;
+
+		if (param->frequency < 157250000) {
+			buf[3] = 0xA0;
+			dprintk("set_parameters VHF low range\n");
+		} else if (param->frequency < 454000000) {
+			buf[3] = 0x90;
+			dprintk("set_parameters VHF high range\n");
+		} else {
+			buf[3] = 0x30;
+			dprintk("set_parameters UHF range\n");
+		}
+		dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
+			"0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
+
+		if (i2c_writebytes(state,0xC2>>1,buf,4))
+			printk(KERN_WARNING "or51211:set_parameters error "
+			       "writing to tuner\n");
+
+		/* Set to ATSC mode */
+		or51211_setmode(fe,0);
+
+		/* Update current frequency */
+		state->current_frequency = param->frequency;
+	}
+	return 0;
+}
+
+static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	unsigned char rec_buf[2];
+	unsigned char snd_buf[] = {0x04,0x00,0x03,0x00};
+	*status = 0;
+
+	/* Receiver Status */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+		printk(KERN_WARNING "or51132: read_status write error\n");
+		return -1;
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status read error\n");
+		return -1;
+	}
+	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+
+	if (rec_buf[0] &  0x01) { /* Receiver Lock */
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+/* log10-1 table at .5 increments from 1 to 100.5 */
+static unsigned int i100x20log10[] = {
+		0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
+	 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
+	 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
+	 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
+	 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
+	 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
+	 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
+	 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
+	 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
+	 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
+	 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
+	 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
+	 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
+	 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
+	 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
+	 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
+	 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
+	 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
+	 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
+	 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
+};
+
+static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+
+static unsigned int i20Log10(unsigned short val)
+{
+	unsigned int rntval = 100;
+	unsigned int tmp = val;
+	unsigned int exp = 1;
+
+	while(tmp > 100) {tmp /= 100; exp++;}
+
+	val = (2 * val)/denom[exp];
+	if (exp > 1) rntval = 2000*exp;
+
+	rntval += i100x20log10[val];
+	return rntval;
+}
+
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 rec_buf[2];
+	u8 snd_buf[4];
+	u8 snr_equ;
+
+	/* SNR after Equalizer */
+	snd_buf[0] = 0x04;
+	snd_buf[1] = 0x00;
+	snd_buf[2] = 0x04;
+	snd_buf[3] = 0x00;
+
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+		printk(KERN_WARNING "or51211: read_status write error\n");
+		return -1;
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51211: read_status read error\n");
+		return -1;
+	}
+	snr_equ = rec_buf[0] & 0xff;
+
+	/* The value reported back from the frontend will be FFFF=100% 0000=0% */
+	*strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
+
+	dprintk("read_signal_strength %i\n",*strength);
+
+	return 0;
+}
+
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 rec_buf[2];
+	u8 snd_buf[4];
+
+	/* SNR after Equalizer */
+	snd_buf[0] = 0x04;
+	snd_buf[1] = 0x00;
+	snd_buf[2] = 0x04;
+	snd_buf[3] = 0x00;
+
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+		printk(KERN_WARNING "or51211: read_status write error\n");
+		return -1;
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51211: read_status read error\n");
+		return -1;
+	}
+	*snr = rec_buf[0] & 0xff;
+
+	dprintk("read_snr %i\n",*snr);
+
+	return 0;
+}
+
+static int or51211_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = -ENOSYS;
+	return 0;
+}
+
+static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	*ucblocks = -ENOSYS;
+	return 0;
+}
+
+static int or51211_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51211_init(struct dvb_frontend* fe)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	const struct or51211_config* config = state->config;
+	const struct firmware* fw;
+	unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
+	unsigned char rec_buf[14];
+	int ret,i;
+
+	if (!state->initialized) {
+		/* Request the firmware, this will block until it uploads */
+		printk(KERN_INFO "or51211: Waiting for firmware upload "
+		       "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
+		ret = config->request_firmware(fe, &fw,
+					       OR51211_DEFAULT_FIRMWARE);
+		printk(KERN_INFO "or51211:Got Hotplug firmware\n");
+		if (ret) {
+			printk(KERN_WARNING "or51211: No firmware uploaded "
+			       "(timeout or file not found?)\n");
+			return ret;
+		}
+
+		ret = or51211_load_firmware(fe, fw);
+		if (ret) {
+			printk(KERN_WARNING "or51211: Writing firmware to "
+			       "device failed!\n");
+			release_firmware(fw);
+			return ret;
+		}
+		printk(KERN_INFO "or51211: Firmware upload complete.\n");
+
+		/* Set operation mode in Receiver 1 register;
+		 * type 1:
+		 * data 0x50h  Automatic sets receiver channel conditions
+		 *             Automatic NTSC rejection filter
+		 *             Enable  MPEG serial data output
+		 *             MPEG2tr
+		 *             High tuner phase noise
+		 *             normal +/-150kHz Carrier acquisition range
+		 */
+		if (i2c_writebytes(state,state->config->demod_address,
+				   cmd_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 5\n");
+			return -1;
+		}
+
+		/* Read back ucode version to besure we loaded correctly */
+		/* and are really up and running */
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x03;
+		rec_buf[3] = 0x00;
+		msleep(30);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error A\n");
+			return -1;
+		}
+		msleep(3);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[10],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error B\n");
+			return -1;
+		}
+
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x01;
+		rec_buf[3] = 0x00;
+		msleep(20);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error C\n");
+			return -1;
+		}
+		msleep(3);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[12],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error D\n");
+			return -1;
+		}
+
+		for (i = 0; i < 8; i++)
+			rec_buf[i]=0xed;
+
+		for (i = 0; i < 5; i++) {
+			msleep(30);
+			get_ver_buf[4] = i+1;
+			if (i2c_writebytes(state,state->config->demod_address,
+					   get_ver_buf,5)) {
+				printk(KERN_WARNING "or51211:Load DVR Error 6"
+				       " - %d\n",i);
+				return -1;
+			}
+			msleep(3);
+
+			if (i2c_readbytes(state,state->config->demod_address,
+					  &rec_buf[i*2],2)) {
+				printk(KERN_WARNING "or51211:Load DVR Error 7"
+				       " - %d\n",i);
+				return -1;
+			}
+			/* If we didn't receive the right index, try again */
+			if ((int)rec_buf[i*2+1]!=i+1){
+			  i--;
+			}
+		}
+		dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
+			rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
+			rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
+			rec_buf[8], rec_buf[9]);
+
+		printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
+		       " Status %02x\n",
+		       rec_buf[2], rec_buf[4],rec_buf[6],
+		       rec_buf[12],rec_buf[10]);
+
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x03;
+		rec_buf[3] = 0x00;
+		msleep(20);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 8\n");
+			return -1;
+		}
+		msleep(20);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[8],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 9\n");
+			return -1;
+		}
+		state->initialized = 1;
+	}
+
+	return 0;
+}
+
+static int or51211_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 500;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void or51211_release(struct dvb_frontend* fe)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	state->config->sleep(fe);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops or51211_ops;
+
+struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct or51211_state* state = NULL;
+
+	/* Allocate memory for the internal state */
+	state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
+	state->initialized = 0;
+	state->current_frequency = 0;
+
+	/* Create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops or51211_ops = {
+
+	.info = {
+		.name               = "Oren OR51211 VSB Frontend",
+		.type               = FE_ATSC,
+		.frequency_min      = 44000000,
+		.frequency_max      = 958000000,
+		.frequency_stepsize = 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_8VSB
+	},
+
+	.release = or51211_release,
+
+	.init = or51211_init,
+	.sleep = or51211_sleep,
+
+	.set_frontend = or51211_set_parameters,
+	.get_tune_settings = or51211_get_tune_settings,
+
+	.read_status = or51211_read_status,
+	.read_ber = or51211_read_ber,
+	.read_signal_strength = or51211_read_signal_strength,
+	.read_snr = or51211_read_snr,
+	.read_ucblocks = or51211_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(or51211_attach);
+
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
new file mode 100644
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51211.h
@@ -0,0 +1,44 @@
+/*
+ *    Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef OR51211_H
+#define OR51211_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct or51211_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+
+	/* Request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+	void (*setmode)(struct dvb_frontend * fe, int mode);
+	void (*reset)(struct dvb_frontend * fe);
+	void (*sleep)(struct dvb_frontend * fe);
+};
+
+extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+					   struct i2c_adapter* i2c);
+
+#endif // OR51211_H
+
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -130,7 +130,7 @@ static int sp8870_firmware_upload (struc
 		msg.flags = 0;
 		msg.buf = tx_buf;
 		msg.len = tx_len + 2;
-        	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 			printk("%s: firmware upload failed!\n", __FUNCTION__);
 			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
 			return err;
@@ -248,7 +248,7 @@ static int sp8870_wake_up(struct sp8870_
 static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
 					   struct dvb_frontend_parameters *p)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	int  err;
 	u16 reg0xc05;
 
@@ -302,7 +302,7 @@ static int sp8870_set_frontend_parameter
 
 static int sp8870_init (struct dvb_frontend* fe)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
         const struct firmware *fw = NULL;
 
 	sp8870_wake_up(state);
@@ -358,7 +358,7 @@ static int sp8870_init (struct dvb_front
 
 static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	int status;
 	int signal;
 
@@ -384,7 +384,7 @@ static int sp8870_read_status (struct dv
 
 static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	int ret;
 	u32 tmp;
 
@@ -412,7 +412,7 @@ static int sp8870_read_ber (struct dvb_f
 
 static int sp8870_read_signal_strength(struct dvb_frontend* fe,  u16 * signal)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	int ret;
 	u16 tmp;
 
@@ -438,7 +438,7 @@ static int sp8870_read_signal_strength(s
 
 static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	int ret;
 
 	*ublocks = 0;
@@ -467,7 +467,7 @@ static int switches = 0;
 
 static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 
 	/*
 	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
@@ -524,7 +524,7 @@ static int sp8870_set_frontend (struct d
 
 static int sp8870_sleep(struct dvb_frontend* fe)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 
 	// tristate TS output and disable interface pins
 	return sp8870_writereg(state, 0xC18, 0x000);
@@ -540,7 +540,7 @@ static int sp8870_get_tune_settings(stru
 
 static void sp8870_release(struct dvb_frontend* fe)
 {
-	struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+	struct sp8870_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -552,7 +552,7 @@ struct dvb_frontend* sp8870_attach(const
 	struct sp8870_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct sp8870_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -570,7 +570,7 @@ struct dvb_frontend* sp8870_attach(const
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -20,13 +20,9 @@
 
 
 struct sp887x_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	const struct sp887x_config* config;
-
 	struct dvb_frontend frontend;
 
 	/* demodulator private data */
@@ -139,7 +135,7 @@ static void sp887x_setup_agc (struct sp8
  */
 static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
 	u8 buf [BLOCKSIZE+2];
 	int i;
 	int fw_size = fw->size;
@@ -315,8 +311,8 @@ static void divide (int n, int d, int *q
 }
 
 static void sp887x_correct_offsets (struct sp887x_state* state,
-			     struct dvb_frontend_parameters *p,
-			     int actual_freq)
+				    struct dvb_frontend_parameters *p,
+				    int actual_freq)
 {
 	static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
 	int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
@@ -345,23 +341,10 @@ static void sp887x_correct_offsets (stru
 	sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
 static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
-				      struct dvb_frontend_parameters *p)
+					     struct dvb_frontend_parameters *p)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
 	int actual_freq, err;
 	u16 val, reg0xc05;
 
@@ -421,116 +404,116 @@ static int sp887x_setup_frontend_paramet
 }
 
 static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status)
-	{
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+{
+	struct sp887x_state* state = fe->demodulator_priv;
 	u16 snr12 = sp887x_readreg(state, 0xf16);
 	u16 sync0x200 = sp887x_readreg(state, 0x200);
 	u16 sync0xf17 = sp887x_readreg(state, 0xf17);
 
-		*status = 0;
+	*status = 0;
 
-		if (snr12 > 0x00f)
-			*status |= FE_HAS_SIGNAL;
+	if (snr12 > 0x00f)
+		*status |= FE_HAS_SIGNAL;
 
-		//if (sync0x200 & 0x004)
-		//	*status |= FE_HAS_SYNC | FE_HAS_CARRIER;
+	//if (sync0x200 & 0x004)
+	//	*status |= FE_HAS_SYNC | FE_HAS_CARRIER;
 
-		//if (sync0x200 & 0x008)
-		//	*status |= FE_HAS_VITERBI;
+	//if (sync0x200 & 0x008)
+	//	*status |= FE_HAS_VITERBI;
 
-		if ((sync0xf17 & 0x00f) == 0x002) {
-			*status |= FE_HAS_LOCK;
-			*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
-		}
+	if ((sync0xf17 & 0x00f) == 0x002) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
+	}
 
-		if (sync0x200 & 0x001) {	/* tuner adjustment requested...*/
-			int steps = (sync0x200 >> 4) & 0x00f;
-			if (steps & 0x008)
-				steps = -steps;
-			dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
-			       steps);
-		}
+	if (sync0x200 & 0x001) {	/* tuner adjustment requested...*/
+		int steps = (sync0x200 >> 4) & 0x00f;
+		if (steps & 0x008)
+			steps = -steps;
+		dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
+		       steps);
+	}
 
 	return 0;
-	}
+}
 
 static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
-	{
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+{
+	struct sp887x_state* state = fe->demodulator_priv;
 
 	*ber = (sp887x_readreg(state, 0xc08) & 0x3f) |
 	       (sp887x_readreg(state, 0xc07) << 6);
 	sp887x_writereg(state, 0xc08, 0x000);
 	sp887x_writereg(state, 0xc07, 0x000);
-		if (*ber >= 0x3fff0)
-			*ber = ~0;
+	if (*ber >= 0x3fff0)
+		*ber = ~0;
 
 	return 0;
-	}
+}
 
 static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-	{
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+{
+	struct sp887x_state* state = fe->demodulator_priv;
 
 	u16 snr12 = sp887x_readreg(state, 0xf16);
-		u32 signal = 3 * (snr12 << 4);
+	u32 signal = 3 * (snr12 << 4);
 	*strength = (signal < 0xffff) ? signal : 0xffff;
 
 	return 0;
-	}
+}
 
 static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
-	{
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+{
+	struct sp887x_state* state = fe->demodulator_priv;
 
 	u16 snr12 = sp887x_readreg(state, 0xf16);
 	*snr = (snr12 << 4) | (snr12 >> 8);
 
-	        return 0;
-	}
+	return 0;
+}
 
 static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
 
 	*ucblocks = sp887x_readreg(state, 0xc0c);
 	if (*ucblocks == 0xfff)
 		*ucblocks = ~0;
 
-        return 0;
+	return 0;
 }
 
 static int sp887x_sleep(struct dvb_frontend* fe)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
 
 	/* tristate TS output and disable interface pins */
 	sp887x_writereg(state, 0xc18, 0x000);
 
 	return 0;
-	}
+}
 
 static int sp887x_init(struct dvb_frontend* fe)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
         const struct firmware *fw = NULL;
 	int ret;
 
 	if (!state->initialised) {
-	/* request the firmware, this will block until someone uploads it */
+		/* request the firmware, this will block until someone uploads it */
 		printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE);
 		ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE);
-	if (ret) {
-		printk("sp887x: no firmware upload (timeout or file not found?)\n");
+		if (ret) {
+			printk("sp887x: no firmware upload (timeout or file not found?)\n");
 			return ret;
-	}
+		}
 
 		ret = sp887x_initial_setup(fe, fw);
-	if (ret) {
-		printk("sp887x: writing firmware to device failed\n");
+		if (ret) {
+			printk("sp887x: writing firmware to device failed\n");
 			release_firmware(fw);
 			return ret;
-	}
+		}
 		printk("sp887x: firmware upload complete\n");
 		state->initialised = 1;
 	}
@@ -551,7 +534,7 @@ static int sp887x_get_tune_settings(stru
 
 static void sp887x_release(struct dvb_frontend* fe)
 {
-	struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+	struct sp887x_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -563,7 +546,7 @@ struct dvb_frontend* sp887x_attach(const
 	struct sp887x_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -581,7 +564,7 @@ struct dvb_frontend* sp887x_attach(const
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -29,14 +29,10 @@
 #include "stv0297.h"
 
 struct stv0297_state {
-
-        struct i2c_adapter* i2c;
-
-        struct dvb_frontend_ops ops;
-
-        const struct stv0297_config* config;
-
-        struct dvb_frontend frontend;
+	struct i2c_adapter *i2c;
+	struct dvb_frontend_ops ops;
+	const struct stv0297_config *config;
+	struct dvb_frontend frontend;
 
 	unsigned long base_freq;
 	u8 pwm;
@@ -50,164 +46,164 @@ struct stv0297_state {
 
 #define STV0297_CLOCK_KHZ   28900
 
-static u8 init_tab [] = {
-  0x00, 0x09,
-  0x01, 0x69,
-  0x03, 0x00,
-  0x04, 0x00,
-  0x07, 0x00,
-  0x08, 0x00,
-  0x20, 0x00,
-  0x21, 0x40,
-  0x22, 0x00,
-  0x23, 0x00,
-  0x24, 0x40,
-  0x25, 0x88,
-  0x30, 0xff,
-  0x31, 0x00,
-  0x32, 0xff,
-  0x33, 0x00,
-  0x34, 0x50,
-  0x35, 0x7f,
-  0x36, 0x00,
-  0x37, 0x20,
-  0x38, 0x00,
-  0x40, 0x1c,
-  0x41, 0xff,
-  0x42, 0x29,
+static u8 init_tab[] = {
+	0x00, 0x09,
+	0x01, 0x69,
+	0x03, 0x00,
+	0x04, 0x00,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x20, 0x00,
+	0x21, 0x40,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x40,
+	0x25, 0x88,
+	0x30, 0xff,
+	0x31, 0x00,
+	0x32, 0xff,
+	0x33, 0x00,
+	0x34, 0x50,
+	0x35, 0x7f,
+	0x36, 0x00,
+	0x37, 0x20,
+	0x38, 0x00,
+	0x40, 0x1c,
+	0x41, 0xff,
+	0x42, 0x29,
 	0x43, 0x00,
-  0x44, 0xff,
-  0x45, 0x00,
-  0x46, 0x00,
-  0x49, 0x04,
-  0x4a, 0xff,
-  0x4b, 0x7f,
-  0x52, 0x30,
-  0x55, 0xae,
-  0x56, 0x47,
-  0x57, 0xe1,
-  0x58, 0x3a,
-  0x5a, 0x1e,
-  0x5b, 0x34,
-  0x60, 0x00,
-  0x63, 0x00,
-  0x64, 0x00,
-  0x65, 0x00,
-  0x66, 0x00,
-  0x67, 0x00,
-  0x68, 0x00,
-  0x69, 0x00,
-  0x6a, 0x02,
-  0x6b, 0x00,
-  0x70, 0xff,
-  0x71, 0x00,
-  0x72, 0x00,
-  0x73, 0x00,
-  0x74, 0x0c,
-  0x80, 0x00,
-  0x81, 0x00,
-  0x82, 0x00,
-  0x83, 0x00,
-  0x84, 0x04,
-  0x85, 0x80,
-  0x86, 0x24,
-  0x87, 0x78,
-  0x88, 0x00,
-  0x89, 0x00,
-  0x90, 0x01,
-  0x91, 0x01,
-  0xa0, 0x00,
-  0xa1, 0x00,
-  0xa2, 0x00,
-  0xb0, 0x91,
-  0xb1, 0x0b,
-  0xc0, 0x53,
-  0xc1, 0x70,
-  0xc2, 0x12,
-  0xd0, 0x00,
-  0xd1, 0x00,
-  0xd2, 0x00,
-  0xd3, 0x00,
-  0xd4, 0x00,
-  0xd5, 0x00,
-  0xde, 0x00,
-  0xdf, 0x00,
-  0x61, 0x49,
-  0x62, 0x0b,
-  0x53, 0x08,
-  0x59, 0x08,
+	0x44, 0xff,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x49, 0x04,
+	0x4a, 0xff,
+	0x4b, 0x7f,
+	0x52, 0x30,
+	0x55, 0xae,
+	0x56, 0x47,
+	0x57, 0xe1,
+	0x58, 0x3a,
+	0x5a, 0x1e,
+	0x5b, 0x34,
+	0x60, 0x00,
+	0x63, 0x00,
+	0x64, 0x00,
+	0x65, 0x00,
+	0x66, 0x00,
+	0x67, 0x00,
+	0x68, 0x00,
+	0x69, 0x00,
+	0x6a, 0x02,
+	0x6b, 0x00,
+	0x70, 0xff,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x73, 0x00,
+	0x74, 0x0c,
+	0x80, 0x00,
+	0x81, 0x00,
+	0x82, 0x00,
+	0x83, 0x00,
+	0x84, 0x04,
+	0x85, 0x80,
+	0x86, 0x24,
+	0x87, 0x78,
+	0x88, 0x00,
+	0x89, 0x00,
+	0x90, 0x01,
+	0x91, 0x01,
+	0xa0, 0x00,
+	0xa1, 0x00,
+	0xa2, 0x00,
+	0xb0, 0x91,
+	0xb1, 0x0b,
+	0xc0, 0x53,
+	0xc1, 0x70,
+	0xc2, 0x12,
+	0xd0, 0x00,
+	0xd1, 0x00,
+	0xd2, 0x00,
+	0xd3, 0x00,
+	0xd4, 0x00,
+	0xd5, 0x00,
+	0xde, 0x00,
+	0xdf, 0x00,
+	0x61, 0x49,
+	0x62, 0x0b,
+	0x53, 0x08,
+	0x59, 0x08,
 };
 
 
-static int stv0297_writereg (struct stv0297_state* state, u8 reg, u8 data)
+static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data)
 {
-        int ret;
-        u8 buf [] = { reg, data };
-        struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
 
-        ret = i2c_transfer (state->i2c, &msg, 1);
+	ret = i2c_transfer(state->i2c, &msg, 1);
 
-        if (ret != 1)
-                dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-                  "ret == %i)\n", __FUNCTION__, reg, data, ret);
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __FUNCTION__, reg, data, ret);
 
-        return (ret != 1) ? -1 : 0;
+	return (ret != 1) ? -1 : 0;
 }
 
-static int stv0297_readreg (struct stv0297_state* state, u8 reg)
+static int stv0297_readreg(struct stv0297_state *state, u8 reg)
 {
-        int ret;
-        u8 b0[] = { reg };
-        u8 b1[] = { 0 };
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
 	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
 				  1},
 	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
 	};
 
-        // this device needs a STOP between the register and data
-        if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
+	// this device needs a STOP between the register and data
+	if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-                return -1;
-        }
-        if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) {
+		return -1;
+	}
+	if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-                return -1;
-        }
+		return -1;
+	}
 
-        return b1[0];
+	return b1[0];
 }
 
-static int stv0297_writereg_mask (struct stv0297_state* state, u8 reg, u8 mask, u8 data)
+static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data)
 {
-        int val;
+	int val;
 
-        val = stv0297_readreg(state, reg);
-        val &= ~mask;
-        val |= (data & mask);
-        stv0297_writereg(state, reg, val);
+	val = stv0297_readreg(state, reg);
+	val &= ~mask;
+	val |= (data & mask);
+	stv0297_writereg(state, reg, val);
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len)
+static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len)
 {
-        int ret;
+	int ret;
 	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf =
 				  &reg1,.len = 1},
 	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
 	};
 
-        // this device needs a STOP between the register and data
-        if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
+	// this device needs a STOP between the register and data
+	if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-                return -1;
-        }
-        if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) {
+		return -1;
+	}
+	if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-                return -1;
-        }
+		return -1;
+	}
 
-        return 0;
+	return 0;
 }
 
 static u32 stv0297_get_symbolrate(struct stv0297_state *state)
@@ -233,10 +229,10 @@ static void stv0297_set_symbolrate(struc
 	tmp = tmp / (STV0297_CLOCK_KHZ / 4);	/* 1/4 = 2^-2 */
 	tmp = tmp * 8192L;	/* 8192 = 2^13 */
 
-        stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF));
-        stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8));
-        stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16));
-        stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24));
+	stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF));
+	stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8));
+	stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16));
+	stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24));
 }
 
 static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate)
@@ -247,19 +243,19 @@ static void stv0297_set_sweeprate(struct
 	tmp /= symrate;
 	tmp *= 1024;		/* 1024 = 2*10   */
 
-        // adjust
-        if (tmp >= 0) {
-                tmp += 500000;
-        } else {
-                tmp -= 500000;
-        }
+	// adjust
+	if (tmp >= 0) {
+		tmp += 500000;
+	} else {
+		tmp -= 500000;
+	}
 	tmp /= 1000000;
 
-        stv0297_writereg(state, 0x60, tmp & 0xFF);
-        stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0);
+	stv0297_writereg(state, 0x60, tmp & 0xFF);
+	stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0);
 }
 
-static void stv0297_set_carrieroffset(struct stv0297_state* state, long offset)
+static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset)
 {
 	long tmp;
 
@@ -276,11 +272,11 @@ static void stv0297_set_carrieroffset(st
 }
 
 /*
-static long stv0297_get_carrieroffset(struct stv0297_state* state)
+static long stv0297_get_carrieroffset(struct stv0297_state *state)
 {
 	s64 tmp;
 
-        stv0297_writereg(state,0x6B, 0x00);
+	stv0297_writereg(state, 0x6B, 0x00);
 
 	tmp = stv0297_readreg(state, 0x66);
 	tmp |= (stv0297_readreg(state, 0x67) << 8);
@@ -294,7 +290,7 @@ static long stv0297_get_carrieroffset(st
 }
 */
 
-static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq)
+static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq)
 {
 	s32 tmp;
 
@@ -306,254 +302,242 @@ static void stv0297_set_initialdemodfreq
 	if (tmp > 0xffff)
 		tmp = 0xffff;
 
-        stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
-        stv0297_writereg(state, 0x21, tmp >> 8);
-        stv0297_writereg(state, 0x20, tmp);
+	stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
+	stv0297_writereg(state, 0x21, tmp >> 8);
+	stv0297_writereg(state, 0x20, tmp);
 }
 
-static int stv0297_set_qam(struct stv0297_state* state, fe_modulation_t modulation)
+static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation)
 {
-        int val = 0;
+	int val = 0;
 
-        switch(modulation) {
-        case QAM_16:
-                val = 0;
-                break;
+	switch (modulation) {
+	case QAM_16:
+		val = 0;
+		break;
 
-        case QAM_32:
-                val = 1;
-                break;
+	case QAM_32:
+		val = 1;
+		break;
 
-        case QAM_64:
-                val = 4;
-                break;
+	case QAM_64:
+		val = 4;
+		break;
 
-        case QAM_128:
-                val = 2;
-                break;
+	case QAM_128:
+		val = 2;
+		break;
 
-        case QAM_256:
-                val = 3;
-                break;
+	case QAM_256:
+		val = 3;
+		break;
 
-        default:
-                return -EINVAL;
-        }
+	default:
+		return -EINVAL;
+	}
 
-        stv0297_writereg_mask(state, 0x00, 0x70, val << 4);
+	stv0297_writereg_mask(state, 0x00, 0x70, val << 4);
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_set_inversion(struct stv0297_state* state, fe_spectral_inversion_t inversion)
+static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion)
 {
-        int val = 0;
+	int val = 0;
 
-        switch(inversion) {
-        case INVERSION_OFF:
-                val = 0;
-                break;
+	switch (inversion) {
+	case INVERSION_OFF:
+		val = 0;
+		break;
 
-        case INVERSION_ON:
-                val = 1;
-                break;
+	case INVERSION_ON:
+		val = 1;
+		break;
 
-        default:
-                return -EINVAL;
-        }
+	default:
+		return -EINVAL;
+	}
 
-        stv0297_writereg_mask(state, 0x83, 0x08, val << 3);
+	stv0297_writereg_mask(state, 0x83, 0x08, val << 3);
 
-        return 0;
+	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-int stv0297_enable_plli2c(struct dvb_frontend* fe)
+int stv0297_enable_plli2c(struct dvb_frontend *fe)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+	struct stv0297_state *state = fe->demodulator_priv;
 
-        stv0297_writereg(state, 0x87, 0x78);
-        stv0297_writereg(state, 0x86, 0xc8);
+	stv0297_writereg(state, 0x87, 0x78);
+	stv0297_writereg(state, 0x86, 0xc8);
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_init (struct dvb_frontend* fe)
+static int stv0297_init(struct dvb_frontend *fe)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        int i;
+	struct stv0297_state *state = fe->demodulator_priv;
+	int i;
 
 	/* soft reset */
-        stv0297_writereg_mask(state, 0x80, 1, 1);
-        stv0297_writereg_mask(state, 0x80, 1, 0);
+	stv0297_writereg_mask(state, 0x80, 1, 1);
+	stv0297_writereg_mask(state, 0x80, 1, 0);
 
 	/* reset deinterleaver */
-        stv0297_writereg_mask(state, 0x81, 1, 1);
-        stv0297_writereg_mask(state, 0x81, 1, 0);
+	stv0297_writereg_mask(state, 0x81, 1, 1);
+	stv0297_writereg_mask(state, 0x81, 1, 0);
 
 	/* load init table */
-        for (i=0; i<sizeof(init_tab); i+=2) {
-                stv0297_writereg (state, init_tab[i], init_tab[i+1]);
-        }
+	for (i = 0; i < sizeof(init_tab); i += 2) {
+		stv0297_writereg(state, init_tab[i], init_tab[i + 1]);
+	}
 
 	/* set a dummy symbol rate */
-        stv0297_set_symbolrate(state, 6900);
+	stv0297_set_symbolrate(state, 6900);
 
 	/* invert AGC1 polarity */
-        stv0297_writereg_mask(state, 0x88, 0x10, 0x10);
+	stv0297_writereg_mask(state, 0x88, 0x10, 0x10);
 
 	/* setup bit error counting */
-        stv0297_writereg_mask(state, 0xA0, 0x80, 0x00);
-        stv0297_writereg_mask(state, 0xA0, 0x10, 0x00);
-        stv0297_writereg_mask(state, 0xA0, 0x08, 0x00);
-        stv0297_writereg_mask(state, 0xA0, 0x07, 0x04);
+	stv0297_writereg_mask(state, 0xA0, 0x80, 0x00);
+	stv0297_writereg_mask(state, 0xA0, 0x10, 0x00);
+	stv0297_writereg_mask(state, 0xA0, 0x08, 0x00);
+	stv0297_writereg_mask(state, 0xA0, 0x07, 0x04);
 
 	/* min + max PWM */
-        stv0297_writereg(state, 0x4a, 0x00);
-        stv0297_writereg(state, 0x4b, state->pwm);
-        msleep(200);
+	stv0297_writereg(state, 0x4a, 0x00);
+	stv0297_writereg(state, 0x4b, state->pwm);
+	msleep(200);
 
 	if (state->config->pll_init)
 		state->config->pll_init(fe);
 
-        return 0;
+	return 0;
 }
 
 static int stv0297_sleep(struct dvb_frontend *fe)
 {
-	struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv;
+	struct stv0297_state *state = fe->demodulator_priv;
 
 	stv0297_writereg_mask(state, 0x80, 1, 1);
 
 	return 0;
 }
 
-static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+	struct stv0297_state *state = fe->demodulator_priv;
 
-        u8 sync = stv0297_readreg (state, 0xDF);
+	u8 sync = stv0297_readreg(state, 0xDF);
 
-        *status = 0;
-        if (sync & 0x80)
+	*status = 0;
+	if (sync & 0x80)
 		*status |=
 			FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
-        return 0;
+	return 0;
 }
 
-static int stv0297_read_ber(struct dvb_frontend* fe, u32* ber)
+static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        u8 BER[3];
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 BER[3];
 
-        stv0297_writereg (state, 0xA0, 0x80);	// Start Counting bit errors for 4096 Bytes
-        mdelay(25);				// Hopefully got 4096 Bytes
-        stv0297_readregs (state, 0xA0, BER, 3);
-        mdelay(25);
-        *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096);
+	stv0297_writereg(state, 0xA0, 0x80);	// Start Counting bit errors for 4096 Bytes
+	mdelay(25);		// Hopefully got 4096 Bytes
+	stv0297_readregs(state, 0xA0, BER, 3);
+	mdelay(25);
+	*ber = (BER[2] << 8 | BER[1]) / (8 * 4096);
 
-        return 0;
+	return 0;
 }
 
 
-static int stv0297_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        u8 STRENGTH[2];
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 STRENGTH[2];
 
-        stv0297_readregs (state, 0x41, STRENGTH, 2);
-        *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
+	stv0297_readregs(state, 0x41, STRENGTH, 2);
+	*strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_read_snr(struct dvb_frontend* fe, u16* snr)
+static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        u8 SNR[2];
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 SNR[2];
 
-        stv0297_readregs (state, 0x07, SNR, 2);
-        *snr = SNR[1] << 8 | SNR[0];
+	stv0297_readregs(state, 0x07, SNR, 2);
+	*snr = SNR[1] << 8 | SNR[0];
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+	struct stv0297_state *state = fe->demodulator_priv;
 
-        *ucblocks = (stv0297_readreg (state, 0xD5) << 8)
-                   | stv0297_readreg (state, 0xD4);
+	*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
+		| stv0297_readreg(state, 0xD4);
 
-        return 0;
+	return 0;
 }
 
-static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        int u_threshold;
-        int initial_u;
-        int blind_u;
-        int delay;
-        int sweeprate;
-        int carrieroffset;
-        unsigned long starttime;
-        unsigned long timeout;
+	struct stv0297_state *state = fe->demodulator_priv;
+	int u_threshold;
+	int initial_u;
+	int blind_u;
+	int delay;
+	int sweeprate;
+	int carrieroffset;
+	unsigned long starttime;
+	unsigned long timeout;
 	fe_spectral_inversion_t inversion;
 
-        switch(p->u.qam.modulation) {
-        case QAM_16:
-        case QAM_32:
-        case QAM_64:
-          delay = 100;
-          sweeprate = 1500;
-          break;
-
-        case QAM_128:
-          delay = 150;
-          sweeprate = 1000;
-          break;
-
-        case QAM_256:
-          delay = 200;
-          sweeprate = 500;
-          break;
-
-        default:
-          return -EINVAL;
-        }
+	switch (p->u.qam.modulation) {
+	case QAM_16:
+	case QAM_32:
+	case QAM_64:
+		delay = 100;
+		sweeprate = 1500;
+		break;
+
+	case QAM_128:
+		delay = 150;
+		sweeprate = 1000;
+		break;
+
+	case QAM_256:
+		delay = 200;
+		sweeprate = 500;
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
-        // determine inversion dependant parameters
+	// determine inversion dependant parameters
 	inversion = p->inversion;
 	if (state->config->invert)
 		inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
-        carrieroffset = -330;
+	carrieroffset = -330;
 	switch (inversion) {
-        case INVERSION_OFF:
-          break;
+	case INVERSION_OFF:
+		break;
+
+	case INVERSION_ON:
+		sweeprate = -sweeprate;
+		carrieroffset = -carrieroffset;
+		break;
 
-        case INVERSION_ON:
-          sweeprate = -sweeprate;
-          carrieroffset = -carrieroffset;
-          break;
-
-        default:
-          return -EINVAL;
-        }
+	default:
+		return -EINVAL;
+	}
 
 	stv0297_init(fe);
-        state->config->pll_set(fe, p);
+	state->config->pll_set(fe, p);
 
 	/* clear software interrupts */
 	stv0297_writereg(state, 0x82, 0x0);
@@ -562,163 +546,163 @@ static int stv0297_set_frontend(struct d
 	stv0297_set_initialdemodfreq(state, 7250);
 
 	/* setup AGC */
-        stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
-        stv0297_writereg(state, 0x41, 0x00);
-        stv0297_writereg_mask(state, 0x42, 0x03, 0x01);
-        stv0297_writereg_mask(state, 0x36, 0x60, 0x00);
-        stv0297_writereg_mask(state, 0x36, 0x18, 0x00);
-        stv0297_writereg_mask(state, 0x71, 0x80, 0x80);
-        stv0297_writereg(state, 0x72, 0x00);
-        stv0297_writereg(state, 0x73, 0x00);
-        stv0297_writereg_mask(state, 0x74, 0x0F, 0x00);
-        stv0297_writereg_mask(state, 0x43, 0x08, 0x00);
-        stv0297_writereg_mask(state, 0x71, 0x80, 0x00);
+	stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
+	stv0297_writereg(state, 0x41, 0x00);
+	stv0297_writereg_mask(state, 0x42, 0x03, 0x01);
+	stv0297_writereg_mask(state, 0x36, 0x60, 0x00);
+	stv0297_writereg_mask(state, 0x36, 0x18, 0x00);
+	stv0297_writereg_mask(state, 0x71, 0x80, 0x80);
+	stv0297_writereg(state, 0x72, 0x00);
+	stv0297_writereg(state, 0x73, 0x00);
+	stv0297_writereg_mask(state, 0x74, 0x0F, 0x00);
+	stv0297_writereg_mask(state, 0x43, 0x08, 0x00);
+	stv0297_writereg_mask(state, 0x71, 0x80, 0x00);
 
 	/* setup STL */
-        stv0297_writereg_mask(state, 0x5a, 0x20, 0x20);
-        stv0297_writereg_mask(state, 0x5b, 0x02, 0x02);
-        stv0297_writereg_mask(state, 0x5b, 0x02, 0x00);
-        stv0297_writereg_mask(state, 0x5b, 0x01, 0x00);
-        stv0297_writereg_mask(state, 0x5a, 0x40, 0x40);
+	stv0297_writereg_mask(state, 0x5a, 0x20, 0x20);
+	stv0297_writereg_mask(state, 0x5b, 0x02, 0x02);
+	stv0297_writereg_mask(state, 0x5b, 0x02, 0x00);
+	stv0297_writereg_mask(state, 0x5b, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x5a, 0x40, 0x40);
 
 	/* disable frequency sweep */
-        stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
 
 	/* reset deinterleaver */
-        stv0297_writereg_mask(state, 0x81, 0x01, 0x01);
-        stv0297_writereg_mask(state, 0x81, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x81, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x81, 0x01, 0x00);
 
 	/* ??? */
-        stv0297_writereg_mask(state, 0x83, 0x20, 0x20);
-        stv0297_writereg_mask(state, 0x83, 0x20, 0x00);
+	stv0297_writereg_mask(state, 0x83, 0x20, 0x20);
+	stv0297_writereg_mask(state, 0x83, 0x20, 0x00);
 
 	/* reset equaliser */
-        u_threshold = stv0297_readreg(state, 0x00) & 0xf;
-        initial_u = stv0297_readreg(state, 0x01) >> 4;
-        blind_u = stv0297_readreg(state, 0x01) & 0xf;
-        stv0297_writereg_mask(state, 0x84, 0x01, 0x01);
-        stv0297_writereg_mask(state, 0x84, 0x01, 0x00);
-        stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold);
-        stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4);
-        stv0297_writereg_mask(state, 0x01, 0x0f, blind_u);
+	u_threshold = stv0297_readreg(state, 0x00) & 0xf;
+	initial_u = stv0297_readreg(state, 0x01) >> 4;
+	blind_u = stv0297_readreg(state, 0x01) & 0xf;
+	stv0297_writereg_mask(state, 0x84, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x84, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold);
+	stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4);
+	stv0297_writereg_mask(state, 0x01, 0x0f, blind_u);
 
 	/* data comes from internal A/D */
-        stv0297_writereg_mask(state, 0x87, 0x80, 0x00);
+	stv0297_writereg_mask(state, 0x87, 0x80, 0x00);
 
 	/* clear phase registers */
-        stv0297_writereg(state, 0x63, 0x00);
-        stv0297_writereg(state, 0x64, 0x00);
-        stv0297_writereg(state, 0x65, 0x00);
-        stv0297_writereg(state, 0x66, 0x00);
-        stv0297_writereg(state, 0x67, 0x00);
-        stv0297_writereg(state, 0x68, 0x00);
-        stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
+	stv0297_writereg(state, 0x63, 0x00);
+	stv0297_writereg(state, 0x64, 0x00);
+	stv0297_writereg(state, 0x65, 0x00);
+	stv0297_writereg(state, 0x66, 0x00);
+	stv0297_writereg(state, 0x67, 0x00);
+	stv0297_writereg(state, 0x68, 0x00);
+	stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
 
 	/* set parameters */
-        stv0297_set_qam(state, p->u.qam.modulation);
-        stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000);
+	stv0297_set_qam(state, p->u.qam.modulation);
+	stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000);
 	stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000);
-        stv0297_set_carrieroffset(state, carrieroffset);
+	stv0297_set_carrieroffset(state, carrieroffset);
 	stv0297_set_inversion(state, inversion);
 
 	/* kick off lock */
-        stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
-        stv0297_writereg_mask(state, 0x5a, 0x20, 0x00);
-        stv0297_writereg_mask(state, 0x6a, 0x01, 0x01);
-        stv0297_writereg_mask(state, 0x43, 0x40, 0x40);
-        stv0297_writereg_mask(state, 0x5b, 0x30, 0x00);
-        stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c);
-        stv0297_writereg_mask(state, 0x03, 0x03, 0x03);
-        stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
+	stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
+	stv0297_writereg_mask(state, 0x5a, 0x20, 0x00);
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x43, 0x40, 0x40);
+	stv0297_writereg_mask(state, 0x5b, 0x30, 0x00);
+	stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c);
+	stv0297_writereg_mask(state, 0x03, 0x03, 0x03);
+	stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
 
 	/* wait for WGAGC lock */
-        starttime = jiffies;
-        timeout = jiffies + (200*HZ)/1000;
-        while(time_before(jiffies, timeout)) {
-                msleep(10);
+	starttime = jiffies;
+	timeout = jiffies + (200 * HZ) / 1000;
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
 		if (stv0297_readreg(state, 0x43) & 0x08)
 			break;
-        }
-        if (time_after(jiffies, timeout)) {
-                goto timeout;
-        }
-        msleep(20);
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+	msleep(20);
 
 	/* wait for equaliser partial convergence */
-        timeout = jiffies + (50*HZ)/1000;
-        while(time_before(jiffies, timeout)) {
-                msleep(10);
+	timeout = jiffies + (50 * HZ) / 1000;
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
 
-                if (stv0297_readreg(state, 0x82) & 0x04) {
+		if (stv0297_readreg(state, 0x82) & 0x04) {
 			break;
-                }
-        }
+		}
+	}
 	if (time_after(jiffies, timeout)) {
-                goto timeout;
-        }
+		goto timeout;
+	}
 
 	/* wait for equaliser full convergence */
-        timeout = jiffies + (delay*HZ)/1000;
-        while(time_before(jiffies, timeout)) {
-                msleep(10);
-
-                if (stv0297_readreg(state, 0x82) & 0x08) {
-                        break;
-                }
-        }
-        if (time_after(jiffies, timeout)) {
-                goto timeout;
-        }
+	timeout = jiffies + (delay * HZ) / 1000;
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+
+		if (stv0297_readreg(state, 0x82) & 0x08) {
+			break;
+		}
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
 
 	/* disable sweep */
-        stv0297_writereg_mask(state, 0x6a, 1, 0);
-        stv0297_writereg_mask(state, 0x88, 8, 0);
+	stv0297_writereg_mask(state, 0x6a, 1, 0);
+	stv0297_writereg_mask(state, 0x88, 8, 0);
 
 	/* wait for main lock */
-        timeout = jiffies + (20*HZ)/1000;
-        while(time_before(jiffies, timeout)) {
-                msleep(10);
-
-                if (stv0297_readreg(state, 0xDF) & 0x80) {
-                        break;
-                }
-        }
-        if (time_after(jiffies, timeout)) {
-                goto timeout;
-        }
-        msleep(100);
+	timeout = jiffies + (20 * HZ) / 1000;
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+
+		if (stv0297_readreg(state, 0xDF) & 0x80) {
+			break;
+		}
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+	msleep(100);
 
 	/* is it still locked after that delay? */
-        if (!(stv0297_readreg(state, 0xDF) & 0x80)) {
-                goto timeout;
-        }
+	if (!(stv0297_readreg(state, 0xDF) & 0x80)) {
+		goto timeout;
+	}
 
 	/* success!! */
-        stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
-        state->base_freq = p->frequency;
-        return 0;
+	stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
+	state->base_freq = p->frequency;
+	return 0;
 
 timeout:
-        stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
-        return 0;
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+	return 0;
 }
 
-static int stv0297_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        int reg_00, reg_83;
+	struct stv0297_state *state = fe->demodulator_priv;
+	int reg_00, reg_83;
 
-        reg_00 = stv0297_readreg(state, 0x00);
-        reg_83 = stv0297_readreg(state, 0x83);
+	reg_00 = stv0297_readreg(state, 0x00);
+	reg_83 = stv0297_readreg(state, 0x83);
 
 	p->frequency = state->base_freq;
-        p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
+	p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
 	if (state->config->invert)
 		p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
 	p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000;
 	p->u.qam.fec_inner = FEC_NONE;
 
-        switch((reg_00 >> 4) & 0x7) {
+	switch ((reg_00 >> 4) & 0x7) {
 	case 0:
 		p->u.qam.modulation = QAM_16;
 		break;
@@ -734,77 +718,76 @@ static int stv0297_get_frontend(struct d
 	case 4:
 		p->u.qam.modulation = QAM_64;
 		break;
-        }
+	}
 
-        return 0;
+	return 0;
 }
 
-static void stv0297_release(struct dvb_frontend* fe)
+static void stv0297_release(struct dvb_frontend *fe)
 {
-        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
-        kfree(state);
+	struct stv0297_state *state = fe->demodulator_priv;
+	kfree(state);
 }
 
 static struct dvb_frontend_ops stv0297_ops;
 
-struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
 				    struct i2c_adapter *i2c, int pwm)
 {
-        struct stv0297_state* state = NULL;
+	struct stv0297_state *state = NULL;
 
-        /* allocate memory for the internal state */
-        state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL);
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct stv0297_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
 
-        /* setup the state */
-        state->config = config;
-        state->i2c = i2c;
-        memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
-        state->base_freq = 0;
-        state->pwm = pwm;
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
+	state->base_freq = 0;
+	state->pwm = pwm;
 
-        /* check if the demod is there */
+	/* check if the demod is there */
 	if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20)
 		goto error;
 
-        /* create dvb_frontend */
-        state->frontend.ops = &state->ops;
-        state->frontend.demodulator_priv = state;
-        return &state->frontend;
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
 
 error:
-	if (state)
-		kfree(state);
-        return NULL;
+	kfree(state);
+	return NULL;
 }
 
 static struct dvb_frontend_ops stv0297_ops = {
 
-        .info = {
-                .name			= "ST STV0297 DVB-C",
-                .type			= FE_QAM,
-                .frequency_min		= 64000000,
-                .frequency_max		= 1300000000,
-                .frequency_stepsize	= 62500,
-                .symbol_rate_min	= 870000,
-                .symbol_rate_max	= 11700000,
-                .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+	.info = {
+		 .name = "ST STV0297 DVB-C",
+		 .type = FE_QAM,
+		 .frequency_min = 64000000,
+		 .frequency_max = 1300000000,
+		 .frequency_stepsize = 62500,
+		 .symbol_rate_min = 870000,
+		 .symbol_rate_max = 11700000,
+		 .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 		 FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
 
-        .release = stv0297_release,
+	.release = stv0297_release,
 
-        .init = stv0297_init,
+	.init = stv0297_init,
 	.sleep = stv0297_sleep,
 
-        .set_frontend = stv0297_set_frontend,
-        .get_frontend = stv0297_get_frontend,
+	.set_frontend = stv0297_set_frontend,
+	.get_frontend = stv0297_get_frontend,
 
-        .read_status = stv0297_read_status,
-        .read_ber = stv0297_read_ber,
-        .read_signal_strength = stv0297_read_signal_strength,
-        .read_snr = stv0297_read_snr,
-        .read_ucblocks = stv0297_read_ucblocks,
+	.read_status = stv0297_read_status,
+	.read_ber = stv0297_read_ber,
+	.read_signal_strength = stv0297_read_signal_strength,
+	.read_snr = stv0297_read_snr,
+	.read_ucblocks = stv0297_read_ucblocks,
 };
 
 MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -5,7 +5,7 @@
 	<ralph@convergence.de>,
 	<holger@convergence.de>,
 	<js@convergence.de>
-    
+
 
     Philips SU1278/SH
 
@@ -15,7 +15,7 @@
     LG TDQF-S001F
 
     Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
-                     & Andreas Oberritter <obi@linuxtv.org>
+		     & Andreas Oberritter <obi@linuxtv.org>
 
 
     Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
@@ -40,7 +40,7 @@
     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>
@@ -54,13 +54,9 @@
 #include "stv0299.h"
 
 struct stv0299_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	const struct stv0299_config* config;
-
 	struct dvb_frontend frontend;
 
 	u8 initialised:1;
@@ -74,6 +70,7 @@ struct stv0299_state {
 #define STATUS_UCBLOCKS 1
 
 static int debug;
+static int debug_legacy_dish_switch;
 #define dprintk(args...) \
 	do { \
 		if (debug) printk(KERN_DEBUG "stv0299: " args); \
@@ -88,7 +85,7 @@ static int stv0299_writeregI (struct stv
 
 	ret = i2c_transfer (state->i2c, &msg, 1);
 
-	if (ret != 1) 
+	if (ret != 1)
 		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
 			"ret == %i)\n", __FUNCTION__, reg, data, ret);
 
@@ -97,12 +94,11 @@ static int stv0299_writeregI (struct stv
 
 int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	return stv0299_writeregI(state, reg, data);
 }
 
-
 static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
 {
 	int ret;
@@ -112,30 +108,28 @@ static u8 stv0299_readreg (struct stv029
 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
 	ret = i2c_transfer (state->i2c, msg, 2);
-        
-	if (ret != 2) 
+
+	if (ret != 2)
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
 				__FUNCTION__, reg, ret);
 
 	return b1[0];
 }
 
-
 static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
 {
-        int ret;
+	int ret;
 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
 
 	ret = i2c_transfer (state->i2c, msg, 2);
 
-        if (ret != 2)
-                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+	if (ret != 2)
+		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
 
-        return ret == 2 ? 0 : ret;
+	return ret == 2 ? 0 : ret;
 }
 
-
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
 	dprintk ("%s\n", __FUNCTION__);
@@ -169,9 +163,8 @@ static int stv0299_set_FEC (struct stv02
 	{
 		return -EINVAL;
 	}
+    }
 }
-}
-
 
 static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
 {
@@ -190,7 +183,6 @@ static fe_code_rate_t stv0299_get_fec (s
 	return fec_tab [index];
 }
 
-
 static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
 {
 	unsigned long start = jiffies;
@@ -208,7 +200,6 @@ static int stv0299_wait_diseqc_fifo (str
 	return 0;
 }
 
-
 static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
 {
 	unsigned long start = jiffies;
@@ -228,7 +219,7 @@ static int stv0299_wait_diseqc_idle (str
 
 static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	u64 big = srate;
 	u32 ratio;
 
@@ -244,7 +235,6 @@ static int stv0299_set_symbolrate (struc
 	return state->config->set_symbol_rate(fe, srate, ratio);
 }
 
-
 static int stv0299_get_symbolrate (struct stv0299_state* state)
 {
 	u32 Mclk = state->config->mclk / 4096L;
@@ -277,23 +267,10 @@ static int stv0299_get_symbolrate (struc
 	return srate;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
 static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
-			     struct dvb_diseqc_master_cmd *m)
+				    struct dvb_diseqc_master_cmd *m)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	u8 val;
 	int i;
 
@@ -321,10 +298,9 @@ static int stv0299_send_diseqc_msg (stru
 	return 0;
 }
 
-
 static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	u8 val;
 
 	dprintk ("%s\n", __FUNCTION__);
@@ -349,10 +325,9 @@ static int stv0299_send_diseqc_burst (st
 	return 0;
 }
 
-
 static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	u8 val;
 
 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
@@ -372,15 +347,14 @@ static int stv0299_set_tone (struct dvb_
 	}
 }
 
-
 static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	u8 reg0x08;
 	u8 reg0x0c;
 
 	dprintk("%s: %s\n", __FUNCTION__,
-		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 
+		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
 		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
 
 	reg0x08 = stv0299_readreg (state, 0x08);
@@ -395,7 +369,7 @@ static int stv0299_set_voltage (struct d
 		stv0299_writeregI (state, 0x0c, 0x00); /*	LNB power off! */
 		return stv0299_writeregI (state, 0x08, 0x00); /*	LNB power off! */
 	}
-	
+
 	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
 
 	switch (voltage) {
@@ -412,46 +386,92 @@ static int stv0299_set_voltage (struct d
 	};
 }
 
+static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime)
+{
+	return ((curtime.tv_usec < lasttime.tv_usec) ?
+		1000000 - lasttime.tv_usec + curtime.tv_usec :
+		curtime.tv_usec - lasttime.tv_usec);
+}
 
-static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd)
+static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec)
 {
+	struct timeval lasttime;
+	s32 delta, newdelta;
+
+	waketime->tv_usec += add_usec;
+	if (waketime->tv_usec >= 1000000) {
+		waketime->tv_usec -= 1000000;
+		waketime->tv_sec++;
+	}
+
+	do_gettimeofday (&lasttime);
+	delta = stv0299_calc_usec_delay (lasttime, *waketime);
+	if (delta > 2500) {
+		msleep ((delta - 1500) / 1000);
+		do_gettimeofday (&lasttime);
+		newdelta = stv0299_calc_usec_delay (lasttime, *waketime);
+		delta = (newdelta > delta) ? 0 : newdelta;
+	}
+	if (delta > 0)
+		udelay (delta);
+}
+
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 reg0x08;
+	u8 reg0x0c;
+	u8 lv_mask = 0x40;
 	u8 last = 1;
 	int i;
+	struct timeval nexttime;
+	struct timeval tv[10];
 
-	/* reset voltage at the end
-	if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50)
-		cmd |= 0x80;
-	else
-		cmd &= 0x7F;
-	*/
+	reg0x08 = stv0299_readreg (state, 0x08);
+	reg0x0c = stv0299_readreg (state, 0x0c);
+	reg0x0c &= 0x0f;
+	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
+	if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
+		lv_mask = 0x10;
 
 	cmd = cmd << 1;
-	dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+	if (debug_legacy_dish_switch)
+		printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+
+	do_gettimeofday (&nexttime);
+	if (debug_legacy_dish_switch)
+		memcpy (&tv[0], &nexttime, sizeof (struct timeval));
+	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
 
-	stv0299_set_voltage(fe,SEC_VOLTAGE_18);
-	msleep(32);
+	stv0299_sleep_until (&nexttime, 32000);
 
 	for (i=0; i<9; i++) {
+		if (debug_legacy_dish_switch)
+			do_gettimeofday (&tv[i+1]);
 		if((cmd & 0x01) != last) {
-			stv0299_set_voltage(fe,
-					    last ? SEC_VOLTAGE_13 :
-					    	   SEC_VOLTAGE_18);
+			/* set voltage to (last ? 13V : 18V) */
+			stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
 			last = (last) ? 0 : 1;
 		}
 
 		cmd = cmd >> 1;
 
 		if (i != 8)
-			msleep(8);
+			stv0299_sleep_until (&nexttime, 8000);
+	}
+	if (debug_legacy_dish_switch) {
+		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
+			__FUNCTION__, fe->dvb->num);
+		for (i=1; i < 10; i++)
+			printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i]));
 	}
 
 	return 0;
 }
 
-
 static int stv0299_init (struct dvb_frontend* fe)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 	int i;
 
 	dprintk("stv0299: init chip\n");
@@ -468,65 +488,64 @@ static int stv0299_init (struct dvb_fron
 	return 0;
 }
 
-
 static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
-	{
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	u8 signal = 0xff - stv0299_readreg (state, 0x18);
 	u8 sync = stv0299_readreg (state, 0x1b);
 
-		dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
-		*status = 0;
+	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
+	*status = 0;
 
-		if (signal > 10)
-			*status |= FE_HAS_SIGNAL;
+	if (signal > 10)
+		*status |= FE_HAS_SIGNAL;
 
-		if (sync & 0x80)
-			*status |= FE_HAS_CARRIER;
+	if (sync & 0x80)
+		*status |= FE_HAS_CARRIER;
 
-		if (sync & 0x10)
-			*status |= FE_HAS_VITERBI;
+	if (sync & 0x10)
+		*status |= FE_HAS_VITERBI;
 
-		if (sync & 0x08)
-			*status |= FE_HAS_SYNC;
+	if (sync & 0x08)
+		*status |= FE_HAS_SYNC;
 
-		if ((sync & 0x98) == 0x98)
-			*status |= FE_HAS_LOCK;
+	if ((sync & 0x98) == 0x98)
+		*status |= FE_HAS_LOCK;
 
 	return 0;
-	}
+}
 
 static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	if (state->errmode != STATUS_BER) return 0;
 	*ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
 
 	return 0;
-		}
+}
 
 static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-	{
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
 			       | stv0299_readreg (state, 0x19));
 
-		dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
+	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
 		 stv0299_readreg (state, 0x18),
 		 stv0299_readreg (state, 0x19), (int) signal);
 
-		signal = signal * 5 / 4;
+	signal = signal * 5 / 4;
 	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
 
 	return 0;
-		}
+}
 
 static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
-        {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
 			   | stv0299_readreg (state, 0x25));
@@ -538,7 +557,7 @@ static int stv0299_read_snr(struct dvb_f
 
 static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
 	else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
@@ -548,41 +567,41 @@ static int stv0299_read_ucblocks(struct 
 
 static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
-		int invval = 0;
+        struct stv0299_state* state = fe->demodulator_priv;
+	int invval = 0;
 
-		dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
+	dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
 
-		// set the inversion
-		if (p->inversion == INVERSION_OFF) invval = 0;
-		else if (p->inversion == INVERSION_ON) invval = 1;
-		else {
-			printk("stv0299 does not support auto-inversion\n");
-			return -EINVAL;
-		}
+	// set the inversion
+	if (p->inversion == INVERSION_OFF) invval = 0;
+	else if (p->inversion == INVERSION_ON) invval = 1;
+	else {
+		printk("stv0299 does not support auto-inversion\n");
+		return -EINVAL;
+	}
 	if (state->config->invert) invval = (~invval) & 1;
 	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
 	if (state->config->enhanced_tuning) {
-			/* check if we should do a finetune */
-			int frequency_delta = p->frequency - state->tuner_frequency;
-			int minmax = p->u.qpsk.symbol_rate / 2000;
-			if (minmax < 5000) minmax = 5000;
-		   
-			if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
-			    (state->fec_inner == p->u.qpsk.fec_inner) && 
-			    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+		/* check if we should do a finetune */
+		int frequency_delta = p->frequency - state->tuner_frequency;
+		int minmax = p->u.qpsk.symbol_rate / 2000;
+		if (minmax < 5000) minmax = 5000;
+
+		if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
+		    (state->fec_inner == p->u.qpsk.fec_inner) &&
+		    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
 			int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
 
-				// zap the derotator registers first
+			// zap the derotator registers first
 			stv0299_writeregI(state, 0x22, 0x00);
 			stv0299_writeregI(state, 0x23, 0x00);
 
-				// now set them as we want
+			// now set them as we want
 			stv0299_writeregI(state, 0x22, Drot_freq >> 8);
 			stv0299_writeregI(state, 0x23, Drot_freq);
-			} else {
-				/* A "normal" tune is requested */
+		} else {
+			/* A "normal" tune is requested */
 			stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
 			state->config->pll_set(fe, p);
 			stv0299_writeregI(state, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
@@ -605,43 +624,43 @@ static int stv0299_set_frontend(struct d
 		stv0299_writeregI(state, 0x23, 0x00);
 		stv0299_readreg (state, 0x23);
 		stv0299_writeregI(state, 0x12, 0xb9);
-		}
+	}
 
-		state->tuner_frequency = p->frequency;
-		state->fec_inner = p->u.qpsk.fec_inner;
-		state->symbol_rate = p->u.qpsk.symbol_rate;
+	state->tuner_frequency = p->frequency;
+	state->fec_inner = p->u.qpsk.fec_inner;
+	state->symbol_rate = p->u.qpsk.symbol_rate;
 
 	return 0;
-        }
+}
 
 static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
-        {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
-		s32 derot_freq;
-		int invval;
+{
+        struct stv0299_state* state = fe->demodulator_priv;
+	s32 derot_freq;
+	int invval;
 
 	derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
 				| stv0299_readreg (state, 0x23));
 
 	derot_freq *= (state->config->mclk >> 16);
-		derot_freq += 500;
-		derot_freq /= 1000;
+	derot_freq += 500;
+	derot_freq /= 1000;
 
-		p->frequency += derot_freq;
+	p->frequency += derot_freq;
 
 	invval = stv0299_readreg (state, 0x0c) & 1;
 	if (state->config->invert) invval = (~invval) & 1;
-		p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
+	p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
 
 	p->u.qpsk.fec_inner = stv0299_get_fec (state);
 	p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
 
 	return 0;
-		}
+}
 
 static int stv0299_sleep(struct dvb_frontend* fe)
 {
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	stv0299_writeregI(state, 0x02, 0x80);
 	state->initialised = 0;
@@ -650,23 +669,23 @@ static int stv0299_sleep(struct dvb_fron
 }
 
 static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-	{
-        struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+        struct stv0299_state* state = fe->demodulator_priv;
 
 	fesettings->min_delay_ms = state->config->min_delay_ms;
-			if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
-				fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
-				fesettings->max_drift = 5000;
-			} else {
-				fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
-				fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
-			}
+	if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
+		fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
+		fesettings->max_drift = 5000;
+	} else {
+		fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
+		fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
+	}
 	return 0;
 }
 
 static void stv0299_release(struct dvb_frontend* fe)
-		{
-	struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+	struct stv0299_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -677,9 +696,9 @@ struct dvb_frontend* stv0299_attach(cons
 {
 	struct stv0299_state* state = NULL;
 	int id;
- 
+
 	/* allocate memory for the internal state */
-	state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -707,7 +726,7 @@ struct dvb_frontend* stv0299_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -751,6 +770,9 @@ static struct dvb_frontend_ops stv0299_o
 	.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
 };
 
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
+
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -35,14 +35,10 @@
 
 
 struct tda10021_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct tda10021_config* config;
-
 	struct dvb_frontend frontend;
 
 	u8 pwm;
@@ -65,12 +61,12 @@ static int verbose;
 
 #define FIN (XIN >> 4)
 
-int tda10021_inittab_size = 0x40;
+static int tda10021_inittab_size = 0x40;
 static u8 tda10021_inittab[0x40]=
 {
 	0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
 	0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
-	0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
+	0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,
 	0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
 	0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
 	0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
@@ -94,7 +90,6 @@ static int tda10021_writereg (struct tda
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-
 static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
 {
 	u8 b0 [] = { reg };
@@ -208,18 +203,9 @@ static int tda10021_set_symbolrate (stru
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
 static int tda10021_init (struct dvb_frontend *fe)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 	int i;
 
 	dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
@@ -252,7 +238,7 @@ static int tda10021_init (struct dvb_fro
 static int tda10021_set_parameters (struct dvb_frontend *fe,
 			    struct dvb_frontend_parameters *p)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	//table for QAM4-QAM256 ready  QAM4  QAM16 QAM32 QAM64 QAM128 QAM256
 	//CONF
@@ -292,7 +278,7 @@ static int tda10021_set_parameters (stru
 
 static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 	int sync;
 
 	*status = 0;
@@ -317,11 +303,11 @@ static int tda10021_read_status(struct d
 
 static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	u32 _ber = tda10021_readreg(state, 0x14) |
-     		  (tda10021_readreg(state, 0x15) << 8) |
-		 ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
+		(tda10021_readreg(state, 0x15) << 8) |
+		((tda10021_readreg(state, 0x16) & 0x0f) << 16);
 	*ber = 10 * _ber;
 
 	return 0;
@@ -329,7 +315,7 @@ static int tda10021_read_ber(struct dvb_
 
 static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	u8 gain = tda10021_readreg(state, 0x17);
 	*strength = (gain << 8) | gain;
@@ -339,7 +325,7 @@ static int tda10021_read_signal_strength
 
 static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	u8 quality = ~tda10021_readreg(state, 0x18);
 	*snr = (quality << 8) | quality;
@@ -349,7 +335,7 @@ static int tda10021_read_snr(struct dvb_
 
 static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	*ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
 	if (*ucblocks == 0x7f)
@@ -364,7 +350,7 @@ static int tda10021_read_ucblocks(struct
 
 static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 	int sync;
 	s8 afc = 0;
 
@@ -392,7 +378,7 @@ static int tda10021_get_frontend(struct 
 
 static int tda10021_sleep(struct dvb_frontend* fe)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 
 	tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
 	tda10021_writereg (state, 0x00, 0x80);  /* standby */
@@ -402,7 +388,7 @@ static int tda10021_sleep(struct dvb_fro
 
 static void tda10021_release(struct dvb_frontend* fe)
 {
-	struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+	struct tda10021_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -415,7 +401,7 @@ struct dvb_frontend* tda10021_attach(con
 	struct tda10021_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -434,7 +420,7 @@ struct dvb_frontend* tda10021_attach(con
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -37,7 +37,6 @@ struct tda10021_config
 };
 
 extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
-					    struct i2c_adapter* i2c,
-					    u8 pwm);
+					    struct i2c_adapter* i2c, u8 pwm);
 
 #endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -35,24 +35,21 @@
 #include "dvb_frontend.h"
 #include "tda1004x.h"
 
-#define TDA1004X_DEMOD_TDA10045 0
-#define TDA1004X_DEMOD_TDA10046 1
-
+enum tda1004x_demod {
+	TDA1004X_DEMOD_TDA10045,
+	TDA1004X_DEMOD_TDA10046,
+};
 
-struct tda1004x_state
-{
+struct tda1004x_state {
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	const struct tda1004x_config* config;
-
 	struct dvb_frontend frontend;
 
 	/* private demod data */
-	u8 initialised:1;
-
-	u8 demod_type;
+	u8 initialised;
+	enum tda1004x_demod demod_type;
+	u8 fw_version;
 };
 
 
@@ -144,7 +141,7 @@ static int tda1004x_write_byteI(struct t
 {
 	int ret;
 	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 };
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
 
 	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
 
@@ -165,8 +162,8 @@ static int tda1004x_read_byte(struct tda
 	int ret;
 	u8 b0[] = { reg };
 	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1},
-				{ .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};
+	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
 
 	dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
 
@@ -299,7 +296,7 @@ static int tda1004x_do_upload(struct tda
 			      u8 dspCodeCounterReg, u8 dspCodeInReg)
 {
 	u8 buf[65];
-	struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };
+	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
 	int tx_size;
 	int pos = 0;
 
@@ -309,12 +306,10 @@ static int tda1004x_do_upload(struct tda
 
 	buf[0] = dspCodeInReg;
 	while (pos != len) {
-
 		// work out how much to send this time
 		tx_size = len - pos;
-		if (tx_size > 0x10) {
+		if (tx_size > 0x10)
 			tx_size = 0x10;
-		}
 
 		// send the chunk
 		memcpy(buf + 1, mem + pos, tx_size);
@@ -327,6 +322,7 @@ static int tda1004x_do_upload(struct tda
 
 		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
 	}
+
 	return 0;
 }
 
@@ -340,30 +336,28 @@ static int tda1004x_check_upload_ok(stru
 
 	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
 	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
-	if (data1 != 0x67 || data2 != dspVersion) {
+	if ((data1 != 0x67) || (data2 != dspVersion))
 		return -EIO;
-	}
 
 	return 0;
 }
 
-
 static int tda10045_fwupload(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 	int ret;
 	const struct firmware *fw;
 
-
 	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0;
+	if (tda1004x_check_upload_ok(state, 0x2c) == 0)
+		return 0;
 
 	/* request the firmware, this will block until someone uploads it */
-	printk("tda1004x: waiting for firmware upload...\n");
+	printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
 	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
 	if (ret) {
 		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-	   	return ret;
+		return ret;
 	}
 
 	/* reset chip */
@@ -378,6 +372,7 @@ static int tda10045_fwupload(struct dvb_
 	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
 	if (ret)
 		return ret;
+	printk("tda1004x: firmware upload complete\n");
 
 	/* wait for DSP to initialise */
 	/* DSPREADY doesn't seem to work on the TDA10045H */
@@ -386,6 +381,25 @@ static int tda10045_fwupload(struct dvb_
 	return tda1004x_check_upload_ok(state, 0x2c);
 }
 
+static int tda10046_get_fw_version(struct tda1004x_state *state,
+				   const struct firmware *fw)
+{
+	const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 };
+	unsigned int i;
+
+	/* area guessed from firmware v20, v21 and v25 */
+	for (i = 0x660; i < 0x700; i++) {
+		if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) {
+			state->fw_version = fw->data[i + sizeof(pattern)];
+			printk(KERN_INFO "tda1004x: using firmware v%02x\n",
+					state->fw_version);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static int tda10046_fwupload(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
@@ -399,19 +413,31 @@ static int tda10046_fwupload(struct dvb_
 	msleep(100);
 
 	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0;
+	if (tda1004x_check_upload_ok(state, state->fw_version) == 0)
+		return 0;
 
 	/* request the firmware, this will block until someone uploads it */
-	printk("tda1004x: waiting for firmware upload...\n");
+	printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
 	ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
 	if (ret) {
 		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-   	   	return ret;
+		return ret;
+	}
+
+	if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */
+		printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size);
+		return -EINVAL;
+	}
+
+	ret = tda10046_get_fw_version(state, fw);
+	if (ret < 0) {
+		printk("tda1004x: unable to find firmware version\n");
+		return ret;
 	}
 
 	/* set parameters */
 	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0);
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c);
 	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
 	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
 	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
@@ -420,10 +446,11 @@ static int tda10046_fwupload(struct dvb_
 	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
 	if (ret)
 		return ret;
+	printk("tda1004x: firmware upload complete\n");
 
 	/* wait for DSP to initialise */
 	timeout = jiffies + HZ;
-	while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+	while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
 		if (time_after(jiffies, timeout)) {
 			printk("tda1004x: DSP failed to initialised.\n");
 			return -EIO;
@@ -431,7 +458,7 @@ static int tda10046_fwupload(struct dvb_
 		msleep(1);
 	}
 
-	return tda1004x_check_upload_ok(state, 0x20);
+	return tda1004x_check_upload_ok(state, state->fw_version);
 }
 
 static int tda1004x_encode_fec(int fec)
@@ -474,29 +501,12 @@ static int tda1004x_decode_fec(int tdafe
 	return -1;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 
 	return tda1004x_write_byteI(state, reg, data);
-		}
+}
 
 static int tda10045_init(struct dvb_frontend* fe)
 {
@@ -504,12 +514,13 @@ static int tda10045_init(struct dvb_fron
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if (state->initialised) return 0;
+	if (state->initialised)
+		return 0;
 
 	if (tda10045_fwupload(fe)) {
 		printk("tda1004x: firmware upload failed\n");
 		return -EIO;
-		}
+	}
 
 	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
 
@@ -537,19 +548,20 @@ static int tda10045_init(struct dvb_fron
 
 	state->initialised = 1;
 	return 0;
-		}
+}
 
 static int tda10046_init(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 	dprintk("%s\n", __FUNCTION__);
 
-	if (state->initialised) return 0;
+	if (state->initialised)
+		return 0;
 
 	if (tda10046_fwupload(fe)) {
 		printk("tda1004x: firmware upload failed\n");
-			return -EIO;
-		}
+		return -EIO;
+	}
 
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
 
@@ -566,7 +578,7 @@ static int tda10046_init(struct dvb_fron
 	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
 	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
 	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0
 	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
 	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
 	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
@@ -623,9 +635,9 @@ static int tda1004x_set_fe(struct dvb_fr
 	// Hardcoded to use auto as much as possible on the TDA10045 as it
 	// is very unreliable if AUTO mode is _not_ used.
 	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
-	fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
-	fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
-	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+		fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
 	}
 
 	// Set standard params.. or put them to auto
@@ -642,12 +654,14 @@ static int tda1004x_set_fe(struct dvb_fr
 
 		// set HP FEC
 		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
-		if (tmp < 0) return tmp;
+		if (tmp < 0)
+			return tmp;
 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
 
 		// set LP FEC
 		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
-		if (tmp < 0) return tmp;
+		if (tmp < 0)
+			return tmp;
 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
 
 		// set constellation
@@ -692,7 +706,7 @@ static int tda1004x_set_fe(struct dvb_fr
 	}
 
 	// set bandwidth
-	switch(state->demod_type) {
+	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
 		tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
 		break;
@@ -704,7 +718,8 @@ static int tda1004x_set_fe(struct dvb_fr
 
 	// set inversion
 	inversion = fe_params->inversion;
-	if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON;
+	if (state->config->invert)
+		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
 	switch (inversion) {
 	case INVERSION_OFF:
 		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
@@ -771,19 +786,19 @@ static int tda1004x_set_fe(struct dvb_fr
 	}
 
 	// start the lock
-	switch(state->demod_type) {
+	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
-		msleep(10);
 		break;
 
 	case TDA1004X_DEMOD_TDA10046:
 		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
-		msleep(10);
 		break;
 	}
 
+	msleep(10);
+
 	return 0;
 }
 
@@ -794,13 +809,13 @@ static int tda1004x_get_fe(struct dvb_fr
 
 	// inversion status
 	fe_params->inversion = INVERSION_OFF;
-	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) {
+	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
 		fe_params->inversion = INVERSION_ON;
-	}
-	if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
+	if (state->config->invert)
+		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
 
 	// bandwidth
-	switch(state->demod_type) {
+	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
 		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
 		case 0x14:
@@ -851,9 +866,8 @@ static int tda1004x_get_fe(struct dvb_fr
 
 	// transmission mode
 	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
-	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) {
+	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
 		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
-	}
 
 	// guard interval
 	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
@@ -901,30 +915,33 @@ static int tda1004x_read_status(struct d
 
 	// read status
 	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
-	if (status == -1) {
+	if (status == -1)
 		return -EIO;
-	}
 
 	// decode
 	*fe_status = 0;
-	if (status & 4) *fe_status |= FE_HAS_SIGNAL;
-	if (status & 2) *fe_status |= FE_HAS_CARRIER;
-	if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	if (status & 4)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (status & 2)
+		*fe_status |= FE_HAS_CARRIER;
+	if (status & 8)
+		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 
 	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
 	// is getting anything valid
 	if (!(*fe_status & FE_HAS_VITERBI)) {
 		// read the CBER
 		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-		if (cber == -1) return -EIO;
+		if (cber == -1)
+			return -EIO;
 		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-		if (status == -1) return -EIO;
+		if (status == -1)
+			return -EIO;
 		cber |= (status << 8);
 		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
-		if (cber != 65535) {
+		if (cber != 65535)
 			*fe_status |= FE_HAS_VITERBI;
-		}
 	}
 
 	// if we DO have some valid VITERBI output, but don't already have SYNC
@@ -932,20 +949,22 @@ static int tda1004x_read_status(struct d
 	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
 		// read the VBER
 		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
-		if (vber == -1) return -EIO;
+		if (vber == -1)
+			return -EIO;
 		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
-		if (status == -1) return -EIO;
+		if (status == -1)
+			return -EIO;
 		vber |= (status << 8);
 		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
-		if (status == -1) return -EIO;
+		if (status == -1)
+			return -EIO;
 		vber |= ((status << 16) & 0x0f);
 		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
 
 		// if RS has passed some valid TS packets, then we must be
 		// getting some SYNC bytes
-		if (vber < 16632) {
+		if (vber < 16632)
 			*fe_status |= FE_HAS_SYNC;
-		}
 	}
 
 	// success
@@ -962,7 +981,7 @@ static int tda1004x_read_signal_strength
 	dprintk("%s\n", __FUNCTION__);
 
 	// determine the register to use
-	switch(state->demod_type) {
+	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
 		reg = TDA10045H_S_AGC;
 		break;
@@ -993,9 +1012,8 @@ static int tda1004x_read_snr(struct dvb_
 	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
 	if (tmp < 0)
 		return -EIO;
-	if (tmp) {
+	if (tmp)
 		tmp = 255 - tmp;
-	}
 
 	*snr = ((tmp << 8) | tmp);
 	dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
@@ -1030,11 +1048,11 @@ static int tda1004x_read_ucblocks(struct
 			break;
 	}
 
-	if (tmp != 0x7f) {
+	if (tmp != 0x7f)
 		*ucblocks = tmp;
-	} else {
+	else
 		*ucblocks = 0xffffffff;
-	}
+
 	dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
 	return 0;
 }
@@ -1048,10 +1066,12 @@ static int tda1004x_read_ber(struct dvb_
 
 	// read it in
 	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-	if (tmp < 0) return -EIO;
+	if (tmp < 0)
+		return -EIO;
 	*ber = tmp << 1;
 	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-	if (tmp < 0) return -EIO;
+	if (tmp < 0)
+		return -EIO;
 	*ber |= (tmp << 9);
 	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
@@ -1063,98 +1083,35 @@ static int tda1004x_sleep(struct dvb_fro
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 
-	switch(state->demod_type) {
+	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
 		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
-			break;
+		break;
 
 	case TDA1004X_DEMOD_TDA10046:
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
-			break;
-		}
+		break;
+	}
 	state->initialised = 0;
 
-			return 0;
-		}
+	return 0;
+}
 
 static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-	{
-		fesettings->min_delay_ms = 800;
-		fesettings->step_size = 166667;
-		fesettings->max_drift = 166667*2;
-		return 0;
-	}
+{
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 166667;
+	fesettings->max_drift = 166667*2;
+	return 0;
+}
 
 static void tda1004x_release(struct dvb_frontend* fe)
 {
-	struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
 	kfree(state);
-	}
-
-static struct dvb_frontend_ops tda10045_ops;
-
-struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct tda1004x_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
-	state->initialised = 0;
-	state->demod_type = TDA1004X_DEMOD_TDA10045;
-
-	/* check if the demod is there */
-	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error;
-
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	if (state) kfree(state);
-	return NULL;
-	}
-
-static struct dvb_frontend_ops tda10046_ops;
-
-struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct tda1004x_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
-	state->initialised = 0;
-	state->demod_type = TDA1004X_DEMOD_TDA10046;
-
-	/* check if the demod is there */
-	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error;
-
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	if (state) kfree(state);
-	return NULL;
-		}
+}
 
 static struct dvb_frontend_ops tda10045_ops = {
-
 	.info = {
 		.name = "Philips TDA10045H DVB-T",
 		.type = FE_OFDM,
@@ -1184,8 +1141,36 @@ static struct dvb_frontend_ops tda10045_
 	.read_ucblocks = tda1004x_read_ucblocks,
 };
 
-static struct dvb_frontend_ops tda10046_ops = {
+struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda1004x_state *state;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
+	state->initialised = 0;
+	state->demod_type = TDA1004X_DEMOD_TDA10045;
+
+	/* check if the demod is there */
+	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) {
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
 
+static struct dvb_frontend_ops tda10046_ops = {
 	.info = {
 		.name = "Philips TDA10046H DVB-T",
 		.type = FE_OFDM,
@@ -1215,6 +1200,36 @@ static struct dvb_frontend_ops tda10046_
 	.read_ucblocks = tda1004x_read_ucblocks,
 };
 
+struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda1004x_state *state;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
+	state->initialised = 0;
+	state->demod_type = TDA1004X_DEMOD_TDA10046;
+	state->fw_version = 0x20;	/* dummy default value */
+
+	/* check if the demod is there */
+	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -32,10 +32,13 @@ struct tda1004x_config
 	u8 demod_address;
 
 	/* does the "inversion" need inverted? */
-	u8 invert:1;
+	u8 invert;
 
 	/* Does the OCLK signal need inverted? */
-	u8 invert_oclk:1;
+	u8 invert_oclk;
+
+	/* value of N_I2C of the CONF_PLL3 register */
+	u8 n_i2c;
 
 	/* PLL maintenance */
 	int (*pll_init)(struct dvb_frontend* fe);
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -35,14 +35,10 @@
 
 
 struct tda8083_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct tda8083_config* config;
-
 	struct dvb_frontend frontend;
 };
 
@@ -78,7 +74,6 @@ static int tda8083_writereg (struct tda8
         return (ret != 1) ? -1 : 0;
 }
 
-
 static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len)
 {
 	int ret;
@@ -94,7 +89,6 @@ static int tda8083_readregs (struct tda8
         return ret == 2 ? 0 : -1;
 }
 
-
 static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg)
 {
 	u8 val;
@@ -104,8 +98,6 @@ static inline u8 tda8083_readreg (struct
 	return val;
 }
 
-
-
 static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion)
 {
 	/*  XXX FIXME: implement other modes than FEC_AUTO */
@@ -115,7 +107,6 @@ static int tda8083_set_inversion (struct
 	return -EINVAL;
 }
 
-
 static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec)
 {
 	if (fec == FEC_AUTO)
@@ -127,7 +118,6 @@ static int tda8083_set_fec (struct tda80
 	return -EINVAL;
 }
 
-
 static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state)
 {
 	u8 index;
@@ -139,7 +129,6 @@ static fe_code_rate_t tda8083_get_fec (s
 	return fec_tab [index];
 }
 
-
 static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate)
 {
         u32 ratio;
@@ -179,7 +168,6 @@ static int tda8083_set_symbolrate (struc
 	return 1;
 }
 
-
 static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout)
 {
 	unsigned long start = jiffies;
@@ -205,7 +193,6 @@ static int tda8083_set_tone (struct tda8
 	};
 }
 
-
 static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
 {
 	switch (voltage) {
@@ -236,31 +223,10 @@ static int tda8083_send_diseqc_burst (st
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 static int tda8083_send_diseqc_msg (struct dvb_frontend* fe,
 				    struct dvb_diseqc_master_cmd *m)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 	int i;
 
 	tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
@@ -277,7 +243,7 @@ static int tda8083_send_diseqc_msg (stru
 
 static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	u8 signal = ~tda8083_readreg (state, 0x01);
 	u8 sync = tda8083_readreg (state, 0x02);
@@ -304,7 +270,7 @@ static int tda8083_read_status(struct dv
 
 static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	u8 signal = ~tda8083_readreg (state, 0x01);
 	*strength = (signal << 8) | signal;
@@ -314,7 +280,7 @@ static int tda8083_read_signal_strength(
 
 static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	u8 _snr = tda8083_readreg (state, 0x08);
 	*snr = (_snr << 8) | _snr;
@@ -324,7 +290,7 @@ static int tda8083_read_snr(struct dvb_f
 
 static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	state->config->pll_set(fe, p);
 	tda8083_set_inversion (state, p->inversion);
@@ -339,7 +305,7 @@ static int tda8083_set_frontend(struct d
 
 static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	/*  FIXME: get symbolrate & frequency offset...*/
 	/*p->frequency = ???;*/
@@ -353,7 +319,7 @@ static int tda8083_get_frontend(struct d
 
 static int tda8083_sleep(struct dvb_frontend* fe)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	tda8083_writereg (state, 0x00, 0x02);
 	return 0;
@@ -361,7 +327,7 @@ static int tda8083_sleep(struct dvb_fron
 
 static int tda8083_init(struct dvb_frontend* fe)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 	int i;
 
 	for (i=0; i<44; i++)
@@ -377,7 +343,7 @@ static int tda8083_init(struct dvb_front
 
 static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	tda8083_send_diseqc_burst (state, burst);
 	tda8083_writereg (state, 0x00, 0x3c);
@@ -388,7 +354,7 @@ static int tda8083_diseqc_send_burst(str
 
 static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	tda8083_set_tone (state, tone);
 	tda8083_writereg (state, 0x00, 0x3c);
@@ -399,7 +365,7 @@ static int tda8083_diseqc_set_tone(struc
 
 static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 
 	tda8083_set_voltage (state, voltage);
 	tda8083_writereg (state, 0x00, 0x3c);
@@ -410,7 +376,7 @@ static int tda8083_diseqc_set_voltage(st
 
 static void tda8083_release(struct dvb_frontend* fe)
 {
-	struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+	struct tda8083_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -422,7 +388,7 @@ struct dvb_frontend* tda8083_attach(cons
 	struct tda8083_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -439,7 +405,7 @@ struct dvb_frontend* tda8083_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -475,9 +441,9 @@ static struct dvb_frontend_ops tda8083_o
 	.read_snr = tda8083_read_snr,
 
 	.diseqc_send_master_cmd = tda8083_send_diseqc_msg,
-     	.diseqc_send_burst = tda8083_diseqc_send_burst,
-     	.set_tone = tda8083_diseqc_set_tone,
-     	.set_voltage = tda8083_diseqc_set_voltage,
+	.diseqc_send_burst = tda8083_diseqc_send_burst,
+	.set_tone = tda8083_diseqc_set_tone,
+	.set_voltage = tda8083_diseqc_set_voltage,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c
--- a/drivers/media/dvb/frontends/tda80xx.c
+++ b/drivers/media/dvb/frontends/tda80xx.c
@@ -27,7 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -204,8 +204,8 @@ static int tda80xx_set_parameters(struct
 	 * r = k * clk / symbol_rate
 	 *
 	 * k:	2^21 for caa 0..3,
-	 * 	2^20 for caa 4..5,
-	 * 	2^19 for caa 6..7
+	 *	2^20 for caa 4..5,
+	 *	2^19 for caa 6..7
 	 */
 	if (symbol_rate <= (clk * 3) / 32)
 		k = (1 << 19);
@@ -400,7 +400,7 @@ static void tda80xx_wait_diseqc_fifo(str
 
 static int tda8044_init(struct dvb_frontend* fe)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 	int ret;
 
 	/*
@@ -422,7 +422,7 @@ static int tda8044_init(struct dvb_front
 	tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post));
 
 	if (state->config->pll_init) {
-	   	tda80xx_writereg(state, 0x1c, 0x80);
+		tda80xx_writereg(state, 0x1c, 0x80);
 		state->config->pll_init(fe);
 		tda80xx_writereg(state, 0x1c, 0x00);
 	}
@@ -432,12 +432,12 @@ static int tda8044_init(struct dvb_front
 
 static int tda8083_init(struct dvb_frontend* fe)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab));
 
 	if (state->config->pll_init) {
-	   	tda80xx_writereg(state, 0x1c, 0x80);
+		tda80xx_writereg(state, 0x1c, 0x80);
 		state->config->pll_init(fe);
 		tda80xx_writereg(state, 0x1c, 0x00);
 	}
@@ -445,24 +445,9 @@ static int tda8083_init(struct dvb_front
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -478,7 +463,7 @@ static int tda80xx_set_voltage(struct dv
 
 static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	switch (tone) {
 	case SEC_TONE_OFF:
@@ -492,7 +477,7 @@ static int tda80xx_set_tone(struct dvb_f
 
 static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
 {
-   	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	if (cmd->msg_len > 6)
 		return -EINVAL;
@@ -507,7 +492,7 @@ static int tda80xx_send_diseqc_msg(struc
 
 static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	switch (cmd) {
 	case SEC_MINI_A:
@@ -527,7 +512,7 @@ static int tda80xx_send_diseqc_burst(str
 
 static int tda80xx_sleep(struct dvb_frontend* fe)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	tda80xx_writereg(state, 0x00, 0x02);	/* enter standby */
 
@@ -536,7 +521,7 @@ static int tda80xx_sleep(struct dvb_fron
 
 static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-   	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	tda80xx_writereg(state, 0x1c, 0x80);
 	state->config->pll_set(fe, p);
@@ -552,7 +537,7 @@ static int tda80xx_set_frontend(struct d
 
 static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	if (!state->config->irq)
 		tda80xx_read_status_int(state);
@@ -565,7 +550,7 @@ static int tda80xx_get_frontend(struct d
 
 static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	if (!state->config->irq)
 		tda80xx_read_status_int(state);
@@ -576,7 +561,7 @@ static int tda80xx_read_status(struct dv
 
 static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 	int ret;
 	u8 buf[3];
 
@@ -590,7 +575,7 @@ static int tda80xx_read_ber(struct dvb_f
 
 static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	u8 gain = ~tda80xx_readreg(state, 0x01);
 	*strength = (gain << 8) | gain;
@@ -600,7 +585,7 @@ static int tda80xx_read_signal_strength(
 
 static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	u8 quality = tda80xx_readreg(state, 0x08);
 	*snr = (quality << 8) | quality;
@@ -610,7 +595,7 @@ static int tda80xx_read_snr(struct dvb_f
 
 static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	*ucblocks = tda80xx_readreg(state, 0x0f);
 	if (*ucblocks == 0xff)
@@ -621,7 +606,7 @@ static int tda80xx_read_ucblocks(struct 
 
 static int tda80xx_init(struct dvb_frontend* fe)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	switch(state->id) {
 	case ID_TDA8044:
@@ -635,7 +620,7 @@ static int tda80xx_init(struct dvb_front
 
 static void tda80xx_release(struct dvb_frontend* fe)
 {
-	struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+	struct tda80xx_state* state = fe->demodulator_priv;
 
 	if (state->config->irq)
 		free_irq(state->config->irq, &state->worklet);
@@ -652,7 +637,7 @@ struct dvb_frontend* tda80xx_attach(cons
 	int ret;
 
 	/* allocate memory for the internal state */
-	state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -698,7 +683,7 @@ struct dvb_frontend* tda80xx_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -735,9 +720,9 @@ static struct dvb_frontend_ops tda80xx_o
 	.read_ucblocks = tda80xx_read_ucblocks,
 
 	.diseqc_send_master_cmd = tda80xx_send_diseqc_msg,
-     	.diseqc_send_burst = tda80xx_send_diseqc_burst,
-     	.set_tone = tda80xx_set_tone,
-     	.set_voltage = tda80xx_set_voltage,
+	.diseqc_send_burst = tda80xx_send_diseqc_burst,
+	.set_tone = tda80xx_set_tone,
+	.set_voltage = tda80xx_set_voltage,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -1,4 +1,4 @@
-/* 
+/*
     VES1820  - Single Chip Cable Channel Receiver driver module
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
@@ -16,7 +16,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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/    
+*/
 
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -34,14 +34,10 @@
 
 
 struct ves1820_state {
-
-	struct i2c_adapter *i2c;
-
+	struct i2c_adapter* i2c;
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct ves1820_config* config;
-
 	struct dvb_frontend frontend;
 
 	/* private demodulator data */
@@ -64,9 +60,9 @@ static u8 ves1820_inittab[] = {
 
 static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
 {
-        u8 buf[] = { 0x00, reg, data };
+	u8 buf[] = { 0x00, reg, data };
 	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
-        int ret;
+	int ret;
 
 	ret = i2c_transfer(state->i2c, &msg, 1);
 
@@ -74,14 +70,13 @@ static int ves1820_writereg(struct ves18
 		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
 			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
-	msleep(10);
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
 static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
 {
-	u8 b0 [] = { 0x00, reg };
-	u8 b1 [] = { 0 };
+	u8 b0[] = { 0x00, reg };
+	u8 b1[] = { 0 };
 	struct i2c_msg msg[] = {
 		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
 		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
@@ -97,23 +92,20 @@ static u8 ves1820_readreg(struct ves1820
 	return b1[0];
 }
 
-
 static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
 {
 	reg0 |= state->reg0 & 0x62;
-	
+
 	if (INVERSION_ON == inversion) {
 		if (!state->config->invert) reg0 |= 0x20;
 		else reg0 &= ~0x20;
-	
 	} else if (INVERSION_OFF == inversion) {
-
-     		if (!state->config->invert) reg0 &= ~0x20;
+		if (!state->config->invert) reg0 &= ~0x20;
 		else reg0 |= 0x20;
 	}
 
-			ves1820_writereg(state, 0x00, reg0 & 0xfe);
-			ves1820_writereg(state, 0x00, reg0 | 0x01);
+	ves1820_writereg(state, 0x00, reg0 & 0xfe);
+	ves1820_writereg(state, 0x00, reg0 | 0x01);
 
 	state->reg0 = reg0;
 
@@ -122,10 +114,10 @@ static int ves1820_setup_reg0(struct ves
 
 static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
 {
-        s32 BDR; 
-        s32 BDRI;
-        s16 SFIL=0;
-        u16 NDEC = 0;
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL = 0;
+	u16 NDEC = 0;
 	u32 ratio;
 	u32 fin;
 	u32 tmp;
@@ -136,7 +128,7 @@ static int ves1820_set_symbolrate(struct
 		symbolrate = state->config->xin / 2;
 
 	if (symbolrate < 500000)
-                symbolrate = 500000;
+		symbolrate = 500000;
 
 	if (symbolrate < state->config->xin / 16)
 		NDEC = 1;
@@ -168,24 +160,24 @@ static int ves1820_set_symbolrate(struct
 	fptmp = fpxin; do_div(fptmp, 984);
 	if (symbolrate < fptmp);
 		SFIL = 1;
-        
+
 	fin = state->config->xin >> 4;
-        symbolrate <<= NDEC;
+	symbolrate <<= NDEC;
 	ratio = (symbolrate << 4) / fin;
 	tmp = ((symbolrate << 4) % fin) << 8;
 	ratio = (ratio << 8) + tmp / fin;
 	tmp = (tmp % fin) << 8;
 	ratio = (ratio << 8) + (tmp + fin / 2) / fin;
-        
-        BDR = ratio;
+
+	BDR = ratio;
 	BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
-        
-        if (BDRI > 0xFF) 
-                BDRI = 0xFF;
-        
-        SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
-        
-        NDEC = (NDEC << 6) | ves1820_inittab[0x03];
+
+	if (BDRI > 0xFF)
+		BDRI = 0xFF;
+
+	SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
+
+	NDEC = (NDEC << 6) | ves1820_inittab[0x03];
 
 	ves1820_writereg(state, 0x03, NDEC);
 	ves1820_writereg(state, 0x0a, BDR & 0xff);
@@ -195,24 +187,12 @@ static int ves1820_set_symbolrate(struct
 	ves1820_writereg(state, 0x0d, BDRI);
 	ves1820_writereg(state, 0x0e, SFIL);
 
-        return 0;
+	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
 static int ves1820_init(struct dvb_frontend* fe)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+	struct ves1820_state* state = fe->demodulator_priv;
 	int i;
 	int val;
 
@@ -233,12 +213,12 @@ static int ves1820_init(struct dvb_front
 
 static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
-	static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
-	static const u8 reg0x01 [] = {  140,  140,  106,  100,   92 };
-	static const u8 reg0x05 [] = {  135,  100,   70,   54,   38 };
-	static const u8 reg0x08 [] = {  162,  116,   67,   52,   35 };
-	static const u8 reg0x09 [] = {  145,  150,  106,  126,  107 };
+	struct ves1820_state* state = fe->demodulator_priv;
+	static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
+	static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
+	static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
+	static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
+	static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
 	int real_qam = p->u.qam.modulation - QAM_16;
 
 	if (real_qam < 0 || real_qam > 4)
@@ -260,91 +240,90 @@ static int ves1820_set_parameters(struct
 
 static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
-		int sync;
+	struct ves1820_state* state = fe->demodulator_priv;
+	int sync;
 
-		*status = 0;
+	*status = 0;
+	sync = ves1820_readreg(state, 0x11);
 
-			sync = ves1820_readreg(state, 0x11);
+	if (sync & 1)
+		*status |= FE_HAS_SIGNAL;
 
-		if (sync & 1)
-			*status |= FE_HAS_SIGNAL;
+	if (sync & 2)
+		*status |= FE_HAS_CARRIER;
 
-		if (sync & 2)
-			*status |= FE_HAS_CARRIER;
+	if (sync & 2)	/* XXX FIXME! */
+		*status |= FE_HAS_VITERBI;
 
-		if (sync & 2)           /* XXX FIXME! */
-			*status |= FE_HAS_VITERBI;
-		
-		if (sync & 4)
-			*status |= FE_HAS_SYNC;
+	if (sync & 4)
+		*status |= FE_HAS_SYNC;
 
-		if (sync & 8)
-			*status |= FE_HAS_LOCK;
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
 
 	return 0;
-	}
+}
 
 static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
-	{
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+{
+	struct ves1820_state* state = fe->demodulator_priv;
 
 	u32 _ber = ves1820_readreg(state, 0x14) |
-					(ves1820_readreg(state, 0x15) << 8) |
-					((ves1820_readreg(state, 0x16) & 0x0f) << 16);
+			(ves1820_readreg(state, 0x15) << 8) |
+			((ves1820_readreg(state, 0x16) & 0x0f) << 16);
 	*ber = 10 * _ber;
 
 	return 0;
-	}
+}
 
 static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-	{
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+{
+	struct ves1820_state* state = fe->demodulator_priv;
 
-			u8 gain = ves1820_readreg(state, 0x17);
+	u8 gain = ves1820_readreg(state, 0x17);
 	*strength = (gain << 8) | gain;
 
 	return 0;
-	}
+}
 
 static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
-	{
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+{
+	struct ves1820_state* state = fe->demodulator_priv;
 
-			u8 quality = ~ves1820_readreg(state, 0x18);
+	u8 quality = ~ves1820_readreg(state, 0x18);
 	*snr = (quality << 8) | quality;
 
 	return 0;
-	}
+}
 
 static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+	struct ves1820_state* state = fe->demodulator_priv;
 
 	*ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
 	if (*ucblocks == 0x7f)
 		*ucblocks = 0xffffffff;
 
-		/* reset uncorrected block counter */
-		ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
-		ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
+	/* reset uncorrected block counter */
+	ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+	ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
 
 	return 0;
 }
 
 static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
-	{
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
-		int sync;
-		s8 afc = 0;
-                
-			sync = ves1820_readreg(state, 0x11);
-			afc = ves1820_readreg(state, 0x19);
-		if (verbose) {
-			/* AFC only valid when carrier has been recovered */
-				printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
-					"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
-		}
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+	int sync;
+	s8 afc = 0;
+
+	sync = ves1820_readreg(state, 0x11);
+	afc = ves1820_readreg(state, 0x19);
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+			"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
+	}
 
 	if (!state->config->invert) {
 		p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
@@ -352,20 +331,20 @@ static int ves1820_get_frontend(struct d
 		p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
 	}
 
-			p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+	p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
-		p->u.qam.fec_inner = FEC_NONE;
+	p->u.qam.fec_inner = FEC_NONE;
 
-		p->frequency = ((p->frequency + 31250) / 62500) * 62500;
-		if (sync & 2)
-			p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+	if (sync & 2)
+		p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
 
-        return 0;
-} 
+	return 0;
+}
 
 static int ves1820_sleep(struct dvb_frontend* fe)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+	struct ves1820_state* state = fe->demodulator_priv;
 
 	ves1820_writereg(state, 0x1b, 0x02);	/* pdown ADC */
 	ves1820_writereg(state, 0x00, 0x80);	/* standby */
@@ -384,7 +363,7 @@ static int ves1820_get_tune_settings(str
 
 static void ves1820_release(struct dvb_frontend* fe)
 {
-	struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+	struct ves1820_state* state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -397,7 +376,7 @@ struct dvb_frontend* ves1820_attach(cons
 	struct ves1820_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
 
@@ -424,9 +403,9 @@ struct dvb_frontend* ves1820_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
-	}
+}
 
 static struct dvb_frontend_ops ves1820_ops = {
 
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -46,7 +46,6 @@ struct ves1820_config
 };
 
 extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
-					   struct i2c_adapter* i2c,
-					   u8 pwm);
+					   struct i2c_adapter* i2c, u8 pwm);
 
 #endif // VES1820_H
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -1,4 +1,4 @@
-/* 
+/*
     Driver for VES1893 and VES1993 QPSK Demodulators
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
@@ -21,7 +21,7 @@
     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/module.h>
@@ -35,14 +35,10 @@
 
 
 struct ves1x93_state {
-
 	struct i2c_adapter* i2c;
-
 	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct ves1x93_config* config;
-
 	struct dvb_frontend frontend;
 
 	/* previous uncorrected block counter */
@@ -69,7 +65,6 @@ static u8 init_1893_tab [] = {
 	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
 };
 
-
 static u8 init_1993_tab [] = {
 	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
 	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
@@ -83,13 +78,12 @@ static u8 init_1993_tab [] = {
 
 static u8 init_1893_wtab[] =
 {
-        1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
-        0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
-        1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
-        1,1,1,0,1,1
+	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
+	0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
+	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
+	1,1,1,0,1,1
 };
 
-
 static u8 init_1993_wtab[] =
 {
 	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
@@ -100,7 +94,7 @@ static u8 init_1993_wtab[] =
 
 static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
 {
-        u8 buf [] = { 0x00, reg, data };
+	u8 buf [] = { 0x00, reg, data };
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
 	int err;
 
@@ -109,10 +103,9 @@ static int ves1x93_writereg (struct ves1
 		return -EREMOTEIO;
 	}
 
-        return 0;
+	return 0;
 }
 
-
 static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
 {
 	int ret;
@@ -163,7 +156,6 @@ static int ves1x93_set_inversion (struct
 	return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
 }
 
-
 static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
 {
 	if (fec == FEC_AUTO)
@@ -174,18 +166,16 @@ static int ves1x93_set_fec (struct ves1x
 		return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
 }
 
-
 static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
 {
 	return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
 }
 
-
 static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
 {
 	u32 BDR;
-        u32 ratio;
-	u8  ADCONF, FCONF, FNR;
+	u32 ratio;
+	u8  ADCONF, FCONF, FNR, AGCR;
 	u32 BDRI;
 	u32 tmp;
 	u32 FIN;
@@ -213,15 +203,15 @@ static int ves1x93_set_symbolrate (struc
 
 	FNR = 0xff;
 
-	if (ratio < MUL/3)           FNR = 0;
+	if (ratio < MUL/3)	     FNR = 0;
 	if (ratio < (MUL*11)/50)     FNR = 1;
-	if (ratio < MUL/6)           FNR = 2;
-	if (ratio < MUL/9)           FNR = 3;
-	if (ratio < MUL/12)          FNR = 4;
+	if (ratio < MUL/6)	     FNR = 2;
+	if (ratio < MUL/9)	     FNR = 3;
+	if (ratio < MUL/12)	     FNR = 4;
 	if (ratio < (MUL*11)/200)    FNR = 5;
-	if (ratio < MUL/24)          FNR = 6;
+	if (ratio < MUL/24)	     FNR = 6;
 	if (ratio < (MUL*27)/1000)   FNR = 7;
-	if (ratio < MUL/48)          FNR = 8;
+	if (ratio < MUL/48)	     FNR = 8;
 	if (ratio < (MUL*137)/10000) FNR = 9;
 
 	if (FNR == 0xff) {
@@ -231,16 +221,16 @@ static int ves1x93_set_symbolrate (struc
 	} else {
 		ADCONF = 0x81;
 		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
-		/*FCONF  = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
+		/*FCONF	 = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
 	}
 
 	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
 	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
 
-        dprintk("FNR= %d\n", FNR);
-        dprintk("ratio= %08x\n", (unsigned int) ratio);
-        dprintk("BDR= %08x\n", (unsigned int) BDR);
-        dprintk("BDRI= %02x\n", (unsigned int) BDRI);
+	dprintk("FNR= %d\n", FNR);
+	dprintk("ratio= %08x\n", (unsigned int) ratio);
+	dprintk("BDR= %08x\n", (unsigned int) BDR);
+	dprintk("BDRI= %02x\n", (unsigned int) BDRI);
 
 	if (BDRI > 0xff)
 		BDRI = 0xff;
@@ -253,10 +243,16 @@ static int ves1x93_set_symbolrate (struc
 	ves1x93_writereg (state, 0x20, ADCONF);
 	ves1x93_writereg (state, 0x21, FCONF);
 
-	if (srate < 6000000) 
-		ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] | 0x80);
+	AGCR = state->init_1x93_tab[0x05];
+	if (state->config->invert_pwm)
+		AGCR |= 0x20;
+
+	if (srate < 6000000)
+		AGCR |= 0x80;
 	else
-		ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] & 0x7f);
+		AGCR &= ~0x80;
+
+	ves1x93_writereg (state, 0x05, AGCR);
 
 	/* ves1993 hates this, will lose lock */
 	if (state->demod_type != DEMOD_VES1993)
@@ -265,23 +261,9 @@ static int ves1x93_set_symbolrate (struc
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 static int ves1x93_init (struct dvb_frontend* fe)
 {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+	struct ves1x93_state* state = fe->demodulator_priv;
 	int i;
 	int val;
 
@@ -307,7 +289,7 @@ static int ves1x93_init (struct dvb_fron
 
 static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -323,84 +305,83 @@ static int ves1x93_set_voltage (struct d
 
 static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	u8 sync = ves1x93_readreg (state, 0x0e);
 
-		/*
-		 * The ves1893 sometimes returns sync values that make no sense,
-		 * because, e.g., the SIGNAL bit is 0, while some of the higher
-		 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
-		 * Tests showed that the the VITERBI and SYNC bits are returned
-		 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
-		 * If such a case occurs, we read the value again, until we get a
-		 * valid value.
-		 */
-		int maxtry = 10; /* just for safety - let's not get stuck here */
-		while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
-			msleep(10);
+	/*
+	 * The ves1893 sometimes returns sync values that make no sense,
+	 * because, e.g., the SIGNAL bit is 0, while some of the higher
+	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
+	 * Tests showed that the the VITERBI and SYNC bits are returned
+	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
+	 * If such a case occurs, we read the value again, until we get a
+	 * valid value.
+	 */
+	int maxtry = 10; /* just for safety - let's not get stuck here */
+	while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
+		msleep(10);
 		sync = ves1x93_readreg (state, 0x0e);
-		}
+	}
 
-		*status = 0;
+	*status = 0;
 
-		if (sync & 1)
-			*status |= FE_HAS_SIGNAL;
+	if (sync & 1)
+		*status |= FE_HAS_SIGNAL;
 
-		if (sync & 2)
-			*status |= FE_HAS_CARRIER;
+	if (sync & 2)
+		*status |= FE_HAS_CARRIER;
 
-		if (sync & 4)
-			*status |= FE_HAS_VITERBI;
+	if (sync & 4)
+		*status |= FE_HAS_VITERBI;
 
-		if (sync & 8)
-			*status |= FE_HAS_SYNC;
+	if (sync & 8)
+		*status |= FE_HAS_SYNC;
 
-		if ((sync & 0x1f) == 0x1f)
-			*status |= FE_HAS_LOCK;
+	if ((sync & 0x1f) == 0x1f)
+		*status |= FE_HAS_LOCK;
 
 	return 0;
-	}
-
+}
 
 static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
-	{
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	*ber = ves1x93_readreg (state, 0x15);
 	*ber |= (ves1x93_readreg (state, 0x16) << 8);
 	*ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
-		*ber *= 10;
+	*ber *= 10;
 
 	return 0;
-	}
+}
 
 static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-	{
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	u8 signal = ~ves1x93_readreg (state, 0x0b);
 	*strength = (signal << 8) | signal;
 
 	return 0;
-	}
+}
 
 static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
-	{
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	u8 _snr = ~ves1x93_readreg (state, 0x1c);
 	*snr = (_snr << 8) | _snr;
 
 	return 0;
-	}
+}
 
 static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-	{
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	*ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
-		
+
 	if (*ucblocks == 0x7f)
 		*ucblocks = 0xffffffff;   /* counter overflow... */
 
@@ -408,11 +389,11 @@ static int ves1x93_read_ucblocks(struct 
 	ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
 
 	return 0;
-	}
+}
 
 static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
-        {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	ves1x93_writereg(state, 0x00, 0x11);
 	state->config->pll_set(fe, p);
@@ -420,28 +401,28 @@ static int ves1x93_set_frontend(struct d
 	ves1x93_set_inversion (state, p->inversion);
 	ves1x93_set_fec (state, p->u.qpsk.fec_inner);
 	ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
-		state->inversion = p->inversion;
+	state->inversion = p->inversion;
 
 	return 0;
-        }
+}
 
 static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
-	{
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
-		int afc;
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+	int afc;
 
 	afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
-		afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+	afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
 
-		p->frequency -= afc;
+	p->frequency -= afc;
 
-		/*
-		 * inversion indicator is only valid
-		 * if auto inversion was used
-		 */
-		if (state->inversion == INVERSION_AUTO)
+	/*
+	 * inversion indicator is only valid
+	 * if auto inversion was used
+	 */
+	if (state->inversion == INVERSION_AUTO)
 		p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
-					INVERSION_OFF : INVERSION_ON;
+				INVERSION_OFF : INVERSION_ON;
 	p->u.qpsk.fec_inner = ves1x93_get_fec (state);
 	/*  XXX FIXME: timing offset !! */
 
@@ -450,16 +431,16 @@ static int ves1x93_get_frontend(struct d
 
 static int ves1x93_sleep(struct dvb_frontend* fe)
 {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+	struct ves1x93_state* state = fe->demodulator_priv;
 
 	return ves1x93_writereg (state, 0x00, 0x08);
 }
-        
+
 static void ves1x93_release(struct dvb_frontend* fe)
 {
-	struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+	struct ves1x93_state* state = fe->demodulator_priv;
 	kfree(state);
-} 
+}
 
 static struct dvb_frontend_ops ves1x93_ops;
 
@@ -470,7 +451,7 @@ struct dvb_frontend* ves1x93_attach(cons
 	u8 identity;
 
 	/* allocate memory for the internal state */
-	state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
+	state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
@@ -516,9 +497,9 @@ struct dvb_frontend* ves1x93_attach(cons
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
-	}
+}
 
 static struct dvb_frontend_ops ves1x93_ops = {
 
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -10,6 +10,7 @@ config DVB_AV7110
 	select DVB_TDA8083
 	select DVB_SP8870
 	select DVB_STV0297
+	select DVB_L64781
 	help
 	  Support for SAA7146 and AV7110 based DVB cards as produced 
 	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2,7 +2,7 @@
  * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB)
  * av7110.c: initialization and demux stuff
  *
- * Copyright (C) 1999-2002 Ralph  Metzler 
+ * Copyright (C) 1999-2002 Ralph  Metzler
  *                       & Marcus Metzler for convergence integrated media GmbH
  *
  * originally based on code by:
@@ -12,19 +12,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.
- * 
+ *
  *
  * 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  *
  * the project's page is at http://www.linuxtv.org/dvb/
  */
@@ -75,9 +75,9 @@
 
 int av7110_debug;
 
-static int vidmode=CVBS_RGB_OUT;
+static int vidmode = CVBS_RGB_OUT;
 static int pids_off;
-static int adac=DVB_ADAC_TI;
+static int adac = DVB_ADAC_TI;
 static int hw_sections;
 static int rgb_on;
 static int volume = 255;
@@ -109,14 +109,14 @@ static int av7110_num = 0;
 {\
 	if (fe_func != NULL) { \
 		av7110_copy = fe_func; \
-	   	fe_func = av7110_func; \
+		fe_func = av7110_func; \
 	} \
 }
 
 
 static void init_av7110_av(struct av7110 *av7110)
 {
-	struct saa7146_dev *dev=av7110->dev;
+	struct saa7146_dev *dev = av7110->dev;
 
 	/* set internal volume control to maximum */
 	av7110->adac_type = DVB_ADAC_TI;
@@ -130,28 +130,28 @@ static void init_av7110_av(struct av7110
 	av7110->current_input = 0;
 	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
 		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
-			av7110->dvb_adapter->num);
+			av7110->dvb_adapter.num);
 		av7110->adac_type = DVB_ADAC_CRYSTAL;
 		i2c_writereg(av7110, 0x20, 0x01, 0xd2);
 		i2c_writereg(av7110, 0x20, 0x02, 0x49);
 		i2c_writereg(av7110, 0x20, 0x03, 0x00);
 		i2c_writereg(av7110, 0x20, 0x04, 0x00);
 
-	/**
-	 * some special handling for the Siemens DVB-C cards...
-	 */
+		/**
+		 * some special handling for the Siemens DVB-C cards...
+		 */
 	} else if (0 == av7110_init_analog_module(av7110)) {
 		/* done. */
 	}
 	else if (dev->pci->subsystem_vendor == 0x110a) {
 		printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n",
-			av7110->dvb_adapter->num);
+			av7110->dvb_adapter.num);
 		av7110->adac_type = DVB_ADAC_NONE;
 	}
 	else {
 		av7110->adac_type = adac;
 		printk("dvb-ttpci: adac type set to %d @ card %d\n",
-			av7110->dvb_adapter->num, av7110->adac_type);
+			av7110->dvb_adapter.num, av7110->adac_type);
 	}
 
 	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
@@ -161,8 +161,8 @@ static void init_av7110_av(struct av7110
 		if (rgb_on &&
 		    (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
 			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
-		//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
-	}
+			//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
+		}
 	}
 
 	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
@@ -175,7 +175,7 @@ static void recover_arm(struct av7110 *a
 
 	av7110_bootarm(av7110);
 	msleep(100);
-        restart_feeds(av7110);
+	restart_feeds(av7110);
 	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
 
@@ -183,23 +183,32 @@ static void arm_error(struct av7110 *av7
 {
 	dprintk(4, "%p\n",av7110);
 
-        av7110->arm_errors++;
-        av7110->arm_ready=0;
-        recover_arm(av7110);
+	av7110->arm_errors++;
+	av7110->arm_ready = 0;
+	recover_arm(av7110);
+}
+
+static void av7110_arm_sync(struct av7110 *av7110)
+{
+	av7110->arm_rmmod = 1;
+	wake_up_interruptible(&av7110->arm_wait);
+
+	while (av7110->arm_thread)
+		msleep(1);
 }
 
 static int arm_thread(void *data)
 {
 	struct av7110 *av7110 = data;
-        u16 newloops = 0;
+	u16 newloops = 0;
 	int timeout;
 
 	dprintk(4, "%p\n",av7110);
-	
-        lock_kernel ();
-        daemonize ("arm_mon");
-        sigfillset (&current->blocked);
-        unlock_kernel ();
+
+        lock_kernel();
+        daemonize("arm_mon");
+        sigfillset(&current->blocked);
+        unlock_kernel();
 
 	av7110->arm_thread = current;
 
@@ -211,31 +220,31 @@ static int arm_thread(void *data)
 			break;
 		}
 
-                if (!av7110->arm_ready)
-                        continue;
+		if (!av7110->arm_ready)
+			continue;
 
-                if (down_interruptible(&av7110->dcomlock))
-                        break;
+		if (down_interruptible(&av7110->dcomlock))
+			break;
 
-                newloops=rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
-                up(&av7110->dcomlock);
+		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
+		up(&av7110->dcomlock);
 
-                if (newloops==av7110->arm_loops) {
+		if (newloops == av7110->arm_loops) {
 			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
-				av7110->dvb_adapter->num);
+			       av7110->dvb_adapter.num);
 
 			arm_error(av7110);
 			av7710_set_video_mode(av7110, vidmode);
 
 			init_av7110_av(av7110);
 
-                        if (down_interruptible(&av7110->dcomlock))
-                                break;
+			if (down_interruptible(&av7110->dcomlock))
+				break;
 
-                        newloops=rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2)-1;
-                        up(&av7110->dcomlock);
-                }
-                av7110->arm_loops=newloops;
+			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
+			up(&av7110->dcomlock);
+		}
+		av7110->arm_loops = newloops;
 	}
 
 	av7110->arm_thread = NULL;
@@ -245,15 +254,15 @@ static int arm_thread(void *data)
 
 /**
  *  Hack! we save the last av7110 ptr. This should be ok, since
- *  you rarely will use more then one IR control. 
+ *  you rarely will use more then one IR control.
  *
  *  If we want to support multiple controls we would have to do much more...
  */
-void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config)
+void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
 {
 	static struct av7110 *last;
 
-	dprintk(4, "%p\n",av7110);
+	dprintk(4, "%p\n", av7110);
 
 	if (!av7110)
 		av7110 = last;
@@ -268,22 +277,22 @@ void av7110_setup_irc_config (struct av7
 
 static void (*irc_handler)(u32);
 
-void av7110_register_irc_handler(void (*func)(u32)) 
+void av7110_register_irc_handler(void (*func)(u32))
 {
 	dprintk(4, "registering %p\n", func);
-        irc_handler = func;
+	irc_handler = func;
 }
 
-void av7110_unregister_irc_handler(void (*func)(u32)) 
+void av7110_unregister_irc_handler(void (*func)(u32))
 {
 	dprintk(4, "unregistering %p\n", func);
-        irc_handler = NULL;
+	irc_handler = NULL;
 }
 
 static void run_handlers(unsigned long ircom)
 {
-        if (irc_handler != NULL)
-                (*irc_handler)((u32) ircom);
+	if (irc_handler != NULL)
+		(*irc_handler)((u32) ircom);
 }
 
 static DECLARE_TASKLET(irtask, run_handlers, 0);
@@ -291,8 +300,8 @@ static DECLARE_TASKLET(irtask, run_handl
 static void IR_handle(struct av7110 *av7110, u32 ircom)
 {
 	dprintk(4, "ircommand = %08x\n", ircom);
-        irtask.data = (unsigned long) ircom;
-        tasklet_schedule(&irtask);
+	irtask.data = (unsigned long) ircom;
+	tasklet_schedule(&irtask);
 }
 
 /****************************************************************************
@@ -300,51 +309,51 @@ static void IR_handle(struct av7110 *av7
  ****************************************************************************/
 
 static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len,
-                     u8 * buffer2, size_t buffer2_len,
-                     struct dvb_demux_filter *dvbdmxfilter,
-                     enum dmx_success success,
-                     struct av7110 *av7110)
-{
-        if (!dvbdmxfilter->feed->demux->dmx.frontend)
-                return 0;
-        if (dvbdmxfilter->feed->demux->dmx.frontend->source==DMX_MEMORY_FE)
-                return 0;
-        
-        switch(dvbdmxfilter->type) {
-        case DMX_TYPE_SEC:
-                if ((((buffer1[1]<<8)|buffer1[2])&0xfff)+3!=buffer1_len)
-                        return 0;
-                if (dvbdmxfilter->doneq) {
-                        struct dmx_section_filter *filter=&dvbdmxfilter->filter;
-                        int i;
-                        u8 xor, neq=0;
-                        
-                        for (i=0; i<DVB_DEMUX_MASK_MAX; i++) {
-                                xor=filter->filter_value[i]^buffer1[i];
-                                neq|=dvbdmxfilter->maskandnotmode[i]&xor;
-                        }
-                        if (!neq)
-                                return 0;
-                }
-                return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,
+				u8 *buffer2, size_t buffer2_len,
+				struct dvb_demux_filter *dvbdmxfilter,
+				enum dmx_success success,
+				struct av7110 *av7110)
+{
+	if (!dvbdmxfilter->feed->demux->dmx.frontend)
+		return 0;
+	if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE)
+		return 0;
+
+	switch (dvbdmxfilter->type) {
+	case DMX_TYPE_SEC:
+		if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len)
+			return 0;
+		if (dvbdmxfilter->doneq) {
+			struct dmx_section_filter *filter = &dvbdmxfilter->filter;
+			int i;
+			u8 xor, neq = 0;
+
+			for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+				xor = filter->filter_value[i] ^ buffer1[i];
+				neq |= dvbdmxfilter->maskandnotmode[i] & xor;
+			}
+			if (!neq)
+				return 0;
+		}
+		return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,
 						  buffer2, buffer2_len,
 						  &dvbdmxfilter->filter,
-						  DMX_OK); 
-        case DMX_TYPE_TS:
-                if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) 
-                        return 0;
-                if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) 
-                        return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,
-                                                         buffer2, buffer2_len,
-                                                         &dvbdmxfilter->feed->feed.ts,
-                                                         DMX_OK); 
-                else
+						  DMX_OK);
+	case DMX_TYPE_TS:
+		if (!(dvbdmxfilter->feed->ts_type & TS_PACKET))
+			return 0;
+		if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY)
+			return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,
+							 buffer2, buffer2_len,
+							 &dvbdmxfilter->feed->feed.ts,
+							 DMX_OK);
+		else
 			av7110_p2t_write(buffer1, buffer1_len,
-                                  dvbdmxfilter->feed->pid, 
-                                  &av7110->p2t_filter[dvbdmxfilter->index]);
+					 dvbdmxfilter->feed->pid,
+					 &av7110->p2t_filter[dvbdmxfilter->index]);
 	default:
-	        return 0;
-        }
+		return 0;
+	}
 }
 
 
@@ -352,9 +361,9 @@ static int DvbDmxFilterCallback(u8 *buff
 static inline void print_time(char *s)
 {
 #ifdef DEBUG_TIMING
-        struct timeval tv;
-        do_gettimeofday(&tv);
-        printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec);
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec);
 #endif
 }
 
@@ -379,129 +388,129 @@ static inline void start_debi_dma(struct
 		irdebi(av7110, DEBISWAB, addr, 0, len);
 }
 
-static void debiirq (unsigned long data)
+static void debiirq(unsigned long data)
 {
-	struct av7110 *av7110 = (struct av7110*) data;
-        int type=av7110->debitype;
-        int handle=(type>>8)&0x1f;
+	struct av7110 *av7110 = (struct av7110 *) data;
+	int type = av7110->debitype;
+	int handle = (type >> 8) & 0x1f;
 	unsigned int xfer = 0;
 
-        print_time("debi");
+	print_time("debi");
 	dprintk(4, "type 0x%04x\n", type);
 
-        if (type==-1) {
+	if (type == -1) {
 		printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
 		       jiffies, saa7146_read(av7110->dev, PSR),
 		       saa7146_read(av7110->dev, SSR));
 		goto debi_done;
-        }
-        av7110->debitype=-1;
+	}
+	av7110->debitype = -1;
 
-        switch (type&0xff) {
+	switch (type & 0xff) {
 
-        case DATA_TS_RECORD:
-                dvb_dmx_swfilter_packets(&av7110->demux, 
-                                      (const u8 *)av7110->debi_virt, 
-                                      av7110->debilen/188);
+	case DATA_TS_RECORD:
+		dvb_dmx_swfilter_packets(&av7110->demux,
+					 (const u8 *) av7110->debi_virt,
+					 av7110->debilen / 188);
 		xfer = RX_BUFF;
 		break;
 
-        case DATA_PES_RECORD:
-                if (av7110->demux.recording) 
+	case DATA_PES_RECORD:
+		if (av7110->demux.recording)
 			av7110_record_cb(&av7110->p2t[handle],
-                                  (u8 *)av7110->debi_virt,
-                                  av7110->debilen);
+					 (u8 *) av7110->debi_virt,
+					 av7110->debilen);
 		xfer = RX_BUFF;
 		break;
 
-        case DATA_IPMPE:
-        case DATA_FSECTION:
-        case DATA_PIPING:
-                if (av7110->handle2filter[handle]) 
-                        DvbDmxFilterCallback((u8 *)av7110->debi_virt, 
-                                             av7110->debilen, NULL, 0, 
-                                             av7110->handle2filter[handle], 
-                                             DMX_OK, av7110); 
+	case DATA_IPMPE:
+	case DATA_FSECTION:
+	case DATA_PIPING:
+		if (av7110->handle2filter[handle])
+			DvbDmxFilterCallback((u8 *)av7110->debi_virt,
+					     av7110->debilen, NULL, 0,
+					     av7110->handle2filter[handle],
+					     DMX_OK, av7110);
 		xfer = RX_BUFF;
 		break;
 
-        case DATA_CI_GET:
-        {
-                u8 *data=av7110->debi_virt;
-
-                if ((data[0]<2) && data[2]==0xff) {
-                        int flags=0;
-                        if (data[5]>0) 
-                                flags|=CA_CI_MODULE_PRESENT;
-                        if (data[5]>5) 
-                                flags|=CA_CI_MODULE_READY;
-                        av7110->ci_slot[data[0]].flags=flags;
-                } else
-                        ci_get_data(&av7110->ci_rbuffer, 
-                                    av7110->debi_virt, 
-                                    av7110->debilen);
+	case DATA_CI_GET:
+	{
+		u8 *data = av7110->debi_virt;
+
+		if ((data[0] < 2) && data[2] == 0xff) {
+			int flags = 0;
+			if (data[5] > 0)
+				flags |= CA_CI_MODULE_PRESENT;
+			if (data[5] > 5)
+				flags |= CA_CI_MODULE_READY;
+			av7110->ci_slot[data[0]].flags = flags;
+		} else
+			ci_get_data(&av7110->ci_rbuffer,
+				    av7110->debi_virt,
+				    av7110->debilen);
 		xfer = RX_BUFF;
 		break;
-        }
+	}
 
-        case DATA_COMMON_INTERFACE:
-                CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);
+	case DATA_COMMON_INTERFACE:
+		CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);
 #if 0
-        {
-                int i;
+	{
+		int i;
 
-                printk("av7110%d: ", av7110->num);
-                printk("%02x ", *(u8 *)av7110->debi_virt);
-                printk("%02x ", *(1+(u8 *)av7110->debi_virt));
-                for (i=2; i<av7110->debilen; i++)
-                  printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt)));
-                for (i=2; i<av7110->debilen; i++)
-                  printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt)));
+		printk("av7110%d: ", av7110->num);
+		printk("%02x ", *(u8 *)av7110->debi_virt);
+		printk("%02x ", *(1+(u8 *)av7110->debi_virt));
+		for (i = 2; i < av7110->debilen; i++)
+			printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt)));
+		for (i = 2; i < av7110->debilen; i++)
+			printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt)));
 
-                printk("\n");
-        }
+		printk("\n");
+	}
 #endif
 		xfer = RX_BUFF;
 		break;
 
-        case DATA_DEBUG_MESSAGE:
-                ((s8*)av7110->debi_virt)[Reserved_SIZE-1]=0;
-                printk("%s\n", (s8 *)av7110->debi_virt);
+	case DATA_DEBUG_MESSAGE:
+		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
+		printk("%s\n", (s8 *) av7110->debi_virt);
 		xfer = RX_BUFF;
 		break;
 
-        case DATA_CI_PUT:
+	case DATA_CI_PUT:
 		dprintk(4, "debi DATA_CI_PUT\n");
-        case DATA_MPEG_PLAY:
+	case DATA_MPEG_PLAY:
 		dprintk(4, "debi DATA_MPEG_PLAY\n");
-        case DATA_BMP_LOAD:
+	case DATA_BMP_LOAD:
 		dprintk(4, "debi DATA_BMP_LOAD\n");
 		xfer = TX_BUFF;
 		break;
-        default:
-                break;
-        }
+	default:
+		break;
+	}
 debi_done:
-        spin_lock(&av7110->debilock);
+	spin_lock(&av7110->debilock);
 	if (xfer)
 		iwdebi(av7110, DEBINOSWAP, xfer, 0, 2);
-        ARM_ClearMailBox(av7110);
-        spin_unlock(&av7110->debilock);
+	ARM_ClearMailBox(av7110);
+	spin_unlock(&av7110->debilock);
 }
 
 /* irq from av7110 firmware writing the mailbox register in the DPRAM */
-static void gpioirq (unsigned long data)
+static void gpioirq(unsigned long data)
 {
-	struct av7110 *av7110 = (struct av7110*) data;
-        u32 rxbuf, txbuf;
-        int len;
-        
-        if (av7110->debitype !=-1)
+	struct av7110 *av7110 = (struct av7110 *) data;
+	u32 rxbuf, txbuf;
+	int len;
+
+	if (av7110->debitype != -1)
 		/* we shouldn't get any irq while a debi xfer is running */
 		printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
 		       jiffies, saa7146_read(av7110->dev, PSR),
 		       saa7146_read(av7110->dev, SSR));
-       
+
 	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
 		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);
 		BUG(); /* maybe we should try resetting the debi? */
@@ -511,37 +520,37 @@ static void gpioirq (unsigned long data)
 	ARM_ClearIrq(av7110);
 
 	/* see what the av7110 wants */
-        av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);
-        av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-        rxbuf=irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-        txbuf=irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+	av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);
+	av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+	rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+	txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
 	len = (av7110->debilen + 3) & ~3;
 
-        print_time("gpio");
+	print_time("gpio");
 	dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen);
 
-        switch (av7110->debitype&0xff) {
+	switch (av7110->debitype & 0xff) {
 
-        case DATA_TS_PLAY:
-        case DATA_PES_PLAY:
-                break;
+	case DATA_TS_PLAY:
+	case DATA_PES_PLAY:
+		break;
 
 	case DATA_MPEG_VIDEO_EVENT:
 	{
 		u32 h_ar;
 		struct video_event event;
 
-                av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2);
-                h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2);
+		av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2);
+		h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2);
 
-                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
 
 		av7110->video_size.h = h_ar & 0xfff;
 		dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
-				av7110->video_size.w,
-				av7110->video_size.h,
-				av7110->video_size.aspect_ratio);
+			av7110->video_size.w,
+			av7110->video_size.h,
+			av7110->video_size.aspect_ratio);
 
 		event.type = VIDEO_EVENT_SIZE_CHANGED;
 		event.u.size.w = av7110->video_size.w;
@@ -567,139 +576,139 @@ static void gpioirq (unsigned long data)
 		break;
 	}
 
-        case DATA_CI_PUT:
-        {
-                int avail;
-                struct dvb_ringbuffer *cibuf=&av7110->ci_wbuffer;
-
-                avail=dvb_ringbuffer_avail(cibuf);
-                if (avail<=2) {
-                        iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                        break;
-                } 
-                len= DVB_RINGBUFFER_PEEK(cibuf,0)<<8;
-                len|=DVB_RINGBUFFER_PEEK(cibuf,1);
-                if (avail<len+2) {
-                        iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                        break;
-                } 
-                DVB_RINGBUFFER_SKIP(cibuf,2); 
+	case DATA_CI_PUT:
+	{
+		int avail;
+		struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer;
 
-                dvb_ringbuffer_read(cibuf,av7110->debi_virt,len,0);
+		avail = dvb_ringbuffer_avail(cibuf);
+		if (avail <= 2) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
+		len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
+		if (avail < len + 2) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		DVB_RINGBUFFER_SKIP(cibuf, 2);
+
+		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0);
 
-                iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
 		dprintk(8, "DMA: CI\n");
 		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
-                spin_unlock(&av7110->debilock);
+		spin_unlock(&av7110->debilock);
 		wake_up(&cibuf->queue);
-                return;
-        }
+		return;
+	}
 
-        case DATA_MPEG_PLAY:
-                if (!av7110->playing) {
-                        iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                        break;
-                }
-                len=0;
-                if (av7110->debitype&0x100) {
-                        spin_lock(&av7110->aout.lock);
-			len=av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);
-                        spin_unlock(&av7110->aout.lock);
-                }
-                if (len<=0 && (av7110->debitype&0x200)
-                        &&av7110->videostate.play_state!=VIDEO_FREEZED) {
-                        spin_lock(&av7110->avout.lock);
-			len=av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);
-                        spin_unlock(&av7110->avout.lock);
-                }
-                if (len<=0) {
-                        iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                        break;
-                } 
+	case DATA_MPEG_PLAY:
+		if (!av7110->playing) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		len = 0;
+		if (av7110->debitype & 0x100) {
+			spin_lock(&av7110->aout.lock);
+			len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);
+			spin_unlock(&av7110->aout.lock);
+		}
+		if (len <= 0 && (av7110->debitype & 0x200)
+		    &&av7110->videostate.play_state != VIDEO_FREEZED) {
+			spin_lock(&av7110->avout.lock);
+			len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);
+			spin_unlock(&av7110->avout.lock);
+		}
+		if (len <= 0) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
 		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
-                iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
 		dprintk(8, "DMA: MPEG_PLAY\n");
 		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
-                spin_unlock(&av7110->debilock);
-                return;
+		spin_unlock(&av7110->debilock);
+		return;
 
-        case DATA_BMP_LOAD:
-                len=av7110->debilen;
+	case DATA_BMP_LOAD:
+		len = av7110->debilen;
 		dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len);
-                if (!len) {
-                        av7110->bmp_state=BMP_LOADED;
-                        iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-                        iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                        wake_up(&av7110->bmpq);
+		if (!len) {
+			av7110->bmp_state = BMP_LOADED;
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			wake_up(&av7110->bmpq);
 			dprintk(8, "gpio DATA_BMP_LOAD done\n");
-                        break;
-                }
-                if (len>av7110->bmplen)
-                        len=av7110->bmplen;
-                if (len>2*1024)
-                        len=2*1024;
-                iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-                memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
-                av7110->bmpp+=len;
-                av7110->bmplen-=len;
+			break;
+		}
+		if (len > av7110->bmplen)
+			len = av7110->bmplen;
+		if (len > 2 * 1024)
+			len = 2 * 1024;
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
+		av7110->bmpp += len;
+		av7110->bmplen -= len;
 		dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
 		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len);
-                spin_unlock(&av7110->debilock);
-                return;
+		spin_unlock(&av7110->debilock);
+		return;
 
-        case DATA_CI_GET:
-        case DATA_COMMON_INTERFACE:
-        case DATA_FSECTION:
-        case DATA_IPMPE:
-        case DATA_PIPING:
-                if (!len || len>4*1024) {
-                        iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                        break;
+	case DATA_CI_GET:
+	case DATA_COMMON_INTERFACE:
+	case DATA_FSECTION:
+	case DATA_IPMPE:
+	case DATA_PIPING:
+		if (!len || len > 4 * 1024) {
+			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+			break;
 		}
 		/* fall through */
 
-        case DATA_TS_RECORD:
-        case DATA_PES_RECORD:
+	case DATA_TS_RECORD:
+	case DATA_PES_RECORD:
 		dprintk(8, "DMA: TS_REC etc.\n");
 		start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len);
-                spin_unlock(&av7110->debilock);
-                return;
+		spin_unlock(&av7110->debilock);
+		return;
 
-        case DATA_DEBUG_MESSAGE:
-                if (!len || len>0xff) {
-                        iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                        break;
-                }
+	case DATA_DEBUG_MESSAGE:
+		if (!len || len > 0xff) {
+			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+			break;
+		}
 		start_debi_dma(av7110, DEBI_READ, Reserved, len);
-                spin_unlock(&av7110->debilock);
-                return;
+		spin_unlock(&av7110->debilock);
+		return;
 
-        case DATA_IRCOMMAND: 
-                IR_handle(av7110, 
-                          swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                break;
+	case DATA_IRCOMMAND:
+		IR_handle(av7110,
+			  swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
+		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+		break;
 
-        default:
+	default:
 		printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n",
-                       av7110->debitype, av7110->debilen);
-                break;
-        }      
-        av7110->debitype=-1;
+		       av7110->debitype, av7110->debilen);
+		break;
+	}
+	av7110->debitype = -1;
 	ARM_ClearMailBox(av7110);
-        spin_unlock(&av7110->debilock);
+	spin_unlock(&av7110->debilock);
 }
 
 
@@ -718,7 +727,7 @@ static int dvb_osd_ioctl(struct inode *i
 		return av7110_osd_capability(av7110, (osd_cap_t *) parg);
 
 	return -EINVAL;
-        }
+}
 
 
 static struct file_operations dvb_osd_fops = {
@@ -740,7 +749,7 @@ static struct dvb_device dvbdev_osd = {
 
 static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 			  u16 subpid, u16 pcrpid)
-        {
+{
 	dprintk(4, "%p\n", av7110);
 
 	if (vpid == 0x1fff || apid == 0x1fff ||
@@ -760,7 +769,7 @@ void ChangePIDs(struct av7110 *av7110, u
 		u16 subpid, u16 pcrpid)
 {
 	dprintk(4, "%p\n", av7110);
-        
+
 	if (down_interruptible(&av7110->pid_mutex))
 		return;
 
@@ -772,13 +781,13 @@ void ChangePIDs(struct av7110 *av7110, u
 		av7110->pids[DMX_PES_TELETEXT] = ttpid;
 	if (!(pcrpid & 0x8000))
 		av7110->pids[DMX_PES_PCR] = pcrpid;
-	
+
 	av7110->pids[DMX_PES_SUBTITLE] = 0;
 
 	if (av7110->fe_synced) {
 		pcrpid = av7110->pids[DMX_PES_PCR];
 		SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
-        }
+	}
 
 	up(&av7110->pid_mutex);
 }
@@ -795,8 +804,8 @@ static int StartHWFilter(struct dvb_demu
 	u16 buf[20];
 	int ret, i;
 	u16 handle;
-//	u16 mode=0x0320;
-	u16 mode=0xb96a;
+//	u16 mode = 0x0320;
+	u16 mode = 0xb96a;
 
 	dprintk(4, "%p\n", av7110);
 
@@ -809,11 +818,11 @@ static int StartHWFilter(struct dvb_demu
 					(dvbdmxfilter->filter.filter_value[i] << 8) |
 					dvbdmxfilter->maskandmode[i];
 			mode = 4;
-                }
+		}
 	} else if ((dvbdmxfeed->ts_type & TS_PACKET) &&
 		   !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) {
 		av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed);
-        }
+	}
 
 	buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter;
 	buf[1] = 16;
@@ -828,13 +837,13 @@ static int StartHWFilter(struct dvb_demu
 				ret, handle);
 		dvbdmxfilter->hw_handle = 0xffff;
 		return -1;
-        }
+	}
 
 	av7110->handle2filter[handle] = dvbdmxfilter;
 	dvbdmxfilter->hw_handle = handle;
 
 	return ret;
-                }
+}
 
 static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 {
@@ -843,7 +852,7 @@ static int StopHWFilter(struct dvb_demux
 	u16 answ[2];
 	int ret;
 	u16 handle;
-        
+
 	dprintk(4, "%p\n", av7110);
 
 	handle = dvbdmxfilter->hw_handle;
@@ -851,7 +860,7 @@ static int StopHWFilter(struct dvb_demux
 		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
 				__FUNCTION__, handle, dvbdmxfilter->type);
 		return 0;
-                }
+	}
 
 	av7110->handle2filter[handle] = NULL;
 
@@ -865,8 +874,8 @@ static int StopHWFilter(struct dvb_demux
 				__FUNCTION__, buf[0], buf[1], buf[2], ret,
 				answ[0], answ[1], dvbdmxfilter->feed->pid);
 		ret = -1;
-        }
-        return ret;
+	}
+	return ret;
 }
 
 
@@ -890,7 +899,7 @@ static void dvb_feed_start_pid(struct dv
 	}
 	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4)
 		ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
-        
+
 	if (dvbdmxfeed->pes_type < 2 && npids[0])
 		if (av7110->fe_synced)
 			av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
@@ -902,16 +911,16 @@ static void dvb_feed_start_pid(struct dv
 			av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
 	}
 }
-                
+
 static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
 	u16 *pid = dvbdmx->pids, npids[5];
 	int i;
-                
+
 	dprintk(4, "%p\n", av7110);
-                
+
 	if (dvbdmxfeed->pes_type <= 1) {
 		av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);
 		if (!av7110->rec_mode)
@@ -926,31 +935,31 @@ static void dvb_feed_stop_pid(struct dvb
 		if (dvbdmxfeed->ts_type & TS_PACKET)
 			StopHWFilter(dvbdmxfeed->filter);
 		npids[2] = 0;
-                break;
+		break;
 	case 0:
 	case 1:
 	case 4:
 		if (!pids_off)
 			return;
 		npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
-                break;
-        }
+		break;
+	}
 	ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
 }
-        
+
 static int av7110_start_feed(struct dvb_demux_feed *feed)
 {
 	struct dvb_demux *demux = feed->demux;
 	struct av7110 *av7110 = demux->priv;
-                
+
 	dprintk(4, "%p\n", av7110);
-                
+
 	if (!demux->dmx.frontend)
 		return -EINVAL;
-                        
+
 	if (feed->pid > 0x1fff)
 		return -EINVAL;
-                        
+
 	if (feed->type == DMX_TYPE_TS) {
 		if ((feed->ts_type & TS_DECODER) &&
 		    (feed->pes_type < DMX_TS_PES_OTHER)) {
@@ -965,17 +974,17 @@ static int av7110_start_feed(struct dvb_
 					       av7110_av_start_play(av7110,RP_AV);
 					       demux->playing = 1;
 					}
-                        break;
-                default:
+				break;
+			default:
 				dvb_feed_start_pid(feed);
-                        break;
-                }
+				break;
+			}
 		} else if ((feed->ts_type & TS_PACKET) &&
 			   (demux->dmx.frontend->source != DMX_MEMORY_FE)) {
 			StartHWFilter(feed->filter);
 		}
 	}
-                
+
 	if (feed->type == DMX_TYPE_SEC) {
 		int i;
 
@@ -989,8 +998,8 @@ static int av7110_start_feed(struct dvb_
 			demux->filter[i].state = DMX_STATE_GO;
 			if (demux->dmx.frontend->source != DMX_MEMORY_FE)
 				StartHWFilter(&demux->filter[i]);
-        }
-        }
+		}
+	}
 
 	return 0;
 }
@@ -1023,7 +1032,7 @@ static int av7110_stop_feed(struct dvb_d
 	if (feed->type == DMX_TYPE_SEC) {
 		int i;
 
-		for (i=0; i<demux->filternum; i++)
+		for (i = 0; i<demux->filternum; i++)
 			if (demux->filter[i].state == DMX_STATE_GO &&
 			    demux->filter[i].filter.parent == &feed->feed.sec) {
 				demux->filter[i].state = DMX_STATE_READY;
@@ -1032,7 +1041,7 @@ static int av7110_stop_feed(struct dvb_d
 		}
 	}
 
-        return 0;
+	return 0;
 }
 
 
@@ -1085,14 +1094,14 @@ static int dvb_get_stc(struct dmx_demux 
 	if (ret) {
 		printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);
 		return -EIO;
-}
+	}
 	dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
 		fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
 
 	*stc =	(((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) |
 		(((uint64_t)  fwstc[1]) << 16) | ((uint64_t) fwstc[0]);
 	*base = 1;
-        
+
 	dprintk(4, "stc = %lu\n", (unsigned long)*stc);
 
 	return 0;
@@ -1109,15 +1118,16 @@ static int av7110_set_tone(struct dvb_fr
 	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 
 	switch (tone) {
-		case SEC_TONE_ON:
-			Set22K(av7110, 1);
-			break;
-		case SEC_TONE_OFF:
-			Set22K(av7110, 0);
-			break;
+	case SEC_TONE_ON:
+		Set22K(av7110, 1);
+		break;
 
-		default:
-			return -EINVAL;
+	case SEC_TONE_OFF:
+		Set22K(av7110, 0);
+		break;
+
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -1241,21 +1251,21 @@ static void vpeirq(unsigned long data)
 
 static int av7110_register(struct av7110 *av7110)
 {
-        int ret, i;
-        struct dvb_demux *dvbdemux=&av7110->demux;
+	int ret, i;
+	struct dvb_demux *dvbdemux = &av7110->demux;
 	struct dvb_demux *dvbdemux1 = &av7110->demux1;
 
 	dprintk(4, "%p\n", av7110);
 
-        if (av7110->registered)
-                return -1;
+	if (av7110->registered)
+		return -1;
 
-        av7110->registered=1;
+	av7110->registered = 1;
 
-        dvbdemux->priv = (void *) av7110;
+	dvbdemux->priv = (void *) av7110;
 
-	for (i=0; i<32; i++)
-		av7110->handle2filter[i]=NULL;
+	for (i = 0; i < 32; i++)
+		av7110->handle2filter[i] = NULL;
 
 	dvbdemux->filternum = 32;
 	dvbdemux->feednum = 32;
@@ -1271,37 +1281,37 @@ static int av7110_register(struct av7110
 	av7110->dmxdev.filternum = 32;
 	av7110->dmxdev.demux = &dvbdemux->dmx;
 	av7110->dmxdev.capabilities = 0;
-        
-	dvb_dmxdev_init(&av7110->dmxdev, av7110->dvb_adapter);
 
-        av7110->hw_frontend.source = DMX_FRONTEND_0;
+	dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter);
+
+	av7110->hw_frontend.source = DMX_FRONTEND_0;
 
-        ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
+
+	if (ret < 0)
+		return ret;
 
-        if (ret < 0)
-                return ret;
-        
-        av7110->mem_frontend.source = DMX_MEMORY_FE;
+	av7110->mem_frontend.source = DMX_MEMORY_FE;
 
 	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
 
 	if (ret < 0)
-                return ret;
-        
-        ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, 
+		return ret;
+
+	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx,
 					     &av7110->hw_frontend);
-        if (ret < 0)
-                return ret;
+	if (ret < 0)
+		return ret;
 
 	av7110_av_register(av7110);
 	av7110_ca_register(av7110);
 
 #ifdef CONFIG_DVB_AV7110_OSD
-	dvb_register_device(av7110->dvb_adapter, &av7110->osd_dev,
+	dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev,
 			    &dvbdev_osd, av7110, DVB_DEVICE_OSD);
 #endif
-        
-        dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
+
+	dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
 
 	if (budgetpatch) {
 		/* initialize software demux1 without its own frontend
@@ -1324,9 +1334,9 @@ static int av7110_register(struct av7110
 		av7110->dmxdev1.demux = &dvbdemux1->dmx;
 		av7110->dmxdev1.capabilities = 0;
 
-		dvb_dmxdev_init(&av7110->dmxdev1, av7110->dvb_adapter);
+		dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter);
 
-		dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
+		dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
 		printk("dvb-ttpci: additional demux1 for budget-patch registered\n");
 	}
 	return 0;
@@ -1335,13 +1345,13 @@ static int av7110_register(struct av7110
 
 static void dvb_unregister(struct av7110 *av7110)
 {
-        struct dvb_demux *dvbdemux=&av7110->demux;
+	struct dvb_demux *dvbdemux = &av7110->demux;
 	struct dvb_demux *dvbdemux1 = &av7110->demux1;
 
 	dprintk(4, "%p\n", av7110);
 
-        if (!av7110->registered)
-                return;
+	if (!av7110->registered)
+		return;
 
 	if (budgetpatch) {
 		dvb_net_release(&av7110->dvb_net1);
@@ -1353,11 +1363,11 @@ static void dvb_unregister(struct av7110
 	dvb_net_release(&av7110->dvb_net);
 
 	dvbdemux->dmx.close(&dvbdemux->dmx);
-        dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
-        dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
 
-        dvb_dmxdev_release(&av7110->dmxdev);
-        dvb_dmx_release(&av7110->demux);
+	dvb_dmxdev_release(&av7110->dmxdev);
+	dvb_dmx_release(&av7110->demux);
 
 	if (av7110->fe != NULL)
 		dvb_unregister_frontend(av7110->fe);
@@ -1375,7 +1385,7 @@ int i2c_writereg(struct av7110 *av7110, 
 {
 	u8 msg[2] = { reg, val };
 	struct i2c_msg msgs;
-	
+
 	msgs.flags = 0;
 	msgs.addr = id / 2;
 	msgs.len = 2;
@@ -1411,10 +1421,10 @@ static int check_firmware(struct av7110*
 {
 	u32 crc = 0, len = 0;
 	unsigned char *ptr;
-		
+
 	/* check for firmware magic */
 	ptr = av7110->bin_fw;
-	if (ptr[0] != 'A' || ptr[1] != 'V' || 
+	if (ptr[0] != 'A' || ptr[1] != 'V' ||
 	    ptr[2] != 'F' || ptr[3] != 'W') {
 		printk("dvb-ttpci: this is not an av7110 firmware\n");
 		return -EINVAL;
@@ -1422,34 +1432,34 @@ static int check_firmware(struct av7110*
 	ptr += 4;
 
 	/* check dpram file */
-	crc = ntohl(*(u32*)ptr);
+	crc = ntohl(*(u32*) ptr);
 	ptr += 4;
-	len = ntohl(*(u32*)ptr);
+	len = ntohl(*(u32*) ptr);
 	ptr += 4;
 	if (len >= 512) {
 		printk("dvb-ttpci: dpram file is way to big.\n");
 		return -EINVAL;
 	}
-	if( crc != crc32_le(0,ptr,len)) {
+	if (crc != crc32_le(0, ptr, len)) {
 		printk("dvb-ttpci: crc32 of dpram file does not match.\n");
 		return -EINVAL;
 	}
 	av7110->bin_dpram = ptr;
 	av7110->size_dpram = len;
 	ptr += len;
-	
+
 	/* check root file */
-	crc = ntohl(*(u32*)ptr);
+	crc = ntohl(*(u32*) ptr);
 	ptr += 4;
-	len = ntohl(*(u32*)ptr);
+	len = ntohl(*(u32*) ptr);
 	ptr += 4;
-	
+
 	if (len <= 200000 || len >= 300000 ||
 	    len > ((av7110->bin_fw + av7110->size_fw) - ptr)) {
-		printk("dvb-ttpci: root file has strange size (%d). aborting.\n",len);
+		printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len);
 		return -EINVAL;
 	}
-	if( crc != crc32_le(0,ptr,len)) {
+	if( crc != crc32_le(0, ptr, len)) {
 		printk("dvb-ttpci: crc32 of root file does not match.\n");
 		return -EINVAL;
 	}
@@ -1460,6 +1470,11 @@ static int check_firmware(struct av7110*
 
 #ifdef CONFIG_DVB_AV7110_FIRMWARE_FILE
 #include "av7110_firm.h"
+static void put_firmware(struct av7110* av7110)
+{
+	av7110->bin_fw = NULL;
+}
+
 static inline int get_firmware(struct av7110* av7110)
 {
 	av7110->bin_fw = dvb_ttpci_fw;
@@ -1467,6 +1482,11 @@ static inline int get_firmware(struct av
 	return check_firmware(av7110);
 }
 #else
+static void put_firmware(struct av7110* av7110)
+{
+	vfree(av7110->bin_fw);
+}
+
 static int get_firmware(struct av7110* av7110)
 {
 	int ret;
@@ -1495,7 +1515,7 @@ static int get_firmware(struct av7110* a
 	}
 
 	/* check if the firmware is available */
-	av7110->bin_fw = (unsigned char*) vmalloc(fw->size);
+	av7110->bin_fw = (unsigned char *) vmalloc(fw->size);
 	if (NULL == av7110->bin_fw) {
 		dprintk(1, "out of memory\n");
 		release_firmware(fw);
@@ -1603,11 +1623,11 @@ static int alps_bsru6_set_symbol_rate(st
 	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
 	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
 
-	stv0299_writereg (fe, 0x13, aclk);
-	stv0299_writereg (fe, 0x14, bclk);
-	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio      ) & 0xf0);
 
 	return 0;
 }
@@ -1631,7 +1651,7 @@ static int alps_bsru6_pll_set(struct dvb
 
 	if (params->frequency > 1530000) data[3] = 0xc0;
 
-	ret = i2c_transfer (&av7110->i2c_adap, &msg, 1);
+	ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
 	if (ret != 1)
 		return -EIO;
 	return 0;
@@ -1653,6 +1673,106 @@ static struct stv0299_config alps_bsru6_
 };
 
 
+static u8 alps_bsbe1_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x92,
+	0xff, 0xff
+};
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	int ret;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+	ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsbe1_pll_set,
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	int ret;
+	u8 data[1];
+	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		data[0] = 0x00;
+		break;
+	case SEC_VOLTAGE_13:
+		data[0] = 0x44;
+		break;
+	case SEC_VOLTAGE_18:
+		data[0] = 0x4c;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
 
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
@@ -1668,7 +1788,7 @@ static int alps_tdbe2_pll_set(struct dvb
 	data[2] = 0x85 | ((div >> 10) & 0x60);
 	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -1698,7 +1818,7 @@ static int grundig_29504_451_pll_set(str
 	data[2] = 0x8e;
 	data[3] = 0x00;
 
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -1726,7 +1846,7 @@ static int philips_cd1516_pll_set(struct
 	data[2] = 0x8e;
 	data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
 
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -1760,7 +1880,7 @@ static int alps_tdlb7_pll_set(struct dvb
 	data[2] = 0x85;
 	data[3] = pwr << 6;
 
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -1808,16 +1928,16 @@ static int nexusca_stv0297_pll_set(struc
 		return -EINVAL;
 
 	stv0297_enable_plli2c(fe);
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) {
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
 		printk("nexusca: pll transfer failed!\n");
 		return -EIO;
 	}
 
 	// wait for PLL lock
-	for(i=0; i< 20; i++) {
+	for(i = 0; i < 20; i++) {
 
 		stv0297_enable_plli2c(fe);
-		if (i2c_transfer (&av7110->i2c_adap, &readmsg, 1) == 1)
+		if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
 			if (data[0] & 0x40) break;
 		msleep(10);
 	}
@@ -1833,6 +1953,45 @@ static struct stv0297_config nexusca_stv
 };
 
 
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (36125000 + params->frequency) / 166666;
+
+	cfg = 0x88;
+
+	if (params->frequency < 175000000) cpump = 2;
+	else if (params->frequency < 390000000) cpump = 1;
+	else if (params->frequency < 470000000) cpump = 2;
+	else if (params->frequency < 750000000) cpump = 1;
+	else cpump = 3;
+
+	if (params->frequency < 175000000) band_select = 0x0e;
+	else if (params->frequency < 470000000) band_select = 0x05;
+	else band_select = 0x03;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | cfg;
+	data[3] = (cpump << 6) | band_select;
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+	.demod_address = 0x55,
+	.pll_set = grundig_29504_401_pll_set,
+};
+
+
+
 static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
 {
 	int synced = (status & FE_HAS_LOCK) ? 1 : 0;
@@ -1855,9 +2014,9 @@ static void av7110_fe_lock_fix(struct av
 			av7110->pids[DMX_PES_AUDIO],
 			av7110->pids[DMX_PES_TELETEXT], 0,
 			av7110->pids[DMX_PES_PCR]);
-	                av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
 	} else {
-			SetPIDs(av7110, 0, 0, 0, 0, 0);
+		SetPIDs(av7110, 0, 0, 0, 0, 0);
 		av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
 		av7110_wait_msgstate(av7110, GPMQBusy);
 	}
@@ -1959,8 +2118,10 @@ static u8 read_pwm(struct av7110* av7110
 	return pwm;
 }
 
-static void frontend_init(struct av7110 *av7110)
+static int frontend_init(struct av7110 *av7110)
 {
+	int ret;
+
 	if (av7110->dev->pci->subsystem_vendor == 0x110a) {
 		switch(av7110->dev->pci->subsystem_device) {
 		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
@@ -2038,6 +2199,11 @@ static void frontend_init(struct av7110 
 			}
 			break;
 
+		case 0x0008: // Hauppauge/TT DVB-T
+
+			av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+			break;
+
 		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
 
 			av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b);
@@ -2050,10 +2216,20 @@ static void frontend_init(struct av7110 
 				av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
 				break;
 			}
+			break;
+
+		case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
+			/* ALPS BSBE1 */
+			av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
+			if (av7110->fe)
+				av7110->fe->ops->set_voltage = lnbp21_set_voltage;
+			break;
 		}
 	}
 
-	if (av7110->fe == NULL) {
+	if (!av7110->fe) {
+		/* FIXME: propagate the failure code from the lower layers */
+		ret = -ENOMEM;
 		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
 		       av7110->dev->pci->vendor,
 		       av7110->dev->pci->device,
@@ -2070,13 +2246,15 @@ static void frontend_init(struct av7110 
 		FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
 		FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
-		if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) {
+		ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
+		if (ret < 0) {
 			printk("av7110: Frontend registration failed!\n");
 			if (av7110->fe->ops->release)
 				av7110->fe->ops->release(av7110->fe);
 			av7110->fe = NULL;
 		}
 	}
+	return ret;
 }
 
 /* Budgetpatch note:
@@ -2146,10 +2324,10 @@ static void frontend_init(struct av7110 
  */
 static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
 {
-	struct av7110 *av7110 = NULL;
-	int length = TS_WIDTH * TS_HEIGHT;
-	int ret = 0;
-	int count = 0;
+	const int length = TS_WIDTH * TS_HEIGHT;
+	struct pci_dev *pdev = dev->pci;
+	struct av7110 *av7110;
+	int ret, count = 0;
 
 	dprintk(4, "dev: %p\n", dev);
 
@@ -2243,23 +2421,26 @@ static int av7110_attach(struct saa7146_
 	}
 
 	/* prepare the av7110 device struct */
-	if (!(av7110 = kmalloc (sizeof (struct av7110), GFP_KERNEL))) {
+	av7110 = kmalloc(sizeof(struct av7110), GFP_KERNEL);
+	if (!av7110) {
 		dprintk(1, "out of memory\n");
 		return -ENOMEM;
 	}
 
 	memset(av7110, 0, sizeof(struct av7110));
-	
-	av7110->card_name = (char*)pci_ext->ext_priv;
+
+	av7110->card_name = (char*) pci_ext->ext_priv;
 	av7110->dev = dev;
 	dev->ext_priv = av7110;
 
-	if ((ret = get_firmware(av7110))) {
-		kfree(av7110);
-		return ret;
-	}
+	ret = get_firmware(av7110);
+	if (ret < 0)
+		goto err_kfree_0;
 
-	dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, THIS_MODULE);
+	ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
+				   THIS_MODULE);
+	if (ret < 0)
+		goto err_put_firmware_1;
 
 	/* the Siemens DVB needs this if you want to have the i2c chips
 	   get recognized before the main driver is fully loaded */
@@ -2274,21 +2455,21 @@ static int av7110_attach(struct saa7146_
 
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
 
-	if (i2c_add_adapter(&av7110->i2c_adap) < 0) {
-err_no_mem:
-		dvb_unregister_adapter (av7110->dvb_adapter);
-		kfree(av7110);
-		return -ENOMEM;
-	}
+	ret = i2c_add_adapter(&av7110->i2c_adap);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter_2;
 
-	ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac);
+	ttpci_eeprom_parse_mac(&av7110->i2c_adap,
+			       av7110->dvb_adapter.proposed_mac);
+	ret = -ENOMEM;
 
 	if (budgetpatch) {
 		spin_lock_init(&av7110->feedlock1);
-		av7110->grabbing = saa7146_vmalloc_build_pgtable(
-					 dev->pci, length, &av7110->pt);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+								 &av7110->pt);
 		if (!av7110->grabbing)
-			goto err_no_mem;
+			goto err_i2c_del_3;
+
 		saa7146_write(dev, PCI_BT_V1, 0x1c1f101f);
 		saa7146_write(dev, BCS_CTRL, 0x80400040);
 		/* set dd1 stream a & b */
@@ -2363,131 +2544,140 @@ err_no_mem:
 		/* end of budgetpatch register initialization */
 		tasklet_init (&av7110->vpe_tasklet,  vpeirq,  (unsigned long) av7110);
 	} else {
-	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
-	saa7146_write(dev, BCS_CTRL, 0x80400040);
+		saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+		saa7146_write(dev, BCS_CTRL, 0x80400040);
 
-	/* set dd1 stream a & b */
-      	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-	saa7146_write(dev, DD1_INIT, 0x03000000);
-	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-	/* upload all */
-	saa7146_write(dev, MC2, 0x077c077c);
-        saa7146_write(dev, GPIO_CTRL, 0x000000);
+		/* set dd1 stream a & b */
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, DD1_INIT, 0x03000000);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+		/* upload all */
+		saa7146_write(dev, MC2, 0x077c077c);
+		saa7146_write(dev, GPIO_CTRL, 0x000000);
 	}
 
 	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
 	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
 
-        sema_init(&av7110->pid_mutex, 1);
+	sema_init(&av7110->pid_mutex, 1);
 
-        /* locks for data transfers from/to AV7110 */
-        spin_lock_init (&av7110->debilock);
-        sema_init(&av7110->dcomlock, 1);
-        av7110->debitype=-1;
+	/* locks for data transfers from/to AV7110 */
+	spin_lock_init(&av7110->debilock);
+	sema_init(&av7110->dcomlock, 1);
+	av7110->debitype = -1;
 
-        /* default OSD window */
-        av7110->osdwin=1;
+	/* default OSD window */
+	av7110->osdwin = 1;
 	sema_init(&av7110->osd_sema, 1);
 
-        /* ARM "watchdog" */
+	/* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);
-        av7110->arm_thread=NULL;
-     
-        /* allocate and init buffers */
-        av7110->debi_virt = pci_alloc_consistent(dev->pci, 8192,
-						 &av7110->debi_bus);
-	if (!av7110->debi_virt) {
-		ret = -ENOMEM;
-                goto err;
-	}
+	av7110->arm_thread = NULL;
 
-        av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
-	if (!av7110->iobuf) {
-		ret = -ENOMEM;
-                goto err;
-	}
+	/* allocate and init buffers */
+	av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus);
+	if (!av7110->debi_virt)
+		goto err_saa71466_vfree_4;
 
-	av7110_av_init(av7110);
 
-        /* init BMP buffer */
-        av7110->bmpbuf=av7110->iobuf+AVOUTLEN+AOUTLEN;
-        init_waitqueue_head(&av7110->bmpq);
-        
-	av7110_ca_init(av7110);
+	av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
+	if (!av7110->iobuf)
+		goto err_pci_free_5;
 
-        /* load firmware into AV7110 cards */
-	av7110_bootarm(av7110);
-	if (av7110_firmversion(av7110)) {
-		ret = -EIO;
-		goto err2;
-	}
+	ret = av7110_av_init(av7110);
+	if (ret < 0)
+		goto err_iobuf_vfree_6;
+
+	/* init BMP buffer */
+	av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN;
+	init_waitqueue_head(&av7110->bmpq);
+
+	ret = av7110_ca_init(av7110);
+	if (ret < 0)
+		goto err_av7110_av_exit_7;
+
+	/* load firmware into AV7110 cards */
+	ret = av7110_bootarm(av7110);
+	if (ret < 0)
+		goto err_av7110_ca_exit_8;
+
+	ret = av7110_firmversion(av7110);
+	if (ret < 0)
+		goto err_stop_arm_9;
 
 	if (FW_VERSION(av7110->arm_app)<0x2501)
 		printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
 			"System might be unstable!\n", FW_VERSION(av7110->arm_app));
 
-	if (kernel_thread(arm_thread, (void *) av7110, 0) < 0) {
-		printk("dvb-ttpci: failed to start arm_mon kernel thread @ card %d\n",
-		       av7110->dvb_adapter->num);
-		goto err2;
-	}
+	ret = kernel_thread(arm_thread, (void *) av7110, 0);
+	if (ret < 0)
+		goto err_stop_arm_9;
 
 	/* set initial volume in mixer struct */
 	av7110->mixer.volume_left  = volume;
 	av7110->mixer.volume_right = volume;
-	
+
 	init_av7110_av(av7110);
 
-	av7110_register(av7110);
-	
+	ret = av7110_register(av7110);
+	if (ret < 0)
+		goto err_arm_thread_stop_10;
+
 	/* special case DVB-C: these cards have an analog tuner
 	   plus need some special handling, so we have separate
 	   saa7146_ext_vv data for these... */
 	ret = av7110_init_v4l(av7110);
-	
-	if (ret)
-		goto err3;
+	if (ret < 0)
+		goto err_av7110_unregister_11;
 
-	av7110->dvb_adapter->priv = av7110;
-	frontend_init(av7110);
+	av7110->dvb_adapter.priv = av7110;
+	ret = frontend_init(av7110);
+	if (ret < 0)
+		goto err_av7110_exit_v4l_12;
 
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+	av7110_ir_init();
+#endif
 	printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
-	av7110->device_initialized = 1;
 	av7110_num++;
-        return 0;
+out:
+	return ret;
 
-err3:
-	av7110->arm_rmmod = 1;
-	wake_up_interruptible(&av7110->arm_wait);
-	while (av7110->arm_thread)
-		msleep(1);
-err2:
+err_av7110_exit_v4l_12:
+	av7110_exit_v4l(av7110);
+err_av7110_unregister_11:
+	dvb_unregister(av7110);
+err_arm_thread_stop_10:
+	av7110_arm_sync(av7110);
+err_stop_arm_9:
+	/* Nothing to do. Rejoice. */
+err_av7110_ca_exit_8:
 	av7110_ca_exit(av7110);
+err_av7110_av_exit_7:
 	av7110_av_exit(av7110);
-err:
+err_iobuf_vfree_6:
+	vfree(av7110->iobuf);
+err_pci_free_5:
+	pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
+err_saa71466_vfree_4:
+	if (!av7110->grabbing)
+		saa7146_pgtable_free(pdev, &av7110->pt);
+err_i2c_del_3:
 	i2c_del_adapter(&av7110->i2c_adap);
-
-	dvb_unregister_adapter (av7110->dvb_adapter);
-
-	if (NULL != av7110->debi_virt)
-		pci_free_consistent(dev->pci, 8192, av7110->debi_virt, av7110->debi_bus);
-	if (NULL != av7110->iobuf)
-		vfree(av7110->iobuf);
-	if (NULL != av7110 ) {
-		kfree(av7110);
-	}
-
-	return ret;
+err_dvb_unregister_adapter_2:
+	dvb_unregister_adapter(&av7110->dvb_adapter);
+err_put_firmware_1:
+	put_firmware(av7110);
+err_kfree_0:
+	kfree(av7110);
+	goto out;
 }
 
-static int av7110_detach (struct saa7146_dev* saa)
+static int av7110_detach(struct saa7146_dev* saa)
 {
-	struct av7110 *av7110 = (struct av7110*)saa->ext_priv;
+	struct av7110 *av7110 = saa->ext_priv;
 	dprintk(4, "%p\n", av7110);
-	
-	if (!av7110->device_initialized )
-		return 0;
 
 	if (budgetpatch) {
 		/* Disable RPS1 */
@@ -2503,17 +2693,13 @@ static int av7110_detach (struct saa7146
 	}
 	av7110_exit_v4l(av7110);
 
-	av7110->arm_rmmod=1;
-	wake_up_interruptible(&av7110->arm_wait);
-
-	while (av7110->arm_thread)
-		msleep(1);
+	av7110_arm_sync(av7110);
 
 	tasklet_kill(&av7110->debi_tasklet);
 	tasklet_kill(&av7110->gpio_tasklet);
 
 	dvb_unregister(av7110);
-	
+
 	SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03);
 	SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03);
 
@@ -2526,21 +2712,21 @@ static int av7110_detach (struct saa7146
 
 	i2c_del_adapter(&av7110->i2c_adap);
 
-	dvb_unregister_adapter (av7110->dvb_adapter);
+	dvb_unregister_adapter (&av7110->dvb_adapter);
 
 	av7110_num--;
-#ifndef CONFIG_DVB_AV7110_FIRMWARE_FILE 
-	if (av7110->bin_fw)
-		vfree(av7110->bin_fw);
-#endif
-	kfree (av7110);
+
+	put_firmware(av7110);
+
+	kfree(av7110);
+
 	saa->ext_priv = NULL;
 
 	return 0;
 }
 
 
-static void av7110_irq(struct saa7146_dev* dev, u32 *isr) 
+static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
 {
 	struct av7110 *av7110 = dev->ext_priv;
 
@@ -2569,13 +2755,13 @@ static void av7110_irq(struct saa7146_de
 		 */
 		SAA7146_IER_DISABLE(av7110->dev, MASK_19);
 		SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
-		tasklet_schedule (&av7110->debi_tasklet);
+		tasklet_schedule(&av7110->debi_tasklet);
 	}
-	
+
 	if (*isr & MASK_03) {
 		//printk("av7110_irq: GPIO\n");
-		tasklet_schedule (&av7110->gpio_tasklet);
-}
+		tasklet_schedule(&av7110->gpio_tasklet);
+	}
 
 	if ((*isr & MASK_10) && budgetpatch)
 		tasklet_schedule(&av7110->vpe_tasklet);
@@ -2594,23 +2780,26 @@ MAKE_AV7110_INFO(ttt_1_X,    "Technotren
 MAKE_AV7110_INFO(ttc_1_X,    "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
 MAKE_AV7110_INFO(ttc_2_X,    "Technotrend/Hauppauge WinTV DVB-C rev2.X");
 MAKE_AV7110_INFO(tts_2_X,    "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
+MAKE_AV7110_INFO(tts_2_3,    "Technotrend/Hauppauge WinTV Nexus-S rev2.3");
 MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE");
+MAKE_AV7110_INFO(ttt,        "Technotrend/Hauppauge DVB-T");
 MAKE_AV7110_INFO(fsc,        "Fujitsu Siemens DVB-C");
 MAKE_AV7110_INFO(fss,        "Fujitsu Siemens DVB-S rev1.6");
 
 static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(fsc,       0x110a, 0x0000),
 	MAKE_EXTENSION_PCI(tts_1_X,   0x13c2, 0x0000),
 	MAKE_EXTENSION_PCI(ttt_1_X,   0x13c2, 0x0001),
 	MAKE_EXTENSION_PCI(ttc_2_X,   0x13c2, 0x0002),
 	MAKE_EXTENSION_PCI(tts_2_X,   0x13c2, 0x0003),
-	MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
-	MAKE_EXTENSION_PCI(fsc,       0x110a, 0x0000),
-	MAKE_EXTENSION_PCI(ttc_1_X,   0x13c2, 0x000a),
 	MAKE_EXTENSION_PCI(fss,       0x13c2, 0x0006),
+	MAKE_EXTENSION_PCI(ttt,       0x13c2, 0x0008),
+	MAKE_EXTENSION_PCI(ttc_1_X,   0x13c2, 0x000a),
+	MAKE_EXTENSION_PCI(tts_2_3,   0x13c2, 0x000e),
+	MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
 
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
-/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
 
 	{
@@ -2632,25 +2821,13 @@ static struct saa7146_extension av7110_e
 
 	.irq_mask	= MASK_19 | MASK_03 | MASK_10,
 	.irq_func	= av7110_irq,
-};	
+};
 
 
-static int __init av7110_init(void) 
+static int __init av7110_init(void)
 {
 	int retval;
 	retval = saa7146_register_extension(&av7110_extension);
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
-	if (retval)
-		goto failed_saa7146_register;
-	
-	retval = av7110_ir_init();
-	if (retval)
-		goto failed_av7110_ir_init;
-	return 0;
-failed_av7110_ir_init:
-	saa7146_unregister_extension(&av7110_extension);
-failed_saa7146_register:
-#endif
 	return retval;
 }
 
@@ -2670,4 +2847,3 @@ MODULE_DESCRIPTION("driver for the SAA71
 		   "Siemens, Technotrend, Hauppauge");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -31,6 +31,7 @@
 #include "tda8083.h"
 #include "sp8870.h"
 #include "stv0297.h"
+#include "l64781.h"
 
 #include <media/saa7146_vv.h>
 
@@ -49,38 +50,38 @@ extern int av7110_debug;
 enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
 
 struct av7110_p2t {
-        u8                pes[TS_SIZE];
-        u8                counter;
-        long int          pos;
-        int               frags;
-        struct dvb_demux_feed *feed;
+	u8		  pes[TS_SIZE];
+	u8		  counter;
+	long int	  pos;
+	int		  frags;
+	struct dvb_demux_feed *feed;
 };
 
 /* video MPEG decoder events: */
 /* (code copied from dvb_frontend.c, should maybe be factored out...) */
 #define MAX_VIDEO_EVENT 8
 struct dvb_video_events {
-	struct video_event        events[MAX_VIDEO_EVENT];
-	int                       eventw;
-	int                       eventr;
-	int                       overflow;
-	wait_queue_head_t         wait_queue;
-	spinlock_t                lock;
+	struct video_event	  events[MAX_VIDEO_EVENT];
+	int			  eventw;
+	int			  eventr;
+	int			  overflow;
+	wait_queue_head_t	  wait_queue;
+	spinlock_t		  lock;
 };
 
 
 /* place to store all the necessary device information */
 struct av7110 {
 
-        /* devices */
+	/* devices */
 
-        struct dvb_device       dvb_dev;
-        struct dvb_net               dvb_net;
+	struct dvb_device	dvb_dev;
+	struct dvb_net		dvb_net;
 
 	struct video_device	*v4l_dev;
 	struct video_device	*vbi_dev;
 
-        struct saa7146_dev	*dev;
+	struct saa7146_dev	*dev;
 
 	struct i2c_adapter	i2c_adap;
 
@@ -90,31 +91,31 @@ struct av7110 {
 	int			analog_tuner_flags;
 	int			current_input;
 	u32			current_freq;
-				
-	struct tasklet_struct   debi_tasklet;
-	struct tasklet_struct   gpio_tasklet;
 
-        int adac_type;         /* audio DAC type */
-#define DVB_ADAC_TI       0
+	struct tasklet_struct	debi_tasklet;
+	struct tasklet_struct	gpio_tasklet;
+
+	int adac_type;	       /* audio DAC type */
+#define DVB_ADAC_TI	  0
 #define DVB_ADAC_CRYSTAL  1
-#define DVB_ADAC_MSP      2
-#define DVB_ADAC_NONE    -1
+#define DVB_ADAC_MSP	  2
+#define DVB_ADAC_NONE	 -1
 
 
-        /* buffers */
+	/* buffers */
 
-        void                   *iobuf;   /* memory for all buffers */
-        struct dvb_ringbuffer        avout;   /* buffer for video or A/V mux */
+	void		       *iobuf;	 /* memory for all buffers */
+	struct dvb_ringbuffer	avout;   /* buffer for video or A/V mux */
 #define AVOUTLEN (128*1024)
-        struct dvb_ringbuffer        aout;    /* buffer for audio */
+	struct dvb_ringbuffer	aout;    /* buffer for audio */
 #define AOUTLEN (64*1024)
-        void                   *bmpbuf;
+	void		       *bmpbuf;
 #define BMPLEN (8*32768+1024)
 
-        /* bitmap buffers and states */
+	/* bitmap buffers and states */
 
-        int                     bmpp;
-        int                     bmplen;
+	int			bmpp;
+	int			bmplen;
 	volatile int		bmp_state;
 #define BMP_NONE     0
 #define BMP_LOADING  1
@@ -123,40 +124,40 @@ struct av7110 {
 	wait_queue_head_t	bmpq;
 
 
-        /* DEBI and polled command interface */
+	/* DEBI and polled command interface */
 
-        spinlock_t              debilock;
-        struct semaphore        dcomlock;
+	spinlock_t		debilock;
+	struct semaphore	dcomlock;
 	volatile int		debitype;
 	volatile int		debilen;
 
 
-        /* Recording and playback flags */
+	/* Recording and playback flags */
 
-        int                     rec_mode;
-        int                     playing;
+	int			rec_mode;
+	int			playing;
 #define RP_NONE  0
 #define RP_VIDEO 1
 #define RP_AUDIO 2
-#define RP_AV    3
+#define RP_AV	 3
 
 
-        /* OSD */
+	/* OSD */
 
-        int                     osdwin;      /* currently active window */
-        u16                     osdbpp[8];
+	int			osdwin;      /* currently active window */
+	u16			osdbpp[8];
 	struct semaphore	osd_sema;
 
-        /* CA */
+	/* CA */
 
-        ca_slot_info_t          ci_slot[2];
+	ca_slot_info_t		ci_slot[2];
 
-        int                     vidmode;
-        struct dmxdev		dmxdev;
-        struct dvb_demux             demux;
+	int			vidmode;
+	struct dmxdev		dmxdev;
+	struct dvb_demux	demux;
 
-        struct dmx_frontend	hw_frontend;
-        struct dmx_frontend	mem_frontend;
+	struct dmx_frontend	hw_frontend;
+	struct dmx_frontend	mem_frontend;
 
 	/* for budget mode demux1 */
 	struct dmxdev		dmxdev1;
@@ -170,69 +171,67 @@ struct av7110 {
 	struct saa7146_pgtable  pt;
 	struct tasklet_struct   vpe_tasklet;
 
-        int                     fe_synced; 
-        struct semaphore        pid_mutex;
+	int			fe_synced;
+	struct semaphore	pid_mutex;
 
-        int                     video_blank;
-        struct video_status     videostate;
-        int                     display_ar;
-        int                     trickmode;
+	int			video_blank;
+	struct video_status	videostate;
+	int			display_ar;
+	int			trickmode;
 #define TRICK_NONE   0
 #define TRICK_FAST   1
 #define TRICK_SLOW   2
 #define TRICK_FREEZE 3
-        struct audio_status      audiostate;
+	struct audio_status	audiostate;
 
-        struct dvb_demux_filter     *handle2filter[32];
-        struct av7110_p2t		p2t_filter[MAXFILT];
-        struct dvb_filter_pes2ts	p2t[2];
-        struct ipack			ipack[2];
-        u8                     *kbuf[2];
+	struct dvb_demux_filter *handle2filter[32];
+	struct av7110_p2t	 p2t_filter[MAXFILT];
+	struct dvb_filter_pes2ts p2t[2];
+	struct ipack		 ipack[2];
+	u8			*kbuf[2];
 
-        int sinfo;
-        int feeding;
+	int sinfo;
+	int feeding;
 
-        int arm_errors;
-        int registered;
+	int arm_errors;
+	int registered;
 
 
 	/* AV711X */
 
-        u32                 arm_fw;
-        u32                 arm_rtsl;
-        u32                 arm_vid;
-        u32                 arm_app;
-        u32                 avtype;
-        int                 arm_ready;
-        struct task_struct *arm_thread;
+	u32		    arm_fw;
+	u32		    arm_rtsl;
+	u32		    arm_vid;
+	u32		    arm_app;
+	u32		    avtype;
+	int		    arm_ready;
+	struct task_struct *arm_thread;
 	wait_queue_head_t   arm_wait;
-        u16                 arm_loops;
-        int                 arm_rmmod;
+	u16		    arm_loops;
+	int		    arm_rmmod;
+
+	void		   *debi_virt;
+	dma_addr_t	    debi_bus;
 
-        void               *debi_virt;
-        dma_addr_t          debi_bus;
+	u16		    pids[DMX_PES_OTHER];
 
-        u16                 pids[DMX_PES_OTHER];
-        
-        struct dvb_ringbuffer    ci_rbuffer;
-        struct dvb_ringbuffer    ci_wbuffer;
+	struct dvb_ringbuffer	 ci_rbuffer;
+	struct dvb_ringbuffer	 ci_wbuffer;
 
 	struct audio_mixer	mixer;
 
-        struct dvb_adapter       *dvb_adapter;
-        struct dvb_device        *video_dev;
-        struct dvb_device        *audio_dev;
-        struct dvb_device        *ca_dev;
-        struct dvb_device        *osd_dev;
+	struct dvb_adapter	 dvb_adapter;
+	struct dvb_device	 *video_dev;
+	struct dvb_device	 *audio_dev;
+	struct dvb_device	 *ca_dev;
+	struct dvb_device	 *osd_dev;
 
 	struct dvb_video_events  video_events;
-	video_size_t             video_size;
+	video_size_t		 video_size;
 
-        u32                 ir_config;
-	
-	/* firmware stuff */
-	unsigned int device_initialized;
+	u32		    ir_config;
 
+	/* firmware stuff */
 	unsigned char *bin_fw;
 	unsigned long size_fw;
 
@@ -260,7 +259,7 @@ extern void ChangePIDs(struct av7110 *av
 		       u16 subpid, u16 pcrpid);
 
 extern void av7110_register_irc_handler(void (*func)(u32));
-extern void av7110_unregister_irc_handler(void (*func)(u32)); 
+extern void av7110_unregister_irc_handler(void (*func)(u32));
 extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
 
 extern int av7110_ir_init (void);
@@ -275,7 +274,6 @@ extern void av7110_ir_exit (void);
 extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val);
 extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg);
 extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val);
-extern int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val);
 
 
 extern int av7110_init_analog_module(struct av7110 *av7110);
@@ -283,4 +281,3 @@ extern int av7110_init_v4l(struct av7110
 extern int av7110_exit_v4l(struct av7110 *av7110);
 
 #endif /* _AV7110_H_ */
-
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -1075,7 +1075,7 @@ static int dvb_video_ioctl(struct inode 
 		}
 		if (ret < 0)
 			break;
-		av7110->videostate.video_format = format;
+		av7110->videostate.display_format = format;
 		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
 				    1, (u16) val);
 		break;
@@ -1230,14 +1230,20 @@ static int dvb_audio_ioctl(struct inode 
 		switch(av7110->audiostate.channel_select) {
 		case AUDIO_STEREO:
 			audcom(av7110, AUDIO_CMD_STEREO);
+			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+				i2c_writereg(av7110, 0x20, 0x02, 0x49);
 			break;
 
 		case AUDIO_MONO_LEFT:
 			audcom(av7110, AUDIO_CMD_MONO_L);
+			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+				i2c_writereg(av7110, 0x20, 0x02, 0x4a);
 			break;
 
 		case AUDIO_MONO_RIGHT:
 			audcom(av7110, AUDIO_CMD_MONO_R);
+			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+				i2c_writereg(av7110, 0x20, 0x02, 0x45);
 			break;
 
 		default:
@@ -1409,10 +1415,10 @@ int av7110_av_register(struct av7110 *av
 	av7110->video_events.overflow = 0;
 	memset(&av7110->video_size, 0, sizeof (video_size_t));
 
-	dvb_register_device(av7110->dvb_adapter, &av7110->video_dev,
+	dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
 			    &dvbdev_video, av7110, DVB_DEVICE_VIDEO);
 
-	dvb_register_device(av7110->dvb_adapter, &av7110->audio_dev,
+	dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,
 			    &dvbdev_audio, av7110, DVB_DEVICE_AUDIO);
 
 	return 0;
@@ -1426,25 +1432,34 @@ void av7110_av_unregister(struct av7110 
 
 int av7110_av_init(struct av7110 *av7110)
 {
+	void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };
+	int i, ret;
+
 	av7110->vidmode = VIDEO_MODE_PAL;
 
-	av7110_ipack_init(&av7110->ipack[0], IPACKS, play_audio_cb);
-	av7110->ipack[0].data = (void *) av7110;
-	av7110_ipack_init(&av7110->ipack[1], IPACKS, play_video_cb);
-	av7110->ipack[1].data = (void *) av7110;
+	for (i = 0; i < 2; i++) {
+		struct ipack *ipack = av7110->ipack + i;
+
+		ret = av7110_ipack_init(ipack, IPACKS, play[i]);
+		if (ret < 0) {
+			if (i)
+				av7110_ipack_free(--ipack);
+			goto out;
+		}
+		ipack->data = av7110;
+	}
 
 	dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);
 	dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);
 
 	av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);
 	av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;
-
-	return 0;
+out:
+	return ret;
 }
 
-int av7110_av_exit(struct av7110 *av7110)
+void av7110_av_exit(struct av7110 *av7110)
 {
 	av7110_ipack_free(&av7110->ipack[0]);
 	av7110_ipack_free(&av7110->ipack[1]);
-	return 0;
 }
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -23,7 +23,7 @@ extern void av7110_p2t_write(u8 const *b
 extern int av7110_av_register(struct av7110 *av7110);
 extern void av7110_av_unregister(struct av7110 *av7110);
 extern int av7110_av_init(struct av7110 *av7110);
-extern int av7110_av_exit(struct av7110 *av7110);
+extern void av7110_av_exit(struct av7110 *av7110);
 
 
 #endif /* _AV7110_AV_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -91,8 +91,20 @@ void ci_get_data(struct dvb_ringbuffer *
 
 static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
 {
-	dvb_ringbuffer_init(cirbuf, vmalloc(size), size);
-	dvb_ringbuffer_init(ciwbuf, vmalloc(size), size);
+	struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p;
+	void *data;
+
+	for (p = tab; *p; p++) {
+		data = vmalloc(size);
+		if (!data) {
+			while (p-- != tab) {
+				vfree(p[0]->data);
+				p[0]->data = NULL;
+			}
+			return -ENOMEM;
+		}
+		dvb_ringbuffer_init(*p, data, size);
+	}
 	return 0;
 }
 
@@ -111,7 +123,7 @@ static void ci_ll_release(struct dvb_rin
 }
 
 static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
-		int slots, ca_slot_info_t *slot)
+		       int slots, ca_slot_info_t *slot)
 {
 	int i;
 	int len = 0;
@@ -358,7 +370,7 @@ static struct dvb_device dvbdev_ca = {
 
 int av7110_ca_register(struct av7110 *av7110)
 {
-	return dvb_register_device(av7110->dvb_adapter, &av7110->ca_dev,
+	return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
 				   &dvbdev_ca, av7110, DVB_DEVICE_CA);
 }
 
@@ -367,9 +379,9 @@ void av7110_ca_unregister(struct av7110 
 	dvb_unregister_device(av7110->ca_dev);
 }
 
-void av7110_ca_init(struct av7110* av7110)
+int av7110_ca_init(struct av7110* av7110)
 {
-	ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
+	return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
 }
 
 void av7110_ca_exit(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110_ca.h b/drivers/media/dvb/ttpci/av7110_ca.h
--- a/drivers/media/dvb/ttpci/av7110_ca.h
+++ b/drivers/media/dvb/ttpci/av7110_ca.h
@@ -8,7 +8,7 @@ extern void ci_get_data(struct dvb_ringb
 
 extern int av7110_ca_register(struct av7110 *av7110);
 extern void av7110_ca_unregister(struct av7110 *av7110);
-extern void av7110_ca_init(struct av7110* av7110);
+extern int av7110_ca_init(struct av7110* av7110);
 extern void av7110_ca_exit(struct av7110* av7110);
 
 #endif /* _AV7110_CA_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -104,7 +104,7 @@ u32 av7110_debiread(struct av7110 *av711
 
 
 /* av7110 ARM core boot stuff */
-
+#if 0
 void av7110_reset_arm(struct av7110 *av7110)
 {
 	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
@@ -124,7 +124,7 @@ void av7110_reset_arm(struct av7110 *av7
 	av7110->arm_ready = 1;
 	dprintk(1, "reset ARM\n");
 }
-
+#endif  /*  0  */
 
 static int waitdebi(struct av7110 *av7110, int adr, int state)
 {
@@ -335,7 +335,7 @@ int av7110_wait_msgstate(struct av7110 *
 	return 0;
 }
 
-int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 {
 	int i;
 	unsigned long start;
@@ -399,7 +399,7 @@ int __av7110_send_fw_cmd(struct av7110 *
 
 	if (type != NULL) {
 		/* non-immediate COMMAND type */
-	start = jiffies;
+		start = jiffies;
 		for (;;) {
 			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 			if (stat & flags[0]) {
@@ -412,8 +412,8 @@ int __av7110_send_fw_cmd(struct av7110 *
 			if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
 					__FUNCTION__, type);
-			return -1;
-		}
+				return -1;
+			}
 			msleep(1);
 		}
 	}
@@ -455,7 +455,7 @@ int __av7110_send_fw_cmd(struct av7110 *
 	return 0;
 }
 
-int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 {
 	int ret;
 
@@ -500,6 +500,7 @@ int av7110_fw_cmd(struct av7110 *av7110,
 	return ret;
 }
 
+#if 0
 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
 {
 	int i, ret;
@@ -521,6 +522,7 @@ int av7110_send_ci_cmd(struct av7110 *av
 		printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
 	return ret;
 }
+#endif  /*  0  */
 
 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
 		      int request_buf_len, u16 *reply_buf, int reply_buf_len)
@@ -593,7 +595,7 @@ int av7110_fw_request(struct av7110 *av7
 	return 0;
 }
 
-int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
+static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
 {
 	int ret;
 	ret = av7110_fw_request(av7110, &tag, 0, buf, length);
@@ -617,7 +619,7 @@ int av7110_firmversion(struct av7110 *av
 
 	if (av7110_fw_query(av7110, tag, buf, 16)) {
 		printk("dvb-ttpci: failed to boot firmware @ card %d\n",
-		       av7110->dvb_adapter->num);
+		       av7110->dvb_adapter.num);
 		return -EIO;
 	}
 
@@ -628,16 +630,16 @@ int av7110_firmversion(struct av7110 *av
 	av7110->avtype = (buf[8] << 16) + buf[9];
 
 	printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
-	       av7110->dvb_adapter->num, av7110->arm_fw,
+	       av7110->dvb_adapter.num, av7110->arm_fw,
 	       av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
 
 	/* print firmware capabilities */
 	if (FW_CI_LL_SUPPORT(av7110->arm_app))
 		printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
-		       av7110->dvb_adapter->num);
+		       av7110->dvb_adapter.num);
 	else
 		printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
-		       av7110->dvb_adapter->num);
+		       av7110->dvb_adapter.num);
 
 	return 0;
 }
@@ -889,11 +891,11 @@ static int BlitBitmap(struct av7110 *av7
 		       ret, av7110->bmp_state);
 		av7110->bmp_state = BMP_NONE;
 		return (ret == 0) ? -ETIMEDOUT : ret;
-		}
+	}
 
 	BUG_ON (av7110->bmp_state != BMP_LOADED);
 
-		return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
 }
 
 static inline int ReleaseBitmap(struct av7110 *av7110)
@@ -962,7 +964,7 @@ static int OSDSetPalette(struct av7110 *
 }
 
 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
-		       int x1, int y1, int inc, u8 __user *data)
+		       int x1, int y1, int inc, u8 __user * data)
 {
 	uint w, h, bpp, bpl, size, lpb, bnum, brest;
 	int i;
@@ -1061,9 +1063,9 @@ int av7110_osd_cmd(struct av7110 *av7110
 				    get_user(blend, colors + i * 4 + 3)) {
 					ret = -EFAULT;
 					goto out;
-		}
+				    }
 				OSDSetColor(av7110, dc->color + i, r, g, b, blend);
-		}
+			}
 		}
 		ret = 0;
 		goto out;
@@ -1162,9 +1164,9 @@ int av7110_osd_capability(struct av7110 
                         cap->val = 1000000;
                 else
                         cap->val = 92000;
-		return 0;
-	default:
-		return -EINVAL;
-	}
+                return 0;
+        default:
+                return -EINVAL;
+        }
 }
 #endif /* CONFIG_DVB_AV7110_OSD */
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -364,7 +364,6 @@ enum av7110_command_type {
 
 
 
-extern void av7110_reset_arm(struct av7110 *av7110);
 extern int av7110_bootarm(struct av7110 *av7110);
 extern int av7110_firmversion(struct av7110 *av7110);
 #define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
@@ -373,12 +372,8 @@ extern int av7110_firmversion(struct av7
 
 extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
 extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
-extern int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length);
-extern int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length);
-extern int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len);
 extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
 			     int request_buf_len, u16 *reply_buf, int reply_buf_len);
-extern int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* Buff, s16 length);
 
 
 /* DEBI (saa7146 data extension bus interface) access */
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/dvb/ttpci/av7110_ipack.c
@@ -21,9 +21,9 @@ void av7110_ipack_reset(struct ipack *p)
 
 
 int av7110_ipack_init(struct ipack *p, int size,
-		       void (*func)(u8 *buf, int size, void *priv))
+		      void (*func)(u8 *buf, int size, void *priv))
 {
-	if ( !(p->buf = vmalloc(size*sizeof(u8))) ){
+	if (!(p->buf = vmalloc(size*sizeof(u8)))) {
 		printk ("Couldn't allocate memory for ipack\n");
 		return -ENOMEM;
 	}
@@ -35,10 +35,9 @@ int av7110_ipack_init(struct ipack *p, i
 }
 
 
-void av7110_ipack_free(struct ipack * p)
+void av7110_ipack_free(struct ipack *p)
 {
-	if (p->buf)
-		vfree(p->buf);
+	vfree(p->buf);
 }
 
 
@@ -47,44 +46,44 @@ static void send_ipack(struct ipack *p)
 	int off;
 	struct dvb_audio_info ai;
 	int ac3_off = 0;
-	int streamid=0;
-	int nframes= 0;
-	int f=0;
+	int streamid = 0;
+	int nframes = 0;
+	int f = 0;
 
-	switch ( p->mpeg ){
-	case 2:		
+	switch (p->mpeg) {
+	case 2:
 		if (p->count < 10)
 			return;
 		p->buf[3] = p->cid;
 		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
 		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
-		if (p->repack_subids && p->cid == PRIVATE_STREAM1){
-			off = 9+p->buf[8];
+		if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
+			off = 9 + p->buf[8];
 			streamid = p->buf[off];
 			if ((streamid & 0xf8) == 0x80) {
 				ai.off = 0;
-				ac3_off = ((p->buf[off+2] << 8)| 
-					   p->buf[off+3]);
+				ac3_off = ((p->buf[off + 2] << 8)|
+					   p->buf[off + 3]);
 				if (ac3_off < p->count)
-					f=dvb_filter_get_ac3info(p->buf+off+3+ac3_off, 
-						      p->count-ac3_off, &ai,0);
-				if ( !f ){
-					nframes = (p->count-off-3-ac3_off)/ 
+					f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
+								   p->count - ac3_off, &ai, 0);
+				if (!f) {
+					nframes = (p->count - off - 3 - ac3_off) /
 						ai.framesize + 1;
 					p->buf[off + 2] = (ac3_off >> 8) & 0xff;
 					p->buf[off + 3] = (ac3_off) & 0xff;
-					p->buf[off+1] = nframes;
+					p->buf[off + 1] = nframes;
 					ac3_off +=  nframes * ai.framesize - p->count;
 				}
 			}
-		} 
+		}
 		p->func(p->buf, p->count, p->data);
-	
+
 		p->buf[6] = 0x80;
 		p->buf[7] = 0x00;
 		p->buf[8] = 0x00;
 		p->count = 9;
-		if (p->repack_subids && p->cid == PRIVATE_STREAM1 
+		if (p->repack_subids && p->cid == PRIVATE_STREAM1
 		    && (streamid & 0xf8) == 0x80) {
 			p->count += 4;
 			p->buf[9] = streamid;
@@ -101,7 +100,7 @@ static void send_ipack(struct ipack *p)
 		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
 		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
 		p->func(p->buf, p->count, p->data);
-	
+
 		p->buf[6] = 0x0f;
 		p->count = 7;
 		break;
@@ -111,9 +110,9 @@ static void send_ipack(struct ipack *p)
 
 void av7110_ipack_flush(struct ipack *p)
 {
-	if (p->plength != MMAX_PLENGTH-6 || p->found<=6)
+	if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
 		return;
-	p->plength = p->found-6;
+	p->plength = p->found - 6;
 	p->found = 0;
 	send_ipack(p);
 	av7110_ipack_reset(p);
@@ -122,9 +121,9 @@ void av7110_ipack_flush(struct ipack *p)
 
 static void write_ipack(struct ipack *p, const u8 *data, int count)
 {
-	u8 headr[3] = { 0x00, 0x00, 0x01} ;
+	u8 headr[3] = { 0x00, 0x00, 0x01 };
 
-	if (p->count < 6){
+	if (p->count < 6) {
 		memcpy(p->buf, headr, 3);
 		p->count = 6;
 	}
@@ -138,7 +137,7 @@ static void write_ipack(struct ipack *p,
 		p->count += rest;
 		send_ipack(p);
 		if (count - rest > 0)
-			write_ipack(p, data+rest, count-rest);
+			write_ipack(p, data + rest, count - rest);
 	}
 }
 
@@ -146,13 +145,13 @@ static void write_ipack(struct ipack *p,
 int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
 {
 	int l;
-	int c=0;
+	int c = 0;
 
 	while (c < count && (p->mpeg == 0 ||
 			     (p->mpeg == 1 && p->found < 7) ||
 			     (p->mpeg == 2 && p->found < 9))
-	       &&  (p->found < 5 || !p->done)){
-		switch ( p->found ){
+	       &&  (p->found < 5 || !p->done)) {
+		switch (p->found) {
 		case 0:
 		case 1:
 			if (buf[c] == 0x00)
@@ -172,7 +171,7 @@ int av7110_ipack_instant_repack (const u
 			break;
 		case 3:
 			p->cid = 0;
-			switch (buf[c]){
+			switch (buf[c]) {
 			case PROG_STREAM_MAP:
 			case PRIVATE_STREAM2:
 			case PROG_STREAM_DIR:
@@ -195,16 +194,16 @@ int av7110_ipack_instant_repack (const u
 				break;
 			}
 			break;
-			
+
 		case 4:
-			if (count-c > 1){
+			if (count-c > 1) {
 				p->plen[0] = buf[c];
 				c++;
 				p->plen[1] = buf[c];
 				c++;
-				p->found+=2;
-				p->plength=(p->plen[0]<<8)|p->plen[1];
- 			} else {
+				p->found += 2;
+				p->plength = (p->plen[0] << 8) | p->plen[1];
+			} else {
 				p->plen[0] = buf[c];
 				p->found++;
 				return count;
@@ -214,10 +213,10 @@ int av7110_ipack_instant_repack (const u
 			p->plen[1] = buf[c];
 			c++;
 			p->found++;
-			p->plength=(p->plen[0]<<8)|p->plen[1];
+			p->plength = (p->plen[0] << 8) | p->plen[1];
 			break;
 		case 6:
-			if (!p->done){
+			if (!p->done) {
 				p->flag1 = buf[c];
 				c++;
 				p->found++;
@@ -233,15 +232,15 @@ int av7110_ipack_instant_repack (const u
 			break;
 
 		case 7:
-			if ( !p->done && p->mpeg == 2) {
+			if (!p->done && p->mpeg == 2) {
 				p->flag2 = buf[c];
 				c++;
 				p->found++;
-			}	
+			}
 			break;
 
 		case 8:
-			if ( !p->done && p->mpeg == 2) {
+			if (!p->done && p->mpeg == 2) {
 				p->hlength = buf[c];
 				c++;
 				p->found++;
@@ -256,28 +255,26 @@ int av7110_ipack_instant_repack (const u
 	if (!p->plength)
 		p->plength = MMAX_PLENGTH - 6;
 
-	if ( p->done || ((p->mpeg == 2 && p->found >= 9) || 
-	     (p->mpeg == 1 && p->found >= 7)) ){
-		switch (p->cid){
-			
-		case AUDIO_STREAM_S ... AUDIO_STREAM_E:			
+	if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
+			(p->mpeg == 1 && p->found >= 7))) {
+		switch (p->cid) {
+		case AUDIO_STREAM_S ... AUDIO_STREAM_E:
 		case VIDEO_STREAM_S ... VIDEO_STREAM_E:
 		case PRIVATE_STREAM1:
-			
 			if (p->mpeg == 2 && p->found == 9) {
 				write_ipack(p, &p->flag1, 1);
 				write_ipack(p, &p->flag2, 1);
 				write_ipack(p, &p->hlength, 1);
 			}
 
-			if (p->mpeg == 1 && p->found == 7) 
+			if (p->mpeg == 1 && p->found == 7)
 				write_ipack(p, &p->flag1, 1);
-			
-			if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&  
+
+			if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
 			    p->found < 14) {
 				while (c < count && p->found < 14) {
-					p->pts[p->found-9] = buf[c];
-					write_ipack(p, buf+c, 1);
+					p->pts[p->found - 9] = buf[c];
+					write_ipack(p, buf + c, 1);
 					c++;
 					p->found++;
 				}
@@ -292,30 +289,30 @@ int av7110_ipack_instant_repack (const u
 					p->hlength = 1;
 				}
 
-				while (!p->which && c < count && 
+				while (!p->which && c < count &&
 				       p->check == 0xff){
 					p->check = buf[c];
-					write_ipack(p, buf+c, 1);
+					write_ipack(p, buf + c, 1);
 					c++;
 					p->found++;
 					p->hlength++;
 				}
-				
+
 				if (c == count)
 					return count;
-				
+
 				if ((p->check & 0xc0) == 0x40 && !p->which) {
 					p->check = buf[c];
-					write_ipack(p, buf+c, 1);
+					write_ipack(p, buf + c, 1);
 					c++;
 					p->found++;
 					p->hlength++;
-					
+
 					p->which = 1;
 					if (c == count)
 						return count;
 					p->check = buf[c];
-					write_ipack(p, buf+c, 1);
+					write_ipack(p, buf + c, 1);
 					c++;
 					p->found++;
 					p->hlength++;
@@ -323,10 +320,10 @@ int av7110_ipack_instant_repack (const u
 					if (c == count)
 						return count;
 				}
-				
-				if (p->which == 1){
+
+				if (p->which == 1) {
 					p->check = buf[c];
-					write_ipack(p, buf+c, 1);
+					write_ipack(p, buf + c, 1);
 					c++;
 					p->found++;
 					p->hlength++;
@@ -334,20 +331,20 @@ int av7110_ipack_instant_repack (const u
 					if (c == count)
 						return count;
 				}
-				
+
 				if ((p->check & 0x30) && p->check != 0xff) {
 					p->flag2 = (p->check & 0xf0) << 2;
 					p->pts[0] = p->check;
 					p->which = 3;
-				} 
-			
+				}
+
 				if (c == count)
 					return count;
 				if (p->which > 2){
 					if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
 						while (c < count && p->which < 7) {
 							p->pts[p->which - 2] = buf[c];
-							write_ipack(p,buf+c,1);
+							write_ipack(p, buf + c, 1);
 							c++;
 							p->found++;
 							p->which++;
@@ -357,9 +354,9 @@ int av7110_ipack_instant_repack (const u
 							return count;
 					} else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
 						while (c < count && p->which < 12) {
-							if (p->which< 7)
+							if (p->which < 7)
 								p->pts[p->which - 2] = buf[c];
-							write_ipack(p,buf+c,1);
+							write_ipack(p, buf + c, 1);
 							c++;
 							p->found++;
 							p->which++;
@@ -370,39 +367,37 @@ int av7110_ipack_instant_repack (const u
 					}
 					p->which = 2000;
 				}
-				
+
 			}
-			
-			while (c < count && p->found < p->plength+6){
-				l = count -c;
-				if (l+p->found > p->plength+6)
-					l = p->plength+6-p->found;
-				write_ipack(p, buf+c, l);
+
+			while (c < count && p->found < p->plength + 6) {
+				l = count - c;
+				if (l + p->found > p->plength + 6)
+					l = p->plength + 6 - p->found;
+				write_ipack(p, buf + c, l);
 				p->found += l;
 				c += l;
-			}	
-			
+			}
 			break;
 		}
 
 
-		if ( p->done ){
-			if( p->found + count - c < p->plength+6){
-				p->found += count-c;
+		if (p->done) {
+			if (p->found + count - c < p->plength + 6) {
+				p->found += count - c;
 				c = count;
 			} else {
-				c += p->plength+6 - p->found;
-				p->found = p->plength+6;
+				c += p->plength + 6 - p->found;
+				p->found = p->plength + 6;
 			}
 		}
 
-		if (p->plength && p->found == p->plength+6) {
+		if (p->plength && p->found == p->plength + 6) {
 			send_ipack(p);
 			av7110_ipack_reset(p);
 			if (c < count)
-				av7110_ipack_instant_repack(buf+c, count-c, p);
+				av7110_ipack_instant_repack(buf + c, count - c, p);
 		}
 	}
 	return count;
 }
-
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.h b/drivers/media/dvb/ttpci/av7110_ipack.h
--- a/drivers/media/dvb/ttpci/av7110_ipack.h
+++ b/drivers/media/dvb/ttpci/av7110_ipack.h
@@ -2,7 +2,7 @@
 #define _AV7110_IPACK_H_
 
 extern int av7110_ipack_init(struct ipack *p, int size,
-			      void (*func)(u8 *buf,  int size, void *priv));
+			     void (*func)(u8 *buf,  int size, void *priv));
 
 extern void av7110_ipack_reset(struct ipack *p);
 extern int  av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p);
@@ -10,4 +10,3 @@ extern void av7110_ipack_free(struct ipa
 extern void av7110_ipack_flush(struct ipack *p);
 
 #endif
-
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -10,8 +10,9 @@
 
 #define UP_TIMEOUT (HZ/4)
 
-/* enable ir debugging by or'ing av7110_debug with 16 */
+/* enable ir debugging by or'ing debug with 16 */
 
+static int ir_initialized;
 static struct input_dev input_dev;
 
 static u32 ir_config;
@@ -19,40 +20,40 @@ static u32 ir_config;
 static u16 key_map [256] = {
 	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
 	KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
-	KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0,
 	0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0,
-	KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, 
+	KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0,
 	KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW,
-	KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
-	0, 0, 0, 0, KEY_EPG, 0, 0, 0, 
+	0, 0, 0, 0, KEY_EPG, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR
 };
 
 
-static void av7110_emit_keyup (unsigned long data)
+static void av7110_emit_keyup(unsigned long data)
 {
-	if (!data || !test_bit (data, input_dev.key))
+	if (!data || !test_bit(data, input_dev.key))
 		return;
 
-	input_event (&input_dev, EV_KEY, data, !!0);
+	input_event(&input_dev, EV_KEY, data, !!0);
 }
 
 
 static struct timer_list keyup_timer = { .function = av7110_emit_keyup };
 
 
-static void av7110_emit_key (u32 ircom)
+static void av7110_emit_key(u32 ircom)
 {
 	u8 data;
 	u8 addr;
@@ -72,9 +73,9 @@ static void av7110_emit_key (u32 ircom)
 	}
 
 	keycode = key_map[data];
-	
+
 	dprintk(16, "#########%08x######### addr %i data 0x%02x (keycode %i)\n",
-		 ircom, addr, data, keycode);
+		ircom, addr, data, keycode);
 
 	/* check device address (if selected) */
 	if (ir_config & 0x4000)
@@ -86,41 +87,41 @@ static void av7110_emit_key (u32 ircom)
 		return;
 	}
 
-	if (ir_config & 0x0001) 
+	if (ir_config & 0x0001)
 		new_toggle = 0; /* RCMM */
 	else
 		new_toggle = (ircom & 0x800); /* RC5 */
 
-	if (timer_pending (&keyup_timer)) {
-		del_timer (&keyup_timer);
+	if (timer_pending(&keyup_timer)) {
+		del_timer(&keyup_timer);
 		if (keyup_timer.data != keycode || new_toggle != old_toggle) {
-			input_event (&input_dev, EV_KEY, keyup_timer.data, !!0);
-			input_event (&input_dev, EV_KEY, keycode, !0);
+			input_event(&input_dev, EV_KEY, keyup_timer.data, !!0);
+			input_event(&input_dev, EV_KEY, keycode, !0);
 		} else
-			input_event (&input_dev, EV_KEY, keycode, 2);
+			input_event(&input_dev, EV_KEY, keycode, 2);
 
 	} else
-	input_event (&input_dev, EV_KEY, keycode, !0);
+		input_event(&input_dev, EV_KEY, keycode, !0);
 
 	keyup_timer.expires = jiffies + UP_TIMEOUT;
 	keyup_timer.data = keycode;
 
-	add_timer (&keyup_timer);
+	add_timer(&keyup_timer);
 
 	old_toggle = new_toggle;
 }
 
-static void input_register_keys (void)
+static void input_register_keys(void)
 {
 	int i;
 
-	memset (input_dev.keybit, 0, sizeof(input_dev.keybit));
+	memset(input_dev.keybit, 0, sizeof(input_dev.keybit));
 
-	for (i=0; i<sizeof(key_map)/sizeof(key_map[0]); i++) {
+	for (i = 0; i < sizeof(key_map) / sizeof(key_map[0]); i++) {
 		if (key_map[i] > KEY_MAX)
 			key_map[i] = 0;
 		else if (key_map[i] > KEY_RESERVED)
-			set_bit (key_map[i], input_dev.keybit);
+			set_bit(key_map[i], input_dev.keybit);
 	}
 }
 
@@ -131,77 +132,79 @@ static void input_repeat_key(unsigned lo
 }
 
 
-static int av7110_ir_write_proc (struct file *file, const char __user *buffer,
-	                  unsigned long count, void *data)
+static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
+				unsigned long count, void *data)
 {
 	char *page;
 	int size = 4 + 256 * sizeof(u16);
 
 	if (count < size)
 		return -EINVAL;
-	
-	page = (char *)vmalloc(size);
+
+	page = (char *) vmalloc(size);
 	if (!page)
 		return -ENOMEM;
-	
+
 	if (copy_from_user(page, buffer, size)) {
 		vfree(page);
 		return -EFAULT;
 	}
 
-	memcpy (&ir_config, page, 4);
-	memcpy (&key_map, page + 4, 256 * sizeof(u16));
-
+	memcpy(&ir_config, page, 4);
+	memcpy(&key_map, page + 4, 256 * sizeof(u16));
 	vfree(page);
-
-	av7110_setup_irc_config (NULL, ir_config);
-
-	input_register_keys ();
-
+	av7110_setup_irc_config(NULL, ir_config);
+	input_register_keys();
 	return count;
 }
 
 
-int __init av7110_ir_init (void)
+int __init av7110_ir_init(void)
 {
 	static struct proc_dir_entry *e;
 
-	init_timer (&keyup_timer);
+	if (ir_initialized)
+		return 0;
+
+	init_timer(&keyup_timer);
 	keyup_timer.data = 0;
 
-        input_dev.name = "DVB on-card IR receiver";
+	input_dev.name = "DVB on-card IR receiver";
 
-        /**
-         *  enable keys
-         */
-        set_bit (EV_KEY, input_dev.evbit);
-        set_bit (EV_REP, input_dev.evbit);
+	/**
+	 *  enable keys
+	 */
+	set_bit(EV_KEY, input_dev.evbit);
+	set_bit(EV_REP, input_dev.evbit);
 
-	input_register_keys ();
+	input_register_keys();
 
 	input_register_device(&input_dev);
 	input_dev.timer.function = input_repeat_key;
 
-	av7110_setup_irc_config (NULL, 0x0001);
-	av7110_register_irc_handler (av7110_emit_key);
-
-	e = create_proc_entry ("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
+	av7110_setup_irc_config(NULL, 0x0001);
+	av7110_register_irc_handler(av7110_emit_key);
 
+	e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
 	if (e) {
 		e->write_proc = av7110_ir_write_proc;
 		e->size = 4 + 256 * sizeof(u16);
 	}
 
+	ir_initialized = 1;
 	return 0;
 }
 
 
-void __exit av7110_ir_exit (void)
+void __exit av7110_ir_exit(void)
 {
+	if (ir_initialized == 0)
+		return;
 	del_timer_sync(&keyup_timer);
-	remove_proc_entry ("av7110_ir", NULL);
-	av7110_unregister_irc_handler (av7110_emit_key);
+	remove_proc_entry("av7110_ir", NULL);
+	av7110_unregister_irc_handler(av7110_emit_key);
 	input_unregister_device(&input_dev);
+	ir_initialized = 0;
 }
 
 //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -46,13 +46,13 @@ int msp_writereg(struct av7110 *av7110, 
 
 	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
 		dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
-		       av7110->dvb_adapter->num, reg, val);
+		       av7110->dvb_adapter.num, reg, val);
 		return -EIO;
 	}
 	return 0;
 }
 
-int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
+static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
 {
 	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
 	u8 msg2[2];
@@ -63,15 +63,13 @@ int msp_readreg(struct av7110 *av7110, u
 
 	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
 		dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
-		       av7110->dvb_adapter->num, reg);
+		       av7110->dvb_adapter.num, reg);
 		return -EIO;
 	}
 	*val = (msg2[0] << 8) | msg2[1];
 	return 0;
 }
 
-
-
 static struct v4l2_input inputs[2] = {
 	{
 		.index		= 0,
@@ -554,13 +552,13 @@ int av7110_init_analog_module(struct av7
 		return -ENODEV;
 
 	printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
-		av7110->dvb_adapter->num);
+		av7110->dvb_adapter.num);
 	av7110->adac_type = DVB_ADAC_MSP;
 	msleep(100); // the probing above resets the msp...
 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
 	dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n",
-		av7110->dvb_adapter->num, version1, version2);
+		av7110->dvb_adapter.num, version1, version2);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
 	msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
@@ -598,7 +596,7 @@ int av7110_init_analog_module(struct av7
 		/* init the saa7113 */
 		while (*i != 0xff) {
 			if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
-				dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter->num);
+				dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
 				break;
 			}
 			i += 2;
@@ -728,11 +726,11 @@ static int std_callback(struct saa7146_d
 {
 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
 
-	if (std->id == V4L2_STD_PAL) {
+	if (std->id & V4L2_STD_PAL) {
 		av7110->vidmode = VIDEO_MODE_PAL;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
-	else if (std->id == V4L2_STD_NTSC) {
+	else if (std->id & V4L2_STD_NTSC) {
 		av7110->vidmode = VIDEO_MODE_NTSC;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1,34 +1,34 @@
 /*
  * budget-av.c: driver for the SAA7146 based Budget DVB cards
- *              with analog video in 
+ *              with analog video in
  *
- * Compiled from various sources by Michael Hunold <michael@mihu.de> 
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
  *
  * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
  *                               Andrew de Quincey <adq_dvb@lidskialf.net>
  *
  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  *
- * Copyright (C) 1999-2002 Ralph  Metzler 
+ * Copyright (C) 1999-2002 Ralph  Metzler
  *                       & Marcus Metzler for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  *
  * the project's page is at http://www.linuxtv.org/dvb/
  */
@@ -59,23 +59,26 @@ struct budget_av {
 	struct dvb_ca_en50221 ca;
 };
 
-int enable_ci = 0;
-
+/* GPIO CI Connections:
+ * 0 - Vcc/Reset (Reset is controlled by capacitor)
+ * 1 - Attribute Memory
+ * 2 - Card Enable (Active Low)
+ * 3 - Card Detect
+ */
 
 /****************************************************************************
  * INITIALIZATION
  ****************************************************************************/
 
-
-static u8 i2c_readreg (struct i2c_adapter *i2c, u8 id, u8 reg)
+static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg)
 {
-	u8 mm1[] = {0x00};
-	u8 mm2[] = {0x00};
+	u8 mm1[] = { 0x00 };
+	u8 mm2[] = { 0x00 };
 	struct i2c_msg msgs[2];
 
 	msgs[0].flags = 0;
 	msgs[1].flags = I2C_M_RD;
-	msgs[0].addr = msgs[1].addr=id/2;
+	msgs[0].addr = msgs[1].addr = id / 2;
 	mm1[0] = reg;
 	msgs[0].len = 1;
 	msgs[1].len = 1;
@@ -87,31 +90,30 @@ static u8 i2c_readreg (struct i2c_adapte
 	return mm2[0];
 }
 
-static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 *buf, u8 len)
+static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len)
 {
-        u8 mm1[] = { reg };
-        struct i2c_msg msgs[2] = {
-		{ .addr = id/2, .flags = 0, .buf = mm1, .len = 1 },
-		{ .addr = id/2, .flags = I2C_M_RD, .buf = buf, .len = len }
+	u8 mm1[] = { reg };
+	struct i2c_msg msgs[2] = {
+		{.addr = id / 2,.flags = 0,.buf = mm1,.len = 1},
+		{.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len}
 	};
 
-        if (i2c_transfer(i2c, msgs, 2) != 2)
+	if (i2c_transfer(i2c, msgs, 2) != 2)
 		return -EIO;
 
 	return 0;
 }
 
-
-static int i2c_writereg (struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
+static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
 {
-        u8 msg[2]={ reg, val }; 
-        struct i2c_msg msgs;
+	u8 msg[2] = { reg, val };
+	struct i2c_msg msgs;
 
-        msgs.flags=0;
-        msgs.addr=id/2;
-        msgs.len=2;
-        msgs.buf=msg;
-        return i2c_transfer(i2c, &msgs, 1);
+	msgs.flags = 0;
+	msgs.addr = id / 2;
+	msgs.len = 2;
+	msgs.buf = msg;
+	return i2c_transfer(i2c, &msgs, 1);
 }
 
 static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
@@ -123,6 +125,8 @@ static int ciintf_read_attribute_mem(str
 		return -EINVAL;
 
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	udelay(1);
+
 	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
 
 	if (result == -ETIMEDOUT)
@@ -139,6 +143,8 @@ static int ciintf_write_attribute_mem(st
 		return -EINVAL;
 
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	udelay(1);
+
 	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
 
 	if (result == -ETIMEDOUT)
@@ -155,6 +161,8 @@ static int ciintf_read_cam_control(struc
 		return -EINVAL;
 
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	udelay(1);
+
 	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
 
 	if (result == -ETIMEDOUT)
@@ -171,6 +179,8 @@ static int ciintf_write_cam_control(stru
 		return -EINVAL;
 
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	udelay(1);
+
 	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
 
 	if (result == -ETIMEDOUT)
@@ -182,19 +192,35 @@ static int ciintf_slot_reset(struct dvb_
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
+	int timeout = 50; // 5 seconds (4.4.6 Ready)
 
 	if (slot != 0)
 		return -EINVAL;
 
 	dprintk(1, "ciintf_slot_reset\n");
 
-	/* reset the card */
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
-	msleep(100);
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
-	msleep(2000);		/* horrendous I know, but its the only way to be absolutely sure without an IRQ line! */
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
+	msleep(2);
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */
+	msleep(20); /* 20 ms Vcc settling time */
+
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+
+	/* This should have been based on pin 16 READY of the pcmcia port,
+	 * but AFAICS it is not routed to the saa7146 */
+	while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
+		msleep(100);
+
+	if (timeout <= 0)
+	{
+		printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
+		saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
+		return -ETIMEDOUT;
+	}
 
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	return 0;
 }
 
@@ -231,7 +257,6 @@ static int ciintf_poll_slot_status(struc
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
-	int cam = 0;
 
 	if (slot != 0)
 		return -EINVAL;
@@ -239,15 +264,21 @@ static int ciintf_poll_slot_status(struc
 	if (!budget_av->slot_status) {
 		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
 		udelay(1);
-		cam = saa7146_read(saa, PSR) & MASK_06;
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
-
-		if (cam)
+		if (saa7146_read(saa, PSR) & MASK_06)
+		{
+			printk(KERN_INFO "budget-av: cam inserted\n");
 			budget_av->slot_status = 1;
+		}
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
 	} else if (!open) {
 		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
 		if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
+		{
+			printk(KERN_INFO "budget-av: cam ejected\n");
+			saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
+			saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
 			budget_av->slot_status = 0;
+		}
 	}
 
 	if (budget_av->slot_status == 1)
@@ -263,17 +294,11 @@ static int ciintf_init(struct budget_av 
 
 	memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
 
-	/* setup GPIOs */
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
 	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
 	saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
 
-	/* Reset the card */
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
-	msleep(50);
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
-	msleep(100);
-
 	/* Enable DEBI pins */
 	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
 
@@ -288,13 +313,14 @@ static int ciintf_init(struct budget_av 
 	budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
 	budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
 	budget_av->ca.data = budget_av;
-	if ((result = dvb_ca_en50221_init(budget_av->budget.dvb_adapter,
+
+	if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
 					  &budget_av->ca, 0, 1)) != 0) {
-		printk("budget_av: CI interface detected, but initialisation failed.\n");
+		printk(KERN_ERR "budget-av: ci initialisation failed.\n");
 		goto error;
 	}
-	// success!
-	printk("ciintf_init: CI interface initialised\n");
+
+	printk(KERN_INFO "budget-av: ci interface initialised.\n");
 	budget_av->budget.ci_present = 1;
 	return 0;
 
@@ -335,49 +361,51 @@ static const u8 saa7113_tab[] = {
 	0x0c, 0x40,
 	0x0d, 0x00,
 	0x0e, 0x01,
-        0x0f, 0x44,
+	0x0f, 0x44,
 
 	0x10, 0x08,
 	0x11, 0x0c,
 	0x12, 0x7b,
 	0x13, 0x00,
-        0x15, 0x00,  0x16, 0x00,  0x17, 0x00,
+	0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
 
-        0x57, 0xff, 
-        0x40, 0x82,  0x58, 0x00,  0x59, 0x54,  0x5a, 0x07,
-        0x5b, 0x83,  0x5e, 0x00,
-        0xff
+	0x57, 0xff,
+	0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,
+	0x5b, 0x83, 0x5e, 0x00,
+	0xff
 };
 
-
-static int saa7113_init (struct budget_av *budget_av)
+static int saa7113_init(struct budget_av *budget_av)
 {
 	struct budget *budget = &budget_av->budget;
+	struct saa7146_dev *saa = budget->dev;
 	const u8 *data = saa7113_tab;
 
-        if (i2c_writereg (&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
-                dprintk(1, "saa7113 not found on KNC card\n");
-                return -ENODEV;
-        }
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+	msleep(200);
+
+	if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
+		dprintk(1, "saa7113 not found on KNC card\n");
+		return -ENODEV;
+	}
 
-        dprintk(1, "saa7113 detected and initializing\n");
+	dprintk(1, "saa7113 detected and initializing\n");
 
 	while (*data != 0xff) {
-                i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data+1));
-                data += 2;
-        }
+		i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));
+		data += 2;
+	}
 
 	dprintk(1, "saa7113  status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
 
 	return 0;
 }
 
-
-static int saa7113_setinput (struct budget_av *budget_av, int input)
+static int saa7113_setinput(struct budget_av *budget_av, int input)
 {
 	struct budget *budget = &budget_av->budget;
 
-	if ( 1 != budget_av->has_saa7113 )
+	if (1 != budget_av->has_saa7113)
 		return -ENODEV;
 
 	if (input == 1) {
@@ -662,7 +690,7 @@ static int philips_tu1216_request_firmwa
 	return request_firmware(fw, name, &budget->dev->pci->dev);
 }
 
-struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_config = {
 
 	.demod_address = 0x8,
 	.invert = 1,
@@ -690,75 +718,90 @@ static u8 read_pwm(struct budget_av *bud
 	return pwm;
 }
 
+#define SUBID_DVBS_KNC1		0x0010
+#define SUBID_DVBS_KNC1_PLUS	0x0011
+#define SUBID_DVBS_TYPHOON	0x4f56
+#define SUBID_DVBS_CINERGY1200	0x1154
+
+#define SUBID_DVBC_KNC1		0x0020
+#define SUBID_DVBC_KNC1_PLUS	0x0021
+#define SUBID_DVBC_CINERGY1200	0x1156
+
+#define SUBID_DVBT_KNC1_PLUS	0x0031
+#define SUBID_DVBT_KNC1		0x0030
+#define SUBID_DVBT_CINERGY1200	0x1157
 
 static void frontend_init(struct budget_av *budget_av)
 {
-	switch (budget_av->budget.dev->pci->subsystem_device) {
-	case 0x4f56:		// Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059))
-		budget_av->budget.dvb_frontend =
-			stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap);
-		if (budget_av->budget.dvb_frontend != NULL) {
+	struct saa7146_dev * saa = budget_av->budget.dev;
+	struct dvb_frontend * fe = NULL;
+
+	switch (saa->pci->subsystem_device) {
+		case SUBID_DVBS_KNC1_PLUS:
+		case SUBID_DVBC_KNC1_PLUS:
+		case SUBID_DVBT_KNC1_PLUS:
+			// Enable / PowerON Frontend
+			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
 			break;
-		}
+	}
+
+	switch (saa->pci->subsystem_device) {
+
+	case SUBID_DVBS_KNC1:
+	case SUBID_DVBS_KNC1_PLUS:
+	case SUBID_DVBS_TYPHOON:
+		fe = stv0299_attach(&typhoon_config,
+				    &budget_av->budget.i2c_adap);
 		break;
 
-	case 0x0020:		// KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034))
-		budget_av->budget.dvb_frontend =
-			tda10021_attach(&philips_cu1216_config,
-					&budget_av->budget.i2c_adap, read_pwm(budget_av));
-		if (budget_av->budget.dvb_frontend != NULL) {
-			break;
-		}
+	case SUBID_DVBS_CINERGY1200:
+		fe = stv0299_attach(&cinergy_1200s_config,
+				    &budget_av->budget.i2c_adap);
 		break;
 
-	case 0x0030:		// KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt))
-		budget_av->budget.dvb_frontend =
-			tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
-		if (budget_av->budget.dvb_frontend != NULL) {
-			break;
-		}
+	case SUBID_DVBC_KNC1:
+	case SUBID_DVBC_KNC1_PLUS:
+		fe = tda10021_attach(&philips_cu1216_config,
+				     &budget_av->budget.i2c_adap,
+				     read_pwm(budget_av));
 		break;
 
-	case 0x1154:		// TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059))
-		budget_av->budget.dvb_frontend =
-			stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap);
-		if (budget_av->budget.dvb_frontend != NULL) {
-			break;
-		}
+	case SUBID_DVBT_KNC1:
+	case SUBID_DVBT_KNC1_PLUS:
+		fe = tda10046_attach(&philips_tu1216_config,
+				     &budget_av->budget.i2c_adap);
 		break;
 
-	case 0x1156:		// Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034))
-		budget_av->budget.dvb_frontend =
-			tda10021_attach(&philips_cu1216_config,
-					&budget_av->budget.i2c_adap, read_pwm(budget_av));
-		if (budget_av->budget.dvb_frontend) {
-			break;
-		}
+	case SUBID_DVBC_CINERGY1200:
+		fe = tda10021_attach(&philips_cu1216_config,
+				     &budget_av->budget.i2c_adap,
+				     read_pwm(budget_av));
 		break;
 
-	case 0x1157:		// Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt))
-		budget_av->budget.dvb_frontend =
-			tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
-		if (budget_av->budget.dvb_frontend) {
-			break;
-		}
+	case SUBID_DVBT_CINERGY1200:
+		fe = tda10046_attach(&philips_tu1216_config,
+				     &budget_av->budget.i2c_adap);
 		break;
 	}
 
-	if (budget_av->budget.dvb_frontend == NULL) {
-		printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
-		       budget_av->budget.dev->pci->vendor,
-		       budget_av->budget.dev->pci->device,
-		       budget_av->budget.dev->pci->subsystem_vendor,
-		       budget_av->budget.dev->pci->subsystem_device);
-	} else {
-		if (dvb_register_frontend
-		    (budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) {
-			printk("budget-av: Frontend registration failed!\n");
-			if (budget_av->budget.dvb_frontend->ops->release)
-				budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
-			budget_av->budget.dvb_frontend = NULL;
-		}
+	if (fe == NULL) {
+		printk(KERN_ERR "budget-av: A frontend driver was not found "
+				"for device %04x/%04x subsystem %04x/%04x\n",
+		       saa->pci->vendor,
+		       saa->pci->device,
+		       saa->pci->subsystem_vendor,
+		       saa->pci->subsystem_device);
+		return;
+	}
+
+	budget_av->budget.dvb_frontend = fe;
+
+	if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
+				  budget_av->budget.dvb_frontend)) {
+		printk(KERN_ERR "budget-av: Frontend registration failed!\n");
+		if (budget_av->budget.dvb_frontend->ops->release)
+			budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+		budget_av->budget.dvb_frontend = NULL;
 	}
 }
 
@@ -773,19 +816,19 @@ static void budget_av_irq(struct saa7146
 		ttpci_budget_irq10_handler(dev, isr);
 }
 
-static int budget_av_detach (struct saa7146_dev *dev)
+static int budget_av_detach(struct saa7146_dev *dev)
 {
-	struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
+	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
 	int err;
 
 	dprintk(2, "dev: %p\n", dev);
 
-	if ( 1 == budget_av->has_saa7113 ) {
-	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
+	if (1 == budget_av->has_saa7113) {
+		saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
 
 		msleep(200);
 
-	saa7146_unregister_device (&budget_av->vd, dev);
+		saa7146_unregister_device(&budget_av->vd, dev);
 	}
 
 	if (budget_av->budget.ci_present)
@@ -793,9 +836,9 @@ static int budget_av_detach (struct saa7
 
 	if (budget_av->budget.dvb_frontend != NULL)
 		dvb_unregister_frontend(budget_av->budget.dvb_frontend);
-	err = ttpci_budget_deinit (&budget_av->budget);
+	err = ttpci_budget_deinit(&budget_av->budget);
 
-	kfree (budget_av);
+	kfree(budget_av);
 
 	return err;
 }
@@ -815,6 +858,7 @@ static int budget_av_attach(struct saa71
 
 	memset(budget_av, 0, sizeof(struct budget_av));
 
+	budget_av->has_saa7113 = 0;
 	budget_av->budget.ci_present = 0;
 
 	dev->ext_priv = budget_av;
@@ -829,101 +873,91 @@ static int budget_av_attach(struct saa71
 	saa7146_write(dev, DD1_INIT, 0x07000600);
 	saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
 
-	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
-	msleep(500);
-
-	if ( 0 == saa7113_init(budget_av) ) {
+	if (saa7113_init(budget_av) == 0) {
 		budget_av->has_saa7113 = 1;
 
-	if ( 0 != saa7146_vv_init(dev,&vv_data)) {
-		/* fixme: proper cleanup here */
-		ERR(("cannot init vv subsystem.\n"));
-		return err;
-	}
+		if (0 != saa7146_vv_init(dev, &vv_data)) {
+			/* fixme: proper cleanup here */
+			ERR(("cannot init vv subsystem.\n"));
+			return err;
+		}
 
 		if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
-		/* fixme: proper cleanup here */
-		ERR(("cannot register capture v4l2 device.\n"));
-		return err;
-	}
+			/* fixme: proper cleanup here */
+			ERR(("cannot register capture v4l2 device.\n"));
+			return err;
+		}
 
-	/* beware: this modifies dev->vv ... */
-	saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
-					SAA7146_HPS_SYNC_PORT_A);
+		/* beware: this modifies dev->vv ... */
+		saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
+						SAA7146_HPS_SYNC_PORT_A);
 
-	saa7113_setinput (budget_av, 0);
+		saa7113_setinput(budget_av, 0);
 	} else {
-		budget_av->has_saa7113 = 0;
-
-	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
+		ciintf_init(budget_av);
 	}
 
 	/* fixme: find some sane values here... */
 	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 
-	mac = budget_av->budget.dvb_adapter->proposed_mac;
+	mac = budget_av->budget.dvb_adapter.proposed_mac;
 	if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
-		printk("KNC1-%d: Could not read MAC from KNC1 card\n",
-				budget_av->budget.dvb_adapter->num);
+		printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",
+		       budget_av->budget.dvb_adapter.num);
 		memset(mac, 0, 6);
 	} else {
-		printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-				budget_av->budget.dvb_adapter->num,
-				mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-}
+		printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+		       budget_av->budget.dvb_adapter.num,
+		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	}
 
-	budget_av->budget.dvb_adapter->priv = budget_av;
+	budget_av->budget.dvb_adapter.priv = budget_av;
 	frontend_init(budget_av);
 
-	if (enable_ci)
-		ciintf_init(budget_av);
-
 	return 0;
 }
 
 #define KNC1_INPUTS 2
 static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
-	{ 0,	"Composite", V4L2_INPUT_TYPE_TUNER,  1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, 
-	{ 1,	"S-Video",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+	{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+	{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
 };
 
-
 static struct saa7146_extension_ioctls ioctls[] = {
-	{ VIDIOC_ENUMINPUT, 	SAA7146_EXCLUSIVE },
-	{ VIDIOC_G_INPUT,	SAA7146_EXCLUSIVE },
-	{ VIDIOC_S_INPUT,	SAA7146_EXCLUSIVE },
-	{ 0,			0 }
+	{VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
+	{VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
+	{VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
+	{0, 0}
 };
 
-
-static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
+static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
 	struct saa7146_dev *dev = fh->dev;
-	struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
+	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
 
-	switch(cmd) {
+	switch (cmd) {
 	case VIDIOC_ENUMINPUT:{
 		struct v4l2_input *i = arg;
-		
+
 		dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
-		if( i->index < 0 || i->index >= KNC1_INPUTS) {
+		if (i->index < 0 || i->index >= KNC1_INPUTS) {
 			return -EINVAL;
 		}
 		memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
 		return 0;
 	}
 	case VIDIOC_G_INPUT:{
-		int *input = (int *)arg;
+		int *input = (int *) arg;
 
 		*input = budget_av->cur_input;
 
 		dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
-		return 0;		
-	}	
+		return 0;
+	}
 	case VIDIOC_S_INPUT:{
-		int input = *(int *)arg;
+		int input = *(int *) arg;
 		dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
-		return saa7113_setinput (budget_av, input);
+		return saa7113_setinput(budget_av, input);
 	}
 	default:
 		return -ENOIOCTLCMD;
@@ -933,24 +967,24 @@ static int av_ioctl(struct saa7146_fh *f
 
 static struct saa7146_standard standard[] = {
 	{.name = "PAL",.id = V4L2_STD_PAL,
-		.v_offset	= 0x17,	.v_field 	= 288,
-		.h_offset	= 0x14,	.h_pixels 	= 680,  	      
+	 .v_offset = 0x17,.v_field = 288,
+	 .h_offset = 0x14,.h_pixels = 680,
 	 .v_max_out = 576,.h_max_out = 768 },
 
 	{.name = "NTSC",.id = V4L2_STD_NTSC,
-		.v_offset	= 0x16,	.v_field 	= 240,
-		.h_offset	= 0x06,	.h_pixels 	= 708,
+	 .v_offset = 0x16,.v_field = 240,
+	 .h_offset = 0x06,.h_pixels = 708,
 	 .v_max_out = 480,.h_max_out = 640, },
 };
 
 static struct saa7146_ext_vv vv_data = {
-	.inputs		= 2,
-	.capabilities	= 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
-	.flags		= 0,
-	.stds		= &standard[0],
-	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
-	.ioctls		= &ioctls[0],
-	.ioctl		= av_ioctl,
+	.inputs = 2,
+	.capabilities = 0,	// perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
+	.flags = 0,
+	.stds = &standard[0],
+	.num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
+	.ioctls = &ioctls[0],
+	.ioctl = av_ioctl,
 };
 
 static struct saa7146_extension budget_extension;
@@ -958,44 +992,51 @@ static struct saa7146_extension budget_e
 MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
+MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
+MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
 MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
 MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
 MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 
-static struct pci_device_id pci_tbl [] = {
+static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
+	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
+	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
 	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
+	MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
 	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
 	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
 	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
 	{
-		.vendor    = 0,
+	 .vendor = 0,
 	}
 };
 
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
-	.name		= "budget dvb /w video in\0",
-	.pci_tbl	= pci_tbl,
+	.name = "budget dvb /w video in\0",
+	.pci_tbl = pci_tbl,
 
-	.module		= THIS_MODULE,
-	.attach		= budget_av_attach,
-	.detach		= budget_av_detach,
+	.module = THIS_MODULE,
+	.attach = budget_av_attach,
+	.detach = budget_av_detach,
 
-	.irq_mask	= MASK_10,
+	.irq_mask = MASK_10,
 	.irq_func = budget_av_irq,
-};	
+};
 
-static int __init budget_av_init(void) 
+static int __init budget_av_init(void)
 {
 	return saa7146_register_extension(&budget_extension);
 }
 
 static void __exit budget_av_exit(void)
 {
-	saa7146_unregister_extension(&budget_extension); 
+	saa7146_unregister_extension(&budget_extension);
 }
 
 module_init(budget_av_init);
@@ -1005,5 +1046,3 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
 		   "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");
-module_param_named(enable_ci, enable_ci, int, 0644);
-MODULE_PARM_DESC(enable_ci, "Turn on/off CI module (default:off).");
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -1,7 +1,7 @@
 /*
- * budget-ci.c: driver for the SAA7146 based Budget DVB cards 
+ * budget-ci.c: driver for the SAA7146 based Budget DVB cards
  *
- * Compiled from various sources by Michael Hunold <michael@mihu.de> 
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
  *
  *     msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
  *     partially based on the Siemens DVB driver by Ralph+Marcus Metzler
@@ -12,19 +12,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.
- * 
+ *
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  *
  * the project's page is at http://www.linuxtv.org/dvb/
  */
@@ -76,57 +76,56 @@ struct budget_ci {
    Hauppauge (from NOVA-CI-s box product)
    i've taken a "middle of the road" approach and note the differences
 */
-static  u16 key_map[64] = {
+static u16 key_map[64] = {
 	/* 0x0X */
 	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
 	KEY_9,
 	KEY_ENTER,
 	KEY_RED,
-	KEY_POWER,              /* RADIO on Hauppauge */
+	KEY_POWER,		/* RADIO on Hauppauge */
 	KEY_MUTE,
 	0,
-	KEY_A,                  /* TV on Hauppauge */
+	KEY_A,			/* TV on Hauppauge */
 	/* 0x1X */
 	KEY_VOLUMEUP, KEY_VOLUMEDOWN,
 	0, 0,
 	KEY_B,
 	0, 0, 0, 0, 0, 0, 0,
 	KEY_UP, KEY_DOWN,
-	KEY_OPTION,             /* RESERVED on Hauppauge */
+	KEY_OPTION,		/* RESERVED on Hauppauge */
 	KEY_BREAK,
 	/* 0x2X */
 	KEY_CHANNELUP, KEY_CHANNELDOWN,
-	KEY_PREVIOUS,           /* Prev. Ch on Zenith, SOURCE on Hauppauge */
+	KEY_PREVIOUS,		/* Prev. Ch on Zenith, SOURCE on Hauppauge */
 	0, KEY_RESTART, KEY_OK,
-	KEY_CYCLEWINDOWS,       /* MINIMIZE on Hauppauge */
+	KEY_CYCLEWINDOWS,	/* MINIMIZE on Hauppauge */
 	0,
-	KEY_ENTER,              /* VCR mode on Zenith */
+	KEY_ENTER,		/* VCR mode on Zenith */
 	KEY_PAUSE,
 	0,
 	KEY_RIGHT, KEY_LEFT,
 	0,
-	KEY_MENU,               /* FULL SCREEN on Hauppauge */
+	KEY_MENU,		/* FULL SCREEN on Hauppauge */
 	0,
 	/* 0x3X */
 	KEY_SLOW,
-	KEY_PREVIOUS,           /* VCR mode on Zenith */
+	KEY_PREVIOUS,		/* VCR mode on Zenith */
 	KEY_REWIND,
 	0,
 	KEY_FASTFORWARD,
 	KEY_PLAY, KEY_STOP,
 	KEY_RECORD,
-	KEY_TUNER,              /* TV/VCR on Zenith */
+	KEY_TUNER,		/* TV/VCR on Zenith */
 	0,
 	KEY_C,
 	0,
 	KEY_EXIT,
 	KEY_POWER2,
-	KEY_TUNER,              /* VCR mode on Zenith */
+	KEY_TUNER,		/* VCR mode on Zenith */
 	0,
 };
 
-
-static void msp430_ir_debounce (unsigned long data)
+static void msp430_ir_debounce(unsigned long data)
 {
 	struct input_dev *dev = (struct input_dev *) data;
 
@@ -138,34 +137,32 @@ static void msp430_ir_debounce (unsigned
 	dev->rep[0] = 0;
 	dev->timer.expires = jiffies + HZ * 350 / 1000;
 	add_timer(&dev->timer);
-	input_event(dev, EV_KEY, key_map[dev->repeat_key], 2);  /* REPEAT */
+	input_event(dev, EV_KEY, key_map[dev->repeat_key], 2);	/* REPEAT */
 }
 
-
-
-static void msp430_ir_interrupt (unsigned long data)
+static void msp430_ir_interrupt(unsigned long data)
 {
-	struct budget_ci *budget_ci = (struct budget_ci*) data;
+	struct budget_ci *budget_ci = (struct budget_ci *) data;
 	struct input_dev *dev = &budget_ci->input_dev;
 	unsigned int code =
 		ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
 
 	if (code & 0x40) {
-	        code &= 0x3f;
+		code &= 0x3f;
 
-        	if (timer_pending(&dev->timer)) {
-                	if (code == dev->repeat_key) {
-                        	++dev->rep[0];
-	                        return;
-        	        }
-                	del_timer(&dev->timer);
-		        input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
+		if (timer_pending(&dev->timer)) {
+			if (code == dev->repeat_key) {
+				++dev->rep[0];
+				return;
+			}
+			del_timer(&dev->timer);
+			input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
 		}
 
 		if (!key_map[code]) {
 			printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
-		        return;
-       		}
+			return;
+		}
 
 		/* initialize debounce and repeat */
 		dev->repeat_key = code;
@@ -174,25 +171,24 @@ static void msp430_ir_interrupt (unsigne
 		/* 350 milliseconds */
 		dev->timer.expires = jiffies + HZ * 350 / 1000;
 		/* MAKE */
-        	input_event(dev, EV_KEY, key_map[code], !0);
+		input_event(dev, EV_KEY, key_map[code], !0);
 		add_timer(&dev->timer);
 	}
 }
 
-
-static int msp430_ir_init (struct budget_ci *budget_ci)
+static int msp430_ir_init(struct budget_ci *budget_ci)
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int i;
 
 	memset(&budget_ci->input_dev, 0, sizeof(struct input_dev));
 
-	sprintf (budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
+	sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
 	budget_ci->input_dev.name = budget_ci->ir_dev_name;
 
 	set_bit(EV_KEY, budget_ci->input_dev.evbit);
 
-	for (i=0; i<sizeof(key_map)/sizeof(*key_map); i++)
+	for (i = 0; i < sizeof(key_map) / sizeof(*key_map); i++)
 		if (key_map[i])
 			set_bit(key_map[i], budget_ci->input_dev.keybit);
 
@@ -202,13 +198,12 @@ static int msp430_ir_init (struct budget
 
 	saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
 
-	saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); 
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
 
 	return 0;
 }
 
-
-static void msp430_ir_deinit (struct budget_ci *budget_ci)
+static void msp430_ir_deinit(struct budget_ci *budget_ci)
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	struct input_dev *dev = &budget_ci->input_dev;
@@ -224,7 +219,7 @@ static void msp430_ir_deinit (struct bud
 
 static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 
 	if (slot != 0)
 		return -EINVAL;
@@ -235,7 +230,7 @@ static int ciintf_read_attribute_mem(str
 
 static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 
 	if (slot != 0)
 		return -EINVAL;
@@ -246,7 +241,7 @@ static int ciintf_write_attribute_mem(st
 
 static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 
 	if (slot != 0)
 		return -EINVAL;
@@ -257,7 +252,7 @@ static int ciintf_read_cam_control(struc
 
 static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 
 	if (slot != 0)
 		return -EINVAL;
@@ -268,7 +263,7 @@ static int ciintf_write_cam_control(stru
 
 static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 
 	if (slot != 0)
@@ -283,13 +278,13 @@ static int ciintf_slot_reset(struct dvb_
 			       CICONTROL_RESET, 1, 0);
 
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
-   	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	return 0;
 }
 
 static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 {
-   	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 
 	if (slot != 0)
@@ -302,7 +297,7 @@ static int ciintf_slot_shutdown(struct d
 
 static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
 {
-	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int tmp;
 
@@ -315,14 +310,13 @@ static int ciintf_slot_ts_enable(struct 
 	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
 			       tmp | CICONTROL_ENABLETS, 1, 0);
 
-   	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
 	return 0;
 }
 
-
-static void ciintf_interrupt (unsigned long data)
+static void ciintf_interrupt(unsigned long data)
 {
-	struct budget_ci *budget_ci = (struct budget_ci*) data;
+	struct budget_ci *budget_ci = (struct budget_ci *) data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	unsigned int flags;
 
@@ -335,7 +329,7 @@ static void ciintf_interrupt (unsigned l
 	if (flags & CICONTROL_CAMDETECT) {
 
 		// GPIO should be set to trigger on falling edge if a CAM is present
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
 
 		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
 			// CAM insertion IRQ
@@ -359,7 +353,7 @@ static void ciintf_interrupt (unsigned l
 		// the CAM might not actually be ready yet.
 		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
 
-	   	// generate a CAM removal IRQ if we haven't already
+		// generate a CAM removal IRQ if we haven't already
 		if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
 			// CAM removal IRQ
 			budget_ci->slot_status = SLOTSTATUS_NONE;
@@ -369,7 +363,7 @@ static void ciintf_interrupt (unsigned l
 	}
 }
 
-static int ciintf_init(struct budget_ci* budget_ci)
+static int ciintf_init(struct budget_ci *budget_ci)
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int flags;
@@ -401,7 +395,7 @@ static int ciintf_init(struct budget_ci*
 	budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
 	budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
 	budget_ci->ca.data = budget_ci;
-	if ((result = dvb_ca_en50221_init(budget_ci->budget.dvb_adapter,
+	if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
 					  &budget_ci->ca,
 					  DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
 					  DVB_CA_EN50221_FLAG_IRQ_FR |
@@ -409,11 +403,10 @@ static int ciintf_init(struct budget_ci*
 		printk("budget_ci: CI interface detected, but initialisation failed.\n");
 		goto error;
 	}
-
 	// Setup CI slot IRQ
-	tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+	tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
 	if (budget_ci->slot_status != SLOTSTATUS_NONE) {
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
 	} else {
 		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
 	}
@@ -438,7 +431,7 @@ error:
 	return result;
 }
 
-static void ciintf_deinit(struct budget_ci* budget_ci)
+static void ciintf_deinit(struct budget_ci *budget_ci)
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 
@@ -461,20 +454,20 @@ static void ciintf_deinit(struct budget_
 	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
 }
 
-static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
+static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
 {
-        struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
+	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
 
 	dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
 
-        if (*isr & MASK_06)
-                tasklet_schedule (&budget_ci->msp430_irq_tasklet);
+	if (*isr & MASK_06)
+		tasklet_schedule(&budget_ci->msp430_irq_tasklet);
 
-        if (*isr & MASK_10)
-		ttpci_budget_irq10_handler (dev, isr);
+	if (*isr & MASK_10)
+		ttpci_budget_irq10_handler(dev, isr);
 
 	if ((*isr & MASK_03) && (budget_ci->budget.ci_present))
-		tasklet_schedule (&budget_ci->ciintf_irq_tasklet);
+		tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
 }
 
 
@@ -888,7 +881,7 @@ static void frontend_init(struct budget_
 		       budget_ci->budget.dev->pci->subsystem_device);
 	} else {
 		if (dvb_register_frontend
-		    (budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+		    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
 			printk("budget-ci: Frontend registration failed!\n");
 			if (budget_ci->budget.dvb_frontend->ops->release)
 				budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
@@ -902,7 +895,7 @@ static int budget_ci_attach(struct saa71
 	struct budget_ci *budget_ci;
 	int err;
 
-	if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL)))
+	if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
 		return -ENOMEM;
 
 	dprintk(2, "budget_ci: %p\n", budget_ci);
@@ -912,28 +905,26 @@ static int budget_ci_attach(struct saa71
 	dev->ext_priv = budget_ci;
 
 	if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
-		kfree (budget_ci);
+		kfree(budget_ci);
 		return err;
 	}
 
-	tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
-		      (unsigned long) budget_ci);
+	tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
+		     (unsigned long) budget_ci);
 
-	msp430_ir_init (budget_ci);
+	msp430_ir_init(budget_ci);
 
 	ciintf_init(budget_ci);
 
-	budget_ci->budget.dvb_adapter->priv = budget_ci;
+	budget_ci->budget.dvb_adapter.priv = budget_ci;
 	frontend_init(budget_ci);
 
 	return 0;
 }
 
-
-
-static int budget_ci_detach (struct saa7146_dev* dev)
+static int budget_ci_detach(struct saa7146_dev *dev)
 {
-	struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
+	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int err;
 
@@ -941,60 +932,57 @@ static int budget_ci_detach (struct saa7
 		ciintf_deinit(budget_ci);
 	if (budget_ci->budget.dvb_frontend)
 		dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
-	err = ttpci_budget_deinit (&budget_ci->budget);
+	err = ttpci_budget_deinit(&budget_ci->budget);
 
-	tasklet_kill (&budget_ci->msp430_irq_tasklet);
+	tasklet_kill(&budget_ci->msp430_irq_tasklet);
 
-	msp430_ir_deinit (budget_ci);
+	msp430_ir_deinit(budget_ci);
 
 	// disable frontend and CI interface
 	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
 
-	kfree (budget_ci);
+	kfree(budget_ci);
 
 	return err;
 }
 
+static struct saa7146_extension budget_extension;
 
-
-static struct saa7146_extension budget_extension; 
-
-MAKE_BUDGET_INFO(ttbci,	"TT-Budget/WinTV-NOVA-CI PCI",	BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(ttbt2,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
+MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
-	MAKE_EXTENSION_PCI(ttbt2,  0x13c2, 0x1011),
+	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
 	{
-		.vendor    = 0,
-	}
+	 .vendor = 0,
+	 }
 };
 
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
-	.name		= "budget_ci dvb\0",
-	.flags	 	= 0,
-
-	.module		= THIS_MODULE,
-	.pci_tbl	= &pci_tbl[0],
-	.attach		= budget_ci_attach,
-	.detach		= budget_ci_detach,
+	.name = "budget_ci dvb\0",
+	.flags = 0,
 
-	.irq_mask	= MASK_03 | MASK_06 | MASK_10,
-	.irq_func	= budget_ci_irq,
-};	
+	.module = THIS_MODULE,
+	.pci_tbl = &pci_tbl[0],
+	.attach = budget_ci_attach,
+	.detach = budget_ci_detach,
 
+	.irq_mask = MASK_03 | MASK_06 | MASK_10,
+	.irq_func = budget_ci_irq,
+};
 
-static int __init budget_ci_init(void) 
+static int __init budget_ci_init(void)
 {
 	return saa7146_register_extension(&budget_extension);
 }
 
 static void __exit budget_ci_exit(void)
 {
-	saa7146_unregister_extension(&budget_extension); 
+	saa7146_unregister_extension(&budget_extension);
 }
 
 module_init(budget_ci_init);
@@ -1005,4 +993,3 @@ MODULE_AUTHOR("Michael Hunold, Jack Thom
 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
 		   "budget PCI DVB cards w/ CI-module produced by "
 		   "Siemens, Technotrend, Hauppauge");
-
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -40,9 +40,8 @@
 #include "ttpci-eeprom.h"
 
 int budget_debug;
-
 module_param_named(debug, budget_debug, int, 0644);
-MODULE_PARM_DESC(budget_debug, "Turn on/off budget debugging (default:off).");
+MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
 
 /****************************************************************************
  * TT budget / WinTV Nova
@@ -52,32 +51,31 @@ static int stop_ts_capture(struct budget
 {
 	dprintk(2, "budget: %p\n", budget);
 
-        if (--budget->feeding)
-                return budget->feeding;
+	if (--budget->feeding)
+		return budget->feeding;
 
-        saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
+	saa7146_write(budget->dev, MC1, MASK_20);	// DMA3 off
 	SAA7146_IER_DISABLE(budget->dev, MASK_10);
-        return 0;
+	return 0;
 }
 
-
-static int start_ts_capture (struct budget *budget)
+static int start_ts_capture(struct budget *budget)
 {
-        struct saa7146_dev *dev=budget->dev;
+	struct saa7146_dev *dev = budget->dev;
 
 	dprintk(2, "budget: %p\n", budget);
 
-        if (budget->feeding) 
-                return ++budget->feeding;
+	if (budget->feeding)
+		return ++budget->feeding;
 
-      	saa7146_write(dev, MC1, MASK_20); // DMA3 off
+	saa7146_write(dev, MC1, MASK_20);	// DMA3 off
 
-        memset(budget->grabbing, 0x00, TS_HEIGHT*TS_WIDTH);
+	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
 
 	saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
 
-        budget->tsf=0xff;
-        budget->ttbp=0;
+	budget->tsf = 0xff;
+	budget->ttbp = 0;
 
 	/*
 	 *  Signal path on the Activy:
@@ -86,7 +84,7 @@ static int start_ts_capture (struct budg
 	 *
 	 *  Since the tuner feeds 204 bytes packets into the SAA7146,
 	 *  DMA3 is configured to strip the trailing 16 FEC bytes:
-	 *	Pitch: 188, NumBytes3: 188, NumLines3: 1024
+	 *      Pitch: 188, NumBytes3: 188, NumLines3: 1024
 	 */
 
         switch(budget->card->type) {
@@ -106,63 +104,62 @@ static int start_ts_capture (struct budg
 			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 			saa7146_write(dev, BRS_CTRL, 0x00000000);
 		} else {
-        saa7146_write(dev, DD1_INIT, 0x02000600);
-        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-        saa7146_write(dev, BRS_CTRL, 0x60000000);	
+			saa7146_write(dev, DD1_INIT, 0x02000600);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
 		}
 	}
 
-      	saa7146_write(dev, MC2, (MASK_08 | MASK_24));
-        mdelay(10);
+	saa7146_write(dev, MC2, (MASK_08 | MASK_24));
+	mdelay(10);
 
-        saa7146_write(dev, BASE_ODD3, 0);
-        saa7146_write(dev, BASE_EVEN3, 0);
-        saa7146_write(dev, PROT_ADDR3, TS_WIDTH*TS_HEIGHT);	
-        saa7146_write(dev, BASE_PAGE3, budget->pt.dma |ME1|0x90);
+	saa7146_write(dev, BASE_ODD3, 0);
+	saa7146_write(dev, BASE_EVEN3, 0);
+	saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
 
 	if (budget->card->type == BUDGET_FS_ACTIVY) {
-		saa7146_write(dev, PITCH3, TS_WIDTH/2);
-		saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT*2)<<16)|(TS_WIDTH/2));
+		saa7146_write(dev, PITCH3, TS_WIDTH / 2);
+		saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT * 2) << 16) | (TS_WIDTH / 2));
 	} else {
 		saa7146_write(dev, PITCH3, TS_WIDTH);
-        saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT<<16)|TS_WIDTH);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
 	}
 
-      	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
+	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
 
 	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
 	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
 	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
 
-        return ++budget->feeding;
+	return ++budget->feeding;
 }
 
-
-static void vpeirq (unsigned long data)
+static void vpeirq(unsigned long data)
 {
-        struct budget *budget = (struct budget*) data;
-        u8 *mem = (u8 *)(budget->grabbing);
-        u32 olddma = budget->ttbp;
-        u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+	struct budget *budget = (struct budget *) data;
+	u8 *mem = (u8 *) (budget->grabbing);
+	u32 olddma = budget->ttbp;
+	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
 
-        /* nearest lower position divisible by 188 */
-        newdma -= newdma % 188;
+	/* nearest lower position divisible by 188 */
+	newdma -= newdma % 188;
 
-        if (newdma >= TS_BUFLEN)
-                return;
+	if (newdma >= TS_BUFLEN)
+		return;
 
 	budget->ttbp = newdma;
-	
-	if(budget->feeding == 0 || newdma == olddma)
+
+	if (budget->feeding == 0 || newdma == olddma)
 		return;
 
-        if (newdma > olddma) { /* no wraparound, dump olddma..newdma */
+	if (newdma > olddma) {	/* no wraparound, dump olddma..newdma */
 		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188);
-        } else { /* wraparound, dump olddma..buflen and 0..newdma */
+	} else {		/* wraparound, dump olddma..buflen and 0..newdma */
 		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
 		dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
 	}
-        }
+}
 
 
 int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
@@ -247,106 +244,104 @@ int ttpci_budget_debiwrite(struct budget
 
 static int budget_start_feed(struct dvb_demux_feed *feed)
 {
-        struct dvb_demux *demux = feed->demux;
-        struct budget *budget = (struct budget*) demux->priv;
+	struct dvb_demux *demux = feed->demux;
+	struct budget *budget = (struct budget *) demux->priv;
 	int status;
 
 	dprintk(2, "budget: %p\n", budget);
 
-        if (!demux->dmx.frontend)
-                return -EINVAL;
+	if (!demux->dmx.frontend)
+		return -EINVAL;
 
-   	spin_lock(&budget->feedlock);   
+	spin_lock(&budget->feedlock);
 	feed->pusi_seen = 0; /* have a clean section start */
-	status = start_ts_capture (budget);
-   	spin_unlock(&budget->feedlock);
+	status = start_ts_capture(budget);
+	spin_unlock(&budget->feedlock);
 	return status;
 }
 
 static int budget_stop_feed(struct dvb_demux_feed *feed)
 {
-        struct dvb_demux *demux = feed->demux;
-        struct budget *budget = (struct budget *) demux->priv;
+	struct dvb_demux *demux = feed->demux;
+	struct budget *budget = (struct budget *) demux->priv;
 	int status;
 
 	dprintk(2, "budget: %p\n", budget);
 
-   	spin_lock(&budget->feedlock);
-	status = stop_ts_capture (budget);
-   	spin_unlock(&budget->feedlock);
+	spin_lock(&budget->feedlock);
+	status = stop_ts_capture(budget);
+	spin_unlock(&budget->feedlock);
 	return status;
 }
 
-
 static int budget_register(struct budget *budget)
 {
-        struct dvb_demux *dvbdemux=&budget->demux;
-        int ret;
+	struct dvb_demux *dvbdemux = &budget->demux;
+	int ret;
 
 	dprintk(2, "budget: %p\n", budget);
 
-        dvbdemux->priv = (void *) budget;
+	dvbdemux->priv = (void *) budget;
 
 	dvbdemux->filternum = 256;
-        dvbdemux->feednum = 256;
-        dvbdemux->start_feed = budget_start_feed;
-        dvbdemux->stop_feed = budget_stop_feed;
-        dvbdemux->write_to_decoder = NULL;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = budget_start_feed;
+	dvbdemux->stop_feed = budget_stop_feed;
+	dvbdemux->write_to_decoder = NULL;
+
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
 
-        dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
-                                      DMX_MEMORY_BASED_FILTERING);
+	dvb_dmx_init(&budget->demux);
 
-        dvb_dmx_init(&budget->demux);
+	budget->dmxdev.filternum = 256;
+	budget->dmxdev.demux = &dvbdemux->dmx;
+	budget->dmxdev.capabilities = 0;
 
-        budget->dmxdev.filternum = 256;
-        budget->dmxdev.demux = &dvbdemux->dmx;
-        budget->dmxdev.capabilities = 0;
+	dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
 
-        dvb_dmxdev_init(&budget->dmxdev, budget->dvb_adapter);
+	budget->hw_frontend.source = DMX_FRONTEND_0;
 
-        budget->hw_frontend.source = DMX_FRONTEND_0;
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
 
-        ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
+	if (ret < 0)
+		return ret;
 
-        if (ret < 0)
-                return ret;
-        
-        budget->mem_frontend.source = DMX_MEMORY_FE;
+	budget->mem_frontend.source = DMX_MEMORY_FE;
 	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
-        if (ret<0)
-                return ret;
-        
+	if (ret < 0)
+		return ret;
+
 	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
-        if (ret < 0)
-                return ret;
+	if (ret < 0)
+		return ret;
 
-        dvb_net_init(budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
+	dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
 
 	return 0;
 }
 
-
 static void budget_unregister(struct budget *budget)
 {
-        struct dvb_demux *dvbdemux=&budget->demux;
+	struct dvb_demux *dvbdemux = &budget->demux;
 
 	dprintk(2, "budget: %p\n", budget);
 
 	dvb_net_release(&budget->dvb_net);
 
 	dvbdemux->dmx.close(&dvbdemux->dmx);
-        dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
-        dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
 
-        dvb_dmxdev_release(&budget->dmxdev);
-        dvb_dmx_release(&budget->demux);
+	dvb_dmxdev_release(&budget->dmxdev);
+	dvb_dmx_release(&budget->demux);
 }
 
 int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 		      struct saa7146_pci_extension_data *info,
 		      struct module *owner)
 {
-	int length = TS_WIDTH*TS_HEIGHT;
+	int length = TS_WIDTH * TS_HEIGHT;
 	int ret = 0;
 	struct budget_info *bi = info->ext_priv;
 
@@ -360,13 +355,13 @@ int ttpci_budget_init(struct budget *bud
 	dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
 
 	/* set dd1 stream a & b */
-      	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25));
 	saa7146_write(dev, MC2, (MASK_10 | MASK_26));
 	saa7146_write(dev, DD1_INIT, 0x02000000);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
-       	if (bi->type != BUDGET_FS_ACTIVY)
+	if (bi->type != BUDGET_FS_ACTIVY)
 		budget->video_port = BUDGET_VIDEO_PORTB;
 	else
 		budget->video_port = BUDGET_VIDEO_PORTA;
@@ -374,10 +369,10 @@ int ttpci_budget_init(struct budget *bud
 	spin_lock_init(&budget->debilock);
 
 	/* the Siemens DVB needs this if you want to have the i2c chips
-           get recognized before the main driver is loaded */
+	   get recognized before the main driver is loaded */
 	if (bi->type != BUDGET_FS_ACTIVY)
-		saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
-	
+		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
+
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
 	budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
 #else
@@ -390,11 +385,11 @@ int ttpci_budget_init(struct budget *bud
 	strcpy(budget->i2c_adap.name, budget->card->name);
 
 	if (i2c_add_adapter(&budget->i2c_adap) < 0) {
-		dvb_unregister_adapter (budget->dvb_adapter);
+		dvb_unregister_adapter(&budget->dvb_adapter);
 		return -ENOMEM;
 	}
 
-	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac);
+	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
 
 	if (NULL ==
 	    (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) {
@@ -404,9 +399,9 @@ int ttpci_budget_init(struct budget *bud
 
 	saa7146_write(dev, PCI_BT_V1, 0x001c0000);
 	/* upload all */
-        saa7146_write(dev, GPIO_CTRL, 0x000000);
+	saa7146_write(dev, GPIO_CTRL, 0x000000);
 
-	tasklet_init (&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
+	tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
 
 	/* frontend power on */
 	if (bi->type == BUDGET_FS_ACTIVY)
@@ -414,66 +409,64 @@ int ttpci_budget_init(struct budget *bud
 	else
 		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 
-        if (budget_register(budget) == 0) {
+	if (budget_register(budget) == 0) {
 		return 0;
 	}
 err:
 	i2c_del_adapter(&budget->i2c_adap);
 
-	if (budget->grabbing)
-		vfree(budget->grabbing);
+	vfree(budget->grabbing);
 
-	dvb_unregister_adapter (budget->dvb_adapter);
+	dvb_unregister_adapter(&budget->dvb_adapter);
 
 	return ret;
 }
 
-
-int ttpci_budget_deinit (struct budget *budget)
+int ttpci_budget_deinit(struct budget *budget)
 {
 	struct saa7146_dev *dev = budget->dev;
 
 	dprintk(2, "budget: %p\n", budget);
 
-	budget_unregister (budget);
+	budget_unregister(budget);
 
 	i2c_del_adapter(&budget->i2c_adap);
 
-	dvb_unregister_adapter (budget->dvb_adapter);
+	dvb_unregister_adapter(&budget->dvb_adapter);
 
-	tasklet_kill (&budget->vpe_tasklet);
+	tasklet_kill(&budget->vpe_tasklet);
 
-	saa7146_pgtable_free (dev->pci, &budget->pt);
+	saa7146_pgtable_free(dev->pci, &budget->pt);
 
-	vfree (budget->grabbing);
+	vfree(budget->grabbing);
 
 	return 0;
 }
 
-void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr) 
+void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
 {
-	struct budget *budget = (struct budget*)dev->ext_priv;
+	struct budget *budget = (struct budget *) dev->ext_priv;
 
-	dprintk(8, "dev: %p, budget: %p\n",dev,budget);
+	dprintk(8, "dev: %p, budget: %p\n", dev, budget);
 
 	if (*isr & MASK_10)
-		tasklet_schedule (&budget->vpe_tasklet);
+		tasklet_schedule(&budget->vpe_tasklet);
 }
 
-void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port)
+void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
 {
-	struct budget *budget = (struct budget*)dev->ext_priv;
+	struct budget *budget = (struct budget *) dev->ext_priv;
 
 	spin_lock(&budget->feedlock);
 	budget->video_port = video_port;
 	if (budget->feeding) {
 		int oldfeeding = budget->feeding;
-	   	budget->feeding = 1;
+		budget->feeding = 1;
 		stop_ts_capture(budget);
 		start_ts_capture(budget);
-	   	budget->feeding = oldfeeding;
+		budget->feeding = oldfeeding;
 	}
-   	spin_unlock(&budget->feedlock);
+	spin_unlock(&budget->feedlock);
 }
 
 EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
@@ -485,4 +478,3 @@ EXPORT_SYMBOL_GPL(ttpci_budget_set_video
 EXPORT_SYMBOL_GPL(budget_debug);
 
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -13,19 +13,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.
- * 
+ *
  *
  * 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  *
  * the project's page is at http://www.linuxtv.org/dvb/
  */
@@ -55,7 +55,7 @@ static struct pci_device_id pci_tbl[] = 
 /* those lines are for budget-patch to be tried
 ** on a true budget card and observe the
 ** behaviour of VSYNC generated by rps1.
-** this code was shamelessly copy/pasted from budget.c 
+** this code was shamelessly copy/pasted from budget.c
 */
 static void gpio_Set22K (struct budget *budget, int state)
 {
@@ -96,10 +96,10 @@ static void DiseqcSendByte (struct budge
 
 static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
 {
-        struct saa7146_dev *dev=budget->dev;
+	struct saa7146_dev *dev=budget->dev;
 	int i;
 
-        dprintk(2, "budget: %p\n", budget);
+	dprintk(2, "budget: %p\n", budget);
 
 	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 	mdelay(16);
@@ -123,7 +123,7 @@ static int SendDiSEqCMsg (struct budget 
 	return 0;
 }
 
-/* shamelessly copy/pasted from budget.c 
+/* shamelessly copy/pasted from budget.c
 */
 static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
@@ -151,7 +151,7 @@ static int budget_diseqc_send_master_cmd
 
 	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
 
-        return 0;
+	return 0;
 }
 
 static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
@@ -173,27 +173,25 @@ static int budget_av7110_send_fw_cmd(str
         {
                   ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
                   msleep(5);
-        }                  
+        }
         if (length)
                   ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
         else
                   ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
-        msleep(5);     
+        msleep(5);
         ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
         msleep(5);
         return 0;
 }
 
-
 static void av7110_set22k(struct budget_patch *budget, int state)
 {
         u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
-        
+
         dprintk(2, "budget: %p\n", budget);
         budget_av7110_send_fw_cmd(budget, buf, 2);
 }
 
-
 static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
 {
         int i;
@@ -212,7 +210,7 @@ static int av7110_send_diseqc_msg(struct
                 buf[3]=burst ? 0x01 : 0x00;
         else
                 buf[3]=0xffff;
-                
+
         for (i=0; i<len; i++)
                 buf[i+4]=msg[i];
 
@@ -225,27 +223,29 @@ static int budget_patch_set_tone(struct 
 	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
 	switch (tone) {
-                case SEC_TONE_ON:
-                        av7110_set22k (budget, 1);
-                        break;
-                case SEC_TONE_OFF:
-                        av7110_set22k (budget, 0);
-                        break;
-                default:
-                        return -EINVAL;
-                }
+	case SEC_TONE_ON:
+		av7110_set22k (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		av7110_set22k (budget, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
 	return 0;
 }
 
 static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-        {
+{
 	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
-                av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
+	av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
 
 	return 0;
-        }
+}
 
 static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
 {
@@ -254,7 +254,7 @@ static int budget_patch_diseqc_send_burs
 	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
 
 	return 0;
-        }
+}
 
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
@@ -350,7 +350,7 @@ static int alps_bsru6_set_symbol_rate(st
 	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
 	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
 
-        return 0;
+	return 0;
 }
 
 static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -406,7 +406,7 @@ static int grundig_29504_451_pll_set(str
 	return 0;
 }
 
-struct tda8083_config grundig_29504_451_config = {
+static struct tda8083_config grundig_29504_451_config = {
 	.demod_address = 0x68,
 	.pll_set = grundig_29504_451_pll_set,
 };
@@ -453,7 +453,7 @@ static void frontend_init(struct budget_
 		       budget->dev->pci->subsystem_vendor,
 		       budget->dev->pci->subsystem_device);
 	} else {
-		if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
 			printk("budget-av: Frontend registration failed!\n");
 			if (budget->dvb_frontend->ops->release)
 				budget->dvb_frontend->ops->release(budget->dvb_frontend);
@@ -498,7 +498,7 @@ static int budget_patch_attach (struct s
         saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
         // Set HPS prescaler for port B input
         saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
-        saa7146_write(dev, MC2, 
+        saa7146_write(dev, MC2,
           0 * (MASK_08 | MASK_24)  |   // BRS control
           0 * (MASK_09 | MASK_25)  |   // a
           0 * (MASK_10 | MASK_26)  |   // b
@@ -512,15 +512,15 @@ static int budget_patch_attach (struct s
         // RPS1 timeout disable
         saa7146_write(dev, RPS_TOV1, 0);
 
-	// code for autodetection 
+	// code for autodetection
 	// will wait for VBI_B event (vertical blank at port B)
 	// and will reset GPIO3 after VBI_B is detected.
 	// (GPIO3 should be raised high by CPU to
-	// test if GPIO3 will generate vertical blank signal 
+	// test if GPIO3 will generate vertical blank signal
 	// in budget patch GPIO3 is connected to VSYNC_B
 	count = 0;
 #if 0
-	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD | 
+	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
 	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
 #endif
         WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
@@ -557,7 +557,7 @@ static int budget_patch_attach (struct s
         saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
 	mdelay(150);
 
-	
+
 	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
 		detected = 1;
 
@@ -570,51 +570,51 @@ static int budget_patch_attach (struct s
 	if(detected == 0)
                 printk("budget-patch not detected or saa7146 in non-default state.\n"
                        "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
-                
+
 	else
                 printk("BUDGET-PATCH DETECTED.\n");
 
 
 /*      OLD (Original design by Roberto Deza):
-**      This code will setup the SAA7146_RPS1 to generate a square 
-**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of 
-**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port; 
-**      then, this GPIO3 output which is connected to the D1B_VSYNC 
-**      input, will trigger the acquisition of the alternate field 
+**      This code will setup the SAA7146_RPS1 to generate a square
+**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
+**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
+**      then, this GPIO3 output which is connected to the D1B_VSYNC
+**      input, will trigger the acquisition of the alternate field
 **      and so on.
-**      Currently, the TT_budget / WinTV_Nova cards have two ICs 
-**      (74HCT4040, LVC74) for the generation of this VSYNC signal, 
+**      Currently, the TT_budget / WinTV_Nova cards have two ICs
+**      (74HCT4040, LVC74) for the generation of this VSYNC signal,
 **      which seems that can be done perfectly without this :-)).
-*/                                                      
+*/
 
 /*      New design (By Emard)
 **      this rps1 code will copy internal HS event to GPIO3 pin.
 **      GPIO3 is in budget-patch hardware connectd to port B VSYNC
 
 **      HS is an internal event of 7146, accessible with RPS
-**      and temporarily raised high every n lines 
+**      and temporarily raised high every n lines
 **      (n in defined in the RPS_THRESH1 counter threshold)
 **      I think HS is raised high on the beginning of the n-th line
 **      and remains high until this n-th line that triggered
 **      it is completely received. When the receiption of n-th line
 **      ends, HS is lowered.
 
-**      To transmit data over DMA, 7146 needs changing state at 
-**      port B VSYNC pin. Any changing of port B VSYNC will 
+**      To transmit data over DMA, 7146 needs changing state at
+**      port B VSYNC pin. Any changing of port B VSYNC will
 **      cause some DMA data transfer, with more or less packets loss.
-**      It depends on the phase and frequency of VSYNC and 
+**      It depends on the phase and frequency of VSYNC and
 **      the way of 7146 is instructed to trigger on port B (defined
 **      in DD1_INIT register, 3rd nibble from the right valid
 **      numbers are 0-7, see datasheet)
 **
-**      The correct triggering can minimize packet loss, 
+**      The correct triggering can minimize packet loss,
 **      dvbtraffic should give this stable bandwidths:
 **        22k transponder = 33814 kbit/s
 **      27.5k transponder = 38045 kbit/s
-**      by experiment it is found that the best results 
-**      (stable bandwidths and almost no packet loss) 
-**      are obtained using DD1_INIT triggering number 2 
-**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle) 
+**      by experiment it is found that the best results
+**      (stable bandwidths and almost no packet loss)
+**      are obtained using DD1_INIT triggering number 2
+**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
 **      and a VSYNC phase that occurs in the middle of DMA transfer
 **      (about byte 188*512=96256 in the DMA window).
 **
@@ -625,20 +625,20 @@ static int budget_patch_attach (struct s
 **      increment. That's how the 7146 is programmed to do event
 **      counting in this budget-patch.c
 **      I *think* HPS setting has something to do with the phase
-**      of HS but I cant be 100% sure in that. 
+**      of HS but I cant be 100% sure in that.
 
 **      hardware debug note: a working budget card (including budget patch)
 **      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
 **      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
 **      and that means 3*25=75 Hz of interrupt freqency, as seen by
-**      watch cat /proc/interrupts 
+**      watch cat /proc/interrupts
 **
 **      If this frequency is 3x lower (and data received in the DMA
 **      buffer don't start with 0x47, but in the middle of packets,
 **      whose lengths appear to be like 188 292 188 104 etc.
-**      this means VSYNC line is not connected in the hardware. 
+**      this means VSYNC line is not connected in the hardware.
 **      (check soldering pcb and pins)
-**      The same behaviour of missing VSYNC can be duplicated on budget 
+**      The same behaviour of missing VSYNC can be duplicated on budget
 **      cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
 */
 
@@ -681,14 +681,14 @@ static int budget_patch_attach (struct s
         // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
         //,then RPS_THRESH1
         // should be set to trigger every TS_HEIGHT (512) lines.
-        // 
+        //
         saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
-        
+
         // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
         // Enable RPS1                                                  (rFC p33)
         saa7146_write(dev, MC1, (MASK_13 | MASK_29));
 
-	
+
         if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
                 return -ENOMEM;
 
@@ -702,13 +702,12 @@ static int budget_patch_attach (struct s
 
         dev->ext_priv = budget;
 
-	budget->dvb_adapter->priv = budget;
+	budget->dvb_adapter.priv = budget;
 	frontend_init(budget);
 
         return 0;
 }
 
-
 static int budget_patch_detach (struct saa7146_dev* dev)
 {
         struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
@@ -723,22 +722,20 @@ static int budget_patch_detach (struct s
         return err;
 }
 
-
-static int __init budget_patch_init(void) 
+static int __init budget_patch_init(void)
 {
 	return saa7146_register_extension(&budget_extension);
 }
 
 static void __exit budget_patch_exit(void)
 {
-        saa7146_unregister_extension(&budget_extension); 
+        saa7146_unregister_extension(&budget_extension);
 }
 
-
 static struct saa7146_extension budget_extension = {
         .name           = "budget_patch dvb\0",
         .flags          = 0,
-        
+
         .module         = THIS_MODULE,
         .pci_tbl        = pci_tbl,
         .attach         = budget_patch_attach,
@@ -748,7 +745,6 @@ static struct saa7146_extension budget_e
         .irq_func       = ttpci_budget_irq10_handler,
 };
 
-
 module_init(budget_patch_init);
 module_exit(budget_patch_exit);
 
@@ -756,4 +752,3 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
 MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 "
                    "based so-called Budget Patch cards");
-
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -1,35 +1,35 @@
 /*
- * budget.c: driver for the SAA7146 based Budget DVB cards 
+ * budget.c: driver for the SAA7146 based Budget DVB cards
  *
- * Compiled from various sources by Michael Hunold <michael@mihu.de> 
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
  *
  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  *
- * Copyright (C) 1999-2002 Ralph  Metzler 
+ * Copyright (C) 1999-2002 Ralph  Metzler
  *                       & Marcus Metzler for convergence integrated media GmbH
  *
  * 26feb2004 Support for FS Activy Card (Grundig tuner) by
  *           Michael Dreher <michael@5dot1.de>,
  *           Oliver Endriss <o.endriss@gmx.de> and
  *           Andreas 'randy' Weinberger
- * 
+ *
  * This program is free software; you can redistribute it 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.
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- * 
+ *
  *
  * the project's page is at http://www.linuxtv.org/dvb/
  */
@@ -48,7 +48,6 @@ static void Set22K (struct budget *budge
 	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
 }
 
-
 /* Diseqc functions only for TT Budget card */
 /* taken from the Skyvision DVB driver by
    Ralph Metzler <rjkm@metzlerbros.de> */
@@ -64,7 +63,6 @@ static void DiseqcSendBit (struct budget
 	udelay(data ? 1000 : 500);
 }
 
-
 static void DiseqcSendByte (struct budget *budget, int data)
 {
 	int i, par=1, d;
@@ -80,7 +78,6 @@ static void DiseqcSendByte (struct budge
 	DiseqcSendBit(budget, par);
 }
 
-
 static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
 {
 	struct saa7146_dev *dev=budget->dev;
@@ -119,7 +116,7 @@ static int SetVoltage_Activy (struct bud
 {
 	struct saa7146_dev *dev=budget->dev;
 
-       dprintk(2, "budget: %p\n", budget);
+	dprintk(2, "budget: %p\n", budget);
 
 	switch (voltage) {
 		case SEC_VOLTAGE_13:
@@ -147,28 +144,29 @@ static int budget_set_tone(struct dvb_fr
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 
 	switch (tone) {
-               case SEC_TONE_ON:
-                       Set22K (budget, 1);
-                       break;
-               case SEC_TONE_OFF:
-                       Set22K (budget, 0);
-                       break;
+	case SEC_TONE_ON:
+		Set22K (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		Set22K (budget, 0);
+		break;
 
-               default:
-                       return -EINVAL;
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
 }
 
 static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-       {
+{
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 
-               SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
 
 	return 0;
-       }
+}
 
 static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
 {
@@ -176,7 +174,7 @@ static int budget_diseqc_send_burst(stru
 
 	SendDiSEqCMsg (budget, 0, NULL, minicmd);
 
-       return 0;
+	return 0;
 }
 
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -275,7 +273,7 @@ static int alps_bsru6_set_symbol_rate(st
 	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
 
 	return 0;
-	}
+}
 
 static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
@@ -368,7 +366,7 @@ static int grundig_29504_401_pll_set(str
 
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
-	}
+}
 
 static struct l64781_config grundig_29504_401_config = {
 	.demod_address = 0x55,
@@ -434,22 +432,28 @@ static void frontend_init(struct budget 
 		}
 		break;
 
-   	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
 
 		budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
 		if (budget->dvb_frontend) break;
 		break;
 
-   	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
 
 		budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) break;
 		break;
 
-	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+	case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
+		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+			break;
+		}
+		break;
 
-		// grundig 29504-451
-                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
+		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
 			break;
@@ -464,7 +468,7 @@ static void frontend_init(struct budget 
 		       budget->dev->pci->subsystem_vendor,
 		       budget->dev->pci->subsystem_device);
 	} else {
-		if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
 			printk("budget: Frontend registration failed!\n");
 			if (budget->dvb_frontend->ops->release)
 				budget->dvb_frontend->ops->release(budget->dvb_frontend);
@@ -493,13 +497,12 @@ static int budget_attach (struct saa7146
 		return err;
 	}
 
-	budget->dvb_adapter->priv = budget;
+	budget->dvb_adapter.priv = budget;
 	frontend_init(budget);
 
 	return 0;
 }
 
-
 static int budget_detach (struct saa7146_dev* dev)
 {
 	struct budget *budget = (struct budget*) dev->ext_priv;
@@ -515,22 +518,22 @@ static int budget_detach (struct saa7146
 	return err;
 }
 
-
-
 static struct saa7146_extension budget_extension;
 
 MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
-	MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
+	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
+	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
 	{
 		.vendor    = 0,
 	}
@@ -540,8 +543,8 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
 	.name		= "budget dvb\0",
-	.flags	 	= 0,
-	
+	.flags		= 0,
+
 	.module		= THIS_MODULE,
 	.pci_tbl	= pci_tbl,
 	.attach		= budget_attach,
@@ -549,18 +552,16 @@ static struct saa7146_extension budget_e
 
 	.irq_mask	= MASK_10,
 	.irq_func	= ttpci_budget_irq10_handler,
-};	
-
+};
 
-static int __init budget_init(void) 
+static int __init budget_init(void)
 {
 	return saa7146_register_extension(&budget_extension);
 }
 
-
 static void __exit budget_exit(void)
 {
-	saa7146_unregister_extension(&budget_extension); 
+	saa7146_unregister_extension(&budget_extension);
 }
 
 module_init(budget_init);
@@ -570,4 +571,3 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
 		   "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");
-
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -29,48 +29,46 @@ struct budget_info {
 /* place to store all the necessary device information */
 struct budget {
 
-        /* devices */
-        struct dvb_device       dvb_dev;
-        struct dvb_net               dvb_net;
+	/* devices */
+	struct dvb_device dvb_dev;
+	struct dvb_net dvb_net;
 
-        struct saa7146_dev	*dev;
+	struct saa7146_dev *dev;
 
-	struct i2c_adapter	i2c_adap;
-	struct budget_info	*card;
+	struct i2c_adapter i2c_adap;
+	struct budget_info *card;
 
-	unsigned char		*grabbing;
-	struct saa7146_pgtable	pt;
+	unsigned char *grabbing;
+	struct saa7146_pgtable pt;
 
-	struct tasklet_struct   fidb_tasklet;
-	struct tasklet_struct   vpe_tasklet;
+	struct tasklet_struct fidb_tasklet;
+	struct tasklet_struct vpe_tasklet;
 
-        struct dmxdev                dmxdev;
-        struct dvb_demux	demux;
+	struct dmxdev dmxdev;
+	struct dvb_demux demux;
 
-        struct dmx_frontend          hw_frontend;
-        struct dmx_frontend          mem_frontend;
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
 
-        int                     fe_synced; 
-        struct semaphore        pid_mutex;
+	int fe_synced;
+	struct semaphore pid_mutex;
 
-	int                     ci_present;
-        int                     video_port;
+	int ci_present;
+	int video_port;
 
-        u8 tsf;
-        u32 ttbp;
-        int feeding;
+	u8 tsf;
+	u32 ttbp;
+	int feeding;
 
 	spinlock_t feedlock;
 
 	spinlock_t debilock;
 
-        struct dvb_adapter       *dvb_adapter;
+	struct dvb_adapter dvb_adapter;
 	struct dvb_frontend *dvb_frontend;
-	void			 *priv;
+	void *priv;
 };
 
-
-
 #define MAKE_BUDGET_INFO(x_var,x_name,x_type) \
 static struct budget_info x_var ## _info = { \
 	.name=x_name,	\
@@ -94,6 +92,9 @@ static struct saa7146_pci_extension_data
 #define BUDGET_KNC1S		   8
 #define BUDGET_KNC1C		   9
 #define BUDGET_KNC1T		   10
+#define BUDGET_KNC1SP		   11
+#define BUDGET_KNC1CP		   12
+#define BUDGET_KNC1TP		   13
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
@@ -101,9 +102,9 @@ static struct saa7146_pci_extension_data
 extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 			     struct saa7146_pci_extension_data *info,
 			     struct module *owner);
-extern int ttpci_budget_deinit (struct budget *budget);
-extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
-extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port);
+extern int ttpci_budget_deinit(struct budget *budget);
+extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
+extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port);
 extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
 				 int uselocks, int nobusyloop);
 extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value,
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -90,7 +90,7 @@ static int ttpci_eeprom_read_encodedMAC(
 	u8 b0[] = { 0xcc };
 
 	struct i2c_msg msg[] = {
-		{.addr = 0x50,.flags = 0,.buf = b0,.len = 1},
+		{ .addr = 0x50, .flags = 0, .buf = b0, .len = 1 },
 		{ .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 }
 	};
 
@@ -144,4 +144,3 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
 MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards "
 		"made by Siemens, Technotrend, Hauppauge");
-
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -10,6 +10,6 @@ config DVB_TTUSB_BUDGET
 	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
 
           These devices don't have a MPEG decoder built in, so you need
-	  an external software decoder to watch TV.	  
+	  an external software decoder to watch TV.
 
 	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -33,6 +33,7 @@
 #include <linux/dvb/dmx.h>
 #include <linux/pci.h>
 
+
 /*
   TTUSB_HWSECTIONS:
     the DSP supports filtering in hardware, however, since the "muxstream"
@@ -41,12 +42,12 @@
     so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just
     parse TS data. USB bandwith will be a problem when having large
     datastreams, especially for dvb-net, but hey, that's not my problem.
-	
+
   TTUSB_DISEQC, TTUSB_TONE:
     let the STC do the diseqc/tone stuff. this isn't supported at least with
     my TTUSB, so let it undef'd unless you want to implement another
     frontend. never tested.
-		
+
   DEBUG:
     define it to > 3 for really hardcore debugging. you probably don't want
     this unless the device doesn't load at all. > 2 for bandwidth statistics.
@@ -67,6 +68,7 @@ MODULE_PARM_DESC(debug, "Turn on/off deb
 #define TTUSB_MAXFILTER    16	/* ??? */
 #endif
 
+#define TTUSB_REV_2_2	0x22
 #define TTUSB_BUDGET_NAME "ttusb_stc_fw"
 
 /**
@@ -78,12 +80,11 @@ struct ttusb {
 	struct dmxdev dmxdev;
 	struct dvb_net dvbnet;
 
-	/* our semaphore, for channel allocation/deallocation */
-	struct semaphore sem;
 	/* and one for USB access. */
+	struct semaphore semi2c;
 	struct semaphore semusb;
 
-	struct dvb_adapter *adapter;
+	struct dvb_adapter adapter;
 	struct usb_device *dev;
 
 	struct i2c_adapter i2c_adap;
@@ -118,21 +119,10 @@ struct ttusb {
 	int cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
 	/* (including stuffing. yes. really.) */
 
-
 	u8 last_result[32];
 
-	struct ttusb_channel {
-		struct ttusb *ttusb;
-		struct dvb_demux_feed *dvbdmxfeed;
-
-		int active;
-		int id;
-		int pid;
-		int type;	/* 1 - TS, 2 - Filter */
-#ifdef TTUSB_HWSECTIONS
-		int filterstate[TTUSB_MAXFILTER];	/* 0: not busy, 1: busy */
-#endif
-	} channel[TTUSB_MAXCHANNEL];
+	int revision;
+
 #if 0
 	devfs_handle_t stc_devfs_handle;
 #endif
@@ -162,7 +152,7 @@ static int ttusb_cmd(struct ttusb *ttusb
 		return -EAGAIN;
 
 	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
-			   (u8 *) data, len, &actual_len, HZ);
+			   (u8 *) data, len, &actual_len, 1000);
 	if (err != 0) {
 		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
 			__FUNCTION__, err);
@@ -177,7 +167,7 @@ static int ttusb_cmd(struct ttusb *ttusb
 	}
 
 	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
-			   ttusb->last_result, 32, &actual_len, HZ);
+			   ttusb->last_result, 32, &actual_len, 1000);
 
 	if (err != 0) {
 		printk("%s: failed, receive error %d\n", __FUNCTION__,
@@ -252,13 +242,13 @@ static int ttusb_i2c_msg(struct ttusb *t
 	return rcv_len;
 }
 
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num)
+static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
 {
 	struct ttusb *ttusb = i2c_get_adapdata(adapter);
 	int i = 0;
 	int inc;
 
-	if (down_interruptible(&ttusb->sem) < 0)
+	if (down_interruptible(&ttusb->semi2c) < 0)
 		return -EAGAIN;
 
 	while (i < num) {
@@ -292,7 +282,7 @@ static int master_xfer(struct i2c_adapte
 		i += inc;
 	}
 
-	up(&ttusb->sem);
+	up(&ttusb->semi2c);
 	return i;
 }
 
@@ -445,13 +435,17 @@ static int ttusb_init_controller(struct 
 
 	if (memcmp(get_version + 4, "V 0.0", 5) &&
 	    memcmp(get_version + 4, "V 1.1", 5) &&
-   	    memcmp(get_version + 4, "V 2.1", 5)) {
+	    memcmp(get_version + 4, "V 2.1", 5) &&
+	    memcmp(get_version + 4, "V 2.2", 5)) {
 		printk
 		    ("%s: unknown STC version %c%c%c%c%c, please report!\n",
 		     __FUNCTION__, get_version[4], get_version[5],
 		     get_version[6], get_version[7], get_version[8]);
 	}
 
+	ttusb->revision = ((get_version[6] - '0') << 4) |
+			   (get_version[8] - '0');
+
 	err =
 	    ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1);
 	if (err)
@@ -468,7 +462,7 @@ static int ttusb_init_controller(struct 
 
 #ifdef TTUSB_DISEQC
 static int ttusb_send_diseqc(struct dvb_frontend* fe,
-		      const struct dvb_diseqc_master_cmd *cmd)
+			     const struct dvb_diseqc_master_cmd *cmd)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
@@ -491,6 +485,31 @@ static int ttusb_send_diseqc(struct dvb_
 }
 #endif
 
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+        struct  ttusb* ttusb = (struct ttusb*)  fe->dvb->priv;
+        int ret;
+        u8 data[1];
+        struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
+
+        switch(voltage) {
+        case SEC_VOLTAGE_OFF:
+                data[0] = 0x00;
+                break;
+        case SEC_VOLTAGE_13:
+                data[0] = 0x44;
+                break;
+        case SEC_VOLTAGE_18:
+                data[0] = 0x4c;
+                break;
+        default:
+                return -EINVAL;
+        };
+
+        ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
+        return (ret != 1) ? -EIO : 0;
+}
+
 static int ttusb_update_lnb(struct ttusb *ttusb)
 {
 	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -831,7 +850,7 @@ static void ttusb_stop_iso_xfer(struct t
 	int i;
 
 	for (i = 0; i < ISO_BUF_COUNT; i++)
-		usb_unlink_urb(ttusb->iso_urb[i]);
+		usb_kill_urb(ttusb->iso_urb[i]);
 
 	ttusb->iso_streaming = 0;
 }
@@ -888,15 +907,13 @@ static int ttusb_start_iso_xfer(struct t
 }
 
 #ifdef TTUSB_HWSECTIONS
-static void ttusb_handle_ts_data(struct ttusb_channel *channel, const u8 * data,
+static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
 			  int len)
 {
-	struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
-
 	dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);
 }
 
-static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data,
+static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
 			   int len)
 {
 //      struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
@@ -905,31 +922,10 @@ static void ttusb_handle_sec_data(struct
 }
 #endif
 
-static struct ttusb_channel *ttusb_channel_allocate(struct ttusb *ttusb)
-{
-	int i;
-
-	if (down_interruptible(&ttusb->sem))
-		return NULL;
-
-	/* lock! */
-	for (i = 0; i < TTUSB_MAXCHANNEL; ++i) {
-		if (!ttusb->channel[i].active) {
-			ttusb->channel[i].active = 1;
-			up(&ttusb->sem);
-			return ttusb->channel + i;
-		}
-	}
-
-	up(&ttusb->sem);
-
-	return NULL;
-}
-
 static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
-	struct ttusb_channel *channel;
+	int feed_type = 1;
 
 	dprintk("ttusb_start_feed\n");
 
@@ -949,35 +945,22 @@ static int ttusb_start_feed(struct dvb_d
 		case DMX_TS_PES_TELETEXT:
 		case DMX_TS_PES_PCR:
 		case DMX_TS_PES_OTHER:
-			channel = ttusb_channel_allocate(ttusb);
 			break;
 		default:
 			return -EINVAL;
 		}
-	} else {
-		channel = ttusb_channel_allocate(ttusb);
 	}
 
-	if (!channel)
-		return -EBUSY;
-
-	dvbdmxfeed->priv = channel;
-	channel->dvbdmxfeed = dvbdmxfeed;
-
-	channel->pid = dvbdmxfeed->pid;
-
 #ifdef TTUSB_HWSECTIONS
+#error TODO: allocate filters
 	if (dvbdmxfeed->type == DMX_TYPE_TS) {
-		channel->type = 1;
+		feed_type = 1;
 	} else if (dvbdmxfeed->type == DMX_TYPE_SEC) {
-		channel->type = 2;
-#error TODO: allocate filters
+		feed_type = 2;
 	}
-#else
-	channel->type = 1;
 #endif
 
-	ttusb_set_channel(ttusb, channel->id, channel->type, channel->pid);
+	ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid);
 
 	if (0 == ttusb->running_feed_count++)
 		ttusb_start_iso_xfer(ttusb);
@@ -987,17 +970,13 @@ static int ttusb_start_feed(struct dvb_d
 
 static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
-	struct ttusb_channel *channel =
-	    (struct ttusb_channel *) dvbdmxfeed->priv;
 	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
 
-	ttusb_del_channel(channel->ttusb, channel->id);
+	ttusb_del_channel(ttusb, dvbdmxfeed->index);
 
 	if (--ttusb->running_feed_count == 0)
 		ttusb_stop_iso_xfer(ttusb);
 
-	channel->active = 0;
-
 	return 0;
 }
 
@@ -1086,7 +1065,7 @@ static int alps_tdmb7_pll_set(struct dvb
 	return 0;
 }
 
-struct cx22700_config alps_tdmb7_config = {
+static struct cx22700_config alps_tdmb7_config = {
 	.demod_address = 0x43,
 	.pll_set = alps_tdmb7_pll_set,
 };
@@ -1201,10 +1180,51 @@ static struct tda1004x_config philips_td
 	.request_firmware = philips_tdm1316l_request_firmware,
 };
 
+static u8 alps_bsbe1_inittab[] = {
+        0x01, 0x15,
+        0x02, 0x30,
+        0x03, 0x00,
+        0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+        0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
+        0x06, 0x40,             /* DAC not used, set to high impendance mode */
+        0x07, 0x00,             /* DAC LSB */
+        0x08, 0x40,             /* DiSEqC off, LNB power on OP2/LOCK pin on */
+        0x09, 0x00,             /* FIFO */
+        0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+        0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
+        0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
+        0x10, 0x3f,             // AGC2  0x3d
+        0x11, 0x84,
+        0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+        0x15, 0xc9,             // lock detector threshold
+        0x16, 0x00,
+        0x17, 0x00,
+        0x18, 0x00,
+        0x19, 0x00,
+        0x1a, 0x00,
+        0x1f, 0x50,
+        0x20, 0x00,
+        0x21, 0x00,
+        0x22, 0x00,
+        0x23, 0x00,
+        0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
+        0x29, 0x1e,             // 1/2 threshold
+        0x2a, 0x14,             // 2/3 threshold
+        0x2b, 0x0f,             // 3/4 threshold
+        0x2c, 0x09,             // 5/6 threshold
+        0x2d, 0x05,             // 7/8 threshold
+        0x2e, 0x01,
+        0x31, 0x1f,             // test all FECs
+        0x32, 0x19,             // viterbi and synchro search
+        0x33, 0xfc,             // rs control
+        0x34, 0x93,             // error control
+        0x0f, 0x92,
+        0xff, 0xff
+};
 
 static u8 alps_bsru6_inittab[] = {
 	0x01, 0x15,
-	0x02, 0x00,
+	0x02, 0x30,
 	0x03, 0x00,
 	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
 	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
@@ -1244,7 +1264,7 @@ static u8 alps_bsru6_inittab[] = {
 	0xff, 0xff
 };
 
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
 {
 	u8 aclk = 0;
 	u8 bclk = 0;
@@ -1278,7 +1298,7 @@ static int alps_bsru6_set_symbol_rate(st
 	return 0;
 }
 
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 buf[4];
@@ -1295,7 +1315,11 @@ static int alps_bsru6_pll_set(struct dvb
 	buf[3] = 0xC4;
 
 	if (params->frequency > 1530000)
-		buf[3] = 0xc0;
+		buf[3] = 0xC0;
+
+	/* BSBE1 wants XCE bit set */
+	if (ttusb->revision == TTUSB_REV_2_2)
+		buf[3] |= 0x20;
 
 	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
 		return -EIO;
@@ -1303,8 +1327,7 @@ static int alps_bsru6_pll_set(struct dvb
 	return 0;
 }
 
-static struct stv0299_config alps_bsru6_config = {
-
+static struct stv0299_config alps_stv0299_config = {
 	.demod_address = 0x68,
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
@@ -1314,8 +1337,8 @@ static struct stv0299_config alps_bsru6_
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
+	.set_symbol_rate = alps_stv0299_set_symbol_rate,
+	.pll_set = philips_tsa5059_pll_set,
 };
 
 static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
@@ -1349,11 +1372,16 @@ static struct tda8083_config ttusb_novas
 static void frontend_init(struct ttusb* ttusb)
 {
 	switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
-	case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6(tsa5059)
-		// try the ALPS BSRU6 first
-		ttusb->fe = stv0299_attach(&alps_bsru6_config, &ttusb->i2c_adap);
+	case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
+		// try the stv0299 based first
+		ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
-			ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+			if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
+				alps_stv0299_config.inittab = alps_bsbe1_inittab;
+				ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+			} else { // ALPS BSRU6
+				ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+			}
 			break;
 		}
 
@@ -1384,7 +1412,7 @@ static void frontend_init(struct ttusb* 
 		       le16_to_cpu(ttusb->dev->descriptor.idVendor),
 		       le16_to_cpu(ttusb->dev->descriptor.idProduct));
 	} else {
-		if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) {
+		if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
 			printk("dvb-ttusb-budget: Frontend registration failed!\n");
 			if (ttusb->fe->ops->release)
 				ttusb->fe->ops->release(ttusb->fe);
@@ -1406,7 +1434,7 @@ static int ttusb_probe(struct usb_interf
 {
 	struct usb_device *udev;
 	struct ttusb *ttusb;
-	int result, channel;
+	int result;
 
 	dprintk("%s: TTUSB DVB connected\n", __FUNCTION__);
 
@@ -1419,15 +1447,10 @@ static int ttusb_probe(struct usb_interf
 
 	memset(ttusb, 0, sizeof(struct ttusb));
 
-	for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) {
-		ttusb->channel[channel].id = channel;
-		ttusb->channel[channel].ttusb = ttusb;
-	}
-
 	ttusb->dev = udev;
 	ttusb->c = 0;
 	ttusb->mux_state = 0;
-	sema_init(&ttusb->sem, 0);
+	sema_init(&ttusb->semi2c, 0);
 	sema_init(&ttusb->semusb, 1);
 
 	ttusb_setup_interfaces(ttusb);
@@ -1436,10 +1459,10 @@ static int ttusb_probe(struct usb_interf
 	if (ttusb_init_controller(ttusb))
 		printk("ttusb_init_controller: error\n");
 
-	up(&ttusb->sem);
+	up(&ttusb->semi2c);
 
 	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
-	ttusb->adapter->priv = ttusb;
+	ttusb->adapter.priv = ttusb;
 
 	/* i2c */
 	memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
@@ -1448,9 +1471,9 @@ static int ttusb_probe(struct usb_interf
 	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
 
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	ttusb->i2c_adap.class 	    	  = I2C_ADAP_CLASS_TV_DIGITAL;
+	ttusb->i2c_adap.class		  = I2C_ADAP_CLASS_TV_DIGITAL;
 #else
-	ttusb->i2c_adap.class 	    	  = I2C_CLASS_TV_DIGITAL;
+	ttusb->i2c_adap.class		  = I2C_CLASS_TV_DIGITAL;
 #endif
 	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
 	ttusb->i2c_adap.algo_data         = NULL;
@@ -1458,7 +1481,7 @@ static int ttusb_probe(struct usb_interf
 
 	result = i2c_add_adapter(&ttusb->i2c_adap);
 	if (result) {
-		dvb_unregister_adapter (ttusb->adapter);
+		dvb_unregister_adapter (&ttusb->adapter);
 		return result;
 	}
 
@@ -1480,7 +1503,7 @@ static int ttusb_probe(struct usb_interf
 	if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) {
 		printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
 		i2c_del_adapter(&ttusb->i2c_adap);
-		dvb_unregister_adapter (ttusb->adapter);
+		dvb_unregister_adapter (&ttusb->adapter);
 		return -ENODEV;
 	}
 //FIXME dmxdev (nur WAS?)
@@ -1488,21 +1511,21 @@ static int ttusb_probe(struct usb_interf
 	ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
 	ttusb->dmxdev.capabilities = 0;
 
-	if ((result = dvb_dmxdev_init(&ttusb->dmxdev, ttusb->adapter)) < 0) {
+	if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) {
 		printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
 		       result);
 		dvb_dmx_release(&ttusb->dvb_demux);
 		i2c_del_adapter(&ttusb->i2c_adap);
-		dvb_unregister_adapter (ttusb->adapter);
+		dvb_unregister_adapter (&ttusb->adapter);
 		return -ENODEV;
 	}
 
-	if (dvb_net_init(ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
+	if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
 		printk("ttusb_dvb: dvb_net_init failed!\n");
 		dvb_dmxdev_release(&ttusb->dmxdev);
 		dvb_dmx_release(&ttusb->dvb_demux);
 		i2c_del_adapter(&ttusb->i2c_adap);
-		dvb_unregister_adapter (ttusb->adapter);
+		dvb_unregister_adapter (&ttusb->adapter);
 		return -ENODEV;
 	}
 
@@ -1536,7 +1559,7 @@ static void ttusb_disconnect(struct usb_
 	dvb_dmx_release(&ttusb->dvb_demux);
 	if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
 	i2c_del_adapter(&ttusb->i2c_adap);
-	dvb_unregister_adapter(ttusb->adapter);
+	dvb_unregister_adapter(&ttusb->adapter);
 
 	ttusb_free_iso_urbs(ttusb);
 
@@ -1555,10 +1578,10 @@ static struct usb_device_id ttusb_table[
 MODULE_DEVICE_TABLE(usb, ttusb_table);
 
 static struct usb_driver ttusb_driver = {
-      .name 		= "Technotrend/Hauppauge USB-Nova",
-      .probe 		= ttusb_probe,
-      .disconnect 	= ttusb_disconnect,
-      .id_table 	= ttusb_table,
+      .name		= "Technotrend/Hauppauge USB-Nova",
+      .probe		= ttusb_probe,
+      .disconnect	= ttusb_disconnect,
+      .id_table		= ttusb_table,
 };
 
 static int __init ttusb_init(void)
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -10,7 +10,7 @@ config DVB_TTUSB_DEC
 
           Even if these devices have a MPEG decoder built in, they transmit
 	  only compressed MPEG data over the USB bus, so you need
-	  an external software decoder to watch TV on your computer.	  
+	  an external software decoder to watch TV on your computer.
 
           This driver needs external firmware. Please use the commands
           "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -2,6 +2,7 @@
  * TTUSB DEC Driver
  *
  * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ * IR support by Peter Beutner <p.beutner@gmx.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
@@ -32,6 +33,7 @@
 #include <linux/firmware.h>
 #include <linux/crc32.h>
 #include <linux/init.h>
+#include <linux/input.h>
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
@@ -42,27 +44,32 @@
 
 static int debug;
 static int output_pva;
+static int enable_rc;
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 module_param(output_pva, int, 0444);
 MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
+module_param(enable_rc, int, 0644);
+MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
 
 #define dprintk	if (debug) printk
 
 #define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"
 
 #define COMMAND_PIPE		0x03
-#define RESULT_PIPE		0x84
-#define IN_PIPE			0x88
+#define RESULT_PIPE		0x04
+#define IN_PIPE			0x08
 #define OUT_PIPE		0x07
+#define IRQ_PIPE		0x0A
 
 #define COMMAND_PACKET_SIZE	0x3c
 #define ARM_PACKET_SIZE		0x1000
+#define IRQ_PACKET_SIZE		0x8
 
 #define ISO_BUF_COUNT		0x04
 #define FRAMES_PER_ISO_BUF	0x04
-#define ISO_FRAME_SIZE		0x03FF
+#define ISO_FRAME_SIZE		0x0380
 
 #define	MAX_PVA_LENGTH		6144
 
@@ -91,7 +98,7 @@ struct ttusb_dec {
 	int				can_playback;
 
 	/* DVB bits */
-	struct dvb_adapter		*adapter;
+	struct dvb_adapter		adapter;
 	struct dmxdev			dmxdev;
 	struct dvb_demux		demux;
 	struct dmx_frontend		frontend;
@@ -101,15 +108,19 @@ struct ttusb_dec {
 	u16			pid[DMX_PES_OTHER];
 
 	/* USB bits */
-	struct usb_device	*udev;
-	u8			trans_count;
-	unsigned int		command_pipe;
-	unsigned int		result_pipe;
+	struct usb_device		*udev;
+	u8				trans_count;
+	unsigned int			command_pipe;
+	unsigned int			result_pipe;
 	unsigned int			in_pipe;
 	unsigned int			out_pipe;
+	unsigned int			irq_pipe;
 	enum ttusb_dec_interface	interface;
-	struct semaphore	usb_sem;
+	struct semaphore		usb_sem;
 
+	void			*irq_buffer;
+	struct urb		*irq_urb;
+	dma_addr_t		irq_dma_handle;
 	void			*iso_buffer;
 	dma_addr_t		iso_dma_handle;
 	struct urb		*iso_urb[ISO_BUF_COUNT];
@@ -142,6 +153,8 @@ struct ttusb_dec {
 	struct list_head	filter_info_list;
 	spinlock_t		filter_info_list_lock;
 
+	struct input_dev	rc_input_dev;
+
 	int			active; /* Loaded successfully */
 };
 
@@ -157,9 +170,83 @@ struct filter_info {
 	struct list_head	filter_info_list;
 };
 
+static u16 rc_keys[] = {
+	KEY_POWER,
+	KEY_MUTE,
+	KEY_1,
+	KEY_2,
+	KEY_3,
+	KEY_4,
+	KEY_5,
+	KEY_6,
+	KEY_7,
+	KEY_8,
+	KEY_9,
+	KEY_0,
+	KEY_CHANNELUP,
+	KEY_VOLUMEDOWN,
+	KEY_OK,
+	KEY_VOLUMEUP,
+	KEY_CHANNELDOWN,
+	KEY_PREVIOUS,
+	KEY_ESC,
+	KEY_RED,
+	KEY_GREEN,
+	KEY_YELLOW,
+	KEY_BLUE,
+	KEY_OPTION,
+	KEY_M,
+	KEY_RADIO
+};
+
 static void ttusb_dec_set_model(struct ttusb_dec *dec,
 				enum ttusb_dec_model model);
 
+static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
+{
+	struct ttusb_dec * dec = urb->context;
+	char *buffer = dec->irq_buffer;
+	int retval;
+
+	switch(urb->status) {
+		case 0: /*success*/
+			break;
+		case -ECONNRESET:
+		case -ENOENT:
+		case -ESHUTDOWN:
+		case -ETIMEDOUT:
+			/* this urb is dead, cleanup */
+			dprintk("%s:urb shutting down with status: %d\n",
+					__FUNCTION__, urb->status);
+			return;
+		default:
+			dprintk("%s:nonzero status received: %d\n",
+					__FUNCTION__,urb->status);
+			goto exit;
+	}
+
+	if( (buffer[0] == 0x1) && (buffer[2] == 0x15) )  {
+		/* IR - Event */
+		/* this is an fact a bit too simple implementation;
+		 * the box also reports a keyrepeat signal
+		 * (with buffer[3] == 0x40) in an intervall of ~100ms.
+		 * But to handle this correctly we had to imlemenent some
+		 * kind of timer which signals a 'key up' event if no
+		 * keyrepeat signal is recieved for lets say 200ms.
+		 * this should/could be added later ...
+		 * for now lets report each signal as a key down and up*/
+		dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
+		input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1);
+		input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0);
+		input_sync(&dec->rc_input_dev);
+	}
+
+exit:	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if(retval)
+		printk("%s - usb_commit_urb failed with result: %d\n",
+			__FUNCTION__, retval);
+}
+
 static u16 crc16(u16 crc, const u8 *buf, size_t len)
 {
 	u16 tmp;
@@ -181,7 +268,7 @@ static int ttusb_dec_send_command(struct
 	u8 *b;
 
 	dprintk("%s\n", __FUNCTION__);
-	
+
 	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
 	if (!b)
 		return -ENOMEM;
@@ -208,7 +295,7 @@ static int ttusb_dec_send_command(struct
 	}
 
 	result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
-			      COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
 
 	if (result) {
 		printk("%s: command bulk message failed: error %d\n",
@@ -219,7 +306,7 @@ static int ttusb_dec_send_command(struct
 	}
 
 	result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
-			      COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
 
 	if (result) {
 		printk("%s: result bulk message failed: error %d\n",
@@ -320,9 +407,9 @@ static void ttusb_dec_set_pids(struct tt
 
 	ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
 
-		dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
+	dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
 			       ttusb_dec_audio_pes2ts_cb, dec);
-		dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
+	dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
 			       ttusb_dec_video_pes2ts_cb, dec);
 	dec->v_pes_length = 0;
 	dec->v_pes_postbytes = 0;
@@ -345,7 +432,7 @@ static void ttusb_dec_process_pva(struct
 	case 0x01: {		/* VideoStream */
 		int prebytes = pva[5] & 0x03;
 		int postbytes = (pva[5] & 0x0c) >> 2;
-			u16 v_pes_payload_length;
+		u16 v_pes_payload_length;
 
 		if (output_pva) {
 			dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
@@ -353,23 +440,23 @@ static void ttusb_dec_process_pva(struct
 			return;
 		}
 
-			if (dec->v_pes_postbytes > 0 &&
-			    dec->v_pes_postbytes == prebytes) {
-				memcpy(&dec->v_pes[dec->v_pes_length],
+		if (dec->v_pes_postbytes > 0 &&
+		    dec->v_pes_postbytes == prebytes) {
+			memcpy(&dec->v_pes[dec->v_pes_length],
 			       &pva[12], prebytes);
 
-				dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
+			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
 					  dec->v_pes_length + prebytes, 1);
-			}
+		}
 
 		if (pva[5] & 0x10) {
-				dec->v_pes[7] = 0x80;
-				dec->v_pes[8] = 0x05;
+			dec->v_pes[7] = 0x80;
+			dec->v_pes[8] = 0x05;
 
 			dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5);
 			dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |
 					 ((pva[9] & 0xc0) >> 6);
-				dec->v_pes[11] = 0x01 |
+			dec->v_pes[11] = 0x01 |
 					 ((pva[9] & 0x3f) << 2) |
 					 ((pva[10] & 0x80) >> 6);
 			dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |
@@ -379,33 +466,33 @@ static void ttusb_dec_process_pva(struct
 			memcpy(&dec->v_pes[14], &pva[12 + prebytes],
 			       length - 12 - prebytes);
 			dec->v_pes_length = 14 + length - 12 - prebytes;
-			} else {
-				dec->v_pes[7] = 0x00;
-				dec->v_pes[8] = 0x00;
+		} else {
+			dec->v_pes[7] = 0x00;
+			dec->v_pes[8] = 0x00;
 
 			memcpy(&dec->v_pes[9], &pva[8], length - 8);
 			dec->v_pes_length = 9 + length - 8;
-			}
+		}
 
-			dec->v_pes_postbytes = postbytes;
+		dec->v_pes_postbytes = postbytes;
 
-			if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
-			    dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
-			    dec->v_pes[11 + dec->v_pes[8]] == 0x01)
-				dec->v_pes[6] = 0x84;
-			else
-				dec->v_pes[6] = 0x80;
+		if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
+		    dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
+		    dec->v_pes[11 + dec->v_pes[8]] == 0x01)
+			dec->v_pes[6] = 0x84;
+		else
+			dec->v_pes[6] = 0x80;
 
-			v_pes_payload_length = htons(dec->v_pes_length - 6 +
-						     postbytes);
-			memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
-
-			if (postbytes == 0)
-				dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
-						  dec->v_pes_length, 1);
+		v_pes_payload_length = htons(dec->v_pes_length - 6 +
+					     postbytes);
+		memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
+
+		if (postbytes == 0)
+			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
+					  dec->v_pes_length, 1);
 
-			break;
-		}
+		break;
+	}
 
 	case 0x02:		/* MainAudioStream */
 		if (output_pva) {
@@ -487,7 +574,7 @@ static void ttusb_dec_process_packet(str
 	case TTUSB_DEC_PACKET_PVA:
 		if (dec->pva_stream_count)
 			ttusb_dec_process_pva(dec, dec->packet,
-						 dec->packet_payload_length);
+					      dec->packet_payload_length);
 		break;
 
 	case TTUSB_DEC_PACKET_SECTION:
@@ -513,7 +600,7 @@ static void swap_bytes(u8 *b, int length
 	}
 }
 
-static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b,
+static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
 					int length)
 {
 	swap_bytes(b, length);
@@ -562,7 +649,7 @@ static void ttusb_dec_process_urb_frame(
 						TTUSB_DEC_PACKET_EMPTY;
 					dec->packet_payload_length = 2;
 					dec->packet_state = 7;
-			} else {
+				} else {
 					printk("%s: unknown packet type: "
 					       "%02x%02x\n", __FUNCTION__,
 					       dec->packet[0], dec->packet[1]);
@@ -598,23 +685,23 @@ static void ttusb_dec_process_urb_frame(
 			int remainder = dec->packet_payload_length -
 					dec->packet_length;
 
-				if (length >= remainder) {
+			if (length >= remainder) {
 				memcpy(dec->packet + dec->packet_length,
-					       b, remainder);
+				       b, remainder);
 				dec->packet_length += remainder;
-					b += remainder;
-					length -= remainder;
+				b += remainder;
+				length -= remainder;
 				dec->packet_state++;
-				} else {
+			} else {
 				memcpy(&dec->packet[dec->packet_length],
-					       b, length);
+				       b, length);
 				dec->packet_length += length;
-					length = 0;
-				}
-
-				break;
+				length = 0;
 			}
 
+			break;
+		}
+
 		case 7: {
 			int tail = 4;
 
@@ -676,7 +763,6 @@ static void ttusb_dec_process_urb(struct
 
 		for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
 			struct usb_iso_packet_descriptor *d;
-
 			u8 *b;
 			int length;
 			struct urb_frame *frame;
@@ -782,7 +868,7 @@ static int ttusb_dec_set_interface(struc
 							b, NULL, NULL);
 			if (result)
 				return result;
-			result = usb_set_interface(dec->udev, 0, 7);
+			result = usb_set_interface(dec->udev, 0, 8);
 			break;
 		case TTUSB_DEC_INTERFACE_OUT:
 			result = usb_set_interface(dec->udev, 0, 1);
@@ -1067,7 +1153,7 @@ static int ttusb_dec_alloc_iso_urbs(stru
 					       ISO_FRAME_SIZE *
 					       (FRAMES_PER_ISO_BUF *
 						ISO_BUF_COUNT),
-				 	       &dec->iso_dma_handle);
+					       &dec->iso_dma_handle);
 
 	memset(dec->iso_buffer, 0,
 	       ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));
@@ -1096,6 +1182,31 @@ static void ttusb_dec_init_tasklet(struc
 		     (unsigned long)dec);
 }
 
+static void ttusb_init_rc( struct ttusb_dec *dec)
+{
+	u8 b[] = { 0x00, 0x01 };
+	int i;
+
+	init_input_dev(&dec->rc_input_dev);
+
+	dec->rc_input_dev.name = "ttusb_dec remote control";
+	dec->rc_input_dev.evbit[0] = BIT(EV_KEY);
+	dec->rc_input_dev.keycodesize = sizeof(u16);
+	dec->rc_input_dev.keycodemax = 0x1a;
+	dec->rc_input_dev.keycode = rc_keys;
+
+	 for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
+                set_bit(rc_keys[i], dec->rc_input_dev.keybit);
+
+	input_register_device(&dec->rc_input_dev);
+
+	if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) {
+		printk("%s: usb_submit_urb failed\n",__FUNCTION__);
+	}
+	/* enable irq pipe */
+	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
+}
+
 static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
 {
 	dprintk("%s\n", __FUNCTION__);
@@ -1106,7 +1217,7 @@ static void ttusb_dec_init_v_pes(struct 
 	dec->v_pes[3] = 0xe0;
 }
 
-static void ttusb_dec_init_usb(struct ttusb_dec *dec)
+static int ttusb_dec_init_usb(struct ttusb_dec *dec)
 {
 	dprintk("%s\n", __FUNCTION__);
 
@@ -1117,8 +1228,26 @@ static void ttusb_dec_init_usb(struct tt
 	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
 	dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
 	dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
+	dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
 
-	ttusb_dec_alloc_iso_urbs(dec);
+	if(enable_rc) {
+		dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if(!dec->irq_urb) {
+			return -ENOMEM;
+		}
+		dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
+					SLAB_ATOMIC, &dec->irq_dma_handle);
+		if(!dec->irq_buffer) {
+			return -ENOMEM;
+		}
+		usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
+				 dec->irq_buffer, IRQ_PACKET_SIZE,
+				 ttusb_dec_handle_irq, dec, 1);
+		dec->irq_urb->transfer_dma = dec->irq_dma_handle;
+		dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	}
+
+	return ttusb_dec_alloc_iso_urbs(dec);
 }
 
 static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1205,12 +1334,12 @@ static int ttusb_dec_boot_dsp(struct ttu
 		if (j >= ARM_PACKET_SIZE) {
 			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
 					      ARM_PACKET_SIZE, &actual_len,
-					      HZ / 10);
+					      100);
 			j = 0;
 		} else if (size < COMMAND_PACKET_SIZE) {
 			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
 					      j - COMMAND_PACKET_SIZE + size,
-					      &actual_len, HZ / 10);
+					      &actual_len, 100);
 		}
 	}
 
@@ -1244,7 +1373,7 @@ static int ttusb_dec_init_stb(struct ttu
 			result = ttusb_dec_boot_dsp(dec);
 			if (result)
 				return result;
-		else
+			else
 				return 1;
 		} else {
 			/* We can't trust the USB IDs that some firmwares
@@ -1273,7 +1402,7 @@ static int ttusb_dec_init_stb(struct ttu
 				dec->can_playback = 1;
 
 			return 0;
-	}
+		}
 	}
 	else
 		return result;
@@ -1306,7 +1435,7 @@ static int ttusb_dec_init_dvb(struct ttu
 		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
 		       result);
 
-		dvb_unregister_adapter(dec->adapter);
+		dvb_unregister_adapter(&dec->adapter);
 
 		return result;
 	}
@@ -1315,12 +1444,12 @@ static int ttusb_dec_init_dvb(struct ttu
 	dec->dmxdev.demux = &dec->demux.dmx;
 	dec->dmxdev.capabilities = 0;
 
-	if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 0) {
+	if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {
 		printk("%s: dvb_dmxdev_init failed: error %d\n",
 		       __FUNCTION__, result);
 
 		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(dec->adapter);
+		dvb_unregister_adapter(&dec->adapter);
 
 		return result;
 	}
@@ -1334,7 +1463,7 @@ static int ttusb_dec_init_dvb(struct ttu
 
 		dvb_dmxdev_release(&dec->dmxdev);
 		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(dec->adapter);
+		dvb_unregister_adapter(&dec->adapter);
 
 		return result;
 	}
@@ -1347,12 +1476,12 @@ static int ttusb_dec_init_dvb(struct ttu
 		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
 		dvb_dmxdev_release(&dec->dmxdev);
 		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(dec->adapter);
+		dvb_unregister_adapter(&dec->adapter);
 
 		return result;
 	}
 
-	dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx);
+	dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx);
 
 	return 0;
 }
@@ -1367,9 +1496,29 @@ static void ttusb_dec_exit_dvb(struct tt
 	dvb_dmxdev_release(&dec->dmxdev);
 	dvb_dmx_release(&dec->demux);
 	if (dec->fe) dvb_unregister_frontend(dec->fe);
-	dvb_unregister_adapter(dec->adapter);
+	dvb_unregister_adapter(&dec->adapter);
 }
 
+static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
+{
+
+	dprintk("%s\n", __FUNCTION__);
+	/* we have to check whether the irq URB is already submitted.
+	  * As the irq is submitted after the interface is changed,
+	  * this is the best method i figured out.
+	  * Any others?*/
+	if(dec->interface == TTUSB_DEC_INTERFACE_IN)
+		usb_kill_urb(dec->irq_urb);
+
+	usb_free_urb(dec->irq_urb);
+
+	usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
+		           dec->irq_buffer, dec->irq_dma_handle);
+
+	input_unregister_device(&dec->rc_input_dev);
+}
+
+
 static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
 {
 	int i;
@@ -1416,15 +1565,15 @@ static void ttusb_dec_exit_filters(struc
 	}
 }
 
-int fe_send_command(struct dvb_frontend* fe, const u8 command,
-		    int param_length, const u8 params[],
-		    int *result_length, u8 cmd_result[])
+static int fe_send_command(struct dvb_frontend* fe, const u8 command,
+			   int param_length, const u8 params[],
+			   int *result_length, u8 cmd_result[])
 {
 	struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
 	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
 }
 
-struct ttusbdecfe_config fe_config = {
+static struct ttusbdecfe_config fe_config = {
 	.send_command = fe_send_command
 };
 
@@ -1448,29 +1597,30 @@ static int ttusb_dec_probe(struct usb_in
 	memset(dec, 0, sizeof(struct ttusb_dec));
 
 	switch (le16_to_cpu(id->idProduct)) {
-		case 0x1006:
+	case 0x1006:
 		ttusb_dec_set_model(dec, TTUSB_DEC3000S);
-			break;
+		break;
 
-		case 0x1008:
+	case 0x1008:
 		ttusb_dec_set_model(dec, TTUSB_DEC2000T);
 		break;
 
 	case 0x1009:
 		ttusb_dec_set_model(dec, TTUSB_DEC2540T);
-			break;
+		break;
 	}
 
 	dec->udev = udev;
 
-	ttusb_dec_init_usb(dec);
+	if (ttusb_dec_init_usb(dec))
+		return 0;
 	if (ttusb_dec_init_stb(dec)) {
 		ttusb_dec_exit_usb(dec);
 		return 0;
 	}
 	ttusb_dec_init_dvb(dec);
 
-	dec->adapter->priv = dec;
+	dec->adapter.priv = dec;
 	switch (le16_to_cpu(id->idProduct)) {
 	case 0x1006:
 		dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
@@ -1487,7 +1637,7 @@ static int ttusb_dec_probe(struct usb_in
 		       le16_to_cpu(dec->udev->descriptor.idVendor),
 		       le16_to_cpu(dec->udev->descriptor.idProduct));
 	} else {
-		if (dvb_register_frontend(dec->adapter, dec->fe)) {
+		if (dvb_register_frontend(&dec->adapter, dec->fe)) {
 			printk("budget-ci: Frontend registration failed!\n");
 			if (dec->fe->ops->release)
 				dec->fe->ops->release(dec->fe);
@@ -1503,6 +1653,9 @@ static int ttusb_dec_probe(struct usb_in
 
 	ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
 
+	if(enable_rc)
+		ttusb_init_rc(dec);
+
 	return 0;
 }
 
@@ -1515,10 +1668,12 @@ static void ttusb_dec_disconnect(struct 
 	dprintk("%s\n", __FUNCTION__);
 
 	if (dec->active) {
-	ttusb_dec_exit_tasklet(dec);
+		ttusb_dec_exit_tasklet(dec);
 		ttusb_dec_exit_filters(dec);
-	ttusb_dec_exit_usb(dec);
-	ttusb_dec_exit_dvb(dec);
+		if(enable_rc)
+			ttusb_dec_exit_rc(dec);
+		ttusb_dec_exit_usb(dec);
+		ttusb_dec_exit_dvb(dec);
 	}
 
 	kfree(dec);
@@ -1557,9 +1712,9 @@ static struct usb_device_id ttusb_dec_ta
 
 static struct usb_driver ttusb_dec_driver = {
 	.name		= "ttusb-dec",
-      .probe		= ttusb_dec_probe,
-      .disconnect	= ttusb_dec_disconnect,
-      .id_table		= ttusb_dec_table,
+	.probe		= ttusb_dec_probe,
+	.disconnect	= ttusb_dec_disconnect,
+	.id_table	= ttusb_dec_table,
 };
 
 static int __init ttusb_dec_init(void)
@@ -1587,4 +1742,3 @@ MODULE_AUTHOR("Alex Woods <linux-dvb@gib
 MODULE_DESCRIPTION(DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
-
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -169,7 +169,7 @@ struct dvb_frontend* ttusbdecfe_dvbt_att
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
@@ -195,7 +195,7 @@ struct dvb_frontend* ttusbdecfe_dvbs_att
 	return &state->frontend;
 
 error:
-	if (state) kfree(state);
+	kfree(state);
 	return NULL;
 }
 
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -75,9 +75,7 @@ static int pcm20_getflags(struct pcm20_d
 
 	if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
 		return i;
-#ifdef DEBUG
-	printk("check_sig: 0x%x\n", i);
-#endif
+	pr_debug("check_sig: 0x%x\n", i);
 	if (i & 0x80) {
 		/* no signal from tuner */
 		*flags=0;
@@ -107,9 +105,7 @@ static int pcm20_getflags(struct pcm20_d
 
 	if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
 		return i;
-#ifdef DEBUG
-	printk("rds-signal: %d\n", buf);
-#endif
+	pr_debug("rds-signal: %d\n", buf);
 	if (buf > 15) {
 		printk("miropcm20-radio: RX strengths unexpected high...\n");
 		buf=15;
@@ -172,9 +168,7 @@ static int pcm20_do_ioctl(struct inode *
 			unsigned long *freq = arg;
 			pcm20->freq = *freq;
 			i=pcm20_setfreq(pcm20, pcm20->freq);
-#ifdef DEBUG
-			printk("First view (setfreq): 0x%x\n", i);
-#endif
+			pr_debug("First view (setfreq): 0x%x\n", i);
 			return i;
 		}
 		case VIDIOCGAUDIO:
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -326,13 +326,3 @@ static void __exit fmi_cleanup_module(vo
 
 module_init(fmi_init);
 module_exit(fmi_cleanup_module);
-
-#ifndef MODULE
-static int __init fmi_setup_io(char *str)
-{
-	get_option(&str, &io);
-	return 1;
-}
-
-__setup("sf16fm=", fmi_setup_io);
-#endif
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -29,7 +29,7 @@
 #include <linux/module.h>	/* Modules                        */
 #include <linux/init.h>		/* Initdata                       */
 #include <linux/ioport.h>	/* check_region, request_region   */
-#include <linux/delay.h>	/* udelay                 */
+#include <linux/delay.h>	/* udelay, msleep                 */
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
 #include <linux/videodev.h>	/* kernel radio structs           */
@@ -51,15 +51,6 @@ struct zol_device {
 	struct semaphore lock;
 };
 
-
-/* local things */
-
-static void sleep_delay(void)
-{
-	/* Sleep nicely for +/- 10 mS */
-	schedule();
-}
-
 static int zol_setvol(struct zol_device *dev, int vol)
 {
 	dev->curvol = vol;
@@ -76,7 +67,7 @@ static int zol_setvol(struct zol_device 
 	}
 
 	outb(dev->curvol-1, io);
-	sleep_delay();
+	msleep(10);
 	inb(io + 2);
 	up(&dev->lock);
 	return 0;
@@ -176,11 +167,10 @@ static int zol_getsigstr(struct zol_devi
 	down(&dev->lock);
 	outb(0x00, io);         /* This stuff I found to do nothing */
 	outb(dev->curvol, io);
-	sleep_delay();
-	sleep_delay();
+	msleep(20);
 
 	a = inb(io);
-	sleep_delay();
+	msleep(10);
 	b = inb(io);
 
 	up(&dev->lock);
@@ -202,11 +192,10 @@ static int zol_is_stereo (struct zol_dev
 	
 	outb(0x00, io);
 	outb(dev->curvol, io);
-	sleep_delay();
-	sleep_delay();
+	msleep(20);
 
 	x1 = inb(io);
-	sleep_delay();
+	msleep(10);
 	x2 = inb(io);
 
 	up(&dev->lock);
@@ -368,8 +357,7 @@ static int __init zoltrix_init(void)
 
 	outb(0, io);
 	outb(0, io);
-	sleep_delay();
-	sleep_delay();
+	msleep(20);
 	inb(io + 3);
 
 	zoltrix_unit.curvol = 0;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -240,6 +240,7 @@ config VIDEO_SAA7134
 	select VIDEO_BUF
 	select VIDEO_IR
 	select VIDEO_TUNER
+	select CRC32
 	---help---
 	  This is a video4linux driver for Philips SAA7130/7134 based
 	  TV cards.
@@ -249,7 +250,10 @@ config VIDEO_SAA7134
 
 config VIDEO_SAA7134_DVB
 	tristate "DVB Support for saa7134 based TV cards"
-	depends on VIDEO_SAA7134 && DVB_CORE && BROKEN
+	depends on VIDEO_SAA7134 && DVB_CORE
+	select VIDEO_BUF_DVB
+	select DVB_MT352
+	select DVB_CX22702
 	---help---
 	  This adds support for DVB cards based on the
 	  Philips saa7134 chip.
@@ -305,11 +309,14 @@ config VIDEO_HEXIUM_GEMINI
 
 config VIDEO_CX88
 	tristate "Conexant 2388x (bt878 successor) support"
-	depends on VIDEO_DEV && PCI && EXPERIMENTAL
+	depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
 	select I2C_ALGOBIT
+	select FW_LOADER
 	select VIDEO_BTCX
 	select VIDEO_BUF
 	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_IR
 	---help---
 	  This is a video4linux driver for Conexant 2388x based
 	  TV cards.
@@ -319,10 +326,12 @@ config VIDEO_CX88
 
 config VIDEO_CX88_DVB
 	tristate "DVB Support for cx2388x based TV cards"
-	depends on VIDEO_CX88 && DVB_CORE && BROKEN
+	depends on VIDEO_CX88 && DVB_CORE
 	select VIDEO_BUF_DVB
+	select DVB_MT352
+	select DVB_OR51132
 	---help---
-	  This adds support for DVB cards based on the
+	  This adds support for DVB/ATSC cards based on the
 	  Connexant 2388x chip.
 
 config VIDEO_OVCAMCHIP
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -7,6 +7,7 @@ bttv-objs	:=	bttv-driver.o bttv-cards.o 
 zoran-objs      :=	zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
+tuner-objs	:=	tuner-core.o tuner-simple.o mt20xx.o tda8290.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
 
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -130,7 +130,7 @@ adv7170_write_block (struct i2c_client *
 		u8 block_data[32];
 
 		msg.addr = client->addr;
-		msg.flags = client->flags;
+		msg.flags = 0;
 		while (len >= 2) {
 			msg.buf = (char *) block_data;
 			msg.len = 0;
@@ -402,7 +402,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int adv7170_i2c_id = 0;
 static struct i2c_driver i2c_driver_adv7170;
 
 static int
@@ -432,7 +431,6 @@ adv7170_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_adv7170;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = adv7170_i2c_id++;
 	if ((client->addr == I2C_ADV7170 >> 1) ||
 	    (client->addr == (I2C_ADV7170 >> 1) + 1)) {
 		dname = adv7170_name;
@@ -444,8 +442,7 @@ adv7170_detect_client (struct i2c_adapte
 		kfree(client);
 		return 0;
 	}
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"%s[%d]", dname, client->id);
+	strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
 
 	encoder = kmalloc(sizeof(struct adv7170), GFP_KERNEL);
 	if (encoder == NULL) {
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -126,7 +126,7 @@ adv7175_write_block (struct i2c_client *
 		u8 block_data[32];
 
 		msg.addr = client->addr;
-		msg.flags = client->flags;
+		msg.flags = 0;
 		while (len >= 2) {
 			msg.buf = (char *) block_data;
 			msg.len = 0;
@@ -452,7 +452,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int adv7175_i2c_id = 0;
 static struct i2c_driver i2c_driver_adv7175;
 
 static int
@@ -482,7 +481,6 @@ adv7175_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_adv7175;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = adv7175_i2c_id++;
 	if ((client->addr == I2C_ADV7175 >> 1) ||
 	    (client->addr == (I2C_ADV7175 >> 1) + 1)) {
 		dname = adv7175_name;
@@ -494,8 +492,7 @@ adv7175_detect_client (struct i2c_adapte
 		kfree(client);
 		return 0;
 	}
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"%s[%d]", dname, client->id);
+	strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
 
 	encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL);
 	if (encoder == NULL) {
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -146,7 +146,7 @@ bt819_write_block (struct i2c_client *cl
 		u8 block_data[32];
 
 		msg.addr = client->addr;
-		msg.flags = client->flags;
+		msg.flags = 0;
 		while (len >= 2) {
 			msg.buf = (char *) block_data;
 			msg.len = 0;
@@ -236,7 +236,8 @@ bt819_init (struct i2c_client *client)
 	init[0x07 * 2 - 1] = timing->hactive & 0xff;
 	init[0x08 * 2 - 1] = timing->hscale >> 8;
 	init[0x09 * 2 - 1] = timing->hscale & 0xff;
-	init[0x19*2-1] = decoder->norm == 0 ? 115 : 93;	/* Chroma burst delay */
+	/* 0x15 in array is address 0x19 */
+	init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93;	/* Chroma burst delay */
 	/* reset */
 	bt819_write(client, 0x1f, 0x00);
 	mdelay(1);
@@ -517,7 +518,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int bt819_i2c_id = 0;
 static struct i2c_driver i2c_driver_bt819;
 
 static int
@@ -546,7 +546,6 @@ bt819_detect_client (struct i2c_adapter 
 	client->adapter = adapter;
 	client->driver = &i2c_driver_bt819;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = bt819_i2c_id++;
 
 	decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
 	if (decoder == NULL) {
@@ -568,16 +567,13 @@ bt819_detect_client (struct i2c_adapter 
 	id = bt819_read(client, 0x17);
 	switch (id & 0xf0) {
 	case 0x70:
-	        snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-			 "bt819a[%d]", client->id);
+		strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
 		break;
 	case 0x60:
-		snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-			 "bt817a[%d]", client->id);
+		strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
 		break;
 	case 0x20:
-		snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-			 "bt815a[%d]", client->id);
+		strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
 		break;
 	default:
 		dprintk(1,
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -306,7 +306,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int bt856_i2c_id = 0;
 static struct i2c_driver i2c_driver_bt856;
 
 static int
@@ -335,9 +334,7 @@ bt856_detect_client (struct i2c_adapter 
 	client->adapter = adapter;
 	client->driver = &i2c_driver_bt856;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = bt856_i2c_id++;
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"bt856[%d]", client->id);
+	strlcpy(I2C_NAME(client), "bt856", sizeof(I2C_NAME(client)));
 
 	encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL);
 	if (encoder == NULL) {
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -1,5 +1,5 @@
 /*
-    $Id: btcx-risc.c,v 1.5 2004/12/10 12:33:39 kraxel Exp $
+    $Id: btcx-risc.c,v 1.6 2005/02/21 13:57:59 kraxel Exp $
 
     btcx-risc.c
 
@@ -52,12 +52,13 @@ void btcx_riscmem_free(struct pci_dev *p
 {
 	if (NULL == risc->cpu)
 		return;
-	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
-	memset(risc,0,sizeof(*risc));
 	if (debug) {
 		memcnt--;
-		printk("btcx: riscmem free [%d]\n",memcnt);
+		printk("btcx: riscmem free [%d] dma=%lx\n",
+		       memcnt, (unsigned long)risc->dma);
 	}
+	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+	memset(risc,0,sizeof(*risc));
 }
 
 int btcx_riscmem_alloc(struct pci_dev *pci,
@@ -78,7 +79,8 @@ int btcx_riscmem_alloc(struct pci_dev *p
 		risc->size = size;
 		if (debug) {
 			memcnt++;
-			printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt);
+			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
+			       memcnt, (unsigned long)dma, cpu, size);
 		}
 	}
 	memset(risc->cpu,0,risc->size);
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-cards.c,v 1.42 2005/01/13 17:22:33 kraxel Exp $
+    $Id: bttv-cards.c,v 1.47 2005/02/22 14:06:32 kraxel Exp $
 
     bttv-cards.c
 
@@ -80,6 +80,9 @@ static void picolo_tetra_init(struct btt
 static void tibetCS16_muxsel(struct bttv *btv, unsigned int input);
 static void tibetCS16_init(struct bttv *btv);
 
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input);
+static void kodicom4400r_init(struct bttv *btv);
+
 static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
 static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
 
@@ -101,6 +104,7 @@ static unsigned int pll[BTTV_MAX]    = {
 static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -170,6 +174,8 @@ static struct CARD {
 	// some cards ship with byteswapped IDs ...
 	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
 	{ 0xff00bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
+	// this seems to happen as well ...
+	{ 0xff1211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
 
 	{ 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
 	{ 0x263710b4, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
@@ -291,7 +297,7 @@ static struct CARD {
 	{ 0x07611461, BTTV_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
 	{ 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
 	{ 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
-	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB-T" },
+	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
 	{ 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
 	{ 0x07711461, BTTV_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
 	{ 0xdb1018ac, BTTV_DVICO_DVBT_LITE,    "DVICO FusionHDTV DVB-T Lite" },
@@ -1920,6 +1926,7 @@ struct tvcard bttv_tvcards[] = {
 	.svhs           = 2,
 	.muxsel         = { 2, 3, 1, 0},
 	.tuner_type     = TUNER_PHILIPS_ATSC,
+	.has_dvb        = 1,
 },{
 	.name           = "Twinhan DST + clones",
 	.no_msp34xx     = 1,
@@ -1939,7 +1946,6 @@ struct tvcard bttv_tvcards[] = {
         .no_tda9875     = 1,
         .no_tda7432     = 1,
         .tuner_type     = TUNER_ABSENT,
-        .no_video       = 1,
 	.pll            = PLL_28,
 },{
 	.name           = "Teppro TEV-560/InterVision IV-560",
@@ -2188,6 +2194,63 @@ struct tvcard bttv_tvcards[] = {
 		.no_tda7432	= 1,
 		.tuner_type     = -1,
 		.muxsel_hook    = tibetCS16_muxsel,
+},
+{
+	/* Bill Brack <wbrack@mmm.com.hk> */
+	/*
+	 * Note that, because of the card's wiring, the "master"
+	 * BT878A chip (i.e. the one which controls the analog switch
+	 * and must use this card type) is the 2nd one detected.  The
+	 * other 3 chips should use card type 0x85, whose description
+	 * follows this one.  There is a EEPROM on the card (which is
+	 * connected to the I2C of one of those other chips), but is
+	 * not currently handled.  There is also a facility for a
+	 * "monitor", which is also not currently implemented.
+	 */
+	.name		= "Kodicom 4400R (master)",
+	.video_inputs	= 16,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.tuner_type	= -1,
+	.svhs		= -1,
+	/* GPIO bits 0-9 used for analog switch:
+	 *   00 - 03:	camera selector
+	 *   04 - 06:	channel (controller) selector
+	 *   07:	data (1->on, 0->off)
+	 *   08:	strobe
+	 *   09:	reset
+	 * bit 16 is input from sync separator for the channel
+	 */
+	.gpiomask	= 0x0003ff,
+	.no_gpioirq     = 1,
+	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+	.pll		= PLL_28,
+	.no_msp34xx	= 1,
+	.no_tda7432	= 1,
+	.no_tda9875	= 1,
+	.muxsel_hook	= kodicom4400r_muxsel,
+},
+{
+	/* Bill Brack <wbrack@mmm.com.hk> */
+	/* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+	 * one which controls the analog switch, and must use the card type)
+	 * is the 2nd one detected.  The other 3 chips should use this card
+	 * type
+	 */
+	.name		= "Kodicom 4400R (slave)",
+	.video_inputs	= 16,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.tuner_type	= -1,
+	.svhs		= -1,
+	.gpiomask	= 0x010000,
+	.no_gpioirq     = 1,
+	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+	.pll		= PLL_28,
+	.no_msp34xx	= 1,
+	.no_tda7432	= 1,
+	.no_tda9875	= 1,
+	.muxsel_hook	= kodicom4400r_muxsel,
 }};
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2682,6 +2745,9 @@ void __devinit bttv_init_card2(struct bt
 	case BTTV_TIBET_CS16:
 		tibetCS16_init(btv);
 		break;
+	case BTTV_KODICOM_4400R:
+		kodicom4400r_init(btv);
+		break;
 	}
 
 	/* pll configuration */
@@ -2718,8 +2784,6 @@ void __devinit bttv_init_card2(struct bt
         }
 	btv->pll.pll_current = -1;
 
-	bttv_reset_audio(btv);
-
 	/* tuner configuration (from card list / autodetect / insmod option) */
  	if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
 		if(UNSET == btv->tuner_type)
@@ -3894,6 +3958,112 @@ static void tibetCS16_init(struct bttv *
 	gpio_write(0x0f7fff);
 }
 
+/*
+ * The following routines for the Kodicom-4400r get a little mind-twisting.
+ * There is a "master" controller and three "slave" controllers, together
+ * an analog switch which connects any of 16 cameras to any of the BT87A's.
+ * The analog switch is controlled by the "master", but the detection order
+ * of the four BT878A chips is in an order which I just don't understand.
+ * The "master" is actually the second controller to be detected.  The
+ * logic on the board uses logical numbers for the 4 controlers, but
+ * those numbers are different from the detection sequence.  When working
+ * with the analog switch, we need to "map" from the detection sequence
+ * over to the board's logical controller number.  This mapping sequence
+ * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
+ * unit 3, the second (which is the master) is logical unit 0, etc.
+ * We need to maintain the status of the analog switch (which of the 16
+ * cameras is connected to which of the 4 controllers).  Rather than
+ * add to the bttv structure for this, we use the data reserved for
+ * the mbox (unused for this card type).
+ */
+
+/*
+ * First a routine to set the analog switch, which controls which camera
+ * is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 7) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 8) latches the data value into the
+ * specified address.  The idea is to set the address and data, then bring
+ * STROBE high, and finally bring STROBE back to low.
+ */
+static void kodicom4400r_write(struct bttv *btv,
+			       unsigned char xaddr,
+			       unsigned char yaddr,
+			       unsigned char data) {
+	unsigned int udata;
+
+	udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf);
+	gpio_bits(0x1ff, udata);		/* write ADDR and DAT */
+	gpio_bits(0x1ff, udata | (1 << 8));	/* strobe high */
+	gpio_bits(0x1ff, udata);		/* strobe low */
+}
+
+/*
+ * Next the mux select.  Both the "master" and "slave" 'cards' (controllers)
+ * use this routine.  The routine finds the "master" for the card, maps
+ * the controller number from the detected position over to the logical
+ * number, writes the appropriate data to the analog switch, and housekeeps
+ * the local copy of the switch information.  The parameter 'input' is the
+ * requested camera number (0 - 15).
+ */
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
+{
+	char *sw_status;
+	int xaddr, yaddr;
+	struct bttv *mctlr;
+	static unsigned char map[4] = {3, 0, 2, 1};
+
+	mctlr = master[btv->c.nr];
+	if (mctlr == NULL) {	/* ignore if master not yet detected */
+		return;
+	}
+	yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
+	yaddr = map[yaddr];
+	sw_status = (char *)(&mctlr->mbox_we);
+	xaddr = input & 0xf;
+	/* Check if the controller/camera pair has changed, else ignore */
+	if (sw_status[yaddr] != xaddr)
+	{
+		/* "open" the old switch, "close" the new one, save the new */
+		kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
+		sw_status[yaddr] = xaddr;
+		kodicom4400r_write(mctlr, xaddr, yaddr, 1);
+	}
+}
+
+/*
+ * During initialisation, we need to reset the analog switch.  We
+ * also preset the switch to map the 4 connectors on the card to the
+ * *user's* (see above description of kodicom4400r_muxsel) channels
+ * 0 through 3
+ */
+static void kodicom4400r_init(struct bttv *btv)
+{
+	char *sw_status = (char *)(&btv->mbox_we);
+	int ix;
+
+	gpio_inout(0x0003ff, 0x0003ff);
+	gpio_write(1 << 9);	/* reset MUX */
+	gpio_write(0);
+	/* Preset camera 0 to the 4 controllers */
+	for (ix=0; ix<4; ix++) {
+		sw_status[ix] = ix;
+		kodicom4400r_write(btv, ix, ix, 1);
+	}
+	/*
+	 * Since this is the "master", we need to set up the
+	 * other three controller chips' pointers to this structure
+	 * for later use in the muxsel routine.
+	 */
+	if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3))
+	    return;
+	master[btv->c.nr-1] = btv;
+	master[btv->c.nr]   = btv;
+	master[btv->c.nr+1] = btv;
+	master[btv->c.nr+2] = btv;
+}
+
 // The Grandtec X-Guard framegrabber card uses two Dual 4-channel
 // video multiplexers to provide up to 16 video inputs. These
 // multiplexers are controlled by the lower 8 GPIO pins of the
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-driver.c,v 1.34 2005/01/07 13:11:19 kraxel Exp $
+    $Id: bttv-driver.c,v 1.37 2005/02/21 13:57:59 kraxel Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -3167,6 +3167,82 @@ static struct video_device radio_templat
 };
 
 /* ----------------------------------------------------------------------- */
+/* some debug code                                                         */
+
+static int bttv_risc_decode(u32 risc)
+{
+	static char *instr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = "write",
+		[ BT848_RISC_SKIP      >> 28 ] = "skip",
+		[ BT848_RISC_WRITEC    >> 28 ] = "writec",
+		[ BT848_RISC_JUMP      >> 28 ] = "jump",
+		[ BT848_RISC_SYNC      >> 28 ] = "sync",
+		[ BT848_RISC_WRITE123  >> 28 ] = "write123",
+		[ BT848_RISC_SKIP123   >> 28 ] = "skip123",
+		[ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
+	};
+	static int incr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = 2,
+		[ BT848_RISC_JUMP      >> 28 ] = 2,
+		[ BT848_RISC_SYNC      >> 28 ] = 2,
+		[ BT848_RISC_WRITE123  >> 28 ] = 5,
+		[ BT848_RISC_SKIP123   >> 28 ] = 2,
+		[ BT848_RISC_WRITE1S23 >> 28 ] = 3,
+	};
+	static char *bits[] = {
+		"be0",  "be1",  "be2",  "be3/resync",
+		"set0", "set1", "set2", "set3",
+		"clr0", "clr1", "clr2", "clr3",
+		"irq",  "res",  "eol",  "sol",
+	};
+	int i;
+
+	printk("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			printk(" %s",bits[i]);
+	printk(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+static void bttv_risc_disasm(struct bttv *btv,
+			     struct btcx_riscmem *risc)
+{
+	unsigned int i,j,n;
+
+	printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+	       btv->c.name, risc->cpu, (unsigned long)risc->dma);
+	for (i = 0; i < (risc->size >> 2); i += n) {
+		printk("%s:   0x%lx: ", btv->c.name,
+		       (unsigned long)(risc->dma + (i<<2)));
+		n = bttv_risc_decode(risc->cpu[i]);
+		for (j = 1; j < n; j++)
+			printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
+			       btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+			       risc->cpu[i+j], j);
+		if (0 == risc->cpu[i])
+			break;
+	}
+}
+
+static void bttv_print_riscaddr(struct bttv *btv)
+{
+	printk("  main: %08Lx\n",
+	       (unsigned long long)btv->main.dma);
+	printk("  vbi : o=%08Lx e=%08Lx\n",
+	       btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+	       btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
+	printk("  cap : o=%08Lx e=%08Lx\n",
+	       btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
+	       btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
+	printk("  scr : o=%08Lx e=%08Lx\n",
+	       btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
+	       btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
+	bttv_risc_disasm(btv, &btv->main);
+}
+
+/* ----------------------------------------------------------------------- */
 /* irq handler                                                             */
 
 static char *irq_name[] = {
@@ -3204,21 +3280,6 @@ static void bttv_print_irqbits(u32 print
 	}
 }
 
-static void bttv_print_riscaddr(struct bttv *btv)
-{
-	printk("  main: %08Lx\n",
-	       (unsigned long long)btv->main.dma);
-	printk("  vbi : o=%08Lx e=%08Lx\n",
-	       btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
-	       btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
-	printk("  cap : o=%08Lx e=%08Lx\n",
-	       btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
-	       btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
-	printk("  scr : o=%08Lx e=%08Lx\n",
-	       btv->screen ? (unsigned long long)btv->screen->top.dma  : 0,
-	       btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
-}
-
 static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
 {
 	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
@@ -3921,7 +3982,7 @@ static void __devexit bttv_remove(struct
         return;
 }
 
-static int bttv_suspend(struct pci_dev *pci_dev, u32 state)
+static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
         struct bttv *btv = pci_get_drvdata(pci_dev);
 	struct bttv_buffer_set idle;
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-gpio.c,v 1.6 2004/11/03 09:04:50 kraxel Exp $
+    $Id: bttv-gpio.c,v 1.7 2005/02/16 12:14:10 kraxel Exp $
 
     bttv-gpio.c  --  gpio sub drivers
 
@@ -94,6 +94,7 @@ int bttv_sub_del_devices(struct bttv_cor
 
 	list_for_each_safe(item,save,&core->subs) {
 		sub = list_entry(item,struct bttv_sub_device,list);
+		list_del(&sub->list);
 		device_unregister(&sub->dev);
 	}
 	return 0;
@@ -113,20 +114,6 @@ void bttv_gpio_irq(struct bttv_core *cor
 	}
 }
 
-void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach)
-{
-	struct bttv_sub_driver *drv;
-	struct bttv_sub_device *dev;
-	struct list_head *item;
-
-	list_for_each(item,&core->subs) {
-		dev = list_entry(item,struct bttv_sub_device,list);
-		drv = to_bttv_sub_drv(dev->dev.driver);
-		if (drv && drv->i2c_info)
-			drv->i2c_info(dev,client,attach);
-	}
-}
-
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-i2c.c,v 1.17 2004/12/14 15:33:30 kraxel Exp $
+    $Id: bttv-i2c.c,v 1.18 2005/02/16 12:14:10 kraxel Exp $
 
     bttv-i2c.c  --  all the i2c code is here
 
@@ -29,6 +29,7 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 
 #include "bttvp.h"
@@ -39,7 +40,6 @@ static struct i2c_adapter bttv_i2c_adap_
 static struct i2c_client bttv_i2c_client_template;
 
 static int attach_inform(struct i2c_client *client);
-static int detach_inform(struct i2c_client *client);
 
 static int i2c_debug = 0;
 static int i2c_hw = 0;
@@ -112,7 +112,6 @@ static struct i2c_adapter bttv_i2c_adap_
 	I2C_DEVNAME("bt848"),
 	.id                = I2C_HW_B_BT848,
 	.client_register   = attach_inform,
-	.client_unregister = detach_inform,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -132,17 +131,14 @@ static u32 functionality(struct i2c_adap
 static int
 bttv_i2c_wait_done(struct bttv *btv)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	int rc = 0;
 
-	add_wait_queue(&btv->i2c_queue, &wait);
-	if (0 == btv->i2c_done)
-		msleep_interruptible(20);
-	remove_wait_queue(&btv->i2c_queue, &wait);
-
-	if (0 == btv->i2c_done)
-		/* timeout */
-		rc = -EIO;
+	/* timeout */
+	if (wait_event_interruptible_timeout(btv->i2c_queue,
+		btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+
+	rc = -EIO;
+
 	if (btv->i2c_done & BT848_INT_RACK)
 		rc = 1;
 	btv->i2c_done = 0;
@@ -245,7 +241,7 @@ bttv_i2c_readbytes(struct bttv *btv, con
        	return retval;
 }
 
-static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
 	struct bttv *btv = i2c_get_adapdata(i2c_adap);
 	int retval = 0;
@@ -290,7 +286,6 @@ static struct i2c_adapter bttv_i2c_adap_
 	.id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
 	.algo          = &bttv_algo,
 	.client_register = attach_inform,
-	.client_unregister = detach_inform,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -305,22 +300,12 @@ static int attach_inform(struct i2c_clie
 	if (btv->pinnacle_id != UNSET)
 		bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
 				      &btv->pinnacle_id);
-	bttv_i2c_info(&btv->c, client, 1);
-
         if (bttv_debug)
 		printk("bttv%d: i2c attach [client=%s]\n",
 		       btv->c.nr, i2c_clientname(client));
         return 0;
 }
 
-static int detach_inform(struct i2c_client *client)
-{
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
-
-	bttv_i2c_info(&btv->c, client, 0);
-	return 0;
-}
-
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 {
 	if (0 != btv->i2c_rc)
@@ -330,7 +315,6 @@ void bttv_call_i2c_clients(struct bttv *
 
 static struct i2c_client bttv_i2c_client_template = {
 	I2C_DEVNAME("bttv internal"),
-        .id       = -1,
 };
 
 
@@ -379,6 +363,9 @@ int bttv_I2CWrite(struct bttv *btv, unsi
 /* read EEPROM content */
 void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
 {
+	memset(eedata, 0, 256);
+	if (0 != btv->i2c_rc)
+		return;
 	btv->i2c_client.addr = addr >> 1;
 	tveeprom_read(&btv->i2c_client, eedata, 256);
 }
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -1,5 +1,5 @@
 /*
- * $Id: bttv.h,v 1.14 2005/01/07 13:11:19 kraxel Exp $
+ * $Id: bttv.h,v 1.17 2005/02/22 14:06:32 kraxel Exp $
  *
  *  bttv - Bt848 frame grabber driver
  *
@@ -134,6 +134,7 @@
 #define BTTV_APAC_VIEWCOMP  0x7f
 #define BTTV_DVICO_DVBT_LITE  0x80
 #define BTTV_TIBET_CS16  0x83
+#define BTTV_KODICOM_4400R  0x84
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -302,8 +303,6 @@ struct bttv_sub_driver {
 	struct device_driver   drv;
 	char                   wanted[BUS_ID_SIZE];
 	void                   (*gpio_irq)(struct bttv_sub_device *sub);
-	void                   (*i2c_info)(struct bttv_sub_device *sub,
-					   struct i2c_client *client, int attach);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -1,5 +1,5 @@
 /*
-    $Id: bttvp.h,v 1.15 2004/12/14 15:33:30 kraxel Exp $
+    $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -209,7 +209,6 @@ extern struct bus_type bttv_sub_bus_type
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 void bttv_gpio_irq(struct bttv_core *core);
-void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach);
 
 
 /* ---------------------------------------------------------- */
@@ -230,7 +229,6 @@ extern int fini_bttv_i2c(struct bttv *bt
 /* our devices */
 #define BTTV_MAX 16
 extern unsigned int bttv_num;
-extern struct bttv bttvs[BTTV_MAX];
 
 #define BTTV_MAX_FBUF   0x208000
 #define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
@@ -377,6 +375,7 @@ struct bttv {
 	unsigned int users;
 	struct bttv_fh init;
 };
+extern struct bttv bttvs[BTTV_MAX];
 
 /* private ioctls */
 #define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -363,7 +363,7 @@ static long qc_capture(struct qcam_devic
 	size_t wantlen, outptr = 0;
 	char tmpbuf[BUFSZ];
 
-	if (verify_area(VERIFY_WRITE, buf, len))
+	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
 	/* Wait for camera to become ready */
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -308,7 +308,7 @@ static int WritePacket(struct usb_device
 			 packet[1] + (packet[0] << 8),
 			 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			 packet[2] + (packet[3] << 8), 
-			 packet[4] + (packet[5] << 8), buf, size, HZ);
+			 packet[4] + (packet[5] << 8), buf, size, 1000);
 }
 
 /****************************************************************************
@@ -325,7 +325,7 @@ static int ReadPacket(struct usb_device 
 			 packet[1] + (packet[0] << 8),
 			 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			 packet[2] + (packet[3] << 8), 
-			 packet[4] + (packet[5] << 8), buf, size, HZ);
+			 packet[4] + (packet[5] << 8), buf, size, 1000);
 }
 
 static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
@@ -440,7 +440,7 @@ static void cpia_usb_free_resources(stru
 
 	/* Unschedule all of the iso td's */
 	if (ucpia->sbuf[1].urb) {
-		usb_unlink_urb(ucpia->sbuf[1].urb);
+		usb_kill_urb(ucpia->sbuf[1].urb);
 		usb_free_urb(ucpia->sbuf[1].urb);
 		ucpia->sbuf[1].urb = NULL;
 	}
@@ -451,7 +451,7 @@ static void cpia_usb_free_resources(stru
 	}
  
 	if (ucpia->sbuf[0].urb) {
-		usb_unlink_urb(ucpia->sbuf[0].urb);
+		usb_kill_urb(ucpia->sbuf[0].urb);
 		usb_free_urb(ucpia->sbuf[0].urb);
 		ucpia->sbuf[0].urb = NULL;
 	}
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -1,4 +1,5 @@
-cx88xx-objs	:= cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o
+cx88xx-objs	:= cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
+		   cx88-input.o
 cx8800-objs	:= cx88-video.o cx88-vbi.o
 cx8802-objs	:= cx88-mpeg.o
 
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-blackbird.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $
  *
  *  Support for a cx23416 mpeg encoder via cx2388x host port.
  *  "blackbird" reference design.
@@ -25,6 +25,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
@@ -207,10 +208,6 @@ static int register_write(struct cx88_co
 	cx_read(P1_RADDR0);
 
 	return wait_ready_gpio0_bit1(core,1);
-#if 0
-	udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */
-	/* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */
-#endif
 }
 
 
@@ -283,7 +280,7 @@ static int blackbird_api_cmd(struct cx88
 	timeout = jiffies + msecs_to_jiffies(10);
 	for (;;) {
 		memory_read(dev->core, dev->mailbox, &flag);
-		if (0 == (flag & 4))
+		if (0 != (flag & 4))
 			break;
 		if (time_after(jiffies,timeout)) {
 			dprintk(0, "ERROR: API Mailbox timeout\n");
@@ -324,7 +321,7 @@ static int blackbird_find_mailbox(struct
 			signaturecnt = 0;
 		if (4 == signaturecnt) {
 			dprintk(1, "Mailbox signature found\n");
-			return i;
+			return i+1;
 		}
 	}
 	dprintk(0, "Mailbox signature values not found!\n");
@@ -427,7 +424,8 @@ static void blackbird_codec_settings(str
         blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
 
         /* assign frame size */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720);
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0,
+			  dev->height, dev->width);
 
         /* assign aspect ratio */
         blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
@@ -629,8 +627,8 @@ static int mpeg_do_ioctl(struct inode *i
 
 		memset(f,0,sizeof(*f));
 		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->fmt.pix.width        = 720;
-		f->fmt.pix.height       = 576;
+		f->fmt.pix.width        = dev->width;
+		f->fmt.pix.height       = dev->height;
 		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 		f->fmt.pix.sizeimage    = 1024 * 512 /* FIXME: BUFFER_SIZE */;
 	}
@@ -694,6 +692,10 @@ static int mpeg_open(struct inode *inode
 	file->private_data = fh;
 	fh->dev      = dev;
 
+	/* FIXME: locking against other video device */
+	cx88_set_scale(dev->core, dev->width, dev->height,
+		       V4L2_FIELD_INTERLACED);
+
 	videobuf_queue_init(&fh->mpegq, &blackbird_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -715,6 +717,7 @@ static int mpeg_release(struct inode *in
 	if (fh->mpegq.reading)
 		videobuf_read_stop(&fh->mpegq);
 
+	videobuf_mmap_free(&fh->mpegq);
 	file->private_data = NULL;
 	kfree(fh);
 	return 0;
@@ -821,6 +824,8 @@ static int __devinit blackbird_probe(str
 	memset(dev,0,sizeof(*dev));
 	dev->pci = pci_dev;
 	dev->core = core;
+	dev->width = 720;
+	dev->height = 480;
 
 	err = cx8802_init_common(dev);
 	if (0 != err)
@@ -852,6 +857,8 @@ static void __devexit blackbird_remove(s
 
 	/* common */
 	cx8802_fini_common(dev);
+	cx88_core_put(dev->core,dev->pci);
+	kfree(dev);
 }
 
 static struct pci_device_id cx8802_pci_tbl[] = {
@@ -885,7 +892,7 @@ static int blackbird_init(void)
 	printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
 	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-	return pci_module_init(&blackbird_pci_driver);
+	return pci_register_driver(&blackbird_pci_driver);
 }
 
 static void blackbird_fini(void)
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-cards.c,v 1.47 2004/11/03 09:04:50 kraxel Exp $
+ * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * card-specific stuff.
@@ -26,14 +26,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
-# define WITH_DVB 1
-#endif
-
 #include "cx88.h"
-#ifdef WITH_DVB
-#include "cx22702.h"
-#endif
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -59,6 +52,7 @@ struct cx88_board cx88_boards[] = {
 	[CX88_BOARD_HAUPPAUGE] = {
 		.name		= "Hauppauge WinTV 34xxx models",
 		.tuner_type     = UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -91,7 +85,7 @@ struct cx88_board cx88_boards[] = {
 	},
 	[CX88_BOARD_PIXELVIEW] = {
 		.name           = "PixelView",
-		.tuner_type     = UNSET,
+		.tuner_type     = 5,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -126,7 +120,7 @@ struct cx88_board cx88_boards[] = {
                         .gpio0  = 0x03fe,
 		}},
 	},
-        [CX88_BOARD_WINFAST2000XP] = {
+        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
                 .name           = "Leadtek Winfast 2000XP Expert",
                 .tuner_type     = 44,
 		.tda9887_conf   = TDA9887_PRESENT,
@@ -217,26 +211,55 @@ struct cx88_board cx88_boards[] = {
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
-                }},
+			.gpio0  = 0x0035e700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035e700,
+			.gpio3  = 0x02000000,
+		},{
+
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035c700,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x0035c700,
+			.gpio2  = 0x02000000,
+			.gpio3  = 0x02000000,
+		}},
                 .radio = {
-                        .type   = CX88_RADIO,
-                },
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0035d700,
+			.gpio1  = 0x00007004,
+			.gpio2  = 0x0035d700,
+			.gpio3  = 0x02000000,
+		 },
         },
         [CX88_BOARD_LEADTEK_PVR2000] = {
+		// gpio values for PAL version from regspy by DScaler
                 .name           = "Leadtek PVR 2000",
                 .tuner_type     = 38,
+		.tda9887_conf   = TDA9887_PRESENT,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
+                        .gpio0  = 0x0000bde6,
                 },{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
+                        .gpio0  = 0x0000bde6,
                 },{
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
+                        .gpio0  = 0x0000bde6,
                 }},
                 .radio = {
                         .type   = CX88_RADIO,
+                        .gpio0  = 0x0000bd62,
                 },
 		.blackbird = 1,
         },
@@ -320,14 +343,15 @@ struct cx88_board cx88_boards[] = {
                 .name           = "KWorld/VStream XPert DVB-T",
 		.tuner_type     = TUNER_ABSENT,
                 .input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                },{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
                 },{
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
                 }},
 		.dvb            = 1,
 	},
@@ -452,6 +476,131 @@ struct cx88_board cx88_boards[] = {
 		}},
 		.dvb            = 1,
 	},
+	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
+		.name	        = "digitalnow DNTV Live! DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.input	        = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_PCHDTV_HD3000] = {
+		.name           = "pcHDTV HD3000 HDTV",
+		.tuner_type     = TUNER_THOMSON_DTT7610,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00008484,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.vmux   = 2,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
+		// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
+		// GPIO values obtained from regspy, courtesy Sean Covel
+		.name        = "Hauppauge WinTV 28xxx (Roslyn) models",
+		.tuner_type  = UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xed12,  // internal decoder
+			.gpio2  = 0x00ff,
+		},{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,  // mono from tuner chip
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xed92,
+			.gpio2  = 0x00ff,
+		}},
+		.radio = {
+			 .type   = CX88_RADIO,
+			 .gpio0  = 0xed96,
+			 .gpio2  = 0x00ff,
+		 },
+		.blackbird = 1,
+	},
+	[CX88_BOARD_DIGITALLOGIC_MEC] = {
+		/* params copied over from Leadtek PVR 2000 */
+		.name           = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
+		/* not sure yet about the tuner type */
+		.tuner_type     = 38,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000bde6,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0000bde6,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000bde6,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0000bd62,
+		},
+		.blackbird = 1,
+	},
+	[CX88_BOARD_IODATA_GVBCTV7E] = {
+		.name           = "IODATA GV/BCTV7E",
+		.tuner_type     = TUNER_PHILIPS_FQ1286,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 1,
+			.gpio1  = 0x0000e03f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 2,
+			.gpio1  = 0x0000e07f,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 3,
+			.gpio1  = 0x0000e07f,
+		}}
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -482,11 +631,11 @@ struct cx88_subid cx88_subids[] = {
 	},{
                 .subvendor = 0x107d,
                 .subdevice = 0x6611,
-                .card      = CX88_BOARD_WINFAST2000XP,
+                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
 	},{
                 .subvendor = 0x107d,
                 .subdevice = 0x6613,	/* NTSC */
-                .card      = CX88_BOARD_WINFAST2000XP,
+                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
 	},{
 		.subvendor = 0x107d,
                 .subdevice = 0x6620,
@@ -543,6 +692,30 @@ struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x18AC,
 		.subdevice = 0xDB10,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
+	},{
+                .subvendor = 0x1554,
+                .subdevice = 0x4811,
+                .card      = CX88_BOARD_PIXELVIEW,
+	},{
+		.subvendor = 0x7063,
+		.subdevice = 0x3000, /* HD-3000 card */
+		.card      = CX88_BOARD_PCHDTV_HD3000,
+	},{
+		.subvendor = 0x17DE,
+		.subdevice = 0xA8A6,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x2801,
+		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
+	},{
+		.subvendor = 0x14F1,
+		.subdevice = 0x0342,
+		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
+	},{
+		.subvendor = 0x10fc,
+		.subdevice = 0xd035,
+		.card      = CX88_BOARD_IODATA_GVBCTV7E,
 	}
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -552,7 +725,7 @@ const unsigned int cx88_idcount = ARRAY_
 
 static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-	/* This is just for the Winfast 2000 XP board ATM; I don't have data on
+	/* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on
 	 * any others.
 	 *
 	 * Byte 0 is 1 on the NTSC board.
@@ -569,108 +742,27 @@ static void __devinit leadtek_eeprom(str
 	core->has_radio  = 1;
 	core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
 
-	printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: "
+	printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
 	       "tuner=%d, eeprom[0]=0x%02x\n",
 	       core->name, core->tuner_type, eeprom_data[0]);
 }
 
 
 /* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff                                           */
-
-static struct {
-        int  id;
-        char *name;
-} hauppauge_tuner[] __devinitdata = {
-        { TUNER_ABSENT,        "" },
-        { TUNER_ABSENT,        "External" },
-        { TUNER_ABSENT,        "Unspecified" },
-        { TUNER_PHILIPS_PAL,   "Philips FI1216" },
-        { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
-        { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
-        { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
-        { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
-        { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
-        { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
-        { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
-        { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
-        { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
-        { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
-        { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
-        { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
-        { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
-        { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
-        { TUNER_PHILIPS_PAL,   "Philips FM1216" },
-        { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
-        { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
-        { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
-        { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
-        { TUNER_ABSENT,        "Samsung TCPN9082D" },
-        { TUNER_ABSENT,        "Samsung TCPM9092P" },
-        { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
-        { TUNER_ABSENT,        "Samsung TCPN9085D" },
-        { TUNER_ABSENT,        "Samsung TCPB9085P" },
-        { TUNER_ABSENT,        "Samsung TCPL9091P" },
-        { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
-        { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
-        { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
-        { TUNER_ABSENT,        "Philips FI1256MP" },
-        { TUNER_ABSENT,        "Samsung TCPQ9091P" },
-        { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
-        { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
-        { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
-	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
-	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
-	{ TUNER_LG_NTSC_FM,    "LG TPI8NSR01F"},
-	{ TUNER_LG_PAL_FM,     "LG TPI8PSB01D"},
-	{ TUNER_LG_PAL,        "LG TPI8PSB11D"},
-	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
-	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
-};
 
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-	unsigned int blk2,tuner,radio,model;
+	struct tveeprom tv;
 
-	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) {
-		printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n",
-		       core->name);
-		return;
-	}
-
-	/* Block 2 starts after len+3 bytes header */
-	blk2 = eeprom_data[1] + 3;
-
-	/* decode + use some config infos */
-	model = eeprom_data[12] << 8 | eeprom_data[11];
-	tuner = eeprom_data[9];
-	radio = eeprom_data[blk2-1] & 0x01;
-
-        if (tuner < ARRAY_SIZE(hauppauge_tuner))
-                core->tuner_type = hauppauge_tuner[tuner].id;
-	if (radio)
-		core->has_radio = 1;
-
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, "
-	       "tuner=%s (%d), radio=%s\n",
-	       core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner)
-				   ? hauppauge_tuner[tuner].name : "?"),
-	       core->tuner_type, radio ? "yes" : "no");
+	tveeprom_hauppauge_analog(&tv, eeprom_data);
+	core->tuner_type = tv.tuner_type;
+	core->has_radio  = tv.has_radio;
 }
 
-#ifdef WITH_DVB
 static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee)
 {
 	int model;
 	int tuner;
-	char *tname;
 
 	/* Make sure we support the board model */
 	model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c];
@@ -689,26 +781,18 @@ static int hauppauge_eeprom_dvb(struct c
 	/* Make sure we support the tuner */
 	tuner = ee[0x2d];
 	switch(tuner) {
-	case 0x4B:
-		tname = "Thomson DTT 7595";
-		core->pll_type = PLLTYPE_DTT7595;
-		break;
-	case 0x4C:
-		tname = "Thomson DTT 7592";
-		core->pll_type = PLLTYPE_DTT7592;
+	case 0x4B: /* dtt 7595 */
+	case 0x4C: /* dtt 7592 */
 		break;
 	default:
 		printk("%s: error: unknown hauppauge tuner 0x%02x\n",
 		       core->name, tuner);
 		return -ENODEV;
 	}
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%s (%d)\n",
-	       core->name, model, tname, tuner);
-
-	core->pll_addr = 0x61;
-	core->demod_addr = 0x43;
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d\n",
+	       core->name, model, tuner);
+	return 0;
 }
-#endif
 
 /* ----------------------------------------------------------------------- */
 /* some GDI (was: Modular Technology) specific stuff                       */
@@ -763,36 +847,6 @@ static void gdi_eeprom(struct cx88_core 
 
 /* ----------------------------------------------------------------------- */
 
-static int
-i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len)
-{
-	unsigned char buf;
-	int err;
-
-	c->addr = 0xa0 >> 1;
-	buf = 0;
-	if (1 != (err = i2c_master_send(c,&buf,1))) {
-		printk(KERN_INFO "cx88: Huh, no eeprom present (err=%d)?\n",
-		       err);
-		return -1;
-	}
-	if (len != (err = i2c_master_recv(c,eedata,len))) {
-		printk(KERN_WARNING "cx88: i2c eeprom read error (err=%d)\n",
-		       err);
-		return -1;
-	}
-#if 0
-	for (i = 0; i < len; i++) {
-		if (0 == (i % 16))
-			printk(KERN_INFO "cx88 ee: %02x:",i);
-		printk(" %02x",eedata[i]);
-		if (15 == (i % 16))
-			printk("\n");
-	}
-#endif
-	return 0;
-}
-
 void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
 	int i;
@@ -823,41 +877,46 @@ void cx88_card_setup(struct cx88_core *c
 {
 	static u8 eeprom[128];
 
+	if (0 == core->i2c_rc) {
+		core->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
+	}
+
 	switch (core->board) {
 	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_ROSLYN:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		hauppauge_eeprom(core,eeprom+8);
+			hauppauge_eeprom(core,eeprom+8);
 		break;
 	case CX88_BOARD_GDI:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		gdi_eeprom(core,eeprom);
+			gdi_eeprom(core,eeprom);
 		break;
-	case CX88_BOARD_WINFAST2000XP:
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		leadtek_eeprom(core,eeprom);
+			leadtek_eeprom(core,eeprom);
+		break;
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		if (0 == core->i2c_rc)
+			hauppauge_eeprom_dvb(core,eeprom);
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		/* Tuner reset is hooked to  the tuner out of reset */
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		/* GPIO0:0 is hooked to mt352 reset pin */
 		cx_set(MO_GP0_IO, 0x00000101);
 		cx_clear(MO_GP0_IO, 0x00000001);
 		msleep(1);
 		cx_set(MO_GP0_IO, 0x00000101);
 		break;
-#ifdef WITH_DVB
-	case CX88_BOARD_HAUPPAUGE_DVB_T1:
-		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		hauppauge_eeprom_dvb(core,eeprom);
-		break;
-	case CX88_BOARD_CONEXANT_DVB_T1:
-		core->pll_type   = PLLTYPE_DTT7579;
-		core->pll_addr   = 0x60;
-		core->demod_addr = 0x43;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		cx_set(MO_GP0_IO, 0x00000707);
+		cx_set(MO_GP2_IO, 0x00000101);
+		cx_clear(MO_GP2_IO, 0x00000001);
+		msleep(1);
+		cx_clear(MO_GP0_IO, 0x00000007);
+		cx_set(MO_GP2_IO, 0x00000101);
 		break;
-#endif
 	}
 	if (cx88_boards[core->board].radio.type == CX88_RADIO)
 		core->has_radio = 1;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-core.c,v 1.15 2004/10/25 11:26:36 kraxel Exp $
+ * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * driver core
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -62,6 +63,10 @@ static unsigned int nicam = 0;
 module_param(nicam,int,0644);
 MODULE_PARM_DESC(nicam,"tv audio is nicam");
 
+static unsigned int nocomb = 0;
+module_param(nocomb,int,0644);
+MODULE_PARM_DESC(nocomb,"disable comb filter");
+
 #define dprintk(level,fmt, arg...)	if (core_debug >= level)	\
 	printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
 
@@ -424,7 +429,7 @@ int cx88_sram_channel_setup(struct cx88_
 /* ------------------------------------------------------------------ */
 /* debug helper code                                                  */
 
-int cx88_risc_decode(u32 risc)
+static int cx88_risc_decode(u32 risc)
 {
 	static char *instr[16] = {
 		[ RISC_SYNC    >> 28 ] = "sync",
@@ -462,6 +467,7 @@ int cx88_risc_decode(u32 risc)
 	return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
+#if 0 /* currently unused, but useful for debugging */
 void cx88_risc_disasm(struct cx88_core *core,
 		      struct btcx_riscmem *risc)
 {
@@ -479,6 +485,7 @@ void cx88_risc_disasm(struct cx88_core *
 			break;
 	}
 }
+#endif
 
 void cx88_sram_channel_dump(struct cx88_core *core,
 			    struct sram_channel *ch)
@@ -535,7 +542,7 @@ void cx88_sram_channel_dump(struct cx88_
 	       core->name,cx_read(ch->cnt2_reg));
 }
 
-char *cx88_pci_irqs[32] = {
+static char *cx88_pci_irqs[32] = {
 	"vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
 	"src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
 	"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
@@ -579,10 +586,19 @@ void cx88_print_irqbits(char *name, char
 
 /* ------------------------------------------------------------------ */
 
-void cx88_irq(struct cx88_core *core, u32 status, u32 mask)
+int cx88_core_irq(struct cx88_core *core, u32 status)
 {
-	cx88_print_irqbits(core->name, "irq pci",
-			   cx88_pci_irqs, status, mask);
+	int handled = 0;
+
+	if (status & (1<<18)) {
+		cx88_ir_irq(core);
+		handled++;
+	}
+	if (!handled)
+		cx88_print_irqbits(core->name, "irq pci",
+				   cx88_pci_irqs, status,
+				   core->pci_irqmask);
+	return handled;
 }
 
 void cx88_wakeup(struct cx88_core *core,
@@ -800,6 +816,8 @@ int cx88_set_scale(struct cx88_core *cor
 		value |= (1 << 0); // 3-tap interpolation
 	if (width < 193)
 		value |= (1 << 1); // 5-tap interpolation
+	if (nocomb)
+		value |= (3 << 5); // disable comb filter
 
 	cx_write(MO_FILTER_EVEN,  value);
 	cx_write(MO_FILTER_ODD,   value);
@@ -887,8 +905,8 @@ static int set_tvaudio(struct cx88_core 
 	cx88_set_tvaudio(core);
 	// cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
 
-	cx_write(MO_AUDD_LNGTH, 128/8);  /* fifo size */
-	cx_write(MO_AUDR_LNGTH, 128/8);  /* fifo size */
+	cx_write(MO_AUDD_LNGTH,    128); /* fifo size */
+	cx_write(MO_AUDR_LNGTH,    128); /* fifo size */
 	cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
 	return 0;
 }
@@ -969,6 +987,9 @@ int cx88_set_tvnorm(struct cx88_core *co
 	cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
 				 norm_vbipack(norm)));
 
+	// this is needed as well to set all tvnorm parameter
+	cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
+
 	// audio
 	set_tvaudio(core);
 
@@ -1105,9 +1126,10 @@ struct cx88_core* cx88_core_get(struct p
 		goto fail_unlock;
 
 	memset(core,0,sizeof(*core));
+	atomic_inc(&core->refcount);
 	core->pci_bus  = pci->bus->number;
 	core->pci_slot = PCI_SLOT(pci->devfn);
-	atomic_inc(&core->refcount);
+	core->pci_irqmask = 0x00fc00;
 
 	core->nr = cx88_devcount++;
 	sprintf(core->name,"cx88[%d]",core->nr);
@@ -1150,6 +1172,7 @@ struct cx88_core* cx88_core_get(struct p
 	cx88_reset(core);
 	cx88_i2c_init(core,pci);
 	cx88_card_setup(core);
+	cx88_ir_init(core,pci);
 
 	up(&devlist);
 	return core;
@@ -1170,6 +1193,7 @@ void cx88_core_put(struct cx88_core *cor
 		return;
 
 	down(&devlist);
+	cx88_ir_fini(core);
 	if (0 == core->i2c_rc)
 		i2c_bit_del_bus(&core->i2c_adap);
 	list_del(&core->devlist);
@@ -1182,12 +1206,11 @@ void cx88_core_put(struct cx88_core *cor
 /* ------------------------------------------------------------------ */
 
 EXPORT_SYMBOL(cx88_print_ioctl);
-EXPORT_SYMBOL(cx88_pci_irqs);
 EXPORT_SYMBOL(cx88_vid_irqs);
 EXPORT_SYMBOL(cx88_mpeg_irqs);
 EXPORT_SYMBOL(cx88_print_irqbits);
 
-EXPORT_SYMBOL(cx88_irq);
+EXPORT_SYMBOL(cx88_core_irq);
 EXPORT_SYMBOL(cx88_wakeup);
 EXPORT_SYMBOL(cx88_reset);
 EXPORT_SYMBOL(cx88_shutdown);
@@ -1197,8 +1220,6 @@ EXPORT_SYMBOL(cx88_risc_databuffer);
 EXPORT_SYMBOL(cx88_risc_stopper);
 EXPORT_SYMBOL(cx88_free_buffer);
 
-EXPORT_SYMBOL(cx88_risc_disasm);
-
 EXPORT_SYMBOL(cx88_sram_channels);
 EXPORT_SYMBOL(cx88_sram_channel_setup);
 EXPORT_SYMBOL(cx88_sram_channel_dump);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-dvb.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
@@ -30,10 +30,20 @@
 #include <linux/file.h>
 #include <linux/suspend.h>
 
+/* those two frontends need merging via linuxtv cvs ... */
+#define HAVE_CX22702 1
+#define HAVE_OR51132 1
+
 #include "cx88.h"
-#include "cx22702.h"
+#include "dvb-pll.h"
 #include "mt352.h"
-#include "mt352_priv.h" /* FIXME */
+#include "mt352_priv.h"
+#if HAVE_CX22702
+# include "cx22702.h"
+#endif
+#if HAVE_OR51132
+# include "or51132.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -81,7 +91,7 @@ static void dvb_buf_release(struct video
 	cx88_free_buffer(dev->pci, (struct cx88_buffer*)vb);
 }
 
-struct videobuf_queue_ops dvb_qops = {
+static struct videobuf_queue_ops dvb_qops = {
 	.buf_setup    = dvb_buf_setup,
 	.buf_prepare  = dvb_buf_prepare,
 	.buf_queue    = dvb_buf_queue,
@@ -110,111 +120,142 @@ static int dvico_fusionhdtv_demod_init(s
 	return 0;
 }
 
-#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-
-static int lg_z201_pll_set(struct dvb_frontend* fe,
-			   struct dvb_frontend_parameters* params, u8* pllbuf)
+static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 {
-	u32 div;
-	unsigned char cp = 0;
-	unsigned char bs = 0;
-
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency < 542000000) cp = 0xbc;
-	else if (params->frequency < 830000000) cp = 0xf4;
-	else cp = 0xfc;
-
-	if (params->frequency == 0) bs = 0x03;
-	else if (params->frequency < 157500000) bs = 0x01;
-	else if (params->frequency < 443250000) bs = 0x02;
-	else bs = 0x04;
-
-	pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */
-	pllbuf[1] = div >> 8;
-	pllbuf[2] = div & 0xff;
-	pllbuf[3] = cp;
-	pllbuf[4] = bs;
+	static u8 clock_config []  = { 0x89, 0x38, 0x39 };
+	static u8 reset []         = { 0x50, 0x80 };
+	static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+	                               0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 dntv_extra[]     = { 0xB5, 0x7A };
+	static u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
 
 	return 0;
 }
 
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe,
-				   struct dvb_frontend_parameters* params,
-				   u8* pllbuf)
-{
-	u32 div;
-	unsigned char cp = 0;
-	unsigned char bs = 0;
-
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency < 542000000) cp = 0xb4;
-	else if (params->frequency < 771000000) cp = 0xbc;
-	else cp = 0xf4;
-
-        if (params->frequency == 0) bs = 0x03;
-	else if (params->frequency < 443250000) bs = 0x02;
-	else bs = 0x08;
-
-	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
-	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = cp;
-   	pllbuf[4] = bs;
-
+static int mt352_pll_set(struct dvb_frontend* fe,
+			 struct dvb_frontend_parameters* params,
+			 u8* pllbuf)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+
+	pllbuf[0] = dev->core->pll_addr << 1;
+	dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
 	return 0;
 }
 
-struct mt352_config dvico_fusionhdtv_dvbt1 = {
+static struct mt352_config dvico_fusionhdtv = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = lg_z201_pll_set,
+	.pll_set       = mt352_pll_set,
 };
 
-struct mt352_config dvico_fusionhdtv_dvbt_plus = {
-	.demod_address = 0x0F,
-	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = thomson_dtt7579_pll_set,
+static struct mt352_config dntv_live_dvbt_config = {
+	.demod_address = 0x0f,
+	.demod_init    = dntv_live_dvbt_demod_init,
+	.pll_set       = mt352_pll_set,
+};
+
+#if HAVE_CX22702
+static struct cx22702_config connexant_refboard_config = {
+	.demod_address = 0x43,
+	.pll_address   = 0x60,
+	.pll_desc      = &dvb_pll_thomson_dtt7579,
+};
+
+static struct cx22702_config hauppauge_novat_config = {
+	.demod_address = 0x43,
+	.pll_address   = 0x61,
+	.pll_desc      = &dvb_pll_thomson_dtt759x,
+};
+#endif
+
+#if HAVE_OR51132
+static int or51132_set_ts_param(struct dvb_frontend* fe,
+				int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+	return 0;
+}
+
+static struct or51132_config pchdtv_hd3000 = {
+	.demod_address    = 0x15,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_thomson_dtt7610,
+	.set_ts_params    = or51132_set_ts_param,
 };
+#endif
 
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
 	dev->dvb.name = dev->core->name;
+	dev->ts_gen_cntrl = 0x0c;
 
 	/* init frontend */
 	switch (dev->core->board) {
+#if HAVE_CX22702
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
+						   &dev->core->i2c_adap);
+		break;
 	case CX88_BOARD_CONEXANT_DVB_T1:
-		dev->dvb.frontend = cx22702_create(&dev->core->i2c_adap,
-						   dev->core->pll_addr,
-						   dev->core->pll_type,
-						   dev->core->demod_addr);
+		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
+						   &dev->core->i2c_adap);
 		break;
+#endif
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1,
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_lg_z201;
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops->info.frequency_min = 174000000;
-			dev->dvb.frontend->ops->info.frequency_max = 862000000;
-		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt_plus,
+		dev->core->pll_addr = 0x60;
+		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops->info.frequency_min = 174000000;
-			dev->dvb.frontend->ops->info.frequency_max = 862000000;
-		}
 		break;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_unknown_1;
+		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
+						 &dev->core->i2c_adap);
+		break;
+#if HAVE_OR51132
+	case CX88_BOARD_PCHDTV_HD3000:
+		dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
+						 &dev->core->i2c_adap);
+		break;
+#endif
 	default:
-		printk("%s: FIXME: frontend handling not here yet ...\n",
+		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
 		break;
 	}
-	if (NULL == dev->dvb.frontend)
+	if (NULL == dev->dvb.frontend) {
+		printk("%s: frontend initialization failed\n",dev->core->name);
 		return -1;
+	}
+
+	if (dev->core->pll_desc) {
+		dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
+		dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+	}
 
 	/* Copy the board name into the DVB structure */
 	strlcpy(dev->dvb.frontend->ops->info.name,
@@ -222,7 +263,7 @@ static int dvb_register(struct cx8802_de
 		sizeof(dev->dvb.frontend->ops->info.name));
 
 	/* register everything */
-	return videobuf_dvb_register(&dev->dvb);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
 
 /* ----------------------------------------------------------- */
@@ -265,9 +306,11 @@ static int __devinit dvb_probe(struct pc
 			    dev);
 	err = dvb_register(dev);
 	if (0 != err)
-		goto fail_free;
+		goto fail_fini;
 	return 0;
 
+ fail_fini:
+	cx8802_fini_common(dev);
  fail_free:
 	kfree(dev);
  fail_core:
@@ -319,7 +362,7 @@ static int dvb_init(void)
 	printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
 	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-	return pci_module_init(&dvb_pci_driver);
+	return pci_register_driver(&dvb_pci_driver);
 }
 
 static void dvb_fini(void)
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-i2c.c,v 1.18 2004/10/13 10:39:00 kraxel Exp $
+    $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $
 
     cx88-i2c.c  --  all the i2c code is here
 
@@ -25,6 +25,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -44,7 +45,7 @@ MODULE_PARM_DESC(i2c_scan,"scan i2c bus 
 
 /* ----------------------------------------------------------------------- */
 
-void cx8800_bit_setscl(void *data, int state)
+static void cx8800_bit_setscl(void *data, int state)
 {
 	struct cx88_core *core = data;
 
@@ -56,7 +57,7 @@ void cx8800_bit_setscl(void *data, int s
 	cx_read(MO_I2C);
 }
 
-void cx8800_bit_setsda(void *data, int state)
+static void cx8800_bit_setsda(void *data, int state)
 {
 	struct cx88_core *core = data;
 
@@ -141,7 +142,6 @@ static struct i2c_adapter cx8800_i2c_ada
 
 static struct i2c_client cx8800_i2c_client_template = {
         I2C_DEVNAME("cx88xx internal"),
-        .id   = -1,
 };
 
 static char *i2c_devs[128] = {
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -0,0 +1,396 @@
+/*
+ * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $
+ *
+ * Device driver for GPIO attached remote control interfaces
+ * on Conexant 2388x based TV/DVB cards.
+ *
+ * Copyright (c) 2003 Pavel Machek
+ * Copyright (c) 2004 Gerd Knorr
+ * Copyright (c) 2004 Chris Pascoe
+ *
+ * This program is free software; you can redistribute it 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/delay.h>
+#include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <media/ir-common.h>
+
+#include "cx88.h"
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live DVB-T Remote */
+static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_ESC,         // 'go up a level?'
+	[ 0x01 ] = KEY_KP1,         // '1'
+	[ 0x02 ] = KEY_KP2,         // '2'
+	[ 0x03 ] = KEY_KP3,         // '3'
+	[ 0x04 ] = KEY_KP4,         // '4'
+	[ 0x05 ] = KEY_KP5,         // '5'
+	[ 0x06 ] = KEY_KP6,         // '6'
+	[ 0x07 ] = KEY_KP7,         // '7'
+	[ 0x08 ] = KEY_KP8,         // '8'
+	[ 0x09 ] = KEY_KP9,         // '9'
+	[ 0x0a ] = KEY_KP0,         // '0'
+	[ 0x0b ] = KEY_TUNER,       // 'tv/fm'
+	[ 0x0c ] = KEY_SEARCH,      // 'scan'
+	[ 0x0d ] = KEY_STOP,        // 'stop'
+	[ 0x0e ] = KEY_PAUSE,       // 'pause'
+	[ 0x0f ] = KEY_LIST,        // 'source'
+
+	[ 0x10 ] = KEY_MUTE,        // 'mute'
+	[ 0x11 ] = KEY_REWIND,      // 'backward <<'
+	[ 0x12 ] = KEY_POWER,       // 'power'
+	[ 0x13 ] = KEY_S,           // 'snap'
+	[ 0x14 ] = KEY_AUDIO,       // 'stereo'
+	[ 0x15 ] = KEY_CLEAR,       // 'reset'
+	[ 0x16 ] = KEY_PLAY,        // 'play'
+	[ 0x17 ] = KEY_ENTER,       // 'enter'
+	[ 0x18 ] = KEY_ZOOM,        // 'full screen'
+	[ 0x19 ] = KEY_FASTFORWARD, // 'forward >>'
+	[ 0x1a ] = KEY_CHANNELUP,   // 'channel +'
+	[ 0x1b ] = KEY_VOLUMEUP,    // 'volume +'
+	[ 0x1c ] = KEY_INFO,        // 'preview'
+	[ 0x1d ] = KEY_RECORD,      // 'record'
+	[ 0x1e ] = KEY_CHANNELDOWN, // 'channel -'
+	[ 0x1f ] = KEY_VOLUMEDOWN,  // 'volume -'
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* IO-DATA BCTV7E Remote */
+static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
+	[ 0x40 ] = KEY_TV,              // TV
+	[ 0x20 ] = KEY_RADIO,           // FM
+	[ 0x60 ] = KEY_EPG,             // EPG
+	[ 0x00 ] = KEY_POWER,           // power
+
+	[ 0x50 ] = KEY_KP1,             // 1
+	[ 0x30 ] = KEY_KP2,             // 2
+	[ 0x70 ] = KEY_KP3,             // 3
+	[ 0x10 ] = KEY_L,               // Live
+
+	[ 0x48 ] = KEY_KP4,             // 4
+	[ 0x28 ] = KEY_KP5,             // 5
+	[ 0x68 ] = KEY_KP6,             // 6
+	[ 0x08 ] = KEY_T,               // Time Shift
+
+	[ 0x58 ] = KEY_KP7,             // 7
+	[ 0x38 ] = KEY_KP8,             // 8
+	[ 0x78 ] = KEY_KP9,             // 9
+	[ 0x18 ] = KEY_PLAYPAUSE,       // Play
+
+	[ 0x44 ] = KEY_KP0,             // 10
+	[ 0x24 ] = KEY_ENTER,           // 11
+	[ 0x64 ] = KEY_ESC,             // 12
+	[ 0x04 ] = KEY_M,               // Multi
+
+	[ 0x54 ] = KEY_VIDEO,           // VIDEO
+	[ 0x34 ] = KEY_CHANNELUP,       // channel +
+	[ 0x74 ] = KEY_VOLUMEUP,        // volume +
+	[ 0x14 ] = KEY_MUTE,            // Mute
+
+	[ 0x4c ] = KEY_S,               // SVIDEO
+	[ 0x2c ] = KEY_CHANNELDOWN,     // channel -
+	[ 0x6c ] = KEY_VOLUMEDOWN,      // volume -
+	[ 0x0c ] = KEY_ZOOM,            // Zoom
+
+	[ 0x5c ] = KEY_PAUSE,           // pause
+	[ 0x3c ] = KEY_C,               // || (red)
+	[ 0x7c ] = KEY_RECORD,          // recording
+	[ 0x1c ] = KEY_STOP,            // stop
+
+	[ 0x41 ] = KEY_REWIND,          // backward <<
+	[ 0x21 ] = KEY_PLAY,            // play
+	[ 0x61 ] = KEY_FASTFORWARD,     // forward >>
+	[ 0x01 ] = KEY_NEXT,            // skip >|
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct cx88_IR {
+	struct cx88_core	*core;
+	struct input_dev        input;
+	struct ir_input_state   ir;
+	char                    name[32];
+	char                    phys[32];
+
+	/* sample from gpio pin 16 */
+	int                     sampling;
+	u32                     samples[16];
+	int                     scount;
+	unsigned long           release;
+
+	/* poll external decoder */
+	int                     polling;
+	struct work_struct      work;
+	struct timer_list       timer;
+	u32			gpio_addr;
+	u32                     last_gpio;
+	u32                     mask_keycode;
+	u32                     mask_keydown;
+	u32                     mask_keyup;
+};
+
+static int ir_debug = 0;
+module_param(ir_debug, int, 0644);    /* debug level [IR] */
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
+
+#define ir_dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static void cx88_ir_handle_key(struct cx88_IR *ir)
+{
+	struct cx88_core *core = ir->core;
+	u32 gpio, data;
+
+	/* read gpio value */
+	gpio = cx_read(ir->gpio_addr);
+	if (ir->polling) {
+		if (ir->last_gpio == gpio)
+			return;
+		ir->last_gpio = gpio;
+	}
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+	ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
+		gpio, data,
+		ir->polling               ? "poll"  : "irq",
+		(gpio & ir->mask_keydown) ? " down" : "",
+		(gpio & ir->mask_keyup)   ? " up"   : "");
+
+	if (ir->mask_keydown) {
+		/* bit set on keydown */
+		if (gpio & ir->mask_keydown) {
+			ir_input_keydown(&ir->input,&ir->ir,data,data);
+		} else {
+			ir_input_nokey(&ir->input,&ir->ir);
+		}
+
+	} else if (ir->mask_keyup) {
+		/* bit cleared on keydown */
+		if (0 == (gpio & ir->mask_keyup)) {
+			ir_input_keydown(&ir->input,&ir->ir,data,data);
+		} else {
+			ir_input_nokey(&ir->input,&ir->ir);
+		}
+
+	} else {
+		/* can't distinguish keydown/up :-/ */
+		ir_input_keydown(&ir->input,&ir->ir,data,data);
+		ir_input_nokey(&ir->input,&ir->ir);
+	}
+}
+
+static void ir_timer(unsigned long data)
+{
+	struct cx88_IR *ir = (struct cx88_IR*)data;
+
+	schedule_work(&ir->work);
+}
+
+static void cx88_ir_work(void *data)
+{
+	struct cx88_IR *ir = data;
+	unsigned long timeout;
+
+	cx88_ir_handle_key(ir);
+	timeout = jiffies + (ir->polling * HZ / 1000);
+	mod_timer(&ir->timer, timeout);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
+{
+	struct cx88_IR *ir;
+	IR_KEYTAB_TYPE *ir_codes = NULL;
+	int ir_type = IR_TYPE_OTHER;
+
+	ir = kmalloc(sizeof(*ir),GFP_KERNEL);
+	if (NULL == ir)
+		return -ENOMEM;
+	memset(ir,0,sizeof(*ir));
+
+	/* detect & configure */
+	switch (core->board) {
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		ir_codes         = ir_codes_dntv_live_dvb_t;
+		ir->gpio_addr    = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup   = 0x60;
+		ir->polling      = 50; // ms
+		break;
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		ir_codes         = ir_codes_hauppauge_new;
+		ir_type          = IR_TYPE_RC5;
+		ir->sampling     = 1;
+		break;
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
+		ir_codes         = ir_codes_winfast;
+		ir->gpio_addr    = MO_GP0_IO;
+		ir->mask_keycode = 0x8f8;
+		ir->mask_keyup   = 0x100;
+		ir->polling      = 1; // ms
+		break;
+	case CX88_BOARD_IODATA_GVBCTV7E:
+		ir_codes         = ir_codes_iodata_bctv7e;
+		ir->gpio_addr    = MO_GP0_IO;
+		ir->mask_keycode = 0xfd;
+		ir->mask_keydown = 0x02;
+		ir->polling      = 5; // ms
+		break;
+	}
+	if (NULL == ir_codes) {
+		kfree(ir);
+		return -ENODEV;
+	}
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
+		 cx88_boards[core->board].name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+		 pci_name(pci));
+
+	ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes);
+	ir->input.name = ir->name;
+	ir->input.phys = ir->phys;
+	ir->input.id.bustype = BUS_PCI;
+	ir->input.id.version = 1;
+	if (pci->subsystem_vendor) {
+		ir->input.id.vendor  = pci->subsystem_vendor;
+		ir->input.id.product = pci->subsystem_device;
+	} else {
+		ir->input.id.vendor  = pci->vendor;
+		ir->input.id.product = pci->device;
+	}
+
+	/* record handles to ourself */
+	ir->core = core;
+	core->ir = ir;
+
+	if (ir->polling) {
+		INIT_WORK(&ir->work, cx88_ir_work, ir);
+		init_timer(&ir->timer);
+		ir->timer.function = ir_timer;
+		ir->timer.data     = (unsigned long)ir;
+		schedule_work(&ir->work);
+	}
+	if (ir->sampling) {
+		core->pci_irqmask |= (1<<18);   // IR_SMP_INT
+		cx_write(MO_DDS_IO, 0xa80a80);  // 4 kHz sample rate
+		cx_write(MO_DDSCFG_IO,   0x5);  // enable
+	}
+
+	/* all done */
+	input_register_device(&ir->input);
+	printk("%s: registered IR remote control\n", core->name);
+
+	return 0;
+}
+
+int cx88_ir_fini(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+
+	/* skip detach on non attached boards */
+	if (NULL == ir)
+		return 0;
+
+	if (ir->polling) {
+		del_timer(&ir->timer);
+		flush_scheduled_work();
+	}
+
+	input_unregister_device(&ir->input);
+	kfree(ir);
+
+	/* done */
+	core->ir = NULL;
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void cx88_ir_irq(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+	u32 samples,rc5;
+	int i;
+
+	if (NULL == ir)
+		return;
+	if (!ir->sampling)
+		return;
+
+	samples = cx_read(MO_SAMPLE_IO);
+	if (0 != samples  &&  0xffffffff != samples) {
+		/* record sample data */
+		if (ir->scount < ARRAY_SIZE(ir->samples))
+			ir->samples[ir->scount++] = samples;
+		return;
+	}
+	if (!ir->scount) {
+		/* nothing to sample */
+		if (ir->ir.keypressed && time_after(jiffies,ir->release))
+			ir_input_nokey(&ir->input,&ir->ir);
+		return;
+	}
+
+	/* have a complete sample */
+	if (ir->scount < ARRAY_SIZE(ir->samples))
+		ir->samples[ir->scount++] = samples;
+	for (i = 0; i < ir->scount; i++)
+		ir->samples[i] = ~ir->samples[i];
+	if (ir_debug)
+		ir_dump_samples(ir->samples,ir->scount);
+
+	/* decode it */
+	switch (core->board) {
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7);
+		ir_dprintk("biphase decoded: %x\n",rc5);
+		if ((rc5 & 0xfffff000) != 0x3000)
+			break;
+		ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5);
+		ir->release = jiffies + msecs_to_jiffies(120);
+		break;
+	}
+
+	ir->scount = 0;
+	return;
+}
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
+MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-mpeg.c,v 1.14 2004/10/25 11:26:36 kraxel Exp $
+ * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $
  *
  *  Support for the mpeg transport stream transfers
  *  PCI function #2 of the cx2388x.
@@ -24,6 +24,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
@@ -68,8 +69,14 @@ static int cx8802_start_dma(struct cx880
 	 * also: move to cx88-blackbird + cx88-dvb source files? */
 
 	if (cx88_boards[core->board].dvb) {
-		/* Setup TS portion of chip */
-		cx_write(TS_GEN_CNTRL, 0x0c);
+		/* negedge driven & software reset */
+		cx_write(TS_GEN_CNTRL, 0x40);
+		udelay(100);
+		cx_write(MO_PINMUX_IO, 0x00);
+		cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00);
+		cx_write(TS_SOP_STAT,0x00);
+		cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
+		udelay(100);
 	}
 
 	if (cx88_boards[core->board].blackbird) {
@@ -93,7 +100,7 @@ static int cx8802_start_dma(struct cx880
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc04);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
 	cx_write(MO_TS_INTMSK,  0x1f0011);
 
 	/* start dma */
@@ -292,19 +299,18 @@ static irqreturn_t cx8802_irq(int irq, v
 {
 	struct cx8802_dev *dev = dev_id;
 	struct cx88_core *core = dev->core;
-	u32 status, mask;
+	u32 status;
 	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x04);
-		mask   = cx_read(MO_PCI_INTMSK);
-		if (0 == (status & mask))
+		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
+		if (0 == status)
 			goto out;
 		handled = 1;
 		cx_write(MO_PCI_INTSTAT, status);
 
-		if (status & mask & ~0x1f)
-			cx88_irq(core,status,mask);
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
 		if (status & 0x04)
 			cx8802_mpeg_irq(dev);
 	};
@@ -323,6 +329,7 @@ static irqreturn_t cx8802_irq(int irq, v
 
 int cx8802_init_common(struct cx8802_dev *dev)
 {
+	struct cx88_core *core = dev->core;
 	int err;
 
 	/* pci init */
@@ -354,11 +361,6 @@ int cx8802_init_common(struct cx8802_dev
 	cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
 			  MO_TS_DMACNTRL,0x11,0x00);
 
-#if 0 /* FIXME */
-	/* initialize hardware */
-	cx8802_reset(dev);
-#endif
-
 	/* get irq */
 	err = request_irq(dev->pci->irq, cx8802_irq,
 			  SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev);
@@ -367,11 +369,7 @@ int cx8802_init_common(struct cx8802_dev
 		       dev->core->name, dev->pci->irq);
 		return err;
 	}
-
-#if 0 /* FIXME */
-	/* register i2c bus + load i2c helpers */
-	cx88_card_setup(dev);
-#endif
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* everything worked */
 	pci_set_drvdata(dev->pci,dev);
@@ -393,7 +391,7 @@ void cx8802_fini_common(struct cx8802_de
 
 /* ----------------------------------------------------------- */
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state)
+int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
         struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -413,7 +411,7 @@ int cx8802_suspend_common(struct pci_dev
 #endif
 
 	pci_save_state(pci_dev);
-	if (0 != pci_set_power_state(pci_dev, state)) {
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
 		pci_disable_device(pci_dev);
 		dev->state.disabled = 1;
 	}
@@ -429,7 +427,7 @@ int cx8802_resume_common(struct pci_dev 
 		pci_enable_device(pci_dev);
 		dev->state.disabled = 0;
 	}
-	pci_set_power_state(pci_dev, 0);
+	pci_set_power_state(pci_dev, PCI_D0);
 	pci_restore_state(pci_dev);
 
 #if 1
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $
+    $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $
 
     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
 
@@ -37,6 +37,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -56,7 +57,7 @@
 
 #include "cx88.h"
 
-static unsigned int audio_debug = 1;
+static unsigned int audio_debug = 0;
 module_param(audio_debug,int,0644);
 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
 
@@ -141,6 +142,13 @@ static void set_audio_finish(struct cx88
 {
 	u32 volume;
 
+	if (cx88_boards[core->board].blackbird) {
+		// 'pass-thru mode': this enables the i2s output to the mpeg encoder
+		cx_set(AUD_CTL, 0x2000);
+		cx_write(AUD_I2SOUTPUTCNTL, 1);
+		//cx_write(AUD_APB_IN_RATE_ADJ, 0);
+	}
+
 	// finish programming
 	cx_write(AUD_SOFT_RESET, 0x0000);
 
@@ -263,6 +271,7 @@ static void set_audio_standard_BTSC(stru
 	set_audio_finish(core);
 }
 
+#if 0
 static void set_audio_standard_NICAM(struct cx88_core *core)
 {
 	static const struct rlist nicam_common[] = {
@@ -335,128 +344,243 @@ static void set_audio_standard_NICAM(str
 	};
         set_audio_finish(core);
 }
+#endif
 
-static void set_audio_standard_NICAM_L(struct cx88_core *core)
+static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
 {
-	/* This is officially weird.. register dumps indicate windows
-	 * uses audio mode 4.. A2. Let's operate and find out. */
+        /* This is probably weird..
+         * Let's operate and find out. */
 
-	static const struct rlist nicam_l[] = {
-		// setup QAM registers
-		{ AUD_PDF_DDS_CNST_BYTE2,	   0x48 },
-		{ AUD_PDF_DDS_CNST_BYTE1,          0x3d },
-		{ AUD_PDF_DDS_CNST_BYTE0,          0xf5 },
-		{ AUD_QAM_MODE,                    0x00 },
-		{ AUD_PHACC_FREQ_8MSB,             0x3a },
-		{ AUD_PHACC_FREQ_8LSB,             0x4a },
-
-		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_IIR1_0_SEL,                  0x00000000 },
-		{ AUD_IIR1_1_SEL,                  0x00000002 },
-		{ AUD_IIR1_2_SEL,                  0x00000023 },
-		{ AUD_IIR1_3_SEL,                  0x00000004 },
-		{ AUD_IIR1_4_SEL,                  0x00000005 },
-		{ AUD_IIR1_5_SEL,                  0x00000007 },
-		{ AUD_IIR1_0_SHIFT,                0x00000007 },
-		{ AUD_IIR1_1_SHIFT,                0x00000000 },
-		{ AUD_IIR1_2_SHIFT,                0x00000000 },
-		{ AUD_IIR1_3_SHIFT,                0x00000007 },
-		{ AUD_IIR1_4_SHIFT,                0x00000007 },
-		{ AUD_IIR1_5_SHIFT,                0x00000007 },
-		{ AUD_IIR2_0_SEL,                  0x00000002 },
-		{ AUD_IIR2_1_SEL,                  0x00000003 },
-		{ AUD_IIR2_2_SEL,                  0x00000004 },
-		{ AUD_IIR2_3_SEL,                  0x00000005 },
-		{ AUD_IIR3_0_SEL,                  0x00000007 },
-		{ AUD_IIR3_1_SEL,                  0x00000023 },
-		{ AUD_IIR3_2_SEL,                  0x00000016 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000000 },
-		{ AUD_IIR3_2_SHIFT,                0x00000002 },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_IIR4_1_SEL,                  0x00000019 },
-		{ AUD_IIR4_2_SEL,                  0x00000008 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000007 },
-		{ AUD_IIR4_2_SHIFT,                0x00000007 },
-		{ AUD_IIR4_0_CA0,                  0x0003e57e },
-		{ AUD_IIR4_0_CA1,                  0x00005e11 },
-		{ AUD_IIR4_0_CA2,                  0x0003a7cf },
-		{ AUD_IIR4_0_CB0,                  0x00002368 },
-		{ AUD_IIR4_0_CB1,                  0x0003bf1b },
-		{ AUD_IIR4_1_CA0,                  0x00006349 },
-		{ AUD_IIR4_1_CA1,                  0x00006f27 },
-		{ AUD_IIR4_1_CA2,                  0x0000e7a3 },
-		{ AUD_IIR4_1_CB0,                  0x00005653 },
-		{ AUD_IIR4_1_CB1,                  0x0000cf97 },
-		{ AUD_IIR4_2_CA0,                  0x00006349 },
-		{ AUD_IIR4_2_CA1,                  0x00006f27 },
-		{ AUD_IIR4_2_CA2,                  0x0000e7a3 },
-		{ AUD_IIR4_2_CB0,                  0x00005653 },
-		{ AUD_IIR4_2_CB1,                  0x0000cf97 },
-		{ AUD_HP_MD_IIR4_1,                0x00000001 },
-		{ AUD_HP_PROG_IIR4_1,              0x0000001a },
-		{ AUD_DN0_FREQ,                    0x00000000 },
-		{ AUD_DN1_FREQ,                    0x00003318 },
-		{ AUD_DN1_SRC_SEL,                 0x00000017 },
-		{ AUD_DN1_SHFT,                    0x00000007 },
-		{ AUD_DN1_AFC,                     0x00000000 },
-		{ AUD_DN1_FREQ_SHIFT,              0x00000000 },
-		{ AUD_DN2_FREQ,                    0x00003551 },
-		{ AUD_DN2_SRC_SEL,                 0x00000001 },
-		{ AUD_DN2_SHFT,                    0x00000000 },
-		{ AUD_DN2_AFC,                     0x00000002 },
-		{ AUD_DN2_FREQ_SHIFT,              0x00000000 },
-		{ AUD_PDET_SRC,                    0x00000014 },
-		{ AUD_PDET_SHIFT,                  0x00000000 },
-		{ AUD_DEEMPH0_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH1_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH0_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH1_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH0_G0,                  0x00007000 },
-		{ AUD_DEEMPH0_A0,                  0x00000000 },
-		{ AUD_DEEMPH0_B0,                  0x00000000 },
-		{ AUD_DEEMPH0_A1,                  0x00000000 },
-		{ AUD_DEEMPH0_B1,                  0x00000000 },
-		{ AUD_DEEMPH1_G0,                  0x00007000 },
-		{ AUD_DEEMPH1_A0,                  0x00000000 },
-		{ AUD_DEEMPH1_B0,                  0x00000000 },
-		{ AUD_DEEMPH1_A1,                  0x00000000 },
-		{ AUD_DEEMPH1_B1,                  0x00000000 },
-		{ AUD_DMD_RA_DDS,                  0x00f5c285 },
-		{ AUD_RATE_ADJ1,                   0x00000100 },
-		{ AUD_RATE_ADJ2,                   0x00000200 },
-		{ AUD_RATE_ADJ3,                   0x00000300 },
-		{ AUD_RATE_ADJ4,                   0x00000400 },
-		{ AUD_RATE_ADJ5,                   0x00000500 },
-		{ AUD_C2_UP_THR,                   0x00005400 },
-		{ AUD_C2_LO_THR,                   0x00003000 },
-		{ AUD_C1_UP_THR,                   0x00007000 },
-		{ AUD_C2_LO_THR,                   0x00005400 },
-		{ AUD_CTL,                         0x0000100c },
-		{ AUD_DCOC_0_SRC,                  0x00000021 },
-		{ AUD_DCOC_1_SRC,                  0x00000003 },
-		{ AUD_DCOC1_SHIFT,                 0x00000000 },
-		{ AUD_DCOC_1_SHIFT_IN0,            0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,            0x00000008 },
-		{ AUD_DCOC_PASS_IN,                0x00000000 },
-		{ AUD_DCOC_2_SRC,                  0x0000001b },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_PHASE_FIX_CTL,               0x00000000 },
-		{ AUD_CORDIC_SHIFT_1,              0x00000007 },
-		{ AUD_PLL_EN,                      0x00000000 },
-		{ AUD_PLL_PRESCALE,                0x00000002 },
-		{ AUD_PLL_INT,                     0x0000001e },
-		{ AUD_OUT1_SHIFT,                  0x00000000 },
+        static const struct rlist nicam_l_mono[] = {
+                { AUD_ERRLOGPERIOD_R,     0x00000064 },
+                { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
+                { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
+                { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
+
+                { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
+                { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
+                { AUD_QAM_MODE,           0x00 },
+                { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
+                { AUD_PHACC_FREQ_8MSB,    0x3a },
+                { AUD_PHACC_FREQ_8LSB,    0x4a },
+
+                { AUD_DEEMPHGAIN_R, 0x6680 },
+                { AUD_DEEMPHNUMER1_R, 0x353DE },
+                { AUD_DEEMPHNUMER2_R, 0x1B1 },
+                { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
+                { AUD_DEEMPHDENOM2_R, 0x0 },
+                { AUD_FM_MODE_ENABLE, 0x7 },
+                { AUD_POLYPH80SCALEFAC, 0x3 },
+                { AUD_AFE_12DB_EN, 0x1 },
+                { AAGC_GAIN, 0x0 },
+                { AAGC_HYST, 0x18 },
+                { AAGC_DEF, 0x20 },
+                { AUD_DN0_FREQ, 0x0 },
+                { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
+                { AUD_DCOC_0_SRC, 0x21 },
+                { AUD_IIR1_0_SEL, 0x0 },
+                { AUD_IIR1_0_SHIFT, 0x7 },
+                { AUD_IIR1_1_SEL, 0x2 },
+                { AUD_IIR1_1_SHIFT, 0x0 },
+                { AUD_DCOC_1_SRC, 0x3 },
+                { AUD_DCOC1_SHIFT, 0x0 },
+                { AUD_DCOC_PASS_IN, 0x0 },
+                { AUD_IIR1_2_SEL, 0x23 },
+                { AUD_IIR1_2_SHIFT, 0x0 },
+                { AUD_IIR1_3_SEL, 0x4 },
+                { AUD_IIR1_3_SHIFT, 0x7 },
+                { AUD_IIR1_4_SEL, 0x5 },
+                { AUD_IIR1_4_SHIFT, 0x7 },
+                { AUD_IIR3_0_SEL, 0x7 },
+                { AUD_IIR3_0_SHIFT, 0x0 },
+                { AUD_DEEMPH0_SRC_SEL, 0x11 },
+                { AUD_DEEMPH0_SHIFT, 0x0 },
+                { AUD_DEEMPH0_G0, 0x7000 },
+                { AUD_DEEMPH0_A0, 0x0 },
+                { AUD_DEEMPH0_B0, 0x0 },
+                { AUD_DEEMPH0_A1, 0x0 },
+                { AUD_DEEMPH0_B1, 0x0 },
+                { AUD_DEEMPH1_SRC_SEL, 0x11 },
+                { AUD_DEEMPH1_SHIFT, 0x0 },
+                { AUD_DEEMPH1_G0, 0x7000 },
+                { AUD_DEEMPH1_A0, 0x0 },
+                { AUD_DEEMPH1_B0, 0x0 },
+                { AUD_DEEMPH1_A1, 0x0 },
+                { AUD_DEEMPH1_B1, 0x0 },
+                { AUD_OUT0_SEL, 0x3F },
+                { AUD_OUT1_SEL, 0x3F },
+                { AUD_DMD_RA_DDS, 0x0F5C285 },
+                { AUD_PLL_INT, 0x1E },
+                { AUD_PLL_DDS, 0x0 },
+                { AUD_PLL_FRAC, 0x0E542 },
+
+                // setup QAM registers
+                { AUD_RATE_ADJ1,      0x00000100 },
+                { AUD_RATE_ADJ2,      0x00000200 },
+                { AUD_RATE_ADJ3,      0x00000300 },
+                { AUD_RATE_ADJ4,      0x00000400 },
+                { AUD_RATE_ADJ5,      0x00000500 },
+                { AUD_RATE_THRES_DMD, 0x000000C0 },
+                { /* end of list */ },
+        };
 
-		{ /* end of list */ },
-	};
+        static const struct rlist nicam_l[] = {
+                // setup QAM registers
+                { AUD_RATE_ADJ1, 0x00000060 },
+                { AUD_RATE_ADJ2, 0x000000F9 },
+                { AUD_RATE_ADJ3, 0x000001CC },
+                { AUD_RATE_ADJ4, 0x000002B3 },
+                { AUD_RATE_ADJ5, 0x00000726 },
+                { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
+                { AUD_DEEMPHDENOM2_R, 0x00000000 },
+                { AUD_ERRLOGPERIOD_R, 0x00000064 },
+                { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
+                { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
+                { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
+                { AUD_POLYPH80SCALEFAC, 0x00000003 },
+                { AUD_DMD_RA_DDS, 0x00C00000 },
+                { AUD_PLL_INT, 0x0000001E },
+                { AUD_PLL_DDS, 0x00000000 },
+                { AUD_PLL_FRAC, 0x0000E542 },
+                { AUD_START_TIMER, 0x00000000 },
+                { AUD_DEEMPHNUMER1_R, 0x000353DE },
+                { AUD_DEEMPHNUMER2_R, 0x000001B1 },
+                { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
+                { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
+                { AUD_QAM_MODE, 0x05 },
+                { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
+                { AUD_PHACC_FREQ_8MSB, 0x34 },
+                { AUD_PHACC_FREQ_8LSB, 0x4C },
+                { AUD_DEEMPHGAIN_R, 0x00006680 },
+                { AUD_RATE_THRES_DMD, 0x000000C0  },
+                { /* end of list */ },
+        } ;
+        dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
 
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
-        set_audio_start(core, 0x0004,
-			0 /* FIXME */);
-	set_audio_registers(core, nicam_l);
+        if (!stereo) {
+		/* AM mono sound */
+                set_audio_start(core, 0x0004,
+				0x100c /* FIXME again */);
+                set_audio_registers(core, nicam_l_mono);
+        } else {
+                set_audio_start(core, 0x0010,
+				0x1924 /* FIXME again */);
+                set_audio_registers(core, nicam_l);
+        }
+        set_audio_finish(core);
+
+}
+
+static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
+{
+       static const struct rlist pal_i_fm_mono[] = {
+            {AUD_ERRLOGPERIOD_R,       0x00000064},
+            {AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
+            {AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
+            {AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
+            {AUD_PDF_DDS_CNST_BYTE2,   0x06},
+            {AUD_PDF_DDS_CNST_BYTE1,   0x82},
+            {AUD_PDF_DDS_CNST_BYTE0,   0x12},
+            {AUD_QAM_MODE,             0x05},
+            {AUD_PHACC_FREQ_8MSB,      0x3a},
+            {AUD_PHACC_FREQ_8LSB,      0x93},
+            {AUD_DMD_RA_DDS,           0x002a4f2f},
+            {AUD_PLL_INT,              0x0000001e},
+            {AUD_PLL_DDS,              0x00000004},
+            {AUD_PLL_FRAC,             0x0000e542},
+            {AUD_RATE_ADJ1,            0x00000100},
+            {AUD_RATE_ADJ2,            0x00000200},
+            {AUD_RATE_ADJ3,            0x00000300},
+            {AUD_RATE_ADJ4,            0x00000400},
+            {AUD_RATE_ADJ5,            0x00000500},
+            {AUD_THR_FR,               0x00000000},
+            {AUD_PILOT_BQD_1_K0,       0x0000755b},
+            {AUD_PILOT_BQD_1_K1,       0x00551340},
+            {AUD_PILOT_BQD_1_K2,       0x006d30be},
+            {AUD_PILOT_BQD_1_K3,       0xffd394af},
+            {AUD_PILOT_BQD_1_K4,       0x00400000},
+            {AUD_PILOT_BQD_2_K0,       0x00040000},
+            {AUD_PILOT_BQD_2_K1,       0x002a4841},
+            {AUD_PILOT_BQD_2_K2,       0x00400000},
+            {AUD_PILOT_BQD_2_K3,       0x00000000},
+            {AUD_PILOT_BQD_2_K4,       0x00000000},
+            {AUD_MODE_CHG_TIMER,       0x00000060},
+            {AUD_AFE_12DB_EN,          0x00000001},
+            {AAGC_HYST,                0x0000000a},
+            {AUD_CORDIC_SHIFT_0,       0x00000007},
+            {AUD_CORDIC_SHIFT_1,       0x00000007},
+            {AUD_C1_UP_THR,            0x00007000},
+            {AUD_C1_LO_THR,            0x00005400},
+            {AUD_C2_UP_THR,            0x00005400},
+            {AUD_C2_LO_THR,            0x00003000},
+            {AUD_DCOC_0_SRC,           0x0000001a},
+            {AUD_DCOC0_SHIFT,          0x00000000},
+            {AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
+            {AUD_DCOC_0_SHIFT_IN1,     0x00000008},
+            {AUD_DCOC_PASS_IN,         0x00000003},
+            {AUD_IIR3_0_SEL,           0x00000021},
+            {AUD_DN2_AFC,              0x00000002},
+            {AUD_DCOC_1_SRC,           0x0000001b},
+            {AUD_DCOC1_SHIFT,          0x00000000},
+            {AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
+            {AUD_DCOC_1_SHIFT_IN1,     0x00000008},
+            {AUD_IIR3_1_SEL,           0x00000023},
+            {AUD_DN0_FREQ,             0x000035a3},
+            {AUD_DN2_FREQ,             0x000029c7},
+            {AUD_CRDC0_SRC_SEL,        0x00000511},
+            {AUD_IIR1_0_SEL,           0x00000001},
+            {AUD_IIR1_1_SEL,           0x00000000},
+            {AUD_IIR3_2_SEL,           0x00000003},
+            {AUD_IIR3_2_SHIFT,         0x00000000},
+            {AUD_IIR3_0_SEL,           0x00000002},
+            {AUD_IIR2_0_SEL,           0x00000021},
+            {AUD_IIR2_0_SHIFT,         0x00000002},
+            {AUD_DEEMPH0_SRC_SEL,      0x0000000b},
+            {AUD_DEEMPH1_SRC_SEL,      0x0000000b},
+            {AUD_POLYPH80SCALEFAC,     0x00000001},
+            {AUD_START_TIMER,          0x00000000},
+            { /* end of list */ },
+       };
+
+       static const struct rlist pal_i_nicam[] = {
+           { AUD_RATE_ADJ1,           0x00000010 },
+           { AUD_RATE_ADJ2,           0x00000040 },
+           { AUD_RATE_ADJ3,           0x00000100 },
+           { AUD_RATE_ADJ4,           0x00000400 },
+           { AUD_RATE_ADJ5,           0x00001000 },
+	   //     { AUD_DMD_RA_DDS,          0x00c0d5ce },
+	   { AUD_DEEMPHGAIN_R,        0x000023c2 },
+	   { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
+	   { AUD_DEEMPHNUMER2_R,      0x0003023e },
+	   { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
+	   { AUD_DEEMPHDENOM2_R,      0x00000000 },
+	   { AUD_DEEMPHDENOM2_R,      0x00000000 },
+	   { AUD_ERRLOGPERIOD_R,      0x00000fff },
+	   { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
+	   { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
+	   { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
+	   { AUD_POLYPH80SCALEFAC,    0x00000003 },
+	   { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
+	   { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
+	   { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
+	   { AUD_QAM_MODE,            0x05 },
+	   { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
+	   { AUD_PHACC_FREQ_8MSB,     0x3a },
+	   { AUD_PHACC_FREQ_8LSB,     0x93 },
+            { /* end of list */ },
+        };
+
+        dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+
+        if (!stereo) {
+		// FM mono
+		set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
+		set_audio_registers(core, pal_i_fm_mono);
+        } else {
+		// Nicam Stereo
+		set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
+		set_audio_registers(core, pal_i_nicam);
+        }
         set_audio_finish(core);
 }
 
@@ -553,13 +677,6 @@ static void set_audio_standard_A2(struct
 	set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
 	set_audio_registers(core, a2_common);
 	switch (core->tvaudio) {
-	case WW_NICAM_I:
-		/* gives at least mono according to the dscaler guys */
-		/* so use use that while nicam is broken ...         */
-		dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__);
-		set_audio_registers(core, a2_table1);
-		cx_write(AUD_CTL, EN_A2_FORCE_MONO1);
-		break;
 	case WW_A2_BG:
 		dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
 		set_audio_registers(core, a2_table1);
@@ -646,11 +763,12 @@ void cx88_set_tvaudio(struct cx88_core *
 	case WW_BTSC:
 		set_audio_standard_BTSC(core,0);
 		break;
-	// case WW_NICAM_I:
 	case WW_NICAM_BGDKL:
-		set_audio_standard_NICAM(core);
+		set_audio_standard_NICAM_L(core,0);
 		break;
 	case WW_NICAM_I:
+		set_audio_standard_PAL_I(core,0);
+		break;
 	case WW_A2_BG:
 	case WW_A2_DK:
 	case WW_A2_M:
@@ -663,7 +781,7 @@ void cx88_set_tvaudio(struct cx88_core *
 		set_audio_standard_FM(core);
 		break;
 	case WW_SYSTEM_L_AM:
-		set_audio_standard_NICAM_L(core);
+		set_audio_standard_NICAM_L(core, 1);
 		break;
 	case WW_NONE:
 	default:
@@ -674,6 +792,19 @@ void cx88_set_tvaudio(struct cx88_core *
 	return;
 }
 
+void cx88_newstation(struct cx88_core *core)
+{
+	core->audiomode_manual = UNSET;
+
+	switch (core->tvaudio) {
+	case WW_SYSTEM_L_AM:
+		/* try nicam ... */
+		core->audiomode_current = V4L2_TUNER_MODE_STEREO;
+		set_audio_standard_NICAM_L(core, 1);
+		break;
+	}
+}
+
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
 	static char *m[] = {"stereo", "dual mono", "mono", "sap"};
@@ -721,22 +852,37 @@ void cx88_get_stereo(struct cx88_core *c
 		}
 		break;
 	case WW_NICAM_BGDKL:
-		if (0 == mode)
+		if (0 == mode) {
 			t->audmode = V4L2_TUNER_MODE_STEREO;
+			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		}
 		break;
+        case WW_SYSTEM_L_AM:
+                if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
+                        t->audmode = V4L2_TUNER_MODE_STEREO;
+			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		}
+                break ;
 	default:
-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
-		t->audmode    = V4L2_TUNER_MODE_MONO;
+		/* nothing */
 		break;
 	}
 	return;
 }
 
-void cx88_set_stereo(struct cx88_core *core, u32 mode)
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
 {
 	u32 ctl  = UNSET;
 	u32 mask = UNSET;
 
+	if (manual) {
+		core->audiomode_manual = mode;
+	} else {
+		if (UNSET != core->audiomode_manual)
+			return;
+	}
+	core->audiomode_current = mode;
+
 	switch (core->tvaudio) {
 	case WW_BTSC:
 		switch (mode) {
@@ -789,6 +935,28 @@ void cx88_set_stereo(struct cx88_core *c
 			break;
 		}
 		break;
+	case WW_SYSTEM_L_AM:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:  /* FIXME */
+			set_audio_standard_NICAM_L(core, 0);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			set_audio_standard_NICAM_L(core, 1);
+			break;
+		}
+		break;
+	case WW_NICAM_I:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+			set_audio_standard_PAL_I(core, 0);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			set_audio_standard_PAL_I(core, 1);
+			break;
+		}
+		break;
 	case WW_FM:
 		switch (mode) {
 		case V4L2_TUNER_MODE_MONO:
@@ -804,13 +972,11 @@ void cx88_set_stereo(struct cx88_core *c
 	}
 
 	if (UNSET != ctl) {
-		cx_write(AUD_SOFT_RESET, 0x0001);
-		cx_andor(AUD_CTL, mask,  ctl);
-		cx_write(AUD_SOFT_RESET, 0x0000);
 		dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
 			"[status=0x%x,ctl=0x%x,vol=0x%x]\n",
 			mask, ctl, cx_read(AUD_STATUS),
 			cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
+		cx_andor(AUD_CTL, mask, ctl);
 	}
 	return;
 }
@@ -819,16 +985,32 @@ int cx88_audio_thread(void *data)
 {
 	struct cx88_core *core = data;
 	struct v4l2_tuner t;
+	u32 mode = 0;
 
 	dprintk("cx88: tvaudio thread started\n");
 	for (;;) {
+		msleep_interruptible(1000);
 		if (kthread_should_stop())
 			break;
 
 		/* just monitor the audio status for now ... */
 		memset(&t,0,sizeof(t));
 		cx88_get_stereo(core,&t);
-		msleep_interruptible(1000);
+
+		if (UNSET != core->audiomode_manual)
+			/* manually set, don't do anything. */
+			continue;
+
+		/* monitor signal */
+		if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
+			mode = V4L2_TUNER_MODE_STEREO;
+		else
+			mode = V4L2_TUNER_MODE_MONO;
+		if (mode == core->audiomode_current)
+			continue;
+
+		/* automatically switch to best available mode */
+		cx88_set_stereo(core, mode, 0);
 	}
 
 	dprintk("cx88: tvaudio thread exiting\n");
@@ -838,6 +1020,7 @@ int cx88_audio_thread(void *data)
 /* ----------------------------------------------------------- */
 
 EXPORT_SYMBOL(cx88_set_tvaudio);
+EXPORT_SYMBOL(cx88_newstation);
 EXPORT_SYMBOL(cx88_set_stereo);
 EXPORT_SYMBOL(cx88_get_stereo);
 EXPORT_SYMBOL(cx88_audio_thread);
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -1,8 +1,9 @@
 /*
- * $Id: cx88-vbi.c,v 1.14 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
@@ -45,9 +46,9 @@ void cx8800_vbi_fmt(struct cx8800_dev *d
 	}
 }
 
-int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
-			 struct cx88_dmaqueue *q,
-			 struct cx88_buffer   *buf)
+static int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
+				struct cx88_dmaqueue *q,
+				struct cx88_buffer   *buf)
 {
 	struct cx88_core *core = dev->core;
 
@@ -64,7 +65,7 @@ int cx8800_start_vbi_dma(struct cx8800_d
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
 	cx_set(MO_VID_INTMSK, 0x0f0088);
 
 	/* enable capture */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-video.c,v 1.46 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * video4linux video interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -324,7 +325,7 @@ static struct cx88_ctrl cx8800_ctls[] = 
 		.shift                 = 0,
 	}
 };
-const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
 
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
@@ -428,7 +429,7 @@ static int start_video_dma(struct cx8800
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
 	cx_set(MO_VID_INTMSK, 0x0f0011);
 
 	/* enable capture */
@@ -664,7 +665,7 @@ static void buffer_release(struct videob
 	cx88_free_buffer(fh->dev->pci,buf);
 }
 
-struct videobuf_queue_ops cx8800_video_qops = {
+static struct videobuf_queue_ops cx8800_video_qops = {
 	.buf_setup    = buffer_setup,
 	.buf_prepare  = buffer_prepare,
 	.buf_queue    = buffer_queue,
@@ -994,7 +995,7 @@ static int video_open(struct inode *inod
 		cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
 		dev->core->tvaudio = WW_FM;
 		cx88_set_tvaudio(core);
-		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO);
+		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
 		cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL);
 	}
 
@@ -1002,7 +1003,7 @@ static int video_open(struct inode *inod
 }
 
 static ssize_t
-video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char *data, size_t count, loff_t *ppos)
 {
 	struct cx8800_fh *fh = file->private_data;
 
@@ -1083,6 +1084,8 @@ static int video_release(struct inode *i
 		res_free(dev,fh,RESOURCE_VBI);
 	}
 
+	videobuf_mmap_free(&fh->vidq);
+	videobuf_mmap_free(&fh->vbiq);
 	file->private_data = NULL;
 	kfree(fh);
 	return 0;
@@ -1338,7 +1341,6 @@ static int video_do_ioctl(struct inode *
 			0;
 		if (UNSET != core->tuner_type)
 			cap->capabilities |= V4L2_CAP_TUNER;
-
 		return 0;
 	}
 
@@ -1429,6 +1431,7 @@ static int video_do_ioctl(struct inode *
 		if (*i >= 4)
 			return -EINVAL;
 		down(&dev->lock);
+		cx88_newstation(core);
 		video_mux(dev,*i);
 		up(&dev->lock);
 		return 0;
@@ -1560,7 +1563,7 @@ static int video_do_ioctl(struct inode *
 			return -EINVAL;
 		if (0 != t->index)
 			return -EINVAL;
-		cx88_set_stereo(core, t->audmode);
+		cx88_set_stereo(core, t->audmode, 1);
 		return 0;
 	}
 	case VIDIOC_G_FREQUENCY:
@@ -1590,6 +1593,7 @@ static int video_do_ioctl(struct inode *
 			return -EINVAL;
 		down(&dev->lock);
 		dev->freq = f->frequency;
+		cx88_newstation(core);
 #ifdef V4L2_I2C_CLIENTS
 		cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
 #else
@@ -1880,19 +1884,18 @@ static irqreturn_t cx8800_irq(int irq, v
 {
 	struct cx8800_dev *dev = dev_id;
 	struct cx88_core *core = dev->core;
-	u32 status, mask;
+	u32 status;
 	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x01);
-		mask   = cx_read(MO_PCI_INTMSK);
-		if (0 == (status & mask))
+		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01);
+		if (0 == status)
 			goto out;
 		cx_write(MO_PCI_INTSTAT, status);
 		handled = 1;
 
-		if (status & mask & ~0x1f)
-			cx88_irq(core,status,mask);
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
 		if (status & 0x01)
 			cx8800_vid_irq(dev);
 	};
@@ -1921,7 +1924,7 @@ static struct file_operations video_fops
 	.llseek        = no_llseek,
 };
 
-struct video_device cx8800_video_template =
+static struct video_device cx8800_video_template =
 {
 	.name          = "cx8800-video",
 	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
@@ -1930,7 +1933,7 @@ struct video_device cx8800_video_templat
 	.minor         = -1,
 };
 
-struct video_device cx8800_vbi_template =
+static struct video_device cx8800_vbi_template =
 {
 	.name          = "cx8800-vbi",
 	.type          = VID_TYPE_TELETEXT|VID_TYPE_TUNER,
@@ -1948,7 +1951,7 @@ static struct file_operations radio_fops
 	.llseek        = no_llseek,
 };
 
-struct video_device cx8800_radio_template =
+static struct video_device cx8800_radio_template =
 {
 	.name          = "cx8800-radio",
 	.type          = VID_TYPE_TUNER,
@@ -2055,6 +2058,7 @@ static int __devinit cx8800_initdev(stru
 		       core->name,pci_dev->irq);
 		goto fail_core;
 	}
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* load and configure helper modules */
 	if (TUNER_ABSENT != core->tuner_type)
@@ -2156,7 +2160,7 @@ static void __devexit cx8800_finidev(str
 	kfree(dev);
 }
 
-static int cx8800_suspend(struct pci_dev *pci_dev, u32 state)
+static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
         struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -2181,7 +2185,7 @@ static int cx8800_suspend(struct pci_dev
 #endif
 
 	pci_save_state(pci_dev);
-	if (0 != pci_set_power_state(pci_dev, state)) {
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
 		pci_disable_device(pci_dev);
 		dev->state.disabled = 1;
 	}
@@ -2197,7 +2201,7 @@ static int cx8800_resume(struct pci_dev 
 		pci_enable_device(pci_dev);
 		dev->state.disabled = 0;
 	}
-	pci_set_power_state(pci_dev, 0);
+	pci_set_power_state(pci_dev, PCI_D0);
 	pci_restore_state(pci_dev);
 
 #if 1
@@ -2222,7 +2226,7 @@ static int cx8800_resume(struct pci_dev 
 
 /* ----------------------------------------------------------- */
 
-struct pci_device_id cx8800_pci_tbl[] = {
+static struct pci_device_id cx8800_pci_tbl[] = {
 	{
 		.vendor       = 0x14f1,
 		.device       = 0x8800,
@@ -2254,7 +2258,7 @@ static int cx8800_init(void)
 	printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
 	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-	return pci_module_init(&cx8800_pci_driver);
+	return pci_register_driver(&cx8800_pci_driver);
 }
 
 static void cx8800_fini(void)
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88.h,v 1.40 2004/11/03 09:04:51 kraxel Exp $
+ * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $
  *
  * v4l2 device driver for cx2388x based TV cards
  *
@@ -27,6 +27,7 @@
 #include <linux/kdev_t.h>
 
 #include <media/tuner.h>
+#include <media/tveeprom.h>
 #include <media/audiochip.h>
 #include <media/video-buf.h>
 #include <media/video-buf-dvb.h>
@@ -139,7 +140,7 @@ extern struct sram_channel cx88_sram_cha
 #define CX88_BOARD_GDI                      2
 #define CX88_BOARD_PIXELVIEW                3
 #define CX88_BOARD_ATI_WONDER_PRO           4
-#define CX88_BOARD_WINFAST2000XP            5
+#define CX88_BOARD_WINFAST2000XP_EXPERT     5
 #define CX88_BOARD_AVERTV_303               6
 #define CX88_BOARD_MSI_TVANYWHERE_MASTER    7
 #define CX88_BOARD_WINFAST_DV2000           8
@@ -156,6 +157,11 @@ extern struct sram_channel cx88_sram_cha
 #define CX88_BOARD_CONEXANT_DVB_T1         19
 #define CX88_BOARD_PROVIDEO_PV259          20
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
+#define CX88_BOARD_PCHDTV_HD3000           22
+#define CX88_BOARD_DNTV_LIVE_DVB_T         23
+#define CX88_BOARD_HAUPPAUGE_ROSLYN        24
+#define CX88_BOARD_DIGITALLOGIC_MEC	       25
+#define CX88_BOARD_IODATA_GVBCTV7E         26
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -238,6 +244,7 @@ struct cx88_core {
         u32                        __iomem *lmmio;
         u8                         __iomem *bmmio;
 	u32                        shadow[SHADOW_MAX];
+	int                        pci_irqmask;
 
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
@@ -252,16 +259,20 @@ struct cx88_core {
 	unsigned int               has_radio;
 
 	/* config info -- dvb */
-	unsigned int               pll_type;
+	struct dvb_pll_desc        *pll_desc;
 	unsigned int               pll_addr;
-	unsigned int               demod_addr;
 
 	/* state info */
 	struct task_struct         *kthread;
 	struct cx88_tvnorm         *tvnorm;
 	u32                        tvaudio;
+	u32                        audiomode_manual;
+	u32                        audiomode_current;
 	u32                        input;
 	u32                        astat;
+
+	/* IR remote control state */
+	struct cx88_IR             *ir;
 };
 
 struct cx8800_dev;
@@ -371,11 +382,16 @@ struct cx8802_dev {
 	struct list_head           devlist;
 	struct video_device        *mpeg_dev;
 	u32                        mailbox;
+	int                        width;
+	int                        height;
 
 	/* for dvb only */
 	struct videobuf_dvb        dvb;
 	void*                      fe_handle;
 	int                        (*fe_release)(void *handle);
+
+	/* for switching modulation types */
+	unsigned char              ts_gen_cntrl;
 };
 
 /* ----------------------------------------------------------- */
@@ -404,14 +420,13 @@ struct cx8802_dev {
 /* ----------------------------------------------------------- */
 /* cx88-core.c                                                 */
 
-extern char *cx88_pci_irqs[32];
 extern char *cx88_vid_irqs[32];
 extern char *cx88_mpeg_irqs[32];
 extern void cx88_print_irqbits(char *name, char *tag, char **strings,
 			       u32 bits, u32 mask);
 extern void cx88_print_ioctl(char *name, unsigned int cmd);
 
-extern void cx88_irq(struct cx88_core *core, u32 status, u32 mask);
+extern int cx88_core_irq(struct cx88_core *core, u32 status);
 extern void cx88_wakeup(struct cx88_core *core,
 			struct cx88_dmaqueue *q, u32 count);
 extern void cx88_shutdown(struct cx88_core *core);
@@ -456,9 +471,6 @@ extern void cx88_core_put(struct cx88_co
 /* cx88-vbi.c                                                  */
 
 void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
-int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
-			 struct cx88_dmaqueue *q,
-			 struct cx88_buffer   *buf);
 int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
 int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
 			     struct cx88_dmaqueue *q);
@@ -503,11 +515,19 @@ extern void cx88_card_setup(struct cx88_
 #define WW_FM		12
 
 void cx88_set_tvaudio(struct cx88_core *core);
+void cx88_newstation(struct cx88_core *core);
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
-void cx88_set_stereo(struct cx88_core *core, u32 mode);
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
 int cx88_audio_thread(void *data);
 
 /* ----------------------------------------------------------- */
+/* cx88-input.c                                                */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
+int cx88_ir_fini(struct cx88_core *core);
+void cx88_ir_irq(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
 int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
@@ -517,7 +537,7 @@ void cx8802_cancel_buffers(struct cx8802
 int cx8802_init_common(struct cx8802_dev *dev);
 void cx8802_fini_common(struct cx8802_dev *dev);
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state);
+int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
 int cx8802_resume_common(struct pci_dev *pci_dev);
 
 /*
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-kbd-gpio.c,v 1.11 2004/10/25 11:26:36 kraxel Exp $
+ * $Id: ir-kbd-gpio.c,v 1.12 2005/02/22 12:28:40 kraxel Exp $
  *
  * Copyright (c) 2003 Gerd Knorr
  * Copyright (c) 2003 Pavel Machek
@@ -114,51 +114,6 @@ static IR_KEYTAB_TYPE ir_codes_avermedia
 	[ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
 };
 
-static IR_KEYTAB_TYPE winfast_codes[IR_KEYTAB_SIZE] = {
-	[  5 ] = KEY_KP1,
-	[  6 ] = KEY_KP2,
-	[  7 ] = KEY_KP3,
-	[  9 ] = KEY_KP4,
-	[ 10 ] = KEY_KP5,
-	[ 11 ] = KEY_KP6,
-	[ 13 ] = KEY_KP7,
-	[ 14 ] = KEY_KP8,
-	[ 15 ] = KEY_KP9,
-	[ 18 ] = KEY_KP0,
-
-	[  0 ] = KEY_POWER,
-//      [ 27 ] = MTS button
-	[  2 ] = KEY_TUNER,     // TV/FM
-	[ 30 ] = KEY_VIDEO,
-//      [ 22 ] = display button
-	[  4 ] = KEY_VOLUMEUP,
-	[  8 ] = KEY_VOLUMEDOWN,
-	[ 12 ] = KEY_CHANNELUP,
-	[ 16 ] = KEY_CHANNELDOWN,
-	[  3 ] = KEY_ZOOM,      // fullscreen
-	[ 31 ] = KEY_SUBTITLE,  // closed caption/teletext
-	[ 32 ] = KEY_SLEEP,
-//      [ 41 ] = boss key
-	[ 20 ] = KEY_MUTE,
-	[ 43 ] = KEY_RED,
-	[ 44 ] = KEY_GREEN,
-	[ 45 ] = KEY_YELLOW,
-	[ 46 ] = KEY_BLUE,
-	[ 24 ] = KEY_KPPLUS,    //fine tune +
-	[ 25 ] = KEY_KPMINUS,   //fine tune -
-//      [ 42 ] = picture in picture
-        [ 33 ] = KEY_KPDOT,
-	[ 19 ] = KEY_KPENTER,
-//      [ 17 ] = recall
-	[ 34 ] = KEY_BACK,
-	[ 35 ] = KEY_PLAYPAUSE,
-	[ 36 ] = KEY_NEXT,
-//      [ 37 ] = time shifting
-	[ 38 ] = KEY_STOP,
-	[ 39 ] = KEY_RECORD
-//      [ 40 ] = snapshot
-};
-
 static IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
 	[  2 ] = KEY_KP0,
 	[  1 ] = KEY_KP1,
@@ -388,12 +343,12 @@ static int ir_probe(struct device *dev)
                 break;
 
 	case BTTV_WINFAST2000:
-		ir_codes         = winfast_codes;
+		ir_codes         = ir_codes_winfast;
 		ir->mask_keycode = 0x1f8;
 		break;
 	case BTTV_MAGICTVIEW061:
 	case BTTV_MAGICTVIEW063:
-		ir_codes         = winfast_codes;
+		ir_codes         = ir_codes_winfast;
 		ir->mask_keycode = 0x0008e000;
 		ir->mask_keydown = 0x00200000;
 		break;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1154,7 +1154,7 @@ static int meye_do_ioctl(struct inode *i
 		memset(cap, 0, sizeof(*cap));
 		strcpy(cap->driver, "meye");
 		strcpy(cap->card, "meye");
-		sprintf(cap->bus_info, "PCI:%s", meye.mchip_dev->slot_name);
+		sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
 		cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
 			       MEYE_DRIVER_MINORVERSION;
 		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
@@ -1768,7 +1768,7 @@ static struct video_device meye_template
 };
 
 #ifdef CONFIG_PM
-static int meye_suspend(struct pci_dev *pdev, u32 state)
+static int meye_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	pci_save_state(pdev);
 	meye.pm_mchip_mode = meye.mchip_mode;
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -380,7 +380,9 @@ static void msp3400c_setvolume(struct i2
 	int val = 0, bal = 0;
 
 	if (!muted) {
-		val = (volume * 0x7F / 65535) << 8;
+		/* 0x7f instead if 0x73 here has sound quality issues,
+		 * probably due to overmodulation + clipping ... */
+		val = (volume * 0x73 / 65535) << 8;
 	}
 	if (val) {
 		bal = (balance / 256) - 128;
@@ -734,6 +736,7 @@ static int msp34xx_sleep(struct msp3400c
 {
 	DECLARE_WAITQUEUE(wait, current);
 
+again:
 	add_wait_queue(&msp->wq, &wait);
 	if (!kthread_should_stop()) {
 		if (timeout < 0) {
@@ -749,9 +752,12 @@ static int msp34xx_sleep(struct msp3400c
 #endif
 		}
 	}
-	if (current->flags & PF_FREEZE)
-		refrigerator(PF_FREEZE);
+
 	remove_wait_queue(&msp->wq, &wait);
+
+	if (try_to_freeze(PF_FREEZE))
+		goto again;
+
 	return msp->restart;
 }
 
@@ -993,7 +999,13 @@ static int msp34xx_modus(int norm)
 {
 	switch (norm) {
 	case VIDEO_MODE_PAL:
+#if 1
+		/* experimental: not sure this works with all chip versions */
+		return 0x7003;
+#else
+		/* previous value, try this if it breaks ... */
 		return 0x1003;
+#endif
 	case VIDEO_MODE_NTSC:  /* BTSC */
 		return 0x2003;
 	case VIDEO_MODE_SECAM:
@@ -1260,6 +1272,7 @@ static int msp34xxg_thread(void *data)
 	int val, std, i;
 
 	printk("msp34xxg: daemon started\n");
+	msp->source = 1; /* default */
 	for (;;) {
 		d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");
 		msp34xx_sleep(msp,-1);
@@ -1330,8 +1343,9 @@ static void msp34xxg_set_source(struct i
 
 	/* fix matrix mode to stereo and let the msp choose what
 	 * to output according to 'source', as recommended
+	 * for MONO (source==0) downmixing set bit[7:0] to 0x30
 	 */
-	int value = (source&0x07)<<8|(source==0 ? 0x00:0x20);
+	int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
 	dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);
 	msp3400c_write(client,
 		       I2C_MSP3400C_DFP,
@@ -1355,7 +1369,7 @@ static void msp34xxg_set_source(struct i
 	msp3400c_write(client,
 		       I2C_MSP3400C_DEM,
 		       0x22, /* a2 threshold for stereo/bilingual */
-		       source==0 ? 0x7f0:stereo_threshold);
+		       stereo_threshold);
 	msp->source=source;
 }
 
@@ -1390,7 +1404,7 @@ static void msp34xxg_detect_stereo(struc
 static void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
 {
 	struct msp3400c *msp = i2c_get_clientdata(client);
-	int source = 0;
+	int source;
 
 	switch (audmode) {
 	case V4L2_TUNER_MODE_MONO:
@@ -1406,9 +1420,10 @@ static void msp34xxg_set_audmode(struct 
 	case V4L2_TUNER_MODE_LANG2:
 		source=4; /* stereo or B */
 		break;
-	default: /* doing nothing: a safe, sane default */
+	default:
 		audmode = 0;
-		return;
+		source  = 1;
+		break;
 	}
 	msp->audmode = audmode;
 	msp34xxg_set_source(client, source);
@@ -1422,7 +1437,7 @@ static int msp_detach(struct i2c_client 
 static int msp_probe(struct i2c_adapter *adap);
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
-static int msp_suspend(struct device * dev, u32 state, u32 level);
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level);
 static int msp_resume(struct device * dev, u32 level);
 
 static void msp_wake_thread(struct i2c_client *client);
@@ -1510,12 +1525,9 @@ static int msp_attach(struct i2c_adapter
 
 	msp->opmode = opmode;
 	if (OPMODE_AUTO == msp->opmode) {
-#if 0 /* seems to work for ivtv only, disable by default for now ... */
 		if (HAVE_SIMPLER(msp))
 			msp->opmode = OPMODE_SIMPLER;
-		else
-#endif
-		if (HAVE_SIMPLE(msp))
+		else if (HAVE_SIMPLE(msp))
 			msp->opmode = OPMODE_SIMPLE;
 		else
 			msp->opmode = OPMODE_MANUAL;
@@ -1830,7 +1842,7 @@ static int msp_command(struct i2c_client
 	return 0;
 }
 
-static int msp_suspend(struct device * dev, u32 state, u32 level)
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level)
 {
 	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
 
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/video/mt20xx.c
@@ -0,0 +1,558 @@
+/*
+ * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $
+ *
+ * i2c tv tuner chip device driver
+ * controls microtune tuners, mt2032 + mt2050 at the moment.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/moduleparam.h>
+#include <media/tuner.h>
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned int optimize_vco  = 1;
+module_param(optimize_vco,      int, 0644);
+
+static unsigned int tv_antenna    = 1;
+module_param(tv_antenna,        int, 0644);
+
+static unsigned int radio_antenna = 0;
+module_param(radio_antenna,     int, 0644);
+
+/* ---------------------------------------------------------------------- */
+
+#define MT2032 0x04
+#define MT2030 0x06
+#define MT2040 0x07
+#define MT2050 0x42
+
+static char *microtune_part[] = {
+	[ MT2030 ] = "MT2030",
+	[ MT2032 ] = "MT2032",
+	[ MT2040 ] = "MT2040",
+	[ MT2050 ] = "MT2050",
+};
+
+// IsSpurInBand()?
+static int mt2032_spurcheck(struct i2c_client *c,
+			    int f1, int f2, int spectrum_from,int spectrum_to)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int n1=1,n2,f;
+
+	f1=f1/1000; //scale to kHz to avoid 32bit overflows
+	f2=f2/1000;
+	spectrum_from/=1000;
+	spectrum_to/=1000;
+
+	tuner_dbg("spurcheck f1=%d f2=%d  from=%d to=%d\n",
+		  f1,f2,spectrum_from,spectrum_to);
+
+	do {
+	    n2=-n1;
+	    f=n1*(f1-f2);
+	    do {
+		n2--;
+		f=f-f2;
+		tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
+
+		if( (f>spectrum_from) && (f<spectrum_to))
+			tuner_dbg("mt2032 spurcheck triggered: %d\n",n1);
+	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
+	    n1++;
+	} while (n1<5);
+
+	return 1;
+}
+
+static int mt2032_compute_freq(struct i2c_client *c,
+			       unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int spectrum_from,
+			       unsigned int spectrum_to,
+			       unsigned char *buf,
+			       int *ret_sel,
+			       unsigned int xogc) //all in Hz
+{
+	struct tuner *t = i2c_get_clientdata(c);
+        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
+
+        fref= 5250 *1000; //5.25MHz
+	desired_lo1=rfin+if1;
+
+	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
+        lo1n=lo1/8;
+        lo1a=lo1-(lo1n*8);
+
+        s=rfin/1000/1000+1090;
+
+	if(optimize_vco) {
+		if(s>1890) sel=0;
+		else if(s>1720) sel=1;
+		else if(s>1530) sel=2;
+		else if(s>1370) sel=3;
+		else sel=4; // >1090
+	}
+	else {
+        	if(s>1790) sel=0; // <1958
+        	else if(s>1617) sel=1;
+        	else if(s>1449) sel=2;
+        	else if(s>1291) sel=3;
+        	else sel=4; // >1090
+	}
+	*ret_sel=sel;
+
+        lo1freq=(lo1a+8*lo1n)*fref;
+
+	tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
+		  rfin,lo1,lo1n,lo1a,sel,lo1freq);
+
+        desired_lo2=lo1freq-rfin-if2;
+        lo2=(desired_lo2)/fref;
+        lo2n=lo2/8;
+        lo2a=lo2-(lo2n*8);
+        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+
+	tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
+		  rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
+
+        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+		tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
+			   lo1a, lo1n, lo2a,lo2n);
+                return(-1);
+        }
+
+	mt2032_spurcheck(c, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
+	// should recalculate lo1 (one step up/down)
+
+	// set up MT2032 register map for transfer over i2c
+	buf[0]=lo1n-1;
+	buf[1]=lo1a | (sel<<4);
+	buf[2]=0x86; // LOGC
+	buf[3]=0x0f; //reserved
+	buf[4]=0x1f;
+	buf[5]=(lo2n-1) | (lo2a<<5);
+ 	if(rfin >400*1000*1000)
+                buf[6]=0xe4;
+        else
+                buf[6]=0xf4; // set PKEN per rev 1.2
+	buf[7]=8+xogc;
+	buf[8]=0xc3; //reserved
+	buf[9]=0x4e; //reserved
+	buf[10]=0xec; //reserved
+	buf[11]=(lo2num&0xff);
+	buf[12]=(lo2num>>8) |0x80; // Lo2RST
+
+	return 0;
+}
+
+static int mt2032_check_lo_lock(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int try,lock=0;
+	unsigned char buf[2];
+
+	for(try=0;try<10;try++) {
+		buf[0]=0x0e;
+		i2c_master_send(c,buf,1);
+		i2c_master_recv(c,buf,1);
+		tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
+		lock=buf[0] &0x06;
+
+		if (lock==6)
+			break;
+
+		tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
+		udelay(1000);
+	}
+        return lock;
+}
+
+static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char buf[2];
+	int tad1;
+
+	buf[0]=0x0f;
+	i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,1);
+	tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
+	tad1=buf[0]&0x07;
+
+	if(tad1 ==0) return lock;
+	if(tad1 ==1) return lock;
+
+	if(tad1==2) {
+		if(sel==0)
+			return lock;
+		else sel--;
+	}
+	else {
+		if(sel<4)
+			sel++;
+		else
+			return lock;
+	}
+
+	tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel);
+
+	buf[0]=0x0f;
+	buf[1]=sel;
+        i2c_master_send(c,buf,2);
+	lock=mt2032_check_lo_lock(c);
+	return lock;
+}
+
+
+static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int from, unsigned int to)
+{
+	unsigned char buf[21];
+	int lint_try,ret,sel,lock=0;
+	struct tuner *t = i2c_get_clientdata(c);
+
+	tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
+		  rfin,if1,if2,from,to);
+
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+
+	buf[0]=0;
+	ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+	if (ret<0)
+		return;
+
+        // send only the relevant registers per Rev. 1.2
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,4);
+        buf[5]=5;
+        ret=i2c_master_send(c,buf+5,4);
+        buf[11]=11;
+        ret=i2c_master_send(c,buf+11,3);
+        if(ret!=3)
+		tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
+
+	// wait for PLLs to lock (per manual), retry LINT if not.
+	for(lint_try=0; lint_try<2; lint_try++) {
+		lock=mt2032_check_lo_lock(c);
+
+		if(optimize_vco)
+			lock=mt2032_optimize_vco(c,sel,lock);
+		if(lock==6) break;
+
+		tuner_dbg("mt2032: re-init PLLs by LINT\n");
+		buf[0]=7;
+		buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+		i2c_master_send(c,buf,2);
+		mdelay(10);
+		buf[1]=8+t->xogc;
+		i2c_master_send(c,buf,2);
+        }
+
+	if (lock!=6)
+		tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
+
+	buf[0]=2;
+	buf[1]=0x20; // LOGC for optimal phase noise
+	ret=i2c_master_send(c,buf,2);
+	if (ret!=2)
+		tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+}
+
+
+static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2,from,to;
+
+	// signal bandwidth and picture carrier
+	if (t->std & V4L2_STD_525_60) {
+		// NTSC
+		from = 40750*1000;
+		to   = 46750*1000;
+		if2  = 45750*1000;
+	} else {
+		// PAL
+		from = 32900*1000;
+		to   = 39900*1000;
+		if2  = 38900*1000;
+	}
+
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1090*1000*1000, if2, from, to);
+}
+
+static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2 = t->radio_if2;
+
+	// per Manual for FM tuning: first if center freq. 1085 MHz
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1085*1000*1000,if2,if2,if2);
+}
+
+// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+static int mt2032_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+        unsigned char buf[21];
+        int ret,xogc,xok=0;
+
+	// Initialize Registers per spec.
+        buf[1]=2; // Index to register 2
+        buf[2]=0xff;
+        buf[3]=0x0f;
+        buf[4]=0x1f;
+        ret=i2c_master_send(c,buf+1,4);
+
+        buf[5]=6; // Index register 6
+        buf[6]=0xe4;
+        buf[7]=0x8f;
+        buf[8]=0xc3;
+        buf[9]=0x4e;
+        buf[10]=0xec;
+        ret=i2c_master_send(c,buf+5,6);
+
+        buf[12]=13;  // Index register 13
+        buf[13]=0x32;
+        ret=i2c_master_send(c,buf+12,2);
+
+        // Adjust XOGC (register 7), wait for XOK
+        xogc=7;
+        do {
+		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                mdelay(10);
+                buf[0]=0x0e;
+                i2c_master_send(c,buf,1);
+                i2c_master_recv(c,buf,1);
+                xok=buf[0]&0x01;
+                tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+                if (xok == 1) break;
+
+                xogc--;
+                tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                if (xogc == 3) {
+                        xogc=4; // min. 4 per spec
+                        break;
+                }
+                buf[0]=0x07;
+                buf[1]=0x88 + xogc;
+                ret=i2c_master_send(c,buf,2);
+                if (ret!=2)
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+        } while (xok != 1 );
+	t->xogc=xogc;
+
+	t->tv_freq    = mt2032_set_tv_freq;
+	t->radio_freq = mt2032_set_radio_freq;
+        return(1);
+}
+
+static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+       unsigned char buf[2];
+       int ret;
+
+       buf[0] = 6;
+       buf[1] = antenna ? 0x11 : 0x10;
+       ret=i2c_master_send(c,buf,2);
+       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+}
+
+static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned int if1=1218*1000*1000;
+	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
+	int ret;
+	unsigned char buf[6];
+
+	tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
+		  freq,if1,if2);
+
+	f_lo1=freq+if1;
+	f_lo1=(f_lo1/1000000)*1000000;
+
+	f_lo2=f_lo1-freq-if2;
+	f_lo2=(f_lo2/50000)*50000;
+
+	lo1=f_lo1/4000000;
+	lo2=f_lo2/4000000;
+
+	f_lo1_modulo= f_lo1-(lo1*4000000);
+	f_lo2_modulo= f_lo2-(lo2*4000000);
+
+	num1=4*f_lo1_modulo/4000000;
+	num2=4096*(f_lo2_modulo/1000)/4000;
+
+	// todo spurchecks
+
+	div1a=(lo1/12)-1;
+	div1b=lo1-(div1a+1)*12;
+
+	div2a=(lo2/8)-1;
+	div2b=lo2-(div2a+1)*8;
+
+	if (tuner_debug > 1) {
+		tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
+		tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
+			  num1,num2,div1a,div1b,div2a,div2b);
+	}
+
+	buf[0]=1;
+	buf[1]= 4*div1b + num1;
+	if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
+
+	buf[2]=div1a;
+	buf[3]=32*div2b + num2/256;
+	buf[4]=num2-(num2/256)*256;
+	buf[5]=div2a;
+	if(num2!=0) buf[5]=buf[5]|0x40;
+
+	if (tuner_debug > 1) {
+		int i;
+		tuner_dbg("bufs is: ");
+		for(i=0;i<6;i++)
+			printk("%x ",buf[i]);
+		printk("\n");
+	}
+
+	ret=i2c_master_send(c,buf,6);
+        if (ret!=6)
+		tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
+}
+
+static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned int if2;
+
+	if (t->std & V4L2_STD_525_60) {
+		// NTSC
+                if2 = 45750*1000;
+        } else {
+                // PAL
+                if2 = 38900*1000;
+        }
+	if (V4L2_TUNER_DIGITAL_TV == t->mode) {
+		// DVB (pinnacle 300i)
+		if2 = 36150*1000;
+	}
+	mt2050_set_if_freq(c, freq*62500, if2);
+	mt2050_set_antenna(c, tv_antenna);
+}
+
+static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2 = t->radio_if2;
+
+	mt2050_set_if_freq(c, freq*62500, if2);
+	mt2050_set_antenna(c, radio_antenna);
+}
+
+static int mt2050_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char buf[2];
+	int ret;
+
+	buf[0]=6;
+	buf[1]=0x10;
+	ret=i2c_master_send(c,buf,2); //  power
+
+	buf[0]=0x0f;
+	buf[1]=0x0f;
+	ret=i2c_master_send(c,buf,2); // m1lo
+
+	buf[0]=0x0d;
+	ret=i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,1);
+
+	tuner_dbg("mt2050: sro is %x\n",buf[0]);
+	t->tv_freq    = mt2050_set_tv_freq;
+	t->radio_freq = mt2050_set_radio_freq;
+	return 0;
+}
+
+int microtune_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	char *name;
+        unsigned char buf[21];
+	int company_code;
+
+	memset(buf,0,sizeof(buf));
+	t->tv_freq    = NULL;
+	t->radio_freq = NULL;
+	name = "unknown";
+
+        i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+        if (tuner_debug) {
+                int i;
+		tuner_dbg("MT20xx hexdump:");
+                for(i=0;i<21;i++) {
+                        printk(" %02x",buf[i]);
+                        if(((i+1)%8)==0) printk(" ");
+                }
+                printk("\n");
+        }
+	company_code = buf[0x11] << 8 | buf[0x12];
+	tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
+		   company_code,buf[0x13],buf[0x14]);
+
+#if 0
+	/* seems to cause more problems than it solves ... */
+	switch (company_code) {
+	case 0x30bf:
+	case 0x3cbf:
+	case 0x3dbf:
+	case 0x4d54:
+	case 0x8e81:
+	case 0x8e91:
+		/* ok (?) */
+		break;
+	default:
+		tuner_warn("tuner: microtune: unknown companycode\n");
+		return 0;
+	}
+#endif
+
+	if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
+	    NULL != microtune_part[buf[0x13]])
+		name = microtune_part[buf[0x13]];
+	switch (buf[0x13]) {
+	case MT2032:
+		mt2032_init(c);
+		break;
+	case MT2050:
+		mt2050_init(c);
+		break;
+	default:
+		tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
+			   name);
+                return 0;
+        }
+
+	strlcpy(c->name, name, sizeof(c->name));
+	tuner_info("microtune %s found, OK\n",name);
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -731,7 +731,7 @@ static int mxb_ioctl(struct saa7146_fh *
 		t->signal = 0xffff;
 		t->afc = 0;		
 
-		byte = mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, NULL);
+		mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
 		t->audmode = mxb->cur_mode;
 		
 		if( byte < 0 ) {
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -422,7 +422,6 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template = {
 	I2C_DEVNAME("(unset)"),
-	.id =		-1,
 	.driver =	&driver,
 };
 
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -40,6 +40,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -421,6 +422,16 @@ static void planb_prepare_close(struct p
 /* overlay support functions */
 /*****************************/
 
+static inline int overlay_is_active(struct planb *pb)
+{
+	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
+	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
+
+	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
+			&& (caddr < (pb->ch1_cmd_phys + size))
+			&& (caddr >= (unsigned)pb->ch1_cmd_phys);
+}
+
 static void overlay_start(struct planb *pb)
 {
 
@@ -852,16 +863,6 @@ static int palette2fmt[] = {
 
 #define PLANB_PALETTE_MAX 15
 
-static inline int overlay_is_active(struct planb *pb)
-{
-	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
-	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
-
-	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
-			&& (caddr < (pb->ch1_cmd_phys + size))
-			&& (caddr >= (unsigned)pb->ch1_cmd_phys);
-}
-
 static int vgrab(struct planb *pb, struct video_mmap *mp)
 {
 	unsigned int fr = mp->frame;
@@ -1609,8 +1610,7 @@ static int planb_ioctl(struct video_devi
 				}
 				planb_lock(pb);
 				/* empty the grabbing queue */
-				while(pb->grabbing)
-					interruptible_sleep_on(&pb->capq);
+				wait_event(pb->capq, !pb->grabbing);
 				pb->maxlines = maxlines;
 				pb->win.norm = v.norm;
 				/* Stop overlay if running */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -65,18 +65,7 @@ static struct video_device saa_template;
 /* Addresses to scan */
 static unsigned short normal_i2c[]	 = { I2C_ADDRESS, I2C_CLIENT_END };
 static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2]		 = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]	 = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]		 = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2]	 = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]		 = { I2C_CLIENT_END, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range,
-	probe, probe_range,
-	ignore, ignore_range,
-	force
-};
+I2C_CLIENT_INSMOD;
 
 static struct i2c_client client_template;
 
@@ -185,7 +174,6 @@ static struct i2c_driver i2c_driver_vide
 };
 
 static struct i2c_client client_template = {
-	.id 		= -1,
 	.driver		= &i2c_driver_videotext,
 	.name		= "(unset)",
 };
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -133,18 +133,7 @@ static struct video_device saa_template;
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
 static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
 
 static struct i2c_client client_template;
 
@@ -258,7 +247,6 @@ static struct i2c_driver i2c_driver_vide
 };
 
 static struct i2c_client client_template = {
-	.id 		= -1,
 	.driver		= &i2c_driver_videotext,
 	.name		= "(unset)",
 };
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -30,6 +30,7 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/wait.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -60,8 +61,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-
 
 #define	I2C_SAA7110		0x9C	/* or 0x9E */
 
+#define SAA7110_NR_REG		0x35
+
 struct saa7110 {
-	unsigned char reg[54];
+	u8 reg[SAA7110_NR_REG];
 
 	int norm;
 	int input;
@@ -95,31 +98,28 @@ saa7110_write_block (struct i2c_client *
 		     unsigned int       len)
 {
 	int ret = -1;
-	u8 reg = *data++;
+	u8 reg = *data;		/* first register to write to */
 
-	len--;
+	/* Sanity check */
+	if (reg + (len - 1) > SAA7110_NR_REG)
+		return ret;
 
 	/* the saa7110 has an autoincrement function, use it if
 	 * the adapter understands raw I2C */
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		struct saa7110 *decoder = i2c_get_clientdata(client);
 		struct i2c_msg msg;
-		u8 block_data[54];
 
-		msg.len = 0;
-		msg.buf = (char *) block_data;
+		msg.len = len;
+		msg.buf = (char *) data;
 		msg.addr = client->addr;
-		msg.flags = client->flags;
-		while (len >= 1) {
-			msg.len = 0;
-			block_data[msg.len++] = reg;
-			while (len-- >= 1 && msg.len < 54)
-				block_data[msg.len++] =
-				    decoder->reg[reg++] = *data++;
-			ret = i2c_transfer(client->adapter, &msg, 1);
-		}
+		msg.flags = 0;
+		ret = i2c_transfer(client->adapter, &msg, 1);
+
+		/* Cache the written data */
+		memcpy(decoder->reg + reg, data + 1, len - 1);
 	} else {
-		while (len-- >= 1) {
+		for (++data, --len; len; len--) {
 			if ((ret = saa7110_write(client, reg++,
 						 *data++)) < 0)
 				break;
@@ -192,7 +192,7 @@ saa7110_selmux (struct i2c_client *clien
 	return 0;
 }
 
-static const unsigned char initseq[] = {
+static const unsigned char initseq[1 + SAA7110_NR_REG] = {
 	0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
 	/* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
 	/* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
@@ -205,13 +205,16 @@ static const unsigned char initseq[] = {
 static int
 determine_norm (struct i2c_client *client)
 {
+	DEFINE_WAIT(wait);
 	struct saa7110 *decoder = i2c_get_clientdata(client);
 	int status;
 
 	/* mode changed, start automatic detection */
 	saa7110_write_block(client, initseq, sizeof(initseq));
 	saa7110_selmux(client, decoder->input);
-	sleep_on_timeout(&decoder->wq, HZ / 4);
+	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/4);
+	finish_wait(&decoder->wq, &wait);
 	status = saa7110_read(client);
 	if (status & 0x40) {
 		dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
@@ -250,7 +253,9 @@ determine_norm (struct i2c_client *clien
 	saa7110_write(client, 0x11, 0x59);
 	//saa7110_write(client,0x2E,0x9A);
 
-	sleep_on_timeout(&decoder->wq, HZ / 4);
+	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/4);
+	finish_wait(&decoder->wq, &wait);
 
 	status = saa7110_read(client);
 	if ((status & 0x03) == 0x01) {
@@ -476,7 +481,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int saa7110_i2c_id = 0;
 static struct i2c_driver i2c_driver_saa7110;
 
 static int
@@ -507,9 +511,7 @@ saa7110_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_saa7110;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = saa7110_i2c_id++;
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"saa7110[%d]", client->id);
+	strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
 
 	decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
 	if (decoder == 0) {
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -500,7 +500,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int saa7111_i2c_id = 0;
 static struct i2c_driver i2c_driver_saa7111;
 
 static int
@@ -530,9 +529,7 @@ saa7111_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_saa7111;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = saa7111_i2c_id++;
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"saa7111[%d]", client->id);
+	strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client)));
 
 	decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
 	if (decoder == NULL) {
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -163,7 +163,7 @@ saa7114_write_block (struct i2c_client *
 		u8 block_data[32];
 
 		msg.addr = client->addr;
-		msg.flags = client->flags;
+		msg.flags = 0;
 		while (len >= 2) {
 			msg.buf = (char *) block_data;
 			msg.len = 0;
@@ -838,7 +838,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int saa7114_i2c_id = 0;
 static struct i2c_driver i2c_driver_saa7114;
 
 static int
@@ -871,9 +870,7 @@ saa7114_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_saa7114;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = saa7114_i2c_id++;
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"saa7114[%d]", client->id);
+	strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client)));
 
 	decoder = kmalloc(sizeof(struct saa7114), GFP_KERNEL);
 	if (decoder == NULL) {
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa71
 
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -11,9 +11,14 @@
 #include <linux/types.h>
 #include <linux/videodev.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <media/id.h>
-#include <media/saa6752hs.h>
+
+#define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
+#define MPEG_VIDEO_MAX_BITRATE_MAX     27000
+#define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
+#define MPEG_PID_MAX ((1 << 14) - 1)
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
@@ -27,6 +32,33 @@ MODULE_LICENSE("GPL");
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
+enum saa6752hs_videoformat {
+	SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
+	SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
+	SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */
+	SAA6752HS_VF_SIF = 3,   /* SIF video format: 352x288 */
+	SAA6752HS_VF_UNKNOWN,
+};
+
+static const struct v4l2_format v4l2_format_table[] =
+{
+	[SAA6752HS_VF_D1] = {
+		.fmt = { .pix = { .width = 720, .height = 576 }, }, },
+	[SAA6752HS_VF_2_3_D1] = {
+		.fmt = { .pix = { .width = 480, .height = 576 }, }, },
+	[SAA6752HS_VF_1_2_D1] = {
+		.fmt = { .pix = { .width = 352, .height = 576 }, }, },
+	[SAA6752HS_VF_SIF] = {
+		.fmt = { .pix = { .width = 352, .height = 288 }, }, },
+	[SAA6752HS_VF_UNKNOWN] = {
+		.fmt = { .pix = { .width = 0, .height = 0 }, }, },
+};
+
+struct saa6752hs_state {
+	struct i2c_client             client;
+	struct v4l2_mpeg_compression  params;
+	enum saa6752hs_videoformat    video_format;
+};
 
 enum saa6752hs_command {
 	SAA6752HS_COMMAND_RESET = 0,
@@ -40,7 +72,6 @@ enum saa6752hs_command {
 	SAA6752HS_COMMAND_MAX
 };
 
-
 /* ---------------------------------------------------------------------- */
 
 static u8 PAT[] = {
@@ -64,9 +95,9 @@ static u8 PAT[] = {
 
 	0x00, 0x01, // program_number(1)
 
-	0xe0, 0x10, // PMT PID(0x10)
+	0xe0, 0x00, // PMT PID
 
-	0x76, 0xf1, 0x44, 0xd1 // CRC32
+	0x00, 0x00, 0x00, 0x00 // CRC32
 };
 
 static u8 PMT[] = {
@@ -74,7 +105,7 @@ static u8 PMT[] = {
 	0x01, // table number for encoder
 
 	0x47, // sync
-	0x40, 0x10, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0x10)
+	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
 	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
 
 	0x00, // PSI pointer to start of table
@@ -88,28 +119,51 @@ static u8 PMT[] = {
 
 	0x00, 0x00, // section_number(0), last_section_number(0)
 
-	0xe1, 0x04, // PCR_PID (0x104)
+	0xe0, 0x00, // PCR_PID
 
 	0xf0, 0x00, // program_info_length(0)
 
-	0x02, 0xe1, 0x00, 0xf0, 0x00, // video stream type(2), pid(0x100)
-	0x04, 0xe1, 0x03, 0xf0, 0x00, // audio stream type(4), pid(0x103)
+	0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
+	0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
 
-	0xa1, 0xca, 0x0f, 0x82 // CRC32
+	0x00, 0x00, 0x00, 0x00 // CRC32
 };
 
-static struct mpeg_params mpeg_params_template =
+static struct v4l2_mpeg_compression param_defaults =
 {
-	.bitrate_mode = MPEG_BITRATE_MODE_CBR,
-	.video_target_bitrate = 5000,
-	.audio_bitrate = MPEG_AUDIO_BITRATE_256,
-	.total_bitrate = 6000,
+	.st_type         = V4L2_MPEG_TS_2,
+	.st_bitrate      = {
+		.mode    = V4L2_BITRATE_CBR,
+		.target  = 7000,
+	},
+
+	.ts_pid_pmt      = 16,
+	.ts_pid_video    = 260,
+	.ts_pid_audio    = 256,
+	.ts_pid_pcr      = 259,
+
+	.vi_type         = V4L2_MPEG_VI_2,
+	.vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
+	.vi_bitrate      = {
+		.mode    = V4L2_BITRATE_VBR,
+		.target  = 4000,
+		.max     = 6000,
+	},
+
+	.au_type         = V4L2_MPEG_AU_2_II,
+	.au_bitrate      = {
+		.mode    = V4L2_BITRATE_CBR,
+		.target  = 256,
+	},
+
+#if 0
+	/* FIXME: size? via S_FMT? */
+	.video_format = MPEG_VIDEO_FORMAT_D1,
+#endif
 };
 
-
 /* ---------------------------------------------------------------------- */
 
-
 static int saa6752hs_chip_command(struct i2c_client* client,
 				  enum saa6752hs_command command)
 {
@@ -124,7 +178,7 @@ static int saa6752hs_chip_command(struct
 		break;
 
 	case SAA6752HS_COMMAND_STOP:
-		  	buf[0] = 0x03;
+	  	buf[0] = 0x03;
 		break;
 
 	case SAA6752HS_COMMAND_START:
@@ -180,74 +234,162 @@ static int saa6752hs_chip_command(struct
 
 
 static int saa6752hs_set_bitrate(struct i2c_client* client,
-				 struct mpeg_params* params)
+				 struct v4l2_mpeg_compression* params)
 {
   	u8 buf[3];
 
 	// set the bitrate mode
 	buf[0] = 0x71;
-	buf[1] = params->bitrate_mode;
+	buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
 
 	// set the video bitrate
-	if (params->bitrate_mode == MPEG_BITRATE_MODE_VBR) {
+	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
 		// set the target bitrate
 		buf[0] = 0x80;
-	    	buf[1] = params->video_target_bitrate >> 8;
-	  	buf[2] = params->video_target_bitrate & 0xff;
+	    	buf[1] = params->vi_bitrate.target >> 8;
+	  	buf[2] = params->vi_bitrate.target & 0xff;
 		i2c_master_send(client, buf, 3);
 
 		// set the max bitrate
 		buf[0] = 0x81;
-	    	buf[1] = params->video_max_bitrate >> 8;
-	  	buf[2] = params->video_max_bitrate & 0xff;
+	    	buf[1] = params->vi_bitrate.max >> 8;
+	  	buf[2] = params->vi_bitrate.max & 0xff;
 		i2c_master_send(client, buf, 3);
 	} else {
 		// set the target bitrate (no max bitrate for CBR)
   		buf[0] = 0x81;
-	    	buf[1] = params->video_target_bitrate >> 8;
-	  	buf[2] = params->video_target_bitrate & 0xff;
+	    	buf[1] = params->vi_bitrate.target >> 8;
+	  	buf[2] = params->vi_bitrate.target & 0xff;
 		i2c_master_send(client, buf, 3);
 	}
 
 	// set the audio bitrate
  	buf[0] = 0x94;
-  	buf[1] = params->audio_bitrate;
+	buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
 
 	// set the total bitrate
 	buf[0] = 0xb1;
-  	buf[1] = params->total_bitrate >> 8;
-  	buf[2] = params->total_bitrate & 0xff;
+  	buf[1] = params->st_bitrate.target >> 8;
+  	buf[2] = params->st_bitrate.target & 0xff;
 	i2c_master_send(client, buf, 3);
 
+	// return success
 	return 0;
 }
 
-
-static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params)
+static void saa6752hs_set_subsampling(struct i2c_client* client,
+				      struct v4l2_format* f)
 {
-	unsigned char buf[3];
-	void *data;
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+	int dist_352, dist_480, dist_720;
 
-	// check the bitrate parameters first
-	if (params != NULL) {
-		if (params->bitrate_mode >= MPEG_BITRATE_MODE_MAX)
-			return -EINVAL;
-		if (params->video_target_bitrate >= MPEG_VIDEO_TARGET_BITRATE_MAX)
-			return -EINVAL;
-  		if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX)
-			return -EINVAL;
-		if (params->audio_bitrate >= MPEG_AUDIO_BITRATE_MAX)
-			return -EINVAL;
-		if (params->total_bitrate >= MPEG_TOTAL_BITRATE_MAX)
-        		return -EINVAL;
-		if (params->bitrate_mode         == MPEG_BITRATE_MODE_MAX &&
-		    params->video_target_bitrate <= params->video_max_bitrate)
-			return -EINVAL;
+	/*
+	  FIXME: translate and round width/height into EMPRESS
+	  subsample type:
+
+	  type   |   PAL   |  NTSC
+	  ---------------------------
+	  SIF    | 352x288 | 352x240
+	  1/2 D1 | 352x576 | 352x480
+	  2/3 D1 | 480x576 | 480x480
+	  D1     | 720x576 | 720x480
+	*/
+
+	dist_352 = abs(f->fmt.pix.width - 352);
+	dist_480 = abs(f->fmt.pix.width - 480);
+	dist_720 = abs(f->fmt.pix.width - 720);
+	if (dist_720 < dist_480) {
+		f->fmt.pix.width = 720;
+		f->fmt.pix.height = 576;
+		h->video_format = SAA6752HS_VF_D1;
 	}
+	else if (dist_480 < dist_352) {
+		f->fmt.pix.width = 480;
+		f->fmt.pix.height = 576;
+		h->video_format = SAA6752HS_VF_2_3_D1;
+	}
+	else {
+		f->fmt.pix.width = 352;
+		if (abs(f->fmt.pix.height - 576) <
+		    abs(f->fmt.pix.height - 288)) {
+			f->fmt.pix.height = 576;
+			h->video_format = SAA6752HS_VF_1_2_D1;
+		}
+		else {
+			f->fmt.pix.height = 288;
+			h->video_format = SAA6752HS_VF_SIF;
+		}
+	}
+}
+
+
+static void saa6752hs_set_params(struct i2c_client* client,
+				 struct v4l2_mpeg_compression* params)
+{
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+
+	/* check PIDs */
+	if (params->ts_pid_pmt <= MPEG_PID_MAX)
+		h->params.ts_pid_pmt = params->ts_pid_pmt;
+	if (params->ts_pid_pcr <= MPEG_PID_MAX)
+		h->params.ts_pid_pcr = params->ts_pid_pcr;
+	if (params->ts_pid_video <= MPEG_PID_MAX)
+		h->params.ts_pid_video = params->ts_pid_video;
+	if (params->ts_pid_audio <= MPEG_PID_MAX)
+		h->params.ts_pid_audio = params->ts_pid_audio;
+
+	/* check bitrate parameters */
+	if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
+	    (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
+		h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.st_bitrate.target = params->st_bitrate.target;
+	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.vi_bitrate.target = params->vi_bitrate.target;
+	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
+		h->params.vi_bitrate.max = params->vi_bitrate.max;
+	if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.au_bitrate.target = params->au_bitrate.target;
+
+	/* aspect ratio */
+	if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
+	    params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
+		h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+
+	/* range checks */
+	if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+		h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+	if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+		h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+	if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+		h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+	if (h->params.au_bitrate.target <= 256)
+		h->params.au_bitrate.target = 256;
+	else
+		h->params.au_bitrate.target = 384;
+}
+
+static int saa6752hs_init(struct i2c_client* client)
+{
+	unsigned char buf[9], buf2[4];
+	struct saa6752hs_state *h;
+	u32 crc;
+	unsigned char localPAT[256];
+	unsigned char localPMT[256];
+
+	h = i2c_get_clientdata(client);
+
+	// Set video format - must be done first as it resets other settings
+	buf[0] = 0x41;
+	buf[1] = h->video_format;
+	i2c_master_send(client, buf, 2);
+
+        // set bitrate
+        saa6752hs_set_bitrate(client, &h->params);
 
-    	// Set GOP structure {3, 13}
+	// Set GOP structure {3, 13}
 	buf[0] = 0x72;
 	buf[1] = 0x03;
 	buf[2] = 0x0D;
@@ -265,7 +407,7 @@ static int saa6752hs_init(struct i2c_cli
 
     	// Set Output Protocol
 	buf[0] = 0xD0;
-	buf[1] = 0x01;
+	buf[1] = 0x81;
 	i2c_master_send(client,buf,2);
 
     	// Set video output stream format {TS}
@@ -273,25 +415,53 @@ static int saa6752hs_init(struct i2c_cli
 	buf[1] = 0x05;
 	i2c_master_send(client,buf,2);
 
-    	// Set Audio PID {0x103}
+	/* compute PAT */
+	memcpy(localPAT, PAT, sizeof(PAT));
+	localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+	localPAT[18] = h->params.ts_pid_pmt & 0xff;
+	crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4);
+	localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF;
+	localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF;
+	localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF;
+	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
+
+	/* compute PMT */
+      	memcpy(localPMT, PMT, sizeof(PMT));
+   	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+   	localPMT[4] = h->params.ts_pid_pmt & 0xff;
+	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
+	localPMT[16] = h->params.ts_pid_pcr & 0xFF;
+	localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
+	localPMT[21] = h->params.ts_pid_video & 0xFF;
+	localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
+	localPMT[26] = h->params.ts_pid_audio & 0xFF;
+	crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
+	localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
+	localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
+	localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
+	localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+
+    	// Set Audio PID
 	buf[0] = 0xC1;
-	buf[1] = 0x01;
-	buf[2] = 0x03;
+	buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_audio & 0xFF;
 	i2c_master_send(client,buf,3);
 
-        // setup bitrate settings
-	data = i2c_get_clientdata(client);
-	if (params) {
-		saa6752hs_set_bitrate(client, params);
-		memcpy(data, params, sizeof(struct mpeg_params));
-	} else {
-		// parameters were not supplied. use the previous set
-   		saa6752hs_set_bitrate(client, (struct mpeg_params*) data);
-	}
+	// Set Video PID
+	buf[0] = 0xC0;
+	buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_video & 0xFF;
+	i2c_master_send(client,buf,3);
+
+ 	// Set PCR PID
+	buf[0] = 0xC4;
+	buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_pcr & 0xFF;
+	i2c_master_send(client,buf,3);
 
 	// Send SI tables
-  	i2c_master_send(client,PAT,sizeof(PAT));
-  	i2c_master_send(client,PMT,sizeof(PMT));
+	i2c_master_send(client,localPAT,sizeof(PAT));
+	i2c_master_send(client,localPMT,sizeof(PMT));
 
 	// mute then unmute audio. This removes buzzing artefacts
 	buf[0] = 0xa4;
@@ -303,31 +473,56 @@ static int saa6752hs_init(struct i2c_cli
 	// start it going
 	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
 
+	// readout current state
+	buf[0] = 0xE1;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	i2c_master_send(client, buf, 5);
+	i2c_master_recv(client, buf2, 4);
+
+	// change aspect ratio
+	buf[0] = 0xE0;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	buf[5] = buf2[0];
+	switch(h->params.vi_aspect_ratio) {
+	case V4L2_MPEG_ASPECT_16_9:
+		buf[6] = buf2[1] | 0x40;
+		break;
+	case V4L2_MPEG_ASPECT_4_3:
+	default:
+		buf[6] = buf2[1] & 0xBF;
+		break;
+		break;
+	}
+	buf[7] = buf2[2];
+	buf[8] = buf2[3];
+	i2c_master_send(client, buf, 9);
+
+   	// return success
 	return 0;
 }
 
 static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
 {
-	struct i2c_client *client;
-	struct mpeg_params* params;
-
-        client_template.adapter = adap;
-        client_template.addr = addr;
+	struct saa6752hs_state *h;
 
         printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
 
-        if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+        if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
                 return -ENOMEM;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-	strlcpy(client->name, "saa6752hs", sizeof(client->name));
-
-	if (NULL == (params = kmalloc(sizeof(struct mpeg_params), GFP_KERNEL)))
-		return -ENOMEM;
-	memcpy(params,&mpeg_params_template,sizeof(struct mpeg_params));
-	i2c_set_clientdata(client, params);
-
-        i2c_attach_client(client);
+	memset(h,0,sizeof(*h));
+	h->client = client_template;
+	h->params = param_defaults;
+	h->client.adapter = adap;
+	h->client.addr = addr;
 
+	i2c_set_clientdata(&h->client, h);
+        i2c_attach_client(&h->client);
 	return 0;
 }
 
@@ -340,30 +535,58 @@ static int saa6752hs_probe(struct i2c_ad
 
 static int saa6752hs_detach(struct i2c_client *client)
 {
-	void *data;
+	struct saa6752hs_state *h;
 
-	data = i2c_get_clientdata(client);
+	h = i2c_get_clientdata(client);
 	i2c_detach_client(client);
-	kfree(data);
-	kfree(client);
+	kfree(h);
 	return 0;
 }
 
 static int
 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	struct mpeg_params* init_arg = arg;
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+	struct v4l2_mpeg_compression *params = arg;
+	int err = 0;
 
         switch (cmd) {
-	case MPEG_SETPARAMS:
-   		return saa6752hs_init(client, init_arg);
+	case VIDIOC_S_MPEGCOMP:
+		if (NULL == params) {
+			/* apply settings and start encoder */
+			saa6752hs_init(client);
+			break;
+		}
+		saa6752hs_set_params(client, params);
+		/* fall through */
+	case VIDIOC_G_MPEGCOMP:
+		*params = h->params;
+		break;
+	case VIDIOC_G_FMT:
+	{
+           struct v4l2_format *f = arg;
+
+	   if (h->video_format == SAA6752HS_VF_UNKNOWN)
+		   h->video_format = SAA6752HS_VF_D1;
+	   f->fmt.pix.width =
+		   v4l2_format_table[h->video_format].fmt.pix.width;
+	   f->fmt.pix.height =
+		   v4l2_format_table[h->video_format].fmt.pix.height;
+	   break ;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
 
+		saa6752hs_set_subsampling(client, f);
+		break;
+	}
 	default:
 		/* nothing */
 		break;
 	}
 
-	return 0;
+	return err;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -380,7 +603,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-	I2C_DEVNAME("(saa6752hs unset)"),
+	I2C_DEVNAME("saa6752hs"),
 	.flags      = I2C_CLIENT_ALLOW_USE,
         .driver     = &driver,
 };
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1,5 +1,6 @@
+
 /*
- * $Id: saa7134-cards.c,v 1.35 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * card-specific stuff.
@@ -156,11 +157,11 @@ struct saa7134_board saa7134_boards[] = 
 			.gpio = 0x8000,
 		},
 	},
-	[SAA7134_BOARD_FLYTVPLATINUM] = {
+	[SAA7134_BOARD_FLYTVPLATINUM_MINI] = {
 		/* "Arnaud Quette" <aquette@free.fr> */
-		.name           = "LifeView FlyTV Platinum",
+		.name           = "LifeView FlyTV Platinum Mini",
 		.audio_clock    = 0x00200000,
-		.tuner_type     = TUNER_PHILIPS_SECAM,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -176,6 +177,47 @@ struct saa7134_board saa7134_boards[] = 
 			.amux = LINE2,
 		}},
 	},
+	[SAA7134_BOARD_FLYTVPLATINUM_FM] = {
+		/* LifeView FlyTV Platinum FM (LR214WF) */
+		/* "Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyTV Platinum FM",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.gpiomask       = 0x1E000,	/* Set GP16 and unused 15,14,13 to Output */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x10000,	/* GP16=1 selects TV input */
+			.tv   = 1,
+                },{
+/*			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+*/			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00000,	/* GP16=0 selects FM radio antenna */
+		},
+	},
 	[SAA7134_BOARD_EMPRESS] = {
 		/* "Gert Vervoort" <gert.vervoort@philips.com> */
 		.name		= "EMPRESS",
@@ -436,6 +478,7 @@ struct saa7134_board saa7134_boards[] = 
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs = {{
 			.name   = name_tv,
 			.vmux   = 1,
@@ -444,11 +487,11 @@ struct saa7134_board saa7134_boards[] = 
 		},{
 			.name   = name_comp1,
 			.vmux   = 0,
-			.amux   = LINE2,
+			.amux   = LINE1,
 		},{
 			.name   = name_svideo,
 			.vmux   = 8,
-			.amux   = LINE2,
+			.amux   = LINE1,
 		}},
 		.radio = {
 			.name   = name_radio,
@@ -544,6 +587,34 @@ struct saa7134_board saa7134_boards[] = 
                         .amux = LINE1,
                 },
 	},
+	[SAA7135_BOARD_ASUSTeK_TVFM7135] = {
+                .name           = "ASUS TV-FM 7135",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_TDA8290,
+		.gpiomask       = 0x200000,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+			.gpio = 0x0000,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE2,
+			.gpio = 0x0000,
+                },{
+                        .name = name_svideo,
+                        .vmux = 6,
+                        .amux = LINE2,
+			.gpio = 0x0000,
+                }},
+                .radio = {
+                        .name = name_radio,
+                        .amux = TV,
+			.gpio = 0x200000,
+                },
+	},
 	[SAA7134_BOARD_VA1000POWER] = {
                 .name           = "AOPEN VA1000 POWER",
 		.audio_clock    = 0x00187de7,
@@ -749,7 +820,7 @@ struct saa7134_board saa7134_boards[] = 
 		},{
 			.name = name_tv,
 			.vmux = 3,
-			.amux = LINE2,
+			.amux = TV,
 			.tv   = 1,
 		}},
 		.mpeg      = SAA7134_MPEG_EMPRESS,
@@ -828,6 +899,10 @@ struct saa7134_board saa7134_boards[] = 
 			.name = name_radio,
 			.amux = LINE2,
 		},
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE1,
+		},
 	},
 	[SAA7134_BOARD_MANLI_MTV001] = {
 		/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
@@ -975,6 +1050,9 @@ struct saa7134_board saa7134_boards[] = 
 		.inputs         = {{
 			.name = name_comp1,
 			.vmux = 3,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
 		}},
 	},
         [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
@@ -995,11 +1073,12 @@ struct saa7134_board saa7134_boards[] = 
                         .vmux = 8,
                 }},
         },
-	[SAA7134_BOARD_AVERMEDIA_305] = {
-		.name           = "AverMedia 305",
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_305] = {
+		.name           = "AverMedia AverTV Studio 305",
 		.audio_clock    = 0x00187de7,
-		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask = 0x3,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -1104,23 +1183,23 @@ struct saa7134_board saa7134_boards[] = 
                         .name = name_svideo,
                         .vmux = 8,
                         .amux = LINE1,
-			.gpio = 0x00080
+			.gpio = 0x00080,
                 },{
                         .name = name_comp1,
                         .vmux = 3,
                         .amux = LINE1,
-			.gpio = 0x00080
+			.gpio = 0x00080,
                 },{
                         .name = name_tv,
                         .vmux = 1,
-                        .amux = LINE2,
+                        .amux = LINE2_LEFT,
                         .tv   = 1,
-			.gpio = 0x00080
+			.gpio = 0x00080,
                 }},
 		.radio = {
-			 .name = name_radio,
-			 .amux = LINE2,
-			.gpio = 0x80000
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x80000,
 		 },
 		.mute = {
 			.name = name_mute,
@@ -1129,21 +1208,20 @@ struct saa7134_board saa7134_boards[] = 
 		},
         },
         [SAA7134_BOARD_SABRENT_SBTTVFM] = {
-		/* Michael Rodriguez-Torrent */
+		/* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */
                 .name           = "Sabrent SBT-TVFM (saa7130)",
                 .audio_clock    = 0x00187de7,
                 .tuner_type     = TUNER_PHILIPS_NTSC_M,
-  		.tda9887_conf   = TDA9887_PRESENT,
                 .inputs         = {{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE2,
+		},{
                         .name = name_tv,
                         .vmux = 3,
                         .amux = LINE2,
                         .tv   = 1,
                 },{
-                        .name = name_comp1,
-                        .vmux = 1,
-                        .amux = LINE2,
-                },{
                         .name = name_svideo,
                         .vmux = 8,
                         .amux = LINE2,
@@ -1208,32 +1286,41 @@ struct saa7134_board saa7134_boards[] = 
 		 }
 	},
         [SAA7134_BOARD_AVERMEDIA_307] = {
-		/* Nickolay V. Shmyrev <nshmyrev@yandex.ru> */
+		/*
+		Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+		Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
+		*/
 		.name           = "Avermedia AVerTV Studio 307",
 		.audio_clock    = 0x00187de7,
-		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x03,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
 			.amux = TV,
 			.tv   = 1,
+			.gpio = 0x00,
 		},{
 			.name = name_comp1,
 			.vmux = 0,
 			.amux = LINE2,
+			.gpio = 0x00,
 		},{
 			.name = name_comp2,
 			.vmux = 3,
 			.amux = LINE2,
+			.gpio = 0x00,
 		},{
 			.name = name_svideo,
 			.vmux = 8,
 			.amux = LINE2,
+			.gpio = 0x00,
 		}},
 		.radio = {
 			.name = name_radio,
-			.amux = TV,
+			.amux = LINE1,
+			.gpio = 0x01,
 		},
         },
 	[SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
@@ -1263,10 +1350,17 @@ struct saa7134_board saa7134_boards[] = 
 	[SAA7134_BOARD_CINERGY400_CARDBUS] = {
 		.name           = "Terratec Cinergy 400 mobile",
 		.audio_clock    = 0x187de7,
-		.tuner_type     = UNSET /* not supported yet :/ */,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+  		.tda9887_conf   = TDA9887_PRESENT,
 		.inputs         = {{
        			.name = name_tv,
-			.vmux = 5,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+               },{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
 			.tv   = 1,
                 },{
                         .name = name_comp1,
@@ -1274,8 +1368,182 @@ struct saa7134_board saa7134_boards[] = 
                         .amux = LINE1,
                 },{
                         .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_CINERGY600_MK3] = {
+                .name           = "Terratec Cinergy 600 TV MK3",
+                .audio_clock    = 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+  		.tda9887_conf   = TDA9887_PRESENT,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
                         .vmux = 4,
                         .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp2, // CVideo over SVideo Connector
+                        .vmux = 0,
+                        .amux = LINE1,
+                }},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+               },
+        },
+ 	[SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
+ 		/* Dylan Walkden <dylan_walkden@hotmail.com> */
+ 		.name		= "Compro VideoMate Gold+ Pal",
+ 		.audio_clock	= 0x00187de7,
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.gpiomask	= 0x1ce780,
+ 		.inputs		= {{
+ 			.name = name_svideo,
+ 			.vmux = 0,		// CVideo over SVideo Connector - ok?
+ 			.amux = LINE1,
+ 			.gpio = 0x008080,
+ 		},{
+ 			.name = name_comp1,
+ 			.vmux = 3,
+ 			.amux = LINE1,
+ 			.gpio = 0x008080,
+ 		},{
+ 			.name = name_tv,
+ 			.vmux = 1,
+ 			.amux = TV,
+ 			.tv   = 1,
+ 			.gpio = 0x008080,
+ 		}},
+ 		.radio = {
+ 			.name = name_radio,
+ 			.amux = LINE2,
+ 			.gpio = 0x80000,
+ 		},
+ 		.mute = {
+ 			.name = name_mute,
+ 			.amux = LINE2,
+ 			.gpio = 0x0c8000,
+ 		},
+ 	},
+	[SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = {
+                .name           = "Pinnacle PCTV 300i DVB-T + PAL",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_MT2032,
+                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+		.mpeg           = SAA7134_MPEG_DVB,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 3,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 0,
+                        .amux = LINE2,
+                },{
+                        .name = name_comp2,
+                        .vmux = 1,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE2,
+                }},
+        },
+	[SAA7134_BOARD_PROVIDEO_PV952] = {
+		/* andreas.kretschmer@web.de */
+		.name		= "ProVideo PV952",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_305] = {
+		/* much like the "studio" version but without radio
+		 * and another tuner (sirspiritus@yandex.ru) */
+		.name           = "AverMedia AverTV/305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask = 0x3,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.mute = {
+			 .name = name_mute,
+			 .amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_FLYDVBTDUO] = {
+		/* LifeView FlyDVB-T DUO */
+		/* "Nico Sabbi <nsabbi@tiscali.it> */
+		.name           = "LifeView FlyDVB-T DUO",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+//		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+//			.gpio = 0x0000,
+			.tv   = 1,
+                },{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+//			.gpio = 0x4000,
 		}},
 	},
 };
@@ -1322,6 +1590,12 @@ struct pci_device_id saa7134_pci_tbl[] =
                 .subdevice    = 0x1143,
                 .driver_data  = SAA7134_BOARD_CINERGY600,
         },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x153B,
+                .subdevice    = 0x1158,
+                .driver_data  = SAA7134_BOARD_CINERGY600_MK3,
+        },{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x153b,
@@ -1349,8 +1623,20 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
 		.subvendor    = 0x5168,
-		.subdevice    = 0x0212,
-		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM,
+		.subdevice    = 0x0212, /* minipci, LR212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,	/* Animation Technologies (LifeView) */
+		.subdevice    = 0x0214, /* Standard PCI, LR214WF */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1489, /* KYE */
+		.subdevice    = 0x0214, /* Genius VideoWonder ProTV */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */
         },{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -1377,6 +1663,12 @@ struct pci_device_id saa7134_pci_tbl[] =
                 .driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
 	},{
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4845,
+                .driver_data  = SAA7135_BOARD_ASUSTeK_TVFM7135,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
                 .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                 .subvendor    = PCI_VENDOR_ID_ASUSTEK,
                 .subdevice    = 0x4830,
@@ -1452,6 +1744,12 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                 .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                 .subdevice    = 0x2115,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x2108,
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_305,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -1483,8 +1781,8 @@ struct pci_device_id saa7134_pci_tbl[] =
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
                 .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                 .subvendor    = 0x11bd,
-                .subdevice    = 0x002d, /* 300i DVB-T + PAL */
-                .driver_data  = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
+                .subdevice    = 0x002d,
+                .driver_data  = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
         },{
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
                 .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -1509,20 +1807,43 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.subvendor    = 0x153B,
 		.subdevice    = 0x1152,
 		.driver_data  = SAA7134_BOARD_CINERGY200,
-
  	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                 .subvendor    = 0x185b,
                 .subdevice    = 0xc100,
 		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV_PVR,
-
  	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1131,
+                .subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_SABRENT_SBTTVFM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
-               .subdevice    = 0x9715,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x9715,
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_307,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc200,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1540,
+		.subdevice    = 0x9524,
+		.driver_data  = SAA7134_BOARD_PROVIDEO_PV952,
+
+ 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0306,
+		.driver_data  = SAA7134_BOARD_FLYDVBTDUO,
 
  	},{
 		/* --- boards without eeprom + subsystem ID --- */
@@ -1631,16 +1952,20 @@ int saa7134_board_init1(struct saa7134_d
 	case SAA7134_BOARD_FLYVIDEO2000:
 	case SAA7134_BOARD_FLYVIDEO3000:
 		dev->has_remote = 1;
-		/* fall throuth */
-	case SAA7134_BOARD_FLYTVPLATINUM:
 		board_flyvideo(dev);
 		break;
+	case SAA7134_BOARD_FLYTVPLATINUM_FM:
 	case SAA7134_BOARD_CINERGY400:
 	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
 	case SAA7134_BOARD_ECS_TVP3XP:
 	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
 	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+	case SAA7134_BOARD_AVERMEDIA_305:
 	case SAA7134_BOARD_AVERMEDIA_307:
+//	case SAA7134_BOARD_SABRENT_SBTTVFM:  /* not finished yet */
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 		dev->has_remote = 1;
 		break;
 	case SAA7134_BOARD_AVACSSMARTTV:
@@ -1656,8 +1981,13 @@ int saa7134_board_init1(struct saa7134_d
 		/* power-up tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
+		msleep(1);
 		break;
 	}
+	if (dev->has_remote)
+		dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
+				   SAA7134_IRQ2_INTE_GPIO18A |
+				   SAA7134_IRQ2_INTE_GPIO16  );
 	return 0;
 }
 
@@ -1676,6 +2006,7 @@ int saa7134_board_init2(struct saa7134_d
 			: SAA7134_BOARD_BMK_MPEX_TUNER;
 		if (board == dev->board)
 			break;
+		dev->board = board;
 		printk("%s: board type fixup: %s\n", dev->name,
 		       saa7134_boards[dev->board].name);
 		dev->tuner_type = saa7134_boards[dev->board].tuner_type;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-core.c,v 1.15 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * driver core
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -88,7 +89,7 @@ MODULE_PARM_DESC(card,     "card type");
 static DECLARE_MUTEX(devlist_lock);
 LIST_HEAD(saa7134_devlist);
 static LIST_HEAD(mops_list);
-unsigned int saa7134_devcount;
+static unsigned int saa7134_devcount;
 
 #define dprintk(fmt, arg...)	if (core_debug) \
 	printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
@@ -620,7 +621,7 @@ static irqreturn_t saa7134_irq(int irq, 
 			dump_statusregs(dev);
 #endif
 
-		if (report & SAA7134_IRQ_REPORT_INTL)
+		if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
 			saa7134_irq_video_intl(dev);
 
 		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
@@ -642,8 +643,8 @@ static irqreturn_t saa7134_irq(int irq, 
 			       SAA7134_IRQ_REPORT_GPIO18)) &&
 		    dev->remote)
 			saa7134_input_irq(dev);
+	}
 
-	};
 	if (10 == loop) {
 		print_irqstatus(dev,loop,report,status);
 		if (report & SAA7134_IRQ_REPORT_PE) {
@@ -651,6 +652,13 @@ static irqreturn_t saa7134_irq(int irq, 
 			printk(KERN_WARNING "%s/irq: looping -- "
 			       "clearing PE (parity error!) enable bit\n",dev->name);
 			saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
+		} else if (report & (SAA7134_IRQ_REPORT_GPIO16 |
+				     SAA7134_IRQ_REPORT_GPIO18)) {
+			/* disable gpio IRQs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing GPIO enable bits\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 |
+						  SAA7134_IRQ2_INTE_GPIO18));
 		} else {
 			/* disable all irqs */
 			printk(KERN_WARNING "%s/irq: looping -- "
@@ -725,20 +733,7 @@ static int saa7134_hwinit2(struct saa713
 
 	/* enable IRQ's */
 	saa_writel(SAA7134_IRQ1, 0);
-	saa_writel(SAA7134_IRQ2,
-		   SAA7134_IRQ2_INTE_GPIO18  |
-		   SAA7134_IRQ2_INTE_GPIO18A |
-		   SAA7134_IRQ2_INTE_GPIO16  |
-		   SAA7134_IRQ2_INTE_SC2     |
-		   SAA7134_IRQ2_INTE_SC1     |
-		   SAA7134_IRQ2_INTE_SC0     |
-		   /* SAA7134_IRQ2_INTE_DEC5    |  FIXME: TRIG_ERR ??? */
-		   SAA7134_IRQ2_INTE_DEC3    |
-		   SAA7134_IRQ2_INTE_DEC2    |
-		   /* SAA7134_IRQ2_INTE_DEC1    | */
-		   SAA7134_IRQ2_INTE_DEC0    |
-		   SAA7134_IRQ2_INTE_PE      |
-		   SAA7134_IRQ2_INTE_AR);
+	saa_writel(SAA7134_IRQ2, dev->irq2_mask);
 
 	return 0;
 }
@@ -959,6 +954,13 @@ static int __devinit saa7134_initdev(str
 	}
 
 	/* initialize hardware #1 */
+   	dev->irq2_mask =
+		SAA7134_IRQ2_INTE_DEC3    |
+		SAA7134_IRQ2_INTE_DEC2    |
+		SAA7134_IRQ2_INTE_DEC1    |
+		SAA7134_IRQ2_INTE_DEC0    |
+		SAA7134_IRQ2_INTE_PE      |
+		SAA7134_IRQ2_INTE_AR;
 	saa7134_board_init1(dev);
 	saa7134_hwinit1(dev);
 
@@ -1060,6 +1062,9 @@ static int __devinit saa7134_initdev(str
 	}
 	list_add_tail(&dev->devlist,&saa7134_devlist);
 	up(&devlist_lock);
+
+	/* check for signal */
+	saa7134_irq_video_intl(dev);
 	return 0;
 
  fail5:
@@ -1207,6 +1212,10 @@ static int saa7134_init(void)
 
 static void saa7134_fini(void)
 {
+#ifdef CONFIG_MODULES
+	if (pending_registered)
+		unregister_module_notifier(&pending_notifier);
+#endif
 	pci_unregister_driver(&saa7134_pci_driver);
 }
 
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-dvb.c,v 1.4 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $
  *
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
@@ -30,35 +30,211 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
+#include "dvb-pll.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
+static unsigned int antenna_pwr = 0;
+module_param(antenna_pwr, int, 0444);
+MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
 /* ------------------------------------------------------------------ */
 
-static int dvb_init(struct saa7134_dev *dev)
+static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
-	printk("%s: %s\n",dev->name,__FUNCTION__);
+	u32 ok;
+
+	if (!on) {
+		saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+		return 0;
+	}
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	udelay(10);
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 28));
+	saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+	udelay(10);
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
+	udelay(10);
+	ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
+	printk("%s: %s %s\n", dev->name, __FUNCTION__,
+	       ok ? "on" : "off");
+
+	if (!ok)
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	return ok;
+}
+
+static int mt352_pinnacle_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x3d, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
+	static u8 fsm_ctl_cfg[]    = { 0x7b,       0x04 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x0f };
+	static u8 scan_ctl_cfg []  = { SCAN_CTL,   0x0d };
+	static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
+	struct saa7134_dev *dev= fe->dvb->priv;
+
+	printk("%s: %s called\n",dev->name,__FUNCTION__);
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+
+	mt352_write(fe, fsm_ctl_cfg,    sizeof(fsm_ctl_cfg));
+	mt352_write(fe, scan_ctl_cfg,   sizeof(scan_ctl_cfg));
+	mt352_write(fe, irq_cfg,        sizeof(irq_cfg));
+	return 0;
+}
 
+static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters* params,
+				  u8* pllbuf)
+{
+	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+	static int off = TDA9887_PRESENT | TDA9887_PORT2_ACTIVE;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct v4l2_frequency f;
+
+	/* set frequency (mt2050) */
+	f.tuner     = 0;
+	f.type      = V4L2_TUNER_DIGITAL_TV;
+	f.frequency = params->frequency / 1000 * 16 / 1000;
+	saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
+	saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+	saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&off);
+
+	pinnacle_antenna_pwr(dev, antenna_pwr);
+
+	/* mt352 setup */
+	mt352_pinnacle_init(fe);
+	pllbuf[0] = 0xc2;
+	pllbuf[1] = 0x00;
+	pllbuf[2] = 0x00;
+	pllbuf[3] = 0x80;
+	pllbuf[4] = 0x00;
+	return 0;
+}
+
+static struct mt352_config pinnacle_300i = {
+	.demod_address = 0x3c >> 1,
+	.adc_clock     = 20333,
+	.if2           = 36150,
+	.no_tuner      = 1,
+	.demod_init    = mt352_pinnacle_init,
+	.pll_set       = mt352_pinnacle_pll_set,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int medion_cardbus_init(struct dvb_frontend* fe)
+{
+	/* anything to do here ??? */
+	return 0;
+}
+
+static int medion_cardbus_pll_set(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters* params)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct v4l2_frequency f;
+
+	/*
+	 * this instructs tuner.o to set the frequency, the call will
+	 * end up in tuner_command(), VIDIOC_S_FREQUENCY switch.
+	 * tda9887.o will see that as well.
+	 */
+	f.tuner     = 0;
+	f.type      = V4L2_TUNER_DIGITAL_TV;
+	f.frequency = params->frequency / 1000 * 16 / 1000;
+	saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+	return 0;
+}
+
+static int fe_request_firmware(struct dvb_frontend* fe,
+			       const struct firmware **fw, char* name)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	return request_firmware(fw, name, &dev->pci->dev);
+}
+
+static struct tda1004x_config medion_cardbus = {
+	.demod_address = 0x08,  /* not sure this is correct */
+	.invert        = 0,
+        .invert_oclk   = 0,
+        .pll_init      = medion_cardbus_init,
+        .pll_set       = medion_cardbus_pll_set,
+        .request_firmware = fe_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
 	/* init struct videobuf_dvb */
+	dev->ts.nr_bufs    = 32;
+	dev->ts.nr_packets = 32*4;
 	dev->dvb.name = dev->name;
 	videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_TOP,
+			    V4L2_FIELD_ALTERNATE,
 			    sizeof(struct saa7134_buf),
 			    dev);
 
-	/* TODO: init frontend */
-	if (NULL == dev->dvb.frontend)
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		printk("%s: pinnacle 300i dvb setup\n",dev->name);
+		dev->dvb.frontend = mt352_attach(&pinnacle_300i,
+						 &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_MD7134:
+		dev->dvb.frontend = tda10046_attach(&medion_cardbus,
+						    &dev->i2c_adap);
+		if (NULL == dev->dvb.frontend)
+			printk("%s: Hmm, looks like this is the old MD7134 "
+			       "version without DVB-T support\n",dev->name);
+		break;
+	default:
+		printk("%s: Huh? unknown DVB card?\n",dev->name);
+		break;
+	}
+
+	if (NULL == dev->dvb.frontend) {
+		printk("%s: frontend initialization failed\n",dev->name);
 		return -1;
+	}
 
 	/* register everything else */
-	return videobuf_dvb_register(&dev->dvb);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
 {
+	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
 	printk("%s: %s\n",dev->name,__FUNCTION__);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		/* otherwise we don't detect the tuner on next insmod */
+		saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
+		break;
+	};
 	videobuf_dvb_unregister(&dev->dvb);
 	return 0;
 }
@@ -86,6 +262,5 @@ module_exit(dvb_unregister);
 /*
  * Local variables:
  * c-basic-offset: 8
- * compile-command: "make DVB=1"
  * End:
  */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-empress.c,v 1.3 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $
  *
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -50,16 +51,21 @@ MODULE_PARM_DESC(debug,"enable debug mes
 
 static void ts_reset_encoder(struct saa7134_dev* dev)
 {
+	if (!dev->empress_started)
+		return;
+
 	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
 	msleep(10);
    	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 	msleep(100);
+	dev->empress_started = 0;
 }
 
-static int ts_init_encoder(struct saa7134_dev* dev, void* arg)
+static int ts_init_encoder(struct saa7134_dev* dev)
 {
 	ts_reset_encoder(dev);
-	saa7134_i2c_call_clients(dev, MPEG_SETPARAMS, arg);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+	dev->empress_started = 1;
  	return 0;
 }
 
@@ -81,18 +87,19 @@ static int ts_open(struct inode *inode, 
 		return -ENODEV;
 
 	dprintk("open minor=%d\n",minor);
-	down(&dev->empress_tsq.lock);
 	err = -EBUSY;
-	if (dev->empress_users)
+	if (down_trylock(&dev->empress_tsq.lock))
 		goto done;
+	if (dev->empress_users)
+		goto done_up;
 
 	dev->empress_users++;
 	file->private_data = dev;
-	ts_init_encoder(dev, NULL);
 	err = 0;
 
- done:
+done_up:
 	up(&dev->empress_tsq.lock);
+done:
 	return err;
 }
 
@@ -105,6 +112,7 @@ static int ts_release(struct inode *inod
 	down(&dev->empress_tsq.lock);
 	if (dev->empress_tsq.reading)
 		videobuf_read_stop(&dev->empress_tsq);
+	videobuf_mmap_free(&dev->empress_tsq);
 	dev->empress_users--;
 
 	/* stop the encoder */
@@ -119,6 +127,9 @@ ts_read(struct file *file, char __user *
 {
 	struct saa7134_dev *dev = file->private_data;
 
+	if (!dev->empress_started)
+		ts_init_encoder(dev);
+
 	return videobuf_read_stream(&dev->empress_tsq,
 				    data, count, ppos, 0,
 				    file->f_flags & O_NONBLOCK);
@@ -222,10 +233,7 @@ static int ts_do_ioctl(struct inode *ino
 		memset(f,0,sizeof(*f));
 		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
-		/* FIXME: translate subsampling type EMPRESS into
-		 *        width/height: */
-		f->fmt.pix.width        = 720; /* D1 */
-		f->fmt.pix.height       = 576;
+		saa7134_i2c_call_clients(dev, cmd, arg);
 		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 		f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
 		return 0;
@@ -238,20 +246,7 @@ static int ts_do_ioctl(struct inode *ino
 		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		    return -EINVAL;
 
-		/*
-		  FIXME: translate and round width/height into EMPRESS
-		  subsample type:
-
-		          type  |   PAL   |  NTSC
-			---------------------------
-			  SIF   | 352x288 | 352x240
-			 1/2 D1 | 352x576 | 352x480
-			 2/3 D1 | 480x576 | 480x480
-			  D1    | 720x576 | 720x480
-		*/
-
-		f->fmt.pix.width        = 720; /* D1 */
-		f->fmt.pix.height       = 576;
+		saa7134_i2c_call_clients(dev, cmd, arg);
 		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 		f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
 		return 0;
@@ -281,8 +276,13 @@ static int ts_do_ioctl(struct inode *ino
 	case VIDIOC_S_CTRL:
 		return saa7134_common_ioctl(dev, cmd, arg);
 
-	case MPEG_SETPARAMS:
-		return ts_init_encoder(dev, arg);
+	case VIDIOC_S_MPEGCOMP:
+		saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
+		ts_init_encoder(dev);
+		return 0;
+	case VIDIOC_G_MPEGCOMP:
+		saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
+		return 0;
 
 	default:
 		return -ENOIOCTLCMD;
@@ -320,6 +320,26 @@ static struct video_device saa7134_empre
 	.minor	       = -1,
 };
 
+static void empress_signal_update(void* data)
+{
+	struct saa7134_dev* dev = (struct saa7134_dev*) data;
+
+	if (dev->nosignal) {
+		dprintk("no video signal\n");
+		ts_reset_encoder(dev);
+	} else {
+		dprintk("video signal acquired\n");
+		if (dev->empress_users)
+			ts_init_encoder(dev);
+	}
+}
+
+static void empress_signal_change(struct saa7134_dev *dev)
+{
+	schedule_work(&dev->empress_workqueue);
+}
+
+
 static int empress_init(struct saa7134_dev *dev)
 {
 	int err;
@@ -335,6 +355,8 @@ static int empress_init(struct saa7134_d
 		 "%s empress (%s)", dev->name,
 		 saa7134_boards[dev->board].name);
 
+	INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev);
+
 	err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
 				    empress_nr[dev->nr]);
 	if (err < 0) {
@@ -353,6 +375,8 @@ static int empress_init(struct saa7134_d
 			    V4L2_FIELD_ALTERNATE,
 			    sizeof(struct saa7134_buf),
 			    dev);
+
+	empress_signal_update(dev);
 	return 0;
 }
 
@@ -362,6 +386,7 @@ static int empress_fini(struct saa7134_d
 
 	if (NULL == dev->empress_dev)
 		return 0;
+	flush_scheduled_work();
 	video_unregister_device(dev->empress_dev);
 	dev->empress_dev = NULL;
 	return 0;
@@ -371,6 +396,7 @@ static struct saa7134_mpeg_ops empress_o
 	.type          = SAA7134_MPEG_EMPRESS,
 	.init          = empress_init,
 	.fini          = empress_fini,
+	.signal_change = empress_signal_change,
 };
 
 static int __init empress_register(void)
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-i2c.c,v 1.7 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * i2c interface support
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -205,7 +206,8 @@ static inline int i2c_send_byte(struct s
 	dword &= 0x0f;
 	dword |= (attr << 6);
 	dword |= ((__u32)data << 8);
-	dword |= 0x00 << 16;
+	dword |= 0x00 << 16;  /* 100 kHz */
+//	dword |= 0x40 << 16;  /* 400 kHz */
 	dword |= 0xf0 << 24;
 	saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
 #endif
@@ -236,7 +238,7 @@ static inline int i2c_recv_byte(struct s
 }
 
 static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
-			    struct i2c_msg msgs[], int num)
+			    struct i2c_msg *msgs, int num)
 {
 	struct saa7134_dev *dev = i2c_adap->algo_data;
 	enum i2c_status status;
@@ -248,13 +250,24 @@ static int saa7134_i2c_xfer(struct i2c_a
 		if (!i2c_reset(dev))
 			return -EIO;
 
+	d2printk("start xfer\n");
 	d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name);
 	for (i = 0; i < num; i++) {
 		if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) {
 			/* send address */
+			d2printk("send address\n");
 			addr  = msgs[i].addr << 1;
 			if (msgs[i].flags & I2C_M_RD)
 				addr |= 1;
+			if (i > 0 && msgs[i].flags & I2C_M_RD) {
+				/* workaround for a saa7134 i2c bug
+				 * needed to talk to the mt352 demux
+				 * thanks to pinnacle for the hint */
+				int quirk = 0xfd;
+				d1printk(" [%02x quirk]",quirk);
+				i2c_send_byte(dev,START,quirk);
+				i2c_recv_byte(dev);
+			}
 			d1printk(" < %02x", addr);
 			rc = i2c_send_byte(dev,START,addr);
 			if (rc < 0)
@@ -262,6 +275,7 @@ static int saa7134_i2c_xfer(struct i2c_a
 		}
 		if (msgs[i].flags & I2C_M_RD) {
 			/* read bytes */
+			d2printk("read bytes\n");
 			for (byte = 0; byte < msgs[i].len; byte++) {
 				d1printk(" =");
 				rc = i2c_recv_byte(dev);
@@ -272,6 +286,7 @@ static int saa7134_i2c_xfer(struct i2c_a
 			}
 		} else {
 			/* write bytes */
+			d2printk("write bytes\n");
 			for (byte = 0; byte < msgs[i].len; byte++) {
 				data = msgs[i].buf[byte];
 				d1printk(" %02x", data);
@@ -281,6 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_a
 			}
 		}
 	}
+	d2printk("xfer done\n");
 	d1printk(" >");
 	i2c_set_attr(dev,STOP);
 	rc = -EIO;
@@ -313,18 +329,6 @@ static u32 functionality(struct i2c_adap
 	return I2C_FUNC_SMBUS_EMUL;
 }
 
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
-	MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
-	MOD_DEC_USE_COUNT;
-}
-#endif
-
 static int attach_inform(struct i2c_client *client)
 {
         struct saa7134_dev *dev = client->adapter->algo_data;
@@ -345,12 +349,7 @@ static struct i2c_algorithm saa7134_algo
 };
 
 static struct i2c_adapter saa7134_adap_template = {
-#ifdef I2C_PEC
 	.owner         = THIS_MODULE,
-#else
-	.inc_use       = inc_use,
-	.dec_use       = dec_use,
-#endif
 #ifdef I2C_CLASS_TV_ANALOG
 	.class         = I2C_CLASS_TV_ANALOG,
 #endif
@@ -362,7 +361,6 @@ static struct i2c_adapter saa7134_adap_t
 
 static struct i2c_client saa7134_client_template = {
 	I2C_DEVNAME("saa7134 internal"),
-        .id        = -1,
 };
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-input.c,v 1.12 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
  *
  * handle saa7134 IR remotes via linux kernel input layer.
  *
@@ -20,6 +20,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
@@ -258,6 +259,55 @@ static IR_KEYTAB_TYPE md2819_codes[IR_KE
 	[ 17 ] = KEY_CHANNELDOWN,	// CHANNEL/PAGE-
 	[ 49 ] = KEY_CHANNELUP		// CHANNEL/PAGE+
 };
+
+static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
+	[ 20 ] = KEY_MUTE,
+	[ 36 ] = KEY_ZOOM,
+
+	[  1 ] = KEY_DVD,
+	[ 35 ] = KEY_RADIO,
+	[  0 ] = KEY_TV,
+
+	[ 10 ] = KEY_REWIND,
+	[  8 ] = KEY_PLAYPAUSE,
+	[ 15 ] = KEY_FORWARD,
+
+	[  2 ] = KEY_PREVIOUS,
+	[  7 ] = KEY_STOP,
+	[  6 ] = KEY_NEXT,
+
+	[ 12 ] = KEY_UP,
+	[ 14 ] = KEY_DOWN,
+	[ 11 ] = KEY_LEFT,
+	[ 13 ] = KEY_RIGHT,
+	[ 17 ] = KEY_OK,
+
+	[  3 ] = KEY_MENU,
+	[  9 ] = KEY_SETUP,
+	[  5 ] = KEY_VIDEO,
+	[ 34 ] = KEY_CHANNEL,
+
+	[ 18 ] = KEY_VOLUMEUP,
+	[ 21 ] = KEY_VOLUMEDOWN,
+	[ 16 ] = KEY_CHANNELUP,
+	[ 19 ] = KEY_CHANNELDOWN,
+
+	[  4 ] = KEY_RECORD,
+
+	[ 22 ] = KEY_KP1,
+	[ 23 ] = KEY_KP2,
+	[ 24 ] = KEY_KP3,
+	[ 25 ] = KEY_KP4,
+	[ 26 ] = KEY_KP5,
+	[ 27 ] = KEY_KP6,
+	[ 28 ] = KEY_KP7,
+	[ 29 ] = KEY_KP8,
+	[ 30 ] = KEY_KP9,
+	[ 31 ] = KEY_KP0,
+
+	[ 32 ] = KEY_LANGUAGE,
+	[ 33 ] = KEY_SLEEP,
+};
 /* ---------------------------------------------------------------------- */
 
 static int build_key(struct saa7134_dev *dev)
@@ -329,12 +379,14 @@ int saa7134_input_init1(struct saa7134_d
 	switch (dev->board) {
 	case SAA7134_BOARD_FLYVIDEO2000:
 	case SAA7134_BOARD_FLYVIDEO3000:
+	case SAA7134_BOARD_FLYTVPLATINUM_FM:
 		ir_codes     = flyvideo_codes;
 		mask_keycode = 0xEC00000;
 		mask_keydown = 0x0040000;
 		break;
 	case SAA7134_BOARD_CINERGY400:
 	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
 		ir_codes     = cinergy_codes;
 		mask_keycode = 0x00003f;
 		mask_keyup   = 0x040000;
@@ -353,6 +405,7 @@ int saa7134_input_init1(struct saa7134_d
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_AVERMEDIA_305:
 	case SAA7134_BOARD_AVERMEDIA_307:
 		ir_codes     = md2819_codes;
 		mask_keycode = 0x0007C8;
@@ -362,6 +415,12 @@ int saa7134_input_init1(struct saa7134_d
 		saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
 		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
 		break;
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+		ir_codes     = videomate_tv_pvr_codes;
+		mask_keycode = 0x00003F;
+		mask_keyup   = 0x400000;
+		polling      = 50; // ms
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-oss.c,v 1.11 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * oss dsp interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
@@ -543,6 +544,7 @@ mixer_recsrc_7134(struct saa7134_dev *de
 		break;
 	case LINE1:
 	case LINE2:
+	case LINE2_LEFT:
 		analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
 		rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
 		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
@@ -566,6 +568,7 @@ mixer_recsrc_7133(struct saa7134_dev *de
 		value = 0xbbbb32;  /* AUX1 */
 		break;
 	case LINE2:
+	case LINE2_LEFT:
 		value = 0xbbbb54;  /* AUX2 */
 		break;
 	}
@@ -608,6 +611,7 @@ mixer_level(struct saa7134_dev *dev, enu
 				   (100 == level) ? 0x00 : 0x10);
 			break;
 		case LINE2:
+		case LINE2_LEFT:
 			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
 				   (100 == level) ? 0x00 : 0x20);
 			break;
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-ts.c,v 1.12 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -220,10 +221,10 @@ void saa7134_irq_ts_done(struct saa7134_
 	if (dev->ts_q.curr) {
 		field = dev->ts_q.curr->vb.field;
 		if (field == V4L2_FIELD_TOP) {
-			if ((status & 0x100000) != 0x100000)
+			if ((status & 0x100000) != 0x000000)
 				goto done;
 		} else {
-			if ((status & 0x100000) != 0x000000)
+			if ((status & 0x100000) != 0x100000)
 				goto done;
 		}
 		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-tvaudio.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * tv audio decoder (fm stereo, nicam, ...)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -237,13 +238,14 @@ static void mute_input_7134(struct saa71
 
 	if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
 		/* 7134 mute */
-		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xff : 0xbb);
+		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
 
 	/* switch internal audio mux */
 	switch (in->amux) {
-	case TV:    ausel=0xc0; ics=0x00; ocs=0x02; break;
-	case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break;
-	case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break;
+	case TV:         ausel=0xc0; ics=0x00; ocs=0x02; break;
+	case LINE1:      ausel=0x80; ics=0x00; ocs=0x00; break;
+	case LINE2:      ausel=0x80; ics=0x08; ocs=0x01; break;
+	case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break;
 	}
 	saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
 	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
@@ -437,15 +439,16 @@ static int tvaudio_getstereo(struct saa7
 		nicam = saa_readb(SAA7134_NICAM_STATUS);
 		dprintk("getstereo: nicam=0x%x\n",nicam);
 		switch (nicam & 0x0b) {
-		case 0x08:
-			retval = V4L2_TUNER_SUB_MONO;
-			break;
 		case 0x09:
 			retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 			break;
 		case 0x0a:
 			retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
 			break;
+		case 0x08:
+		default:
+			retval = V4L2_TUNER_SUB_MONO;
+			break;
 		}
 		break;
 	}
@@ -748,9 +751,16 @@ static int mute_input_7133(struct saa713
 	int mask;
 
 	switch (dev->input->amux) {
-	case TV:    reg = 0x02; break;
-	case LINE1: reg = 0x00; break;
-	case LINE2: reg = 0x01; break;
+	case TV:
+		reg = 0x02;
+		break;
+	case LINE1:
+		reg = 0x00;
+		break;
+	case LINE2:
+	case LINE2_LEFT:
+		reg = 0x01;
+		break;
 	}
 	if (dev->ctl_mute)
 		reg = 0x07;
@@ -869,6 +879,21 @@ static int tvaudio_thread_ddep(void *dat
 /* ------------------------------------------------------------------ */
 /* common stuff + external entry points                               */
 
+static void saa7134_enable_i2s(struct saa7134_dev *dev)
+{
+	int i2s_format;
+
+	if (!card_is_empress(dev))
+		return;
+	i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+	/* enable I2S audio output for the mpeg encoder */
+	saa_writeb(SAA7134_I2S_OUTPUT_SELECT,  0x80);
+	saa_writeb(SAA7134_I2S_OUTPUT_FORMAT,  i2s_format);
+	saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,   0x0F);
+	saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,   0x01);
+}
+
 int saa7134_tvaudio_rx2mode(u32 rx)
 {
 	u32 mode;
@@ -911,6 +936,7 @@ void saa7134_tvaudio_setinput(struct saa
 		mute_input_7133(dev);
 		break;
 	}
+	saa7134_enable_i2s(dev);
 }
 
 void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
@@ -946,18 +972,6 @@ int saa7134_tvaudio_init2(struct saa7134
 	DECLARE_MUTEX_LOCKED(sem);
 	int (*my_thread)(void *data) = NULL;
 
-	/* enable I2S audio output */
-	if (card_is_empress(dev)) {
-		int i2sform = (48000 == dev->oss.rate)
-			? 0x01 : 0x00;
-
-		/* enable I2S output */
-		saa_writeb(SAA7134_I2S_OUTPUT_SELECT,  0x80);
-		saa_writeb(SAA7134_I2S_OUTPUT_FORMAT,  i2sform);
-		saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,   0x0F);
-		saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,   0x01);
-	}
-
 	switch (dev->pci->device) {
 	case PCI_DEVICE_ID_PHILIPS_SAA7134:
 		my_thread = tvaudio_thread;
@@ -977,9 +991,10 @@ int saa7134_tvaudio_init2(struct saa7134
 		if (dev->thread.pid < 0)
 			printk(KERN_WARNING "%s: kernel_thread() failed\n",
 			       dev->name);
-		wake_up_interruptible(&dev->thread.wq);
+		saa7134_tvaudio_do_scan(dev);
 	}
 
+	saa7134_enable_i2s(dev);
 	return 0;
 }
 
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-vbi.c,v 1.5 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134-video.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $
  *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
@@ -267,6 +268,24 @@ static struct saa7134_tvnorm tvnorms[] =
 		.chroma_ctrl2  = 0x06,
 		.vgate_misc    = 0x1c,
 
+	},{
+		.name          = "PAL-60",
+		.id            = V4L2_STD_PAL_60,
+
+		.h_start       = 0,
+		.h_stop        = 719,
+		.video_v_start = 22,
+		.video_v_stop  = 22+239,
+		.vbi_v_start   = 10, /* FIXME */
+		.vbi_v_stop    = 21, /* FIXME */
+		.src_timing    = 1,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
 	}
 };
 #define TVNORMS ARRAY_SIZE(tvnorms)
@@ -443,11 +462,10 @@ void res_free(struct saa7134_dev *dev, s
 
 static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 {
-	int luma_control,sync_control,mux,nosignal;
+	int luma_control,sync_control,mux;
 
 	dprintk("set tv norm = %s\n",norm->name);
 	dev->tvnorm = norm;
-        nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03));
 
 	mux = card_in(dev,dev->ctl_input).vmux;
 	luma_control = norm->luma_control;
@@ -455,7 +473,7 @@ static void set_tvnorm(struct saa7134_de
 
 	if (mux > 5)
 		luma_control |= 0x80; /* svideo */
-	if (noninterlaced || nosignal)
+	if (noninterlaced || dev->nosignal)
 		sync_control |= 0x20;
 
 	/* setup cropping */
@@ -1359,6 +1377,9 @@ static int video_release(struct inode *i
 		res_free(dev,fh,RESOURCE_VBI);
 	}
 
+	/* free stuff */
+	videobuf_mmap_free(&fh->cap);
+	videobuf_mmap_free(&fh->vbi);
 	saa7134_pgtable_free(dev->pci,&fh->pt_cap);
 	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
 
@@ -1472,6 +1493,7 @@ static int saa7134_try_fmt(struct saa713
 			f->fmt.pix.width = maxw;
 		if (f->fmt.pix.height > maxh)
 			f->fmt.pix.height = maxh;
+		f->fmt.pix.width &= ~0x03;
 		f->fmt.pix.bytesperline =
 			(f->fmt.pix.width * fmt->depth) >> 3;
 		f->fmt.pix.sizeimage =
@@ -2267,7 +2289,7 @@ int saa7134_video_init1(struct saa7134_d
 	dev->ctl_hue        = ctrl_by_id(V4L2_CID_HUE)->default_value;
 	dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value;
 	dev->ctl_volume     = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value;
-	dev->ctl_mute       = ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
+	dev->ctl_mute       = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
 	dev->ctl_invert     = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value;
 	dev->ctl_automute   = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value;
 
@@ -2317,24 +2339,31 @@ int saa7134_video_fini(struct saa7134_de
 void saa7134_irq_video_intl(struct saa7134_dev *dev)
 {
 	static const char *st[] = {
-		"no signal", "found NTSC", "found PAL", "found SECAM" };
-	int norm;
+		"(no signal)", "NTSC", "PAL", "SECAM" };
+	u32 st1,st2;
 
-	norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03;
-	dprintk("DCSDT: %s\n",st[norm]);
+	st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+	st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+	dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n",
+		(st1 & 0x40) ? "not locked" : "locked",
+		(st2 & 0x40) ? "no"         : "yes",
+		st[st1 & 0x03]);
+	dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
 
-	if (0 != norm) {
-		/* wake up tvaudio audio carrier scan thread */
-		saa7134_tvaudio_do_scan(dev);
-		if (!noninterlaced)
-			saa_clearb(SAA7134_SYNC_CTRL, 0x20);
-	} else {
+	if (dev->nosignal) {
 		/* no video signal -> mute audio */
 		if (dev->ctl_automute)
 			dev->automute = 1;
 		saa7134_tvaudio_setmute(dev);
 		saa_setb(SAA7134_SYNC_CTRL, 0x20);
+	} else {
+		/* wake up tvaudio audio carrier scan thread */
+		saa7134_tvaudio_do_scan(dev);
+		if (!noninterlaced)
+			saa_clearb(SAA7134_SYNC_CTRL, 0x20);
 	}
+	if (dev->mops && dev->mops->signal_change)
+		dev->mops->signal_change(dev);
 }
 
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -1,5 +1,5 @@
 /*
- * $Id: saa7134.h,v 1.27 2004/11/04 11:03:52 kraxel Exp $
+ * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $
  *
  * v4l2 device driver for philips saa7134 based TV cards
  *
@@ -64,6 +64,7 @@ enum saa7134_audio_in {
 	TV    = 1,
 	LINE1 = 2,
 	LINE2 = 3,
+	LINE2_LEFT,
 };
 
 enum saa7134_video_out {
@@ -156,11 +157,11 @@ struct saa7134_format {
 #define SAA7134_BOARD_AVACSSMARTTV     32
 #define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
 #define SAA7134_BOARD_NOVAC_PRIMETV7133 34
-#define SAA7134_BOARD_AVERMEDIA_305    35
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
 #define SAA7133_BOARD_UPMOST_PURPLE_TV 36
 #define SAA7134_BOARD_ITEMS_MTV005     37
 #define SAA7134_BOARD_CINERGY200       38
-#define SAA7134_BOARD_FLYTVPLATINUM    39
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
 #define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
 #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
 #define SAA7134_BOARD_SABRENT_SBTTVFM  42
@@ -169,6 +170,14 @@ struct saa7134_format {
 #define SAA7134_BOARD_AVERMEDIA_307    45
 #define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
 #define SAA7134_BOARD_CINERGY400_CARDBUS 47
+#define SAA7134_BOARD_CINERGY600_MK3   48
+#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
+#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
+#define SAA7134_BOARD_PROVIDEO_PV952   51
+#define SAA7134_BOARD_AVERMEDIA_305    52
+#define SAA7135_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
+#define SAA7134_BOARD_FLYDVBTDUO 55
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -355,6 +364,7 @@ struct saa7134_mpeg_ops {
 	struct list_head           next;
 	int                        (*init)(struct saa7134_dev *dev);
 	int                        (*fini)(struct saa7134_dev *dev);
+	void                       (*signal_change)(struct saa7134_dev *dev);
 };
 
 /* global device status */
@@ -390,6 +400,7 @@ struct saa7134_dev {
 	unsigned int               tuner_type;
 	unsigned int               tda9887_conf;
 	unsigned int               gpio_value;
+	unsigned int               irq2_mask;
 
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
@@ -437,6 +448,7 @@ struct saa7134_dev {
 	struct saa7134_input       *hw_input;
 	unsigned int               hw_mute;
 	int                        last_carrier;
+	int                        nosignal;
 
 	/* SAA7134_MPEG_* */
 	struct saa7134_ts          ts;
@@ -447,6 +459,8 @@ struct saa7134_dev {
 	struct video_device        *empress_dev;
 	struct videobuf_queue      empress_tsq;
 	unsigned int               empress_users;
+	struct work_struct         empress_workqueue;
+	int                        empress_started;
 
 	/* SAA7134_MPEG_DVB only */
 	struct videobuf_dvb        dvb;
@@ -476,7 +490,6 @@ struct saa7134_dev {
 /* saa7134-core.c                                              */
 
 extern struct list_head  saa7134_devlist;
-extern unsigned int      saa7134_devcount;
 
 void saa7134_print_ioctl(char *name, unsigned int cmd);
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -118,7 +118,7 @@ saa7185_write_block (struct i2c_client *
 		u8 block_data[32];
 
 		msg.addr = client->addr;
-		msg.flags = client->flags;
+		msg.flags = 0;
 		while (len >= 2) {
 			msg.buf = (char *) block_data;
 			msg.len = 0;
@@ -398,7 +398,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int saa7185_i2c_id = 0;
 static struct i2c_driver i2c_driver_saa7185;
 
 static int
@@ -427,9 +426,7 @@ saa7185_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &i2c_driver_saa7185;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = saa7185_i2c_id++;
-	snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-		"saa7185[%d]", client->id);
+	strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client)));
 
 	encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL);
 	if (encoder == NULL) {
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -2181,12 +2181,9 @@ static void release_saa(void)
 		/* unmap and free memory */
 		saa->audhead = saa->audtail = saa->osdhead = 0;
 		saa->vidhead = saa->vidtail = saa->osdtail = 0;
-		if (saa->vidbuf)
-			vfree(saa->vidbuf);
-		if (saa->audbuf)
-			vfree(saa->audbuf);
-		if (saa->osdbuf)
-			vfree(saa->osdbuf);
+		vfree(saa->vidbuf);
+		vfree(saa->audbuf);
+		vfree(saa->osdbuf);
 		if (saa->dmavid2)
 			kfree((void *) saa->dmavid2);
 		saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -528,7 +528,6 @@ static struct i2c_driver driver = {
 static struct i2c_client client_template =
 {
 	I2C_DEVNAME("tda7432"),
-        .id         = -1,
 	.driver     = &driver,
 };
 
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/video/tda8290.c
@@ -0,0 +1,224 @@
+/*
+ * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $
+ *
+ * i2c tv tuner chip device driver
+ * controls the philips tda8290+75 tuner chip combo.
+ */
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+
+/* ---------------------------------------------------------------------- */
+
+struct freq_entry {
+	u16	freq;
+	u8	value;
+};
+
+static struct freq_entry band_table[] = {
+	{ 0x2DF4, 0x1C },
+	{ 0x2574, 0x14 },
+	{ 0x22B4, 0x0C },
+	{ 0x20D4, 0x0B },
+	{ 0x1E74, 0x3B },
+	{ 0x1C34, 0x33 },
+	{ 0x16F4, 0x5B },
+	{ 0x1454, 0x53 },
+	{ 0x12D4, 0x52 },
+	{ 0x1034, 0x4A },
+	{ 0x0EE4, 0x7A },
+	{ 0x0D34, 0x72 },
+	{ 0x0B54, 0x9A },
+	{ 0x0914, 0x91 },
+	{ 0x07F4, 0x89 },
+	{ 0x0774, 0xB9 },
+	{ 0x067B, 0xB1 },
+	{ 0x0634, 0xD9 },
+	{ 0x05A4, 0xD8 },	// FM radio
+	{ 0x0494, 0xD0 },
+	{ 0x03BC, 0xC8 },
+	{ 0x0394, 0xF8 },	// 57250000 Hz
+	{ 0x0000, 0xF0 },	// 0
+};
+
+static struct freq_entry div_table[] = {
+	{ 0x1C34, 3 },
+	{ 0x0D34, 2 },
+	{ 0x067B, 1 },
+        { 0x0000, 0 },
+};
+
+static struct freq_entry agc_table[] = {
+	{ 0x22B4, 0x8F },
+	{ 0x0B54, 0x9F },
+	{ 0x09A4, 0x8F },
+	{ 0x0554, 0x9F },
+	{ 0x0000, 0xBF },
+};
+
+static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
+{
+	while(table->freq && table->freq > freq)
+		table++;
+	return table->value;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned char i2c_enable_bridge[2] = 	{ 0x21, 0xC0 };
+static unsigned char i2c_disable_bridge[2] = 	{ 0x21, 0x80 };
+static unsigned char i2c_init_tda8275[14] = 	{ 0x00, 0x00, 0x00, 0x00,
+						  0x7C, 0x04, 0xA3, 0x3F,
+						  0x2A, 0x04, 0xFF, 0x00,
+						  0x00, 0x40 };
+static unsigned char i2c_set_VS[2] = 		{ 0x30, 0x6F };
+static unsigned char i2c_set_GP01_CF[2] = 	{ 0x20, 0x0B };
+static unsigned char i2c_tda8290_reset[2] =	{ 0x00, 0x00 };
+static unsigned char i2c_gainset_off[2] =	{ 0x28, 0x14 };
+static unsigned char i2c_gainset_on[2] =	{ 0x28, 0x54 };
+static unsigned char i2c_agc3_00[2] =		{ 0x80, 0x00 };
+static unsigned char i2c_agc2_BF[2] =		{ 0x60, 0xBF };
+static unsigned char i2c_cb1_D2[2] =		{ 0x30, 0xD2 };
+static unsigned char i2c_cb1_56[2] =		{ 0x30, 0x56 };
+static unsigned char i2c_cb1_52[2] =		{ 0x30, 0x52 };
+static unsigned char i2c_cb1_50[2] =		{ 0x30, 0x50 };
+static unsigned char i2c_agc2_7F[2] =		{ 0x60, 0x7F };
+static unsigned char i2c_agc3_08[2] =		{ 0x80, 0x08 };
+
+static struct i2c_msg i2c_msg_init[] = {
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF },
+};
+
+static struct i2c_msg i2c_msg_prolog[] = {
+//	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
+};
+
+static struct i2c_msg i2c_msg_config[] = {
+//	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 },
+};
+
+static struct i2c_msg i2c_msg_epilog[] = {
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F },
+	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
+	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on },
+};
+
+static int tda8290_tune(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	struct i2c_msg easy_mode =
+		{ I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode };
+	struct i2c_msg set_freq =
+		{ I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq  };
+
+	i2c_transfer(c->adapter, &easy_mode,      1);
+	i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog));
+
+	i2c_transfer(c->adapter, &set_freq,       1);
+	i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config));
+
+	msleep(550);
+	i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog));
+	return 0;
+}
+
+static void set_frequency(struct tuner *t, u16 ifc)
+{
+	u32 N = (((t->freq<<3)+ifc)&0x3fffc);
+
+	N = N >> get_freq_entry(div_table, t->freq);
+	t->i2c_set_freq[0] = 0;
+	t->i2c_set_freq[1] = (unsigned char)(N>>8);
+	t->i2c_set_freq[2] = (unsigned char) N;
+	t->i2c_set_freq[3] = 0x40;
+	t->i2c_set_freq[4] = 0x52;
+	t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq);
+	t->i2c_set_freq[6] = get_freq_entry(agc_table,  t->freq);
+	t->i2c_set_freq[7] = 0x8f;
+}
+
+#define V4L2_STD_MN	(V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
+#define V4L2_STD_B	(V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
+#define V4L2_STD_GH	(V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
+#define V4L2_STD_DK	(V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+
+static void set_audio(struct tuner *t)
+{
+	t->i2c_easy_mode[0] = 0x01;
+
+	if (t->std & V4L2_STD_MN)
+		t->i2c_easy_mode[1] = 0x01;
+	else if (t->std & V4L2_STD_B)
+		t->i2c_easy_mode[1] = 0x02;
+	else if (t->std & V4L2_STD_GH)
+		t->i2c_easy_mode[1] = 0x04;
+	else if (t->std & V4L2_STD_PAL_I)
+		t->i2c_easy_mode[1] = 0x08;
+	else if (t->std & V4L2_STD_DK)
+		t->i2c_easy_mode[1] = 0x10;
+	else if (t->std & V4L2_STD_SECAM_L)
+		t->i2c_easy_mode[1] = 0x20;
+}
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	set_audio(t);
+	set_frequency(t, 864);
+	tda8290_tune(c);
+}
+
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	set_frequency(t, 704);
+	tda8290_tune(c);
+}
+
+static int has_signal(struct i2c_client *c)
+{
+	unsigned char i2c_get_afc[1] = { 0x1B };
+	unsigned char afc = 0;
+
+	i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+	i2c_master_recv(c, &afc, 1);
+	return (afc & 0x80)? 65535:0;
+}
+
+int tda8290_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	strlcpy(c->name, "tda8290+75", sizeof(c->name));
+	tuner_info("tuner: type set to %s\n", c->name);
+	t->tv_freq    = set_tv_freq;
+	t->radio_freq = set_radio_freq;
+	t->has_signal = has_signal;
+
+	i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge));
+	i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init));
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -51,9 +51,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
-/* unique ID allocation */
-static int tda9840_id = 0;
-
 static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	int result;
@@ -120,7 +117,8 @@ static int command(struct i2c_client *cl
 			dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
 		break;
 
-	case TDA9840_DETECT:
+	case TDA9840_DETECT: {
+		int *ret = (int *)arg;
 
 		byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST);
 		if (byte == -1) {
@@ -134,8 +132,10 @@ static int command(struct i2c_client *cl
 		}
 
 		dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte);
-		return ((byte & 0x60) >> 5);
-
+		*ret = ((byte & 0x60) >> 5);
+		result = 0;
+		break;
+	}
 	case TDA9840_TEST:
 		dprintk("TDA9840_TEST: 0x%02x\n", byte);
 
@@ -179,7 +179,6 @@ static int detect(struct i2c_adapter *ad
 
 	/* fill client structure */
 	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->id = tda9840_id++;
 	client->addr = address;
 	client->adapter = adapter;
 
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -399,7 +399,6 @@ static struct i2c_driver driver = {
 static struct i2c_client client_template =
 {
         I2C_DEVNAME("tda9875"),
-        .id        = -1,
         .driver    = &driver,
 };
 
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -478,9 +478,9 @@ static int tda9887_set_pinnacle(struct t
 /* ---------------------------------------------------------------------- */
 
 static char pal[] = "-";
-module_param_string(pal, pal, 0644, sizeof(pal));
+module_param_string(pal, pal, sizeof(pal), 0644);
 static char secam[] = "-";
-module_param_string(secam, secam, 0644, sizeof(secam));
+module_param_string(secam, secam, sizeof(secam), 0644);
 
 static int tda9887_fixup_std(struct tda9887 *t)
 {
@@ -557,7 +557,7 @@ static int tda9887_configure(struct tda9
 #if 0
 	/* This as-is breaks some cards, must be fixed in a
 	 * card-specific way, probably using TDA9887_SET_CONFIG to
-	  * turn on/off port2 */
+	 * turn on/off port2 */
 	if (t->std & V4L2_STD_SECAM_L) {
 		/* secam fixup (FIXME: move this to tvnorms array?) */
 		buf[1] &= ~cOutputPort2Inactive;
@@ -741,7 +741,7 @@ tda9887_command(struct i2c_client *clien
 	return 0;
 }
 
-static int tda9887_suspend(struct device * dev, u32 state, u32 level)
+static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level)
 {
 	dprintk("tda9887: suspend\n");
 	return 0;
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -51,9 +51,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
-/* unique ID allocation */
-static int tea6415c_id = 0;
-
 /* this function is called by i2c_probe */
 static int detect(struct i2c_adapter *adapter, int address, int kind)
 {
@@ -73,7 +70,6 @@ static int detect(struct i2c_adapter *ad
 
 	/* fill client structure */
 	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->id = tea6415c_id++;
 	client->addr = address;
 	client->adapter = adapter;
 
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -48,9 +48,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
-/* unique ID allocation */
-static int tea6420_id = 0;
-
 /* make a connection between the input 'i' and the output 'o'
    with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
 static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
@@ -111,7 +108,6 @@ static int tea6420_detect(struct i2c_ada
 
 	/* fill client structure */
 	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->id = tea6420_id++;
 	client->addr = address;
 	client->adapter = adapter;
 
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -192,7 +192,6 @@ i2c_driver_tuner = 
 
 static struct i2c_client client_template =
 {
-        .id 		= -1,
         .driver		= &i2c_driver_tuner,
 	.name		= "SAB3036",
 };
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/video/tuner-core.c
@@ -0,0 +1,453 @@
+/*
+ * $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $
+ *
+ * i2c tv tuner chip device driver
+ * core core, i.e. kernel interfaces, registering and so on
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+
+#include <media/tuner.h>
+#include <media/audiochip.h>
+
+#define UNSET (-1U)
+
+/* standard i2c insmod options */
+static unsigned short normal_i2c[] = {
+	0x4b, /* tda8290 */
+	I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = {
+	0x60, 0x6f,
+	I2C_CLIENT_END
+};
+I2C_CLIENT_INSMOD;
+
+/* insmod options used at init time => read/only */
+static unsigned int addr  =  0;
+module_param(addr, int, 0444);
+
+/* insmod options used at runtime => read/write */
+unsigned int tuner_debug   = 0;
+module_param(tuner_debug,       int, 0644);
+
+static unsigned int tv_range[2]    = { 44, 958 };
+static unsigned int radio_range[2] = { 65, 108 };
+
+module_param_array(tv_range,    int, NULL, 0644);
+module_param_array(radio_range, int, NULL, 0644);
+
+MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
+static int this_adap;
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->type == UNSET) {
+		tuner_info("tuner type not set\n");
+		return;
+	}
+	if (NULL == t->tv_freq) {
+		tuner_info("Huh? tv_set is NULL?\n");
+		return;
+	}
+	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
+		/* FIXME: better do that chip-specific, but
+		   right now we don't have that in the config
+		   struct and this way is still better than no
+		   check at all */
+		tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n",
+			   freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
+		return;
+	}
+	t->tv_freq(c,freq);
+}
+
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->type == UNSET) {
+		tuner_info("tuner type not set\n");
+		return;
+	}
+	if (NULL == t->radio_freq) {
+		tuner_info("no radio tuning for this one, sorry.\n");
+		return;
+	}
+	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
+		tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n",
+			   freq/16,freq%16*100/16,
+			   radio_range[0],radio_range[1]);
+		return;
+	}
+	t->radio_freq(c,freq);
+}
+
+static void set_freq(struct i2c_client *c, unsigned long freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	switch (t->mode) {
+	case V4L2_TUNER_RADIO:
+		tuner_dbg("radio freq set to %lu.%02lu\n",
+			  freq/16,freq%16*100/16);
+		set_radio_freq(c,freq);
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		tuner_dbg("tv freq set to %lu.%02lu\n",
+			  freq/16,freq%16*100/16);
+		set_tv_freq(c, freq);
+		break;
+	}
+	t->freq = freq;
+}
+
+static void set_type(struct i2c_client *c, unsigned int type)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	/* sanity check */
+	if (type == UNSET  ||  type == TUNER_ABSENT)
+		return;
+	if (type >= tuner_count)
+		return;
+
+	if (NULL == t->i2c.dev.driver) {
+		/* not registered yet */
+		t->type = type;
+		return;
+	}
+	if (t->initialized)
+		/* run only once */
+		return;
+
+	t->initialized = 1;
+	t->type = type;
+	switch (t->type) {
+	case TUNER_MT2032:
+		microtune_init(c);
+		break;
+	case TUNER_PHILIPS_TDA8290:
+		tda8290_init(c);
+		break;
+	default:
+		default_tuner_init(c);
+		break;
+	}
+}
+
+static char pal[] = "-";
+module_param_string(pal, pal, sizeof(pal), 0644);
+
+static int tuner_fixup_std(struct tuner *t)
+{
+	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
+		/* get more precise norm info from insmod option */
+		switch (pal[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+			tuner_dbg("insmod fixup: PAL => PAL-BG\n");
+			t->std = V4L2_STD_PAL_BG;
+			break;
+		case 'i':
+		case 'I':
+			tuner_dbg("insmod fixup: PAL => PAL-I\n");
+			t->std = V4L2_STD_PAL_I;
+			break;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			tuner_dbg("insmod fixup: PAL => PAL-DK\n");
+			t->std = V4L2_STD_PAL_DK;
+			break;
+		}
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct tuner *t;
+
+	if (this_adap > 0)
+		return -1;
+	this_adap++;
+
+        client_template.adapter = adap;
+        client_template.addr = addr;
+
+        t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+        if (NULL == t)
+                return -ENOMEM;
+        memset(t,0,sizeof(struct tuner));
+        memcpy(&t->i2c,&client_template,sizeof(struct i2c_client));
+	i2c_set_clientdata(&t->i2c, t);
+	t->type       = UNSET;
+	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
+
+        i2c_attach_client(&t->i2c);
+	tuner_info("chip found @ 0x%x (%s)\n",
+		   addr << 1, adap->name);
+	set_type(&t->i2c, t->type);
+	return 0;
+}
+
+static int tuner_probe(struct i2c_adapter *adap)
+{
+	if (0 != addr) {
+		normal_i2c[0]       = addr;
+		normal_i2c_range[0] = addr;
+		normal_i2c_range[1] = addr;
+	}
+	this_adap = 0;
+
+	if (adap->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tuner_attach);
+	return 0;
+}
+
+static int tuner_detach(struct i2c_client *client)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+
+	i2c_detach_client(&t->i2c);
+	kfree(t);
+	return 0;
+}
+
+#define SWITCH_V4L2	if (!t->using_v4l2 && tuner_debug) \
+		          tuner_info("switching to v4l2\n"); \
+	                  t->using_v4l2 = 1;
+#define CHECK_V4L2	if (t->using_v4l2) { if (tuner_debug) \
+			  tuner_info("ignore v4l1 call\n"); \
+		          return 0; }
+
+static int
+tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+        unsigned int *iarg = (int*)arg;
+
+        switch (cmd) {
+
+	/* --- configuration --- */
+	case TUNER_SET_TYPE:
+		set_type(client,*iarg);
+		break;
+	case AUDC_SET_RADIO:
+		if (V4L2_TUNER_RADIO != t->mode) {
+			set_tv_freq(client,400 * 16);
+			t->mode = V4L2_TUNER_RADIO;
+		}
+		break;
+	case AUDC_CONFIG_PINNACLE:
+		switch (*iarg) {
+		case 2:
+			tuner_dbg("pinnacle pal\n");
+			t->radio_if2 = 33300 * 1000;
+			break;
+		case 3:
+			tuner_dbg("pinnacle ntsc\n");
+			t->radio_if2 = 41300 * 1000;
+			break;
+		}
+                break;
+
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCSCHAN:
+	{
+		static const v4l2_std_id map[] = {
+			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,
+			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,
+			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
+			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,
+			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,
+			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,
+		};
+		struct video_channel *vc = arg;
+
+		CHECK_V4L2;
+		t->mode = V4L2_TUNER_ANALOG_TV;
+		if (vc->norm < ARRAY_SIZE(map))
+			t->std = map[vc->norm];
+		tuner_fixup_std(t);
+		if (t->freq)
+			set_tv_freq(client,t->freq);
+		return 0;
+	}
+	case VIDIOCSFREQ:
+	{
+		unsigned long *v = arg;
+
+		CHECK_V4L2;
+		set_freq(client,*v);
+		return 0;
+	}
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner *vt = arg;
+
+		CHECK_V4L2;
+		if (V4L2_TUNER_RADIO == t->mode  &&  t->has_signal)
+			vt->signal = t->has_signal(client);
+		return 0;
+	}
+	case VIDIOCGAUDIO:
+	{
+		struct video_audio *va = arg;
+
+		CHECK_V4L2;
+		if (V4L2_TUNER_RADIO == t->mode  &&  t->is_stereo)
+			va->mode = t->is_stereo(client)
+				? VIDEO_SOUND_STEREO
+				: VIDEO_SOUND_MONO;
+		return 0;
+	}
+
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		SWITCH_V4L2;
+		t->mode = V4L2_TUNER_ANALOG_TV;
+		t->std = *id;
+		tuner_fixup_std(t);
+		if (t->freq)
+			set_freq(client,t->freq);
+		break;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		SWITCH_V4L2;
+		if (V4L2_TUNER_RADIO == f->type &&
+		    V4L2_TUNER_RADIO != t->mode)
+			set_tv_freq(client,400*16);
+		t->mode  = f->type;
+		set_freq(client,f->frequency);
+		break;
+	}
+	case VIDIOC_G_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		SWITCH_V4L2;
+		f->type = t->mode;
+		f->frequency = t->freq;
+		break;
+	}
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *tuner = arg;
+
+		SWITCH_V4L2;
+		if (V4L2_TUNER_RADIO == t->mode  &&  t->has_signal)
+			tuner->signal = t->has_signal(client);
+		tuner->rangelow = tv_range[0] * 16;
+		tuner->rangehigh = tv_range[1] * 16;
+		break;
+	}
+	default:
+		/* nothing */
+		break;
+	}
+
+	return 0;
+}
+
+static int tuner_suspend(struct device * dev, pm_message_t state, u32 level)
+{
+	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct tuner *t = i2c_get_clientdata(c);
+
+	tuner_dbg("suspend\n");
+	/* FIXME: power down ??? */
+	return 0;
+}
+
+static int tuner_resume(struct device * dev, u32 level)
+{
+	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct tuner *t = i2c_get_clientdata(c);
+
+	tuner_dbg("resume\n");
+	if (t->freq)
+		set_freq(c,t->freq);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+	.owner          = THIS_MODULE,
+        .name           = "tuner",
+        .id             = I2C_DRIVERID_TUNER,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tuner_probe,
+        .detach_client  = tuner_detach,
+        .command        = tuner_command,
+	.driver = {
+		.suspend = tuner_suspend,
+		.resume  = tuner_resume,
+	},
+};
+static struct i2c_client client_template =
+{
+	I2C_DEVNAME("(tuner unset)"),
+	.flags      = I2C_CLIENT_ALLOW_USE,
+        .driver     = &driver,
+};
+
+static int __init tuner_init_module(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit tuner_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(tuner_init_module);
+module_exit(tuner_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
new file mode 100644
--- /dev/null
+++ b/drivers/media/video/tuner-simple.c
@@ -0,0 +1,474 @@
+/*
+ * $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $
+ *
+ * i2c tv tuner chip device driver
+ * controls all those simple 4-control-bytes style tuners.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/tuner.h>
+
+/* ---------------------------------------------------------------------- */
+
+/* tv standard selection for Temic 4046 FM5
+   this value takes the low bits of control byte 2
+   from datasheet Rev.01, Feb.00
+     standard     BG      I       L       L2      D
+     picture IF   38.9    38.9    38.9    33.95   38.9
+     sound 1      33.4    32.9    32.4    40.45   32.4
+     sound 2      33.16
+     NICAM        33.05   32.348  33.05           33.05
+ */
+#define TEMIC_SET_PAL_I         0x05
+#define TEMIC_SET_PAL_DK        0x09
+#define TEMIC_SET_PAL_L         0x0a // SECAM ?
+#define TEMIC_SET_PAL_L2        0x0b // change IF !
+#define TEMIC_SET_PAL_BG        0x0c
+
+/* tv tuner system standard selection for Philips FQ1216ME
+   this value takes the low bits of control byte 2
+   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
+     standard 		BG	DK	I	L	L`
+     picture carrier	38.90	38.90	38.90	38.90	33.95
+     colour		34.47	34.47	34.47	34.47	38.38
+     sound 1		33.40	32.40	32.90	32.40	40.45
+     sound 2		33.16	-	-	-	-
+     NICAM		33.05	33.05	32.35	33.05	39.80
+ */
+#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
+#define PHILIPS_SET_PAL_BGDK	0x09
+#define PHILIPS_SET_PAL_L2	0x0a
+#define PHILIPS_SET_PAL_L	0x0b
+
+/* 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 // France
+#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
+
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype
+{
+	char *name;
+	unsigned char Vendor;
+	unsigned char Type;
+
+	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
+	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
+	unsigned char VHF_L;
+	unsigned char VHF_H;
+	unsigned char UHF;
+	unsigned char config;
+	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL,
+				   732  =16*45.75 NTSCi,
+				   940  =16*58.75 NTSC-Japan
+				   704  =16*44    ATSC */
+};
+
+/*
+ *	The floats in the tuner struct are computed at compile time
+ *	by gcc and cast back to integers. Thus we don't violate the
+ *	"no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+        { "Temic PAL (4002 FH5)", TEMIC, PAL,
+	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
+	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
+	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
+	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
+	{ "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_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},
+	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
+	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
+
+ 	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
+        { "Alps HSBH1", TEMIC, NTSC,
+	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+        { "Alps TSBE1",TEMIC,PAL,
+	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+        { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
+
+        { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
+        { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
+	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+  	{ "Alps TSCH6",Alps,NTSC,
+  	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+
+  	{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL,
+  	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+  	{ "Philips NTSC_M (MK2)",Philips,NTSC,
+  	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+
+        { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+          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 (FI1256 and compatibles)", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+
+	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
+	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
+
+	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "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 },
+
+	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
+          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+	{ "MT20xx universal", Microtune,PAL|NTSC,
+	  /* see mt20xx.c for details */ },
+	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
+          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+
+	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
+          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},
+
+	{ "HITACHI V7-J180AT", HITACHI, NTSC,
+	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
+	{ "Philips PAL_MK (FI1216 MK)", Philips, PAL,
+	  16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
+	{ "Philips 1236D ATSC/NTSC daul in",Philips,ATSC,
+	  16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
+        { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+
+        { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+	{ "Microtune 4049 FM5",Microtune,PAL,
+	  16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
+	{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
+	  16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
+        { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+
+        { "Tenna TNF 8831 BGFF)", Philips, PAL,
+          16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+	{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
+	  16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
+        { "TCL 2002N", TCL, NTSC,
+          16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
+	{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+
+	{ "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
+	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
+	{ "Philips FQ1286", Philips, NTSC,
+	  16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested
+	{ "tda8290+75", Philips,PAL|NTSC,
+	  /* see tda8290.c for details */ },
+	{ "LG PAL (TAPE series)", LGINNOTEK, PAL,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
+
+        { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
+          16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
+        { "Philips FQ1236A MK4", Philips, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+
+};
+unsigned const int tuner_count = ARRAY_SIZE(tuners);
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus(struct i2c_client *c)
+{
+	unsigned char byte;
+
+	if (1 != i2c_master_recv(c,&byte,1))
+		return 0;
+	return byte;
+}
+
+#define TUNER_POR       0x80
+#define TUNER_FL        0x40
+#define TUNER_MODE      0x38
+#define TUNER_AFC       0x07
+
+#define TUNER_STEREO    0x10 /* radio mode */
+#define TUNER_SIGNAL    0x07 /* radio mode */
+
+static int tuner_signal(struct i2c_client *c)
+{
+	return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+}
+
+static int tuner_stereo(struct i2c_client *c)
+{
+	return (tuner_getstatus (c) & TUNER_STEREO);
+}
+
+#if 0 /* unused */
+static int tuner_islocked (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_AFC) - 2;
+}
+
+static int tuner_mode (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_MODE) >> 3;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	u8 config;
+	u16 div;
+	struct tunertype *tun;
+        unsigned char buffer[4];
+	int rc;
+
+	tun = &tuners[t->type];
+	if (freq < tun->thresh1) {
+		config = tun->VHF_L;
+		tuner_dbg("tv: VHF lowrange\n");
+	} else if (freq < tun->thresh2) {
+		config = tun->VHF_H;
+		tuner_dbg("tv: VHF high range\n");
+	} else {
+		config = tun->UHF;
+		tuner_dbg("tv: UHF range\n");
+	}
+
+
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (t->type) {
+	case TUNER_PHILIPS_SECAM: // FI1216MF
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		config &= ~0x02;
+		if (t->std & V4L2_STD_SECAM)
+			config |= 0x02;
+		break;
+
+	case TUNER_TEMIC_4046FM5:
+		config &= ~0x0f;
+
+		if (t->std & V4L2_STD_PAL_BG) {
+			config |= TEMIC_SET_PAL_BG;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			config |= TEMIC_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_PAL_DK) {
+			config |= TEMIC_SET_PAL_DK;
+
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			config |= TEMIC_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FQ1216ME:
+		config &= ~0x0f;
+
+		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+			config |= PHILIPS_SET_PAL_BGDK;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			config |= PHILIPS_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			config |= PHILIPS_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_ATSC:
+		/* 0x00 -> ATSC antenna input 1 */
+		/* 0x01 -> ATSC antenna input 2 */
+		/* 0x02 -> NTSC antenna input 1 */
+		/* 0x03 -> NTSC antenna input 2 */
+		config &= ~0x03;
+		if (!(t->std & V4L2_STD_ATSC))
+			config |= 2;
+		/* FIXME: input */
+		break;
+
+	case TUNER_MICROTUNE_4042FI5:
+		/* Set the charge pump for fast tuning */
+		tun->config |= 0x40;
+		break;
+	}
+
+	/*
+	 * Philips FI1216MK2 remark from specification :
+	 * for channel selection involving band switching, and to ensure
+	 * smooth tuning to the desired channel without causing
+	 * unnecessary charge pump action, it is recommended to consider
+	 * the difference between wanted channel frequency and the
+	 * current channel frequency.  Unnecessary charge pump action
+	 * will result in very low tuning voltage which may drive the
+	 * oscillator to extreme conditions.
+	 *
+	 * Progfou: specification says to send config data before
+	 * frequency in case (wanted frequency < current frequency).
+	 */
+
+	div=freq + tun->IFPCoff;
+	if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
+		buffer[0] = tun->config;
+		buffer[1] = config;
+		buffer[2] = (div>>8) & 0x7f;
+		buffer[3] = div      & 0xff;
+	} else {
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = tun->config;
+		buffer[3] = config;
+	}
+	tuner_dbg("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)))
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+
+	if (t->type == TUNER_MICROTUNE_4042FI5) {
+		// FIXME - this may also work for other tuners
+		unsigned long timeout = jiffies + msecs_to_jiffies(1);
+		u8 status_byte = 0;
+
+		/* Wait until the PLL locks */
+		for (;;) {
+			if (time_after(jiffies,timeout))
+				return;
+			if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
+				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
+				break;
+			}
+			/* bit 6 is PLL locked indicator */
+			if (status_byte & 0x40)
+				break;
+			udelay(10);
+		}
+
+		/* Set the charge pump for optimized phase noise figure */
+		tun->config &= ~0x40;
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = tun->config;
+		buffer[3] = config;
+		tuner_dbg("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)))
+			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+	}
+}
+
+static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tunertype *tun;
+	struct tuner *t = i2c_get_clientdata(c);
+        unsigned char buffer[4];
+	unsigned div;
+	int rc;
+
+	tun=&tuners[t->type];
+	div = freq + (int)(16*10.7);
+	buffer[2] = tun->config;
+
+	switch (t->type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+		buffer[3] = 0x19;
+		break;
+	case TUNER_PHILIPS_FM1256_IH3:
+		div = (20 * freq)/16 + 333 * 2;
+	        buffer[2] = 0x80;
+		buffer[3] = 0x19;
+		break;
+	case TUNER_LG_PAL_FM:
+		buffer[3] = 0xa5;
+		break;
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
+        buffer[0] = (div>>8) & 0x7f;
+        buffer[1] = div      & 0xff;
+
+	tuner_dbg("radio 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)))
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+}
+
+int default_tuner_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	tuner_info("type set to %d (%s)\n",
+		   t->type, tuners[t->type].name);
+	strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
+
+	t->tv_freq    = default_set_tv_freq;
+	t->radio_freq = default_set_radio_freq;
+	t->has_signal = tuner_signal;
+	t->is_stereo  = tuner_stereo;
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c
deleted file mode 100644
--- a/drivers/media/video/tuner.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- * $Id: tuner.c,v 1.36 2005/01/14 13:29:40 kraxel Exp $
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-
-#include <media/tuner.h>
-#include <media/audiochip.h>
-
-#define UNSET (-1U)
-
-/* standard i2c insmod options */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END};
-I2C_CLIENT_INSMOD;
-
-/* insmod options used at init time => read/only */
-static unsigned int type  =  UNSET;
-static unsigned int addr  =  0;
-module_param(type, int, 0444);
-module_param(addr, int, 0444);
-
-/* insmod options used at runtime => read/write */
-static unsigned int debug         = 0;
-static unsigned int tv_antenna    = 1;
-static unsigned int radio_antenna = 0;
-static unsigned int optimize_vco  = 1;
-module_param(debug,             int, 0644);
-module_param(tv_antenna,        int, 0644);
-module_param(radio_antenna,     int, 0644);
-module_param(optimize_vco,      int, 0644);
-
-static unsigned int tv_range[2]    = { 44, 958 };
-static unsigned int radio_range[2] = { 65, 108 };
-
-module_param_array(tv_range,    int, NULL, 0644);
-module_param_array(radio_range, int, NULL, 0644);
-
-MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-static int this_adap;
-#define dprintk     if (debug) printk
-
-struct tuner {
-	unsigned int type;            /* chip type */
-	unsigned int freq;            /* keep track of the current settings */
-	v4l2_std_id  std;
-	int          using_v4l2;
-
-	enum v4l2_tuner_type mode;
-	unsigned int input;
-
-	// only for MT2032
-	unsigned int xogc;
-	unsigned int radio_if2;
-
-	void (*tv_freq)(struct i2c_client *c, unsigned int freq);
-	void (*radio_freq)(struct i2c_client *c, unsigned int freq);
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-/* ---------------------------------------------------------------------- */
-
-/* tv standard selection for Temic 4046 FM5
-   this value takes the low bits of control byte 2
-   from datasheet Rev.01, Feb.00
-     standard     BG      I       L       L2      D
-     picture IF   38.9    38.9    38.9    33.95   38.9
-     sound 1      33.4    32.9    32.4    40.45   32.4
-     sound 2      33.16
-     NICAM        33.05   32.348  33.05           33.05
- */
-#define TEMIC_SET_PAL_I         0x05
-#define TEMIC_SET_PAL_DK        0x09
-#define TEMIC_SET_PAL_L         0x0a // SECAM ?
-#define TEMIC_SET_PAL_L2        0x0b // change IF !
-#define TEMIC_SET_PAL_BG        0x0c
-
-/* tv tuner system standard selection for Philips FQ1216ME
-   this value takes the low bits of control byte 2
-   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
-     standard 		BG	DK	I	L	L`
-     picture carrier	38.90	38.90	38.90	38.90	33.95
-     colour		34.47	34.47	34.47	34.47	38.38
-     sound 1		33.40	32.40	32.90	32.40	40.45
-     sound 2		33.16	-	-	-	-
-     NICAM		33.05	33.05	32.35	33.05	39.80
- */
-#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
-#define PHILIPS_SET_PAL_BGDK	0x09
-#define PHILIPS_SET_PAL_L2	0x0a
-#define PHILIPS_SET_PAL_L	0x0b
-
-/* 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 // France
-#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
-
-
-/* ---------------------------------------------------------------------- */
-
-struct tunertype
-{
-	char *name;
-	unsigned char Vendor;
-	unsigned char Type;
-
-	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
-	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
-	unsigned char VHF_L;
-	unsigned char VHF_H;
-	unsigned char UHF;
-	unsigned char config;
-	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL,
-				   732  =16*45.75 NTSCi,
-				   940  =16*58.75 NTSC-Japan
-				   704  =16*44    ATSC */
-};
-
-/*
- *	The floats in the tuner struct are computed at compile time
- *	by gcc and cast back to integers. Thus we don't violate the
- *	"no float in kernel" rule.
- */
-static struct tunertype tuners[] = {
-        { "Temic PAL (4002 FH5)", TEMIC, PAL,
-	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
-	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
-	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
-	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
-	{ "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_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},
-	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
-	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
-
- 	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
-	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
-        { "Alps HSBH1", TEMIC, NTSC,
-	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-        { "Alps TSBE1",TEMIC,PAL,
-	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-        { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
-
-        { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
-        { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
-	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-  	{ "Alps TSCH6",Alps,NTSC,
-  	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
-
-  	{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL,
-  	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
-  	{ "Philips NTSC_M (MK2)",Philips,NTSC,
-  	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-
-        { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
-          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 (FI1256 and compatibles)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-
-	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
-	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
-
-	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "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 },
-
-	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
-          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
-	{ "MT20xx universal", Microtune,PAL|NTSC,
-               0,0,0,0,0,0,0},
-	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
-          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
-
-	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
-          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},
-
-	{ "HITACHI V7-J180AT", HITACHI, NTSC,
-	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
-	{ "Philips PAL_MK (FI1216 MK)", Philips, PAL,
-	  16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
-	{ "Philips 1236D ATSC/NTSC daul in",Philips,ATSC,
-	  16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-
-        { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-	{ "Microtune 4049 FM5",Microtune,PAL,
-	  16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
-	{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
-	  16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
-        { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-
-        { "Tenna TNF 8831 BGFF)", Philips, PAL,
-          16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
-	  16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
-        { "TCL 2002N", TCL, NTSC,
-          16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
-	{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
-
-	{ "Thomson DDT 7610 ATSC/NTSC)", THOMSON, ATSC,
-	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
-	{ "Philips FQ1286", Philips, NTSC,
-	  16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested
-
-};
-#define TUNERS ARRAY_SIZE(tuners)
-
-/* ---------------------------------------------------------------------- */
-
-static int tuner_getstatus(struct i2c_client *c)
-{
-	unsigned char byte;
-
-	struct tuner *t = i2c_get_clientdata(c);
-
-        if (t->type == TUNER_MT2032)
-		return 0;
-
-	if (1 != i2c_master_recv(c,&byte,1))
-		return 0;
-	return byte;
-}
-
-#define TUNER_POR       0x80
-#define TUNER_FL        0x40
-#define TUNER_MODE      0x38
-#define TUNER_AFC       0x07
-
-#define TUNER_STEREO    0x10 /* radio mode */
-#define TUNER_SIGNAL    0x07 /* radio mode */
-
-static int tuner_signal(struct i2c_client *c)
-{
-	return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
-}
-
-static int tuner_stereo(struct i2c_client *c)
-{
-	return (tuner_getstatus (c) & TUNER_STEREO);
-}
-
-#if 0 /* unused */
-static int tuner_islocked (struct i2c_client *c)
-{
-        return (tuner_getstatus (c) & TUNER_FL);
-}
-
-static int tuner_afcstatus (struct i2c_client *c)
-{
-        return (tuner_getstatus (c) & TUNER_AFC) - 2;
-}
-
-static int tuner_mode (struct i2c_client *c)
-{
-        return (tuner_getstatus (c) & TUNER_MODE) >> 3;
-}
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-#define MT2032 0x04
-#define MT2030 0x06
-#define MT2040 0x07
-#define MT2050 0x42
-
-static char *microtune_part[] = {
-	[ MT2030 ] = "MT2030",
-	[ MT2032 ] = "MT2032",
-	[ MT2040 ] = "MT2040",
-	[ MT2050 ] = "MT2050",
-};
-
-// IsSpurInBand()?
-static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to)
-{
-	int n1=1,n2,f;
-
-	f1=f1/1000; //scale to kHz to avoid 32bit overflows
-	f2=f2/1000;
-	spectrum_from/=1000;
-	spectrum_to/=1000;
-
-	dprintk("spurcheck f1=%d f2=%d  from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to);
-
-	do {
-	    n2=-n1;
-	    f=n1*(f1-f2);
-	    do {
-		n2--;
-		f=f-f2;
-		dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
-
-		if( (f>spectrum_from) && (f<spectrum_to))
-			printk("mt2032 spurcheck triggered: %d\n",n1);
-	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
-	    n1++;
-	} while (n1<5);
-
-	return 1;
-}
-
-static int mt2032_compute_freq(unsigned int rfin,
-			       unsigned int if1, unsigned int if2,
-			       unsigned int spectrum_from,
-			       unsigned int spectrum_to,
-			       unsigned char *buf,
-			       int *ret_sel,
-			       unsigned int xogc) //all in Hz
-{
-        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
-		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
-
-        fref= 5250 *1000; //5.25MHz
-	desired_lo1=rfin+if1;
-
-	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
-        lo1n=lo1/8;
-        lo1a=lo1-(lo1n*8);
-
-        s=rfin/1000/1000+1090;
-
-	if(optimize_vco) {
-		if(s>1890) sel=0;
-		else if(s>1720) sel=1;
-		else if(s>1530) sel=2;
-		else if(s>1370) sel=3;
-		else sel=4; // >1090
-	}
-	else {
-        	if(s>1790) sel=0; // <1958
-        	else if(s>1617) sel=1;
-        	else if(s>1449) sel=2;
-        	else if(s>1291) sel=3;
-        	else sel=4; // >1090
-	}
-	*ret_sel=sel;
-
-        lo1freq=(lo1a+8*lo1n)*fref;
-
-        dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
-		rfin,lo1,lo1n,lo1a,sel,lo1freq);
-
-        desired_lo2=lo1freq-rfin-if2;
-        lo2=(desired_lo2)/fref;
-        lo2n=lo2/8;
-        lo2a=lo2-(lo2n*8);
-        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
-        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
-
-        dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
-		rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
-
-        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
-                printk("mt2032: frequency parameters out of range: %d %d %d %d\n",
-		       lo1a, lo1n, lo2a,lo2n);
-                return(-1);
-        }
-
-	mt2032_spurcheck(lo1freq, desired_lo2,  spectrum_from, spectrum_to);
-	// should recalculate lo1 (one step up/down)
-
-	// set up MT2032 register map for transfer over i2c
-	buf[0]=lo1n-1;
-	buf[1]=lo1a | (sel<<4);
-	buf[2]=0x86; // LOGC
-	buf[3]=0x0f; //reserved
-	buf[4]=0x1f;
-	buf[5]=(lo2n-1) | (lo2a<<5);
- 	if(rfin >400*1000*1000)
-                buf[6]=0xe4;
-        else
-                buf[6]=0xf4; // set PKEN per rev 1.2
-	buf[7]=8+xogc;
-	buf[8]=0xc3; //reserved
-	buf[9]=0x4e; //reserved
-	buf[10]=0xec; //reserved
-	buf[11]=(lo2num&0xff);
-	buf[12]=(lo2num>>8) |0x80; // Lo2RST
-
-	return 0;
-}
-
-static int mt2032_check_lo_lock(struct i2c_client *c)
-{
-	int try,lock=0;
-	unsigned char buf[2];
-	for(try=0;try<10;try++) {
-		buf[0]=0x0e;
-		i2c_master_send(c,buf,1);
-		i2c_master_recv(c,buf,1);
-		dprintk("mt2032 Reg.E=0x%02x\n",buf[0]);
-		lock=buf[0] &0x06;
-
-		if (lock==6)
-			break;
-
-		dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
-		udelay(1000);
-	}
-        return lock;
-}
-
-static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
-{
-	unsigned char buf[2];
-	int tad1;
-
-	buf[0]=0x0f;
-	i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,1);
-	dprintk("mt2032 Reg.F=0x%02x\n",buf[0]);
-	tad1=buf[0]&0x07;
-
-	if(tad1 ==0) return lock;
-	if(tad1 ==1) return lock;
-
-	if(tad1==2) {
-		if(sel==0)
-			return lock;
-		else sel--;
-	}
-	else {
-		if(sel<4)
-			sel++;
-		else
-			return lock;
-	}
-
-	dprintk("mt2032 optimize_vco: sel=%d\n",sel);
-
-	buf[0]=0x0f;
-	buf[1]=sel;
-        i2c_master_send(c,buf,2);
-	lock=mt2032_check_lo_lock(c);
-	return lock;
-}
-
-
-static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
-			       unsigned int if1, unsigned int if2,
-			       unsigned int from, unsigned int to)
-{
-	unsigned char buf[21];
-	int lint_try,ret,sel,lock=0;
-	struct tuner *t = i2c_get_clientdata(c);
-
-	dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to);
-
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
-
-	buf[0]=0;
-	ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
-	if (ret<0)
-		return;
-
-        // send only the relevant registers per Rev. 1.2
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,4);
-        buf[5]=5;
-        ret=i2c_master_send(c,buf+5,4);
-        buf[11]=11;
-        ret=i2c_master_send(c,buf+11,3);
-        if(ret!=3)
-                printk("mt2032_set_if_freq failed with %d\n",ret);
-
-	// wait for PLLs to lock (per manual), retry LINT if not.
-	for(lint_try=0; lint_try<2; lint_try++) {
-		lock=mt2032_check_lo_lock(c);
-
-		if(optimize_vco)
-			lock=mt2032_optimize_vco(c,sel,lock);
-		if(lock==6) break;
-
-		printk("mt2032: re-init PLLs by LINT\n");
-		buf[0]=7;
-		buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
-		i2c_master_send(c,buf,2);
-		mdelay(10);
-		buf[1]=8+t->xogc;
-		i2c_master_send(c,buf,2);
-        }
-
-	if (lock!=6)
-		printk("MT2032 Fatal Error: PLLs didn't lock.\n");
-
-	buf[0]=2;
-	buf[1]=0x20; // LOGC for optimal phase noise
-	ret=i2c_master_send(c,buf,2);
-	if (ret!=2)
-		printk("mt2032_set_if_freq2 failed with %d\n",ret);
-}
-
-
-static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	int if2,from,to;
-
-	// signal bandwidth and picture carrier
-	if (t->std & V4L2_STD_525_60) {
-		// NTSC
-		from = 40750*1000;
-		to   = 46750*1000;
-		if2  = 45750*1000;
-	} else {
-		// PAL
-		from = 32900*1000;
-		to   = 39900*1000;
-		if2  = 38900*1000;
-	}
-
-        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
-			   1090*1000*1000, if2, from, to);
-}
-
-static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	int if2 = t->radio_if2;
-
-	// per Manual for FM tuning: first if center freq. 1085 MHz
-        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
-			   1085*1000*1000,if2,if2,if2);
-}
-
-// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct i2c_client *c)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buf[21];
-        int ret,xogc,xok=0;
-
-	// Initialize Registers per spec.
-        buf[1]=2; // Index to register 2
-        buf[2]=0xff;
-        buf[3]=0x0f;
-        buf[4]=0x1f;
-        ret=i2c_master_send(c,buf+1,4);
-
-        buf[5]=6; // Index register 6
-        buf[6]=0xe4;
-        buf[7]=0x8f;
-        buf[8]=0xc3;
-        buf[9]=0x4e;
-        buf[10]=0xec;
-        ret=i2c_master_send(c,buf+5,6);
-
-        buf[12]=13;  // Index register 13
-        buf[13]=0x32;
-        ret=i2c_master_send(c,buf+12,2);
-
-        // Adjust XOGC (register 7), wait for XOK
-        xogc=7;
-        do {
-		dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                mdelay(10);
-                buf[0]=0x0e;
-                i2c_master_send(c,buf,1);
-                i2c_master_recv(c,buf,1);
-                xok=buf[0]&0x01;
-                dprintk("mt2032: xok = 0x%02x\n",xok);
-                if (xok == 1) break;
-
-                xogc--;
-                dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                if (xogc == 3) {
-                        xogc=4; // min. 4 per spec
-                        break;
-                }
-                buf[0]=0x07;
-                buf[1]=0x88 + xogc;
-                ret=i2c_master_send(c,buf,2);
-                if (ret!=2)
-                        printk("mt2032_init failed with %d\n",ret);
-        } while (xok != 1 );
-	t->xogc=xogc;
-
-	t->tv_freq    = mt2032_set_tv_freq;
-	t->radio_freq = mt2032_set_radio_freq;
-        return(1);
-}
-
-static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
-{
-       unsigned char buf[2];
-       int ret;
-
-       buf[0] = 6;
-       buf[1] = antenna ? 0x11 : 0x10;
-       ret=i2c_master_send(c,buf,2);
-       dprintk("mt2050: enabled antenna connector %d\n", antenna);
-}
-
-static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
-{
-	unsigned int if1=1218*1000*1000;
-	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
-	int ret;
-	unsigned char buf[6];
-
-	dprintk("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
-		freq,if1,if2);
-
-	f_lo1=freq+if1;
-	f_lo1=(f_lo1/1000000)*1000000;
-
-	f_lo2=f_lo1-freq-if2;
-	f_lo2=(f_lo2/50000)*50000;
-
-	lo1=f_lo1/4000000;
-	lo2=f_lo2/4000000;
-
-	f_lo1_modulo= f_lo1-(lo1*4000000);
-	f_lo2_modulo= f_lo2-(lo2*4000000);
-
-	num1=4*f_lo1_modulo/4000000;
-	num2=4096*(f_lo2_modulo/1000)/4000;
-
-	// todo spurchecks
-
-	div1a=(lo1/12)-1;
-	div1b=lo1-(div1a+1)*12;
-
-	div2a=(lo2/8)-1;
-	div2b=lo2-(div2a+1)*8;
-
-	if (debug > 1) {
-		printk("lo1 lo2 = %d %d\n", lo1, lo2);
-		printk("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",num1,num2,div1a,div1b,div2a,div2b);
-	}
-
-	buf[0]=1;
-	buf[1]= 4*div1b + num1;
-	if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
-
-	buf[2]=div1a;
-	buf[3]=32*div2b + num2/256;
-	buf[4]=num2-(num2/256)*256;
-	buf[5]=div2a;
-	if(num2!=0) buf[5]=buf[5]|0x40;
-
-	if (debug > 1) {
-		int i;
-		printk("bufs is: ");
-		for(i=0;i<6;i++)
-			printk("%x ",buf[i]);
-		printk("\n");
-	}
-
-	ret=i2c_master_send(c,buf,6);
-        if (ret!=6)
-                printk("mt2050_set_if_freq failed with %d\n",ret);
-}
-
-static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	unsigned int if2;
-
-	if (t->std & V4L2_STD_525_60) {
-		// NTSC
-                if2 = 45750*1000;
-        } else {
-                // PAL
-                if2 = 38900*1000;
-        }
-	if (V4L2_TUNER_DIGITAL_TV == t->mode) {
-		// testing for DVB ...
-		if2 = 36150*1000;
-	}
-	mt2050_set_if_freq(c, freq*62500, if2);
-	mt2050_set_antenna(c, tv_antenna);
-}
-
-static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	int if2 = t->radio_if2;
-
-	mt2050_set_if_freq(c, freq*62500, if2);
-	mt2050_set_antenna(c, radio_antenna);
-}
-
-static int mt2050_init(struct i2c_client *c)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	unsigned char buf[2];
-	int ret;
-
-	buf[0]=6;
-	buf[1]=0x10;
-	ret=i2c_master_send(c,buf,2); //  power
-
-	buf[0]=0x0f;
-	buf[1]=0x0f;
-	ret=i2c_master_send(c,buf,2); // m1lo
-
-	buf[0]=0x0d;
-	ret=i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,1);
-
-	dprintk("mt2050: sro is %x\n",buf[0]);
-	t->tv_freq    = mt2050_set_tv_freq;
-	t->radio_freq = mt2050_set_radio_freq;
-	return 0;
-}
-
-static int microtune_init(struct i2c_client *c)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	char *name;
-        unsigned char buf[21];
-	int company_code;
-
-	memset(buf,0,sizeof(buf));
-	t->tv_freq    = NULL;
-	t->radio_freq = NULL;
-	name = "unknown";
-
-        i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
-        if(debug) {
-                int i;
-                printk(KERN_DEBUG "tuner: MT2032 hexdump:\n");
-                for(i=0;i<21;i++) {
-                        printk(" %02x",buf[i]);
-                        if(((i+1)%8)==0) printk(" ");
-                        if(((i+1)%16)==0) printk("\n ");
-                }
-                printk("\n ");
-        }
-	company_code = buf[0x11] << 8 | buf[0x12];
-        printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n",
-	       company_code,buf[0x13],buf[0x14]);
-
-#if 0
-	/* seems to cause more problems than it solves ... */
-	switch (company_code) {
-	case 0x30bf:
-	case 0x3cbf:
-	case 0x3dbf:
-	case 0x4d54:
-	case 0x8e81:
-	case 0x8e91:
-		/* ok (?) */
-		break;
-	default:
-		printk("tuner: microtune: unknown companycode\n");
-		return 0;
-	}
-#endif
-
-	if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
-	    NULL != microtune_part[buf[0x13]])
-		name = microtune_part[buf[0x13]];
-	switch (buf[0x13]) {
-	case MT2032:
-		mt2032_init(c);
-		break;
-	case MT2050:
-		mt2050_init(c);
-		break;
-	default:
-		printk("tuner: microtune %s found, not (yet?) supported, sorry :-/\n",
-		       name);
-                return 0;
-        }
-	printk("tuner: microtune %s found, OK\n",name);
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	u8 config;
-	u16 div;
-	struct tunertype *tun;
-        unsigned char buffer[4];
-	int rc;
-
-	tun = &tuners[t->type];
-	if (freq < tun->thresh1) {
-		config = tun->VHF_L;
-		dprintk("tv: VHF lowrange\n");
-	} else if (freq < tun->thresh2) {
-		config = tun->VHF_H;
-		dprintk("tv: VHF high range\n");
-	} else {
-		config = tun->UHF;
-		dprintk("tv: UHF range\n");
-	}
-
-
-	/* tv norm specific stuff for multi-norm tuners */
-	switch (t->type) {
-	case TUNER_PHILIPS_SECAM: // FI1216MF
-		/* 0x01 -> ??? no change ??? */
-		/* 0x02 -> PAL BDGHI / SECAM L */
-		/* 0x04 -> ??? PAL others / SECAM others ??? */
-		config &= ~0x02;
-		if (t->std & V4L2_STD_SECAM)
-			config |= 0x02;
-		break;
-
-	case TUNER_TEMIC_4046FM5:
-		config &= ~0x0f;
-
-		if (t->std & V4L2_STD_PAL_BG) {
-			config |= TEMIC_SET_PAL_BG;
-
-		} else if (t->std & V4L2_STD_PAL_I) {
-			config |= TEMIC_SET_PAL_I;
-
-		} else if (t->std & V4L2_STD_PAL_DK) {
-			config |= TEMIC_SET_PAL_DK;
-
-		} else if (t->std & V4L2_STD_SECAM_L) {
-			config |= TEMIC_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_FQ1216ME:
-		config &= ~0x0f;
-
-		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
-			config |= PHILIPS_SET_PAL_BGDK;
-
-		} else if (t->std & V4L2_STD_PAL_I) {
-			config |= PHILIPS_SET_PAL_I;
-
-		} else if (t->std & V4L2_STD_SECAM_L) {
-			config |= PHILIPS_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_ATSC:
-		/* 0x00 -> ATSC antenna input 1 */
-		/* 0x01 -> ATSC antenna input 2 */
-		/* 0x02 -> NTSC antenna input 1 */
-		/* 0x03 -> NTSC antenna input 2 */
-		config &= ~0x03;
-		if (!(t->std & V4L2_STD_ATSC))
-			config |= 2;
-		/* FIXME: input */
-		break;
-
-	case TUNER_MICROTUNE_4042FI5:
-		/* Set the charge pump for fast tuning */
-		tun->config |= 0x40;
-		break;
-	}
-
-	/*
-	 * Philips FI1216MK2 remark from specification :
-	 * for channel selection involving band switching, and to ensure
-	 * smooth tuning to the desired channel without causing
-	 * unnecessary charge pump action, it is recommended to consider
-	 * the difference between wanted channel frequency and the
-	 * current channel frequency.  Unnecessary charge pump action
-	 * will result in very low tuning voltage which may drive the
-	 * oscillator to extreme conditions.
-	 *
-	 * Progfou: specification says to send config data before
-	 * frequency in case (wanted frequency < current frequency).
-	 */
-
-	div=freq + tun->IFPCoff;
-	if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
-		buffer[0] = tun->config;
-		buffer[1] = config;
-		buffer[2] = (div>>8) & 0x7f;
-		buffer[3] = div      & 0xff;
-	} else {
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-		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);
-
-	if (t->type == TUNER_MICROTUNE_4042FI5) {
-		// FIXME - this may also work for other tuners
-		unsigned long timeout = jiffies + msecs_to_jiffies(1);
-		u8 status_byte = 0;
-
-		/* Wait until the PLL locks */
-		for (;;) {
-			if (time_after(jiffies,timeout))
-				return;
-			if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
-				dprintk("tuner: i2c i/o read error: rc == %d (should be 1)\n",rc);
-				break;
-			}
-			/* bit 6 is PLL locked indicator */
-			if (status_byte & 0x40)
-				break;
-			udelay(10);
-		}
-
-		/* Set the charge pump for optimized phase noise figure */
-		tun->config &= ~0x40;
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-		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)))
-			dprintk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
-	}
-}
-
-static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tunertype *tun;
-	struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buffer[4];
-	unsigned div;
-	int rc;
-
-	tun=&tuners[t->type];
-	div = freq + (int)(16*10.7);
-	buffer[2] = tun->config;
-
-	switch (t->type) {
-	case TUNER_PHILIPS_FM1216ME_MK3:
-	case TUNER_PHILIPS_FM1236_MK3:
-		buffer[3] = 0x19;
-		break;
-	case TUNER_PHILIPS_FM1256_IH3:
-		div = (20 * freq)/16 + 333 * 2;
-	        buffer[2] = 0x80;
-		buffer[3] = 0x19;
-		break;
-	case TUNER_LG_PAL_FM:
-		buffer[3] = 0xa5;
-		break;
-	default:
-		buffer[3] = 0xa4;
-		break;
-	}
-        buffer[0] = (div>>8) & 0x7f;
-        buffer[1] = div      & 0xff;
-
-	dprintk("tuner: radio 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);
-}
-
-/* ---------------------------------------------------------------------- */
-
-// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	if (t->type == UNSET) {
-		printk("tuner: tuner type not set\n");
-		return;
-	}
-	if (NULL == t->tv_freq) {
-		printk("tuner: Huh? tv_set is NULL?\n");
-		return;
-	}
-	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
-		/* FIXME: better do that chip-specific, but
-		   right now we don't have that in the config
-		   struct and this way is still better than no
-		   check at all */
-		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",
-		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
-		return;
-	}
-	t->tv_freq(c,freq);
-}
-
-static void set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	if (t->type == UNSET) {
-		printk("tuner: tuner type not set\n");
-		return;
-	}
-	if (NULL == t->radio_freq) {
-		printk("tuner: no radio tuning for this one, sorry.\n");
-		return;
-	}
-	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
-		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
-		       freq/16,freq%16*100/16,
-		       radio_range[0],radio_range[1]);
-		return;
-	}
-	t->radio_freq(c,freq);
-}
-
-static void set_freq(struct i2c_client *c, unsigned long freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	switch (t->mode) {
-	case V4L2_TUNER_RADIO:
-		dprintk("tuner: radio freq set to %lu.%02lu\n",
-			freq/16,freq%16*100/16);
-		set_radio_freq(c,freq);
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-	case V4L2_TUNER_DIGITAL_TV:
-		dprintk("tuner: tv freq set to %lu.%02lu\n",
-			freq/16,freq%16*100/16);
-		set_tv_freq(c, freq);
-		break;
-	}
-	t->freq = freq;
-}
-
-static void set_type(struct i2c_client *c, unsigned int type, char *source)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	if (t->type != UNSET && t->type != TUNER_ABSENT) {
-		if (t->type != type)
-			printk("tuner: type already set to %d, "
-			       "ignoring request for %d\n", t->type, type);
-		return;
-	}
-	if (type >= TUNERS)
-		return;
-
-	t->type = type;
-	printk("tuner: type set to %d (%s) by %s\n",
-	       t->type,tuners[t->type].name, source);
-	strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
-
-	switch (t->type) {
-	case TUNER_MT2032:
-		microtune_init(c);
-		break;
-	default:
-		t->tv_freq    = default_set_tv_freq;
-		t->radio_freq = default_set_radio_freq;
-		break;
-	}
-}
-
-static char pal[] = "-";
-module_param_string(pal, pal, 0644, sizeof(pal));
-
-static int tuner_fixup_std(struct tuner *t)
-{
-	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
-		/* get more precise norm info from insmod option */
-		switch (pal[0]) {
-		case 'b':
-		case 'B':
-		case 'g':
-		case 'G':
-			dprintk("insmod fixup: PAL => PAL-BG\n");
-			t->std = V4L2_STD_PAL_BG;
-			break;
-		case 'i':
-		case 'I':
-			dprintk("insmod fixup: PAL => PAL-I\n");
-			t->std = V4L2_STD_PAL_I;
-			break;
-		case 'd':
-		case 'D':
-		case 'k':
-		case 'K':
-			dprintk("insmod fixup: PAL => PAL-DK\n");
-			t->std = V4L2_STD_PAL_DK;
-			break;
-		}
-	}
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct tuner *t;
-	struct i2c_client *client;
-
-	if (this_adap > 0)
-		return -1;
-	this_adap++;
-
-        client_template.adapter = adap;
-        client_template.addr = addr;
-
-        printk("tuner: chip found at addr 0x%x i2c-bus %s\n",
-	       addr<<1, adap->name);
-
-        if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
-                return -ENOMEM;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
-        if (NULL == t) {
-                kfree(client);
-                return -ENOMEM;
-        }
-        memset(t,0,sizeof(struct tuner));
-	i2c_set_clientdata(client, t);
-	t->type       = UNSET;
-	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
-
-        i2c_attach_client(client);
-	if (type < TUNERS) {
-		set_type(client, type, "insmod option");
-		printk("tuner: The type=<n> insmod option will go away soon.\n");
-		printk("tuner: Please use the tuner=<n> option provided by\n");
-		printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n");
-	}
-	return 0;
-}
-
-static int tuner_probe(struct i2c_adapter *adap)
-{
-	if (0 != addr) {
-		normal_i2c_range[0] = addr;
-		normal_i2c_range[1] = addr;
-	}
-	this_adap = 0;
-
-#ifdef I2C_CLASS_TV_ANALOG
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, tuner_attach);
-#else
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-	case I2C_ALGO_SAA7146:
-		return i2c_probe(adap, &addr_data, tuner_attach);
-		break;
-	}
-#endif
-	return 0;
-}
-
-static int tuner_detach(struct i2c_client *client)
-{
-	struct tuner *t = i2c_get_clientdata(client);
-
-	i2c_detach_client(client);
-	kfree(t);
-	kfree(client);
-	return 0;
-}
-
-#define SWITCH_V4L2	if (!t->using_v4l2 && debug) \
-		          printk("tuner: switching to v4l2\n"); \
-	                  t->using_v4l2 = 1;
-#define CHECK_V4L2	if (t->using_v4l2) { if (debug) \
-			  printk("tuner: ignore v4l1 call\n"); \
-		          return 0; }
-
-static int
-tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-	struct tuner *t = i2c_get_clientdata(client);
-        unsigned int *iarg = (int*)arg;
-
-        switch (cmd) {
-
-	/* --- configuration --- */
-	case TUNER_SET_TYPE:
-		set_type(client,*iarg,client->adapter->name);
-		break;
-	case AUDC_SET_RADIO:
-		if (V4L2_TUNER_RADIO != t->mode) {
-			set_tv_freq(client,400 * 16);
-			t->mode = V4L2_TUNER_RADIO;
-		}
-		break;
-	case AUDC_CONFIG_PINNACLE:
-		switch (*iarg) {
-		case 2:
-			dprintk("tuner: pinnacle pal\n");
-			t->radio_if2 = 33300 * 1000;
-			break;
-		case 3:
-			dprintk("tuner: pinnacle ntsc\n");
-			t->radio_if2 = 41300 * 1000;
-			break;
-		}
-                break;
-
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-	case VIDIOCSCHAN:
-	{
-		static const v4l2_std_id map[] = {
-			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,
-			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,
-			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
-			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,
-			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,
-			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,
-		};
-		struct video_channel *vc = arg;
-
-		CHECK_V4L2;
-		t->mode = V4L2_TUNER_ANALOG_TV;
-		if (vc->norm < ARRAY_SIZE(map))
-			t->std = map[vc->norm];
-		tuner_fixup_std(t);
-		if (t->freq)
-			set_tv_freq(client,t->freq);
-		return 0;
-	}
-	case VIDIOCSFREQ:
-	{
-		unsigned long *v = arg;
-
-		CHECK_V4L2;
-		set_freq(client,*v);
-		return 0;
-	}
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *vt = arg;
-
-		CHECK_V4L2;
-		if (V4L2_TUNER_RADIO == t->mode)
-			vt->signal = tuner_signal(client);
-		return 0;
-	}
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *va = arg;
-
-		CHECK_V4L2;
-		if (V4L2_TUNER_RADIO == t->mode)
-			va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
-		return 0;
-	}
-
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-
-		SWITCH_V4L2;
-		t->mode = V4L2_TUNER_ANALOG_TV;
-		t->std = *id;
-		tuner_fixup_std(t);
-		if (t->freq)
-			set_freq(client,t->freq);
-		break;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		SWITCH_V4L2;
-		if (V4L2_TUNER_RADIO == f->type &&
-		    V4L2_TUNER_RADIO != t->mode)
-			set_tv_freq(client,400*16);
-		t->mode  = f->type;
-		t->freq  = f->frequency;
-		set_freq(client,t->freq);
-		break;
-	}
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *tuner = arg;
-
-		SWITCH_V4L2;
-		if (V4L2_TUNER_RADIO == t->mode)
-			tuner->signal = tuner_signal(client);
-		break;
-	}
-	default:
-		/* nothing */
-		break;
-	}
-
-	return 0;
-}
-
-static int tuner_suspend(struct device * dev, u32 state, u32 level)
-{
-	dprintk("tuner: suspend\n");
-	/* FIXME: power down ??? */
-	return 0;
-}
-
-static int tuner_resume(struct device * dev, u32 level)
-{
-	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
-	struct tuner *t = i2c_get_clientdata(c);
-
-	dprintk("tuner: resume\n");
-	if (t->freq)
-		set_freq(c,t->freq);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-	.owner          = THIS_MODULE,
-        .name           = "i2c TV tuner driver",
-        .id             = I2C_DRIVERID_TUNER,
-        .flags          = I2C_DF_NOTIFY,
-        .attach_adapter = tuner_probe,
-        .detach_client  = tuner_detach,
-        .command        = tuner_command,
-	.driver = {
-		.suspend = tuner_suspend,
-		.resume  = tuner_resume,
-	},
-};
-static struct i2c_client client_template =
-{
-	I2C_DEVNAME("(tuner unset)"),
-	.flags      = I2C_CLIENT_ALLOW_USE,
-        .driver     = &driver,
-};
-
-static int __init tuner_init_module(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit tuner_cleanup_module(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(tuner_init_module);
-module_exit(tuner_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -286,6 +286,7 @@ static int chip_thread(void *data)
 			schedule();
 		}
 		remove_wait_queue(&chip->wq, &wait);
+		try_to_freeze(PF_FREEZE);
 		if (chip->done || signal_pending(current))
 			break;
 		dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
@@ -990,7 +991,7 @@ static int tda9874a_initialize(struct CH
 {
 	if (tda9874a_SIF > 2)
 		tda9874a_SIF = 1;
-	if (tda9874a_STD >= 8)
+	if (tda9874a_STD > 8)
 		tda9874a_STD = 0;
 	if(tda9874a_AMSEL > 1)
 		tda9874a_AMSEL = 0;
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -30,10 +30,12 @@
 
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/videodev.h>
 #include <linux/i2c.h>
 
 #include <media/tuner.h>
@@ -190,11 +192,13 @@ hauppauge_tuner[] =
 	{ TUNER_ABSENT,        "TCL MFPE05 2"},
 	/* 90-99 */
 	{ TUNER_ABSENT,        "LG TALN H202T"},
-	{ TUNER_ABSENT,        "Philips FQ1216AME MK4"},
-	{ TUNER_ABSENT,        "Philips FQ1236A MK4"},
+	{ TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
+	{ TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
 	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
 	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
 	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
+	{ TUNER_ABSENT,        "Unspecified"},
+	{ TUNER_LG_PAL_TAPE,   "LG PAL (TAPE Series)"},
 };
 
 static char *sndtype[] = {
@@ -240,6 +244,7 @@ static int hasRadioTuner(int tunerType)
                 case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
                 case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
                 case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+                case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
                     return 1;
         }
         return 0;
@@ -255,8 +260,8 @@ void tveeprom_hauppauge_analog(struct tv
 	** if packet[0] & f8 == f8, then EOD and packet[1] == checksum
 	**
 	** In our (ivtv) case we're interested in the following:
-	** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuners)
-	** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_fmts)
+	** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner)
+	** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
 	** radio:      tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
 	** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?)
 
@@ -268,11 +273,11 @@ void tveeprom_hauppauge_analog(struct tv
 	** # of inputs/outputs ???
 	*/
 
-	int i, j, len, done, tag, tuner = 0, t_format = 0;
+	int i, j, len, done, beenhere, tag, tuner = 0, t_format = 0;
 	char *t_name = NULL, *t_fmt_name = NULL;
 
 	dprintk(1, "%s\n",__FUNCTION__);
-	tvee->revision = done = len = 0;
+	tvee->revision = done = len = beenhere = 0;
 	for (i = 0; !done && i < 256; i += len) {
 		dprintk(2, "processing pos = %02x (%02x, %02x)\n",
 			i, eeprom_data[i], eeprom_data[i + 1]);
@@ -341,9 +346,14 @@ void tveeprom_hauppauge_analog(struct tv
 				(eeprom_data[i+7] << 16);
 			break;
 		case 0x0a:
-			tuner = eeprom_data[i+2];
-			t_format = eeprom_data[i+1];
-			break;
+			if(beenhere == 0) {
+				tuner = eeprom_data[i+2];
+				t_format = eeprom_data[i+1];
+				beenhere = 1;
+				break;
+			} else {
+				break;
+			}
 		case 0x0e:
 			tvee->has_radio = eeprom_data[i+1];
 			break;
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -149,10 +149,10 @@ int videobuf_dvb_register(struct videobu
 		       dvb->name, result);
 		goto fail_adapter;
 	}
-	dvb->adapter->priv = adapter_priv;
+	dvb->adapter.priv = adapter_priv;
 
 	/* register frontend */
-	result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 	if (result < 0) {
 		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
 		       dvb->name, result);
@@ -178,7 +178,7 @@ int videobuf_dvb_register(struct videobu
 	dvb->dmxdev.filternum    = 256;
 	dvb->dmxdev.demux        = &dvb->demux.dmx;
 	dvb->dmxdev.capabilities = 0;
-	result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 	if (result < 0) {
 		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
 		       dvb->name, result);
@@ -209,7 +209,7 @@ int videobuf_dvb_register(struct videobu
 	}
 
 	/* register network adapter */
-	dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
 	return 0;
 
 fail_fe_conn:
@@ -223,7 +223,7 @@ fail_dmxdev:
 fail_dmx:
 	dvb_unregister_frontend(dvb->frontend);
 fail_frontend:
-	dvb_unregister_adapter(dvb->adapter);
+	dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
 	return result;
 }
@@ -236,7 +236,7 @@ void videobuf_dvb_unregister(struct vide
 	dvb_dmxdev_release(&dvb->dmxdev);
 	dvb_dmx_release(&dvb->demux);
 	dvb_unregister_frontend(dvb->frontend);
-	dvb_unregister_adapter(dvb->adapter);
+	dvb_unregister_adapter(&dvb->adapter);
 }
 
 EXPORT_SYMBOL(videobuf_dvb_register);
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -1,5 +1,5 @@
 /*
- * $Id: video-buf.c,v 1.17 2004/12/10 12:33:40 kraxel Exp $
+ * $Id: video-buf.c,v 1.18 2005/02/24 13:32:30 kraxel Exp $
  *
  * generic helper functions for video4linux capture buffers, to handle
  * memory management and PCI DMA.  Right now bttv + saa7134 use it.
@@ -217,9 +217,18 @@ int videobuf_dma_pci_map(struct pci_dev 
 		return -ENOMEM;
 	}
 
-	if (!dma->bus_addr)
+	if (!dma->bus_addr) {
 		dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages,
 					dma->direction);
+		if (0 == dma->sglen) {
+			printk(KERN_WARNING
+			       "%s: pci_map_sg failed\n",__FUNCTION__);
+			kfree(dma->sglist);
+			dma->sglist = NULL;
+			dma->sglen = 0;
+			return -EIO;
+		}
+	}
 	return 0;
 }
 
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -46,15 +46,7 @@ static ssize_t show_name(struct class_de
 	return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
 }
 
-static ssize_t show_dev(struct class_device *cd, char *buf)
-{
-	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
-	dev_t dev = MKDEV(VIDEO_MAJOR, vfd->minor);
-	return print_dev_t(buf,dev);
-}
-
 static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static CLASS_DEVICE_ATTR(dev,  S_IRUGO, show_dev, NULL);
 
 struct video_device *video_device_alloc(void)
 {
@@ -347,12 +339,11 @@ int video_register_device(struct video_d
 	if (vfd->dev)
 		vfd->class_dev.dev = vfd->dev;
 	vfd->class_dev.class       = &video_class;
+	vfd->class_dev.devt       = MKDEV(VIDEO_MAJOR, vfd->minor);
 	strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
 	class_device_register(&vfd->class_dev);
 	class_device_create_file(&vfd->class_dev,
 				 &class_device_attr_name);
-	class_device_create_file(&vfd->class_dev,
-				 &class_device_attr_dev);
 
 #if 1 /* needed until all drivers are fixed */
 	if (!vfd->release)
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -587,7 +587,6 @@ static struct i2c_client_address_data ad
 	.force			= force
 };
 
-static int vpx3220_i2c_id = 0;
 static struct i2c_driver vpx3220_i2c_driver;
 
 static int
@@ -634,7 +633,6 @@ vpx3220_detect_client (struct i2c_adapte
 	client->adapter = adapter;
 	client->driver = &vpx3220_i2c_driver;
 	client->flags = I2C_CLIENT_ALLOW_USE;
-	client->id = vpx3220_i2c_id++;
 
 	/* Check for manufacture ID and part number */
 	if (kind < 0) {
@@ -655,16 +653,16 @@ vpx3220_detect_client (struct i2c_adapte
 		    vpx3220_read(client, 0x01);
 		switch (pn) {
 		case 0x4680:
-			snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-				 "vpx3220a[%d]", client->id);
+			strlcpy(I2C_NAME(client), "vpx3220a",
+				sizeof(I2C_NAME(client)));
 			break;
 		case 0x4260:
-			snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-				 "vpx3216b[%d]", client->id);
+			strlcpy(I2C_NAME(client), "vpx3216b",
+				sizeof(I2C_NAME(client)));
 			break;
 		case 0x4280:
-			snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-				 "vpx3214c[%d]", client->id);
+			strlcpy(I2C_NAME(client), "vpx3214c",
+				sizeof(I2C_NAME(client)));
 			break;
 		default:
 			dprintk(1,
@@ -675,9 +673,8 @@ vpx3220_detect_client (struct i2c_adapte
 			return 0;
 		}
 	} else {
-		snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-			 "forced vpx32xx[%d]",
-		client->id);
+		strlcpy(I2C_NAME(client), "forced vpx32xx",
+			sizeof(I2C_NAME(client)));
 	}
 
 	decoder = kmalloc(sizeof(struct vpx3220), GFP_KERNEL);
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -41,6 +41,7 @@
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/kmod.h>
+#include <linux/wait.h>
 
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -968,6 +969,7 @@ zoran_open_init_params (struct zoran *zr
 static void __devinit
 test_interrupts (struct zoran *zr)
 {
+	DEFINE_WAIT(wait);
 	int timeout, icr;
 
 	clear_interrupt_counters(zr);
@@ -975,7 +977,9 @@ test_interrupts (struct zoran *zr)
 	zr->testing = 1;
 	icr = btread(ZR36057_ICR);
 	btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
-	timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ);
+	prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE);
+	timeout = schedule_timeout(HZ);
+	finish_wait(&zr->test_q, &wait);
 	btwrite(0, ZR36057_ICR);
 	btwrite(0x78000000, ZR36057_ISR);
 	zr->testing = 0;
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -46,6 +46,7 @@
 #include <linux/video_decoder.h>
 #include <linux/video_encoder.h>
 #include <linux/delay.h>
+#include <linux/wait.h>
 
 #include <asm/io.h>
 
@@ -696,11 +697,10 @@ wait_grab_pending (struct zoran *zr)
 	if (!zr->v4l_memgrab_active)
 		return 0;
 
-	while (zr->v4l_pend_tail != zr->v4l_pend_head) {
-		interruptible_sleep_on(&zr->v4l_capq);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
+	wait_event_interruptible(zr->v4l_capq,
+			(zr->v4l_pend_tail == zr->v4l_pend_head));
+	if (signal_pending(current))
+		return -ERESTARTSYS;
 
 	spin_lock_irqsave(&zr->spinlock, flags);
 	zr36057_set_memgrab(zr, 0);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -52,6 +52,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
+#include <linux/wait.h>
 #include <linux/byteorder/generic.h>
 
 #include <linux/interrupt.h>
@@ -918,12 +919,12 @@ v4l_sync (struct file *file,
 	}
 
 	/* wait on this buffer to get ready */
-	while (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_PEND) {
-		if (!interruptible_sleep_on_timeout(&zr->v4l_capq, 10 * HZ))
-			return -ETIME;
-		else if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
+	if (!wait_event_interruptible_timeout(zr->v4l_capq,
+				(zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
+				10*HZ))
+		return -ETIME;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
 
 	/* buffer should now be in BUZ_STATE_DONE */
 	if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
@@ -1107,7 +1108,7 @@ jpg_sync (struct file       *file,
 	struct zoran_fh *fh = file->private_data;
 	struct zoran *zr = fh->zr;
 	unsigned long flags;
-	int frame, timeout;
+	int frame;
 
 	if (fh->jpg_buffers.active == ZORAN_FREE) {
 		dprintk(1,
@@ -1124,29 +1125,26 @@ jpg_sync (struct file       *file,
 			ZR_DEVNAME(zr));
 		return -EINVAL;
 	}
-	while (zr->jpg_que_tail == zr->jpg_dma_tail) {
-		if (zr->jpg_dma_tail == zr->jpg_dma_head)
-			break;
-
-		timeout =
-		    interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ);
-		if (!timeout) {
-			int isr;
-
-			btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-			udelay(1);
-			zr->codec->control(zr->codec, CODEC_G_STATUS,
+	if (!wait_event_interruptible_timeout(zr->jpg_capq,
+			(zr->jpg_que_tail != zr->jpg_dma_tail ||
+			 zr->jpg_dma_tail == zr->jpg_dma_head),
+			10*HZ)) {
+		int isr;
+
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		udelay(1);
+		zr->codec->control(zr->codec, CODEC_G_STATUS,
 					   sizeof(isr), &isr);
-			dprintk(1,
-				KERN_ERR
-				"%s: jpg_sync() - timeout: codec isr=0x%02x\n",
-				ZR_DEVNAME(zr), isr);
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_sync() - timeout: codec isr=0x%02x\n",
+			ZR_DEVNAME(zr), isr);
 
-			return -ETIME;
+		return -ETIME;
 
-		} else if (signal_pending(current))
-			return -ERESTARTSYS;
 	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
 
 	spin_lock_irqsave(&zr->spinlock, flags);
 
@@ -2694,7 +2692,7 @@ zoran_do_ioctl (struct inode *inode,
 		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
 		strncpy(cap->driver, "zoran", sizeof(cap->driver));
 		snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-			 zr->pci_dev->slot_name);
+			 pci_name(zr->pci_dev));
 		cap->version =
 		    KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
 				   RELEASE_VERSION);
@@ -3761,7 +3759,7 @@ zoran_do_ioctl (struct inode *inode,
 		v4l2_std_id *std = arg;
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
-			ZR_DEVNAME(zr), *std);
+			ZR_DEVNAME(zr), (unsigned long long)*std);
 
 		if (*std == V4L2_STD_PAL)
 			norm = VIDEO_MODE_PAL;
@@ -3775,7 +3773,7 @@ zoran_do_ioctl (struct inode *inode,
 			dprintk(1,
 				KERN_ERR
 				"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
-				ZR_DEVNAME(zr), *std);
+				ZR_DEVNAME(zr), (unsigned long long)*std);
 			return -EINVAL;
 		}
 
@@ -4108,7 +4106,7 @@ zoran_do_ioctl (struct inode *inode,
 
 		dprintk(3,
 			KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
-			ZR_DEVNAME(zr), *std);
+			ZR_DEVNAME(zr), (unsigned long long)*std);
 
 		if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
 		    *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -419,7 +419,7 @@ zr36050_set_dri (struct zr36050 *ptr)
 	dri_data[2] = 0x00;
 	dri_data[3] = 0x04;
 	dri_data[4] = ptr->dri >> 8;
-	dri_data[5] = ptr->dri * 0xff;
+	dri_data[5] = ptr->dri & 0xff;
 	return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data);
 }
 
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -30,6 +30,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
+#include <linux/wait.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -899,12 +900,11 @@ long zoran_read(struct video_device* dev
 		zoran_cap(ztv, 1);
 
 		/* wait till this buffer gets grabbed */
-		while (unused->status == FBUFFER_BUSY) {
-			interruptible_sleep_on(&ztv->grabq);
-			/* see if a signal did it */
-			if (signal_pending(current))
-				return -EINTR;
-		}
+		wait_event_interruptible(ztv->grabq,
+				(unused->status != FBUFFER_BUSY));
+		/* see if a signal did it */
+		if (signal_pending(current))
+			return -EINTR;
 		done = unused;
 	}
 	else
@@ -1326,12 +1326,11 @@ int zoran_ioctl(struct video_device* dev
 			return -EINVAL;
 		 case FBUFFER_BUSY:
 			/* wait till this buffer gets grabbed */
-			while (ztv->grabinfo[i].status == FBUFFER_BUSY) {
-				interruptible_sleep_on(&ztv->grabq);
-				/* see if a signal did it */
-				if (signal_pending(current))
-					return -EINTR;
-			}
+			wait_event_interruptible(ztv->grabq,
+					(ztv->grabinfo[i].status != FBUFFER_BUSY));
+			/* see if a signal did it */
+			if (signal_pending(current))
+				return -EINTR;
 			/* don't fall through; a DONE buffer is not UNUSED */
 			break;
 		 case FBUFFER_DONE:
@@ -1640,12 +1639,11 @@ long vbi_read(struct video_device* dev, 
 		zoran_cap(ztv, 1);
 
 		/* wait till this buffer gets grabbed */
-		while (unused->status == FBUFFER_BUSY) {
-			interruptible_sleep_on(&ztv->vbiq);
-			/* see if a signal did it */
-			if (signal_pending(current))
-				return -EINTR;
-		}
+		wait_event_interruptible(ztv->vbiq,
+				(unused->status != FBUFFER_BUSY));
+		/* see if a signal did it */
+		if (signal_pending(current))
+			return -EINTR;
 		done = unused;
 	}
 	else
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1429,7 +1429,7 @@ mptbase_shutdown(struct device * dev)
  *
  */
 static int
-mptbase_suspend(struct pci_dev *pdev, u32 state)
+mptbase_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	u32 device_state;
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
@@ -3137,8 +3137,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
 
 				/* wait 1 sec */
 				if (sleepFlag == CAN_SLEEP) {
-					set_current_state(TASK_INTERRUPTIBLE);
-					schedule_timeout(1000 * HZ / 1000);
+					ssleep(1);
 				} else {
 					mdelay (1000);
 				}
@@ -5914,7 +5913,7 @@ fusion_init(void)
 #ifdef CONFIG_PROC_FS
 	(void) procmpt_create();
 #endif
-	r = pci_module_init(&mptbase_driver);
+	r = pci_register_driver(&mptbase_driver);
 	if(r)
 		return(r);
 
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -83,8 +83,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2004 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.01.18"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.18"
+#define MPT_LINUX_VERSION_COMMON	"3.01.20"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.20"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -215,7 +215,7 @@ struct mpt_pci_driver{
 	void (*shutdown) (struct device * dev);
 #ifdef CONFIG_PM
 	int  (*resume) (struct pci_dev *dev);
-	int  (*suspend) (struct pci_dev *dev, u32 state);
+	int  (*suspend) (struct pci_dev *dev, pm_message_t state);
 #endif
 };
 
@@ -420,7 +420,6 @@ do { \
 
 typedef struct _MPT_IOCTL {
 	struct _MPT_ADAPTER	*ioc;
-	struct timer_list	 timer;		/* timer function for this adapter */
 	u8			 ReplyFrame[MPT_DEFAULT_FRAME_SIZE];	/* reply frame data */
 	u8			 sense[MPT_SENSE_BUFFER_ALLOC];
 	int			 wait_done;	/* wake-up value for this ioc */
@@ -428,8 +427,6 @@ typedef struct _MPT_IOCTL {
 	u8			 status;	/* current command status */
 	u8			 reset;		/* 1 if bus reset allowed */
 	u8			 target;	/* target for reset */
-	void 			*tmPtr;
-	struct timer_list	 TMtimer;	/* timer function for this adapter */
 	struct semaphore	 sem_ioc;
 } MPT_IOCTL;
 
@@ -882,11 +879,9 @@ typedef struct _MPT_SCSI_HOST {
 	int			  port;
 	u32			  pad0;
 	struct scsi_cmnd	**ScsiLookup;
-	u32			  qtag_tick;
 	VirtDevice		**Targets;
 	MPT_LOCAL_REPLY		 *pLocal;		/* used for internal commands */
 	struct timer_list	  timer;
-	struct timer_list	  TMtimer;		/* Timer for TM commands ONLY */
 		/* Pool of memory for holding SCpnts before doing
 		 * OS callbacks. freeQ is the free pool.
 		 */
@@ -896,7 +891,6 @@ typedef struct _MPT_SCSI_HOST {
 	u8			  pad1;
 	u8                        tmState;
 	u8			  rsvd[2];
-	MPT_FRAME_HDR		 *tmPtr;		/* Ptr to TM request*/
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
 	MPT_LOCAL_REPLY		  localReply;		/* internal cmd reply struct */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -81,6 +81,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/delay.h>	/* for mdelay */
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/compat.h>
@@ -142,6 +143,9 @@ static int mptctl_hp_targetinfo(unsigned
 static int  mptctl_probe(struct pci_dev *, const struct pci_device_id *);
 static void mptctl_remove(struct pci_dev *);
 
+#ifdef CONFIG_COMPAT
+static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg);
+#endif
 /*
  * Private function calls.
  */
@@ -151,7 +155,7 @@ static MptSge_t *kbuf_alloc_2_sgl( int b
 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 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 void mptctl_timeout_expired (MPT_IOCTL *ioctl);
 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);
@@ -184,9 +188,6 @@ static int  mptctl_ioc_reset(MPT_ADAPTER
 
 #define MPT_IOCTL_DEFAULT_TIMEOUT 10	/* Default timeout value (seconds) */
 
-static u32 fwReplyBuffer[16];
-static pMPIDefaultReply_t ReplyMsg = NULL;
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
@@ -204,11 +205,6 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in
 	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 (nonblock) {
 		if (down_trylock(&ioc->ioctl->sem_ioc))
 			rc = -EAGAIN;
@@ -235,131 +231,101 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME
 	u16 iocStatus;
 	u8 cmd;
 
-	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_reply()!\n", ioc->name));
+	dctlprintk(("mptctl_reply()!\n"));
 	if (req)
 		 cmd = req->u.hdr.Function;
 	else
 		return 1;
 
 	if (ioc->ioctl) {
-		/* If timer is not running, then an error occurred.
-		 * A timeout will call the reset routine to reload the messaging
-		 * queues.
-		 * Main callback will free message and reply frames.
-		 */
-		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 (reply==NULL) {
 
-			/* 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) {
-					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
-					del_timer (&ioc->ioctl->timer);
-					ioc->ioctl->timer.expires = jiffies + HZ;
-					add_timer(&ioc->ioctl->timer);
-				}
-			}
-			ioc->ioctl->tmPtr = NULL;
+			dctlprintk(("mptctl_reply() NULL Reply "
+				"Function=%x!\n", cmd));
 
-		} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
-			/* Delete this timer
-			 */
-			del_timer (&ioc->ioctl->timer);
-			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
+			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
 
-			/* Set the overall status byte.  Good if:
-			 * IOC status is good OR if no reply and a SCSI IO request
-			 */
-			if (reply) {
-				/* Copy the reply frame (which much exist
-				 * for non-SCSI I/O) to the IOC structure.
-				 */
-				dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n",
-						ioc->name, reply));
-				memcpy(ioc->ioctl->ReplyFrame, reply,
-					min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
-				ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+			/* We are done, issue wake up
+	 		*/
+			ioc->ioctl->wait_done = 1;
+			wake_up (&mptctl_wait);
+			return 1;
 
-				/* Set the command status to GOOD if IOC Status is GOOD
-				 * OR if SCSI I/O cmd and data underrun or recovered error.
-				 */
-				iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
-				if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
-					ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-
-				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;
-					}
-				}
+		}
 
-				/* Copy the sense data - if present
-				 */
-				if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
-					(reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)){
+		dctlprintk(("mptctl_reply() with req=%p "
+			"reply=%p Function=%x!\n", req, reply, cmd));
 
-					sz = req->u.scsireq.SenseBufferLength;
-					req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
-					sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
-					memcpy(ioc->ioctl->sense, sense_data, sz);
-					ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
-				}
+		/* Copy the reply frame (which much exist
+		 * for non-SCSI I/O) to the IOC structure.
+		 */
+		dctlprintk(("Copying Reply Frame @%p to ioc%d!\n",
+			reply, ioc->id));
+		memcpy(ioc->ioctl->ReplyFrame, reply,
+			min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
+		ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
 
-				if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
-					mptctl_free_tm_flags(ioc);
+		/* Set the command status to GOOD if IOC Status is GOOD
+		 * OR if SCSI I/O cmd and data underrun or recovered error.
+		 */
+		iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+		if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
+			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 
+		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+			(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
 
-			} 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;
+			if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
+			(iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
+			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 			}
+		}
 
-			/* We are done, issue wake up
-			 */
-			ioc->ioctl->wait_done = 1;
-			wake_up (&mptctl_wait);
-		} else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) {
-			/* Two paths to FW DOWNLOAD! */
-			// NOTE: Expects/requires non-Turbo reply!
-			dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n",
-				ioc->name));
-			memcpy(fwReplyBuffer, reply, min_t(int, sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
-			ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+		/* Copy the sense data - if present
+		 */
+		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
+			(reply->u.sreply.SCSIState &
+			 MPI_SCSI_STATE_AUTOSENSE_VALID)){
+			sz = req->u.scsireq.SenseBufferLength;
+			req_index =
+			    le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+			sense_data =
+			    ((u8 *)ioc->sense_buf_pool +
+			     (req_index * MPT_SENSE_BUFFER_ALLOC));
+			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);
+
+		/* We are done, issue wake up
+		 */
+		ioc->ioctl->wait_done = 1;
+		wake_up (&mptctl_wait);
 	}
 	return 1;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timer_expired
+/* mptctl_timeout_expired
  *
- * Call back for timer process. Used only for ioctl functionality.
+ * Expecting an interrupt, however timed out.
  *
  */
-static void mptctl_timer_expired (unsigned long data)
+static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
 {
-	MPT_IOCTL *ioctl = (MPT_IOCTL *) data;
 	int rc = 1;
 
-	dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n",
+	dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n",
 				ioctl->ioc->id));
 	if (ioctl == NULL)
 		return;
 
+	ioctl->wait_done = 0;
 	if (ioctl->reset & MPTCTL_RESET_OK)
 		rc = mptctl_bus_reset(ioctl);
 
@@ -367,6 +333,8 @@ static void mptctl_timer_expired (unsign
 		/* Issue a reset for this device.
 		 * The IOC is not responding.
 		 */
+		dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+			 ioctl->ioc->name));
 		mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
 	}
 	return;
@@ -391,7 +359,7 @@ static int mptctl_bus_reset(MPT_IOCTL *i
 
 	if (ioctl->ioc->sh == NULL)
 		return -EPERM;
-	
+
 	hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
 	if (hd == NULL)
 		return -EPERM;
@@ -431,26 +399,34 @@ static int mptctl_bus_reset(MPT_IOCTL *i
 		pScsiTm->Reserved2[ii] = 0;
 
 	pScsiTm->TaskMsgContext = 0;
-	dtmprintk((MYIOC_s_INFO_FMT "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
+	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,
-			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));
+	DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
 
-		mptctl_free_tm_flags(ioctl->ioc);
-		del_timer(&ioctl->TMtimer);
-		mpt_free_msg_frame(ioctl->ioc, mf);
-		ioctl->tmPtr = NULL;
+	ioctl->wait_done=0;
+	if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
+	     sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
+		dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+			hd->ioc, mf));
+		goto mptctl_bus_reset_done;
 	}
 
+	/* Now wait for the command to complete */
+	ii = wait_event_interruptible_timeout(mptctl_wait,
+	     ioctl->wait_done == 1,
+	     HZ*5 /* 5 second timeout */);
+
+	if(ii <=0 && (ioctl->wait_done != 1 ))  {
+		ioctl->wait_done = 0;
+		retval = -1; /* return failure */
+	}
+
+mptctl_bus_reset_done:
+
+	mpt_free_msg_frame(hd->ioc, mf);
+	mptctl_free_tm_flags(ioctl->ioc);
 	return retval;
 }
 
@@ -491,7 +467,6 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
 	return;
 }
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
  *
@@ -504,43 +479,22 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int r
 {
 	MPT_IOCTL *ioctl = ioc->ioctl;
 	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
-			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-	if (reset_phase == MPT_IOC_SETUP_RESET){
-		;
-	} else if (reset_phase == MPT_IOC_PRE_RESET){
-
-		/* Someone has called the reset handler to
-		 * do a hard reset. No more replies from the FW.
-		 * 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)){
-			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(ioc, ioctl->tmPtr);
-		}
-
-	} else {
-		ioctl->tmPtr = NULL;
+		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
-		/* Set the status and continue IOCTL
-		 * processing. All memory will be free'd
-		 * by originating thread after wake_up is
-		 * called.
-		 */
-		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
-			ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
+	if(ioctl == NULL)
+		return 1;
 
-			/* Wake up the calling process
-			 */
-			ioctl->wait_done = 1;
-			wake_up(&mptctl_wait);
-		}
+	switch(reset_phase) {
+	case MPT_IOC_SETUP_RESET:
+		ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
+		break;
+	case MPT_IOC_POST_RESET:
+		ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
+		break;
+	case MPT_IOC_PRE_RESET:
+	default:
+		break;
 	}
 
 	return 1;
@@ -552,8 +506,8 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int r
  *  cmd - specify the particular IOCTL command to be issued
  *  arg - data specific to the command. Must not be null.
  */
-static int
-mptctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long
+__mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	mpt_ioctl_header __user *uhdr = (void __user *) arg;
 	mpt_ioctl_header	 khdr;
@@ -637,6 +591,16 @@ mptctl_ioctl(struct inode *inode, struct
 	return ret;
 }
 
+static long
+mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long ret;
+	lock_kernel();
+	ret = __mptctl_ioctl(file, cmd, arg);
+	unlock_kernel();
+	return ret;
+}
+
 static int mptctl_do_reset(unsigned long arg)
 {
 	struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
@@ -735,9 +699,9 @@ mptctl_do_fw_download(int ioc, char __us
 	u32			 nib;
 	int			 fw_bytes_copied = 0;
 	int			 i;
-	int			 cntdn;
 	int			 sge_offset = 0;
 	u16			 iocstat;
+	pFWDownloadReply_t	 ReplyMsg = NULL;
 
 	dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
 
@@ -868,31 +832,25 @@ mptctl_do_fw_download(int ioc, char __us
 	/*
 	 * Finally, perform firmware download.
 	 */
-	ReplyMsg = NULL;
+	iocp->ioctl->wait_done = 0;
 	mpt_put_msg_frame(mptctl_id, iocp, mf);
 
-	/*
-	 *  Wait until the reply has been received
-	 */
-	for (cntdn=HZ*60, i=1; ReplyMsg == NULL; cntdn--, i++) {
-		if (!cntdn) {
-			ret = -ETIME;
-			goto fwdl_out;
-		}
-
-		if (!(i%HZ)) {
-			dctlprintk((KERN_INFO "DbG::_do_fwdl: "
-				   "In ReplyMsg loop - iteration %d\n",
-				   i));
-		}
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
+	/* Now wait for the command to complete */
+	ret = wait_event_interruptible_timeout(mptctl_wait,
+	     iocp->ioctl->wait_done == 1,
+	     HZ*60);
+
+	if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
+	/* Now we need to reset the board */
+		mptctl_timeout_expired(iocp->ioctl);
+		ret = -ENODATA;
+		goto fwdl_out;
 	}
 
 	if (sgl)
 		kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
+	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
 	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
 	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
 		printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
@@ -1180,14 +1138,14 @@ mptctl_getiocinfo (unsigned long arg, un
 		cim_rev = 0;	/* obsolete */
 	else
 		return -EFAULT;
-	
+
 	karg = kmalloc(data_size, GFP_KERNEL);
 	if (karg == NULL) {
 		printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
 				__FILE__, __LINE__);
 		return -ENOMEM;
 	}
-		
+
 	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",
@@ -1812,8 +1770,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	int		iocnum, flagsLength;
 	int		sz, rc = 0;
 	int		msgContext;
-	int		tm_flags_set = 0;
 	u16		req_idx;
+	ulong 		timeout;
 
 	dctlprintk(("mptctl_do_mpt_command called.\n"));
 	bufIn.kptr = bufOut.kptr = NULL;
@@ -2029,7 +1987,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 				rc = -EPERM;
 				goto done_free_mem;
 			}
-			tm_flags_set = 1;
 		}
 		break;
 
@@ -2181,136 +2138,108 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 		mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
 	}
 
-	/* The request is complete. Set the timer parameters
-	 * and issue the request.
-	 */
-	if (karg.timeout > 0) {
-		ioc->ioctl->timer.expires = jiffies + HZ*karg.timeout;
-	} else {
-		ioc->ioctl->timer.expires = jiffies + HZ*MPT_IOCTL_DEFAULT_TIMEOUT;
-	}
-
 	ioc->ioctl->wait_done = 0;
-	ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE;
-	add_timer(&ioc->ioctl->timer);
-
 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+
 		DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
-		rc = mpt_send_handshake_request(mptctl_id, ioc,
-				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
-		if (rc == 0) {
-			wait_event(mptctl_wait, ioc->ioctl->wait_done);
-		} else {
+
+		if (mpt_send_handshake_request(mptctl_id, ioc,
+			sizeof(SCSITaskMgmt_t), (u32*)mf,
+			CAN_SLEEP) != 0) {
+			dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+				" (ioc %p, mf %p) \n", ioc->name,
+				ioc, mf));
 			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;
-			mpt_free_msg_frame(ioc, mf);
+			rc = -ENODATA;
+			goto done_free_mem;
 		}
-	} else {
+
+	} else
 		mpt_put_msg_frame(mptctl_id, ioc, mf);
-		wait_event(mptctl_wait, ioc->ioctl->wait_done);
+
+	/* Now wait for the command to complete */
+	timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
+	timeout = wait_event_interruptible_timeout(mptctl_wait,
+	     ioc->ioctl->wait_done == 1,
+	     HZ*timeout);
+
+	if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
+	/* Now we need to reset the board */
+
+		if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+			mptctl_free_tm_flags(ioc);
+
+		mptctl_timeout_expired(ioc->ioctl);
+		rc = -ENODATA;
+		goto done_free_mem;
 	}
 
 	mf = NULL;
 
-	/* MF Cleanup:
-	 * If command failed and failure triggered a diagnostic reset
-	 * OR a diagnostic reset happens during command processing,
-	 * no data, messaging queues are reset (mf cannot be accessed),
-	 * and status is DID_IOCRESET
-	 *
-	 * If a user-requested bus reset fails to be handshaked, then
-	 * mf is returned to free queue and status is TM_FAILED.
-	 *
-	 * Otherise, the command completed and the mf was freed
-	 # by ISR (mf cannot be touched).
+	/* If a valid reply frame, copy to the user.
+	 * Offset 2: reply length in U32's
 	 */
-	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
-		/* The timer callback deleted the
-		 * timer and reset the adapter queues.
-		 */
-		printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
-			"Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__);
-		tm_flags_set= 0;
-		rc = -ETIME;
-	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) {
-		/* User TM request failed! mf has not been freed.
-		 */
-		rc = -ENODATA;
-	} else {
-		/* If a valid reply frame, copy to the user.
-		 * Offset 2: reply length in U32's
-		 */
-		if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
-			if (karg.maxReplyBytes < ioc->reply_sz) {
-				 sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
-			} else {
-				 sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
-			}
-
-			if (sz > 0) {
-				if (copy_to_user(karg.replyFrameBufPtr,
-					 &ioc->ioctl->ReplyFrame, sz)){
-
-					 printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
-					 "Unable to write out reply frame %p\n",
-					 __FILE__, __LINE__, karg.replyFrameBufPtr);
-					 rc =  -ENODATA;
-					 goto done_free_mem;
-				}
-			}
+	if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+		if (karg.maxReplyBytes < ioc->reply_sz) {
+			 sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+		} else {
+			 sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
 		}
 
-		/* If valid sense data, copy to user.
-		 */
-		if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
-			sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
-			if (sz > 0) {
-				if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
-					printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
-					"Unable to write sense data to user %p\n",
-					__FILE__, __LINE__,
-					karg.senseDataPtr);
-					rc =  -ENODATA;
-					goto done_free_mem;
-				}
+		if (sz > 0) {
+			if (copy_to_user(karg.replyFrameBufPtr,
+				 &ioc->ioctl->ReplyFrame, sz)){
+				 printk(KERN_ERR
+				     "%s@%d::mptctl_do_mpt_command - "
+				 "Unable to write out reply frame %p\n",
+				 __FILE__, __LINE__, karg.replyFrameBufPtr);
+				 rc =  -ENODATA;
+				 goto done_free_mem;
 			}
 		}
+	}
 
-		/* If the overall status is _GOOD and data in, copy data
-		 * to user.
-		 */
-		if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
-					(karg.dataInSize > 0) && (bufIn.kptr)) {
-
-			if (copy_to_user(karg.dataInBufPtr,
-					 bufIn.kptr, karg.dataInSize)) {
+	/* If valid sense data, copy to user.
+	 */
+	if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+		sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
+		if (sz > 0) {
+			if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
-					"Unable to write data to user %p\n",
-					__FILE__, __LINE__,
-					karg.dataInBufPtr);
+				"Unable to write sense data to user %p\n",
+				__FILE__, __LINE__,
+				karg.senseDataPtr);
 				rc =  -ENODATA;
+				goto done_free_mem;
 			}
 		}
 	}
 
+	/* If the overall status is _GOOD and data in, copy data
+	 * to user.
+	 */
+	if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+				(karg.dataInSize > 0) && (bufIn.kptr)) {
+
+		if (copy_to_user(karg.dataInBufPtr,
+				 bufIn.kptr, karg.dataInSize)) {
+			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+				"Unable to write data to user %p\n",
+				__FILE__, __LINE__,
+				karg.dataInBufPtr);
+			rc =  -ENODATA;
+		}
+	}
+
 done_free_mem:
-	/* Clear all status bits except TMTIMER_ACTIVE, this bit is cleared
-	 * upon completion of the TM command.
-	 * ioc->ioctl->status = 0;
-	 */
-	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_TIMER_ACTIVE | MPT_IOCTL_STATUS_TM_FAILED |
-			MPT_IOCTL_STATUS_COMMAND_GOOD | MPT_IOCTL_STATUS_SENSE_VALID |
-			MPT_IOCTL_STATUS_RF_VALID | MPT_IOCTL_STATUS_DID_IOCRESET);
 
-	if (tm_flags_set)
-		mptctl_free_tm_flags(ioc);
+	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
+		MPT_IOCTL_STATUS_SENSE_VALID |
+		MPT_IOCTL_STATUS_RF_VALID );
 
 	/* Free the allocated memory.
 	 */
-	 if (bufOut.kptr != NULL) {
+	if (bufOut.kptr != NULL) {
 		pci_free_consistent(ioc->pcidev,
 			bufOut.len, (void *) bufOut.kptr, dma_addr_out);
 	}
@@ -2549,7 +2478,7 @@ mptctl_hp_targetinfo(unsigned long arg)
 				__FILE__, __LINE__, uarg);
 		return -EFAULT;
 	}
-	
+
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 		(ioc == NULL)) {
 		dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
@@ -2567,7 +2496,7 @@ mptctl_hp_targetinfo(unsigned long arg)
 
 	if (ioc->sh->host_no != karg.hdr.host)
 		return -ENODEV;
-		
+
        /* Get the data transfer speeds
         */
 	data_sz = ioc->spi_data.sdp0length * 4;
@@ -2669,7 +2598,10 @@ mptctl_hp_targetinfo(unsigned long arg)
 static struct file_operations mptctl_fops = {
 	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
-	.ioctl =	mptctl_ioctl,
+	.unlocked_ioctl = mptctl_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = compat_mpctl_ioctl,
+#endif
 };
 
 static struct miscdevice mptctl_miscdev = {
@@ -2684,29 +2616,9 @@ static struct miscdevice mptctl_miscdev 
 
 #include <linux/ioctl32.h>
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* compat_XXX functions are used to provide a conversion between
- * pointers and u32's. If the arg does not contain any pointers, then
- * a specialized function (compat_XXX) is not needed. If the arg
- * does contain pointer(s), then the specialized function is used
- * to ensure the structure contents is properly processed by mptctl.
- */
 static int
-compat_mptctl_ioctl(unsigned int fd, unsigned int cmd,
-			unsigned long arg, struct file *filp)
-{
-	int ret;
-
-	lock_kernel();
-	dctlprintk((KERN_INFO MYNAM "::compat_mptctl_ioctl() called\n"));
-	ret = mptctl_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-	unlock_kernel();
-	return ret;
-}
- 
-static int
-compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
-			unsigned long arg, struct file *filp)
+compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
+			unsigned long arg)
 {
 	struct mpt_fw_xfer32 kfw32;
 	struct mpt_fw_xfer kfw;
@@ -2744,8 +2656,8 @@ compat_mptfwxfer_ioctl(unsigned int fd, 
 }
 
 static int
-compat_mpt_command(unsigned int fd, unsigned int cmd,
-			unsigned long arg, struct file *filp)
+compat_mpt_command(struct file *filp, unsigned int cmd,
+			unsigned long arg)
 {
 	struct mpt_ioctl_command32 karg32;
 	struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
@@ -2797,6 +2709,38 @@ compat_mpt_command(unsigned int fd, unsi
 	return ret;
 }
 
+static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	long ret;
+	lock_kernel();
+	switch (cmd) {
+	case MPTIOCINFO:
+	case MPTIOCINFO1:
+	case MPTIOCINFO2:
+	case MPTTARGETINFO:
+	case MPTEVENTQUERY:
+	case MPTEVENTENABLE:
+	case MPTEVENTREPORT:
+	case MPTHARDRESET:
+	case HP_GETHOSTINFO:
+	case HP_GETTARGETINFO:
+	case MPTTEST:
+		ret = __mptctl_ioctl(f, cmd, arg);
+		break;
+	case MPTCOMMAND32:
+		ret = compat_mpt_command(f, cmd, arg);
+		break;
+	case MPTFWDOWNLOAD32:
+		ret = compat_mptfwxfer_ioctl(f, cmd, arg);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	unlock_kernel();
+	return ret;
+}
+
 #endif
 
 
@@ -2830,12 +2774,6 @@ mptctl_probe(struct pci_dev *pdev, const
 	memset(mem, 0, sz);
 	ioc->ioctl = (MPT_IOCTL *) mem;
 	ioc->ioctl->ioc = ioc;
-	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;
 	sema_init(&ioc->ioctl->sem_ioc, 1);
 	return 0;
 
@@ -2879,36 +2817,6 @@ static int __init mptctl_init(void)
 		": failed to register dd callbacks\n"));
 	}
 
-#ifdef CONFIG_COMPAT
-	err = register_ioctl32_conversion(MPTIOCINFO, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTIOCINFO1, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTIOCINFO2, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTARGETINFO, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTEST, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTQUERY, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTENABLE, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTREPORT, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTHARDRESET, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTCOMMAND32, compat_mpt_command);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
-					  compat_mptfwxfer_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETHOSTINFO, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETTARGETINFO, compat_mptctl_ioctl);
-	if (++where && err) goto out_fail;
-#endif
-
 	/* Register this device */
 	err = misc_register(&mptctl_miscdev);
 	if (err < 0) {
@@ -2940,24 +2848,6 @@ static int __init mptctl_init(void)
 
 out_fail:
 
-#ifdef CONFIG_COMPAT
-	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
-			" (%d:err=%d)\n", where, err);
-	unregister_ioctl32_conversion(MPTIOCINFO);
-	unregister_ioctl32_conversion(MPTIOCINFO1);
-	unregister_ioctl32_conversion(MPTIOCINFO2);
-	unregister_ioctl32_conversion(MPTTARGETINFO);
-	unregister_ioctl32_conversion(MPTTEST);
-	unregister_ioctl32_conversion(MPTEVENTQUERY);
-	unregister_ioctl32_conversion(MPTEVENTENABLE);
-	unregister_ioctl32_conversion(MPTEVENTREPORT);
-	unregister_ioctl32_conversion(MPTHARDRESET);
-	unregister_ioctl32_conversion(MPTCOMMAND32);
-	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
-	unregister_ioctl32_conversion(HP_GETHOSTINFO);
-	unregister_ioctl32_conversion(HP_GETTARGETINFO);
-#endif
-
 	mpt_device_driver_deregister(MPTCTL_DRIVER);
 
 	return err;
@@ -2980,22 +2870,6 @@ static void mptctl_exit(void)
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 
-#ifdef CONFIG_COMPAT
-	unregister_ioctl32_conversion(MPTIOCINFO);
-	unregister_ioctl32_conversion(MPTIOCINFO1);
-	unregister_ioctl32_conversion(MPTIOCINFO2);
-	unregister_ioctl32_conversion(MPTTARGETINFO);
-	unregister_ioctl32_conversion(MPTTEST);
-	unregister_ioctl32_conversion(MPTEVENTQUERY);
-	unregister_ioctl32_conversion(MPTEVENTENABLE);
-	unregister_ioctl32_conversion(MPTEVENTREPORT);
-	unregister_ioctl32_conversion(MPTHARDRESET);
-	unregister_ioctl32_conversion(MPTCOMMAND32);
-	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
-	unregister_ioctl32_conversion(HP_GETHOSTINFO);
-	unregister_ioctl32_conversion(HP_GETTARGETINFO);
-#endif
-
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -96,23 +96,26 @@ MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
-#ifdef MODULE
-static int dv = MPTSCSIH_DOMAIN_VALIDATION;
-module_param(dv, int, 0);
-MODULE_PARM_DESC(dv, "DV Algorithm: enhanced = 1, basic = 0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)");
-
-static int width = MPTSCSIH_MAX_WIDTH;
-module_param(width, int, 0);
-MODULE_PARM_DESC(width, "Max Bus Width: wide = 1, narrow = 0 (default=MPTSCSIH_MAX_WIDTH=1)");
-
-static ushort factor = MPTSCSIH_MIN_SYNC;
-module_param(factor, ushort, 0);
-MODULE_PARM_DESC(factor, "Min Sync Factor: (default=MPTSCSIH_MIN_SYNC=0x08)");
-
-static int saf_te = MPTSCSIH_SAF_TE;
-module_param(saf_te, int, 0);
-MODULE_PARM_DESC(saf_te, "Force enabling SEP Processor: (default=MPTSCSIH_SAF_TE=0)");
-#endif
+/* Command line args */
+static int mpt_dv = MPTSCSIH_DOMAIN_VALIDATION;
+MODULE_PARM(mpt_dv, "i");
+MODULE_PARM_DESC(mpt_dv, " DV Algorithm: enhanced=1, basic=0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)");
+
+static int mpt_width = MPTSCSIH_MAX_WIDTH;
+MODULE_PARM(mpt_width, "i");
+MODULE_PARM_DESC(mpt_width, " Max Bus Width: wide=1, narrow=0 (default=MPTSCSIH_MAX_WIDTH=1)");
+
+static int mpt_factor = MPTSCSIH_MIN_SYNC;
+MODULE_PARM(mpt_factor, "h");
+MODULE_PARM_DESC(mpt_factor, " Min Sync Factor (default=MPTSCSIH_MIN_SYNC=0x08)");
+
+static int mpt_saf_te = MPTSCSIH_SAF_TE;
+MODULE_PARM(mpt_saf_te, "i");
+MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1  (default=MPTSCSIH_SAF_TE=0)");
+
+static int mpt_pq_filter = 0;
+MODULE_PARM(mpt_pq_filter, "i");
+MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -179,10 +182,11 @@ static int	mptscsih_AddSGE(MPT_ADAPTER *
 static void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void	copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 static int	mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
+static int	mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
 static u32	SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
 
-static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
-static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
+static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
+static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
 
 static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
@@ -196,13 +200,9 @@ static int	mptscsih_writeSDP1(MPT_SCSI_H
 static int	mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
 static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void	mptscsih_timer_expired(unsigned long data);
-static void	mptscsih_taskmgmt_timeout(unsigned long data);
-static void	mptscsih_schedule_reset(void *hd);
 static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static int	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
 
-static struct work_struct   mptscsih_rstTask;
-
 #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void	mptscsih_domainValidation(void *hd);
@@ -220,7 +220,7 @@ static int  mptscsih_probe (struct pci_d
 static void mptscsih_remove(struct pci_dev *);
 static void mptscsih_shutdown(struct device *);
 #ifdef CONFIG_PM
-static int mptscsih_suspend(struct pci_dev *pdev, u32 state);
+static int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
 static int mptscsih_resume(struct pci_dev *pdev);
 #endif
 
@@ -256,7 +256,6 @@ static int scandv_wait_done = 1;
 
 /* Driver command line structure
  */
-static struct mptscsih_driver_setup driver_setup;
 static struct scsi_host_template driver_template;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1207,7 +1206,6 @@ mptscsih_probe(struct pci_dev *pdev, con
 	hd->tmState = TM_STATE_NONE;
 	hd->resetPending = 0;
 	hd->abortSCpnt = NULL;
-	hd->tmPtr = NULL;
 
 	/* Clear the pointer used to store
 	 * single-threaded commands, i.e., those
@@ -1224,41 +1222,27 @@ mptscsih_probe(struct pci_dev *pdev, con
 	hd->timer.data = (unsigned long) hd;
 	hd->timer.function = mptscsih_timer_expired;
 
-	init_timer(&hd->TMtimer);
-	hd->TMtimer.data = (unsigned long) hd;
-	hd->TMtimer.function = mptscsih_taskmgmt_timeout;
-	hd->qtag_tick = jiffies;
-
-	/* Moved Earlier Pam D */
-	/* ioc->sh = sh;	*/
-
 	if (ioc->bus_type == SCSI) {
 		/* Update with the driver setup
 		 * values.
 		 */
-		if (ioc->spi_data.maxBusWidth >
-		  driver_setup.max_width) {
-			ioc->spi_data.maxBusWidth =
-			  driver_setup.max_width;
-		}
-
-		if (ioc->spi_data.minSyncFactor <
-		  driver_setup.min_sync_factor) {
-			ioc->spi_data.minSyncFactor =
-			  driver_setup.min_sync_factor;
-		}
+		if (ioc->spi_data.maxBusWidth > mpt_width)
+			ioc->spi_data.maxBusWidth = mpt_width;
+		if (ioc->spi_data.minSyncFactor < mpt_factor)
+			ioc->spi_data.minSyncFactor = mpt_factor;
 
 		if (ioc->spi_data.minSyncFactor == MPT_ASYNC) {
 			ioc->spi_data.maxSyncOffset = 0;
 		}
 
-		ioc->spi_data.Saf_Te = driver_setup.saf_te;
+		ioc->spi_data.Saf_Te = mpt_saf_te;
 
 		hd->negoNvram = 0;
 #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
 		hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 #endif
 		ioc->spi_data.forceDv = 0;
+		ioc->spi_data.noQas = 0;
 		for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
 			ioc->spi_data.dvStatus[ii] =
 			  MPT_SCSICFG_NEGOTIATE;
@@ -1268,12 +1252,12 @@ mptscsih_probe(struct pci_dev *pdev, con
 			ioc->spi_data.dvStatus[ii] |=
 			  MPT_SCSICFG_DV_NOT_DONE;
 
-		ddvprintk((MYIOC_s_INFO_FMT
+		dinitprintk((MYIOC_s_INFO_FMT
 			"dv %x width %x factor %x saf_te %x\n",
-			ioc->name, driver_setup.dv,
-			driver_setup.max_width,
-			driver_setup.min_sync_factor,
-			driver_setup.saf_te));
+			ioc->name, mpt_dv,
+			mpt_width,
+			mpt_factor,
+			mpt_saf_te));
 	}
 
 	mpt_scsi_hosts++;
@@ -1405,7 +1389,7 @@ mptscsih_shutdown(struct device * dev)
  *
  */
 static int
-mptscsih_suspend(struct pci_dev *pdev, u32 state)
+mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	mptscsih_shutdown(&pdev->dev);
 	return 0;
@@ -1489,18 +1473,6 @@ mptscsih_init(void)
 		  ": Registered for IOC reset notifications\n"));
 	}
 
-#ifdef MODULE
-	dinitprintk((KERN_INFO MYNAM
-		": Command Line Args: dv=%d max_width=%d "
-		"factor=0x%x saf_te=%d\n",
-		dv, width, factor, saf_te));
-
-	driver_setup.dv = (dv) ? 1 : 0;
-	driver_setup.max_width = (width) ? 1 : 0;
-	driver_setup.min_sync_factor = factor;
-	driver_setup.saf_te = (saf_te) ? 1 : 0;;
-#endif
-
 	if(mpt_device_driver_register(&mptscsih_driver,
 	  MPTSCSIH_DRIVER) != 0 ) {
 		dprintk((KERN_INFO MYNAM
@@ -1925,7 +1897,6 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i
  *	@target: Logical Target ID for reset (if appropriate)
  *	@lun: Logical Unit for reset (if appropriate)
  *	@ctx2abort: Context for the task to be aborted (if appropriate)
- *	@sleepFlag: If set, use udelay instead of schedule in handshake code.
  *
  *	Remark: Currently invoked from a non-interrupt thread (_bh).
  *
@@ -1935,7 +1906,7 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i
  *	Returns 0 for SUCCESS or -1 if FAILED.
  */
 static int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
 {
 	MPT_ADAPTER	*ioc;
 	int		 rc = -1;
@@ -2015,7 +1986,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 		 */
 		if (hd->hard_resets < -1)
 			hd->hard_resets++;
-		rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout, sleepFlag);
+		rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
 		if (rc) {
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
 		} else {
@@ -2029,7 +2000,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 		ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
 		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
 			 hd->ioc->name));
-		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
+		rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
 	}
 
 	dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
@@ -2046,7 +2017,6 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
  *	@target: Logical Target ID for reset (if appropriate)
  *	@lun: Logical Unit for reset (if appropriate)
  *	@ctx2abort: Context for the task to be aborted (if appropriate)
- *	@sleepFlag: If set, use udelay instead of schedule in handshake code.
  *
  *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
  *	or a non-interrupt thread.  In the former, must not call schedule().
@@ -2057,7 +2027,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
  *	else other non-zero value returned.
  */
 static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
@@ -2087,7 +2057,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd
 	pScsiTm->TaskType = type;
 	pScsiTm->Reserved1 = 0;
 	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
-	                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
 
 	for (ii= 0; ii < 8; ii++) {
 		pScsiTm->LUN[ii] = 0;
@@ -2099,29 +2069,32 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd
 
 	pScsiTm->TaskMsgContext = ctx2abort;
 
-	/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-		mpt_put_msg_frame(hd->ioc->id, mf);
-	* Save the MF pointer in case the request times out.
-	*/
-	hd->tmPtr = mf;
-	hd->TMtimer.expires = jiffies + timeout;
-	add_timer(&hd->TMtimer);
-
-	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
-			hd->ioc->name, ctx2abort, type));
+	dtmprintk((MYIOC_s_INFO_FMT
+		"IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
+		hd->ioc->name, ctx2abort, type));
 
 	DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
 
 	if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc,
-				sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag))
-	!= 0) {
+		sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
+		CAN_SLEEP)) != 0) {
 		dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf));
-		hd->tmPtr = NULL;
-		del_timer(&hd->TMtimer);
+			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+			hd->ioc, mf));
 		mpt_free_msg_frame(hd->ioc, mf);
+		return retval;
 	}
-	
+
+	if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
+		dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
+			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+			hd->ioc, mf));
+		mpt_free_msg_frame(hd->ioc, mf);
+		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+			 hd->ioc->name));
+		retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
+	}
+
 	return retval;
 }
 
@@ -2187,13 +2160,13 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 	 */
 	mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
-	
+
 	hd->abortSCpnt = SCpnt;
 
 	spin_unlock_irq(host_lock);
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
 		SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
-		ctx2abort, (HZ*2) /* 2 second timeout */,CAN_SLEEP)
+		ctx2abort, 2 /* 2 second timeout */)
 		< 0) {
 
 		/* The TM request failed and the subsequent FW-reload failed!
@@ -2206,7 +2179,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 		 */
 		hd->tmPending = 0;
 		hd->tmState = TM_STATE_NONE;
-		
+
 		spin_lock_irq(host_lock);
 
 		/* Unmap the DMA buffers, if any. */
@@ -2226,7 +2199,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 	}
 	spin_lock_irq(host_lock);
 	return SUCCESS;
-
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2259,15 +2231,10 @@ mptscsih_dev_reset(struct scsi_cmnd * SC
 	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
 	       hd->ioc->name, SCpnt);
 
-	/* Supported for FC only.
-	 */
-	if (hd->ioc->bus_type == SCSI) 
-		return FAILED;
-
 	spin_unlock_irq(host_lock);
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
 		SCpnt->device->channel, SCpnt->device->id,
-		0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
+		0, 0, 5 /* 5 second timeout */)
 		< 0){
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
@@ -2317,7 +2284,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SC
 	/* We are now ready to execute the task management request. */
 	spin_unlock_irq(host_lock);
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-		SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
+		SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */)
 	    < 0){
 
 		/* The TM request failed and the subsequent FW-reload failed!
@@ -2398,7 +2365,7 @@ static int
 mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
 {
 	unsigned long  flags;
-	int            loop_count = 10 * 4;  /* Wait 10 seconds */
+	int            loop_count = 4 * 10;  /* Wait 10 seconds */
 	int            status = FAILED;
 
 	do {
@@ -2406,8 +2373,8 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST *
 		if (hd->tmState == TM_STATE_NONE) {
 			hd->tmState = TM_STATE_IN_PROGRESS;
 			hd->tmPending = 1;
-			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 			status = SUCCESS;
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 			break;
 		}
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
@@ -2419,6 +2386,34 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST *
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
+ *	mptscsih_tm_wait_for_completion - wait for completion of TM task
+ *	@hd: Pointer to MPT host structure.
+ *
+ *	Returns {SUCCESS,FAILED}.
+ */
+static int
+mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
+{
+	unsigned long  flags;
+	int            loop_count = 4 * timeout;
+	int            status = FAILED;
+
+	do {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		if(hd->tmPending == 0) {
+			status = SUCCESS;
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		msleep_interruptible(250);
+	} while (--loop_count);
+
+	return status;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
  *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@mf: Pointer to SCSI task mgmt request frame
@@ -2449,9 +2444,6 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *
 		 * Decrement count of outstanding TM requests.
 		 */
 		hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
-		if (hd->tmPtr) {
-			del_timer(&hd->TMtimer);
-		}
 	} else {
 		dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
 			ioc->name));
@@ -2505,7 +2497,6 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *
 		}
 	}
 
-	hd->tmPtr = NULL;
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 	hd->tmPending = 0;
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -2913,14 +2904,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 			mpt_free_msg_frame(ioc, hd->cmdPtr);
 		}
 
-		/* 2d. If a task management has not completed,
-		 * free resources associated with this request.
-		 */
-		if (hd->tmPtr) {
-			del_timer(&hd->TMtimer);
-			mpt_free_msg_frame(ioc, hd->tmPtr);
-		}
-
 		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
 
 	} else {
@@ -2942,12 +2925,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 		/* 2. Chain Buffer initialization
 		 */
 
-		/* 3. tmPtr clear
-		 */
-		if (hd->tmPtr) {
-			hd->tmPtr = NULL;
-		}
-
 		/* 4. Renegotiate to all devices, if SCSI
 		 */
 		if (ioc->bus_type == SCSI) {
@@ -3172,6 +3149,18 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, i
 	dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
 			hd->ioc->name, bus_id, target_id, lun, hd));
 
+	/*
+	 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
+	 * (i.e. The targer is capable of supporting the specified peripheral device type
+	 * on this logical unit; however, the physical device is not currently connected
+	 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not 
+	 * capable of supporting a physical device on this logical unit). This is to work
+	 * around a bug in th emid-layer in some distributions in which the mid-layer will
+	 * continue to try to communicate to the LUN and evntually create a dummy LUN.
+	*/
+	if (mpt_pq_filter && dlen && (data[0] & 0xE0))
+		data[0] |= 0x40;
+	
 	/* Is LUN supported? If so, upper 2 bits will be 0
 	* in first byte of inquiry data.
 	*/
@@ -3811,60 +3800,6 @@ mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*	mptscsih_taskmgmt_timeout - Call back for timeout on a
- *	task management request.
- *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- *
- */
-static void mptscsih_taskmgmt_timeout(unsigned long data)
-{
-	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
-
-	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);
-
-	/* Call the reset handler. Already had a TM request
-	 * timeout - so issue a diagnostic reset
-	 */
-	INIT_WORK(&mptscsih_rstTask, mptscsih_schedule_reset, (void *)hd);
-	schedule_work(&mptscsih_rstTask);
-	return;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*	mptscsih_schedule_reset - Call back for timeout on a
- *	task management request.
- *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- *
- */
-static void
-mptscsih_schedule_reset(void *arg)
-{
-        MPT_SCSI_HOST           *hd;
-        hd = (MPT_SCSI_HOST *) arg;
-
-	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
-		printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
-	} else {
-		/* Because we have reset the IOC, no TM requests can be
-		 * pending.  So let's make sure the tmPending flag is reset.
-		 */
-		dtmprintk((KERN_WARNING MYNAM
-			   ": %s: mptscsih_taskmgmt_timeout\n",
-			   hd->ioc->name));
-		hd->tmPending = 0;
-	}
-
-	return;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Bus Scan and Domain Validation functionality ...
  */
@@ -5222,7 +5157,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus
 	}
 	ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
 
-	if (driver_setup.dv == 0)
+	if (mpt_dv == 0)
 		goto target_done;
 
 	inq0 = (*pbuf1) & 0x1F;
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -91,12 +91,4 @@
 #define MPTSCSIH_MIN_SYNC               0x08
 #define MPTSCSIH_SAF_TE                 0
 
-struct mptscsih_driver_setup
-{
-        u8      dv;
-        u8      max_width;
-        u8      min_sync_factor;
-        u8      saf_te;
-};
-
 #endif
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -573,6 +573,7 @@ static int i2o_block_reply(struct i2o_co
 static void i2o_block_event(struct i2o_event *evt)
 {
 	osm_info("block-osm: event received\n");
+	kfree(evt);
 };
 
 /*
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -54,6 +54,9 @@
 
 extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
 
+static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
+			 unsigned long arg);
+
 static spinlock_t i2o_config_lock;
 
 #define MODINC(x,y) ((x) = ((x) + 1) % (y))
@@ -538,8 +541,7 @@ static int i2o_cfg_evt_get(unsigned long
 }
 
 #ifdef CONFIG_COMPAT
-static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
-			      struct file *file)
+static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long arg)
 {
 	struct i2o_cmd_passthru32 __user *cmd;
 	struct i2o_controller *c;
@@ -752,7 +754,26 @@ static int i2o_cfg_passthru32(unsigned f
 	return rcode;
 }
 
-#else
+static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	int ret;
+	lock_kernel();		
+	switch (cmd) { 
+	case I2OGETIOPS:
+		ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
+		break;
+	case I2OPASSTHRU32:
+		ret = i2o_cfg_passthru32(file, cmd, arg);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	unlock_kernel();
+	return ret;
+}
+
+#endif
 
 static int i2o_cfg_passthru(unsigned long arg)
 {
@@ -958,7 +979,6 @@ static int i2o_cfg_passthru(unsigned lon
 	kfree(reply);
 	return rcode;
 }
-#endif
 
 /*
  * IOCTL Handler
@@ -1013,11 +1033,9 @@ static int i2o_cfg_ioctl(struct inode *i
 		ret = i2o_cfg_evt_get(arg, fp);
 		break;
 
-#ifndef CONFIG_COMPAT
 	case I2OPASSTHRU:
 		ret = i2o_cfg_passthru(arg);
 		break;
-#endif
 
 	default:
 		osm_debug("unknown ioctl called!\n");
@@ -1105,6 +1123,9 @@ static struct file_operations config_fop
 	.owner = THIS_MODULE,
 	.llseek = no_llseek,
 	.ioctl = i2o_cfg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = i2o_cfg_compat_ioctl,
+#endif
 	.open = cfg_open,
 	.release = cfg_release,
 	.fasync = cfg_fasync,
@@ -1134,19 +1155,11 @@ static int __init i2o_config_init(void)
 		misc_deregister(&i2o_miscdev);
 		return -EBUSY;
 	}
-#ifdef CONFIG_COMPAT
-	register_ioctl32_conversion(I2OPASSTHRU32, i2o_cfg_passthru32);
-	register_ioctl32_conversion(I2OGETIOPS, (void *)sys_ioctl);
-#endif
 	return 0;
 }
 
 static void i2o_config_exit(void)
 {
-#ifdef CONFIG_COMPAT
-	unregister_ioctl32_conversion(I2OPASSTHRU32);
-	unregister_ioctl32_conversion(I2OGETIOPS);
-#endif
 	misc_deregister(&i2o_miscdev);
 	i2o_driver_unregister(&i2o_config_driver);
 }
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -525,3 +525,4 @@ void __exit i2o_pci_exit(void)
 };
 
 EXPORT_SYMBOL(i2o_dma_realloc);
+MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,3 +4,4 @@
 obj- := misc.o	# Dummy rule to force built-in.o to be made
 
 obj-$(CONFIG_IBM_ASM)	+= ibmasm/
+obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
diff --git a/drivers/misc/hdpuftrs/Makefile b/drivers/misc/hdpuftrs/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/misc/hdpuftrs/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HDPU_FEATURES) := hdpu_cpustate.o hdpu_nexus.o
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
new file mode 100644
--- /dev/null
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -0,0 +1,234 @@
+/*
+ *	Sky CPU State Driver
+ *
+ *	Copyright (C) 2002 Brian Waite
+ *
+ *	This driver allows use of the CPU state bits
+ *	It exports the /dev/sky_cpustate and also
+ *	/proc/sky_cpustate 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.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <asm/uaccess.h>
+#include <linux/hdpu_features.h>
+
+#define SKY_CPUSTATE_VERSION		"1.1"
+
+static int hdpu_cpustate_probe(struct device *ddev);
+static int hdpu_cpustate_remove(struct device *ddev);
+
+struct cpustate_t cpustate;
+
+static int cpustate_get_ref(int excl)
+{
+
+	int retval = -EBUSY;
+
+	spin_lock(&cpustate.lock);
+
+	if (cpustate.excl)
+		goto out_busy;
+
+	if (excl) {
+		if (cpustate.open_count)
+			goto out_busy;
+		cpustate.excl = 1;
+	}
+
+	cpustate.open_count++;
+	retval = 0;
+
+      out_busy:
+	spin_unlock(&cpustate.lock);
+	return retval;
+}
+
+static int cpustate_free_ref(void)
+{
+
+	spin_lock(&cpustate.lock);
+
+	cpustate.excl = 0;
+	cpustate.open_count--;
+
+	spin_unlock(&cpustate.lock);
+	return 0;
+}
+
+unsigned char cpustate_get_state(void)
+{
+
+	return cpustate.cached_val;
+}
+
+void cpustate_set_state(unsigned char new_state)
+{
+	unsigned int state = (new_state << 21);
+
+#ifdef DEBUG_CPUSTATE
+	printk("CPUSTATE -> 0x%x\n", new_state);
+#endif
+	spin_lock(&cpustate.lock);
+	cpustate.cached_val = new_state;
+	writel((0xff << 21), cpustate.clr_addr);
+	writel(state, cpustate.set_addr);
+	spin_unlock(&cpustate.lock);
+}
+
+/*
+ *	Now all the various file operations that we export.
+ */
+
+static ssize_t cpustate_read(struct file *file, char *buf,
+			     size_t count, loff_t * ppos)
+{
+	unsigned char data;
+
+	if (count < 0)
+		return -EFAULT;
+	if (count == 0)
+		return 0;
+
+	data = cpustate_get_state();
+	if (copy_to_user(buf, &data, sizeof(unsigned char)))
+		return -EFAULT;
+	return sizeof(unsigned char);
+}
+
+static ssize_t cpustate_write(struct file *file, const char *buf,
+			      size_t count, loff_t * ppos)
+{
+	unsigned char data;
+
+	if (count < 0)
+		return -EFAULT;
+
+	if (count == 0)
+		return 0;
+
+	if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char)))
+		return -EFAULT;
+
+	cpustate_set_state(data);
+	return sizeof(unsigned char);
+}
+
+static int cpustate_open(struct inode *inode, struct file *file)
+{
+	return cpustate_get_ref((file->f_flags & O_EXCL));
+}
+
+static int cpustate_release(struct inode *inode, struct file *file)
+{
+	return cpustate_free_ref();
+}
+
+/*
+ *	Info exported via "/proc/sky_cpustate".
+ */
+static int cpustate_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	char *p = page;
+	int len = 0;
+
+	p += sprintf(p, "CPU State: %04x\n", cpustate_get_state());
+	len = p - 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 struct device_driver hdpu_cpustate_driver = {
+	.name = HDPU_CPUSTATE_NAME,
+	.bus = &platform_bus_type,
+	.probe = hdpu_cpustate_probe,
+	.remove = hdpu_cpustate_remove,
+};
+
+/*
+ *	The various file operations we support.
+ */
+static struct file_operations cpustate_fops = {
+      owner:THIS_MODULE,
+      open:cpustate_open,
+      release:cpustate_release,
+      read:cpustate_read,
+      write:cpustate_write,
+      fasync:NULL,
+      poll:NULL,
+      ioctl:NULL,
+      llseek:no_llseek,
+
+};
+
+static struct miscdevice cpustate_dev = {
+	MISC_DYNAMIC_MINOR,
+	"sky_cpustate",
+	&cpustate_fops
+};
+
+static int hdpu_cpustate_probe(struct device *ddev)
+{
+	struct platform_device *pdev = to_platform_device(ddev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cpustate.set_addr = (unsigned long *)res->start;
+	cpustate.clr_addr = (unsigned long *)res->end - 1;
+
+	misc_register(&cpustate_dev);
+	create_proc_read_entry("sky_cpustate", 0, 0, cpustate_read_proc, NULL);
+
+	printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
+	return 0;
+}
+static int hdpu_cpustate_remove(struct device *ddev)
+{
+
+	cpustate.set_addr = 0;
+	cpustate.clr_addr = 0;
+
+	remove_proc_entry("sky_cpustate", NULL);
+	misc_deregister(&cpustate_dev);
+	return 0;
+
+}
+
+static int __init cpustate_init(void)
+{
+	int rc;
+	rc = driver_register(&hdpu_cpustate_driver);
+	return rc;
+}
+
+static void __exit cpustate_exit(void)
+{
+	driver_unregister(&hdpu_cpustate_driver);
+}
+
+module_init(cpustate_init);
+module_exit(cpustate_exit);
+
+MODULE_AUTHOR("Brian Waite");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
new file mode 100644
--- /dev/null
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -0,0 +1,111 @@
+/*
+ *	Sky Nexus Register Driver
+ *
+ *	Copyright (C) 2002 Brian Waite
+ *
+ *	This driver allows reading the Nexus register
+ *	It exports the /proc/sky_chassis_id and also
+ *	/proc/sky_slot_id 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.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/hdpu_features.h>
+#include <linux/pci.h>
+
+#include <linux/device.h>
+
+static int hdpu_nexus_probe(struct device *ddev);
+static int hdpu_nexus_remove(struct device *ddev);
+
+static struct proc_dir_entry *hdpu_slot_id;
+static struct proc_dir_entry *hdpu_chassis_id;
+static int slot_id = -1;
+static int chassis_id = -1;
+
+static struct device_driver hdpu_nexus_driver = {
+	.name = HDPU_NEXUS_NAME,
+	.bus = &platform_bus_type,
+	.probe = hdpu_nexus_probe,
+	.remove = hdpu_nexus_remove,
+};
+
+int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
+		      int buffer_length, int *zero, void *ptr)
+{
+
+	if (offset > 0)
+		return 0;
+	return sprintf(buffer, "%d\n", slot_id);
+}
+
+int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset,
+			 int buffer_length, int *zero, void *ptr)
+{
+
+	if (offset > 0)
+		return 0;
+	return sprintf(buffer, "%d\n", chassis_id);
+}
+
+static int hdpu_nexus_probe(struct device *ddev)
+{
+	struct platform_device *pdev = to_platform_device(ddev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	int *nexus_id_addr;
+	nexus_id_addr =
+	    ioremap(res->start, (unsigned long)(res->end - res->start));
+	if (nexus_id_addr) {
+		slot_id = (*nexus_id_addr >> 8) & 0x1f;
+		chassis_id = *nexus_id_addr & 0xff;
+		iounmap(nexus_id_addr);
+	} else
+		printk("Could not map slot id\n");
+	hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
+	hdpu_slot_id->read_proc = hdpu_slot_id_read;
+	hdpu_slot_id->nlink = 1;
+
+	hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
+	hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
+	hdpu_chassis_id->nlink = 1;
+	return 0;
+}
+
+static int hdpu_nexus_remove(struct device *ddev)
+{
+	slot_id = -1;
+	chassis_id = -1;
+	remove_proc_entry("sky_slot_id", &proc_root);
+	remove_proc_entry("sky_chassis_id", &proc_root);
+	hdpu_slot_id = 0;
+	hdpu_chassis_id = 0;
+	return 0;
+}
+
+static int __init nexus_init(void)
+{
+	int rc;
+	rc = driver_register(&hdpu_nexus_driver);
+	return rc;
+}
+
+static void __exit nexus_exit(void)
+{
+	driver_unregister(&hdpu_nexus_driver);
+}
+
+module_init(nexus_init);
+module_exit(nexus_exit);
+
+MODULE_AUTHOR("Brian Waite");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -224,4 +224,5 @@ module_exit(ibmasm_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ibmasm_pci_table);
 
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -51,7 +51,7 @@ config MMC_PXA
 
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
-	depends on MMC && ISA
+	depends on MMC && ISA_DMA_API
 	help
 	  This selects the Winbond(R) W83L51xD Secure digital and
           Multimedia card Interface.
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -884,7 +884,7 @@ EXPORT_SYMBOL(mmc_free_host);
  *	@host: mmc host
  *	@state: suspend mode (PM_SUSPEND_xxx)
  */
-int mmc_suspend_host(struct mmc_host *host, u32 state)
+int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
 {
 	mmc_claim_host(host);
 	mmc_deselect_cards(host);
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -383,7 +383,10 @@ static int mmc_blk_probe(struct mmc_card
 	struct mmc_blk_data *md;
 	int err;
 
-	if (card->csd.cmdclass & ~0x1ff)
+	/*
+	 * Check that the card supports the command class(es) we need.
+	 */
+	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
 		return -ENODEV;
 
 	if (card->csd.read_blkbits < 9) {
@@ -437,7 +440,7 @@ static void mmc_blk_remove(struct mmc_ca
 }
 
 #ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card, u32 state)
+static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -21,6 +21,41 @@
 #define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
 
+#define MMC_ATTR(name, fmt, args...)					\
+static ssize_t mmc_##name##_show (struct device *dev, char *buf)	\
+{									\
+	struct mmc_card *card = dev_to_mmc_card(dev);			\
+	return sprintf(buf, fmt, args);					\
+}
+
+MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
+	card->raw_cid[2], card->raw_cid[3]);
+MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
+	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
+MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
+MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
+MMC_ATTR(name, "%s\n", card->cid.prod_name);
+MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
+
+#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
+
+static struct device_attribute mmc_dev_attrs[] = {
+	MMC_ATTR_RO(cid),
+	MMC_ATTR_RO(csd),
+	MMC_ATTR_RO(date),
+	MMC_ATTR_RO(fwrev),
+	MMC_ATTR_RO(hwrev),
+	MMC_ATTR_RO(manfid),
+	MMC_ATTR_RO(name),
+	MMC_ATTR_RO(oemid),
+	MMC_ATTR_RO(serial),
+	__ATTR_NULL
+};
+
+
 static void mmc_release_card(struct device *dev)
 {
 	struct mmc_card *card = dev_to_mmc_card(dev);
@@ -74,7 +109,7 @@ mmc_bus_hotplug(struct device *dev, char
 	return 0;
 }
 
-static int mmc_bus_suspend(struct device *dev, u32 state)
+static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = dev_to_mmc_card(dev);
@@ -98,6 +133,7 @@ static int mmc_bus_resume(struct device 
 
 static struct bus_type mmc_bus_type = {
 	.name		= "mmc",
+	.dev_attrs	= mmc_dev_attrs,
 	.match		= mmc_bus_match,
 	.hotplug	= mmc_bus_hotplug,
 	.suspend	= mmc_bus_suspend,
@@ -151,38 +187,6 @@ void mmc_unregister_driver(struct mmc_dr
 EXPORT_SYMBOL(mmc_unregister_driver);
 
 
-#define MMC_ATTR(name, fmt, args...)					\
-static ssize_t mmc_dev_show_##name (struct device *dev, char *buf)	\
-{									\
-	struct mmc_card *card = dev_to_mmc_card(dev);			\
-	return sprintf(buf, fmt, args);					\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
-
-MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
-	card->raw_cid[2], card->raw_cid[3]);
-MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
-	card->raw_csd[2], card->raw_csd[3]);
-MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
-MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
-MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
-MMC_ATTR(name, "%s\n", card->cid.prod_name);
-MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
-MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
-
-static struct device_attribute *mmc_dev_attributes[] = {
-	&dev_attr_cid,
-	&dev_attr_csd,
-	&dev_attr_date,
-	&dev_attr_fwrev,
-	&dev_attr_hwrev,
-	&dev_attr_manfid,
-	&dev_attr_name,
-	&dev_attr_oemid,
-	&dev_attr_serial,
-};
-
 /*
  * Internal function.  Initialise a MMC card structure.
  */
@@ -201,17 +205,10 @@ void mmc_init_card(struct mmc_card *card
  */
 int mmc_register_card(struct mmc_card *card)
 {
-	int ret, i;
-
 	snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
 		 "%s:%04x", card->host->host_name, card->rca);
 
-	ret = device_add(&card->dev);
-	if (ret == 0)
-		for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++)
-			device_create_file(&card->dev, mmc_dev_attributes[i]);
-
-	return ret;
+	return device_add(&card->dev);
 }
 
 /*
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -603,7 +603,7 @@ static int mmci_remove(struct amba_devic
 }
 
 #ifdef CONFIG_PM
-static int mmci_suspend(struct amba_device *dev, u32 state)
+static int mmci_suspend(struct amba_device *dev, pm_message_t state)
 {
 	struct mmc_host *mmc = amba_get_drvdata(dev);
 	int ret = 0;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -558,7 +558,7 @@ static int pxamci_remove(struct device *
 }
 
 #ifdef CONFIG_PM
-static int pxamci_suspend(struct device *dev, u32 state, u32 level)
+static int pxamci_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	int ret = 0;
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -28,7 +28,9 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/pnp.h>
 #include <linux/highmem.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
@@ -40,7 +42,7 @@
 #include "wbsd.h"
 
 #define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.1"
+#define DRIVER_VERSION "1.2"
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(x...) \
@@ -52,10 +54,6 @@
 #define DBGF(x...)	do { } while (0)
 #endif
 
-static unsigned int io = 0x248;
-static unsigned int irq = 6;
-static int dma = 2;
-
 #ifdef CONFIG_MMC_DEBUG
 void DBG_REG(int reg, u8 value)
 {
@@ -79,28 +77,61 @@ void DBG_REG(int reg, u8 value)
 #endif
 
 /*
+ * Device resources
+ */
+
+#ifdef CONFIG_PNP
+
+static const struct pnp_device_id pnp_dev_table[] = {
+	{ "WEC0517", 0 },
+	{ "WEC0518", 0 },
+	{ "", 0 },
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+#endif /* CONFIG_PNP */
+
+#ifdef CONFIG_PNP
+static unsigned int nopnp = 0;
+#else
+static const unsigned int nopnp = 1;
+#endif
+static unsigned int io = 0x248;
+static unsigned int irq = 6;
+static int dma = 2;
+
+/*
  * Basic functions
  */
 
 static inline void wbsd_unlock_config(struct wbsd_host* host)
 {
+	BUG_ON(host->config == 0);
+	
 	outb(host->unlock_code, host->config);
 	outb(host->unlock_code, host->config);
 }
 
 static inline void wbsd_lock_config(struct wbsd_host* host)
 {
+	BUG_ON(host->config == 0);
+	
 	outb(LOCK_CODE, host->config);
 }
 
 static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
 {
+	BUG_ON(host->config == 0);
+	
 	outb(reg, host->config);
 	outb(value, host->config + 1);
 }
 
 static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
 {
+	BUG_ON(host->config == 0);
+	
 	outb(reg, host->config);
 	return inb(host->config + 1);
 }
@@ -133,6 +164,13 @@ static void wbsd_init_device(struct wbsd
 	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
 	
 	/*
+	 * Set DAT3 to input
+	 */
+	setup &= ~WBSD_DAT3_H;
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+	host->flags &= ~WBSD_FIGNORE_DETECT;
+	
+	/*
 	 * Read back default clock.
 	 */
 	host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
@@ -148,6 +186,14 @@ static void wbsd_init_device(struct wbsd
 	wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
 	
 	/*
+	 * Test for card presence
+	 */
+	if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
+		host->flags |= WBSD_FCARD_PRESENT;
+	else
+		host->flags &= ~WBSD_FCARD_PRESENT;
+	
+	/*
 	 * Enable interesting interrupts.
 	 */
 	ier = 0;
@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(s
 	}
 }
 
-static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs);
-
 static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
 {
 	int i;
@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_h
 	}
 	
 	wbsd_kunmap_sg(host);
+	
+	/*
+	 * The controller stops sending interrupts for
+	 * 'FIFO empty' under certain conditions. So we
+	 * need to be a bit more pro-active.
+	 */
+	tasklet_schedule(&host->fifo_tasklet);
 }
 
 static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
@@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd
 	wbsd_request_end(host, host->mrq);
 }
 
-/*
- * MMC Callbacks
- */
+/*****************************************************************************\
+ *                                                                           *
+ * MMC layer callbacks                                                       *
+ *                                                                           *
+\*****************************************************************************/
 
 static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
 {
@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host
 	 * If there is no card in the slot then
 	 * timeout immediatly.
 	 */
-	if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT))
+	if (!(host->flags & WBSD_FCARD_PRESENT))
 	{
 		cmd->error = MMC_ERR_TIMEOUT;
 		goto done;
@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host
 		host->clk = clk;
 	}
 
+	/*
+	 * Power up card.
+	 */
 	if (ios->power_mode != MMC_POWER_OFF)
 	{
-		/*
-		 * Power up card.
-		 */
 		pwr = inb(host->base + WBSD_CSR);
 		pwr &= ~WBSD_POWER_N;
 		outb(pwr, host->base + WBSD_CSR);
-
-		/*
-		 * This behaviour is stolen from the
-		 * Windows driver. Don't know why, but
-		 * it is needed.
-		 */
-		setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-		if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-			setup |= WBSD_DAT3_H;
-		else
-			setup &= ~WBSD_DAT3_H;
-		wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-		mdelay(1);
 	}
 
+	/*
+	 * MMC cards need to have pin 1 high during init.
+	 * Init time corresponds rather nicely with the bus mode.
+	 * It wreaks havoc with the card detection though so
+	 * that needs to be disabed.
+	 */
+	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+	if ((ios->power_mode == MMC_POWER_ON) &&
+		(ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
+	{
+		setup |= WBSD_DAT3_H;
+		host->flags |= WBSD_FIGNORE_DETECT;
+	}
+	else
+	{
+		setup &= ~WBSD_DAT3_H;
+		host->flags &= ~WBSD_FIGNORE_DETECT;
+	}
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+	
 	spin_unlock_bh(&host->lock);
 }
 
+static struct mmc_host_ops wbsd_ops = {
+	.request	= wbsd_request,
+	.set_ios	= wbsd_set_ios,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
 /*
  * Tasklets
  */
@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned l
 {
 	struct wbsd_host* host = (struct wbsd_host*)param;
 	u8 csr;
+	int change = 0;
 	
 	spin_lock(&host->lock);
 	
+	if (host->flags & WBSD_FIGNORE_DETECT)
+	{
+		spin_unlock(&host->lock);
+		return;
+	}
+	
 	csr = inb(host->base + WBSD_CSR);
 	WARN_ON(csr == 0xff);
 	
 	if (csr & WBSD_CARDPRESENT)
-		DBG("Card inserted\n");
-	else
+	{
+		if (!(host->flags & WBSD_FCARD_PRESENT))
+		{
+			DBG("Card inserted\n");
+			host->flags |= WBSD_FCARD_PRESENT;
+			change = 1;
+		}
+	}
+	else if (host->flags & WBSD_FCARD_PRESENT)
 	{
 		DBG("Card removed\n");
+		host->flags &= ~WBSD_FCARD_PRESENT;
+		change = 1;
 		
 		if (host->mrq)
 		{
@@ -1033,7 +1119,8 @@ static void wbsd_tasklet_card(unsigned l
 	 */
 	spin_unlock(&host->lock);
 
-	mmc_detect_change(host->mmc);
+	if (change)
+		mmc_detect_change(host->mmc);
 }
 
 static void wbsd_tasklet_fifo(unsigned long param)
@@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, voi
 	return IRQ_HANDLED;
 }
 
+/*****************************************************************************\
+ *                                                                           *
+ * Device initialisation and shutdown                                        *
+ *                                                                           *
+\*****************************************************************************/
+
 /*
- * Support functions for probe
+ * Allocate/free MMC structure.
  */
 
-static int wbsd_scan(struct wbsd_host* host)
+static int __devinit wbsd_alloc_mmc(struct device* dev)
+{
+	struct mmc_host* mmc;
+	struct wbsd_host* host;
+	
+	/*
+	 * Allocate MMC structure.
+	 */
+	mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+	if (!mmc)
+		return -ENOMEM;
+	
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+
+	host->dma = -1;
+
+	/*
+	 * Set host parameters.
+	 */
+	mmc->ops = &wbsd_ops;
+	mmc->f_min = 375000;
+	mmc->f_max = 24000000;
+	mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+	
+	spin_lock_init(&host->lock);
+	
+	/*
+	 * Maximum number of segments. Worst case is one sector per segment
+	 * so this will be 64kB/512.
+	 */
+	mmc->max_hw_segs = 128;
+	mmc->max_phys_segs = 128;
+	
+	/*
+	 * Maximum number of sectors in one transfer. Also limited by 64kB
+	 * buffer.
+	 */
+	mmc->max_sectors = 128;
+	
+	/*
+	 * Maximum segment size. Could be one segment with the maximum number
+	 * of segments.
+	 */
+	mmc->max_seg_size = mmc->max_sectors * 512;
+	
+	dev_set_drvdata(dev, mmc);
+	
+	return 0;
+}
+
+static void __devexit wbsd_free_mmc(struct device* dev)
+{
+	struct mmc_host* mmc;
+	
+	mmc = dev_get_drvdata(dev);
+	if (!mmc)
+		return;
+	
+	mmc_free_host(mmc);
+	
+	dev_set_drvdata(dev, NULL);
+}
+
+/*
+ * Scan for known chip id:s
+ */
+
+static int __devinit wbsd_scan(struct wbsd_host* host)
 {
 	int i, j, k;
 	int id;
@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* h
 	return -ENODEV;
 }
 
-static int wbsd_request_regions(struct wbsd_host* host)
+/*
+ * Allocate/free io port ranges
+ */
+
+static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
 {
 	if (io & 0x7)
 		return -EINVAL;
 	
-	if (!request_region(io, 8, DRIVER_NAME))
+	if (!request_region(base, 8, DRIVER_NAME))
 		return -EIO;
 	
 	host->base = io;
@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct w
 	return 0;
 }
 
-static void wbsd_release_regions(struct wbsd_host* host)
+static void __devexit wbsd_release_regions(struct wbsd_host* host)
 {
 	if (host->base)
 		release_region(host->base, 8);
+	
+	host->base = 0;
 
 	if (host->config)
 		release_region(host->config, 2);
+	
+	host->config = 0;
 }
 
-static void wbsd_init_dma(struct wbsd_host* host)
+/*
+ * Allocate/free DMA port and buffer
+ */
+
+static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
 {
-	host->dma = -1;
-	
 	if (dma < 0)
 		return;
 	
@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_ho
 	 * We need to allocate a special buffer in
 	 * order for ISA to be able to DMA to it.
 	 */
-	host->dma_buffer = kmalloc(65536,
+	host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
 		GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
 	if (!host->dma_buffer)
 		goto free;
@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_ho
 	/*
 	 * Translate the address to a physical address.
 	 */
-	host->dma_addr = isa_virt_to_bus(host->dma_buffer);
+	host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer,
+		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
 			
 	/*
 	 * ISA DMA must be aligned on a 64k basis.
@@ -1325,6 +1497,10 @@ kfree:
 	 */
 	BUG_ON(1);
 	
+	dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
+		DMA_BIDIRECTIONAL);
+	host->dma_addr = (dma_addr_t)NULL;
+	
 	kfree(host->dma_buffer);
 	host->dma_buffer = NULL;
 
@@ -1336,60 +1512,122 @@ err:
 		"Falling back on FIFO.\n", dma);
 }
 
-static struct mmc_host_ops wbsd_ops = {
-	.request	= wbsd_request,
-	.set_ios	= wbsd_set_ios,
-};
+static void __devexit wbsd_release_dma(struct wbsd_host* host)
+{
+	if (host->dma_addr)
+		dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
+			DMA_BIDIRECTIONAL);
+	if (host->dma_buffer)
+		kfree(host->dma_buffer);
+	if (host->dma >= 0)
+		free_dma(host->dma);
+	
+	host->dma = -1;
+	host->dma_buffer = NULL;
+	host->dma_addr = (dma_addr_t)NULL;
+}
 
 /*
- * Device probe
+ * Allocate/free IRQ.
  */
 
-static int wbsd_probe(struct device* dev)
+static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
 {
-	struct wbsd_host* host = NULL;
-	struct mmc_host* mmc = NULL;
 	int ret;
 	
 	/*
-	 * Allocate MMC structure.
+	 * Allocate interrupt.
 	 */
-	mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
-	if (!mmc)
-		return -ENOMEM;
-	
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
+
+	ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
+	if (ret)
+		return ret;
 	
+	host->irq = irq;
+
 	/*
-	 * Scan for hardware.
+	 * Set up tasklets.
 	 */
-	ret = wbsd_scan(host);
-	if (ret)
-		goto freemmc;
+	tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
+	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
+	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
+	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
+	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
+	tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+	
+	return 0;
+}
 
-	/*
-	 * Reset the chip.
-	 */	
-	wbsd_write_config(host, WBSD_CONF_SWRST, 1);
-	wbsd_write_config(host, WBSD_CONF_SWRST, 0);
+static void __devexit wbsd_release_irq(struct wbsd_host* host)
+{
+	if (!host->irq)
+		return;
 
+	free_irq(host->irq, host);
+	
+	host->irq = 0;
+		
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->fifo_tasklet);
+	tasklet_kill(&host->crc_tasklet);
+	tasklet_kill(&host->timeout_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+	tasklet_kill(&host->block_tasklet);
+}
+
+/*
+ * Allocate all resources for the host.
+ */
+
+static int __devinit wbsd_request_resources(struct wbsd_host* host,
+	int base, int irq, int dma)
+{
+	int ret;
+	
 	/*
 	 * Allocate I/O ports.
 	 */
-	ret = wbsd_request_regions(host);
+	ret = wbsd_request_region(host, base);
 	if (ret)
-		goto release;
+		return ret;
 
 	/*
-	 * Set host parameters.
+	 * Allocate interrupt.
 	 */
-	mmc->ops = &wbsd_ops;
-	mmc->f_min = 375000;
-	mmc->f_max = 24000000;
-	mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+	ret = wbsd_request_irq(host, irq);
+	if (ret)
+		return ret;
+
+	/*
+	 * Allocate DMA.
+	 */
+	wbsd_request_dma(host, dma);
 	
-	spin_lock_init(&host->lock);
+	return 0;
+}
+
+/*
+ * Release all resources for the host.
+ */
+
+static void __devexit wbsd_release_resources(struct wbsd_host* host)
+{
+	wbsd_release_dma(host);
+	wbsd_release_irq(host);
+	wbsd_release_regions(host);
+}
+
+/*
+ * Configure the resources the chip should use.
+ */
+
+static void __devinit wbsd_chip_config(struct wbsd_host* host)
+{
+	/*
+	 * Reset the chip.
+	 */	
+	wbsd_write_config(host, WBSD_CONF_SWRST, 1);
+	wbsd_write_config(host, WBSD_CONF_SWRST, 0);
 
 	/*
 	 * Select SD/MMC function.
@@ -1399,171 +1637,247 @@ static int wbsd_probe(struct device* dev
 	/*
 	 * Set up card detection.
 	 */
-	wbsd_write_config(host, WBSD_CONF_PINS, 0x02);
+	wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
 	
 	/*
-	 * Configure I/O port.
+	 * Configure chip
 	 */
 	wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
 	wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-
-	/*
-	 * Allocate interrupt.
-	 */
-	ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
-	if (ret)
-		goto release;
 	
-	host->irq = irq;
+	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
 	
-	/*
-	 * Set up tasklets.
-	 */
-	tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
-	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
-	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
-	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
-	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
-	tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+	if (host->dma >= 0)
+		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
 	
 	/*
-	 * Configure interrupt.
+	 * Enable and power up chip.
 	 */
-	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
+	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+}
+
+/*
+ * Check that configured resources are correct.
+ */
+ 
+static int __devinit wbsd_chip_validate(struct wbsd_host* host)
+{
+	int base, irq, dma;
 	
 	/*
-	 * Allocate DMA.
+	 * Select SD/MMC function.
 	 */
-	wbsd_init_dma(host);
+	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
 	
 	/*
-	 * If all went well, then configure DMA.
+	 * Read configuration.
 	 */
-	if (host->dma >= 0)
-		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
+	base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
+	base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
 	
-	/*
-	 * Maximum number of segments. Worst case is one sector per segment
-	 * so this will be 64kB/512.
-	 */
-	mmc->max_hw_segs = 128;
-	mmc->max_phys_segs = 128;
+	irq = wbsd_read_config(host, WBSD_CONF_IRQ);
+	
+	dma = wbsd_read_config(host, WBSD_CONF_DRQ);
 	
 	/*
-	 * Maximum number of sectors in one transfer. Also limited by 64kB
-	 * buffer.
+	 * Validate against given configuration.
 	 */
-	mmc->max_sectors = 128;
+	if (base != host->base)
+		return 0;
+	if (irq != host->irq)
+		return 0;
+	if ((dma != host->dma) && (host->dma != -1))
+		return 0;
+	
+	return 1;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Devices setup and shutdown                                                *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
+	int pnp)
+{
+	struct wbsd_host* host = NULL;
+	struct mmc_host* mmc = NULL;
+	int ret;
+	
+	ret = wbsd_alloc_mmc(dev);
+	if (ret)
+		return ret;
+	
+	mmc = dev_get_drvdata(dev);
+	host = mmc_priv(mmc);
 	
 	/*
-	 * Maximum segment size. Could be one segment with the maximum number
-	 * of segments.
+	 * Scan for hardware.
 	 */
-	mmc->max_seg_size = mmc->max_sectors * 512;
+	ret = wbsd_scan(host);
+	if (ret)
+	{
+		if (pnp && (ret == -ENODEV))
+		{
+			printk(KERN_WARNING DRIVER_NAME
+				": Unable to confirm device presence. You may "
+				"experience lock-ups.\n");
+		}
+		else
+		{
+			wbsd_free_mmc(dev);
+			return ret;
+		}
+	}
 	
 	/*
-	 * Enable chip.
+	 * Request resources.
 	 */
-	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+	ret = wbsd_request_resources(host, io, irq, dma);
+	if (ret)
+	{
+		wbsd_release_resources(host);
+		wbsd_free_mmc(dev);
+		return ret;
+	}
 	
 	/*
-	 * Power up chip.
+	 * See if chip needs to be configured.
 	 */
-	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+	if (pnp && (host->config != 0))
+	{
+		if (!wbsd_chip_validate(host))
+		{
+			printk(KERN_WARNING DRIVER_NAME
+				": PnP active but chip not configured! "
+				"You probably have a buggy BIOS. "
+				"Configuring chip manually.\n");
+			wbsd_chip_config(host);
+		}
+	}
+	else
+		wbsd_chip_config(host);
 	
 	/*
 	 * Power Management stuff. No idea how this works.
 	 * Not tested.
 	 */
 #ifdef CONFIG_PM
-	wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
+	if (host->config)
+		wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
 #endif
+	/*
+	 * Allow device to initialise itself properly.
+	 */
+	mdelay(5);
 
 	/*
 	 * Reset the chip into a known state.
 	 */
 	wbsd_init_device(host);
 	
-	dev_set_drvdata(dev, mmc);
-	
-	/*
-	 * Add host to MMC layer.
-	 */
 	mmc_add_host(mmc);
 
-	printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n",
-		mmc->host_name, (int)host->chip_id, (int)host->base,
-		(int)host->irq, (int)host->dma);
+	printk(KERN_INFO "%s: W83L51xD", mmc->host_name);
+	if (host->chip_id != 0)
+		printk(" id %x", (int)host->chip_id);
+	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
+	if (host->dma >= 0)
+		printk(" dma %d", (int)host->dma);
+	else
+		printk(" FIFO");
+	if (pnp)
+		printk(" PnP");
+	printk("\n");
 
 	return 0;
-
-release:
-	wbsd_release_regions(host);
-
-freemmc:
-	mmc_free_host(mmc);
-
-	return ret;
 }
 
-/*
- * Device remove
- */
-
-static int wbsd_remove(struct device* dev)
+static void __devexit wbsd_shutdown(struct device* dev, int pnp)
 {
 	struct mmc_host* mmc = dev_get_drvdata(dev);
 	struct wbsd_host* host;
 	
 	if (!mmc)
-		return 0;
+		return;
 
 	host = mmc_priv(mmc);
 	
-	/*
-	 * Unregister host with MMC layer.
-	 */
 	mmc_remove_host(mmc);
 
-	/*
-	 * Power down the SD/MMC function.
-	 */
-	wbsd_unlock_config(host);
-	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-	wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
-	wbsd_lock_config(host);
+	if (!pnp)
+	{
+		/*
+		 * Power down the SD/MMC function.
+		 */
+		wbsd_unlock_config(host);
+		wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+		wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
+		wbsd_lock_config(host);
+	}
 	
-	/*
-	 * Free resources.
-	 */
-	if (host->dma_buffer)
-		kfree(host->dma_buffer);
+	wbsd_release_resources(host);
 	
-	if (host->dma >= 0)
-		free_dma(host->dma);
+	wbsd_free_mmc(dev);
+}
 
-	free_irq(host->irq, host);
+/*
+ * Non-PnP
+ */
+
+static int __devinit wbsd_probe(struct device* dev)
+{
+	return wbsd_init(dev, io, irq, dma, 0);
+}
+
+static int __devexit wbsd_remove(struct device* dev)
+{
+	wbsd_shutdown(dev, 0);
+
+	return 0;
+}
+
+/*
+ * PnP
+ */
+
+#ifdef CONFIG_PNP
+
+static int __devinit
+wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
+{
+	int io, irq, dma;
 	
-	tasklet_kill(&host->card_tasklet);
-	tasklet_kill(&host->fifo_tasklet);
-	tasklet_kill(&host->crc_tasklet);
-	tasklet_kill(&host->timeout_tasklet);
-	tasklet_kill(&host->finish_tasklet);
-	tasklet_kill(&host->block_tasklet);
+	/*
+	 * Get resources from PnP layer.
+	 */
+	io = pnp_port_start(pnpdev, 0);
+	irq = pnp_irq(pnpdev, 0);
+	if (pnp_dma_valid(pnpdev, 0))
+		dma = pnp_dma(pnpdev, 0);
+	else
+		dma = -1;
 	
-	wbsd_release_regions(host);
+	DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
 	
-	mmc_free_host(mmc);
+	return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
+}
 
-	return 0;
+static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
+{
+	wbsd_shutdown(&dev->dev, 1);
 }
 
+#endif /* CONFIG_PNP */
+
 /*
  * Power management
  */
 
 #ifdef CONFIG_PM
-static int wbsd_suspend(struct device *dev, u32 state, u32 level)
+static int wbsd_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	DBGF("Not yet supported\n");
 
@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *de
 #define wbsd_resume NULL
 #endif
 
-static void wbsd_release(struct device *dev)
-{
-}
-
-static struct platform_device wbsd_device = {
-	.name		= DRIVER_NAME,
-	.id			= -1,
-	.dev		= {
-		.release = wbsd_release,
-	},
-};
+static struct platform_device *wbsd_device;
 
 static struct device_driver wbsd_driver = {
 	.name		= DRIVER_NAME,
@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver 
 	.resume		= wbsd_resume,
 };
 
+#ifdef CONFIG_PNP
+
+static struct pnp_driver wbsd_pnp_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= pnp_dev_table,
+	.probe		= wbsd_pnp_probe,
+	.remove		= wbsd_pnp_remove,
+};
+
+#endif /* CONFIG_PNP */
+
 /*
  * Module loading/unloading
  */
@@ -1615,29 +1930,57 @@ static int __init wbsd_drv_init(void)
 		": Winbond W83L51xD SD/MMC card interface driver, "
 		DRIVER_VERSION "\n");
 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+#ifdef CONFIG_PNP
+
+	if (!nopnp)
+	{
+		result = pnp_register_driver(&wbsd_pnp_driver);
+		if (result < 0)
+			return result;
+	}
+
+#endif /* CONFIG_PNP */	
 	
-	result = driver_register(&wbsd_driver);
-	if (result < 0)
-		return result;
-
-	result = platform_device_register(&wbsd_device);
-	if (result < 0)
-		return result;
+	if (nopnp)
+	{
+		result = driver_register(&wbsd_driver);
+		if (result < 0)
+			return result;
+
+		wbsd_device = platform_device_register_simple(DRIVER_NAME, -1,
+			NULL, 0);
+		if (IS_ERR(wbsd_device))
+			return PTR_ERR(wbsd_device);
+	}
 
 	return 0;
 }
 
 static void __exit wbsd_drv_exit(void)
 {
-	platform_device_unregister(&wbsd_device);
+#ifdef CONFIG_PNP
+
+	if (!nopnp)
+		pnp_unregister_driver(&wbsd_pnp_driver);
 	
-	driver_unregister(&wbsd_driver);
+#endif /* CONFIG_PNP */	
+
+	if (nopnp)
+	{
+		platform_device_unregister(wbsd_device);
+	
+		driver_unregister(&wbsd_driver);
+	}
 
 	DBG("unloaded\n");
 }
 
 module_init(wbsd_drv_init);
 module_exit(wbsd_drv_exit);
+#ifdef CONFIG_PNP
+module_param(nopnp, uint, 0444);
+#endif
 module_param(io, uint, 0444);
 module_param(irq, uint, 0444);
 module_param(dma, int, 0444);
@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
 MODULE_VERSION(DRIVER_VERSION);
 
+#ifdef CONFIG_PNP
+MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
+#endif
 MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
 MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
 MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -35,6 +35,12 @@ const int valid_ids[] = {
 
 #define DEVICE_SD		0x03
 
+#define WBSD_PINS_DAT3_HI	0x20
+#define WBSD_PINS_DAT3_OUT	0x10
+#define WBSD_PINS_GP11_HI	0x04
+#define WBSD_PINS_DETECT_GP11	0x02
+#define WBSD_PINS_DETECT_DAT3	0x01
+
 #define WBSD_CMDR		0x00
 #define WBSD_DFR		0x01
 #define WBSD_EIR		0x02
@@ -133,6 +139,7 @@ const int valid_ids[] = {
 #define WBSD_CRC_OK		0x05 /* S010E (00101) */
 #define WBSD_CRC_FAIL		0x0B /* S101E (01011) */
 
+#define WBSD_DMA_SIZE		65536
 
 struct wbsd_host
 {
@@ -140,6 +147,11 @@ struct wbsd_host
 	
 	spinlock_t		lock;		/* Mutex */
 
+	int			flags;		/* Driver states */
+
+#define WBSD_FCARD_PRESENT	(1<<0)		/* Card is present */
+#define WBSD_FIGNORE_DETECT	(1<<1)		/* Ignore card detection */
+	
 	struct mmc_request*	mrq;		/* Current request */
 	
 	u8			isr;		/* Accumulated ISR */
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -27,6 +27,15 @@ config MTD_DEBUG_VERBOSE
 	help
 	  Determines the verbosity level of the MTD debugging messages.
 
+config MTD_CONCAT
+	tristate "MTD concatenating support"
+	depends on MTD
+	help
+	  Support for concatenating several MTD devices into a single
+	  (virtual) one. This allows you to have -for example- a JFFS(2)
+	  file system spanning multiple physical flash chips. If unsure,
+	  say 'Y'.
+
 config MTD_PARTITIONS
 	bool "MTD partitioning support"
 	depends on MTD
@@ -40,15 +49,6 @@ config MTD_PARTITIONS
 	  devices. Partitioning on NFTL 'devices' is a different - that's the
 	  'normal' form of partitioning used on a block device.
 
-config MTD_CONCAT
-	tristate "MTD concatenating support"
-	depends on MTD
-	help
-	  Support for concatenating several MTD devices into a single
-	  (virtual) one. This allows you to have -for example- a JFFS(2)
-	  file system spanning multiple physical flash chips. If unsure,
-	  say 'Y'.
-
 config MTD_REDBOOT_PARTS
 	tristate "RedBoot partition table parsing"
 	depends on MTD_PARTITIONS
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -59,7 +59,7 @@ void cache_readahead(struct address_spac
 
 	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	for (i = 0; i < PAGE_READAHEAD; i++) {
 		pagei = index + i;
 		if (pagei > end_index) {
@@ -71,16 +71,16 @@ void cache_readahead(struct address_spac
 			break;
 		if (page)
 			continue;
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (!page)
 			break;
 		page->index = pagei;
 		list_add(&page->lru, &page_pool);
 		ret++;
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	if (ret)
 		read_cache_pages(mapping, &page_pool, filler, NULL);
 }
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -159,7 +159,7 @@ config MTD_VMAX
 
 config MTD_SCx200_DOCFLASH
 	tristate "Flash device mapped with DOCCS on NatSemi SCx200"
-	depends on X86 && MTD_CFI && MTD_PARTITIONS
+	depends on SCx200 && MTD_CFI && MTD_PARTITIONS
 	help
 	  Enable support for a flash chip mapped using the DOCCS signal on a
 	  National Semiconductor SCx200 processor.
@@ -405,14 +405,6 @@ config MTD_REDWOOD
 	  Redwood board. If you have one of these boards and would like to
 	  use the flash chips on it, say 'Y'.
 
-config MTD_CHESTNUT
-	tristate "CFI Flash devices mapped on IBM 750FX or IBM 750GX Eval Boards"
-	depends on MTD_CFI && PPC32 && CHESTNUT && MTD_PARTITIONS
-	help
-	  This enables access routines for the flash chips on the IBM
-	  750FX and 750GX Eval Boards. If you have one of these boards and
-	  would like to use the flash chips on it, say 'Y'
-
 config MTD_CSTM_MIPS_IXX
 	tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
 	depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -54,7 +54,6 @@ obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
 obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
 obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o
 obj-$(CONFIG_MTD_REDWOOD)	+= redwood.o
-obj-$(CONFIG_MTD_CHESTNUT)	+= chestnut.o
 obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
 obj-$(CONFIG_MTD_NETtel)	+= nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
diff --git a/drivers/mtd/maps/chestnut.c b/drivers/mtd/maps/chestnut.c
deleted file mode 100644
--- a/drivers/mtd/maps/chestnut.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * drivers/mtd/maps/chestnut.c
- *
- * $Id: chestnut.c,v 1.1 2005/01/05 16:59:50 dwmw2 Exp $
- *
- * Flash map driver for IBM Chestnut (750FXGX Eval)
- *
- * Chose not to enable 8 bit flash as it contains the firmware and board
- * info.  Thus only the 32bit flash is supported.
- *
- * Author: <source@mvista.com>
- *
- * 2004 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <platforms/chestnut.h>
-
-static struct map_info chestnut32_map = {
-   	.name 		= "User FS",
-   	.size 		= CHESTNUT_32BIT_SIZE,
-   	.bankwidth 	= 4,
-	.phys 		= CHESTNUT_32BIT_BASE,
-};
-
-static struct mtd_partition chestnut32_partitions[] = {
-	{
-		.name 	= "User FS",
-		.offset	= 0,
-		.size	= CHESTNUT_32BIT_SIZE,
-	}
-};
-
-static struct mtd_info *flash32;
-
-int __init init_chestnut(void)
-{
-	/* 32-bit FLASH */
-
-   	chestnut32_map.virt = ioremap(chestnut32_map.phys, chestnut32_map.size);
-
-   	if (!chestnut32_map.virt) {
-      		printk(KERN_NOTICE "Failed to ioremap 32-bit flash\n");
-		return -EIO;
-   	}
-
-	simple_map_init(&chestnut32_map);
-
-   	flash32 = do_map_probe("cfi_probe", &chestnut32_map);
-   	if (flash32) {
-   		flash32->owner = THIS_MODULE;
-   		add_mtd_partitions(flash32, chestnut32_partitions,
-					ARRAY_SIZE(chestnut32_partitions));
-   	} else {
-      		printk(KERN_NOTICE "map probe failed for 32-bit flash\n");
-		return -ENXIO;
-	}
-
-   	return 0;
-}
-
-static void __exit
-cleanup_chestnut(void)
-{
-   	if (flash32) {
-      		del_mtd_partitions(flash32);
-		map_destroy(flash32);
-   	}
-
-   	if (chestnut32_map.virt) {
-      		iounmap((void *)chestnut32_map.virt);
-	  	chestnut32_map.virt = 0;
-   	}
-}
-
-module_init(init_chestnut);
-module_exit(cleanup_chestnut);
-
-MODULE_DESCRIPTION("MTD map and partitions for IBM Chestnut (750fxgx Eval)");
-MODULE_AUTHOR("<source@mvista.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/ich2rom.c b/drivers/mtd/maps/ich2rom.c
deleted file mode 100644
--- a/drivers/mtd/maps/ich2rom.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * ich2rom.c
- *
- * Normal mappings of chips in physical memory
- * $Id: ich2rom.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/config.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-#define RESERVE_MEM_REGION 0
-
-#define ICH2_FWH_REGION_START	0xFF000000UL
-#define ICH2_FWH_REGION_SIZE	0x01000000UL
-#define BIOS_CNTL	0x4e
-#define FWH_DEC_EN1	0xE3
-#define FWH_DEC_EN2	0xF0
-#define FWH_SEL1	0xE8
-#define FWH_SEL2	0xEE
-
-struct ich2rom_map_info {
-	struct map_info map;
-	struct mtd_info *mtd;
-	unsigned long window_addr;
-};
-
-static inline unsigned long addr(struct map_info *map, unsigned long ofs)
-{
-	unsigned long offset;
-	offset = ((8*1024*1024) - map->size) + ofs;
-	if (offset >= (4*1024*1024)) {
-		offset += 0x400000;
-	}
-	return map->map_priv_1 + 0x400000 + offset;
-}
-
-static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
-{
-	return addr - map->map_priv_1 + ICH2_FWH_REGION_START;
-}
-	
-static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(addr(map, ofs));
-}
-
-static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(addr(map, ofs));
-}
-
-static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(addr(map, ofs));
-}
-
-static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, addr(map, from), len);
-}
-
-static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs)
-{
-	__raw_writeb(d, addr(map,ofs));
-	mb();
-}
-
-static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs)
-{
-	__raw_writew(d, addr(map, ofs));
-	mb();
-}
-
-static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs)
-{
-	__raw_writel(d, addr(map, ofs));
-	mb();
-}
-
-static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(addr(map, to), from, len);
-}
-
-static struct ich2rom_map_info ich2rom_map = {
-	.map = {
-		.name = "ICH2 rom",
-		.phys = NO_XIP,
-		.size = 0,
-		.buswidth = 1,
-		.read8 = ich2rom_read8,
-		.read16 = ich2rom_read16,
-		.read32 = ich2rom_read32,
-		.copy_from = ich2rom_copy_from,
-		.write8 = ich2rom_write8,
-		.write16 = ich2rom_write16,
-		.write32 = ich2rom_write32,
-		.copy_to = ich2rom_copy_to,
-		/* Firmware hubs only use vpp when being programmed
-		 * in a factory setting.  So in place programming
-		 * needs to use a different method.
-		 */
-	},
-	.mtd = NULL,
-	.window_addr = 0,
-};
-
-enum fwh_lock_state {
-	FWH_DENY_WRITE = 1,
-	FWH_IMMUTABLE  = 2,
-	FWH_DENY_READ  = 4,
-};
-
-static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
-	enum fwh_lock_state state)
-{
-	struct map_info *map = mtd->priv;
-	unsigned long start = ofs;
-	unsigned long end = start + len -1;
-
-	/* FIXME do I need to guard against concurrency here? */
-	/* round down to 64K boundaries */
-	start = start & ~0xFFFF;
-	end = end & ~0xFFFF;
-	while (start <= end) {
-		unsigned long ctrl_addr;
-		ctrl_addr = addr(map, start) - 0x400000 + 2;
-		writeb(state, ctrl_addr);
-		start = start + 0x10000;
-	}
-	return 0;
-}
-
-static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
-}
-
-static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	return ich2rom_set_lock_state(mtd, ofs, len, 0);
-}
-
-static int __devinit ich2rom_init_one (struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	u16 word;
-	struct ich2rom_map_info *info = &ich2rom_map;
-	unsigned long map_size;
-
-	/* For now I just handle the ich2 and I assume there
-	 * are not a lot of resources up at the top of the address
-	 * space.  It is possible to handle other devices in the
-	 * top 16MB but it is very painful.  Also since
-	 * you can only really attach a FWH to an ICH2 there
-	 * a number of simplifications you can make.
-	 *
-	 * Also you can page firmware hubs if an 8MB window isn't enough 
-	 * but don't currently handle that case either.
-	 */
-
-#if RESERVE_MEM_REGION
-	/* Some boards have this reserved and I haven't found a good work
-	 * around to say I know what I'm doing!
-	 */
-	if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) {
-		printk(KERN_ERR "ich2rom: cannot reserve rom window\n");
-		goto err_out_none;
-	}
-#endif /* RESERVE_MEM_REGION */
-	
-	/* Enable writes through the rom window */
-	pci_read_config_word(pdev, BIOS_CNTL, &word);
-	if (!(word & 1)  && (word & (1<<1))) {
-		/* The BIOS will generate an error if I enable
-		 * this device, so don't even try.
-		 */
-		printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n");
-		goto err_out_none;
-	}
-	pci_write_config_word(pdev, BIOS_CNTL, word | 1);
-
-
-	/* Map the firmware hub into my address space. */
-	/* Does this use to much virtual address space? */
-	info->window_addr = (unsigned long)ioremap(
-		ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
-	if (!info->window_addr) {
-		printk(KERN_ERR "Failed to ioremap\n");
-		goto err_out_free_mmio_region;
-	}
-
-	/* For now assume the firmware has setup all relevant firmware
-	 * windows.  We don't have enough information to handle this case
-	 * intelligently.
-	 */
-
-	/* FIXME select the firmware hub and enable a window to it. */
-
-	info->mtd = NULL;
-	info->map.map_priv_1 = 	info->window_addr;
-
-	map_size = ICH2_FWH_REGION_SIZE;
-	while(!info->mtd && (map_size > 0)) {
-		info->map.size = map_size;
-		info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map);
-		map_size -= 512*1024;
-	}
-	if (!info->mtd) {
-		goto err_out_iounmap;
-	}
-	/* I know I can only be a firmware hub here so put
-	 * in the special lock and unlock routines.
-	 */
-	info->mtd->lock = ich2rom_lock;
-	info->mtd->unlock = ich2rom_unlock;
-		
-	info->mtd->owner = THIS_MODULE;
-	add_mtd_device(info->mtd);
-	return 0;
-
-err_out_iounmap:
-	iounmap((void *)(info->window_addr));
-err_out_free_mmio_region:
-#if RESERVE_MEM_REGION
-	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
-#endif
-err_out_none:
-	return -ENODEV;
-}
-
-
-static void __devexit ich2rom_remove_one (struct pci_dev *pdev)
-{
-	struct ich2rom_map_info *info = &ich2rom_map;
-	u16 word;
-
-	del_mtd_device(info->mtd);
-	map_destroy(info->mtd);
-	info->mtd = NULL;
-	info->map.map_priv_1 = 0;
-
-	iounmap((void *)(info->window_addr));
-	info->window_addr = 0;
-
-	/* Disable writes through the rom window */
-	pci_read_config_word(pdev, BIOS_CNTL, &word);
-	pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
-
-#if RESERVE_MEM_REGION	
-	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
-#endif
-}
-
-static struct pci_device_id ich2rom_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
-	  PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
-	  PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
-	  PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
-
-#if 0
-static struct pci_driver ich2rom_driver = {
-	.name =		"ich2rom",
-	.id_table =	ich2rom_pci_tbl,
-	.probe =	ich2rom_init_one,
-	.remove =	ich2rom_remove_one,
-};
-#endif
-
-static struct pci_dev *mydev;
-int __init init_ich2rom(void)
-{
-	struct pci_dev *pdev;
-	struct pci_device_id *id;
-	pdev = NULL;
-	for(id = ich2rom_pci_tbl; id->vendor; id++) {
-		pdev = pci_find_device(id->vendor, id->device, NULL);
-		if (pdev) {
-			break;
-		}
-	}
-	if (pdev) {
-		mydev = pdev;
-		return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
-	}
-	return -ENXIO;
-#if 0
-	return pci_module_init(&ich2rom_driver);
-#endif
-}
-
-static void __exit cleanup_ich2rom(void)
-{
-	ich2rom_remove_one(mydev);
-}
-
-module_init(init_ich2rom);
-module_exit(cleanup_ich2rom);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
-MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge");
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -205,9 +205,9 @@ intel_dc21285_init(struct pci_dev *dev, 
 		 * or simply enabling it?
 		 */
 		if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
-		     PCI_ROM_ADDRESS_ENABLE)) {
+				    IORESOURCE_ROM_ENABLE)) {
 		     	u32 val;
-			pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE;
+			pci_resource_flags(dev, PCI_ROM_RESOURCE) |= IORESOURCE_ROM_ENABLE;
 			pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
 			val |= PCI_ROM_ADDRESS_ENABLE;
 			pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
@@ -241,7 +241,7 @@ intel_dc21285_exit(struct pci_dev *dev, 
 	/*
 	 * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
 	 */
-	pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~IORESOURCE_ROM_ENABLE;
 	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
 	val &= ~PCI_ROM_ADDRESS_ENABLE;
 	pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -403,7 +403,7 @@ static int __exit sa1100_mtd_remove(stru
 }
 
 #ifdef CONFIG_PM
-static int sa1100_mtd_suspend(struct device *dev, u32 state, u32 level)
+static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct sa_info *info = dev_get_drvdata(dev);
 	int ret = 0;
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
--- a/drivers/mtd/maps/scx200_docflash.c
+++ b/drivers/mtd/maps/scx200_docflash.c
@@ -92,17 +92,16 @@ static int __init init_scx200_docflash(v
 				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
 				      NULL)) == NULL)
 		return -ENODEV;
-	
-	if (!scx200_cb_probe(SCx200_CB_BASE)) {
-		printk(KERN_WARNING NAME ": no configuration block found\n");
+
+	/* check that we have found the configuration block */
+	if (!scx200_cb_present())
 		return -ENODEV;
-	}
 
 	if (probe) {
 		/* Try to use the present flash mapping if any */
 		pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
 		pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
-		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+		pmr = inl(scx200_cb_base + SCx200_PMR);
 
 		if (base == 0
 		    || (ctrl & 0x07000000) != 0x07000000
@@ -155,14 +154,14 @@ static int __init init_scx200_docflash(v
 		
 		pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
 		pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
-		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+		pmr = inl(scx200_cb_base + SCx200_PMR);
 		
 		if (width == 8) {
 			pmr &= ~(1<<6);
 		} else {
 			pmr |= (1<<6);
 		}
-		outl(pmr, SCx200_CB_BASE + SCx200_PMR);
+		outl(pmr, scx200_cb_base + SCx200_PMR);
 	}
 	
        	printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -285,12 +285,12 @@ static int mtd_ioctl(struct inode *inode
 
 	size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
 	if (cmd & IOC_IN) {
-		ret = verify_area(VERIFY_READ, argp, size);
-		if (ret) return ret;
+		if (!access_ok(VERIFY_READ, argp, size))
+			return -EFAULT;
 	}
 	if (cmd & IOC_OUT) {
-		ret = verify_area(VERIFY_WRITE, argp, size);
-		if (ret) return ret;
+		if (!access_ok(VERIFY_WRITE, argp, size))
+			return -EFAULT;
 	}
 	
 	switch (cmd) {
@@ -389,7 +389,8 @@ static int mtd_ioctl(struct inode *inode
 		if (!mtd->write_oob)
 			ret = -EOPNOTSUPP;
 		else
-			ret = verify_area(VERIFY_READ, buf.ptr, buf.length);
+			ret = access_ok(VERIFY_READ, buf.ptr,
+					buf.length) ? 0 : EFAULT;
 
 		if (ret)
 			return ret;
@@ -428,7 +429,8 @@ static int mtd_ioctl(struct inode *inode
 		if (!mtd->read_oob)
 			ret = -EOPNOTSUPP;
 		else
-			ret = verify_area(VERIFY_WRITE, buf.ptr, buf.length);
+			ret = access_ok(VERIFY_WRITE, buf.ptr,
+					buf.length) ? 0 : -EFAULT;
 
 		if (ret)
 			return ret;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -103,8 +103,15 @@ static int __init do_el2_probe(struct ne
 	return -ENXIO;
 
     for (addr = addrs; *addr; addr++) {
-	unsigned base_bits = isa_readb(*addr);
-	int i = ffs(base_bits) - 1;
+	void __iomem *p = ioremap(*addr, 1);
+	unsigned base_bits;
+	int i;
+
+	if (!p)
+		continue;
+	base_bits = readb(p);
+	iounmap(p);
+	i = ffs(base_bits) - 1;
 	if (i == -1 || base_bits != (1 << i))
 	    continue;
 	if (el2_probe1(dev, netcard_portlist[i]) == 0)
@@ -145,6 +152,8 @@ static void cleanup_card(struct net_devi
 {
 	/* NB: el2_close() handles free_irq */
 	release_region(dev->base_addr, EL2_IO_EXTENT);
+	if (ei_status.mem)
+		iounmap(ei_status.mem);
 }
 
 #ifndef MODULE
@@ -262,42 +271,46 @@ el2_probe1(struct net_device *dev, int i
     if ((membase_reg & 0xf0) == 0) {
 	dev->mem_start = 0;
 	ei_status.name = "3c503-PIO";
+	ei_status.mem = NULL;
     } else {
 	dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
 	    ((membase_reg & 0xA0) ? 0x4000 : 0);
-
 #define EL2_MEMSIZE (EL2_MB1_STOP_PG - EL2_MB1_START_PG)*256
+	ei_status.mem = ioremap(dev->mem_start, EL2_MEMSIZE);
+
 #ifdef EL2MEMTEST
 	/* This has never found an error, but someone might care.
 	   Note that it only tests the 2nd 8kB on 16kB 3c503/16
 	   cards between card addr. 0x2000 and 0x3fff. */
 	{			/* Check the card's memory. */
-	    unsigned long mem_base = dev->mem_start;
+	    void __iomem *mem_base = ei_status.mem;
 	    unsigned int test_val = 0xbbadf00d;
-	    isa_writel(0xba5eba5e, mem_base);
+	    writel(0xba5eba5e, mem_base);
 	    for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) {
-		isa_writel(test_val, mem_base + i);
-		if (isa_readl(mem_base) != 0xba5eba5e
-		    || isa_readl(mem_base + i) != test_val) {
+		writel(test_val, mem_base + i);
+		if (readl(mem_base) != 0xba5eba5e
+		    || readl(mem_base + i) != test_val) {
 		    printk("3c503: memory failure or memory address conflict.\n");
 		    dev->mem_start = 0;
 		    ei_status.name = "3c503-PIO";
+		    iounmap(mem_base);
+		    ei_status.mem = NULL;
 		    break;
 		}
 		test_val += 0x55555555;
-		isa_writel(0, mem_base + i);
+		writel(0, mem_base + i);
 	    }
 	}
 #endif  /* EL2MEMTEST */
 
 	if (dev->mem_start)
-		dev->mem_end = ei_status.rmem_end = dev->mem_start + EL2_MEMSIZE;
+		dev->mem_end = dev->mem_start + EL2_MEMSIZE;
 
 	if (wordlength) {	/* No Tx pages to skip over to get to Rx */
-		ei_status.rmem_start = dev->mem_start;
+		ei_status.priv = 0;
 		ei_status.name = "3c503/16";
 	} else {
-		ei_status.rmem_start = TX_PAGES*256 + dev->mem_start;
+		ei_status.priv = TX_PAGES * 256;
 		ei_status.name = "3c503";
 	}
     }
@@ -471,16 +484,16 @@ el2_block_output(struct net_device *dev,
     unsigned short int *wrd;
     int boguscount;		/* timeout counter */
     unsigned short word;	/* temporary for better machine code */
+    void __iomem *base = ei_status.mem;
 
     if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
 	outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
     else
 	outb(EGACFR_NORM, E33G_GACFR);
 
-    if (dev->mem_start) {	/* Shared memory transfer */
-	unsigned long dest_addr = dev->mem_start +
-	    ((start_page - ei_status.tx_start_page) << 8);
-	isa_memcpy_toio(dest_addr, buf, count);
+    if (base) {	/* Shared memory transfer */
+	memcpy_toio(base + ((start_page - ei_status.tx_start_page) << 8),
+			buf, count);
 	outb(EGACFR_NORM, E33G_GACFR);	/* Back to bank1 in case on bank0 */
 	return;
     }
@@ -541,11 +554,12 @@ static void
 el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
     int boguscount;
-    unsigned long hdr_start = dev->mem_start + ((ring_page - EL2_MB1_START_PG)<<8);
+    void __iomem *base = ei_status.mem;
     unsigned short word;
 
-    if (dev->mem_start) {       /* Use the shared memory. */
-	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+    if (base) {       /* Use the shared memory. */
+	void __iomem *hdr_start = base + ((ring_page - EL2_MB1_START_PG)<<8);
+	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 	hdr->count = le16_to_cpu(hdr->count);
 	return;
     }
@@ -581,23 +595,22 @@ static void
 el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
     int boguscount = 0;
+    void __iomem *base = ei_status.mem;
     unsigned short int *buf;
     unsigned short word;
 
-    int end_of_ring = ei_status.rmem_end;
-
     /* Maybe enable shared memory just be to be safe... nahh.*/
-    if (dev->mem_start) {	/* Use the shared memory. */
+    if (base) {	/* Use the shared memory. */
 	ring_offset -= (EL2_MB1_START_PG<<8);
-	if (dev->mem_start + ring_offset + count > end_of_ring) {
+	if (ring_offset + count > EL2_MEMSIZE) {
 	    /* We must wrap the input move. */
-	    int semi_count = end_of_ring - (dev->mem_start + ring_offset);
-	    isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
+	    int semi_count = EL2_MEMSIZE - ring_offset;
+	    memcpy_fromio(skb->data, base + ring_offset, semi_count);
 	    count -= semi_count;
-	    isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+	    memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
+		eth_io_copy_and_sum(skb, base + ring_offset, count, 0);
 	}
 	return;
     }
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -32,7 +32,7 @@
  *              Linux 1.3.0 changes by
  *                      Alan Cox <Alan.Cox@linux.org>
  *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <Philip.Blundell@pobox.com>
+ *                      Philip Blundell <philb@gnu.org>
  *              Multicard/soft configurable dma channel/rev 2 hardware support
  *                      by Christopher Collins <ccollins@pcug.org.au>
  *		Ethtool support (jgarzik), 11/17/2001
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -214,7 +214,7 @@ static void el3_poll_controller(struct n
 #endif
 
 #ifdef CONFIG_EISA
-struct eisa_device_id el3_eisa_ids[] = {
+static struct eisa_device_id el3_eisa_ids[] = {
 		{ "TCM5092" },
 		{ "TCM5093" },
 		{ "" }
@@ -222,7 +222,7 @@ struct eisa_device_id el3_eisa_ids[] = {
 
 static int el3_eisa_probe (struct device *device);
 
-struct eisa_driver el3_eisa_driver = {
+static struct eisa_driver el3_eisa_driver = {
 		.id_table = el3_eisa_ids,
 		.driver   = {
 				.name    = "3c509",
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -86,6 +86,7 @@ static int max_interrupt_work = 20;
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 /* "Knobs" for adjusting internal parameters. */
 /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
@@ -472,7 +473,7 @@ static int check_device(unsigned ioaddr)
 
 static void cleanup_card(struct net_device *dev)
 {
-	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	list_del_init(&vp->list);
 	if (dev->dma)
 		free_dma(dev->dma);
@@ -570,7 +571,7 @@ no_pnp:
 static void corkscrew_setup(struct net_device *dev, int ioaddr,
 			    struct pnp_dev *idev, int card_number)
 {
-	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	unsigned int eeprom[0x40], checksum = 0;	/* EEPROM contents */
 	int i;
 	int irq;
@@ -696,8 +697,7 @@ static void corkscrew_setup(struct net_d
 static int corkscrew_open(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	union wn3_config config;
 	int i;
 
@@ -862,7 +862,7 @@ static void corkscrew_timer(unsigned lon
 {
 #ifdef AUTOMEDIA
 	struct net_device *dev = (struct net_device *) data;
-	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 	int ok = 0;
@@ -954,8 +954,7 @@ static void corkscrew_timer(unsigned lon
 static void corkscrew_timeout(struct net_device *dev)
 {
 	int i;
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING
@@ -994,8 +993,7 @@ static void corkscrew_timeout(struct net
 static int corkscrew_start_xmit(struct sk_buff *skb,
 				struct net_device *dev)
 {
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Block a timer-based transmit from overlapping. */
@@ -1123,14 +1121,13 @@ static irqreturn_t corkscrew_interrupt(i
 {
 	/* Use the now-standard shared IRQ implementation. */
 	struct net_device *dev = dev_id;
-	struct corkscrew_private *lp;
+	struct corkscrew_private *lp = netdev_priv(dev);
 	int ioaddr, status;
 	int latency;
 	int i = max_interrupt_work;
 
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
-	lp = (struct corkscrew_private *) dev->priv;
 
 	spin_lock(&lp->lock);
 	
@@ -1262,7 +1259,7 @@ static irqreturn_t corkscrew_interrupt(i
 
 static int corkscrew_rx(struct net_device *dev)
 {
-	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int i;
 	short rx_status;
@@ -1329,8 +1326,7 @@ static int corkscrew_rx(struct net_devic
 
 static int boomerang_rx(struct net_device *dev)
 {
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int entry = vp->cur_rx % RX_RING_SIZE;
 	int ioaddr = dev->base_addr;
 	int rx_status;
@@ -1420,8 +1416,7 @@ static int boomerang_rx(struct net_devic
 
 static int corkscrew_close(struct net_device *dev)
 {
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int i;
 
@@ -1476,7 +1471,7 @@ static int corkscrew_close(struct net_de
 
 static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
 {
-	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 	unsigned long flags;
 
 	if (netif_running(dev)) {
@@ -1496,8 +1491,7 @@ static struct net_device_stats *corkscre
 	*/
 static void update_stats(int ioaddr, struct net_device *dev)
 {
-	struct corkscrew_private *vp =
-	    (struct corkscrew_private *) dev->priv;
+	struct corkscrew_private *vp = netdev_priv(dev);
 
 	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
 	/* Switch to the stats window, and read everything. */
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -197,7 +197,7 @@ struct mca_adapters_t {
 	char		*name;
 };
 
-const struct mca_adapters_t mc32_adapters[] = {
+static const struct mca_adapters_t mc32_adapters[] = {
 	{ 0x0041, "3COM EtherLink MC/32" },
 	{ 0x8EF5, "IBM High Performance Lan Adapter" },
 	{ 0x0000, NULL }
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -964,7 +964,7 @@ static void poll_vortex(struct net_devic
 
 #ifdef CONFIG_PM
 
-static int vortex_suspend (struct pci_dev *pdev, u32 state)
+static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -1581,7 +1581,8 @@ vortex_up(struct net_device *dev)
 
 	if (VORTEX_PCI(vp)) {
 		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
-		pci_restore_state(VORTEX_PCI(vp));
+		if (vp->pm_state_valid)
+			pci_restore_state(VORTEX_PCI(vp));
 		pci_enable_device(VORTEX_PCI(vp));
 	}
 
@@ -2741,6 +2742,7 @@ vortex_down(struct net_device *dev, int 
 		outl(0, ioaddr + DownListPtr);
 
 	if (final_down && VORTEX_PCI(vp)) {
+		vp->pm_state_valid = 1;
 		pci_save_state(VORTEX_PCI(vp));
 		acpi_set_WOL(dev);
 	}
@@ -3243,9 +3245,10 @@ static void acpi_set_WOL(struct net_devi
 		outw(RxEnable, ioaddr + EL3_CMD);
 
 		pci_enable_wake(VORTEX_PCI(vp), 0, 1);
+
+		/* Change the power state to D3; RxEnable doesn't take effect. */
+		pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
 	}
-	/* Change the power state to D3; RxEnable doesn't take effect. */
-	pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
 }
 
 
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1824,7 +1824,7 @@ static void cp_remove_one (struct pci_de
 }
 
 #ifdef CONFIG_PM
-static int cp_suspend (struct pci_dev *pdev, u32 state)
+static int cp_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev;
 	struct cp_private *cp;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -389,8 +389,14 @@ enum rx_mode_bits {
 
 /* Bits in TxConfig. */
 enum tx_config_bits {
-	TxIFG1 = (1 << 25),	/* Interframe Gap Time */
-	TxIFG0 = (1 << 24),	/* Enabling these bits violates IEEE 802.3 */
+
+        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+        TxIFGShift = 24,
+        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
 	TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
 	TxCRC = (1 << 16),	/* DISABLE appending CRC to end of Tx packets */
 	TxClearAbt = (1 << 0),	/* Clear abort (WO) */
@@ -723,17 +729,14 @@ static const unsigned int rtl8139_rx_con
 #endif
 
 static const unsigned int rtl8139_tx_config =
-	(TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+	TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
 
 static void __rtl8139_cleanup_dev (struct net_device *dev)
 {
-	struct rtl8139_private *tp;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev;
 
 	assert (dev != NULL);
-	assert (dev->priv != NULL);
-
-	tp = dev->priv;
 	assert (tp->pci_dev != NULL);
 	pdev = tp->pci_dev;
 
@@ -746,7 +749,6 @@ static void __rtl8139_cleanup_dev (struc
 	pci_release_regions (pdev);
 
 	free_netdev(dev);
-
 	pci_set_drvdata (pdev, NULL);
 }
 
@@ -775,7 +777,7 @@ static int __devinit rtl8139_init_board 
 	struct net_device *dev;
 	struct rtl8139_private *tp;
 	u8 tmp8;
-	int rc;
+	int rc, disable_dev_on_err = 0;
 	unsigned int i;
 	unsigned long pio_start, pio_end, pio_flags, pio_len;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
@@ -785,7 +787,7 @@ static int __devinit rtl8139_init_board 
 
 	*dev_out = NULL;
 
-	/* dev and dev->priv zeroed in alloc_etherdev */
+	/* dev and priv zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
 		printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
@@ -794,7 +796,7 @@ static int __devinit rtl8139_init_board 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	tp->pci_dev = pdev;
 
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
@@ -847,6 +849,7 @@ static int __devinit rtl8139_init_board 
 	rc = pci_request_regions (pdev, "8139too");
 	if (rc)
 		goto err_out;
+	disable_dev_on_err = 1;
 
 	/* enable PCI bus-mastering */
 	pci_set_master (pdev);
@@ -932,6 +935,8 @@ match:
 
 err_out:
 	__rtl8139_cleanup_dev (dev);
+	if (disable_dev_on_err)
+		pci_disable_device (pdev);
 	return rc;
 }
 
@@ -976,8 +981,8 @@ static int __devinit rtl8139_init_one (s
 		return i;
 
 	assert (dev != NULL);
-	tp = dev->priv;
-	assert (tp != NULL);
+	tp = netdev_priv(dev);
+
 	ioaddr = tp->mmio_addr;
 	assert (ioaddr != NULL);
 
@@ -1010,8 +1015,8 @@ static int __devinit rtl8139_init_one (s
 
 	dev->irq = pdev->irq;
 
-	/* dev->priv/tp zeroed and aligned in alloc_etherdev */
-	tp = dev->priv;
+	/* tp zeroed and aligned in alloc_etherdev */
+	tp = netdev_priv(dev);
 
 	/* note: tp->chipset set in rtl8139_init_board */
 	tp->drv_flags = board_info[ent->driver_data].hw_flags;
@@ -1109,6 +1114,7 @@ static int __devinit rtl8139_init_one (s
 
 err_out:
 	__rtl8139_cleanup_dev (dev);
+	pci_disable_device (pdev);
 	return i;
 }
 
@@ -1116,15 +1122,13 @@ err_out:
 static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct rtl8139_private *np;
 
 	assert (dev != NULL);
-	np = dev->priv;
-	assert (np != NULL);
 
 	unregister_netdev (dev);
 
 	__rtl8139_cleanup_dev (dev);
+	pci_disable_device (pdev);
 }
 
 
@@ -1234,7 +1238,7 @@ static void mdio_sync (void *mdio_addr)
 
 static int mdio_read (struct net_device *dev, int phy_id, int location)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	int retval = 0;
 #ifdef CONFIG_8139TOO_8129
 	void *mdio_addr = tp->mmio_addr + Config4;
@@ -1276,7 +1280,7 @@ static int mdio_read (struct net_device 
 static void mdio_write (struct net_device *dev, int phy_id, int location,
 			int value)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 #ifdef CONFIG_8139TOO_8129
 	void *mdio_addr = tp->mmio_addr + Config4;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
@@ -1319,7 +1323,7 @@ static void mdio_write (struct net_devic
 
 static int rtl8139_open (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	int retval;
 	void *ioaddr = tp->mmio_addr;
 
@@ -1367,7 +1371,7 @@ static int rtl8139_open (struct net_devi
 
 static void rtl_check_media (struct net_device *dev, unsigned int init_media)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 
 	if (tp->phys[0] >= 0) {
 		mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
@@ -1377,7 +1381,7 @@ static void rtl_check_media (struct net_
 /* Start the hardware at open or resume. */
 static void rtl8139_hw_start (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u32 i;
 	u8 tmp;
@@ -1399,8 +1403,6 @@ static void rtl8139_hw_start (struct net
 
 	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
 	RTL_W32 (RxConfig, tp->rx_config);
-
-	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, rtl8139_tx_config);
 
 	tp->cur_rx = 0;
@@ -1446,7 +1448,7 @@ static void rtl8139_hw_start (struct net
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void rtl8139_init_ring (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	int i;
 
 	tp->cur_rx = 0;
@@ -1613,7 +1615,7 @@ static inline void rtl8139_thread_iter (
 static int rtl8139_thread (void *data)
 {
 	struct net_device *dev = data;
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	unsigned long timeout;
 
 	daemonize("%s", dev->name);
@@ -1645,7 +1647,7 @@ static int rtl8139_thread (void *data)
 
 static void rtl8139_start_thread(struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 
 	tp->thr_pid = -1;
 	tp->twistie = 0;
@@ -1673,7 +1675,7 @@ static inline void rtl8139_tx_clear (str
 
 static void rtl8139_tx_timeout (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	int i;
 	u8 tmp8;
@@ -1718,7 +1720,7 @@ static void rtl8139_tx_timeout (struct n
 
 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned int entry;
 	unsigned int len = skb->len;
@@ -1766,7 +1768,6 @@ static void rtl8139_tx_interrupt (struct
 	unsigned long dirty_tx, tx_left;
 
 	assert (dev != NULL);
-	assert (tp != NULL);
 	assert (ioaddr != NULL);
 
 	dirty_tx = tp->dirty_tx;
@@ -2125,7 +2126,7 @@ static void rtl8139_weird_interrupt (str
 
 static int rtl8139_poll(struct net_device *dev, int *budget)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	int orig_budget = min(*budget, dev->quota);
 	int done = 1;
@@ -2163,7 +2164,7 @@ static irqreturn_t rtl8139_interrupt (in
 			       struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u16 status, ackstat;
 	int link_changed = 0; /* avoid bogus "uninit" warning */
@@ -2239,7 +2240,7 @@ static void rtl8139_poll_controller(stru
 
 static int rtl8139_close (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	int ret = 0;
 	unsigned long flags;
@@ -2302,7 +2303,7 @@ static int rtl8139_close (struct net_dev
    other threads or interrupts aren't messing with the 8139.  */
 static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	void *ioaddr = np->mmio_addr;
 
 	spin_lock_irq(&np->lock);
@@ -2336,7 +2337,7 @@ static void rtl8139_get_wol(struct net_d
    aren't messing with the 8139.  */
 static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	void *ioaddr = np->mmio_addr;
 	u32 support;
 	u8 cfg3, cfg5;
@@ -2376,7 +2377,7 @@ static int rtl8139_set_wol(struct net_de
 
 static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
 	strcpy(info->bus_info, pci_name(np->pci_dev));
@@ -2385,7 +2386,7 @@ static void rtl8139_get_drvinfo(struct n
 
 static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	spin_lock_irq(&np->lock);
 	mii_ethtool_gset(&np->mii, cmd);
 	spin_unlock_irq(&np->lock);
@@ -2394,7 +2395,7 @@ static int rtl8139_get_settings(struct n
 
 static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	int rc;
 	spin_lock_irq(&np->lock);
 	rc = mii_ethtool_sset(&np->mii, cmd);
@@ -2404,25 +2405,25 @@ static int rtl8139_set_settings(struct n
 
 static int rtl8139_nway_reset(struct net_device *dev)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	return mii_nway_restart(&np->mii);
 }
 
 static u32 rtl8139_get_link(struct net_device *dev)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	return mii_link_ok(&np->mii);
 }
 
 static u32 rtl8139_get_msglevel(struct net_device *dev)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	return np->msg_enable;
 }
 
 static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	np->msg_enable = datum;
 }
 
@@ -2433,13 +2434,13 @@ static void rtl8139_set_msglevel(struct 
 #else
 static int rtl8139_get_regs_len(struct net_device *dev)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	return np->regs_len;
 }
 
 static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 
 	regs->version = RTL_REGS_VER;
 
@@ -2456,7 +2457,7 @@ static int rtl8139_get_stats_count(struc
 
 static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 
 	data[0] = np->xstats.early_rx;
 	data[1] = np->xstats.tx_buf_mapped;
@@ -2488,7 +2489,7 @@ static struct ethtool_ops rtl8139_ethtoo
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct rtl8139_private *np = dev->priv;
+	struct rtl8139_private *np = netdev_priv(dev);
 	int rc;
 
 	if (!netif_running(dev))
@@ -2504,7 +2505,7 @@ static int netdev_ioctl(struct net_devic
 
 static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
@@ -2523,7 +2524,7 @@ static struct net_device_stats *rtl8139_
 
 static void __set_rx_mode (struct net_device *dev)
 {
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
@@ -2572,7 +2573,7 @@ static void __set_rx_mode (struct net_de
 static void rtl8139_set_rx_mode (struct net_device *dev)
 {
 	unsigned long flags;
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 
 	spin_lock_irqsave (&tp->lock, flags);
 	__set_rx_mode(dev);
@@ -2581,10 +2582,10 @@ static void rtl8139_set_rx_mode (struct 
 
 #ifdef CONFIG_PM
 
-static int rtl8139_suspend (struct pci_dev *pdev, u32 state)
+static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct rtl8139_private *tp = dev->priv;
+	struct rtl8139_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -999,6 +999,7 @@ static void ethdev_setup(struct net_devi
 
 /**
  * alloc_ei_netdev - alloc_etherdev counterpart for 8390
+ * @size: extra bytes to allocate
  *
  * Allocate 8390-specific net_device.
  */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -44,19 +44,17 @@ config DUMMY
 config BONDING
 	tristate "Bonding driver support"
 	depends on NETDEVICES
+	depends on INET
 	---help---
 	  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
 	  Channels together. This is called 'Etherchannel' by Cisco,
-	  'Trunking' by Sun, and 'Bonding' in Linux.
+	  'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux.
 
-	  If you have two Ethernet connections to some other computer, you can
-	  make them behave like one double speed connection using this driver.
-	  Naturally, this has to be supported at the other end as well, either
-	  with a similar Bonding Linux driver, a Cisco 5500 switch or a
-	  SunTrunking SunSoft driver.
+	  The driver supports multiple bonding modes to allow for both high
+	  perfomance and high availability operation.
 
-	  This is similar to the EQL driver, but it merges Ethernet segments
-	  instead of serial lines.
+	  Refer to <file:Documentation/networking/bonding.txt> for more
+	  information.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called bonding.
@@ -105,29 +103,6 @@ config TUN
 
 	  If you don't know what to use this for, you don't need it.
 
-config ETHERTAP
-	tristate "Ethertap network tap"
-	depends on NETDEVICES && EXPERIMENTAL && NETLINK_DEV
-	---help---
-	  If you say Y here (and have said Y to "Kernel/User network link
-	  driver", above) and create a character special file /dev/tap0 with
-	  major number 36 and minor number 16 using mknod ("man mknod"), you
-	  will be able to have a user space program read and write raw
-	  Ethernet frames from/to that special file.  tap0 can be configured
-	  with ifconfig and route like any other Ethernet device but it is not
-	  connected to any physical LAN; everything written by the user to
-	  /dev/tap0 is treated by the kernel as if it had come in from a LAN
-	  to the device tap0; everything the kernel wants to send out over the
-	  device tap0 can instead be read by the user from /dev/tap0: the user
-	  mode program replaces the LAN that would be attached to an ordinary
-	  Ethernet device. Please read the file
-	  <file:Documentation/networking/ethertap.txt> for more information.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ethertap.
-
-	  If you don't know what to use this for, you don't need it.
-
 config NET_SB1000
 	tristate "General Instruments Surfboard 1000"
 	depends on NETDEVICES && PNP
@@ -161,7 +136,7 @@ endif
 #
 
 menu "Ethernet (10 or 100Mbit)"
-	depends on NETDEVICES
+	depends on NETDEVICES && !UML
 
 config NET_ETHERNET
 	bool "Ethernet (10 or 100Mbit)"
@@ -445,7 +420,7 @@ config LASI_82596
 
 config MIPS_JAZZ_SONIC
 	tristate "MIPS JAZZ onboard SONIC Ethernet support"
-	depends on NET_ETHERNET && MIPS_JAZZ
+	depends on NET_ETHERNET && MACH_JAZZ
 	help
 	  This is the driver for the onboard card of MIPS Magnum 4000,
 	  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
@@ -470,7 +445,7 @@ config NET_SB1250_MAC
 
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
-	depends on NET_ETHERNET && SGI_IP27
+	depends on NET_ETHERNET && PCI && SGI_IP27
 	select CRC32
 	select MII
 	help
@@ -614,7 +589,7 @@ config EL2
 
 config ELPLUS
 	tristate "3c505 \"EtherLink Plus\" support"
-	depends on NET_VENDOR_3COM && ISA
+	depends on NET_VENDOR_3COM && ISA && ISA_DMA_API
 	---help---
 	  Information about this network (Ethernet) card can be found in
 	  <file:Documentation/networking/3c505.txt>.  If you have a card of
@@ -638,7 +613,7 @@ config EL16
 	  will be called 3c507.
 
 config EL3
-	tristate "3c509/3c529 (MCA)/3c569B (98)/3c579 \"EtherLink III\" support"
+	tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
 	depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
 	---help---
 	  If you have a network (Ethernet) card belonging to the 3Com
@@ -655,7 +630,7 @@ config EL3
 
 config 3C515
 	tristate "3c515 ISA \"Fast EtherLink\""
-	depends on NET_VENDOR_3COM && (ISA || EISA)
+	depends on NET_VENDOR_3COM && (ISA || EISA) && ISA_DMA_API
 	help
 	  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
 	  network card, say Y and read the Ethernet-HOWTO, available from
@@ -733,7 +708,7 @@ config TYPHOON
 
 config LANCE
 	tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
-	depends on NET_ETHERNET && ISA
+	depends on NET_ETHERNET && ISA && ISA_DMA_API
 	help
 	  If you have a network (Ethernet) card of this type, say Y and read
 	  the Ethernet-HOWTO, available from
@@ -819,7 +794,7 @@ config SMC91X
 	tristate "SMC 91C9x/91C1xxx support"
 	select CRC32
 	select MII
-	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R)
+	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH)
 	help
 	  This is a driver for SMC's 91x series of Ethernet chipsets,
 	  including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -889,7 +864,7 @@ config NI52
 
 config NI65
 	tristate "NI6510 support"
-	depends on NET_VENDOR_RACAL && ISA
+	depends on NET_VENDOR_RACAL && ISA && ISA_DMA_API
 	help
 	  If you have a network (Ethernet) card of this type, say Y and read
 	  the Ethernet-HOWTO, available from
@@ -902,7 +877,7 @@ config NI65
 source "drivers/net/tulip/Kconfig"
 
 config AT1700
-	tristate "AT1700/1720/RE1000Plus(C-Bus) support (EXPERIMENTAL)"
+	tristate "AT1700/1720 support (EXPERIMENTAL)"
 	depends on NET_ETHERNET && (ISA || MCA_LEGACY) && EXPERIMENTAL
 	select CRC32
 	---help---
@@ -1097,7 +1072,7 @@ config NE2000
 
 config ZNET
 	tristate "Zenith Z-Note support (EXPERIMENTAL)"
-	depends on NET_ISA && EXPERIMENTAL
+	depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API
 	help
 	  The Zenith Z-Note notebook computer has a built-in network
 	  (Ethernet) card, and this is the Linux driver for it. Note that the
@@ -1428,23 +1403,6 @@ config E100
 	  <file:Documentation/networking/net-modules.txt>.  The module
 	  will be called e100.
 
-config E100_NAPI
-	bool "Use Rx Polling (NAPI)"
-	depends on E100
-	help
-	  NAPI is a new driver API designed to reduce CPU and interrupt load
-	  when the driver is receiving lots of packets from the card. It is
-	  still somewhat experimental and thus not yet enabled by default.
-
-	  If your estimated Rx load is 10kpps or more, or if the card will be
-	  deployed on potentially unfriendly networks (e.g. in a firewall),
-	  then say Y here.
-
-	  See <file:Documentation/networking/NAPI_HOWTO.txt> for more
-	  information.
-
-	  If in doubt, say N.
-
 config LNE390
 	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
 	depends on NET_PCI && EISA && EXPERIMENTAL
@@ -1597,6 +1555,7 @@ config SIS900
 	tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
 	depends on NET_PCI && PCI
 	select CRC32
+	select MII
 	---help---
 	  This is a driver for the Fast Ethernet PCI network cards based on
 	  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
@@ -1780,14 +1739,6 @@ config DECLANCE
 	  DEC (now Compaq) based on the AMD Lance chipset, including the
 	  DEPCA series.  (This chipset is better known via the NE2100 cards.)
 
-config BAGETLANCE
-	tristate "Baget AMD LANCE support"
-	depends on NET_ETHERNET && BAGET_MIPS
-	help
-	  Say Y to enable kernel support for AMD Lance Ethernet cards on the
-	  MIPS-32-based Baget embedded system.  This chipset is better known
-	  via the NE2100 cards.
-
 config 68360_ENET
 	bool "Motorola 68360 ethernet controller"
 	depends on M68360
@@ -1818,7 +1769,7 @@ endmenu
 #
 
 menu "Ethernet (1000 Mbit)"
-	depends on NETDEVICES
+	depends on NETDEVICES && !UML
 
 config ACENIC
 	tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support"
@@ -2081,9 +2032,18 @@ config TIGON3
 	  To compile this driver as a module, choose M here: the module
 	  will be called tg3.  This is recommended.
 
+config BNX2
+	tristate "Broadcom NetXtremeII support"
+	depends on PCI
+	help
+	  This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bnx2.  This is recommended.
+
 config GIANFAR
 	tristate "Gianfar Ethernet"
-	depends on 85xx
+	depends on 85xx || 83xx
 	help
 	  This driver supports the Gigabit TSEC on the MPC85xx 
 	  family of chips, and the FEC on the 8540
@@ -2094,10 +2054,11 @@ config GFAR_NAPI
 
 config MV643XX_ETH
 	tristate "MV-643XX Ethernet support"
-	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX
+	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM
 	help
 	  This driver supports the gigabit Ethernet on the Marvell MV643XX
-	  chipset which is used in the Momenco Ocelot C and Jaguar ATX.
+	  chipset which is used in the Momenco Ocelot C and Jaguar ATX and
+	  Pegasos II, amongst other PPC and MIPS boards.
 
 config MV643XX_ETH_0
 	bool "MV-643XX Port 0"
@@ -2127,7 +2088,7 @@ endmenu
 #
 
 menu "Ethernet (10000 Mbit)"
-	depends on NETDEVICES
+	depends on NETDEVICES && !UML
 
 config IXGB
 	tristate "Intel(R) PRO/10GbE support"
@@ -2206,11 +2167,13 @@ config 2BUFF_MODE
 
 endmenu
 
+if !UML
 source "drivers/net/tokenring/Kconfig"
 
 source "drivers/net/wireless/Kconfig"
 
 source "drivers/net/pcmcia/Kconfig"
+endif
 
 source "drivers/net/wan/Kconfig"
 
@@ -2555,15 +2518,6 @@ config NET_FC
 	  adaptor below. You also should have said Y to "SCSI support" and
 	  "SCSI generic support".
 
-config IPHASE5526
-	tristate "Interphase 5526 Tachyon chipset based adapter support"
-	depends on NET_FC && SCSI && PCI && BROKEN
-	help
-	  Say Y here if you have a Fibre Channel adaptor of this kind.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called iph5526.
-
 config SHAPER
 	tristate "Traffic Shaper (EXPERIMENTAL)"
 	depends on NETDEVICES && EXPERIMENTAL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_NS83820) += ns83820.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_BNX2) += bnx2.o
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
@@ -68,7 +69,6 @@ obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
-obj-$(CONFIG_ETHERTAP) += ethertap.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
 obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
@@ -162,7 +162,6 @@ obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzson
 obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
-obj-$(CONFIG_BAGETLANCE) += bagetlance.o
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
@@ -184,13 +183,12 @@ obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 
 obj-$(CONFIG_ARM) += arm/
-obj-$(CONFIG_NET_FC) += fc/
 obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
 obj-$(CONFIG_NET_PCMCIA) += pcmcia/
-obj-$(CONFIG_NET_WIRELESS) += wireless/
+obj-$(CONFIG_NET_RADIO) += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)Space.c	1.0.7	08/12/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald J. Becker, <becker@scyld.com>
  *
@@ -302,16 +302,6 @@ static struct devprobe2 m68k_probes[] __
 	{NULL, 0},
 };
 
-static struct devprobe2 mips_probes[] __initdata = {
-#ifdef CONFIG_MIPS_JAZZ_SONIC
-	{sonic_probe, 0},
-#endif
-#ifdef CONFIG_BAGETLANCE        /* Lance-based Baget ethernet boards */
-        {bagetlance_probe, 0},
-#endif
-	{NULL, 0},
-};
-
 /*
  * Unified ethernet device probe, segmented per architecture and
  * per bus interface. This drives the legacy devices only for now.
@@ -325,7 +315,6 @@ static void __init ethif_probe2(int unit
 		return;
 
 	(void)(	probe_list2(unit, m68k_probes, base_addr == 0) &&
-		probe_list2(unit, mips_probes, base_addr == 0) &&
 		probe_list2(unit, eisa_probes, base_addr == 0) &&
 		probe_list2(unit, mca_probes, base_addr == 0) &&
 		probe_list2(unit, isa_probes, base_addr == 0) &&
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -105,6 +105,7 @@ Revision History:
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3");
 MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
 module_param_array(speed_duplex, int, NULL, 0);
 MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
 module_param_array(coalesce, bool, NULL, 0);
@@ -737,6 +738,7 @@ static int amd8111e_rx_poll(struct net_d
 	short vtag;
 #endif
 	int rx_pkt_limit = dev->quota;
+	unsigned long flags;
 	
 	do{   
 		/* process receive packets until we use the quota*/
@@ -840,18 +842,19 @@ static int amd8111e_rx_poll(struct net_d
 	/* Receive descriptor is empty now */
 	dev->quota -= num_rx_pkt;
 	*budget -= num_rx_pkt;
+
+	spin_lock_irqsave(&lp->lock, flags);
 	netif_rx_complete(dev);
-	/* enable receive interrupt */
 	writel(VAL0|RINTEN0, mmio + INTEN0);
 	writel(VAL2 | RDMD0, mmio + CMD0);
+	spin_unlock_irqrestore(&lp->lock, flags);
 	return 0;
+
 rx_not_empty:
 	/* Do not call a netif_rx_complete */
 	dev->quota -= num_rx_pkt;	
 	*budget -= num_rx_pkt;
 	return 1;
-
-	
 }
 
 #else
@@ -1260,18 +1263,20 @@ static irqreturn_t amd8111e_interrupt(in
 	struct net_device * dev = (struct net_device *) dev_id;
 	struct amd8111e_priv *lp = netdev_priv(dev);
 	void __iomem *mmio = lp->mmio;
-	unsigned int intr0;
+	unsigned int intr0, intren0;
 	unsigned int handled = 1;
 
-	if(dev == NULL)
+	if(unlikely(dev == NULL))
 		return IRQ_NONE;
 
-	if (regs) spin_lock (&lp->lock);
+	spin_lock(&lp->lock);
+
 	/* disabling interrupt */
 	writel(INTREN, mmio + CMD0);
 
 	/* Read interrupt status */
 	intr0 = readl(mmio + INT0);
+	intren0 = readl(mmio + INTEN0);
 
 	/* Process all the INT event until INTR bit is clear. */
 
@@ -1292,11 +1297,11 @@ static irqreturn_t amd8111e_interrupt(in
 			/* Schedule a polling routine */
 			__netif_rx_schedule(dev);
 		}
-		else {
+		else if (intren0 & RINTEN0) {
 			printk("************Driver bug! \
 				interrupt while in poll\n");
-			/* Fix by disabling interrupts */
-			writel(RINT0, mmio + INT0);
+			/* Fix by disable receive interrupts */
+			writel(RINTEN0, mmio + INTEN0);
 		}
 	}
 #else
@@ -1320,7 +1325,7 @@ static irqreturn_t amd8111e_interrupt(in
 err_no_interrupt:
 	writel( VAL0 | INTREN,mmio + CMD0);
 	
-	if (regs) spin_unlock(&lp->lock);
+	spin_unlock(&lp->lock);
 	
 	return IRQ_RETVAL(handled);
 }
@@ -1381,6 +1386,8 @@ static int amd8111e_open(struct net_devi
 
 	if(amd8111e_restart(dev)){
 		spin_unlock_irq(&lp->lock);
+		if (dev->irq)
+			free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
 	/* Start ipg timer */
@@ -1487,7 +1494,7 @@ static void amd8111e_read_regs(struct am
 amd8111e crc generator implementation is different from the kernel
 ether_crc() function.
 */
-int amd8111e_ether_crc(int len, char* mac_addr)
+static int amd8111e_ether_crc(int len, char* mac_addr)
 {
 	int i,byte;
 	unsigned char octet;
@@ -1715,7 +1722,7 @@ static int amd8111e_set_mac_address(stru
 /* 
 This function changes the mtu of the device. It restarts the device  to initialize the descriptor with new receive buffers.
 */  
-int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
+static int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct amd8111e_priv *lp = netdev_priv(dev);
 	int err;
@@ -1797,7 +1804,7 @@ static void amd8111e_tx_timeout(struct n
 	if(!err)
 		netif_wake_queue(dev);
 }
-static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
+static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {	
 	struct net_device *dev = pci_get_drvdata(pci_dev);
 	struct amd8111e_priv *lp = netdev_priv(dev);
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -13,7 +13,7 @@ config DEV_APPLETALK
 
 config LTPC
 	tristate "Apple/Farallon LocalTalk PC support"
-	depends on DEV_APPLETALK && (ISA || EISA)
+	depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
 	help
 	  This allows you to use the AppleTalk PC card to connect to LocalTalk
 	  networks. The card is also known as the Farallon PhoneNet PC card.
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -65,7 +65,7 @@ static const char *version =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
-#include <linux/if_ltalk.h>	/* For ltalk_setup() */
+#include <linux/if_ltalk.h>
 #include <linux/delay.h>	/* For udelay() */
 #include <linux/atalk.h>
 #include <linux/spinlock.h>
@@ -223,7 +223,7 @@ struct net_device * __init cops_probe(in
 	int base_addr;
 	int err = 0;
 
-	dev = alloc_netdev(sizeof(struct cops_local), "lt%d", ltalk_setup);
+	dev = alloc_ltalkdev(sizeof(struct cops_local));
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/drivers/net/appletalk/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h
--- a/drivers/net/appletalk/cops_ffdrv.h
+++ b/drivers/net/appletalk/cops_ffdrv.h
@@ -28,7 +28,7 @@
 
 #ifdef CONFIG_COPS_DAYNA
 
-unsigned char ffdrv_code[] = {
+static const unsigned char ffdrv_code[] = {
 	58,3,0,50,228,149,33,255,255,34,226,149,
 	249,17,40,152,33,202,154,183,237,82,77,68,
 	11,107,98,19,54,0,237,176,175,50,80,0,
diff --git a/drivers/net/appletalk/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h
--- a/drivers/net/appletalk/cops_ltdrv.h
+++ b/drivers/net/appletalk/cops_ltdrv.h
@@ -27,7 +27,7 @@
 
 #ifdef CONFIG_COPS_TANGENT
 
-unsigned char ltdrv_code[] = {
+static const unsigned char ltdrv_code[] = {
 	58,3,0,50,148,10,33,143,15,62,85,119,
 	190,32,9,62,170,119,190,32,3,35,24,241,
 	34,146,10,249,17,150,10,33,143,15,183,237,
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1039,7 +1039,7 @@ struct net_device * __init ltpc_probe(vo
 	unsigned long f;
 	unsigned long timeout;
 
-	dev = alloc_netdev(sizeof(struct ltpc_private), "lt%d", ltalk_setup);
+	dev = alloc_ltalkdev(sizeof(struct ltpc_private));
 	if (!dev)
 		goto out;
 
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
--- a/drivers/net/arcnet/arc-rawmode.c
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -87,7 +87,7 @@ MODULE_LICENSE("GPL");
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	int ofs;
@@ -168,7 +168,7 @@ static int build_header(struct sk_buff *
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct arc_hardware *hard = &pkt->hard;
 	int ofs;
 
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -230,7 +230,7 @@ err_free_irq:
  */
 static int arcrimi_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
@@ -251,7 +251,7 @@ static int arcrimi_reset(struct net_devi
 
 static void arcrimi_setmask(struct net_device *dev, int mask)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	AINTMASK(mask);
@@ -259,7 +259,7 @@ static void arcrimi_setmask(struct net_d
 
 static int arcrimi_status(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	return ASTATUS();
@@ -267,7 +267,7 @@ static int arcrimi_status(struct net_dev
 
 static void arcrimi_command(struct net_device *dev, int cmd)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	ACOMMAND(cmd);
@@ -276,7 +276,7 @@ static void arcrimi_command(struct net_d
 static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
 				 void *buf, int count)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 	TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
 }
@@ -285,7 +285,7 @@ static void arcrimi_copy_to_card(struct 
 static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset,
 				   void *buf, int count)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 	TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
 }
@@ -331,7 +331,7 @@ static int __init arc_rimi_init(void)
 static void __exit arc_rimi_exit(void)
 {
 	struct net_device *dev = my_dev;
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 
 	unregister_netdev(dev);
 	iounmap(lp->mem_start);
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -181,7 +181,7 @@ EXPORT_SYMBOL(arcnet_dump_skb);
 void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc,
 			int take_arcnet_lock)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int i, length;
 	unsigned long flags = 0;
 	static uint8_t buf[512];
@@ -244,7 +244,7 @@ void arcnet_unregister_proto(struct ArcP
  */
 static void release_arcbuf(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int i;
 
 	lp->buf_queue[lp->first_free_buf++] = bufnum;
@@ -253,7 +253,7 @@ static void release_arcbuf(struct net_de
 	BUGLVL(D_DURING) {
 		BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ",
 		       bufnum);
-		for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
+		for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5)
 			BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
 		BUGMSG2(D_DURING, "\n");
 	}
@@ -266,7 +266,7 @@ static void release_arcbuf(struct net_de
  */
 static int get_arcbuf(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int buf = -1, i;
 
 	if (!atomic_dec_and_test(&lp->buf_lock)) {
@@ -289,7 +289,7 @@ static int get_arcbuf(struct net_device 
 
 	BUGLVL(D_DURING) {
 		BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf);
-		for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
+		for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5)
 			BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
 		BUGMSG2(D_DURING, "\n");
 	}
@@ -367,7 +367,7 @@ struct net_device *alloc_arcdev(char *na
  */
 static int arcnet_open(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int count, newmtu, error;
 
 	BUGMSG(D_INIT,"opened.");
@@ -467,7 +467,7 @@ static int arcnet_open(struct net_device
 /* The inverse routine to arcnet_open - shuts down the card. */
 static int arcnet_close(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 
 	netif_stop_queue(dev);
 
@@ -488,7 +488,7 @@ static int arcnet_header(struct sk_buff 
 			 unsigned short type, void *daddr, void *saddr,
 			 unsigned len)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	uint8_t _daddr, proto_num;
 	struct ArcProto *proto;
 
@@ -546,7 +546,7 @@ static int arcnet_header(struct sk_buff 
 static int arcnet_rebuild_header(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int status = 0;		/* default is failure */
 	unsigned short type;
 	uint8_t daddr=0;
@@ -591,7 +591,7 @@ static int arcnet_rebuild_header(struct 
 /* Called by the kernel in order to transmit a packet. */
 static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct archdr *pkt;
 	struct arc_rfc1201 *soft;
 	struct ArcProto *proto;
@@ -674,7 +674,7 @@ static int arcnet_send_packet(struct sk_
  */
 static int go_tx(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 
 	BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n",
 	       ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx);
@@ -705,7 +705,7 @@ static int go_tx(struct net_device *dev)
 static void arcnet_timeout(struct net_device *dev)
 {
 	unsigned long flags;
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int status = ASTATUS();
 	char *msg;
 
@@ -754,7 +754,7 @@ irqreturn_t arcnet_interrupt(int irq, vo
 
 	BUGMSG(D_DURING, "in arcnet_interrupt\n");
 	
-	lp = (struct arcnet_local *) dev->priv;
+	lp = dev->priv;
 	if (!lp)
 		BUG();
 		
@@ -989,7 +989,7 @@ irqreturn_t arcnet_interrupt(int irq, vo
  */
 void arcnet_rx(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct archdr pkt;
 	struct arc_rfc1201 *soft;
 	int length, ofs;
@@ -1053,7 +1053,7 @@ void arcnet_rx(struct net_device *dev, i
  */
 static struct net_device_stats *arcnet_get_stats(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	return &lp->stats;
 }
 
@@ -1070,7 +1070,7 @@ static void null_rx(struct net_device *d
 static int null_build_header(struct sk_buff *skb, struct net_device *dev,
 			     unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 
 	BUGMSG(D_PROTO,
 	       "tx: can't build header for encap %02Xh; load a protocol driver.\n",
@@ -1085,7 +1085,7 @@ static int null_build_header(struct sk_b
 static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
 			   int length, int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct arc_hardware newpkt;
 
 	BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n");
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -48,7 +48,7 @@ static int prepare_tx(struct net_device 
 static int ack_tx(struct net_device *dev, int acked);
 
 
-struct ArcProto capmode_proto =
+static struct ArcProto capmode_proto =
 {
 	'r',
 	XMTU,
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -159,7 +159,7 @@ int com20020_found(struct net_device *de
 
 	/* Initialize the rest of the device structure. */
 
-	lp = (struct arcnet_local *) dev->priv;
+	lp = dev->priv;
 
 	lp->hw.owner = THIS_MODULE;
 	lp->hw.command = com20020_command;
@@ -233,7 +233,7 @@ int com20020_found(struct net_device *de
  */
 static int com20020_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	u_int ioaddr = dev->base_addr;
 	u_char inbyte;
 
@@ -300,7 +300,7 @@ static int com20020_status(struct net_de
 
 static void com20020_close(struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 
 	/* disable transmitter */
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -248,7 +248,7 @@ static int __init com90io_found(struct n
 		return -EBUSY;
 	}
 
-	lp = (struct arcnet_local *) (dev->priv);
+	lp = dev->priv;
 	lp->card_name = "COM90xx I/O";
 	lp->hw.command = com90io_command;
 	lp->hw.status = com90io_status;
@@ -290,7 +290,7 @@ static int __init com90io_found(struct n
  */
 static int com90io_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	short ioaddr = dev->base_addr;
 
 	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -529,7 +529,7 @@ static void com90xx_setmask(struct net_d
  */
 int com90xx_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	short ioaddr = dev->base_addr;
 
 	BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
@@ -565,7 +565,7 @@ int com90xx_reset(struct net_device *dev
 static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
 				 void *buf, int count)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 	TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
 }
@@ -574,7 +574,7 @@ static void com90xx_copy_to_card(struct 
 static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset,
 				   void *buf, int count)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 	TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
 }
@@ -600,7 +600,7 @@ static void __exit com90xx_exit(void)
 
 	for (count = 0; count < numcards; count++) {
 		dev = cards[count];
-		lp = (struct arcnet_local *) dev->priv;
+		lp = dev->priv;
 
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -88,7 +88,7 @@ MODULE_LICENSE("GPL");
  */
 static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct archdr *pkt = (struct archdr *) skb->data;
 	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
 	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
@@ -125,7 +125,7 @@ static unsigned short type_trans(struct 
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	int ofs;
@@ -169,7 +169,7 @@ static void rx(struct net_device *dev, i
 static int build_header(struct sk_buff *skb, struct net_device *dev,
 			unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
 	struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
 	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
@@ -220,7 +220,7 @@ static int build_header(struct sk_buff *
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct arc_hardware *hard = &pkt->hard;
 	int ofs;
 
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -92,7 +92,7 @@ static unsigned short type_trans(struct 
 {
 	struct archdr *pkt = (struct archdr *) skb->data;
 	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
 
 	/* Pull off the arcnet header. */
@@ -134,7 +134,7 @@ static unsigned short type_trans(struct 
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201;
@@ -376,7 +376,7 @@ static void rx(struct net_device *dev, i
 static int build_header(struct sk_buff *skb, struct net_device *dev,
 			unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
 	struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
 	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
@@ -443,7 +443,7 @@ static int build_header(struct sk_buff *
 static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
 		     struct arc_rfc1201 *soft, int softlen, int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	int ofs;
 
 	/* assume length <= XMTU: someone should have handled that by now. */
@@ -476,7 +476,7 @@ static void load_pkt(struct net_device *
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
 	struct Outgoing *out;
 
@@ -511,7 +511,7 @@ static int prepare_tx(struct net_device 
 
 static int continue_tx(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = dev->priv;
 	struct Outgoing *out = &lp->outgoing;
 	struct arc_hardware *hard = &out->pkt->hard;
 	struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft;
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -86,8 +86,8 @@ static char version[] __initdata = "ethe
 #define DISABLEIRQS 1
 #define NORMALIRQS  0
 
-#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
-#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
+#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
+#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
 
 static inline unsigned short
 ether1_inw_p (struct net_device *dev, int addr, int svflgs)
@@ -98,8 +98,8 @@ ether1_inw_p (struct net_device *dev, in
 	if (svflgs)
 		local_irq_save (flags);
 
-	outb (addr >> 12, REG_PAGE);
-	ret = inw (ETHER1_RAM + ((addr & 4095) >> 1));
+	writeb(addr >> 12, REG_PAGE);
+	ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
 	if (svflgs)
 		local_irq_restore (flags);
 	return ret;
@@ -113,8 +113,8 @@ ether1_outw_p (struct net_device *dev, u
 	if (svflgs)
 		local_irq_save (flags);
 
-	outb (addr >> 12, REG_PAGE);
-	outw (val, ETHER1_RAM + ((addr & 4095) >> 1));
+	writeb(addr >> 12, REG_PAGE);
+	writew(val, ETHER1_RAM + ((addr & 4095) << 1));
 	if (svflgs)
 		local_irq_restore (flags);
 }
@@ -131,11 +131,12 @@ ether1_outw_p (struct net_device *dev, u
 static void
 ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
 {
-	unsigned int page, thislen, offset, addr;
+	unsigned int page, thislen, offset;
+	void __iomem *addr;
 
 	offset = start & 4095;
 	page = start >> 12;
-	addr = ioaddr(ETHER1_RAM + (offset >> 1));
+	addr = ETHER1_RAM + (offset << 1);
 
 	if (offset + length > 4096)
 		thislen = 4096 - offset;
@@ -145,7 +146,7 @@ ether1_writebuffer (struct net_device *d
 	do {
 		int used;
 
-		outb(page, REG_PAGE);
+		writeb(page, REG_PAGE);
 		length -= thislen;
 
 		__asm__ __volatile__(
@@ -181,7 +182,7 @@ ether1_writebuffer (struct net_device *d
 		: "=&r" (used), "=&r" (data)
 		: "r"  (addr), "r" (thislen), "1" (data));
 
-		addr = ioaddr(ETHER1_RAM);
+		addr = ETHER1_RAM;
 
 		thislen = length;
 		if (thislen > 4096)
@@ -193,11 +194,12 @@ ether1_writebuffer (struct net_device *d
 static void
 ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
 {
-	unsigned int page, thislen, offset, addr;
+	unsigned int page, thislen, offset;
+	void __iomem *addr;
 
 	offset = start & 4095;
 	page = start >> 12;
-	addr = ioaddr(ETHER1_RAM + (offset >> 1));
+	addr = ETHER1_RAM + (offset << 1);
 
 	if (offset + length > 4096)
 		thislen = 4096 - offset;
@@ -207,7 +209,7 @@ ether1_readbuffer (struct net_device *de
 	do {
 		int used;
 
-		outb(page, REG_PAGE);
+		writeb(page, REG_PAGE);
 		length -= thislen;
 
 		__asm__ __volatile__(
@@ -243,7 +245,7 @@ ether1_readbuffer (struct net_device *de
 		: "=&r" (used), "=&r" (data)
 		: "r"  (addr), "r" (thislen), "1" (data));
 
-		addr = ioaddr(ETHER1_RAM);
+		addr = ETHER1_RAM;
 
 		thislen = length;
 		if (thislen > 4096)
@@ -302,7 +304,7 @@ ether1_ramtest(struct net_device *dev, u
 static int
 ether1_reset (struct net_device *dev)
 {
-	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
+	writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
 	return BUS_16;
 }
 
@@ -447,12 +449,11 @@ static rbd_t  init_rbd	= {
 static int
 ether1_init_for_open (struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
 	int i, status, addr, next, next2;
 	int failures = 0;
 	unsigned long timeout;
 
-	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
+	writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
 
 	for (i = 0; i < 6; i++)
 		init_sa.sa_addr[i] = dev->dev_addr[i];
@@ -467,7 +468,7 @@ ether1_init_for_open (struct net_device 
 	ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
 	ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
 
-	if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
+	if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
 		printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
 			dev->name);
 		return 1;
@@ -487,7 +488,7 @@ ether1_init_for_open (struct net_device 
 		if (next2 >= RX_AREA_END) {
 			next = RX_AREA_START;
 			init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
-			priv->rx_tail = addr;
+			priv(dev)->rx_tail = addr;
 		} else
 			init_rfd.rfd_command = 0;
 		if (addr == RX_AREA_START)
@@ -503,21 +504,21 @@ ether1_init_for_open (struct net_device 
 		addr = next;
 	} while (next2 < RX_AREA_END);
 
-	priv->tx_link = NOP_ADDR;
-	priv->tx_head = NOP_ADDR + NOP_SIZE;
-	priv->tx_tail = TDR_ADDR;
-	priv->rx_head = RX_AREA_START;
+	priv(dev)->tx_link = NOP_ADDR;
+	priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
+	priv(dev)->tx_tail = TDR_ADDR;
+	priv(dev)->rx_head = RX_AREA_START;
 
 	/* release reset & give 586 a prod */
-	priv->resetting = 1;
-	priv->initialising = 1;
-	outb (CTRL_RST, REG_CONTROL);
-	outb (0, REG_CONTROL);
-	outb (CTRL_CA, REG_CONTROL);
+	priv(dev)->resetting = 1;
+	priv(dev)->initialising = 1;
+	writeb(CTRL_RST, REG_CONTROL);
+	writeb(0, REG_CONTROL);
+	writeb(CTRL_CA, REG_CONTROL);
 
 	/* 586 should now unset iscp.busy */
 	timeout = jiffies + HZ/2;
-	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
+	while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
 		if (time_after(jiffies, timeout)) {
 			printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
 			return 1;
@@ -526,7 +527,7 @@ ether1_init_for_open (struct net_device 
 
 	/* check status of commands that we issued */
 	timeout += HZ/10;
-	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
+	while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
 		if (time_after(jiffies, timeout))
 			break;
@@ -535,15 +536,15 @@ ether1_init_for_open (struct net_device 
 	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
 		failures += 1;
 	}
 
 	timeout += HZ/10;
-	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
+	while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
 		if (time_after(jiffies, timeout))
 			break;
@@ -552,15 +553,15 @@ ether1_init_for_open (struct net_device 
 	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
 		failures += 1;
 	}
 
 	timeout += HZ/10;
-	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
+	while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
 		if (time_after(jiffies, timeout))
 			break;
@@ -569,15 +570,15 @@ ether1_init_for_open (struct net_device 
 	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
 		failures += 1;
 	}
 
 	timeout += HZ;
-	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
+	while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
 		if (time_after(jiffies, timeout))
 			break;
@@ -586,12 +587,12 @@ ether1_init_for_open (struct net_device 
 	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
 	} else {
-		status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
+		status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
 		if (status & TDR_XCVRPROB)
 			printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
 		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
@@ -616,24 +617,23 @@ ether1_init_for_open (struct net_device 
 static int
 ether1_txalloc (struct net_device *dev, int size)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
 	int start, tail;
 
 	size = (size + 1) & ~1;
-	tail = priv->tx_tail;
+	tail = priv(dev)->tx_tail;
 
-	if (priv->tx_head + size > TX_AREA_END) {
-		if (tail > priv->tx_head)
+	if (priv(dev)->tx_head + size > TX_AREA_END) {
+		if (tail > priv(dev)->tx_head)
 			return -1;
 		start = TX_AREA_START;
 		if (start + size > tail)
 			return -1;
-		priv->tx_head = start + size;
+		priv(dev)->tx_head = start + size;
 	} else {
-		if (priv->tx_head < tail && (priv->tx_head + size) > tail)
+		if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
 			return -1;
-		start = priv->tx_head;
-		priv->tx_head += size;
+		start = priv(dev)->tx_head;
+		priv(dev)->tx_head += size;
 	}
 
 	return start;
@@ -642,8 +642,6 @@ ether1_txalloc (struct net_device *dev, 
 static int
 ether1_open (struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
-
 	if (!is_valid_ether_addr(dev->dev_addr)) {
 		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
 			dev->name);
@@ -653,7 +651,7 @@ ether1_open (struct net_device *dev)
 	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
 		return -EAGAIN;
 
-	memset (&priv->stats, 0, sizeof (struct net_device_stats));
+	memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
 
 	if (ether1_init_for_open (dev)) {
 		free_irq (dev->irq, dev);
@@ -668,8 +666,6 @@ ether1_open (struct net_device *dev)
 static void
 ether1_timeout(struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
-
 	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
 		dev->name);
 	printk(KERN_WARNING "%s: resetting device\n", dev->name);
@@ -679,21 +675,20 @@ ether1_timeout(struct net_device *dev)
 	if (ether1_init_for_open (dev))
 		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
 
-	priv->stats.tx_errors++;
+	priv(dev)->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
 static int
 ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
 	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
 	unsigned long flags;
 	tx_t tx;
 	tbd_t tbd;
 	nop_t nop;
 
-	if (priv->restart) {
+	if (priv(dev)->restart) {
 		printk(KERN_WARNING "%s: resetting device\n", dev->name);
 
 		ether1_reset(dev);
@@ -701,7 +696,7 @@ ether1_sendpacket (struct sk_buff *skb, 
 		if (ether1_init_for_open(dev))
 			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
 		else
-			priv->restart = 0;
+			priv(dev)->restart = 0;
 	}
 
 	if (skb->len < ETH_ZLEN) {
@@ -735,11 +730,11 @@ ether1_sendpacket (struct sk_buff *skb, 
 	ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
 	ether1_writebuffer (dev, skb->data, dataddr, skb->len);
 	ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
-	tmp = priv->tx_link;
-	priv->tx_link = nopaddr;
+	tmp = priv(dev)->tx_link;
+	priv(dev)->tx_link = nopaddr;
 
 	/* now reset the previous nop pointer */
-	ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+	ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
 
 	local_irq_restore(flags);
 
@@ -747,9 +742,9 @@ ether1_sendpacket (struct sk_buff *skb, 
 	dev->trans_start = jiffies;
 
 	/* check to see if we have room for a full sized ether frame */
-	tmp = priv->tx_head;
+	tmp = priv(dev)->tx_head;
 	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-	priv->tx_head = tmp;
+	priv(dev)->tx_head = tmp;
 	dev_kfree_skb (skb);
 
 	if (tst == -1)
@@ -762,11 +757,10 @@ ether1_sendpacket (struct sk_buff *skb, 
 static void
 ether1_xmit_done (struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
 	nop_t nop;
 	int caddr, tst;
 
-	caddr = priv->tx_tail;
+	caddr = priv(dev)->tx_tail;
 
 again:
 	ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
@@ -774,21 +768,21 @@ again:
 	switch (nop.nop_command & CMD_MASK) {
 	case CMD_TDR:
 		/* special case */
-		if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+		if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
 				!= (unsigned short)I82586_NULL) {
-			ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
+			ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
 				    scb_command, NORMALIRQS);
-			outb (CTRL_CA, REG_CONTROL);
+			writeb(CTRL_CA, REG_CONTROL);
 		}
-		priv->tx_tail = NOP_ADDR;
+		priv(dev)->tx_tail = NOP_ADDR;
 		return;
 
 	case CMD_NOP:
 		if (nop.nop_link == caddr) {
-			if (priv->initialising == 0)
+			if (priv(dev)->initialising == 0)
 				printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
 			else
-			        priv->initialising = 0;
+			        priv(dev)->initialising = 0;
 			return;
 		}
 		if (caddr == nop.nop_link)
@@ -800,33 +794,33 @@ again:
 		if (nop.nop_status & STAT_COMPLETE)
 			break;
 		printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
-		priv->restart = 1;
+		priv(dev)->restart = 1;
 		return;
 
 	default:
 		printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
 			nop.nop_command & CMD_MASK, caddr);
-		priv->restart = 1;
+		priv(dev)->restart = 1;
 		return;
 	}
 
 	while (nop.nop_status & STAT_COMPLETE) {
 		if (nop.nop_status & STAT_OK) {
-			priv->stats.tx_packets ++;
-			priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+			priv(dev)->stats.tx_packets ++;
+			priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
 		} else {
-			priv->stats.tx_errors ++;
+			priv(dev)->stats.tx_errors ++;
 
 			if (nop.nop_status & STAT_COLLAFTERTX)
-				priv->stats.collisions ++;
+				priv(dev)->stats.collisions ++;
 			if (nop.nop_status & STAT_NOCARRIER)
-				priv->stats.tx_carrier_errors ++;
+				priv(dev)->stats.tx_carrier_errors ++;
 			if (nop.nop_status & STAT_TXLOSTCTS)
 				printk (KERN_WARNING "%s: cts lost\n", dev->name);
 			if (nop.nop_status & STAT_TXSLOWDMA)
-				priv->stats.tx_fifo_errors ++;
+				priv(dev)->stats.tx_fifo_errors ++;
 			if (nop.nop_status & STAT_COLLEXCESSIVE)
-				priv->stats.collisions += 16;
+				priv(dev)->stats.collisions += 16;
 		}
 
 		if (nop.nop_link == caddr) {
@@ -851,11 +845,11 @@ again:
 			break;
 		}
 	}
-	priv->tx_tail = caddr;
+	priv(dev)->tx_tail = caddr;
 
-	caddr = priv->tx_head;
+	caddr = priv(dev)->tx_head;
 	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-	priv->tx_head = caddr;
+	priv(dev)->tx_head = caddr;
 	if (tst != -1)
 		netif_wake_queue(dev);
 }
@@ -863,17 +857,16 @@ again:
 static void
 ether1_recv_done (struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
 	int status;
 	int nexttail, rbdaddr;
 	rbd_t rbd;
 
 	do {
-		status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS);
+		status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
 		if ((status & RFD_COMPLETE) == 0)
 			break;
 
-		rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
+		rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
 		ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
 
 		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
@@ -891,27 +884,27 @@ ether1_recv_done (struct net_device *dev
 
 				skb->protocol = eth_type_trans (skb, dev);
 				netif_rx (skb);
-				priv->stats.rx_packets ++;
+				priv(dev)->stats.rx_packets ++;
 			} else
-				priv->stats.rx_dropped ++;
+				priv(dev)->stats.rx_dropped ++;
 		} else {
 			printk(KERN_WARNING "%s: %s\n", dev->name,
 				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-			priv->stats.rx_dropped ++;
+			priv(dev)->stats.rx_dropped ++;
 		}
 
-		nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);
+		nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
 		/* nexttail should be rx_head */
-		if (nexttail != priv->rx_head)
+		if (nexttail != priv(dev)->rx_head)
 			printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
-				dev->name, nexttail, priv->rx_head);
-		ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
+				dev->name, nexttail, priv(dev)->rx_head);
+		ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
+		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
+		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
+		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
 	
-		priv->rx_tail = nexttail;
-		priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);
+		priv(dev)->rx_tail = nexttail;
+		priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
 	} while (1);
 }
 
@@ -919,48 +912,47 @@ static irqreturn_t
 ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct ether1_priv *priv = netdev_priv(dev);
 	int status;
 
-	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
+	status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
 
 	if (status) {
-		ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
+		ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
 			    SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-		outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
+		writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
 		if (status & SCB_STCX) {
 			ether1_xmit_done (dev);
 		}
 		if (status & SCB_STCNA) {
-			if (priv->resetting == 0)
+			if (priv(dev)->resetting == 0)
 				printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
 			else
-				priv->resetting += 1;
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+				priv(dev)->resetting += 1;
+			if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
 					!= (unsigned short)I82586_NULL) {
-				ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-				outb (CTRL_CA, REG_CONTROL);
+				ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+				writeb(CTRL_CA, REG_CONTROL);
 			}
-			if (priv->resetting == 2)
-				priv->resetting = 0;
+			if (priv(dev)->resetting == 2)
+				priv(dev)->resetting = 0;
 		}
 		if (status & SCB_STFR) {
 			ether1_recv_done (dev);
 		}
 		if (status & SCB_STRNR) {
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
+			if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
 				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
-				ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-				outb (CTRL_CA, REG_CONTROL);
-				priv->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
+				ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+				writeb(CTRL_CA, REG_CONTROL);
+				priv(dev)->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
 			} else
 				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
-					ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
-			printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,
+					ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
+			printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
 						NORMALIRQS));
 		}
 	} else
-		outb (CTRL_ACK, REG_CONTROL);
+		writeb(CTRL_ACK, REG_CONTROL);
 
 	return IRQ_HANDLED;
 }
@@ -978,8 +970,7 @@ ether1_close (struct net_device *dev)
 static struct net_device_stats *
 ether1_getstats (struct net_device *dev)
 {
-	struct ether1_priv *priv = netdev_priv(dev);
-	return &priv->stats;
+	return &priv(dev)->stats;
 }
 
 /*
@@ -1008,40 +999,42 @@ static int __devinit
 ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct net_device *dev;
-	struct ether1_priv *priv;
 	int i, ret = 0;
 
 	ether1_banner();
 
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
 	dev = alloc_etherdev(sizeof(struct ether1_priv));
 	if (!dev) {
 		ret = -ENOMEM;
-		goto out;
+		goto release;
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &ec->dev);
 
-	dev->base_addr	= ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	dev->irq	= ec->irq;
-
-	/*
-	 * these will not fail - the nature of the bus ensures this
-	 */
-	request_region(dev->base_addr, 16, dev->name);
-	request_region(dev->base_addr + 0x800, 4096, dev->name);
+	dev->irq = ec->irq;
+	priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+				  ecard_resource_len(ec, ECARD_RES_IOCFAST));
+	if (!priv(dev)->base) {
+		ret = -ENOMEM;
+		goto free;
+	}
 
-	priv = netdev_priv(dev);
-	if ((priv->bus_type = ether1_reset(dev)) == 0) {
+	if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
 		ret = -ENODEV;
-		goto release;
+		goto free;
 	}
 
 	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = inb(IDPROM_ADDRESS + i);
+		dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
 
 	if (ether1_init_2(dev)) {
 		ret = -ENODEV;
-		goto release;
+		goto free;
 	}
 
 	dev->open		= ether1_open;
@@ -1054,7 +1047,7 @@ ether1_probe(struct expansion_card *ec, 
 
 	ret = register_netdev(dev);
 	if (ret)
-		goto release;
+		goto free;
 
 	printk(KERN_INFO "%s: ether1 in slot %d, ",
 		dev->name, ec->slot_no);
@@ -1065,11 +1058,13 @@ ether1_probe(struct expansion_card *ec, 
 	ecard_set_drvdata(ec, dev);
 	return 0;
 
-release:
-	release_region(dev->base_addr, 16);
-	release_region(dev->base_addr + 0x800, 4096);
+ free:
+	if (priv(dev)->base)
+		iounmap(priv(dev)->base);
 	free_netdev(dev);
-out:
+ release:
+	ecard_release_resources(ec);
+ out:
 	return ret;
 }
 
@@ -1080,10 +1075,9 @@ static void __devexit ether1_remove(stru
 	ecard_set_drvdata(ec, NULL);	
 
 	unregister_netdev(dev);
-
-	release_region(dev->base_addr, 16);
-	release_region(dev->base_addr + 0x800, 4096);
+	iounmap(priv(dev)->base);
 	free_netdev(dev);
+	ecard_release_resources(ec);
 }
 
 static const struct ecard_id ether1_ids[] = {
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
--- a/drivers/net/arm/ether1.h
+++ b/drivers/net/arm/ether1.h
@@ -19,22 +19,25 @@
 #define NET_DEBUG 0
 #endif
 
+#define priv(dev)	((struct ether1_priv *)netdev_priv(dev))
+
 /* Page register */
-#define REG_PAGE	(dev->base_addr + 0x00)
+#define REG_PAGE	(priv(dev)->base + 0x0000)
 
 /* Control register */
-#define REG_CONTROL	(dev->base_addr + 0x01)
+#define REG_CONTROL	(priv(dev)->base + 0x0004)
 #define CTRL_RST	0x01
 #define CTRL_LOOPBACK	0x02
 #define CTRL_CA		0x04
 #define CTRL_ACK	0x08
 
-#define ETHER1_RAM	(dev->base_addr + 0x800)
+#define ETHER1_RAM	(priv(dev)->base + 0x2000)
 
 /* HW address */
-#define IDPROM_ADDRESS	(dev->base_addr + 0x09)
+#define IDPROM_ADDRESS	(priv(dev)->base + 0x0024)
 
 struct ether1_priv {
+	void __iomem *base;
 	struct net_device_stats stats;
 	unsigned int tx_link;
 	unsigned int tx_head;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -78,8 +78,8 @@ static char version[] __initdata = "ethe
 static unsigned int net_debug = NET_DEBUG;
 
 static void	ether3_setmulticastlist(struct net_device *dev);
-static int	ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
-static void	ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static int	ether3_rx(struct net_device *dev, unsigned int maxcnt);
+static void	ether3_tx(struct net_device *dev);
 static int	ether3_open (struct net_device *dev);
 static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
@@ -104,33 +104,32 @@ typedef enum {
  * The SEEQ8005 doesn't like us writing to its registers
  * too quickly.
  */
-static inline void ether3_outb(int v, const int r)
+static inline void ether3_outb(int v, const void __iomem *r)
 {
-	outb(v, r);
+	writeb(v, r);
 	udelay(1);
 }
 
-static inline void ether3_outw(int v, const int r)
+static inline void ether3_outw(int v, const void __iomem *r)
 {
-	outw(v, r);
+	writew(v, r);
 	udelay(1);
 }
-#define ether3_inb(r)		({ unsigned int __v = inb((r)); udelay(1); __v; })
-#define ether3_inw(r)		({ unsigned int __v = inw((r)); udelay(1); __v; })
+#define ether3_inb(r)		({ unsigned int __v = readb((r)); udelay(1); __v; })
+#define ether3_inw(r)		({ unsigned int __v = readw((r)); udelay(1); __v; })
 
 static int
 ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start)
 {
-	struct dev_priv *priv = netdev_priv(dev);
 	int timeout = 1000;
 
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND);
 
 	while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
 		if (!timeout--) {
 			printk("%s: setbuffer broken\n", dev->name);
-			priv->broken = 1;
+			priv(dev)->broken = 1;
 			return 1;
 		}
 		udelay(1);
@@ -138,9 +137,9 @@ ether3_setbuffer(struct net_device *dev,
 
 	if (read == buffer_read) {
 		ether3_outw(start, REG_DMAADDR);
-		ether3_outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
+		ether3_outw(priv(dev)->regs.command | CMD_FIFOREAD, REG_COMMAND);
 	} else {
-		ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+		ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND);
 		ether3_outw(start, REG_DMAADDR);
 	}
 	return 0;
@@ -150,53 +149,50 @@ ether3_setbuffer(struct net_device *dev,
  * write data to the buffer memory
  */
 #define ether3_writebuffer(dev,data,length)			\
-	outsw(REG_BUFWIN, (data), (length) >> 1)
+	writesw(REG_BUFWIN, (data), (length) >> 1)
 
 #define ether3_writeword(dev,data)				\
-	outw((data), REG_BUFWIN)
+	writew((data), REG_BUFWIN)
 
 #define ether3_writelong(dev,data)	{			\
-	unsigned long reg_bufwin = REG_BUFWIN;			\
-	outw((data), reg_bufwin);				\
-	outw((data) >> 16, reg_bufwin);				\
+	void __iomem *reg_bufwin = REG_BUFWIN;			\
+	writew((data), reg_bufwin);				\
+	writew((data) >> 16, reg_bufwin);			\
 }
 
 /*
  * read data from the buffer memory
  */
 #define ether3_readbuffer(dev,data,length)			\
-	insw(REG_BUFWIN, (data), (length) >> 1)
+	readsw(REG_BUFWIN, (data), (length) >> 1)
 
 #define ether3_readword(dev)					\
-	inw(REG_BUFWIN)
+	readw(REG_BUFWIN)
 
 #define ether3_readlong(dev)	 				\
-	inw(REG_BUFWIN) | (inw(REG_BUFWIN) << 16)
+	readw(REG_BUFWIN) | (readw(REG_BUFWIN) << 16)
 
 /*
  * Switch LED off...
  */
-static void
-ether3_ledoff(unsigned long data)
+static void ether3_ledoff(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct dev_priv *priv = netdev_priv(dev);
-	ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
+	ether3_outw(priv(dev)->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
 }
 
 /*
  * switch LED on...
  */
-static inline void
-ether3_ledon(struct net_device *dev, struct dev_priv *priv)
+static inline void ether3_ledon(struct net_device *dev)
 {
-	del_timer(&priv->timer);
-	priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */
-	priv->timer.data = (unsigned long)dev;
-	priv->timer.function = ether3_ledoff;
-	add_timer(&priv->timer);
-	if (priv->regs.config2 & CFG2_CTRLO)
-		ether3_outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
+	del_timer(&priv(dev)->timer);
+	priv(dev)->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */
+	priv(dev)->timer.data = (unsigned long)dev;
+	priv(dev)->timer.function = ether3_ledoff;
+	add_timer(&priv(dev)->timer);
+	if (priv(dev)->regs.config2 & CFG2_CTRLO)
+		ether3_outw(priv(dev)->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
 }
 
 /*
@@ -277,43 +273,41 @@ ether3_ramtest(struct net_device *dev, u
 
 /* ------------------------------------------------------------------------------- */
 
-static int __init
-ether3_init_2(struct net_device *dev)
+static int __init ether3_init_2(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
 	int i;
 
-	priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
-	priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
-	priv->regs.command = 0;
+	priv(dev)->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
+	priv(dev)->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
+	priv(dev)->regs.command = 0;
 
 	/*
 	 * Set up our hardware address
 	 */
-	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
 	for (i = 0; i < 6; i++)
 		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
 
 	if (dev->flags & IFF_PROMISC)
-		priv->regs.config1 |= CFG1_RECVPROMISC;
+		priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
 	else if (dev->flags & IFF_MULTICAST)
-		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
+		priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
 	else
-		priv->regs.config1 |= CFG1_RECVSPECBROAD;
+		priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
 
 	/*
 	 * There is a problem with the NQ8005 in that it occasionally loses the
 	 * last two bytes.  To get round this problem, we receive the CRC as
 	 * well.  That way, if we do lose the last two, then it doesn't matter.
 	 */
-	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
 	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
-	ether3_outw(priv->rx_head, REG_RECVPTR);
+	ether3_outw(priv(dev)->rx_head, REG_RECVPTR);
 	ether3_outw(0, REG_TRANSMITPTR);
-	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	ether3_outw(priv->regs.command, REG_COMMAND);
+	ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND);
+	ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.command, REG_COMMAND);
 
 	i = ether3_ramtest(dev, 0x5A);
 	if(i)
@@ -330,41 +324,41 @@ ether3_init_2(struct net_device *dev)
 static void
 ether3_init_for_open(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
 	int i;
 
-	memset(&priv->stats, 0, sizeof(struct net_device_stats));
+	memset(&priv(dev)->stats, 0, sizeof(struct net_device_stats));
 
 	/* Reset the chip */
 	ether3_outw(CFG2_RESET, REG_CONFIG2);
 	udelay(4);
 
-	priv->regs.command = 0;
+	priv(dev)->regs.command = 0;
 	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
-	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON))
+		barrier();
 
-	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
 	for (i = 0; i < 6; i++)
 		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
 
-	priv->tx_head	= 0;
-	priv->tx_tail	= 0;
-	priv->regs.config2 |= CFG2_CTRLO;
-	priv->rx_head	= RX_START;
+	priv(dev)->tx_head	= 0;
+	priv(dev)->tx_tail	= 0;
+	priv(dev)->regs.config2 |= CFG2_CTRLO;
+	priv(dev)->rx_head	= RX_START;
 
-	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
 	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
-	ether3_outw(priv->rx_head, REG_RECVPTR);
-	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
+	ether3_outw(priv(dev)->rx_head, REG_RECVPTR);
+	ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND);
 	ether3_outw(0, REG_TRANSMITPTR);
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 
 	ether3_setbuffer(dev, buffer_write, 0);
 	ether3_writelong(dev, 0);
 
-	priv->regs.command = CMD_ENINTRX | CMD_ENINTTX;
-	ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+	priv(dev)->regs.command = CMD_ENINTRX | CMD_ENINTTX;
+	ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
 }
 
 static inline int
@@ -378,10 +372,10 @@ ether3_probe_bus_8(struct net_device *de
 	printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low);
 
 	ether3_outb(write_low, REG_RECVPTR);
-	ether3_outb(write_high, REG_RECVPTR + 1);
+	ether3_outb(write_high, REG_RECVPTR + 4);
 
 	read_low = ether3_inb(REG_RECVPTR);
-	read_high = ether3_inb(REG_RECVPTR + 1);
+	read_high = ether3_inb(REG_RECVPTR + 4);
 
 	printk(", read8 [%02X:%02X]\n", read_high, read_low);
 
@@ -434,16 +428,15 @@ ether3_open(struct net_device *dev)
 static int
 ether3_close(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
-
 	netif_stop_queue(dev);
 
 	disable_irq(dev->irq);
 
 	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
-	priv->regs.command = 0;
-	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
-	ether3_outb(0x80, REG_CONFIG2 + 1);
+	priv(dev)->regs.command = 0;
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON))
+		barrier();
+	ether3_outb(0x80, REG_CONFIG2 + 4);
 	ether3_outw(0, REG_COMMAND);
 
 	free_irq(dev->irq, dev);
@@ -457,8 +450,7 @@ ether3_close(struct net_device *dev)
  */
 static struct net_device_stats *ether3_getstats(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
-	return &priv->stats;
+	return &priv(dev)->stats;
 }
 
 /*
@@ -469,28 +461,24 @@ static struct net_device_stats *ether3_g
  */
 static void ether3_setmulticastlist(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
-
-	priv->regs.config1 &= ~CFG1_RECVPROMISC;
+	priv(dev)->regs.config1 &= ~CFG1_RECVPROMISC;
 
 	if (dev->flags & IFF_PROMISC) {
 		/* promiscuous mode */
-		priv->regs.config1 |= CFG1_RECVPROMISC;
+		priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
 	} else if (dev->flags & IFF_ALLMULTI) {
-		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
+		priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
 	} else
-		priv->regs.config1 |= CFG1_RECVSPECBROAD;
+		priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
 
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 }
 
-static void
-ether3_timeout(struct net_device *dev)
+static void ether3_timeout(struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 
-	del_timer(&priv->timer);
+	del_timer(&priv(dev)->timer);
 
 	local_irq_save(flags);
 	printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
@@ -499,15 +487,15 @@ ether3_timeout(struct net_device *dev)
 	printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
 		ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
 	printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
-		priv->tx_head, priv->tx_tail);
-	ether3_setbuffer(dev, buffer_read, priv->tx_tail);
+		priv(dev)->tx_head, priv(dev)->tx_tail);
+	ether3_setbuffer(dev, buffer_read, priv(dev)->tx_tail);
 	printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
 	local_irq_restore(flags);
 
-	priv->regs.config2 |= CFG2_CTRLO;
-	priv->stats.tx_errors += 1;
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	priv->tx_head = priv->tx_tail = 0;
+	priv(dev)->regs.config2 |= CFG2_CTRLO;
+	priv(dev)->stats.tx_errors += 1;
+	ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
+	priv(dev)->tx_head = priv(dev)->tx_tail = 0;
 
 	netif_wake_queue(dev);
 }
@@ -518,14 +506,13 @@ ether3_timeout(struct net_device *dev)
 static int
 ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
-	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned int ptr, next_ptr;
 
-	if (priv->broken) {
+	if (priv(dev)->broken) {
 		dev_kfree_skb(skb);
-		priv->stats.tx_dropped ++;
+		priv(dev)->stats.tx_dropped ++;
 		netif_start_queue(dev);
 		return 0;
 	}
@@ -537,18 +524,18 @@ ether3_sendpacket(struct sk_buff *skb, s
 			goto out;
 	}
 
-	next_ptr = (priv->tx_head + 1) & 15;
+	next_ptr = (priv(dev)->tx_head + 1) & 15;
 
 	local_irq_save(flags);
 
-	if (priv->tx_tail == next_ptr) {
+	if (priv(dev)->tx_tail == next_ptr) {
 		local_irq_restore(flags);
 		return 1;	/* unable to queue */
 	}
 
 	dev->trans_start = jiffies;
-	ptr		 = 0x600 * priv->tx_head;
-	priv->tx_head	 = next_ptr;
+	ptr		 = 0x600 * priv(dev)->tx_head;
+	priv(dev)->tx_head = next_ptr;
 	next_ptr	*= 0x600;
 
 #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
@@ -563,19 +550,19 @@ ether3_sendpacket(struct sk_buff *skb, s
 	ether3_setbuffer(dev, buffer_write, ptr);
 	ether3_writeword(dev, htons((ptr + length + 4)));
 	ether3_writeword(dev, TXHDR_FLAGS >> 16);
-	ether3_ledon(dev, priv);
+	ether3_ledon(dev);
 
 	if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
 		ether3_outw(ptr, REG_TRANSMITPTR);
-		ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
+		ether3_outw(priv(dev)->regs.command | CMD_TXON, REG_COMMAND);
 	}
 
-	next_ptr = (priv->tx_head + 1) & 15;
+	next_ptr = (priv(dev)->tx_head + 1) & 15;
 	local_irq_restore(flags);
 
 	dev_kfree_skb(skb);
 
-	if (priv->tx_tail == next_ptr)
+	if (priv(dev)->tx_tail == next_ptr)
 		netif_stop_queue(dev);
 
  out:
@@ -586,7 +573,6 @@ static irqreturn_t
 ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct dev_priv *priv;
 	unsigned int status, handled = IRQ_NONE;
 
 #if NET_DEBUG > 1
@@ -594,19 +580,17 @@ ether3_interrupt(int irq, void *dev_id, 
 		printk("eth3irq: %d ", irq);
 #endif
 
-	priv = netdev_priv(dev);
-
 	status = ether3_inw(REG_STATUS);
 
 	if (status & STAT_INTRX) {
-		ether3_outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
-		ether3_rx(dev, priv, 12);
+		ether3_outw(CMD_ACKINTRX | priv(dev)->regs.command, REG_COMMAND);
+		ether3_rx(dev, 12);
 		handled = IRQ_HANDLED;
 	}
 
 	if (status & STAT_INTTX) {
-		ether3_outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
-		ether3_tx(dev, priv);
+		ether3_outw(CMD_ACKINTTX | priv(dev)->regs.command, REG_COMMAND);
+		ether3_tx(dev);
 		handled = IRQ_HANDLED;
 	}
 
@@ -620,11 +604,11 @@ ether3_interrupt(int irq, void *dev_id, 
 /*
  * If we have a good packet(s), get it/them out of the buffers.
  */
-static int
-ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt)
+static int ether3_rx(struct net_device *dev, unsigned int maxcnt)
 {
-	unsigned int next_ptr = priv->rx_head, received = 0;
-	ether3_ledon(dev, priv);
+	unsigned int next_ptr = priv(dev)->rx_head, received = 0;
+
+	ether3_ledon(dev);
 
 	do {
 		unsigned int this_ptr, status;
@@ -653,12 +637,12 @@ ether3_rx(struct net_device *dev, struct
 
 if (next_ptr < RX_START || next_ptr >= RX_END) {
  int i;
- printk("%s: bad next pointer @%04X: ", dev->name, priv->rx_head);
+ printk("%s: bad next pointer @%04X: ", dev->name, priv(dev)->rx_head);
  printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8);
  for (i = 2; i < 14; i++)
    printk("%02X ", addrs[i]);
  printk("\n");
- next_ptr = priv->rx_head;
+ next_ptr = priv(dev)->rx_head;
  break;
 }
 		/*
@@ -695,7 +679,7 @@ if (next_ptr < RX_START || next_ptr >= R
 			} else
 				goto dropping;
 		} else {
-			struct net_device_stats *stats = &priv->stats;
+			struct net_device_stats *stats = &priv(dev)->stats;
 			ether3_outw(next_ptr >> 8, REG_RECVEND);
 			if (status & RXSTAT_OVERSIZE)	  stats->rx_over_errors ++;
 			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
@@ -707,16 +691,16 @@ if (next_ptr < RX_START || next_ptr >= R
 	while (-- maxcnt);
 
 done:
-	priv->stats.rx_packets += received;
-	priv->rx_head = next_ptr;
+	priv(dev)->stats.rx_packets += received;
+	priv(dev)->rx_head = next_ptr;
 	/*
 	 * If rx went off line, then that means that the buffer may be full.  We
 	 * have dropped at least one packet.
 	 */
 	if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
-		priv->stats.rx_dropped ++;
+		priv(dev)->stats.rx_dropped ++;
     		ether3_outw(next_ptr, REG_RECVPTR);
-		ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+		ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
 	}
 
 	return maxcnt;
@@ -732,7 +716,7 @@ dropping:{
 		last_warned = jiffies;
 		printk("%s: memory squeeze, dropping packet.\n", dev->name);
 	}
-	priv->stats.rx_dropped ++;
+	priv(dev)->stats.rx_dropped ++;
 	goto done;
 	}
 }
@@ -740,10 +724,9 @@ dropping:{
 /*
  * Update stats for the transmitted packet(s)
  */
-static void
-ether3_tx(struct net_device *dev, struct dev_priv *priv)
+static void ether3_tx(struct net_device *dev)
 {
-	unsigned int tx_tail = priv->tx_tail;
+	unsigned int tx_tail = priv(dev)->tx_tail;
 	int max_work = 14;
 
 	do {
@@ -766,18 +749,20 @@ ether3_tx(struct net_device *dev, struct
 		 * Update errors
 		 */
 		if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
-			priv->stats.tx_packets++;
+			priv(dev)->stats.tx_packets++;
 		else {
-			priv->stats.tx_errors ++;
-			if (status & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
-			if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
+			priv(dev)->stats.tx_errors ++;
+			if (status & TXSTAT_16COLLISIONS)
+				priv(dev)->stats.collisions += 16;
+			if (status & TXSTAT_BABBLED)
+				priv(dev)->stats.tx_fifo_errors ++;
 		}
 
 		tx_tail = (tx_tail + 1) & 15;
 	} while (--max_work);
 
-	if (priv->tx_tail != tx_tail) {
-		priv->tx_tail = tx_tail;
+	if (priv(dev)->tx_tail != tx_tail) {
+		priv(dev)->tx_tail = tx_tail;
 		netif_wake_queue(dev);
 	}
 }
@@ -790,66 +775,48 @@ static void __init ether3_banner(void)
 		printk(KERN_INFO "%s", version);
 }
 
-static const char * __init
-ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
-{
-	const char *name = "ether3";
-
-	dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
-	dev->irq = ec->irq;
-
-	if (ec->cid.manufacturer == MANU_ANT &&
-	    ec->cid.product == PROD_ANT_ETHERB) {
-		dev->base_addr += 0x200;
-		name = "etherb";
-	}
-
-	ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
-	ec->irqmask = 0xf0;
-
-	ether3_addr(dev->dev_addr, ec);
-
-	return name;
-}
-
 static int __devinit
 ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
+	const struct ether3_data *data = id->data;
 	struct net_device *dev;
-	struct dev_priv *priv;
-	const char *name;
 	int i, bus_type, ret;
 
 	ether3_banner();
 
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
 	dev = alloc_etherdev(sizeof(struct dev_priv));
 	if (!dev) {
 		ret = -ENOMEM;
-		goto out;
+		goto release;
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &ec->dev);
 
-	name = ether3_get_dev(dev, ec);
-	if (!name) {
-		ret = -ENODEV;
+	priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+				  ecard_resource_len(ec, ECARD_RES_MEMC));
+	if (!priv(dev)->base) {
+		ret = -ENOMEM;
 		goto free;
 	}
 
-	/*
-	 * this will not fail - the nature of the bus ensures this
-	 */
-	if (!request_region(dev->base_addr, 128, dev->name)) {
-		ret = -EBUSY;
-		goto free;
-	}
+	ec->irqaddr = priv(dev)->base + data->base_offset;
+	ec->irqmask = 0xf0;
+
+	priv(dev)->seeq = priv(dev)->base + data->base_offset;
+	dev->irq = ec->irq;
 
-	priv = netdev_priv(dev);
-	init_timer(&priv->timer);
+	ether3_addr(dev->dev_addr, ec);
+
+	init_timer(&priv(dev)->timer);
 
 	/* Reset card...
 	 */
-	ether3_outb(0x80, REG_CONFIG2 + 1);
+	ether3_outb(0x80, REG_CONFIG2 + 4);
 	bus_type = BUS_UNKNOWN;
 	udelay(4);
 
@@ -869,13 +836,13 @@ ether3_probe(struct expansion_card *ec, 
 	case BUS_UNKNOWN:
 		printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
 		ret = -ENODEV;
-		goto failed;
+		goto free;
 
 	case BUS_8:
 		printk(KERN_ERR "%s: %s found, but is an unsupported "
-			"8-bit card\n", dev->name, name);
+			"8-bit card\n", dev->name, data->name);
 		ret = -ENODEV;
-		goto failed;
+		goto free;
 
 	default:
 		break;
@@ -883,7 +850,7 @@ ether3_probe(struct expansion_card *ec, 
 
 	if (ether3_init_2(dev)) {
 		ret = -ENODEV;
-		goto failed;
+		goto free;
 	}
 
 	dev->open		= ether3_open;
@@ -896,20 +863,22 @@ ether3_probe(struct expansion_card *ec, 
 
 	ret = register_netdev(dev);
 	if (ret)
-		goto failed;
+		goto free;
 
-	printk("%s: %s in slot %d, ", dev->name, name, ec->slot_no);
+	printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no);
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
 
 	ecard_set_drvdata(ec, dev);
 	return 0;
 
-failed:
-	release_region(dev->base_addr, 128);
-free:
+ free:
+	if (priv(dev)->base)
+		iounmap(priv(dev)->base);
 	free_netdev(dev);
-out:
+ release:
+	ecard_release_resources(ec);
+ out:
 	return ret;
 }
 
@@ -920,14 +889,25 @@ static void __devexit ether3_remove(stru
 	ecard_set_drvdata(ec, NULL);
 
 	unregister_netdev(dev);
-	release_region(dev->base_addr, 128);
+	iounmap(priv(dev)->base);
 	free_netdev(dev);
+	ecard_release_resources(ec);
 }
 
+static struct ether3_data ether3 = {
+	.name		= "ether3",
+	.base_offset	= 0,
+};
+
+static struct ether3_data etherb = {
+	.name		= "etherb",
+	.base_offset	= 0x800,
+};
+
 static const struct ecard_id ether3_ids[] = {
-	{ MANU_ANT2, PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHERB },
+	{ MANU_ANT2, PROD_ANT_ETHER3, &ether3 },
+	{ MANU_ANT,  PROD_ANT_ETHER3, &ether3 },
+	{ MANU_ANT,  PROD_ANT_ETHERB, &etherb },
 	{ 0xffff, 0xffff }
 };
 
diff --git a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h
--- a/drivers/net/arm/ether3.h
+++ b/drivers/net/arm/ether3.h
@@ -22,8 +22,10 @@
 #define NET_DEBUG 	0
 #endif
 
+#define priv(dev)	((struct dev_priv *)netdev_priv(dev))
+
 /* Command register definitions & bits */
-#define REG_COMMAND		(dev->base_addr + 0x00)
+#define REG_COMMAND		(priv(dev)->seeq + 0x0000)
 #define CMD_ENINTDMA		0x0001
 #define CMD_ENINTRX		0x0002
 #define CMD_ENINTTX		0x0004
@@ -42,7 +44,7 @@
 #define CMD_FIFOWRITE		0x8000
 
 /* status register */
-#define REG_STATUS		(dev->base_addr + 0x00)
+#define REG_STATUS		(priv(dev)->seeq + 0x0000)
 #define STAT_ENINTSTAT		0x0001
 #define STAT_ENINTRX		0x0002
 #define STAT_ENINTTX		0x0004
@@ -59,7 +61,7 @@
 #define STAT_FIFODIR		0x8000
 
 /* configuration register 1 */
-#define REG_CONFIG1		(dev->base_addr + 0x10)
+#define REG_CONFIG1		(priv(dev)->seeq + 0x0040)
 #define CFG1_BUFSELSTAT0	0x0000
 #define CFG1_BUFSELSTAT1	0x0001
 #define CFG1_BUFSELSTAT2	0x0002
@@ -92,7 +94,7 @@
 #define CFG1_RECVCOMPSTAT5	0x2000
 
 /* configuration register 2 */
-#define REG_CONFIG2		(dev->base_addr + 0x20)
+#define REG_CONFIG2		(priv(dev)->seeq + 0x0080)
 #define CFG2_BYTESWAP		0x0001
 #define CFG2_ERRENCRC		0x0008
 #define CFG2_ERRENDRIBBLE	0x0010
@@ -106,15 +108,15 @@
 #define CFG2_CTRLO		0x1000
 #define CFG2_RESET		0x8000
 
-#define REG_RECVEND		(dev->base_addr + 0x30)
+#define REG_RECVEND		(priv(dev)->seeq + 0x00c0)
 
-#define REG_BUFWIN		(dev->base_addr + 0x40)
+#define REG_BUFWIN		(priv(dev)->seeq + 0x0100)
 
-#define REG_RECVPTR		(dev->base_addr + 0x50)
+#define REG_RECVPTR		(priv(dev)->seeq + 0x0140)
 
-#define REG_TRANSMITPTR		(dev->base_addr + 0x60)
+#define REG_TRANSMITPTR		(priv(dev)->seeq + 0x0180)
 
-#define REG_DMAADDR		(dev->base_addr + 0x70)
+#define REG_DMAADDR		(priv(dev)->seeq + 0x01c0)
 
 /*
  * Cards transmit/receive headers
@@ -152,6 +154,8 @@
 #define MAX_TX_BUFFERED	10
 
 struct dev_priv {
+    void __iomem *base;
+    void __iomem *seeq;
     struct {
 	unsigned int command;
 	unsigned int config1;
@@ -165,4 +169,9 @@ struct dev_priv {
     int broken;				/* 0 = ok, 1 = something went wrong	 */
 };
 
+struct ether3_data {
+	const char name[8];
+	unsigned long base_offset;
+};
+
 #endif
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1,10 +1,19 @@
 /*
- * Alchemy Semi Au1000 ethernet driver
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Alchemy Au1x00 ethernet driver
+ *
+ * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2002 TimeSys Corp.
+ * Added ethtool/mii-tool support,
+ * Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
+ * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de 
+ * or riemer@riemer-nt.de: fixed the link beat detection with 
+ * ioctls (SIOCGMIIPHY)
  * 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.
@@ -17,46 +26,59 @@
  *  You 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/sched.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
+#include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/au1000.h>
+#include <asm/processor.h>
 
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/cpu.h>
 #include "au1000_eth.h"
 
 #ifdef AU1000_ETH_DEBUG
-static int au1000_debug = 10;
+static int au1000_debug = 5;
 #else
 static int au1000_debug = 3;
 #endif
 
+#define DRV_NAME	"au1000eth"
+#define DRV_VERSION	"1.5"
+#define DRV_AUTHOR	"Pete Popov <ppopov@embeddedalley.com>"
+#define DRV_DESC	"Au1xxx on-chip Ethernet driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
 // prototypes
-static void *dma_alloc(size_t, dma_addr_t *);
-static void dma_free(void *, size_t);
 static void hard_stop(struct net_device *);
 static void enable_rx_tx(struct net_device *dev);
-static int __init au1000_probe1(long, int, int);
+static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
 static int au1000_init(struct net_device *);
 static int au1000_open(struct net_device *);
 static int au1000_close(struct net_device *);
@@ -78,8 +100,7 @@ static void dump_mii(struct net_device *
 // externs
 extern  void ack_rise_edge_irq(unsigned int);
 extern int get_ethernet_addr(char *ethernet_addr);
-extern inline void str2eaddr(unsigned char *ea, unsigned char *str);
-extern inline unsigned char str2hexnum(unsigned char c);
+extern void str2eaddr(unsigned char *ea, unsigned char *str);
 extern char * __init prom_getcmdline(void);
 
 /*
@@ -97,29 +118,6 @@ extern char * __init prom_getcmdline(voi
  * complete immediately.
  */
 
-
-/*
- * Base address and interrupt of the Au1xxx ethernet macs
- */
-static struct {
-	unsigned int port;
-	int irq;
-} au1000_iflist[NUM_INTERFACES] = {
-		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 
-		{AU1000_ETH1_BASE, AU1000_ETH1_IRQ}
-	},
-  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}, 
-		{0, 0}
-	};
-
-static char version[] __devinitdata =
-    "au1000eth.c:1.0 ppopov@mvista.com\n";
-
 /* These addresses are only used if yamon doesn't tell us what
  * the mac address is, and the mac address is not passed on the
  * command line.
@@ -135,18 +133,401 @@ static unsigned char au1000_mac_addr[6] 
 #define cpu_to_dma32 cpu_to_be32
 #define dma32_to_cpu be32_to_cpu
 
+struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 
 /* FIXME 
  * All of the PHY code really should be detached from the MAC 
  * code.
  */
 
-int bcm_5201_init(struct net_device *dev, int phy_addr)
+/* Default advertise */
+#define GENMII_DEFAULT_ADVERTISE \
+	ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+	ADVERTISED_Autoneg
+
+#define GENMII_DEFAULT_FEATURES \
+	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+	SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+	SUPPORTED_Autoneg
+
+static char *phy_link[] = 
+{	"unknown", 
+	"10Base2", "10BaseT", 
+	"AUI",
+	"100BaseT", "100BaseTX", "100BaseFX"
+};
+
+int bcm_5201_init(struct net_device *dev, int phy_addr)
+{
+	s16 data;
+	
+	/* Stop auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
+
+	if (au1000_debug > 4) 
+		dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int bcm_5201_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int 
+bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "bcm_5201_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
+		if (mii_data & MII_AUX_100) {
+			if (mii_data & MII_AUX_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int lsi_80227_init(struct net_device *dev, int phy_addr)
+{
+	if (au1000_debug > 4)
+		printk("lsi_80227_init\n");
+
+	/* restart auto-negotiation */
+	mdio_write(dev, phy_addr, MII_CONTROL,
+		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); // | MII_CNTL_FDX);
+	mdelay(1);
+
+	/* set up LEDs to correct display */
+#ifdef CONFIG_MIPS_MTX1
+	mdio_write(dev, phy_addr, 17, 0xff80);
+#else
+	mdio_write(dev, phy_addr, 17, 0xffc0);
+#endif
+
+	if (au1000_debug > 4)
+		dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int lsi_80227_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	if (au1000_debug > 4) {
+		printk("lsi_80227_reset\n");
+		dump_mii(dev, phy_addr);
+	}
+
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int
+lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "lsi_80227_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_PHY_STAT);
+		if (mii_data & MII_LSI_PHY_STAT_SPD) {
+			if (mii_data & MII_LSI_PHY_STAT_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int am79c901_init(struct net_device *dev, int phy_addr)
+{
+	printk("am79c901_init\n");
+	return 0;
+}
+
+int am79c901_reset(struct net_device *dev, int phy_addr)
+{
+	printk("am79c901_reset\n");
+	return 0;
+}
+
+int 
+am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	return 0;
+}
+
+int am79c874_init(struct net_device *dev, int phy_addr)
+{
+	s16 data;
+
+	/* 79c874 has quit resembled bit assignments to BCM5201 */
+	if (au1000_debug > 4)
+		printk("am79c847_init\n");
+
+	/* Stop auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
+
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
+
+	if (au1000_debug > 4) dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int am79c874_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	if (au1000_debug > 4)
+		printk("am79c874_reset\n");
+
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int 
+am79c874_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	// printk("am79c874_status\n");
+	if (!dev) {
+		printk(KERN_ERR "am79c874_status error: NULL dev\n");
+		return -1;
+	}
+
+	aup = (struct au1000_private *) dev->priv;
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_AMD_PHY_STAT);
+		if (mii_data & MII_AMD_PHY_STAT_SPD) {
+			if (mii_data & MII_AMD_PHY_STAT_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int lxt971a_init(struct net_device *dev, int phy_addr)
+{
+	if (au1000_debug > 4)
+		printk("lxt971a_init\n");
+
+	/* restart auto-negotiation */
+	mdio_write(dev, phy_addr, MII_CONTROL,
+		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO | MII_CNTL_FDX);
+
+	/* set up LEDs to correct display */
+	mdio_write(dev, phy_addr, 20, 0x0422);
+
+	if (au1000_debug > 4)
+		dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int lxt971a_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	if (au1000_debug > 4) {
+		printk("lxt971a_reset\n");
+		dump_mii(dev, phy_addr);
+	}
+
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int
+lxt971a_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "lxt971a_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_INTEL_PHY_STAT);
+		if (mii_data & MII_INTEL_PHY_STAT_SPD) {
+			if (mii_data & MII_INTEL_PHY_STAT_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int ks8995m_init(struct net_device *dev, int phy_addr)
 {
 	s16 data;
 	
+//	printk("ks8995m_init\n");
 	/* Stop auto-negotiation */
-	//printk("bcm_5201_init\n");
 	data = mdio_read(dev, phy_addr, MII_CONTROL);
 	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
 
@@ -161,25 +542,16 @@ int bcm_5201_init(struct net_device *dev
 	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);
-
-	/* 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;
 }
 
-int bcm_5201_reset(struct net_device *dev, int phy_addr)
+int ks8995m_reset(struct net_device *dev, int phy_addr)
 {
 	s16 mii_control, timeout;
 	
-	//printk("bcm_5201_reset\n");
+//	printk("ks8995m_reset\n");
 	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
 	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
 	mdelay(1);
@@ -196,14 +568,13 @@ int bcm_5201_reset(struct net_device *de
 	return 0;
 }
 
-int 
-bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+int ks8995m_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
 {
 	u16 mii_data;
 	struct au1000_private *aup;
 
 	if (!dev) {
-		printk(KERN_ERR "bcm_5201_status error: NULL dev\n");
+		printk(KERN_ERR "ks8995m_status error: NULL dev\n");
 		return -1;
 	}
 	aup = (struct au1000_private *) dev->priv;
@@ -222,7 +593,7 @@ bcm_5201_status(struct net_device *dev, 
 				dev->if_port = IF_PORT_100BASETX;
 			}
 		}
-		else  {
+		else  {											
 			*speed = IF_PORT_10BASET;
 			dev->if_port = IF_PORT_10BASET;
 		}
@@ -236,32 +607,41 @@ bcm_5201_status(struct net_device *dev, 
 	return 0;
 }
 
-int lsi_80227_init(struct net_device *dev, int phy_addr)
+int
+smsc_83C185_init (struct net_device *dev, int phy_addr)
 {
+	s16 data;
+
 	if (au1000_debug > 4)
-		printk("lsi_80227_init\n");
+		printk("smsc_83C185_init\n");
 
-	/* restart auto-negotiation */
-	mdio_write(dev, phy_addr, 0, 0x3200);
+	/* Stop auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
 
-	mdelay(1);
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
 
-	/* set up LEDs to correct display */
-	mdio_write(dev, phy_addr, 17, 0xffc0);
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
 
-	if (au1000_debug > 4)
-		dump_mii(dev, phy_addr);
+	if (au1000_debug > 4) dump_mii(dev, phy_addr);
 	return 0;
 }
 
-int lsi_80227_reset(struct net_device *dev, int phy_addr)
+int
+smsc_83C185_reset (struct net_device *dev, int phy_addr)
 {
 	s16 mii_control, timeout;
 	
-	if (au1000_debug > 4) {
-		printk("lsi_80227_reset\n");
-		dump_mii(dev, phy_addr);
-	}
+	if (au1000_debug > 4)
+		printk("smsc_83C185_reset\n");
 
 	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
 	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
@@ -279,24 +659,25 @@ int lsi_80227_reset(struct net_device *d
 	return 0;
 }
 
-int
-lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+int 
+smsc_83C185_status (struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
 {
 	u16 mii_data;
 	struct au1000_private *aup;
 
 	if (!dev) {
-		printk(KERN_ERR "lsi_80227_status error: NULL dev\n");
+		printk(KERN_ERR "smsc_83C185_status error: NULL dev\n");
 		return -1;
 	}
-	aup = (struct au1000_private *) dev->priv;
 
+	aup = (struct au1000_private *) dev->priv;
 	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+
 	if (mii_data & MII_STAT_LINK) {
 		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT);
-		if (mii_data & MII_LSI_STAT_SPD) {
-			if (mii_data & MII_LSI_STAT_FDX) {
+		mii_data = mdio_read(dev, aup->phy_addr, 0x1f);
+		if (mii_data & (1<<3)) {
+			if (mii_data & (1<<4)) {
 				*speed = IF_PORT_100BASEFX;
 				dev->if_port = IF_PORT_100BASEFX;
 			}
@@ -305,11 +686,10 @@ lsi_80227_status(struct net_device *dev,
 				dev->if_port = IF_PORT_100BASETX;
 			}
 		}
-		else  {
+		else {
 			*speed = IF_PORT_10BASET;
 			dev->if_port = IF_PORT_10BASET;
 		}
-
 	}
 	else {
 		*link = 0;
@@ -319,23 +699,31 @@ lsi_80227_status(struct net_device *dev,
 	return 0;
 }
 
-int am79c901_init(struct net_device *dev, int phy_addr)
+
+#ifdef CONFIG_MIPS_BOSPORUS
+int stub_init(struct net_device *dev, int phy_addr)
 {
-	printk("am79c901_init\n");
+	//printk("PHY stub_init\n");
 	return 0;
 }
 
-int am79c901_reset(struct net_device *dev, int phy_addr)
+int stub_reset(struct net_device *dev, int phy_addr)
 {
-	printk("am79c901_reset\n");
+	//printk("PHY stub_reset\n");
 	return 0;
 }
 
 int 
-am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+stub_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
 {
+	//printk("PHY stub_status\n");
+	*link = 1;
+	/* hmmm, revisit */
+	*speed = IF_PORT_100BASEFX;
+	dev->if_port = IF_PORT_100BASEFX;
 	return 0;
 }
+#endif
 
 struct phy_ops bcm_5201_ops = {
 	bcm_5201_init,
@@ -343,6 +731,12 @@ struct phy_ops bcm_5201_ops = {
 	bcm_5201_status,
 };
 
+struct phy_ops am79c874_ops = {
+	am79c874_init,
+	am79c874_reset,
+	am79c874_status,
+};
+
 struct phy_ops am79c901_ops = {
 	am79c901_init,
 	am79c901_reset,
@@ -355,26 +749,89 @@ struct phy_ops lsi_80227_ops = { 
 	lsi_80227_status,
 };
 
+struct phy_ops lxt971a_ops = { 
+	lxt971a_init,
+	lxt971a_reset,
+	lxt971a_status,
+};
+
+struct phy_ops ks8995m_ops = {
+	ks8995m_init,
+	ks8995m_reset,
+	ks8995m_status,
+};
+
+struct phy_ops smsc_83C185_ops = {
+	smsc_83C185_init,
+	smsc_83C185_reset,
+	smsc_83C185_status,
+};
+
+#ifdef CONFIG_MIPS_BOSPORUS
+struct phy_ops stub_ops = {
+	stub_init,
+	stub_reset,
+	stub_status,
+};
+#endif
+
 static struct mii_chip_info {
 	const char * name;
 	u16 phy_id0;
 	u16 phy_id1;
 	struct phy_ops *phy_ops;	
+	int dual_phy;
 } mii_chip_table[] = {
-	{"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 },
+	{"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
+	{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
+	{"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
+	{"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
+	{"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
+	{"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
+	{"Intel LXT971A Dual Speed PHY",0x0013,0x78e2, &lxt971a_ops,0},
+	{"Kendin KS8995M 10/100 BaseT PHY",0x0022,0x1450, &ks8995m_ops,0},
+	{"SMSC LAN83C185 10/100 BaseT PHY",0x0007,0xc0a3, &smsc_83C185_ops,0},
+#ifdef CONFIG_MIPS_BOSPORUS
+	{"Stub", 0x1234, 0x5678, &stub_ops },
+#endif
 	{0,},
 };
 
 static int mdio_read(struct net_device *dev, int phy_id, int reg)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	volatile u32 *mii_control_reg;
+	volatile u32 *mii_data_reg;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	/* First time we probe, it's for the mac0 phy.
+	 * Since we haven't determined yet that we have a dual phy,
+	 * aup->mii->mii_control_reg won't be setup and we'll
+	 * default to the else statement.
+	 * By the time we probe for the mac1 phy, the mii_control_reg
+	 * will be setup to be the address of the mac0 phy control since
+	 * both phys are controlled through mac0.
+	 */
+	if (aup->mii && aup->mii->mii_control_reg) {
+		mii_control_reg = aup->mii->mii_control_reg;
+		mii_data_reg = aup->mii->mii_data_reg;
+	}
+	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+		/* assume both phys are controlled through mac0 */
+		mii_control_reg = au_macs[0]->mii->mii_control_reg;
+		mii_data_reg = au_macs[0]->mii->mii_data_reg;
+	}
+	else 
+	#endif
+	{
+		/* default control and data reg addresses */
+		mii_control_reg = &aup->mac->mii_control;
+		mii_data_reg = &aup->mac->mii_data;
+	}
+
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: read_MII busy timeout!!\n", 
@@ -386,10 +843,10 @@ static int mdio_read(struct net_device *
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;
 
-	aup->mac->mii_control = mii_control;
+	*mii_control_reg = mii_control;
 
 	timedout = 20;
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: mdio_read busy timeout!!\n", 
@@ -397,16 +854,36 @@ static int mdio_read(struct net_device *
 			return -1;
 		}
 	}
-	return (int)aup->mac->mii_data;
+	return (int)*mii_data_reg;
 }
 
 static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	volatile u32 *mii_control_reg;
+	volatile u32 *mii_data_reg;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	if (aup->mii && aup->mii->mii_control_reg) {
+		mii_control_reg = aup->mii->mii_control_reg;
+		mii_data_reg = aup->mii->mii_data_reg;
+	}
+	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+		/* assume both phys are controlled through mac0 */
+		mii_control_reg = au_macs[0]->mii->mii_control_reg;
+		mii_data_reg = au_macs[0]->mii->mii_data_reg;
+	}
+	else 
+	#endif
+	{
+		/* default control and data reg addresses */
+		mii_control_reg = &aup->mac->mii_control;
+		mii_data_reg = &aup->mac->mii_data;
+	}
+
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: mdio_write busy timeout!!\n", 
@@ -418,8 +895,8 @@ static void mdio_write(struct net_device
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;
 
-	aup->mac->mii_data = value;
-	aup->mac->mii_control = mii_control;
+	*mii_data_reg = value;
+	*mii_control_reg = mii_control;
 }
 
 
@@ -437,12 +914,13 @@ static void dump_mii(struct net_device *
 	}
 }
 
-static int __init mii_probe (struct net_device * dev)
+static int mii_probe (struct net_device * dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 	int phy_addr;
-
-	aup->mii = NULL;
+#ifdef CONFIG_MIPS_BOSPORUS
+	int phy_found=0;
+#endif
 
 	/* search for total of 32 possible mii phy addresses */
 	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
@@ -450,9 +928,17 @@ static int __init mii_probe (struct net_
 		u16 phy_id0, phy_id1;
 		int i;
 
+		#ifdef CONFIG_BCM5222_DUAL_PHY
+		/* Mask the already found phy, try next one */
+		if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+			if (au_macs[0]->phy_addr == phy_addr)
+				continue;
+		}
+		#endif
+
 		mii_status = mdio_read(dev, phy_addr, MII_STATUS);
 		if (mii_status == 0xffff || mii_status == 0x0000)
-			/* the mii is not accessible, try next one */
+			/* the mii is not accessable, try next one */
 			continue;
 
 		phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);
@@ -462,6 +948,66 @@ static int __init mii_probe (struct net_
 		for (i = 0; mii_chip_table[i].phy_id1; i++) {
 			if (phy_id0 == mii_chip_table[i].phy_id0 &&
 			    phy_id1 == mii_chip_table[i].phy_id1) {
+				struct mii_phy * mii_phy = aup->mii;
+
+				printk(KERN_INFO "%s: %s at phy address %d\n",
+				       dev->name, mii_chip_table[i].name, 
+				       phy_addr);
+#ifdef CONFIG_MIPS_BOSPORUS
+				phy_found = 1;
+#endif
+				mii_phy->chip_info = mii_chip_table+i;
+				aup->phy_addr = phy_addr;
+				aup->want_autoneg = 1;
+				aup->phy_ops = mii_chip_table[i].phy_ops;
+				aup->phy_ops->phy_init(dev,phy_addr);
+
+				// Check for dual-phy and then store required 
+				// values and set indicators. We need to do 
+				// this now since mdio_{read,write} need the 
+				// control and data register addresses.
+				#ifdef CONFIG_BCM5222_DUAL_PHY
+				if ( mii_chip_table[i].dual_phy) {
+
+					/* assume both phys are controlled 
+					 * through MAC0. Board specific? */
+					
+					/* sanity check */
+					if (!au_macs[0] || !au_macs[0]->mii)
+						return -1;
+					aup->mii->mii_control_reg = (u32 *)
+						&au_macs[0]->mac->mii_control;
+					aup->mii->mii_data_reg = (u32 *)
+						&au_macs[0]->mac->mii_data;
+				}
+				#endif
+				goto found;
+			}
+		}
+	}
+found:
+
+#ifdef CONFIG_MIPS_BOSPORUS
+	/* This is a workaround for the Micrel/Kendin 5 port switch
+	   The second MAC doesn't see a PHY connected... so we need to
+	   trick it into thinking we have one.
+		
+	   If this kernel is run on another Au1500 development board
+	   the stub will be found as well as the actual PHY. However,
+	   the last found PHY will be used... usually at Addr 31 (Db1500).	
+	*/
+	if ( (!phy_found) )
+	{
+		u16 phy_id0, phy_id1;
+		int i;
+
+		phy_id0 = 0x1234;
+		phy_id1 = 0x5678;
+
+		/* search our mii table for the current mii */ 
+		for (i = 0; mii_chip_table[i].phy_id1; i++) {
+			if (phy_id0 == mii_chip_table[i].phy_id0 &&
+			    phy_id1 == mii_chip_table[i].phy_id1) {
 				struct mii_phy * mii_phy;
 
 				printk(KERN_INFO "%s: %s at phy address %d\n",
@@ -471,31 +1017,39 @@ static int __init mii_probe (struct net_
 						GFP_KERNEL);
 				if (mii_phy) {
 					mii_phy->chip_info = mii_chip_table+i;
-					mii_phy->phy_addr = phy_addr;
+					aup->phy_addr = phy_addr;
 					mii_phy->next = aup->mii;
 					aup->phy_ops = 
 						mii_chip_table[i].phy_ops;
 					aup->mii = mii_phy;
 					aup->phy_ops->phy_init(dev,phy_addr);
 				} else {
-					printk(KERN_ERR "%s: out of memory\n",
+					printk(KERN_ERR "%s: out of memory\n", 
 							dev->name);
 					return -1;
 				}
-				/* the current mii is on our mii_info_table,
-				   try next address */
+				mii_phy->chip_info = mii_chip_table+i;
+				aup->phy_addr = phy_addr;
+				aup->phy_ops = mii_chip_table[i].phy_ops;
+				aup->phy_ops->phy_init(dev,phy_addr);
 				break;
 			}
 		}
 	}
+	if (aup->mac_id == 0) {
+		/* the Bosporus phy responds to addresses 0-5 but 
+		 * 5 is the correct one.
+		 */
+		aup->phy_addr = 5;
+	}
+#endif
 
-	if (aup->mii == NULL) {
-		printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name);
+	if (aup->mii->chip_info == NULL) {
+		printk(KERN_ERR "%s: Au1x No MII transceivers found!\n",
+				dev->name);
 		return -1;
 	}
 
-	/* use last PHY */
-	aup->phy_addr = aup->mii->phy_addr;
 	printk(KERN_INFO "%s: Using %s as default\n", 
 			dev->name, aup->mii->chip_info->name);
 
@@ -516,7 +1070,6 @@ static db_dest_t *GetFreeDB(struct au100
 	if (pDB) {
 		aup->pDBfree = pDB->pnext;
 	}
-	//printk("GetFreeDB: %x\n", pDB);
 	return pDB;
 }
 
@@ -528,35 +1081,6 @@ void ReleaseDB(struct au1000_private *au
 	aup->pDBfree = pDB;
 }
 
-
-/*
-  DMA memory allocation, derived from pci_alloc_consistent.
-  However, the Au1000 data cache is coherent (when programmed
-  so), therefore we return KSEG0 address, not KSEG1.
-*/
-static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC | GFP_DMA;
-
-	ret = (void *) __get_free_pages(gfp, get_order(size));
-
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_bus(ret);
-		ret = (void *)KSEG0ADDR(ret);
-	}
-	return ret;
-}
-
-
-static void dma_free(void *vaddr, size_t size)
-{
-	vaddr = (void *)KSEG0ADDR(vaddr);
-	free_pages((unsigned long) vaddr, get_order(size));
-}
-
-
 static void enable_rx_tx(struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -582,6 +1106,7 @@ static void hard_stop(struct net_device 
 
 static void reset_mac(struct net_device *dev)
 {
+	int i;
 	u32 flags;
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 
@@ -590,13 +1115,32 @@ static void reset_mac(struct net_device 
 				dev->name, (unsigned)aup);
 
 	spin_lock_irqsave(&aup->lock, flags);
-	del_timer(&aup->timer);
+	if (aup->timer.function == &au1000_timer) {/* check if timer initted */
+		del_timer(&aup->timer);
+	}
+
 	hard_stop(dev);
-	*aup->enable = MAC_EN_CLOCK_ENABLE;
-	au_sync_delay(2);
-       	*aup->enable = 0;
-	au_sync_delay(2);
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	if (aup->mac_id != 0) {
+	#endif
+		/* If BCM5222, we can't leave MAC0 in reset because then 
+		 * we can't access the dual phy for ETH1 */
+		*aup->enable = MAC_EN_CLOCK_ENABLE;
+		au_sync_delay(2);
+		*aup->enable = 0;
+		au_sync_delay(2);
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	}
+	#endif
 	aup->tx_full = 0;
+	for (i = 0; i < NUM_RX_DMA; i++) {
+		/* reset control bits */
+		aup->rx_dma_ring[i]->buff_stat &= ~0xf;
+	}
+	for (i = 0; i < NUM_TX_DMA; i++) {
+		/* reset control bits */
+		aup->tx_dma_ring[i]->buff_stat &= ~0xf;
+	}
 	spin_unlock_irqrestore(&aup->lock, flags);
 }
 
@@ -611,93 +1155,348 @@ setup_hw_rings(struct au1000_private *au
 {
 	int i;
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		aup->rx_dma_ring[i] = 
 			(volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
 	}
-	for (i=0; i<NUM_TX_DMA; i++) {
+	for (i = 0; i < NUM_TX_DMA; i++) {
 		aup->tx_dma_ring[i] = 
 			(volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
 	}
 }
 
+static struct {
+	int port;
+	u32 base_addr;
+	u32 macen_addr;
+	int irq;
+	struct net_device *dev;
+} iflist[2];
+
+static int num_ifs;
+
+/*
+ * Setup the base address and interupt of the Au1xxx ethernet macs
+ * based on cpu type and whether the interface is enabled in sys_pinfunc
+ * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
+ */
 static int __init au1000_init_module(void)
 {
-	int i;
-	int prid;
-	int base_addr, irq;
+	struct cpuinfo_mips *c = &current_cpu_data;
+	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
+	struct net_device *dev;
+	int i, found_one = 0;
+
+	switch (c->cputype) {
+#ifdef CONFIG_SOC_AU1000
+	case CPU_AU1000:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1000_ETH0_BASE;
+		iflist[1].base_addr = AU1000_ETH1_BASE;
+		iflist[0].macen_addr = AU1000_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1000_MAC1_ENABLE;
+		iflist[0].irq = AU1000_MAC0_DMA_INT;
+		iflist[1].irq = AU1000_MAC1_DMA_INT;
+		break;
+#endif
+#ifdef CONFIG_SOC_AU1100
+	case CPU_AU1100:
+		num_ifs = 1 - ni;
+		iflist[0].base_addr = AU1100_ETH0_BASE;
+		iflist[0].macen_addr = AU1100_MAC0_ENABLE;
+		iflist[0].irq = AU1100_MAC0_DMA_INT;
+		break;
+#endif
+#ifdef CONFIG_SOC_AU1500
+	case CPU_AU1500:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1500_ETH0_BASE;
+		iflist[1].base_addr = AU1500_ETH1_BASE;
+		iflist[0].macen_addr = AU1500_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1500_MAC1_ENABLE;
+		iflist[0].irq = AU1500_MAC0_DMA_INT;
+		iflist[1].irq = AU1500_MAC1_DMA_INT;
+		break;
+#endif
+#ifdef CONFIG_SOC_AU1550
+	case CPU_AU1550:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1550_ETH0_BASE;
+		iflist[1].base_addr = AU1550_ETH1_BASE;
+		iflist[0].macen_addr = AU1550_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1550_MAC1_ENABLE;
+		iflist[0].irq = AU1550_MAC0_DMA_INT;
+		iflist[1].irq = AU1550_MAC1_DMA_INT;
+		break;
+#endif
+	default:
+		num_ifs = 0;
+	}
+	for(i = 0; i < num_ifs; i++) {
+		dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
+		iflist[i].dev = dev;
+		if (dev)
+			found_one++;
+	}
+	if (!found_one)
+		return -ENODEV;
+	return 0;
+}
+
+static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	u16 ctl, adv;
+
+	/* Setup standard advertise */
+	adv = mdio_read(dev, aup->phy_addr, MII_ADVERTISE);
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	mdio_write(dev, aup->phy_addr, MII_ADVERTISE, adv);
+
+	/* Start/Restart aneg */
+	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
+
+	return 0;
+}
 
-	prid = read_c0_prid();
-	for (i=0; i<NUM_INTERFACES; i++) {
-		if ( (prid & 0xffff0000) == 0x00030000 ) {
-			base_addr = au1000_iflist[i].port;
-			irq = au1000_iflist[i].irq;
-		} 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;
+static int au1000_setup_forced(struct net_device *dev, int speed, int fd)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	u16 ctl;
+
+	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
+
+	/* First reset the PHY */
+	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl | BMCR_RESET);
+
+	/* Select speed & duplex */
+	switch (speed) {
+		case SPEED_10:
+			break;
+		case SPEED_100:
+			ctl |= BMCR_SPEED100;
+			break;
+		case SPEED_1000:
+		default:
+			return -EINVAL;
+	}
+	if (fd == DUPLEX_FULL)
+		ctl |= BMCR_FULLDPLX;
+	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
+
+	return 0;
+}
+
+
+static void
+au1000_start_link(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	u32 advertise;
+	int autoneg;
+	int forced_speed;
+	int forced_duplex;
+
+	/* Default advertise */
+	advertise = GENMII_DEFAULT_ADVERTISE;
+	autoneg = aup->want_autoneg;
+	forced_speed = SPEED_100;
+	forced_duplex = DUPLEX_FULL;
+
+	/* Setup link parameters */
+	if (cmd) {
+		if (cmd->autoneg == AUTONEG_ENABLE) {
+			advertise = cmd->advertising;
+			autoneg = 1;
 		} 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(base_addr, irq, i) != 0)
-				return -ENODEV;
+			autoneg = 0;
+
+			forced_speed = cmd->speed;
+			forced_duplex = cmd->duplex;
 		}
 	}
+
+	/* Configure PHY & start aneg */
+	aup->want_autoneg = autoneg;
+	if (autoneg)
+		au1000_setup_aneg(dev, advertise);
+	else
+		au1000_setup_forced(dev, forced_speed, forced_duplex);
+	mod_timer(&aup->timer, jiffies + HZ);
+}
+
+static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	u16 link, speed;
+
+	cmd->supported = GENMII_DEFAULT_FEATURES;
+	cmd->advertising = GENMII_DEFAULT_ADVERTISE;
+	cmd->port = PORT_MII;
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->phy_address = aup->phy_addr;
+	spin_lock_irq(&aup->lock);
+	cmd->autoneg = aup->want_autoneg;
+	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
+	if ((speed == IF_PORT_100BASETX) || (speed == IF_PORT_100BASEFX))
+		cmd->speed = SPEED_100;
+	else if (speed == IF_PORT_10BASET)
+		cmd->speed = SPEED_10;
+	if (link && (dev->if_port == IF_PORT_100BASEFX))
+		cmd->duplex = DUPLEX_FULL;
+	else
+		cmd->duplex = DUPLEX_HALF;
+	spin_unlock_irq(&aup->lock);
 	return 0;
 }
 
-static int __init
-au1000_probe1(long ioaddr, int irq, int port_num)
+static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	 struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	  unsigned long features = GENMII_DEFAULT_FEATURES;
+
+	 if (!capable(CAP_NET_ADMIN))
+		 return -EPERM;
+
+	 if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+		 return -EINVAL;
+	 if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+		 return -EINVAL;
+	 if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
+		 return -EINVAL;
+	 if (cmd->autoneg == AUTONEG_DISABLE)
+		 switch (cmd->speed) {
+		 case SPEED_10:
+			 if (cmd->duplex == DUPLEX_HALF &&
+				 (features & SUPPORTED_10baseT_Half) == 0)
+				 return -EINVAL;
+			 if (cmd->duplex == DUPLEX_FULL &&
+				 (features & SUPPORTED_10baseT_Full) == 0)
+				 return -EINVAL;
+			 break;
+		 case SPEED_100:
+			 if (cmd->duplex == DUPLEX_HALF &&
+				 (features & SUPPORTED_100baseT_Half) == 0)
+				 return -EINVAL;
+			 if (cmd->duplex == DUPLEX_FULL &&
+				 (features & SUPPORTED_100baseT_Full) == 0)
+				 return -EINVAL;
+			 break;
+		 default:
+			 return -EINVAL;
+		 }
+	 else if ((features & SUPPORTED_Autoneg) == 0)
+		 return -EINVAL;
+
+	 spin_lock_irq(&aup->lock);
+	 au1000_start_link(dev, cmd);
+	 spin_unlock_irq(&aup->lock);
+	 return 0;
+}
+
+static int au1000_nway_reset(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+
+	if (!aup->want_autoneg)
+		return -EINVAL;
+	spin_lock_irq(&aup->lock);
+	au1000_start_link(dev, NULL);
+	spin_unlock_irq(&aup->lock);
+	return 0;
+}
+
+static void
+au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	info->fw_version[0] = '\0';
+	sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id);
+	info->regdump_len = 0;
+}
+
+static u32 au1000_get_link(struct net_device *dev)
+{
+	return netif_carrier_ok(dev);
+}
+
+static struct ethtool_ops au1000_ethtool_ops = {
+	.get_settings = au1000_get_settings,
+	.set_settings = au1000_set_settings,
+	.get_drvinfo = au1000_get_drvinfo,
+	.nway_reset = au1000_nway_reset,
+	.get_link = au1000_get_link
+};
+
+static struct net_device *
+au1000_probe(u32 ioaddr, int irq, int port_num)
 {
-	struct net_device *dev;
 	static unsigned version_printed = 0;
 	struct au1000_private *aup = NULL;
-	int i, retval = 0;
+	struct net_device *dev = NULL;
 	db_dest_t *pDB, *pDBfree;
 	char *pmac, *argptr;
 	char ethaddr[6];
+	int i, err;
 
-	if (!request_region(PHYSADDR(ioaddr), MAC_IOSIZE, "Au1000 ENET"))
-		 return -ENODEV;
+	if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
+		return NULL;
 
-	if (version_printed++ == 0)
-		printk(version);
-
-	retval = -ENOMEM;
+	if (version_printed++ == 0) 
+		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
 
 	dev = alloc_etherdev(sizeof(struct au1000_private));
 	if (!dev) {
 		printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");  
-		goto out;
+		return NULL;
 	}
 
-	SET_MODULE_OWNER(dev);
+	if ((err = register_netdev(dev))) {
+		printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
+				err);
+		free_netdev(dev);
+		return NULL;
+	}
 
-	printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", 
-	       dev->name, ioaddr, irq);
+	printk("%s: Au1x Ethernet found at 0x%x, irq %d\n", 
+			dev->name, ioaddr, irq);
 
 	aup = dev->priv;
 
 	/* Allocate the data buffers */
-	aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * 
-			(NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr);
-	if (!aup->vaddr)
-		goto out1;
+	/* Snooping works fine with eth on all au1xxx */
+	aup->vaddr = (u32)dma_alloc_noncoherent(NULL,
+			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
+			&aup->dma_addr,
+			0);
+	if (!aup->vaddr) {
+		free_netdev(dev);
+		release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+		return NULL;
+	}
 
 	/* aup->mac is the base address of the MAC's registers */
 	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
 	/* Setup some variables for quick register address access */
-	switch (ioaddr) {
-	case AU1000_ETH0_BASE:
-	case AU1500_ETH0_BASE:
+	if (ioaddr == iflist[0].base_addr)
+	{
 		/* check env variables first */
 		if (!get_ethernet_addr(ethaddr)) { 
-			memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr));
+			memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
 		} else {
 			/* Check command line */
 			argptr = prom_getcmdline();
@@ -708,38 +1507,32 @@ au1000_probe1(long ioaddr, int irq, int 
 			} else {
 				str2eaddr(ethaddr, pmac + strlen("ethaddr="));
 				memcpy(au1000_mac_addr, ethaddr, 
-						sizeof(dev->dev_addr));
+						sizeof(au1000_mac_addr));
 			}
 		}
-		if (ioaddr == AU1000_ETH0_BASE)
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC0_ENABLE);
-		else
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC0_ENABLE);
-		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
+				((unsigned long)iflist[0].macen_addr);
+		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
 		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
-			break;
-	case AU1000_ETH1_BASE:
-	case AU1500_ETH1_BASE:
-		if (ioaddr == AU1000_ETH1_BASE)
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC1_ENABLE);
+		aup->mac_id = 0;
+		au_macs[0] = aup;
+	}
 		else
+	if (ioaddr == iflist[1].base_addr)
+	{
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC1_ENABLE);
-		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
+				((unsigned long)iflist[1].macen_addr);
+		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
 		dev->dev_addr[4] += 0x10;
 		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
-			break;
-	default:
+		aup->mac_id = 1;
+		au_macs[1] = aup;
+	}
+	else
+	{
 		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
-		break;
-
 	}
 
-	aup->phy_addr = PHY_ADDRESS;
-
 	/* bring the device out of reset, otherwise probing the mii
 	 * will hang */
 	*aup->enable = MAC_EN_CLOCK_ENABLE;
@@ -748,15 +1541,22 @@ au1000_probe1(long ioaddr, int irq, int 
 		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
 	au_sync_delay(2);
 
-	retval = mii_probe(dev);
-	if (retval)
-		 goto out2;
+	aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
+	if (!aup->mii) {
+		printk(KERN_ERR "%s: out of memory\n", dev->name);
+		goto err_out;
+	}
+	aup->mii->mii_control_reg = 0;
+	aup->mii->mii_data_reg = 0;
+
+	if (mii_probe(dev) != 0) {
+		goto err_out;
+	}
 
-	retval = -EINVAL;
 	pDBfree = NULL;
 	/* setup the data buffer descriptors and attach a buffer to each one */
 	pDB = aup->db;
-	for (i=0; i<(NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
+	for (i = 0; i < (NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
 		pDB->pnext = pDBfree;
 		pDBfree = pDB;
 		pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i);
@@ -765,15 +1565,19 @@ au1000_probe1(long ioaddr, int irq, int 
 	}
 	aup->pDBfree = pDBfree;
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto out2;
+		if (!pDB) {
+			goto err_out;
+		}
 		aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
 		aup->rx_db_inuse[i] = pDB;
 	}
-	for (i=0; i<NUM_TX_DMA; i++) {
+	for (i = 0; i < NUM_TX_DMA; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto out2;
+		if (!pDB) {
+			goto err_out;
+		}
 		aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
 		aup->tx_dma_ring[i]->len = 0;
 		aup->tx_db_inuse[i] = pDB;
@@ -788,6 +1592,7 @@ au1000_probe1(long ioaddr, int irq, int 
 	dev->get_stats = au1000_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &au1000_ioctl;
+	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
 	dev->set_config = &au1000_set_config;
 	dev->tx_timeout = au1000_tx_timeout;
 	dev->watchdog_timeo = ETH_TX_TIMEOUT;
@@ -798,23 +1603,32 @@ au1000_probe1(long ioaddr, int irq, int 
 	 */
 	reset_mac(dev);
 
-	retval = register_netdev(dev);
-	if (retval)
-		goto out2;
-	return 0;
+	return dev;
 
-out2:
-	dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));
-out1:
+err_out:
+	/* here we should have a valid dev plus aup-> register addresses
+	 * so we can reset the mac properly.*/
+	reset_mac(dev);
+	if (aup->mii)
+		kfree(aup->mii);
+	for (i = 0; i < NUM_RX_DMA; i++) {
+		if (aup->rx_db_inuse[i])
+			ReleaseDB(aup, aup->rx_db_inuse[i]);
+	}
+	for (i = 0; i < NUM_TX_DMA; i++) {
+		if (aup->tx_db_inuse[i])
+			ReleaseDB(aup, aup->tx_db_inuse[i]);
+	}
+	dma_free_noncoherent(NULL,
+			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
+			(void *)aup->vaddr,
+			aup->dma_addr);
+	unregister_netdev(dev);
 	free_netdev(dev);
-out:
-	release_region(PHYSADDR(ioaddr), MAC_IOSIZE);
-	printk(KERN_ERR "%s: au1000_probe1 failed.  Returns %d\n",
-	       dev->name, retval);
-	return retval;
+	release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+	return NULL;
 }
 
-
 /* 
  * Initialize the interface.
  *
@@ -832,7 +1646,8 @@ static int au1000_init(struct net_device
 	u32 control;
 	u16 link, speed;
 
-	if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name);
+	if (au1000_debug > 4) 
+		printk("%s: au1000_init\n", dev->name);
 
 	spin_lock_irqsave(&aup->lock, flags);
 
@@ -852,7 +1667,7 @@ static int au1000_init(struct net_device
 	aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
 		dev->dev_addr[1]<<8 | dev->dev_addr[0];
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
 	}
 	au_sync();
@@ -865,7 +1680,13 @@ static int au1000_init(struct net_device
 	if (link && (dev->if_port == IF_PORT_100BASEFX)) {
 		control |= MAC_FULL_DUPLEX;
 	}
+
+	/* fix for startup without cable */
+	if (!link) 
+		dev->flags &= ~IFF_RUNNING;
+
 	aup->mac->control = control;
+	aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
 	au_sync();
 
 	spin_unlock_irqrestore(&aup->lock, flags);
@@ -949,6 +1770,7 @@ static int au1000_open(struct net_device
 		return retval;
 	}
 
+	init_timer(&aup->timer); /* used in ioctl() */
 	aup->timer.expires = RUN_AT((3*HZ)); 
 	aup->timer.data = (unsigned long)dev;
 	aup->timer.function = &au1000_timer; /* timer handler */
@@ -968,22 +1790,49 @@ static int au1000_close(struct net_devic
 	if (au1000_debug > 4)
 		printk("%s: close: dev=%p\n", dev->name, dev);
 
+	reset_mac(dev);
+
 	spin_lock_irqsave(&aup->lock, flags);
 	
 	/* stop the device */
-	if (netif_device_present(dev))
-		netif_stop_queue(dev);
+	netif_stop_queue(dev);
 
 	/* disable the interrupt */
 	free_irq(dev->irq, dev);
 	spin_unlock_irqrestore(&aup->lock, flags);
 
-	reset_mac(dev);
 	return 0;
 }
 
 static void __exit au1000_cleanup_module(void)
 {
+	int i, j;
+	struct net_device *dev;
+	struct au1000_private *aup;
+
+	for (i = 0; i < num_ifs; i++) {
+		dev = iflist[i].dev;
+		if (dev) {
+			aup = (struct au1000_private *) dev->priv;
+			unregister_netdev(dev);
+			if (aup->mii)
+				kfree(aup->mii);
+			for (j = 0; j < NUM_RX_DMA; j++) {
+				if (aup->rx_db_inuse[j])
+					ReleaseDB(aup, aup->rx_db_inuse[j]);
+			}
+			for (j = 0; j < NUM_TX_DMA; j++) {
+				if (aup->tx_db_inuse[j])
+					ReleaseDB(aup, aup->tx_db_inuse[j]);
+			}
+			dma_free_noncoherent(NULL,
+					MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
+					(void *)aup->vaddr,
+					aup->dma_addr);
+			free_netdev(dev);
+			release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
+		}
+	}
 }
 
 
@@ -1028,9 +1877,8 @@ static void au1000_tx_ack(struct net_dev
 	ptxd = aup->tx_dma_ring[aup->tx_tail];
 
 	while (ptxd->buff_stat & TX_T_DONE) {
- 		update_tx_stats(dev, ptxd->status, aup->tx_len[aup->tx_tail]  & 0x3ff);
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
 		ptxd->buff_stat &= ~TX_T_DONE;
- 		aup->tx_len[aup->tx_tail] = 0;
 		ptxd->len = 0;
 		au_sync();
 
@@ -1056,7 +1904,7 @@ static int au1000_tx(struct sk_buff *skb
 	db_dest_t *pDB;
 	int i;
 
-	if (au1000_debug > 4)
+	if (au1000_debug > 5)
 		printk("%s: tx: aup %x len=%d, data=%p, head %d\n", 
 				dev->name, (unsigned)aup, skb->len, 
 				skb->data, aup->tx_head);
@@ -1070,8 +1918,7 @@ static int au1000_tx(struct sk_buff *skb
 		return 1;
 	}
 	else if (buff_stat & TX_T_DONE) {
- 		update_tx_stats(dev, ptxd->status, aup->tx_len[aup->tx_head] & 0x3ff);
- 		aup->tx_len[aup->tx_head] = 0;
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
 		ptxd->len = 0;
 	}
 
@@ -1082,17 +1929,15 @@ static int au1000_tx(struct sk_buff *skb
 
 	pDB = aup->tx_db_inuse[aup->tx_head];
 	memcpy((void *)pDB->vaddr, skb->data, skb->len);
-	if (skb->len < MAC_MIN_PKT_SIZE) {
-		for (i=skb->len; i<MAC_MIN_PKT_SIZE; i++) { 
+	if (skb->len < ETH_ZLEN) {
+		for (i=skb->len; i<ETH_ZLEN; i++) { 
 			((char *)pDB->vaddr)[i] = 0;
 		}
- 		aup->tx_len[aup->tx_head] = MAC_MIN_PKT_SIZE;
-		ptxd->len = MAC_MIN_PKT_SIZE;
+		ptxd->len = ETH_ZLEN;
 	}
-	else {
- 		aup->tx_len[aup->tx_head] = skb->len;
+	else
 		ptxd->len = skb->len;
-	}
+
 	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
 	au_sync();
 	dev_kfree_skb(skb);
@@ -1137,8 +1982,9 @@ static int au1000_rx(struct net_device *
 	volatile rx_dma_t *prxd;
 	u32 buff_stat, status;
 	db_dest_t *pDB;
+	u32	frmlen;
 
-	if (au1000_debug > 4)
+	if (au1000_debug > 5)
 		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
 
 	prxd = aup->rx_dma_ring[aup->rx_head];
@@ -1150,7 +1996,9 @@ static int au1000_rx(struct net_device *
 		if (!(status & RX_ERROR))  {
 
 			/* good frame */
-			skb = dev_alloc_skb((status & RX_FRAME_LEN_MASK) + 2);
+			frmlen = (status & RX_FRAME_LEN_MASK);
+			frmlen -= 4; /* Remove FCS */
+			skb = dev_alloc_skb(frmlen + 2);
 			if (skb == NULL) {
 				printk(KERN_ERR
 				       "%s: Memory squeeze, dropping packet.\n",
@@ -1160,9 +2008,9 @@ static int au1000_rx(struct net_device *
 			}
 			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte IP header align */
-			eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, 
-					status & RX_FRAME_LEN_MASK, 0);
-			skb_put(skb, status & RX_FRAME_LEN_MASK);
+			eth_copy_and_sum(skb,
+				(unsigned char *)pDB->vaddr, frmlen, 0);
+			skb_put(skb, frmlen);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);	/* pass the packet to upper layers */
 		}
@@ -1206,17 +2054,20 @@ static int au1000_rx(struct net_device *
 /*
  * Au1000 interrupt service routine.
  */
-irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 
 	if (dev == NULL) {
 		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
-		return IRQ_NONE;
+		return IRQ_RETVAL(1);
 	}
-	au1000_tx_ack(dev);
+
+	/* Handle RX interrupts first to minimize chance of overrun */
+
 	au1000_rx(dev);
-	return IRQ_HANDLED;
+	au1000_tx_ack(dev);
+	return IRQ_RETVAL(1);
 }
 
 
@@ -1233,6 +2084,23 @@ static void au1000_tx_timeout(struct net
 	netif_wake_queue(dev);
 }
 
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+    int crc = -1;
+
+    while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ? 
+				 ethernet_polynomial : 0);
+    }
+    return crc;
+}
+
 static void set_rx_mode(struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -1256,8 +2124,8 @@ static void set_rx_mode(struct net_devic
 		mc_filter[1] = mc_filter[0] = 0;
 		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)>>26, 
-					mc_filter);
+			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, 
+					(long *)mc_filter);
 		}
 		aup->mac->multi_hash_high = mc_filter[1];
 		aup->mac->multi_hash_low = mc_filter[0];
@@ -1269,28 +2137,28 @@ static void set_rx_mode(struct net_devic
 
 static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct au1000_private *aup = (struct au1000_private *)dev->priv;
 	u16 *data = (u16 *)&rq->ifr_ifru;
 
-	/* fixme */
 	switch(cmd) { 
-	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-		data[0] = PHY_ADDRESS;
-		return 0;
-
-	case SIOCGMIIREG:	/* Read the specified MII register. */
-		//data[3] = mdio_read(ioaddr, data[0], data[1]); 
-		return 0;
-
-	case SIOCSMIIREG:	/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-
-		//mdio_write(ioaddr, data[0], data[1], data[2]);
-		return 0;
-
-	default:
-		return -EOPNOTSUPP;
+		case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+		case SIOCGMIIPHY:
+		        if (!netif_running(dev)) return -EINVAL;
+			data[0] = aup->phy_addr;
+		case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
+		case SIOCGMIIREG:
+			data[3] =  mdio_read(dev, data[0], data[1]); 
+			return 0;
+		case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
+		case SIOCSMIIREG: 
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			mdio_write(dev, data[0], data[1],data[2]);
+			return 0;
+		default:
+			return -EOPNOTSUPP;
 	}
+
 }
 
 
@@ -1352,7 +2220,6 @@ static int au1000_set_config(struct net_
 			/* set Speed to 100Mbps, Half Duplex */
 			/* disable auto negotiation and enable 100MBit Mode */
 			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			printk("read control %x\n", control);
 			control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX);
 			control |= MII_CNTL_F100;
 			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -1,10 +1,13 @@
 /*
- * Alchemy Semi Au1000 ethernet driver include file
+ *
+ * Alchemy Au1x00 ethernet driver include file
  *
  * Author: Pete Popov <ppopov@mvista.com>
  *
  * Copyright 2001 MontaVista Software Inc.
  *
+ * ########################################################################
+ *
  *  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.
@@ -17,14 +20,16 @@
  *  You 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>
 
 
-#define NUM_INTERFACES 2
 #define MAC_IOSIZE 0x10000
-#define NUM_RX_DMA 4       /* Au1000 has 4 rx hardware descriptors */
-#define NUM_TX_DMA 4       /* Au1000 has 4 tx hardware descriptors */
+#define NUM_RX_DMA 4       /* Au1x00 has 4 rx hardware descriptors */
+#define NUM_TX_DMA 4       /* Au1x00 has 4 tx hardware descriptors */
 
 #define NUM_RX_BUFFS 4
 #define NUM_TX_BUFFS 4
@@ -33,12 +38,6 @@
 #define ETH_TX_TIMEOUT HZ/4
 #define MAC_MIN_PKT_SIZE 64
 
-#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
-#endif
-
 #define MULTICAST_FILTER_LIMIT 64
 
 /* FIXME 
@@ -54,11 +53,13 @@
 #define MII_ANLPAR  0x0005
 #define MII_AEXP    0x0006
 #define MII_ANEXT   0x0007
-#define MII_LSI_CONFIG 0x0011
-#define MII_LSI_STAT   0x0012
-#define MII_AUX_CNTRL  0x0018
-#define MII_INT        0x001A
+#define MII_LSI_PHY_CONFIG 0x0011
+/* Status register */
+#define MII_LSI_PHY_STAT   0x0012
+#define MII_AMD_PHY_STAT   MII_LSI_PHY_STAT
+#define MII_INTEL_PHY_STAT 0x0011
 
+#define MII_AUX_CNTRL  0x0018
 /* mii registers specific to AMD 79C901 */
 #define	MII_STATUS_SUMMARY = 0x0018
 
@@ -121,23 +122,30 @@
 #define	MII_STSSUM_AUTO  0x0002
 #define MII_STSSUM_SPD   0x0001
 
-/* lsi status register */
-
-#define MII_LSI_STAT_FDX	0x0040
-#define MII_LSI_STAT_SPD	0x0080
+/* lsi phy status register */
+#define MII_LSI_PHY_STAT_FDX	0x0040
+#define MII_LSI_PHY_STAT_SPD	0x0080
+
+/* amd phy status register */
+#define MII_AMD_PHY_STAT_FDX	0x0800
+#define MII_AMD_PHY_STAT_SPD	0x0400
+
+/* intel phy status register */
+#define MII_INTEL_PHY_STAT_FDX	0x0200
+#define MII_INTEL_PHY_STAT_SPD	0x4000
 
 /* 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;
 	struct mii_chip_info * chip_info;
-	int phy_addr;
 	u16 status;
+	u32 *mii_control_reg;
+	u32 *mii_data_reg;
 } mii_phy_t;
 
 struct phy_ops {
@@ -197,7 +205,6 @@ struct au1000_private {
 	db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
 	volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
 	volatile tx_dma_t *tx_dma_ring[NUM_TX_DMA];
-	int tx_len[NUM_TX_DMA];
 	db_dest_t *rx_db_inuse[NUM_RX_DMA];
 	db_dest_t *tx_db_inuse[NUM_TX_DMA];
 	u32 rx_head;
@@ -205,6 +212,7 @@ struct au1000_private {
 	u32 tx_tail;
 	u32 tx_full;
 
+	int mac_id;
 	mii_phy_t *mii;
 	struct phy_ops *phy_ops;
 	
@@ -218,9 +226,10 @@ struct au1000_private {
 	u8 *hash_table;
 	u32 hash_mode;
 	u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
-	u32 phy_addr;          /* PHY address */
+	int phy_addr;          /* phy address */
 	u32 options;           /* User-settable misc. driver options. */
 	u32 drv_flags;
+	int want_autoneg;
 	struct net_device_stats stats;
 	struct timer_list timer;
 	spinlock_t lock;       /* Serialise access to device */
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -907,6 +907,7 @@ static void b44_tx_timeout(struct net_de
 static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct b44 *bp = netdev_priv(dev);
+	struct sk_buff *bounce_skb;
 	dma_addr_t mapping;
 	u32 len, entry, ctrl;
 
@@ -922,15 +923,31 @@ static int b44_start_xmit(struct sk_buff
 		return 1;
 	}
 
-	entry = bp->tx_prod;
 	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 	if(mapping+len > B44_DMA_MASK) {
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
-		pci_unmap_single(bp->pdev, mapping, len,PCI_DMA_TODEVICE);
-		memcpy(bp->tx_bufs+entry*TX_PKT_BUF_SZ,skb->data,skb->len);
-		mapping = pci_map_single(bp->pdev, bp->tx_bufs+entry*TX_PKT_BUF_SZ, len, PCI_DMA_TODEVICE);
+		pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
+
+		bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
+					     GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return NETDEV_TX_BUSY;
+
+		mapping = pci_map_single(bp->pdev, bounce_skb->data,
+					 len, PCI_DMA_TODEVICE);
+		if(mapping+len > B44_DMA_MASK) {
+			pci_unmap_single(bp->pdev, mapping,
+					 len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_any(bounce_skb);
+			return NETDEV_TX_BUSY;
+		}
+
+		memcpy(skb_put(bounce_skb, len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
 	}
 
+	entry = bp->tx_prod;
 	bp->tx_buffers[entry].skb = skb;
 	pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
 
@@ -1077,11 +1094,6 @@ static void b44_free_consistent(struct b
 				    bp->tx_ring, bp->tx_ring_dma);
 		bp->tx_ring = NULL;
 	}
-	if (bp->tx_bufs) {
-		pci_free_consistent(bp->pdev, B44_TX_RING_SIZE * TX_PKT_BUF_SZ,
-				    bp->tx_bufs, bp->tx_bufs_dma);
-		bp->tx_bufs = NULL;
-	}
 }
 
 /*
@@ -1104,12 +1116,6 @@ static int b44_alloc_consistent(struct b
 		goto out_err;
 	memset(bp->tx_buffers, 0, size);
 
-	size = B44_TX_RING_SIZE * TX_PKT_BUF_SZ;
-	bp->tx_bufs = pci_alloc_consistent(bp->pdev, size, &bp->tx_bufs_dma);
-	if (!bp->tx_bufs)
-		goto out_err;
-	memset(bp->tx_bufs, 0, size);
-
 	size = DMA_TABLE_BYTES;
 	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
 	if (!bp->rx_ring)
@@ -1903,7 +1909,7 @@ static void __devexit b44_remove_one(str
 	}
 }
 
-static int b44_suspend(struct pci_dev *pdev, u32 state)
+static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct b44 *bp = netdev_priv(dev);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -302,20 +302,6 @@
 #define B44_MII_TLEDCTRL	27	/* Traffic Meter LED */
 #define  MII_TLEDCTRL_ENABLE	0x0040
 
-/* XXX Add this to mii.h */
-#ifndef ADVERTISE_PAUSE
-#define ADVERTISE_PAUSE_CAP		0x0400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-#define ADVERTISE_PAUSE_ASYM		0x0800
-#endif
-#ifndef LPA_PAUSE
-#define LPA_PAUSE_CAP			0x0400
-#endif
-#ifndef LPA_PAUSE_ASYM
-#define LPA_PAUSE_ASYM			0x0800
-#endif
-
 struct dma_desc {
 	u32	ctrl;
 	u32	addr;
@@ -397,7 +383,6 @@ struct b44 {
 
 	struct ring_info	*rx_buffers;
 	struct ring_info	*tx_buffers;
-	unsigned char		*tx_bufs; 
 
 	u32			dma_offset;
 	u32			flags;
@@ -429,7 +414,7 @@ struct b44 {
 	struct pci_dev		*pdev;
 	struct net_device	*dev;
 
-	dma_addr_t		rx_ring_dma, tx_ring_dma,tx_bufs_dma;
+	dma_addr_t		rx_ring_dma, tx_ring_dma;
 
 	u32			rx_pending;
 	u32			tx_pending;
diff --git a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c
deleted file mode 100644
--- a/drivers/net/bagetlance.c
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*
- * bagetlance.c: Ethernet driver for VME Lance cards on Baget/MIPS
- *      This code stealed and adopted from linux/drivers/net/atarilance.c
- *      See that for author info
- *
- * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
- */
-
-/* 
- * Driver code for Baget/Lance taken from atarilance.c, which also
- * works well in case of Besta. Most significant changes made here
- * related with 16BIT-only access to A24 space.
- */
-
-static char *version = "bagetlance.c: v1.1 11/10/98\n";
-
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/baget/baget.h>
-
-#define BAGET_LANCE_IRQ  BAGET_IRQ_MASK(0xdf)
-
-/*
- *  Define following if you don't need 16BIT-only access to Lance memory
- *  (Normally BAGET needs it)
- */
-#undef NORMAL_MEM_ACCESS 
-
-/* Debug level:
- *  0 = silent, print only serious errors
- *  1 = normal, print error messages
- *  2 = debug, print debug infos
- *  3 = debug, print even more debug infos (packet data)
- */
-
-#define	LANCE_DEBUG	1  
-
-#ifdef LANCE_DEBUG
-static int lance_debug = LANCE_DEBUG;
-#else
-static int lance_debug = 1;
-#endif
-MODULE_PARM(lance_debug, "i");
-MODULE_PARM_DESC(lance_debug, "Lance debug level (0-3)");
-MODULE_LICENSE("GPL");
-
-/* Print debug messages on probing? */
-#undef LANCE_DEBUG_PROBE
-
-#define	DPRINTK(n,a)							\
-	do {										\
-		if (lance_debug >= n)					\
-			printk a;							\
-	} while( 0 )
-
-#ifdef LANCE_DEBUG_PROBE
-# define PROBE_PRINT(a)	printk a
-#else
-# define PROBE_PRINT(a)
-#endif
-
-/* These define the number of Rx and Tx buffers as log2. (Only powers
- * of two are valid)
- * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
- * is more time critical then sending and packets may have to remain in the
- * board's memory when main memory is low.
- */
-
-/* Baget Lance has 64K on-board memory, so it looks we can't increase
-   buffer quantity (40*1.5K is about 64K) */
-
-#define TX_LOG_RING_SIZE			3
-#define RX_LOG_RING_SIZE			5
-
-/* These are the derived values */
-
-#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
-#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
-#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-
-#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
-#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
-#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
-	volatile unsigned short	base;		/* Low word of base addr */
-#ifdef NORMAL_MEM_ACCESS
-       /* Following two fields are joined into one short to guarantee
-		  16BIT access to Baget lance registers */
-	volatile unsigned char	flag;
-	unsigned char			base_hi;	/* High word of base addr (unused) */
-#else
-/* Following macros are used as replecements to 8BIT fields */
-#define GET_FLAG(h)    (((h)->flag_base_hi >> 8) & 0xff)
-#define SET_FLAG(h,f)  (h)->flag_base_hi = ((h)->flag_base_hi & 0xff) | \
-		                                                (((unsigned)(f)) << 8)
-	volatile unsigned short flag_base_hi; 
-#endif
-	volatile short			buf_length;	/* This length is 2s complement! */
-	volatile short			msg_length;	/* This length is "normal". */
-};
-
-
-struct lance_tx_head {
-	volatile unsigned short	base;		/* Low word of base addr */
-#ifdef NORMAL_MEM_ACCESS 
-/* See comments above about 8BIT-access Baget A24-space problems */
-	volatile unsigned char	flag;
-	unsigned char			base_hi;	/* High word of base addr (unused) */
-#else
-	volatile unsigned short  flag_base_hi;
-#endif
-	volatile short			length;		/* Length is 2s complement! */
-	volatile short			misc;
-};
-
-struct ringdesc {
-	volatile unsigned short	adr_lo;		/* Low 16 bits of address */
-#ifdef NORMAL_MEM_ACCESS 
-/* See comments above about 8BIT-access Bage A24-space problems */
-	unsigned char	len;		/* Length bits */
-	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
-#else
-	volatile unsigned short  len_adr_hi;
-#endif
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
-	unsigned short	mode;		/* Pre-set mode */
-	unsigned char	hwaddr[6];	/* Physical ethernet address */
-	unsigned		filter[2];	/* Multicast filter (unused). */
-	/* Receive and transmit ring base, along with length bits. */
-	struct ringdesc	rx_ring;
-	struct ringdesc	tx_ring;
-};
-
-/* The whole layout of the Lance shared memory */
-struct lance_memory {
-	struct lance_init_block	init;
-	struct lance_tx_head	tx_head[TX_RING_SIZE];
-	struct lance_rx_head	rx_head[RX_RING_SIZE];
-	char					packet_area[0];	/* packet data follow after the
-											 * init block and the ring
-											 * descriptors and are located
-											 * at runtime */
-};
-
-/* RieblCard specifics:
- * The original TOS driver for these cards reserves the area from offset
- * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
- * Ethernet address there, and the magic for verifying the data's validity.
- * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
- * is reserved for the interrupt vector number.
- */
-#define	RIEBL_RSVD_START	0xee70
-#define	RIEBL_RSVD_END		0xeec0
-#define RIEBL_MAGIC			0x09051990
-#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
-#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
-#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
-
-/* This is a default address for the old RieblCards without a battery
- * that have no ethernet address at boot time. 00:00:36:04 is the
- * prefix for Riebl cards, the 00:00 at the end is arbitrary.
- */
-
-static unsigned char OldRieblDefHwaddr[6] = {
-	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
-};
-
-/* I/O registers of the Lance chip */
-
-struct lance_ioreg {
-/* base+0x0 */	volatile unsigned short	data;
-/* base+0x2 */	volatile unsigned short	addr;
-				unsigned char			_dummy1[3];
-/* base+0x7 */	volatile unsigned char	ivec;
-				unsigned char			_dummy2[5];
-/* base+0xd */	volatile unsigned char	eeprom;
-				unsigned char			_dummy3;
-/* base+0xf */	volatile unsigned char	mem;
-};
-
-/* Types of boards this driver supports */
-
-enum lance_type {
-	OLD_RIEBL,		/* old Riebl card without battery */
-	NEW_RIEBL,		/* new Riebl card with battery */
-	PAM_CARD		/* PAM card with EEPROM */
-};
-
-static char *lance_names[] = {
-	"Riebl-Card (without battery)",
-	"Riebl-Card (with battery)",
-	"PAM intern card"
-};
-
-/* The driver's private device structure */
-
-struct lance_private {
-	enum lance_type		cardtype;
-	struct lance_ioreg	*iobase;
-	struct lance_memory	*mem;
-	int					cur_rx, cur_tx;	/* The next free ring entry */
-	int					dirty_tx;		/* Ring entries to be freed. */
-						/* copy function */
-	void				*(*memcpy_f)( void *, const void *, size_t );
-	struct net_device_stats stats;
-/* These two must be longs for set_bit() */
-	long				tx_full;
-	long				lock;
-};
-
-/* I/O register access macros */
-
-#define	MEM		lp->mem
-#define	DREG	IO->data
-#define	AREG	IO->addr
-#define	REGA(a)	( AREG = (a), DREG )
-
-/* Definitions for packet buffer access: */
-#define PKT_BUF_SZ		1544
-/* Get the address of a packet buffer corresponding to a given buffer head */
-#define	PKTBUF_ADDR(head)	(((unsigned char *)(MEM)) + (head)->base)
-
-/* Possible memory/IO addresses for probing */
-
-struct lance_addr {
-	unsigned long	memaddr;
-	unsigned long	ioaddr;
-	int				slow_flag;
-} lance_addr_list[] = {
-	{ BAGET_LANCE_MEM_BASE, BAGET_LANCE_IO_BASE, 1 }	/* Baget Lance */
-};
-
-#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
-
-
-#define LANCE_HI_BASE (0xff & (BAGET_LANCE_MEM_BASE >> 16))
-
-/* Definitions for the Lance */
-
-/* tx_head flags */
-#define TMD1_ENP		0x01	/* end of packet */
-#define TMD1_STP		0x02	/* start of packet */
-#define TMD1_DEF		0x04	/* deferred */
-#define TMD1_ONE		0x08	/* one retry needed */
-#define TMD1_MORE		0x10	/* more than one retry needed */
-#define TMD1_ERR		0x40	/* error summary */
-#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
-
-#define TMD1_OWN_CHIP	TMD1_OWN
-#define TMD1_OWN_HOST	0
-
-/* tx_head misc field */
-#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
-#define TMD3_RTRY		0x0400	/* failed after 16 retries */
-#define TMD3_LCAR		0x0800	/* carrier lost */
-#define TMD3_LCOL		0x1000	/* late collision */
-#define TMD3_UFLO		0x4000	/* underflow (late memory) */
-#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
-
-/* rx_head flags */
-#define RMD1_ENP		0x01	/* end of packet */
-#define RMD1_STP		0x02	/* start of packet */
-#define RMD1_BUFF		0x04	/* buffer error */
-#define RMD1_CRC		0x08	/* CRC error */
-#define RMD1_OFLO		0x10	/* overflow */
-#define RMD1_FRAM		0x20	/* framing error */
-#define RMD1_ERR		0x40	/* error summary */
-#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
-
-#define RMD1_OWN_CHIP	RMD1_OWN
-#define RMD1_OWN_HOST	0
-
-/* register names */
-#define CSR0	0		/* mode/status */
-#define CSR1	1		/* init block addr (low) */
-#define CSR2	2		/* init block addr (high) */
-#define CSR3	3		/* misc */
-#define CSR8	8	  	/* address filter */
-#define CSR15	15		/* promiscuous mode */
-
-/* CSR0 */
-/* (R=readable, W=writeable, S=set on write, C=clear on write) */
-#define CSR0_INIT	0x0001		/* initialize (RS) */
-#define CSR0_STRT	0x0002		/* start (RS) */
-#define CSR0_STOP	0x0004		/* stop (RS) */
-#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
-#define CSR0_TXON	0x0010		/* transmitter on (R) */
-#define CSR0_RXON	0x0020		/* receiver on (R) */
-#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
-#define CSR0_INTR	0x0080		/* interrupt active (R) */
-#define CSR0_IDON	0x0100		/* initialization done (RC) */
-#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
-#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
-#define CSR0_MERR	0x0800		/* memory error (RC) */
-#define CSR0_MISS	0x1000		/* missed frame (RC) */
-#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
-#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
-#define CSR0_ERR	0x8000		/* error (RC) */
-
-/* CSR3 */
-#define CSR3_BCON	0x0001		/* byte control */
-#define CSR3_ACON	0 // fixme: 0x0002		/* ALE control */
-#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
-
-
-
-/***************************** Prototypes *****************************/
-
-static int addr_accessible( volatile void *regp, int wordflag, int
-                            writeflag );
-static int lance_probe1( struct net_device *dev, struct lance_addr *init_rec );
-static int lance_open( struct net_device *dev );
-static void lance_init_ring( struct net_device *dev );
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
-static int lance_rx( struct net_device *dev );
-static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
-static void set_multicast_list( struct net_device *dev );
-static int lance_set_mac_address( struct net_device *dev, void *addr );
-
-/************************* End of Prototypes **************************/
-
-/* Network traffic statistic (bytes) */
-
-int lance_stat = 0;
-
-static void update_lance_stat (int len) {
-		lance_stat += len;
-}
-
-/* 
-   This function is used to access Baget/Lance memory to avoid 
-   8/32BIT access to VAC A24 space 
-   ALL memcpy calls was chenged to this function to avoid dbe problems
-   Don't confuse with function name -- it stays from original code
-*/
-
-void *slow_memcpy( void *dst, const void *src, size_t len )
-
-{	
-	unsigned long to     = (unsigned long)dst;
-	unsigned long from   = (unsigned long)src;
-	unsigned long to_end = to +len;
-	
-	/* Unaligned flags */
-
-	int odd_from   = from   & 1;
-	int odd_to     = to     & 1;
-	int odd_to_end = to_end & 1;
-
-	/* Align for 16BIT-access first */
-
-	register unsigned short *from_a   = (unsigned short*) (from   & ~1);
-	register unsigned short *to_a     = (unsigned short*) (to     & ~1); 
-	register unsigned short *to_end_a = (unsigned short*) (to_end & ~1);
-
-	/* Caching values -- not in loop invariant */
-
-	register unsigned short from_v; 
-	register unsigned short to_v;
-
-	/* Invariant is: from_a and to_a are pointers before or exactly to
-	   currently copying byte */
-
-	if (odd_to) { 
-			/* First byte unaligned case */
-			from_v = *from_a;
-			to_v   = *to_a;
-
-			to_v &= ~0xff;
-			to_v |=  0xff & (from_v >> (odd_from ? 0 : 8));
-			*to_a++ = to_v;
-
-			if (odd_from) from_a++;
-	}
-    if (odd_from == odd_to) {
-			/* Same parity */
-			while (to_a + 7 < to_end_a) {
-					unsigned long dummy1, dummy2;
-					unsigned long reg1, reg2, reg3, reg4;
-
-					__asm__ __volatile__(
-					".set\tnoreorder\n\t"
-					".set\tnoat\n\t"
-					"lh\t%2,0(%1)\n\t"
-					"nop\n\t"
-					 "lh\t%3,2(%1)\n\t"
-					"sh\t%2,0(%0)\n\t"
-					   "lh\t%4,4(%1)\n\t"
-					 "sh\t%3,2(%0)\n\t"
-					    "lh\t%5,6(%1)\n\t"
-					   "sh\t%4,4(%0)\n\t"
-					"lh\t%2,8(%1)\n\t"
-					    "sh\t%5,6(%0)\n\t"
-					 "lh\t%3,10(%1)\n\t"
-					"sh\t%2,8(%0)\n\t"
-					  "lh\t%4,12(%1)\n\t"
-					 "sh\t%3,10(%0)\n\t"
-					    "lh\t%5,14(%1)\n\t"
-					  "sh\t%4,12(%0)\n\t"
-					 "nop\n\t"
-					    "sh\t%5,14(%0)\n\t"
-					".set\tat\n\t"
-					".set\treorder"
-					:"=r" (dummy1), "=r" (dummy2),
-					"=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
-					:"0" (to_a), "1" (from_a)
-					:"memory");
-
-					to_a   += 8;
-					from_a += 8;
-
-			}
-			while (to_a < to_end_a) {
-					*to_a++ = *from_a++;
-			}
-	} else {
-			/* Different parity */
-			from_v = *from_a;
-			while (to_a < to_end_a) {
-					unsigned short from_v_next;
-					from_v_next = *++from_a;
-					*to_a++ = ((from_v & 0xff)<<8) | ((from_v_next>>8) & 0xff);
-					from_v = from_v_next; 
-			}
-
-	}
-	if (odd_to_end) {
-			/* Last byte unaligned case */
-			to_v = *to_a;
-			from_v = *from_a;
-
-			to_v &= ~0xff00;
-			if (odd_from == odd_to) {
-					to_v |= from_v & 0xff00;
-			} else {
-					to_v |= (from_v<<8) & 0xff00;
-			}
-
-			*to_a = to_v;
-	}
-
-	update_lance_stat( len );
-
-	return( dst );
-}
-
-
-struct net_device * __init bagetlance_probe(int unit)
-{
-	struct net_device *dev;
-	int i;
-	static int found;
-	int err = -ENODEV;
-
-	if (found)
-		/* Assume there's only one board possible... That seems true, since
-		 * the Riebl/PAM board's address cannot be changed. */
-		return ERR_PTR(-ENODEV);
-
-	dev = alloc_etherdev(sizeof(struct lance_private));
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	SET_MODULE_OWNER(dev);
-
-	for( i = 0; i < N_LANCE_ADDR; ++i ) {
-		if (lance_probe1( dev, &lance_addr_list[i] )) {
-			found = 1;
-			break;
-		}
-	}
-	if (!found)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	free_irq(dev->irq, dev);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-/* Derived from hwreg_present() in vme/config.c: */
-
-static int __init addr_accessible( volatile void *regp, 
-				   int wordflag, 
-				   int writeflag )
-{	
-		/* We have a fine function to do it */
-		extern int try_read(unsigned long, int);
-		return try_read((unsigned long)regp, sizeof(short)) != -1;   
-}
-
-
-
-/* Original atari driver uses it */
-#define IRQ_TYPE_PRIO SA_INTERRUPT
-#define IRQ_SOURCE_TO_VECTOR(x) (x)
-
-static int __init lance_probe1( struct net_device *dev,
-				struct lance_addr *init_rec )
-
-{	volatile unsigned short *memaddr =
-		(volatile unsigned short *)init_rec->memaddr;
-	volatile unsigned short *ioaddr =
-		(volatile unsigned short *)init_rec->ioaddr;
-	struct lance_private	*lp;
-	struct lance_ioreg		*IO;
-	int 					i;
-	static int 				did_version;
-	unsigned short			save1, save2;
-
-	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
-				  (long)memaddr, (long)ioaddr ));
-
-	/* Test whether memory readable and writable */
-	PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
-	if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
-
-	if ((unsigned long)memaddr >= KSEG2) {
-			/* FIXME: do we need to undo that on cleanup paths? */
-			extern int kseg2_alloc_io (unsigned long addr, unsigned long size);
-			if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) {
-					printk("bagetlance: unable map lance memory\n");
-					goto probe_fail;
-			}
-	}
-
-	/* Written values should come back... */
-	PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
-	save1 = *memaddr;
-	*memaddr = 0x0001;
-	if (*memaddr != 0x0001) goto probe_fail;
-	PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
-	*memaddr = 0x0000;
-	if (*memaddr != 0x0000) goto probe_fail;
-	*memaddr = save1;
-
-	/* First port should be readable and writable */
-	PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
-	if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
-
-	/* and written values should be readable */
-	PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
-	save2 = ioaddr[1];
-	ioaddr[1] = 0x0001;
-	if (ioaddr[1] != 0x0001) goto probe_fail;
-
-	/* The CSR0_INIT bit should not be readable */
-	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
-	save1 = ioaddr[0];
-	ioaddr[1] = CSR0;
-	ioaddr[0] = CSR0_INIT | CSR0_STOP;
-	if (ioaddr[0] != CSR0_STOP) {
-		ioaddr[0] = save1;
-		ioaddr[1] = save2;
-		goto probe_fail;
-	}
-	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
-	ioaddr[0] = CSR0_STOP;
-	if (ioaddr[0] != CSR0_STOP) {
-		ioaddr[0] = save1;
-		ioaddr[1] = save2;
-		goto probe_fail;
-	}
-
-	/* Now ok... */
-	PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
-	goto probe_ok;
-
-  probe_fail:
-	return( 0 );
-
-  probe_ok:
-	lp = netdev_priv(dev);
-	MEM = (struct lance_memory *)memaddr;
-	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
-	dev->base_addr = (unsigned long)ioaddr; /* informational only */
-	lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
-
-	REGA( CSR0 ) = CSR0_STOP;
-
-	/* Now test for type: If the eeprom I/O port is readable, it is a
-	 * PAM card */
-	if (addr_accessible( &(IO->eeprom), 0, 0 )) {
-		/* Switch back to Ram */
-		i = IO->mem;
-		lp->cardtype = PAM_CARD;
-	}
-#ifdef NORMAL_MEM_ACCESS
-	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
-#else
-	else if (({
-			unsigned short *a = (unsigned short*)RIEBL_MAGIC_ADDR;
-		    (((int)a[0]) << 16) + ((int)a[1]) == RIEBL_MAGIC;
-	})) {
-#endif
-		lp->cardtype = NEW_RIEBL;
-	}
-	else
-		lp->cardtype = OLD_RIEBL;
-
-	if (lp->cardtype == PAM_CARD ||
-		memaddr == (unsigned short *)0xffe00000) {
-		/* PAMs card and Riebl on ST use level 5 autovector */
-		if (request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO,
-		            "PAM/Riebl-ST Ethernet", dev))
-			goto probe_fail;
-		dev->irq = (unsigned short)BAGET_LANCE_IRQ;
-	}
-	else {
-		/* For VME-RieblCards, request a free VME int;
-		 * (This must be unsigned long, since dev->irq is short and the
-		 * IRQ_MACHSPEC bit would be cut off...)
-		 */
-		unsigned long irq = BAGET_LANCE_IRQ; 
-		if (!irq) {
-			printk( "Lance: request for VME interrupt failed\n" );
-			goto probe_fail;
-		}
-		if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
-		            "Riebl-VME Ethernet", dev))
-			goto probe_fail;
-		dev->irq = irq;
-	}
-
-	printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
-		   dev->name, lance_names[lp->cardtype],
-		   (unsigned long)ioaddr,
-		   (unsigned long)memaddr,
-		   dev->irq,
-		   init_rec->slow_flag ? " (slow memcpy)" : "" );
-
-	/* Get the ethernet address */
-	switch( lp->cardtype ) {
-	  case OLD_RIEBL:
-		/* No ethernet address! (Set some default address) */
-		slow_memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
-		break;
-	  case NEW_RIEBL:
-		lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
-		break;
-	  case PAM_CARD:
-		i = IO->eeprom;
-		for( i = 0; i < 6; ++i )
-			dev->dev_addr[i] =
-				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
-				((((unsigned short *)MEM)[i*2+1] & 0x0f));
-		i = IO->mem;
-		break;
-	}
-	for( i = 0; i < 6; ++i )
-		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
-	if (lp->cardtype == OLD_RIEBL) {
-		printk( "%s: Warning: This is a default ethernet address!\n",
-				dev->name );
-		printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
-	}
-
-	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
-
-	{
-			unsigned char hwaddr[6];
-			for( i = 0; i < 6; i++ ) 
-					hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
-			slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
-	}
-
-	MEM->init.filter[0] = 0x00000000;
-	MEM->init.filter[1] = 0x00000000;
-	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
-
-#ifdef NORMAL_MEM_ACCESS
-	MEM->init.rx_ring.adr_hi = LANCE_HI_BASE; 
-	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
-#else
-	MEM->init.rx_ring.len_adr_hi = 
-			((unsigned)RX_RING_LEN_BITS << 8) | LANCE_HI_BASE;
-#endif
-
-
-	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
-
-#ifdef NORMAL_MEM_ACCESS
-	MEM->init.tx_ring.adr_hi = LANCE_HI_BASE; 
-	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
-#else
-	MEM->init.tx_ring.len_adr_hi = 
-			((unsigned)TX_RING_LEN_BITS<<8) | LANCE_HI_BASE;
-#endif
-
-	if (lp->cardtype == PAM_CARD)
-		IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
-	else
-		*RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
-
-	if (did_version++ == 0)
-		DPRINTK( 1, ( version ));
-
-	/* The LANCE-specific entries in the device structure. */
-	dev->open = &lance_open;
-	dev->hard_start_xmit = &lance_start_xmit;
-	dev->stop = &lance_close;
-	dev->get_stats = &lance_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
-	dev->set_mac_address = &lance_set_mac_address;
-	dev->start = 0;
-
-	memset( &lp->stats, 0, sizeof(lp->stats) );
-
-	return( 1 );
-}
-
-
-static int lance_open( struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	struct lance_ioreg	 *IO = lp->iobase;
-	int i;
-
-	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
-
-	lance_init_ring(dev);
-	/* Re-initialize the LANCE, and start it when done. */
-
-	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
-	REGA( CSR2 ) = 0;
-	REGA( CSR1 ) = 0;
-	REGA( CSR0 ) = CSR0_INIT;
-	/* From now on, AREG is kept to point to CSR0 */
-
-	i = 1000000;
-	while (--i > 0)
-		if (DREG & CSR0_IDON)
-			break;
-	if (i < 0 || (DREG & CSR0_ERR)) {
-		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
-					  dev->name, i, DREG ));
-		DREG = CSR0_STOP;
-		return( -EIO );
-	}
-	DREG = CSR0_IDON;
-	DREG = CSR0_STRT;
-	DREG = CSR0_INEA;
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
-	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
-	return( 0 );
-}
-
-
-/* Initialize the LANCE Rx and Tx rings. */
-
-static void lance_init_ring( struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	int i;
-	unsigned offset;
-
-	lp->lock = 0;
-	lp->tx_full = 0;
-	lp->cur_rx = lp->cur_tx = 0;
-	lp->dirty_tx = 0;
-
-	offset = offsetof( struct lance_memory, packet_area );
-
-/* If the packet buffer at offset 'o' would conflict with the reserved area
- * of RieblCards, advance it */
-#define	CHECK_OFFSET(o)														 \
-	do {																	 \
-		if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) {		 \
-			if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
-										 : (o) < RIEBL_RSVD_END)			 \
-				(o) = RIEBL_RSVD_END;										 \
-		}																	 \
-	} while(0)
-
-	for( i = 0; i < TX_RING_SIZE; i++ ) {
-		CHECK_OFFSET(offset);
-		MEM->tx_head[i].base = offset;
-#ifdef NORMAL_MEM_ACCESS
-		MEM->tx_head[i].flag = TMD1_OWN_HOST;
- 		MEM->tx_head[i].base_hi = LANCE_HI_BASE;
-#else
-		MEM->tx_head[i].flag_base_hi = 
-				(TMD1_OWN_HOST<<8) | LANCE_HI_BASE;
-#endif
-		MEM->tx_head[i].length = 0;
-		MEM->tx_head[i].misc = 0;
-		offset += PKT_BUF_SZ;
-	}
-
-	for( i = 0; i < RX_RING_SIZE; i++ ) {
-		CHECK_OFFSET(offset);
-		MEM->rx_head[i].base = offset;
-#ifdef NORMAL_MEM_ACCESS
-		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
-		MEM->rx_head[i].base_hi = LANCE_HI_BASE; 
-#else
-		MEM->rx_head[i].flag_base_hi = 
-				(TMD1_OWN_CHIP<<8) | LANCE_HI_BASE;
-#endif
-		MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
-		MEM->rx_head[i].msg_length = 0;
-		offset += PKT_BUF_SZ;
-	}
-}
-
-
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	struct lance_ioreg	 *IO = lp->iobase;
-	int entry, len;
-	struct lance_tx_head *head;
-	unsigned long flags;
-
-	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
-	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
-	if (lp->cardtype == PAM_CARD && (len & 1))
-		++len;
-
-	if (len > skb->len) {
-		skb = skb_padto(skb, len);
-		if (skb == NULL)
-			return 0;
-	}	
-
-	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 20)
-			return( 1 );
-		AREG = CSR0;
-		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
-					  dev->name, DREG ));
-		DREG = CSR0_STOP;
-		/*
-		 * Always set BSWP after a STOP as STOP puts it back into
-		 * little endian mode.
-		 */
-		REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
-		lp->stats.tx_errors++;
-#ifndef final_version
-		{	int i;
-			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
-						  lp->dirty_tx, lp->cur_tx,
-						  lp->tx_full ? " (full)" : "",
-						  lp->cur_rx ));
-			for( i = 0 ; i < RX_RING_SIZE; i++ )
-				DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
-							  i, MEM->rx_head[i].base,
-							  -MEM->rx_head[i].buf_length,
-							  MEM->rx_head[i].msg_length ));
-			for( i = 0 ; i < TX_RING_SIZE; i++ )
-				DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
-							  i, MEM->tx_head[i].base,
-							  -MEM->tx_head[i].length,
-							  MEM->tx_head[i].misc ));
-		}
-#endif
-		lance_init_ring(dev);
-		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
-
-		dev->tbusy = 0;
-		dev->trans_start = jiffies;
-
-		return( 0 );
-	}
-
-	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
-				  dev->name, DREG ));
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
-		DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
-		return 1;
-	}
-
-	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
-		DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
-		/* don't clear dev->tbusy flag. */
-		return 1;
-	}
-
-	/* Fill in a Tx ring entry */
-	if (lance_debug >= 3) {
-		u_char *p;
-		int i;
-		printk( "%s: TX pkt type 0x%04x from ", dev->name,
-				((u_short *)skb->data)[6]);
-		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" to ");
-		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" data at 0x%08x len %d\n", (int)skb->data,
-			   (int)skb->len );
-	}
-
-	/* We're not prepared for the int until the last flags are set/reset. And
-	 * the int may happen already after setting the OWN_CHIP... */
-	save_flags(flags);
-	cli();
-
-	/* Mask to ring buffer boundary. */
-	entry = lp->cur_tx & TX_RING_MOD_MASK;
-	head  = &(MEM->tx_head[entry]);
-
-	/* Caution: the write order is important here, set the "ownership" bits
-	 * last.
-	 */
-
-	head->length = -len;
-	head->misc = 0;
-	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
-#ifdef NORMAL_MEM_ACCESS
-	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-#else
-    SET_FLAG(head,(TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP));
-#endif
-	lp->stats.tx_bytes += skb->len;
-	dev_kfree_skb( skb );
-	lp->cur_tx++;
-	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
-		lp->cur_tx -= TX_RING_SIZE;
-		lp->dirty_tx -= TX_RING_SIZE;
-	}
-
-	/* Trigger an immediate send poll. */
-	DREG = CSR0_INEA | CSR0_TDMD;
-	dev->trans_start = jiffies;
-
-	lp->lock = 0;
-#ifdef NORMAL_MEM_ACCESS
-	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
-#else
-	if ((GET_FLAG(&MEM->tx_head[(entry+1) & TX_RING_MOD_MASK]) & TMD1_OWN) ==
-#endif
-		TMD1_OWN_HOST)
-		dev->tbusy = 0;
-	else
-		lp->tx_full = 1;
-	restore_flags(flags);
-
-	return 0;
-}
-
-/* The LANCE interrupt handler. */
-
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
-{
-	struct net_device *dev = dev_id;
-	struct lance_private *lp;
-	struct lance_ioreg	 *IO;
-	int csr0, boguscnt = 10;
-	int handled = 0;
-
-	if (dev == NULL) {
-		DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
-		return IRQ_NONE;
-	}
-
-	lp = netdev_priv(dev);
-	IO = lp->iobase;
-	AREG = CSR0;
-
-	if (dev->interrupt) {
-			DPRINTK( 1, ( "Re-entering CAUSE=%08x STATUS=%08x\n",  
-						  read_32bit_cp0_register(CP0_CAUSE),  
-						  read_32bit_cp0_register(CP0_STATUS) ));
-			panic("lance: interrupt handler reentered !");
-	}
-
-	dev->interrupt = 1;
-
-	while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
-		   --boguscnt >= 0) {
-		handled = 1;
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
-									CSR0_TDMD | CSR0_INEA);
-
-		DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
-					  dev->name, csr0, DREG ));
-
-		if (csr0 & CSR0_RINT)			/* Rx interrupt */
-			lance_rx( dev );
-
-		if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
-			int dirty_tx = lp->dirty_tx;
-
-			while( dirty_tx < lp->cur_tx) {
-				int entry = dirty_tx & TX_RING_MOD_MASK;
-#ifdef NORMAL_MEM_ACCESS
-				int status = MEM->tx_head[entry].flag;
-#else
-				int status = GET_FLAG(&MEM->tx_head[entry]);
-#endif
-				if (status & TMD1_OWN_CHIP)
-					break;			/* It still hasn't been Txed */
-
-#ifdef NORMAL_MEM_ACCESS
-				MEM->tx_head[entry].flag = 0;
-#else
-				SET_FLAG(&MEM->tx_head[entry],0);
-#endif
-
-				if (status & TMD1_ERR) {
-					/* There was an major error, log it. */
-					int err_status = MEM->tx_head[entry].misc;
-					lp->stats.tx_errors++;
-					if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-					if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-					if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
-					if (err_status & TMD3_UFLO) {
-						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						lp->stats.tx_fifo_errors++;
-						/* Remove this verbosity later! */
-						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
-									  dev->name, csr0 ));
-						/* Restart the chip. */
-						DREG = CSR0_STRT;
-					}
-				} else {
-					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
-						lp->stats.collisions++;
-					lp->stats.tx_packets++;
-				}
-				dirty_tx++;
-			}
-
-#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",
-							  dirty_tx, lp->cur_tx, lp->tx_full ));
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-
-			if (lp->tx_full && dev->tbusy
-				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
-				/* The ring is no longer full, clear tbusy. */
-				lp->tx_full = 0;
-				dev->tbusy = 0;
-				mark_bh( NET_BH );
-			}
-
-			lp->dirty_tx = dirty_tx;
-		}
-
-		/* Log misc errors. */
-		if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
-		if (csr0 & CSR0_MERR) {
-			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
-						  "status %04x.\n", dev->name, csr0 ));
-			/* Restart the chip. */
-			DREG = CSR0_STRT;
-		}
-	}
-
-    /* Clear any other interrupt, and set interrupt enable. */
-	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
-		   CSR0_IDON | CSR0_INEA;
-
-	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
-				  dev->name, DREG ));
-	dev->interrupt = 0;
-	return IRQ_RETVAL(handled);
-}
-
-
-static int lance_rx( struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	int entry = lp->cur_rx & RX_RING_MOD_MASK;
-	int i;
-
-#ifdef NORMAL_MEM_ACCESS
-	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
-				  MEM->rx_head[entry].flag ));
-#else
-	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
-				  GET_FLAG(&MEM->rx_head[entry]) ));
-#endif
-
-	/* If we own the next entry, it's a new packet. Send it up. */
-#ifdef NORMAL_MEM_ACCESS
-	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
-#else
-	while( (GET_FLAG(&MEM->rx_head[entry]) & RMD1_OWN) == RMD1_OWN_HOST ) {
-#endif
-		struct lance_rx_head *head = &(MEM->rx_head[entry]);
-#ifdef NORMAL_MEM_ACCESS
-		int status = head->flag;
-#else
-		int status = GET_FLAG(head);
-#endif
-
-		if (status != (RMD1_ENP|RMD1_STP)) {		/* There was an error. */
-			/* There is a tricky error noted by John Murphy,
-			   <murf@perftech.com> to Russ Nelson: Even with full-sized
-			   buffers it's possible for a jabber packet to use two
-			   buffers, with only the last correctly noting the error. */
-			if (status & RMD1_ENP)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
-			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
-			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
-			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
-#ifdef NORMAL_MEM_ACCESS
-			head->flag &= (RMD1_ENP|RMD1_STP);
-#else
-			SET_FLAG(head,GET_FLAG(head) & (RMD1_ENP|RMD1_STP));
-#endif
-		} else {
-			/* Malloc up new buffer, compatible with net-3. */
-			short pkt_len = head->msg_length & 0xfff;
-			struct sk_buff *skb;
-
-			if (pkt_len < 60) {
-				printk( "%s: Runt packet!\n", dev->name );
-				lp->stats.rx_errors++;
-			}
-			else {
-				skb = dev_alloc_skb( pkt_len+2 );
-				if (skb == NULL) {
-					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
-								  dev->name ));
-                          for( i = 0; i < RX_RING_SIZE; i++ )
-#ifdef NORMAL_MEM_ACCESS
-                        if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
-#else
-						if (GET_FLAG(&MEM->rx_head[(entry+i) & \
-												  RX_RING_MOD_MASK]) &
-#endif
-							RMD1_OWN_CHIP)
-							break;
-
-					if (i > RX_RING_SIZE - 2) {
-						lp->stats.rx_dropped++;
-#ifdef NORMAL_MEM_ACCESS
-                        head->flag |= RMD1_OWN_CHIP;
-#else
-                        SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
-#endif
-						lp->cur_rx++;
-					}
-					break;
-				}
-
-				if (lance_debug >= 3) {
-					u_char *data = PKTBUF_ADDR(head), *p;
-					printk( "%s: RX pkt type 0x%04x from ", dev->name,
-							((u_short *)data)[6]);
-					for( p = &data[6], i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
-					printk(" to ");
-					for( p = data, i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
-					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
-						   "len %d\n",
-						   data[15], data[16], data[17], data[18],
-						   data[19], data[20], data[21], data[22],
-						   pkt_len );
-				}
-
-				skb->dev = dev;
-				skb_reserve( skb, 2 );	/* 16 byte align */
-				skb_put( skb, pkt_len );	/* Make room */
-				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
-				skb->protocol = eth_type_trans( skb, dev );
-				netif_rx( skb );
-				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
-			}
-		}
-
-#ifdef NORMAL_MEM_ACCESS
-		head->flag |= RMD1_OWN_CHIP;
-#else
-		SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
-#endif
-		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
-	}
-	lp->cur_rx &= RX_RING_MOD_MASK;
-
-	/* From lance.c (Donald Becker): */
-	/* We should check that at least two ring entries are free.	 If not,
-	   we should free one and mark stats->rx_dropped++. */
-
-	return 0;
-}
-
-
-static int lance_close( struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	struct lance_ioreg	 *IO = lp->iobase;
-
-	dev->start = 0;
-	dev->tbusy = 1;
-
-	AREG = CSR0;
-
-	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
-				  dev->name, DREG ));
-
-	/* We stop the LANCE here -- it occasionally polls
-	   memory if we don't. */
-	DREG = CSR0_STOP;
-
-	return 0;
-}
-
-
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-
-{	
-	struct lance_private *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1		Promiscuous mode, receive all packets
-   num_addrs == 0		Normal mode, clear multicast list
-   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
-						best-effort filtering.
- */
-
-static void set_multicast_list( struct net_device *dev )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	struct lance_ioreg	 *IO = lp->iobase;
-
-	if (!dev->start)
-		/* Only possible if board is already started */
-		return;
-
-	/* We take the simple way out and always enable promiscuous mode. */
-	DREG = CSR0_STOP; /* Temporarily stop the lance. */
-
-	if (dev->flags & IFF_PROMISC) {
-		/* Log any net taps. */
-		DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
-		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
-	} else {
-		short multicast_table[4];
-		int num_addrs = dev->mc_count;
-		int i;
-		/* We don't use the multicast table, but rely on upper-layer
-		 * filtering. */
-		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
-				sizeof(multicast_table) );
-		for( i = 0; i < 4; i++ )
-			REGA( CSR8+i ) = multicast_table[i];
-		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
-	}
-
-	/*
-	 * Always set BSWP after a STOP as STOP puts it back into
-	 * little endian mode.
-	 */
-	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
-
-	/* Resume normal operation and reset AREG to CSR0 */
-	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
-}
-
-
-/* This is needed for old RieblCards and possible for new RieblCards */
-
-static int lance_set_mac_address( struct net_device *dev, void *addr )
-
-{	struct lance_private *lp = netdev_priv(dev);
-	struct sockaddr *saddr = addr;
-	int i;
-
-	if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
-		return( -EOPNOTSUPP );
-
-	if (dev->start) {
-		/* Only possible while card isn't started */
-		DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
-					  dev->name ));
-		return( -EIO );
-	}
-
-	slow_memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
-
-	{
-			unsigned char hwaddr[6];
-			for( i = 0; i < 6; i++ ) 
-					hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
-			slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
-	}
-
-	lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
-	/* set also the magic for future sessions */
-#ifdef NORMAL_MEM_ACCESS
-	*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
-#else
-	{
-			unsigned long magic = RIEBL_MAGIC;
-			slow_memcpy(RIEBL_MAGIC_ADDR, &magic, sizeof(*RIEBL_MAGIC_ADDR));
-	}
-#endif
-	return( 0 );
-}
-
-
-#ifdef MODULE
-static struct net_device *bagetlance_dev;
-
-int init_module(void)
-{
-	bagetlance_dev = bagetlance_probe(-1);
-	if (IS_ERR(bagetlance_dev))
-		return PTR_ERR(bagetlance_dev);
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_netdev(bagetlance_dev);
-	free_irq(bagetlance_dev->irq, bagetlance_dev);
-	free_netdev(bagetlance_dev);
-}
-
-#endif /* MODULE */
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -455,7 +455,7 @@ static void bmac_init_chip(struct net_de
 }
 
 #ifdef CONFIG_PM
-static int bmac_suspend(struct macio_dev *mdev, u32 state)
+static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
 {
 	struct net_device* dev = macio_get_drvdata(mdev);	
 	struct bmac_data *bp = netdev_priv(dev);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
new file mode 100644
--- /dev/null
+++ b/drivers/net/bnx2.c
@@ -0,0 +1,5530 @@
+/* bnx2.c: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005 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.
+ *
+ * Written by: Michael Chan  (mchan@broadcom.com)
+ */
+
+#include "bnx2.h"
+#include "bnx2_fw.h"
+
+#define DRV_MODULE_NAME		"bnx2"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"1.2.19"
+#define DRV_MODULE_RELDATE	"May 23, 2005"
+
+#define RUN_AT(x) (jiffies + (x))
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (5*HZ)
+
+static char version[] __devinitdata =
+	"Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706 Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int disable_msi = 0;
+
+module_param(disable_msi, int, 0);
+MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+
+typedef enum {
+	BCM5706 = 0,
+	NC370T,
+	NC370I,
+	BCM5706S,
+	NC370F,
+} board_t;
+
+/* indexed by board_t, above */
+static struct {
+	char *name;
+} board_info[] __devinitdata = {
+	{ "Broadcom NetXtreme II BCM5706 1000Base-T" },
+	{ "HP NC370T Multifunction Gigabit Server Adapter" },
+	{ "HP NC370i Multifunction Gigabit Server Adapter" },
+	{ "Broadcom NetXtreme II BCM5706 1000Base-SX" },
+	{ "HP NC370F Multifunction Gigabit Server Adapter" },
+	{ 0 },
+	};
+
+static struct pci_device_id bnx2_pci_tbl[] = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+	  PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+	  PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
+	  PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
+	{ 0, }
+};
+
+static struct flash_spec flash_table[] =
+{
+	/* Slow EEPROM */
+	{0x00000000, 0x40030380, 0x009f0081, 0xa184a053, 0xaf000400,
+	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
+	 "EEPROM - slow"},
+	/* Fast EEPROM */
+	{0x02000000, 0x62008380, 0x009f0081, 0xa184a053, 0xaf000400,
+	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
+	 "EEPROM - fast"},
+	/* ATMEL AT45DB011B (buffered flash) */
+	{0x02000003, 0x6e008173, 0x00570081, 0x68848353, 0xaf000400,
+	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
+	 "Buffered flash"},
+	/* Saifun SA25F005 (non-buffered flash) */
+       	/* strap, cfg1, & write1 need updates */
+	{0x01000003, 0x5f008081, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
+	 "Non-buffered flash (64kB)"},
+	/* Saifun SA25F010 (non-buffered flash) */
+	/* strap, cfg1, & write1 need updates */
+	{0x00000001, 0x47008081, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
+	 "Non-buffered flash (128kB)"},
+	/* Saifun SA25F020 (non-buffered flash) */
+	/* strap, cfg1, & write1 need updates */
+	{0x00000003, 0x4f008081, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
+	 "Non-buffered flash (256kB)"},
+};
+
+MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
+
+static u32
+bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
+{
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
+	return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
+}
+
+static void
+bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
+{
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
+}
+
+static void
+bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
+{
+	offset += cid_addr;
+	REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
+	REG_WR(bp, BNX2_CTX_DATA, val);
+}
+
+static int
+bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
+{
+	u32 val1;
+	int i, ret;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	val1 = (bp->phy_addr << 21) | (reg << 16) |
+		BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
+		BNX2_EMAC_MDIO_COMM_START_BUSY;
+	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+
+			val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+			val1 &= BNX2_EMAC_MDIO_COMM_DATA;
+
+			break;
+		}
+	}
+
+	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
+		*val = 0x0;
+		ret = -EBUSY;
+	}
+	else {
+		*val = val1;
+		ret = 0;
+	}
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	return ret;
+}
+
+static int
+bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
+{
+	u32 val1;
+	int i, ret;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	val1 = (bp->phy_addr << 21) | (reg << 16) | val |
+		BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
+		BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
+	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
+    
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+			break;
+		}
+	}
+
+	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
+        	ret = -EBUSY;
+	else
+		ret = 0;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	return ret;
+}
+
+static void
+bnx2_disable_int(struct bnx2 *bp)
+{
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+	REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
+}
+
+static void
+bnx2_enable_int(struct bnx2 *bp)
+{
+	u32 val;
+
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
+
+	val = REG_RD(bp, BNX2_HC_COMMAND);
+	REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW);
+}
+
+static void
+bnx2_disable_int_sync(struct bnx2 *bp)
+{
+	atomic_inc(&bp->intr_sem);
+	bnx2_disable_int(bp);
+	synchronize_irq(bp->pdev->irq);
+}
+
+static void
+bnx2_netif_stop(struct bnx2 *bp)
+{
+	bnx2_disable_int_sync(bp);
+	if (netif_running(bp->dev)) {
+		netif_poll_disable(bp->dev);
+		netif_tx_disable(bp->dev);
+		bp->dev->trans_start = jiffies;	/* prevent tx timeout */
+	}
+}
+
+static void
+bnx2_netif_start(struct bnx2 *bp)
+{
+	if (atomic_dec_and_test(&bp->intr_sem)) {
+		if (netif_running(bp->dev)) {
+			netif_wake_queue(bp->dev);
+			netif_poll_enable(bp->dev);
+			bnx2_enable_int(bp);
+		}
+	}
+}
+
+static void
+bnx2_free_mem(struct bnx2 *bp)
+{
+	if (bp->stats_blk) {
+		pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
+				    bp->stats_blk, bp->stats_blk_mapping);
+		bp->stats_blk = NULL;
+	}
+	if (bp->status_blk) {
+		pci_free_consistent(bp->pdev, sizeof(struct status_block),
+				    bp->status_blk, bp->status_blk_mapping);
+		bp->status_blk = NULL;
+	}
+	if (bp->tx_desc_ring) {
+		pci_free_consistent(bp->pdev,
+				    sizeof(struct tx_bd) * TX_DESC_CNT,
+				    bp->tx_desc_ring, bp->tx_desc_mapping);
+		bp->tx_desc_ring = NULL;
+	}
+	if (bp->tx_buf_ring) {
+		kfree(bp->tx_buf_ring);
+		bp->tx_buf_ring = NULL;
+	}
+	if (bp->rx_desc_ring) {
+		pci_free_consistent(bp->pdev,
+				    sizeof(struct rx_bd) * RX_DESC_CNT,
+				    bp->rx_desc_ring, bp->rx_desc_mapping);
+		bp->rx_desc_ring = NULL;
+	}
+	if (bp->rx_buf_ring) {
+		kfree(bp->rx_buf_ring);
+		bp->rx_buf_ring = NULL;
+	}
+}
+
+static int
+bnx2_alloc_mem(struct bnx2 *bp)
+{
+	bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
+				     GFP_KERNEL);
+	if (bp->tx_buf_ring == NULL)
+		return -ENOMEM;
+
+	memset(bp->tx_buf_ring, 0, sizeof(struct sw_bd) * TX_DESC_CNT);
+	bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
+					        sizeof(struct tx_bd) *
+						TX_DESC_CNT,
+						&bp->tx_desc_mapping);
+	if (bp->tx_desc_ring == NULL)
+		goto alloc_mem_err;
+
+	bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT,
+				     GFP_KERNEL);
+	if (bp->rx_buf_ring == NULL)
+		goto alloc_mem_err;
+
+	memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT);
+	bp->rx_desc_ring = pci_alloc_consistent(bp->pdev,
+					        sizeof(struct rx_bd) *
+						RX_DESC_CNT,
+						&bp->rx_desc_mapping);
+	if (bp->rx_desc_ring == NULL)
+		goto alloc_mem_err;
+
+	bp->status_blk = pci_alloc_consistent(bp->pdev,
+					      sizeof(struct status_block),
+					      &bp->status_blk_mapping);
+	if (bp->status_blk == NULL)
+		goto alloc_mem_err;
+
+	memset(bp->status_blk, 0, sizeof(struct status_block));
+
+	bp->stats_blk = pci_alloc_consistent(bp->pdev,
+					     sizeof(struct statistics_block),
+					     &bp->stats_blk_mapping);
+	if (bp->stats_blk == NULL)
+		goto alloc_mem_err;
+
+	memset(bp->stats_blk, 0, sizeof(struct statistics_block));
+
+	return 0;
+
+alloc_mem_err:
+	bnx2_free_mem(bp);
+	return -ENOMEM;
+}
+
+static void
+bnx2_report_link(struct bnx2 *bp)
+{
+	if (bp->link_up) {
+		netif_carrier_on(bp->dev);
+		printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
+
+		printk("%d Mbps ", bp->line_speed);
+
+		if (bp->duplex == DUPLEX_FULL)
+			printk("full duplex");
+		else
+			printk("half duplex");
+
+		if (bp->flow_ctrl) {
+			if (bp->flow_ctrl & FLOW_CTRL_RX) {
+				printk(", receive ");
+				if (bp->flow_ctrl & FLOW_CTRL_TX)
+					printk("& transmit ");
+			}
+			else {
+				printk(", transmit ");
+			}
+			printk("flow control ON");
+		}
+		printk("\n");
+	}
+	else {
+		netif_carrier_off(bp->dev);
+		printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
+	}
+}
+
+static void
+bnx2_resolve_flow_ctrl(struct bnx2 *bp)
+{
+	u32 local_adv, remote_adv;
+
+	bp->flow_ctrl = 0;
+	if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) != 
+		(AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
+
+		if (bp->duplex == DUPLEX_FULL) {
+			bp->flow_ctrl = bp->req_flow_ctrl;
+		}
+		return;
+	}
+
+	if (bp->duplex != DUPLEX_FULL) {
+		return;
+	}
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		u32 new_local_adv = 0;
+		u32 new_remote_adv = 0;
+
+		if (local_adv & ADVERTISE_1000XPAUSE)
+			new_local_adv |= ADVERTISE_PAUSE_CAP;
+		if (local_adv & ADVERTISE_1000XPSE_ASYM)
+			new_local_adv |= ADVERTISE_PAUSE_ASYM;
+		if (remote_adv & ADVERTISE_1000XPAUSE)
+			new_remote_adv |= ADVERTISE_PAUSE_CAP;
+		if (remote_adv & ADVERTISE_1000XPSE_ASYM)
+			new_remote_adv |= ADVERTISE_PAUSE_ASYM;
+
+		local_adv = new_local_adv;
+		remote_adv = new_remote_adv;
+	}
+
+	/* See Table 28B-3 of 802.3ab-1999 spec. */
+	if (local_adv & ADVERTISE_PAUSE_CAP) {
+		if(local_adv & ADVERTISE_PAUSE_ASYM) {
+	                if (remote_adv & ADVERTISE_PAUSE_CAP) {
+				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			}
+			else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
+				bp->flow_ctrl = FLOW_CTRL_RX;
+			}
+		}
+		else {
+			if (remote_adv & ADVERTISE_PAUSE_CAP) {
+				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			}
+		}
+	}
+	else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+		if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
+			(remote_adv & ADVERTISE_PAUSE_ASYM)) {
+
+			bp->flow_ctrl = FLOW_CTRL_TX;
+		}
+	}
+}
+
+static int
+bnx2_serdes_linkup(struct bnx2 *bp)
+{
+	u32 bmcr, local_adv, remote_adv, common;
+
+	bp->link_up = 1;
+	bp->line_speed = SPEED_1000;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	if (bmcr & BMCR_FULLDPLX) {
+		bp->duplex = DUPLEX_FULL;
+	}
+	else {
+		bp->duplex = DUPLEX_HALF;
+	}
+
+	if (!(bmcr & BMCR_ANENABLE)) {
+		return 0;
+	}
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+	common = local_adv & remote_adv;
+	if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
+
+		if (common & ADVERTISE_1000XFULL) {
+			bp->duplex = DUPLEX_FULL;
+		}
+		else {
+			bp->duplex = DUPLEX_HALF;
+		}
+	}
+
+	return 0;
+}
+
+static int
+bnx2_copper_linkup(struct bnx2 *bp)
+{
+	u32 bmcr;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	if (bmcr & BMCR_ANENABLE) {
+		u32 local_adv, remote_adv, common;
+
+		bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
+		bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
+
+		common = local_adv & (remote_adv >> 2);
+		if (common & ADVERTISE_1000FULL) {
+			bp->line_speed = SPEED_1000;
+			bp->duplex = DUPLEX_FULL;
+		}
+		else if (common & ADVERTISE_1000HALF) {
+			bp->line_speed = SPEED_1000;
+			bp->duplex = DUPLEX_HALF;
+		}
+		else {
+			bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+			bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+			common = local_adv & remote_adv;
+			if (common & ADVERTISE_100FULL) {
+				bp->line_speed = SPEED_100;
+				bp->duplex = DUPLEX_FULL;
+			}
+			else if (common & ADVERTISE_100HALF) {
+				bp->line_speed = SPEED_100;
+				bp->duplex = DUPLEX_HALF;
+			}
+			else if (common & ADVERTISE_10FULL) {
+				bp->line_speed = SPEED_10;
+				bp->duplex = DUPLEX_FULL;
+			}
+			else if (common & ADVERTISE_10HALF) {
+				bp->line_speed = SPEED_10;
+				bp->duplex = DUPLEX_HALF;
+			}
+			else {
+				bp->line_speed = 0;
+				bp->link_up = 0;
+			}
+		}
+	}
+	else {
+		if (bmcr & BMCR_SPEED100) {
+			bp->line_speed = SPEED_100;
+		}
+		else {
+			bp->line_speed = SPEED_10;
+		}
+		if (bmcr & BMCR_FULLDPLX) {
+			bp->duplex = DUPLEX_FULL;
+		}
+		else {
+			bp->duplex = DUPLEX_HALF;
+		}
+	}
+
+	return 0;
+}
+
+static int
+bnx2_set_mac_link(struct bnx2 *bp)
+{
+	u32 val;
+
+	REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
+	if (bp->link_up && (bp->line_speed == SPEED_1000) &&
+		(bp->duplex == DUPLEX_HALF)) {
+		REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
+	}
+
+	/* Configure the EMAC mode register. */
+	val = REG_RD(bp, BNX2_EMAC_MODE);
+
+	val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
+		BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK);
+
+	if (bp->link_up) {
+		if (bp->line_speed != SPEED_1000)
+			val |= BNX2_EMAC_MODE_PORT_MII;
+		else
+			val |= BNX2_EMAC_MODE_PORT_GMII;
+	}
+	else {
+		val |= BNX2_EMAC_MODE_PORT_GMII;
+	}
+
+	/* Set the MAC to operate in the appropriate duplex mode. */
+	if (bp->duplex == DUPLEX_HALF)
+		val |= BNX2_EMAC_MODE_HALF_DUPLEX;
+	REG_WR(bp, BNX2_EMAC_MODE, val);
+
+	/* Enable/disable rx PAUSE. */
+	bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
+
+	if (bp->flow_ctrl & FLOW_CTRL_RX)
+		bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
+	REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
+
+	/* Enable/disable tx PAUSE. */
+	val = REG_RD(bp, BNX2_EMAC_TX_MODE);
+	val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
+
+	if (bp->flow_ctrl & FLOW_CTRL_TX)
+		val |= BNX2_EMAC_TX_MODE_FLOW_EN;
+	REG_WR(bp, BNX2_EMAC_TX_MODE, val);
+
+	/* Acknowledge the interrupt. */
+	REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
+
+	return 0;
+}
+
+static int
+bnx2_set_link(struct bnx2 *bp)
+{
+	u32 bmsr;
+	u8 link_up;
+
+	if (bp->loopback == MAC_LOOPBACK) {
+		bp->link_up = 1;
+		return 0;
+	}
+
+	link_up = bp->link_up;
+
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
+		u32 val;
+
+		val = REG_RD(bp, BNX2_EMAC_STATUS);
+		if (val & BNX2_EMAC_STATUS_LINK)
+			bmsr |= BMSR_LSTATUS;
+		else
+			bmsr &= ~BMSR_LSTATUS;
+	}
+
+	if (bmsr & BMSR_LSTATUS) {
+		bp->link_up = 1;
+
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			bnx2_serdes_linkup(bp);
+		}
+		else {
+			bnx2_copper_linkup(bp);
+		}
+		bnx2_resolve_flow_ctrl(bp);
+	}
+	else {
+		if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+			(bp->autoneg & AUTONEG_SPEED)) {
+
+			u32 bmcr;
+
+			bnx2_read_phy(bp, MII_BMCR, &bmcr);
+			if (!(bmcr & BMCR_ANENABLE)) {
+				bnx2_write_phy(bp, MII_BMCR, bmcr |
+					BMCR_ANENABLE);
+			}
+		}
+		bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+		bp->link_up = 0;
+	}
+
+	if (bp->link_up != link_up) {
+		bnx2_report_link(bp);
+	}
+
+	bnx2_set_mac_link(bp);
+
+	return 0;
+}
+
+static int
+bnx2_reset_phy(struct bnx2 *bp)
+{
+	int i;
+	u32 reg;
+
+        bnx2_write_phy(bp, MII_BMCR, BMCR_RESET);
+
+#define PHY_RESET_MAX_WAIT 100
+	for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
+		udelay(10);
+
+		bnx2_read_phy(bp, MII_BMCR, &reg);
+		if (!(reg & BMCR_RESET)) {
+			udelay(20);
+			break;
+		}
+	}
+	if (i == PHY_RESET_MAX_WAIT) {
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static u32
+bnx2_phy_get_pause_adv(struct bnx2 *bp)
+{
+	u32 adv = 0;
+
+	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
+		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {
+
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPAUSE;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_CAP;
+		}
+	}
+	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPSE_ASYM;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_ASYM;
+		}
+	}
+	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+		}
+	}
+	return adv;
+}
+
+static int
+bnx2_setup_serdes_phy(struct bnx2 *bp)
+{
+	u32 adv, bmcr;
+	u32 new_adv = 0;
+
+	if (!(bp->autoneg & AUTONEG_SPEED)) {
+		u32 new_bmcr;
+
+		bnx2_read_phy(bp, MII_BMCR, &bmcr);
+		new_bmcr = bmcr & ~BMCR_ANENABLE;
+		new_bmcr |= BMCR_SPEED1000;
+		if (bp->req_duplex == DUPLEX_FULL) {
+			new_bmcr |= BMCR_FULLDPLX;
+		}
+		else {
+			new_bmcr &= ~BMCR_FULLDPLX;
+		}
+		if (new_bmcr != bmcr) {
+			/* Force a link down visible on the other side */
+			if (bp->link_up) {
+				bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+				adv &= ~(ADVERTISE_1000XFULL |
+					ADVERTISE_1000XHALF);
+				bnx2_write_phy(bp, MII_ADVERTISE, adv);
+				bnx2_write_phy(bp, MII_BMCR, bmcr |
+					BMCR_ANRESTART | BMCR_ANENABLE);
+
+				bp->link_up = 0;
+				netif_carrier_off(bp->dev);
+			}
+			bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+		}
+		return 0;
+	}
+
+	if (bp->advertising & ADVERTISED_1000baseT_Full)
+		new_adv |= ADVERTISE_1000XFULL;
+
+	new_adv |= bnx2_phy_get_pause_adv(bp);
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+
+	bp->serdes_an_pending = 0;
+	if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
+		/* Force a link down visible on the other side */
+		if (bp->link_up) {
+			int i;
+
+			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			for (i = 0; i < 110; i++) {
+				udelay(100);
+			}
+		}
+
+		bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
+		bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
+			BMCR_ANENABLE);
+		bp->serdes_an_pending = SERDES_AN_TIMEOUT / bp->timer_interval;
+	}
+
+	return 0;
+}
+
+#define ETHTOOL_ALL_FIBRE_SPEED						\
+	(ADVERTISED_1000baseT_Full)
+
+#define ETHTOOL_ALL_COPPER_SPEED					\
+	(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |		\
+	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |		\
+	ADVERTISED_1000baseT_Full)
+
+#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+	ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
+	
+#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
+
+static int
+bnx2_setup_copper_phy(struct bnx2 *bp)
+{
+	u32 bmcr;
+	u32 new_bmcr;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+
+	if (bp->autoneg & AUTONEG_SPEED) {
+		u32 adv_reg, adv1000_reg;
+		u32 new_adv_reg = 0;
+		u32 new_adv1000_reg = 0;
+
+		bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg);
+		adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
+			ADVERTISE_PAUSE_ASYM);
+
+		bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
+		adv1000_reg &= PHY_ALL_1000_SPEED;
+
+		if (bp->advertising & ADVERTISED_10baseT_Half)
+			new_adv_reg |= ADVERTISE_10HALF;
+		if (bp->advertising & ADVERTISED_10baseT_Full)
+			new_adv_reg |= ADVERTISE_10FULL;
+		if (bp->advertising & ADVERTISED_100baseT_Half)
+			new_adv_reg |= ADVERTISE_100HALF;
+		if (bp->advertising & ADVERTISED_100baseT_Full)
+			new_adv_reg |= ADVERTISE_100FULL;
+		if (bp->advertising & ADVERTISED_1000baseT_Full)
+			new_adv1000_reg |= ADVERTISE_1000FULL;
+		
+		new_adv_reg |= ADVERTISE_CSMA;
+
+		new_adv_reg |= bnx2_phy_get_pause_adv(bp);
+
+		if ((adv1000_reg != new_adv1000_reg) ||
+			(adv_reg != new_adv_reg) ||
+			((bmcr & BMCR_ANENABLE) == 0)) {
+
+			bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg);
+			bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
+			bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART |
+				BMCR_ANENABLE);
+		}
+		else if (bp->link_up) {
+			/* Flow ctrl may have changed from auto to forced */
+			/* or vice-versa. */
+
+			bnx2_resolve_flow_ctrl(bp);
+			bnx2_set_mac_link(bp);
+		}
+		return 0;
+	}
+
+	new_bmcr = 0;
+	if (bp->req_line_speed == SPEED_100) {
+		new_bmcr |= BMCR_SPEED100;
+	}
+	if (bp->req_duplex == DUPLEX_FULL) {
+		new_bmcr |= BMCR_FULLDPLX;
+	}
+	if (new_bmcr != bmcr) {
+		u32 bmsr;
+		int i = 0;
+
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		
+		if (bmsr & BMSR_LSTATUS) {
+			/* Force link down */
+			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			do {
+				udelay(100);
+				bnx2_read_phy(bp, MII_BMSR, &bmsr);
+				bnx2_read_phy(bp, MII_BMSR, &bmsr);
+				i++;
+			} while ((bmsr & BMSR_LSTATUS) && (i < 620));
+		}
+
+		bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+
+		/* Normally, the new speed is setup after the link has
+		 * gone down and up again. In some cases, link will not go
+		 * down so we need to set up the new speed here.
+		 */
+		if (bmsr & BMSR_LSTATUS) {
+			bp->line_speed = bp->req_line_speed;
+			bp->duplex = bp->req_duplex;
+			bnx2_resolve_flow_ctrl(bp);
+			bnx2_set_mac_link(bp);
+		}
+	}
+	return 0;
+}
+
+static int
+bnx2_setup_phy(struct bnx2 *bp)
+{
+	if (bp->loopback == MAC_LOOPBACK)
+		return 0;
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		return (bnx2_setup_serdes_phy(bp));
+	}
+	else {
+		return (bnx2_setup_copper_phy(bp));
+	}
+}
+
+static int
+bnx2_init_serdes_phy(struct bnx2 *bp)
+{
+	bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+        	REG_WR(bp, BNX2_MISC_UNUSED0, 0x300);
+	}
+
+	if (bp->dev->mtu > 1500) {
+		u32 val;
+
+		/* Set extended packet length bit */
+		bnx2_write_phy(bp, 0x18, 0x7);
+		bnx2_read_phy(bp, 0x18, &val);
+		bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
+
+		bnx2_write_phy(bp, 0x1c, 0x6c00);
+		bnx2_read_phy(bp, 0x1c, &val);
+		bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
+	}
+	else {
+		u32 val;
+
+		bnx2_write_phy(bp, 0x18, 0x7);
+		bnx2_read_phy(bp, 0x18, &val);
+		bnx2_write_phy(bp, 0x18, val & ~0x4007);
+
+		bnx2_write_phy(bp, 0x1c, 0x6c00);
+		bnx2_read_phy(bp, 0x1c, &val);
+		bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
+	}
+
+	return 0;
+}
+
+static int
+bnx2_init_copper_phy(struct bnx2 *bp)
+{
+	bp->phy_flags |= PHY_CRC_FIX_FLAG;
+
+	if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
+		bnx2_write_phy(bp, 0x18, 0x0c00);
+		bnx2_write_phy(bp, 0x17, 0x000a);
+		bnx2_write_phy(bp, 0x15, 0x310b);
+		bnx2_write_phy(bp, 0x17, 0x201f);
+		bnx2_write_phy(bp, 0x15, 0x9506);
+		bnx2_write_phy(bp, 0x17, 0x401f);
+		bnx2_write_phy(bp, 0x15, 0x14e2);
+		bnx2_write_phy(bp, 0x18, 0x0400);
+	}
+
+	if (bp->dev->mtu > 1500) {
+		u32 val;
+
+		/* Set extended packet length bit */
+		bnx2_write_phy(bp, 0x18, 0x7);
+		bnx2_read_phy(bp, 0x18, &val);
+		bnx2_write_phy(bp, 0x18, val | 0x4000);
+
+		bnx2_read_phy(bp, 0x10, &val);
+		bnx2_write_phy(bp, 0x10, val | 0x1);
+	}
+	else {
+		u32 val;
+
+		bnx2_write_phy(bp, 0x18, 0x7);
+		bnx2_read_phy(bp, 0x18, &val);
+		bnx2_write_phy(bp, 0x18, val & ~0x4007);
+
+		bnx2_read_phy(bp, 0x10, &val);
+		bnx2_write_phy(bp, 0x10, val & ~0x1);
+	}
+
+	return 0;
+}
+
+
+static int
+bnx2_init_phy(struct bnx2 *bp)
+{
+	u32 val;
+	int rc = 0;
+
+	bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
+	bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
+
+        REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+
+	bnx2_reset_phy(bp);
+
+	bnx2_read_phy(bp, MII_PHYSID1, &val);
+	bp->phy_id = val << 16;
+	bnx2_read_phy(bp, MII_PHYSID2, &val);
+	bp->phy_id |= val & 0xffff;
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		rc = bnx2_init_serdes_phy(bp);
+	}
+	else {
+		rc = bnx2_init_copper_phy(bp);
+	}
+
+	bnx2_setup_phy(bp);
+
+	return rc;
+}
+
+static int
+bnx2_set_mac_loopback(struct bnx2 *bp)
+{
+	u32 mac_mode;
+
+	mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
+	mac_mode &= ~BNX2_EMAC_MODE_PORT;
+	mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
+	REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
+	bp->link_up = 1;
+	return 0;
+}
+
+static int
+bnx2_fw_sync(struct bnx2 *bp, u32 msg_data)
+{
+	int i;
+	u32 val;
+
+	if (bp->fw_timed_out)
+		return -EBUSY;
+
+	bp->fw_wr_seq++;
+	msg_data |= bp->fw_wr_seq;
+
+	REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data);
+
+	/* wait for an acknowledgement. */
+	for (i = 0; i < (FW_ACK_TIME_OUT_MS * 1000)/5; i++) {
+		udelay(5);
+
+		val = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_FW_MB);
+
+		if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
+			break;
+	}
+
+	/* If we timed out, inform the firmware that this is the case. */
+	if (((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) &&
+		((msg_data & BNX2_DRV_MSG_DATA) != BNX2_DRV_MSG_DATA_WAIT0)) {
+
+		msg_data &= ~BNX2_DRV_MSG_CODE;
+		msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
+
+		REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data);
+
+		bp->fw_timed_out = 1;
+
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void
+bnx2_init_context(struct bnx2 *bp)
+{
+	u32 vcid;
+
+	vcid = 96;
+	while (vcid) {
+		u32 vcid_addr, pcid_addr, offset;
+
+		vcid--;
+
+		if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+			u32 new_vcid;
+
+			vcid_addr = GET_PCID_ADDR(vcid);
+			if (vcid & 0x8) {
+				new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
+			}
+			else {
+				new_vcid = vcid;
+			}
+			pcid_addr = GET_PCID_ADDR(new_vcid);
+		}
+		else {
+	    		vcid_addr = GET_CID_ADDR(vcid);
+			pcid_addr = vcid_addr;
+		}
+
+		REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
+		REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+
+		/* Zero out the context. */
+		for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
+			CTX_WR(bp, 0x00, offset, 0);
+		}
+
+		REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
+		REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+	}
+}
+
+static int
+bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+{
+	u16 *good_mbuf;
+	u32 good_mbuf_cnt;
+	u32 val;
+
+	good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
+	if (good_mbuf == NULL) {
+		printk(KERN_ERR PFX "Failed to allocate memory in "
+				    "bnx2_alloc_bad_rbuf\n");
+		return -ENOMEM;
+	}
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
+		BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
+
+	good_mbuf_cnt = 0;
+
+	/* Allocate a bunch of mbufs and save the good ones in an array. */
+	val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+	while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
+		REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
+
+		val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
+
+		val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
+
+		/* The addresses with Bit 9 set are bad memory blocks. */
+		if (!(val & (1 << 9))) {
+			good_mbuf[good_mbuf_cnt] = (u16) val;
+			good_mbuf_cnt++;
+		}
+
+		val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+	}
+
+	/* Free the good ones back to the mbuf pool thus discarding
+	 * all the bad ones. */
+	while (good_mbuf_cnt) {
+		good_mbuf_cnt--;
+
+		val = good_mbuf[good_mbuf_cnt];
+		val = (val << 9) | val | 1;
+
+		REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
+	}
+	kfree(good_mbuf);
+	return 0;
+}
+
+static void
+bnx2_set_mac_addr(struct bnx2 *bp) 
+{
+	u32 val;
+	u8 *mac_addr = bp->dev->dev_addr;
+
+	val = (mac_addr[0] << 8) | mac_addr[1];
+
+	REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
+
+	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | 
+		(mac_addr[4] << 8) | mac_addr[5];
+
+	REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
+}
+
+static inline int
+bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
+{
+	struct sk_buff *skb;
+	struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
+	dma_addr_t mapping;
+	struct rx_bd *rxbd = &bp->rx_desc_ring[index];
+	unsigned long align;
+
+	skb = dev_alloc_skb(bp->rx_buf_size);
+	if (skb == NULL) {
+		return -ENOMEM;
+	}
+
+	if (unlikely((align = (unsigned long) skb->data & 0x7))) {
+		skb_reserve(skb, 8 - align);
+	}
+
+	skb->dev = bp->dev;
+	mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
+		PCI_DMA_FROMDEVICE);
+
+	rx_buf->skb = skb;
+	pci_unmap_addr_set(rx_buf, mapping, mapping);
+
+	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
+	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
+
+	bp->rx_prod_bseq += bp->rx_buf_use_size;
+
+	return 0;
+}
+
+static void
+bnx2_phy_int(struct bnx2 *bp)
+{
+	u32 new_link_state, old_link_state;
+
+	new_link_state = bp->status_blk->status_attn_bits &
+		STATUS_ATTN_BITS_LINK_STATE;
+	old_link_state = bp->status_blk->status_attn_bits_ack &
+		STATUS_ATTN_BITS_LINK_STATE;
+	if (new_link_state != old_link_state) {
+		if (new_link_state) {
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
+				STATUS_ATTN_BITS_LINK_STATE);
+		}
+		else {
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
+				STATUS_ATTN_BITS_LINK_STATE);
+		}
+		bnx2_set_link(bp);
+	}
+}
+
+static void
+bnx2_tx_int(struct bnx2 *bp)
+{
+	u16 hw_cons, sw_cons, sw_ring_cons;
+	int tx_free_bd = 0;
+
+	hw_cons = bp->status_blk->status_tx_quick_consumer_index0;
+	if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
+		hw_cons++;
+	}
+	sw_cons = bp->tx_cons;
+
+	while (sw_cons != hw_cons) {
+		struct sw_bd *tx_buf;
+		struct sk_buff *skb;
+		int i, last;
+
+		sw_ring_cons = TX_RING_IDX(sw_cons);
+
+		tx_buf = &bp->tx_buf_ring[sw_ring_cons];
+		skb = tx_buf->skb;
+#ifdef BCM_TSO 
+		/* partial BD completions possible with TSO packets */
+		if (skb_shinfo(skb)->tso_size) {
+			u16 last_idx, last_ring_idx;
+
+			last_idx = sw_cons +
+				skb_shinfo(skb)->nr_frags + 1;
+			last_ring_idx = sw_ring_cons +
+				skb_shinfo(skb)->nr_frags + 1;
+			if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
+				last_idx++;
+			}
+			if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
+				break;
+			}
+		}
+#endif
+		pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
+			skb_headlen(skb), PCI_DMA_TODEVICE);
+
+		tx_buf->skb = NULL;
+		last = skb_shinfo(skb)->nr_frags;
+
+		for (i = 0; i < last; i++) {
+			sw_cons = NEXT_TX_BD(sw_cons);
+
+			pci_unmap_page(bp->pdev,
+				pci_unmap_addr(
+					&bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
+				       	mapping),
+				skb_shinfo(skb)->frags[i].size,
+				PCI_DMA_TODEVICE);
+		}
+
+		sw_cons = NEXT_TX_BD(sw_cons);
+
+		tx_free_bd += last + 1;
+
+		dev_kfree_skb_irq(skb);
+
+		hw_cons = bp->status_blk->status_tx_quick_consumer_index0;
+		if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
+			hw_cons++;
+		}
+	}
+
+	atomic_add(tx_free_bd, &bp->tx_avail_bd);
+
+	if (unlikely(netif_queue_stopped(bp->dev))) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&bp->tx_lock, flags);
+		if ((netif_queue_stopped(bp->dev)) &&
+			(atomic_read(&bp->tx_avail_bd) > MAX_SKB_FRAGS)) {
+
+			netif_wake_queue(bp->dev);
+		}
+		spin_unlock_irqrestore(&bp->tx_lock, flags);
+	}
+
+	bp->tx_cons = sw_cons;
+
+}
+
+static inline void
+bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
+	u16 cons, u16 prod)
+{
+	struct sw_bd *cons_rx_buf = &bp->rx_buf_ring[cons];
+	struct sw_bd *prod_rx_buf = &bp->rx_buf_ring[prod];
+	struct rx_bd *cons_bd = &bp->rx_desc_ring[cons];
+	struct rx_bd *prod_bd = &bp->rx_desc_ring[prod];
+
+	pci_dma_sync_single_for_device(bp->pdev,
+		pci_unmap_addr(cons_rx_buf, mapping),
+		bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+
+	prod_rx_buf->skb = cons_rx_buf->skb;
+	pci_unmap_addr_set(prod_rx_buf, mapping,
+			pci_unmap_addr(cons_rx_buf, mapping));
+
+	memcpy(prod_bd, cons_bd, 8);
+
+	bp->rx_prod_bseq += bp->rx_buf_use_size;
+
+}
+
+static int
+bnx2_rx_int(struct bnx2 *bp, int budget)
+{
+	u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
+	struct l2_fhdr *rx_hdr;
+	int rx_pkt = 0;
+
+	hw_cons = bp->status_blk->status_rx_quick_consumer_index0;
+	if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
+		hw_cons++;
+	}
+	sw_cons = bp->rx_cons;
+	sw_prod = bp->rx_prod;
+
+	/* Memory barrier necessary as speculative reads of the rx
+	 * buffer can be ahead of the index in the status block
+	 */
+	rmb();
+	while (sw_cons != hw_cons) {
+		unsigned int len;
+		u16 status;
+		struct sw_bd *rx_buf;
+		struct sk_buff *skb;
+
+		sw_ring_cons = RX_RING_IDX(sw_cons);
+		sw_ring_prod = RX_RING_IDX(sw_prod);
+
+		rx_buf = &bp->rx_buf_ring[sw_ring_cons];
+		skb = rx_buf->skb;
+		pci_dma_sync_single_for_cpu(bp->pdev,
+			pci_unmap_addr(rx_buf, mapping),
+			bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+
+		rx_hdr = (struct l2_fhdr *) skb->data;
+		len = rx_hdr->l2_fhdr_pkt_len - 4;
+
+		if (rx_hdr->l2_fhdr_errors &
+			(L2_FHDR_ERRORS_BAD_CRC |
+			L2_FHDR_ERRORS_PHY_DECODE |
+			L2_FHDR_ERRORS_ALIGNMENT |
+			L2_FHDR_ERRORS_TOO_SHORT |
+			L2_FHDR_ERRORS_GIANT_FRAME)) {
+
+			goto reuse_rx;
+		}
+
+		/* Since we don't have a jumbo ring, copy small packets
+		 * if mtu > 1500
+		 */
+		if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
+			struct sk_buff *new_skb;
+
+			new_skb = dev_alloc_skb(len + 2);
+			if (new_skb == NULL)
+				goto reuse_rx;
+
+			/* aligned copy */
+			memcpy(new_skb->data,
+				skb->data + bp->rx_offset - 2,
+				len + 2);
+
+			skb_reserve(new_skb, 2);
+			skb_put(new_skb, len);
+			new_skb->dev = bp->dev;
+
+			bnx2_reuse_rx_skb(bp, skb,
+				sw_ring_cons, sw_ring_prod);
+
+			skb = new_skb;
+		}
+		else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
+			pci_unmap_single(bp->pdev,
+				pci_unmap_addr(rx_buf, mapping),
+				bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+
+			skb_reserve(skb, bp->rx_offset);
+			skb_put(skb, len);
+		}
+		else {
+reuse_rx:
+			bnx2_reuse_rx_skb(bp, skb,
+				sw_ring_cons, sw_ring_prod);
+			goto next_rx;
+		}
+
+		skb->protocol = eth_type_trans(skb, bp->dev);
+
+		if ((len > (bp->dev->mtu + ETH_HLEN)) &&
+			(htons(skb->protocol) != 0x8100)) {
+
+			dev_kfree_skb_irq(skb);
+			goto next_rx;
+
+		}
+
+		status = rx_hdr->l2_fhdr_status;
+		skb->ip_summed = CHECKSUM_NONE;
+		if (bp->rx_csum &&
+			(status & (L2_FHDR_STATUS_TCP_SEGMENT |
+			L2_FHDR_STATUS_UDP_DATAGRAM))) {
+
+			u16 cksum = rx_hdr->l2_fhdr_tcp_udp_xsum;
+
+			if (cksum == 0xffff)
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+
+#ifdef BCM_VLAN
+		if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
+			vlan_hwaccel_receive_skb(skb, bp->vlgrp,
+				rx_hdr->l2_fhdr_vlan_tag);
+		}
+		else
+#endif
+			netif_receive_skb(skb);
+
+		bp->dev->last_rx = jiffies;
+		rx_pkt++;
+
+next_rx:
+		rx_buf->skb = NULL;
+
+		sw_cons = NEXT_RX_BD(sw_cons);
+		sw_prod = NEXT_RX_BD(sw_prod);
+
+		if ((rx_pkt == budget))
+			break;
+	}
+	bp->rx_cons = sw_cons;
+	bp->rx_prod = sw_prod;
+
+	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
+
+	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+
+	mmiowb();
+
+	return rx_pkt;
+
+}
+
+/* MSI ISR - The only difference between this and the INTx ISR
+ * is that the MSI interrupt is always serviced.
+ */
+static irqreturn_t
+bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2 *bp = dev->priv;
+
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
+		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+
+	/* Return here if interrupt is disabled. */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		return IRQ_RETVAL(1);
+	}
+
+	if (netif_rx_schedule_prep(dev)) {
+		__netif_rx_schedule(dev);
+	}
+
+	return IRQ_RETVAL(1);
+}
+
+static irqreturn_t
+bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2 *bp = dev->priv;
+
+	/* When using INTx, it is possible for the interrupt to arrive
+	 * at the CPU before the status block posted prior to the
+	 * interrupt. Reading a register will flush the status block.
+	 * When using MSI, the MSI message will always complete after
+	 * the status block write.
+	 */
+	if ((bp->status_blk->status_idx == bp->last_status_idx) ||
+	    (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
+	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
+		return IRQ_RETVAL(0);
+
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
+		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+
+	/* Return here if interrupt is shared and is disabled. */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		return IRQ_RETVAL(1);
+	}
+
+	if (netif_rx_schedule_prep(dev)) {
+		__netif_rx_schedule(dev);
+	}
+
+	return IRQ_RETVAL(1);
+}
+
+static int
+bnx2_poll(struct net_device *dev, int *budget)
+{
+	struct bnx2 *bp = dev->priv;
+	int rx_done = 1;
+
+	bp->last_status_idx = bp->status_blk->status_idx;
+
+	rmb();
+	if ((bp->status_blk->status_attn_bits &
+		STATUS_ATTN_BITS_LINK_STATE) !=
+		(bp->status_blk->status_attn_bits_ack &
+		STATUS_ATTN_BITS_LINK_STATE)) {
+
+		unsigned long flags;
+
+		spin_lock_irqsave(&bp->phy_lock, flags);
+		bnx2_phy_int(bp);
+		spin_unlock_irqrestore(&bp->phy_lock, flags);
+	}
+
+	if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) {
+		bnx2_tx_int(bp);
+	}
+
+	if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) {
+		int orig_budget = *budget;
+		int work_done;
+
+		if (orig_budget > dev->quota)
+			orig_budget = dev->quota;
+		
+		work_done = bnx2_rx_int(bp, orig_budget);
+		*budget -= work_done;
+		dev->quota -= work_done;
+		
+		if (work_done >= orig_budget) {
+			rx_done = 0;
+		}
+	}
+	
+	if (rx_done) {
+		netif_rx_complete(dev);
+		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+			BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+			bp->last_status_idx);
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
+ * from set_multicast.
+ */
+static void
+bnx2_set_rx_mode(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+	u32 rx_mode, sort_mode;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->phy_lock, flags);
+
+	rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
+				  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
+	sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
+#ifdef BCM_VLAN
+	if (!bp->vlgrp) {
+		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
+	}
+#else
+	rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
+#endif
+	if (dev->flags & IFF_PROMISC) {
+		/* Promiscuous mode. */
+		rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
+		sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN;
+	}
+	else if (dev->flags & IFF_ALLMULTI) {
+		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
+			REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
+			       0xffffffff);
+        	}
+		sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
+	}
+	else {
+		/* Accept one or more multicast(s). */
+		struct dev_mc_list *mclist;
+		u32 mc_filter[NUM_MC_HASH_REGISTERS];
+		u32 regidx;
+		u32 bit;
+		u32 crc;
+
+		memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
+
+		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);
+			bit = crc & 0xff;
+			regidx = (bit & 0xe0) >> 5;
+			bit &= 0x1f;
+			mc_filter[regidx] |= (1 << bit);
+		}
+
+		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
+			REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
+			       mc_filter[i]);
+		}
+
+		sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
+	}
+
+	if (rx_mode != bp->rx_mode) {
+		bp->rx_mode = rx_mode;
+		REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
+	}
+
+	REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
+	REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
+	REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
+
+	spin_unlock_irqrestore(&bp->phy_lock, flags);
+}
+
+static void
+load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
+	u32 rv2p_proc)
+{
+	int i;
+	u32 val;
+
+
+	for (i = 0; i < rv2p_code_len; i += 8) {
+		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code);
+		rv2p_code++;
+		REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code);
+		rv2p_code++;
+
+		if (rv2p_proc == RV2P_PROC1) {
+			val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
+			REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
+		}
+		else {
+			val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
+			REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
+		}
+	}
+
+	/* Reset the processor, un-stall is done later. */
+	if (rv2p_proc == RV2P_PROC1) {
+		REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
+	}
+	else {
+		REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
+	}
+}
+
+static void
+load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+{
+	u32 offset;
+	u32 val;
+
+	/* Halt the CPU. */
+	val = REG_RD_IND(bp, cpu_reg->mode);
+	val |= cpu_reg->mode_value_halt;
+	REG_WR_IND(bp, cpu_reg->mode, val);
+	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+
+	/* Load the Text area. */
+	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
+	if (fw->text) {
+		int j;
+
+		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->text[j]);
+	        }
+	}
+
+	/* Load the Data area. */
+	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
+	if (fw->data) {
+		int j;
+
+		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->data[j]);
+		}
+	}
+
+	/* Load the SBSS area. */
+	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
+	if (fw->sbss) {
+		int j;
+
+		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->sbss[j]);
+		}
+	}
+
+	/* Load the BSS area. */
+	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
+	if (fw->bss) {
+		int j;
+
+		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->bss[j]);
+		}
+	}
+
+	/* Load the Read-Only area. */
+	offset = cpu_reg->spad_base +
+		(fw->rodata_addr - cpu_reg->mips_view_base);
+	if (fw->rodata) {
+		int j;
+
+		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->rodata[j]);
+		}
+	}
+
+	/* Clear the pre-fetch instruction. */
+	REG_WR_IND(bp, cpu_reg->inst, 0);
+	REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
+
+	/* Start the CPU. */
+	val = REG_RD_IND(bp, cpu_reg->mode);
+	val &= ~cpu_reg->mode_value_halt;
+	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+	REG_WR_IND(bp, cpu_reg->mode, val);
+}
+
+static void
+bnx2_init_cpus(struct bnx2 *bp)
+{
+	struct cpu_reg cpu_reg;
+	struct fw_info fw;
+
+	/* Initialize the RV2P processor. */
+	load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1);
+	load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2);
+
+	/* Initialize the RX Processor. */
+	cpu_reg.mode = BNX2_RXP_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_RXP_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_RXP_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_RXP_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_RXP_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_RXP_b06FwReleaseFix;
+	fw.start_addr = bnx2_RXP_b06FwStartAddr;
+
+	fw.text_addr = bnx2_RXP_b06FwTextAddr;
+	fw.text_len = bnx2_RXP_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_RXP_b06FwText;
+
+	fw.data_addr = bnx2_RXP_b06FwDataAddr;
+	fw.data_len = bnx2_RXP_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_RXP_b06FwData;
+
+	fw.sbss_addr = bnx2_RXP_b06FwSbssAddr;
+	fw.sbss_len = bnx2_RXP_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_RXP_b06FwSbss;
+
+	fw.bss_addr = bnx2_RXP_b06FwBssAddr;
+	fw.bss_len = bnx2_RXP_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_RXP_b06FwBss;
+
+	fw.rodata_addr = bnx2_RXP_b06FwRodataAddr;
+	fw.rodata_len = bnx2_RXP_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_RXP_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the TX Processor. */
+	cpu_reg.mode = BNX2_TXP_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_TXP_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_TXP_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_TXP_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_TXP_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_TXP_b06FwReleaseFix;
+	fw.start_addr = bnx2_TXP_b06FwStartAddr;
+
+	fw.text_addr = bnx2_TXP_b06FwTextAddr;
+	fw.text_len = bnx2_TXP_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_TXP_b06FwText;
+
+	fw.data_addr = bnx2_TXP_b06FwDataAddr;
+	fw.data_len = bnx2_TXP_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_TXP_b06FwData;
+
+	fw.sbss_addr = bnx2_TXP_b06FwSbssAddr;
+	fw.sbss_len = bnx2_TXP_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_TXP_b06FwSbss;
+
+	fw.bss_addr = bnx2_TXP_b06FwBssAddr;
+	fw.bss_len = bnx2_TXP_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_TXP_b06FwBss;
+
+	fw.rodata_addr = bnx2_TXP_b06FwRodataAddr;
+	fw.rodata_len = bnx2_TXP_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_TXP_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the TX Patch-up Processor. */
+	cpu_reg.mode = BNX2_TPAT_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_TPAT_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_TPAT_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_TPAT_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_TPAT_b06FwReleaseFix;
+	fw.start_addr = bnx2_TPAT_b06FwStartAddr;
+
+	fw.text_addr = bnx2_TPAT_b06FwTextAddr;
+	fw.text_len = bnx2_TPAT_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_TPAT_b06FwText;
+
+	fw.data_addr = bnx2_TPAT_b06FwDataAddr;
+	fw.data_len = bnx2_TPAT_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_TPAT_b06FwData;
+
+	fw.sbss_addr = bnx2_TPAT_b06FwSbssAddr;
+	fw.sbss_len = bnx2_TPAT_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_TPAT_b06FwSbss;
+
+	fw.bss_addr = bnx2_TPAT_b06FwBssAddr;
+	fw.bss_len = bnx2_TPAT_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_TPAT_b06FwBss;
+
+	fw.rodata_addr = bnx2_TPAT_b06FwRodataAddr;
+	fw.rodata_len = bnx2_TPAT_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_TPAT_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the Completion Processor. */
+	cpu_reg.mode = BNX2_COM_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_COM_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_COM_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_COM_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_COM_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_COM_b06FwReleaseFix;
+	fw.start_addr = bnx2_COM_b06FwStartAddr;
+
+	fw.text_addr = bnx2_COM_b06FwTextAddr;
+	fw.text_len = bnx2_COM_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_COM_b06FwText;
+
+	fw.data_addr = bnx2_COM_b06FwDataAddr;
+	fw.data_len = bnx2_COM_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_COM_b06FwData;
+
+	fw.sbss_addr = bnx2_COM_b06FwSbssAddr;
+	fw.sbss_len = bnx2_COM_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_COM_b06FwSbss;
+
+	fw.bss_addr = bnx2_COM_b06FwBssAddr;
+	fw.bss_len = bnx2_COM_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_COM_b06FwBss;
+
+	fw.rodata_addr = bnx2_COM_b06FwRodataAddr;
+	fw.rodata_len = bnx2_COM_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_COM_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+}
+
+static int
+bnx2_set_power_state(struct bnx2 *bp, int state)
+{
+	u16 pmcsr;
+
+	pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+
+	switch (state) {
+	case 0: {
+		u32 val;
+
+		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+			(pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
+			PCI_PM_CTRL_PME_STATUS);
+
+		if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+			/* delay required during transition out of D3hot */
+			msleep(20);
+
+		val = REG_RD(bp, BNX2_EMAC_MODE);
+		val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
+		val &= ~BNX2_EMAC_MODE_MPKT;
+		REG_WR(bp, BNX2_EMAC_MODE, val);
+
+		val = REG_RD(bp, BNX2_RPM_CONFIG);
+		val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
+		REG_WR(bp, BNX2_RPM_CONFIG, val);
+		break;
+	}
+	case 3: {
+		int i;
+		u32 val, wol_msg;
+
+		if (bp->wol) {
+			u32 advertising;
+			u8 autoneg;
+
+			autoneg = bp->autoneg;
+			advertising = bp->advertising;
+
+			bp->autoneg = AUTONEG_SPEED;
+			bp->advertising = ADVERTISED_10baseT_Half |
+				ADVERTISED_10baseT_Full |
+				ADVERTISED_100baseT_Half |
+				ADVERTISED_100baseT_Full |
+				ADVERTISED_Autoneg;
+
+			bnx2_setup_copper_phy(bp);
+
+			bp->autoneg = autoneg;
+			bp->advertising = advertising;
+
+			bnx2_set_mac_addr(bp);
+
+			val = REG_RD(bp, BNX2_EMAC_MODE);
+
+			/* Enable port mode. */
+			val &= ~BNX2_EMAC_MODE_PORT;
+			val |= BNX2_EMAC_MODE_PORT_MII |
+			       BNX2_EMAC_MODE_MPKT_RCVD |
+			       BNX2_EMAC_MODE_ACPI_RCVD |
+			       BNX2_EMAC_MODE_FORCE_LINK |
+			       BNX2_EMAC_MODE_MPKT;
+
+			REG_WR(bp, BNX2_EMAC_MODE, val);
+
+			/* receive all multicast */
+			for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
+				REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
+				       0xffffffff);
+			}
+			REG_WR(bp, BNX2_EMAC_RX_MODE,
+			       BNX2_EMAC_RX_MODE_SORT_MODE);
+
+			val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
+			      BNX2_RPM_SORT_USER0_MC_EN;
+			REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
+			REG_WR(bp, BNX2_RPM_SORT_USER0, val);
+			REG_WR(bp, BNX2_RPM_SORT_USER0, val |
+			       BNX2_RPM_SORT_USER0_ENA);
+
+			/* Need to enable EMAC and RPM for WOL. */
+			REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
+			       BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
+			       BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
+			       BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
+
+			val = REG_RD(bp, BNX2_RPM_CONFIG);
+			val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
+			REG_WR(bp, BNX2_RPM_CONFIG, val);
+
+			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
+		}
+		else {
+			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
+		}
+
+		bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg);
+
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
+		    (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
+
+			if (bp->wol)
+				pmcsr |= 3;
+		}
+		else {
+			pmcsr |= 3;
+		}
+		if (bp->wol) {
+			pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+		}
+		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+				      pmcsr);
+
+		/* No more memory access after this point until
+		 * device is brought back to D0.
+		 */
+		udelay(50);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+bnx2_acquire_nvram_lock(struct bnx2 *bp)
+{
+	u32 val;
+	int j;
+
+	/* Request access to the flash interface. */
+	REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
+	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+		val = REG_RD(bp, BNX2_NVM_SW_ARB);
+		if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
+			break;
+
+		udelay(5);
+	}
+
+	if (j >= NVRAM_TIMEOUT_COUNT)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int
+bnx2_release_nvram_lock(struct bnx2 *bp)
+{
+	int j;
+	u32 val;
+
+	/* Relinquish nvram interface. */
+	REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
+
+	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+		val = REG_RD(bp, BNX2_NVM_SW_ARB);
+		if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
+			break;
+
+		udelay(5);
+	}
+
+	if (j >= NVRAM_TIMEOUT_COUNT)
+		return -EBUSY;
+
+	return 0;
+}
+
+
+static int
+bnx2_enable_nvram_write(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_MISC_CFG);
+	REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
+
+	if (!bp->flash_info->buffered) {
+		int j;
+
+		REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
+		REG_WR(bp, BNX2_NVM_COMMAND,
+		       BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
+
+		for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+			udelay(5);
+
+			val = REG_RD(bp, BNX2_NVM_COMMAND);
+			if (val & BNX2_NVM_COMMAND_DONE)
+				break;
+		}
+
+		if (j >= NVRAM_TIMEOUT_COUNT)
+			return -EBUSY;
+	}
+	return 0;
+}
+
+static void
+bnx2_disable_nvram_write(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_MISC_CFG);
+	REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
+}
+
+
+static void
+bnx2_enable_nvram_access(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+	/* Enable both bits, even on read. */
+	REG_WR(bp, BNX2_NVM_ACCESS_ENABLE, 
+	       val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
+}
+
+static void
+bnx2_disable_nvram_access(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+	/* Disable both bits, even after read. */
+	REG_WR(bp, BNX2_NVM_ACCESS_ENABLE, 
+		val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
+			BNX2_NVM_ACCESS_ENABLE_WR_EN));
+}
+
+static int
+bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
+{
+	u32 cmd;
+	int j;
+
+	if (bp->flash_info->buffered)
+		/* Buffered flash, no erase needed */
+		return 0;
+
+	/* Build an erase command */
+	cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
+	      BNX2_NVM_COMMAND_DOIT;
+
+	/* Need to clear DONE bit separately. */
+	REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
+
+	/* Address of the NVRAM to read from. */
+	REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
+
+	/* Issue an erase command. */
+	REG_WR(bp, BNX2_NVM_COMMAND, cmd);
+
+	/* Wait for completion. */
+	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+		u32 val;
+
+		udelay(5);
+
+		val = REG_RD(bp, BNX2_NVM_COMMAND);
+		if (val & BNX2_NVM_COMMAND_DONE)
+			break;
+	}
+
+	if (j >= NVRAM_TIMEOUT_COUNT)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int
+bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
+{
+	u32 cmd;
+	int j;
+
+	/* Build the command word. */
+	cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
+
+	/* Calculate an offset of a buffered flash. */
+	if (bp->flash_info->buffered) {
+		offset = ((offset / bp->flash_info->page_size) <<
+			   bp->flash_info->page_bits) +
+			  (offset % bp->flash_info->page_size);
+	}
+
+	/* Need to clear DONE bit separately. */
+	REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
+
+	/* Address of the NVRAM to read from. */
+	REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
+
+	/* Issue a read command. */
+	REG_WR(bp, BNX2_NVM_COMMAND, cmd);
+
+	/* Wait for completion. */
+	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+		u32 val;
+
+		udelay(5);
+
+		val = REG_RD(bp, BNX2_NVM_COMMAND);
+		if (val & BNX2_NVM_COMMAND_DONE) {
+			val = REG_RD(bp, BNX2_NVM_READ);
+
+			val = be32_to_cpu(val);
+			memcpy(ret_val, &val, 4);
+			break;
+		}
+	}
+	if (j >= NVRAM_TIMEOUT_COUNT)
+		return -EBUSY;
+
+	return 0;
+}
+
+
+static int
+bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
+{
+	u32 cmd, val32;
+	int j;
+
+	/* Build the command word. */
+	cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
+
+	/* Calculate an offset of a buffered flash. */
+	if (bp->flash_info->buffered) {
+		offset = ((offset / bp->flash_info->page_size) <<
+			  bp->flash_info->page_bits) +
+			 (offset % bp->flash_info->page_size);
+	}
+
+	/* Need to clear DONE bit separately. */
+	REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
+
+	memcpy(&val32, val, 4);
+	val32 = cpu_to_be32(val32);
+
+	/* Write the data. */
+	REG_WR(bp, BNX2_NVM_WRITE, val32);
+
+	/* Address of the NVRAM to write to. */
+	REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
+
+	/* Issue the write command. */
+	REG_WR(bp, BNX2_NVM_COMMAND, cmd);
+
+	/* Wait for completion. */
+	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
+		udelay(5);
+
+		if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
+			break;
+	}
+	if (j >= NVRAM_TIMEOUT_COUNT)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int
+bnx2_init_nvram(struct bnx2 *bp)
+{
+	u32 val;
+	int j, entry_count, rc;
+	struct flash_spec *flash;
+
+	/* Determine the selected interface. */
+	val = REG_RD(bp, BNX2_NVM_CFG1);
+
+	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
+
+	rc = 0;
+	if (val & 0x40000000) {
+
+		/* Flash interface has been reconfigured */
+		for (j = 0, flash = &flash_table[0]; j < entry_count;
+			j++, flash++) {
+
+			if (val == flash->config1) {
+				bp->flash_info = flash;
+				break;
+			}
+		}
+	}
+	else {
+		/* Not yet been reconfigured */
+
+		for (j = 0, flash = &flash_table[0]; j < entry_count;
+			j++, flash++) {
+
+			if ((val & FLASH_STRAP_MASK) == flash->strapping) {
+				bp->flash_info = flash;
+
+				/* Request access to the flash interface. */
+				if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
+					return rc;
+
+				/* Enable access to flash interface */
+				bnx2_enable_nvram_access(bp);
+
+				/* Reconfigure the flash interface */
+				REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
+				REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
+				REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
+				REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
+
+				/* Disable access to flash interface */
+				bnx2_disable_nvram_access(bp);
+				bnx2_release_nvram_lock(bp);
+
+				break;
+			}
+		}
+	} /* if (val & 0x40000000) */
+
+	if (j == entry_count) {
+		bp->flash_info = NULL;
+		printk(KERN_ALERT "Unknown flash/EEPROM type.\n");
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+static int
+bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
+		int buf_size)
+{
+	int rc = 0;
+	u32 cmd_flags, offset32, len32, extra;
+
+	if (buf_size == 0)
+		return 0;
+
+	/* Request access to the flash interface. */
+	if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
+		return rc;
+
+	/* Enable access to flash interface */
+	bnx2_enable_nvram_access(bp);
+
+	len32 = buf_size;
+	offset32 = offset;
+	extra = 0;
+
+	cmd_flags = 0;
+
+	if (offset32 & 3) {
+		u8 buf[4];
+		u32 pre_len;
+
+		offset32 &= ~3;
+		pre_len = 4 - (offset & 3);
+
+		if (pre_len >= len32) {
+			pre_len = len32;
+			cmd_flags = BNX2_NVM_COMMAND_FIRST |
+				    BNX2_NVM_COMMAND_LAST;
+		}
+		else {
+			cmd_flags = BNX2_NVM_COMMAND_FIRST;
+		}
+
+		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
+
+		if (rc)
+			return rc;
+
+		memcpy(ret_buf, buf + (offset & 3), pre_len);
+
+		offset32 += 4;
+		ret_buf += pre_len;
+		len32 -= pre_len;
+	}
+	if (len32 & 3) {
+		extra = 4 - (len32 & 3);
+		len32 = (len32 + 4) & ~3;
+	}
+
+	if (len32 == 4) {
+		u8 buf[4];
+
+		if (cmd_flags)
+			cmd_flags = BNX2_NVM_COMMAND_LAST;
+		else
+			cmd_flags = BNX2_NVM_COMMAND_FIRST |
+				    BNX2_NVM_COMMAND_LAST;
+
+		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
+
+		memcpy(ret_buf, buf, 4 - extra);
+	}
+	else if (len32 > 0) {
+		u8 buf[4];
+
+		/* Read the first word. */
+		if (cmd_flags)
+			cmd_flags = 0;
+		else
+			cmd_flags = BNX2_NVM_COMMAND_FIRST;
+
+		rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
+
+		/* Advance to the next dword. */
+		offset32 += 4;
+		ret_buf += 4;
+		len32 -= 4;
+
+		while (len32 > 4 && rc == 0) {
+			rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
+
+			/* Advance to the next dword. */
+			offset32 += 4;
+			ret_buf += 4;
+			len32 -= 4;
+		}
+
+		if (rc)
+			return rc;
+
+		cmd_flags = BNX2_NVM_COMMAND_LAST;
+		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
+
+		memcpy(ret_buf, buf, 4 - extra);
+	}
+
+	/* Disable access to flash interface */
+	bnx2_disable_nvram_access(bp);
+
+	bnx2_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int
+bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
+		int buf_size)
+{
+	u32 written, offset32, len32;
+	u8 *buf, start[4], end[4];
+	int rc = 0;
+	int align_start, align_end;
+
+	buf = data_buf;
+	offset32 = offset;
+	len32 = buf_size;
+	align_start = align_end = 0;
+
+	if ((align_start = (offset32 & 3))) {
+		offset32 &= ~3;
+		len32 += align_start;
+		if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
+			return rc;
+	}
+
+	if (len32 & 3) {
+	       	if ((len32 > 4) || !align_start) {
+			align_end = 4 - (len32 & 3);
+			len32 += align_end;
+			if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4,
+				end, 4))) {
+				return rc;
+			}
+		}
+	}
+
+	if (align_start || align_end) {
+		buf = kmalloc(len32, GFP_KERNEL);
+		if (buf == 0)
+			return -ENOMEM;
+		if (align_start) {
+			memcpy(buf, start, 4);
+		}
+		if (align_end) {
+			memcpy(buf + len32 - 4, end, 4);
+		}
+		memcpy(buf + align_start, data_buf, buf_size);
+	}
+
+	written = 0;
+	while ((written < len32) && (rc == 0)) {
+		u32 page_start, page_end, data_start, data_end;
+		u32 addr, cmd_flags;
+		int i;
+		u8 flash_buffer[264];
+
+	        /* Find the page_start addr */
+		page_start = offset32 + written;
+		page_start -= (page_start % bp->flash_info->page_size);
+		/* Find the page_end addr */
+		page_end = page_start + bp->flash_info->page_size;
+		/* Find the data_start addr */
+		data_start = (written == 0) ? offset32 : page_start;
+		/* Find the data_end addr */
+		data_end = (page_end > offset32 + len32) ? 
+			(offset32 + len32) : page_end;
+
+		/* Request access to the flash interface. */
+		if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
+			goto nvram_write_end;
+
+		/* Enable access to flash interface */
+		bnx2_enable_nvram_access(bp);
+
+		cmd_flags = BNX2_NVM_COMMAND_FIRST;
+		if (bp->flash_info->buffered == 0) {
+			int j;
+
+			/* Read the whole page into the buffer
+			 * (non-buffer flash only) */
+			for (j = 0; j < bp->flash_info->page_size; j += 4) {
+				if (j == (bp->flash_info->page_size - 4)) {
+					cmd_flags |= BNX2_NVM_COMMAND_LAST;
+				}
+				rc = bnx2_nvram_read_dword(bp,
+					page_start + j, 
+					&flash_buffer[j], 
+					cmd_flags);
+
+				if (rc)
+					goto nvram_write_end;
+
+				cmd_flags = 0;
+			}
+		}
+
+		/* Enable writes to flash interface (unlock write-protect) */
+		if ((rc = bnx2_enable_nvram_write(bp)) != 0)
+			goto nvram_write_end;
+
+		/* Erase the page */
+		if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
+			goto nvram_write_end;
+
+		/* Re-enable the write again for the actual write */
+		bnx2_enable_nvram_write(bp);
+
+		/* Loop to write back the buffer data from page_start to
+		 * data_start */
+		i = 0;
+		if (bp->flash_info->buffered == 0) {
+			for (addr = page_start; addr < data_start;
+				addr += 4, i += 4) {
+				
+				rc = bnx2_nvram_write_dword(bp, addr,
+					&flash_buffer[i], cmd_flags);
+
+				if (rc != 0)
+					goto nvram_write_end;
+
+				cmd_flags = 0;
+			}
+		}
+
+		/* Loop to write the new data from data_start to data_end */
+		for (addr = data_start; addr < data_end; addr += 4, i++) {
+			if ((addr == page_end - 4) ||
+				((bp->flash_info->buffered) &&
+				 (addr == data_end - 4))) {
+
+				cmd_flags |= BNX2_NVM_COMMAND_LAST;
+			}
+			rc = bnx2_nvram_write_dword(bp, addr, buf,
+				cmd_flags);
+
+			if (rc != 0)
+				goto nvram_write_end;
+
+			cmd_flags = 0;
+			buf += 4;
+		}
+
+		/* Loop to write back the buffer data from data_end
+		 * to page_end */
+		if (bp->flash_info->buffered == 0) {
+			for (addr = data_end; addr < page_end;
+				addr += 4, i += 4) {
+			
+				if (addr == page_end-4) {
+					cmd_flags = BNX2_NVM_COMMAND_LAST;
+                		}
+				rc = bnx2_nvram_write_dword(bp, addr,
+					&flash_buffer[i], cmd_flags);
+
+				if (rc != 0)
+					goto nvram_write_end;
+
+				cmd_flags = 0;
+			}
+		}
+
+		/* Disable writes to flash interface (lock write-protect) */
+		bnx2_disable_nvram_write(bp);
+
+		/* Disable access to flash interface */
+		bnx2_disable_nvram_access(bp);
+		bnx2_release_nvram_lock(bp);
+
+		/* Increment written */
+		written += data_end - data_start;
+	}
+
+nvram_write_end:
+	if (align_start || align_end)
+		kfree(buf);
+	return rc;
+}
+
+static int
+bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+{
+	u32 val;
+	int i, rc = 0;
+
+	/* Wait for the current PCI transaction to complete before
+	 * issuing a reset. */
+	REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
+	       BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
+	val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
+	udelay(5);
+
+	/* Deposit a driver reset signature so the firmware knows that
+	 * this is a soft reset. */
+	REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_RESET_SIGNATURE,
+		   BNX2_DRV_RESET_SIGNATURE_MAGIC);
+
+	bp->fw_timed_out = 0;
+
+	/* Wait for the firmware to tell us it is ok to issue a reset. */
+	bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code);
+
+	/* Do a dummy read to force the chip to complete all current transaction
+	 * before we issue a reset. */
+	val = REG_RD(bp, BNX2_MISC_ID);
+
+	val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+	      BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
+	      BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
+
+	/* Chip reset. */
+	REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
+
+	if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
+	    (CHIP_ID(bp) == CHIP_ID_5706_A1))
+		msleep(15);
+
+	/* Reset takes approximate 30 usec */
+	for (i = 0; i < 10; i++) {
+		val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
+		if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+			    BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
+			break;
+		}
+		udelay(10);
+	}
+
+	if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+		   BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
+		printk(KERN_ERR PFX "Chip reset did not complete\n");
+		return -EBUSY;
+	}
+
+	/* Make sure byte swapping is properly configured. */
+	val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
+	if (val != 0x01020304) {
+		printk(KERN_ERR PFX "Chip not in correct endian mode\n");
+		return -ENODEV;
+	}
+
+	bp->fw_timed_out = 0;
+
+	/* Wait for the firmware to finish its initialization. */
+	bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code);
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		/* Adjust the voltage regular to two steps lower.  The default
+		 * of this register is 0x0000000e. */
+		REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
+
+		/* Remove bad rbuf memory from the free pool. */
+		rc = bnx2_alloc_bad_rbuf(bp);
+	}
+
+	return rc;
+}
+
+static int
+bnx2_init_chip(struct bnx2 *bp)
+{
+	u32 val;
+
+	/* Make sure the interrupt is not active. */
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+
+	val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
+	      BNX2_DMA_CONFIG_DATA_WORD_SWAP |
+#ifdef __BIG_ENDIAN
+	      BNX2_DMA_CONFIG_CNTL_BYTE_SWAP | 
+#endif
+	      BNX2_DMA_CONFIG_CNTL_WORD_SWAP | 
+	      DMA_READ_CHANS << 12 |
+	      DMA_WRITE_CHANS << 16;
+
+	val |= (0x2 << 20) | (1 << 11);
+
+	if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz = 133))
+		val |= (1 << 23);
+
+	if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
+	    (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
+		val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
+
+	REG_WR(bp, BNX2_DMA_CONFIG, val);
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		val = REG_RD(bp, BNX2_TDMA_CONFIG);
+		val |= BNX2_TDMA_CONFIG_ONE_DMA;
+		REG_WR(bp, BNX2_TDMA_CONFIG, val);
+	}
+
+	if (bp->flags & PCIX_FLAG) {
+		u16 val16;
+
+		pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
+				     &val16);
+		pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
+				      val16 & ~PCI_X_CMD_ERO);
+	}
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
+	       BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
+	       BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
+	       BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
+
+	/* Initialize context mapping and zero out the quick contexts.  The
+	 * context block must have already been enabled. */
+	bnx2_init_context(bp);
+
+	bnx2_init_cpus(bp);
+	bnx2_init_nvram(bp);
+
+	bnx2_set_mac_addr(bp);
+
+	val = REG_RD(bp, BNX2_MQ_CONFIG);
+	val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
+	val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
+	REG_WR(bp, BNX2_MQ_CONFIG, val);
+
+	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
+	REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
+	REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
+
+	val = (BCM_PAGE_BITS - 8) << 24;
+	REG_WR(bp, BNX2_RV2P_CONFIG, val);
+
+	/* Configure page size. */
+	val = REG_RD(bp, BNX2_TBDR_CONFIG);
+	val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
+	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
+	REG_WR(bp, BNX2_TBDR_CONFIG, val);
+
+	val = bp->mac_addr[0] +
+	      (bp->mac_addr[1] << 8) +
+	      (bp->mac_addr[2] << 16) +
+	      bp->mac_addr[3] +
+	      (bp->mac_addr[4] << 8) +
+	      (bp->mac_addr[5] << 16);
+	REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
+
+	/* Program the MTU.  Also include 4 bytes for CRC32. */
+	val = bp->dev->mtu + ETH_HLEN + 4;
+	if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
+		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
+	REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
+
+	bp->last_status_idx = 0;
+	bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
+
+	/* Set up how to generate a link change interrupt. */
+	REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+
+	REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
+	       (u64) bp->status_blk_mapping & 0xffffffff);
+	REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
+
+	REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
+	       (u64) bp->stats_blk_mapping & 0xffffffff);
+	REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
+	       (u64) bp->stats_blk_mapping >> 32);
+
+	REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP, 
+	       (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
+
+	REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
+	       (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
+
+	REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
+	       (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
+
+	REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
+
+	REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
+
+	REG_WR(bp, BNX2_HC_COM_TICKS,
+	       (bp->com_ticks_int << 16) | bp->com_ticks);
+
+	REG_WR(bp, BNX2_HC_CMD_TICKS,
+	       (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
+
+	REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+	REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A1)
+		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
+	else {
+		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
+		       BNX2_HC_CONFIG_TX_TMR_MODE |
+		       BNX2_HC_CONFIG_COLLECT_STATS);
+	}
+
+	/* Clear internal stats counters. */
+	REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
+
+	REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
+
+	/* Initialize the receive filter. */
+	bnx2_set_rx_mode(bp->dev);
+
+	bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET);
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 0x5ffffff);
+	REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
+
+	udelay(20);
+
+	return 0;
+}
+
+
+static void
+bnx2_init_tx_ring(struct bnx2 *bp)
+{
+	struct tx_bd *txbd;
+	u32 val;
+
+	txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
+		
+	txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
+	txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
+
+	bp->tx_prod = 0;
+	bp->tx_cons = 0;
+	bp->tx_prod_bseq = 0;
+	atomic_set(&bp->tx_avail_bd, bp->tx_ring_size);
+	
+	val = BNX2_L2CTX_TYPE_TYPE_L2;
+	val |= BNX2_L2CTX_TYPE_SIZE_L2;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TYPE, val);
+
+	val = BNX2_L2CTX_CMD_TYPE_TYPE_L2;
+	val |= 8 << 16;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_CMD_TYPE, val);
+
+	val = (u64) bp->tx_desc_mapping >> 32;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_HI, val);
+
+	val = (u64) bp->tx_desc_mapping & 0xffffffff;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_LO, val);
+}
+
+static void
+bnx2_init_rx_ring(struct bnx2 *bp)
+{
+	struct rx_bd *rxbd;
+	int i;
+	u16 prod, ring_prod; 
+	u32 val;
+
+	/* 8 for CRC and VLAN */
+	bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
+	/* 8 for alignment */
+	bp->rx_buf_size = bp->rx_buf_use_size + 8;
+
+	ring_prod = prod = bp->rx_prod = 0;
+	bp->rx_cons = 0;
+	bp->rx_prod_bseq = 0;
+		
+	rxbd = &bp->rx_desc_ring[0];
+	for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
+		rxbd->rx_bd_len = bp->rx_buf_use_size;
+		rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+	}
+
+	rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32;
+	rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+
+	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
+	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
+	val |= 0x02 << 8;
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
+
+	val = (u64) bp->rx_desc_mapping >> 32;
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
+
+	val = (u64) bp->rx_desc_mapping & 0xffffffff;
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
+
+	for ( ;ring_prod < bp->rx_ring_size; ) {
+		if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
+			break;
+		}
+		prod = NEXT_RX_BD(prod);
+		ring_prod = RX_RING_IDX(prod);
+	}
+	bp->rx_prod = prod;
+
+	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
+
+	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+}
+
+static void
+bnx2_free_tx_skbs(struct bnx2 *bp)
+{
+	int i;
+
+	if (bp->tx_buf_ring == NULL)
+		return;
+
+	for (i = 0; i < TX_DESC_CNT; ) {
+		struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
+		struct sk_buff *skb = tx_buf->skb;
+		int j, last;
+
+		if (skb == NULL) {
+			i++;
+			continue;
+		}
+
+		pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
+			skb_headlen(skb), PCI_DMA_TODEVICE);
+
+		tx_buf->skb = NULL;
+
+		last = skb_shinfo(skb)->nr_frags;
+		for (j = 0; j < last; j++) {
+			tx_buf = &bp->tx_buf_ring[i + j + 1];
+			pci_unmap_page(bp->pdev,
+				pci_unmap_addr(tx_buf, mapping),
+				skb_shinfo(skb)->frags[j].size,
+				PCI_DMA_TODEVICE);
+		}
+		dev_kfree_skb_any(skb);
+		i += j + 1;
+	}
+
+}
+
+static void
+bnx2_free_rx_skbs(struct bnx2 *bp)
+{
+	int i;
+
+	if (bp->rx_buf_ring == NULL)
+		return;
+
+	for (i = 0; i < RX_DESC_CNT; i++) {
+		struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
+		struct sk_buff *skb = rx_buf->skb;
+
+		if (skb == 0)
+			continue;
+
+		pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
+			bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+
+		rx_buf->skb = NULL;
+
+		dev_kfree_skb_any(skb);
+	}
+}
+
+static void
+bnx2_free_skbs(struct bnx2 *bp)
+{
+	bnx2_free_tx_skbs(bp);
+	bnx2_free_rx_skbs(bp);
+}
+
+static int
+bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
+{
+	int rc;
+
+	rc = bnx2_reset_chip(bp, reset_code);
+	bnx2_free_skbs(bp);
+	if (rc)
+		return rc;
+
+	bnx2_init_chip(bp);
+	bnx2_init_tx_ring(bp);
+	bnx2_init_rx_ring(bp);
+	return 0;
+}
+
+static int
+bnx2_init_nic(struct bnx2 *bp)
+{
+	int rc;
+
+	if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
+		return rc;
+
+	bnx2_init_phy(bp);
+	bnx2_set_link(bp);
+	return 0;
+}
+
+static int
+bnx2_test_registers(struct bnx2 *bp)
+{
+	int ret;
+	int i;
+	static struct {
+		u16   offset;
+		u16   flags;
+		u32   rw_mask;
+		u32   ro_mask;
+	} reg_tbl[] = {
+		{ 0x006c, 0, 0x00000000, 0x0000003f },
+		{ 0x0090, 0, 0xffffffff, 0x00000000 },
+		{ 0x0094, 0, 0x00000000, 0x00000000 },
+
+		{ 0x0404, 0, 0x00003f00, 0x00000000 },
+		{ 0x0418, 0, 0x00000000, 0xffffffff },
+		{ 0x041c, 0, 0x00000000, 0xffffffff },
+		{ 0x0420, 0, 0x00000000, 0x80ffffff },
+		{ 0x0424, 0, 0x00000000, 0x00000000 },
+		{ 0x0428, 0, 0x00000000, 0x00000001 },
+		{ 0x0450, 0, 0x00000000, 0x0000ffff },
+		{ 0x0454, 0, 0x00000000, 0xffffffff },
+		{ 0x0458, 0, 0x00000000, 0xffffffff },
+
+		{ 0x0808, 0, 0x00000000, 0xffffffff },
+		{ 0x0854, 0, 0x00000000, 0xffffffff },
+		{ 0x0868, 0, 0x00000000, 0x77777777 },
+		{ 0x086c, 0, 0x00000000, 0x77777777 },
+		{ 0x0870, 0, 0x00000000, 0x77777777 },
+		{ 0x0874, 0, 0x00000000, 0x77777777 },
+
+		{ 0x0c00, 0, 0x00000000, 0x00000001 },
+		{ 0x0c04, 0, 0x00000000, 0x03ff0001 },
+		{ 0x0c08, 0, 0x0f0ff073, 0x00000000 },
+		{ 0x0c0c, 0, 0x00ffffff, 0x00000000 },
+		{ 0x0c30, 0, 0x00000000, 0xffffffff },
+		{ 0x0c34, 0, 0x00000000, 0xffffffff },
+		{ 0x0c38, 0, 0x00000000, 0xffffffff },
+		{ 0x0c3c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c40, 0, 0x00000000, 0xffffffff },
+		{ 0x0c44, 0, 0x00000000, 0xffffffff },
+		{ 0x0c48, 0, 0x00000000, 0x0007ffff },
+		{ 0x0c4c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c50, 0, 0x00000000, 0xffffffff },
+		{ 0x0c54, 0, 0x00000000, 0xffffffff },
+		{ 0x0c58, 0, 0x00000000, 0xffffffff },
+		{ 0x0c5c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c60, 0, 0x00000000, 0xffffffff },
+		{ 0x0c64, 0, 0x00000000, 0xffffffff },
+		{ 0x0c68, 0, 0x00000000, 0xffffffff },
+		{ 0x0c6c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c70, 0, 0x00000000, 0xffffffff },
+		{ 0x0c74, 0, 0x00000000, 0xffffffff },
+		{ 0x0c78, 0, 0x00000000, 0xffffffff },
+		{ 0x0c7c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c80, 0, 0x00000000, 0xffffffff },
+		{ 0x0c84, 0, 0x00000000, 0xffffffff },
+		{ 0x0c88, 0, 0x00000000, 0xffffffff },
+		{ 0x0c8c, 0, 0x00000000, 0xffffffff },
+		{ 0x0c90, 0, 0x00000000, 0xffffffff },
+		{ 0x0c94, 0, 0x00000000, 0xffffffff },
+		{ 0x0c98, 0, 0x00000000, 0xffffffff },
+		{ 0x0c9c, 0, 0x00000000, 0xffffffff },
+		{ 0x0ca0, 0, 0x00000000, 0xffffffff },
+		{ 0x0ca4, 0, 0x00000000, 0xffffffff },
+		{ 0x0ca8, 0, 0x00000000, 0x0007ffff },
+		{ 0x0cac, 0, 0x00000000, 0xffffffff },
+		{ 0x0cb0, 0, 0x00000000, 0xffffffff },
+		{ 0x0cb4, 0, 0x00000000, 0xffffffff },
+		{ 0x0cb8, 0, 0x00000000, 0xffffffff },
+		{ 0x0cbc, 0, 0x00000000, 0xffffffff },
+		{ 0x0cc0, 0, 0x00000000, 0xffffffff },
+		{ 0x0cc4, 0, 0x00000000, 0xffffffff },
+		{ 0x0cc8, 0, 0x00000000, 0xffffffff },
+		{ 0x0ccc, 0, 0x00000000, 0xffffffff },
+		{ 0x0cd0, 0, 0x00000000, 0xffffffff },
+		{ 0x0cd4, 0, 0x00000000, 0xffffffff },
+		{ 0x0cd8, 0, 0x00000000, 0xffffffff },
+		{ 0x0cdc, 0, 0x00000000, 0xffffffff },
+		{ 0x0ce0, 0, 0x00000000, 0xffffffff },
+		{ 0x0ce4, 0, 0x00000000, 0xffffffff },
+		{ 0x0ce8, 0, 0x00000000, 0xffffffff },
+		{ 0x0cec, 0, 0x00000000, 0xffffffff },
+		{ 0x0cf0, 0, 0x00000000, 0xffffffff },
+		{ 0x0cf4, 0, 0x00000000, 0xffffffff },
+		{ 0x0cf8, 0, 0x00000000, 0xffffffff },
+		{ 0x0cfc, 0, 0x00000000, 0xffffffff },
+		{ 0x0d00, 0, 0x00000000, 0xffffffff },
+		{ 0x0d04, 0, 0x00000000, 0xffffffff },
+
+		{ 0x1000, 0, 0x00000000, 0x00000001 },
+		{ 0x1004, 0, 0x00000000, 0x000f0001 },
+		{ 0x1044, 0, 0x00000000, 0xffc003ff },
+		{ 0x1080, 0, 0x00000000, 0x0001ffff },
+		{ 0x1084, 0, 0x00000000, 0xffffffff },
+		{ 0x1088, 0, 0x00000000, 0xffffffff },
+		{ 0x108c, 0, 0x00000000, 0xffffffff },
+		{ 0x1090, 0, 0x00000000, 0xffffffff },
+		{ 0x1094, 0, 0x00000000, 0xffffffff },
+		{ 0x1098, 0, 0x00000000, 0xffffffff },
+		{ 0x109c, 0, 0x00000000, 0xffffffff },
+		{ 0x10a0, 0, 0x00000000, 0xffffffff },
+
+		{ 0x1408, 0, 0x01c00800, 0x00000000 },
+		{ 0x149c, 0, 0x8000ffff, 0x00000000 },
+		{ 0x14a8, 0, 0x00000000, 0x000001ff },
+		{ 0x14ac, 0, 0x4fffffff, 0x10000000 },
+		{ 0x14b0, 0, 0x00000002, 0x00000001 },
+		{ 0x14b8, 0, 0x00000000, 0x00000000 },
+		{ 0x14c0, 0, 0x00000000, 0x00000009 },
+		{ 0x14c4, 0, 0x00003fff, 0x00000000 },
+		{ 0x14cc, 0, 0x00000000, 0x00000001 },
+		{ 0x14d0, 0, 0xffffffff, 0x00000000 },
+		{ 0x1500, 0, 0x00000000, 0xffffffff },
+		{ 0x1504, 0, 0x00000000, 0xffffffff },
+		{ 0x1508, 0, 0x00000000, 0xffffffff },
+		{ 0x150c, 0, 0x00000000, 0xffffffff },
+		{ 0x1510, 0, 0x00000000, 0xffffffff },
+		{ 0x1514, 0, 0x00000000, 0xffffffff },
+		{ 0x1518, 0, 0x00000000, 0xffffffff },
+		{ 0x151c, 0, 0x00000000, 0xffffffff },
+		{ 0x1520, 0, 0x00000000, 0xffffffff },
+		{ 0x1524, 0, 0x00000000, 0xffffffff },
+		{ 0x1528, 0, 0x00000000, 0xffffffff },
+		{ 0x152c, 0, 0x00000000, 0xffffffff },
+		{ 0x1530, 0, 0x00000000, 0xffffffff },
+		{ 0x1534, 0, 0x00000000, 0xffffffff },
+		{ 0x1538, 0, 0x00000000, 0xffffffff },
+		{ 0x153c, 0, 0x00000000, 0xffffffff },
+		{ 0x1540, 0, 0x00000000, 0xffffffff },
+		{ 0x1544, 0, 0x00000000, 0xffffffff },
+		{ 0x1548, 0, 0x00000000, 0xffffffff },
+		{ 0x154c, 0, 0x00000000, 0xffffffff },
+		{ 0x1550, 0, 0x00000000, 0xffffffff },
+		{ 0x1554, 0, 0x00000000, 0xffffffff },
+		{ 0x1558, 0, 0x00000000, 0xffffffff },
+		{ 0x1600, 0, 0x00000000, 0xffffffff },
+		{ 0x1604, 0, 0x00000000, 0xffffffff },
+		{ 0x1608, 0, 0x00000000, 0xffffffff },
+		{ 0x160c, 0, 0x00000000, 0xffffffff },
+		{ 0x1610, 0, 0x00000000, 0xffffffff },
+		{ 0x1614, 0, 0x00000000, 0xffffffff },
+		{ 0x1618, 0, 0x00000000, 0xffffffff },
+		{ 0x161c, 0, 0x00000000, 0xffffffff },
+		{ 0x1620, 0, 0x00000000, 0xffffffff },
+		{ 0x1624, 0, 0x00000000, 0xffffffff },
+		{ 0x1628, 0, 0x00000000, 0xffffffff },
+		{ 0x162c, 0, 0x00000000, 0xffffffff },
+		{ 0x1630, 0, 0x00000000, 0xffffffff },
+		{ 0x1634, 0, 0x00000000, 0xffffffff },
+		{ 0x1638, 0, 0x00000000, 0xffffffff },
+		{ 0x163c, 0, 0x00000000, 0xffffffff },
+		{ 0x1640, 0, 0x00000000, 0xffffffff },
+		{ 0x1644, 0, 0x00000000, 0xffffffff },
+		{ 0x1648, 0, 0x00000000, 0xffffffff },
+		{ 0x164c, 0, 0x00000000, 0xffffffff },
+		{ 0x1650, 0, 0x00000000, 0xffffffff },
+		{ 0x1654, 0, 0x00000000, 0xffffffff },
+
+		{ 0x1800, 0, 0x00000000, 0x00000001 },
+		{ 0x1804, 0, 0x00000000, 0x00000003 },
+		{ 0x1840, 0, 0x00000000, 0xffffffff },
+		{ 0x1844, 0, 0x00000000, 0xffffffff },
+		{ 0x1848, 0, 0x00000000, 0xffffffff },
+		{ 0x184c, 0, 0x00000000, 0xffffffff },
+		{ 0x1850, 0, 0x00000000, 0xffffffff },
+		{ 0x1900, 0, 0x7ffbffff, 0x00000000 },
+		{ 0x1904, 0, 0xffffffff, 0x00000000 },
+		{ 0x190c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1914, 0, 0xffffffff, 0x00000000 },
+		{ 0x191c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1924, 0, 0xffffffff, 0x00000000 },
+		{ 0x192c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1934, 0, 0xffffffff, 0x00000000 },
+		{ 0x193c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1944, 0, 0xffffffff, 0x00000000 },
+		{ 0x194c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1954, 0, 0xffffffff, 0x00000000 },
+		{ 0x195c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1964, 0, 0xffffffff, 0x00000000 },
+		{ 0x196c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1974, 0, 0xffffffff, 0x00000000 },
+		{ 0x197c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1980, 0, 0x0700ffff, 0x00000000 },
+
+		{ 0x1c00, 0, 0x00000000, 0x00000001 },
+		{ 0x1c04, 0, 0x00000000, 0x00000003 },
+		{ 0x1c08, 0, 0x0000000f, 0x00000000 },
+		{ 0x1c40, 0, 0x00000000, 0xffffffff },
+		{ 0x1c44, 0, 0x00000000, 0xffffffff },
+		{ 0x1c48, 0, 0x00000000, 0xffffffff },
+		{ 0x1c4c, 0, 0x00000000, 0xffffffff },
+		{ 0x1c50, 0, 0x00000000, 0xffffffff },
+		{ 0x1d00, 0, 0x7ffbffff, 0x00000000 },
+		{ 0x1d04, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d0c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d14, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d1c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d24, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d2c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d34, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d3c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d44, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d4c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d54, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d5c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d64, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d6c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d74, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d7c, 0, 0xffffffff, 0x00000000 },
+		{ 0x1d80, 0, 0x0700ffff, 0x00000000 },
+
+		{ 0x2004, 0, 0x00000000, 0x0337000f },
+		{ 0x2008, 0, 0xffffffff, 0x00000000 },
+		{ 0x200c, 0, 0xffffffff, 0x00000000 },
+		{ 0x2010, 0, 0xffffffff, 0x00000000 },
+		{ 0x2014, 0, 0x801fff80, 0x00000000 },
+		{ 0x2018, 0, 0x000003ff, 0x00000000 },
+
+		{ 0x2800, 0, 0x00000000, 0x00000001 },
+		{ 0x2804, 0, 0x00000000, 0x00003f01 },
+		{ 0x2808, 0, 0x0f3f3f03, 0x00000000 },
+		{ 0x2810, 0, 0xffff0000, 0x00000000 },
+		{ 0x2814, 0, 0xffff0000, 0x00000000 },
+		{ 0x2818, 0, 0xffff0000, 0x00000000 },
+		{ 0x281c, 0, 0xffff0000, 0x00000000 },
+		{ 0x2834, 0, 0xffffffff, 0x00000000 },
+		{ 0x2840, 0, 0x00000000, 0xffffffff },
+		{ 0x2844, 0, 0x00000000, 0xffffffff },
+		{ 0x2848, 0, 0xffffffff, 0x00000000 },
+		{ 0x284c, 0, 0xf800f800, 0x07ff07ff },
+
+		{ 0x2c00, 0, 0x00000000, 0x00000011 },
+		{ 0x2c04, 0, 0x00000000, 0x00030007 },
+
+		{ 0x3000, 0, 0x00000000, 0x00000001 },
+		{ 0x3004, 0, 0x00000000, 0x007007ff },
+		{ 0x3008, 0, 0x00000003, 0x00000000 },
+		{ 0x300c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3010, 0, 0xffffffff, 0x00000000 },
+		{ 0x3014, 0, 0xffffffff, 0x00000000 },
+		{ 0x3034, 0, 0xffffffff, 0x00000000 },
+		{ 0x3038, 0, 0xffffffff, 0x00000000 },
+		{ 0x3050, 0, 0x00000001, 0x00000000 },
+
+		{ 0x3c00, 0, 0x00000000, 0x00000001 },
+		{ 0x3c04, 0, 0x00000000, 0x00070000 },
+		{ 0x3c08, 0, 0x00007f71, 0x07f00000 },
+		{ 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
+		{ 0x3c10, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c14, 0, 0x00000000, 0xffffffff },
+		{ 0x3c18, 0, 0x00000000, 0xffffffff },
+		{ 0x3c1c, 0, 0xfffff000, 0x00000000 },
+		{ 0x3c20, 0, 0xffffff00, 0x00000000 },
+		{ 0x3c24, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c28, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c2c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c30, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c34, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c38, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c3c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c40, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c44, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c48, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c4c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c50, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c54, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c58, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c5c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c60, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c64, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c68, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c6c, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c70, 0, 0xffffffff, 0x00000000 },
+		{ 0x3c74, 0, 0x0000003f, 0x00000000 },
+		{ 0x3c78, 0, 0x00000000, 0x00000000 },
+		{ 0x3c7c, 0, 0x00000000, 0x00000000 },
+		{ 0x3c80, 0, 0x3fffffff, 0x00000000 },
+		{ 0x3c84, 0, 0x0000003f, 0x00000000 },
+		{ 0x3c88, 0, 0x00000000, 0xffffffff },
+		{ 0x3c8c, 0, 0x00000000, 0xffffffff },
+
+		{ 0x4000, 0, 0x00000000, 0x00000001 },
+		{ 0x4004, 0, 0x00000000, 0x00030000 },
+		{ 0x4008, 0, 0x00000ff0, 0x00000000 },
+		{ 0x400c, 0, 0xffffffff, 0x00000000 },
+		{ 0x4088, 0, 0x00000000, 0x00070303 },
+
+		{ 0x4400, 0, 0x00000000, 0x00000001 },
+		{ 0x4404, 0, 0x00000000, 0x00003f01 },
+		{ 0x4408, 0, 0x7fff00ff, 0x00000000 },
+		{ 0x440c, 0, 0xffffffff, 0x00000000 },
+		{ 0x4410, 0, 0xffff,     0x0000 },
+		{ 0x4414, 0, 0xffff,     0x0000 },
+		{ 0x4418, 0, 0xffff,     0x0000 },
+		{ 0x441c, 0, 0xffff,     0x0000 },
+		{ 0x4428, 0, 0xffffffff, 0x00000000 },
+		{ 0x442c, 0, 0xffffffff, 0x00000000 },
+		{ 0x4430, 0, 0xffffffff, 0x00000000 },
+		{ 0x4434, 0, 0xffffffff, 0x00000000 },
+		{ 0x4438, 0, 0xffffffff, 0x00000000 },
+		{ 0x443c, 0, 0xffffffff, 0x00000000 },
+		{ 0x4440, 0, 0xffffffff, 0x00000000 },
+		{ 0x4444, 0, 0xffffffff, 0x00000000 },
+
+		{ 0x4c00, 0, 0x00000000, 0x00000001 },
+		{ 0x4c04, 0, 0x00000000, 0x0000003f },
+		{ 0x4c08, 0, 0xffffffff, 0x00000000 },
+		{ 0x4c0c, 0, 0x0007fc00, 0x00000000 },
+		{ 0x4c10, 0, 0x80003fe0, 0x00000000 },
+		{ 0x4c14, 0, 0xffffffff, 0x00000000 },
+		{ 0x4c44, 0, 0x00000000, 0x9fff9fff },
+		{ 0x4c48, 0, 0x00000000, 0xb3009fff },
+		{ 0x4c4c, 0, 0x00000000, 0x77f33b30 },
+		{ 0x4c50, 0, 0x00000000, 0xffffffff },
+
+		{ 0x5004, 0, 0x00000000, 0x0000007f },
+		{ 0x5008, 0, 0x0f0007ff, 0x00000000 },
+		{ 0x500c, 0, 0xf800f800, 0x07ff07ff },
+
+		{ 0x5400, 0, 0x00000008, 0x00000001 },
+		{ 0x5404, 0, 0x00000000, 0x0000003f },
+		{ 0x5408, 0, 0x0000001f, 0x00000000 },
+		{ 0x540c, 0, 0xffffffff, 0x00000000 },
+		{ 0x5410, 0, 0xffffffff, 0x00000000 },
+		{ 0x5414, 0, 0x0000ffff, 0x00000000 },
+		{ 0x5418, 0, 0x0000ffff, 0x00000000 },
+		{ 0x541c, 0, 0x0000ffff, 0x00000000 },
+		{ 0x5420, 0, 0x0000ffff, 0x00000000 },
+		{ 0x5428, 0, 0x000000ff, 0x00000000 },
+		{ 0x542c, 0, 0xff00ffff, 0x00000000 },
+		{ 0x5430, 0, 0x001fff80, 0x00000000 },
+		{ 0x5438, 0, 0xffffffff, 0x00000000 },
+		{ 0x543c, 0, 0xffffffff, 0x00000000 },
+		{ 0x5440, 0, 0xf800f800, 0x07ff07ff },
+
+		{ 0x5c00, 0, 0x00000000, 0x00000001 },
+		{ 0x5c04, 0, 0x00000000, 0x0003000f },
+		{ 0x5c08, 0, 0x00000003, 0x00000000 },
+		{ 0x5c0c, 0, 0x0000fff8, 0x00000000 },
+		{ 0x5c10, 0, 0x00000000, 0xffffffff },
+		{ 0x5c80, 0, 0x00000000, 0x0f7113f1 },
+		{ 0x5c84, 0, 0x00000000, 0x0000f333 },
+		{ 0x5c88, 0, 0x00000000, 0x00077373 },
+		{ 0x5c8c, 0, 0x00000000, 0x0007f737 },
+
+		{ 0x6808, 0, 0x0000ff7f, 0x00000000 },
+		{ 0x680c, 0, 0xffffffff, 0x00000000 },
+		{ 0x6810, 0, 0xffffffff, 0x00000000 },
+		{ 0x6814, 0, 0xffffffff, 0x00000000 },
+		{ 0x6818, 0, 0xffffffff, 0x00000000 },
+		{ 0x681c, 0, 0xffffffff, 0x00000000 },
+		{ 0x6820, 0, 0x00ff00ff, 0x00000000 },
+		{ 0x6824, 0, 0x00ff00ff, 0x00000000 },
+		{ 0x6828, 0, 0x00ff00ff, 0x00000000 },
+		{ 0x682c, 0, 0x03ff03ff, 0x00000000 },
+		{ 0x6830, 0, 0x03ff03ff, 0x00000000 },
+		{ 0x6834, 0, 0x03ff03ff, 0x00000000 },
+		{ 0x6838, 0, 0x03ff03ff, 0x00000000 },
+		{ 0x683c, 0, 0x0000ffff, 0x00000000 },
+		{ 0x6840, 0, 0x00000ff0, 0x00000000 },
+		{ 0x6844, 0, 0x00ffff00, 0x00000000 },
+		{ 0x684c, 0, 0xffffffff, 0x00000000 },
+		{ 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
+		{ 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
+		{ 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
+		{ 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
+		{ 0x6908, 0, 0x00000000, 0x0001ff0f },
+		{ 0x690c, 0, 0x00000000, 0x0ffe00f0 },
+
+		{ 0xffff, 0, 0x00000000, 0x00000000 },
+	};
+
+	ret = 0;
+	for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
+		u32 offset, rw_mask, ro_mask, save_val, val;
+
+		offset = (u32) reg_tbl[i].offset;
+		rw_mask = reg_tbl[i].rw_mask;
+		ro_mask = reg_tbl[i].ro_mask;
+
+		save_val = readl((u8 *) bp->regview + offset);
+
+		writel(0, (u8 *) bp->regview + offset);
+
+		val = readl((u8 *) bp->regview + offset);
+		if ((val & rw_mask) != 0) {
+			goto reg_test_err;
+		}
+
+		if ((val & ro_mask) != (save_val & ro_mask)) {
+			goto reg_test_err;
+		}
+
+		writel(0xffffffff, (u8 *) bp->regview + offset);
+
+		val = readl((u8 *) bp->regview + offset);
+		if ((val & rw_mask) != rw_mask) {
+			goto reg_test_err;
+		}
+
+		if ((val & ro_mask) != (save_val & ro_mask)) {
+			goto reg_test_err;
+		}
+
+		writel(save_val, (u8 *) bp->regview + offset);
+		continue;
+
+reg_test_err:
+		writel(save_val, (u8 *) bp->regview + offset);
+		ret = -ENODEV;
+		break;
+	}
+	return ret;
+}
+
+static int
+bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
+{
+	static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
+		0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
+	int i;
+
+	for (i = 0; i < sizeof(test_pattern) / 4; i++) {
+		u32 offset;
+
+		for (offset = 0; offset < size; offset += 4) {
+
+			REG_WR_IND(bp, start + offset, test_pattern[i]);
+
+			if (REG_RD_IND(bp, start + offset) !=
+				test_pattern[i]) {
+				return -ENODEV;
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+bnx2_test_memory(struct bnx2 *bp)
+{
+	int ret = 0;
+	int i;
+	static struct {
+		u32   offset;
+		u32   len;
+	} mem_tbl[] = {
+		{ 0x60000,  0x4000 },
+		{ 0xa0000,  0x4000 },
+		{ 0xe0000,  0x4000 },
+		{ 0x120000, 0x4000 },
+		{ 0x1a0000, 0x4000 },
+		{ 0x160000, 0x4000 },
+		{ 0xffffffff, 0    },
+	};
+
+	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
+		if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
+			mem_tbl[i].len)) != 0) {
+			return ret;
+		}
+	}
+	
+	return ret;
+}
+
+static int
+bnx2_test_loopback(struct bnx2 *bp)
+{
+	unsigned int pkt_size, num_pkts, i;
+	struct sk_buff *skb, *rx_skb;
+	unsigned char *packet;
+	u16 rx_start_idx, rx_idx, send_idx;
+	u32 send_bseq, val;
+	dma_addr_t map;
+	struct tx_bd *txbd;
+	struct sw_bd *rx_buf;
+	struct l2_fhdr *rx_hdr;
+	int ret = -ENODEV;
+
+	if (!netif_running(bp->dev))
+		return -ENODEV;
+
+	bp->loopback = MAC_LOOPBACK;
+	bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_DIAG);
+	bnx2_set_mac_loopback(bp);
+
+	pkt_size = 1514;
+	skb = dev_alloc_skb(pkt_size);
+	packet = skb_put(skb, pkt_size);
+	memcpy(packet, bp->mac_addr, 6);
+	memset(packet + 6, 0x0, 8);
+	for (i = 14; i < pkt_size; i++)
+		packet[i] = (unsigned char) (i & 0xff);
+
+	map = pci_map_single(bp->pdev, skb->data, pkt_size,
+		PCI_DMA_TODEVICE);
+
+	val = REG_RD(bp, BNX2_HC_COMMAND);
+	REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+	REG_RD(bp, BNX2_HC_COMMAND);
+
+	udelay(5);
+	rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
+
+	send_idx = 0;
+	send_bseq = 0;
+	num_pkts = 0;
+
+	txbd = &bp->tx_desc_ring[send_idx];
+
+	txbd->tx_bd_haddr_hi = (u64) map >> 32;
+	txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
+	txbd->tx_bd_mss_nbytes = pkt_size;
+	txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
+
+	num_pkts++;
+	send_idx = NEXT_TX_BD(send_idx);
+
+	send_bseq += pkt_size;
+
+	REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, send_idx);
+	REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, send_bseq);
+
+
+	udelay(100);
+
+	val = REG_RD(bp, BNX2_HC_COMMAND);
+	REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+	REG_RD(bp, BNX2_HC_COMMAND);
+
+	udelay(5);
+
+	pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
+	dev_kfree_skb_irq(skb);
+
+	if (bp->status_blk->status_tx_quick_consumer_index0 != send_idx) {
+		goto loopback_test_done;
+	}
+
+	rx_idx = bp->status_blk->status_rx_quick_consumer_index0;
+	if (rx_idx != rx_start_idx + num_pkts) {
+		goto loopback_test_done;
+	}
+
+	rx_buf = &bp->rx_buf_ring[rx_start_idx];
+	rx_skb = rx_buf->skb;
+
+	rx_hdr = (struct l2_fhdr *) rx_skb->data;
+	skb_reserve(rx_skb, bp->rx_offset);
+
+	pci_dma_sync_single_for_cpu(bp->pdev,
+		pci_unmap_addr(rx_buf, mapping),
+		bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+
+	if (rx_hdr->l2_fhdr_errors &
+		(L2_FHDR_ERRORS_BAD_CRC |
+		L2_FHDR_ERRORS_PHY_DECODE |
+		L2_FHDR_ERRORS_ALIGNMENT |
+		L2_FHDR_ERRORS_TOO_SHORT |
+		L2_FHDR_ERRORS_GIANT_FRAME)) {
+
+		goto loopback_test_done;
+	}
+
+	if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
+		goto loopback_test_done;
+	}
+
+	for (i = 14; i < pkt_size; i++) {
+		if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
+			goto loopback_test_done;
+		}
+	}
+
+	ret = 0;
+
+loopback_test_done:
+	bp->loopback = 0;
+	return ret;
+}
+
+#define NVRAM_SIZE 0x200
+#define CRC32_RESIDUAL 0xdebb20e3
+
+static int
+bnx2_test_nvram(struct bnx2 *bp)
+{
+	u32 buf[NVRAM_SIZE / 4];
+	u8 *data = (u8 *) buf;
+	int rc = 0;
+	u32 magic, csum;
+
+	if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
+		goto test_nvram_done;
+
+        magic = be32_to_cpu(buf[0]);
+	if (magic != 0x669955aa) {
+		rc = -ENODEV;
+		goto test_nvram_done;
+	}
+
+	if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
+		goto test_nvram_done;
+
+	csum = ether_crc_le(0x100, data);
+	if (csum != CRC32_RESIDUAL) {
+		rc = -ENODEV;
+		goto test_nvram_done;
+	}
+
+	csum = ether_crc_le(0x100, data + 0x100);
+	if (csum != CRC32_RESIDUAL) {
+		rc = -ENODEV;
+	}
+
+test_nvram_done:
+	return rc;
+}
+
+static int
+bnx2_test_link(struct bnx2 *bp)
+{
+	u32 bmsr;
+
+	spin_lock_irq(&bp->phy_lock);
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	spin_unlock_irq(&bp->phy_lock);
+		
+	if (bmsr & BMSR_LSTATUS) {
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int
+bnx2_test_intr(struct bnx2 *bp)
+{
+	int i;
+	u32 val;
+	u16 status_idx;
+
+	if (!netif_running(bp->dev))
+		return -ENODEV;
+
+	status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
+
+	/* This register is not touched during run-time. */
+	val = REG_RD(bp, BNX2_HC_COMMAND);
+	REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW);
+	REG_RD(bp, BNX2_HC_COMMAND);
+
+	for (i = 0; i < 10; i++) {
+		if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
+			status_idx) {
+
+			break;
+		}
+
+		msleep_interruptible(10);
+	}
+	if (i < 10)
+		return 0;
+
+	return -ENODEV;
+}
+
+static void
+bnx2_timer(unsigned long data)
+{
+	struct bnx2 *bp = (struct bnx2 *) data;
+	u32 msg;
+
+	if (atomic_read(&bp->intr_sem) != 0)
+		goto bnx2_restart_timer;
+
+	msg = (u32) ++bp->fw_drv_pulse_wr_seq;
+	REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_PULSE_MB, msg);
+
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&bp->phy_lock, flags);
+		if (bp->serdes_an_pending) {
+			bp->serdes_an_pending--;
+		}
+		else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
+			u32 bmcr;
+
+			bnx2_read_phy(bp, MII_BMCR, &bmcr);
+
+			if (bmcr & BMCR_ANENABLE) {
+				u32 phy1, phy2;
+
+				bnx2_write_phy(bp, 0x1c, 0x7c00);
+				bnx2_read_phy(bp, 0x1c, &phy1);
+
+				bnx2_write_phy(bp, 0x17, 0x0f01);
+				bnx2_read_phy(bp, 0x15, &phy2);
+				bnx2_write_phy(bp, 0x17, 0x0f01);
+				bnx2_read_phy(bp, 0x15, &phy2);
+
+				if ((phy1 & 0x10) &&	/* SIGNAL DETECT */
+					!(phy2 & 0x20)) {	/* no CONFIG */
+
+					bmcr &= ~BMCR_ANENABLE;
+					bmcr |= BMCR_SPEED1000 |
+						BMCR_FULLDPLX;
+					bnx2_write_phy(bp, MII_BMCR, bmcr);
+					bp->phy_flags |=
+						PHY_PARALLEL_DETECT_FLAG;
+				}
+			}
+		}
+		else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
+			(bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
+			u32 phy2;
+
+			bnx2_write_phy(bp, 0x17, 0x0f01);
+			bnx2_read_phy(bp, 0x15, &phy2);
+			if (phy2 & 0x20) {
+				u32 bmcr;
+
+				bnx2_read_phy(bp, MII_BMCR, &bmcr);
+				bmcr |= BMCR_ANENABLE;
+				bnx2_write_phy(bp, MII_BMCR, bmcr);
+
+				bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+
+			}
+		}
+
+		spin_unlock_irqrestore(&bp->phy_lock, flags);
+	}
+
+bnx2_restart_timer:
+	bp->timer.expires = RUN_AT(bp->timer_interval);
+
+	add_timer(&bp->timer);
+}
+
+/* Called with rtnl_lock */
+static int
+bnx2_open(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+	int rc;
+
+	bnx2_set_power_state(bp, 0);
+	bnx2_disable_int(bp);
+
+	rc = bnx2_alloc_mem(bp);
+	if (rc)
+		return rc;
+
+	if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
+		(CHIP_ID(bp) != CHIP_ID_5706_A1) &&
+		!disable_msi) {
+
+		if (pci_enable_msi(bp->pdev) == 0) {
+			bp->flags |= USING_MSI_FLAG;
+			rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name,
+					dev);
+		}
+		else {
+			rc = request_irq(bp->pdev->irq, bnx2_interrupt,
+					SA_SHIRQ, dev->name, dev);
+		}
+	}
+	else {
+		rc = request_irq(bp->pdev->irq, bnx2_interrupt, SA_SHIRQ,
+				dev->name, dev);
+	}
+	if (rc) {
+		bnx2_free_mem(bp);
+		return rc;
+	}
+
+	rc = bnx2_init_nic(bp);
+
+	if (rc) {
+		free_irq(bp->pdev->irq, dev);
+		if (bp->flags & USING_MSI_FLAG) {
+			pci_disable_msi(bp->pdev);
+			bp->flags &= ~USING_MSI_FLAG;
+		}
+		bnx2_free_skbs(bp);
+		bnx2_free_mem(bp);
+		return rc;
+	}
+	
+	init_timer(&bp->timer);
+
+	bp->timer.expires = RUN_AT(bp->timer_interval);
+	bp->timer.data = (unsigned long) bp;
+	bp->timer.function = bnx2_timer;
+	add_timer(&bp->timer);
+
+	atomic_set(&bp->intr_sem, 0);
+
+	bnx2_enable_int(bp);
+
+	if (bp->flags & USING_MSI_FLAG) {
+		/* Test MSI to make sure it is working
+		 * If MSI test fails, go back to INTx mode
+		 */
+		if (bnx2_test_intr(bp) != 0) {
+			printk(KERN_WARNING PFX "%s: No interrupt was generated"
+			       " using MSI, switching to INTx mode. Please"
+			       " report this failure to the PCI maintainer"
+			       " and include system chipset information.\n",
+			       bp->dev->name);
+
+			bnx2_disable_int(bp);
+			free_irq(bp->pdev->irq, dev);
+			pci_disable_msi(bp->pdev);
+			bp->flags &= ~USING_MSI_FLAG;
+
+			rc = bnx2_init_nic(bp);
+
+			if (!rc) {
+				rc = request_irq(bp->pdev->irq, bnx2_interrupt,
+					SA_SHIRQ, dev->name, dev);
+			}
+			if (rc) {
+				bnx2_free_skbs(bp);
+				bnx2_free_mem(bp);
+				del_timer_sync(&bp->timer);
+				return rc;
+			}
+			bnx2_enable_int(bp);
+		}
+	}
+	if (bp->flags & USING_MSI_FLAG) {
+		printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
+	}
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static void
+bnx2_reset_task(void *data)
+{
+	struct bnx2 *bp = data;
+
+	bnx2_netif_stop(bp);
+
+	bnx2_init_nic(bp);
+
+	atomic_set(&bp->intr_sem, 1);
+	bnx2_netif_start(bp);
+}
+
+static void
+bnx2_tx_timeout(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+
+	/* This allows the netif to be shutdown gracefully before resetting */
+	schedule_work(&bp->reset_task);
+}
+
+#ifdef BCM_VLAN
+/* Called with rtnl_lock */
+static void
+bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
+{
+	struct bnx2 *bp = dev->priv;
+
+	bnx2_netif_stop(bp);
+
+	bp->vlgrp = vlgrp;
+	bnx2_set_rx_mode(dev);
+
+	bnx2_netif_start(bp);
+}
+
+/* Called with rtnl_lock */
+static void
+bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+	struct bnx2 *bp = dev->priv;
+
+	bnx2_netif_stop(bp);
+
+	if (bp->vlgrp)
+		bp->vlgrp->vlan_devices[vid] = NULL;
+	bnx2_set_rx_mode(dev);
+
+	bnx2_netif_start(bp);
+}
+#endif
+
+/* Called with dev->xmit_lock.
+ * hard_start_xmit is pseudo-lockless - a lock is only required when
+ * the tx queue is full. This way, we get the benefit of lockless
+ * operations most of the time without the complexities to handle
+ * netif_stop_queue/wake_queue race conditions.
+ */
+static int
+bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+	dma_addr_t mapping;
+	struct tx_bd *txbd;
+	struct sw_bd *tx_buf;
+	u32 len, vlan_tag_flags, last_frag, mss;
+	u16 prod, ring_prod;
+	int i;
+
+	if (unlikely(atomic_read(&bp->tx_avail_bd) <
+		(skb_shinfo(skb)->nr_frags + 1))) {
+
+		netif_stop_queue(dev);
+		printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
+			dev->name);
+
+		return NETDEV_TX_BUSY;
+	}
+	len = skb_headlen(skb);
+	prod = bp->tx_prod;
+	ring_prod = TX_RING_IDX(prod);
+
+	vlan_tag_flags = 0;
+	if (skb->ip_summed == CHECKSUM_HW) {
+		vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
+	}
+
+	if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
+		vlan_tag_flags |=
+			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
+	}
+#ifdef BCM_TSO 
+	if ((mss = skb_shinfo(skb)->tso_size) &&
+		(skb->len > (bp->dev->mtu + ETH_HLEN))) {
+		u32 tcp_opt_len, ip_tcp_len;
+
+		if (skb_header_cloned(skb) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return NETDEV_TX_OK;
+		}
+
+		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
+		vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
+
+		tcp_opt_len = 0;
+		if (skb->h.th->doff > 5) {
+			tcp_opt_len = (skb->h.th->doff - 5) << 2;
+		}
+		ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
+
+		skb->nh.iph->check = 0;
+		skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+		skb->h.th->check =
+			~csum_tcpudp_magic(skb->nh.iph->saddr,
+					    skb->nh.iph->daddr,
+					    0, IPPROTO_TCP, 0);
+
+		if (tcp_opt_len || (skb->nh.iph->ihl > 5)) {
+			vlan_tag_flags |= ((skb->nh.iph->ihl - 5) +
+				(tcp_opt_len >> 2)) << 8;
+		}
+	}
+	else
+#endif
+	{
+		mss = 0;
+	}
+
+	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	
+	tx_buf = &bp->tx_buf_ring[ring_prod];
+	tx_buf->skb = skb;
+	pci_unmap_addr_set(tx_buf, mapping, mapping);
+
+	txbd = &bp->tx_desc_ring[ring_prod];
+
+	txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
+	txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
+	txbd->tx_bd_mss_nbytes = len | (mss << 16);
+	txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
+
+	last_frag = skb_shinfo(skb)->nr_frags;
+
+	for (i = 0; i < last_frag; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		prod = NEXT_TX_BD(prod);
+		ring_prod = TX_RING_IDX(prod);
+		txbd = &bp->tx_desc_ring[ring_prod];
+
+		len = frag->size;
+		mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
+			len, PCI_DMA_TODEVICE);
+		pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
+				mapping, mapping);
+
+		txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
+		txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
+		txbd->tx_bd_mss_nbytes = len | (mss << 16);
+		txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
+
+	}
+	txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
+
+	prod = NEXT_TX_BD(prod);
+	bp->tx_prod_bseq += skb->len;
+
+	atomic_sub(last_frag + 1, &bp->tx_avail_bd);
+
+	REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod);
+	REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
+
+	mmiowb();
+
+	bp->tx_prod = prod;
+	dev->trans_start = jiffies;
+
+	if (unlikely(atomic_read(&bp->tx_avail_bd) <= MAX_SKB_FRAGS)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&bp->tx_lock, flags);
+		if (atomic_read(&bp->tx_avail_bd) <= MAX_SKB_FRAGS) {
+			netif_stop_queue(dev);
+
+			if (atomic_read(&bp->tx_avail_bd) > MAX_SKB_FRAGS)
+				netif_wake_queue(dev);
+		}
+		spin_unlock_irqrestore(&bp->tx_lock, flags);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+/* Called with rtnl_lock */
+static int
+bnx2_close(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+	u32 reset_code;
+
+	flush_scheduled_work();
+	bnx2_netif_stop(bp);
+	del_timer_sync(&bp->timer);
+	if (bp->wol)
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
+	else
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
+	bnx2_reset_chip(bp, reset_code);
+	free_irq(bp->pdev->irq, dev);
+	if (bp->flags & USING_MSI_FLAG) {
+		pci_disable_msi(bp->pdev);
+		bp->flags &= ~USING_MSI_FLAG;
+	}
+	bnx2_free_skbs(bp);
+	bnx2_free_mem(bp);
+	bp->link_up = 0;
+	netif_carrier_off(bp->dev);
+	bnx2_set_power_state(bp, 3);
+	return 0;
+}
+
+#define GET_NET_STATS64(ctr)					\
+	(unsigned long) ((unsigned long) (ctr##_hi) << 32) +	\
+	(unsigned long) (ctr##_lo)
+
+#define GET_NET_STATS32(ctr)		\
+	(ctr##_lo)
+
+#if (BITS_PER_LONG == 64)
+#define GET_NET_STATS	GET_NET_STATS64
+#else
+#define GET_NET_STATS	GET_NET_STATS32
+#endif
+
+static struct net_device_stats *
+bnx2_get_stats(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+	struct statistics_block *stats_blk = bp->stats_blk;
+	struct net_device_stats *net_stats = &bp->net_stats;
+
+	if (bp->stats_blk == NULL) {
+		return net_stats;
+	}
+	net_stats->rx_packets =
+		GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
+		GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
+		GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
+
+	net_stats->tx_packets =
+		GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
+		GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
+		GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
+
+	net_stats->rx_bytes =
+		GET_NET_STATS(stats_blk->stat_IfHCInOctets);
+
+	net_stats->tx_bytes =
+		GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
+
+	net_stats->multicast = 
+		GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
+
+	net_stats->collisions = 
+		(unsigned long) stats_blk->stat_EtherStatsCollisions;
+
+	net_stats->rx_length_errors = 
+		(unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
+		stats_blk->stat_EtherStatsOverrsizePkts);
+
+	net_stats->rx_over_errors = 
+		(unsigned long) stats_blk->stat_IfInMBUFDiscards;
+
+	net_stats->rx_frame_errors = 
+		(unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
+
+	net_stats->rx_crc_errors = 
+		(unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
+
+	net_stats->rx_errors = net_stats->rx_length_errors +
+		net_stats->rx_over_errors + net_stats->rx_frame_errors +
+		net_stats->rx_crc_errors;
+
+	net_stats->tx_aborted_errors =
+    		(unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
+		stats_blk->stat_Dot3StatsLateCollisions);
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5706)
+		net_stats->tx_carrier_errors = 0;
+	else {
+		net_stats->tx_carrier_errors =
+			(unsigned long)
+			stats_blk->stat_Dot3StatsCarrierSenseErrors;
+	}
+
+	net_stats->tx_errors =
+    		(unsigned long) 
+		stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
+		+
+		net_stats->tx_aborted_errors +
+		net_stats->tx_carrier_errors;
+
+	return net_stats;
+}
+
+/* All ethtool functions called with rtnl_lock */
+
+static int
+bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	cmd->supported = SUPPORTED_Autoneg;
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		cmd->supported |= SUPPORTED_1000baseT_Full |
+			SUPPORTED_FIBRE;
+
+		cmd->port = PORT_FIBRE;
+	}
+	else {
+		cmd->supported |= SUPPORTED_10baseT_Half |
+			SUPPORTED_10baseT_Full |
+			SUPPORTED_100baseT_Half |
+			SUPPORTED_100baseT_Full |
+			SUPPORTED_1000baseT_Full |
+			SUPPORTED_TP;
+
+		cmd->port = PORT_TP;
+	}
+
+	cmd->advertising = bp->advertising;
+
+	if (bp->autoneg & AUTONEG_SPEED) {
+		cmd->autoneg = AUTONEG_ENABLE;
+	}
+	else {
+		cmd->autoneg = AUTONEG_DISABLE;
+	}
+
+	if (netif_carrier_ok(dev)) {
+		cmd->speed = bp->line_speed;
+		cmd->duplex = bp->duplex;
+	}
+	else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->phy_address = bp->phy_addr;
+
+	return 0;
+}
+  
+static int
+bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+  	struct bnx2 *bp = dev->priv;
+	u8 autoneg = bp->autoneg;
+	u8 req_duplex = bp->req_duplex;
+	u16 req_line_speed = bp->req_line_speed;
+	u32 advertising = bp->advertising;
+
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		autoneg |= AUTONEG_SPEED;
+
+		cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED; 
+
+		/* allow advertising 1 speed */
+		if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
+			(cmd->advertising == ADVERTISED_10baseT_Full) ||
+			(cmd->advertising == ADVERTISED_100baseT_Half) ||
+			(cmd->advertising == ADVERTISED_100baseT_Full)) {
+
+			if (bp->phy_flags & PHY_SERDES_FLAG)
+				return -EINVAL;
+
+			advertising = cmd->advertising;
+
+		}
+		else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+			advertising = cmd->advertising;
+		}
+		else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
+			return -EINVAL;
+		}
+		else {
+			if (bp->phy_flags & PHY_SERDES_FLAG) {
+				advertising = ETHTOOL_ALL_FIBRE_SPEED;
+			}
+			else {
+				advertising = ETHTOOL_ALL_COPPER_SPEED;
+			}
+		}
+		advertising |= ADVERTISED_Autoneg;
+	}
+	else {
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			if ((cmd->speed != SPEED_1000) ||
+				(cmd->duplex != DUPLEX_FULL)) {
+				return -EINVAL;
+			}
+		}
+		else if (cmd->speed == SPEED_1000) {
+			return -EINVAL;
+		}
+		autoneg &= ~AUTONEG_SPEED;
+		req_line_speed = cmd->speed;
+		req_duplex = cmd->duplex;
+		advertising = 0;
+	}
+
+	bp->autoneg = autoneg;
+	bp->advertising = advertising;
+	bp->req_line_speed = req_line_speed;
+	bp->req_duplex = req_duplex;
+
+	spin_lock_irq(&bp->phy_lock);
+
+	bnx2_setup_phy(bp);
+
+	spin_unlock_irq(&bp->phy_lock);
+
+	return 0;
+}
+
+static void
+bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+	strcpy(info->bus_info, pci_name(bp->pdev));
+	info->fw_version[0] = ((bp->fw_ver & 0xff000000) >> 24) + '0';
+	info->fw_version[2] = ((bp->fw_ver & 0xff0000) >> 16) + '0';
+	info->fw_version[4] = ((bp->fw_ver & 0xff00) >> 8) + '0';
+	info->fw_version[6] = (bp->fw_ver & 0xff) + '0';
+	info->fw_version[1] = info->fw_version[3] = info->fw_version[5] = '.';
+	info->fw_version[7] = 0;
+}
+
+static void
+bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	if (bp->flags & NO_WOL_FLAG) {
+		wol->supported = 0;
+		wol->wolopts = 0;
+	}
+	else {
+		wol->supported = WAKE_MAGIC;
+		if (bp->wol)
+			wol->wolopts = WAKE_MAGIC;
+		else
+			wol->wolopts = 0;
+	}
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int
+bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+
+	if (wol->wolopts & WAKE_MAGIC) {
+		if (bp->flags & NO_WOL_FLAG)
+			return -EINVAL;
+
+		bp->wol = 1;
+	}
+	else {
+		bp->wol = 0;
+	}
+	return 0;
+}
+
+static int
+bnx2_nway_reset(struct net_device *dev)
+{
+  	struct bnx2 *bp = dev->priv;
+	u32 bmcr;
+
+	if (!(bp->autoneg & AUTONEG_SPEED)) {
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&bp->phy_lock);
+
+	/* Force a link down visible on the other side */
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+		spin_unlock_irq(&bp->phy_lock);
+
+		msleep(20);
+
+		spin_lock_irq(&bp->phy_lock);
+		if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+			bp->serdes_an_pending = SERDES_AN_TIMEOUT /
+				bp->timer_interval;
+		}
+	}
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bmcr &= ~BMCR_LOOPBACK;
+	bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
+
+	spin_unlock_irq(&bp->phy_lock);
+
+	return 0;
+}
+
+static int
+bnx2_get_eeprom_len(struct net_device *dev)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	if (bp->flash_info == 0)
+		return 0;
+
+	return (int) bp->flash_info->total_size;
+}
+
+static int
+bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+		u8 *eebuf)
+{
+  	struct bnx2 *bp = dev->priv;
+	int rc;
+
+	if (eeprom->offset > bp->flash_info->total_size)
+		return -EINVAL;
+
+	if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
+		eeprom->len = bp->flash_info->total_size - eeprom->offset;
+
+	rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+
+static int
+bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+		u8 *eebuf)
+{
+  	struct bnx2 *bp = dev->priv;
+	int rc;
+
+	if (eeprom->offset > bp->flash_info->total_size)
+		return -EINVAL;
+
+	if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
+		eeprom->len = bp->flash_info->total_size - eeprom->offset;
+
+	rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+
+static int
+bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	memset(coal, 0, sizeof(struct ethtool_coalesce));
+
+	coal->rx_coalesce_usecs = bp->rx_ticks;
+	coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
+	coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
+	coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
+
+	coal->tx_coalesce_usecs = bp->tx_ticks;
+	coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
+	coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
+	coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
+
+	coal->stats_block_coalesce_usecs = bp->stats_ticks;
+
+	return 0;
+}
+
+static int
+bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
+	if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
+
+	bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames; 
+	if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
+
+	bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
+	if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
+
+	bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
+	if (bp->rx_quick_cons_trip_int > 0xff)
+		bp->rx_quick_cons_trip_int = 0xff;
+
+	bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
+	if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
+
+	bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
+	if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
+
+	bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
+	if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
+
+	bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
+	if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
+		0xff;
+
+	bp->stats_ticks = coal->stats_block_coalesce_usecs;
+	if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
+	bp->stats_ticks &= 0xffff00;
+
+	if (netif_running(bp->dev)) {
+		bnx2_netif_stop(bp);
+		bnx2_init_nic(bp);
+		bnx2_netif_start(bp);
+	}
+
+	return 0;
+}
+
+static void
+bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	ering->rx_max_pending = MAX_RX_DESC_CNT;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = 0;
+
+	ering->rx_pending = bp->rx_ring_size;
+	ering->rx_mini_pending = 0;
+	ering->rx_jumbo_pending = 0;
+
+	ering->tx_max_pending = MAX_TX_DESC_CNT;
+	ering->tx_pending = bp->tx_ring_size;
+}
+
+static int
+bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	if ((ering->rx_pending > MAX_RX_DESC_CNT) ||
+		(ering->tx_pending > MAX_TX_DESC_CNT) ||
+		(ering->tx_pending <= MAX_SKB_FRAGS)) {
+
+		return -EINVAL;
+	}
+	bp->rx_ring_size = ering->rx_pending;
+	bp->tx_ring_size = ering->tx_pending;
+
+	if (netif_running(bp->dev)) {
+		bnx2_netif_stop(bp);
+		bnx2_init_nic(bp);
+		bnx2_netif_start(bp);
+	}
+
+	return 0;
+}
+
+static void
+bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
+	epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
+	epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
+}
+
+static int
+bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	bp->req_flow_ctrl = 0;
+	if (epause->rx_pause)
+		bp->req_flow_ctrl |= FLOW_CTRL_RX;
+	if (epause->tx_pause)
+		bp->req_flow_ctrl |= FLOW_CTRL_TX;
+
+	if (epause->autoneg) {
+		bp->autoneg |= AUTONEG_FLOW_CTRL;
+	}
+	else {
+		bp->autoneg &= ~AUTONEG_FLOW_CTRL;
+	}
+
+	spin_lock_irq(&bp->phy_lock);
+
+	bnx2_setup_phy(bp);
+
+	spin_unlock_irq(&bp->phy_lock);
+
+	return 0;
+}
+
+static u32
+bnx2_get_rx_csum(struct net_device *dev)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	return bp->rx_csum;
+}
+
+static int
+bnx2_set_rx_csum(struct net_device *dev, u32 data)
+{
+  	struct bnx2 *bp = dev->priv;
+
+	bp->rx_csum = data;
+	return 0;
+}
+
+#define BNX2_NUM_STATS 45
+
+struct {
+	char string[ETH_GSTRING_LEN];
+} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
+	{ "rx_bytes" },
+	{ "rx_error_bytes" },
+	{ "tx_bytes" },
+	{ "tx_error_bytes" },
+	{ "rx_ucast_packets" },
+	{ "rx_mcast_packets" },
+	{ "rx_bcast_packets" },
+	{ "tx_ucast_packets" },
+	{ "tx_mcast_packets" },
+	{ "tx_bcast_packets" },
+	{ "tx_mac_errors" },
+	{ "tx_carrier_errors" },
+	{ "rx_crc_errors" },
+	{ "rx_align_errors" },
+	{ "tx_single_collisions" },
+	{ "tx_multi_collisions" },
+	{ "tx_deferred" },
+	{ "tx_excess_collisions" },
+	{ "tx_late_collisions" },
+	{ "tx_total_collisions" },
+	{ "rx_fragments" },
+	{ "rx_jabbers" },
+	{ "rx_undersize_packets" },
+	{ "rx_oversize_packets" },
+	{ "rx_64_byte_packets" },
+	{ "rx_65_to_127_byte_packets" },
+	{ "rx_128_to_255_byte_packets" },
+	{ "rx_256_to_511_byte_packets" },
+	{ "rx_512_to_1023_byte_packets" },
+	{ "rx_1024_to_1522_byte_packets" },
+	{ "rx_1523_to_9022_byte_packets" },
+	{ "tx_64_byte_packets" },
+	{ "tx_65_to_127_byte_packets" },
+	{ "tx_128_to_255_byte_packets" },
+	{ "tx_256_to_511_byte_packets" },
+	{ "tx_512_to_1023_byte_packets" },
+	{ "tx_1024_to_1522_byte_packets" },
+	{ "tx_1523_to_9022_byte_packets" },
+	{ "rx_xon_frames" },
+	{ "rx_xoff_frames" },
+	{ "tx_xon_frames" },
+	{ "tx_xoff_frames" },
+	{ "rx_mac_ctrl_frames" },
+	{ "rx_filtered_packets" },
+	{ "rx_discards" },
+};
+
+#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
+
+unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
+    STATS_OFFSET32(stat_IfHCInOctets_hi),
+    STATS_OFFSET32(stat_IfHCInBadOctets_hi),
+    STATS_OFFSET32(stat_IfHCOutOctets_hi),
+    STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
+    STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
+    STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
+    STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
+    STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
+    STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
+    STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
+    STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
+    STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),                 
+    STATS_OFFSET32(stat_Dot3StatsFCSErrors),                          
+    STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),                    
+    STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),              
+    STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),            
+    STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),              
+    STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),                
+    STATS_OFFSET32(stat_Dot3StatsLateCollisions),                     
+    STATS_OFFSET32(stat_EtherStatsCollisions),                        
+    STATS_OFFSET32(stat_EtherStatsFragments),                         
+    STATS_OFFSET32(stat_EtherStatsJabbers),                           
+    STATS_OFFSET32(stat_EtherStatsUndersizePkts),                     
+    STATS_OFFSET32(stat_EtherStatsOverrsizePkts),                     
+    STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),                    
+    STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),         
+    STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),        
+    STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),        
+    STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),       
+    STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),      
+    STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),      
+    STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),                    
+    STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),         
+    STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),        
+    STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),        
+    STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),       
+    STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),      
+    STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),      
+    STATS_OFFSET32(stat_XonPauseFramesReceived),                      
+    STATS_OFFSET32(stat_XoffPauseFramesReceived),                     
+    STATS_OFFSET32(stat_OutXonSent),                                  
+    STATS_OFFSET32(stat_OutXoffSent),                                 
+    STATS_OFFSET32(stat_MacControlFramesReceived),                    
+    STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),                  
+    STATS_OFFSET32(stat_IfInMBUFDiscards),                            
+};
+
+/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
+ * skipped because of errata.
+ */               
+u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
+	8,0,8,8,8,8,8,8,8,8,
+	4,0,4,4,4,4,4,4,4,4,
+	4,4,4,4,4,4,4,4,4,4,
+	4,4,4,4,4,4,4,4,4,4,
+	4,4,4,4,4,
+};
+
+#define BNX2_NUM_TESTS 6
+
+struct {
+	char string[ETH_GSTRING_LEN];
+} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
+	{ "register_test (offline)" },
+	{ "memory_test (offline)" },
+	{ "loopback_test (offline)" },
+	{ "nvram_test (online)" },
+	{ "interrupt_test (online)" },
+	{ "link_test (online)" },
+};
+
+static int
+bnx2_self_test_count(struct net_device *dev)
+{
+	return BNX2_NUM_TESTS;
+}
+
+static void
+bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
+{
+	struct bnx2 *bp = dev->priv;
+
+	memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
+	if (etest->flags & ETH_TEST_FL_OFFLINE) {
+		bnx2_netif_stop(bp);
+		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
+		bnx2_free_skbs(bp);
+
+		if (bnx2_test_registers(bp) != 0) {
+			buf[0] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+		if (bnx2_test_memory(bp) != 0) {
+			buf[1] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+		if (bnx2_test_loopback(bp) != 0) {
+			buf[2] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+
+		if (!netif_running(bp->dev)) {
+			bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+		}
+		else {
+			bnx2_init_nic(bp);
+			bnx2_netif_start(bp);
+		}
+
+		/* wait for link up */
+		msleep_interruptible(3000);
+		if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG))
+			msleep_interruptible(4000);
+	}
+
+	if (bnx2_test_nvram(bp) != 0) {
+		buf[3] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+	}
+	if (bnx2_test_intr(bp) != 0) {
+		buf[4] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+	}
+
+	if (bnx2_test_link(bp) != 0) {
+		buf[5] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+
+	}
+}
+
+static void
+bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, bnx2_stats_str_arr,
+			sizeof(bnx2_stats_str_arr));
+		break;
+	case ETH_SS_TEST:
+		memcpy(buf, bnx2_tests_str_arr,
+			sizeof(bnx2_tests_str_arr));
+		break;
+	}
+}
+
+static int
+bnx2_get_stats_count(struct net_device *dev)
+{
+	return BNX2_NUM_STATS;
+}
+
+static void
+bnx2_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *buf)
+{
+	struct bnx2 *bp = dev->priv;
+	int i;
+	u32 *hw_stats = (u32 *) bp->stats_blk;
+	u8 *stats_len_arr = 0;
+
+	if (hw_stats == NULL) {
+		memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
+		return;
+	}
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5706)
+		stats_len_arr = bnx2_5706_stats_len_arr;
+
+	for (i = 0; i < BNX2_NUM_STATS; i++) {
+		if (stats_len_arr[i] == 0) {
+			/* skip this counter */
+			buf[i] = 0;
+			continue;
+		}
+		if (stats_len_arr[i] == 4) {
+			/* 4-byte counter */
+			buf[i] = (u64)
+				*(hw_stats + bnx2_stats_offset_arr[i]);
+			continue;
+		}
+		/* 8-byte counter */
+		buf[i] = (((u64) *(hw_stats +
+					bnx2_stats_offset_arr[i])) << 32) +
+				*(hw_stats + bnx2_stats_offset_arr[i] + 1);
+	}
+}
+
+static int
+bnx2_phys_id(struct net_device *dev, u32 data)
+{
+	struct bnx2 *bp = dev->priv;
+	int i;
+	u32 save;
+
+	if (data == 0)
+		data = 2;
+
+	save = REG_RD(bp, BNX2_MISC_CFG);
+	REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
+
+	for (i = 0; i < (data * 2); i++) {
+		if ((i % 2) == 0) {
+			REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
+		}
+		else {
+			REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
+				BNX2_EMAC_LED_1000MB_OVERRIDE |
+				BNX2_EMAC_LED_100MB_OVERRIDE |
+				BNX2_EMAC_LED_10MB_OVERRIDE |
+				BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
+				BNX2_EMAC_LED_TRAFFIC);
+		}
+		msleep_interruptible(500);
+		if (signal_pending(current))
+			break;
+	}
+	REG_WR(bp, BNX2_EMAC_LED, 0);
+	REG_WR(bp, BNX2_MISC_CFG, save);
+	return 0;
+}
+
+static struct ethtool_ops bnx2_ethtool_ops = {
+	.get_settings		= bnx2_get_settings,
+	.set_settings		= bnx2_set_settings,
+	.get_drvinfo		= bnx2_get_drvinfo,
+	.get_wol		= bnx2_get_wol,
+	.set_wol		= bnx2_set_wol,
+	.nway_reset		= bnx2_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= bnx2_get_eeprom_len,
+	.get_eeprom		= bnx2_get_eeprom,
+	.set_eeprom		= bnx2_set_eeprom,
+	.get_coalesce		= bnx2_get_coalesce,
+	.set_coalesce		= bnx2_set_coalesce,
+	.get_ringparam		= bnx2_get_ringparam,
+	.set_ringparam		= bnx2_set_ringparam,
+	.get_pauseparam		= bnx2_get_pauseparam,
+	.set_pauseparam		= bnx2_set_pauseparam,
+	.get_rx_csum		= bnx2_get_rx_csum,
+	.set_rx_csum		= bnx2_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+#ifdef BCM_TSO
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= ethtool_op_set_tso,
+#endif
+	.self_test_count	= bnx2_self_test_count,
+	.self_test		= bnx2_self_test,
+	.get_strings		= bnx2_get_strings,
+	.phys_id		= bnx2_phys_id,
+	.get_stats_count	= bnx2_get_stats_count,
+	.get_ethtool_stats	= bnx2_get_ethtool_stats,
+};
+
+/* Called with rtnl_lock */
+static int
+bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct bnx2 *bp = dev->priv;
+	int err;
+
+	switch(cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = bp->phy_addr;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u32 mii_regval;
+
+		spin_lock_irq(&bp->phy_lock);
+		err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
+		spin_unlock_irq(&bp->phy_lock);
+
+		data->val_out = mii_regval;
+
+		return err;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_irq(&bp->phy_lock);
+		err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
+		spin_unlock_irq(&bp->phy_lock);
+
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	}
+	return -EOPNOTSUPP;
+}
+
+/* Called with rtnl_lock */
+static int
+bnx2_change_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct bnx2 *bp = dev->priv;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	if (netif_running(dev))
+		bnx2_set_mac_addr(bp);
+
+	return 0;
+}
+
+/* Called with rtnl_lock */
+static int
+bnx2_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct bnx2 *bp = dev->priv;
+
+	if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
+		((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	if (netif_running(dev)) {
+		bnx2_netif_stop(bp);
+
+		bnx2_init_nic(bp);
+
+		bnx2_netif_start(bp);
+	}
+	return 0;
+}
+
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+static void
+poll_bnx2(struct net_device *dev)
+{
+	struct bnx2 *bp = dev->priv;
+
+	disable_irq(bp->pdev->irq);
+	bnx2_interrupt(bp->pdev->irq, dev, NULL);
+	enable_irq(bp->pdev->irq);
+}
+#endif
+
+static int __devinit
+bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+{
+	struct bnx2 *bp;
+	unsigned long mem_len;
+	int rc;
+	u32 reg;
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	bp = dev->priv;
+
+	bp->flags = 0;
+	bp->phy_flags = 0;
+
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+		goto err_out;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find PCI device base address, "
+		       "aborting.\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	rc = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
+		goto err_out_disable;
+	}
+
+	pci_set_master(pdev);
+
+	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (bp->pm_cap == 0) {
+		printk(KERN_ERR PFX "Cannot find power management capability, "
+			       "aborting.\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
+	if (bp->pcix_cap == 0) {
+		printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+		bp->flags |= USING_DAC_FLAG;
+		if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+			printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
+			       "failed, aborting.\n");
+			rc = -EIO;
+			goto err_out_release;
+		}
+	}
+	else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
+		printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	bp->dev = dev;
+	bp->pdev = pdev;
+
+	spin_lock_init(&bp->phy_lock);
+	spin_lock_init(&bp->tx_lock);
+	INIT_WORK(&bp->reset_task, bnx2_reset_task, bp);
+
+	dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
+	mem_len = MB_GET_CID_ADDR(17);
+	dev->mem_end = dev->mem_start + mem_len;
+	dev->irq = pdev->irq;
+
+	bp->regview = ioremap_nocache(dev->base_addr, mem_len);
+
+	if (!bp->regview) {
+		printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
+		rc = -ENOMEM;
+		goto err_out_release;
+	}
+
+	/* Configure byte swap and enable write to the reg_window registers.
+	 * Rely on CPU to do target byte swapping on big endian systems
+	 * The chip's target access swapping will not swap all accesses
+	 */
+	pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
+			       BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
+			       BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
+
+	bnx2_set_power_state(bp, 0);
+
+	bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
+
+	bp->phy_addr = 1;
+
+	/* Get bus information. */
+	reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
+	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
+		u32 clkreg;
+
+		bp->flags |= PCIX_FLAG;
+
+		clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
+		
+		clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
+		switch (clkreg) {
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
+			bp->bus_speed_mhz = 133;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
+			bp->bus_speed_mhz = 100;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
+			bp->bus_speed_mhz = 66;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
+			bp->bus_speed_mhz = 50;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
+			bp->bus_speed_mhz = 33;
+			break;
+		}
+	}
+	else {
+		if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
+			bp->bus_speed_mhz = 66;
+		else
+			bp->bus_speed_mhz = 33;
+	}
+
+	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
+		bp->flags |= PCI_32BIT_FLAG;
+
+	/* 5706A0 may falsely detect SERR and PERR. */
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		reg = REG_RD(bp, PCI_COMMAND);
+		reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+		REG_WR(bp, PCI_COMMAND, reg);
+	}
+	else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
+		!(bp->flags & PCIX_FLAG)) {
+
+		printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
+		       "aborting.\n");
+		goto err_out_unmap;
+	}
+
+	bnx2_init_nvram(bp);
+
+	/* Get the permanent MAC address.  First we need to make sure the
+	 * firmware is actually running.
+	 */
+	reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DEV_INFO_SIGNATURE);
+
+	if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
+	    BNX2_DEV_INFO_SIGNATURE_MAGIC) {
+		printk(KERN_ERR PFX "Firmware not running, aborting.\n");
+		rc = -ENODEV;
+		goto err_out_unmap;
+	}
+
+	bp->fw_ver = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
+				BNX2_DEV_INFO_BC_REV);
+
+	reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_UPPER);
+	bp->mac_addr[0] = (u8) (reg >> 8);
+	bp->mac_addr[1] = (u8) reg;
+
+	reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_LOWER);
+	bp->mac_addr[2] = (u8) (reg >> 24);
+	bp->mac_addr[3] = (u8) (reg >> 16);
+	bp->mac_addr[4] = (u8) (reg >> 8);
+	bp->mac_addr[5] = (u8) reg;
+
+	bp->tx_ring_size = MAX_TX_DESC_CNT;
+	bp->rx_ring_size = 100;
+
+	bp->rx_csum = 1;
+
+	bp->rx_offset = sizeof(struct l2_fhdr) + 2;
+
+	bp->tx_quick_cons_trip_int = 20;
+	bp->tx_quick_cons_trip = 20;
+	bp->tx_ticks_int = 80;
+	bp->tx_ticks = 80;
+		
+	bp->rx_quick_cons_trip_int = 6;
+	bp->rx_quick_cons_trip = 6;
+	bp->rx_ticks_int = 18;
+	bp->rx_ticks = 18;
+
+	bp->stats_ticks = 1000000 & 0xffff00;
+
+	bp->timer_interval =  HZ;
+
+	/* Disable WOL support if we are running on a SERDES chip. */
+	if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
+		bp->phy_flags |= PHY_SERDES_FLAG;
+		bp->flags |= NO_WOL_FLAG;
+	}
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		bp->tx_quick_cons_trip_int =
+			bp->tx_quick_cons_trip;
+		bp->tx_ticks_int = bp->tx_ticks;
+		bp->rx_quick_cons_trip_int =
+			bp->rx_quick_cons_trip;
+		bp->rx_ticks_int = bp->rx_ticks;
+		bp->comp_prod_trip_int = bp->comp_prod_trip;
+		bp->com_ticks_int = bp->com_ticks;
+		bp->cmd_ticks_int = bp->cmd_ticks;
+	}
+
+	bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
+	bp->req_line_speed = 0;
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
+	}
+	else {
+		bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
+	}
+
+	bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
+
+	return 0;
+
+err_out_unmap:
+	if (bp->regview) {
+		iounmap(bp->regview);
+	}
+
+err_out_release:
+	pci_release_regions(pdev);
+
+err_out_disable:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+err_out:
+	return rc;
+}
+
+static int __devinit
+bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int version_printed = 0;
+	struct net_device *dev = NULL;
+	struct bnx2 *bp;
+	int rc, i;
+
+	if (version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	/* dev zeroed in init_etherdev */
+	dev = alloc_etherdev(sizeof(*bp));
+
+	if (!dev)
+		return -ENOMEM;
+
+	rc = bnx2_init_board(pdev, dev);
+	if (rc < 0) {
+		free_netdev(dev);
+		return rc;
+	}
+
+	dev->open = bnx2_open;
+	dev->hard_start_xmit = bnx2_start_xmit;
+	dev->stop = bnx2_close;
+	dev->get_stats = bnx2_get_stats;
+	dev->set_multicast_list = bnx2_set_rx_mode;
+	dev->do_ioctl = bnx2_ioctl;
+	dev->set_mac_address = bnx2_change_mac_addr;
+	dev->change_mtu = bnx2_change_mtu;
+	dev->tx_timeout = bnx2_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef BCM_VLAN
+	dev->vlan_rx_register = bnx2_vlan_rx_register;
+	dev->vlan_rx_kill_vid = bnx2_vlan_rx_kill_vid;
+#endif
+	dev->poll = bnx2_poll;
+	dev->ethtool_ops = &bnx2_ethtool_ops;
+	dev->weight = 64;
+
+	bp = dev->priv;
+
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+	dev->poll_controller = poll_bnx2;
+#endif
+
+	if ((rc = register_netdev(dev))) {
+		printk(KERN_ERR PFX "Cannot register net device\n");
+		if (bp->regview)
+			iounmap(bp->regview);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+		free_netdev(dev);
+		return rc;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	memcpy(dev->dev_addr, bp->mac_addr, 6);
+	bp->name = board_info[ent->driver_data].name,
+	printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
+		"IRQ %d, ",
+		dev->name,
+		bp->name,
+		((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
+		((CHIP_ID(bp) & 0x0ff0) >> 4),
+		((bp->flags & PCIX_FLAG) ? "-X" : ""),
+		((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
+		bp->bus_speed_mhz,
+		dev->base_addr,
+		bp->pdev->irq);
+
+	printk("node addr ");
+	for (i = 0; i < 6; i++)
+		printk("%2.2x", dev->dev_addr[i]);
+	printk("\n");
+
+	dev->features |= NETIF_F_SG;
+	if (bp->flags & USING_DAC_FLAG)
+		dev->features |= NETIF_F_HIGHDMA;
+	dev->features |= NETIF_F_IP_CSUM;
+#ifdef BCM_VLAN
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+#endif
+#ifdef BCM_TSO
+	dev->features |= NETIF_F_TSO;
+#endif
+
+	netif_carrier_off(bp->dev);
+
+	return 0;
+}
+
+static void __devexit
+bnx2_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2 *bp = dev->priv;
+
+	unregister_netdev(dev);
+
+	if (bp->regview)
+		iounmap(bp->regview);
+
+	free_netdev(dev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int
+bnx2_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2 *bp = dev->priv;
+	u32 reset_code;
+
+	if (!netif_running(dev))
+		return 0;
+
+	bnx2_netif_stop(bp);
+	netif_device_detach(dev);
+	del_timer_sync(&bp->timer);
+	if (bp->wol)
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
+	else
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
+	bnx2_reset_chip(bp, reset_code);
+	bnx2_free_skbs(bp);
+	bnx2_set_power_state(bp, state);
+	return 0;
+}
+
+static int
+bnx2_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2 *bp = dev->priv;
+
+	if (!netif_running(dev))
+		return 0;
+
+	bnx2_set_power_state(bp, 0);
+	netif_device_attach(dev);
+	bnx2_init_nic(bp);
+	bnx2_netif_start(bp);
+	return 0;
+}
+
+static struct pci_driver bnx2_pci_driver = {
+	name:		DRV_MODULE_NAME,
+	id_table:	bnx2_pci_tbl,
+	probe:		bnx2_init_one,
+	remove:		__devexit_p(bnx2_remove_one),
+	suspend:	bnx2_suspend,
+	resume:		bnx2_resume,
+};
+
+static int __init bnx2_init(void)
+{
+	return pci_module_init(&bnx2_pci_driver);
+}
+
+static void __exit bnx2_cleanup(void)
+{
+	pci_unregister_driver(&bnx2_pci_driver);
+}
+
+module_init(bnx2_init);
+module_exit(bnx2_cleanup);
+
+
+
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
new file mode 100644
--- /dev/null
+++ b/drivers/net/bnx2.h
@@ -0,0 +1,4352 @@
+/* bnx2.h: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005 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.
+ *
+ * Written by: Michael Chan  (mchan@broadcom.com)
+ */
+
+
+#ifndef BNX2_H
+#define BNX2_H
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <linux/time.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#define BCM_VLAN 1
+#endif
+#ifdef NETIF_F_TSO
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/checksum.h>
+#define BCM_TSO 1
+#endif
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+
+/* Hardware data structures and register definitions automatically
+ * generated from RTL code. Do not modify.
+ */
+
+/*
+ *  tx_bd definition
+ */
+struct tx_bd {
+	u32 tx_bd_haddr_hi;
+	u32 tx_bd_haddr_lo;                                   
+	u32 tx_bd_mss_nbytes;                                     
+	u32 tx_bd_vlan_tag_flags;                                      
+		#define TX_BD_FLAGS_CONN_FAULT		(1<<0)
+		#define TX_BD_FLAGS_TCP_UDP_CKSUM	(1<<1)
+		#define TX_BD_FLAGS_IP_CKSUM		(1<<2)
+		#define TX_BD_FLAGS_VLAN_TAG		(1<<3)
+		#define TX_BD_FLAGS_COAL_NOW		(1<<4)
+		#define TX_BD_FLAGS_DONT_GEN_CRC	(1<<5)
+		#define TX_BD_FLAGS_END			(1<<6)
+		#define TX_BD_FLAGS_START		(1<<7)
+		#define TX_BD_FLAGS_SW_OPTION_WORD	(0x1f<<8)
+		#define TX_BD_FLAGS_SW_FLAGS		(1<<13)
+		#define TX_BD_FLAGS_SW_SNAP		(1<<14)
+		#define TX_BD_FLAGS_SW_LSO		(1<<15)
+
+};
+
+
+/*
+ *  rx_bd definition
+ */
+struct rx_bd {
+	u32 rx_bd_haddr_hi;
+	u32 rx_bd_haddr_lo;
+	u32 rx_bd_len;
+	u32 rx_bd_flags;
+		#define RX_BD_FLAGS_NOPUSH		(1<<0)
+		#define RX_BD_FLAGS_DUMMY		(1<<1)
+		#define RX_BD_FLAGS_END			(1<<2)
+		#define RX_BD_FLAGS_START		(1<<3)
+
+};
+
+
+/*
+ *  status_block definition
+ */
+struct status_block {
+	u32 status_attn_bits;
+		#define STATUS_ATTN_BITS_LINK_STATE		(1L<<0)
+		#define STATUS_ATTN_BITS_TX_SCHEDULER_ABORT	(1L<<1)
+		#define STATUS_ATTN_BITS_TX_BD_READ_ABORT	(1L<<2)
+		#define STATUS_ATTN_BITS_TX_BD_CACHE_ABORT	(1L<<3)
+		#define STATUS_ATTN_BITS_TX_PROCESSOR_ABORT	(1L<<4)
+		#define STATUS_ATTN_BITS_TX_DMA_ABORT		(1L<<5)
+		#define STATUS_ATTN_BITS_TX_PATCHUP_ABORT	(1L<<6)
+		#define STATUS_ATTN_BITS_TX_ASSEMBLER_ABORT	(1L<<7)
+		#define STATUS_ATTN_BITS_RX_PARSER_MAC_ABORT	(1L<<8)
+		#define STATUS_ATTN_BITS_RX_PARSER_CATCHUP_ABORT	(1L<<9)
+		#define STATUS_ATTN_BITS_RX_MBUF_ABORT		(1L<<10)
+		#define STATUS_ATTN_BITS_RX_LOOKUP_ABORT	(1L<<11)
+		#define STATUS_ATTN_BITS_RX_PROCESSOR_ABORT	(1L<<12)
+		#define STATUS_ATTN_BITS_RX_V2P_ABORT		(1L<<13)
+		#define STATUS_ATTN_BITS_RX_BD_CACHE_ABORT	(1L<<14)
+		#define STATUS_ATTN_BITS_RX_DMA_ABORT		(1L<<15)
+		#define STATUS_ATTN_BITS_COMPLETION_ABORT	(1L<<16)
+		#define STATUS_ATTN_BITS_HOST_COALESCE_ABORT	(1L<<17)
+		#define STATUS_ATTN_BITS_MAILBOX_QUEUE_ABORT	(1L<<18)
+		#define STATUS_ATTN_BITS_CONTEXT_ABORT		(1L<<19)
+		#define STATUS_ATTN_BITS_CMD_SCHEDULER_ABORT	(1L<<20)
+		#define STATUS_ATTN_BITS_CMD_PROCESSOR_ABORT	(1L<<21)
+		#define STATUS_ATTN_BITS_MGMT_PROCESSOR_ABORT	(1L<<22)
+		#define STATUS_ATTN_BITS_MAC_ABORT		(1L<<23)
+		#define STATUS_ATTN_BITS_TIMER_ABORT		(1L<<24)
+		#define STATUS_ATTN_BITS_DMAE_ABORT		(1L<<25)
+		#define STATUS_ATTN_BITS_FLSH_ABORT		(1L<<26)
+		#define STATUS_ATTN_BITS_GRC_ABORT		(1L<<27)
+		#define STATUS_ATTN_BITS_PARITY_ERROR		(1L<<31)
+
+	u32 status_attn_bits_ack;
+#if defined(__BIG_ENDIAN)
+	u16 status_tx_quick_consumer_index0;
+	u16 status_tx_quick_consumer_index1;
+	u16 status_tx_quick_consumer_index2;
+	u16 status_tx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index0;
+	u16 status_rx_quick_consumer_index1;
+	u16 status_rx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index4;
+	u16 status_rx_quick_consumer_index5;
+	u16 status_rx_quick_consumer_index6;
+	u16 status_rx_quick_consumer_index7;
+	u16 status_rx_quick_consumer_index8;
+	u16 status_rx_quick_consumer_index9;
+	u16 status_rx_quick_consumer_index10;
+	u16 status_rx_quick_consumer_index11;
+	u16 status_rx_quick_consumer_index12;
+	u16 status_rx_quick_consumer_index13;
+	u16 status_rx_quick_consumer_index14;
+	u16 status_rx_quick_consumer_index15;
+	u16 status_completion_producer_index;
+	u16 status_cmd_consumer_index;
+	u16 status_idx;
+	u16 status_unused;
+#elif defined(__LITTLE_ENDIAN)
+	u16 status_tx_quick_consumer_index1;
+	u16 status_tx_quick_consumer_index0;
+	u16 status_tx_quick_consumer_index3;
+	u16 status_tx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index1;
+	u16 status_rx_quick_consumer_index0;
+	u16 status_rx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index5;
+	u16 status_rx_quick_consumer_index4;
+	u16 status_rx_quick_consumer_index7;
+	u16 status_rx_quick_consumer_index6;
+	u16 status_rx_quick_consumer_index9;
+	u16 status_rx_quick_consumer_index8;
+	u16 status_rx_quick_consumer_index11;
+	u16 status_rx_quick_consumer_index10;
+	u16 status_rx_quick_consumer_index13;
+	u16 status_rx_quick_consumer_index12;
+	u16 status_rx_quick_consumer_index15;
+	u16 status_rx_quick_consumer_index14;
+	u16 status_cmd_consumer_index;
+	u16 status_completion_producer_index;
+	u16 status_unused;
+	u16 status_idx;
+#endif
+};
+
+
+/*
+ *  statistics_block definition
+ */
+struct statistics_block {
+	u32 stat_IfHCInOctets_hi;
+	u32 stat_IfHCInOctets_lo;
+	u32 stat_IfHCInBadOctets_hi;
+	u32 stat_IfHCInBadOctets_lo;
+	u32 stat_IfHCOutOctets_hi;
+	u32 stat_IfHCOutOctets_lo;
+	u32 stat_IfHCOutBadOctets_hi;
+	u32 stat_IfHCOutBadOctets_lo;
+	u32 stat_IfHCInUcastPkts_hi;
+	u32 stat_IfHCInUcastPkts_lo;
+	u32 stat_IfHCInMulticastPkts_hi;
+	u32 stat_IfHCInMulticastPkts_lo;
+	u32 stat_IfHCInBroadcastPkts_hi;
+	u32 stat_IfHCInBroadcastPkts_lo;
+	u32 stat_IfHCOutUcastPkts_hi;
+	u32 stat_IfHCOutUcastPkts_lo;
+	u32 stat_IfHCOutMulticastPkts_hi;
+	u32 stat_IfHCOutMulticastPkts_lo;
+	u32 stat_IfHCOutBroadcastPkts_hi;
+	u32 stat_IfHCOutBroadcastPkts_lo;
+	u32 stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
+	u32 stat_Dot3StatsCarrierSenseErrors;
+	u32 stat_Dot3StatsFCSErrors;
+	u32 stat_Dot3StatsAlignmentErrors;
+	u32 stat_Dot3StatsSingleCollisionFrames;
+	u32 stat_Dot3StatsMultipleCollisionFrames;
+	u32 stat_Dot3StatsDeferredTransmissions;
+	u32 stat_Dot3StatsExcessiveCollisions;
+	u32 stat_Dot3StatsLateCollisions;
+	u32 stat_EtherStatsCollisions;
+	u32 stat_EtherStatsFragments;
+	u32 stat_EtherStatsJabbers;
+	u32 stat_EtherStatsUndersizePkts;
+	u32 stat_EtherStatsOverrsizePkts;
+	u32 stat_EtherStatsPktsRx64Octets;
+	u32 stat_EtherStatsPktsRx65Octetsto127Octets;
+	u32 stat_EtherStatsPktsRx128Octetsto255Octets;
+	u32 stat_EtherStatsPktsRx256Octetsto511Octets;
+	u32 stat_EtherStatsPktsRx512Octetsto1023Octets;
+	u32 stat_EtherStatsPktsRx1024Octetsto1522Octets;
+	u32 stat_EtherStatsPktsRx1523Octetsto9022Octets;
+	u32 stat_EtherStatsPktsTx64Octets;
+	u32 stat_EtherStatsPktsTx65Octetsto127Octets;
+	u32 stat_EtherStatsPktsTx128Octetsto255Octets;
+	u32 stat_EtherStatsPktsTx256Octetsto511Octets;
+	u32 stat_EtherStatsPktsTx512Octetsto1023Octets;
+	u32 stat_EtherStatsPktsTx1024Octetsto1522Octets;
+	u32 stat_EtherStatsPktsTx1523Octetsto9022Octets;
+	u32 stat_XonPauseFramesReceived;
+	u32 stat_XoffPauseFramesReceived;
+	u32 stat_OutXonSent;
+	u32 stat_OutXoffSent;
+	u32 stat_FlowControlDone;
+	u32 stat_MacControlFramesReceived;
+	u32 stat_XoffStateEntered;
+	u32 stat_IfInFramesL2FilterDiscards;
+	u32 stat_IfInRuleCheckerDiscards;
+	u32 stat_IfInFTQDiscards;
+	u32 stat_IfInMBUFDiscards;
+	u32 stat_IfInRuleCheckerP4Hit;
+	u32 stat_CatchupInRuleCheckerDiscards;
+	u32 stat_CatchupInFTQDiscards;
+	u32 stat_CatchupInMBUFDiscards;
+	u32 stat_CatchupInRuleCheckerP4Hit;
+	u32 stat_GenStat00;
+	u32 stat_GenStat01;
+	u32 stat_GenStat02;
+	u32 stat_GenStat03;
+	u32 stat_GenStat04;
+	u32 stat_GenStat05;
+	u32 stat_GenStat06;
+	u32 stat_GenStat07;
+	u32 stat_GenStat08;
+	u32 stat_GenStat09;
+	u32 stat_GenStat10;
+	u32 stat_GenStat11;
+	u32 stat_GenStat12;
+	u32 stat_GenStat13;
+	u32 stat_GenStat14;
+	u32 stat_GenStat15;
+};
+
+
+/*
+ *  l2_fhdr definition
+ */
+struct l2_fhdr {
+#if defined(__BIG_ENDIAN)
+	u16 l2_fhdr_errors;
+	u16 l2_fhdr_status;
+#elif defined(__LITTLE_ENDIAN)
+	u16 l2_fhdr_status;
+	u16 l2_fhdr_errors;
+#endif
+		#define L2_FHDR_ERRORS_BAD_CRC		(1<<1)
+		#define L2_FHDR_ERRORS_PHY_DECODE	(1<<2)
+		#define L2_FHDR_ERRORS_ALIGNMENT	(1<<3)
+		#define L2_FHDR_ERRORS_TOO_SHORT	(1<<4)
+		#define L2_FHDR_ERRORS_GIANT_FRAME	(1<<5)
+
+		#define L2_FHDR_STATUS_RULE_CLASS	(0x7<<0)
+		#define L2_FHDR_STATUS_RULE_P2		(1<<3)
+		#define L2_FHDR_STATUS_RULE_P3		(1<<4)
+		#define L2_FHDR_STATUS_RULE_P4		(1<<5)
+		#define L2_FHDR_STATUS_L2_VLAN_TAG	(1<<6)
+		#define L2_FHDR_STATUS_L2_LLC_SNAP	(1<<7)
+		#define L2_FHDR_STATUS_RSS_HASH		(1<<8)
+		#define L2_FHDR_STATUS_IP_DATAGRAM	(1<<13)
+		#define L2_FHDR_STATUS_TCP_SEGMENT	(1<<14)
+		#define L2_FHDR_STATUS_UDP_DATAGRAM	(1<<15)
+
+	u32 l2_fhdr_hash;
+#if defined(__BIG_ENDIAN)
+	u16 l2_fhdr_pkt_len;
+	u16 l2_fhdr_vlan_tag;
+	u16 l2_fhdr_ip_xsum;
+	u16 l2_fhdr_tcp_udp_xsum;
+#elif defined(__LITTLE_ENDIAN)
+	u16 l2_fhdr_vlan_tag;
+	u16 l2_fhdr_pkt_len;
+	u16 l2_fhdr_tcp_udp_xsum;
+	u16 l2_fhdr_ip_xsum;
+#endif
+};
+
+
+/*
+ *  l2_context definition
+ */
+#define BNX2_L2CTX_TYPE					0x00000000
+#define BNX2_L2CTX_TYPE_SIZE_L2				 ((0xc0/0x20)<<16)
+#define BNX2_L2CTX_TYPE_TYPE				 (0xf<<28)
+#define BNX2_L2CTX_TYPE_TYPE_EMPTY			 (0<<28)
+#define BNX2_L2CTX_TYPE_TYPE_L2				 (1<<28)
+
+#define BNX2_L2CTX_TX_HOST_BIDX				0x00000088
+#define BNX2_L2CTX_EST_NBD				0x00000088
+#define BNX2_L2CTX_CMD_TYPE				0x00000088
+#define BNX2_L2CTX_CMD_TYPE_TYPE			 (0xf<<24)
+#define BNX2_L2CTX_CMD_TYPE_TYPE_L2			 (0<<24)
+#define BNX2_L2CTX_CMD_TYPE_TYPE_TCP			 (1<<24)
+
+#define BNX2_L2CTX_TX_HOST_BSEQ				0x00000090
+#define BNX2_L2CTX_TSCH_BSEQ				0x00000094
+#define BNX2_L2CTX_TBDR_BSEQ				0x00000098
+#define BNX2_L2CTX_TBDR_BOFF				0x0000009c
+#define BNX2_L2CTX_TBDR_BIDX				0x0000009c
+#define BNX2_L2CTX_TBDR_BHADDR_HI			0x000000a0
+#define BNX2_L2CTX_TBDR_BHADDR_LO			0x000000a4
+#define BNX2_L2CTX_TXP_BOFF				0x000000a8
+#define BNX2_L2CTX_TXP_BIDX				0x000000a8
+#define BNX2_L2CTX_TXP_BSEQ				0x000000ac
+
+
+/*
+ *  l2_bd_chain_context definition
+ */
+#define BNX2_L2CTX_BD_PRE_READ				0x00000000
+#define BNX2_L2CTX_CTX_SIZE				0x00000000
+#define BNX2_L2CTX_CTX_TYPE				0x00000000
+#define BNX2_L2CTX_CTX_TYPE_SIZE_L2			 ((0x20/20)<<16)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE		 (0xf<<28)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_UNDEFINED	 (0<<28)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE	 (1<<28)
+
+#define BNX2_L2CTX_HOST_BDIDX				0x00000004
+#define BNX2_L2CTX_HOST_BSEQ				0x00000008
+#define BNX2_L2CTX_NX_BSEQ				0x0000000c
+#define BNX2_L2CTX_NX_BDHADDR_HI			0x00000010
+#define BNX2_L2CTX_NX_BDHADDR_LO			0x00000014
+#define BNX2_L2CTX_NX_BDIDX				0x00000018
+
+
+/*
+ *  pci_config_l definition
+ *  offset: 0000
+ */
+#define BNX2_PCICFG_MISC_CONFIG				0x00000068
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_BYTE_SWAP	 (1L<<2)
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP	 (1L<<3)
+#define BNX2_PCICFG_MISC_CONFIG_CLOCK_CTL_ENA		 (1L<<5)
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_GRC_WORD_SWAP	 (1L<<6)
+#define BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA		 (1L<<7)
+#define BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ		 (1L<<8)
+#define BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY		 (1L<<9)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_METAL_REV		 (0xffL<<16)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_BASE_REV		 (0xfL<<24)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_ID			 (0xfL<<28)
+
+#define BNX2_PCICFG_MISC_STATUS				0x0000006c
+#define BNX2_PCICFG_MISC_STATUS_INTA_VALUE		 (1L<<0)
+#define BNX2_PCICFG_MISC_STATUS_32BIT_DET		 (1L<<1)
+#define BNX2_PCICFG_MISC_STATUS_M66EN			 (1L<<2)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_DET		 (1L<<3)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED		 (0x3L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_66		 (0L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_100		 (1L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_133		 (2L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_PCI_MODE	 (3L<<4)
+
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS		0x00000070
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET	 (0xfL<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ	 (0L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ	 (1L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ	 (2L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ	 (3L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ	 (4L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ	 (5L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ	 (6L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ	 (7L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW	 (0xfL<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE	 (1L<<6)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT	 (1L<<7)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC	 (0x7L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_UNDEF	 (0L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12	 (1L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_6	 (2L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_62	 (4L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PLAY_DEAD	 (1L<<11)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED	 (0xfL<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_100	 (0L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_80	 (1L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_50	 (2L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_40	 (4L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_25	 (8L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_STOP	 (1L<<16)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_PLL_STOP	 (1L<<17)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_RESERVED_18	 (1L<<18)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_USE_SPD_DET	 (1L<<19)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_RESERVED	 (0xfffL<<20)
+
+#define BNX2_PCICFG_REG_WINDOW_ADDRESS			0x00000078
+#define BNX2_PCICFG_REG_WINDOW				0x00000080
+#define BNX2_PCICFG_INT_ACK_CMD				0x00000084
+#define BNX2_PCICFG_INT_ACK_CMD_INDEX			 (0xffffL<<0)
+#define BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID		 (1L<<16)
+#define BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM	 (1L<<17)
+#define BNX2_PCICFG_INT_ACK_CMD_MASK_INT		 (1L<<18)
+
+#define BNX2_PCICFG_STATUS_BIT_SET_CMD			0x00000088
+#define BNX2_PCICFG_STATUS_BIT_CLEAR_CMD		0x0000008c
+#define BNX2_PCICFG_MAILBOX_QUEUE_ADDR			0x00000090
+#define BNX2_PCICFG_MAILBOX_QUEUE_DATA			0x00000094
+
+
+/*
+ *  pci_reg definition
+ *  offset: 0x400
+ */
+#define BNX2_PCI_GRC_WINDOW_ADDR			0x00000400
+#define BNX2_PCI_GRC_WINDOW_ADDR_PCI_GRC_WINDOW_ADDR_VALUE	 (0x3ffffL<<8)
+
+#define BNX2_PCI_CONFIG_1				0x00000404
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY			 (0x7L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_OFF		 (0L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_16		 (1L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_32		 (2L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_64		 (3L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_128		 (4L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_256		 (5L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_512		 (6L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_1024		 (7L<<8)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY		 (0x7L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_OFF		 (0L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_16		 (1L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_32		 (2L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_64		 (3L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_128		 (4L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_256		 (5L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_512		 (6L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_1024		 (7L<<11)
+
+#define BNX2_PCI_CONFIG_2				0x00000408
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE			 (0xfL<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_DISABLED		 (0L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_64K			 (1L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_128K		 (2L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_256K		 (3L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_512K		 (4L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_1M			 (5L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_2M			 (6L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_4M			 (7L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_8M			 (8L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_16M			 (9L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_32M			 (10L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_64M			 (11L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_128M		 (12L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_256M		 (13L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_512M		 (14L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_1G			 (15L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_64ENA			 (1L<<4)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_RETRY			 (1L<<5)
+#define BNX2_PCI_CONFIG_2_CFG_CYCLE_RETRY		 (1L<<6)
+#define BNX2_PCI_CONFIG_2_FIRST_CFG_DONE		 (1L<<7)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE			 (0xffL<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_DISABLED		 (0L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_1K		 (1L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_2K		 (2L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_4K		 (3L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_8K		 (4L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_16K		 (5L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_32K		 (6L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_64K		 (7L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_128K		 (8L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_256K		 (9L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_512K		 (10L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_1M		 (11L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_2M		 (12L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_4M		 (13L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_8M		 (14L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_16M		 (15L<<8)
+#define BNX2_PCI_CONFIG_2_MAX_SPLIT_LIMIT		 (0x1fL<<16)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT		 (0x3L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_512		 (0L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_1K		 (1L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_2K		 (2L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_4K		 (3L<<21)
+#define BNX2_PCI_CONFIG_2_FORCE_32_BIT_MSTR		 (1L<<23)
+#define BNX2_PCI_CONFIG_2_FORCE_32_BIT_TGT		 (1L<<24)
+#define BNX2_PCI_CONFIG_2_KEEP_REQ_ASSERT		 (1L<<25)
+
+#define BNX2_PCI_CONFIG_3				0x0000040c
+#define BNX2_PCI_CONFIG_3_STICKY_BYTE			 (0xffL<<0)
+#define BNX2_PCI_CONFIG_3_FORCE_PME			 (1L<<24)
+#define BNX2_PCI_CONFIG_3_PME_STATUS			 (1L<<25)
+#define BNX2_PCI_CONFIG_3_PME_ENABLE			 (1L<<26)
+#define BNX2_PCI_CONFIG_3_PM_STATE			 (0x3L<<27)
+#define BNX2_PCI_CONFIG_3_VAUX_PRESET			 (1L<<30)
+#define BNX2_PCI_CONFIG_3_PCI_POWER			 (1L<<31)
+
+#define BNX2_PCI_PM_DATA_A				0x00000410
+#define BNX2_PCI_PM_DATA_A_PM_DATA_0_PRG		 (0xffL<<0)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_1_PRG		 (0xffL<<8)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_2_PRG		 (0xffL<<16)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_3_PRG		 (0xffL<<24)
+
+#define BNX2_PCI_PM_DATA_B				0x00000414
+#define BNX2_PCI_PM_DATA_B_PM_DATA_4_PRG		 (0xffL<<0)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_5_PRG		 (0xffL<<8)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_6_PRG		 (0xffL<<16)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_7_PRG		 (0xffL<<24)
+
+#define BNX2_PCI_SWAP_DIAG0				0x00000418
+#define BNX2_PCI_SWAP_DIAG1				0x0000041c
+#define BNX2_PCI_EXP_ROM_ADDR				0x00000420
+#define BNX2_PCI_EXP_ROM_ADDR_ADDRESS			 (0x3fffffL<<2)
+#define BNX2_PCI_EXP_ROM_ADDR_REQ			 (1L<<31)
+
+#define BNX2_PCI_EXP_ROM_DATA				0x00000424
+#define BNX2_PCI_VPD_INTF				0x00000428
+#define BNX2_PCI_VPD_INTF_INTF_REQ			 (1L<<0)
+
+#define BNX2_PCI_VPD_ADDR_FLAG				0x0000042c
+#define BNX2_PCI_VPD_ADDR_FLAG_ADDRESS			 (0x1fff<<2)
+#define BNX2_PCI_VPD_ADDR_FLAG_WR			 (1<<15)
+
+#define BNX2_PCI_VPD_DATA				0x00000430
+#define BNX2_PCI_ID_VAL1				0x00000434
+#define BNX2_PCI_ID_VAL1_DEVICE_ID			 (0xffffL<<0)
+#define BNX2_PCI_ID_VAL1_VENDOR_ID			 (0xffffL<<16)
+
+#define BNX2_PCI_ID_VAL2				0x00000438
+#define BNX2_PCI_ID_VAL2_SUBSYSTEM_VENDOR_ID		 (0xffffL<<0)
+#define BNX2_PCI_ID_VAL2_SUBSYSTEM_ID			 (0xffffL<<16)
+
+#define BNX2_PCI_ID_VAL3				0x0000043c
+#define BNX2_PCI_ID_VAL3_CLASS_CODE			 (0xffffffL<<0)
+#define BNX2_PCI_ID_VAL3_REVISION_ID			 (0xffL<<24)
+
+#define BNX2_PCI_ID_VAL4				0x00000440
+#define BNX2_PCI_ID_VAL4_CAP_ENA			 (0xfL<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_0			 (0L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_1			 (1L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_2			 (2L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_3			 (3L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_4			 (4L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_5			 (5L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_6			 (6L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_7			 (7L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_8			 (8L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_9			 (9L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_10			 (10L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_11			 (11L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_12			 (12L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_13			 (13L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_14			 (14L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_15			 (15L<<0)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG			 (0x3L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_0			 (0L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_1			 (1L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_2			 (2L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_3			 (3L<<6)
+#define BNX2_PCI_ID_VAL4_MSI_LIMIT			 (0x7L<<9)
+#define BNX2_PCI_ID_VAL4_MSI_ADVERTIZE			 (0x7L<<12)
+#define BNX2_PCI_ID_VAL4_MSI_ENABLE			 (1L<<15)
+#define BNX2_PCI_ID_VAL4_MAX_64_ADVERTIZE		 (1L<<16)
+#define BNX2_PCI_ID_VAL4_MAX_133_ADVERTIZE		 (1L<<17)
+#define BNX2_PCI_ID_VAL4_MAX_MEM_READ_SIZE		 (0x3L<<21)
+#define BNX2_PCI_ID_VAL4_MAX_SPLIT_SIZE			 (0x7L<<23)
+#define BNX2_PCI_ID_VAL4_MAX_CUMULATIVE_SIZE		 (0x7L<<26)
+
+#define BNX2_PCI_ID_VAL5				0x00000444
+#define BNX2_PCI_ID_VAL5_D1_SUPPORT			 (1L<<0)
+#define BNX2_PCI_ID_VAL5_D2_SUPPORT			 (1L<<1)
+#define BNX2_PCI_ID_VAL5_PME_IN_D0			 (1L<<2)
+#define BNX2_PCI_ID_VAL5_PME_IN_D1			 (1L<<3)
+#define BNX2_PCI_ID_VAL5_PME_IN_D2			 (1L<<4)
+#define BNX2_PCI_ID_VAL5_PME_IN_D3_HOT			 (1L<<5)
+
+#define BNX2_PCI_PCIX_EXTENDED_STATUS			0x00000448
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_NO_SNOOP		 (1L<<8)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_LONG_BURST	 (1L<<9)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_SPLIT_COMP_MSG_CLASS	 (0xfL<<16)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_SPLIT_COMP_MSG_IDX	 (0xffL<<24)
+
+#define BNX2_PCI_ID_VAL6				0x0000044c
+#define BNX2_PCI_ID_VAL6_MAX_LAT			 (0xffL<<0)
+#define BNX2_PCI_ID_VAL6_MIN_GNT			 (0xffL<<8)
+#define BNX2_PCI_ID_VAL6_BIST				 (0xffL<<16)
+
+#define BNX2_PCI_MSI_DATA				0x00000450
+#define BNX2_PCI_MSI_DATA_PCI_MSI_DATA			 (0xffffL<<0)
+
+#define BNX2_PCI_MSI_ADDR_H				0x00000454
+#define BNX2_PCI_MSI_ADDR_L				0x00000458
+
+
+/*
+ *  misc_reg definition
+ *  offset: 0x800
+ */
+#define BNX2_MISC_COMMAND				0x00000800
+#define BNX2_MISC_COMMAND_ENABLE_ALL			 (1L<<0)
+#define BNX2_MISC_COMMAND_DISABLE_ALL			 (1L<<1)
+#define BNX2_MISC_COMMAND_CORE_RESET			 (1L<<4)
+#define BNX2_MISC_COMMAND_HARD_RESET			 (1L<<5)
+#define BNX2_MISC_COMMAND_PAR_ERROR			 (1L<<8)
+#define BNX2_MISC_COMMAND_PAR_ERR_RAM			 (0x7fL<<16)
+
+#define BNX2_MISC_CFG					0x00000804
+#define BNX2_MISC_CFG_PCI_GRC_TMOUT			 (1L<<0)
+#define BNX2_MISC_CFG_NVM_WR_EN				 (0x3L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_PROTECT			 (0L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_PCI			 (1L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_ALLOW			 (2L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_ALLOW2			 (3L<<1)
+#define BNX2_MISC_CFG_BIST_EN				 (1L<<3)
+#define BNX2_MISC_CFG_CK25_OUT_ALT_SRC			 (1L<<4)
+#define BNX2_MISC_CFG_BYPASS_BSCAN			 (1L<<5)
+#define BNX2_MISC_CFG_BYPASS_EJTAG			 (1L<<6)
+#define BNX2_MISC_CFG_CLK_CTL_OVERRIDE			 (1L<<7)
+#define BNX2_MISC_CFG_LEDMODE				 (0x3L<<8)
+#define BNX2_MISC_CFG_LEDMODE_MAC			 (0L<<8)
+#define BNX2_MISC_CFG_LEDMODE_GPHY1			 (1L<<8)
+#define BNX2_MISC_CFG_LEDMODE_GPHY2			 (2L<<8)
+
+#define BNX2_MISC_ID					0x00000808
+#define BNX2_MISC_ID_BOND_ID				 (0xfL<<0)
+#define BNX2_MISC_ID_CHIP_METAL				 (0xffL<<4)
+#define BNX2_MISC_ID_CHIP_REV				 (0xfL<<12)
+#define BNX2_MISC_ID_CHIP_NUM				 (0xffffL<<16)
+
+#define BNX2_MISC_ENABLE_STATUS_BITS			0x0000080c
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_DMA_ENABLE	 (1L<<4)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_STATUS_BITS_EMAC_ENABLE	 (1L<<9)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE	 (1L<<15)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_DMA_ENABLE	 (1L<<17)
+#define BNX2_MISC_ENABLE_STATUS_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_STATUS_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_STATUS_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_STATUS_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TIMER_ENABLE	 (1L<<25)
+#define BNX2_MISC_ENABLE_STATUS_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_STATUS_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ENABLE_SET_BITS			0x00000810
+#define BNX2_MISC_ENABLE_SET_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_ENABLE_SET_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_SET_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_SET_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_SET_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_SET_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_SET_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_SET_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_ENABLE_SET_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_SET_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ENABLE_CLR_BITS			0x00000814
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_CLR_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_ENABLE_CLR_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_CLR_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_CLR_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_CLR_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_CLR_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_CLR_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_CLR_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_CLR_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_CLOCK_CONTROL_BITS			0x00000818
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET	 (0xfL<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ	 (0L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ	 (1L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ	 (2L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ	 (3L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ	 (4L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ	 (5L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ	 (6L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ	 (7L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW	 (0xfL<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE	 (1L<<6)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT	 (1L<<7)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC	 (0x7L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_UNDEF	 (0L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12	 (1L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_6	 (2L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_62	 (4L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PLAY_DEAD		 (1L<<11)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED	 (0xfL<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_100	 (0L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_80	 (1L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_50	 (2L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_40	 (4L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_25	 (8L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_STOP	 (1L<<16)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_PLL_STOP	 (1L<<17)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_RESERVED_18	 (1L<<18)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_USE_SPD_DET	 (1L<<19)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_RESERVED		 (0xfffL<<20)
+
+#define BNX2_MISC_GPIO					0x0000081c
+#define BNX2_MISC_GPIO_VALUE				 (0xffL<<0)
+#define BNX2_MISC_GPIO_SET				 (0xffL<<8)
+#define BNX2_MISC_GPIO_CLR				 (0xffL<<16)
+#define BNX2_MISC_GPIO_FLOAT				 (0xffL<<24)
+
+#define BNX2_MISC_GPIO_INT				0x00000820
+#define BNX2_MISC_GPIO_INT_INT_STATE			 (0xfL<<0)
+#define BNX2_MISC_GPIO_INT_OLD_VALUE			 (0xfL<<8)
+#define BNX2_MISC_GPIO_INT_OLD_SET			 (0xfL<<16)
+#define BNX2_MISC_GPIO_INT_OLD_CLR			 (0xfL<<24)
+
+#define BNX2_MISC_CONFIG_LFSR				0x00000824
+#define BNX2_MISC_CONFIG_LFSR_DIV			 (0xffffL<<0)
+
+#define BNX2_MISC_LFSR_MASK_BITS			0x00000828
+#define BNX2_MISC_LFSR_MASK_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_LFSR_MASK_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_MBUF_ENABLE		 (1L<<12)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_LFSR_MASK_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_LFSR_MASK_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_LFSR_MASK_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_LFSR_MASK_BITS_CONTEXT_ENABLE		 (1L<<21)
+#define BNX2_MISC_LFSR_MASK_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_LFSR_MASK_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_LFSR_MASK_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_LFSR_MASK_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_LFSR_MASK_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_LFSR_MASK_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ARB_REQ0				0x0000082c
+#define BNX2_MISC_ARB_REQ1				0x00000830
+#define BNX2_MISC_ARB_REQ2				0x00000834
+#define BNX2_MISC_ARB_REQ3				0x00000838
+#define BNX2_MISC_ARB_REQ4				0x0000083c
+#define BNX2_MISC_ARB_FREE0				0x00000840
+#define BNX2_MISC_ARB_FREE1				0x00000844
+#define BNX2_MISC_ARB_FREE2				0x00000848
+#define BNX2_MISC_ARB_FREE3				0x0000084c
+#define BNX2_MISC_ARB_FREE4				0x00000850
+#define BNX2_MISC_ARB_REQ_STATUS0			0x00000854
+#define BNX2_MISC_ARB_REQ_STATUS1			0x00000858
+#define BNX2_MISC_ARB_REQ_STATUS2			0x0000085c
+#define BNX2_MISC_ARB_REQ_STATUS3			0x00000860
+#define BNX2_MISC_ARB_REQ_STATUS4			0x00000864
+#define BNX2_MISC_ARB_GNT0				0x00000868
+#define BNX2_MISC_ARB_GNT0_0				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT0_1				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT0_2				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT0_3				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT0_4				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT0_5				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT0_6				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT0_7				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT1				0x0000086c
+#define BNX2_MISC_ARB_GNT1_8				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT1_9				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT1_10				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT1_11				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT1_12				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT1_13				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT1_14				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT1_15				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT2				0x00000870
+#define BNX2_MISC_ARB_GNT2_16				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT2_17				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT2_18				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT2_19				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT2_20				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT2_21				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT2_22				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT2_23				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT3				0x00000874
+#define BNX2_MISC_ARB_GNT3_24				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT3_25				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT3_26				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT3_27				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT3_28				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT3_29				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT3_30				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT3_31				 (0x7L<<28)
+
+#define BNX2_MISC_PRBS_CONTROL				0x00000878
+#define BNX2_MISC_PRBS_CONTROL_EN			 (1L<<0)
+#define BNX2_MISC_PRBS_CONTROL_RSTB			 (1L<<1)
+#define BNX2_MISC_PRBS_CONTROL_INV			 (1L<<2)
+#define BNX2_MISC_PRBS_CONTROL_ERR_CLR			 (1L<<3)
+#define BNX2_MISC_PRBS_CONTROL_ORDER			 (0x3L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_7TH		 (0L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_15TH		 (1L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_23RD		 (2L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_31ST		 (3L<<4)
+
+#define BNX2_MISC_PRBS_STATUS				0x0000087c
+#define BNX2_MISC_PRBS_STATUS_LOCK			 (1L<<0)
+#define BNX2_MISC_PRBS_STATUS_STKY			 (1L<<1)
+#define BNX2_MISC_PRBS_STATUS_ERRORS			 (0x3fffL<<2)
+#define BNX2_MISC_PRBS_STATUS_STATE			 (0xfL<<16)
+
+#define BNX2_MISC_SM_ASF_CONTROL			0x00000880
+#define BNX2_MISC_SM_ASF_CONTROL_ASF_RST		 (1L<<0)
+#define BNX2_MISC_SM_ASF_CONTROL_TSC_EN			 (1L<<1)
+#define BNX2_MISC_SM_ASF_CONTROL_WG_TO			 (1L<<2)
+#define BNX2_MISC_SM_ASF_CONTROL_HB_TO			 (1L<<3)
+#define BNX2_MISC_SM_ASF_CONTROL_PA_TO			 (1L<<4)
+#define BNX2_MISC_SM_ASF_CONTROL_PL_TO			 (1L<<5)
+#define BNX2_MISC_SM_ASF_CONTROL_RT_TO			 (1L<<6)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EVENT		 (1L<<7)
+#define BNX2_MISC_SM_ASF_CONTROL_RES			 (0xfL<<8)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EN			 (1L<<12)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_BB_EN		 (1L<<13)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_NO_ADDR_FILT	 (1L<<14)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_AUTOREAD		 (1L<<15)
+#define BNX2_MISC_SM_ASF_CONTROL_NIC_SMB_ADDR1		 (0x3fL<<16)
+#define BNX2_MISC_SM_ASF_CONTROL_NIC_SMB_ADDR2		 (0x3fL<<24)
+#define BNX2_MISC_SM_ASF_CONTROL_EN_NIC_SMB_ADDR_0	 (1L<<30)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EARLY_ATTN		 (1L<<31)
+
+#define BNX2_MISC_SMB_IN				0x00000884
+#define BNX2_MISC_SMB_IN_DAT_IN				 (0xffL<<0)
+#define BNX2_MISC_SMB_IN_RDY				 (1L<<8)
+#define BNX2_MISC_SMB_IN_DONE				 (1L<<9)
+#define BNX2_MISC_SMB_IN_FIRSTBYTE			 (1L<<10)
+#define BNX2_MISC_SMB_IN_STATUS				 (0x7L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_OK			 (0x0L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_PEC			 (0x1L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_OFLOW			 (0x2L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_STOP			 (0x3L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_TIMEOUT			 (0x4L<<11)
+
+#define BNX2_MISC_SMB_OUT				0x00000888
+#define BNX2_MISC_SMB_OUT_DAT_OUT			 (0xffL<<0)
+#define BNX2_MISC_SMB_OUT_RDY				 (1L<<8)
+#define BNX2_MISC_SMB_OUT_START				 (1L<<9)
+#define BNX2_MISC_SMB_OUT_LAST				 (1L<<10)
+#define BNX2_MISC_SMB_OUT_ACC_TYPE			 (1L<<11)
+#define BNX2_MISC_SMB_OUT_ENB_PEC			 (1L<<12)
+#define BNX2_MISC_SMB_OUT_GET_RX_LEN			 (1L<<13)
+#define BNX2_MISC_SMB_OUT_SMB_READ_LEN			 (0x3fL<<14)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS		 (0xfL<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_OK		 (0L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_FIRST_NACK	 (1L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_SUB_NACK	 (9L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_UFLOW		 (2L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_STOP		 (3L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_TIMEOUT	 (4L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_FIRST_LOST	 (5L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_SUB_LOST	 (0xdL<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_BADACK		 (0x6L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_SLAVEMODE		 (1L<<24)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_DAT_EN		 (1L<<25)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_DAT_IN		 (1L<<26)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_CLK_EN		 (1L<<27)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_CLK_IN		 (1L<<28)
+
+#define BNX2_MISC_SMB_WATCHDOG				0x0000088c
+#define BNX2_MISC_SMB_WATCHDOG_WATCHDOG			 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_HEARTBEAT				0x00000890
+#define BNX2_MISC_SMB_HEARTBEAT_HEARTBEAT		 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_POLL_ASF				0x00000894
+#define BNX2_MISC_SMB_POLL_ASF_POLL_ASF			 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_POLL_LEGACY			0x00000898
+#define BNX2_MISC_SMB_POLL_LEGACY_POLL_LEGACY		 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_RETRAN				0x0000089c
+#define BNX2_MISC_SMB_RETRAN_RETRAN			 (0xffL<<0)
+
+#define BNX2_MISC_SMB_TIMESTAMP				0x000008a0
+#define BNX2_MISC_SMB_TIMESTAMP_TIMESTAMP		 (0xffffffffL<<0)
+
+#define BNX2_MISC_PERR_ENA0				0x000008a4
+#define BNX2_MISC_PERR_ENA0_COM_MISC_CTXC		 (1L<<0)
+#define BNX2_MISC_PERR_ENA0_COM_MISC_REGF		 (1L<<1)
+#define BNX2_MISC_PERR_ENA0_COM_MISC_SCPAD		 (1L<<2)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_CTXC		 (1L<<3)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_REGF		 (1L<<4)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_SCPAD		 (1L<<5)
+#define BNX2_MISC_PERR_ENA0_CS_MISC_TMEM		 (1L<<6)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM0		 (1L<<7)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM1		 (1L<<8)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM2		 (1L<<9)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM3		 (1L<<10)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM4		 (1L<<11)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM5		 (1L<<12)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_PGTBL		 (1L<<13)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR0		 (1L<<14)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR1		 (1L<<15)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR2		 (1L<<16)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR3		 (1L<<17)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR4		 (1L<<18)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW0		 (1L<<19)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW1		 (1L<<20)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW2		 (1L<<21)
+#define BNX2_MISC_PERR_ENA0_HC_MISC_DMA			 (1L<<22)
+#define BNX2_MISC_PERR_ENA0_MCP_MISC_REGF		 (1L<<23)
+#define BNX2_MISC_PERR_ENA0_MCP_MISC_SCPAD		 (1L<<24)
+#define BNX2_MISC_PERR_ENA0_MQ_MISC_CTX			 (1L<<25)
+#define BNX2_MISC_PERR_ENA0_RBDC_MISC			 (1L<<26)
+#define BNX2_MISC_PERR_ENA0_RBUF_MISC_MB		 (1L<<27)
+#define BNX2_MISC_PERR_ENA0_RBUF_MISC_PTR		 (1L<<28)
+#define BNX2_MISC_PERR_ENA0_RDE_MISC_RPC		 (1L<<29)
+#define BNX2_MISC_PERR_ENA0_RDE_MISC_RPM		 (1L<<30)
+#define BNX2_MISC_PERR_ENA0_RV2P_MISC_CB0REGS		 (1L<<31)
+
+#define BNX2_MISC_PERR_ENA1				0x000008a8
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_CB1REGS		 (1L<<0)
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_P1IRAM		 (1L<<1)
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_P2IRAM		 (1L<<2)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_CTXC		 (1L<<3)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_REGF		 (1L<<4)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_SCPAD		 (1L<<5)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_RBUFC		 (1L<<6)
+#define BNX2_MISC_PERR_ENA1_TBDC_MISC			 (1L<<7)
+#define BNX2_MISC_PERR_ENA1_TDMA_MISC			 (1L<<8)
+#define BNX2_MISC_PERR_ENA1_THBUF_MISC_MB0		 (1L<<9)
+#define BNX2_MISC_PERR_ENA1_THBUF_MISC_MB1		 (1L<<10)
+#define BNX2_MISC_PERR_ENA1_TPAT_MISC_REGF		 (1L<<11)
+#define BNX2_MISC_PERR_ENA1_TPAT_MISC_SCPAD		 (1L<<12)
+#define BNX2_MISC_PERR_ENA1_TPBUF_MISC_MB		 (1L<<13)
+#define BNX2_MISC_PERR_ENA1_TSCH_MISC_LR		 (1L<<14)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_CTXC		 (1L<<15)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_REGF		 (1L<<16)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_SCPAD		 (1L<<17)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_FIORX		 (1L<<18)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_FIOTX		 (1L<<19)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_RX			 (1L<<20)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_TX			 (1L<<21)
+#define BNX2_MISC_PERR_ENA1_RDMAQ_MISC			 (1L<<22)
+#define BNX2_MISC_PERR_ENA1_CSQ_MISC			 (1L<<23)
+#define BNX2_MISC_PERR_ENA1_CPQ_MISC			 (1L<<24)
+#define BNX2_MISC_PERR_ENA1_MCPQ_MISC			 (1L<<25)
+#define BNX2_MISC_PERR_ENA1_RV2PMQ_MISC			 (1L<<26)
+#define BNX2_MISC_PERR_ENA1_RV2PPQ_MISC			 (1L<<27)
+#define BNX2_MISC_PERR_ENA1_RV2PTQ_MISC			 (1L<<28)
+#define BNX2_MISC_PERR_ENA1_RXPQ_MISC			 (1L<<29)
+#define BNX2_MISC_PERR_ENA1_RXPCQ_MISC			 (1L<<30)
+#define BNX2_MISC_PERR_ENA1_RLUPQ_MISC			 (1L<<31)
+
+#define BNX2_MISC_PERR_ENA2				0x000008ac
+#define BNX2_MISC_PERR_ENA2_COMQ_MISC			 (1L<<0)
+#define BNX2_MISC_PERR_ENA2_COMXQ_MISC			 (1L<<1)
+#define BNX2_MISC_PERR_ENA2_COMTQ_MISC			 (1L<<2)
+#define BNX2_MISC_PERR_ENA2_TSCHQ_MISC			 (1L<<3)
+#define BNX2_MISC_PERR_ENA2_TBDRQ_MISC			 (1L<<4)
+#define BNX2_MISC_PERR_ENA2_TXPQ_MISC			 (1L<<5)
+#define BNX2_MISC_PERR_ENA2_TDMAQ_MISC			 (1L<<6)
+#define BNX2_MISC_PERR_ENA2_TPATQ_MISC			 (1L<<7)
+#define BNX2_MISC_PERR_ENA2_TASQ_MISC			 (1L<<8)
+
+#define BNX2_MISC_DEBUG_VECTOR_SEL			0x000008b0
+#define BNX2_MISC_DEBUG_VECTOR_SEL_0			 (0xfffL<<0)
+#define BNX2_MISC_DEBUG_VECTOR_SEL_1			 (0xfffL<<12)
+
+#define BNX2_MISC_VREG_CONTROL				0x000008b4
+#define BNX2_MISC_VREG_CONTROL_1_2			 (0xfL<<0)
+#define BNX2_MISC_VREG_CONTROL_2_5			 (0xfL<<4)
+
+#define BNX2_MISC_FINAL_CLK_CTL_VAL			0x000008b8
+#define BNX2_MISC_FINAL_CLK_CTL_VAL_MISC_FINAL_CLK_CTL_VAL	 (0x3ffffffL<<6)
+
+#define BNX2_MISC_UNUSED0				0x000008bc
+
+
+/*
+ *  nvm_reg definition
+ *  offset: 0x6400
+ */
+#define BNX2_NVM_COMMAND				0x00006400
+#define BNX2_NVM_COMMAND_RST				 (1L<<0)
+#define BNX2_NVM_COMMAND_DONE				 (1L<<3)
+#define BNX2_NVM_COMMAND_DOIT				 (1L<<4)
+#define BNX2_NVM_COMMAND_WR				 (1L<<5)
+#define BNX2_NVM_COMMAND_ERASE				 (1L<<6)
+#define BNX2_NVM_COMMAND_FIRST				 (1L<<7)
+#define BNX2_NVM_COMMAND_LAST				 (1L<<8)
+#define BNX2_NVM_COMMAND_WREN				 (1L<<16)
+#define BNX2_NVM_COMMAND_WRDI				 (1L<<17)
+#define BNX2_NVM_COMMAND_EWSR				 (1L<<18)
+#define BNX2_NVM_COMMAND_WRSR				 (1L<<19)
+
+#define BNX2_NVM_STATUS					0x00006404
+#define BNX2_NVM_STATUS_PI_FSM_STATE			 (0xfL<<0)
+#define BNX2_NVM_STATUS_EE_FSM_STATE			 (0xfL<<4)
+#define BNX2_NVM_STATUS_EQ_FSM_STATE			 (0xfL<<8)
+
+#define BNX2_NVM_WRITE					0x00006408
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE			 (0xffffffffL<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SO		 (16L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SI		 (32L<<0)
+
+#define BNX2_NVM_ADDR					0x0000640c
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE			 (0xffffffL<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SO			 (16L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SI			 (32L<<0)
+
+#define BNX2_NVM_READ					0x00006410
+#define BNX2_NVM_READ_NVM_READ_VALUE			 (0xffffffffL<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SO			 (16L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SI			 (32L<<0)
+
+#define BNX2_NVM_CFG1					0x00006414
+#define BNX2_NVM_CFG1_FLASH_MODE			 (1L<<0)
+#define BNX2_NVM_CFG1_BUFFER_MODE			 (1L<<1)
+#define BNX2_NVM_CFG1_PASS_MODE				 (1L<<2)
+#define BNX2_NVM_CFG1_BITBANG_MODE			 (1L<<3)
+#define BNX2_NVM_CFG1_STATUS_BIT			 (0x7L<<4)
+#define BNX2_NVM_CFG1_STATUS_BIT_FLASH_RDY		 (0L<<4)
+#define BNX2_NVM_CFG1_STATUS_BIT_BUFFER_RDY		 (7L<<4)
+#define BNX2_NVM_CFG1_SPI_CLK_DIV			 (0xfL<<7)
+#define BNX2_NVM_CFG1_SEE_CLK_DIV			 (0x7ffL<<11)
+#define BNX2_NVM_CFG1_PROTECT_MODE			 (1L<<24)
+#define BNX2_NVM_CFG1_FLASH_SIZE			 (1L<<25)
+#define BNX2_NVM_CFG1_COMPAT_BYPASSS			 (1L<<31)
+
+#define BNX2_NVM_CFG2					0x00006418
+#define BNX2_NVM_CFG2_ERASE_CMD				 (0xffL<<0)
+#define BNX2_NVM_CFG2_DUMMY				 (0xffL<<8)
+#define BNX2_NVM_CFG2_STATUS_CMD			 (0xffL<<16)
+
+#define BNX2_NVM_CFG3					0x0000641c
+#define BNX2_NVM_CFG3_BUFFER_RD_CMD			 (0xffL<<0)
+#define BNX2_NVM_CFG3_WRITE_CMD				 (0xffL<<8)
+#define BNX2_NVM_CFG3_BUFFER_WRITE_CMD			 (0xffL<<16)
+#define BNX2_NVM_CFG3_READ_CMD				 (0xffL<<24)
+
+#define BNX2_NVM_SW_ARB					0x00006420
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET0			 (1L<<0)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET1			 (1L<<1)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET2			 (1L<<2)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET3			 (1L<<3)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR0			 (1L<<4)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR1			 (1L<<5)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR2			 (1L<<6)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR3			 (1L<<7)
+#define BNX2_NVM_SW_ARB_ARB_ARB0			 (1L<<8)
+#define BNX2_NVM_SW_ARB_ARB_ARB1			 (1L<<9)
+#define BNX2_NVM_SW_ARB_ARB_ARB2			 (1L<<10)
+#define BNX2_NVM_SW_ARB_ARB_ARB3			 (1L<<11)
+#define BNX2_NVM_SW_ARB_REQ0				 (1L<<12)
+#define BNX2_NVM_SW_ARB_REQ1				 (1L<<13)
+#define BNX2_NVM_SW_ARB_REQ2				 (1L<<14)
+#define BNX2_NVM_SW_ARB_REQ3				 (1L<<15)
+
+#define BNX2_NVM_ACCESS_ENABLE				0x00006424
+#define BNX2_NVM_ACCESS_ENABLE_EN			 (1L<<0)
+#define BNX2_NVM_ACCESS_ENABLE_WR_EN			 (1L<<1)
+
+#define BNX2_NVM_WRITE1					0x00006428
+#define BNX2_NVM_WRITE1_WREN_CMD			 (0xffL<<0)
+#define BNX2_NVM_WRITE1_WRDI_CMD			 (0xffL<<8)
+#define BNX2_NVM_WRITE1_SR_DATA				 (0xffL<<16)
+
+
+
+/*
+ *  dma_reg definition
+ *  offset: 0xc00
+ */
+#define BNX2_DMA_COMMAND				0x00000c00
+#define BNX2_DMA_COMMAND_ENABLE				 (1L<<0)
+
+#define BNX2_DMA_STATUS					0x00000c04
+#define BNX2_DMA_STATUS_PAR_ERROR_STATE			 (1L<<0)
+#define BNX2_DMA_STATUS_READ_TRANSFERS_STAT		 (1L<<16)
+#define BNX2_DMA_STATUS_READ_DELAY_PCI_CLKS_STAT	 (1L<<17)
+#define BNX2_DMA_STATUS_BIG_READ_TRANSFERS_STAT		 (1L<<18)
+#define BNX2_DMA_STATUS_BIG_READ_DELAY_PCI_CLKS_STAT	 (1L<<19)
+#define BNX2_DMA_STATUS_BIG_READ_RETRY_AFTER_DATA_STAT	 (1L<<20)
+#define BNX2_DMA_STATUS_WRITE_TRANSFERS_STAT		 (1L<<21)
+#define BNX2_DMA_STATUS_WRITE_DELAY_PCI_CLKS_STAT	 (1L<<22)
+#define BNX2_DMA_STATUS_BIG_WRITE_TRANSFERS_STAT	 (1L<<23)
+#define BNX2_DMA_STATUS_BIG_WRITE_DELAY_PCI_CLKS_STAT	 (1L<<24)
+#define BNX2_DMA_STATUS_BIG_WRITE_RETRY_AFTER_DATA_STAT	 (1L<<25)
+
+#define BNX2_DMA_CONFIG					0x00000c08
+#define BNX2_DMA_CONFIG_DATA_BYTE_SWAP			 (1L<<0)
+#define BNX2_DMA_CONFIG_DATA_WORD_SWAP			 (1L<<1)
+#define BNX2_DMA_CONFIG_CNTL_BYTE_SWAP			 (1L<<4)
+#define BNX2_DMA_CONFIG_CNTL_WORD_SWAP			 (1L<<5)
+#define BNX2_DMA_CONFIG_ONE_DMA				 (1L<<6)
+#define BNX2_DMA_CONFIG_CNTL_TWO_DMA			 (1L<<7)
+#define BNX2_DMA_CONFIG_CNTL_FPGA_MODE			 (1L<<8)
+#define BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA		 (1L<<10)
+#define BNX2_DMA_CONFIG_CNTL_PCI_COMP_DLY		 (1L<<11)
+#define BNX2_DMA_CONFIG_NO_RCHANS_IN_USE		 (0xfL<<12)
+#define BNX2_DMA_CONFIG_NO_WCHANS_IN_USE		 (0xfL<<16)
+#define BNX2_DMA_CONFIG_PCI_CLK_CMP_BITS		 (0x7L<<20)
+#define BNX2_DMA_CONFIG_PCI_FAST_CLK_CMP		 (1L<<23)
+#define BNX2_DMA_CONFIG_BIG_SIZE			 (0xfL<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_NONE			 (0x0L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_64			 (0x1L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_128			 (0x2L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_256			 (0x4L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_512			 (0x8L<<24)
+
+#define BNX2_DMA_BLACKOUT				0x00000c0c
+#define BNX2_DMA_BLACKOUT_RD_RETRY_BLACKOUT		 (0xffL<<0)
+#define BNX2_DMA_BLACKOUT_2ND_RD_RETRY_BLACKOUT		 (0xffL<<8)
+#define BNX2_DMA_BLACKOUT_WR_RETRY_BLACKOUT		 (0xffL<<16)
+
+#define BNX2_DMA_RCHAN_STAT				0x00000c30
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_0			 (0x7L<<0)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_0			 (1L<<3)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_1			 (0x7L<<4)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_1			 (1L<<7)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_2			 (0x7L<<8)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_2			 (1L<<11)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_3			 (0x7L<<12)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_3			 (1L<<15)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_4			 (0x7L<<16)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_4			 (1L<<19)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_5			 (0x7L<<20)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_5			 (1L<<23)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_6			 (0x7L<<24)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_6			 (1L<<27)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_7			 (0x7L<<28)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_7			 (1L<<31)
+
+#define BNX2_DMA_WCHAN_STAT				0x00000c34
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_0			 (0x7L<<0)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_0			 (1L<<3)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_1			 (0x7L<<4)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_1			 (1L<<7)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_2			 (0x7L<<8)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_2			 (1L<<11)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_3			 (0x7L<<12)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_3			 (1L<<15)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_4			 (0x7L<<16)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_4			 (1L<<19)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_5			 (0x7L<<20)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_5			 (1L<<23)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_6			 (0x7L<<24)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_6			 (1L<<27)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_7			 (0x7L<<28)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_7			 (1L<<31)
+
+#define BNX2_DMA_RCHAN_ASSIGNMENT			0x00000c38
+#define BNX2_DMA_RCHAN_ASSIGNMENT_0			 (0xfL<<0)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_1			 (0xfL<<4)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_2			 (0xfL<<8)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_3			 (0xfL<<12)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_4			 (0xfL<<16)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_5			 (0xfL<<20)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_6			 (0xfL<<24)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_7			 (0xfL<<28)
+
+#define BNX2_DMA_WCHAN_ASSIGNMENT			0x00000c3c
+#define BNX2_DMA_WCHAN_ASSIGNMENT_0			 (0xfL<<0)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_1			 (0xfL<<4)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_2			 (0xfL<<8)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_3			 (0xfL<<12)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_4			 (0xfL<<16)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_5			 (0xfL<<20)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_6			 (0xfL<<24)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_7			 (0xfL<<28)
+
+#define BNX2_DMA_RCHAN_STAT_00				0x00000c40
+#define BNX2_DMA_RCHAN_STAT_00_RCHAN_STA_HOST_ADDR_LOW	 (0xffffffffL<<0)
+
+#define BNX2_DMA_RCHAN_STAT_01				0x00000c44
+#define BNX2_DMA_RCHAN_STAT_01_RCHAN_STA_HOST_ADDR_HIGH	 (0xffffffffL<<0)
+
+#define BNX2_DMA_RCHAN_STAT_02				0x00000c48
+#define BNX2_DMA_RCHAN_STAT_02_LENGTH			 (0xffffL<<0)
+#define BNX2_DMA_RCHAN_STAT_02_WORD_SWAP		 (1L<<16)
+#define BNX2_DMA_RCHAN_STAT_02_BYTE_SWAP		 (1L<<17)
+#define BNX2_DMA_RCHAN_STAT_02_PRIORITY_LVL		 (1L<<18)
+
+#define BNX2_DMA_RCHAN_STAT_10				0x00000c4c
+#define BNX2_DMA_RCHAN_STAT_11				0x00000c50
+#define BNX2_DMA_RCHAN_STAT_12				0x00000c54
+#define BNX2_DMA_RCHAN_STAT_20				0x00000c58
+#define BNX2_DMA_RCHAN_STAT_21				0x00000c5c
+#define BNX2_DMA_RCHAN_STAT_22				0x00000c60
+#define BNX2_DMA_RCHAN_STAT_30				0x00000c64
+#define BNX2_DMA_RCHAN_STAT_31				0x00000c68
+#define BNX2_DMA_RCHAN_STAT_32				0x00000c6c
+#define BNX2_DMA_RCHAN_STAT_40				0x00000c70
+#define BNX2_DMA_RCHAN_STAT_41				0x00000c74
+#define BNX2_DMA_RCHAN_STAT_42				0x00000c78
+#define BNX2_DMA_RCHAN_STAT_50				0x00000c7c
+#define BNX2_DMA_RCHAN_STAT_51				0x00000c80
+#define BNX2_DMA_RCHAN_STAT_52				0x00000c84
+#define BNX2_DMA_RCHAN_STAT_60				0x00000c88
+#define BNX2_DMA_RCHAN_STAT_61				0x00000c8c
+#define BNX2_DMA_RCHAN_STAT_62				0x00000c90
+#define BNX2_DMA_RCHAN_STAT_70				0x00000c94
+#define BNX2_DMA_RCHAN_STAT_71				0x00000c98
+#define BNX2_DMA_RCHAN_STAT_72				0x00000c9c
+#define BNX2_DMA_WCHAN_STAT_00				0x00000ca0
+#define BNX2_DMA_WCHAN_STAT_00_WCHAN_STA_HOST_ADDR_LOW	 (0xffffffffL<<0)
+
+#define BNX2_DMA_WCHAN_STAT_01				0x00000ca4
+#define BNX2_DMA_WCHAN_STAT_01_WCHAN_STA_HOST_ADDR_HIGH	 (0xffffffffL<<0)
+
+#define BNX2_DMA_WCHAN_STAT_02				0x00000ca8
+#define BNX2_DMA_WCHAN_STAT_02_LENGTH			 (0xffffL<<0)
+#define BNX2_DMA_WCHAN_STAT_02_WORD_SWAP		 (1L<<16)
+#define BNX2_DMA_WCHAN_STAT_02_BYTE_SWAP		 (1L<<17)
+#define BNX2_DMA_WCHAN_STAT_02_PRIORITY_LVL		 (1L<<18)
+
+#define BNX2_DMA_WCHAN_STAT_10				0x00000cac
+#define BNX2_DMA_WCHAN_STAT_11				0x00000cb0
+#define BNX2_DMA_WCHAN_STAT_12				0x00000cb4
+#define BNX2_DMA_WCHAN_STAT_20				0x00000cb8
+#define BNX2_DMA_WCHAN_STAT_21				0x00000cbc
+#define BNX2_DMA_WCHAN_STAT_22				0x00000cc0
+#define BNX2_DMA_WCHAN_STAT_30				0x00000cc4
+#define BNX2_DMA_WCHAN_STAT_31				0x00000cc8
+#define BNX2_DMA_WCHAN_STAT_32				0x00000ccc
+#define BNX2_DMA_WCHAN_STAT_40				0x00000cd0
+#define BNX2_DMA_WCHAN_STAT_41				0x00000cd4
+#define BNX2_DMA_WCHAN_STAT_42				0x00000cd8
+#define BNX2_DMA_WCHAN_STAT_50				0x00000cdc
+#define BNX2_DMA_WCHAN_STAT_51				0x00000ce0
+#define BNX2_DMA_WCHAN_STAT_52				0x00000ce4
+#define BNX2_DMA_WCHAN_STAT_60				0x00000ce8
+#define BNX2_DMA_WCHAN_STAT_61				0x00000cec
+#define BNX2_DMA_WCHAN_STAT_62				0x00000cf0
+#define BNX2_DMA_WCHAN_STAT_70				0x00000cf4
+#define BNX2_DMA_WCHAN_STAT_71				0x00000cf8
+#define BNX2_DMA_WCHAN_STAT_72				0x00000cfc
+#define BNX2_DMA_ARB_STAT_00				0x00000d00
+#define BNX2_DMA_ARB_STAT_00_MASTER			 (0xffffL<<0)
+#define BNX2_DMA_ARB_STAT_00_MASTER_ENC			 (0xffL<<16)
+#define BNX2_DMA_ARB_STAT_00_CUR_BINMSTR		 (0xffL<<24)
+
+#define BNX2_DMA_ARB_STAT_01				0x00000d04
+#define BNX2_DMA_ARB_STAT_01_LPR_RPTR			 (0xfL<<0)
+#define BNX2_DMA_ARB_STAT_01_LPR_WPTR			 (0xfL<<4)
+#define BNX2_DMA_ARB_STAT_01_LPB_RPTR			 (0xfL<<8)
+#define BNX2_DMA_ARB_STAT_01_LPB_WPTR			 (0xfL<<12)
+#define BNX2_DMA_ARB_STAT_01_HPR_RPTR			 (0xfL<<16)
+#define BNX2_DMA_ARB_STAT_01_HPR_WPTR			 (0xfL<<20)
+#define BNX2_DMA_ARB_STAT_01_HPB_RPTR			 (0xfL<<24)
+#define BNX2_DMA_ARB_STAT_01_HPB_WPTR			 (0xfL<<28)
+
+#define BNX2_DMA_FUSE_CTRL0_CMD				0x00000f00
+#define BNX2_DMA_FUSE_CTRL0_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL0_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL0_DATA			0x00000f04
+#define BNX2_DMA_FUSE_CTRL1_CMD				0x00000f08
+#define BNX2_DMA_FUSE_CTRL1_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL1_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL1_DATA			0x00000f0c
+#define BNX2_DMA_FUSE_CTRL2_CMD				0x00000f10
+#define BNX2_DMA_FUSE_CTRL2_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL2_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL2_DATA			0x00000f14
+
+
+/*
+ *  context_reg definition
+ *  offset: 0x1000
+ */
+#define BNX2_CTX_COMMAND				0x00001000
+#define BNX2_CTX_COMMAND_ENABLED			 (1L<<0)
+
+#define BNX2_CTX_STATUS					0x00001004
+#define BNX2_CTX_STATUS_LOCK_WAIT			 (1L<<0)
+#define BNX2_CTX_STATUS_READ_STAT			 (1L<<16)
+#define BNX2_CTX_STATUS_WRITE_STAT			 (1L<<17)
+#define BNX2_CTX_STATUS_ACC_STALL_STAT			 (1L<<18)
+#define BNX2_CTX_STATUS_LOCK_STALL_STAT			 (1L<<19)
+
+#define BNX2_CTX_VIRT_ADDR				0x00001008
+#define BNX2_CTX_VIRT_ADDR_VIRT_ADDR			 (0x7fffL<<6)
+
+#define BNX2_CTX_PAGE_TBL				0x0000100c
+#define BNX2_CTX_PAGE_TBL_PAGE_TBL			 (0x3fffL<<6)
+
+#define BNX2_CTX_DATA_ADR				0x00001010
+#define BNX2_CTX_DATA_ADR_DATA_ADR			 (0x7ffffL<<2)
+
+#define BNX2_CTX_DATA					0x00001014
+#define BNX2_CTX_LOCK					0x00001018
+#define BNX2_CTX_LOCK_TYPE				 (0x7L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_VOID		 (0x0L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_COMPLETE		 (0x7L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_PROTOCOL		 (0x1L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_TX			 (0x2L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_TIMER		 (0x4L<<0)
+#define BNX2_CTX_LOCK_CID_VALUE				 (0x3fffL<<7)
+#define BNX2_CTX_LOCK_GRANTED				 (1L<<26)
+#define BNX2_CTX_LOCK_MODE				 (0x7L<<27)
+#define BNX2_CTX_LOCK_MODE_UNLOCK			 (0x0L<<27)
+#define BNX2_CTX_LOCK_MODE_IMMEDIATE			 (0x1L<<27)
+#define BNX2_CTX_LOCK_MODE_SURE				 (0x2L<<27)
+#define BNX2_CTX_LOCK_STATUS				 (1L<<30)
+#define BNX2_CTX_LOCK_REQ				 (1L<<31)
+
+#define BNX2_CTX_ACCESS_STATUS				0x00001040
+#define BNX2_CTX_ACCESS_STATUS_MASTERENCODED		 (0xfL<<0)
+#define BNX2_CTX_ACCESS_STATUS_ACCESSMEMORYSM		 (0x3L<<10)
+#define BNX2_CTX_ACCESS_STATUS_PAGETABLEINITSM		 (0x3L<<12)
+#define BNX2_CTX_ACCESS_STATUS_ACCESSMEMORYINITSM	 (0x3L<<14)
+#define BNX2_CTX_ACCESS_STATUS_QUALIFIED_REQUEST	 (0x7ffL<<17)
+
+#define BNX2_CTX_DBG_LOCK_STATUS			0x00001044
+#define BNX2_CTX_DBG_LOCK_STATUS_SM			 (0x3ffL<<0)
+#define BNX2_CTX_DBG_LOCK_STATUS_MATCH			 (0x3ffL<<22)
+
+#define BNX2_CTX_CHNL_LOCK_STATUS_0			0x00001080
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_CID			 (0x3fffL<<0)
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_TYPE		 (0x3L<<14)
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_MODE		 (1L<<16)
+
+#define BNX2_CTX_CHNL_LOCK_STATUS_1			0x00001084
+#define BNX2_CTX_CHNL_LOCK_STATUS_2			0x00001088
+#define BNX2_CTX_CHNL_LOCK_STATUS_3			0x0000108c
+#define BNX2_CTX_CHNL_LOCK_STATUS_4			0x00001090
+#define BNX2_CTX_CHNL_LOCK_STATUS_5			0x00001094
+#define BNX2_CTX_CHNL_LOCK_STATUS_6			0x00001098
+#define BNX2_CTX_CHNL_LOCK_STATUS_7			0x0000109c
+#define BNX2_CTX_CHNL_LOCK_STATUS_8			0x000010a0
+
+
+/*
+ *  emac_reg definition
+ *  offset: 0x1400
+ */
+#define BNX2_EMAC_MODE					0x00001400
+#define BNX2_EMAC_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_MODE_HALF_DUPLEX			 (1L<<1)
+#define BNX2_EMAC_MODE_PORT				 (0x3L<<2)
+#define BNX2_EMAC_MODE_PORT_NONE			 (0L<<2)
+#define BNX2_EMAC_MODE_PORT_MII				 (1L<<2)
+#define BNX2_EMAC_MODE_PORT_GMII			 (2L<<2)
+#define BNX2_EMAC_MODE_PORT_UNDEF			 (3L<<2)
+#define BNX2_EMAC_MODE_MAC_LOOP				 (1L<<4)
+#define BNX2_EMAC_MODE_TAGGED_MAC_CTL			 (1L<<7)
+#define BNX2_EMAC_MODE_TX_BURST				 (1L<<8)
+#define BNX2_EMAC_MODE_MAX_DEFER_DROP_ENA		 (1L<<9)
+#define BNX2_EMAC_MODE_EXT_LINK_POL			 (1L<<10)
+#define BNX2_EMAC_MODE_FORCE_LINK			 (1L<<11)
+#define BNX2_EMAC_MODE_MPKT				 (1L<<18)
+#define BNX2_EMAC_MODE_MPKT_RCVD			 (1L<<19)
+#define BNX2_EMAC_MODE_ACPI_RCVD			 (1L<<20)
+
+#define BNX2_EMAC_STATUS				0x00001404
+#define BNX2_EMAC_STATUS_LINK				 (1L<<11)
+#define BNX2_EMAC_STATUS_LINK_CHANGE			 (1L<<12)
+#define BNX2_EMAC_STATUS_MI_COMPLETE			 (1L<<22)
+#define BNX2_EMAC_STATUS_MI_INT				 (1L<<23)
+#define BNX2_EMAC_STATUS_AP_ERROR			 (1L<<24)
+#define BNX2_EMAC_STATUS_PARITY_ERROR_STATE		 (1L<<31)
+
+#define BNX2_EMAC_ATTENTION_ENA				0x00001408
+#define BNX2_EMAC_ATTENTION_ENA_LINK			 (1L<<11)
+#define BNX2_EMAC_ATTENTION_ENA_MI_COMPLETE		 (1L<<22)
+#define BNX2_EMAC_ATTENTION_ENA_MI_INT			 (1L<<23)
+#define BNX2_EMAC_ATTENTION_ENA_AP_ERROR		 (1L<<24)
+
+#define BNX2_EMAC_LED					0x0000140c
+#define BNX2_EMAC_LED_OVERRIDE				 (1L<<0)
+#define BNX2_EMAC_LED_1000MB_OVERRIDE			 (1L<<1)
+#define BNX2_EMAC_LED_100MB_OVERRIDE			 (1L<<2)
+#define BNX2_EMAC_LED_10MB_OVERRIDE			 (1L<<3)
+#define BNX2_EMAC_LED_TRAFFIC_OVERRIDE			 (1L<<4)
+#define BNX2_EMAC_LED_BLNK_TRAFFIC			 (1L<<5)
+#define BNX2_EMAC_LED_TRAFFIC				 (1L<<6)
+#define BNX2_EMAC_LED_1000MB				 (1L<<7)
+#define BNX2_EMAC_LED_100MB				 (1L<<8)
+#define BNX2_EMAC_LED_10MB				 (1L<<9)
+#define BNX2_EMAC_LED_TRAFFIC_STAT			 (1L<<10)
+#define BNX2_EMAC_LED_BLNK_RATE				 (0xfffL<<19)
+#define BNX2_EMAC_LED_BLNK_RATE_ENA			 (1L<<31)
+
+#define BNX2_EMAC_MAC_MATCH0				0x00001410
+#define BNX2_EMAC_MAC_MATCH1				0x00001414
+#define BNX2_EMAC_MAC_MATCH2				0x00001418
+#define BNX2_EMAC_MAC_MATCH3				0x0000141c
+#define BNX2_EMAC_MAC_MATCH4				0x00001420
+#define BNX2_EMAC_MAC_MATCH5				0x00001424
+#define BNX2_EMAC_MAC_MATCH6				0x00001428
+#define BNX2_EMAC_MAC_MATCH7				0x0000142c
+#define BNX2_EMAC_MAC_MATCH8				0x00001430
+#define BNX2_EMAC_MAC_MATCH9				0x00001434
+#define BNX2_EMAC_MAC_MATCH10				0x00001438
+#define BNX2_EMAC_MAC_MATCH11				0x0000143c
+#define BNX2_EMAC_MAC_MATCH12				0x00001440
+#define BNX2_EMAC_MAC_MATCH13				0x00001444
+#define BNX2_EMAC_MAC_MATCH14				0x00001448
+#define BNX2_EMAC_MAC_MATCH15				0x0000144c
+#define BNX2_EMAC_MAC_MATCH16				0x00001450
+#define BNX2_EMAC_MAC_MATCH17				0x00001454
+#define BNX2_EMAC_MAC_MATCH18				0x00001458
+#define BNX2_EMAC_MAC_MATCH19				0x0000145c
+#define BNX2_EMAC_MAC_MATCH20				0x00001460
+#define BNX2_EMAC_MAC_MATCH21				0x00001464
+#define BNX2_EMAC_MAC_MATCH22				0x00001468
+#define BNX2_EMAC_MAC_MATCH23				0x0000146c
+#define BNX2_EMAC_MAC_MATCH24				0x00001470
+#define BNX2_EMAC_MAC_MATCH25				0x00001474
+#define BNX2_EMAC_MAC_MATCH26				0x00001478
+#define BNX2_EMAC_MAC_MATCH27				0x0000147c
+#define BNX2_EMAC_MAC_MATCH28				0x00001480
+#define BNX2_EMAC_MAC_MATCH29				0x00001484
+#define BNX2_EMAC_MAC_MATCH30				0x00001488
+#define BNX2_EMAC_MAC_MATCH31				0x0000148c
+#define BNX2_EMAC_BACKOFF_SEED				0x00001498
+#define BNX2_EMAC_BACKOFF_SEED_EMAC_BACKOFF_SEED	 (0x3ffL<<0)
+
+#define BNX2_EMAC_RX_MTU_SIZE				0x0000149c
+#define BNX2_EMAC_RX_MTU_SIZE_MTU_SIZE			 (0xffffL<<0)
+#define BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA			 (1L<<31)
+
+#define BNX2_EMAC_SERDES_CNTL				0x000014a4
+#define BNX2_EMAC_SERDES_CNTL_RXR			 (0x7L<<0)
+#define BNX2_EMAC_SERDES_CNTL_RXG			 (0x3L<<3)
+#define BNX2_EMAC_SERDES_CNTL_RXCKSEL			 (1L<<6)
+#define BNX2_EMAC_SERDES_CNTL_TXBIAS			 (0x7L<<7)
+#define BNX2_EMAC_SERDES_CNTL_BGMAX			 (1L<<10)
+#define BNX2_EMAC_SERDES_CNTL_BGMIN			 (1L<<11)
+#define BNX2_EMAC_SERDES_CNTL_TXMODE			 (1L<<12)
+#define BNX2_EMAC_SERDES_CNTL_TXEDGE			 (1L<<13)
+#define BNX2_EMAC_SERDES_CNTL_SERDES_MODE		 (1L<<14)
+#define BNX2_EMAC_SERDES_CNTL_PLLTEST			 (1L<<15)
+#define BNX2_EMAC_SERDES_CNTL_CDET_EN			 (1L<<16)
+#define BNX2_EMAC_SERDES_CNTL_TBI_LBK			 (1L<<17)
+#define BNX2_EMAC_SERDES_CNTL_REMOTE_LBK		 (1L<<18)
+#define BNX2_EMAC_SERDES_CNTL_REV_PHASE			 (1L<<19)
+#define BNX2_EMAC_SERDES_CNTL_REGCTL12			 (0x3L<<20)
+#define BNX2_EMAC_SERDES_CNTL_REGCTL25			 (0x3L<<22)
+
+#define BNX2_EMAC_SERDES_STATUS				0x000014a8
+#define BNX2_EMAC_SERDES_STATUS_RX_STAT			 (0xffL<<0)
+#define BNX2_EMAC_SERDES_STATUS_COMMA_DET		 (1L<<8)
+
+#define BNX2_EMAC_MDIO_COMM				0x000014ac
+#define BNX2_EMAC_MDIO_COMM_DATA			 (0xffffL<<0)
+#define BNX2_EMAC_MDIO_COMM_REG_ADDR			 (0x1fL<<16)
+#define BNX2_EMAC_MDIO_COMM_PHY_ADDR			 (0x1fL<<21)
+#define BNX2_EMAC_MDIO_COMM_COMMAND			 (0x3L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_UNDEFINED_0		 (0L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_WRITE		 (1L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_READ		 (2L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_UNDEFINED_3		 (3L<<26)
+#define BNX2_EMAC_MDIO_COMM_FAIL			 (1L<<28)
+#define BNX2_EMAC_MDIO_COMM_START_BUSY			 (1L<<29)
+#define BNX2_EMAC_MDIO_COMM_DISEXT			 (1L<<30)
+
+#define BNX2_EMAC_MDIO_STATUS				0x000014b0
+#define BNX2_EMAC_MDIO_STATUS_LINK			 (1L<<0)
+#define BNX2_EMAC_MDIO_STATUS_10MB			 (1L<<1)
+
+#define BNX2_EMAC_MDIO_MODE				0x000014b4
+#define BNX2_EMAC_MDIO_MODE_SHORT_PREAMBLE		 (1L<<1)
+#define BNX2_EMAC_MDIO_MODE_AUTO_POLL			 (1L<<4)
+#define BNX2_EMAC_MDIO_MODE_BIT_BANG			 (1L<<8)
+#define BNX2_EMAC_MDIO_MODE_MDIO			 (1L<<9)
+#define BNX2_EMAC_MDIO_MODE_MDIO_OE			 (1L<<10)
+#define BNX2_EMAC_MDIO_MODE_MDC				 (1L<<11)
+#define BNX2_EMAC_MDIO_MODE_MDINT			 (1L<<12)
+#define BNX2_EMAC_MDIO_MODE_CLOCK_CNT			 (0x1fL<<16)
+
+#define BNX2_EMAC_MDIO_AUTO_STATUS			0x000014b8
+#define BNX2_EMAC_MDIO_AUTO_STATUS_AUTO_ERR		 (1L<<0)
+
+#define BNX2_EMAC_TX_MODE				0x000014bc
+#define BNX2_EMAC_TX_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_TX_MODE_EXT_PAUSE_EN			 (1L<<3)
+#define BNX2_EMAC_TX_MODE_FLOW_EN			 (1L<<4)
+#define BNX2_EMAC_TX_MODE_BIG_BACKOFF			 (1L<<5)
+#define BNX2_EMAC_TX_MODE_LONG_PAUSE			 (1L<<6)
+#define BNX2_EMAC_TX_MODE_LINK_AWARE			 (1L<<7)
+
+#define BNX2_EMAC_TX_STATUS				0x000014c0
+#define BNX2_EMAC_TX_STATUS_XOFFED			 (1L<<0)
+#define BNX2_EMAC_TX_STATUS_XOFF_SENT			 (1L<<1)
+#define BNX2_EMAC_TX_STATUS_XON_SENT			 (1L<<2)
+#define BNX2_EMAC_TX_STATUS_LINK_UP			 (1L<<3)
+#define BNX2_EMAC_TX_STATUS_UNDERRUN			 (1L<<4)
+
+#define BNX2_EMAC_TX_LENGTHS				0x000014c4
+#define BNX2_EMAC_TX_LENGTHS_SLOT			 (0xffL<<0)
+#define BNX2_EMAC_TX_LENGTHS_IPG			 (0xfL<<8)
+#define BNX2_EMAC_TX_LENGTHS_IPG_CRS			 (0x3L<<12)
+
+#define BNX2_EMAC_RX_MODE				0x000014c8
+#define BNX2_EMAC_RX_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_RX_MODE_FLOW_EN			 (1L<<2)
+#define BNX2_EMAC_RX_MODE_KEEP_MAC_CONTROL		 (1L<<3)
+#define BNX2_EMAC_RX_MODE_KEEP_PAUSE			 (1L<<4)
+#define BNX2_EMAC_RX_MODE_ACCEPT_OVERSIZE		 (1L<<5)
+#define BNX2_EMAC_RX_MODE_ACCEPT_RUNTS			 (1L<<6)
+#define BNX2_EMAC_RX_MODE_LLC_CHK			 (1L<<7)
+#define BNX2_EMAC_RX_MODE_PROMISCUOUS			 (1L<<8)
+#define BNX2_EMAC_RX_MODE_NO_CRC_CHK			 (1L<<9)
+#define BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG			 (1L<<10)
+#define BNX2_EMAC_RX_MODE_FILT_BROADCAST		 (1L<<11)
+#define BNX2_EMAC_RX_MODE_SORT_MODE			 (1L<<12)
+
+#define BNX2_EMAC_RX_STATUS				0x000014cc
+#define BNX2_EMAC_RX_STATUS_FFED			 (1L<<0)
+#define BNX2_EMAC_RX_STATUS_FF_RECEIVED			 (1L<<1)
+#define BNX2_EMAC_RX_STATUS_N_RECEIVED			 (1L<<2)
+
+#define BNX2_EMAC_MULTICAST_HASH0			0x000014d0
+#define BNX2_EMAC_MULTICAST_HASH1			0x000014d4
+#define BNX2_EMAC_MULTICAST_HASH2			0x000014d8
+#define BNX2_EMAC_MULTICAST_HASH3			0x000014dc
+#define BNX2_EMAC_MULTICAST_HASH4			0x000014e0
+#define BNX2_EMAC_MULTICAST_HASH5			0x000014e4
+#define BNX2_EMAC_MULTICAST_HASH6			0x000014e8
+#define BNX2_EMAC_MULTICAST_HASH7			0x000014ec
+#define BNX2_EMAC_RX_STAT_IFHCINOCTETS			0x00001500
+#define BNX2_EMAC_RX_STAT_IFHCINBADOCTETS		0x00001504
+#define BNX2_EMAC_RX_STAT_ETHERSTATSFRAGMENTS		0x00001508
+#define BNX2_EMAC_RX_STAT_IFHCINUCASTPKTS		0x0000150c
+#define BNX2_EMAC_RX_STAT_IFHCINMULTICASTPKTS		0x00001510
+#define BNX2_EMAC_RX_STAT_IFHCINBROADCASTPKTS		0x00001514
+#define BNX2_EMAC_RX_STAT_DOT3STATSFCSERRORS		0x00001518
+#define BNX2_EMAC_RX_STAT_DOT3STATSALIGNMENTERRORS	0x0000151c
+#define BNX2_EMAC_RX_STAT_DOT3STATSCARRIERSENSEERRORS	0x00001520
+#define BNX2_EMAC_RX_STAT_XONPAUSEFRAMESRECEIVED	0x00001524
+#define BNX2_EMAC_RX_STAT_XOFFPAUSEFRAMESRECEIVED	0x00001528
+#define BNX2_EMAC_RX_STAT_MACCONTROLFRAMESRECEIVED	0x0000152c
+#define BNX2_EMAC_RX_STAT_XOFFSTATEENTERED		0x00001530
+#define BNX2_EMAC_RX_STAT_DOT3STATSFRAMESTOOLONG	0x00001534
+#define BNX2_EMAC_RX_STAT_ETHERSTATSJABBERS		0x00001538
+#define BNX2_EMAC_RX_STAT_ETHERSTATSUNDERSIZEPKTS	0x0000153c
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS64OCTETS	0x00001540
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS65OCTETSTO127OCTETS	0x00001544
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS128OCTETSTO255OCTETS	0x00001548
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS256OCTETSTO511OCTETS	0x0000154c
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS512OCTETSTO1023OCTETS	0x00001550
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS1024OCTETSTO1522OCTETS	0x00001554
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS1523OCTETSTO9022OCTETS	0x00001558
+#define BNX2_EMAC_RXMAC_DEBUG0				0x0000155c
+#define BNX2_EMAC_RXMAC_DEBUG1				0x00001560
+#define BNX2_EMAC_RXMAC_DEBUG1_LENGTH_NE_BYTE_COUNT	 (1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG1_LENGTH_OUT_RANGE		 (1L<<1)
+#define BNX2_EMAC_RXMAC_DEBUG1_BAD_CRC			 (1L<<2)
+#define BNX2_EMAC_RXMAC_DEBUG1_RX_ERROR			 (1L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG1_ALIGN_ERROR		 (1L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG1_LAST_DATA		 (1L<<5)
+#define BNX2_EMAC_RXMAC_DEBUG1_ODD_BYTE_START		 (1L<<6)
+#define BNX2_EMAC_RXMAC_DEBUG1_BYTE_COUNT		 (0xffffL<<7)
+#define BNX2_EMAC_RXMAC_DEBUG1_SLOT_TIME		 (0xffL<<23)
+
+#define BNX2_EMAC_RXMAC_DEBUG2				0x00001564
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE			 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SFD		 (0x1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_DATA		 (0x2L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SKEEP		 (0x3L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_EXT		 (0x4L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_DROP		 (0x5L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SDROP		 (0x6L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_FC		 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE		 (0xfL<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_IDLE		 (0x0L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA0		 (0x1L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA1		 (0x2L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA2		 (0x3L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA3		 (0x4L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_ABORT		 (0x5L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_WAIT		 (0x6L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_STATUS		 (0x7L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_LAST		 (0x8L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_BYTE_IN			 (0xffL<<7)
+#define BNX2_EMAC_RXMAC_DEBUG2_FALSEC			 (1L<<15)
+#define BNX2_EMAC_RXMAC_DEBUG2_TAGGED			 (1L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE		 (1L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE_IDLE		 (0L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE_PAUSED	 (1L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_SE_COUNTER		 (0xfL<<19)
+#define BNX2_EMAC_RXMAC_DEBUG2_QUANTA			 (0x1fL<<23)
+
+#define BNX2_EMAC_RXMAC_DEBUG3				0x00001568
+#define BNX2_EMAC_RXMAC_DEBUG3_PAUSE_CTR		 (0xffffL<<0)
+#define BNX2_EMAC_RXMAC_DEBUG3_TMP_PAUSE_CTR		 (0xffffL<<16)
+
+#define BNX2_EMAC_RXMAC_DEBUG4				0x0000156c
+#define BNX2_EMAC_RXMAC_DEBUG4_TYPE_FIELD		 (0xffffL<<0)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE		 (0x3fL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_IDLE		 (0x0L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UMAC2		 (0x1L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UMAC3		 (0x2L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UNI		 (0x3L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MMAC2		 (0x7L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MMAC3		 (0x5L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA1		 (0x6L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA2		 (0x7L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA3		 (0x8L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC2		 (0x9L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC3		 (0xaL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MWAIT1	 (0xeL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MWAIT2	 (0xfL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MCHECK	 (0x10L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC		 (0x11L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC2		 (0x12L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC3		 (0x13L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA1		 (0x14L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA2		 (0x15L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA3		 (0x16L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BTYPE		 (0x17L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC		 (0x18L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PTYPE		 (0x19L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_CMD		 (0x1aL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MAC		 (0x1bL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_LATCH		 (0x1cL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_XOFF		 (0x1dL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_XON		 (0x1eL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PAUSED	 (0x1fL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_NPAUSED	 (0x20L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_TTYPE		 (0x21L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_TVAL		 (0x22L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA1		 (0x23L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA2		 (0x24L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA3		 (0x25L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTYPE		 (0x26L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTTYPE	 (0x27L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTVAL		 (0x28L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MTYPE		 (0x29L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_DROP		 (0x2aL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_DROP_PKT			 (1L<<22)
+#define BNX2_EMAC_RXMAC_DEBUG4_SLOT_FILLED		 (1L<<23)
+#define BNX2_EMAC_RXMAC_DEBUG4_FALSE_CARRIER		 (1L<<24)
+#define BNX2_EMAC_RXMAC_DEBUG4_LAST_DATA		 (1L<<25)
+#define BNX2_EMAC_RXMAC_DEBUG4_sfd_FOUND		 (1L<<26)
+#define BNX2_EMAC_RXMAC_DEBUG4_ADVANCE			 (1L<<27)
+#define BNX2_EMAC_RXMAC_DEBUG4_START			 (1L<<28)
+
+#define BNX2_EMAC_RXMAC_DEBUG5				0x00001570
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM			 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_IDLE		 (0L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_WAIT_EOF	 (1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_WAIT_STAT	 (2L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4FCRC	 (3L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4RDE	 (4L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4ALL	 (5L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_1WD_WAIT_STAT	 (6L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1		 (0x7L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_VDW		 (0x0L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_STAT		 (0x1L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_AEOF		 (0x2L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_NEOF		 (0x3L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SOF		 (0x4L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SAEOF		 (0x6L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SNEOF		 (0x7L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_EOF_DETECTED		 (1L<<7)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF0		 (0x7L<<8)
+#define BNX2_EMAC_RXMAC_DEBUG5_RPM_IDI_FIFO_FULL	 (1L<<11)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_CCODE		 (1L<<12)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_DATA		 (1L<<13)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_STAT		 (1L<<14)
+#define BNX2_EMAC_RXMAC_DEBUG5_CLR_STAT			 (1L<<15)
+#define BNX2_EMAC_RXMAC_DEBUG5_IDI_RPM_CCODE		 (0x3L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG5_IDI_RPM_ACCEPT		 (1L<<19)
+#define BNX2_EMAC_RXMAC_DEBUG5_FMLEN			 (0xfffL<<20)
+
+#define BNX2_EMAC_RX_STAT_AC0				0x00001580
+#define BNX2_EMAC_RX_STAT_AC1				0x00001584
+#define BNX2_EMAC_RX_STAT_AC2				0x00001588
+#define BNX2_EMAC_RX_STAT_AC3				0x0000158c
+#define BNX2_EMAC_RX_STAT_AC4				0x00001590
+#define BNX2_EMAC_RX_STAT_AC5				0x00001594
+#define BNX2_EMAC_RX_STAT_AC6				0x00001598
+#define BNX2_EMAC_RX_STAT_AC7				0x0000159c
+#define BNX2_EMAC_RX_STAT_AC8				0x000015a0
+#define BNX2_EMAC_RX_STAT_AC9				0x000015a4
+#define BNX2_EMAC_RX_STAT_AC10				0x000015a8
+#define BNX2_EMAC_RX_STAT_AC11				0x000015ac
+#define BNX2_EMAC_RX_STAT_AC12				0x000015b0
+#define BNX2_EMAC_RX_STAT_AC13				0x000015b4
+#define BNX2_EMAC_RX_STAT_AC14				0x000015b8
+#define BNX2_EMAC_RX_STAT_AC15				0x000015bc
+#define BNX2_EMAC_RX_STAT_AC16				0x000015c0
+#define BNX2_EMAC_RX_STAT_AC17				0x000015c4
+#define BNX2_EMAC_RX_STAT_AC18				0x000015c8
+#define BNX2_EMAC_RX_STAT_AC19				0x000015cc
+#define BNX2_EMAC_RX_STAT_AC20				0x000015d0
+#define BNX2_EMAC_RX_STAT_AC21				0x000015d4
+#define BNX2_EMAC_RX_STAT_AC22				0x000015d8
+#define BNX2_EMAC_RXMAC_SUC_DBG_OVERRUNVEC		0x000015dc
+#define BNX2_EMAC_TX_STAT_IFHCOUTOCTETS			0x00001600
+#define BNX2_EMAC_TX_STAT_IFHCOUTBADOCTETS		0x00001604
+#define BNX2_EMAC_TX_STAT_ETHERSTATSCOLLISIONS		0x00001608
+#define BNX2_EMAC_TX_STAT_OUTXONSENT			0x0000160c
+#define BNX2_EMAC_TX_STAT_OUTXOFFSENT			0x00001610
+#define BNX2_EMAC_TX_STAT_FLOWCONTROLDONE		0x00001614
+#define BNX2_EMAC_TX_STAT_DOT3STATSSINGLECOLLISIONFRAMES	0x00001618
+#define BNX2_EMAC_TX_STAT_DOT3STATSMULTIPLECOLLISIONFRAMES	0x0000161c
+#define BNX2_EMAC_TX_STAT_DOT3STATSDEFERREDTRANSMISSIONS	0x00001620
+#define BNX2_EMAC_TX_STAT_DOT3STATSEXCESSIVECOLLISIONS	0x00001624
+#define BNX2_EMAC_TX_STAT_DOT3STATSLATECOLLISIONS	0x00001628
+#define BNX2_EMAC_TX_STAT_IFHCOUTUCASTPKTS		0x0000162c
+#define BNX2_EMAC_TX_STAT_IFHCOUTMULTICASTPKTS		0x00001630
+#define BNX2_EMAC_TX_STAT_IFHCOUTBROADCASTPKTS		0x00001634
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS64OCTETS	0x00001638
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS65OCTETSTO127OCTETS	0x0000163c
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS128OCTETSTO255OCTETS	0x00001640
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS256OCTETSTO511OCTETS	0x00001644
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS512OCTETSTO1023OCTETS	0x00001648
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS1024OCTETSTO1522OCTETS	0x0000164c
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS1523OCTETSTO9022OCTETS	0x00001650
+#define BNX2_EMAC_TX_STAT_DOT3STATSINTERNALMACTRANSMITERRORS	0x00001654
+#define BNX2_EMAC_TXMAC_DEBUG0				0x00001658
+#define BNX2_EMAC_TXMAC_DEBUG1				0x0000165c
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE		 (0xfL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_START0		 (0x1L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA0		 (0x4L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA1		 (0x5L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA2		 (0x6L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA3		 (0x7L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_WAIT0		 (0x8L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_WAIT1		 (0x9L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_CRS_ENABLE		 (1L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG1_BAD_CRC			 (1L<<5)
+#define BNX2_EMAC_TXMAC_DEBUG1_SE_COUNTER		 (0xfL<<6)
+#define BNX2_EMAC_TXMAC_DEBUG1_SEND_PAUSE		 (1L<<10)
+#define BNX2_EMAC_TXMAC_DEBUG1_LATE_COLLISION		 (1L<<11)
+#define BNX2_EMAC_TXMAC_DEBUG1_MAX_DEFER		 (1L<<12)
+#define BNX2_EMAC_TXMAC_DEBUG1_DEFERRED			 (1L<<13)
+#define BNX2_EMAC_TXMAC_DEBUG1_ONE_BYTE			 (1L<<14)
+#define BNX2_EMAC_TXMAC_DEBUG1_IPG_TIME			 (0xfL<<15)
+#define BNX2_EMAC_TXMAC_DEBUG1_SLOT_TIME		 (0xffL<<19)
+
+#define BNX2_EMAC_TXMAC_DEBUG2				0x00001660
+#define BNX2_EMAC_TXMAC_DEBUG2_BACK_OFF			 (0x3ffL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG2_BYTE_COUNT		 (0xffffL<<10)
+#define BNX2_EMAC_TXMAC_DEBUG2_COL_COUNT		 (0x1fL<<26)
+#define BNX2_EMAC_TXMAC_DEBUG2_COL_BIT			 (1L<<31)
+
+#define BNX2_EMAC_TXMAC_DEBUG3				0x00001664
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE			 (0xfL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_PRE1		 (0x1L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_PRE2		 (0x2L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_SFD		 (0x3L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_DATA		 (0x4L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_CRC1		 (0x5L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_CRC2		 (0x6L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_EXT		 (0x7L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_STATB		 (0x8L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_STATG		 (0x9L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_JAM		 (0xaL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_EJAM		 (0xbL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_BJAM		 (0xcL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_SWAIT		 (0xdL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_BACKOFF		 (0xeL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE		 (0x7L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_IDLE		 (0x0L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_WAIT		 (0x1L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_UNI		 (0x2L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_MC		 (0x3L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC2		 (0x4L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC3		 (0x5L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC		 (0x6L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_CRS_DONE			 (1L<<7)
+#define BNX2_EMAC_TXMAC_DEBUG3_XOFF			 (1L<<8)
+#define BNX2_EMAC_TXMAC_DEBUG3_SE_COUNTER		 (0xfL<<9)
+#define BNX2_EMAC_TXMAC_DEBUG3_QUANTA_COUNTER		 (0x1fL<<13)
+
+#define BNX2_EMAC_TXMAC_DEBUG4				0x00001668
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_COUNTER		 (0xffffL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE		 (0xfL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_IDLE		 (0x0L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA1		 (0x2L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA2		 (0x3L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA3		 (0x6L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC1		 (0x7L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC2		 (0x5L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC3		 (0x4L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_TYPE		 (0xcL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CMD		 (0xeL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_TIME		 (0xaL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CRC1		 (0x8L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CRC2		 (0x9L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_WAIT		 (0xdL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_STATS0_VALID		 (1L<<20)
+#define BNX2_EMAC_TXMAC_DEBUG4_APPEND_CRC		 (1L<<21)
+#define BNX2_EMAC_TXMAC_DEBUG4_SLOT_FILLED		 (1L<<22)
+#define BNX2_EMAC_TXMAC_DEBUG4_MAX_DEFER		 (1L<<23)
+#define BNX2_EMAC_TXMAC_DEBUG4_SEND_EXTEND		 (1L<<24)
+#define BNX2_EMAC_TXMAC_DEBUG4_SEND_PADDING		 (1L<<25)
+#define BNX2_EMAC_TXMAC_DEBUG4_EOF_LOC			 (1L<<26)
+#define BNX2_EMAC_TXMAC_DEBUG4_COLLIDING		 (1L<<27)
+#define BNX2_EMAC_TXMAC_DEBUG4_COL_IN			 (1L<<28)
+#define BNX2_EMAC_TXMAC_DEBUG4_BURSTING			 (1L<<29)
+#define BNX2_EMAC_TXMAC_DEBUG4_ADVANCE			 (1L<<30)
+#define BNX2_EMAC_TXMAC_DEBUG4_GO			 (1L<<31)
+
+#define BNX2_EMAC_TX_STAT_AC0				0x00001680
+#define BNX2_EMAC_TX_STAT_AC1				0x00001684
+#define BNX2_EMAC_TX_STAT_AC2				0x00001688
+#define BNX2_EMAC_TX_STAT_AC3				0x0000168c
+#define BNX2_EMAC_TX_STAT_AC4				0x00001690
+#define BNX2_EMAC_TX_STAT_AC5				0x00001694
+#define BNX2_EMAC_TX_STAT_AC6				0x00001698
+#define BNX2_EMAC_TX_STAT_AC7				0x0000169c
+#define BNX2_EMAC_TX_STAT_AC8				0x000016a0
+#define BNX2_EMAC_TX_STAT_AC9				0x000016a4
+#define BNX2_EMAC_TX_STAT_AC10				0x000016a8
+#define BNX2_EMAC_TX_STAT_AC11				0x000016ac
+#define BNX2_EMAC_TX_STAT_AC12				0x000016b0
+#define BNX2_EMAC_TX_STAT_AC13				0x000016b4
+#define BNX2_EMAC_TX_STAT_AC14				0x000016b8
+#define BNX2_EMAC_TX_STAT_AC15				0x000016bc
+#define BNX2_EMAC_TX_STAT_AC16				0x000016c0
+#define BNX2_EMAC_TX_STAT_AC17				0x000016c4
+#define BNX2_EMAC_TX_STAT_AC18				0x000016c8
+#define BNX2_EMAC_TX_STAT_AC19				0x000016cc
+#define BNX2_EMAC_TX_STAT_AC20				0x000016d0
+#define BNX2_EMAC_TX_STAT_AC21				0x000016d4
+#define BNX2_EMAC_TXMAC_SUC_DBG_OVERRUNVEC		0x000016d8
+
+
+/*
+ *  rpm_reg definition
+ *  offset: 0x1800
+ */
+#define BNX2_RPM_COMMAND				0x00001800
+#define BNX2_RPM_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RPM_COMMAND_OVERRUN_ABORT			 (1L<<4)
+
+#define BNX2_RPM_STATUS					0x00001804
+#define BNX2_RPM_STATUS_MBUF_WAIT			 (1L<<0)
+#define BNX2_RPM_STATUS_FREE_WAIT			 (1L<<1)
+
+#define BNX2_RPM_CONFIG					0x00001808
+#define BNX2_RPM_CONFIG_NO_PSD_HDR_CKSUM		 (1L<<0)
+#define BNX2_RPM_CONFIG_ACPI_ENA			 (1L<<1)
+#define BNX2_RPM_CONFIG_ACPI_KEEP			 (1L<<2)
+#define BNX2_RPM_CONFIG_MP_KEEP				 (1L<<3)
+#define BNX2_RPM_CONFIG_SORT_VECT_VAL			 (0xfL<<4)
+#define BNX2_RPM_CONFIG_IGNORE_VLAN			 (1L<<31)
+
+#define BNX2_RPM_VLAN_MATCH0				0x00001810
+#define BNX2_RPM_VLAN_MATCH0_RPM_VLAN_MTCH0_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH1				0x00001814
+#define BNX2_RPM_VLAN_MATCH1_RPM_VLAN_MTCH1_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH2				0x00001818
+#define BNX2_RPM_VLAN_MATCH2_RPM_VLAN_MTCH2_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH3				0x0000181c
+#define BNX2_RPM_VLAN_MATCH3_RPM_VLAN_MTCH3_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_SORT_USER0				0x00001820
+#define BNX2_RPM_SORT_USER0_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER0_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER0_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER0_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER0_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER0_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER0_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER0_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER1				0x00001824
+#define BNX2_RPM_SORT_USER1_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER1_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER1_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER1_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER1_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER1_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER1_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER1_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER2				0x00001828
+#define BNX2_RPM_SORT_USER2_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER2_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER2_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER2_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER2_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER2_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER2_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER2_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER3				0x0000182c
+#define BNX2_RPM_SORT_USER3_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER3_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER3_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER3_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER3_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER3_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER3_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER3_ENA				 (1L<<31)
+
+#define BNX2_RPM_STAT_L2_FILTER_DISCARDS		0x00001840
+#define BNX2_RPM_STAT_RULE_CHECKER_DISCARDS		0x00001844
+#define BNX2_RPM_STAT_IFINFTQDISCARDS			0x00001848
+#define BNX2_RPM_STAT_IFINMBUFDISCARD			0x0000184c
+#define BNX2_RPM_STAT_RULE_CHECKER_P4_HIT		0x00001850
+#define BNX2_RPM_STAT_AC0				0x00001880
+#define BNX2_RPM_STAT_AC1				0x00001884
+#define BNX2_RPM_STAT_AC2				0x00001888
+#define BNX2_RPM_STAT_AC3				0x0000188c
+#define BNX2_RPM_STAT_AC4				0x00001890
+#define BNX2_RPM_RC_CNTL_0				0x00001900
+#define BNX2_RPM_RC_CNTL_0_OFFSET			 (0xffL<<0)
+#define BNX2_RPM_RC_CNTL_0_CLASS			 (0x7L<<8)
+#define BNX2_RPM_RC_CNTL_0_PRIORITY			 (1L<<11)
+#define BNX2_RPM_RC_CNTL_0_P4				 (1L<<12)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE			 (0x7L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_START		 (0L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_IP			 (1L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_TCP			 (2L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_UDP			 (3L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_DATA		 (4L<<13)
+#define BNX2_RPM_RC_CNTL_0_COMP				 (0x3L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_EQUAL			 (0L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_NEQUAL			 (1L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_GREATER			 (2L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_LESS			 (3L<<16)
+#define BNX2_RPM_RC_CNTL_0_SBIT				 (1L<<19)
+#define BNX2_RPM_RC_CNTL_0_CMDSEL			 (0xfL<<20)
+#define BNX2_RPM_RC_CNTL_0_MAP				 (1L<<24)
+#define BNX2_RPM_RC_CNTL_0_DISCARD			 (1L<<25)
+#define BNX2_RPM_RC_CNTL_0_MASK				 (1L<<26)
+#define BNX2_RPM_RC_CNTL_0_P1				 (1L<<27)
+#define BNX2_RPM_RC_CNTL_0_P2				 (1L<<28)
+#define BNX2_RPM_RC_CNTL_0_P3				 (1L<<29)
+#define BNX2_RPM_RC_CNTL_0_NBIT				 (1L<<30)
+
+#define BNX2_RPM_RC_VALUE_MASK_0			0x00001904
+#define BNX2_RPM_RC_VALUE_MASK_0_VALUE			 (0xffffL<<0)
+#define BNX2_RPM_RC_VALUE_MASK_0_MASK			 (0xffffL<<16)
+
+#define BNX2_RPM_RC_CNTL_1				0x00001908
+#define BNX2_RPM_RC_CNTL_1_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_1_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_1			0x0000190c
+#define BNX2_RPM_RC_CNTL_2				0x00001910
+#define BNX2_RPM_RC_CNTL_2_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_2_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_2			0x00001914
+#define BNX2_RPM_RC_CNTL_3				0x00001918
+#define BNX2_RPM_RC_CNTL_3_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_3_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_3			0x0000191c
+#define BNX2_RPM_RC_CNTL_4				0x00001920
+#define BNX2_RPM_RC_CNTL_4_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_4_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_4			0x00001924
+#define BNX2_RPM_RC_CNTL_5				0x00001928
+#define BNX2_RPM_RC_CNTL_5_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_5_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_5			0x0000192c
+#define BNX2_RPM_RC_CNTL_6				0x00001930
+#define BNX2_RPM_RC_CNTL_6_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_6_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_6			0x00001934
+#define BNX2_RPM_RC_CNTL_7				0x00001938
+#define BNX2_RPM_RC_CNTL_7_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_7_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_7			0x0000193c
+#define BNX2_RPM_RC_CNTL_8				0x00001940
+#define BNX2_RPM_RC_CNTL_8_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_8_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_8			0x00001944
+#define BNX2_RPM_RC_CNTL_9				0x00001948
+#define BNX2_RPM_RC_CNTL_9_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_9_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_9			0x0000194c
+#define BNX2_RPM_RC_CNTL_10				0x00001950
+#define BNX2_RPM_RC_CNTL_10_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_10_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_10			0x00001954
+#define BNX2_RPM_RC_CNTL_11				0x00001958
+#define BNX2_RPM_RC_CNTL_11_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_11_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_11			0x0000195c
+#define BNX2_RPM_RC_CNTL_12				0x00001960
+#define BNX2_RPM_RC_CNTL_12_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_12_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_12			0x00001964
+#define BNX2_RPM_RC_CNTL_13				0x00001968
+#define BNX2_RPM_RC_CNTL_13_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_13_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_13			0x0000196c
+#define BNX2_RPM_RC_CNTL_14				0x00001970
+#define BNX2_RPM_RC_CNTL_14_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_14_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_14			0x00001974
+#define BNX2_RPM_RC_CNTL_15				0x00001978
+#define BNX2_RPM_RC_CNTL_15_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_15_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_15			0x0000197c
+#define BNX2_RPM_RC_CONFIG				0x00001980
+#define BNX2_RPM_RC_CONFIG_RULE_ENABLE			 (0xffffL<<0)
+#define BNX2_RPM_RC_CONFIG_DEF_CLASS			 (0x7L<<24)
+
+#define BNX2_RPM_DEBUG0					0x00001984
+#define BNX2_RPM_DEBUG0_FM_BCNT				 (0xffffL<<0)
+#define BNX2_RPM_DEBUG0_T_DATA_OFST_VLD			 (1L<<16)
+#define BNX2_RPM_DEBUG0_T_UDP_OFST_VLD			 (1L<<17)
+#define BNX2_RPM_DEBUG0_T_TCP_OFST_VLD			 (1L<<18)
+#define BNX2_RPM_DEBUG0_T_IP_OFST_VLD			 (1L<<19)
+#define BNX2_RPM_DEBUG0_IP_MORE_FRGMT			 (1L<<20)
+#define BNX2_RPM_DEBUG0_T_IP_NO_TCP_UDP_HDR		 (1L<<21)
+#define BNX2_RPM_DEBUG0_LLC_SNAP			 (1L<<22)
+#define BNX2_RPM_DEBUG0_FM_STARTED			 (1L<<23)
+#define BNX2_RPM_DEBUG0_DONE				 (1L<<24)
+#define BNX2_RPM_DEBUG0_WAIT_4_DONE			 (1L<<25)
+#define BNX2_RPM_DEBUG0_USE_TPBUF_CKSUM			 (1L<<26)
+#define BNX2_RPM_DEBUG0_RX_NO_PSD_HDR_CKSUM		 (1L<<27)
+#define BNX2_RPM_DEBUG0_IGNORE_VLAN			 (1L<<28)
+#define BNX2_RPM_DEBUG0_RP_ENA_ACTIVE			 (1L<<31)
+
+#define BNX2_RPM_DEBUG1					0x00001988
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IDLE			 (0L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B6_ALL		 (1L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B2_IPLLC	 (2L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B6_IP		 (4L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B2_IP		 (8L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IP_START		 (16L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IP			 (32L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_TCP			 (64L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_UDP			 (128L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_AH			 (256L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ESP			 (512L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ESP_PAYLOAD		 (1024L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_DATA			 (2048L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ADD_CARRY		 (0x2000L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ADD_CARRYOUT		 (0x4000L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_LATCH_RESULT		 (0x8000L<<0)
+#define BNX2_RPM_DEBUG1_HDR_BCNT			 (0x7ffL<<16)
+#define BNX2_RPM_DEBUG1_UNKNOWN_ETYPE_D			 (1L<<28)
+#define BNX2_RPM_DEBUG1_VLAN_REMOVED_D2			 (1L<<29)
+#define BNX2_RPM_DEBUG1_VLAN_REMOVED_D1			 (1L<<30)
+#define BNX2_RPM_DEBUG1_EOF_0XTRA_WD			 (1L<<31)
+
+#define BNX2_RPM_DEBUG2					0x0000198c
+#define BNX2_RPM_DEBUG2_CMD_HIT_VEC			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG2_IP_BCNT				 (0xffL<<16)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M4			 (1L<<24)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M3			 (1L<<25)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M2			 (1L<<26)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M1			 (1L<<27)
+#define BNX2_RPM_DEBUG2_IPIPE_EMPTY			 (1L<<28)
+#define BNX2_RPM_DEBUG2_FM_DISCARD			 (1L<<29)
+#define BNX2_RPM_DEBUG2_LAST_RULE_IN_FM_D2		 (1L<<30)
+#define BNX2_RPM_DEBUG2_LAST_RULE_IN_FM_D1		 (1L<<31)
+
+#define BNX2_RPM_DEBUG3					0x00001990
+#define BNX2_RPM_DEBUG3_AVAIL_MBUF_PTR			 (0x1ffL<<0)
+#define BNX2_RPM_DEBUG3_RDE_RLUPQ_WR_REQ_INT		 (1L<<9)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_WR_LAST_INT		 (1L<<10)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_WR_REQ_INT		 (1L<<11)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_FREE_REQ		 (1L<<12)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_ALLOC_REQ		 (1L<<13)
+#define BNX2_RPM_DEBUG3_DFSM_MBUF_NOTAVAIL		 (1L<<14)
+#define BNX2_RPM_DEBUG3_RBUF_RDE_SOF_DROP		 (1L<<15)
+#define BNX2_RPM_DEBUG3_DFIFO_VLD_ENTRY_CT		 (0xfL<<16)
+#define BNX2_RPM_DEBUG3_RDE_SRC_FIFO_ALMFULL		 (1L<<21)
+#define BNX2_RPM_DEBUG3_DROP_NXT_VLD			 (1L<<22)
+#define BNX2_RPM_DEBUG3_DROP_NXT			 (1L<<23)
+#define BNX2_RPM_DEBUG3_FTQ_FSM				 (0x3L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_IDLE			 (0x0L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_WAIT_ACK		 (0x1L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_WAIT_FREE		 (0x2L<<24)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM			 (0x3L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_SOF		 (0x0L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_GET_MBUF		 (0x1L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_DMA_DATA		 (0x2L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_DATA		 (0x3L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_EOF		 (0x4L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_MF_ACK		 (0x5L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_DROP_NXT_VLD	 (0x6L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_DONE		 (0x7L<<26)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM			 (1L<<29)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM_IDLE			 (0L<<29)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM_WAIT_ACK		 (1L<<29)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM			 (1L<<30)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM_ET_MBUF		 (0x0L<<30)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM_IVE_MBUF		 (0x1L<<30)
+#define BNX2_RPM_DEBUG3_CCODE_EOF_ERROR			 (1L<<31)
+
+#define BNX2_RPM_DEBUG4					0x00001994
+#define BNX2_RPM_DEBUG4_DFSM_MBUF_CLUSTER		 (0x1ffffffL<<0)
+#define BNX2_RPM_DEBUG4_DFIFO_CUR_CCODE			 (0x7L<<25)
+#define BNX2_RPM_DEBUG4_MBWRITE_FSM			 (0x7L<<28)
+#define BNX2_RPM_DEBUG4_DFIFO_EMPTY			 (1L<<31)
+
+#define BNX2_RPM_DEBUG5					0x00001998
+#define BNX2_RPM_DEBUG5_RDROP_WPTR			 (0x1fL<<0)
+#define BNX2_RPM_DEBUG5_RDROP_ACPI_RPTR			 (0x1fL<<5)
+#define BNX2_RPM_DEBUG5_RDROP_MC_RPTR			 (0x1fL<<10)
+#define BNX2_RPM_DEBUG5_RDROP_RC_RPTR			 (0x1fL<<15)
+#define BNX2_RPM_DEBUG5_RDROP_ACPI_EMPTY		 (1L<<20)
+#define BNX2_RPM_DEBUG5_RDROP_MC_EMPTY			 (1L<<21)
+#define BNX2_RPM_DEBUG5_RDROP_AEOF_VEC_AT_RDROP_MC_RPTR	 (1L<<22)
+#define BNX2_RPM_DEBUG5_HOLDREG_WOL_DROP_INT		 (1L<<23)
+#define BNX2_RPM_DEBUG5_HOLDREG_DISCARD			 (1L<<24)
+#define BNX2_RPM_DEBUG5_HOLDREG_MBUF_NOTAVAIL		 (1L<<25)
+#define BNX2_RPM_DEBUG5_HOLDREG_MC_EMPTY		 (1L<<26)
+#define BNX2_RPM_DEBUG5_HOLDREG_RC_EMPTY		 (1L<<27)
+#define BNX2_RPM_DEBUG5_HOLDREG_FC_EMPTY		 (1L<<28)
+#define BNX2_RPM_DEBUG5_HOLDREG_ACPI_EMPTY		 (1L<<29)
+#define BNX2_RPM_DEBUG5_HOLDREG_FULL_T			 (1L<<30)
+#define BNX2_RPM_DEBUG5_HOLDREG_RD			 (1L<<31)
+
+#define BNX2_RPM_DEBUG6					0x0000199c
+#define BNX2_RPM_DEBUG6_ACPI_VEC			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG6_VEC				 (0xffffL<<16)
+
+#define BNX2_RPM_DEBUG7					0x000019a0
+#define BNX2_RPM_DEBUG7_RPM_DBG7_LAST_CRC		 (0xffffffffL<<0)
+
+#define BNX2_RPM_DEBUG8					0x000019a4
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM			 (0xfL<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_IDLE		 (0L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W1_ADDR		 (1L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W2_ADDR		 (2L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W3_ADDR		 (3L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_WAIT_THBUF	 (4L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W3_DATA		 (5L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W0_ADDR		 (6L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W1_ADDR		 (7L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W2_ADDR		 (8L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W3_ADDR		 (9L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_WAIT_THBUF		 (10L<<0)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_W0			 (1L<<4)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_W3_DATA		 (1L<<5)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_WAIT		 (1L<<6)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_W3		 (1L<<7)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_W2		 (1L<<8)
+#define BNX2_RPM_DEBUG8_EOF_W_LTEQ6_VLDBYTES		 (1L<<9)
+#define BNX2_RPM_DEBUG8_EOF_W_LTEQ4_VLDBYTES		 (1L<<10)
+#define BNX2_RPM_DEBUG8_NXT_EOF_W_12_VLDBYTES		 (1L<<11)
+#define BNX2_RPM_DEBUG8_EOF_DET				 (1L<<12)
+#define BNX2_RPM_DEBUG8_SOF_DET				 (1L<<13)
+#define BNX2_RPM_DEBUG8_WAIT_4_SOF			 (1L<<14)
+#define BNX2_RPM_DEBUG8_ALL_DONE			 (1L<<15)
+#define BNX2_RPM_DEBUG8_THBUF_ADDR			 (0x7fL<<16)
+#define BNX2_RPM_DEBUG8_BYTE_CTR			 (0xffL<<24)
+
+#define BNX2_RPM_DEBUG9					0x000019a8
+#define BNX2_RPM_DEBUG9_OUTFIFO_COUNT			 (0x7L<<0)
+#define BNX2_RPM_DEBUG9_RDE_ACPI_RDY			 (1L<<3)
+#define BNX2_RPM_DEBUG9_VLD_RD_ENTRY_CT			 (0x7L<<4)
+#define BNX2_RPM_DEBUG9_OUTFIFO_OVERRUN_OCCURRED	 (1L<<28)
+#define BNX2_RPM_DEBUG9_INFIFO_OVERRUN_OCCURRED		 (1L<<29)
+#define BNX2_RPM_DEBUG9_ACPI_MATCH_INT			 (1L<<30)
+#define BNX2_RPM_DEBUG9_ACPI_ENABLE_SYN			 (1L<<31)
+
+#define BNX2_RPM_ACPI_DBG_BUF_W00			0x000019c0
+#define BNX2_RPM_ACPI_DBG_BUF_W01			0x000019c4
+#define BNX2_RPM_ACPI_DBG_BUF_W02			0x000019c8
+#define BNX2_RPM_ACPI_DBG_BUF_W03			0x000019cc
+#define BNX2_RPM_ACPI_DBG_BUF_W10			0x000019d0
+#define BNX2_RPM_ACPI_DBG_BUF_W11			0x000019d4
+#define BNX2_RPM_ACPI_DBG_BUF_W12			0x000019d8
+#define BNX2_RPM_ACPI_DBG_BUF_W13			0x000019dc
+#define BNX2_RPM_ACPI_DBG_BUF_W20			0x000019e0
+#define BNX2_RPM_ACPI_DBG_BUF_W21			0x000019e4
+#define BNX2_RPM_ACPI_DBG_BUF_W22			0x000019e8
+#define BNX2_RPM_ACPI_DBG_BUF_W23			0x000019ec
+#define BNX2_RPM_ACPI_DBG_BUF_W30			0x000019f0
+#define BNX2_RPM_ACPI_DBG_BUF_W31			0x000019f4
+#define BNX2_RPM_ACPI_DBG_BUF_W32			0x000019f8
+#define BNX2_RPM_ACPI_DBG_BUF_W33			0x000019fc
+
+
+/*
+ *  rbuf_reg definition
+ *  offset: 0x200000
+ */
+#define BNX2_RBUF_COMMAND				0x00200000
+#define BNX2_RBUF_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RBUF_COMMAND_FREE_INIT			 (1L<<1)
+#define BNX2_RBUF_COMMAND_RAM_INIT			 (1L<<2)
+#define BNX2_RBUF_COMMAND_OVER_FREE			 (1L<<4)
+#define BNX2_RBUF_COMMAND_ALLOC_REQ			 (1L<<5)
+
+#define BNX2_RBUF_STATUS1				0x00200004
+#define BNX2_RBUF_STATUS1_FREE_COUNT			 (0x3ffL<<0)
+
+#define BNX2_RBUF_STATUS2				0x00200008
+#define BNX2_RBUF_STATUS2_FREE_TAIL			 (0x3ffL<<0)
+#define BNX2_RBUF_STATUS2_FREE_HEAD			 (0x3ffL<<16)
+
+#define BNX2_RBUF_CONFIG				0x0020000c
+#define BNX2_RBUF_CONFIG_XOFF_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG_XON_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_FW_BUF_ALLOC				0x00200010
+#define BNX2_RBUF_FW_BUF_ALLOC_VALUE			 (0x1ffL<<7)
+
+#define BNX2_RBUF_FW_BUF_FREE				0x00200014
+#define BNX2_RBUF_FW_BUF_FREE_COUNT			 (0x7fL<<0)
+#define BNX2_RBUF_FW_BUF_FREE_TAIL			 (0x1ffL<<7)
+#define BNX2_RBUF_FW_BUF_FREE_HEAD			 (0x1ffL<<16)
+
+#define BNX2_RBUF_FW_BUF_SEL				0x00200018
+#define BNX2_RBUF_FW_BUF_SEL_COUNT			 (0x7fL<<0)
+#define BNX2_RBUF_FW_BUF_SEL_TAIL			 (0x1ffL<<7)
+#define BNX2_RBUF_FW_BUF_SEL_HEAD			 (0x1ffL<<16)
+
+#define BNX2_RBUF_CONFIG2				0x0020001c
+#define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_CONFIG3				0x00200020
+#define BNX2_RBUF_CONFIG3_CU_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_PKT_DATA				0x00208000
+#define BNX2_RBUF_CLIST_DATA				0x00210000
+#define BNX2_RBUF_BUF_DATA				0x00220000
+
+
+/*
+ *  rv2p_reg definition
+ *  offset: 0x2800
+ */
+#define BNX2_RV2P_COMMAND				0x00002800
+#define BNX2_RV2P_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RV2P_COMMAND_PROC1_INTRPT			 (1L<<1)
+#define BNX2_RV2P_COMMAND_PROC2_INTRPT			 (1L<<2)
+#define BNX2_RV2P_COMMAND_ABORT0			 (1L<<4)
+#define BNX2_RV2P_COMMAND_ABORT1			 (1L<<5)
+#define BNX2_RV2P_COMMAND_ABORT2			 (1L<<6)
+#define BNX2_RV2P_COMMAND_ABORT3			 (1L<<7)
+#define BNX2_RV2P_COMMAND_ABORT4			 (1L<<8)
+#define BNX2_RV2P_COMMAND_ABORT5			 (1L<<9)
+#define BNX2_RV2P_COMMAND_PROC1_RESET			 (1L<<16)
+#define BNX2_RV2P_COMMAND_PROC2_RESET			 (1L<<17)
+#define BNX2_RV2P_COMMAND_CTXIF_RESET			 (1L<<18)
+
+#define BNX2_RV2P_STATUS				0x00002804
+#define BNX2_RV2P_STATUS_ALWAYS_0			 (1L<<0)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT0_CNT		 (1L<<8)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT1_CNT		 (1L<<9)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT2_CNT		 (1L<<10)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT3_CNT		 (1L<<11)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT4_CNT		 (1L<<12)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT5_CNT		 (1L<<13)
+
+#define BNX2_RV2P_CONFIG				0x00002808
+#define BNX2_RV2P_CONFIG_STALL_PROC1			 (1L<<0)
+#define BNX2_RV2P_CONFIG_STALL_PROC2			 (1L<<1)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT0		 (1L<<8)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT1		 (1L<<9)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT2		 (1L<<10)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT3		 (1L<<11)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT4		 (1L<<12)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT5		 (1L<<13)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT0		 (1L<<16)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT1		 (1L<<17)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT2		 (1L<<18)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT3		 (1L<<19)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT4		 (1L<<20)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT5		 (1L<<21)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE			 (0xfL<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_256			 (0L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_512			 (1L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_1K			 (2L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_2K			 (3L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_4K			 (4L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_8K			 (5L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_16K			 (6L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_32K			 (7L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_64K			 (8L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_128K			 (9L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_256K			 (10L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_512K			 (11L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_1M			 (12L<<24)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_0			0x00002810
+#define BNX2_RV2P_GEN_BFR_ADDR_0_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_1			0x00002814
+#define BNX2_RV2P_GEN_BFR_ADDR_1_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_2			0x00002818
+#define BNX2_RV2P_GEN_BFR_ADDR_2_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_3			0x0000281c
+#define BNX2_RV2P_GEN_BFR_ADDR_3_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_INSTR_HIGH				0x00002830
+#define BNX2_RV2P_INSTR_HIGH_HIGH			 (0x1fL<<0)
+
+#define BNX2_RV2P_INSTR_LOW				0x00002834
+#define BNX2_RV2P_PROC1_ADDR_CMD			0x00002838
+#define BNX2_RV2P_PROC1_ADDR_CMD_ADD			 (0x3ffL<<0)
+#define BNX2_RV2P_PROC1_ADDR_CMD_RDWR			 (1L<<31)
+
+#define BNX2_RV2P_PROC2_ADDR_CMD			0x0000283c
+#define BNX2_RV2P_PROC2_ADDR_CMD_ADD			 (0x3ffL<<0)
+#define BNX2_RV2P_PROC2_ADDR_CMD_RDWR			 (1L<<31)
+
+#define BNX2_RV2P_PROC1_GRC_DEBUG			0x00002840
+#define BNX2_RV2P_PROC2_GRC_DEBUG			0x00002844
+#define BNX2_RV2P_GRC_PROC_DEBUG			0x00002848
+#define BNX2_RV2P_DEBUG_VECT_PEEK			0x0000284c
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+#define BNX2_RV2P_PFTQ_DATA				0x00002b40
+#define BNX2_RV2P_PFTQ_CMD				0x00002b78
+#define BNX2_RV2P_PFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_PFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_PFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_PFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_PFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_PFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_PFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_PFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_PFTQ_CTL				0x00002b7c
+#define BNX2_RV2P_PFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_PFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_PFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_PFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_PFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RV2P_TFTQ_DATA				0x00002b80
+#define BNX2_RV2P_TFTQ_CMD				0x00002bb8
+#define BNX2_RV2P_TFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_TFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_TFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_TFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_TFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_TFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_TFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_TFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_TFTQ_CTL				0x00002bbc
+#define BNX2_RV2P_TFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_TFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_TFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_TFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_TFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RV2P_MFTQ_DATA				0x00002bc0
+#define BNX2_RV2P_MFTQ_CMD				0x00002bf8
+#define BNX2_RV2P_MFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_MFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_MFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_MFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_MFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_MFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_MFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_MFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_MFTQ_CTL				0x00002bfc
+#define BNX2_RV2P_MFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_MFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_MFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_MFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_MFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  mq_reg definition
+ *  offset: 0x3c00
+ */
+#define BNX2_MQ_COMMAND					0x00003c00
+#define BNX2_MQ_COMMAND_ENABLED				 (1L<<0)
+#define BNX2_MQ_COMMAND_OVERFLOW			 (1L<<4)
+#define BNX2_MQ_COMMAND_WR_ERROR			 (1L<<5)
+#define BNX2_MQ_COMMAND_RD_ERROR			 (1L<<6)
+
+#define BNX2_MQ_STATUS					0x00003c04
+#define BNX2_MQ_STATUS_CTX_ACCESS_STAT			 (1L<<16)
+#define BNX2_MQ_STATUS_CTX_ACCESS64_STAT		 (1L<<17)
+#define BNX2_MQ_STATUS_PCI_STALL_STAT			 (1L<<18)
+
+#define BNX2_MQ_CONFIG					0x00003c08
+#define BNX2_MQ_CONFIG_TX_HIGH_PRI			 (1L<<0)
+#define BNX2_MQ_CONFIG_HALT_DIS				 (1L<<1)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE			 (0x7L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256		 (0L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_512		 (1L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_1K		 (2L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_2K		 (3L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_4K		 (4L<<4)
+#define BNX2_MQ_CONFIG_MAX_DEPTH			 (0x7fL<<8)
+#define BNX2_MQ_CONFIG_CUR_DEPTH			 (0x7fL<<20)
+
+#define BNX2_MQ_ENQUEUE1				0x00003c0c
+#define BNX2_MQ_ENQUEUE1_OFFSET				 (0x3fL<<2)
+#define BNX2_MQ_ENQUEUE1_CID				 (0x3fffL<<8)
+#define BNX2_MQ_ENQUEUE1_BYTE_MASK			 (0xfL<<24)
+#define BNX2_MQ_ENQUEUE1_KNL_MODE			 (1L<<28)
+
+#define BNX2_MQ_ENQUEUE2				0x00003c10
+#define BNX2_MQ_BAD_WR_ADDR				0x00003c14
+#define BNX2_MQ_BAD_RD_ADDR				0x00003c18
+#define BNX2_MQ_KNL_BYP_WIND_START			0x00003c1c
+#define BNX2_MQ_KNL_BYP_WIND_START_VALUE		 (0xfffffL<<12)
+
+#define BNX2_MQ_KNL_WIND_END				0x00003c20
+#define BNX2_MQ_KNL_WIND_END_VALUE			 (0xffffffL<<8)
+
+#define BNX2_MQ_KNL_WRITE_MASK1				0x00003c24
+#define BNX2_MQ_KNL_TX_MASK1				0x00003c28
+#define BNX2_MQ_KNL_CMD_MASK1				0x00003c2c
+#define BNX2_MQ_KNL_COND_ENQUEUE_MASK1			0x00003c30
+#define BNX2_MQ_KNL_RX_V2P_MASK1			0x00003c34
+#define BNX2_MQ_KNL_WRITE_MASK2				0x00003c38
+#define BNX2_MQ_KNL_TX_MASK2				0x00003c3c
+#define BNX2_MQ_KNL_CMD_MASK2				0x00003c40
+#define BNX2_MQ_KNL_COND_ENQUEUE_MASK2			0x00003c44
+#define BNX2_MQ_KNL_RX_V2P_MASK2			0x00003c48
+#define BNX2_MQ_KNL_BYP_WRITE_MASK1			0x00003c4c
+#define BNX2_MQ_KNL_BYP_TX_MASK1			0x00003c50
+#define BNX2_MQ_KNL_BYP_CMD_MASK1			0x00003c54
+#define BNX2_MQ_KNL_BYP_COND_ENQUEUE_MASK1		0x00003c58
+#define BNX2_MQ_KNL_BYP_RX_V2P_MASK1			0x00003c5c
+#define BNX2_MQ_KNL_BYP_WRITE_MASK2			0x00003c60
+#define BNX2_MQ_KNL_BYP_TX_MASK2			0x00003c64
+#define BNX2_MQ_KNL_BYP_CMD_MASK2			0x00003c68
+#define BNX2_MQ_KNL_BYP_COND_ENQUEUE_MASK2		0x00003c6c
+#define BNX2_MQ_KNL_BYP_RX_V2P_MASK2			0x00003c70
+#define BNX2_MQ_MEM_WR_ADDR				0x00003c74
+#define BNX2_MQ_MEM_WR_ADDR_VALUE			 (0x3fL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA0				0x00003c78
+#define BNX2_MQ_MEM_WR_DATA0_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA1				0x00003c7c
+#define BNX2_MQ_MEM_WR_DATA1_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA2				0x00003c80
+#define BNX2_MQ_MEM_WR_DATA2_VALUE			 (0x3fffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_ADDR				0x00003c84
+#define BNX2_MQ_MEM_RD_ADDR_VALUE			 (0x3fL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA0				0x00003c88
+#define BNX2_MQ_MEM_RD_DATA0_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA1				0x00003c8c
+#define BNX2_MQ_MEM_RD_DATA1_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA2				0x00003c90
+#define BNX2_MQ_MEM_RD_DATA2_VALUE			 (0x3fffffffL<<0)
+
+
+
+/*
+ *  tbdr_reg definition
+ *  offset: 0x5000
+ */
+#define BNX2_TBDR_COMMAND				0x00005000
+#define BNX2_TBDR_COMMAND_ENABLE			 (1L<<0)
+#define BNX2_TBDR_COMMAND_SOFT_RST			 (1L<<1)
+#define BNX2_TBDR_COMMAND_MSTR_ABORT			 (1L<<4)
+
+#define BNX2_TBDR_STATUS				0x00005004
+#define BNX2_TBDR_STATUS_DMA_WAIT			 (1L<<0)
+#define BNX2_TBDR_STATUS_FTQ_WAIT			 (1L<<1)
+#define BNX2_TBDR_STATUS_FIFO_OVERFLOW			 (1L<<2)
+#define BNX2_TBDR_STATUS_FIFO_UNDERFLOW			 (1L<<3)
+#define BNX2_TBDR_STATUS_SEARCHMISS_ERROR		 (1L<<4)
+#define BNX2_TBDR_STATUS_FTQ_ENTRY_CNT			 (1L<<5)
+#define BNX2_TBDR_STATUS_BURST_CNT			 (1L<<6)
+
+#define BNX2_TBDR_CONFIG				0x00005008
+#define BNX2_TBDR_CONFIG_MAX_BDS			 (0xffL<<0)
+#define BNX2_TBDR_CONFIG_SWAP_MODE			 (1L<<8)
+#define BNX2_TBDR_CONFIG_PRIORITY			 (1L<<9)
+#define BNX2_TBDR_CONFIG_CACHE_NEXT_PAGE_PTRS		 (1L<<10)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE			 (0xfL<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_256			 (0L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_512			 (1L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_1K			 (2L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_2K			 (3L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_4K			 (4L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_8K			 (5L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_16K			 (6L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_32K			 (7L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_64K			 (8L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_128K			 (9L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_256K			 (10L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_512K			 (11L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_1M			 (12L<<24)
+
+#define BNX2_TBDR_DEBUG_VECT_PEEK			0x0000500c
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+#define BNX2_TBDR_FTQ_DATA				0x000053c0
+#define BNX2_TBDR_FTQ_CMD				0x000053f8
+#define BNX2_TBDR_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TBDR_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TBDR_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TBDR_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TBDR_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TBDR_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TBDR_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TBDR_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TBDR_FTQ_CTL				0x000053fc
+#define BNX2_TBDR_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TBDR_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TBDR_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TBDR_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TBDR_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  tdma_reg definition
+ *  offset: 0x5c00
+ */
+#define BNX2_TDMA_COMMAND				0x00005c00
+#define BNX2_TDMA_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_TDMA_COMMAND_MASTER_ABORT			 (1L<<4)
+#define BNX2_TDMA_COMMAND_BAD_L2_LENGTH_ABORT		 (1L<<7)
+
+#define BNX2_TDMA_STATUS				0x00005c04
+#define BNX2_TDMA_STATUS_DMA_WAIT			 (1L<<0)
+#define BNX2_TDMA_STATUS_PAYLOAD_WAIT			 (1L<<1)
+#define BNX2_TDMA_STATUS_PATCH_FTQ_WAIT			 (1L<<2)
+#define BNX2_TDMA_STATUS_LOCK_WAIT			 (1L<<3)
+#define BNX2_TDMA_STATUS_FTQ_ENTRY_CNT			 (1L<<16)
+#define BNX2_TDMA_STATUS_BURST_CNT			 (1L<<17)
+
+#define BNX2_TDMA_CONFIG				0x00005c08
+#define BNX2_TDMA_CONFIG_ONE_DMA			 (1L<<0)
+#define BNX2_TDMA_CONFIG_ONE_RECORD			 (1L<<1)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ			 (0xfL<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_64			 (0L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_128			 (0x4L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_256			 (0x6L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_512			 (0x8L<<4)
+#define BNX2_TDMA_CONFIG_LINE_SZ			 (0xfL<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_64			 (0L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_128			 (4L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_256			 (6L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_512			 (8L<<8)
+#define BNX2_TDMA_CONFIG_ALIGN_ENA			 (1L<<15)
+#define BNX2_TDMA_CONFIG_CHK_L2_BD			 (1L<<16)
+#define BNX2_TDMA_CONFIG_FIFO_CMP			 (0xfL<<20)
+
+#define BNX2_TDMA_PAYLOAD_PROD				0x00005c0c
+#define BNX2_TDMA_PAYLOAD_PROD_VALUE			 (0x1fffL<<3)
+
+#define BNX2_TDMA_DBG_WATCHDOG				0x00005c10
+#define BNX2_TDMA_DBG_TRIGGER				0x00005c14
+#define BNX2_TDMA_DMAD_FSM				0x00005c80
+#define BNX2_TDMA_DMAD_FSM_BD_INVLD			 (1L<<0)
+#define BNX2_TDMA_DMAD_FSM_PUSH				 (0xfL<<4)
+#define BNX2_TDMA_DMAD_FSM_ARB_TBDC			 (0x3L<<8)
+#define BNX2_TDMA_DMAD_FSM_ARB_CTX			 (1L<<12)
+#define BNX2_TDMA_DMAD_FSM_DR_INTF			 (1L<<16)
+#define BNX2_TDMA_DMAD_FSM_DMAD				 (0x7L<<20)
+#define BNX2_TDMA_DMAD_FSM_BD				 (0xfL<<24)
+
+#define BNX2_TDMA_DMAD_STATUS				0x00005c84
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_PUSH_ENTRY		 (0x3L<<0)
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_DMAD_ENTRY		 (0x3L<<4)
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_BD_ENTRY		 (0x3L<<8)
+#define BNX2_TDMA_DMAD_STATUS_IFTQ_ENUM			 (0xfL<<12)
+
+#define BNX2_TDMA_DR_INTF_FSM				0x00005c88
+#define BNX2_TDMA_DR_INTF_FSM_L2_COMP			 (0x3L<<0)
+#define BNX2_TDMA_DR_INTF_FSM_TPATQ			 (0x7L<<4)
+#define BNX2_TDMA_DR_INTF_FSM_TPBUF			 (0x3L<<8)
+#define BNX2_TDMA_DR_INTF_FSM_DR_BUF			 (0x7L<<12)
+#define BNX2_TDMA_DR_INTF_FSM_DMAD			 (0x7L<<16)
+
+#define BNX2_TDMA_DR_INTF_STATUS			0x00005c8c
+#define BNX2_TDMA_DR_INTF_STATUS_HOLE_PHASE		 (0x7L<<0)
+#define BNX2_TDMA_DR_INTF_STATUS_DATA_AVAIL		 (0x3L<<4)
+#define BNX2_TDMA_DR_INTF_STATUS_SHIFT_ADDR		 (0x7L<<8)
+#define BNX2_TDMA_DR_INTF_STATUS_NXT_PNTR		 (0xfL<<12)
+#define BNX2_TDMA_DR_INTF_STATUS_BYTE_COUNT		 (0x7L<<16)
+
+#define BNX2_TDMA_FTQ_DATA				0x00005fc0
+#define BNX2_TDMA_FTQ_CMD				0x00005ff8
+#define BNX2_TDMA_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TDMA_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TDMA_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TDMA_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TDMA_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TDMA_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TDMA_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TDMA_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TDMA_FTQ_CTL				0x00005ffc
+#define BNX2_TDMA_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TDMA_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TDMA_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TDMA_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TDMA_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  hc_reg definition
+ *  offset: 0x6800
+ */
+#define BNX2_HC_COMMAND					0x00006800
+#define BNX2_HC_COMMAND_ENABLE				 (1L<<0)
+#define BNX2_HC_COMMAND_SKIP_ABORT			 (1L<<4)
+#define BNX2_HC_COMMAND_COAL_NOW			 (1L<<16)
+#define BNX2_HC_COMMAND_COAL_NOW_WO_INT			 (1L<<17)
+#define BNX2_HC_COMMAND_STATS_NOW			 (1L<<18)
+#define BNX2_HC_COMMAND_FORCE_INT			 (0x3L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_NULL			 (0L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_HIGH			 (1L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_LOW			 (2L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_FREE			 (3L<<19)
+#define BNX2_HC_COMMAND_CLR_STAT_NOW			 (1L<<21)
+
+#define BNX2_HC_STATUS					0x00006804
+#define BNX2_HC_STATUS_MASTER_ABORT			 (1L<<0)
+#define BNX2_HC_STATUS_PARITY_ERROR_STATE		 (1L<<1)
+#define BNX2_HC_STATUS_PCI_CLK_CNT_STAT			 (1L<<16)
+#define BNX2_HC_STATUS_CORE_CLK_CNT_STAT		 (1L<<17)
+#define BNX2_HC_STATUS_NUM_STATUS_BLOCKS_STAT		 (1L<<18)
+#define BNX2_HC_STATUS_NUM_INT_GEN_STAT			 (1L<<19)
+#define BNX2_HC_STATUS_NUM_INT_MBOX_WR_STAT		 (1L<<20)
+#define BNX2_HC_STATUS_CORE_CLKS_TO_HW_INTACK_STAT	 (1L<<23)
+#define BNX2_HC_STATUS_CORE_CLKS_TO_SW_INTACK_STAT	 (1L<<24)
+#define BNX2_HC_STATUS_CORE_CLKS_DURING_SW_INTACK_STAT	 (1L<<25)
+
+#define BNX2_HC_CONFIG					0x00006808
+#define BNX2_HC_CONFIG_COLLECT_STATS			 (1L<<0)
+#define BNX2_HC_CONFIG_RX_TMR_MODE			 (1L<<1)
+#define BNX2_HC_CONFIG_TX_TMR_MODE			 (1L<<2)
+#define BNX2_HC_CONFIG_COM_TMR_MODE			 (1L<<3)
+#define BNX2_HC_CONFIG_CMD_TMR_MODE			 (1L<<4)
+#define BNX2_HC_CONFIG_STATISTIC_PRIORITY		 (1L<<5)
+#define BNX2_HC_CONFIG_STATUS_PRIORITY			 (1L<<6)
+#define BNX2_HC_CONFIG_STAT_MEM_ADDR			 (0xffL<<8)
+
+#define BNX2_HC_ATTN_BITS_ENABLE			0x0000680c
+#define BNX2_HC_STATUS_ADDR_L				0x00006810
+#define BNX2_HC_STATUS_ADDR_H				0x00006814
+#define BNX2_HC_STATISTICS_ADDR_L			0x00006818
+#define BNX2_HC_STATISTICS_ADDR_H			0x0000681c
+#define BNX2_HC_TX_QUICK_CONS_TRIP			0x00006820
+#define BNX2_HC_TX_QUICK_CONS_TRIP_VALUE		 (0xffL<<0)
+#define BNX2_HC_TX_QUICK_CONS_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_COMP_PROD_TRIP				0x00006824
+#define BNX2_HC_COMP_PROD_TRIP_VALUE			 (0xffL<<0)
+#define BNX2_HC_COMP_PROD_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_RX_QUICK_CONS_TRIP			0x00006828
+#define BNX2_HC_RX_QUICK_CONS_TRIP_VALUE		 (0xffL<<0)
+#define BNX2_HC_RX_QUICK_CONS_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_RX_TICKS				0x0000682c
+#define BNX2_HC_RX_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_RX_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_TX_TICKS				0x00006830
+#define BNX2_HC_TX_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_TX_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_COM_TICKS				0x00006834
+#define BNX2_HC_COM_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_COM_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_CMD_TICKS				0x00006838
+#define BNX2_HC_CMD_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_CMD_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_PERIODIC_TICKS				0x0000683c
+#define BNX2_HC_PERIODIC_TICKS_HC_PERIODIC_TICKS	 (0xffffL<<0)
+
+#define BNX2_HC_STAT_COLLECT_TICKS			0x00006840
+#define BNX2_HC_STAT_COLLECT_TICKS_HC_STAT_COLL_TICKS	 (0xffL<<4)
+
+#define BNX2_HC_STATS_TICKS				0x00006844
+#define BNX2_HC_STATS_TICKS_HC_STAT_TICKS		 (0xffffL<<8)
+
+#define BNX2_HC_STAT_MEM_DATA				0x0000684c
+#define BNX2_HC_STAT_GEN_SEL_0				0x00006850
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT0	 (0L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT1	 (1L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT2	 (2L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT3	 (3L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT4	 (4L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT5	 (5L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT6	 (6L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT7	 (7L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT8	 (8L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT9	 (9L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT10	 (10L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT11	 (11L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT0	 (12L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT1	 (13L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT2	 (14L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT3	 (15L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT4	 (16L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT5	 (17L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT6	 (18L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT7	 (19L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT0	 (20L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT1	 (21L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT2	 (22L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT3	 (23L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT4	 (24L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT5	 (25L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT6	 (26L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT7	 (27L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT8	 (28L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT9	 (29L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT10	 (30L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT11	 (31L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT0	 (32L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT1	 (33L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT2	 (34L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT3	 (35L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT0	 (36L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT1	 (37L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT2	 (38L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT3	 (39L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT4	 (40L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT5	 (41L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT6	 (42L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT7	 (43L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT0	 (44L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT1	 (45L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT2	 (46L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT3	 (47L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT4	 (48L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT5	 (49L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT6	 (50L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT7	 (51L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_PCI_CLK_CNT	 (52L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CORE_CLK_CNT	 (53L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_STATUS_BLOCKS	 (54L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_INT_GEN	 (55L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_INT_MBOX_WR	 (56L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_TO_HW_INTACK	 (59L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_TO_SW_INTACK	 (60L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_DURING_SW_INTACK	 (61L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCH_CMD_CNT	 (62L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCH_SLOT_CNT	 (63L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSCH_CMD_CNT	 (64L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSCH_SLOT_CNT	 (65L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUPQ_VALID_CNT	 (66L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPQ_VALID_CNT	 (67L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPCQ_VALID_CNT	 (68L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PPQ_VALID_CNT	 (69L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PMQ_VALID_CNT	 (70L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PTQ_VALID_CNT	 (71L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMAQ_VALID_CNT	 (72L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCHQ_VALID_CNT	 (73L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDRQ_VALID_CNT	 (74L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXPQ_VALID_CNT	 (75L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMAQ_VALID_CNT	 (76L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPATQ_VALID_CNT	 (77L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TASQ_VALID_CNT	 (78L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSQ_VALID_CNT	 (79L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CPQ_VALID_CNT	 (80L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMXQ_VALID_CNT	 (81L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMTQ_VALID_CNT	 (82L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMQ_VALID_CNT	 (83L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MGMQ_VALID_CNT	 (84L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_READ_TRANSFERS_CNT	 (85L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_READ_DELAY_PCI_CLKS_CNT	 (86L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_TRANSFERS_CNT	 (87L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_DELAY_PCI_CLKS_CNT	 (88L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_RETRY_AFTER_DATA_CNT	 (89L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_WRITE_TRANSFERS_CNT	 (90L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_WRITE_DELAY_PCI_CLKS_CNT	 (91L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_TRANSFERS_CNT	 (92L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_DELAY_PCI_CLKS_CNT	 (93L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_RETRY_AFTER_DATA_CNT	 (94L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_WR_CNT64	 (95L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_RD_CNT64	 (96L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_ACC_STALL_CLKS	 (97L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_LOCK_STALL_CLKS	 (98L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_CTX_ACCESS_STAT	 (99L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_CTX_ACCESS64_STAT	 (100L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_PCI_STALL_STAT	 (101L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDR_FTQ_ENTRY_CNT	 (102L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDR_BURST_CNT	 (103L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMA_FTQ_ENTRY_CNT	 (104L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMA_BURST_CNT	 (105L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMA_FTQ_ENTRY_CNT	 (106L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMA_BURST_CNT	 (107L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUP_MATCH_CNT	 (108L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_POLL_PASS_CNT	 (109L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR1_CNT	 (110L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR2_CNT	 (111L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR3_CNT	 (112L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR4_CNT	 (113L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR5_CNT	 (114L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT0	 (115L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT1	 (116L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT2	 (117L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT3	 (118L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT4	 (119L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT5	 (120L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_PROC1_MISS	 (121L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_PROC2_MISS	 (122L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_BURST_CNT	 (127L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_1		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_2		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_3		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_1				0x00006854
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_4		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_5		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_6		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_7		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_2				0x00006858
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_8		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_9		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_10		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_11		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_3				0x0000685c
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_12		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_13		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_14		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_15		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_STAT0				0x00006888
+#define BNX2_HC_STAT_GEN_STAT1				0x0000688c
+#define BNX2_HC_STAT_GEN_STAT2				0x00006890
+#define BNX2_HC_STAT_GEN_STAT3				0x00006894
+#define BNX2_HC_STAT_GEN_STAT4				0x00006898
+#define BNX2_HC_STAT_GEN_STAT5				0x0000689c
+#define BNX2_HC_STAT_GEN_STAT6				0x000068a0
+#define BNX2_HC_STAT_GEN_STAT7				0x000068a4
+#define BNX2_HC_STAT_GEN_STAT8				0x000068a8
+#define BNX2_HC_STAT_GEN_STAT9				0x000068ac
+#define BNX2_HC_STAT_GEN_STAT10				0x000068b0
+#define BNX2_HC_STAT_GEN_STAT11				0x000068b4
+#define BNX2_HC_STAT_GEN_STAT12				0x000068b8
+#define BNX2_HC_STAT_GEN_STAT13				0x000068bc
+#define BNX2_HC_STAT_GEN_STAT14				0x000068c0
+#define BNX2_HC_STAT_GEN_STAT15				0x000068c4
+#define BNX2_HC_STAT_GEN_STAT_AC0			0x000068c8
+#define BNX2_HC_STAT_GEN_STAT_AC1			0x000068cc
+#define BNX2_HC_STAT_GEN_STAT_AC2			0x000068d0
+#define BNX2_HC_STAT_GEN_STAT_AC3			0x000068d4
+#define BNX2_HC_STAT_GEN_STAT_AC4			0x000068d8
+#define BNX2_HC_STAT_GEN_STAT_AC5			0x000068dc
+#define BNX2_HC_STAT_GEN_STAT_AC6			0x000068e0
+#define BNX2_HC_STAT_GEN_STAT_AC7			0x000068e4
+#define BNX2_HC_STAT_GEN_STAT_AC8			0x000068e8
+#define BNX2_HC_STAT_GEN_STAT_AC9			0x000068ec
+#define BNX2_HC_STAT_GEN_STAT_AC10			0x000068f0
+#define BNX2_HC_STAT_GEN_STAT_AC11			0x000068f4
+#define BNX2_HC_STAT_GEN_STAT_AC12			0x000068f8
+#define BNX2_HC_STAT_GEN_STAT_AC13			0x000068fc
+#define BNX2_HC_STAT_GEN_STAT_AC14			0x00006900
+#define BNX2_HC_STAT_GEN_STAT_AC15			0x00006904
+#define BNX2_HC_VIS					0x00006908
+#define BNX2_HC_VIS_STAT_BUILD_STATE			 (0xfL<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_IDLE		 (0L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_START		 (1L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_REQUEST		 (2L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE64		 (3L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE32		 (4L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE_DONE	 (5L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_DMA		 (6L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_CONTROL	 (7L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_LOW		 (8L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_HIGH		 (9L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_DATA		 (10L<<0)
+#define BNX2_HC_VIS_DMA_STAT_STATE			 (0xfL<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_IDLE			 (0L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATUS_PARAM		 (1L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATUS_DMA		 (2L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP		 (3L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_COMP			 (4L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATISTIC_PARAM	 (5L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATISTIC_DMA	 (6L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP_1		 (7L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP_2		 (8L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WAIT			 (9L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_ABORT		 (15L<<8)
+#define BNX2_HC_VIS_DMA_MSI_STATE			 (0x7L<<12)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE		 (0x3L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_IDLE		 (0L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_COUNT	 (1L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_START	 (2L<<15)
+
+#define BNX2_HC_VIS_1					0x0000690c
+#define BNX2_HC_VIS_1_HW_INTACK_STATE			 (1L<<4)
+#define BNX2_HC_VIS_1_HW_INTACK_STATE_IDLE		 (0L<<4)
+#define BNX2_HC_VIS_1_HW_INTACK_STATE_COUNT		 (1L<<4)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE			 (1L<<5)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE_IDLE		 (0L<<5)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE_COUNT		 (1L<<5)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE		 (1L<<6)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE_IDLE	 (0L<<6)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE_COUNT	 (1L<<6)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE		 (1L<<7)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE_IDLE		 (0L<<7)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE_COUNT		 (1L<<7)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE			 (0xfL<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_IDLE		 (0L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_DMA		 (1L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_UPDATE		 (2L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_ASSIGN		 (3L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_WAIT		 (4L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_UPDATE	 (5L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_ASSIGN	 (6L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_WAIT		 (7L<<17)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE			 (0x3L<<21)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE_NORMAL		 (0L<<21)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE_CLEAR		 (1L<<21)
+#define BNX2_HC_VIS_1_INT_GEN_STATE			 (1L<<23)
+#define BNX2_HC_VIS_1_INT_GEN_STATE_DLE			 (0L<<23)
+#define BNX2_HC_VIS_1_INT_GEN_STATE_NTERRUPT		 (1L<<23)
+#define BNX2_HC_VIS_1_STAT_CHAN_ID			 (0x7L<<24)
+#define BNX2_HC_VIS_1_INT_B				 (1L<<27)
+
+#define BNX2_HC_DEBUG_VECT_PEEK				0x00006910
+#define BNX2_HC_DEBUG_VECT_PEEK_1_VALUE			 (0x7ffL<<0)
+#define BNX2_HC_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_HC_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_VALUE			 (0x7ffL<<16)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+
+
+/*
+ *  txp_reg definition
+ *  offset: 0x40000
+ */
+#define BNX2_TXP_CPU_MODE				0x00045000
+#define BNX2_TXP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_TXP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_TXP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_TXP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_TXP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_TXP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_TXP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_TXP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_TXP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_TXP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_TXP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_TXP_CPU_STATE				0x00045004
+#define BNX2_TXP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_TXP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_TXP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_TXP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_TXP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_TXP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_TXP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_TXP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_TXP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_TXP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_TXP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_TXP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_TXP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_TXP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_TXP_CPU_EVENT_MASK				0x00045008
+#define BNX2_TXP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_TXP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_TXP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_TXP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_TXP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_TXP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_TXP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_TXP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_TXP_CPU_PROGRAM_COUNTER			0x0004501c
+#define BNX2_TXP_CPU_INSTRUCTION			0x00045020
+#define BNX2_TXP_CPU_DATA_ACCESS			0x00045024
+#define BNX2_TXP_CPU_INTERRUPT_ENABLE			0x00045028
+#define BNX2_TXP_CPU_INTERRUPT_VECTOR			0x0004502c
+#define BNX2_TXP_CPU_INTERRUPT_SAVED_PC			0x00045030
+#define BNX2_TXP_CPU_HW_BREAKPOINT			0x00045034
+#define BNX2_TXP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_TXP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK			0x00045038
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR			0x00045048
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_TXP_CPU_REG_FILE				0x00045200
+#define BNX2_TXP_FTQ_DATA				0x000453c0
+#define BNX2_TXP_FTQ_CMD				0x000453f8
+#define BNX2_TXP_FTQ_CMD_OFFSET				 (0x3ffL<<0)
+#define BNX2_TXP_FTQ_CMD_WR_TOP				 (1L<<10)
+#define BNX2_TXP_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TXP_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TXP_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TXP_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TXP_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TXP_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TXP_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TXP_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TXP_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TXP_FTQ_CTL				0x000453fc
+#define BNX2_TXP_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TXP_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TXP_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TXP_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TXP_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_TXP_SCRATCH				0x00060000
+
+
+/*
+ *  tpat_reg definition
+ *  offset: 0x80000
+ */
+#define BNX2_TPAT_CPU_MODE				0x00085000
+#define BNX2_TPAT_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_TPAT_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_TPAT_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_TPAT_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_TPAT_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_TPAT_CPU_MODE_INTERRUPT_ENA		 (1L<<7)
+#define BNX2_TPAT_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_TPAT_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_TPAT_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_TPAT_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_TPAT_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_TPAT_CPU_STATE				0x00085004
+#define BNX2_TPAT_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_TPAT_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_TPAT_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_TPAT_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_TPAT_CPU_STATE_BAD_DATA_ADDR_HALTED	 (1L<<5)
+#define BNX2_TPAT_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_TPAT_CPU_STATE_ALIGN_HALTED		 (1L<<7)
+#define BNX2_TPAT_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_TPAT_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_TPAT_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_TPAT_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_TPAT_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_TPAT_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_TPAT_CPU_STATE_BLOCKED_READ		 (1L<<31)
+
+#define BNX2_TPAT_CPU_EVENT_MASK			0x00085008
+#define BNX2_TPAT_CPU_EVENT_MASK_BREAKPOINT_MASK	 (1L<<0)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_TPAT_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_TPAT_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_TPAT_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_TPAT_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_TPAT_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_TPAT_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_TPAT_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_TPAT_CPU_PROGRAM_COUNTER			0x0008501c
+#define BNX2_TPAT_CPU_INSTRUCTION			0x00085020
+#define BNX2_TPAT_CPU_DATA_ACCESS			0x00085024
+#define BNX2_TPAT_CPU_INTERRUPT_ENABLE			0x00085028
+#define BNX2_TPAT_CPU_INTERRUPT_VECTOR			0x0008502c
+#define BNX2_TPAT_CPU_INTERRUPT_SAVED_PC		0x00085030
+#define BNX2_TPAT_CPU_HW_BREAKPOINT			0x00085034
+#define BNX2_TPAT_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_TPAT_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK			0x00085038
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR			0x00085048
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE_JUMP	 (0L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_TPAT_CPU_REG_FILE				0x00085200
+#define BNX2_TPAT_FTQ_DATA				0x000853c0
+#define BNX2_TPAT_FTQ_CMD				0x000853f8
+#define BNX2_TPAT_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TPAT_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TPAT_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TPAT_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TPAT_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TPAT_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TPAT_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TPAT_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TPAT_FTQ_CTL				0x000853fc
+#define BNX2_TPAT_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TPAT_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TPAT_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TPAT_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TPAT_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_TPAT_SCRATCH				0x000a0000
+
+
+/*
+ *  rxp_reg definition
+ *  offset: 0xc0000
+ */
+#define BNX2_RXP_CPU_MODE				0x000c5000
+#define BNX2_RXP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_RXP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_RXP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_RXP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_RXP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_RXP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_RXP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_RXP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_RXP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_RXP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_RXP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_RXP_CPU_STATE				0x000c5004
+#define BNX2_RXP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_RXP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_RXP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_RXP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_RXP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_RXP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_RXP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_RXP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_RXP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_RXP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_RXP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_RXP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_RXP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_RXP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_RXP_CPU_EVENT_MASK				0x000c5008
+#define BNX2_RXP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_RXP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_RXP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_RXP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_RXP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_RXP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_RXP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_RXP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_RXP_CPU_PROGRAM_COUNTER			0x000c501c
+#define BNX2_RXP_CPU_INSTRUCTION			0x000c5020
+#define BNX2_RXP_CPU_DATA_ACCESS			0x000c5024
+#define BNX2_RXP_CPU_INTERRUPT_ENABLE			0x000c5028
+#define BNX2_RXP_CPU_INTERRUPT_VECTOR			0x000c502c
+#define BNX2_RXP_CPU_INTERRUPT_SAVED_PC			0x000c5030
+#define BNX2_RXP_CPU_HW_BREAKPOINT			0x000c5034
+#define BNX2_RXP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_RXP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK			0x000c5038
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR			0x000c5048
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_RXP_CPU_REG_FILE				0x000c5200
+#define BNX2_RXP_CFTQ_DATA				0x000c5380
+#define BNX2_RXP_CFTQ_CMD				0x000c53b8
+#define BNX2_RXP_CFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RXP_CFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RXP_CFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RXP_CFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RXP_CFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RXP_CFTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_RXP_CFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RXP_CFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RXP_CFTQ_CTL				0x000c53bc
+#define BNX2_RXP_CFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RXP_CFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RXP_CFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RXP_CFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RXP_CFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RXP_FTQ_DATA				0x000c53c0
+#define BNX2_RXP_FTQ_CMD				0x000c53f8
+#define BNX2_RXP_FTQ_CMD_OFFSET				 (0x3ffL<<0)
+#define BNX2_RXP_FTQ_CMD_WR_TOP				 (1L<<10)
+#define BNX2_RXP_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RXP_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RXP_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RXP_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RXP_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RXP_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RXP_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_RXP_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_RXP_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RXP_FTQ_CTL				0x000c53fc
+#define BNX2_RXP_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RXP_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RXP_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RXP_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RXP_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RXP_SCRATCH				0x000e0000
+
+
+/*
+ *  com_reg definition
+ *  offset: 0x100000
+ */
+#define BNX2_COM_CPU_MODE				0x00105000
+#define BNX2_COM_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_COM_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_COM_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_COM_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_COM_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_COM_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_COM_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_COM_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_COM_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_COM_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_COM_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_COM_CPU_STATE				0x00105004
+#define BNX2_COM_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_COM_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_COM_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_COM_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_COM_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_COM_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_COM_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_COM_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_COM_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_COM_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_COM_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_COM_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_COM_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_COM_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_COM_CPU_EVENT_MASK				0x00105008
+#define BNX2_COM_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_COM_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_COM_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_COM_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_COM_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_COM_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_COM_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_COM_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_COM_CPU_PROGRAM_COUNTER			0x0010501c
+#define BNX2_COM_CPU_INSTRUCTION			0x00105020
+#define BNX2_COM_CPU_DATA_ACCESS			0x00105024
+#define BNX2_COM_CPU_INTERRUPT_ENABLE			0x00105028
+#define BNX2_COM_CPU_INTERRUPT_VECTOR			0x0010502c
+#define BNX2_COM_CPU_INTERRUPT_SAVED_PC			0x00105030
+#define BNX2_COM_CPU_HW_BREAKPOINT			0x00105034
+#define BNX2_COM_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_COM_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK			0x00105038
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR			0x00105048
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_COM_CPU_REG_FILE				0x00105200
+#define BNX2_COM_COMXQ_FTQ_DATA				0x00105340
+#define BNX2_COM_COMXQ_FTQ_CMD				0x00105378
+#define BNX2_COM_COMXQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_SFT_RESET		 (1L<<25)
+#define BNX2_COM_COMXQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMXQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMXQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMXQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMXQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMXQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMXQ_FTQ_CTL				0x0010537c
+#define BNX2_COM_COMXQ_FTQ_CTL_INTERVENE		 (1L<<0)
+#define BNX2_COM_COMXQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMXQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMXQ_FTQ_CTL_MAX_DEPTH		 (0x3ffL<<12)
+#define BNX2_COM_COMXQ_FTQ_CTL_CUR_DEPTH		 (0x3ffL<<22)
+
+#define BNX2_COM_COMTQ_FTQ_DATA				0x00105380
+#define BNX2_COM_COMTQ_FTQ_CMD				0x001053b8
+#define BNX2_COM_COMTQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_SFT_RESET		 (1L<<25)
+#define BNX2_COM_COMTQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMTQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMTQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMTQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMTQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMTQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMTQ_FTQ_CTL				0x001053bc
+#define BNX2_COM_COMTQ_FTQ_CTL_INTERVENE		 (1L<<0)
+#define BNX2_COM_COMTQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMTQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMTQ_FTQ_CTL_MAX_DEPTH		 (0x3ffL<<12)
+#define BNX2_COM_COMTQ_FTQ_CTL_CUR_DEPTH		 (0x3ffL<<22)
+
+#define BNX2_COM_COMQ_FTQ_DATA				0x001053c0
+#define BNX2_COM_COMQ_FTQ_CMD				0x001053f8
+#define BNX2_COM_COMQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_COM_COMQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMQ_FTQ_CTL				0x001053fc
+#define BNX2_COM_COMQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_COM_COMQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_COM_COMQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_COM_SCRATCH				0x00120000
+
+
+/*
+ *  cp_reg definition
+ *  offset: 0x180000
+ */
+#define BNX2_CP_CPU_MODE				0x00185000
+#define BNX2_CP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_CP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_CP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_CP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_CP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_CP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_CP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_CP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_CP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_CP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_CP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_CP_CPU_STATE				0x00185004
+#define BNX2_CP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_CP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_CP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_CP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_CP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_CP_CPU_STATE_BAD_pc_HALTED			 (1L<<6)
+#define BNX2_CP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_CP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_CP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_CP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_CP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_CP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_CP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_CP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_CP_CPU_EVENT_MASK				0x00185008
+#define BNX2_CP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_CP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_CP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_CP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_CP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_CP_CPU_EVENT_MASK_SOFT_HALTED_MASK		 (1L<<10)
+#define BNX2_CP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_CP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_CP_CPU_PROGRAM_COUNTER			0x0018501c
+#define BNX2_CP_CPU_INSTRUCTION				0x00185020
+#define BNX2_CP_CPU_DATA_ACCESS				0x00185024
+#define BNX2_CP_CPU_INTERRUPT_ENABLE			0x00185028
+#define BNX2_CP_CPU_INTERRUPT_VECTOR			0x0018502c
+#define BNX2_CP_CPU_INTERRUPT_SAVED_PC			0x00185030
+#define BNX2_CP_CPU_HW_BREAKPOINT			0x00185034
+#define BNX2_CP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_CP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK			0x00185038
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR			0x00185048
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_CP_CPU_REG_FILE				0x00185200
+#define BNX2_CP_CPQ_FTQ_DATA				0x001853c0
+#define BNX2_CP_CPQ_FTQ_CMD				0x001853f8
+#define BNX2_CP_CPQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_CP_CPQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_CP_CPQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_CP_CPQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_CP_CPQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_CP_CPQ_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_CP_CPQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_CP_CPQ_FTQ_CTL				0x001853fc
+#define BNX2_CP_CPQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_CP_CPQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_CP_CPQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_CP_CPQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_CP_CPQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_CP_SCRATCH					0x001a0000
+
+
+/*
+ *  mcp_reg definition
+ *  offset: 0x140000
+ */
+#define BNX2_MCP_CPU_MODE				0x00145000
+#define BNX2_MCP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_MCP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_MCP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_MCP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_MCP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_MCP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_MCP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_MCP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_MCP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_MCP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_MCP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_MCP_CPU_STATE				0x00145004
+#define BNX2_MCP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_MCP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_MCP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_MCP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_MCP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_MCP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_MCP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_MCP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_MCP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_MCP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_MCP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_MCP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_MCP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_MCP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_MCP_CPU_EVENT_MASK				0x00145008
+#define BNX2_MCP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_MCP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_MCP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_MCP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_MCP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_MCP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_MCP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_MCP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_MCP_CPU_PROGRAM_COUNTER			0x0014501c
+#define BNX2_MCP_CPU_INSTRUCTION			0x00145020
+#define BNX2_MCP_CPU_DATA_ACCESS			0x00145024
+#define BNX2_MCP_CPU_INTERRUPT_ENABLE			0x00145028
+#define BNX2_MCP_CPU_INTERRUPT_VECTOR			0x0014502c
+#define BNX2_MCP_CPU_INTERRUPT_SAVED_PC			0x00145030
+#define BNX2_MCP_CPU_HW_BREAKPOINT			0x00145034
+#define BNX2_MCP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_MCP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK			0x00145038
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR			0x00145048
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_MCP_CPU_REG_FILE				0x00145200
+#define BNX2_MCP_MCPQ_FTQ_DATA				0x001453c0
+#define BNX2_MCP_MCPQ_FTQ_CMD				0x001453f8
+#define BNX2_MCP_MCPQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_MCP_MCPQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_MCP_MCPQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_MCP_MCPQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_MCP_MCPQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_MCP_MCPQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_MCP_MCPQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_MCP_MCPQ_FTQ_CTL				0x001453fc
+#define BNX2_MCP_MCPQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_MCP_MCPQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_MCP_MCPQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_MCP_MCPQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_MCP_MCPQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_MCP_ROM					0x00150000
+#define BNX2_MCP_SCRATCH				0x00160000
+
+
+#define NUM_MC_HASH_REGISTERS   8
+
+
+/* PHY_ID1: bits 31-16; PHY_ID2: bits 15-0.  */
+#define PHY_BCM5706_PHY_ID                          0x00206160
+
+#define PHY_ID(id)                                  ((id) & 0xfffffff0)
+#define PHY_REV_ID(id)                              ((id) & 0xf)
+
+#define MIN_ETHERNET_PACKET_SIZE	60
+#define MAX_ETHERNET_PACKET_SIZE	1514
+#define MAX_ETHERNET_JUMBO_PACKET_SIZE	9014
+
+#define RX_COPY_THRESH			92
+
+#define DMA_READ_CHANS	5
+#define DMA_WRITE_CHANS	3
+
+#define BCM_PAGE_BITS	12
+#define BCM_PAGE_SIZE	(1 << BCM_PAGE_BITS)
+
+#define TX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct tx_bd))
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
+
+#define RX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct rx_bd))
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
+
+#define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
+		(MAX_TX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define TX_RING_IDX(x) ((x) & MAX_TX_DESC_CNT)
+
+#define NEXT_RX_BD(x) (((x) & (MAX_RX_DESC_CNT - 1)) ==			\
+		(MAX_RX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define RX_RING_IDX(x) ((x) & MAX_RX_DESC_CNT)
+
+
+/* Context size. */
+#define CTX_SHIFT                   7
+#define CTX_SIZE                    (1 << CTX_SHIFT)
+#define CTX_MASK                    (CTX_SIZE - 1)
+#define GET_CID_ADDR(_cid)          ((_cid) << CTX_SHIFT)
+#define GET_CID(_cid_addr)          ((_cid_addr) >> CTX_SHIFT)
+
+#define PHY_CTX_SHIFT               6
+#define PHY_CTX_SIZE                (1 << PHY_CTX_SHIFT)
+#define PHY_CTX_MASK                (PHY_CTX_SIZE - 1)
+#define GET_PCID_ADDR(_pcid)        ((_pcid) << PHY_CTX_SHIFT)
+#define GET_PCID(_pcid_addr)        ((_pcid_addr) >> PHY_CTX_SHIFT)
+
+#define MB_KERNEL_CTX_SHIFT         8
+#define MB_KERNEL_CTX_SIZE          (1 << MB_KERNEL_CTX_SHIFT)
+#define MB_KERNEL_CTX_MASK          (MB_KERNEL_CTX_SIZE - 1)
+#define MB_GET_CID_ADDR(_cid)       (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT))
+
+#define MAX_CID_CNT                 0x4000
+#define MAX_CID_ADDR                (GET_CID_ADDR(MAX_CID_CNT))
+#define INVALID_CID_ADDR            0xffffffff
+
+#define TX_CID		16
+#define RX_CID		0
+
+#define MB_TX_CID_ADDR	MB_GET_CID_ADDR(TX_CID)
+#define MB_RX_CID_ADDR	MB_GET_CID_ADDR(RX_CID)
+
+struct sw_bd {
+	struct sk_buff		*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+/* Buffered flash (Atmel: AT45DB011B) specific information */
+#define SEEPROM_PAGE_BITS			2
+#define SEEPROM_PHY_PAGE_SIZE			(1 << SEEPROM_PAGE_BITS)
+#define SEEPROM_BYTE_ADDR_MASK			(SEEPROM_PHY_PAGE_SIZE-1)
+#define SEEPROM_PAGE_SIZE			4
+#define SEEPROM_TOTAL_SIZE			65536
+
+#define BUFFERED_FLASH_PAGE_BITS		9
+#define BUFFERED_FLASH_PHY_PAGE_SIZE		(1 << BUFFERED_FLASH_PAGE_BITS)
+#define BUFFERED_FLASH_BYTE_ADDR_MASK		(BUFFERED_FLASH_PHY_PAGE_SIZE-1)
+#define BUFFERED_FLASH_PAGE_SIZE		264
+#define BUFFERED_FLASH_TOTAL_SIZE		131072
+
+#define SAIFUN_FLASH_PAGE_BITS			8
+#define SAIFUN_FLASH_PHY_PAGE_SIZE		(1 << SAIFUN_FLASH_PAGE_BITS)
+#define SAIFUN_FLASH_BYTE_ADDR_MASK		(SAIFUN_FLASH_PHY_PAGE_SIZE-1)
+#define SAIFUN_FLASH_PAGE_SIZE			256
+#define SAIFUN_FLASH_BASE_TOTAL_SIZE		65536
+
+#define NVRAM_TIMEOUT_COUNT			30000
+
+
+#define FLASH_STRAP_MASK			(BNX2_NVM_CFG1_FLASH_MODE   | \
+						 BNX2_NVM_CFG1_BUFFER_MODE  | \
+						 BNX2_NVM_CFG1_PROTECT_MODE | \
+						 BNX2_NVM_CFG1_FLASH_SIZE)
+
+struct flash_spec {
+	u32 strapping;
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 write1;
+	u32 buffered;
+	u32 page_bits;
+	u32 page_size;
+	u32 addr_mask;
+	u32 total_size;
+	u8  *name;
+};
+
+struct bnx2 {
+	/* Fields used in the tx and intr/napi performance paths are grouped */
+	/* together in the beginning of the structure. */
+	void __iomem		*regview;
+
+	struct net_device	*dev;
+	struct pci_dev		*pdev;
+
+	atomic_t		intr_sem;
+
+	struct status_block	*status_blk;
+	u32 			last_status_idx;
+
+	atomic_t		tx_avail_bd;
+	struct tx_bd		*tx_desc_ring;
+	struct sw_bd		*tx_buf_ring;
+	u32			tx_prod_bseq;
+	u16			tx_prod;
+	u16			tx_cons;
+
+#ifdef BCM_VLAN 
+	struct			vlan_group *vlgrp;
+#endif
+
+	u32			rx_offset;
+	u32			rx_buf_use_size;	/* useable size */
+	u32			rx_buf_size;		/* with alignment */
+	struct rx_bd		*rx_desc_ring;
+	struct sw_bd		*rx_buf_ring;
+	u32			rx_prod_bseq;
+	u16			rx_prod;
+	u16			rx_cons;
+
+	u32			rx_csum;
+
+	/* Only used to synchronize netif_stop_queue/wake_queue when tx */
+	/* ring is full */
+	spinlock_t		tx_lock;
+
+	/* End of fileds used in the performance code paths. */
+
+	char			*name;
+
+	int			timer_interval;
+	struct			timer_list timer;
+	struct work_struct	reset_task;
+
+	/* Used to synchronize phy accesses. */
+	spinlock_t		phy_lock;
+
+	u32			flags;
+#define PCIX_FLAG			1
+#define PCI_32BIT_FLAG			2
+#define ONE_TDMA_FLAG			4	/* no longer used */
+#define NO_WOL_FLAG			8
+#define USING_DAC_FLAG			0x10
+#define USING_MSI_FLAG			0x20
+
+	u32			phy_flags;
+#define PHY_SERDES_FLAG			1
+#define PHY_CRC_FIX_FLAG		2
+#define PHY_PARALLEL_DETECT_FLAG	4
+#define PHY_INT_MODE_MASK_FLAG		0x300
+#define PHY_INT_MODE_AUTO_POLLING_FLAG	0x100
+#define PHY_INT_MODE_LINK_READY_FLAG	0x200
+
+	u32			chip_id;
+	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+#define CHIP_NUM(bp)			(((bp)->chip_id) & 0xffff0000)
+#define CHIP_NUM_5706			0x57060000
+
+#define CHIP_REV(bp)			(((bp)->chip_id) & 0x0000f000)
+#define CHIP_REV_Ax			0x00000000
+#define CHIP_REV_Bx			0x00001000
+#define CHIP_REV_Cx			0x00002000
+    
+#define CHIP_METAL(bp)			(((bp)->chip_id) & 0x00000ff0)
+#define CHIP_BONDING(bp)		(((bp)->chip_id) & 0x0000000f)
+
+#define CHIP_ID(bp)			(((bp)->chip_id) & 0xfffffff0)
+#define CHIP_ID_5706_A0			0x57060000
+#define CHIP_ID_5706_A1			0x57060010
+
+#define CHIP_BOND_ID(bp)		(((bp)->chip_id) & 0xf)
+
+/* A serdes chip will have the first bit of the bond id set. */
+#define CHIP_BOND_ID_SERDES_BIT		0x01
+
+	u32			phy_addr;
+	u32			phy_id;
+	
+	u16			bus_speed_mhz;
+	u8			wol;
+
+	u8			fw_timed_out;
+
+	u16			fw_wr_seq;
+	u16			fw_drv_pulse_wr_seq;
+
+	int			tx_ring_size;
+	dma_addr_t		tx_desc_mapping;
+
+
+	int			rx_ring_size;
+	dma_addr_t		rx_desc_mapping;
+
+	u16			tx_quick_cons_trip;
+	u16			tx_quick_cons_trip_int;
+	u16			rx_quick_cons_trip;
+	u16			rx_quick_cons_trip_int;
+	u16			comp_prod_trip;
+	u16			comp_prod_trip_int;
+	u16			tx_ticks;
+	u16			tx_ticks_int;
+	u16			com_ticks;
+	u16			com_ticks_int;
+	u16			cmd_ticks;
+	u16			cmd_ticks_int;
+	u16			rx_ticks;
+	u16			rx_ticks_int;
+
+	u32			stats_ticks;
+
+	dma_addr_t		status_blk_mapping;
+
+	struct statistics_block	*stats_blk;
+	dma_addr_t		stats_blk_mapping;
+
+	u32			rx_mode;
+
+	u16			req_line_speed;
+	u8			req_duplex;
+
+	u8			link_up;
+
+	u16			line_speed;
+	u8			duplex;
+	u8			flow_ctrl;	/* actual flow ctrl settings */
+						/* may be different from     */
+						/* req_flow_ctrl if autoneg  */
+#define FLOW_CTRL_TX		1
+#define FLOW_CTRL_RX		2
+
+	u32			advertising;
+
+	u8			req_flow_ctrl;	/* flow ctrl advertisement */ 
+						/* settings or forced      */
+						/* settings                */
+	u8			autoneg;
+#define AUTONEG_SPEED		1
+#define AUTONEG_FLOW_CTRL	2
+
+	u8			loopback;
+#define MAC_LOOPBACK		1
+#define PHY_LOOPBACK		2
+
+	u8			serdes_an_pending;
+#define SERDES_AN_TIMEOUT	(2 * HZ)
+
+	u8			mac_addr[8];
+
+	u32			fw_ver;
+
+	int			pm_cap;
+	int			pcix_cap;
+
+	struct net_device_stats net_stats;
+
+	struct flash_spec	*flash_info;
+};
+
+static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
+static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
+
+#define REG_RD(bp, offset)					\
+	readl(bp->regview + offset)
+
+#define REG_WR(bp, offset, val)					\
+	writel(val, bp->regview + offset)
+
+#define REG_WR16(bp, offset, val)				\
+	writew(val, bp->regview + offset)
+
+#define REG_RD_IND(bp, offset)					\
+	bnx2_reg_rd_ind(bp, offset)
+
+#define REG_WR_IND(bp, offset, val)				\
+	bnx2_reg_wr_ind(bp, offset, val)
+
+/* Indirect context access.  Unlike the MBQ_WR, these macros will not
+ * trigger a chip event. */
+static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val);
+
+#define CTX_WR(bp, cid_addr, offset, val)			\
+	bnx2_ctx_wr(bp, cid_addr, offset, val)
+
+struct cpu_reg {
+	u32 mode;
+	u32 mode_value_halt;
+	u32 mode_value_sstep;
+
+	u32 state;
+	u32 state_value_clear;
+
+	u32 gpr0;
+	u32 evmask;
+	u32 pc;
+	u32 inst;
+	u32 bp;
+
+	u32 spad_base;
+
+	u32 mips_view_base;
+};
+
+struct fw_info {
+	u32 ver_major;
+	u32 ver_minor;
+	u32 ver_fix;
+
+	u32 start_addr;
+
+	/* Text section. */
+	u32 text_addr;
+	u32 text_len;
+	u32 text_index;
+	u32 *text;
+
+	/* Data section. */
+	u32 data_addr;
+	u32 data_len;
+	u32 data_index;
+	u32 *data;
+
+	/* SBSS section. */
+	u32 sbss_addr;
+	u32 sbss_len;
+	u32 sbss_index;
+	u32 *sbss;
+
+	/* BSS section. */
+	u32 bss_addr;
+	u32 bss_len;
+	u32 bss_index;
+	u32 *bss;
+
+	/* Read-only section. */
+	u32 rodata_addr;
+	u32 rodata_len;
+	u32 rodata_index;
+	u32 *rodata;
+};
+
+#define RV2P_PROC1                              0
+#define RV2P_PROC2                              1
+
+
+/* This value (in milliseconds) determines the frequency of the driver
+ * issuing the PULSE message code.  The firmware monitors this periodic
+ * pulse to determine when to switch to an OS-absent mode. */
+#define DRV_PULSE_PERIOD_MS                 250
+
+/* This value (in milliseconds) determines how long the driver should
+ * wait for an acknowledgement from the firmware before timing out.  Once
+ * the firmware has timed out, the driver will assume there is no firmware
+ * running and there won't be any firmware-driver synchronization during a
+ * driver reset. */
+#define FW_ACK_TIME_OUT_MS                  50
+
+
+#define BNX2_DRV_RESET_SIGNATURE		0x00000000
+#define BNX2_DRV_RESET_SIGNATURE_MAGIC		 0x4841564b /* HAVK */
+//#define DRV_RESET_SIGNATURE_MAGIC		 0x47495352 /* RSIG */
+
+#define BNX2_DRV_MB				0x00000004
+#define BNX2_DRV_MSG_CODE			 0xff000000
+#define BNX2_DRV_MSG_CODE_RESET			 0x01000000
+#define BNX2_DRV_MSG_CODE_UNLOAD		 0x02000000
+#define BNX2_DRV_MSG_CODE_SHUTDOWN		 0x03000000
+#define BNX2_DRV_MSG_CODE_SUSPEND_WOL		 0x04000000
+#define BNX2_DRV_MSG_CODE_FW_TIMEOUT		 0x05000000
+#define BNX2_DRV_MSG_CODE_PULSE			 0x06000000
+#define BNX2_DRV_MSG_CODE_DIAG			 0x07000000
+#define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL	 0x09000000
+
+#define BNX2_DRV_MSG_DATA			 0x00ff0000
+#define BNX2_DRV_MSG_DATA_WAIT0			 0x00010000
+#define BNX2_DRV_MSG_DATA_WAIT1			 0x00020000
+#define BNX2_DRV_MSG_DATA_WAIT2			 0x00030000
+#define BNX2_DRV_MSG_DATA_WAIT3			 0x00040000
+        
+#define BNX2_DRV_MSG_SEQ			 0x0000ffff
+
+#define BNX2_FW_MB				0x00000008
+#define BNX2_FW_MSG_ACK				 0x0000ffff
+#define BNX2_FW_MSG_STATUS_MASK			 0x00ff0000
+#define BNX2_FW_MSG_STATUS_OK			 0x00000000
+#define BNX2_FW_MSG_STATUS_FAILURE		 0x00ff0000
+
+#define BNX2_LINK_STATUS			0x0000000c
+
+#define BNX2_DRV_PULSE_MB			0x00000010
+#define BNX2_DRV_PULSE_SEQ_MASK			 0x0000ffff
+
+/* Indicate to the firmware not to go into the
+ * OS absent when it is not getting driver pulse.
+ * This is used for debugging. */
+#define BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE	 0x00010000
+
+#define BNX2_DEV_INFO_SIGNATURE			0x00000020
+#define BNX2_DEV_INFO_SIGNATURE_MAGIC		 0x44564900
+#define BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK	 0xffffff00
+#define BNX2_DEV_INFO_FEATURE_CFG_VALID		 0x01
+#define BNX2_DEV_INFO_SECONDARY_PORT		 0x80
+#define BNX2_DEV_INFO_DRV_ALWAYS_ALIVE		 0x40
+
+#define BNX2_SHARED_HW_CFG_PART_NUM		0x00000024
+
+#define BNX2_SHARED_HW_CFG_POWER_DISSIPATED	0x00000034
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D3_MASK	 0xff000000
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D2_MASK	 0xff0000
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D1_MASK	 0xff00
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D0_MASK	 0xff
+
+#define BNX2_SHARED_HW_CFG POWER_CONSUMED	0x00000038
+#define BNX2_SHARED_HW_CFG_CONFIG		0x0000003c
+#define BNX2_SHARED_HW_CFG_DESIGN_NIC		 0
+#define BNX2_SHARED_HW_CFG_DESIGN_LOM		 0x1
+#define BNX2_SHARED_HW_CFG_PHY_COPPER		 0
+#define BNX2_SHARED_HW_CFG_PHY_FIBER		 0x2
+#define BNX2_SHARED_HW_CFG_LED_MODE_SHIFT_BITS	 8
+#define BNX2_SHARED_HW_CFG_LED_MODE_MASK	 0x300
+#define BNX2_SHARED_HW_CFG_LED_MODE_MAC		 0
+#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1	 0x100
+#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2	 0x200
+
+#define BNX2_DEV_INFO_BC_REV			0x0000004c
+
+#define BNX2_PORT_HW_CFG_MAC_UPPER		0x00000050
+#define BNX2_PORT_HW_CFG_UPPERMAC_MASK		 0xffff
+
+#define BNX2_PORT_HW_CFG_MAC_LOWER		0x00000054
+#define BNX2_PORT_HW_CFG_CONFIG			0x00000058
+
+#define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER	0x00000068
+#define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER	0x0000006c
+#define BNX2_PORT_HW_CFG_IMD_MAC_B_UPPER	0x00000070
+#define BNX2_PORT_HW_CFG_IMD_MAC_B_LOWER	0x00000074
+#define BNX2_PORT_HW_CFG_ISCSI_MAC_UPPER	0x00000078
+#define BNX2_PORT_HW_CFG_ISCSI_MAC_LOWER	0x0000007c
+
+#define BNX2_DEV_INFO_PER_PORT_HW_CONFIG2	0x000000b4
+
+#define BNX2_DEV_INFO_FORMAT_REV		0x000000c4
+#define BNX2_DEV_INFO_FORMAT_REV_MASK		 0xff000000
+#define BNX2_DEV_INFO_FORMAT_REV_ID		 ('A' << 24)
+
+#define BNX2_SHARED_FEATURE			0x000000c8
+#define BNX2_SHARED_FEATURE_MASK		 0xffffffff
+
+#define BNX2_PORT_FEATURE			0x000000d8
+#define BNX2_PORT2_FEATURE			0x00000014c
+#define BNX2_PORT_FEATURE_WOL_ENABLED		 0x01000000
+#define BNX2_PORT_FEATURE_MBA_ENABLED		 0x02000000
+#define BNX2_PORT_FEATURE_ASF_ENABLED		 0x04000000
+#define BNX2_PORT_FEATURE_IMD_ENABLED		 0x08000000
+#define BNX2_PORT_FEATURE_BAR1_SIZE_MASK	 0xf
+#define BNX2_PORT_FEATURE_BAR1_SIZE_DISABLED	 0x0
+#define BNX2_PORT_FEATURE_BAR1_SIZE_64K		 0x1
+#define BNX2_PORT_FEATURE_BAR1_SIZE_128K	 0x2
+#define BNX2_PORT_FEATURE_BAR1_SIZE_256K	 0x3
+#define BNX2_PORT_FEATURE_BAR1_SIZE_512K	 0x4
+#define BNX2_PORT_FEATURE_BAR1_SIZE_1M		 0x5
+#define BNX2_PORT_FEATURE_BAR1_SIZE_2M		 0x6
+#define BNX2_PORT_FEATURE_BAR1_SIZE_4M		 0x7
+#define BNX2_PORT_FEATURE_BAR1_SIZE_8M		 0x8
+#define BNX2_PORT_FEATURE_BAR1_SIZE_16M		 0x9
+#define BNX2_PORT_FEATURE_BAR1_SIZE_32M		 0xa
+#define BNX2_PORT_FEATURE_BAR1_SIZE_64M		 0xb
+#define BNX2_PORT_FEATURE_BAR1_SIZE_128M	 0xc
+#define BNX2_PORT_FEATURE_BAR1_SIZE_256M	 0xd
+#define BNX2_PORT_FEATURE_BAR1_SIZE_512M	 0xe
+#define BNX2_PORT_FEATURE_BAR1_SIZE_1G		 0xf
+
+#define BNX2_PORT_FEATURE_WOL			0xdc
+#define BNX2_PORT2_FEATURE_WOL			0x150
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_SHIFT_BITS	 4
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MASK	 0x30
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_DISABLE	 0
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MAGIC	 0x10
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_ACPI	 0x20
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MAGIC_AND_ACPI	 0x30
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_MASK	 0xf
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_AUTONEG	 0
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_10HALF	 1
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_10FULL	 2
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_100HALF 3
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_100FULL 4
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_1000HALF	 5
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_1000FULL	 6
+#define BNX2_PORT_FEATURE_WOL_AUTONEG_ADVERTISE_1000	 0x40
+#define BNX2_PORT_FEATURE_WOL_RESERVED_PAUSE_CAP 0x400
+#define BNX2_PORT_FEATURE_WOL_RESERVED_ASYM_PAUSE_CAP	 0x800
+
+#define BNX2_PORT_FEATURE_MBA			0xe0
+#define BNX2_PORT2_FEATURE_MBA			0x154
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_SHIFT_BITS	 0
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK	 0x3
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE	 0
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_RPL	 1
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_BOOTP	 2
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_SHIFT_BITS	 2
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_MASK	 0x3c
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_AUTONEG	 0
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_10HALF	 0x4
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_10FULL	 0x8
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_100HALF	 0xc
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_100FULL	 0x10
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_1000HALF	 0x14
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_1000FULL	 0x18
+#define BNX2_PORT_FEATURE_MBA_SETUP_PROMPT_ENABLE	 0x40
+#define BNX2_PORT_FEATURE_MBA_HOTKEY_CTRL_S	 0
+#define BNX2_PORT_FEATURE_MBA_HOTKEY_CTRL_B	 0x80
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_SHIFT_BITS	 8
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_MASK	 0xff00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_DISABLED	 0
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_1K	 0x100
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_2K	 0x200
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_4K	 0x300
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_8K	 0x400
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_16K	 0x500
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_32K	 0x600
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_64K	 0x700
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_128K	 0x800
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_256K	 0x900
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_512K	 0xa00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_1M	 0xb00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_2M	 0xc00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_4M	 0xd00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_8M	 0xe00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_16M	 0xf00
+#define BNX2_PORT_FEATURE_MBA_MSG_TIMEOUT_SHIFT_BITS	 16
+#define BNX2_PORT_FEATURE_MBA_MSG_TIMEOUT_MASK	 0xf0000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_SHIFT_BITS	 20
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_MASK	 0x300000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_AUTO	 0
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_BBS	 0x100000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT18H	 0x200000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT19H	 0x300000
+
+#define BNX2_PORT_FEATURE_IMD			0xe4
+#define BNX2_PORT2_FEATURE_IMD			0x158
+#define BNX2_PORT_FEATURE_IMD_LINK_OVERRIDE_DEFAULT	 0
+#define BNX2_PORT_FEATURE_IMD_LINK_OVERRIDE_ENABLE	 1
+
+#define BNX2_PORT_FEATURE_VLAN			0xe8
+#define BNX2_PORT2_FEATURE_VLAN			0x15c
+#define BNX2_PORT_FEATURE_MBA_VLAN_TAG_MASK	 0xffff
+#define BNX2_PORT_FEATURE_MBA_VLAN_ENABLE	 0x10000
+
+#define BNX2_BC_STATE_RESET_TYPE		0x000001c0
+#define BNX2_BC_STATE_RESET_TYPE_SIG		 0x00005254
+#define BNX2_BC_STATE_RESET_TYPE_SIG_MASK	 0x0000ffff
+#define BNX2_BC_STATE_RESET_TYPE_NONE	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00010000)
+#define BNX2_BC_STATE_RESET_TYPE_PCI	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00020000)
+#define BNX2_BC_STATE_RESET_TYPE_VAUX	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00030000)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK	 DRV_MSG_CODE         
+#define BNX2_BC_STATE_RESET_TYPE_DRV_RESET (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					    DRV_MSG_CODE_RESET)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_UNLOAD (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					     DRV_MSG_CODE_UNLOAD)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_SHUTDOWN (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					       DRV_MSG_CODE_SHUTDOWN)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_WOL (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  DRV_MSG_CODE_WOL)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_DIAG (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					   DRV_MSG_CODE_DIAG)
+#define BNX2_BC_STATE_RESET_TYPE_VALUE(msg) (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					     (msg))
+
+#define BNX2_BC_STATE				0x000001c4
+#define BNX2_BC_STATE_ERR_MASK			 0x0000ff00
+#define BNX2_BC_STATE_SIGN			 0x42530000
+#define BNX2_BC_STATE_SIGN_MASK			 0xffff0000
+#define BNX2_BC_STATE_BC1_START			 (BNX2_BC_STATE_SIGN | 0x1)
+#define BNX2_BC_STATE_GET_NVM_CFG1		 (BNX2_BC_STATE_SIGN | 0x2)
+#define BNX2_BC_STATE_PROG_BAR			 (BNX2_BC_STATE_SIGN | 0x3)
+#define BNX2_BC_STATE_INIT_VID			 (BNX2_BC_STATE_SIGN | 0x4)
+#define BNX2_BC_STATE_GET_NVM_CFG2		 (BNX2_BC_STATE_SIGN | 0x5)
+#define BNX2_BC_STATE_APPLY_WKARND		 (BNX2_BC_STATE_SIGN | 0x6)
+#define BNX2_BC_STATE_LOAD_BC2			 (BNX2_BC_STATE_SIGN | 0x7)
+#define BNX2_BC_STATE_GOING_BC2			 (BNX2_BC_STATE_SIGN | 0x8)
+#define BNX2_BC_STATE_GOING_DIAG		 (BNX2_BC_STATE_SIGN | 0x9)
+#define BNX2_BC_STATE_RT_FINAL_INIT		 (BNX2_BC_STATE_SIGN | 0x81)
+#define BNX2_BC_STATE_RT_WKARND			 (BNX2_BC_STATE_SIGN | 0x82)
+#define BNX2_BC_STATE_RT_DRV_PULSE		 (BNX2_BC_STATE_SIGN | 0x83)
+#define BNX2_BC_STATE_RT_FIOEVTS		 (BNX2_BC_STATE_SIGN | 0x84)
+#define BNX2_BC_STATE_RT_DRV_CMD		 (BNX2_BC_STATE_SIGN | 0x85)
+#define BNX2_BC_STATE_RT_LOW_POWER		 (BNX2_BC_STATE_SIGN | 0x86)
+#define BNX2_BC_STATE_RT_SET_WOL		 (BNX2_BC_STATE_SIGN | 0x87)
+#define BNX2_BC_STATE_RT_OTHER_FW		 (BNX2_BC_STATE_SIGN | 0x88)
+#define BNX2_BC_STATE_RT_GOING_D3		 (BNX2_BC_STATE_SIGN | 0x89)
+#define BNX2_BC_STATE_ERR_BAD_VERSION		 (BNX2_BC_STATE_SIGN | 0x0100)
+#define BNX2_BC_STATE_ERR_BAD_BC2_CRC		 (BNX2_BC_STATE_SIGN | 0x0200)
+#define BNX2_BC_STATE_ERR_BC1_LOOP		 (BNX2_BC_STATE_SIGN | 0x0300)
+#define BNX2_BC_STATE_ERR_UNKNOWN_CMD		 (BNX2_BC_STATE_SIGN | 0x0400)
+#define BNX2_BC_STATE_ERR_DRV_DEAD		 (BNX2_BC_STATE_SIGN | 0x0500)
+#define BNX2_BC_STATE_ERR_NO_RXP		 (BNX2_BC_STATE_SIGN | 0x0600)
+#define BNX2_BC_STATE_ERR_TOO_MANY_RBUF		 (BNX2_BC_STATE_SIGN | 0x0700)
+	
+#define BNX2_BC_STATE_DEBUG_CMD			0x1dc
+#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE	 0x42440000
+#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE_MASK	 0xffff0000
+#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_CNT_MASK	 0xffff
+#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_INFINITE	 0xffff
+
+#define HOST_VIEW_SHMEM_BASE			0x167c00
+
+#endif
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
new file mode 100644
--- /dev/null
+++ b/drivers/net/bnx2_fw.h
@@ -0,0 +1,2468 @@
+/* bnx2_fw.h: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005 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, except as noted below.
+ *
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004, 2005 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
+
+
+static int bnx2_COM_b06FwReleaseMajor = 0x0;
+static int bnx2_COM_b06FwReleaseMinor = 0x0;
+static int bnx2_COM_b06FwReleaseFix = 0x0;
+static u32 bnx2_COM_b06FwStartAddr = 0x080004a0;
+static u32 bnx2_COM_b06FwTextAddr = 0x08000000;
+static int bnx2_COM_b06FwTextLen = 0x4594;
+static u32 bnx2_COM_b06FwDataAddr = 0x080045e0;
+static int bnx2_COM_b06FwDataLen = 0x0;
+static u32 bnx2_COM_b06FwRodataAddr = 0x08004598;
+static int bnx2_COM_b06FwRodataLen = 0x18;
+static u32 bnx2_COM_b06FwBssAddr = 0x08004600;
+static int bnx2_COM_b06FwBssLen = 0x88;
+static u32 bnx2_COM_b06FwSbssAddr = 0x080045e0;
+static int bnx2_COM_b06FwSbssLen = 0x1c;
+static u32 bnx2_COM_b06FwText[(0x4594/4) + 1] = {
+	0x0a000128, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x302e362e,
+	0x39000000, 0x00060902, 0x00000000, 0x00000003, 0x00000014, 0x00000032,
+	0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000010, 0x000003e8, 0x0000ea60, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x0000ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000002, 0x00000020, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d,
+	0x0000000d, 0x3c020800, 0x244245e0, 0x3c030800, 0x24634688, 0xac400000,
+	0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021,
+	0x3c100800, 0x261004a0, 0x3c1c0800, 0x279c45e0, 0x0e0001f2, 0x00000000,
+	0x0000000d, 0x27bdffe8, 0x3c1a8000, 0x3c020008, 0x0342d825, 0x3c036010,
+	0xafbf0010, 0x8c655000, 0x3c020800, 0x24470ac8, 0x3c040800, 0x24864600,
+	0x2402ff7f, 0x00a22824, 0x34a5380c, 0xac655000, 0x00002821, 0x24020037,
+	0x24030c80, 0xaf420008, 0xaf430024, 0xacc70000, 0x24a50001, 0x2ca20016,
+	0x1440fffc, 0x24c60004, 0x24844600, 0x3c020800, 0x24420ad4, 0x3c030800,
+	0x246309d4, 0xac820004, 0x3c020800, 0x24420618, 0x3c050800, 0x24a50ca0,
+	0xac82000c, 0x3c020800, 0x24423100, 0xac830008, 0x3c030800, 0x246325c8,
+	0xac820014, 0x3c020800, 0x24422b0c, 0xac830018, 0xac83001c, 0x3c030800,
+	0x24630adc, 0xac820024, 0x3c020800, 0x24423040, 0xac83002c, 0x3c030800,
+	0x24633060, 0xac820030, 0x3c020800, 0x24422f6c, 0xac830034, 0x3c030800,
+	0x24632c60, 0xac82003c, 0x3c020800, 0x24420b6c, 0xac850010, 0xac850020,
+	0xac830040, 0x0e000bd6, 0xac820050, 0x8fbf0010, 0x03e00008, 0x27bd0018,
+	0x27bdffe0, 0xafb00010, 0x27500100, 0xafbf0018, 0xafb10014, 0x9203000b,
+	0x24020003, 0x1462005b, 0x96110008, 0x32220001, 0x10400009, 0x27430080,
+	0x8e020000, 0x96040014, 0x000211c2, 0x00021040, 0x00621821, 0xa4640000,
+	0x0a0001cb, 0x3c020800, 0x3c020800, 0x8c430020, 0x1060002a, 0x3c030800,
+	0x0e001006, 0x00000000, 0x97420108, 0x8f850018, 0x9743010c, 0x3042003e,
+	0x00021400, 0x00621825, 0xaca30000, 0x8f840018, 0x8f420100, 0xac820004,
+	0x97430116, 0x9742010e, 0x8f840018, 0x00031c00, 0x00431025, 0xac820008,
+	0x97430110, 0x97440112, 0x8f850018, 0x00031c00, 0x00832025, 0xaca4000c,
+	0x97420114, 0x8f840018, 0x3042ffff, 0xac820010, 0x8f830018, 0xac600014,
+	0x8f820018, 0x3c030800, 0xac400018, 0x9462466e, 0x8f840018, 0x3c032000,
+	0x00431025, 0xac82001c, 0x0e001044, 0x24040001, 0x3c030800, 0x8c620040,
+	0x24420001, 0xac620040, 0x3c020800, 0x8c430044, 0x32240004, 0x24630001,
+	0x10800017, 0xac430044, 0x8f4202b8, 0x04430007, 0x8e020020, 0x3c040800,
+	0x8c830060, 0x24020001, 0x24630001, 0x0a0001ed, 0xac830060, 0x3c060800,
+	0x8cc4005c, 0xaf420280, 0x96030016, 0x00001021, 0xa7430284, 0x8e050004,
+	0x24840001, 0x3c031000, 0xaf450288, 0xaf4302b8, 0x0a0001ed, 0xacc4005c,
+	0x32220002, 0x0a0001ed, 0x0002102b, 0x3c026000, 0xac400808, 0x0000000d,
+	0x00001021, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
+	0x27bdffc8, 0xafbf0034, 0xafbe0030, 0xafb7002c, 0xafb60028, 0xafb50024,
+	0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0x0e00013f, 0xafb00010,
+	0x24110020, 0x24150030, 0x2794000c, 0x27930008, 0x3c124000, 0x3c1e0800,
+	0x3c170800, 0x3c160800, 0x8f820004, 0x3c040800, 0x8c830020, 0x10430004,
+	0x00000000, 0xaf830004, 0x0e00110b, 0x00000000, 0x8f500000, 0x32020007,
+	0x1040fff5, 0x32020001, 0x1040002b, 0x32020002, 0x8f420100, 0xaf420020,
+	0x8f430104, 0xaf4300a8, 0x9342010b, 0x93630000, 0x306300ff, 0x10710005,
+	0x304400ff, 0x10750006, 0x2c820016, 0x0a000227, 0x00000000, 0xaf940000,
+	0x0a000228, 0x2c820016, 0xaf930000, 0x0a000228, 0x00000000, 0xaf800000,
+	0x14400005, 0x00041880, 0x0e0002b2, 0x00000000, 0x0a000234, 0x00000000,
+	0x3c020800, 0x24424600, 0x00621821, 0x8c620000, 0x0040f809, 0x00000000,
+	0x10400005, 0x8fc20034, 0x8f420104, 0x3c016020, 0xac220014, 0x8fc20034,
+	0xaf520138, 0x24420001, 0xafc20034, 0x32020002, 0x10400019, 0x32020004,
+	0x8f420140, 0xaf420020, 0x93630000, 0x306300ff, 0x10710005, 0x00000000,
+	0x10750006, 0x00000000, 0x0a000250, 0x00000000, 0xaf940000, 0x0a000251,
+	0x00000000, 0xaf930000, 0x0a000251, 0x00000000, 0xaf800000, 0x0e0008b9,
+	0x00000000, 0x8ee20038, 0xaf520178, 0x24420001, 0xaee20038, 0x32020004,
+	0x1040ffad, 0x00000000, 0x8f420180, 0xaf420020, 0x93630000, 0x306300ff,
+	0x10710005, 0x00000000, 0x10750006, 0x00000000, 0x0a00026a, 0x00000000,
+	0xaf940000, 0x0a00026b, 0x00000000, 0xaf930000, 0x0a00026b, 0x00000000,
+	0xaf800000, 0x93620000, 0x14510004, 0x8ec2003c, 0x0e000835, 0x00000000,
+	0x8ec2003c, 0xaf5201b8, 0x24420001, 0x0a000206, 0xaec2003c, 0x27bdffe8,
+	0xafbf0010, 0x97420108, 0x24033000, 0x30447000, 0x10830012, 0x28823001,
+	0x10400007, 0x24024000, 0x1080000b, 0x24022000, 0x1082001a, 0x24020001,
+	0x0a000299, 0x00000000, 0x1082000c, 0x24025000, 0x1082000e, 0x00000000,
+	0x0a000299, 0x00000000, 0x0000000d, 0x0a00029b, 0x00001021, 0x0e000300,
+	0x00000000, 0x0a00029b, 0x00001021, 0x0e00048f, 0x00000000, 0x0a00029b,
+	0x00001021, 0x0e000fdf, 0x00000000, 0x0a00029b, 0x00001021, 0x0000000d,
+	0x00001021, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x93620000, 0x24030020,
+	0x304400ff, 0x10830005, 0x24020030, 0x10820007, 0x00000000, 0x0a0002af,
+	0x00000000, 0x2782000c, 0xaf820000, 0x03e00008, 0x00000000, 0x27820008,
+	0xaf820000, 0x03e00008, 0x00000000, 0xaf800000, 0x03e00008, 0x00000000,
+	0x0000000d, 0x03e00008, 0x00001021, 0x03e00008, 0x00001021, 0x27440100,
+	0x94830008, 0x30620004, 0x10400017, 0x30620002, 0x8f4202b8, 0x04430007,
+	0x8c820020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001, 0x03e00008,
+	0xac830060, 0xaf420280, 0x94830016, 0x3c060800, 0xa7430284, 0x8c850004,
+	0x8cc4005c, 0x00001021, 0x3c031000, 0x24840001, 0xaf450288, 0xaf4302b8,
+	0x03e00008, 0xacc4005c, 0x14400003, 0x3c040800, 0x03e00008, 0x00001021,
+	0x8c830084, 0x24020001, 0x24630001, 0x03e00008, 0xac830084, 0x27450100,
+	0x3c040800, 0x8c820088, 0x94a3000c, 0x24420001, 0x007a1821, 0xac820088,
+	0x8ca40018, 0x90664000, 0xaf440038, 0x8ca2001c, 0x2403fff8, 0x00063600,
+	0x00431024, 0x34420004, 0x3c030005, 0xaf42003c, 0xaf430030, 0x00000000,
+	0x00000000, 0x00000000, 0xaf460404, 0x00000000, 0x00000000, 0x00000000,
+	0x3c020006, 0x34420001, 0xaf420030, 0x00000000, 0x00000000, 0x00000000,
+	0x8f420000, 0x30420010, 0x1040fffd, 0x00001021, 0x03e00008, 0x00000000,
+	0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x1060001e,
+	0xafbf0014, 0x0e001006, 0x00000000, 0x8f830018, 0x8e020018, 0xac620000,
+	0x8f840018, 0x9602000c, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018,
+	0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018,
+	0x3c026000, 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e,
+	0x8f850018, 0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffc8, 0xafb3001c,
+	0x00009821, 0xafb7002c, 0x0000b821, 0xafbe0030, 0x0000f021, 0xafb50024,
+	0x27550100, 0xafbf0034, 0xafb60028, 0xafb40020, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x96a20008, 0x8f540100, 0x8eb20018, 0x30420001, 0x10400037,
+	0x02a0b021, 0x8f630054, 0x2642ffff, 0x00431023, 0x18400006, 0x00000000,
+	0x0000000d, 0x00000000, 0x24000128, 0x0a000372, 0x00002021, 0x8f62004c,
+	0x02421023, 0x18400028, 0x00002021, 0x93650120, 0x93640121, 0x3c030800,
+	0x8c62008c, 0x308400ff, 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b,
+	0xac62008c, 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122,
+	0x30420001, 0x00021023, 0x30420005, 0x0a000372, 0x34440004, 0x27660100,
+	0x00041080, 0x00c21021, 0x8c430000, 0x02431823, 0x04600004, 0x24820001,
+	0x30440007, 0x1485fff9, 0x00041080, 0x10870007, 0x3c030800, 0xa3640121,
+	0x8c620094, 0x24040005, 0x24420001, 0x0a000372, 0xac620094, 0x24040004,
+	0x00809821, 0x9362003f, 0x304400ff, 0x38830016, 0x2c630001, 0x38820010,
+	0x2c420001, 0x00621825, 0x1460000c, 0x24020001, 0x38830008, 0x2c630001,
+	0x38820014, 0x2c420001, 0x00621825, 0x14600005, 0x24020001, 0x24020012,
+	0x14820002, 0x00001021, 0x24020001, 0x50400007, 0x8eb10020, 0x8ea20020,
+	0x8f630040, 0x00408821, 0x00431023, 0x5c400001, 0x8f710040, 0x9343010b,
+	0x24020004, 0x54620005, 0x36730080, 0x96a20008, 0x36730002, 0x24170001,
+	0x305e0020, 0x2402fffb, 0x02628024, 0x1200002a, 0x3c030800, 0x8c620030,
+	0x02021024, 0x10400026, 0x3c020800, 0x8c430020, 0x10600024, 0x32620004,
+	0x0e001006, 0x00000000, 0x8f830018, 0x8f420100, 0xac620000, 0x8f840018,
+	0x02201821, 0x32620002, 0xac900004, 0x8f840018, 0x50400001, 0x8ec30014,
+	0xac830008, 0x8f830018, 0x8ec20020, 0xac62000c, 0x8f840018, 0x8f620040,
+	0xac820010, 0x8f830018, 0x8ec20018, 0xac620014, 0x8f840018, 0x3c026000,
+	0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c024010,
+	0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x32620004, 0x10400076,
+	0x00003821, 0x3c029000, 0x34420001, 0x3c038000, 0x02821025, 0xa360007c,
+	0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023,
+	0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c,
+	0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff,
+	0x93620023, 0x3042007f, 0xa3620023, 0xaf720064, 0x3c023fff, 0x0a0003f1,
+	0x3442ffff, 0x8f62005c, 0x02421023, 0x04400011, 0x00000000, 0x8f65005c,
+	0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf720064, 0x00a32823,
+	0x00852821, 0x0045102b, 0x10400004, 0x02451021, 0x3c053fff, 0x34a5ffff,
+	0x02451021, 0xaf62005c, 0x24070001, 0xaf72004c, 0x8f620054, 0x16420005,
+	0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a,
+	0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800,
+	0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021,
+	0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074,
+	0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001,
+	0x02821025, 0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004,
+	0x00000000, 0x0e000f2a, 0x00000000, 0x00403821, 0x10e00017, 0x3c029000,
+	0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02821025,
+	0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002,
+	0x3c031000, 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x8ea30014, 0x8f620040,
+	0x14430003, 0x00431023, 0x0a000443, 0x00001021, 0x28420001, 0x10400034,
+	0x00000000, 0x8f620040, 0xaf630040, 0x9362003e, 0x30420001, 0x1440000b,
+	0x3c029000, 0x93620022, 0x24420001, 0xa3620022, 0x93630022, 0x3c020800,
+	0x8c440098, 0x0064182b, 0x1460001e, 0x3c020800, 0x3c029000, 0x34420001,
+	0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x3c038000, 0x9362007d, 0x34630001, 0x3c048000, 0x02831825,
+	0x34420001, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, 0x24020001, 0xaf4301f8,
+	0xa7620012, 0x0a000476, 0xa3600022, 0x9743007a, 0x9444002a, 0x00641821,
+	0x3063fffe, 0xa7630012, 0x0e000b68, 0x00000000, 0x12e00003, 0x00000000,
+	0x0e000f27, 0x00000000, 0x53c00004, 0x96a20008, 0x0e000c10, 0x00000000,
+	0x96a20008, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028, 0x8fb50024,
+	0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042,
+	0x30420001, 0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0010, 0x97420108,
+	0x2403000b, 0x304400ff, 0x1083004e, 0x2882000c, 0x10400011, 0x24020006,
+	0x1082003e, 0x28820007, 0x10400007, 0x28820008, 0x1080002b, 0x24020001,
+	0x1082002e, 0x3c026000, 0x0a000504, 0x00000000, 0x14400061, 0x2882000a,
+	0x1440002b, 0x00000000, 0x0a0004ec, 0x00000000, 0x2402001c, 0x1082004e,
+	0x2882001d, 0x1040000e, 0x24020019, 0x10820041, 0x2882001a, 0x10400005,
+	0x2402000e, 0x10820036, 0x00000000, 0x0a000504, 0x00000000, 0x2402001b,
+	0x1082003c, 0x00000000, 0x0a000504, 0x00000000, 0x240200c1, 0x10820040,
+	0x288200c2, 0x10400005, 0x24020080, 0x1082001f, 0x00000000, 0x0a000504,
+	0x00000000, 0x240200c2, 0x1082003b, 0x00000000, 0x0a000504, 0x00000000,
+	0x3c026000, 0x0e000c7d, 0xac400808, 0x0a000506, 0x8fbf0010, 0x8c444448,
+	0x3c030800, 0xac640064, 0x0e000c7d, 0x00000000, 0x3c026000, 0x8c444448,
+	0x3c030800, 0x0a000505, 0xac640068, 0x8f440100, 0x0e000508, 0x00000000,
+	0x3c026000, 0x8c444448, 0x3c030800, 0x0a000505, 0xac64006c, 0x0e000cab,
+	0x00000000, 0x0a000506, 0x8fbf0010, 0x8f440100, 0x0e000cd5, 0x00000000,
+	0x0a000506, 0x8fbf0010, 0x0e000d1c, 0x00000000, 0x0a000506, 0x8fbf0010,
+	0x0000000d, 0x0a000506, 0x8fbf0010, 0x0e0005d7, 0x00000000, 0x0a000506,
+	0x8fbf0010, 0x8f440100, 0x0e000d7e, 0x00000000, 0x0a000506, 0x8fbf0010,
+	0x0e000e95, 0x00000000, 0x0a000506, 0x8fbf0010, 0x0e000626, 0x00000000,
+	0x0a000506, 0x8fbf0010, 0x0e000b68, 0x00000000, 0x0a000506, 0x8fbf0010,
+	0x0000000d, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0x3c029000,
+	0x34420001, 0xafb00010, 0x00808021, 0x02021025, 0x3c038000, 0xafbf0014,
+	0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005,
+	0x34420001, 0xa3620005, 0x8f63004c, 0x8f620054, 0x10620019, 0x3c028000,
+	0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081,
+	0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001,
+	0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021,
+	0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000,
+	0x34420001, 0x02021025, 0x0e000c7d, 0xaf420020, 0x3c029000, 0x34420001,
+	0x3c038000, 0x02021025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02021025, 0xa363007d,
+	0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x8fbf0014, 0xaf5001c0,
+	0x8fb00010, 0x24020002, 0x3c031000, 0xa34201c4, 0xaf4301f8, 0x03e00008,
+	0x27bd0018, 0x27bdffd8, 0xafbf0020, 0xafb3001c, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x93630005, 0x00809021, 0x24020030, 0x30630030, 0x14620072,
+	0x00a09821, 0x3c020800, 0x8c430020, 0x1060006c, 0x00000000, 0x0e001006,
+	0x00000000, 0x8f820018, 0xac520000, 0x9363003e, 0x9362003f, 0x8f840018,
+	0x00031a00, 0x00431025, 0xac820004, 0x93630081, 0x93620082, 0x8f850018,
+	0x00031e00, 0x00021400, 0x00621825, 0xaca30008, 0x8f840018, 0x8f620040,
+	0xac82000c, 0x8f830018, 0x8f620048, 0xac620010, 0x8f840018, 0x8f62004c,
+	0x3c110800, 0xac820014, 0x8f830018, 0x8f620050, 0x26304660, 0x00002021,
+	0xac620018, 0x9602000e, 0x8f850018, 0x3c03c00b, 0x00431025, 0x0e001044,
+	0xaca2001c, 0x8f830018, 0x8f620054, 0xac620000, 0x8f840018, 0x8f620058,
+	0xac820004, 0x8f830018, 0x8f62005c, 0xac620008, 0x8f840018, 0x8f620060,
+	0xac82000c, 0x8f850018, 0x8f620064, 0xaca20010, 0x97630068, 0x9762006a,
+	0x8f840018, 0x00031c00, 0x00431025, 0xac820014, 0x8f830018, 0x00002021,
+	0xac600018, 0x9602000e, 0x8f850018, 0x3c03c00c, 0x00431025, 0x0e001044,
+	0xaca2001c, 0x8f840018, 0x8f630018, 0xac830000, 0x936200c4, 0x30420002,
+	0x10400006, 0x00000000, 0x976200c8, 0x8f830018, 0x3042ffff, 0x0a0005b5,
+	0xac620004, 0x8f820018, 0xac400004, 0x8f830018, 0x8f62006c, 0xac620008,
+	0x8f840018, 0x8f6200dc, 0xac82000c, 0x8f830018, 0xac600010, 0x93620005,
+	0x8f830018, 0x00021600, 0x00531025, 0xac620014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x26224660, 0xaca30018, 0x9443000e, 0x8f850018,
+	0x3c02400d, 0x00621825, 0x0e001044, 0xaca3001c, 0x0e000d48, 0x02402021,
+	0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008,
+	0x27bd0028, 0x27bdffe0, 0xafb00010, 0x27500100, 0xafbf0018, 0xafb10014,
+	0x9603000c, 0x240200c1, 0x5462001d, 0x8e040000, 0x3c029000, 0x8f440100,
+	0x34420001, 0x3c038000, 0x00821025, 0xaf420020, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d, 0x34630001, 0x3c058000,
+	0x00831825, 0x34420004, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00451024,
+	0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0, 0xa34201c4, 0xaf4301f8,
+	0x0a000622, 0x8fbf0018, 0x8f65004c, 0x24060001, 0x0e000db5, 0x2407049f,
+	0x3c020800, 0x8c430020, 0x9611000c, 0x1060001d, 0x8e100000, 0x0e001006,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x00111400, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f840018, 0x240204a2, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019,
+	0x00621825, 0x0e001044, 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x27bdffb0, 0xafb1002c, 0x27510100, 0xafbf004c,
+	0xafbe0048, 0xafb70044, 0xafb60040, 0xafb5003c, 0xafb40038, 0xafb30034,
+	0xafb20030, 0xafb00028, 0x8e350000, 0x9634000c, 0x3c026000, 0x8c434448,
+	0x0000f021, 0xaf630170, 0x8f620040, 0x8e230014, 0x0000b821, 0x00431023,
+	0x044001ec, 0x0000b021, 0x32820010, 0x1040002e, 0x3c026000, 0x9363003f,
+	0x9222000e, 0x10430006, 0x2402000c, 0x9223000f, 0x10620003, 0x24020014,
+	0x14620025, 0x3c026000, 0x32820004, 0x10400007, 0x241e0001, 0x8f620050,
+	0x24420001, 0xaf620050, 0x8f630054, 0x24630001, 0xaf630054, 0x32830102,
+	0x24020002, 0x5462000d, 0x9222000f, 0x8f620040, 0x24420001, 0xaf620040,
+	0x8f630048, 0x8f620040, 0x24630001, 0x54620005, 0x9222000f, 0x8f620048,
+	0x24420001, 0xaf620048, 0x9222000f, 0xa362003f, 0x9223000f, 0x24020012,
+	0x14620007, 0x3c026000, 0x3c030800, 0x8c620074, 0x24420001, 0x0e000f6e,
+	0xac620074, 0x3c026000, 0x8c434448, 0x32820040, 0xaf630174, 0x32830020,
+	0xafa30010, 0x32830080, 0xafa30014, 0x32830001, 0xafa3001c, 0x32830008,
+	0xafa30020, 0x32830100, 0x104000bb, 0xafa30018, 0x8e260010, 0x8f630054,
+	0x24c2ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, 0x00000000,
+	0x24000128, 0x0a0006b2, 0x00009021, 0x8f62004c, 0x00c21023, 0x18400028,
+	0x00009021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff,
+	0x24420001, 0x30a500ff, 0x00804021, 0x1485000b, 0xac62008c, 0x3c040800,
+	0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, 0x00021023,
+	0x30420005, 0x0a0006b2, 0x34520004, 0x27670100, 0x00041080, 0x00e21021,
+	0x8c430000, 0x00c31823, 0x04600004, 0x24820001, 0x30440007, 0x1485fff9,
+	0x00041080, 0x10880007, 0x3c030800, 0xa3640121, 0x8c620094, 0x24120005,
+	0x24420001, 0x0a0006b2, 0xac620094, 0x24120004, 0x32420001, 0x10400020,
+	0x3c020800, 0x8c430020, 0x8e300000, 0x1060001c, 0x8e330010, 0x0e001006,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac530014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024010, 0x00621825,
+	0x0e001044, 0xaca3001c, 0x32420004, 0x10400060, 0x00003821, 0x3c029000,
+	0x8e260010, 0x34420001, 0x3c038000, 0x02a21025, 0xa360007c, 0xaf420020,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, 0x30420080,
+	0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c, 0x8f620064,
+	0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff, 0x93620023,
+	0x3042007f, 0xa3620023, 0xaf660064, 0x3c023fff, 0x0a000702, 0x3442ffff,
+	0x8f62005c, 0x00c21023, 0x04400011, 0x00000000, 0x8f65005c, 0x8f630064,
+	0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf660064, 0x00a32823, 0x00852821,
+	0x0045102b, 0x10400004, 0x00c51021, 0x3c053fff, 0x34a5ffff, 0x00c51021,
+	0xaf62005c, 0x24070001, 0xaf66004c, 0x8f620054, 0x14c20005, 0x00000000,
+	0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a, 0x00022880,
+	0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c,
+	0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800,
+	0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe,
+	0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001, 0x02a21025,
+	0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620005, 0x00e0b021,
+	0x0e000f2a, 0x00000000, 0x00403821, 0x00e0b021, 0x8fa20010, 0x10400008,
+	0x00000000, 0x8e220018, 0xaf620018, 0x8e23001c, 0xaf63001c, 0x8e220020,
+	0x24160001, 0xaf620058, 0x13c00036, 0x32820004, 0x10400035, 0x8fa30014,
+	0x93620023, 0x30420040, 0x10400031, 0x3c020800, 0x8c430020, 0x1060001c,
+	0x8e300000, 0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x8f830018,
+	0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018,
+	0xac400010, 0x8f830018, 0x24020587, 0xac620014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018,
+	0x3c024019, 0x00621825, 0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001,
+	0x02a21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x24020001, 0xaf62000c, 0x93630023, 0x3c028000, 0x34420001, 0x02a21025,
+	0x306300bf, 0xa3630023, 0xaf420020, 0x8fa30014, 0x10600012, 0x8fa3001c,
+	0x9362007c, 0x24420001, 0xa362007c, 0x9363007e, 0x9362007a, 0x1462000b,
+	0x8fa3001c, 0x9362007c, 0x3c030800, 0x8c640024, 0x0044102b, 0x14400005,
+	0x8fa3001c, 0x0e000f2a, 0x00000000, 0x02c2b025, 0x8fa3001c, 0x3062ffff,
+	0x10400003, 0x32820200, 0x0a000793, 0x24170004, 0x10400003, 0x00000000,
+	0x24170040, 0x24160001, 0x13c0005d, 0x32820002, 0x1040005c, 0x8fa20020,
+	0x9222000a, 0x30420020, 0x10400033, 0x3c100800, 0x93620023, 0x30420040,
+	0x1040002f, 0x8e020020, 0x1040001e, 0x3c029000, 0x0e001006, 0x00000000,
+	0x8f820018, 0xac550000, 0x8f840018, 0x3c02008d, 0xac820004, 0x8f830018,
+	0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f840018,
+	0x240205bf, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019, 0x00621825,
+	0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001, 0x02a21025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023,
+	0x3c028000, 0x34420001, 0x02a21025, 0x306300bf, 0xa3630023, 0xaf420020,
+	0x8e020020, 0x10400023, 0x8fa20020, 0x0e001006, 0x00000000, 0x8f840018,
+	0x8e230000, 0xac830000, 0x9222000a, 0x8f830018, 0x00021600, 0xac620004,
+	0x8f840018, 0x8f620040, 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c,
+	0x9362003f, 0x8f840018, 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000,
+	0xac600014, 0x8f850018, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
+	0x9443466e, 0x8f850018, 0x3c02401a, 0x00621825, 0x0e001044, 0xaca3001c,
+	0x8fa20020, 0x1040000e, 0x8fa20018, 0x9222000a, 0xa3620082, 0x56e00005,
+	0x36f70008, 0x8fa30018, 0x10600004, 0x00000000, 0x36f70008, 0x0a000801,
+	0x24160001, 0x0e000de1, 0x02a02021, 0x8fa20018, 0x10400003, 0x00000000,
+	0x36f70010, 0x24160001, 0x12c00019, 0x3c029000, 0x34420001, 0x02a21025,
+	0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
+	0x3c038000, 0x9362007d, 0x34630001, 0x3c048000, 0x02a31825, 0x02e21025,
+	0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002,
+	0x3c031000, 0xaf5501c0, 0xa34201c4, 0xaf4301f8, 0x9363003f, 0x24020012,
+	0x14620004, 0x3c026000, 0x0e000f6e, 0x00000000, 0x3c026000, 0x8c434448,
+	0xaf630178, 0x8fbf004c, 0x8fbe0048, 0x8fb70044, 0x8fb60040, 0x8fb5003c,
+	0x8fb40038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x03e00008,
+	0x27bd0050, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f500180, 0x97420184,
+	0x30420200, 0x14400015, 0x00000000, 0x8f430188, 0x3c02ff00, 0x00621824,
+	0x3c020200, 0x10620031, 0x0043102b, 0x14400007, 0x3c020300, 0x1060000b,
+	0x3c020100, 0x1062000d, 0x00000000, 0x0a0008b4, 0x00000000, 0x10620027,
+	0x3c020400, 0x1062003e, 0x02002021, 0x0a0008b4, 0x00000000, 0x0e000e1e,
+	0x02002021, 0x0a0008b6, 0x8fbf0014, 0x93620005, 0x30420020, 0x1440005e,
+	0x8fbf0014, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000,
+	0x34630001, 0x02031825, 0x34420020, 0xa3620005, 0xaf430020, 0x93620005,
+	0x30420020, 0x14400003, 0x02002021, 0x0000000d, 0x02002021, 0x0e000553,
+	0x24055854, 0x0a0008b6, 0x8fbf0014, 0x93620005, 0x30420001, 0x1040003f,
+	0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c048000, 0x3c030800,
+	0x304200fe, 0xa3620005, 0x8c620020, 0x34840001, 0x02042025, 0xaf440020,
+	0x1040002d, 0x8fbf0014, 0x0a000894, 0x00000000, 0x00002821, 0x00003021,
+	0x0e000f78, 0x240706a4, 0x3c020800, 0x8c430020, 0x10600023, 0x8fbf0014,
+	0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x93630082, 0x9362003f,
+	0x8f840018, 0x00031a00, 0x00431025, 0xac820004, 0x8f830018, 0xac600008,
+	0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
+	0x9443466e, 0x8f850018, 0x3c02400a, 0x00621825, 0x0e001044, 0xaca3001c,
+	0x0a0008b6, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93420148, 0x2444ffff, 0x2c830005,
+	0x10600047, 0x3c020800, 0x24424598, 0x00041880, 0x00621821, 0x8c640000,
+	0x00800008, 0x00000000, 0x8f430144, 0x8f62000c, 0x14620006, 0x24020001,
+	0xaf62000c, 0x0e000909, 0x00000000, 0x0a000907, 0x8fbf0010, 0x8f62000c,
+	0x0a000900, 0x00000000, 0x97630010, 0x8f420144, 0x14430006, 0x24020001,
+	0xa7620010, 0x0e000eeb, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620010,
+	0x0a000900, 0x00000000, 0x97630012, 0x8f420144, 0x14430006, 0x24020001,
+	0xa7620012, 0x0e000f06, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620012,
+	0x0a000900, 0x00000000, 0x97630014, 0x8f420144, 0x14430006, 0x24020001,
+	0xa7620014, 0x0e000f21, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620014,
+	0x0a000900, 0x00000000, 0x97630016, 0x8f420144, 0x14430006, 0x24020001,
+	0xa7620016, 0x0e000f24, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620016,
+	0x14400006, 0x8fbf0010, 0x3c030800, 0x8c620070, 0x24420001, 0xac620070,
+	0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93620081,
+	0x3c030800, 0x8c640048, 0x0044102b, 0x14400028, 0x3c029000, 0x8f460140,
+	0x34420001, 0x3c038000, 0x00c21025, 0xaf420020, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x3c048000, 0x34840001, 0x3c059000, 0x34a50001, 0x3c078000,
+	0x24020012, 0x24030080, 0x00c42025, 0x00c52825, 0xa362003f, 0xa3630082,
+	0xaf440020, 0xaf450020, 0x8f420020, 0x00471024, 0x1440fffd, 0x3c038000,
+	0x9362007d, 0x34630001, 0x3c048000, 0x00c31825, 0x34420020, 0xa362007d,
+	0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0x0a00096d, 0xaf4601c0, 0x93620081, 0x24420001, 0x0e000f2a, 0xa3620081,
+	0x9763006a, 0x00032880, 0x14a00002, 0x00403821, 0x24050001, 0x97630068,
+	0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b,
+	0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001,
+	0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c,
+	0x10e0001a, 0x3c029000, 0x8f440140, 0x34420001, 0x3c038000, 0x00821025,
+	0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000,
+	0x9362007d, 0x34630001, 0x3c058000, 0x00831825, 0x34420004, 0xa362007d,
+	0xaf430020, 0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0xaf4401c0, 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018,
+	0x27bdffd8, 0xafb3001c, 0x27530100, 0xafbf0024, 0xafb40020, 0xafb20018,
+	0xafb10014, 0xafb00010, 0x96620008, 0x3c140800, 0x8f520100, 0x30420001,
+	0x104000cf, 0x00000000, 0x8e700018, 0x8f630054, 0x2602ffff, 0x00431023,
+	0x18400006, 0x00000000, 0x0000000d, 0x00000000, 0x24000128, 0x0a0009b6,
+	0x00008821, 0x8f62004c, 0x02021023, 0x18400028, 0x00008821, 0x93650120,
+	0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff, 0x24420001, 0x30a500ff,
+	0x00803821, 0x1485000b, 0xac62008c, 0x3c040800, 0x8c830090, 0x24630001,
+	0xac830090, 0x93620122, 0x30420001, 0x00021023, 0x30420005, 0x0a0009b6,
+	0x34510004, 0x27660100, 0x00041080, 0x00c21021, 0x8c430000, 0x02031823,
+	0x04600004, 0x24820001, 0x30440007, 0x1485fff9, 0x00041080, 0x10870007,
+	0x3c030800, 0xa3640121, 0x8c620094, 0x24110005, 0x24420001, 0x0a0009b6,
+	0xac620094, 0x24110004, 0x32220001, 0x1040001e, 0x8e820020, 0x1040001d,
+	0x32220004, 0x0e001006, 0x00000000, 0x8f820018, 0xac520000, 0x8f840018,
+	0x24020001, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018,
+	0x3c024010, 0x00621825, 0x0e001044, 0xaca3001c, 0x32220004, 0x10400076,
+	0x00003821, 0x3c029000, 0x34420001, 0x3c038000, 0x02421025, 0xa360007c,
+	0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023,
+	0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c,
+	0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff,
+	0x93620023, 0x3042007f, 0xa3620023, 0xaf700064, 0x3c023fff, 0x0a000a03,
+	0x3442ffff, 0x8f62005c, 0x02021023, 0x04400011, 0x00000000, 0x8f65005c,
+	0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf700064, 0x00a32823,
+	0x00852821, 0x0045102b, 0x10400004, 0x02051021, 0x3c053fff, 0x34a5ffff,
+	0x02051021, 0xaf62005c, 0x24070001, 0xaf70004c, 0x8f620054, 0x16020005,
+	0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a,
+	0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800,
+	0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021,
+	0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074,
+	0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001,
+	0x02421025, 0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004,
+	0x00000000, 0x0e000f2a, 0x00000000, 0x00403821, 0x10e00017, 0x3c029000,
+	0x34420001, 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02421025,
+	0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002,
+	0x3c031000, 0xaf5201c0, 0xa34201c4, 0xaf4301f8, 0x9342010b, 0x8e830020,
+	0x27500100, 0x38420006, 0x10600029, 0x2c510001, 0x0e001006, 0x00000000,
+	0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x96020008, 0xac820004,
+	0x8f830018, 0x8e020014, 0xac620008, 0x8f850018, 0x3c026000, 0x8c434448,
+	0xaca3000c, 0x8f840018, 0x96020012, 0xac820010, 0x8f850018, 0x8e030020,
+	0xaca30014, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400, 0x00431025,
+	0xac820018, 0x12200005, 0x3c020800, 0x9443466e, 0x8f840018, 0x0a000a78,
+	0x3c024013, 0x9443466e, 0x8f840018, 0x3c024014, 0x00621825, 0xac83001c,
+	0x0e001044, 0x24040001, 0x8e630014, 0x8f620040, 0x14430003, 0x00431023,
+	0x0a000a83, 0x00001021, 0x28420001, 0x10400034, 0x00000000, 0x8f620040,
+	0xaf630040, 0x9362003e, 0x30420001, 0x1440000b, 0x3c029000, 0x93620022,
+	0x24420001, 0xa3620022, 0x93630022, 0x3c020800, 0x8c440098, 0x0064182b,
+	0x1460001e, 0x3c020800, 0x3c029000, 0x34420001, 0x02421025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000,
+	0x9362007d, 0x34630001, 0x3c048000, 0x02431825, 0x34420001, 0xa362007d,
+	0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0xaf5201c0, 0xa34201c4, 0x24020001, 0xaf4301f8, 0xa7620012, 0x0a000ab6,
+	0xa3600022, 0x9743007a, 0x9444002a, 0x00641821, 0x3063fffe, 0xa7630012,
+	0x0e000b68, 0x00000000, 0x97420108, 0x8fbf0024, 0x8fb40020, 0x8fb3001c,
+	0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042, 0x30420001, 0x03e00008,
+	0x27bd0028, 0x27bdffe0, 0xafb20018, 0x3c120800, 0x8e420020, 0xafb00010,
+	0x27500100, 0xafbf001c, 0x10400046, 0xafb10014, 0x0e001006, 0x00000000,
+	0x8f840018, 0x8e020000, 0xac820000, 0x936300b1, 0x936200c5, 0x8f850018,
+	0x00031e00, 0x00021400, 0x34420100, 0x00621825, 0xaca30004, 0x8f840018,
+	0x8e02001c, 0xac820008, 0x8f830018, 0x8f620048, 0xac62000c, 0x8f840018,
+	0x96020012, 0xac820010, 0x8f830018, 0x8f620040, 0x24040001, 0xac620014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800, 0x24514660, 0xaca30018,
+	0x9623000e, 0x8f850018, 0x3c024016, 0x00621825, 0x0e001044, 0xaca3001c,
+	0x96030008, 0x30630010, 0x1060001c, 0x8e420020, 0x1040001a, 0x8e100000,
+	0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x8f830018, 0xac600004,
+	0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
+	0x8f830018, 0xac600014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001,
+	0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015, 0x00431025, 0x0e001044,
+	0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x27bdffe0, 0xafb20018, 0x3c120800, 0x8e420020,
+	0xafb00010, 0x27500100, 0xafbf001c, 0x10400041, 0xafb10014, 0x0e001006,
+	0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x24020100,
+	0xac820004, 0x8f830018, 0x8e02001c, 0xac620008, 0x8f840018, 0x8e020018,
+	0xac82000c, 0x8f830018, 0x96020012, 0xac620010, 0x8f840018, 0x96020008,
+	0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
+	0x24514660, 0xaca30018, 0x9623000e, 0x8f850018, 0x3c024017, 0x00621825,
+	0x0e001044, 0xaca3001c, 0x96030008, 0x30630010, 0x1060001c, 0x8e420020,
+	0x1040001a, 0x8e100000, 0x0e001006, 0x00000000, 0x8f820018, 0xac500000,
+	0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c,
+	0x8f820018, 0xac400010, 0x8f830018, 0xac600014, 0x8f850018, 0x3c036000,
+	0x8c634448, 0x24040001, 0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015,
+	0x00431025, 0x0e001044, 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010,
+	0x936200c4, 0x30420002, 0x10400019, 0x00000000, 0x936200c5, 0x936300b1,
+	0x00431023, 0x304400ff, 0x30830080, 0x10600004, 0x00000000, 0x0000000d,
+	0x00000000, 0x24000a6a, 0x93620004, 0x00441023, 0x304400ff, 0x30830080,
+	0x10600004, 0x2482ffff, 0x8f650024, 0x0a000b82, 0x00000000, 0x00022b00,
+	0x8f620024, 0x0045102b, 0x10400002, 0x00000000, 0x8f650024, 0x8f620048,
+	0x8f630040, 0x00431823, 0x0065202b, 0x10800004, 0x00000000, 0x8f620040,
+	0x00451021, 0xaf620048, 0x9762003c, 0x0062102b, 0x10400041, 0x8fbf0010,
+	0x10a0003f, 0x3c029000, 0x34420001, 0x3c040800, 0x8c830080, 0x8f450100,
+	0x3c068000, 0x24630001, 0x00a21025, 0xac830080, 0xaf420020, 0x8f420020,
+	0x00461024, 0x1440fffd, 0x3c038000, 0x9362007d, 0x34630001, 0x3c048000,
+	0x00a31825, 0x34420004, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024,
+	0x1440fffd, 0x24020002, 0x3c030800, 0xaf4501c0, 0xa34201c4, 0x8c640020,
+	0x3c021000, 0xaf4201f8, 0x1080001f, 0x8fbf0010, 0x0e001006, 0x00000000,
+	0x8f830018, 0x8f420100, 0xac620000, 0x8f840018, 0x8f620040, 0xac820004,
+	0x8f850018, 0x8f620048, 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018,
+	0xac400010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, 0x8c434448,
+	0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c0240c2, 0x00621825,
+	0xac83001c, 0x0e001044, 0x24040001, 0x8fbf0010, 0x03e00008, 0x27bd0018,
+	0x3c020800, 0x24423958, 0xaf82000c, 0x03e00008, 0x00000000, 0x27bdffe8,
+	0xafb00010, 0x27500100, 0xafbf0014, 0x8e02001c, 0x14400003, 0x3c020800,
+	0x0000000d, 0x3c020800, 0x8c430020, 0x10600026, 0x00001021, 0x0e001006,
+	0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x8e02001c,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f840018, 0x8e020018, 0xac82000c,
+	0x8f850018, 0x96020012, 0xaca20010, 0x8f830018, 0x3c106000, 0xac600014,
+	0x8f840018, 0x8e024448, 0x3c030800, 0xac820018, 0x9462466e, 0x8f840018,
+	0x3c034012, 0x00431025, 0xac82001c, 0x0e001044, 0x24040001, 0x8e036800,
+	0x00001021, 0x3c040001, 0x00641825, 0xae036800, 0x0a000c0d, 0x8fbf0014,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x97430078,
+	0x9444002e, 0x00001021, 0x00641821, 0x3063fffe, 0x03e00008, 0xa7630010,
+	0x27450100, 0x8f640048, 0x8ca30018, 0x00641023, 0x18400021, 0x00000000,
+	0xaf630048, 0x8f620040, 0x9763003c, 0x00821023, 0x0043102a, 0x1040001a,
+	0x3c029000, 0x8ca40000, 0x34420001, 0x3c038000, 0x00821025, 0xaf420020,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d,
+	0x34630001, 0x3c058000, 0x00831825, 0x34420004, 0xa362007d, 0xaf430020,
+	0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0,
+	0xa34201c4, 0xaf4301f8, 0x03e00008, 0x00001021, 0x8f420100, 0x34420001,
+	0xaf4200a4, 0x03e00008, 0x00001021, 0x27bdffe0, 0xafbf0018, 0xafb10014,
+	0xafb00010, 0x9362007e, 0x30d000ff, 0x16020029, 0x00808821, 0x93620080,
+	0x16020026, 0x00000000, 0x9362007f, 0x16020023, 0x00000000, 0x9362007a,
+	0x16020004, 0x00000000, 0x0000000d, 0x00000000, 0x24000771, 0x0e000f49,
+	0x00000000, 0x3c039000, 0x34630001, 0x3c048000, 0x02231825, 0xa370007a,
+	0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x3c028000, 0x9363007d,
+	0x34420001, 0x3c048000, 0x02221025, 0xa363007d, 0xaf420020, 0x8f4201f8,
+	0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5101c0, 0xa34201c4,
+	0xaf4301f8, 0x0a000c79, 0x8fbf0018, 0x0000000d, 0x00000000, 0x24000781,
+	0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800,
+	0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x10600024, 0xafbf0014,
+	0x0e001006, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
+	0x8e020004, 0xac820004, 0x8f830018, 0x8e020018, 0xac620008, 0x8f840018,
+	0x8e03001c, 0xac83000c, 0x9602000c, 0x9203000a, 0x8f840018, 0x00021400,
+	0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
+	0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e, 0x8f850018,
+	0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8,
+	0xafb00010, 0x27500100, 0x10600020, 0xafbf0014, 0x0e001006, 0x00000000,
+	0x8f820018, 0xac400000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008,
+	0x8f830018, 0xac60000c, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400,
+	0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
+	0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e, 0x8f850018,
+	0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010, 0x27500100,
+	0xafbf0014, 0x9602000c, 0x10400024, 0x00802821, 0x3c020800, 0x8c430020,
+	0x1060003a, 0x8fbf0014, 0x0e001006, 0x00000000, 0x8f840018, 0x8e030000,
+	0xac830000, 0x9602000c, 0x8f840018, 0x00021400, 0xac820004, 0x8f830018,
+	0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
+	0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
+	0xaca30018, 0x9443466e, 0x8f850018, 0x3c02400b, 0x00621825, 0x0e001044,
+	0xaca3001c, 0x0a000d19, 0x8fbf0014, 0x93620005, 0x30420010, 0x14400015,
+	0x3c029000, 0x34420001, 0x00a21025, 0xaf420020, 0x3c038000, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x93620005, 0x34630001,
+	0x00a02021, 0x00a31825, 0x24055852, 0x34420010, 0xa3620005, 0x0e000553,
+	0xaf430020, 0x0a000d19, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010,
+	0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010,
+	0x27500100, 0x10600022, 0xafbf0014, 0x0e001006, 0x00000000, 0x8f840018,
+	0x8e020004, 0xac820000, 0x9603000c, 0x9762002c, 0x8f840018, 0x00031c00,
+	0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018,
+	0x3c02400e, 0x00621825, 0x0e001044, 0xaca3001c, 0x0e000d48, 0x8e040000,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c038000, 0x8f420278,
+	0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf440240, 0xa3420244,
+	0x03e00008, 0xaf430278, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014,
+	0x00808821, 0xafb20018, 0x00c09021, 0xafb00010, 0x30b0ffff, 0x1060001c,
+	0xafbf001c, 0x0e001006, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018,
+	0x00101400, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000,
+	0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c024019,
+	0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x27450100,
+	0xafbf0010, 0x94a3000c, 0x240200c1, 0x14620029, 0x00803021, 0x3c029000,
+	0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x3c028000, 0x34420001, 0x3c049000, 0x34840001, 0x3c058000,
+	0x24030012, 0x00c21025, 0x00c42025, 0xa363003f, 0xaf420020, 0xaf440020,
+	0x8f420020, 0x00451024, 0x1440fffd, 0x3c038000, 0x9362007d, 0x34630001,
+	0x3c048000, 0x00c31825, 0x34420020, 0xa362007d, 0xaf430020, 0x8f4201f8,
+	0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4,
+	0xaf4301f8, 0x0a000db3, 0x8fbf0010, 0x00c02021, 0x94a5000c, 0x24060001,
+	0x0e000f78, 0x240706d8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800,
+	0x8c430020, 0x27bdffe0, 0xafb00010, 0x00808021, 0xafb20018, 0x00a09021,
+	0xafb10014, 0x30d100ff, 0x1060001c, 0xafbf001c, 0x0e001006, 0x00000000,
+	0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018,
+	0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
+	0xac520014, 0x8f840018, 0x3c026000, 0x8c434448, 0x3c020800, 0xac830018,
+	0x9443466e, 0x8f840018, 0x3c024010, 0x00621825, 0xac83001c, 0x0e001044,
+	0x02202021, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008,
+	0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x93620005, 0x30420001,
+	0x10400033, 0x00808021, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005,
+	0x3c048000, 0x3c030800, 0x304200fe, 0xa3620005, 0x8c620020, 0x34840001,
+	0x02042025, 0xaf440020, 0x10400020, 0x8fbf0014, 0x0e001006, 0x00000000,
+	0x8f820018, 0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00,
+	0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000,
+	0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c02400a,
+	0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x8fbf0014, 0x8fb00010,
+	0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x8f420188, 0x00803021,
+	0x9364003f, 0x24030012, 0x00021402, 0x1483001c, 0x304500ff, 0x3c029000,
+	0x34420001, 0x3c038000, 0x00c21025, 0xa3650080, 0xa365007a, 0xaf420020,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001,
+	0x3c048000, 0x00c21025, 0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024,
+	0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, 0xaf4301f8,
+	0x0a000e54, 0x8fbf0010, 0x9362007e, 0x1445000e, 0x00000000, 0x93620080,
+	0x1045000b, 0x00000000, 0xa3650080, 0x8f820000, 0x93660080, 0x8f440180,
+	0x8f65004c, 0x8c430000, 0x0060f809, 0x00000000, 0x0a000e54, 0x8fbf0010,
+	0xa3650080, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020,
+	0x27bdffe0, 0xafb10014, 0x00808821, 0xafb20018, 0x00a09021, 0xafb00010,
+	0x30d000ff, 0x1060002f, 0xafbf001c, 0x0e001006, 0x00000000, 0x8f820018,
+	0xac510000, 0x8f830018, 0xac700004, 0x8f820018, 0xac520008, 0x8f830018,
+	0xac60000c, 0x8f820018, 0xac400010, 0x9763006a, 0x00032880, 0x50a00001,
+	0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821,
+	0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050,
+	0x00c4182b, 0x54600001, 0x00c02021, 0x8f830018, 0x2402fffe, 0x00822824,
+	0x3c026000, 0xac650014, 0x8f840018, 0x8c434448, 0x3c020800, 0xac830018,
+	0x9443466e, 0x8f840018, 0x3c024011, 0x00621825, 0xac83001c, 0x0e001044,
+	0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008,
+	0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f440100, 0x27500100,
+	0x8f650050, 0x0e000c45, 0x9206001b, 0x3c020800, 0x8c430020, 0x1060001d,
+	0x8e100018, 0x0e001006, 0x00000000, 0x8f840018, 0x8f420100, 0xac820000,
+	0x8f830018, 0xac700004, 0x8f840018, 0x8f620050, 0xac820008, 0x8f830018,
+	0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0x3c026000, 0xac600014,
+	0x8f850018, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e,
+	0x8f850018, 0x3c02401c, 0x00621825, 0x0e001044, 0xaca3001c, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c029000, 0x8f460140, 0x34420001,
+	0x3c038000, 0x00c21025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x3c048000, 0x34840001, 0x3c059000, 0x34a50001, 0x3c078000, 0x24020012,
+	0x24030080, 0x00c42025, 0x00c52825, 0xa362003f, 0xa3630082, 0xaf440020,
+	0xaf450020, 0x8f420020, 0x00471024, 0x1440fffd, 0x3c038000, 0x9362007d,
+	0x34630001, 0x3c048000, 0x00c31825, 0x34420020, 0xa362007d, 0xaf430020,
+	0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0,
+	0xa34201c4, 0x03e00008, 0xaf4301f8, 0x8f430238, 0x3c020800, 0x04610013,
+	0x8c44009c, 0x2406fffe, 0x3c050800, 0x3c038000, 0x2484ffff, 0x14800009,
+	0x00000000, 0x97420078, 0x8ca3007c, 0x24420001, 0x00461024, 0x24630001,
+	0xa7620010, 0x03e00008, 0xaca3007c, 0x8f420238, 0x00431024, 0x1440fff3,
+	0x2484ffff, 0x8f420140, 0x3c031000, 0xaf420200, 0x03e00008, 0xaf430238,
+	0x3c029000, 0x8f440140, 0x34420001, 0x3c038000, 0x00821025, 0xaf420020,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d,
+	0x34630001, 0x3c058000, 0x00831825, 0x34420001, 0xa362007d, 0xaf430020,
+	0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0,
+	0xa34201c4, 0x03e00008, 0xaf4301f8, 0x0000000d, 0x03e00008, 0x00000000,
+	0x0000000d, 0x03e00008, 0x00000000, 0x24020001, 0x03e00008, 0xa7620010,
+	0x9362003f, 0x304400ff, 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001,
+	0x00621825, 0x14600003, 0x24020012, 0x14820003, 0x00000000, 0x03e00008,
+	0x00001021, 0x9363007e, 0x9362007a, 0x14620006, 0x00000000, 0x9363007e,
+	0x24020001, 0x24630001, 0x03e00008, 0xa363007e, 0x9363007e, 0x93620080,
+	0x14620004, 0x24020001, 0xa362000b, 0x03e00008, 0x24020001, 0x03e00008,
+	0x00001021, 0x9362000b, 0x10400021, 0x00001021, 0xa360000b, 0x9362003f,
+	0x304400ff, 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, 0x00621825,
+	0x14600015, 0x00001821, 0x24020012, 0x10820012, 0x00000000, 0x9363007e,
+	0x9362007a, 0x14620007, 0x00000000, 0x9362007e, 0x24030001, 0x24420001,
+	0xa362007e, 0x03e00008, 0x00601021, 0x9363007e, 0x93620080, 0x14620004,
+	0x00001821, 0x24020001, 0xa362000b, 0x24030001, 0x03e00008, 0x00601021,
+	0x03e00008, 0x00000000, 0x24040001, 0xaf64000c, 0x8f6300dc, 0x8f6200cc,
+	0x50620001, 0xa7640010, 0xa7640012, 0xa7640014, 0x03e00008, 0xa7640016,
+	0x27bdffd8, 0xafb00010, 0x00808021, 0xafb3001c, 0x00c09821, 0xafbf0020,
+	0xafb20018, 0xafb10014, 0x93620023, 0x00e09021, 0x30420040, 0x10400020,
+	0x30b1ffff, 0x3c020800, 0x8c430020, 0x1060001c, 0x00000000, 0x0e001006,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x3c02008d, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac520014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019, 0x00621825,
+	0x0e001044, 0xaca3001c, 0x93620023, 0x30420020, 0x14400003, 0x3c020800,
+	0x52600020, 0x3c029000, 0x8c430020, 0x1060001d, 0x3c029000, 0x0e001006,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x00111400, 0xac820004,
+	0x8f830018, 0xac720008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c02401b, 0x00621825,
+	0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023,
+	0x3c028000, 0x34420001, 0x02021025, 0x8fbf0020, 0x8fb3001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x3063009f, 0xa3630023, 0xaf420020, 0x03e00008,
+	0x27bd0028, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100,
+	0x1060001d, 0xafbf0014, 0x0e001006, 0x00000000, 0x8f830018, 0x8e020004,
+	0xac620000, 0x8f840018, 0x8e020018, 0xac820004, 0x8f850018, 0x8e020000,
+	0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018,
+	0xac600014, 0x8f820018, 0xac400018, 0x96030008, 0x3c020800, 0x9444466e,
+	0x8f850018, 0x00031c00, 0x00641825, 0x24040001, 0x0e001044, 0xaca3001c,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c060800, 0x24c54660,
+	0x3c02000a, 0x03421821, 0x94640006, 0x94a2000a, 0x00441023, 0x00021400,
+	0x00021c03, 0x04610006, 0xa4a40006, 0x0000000d, 0x00000000, 0x2400005a,
+	0x0a00101b, 0x24020001, 0x8f820014, 0x0062102b, 0x14400002, 0x00001021,
+	0x24020001, 0x304200ff, 0x1040001c, 0x274a0400, 0x3c07000a, 0x3c020800,
+	0x24454660, 0x94a9000a, 0x8f880014, 0x03471021, 0x94430006, 0x00402021,
+	0xa4a30006, 0x94820006, 0xa4a20006, 0x01221023, 0x00021400, 0x00021403,
+	0x04410006, 0x0048102b, 0x0000000d, 0x00000000, 0x2400005a, 0x0a001036,
+	0x24020001, 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1440ffec,
+	0x03471021, 0x24c44660, 0x8c820010, 0xaf420038, 0x8c830014, 0x3c020005,
+	0xaf43003c, 0xaf420030, 0xaf800010, 0xaf8a0018, 0x03e00008, 0x00000000,
+	0x27bdffe0, 0x8f820010, 0x8f850018, 0x3c070800, 0x24e84660, 0xafbf001c,
+	0xafb20018, 0xafb10014, 0xafb00010, 0x9503000a, 0x8d060014, 0x00009021,
+	0x309000ff, 0x00e08821, 0x24420001, 0x24a50020, 0x24630001, 0xaf820010,
+	0xaf850018, 0xa503000a, 0x24c30020, 0x3c028000, 0x04c10007, 0xad030014,
+	0x00621024, 0x14400005, 0x26224660, 0x8d020010, 0x24420001, 0xad020010,
+	0x26224660, 0x9444000a, 0x94450018, 0x0010102b, 0x00a41826, 0x2c630001,
+	0x00621825, 0x1060001c, 0x3c030006, 0x8f820010, 0x24120001, 0x00021140,
+	0x00431025, 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x27450400,
+	0x8f420000, 0x30420010, 0x1040fffd, 0x26224660, 0x9444000a, 0x94430018,
+	0xaf800010, 0xaf850018, 0x14830012, 0x26274660, 0x0e0010d2, 0x00000000,
+	0x1600000e, 0x26274660, 0x0e001006, 0x00000000, 0x0a00108f, 0x26274660,
+	0x00041c00, 0x00031c03, 0x00051400, 0x00021403, 0x00621823, 0x18600002,
+	0x3c026000, 0xac400808, 0x26274660, 0x94e2000e, 0x94e3000c, 0x24420001,
+	0xa4e2000e, 0x3042ffff, 0x50430001, 0xa4e0000e, 0x12000005, 0x3c02000a,
+	0x94e2000a, 0xa74200a2, 0x0a0010cc, 0x02401021, 0x03421821, 0x94640006,
+	0x94e2000a, 0x00441023, 0x00021400, 0x00021c03, 0x04610006, 0xa4e40006,
+	0x0000000d, 0x00000000, 0x2400005a, 0x0a0010ae, 0x24020001, 0x8f820014,
+	0x0062102b, 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1040001b,
+	0x3c020800, 0x3c06000a, 0x24454660, 0x94a8000a, 0x8f870014, 0x03461021,
+	0x94430006, 0x00402021, 0xa4a30006, 0x94820006, 0xa4a20006, 0x01021023,
+	0x00021400, 0x00021403, 0x04410006, 0x0047102b, 0x0000000d, 0x00000000,
+	0x2400005a, 0x0a0010c8, 0x24020001, 0x14400002, 0x00001021, 0x24020001,
+	0x304200ff, 0x1440ffec, 0x03461021, 0x02401021, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, 0x24454660,
+	0x94a3001a, 0x8ca40024, 0x00403021, 0x000318c0, 0x00832021, 0xaf44003c,
+	0x8ca20020, 0xaf420038, 0x3c020050, 0x34420008, 0xaf420030, 0x00000000,
+	0x00000000, 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, 0x00000000,
+	0x8f430400, 0x24c64660, 0xacc30010, 0x8f420404, 0x3c030020, 0xacc20014,
+	0xaf430030, 0x94c40018, 0x94c3001c, 0x94c2001a, 0x94c5001e, 0x00832021,
+	0x24420001, 0xa4c2001a, 0x3042ffff, 0x14450002, 0xa4c40018, 0xa4c0001a,
+	0x03e00008, 0x00000000, 0x8f820010, 0x3c030006, 0x00021140, 0x00431025,
+	0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x27430400, 0x8f420000,
+	0x30420010, 0x1040fffd, 0x00000000, 0xaf800010, 0xaf830018, 0x03e00008,
+	0x00000000, 0x27bdffe8, 0xafb00010, 0x3c100800, 0x26104660, 0x3c05000a,
+	0x02002021, 0x03452821, 0xafbf0014, 0x0e001128, 0x2406000a, 0x96020002,
+	0x9603001e, 0x3042000f, 0x24420003, 0x00431804, 0x24027fff, 0x0043102b,
+	0xaf830014, 0x10400004, 0x00000000, 0x0000000d, 0x00000000, 0x24000043,
+	0x0e0010d2, 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018,
+	0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000,
+	0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a001137, 0x00a01021,
+	0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008,
+	0x00000000, 0x3c036000, 0x8c642b7c, 0x3c036010, 0x8c6553fc, 0x00041582,
+	0x00042302, 0x308403ff, 0x00052d82, 0x00441026, 0x0002102b, 0x0005282b,
+	0x00451025, 0x1440000d, 0x3c020050, 0x34420004, 0xaf400038, 0xaf40003c,
+	0xaf420030, 0x00000000, 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd,
+	0x3c020020, 0xaf420030, 0x0000000d, 0x03e00008, 0x00000000, 0x3c020050,
+	0x34420004, 0xaf440038, 0xaf45003c, 0xaf420030, 0x00000000, 0x00000000,
+	0x8f420000, 0x30420020, 0x1040fffd, 0x3c020020, 0xaf420030, 0x03e00008,
+	0x00000000, 0x00000000 };
+
+static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_COM_b06FwRodata[(0x18/4) + 1] = {
+	0x08002318, 0x08002348, 0x08002378, 0x080023a8, 0x080023d8, 0x00000000,
+	0x00000000 };
+
+static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x00000000 };
+static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x00000000 };
+
+static int bnx2_RXP_b06FwReleaseMajor = 0x0;
+static int bnx2_RXP_b06FwReleaseMinor = 0x0;
+static int bnx2_RXP_b06FwReleaseFix = 0x0;
+static u32 bnx2_RXP_b06FwStartAddr = 0x08000060;
+static u32 bnx2_RXP_b06FwTextAddr = 0x08000000;
+static int bnx2_RXP_b06FwTextLen = 0x20b8;
+static u32 bnx2_RXP_b06FwDataAddr = 0x080020e0;
+static int bnx2_RXP_b06FwDataLen = 0x0;
+static u32 bnx2_RXP_b06FwRodataAddr = 0x00000000;
+static int bnx2_RXP_b06FwRodataLen = 0x0;
+static u32 bnx2_RXP_b06FwBssAddr = 0x08002100;
+static int bnx2_RXP_b06FwBssLen = 0x239c;
+static u32 bnx2_RXP_b06FwSbssAddr = 0x080020e0;
+static int bnx2_RXP_b06FwSbssLen = 0x14;
+
+static u32 bnx2_RXP_b06FwText[(0x20b8/4) + 1] = {
+	0x0a000018, 0x00000000, 0x00000000, 0x0000000d, 0x72787020, 0x302e362e,
+	0x39000000, 0x00060903, 0x00000000, 0x0000000d, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800,
+	0x244220e0, 0x3c030800, 0x2463449c, 0xac400000, 0x0043202b, 0x1480fffd,
+	0x24420004, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100060,
+	0x3c1c0800, 0x279c20e0, 0x0e000329, 0x00000000, 0x0000000d, 0x8f870008,
+	0x2ce20080, 0x10400018, 0x3c030800, 0x24633490, 0x8f460100, 0x00072140,
+	0x00831021, 0xac460000, 0x8f450104, 0x00641021, 0xac450004, 0x8f460108,
+	0xac460008, 0x8f45010c, 0xac45000c, 0x8f460114, 0xac460010, 0x8f450118,
+	0xac450014, 0x8f460124, 0xac460018, 0x8f450128, 0x00641821, 0x24e20001,
+	0xaf820008, 0xac65001c, 0x03e00008, 0x00000000, 0x00804021, 0x8f830000,
+	0x24070001, 0x3c020001, 0x00621024, 0x10400037, 0x00603021, 0x9742010e,
+	0x3c038000, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
+	0xa342018b, 0x8f840004, 0x24020080, 0x24030002, 0xaf420180, 0xa743018c,
+	0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000069, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x24020003, 0x30838000, 0x1060000d, 0xa7420188, 0x93420116, 0x304200fc,
+	0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600005, 0x00000000,
+	0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c,
+	0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
+	0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x30c21000,
+	0x1040000f, 0x00000000, 0x9742010c, 0x3042fc00, 0x5440000b, 0x24070005,
+	0x3c021000, 0x00c21024, 0x10400007, 0x3c030dff, 0x3463ffff, 0x3c020e00,
+	0x00c21024, 0x0062182b, 0x54600001, 0x24070005, 0x8f82000c, 0x30434000,
+	0x10600016, 0x00404821, 0x3c020f00, 0x00c21024, 0x14400012, 0x00000000,
+	0x93420116, 0x34424000, 0x03421821, 0x94650002, 0x2ca21389, 0x1040000b,
+	0x3c020800, 0x24422100, 0x00051942, 0x00031880, 0x00621821, 0x30a5001f,
+	0x8c640000, 0x24020001, 0x00a21004, 0x00822024, 0x01044025, 0x11000037,
+	0x3c021000, 0x9742010e, 0x34e60002, 0x3c038000, 0x24420004, 0x3045ffff,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x8f840004,
+	0x24020180, 0x24030002, 0xaf420180, 0xa743018c, 0x10800005, 0xa745018e,
+	0x9743011c, 0x9742011e, 0x0a0000cd, 0x00021400, 0x9743011e, 0x9742011c,
+	0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c,
+	0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000,
+	0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c,
+	0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff,
+	0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008,
+	0x00001021, 0x00c21024, 0x104000ba, 0x3c020800, 0x8c430030, 0x1060003e,
+	0x31224000, 0x1040003c, 0x3c030f00, 0x00c31824, 0x3c020100, 0x0043102b,
+	0x14400038, 0x3c030800, 0x9742010e, 0x34e60002, 0x3c038000, 0x24420004,
+	0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b,
+	0x8f840004, 0x24020080, 0x24030002, 0xaf420180, 0xa743018c, 0x10800005,
+	0xa745018e, 0x9743011c, 0x9742011e, 0x0a000110, 0x00021400, 0x9743011e,
+	0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000,
+	0x1040000c, 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
+	0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024,
+	0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
+	0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
+	0x03e00008, 0x00001021, 0x3c030800, 0x8c620024, 0x30420008, 0x1040003d,
+	0x34e80002, 0x3c020f00, 0x00c21024, 0x5440003a, 0x3107ffff, 0x9742010c,
+	0x30420200, 0x50400036, 0x3107ffff, 0x9742010e, 0x30e6fffb, 0x3c038000,
+	0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
+	0xa342018b, 0x8f840004, 0x24020180, 0x24030002, 0xaf420180, 0xa743018c,
+	0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000153, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x30828000, 0x1040000c, 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x3107ffff, 0x8f820000, 0x3c068000, 0x9743010e, 0x00021442,
+	0x30440780, 0x24630004, 0x3065ffff, 0x8f4201b8, 0x00461024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf440180, 0xa742018c,
+	0x10600005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000189, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x03e00008, 0x00001021, 0x8f424000, 0x30420100, 0x104000ef,
+	0x3c020800, 0x8c440024, 0x24030001, 0x14830036, 0x00404021, 0x9742010e,
+	0x34e50002, 0x3c038000, 0x24420004, 0x3044ffff, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf400180,
+	0xa742018c, 0x10600005, 0xa744018e, 0x9743011c, 0x9742011e, 0x0a0001c6,
+	0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8,
+	0x8f84000c, 0x30828000, 0x1040000c, 0xa7450188, 0x93420116, 0x304200fc,
+	0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff,
+	0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104,
+	0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac,
+	0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x30820001, 0x10400035,
+	0x30e90004, 0x9742010e, 0x30e6fffb, 0x3c038000, 0x24420004, 0x3044ffff,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004,
+	0x24020002, 0xaf400180, 0xa742018c, 0x10600005, 0xa744018e, 0x9743011c,
+	0x9742011e, 0x0a0001fe, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400,
+	0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c, 0xa7470188,
+	0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff,
+	0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e,
+	0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825,
+	0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x30c7ffff, 0x8d020024,
+	0x30420004, 0x10400037, 0x8d020024, 0x9742010e, 0x30e6fffb, 0x3c038000,
+	0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
+	0xa342018b, 0x8f840004, 0x24020100, 0x24030002, 0xaf420180, 0xa743018c,
+	0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000237, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x30c7ffff, 0x8d020024, 0x30420008, 0x10400034, 0x00000000,
+	0x9742010e, 0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x24020003, 0xa342018b, 0x8f840004, 0x24020180, 0x24030002,
+	0xaf420180, 0xa743018c, 0x10800005, 0xa745018e, 0x9743011c, 0x9742011e,
+	0x0a00026f, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825,
+	0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116,
+	0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004,
+	0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c,
+	0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
+	0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x15200046, 0x00001021, 0x3c038000,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0x24032000, 0xa342018b,
+	0xa7430188, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x3c030800,
+	0x8c620024, 0x30420001, 0x10400035, 0x00001021, 0x9742010e, 0x34e50002,
+	0x3c038000, 0x24420004, 0x3044ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf400180, 0xa742018c,
+	0x10600005, 0xa744018e, 0x9743011c, 0x9742011e, 0x0a0002b5, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x30828000, 0x1040000c, 0xa7450188, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x00001021, 0x03e00008, 0x00000000, 0x27bdffe0, 0xafbf0018,
+	0xafb10014, 0xafb00010, 0x8f420140, 0xaf420020, 0x8f430148, 0x3c027000,
+	0x00621824, 0x3c024000, 0x1062000c, 0x0043102b, 0x14400006, 0x3c025000,
+	0x3c023000, 0x1062000b, 0x3c024000, 0x0a00031f, 0x00000000, 0x10620034,
+	0x3c024000, 0x0a00031f, 0x00000000, 0x0e00067c, 0x00000000, 0x0a00031f,
+	0x3c024000, 0x8f420148, 0x24030002, 0x3044ffff, 0x00021402, 0x305000ff,
+	0x1203000c, 0x27510180, 0x2a020003, 0x10400005, 0x24020003, 0x0600001d,
+	0x36053000, 0x0a00030a, 0x3c038000, 0x12020007, 0x00000000, 0x0a000317,
+	0x00000000, 0x0e000423, 0x00000000, 0x0a000308, 0x00402021, 0x0e000435,
+	0x00000000, 0x00402021, 0x36053000, 0x3c038000, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x24020002, 0xa6250008, 0xa222000b, 0xa6240010, 0x8f420144,
+	0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00031f, 0x3c024000, 0x0000000d,
+	0x00000000, 0x240001c3, 0x0a00031f, 0x3c024000, 0x0e0007f7, 0x00000000,
+	0x3c024000, 0xaf420178, 0x00000000, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x24020800, 0x03e00008, 0xaf4201b8, 0x27bdffe8,
+	0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f,
+	0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000, 0x3c040008,
+	0xaf430008, 0x8e020808, 0x3c030800, 0xac600020, 0x3042fff0, 0x2c420001,
+	0xaf820004, 0x0e000819, 0x0344d825, 0x0e000781, 0x00000000, 0x3c020400,
+	0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c, 0x8e021980,
+	0x34420200, 0xae021980, 0x8f500000, 0x32020003, 0x1040fffd, 0x32020001,
+	0x10400004, 0x32020002, 0x0e0003bd, 0x00000000, 0x32020002, 0x1040fff6,
+	0x00000000, 0x0e0002d4, 0x00000000, 0x0a00034a, 0x00000000, 0x27bdffe8,
+	0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f,
+	0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000, 0x3c040008,
+	0xaf430008, 0x8e020808, 0x3c030800, 0xac600020, 0x3042fff0, 0x2c420001,
+	0xaf820004, 0x0e000819, 0x0344d825, 0x0e000781, 0x00000000, 0x3c020400,
+	0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c, 0x8e021980,
+	0x8fbf0014, 0x34420200, 0xae021980, 0x8fb00010, 0x03e00008, 0x27bd0018,
+	0x30a5ffff, 0x30c6ffff, 0x30e7ffff, 0x3c038000, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004, 0xaf440180, 0xa745018c,
+	0x10600005, 0xa746018e, 0x9743011c, 0x9742011e, 0x0a000393, 0x00021400,
+	0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c,
+	0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x03e00008, 0x00000000, 0x3c038000, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x24020002, 0x24032000, 0xa342018b, 0xa7430188, 0x3c021000,
+	0xaf4201b8, 0x03e00008, 0x00000000, 0x27bdffe8, 0xafbf0010, 0x8f460128,
+	0xaf460020, 0x8f420104, 0x8f450100, 0x24030800, 0x3c040010, 0xaf820000,
+	0x00441024, 0xaf85000c, 0xaf4301b8, 0x14400005, 0x3c02001f, 0x3c030800,
+	0x8c620020, 0x0a0003d5, 0x00002021, 0x3442ff00, 0x14c20009, 0x2402bfff,
+	0x3c030800, 0x8c620020, 0x24040001, 0x24420001, 0x0e00004c, 0xac620020,
+	0x0a0003e4, 0x00000000, 0x00a21024, 0x14400006, 0x00000000, 0xaf400048,
+	0x0e000448, 0xaf400040, 0x0a0003e4, 0x00000000, 0x0e000783, 0x00000000,
+	0x10400005, 0x3c024000, 0x8f430124, 0x3c026020, 0xac430014, 0x3c024000,
+	0xaf420138, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0,
+	0xafbf0018, 0xafb10014, 0xafb00010, 0x8f420148, 0x24030002, 0x3044ffff,
+	0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003, 0x10400005,
+	0x24020003, 0x0600001d, 0x36053000, 0x0a00040e, 0x3c038000, 0x12020007,
+	0x00000000, 0x0a00041b, 0x00000000, 0x0e000423, 0x00000000, 0x0a00040c,
+	0x00402021, 0x0e000435, 0x00000000, 0x00402021, 0x36053000, 0x3c038000,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008, 0xa222000b,
+	0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00041f,
+	0x8fbf0018, 0x0000000d, 0x00000000, 0x240001c3, 0x8fbf0018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x3084ffff, 0x2c821389, 0x1040000d,
+	0x00001021, 0x3c030800, 0x24632100, 0x00042942, 0x00052880, 0x00a32821,
+	0x3086001f, 0x8ca40000, 0x24030001, 0x00c31804, 0x00832025, 0x03e00008,
+	0xaca40000, 0x03e00008, 0x24020091, 0x3084ffff, 0x2c821389, 0x1040000e,
+	0x00001021, 0x3c030800, 0x24632100, 0x00042942, 0x00052880, 0x00a32821,
+	0x3086001f, 0x24030001, 0x8ca40000, 0x00c31804, 0x00031827, 0x00832024,
+	0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x27bdffb0, 0x3c026000,
+	0xafbf0048, 0x8c434448, 0xaf630140, 0x93620005, 0x30420001, 0x14400005,
+	0x00000000, 0x0e0007ed, 0x00000000, 0x0a00067a, 0x8fbf0048, 0x93420116,
+	0x93430112, 0x8f430104, 0x3c040020, 0x34424000, 0x00641824, 0x1060000d,
+	0x03426021, 0x8f430128, 0x27420180, 0xac430000, 0x8f650040, 0x24040008,
+	0x240340c1, 0xa4430008, 0x24030002, 0xa043000b, 0x3c031000, 0x0a000563,
+	0xa044000a, 0x8f420104, 0x3c030040, 0x00431024, 0x10400007, 0x00000000,
+	0x8f430128, 0x27420180, 0xac430000, 0x8f650040, 0x0a00055c, 0x24040010,
+	0xaf400048, 0xaf400054, 0xaf400040, 0x8f630048, 0x8f620040, 0x00624823,
+	0x05210004, 0x00000000, 0x0000000d, 0x00000000, 0x24000132, 0x9742011a,
+	0x3046ffff, 0x10c00004, 0x8d880004, 0x01061021, 0x0a000487, 0x2445ffff,
+	0x01002821, 0x918a000d, 0xa7a00020, 0xafa00028, 0x9364003f, 0x3c026000,
+	0x8c434448, 0x308700ff, 0x31420004, 0x10400033, 0xaf630144, 0x24090012,
+	0x14e90006, 0x3c040800, 0x8c830028, 0x24020001, 0x24630001, 0x0a00054e,
+	0xac830028, 0x8f620044, 0x15020012, 0x97a20020, 0x27a60010, 0x27450180,
+	0x3442001a, 0xa7a20020, 0x8f630040, 0x3c048000, 0x24020020, 0xa3a70022,
+	0xa3a90023, 0xa3a2001a, 0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd,
+	0x00000000, 0x0a000533, 0x00000000, 0x8f620044, 0x01021023, 0x0440009e,
+	0x24020001, 0x8f620048, 0x01021023, 0x0441009a, 0x24020001, 0x97a20020,
+	0x27a60010, 0x34420001, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000,
+	0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x0a000533,
+	0x00000000, 0x3c026000, 0x8c424448, 0xaf620148, 0x8f630040, 0x00685823,
+	0x19600013, 0x00cb102a, 0x54400007, 0x314a00fe, 0x5566000c, 0x010b4021,
+	0x31420001, 0x54400009, 0x010b4021, 0x314a00fe, 0x24020001, 0xa7a20020,
+	0x8f630040, 0x00c05821, 0x00003021, 0x0a0004dd, 0xafa30028, 0x00cb1023,
+	0x0a0004dd, 0x3046ffff, 0x00005821, 0x8f620048, 0x2442ffff, 0x00a21823,
+	0x18600019, 0x0066102a, 0x14400013, 0x24020001, 0xa7a20020, 0x8f630040,
+	0xafa30028, 0x8f620040, 0x55020005, 0x27a60010, 0x55200003, 0x27a60010,
+	0x0a0004f6, 0x00c01821, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x00000000, 0x0a000533, 0x00000000, 0x8f650048, 0x00c31023,
+	0x3046ffff, 0x314a00f6, 0x3c046000, 0x8c824448, 0x31430002, 0x1060001e,
+	0xaf62014c, 0x8f620044, 0x1502000e, 0x97a20020, 0x27a60010, 0x34420200,
+	0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, 0xafa30028, 0x8f4201b8,
+	0x00441024, 0x1440fffd, 0x00000000, 0x0a000533, 0x00000000, 0x27a60010,
+	0x34420001, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, 0xafa30028,
+	0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x0a000533, 0x00000000,
+	0x3c026000, 0x8c424448, 0x31430010, 0xaf620150, 0x54600003, 0x8d890008,
+	0x0a00054e, 0x24020001, 0x8f630054, 0x2522ffff, 0x00431023, 0x1840002a,
+	0x24020001, 0x27a60010, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000,
+	0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x8f420128,
+	0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, 0x90c4000a,
+	0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, 0x90c30012,
+	0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, 0x8cc20024,
+	0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc4002c, 0x24020001, 0x3c031000,
+	0xaca4002c, 0xaf4301b8, 0xaf400044, 0xaf400050, 0x0a00067a, 0x8fbf0048,
+	0x3c026000, 0x8c424448, 0x31430020, 0x10600019, 0xaf620154, 0x8f430128,
+	0x27420180, 0xac430000, 0x8f650040, 0x24040004, 0x240340c1, 0xa4430008,
+	0x24030002, 0xa044000a, 0x24040008, 0xa043000b, 0x3c031000, 0xa4440010,
+	0xa0400012, 0xa0400013, 0xac400014, 0xac400024, 0xac400028, 0xac40002c,
+	0xac450018, 0x0e0007ed, 0xaf4301b8, 0x0a00067a, 0x8fbf0048, 0x8f430104,
+	0x8c824448, 0x38e3000a, 0x2c630001, 0xaf620158, 0x38e2000c, 0x2c420001,
+	0x00621825, 0x14600003, 0x2402000e, 0x14e2002a, 0x00000000, 0x50c00008,
+	0x9584000e, 0x10c00004, 0xa7a60040, 0x01061021, 0x0a000583, 0x2445ffff,
+	0x01002821, 0x9584000e, 0x93630035, 0x8f62004c, 0x00642004, 0x00892021,
+	0x00821023, 0x1840001f, 0x3c026000, 0x8f620018, 0x01021023, 0x1c40000f,
+	0x97a20020, 0x8f620018, 0x15020018, 0x3c026000, 0x8f62001c, 0x01221023,
+	0x1c400008, 0x97a20020, 0x8f62001c, 0x15220011, 0x3c026000, 0x8f620058,
+	0x00821023, 0x1840000c, 0x97a20020, 0xafa50028, 0xafa80034, 0xafa90038,
+	0xafa4003c, 0x34420020, 0x0a0005a8, 0xa7a20020, 0x8f680040, 0x00003021,
+	0x8f640058, 0x01002821, 0x3c026000, 0x8c434448, 0xaf63015c, 0x8f62004c,
+	0x01221023, 0x18400009, 0x00000000, 0x8f620054, 0x01221023, 0x1c400005,
+	0x97a20020, 0xafa50028, 0xafa90024, 0x0a0005c3, 0x34420040, 0x9742011a,
+	0x1440000c, 0x24020014, 0x8f620058, 0x14820009, 0x24020014, 0x8f63004c,
+	0x8f620054, 0x10620004, 0x97a20020, 0xafa50028, 0x34420080, 0xa7a20020,
+	0x24020014, 0x10e2000a, 0x28e20015, 0x10400005, 0x2402000c, 0x10e20006,
+	0x3c026000, 0x0a000600, 0x00000000, 0x24020016, 0x14e20031, 0x3c026000,
+	0x8f620054, 0x24420001, 0x1522002d, 0x3c026000, 0x24020014, 0x10e2001e,
+	0x28e20015, 0x10400005, 0x2402000c, 0x10e20008, 0x3c026000, 0x0a000600,
+	0x00000000, 0x24020016, 0x10e2000c, 0x97a20020, 0x0a000600, 0x3c026000,
+	0x97a30020, 0x2402000e, 0xafa50028, 0xa3a70022, 0xa3a20023, 0xafa90024,
+	0x34630054, 0x0a0005ff, 0xa7a30020, 0x24030010, 0x24040002, 0xafa50028,
+	0xa3a70022, 0xa3a30023, 0xa3a4001a, 0xafa90024, 0x0a0005fe, 0x3442005d,
+	0x97a20020, 0x24030012, 0x24040002, 0xafa50028, 0xa3a70022, 0xa3a30023,
+	0xa3a4001a, 0xafa90024, 0x3042fffe, 0x3442005c, 0xa7a20020, 0x3c026000,
+	0x8c434448, 0x31420001, 0xaf630160, 0x1040002c, 0x2402000c, 0x10e20014,
+	0x28e2000d, 0x10400005, 0x2402000a, 0x10e20008, 0x97a20020, 0x0a000631,
+	0x3c026000, 0x2402000e, 0x10e20018, 0x3c026000, 0x0a000631, 0x00000000,
+	0x24030008, 0x24040002, 0xafa50028, 0xa3a70022, 0xa3a30023, 0xa3a4001a,
+	0x0a00062f, 0x34420013, 0x97a30020, 0x30620004, 0x1440000b, 0x97a20020,
+	0x3462001b, 0xa7a20020, 0x24020016, 0x24030002, 0xafa50028, 0xa3a70022,
+	0xa3a20023, 0x0a000630, 0xa3a3001a, 0x97a20020, 0x24030010, 0x24040002,
+	0xafa50028, 0xa3a70022, 0xa3a30023, 0xa3a4001a, 0x3442001b, 0xa7a20020,
+	0x3c026000, 0x8c434448, 0x31420009, 0x0002102b, 0x00021023, 0x30420007,
+	0x34440003, 0xaf630164, 0x10c00016, 0x24030800, 0x8f820010, 0x27450180,
+	0x24420001, 0xaf820010, 0x24020004, 0xaf4301b8, 0xa4a40008, 0xa0a2000b,
+	0x93440120, 0x3c031000, 0xa4a6000e, 0xaca90024, 0xaca80028, 0x008b2021,
+	0xa4a4000c, 0xaf4301b8, 0x97a20020, 0x00003021, 0x3042ffbf, 0x0a000650,
+	0xa7a20020, 0x24060001, 0x3c026000, 0x8c434448, 0xaf630168, 0x97a20020,
+	0x10400020, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x00000000, 0x8f420128, 0xaca20000, 0x8fa30028, 0x240240c1, 0xa4a20008,
+	0xaca30018, 0x93a4001a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x97a20020,
+	0xa4a20010, 0x93a30022, 0xa0a30012, 0x93a20023, 0xa0a20013, 0x8fa30024,
+	0xaca30014, 0x8fa20034, 0xaca20024, 0x8fa30038, 0xaca30028, 0x8fa2003c,
+	0x3c031000, 0xaca2002c, 0xaf4301b8, 0x3c026000, 0x8c434448, 0x00c01021,
+	0xaf63016c, 0x8fbf0048, 0x03e00008, 0x27bd0050, 0x8f460140, 0x8f470148,
+	0x3c028000, 0x00e24024, 0x00072c02, 0x30a300ff, 0x2402000b, 0x1062008f,
+	0x27440180, 0x2862000c, 0x10400011, 0x24020006, 0x1062005a, 0x28620007,
+	0x10400007, 0x24020008, 0x10600024, 0x24020001, 0x10620037, 0x00000000,
+	0x0a00077e, 0x00000000, 0x106200a9, 0x24020009, 0x106200bb, 0x00071c02,
+	0x0a00077e, 0x00000000, 0x2402001b, 0x106200c7, 0x2862001c, 0x10400007,
+	0x2402000e, 0x106200b1, 0x24020019, 0x106200c2, 0x00071c02, 0x0a00077e,
+	0x00000000, 0x24020080, 0x10620060, 0x28620081, 0x10400005, 0x2402001c,
+	0x10620094, 0x00071c02, 0x0a00077e, 0x00000000, 0x240200c2, 0x106200c5,
+	0x00a01821, 0x0a00077e, 0x00000000, 0x00a01821, 0x3c058000, 0x8f4201b8,
+	0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, 0xac860000,
+	0xac800004, 0xa082000a, 0xa083000b, 0xa4870010, 0x8f430144, 0x3c021000,
+	0xac800028, 0xac830024, 0x3c036000, 0xaf4201b8, 0x03e00008, 0xac600808,
+	0x11000009, 0x00a01821, 0x3c020800, 0x24030002, 0xa0434490, 0x24424490,
+	0xac460008, 0x8f430144, 0x03e00008, 0xac430004, 0x3c058000, 0x8f4201b8,
+	0x00451024, 0x1440fffd, 0x24020002, 0xac800000, 0xac860004, 0xa4830008,
+	0xa082000a, 0xa082000b, 0xa4870010, 0xac800024, 0x8f420144, 0x3c031000,
+	0xac820028, 0x3c026000, 0xaf4301b8, 0x03e00008, 0xac400808, 0x00a01821,
+	0x3c080800, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x00000000,
+	0xac860000, 0x91024490, 0x00002821, 0x10400002, 0x25064490, 0x8cc50008,
+	0xac850004, 0xa4830008, 0x91034490, 0x24020002, 0xa082000b, 0xa4870010,
+	0x34630001, 0xa083000a, 0x8f420144, 0xac820024, 0x91034490, 0x10600002,
+	0x00001021, 0x8cc20004, 0xac820028, 0x3c021000, 0xaf4201b8, 0x3c026000,
+	0xa1004490, 0x03e00008, 0xac400808, 0x00a01821, 0x3c058000, 0x8f4201b8,
+	0x00451024, 0x1440fffd, 0x24020002, 0xa082000b, 0xa4830008, 0xa4870010,
+	0x8f420144, 0x3c031000, 0xa4820012, 0x03e00008, 0xaf4301b8, 0x30e2ffff,
+	0x14400028, 0x00071c02, 0x93620005, 0x30420004, 0x14400020, 0x3c029000,
+	0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x93620005, 0x3c038000, 0x34630001, 0x00c31825,
+	0x34420004, 0xa3620005, 0xaf430020, 0x93620005, 0x30420004, 0x14400003,
+	0x3c038000, 0x0000000d, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020005, 0x3c031000, 0xac860000, 0xa082000b, 0xaf4301b8, 0x0a00073d,
+	0x00071c02, 0x0000000d, 0x03e00008, 0x00000000, 0x00071c02, 0x3c058000,
+	0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002,
+	0xac860000, 0xac800004, 0xa082000a, 0xa083000b, 0xa4870010, 0x8f430144,
+	0x3c021000, 0xac800028, 0xac830024, 0x03e00008, 0xaf4201b8, 0x00071c02,
+	0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xac800000,
+	0xac860004, 0xa4830008, 0xa082000a, 0xa082000b, 0xa4870010, 0xac800024,
+	0x8f420144, 0x3c031000, 0xac820028, 0x03e00008, 0xaf4301b8, 0x00071c02,
+	0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008,
+	0x24030002, 0xa082000a, 0x3c021000, 0xac860000, 0xac800004, 0xa083000b,
+	0xa4870010, 0xac800024, 0xac800028, 0x03e00008, 0xaf4201b8, 0x3c058000,
+	0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xac860000, 0xac800004,
+	0xa4830008, 0xa080000a, 0x0a000748, 0xa082000b, 0x0000000d, 0x03e00008,
+	0x00000000, 0x03e00008, 0x00000000, 0x8f420100, 0x3042003e, 0x14400011,
+	0x24020001, 0xaf400048, 0x8f420100, 0x304207c0, 0x10400005, 0x00000000,
+	0xaf40004c, 0xaf400050, 0x03e00008, 0x24020001, 0xaf400054, 0xaf400040,
+	0x8f420100, 0x30423800, 0x54400001, 0xaf400044, 0x24020001, 0x03e00008,
+	0x00000000, 0x3c029000, 0x34420001, 0x00822025, 0xaf440020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x03e00008, 0x00000000,
+	0x3c028000, 0x34420001, 0x00822025, 0x03e00008, 0xaf440020, 0x8f430128,
+	0x27420180, 0xac430000, 0x8f650040, 0x240340c1, 0xa4430008, 0x24030002,
+	0xa044000a, 0x24040008, 0xa043000b, 0x3c031000, 0xa4440010, 0xa0400012,
+	0xa0400013, 0xac400014, 0xac400024, 0xac400028, 0xac40002c, 0xac450018,
+	0x03e00008, 0xaf4301b8, 0x24020001, 0xacc40000, 0x03e00008, 0xa4e50000,
+	0x03e00008, 0x24020001, 0x24020001, 0xaf400044, 0x03e00008, 0xaf400050,
+	0x00803021, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x00000000, 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008,
+	0xaca30018, 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010,
+	0xa4a20010, 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014,
+	0xaca30014, 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc2002c,
+	0x3c031000, 0xaca2002c, 0x24020001, 0xaf4301b8, 0xaf400044, 0x03e00008,
+	0xaf400050, 0x27bdffe8, 0xafbf0010, 0x0e000326, 0x00000000, 0x00002021,
+	0x0e00004c, 0xaf400180, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x8f460148,
+	0x27450180, 0x3c038000, 0x00061402, 0x304700ff, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x00000000, 0x8f440140, 0x00061202, 0x304200ff, 0x00061c02,
+	0xaca20004, 0x24020002, 0xa4a30008, 0x30c300ff, 0xa0a2000b, 0xaca30024,
+	0x10e0000a, 0xaca40000, 0x28e20004, 0x14400005, 0x24020001, 0x24020005,
+	0x54e20005, 0xa0a0000a, 0x24020001, 0x0a000816, 0xa0a2000a, 0xa0a0000a,
+	0x3c021000, 0x03e00008, 0xaf4201b8, 0x03e00008, 0x00001021, 0x10c00007,
+	0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb,
+	0x24840004, 0x03e00008, 0x00000000, 0x0a00082a, 0x00a01021, 0xac860000,
+	0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008, 0x00000000,
+	0x00000000 }; 
+
+static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_RXP_b06FwRodata[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_RXP_b06FwBss[(0x239c/4) + 1] = { 0x00000000 };
+static u32 bnx2_RXP_b06FwSbss[(0x14/4) + 1] = { 0x00000000 };
+
+static u32 bnx2_rv2p_proc1[] = {
+	0x00000008, 0xac000001, 0x0000000c, 0x2f800001, 0x00000010, 0x213f0004,
+	0x00000010, 0x20bf002c, 0x00000010, 0x203f0143, 0x00000018, 0x8000fffd,
+	0x00000010, 0xb1b8b017, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
+	0x00000000, 0x2c380000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x00000008, 0x02000002,
+	0x00000010, 0x91de0000, 0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08,
+	0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000010, 0x2c620002,
+	0x00000018, 0x80000012, 0x0000000b, 0x2fdf0002, 0x0000000c, 0x1f800002,
+	0x00000000, 0x2c070000, 0x00000018, 0x8000ffe6, 0x00000008, 0x02000002,
+	0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
+	0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000018, 0x80000004,
+	0x0000000c, 0x1f800002, 0x00000000, 0x00000000, 0x00000018, 0x8000ffd9,
+	0x0000000c, 0x29800002, 0x0000000c, 0x1f800002, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000005, 0x00000018, 0x8000ffd4, 0x00000008, 0x02240030,
+	0x00000018, 0x00040000, 0x00000018, 0x80000015, 0x00000018, 0x80000017,
+	0x00000018, 0x8000001b, 0x00000018, 0x8000004c, 0x00000018, 0x8000008c,
+	0x00000018, 0x8000000f, 0x00000018, 0x8000000e, 0x00000018, 0x8000000d,
+	0x00000018, 0x8000000c, 0x00000018, 0x800000c2, 0x00000018, 0x8000000a,
+	0x00000018, 0x80000009, 0x00000018, 0x80000008, 0x00000018, 0x800000fd,
+	0x00000018, 0x80000006, 0x00000018, 0x80000005, 0x00000018, 0x800000ff,
+	0x00000018, 0x80000104, 0x00000018, 0x80000002, 0x00000018, 0x80000098,
+	0x00000018, 0x80000000, 0x0000000c, 0x1f800001, 0x00000000, 0x00000000,
+	0x00000018, 0x8000ffba, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
+	0x0000000c, 0x1f800001, 0x00000008, 0x2a000002, 0x00000018, 0x8000ffb5,
+	0x00000010, 0xb1a0b012, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000,
+	0x00000008, 0x2c800000, 0x00000008, 0x2d000000, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d80011c, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x0000000f, 0x47600008, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
+	0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000018, 0x80000013,
+	0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000010, 0x91d40000, 0x00000008, 0x2d80011c,
+	0x0000000f, 0x060e0001, 0x00000010, 0x001f0000, 0x00000000, 0x0f580000,
+	0x00000010, 0x91de0000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000000, 0x02620000,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x309a0000, 0x00000000, 0x31040000,
+	0x00000000, 0x0c961800, 0x00000009, 0x0c99ffff, 0x00000004, 0xcc993400,
+	0x00000010, 0xb1963202, 0x00000008, 0x0f800000, 0x0000000c, 0x29800001,
+	0x00000010, 0x00220002, 0x0000000c, 0x29520001, 0x0000000c, 0x29520000,
+	0x00000008, 0x22000001, 0x0000000c, 0x1f800001, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000003, 0x00000018, 0x8000ff83, 0x00000010, 0xb1a0b01d,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x0000000f, 0x47600008, 0x00000000, 0x060e0000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f580000, 0x00000010, 0x91de0000,
+	0x00000000, 0x0a640000, 0x00000000, 0x0ae50000, 0x00000000, 0x0b670000,
+	0x00000000, 0x0d620000, 0x00000000, 0x0ce71800, 0x00000009, 0x0c99ffff,
+	0x00000004, 0xcc993400, 0x00000010, 0xb1963220, 0x00000008, 0x0f800000,
+	0x00000018, 0x8000001e, 0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002,
+	0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d80012c, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
+	0x00000000, 0x0f580000, 0x00000010, 0x91de0000, 0x00000000, 0x0a640000,
+	0x00000000, 0x0ae50000, 0x00000000, 0x0b670000, 0x00000000, 0x0d620000,
+	0x00000000, 0x02630000, 0x0000000f, 0x47620010, 0x00000000, 0x0ce71800,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x311a0000, 0x00000000, 0x31840000,
+	0x0000000b, 0xc20000ff, 0x00000002, 0x42040000, 0x00000001, 0x31620800,
+	0x0000000f, 0x020e0010, 0x00000002, 0x31620800, 0x00000009, 0x0c99ffff,
+	0x00000004, 0xcc993400, 0x00000010, 0xb1963202, 0x00000008, 0x0f800000,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x0000000c, 0x61420006,
+	0x00000008, 0x22000008, 0x00000000, 0x2adf0000, 0x00000008, 0x2a000004,
+	0x00000018, 0x8000ff42, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91a0b008, 0x00000010, 0x91d40000, 0x0000000c, 0x31620018,
+	0x00000008, 0x2d800001, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x00000008, 0xac000001, 0x00000018, 0x8000000e, 0x00000000, 0x0380b000,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c004000, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d800101, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x0000000c, 0x31620018, 0x00000008, 0x2d800001, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c000e00,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000008, 0x2a000007,
+	0x00000018, 0x8000ff27, 0x00000010, 0xb1a0b016, 0x0000000b, 0x2fdf0002,
+	0x00000000, 0x03d80000, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000008, 0x07000001,
+	0x00000010, 0xb5de1c00, 0x00000010, 0x2c620002, 0x00000018, 0x8000000a,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c070000, 0x0000000c, 0x1f800001,
+	0x00000010, 0x91de0000, 0x00000018, 0x8000ff11, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000010, 0x91de0000,
+	0x00000000, 0x2adf0000, 0x00000008, 0x2a00000a, 0x00000018, 0x8000ff07,
+	0x00000000, 0x82265600, 0x0000000f, 0x47220008, 0x00000009, 0x070e000f,
+	0x00000008, 0x070e0008, 0x00000008, 0x02800001, 0x00000007, 0x02851c00,
+	0x00000008, 0x82850001, 0x00000000, 0x02840a00, 0x00000007, 0x42851c00,
+	0x00000003, 0xc3aa5200, 0x00000000, 0x03b10e00, 0x00000010, 0x001f0000,
+	0x0000000f, 0x0f280007, 0x00000007, 0x4b071c00, 0x00000000, 0x00000000,
+	0x0000000f, 0x0a960003, 0x00000000, 0x0a955c00, 0x00000000, 0x4a005a00,
+	0x00000000, 0x0c960a00, 0x00000009, 0x0c99ffff, 0x00000008, 0x0d00ffff,
+	0x00000010, 0xb1963202, 0x00000008, 0x0f800005, 0x00000010, 0x00220020,
+	0x00000000, 0x02a70000, 0x00000010, 0xb1850002, 0x00000008, 0x82850200,
+	0x00000000, 0x02000000, 0x00000000, 0x03a60000, 0x00000018, 0x8000004e,
+	0x00000000, 0x072b0000, 0x00000001, 0x878c1c00, 0x00000000, 0x870e1e00,
+	0x00000000, 0x860c1e00, 0x00000000, 0x03061e00, 0x00000010, 0xb18e0003,
+	0x00000018, 0x80000047, 0x00000018, 0x8000fffa, 0x00000010, 0x918c0003,
+	0x00000010, 0xb1870002, 0x00000018, 0x80000043, 0x00000010, 0x91d40000,
+	0x0000000c, 0x29800001, 0x00000000, 0x2a860000, 0x00000000, 0x230c0000,
+	0x00000000, 0x2b070000, 0x00000010, 0xb187000e, 0x00000008, 0x2a000008,
+	0x00000018, 0x8000003b, 0x00000010, 0x91d40000, 0x00000000, 0x28d18c00,
+	0x00000000, 0x2a860000, 0x00000000, 0x230c0000, 0x00000000, 0x2b070000,
+	0x00000018, 0x8000fff8, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
+	0x00000000, 0x2aab0000, 0x00000000, 0xa3265600, 0x00000000, 0x2b000000,
+	0x0000000c, 0x1f800001, 0x00000008, 0x2a000008, 0x00000018, 0x8000fec8,
+	0x00000010, 0x91d40000, 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001,
+	0x00000008, 0x2a000009, 0x00000018, 0x8000fec3, 0x00000010, 0x91d40000,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000000, 0x29420000,
+	0x00000008, 0x2a000002, 0x00000018, 0x8000febd, 0x00000018, 0x8000febc,
+	0x00000010, 0xb1bcb016, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
+	0x00000000, 0x2c3c0000, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800150, 0x00000000, 0x00000000,
+	0x00000010, 0x205f0000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
+	0x00000008, 0x2d800108, 0x00000008, 0x07000001, 0x00000010, 0xb5de1c00,
+	0x00000010, 0x2c620002, 0x00000018, 0x8000000a, 0x0000000b, 0x2fdf0002,
+	0x00000000, 0x2c070000, 0x0000000c, 0x1f800000, 0x00000010, 0x91de0000,
+	0x00000018, 0x8000fea6, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x0000000c, 0x29800000,
+	0x0000000c, 0x1f800000, 0x00000010, 0x91de0000, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000006, 0x00000018, 0x8000fe9c, 0x00000008, 0x03050004,
+	0x00000006, 0x83040c00, 0x00000008, 0x02850200, 0x00000000, 0x86050c00,
+	0x00000001, 0x860c0e00, 0x00000008, 0x02040004, 0x00000000, 0x02041800,
+	0x00000000, 0x83871800, 0x00000018, 0x00020000 };
+
+static u32 bnx2_rv2p_proc2[] = {
+	0x00000000, 0x2a000000, 0x00000010, 0xb1d40000, 0x00000008, 0x02540003,
+	0x00000018, 0x00040000, 0x00000018, 0x8000000a, 0x00000018, 0x8000000a,
+	0x00000018, 0x8000000e, 0x00000018, 0x80000056, 0x00000018, 0x800001b9,
+	0x00000018, 0x800001e1, 0x00000018, 0x8000019b, 0x00000018, 0x800001f9,
+	0x00000018, 0x8000019f, 0x00000018, 0x800001a6, 0x00000018, 0x80000000,
+	0x0000000c, 0x29800001, 0x00000000, 0x2a000000, 0x0000000c, 0x29800000,
+	0x00000010, 0x20530000, 0x00000018, 0x8000ffee, 0x0000000c, 0x29800001,
+	0x00000010, 0x91de0000, 0x00000010, 0x001f0000, 0x00000000, 0x2f80aa00,
+	0x00000000, 0x2a000000, 0x00000000, 0x0d610000, 0x00000000, 0x03620000,
+	0x00000000, 0x2c400000, 0x00000000, 0x02638c00, 0x00000000, 0x26460000,
+	0x00000010, 0x00420002, 0x00000008, 0x02040012, 0x00000010, 0xb9060836,
+	0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0c000000, 0x00000000, 0x0b800000,
+	0x00000010, 0x00420009, 0x00000008, 0x0cc60012, 0x00000008, 0x0f800003,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000008, 0x27110012,
+	0x00000000, 0x66900000, 0x00000008, 0xa31b0012, 0x00000018, 0x80000008,
+	0x00000000, 0x0cc60000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
+	0x00000010, 0x009f0000, 0x00000000, 0x27110000, 0x00000000, 0x66900000,
+	0x00000000, 0x231b0000, 0x00000010, 0xb197320e, 0x00000000, 0x25960000,
+	0x00000000, 0x021b0000, 0x00000010, 0x001f0000, 0x00000008, 0x0f800003,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000000, 0x22c50800,
+	0x00000010, 0x009f0000, 0x00000000, 0x27002200, 0x00000000, 0x26802000,
+	0x00000000, 0x231b0000, 0x0000000c, 0x69520001, 0x00000018, 0x8000fff3,
+	0x00000010, 0x01130002, 0x00000010, 0xb1980003, 0x00000010, 0x001f0000,
+	0x00000008, 0x0f800004, 0x00000008, 0x22000003, 0x00000008, 0x2c80000c,
+	0x00000008, 0x2d00000c, 0x00000010, 0x009f0000, 0x00000000, 0x25960000,
+	0x0000000c, 0x29800000, 0x00000000, 0x32140000, 0x00000000, 0x32950000,
+	0x00000000, 0x33160000, 0x00000000, 0x31e32e00, 0x00000008, 0x2d800010,
+	0x00000010, 0x20530000, 0x00000018, 0x8000ffac, 0x00000000, 0x23000000,
+	0x00000000, 0x25e60000, 0x00000008, 0x2200000b, 0x0000000c, 0x69520000,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000018, 0x8000ffa5,
+	0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
+	0x00000010, 0x001f0000, 0x00000000, 0x02700000, 0x00000000, 0x0d620000,
+	0x00000000, 0xbb630800, 0x00000000, 0x2a000000, 0x00000009, 0x076000ff,
+	0x0000000f, 0x2c0e0007, 0x00000008, 0x2c800000, 0x00000008, 0x2d000064,
+	0x00000008, 0x2d80011c, 0x00000009, 0x06420002, 0x0000000c, 0x61420001,
+	0x00000000, 0x0f400000, 0x00000000, 0x02d08c00, 0x00000000, 0x23000000,
+	0x00000004, 0x826da000, 0x00000000, 0x8304a000, 0x00000000, 0x22c50c00,
+	0x00000000, 0x03760000, 0x00000004, 0x83860a00, 0x00000000, 0x83870c00,
+	0x00000010, 0x91de0000, 0x00000000, 0x037c0000, 0x00000000, 0x837b0c00,
+	0x00000001, 0x83060e00, 0x00000000, 0x83870c00, 0x00000000, 0x82850e00,
+	0x00000010, 0xb1860016, 0x0000000f, 0x47610018, 0x00000000, 0x068e0000,
+	0x0000000f, 0x47670010, 0x0000000f, 0x47e20010, 0x00000000, 0x870e1e00,
+	0x00000010, 0xb70e1a10, 0x00000010, 0x0ce7000e, 0x00000008, 0x22000009,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
+	0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
+	0x00000018, 0x8000023f, 0x00000000, 0x37ed0000, 0x0000000c, 0x73e7001a,
+	0x00000010, 0x20530000, 0x00000008, 0x22000008, 0x0000000c, 0x61420004,
+	0x00000000, 0x02f60000, 0x00000004, 0x82840a00, 0x00000010, 0xb1840a2b,
+	0x00000010, 0x2d67000a, 0x00000010, 0xb96d0804, 0x00000004, 0xb6ed0a00,
+	0x00000000, 0x37ed0000, 0x00000018, 0x80000029, 0x0000000c, 0x61420000,
+	0x00000000, 0x37040000, 0x00000000, 0x37850000, 0x0000000c, 0x33e7001a,
+	0x00000018, 0x80000024, 0x00000010, 0xb96d0809, 0x00000004, 0xb6ed0a00,
+	0x00000000, 0x036d0000, 0x00000004, 0xb76e0c00, 0x00000010, 0x91ee0c1f,
+	0x0000000c, 0x73e7001a, 0x00000004, 0xb6ef0c00, 0x00000000, 0x37ed0000,
+	0x00000018, 0x8000001b, 0x0000000c, 0x61420000, 0x00000010, 0xb7ee0a05,
+	0x00000010, 0xb96f0815, 0x00000003, 0xb76e0800, 0x00000004, 0xb7ef0a00,
+	0x00000018, 0x80000015, 0x00000010, 0x0ce7000c, 0x00000008, 0x22000009,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
+	0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
+	0x00000018, 0x80000215, 0x00000010, 0x20530000, 0x00000008, 0x22000008,
+	0x0000000c, 0x61420004, 0x00000000, 0x37040000, 0x00000000, 0x37850000,
+	0x00000000, 0x036d0000, 0x00000003, 0xb8f10c00, 0x00000018, 0x80000004,
+	0x00000000, 0x02840000, 0x00000002, 0x21421800, 0x0000000c, 0x61420000,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff,
+	0x00000000, 0x23000000, 0x00000010, 0xb1840a3d, 0x00000010, 0x01420002,
+	0x00000004, 0xb8f10a00, 0x00000003, 0x83760a00, 0x00000010, 0xb8040c39,
+	0x00000010, 0xb7e6080a, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000009, 0x0c68ffff, 0x00000009, 0x0b67ffff, 0x00000000, 0x0be60000,
+	0x00000000, 0x0c840000, 0x00000010, 0xb197320c, 0x00000008, 0x0f800002,
+	0x00000018, 0x8000000a, 0x00000000, 0x0a6a0000, 0x00000000, 0x0aeb0000,
+	0x00000000, 0x0c000000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0be90000,
+	0x00000000, 0x0c840000, 0x00000010, 0xb1973203, 0x00000008, 0x0f800002,
+	0x00000018, 0x80000001, 0x00000010, 0x001f0000, 0x00000000, 0x0c860000,
+	0x00000000, 0x06980000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
+	0x00000010, 0x009f0000, 0x00000010, 0xb1973210, 0x00000000, 0x231b0000,
+	0x00000000, 0x02043600, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x800001de, 0x00000000, 0x06980000,
+	0x00000010, 0x20530000, 0x00000000, 0x22c58c00, 0x00000010, 0x001f0000,
+	0x00000008, 0x0f800003, 0x00000018, 0x8000fff0, 0x00000000, 0x02043600,
+	0x00000000, 0x231b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
+	0x0000000c, 0x29000000, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000000, 0x32140000, 0x00000000, 0x32950000, 0x00000005, 0x73e72c00,
+	0x00000005, 0x74683000, 0x00000000, 0x33170000, 0x00000018, 0x80000138,
+	0x00000010, 0x91c60004, 0x00000008, 0x07000004, 0x00000010, 0xb1c41c02,
+	0x00000010, 0x91840a04, 0x00000018, 0x800001c3, 0x00000010, 0x20530000,
+	0x00000000, 0x22c58c00, 0x00000010, 0xb1840a8e, 0x0000000c, 0x21420006,
+	0x00000010, 0x0ce7001a, 0x0000000f, 0x43680010, 0x00000000, 0x03f30c00,
+	0x00000010, 0x91870850, 0x0000000f, 0x46ec0010, 0x00000010, 0xb68d0c4e,
+	0x00000000, 0x838d0c00, 0x00000000, 0xa3050800, 0x00000001, 0xa3460e00,
+	0x00000000, 0x02048c00, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000010, 0x001f0000, 0x00000008, 0x22000008, 0x00000003, 0x8384a000,
+	0x0000000f, 0x65870010, 0x00000009, 0x2607ffff, 0x00000000, 0x27750c00,
+	0x00000000, 0x66f40000, 0x0000000c, 0x29000000, 0x00000018, 0x800001aa,
+	0x00000000, 0x03068c00, 0x00000003, 0xf4680c00, 0x00000010, 0x20530000,
+	0x00000000, 0x22c58c00, 0x00000018, 0x8000ffe5, 0x00000000, 0x39760000,
+	0x00000000, 0x39840000, 0x0000000c, 0x33e70019, 0x00000010, 0x001f0000,
+	0x00000000, 0x031e0000, 0x00000000, 0x0760fe00, 0x0000000f, 0x0f0e0007,
+	0x00000000, 0x83850800, 0x00000000, 0x0a7d0000, 0x00000000, 0x0afe0000,
+	0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000, 0x00000000, 0x0c000000,
+	0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
+	0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
+	0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
+	0x00000002, 0x33e70e00, 0x00000000, 0x28f30000, 0x00000010, 0x009f0000,
+	0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000008, 0x22000006, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
+	0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x8000017e, 0x00000003, 0xf4683600,
+	0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
+	0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
+	0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000018, 0x8000ffac, 0x00000010, 0x001f0000,
+	0x00000000, 0x031e0000, 0x00000000, 0x83850800, 0x00000009, 0x076000ff,
+	0x0000000f, 0x0f0e0007, 0x00000000, 0x0c000000, 0x00000000, 0x0a7d0000,
+	0x00000000, 0x0afe0000, 0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000,
+	0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
+	0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
+	0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
+	0x00000002, 0x33e70e00, 0x00000000, 0x39840000, 0x00000003, 0xb9720800,
+	0x00000000, 0x28f30000, 0x0000000f, 0x65680010, 0x00000010, 0x009f0000,
+	0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000008, 0x22000007, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
+	0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x80000145, 0x00000003, 0xf4683600,
+	0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
+	0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
+	0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000018, 0x8000ff73, 0x00000010, 0x0ce70005,
+	0x00000008, 0x2c80000c, 0x00000008, 0x2d000070, 0x00000008, 0x2d800010,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000018, 0x8000011d,
+	0x00000000, 0x2c1e0000, 0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010,
+	0x00000008, 0x2d800048, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x00000018, 0x8000fe5d, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f008000, 0x00000008, 0x0f800007,
+	0x00000018, 0x80000006, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
+	0x00000010, 0x001f0000, 0x0000000f, 0x0f470007, 0x00000008, 0x0f800008,
+	0x00000018, 0x80000119, 0x00000010, 0x20530000, 0x00000018, 0x8000fe4f,
+	0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
+	0x00000000, 0x2a000000, 0x00000009, 0x0261ffff, 0x0000000d, 0x70e10001,
+	0x00000018, 0x80000101, 0x00000000, 0x2c400000, 0x00000008, 0x2c8000c4,
+	0x00000008, 0x2d00001c, 0x00000008, 0x2d800001, 0x00000005, 0x70e10800,
+	0x00000010, 0x91de0000, 0x00000018, 0x8000fe41, 0x0000000c, 0x29800001,
+	0x00000010, 0x91de0000, 0x00000000, 0x2fd50000, 0x00000010, 0x001f0000,
+	0x00000000, 0x02700000, 0x00000000, 0x0d620000, 0x00000000, 0xbb630800,
+	0x00000000, 0x2a000000, 0x00000000, 0x0f400000, 0x00000000, 0x2c400000,
+	0x0000000c, 0x73e7001b, 0x00000010, 0x0ce7000e, 0x00000000, 0x286d0000,
+	0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff, 0x00000018, 0x80000069,
+	0x00000008, 0x02000004, 0x00000010, 0x91c40803, 0x00000018, 0x800000f6,
+	0x00000010, 0x20530000, 0x00000018, 0x800000e5, 0x00000008, 0x2c8000b8,
+	0x00000008, 0x2d000010, 0x00000008, 0x2d800048, 0x00000018, 0x80000005,
+	0x00000008, 0x2c8000c4, 0x00000008, 0x2d00001c, 0x00000008, 0x2d800001,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800048,
+	0x00000008, 0x2d000068, 0x00000008, 0x2d800104, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x00000000, 0x27f60000, 0x00000010, 0xb87a9e04,
+	0x00000008, 0x2200000d, 0x00000018, 0x800000e2, 0x00000010, 0x20530000,
+	0x00000018, 0x8000fe18, 0x0000000c, 0x29800001, 0x00000010, 0x91de0000,
+	0x00000000, 0x2fd50000, 0x00000010, 0x001f0000, 0x00000000, 0x02700000,
+	0x00000000, 0x0d620000, 0x00000000, 0xbb630800, 0x00000000, 0x2a000000,
+	0x00000010, 0x0e670011, 0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010,
+	0x00000009, 0x266dffff, 0x00000004, 0xb8f1a000, 0x00000000, 0x0f400000,
+	0x0000000c, 0x73e7001c, 0x00000018, 0x80000040, 0x00000008, 0x02000004,
+	0x00000010, 0x91c40802, 0x00000018, 0x800000cd, 0x00000000, 0x2c1e0000,
+	0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010, 0x00000008, 0x2d800048,
+	0x00000010, 0x20530000, 0x00000010, 0x91de0000, 0x00000018, 0x8000fdfe,
+	0x0000000c, 0x29800001, 0x00000000, 0x03550000, 0x00000000, 0x06460000,
+	0x00000000, 0x03d60000, 0x00000000, 0x2a000000, 0x0000000f, 0x0f480007,
+	0x00000010, 0xb18c0027, 0x0000000f, 0x47420008, 0x00000009, 0x070e000f,
+	0x00000008, 0x070e0008, 0x00000010, 0x001f0000, 0x00000008, 0x09000001,
+	0x00000007, 0x09121c00, 0x00000003, 0xcbca9200, 0x00000000, 0x0b97a200,
+	0x00000007, 0x4b171c00, 0x0000000f, 0x0a960003, 0x00000000, 0x0a959c00,
+	0x00000000, 0x4a009a00, 0x00000008, 0x82120001, 0x00000001, 0x0c170800,
+	0x00000000, 0x02180000, 0x00000000, 0x0c971800, 0x00000008, 0x0d00ffff,
+	0x00000008, 0x0f800006, 0x0000000c, 0x29000000, 0x00000008, 0x22000001,
+	0x00000000, 0x22c50c00, 0x00000010, 0x009f0000, 0x00000010, 0xb197320b,
+	0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
+	0x00000018, 0x800000a4, 0x00000000, 0x02180000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000010, 0x001f0000, 0x00000008, 0x0f800006,
+	0x00000018, 0x8000fff5, 0x00000010, 0x91870002, 0x00000008, 0x2200000a,
+	0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
+	0x00000018, 0x80000098, 0x00000008, 0x0200000a, 0x00000010, 0x91c40804,
+	0x00000010, 0x02c20003, 0x00000010, 0x001f0000, 0x00000008, 0x0f800008,
+	0x00000010, 0x20530000, 0x00000018, 0x8000fdc9, 0x00000000, 0x06820000,
+	0x00000010, 0x001f0000, 0x00000010, 0x0ce70028, 0x00000000, 0x03720000,
+	0x00000000, 0xa8760c00, 0x00000000, 0x0cf60000, 0x00000010, 0xb8723224,
+	0x00000000, 0x03440000, 0x00000008, 0x22000010, 0x00000000, 0x03ca0000,
+	0x0000000f, 0x65680010, 0x00000000, 0x0bcf0000, 0x00000000, 0x27f20000,
+	0x00000010, 0xb7ef3203, 0x0000000c, 0x21420004, 0x0000000c, 0x73e70019,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x8000007e,
+	0x00000004, 0xb9723200, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
+	0x0000000c, 0x61420004, 0x00000000, 0x25070000, 0x00000000, 0x27970000,
+	0x00000000, 0x290e0000, 0x00000010, 0x0ce70010, 0x00000010, 0xb873320f,
+	0x0000000f, 0x436c0010, 0x00000000, 0x03f30c00, 0x00000000, 0x03f30000,
+	0x00000000, 0x83990e00, 0x00000001, 0x83860e00, 0x00000000, 0x83060e00,
+	0x00000003, 0xf66c0c00, 0x00000000, 0x39f30e00, 0x00000000, 0x3af50e00,
+	0x00000000, 0x7a740000, 0x0000000f, 0x43680010, 0x00000001, 0x83860e00,
+	0x00000000, 0x83060e00, 0x00000003, 0xf4680c00, 0x00000000, 0x286d0000,
+	0x00000000, 0x03690000, 0x00000010, 0xb1f60c54, 0x00000000, 0x0a6a0000,
+	0x00000000, 0x0aeb0000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0c000000,
+	0x00000000, 0x0be90000, 0x00000003, 0x8cf6a000, 0x0000000c, 0x09800002,
+	0x00000010, 0x009f0000, 0x00000010, 0xb8173209, 0x00000000, 0x35140000,
+	0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34970000,
+	0x00000004, 0xb8f12e00, 0x00000010, 0x001f0000, 0x00000008, 0x0f800004,
+	0x00000018, 0x8000fff7, 0x00000000, 0x03e90000, 0x00000010, 0xb8f6a01a,
+	0x00000010, 0x20130019, 0x00000010, 0xb1f10e18, 0x00000000, 0x83973200,
+	0x00000000, 0x38700e00, 0x00000000, 0xbb760e00, 0x00000000, 0x37d00000,
+	0x0000000c, 0x73e7001a, 0x00000003, 0xb8f1a000, 0x00000000, 0x32140000,
+	0x00000000, 0x32950000, 0x00000005, 0x73e72c00, 0x00000000, 0x33190000,
+	0x00000005, 0x74680000, 0x00000010, 0x0ce7000d, 0x00000008, 0x22000009,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x0000000c, 0x73e70019,
+	0x0000000f, 0x65680010, 0x0000000c, 0x21420004, 0x00000018, 0x8000003c,
+	0x00000010, 0x20530000, 0x0000000c, 0x61420004, 0x00000000, 0x290e0000,
+	0x00000018, 0x80000002, 0x00000010, 0x91973206, 0x00000000, 0x35140000,
+	0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34990000,
+	0x00000004, 0xb8f13200, 0x00000000, 0x83690c00, 0x00000010, 0xb1860013,
+	0x00000000, 0x28e90000, 0x00000008, 0x22000004, 0x00000000, 0x23ec0000,
+	0x00000000, 0x03690000, 0x00000010, 0xb8660c07, 0x00000009, 0x036cffff,
+	0x00000000, 0x326a0000, 0x00000000, 0x32eb0000, 0x00000005, 0x73e70c00,
+	0x00000000, 0x33690000, 0x00000005, 0x74680000, 0x0000000c, 0x73e7001c,
+	0x00000000, 0x03690000, 0x00000010, 0xb1f60c12, 0x00000010, 0xb1d00c11,
+	0x0000000c, 0x21420005, 0x0000000c, 0x33e7001c, 0x00000018, 0x8000000e,
+	0x00000010, 0x2e67000d, 0x00000000, 0x03690000, 0x00000010, 0xb1f60c0b,
+	0x00000010, 0xb1d00c0a, 0x00000000, 0x03440000, 0x00000008, 0x2200000c,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x80000015,
+	0x0000000c, 0x33e7001c, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
+	0x00000000, 0x290e0000, 0x00000018, 0x000d0000, 0x00000000, 0x06820000,
+	0x00000010, 0x2de7000d, 0x00000010, 0x0ce7000c, 0x00000000, 0x27f20000,
+	0x00000010, 0xb96d9e0a, 0x00000000, 0xa86d9e00, 0x00000009, 0x0361ffff,
+	0x00000010, 0xb7500c07, 0x00000008, 0x2200000f, 0x0000000f, 0x65680010,
+	0x00000000, 0x29000000, 0x00000018, 0x80000004, 0x0000000c, 0x33e7001b,
+	0x00000010, 0x20530000, 0x00000018, 0x000d0000, 0x00000000, 0x2b820000,
+	0x00000010, 0x20d2002f, 0x00000010, 0x0052002e, 0x00000009, 0x054e0007,
+	0x00000010, 0xb18a002c, 0x00000000, 0x050a8c00, 0x00000008, 0x850a0008,
+	0x00000010, 0x918a0029, 0x00000003, 0xc5008800, 0x00000008, 0xa3460001,
+	0x00000010, 0xb1c60007, 0x00000008, 0x22000001, 0x0000000c, 0x29800000,
+	0x00000010, 0x20530000, 0x00000000, 0x274e8c00, 0x00000000, 0x66cd0000,
+	0x00000000, 0x22c58c00, 0x00000008, 0x22000014, 0x00000003, 0x22c58e00,
+	0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
+	0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
+	0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x0000000c, 0x69520000,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000003, 0x22c58e00,
+	0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
+	0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
+	0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x00000000, 0xa2c58c00,
+	0x00000000, 0xa74e8c00, 0x00000000, 0xe6cd0000, 0x0000000f, 0x620a0010,
+	0x00000008, 0x23460001, 0x0000000c, 0x29800000, 0x00000010, 0x20530000,
+	0x0000000c, 0x29520000, 0x00000018, 0x80000002, 0x0000000c, 0x29800000,
+	0x00000018, 0x00570000 };
+
+static int bnx2_TPAT_b06FwReleaseMajor = 0x0;
+static int bnx2_TPAT_b06FwReleaseMinor = 0x0;
+static int bnx2_TPAT_b06FwReleaseFix = 0x0;
+static u32 bnx2_TPAT_b06FwStartAddr = 0x08000858;
+static u32 bnx2_TPAT_b06FwTextAddr = 0x08000800;
+static int bnx2_TPAT_b06FwTextLen = 0x1314;
+static u32 bnx2_TPAT_b06FwDataAddr = 0x08001b40;
+static int bnx2_TPAT_b06FwDataLen = 0x0;
+static u32 bnx2_TPAT_b06FwRodataAddr = 0x00000000;
+static int bnx2_TPAT_b06FwRodataLen = 0x0;
+static u32 bnx2_TPAT_b06FwBssAddr = 0x08001b90;
+static int bnx2_TPAT_b06FwBssLen = 0x80;
+static u32 bnx2_TPAT_b06FwSbssAddr = 0x08001b40;
+static int bnx2_TPAT_b06FwSbssLen = 0x48;
+
+static u32 bnx2_TPAT_b06FwText[(0x1314/4) + 1] = {
+	0x0a000216, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20302e36,
+	0x2e390000, 0x00060901, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000003,
+	0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24421b40, 0x3c030800,
+	0x24631c10, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800,
+	0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100858, 0x3c1c0800, 0x279c1b40,
+	0x0e00051f, 0x00000000, 0x0000000d, 0x8f820024, 0x27bdffe8, 0xafbf0014,
+	0x10400004, 0xafb00010, 0x0000000d, 0x00000000, 0x2400015f, 0x8f82001c,
+	0x8c450008, 0x24030800, 0xaf430178, 0x97430104, 0x3c020008, 0xaf420140,
+	0x8f820034, 0x30420001, 0x10400006, 0x3070ffff, 0x24020002, 0x2603fffe,
+	0xa7420146, 0x0a000246, 0xa7430148, 0xa7400146, 0x8f850034, 0x30a20020,
+	0x0002102b, 0x00021023, 0x30460009, 0x30a30c00, 0x24020400, 0x14620002,
+	0x34c40001, 0x34c40005, 0xa744014a, 0x3c020800, 0x8c440820, 0x3c030048,
+	0x24020002, 0x00832025, 0x30a30006, 0x1062000d, 0x2c620003, 0x50400005,
+	0x24020004, 0x10600012, 0x3c020001, 0x0a000271, 0x00000000, 0x10620007,
+	0x24020006, 0x1462000f, 0x3c020111, 0x0a000269, 0x00821025, 0x0a000268,
+	0x3c020101, 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830030,
+	0x0a000271, 0x00000000, 0x00821025, 0xaf421000, 0xaf800030, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x8f830030, 0x1060003f, 0x3c048000,
+	0x8f421000, 0x00441024, 0x1040fffd, 0x00000000, 0x10600039, 0x00000000,
+	0x8f421000, 0x3c030020, 0x00431024, 0x10400034, 0x00000000, 0x97421014,
+	0x14400031, 0x00000000, 0x97421008, 0x8f84001c, 0x24420006, 0x00024082,
+	0x00081880, 0x00643821, 0x8ce50000, 0x30430003, 0x30420001, 0x10400004,
+	0x00000000, 0x0000000d, 0x0a0002b0, 0x00081080, 0x5460000f, 0x30a5ffff,
+	0x3c06ffff, 0x00a62824, 0x0005182b, 0x00a61026, 0x0002102b, 0x00621824,
+	0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x240001fc, 0x8ce20000,
+	0x0a0002af, 0x00462825, 0x0005182b, 0x38a2ffff, 0x0002102b, 0x00621824,
+	0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x24000206, 0x8ce20000,
+	0x3445ffff, 0x00081080, 0x00441021, 0x3c030800, 0xac450000, 0x8c620840,
+	0x24420001, 0xac620840, 0x8f820008, 0x10400003, 0x00000000, 0x0e000660,
+	0x00000000, 0x8f840028, 0x02002821, 0x24820008, 0x30421fff, 0x24434000,
+	0x0343d821, 0x30a30007, 0xaf840018, 0xaf820028, 0xaf420084, 0x10600002,
+	0x24a20007, 0x3045fff8, 0x8f820044, 0x8f840004, 0x00451821, 0xaf82002c,
+	0x0064102b, 0xaf830044, 0x14400002, 0x00641023, 0xaf820044, 0x8f840044,
+	0x34028000, 0x8fbf0014, 0x8fb00010, 0x00821021, 0x03421821, 0x3c021000,
+	0xaf83001c, 0xaf440080, 0xaf420178, 0x03e00008, 0x27bd0018, 0x8f820024,
+	0x27bdffe8, 0xafbf0014, 0x10400004, 0xafb00010, 0x0000000d, 0x00000000,
+	0x24000249, 0x8f85001c, 0x24020001, 0xaf820024, 0x8ca70008, 0xa3800023,
+	0x8f620004, 0x3c100800, 0x26041b90, 0x00021402, 0xa3820010, 0x304600ff,
+	0x24c60005, 0x0e00064a, 0x00063082, 0x8f640004, 0x8f430108, 0x3c021000,
+	0x00621824, 0xa7840020, 0x10600008, 0x00000000, 0x97420104, 0x93830023,
+	0x2442ffec, 0x34630002, 0xa3830023, 0x0a000304, 0x3045ffff, 0x97420104,
+	0x2442fff0, 0x3045ffff, 0x8f620004, 0x3042ffff, 0x2c420013, 0x14400004,
+	0x00000000, 0x93820023, 0x34420001, 0xa3820023, 0x93830023, 0x24020001,
+	0x10620009, 0x28620002, 0x14400014, 0x24020002, 0x10620012, 0x24020003,
+	0x1062000a, 0x00000000, 0x0a000325, 0x00000000, 0x8f82001c, 0x8c43000c,
+	0x3c04ffff, 0x00641824, 0x00651825, 0x0a000325, 0xac43000c, 0x8f82001c,
+	0x8c430010, 0x3c04ffff, 0x00641824, 0x00651825, 0xac430010, 0x8f620004,
+	0x3042ffff, 0x24420002, 0x00021083, 0xa3820038, 0x304500ff, 0x8f82001c,
+	0x3c04ffff, 0x00052880, 0x00a22821, 0x8ca70000, 0x97820020, 0x97430104,
+	0x00e42024, 0x24420002, 0x00621823, 0x00833825, 0xaca70000, 0x93840038,
+	0x26061b90, 0x00041080, 0x00461021, 0x90430000, 0x3063000f, 0x00832021,
+	0xa3840022, 0x308200ff, 0x3c04fff6, 0x24420003, 0x00021080, 0x00461021,
+	0x8c450000, 0x93830022, 0x8f82001c, 0x3484ffff, 0x00a43824, 0x00031880,
+	0x00621821, 0xaf850000, 0xac67000c, 0x93820022, 0x93830022, 0x8f84001c,
+	0x24420003, 0x00021080, 0x00461021, 0x24630004, 0x00031880, 0xac470000,
+	0x93820022, 0x00661821, 0x94670002, 0x00021080, 0x00441021, 0xac670000,
+	0x24030010, 0xac470010, 0xa7430140, 0x24030002, 0xa7400142, 0xa7400144,
+	0xa7430146, 0x97420104, 0x8f840034, 0x24030001, 0x2442fffe, 0x30840006,
+	0xa7420148, 0x24020002, 0xa743014a, 0x1082000d, 0x2c820003, 0x10400005,
+	0x24020004, 0x10800011, 0x3c020009, 0x0a000383, 0x00000000, 0x10820007,
+	0x24020006, 0x1482000d, 0x3c020119, 0x0a00037d, 0x24030001, 0x0a00037c,
+	0x3c020109, 0x3c020019, 0x24030001, 0xaf421000, 0xaf830030, 0x0a000383,
+	0x00000000, 0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x93820010, 0x24030008, 0x8f840030, 0x24420002, 0x30420007,
+	0x00621823, 0x30630007, 0xaf83000c, 0x10800005, 0x3c038000, 0x8f421000,
+	0x00431024, 0x1040fffd, 0x00000000, 0x8f820028, 0xaf820018, 0x24420010,
+	0x30421fff, 0xaf820028, 0xaf420084, 0x97430104, 0x24424000, 0x0342d821,
+	0x3063ffff, 0x30620007, 0x10400002, 0x24620007, 0x3043fff8, 0x8f820044,
+	0x8f840004, 0x00431821, 0xaf82002c, 0x0064102b, 0xaf830044, 0x14400002,
+	0x00641023, 0xaf820044, 0x8f840044, 0x34028000, 0x8fbf0014, 0x8fb00010,
+	0x00821021, 0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0xaf420178,
+	0x03e00008, 0x27bd0018, 0x8f820024, 0x27bdffe8, 0xafbf0014, 0x14400004,
+	0xafb00010, 0x0000000d, 0x00000000, 0x240002db, 0x8f620004, 0x04410009,
+	0x3c050800, 0x93820022, 0x8f830000, 0x24a41b90, 0xaf800024, 0x24420003,
+	0x00021080, 0x00441021, 0xac430000, 0x93820038, 0x24a51b90, 0x93860010,
+	0x3c040001, 0x27700008, 0x24420001, 0x00021080, 0x00451021, 0x8c430000,
+	0x24c60005, 0x00063082, 0x00641821, 0x02002021, 0x0e00064a, 0xac430000,
+	0x93840022, 0x3c057fff, 0x8f620004, 0x00042080, 0x00902021, 0x8c830004,
+	0x34a5ffff, 0x00451024, 0x00621821, 0xac830004, 0x93850038, 0x3c07ffff,
+	0x93840010, 0x00052880, 0x00b02821, 0x8ca30000, 0x97420104, 0x97860020,
+	0x00671824, 0x00441021, 0x00461023, 0x3042ffff, 0x00621825, 0xaca30000,
+	0x93830023, 0x24020001, 0x10620009, 0x28620002, 0x1440001a, 0x24020002,
+	0x10620018, 0x24020003, 0x1062000d, 0x00000000, 0x0a000411, 0x00000000,
+	0x93820010, 0x97430104, 0x8e04000c, 0x00621821, 0x2463fff2, 0x3063ffff,
+	0x00872024, 0x00832025, 0x0a000411, 0xae04000c, 0x93820010, 0x97430104,
+	0x8e040010, 0x00621821, 0x2463ffee, 0x3063ffff, 0x00872024, 0x00832025,
+	0xae040010, 0x9783000e, 0x8f840034, 0x2402000a, 0xa7420140, 0xa7430142,
+	0x93820010, 0xa7420144, 0xa7400146, 0x97430104, 0x30840006, 0x24020001,
+	0xa7430148, 0xa742014a, 0x24020002, 0x1082000d, 0x2c820003, 0x10400005,
+	0x24020004, 0x10800011, 0x3c020041, 0x0a000437, 0x00000000, 0x10820007,
+	0x24020006, 0x1482000d, 0x3c020151, 0x0a000431, 0x24030001, 0x0a000430,
+	0x3c020141, 0x3c020051, 0x24030001, 0xaf421000, 0xaf830030, 0x0a000437,
+	0x00000000, 0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x8f820030, 0x93840010, 0x8f850028, 0x10400005, 0x3c038000,
+	0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x2483000a, 0x30620007,
+	0x10400002, 0x24620007, 0x304303f8, 0x00a31021, 0x30421fff, 0xaf850018,
+	0xaf820028, 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff,
+	0x30620007, 0x10400002, 0x24620007, 0x3043fff8, 0x8f820044, 0x8f840004,
+	0x00431821, 0xaf82002c, 0x0064102b, 0xaf830044, 0x14400002, 0x00641023,
+	0xaf820044, 0x8f840044, 0x34028000, 0x8fbf0014, 0x8fb00010, 0x00821021,
+	0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0xaf420178, 0x03e00008,
+	0x27bd0018, 0x3c026000, 0x8c444448, 0x3c030800, 0xac64082c, 0x8f620000,
+	0x97430104, 0x3c048000, 0x3046ffff, 0x3067ffff, 0x8f420178, 0x00441024,
+	0x1440fffd, 0x2402000a, 0x30c30007, 0xa7420140, 0x24020008, 0x00431023,
+	0x30420007, 0x24c3fffe, 0xa7420142, 0xa7430144, 0xa7400146, 0xa7470148,
+	0x8f420108, 0x3c036000, 0x8f850034, 0x30420020, 0x0002102b, 0x00021023,
+	0x30420009, 0x34420001, 0xa742014a, 0x8c644448, 0x3c020800, 0x30a50006,
+	0xac440830, 0x24020002, 0x10a2000d, 0x2ca20003, 0x10400005, 0x24020004,
+	0x10a00011, 0x3c020041, 0x0a0004a8, 0x00000000, 0x10a20007, 0x24020006,
+	0x14a2000d, 0x3c020151, 0x0a0004a2, 0x24030001, 0x0a0004a1, 0x3c020141,
+	0x3c020051, 0x24030001, 0xaf421000, 0xaf830030, 0x0a0004a8, 0x00000000,
+	0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x8f820030, 0x24c30008, 0x10400006, 0x30e6ffff, 0x3c048000, 0x8f421000,
+	0x00441024, 0x1040fffd, 0x00000000, 0x3c026000, 0x8c444448, 0x3065ffff,
+	0x3c020800, 0x30a30007, 0x10600003, 0xac440834, 0x24a20007, 0x3045fff8,
+	0x8f840028, 0x00851021, 0x30421fff, 0x24434000, 0x0343d821, 0x30c30007,
+	0xaf840018, 0xaf820028, 0xaf420084, 0x10600002, 0x24c20007, 0x3046fff8,
+	0x8f820044, 0x8f840004, 0x00461821, 0xaf82002c, 0x0064102b, 0xaf830044,
+	0x14400002, 0x00641023, 0xaf820044, 0x8f840044, 0x34028000, 0x3c030800,
+	0x8c650844, 0x00821021, 0x03421821, 0xaf83001c, 0xaf440080, 0x10a00006,
+	0x2402000e, 0x93830043, 0x14620004, 0x3c021000, 0x2402043f, 0xa7420148,
+	0x3c021000, 0x3c036000, 0xaf420178, 0x8c644448, 0x3c020800, 0x03e00008,
+	0xac440838, 0x8f820034, 0x30424000, 0x10400005, 0x24020800, 0x0000000d,
+	0x00000000, 0x24000405, 0x24020800, 0xaf420178, 0x97440104, 0x3c030008,
+	0xaf430140, 0x8f820034, 0x30420001, 0x10400006, 0x3085ffff, 0x24020002,
+	0x24a3fffe, 0xa7420146, 0x0a0004ff, 0xa7430148, 0xa7400146, 0x8f840028,
+	0x2402000d, 0xa742014a, 0x24830008, 0x30631fff, 0x24624000, 0x0342d821,
+	0x30a20007, 0xaf840018, 0xaf830028, 0xaf430084, 0x10400002, 0x24a20007,
+	0x3045fff8, 0x8f820044, 0x8f840004, 0x00451821, 0xaf82002c, 0x0064102b,
+	0xaf830044, 0x14400002, 0x00641023, 0xaf820044, 0x8f840044, 0x34028000,
+	0x00821021, 0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0x03e00008,
+	0xaf420178, 0x27bdffe8, 0x3c046008, 0xafbf0014, 0xafb00010, 0x8c825000,
+	0x3c1a8000, 0x2403ff7f, 0x375b4000, 0x00431024, 0x3442380c, 0xac825000,
+	0x8f430008, 0x3c100800, 0x37428000, 0x34630001, 0xaf430008, 0xaf82001c,
+	0x3c02601c, 0xaf800028, 0xaf400080, 0xaf400084, 0x8c450008, 0x3c036000,
+	0x8c620808, 0x3c040800, 0x3c030080, 0xac830820, 0x3042fff0, 0x38420010,
+	0x2c420001, 0xaf850004, 0xaf820008, 0x0e00062f, 0x00000000, 0x8f420000,
+	0x30420001, 0x1040fffb, 0x00000000, 0x8f440108, 0x30822000, 0xaf840034,
+	0x10400004, 0x8e02083c, 0x24420001, 0x0a00059d, 0xae02083c, 0x30820200,
+	0x10400027, 0x00000000, 0x97420104, 0x1040001c, 0x30824000, 0x14400005,
+	0x00000000, 0x0e00022d, 0x00000000, 0x0a000592, 0x00000000, 0x8f620008,
+	0x8f630000, 0x24020030, 0x00031e02, 0x306300f0, 0x10620007, 0x28620031,
+	0x14400031, 0x24020040, 0x10620007, 0x00000000, 0x0a000592, 0x00000000,
+	0x0e0002dd, 0x00000000, 0x0a000592, 0x00000000, 0x0e0003b8, 0x00000000,
+	0x0a000592, 0x00000000, 0x30820040, 0x1440002d, 0x00000000, 0x0000000d,
+	0x00000000, 0x240004a6, 0x0a00059d, 0x00000000, 0x8f430100, 0x24020d00,
+	0x1462000f, 0x30820006, 0x97420104, 0x10400005, 0x30820040, 0x0e0004e9,
+	0x00000000, 0x0a000592, 0x00000000, 0x1440001b, 0x00000000, 0x0000000d,
+	0x00000000, 0x240004b8, 0x0a00059d, 0x00000000, 0x1040000e, 0x30821000,
+	0x10400005, 0x00000000, 0x0e00065d, 0x00000000, 0x0a000592, 0x00000000,
+	0x0e00046b, 0x00000000, 0x8f820040, 0x24420001, 0xaf820040, 0x0a00059d,
+	0x00000000, 0x30820040, 0x14400004, 0x00000000, 0x0000000d, 0x00000000,
+	0x240004cf, 0x8f420138, 0x3c034000, 0x00431025, 0xaf420138, 0x0a00053f,
+	0x00000000, 0x3c046008, 0x8c835000, 0x3c1a8000, 0x2402ff7f, 0x375b4000,
+	0x00621824, 0x3463380c, 0xac835000, 0x8f420008, 0x3c056000, 0x3c03601c,
+	0x34420001, 0xaf420008, 0x37428000, 0xaf800028, 0xaf82001c, 0xaf400080,
+	0xaf400084, 0x8c660008, 0x8ca20808, 0x3c040800, 0x3c030080, 0xac830820,
+	0x3042fff0, 0x38420010, 0x2c420001, 0xaf860004, 0xaf820008, 0x03e00008,
+	0x00000000, 0x3084ffff, 0x30820007, 0x10400002, 0x24820007, 0x3044fff8,
+	0x8f820028, 0x00441821, 0x30631fff, 0x24644000, 0x0344d821, 0xaf820018,
+	0xaf830028, 0x03e00008, 0xaf430084, 0x3084ffff, 0x30820007, 0x10400002,
+	0x24820007, 0x3044fff8, 0x8f820044, 0x8f830004, 0x00442021, 0xaf82002c,
+	0x0083102b, 0xaf840044, 0x14400002, 0x00831023, 0xaf820044, 0x8f820044,
+	0x34038000, 0x00431821, 0x03432021, 0xaf84001c, 0x03e00008, 0xaf420080,
+	0x8f830034, 0x24020002, 0x30630006, 0x1062000d, 0x2c620003, 0x50400005,
+	0x24020004, 0x10600012, 0x3c020001, 0x0a000601, 0x00000000, 0x10620007,
+	0x24020006, 0x1462000f, 0x3c020111, 0x0a0005f9, 0x00821025, 0x0a0005f8,
+	0x3c020101, 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830030,
+	0x0a000601, 0x00000000, 0x00821025, 0xaf421000, 0xaf800030, 0x00000000,
+	0x00000000, 0x00000000, 0x03e00008, 0x00000000, 0x8f820030, 0x10400005,
+	0x3c038000, 0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x03e00008,
+	0x00000000, 0x8f820034, 0x27bdffe8, 0x30424000, 0x14400005, 0xafbf0010,
+	0x0e00022d, 0x00000000, 0x0a00062d, 0x8fbf0010, 0x8f620008, 0x8f630000,
+	0x24020030, 0x00031e02, 0x306300f0, 0x10620008, 0x28620031, 0x1440000d,
+	0x8fbf0010, 0x24020040, 0x10620007, 0x00000000, 0x0a00062d, 0x00000000,
+	0x0e0002dd, 0x00000000, 0x0a00062d, 0x8fbf0010, 0x0e0003b8, 0x00000000,
+	0x8fbf0010, 0x03e00008, 0x27bd0018, 0x8f84003c, 0x1080000f, 0x3c026000,
+	0x8c430c3c, 0x30630fff, 0xaf830014, 0x14600011, 0x3082000f, 0x10400005,
+	0x308200f0, 0x10400003, 0x30820f00, 0x14400006, 0x00000000, 0x0000000d,
+	0x00000000, 0x2400050e, 0x03e00008, 0x00000000, 0x0000000d, 0x00000000,
+	0x24000513, 0x03e00008, 0x00000000, 0xaf83003c, 0x03e00008, 0x00000000,
+	0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000,
+	0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a000659, 0x00a01021,
+	0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008,
+	0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x3c040800, 0x8c82084c,
+	0x54400007, 0xac80084c, 0x8f820034, 0x24030400, 0x30420c00, 0x1443005b,
+	0x00000000, 0xac80084c, 0x0000000d, 0x00000000, 0x2400003c, 0x3c026000,
+	0x8c444448, 0x3c030800, 0xac640850, 0x24000043, 0x97420104, 0x3045ffff,
+	0x000530c2, 0x24a2007f, 0x000239c2, 0x2400004e, 0x3c046020, 0x24030020,
+	0xac830000, 0x8c820000, 0x30420020, 0x10400005, 0x3c036020, 0x8c620000,
+	0x30420020, 0x1440fffd, 0x00000000, 0x3c026020, 0x8c430010, 0x24040001,
+	0x0087102b, 0x30ea007f, 0x24abfffe, 0x10400010, 0x00034240, 0x3c056020,
+	0x24090020, 0xaca90000, 0x8ca20000, 0x30420020, 0x10400006, 0x24840001,
+	0x3c036020, 0x8c620000, 0x30420020, 0x1440fffd, 0x00000000, 0x0087102b,
+	0x1440fff4, 0x00000000, 0x8f85001c, 0x3c026020, 0x8c430010, 0x3c046020,
+	0x34848000, 0x006a1825, 0x01034025, 0x2400006b, 0x10c0000b, 0x00000000,
+	0x8ca30000, 0x24a50004, 0x8ca20000, 0x24a50004, 0x24c6ffff, 0xac820000,
+	0x24840004, 0xac830000, 0x14c0fff7, 0x24840004, 0x24000077, 0x3c020007,
+	0x34427700, 0x3c036000, 0xac6223c8, 0xac6b23cc, 0xac6823e4, 0x24000086,
+	0x3c046000, 0x3c038000, 0x8c8223f8, 0x00431024, 0x1440fffd, 0x3c021000,
+	0x3c056000, 0x24030019, 0xaca223f8, 0xa743014a, 0x8ca44448, 0x3c020800,
+	0xac440854, 0x03e00008, 0x00000000, 0x00000000 };
+
+static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_TPAT_b06FwBss[(0x80/4) + 1] = { 0x00000000 };
+static u32 bnx2_TPAT_b06FwSbss[(0x48/4) + 1] = { 0x00000000 };
+
+static int bnx2_TXP_b06FwReleaseMajor = 0x0;
+static int bnx2_TXP_b06FwReleaseMinor = 0x0;
+static int bnx2_TXP_b06FwReleaseFix = 0x0;
+static u32 bnx2_TXP_b06FwStartAddr = 0x08002090;
+static u32 bnx2_TXP_b06FwTextAddr = 0x08000000;
+static int bnx2_TXP_b06FwTextLen = 0x3ffc;
+static u32 bnx2_TXP_b06FwDataAddr = 0x08004020;
+static int bnx2_TXP_b06FwDataLen = 0x0;
+static u32 bnx2_TXP_b06FwRodataAddr = 0x00000000;
+static int bnx2_TXP_b06FwRodataLen = 0x0;
+static u32 bnx2_TXP_b06FwBssAddr = 0x08004060;
+static int bnx2_TXP_b06FwBssLen = 0x194;
+static u32 bnx2_TXP_b06FwSbssAddr = 0x08004020;
+static int bnx2_TXP_b06FwSbssLen = 0x34;
+static u32 bnx2_TXP_b06FwText[(0x3ffc/4) + 1] = {
+	0x0a000824, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x302e362e,
+	0x39000000, 0x00060900, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d,
+	0x0000000d, 0x3c020800, 0x24424020, 0x3c030800, 0x246341f4, 0xac400000,
+	0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021,
+	0x3c100800, 0x26102090, 0x3c1c0800, 0x279c4020, 0x0e000a0e, 0x00000000,
+	0x0000000d, 0x8f840014, 0x27bdffe8, 0xafb00010, 0x8f460104, 0x8f830008,
+	0x8c8500ac, 0xaf430080, 0x948200a8, 0xa7420e10, 0x948300aa, 0xa7430e12,
+	0x8c8200ac, 0xaf420e18, 0x97430e10, 0xa7430e14, 0x97420e12, 0xa7420e16,
+	0x8f430e18, 0x00005021, 0x00c53023, 0x10c001a3, 0xaf430e1c, 0x240f0800,
+	0x3c0e1000, 0x2419fff8, 0x24100010, 0x3c188100, 0x93620008, 0x10400009,
+	0x00000000, 0x97620010, 0x00c2102b, 0x14400005, 0x00000000, 0x97620010,
+	0x3042ffff, 0x0a000862, 0xaf420e00, 0xaf460e00, 0x8f420000, 0x30420008,
+	0x1040fffd, 0x00000000, 0x97420e08, 0x8f450e04, 0x3044ffff, 0x30820001,
+	0x14400005, 0x00000000, 0x14a00005, 0x3083a040, 0x0a0009e6, 0x00000000,
+	0x0000000d, 0x3083a040, 0x24020040, 0x14620049, 0x3082a000, 0x8f87000c,
+	0x30880036, 0x30890008, 0xaf4f0178, 0x00e01821, 0x9742008a, 0x00431023,
+	0x2442ffff, 0x30421fff, 0x2c420008, 0x1440fffa, 0x00000000, 0x8f830018,
+	0x00a05021, 0x00c53023, 0x24e24000, 0x03422821, 0x306b00ff, 0x24630001,
+	0xaf830018, 0x93840012, 0x000b1400, 0x3c030100, 0x00431025, 0xaca20000,
+	0x8f820018, 0x30840007, 0x00042240, 0x34870001, 0x00e83825, 0x1120000f,
+	0xaca20004, 0x97430e0a, 0x8f84000c, 0x00ee3825, 0x2402000e, 0x00781825,
+	0xaf430160, 0x25430006, 0x24840008, 0x30841fff, 0xa742015a, 0xa7430158,
+	0xaf84000c, 0x0a0008a9, 0x00000000, 0x8f83000c, 0x25420002, 0xa7420158,
+	0x24630008, 0x30631fff, 0xaf83000c, 0x54c0000c, 0x8f420e14, 0x97420e10,
+	0x97430e12, 0x8f840014, 0x00021400, 0x00621825, 0xac8300a8, 0x8f850014,
+	0x8f420e18, 0x34e70040, 0xaca200ac, 0x8f420e14, 0x8f430e1c, 0xaf420144,
+	0xaf430148, 0xa34b0152, 0xaf470154, 0x0a0009f1, 0xaf4e0178, 0x10400128,
+	0x00000000, 0x97620010, 0x00a2102b, 0x10400003, 0x30820040, 0x10400122,
+	0x00000000, 0xafa60008, 0xa7840010, 0xaf850004, 0x93620008, 0x1440005e,
+	0x27ac0008, 0xaf60000c, 0x97820010, 0x30424000, 0x10400002, 0x2403000e,
+	0x24030016, 0xa363000a, 0x24034007, 0xaf630014, 0x93820012, 0x8f630014,
+	0x30420007, 0x00021240, 0x00621825, 0xaf630014, 0x97820010, 0x8f630014,
+	0x30420010, 0x00621825, 0xaf630014, 0x97820010, 0x30420008, 0x5040000e,
+	0x00002821, 0x8f620014, 0x004e1025, 0xaf620014, 0x97430e0a, 0x2402000e,
+	0x00781825, 0xaf630004, 0xa3620002, 0x9363000a, 0x3405fffc, 0x24630004,
+	0x0a0008f2, 0xa363000a, 0xaf600004, 0xa3600002, 0x97820010, 0x9363000a,
+	0x30421f00, 0x00021182, 0x24420028, 0x00621821, 0xa3630009, 0x97420e0c,
+	0xa7620010, 0x93630009, 0x24020008, 0x24630002, 0x30630007, 0x00431023,
+	0x30420007, 0xa362000b, 0x93640009, 0x97620010, 0x8f890004, 0x97830010,
+	0x00441021, 0x00a21021, 0x30630040, 0x10600006, 0x3045ffff, 0x15250005,
+	0x0125102b, 0x3c068000, 0x0a000925, 0x00005821, 0x0125102b, 0x144000c8,
+	0x00005021, 0x97420e14, 0xa7420e10, 0x97430e16, 0xa7430e12, 0x8f420e1c,
+	0xaf420e18, 0xaf450e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000,
+	0x97420e08, 0x00a04821, 0xa7820010, 0x8f430e04, 0x00003021, 0x240b0001,
+	0xaf830004, 0x97620010, 0x0a000936, 0x304dffff, 0x8f890004, 0x97820010,
+	0x30420040, 0x10400004, 0x01206821, 0x3c068000, 0x0a000936, 0x00005821,
+	0x97630010, 0x8f820004, 0x144300a7, 0x00005021, 0x00003021, 0x240b0001,
+	0x8d820000, 0x00491023, 0x1440000d, 0xad820000, 0x8f620014, 0x34420040,
+	0xaf620014, 0x97430e10, 0x97420e12, 0x8f840014, 0x00031c00, 0x00431025,
+	0xac8200a8, 0x8f830014, 0x8f420e18, 0xac6200ac, 0x93620008, 0x1440003f,
+	0x00000000, 0x25260002, 0x8f84000c, 0x9743008a, 0x3063ffff, 0xafa30000,
+	0x8fa20000, 0x00441023, 0x2442ffff, 0x30421fff, 0x2c420010, 0x1440fff7,
+	0x00000000, 0x8f82000c, 0x8f830018, 0x00021082, 0x00021080, 0x24424000,
+	0x03422821, 0x00605021, 0x24630001, 0x314200ff, 0x00021400, 0xaf830018,
+	0x3c033200, 0x00431025, 0xaca20000, 0x93630009, 0x9362000a, 0x00031c00,
+	0x00431025, 0xaca20004, 0x8f830018, 0xaca30008, 0x97820010, 0x30420008,
+	0x10400002, 0x00c04021, 0x25280006, 0x97430e14, 0x93640002, 0x8f450e1c,
+	0x8f660004, 0x8f670014, 0xaf4f0178, 0x3063ffff, 0xa7430144, 0x97420e16,
+	0xa7420146, 0xaf450148, 0xa34a0152, 0x8f82000c, 0x308400ff, 0xa744015a,
+	0xaf460160, 0xa7480158, 0xaf470154, 0xaf4e0178, 0x00501021, 0x30421fff,
+	0xaf82000c, 0x0a0009c5, 0x8d820000, 0x93620009, 0x9363000b, 0x8f85000c,
+	0x2463000a, 0x00435021, 0x25440007, 0x00992024, 0x9743008a, 0x3063ffff,
+	0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b,
+	0x1440fff7, 0x00000000, 0x8f82000c, 0x8f840018, 0x00021082, 0x00021080,
+	0x24424000, 0x03422821, 0x00804021, 0x24840001, 0xaf840018, 0x93630009,
+	0x310200ff, 0x00022400, 0x3c024100, 0x24630002, 0x00621825, 0x00832025,
+	0xaca40000, 0x8f62000c, 0x00461025, 0xaca20004, 0x97430e14, 0x93640002,
+	0x8f450e1c, 0x8f660004, 0x8f670014, 0xaf4f0178, 0x3063ffff, 0xa7430144,
+	0x97420e16, 0x308400ff, 0xa7420146, 0xaf450148, 0xa3480152, 0x8f83000c,
+	0x25420007, 0x00591024, 0xa744015a, 0xaf460160, 0xa7490158, 0xaf470154,
+	0xaf4e0178, 0x00621821, 0x30631fff, 0xaf83000c, 0x8d820000, 0x14400005,
+	0x00000000, 0x8f620014, 0x2403ffbf, 0x00431024, 0xaf620014, 0x8f62000c,
+	0x004d1021, 0xaf62000c, 0x93630008, 0x14600008, 0x00000000, 0x11600006,
+	0x00000000, 0x8f630014, 0x3c02efff, 0x3442fffe, 0x00621824, 0xaf630014,
+	0xa36b0008, 0x01205021, 0x15400016, 0x8fa60008, 0x97420e14, 0x97430e16,
+	0x8f850014, 0x00021400, 0x00621825, 0xaca300a8, 0x8f840014, 0x8f420e1c,
+	0x0a0009f3, 0xac8200ac, 0x97420e14, 0x97430e16, 0x8f840014, 0x00021400,
+	0x00621825, 0xac8300a8, 0x8f850014, 0x8f420e1c, 0x00005021, 0x0a0009f3,
+	0xaca200ac, 0x14c0fe64, 0x00000000, 0x55400018, 0x8fb00010, 0x3c038000,
+	0x8f420178, 0x00431024, 0x1440fffd, 0x00000000, 0x97430e14, 0x8f440e1c,
+	0x24020800, 0xaf420178, 0x3063ffff, 0xa7430144, 0x97420e16, 0x3c031000,
+	0xa7420146, 0x24020240, 0xaf440148, 0xa3400152, 0xa740015a, 0xaf400160,
+	0xa7400158, 0xaf420154, 0xaf430178, 0x8fb00010, 0x03e00008, 0x27bd0018,
+	0x27bdffd8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008, 0x03421821,
+	0xafbf0020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0xaf830014,
+	0xaf440e00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x3c0200ff, 0x3442fffd, 0x3c046004, 0xaf420e00, 0x8c835000, 0x24130d00,
+	0x3c120800, 0x3c114000, 0x2402ff7f, 0x00621824, 0x3463380c, 0x24020009,
+	0xac835000, 0xaf420008, 0xaf800018, 0xaf80000c, 0x0e000fa1, 0x00000000,
+	0x0e000a96, 0x00000000, 0x3c020800, 0x24504080, 0x8f420000, 0x30420001,
+	0x1040fffd, 0x00000000, 0x8f440100, 0xaf840008, 0xaf440020, 0x93430108,
+	0xa3830012, 0x93820012, 0x30420001, 0x10400008, 0x00000000, 0x93820012,
+	0x30420006, 0x00021100, 0x0e00083b, 0x0050d821, 0x0a000a52, 0x00000000,
+	0x14930005, 0x00000000, 0x0e00083b, 0x265b4100, 0x0a000a52, 0x00000000,
+	0x0e000ba3, 0x00000000, 0xaf510138, 0x0a000a36, 0x00000000, 0x27bdfff8,
+	0x3084ffff, 0x24820007, 0x3044fff8, 0x8f85000c, 0x9743008a, 0x3063ffff,
+	0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b,
+	0x1440fff7, 0x00000000, 0x8f82000c, 0x00021082, 0x00021080, 0x24424000,
+	0x03421021, 0x03e00008, 0x27bd0008, 0x3084ffff, 0x8f82000c, 0x24840007,
+	0x3084fff8, 0x00441021, 0x30421fff, 0xaf82000c, 0x03e00008, 0x00000000,
+	0x27bdffe8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008, 0x03421821,
+	0xafbf0010, 0xaf830014, 0xaf440e00, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd, 0x3c046004, 0xaf420e00,
+	0x8c825000, 0x2403ff7f, 0x00431024, 0x3442380c, 0x24030009, 0xac825000,
+	0xaf430008, 0xaf800018, 0xaf80000c, 0x0e000fa1, 0x00000000, 0x0e000a96,
+	0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0x3c02000a,
+	0x03421821, 0x3c040800, 0x24844120, 0x24050018, 0xafbf0010, 0xaf830024,
+	0x0e000fad, 0x00003021, 0x3c050800, 0x3c020800, 0x24423d60, 0xaca24180,
+	0x24a54180, 0x3c020800, 0x24423e18, 0x3c030800, 0x24633e2c, 0x3c040800,
+	0xaca20004, 0x3c020800, 0x24423d68, 0xaca30008, 0xac824190, 0x24844190,
+	0x3c020800, 0x24423da4, 0x3c070800, 0x24e73de4, 0x3c060800, 0x24c63e40,
+	0x3c050800, 0x24a52b28, 0x3c030800, 0xac820004, 0x3c020800, 0x24423e48,
+	0xac870008, 0xac86000c, 0xac850010, 0xac6241b0, 0x246341b0, 0x8fbf0010,
+	0x3c020800, 0x24423e60, 0xac620004, 0xac670008, 0xac66000c, 0xac650010,
+	0x03e00008, 0x27bd0018, 0x27bdffc8, 0x3c020800, 0x24424120, 0xafbf0030,
+	0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x90470021, 0x8c510008,
+	0x8c45001c, 0x8f900020, 0x3c060800, 0x3c038000, 0x8f420178, 0x00431024,
+	0x1440fffd, 0x8cc2414c, 0x24c3414c, 0x2473ffd4, 0xaf420144, 0x8e620030,
+	0x30b22000, 0xaf420148, 0x3c021000, 0xaf50014c, 0xa3470152, 0xa7510158,
+	0xaf450154, 0xaf420178, 0x12400004, 0x3c030800, 0x8c620030, 0x24420001,
+	0xac620030, 0x93420109, 0x9344010a, 0x00111c00, 0xafa30018, 0x00071a00,
+	0xafa50014, 0x8cc5414c, 0x00021600, 0x00042400, 0x00441025, 0x00431025,
+	0xafa20010, 0x8f440100, 0x8e660030, 0x0e000fe1, 0x02003821, 0x1640000e,
+	0x8fbf0030, 0x8f820000, 0x8e630030, 0x8c44017c, 0x02031823, 0x00711823,
+	0x00641823, 0x2c630002, 0x14600006, 0x8fb3002c, 0x0000000d, 0x00000000,
+	0x240000ca, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+	0x03e00008, 0x27bd0038, 0x974309da, 0x00804021, 0xad030000, 0x8f4209dc,
+	0xad020004, 0x8f4309e0, 0xad030008, 0x934409d9, 0x24020001, 0x30840003,
+	0x1082001f, 0x30a900ff, 0x28820002, 0x10400005, 0x24020002, 0x10800009,
+	0x3c0a0800, 0x0a000b64, 0x93420934, 0x1082000b, 0x24020003, 0x10820026,
+	0x3c0a0800, 0x0a000b64, 0x93420934, 0x974209e4, 0x00021400, 0x34420800,
+	0xad02000c, 0x0a000b63, 0x25080010, 0x974209e4, 0x00021400, 0x34428100,
+	0xad02000c, 0x974309e8, 0x3c0a0800, 0x00031c00, 0x34630800, 0xad030010,
+	0x0a000b63, 0x25080014, 0x974409e4, 0x3c050800, 0x24a24120, 0x94430018,
+	0x94460010, 0x9447000c, 0x00a05021, 0x24020800, 0xad000010, 0xad020014,
+	0x00042400, 0x00661821, 0x00671823, 0x2463fff2, 0x00832025, 0xad04000c,
+	0x0a000b63, 0x25080018, 0x974209e4, 0x3c050800, 0x00021400, 0x34428100,
+	0xad02000c, 0x974409e8, 0x24a24120, 0x94430018, 0x94460010, 0x9447000c,
+	0x00a05021, 0x24020800, 0xad000014, 0xad020018, 0x00042400, 0x00661821,
+	0x00671823, 0x2463ffee, 0x00832025, 0xad040010, 0x2508001c, 0x93420934,
+	0x93450921, 0x3c074000, 0x25444120, 0x94830014, 0x94860010, 0x00021082,
+	0x00021600, 0x00052c00, 0x00a72825, 0x00451025, 0x00661821, 0x00431025,
+	0xad020000, 0x97830028, 0x974209ea, 0x00621821, 0x00031c00, 0xad030004,
+	0x97820028, 0x24420001, 0x30427fff, 0xa7820028, 0x93430920, 0x3c020006,
+	0x00031e00, 0x00621825, 0xad030008, 0x8f42092c, 0xad02000c, 0x8f430930,
+	0xad030010, 0x8f440938, 0x25080014, 0xad040000, 0x8f820020, 0x11200004,
+	0xad020004, 0x8f420940, 0x0a000b8d, 0x2442ffff, 0x8f420940, 0xad020008,
+	0x8f440948, 0x8f420940, 0x93430936, 0x00822823, 0x00652806, 0x3402ffff,
+	0x0045102b, 0x54400001, 0x3405ffff, 0x93420937, 0x25444120, 0x90830020,
+	0xad000010, 0x00021700, 0x34630010, 0x00031c00, 0x00431025, 0x00451025,
+	0xad02000c, 0x03e00008, 0x25020014, 0x27bdffb0, 0x3c020008, 0x03421821,
+	0xafbf004c, 0xafbe0048, 0xafb70044, 0xafb60040, 0xafb5003c, 0xafb40038,
+	0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, 0xaf830000, 0x24020040,
+	0xaf420814, 0xaf400810, 0x8f420944, 0x8f430950, 0x8f440954, 0x8f45095c,
+	0xaf820030, 0xaf830020, 0xaf84001c, 0xaf85002c, 0x93430900, 0x24020020,
+	0x10620005, 0x24020030, 0x10620022, 0x3c030800, 0x0a000bf1, 0x8c62002c,
+	0x24020088, 0xaf420818, 0x3c020800, 0x24424180, 0xafa20020, 0x93430109,
+	0x3c020800, 0x10600009, 0x24574190, 0x3c026000, 0x24030100, 0xac43081c,
+	0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x2400031d, 0x9342010a,
+	0x30420080, 0x1440001c, 0x00000000, 0x3c026000, 0x24030100, 0xac43081c,
+	0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x24000324, 0x0a000bf4,
+	0x00000000, 0x93430109, 0x3063007f, 0x00031140, 0x000318c0, 0x00431021,
+	0x24430088, 0xaf430818, 0x0000000d, 0x3c020800, 0x244241d0, 0x3c030800,
+	0x247741e0, 0x0a000bf4, 0xafa20020, 0x24420001, 0x0a000f4c, 0xac62002c,
+	0x8f840000, 0x8f850020, 0x24020800, 0xaf420178, 0x8f4209a4, 0x8c83017c,
+	0x00a21023, 0x00431023, 0x2c420002, 0x14400004, 0x00000000, 0x0000000d,
+	0x00000000, 0x24000349, 0x8f420104, 0x8f430988, 0x00431023, 0x58400005,
+	0x8f4209a0, 0x0000000d, 0x00000000, 0x2400034d, 0x8f4209a0, 0x3c100800,
+	0xae02414c, 0x8f4309a4, 0x2604414c, 0x2491ffd4, 0xae230030, 0x8f420104,
+	0xae250024, 0x00431023, 0xac82ffd4, 0x8fa30020, 0x8c620000, 0x0040f809,
+	0x0200b021, 0x00409021, 0x32440010, 0x32420002, 0x10400007, 0xafa40024,
+	0x8e22001c, 0x32500040, 0x2403ffbf, 0x00431024, 0x0a000f13, 0xae22001c,
+	0x32420020, 0x10400002, 0x3c020800, 0x245741b0, 0x32420001, 0x14400007,
+	0x00000000, 0x8f820008, 0xaf420080, 0x8ec3414c, 0xaf430e10, 0x8e220030,
+	0xaf420e18, 0x9343010b, 0x93420905, 0x30420008, 0x1040003c, 0x307400ff,
+	0x8f820000, 0x8c430074, 0x0460000a, 0x00000000, 0x3c026000, 0x24030100,
+	0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x24000384,
+	0x8f820000, 0x9044007b, 0x9343010a, 0x14830027, 0x32500040, 0x24072000,
+	0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec2414c,
+	0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030100, 0xaf420148,
+	0x24020047, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000, 0xa7430158,
+	0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, 0x24630001,
+	0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018, 0x00021600,
+	0x00031c00, 0x00431025, 0x34424700, 0xafa20010, 0x8f440100, 0x0e000fe1,
+	0x3c070100, 0x3c030800, 0x24624120, 0x0a000d01, 0x8c43001c, 0x32820002,
+	0x10400047, 0x3c039000, 0x34630001, 0x8f820008, 0x32500040, 0x3c048000,
+	0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000,
+	0x8f830000, 0x90620005, 0x3c058000, 0x34420008, 0xa0620005, 0x8f860000,
+	0x34a50001, 0x8f840008, 0x8cc20074, 0x3c038000, 0x00852025, 0x00431025,
+	0xacc20074, 0xaf440020, 0x90c3007b, 0x9342010a, 0x14620028, 0x3c040800,
+	0x24072000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd,
+	0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030100,
+	0xaf420148, 0x24020046, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000,
+	0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030,
+	0x24630001, 0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018,
+	0x00021600, 0x00031c00, 0x00431025, 0x34424600, 0xafa20010, 0x8f440100,
+	0x0e000fe1, 0x3c070100, 0x3c040800, 0x24824120, 0x0a000d01, 0x8c43001c,
+	0x93420108, 0x30420010, 0x50400050, 0x9343093f, 0x8f860000, 0x90c3007f,
+	0x90c2007e, 0x90c40080, 0x306800ff, 0x00021600, 0x00081c00, 0x00431025,
+	0x00042200, 0x90c3007a, 0x90c5000a, 0x00441025, 0x11050028, 0x00623825,
+	0xa0c8000a, 0x24086000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024,
+	0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030,
+	0x00001821, 0xaf420148, 0x24020052, 0xaf47014c, 0xa3420152, 0x3c021000,
+	0xa7430158, 0xaf480154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030,
+	0x24630001, 0xad230030, 0x93420109, 0x9343010a, 0xafa80014, 0xafa00018,
+	0x00021600, 0x00031c00, 0x00431025, 0x34425200, 0xafa20010, 0x0e000fe1,
+	0x8f440100, 0x0a000cfb, 0x00000000, 0x3c026000, 0x24030100, 0xac43081c,
+	0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x240003cd, 0x16800009,
+	0x3c040800, 0x3c030800, 0x24624120, 0x8c43001c, 0x32500040, 0x2404ffbf,
+	0x00641824, 0x0a000f13, 0xac43001c, 0x8c824120, 0x10400005, 0x3c030800,
+	0x8c620034, 0xac804120, 0x24420001, 0xac620034, 0x9343093f, 0x24020012,
+	0x1462000f, 0x329e0038, 0x17c0000c, 0x3c030800, 0x8f830000, 0x8c62004c,
+	0xac62005c, 0x3c020800, 0x24444120, 0x8c82001c, 0x32500040, 0x2403ffbf,
+	0x00431024, 0x0a000f13, 0xac82001c, 0xac604120, 0x97420908, 0x000211c0,
+	0xaf420024, 0x97420908, 0x3c030080, 0x34630003, 0x000211c0, 0xaf42080c,
+	0xaf43081c, 0x974209ec, 0x8f4309a4, 0xa7820028, 0x3c020800, 0x24444120,
+	0xac830028, 0x93420937, 0x93430934, 0x00021080, 0x00621821, 0xa4830014,
+	0x934209d8, 0x00621821, 0xa4830016, 0x934209d8, 0x93430934, 0x00809821,
+	0x00431021, 0x24420010, 0xa4820012, 0x0000a821, 0x24020006, 0x13c00003,
+	0xae62001c, 0x0a000d82, 0x24120008, 0x8f420958, 0x8f830020, 0x8f84002c,
+	0x00431023, 0x00832023, 0x04800003, 0xae620004, 0x04410003, 0x0082102b,
+	0x0a000d4e, 0xae600004, 0x54400001, 0xae640004, 0x8ee20000, 0x0040f809,
+	0x00000000, 0x00409021, 0x32420001, 0x5440001e, 0x8ee20004, 0x8e630008,
+	0x1060002b, 0x3c02c000, 0x00621025, 0xaf420e00, 0x8f420000, 0x30420008,
+	0x1040fffd, 0x00000000, 0x97420e08, 0xa7820010, 0x8f430e04, 0x8e620008,
+	0xaf830004, 0x8f840004, 0x0044102b, 0x1040000b, 0x24150001, 0x24020100,
+	0x3c016000, 0xac22081c, 0x3c020001, 0x3c016000, 0xac22081c, 0x0000000d,
+	0x00000000, 0x24000449, 0x24150001, 0x8ee20004, 0x0040f809, 0x00000000,
+	0x02429025, 0x32420002, 0x5040001d, 0x8f470940, 0x12a00006, 0x8ec2414c,
+	0x8f830000, 0xac6200a8, 0x8f840000, 0x8e620030, 0xac8200ac, 0x32420004,
+	0x50400013, 0x8f470940, 0x3c020800, 0x3283007d, 0x106000fe, 0x245741b0,
+	0x32820001, 0x50400006, 0x36520002, 0x8f830030, 0x8f420940, 0x106200f7,
+	0x00000000, 0x36520002, 0x24020008, 0xa660000c, 0xa662000e, 0xae600008,
+	0xa2600020, 0x8f470940, 0x3c030800, 0x24684120, 0x8d020028, 0x8d050008,
+	0x9504000c, 0x9506000a, 0x95030022, 0x00451021, 0x00862021, 0x00641821,
+	0xaf870030, 0xad020028, 0x32820030, 0x10400006, 0xa5030010, 0x91020020,
+	0x32910040, 0x34420004, 0x0a000dd4, 0xa1020020, 0x93420923, 0x30420040,
+	0x10400029, 0x32910040, 0x8f830000, 0x8f840020, 0x8c620084, 0x00441023,
+	0x0442000a, 0x3c039000, 0x95020010, 0x8c630084, 0x00821021, 0x00621823,
+	0x1c600004, 0x3c039000, 0x91020020, 0x34420001, 0xa1020020, 0x34630001,
+	0x8f820008, 0x32910040, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020,
+	0x00441024, 0x1440fffd, 0x00000000, 0x8f840000, 0x9083003f, 0x2402000a,
+	0x10620005, 0x2402000c, 0x9083003f, 0x24020008, 0x14620002, 0x24020014,
+	0xa082003f, 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020,
+	0x3c040800, 0x24904120, 0x9602000c, 0x96030016, 0x9604000e, 0x00431021,
+	0x00442021, 0x24840002, 0x3084ffff, 0x0e000a55, 0xa6020018, 0x8f850018,
+	0x00a01821, 0xa2030021, 0x8ee60008, 0x00402021, 0x24a50001, 0xaf850018,
+	0x00c0f809, 0x00000000, 0x00402021, 0x0e000b12, 0x02202821, 0x8ee3000c,
+	0x0060f809, 0x00402021, 0x96040018, 0x9602000e, 0x00822021, 0x24840002,
+	0x0e000a6b, 0x3084ffff, 0x3c030800, 0x8c624120, 0x8e030008, 0x3c040800,
+	0x00431023, 0x14400012, 0xac824120, 0x54600006, 0x8e02001c, 0x3243004a,
+	0x24020002, 0x14620005, 0x00000000, 0x8e02001c, 0x34420040, 0x0a000e0b,
+	0xae02001c, 0x52a00006, 0x36520002, 0x8e02002c, 0xaf420e10, 0x8e030030,
+	0xaf430e18, 0x36520002, 0x52a00008, 0x96670010, 0x8f830000, 0x8f420e10,
+	0xac6200a8, 0x8f840000, 0x8f420e18, 0xac8200ac, 0x96670010, 0x92680020,
+	0x24020040, 0xaf420814, 0x8f830020, 0x8f82001c, 0x00671821, 0x00621023,
+	0xaf830020, 0x58400005, 0x8f42095c, 0x8f820000, 0xaf83001c, 0xac430054,
+	0x8f42095c, 0x31030008, 0xaf82002c, 0x1060001a, 0x00000000, 0x8f840000,
+	0x90820120, 0x90830121, 0x304600ff, 0x00c31823, 0x30630007, 0x24020007,
+	0x1062000e, 0x00000000, 0x90820122, 0x304200fe, 0xa0820122, 0x8f850000,
+	0x00061880, 0x8f840020, 0x24a20100, 0x00431021, 0x24c30001, 0x30630007,
+	0xac440000, 0x0a000e40, 0xa0a30120, 0x90820122, 0x34420001, 0xa0820122,
+	0x14e00003, 0x31020001, 0x10400031, 0x32510002, 0x8f820000, 0x8c43000c,
+	0x30630001, 0x1060002c, 0x32510002, 0x3c029000, 0x8f830008, 0x34420001,
+	0x3c048000, 0x00621825, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd,
+	0x00000000, 0x8f870000, 0x8ce2000c, 0x30420001, 0x10400018, 0x00000000,
+	0x94e2006a, 0x00022880, 0x50a00001, 0x24050001, 0x94e30068, 0x90e40081,
+	0x3c020800, 0x8c460024, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001,
+	0x00a03021, 0x3c020800, 0x8c440028, 0x00c4182b, 0x54600001, 0x00c02021,
+	0x8f430074, 0x2402fffe, 0x00822824, 0x00a31821, 0xace3000c, 0x8f830008,
+	0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x8f830020, 0x3c020800,
+	0x24504120, 0xae030024, 0x8ee20010, 0x0040f809, 0x00000000, 0x12a00005,
+	0x00000000, 0x8f420e10, 0xae02002c, 0x8f430e18, 0xae030030, 0x1220feba,
+	0x0000a821, 0x8f870024, 0x97860028, 0x8f830000, 0x8f820030, 0x8f840020,
+	0x8f85001c, 0x32500040, 0xa4e6002c, 0xac620044, 0x32420008, 0xac640050,
+	0xac650054, 0x1040007a, 0x32820020, 0x10400027, 0x32910010, 0x24072000,
+	0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec2414c,
+	0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030400, 0xaf420148,
+	0x24020041, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000, 0xa7430158,
+	0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, 0x24630001,
+	0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018, 0x00021600,
+	0x00031c00, 0x00431025, 0x34424100, 0xafa20010, 0x8f440100, 0x0e000fe1,
+	0x3c070400, 0x12200028, 0x24072000, 0x3c090800, 0x3c038000, 0x8f420178,
+	0x00431024, 0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144,
+	0x8c820030, 0x3c030300, 0xaf420148, 0x2402004e, 0xaf43014c, 0x00001821,
+	0xa3420152, 0x3c021000, 0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c,
+	0x8d230030, 0x8c860030, 0x24630001, 0xad230030, 0x93420109, 0x9343010a,
+	0xafa70014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025, 0x34424e00,
+	0xafa20010, 0x8f440100, 0x0e000fe1, 0x3c070300, 0x0a000f0b, 0x8fa30024,
+	0x32820008, 0x10400026, 0x3c090800, 0x24072000, 0x3c038000, 0x8f420178,
+	0x00431024, 0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144,
+	0x8c820030, 0x3c030200, 0xaf420148, 0x2402004b, 0xaf43014c, 0x00001821,
+	0xa3420152, 0x3c021000, 0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c,
+	0x8d230030, 0x8c860030, 0x24630001, 0xad230030, 0x93420109, 0x9343010a,
+	0xafa70014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025, 0x34424b00,
+	0xafa20010, 0x8f440100, 0x0e000fe1, 0x3c070200, 0x8fa30024, 0x14600004,
+	0x8fa40020, 0x32420010, 0x10400004, 0x00000000, 0x8c820004, 0x0040f809,
+	0x00000000, 0x12000006, 0x8fa30020, 0x8c620008, 0x0040f809, 0x00000000,
+	0x0a000f4d, 0x8fbf004c, 0x3c030800, 0x8c62413c, 0x30420040, 0x1440002f,
+	0x8fbf004c, 0x24040040, 0x8f910020, 0x3c038000, 0x8f420178, 0x00431024,
+	0x1440fffd, 0x8ec2414c, 0x26d0414c, 0x2610ffd4, 0xaf420144, 0x8e020030,
+	0x00001821, 0xaf420148, 0x24020049, 0xaf51014c, 0xa3420152, 0x3c021000,
+	0xa7430158, 0xaf440154, 0xaf420178, 0x8ec5414c, 0x8e060030, 0x93420109,
+	0x9343010a, 0xafa40014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025,
+	0x34424900, 0xafa20010, 0x8f440100, 0x0e000fe1, 0x02203821, 0x8f830000,
+	0x8e020030, 0x8c64017c, 0x02221023, 0x00441023, 0x2c420002, 0x14400005,
+	0x8fbf004c, 0x0000000d, 0x00000000, 0x240000ca, 0x8fbf004c, 0x8fbe0048,
+	0x8fb70044, 0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034, 0x8fb20030,
+	0x8fb1002c, 0x8fb00028, 0x03e00008, 0x27bd0050, 0x03e00008, 0x00001021,
+	0x3c030800, 0x24654120, 0x8ca40004, 0x8c634120, 0x0064102b, 0x54400001,
+	0x00602021, 0x9743093c, 0x0083102b, 0x54400001, 0x00801821, 0x00001021,
+	0xaca30008, 0x03e00008, 0xa4a00022, 0x8f850004, 0x97840010, 0x3c030800,
+	0x24634120, 0x24020008, 0xa462000e, 0x8f820004, 0xa460000c, 0x000420c2,
+	0x30840008, 0x2c420001, 0x00021023, 0x30420006, 0xac650008, 0x03e00008,
+	0xa0640020, 0x3c020800, 0x24424120, 0x90450021, 0x94430018, 0x3c021100,
+	0xac800004, 0x00052c00, 0x24630002, 0x00621825, 0x00a32825, 0x24820008,
+	0x03e00008, 0xac850000, 0x0000000d, 0x00000000, 0x2400016f, 0x03e00008,
+	0x00000000, 0x0000000d, 0x00000000, 0x2400017b, 0x03e00008, 0x00000000,
+	0x03e00008, 0x00000000, 0x3c020800, 0x24424120, 0xac400008, 0xa4400022,
+	0x03e00008, 0x24020001, 0x3c020800, 0x24424120, 0x24030008, 0xac400008,
+	0xa440000c, 0xa443000e, 0xa0400020, 0x03e00008, 0x24020004, 0x03e00008,
+	0x00001021, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004,
+	0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a000fb2,
+	0x00a01021, 0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff,
+	0x03e00008, 0x00000000, 0x3c0a0800, 0x8d490068, 0x3c050800, 0x24a51090,
+	0x00093140, 0x00c51021, 0xac440000, 0x8f440e04, 0x00a61021, 0xac440004,
+	0x97430e08, 0x97420e0c, 0x00a62021, 0x00031c00, 0x00431025, 0xac820008,
+	0x8f430e10, 0x00801021, 0xac43000c, 0x8f440e14, 0xac440010, 0x8f430e18,
+	0x3c0800ff, 0xac430014, 0x8f470e1c, 0x3508ffff, 0x25290001, 0xac470018,
+	0x3c070800, 0x8ce3006c, 0x9344010a, 0x3c026000, 0x24630001, 0xace3006c,
+	0x8c434448, 0x3129007f, 0x00a62821, 0xad490068, 0x00042600, 0x00681824,
+	0x00832025, 0x03e00008, 0xaca4001c, 0x8fac0010, 0x8fad0014, 0x8fae0018,
+	0x3c0b0800, 0x8d6a0060, 0x3c080800, 0x25080078, 0x000a4940, 0x01281021,
+	0x01091821, 0xac440000, 0x00601021, 0xac650004, 0xac460008, 0xac67000c,
+	0xac4c0010, 0xac6d0014, 0x3c036000, 0xac4e0018, 0x8c654448, 0x3c040800,
+	0x8c820064, 0x254a0001, 0x314a007f, 0x01094021, 0xad6a0060, 0x24420001,
+	0xac820064, 0x03e00008, 0xad05001c, 0x00000000 };
+
+static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x00000000 };
+static u32 bnx2_TXP_b06FwBss[(0x194/4) + 1] = { 0x00000000 };
+static u32 bnx2_TXP_b06FwSbss[(0x34/4) + 1] = { 0x00000000 };
+
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2175,7 +2175,7 @@ out:
  * received frames (loopback). Since only the payload is given to this
  * function, it check for loopback.
  */
-void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
+static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
 {
 	struct port *port;
 
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -290,7 +290,6 @@ void bond_3ad_initialize(struct bonding 
 int  bond_3ad_bind_slave(struct slave *slave);
 void bond_3ad_unbind_slave(struct slave *slave);
 void bond_3ad_state_machine_handler(struct bonding *bond);
-void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length);
 void bond_3ad_adapter_speed_changed(struct slave *slave);
 void bond_3ad_adapter_duplex_changed(struct slave *slave);
 void bond_3ad_handle_link_change(struct slave *slave, char link);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -54,6 +54,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_bonding.h>
 #include <linux/if_vlan.h>
+#include <linux/in.h>
 #include <net/ipx.h>
 #include <net/arp.h>
 #include <asm/byteorder.h>
@@ -275,7 +276,7 @@ static struct slave *tlb_get_least_loade
 }
 
 /* Caller must hold bond lock for read */
-struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len)
+static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct tlb_client_info *hash_table;
@@ -627,7 +628,7 @@ static void rlb_req_update_subnet_client
 }
 
 /* Caller must hold both bond and ptr locks for read */
-struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
+static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
@@ -954,9 +955,9 @@ static int alb_set_slave_mac_addr(struct
 	/* each slave will receive packets destined to a different mac */
 	memcpy(s_addr.sa_data, addr, dev->addr_len);
 	s_addr.sa_family = dev->type;
-	if (dev->set_mac_address(dev, &s_addr)) {
+	if (dev_set_mac_address(dev, &s_addr)) {
 		printk(KERN_ERR DRV_NAME
-		       ": Error: dev->set_mac_address of dev %s failed! ALB "
+		       ": Error: dev_set_mac_address of dev %s failed! ALB "
 		       "mode requires that the base driver support setting "
 		       "the hw address also when the network device's "
 		       "interface is open\n",
@@ -1209,7 +1210,7 @@ static int alb_set_mac_address(struct bo
 		/* save net_device's current hw address */
 		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
 
-		res = slave->dev->set_mac_address(slave->dev, addr);
+		res = dev_set_mac_address(slave->dev, addr);
 
 		/* restore net_device's hw address */
 		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
@@ -1229,7 +1230,7 @@ unwind:
 	stop_at = slave;
 	bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
 		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
-		slave->dev->set_mac_address(slave->dev, &sa);
+		dev_set_mac_address(slave->dev, &sa);
 		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
 	}
 
@@ -1300,7 +1301,8 @@ int bond_alb_xmit(struct sk_buff *skb, s
 	switch (ntohs(skb->protocol)) {
 	case ETH_P_IP:
 		if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) ||
-		    (skb->nh.iph->daddr == ip_bcast)) {
+		    (skb->nh.iph->daddr == ip_bcast) ||
+		    (skb->nh.iph->protocol == IPPROTO_IGMP)) {
 			do_tx_balance = 0;
 			break;
 		}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -793,29 +793,20 @@ struct vlan_entry *bond_next_vlan(struct
  * @skb: hw accel VLAN tagged skb to transmit
  * @slave_dev: slave that is supposed to xmit this skbuff
  * 
- * When the bond gets an skb to tarnsmit that is
+ * When the bond gets an skb to transmit that is
  * already hardware accelerated VLAN tagged, and it
  * needs to relay this skb to a slave that is not
  * hw accel capable, the skb needs to be "unaccelerated",
  * i.e. strip the hwaccel tag and re-insert it as part
  * of the payload.
- * 
- * Assumption - once a VLAN device is created over the bond device, all
- * packets are going to be hardware accelerated VLAN tagged since the IP
- * binding is done over the VLAN device
  */
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev)
 {
 	unsigned short vlan_id;
-	int res;
 
 	if (!list_empty(&bond->vlan_list) &&
-	    !(slave_dev->features & NETIF_F_HW_VLAN_TX)) {
-		res = vlan_get_tag(skb, &vlan_id);
-		if (res) {
-			return -EINVAL;
-		}
-
+	    !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
+	    vlan_get_tag(skb, &vlan_id) == 0) {
 		skb->dev = slave_dev;
 		skb = vlan_put_tag(skb, vlan_id);
 		if (!skb) {
@@ -1719,7 +1710,7 @@ static int bond_enslave(struct net_devic
 		 */
 		memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
 		addr.sa_family = slave_dev->type;
-		res = slave_dev->set_mac_address(slave_dev, &addr);
+		res = dev_set_mac_address(slave_dev, &addr);
 		if (res) {
 			dprintk("Error %d calling set_mac_address\n", res);
 			goto err_free;
@@ -1849,8 +1840,8 @@ static int bond_enslave(struct net_devic
 	if (bond_update_speed_duplex(new_slave) &&
 	    (new_slave->link != BOND_LINK_DOWN)) {
 		printk(KERN_WARNING DRV_NAME
-		       ": Warning: failed to get speed/duplex from %s, speed "
-		       "forced to 100Mbps, duplex forced to Full.\n",
+		       ": Warning: failed to get speed and duplex from %s, "
+		       "assumed to be 100Mb/sec and Full.\n",
 		       new_slave->dev->name);
 
 		if (bond->params.mode == BOND_MODE_8023AD) {
@@ -1991,7 +1982,7 @@ err_close:
 err_restore_mac:
 	memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
 	addr.sa_family = slave_dev->type;
-	slave_dev->set_mac_address(slave_dev, &addr);
+	dev_set_mac_address(slave_dev, &addr);
 
 err_free:
 	kfree(new_slave);
@@ -2171,7 +2162,7 @@ static int bond_release(struct net_devic
 		/* restore original ("permanent") mac address */
 		memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
 		addr.sa_family = slave_dev->type;
-		slave_dev->set_mac_address(slave_dev, &addr);
+		dev_set_mac_address(slave_dev, &addr);
 	}
 
 	/* restore the original state of the
@@ -2262,7 +2253,7 @@ static int bond_release_all(struct net_d
 			/* restore original ("permanent") mac address*/
 			memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
 			addr.sa_family = slave_dev->type;
-			slave_dev->set_mac_address(slave_dev, &addr);
+			dev_set_mac_address(slave_dev, &addr);
 		}
 
 		/* restore the original state of the IFF_NOARP flag that might have
@@ -3046,7 +3037,7 @@ static void bond_activebackup_arp_mon(st
 			bond_set_slave_inactive_flags(bond->current_arp_slave);
 
 			/* search for next candidate */
-			bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) {
+			bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
 				if (IS_UP(slave->dev)) {
 					slave->link = BOND_LINK_BACK;
 					bond_set_slave_active_flags(slave);
@@ -3898,12 +3889,7 @@ static int bond_change_mtu(struct net_de
 	bond_for_each_slave(bond, slave, i) {
 		dprintk("s %p s->p %p c_m %p\n", slave,
 			slave->prev, slave->dev->change_mtu);
-		if (slave->dev->change_mtu) {
-			res = slave->dev->change_mtu(slave->dev, new_mtu);
-		} else {
-			slave->dev->mtu = new_mtu;
-			res = 0;
-		}
+		res = dev_set_mtu(slave->dev, new_mtu);
 
 		if (res) {
 			/* If we failed to set the slave's mtu to the new value
@@ -3929,14 +3915,10 @@ unwind:
 	bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
 		int tmp_res;
 
-		if (slave->dev->change_mtu) {
-			tmp_res = slave->dev->change_mtu(slave->dev, bond_dev->mtu);
-			if (tmp_res) {
-				dprintk("unwind err %d dev %s\n", tmp_res,
-					slave->dev->name);
-			}
-		} else {
-			slave->dev->mtu = bond_dev->mtu;
+		tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
+		if (tmp_res) {
+			dprintk("unwind err %d dev %s\n", tmp_res,
+				slave->dev->name);
 		}
 	}
 
@@ -3988,7 +3970,7 @@ static int bond_set_mac_address(struct n
 			goto unwind;
 		}
 
-		res = slave->dev->set_mac_address(slave->dev, addr);
+		res = dev_set_mac_address(slave->dev, addr);
 		if (res) {
 			/* TODO: consider downing the slave
 			 * and retry ?
@@ -4014,7 +3996,7 @@ unwind:
 	bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
 		int tmp_res;
 
-		tmp_res = slave->dev->set_mac_address(slave->dev, &tmp_sa);
+		tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
 		if (tmp_res) {
 			dprintk("unwind err %d dev %s\n", tmp_res,
 				slave->dev->name);
@@ -4306,6 +4288,10 @@ static int __init bond_init(struct net_d
 	 */
 	bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
 
+	/* don't acquire bond device's xmit_lock when 
+	 * transmitting */
+	bond_dev->features |= NETIF_F_LLTX;
+
 	/* By default, we declare the bond to be fully
 	 * VLAN hardware accelerated capable. Special
 	 * care is taken in the various xmit functions
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -136,6 +136,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -909,8 +910,7 @@ void  __init reset_chip(struct net_devic
 	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
 
 	/* wait 30 ms */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(30*HZ/1000);
+	msleep(30);
 
 #ifndef CONFIG_ARCH_IXDP2X01
 	if (lp->chip_type != CS8900) {
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -420,7 +420,7 @@ static int __devinit dfx_init_one_pci_or
 	}
 
 	if (pdev != NULL)
-		print_name = pdev->slot_name;
+		print_name = pci_name(pdev);
 
 	dev = alloc_fddidev(sizeof(*bp));
 	if (!dev) {
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -342,14 +342,15 @@ static char depca_string[] = "depca";
 static int depca_device_remove (struct device *device);
 
 #ifdef CONFIG_EISA
-struct eisa_device_id depca_eisa_ids[] = {
+static struct eisa_device_id depca_eisa_ids[] = {
 	{ "DEC4220", de422 },
 	{ "" }
 };
+MODULE_DEVICE_TABLE(eisa, depca_eisa_ids);
 
 static int depca_eisa_probe  (struct device *device);
 
-struct eisa_driver depca_eisa_driver = {
+static struct eisa_driver depca_eisa_driver = {
 	.id_table = depca_eisa_ids,
 	.driver   = {
 		.name    = depca_string,
@@ -1826,7 +1827,7 @@ static int load_packet(struct net_device
 
 		/* set up the buffer descriptors */
 		len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-		for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+		for (i = entry; i != end; i = (i+1) & 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 */
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -454,7 +454,7 @@ do_plx_dma(
  *	up some state variables to let the host CPU continue doing
  *	other things until a DMA completion interrupt comes along.
  */
-void
+static void
 dgrs_rcv_frame(
 	struct net_device	*dev0,
 	DGRS_PRIV	*priv0,
@@ -1150,7 +1150,7 @@ dgrs_download(struct net_device *dev0)
 /*
  *	Probe (init) a board
  */
-int __init 
+static int __init 
 dgrs_probe1(struct net_device *dev)
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
@@ -1228,7 +1228,7 @@ err_out:
        	return rc;
 }
 
-int __init 
+static int __init 
 dgrs_initclone(struct net_device *dev)
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1199,7 +1199,7 @@ set_multicast (struct net_device *dev)
 static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct netdev_private *np = netdev_priv(dev);
-	strcpy(info->driver, "DL2K");
+	strcpy(info->driver, "dl2k");
 	strcpy(info->version, DRV_VERSION);
 	strcpy(info->bus_info, pci_name(np->pdev));
 }	
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -155,9 +155,9 @@
 
 #define DRV_NAME		"e100"
 #define DRV_EXT		"-NAPI"
-#define DRV_VERSION		"3.3.6-k2"DRV_EXT
+#define DRV_VERSION		"3.4.8-k2"DRV_EXT
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
-#define DRV_COPYRIGHT		"Copyright(c) 1999-2004 Intel Corporation"
+#define DRV_COPYRIGHT		"Copyright(c) 1999-2005 Intel Corporation"
 #define PFX			DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD	(2 * HZ)
@@ -210,11 +210,17 @@ static struct pci_device_id e100_id_tabl
 	INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
 	INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
 	INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1091, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1092, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
 	INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
 	INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
 	INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
 	INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
 	INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, e100_id_table);
@@ -269,6 +275,12 @@ enum scb_status {
 	rus_mask         = 0x3C,
 };
 
+enum ru_state  {
+	RU_SUSPENDED = 0,
+	RU_RUNNING	 = 1,
+	RU_UNINITIALIZED = -1,
+};
+
 enum scb_stat_ack {
 	stat_ack_not_ours    = 0x00,
 	stat_ack_sw_gen      = 0x04,
@@ -510,7 +522,7 @@ struct nic {
 	struct rx *rx_to_use;
 	struct rx *rx_to_clean;
 	struct rfd blank_rfd;
-	int ru_running;
+	enum ru_state ru_running;
 
 	spinlock_t cb_lock			____cacheline_aligned;
 	spinlock_t cmd_lock;
@@ -539,6 +551,7 @@ struct nic {
 	struct timer_list watchdog;
 	struct timer_list blink_timer;
 	struct mii_if_info mii;
+	struct work_struct tx_timeout_task;
 	enum loopback loopback;
 
 	struct mem *mem;
@@ -770,7 +783,7 @@ static int e100_eeprom_save(struct nic *
 	return 0;
 }
 
-#define E100_WAIT_SCB_TIMEOUT 40
+#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
 static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 {
 	unsigned long flags;
@@ -840,6 +853,10 @@ static inline int e100_exec_cb(struct ni
 			 * because the controller is too busy, so
 			 * let's just queue the command and try again
 			 * when another command is scheduled. */
+			if(err == -ENOSPC) {
+				//request a reset
+				schedule_work(&nic->tx_timeout_task);
+			}
 			break;
 		} else {
 			nic->cuc_cmd = cuc_resume;
@@ -884,7 +901,7 @@ static void mdio_write(struct net_device
 
 static void e100_get_defaults(struct nic *nic)
 {
-	struct param_range rfds = { .min = 64, .max = 256, .count = 64 };
+	struct param_range rfds = { .min = 16, .max = 256, .count = 64 };
 	struct param_range cbs  = { .min = 64, .max = 256, .count = 64 };
 
 	pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
@@ -899,8 +916,9 @@ static void e100_get_defaults(struct nic
 	/* Quadwords to DMA into FIFO before starting frame transmit */
 	nic->tx_threshold = 0xE0;
 
-	nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf |
-		((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0));
+	/* no interrupt for every tx completion, delay = 256us if not 557*/
+	nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
+		((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
 	/* Template for a freshly allocated RFD */
 	nic->blank_rfd.command = cpu_to_le16(cb_el);
@@ -964,7 +982,8 @@ static void e100_configure(struct nic *n
 	if(nic->flags & multicast_all)
 		config->multicast_all = 0x1;		/* 1=accept, 0=no */
 
-	if(!(nic->flags & wol_magic))
+	/* disable WoL when up */
+	if(netif_running(nic->netdev) || !(nic->flags & wol_magic))
 		config->magic_packet_disable = 0x1;	/* 1=off, 0=on */
 
 	if(nic->mac >= mac_82558_D101_A4) {
@@ -1203,7 +1222,9 @@ static void e100_update_stats(struct nic
 		}
 	}
 
-	e100_exec_cmd(nic, cuc_dump_reset, 0);
+	
+	if(e100_exec_cmd(nic, cuc_dump_reset, 0))
+		DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
 }
 
 static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
@@ -1279,12 +1300,15 @@ static inline void e100_xmit_prepare(str
 	struct sk_buff *skb)
 {
 	cb->command = nic->tx_command;
+	/* interrupt every 16 packets regardless of delay */
+	if((nic->cbs_avail & ~15) == nic->cbs_avail) cb->command |= cb_i;
 	cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
 	cb->u.tcb.tcb_byte_count = 0;
 	cb->u.tcb.threshold = nic->tx_threshold;
 	cb->u.tcb.tbd_count = 1;
 	cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
 		skb->data, skb->len, PCI_DMA_TODEVICE));
+	// check for mapping failure?
 	cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
 }
 
@@ -1297,7 +1321,8 @@ static int e100_xmit_frame(struct sk_buf
 		/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
 		   Issue a NOP command followed by a 1us delay before
 		   issuing the Tx command. */
-		e100_exec_cmd(nic, cuc_nop, 0);
+		if(e100_exec_cmd(nic, cuc_nop, 0))
+			DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
 		udelay(1);
 	}
 
@@ -1415,12 +1440,18 @@ static int e100_alloc_cbs(struct nic *ni
 	return 0;
 }
 
-static inline void e100_start_receiver(struct nic *nic)
+static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
 {
+	if(!nic->rxs) return;
+	if(RU_SUSPENDED != nic->ru_running) return;
+
+	/* handle init time starts */
+	if(!rx) rx = nic->rxs;
+
 	/* (Re)start RU if suspended or idle and RFA is non-NULL */
-	if(!nic->ru_running && nic->rx_to_clean->skb) {
-		e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
-		nic->ru_running = 1;
+	if(rx->skb) {
+		e100_exec_cmd(nic, ruc_start, rx->dma_addr);
+		nic->ru_running = RU_RUNNING;
 	}
 }
 
@@ -1437,6 +1468,13 @@ static inline int e100_rx_alloc_skb(stru
 	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
 		RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
 
+	if(pci_dma_mapping_error(rx->dma_addr)) {
+		dev_kfree_skb_any(rx->skb);
+		rx->skb = 0;
+		rx->dma_addr = 0;
+		return -ENOMEM;
+	}
+
 	/* Link the RFD to end of RFA by linking previous RFD to
 	 * this one, and clearing EL bit of previous.  */
 	if(rx->prev->skb) {
@@ -1471,7 +1509,7 @@ static inline int e100_rx_indicate(struc
 
 	/* If data isn't ready, nothing to indicate */
 	if(unlikely(!(rfd_status & cb_complete)))
-		return -EAGAIN;
+		return -ENODATA;
 
 	/* Get actual data size */
 	actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
@@ -1482,6 +1520,10 @@ static inline int e100_rx_indicate(struc
 	pci_unmap_single(nic->pdev, rx->dma_addr,
 		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
+	/* this allows for a fast restart without re-enabling interrupts */
+	if(le16_to_cpu(rfd->command) & cb_el)
+		nic->ru_running = RU_SUSPENDED;
+
 	/* Pull off the RFD and put the actual data (minus eth hdr) */
 	skb_reserve(skb, sizeof(struct rfd));
 	skb_put(skb, actual_size);
@@ -1514,20 +1556,45 @@ static inline void e100_rx_clean(struct 
 	unsigned int work_to_do)
 {
 	struct rx *rx;
+	int restart_required = 0;
+	struct rx *rx_to_start = NULL;
+
+	/* are we already rnr? then pay attention!!! this ensures that
+	 * the state machine progression never allows a start with a 
+	 * partially cleaned list, avoiding a race between hardware
+	 * and rx_to_clean when in NAPI mode */
+	if(RU_SUSPENDED == nic->ru_running)
+		restart_required = 1;
 
 	/* Indicate newly arrived packets */
 	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-		if(e100_rx_indicate(nic, rx, work_done, work_to_do))
+		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+		if(-EAGAIN == err) {
+			/* hit quota so have more work to do, restart once
+			 * cleanup is complete */
+			restart_required = 0;
+			break;
+		} else if(-ENODATA == err)
 			break; /* No more to clean */
 	}
 
+	/* save our starting point as the place we'll restart the receiver */
+	if(restart_required)
+		rx_to_start = nic->rx_to_clean;
+
 	/* Alloc new skbs to refill list */
 	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
 		if(unlikely(e100_rx_alloc_skb(nic, rx)))
 			break; /* Better luck next time (see watchdog) */
 	}
 
-	e100_start_receiver(nic);
+	if(restart_required) {
+		// ack the rnr?
+		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+		e100_start_receiver(nic, rx_to_start);
+		if(work_done)
+			(*work_done)++;
+	}
 }
 
 static void e100_rx_clean_list(struct nic *nic)
@@ -1535,6 +1602,8 @@ static void e100_rx_clean_list(struct ni
 	struct rx *rx;
 	unsigned int i, count = nic->params.rfds.count;
 
+	nic->ru_running = RU_UNINITIALIZED;
+
 	if(nic->rxs) {
 		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
 			if(rx->skb) {
@@ -1548,7 +1617,6 @@ static void e100_rx_clean_list(struct ni
 	}
 
 	nic->rx_to_use = nic->rx_to_clean = NULL;
-	nic->ru_running = 0;
 }
 
 static int e100_rx_alloc_list(struct nic *nic)
@@ -1557,6 +1625,7 @@ static int e100_rx_alloc_list(struct nic
 	unsigned int i, count = nic->params.rfds.count;
 
 	nic->rx_to_use = nic->rx_to_clean = NULL;
+	nic->ru_running = RU_UNINITIALIZED;
 
 	if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
 		return -ENOMEM;
@@ -1572,6 +1641,7 @@ static int e100_rx_alloc_list(struct nic
 	}
 
 	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
+	nic->ru_running = RU_SUSPENDED;
 
 	return 0;
 }
@@ -1593,7 +1663,7 @@ static irqreturn_t e100_intr(int irq, vo
 
 	/* We hit Receive No Resource (RNR); restart RU after cleaning */
 	if(stat_ack & stat_ack_rnr)
-		nic->ru_running = 0;
+		nic->ru_running = RU_SUSPENDED;
 
 	e100_disable_irq(nic);
 	netif_rx_schedule(netdev);
@@ -1663,6 +1733,7 @@ static int e100_change_mtu(struct net_de
 	return 0;
 }
 
+#ifdef CONFIG_PM
 static int e100_asf(struct nic *nic)
 {
 	/* ASF can be enabled from eeprom */
@@ -1671,6 +1742,7 @@ static int e100_asf(struct nic *nic)
 	   !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
 	   ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
 }
+#endif
 
 static int e100_up(struct nic *nic)
 {
@@ -1683,13 +1755,16 @@ static int e100_up(struct nic *nic)
 	if((err = e100_hw_init(nic)))
 		goto err_clean_cbs;
 	e100_set_multicast_list(nic->netdev);
-	e100_start_receiver(nic);
+	e100_start_receiver(nic, 0);
 	mod_timer(&nic->watchdog, jiffies);
 	if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
 		nic->netdev->name, nic->netdev)))
 		goto err_no_irq;
-	e100_enable_irq(nic);
 	netif_wake_queue(nic->netdev);
+	netif_poll_enable(nic->netdev);
+	/* enable ints _after_ enabling poll, preventing a race between
+	 * disable ints+schedule */
+	e100_enable_irq(nic);
 	return 0;
 
 err_no_irq:
@@ -1703,11 +1778,13 @@ err_rx_clean_list:
 
 static void e100_down(struct nic *nic)
 {
+	/* wait here for poll to complete */
+	netif_poll_disable(nic->netdev);
+	netif_stop_queue(nic->netdev);
 	e100_hw_reset(nic);
 	free_irq(nic->pdev->irq, nic->netdev);
 	del_timer_sync(&nic->watchdog);
 	netif_carrier_off(nic->netdev);
-	netif_stop_queue(nic->netdev);
 	e100_clean_cbs(nic);
 	e100_rx_clean_list(nic);
 }
@@ -1716,6 +1793,15 @@ static void e100_tx_timeout(struct net_d
 {
 	struct nic *nic = netdev_priv(netdev);
 
+	/* Reset outside of interrupt context, to avoid request_irq 
+	 * in interrupt context */
+	schedule_work(&nic->tx_timeout_task);
+}
+
+static void e100_tx_timeout_task(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+
 	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
 		readb(&nic->csr->scb.status));
 	e100_down(netdev_priv(netdev));
@@ -1749,7 +1835,7 @@ static int e100_loopback_test(struct nic
 		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
 			BMCR_LOOPBACK);
 
-	e100_start_receiver(nic);
+	e100_start_receiver(nic, 0);
 
 	if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
 		err = -ENOMEM;
@@ -1869,7 +1955,6 @@ static int e100_set_wol(struct net_devic
 	else
 		nic->flags &= ~wol_magic;
 
-	pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
 	e100_exec_cb(nic, NULL, e100_configure);
 
 	return 0;
@@ -2223,6 +2308,7 @@ static int __devinit e100_probe(struct p
 
 	e100_get_defaults(nic);
 
+	/* locks must be initialized before calling hw_reset */
 	spin_lock_init(&nic->cb_lock);
 	spin_lock_init(&nic->cmd_lock);
 
@@ -2240,6 +2326,9 @@ static int __devinit e100_probe(struct p
 	nic->blink_timer.function = e100_blink_led;
 	nic->blink_timer.data = (unsigned long)nic;
 
+	INIT_WORK(&nic->tx_timeout_task,
+		(void (*)(void *))e100_tx_timeout_task, netdev);
+
 	if((err = e100_alloc(nic))) {
 		DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
 		goto err_out_iounmap;
@@ -2263,7 +2352,8 @@ static int __devinit e100_probe(struct p
 	   (nic->eeprom[eeprom_id] & eeprom_id_wol))
 		nic->flags |= wol_magic;
 
-	pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+	/* ack any pending wake events, disable PME */
+	pci_enable_wake(pdev, 0, 0);
 
 	strcpy(netdev->name, "eth%d");
 	if((err = register_netdev(netdev))) {
@@ -2310,7 +2400,7 @@ static void __devexit e100_remove(struct
 }
 
 #ifdef CONFIG_PM
-static int e100_suspend(struct pci_dev *pdev, u32 state)
+static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct nic *nic = netdev_priv(netdev);
@@ -2321,7 +2411,7 @@ static int e100_suspend(struct pci_dev *
 	netif_device_detach(netdev);
 
 	pci_save_state(pdev);
-	pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic)));
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), nic->flags & (wol_magic | e100_asf(nic)));
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
@@ -2335,7 +2425,10 @@ static int e100_resume(struct pci_dev *p
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
-	e100_hw_init(nic);
+	/* ack any pending wake events, disable PME */
+	pci_enable_wake(pdev, 0, 0);
+	if(e100_hw_init(nic))
+		DPRINTK(HW, ERR, "e100_hw_init failed\n");
 
 	netif_device_attach(netdev);
 	if(netif_running(netdev))
@@ -2345,6 +2438,21 @@ static int e100_resume(struct pci_dev *p
 }
 #endif
 
+
+static void e100_shutdown(struct device *dev)
+{
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+#ifdef CONFIG_PM
+	pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+#else
+	pci_enable_wake(pdev, 0, nic->flags & (wol_magic));
+#endif
+}
+
+
 static struct pci_driver e100_driver = {
 	.name =         DRV_NAME,
 	.id_table =     e100_id_table,
@@ -2354,6 +2462,11 @@ static struct pci_driver e100_driver = {
 	.suspend =      e100_suspend,
 	.resume =       e100_resume,
 #endif
+
+	.driver = {
+		.shutdown = e100_shutdown,
+	}
+
 };
 
 static int __init e100_init_module(void)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -112,6 +112,8 @@ struct e1000_adapter;
 #define E1000_MAX_82544_RXD               4096
 
 /* Supported Rx Buffer Sizes */
+#define E1000_RXBUFFER_128   128    /* Used for packet split */
+#define E1000_RXBUFFER_256   256    /* Used for packet split */
 #define E1000_RXBUFFER_2048  2048
 #define E1000_RXBUFFER_4096  4096
 #define E1000_RXBUFFER_8192  8192
@@ -137,14 +139,19 @@ struct e1000_adapter;
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
-#define AUTO_ALL_MODES       0
-#define E1000_EEPROM_APME    0x0400
+#define AUTO_ALL_MODES            0
+#define E1000_EEPROM_82544_APM    0x0400
+#define E1000_EEPROM_APME         0x0400
 
 #ifndef E1000_MASTER_SLAVE
 /* Switch to override PHY master/slave setting */
 #define E1000_MASTER_SLAVE	e1000_ms_hw_default
 #endif
 
+#define E1000_MNG_VLAN_NONE -1
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1
+
 /* only works for sizes that are powers of 2 */
 #define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
 
@@ -158,6 +165,9 @@ struct e1000_buffer {
 	uint16_t next_to_watch;
 };
 
+struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; };
+struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; };
+
 struct e1000_desc_ring {
 	/* pointer to the descriptor ring memory */
 	void *desc;
@@ -173,12 +183,19 @@ struct e1000_desc_ring {
 	unsigned int next_to_clean;
 	/* array of buffer information structs */
 	struct e1000_buffer *buffer_info;
+	/* arrays of page information for packet split */
+	struct e1000_ps_page *ps_page;
+	struct e1000_ps_page_dma *ps_page_dma;
 };
 
 #define E1000_DESC_UNUSED(R) \
 	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
 	(R)->next_to_clean - (R)->next_to_use - 1)
 
+#define E1000_RX_DESC_PS(R, i)	    \
+	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_RX_DESC_EXT(R, i)	    \
+	(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
 #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)
@@ -191,6 +208,7 @@ struct e1000_adapter {
 	struct timer_list watchdog_timer;
 	struct timer_list phy_info_timer;
 	struct vlan_group *vlgrp;
+    	uint16_t mng_vlan_id;
 	uint32_t bd_number;
 	uint32_t rx_buffer_len;
 	uint32_t part_num;
@@ -202,6 +220,7 @@ struct e1000_adapter {
 	spinlock_t stats_lock;
 	atomic_t irq_sem;
 	struct work_struct tx_timeout_task;
+	struct work_struct watchdog_task;
 	uint8_t fc_autoneg;
 
 	struct timer_list blink_timer;
@@ -209,6 +228,7 @@ struct e1000_adapter {
 
 	/* TX */
 	struct e1000_desc_ring tx_ring;
+	struct e1000_buffer previous_buffer_info;
 	spinlock_t tx_lock;
 	uint32_t txd_cmd;
 	uint32_t tx_int_delay;
@@ -222,16 +242,26 @@ struct e1000_adapter {
 	uint32_t tx_fifo_size;
 	atomic_t tx_fifo_stall;
 	boolean_t pcix_82544;
+	boolean_t detect_tx_hung;
 
 	/* RX */
+#ifdef CONFIG_E1000_NAPI
+	boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done,
+			  int work_to_do);
+#else
+	boolean_t (*clean_rx) (struct e1000_adapter *adapter);
+#endif
+	void (*alloc_rx_buf) (struct e1000_adapter *adapter);
 	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;
+	boolean_t rx_ps;
 	uint32_t gorcl;
 	uint64_t gorcl_old;
+	uint16_t rx_ps_bsize0;
 
 	/* Interrupt Throttle Rate */
 	uint32_t itr;
@@ -253,5 +283,8 @@ struct e1000_adapter {
 
 
 	int msg_enable;
+#ifdef CONFIG_PCI_MSI
+	boolean_t have_msi;
+#endif
 };
 #endif /* _E1000_H_ */
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -69,6 +69,7 @@ static const struct e1000_stats e1000_gs
 	{ "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
 	{ "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
 	{ "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) },
+	{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
 	{ "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
 	{ "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
 	{ "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
@@ -593,7 +594,7 @@ e1000_set_ringparam(struct net_device *n
 	tx_old = adapter->tx_ring;
 	rx_old = adapter->rx_ring;
 
-	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 
+	if((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
 		return -EINVAL;
 
 	if(netif_running(adapter->netdev))
@@ -784,8 +785,8 @@ e1000_intr_test(struct e1000_adapter *ad
 	/* Hook up test interrupt handler just for this test */
  	if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) {
  		shared_int = FALSE;
- 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, 
-			netdev->name, netdev)){
+ 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ,
+			      netdev->name, netdev)){
 		*data = 1;
 		return -1;
 	}
@@ -842,10 +843,8 @@ e1000_intr_test(struct e1000_adapter *ad
 			 * test failed.
 			 */
 			adapter->test_icr = 0;
-			E1000_WRITE_REG(&adapter->hw, IMC, 
-					(~mask & 0x00007FFF));
-			E1000_WRITE_REG(&adapter->hw, ICS, 
-					(~mask & 0x00007FFF));
+			E1000_WRITE_REG(&adapter->hw, IMC, ~mask & 0x00007FFF);
+			E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF);
 			msec_delay(10);
 
 			if(adapter->test_icr) {
@@ -919,7 +918,8 @@ e1000_setup_desc_rings(struct e1000_adap
 
 	/* Setup Tx descriptor ring and Tx buffers */
 
-	txdr->count = 80;
+	if(!txdr->count)
+		txdr->count = E1000_DEFAULT_TXD;   
 
 	size = txdr->count * sizeof(struct e1000_buffer);
 	if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
@@ -974,7 +974,8 @@ e1000_setup_desc_rings(struct e1000_adap
 
 	/* Setup Rx descriptor ring and Rx buffers */
 
-	rxdr->count = 80;
+	if(!rxdr->count)
+		rxdr->count = E1000_DEFAULT_RXD;   
 
 	size = rxdr->count * sizeof(struct e1000_buffer);
 	if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
@@ -1008,7 +1009,7 @@ e1000_setup_desc_rings(struct e1000_adap
 		struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i);
 		struct sk_buff *skb;
 
-		if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, 
+		if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN,
 				GFP_KERNEL))) {
 			ret_val = 6;
 			goto err_nomem;
@@ -1310,31 +1311,63 @@ e1000_run_loopback_test(struct e1000_ada
 	struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
 	struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
 	struct pci_dev *pdev = adapter->pdev;
-	int i;
+	int i, j, k, l, lc, good_cnt, ret_val=0;
+	unsigned long time;
 
 	E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1);
 
-	for(i = 0; i < 64; i++) {
-		e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024);
-		pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma,
-					    txdr->buffer_info[i].length,
-					    PCI_DMA_TODEVICE);
-	}
-	E1000_WRITE_REG(&adapter->hw, TDT, i);
-
-	msec_delay(200);
-
-	i = 0;
-	do {
-		pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[i].dma,
-					    rxdr->buffer_info[i].length,
-					    PCI_DMA_FROMDEVICE);
+	/* Calculate the loop count based on the largest descriptor ring 
+	 * The idea is to wrap the largest ring a number of times using 64
+	 * send/receive pairs during each loop
+	 */
 
-		if (!e1000_check_lbtest_frame(rxdr->buffer_info[i++].skb, 1024))
-			return 0;
-	} while (i < 64);
+	if(rxdr->count <= txdr->count)
+		lc = ((txdr->count / 64) * 2) + 1;
+	else
+		lc = ((rxdr->count / 64) * 2) + 1;
 
-	return 13;
+	k = l = 0;
+	for(j = 0; j <= lc; j++) { /* loop count loop */
+		for(i = 0; i < 64; i++) { /* send the packets */
+			e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 
+					1024);
+			pci_dma_sync_single_for_device(pdev, 
+					txdr->buffer_info[k].dma,
+				    	txdr->buffer_info[k].length,
+				    	PCI_DMA_TODEVICE);
+			if(unlikely(++k == txdr->count)) k = 0;
+		}
+		E1000_WRITE_REG(&adapter->hw, TDT, k);
+		msec_delay(200);
+		time = jiffies; /* set the start time for the receive */
+		good_cnt = 0;
+		do { /* receive the sent packets */
+			pci_dma_sync_single_for_cpu(pdev, 
+					rxdr->buffer_info[l].dma,
+				    	rxdr->buffer_info[l].length,
+				    	PCI_DMA_FROMDEVICE);
+	
+			ret_val = e1000_check_lbtest_frame(
+					rxdr->buffer_info[l].skb,
+				   	1024);
+			if(!ret_val)
+				good_cnt++;
+			if(unlikely(++l == rxdr->count)) l = 0;
+			/* time + 20 msecs (200 msecs on 2.4) is more than 
+			 * enough time to complete the receives, if it's 
+			 * exceeded, break and error off
+			 */
+		} while (good_cnt < 64 && jiffies < (time + 20));
+		if(good_cnt != 64) {
+			ret_val = 13; /* ret_val is the same as mis-compare */
+			break; 
+		}
+		if(jiffies >= (time + 2)) {
+			ret_val = 14; /* error code for time out error */
+			break;
+		}
+	} /* end loop count loop */
+	return ret_val;
 }
 
 static int
@@ -1353,13 +1386,12 @@ static int
 e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	*data = 0;
-
 	if (adapter->hw.media_type == e1000_media_type_internal_serdes) {
 		int i = 0;
 		adapter->hw.serdes_link_down = TRUE;
 
-		/* on some blade server designs link establishment */
-		/* could take as long as 2-3 minutes.              */
+		/* On some blade server designs, link establishment
+		 * could take as long as 2-3 minutes */
 		do {
 			e1000_check_for_link(&adapter->hw);
 			if (adapter->hw.serdes_link_down == FALSE)
@@ -1367,9 +1399,11 @@ e1000_link_test(struct e1000_adapter *ad
 			msec_delay(20);
 		} while (i++ < 3750);
 
-		*data = 1; 
+		*data = 1;
 	} else {
 		e1000_check_for_link(&adapter->hw);
+		if(adapter->hw.autoneg)  /* if auto_neg is set wait for it */
+			msec_delay(4000);
 
 		if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
 			*data = 1;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -63,10 +63,11 @@ static uint16_t e1000_shift_in_ee_bits(s
 static int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
 static void e1000_release_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);
 static int32_t e1000_set_vco_speed(struct e1000_hw *hw);
 static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw);
 static int32_t e1000_set_phy_mode(struct e1000_hw *hw);
+static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer);
+static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length);
 
 /* IGP cable length table */
 static const
@@ -80,6 +81,17 @@ uint16_t e1000_igp_cable_length_table[IG
       100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
       110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
 
+static const
+uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
+    { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
+      22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58,
+      32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74,
+      43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90,
+      57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108,
+      73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124,
+      91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128,
+      108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
+
 
 /******************************************************************************
  * Set the phy type member in the hw struct.
@@ -91,10 +103,14 @@ e1000_set_phy_type(struct e1000_hw *hw)
 {
     DEBUGFUNC("e1000_set_phy_type");
 
+    if(hw->mac_type == e1000_undefined)
+        return -E1000_ERR_PHY_TYPE;
+
     switch(hw->phy_id) {
     case M88E1000_E_PHY_ID:
     case M88E1000_I_PHY_ID:
     case M88E1011_I_PHY_ID:
+    case M88E1111_I_PHY_ID:
         hw->phy_type = e1000_phy_m88;
         break;
     case IGP01E1000_I_PHY_ID:
@@ -128,7 +144,6 @@ e1000_phy_init_script(struct e1000_hw *h
 
     DEBUGFUNC("e1000_phy_init_script");
 
-
     if(hw->phy_init_script) {
         msec_delay(20);
 
@@ -271,6 +286,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
     case E1000_DEV_ID_82546GB_FIBER:
     case E1000_DEV_ID_82546GB_SERDES:
     case E1000_DEV_ID_82546GB_PCIE:
+    case E1000_DEV_ID_82546GB_QUAD_COPPER:
         hw->mac_type = e1000_82546_rev_3;
         break;
     case E1000_DEV_ID_82541EI:
@@ -289,12 +305,19 @@ e1000_set_mac_type(struct e1000_hw *hw)
     case E1000_DEV_ID_82547GI:
         hw->mac_type = e1000_82547_rev_2;
         break;
+    case E1000_DEV_ID_82573E:
+    case E1000_DEV_ID_82573E_IAMT:
+        hw->mac_type = e1000_82573;
+        break;
     default:
         /* Should never have loaded on this device */
         return -E1000_ERR_MAC_TYPE;
     }
 
     switch(hw->mac_type) {
+    case e1000_82573:
+        hw->eeprom_semaphore_present = TRUE;
+        /* fall through */
     case e1000_82541:
     case e1000_82547:
     case e1000_82541_rev_2:
@@ -360,6 +383,9 @@ e1000_reset_hw(struct e1000_hw *hw)
     uint32_t icr;
     uint32_t manc;
     uint32_t led_ctrl;
+    uint32_t timeout;
+    uint32_t extcnf_ctrl;
+    int32_t ret_val;
 
     DEBUGFUNC("e1000_reset_hw");
 
@@ -369,6 +395,15 @@ e1000_reset_hw(struct e1000_hw *hw)
         e1000_pci_clear_mwi(hw);
     }
 
+    if(hw->bus_type == e1000_bus_type_pci_express) {
+        /* Prevent the PCI-E bus from sticking if there is no TLP connection
+         * on the last TLP read/write transaction when MAC is reset.
+         */
+        if(e1000_disable_pciex_master(hw) != E1000_SUCCESS) {
+            DEBUGOUT("PCI-E Master disable polling has failed.\n");
+        }
+    }
+
     /* Clear interrupt mask to stop board from generating interrupts */
     DEBUGOUT("Masking off all interrupts\n");
     E1000_WRITE_REG(hw, IMC, 0xffffffff);
@@ -393,10 +428,32 @@ e1000_reset_hw(struct e1000_hw *hw)
 
     /* Must reset the PHY before resetting the MAC */
     if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
-        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+        E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
         msec_delay(5);
     }
 
+    /* Must acquire the MDIO ownership before MAC reset.
+     * Ownership defaults to firmware after a reset. */
+    if(hw->mac_type == e1000_82573) {
+        timeout = 10;
+
+        extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+        extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+        do {
+            E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+            extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+
+            if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+                break;
+            else
+                extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+            msec_delay(2);
+            timeout--;
+        } while(timeout);
+    }
+
     /* 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-
@@ -450,6 +507,18 @@ e1000_reset_hw(struct e1000_hw *hw)
             /* Wait for EEPROM reload */
             msec_delay(20);
             break;
+        case e1000_82573:
+            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);
+            /* fall through */
+            ret_val = e1000_get_auto_rd_done(hw);
+            if(ret_val)
+                /* We don't want to continue accessing MAC registers. */
+                return ret_val;
+            break;
         default:
             /* Wait for EEPROM reload (it happens automatically) */
             msec_delay(5);
@@ -457,7 +526,7 @@ e1000_reset_hw(struct e1000_hw *hw)
     }
 
     /* Disable HW ARPs on ASF enabled adapters */
-    if(hw->mac_type >= e1000_82540) {
+    if(hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) {
         manc = E1000_READ_REG(hw, MANC);
         manc &= ~(E1000_MANC_ARP_EN);
         E1000_WRITE_REG(hw, MANC, manc);
@@ -510,6 +579,8 @@ e1000_init_hw(struct e1000_hw *hw)
     uint16_t pcix_stat_hi_word;
     uint16_t cmd_mmrbc;
     uint16_t stat_mmrbc;
+    uint32_t mta_size;
+
     DEBUGFUNC("e1000_init_hw");
 
     /* Initialize Identification LED */
@@ -524,8 +595,8 @@ e1000_init_hw(struct e1000_hw *hw)
 
     /* Disabling VLAN filtering. */
     DEBUGOUT("Initializing the IEEE VLAN\n");
-    E1000_WRITE_REG(hw, VET, 0);
-
+    if (hw->mac_type < e1000_82545_rev_3)
+        E1000_WRITE_REG(hw, VET, 0);
     e1000_clear_vfta(hw);
 
     /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
@@ -553,14 +624,16 @@ e1000_init_hw(struct e1000_hw *hw)
 
     /* Zero out the Multicast HASH table */
     DEBUGOUT("Zeroing the MTA\n");
-    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+    mta_size = E1000_MC_TBL_SIZE;
+    for(i = 0; i < mta_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.
+     * gives equal priority to transmits and receives.  Valid only on
+     * 82542 and 82543 silicon.
      */
-    if(hw->dma_fairness) {
+    if(hw->dma_fairness && hw->mac_type <= e1000_82543) {
         ctrl = E1000_READ_REG(hw, CTRL);
         E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
     }
@@ -598,9 +671,21 @@ e1000_init_hw(struct e1000_hw *hw)
     if(hw->mac_type > e1000_82544) {
         ctrl = E1000_READ_REG(hw, TXDCTL);
         ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        switch (hw->mac_type) {
+        default:
+            break;
+        case e1000_82573:
+            ctrl |= E1000_TXDCTL_COUNT_DESC;
+            break;
+        }
         E1000_WRITE_REG(hw, TXDCTL, ctrl);
     }
 
+    if (hw->mac_type == e1000_82573) {
+        e1000_enable_tx_pkt_filtering(hw); 
+    }
+
+
     /* 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
@@ -679,7 +764,7 @@ e1000_setup_link(struct e1000_hw *hw)
      * 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, 1, &eeprom_data) < 0) {
+    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -736,6 +821,7 @@ e1000_setup_link(struct e1000_hw *hw)
     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,
@@ -906,20 +992,18 @@ e1000_setup_fiber_serdes_link(struct e10
 }
 
 /******************************************************************************
-* Detects which PHY is present and the speed and duplex
+* Make sure we have a valid PHY and change PHY mode before link setup.
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 static int32_t
-e1000_setup_copper_link(struct e1000_hw *hw)
+e1000_copper_link_preconfig(struct e1000_hw *hw)
 {
     uint32_t ctrl;
-    uint32_t led_ctrl;
     int32_t ret_val;
-    uint16_t i;
     uint16_t phy_data;
 
-    DEBUGFUNC("e1000_setup_copper_link");
+    DEBUGFUNC("e1000_copper_link_preconfig");
 
     ctrl = E1000_READ_REG(hw, CTRL);
     /* With 82543, we need to force speed and duplex on the MAC equal to what
@@ -933,7 +1017,9 @@ e1000_setup_copper_link(struct e1000_hw 
     } else {
         ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
         E1000_WRITE_REG(hw, CTRL, ctrl);
-        e1000_phy_hw_reset(hw);
+        ret_val = e1000_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
     }
 
     /* Make sure we have a valid PHY */
@@ -961,359 +1047,457 @@ e1000_setup_copper_link(struct e1000_hw 
        hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
         hw->phy_reset_disable = FALSE;
 
-    if(!hw->phy_reset_disable) {
-        if (hw->phy_type == e1000_phy_igp) {
+   return E1000_SUCCESS;
+}
 
-            ret_val = e1000_phy_reset(hw);
-            if(ret_val) {
-                DEBUGOUT("Error Resetting the PHY\n");
-                return ret_val;
-            }
 
-            /* Wait 10ms for MAC to configure PHY from eeprom settings */
-            msec_delay(15);
+/********************************************************************
+* Copper link setup for e1000_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_igp_setup(struct e1000_hw *hw)
+{
+    uint32_t led_ctrl;
+    int32_t ret_val;
+    uint16_t phy_data;
 
-            /* Configure activity LED after PHY reset */
-            led_ctrl = E1000_READ_REG(hw, LEDCTL);
-            led_ctrl &= IGP_ACTIVITY_LED_MASK;
-            led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-            E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    DEBUGFUNC("e1000_copper_link_igp_setup");
 
-            /* disable lplu d3 during driver init */
-            ret_val = e1000_set_d3_lplu_state(hw, FALSE);
-            if(ret_val) {
-                DEBUGOUT("Error Disabling LPLU D3\n");
-                return ret_val;
-            }
+    if (hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    ret_val = e1000_phy_reset(hw);
+    if (ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
 
-            /* Configure mdi-mdix settings */
-            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                         &phy_data);
-            if(ret_val)
-                return ret_val;
+    /* Wait 10ms for MAC to configure PHY from eeprom settings */
+    msec_delay(15);
 
-            if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
-                hw->dsp_config_state = e1000_dsp_config_disabled;
-                /* Force MDI for earlier revs of the IGP PHY */
-                phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
-                              IGP01E1000_PSCR_FORCE_MDI_MDIX);
-                hw->mdix = 1;
+    /* Configure activity LED after PHY reset */
+    led_ctrl = E1000_READ_REG(hw, LEDCTL);
+    led_ctrl &= IGP_ACTIVITY_LED_MASK;
+    led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+    E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
 
-            } else {
-                hw->dsp_config_state = e1000_dsp_config_enabled;
-                phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+    /* disable lplu d3 during driver init */
+    ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D3\n");
+        return ret_val;
+    }
 
-                switch (hw->mdix) {
-                case 1:
-                    phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-                    break;
-                case 2:
-                    phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
-                    break;
-                case 0:
-                default:
-                    phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
-                    break;
-                }
-            }
-            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                          phy_data);
-            if(ret_val)
-                return ret_val;
+    /* disable lplu d0 during driver init */
+    ret_val = e1000_set_d0_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D0\n");
+        return ret_val;
+    }
+    /* Configure mdi-mdix settings */
+    ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+    if (ret_val)
+        return ret_val;
 
-            /* set auto-master slave resolution settings */
-            if(hw->autoneg) {
-                e1000_ms_type phy_ms_setting = hw->master_slave;
-
-                if(hw->ffe_config_state == e1000_ffe_config_active)
-                    hw->ffe_config_state = e1000_ffe_config_enabled;
-
-                if(hw->dsp_config_state == e1000_dsp_config_activated)
-                    hw->dsp_config_state = e1000_dsp_config_enabled;
-
-                /* when autonegotiation advertisment is only 1000Mbps then we
-                 * should disable SmartSpeed and enable Auto MasterSlave
-                 * resolution as hardware default. */
-                if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
-                    /* Disable SmartSpeed */
-                    ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                                 &phy_data);
-                    if(ret_val)
-                        return ret_val;
-                    phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-                    ret_val = e1000_write_phy_reg(hw,
-                                                  IGP01E1000_PHY_PORT_CONFIG,
-                                                  phy_data);
-                    if(ret_val)
-                        return ret_val;
-                    /* Set auto Master/Slave resolution process */
-                    ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
-                    if(ret_val)
-                        return ret_val;
-                    phy_data &= ~CR_1000T_MS_ENABLE;
-                    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
-                    if(ret_val)
-                        return ret_val;
-                }
+    if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+        hw->dsp_config_state = e1000_dsp_config_disabled;
+        /* Force MDI for earlier revs of the IGP PHY */
+        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+        hw->mdix = 1;
 
-                ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
-                if(ret_val)
-                    return ret_val;
+    } else {
+        hw->dsp_config_state = e1000_dsp_config_enabled;
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
 
-                /* load defaults for future use */
-                hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
-                                            ((phy_data & CR_1000T_MS_VALUE) ?
-                                             e1000_ms_force_master :
-                                             e1000_ms_force_slave) :
-                                             e1000_ms_auto;
-
-                switch (phy_ms_setting) {
-                case e1000_ms_force_master:
-                    phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-                    break;
-                case e1000_ms_force_slave:
-                    phy_data |= CR_1000T_MS_ENABLE;
-                    phy_data &= ~(CR_1000T_MS_VALUE);
-                    break;
-                case e1000_ms_auto:
-                    phy_data &= ~CR_1000T_MS_ENABLE;
-                default:
-                    break;
-                }
-                ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
-                if(ret_val)
-                    return ret_val;
-            }
-        } else {
-            /* Enable CRS on TX. This must be set for half-duplex operation. */
-            ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                         &phy_data);
-            if(ret_val)
-                return ret_val;
+        switch (hw->mdix) {
+        case 1:
+            phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 2:
+            phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 0:
+        default:
+            phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+            break;
+        }
+    }
+    ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+    if(ret_val)
+        return ret_val;
 
-            phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    /* set auto-master slave resolution settings */
+    if(hw->autoneg) {
+        e1000_ms_type phy_ms_setting = hw->master_slave;
 
-            /* 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;
+        if(hw->ffe_config_state == e1000_ffe_config_active)
+            hw->ffe_config_state = e1000_ffe_config_enabled;
 
-            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;
-            }
+        if(hw->dsp_config_state == e1000_dsp_config_activated)
+            hw->dsp_config_state = e1000_dsp_config_enabled;
 
-            /* 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;
-            ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                          phy_data);
+        /* when autonegotiation advertisment is only 1000Mbps then we
+          * should disable SmartSpeed and enable Auto MasterSlave
+          * resolution as hardware default. */
+        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+            /* Disable SmartSpeed */
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
             if(ret_val)
                 return ret_val;
-
-            /* Force TX_CLK in the Extended PHY Specific Control Register
-             * to 25MHz clock.
-             */
-            ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                         &phy_data);
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw,
+                                                  IGP01E1000_PHY_PORT_CONFIG,
+                                                  phy_data);
+            if(ret_val)
+                return ret_val;
+            /* Set auto Master/Slave resolution process */
+            ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+            if(ret_val)
+                return ret_val;
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
             if(ret_val)
                 return ret_val;
+        }
 
-            phy_data |= M88E1000_EPSCR_TX_CLK_25;
+        ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
 
-            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);
-                ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                              phy_data);
-                if(ret_val)
-                    return ret_val;
-            }
+        /* load defaults for future use */
+        hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+                                        ((phy_data & CR_1000T_MS_VALUE) ?
+                                         e1000_ms_force_master :
+                                         e1000_ms_force_slave) :
+                                         e1000_ms_auto;
 
-            /* SW Reset the PHY so all changes take effect */
-            ret_val = e1000_phy_reset(hw);
-            if(ret_val) {
-                DEBUGOUT("Error Resetting the PHY\n");
-                return ret_val;
-            }
+        switch (phy_ms_setting) {
+        case e1000_ms_force_master:
+            phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+            break;
+        case e1000_ms_force_slave:
+            phy_data |= CR_1000T_MS_ENABLE;
+            phy_data &= ~(CR_1000T_MS_VALUE);
+            break;
+        case e1000_ms_auto:
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            default:
+            break;
+        }
+        ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+        if(ret_val)
+            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;
+   return E1000_SUCCESS;
+}
 
-            /* 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) {
-                DEBUGOUT("Error Setting up Auto-Negotiation\n");
-                return ret_val;
-            }
-            DEBUGOUT("Restarting Auto-Neg\n");
+/********************************************************************
+* Copper link setup for e1000_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_mgp_setup(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
 
-            /* Restart auto-negotiation by setting the Auto Neg Enable bit and
-             * the Auto Neg Restart bit in the PHY control register.
-             */
-            ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
-            if(ret_val)
-                return ret_val;
+    DEBUGFUNC("e1000_copper_link_mgp_setup");
 
-            phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-            ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
-            if(ret_val)
-                return ret_val;
+    if(hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
 
-            /* 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) {
-                    DEBUGOUT("Error while waiting for autoneg to complete\n");
-                    return ret_val;
-                }
-            }
-            hw->get_link_status = TRUE;
-        } else {
-            DEBUGOUT("Forcing speed and duplex\n");
-            ret_val = e1000_phy_force_speed_duplex(hw);
-            if(ret_val) {
-                DEBUGOUT("Error Forcing Speed and Duplex\n");
-                return ret_val;
-            }
-        }
-    } /* !hw->phy_reset_disable */
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
-    /* Check link status. Wait up to 100 microseconds for link to become
-     * valid.
+    /* 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)
      */
-    for(i = 0; i < 10; i++) {
-        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    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;
+        ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
         if(ret_val)
             return ret_val;
-        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    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);
+        ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
         if(ret_val)
             return ret_val;
+    }
 
-        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) {
-                    DEBUGOUT("Error configuring MAC to PHY settings\n");
-                    return ret_val;
-                }
-            }
-            ret_val = e1000_config_fc_after_link_up(hw);
-            if(ret_val) {
-                DEBUGOUT("Error Configuring Flow Control\n");
-                return ret_val;
-            }
-            DEBUGOUT("Valid link established!!!\n");
-
-            if(hw->phy_type == e1000_phy_igp) {
-                ret_val = e1000_config_dsp_after_link_change(hw, TRUE);
-                if(ret_val) {
-                    DEBUGOUT("Error Configuring DSP after link up\n");
-                    return ret_val;
-                }
-            }
-            DEBUGOUT("Valid link established!!!\n");
-            return E1000_SUCCESS;
-        }
-        udelay(10);
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = e1000_phy_reset(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
     }
 
-    DEBUGOUT("Unable to establish link!!!\n");
-    return E1000_SUCCESS;
+   return E1000_SUCCESS;
 }
 
-/******************************************************************************
-* Configures PHY autoneg and flow control advertisement settings
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
 *
 * hw - Struct containing variables accessed by shared code
-******************************************************************************/
-int32_t
-e1000_phy_setup_autoneg(struct e1000_hw *hw)
+*********************************************************************/
+static int32_t
+e1000_copper_link_autoneg(struct e1000_hw *hw)
 {
     int32_t ret_val;
-    uint16_t mii_autoneg_adv_reg;
-    uint16_t mii_1000t_ctrl_reg;
+    uint16_t phy_data;
 
-    DEBUGFUNC("e1000_phy_setup_autoneg");
+    DEBUGFUNC("e1000_copper_link_autoneg");
 
-    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-    ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+    /* 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) {
+        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.
+     */
+    ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
     if(ret_val)
         return ret_val;
 
-    /* Read the MII 1000Base-T Control Register (Address 9). */
-    ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+    phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+    ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
     if(ret_val)
         return ret_val;
 
-    /* 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.
+    /* 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) {
+            DEBUGOUT("Error while waiting for autoneg to complete\n");
+            return ret_val;
+        }
+    }
+
+    hw->get_link_status = TRUE;
+
+    return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+*   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.
+*   3) Config DSP to improve Gigabit link quality for some PHY revisions.    
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_copper_link_postconfig(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    DEBUGFUNC("e1000_copper_link_postconfig");
+    
+    if(hw->mac_type >= e1000_82544) {
+        e1000_config_collision_dist(hw);
+    } else {
+        ret_val = e1000_config_mac_to_phy(hw);
+        if(ret_val) {
+            DEBUGOUT("Error configuring MAC to PHY settings\n");
+            return ret_val;
+        }
+    }
+    ret_val = e1000_config_fc_after_link_up(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Configuring Flow Control\n");
+        return ret_val;
+    }
+
+    /* Config DSP to improve Giga link quality */
+    if(hw->phy_type == e1000_phy_igp) {
+        ret_val = e1000_config_dsp_after_link_change(hw, TRUE);
+        if(ret_val) {
+            DEBUGOUT("Error Configuring DSP after link up\n");
+            return ret_val;
+        }
+    }
+                
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_setup_copper_link");
+
+    /* Check if it is a valid PHY and set PHY mode if necessary. */
+    ret_val = e1000_copper_link_preconfig(hw);
+    if(ret_val)
+        return ret_val;
+
+    if (hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_2) {
+        ret_val = e1000_copper_link_igp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    } else if (hw->phy_type == e1000_phy_m88) {
+        ret_val = e1000_copper_link_mgp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    }
+
+    if(hw->autoneg) {
+        /* Setup autoneg and flow control advertisement 
+          * and perform autonegotiation */   
+        ret_val = e1000_copper_link_autoneg(hw);
+        if(ret_val)
+            return ret_val;           
+    } else {
+        /* PHY will be set to 10H, 10F, 100H,or 100F
+          * depending on value from forced_speed_duplex. */
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = e1000_phy_force_speed_duplex(hw);
+        if(ret_val) {
+            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++) {
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* Config the MAC and PHY after link is up */
+            ret_val = e1000_copper_link_postconfig(hw);
+            if(ret_val)
+                return ret_val;
+            
+            DEBUGOUT("Valid link established!!!\n");
+            return E1000_SUCCESS;
+        }
+        udelay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* 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)
+{
+    int32_t ret_val;
+    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). */
+    ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+    if(ret_val)
+        return ret_val;
+
+        /* Read the MII 1000Base-T Control Register (Address 9). */
+        ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+        if(ret_val)
+            return ret_val;
+
+    /* 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).
@@ -1417,7 +1601,7 @@ e1000_phy_setup_autoneg(struct e1000_hw 
 
     DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
-    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);    
     if(ret_val)
         return ret_val;
 
@@ -1572,7 +1756,8 @@ e1000_phy_force_speed_duplex(struct e100
             if(mii_status_reg & MII_SR_LINK_STATUS) break;
             msec_delay(100);
         }
-        if((i == 0) && (hw->phy_type == e1000_phy_m88)) {
+        if((i == 0) &&
+           (hw->phy_type == e1000_phy_m88)) {
             /* We didn't get link.  Reset the DSP and wait again for link. */
             ret_val = e1000_phy_reset_dsp(hw);
             if(ret_val) {
@@ -1677,6 +1862,11 @@ e1000_config_mac_to_phy(struct e1000_hw 
 
     DEBUGFUNC("e1000_config_mac_to_phy");
 
+    /* 82544 or newer MAC, Auto Speed Detection takes care of 
+    * MAC speed/duplex configuration.*/
+    if (hw->mac_type >= e1000_82544)
+        return E1000_SUCCESS;
+
     /* Read the Device Control Register and set the bits to Force Speed
      * and Duplex.
      */
@@ -1687,45 +1877,25 @@ e1000_config_mac_to_phy(struct e1000_hw 
     /* Set up duplex in the Device Control and Transmit Control
      * registers depending on negotiated values.
      */
-    if (hw->phy_type == e1000_phy_igp) {
-        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                     &phy_data);
-        if(ret_val)
-            return ret_val;
-
-        if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
-        else ctrl &= ~E1000_CTRL_FD;
-
-        e1000_config_collision_dist(hw);
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
 
-        /* Set up speed in the Device Control register depending on
-         * negotiated values.
-         */
-        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
-           IGP01E1000_PSSR_SPEED_1000MBPS)
-            ctrl |= E1000_CTRL_SPD_1000;
-        else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
-                IGP01E1000_PSSR_SPEED_100MBPS)
-            ctrl |= E1000_CTRL_SPD_100;
-    } else {
-        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                     &phy_data);
-        if(ret_val)
-            return ret_val;
+    if(phy_data & M88E1000_PSSR_DPLX) 
+        ctrl |= E1000_CTRL_FD;
+    else 
+        ctrl &= ~E1000_CTRL_FD;
 
-        if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
-        else ctrl &= ~E1000_CTRL_FD;
+    e1000_config_collision_dist(hw);
 
-        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;
 
-        /* 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 E1000_SUCCESS;
@@ -2493,8 +2663,8 @@ e1000_read_phy_reg(struct e1000_hw *hw,
 
     DEBUGFUNC("e1000_read_phy_reg");
 
-
-    if(hw->phy_type == e1000_phy_igp &&
+    if((hw->phy_type == e1000_phy_igp || 
+        hw->phy_type == e1000_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
@@ -2503,7 +2673,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
         }
     }
 
-    ret_val = e1000_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+    ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
                                     phy_data);
 
     return ret_val;
@@ -2599,8 +2769,8 @@ e1000_write_phy_reg(struct e1000_hw *hw,
 
     DEBUGFUNC("e1000_write_phy_reg");
 
-
-    if(hw->phy_type == e1000_phy_igp &&
+    if((hw->phy_type == e1000_phy_igp || 
+        hw->phy_type == e1000_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
@@ -2609,7 +2779,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
         }
     }
 
-    ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+    ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
                                      phy_data);
 
     return ret_val;
@@ -2678,19 +2848,27 @@ e1000_write_phy_reg_ex(struct e1000_hw *
     return E1000_SUCCESS;
 }
 
+
 /******************************************************************************
 * Returns the PHY to the power-on reset state
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-void
+int32_t
 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
     uint32_t ctrl, ctrl_ext;
     uint32_t led_ctrl;
+    int32_t ret_val;
 
     DEBUGFUNC("e1000_phy_hw_reset");
 
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = e1000_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
     DEBUGOUT("Resetting Phy...\n");
 
     if(hw->mac_type > e1000_82543) {
@@ -2726,6 +2904,11 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
         led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
         E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
     }
+
+    /* Wait for FW to finish PHY configuration. */
+    ret_val = e1000_get_phy_cfg_done(hw);
+
+    return ret_val;
 }
 
 /******************************************************************************
@@ -2743,7 +2926,19 @@ e1000_phy_reset(struct e1000_hw *hw)
 
     DEBUGFUNC("e1000_phy_reset");
 
-    if(hw->mac_type != e1000_82541_rev_2) {
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = e1000_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
+    switch (hw->mac_type) {
+    case e1000_82541_rev_2:
+        ret_val = e1000_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
+        break;
+    default:
         ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
         if(ret_val)
             return ret_val;
@@ -2754,9 +2949,10 @@ e1000_phy_reset(struct e1000_hw *hw)
             return ret_val;
 
         udelay(1);
-    } else e1000_phy_hw_reset(hw);
+        break;
+    }
 
-    if(hw->phy_type == e1000_phy_igp)
+    if(hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
         e1000_phy_init_script(hw);
 
     return E1000_SUCCESS;
@@ -2810,6 +3006,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw
     case e1000_82547_rev_2:
         if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
         break;
+    case e1000_82573:
+        if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+        break;
     default:
         DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
         return -E1000_ERR_CONFIG;
@@ -2865,7 +3064,7 @@ e1000_phy_igp_get_info(struct e1000_hw *
 
     /* The downshift status is checked only once, after link is established,
      * and it stored in the hw->speed_downgraded parameter. */
-    phy_info->downshift = hw->speed_downgraded;
+    phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
 
     /* IGP01E1000 does not need to support it. */
     phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
@@ -2904,7 +3103,7 @@ e1000_phy_igp_get_info(struct e1000_hw *
         if(ret_val)
             return ret_val;
 
-        /* transalte to old method */
+        /* Translate to old method */
         average = (max_length + min_length) / 2;
 
         if(average <= e1000_igp_cable_length_50)
@@ -2939,7 +3138,7 @@ e1000_phy_m88_get_info(struct e1000_hw *
 
     /* The downshift status is checked only once, after link is established,
      * and it stored in the hw->speed_downgraded parameter. */
-    phy_info->downshift = hw->speed_downgraded;
+    phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
 
     ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
     if(ret_val)
@@ -2955,8 +3154,7 @@ e1000_phy_m88_get_info(struct e1000_hw *
     /* Check polarity status */
     ret_val = e1000_check_polarity(hw, &polarity);
     if(ret_val)
-        return ret_val;
-
+        return ret_val; 
     phy_info->cable_polarity = polarity;
 
     ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
@@ -2966,9 +3164,9 @@ e1000_phy_m88_get_info(struct e1000_hw *
     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
+    if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+        /* Cable Length Estimation and Local/Remote Receiver Information
+         * are only valid at 1000 Mbps.
          */
         phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
                                   M88E1000_PSSR_CABLE_LENGTH_SHIFT);
@@ -3029,7 +3227,8 @@ e1000_phy_get_info(struct e1000_hw *hw,
         return -E1000_ERR_CONFIG;
     }
 
-    if(hw->phy_type == e1000_phy_igp)
+    if(hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_2)
         return e1000_phy_igp_get_info(hw, phy_info);
     else
         return e1000_phy_m88_get_info(hw, phy_info);
@@ -3055,11 +3254,12 @@ e1000_validate_mdi_setting(struct e1000_
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-void
+int32_t
 e1000_init_eeprom_params(struct e1000_hw *hw)
 {
     struct e1000_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd = E1000_READ_REG(hw, EECD);
+    int32_t ret_val = E1000_SUCCESS;
     uint16_t eeprom_size;
 
     DEBUGFUNC("e1000_init_eeprom_params");
@@ -3074,6 +3274,8 @@ e1000_init_eeprom_params(struct e1000_hw
         eeprom->opcode_bits = 3;
         eeprom->address_bits = 6;
         eeprom->delay_usec = 50;
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
     case e1000_82540:
     case e1000_82545:
@@ -3090,6 +3292,8 @@ e1000_init_eeprom_params(struct e1000_hw
             eeprom->word_size = 64;
             eeprom->address_bits = 6;
         }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
     case e1000_82541:
     case e1000_82541_rev_2:
@@ -3118,42 +3322,60 @@ e1000_init_eeprom_params(struct e1000_hw
                 eeprom->address_bits = 6;
             }
         }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
+        break;
+    case e1000_82573:
+        eeprom->type = e1000_eeprom_spi;
+        eeprom->opcode_bits = 8;
+        eeprom->delay_usec = 1;
+        if (eecd & E1000_EECD_ADDR_BITS) {
+            eeprom->page_size = 32;
+            eeprom->address_bits = 16;
+        } else {
+            eeprom->page_size = 8;
+            eeprom->address_bits = 8;
+        }
+        eeprom->use_eerd = TRUE;
+        eeprom->use_eewr = TRUE;
+        if(e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+            eeprom->type = e1000_eeprom_flash;
+            eeprom->word_size = 2048;
+
+            /* Ensure that the Autonomous FLASH update bit is cleared due to
+             * Flash update issue on parts which use a FLASH for NVM. */
+            eecd &= ~E1000_EECD_AUPDEN;
+            E1000_WRITE_REG(hw, EECD, eecd);
+        }
         break;
     default:
         break;
     }
 
     if (eeprom->type == e1000_eeprom_spi) {
-        eeprom->word_size = 64;
-        if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) {
-            eeprom_size &= EEPROM_SIZE_MASK;
-
-            switch (eeprom_size) {
-            case EEPROM_SIZE_16KB:
-                eeprom->word_size = 8192;
-                break;
-            case EEPROM_SIZE_8KB:
-                eeprom->word_size = 4096;
-                break;
-            case EEPROM_SIZE_4KB:
-                eeprom->word_size = 2048;
-                break;
-            case EEPROM_SIZE_2KB:
-                eeprom->word_size = 1024;
-                break;
-            case EEPROM_SIZE_1KB:
-                eeprom->word_size = 512;
-                break;
-            case EEPROM_SIZE_512B:
-                eeprom->word_size = 256;
-                break;
-            case EEPROM_SIZE_128B:
-            default:
-                eeprom->word_size = 64;
-                break;
-            }
+        /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
+         * 32KB (incremented by powers of 2).
+         */
+        if(hw->mac_type <= e1000_82547_rev_2) {
+            /* Set to default value for initial eeprom read. */
+            eeprom->word_size = 64;
+            ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
+            if(ret_val)
+                return ret_val;
+            eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+            /* 256B eeprom size was not supported in earlier hardware, so we
+             * bump eeprom_size up one to ensure that "1" (which maps to 256B)
+             * is never the result used in the shifting logic below. */
+            if(eeprom_size)
+                eeprom_size++;
+        } else {
+            eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+                          E1000_EECD_SIZE_EX_SHIFT);
         }
+
+        eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
     }
+    return ret_val;
 }
 
 /******************************************************************************
@@ -3306,8 +3528,12 @@ e1000_acquire_eeprom(struct e1000_hw *hw
 
     DEBUGFUNC("e1000_acquire_eeprom");
 
+    if(e1000_get_hw_eeprom_semaphore(hw))
+        return -E1000_ERR_EEPROM;
+
     eecd = E1000_READ_REG(hw, EECD);
 
+    if (hw->mac_type != e1000_82573) {
     /* Request EEPROM Access */
     if(hw->mac_type > e1000_82544) {
         eecd |= E1000_EECD_REQ;
@@ -3326,6 +3552,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw
             return -E1000_ERR_EEPROM;
         }
     }
+    }
 
     /* Setup EEPROM for Read/Write */
 
@@ -3443,6 +3670,8 @@ e1000_release_eeprom(struct e1000_hw *hw
         eecd &= ~E1000_EECD_REQ;
         E1000_WRITE_REG(hw, EECD, eecd);
     }
+
+    e1000_put_hw_eeprom_semaphore(hw);
 }
 
 /******************************************************************************
@@ -3504,8 +3733,10 @@ e1000_read_eeprom(struct e1000_hw *hw,
 {
     struct e1000_eeprom_info *eeprom = &hw->eeprom;
     uint32_t i = 0;
+    int32_t ret_val;
 
     DEBUGFUNC("e1000_read_eeprom");
+
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
@@ -3515,9 +3746,23 @@ e1000_read_eeprom(struct e1000_hw *hw,
         return -E1000_ERR_EEPROM;
     }
 
-    /* Prepare the EEPROM for reading  */
-    if(e1000_acquire_eeprom(hw) != E1000_SUCCESS)
-        return -E1000_ERR_EEPROM;
+    /* FLASH reads without acquiring the semaphore are safe in 82573-based
+     * controllers.
+     */
+    if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) ||
+        (hw->mac_type != e1000_82573)) {
+        /* Prepare the EEPROM for reading  */
+        if(e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+            return -E1000_ERR_EEPROM;
+    }
+
+    if(eeprom->use_eerd == TRUE) {
+        ret_val = e1000_read_eeprom_eerd(hw, offset, words, data);
+        if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) ||
+            (hw->mac_type != e1000_82573))
+            e1000_release_eeprom(hw);
+        return ret_val;
+    }
 
     if(eeprom->type == e1000_eeprom_spi) {
         uint16_t word_in;
@@ -3569,53 +3814,198 @@ e1000_read_eeprom(struct e1000_hw *hw,
 }
 
 /******************************************************************************
- * Verifies that the EEPROM has a valid checksum
+ * Reads a 16 bit word from the EEPROM using the EERD register.
  *
  * 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.
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
  *****************************************************************************/
 int32_t
-e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+e1000_read_eeprom_eerd(struct e1000_hw *hw,
+                  uint16_t offset,
+                  uint16_t words,
+                  uint16_t *data)
 {
-    uint16_t checksum = 0;
-    uint16_t i, eeprom_data;
-
-    DEBUGFUNC("e1000_validate_eeprom_checksum");
+    uint32_t i, eerd = 0;
+    int32_t error = 0;
 
-    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
-        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
-            DEBUGOUT("EEPROM Read Error\n");
-            return -E1000_ERR_EEPROM;
+    for (i = 0; i < words; i++) {
+        eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+                         E1000_EEPROM_RW_REG_START;
+
+        E1000_WRITE_REG(hw, EERD, eerd);
+        error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+        
+        if(error) {
+            break;
         }
-        checksum += eeprom_data;
-    }
-
-    if(checksum == (uint16_t) EEPROM_SUM)
-        return E1000_SUCCESS;
-    else {
-        DEBUGOUT("EEPROM Checksum Invalid\n");
-        return -E1000_ERR_EEPROM;
+        data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
+      
     }
+    
+    return error;
 }
 
 /******************************************************************************
- * Calculates the EEPROM checksum and writes it to the EEPROM
+ * Writes a 16 bit word from the EEPROM using the EEWR register.
  *
  * 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.
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
  *****************************************************************************/
 int32_t
-e1000_update_eeprom_checksum(struct e1000_hw *hw)
+e1000_write_eeprom_eewr(struct e1000_hw *hw,
+                   uint16_t offset,
+                   uint16_t words,
+                   uint16_t *data)
 {
-    uint16_t checksum = 0;
-    uint16_t i, eeprom_data;
+    uint32_t    register_value = 0;
+    uint32_t    i              = 0;
+    int32_t     error          = 0;
+
+    for (i = 0; i < words; i++) {
+        register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | 
+                         ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | 
+                         E1000_EEPROM_RW_REG_START;
 
-    DEBUGFUNC("e1000_update_eeprom_checksum");
+        error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        if(error) {
+            break;
+        }       
+
+        E1000_WRITE_REG(hw, EEWR, register_value);
+        
+        error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        
+        if(error) {
+            break;
+        }       
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
+{
+    uint32_t attempts = 100000;
+    uint32_t i, reg = 0;
+    int32_t done = E1000_ERR_EEPROM;
+
+    for(i = 0; i < attempts; i++) {
+        if(eerd == E1000_EEPROM_POLL_READ)
+            reg = E1000_READ_REG(hw, EERD);
+        else 
+            reg = E1000_READ_REG(hw, EEWR);
+
+        if(reg & E1000_EEPROM_RW_REG_DONE) {
+            done = E1000_SUCCESS;
+            break;
+        }
+        udelay(5);
+    }
+
+    return done;
+}
+
+/***************************************************************************
+* Description:     Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+boolean_t
+e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd = 0;
+
+    if(hw->mac_type == e1000_82573) {
+        eecd = E1000_READ_REG(hw, EECD);
+
+        /* Isolate bits 15 & 16 */
+        eecd = ((eecd >> 15) & 0x03);
+
+        /* If both bits are set, device is Flash type */
+        if(eecd == 0x03) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/******************************************************************************
+ * 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");
+
+    if ((hw->mac_type == e1000_82573) &&
+        (e1000_is_onboard_nvm_eeprom(hw) == FALSE)) {
+        /* Check bit 4 of word 10h.  If it is 0, firmware is done updating
+         * 10h-12h.  Checksum may need to be fixed. */
+        e1000_read_eeprom(hw, 0x10, 1, &eeprom_data);
+        if ((eeprom_data & 0x10) == 0) {
+            /* Read 0x23 and check bit 15.  This bit is a 1 when the checksum
+             * has already been fixed.  If the checksum is still wrong and this
+             * bit is a 1, we need to return bad checksum.  Otherwise, we need
+             * to set this bit to a 1 and update the checksum. */
+            e1000_read_eeprom(hw, 0x23, 1, &eeprom_data);
+            if ((eeprom_data & 0x8000) == 0) {
+                eeprom_data |= 0x8000;
+                e1000_write_eeprom(hw, 0x23, 1, &eeprom_data);
+                e1000_update_eeprom_checksum(hw);
+            }
+        }
+    }
+
+    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+
+    if(checksum == (uint16_t) EEPROM_SUM)
+        return E1000_SUCCESS;
+    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, 1, &eeprom_data) < 0) {
@@ -3628,6 +4018,8 @@ e1000_update_eeprom_checksum(struct e100
     if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
         DEBUGOUT("EEPROM Write Error\n");
         return -E1000_ERR_EEPROM;
+    } else if (hw->eeprom.type == e1000_eeprom_flash) {
+        e1000_commit_shadow_ram(hw);
     }
     return E1000_SUCCESS;
 }
@@ -3663,6 +4055,10 @@ e1000_write_eeprom(struct e1000_hw *hw,
         return -E1000_ERR_EEPROM;
     }
 
+    /* 82573 reads only through eerd */
+    if(eeprom->use_eewr == TRUE)
+        return e1000_write_eeprom_eewr(hw, offset, words, data);
+
     /* Prepare the EEPROM for writing  */
     if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
         return -E1000_ERR_EEPROM;
@@ -3833,6 +4229,65 @@ e1000_write_eeprom_microwire(struct e100
 }
 
 /******************************************************************************
+ * Flushes the cached eeprom to NVM. This is done by saving the modified values
+ * in the eeprom cache and the non modified values in the currently active bank
+ * to the new bank.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+e1000_commit_shadow_ram(struct e1000_hw *hw)
+{
+    uint32_t attempts = 100000;
+    uint32_t eecd = 0;
+    uint32_t flop = 0;
+    uint32_t i = 0;
+    int32_t error = E1000_SUCCESS;
+
+    /* The flop register will be used to determine if flash type is STM */
+    flop = E1000_READ_REG(hw, FLOP);
+
+    if (hw->mac_type == e1000_82573) {
+        for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            udelay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+
+	/* If STM opcode located in bits 15:8 of flop, reset firmware */
+        if ((flop & 0xFF00) == E1000_STM_OPCODE) {
+            E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET);
+        }
+
+        /* Perform the flash update */
+        E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD);
+
+	for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            udelay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    return error;
+}
+
+/******************************************************************************
  * Reads the adapter's part number from the EEPROM
  *
  * hw - Struct containing variables accessed by shared code
@@ -3911,6 +4366,7 @@ void
 e1000_init_rx_addrs(struct e1000_hw *hw)
 {
     uint32_t i;
+    uint32_t rar_num;
 
     DEBUGFUNC("e1000_init_rx_addrs");
 
@@ -3919,9 +4375,10 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
 
     e1000_rar_set(hw, hw->mac_addr, 0);
 
+    rar_num = E1000_RAR_ENTRIES;
     /* Zero out the other 15 receive addresses. */
     DEBUGOUT("Clearing RAR[1-15]\n");
-    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+    for(i = 1; i < rar_num; i++) {
         E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
         E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
     }
@@ -3950,7 +4407,9 @@ e1000_mc_addr_list_update(struct e1000_h
 {
     uint32_t hash_value;
     uint32_t i;
-
+    uint32_t num_rar_entry;
+    uint32_t num_mta_entry;
+    
     DEBUGFUNC("e1000_mc_addr_list_update");
 
     /* Set the new number of MC addresses that we are being requested to use. */
@@ -3958,14 +4417,16 @@ e1000_mc_addr_list_update(struct e1000_h
 
     /* Clear RAR[1-15] */
     DEBUGOUT(" Clearing RAR[1-15]\n");
-    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+    num_rar_entry = E1000_RAR_ENTRIES;
+    for(i = rar_used_count; i < num_rar_entry; 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++) {
+    num_mta_entry = E1000_NUM_MTA_REGISTERS;
+    for(i = 0; i < num_mta_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
     }
 
@@ -3989,7 +4450,7 @@ e1000_mc_addr_list_update(struct e1000_h
         /* Place this multicast address in the RAR if there is room, *
          * else put it in the MTA
          */
-        if(rar_used_count < E1000_RAR_ENTRIES) {
+        if (rar_used_count < num_rar_entry) {
             e1000_rar_set(hw,
                           mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
                           rar_used_count);
@@ -4040,6 +4501,7 @@ e1000_hash_mc_addr(struct e1000_hw *hw,
     }
 
     hash_value &= 0xFFF;
+
     return hash_value;
 }
 
@@ -4144,12 +4606,33 @@ 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);
+    uint32_t vfta_value = 0;
+    uint32_t vfta_offset = 0;
+    uint32_t vfta_bit_in_reg = 0;
+
+    if (hw->mac_type == e1000_82573) {
+        if (hw->mng_cookie.vlan_id != 0) {
+            /* The VFTA is a 4096b bit-field, each identifying a single VLAN
+             * ID.  The following operations determine which 32b entry
+             * (i.e. offset) into the array we want to set the VLAN ID
+             * (i.e. bit) of the manageability unit. */
+            vfta_offset = (hw->mng_cookie.vlan_id >>
+                           E1000_VFTA_ENTRY_SHIFT) &
+                          E1000_VFTA_ENTRY_MASK;
+            vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+                                    E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+        }
+    }
+    for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+        /* If the offset we want to clear is the same offset of the
+         * manageability VLAN ID, then clear all bits except that of the
+         * manageability unit */
+        vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+    }
 }
 
-static int32_t
+int32_t
 e1000_id_led_init(struct e1000_hw * hw)
 {
     uint32_t ledctl;
@@ -4480,6 +4963,19 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
     temp = E1000_READ_REG(hw, MGTPRC);
     temp = E1000_READ_REG(hw, MGTPDC);
     temp = E1000_READ_REG(hw, MGTPTC);
+
+    if(hw->mac_type <= e1000_82547_rev_2) return;
+
+    temp = E1000_READ_REG(hw, IAC);
+    temp = E1000_READ_REG(hw, ICRXOC);
+    temp = E1000_READ_REG(hw, ICRXPTC);
+    temp = E1000_READ_REG(hw, ICRXATC);
+    temp = E1000_READ_REG(hw, ICTXPTC);
+    temp = E1000_READ_REG(hw, ICTXATC);
+    temp = E1000_READ_REG(hw, ICTXQEC);
+    temp = E1000_READ_REG(hw, ICTXQMTC);
+    temp = E1000_READ_REG(hw, ICRXDMTC);
+
 }
 
 /******************************************************************************
@@ -4639,41 +5135,49 @@ e1000_get_bus_info(struct e1000_hw *hw)
 {
     uint32_t status;
 
-    if(hw->mac_type < e1000_82543) {
+    switch (hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
         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;
+        break;
+    case e1000_82573:
+        hw->bus_type = e1000_bus_type_pci_express;
+        hw->bus_speed = e1000_bus_speed_2500;
+        hw->bus_width = e1000_bus_width_pciex_4;
+        break;
+    default:
+        status = E1000_READ_REG(hw, STATUS);
+        hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                       e1000_bus_type_pcix : e1000_bus_type_pci;
 
-    if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
-        hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
-                        e1000_bus_speed_66 : e1000_bus_speed_120;
-    } else 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;
+        if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+            hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
+                            e1000_bus_speed_66 : e1000_bus_speed_120;
+        } else 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;
+        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
@@ -4738,6 +5242,7 @@ e1000_get_cable_length(struct e1000_hw *
     uint16_t agc_value = 0;
     uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
     uint16_t i, phy_data;
+    uint16_t cable_length;
 
     DEBUGFUNC("e1000_get_cable_length");
 
@@ -4745,14 +5250,16 @@ e1000_get_cable_length(struct e1000_hw *
 
     /* Use old method for Phy older than IGP */
     if(hw->phy_type == e1000_phy_m88) {
+
         ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
                                      &phy_data);
         if(ret_val)
             return ret_val;
+        cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                       M88E1000_PSSR_CABLE_LENGTH_SHIFT;
 
         /* Convert the enum value to ranged values */
-        switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-               M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
+        switch (cable_length) {
         case e1000_cable_length_50:
             *min_length = 0;
             *max_length = e1000_igp_cable_length_50;
@@ -4860,7 +5367,8 @@ e1000_check_polarity(struct e1000_hw *hw
             return ret_val;
         *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
                     M88E1000_PSSR_REV_POLARITY_SHIFT;
-    } else if(hw->phy_type == e1000_phy_igp) {
+    } else if(hw->phy_type == e1000_phy_igp ||
+              hw->phy_type == e1000_phy_igp_2) {
         /* Read the Status register to check the speed */
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
                                      &phy_data);
@@ -4912,15 +5420,15 @@ e1000_check_downshift(struct e1000_hw *h
 
     DEBUGFUNC("e1000_check_downshift");
 
-    if(hw->phy_type == e1000_phy_igp) {
+    if(hw->phy_type == e1000_phy_igp || 
+        hw->phy_type == e1000_phy_igp_2) {
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
                                      &phy_data);
         if(ret_val)
             return ret_val;
 
         hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
-    }
-    else if(hw->phy_type == e1000_phy_m88) {
+    } else if(hw->phy_type == e1000_phy_m88) {
         ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
                                      &phy_data);
         if(ret_val)
@@ -4929,6 +5437,7 @@ e1000_check_downshift(struct e1000_hw *h
         hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
     }
+
     return E1000_SUCCESS;
 }
 
@@ -5043,7 +5552,7 @@ e1000_config_dsp_after_link_change(struc
             if(ret_val)
                 return ret_val;
 
-            msec_delay(20);
+            msec_delay_irq(20);
 
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
@@ -5067,7 +5576,7 @@ e1000_config_dsp_after_link_change(struc
             if(ret_val)
                 return ret_val;
 
-            msec_delay(20);
+            msec_delay_irq(20);
 
             /* Now enable the transmitter */
             ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
@@ -5092,7 +5601,7 @@ e1000_config_dsp_after_link_change(struc
             if(ret_val)
                 return ret_val;
 
-            msec_delay(20);
+            msec_delay_irq(20);
 
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
@@ -5108,7 +5617,7 @@ e1000_config_dsp_after_link_change(struc
             if(ret_val)
                 return ret_val;
 
-            msec_delay(20);
+            msec_delay_irq(20);
 
             /* Now enable the transmitter */
             ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
@@ -5183,22 +5692,36 @@ e1000_set_d3_lplu_state(struct e1000_hw 
     uint16_t phy_data;
     DEBUGFUNC("e1000_set_d3_lplu_state");
 
-    if(!((hw->mac_type == e1000_82541_rev_2) ||
-         (hw->mac_type == e1000_82547_rev_2)))
+    if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2)
         return E1000_SUCCESS;
 
     /* During driver activity LPLU should not be used or it will attain link
      * from the lowest speeds starting from 10Mbps. The capability is used for
      * Dx transitions and states */
-    ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
-    if(ret_val)
-        return ret_val;
-
-    if(!active) {
-        phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
-        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+    if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
+        if(ret_val)
+            return ret_val;
+    } else {
+        ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
         if(ret_val)
             return ret_val;
+    }
+
+    if(!active) {
+        if(hw->mac_type == e1000_82541_rev_2 ||
+           hw->mac_type == e1000_82547_rev_2) {
+            phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data &= ~IGP02E1000_PM_D3_LPLU;
+                ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
 
         /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
          * Dx states where the power conservation is most important.  During
@@ -5232,11 +5755,105 @@ e1000_set_d3_lplu_state(struct e1000_hw 
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
 
-        phy_data |= IGP01E1000_GMII_FLEX_SPD;
-        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+        if(hw->mac_type == e1000_82541_rev_2 ||
+           hw->mac_type == e1000_82547_rev_2) {
+            phy_data |= IGP01E1000_GMII_FLEX_SPD;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data |= IGP02E1000_PM_D3_LPLU;
+                ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
+
+        /* When LPLU is enabled we should disable SmartSpeed */
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
+            return ret_val;
+
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+e1000_set_d0_lplu_state(struct e1000_hw *hw,
+                        boolean_t active)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+    DEBUGFUNC("e1000_set_d0_lplu_state");
+
+    if(hw->mac_type <= e1000_82547_rev_2)
+        return E1000_SUCCESS;
+
+        ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
         if(ret_val)
             return ret_val;
 
+    if (!active) {
+            phy_data &= ~IGP02E1000_PM_D0_LPLU;
+            ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
+        /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
+         * Dx states where the power conservation is most important.  During
+         * driver activity we should enable SmartSpeed, so performance is
+         * maintained. */
+        if (hw->smart_speed == e1000_smart_speed_on) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == e1000_smart_speed_off) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+	    if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
+
+
+    } else {
+ 
+            phy_data |= IGP02E1000_PM_D0_LPLU;   
+            ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
         /* When LPLU is enabled we should disable SmartSpeed */
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
         if(ret_val)
@@ -5314,7 +5931,339 @@ e1000_set_vco_speed(struct e1000_hw *hw)
     return E1000_SUCCESS;
 }
 
-static int32_t
+
+/*****************************************************************************
+ * This function reads the cookie from ARC ram.
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+int32_t
+e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
+{
+    uint8_t i;
+    uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; 
+    uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
+
+    length = (length >> 2);
+    offset = (offset >> 2);
+
+    for (i = 0; i < length; i++) {
+        *((uint32_t *) buffer + i) =
+            E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i);
+    }
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed.
+ * It busy waits in case of previous command is not completed.
+ *
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or 
+ *            timeout
+ *          - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_enable_host_if(struct e1000_hw * hw)
+{
+    uint32_t hicr;
+    uint8_t i;
+
+    /* Check that the host interface is enabled. */
+    hicr = E1000_READ_REG(hw, HICR);
+    if ((hicr & E1000_HICR_EN) == 0) {
+        DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    /* check the previous command is completed */
+    for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+        hicr = E1000_READ_REG(hw, HICR);
+        if (!(hicr & E1000_HICR_C))
+            break;
+        msec_delay_irq(1);
+    }
+
+    if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 
+        DEBUGOUT("Previous command timeout failed .\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient way.
+ * Also fills up the sum of the buffer in *buffer parameter.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer,
+                        uint16_t length, uint16_t offset, uint8_t *sum)
+{
+    uint8_t *tmp;
+    uint8_t *bufptr = buffer;
+    uint32_t data;
+    uint16_t remaining, i, j, prev_bytes;
+
+    /* sum = only sum of the data and it is not checksum */
+
+    if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+        return -E1000_ERR_PARAM;
+    }
+
+    tmp = (uint8_t *)&data;
+    prev_bytes = offset & 0x3;
+    offset &= 0xFFFC;
+    offset >>= 2;
+
+    if (prev_bytes) {
+        data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset);
+        for (j = prev_bytes; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data);
+        length -= j - prev_bytes;
+        offset++;
+    }
+
+    remaining = length & 0x3;
+    length -= remaining;
+
+    /* Calculate length in DWORDs */
+    length >>= 2;
+
+    /* The device driver writes the relevant command block into the
+     * ram area. */
+    for (i = 0; i < length; i++) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+    if (remaining) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            if (j < remaining)
+                *(tmp + j) = *bufptr++;
+            else
+                *(tmp + j) = 0;
+
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function writes the command header after does the checksum calculation.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_write_cmd_header(struct e1000_hw * hw,
+                           struct e1000_host_mng_command_header * hdr)
+{
+    uint16_t i;
+    uint8_t sum;
+    uint8_t *buffer;
+
+    /* Write the whole command header structure which includes sum of
+     * the buffer */
+
+    uint16_t length = sizeof(struct e1000_host_mng_command_header);
+
+    sum = hdr->checksum;
+    hdr->checksum = 0;
+
+    buffer = (uint8_t *) hdr;
+    i = length;
+    while(i--)
+        sum += buffer[i];
+
+    hdr->checksum = 0 - sum;
+
+    length >>= 2;
+    /* The device driver writes the relevant command block into the ram area. */
+    for (i = 0; i < length; i++)
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function indicates to ARC that a new command is pending which completes
+ * one write operation by the driver.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_write_commit(
+    struct e1000_hw * hw)
+{
+    uint32_t hicr;
+
+    hicr = E1000_READ_REG(hw, HICR);
+    /* Setting this bit tells the ARC that a new command is pending. */
+    E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C);
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns  - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_check_mng_mode(
+    struct e1000_hw *hw)
+{
+    uint32_t fwsm;
+
+    fwsm = E1000_READ_REG(hw, FWSM);
+
+    if((fwsm & E1000_FWSM_MODE_MASK) ==
+        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+        return TRUE;
+
+    return FALSE;
+}
+
+
+/*****************************************************************************
+ * This function writes the dhcp info .
+ ****************************************************************************/
+int32_t
+e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer,
+			  uint16_t length)
+{
+    int32_t ret_val;
+    struct e1000_host_mng_command_header hdr;
+
+    hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+    hdr.command_length = length;
+    hdr.reserved1 = 0;
+    hdr.reserved2 = 0;
+    hdr.checksum = 0;
+
+    ret_val = e1000_mng_enable_host_if(hw);
+    if (ret_val == E1000_SUCCESS) {
+        ret_val = e1000_mng_host_if_write(hw, buffer, length, sizeof(hdr),
+                                          &(hdr.checksum));
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = e1000_mng_write_cmd_header(hw, &hdr);
+            if (ret_val == E1000_SUCCESS)
+                ret_val = e1000_mng_write_commit(hw);
+        }
+    }
+    return ret_val;
+}
+
+
+/*****************************************************************************
+ * This function calculates the checksum.
+ *
+ * returns  - checksum of buffer contents.
+ ****************************************************************************/
+uint8_t
+e1000_calculate_mng_checksum(char *buffer, uint32_t length)
+{
+    uint8_t sum = 0;
+    uint32_t i;
+
+    if (!buffer)
+        return 0;
+
+    for (i=0; i < length; i++)
+        sum += buffer[i];
+
+    return (uint8_t) (0 - sum);
+}
+
+/*****************************************************************************
+ * This function checks whether tx pkt filtering needs to be enabled or not.
+ *
+ * returns  - TRUE for packet filtering or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+    /* called in init as well as watchdog timer functions */
+
+    int32_t ret_val, checksum;
+    boolean_t tx_filter = FALSE;
+    struct e1000_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie);
+    uint8_t *buffer = (uint8_t *) &(hw->mng_cookie);
+
+    if (e1000_check_mng_mode(hw)) {
+        ret_val = e1000_mng_enable_host_if(hw);
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = e1000_host_if_read_cookie(hw, buffer);
+            if (ret_val == E1000_SUCCESS) {
+                checksum = hdr->checksum;
+                hdr->checksum = 0;
+                if ((hdr->signature == E1000_IAMT_SIGNATURE) &&
+                    checksum == e1000_calculate_mng_checksum((char *)buffer,
+                                               E1000_MNG_DHCP_COOKIE_LENGTH)) {
+                    if (hdr->status &
+                        E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT)
+                        tx_filter = TRUE;
+                } else
+                    tx_filter = TRUE;
+            } else
+                tx_filter = TRUE;
+        }
+    }
+
+    hw->tx_pkt_filtering = tx_filter;
+    return tx_filter;
+}
+
+/******************************************************************************
+ * Verifies the hardware needs to allow ARPs to be processed by the host
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - TRUE/FALSE
+ *
+ *****************************************************************************/
+uint32_t
+e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+    uint32_t manc;
+    uint32_t fwsm, factps;
+
+    if (hw->asf_firmware_present) {
+        manc = E1000_READ_REG(hw, MANC);
+
+        if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+            !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+            return FALSE;
+        if (e1000_arc_subsystem_valid(hw) == TRUE) {
+            fwsm = E1000_READ_REG(hw, FWSM);
+            factps = E1000_READ_REG(hw, FACTPS);
+
+            if (((fwsm & E1000_FWSM_MODE_MASK) ==
+                (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
+                (factps & E1000_FACTPS_MNGCG))
+                return TRUE;
+        } else
+            if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
+                return TRUE;
+    }
+    return FALSE;
+}
+
+static int32_t
 e1000_polarity_reversal_workaround(struct e1000_hw *hw)
 {
     int32_t ret_val;
@@ -5399,3 +6348,265 @@ e1000_polarity_reversal_workaround(struc
     return E1000_SUCCESS;
 }
 
+/***************************************************************************
+ *
+ * Disables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+e1000_set_pci_express_master_disable(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_set_pci_express_master_disable");
+
+    if (hw->bus_type != e1000_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/***************************************************************************
+ *
+ * Enables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+e1000_enable_pciex_master(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_enable_pciex_master");
+
+    if (hw->bus_type != e1000_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't
+ *            caused the master requests to be disabled.
+ *            E1000_SUCCESS master requests disabled.
+ *
+ ******************************************************************************/
+int32_t
+e1000_disable_pciex_master(struct e1000_hw *hw)
+{
+    int32_t timeout = MASTER_DISABLE_TIMEOUT;   /* 80ms */
+
+    DEBUGFUNC("e1000_disable_pciex_master");
+
+    if (hw->bus_type != e1000_bus_type_pci_express)
+        return E1000_SUCCESS;
+
+    e1000_set_pci_express_master_disable(hw);
+
+    while(timeout) {
+        if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+            break;
+        else
+            udelay(100);
+        timeout--;
+    }
+
+    if(!timeout) {
+        DEBUGOUT("Master requests are pending.\n");
+        return -E1000_ERR_MASTER_REQUESTS_PENDING;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+int32_t
+e1000_get_auto_rd_done(struct e1000_hw *hw)
+{
+    int32_t timeout = AUTO_READ_DONE_TIMEOUT;
+
+    DEBUGFUNC("e1000_get_auto_rd_done");
+
+    switch (hw->mac_type) {
+    default:
+        msec_delay(5);
+        break;
+    case e1000_82573:
+        while(timeout) {
+            if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+            else msec_delay(1);
+            timeout--;
+        }
+
+        if(!timeout) {
+            DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+            return -E1000_ERR_RESET;
+        }
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_get_phy_cfg_done");
+
+    /* Simply wait for 10ms */
+    msec_delay(10);
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+    int32_t timeout;
+    uint32_t swsm;
+
+    DEBUGFUNC("e1000_get_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return E1000_SUCCESS;
+
+
+    /* Get the FW semaphore. */
+    timeout = hw->eeprom.word_size + 1;
+    while(timeout) {
+        swsm = E1000_READ_REG(hw, SWSM);
+        swsm |= E1000_SWSM_SWESMBI;
+        E1000_WRITE_REG(hw, SWSM, swsm);
+        /* if we managed to set the bit we got the semaphore. */
+        swsm = E1000_READ_REG(hw, SWSM);
+        if(swsm & E1000_SWSM_SWESMBI)
+            break;
+
+        udelay(50);
+        timeout--;
+    }
+
+    if(!timeout) {
+        /* Release semaphores */
+        e1000_put_hw_eeprom_semaphore(hw);
+        DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+void
+e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+    uint32_t swsm;
+
+    DEBUGFUNC("e1000_put_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return;
+
+    swsm = E1000_READ_REG(hw, SWSM);
+    /* Release both semaphores. */
+    swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+    E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error.  But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ *            E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_check_phy_reset_block(struct e1000_hw *hw)
+{
+    uint32_t manc = 0;
+    if(hw->mac_type > e1000_82547_rev_2)
+        manc = E1000_READ_REG(hw, MANC);
+    return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	    E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+uint8_t
+e1000_arc_subsystem_valid(struct e1000_hw *hw)
+{
+    uint32_t fwsm;
+
+    /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC
+     * may not be provided a DMA clock when no manageability features are
+     * enabled.  We do not want to perform any reads/writes to these registers
+     * if this is the case.  We read FWSM to determine the manageability mode.
+     */
+    switch (hw->mac_type) {
+    case e1000_82573:
+        fwsm = E1000_READ_REG(hw, FWSM);
+        if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+            return TRUE;
+        break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+
+
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -57,6 +57,7 @@ typedef enum {
     e1000_82541_rev_2,
     e1000_82547,
     e1000_82547_rev_2,
+    e1000_82573,
     e1000_num_macs
 } e1000_mac_type;
 
@@ -64,6 +65,7 @@ typedef enum {
     e1000_eeprom_uninitialized = 0,
     e1000_eeprom_spi,
     e1000_eeprom_microwire,
+    e1000_eeprom_flash,
     e1000_num_eeprom_types
 } e1000_eeprom_type;
 
@@ -96,6 +98,7 @@ typedef enum {
     e1000_bus_type_unknown = 0,
     e1000_bus_type_pci,
     e1000_bus_type_pcix,
+    e1000_bus_type_pci_express,
     e1000_bus_type_reserved
 } e1000_bus_type;
 
@@ -107,6 +110,7 @@ typedef enum {
     e1000_bus_speed_100,
     e1000_bus_speed_120,
     e1000_bus_speed_133,
+    e1000_bus_speed_2500,
     e1000_bus_speed_reserved
 } e1000_bus_speed;
 
@@ -115,6 +119,8 @@ typedef enum {
     e1000_bus_width_unknown = 0,
     e1000_bus_width_32,
     e1000_bus_width_64,
+    e1000_bus_width_pciex_1,
+    e1000_bus_width_pciex_4,
     e1000_bus_width_reserved
 } e1000_bus_width;
 
@@ -196,6 +202,7 @@ typedef enum {
 typedef enum {
     e1000_phy_m88 = 0,
     e1000_phy_igp,
+    e1000_phy_igp_2,
     e1000_phy_undefined = 0xFF
 } e1000_phy_type;
 
@@ -242,8 +249,19 @@ struct e1000_eeprom_info {
     uint16_t address_bits;
     uint16_t delay_usec;
     uint16_t page_size;
+    boolean_t use_eerd;
+    boolean_t use_eewr;
 };
 
+/* Flex ASF Information */
+#define E1000_HOST_IF_MAX_SIZE  2048
+
+typedef enum {
+    e1000_byte_align = 0,
+    e1000_word_align = 1,
+    e1000_dword_align = 2
+} e1000_align_type;
+
 
 
 /* Error Codes */
@@ -254,11 +272,16 @@ struct e1000_eeprom_info {
 #define E1000_ERR_PARAM    4
 #define E1000_ERR_MAC_TYPE 5
 #define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
 
 /* Function prototypes */
 /* Initialization */
 int32_t e1000_reset_hw(struct e1000_hw *hw);
 int32_t e1000_init_hw(struct e1000_hw *hw);
+int32_t e1000_id_led_init(struct e1000_hw * hw);
 int32_t e1000_set_mac_type(struct e1000_hw *hw);
 void e1000_set_media_type(struct e1000_hw *hw);
 
@@ -275,7 +298,7 @@ int32_t e1000_force_mac_fc(struct e1000_
 /* 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_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);
@@ -287,13 +310,86 @@ int32_t e1000_check_downshift(struct e10
 int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
 
 /* EEPROM Functions */
-void e1000_init_eeprom_params(struct e1000_hw *hw);
+int32_t e1000_init_eeprom_params(struct e1000_hw *hw);
+boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw);
+int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd);
+
+/* MNG HOST IF functions */
+uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD   64
+#define E1000_HI_MAX_MNG_DATA_LENGTH    0x6F8   /* Host Interface data length */
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT  10      /* Time in ms to process MNG command */
+#define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0   /* Cookie offset */
+#define E1000_MNG_DHCP_COOKIE_LENGTH	0x10    /* Cookie length */
+#define E1000_MNG_IAMT_MODE		0x3
+#define E1000_IAMT_SIGNATURE            0x544D4149 /* Intel(R) Active Management Technology signature */
+
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT    0x2 /* DHCP parsing enabled */
+#define E1000_VFTA_ENTRY_SHIFT                       0x5
+#define E1000_VFTA_ENTRY_MASK                        0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK              0x1F
+
+struct e1000_host_mng_command_header {
+    uint8_t command_id;
+    uint8_t checksum;
+    uint16_t reserved1;
+    uint16_t reserved2;
+    uint16_t command_length;
+};
+
+struct e1000_host_mng_command_info {
+    struct e1000_host_mng_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command data can length 0..0x658*/
+};
+#ifdef __BIG_ENDIAN
+struct e1000_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint16_t vlan_id;
+    uint8_t reserved0;
+    uint8_t status;
+    uint32_t reserved1;
+    uint8_t checksum;
+    uint8_t reserved3;
+    uint16_t reserved2;
+};
+#else
+struct e1000_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint8_t status;
+    uint8_t reserved0;
+    uint16_t vlan_id;
+    uint32_t reserved1;
+    uint16_t reserved2;
+    uint8_t reserved3;
+    uint8_t checksum;
+};
+#endif
+
+int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer, 
+							uint16_t length);
+boolean_t e1000_check_mng_mode(struct e1000_hw *hw);
+boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
+int32_t e1000_mng_enable_host_if(struct e1000_hw *hw);
+int32_t e1000_mng_host_if_write(struct e1000_hw *hw, uint8_t *buffer,
+                            uint16_t length, uint16_t offset, uint8_t *sum);
+int32_t e1000_mng_write_cmd_header(struct e1000_hw* hw, 
+                                   struct e1000_host_mng_command_header* hdr);
+
+int32_t e1000_mng_write_commit(struct e1000_hw *hw);
+
 int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, 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 words, 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);
+int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
 
 /* Filters (multicast, vlan, receive) */
 void e1000_init_rx_addrs(struct e1000_hw *hw);
@@ -313,7 +409,6 @@ int32_t e1000_led_off(struct e1000_hw *h
 /* Adaptive IFS Functions */
 
 /* Everything else */
-uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw);
 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);
@@ -330,6 +425,19 @@ void e1000_io_write(struct e1000_hw *hw,
 void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
 int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up);
 int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active);
+int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active);
+void e1000_set_pci_express_master_disable(struct e1000_hw *hw);
+void e1000_enable_pciex_master(struct e1000_hw *hw);
+int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
+int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
+int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
+int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
+void e1000_release_software_semaphore(struct e1000_hw *hw);
+int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
+int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
+void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+int32_t e1000_commit_shadow_ram(struct e1000_hw *hw);
+uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
 
 #define E1000_READ_REG_IO(a, reg) \
     e1000_read_reg_io((a), E1000_##reg)
@@ -369,6 +477,11 @@ int32_t e1000_set_d3_lplu_state(struct e
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
 #define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
 
@@ -380,6 +493,7 @@ int32_t e1000_set_d3_lplu_state(struct e
 #define E1000_REVISION_0       0
 #define E1000_REVISION_1       1
 #define E1000_REVISION_2       2
+#define E1000_REVISION_3       3
 
 #define SPEED_10    10
 #define SPEED_100   100
@@ -436,6 +550,7 @@ int32_t e1000_set_d3_lplu_state(struct e
     E1000_IMS_RXSEQ  |    \
     E1000_IMS_LSC)
 
+
 /* 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
@@ -456,14 +571,74 @@ struct e1000_rx_desc {
     uint16_t special;
 };
 
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+    struct {
+        uint64_t buffer_addr;
+        uint64_t reserved;
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length;
+            uint16_t vlan;             /* VLAN tag */
+        } upper;
+    } wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+    struct {
+        /* one buffer for protocol header(s), three data buffers */
+        uint64_t buffer_addr[MAX_PS_BUFFERS];
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length0;          /* length of buffer 0 */
+            uint16_t vlan;             /* VLAN tag */
+        } middle;
+        struct {
+            uint16_t header_status;
+            uint16_t length[3];        /* length of buffers 1-3 */
+        } upper;
+        uint64_t reserved;
+    } wb; /* writeback */
+};
+
 /* 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_UDPCS    0x10    /* UDP xsum caculated */
 #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_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
 #define E1000_RXD_ERR_CE        0x01    /* CRC Error */
 #define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
 #define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
@@ -473,9 +648,20 @@ struct e1000_rx_desc {
 #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_PRI_SHIFT 13
 #define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
 
 /* mask to determine if packets should be dropped due to frame errors */
 #define E1000_RXD_ERR_FRAME_ERR_MASK ( \
@@ -485,6 +671,15 @@ struct e1000_rx_desc {
     E1000_RXD_ERR_CXE |                \
     E1000_RXD_ERR_RXE)
 
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
 /* Transmit Descriptor */
 struct e1000_tx_desc {
     uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
@@ -666,6 +861,7 @@ struct e1000_ffvt_entry {
 #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_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
 #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 */
@@ -675,9 +871,23 @@ struct e1000_ffvt_entry {
 #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_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
 #define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - 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 */
@@ -687,6 +897,7 @@ struct e1000_ffvt_entry {
 #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_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
 #define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
 #define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
 #define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
@@ -702,6 +913,14 @@ struct e1000_ffvt_entry {
 #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_TARC0    0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1   0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1   0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1   0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1     0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1     0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1  0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1    0x03940 /* TX Arbitration Count (1) */
 #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 */
@@ -760,7 +979,17 @@ struct e1000_ffvt_entry {
 #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_IAC       0x4100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC   0x4104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC   0x4108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC   0x410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC   0x4110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC   0x4118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC  0x411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC  0x4120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC    0x4124  /* Interrupt Cause Receiver Overrun Count */
 #define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
 #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 */
@@ -778,6 +1007,16 @@ struct e1000_ffvt_entry {
 #define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
 #define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
 
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
 /* Register Set (82542)
  *
  * Some of the 82542 registers are located at different offsets than they are
@@ -828,6 +1067,18 @@ struct e1000_ffvt_entry {
 #define E1000_82542_VFTA     0x00600
 #define E1000_82542_LEDCTL   E1000_LEDCTL
 #define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_PBS      E1000_PBS
+#define E1000_82542_EEMNGCTL E1000_EEMNGCTL
+#define E1000_82542_EEARBC   E1000_EEARBC
+#define E1000_82542_FLASHT   E1000_FLASHT
+#define E1000_82542_EEWR     E1000_EEWR
+#define E1000_82542_FLSWCTL  E1000_FLSWCTL
+#define E1000_82542_FLSWDATA E1000_FLSWDATA
+#define E1000_82542_FLSWCNT  E1000_FLSWCNT
+#define E1000_82542_FLOP     E1000_FLOP
+#define E1000_82542_EXTCNF_CTRL  E1000_EXTCNF_CTRL
+#define E1000_82542_EXTCNF_SIZE  E1000_EXTCNF_SIZE
+#define E1000_82542_ERT      E1000_ERT
 #define E1000_82542_RXDCTL   E1000_RXDCTL
 #define E1000_82542_RADV     E1000_RADV
 #define E1000_82542_RSRPD    E1000_RSRPD
@@ -912,6 +1163,38 @@ struct e1000_ffvt_entry {
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
 #define E1000_82542_HOST_IF  E1000_HOST_IF
+#define E1000_82542_IAM         E1000_IAM
+#define E1000_82542_EEMNGCTL    E1000_EEMNGCTL
+#define E1000_82542_PSRCTL      E1000_PSRCTL
+#define E1000_82542_RAID        E1000_RAID
+#define E1000_82542_TARC0       E1000_TARC0
+#define E1000_82542_TDBAL1      E1000_TDBAL1
+#define E1000_82542_TDBAH1      E1000_TDBAH1
+#define E1000_82542_TDLEN1      E1000_TDLEN1
+#define E1000_82542_TDH1        E1000_TDH1
+#define E1000_82542_TDT1        E1000_TDT1
+#define E1000_82542_TXDCTL1     E1000_TXDCTL1
+#define E1000_82542_TARC1       E1000_TARC1
+#define E1000_82542_RFCTL       E1000_RFCTL
+#define E1000_82542_GCR         E1000_GCR
+#define E1000_82542_GSCL_1      E1000_GSCL_1
+#define E1000_82542_GSCL_2      E1000_GSCL_2
+#define E1000_82542_GSCL_3      E1000_GSCL_3
+#define E1000_82542_GSCL_4      E1000_GSCL_4
+#define E1000_82542_FACTPS      E1000_FACTPS
+#define E1000_82542_SWSM        E1000_SWSM
+#define E1000_82542_FWSM        E1000_FWSM
+#define E1000_82542_FFLT_DBG    E1000_FFLT_DBG
+#define E1000_82542_IAC         E1000_IAC
+#define E1000_82542_ICRXPTC     E1000_ICRXPTC
+#define E1000_82542_ICRXATC     E1000_ICRXATC
+#define E1000_82542_ICTXPTC     E1000_ICTXPTC
+#define E1000_82542_ICTXATC     E1000_ICTXATC
+#define E1000_82542_ICTXQEC     E1000_ICTXQEC
+#define E1000_82542_ICTXQMTC    E1000_ICTXQMTC
+#define E1000_82542_ICRXDMTC    E1000_ICRXDMTC
+#define E1000_82542_ICRXOC      E1000_ICRXOC
+#define E1000_82542_HICR        E1000_HICR
 
 /* Statistics counters collected by the MAC */
 struct e1000_hw_stats {
@@ -973,11 +1256,21 @@ struct e1000_hw_stats {
     uint64_t bptc;
     uint64_t tsctc;
     uint64_t tsctfc;
+    uint64_t iac;
+    uint64_t icrxptc;
+    uint64_t icrxatc;
+    uint64_t ictxptc;
+    uint64_t ictxatc;
+    uint64_t ictxqec;
+    uint64_t ictxqmtc;
+    uint64_t icrxdmtc;
+    uint64_t icrxoc;
 };
 
 /* Structure containing variables used by the shared code (e1000_hw.c) */
 struct e1000_hw {
-    uint8_t __iomem *hw_addr;
+    uint8_t *hw_addr;
+    uint8_t *flash_address;
     e1000_mac_type mac_type;
     e1000_phy_type phy_type;
     uint32_t phy_init_script;
@@ -992,6 +1285,7 @@ struct e1000_hw {
     e1000_ms_type original_master_slave;
     e1000_ffe_config ffe_config_state;
     uint32_t asf_firmware_present;
+    uint32_t eeprom_semaphore_present;
     unsigned long io_base;
     uint32_t phy_id;
     uint32_t phy_revision;
@@ -1008,6 +1302,8 @@ struct e1000_hw {
     uint32_t ledctl_default;
     uint32_t ledctl_mode1;
     uint32_t ledctl_mode2;
+    boolean_t tx_pkt_filtering;
+    struct e1000_host_mng_dhcp_cookie mng_cookie;
     uint16_t phy_spd_default;
     uint16_t autoneg_advertised;
     uint16_t pci_cmd_word;
@@ -1046,16 +1342,24 @@ struct e1000_hw {
     boolean_t adaptive_ifs;
     boolean_t ifs_params_forced;
     boolean_t in_ifs_mode;
+    boolean_t mng_reg_access_disabled;
 };
 
 
 #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
 #define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
 /* 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_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
 #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 */
@@ -1069,6 +1373,7 @@ struct e1000_hw {
 #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_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
 #define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
@@ -1088,6 +1393,7 @@ struct e1000_hw {
 #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_SHIFT 2
 #define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
 #define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
 #define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
@@ -1097,6 +1403,8 @@ struct e1000_hw {
 #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_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 #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 */
@@ -1127,6 +1435,18 @@ struct e1000_hw {
 #ifndef E1000_EEPROM_GRANT_ATTEMPTS
 #define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
 
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
@@ -1170,6 +1490,8 @@ struct e1000_hw {
 #define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
 #define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
 #define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_IAME           0x08000000  /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000  /* Clear Interrupt timers after IMS clear */
 
 /* MDI Control */
 #define E1000_MDIC_DATA_MASK 0x0000FFFF
@@ -1186,14 +1508,17 @@ struct e1000_hw {
 /* LED Control */
 #define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
 #define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x0000020
 #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_BLINK_RATE      0x0002000
 #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_BLINK_RATE      0x00200000
 #define E1000_LEDCTL_LED2_IVRT            0x00400000
 #define E1000_LEDCTL_LED2_BLINK           0x00800000
 #define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
@@ -1237,6 +1562,10 @@ struct e1000_hw {
 #define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
 #define E1000_ICR_TXD_LOW       0x00008000
 #define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1254,6 +1583,9 @@ struct e1000_hw {
 #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
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1271,6 +1603,9 @@ struct e1000_hw {
 #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
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Interrupt Mask Clear */
 #define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1288,6 +1623,9 @@ struct e1000_hw {
 #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
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Receive Control */
 #define E1000_RCTL_RST            0x00000001    /* Software reset */
@@ -1300,6 +1638,8 @@ struct e1000_hw {
 #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_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
 #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 */
@@ -1326,6 +1666,34 @@ struct e1000_hw {
 #define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
 #define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
 #define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+    
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
 
 /* Receive Descriptor */
 #define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
@@ -1340,6 +1708,23 @@ struct e1000_hw {
 #define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
 #define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
 
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
 /* Receive Descriptor Control */
 #define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
 #define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
@@ -1353,6 +1738,8 @@ struct e1000_hw {
 #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 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+                                              still to be processed. */
 
 /* Transmit Configuration Word */
 #define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
@@ -1386,12 +1773,16 @@ struct e1000_hw {
 #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 */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
 
 /* 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 */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
@@ -1410,6 +1801,7 @@ struct e1000_hw {
 #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_IGNORE_TCO      0x00008000 /* Ignore WakeOn TCO packets */
 #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 */
@@ -1445,13 +1837,19 @@ struct e1000_hw {
 #define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
 #define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
                                              * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response 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_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
 #define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
                                                     * filtering */
 #define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
                                              * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
 #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 */
@@ -1462,11 +1860,97 @@ struct e1000_hw {
 #define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
 #define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
 
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK    0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT            1
+#define E1000_FWSM_FW_VALID     0x00008000 /* FW established a valid mode */
+
+/* FFLT Debug Register */
+#define E1000_FFLT_DBG_INVC     0x00100000 /* Invalid /C/ code handling */
+
+typedef enum {
+    e1000_mng_mode_none     = 0,
+    e1000_mng_mode_asf,
+    e1000_mng_mode_pt,
+    e1000_mng_mode_ipmi,
+    e1000_mng_mode_host_interface_only
+} e1000_mng_mode;
+
+/* Host Inteface Control Register */
+#define E1000_HICR_EN           0x00000001  /* Enable Bit - RO */
+#define E1000_HICR_C            0x00000002  /* Driver sets this bit when done
+                                             * to put command in RAM */
+#define E1000_HICR_SV           0x00000004  /* Status Validity */
+#define E1000_HICR_FWR          0x00000080  /* FW reset. Set by the Host */
+
+/* Host Interface Command Interface - Address range 0x8800-0x8EFF */
+#define E1000_HI_MAX_DATA_LENGTH         252 /* Host Interface data length */
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH  1792 /* Number of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH  448 /* Number of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT         500 /* Time in ms to process HI command */
+
+struct e1000_host_command_header {
+    uint8_t command_id;
+    uint8_t command_length;
+    uint8_t command_options;   /* I/F bits for command, status for return */
+    uint8_t checksum;
+};
+struct e1000_host_command_info {
+    struct e1000_host_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_DATA_LENGTH];   /* Command data can length 0..252 */
+};
+
+/* Host SMB register #0 */
+#define E1000_HSMC0R_CLKIN      0x00000001  /* SMB Clock in */
+#define E1000_HSMC0R_DATAIN     0x00000002  /* SMB Data in */
+#define E1000_HSMC0R_DATAOUT    0x00000004  /* SMB Data out */
+#define E1000_HSMC0R_CLKOUT     0x00000008  /* SMB Clock out */
+
+/* Host SMB register #1 */
+#define E1000_HSMC1R_CLKIN      E1000_HSMC0R_CLKIN
+#define E1000_HSMC1R_DATAIN     E1000_HSMC0R_DATAIN
+#define E1000_HSMC1R_DATAOUT    E1000_HSMC0R_DATAOUT
+#define E1000_HSMC1R_CLKOUT     E1000_HSMC0R_CLKOUT
+
+/* FW Status Register */
+#define E1000_FWSTS_FWS_MASK    0x000000FF  /* FW Status */
+
 /* Wake Up Packet Length */
 #define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
 
 #define E1000_MDALIGN          4096
 
+#define E1000_GCR_BEM32                 0x00400000
+/* Function Active and Power State to MNG */
+#define E1000_FACTPS_FUNC0_POWER_STATE_MASK         0x00000003
+#define E1000_FACTPS_LAN0_VALID                     0x00000004
+#define E1000_FACTPS_FUNC0_AUX_EN                   0x00000008
+#define E1000_FACTPS_FUNC1_POWER_STATE_MASK         0x000000C0
+#define E1000_FACTPS_FUNC1_POWER_STATE_SHIFT        6
+#define E1000_FACTPS_LAN1_VALID                     0x00000100
+#define E1000_FACTPS_FUNC1_AUX_EN                   0x00000200
+#define E1000_FACTPS_FUNC2_POWER_STATE_MASK         0x00003000
+#define E1000_FACTPS_FUNC2_POWER_STATE_SHIFT        12
+#define E1000_FACTPS_IDE_ENABLE                     0x00004000
+#define E1000_FACTPS_FUNC2_AUX_EN                   0x00008000
+#define E1000_FACTPS_FUNC3_POWER_STATE_MASK         0x000C0000
+#define E1000_FACTPS_FUNC3_POWER_STATE_SHIFT        18
+#define E1000_FACTPS_SP_ENABLE                      0x00100000
+#define E1000_FACTPS_FUNC3_AUX_EN                   0x00200000
+#define E1000_FACTPS_FUNC4_POWER_STATE_MASK         0x03000000
+#define E1000_FACTPS_FUNC4_POWER_STATE_SHIFT        24
+#define E1000_FACTPS_IPMI_ENABLE                    0x04000000
+#define E1000_FACTPS_FUNC4_AUX_EN                   0x08000000
+#define E1000_FACTPS_MNGCG                          0x20000000
+#define E1000_FACTPS_LAN_FUNC_SEL                   0x40000000
+#define E1000_FACTPS_PM_STATE_CHANGED               0x80000000
+
 /* EEPROM Commands - Microwire */
 #define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
 #define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
@@ -1476,22 +1960,20 @@ struct e1000_hw {
 
 /* EEPROM Commands - SPI */
 #define EEPROM_MAX_RETRY_SPI    5000 /* Max wait of 5ms, for RDY signal */
-#define EEPROM_READ_OPCODE_SPI  0x3  /* EEPROM read opcode */
-#define EEPROM_WRITE_OPCODE_SPI 0x2  /* EEPROM write opcode */
-#define EEPROM_A8_OPCODE_SPI    0x8  /* opcode bit-3 = address bit-8 */
-#define EEPROM_WREN_OPCODE_SPI  0x6  /* EEPROM set Write Enable latch */
-#define EEPROM_WRDI_OPCODE_SPI  0x4  /* EEPROM reset Write Enable latch */
-#define EEPROM_RDSR_OPCODE_SPI  0x5  /* EEPROM read Status register */
-#define EEPROM_WRSR_OPCODE_SPI  0x1  /* EEPROM write Status register */
+#define EEPROM_READ_OPCODE_SPI      0x03  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI     0x02  /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI        0x08  /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI      0x06  /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI      0x04  /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI      0x05  /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI      0x01  /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI   0x20  /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI  0xD8  /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI  0xDB  /* EEPROM ERASE 256B */
 
 /* EEPROM Size definitions */
-#define EEPROM_SIZE_16KB        0x1800
-#define EEPROM_SIZE_8KB         0x1400
-#define EEPROM_SIZE_4KB         0x1000
-#define EEPROM_SIZE_2KB         0x0C00
-#define EEPROM_SIZE_1KB         0x0800
-#define EEPROM_SIZE_512B        0x0400
-#define EEPROM_SIZE_128B        0x0000
+#define EEPROM_WORD_SIZE_SHIFT  6
+#define EEPROM_SIZE_SHIFT       10
 #define EEPROM_SIZE_MASK        0x1C00
 
 /* EEPROM Word Offsets */
@@ -1605,7 +2087,22 @@ struct e1000_hw {
 #define IFS_MIN                40
 #define IFS_RATIO              4
 
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_PHY_WRITE_ENABLE  0x00000002
+#define E1000_EXTCNF_CTRL_D_UD_ENABLE       0x00000004
+#define E1000_EXTCNF_CTRL_D_UD_LATENCY      0x00000008
+#define E1000_EXTCNF_CTRL_D_UD_OWNER        0x00000010
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER   0x1FFF0000
+
+#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH    0x000000FF
+#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH   0x0000FF00
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH   0x00FF0000
+
 /* PBA constants */
+#define E1000_PBA_12K 0x000C    /* 12KB, default Rx allocation */
 #define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
 #define E1000_PBA_22K 0x0016
 #define E1000_PBA_24K 0x0018
@@ -1662,6 +2159,13 @@ struct e1000_hw {
 /* Number of milliseconds we wait for auto-negotiation to complete */
 #define LINK_UP_TIMEOUT             500
 
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
+#define AUTO_READ_DONE_TIMEOUT      10
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             40
+
 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
 
 /* The carrier extension symbol, as received by the NIC. */
@@ -1734,6 +2238,9 @@ struct e1000_hw {
 #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
 #define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
 
+#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
+
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
 #define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
@@ -1759,6 +2266,7 @@ struct e1000_hw {
 #define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
 #define IGP01E1000_GMII_FIFO       0x14 /* GMII FIFO Register */
 #define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT      0x19
 #define IGP01E1000_PHY_PAGE_SELECT     0x1F /* PHY Page Select Core Register */
 
 /* IGP01E1000 AGC Registers - stores the cable length values*/
@@ -1767,12 +2275,20 @@ struct e1000_hw {
 #define IGP01E1000_PHY_AGC_C        0x1472
 #define IGP01E1000_PHY_AGC_D        0x1872
 
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A        0x11B1
+#define IGP02E1000_PHY_AGC_B        0x12B1
+#define IGP02E1000_PHY_AGC_C        0x14B1
+#define IGP02E1000_PHY_AGC_D        0x18B1
+
 /* IGP01E1000 DSP Reset Register */
 #define IGP01E1000_PHY_DSP_RESET   0x1F33
 #define IGP01E1000_PHY_DSP_SET     0x1F71
 #define IGP01E1000_PHY_DSP_FFE     0x1F35
 
 #define IGP01E1000_PHY_CHANNEL_NUM    4
+#define IGP02E1000_PHY_CHANNEL_NUM    4
+
 #define IGP01E1000_PHY_AGC_PARAM_A    0x1171
 #define IGP01E1000_PHY_AGC_PARAM_B    0x1271
 #define IGP01E1000_PHY_AGC_PARAM_C    0x1471
@@ -1794,8 +2310,7 @@ struct e1000_hw {
 
 #define IGP01E1000_ANALOG_REGS_PAGE  0x20C0
 
-#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG  0xF     /*Registers that are equal on all pages*/
+
 /* 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 */
@@ -2057,20 +2572,30 @@ struct e1000_hw {
 #define IGP01E1000_MSE_CHANNEL_B        0x0F00
 #define IGP01E1000_MSE_CHANNEL_A        0xF000
 
+#define IGP02E1000_PM_SPD                         0x0001  /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU                     0x0004  /* Enable LPLU in non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU                     0x0002  /* Enable LPLU in D0a mode */
+
 /* IGP01E1000 DSP reset macros */
 #define DSP_RESET_ENABLE     0x0
 #define DSP_RESET_DISABLE    0x2
 #define E1000_MAX_DSP_RESETS 10
 
-/* IGP01E1000 AGC Registers */
+/* IGP01E1000 & IGP02E1000 AGC Registers */
 
 #define IGP01E1000_AGC_LENGTH_SHIFT 7         /* Coarse - 13:11, Fine - 10:7 */
+#define IGP02E1000_AGC_LENGTH_SHIFT 9         /* Coarse - 15:13, Fine - 12:9 */
+
+/* IGP02E1000 AGC Register Length 9-bit mask */
+#define IGP02E1000_AGC_LENGTH_MASK  0x7F
 
 /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
 #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128
 
-/* The precision of the length is +/- 10 meters */
+/* The precision error of the cable length is +/- 10 meters */
 #define IGP01E1000_AGC_RANGE    10
+#define IGP02E1000_AGC_RANGE    10
 
 /* IGP01E1000 PCS Initialization register */
 /* bits 3:6 in the PCS registers stores the channels polarity */
@@ -2098,7 +2623,11 @@ struct e1000_hw {
 #define IGP01E1000_ANALOG_FUSE_FINE_1               0x0080
 #define IGP01E1000_ANALOG_FUSE_FINE_10              0x0500
 
+
 /* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
 #define M88E1000_E_PHY_ID  0x01410C50
 #define M88E1000_I_PHY_ID  0x01410C30
 #define M88E1011_I_PHY_ID  0x01410C20
@@ -2106,6 +2635,8 @@ struct e1000_hw {
 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
 #define M88E1011_I_REV_4   0x04
+#define M88E1111_I_PHY_ID  0x01410CC0
+#define L1LXT971A_PHY_ID   0x001378E0
 
 /* Miscellaneous PHY bit definitions. */
 #define PHY_PREAMBLE        0xFFFFFFFF
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -29,25 +29,9 @@
 #include "e1000.h"
 
 /* Change Log
- * 5.3.12	6/7/04
- * - kcompat NETIF_MSG for older kernels (2.4.9) <sean.p.mcdermott@intel.com>
- * - if_mii support and associated kcompat for older kernels
- * - More errlogging support from Jon Mason <jonmason@us.ibm.com>
- * - Fix TSO issues on PPC64 machines -- Jon Mason <jonmason@us.ibm.com>
- *
- * 5.6.5 	11/01/04
- * - Enabling NETIF_F_SG without checksum offload is illegal - 
-     John Mason <jdmason@us.ibm.com>
- * 5.6.3        10/26/04
- * - Remove redundant initialization - Jamal Hadi
- * - Reset buffer_info->dma in tx resource cleanup logic
- * 5.6.2	10/12/04
- * - Avoid filling tx_ring completely - shemminger@osdl.org
- * - Replace schedule_timeout() with msleep()/msleep_interruptible() -
- *   nacc@us.ibm.com
- * - Sparse cleanup - shemminger@osdl.org
- * - Fix tx resource cleanup logic
- * - LLTX support - ak@suse.de and hadi@cyberus.ca
+ * 6.0.44+	2/15/05
+ *   o applied Anton's patch to resolve tx hang in hardware
+ *   o Applied Andrew Mortons patch - e1000 stops working after resume
  */
 
 char e1000_driver_name[] = "e1000";
@@ -57,7 +41,8 @@ char e1000_driver_string[] = "Intel(R) P
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-char e1000_driver_version[] = "5.6.10.1-k2"DRIVERNAPI;
+#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+char e1000_driver_version[] = DRV_VERSION;
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -81,11 +66,13 @@ static struct pci_device_id e1000_pci_tb
 	INTEL_E1000_ETHERNET_DEVICE(0x1011),
 	INTEL_E1000_ETHERNET_DEVICE(0x1012),
 	INTEL_E1000_ETHERNET_DEVICE(0x1013),
+	INTEL_E1000_ETHERNET_DEVICE(0x1014),
 	INTEL_E1000_ETHERNET_DEVICE(0x1015),
 	INTEL_E1000_ETHERNET_DEVICE(0x1016),
 	INTEL_E1000_ETHERNET_DEVICE(0x1017),
 	INTEL_E1000_ETHERNET_DEVICE(0x1018),
 	INTEL_E1000_ETHERNET_DEVICE(0x1019),
+	INTEL_E1000_ETHERNET_DEVICE(0x101A),
 	INTEL_E1000_ETHERNET_DEVICE(0x101D),
 	INTEL_E1000_ETHERNET_DEVICE(0x101E),
 	INTEL_E1000_ETHERNET_DEVICE(0x1026),
@@ -100,6 +87,9 @@ static struct pci_device_id e1000_pci_tb
 	INTEL_E1000_ETHERNET_DEVICE(0x107B),
 	INTEL_E1000_ETHERNET_DEVICE(0x107C),
 	INTEL_E1000_ETHERNET_DEVICE(0x108A),
+	INTEL_E1000_ETHERNET_DEVICE(0x108B),
+	INTEL_E1000_ETHERNET_DEVICE(0x108C),
+	INTEL_E1000_ETHERNET_DEVICE(0x1099),
 	/* required last entry */
 	{0,}
 };
@@ -133,6 +123,7 @@ static void e1000_clean_rx_ring(struct e
 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 void e1000_watchdog_task(struct e1000_adapter *adapter);
 static void e1000_82547_tx_fifo_stall(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);
@@ -144,10 +135,14 @@ static boolean_t e1000_clean_tx_irq(stru
 static int e1000_clean(struct net_device *netdev, int *budget);
 static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
                                     int *work_done, int work_to_do);
+static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+                                       int *work_done, int work_to_do);
 #else
 static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter);
 #endif
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter);
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
 static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
 			   int cmd);
@@ -201,6 +196,7 @@ static struct pci_driver e1000_driver = 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
 module_param(debug, int, 0);
@@ -274,7 +270,29 @@ e1000_irq_enable(struct e1000_adapter *a
 		E1000_WRITE_FLUSH(&adapter->hw);
 	}
 }
-
+void
+e1000_update_mng_vlan(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	uint16_t vid = adapter->hw.mng_cookie.vlan_id;
+	uint16_t old_vid = adapter->mng_vlan_id;
+	if(adapter->vlgrp) {
+		if(!adapter->vlgrp->vlan_devices[vid]) {
+			if(adapter->hw.mng_cookie.status &
+				E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) {
+				e1000_vlan_rx_add_vid(netdev, vid);
+				adapter->mng_vlan_id = vid;
+			} else
+				adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+				
+			if((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) &&
+					(vid != old_vid) && 
+					!adapter->vlgrp->vlan_devices[old_vid])
+				e1000_vlan_rx_kill_vid(netdev, old_vid);
+		}
+	}
+}
+	
 int
 e1000_up(struct e1000_adapter *adapter)
 {
@@ -298,14 +316,31 @@ e1000_up(struct e1000_adapter *adapter)
 	e1000_configure_tx(adapter);
 	e1000_setup_rctl(adapter);
 	e1000_configure_rx(adapter);
-	e1000_alloc_rx_buffers(adapter);
+	adapter->alloc_rx_buf(adapter);
 
+#ifdef CONFIG_PCI_MSI
+	if(adapter->hw.mac_type > e1000_82547_rev_2) {
+		adapter->have_msi = TRUE;
+		if((err = pci_enable_msi(adapter->pdev))) {
+			DPRINTK(PROBE, ERR,
+			 "Unable to allocate MSI interrupt Error: %d\n", err);
+			adapter->have_msi = FALSE;
+		}
+	}
+#endif
 	if((err = request_irq(adapter->pdev->irq, &e1000_intr,
 		              SA_SHIRQ | SA_SAMPLE_RANDOM,
-		              netdev->name, netdev)))
+		              netdev->name, netdev))) {
+		DPRINTK(PROBE, ERR,
+		    "Unable to allocate interrupt Error: %d\n", err);
 		return err;
+	}
 
 	mod_timer(&adapter->watchdog_timer, jiffies);
+
+#ifdef CONFIG_E1000_NAPI
+	netif_poll_enable(netdev);
+#endif
 	e1000_irq_enable(adapter);
 
 	return 0;
@@ -318,9 +353,18 @@ e1000_down(struct e1000_adapter *adapter
 
 	e1000_irq_disable(adapter);
 	free_irq(adapter->pdev->irq, netdev);
+#ifdef CONFIG_PCI_MSI
+	if(adapter->hw.mac_type > e1000_82547_rev_2 &&
+	   adapter->have_msi == TRUE)
+		pci_disable_msi(adapter->pdev);
+#endif
 	del_timer_sync(&adapter->tx_fifo_stall_timer);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
+
+#ifdef CONFIG_E1000_NAPI
+	netif_poll_disable(netdev);
+#endif
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 	netif_carrier_off(netdev);
@@ -331,62 +375,93 @@ e1000_down(struct e1000_adapter *adapter
 	e1000_clean_rx_ring(adapter);
 
 	/* If WoL is not enabled
+	 * and management mode is not IAMT
 	 * Power down the PHY so no link is implied when interface is down */
-	if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) {
+	if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.media_type == e1000_media_type_copper &&
+	   !e1000_check_mng_mode(&adapter->hw) &&
+	   !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) {
 		uint16_t mii_reg;
 		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
 		mii_reg |= MII_CR_POWER_DOWN;
 		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+		mdelay(1);
 	}
 }
 
 void
 e1000_reset(struct e1000_adapter *adapter)
 {
-	uint32_t pba;
+	struct net_device *netdev = adapter->netdev;
+	uint32_t pba, manc;
+	uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF;
+	uint16_t fc_low_water_mark = E1000_FC_LOW_DIFF;
 
 	/* Repartition Pba for greater than 9k mtu
 	 * To take effect CTRL.RST is required.
 	 */
 
-	if(adapter->hw.mac_type < e1000_82547) {
-		if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
-			pba = E1000_PBA_40K;
-		else
-			pba = E1000_PBA_48K;
-	} else {
-		if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
-			pba = E1000_PBA_22K;
-		else
-			pba = E1000_PBA_30K;
+	switch (adapter->hw.mac_type) {
+	case e1000_82547:
+	case e1000_82547_rev_2:
+		pba = E1000_PBA_30K;
+		break;
+	case e1000_82573:
+		pba = E1000_PBA_12K;
+		break;
+	default:
+		pba = E1000_PBA_48K;
+		break;
+	}
+
+	if((adapter->hw.mac_type != e1000_82573) &&
+	   (adapter->rx_buffer_len > E1000_RXBUFFER_8192)) {
+		pba -= 8; /* allocate more FIFO for Tx */
+		/* send an XOFF when there is enough space in the
+		 * Rx FIFO to hold one extra full size Rx packet 
+		*/
+		fc_high_water_mark = netdev->mtu + ENET_HEADER_SIZE + 
+					ETHERNET_FCS_SIZE + 1;
+		fc_low_water_mark = fc_high_water_mark + 8;
+	}
+
+
+	if(adapter->hw.mac_type == e1000_82547) {
 		adapter->tx_fifo_head = 0;
 		adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
 		adapter->tx_fifo_size =
 			(E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
 		atomic_set(&adapter->tx_fifo_stall, 0);
 	}
+
 	E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
 	/* flow control settings */
 	adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) -
-				    E1000_FC_HIGH_DIFF;
+				    fc_high_water_mark;
 	adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) -
-				   E1000_FC_LOW_DIFF;
+				   fc_low_water_mark;
 	adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME;
 	adapter->hw.fc_send_xon = 1;
 	adapter->hw.fc = adapter->hw.original_fc;
 
+	/* Allow time for pending master requests to run */
 	e1000_reset_hw(&adapter->hw);
 	if(adapter->hw.mac_type >= e1000_82544)
 		E1000_WRITE_REG(&adapter->hw, WUC, 0);
 	if(e1000_init_hw(&adapter->hw))
 		DPRINTK(PROBE, ERR, "Hardware Error\n");
-
+	e1000_update_mng_vlan(adapter);
 	/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
 	E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
 
 	e1000_reset_adaptive(&adapter->hw);
 	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+	if (adapter->en_mng_pt) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
+		E1000_WRITE_REG(&adapter->hw, MANC, manc);
+	}
 }
 
 /**
@@ -407,14 +482,13 @@ e1000_probe(struct pci_dev *pdev,
 {
 	struct net_device *netdev;
 	struct e1000_adapter *adapter;
+	unsigned long mmio_start, mmio_len;
+	uint32_t swsm;
+
 	static int cards_found = 0;
-	unsigned long mmio_start;
-	int mmio_len;
-	int pci_using_dac;
-	int i;
-	int err;
+	int i, err, pci_using_dac;
 	uint16_t eeprom_data;
-
+	uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
 	if((err = pci_enable_device(pdev)))
 		return err;
 
@@ -501,6 +575,9 @@ e1000_probe(struct pci_dev *pdev,
 	if((err = e1000_sw_init(adapter)))
 		goto err_sw_init;
 
+	if((err = e1000_check_phy_reset_block(&adapter->hw)))
+		DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
+
 	if(adapter->hw.mac_type >= e1000_82543) {
 		netdev->features = NETIF_F_SG |
 				   NETIF_F_HW_CSUM |
@@ -510,12 +587,14 @@ e1000_probe(struct pci_dev *pdev,
 	}
 
 #ifdef NETIF_F_TSO
-	/* Disbaled for now until root-cause is found for
-	 * hangs reported against non-IA archs.  TSO can be
-	 * enabled using ethtool -K eth<x> tso on */
 	if((adapter->hw.mac_type >= e1000_82544) &&
 	   (adapter->hw.mac_type != e1000_82547))
 		netdev->features |= NETIF_F_TSO;
+
+#ifdef NETIF_F_TSO_IPV6
+	if(adapter->hw.mac_type > e1000_82547_rev_2)
+		netdev->features |= NETIF_F_TSO_IPV6;
+#endif
 #endif
 	if(pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
@@ -523,6 +602,8 @@ e1000_probe(struct pci_dev *pdev,
  	/* hard_start_xmit is safe against parallel locking */
  	netdev->features |= NETIF_F_LLTX; 
  
+	adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
+
 	/* before reading the EEPROM, reset the controller to 
 	 * put the device in a known good starting state */
 	
@@ -538,7 +619,7 @@ e1000_probe(struct pci_dev *pdev,
 
 	/* copy the MAC address out of the EEPROM */
 
-	if (e1000_read_mac_addr(&adapter->hw))
+	if(e1000_read_mac_addr(&adapter->hw))
 		DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
@@ -560,6 +641,9 @@ e1000_probe(struct pci_dev *pdev,
 	adapter->watchdog_timer.function = &e1000_watchdog;
 	adapter->watchdog_timer.data = (unsigned long) adapter;
 
+	INIT_WORK(&adapter->watchdog_task,
+		(void (*)(void *))e1000_watchdog_task, adapter);
+
 	init_timer(&adapter->phy_info_timer);
 	adapter->phy_info_timer.function = &e1000_update_phy_info;
 	adapter->phy_info_timer.data = (unsigned long) adapter;
@@ -584,6 +668,11 @@ e1000_probe(struct pci_dev *pdev,
 	case e1000_82542_rev2_1:
 	case e1000_82543:
 		break;
+	case e1000_82544:
+		e1000_read_eeprom(&adapter->hw,
+			EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
+		eeprom_apme_mask = E1000_EEPROM_82544_APM;
+		break;
 	case e1000_82546:
 	case e1000_82546_rev_3:
 		if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
@@ -598,12 +687,23 @@ e1000_probe(struct pci_dev *pdev,
 			EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
 		break;
 	}
-	if(eeprom_data & E1000_EEPROM_APME)
+	if(eeprom_data & eeprom_apme_mask)
 		adapter->wol |= E1000_WUFC_MAG;
 
 	/* reset the hardware with the new settings */
 	e1000_reset(adapter);
 
+	/* Let firmware know the driver has taken over */
+	switch(adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm | E1000_SWSM_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+
 	strcpy(netdev->name, "eth%d");
 	if((err = register_netdev(netdev)))
 		goto err_register;
@@ -639,7 +739,9 @@ e1000_remove(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t manc;
+	uint32_t manc, swsm;
+
+	flush_scheduled_work();
 
 	if(adapter->hw.mac_type >= e1000_82540 &&
 	   adapter->hw.media_type == e1000_media_type_copper) {
@@ -650,9 +752,21 @@ e1000_remove(struct pci_dev *pdev)
 		}
 	}
 
+	switch(adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm & ~E1000_SWSM_DRV_LOAD);
+		break;
+
+	default:
+		break;
+	}
+
 	unregister_netdev(netdev);
 
-	e1000_phy_hw_reset(&adapter->hw);
+	if(!e1000_check_phy_reset_block(&adapter->hw))
+		e1000_phy_hw_reset(&adapter->hw);
 
 	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
@@ -690,6 +804,7 @@ e1000_sw_init(struct e1000_adapter *adap
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
 
 	adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+	adapter->rx_ps_bsize0 = E1000_RXBUFFER_256;
 	hw->max_frame_size = netdev->mtu +
 			     ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
@@ -703,7 +818,10 @@ e1000_sw_init(struct e1000_adapter *adap
 
 	/* initialize eeprom parameters */
 
-	e1000_init_eeprom_params(hw);
+	if(e1000_init_eeprom_params(hw)) {
+		E1000_ERR("EEPROM initialization failed\n");
+		return -EIO;
+	}
 
 	switch(hw->mac_type) {
 	default:
@@ -768,6 +886,11 @@ e1000_open(struct net_device *netdev)
 
 	if((err = e1000_up(adapter)))
 		goto err_up;
+	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+	if((adapter->hw.mng_cookie.status &
+			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
+		e1000_update_mng_vlan(adapter);
+	}
 
 	return E1000_SUCCESS;
 
@@ -803,10 +926,37 @@ e1000_close(struct net_device *netdev)
 	e1000_free_tx_resources(adapter);
 	e1000_free_rx_resources(adapter);
 
+	if((adapter->hw.mng_cookie.status &
+			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
+		e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+	}
 	return 0;
 }
 
 /**
+ * e1000_check_64k_bound - check that memory doesn't cross 64kB boundary
+ * @adapter: address of board private structure
+ * @start: address of beginning of memory
+ * @len: length of memory
+ **/
+static inline boolean_t
+e1000_check_64k_bound(struct e1000_adapter *adapter,
+		      void *start, unsigned long len)
+{
+	unsigned long begin = (unsigned long) start;
+	unsigned long end = begin + len;
+
+	/* First rev 82545 and 82546 need to not allow any memory
+	 * write location to cross 64k boundary due to errata 23 */
+	if (adapter->hw.mac_type == e1000_82545 ||
+	    adapter->hw.mac_type == e1000_82546) {
+		return ((begin ^ (end - 1)) >> 16) != 0 ? FALSE : TRUE;
+	}
+
+	return TRUE;
+}
+
+/**
  * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
  * @adapter: board private structure
  *
@@ -823,8 +973,8 @@ e1000_setup_tx_resources(struct e1000_ad
 	size = sizeof(struct e1000_buffer) * txdr->count;
 	txdr->buffer_info = vmalloc(size);
 	if(!txdr->buffer_info) {
-		DPRINTK(PROBE, ERR, 
-		"Unble to Allocate Memory for the Transmit descriptor ring\n");
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the transmit descriptor ring\n");
 		return -ENOMEM;
 	}
 	memset(txdr->buffer_info, 0, size);
@@ -836,11 +986,42 @@ e1000_setup_tx_resources(struct e1000_ad
 
 	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
 	if(!txdr->desc) {
-		DPRINTK(PROBE, ERR, 
-		"Unble to Allocate Memory for the Transmit descriptor ring\n");
+setup_tx_desc_die:
 		vfree(txdr->buffer_info);
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the transmit descriptor ring\n");
 		return -ENOMEM;
 	}
+
+	/* Fix for errata 23, can't cross 64kB boundary */
+	if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
+		void *olddesc = txdr->desc;
+		dma_addr_t olddma = txdr->dma;
+		DPRINTK(TX_ERR, ERR, "txdr align check failed: %u bytes "
+				     "at %p\n", txdr->size, txdr->desc);
+		/* Try again, without freeing the previous */
+		txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+		if(!txdr->desc) {
+		/* Failed allocation, critical failure */
+			pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+			goto setup_tx_desc_die;
+		}
+
+		if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
+			/* give up */
+			pci_free_consistent(pdev, txdr->size, txdr->desc,
+					    txdr->dma);
+			pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+			DPRINTK(PROBE, ERR,
+				"Unable to allocate aligned memory "
+				"for the transmit descriptor ring\n");
+			vfree(txdr->buffer_info);
+			return -ENOMEM;
+		} else {
+			/* Free old allocation, new allocation was successful */
+			pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+		}
+	}
 	memset(txdr->desc, 0, txdr->size);
 
 	txdr->next_to_use = 0;
@@ -939,30 +1120,91 @@ e1000_setup_rx_resources(struct e1000_ad
 {
 	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
 	struct pci_dev *pdev = adapter->pdev;
-	int size;
+	int size, desc_len;
 
 	size = sizeof(struct e1000_buffer) * rxdr->count;
 	rxdr->buffer_info = vmalloc(size);
 	if(!rxdr->buffer_info) {
-		DPRINTK(PROBE, ERR, 
-		"Unble to Allocate Memory for the Recieve descriptor ring\n");
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the receive descriptor ring\n");
 		return -ENOMEM;
 	}
 	memset(rxdr->buffer_info, 0, size);
 
+	size = sizeof(struct e1000_ps_page) * rxdr->count;
+	rxdr->ps_page = kmalloc(size, GFP_KERNEL);
+	if(!rxdr->ps_page) {
+		vfree(rxdr->buffer_info);
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the receive descriptor ring\n");
+		return -ENOMEM;
+	}
+	memset(rxdr->ps_page, 0, size);
+
+	size = sizeof(struct e1000_ps_page_dma) * rxdr->count;
+	rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL);
+	if(!rxdr->ps_page_dma) {
+		vfree(rxdr->buffer_info);
+		kfree(rxdr->ps_page);
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the receive descriptor ring\n");
+		return -ENOMEM;
+	}
+	memset(rxdr->ps_page_dma, 0, size);
+
+	if(adapter->hw.mac_type <= e1000_82547_rev_2)
+		desc_len = sizeof(struct e1000_rx_desc);
+	else
+		desc_len = sizeof(union e1000_rx_desc_packet_split);
+
 	/* Round up to nearest 4K */
 
-	rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
+	rxdr->size = rxdr->count * desc_len;
 	E1000_ROUNDUP(rxdr->size, 4096);
 
 	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
 	if(!rxdr->desc) {
-		DPRINTK(PROBE, ERR, 
-		"Unble to Allocate Memory for the Recieve descriptor ring\n");
+setup_rx_desc_die:
 		vfree(rxdr->buffer_info);
+		kfree(rxdr->ps_page);
+		kfree(rxdr->ps_page_dma);
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the receive descriptor ring\n");
 		return -ENOMEM;
 	}
+
+	/* Fix for errata 23, can't cross 64kB boundary */
+	if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
+		void *olddesc = rxdr->desc;
+		dma_addr_t olddma = rxdr->dma;
+		DPRINTK(RX_ERR, ERR, "rxdr align check failed: %u bytes "
+				     "at %p\n", rxdr->size, rxdr->desc);
+		/* Try again, without freeing the previous */
+		rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+		if(!rxdr->desc) {
+		/* Failed allocation, critical failure */
+			pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+			goto setup_rx_desc_die;
+		}
+
+		if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
+			/* give up */
+			pci_free_consistent(pdev, rxdr->size, rxdr->desc,
+					    rxdr->dma);
+			pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+			DPRINTK(PROBE, ERR,
+				"Unable to allocate aligned memory "
+				"for the receive descriptor ring\n");
+			vfree(rxdr->buffer_info);
+			kfree(rxdr->ps_page);
+			kfree(rxdr->ps_page_dma);
+			return -ENOMEM;
+		} else {
+			/* Free old allocation, new allocation was successful */
+			pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+		}
+	}
 	memset(rxdr->desc, 0, rxdr->size);
 
 	rxdr->next_to_clean = 0;
@@ -972,14 +1214,15 @@ e1000_setup_rx_resources(struct e1000_ad
 }
 
 /**
- * e1000_setup_rctl - configure the receive control register
+ * e1000_setup_rctl - configure the receive control registers
  * @adapter: Board private structure
  **/
 
 static void
 e1000_setup_rctl(struct e1000_adapter *adapter)
 {
-	uint32_t rctl;
+	uint32_t rctl, rfctl;
+	uint32_t psrctl = 0;
 
 	rctl = E1000_READ_REG(&adapter->hw, RCTL);
 
@@ -994,24 +1237,69 @@ e1000_setup_rctl(struct e1000_adapter *a
 	else
 		rctl &= ~E1000_RCTL_SBP;
 
+	if (adapter->netdev->mtu <= ETH_DATA_LEN)
+		rctl &= ~E1000_RCTL_LPE;
+	else
+		rctl |= E1000_RCTL_LPE;
+
 	/* Setup buffer sizes */
-	rctl &= ~(E1000_RCTL_SZ_4096);
-	rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE);
-	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;
-		break;
-	case E1000_RXBUFFER_8192:
-		rctl |= E1000_RCTL_SZ_8192;
-		break;
-	case E1000_RXBUFFER_16384:
-		rctl |= E1000_RCTL_SZ_16384;
-		break;
+	if(adapter->hw.mac_type == e1000_82573) {
+		/* We can now specify buffers in 1K increments.
+		 * BSIZE and BSEX are ignored in this case. */
+		rctl |= adapter->rx_buffer_len << 0x11;
+	} else {
+		rctl &= ~E1000_RCTL_SZ_4096;
+		rctl |= E1000_RCTL_BSEX; 
+		switch (adapter->rx_buffer_len) {
+		case E1000_RXBUFFER_2048:
+		default:
+			rctl |= E1000_RCTL_SZ_2048;
+			rctl &= ~E1000_RCTL_BSEX;
+			break;
+		case E1000_RXBUFFER_4096:
+			rctl |= E1000_RCTL_SZ_4096;
+			break;
+		case E1000_RXBUFFER_8192:
+			rctl |= E1000_RCTL_SZ_8192;
+			break;
+		case E1000_RXBUFFER_16384:
+			rctl |= E1000_RCTL_SZ_16384;
+			break;
+		}
+	}
+
+#ifdef CONFIG_E1000_PACKET_SPLIT
+	/* 82571 and greater support packet-split where the protocol
+	 * header is placed in skb->data and the packet data is
+	 * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+	 * In the case of a non-split, skb->data is linearly filled,
+	 * followed by the page buffers.  Therefore, skb->data is
+	 * sized to hold the largest protocol header.
+	 */
+	adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2) 
+			  && (adapter->netdev->mtu 
+	                      < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0));
+#endif
+	if(adapter->rx_ps) {
+		/* Configure extra packet-split registers */
+		rfctl = E1000_READ_REG(&adapter->hw, RFCTL);
+		rfctl |= E1000_RFCTL_EXTEN;
+		/* disable IPv6 packet split support */
+		rfctl |= E1000_RFCTL_IPV6_DIS;
+		E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
+
+		rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
+		
+		psrctl |= adapter->rx_ps_bsize0 >>
+			E1000_PSRCTL_BSIZE0_SHIFT;
+		psrctl |= PAGE_SIZE >>
+			E1000_PSRCTL_BSIZE1_SHIFT;
+		psrctl |= PAGE_SIZE <<
+			E1000_PSRCTL_BSIZE2_SHIFT;
+		psrctl |= PAGE_SIZE <<
+			E1000_PSRCTL_BSIZE3_SHIFT;
+
+		E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl);
 	}
 
 	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
@@ -1028,9 +1316,18 @@ 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;
+	uint32_t rdlen, rctl, rxcsum;
+
+	if(adapter->rx_ps) {
+		rdlen = adapter->rx_ring.count *
+			sizeof(union e1000_rx_desc_packet_split);
+		adapter->clean_rx = e1000_clean_rx_irq_ps;
+		adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
+	} else {
+		rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc);
+		adapter->clean_rx = e1000_clean_rx_irq;
+		adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+	}
 
 	/* disable receives while setting up the descriptors */
 	rctl = E1000_READ_REG(&adapter->hw, RCTL);
@@ -1057,13 +1354,27 @@ e1000_configure_rx(struct e1000_adapter 
 	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)) {
+	if(adapter->hw.mac_type >= e1000_82543) {
 		rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
-		rxcsum |= E1000_RXCSUM_TUOFL;
+		if(adapter->rx_csum == TRUE) {
+			rxcsum |= E1000_RXCSUM_TUOFL;
+
+			/* Enable 82573 IPv4 payload checksum for UDP fragments
+			 * Must be used in conjunction with packet-split. */
+			if((adapter->hw.mac_type > e1000_82547_rev_2) && 
+			   (adapter->rx_ps)) {
+				rxcsum |= E1000_RXCSUM_IPPCSE;
+			}
+		} else {
+			rxcsum &= ~E1000_RXCSUM_TUOFL;
+			/* don't need to clear IPPCSE as it defaults to 0 */
+		}
 		E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
 	}
 
+	if (adapter->hw.mac_type == e1000_82573)
+		E1000_WRITE_REG(&adapter->hw, ERT, 0x0100);
+
 	/* Enable Receives */
 	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 }
@@ -1095,12 +1406,11 @@ static inline void
 e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
 			struct e1000_buffer *buffer_info)
 {
-	struct pci_dev *pdev = adapter->pdev;
 	if(buffer_info->dma) {
-		pci_unmap_page(pdev,
-			       buffer_info->dma,
-			       buffer_info->length,
-			       PCI_DMA_TODEVICE);
+		pci_unmap_page(adapter->pdev,
+				buffer_info->dma,
+				buffer_info->length,
+				PCI_DMA_TODEVICE);
 		buffer_info->dma = 0;
 	}
 	if(buffer_info->skb) {
@@ -1124,6 +1434,11 @@ e1000_clean_tx_ring(struct e1000_adapter
 
 	/* Free all the Tx ring sk_buffs */
 
+	if (likely(adapter->previous_buffer_info.skb != NULL)) {
+		e1000_unmap_and_free_tx_resource(adapter,
+				&adapter->previous_buffer_info);
+	}
+
 	for(i = 0; i < tx_ring->count; i++) {
 		buffer_info = &tx_ring->buffer_info[i];
 		e1000_unmap_and_free_tx_resource(adapter, buffer_info);
@@ -1160,6 +1475,10 @@ e1000_free_rx_resources(struct e1000_ada
 
 	vfree(rx_ring->buffer_info);
 	rx_ring->buffer_info = NULL;
+	kfree(rx_ring->ps_page);
+	rx_ring->ps_page = NULL;
+	kfree(rx_ring->ps_page_dma);
+	rx_ring->ps_page_dma = NULL;
 
 	pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
 
@@ -1176,16 +1495,19 @@ e1000_clean_rx_ring(struct e1000_adapter
 {
 	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
 	struct e1000_buffer *buffer_info;
+	struct e1000_ps_page *ps_page;
+	struct e1000_ps_page_dma *ps_page_dma;
 	struct pci_dev *pdev = adapter->pdev;
 	unsigned long size;
-	unsigned int i;
+	unsigned int i, j;
 
 	/* Free all the Rx ring sk_buffs */
 
 	for(i = 0; i < rx_ring->count; i++) {
 		buffer_info = &rx_ring->buffer_info[i];
 		if(buffer_info->skb) {
-
+			ps_page = &rx_ring->ps_page[i];
+			ps_page_dma = &rx_ring->ps_page_dma[i];
 			pci_unmap_single(pdev,
 					 buffer_info->dma,
 					 buffer_info->length,
@@ -1193,11 +1515,25 @@ e1000_clean_rx_ring(struct e1000_adapter
 
 			dev_kfree_skb(buffer_info->skb);
 			buffer_info->skb = NULL;
+
+			for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+				if(!ps_page->ps_page[j]) break;
+				pci_unmap_single(pdev,
+						 ps_page_dma->ps_page_dma[j],
+						 PAGE_SIZE, PCI_DMA_FROMDEVICE);
+				ps_page_dma->ps_page_dma[j] = 0;
+				put_page(ps_page->ps_page[j]);
+				ps_page->ps_page[j] = NULL;
+			}
 		}
 	}
 
 	size = sizeof(struct e1000_buffer) * rx_ring->count;
 	memset(rx_ring->buffer_info, 0, size);
+	size = sizeof(struct e1000_ps_page) * rx_ring->count;
+	memset(rx_ring->ps_page, 0, size);
+	size = sizeof(struct e1000_ps_page_dma) * rx_ring->count;
+	memset(rx_ring->ps_page_dma, 0, size);
 
 	/* Zero out the descriptor ring */
 
@@ -1301,15 +1637,15 @@ e1000_set_multi(struct net_device *netde
 	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_hw *hw = &adapter->hw;
 	struct dev_mc_list *mc_ptr;
+	unsigned long flags;
 	uint32_t rctl;
 	uint32_t hash_value;
 	int i;
-	unsigned long flags;
-
-	/* Check for Promiscuous and All Multicast modes */
 
 	spin_lock_irqsave(&adapter->tx_lock, flags);
 
+	/* Check for Promiscuous and All Multicast modes */
+
 	rctl = E1000_READ_REG(hw, RCTL);
 
 	if(netdev->flags & IFF_PROMISC) {
@@ -1416,19 +1752,30 @@ e1000_82547_tx_fifo_stall(unsigned long 
 
 /**
  * e1000_watchdog - Timer Call-back
- * @data: pointer to netdev cast into an unsigned long
+ * @data: pointer to adapter cast into an unsigned long
  **/
-
 static void
 e1000_watchdog(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+	/* Do the rest outside of interrupt context */
+	schedule_work(&adapter->watchdog_task);
+}
+
+static void
+e1000_watchdog_task(struct e1000_adapter *adapter)
+{
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
-	unsigned int i;
 	uint32_t link;
 
 	e1000_check_for_link(&adapter->hw);
+	if (adapter->hw.mac_type == e1000_82573) {
+		e1000_enable_tx_pkt_filtering(&adapter->hw);
+		if(adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)
+			e1000_update_mng_vlan(adapter);
+	}	
 
 	if((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
 	   !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE))
@@ -1505,12 +1852,8 @@ e1000_watchdog(unsigned long data)
 	/* 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);
+	/* Force detection of hung controller every watchdog period */
+	adapter->detect_tx_hung = TRUE;
 
 	/* Reset the timer */
 	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -1519,39 +1862,61 @@ e1000_watchdog(unsigned long data)
 #define E1000_TX_FLAGS_CSUM		0x00000001
 #define E1000_TX_FLAGS_VLAN		0x00000002
 #define E1000_TX_FLAGS_TSO		0x00000004
+#define E1000_TX_FLAGS_IPV4		0x00000008
 #define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
 #define E1000_TX_FLAGS_VLAN_SHIFT	16
 
-static inline boolean_t
+static inline int
 e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
 {
 #ifdef NETIF_F_TSO
 	struct e1000_context_desc *context_desc;
 	unsigned int i;
 	uint32_t cmd_length = 0;
-	uint16_t ipcse, tucse, mss;
+	uint16_t ipcse = 0, tucse, mss;
 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
+	int err;
 
 	if(skb_shinfo(skb)->tso_size) {
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (err)
+				return err;
+		}
+
 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
 		mss = skb_shinfo(skb)->tso_size;
-		skb->nh.iph->tot_len = 0;
-		skb->nh.iph->check = 0;
-		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
-		                                      skb->nh.iph->daddr,
-		                                      0,
-		                                      IPPROTO_TCP,
-		                                      0);
+		if(skb->protocol == ntohs(ETH_P_IP)) {
+			skb->nh.iph->tot_len = 0;
+			skb->nh.iph->check = 0;
+			skb->h.th->check =
+				~csum_tcpudp_magic(skb->nh.iph->saddr,
+						   skb->nh.iph->daddr,
+						   0,
+						   IPPROTO_TCP,
+						   0);
+			cmd_length = E1000_TXD_CMD_IP;
+			ipcse = skb->h.raw - skb->data - 1;
+#ifdef NETIF_F_TSO_IPV6
+		} else if(skb->protocol == ntohs(ETH_P_IPV6)) {
+			skb->nh.ipv6h->payload_len = 0;
+			skb->h.th->check =
+				~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+						 &skb->nh.ipv6h->daddr,
+						 0,
+						 IPPROTO_TCP,
+						 0);
+			ipcse = 0;
+#endif
+		}
 		ipcss = skb->nh.raw - skb->data;
 		ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
-		ipcse = skb->h.raw - skb->data - 1;
 		tucss = skb->h.raw - skb->data;
 		tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
 		tucse = 0;
 
 		cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
-			       E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
-			       (skb->len - (hdr_len)));
+			       E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
 
 		i = adapter->tx_ring.next_to_use;
 		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
@@ -1569,11 +1934,11 @@ e1000_tso(struct e1000_adapter *adapter,
 		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
 
-		return TRUE;
+		return 1;
 	}
 #endif
 
-	return FALSE;
+	return 0;
 }
 
 static inline boolean_t
@@ -1630,6 +1995,15 @@ e1000_tx_map(struct e1000_adapter *adapt
 		if(unlikely(mss && !nr_frags && size == len && size > 8))
 			size -= 4;
 #endif
+		/* work-around for errata 10 and it applies
+		 * to all controllers in PCI-X mode
+		 * The fix is to make sure that the first descriptor of a
+		 * packet is smaller than 2048 - 16 - 16 (or 2016) bytes
+		 */
+		if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) &&
+		                (size > 2015) && count == 0))
+		        size = 2015;
+                                                                                
 		/* Workaround for potential 82544 hang in PCI-X.  Avoid
 		 * terminating buffers within evenly-aligned dwords. */
 		if(unlikely(adapter->pcix_82544 &&
@@ -1710,7 +2084,10 @@ e1000_tx_queue(struct e1000_adapter *ada
 	if(likely(tx_flags & E1000_TX_FLAGS_TSO)) {
 		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
 		             E1000_TXD_CMD_TSE;
-		txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8;
+		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+
+		if(likely(tx_flags & E1000_TX_FLAGS_IPV4))
+			txd_upper |= E1000_TXD_POPTS_IXSM << 8;
 	}
 
 	if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) {
@@ -1785,6 +2162,53 @@ no_fifo_stall_required:
 	return 0;
 }
 
+#define MINIMUM_DHCP_PACKET_SIZE 282
+static inline int
+e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	struct e1000_hw *hw =  &adapter->hw;
+	uint16_t length, offset;
+	if(vlan_tx_tag_present(skb)) {
+		if(!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
+			( adapter->hw.mng_cookie.status &
+			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) )
+			return 0;
+	}
+	if(htons(ETH_P_IP) == skb->protocol) {
+		const struct iphdr *ip = skb->nh.iph;
+		if(IPPROTO_UDP == ip->protocol) {
+			struct udphdr *udp = (struct udphdr *)(skb->h.uh);
+			if(ntohs(udp->dest) == 67) {
+				offset = (uint8_t *)udp + 8 - skb->data;
+				length = skb->len - offset;
+
+				return e1000_mng_write_dhcp_info(hw,
+						(uint8_t *)udp + 8, length);
+			}
+		}
+	} else if((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) {
+		struct ethhdr *eth = (struct ethhdr *) skb->data;
+		if((htons(ETH_P_IP) == eth->h_proto)) {
+			const struct iphdr *ip = 
+				(struct iphdr *)((uint8_t *)skb->data+14);
+			if(IPPROTO_UDP == ip->protocol) {
+				struct udphdr *udp = 
+					(struct udphdr *)((uint8_t *)ip + 
+						(ip->ihl << 2));
+				if(ntohs(udp->dest) == 67) {
+					offset = (uint8_t *)udp + 8 - skb->data;
+					length = skb->len - offset;
+
+					return e1000_mng_write_dhcp_info(hw,
+							(uint8_t *)udp + 8, 
+							length);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
 #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
@@ -1798,6 +2222,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	unsigned int nr_frags = 0;
 	unsigned int mss = 0;
 	int count = 0;
+	int tso;
 	unsigned int f;
 	len -= skb->data_len;
 
@@ -1808,7 +2233,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 
 #ifdef NETIF_F_TSO
 	mss = skb_shinfo(skb)->tso_size;
-	/* The controller does a simple calculation to
+	/* The controller does a simple calculation to 
 	 * make sure there is enough room in the FIFO before
 	 * initiating the DMA for each buffer.  The calc is:
 	 * 4 = ceil(buffer len/mss).  To make sure we don't
@@ -1821,7 +2246,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 
 	if((mss) || (skb->ip_summed == CHECKSUM_HW))
 		count++;
-	count++;	/* for sentinel desc */
+	count++;
 #else
 	if(skb->ip_summed == CHECKSUM_HW)
 		count++;
@@ -1831,6 +2256,13 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	if(adapter->pcix_82544)
 		count++;
 
+	/* work-around for errata 10 and it applies to all controllers 
+	 * in PCI-X mode, so add one more descriptor to the count
+	 */
+	if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) &&
+			(len > 2015)))
+		count++;
+
 	nr_frags = skb_shinfo(skb)->nr_frags;
 	for(f = 0; f < nr_frags; f++)
 		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
@@ -1844,6 +2276,9 @@ e1000_xmit_frame(struct sk_buff *skb, st
  		local_irq_restore(flags); 
  		return NETDEV_TX_LOCKED; 
  	} 
+	if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) )
+		e1000_transfer_dhcp_info(adapter, skb);
+
 
 	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
@@ -1869,11 +2304,23 @@ e1000_xmit_frame(struct sk_buff *skb, st
 
 	first = adapter->tx_ring.next_to_use;
 	
-	if(likely(e1000_tso(adapter, skb)))
+	tso = e1000_tso(adapter, skb);
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (likely(tso))
 		tx_flags |= E1000_TX_FLAGS_TSO;
 	else if(likely(e1000_tx_csum(adapter, skb)))
 		tx_flags |= E1000_TX_FLAGS_CSUM;
 
+	/* Old method was to assume IPv4 packet by default if TSO was enabled.
+	 * 82573 hardware supports TSO capabilities for IPv6 as well...
+	 * no longer assume, we must. */
+	if(likely(skb->protocol == ntohs(ETH_P_IP)))
+		tx_flags |= E1000_TX_FLAGS_IPV4;
+
 	e1000_tx_queue(adapter,
 		e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
 		tx_flags);
@@ -1940,7 +2387,6 @@ 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) ||
@@ -1949,29 +2395,45 @@ e1000_change_mtu(struct net_device *netd
 			return -EINVAL;
 	}
 
-	if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) {
-		adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-
-	} else if(adapter->hw.mac_type < e1000_82543) {
-		DPRINTK(PROBE, ERR, "Jumbo Frames not supported on 82542\n");
+#define MAX_STD_JUMBO_FRAME_SIZE 9216
+	/* might want this to be bigger enum check... */
+	if (adapter->hw.mac_type == e1000_82573 &&
+	    max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+		DPRINTK(PROBE, ERR, "Jumbo Frames not supported "
+				    "on 82573\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;
-
+	if(adapter->hw.mac_type > e1000_82547_rev_2) {
+		adapter->rx_buffer_len = max_frame;
+		E1000_ROUNDUP(adapter->rx_buffer_len, 1024);
 	} else {
-		adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+		if(unlikely((adapter->hw.mac_type < e1000_82543) &&
+		   (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE))) {
+			DPRINTK(PROBE, ERR, "Jumbo Frames not supported "
+					    "on 82542\n");
+			return -EINVAL;
+
+		} else {
+			if(max_frame <= E1000_RXBUFFER_2048) {
+				adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+			} 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 if(max_frame <= E1000_RXBUFFER_16384) {
+				adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+			}
+		}
 	}
 
-	if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
+	netdev->mtu = new_mtu;
+
+	if(netif_running(netdev)) {
 		e1000_down(adapter);
 		e1000_up(adapter);
 	}
 
-	netdev->mtu = new_mtu;
 	adapter->hw.max_frame_size = max_frame;
 
 	return 0;
@@ -2062,6 +2524,17 @@ e1000_update_stats(struct e1000_adapter 
 		adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
 		adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
 	}
+	if(hw->mac_type > e1000_82547_rev_2) {
+		adapter->stats.iac += E1000_READ_REG(hw, IAC);
+		adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC);
+		adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC);
+		adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC);
+		adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC);
+		adapter->stats.ictxatc += E1000_READ_REG(hw, ICTXATC);
+		adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC);
+		adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC);
+		adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC);
+	}
 
 	/* Fill out the OS statistics structure */
 
@@ -2076,9 +2549,9 @@ e1000_update_stats(struct e1000_adapter 
 
 	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->stats.rlec + adapter->stats.mpc + 
+		adapter->stats.cexterr;
+	adapter->net_stats.rx_dropped = adapter->stats.mpc;
 	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;
@@ -2151,10 +2624,28 @@ e1000_intr(int irq, void *data, struct p
 		__netif_rx_schedule(netdev);
 	}
 #else
+	/* Writing IMC and IMS is needed for 82547.
+	   Due to Hub Link bus being occupied, an interrupt
+	   de-assertion message is not able to be sent.
+	   When an interrupt assertion message is generated later,
+	   two messages are re-ordered and sent out.
+	   That causes APIC to think 82547 is in de-assertion
+	   state, while 82547 is in assertion state, resulting
+	   in dead lock. Writing IMC forces 82547 into
+	   de-assertion state.
+	*/
+	if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2){
+		atomic_inc(&adapter->irq_sem);
+		E1000_WRITE_REG(hw, IMC, ~0);
+	}
+
 	for(i = 0; i < E1000_MAX_INTR; i++)
-		if(unlikely(!e1000_clean_rx_irq(adapter) &
+		if(unlikely(!adapter->clean_rx(adapter) &
 		   !e1000_clean_tx_irq(adapter)))
 			break;
+
+	if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
+		e1000_irq_enable(adapter);
 #endif
 
 	return IRQ_HANDLED;
@@ -2173,25 +2664,21 @@ e1000_clean(struct net_device *netdev, i
 	int work_to_do = min(*budget, netdev->quota);
 	int tx_cleaned;
 	int work_done = 0;
-	
-	if (!netif_carrier_ok(netdev))
-		goto quit_polling;
 
 	tx_cleaned = e1000_clean_tx_irq(adapter);
-	e1000_clean_rx_irq(adapter, &work_done, work_to_do);
+	adapter->clean_rx(adapter, &work_done, work_to_do);
 
 	*budget -= work_done;
 	netdev->quota -= work_done;
 	
-	/* if no Rx and Tx cleanup work was done, exit the polling mode */
-	if(!tx_cleaned || (work_done < work_to_do) || 
-				!netif_running(netdev)) {
-quit_polling:	netif_rx_complete(netdev);
+	/* If no Tx and no Rx work done, exit the polling mode */
+	if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+		netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
 		return 0;
 	}
 
-	return (work_done >= work_to_do);
+	return 1;
 }
 
 #endif
@@ -2215,16 +2702,42 @@ e1000_clean_tx_irq(struct e1000_adapter 
 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
 
 	while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+		/* Premature writeback of Tx descriptors clear (free buffers
+		 * and unmap pci_mapping) previous_buffer_info */
+		if (likely(adapter->previous_buffer_info.skb != NULL)) {
+			e1000_unmap_and_free_tx_resource(adapter,
+					&adapter->previous_buffer_info);
+		}
+
 		for(cleaned = FALSE; !cleaned; ) {
 			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
+			cleaned = (i == eop);
+
+#ifdef NETIF_F_TSO
+			if (!(netdev->features & NETIF_F_TSO)) {
+#endif
+				e1000_unmap_and_free_tx_resource(adapter,
+				                                 buffer_info);
+#ifdef NETIF_F_TSO
+			} else {
+				if (cleaned) {
+					memcpy(&adapter->previous_buffer_info,
+					       buffer_info,
+					       sizeof(struct e1000_buffer));
+					memset(buffer_info, 0,
+					       sizeof(struct e1000_buffer));
+				} else {
+					e1000_unmap_and_free_tx_resource(
+					    adapter, buffer_info);
+				}
+			}
+#endif
 
-			e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 			tx_desc->buffer_addr = 0;
 			tx_desc->lower.data = 0;
 			tx_desc->upper.data = 0;
 
-			cleaned = (i == eop);
 			if(unlikely(++i == tx_ring->count)) i = 0;
 		}
 		
@@ -2241,47 +2754,107 @@ e1000_clean_tx_irq(struct e1000_adapter 
 		netif_wake_queue(netdev);
 
 	spin_unlock(&adapter->tx_lock);
+	if(adapter->detect_tx_hung) {
 
+		/* Detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i */
+		adapter->detect_tx_hung = FALSE;
+		if (tx_ring->buffer_info[i].dma &&
+		    time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ)
+		    && !(E1000_READ_REG(&adapter->hw, STATUS) &
+			E1000_STATUS_TXOFF)) {
+
+			/* detected Tx unit hang */
+			i = tx_ring->next_to_clean;
+			eop = tx_ring->buffer_info[i].next_to_watch;
+			eop_desc = E1000_TX_DESC(*tx_ring, eop);
+			DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+					"  TDH                  <%x>\n"
+					"  TDT                  <%x>\n"
+					"  next_to_use          <%x>\n"
+					"  next_to_clean        <%x>\n"
+					"buffer_info[next_to_clean]\n"
+					"  dma                  <%llx>\n"
+					"  time_stamp           <%lx>\n"
+					"  next_to_watch        <%x>\n"
+					"  jiffies              <%lx>\n"
+					"  next_to_watch.status <%x>\n",
+				E1000_READ_REG(&adapter->hw, TDH),
+				E1000_READ_REG(&adapter->hw, TDT),
+				tx_ring->next_to_use,
+				i,
+				tx_ring->buffer_info[i].dma,
+				tx_ring->buffer_info[i].time_stamp,
+				eop,
+				jiffies,
+				eop_desc->upper.fields.status);
+			netif_stop_queue(netdev);
+		}
+	}
+#ifdef NETIF_F_TSO
+
+	if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
+	    time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ)))
+		e1000_unmap_and_free_tx_resource(
+		    adapter, &adapter->previous_buffer_info);
+
+#endif
 	return cleaned;
 }
 
 /**
  * e1000_rx_checksum - Receive Checksum Offload for 82543
- * @adapter: board private structure
- * @rx_desc: receive descriptor
- * @sk_buff: socket buffer with received data
+ * @adapter:     board private structure
+ * @status_err:  receive descriptor status and error fields
+ * @csum:        receive descriptor csum field
+ * @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)
+		  uint32_t status_err, uint32_t csum,
+		  struct sk_buff *skb)
 {
+	uint16_t status = (uint16_t)status_err;
+	uint8_t errors = (uint8_t)(status_err >> 24);
+	skb->ip_summed = CHECKSUM_NONE;
+
 	/* 82543 or newer only */
-	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
+	if(unlikely(adapter->hw.mac_type < e1000_82543)) return;
 	/* 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) {
+	if(unlikely(status & E1000_RXD_STAT_IXSM)) return;
+	/* TCP/UDP checksum error bit is set */
+	if(unlikely(errors & E1000_RXD_ERR_TCPE)) {
 		/* let the stack verify checksum errors */
-		skb->ip_summed = CHECKSUM_NONE;
 		adapter->hw_csum_err++;
+		return;
+	}
+	/* TCP/UDP Checksum has not been calculated */
+	if(adapter->hw.mac_type <= e1000_82547_rev_2) {
+		if(!(status & E1000_RXD_STAT_TCPCS))
+			return;
 	} else {
+		if(!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)))
+			return;
+	}
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (likely(status & E1000_RXD_STAT_TCPCS)) {
 		/* TCP checksum is good */
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		adapter->hw_csum_good++;
+	} else if (adapter->hw.mac_type > e1000_82547_rev_2) {
+		/* IP fragment with UDP payload */
+		/* Hardware complements the payload checksum, so we undo it
+		 * and then put the value in host order for further stack use.
+		 */
+		csum = ntohl(csum ^ 0xFFFF);
+		skb->csum = csum;
+		skb->ip_summed = CHECKSUM_HW;
 	}
+	adapter->hw_csum_good++;
 }
 
 /**
- * e1000_clean_rx_irq - Send received data up the network stack
+ * e1000_clean_rx_irq - Send received data up the network stack; legacy
  * @adapter: board private structure
  **/
 
@@ -2328,7 +2901,7 @@ e1000_clean_rx_irq(struct e1000_adapter 
 		if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) {
 			/* All receives must fit into a single buffer */
 			E1000_DBG("%s: Receive packet consumed multiple"
-					" buffers\n", netdev->name);
+				  " buffers\n", netdev->name);
 			dev_kfree_skb_irq(skb);
 			goto next_desc;
 		}
@@ -2354,15 +2927,17 @@ e1000_clean_rx_irq(struct e1000_adapter 
 		skb_put(skb, length - ETHERNET_FCS_SIZE);
 
 		/* Receive Checksum Offload */
-		e1000_rx_checksum(adapter, rx_desc, skb);
-
+		e1000_rx_checksum(adapter,
+				  (uint32_t)(rx_desc->status) |
+				  ((uint32_t)(rx_desc->errors) << 24),
+				  rx_desc->csum, skb);
 		skb->protocol = eth_type_trans(skb, netdev);
 #ifdef CONFIG_E1000_NAPI
 		if(unlikely(adapter->vlgrp &&
 			    (rx_desc->status & E1000_RXD_STAT_VP))) {
 			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-					le16_to_cpu(rx_desc->special) &
-					E1000_RXD_SPC_VLAN_MASK);
+						 le16_to_cpu(rx_desc->special) &
+						 E1000_RXD_SPC_VLAN_MASK);
 		} else {
 			netif_receive_skb(skb);
 		}
@@ -2385,16 +2960,142 @@ next_desc:
 
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
 	}
-
 	rx_ring->next_to_clean = i;
+	adapter->alloc_rx_buf(adapter);
+
+	return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
+ * @adapter: board private structure
+ **/
+
+static boolean_t
+#ifdef CONFIG_E1000_NAPI
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done,
+                      int work_to_do)
+#else
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
+#endif
+{
+	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+	union e1000_rx_desc_packet_split *rx_desc;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ps_page *ps_page;
+	struct e1000_ps_page_dma *ps_page_dma;
+	struct sk_buff *skb;
+	unsigned int i, j;
+	uint32_t length, staterr;
+	boolean_t cleaned = FALSE;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+	staterr = rx_desc->wb.middle.status_error;
+
+	while(staterr & E1000_RXD_STAT_DD) {
+		buffer_info = &rx_ring->buffer_info[i];
+		ps_page = &rx_ring->ps_page[i];
+		ps_page_dma = &rx_ring->ps_page_dma[i];
+#ifdef CONFIG_E1000_NAPI
+		if(unlikely(*work_done >= work_to_do))
+			break;
+		(*work_done)++;
+#endif
+		cleaned = TRUE;
+		pci_unmap_single(pdev, buffer_info->dma,
+				 buffer_info->length,
+				 PCI_DMA_FROMDEVICE);
+
+		skb = buffer_info->skb;
+
+		if(unlikely(!(staterr & E1000_RXD_STAT_EOP))) {
+			E1000_DBG("%s: Packet Split buffers didn't pick up"
+				  " the full packet\n", netdev->name);
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		if(unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) {
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		length = le16_to_cpu(rx_desc->wb.middle.length0);
+
+		if(unlikely(!length)) {
+			E1000_DBG("%s: Last part of the packet spanning"
+				  " multiple descriptors\n", netdev->name);
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		/* Good Receive */
+		skb_put(skb, length);
+
+		for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+			if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j])))
+				break;
+
+			pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j],
+					PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			ps_page_dma->ps_page_dma[j] = 0;
+			skb_shinfo(skb)->frags[j].page =
+				ps_page->ps_page[j];
+			ps_page->ps_page[j] = NULL;
+			skb_shinfo(skb)->frags[j].page_offset = 0;
+			skb_shinfo(skb)->frags[j].size = length;
+			skb_shinfo(skb)->nr_frags++;
+			skb->len += length;
+			skb->data_len += length;
+		}
+
+		e1000_rx_checksum(adapter, staterr,
+				  rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+		skb->protocol = eth_type_trans(skb, netdev);
+
+#ifdef HAVE_RX_ZERO_COPY
+		if(likely(rx_desc->wb.upper.header_status &
+			  E1000_RXDPS_HDRSTAT_HDRSP))
+			skb_shinfo(skb)->zero_copy = TRUE;
+#endif
+#ifdef CONFIG_E1000_NAPI
+		if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
+			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+				le16_to_cpu(rx_desc->wb.middle.vlan &
+					E1000_RXD_SPC_VLAN_MASK));
+		} else {
+			netif_receive_skb(skb);
+		}
+#else /* CONFIG_E1000_NAPI */
+		if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
+			vlan_hwaccel_rx(skb, adapter->vlgrp,
+				le16_to_cpu(rx_desc->wb.middle.vlan &
+					E1000_RXD_SPC_VLAN_MASK));
+		} else {
+			netif_rx(skb);
+		}
+#endif /* CONFIG_E1000_NAPI */
+		netdev->last_rx = jiffies;
 
-	e1000_alloc_rx_buffers(adapter);
+next_desc:
+		rx_desc->wb.middle.status_error &= ~0xFF;
+		buffer_info->skb = NULL;
+		if(unlikely(++i == rx_ring->count)) i = 0;
+
+		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+		staterr = rx_desc->wb.middle.status_error;
+	}
+	rx_ring->next_to_clean = i;
+	adapter->alloc_rx_buf(adapter);
 
 	return cleaned;
 }
 
 /**
- * e1000_alloc_rx_buffers - Replace used receive buffers
+ * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
  * @adapter: address of board private structure
  **/
 
@@ -2408,18 +3109,42 @@ e1000_alloc_rx_buffers(struct e1000_adap
 	struct e1000_buffer *buffer_info;
 	struct sk_buff *skb;
 	unsigned int i;
+	unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
 
 	i = rx_ring->next_to_use;
 	buffer_info = &rx_ring->buffer_info[i];
 
 	while(!buffer_info->skb) {
-		skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+		skb = dev_alloc_skb(bufsz);
 
 		if(unlikely(!skb)) {
 			/* Better luck next round */
 			break;
 		}
 
+		/* Fix for errata 23, can't cross 64kB boundary */
+		if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+			struct sk_buff *oldskb = skb;
+			DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes "
+					     "at %p\n", bufsz, skb->data);
+			/* Try again, without freeing the previous */
+			skb = dev_alloc_skb(bufsz);
+			/* Failed allocation, critical failure */
+			if (!skb) {
+				dev_kfree_skb(oldskb);
+				break;
+			}
+
+			if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+				/* give up */
+				dev_kfree_skb(skb);
+				dev_kfree_skb(oldskb);
+				break; /* while !buffer_info->skb */
+			} else {
+				/* Use new allocation */
+				dev_kfree_skb(oldskb);
+			}
+		}
 		/* 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
@@ -2435,6 +3160,23 @@ e1000_alloc_rx_buffers(struct e1000_adap
 						  adapter->rx_buffer_len,
 						  PCI_DMA_FROMDEVICE);
 
+		/* Fix for errata 23, can't cross 64kB boundary */
+		if (!e1000_check_64k_bound(adapter,
+					(void *)(unsigned long)buffer_info->dma,
+					adapter->rx_buffer_len)) {
+			DPRINTK(RX_ERR, ERR,
+				"dma align check failed: %u bytes at %p\n",
+				adapter->rx_buffer_len,
+				(void *)(unsigned long)buffer_info->dma);
+			dev_kfree_skb(skb);
+			buffer_info->skb = NULL;
+
+			pci_unmap_single(pdev, buffer_info->dma,
+					 adapter->rx_buffer_len,
+					 PCI_DMA_FROMDEVICE);
+
+			break; /* while !buffer_info->skb */
+		}
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
 		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
 
@@ -2444,7 +3186,6 @@ e1000_alloc_rx_buffers(struct e1000_adap
 			 * applicable for weak-ordered memory model archs,
 			 * such as IA-64). */
 			wmb();
-
 			E1000_WRITE_REG(&adapter->hw, RDT, i);
 		}
 
@@ -2456,6 +3197,95 @@ e1000_alloc_rx_buffers(struct e1000_adap
 }
 
 /**
+ * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+
+static void
+e1000_alloc_rx_buffers_ps(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;
+	union e1000_rx_desc_packet_split *rx_desc;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ps_page *ps_page;
+	struct e1000_ps_page_dma *ps_page_dma;
+	struct sk_buff *skb;
+	unsigned int i, j;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+	ps_page = &rx_ring->ps_page[i];
+	ps_page_dma = &rx_ring->ps_page_dma[i];
+
+	while(!buffer_info->skb) {
+		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+
+		for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+			if(unlikely(!ps_page->ps_page[j])) {
+				ps_page->ps_page[j] =
+					alloc_page(GFP_ATOMIC);
+				if(unlikely(!ps_page->ps_page[j]))
+					goto no_buffers;
+				ps_page_dma->ps_page_dma[j] =
+					pci_map_page(pdev,
+						     ps_page->ps_page[j],
+						     0, PAGE_SIZE,
+						     PCI_DMA_FROMDEVICE);
+			}
+			/* Refresh the desc even if buffer_addrs didn't
+			 * change because each write-back erases this info.
+			 */
+			rx_desc->read.buffer_addr[j+1] =
+				cpu_to_le64(ps_page_dma->ps_page_dma[j]);
+		}
+
+		skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+
+		if(unlikely(!skb))
+			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, NET_IP_ALIGN);
+
+		skb->dev = netdev;
+
+		buffer_info->skb = skb;
+		buffer_info->length = adapter->rx_ps_bsize0;
+		buffer_info->dma = pci_map_single(pdev, skb->data,
+						  adapter->rx_ps_bsize0,
+						  PCI_DMA_FROMDEVICE);
+
+		rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
+
+		if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) {
+			/* 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();
+			/* Hardware increments by 16 bytes, but packet split
+			 * descriptors are 32 bytes...so we increment tail
+			 * twice as much.
+			 */
+			E1000_WRITE_REG(&adapter->hw, RDT, i<<1);
+		}
+
+		if(unlikely(++i == rx_ring->count)) i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+		ps_page = &rx_ring->ps_page[i];
+		ps_page_dma = &rx_ring->ps_page_dma[i];
+	}
+
+no_buffers:
+	rx_ring->next_to_use = i;
+}
+
+/**
  * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
  * @adapter:
  **/
@@ -2628,9 +3458,10 @@ void
 e1000_pci_set_mwi(struct e1000_hw *hw)
 {
 	struct e1000_adapter *adapter = hw->back;
+	int ret_val = pci_set_mwi(adapter->pdev);
 
-	int ret;
-	ret = pci_set_mwi(adapter->pdev);
+	if(ret_val)
+		DPRINTK(PROBE, ERR, "Error in setting MWI\n");
 }
 
 void
@@ -2689,6 +3520,7 @@ e1000_vlan_rx_register(struct net_device
 		rctl |= E1000_RCTL_VFE;
 		rctl &= ~E1000_RCTL_CFIEN;
 		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+		e1000_update_mng_vlan(adapter);
 	} else {
 		/* disable VLAN tag insert/strip */
 		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
@@ -2699,6 +3531,10 @@ e1000_vlan_rx_register(struct net_device
 		rctl = E1000_READ_REG(&adapter->hw, RCTL);
 		rctl &= ~E1000_RCTL_VFE;
 		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+		if(adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) {
+			e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+			adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+		}
 	}
 
 	e1000_irq_enable(adapter);
@@ -2709,7 +3545,10 @@ e1000_vlan_rx_add_vid(struct net_device 
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	uint32_t vfta, index;
-
+	if((adapter->hw.mng_cookie.status &
+		E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
+		(vid == adapter->mng_vlan_id))
+		return;
 	/* add VID to filter table */
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
@@ -2730,6 +3569,10 @@ e1000_vlan_rx_kill_vid(struct net_device
 
 	e1000_irq_enable(adapter);
 
+	if((adapter->hw.mng_cookie.status &
+		E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
+		(vid == adapter->mng_vlan_id))
+		return;
 	/* remove VID from filter table */
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
@@ -2776,8 +3619,7 @@ e1000_set_spd_dplx(struct e1000_adapter 
 		break;
 	case SPEED_1000 + DUPLEX_HALF: /* not supported */
 	default:
-		DPRINTK(PROBE, ERR, 
-			"Unsupported Speed/Duplexity configuration\n");
+		DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -2805,7 +3647,7 @@ e1000_suspend(struct pci_dev *pdev, uint
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t ctrl, ctrl_ext, rctl, manc, status;
+	uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
 	uint32_t wufc = adapter->wol;
 
 	netif_device_detach(netdev);
@@ -2847,6 +3689,9 @@ e1000_suspend(struct pci_dev *pdev, uint
 			E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext);
 		}
 
+		/* Allow time for pending master requests to run */
+		e1000_disable_pciex_master(&adapter->hw);
+
 		E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
 		E1000_WRITE_REG(&adapter->hw, WUFC, wufc);
 		pci_enable_wake(pdev, 3, 1);
@@ -2871,6 +3716,16 @@ e1000_suspend(struct pci_dev *pdev, uint
 		}
 	}
 
+	switch(adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm & ~E1000_SWSM_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+
 	pci_disable_device(pdev);
 
 	state = (state > 0) ? 3 : 0;
@@ -2885,13 +3740,12 @@ e1000_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t manc, ret;
+	uint32_t manc, ret, swsm;
 
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev);
 	ret = pci_enable_device(pdev);
-	if (pdev->is_busmaster)
-		pci_set_master(pdev);
+	pci_set_master(pdev);
 
 	pci_enable_wake(pdev, 3, 0);
 	pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
@@ -2911,10 +3765,19 @@ e1000_resume(struct pci_dev *pdev)
 		E1000_WRITE_REG(&adapter->hw, MANC, manc);
 	}
 
+	switch(adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm | E1000_SWSM_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+
 	return 0;
 }
 #endif
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling 'interrupt' - used by things like netconsole to send skbs
@@ -2922,7 +3785,7 @@ e1000_resume(struct pci_dev *pdev)
  * the interrupt routine is executing.
  */
 static void
-e1000_netpoll (struct net_device *netdev)
+e1000_netpoll(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	disable_irq(adapter->pdev->irq);
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -42,7 +42,12 @@
 #include <linux/sched.h>
 
 #ifndef msec_delay
-#define msec_delay(x) msleep(x)
+#define msec_delay(x)	do { if(in_interrupt()) { \
+				/* Don't mdelay in interrupt context! */ \
+	                	BUG(); \
+			} else { \
+				msleep(x); \
+			} } while(0)
 
 /* Some workarounds require millisecond delays and are run during interrupt
  * context.  Most notably, when establishing link, the phy may need tweaking
@@ -96,6 +101,29 @@ typedef enum {
         (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
         ((offset) << 2)))
 
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+    writew((value), ((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        ((offset) << 1))))
+
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+    readw((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        ((offset) << 1)))
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+    writeb((value), ((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        (offset))))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+    readb((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        (offset)))
+
 #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
 
 #endif /* _E1000_OSDEP_H_ */
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -478,7 +478,6 @@ e1000_check_options(struct e1000_adapter
 				DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", 
 					opt.name);
 				break;
-			case -1:
 			default:
 				e1000_validate_option(&adapter->itr, &opt, 
 					adapter);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -144,24 +144,14 @@ MODULE_PARM_DESC(full_duplex, "full dupl
 MODULE_PARM_DESC(congenb, "Enable congestion control (1)");
 MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)");
 MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(txdmaccount, "Tx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rxdmaccount, "Rx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(txdmacount, "Tx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rxdmacount, "Rx DMA burst length; 128 - disable (0-128)");
 MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
 MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses");
 
 #define RUN_AT(x) (jiffies + (x))
 
-/* ACPI power states don't universally work (yet) */
-#ifndef CONFIG_PM
-#undef pci_set_power_state
-#define pci_set_power_state null_set_power_state
-static inline int null_set_power_state(struct pci_dev *dev, int state)
-{
-	return 0;
-}
-#endif /* CONFIG_PM */
-
 #define netdevice_start(dev)
 #define netdevice_stop(dev)
 #define netif_set_tx_timeout(dev, tf, tm) \
@@ -2281,7 +2271,7 @@ static void set_rx_mode(struct net_devic
 }
 
 #ifdef CONFIG_PM
-static int eepro100_suspend(struct pci_dev *pdev, u32 state)
+static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct speedo_private *sp = netdev_priv(dev);
@@ -2299,7 +2289,7 @@ static int eepro100_suspend(struct pci_d
 	
 	/* XXX call pci_set_power_state ()? */
 	pci_disable_device(pdev);
-	pci_set_power_state (pdev, 3);
+	pci_set_power_state (pdev, PCI_D3hot);
 	return 0;
 }
 
@@ -2309,7 +2299,7 @@ static int eepro100_resume(struct pci_de
 	struct speedo_private *sp = netdev_priv(dev);
 	void __iomem *ioaddr = sp->regs;
 
-	pci_set_power_state(pdev, 0);
+	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 	pci_enable_device(pdev);
 	pci_set_master(pdev);
@@ -2355,12 +2345,8 @@ static void __devexit eepro100_remove_on
 }
 
 static struct pci_device_id eepro100_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
-		PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
-		PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_7,
-		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, },
@@ -2380,7 +2366,6 @@ static struct pci_device_id eepro100_pci
 	{ PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1228, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -7,7 +7,7 @@
  * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
  *
  * Many modifications, and currently maintained, by
- *  Philip Blundell <Philip.Blundell@pobox.com>
+ *  Philip Blundell <philb@gnu.org>
  * Added the Compaq LTE  Alan Cox <alan@redhat.com>
  * Added MCA support Adam Fritzler <mid@auk.cx>
  *
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1624,7 +1624,7 @@ static void __devexit epic_remove_one (s
 
 #ifdef CONFIG_PM
 
-static int epic_suspend (struct pci_dev *pdev, u32 state)
+static int epic_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	long ioaddr = dev->base_addr;
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -499,8 +499,6 @@ static int eql_g_slave_cfg(struct net_de
 		return -ENODEV;
 
 	ret = -EINVAL;
-	if (!slave_dev)
-		return ret;
 
 	spin_lock_bh(&eql->queue.lock);
 	if (eql_is_slave(slave_dev)) {
@@ -536,8 +534,6 @@ static int eql_s_slave_cfg(struct net_de
 		return -ENODEV;
 
 	ret = -EINVAL;
-	if (!slave_dev)
-		return ret;
 
 	eql = netdev_priv(dev);
 	spin_lock_bh(&eql->queue.lock);
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -159,6 +159,7 @@ static void cleanup_card(struct net_devi
 {
 	free_irq(dev->irq, dev);
 	release_region(dev->base_addr, ES_IO_EXTENT);
+	iounmap(ei_status.mem);
 }
 
 #ifndef MODULE
@@ -271,9 +272,14 @@ static int __init es_probe1(struct net_d
 		printk(" assigning ");
 	}
 
-	dev->mem_end = ei_status.rmem_end = dev->mem_start
-		+ (ES_STOP_PG - ES_START_PG)*256;
-	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
+	if (!ei_status.mem) {
+		printk("ioremap failed - giving up\n");
+		retval = -ENXIO;
+		goto out1;
+	}
+
+	dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
 
 	printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
 
@@ -353,8 +359,8 @@ static void es_reset_8390(struct net_dev
 static void
 es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
-	unsigned long hdr_start = dev->mem_start + ((ring_page - ES_START_PG)<<8);
-	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
+	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 	hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
 }
 
@@ -367,27 +373,27 @@ es_get_8390_hdr(struct net_device *dev, 
 static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
 						  int ring_offset)
 {
-	unsigned long xfer_start = dev->mem_start + ring_offset - (ES_START_PG<<8);
+	void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
 
-	if (xfer_start + count > ei_status.rmem_end) {
+	if (ring_offset + count > ES_STOP_PG*256) {
 		/* Packet wraps over end of ring buffer. */
-		int semi_count = ei_status.rmem_end - xfer_start;
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		int semi_count = ES_STOP_PG*256 - ring_offset;
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+		memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
 	} else {
 		/* Packet is in one chunk. */
-		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 }
 
 static void es_block_output(struct net_device *dev, int count,
 				const unsigned char *buf, int start_page)
 {
-	unsigned long shmem = dev->mem_start + ((start_page - ES_START_PG)<<8);
+	void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
 
 	count = (count + 3) & ~3;     /* Round up to doubleword */
-	isa_memcpy_toio(shmem, buf, count);
+	memcpy_toio(shmem, buf, count);
 }
 
 static int es_open(struct net_device *dev)
diff --git a/drivers/net/ethertap.c b/drivers/net/ethertap.c
deleted file mode 100644
--- a/drivers/net/ethertap.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- *	Ethertap: A network device for bouncing packets via user space
- *
- *	This is a very simple ethernet driver. It bounces ethernet frames
- *	to user space on /dev/tap0->/dev/tap15 and expects ethernet frames
- *	to be written back to it. By default it does not ARP. If you turn ARP
- *	on it will attempt to ARP the user space and reply to ARPS from the
- *	user space.
- *
- *	As this is an ethernet device you can use it for appletalk, IPX etc
- *	even for building bridging tunnels.
- */
- 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include <net/sock.h>
-#include <linux/netlink.h>
-
-/*
- *	Index to functions.
- */
-
-static int  ethertap_open(struct net_device *dev);
-static int  ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int  ethertap_close(struct net_device *dev);
-static struct net_device_stats *ethertap_get_stats(struct net_device *dev);
-static void ethertap_rx(struct sock *sk, int len);
-#ifdef CONFIG_ETHERTAP_MC
-static void set_multicast_list(struct net_device *dev);
-#endif
-
-static int ethertap_debug;
-
-static int max_taps = 1;
-module_param(max_taps, int, 0);
-MODULE_PARM_DESC(max_taps,"Max number of ethernet tap devices");
-
-static struct net_device **tap_map;	/* Returns the tap device for a given netlink */
-
-/*
- *	Board-specific info in dev->priv.
- */
-
-struct net_local
-{
-	struct sock	*nl;
-#ifdef CONFIG_ETHERTAP_MC
-	__u32		groups;
-#endif
-	struct net_device_stats stats;
-};
-
-/*
- *	To call this a probe is a bit misleading, however for real
- *	hardware it would have to check what was present.
- */
-static int  __init ethertap_probe(int unit)
-{
-	struct net_device *dev;
-	int err = -ENOMEM;
-
-	dev = alloc_etherdev(sizeof(struct net_local));
-
-	if (!dev)
-		goto out;
-
-	SET_MODULE_OWNER(dev);
-
-	sprintf(dev->name, "tap%d", unit);
-	dev->base_addr = unit + NETLINK_TAPBASE;
-
-	netdev_boot_setup_check(dev);
-
-	memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6);
-	if (dev->mem_start & 0xf)
-		ethertap_debug = dev->mem_start & 0x7;
-
-	/*
-	 *	The tap specific entries in the device structure.
-	 */
-
-	dev->open = ethertap_open;
-	dev->hard_start_xmit = ethertap_start_xmit;
-	dev->stop = ethertap_close;
-	dev->get_stats = ethertap_get_stats;
-#ifdef CONFIG_ETHERTAP_MC
-	dev->set_multicast_list = set_multicast_list;
-#endif
-
-	dev->tx_queue_len = 0;
-	dev->flags|=IFF_NOARP;
-
-	err = register_netdev(dev);
-	if (err)
-		goto out_free;
-
-	tap_map[unit]=dev;
-	return 0;
-out_free:
-	free_netdev(dev);
-out:
-	return err;
-}
-
-/*
- *	Open/initialize the board.
- */
-
-static int ethertap_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if (ethertap_debug > 2)
-		printk(KERN_DEBUG "%s: Doing ethertap_open()...\n", dev->name);
-
-	lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx);
-	if (lp->nl == NULL)
-		return -ENOBUFS;
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-#ifdef CONFIG_ETHERTAP_MC
-static unsigned ethertap_mc_hash(__u8 *dest)
-{
-	unsigned idx = 0;
-	idx ^= dest[0];
-	idx ^= dest[1];
-	idx ^= dest[2];
-	idx ^= dest[3];
-	idx ^= dest[4];
-	idx ^= dest[5];
-	return 1U << (idx&0x1F);
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	unsigned groups = ~0;
-	struct net_local *lp = netdev_priv(dev);
-
-	if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) {
-		struct dev_mc_list *dmi;
-
-		groups = ethertap_mc_hash(dev->broadcast);
-
-		for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
-			if (dmi->dmi_addrlen != 6)
-				continue;
-			groups |= ethertap_mc_hash(dmi->dmi_addr);
-		}
-	}
-	lp->groups = groups;
-	if (lp->nl)
-		lp->nl->protinfo.af_netlink.groups = groups;
-}
-#endif
-
-/*
- *	We transmit by throwing the packet at netlink. We have to clone
- *	it for 2.0 so that we dev_kfree_skb() the locked original.
- */
- 
-static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_ETHERTAP_MC
-	struct ethhdr *eth = (struct ethhdr*)skb->data;
-#endif
-
-	if (skb_headroom(skb) < 2) {
-		static int once;
-	  	struct sk_buff *skb2;
-
-		if (!once) {
-			once = 1;
-			printk(KERN_DEBUG "%s: not aligned xmit by protocol %04x\n", dev->name, skb->protocol);
-		}
-
-		skb2 = skb_realloc_headroom(skb, 2);
-		dev_kfree_skb(skb);
-		if (skb2 == NULL)
-			return 0;
-		skb = skb2;
-	}
-	__skb_push(skb, 2);
-
-	/* Make the same thing, which loopback does. */
-	if (skb_shared(skb)) {
-	  	struct sk_buff *skb2 = skb;
-	  	skb = skb_clone(skb, GFP_ATOMIC);	/* Clone the buffer */
-	  	if (skb==NULL) {
-			dev_kfree_skb(skb2);
-			return 0;
-		}
-	  	dev_kfree_skb(skb2);
-	}
-	/* ... but do not orphan it here, netlink does it in any case. */
-
-	lp->stats.tx_bytes+=skb->len;
-	lp->stats.tx_packets++;
-
-#ifndef CONFIG_ETHERTAP_MC
-	netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC);
-#else
-	if (dev->flags&IFF_NOARP) {
-		netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC);
-		return 0;
-	}
-
-	if (!(eth->h_dest[0]&1)) {
-		/* Unicast packet */
-		__u32 pid;
-		memcpy(&pid, eth->h_dest+2, 4);
-		netlink_unicast(lp->nl, skb, ntohl(pid), MSG_DONTWAIT);
-	} else
-		netlink_broadcast(lp->nl, skb, 0, ethertap_mc_hash(eth->h_dest), GFP_ATOMIC);
-#endif
-	return 0;
-}
-
-static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_ETHERTAP_MC
-	struct ethhdr *eth = (struct ethhdr*)(skb->data + 2);
-#endif
-	int len = skb->len;
-
-	if (len < 16) {
-		printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
-		kfree_skb(skb);
-		return -EINVAL;
-	}
-	if (NETLINK_CREDS(skb)->uid) {
-		printk(KERN_INFO "%s : user %d\n", dev->name, NETLINK_CREDS(skb)->uid);
-		kfree_skb(skb);
-		return -EPERM;
-	}
-
-#ifdef CONFIG_ETHERTAP_MC
-	if (!(dev->flags&(IFF_NOARP|IFF_PROMISC))) {
-		int drop = 0;
-
-		if (eth->h_dest[0]&1) {
-			if (!(ethertap_mc_hash(eth->h_dest)&lp->groups))
-				drop = 1;
-		} else if (memcmp(eth->h_dest, dev->dev_addr, 6) != 0)
-			drop = 1;
-
-		if (drop) {
-			if (ethertap_debug > 3)
-				printk(KERN_DEBUG "%s : not for us\n", dev->name);
-			kfree_skb(skb);
-			return -EINVAL;
-		}
-	}
-#endif
-
-	if (skb_shared(skb)) {
-	  	struct sk_buff *skb2 = skb;
-	  	skb = skb_clone(skb, GFP_KERNEL);	/* Clone the buffer */
-	  	if (skb==NULL) {
-			kfree_skb(skb2);
-			return -ENOBUFS;
-		}
-	  	kfree_skb(skb2);
-	} else
-		skb_orphan(skb);
-
-	skb_pull(skb, 2);
-	skb->dev = dev;
-	skb->protocol=eth_type_trans(skb,dev);
-	memset(skb->cb, 0, sizeof(skb->cb));
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes+=len;
-	netif_rx(skb);
-	dev->last_rx = jiffies;
-	return len;
-}
-
-/*
- *	The typical workload of the driver:
- *	Handle the ether interface interrupts.
- *
- *	(In this case handle the packets posted from user space..)
- */
-
-static void ethertap_rx(struct sock *sk, int len)
-{
-	unsigned unit = sk->sk_protocol - NETLINK_TAPBASE; 
-	struct net_device *dev;
-	struct sk_buff *skb;
-
-	if (unit >= max_taps || (dev = tap_map[unit]) == NULL) { 
-		printk(KERN_CRIT "ethertap: bad unit %u!\n", unit);
-		skb_queue_purge(&sk->sk_receive_queue);
-		return;
-	}
-
-	if (ethertap_debug > 3)
-		printk(KERN_DEBUG "%s: ethertap_rx()\n", dev->name);
-
-	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
-		ethertap_rx_skb(skb, dev);
-}
-
-static int ethertap_close(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sock *sk = lp->nl;
-
-	if (ethertap_debug > 2)
-		printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
-
-	netif_stop_queue(dev);
-
-	if (sk) {
-		lp->nl = NULL;
-		sock_release(sk->sk_socket);
-	}
-
-	return 0;
-}
-
-static struct net_device_stats *ethertap_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
-
-int __init ethertap_init(void)
-{
-	int i, err = 0;
-
-	/* netlink can only hande 16 entries unless modified */
-	if (max_taps > MAX_LINKS - NETLINK_TAPBASE)
-		return -E2BIG;
-
-	tap_map = kmalloc(sizeof(struct net_device *)*max_taps, GFP_KERNEL);
-	if (!tap_map)
-		return -ENOMEM;
-
-	for (i = 0; i < max_taps; i++) {
-		err = ethertap_probe(i);
-		if (err) {
-			while (--i > 0) {
-				unregister_netdev(tap_map[i]);
-				free_netdev(tap_map[i]);
-			}
-			break;
-		}
-	}
-	if (err)
-		kfree(tap_map);
-	return err;
-}
-module_init(ethertap_init);
-
-void __exit ethertap_cleanup(void)
-{
-	int i;
-
-	for (i = 0; i < max_taps; i++) {
-		struct net_device *dev = tap_map[i];
-		if (dev) {
-			tap_map[i] = NULL;
-			unregister_netdev(dev);
-			free_netdev(dev);
-		}
-	}
-	kfree(tap_map);
-}
-module_exit(ethertap_cleanup);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -273,6 +273,7 @@ struct ewrk3_stats {
 struct ewrk3_private {
 	char adapter_name[80];	/* Name exported to /proc/ioports */
 	u_long shmem_base;	/* Shared memory start address */
+	void __iomem *shmem;
 	u_long shmem_length;	/* Shared memory window length */
 	struct net_device_stats stats;	/* Public stats */
 	struct ewrk3_stats pktStats; /* Private stats counters */
@@ -281,7 +282,7 @@ struct ewrk3_private {
 	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 */
+	void __iomem *mctbl;	/* Pointer to the multicast table */
 	u_char led_mask;	/* Used to reserve LED access for ethtool */
 	spinlock_t hw_lock;
 };
@@ -535,6 +536,9 @@ ewrk3_hw_init(struct net_device *dev, u_
 
 	lp = netdev_priv(dev);
 	lp->shmem_base = mem_start;
+	lp->shmem = ioremap(mem_start, shmem_length);
+	if (!lp->shmem)
+		return -ENOMEM;
 	lp->shmem_length = shmem_length;
 	lp->lemac = lemac;
 	lp->hard_strapped = hard_strapped;
@@ -590,6 +594,7 @@ ewrk3_hw_init(struct net_device *dev, u_
 				} else {
 					printk(", but incorrect IRQ line detected.\n");
 				}
+				iounmap(lp->shmem);
 				return -ENXIO;
 			}
 
@@ -768,7 +773,7 @@ static int ewrk3_queue_pkt (struct sk_bu
 {
 	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
-	u_long buf = 0;
+	void __iomem *buf = NULL;
 	u_char icr;
 	u_char page;
 
@@ -801,13 +806,13 @@ static int ewrk3_queue_pkt (struct sk_bu
 	if (lp->shmem_length == IO_ONLY) {
 		outb (page, EWRK3_IOPR);
 	} else if (lp->shmem_length == SHMEM_2K) {
-		buf = lp->shmem_base;
+		buf = lp->shmem;
 		outb (page, EWRK3_MPR);
 	} else if (lp->shmem_length == SHMEM_32K) {
-		buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+		buf = (((short) page << 11) & 0x7800) + lp->shmem;
 		outb ((page >> 4), EWRK3_MPR);
 	} else if (lp->shmem_length == SHMEM_64K) {
-		buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+		buf = (((short) page << 11) & 0xf800) + lp->shmem;
 		outb ((page >> 5), EWRK3_MPR);
 	} else {
 		printk (KERN_ERR "%s: Oops - your private data area is hosed!\n",
@@ -831,30 +836,28 @@ static int ewrk3_queue_pkt (struct sk_bu
 		}
 		outb (page, EWRK3_TQ);	/* Start sending pkt */
 	} else {
-		isa_writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf);	/* ctrl byte */
+		writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf);	/* ctrl byte */
 		buf += 1;
-		isa_writeb ((char) (skb->len & 0xff), buf);	/* length (16 bit xfer) */
+		writeb ((char) (skb->len & 0xff), buf);	/* length (16 bit xfer) */
 		buf += 1;
 		if (lp->txc) {
-			isa_writeb ((char)
-				    (((skb->len >> 8) & 0xff) | XCT), buf);
+			writeb(((skb->len >> 8) & 0xff) | XCT, buf);
 			buf += 1;
-			isa_writeb (0x04, buf);	/* index byte */
+			writeb (0x04, buf);	/* index byte */
 			buf += 1;
-			isa_writeb (0x00, (buf + skb->len));	/* Write the XCT flag */
-			isa_memcpy_toio (buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
+			writeb (0x00, (buf + skb->len));	/* Write the XCT flag */
+			memcpy_toio (buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
 			outb (page, EWRK3_TQ);	/* Start sending pkt */
-			isa_memcpy_toio (buf + PRELOAD,
+			memcpy_toio (buf + PRELOAD,
 					 skb->data + PRELOAD,
 					 skb->len - PRELOAD);
-			isa_writeb (0xff, (buf + skb->len));	/* Write the XCT flag */
+			writeb (0xff, (buf + skb->len));	/* Write the XCT flag */
 		} else {
-			isa_writeb ((char)
-				    ((skb->len >> 8) & 0xff), buf);
+			writeb ((skb->len >> 8) & 0xff, buf);
 			buf += 1;
-			isa_writeb (0x04, buf);	/* index byte */
+			writeb (0x04, buf);	/* index byte */
 			buf += 1;
-			isa_memcpy_toio (buf, skb->data, skb->len);	/* Write data bytes */
+			memcpy_toio (buf, skb->data, skb->len);	/* Write data bytes */
 			outb (page, EWRK3_TQ);	/* Start sending pkt */
 		}
 	}
@@ -940,7 +943,7 @@ static int ewrk3_rx(struct net_device *d
 	u_long iobase = dev->base_addr;
 	int i, status = 0;
 	u_char page;
-	u_long buf = 0;
+	void __iomem *buf = NULL;
 
 	while (inb(EWRK3_RQC) && !status) {	/* Whilst there's incoming data */
 		if ((page = inb(EWRK3_RQ)) < lp->mPage) {	/* Get next entry's buffer page */
@@ -950,13 +953,13 @@ static int ewrk3_rx(struct net_device *d
 			if (lp->shmem_length == IO_ONLY) {
 				outb(page, EWRK3_IOPR);
 			} else if (lp->shmem_length == SHMEM_2K) {
-				buf = lp->shmem_base;
+				buf = lp->shmem;
 				outb(page, EWRK3_MPR);
 			} else if (lp->shmem_length == SHMEM_32K) {
-				buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+				buf = (((short) page << 11) & 0x7800) + lp->shmem;
 				outb((page >> 4), EWRK3_MPR);
 			} else if (lp->shmem_length == SHMEM_64K) {
-				buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+				buf = (((short) page << 11) & 0xf800) + lp->shmem;
 				outb((page >> 5), EWRK3_MPR);
 			} else {
 				status = -1;
@@ -972,9 +975,9 @@ static int ewrk3_rx(struct net_device *d
 					pkt_len = inb(EWRK3_DATA);
 					pkt_len |= ((u_short) inb(EWRK3_DATA) << 8);
 				} else {
-					rx_status = isa_readb(buf);
+					rx_status = readb(buf);
 					buf += 1;
-					pkt_len = isa_readw(buf);
+					pkt_len = readw(buf);
 					buf += 3;
 				}
 
@@ -1001,7 +1004,7 @@ static int ewrk3_rx(struct net_device *d
 								*p++ = inb(EWRK3_DATA);
 							}
 						} else {
-							isa_memcpy_fromio(p, buf, pkt_len);
+							memcpy_fromio(p, buf, pkt_len);
 						}
 
 						for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
@@ -1153,9 +1156,9 @@ static void set_multicast_list(struct ne
 	csr = inb(EWRK3_CSR);
 
 	if (lp->shmem_length == IO_ONLY) {
-		lp->mctbl = (char *) PAGE0_HTE;
+		lp->mctbl = NULL;
 	} else {
-		lp->mctbl = (char *) (lp->shmem_base + PAGE0_HTE);
+		lp->mctbl = lp->shmem + PAGE0_HTE;
 	}
 
 	csr &= ~(CSR_PME | CSR_MCE);
@@ -1184,7 +1187,7 @@ static void SetMulticastFilter(struct ne
 	u_long iobase = dev->base_addr;
 	int i;
 	char *addrs, bit, byte;
-	short *p = (short *) lp->mctbl;
+	short __iomem *p = lp->mctbl;
 	u16 hashcode;
 	u32 crc;
 
@@ -1192,7 +1195,7 @@ static void SetMulticastFilter(struct ne
 
 	if (lp->shmem_length == IO_ONLY) {
 		outb(0, EWRK3_IOPR);
-		outw(EEPROM_OFFSET(lp->mctbl), EWRK3_PIR1);
+		outw(PAGE0_HTE, EWRK3_PIR1);
 	} else {
 		outb(0, EWRK3_MPR);
 	}
@@ -1202,7 +1205,7 @@ static void SetMulticastFilter(struct ne
 			if (lp->shmem_length == IO_ONLY) {
 				outb(0xff, EWRK3_DATA);
 			} else {	/* memset didn't work here */
-				isa_writew(0xffff, (int) p);
+				writew(0xffff, p);
 				p++;
 				i++;
 			}
@@ -1219,8 +1222,8 @@ static void SetMulticastFilter(struct ne
 				outb(0x00, EWRK3_DATA);
 			}
 		} else {
-			isa_memset_io((int) lp->mctbl, 0, (HASH_TABLE_LEN >> 3));
-			isa_writeb(0x80, (int) (lp->mctbl + (HASH_TABLE_LEN >> 4) - 1));
+			memset_io(lp->mctbl, 0, HASH_TABLE_LEN >> 3);
+			writeb(0x80, lp->mctbl + (HASH_TABLE_LEN >> 4) - 1);
 		}
 
 		/* Update table */
@@ -1237,13 +1240,13 @@ static void SetMulticastFilter(struct ne
 				if (lp->shmem_length == IO_ONLY) {
 					u_char tmp;
 
-					outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1);
+					outw(PAGE0_HTE + byte, EWRK3_PIR1);
 					tmp = inb(EWRK3_DATA);
 					tmp |= bit;
-					outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1);
+					outw(PAGE0_HTE + byte, EWRK3_PIR1);
 					outb(tmp, EWRK3_DATA);
 				} else {
-					isa_writeb(isa_readb((int)(lp->mctbl + byte)) | bit, (int)(lp->mctbl + byte));
+					writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);
 				}
 			}
 		}
@@ -1654,8 +1657,7 @@ static int ewrk3_phys_id(struct net_devi
 
 		/* Wait a little while */
 		spin_unlock_irqrestore(&lp->hw_lock, flags);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ>>2);
+		msleep(250);
 		spin_lock_irqsave(&lp->hw_lock, flags);
 
 		/* Exit if we got a signal */
@@ -1784,7 +1786,7 @@ static int ewrk3_ioctl(struct net_device
 			}
 		} else {
 			outb(0, EWRK3_MPR);
-			isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
+			memcpy_fromio(tmp->addr, lp->shmem + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
 		}
 		spin_unlock_irqrestore(&lp->hw_lock, flags);
 
@@ -1954,10 +1956,13 @@ static __exit void ewrk3_exit_module(voi
 	int i;
 
 	for( i=0; i<ndevs; i++ ) {
-		unregister_netdev(ewrk3_devs[i]);
-		release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE);
-		free_netdev(ewrk3_devs[i]);
+		struct net_device *dev = ewrk3_devs[i];
+		struct ewrk3_private *lp = netdev_priv(dev);
 		ewrk3_devs[i] = NULL;
+		unregister_netdev(dev);
+		release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
+		iounmap(lp->shmem);
+		free_netdev(dev);
 	}
 }
 
diff --git a/drivers/net/fc/Makefile b/drivers/net/fc/Makefile
deleted file mode 100644
--- a/drivers/net/fc/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for linux/drivers/net/fc
-#
-# 9 Aug 2000, Christoph Hellwig <hch@infradead.org>
-# Rewritten to use lists instead of if-statements.
-#
-
-obj-$(CONFIG_IPHASE5526)	+= iph5526.o
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
deleted file mode 100644
--- a/drivers/net/fc/iph5526.c
+++ /dev/null
@@ -1,4645 +0,0 @@
-/**********************************************************************
- * iph5526.c: IP/SCSI driver for the Interphase 5526 PCI Fibre Channel
- *			  Card.
- * Copyright (C) 1999 Vineet M Abraham <vmabraham@hotmail.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.
- *********************************************************************/
-/**********************************************************************
-Log:
-Vineet M Abraham
-02.12.99 Support multiple cards.
-03.15.99 Added Fabric support.
-04.04.99 Added N_Port support.
-04.15.99 Added SCSI support.
-06.18.99 Added ABTS Protocol.
-06.24.99 Fixed data corruption when multiple XFER_RDYs are received.
-07.07.99 Can be loaded as part of the Kernel. Changed semaphores. Added
-         more checks before invalidating SEST entries.
-07.08.99 Added Broadcast IP stuff and fixed an unicast timeout bug.
-***********************************************************************/
-/* TODO:
-	R_T_TOV set to 15msec in Loop topology. Need to be 100 msec.
-    SMP testing.
-	Fix ADISC Tx before completing FLOGI. 
-*/	
-
-static const char *version =
-    "iph5526.c:v1.0 07.08.99 Vineet Abraham (vmabraham@hotmail.com)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/fcdevice.h> /* had the declarations for init_fcdev among
-			       others + includes if_fcdevice.h */
-
-#include "../../scsi/scsi.h"
-#include <scsi/scsi_host.h>
-#include "../../fc4/fcp.h"
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-/* driver specific header files */
-#include "tach.h"
-#include "tach_structs.h"
-#include "iph5526_ip.h"
-#include "iph5526_scsi.h"
-#include "iph5526_novram.c"
-
-#define RUN_AT(x) (jiffies + (x))
-
-#define DEBUG_5526_0 0
-#define DEBUG_5526_1 0
-#define DEBUG_5526_2 0
-
-#if DEBUG_5526_0
-#define DPRINTK(format, a...) {printk("%s: ", fi->name); \
-							   printk(format, ##a); \
-							   printk("\n");}
-#define ENTER(x)	{printk("%s: ", fi->name); \
-					 printk("iph5526.c : entering %s()\n", x);}
-#define LEAVE(x)	{printk("%s: ", fi->name); \
-					 printk("iph5526.c : leaving %s()\n",x);}
-
-#else
-#define DPRINTK(format, a...) {}
-#define ENTER(x)	{}
-#define LEAVE(x)	{}
-#endif
-
-#if DEBUG_5526_1
-#define DPRINTK1(format, a...) {printk("%s: ", fi->name); \
-							   printk(format, ##a); \
-							   printk("\n");}
-#else
-#define DPRINTK1(format, a...) {}
-#endif
-
-#if DEBUG_5526_2
-#define DPRINTK2(format, a...) {printk("%s: ", fi->name); \
-							   printk(format, ##a); \
-							   printk("\n");}
-#else
-#define DPRINTK2(format, a...) {}
-#endif
-
-#define T_MSG(format, a...) {printk("%s: ", fi->name); \
-							 printk(format, ##a);\
-							 printk("\n");}
-
-#define ALIGNED_SFS_ADDR(addr) ((((unsigned long)(addr) + (SFS_BUFFER_SIZE - 1)) & ~(SFS_BUFFER_SIZE - 1)) - (unsigned long)(addr))
-#define ALIGNED_ADDR(addr, len) ((((unsigned long)(addr) + (len - 1)) & ~(len - 1)) - (unsigned long)(addr))
-
-
-static struct pci_device_id iph5526_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_5526, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_55x6, PCI_ANY_ID, PCI_ANY_ID, },
-	{ }			/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, iph5526_pci_tbl);
-
-MODULE_LICENSE("GPL");
-
-#define MAX_FC_CARDS 2
-static struct fc_info *fc[MAX_FC_CARDS+1];
-static unsigned int pci_irq_line;
-static struct {
-	unsigned short vendor_id;
-	unsigned short device_id;
-	char *name;
-}
-clone_list[] __initdata  = {
-	{PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_5526, "Interphase Fibre Channel HBA"},
-	{PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_55x6, "Interphase Fibre Channel HBA"},
-	{0,}
-};
-
-static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs);
-
-static int initialize_register_pointers(struct fc_info *fi);
-void clean_up_memory(struct fc_info *fi);
-
-static int tachyon_init(struct fc_info *fi);
-static int build_queues(struct fc_info *fi);
-static void build_tachyon_header(struct fc_info *fi, u_int my_id, u_int r_ctl, u_int d_id, u_int type, u_char seq_id, u_char df_ctl, u_short ox_id, u_short rx_id, char *data);
-static int get_free_header(struct fc_info *fi);
-static void build_EDB(struct fc_info *fi, char *data, u_short flags, u_short len);
-static int get_free_EDB(struct fc_info *fi);
-static void build_ODB(struct fc_info *fi, u_char seq_id, u_int d_id, u_int len, u_int cntl, u_short mtu, u_short ox_id, u_short rx_id, int NW_header, int int_required, u_int frame_class);
-static void write_to_tachyon_registers(struct fc_info *fi);
-static void reset_latch(struct fc_info *fi);
-static void reset_tachyon(struct fc_info *fi, u_int value);
-static void take_tachyon_offline(struct fc_info *fi);
-static void read_novram(struct fc_info *fi);
-static void reset_ichip(struct fc_info *fi);
-static void update_OCQ_indx(struct fc_info *fi);
-static void update_IMQ_indx(struct fc_info *fi, int count);
-static void update_SFSBQ_indx(struct fc_info *fi);
-static void update_MFSBQ_indx(struct fc_info *fi, int count);
-static void update_tachyon_header_indx(struct fc_info *fi);
-static void update_EDB_indx(struct fc_info *fi);
-static void handle_FM_interrupt(struct fc_info *fi);
-static void handle_MFS_interrupt(struct fc_info *fi);
-static void handle_OOO_interrupt(struct fc_info *fi);
-static void handle_SFS_interrupt(struct fc_info *fi);
-static void handle_OCI_interrupt(struct fc_info *fi);
-static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi);
-static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi);
-static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi);
-static void handle_Unknown_Frame_interrupt(struct fc_info *fi);
-static void handle_Busied_Frame_interrupt(struct fc_info *fi);
-static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi);
-static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi);
-static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi);
-static void completion_message_handler(struct fc_info *fi, u_int imq_int_type);
-static void fill_login_frame(struct fc_info *fi, u_int logi);
-
-static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short ox_id, u_int frame_class);
-static int tx_sequence(struct fc_info *fi, char *data, u_int len, u_int mtu, u_int d_id, u_short ox_id, u_short rx_id, u_char seq_id, int NW_flag, int int_required, u_int frame_class);
-static int validate_login(struct fc_info *fi, u_int *base_ptr);
-static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr);
-static void remove_from_address_cache(struct fc_info *fi, u_int *data, u_int cmnd_code);
-static int node_logged_in_prev(struct fc_info *fi, u_int *buff_addr);
-static int sid_logged_in(struct fc_info *fi, u_int s_id);
-static struct fc_node_info *look_up_cache(struct fc_info *fi, char *data);
-static int display_cache(struct fc_info *fi);
-
-static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id);
-static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id);
-static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id);
-static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id);
-static void tx_adisc(struct fc_info *fi, u_int cmnd_code, u_int d_id, u_short received_ox_id);
-static void tx_ls_rjt(struct fc_info *fi, u_int d_id, u_short received_ox_id, u_short reason_code, u_short expln_code);
-static u_int plogi_ok(struct fc_info *fi, u_int *buff_addr, int size);
-static void tx_acc(struct fc_info *fi, u_int d_id, u_short received_ox_id);
-static void tx_name_server_req(struct fc_info *fi, u_int req);
-static void rscn_handler(struct fc_info *fi, u_int node_id);
-static void tx_scr(struct fc_info *fi);
-static void scr_timer(unsigned long data);
-static void explore_fabric(struct fc_info *fi, u_int *buff_addr);
-static void perform_adisc(struct fc_info *fi);
-static void local_port_discovery(struct fc_info *fi);
-static void add_to_ox_id_list(struct fc_info *fi, u_int transaction_id, u_int cmnd_code);
-static u_int remove_from_ox_id_list(struct fc_info *fi, u_short received_ox_id);
-static void add_display_cache_timer(struct fc_info *fi);
-
-/* Timers... */
-static void nos_ols_timer(unsigned long data);
-static void loop_timer(unsigned long data);
-static void fabric_explore_timer(unsigned long data);
-static void port_discovery_timer(unsigned long data);
-static void display_cache_timer(unsigned long data);
-
-/* SCSI Stuff */
-static int add_to_sest(struct fc_info *fi, Scsi_Cmnd *Cmnd, struct fc_node_info *ni);
-static struct fc_node_info *resolve_target(struct fc_info *fi, u_char target);
-static void update_FCP_CMND_indx(struct fc_info *fi);
-static int get_free_SDB(struct fc_info *fi);
-static void update_SDB_indx(struct fc_info *fi);
-static void mark_scsi_sid(struct fc_info *fi, u_int *buff_addr, u_char action);
-static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id);
-static int abort_exchange(struct fc_info *fi, u_short ox_id);
-static void flush_tachyon_cache(struct fc_info *fi, u_short ox_id);
-static int get_scsi_oxid(struct fc_info *fi);
-static void update_scsi_oxid(struct fc_info *fi);
-
-static Scsi_Host_Template driver_template = IPH5526_SCSI_FC;
-
-static void iph5526_timeout(struct net_device *dev);
-
-static int iph5526_probe_pci(struct net_device *dev);
-
-int __init iph5526_probe(struct net_device *dev)
-{
-	if (iph5526_probe_pci(dev) == 0)
-		return 0;
-	return -ENODEV;
-}
-
-static int __init iph5526_probe_pci(struct net_device *dev)
-{
-	struct fc_info *fi = dev->priv;
-	fi->dev = dev;
-	dev->base_addr = fi->base_addr;
-	dev->irq = fi->irq;
-	if (dev->priv == NULL) 
-		dev->priv = fi; 
-	fcdev_init(dev);
-	/* Assign ur MAC address.
-	 */
-	dev->dev_addr[0] = (fi->g.my_port_name_high & 0x0000FF00) >> 8;
-	dev->dev_addr[1] = fi->g.my_port_name_high;
-	dev->dev_addr[2] = (fi->g.my_port_name_low & 0xFF000000) >> 24;
-	dev->dev_addr[3] = (fi->g.my_port_name_low & 0x00FF0000) >> 16;
-	dev->dev_addr[4] = (fi->g.my_port_name_low & 0x0000FF00) >> 8;
-	dev->dev_addr[5] = fi->g.my_port_name_low;
-	display_cache(fi);
-	return 0;
-}
-
-static int __init fcdev_init(struct net_device *dev)
-{
-	SET_MODULE_OWNER(dev);
-	dev->open = iph5526_open;
-	dev->stop = iph5526_close;
-	dev->hard_start_xmit = iph5526_send_packet;
-	dev->get_stats = iph5526_get_stats;
-	dev->set_multicast_list = NULL;
-	dev->change_mtu = iph5526_change_mtu; 
-	dev->tx_timeout = iph5526_timeout;
-	dev->watchdog_timeo = 5*HZ;
-	return 0;
-}
-
-/* initialize tachyon and take it OnLine */
-static int tachyon_init(struct fc_info *fi)
-{
-	ENTER("tachyon_init");
-	if (build_queues(fi) == 0) {
-		T_MSG("build_queues() failed");
-		return 0;
-	}
-
-	/* Retrieve your port/node name.
-	 */
-	read_novram(fi);
-
-	reset_ichip(fi);
-
-	reset_tachyon(fi, SOFTWARE_RESET);
-
-	LEAVE("tachyon_init");
-	return 1;
-}
-
-/* Build the 4 Qs - IMQ, OCQ, MFSBQ, SFSBQ */
-/* Lots of dma_pages needed as Tachyon DMAs almost everything into 
- * host memory.
- */
-static int build_queues(struct fc_info *fi)
-{
-int i,j;
-u_char *addr;
-	ENTER("build_queues");
-	/* Initializing Queue Variables.
-	 */
-	fi->q.ptr_host_ocq_cons_indx = NULL;
-	fi->q.ptr_host_hpcq_cons_indx = NULL;
-	fi->q.ptr_host_imq_prod_indx = NULL;
-
-	fi->q.ptr_ocq_base = NULL;
-	fi->q.ocq_len = 0;
-	fi->q.ocq_end = 0;
-	fi->q.ocq_prod_indx = 0;
-
-	fi->q.ptr_imq_base = NULL;
-	fi->q.imq_len = 0;
-	fi->q.imq_end = 0;
-	fi->q.imq_cons_indx = 0;
-	fi->q.imq_prod_indx = 0;
-
-	fi->q.ptr_mfsbq_base = NULL;
-	fi->q.mfsbq_len = 0;
-	fi->q.mfsbq_end = 0;
-	fi->q.mfsbq_prod_indx = 0;
-	fi->q.mfsbq_cons_indx = 0;
-	fi->q.mfsbuff_len = 0;
-	fi->q.mfsbuff_end = 0;
-	fi->g.mfs_buffer_count = 0;
-
-	fi->q.ptr_sfsbq_base = NULL;
-	fi->q.sfsbq_len = 0;
-	fi->q.sfsbq_end = 0;
-	fi->q.sfsbq_prod_indx = 0;
-	fi->q.sfsbq_cons_indx = 0;
-	fi->q.sfsbuff_len = 0;
-	fi->q.sfsbuff_end = 0;
-
-	fi->q.sdb_indx = 0;
-	fi->q.fcp_cmnd_indx = 0;
-
-	fi->q.ptr_edb_base = NULL;
-	fi->q.edb_buffer_indx = 0;
-	fi->q.ptr_tachyon_header_base = NULL;
-	fi->q.tachyon_header_indx = 0;
-	fi->node_info_list = NULL;
-	fi->ox_id_list = NULL;
-	fi->g.loop_up = FALSE;
-	fi->g.ptp_up = FALSE;
-	fi->g.link_up = FALSE;
-	fi->g.fabric_present = FALSE;
-	fi->g.n_port_try = FALSE;
-	fi->g.dont_init = FALSE;
-	fi->g.nport_timer_set = FALSE;
-	fi->g.lport_timer_set = FALSE;
-	fi->g.no_of_targets = 0;
-	fi->g.sem = 0;
-	fi->g.perform_adisc = FALSE;
-	fi->g.e_i = 0;
-
-	/* build OCQ */
-	if ( (fi->q.ptr_ocq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
-		T_MSG("failed to get OCQ page");
-		return 0;
-	}
-	/* set up the OCQ structures */
-	for (i = 0; i < OCQ_LENGTH; i++)
-		fi->q.ptr_odb[i] = fi->q.ptr_ocq_base + NO_OF_ENTRIES*i;
-
-	/* build IMQ */
-	if ( (fi->q.ptr_imq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
-		T_MSG("failed to get IMQ page");
-		return 0;
-	}
-	for (i = 0; i < IMQ_LENGTH; i++)
-		fi->q.ptr_imqe[i] = fi->q.ptr_imq_base + NO_OF_ENTRIES*i;
-
-	/* build MFSBQ */
-	if ( (fi->q.ptr_mfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
-		T_MSG("failed to get MFSBQ page");
-		return 0;
-	}
-	memset((char *)fi->q.ptr_mfsbq_base, 0, MFSBQ_LENGTH * 32);
-	/* Allocate one huge chunk of memory... helps while reassembling
-	 * frames.
-	 */
-	if ( (addr = (u_char *)__get_free_pages(GFP_KERNEL, 5) ) == 0) {
-		T_MSG("failed to get MFSBQ page");
-		return 0;
-	}
-	/* fill in addresses of empty buffers */
-	for (i = 0; i < MFSBQ_LENGTH; i++) {
-		for (j = 0; j < NO_OF_ENTRIES; j++) {
-				*(fi->q.ptr_mfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr));
-				addr += MFS_BUFFER_SIZE;
-		}
-	}
-
-	/* The number of entries in each MFS buffer is 8. There are 8
-	 * MFS buffers. That leaves us with 4096-256 bytes. We use them
-	 * as temporary space for ELS frames. This is done to make sure that
-	 * the addresses are aligned.
-	 */
-	fi->g.els_buffer[0] = fi->q.ptr_mfsbq_base + MFSBQ_LENGTH*NO_OF_ENTRIES;
-	for (i = 1; i < MAX_PENDING_FRAMES; i++)
-		fi->g.els_buffer[i] = fi->g.els_buffer[i-1] + 64;
-	
-	/* build SFSBQ */
-	if ( (fi->q.ptr_sfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
-		T_MSG("failed to get SFSBQ page");
-		return 0;
-	}
-	memset((char *)fi->q.ptr_sfsbq_base, 0, SFSBQ_LENGTH * 32);
-	/* fill in addresses of empty buffers */
-	for (i = 0; i < SFSBQ_LENGTH; i++)
-		for (j = 0; j < NO_OF_ENTRIES; j++){
-			addr = kmalloc(SFS_BUFFER_SIZE*2, GFP_KERNEL);
-			if (addr == NULL){ 
-				T_MSG("ptr_sfs_buffer : memory not allocated");
-				return 0;
-			}
-			else {
-			int offset = ALIGNED_SFS_ADDR(addr);
-				memset((char *)addr, 0, SFS_BUFFER_SIZE);
-				fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES +j] = (u_int *)addr;
-				addr += offset;
-				*(fi->q.ptr_sfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr));
-			}
-		}
-
-	/* The number of entries in each SFS buffer is 8. There are 8
-	 * MFS buffers. That leaves us with 4096-256 bytes. We use them
-	 * as temporary space for ARP frames. This is done inorder to 
-	 * support HW_Types of 0x1 and 0x6. 
-	 */
-	fi->g.arp_buffer = (char *)fi->q.ptr_sfsbq_base + SFSBQ_LENGTH*NO_OF_ENTRIES*4;
-	
-	/* build EDB */
-	if ((fi->q.ptr_edb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5) ) == 0) {
-		T_MSG("failed to get EDB page");
-		return 0;
-	}
-	for (i = 0; i < EDB_LEN; i++)
-		fi->q.ptr_edb[i] = fi->q.ptr_edb_base + 2*i;
-
-	/* build SEST */
-
-	/* OX_IDs range from 0x0 - 0x4FFF.
-	 */
-	if ((fi->q.ptr_sest_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) {
-		T_MSG("failed to get SEST page");
-		return 0;
-	}
-	for (i = 0; i < SEST_LENGTH; i++)
-		fi->q.ptr_sest[i] = fi->q.ptr_sest_base + NO_OF_ENTRIES*i;
-	
-	if ((fi->q.ptr_sdb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) {
-		T_MSG("failed to get SDB page");
-		return 0;
-	}
-	for (i = 0 ; i < NO_OF_SDB_ENTRIES; i++)
-		fi->q.ptr_sdb_slot[i] = fi->q.ptr_sdb_base + (SDB_SIZE/4)*i;
-
-	if ((fi->q.ptr_fcp_cmnd_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
-		T_MSG("failed to get FCP_CMND page");
-		return 0;
-	}
-	for (i = 0; i < NO_OF_FCP_CMNDS; i++)
-		fi->q.ptr_fcp_cmnd[i] = fi->q.ptr_fcp_cmnd_base + NO_OF_ENTRIES*i;
-
-	/* Allocate space for Tachyon Header as well... 
-	 */
-	if ((fi->q.ptr_tachyon_header_base = (u_int *)__get_free_pages(GFP_KERNEL, 0) ) == 0) {
-		T_MSG("failed to get tachyon_header page");
-		return 0;
-	}
-	for (i = 0; i < NO_OF_TACH_HEADERS; i++) 
-		fi->q.ptr_tachyon_header[i] = fi->q.ptr_tachyon_header_base + 16*i;
-	
-	/* Allocate memory for indices.
-	 * Indices should be aligned on 32 byte boundaries. 
-	 */
-	fi->q.host_ocq_cons_indx = kmalloc(2*32, GFP_KERNEL);
-	if (fi->q.host_ocq_cons_indx == NULL){ 
-		T_MSG("fi->q.host_ocq_cons_indx : memory not allocated");
-		return 0;
-	}
-	fi->q.ptr_host_ocq_cons_indx = fi->q.host_ocq_cons_indx; 
-	if ((u_long)(fi->q.host_ocq_cons_indx) % 32)
-		fi->q.host_ocq_cons_indx++;
-	
-	fi->q.host_hpcq_cons_indx = kmalloc(2*32, GFP_KERNEL);
-	if (fi->q.host_hpcq_cons_indx == NULL){ 
-		T_MSG("fi->q.host_hpcq_cons_indx : memory not allocated");
-		return 0;
-	}
-	fi->q.ptr_host_hpcq_cons_indx= fi->q.host_hpcq_cons_indx;
-	if ((u_long)(fi->q.host_hpcq_cons_indx) % 32)
-		fi->q.host_hpcq_cons_indx++;
-
-	fi->q.host_imq_prod_indx = kmalloc(2*32, GFP_KERNEL);
-	if (fi->q.host_imq_prod_indx == NULL){ 
-		T_MSG("fi->q.host_imq_prod_indx : memory not allocated");
-		return 0;
-	}
-	fi->q.ptr_host_imq_prod_indx = fi->q.host_imq_prod_indx;
-	if ((u_long)(fi->q.host_imq_prod_indx) % 32)
-		fi->q.host_imq_prod_indx++;
-
-	LEAVE("build_queues");
-	return 1;
-}
-
-
-static void write_to_tachyon_registers(struct fc_info *fi)
-{
-u_int bus_addr, bus_indx_addr, i;
-
-	ENTER("write_to_tachyon_registers");
-
-	/* Clear Queues each time Tachyon is reset */
-	memset((char *)fi->q.ptr_ocq_base, 0, OCQ_LENGTH * 32);
-	memset((char *)fi->q.ptr_imq_base, 0, IMQ_LENGTH * 32);
-	memset((char *)fi->q.ptr_edb_base, 0, EDB_LEN * 8);
-	memset((char *)fi->q.ptr_sest_base, 0, SEST_LENGTH * 32);
-	memset((char *)fi->q.ptr_sdb_base, 0, NO_OF_SDB_ENTRIES * SDB_SIZE);
-	memset((char *)fi->q.ptr_tachyon_header_base, 0xFF, NO_OF_TACH_HEADERS * TACH_HEADER_SIZE);
-	for (i = 0; i < SEST_LENGTH; i++)
-		fi->q.free_scsi_oxid[i] = OXID_AVAILABLE;
-	for (i = 0; i < NO_OF_SDB_ENTRIES; i++)
-		fi->q.sdb_slot_status[i] = SDB_FREE;
-
-	take_tachyon_offline(fi);
-	writel(readl(fi->t_r.ptr_tach_config_reg) | SCSI_ENABLE | WRITE_STREAM_SIZE | READ_STREAM_SIZE | PARITY_EVEN | OOO_REASSEMBLY_DISABLE, fi->t_r.ptr_tach_config_reg);
-
-	/* Write OCQ registers */
-	fi->q.ocq_prod_indx = 0;
-	*(fi->q.host_ocq_cons_indx) = 0;
-	
-	/* The Tachyon needs to be passed the "real" address */
-	bus_addr = virt_to_bus(fi->q.ptr_ocq_base);
-	writel(bus_addr, fi->t_r.ptr_ocq_base_reg);
-	writel(OCQ_LENGTH - 1, fi->t_r. ptr_ocq_len_reg);
-	bus_indx_addr = virt_to_bus(fi->q.host_ocq_cons_indx);
-	writel(bus_indx_addr, fi->t_r.ptr_ocq_cons_indx_reg);
-
-	/* Write IMQ registers */
-	fi->q.imq_cons_indx = 0;
-	*(fi->q.host_imq_prod_indx) = 0;
-	bus_addr = virt_to_bus(fi->q.ptr_imq_base);
-	writel(bus_addr, fi->t_r.ptr_imq_base_reg);
-	writel(IMQ_LENGTH - 1, fi->t_r.ptr_imq_len_reg);
-	bus_indx_addr = virt_to_bus(fi->q.host_imq_prod_indx);
-	writel(bus_indx_addr, fi->t_r.ptr_imq_prod_indx_reg);
-	
-	/* Write MFSBQ registers */
-	fi->q.mfsbq_prod_indx = MFSBQ_LENGTH - 1;
-	fi->q.mfsbuff_end = MFS_BUFFER_SIZE - 1;
-	fi->q.mfsbq_cons_indx = 0;
-	bus_addr = virt_to_bus(fi->q.ptr_mfsbq_base);
-	writel(bus_addr, fi->t_r.ptr_mfsbq_base_reg);
-	writel(MFSBQ_LENGTH - 1, fi->t_r.ptr_mfsbq_len_reg);
-	writel(fi->q.mfsbuff_end, fi->t_r.ptr_mfsbuff_len_reg);
-	/* Do this last as tachyon will prefetch the 
-	 * first entry as soon as we write to it.
-	 */
-	writel(fi->q.mfsbq_prod_indx, fi->t_r.ptr_mfsbq_prod_reg);
-
-	/* Write SFSBQ registers */
-	fi->q.sfsbq_prod_indx = SFSBQ_LENGTH - 1;
-	fi->q.sfsbuff_end = SFS_BUFFER_SIZE - 1;
-	fi->q.sfsbq_cons_indx = 0;
-	bus_addr = virt_to_bus(fi->q.ptr_sfsbq_base);
-	writel(bus_addr, fi->t_r.ptr_sfsbq_base_reg);
-	writel(SFSBQ_LENGTH - 1, fi->t_r.ptr_sfsbq_len_reg);
-	writel(fi->q.sfsbuff_end, fi->t_r.ptr_sfsbuff_len_reg);
-	/* Do this last as tachyon will prefetch the first 
-	 * entry as soon as we write to it. 
-	 */
-	writel(fi->q.sfsbq_prod_indx, fi->t_r.ptr_sfsbq_prod_reg);
-
-	/* Write SEST registers */
-	bus_addr = virt_to_bus(fi->q.ptr_sest_base);
-	writel(bus_addr, fi->t_r.ptr_sest_base_reg);
-	writel(SEST_LENGTH - 1, fi->t_r.ptr_sest_len_reg);
-	/* the last 2 bits _should_ be 1 */
-	writel(SEST_BUFFER_SIZE - 1, fi->t_r.ptr_scsibuff_len_reg);
-
-	/* write AL_TIME & E_D_TOV into the registers */
-	writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-	/* Tell Tachyon to pick a Soft Assigned AL_PA */
-	writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
-
-	/* Read the WWN from EEPROM . But, for now we assign it here. */
-	writel(WORLD_WIDE_NAME_LOW, fi->t_r.ptr_fm_wwn_low_reg);
-	writel(WORLD_WIDE_NAME_HIGH, fi->t_r.ptr_fm_wwn_hi_reg);
-
-	DPRINTK1("TACHYON initializing as L_Port...\n");
-	writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-			
-	LEAVE("write_to_tachyon_registers");
-}
-
-
-static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
-{
-struct Scsi_Host *host = dev_id;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
-struct fc_info *fi = hostdata->fi; 
-u_long flags;
-	spin_lock_irqsave(&fi->fc_lock, flags);
-	tachyon_interrupt_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&fi->fc_lock, flags);
-	return IRQ_HANDLED;
-}
-
-static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs)
-{
-struct Scsi_Host *host = dev_id;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
-struct fc_info *fi = hostdata->fi; 
-u_int *ptr_imq_entry;
-u_int imq_int_type, current_IMQ_index = 0, prev_IMQ_index;
-int index, no_of_entries = 0;
-
-	DPRINTK("\n");
-	ENTER("tachyon_interrupt");
-	if (fi->q.host_imq_prod_indx != NULL) {
-		current_IMQ_index =  ntohl(*(fi->q.host_imq_prod_indx));
-	}
-	else {
-		/* _Should not_ happen */
-		T_MSG("IMQ_indx NULL. DISABLING INTERRUPTS!!!\n");
-		writel(0x0, fi->i_r.ptr_ichip_hw_control_reg);
-	}
-
-	if (current_IMQ_index > fi->q.imq_cons_indx)
-		no_of_entries = current_IMQ_index - fi->q.imq_cons_indx;
-	else
-	if (current_IMQ_index < fi->q.imq_cons_indx)
-		no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index);
-
-	if (no_of_entries == 0) {
-	u_int ichip_status;
-		ichip_status = readl(fi->i_r.ptr_ichip_hw_status_reg);
-		if (ichip_status & 0x20) {
-			/* Should _never_ happen. Might require a hard reset */
-			T_MSG("Too bad... PCI Bus Error. Resetting (i)chip"); 
-			reset_ichip(fi);
-			T_MSG("DISABLING INTERRUPTS!!!\n");
-			writel(0x0, fi->i_r.ptr_ichip_hw_control_reg);
-		}
-	}
-
-	prev_IMQ_index = current_IMQ_index;
-	for (index = 0; index < no_of_entries; index++) {
-		ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-		imq_int_type = ntohl(*ptr_imq_entry);
-
-		completion_message_handler(fi, imq_int_type);
-		if ((fi->g.link_up == FALSE) && ((imq_int_type == MFS_BUF_WARN) || (imq_int_type == SFS_BUF_WARN) || (imq_int_type == IMQ_BUF_WARN))) 
-			break;
-		update_IMQ_indx(fi, 1);
-	
-		/* Check for more entries */
-		current_IMQ_index =  ntohl(*(fi->q.host_imq_prod_indx));
-		if (current_IMQ_index != prev_IMQ_index) {
-			no_of_entries++;
-			prev_IMQ_index = current_IMQ_index;
-		}
-	} /*end of for loop*/		
-	LEAVE("tachyon_interrupt");
-       return;
-}
-
-
-static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi)
-{
-int i;
-	ENTER("handle_SFS_BUF_WARN_interrupt");
-	if (fi->g.link_up == FALSE) {
-		reset_tachyon(fi, SOFTWARE_RESET);
-		return;
-	}
-	/* Free up all but one entry in the Q. 
-	 */
-	for (i = 0; i < ((SFSBQ_LENGTH - 1) * NO_OF_ENTRIES); i++) {
-		handle_SFS_interrupt(fi);
-		update_IMQ_indx(fi, 1);
-	}
-	LEAVE("handle_SFS_BUF_WARN_interrupt");
-}
-
-/* Untested_Code_Begin */ 
-static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi)
-{
-int i;
-	ENTER("handle_MFS_BUF_WARN_interrupt");
-	if (fi->g.link_up == FALSE) {
-		reset_tachyon(fi, SOFTWARE_RESET);
-		return;
-	}
-	/* FIXME: freeing up 8 entries. 
-	 */
-	for (i = 0; i < NO_OF_ENTRIES; i++) {
-		handle_MFS_interrupt(fi);
-		update_IMQ_indx(fi, 1);
-	}
-	LEAVE("handle_MFS_BUF_WARN_interrupt");
-}
-/*Untested_Code_End */
-
-static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-u_int imq_int_type, current_IMQ_index = 0, temp_imq_cons_indx;
-int index, no_of_entries = 0;
-
-	ENTER("handle_IMQ_BUF_WARN_interrupt");
-	if (fi->g.link_up == FALSE) {
-		reset_tachyon(fi, SOFTWARE_RESET);
-		return;
-	}
-	current_IMQ_index =  ntohl(*(fi->q.host_imq_prod_indx));
-
-	if (current_IMQ_index > fi->q.imq_cons_indx)
- 		no_of_entries = current_IMQ_index - fi->q.imq_cons_indx;
-	else
-		if (current_IMQ_index < fi->q.imq_cons_indx)
-			no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index);
-	/* We don't want to look at the same IMQ entry again. 
-	 */
-	temp_imq_cons_indx = fi->q.imq_cons_indx + 1;
-	if (no_of_entries != 0)
-		no_of_entries -= 1;
-	for (index = 0; index < no_of_entries; index++) {
-		ptr_imq_entry = fi->q.ptr_imqe[temp_imq_cons_indx];
-		imq_int_type = ntohl(*ptr_imq_entry);
-		if (imq_int_type != IMQ_BUF_WARN)
-			completion_message_handler(fi, imq_int_type);
-		temp_imq_cons_indx++;
-		if (temp_imq_cons_indx == IMQ_LENGTH)
-			temp_imq_cons_indx = 0;
-	} /*end of for loop*/	
-	if (no_of_entries != 0)
-		update_IMQ_indx(fi, no_of_entries);
-	LEAVE("handle_IMQ_BUF_WARN_interrupt");
-}
-
-static void completion_message_handler(struct fc_info *fi, u_int imq_int_type)
-{
-	switch(imq_int_type) {
-		case OUTBOUND_COMPLETION:
-			DPRINTK("OUTBOUND_COMPLETION message received");
-			break;
-		case OUTBOUND_COMPLETION_I:
-			DPRINTK("OUTBOUND_COMPLETION_I message received");
-			handle_OCI_interrupt(fi);
-			break;
-		case OUT_HI_PRI_COMPLETION:
-			DPRINTK("OUT_HI_PRI_COMPLETION message received");
-			break;
-		case OUT_HI_PRI_COMPLETION_I:
-			DPRINTK("OUT_HI_PRI_COMPLETION_I message received");
-			break;
-		case INBOUND_MFS_COMPLETION:
-			DPRINTK("INBOUND_MFS_COMPLETION message received");
-			handle_MFS_interrupt(fi);
-			break;
-		case INBOUND_OOO_COMPLETION:
-			DPRINTK("INBOUND_OOO_COMPLETION message received");
-			handle_OOO_interrupt(fi);
-			break;
-		case INBOUND_SFS_COMPLETION:
-			DPRINTK("INBOUND_SFS_COMPLETION message received");
-			handle_SFS_interrupt(fi);
-			break;
-		case INBOUND_UNKNOWN_FRAME_I:
-			DPRINTK("INBOUND_UNKNOWN_FRAME message received");
-			handle_Unknown_Frame_interrupt(fi);
-			break;
-		case INBOUND_BUSIED_FRAME:
-			DPRINTK("INBOUND_BUSIED_FRAME message received");
-			handle_Busied_Frame_interrupt(fi);
-			break;
-		case FRAME_MGR_INTERRUPT:
-			DPRINTK("FRAME_MGR_INTERRUPT message received");
-			handle_FM_interrupt(fi);
-			break;
-		case READ_STATUS:
-			DPRINTK("READ_STATUS message received");
-			break;
-		case SFS_BUF_WARN:
-			DPRINTK("SFS_BUF_WARN message received");
-			handle_SFS_BUF_WARN_interrupt(fi);
-			break;
-		case MFS_BUF_WARN:
-			DPRINTK("MFS_BUF_WARN message received");
-			handle_MFS_BUF_WARN_interrupt(fi);
-			break;
-		case IMQ_BUF_WARN:
-			DPRINTK("IMQ_BUF_WARN message received");
-			handle_IMQ_BUF_WARN_interrupt(fi);
-			break;
-		case INBOUND_C1_TIMEOUT:
-			DPRINTK("INBOUND_C1_TIMEOUT message received");
-			break;
-		case BAD_SCSI_FRAME:
-			DPRINTK("BAD_SCSI_FRAME message received");
-			handle_Bad_SCSI_Frame_interrupt(fi);
-			break;
-		case INB_SCSI_STATUS_COMPLETION:
-			DPRINTK("INB_SCSI_STATUS_COMPL message received");
-			handle_Inbound_SCSI_Status_interrupt(fi);
-			break;
-		case INBOUND_SCSI_COMMAND:
-			DPRINTK("INBOUND_SCSI_COMMAND message received");
-			handle_Inbound_SCSI_Command_interrupt(fi);
-			break;
-		case INBOUND_SCSI_DATA_COMPLETION:
-			DPRINTK("INBOUND_SCSI_DATA message received");
-			/* Only for targets */
-			break;
-		default:		
-			T_MSG("DEFAULT message received, type = %x", imq_int_type);
-			return;
-	}
-	reset_latch(fi);
-}
-
-static void handle_OCI_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-u_long transaction_id = 0;
-unsigned short status, seq_count, transmitted_ox_id;
-struct Scsi_Host *host = fi->host;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
-Scsi_Cmnd *Cmnd;
-u_int tag;
-
-	ENTER("handle_OCI_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	transaction_id = ntohl(*(ptr_imq_entry + 1));
-	status = ntohl(*(ptr_imq_entry + 2)) >> 16;
-	seq_count = ntohl(*(ptr_imq_entry + 3));
-	DPRINTK("transaction_id= %x", (u_int)transaction_id);
-	tag = transaction_id & 0xFFFF0000;
-	transmitted_ox_id = transaction_id;
-
-	/* The INT could be either due to TIME_OUT | BAD_ALPA. 
-	 * But we check only for TimeOuts. Bad AL_PA will 
-	 * caught by FM_interrupt handler. 
-	 */
-
-	if ((status == OCM_TIMEOUT_OR_BAD_ALPA) && (!fi->g.port_discovery) && (!fi->g.perform_adisc)){
-		DPRINTK("Frame TimeOut on OX_ID = %x", (u_int)transaction_id);
-
-		/* Is it a SCSI frame that is timing out ? Not a very good check... 
-		 */
-		if ((transmitted_ox_id <= MAX_SCSI_OXID) && ((tag == FC_SCSI_BAD_TARGET) || (tag < 0x00FF0000))) {
-			/* If it is a Bad AL_PA, we report it as BAD_TARGET.
-			 * Else, we allow the command to time-out. A Link
-			 * re-initialization could be taking place.
-			 */
-			if (tag == FC_SCSI_BAD_TARGET) {
-				Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID];
-				hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL;
-				if (Cmnd != NULL) {
-					Cmnd->result = DID_BAD_TARGET << 16;
-					(*Cmnd->scsi_done) (Cmnd);
-				}
-				else
-					T_MSG("NULL Command out of handler!");
-			} /* if Bad Target */
-			else {
-			u_char missing_target = tag >> 16;
-			struct fc_node_info *q = fi->node_info_list;
-				/* A Node that we thought was logged in has gone
-				 * away. We are the optimistic kind and we keep
-				 * hoping that our dear little Target will come back
-				 * to us. For now we log him out.
-				 */
-				DPRINTK2("Missing Target = %d", missing_target);
-				while (q != NULL) {
-					if (q->target_id == missing_target) {
-						T_MSG("Target %d Logged out", q->target_id);
-						q->login = LOGIN_ATTEMPTED;
-						if (fi->num_nodes > 0)
-							fi->num_nodes--;
-						tx_logi(fi, ELS_PLOGI, q->d_id);
-						break;
-					}
-					else
-						q = q->next;
-				}
-			}
-		} /* End of SCSI frame timing out. */
-		else {
-			if (seq_count > 1) {
-				/* An IP frame was transmitted to a Bad AL_PA. Free up
-			 	 * the skb used.
-			 	 */
-				dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
-				netif_wake_queue(fi->dev);
-			}
-		} /* End of IP frame timing out. */
-	} /* End of frame timing out. */
-	else {
-		/* Frame was transmitted successfully. Check if it was an ELS
-		 * frame or an IP frame or a Bad_Target_Notification frame (in
-		 * case of a ptp_link). Ugly!
-		 */
-		if ((status == 0) && (seq_count == 0)) {
-		u_int tag = transaction_id & 0xFFFF0000;
-		/* Continue with port discovery after an ELS is successfully 
-		 * transmitted. (status == 0). 
-		 */
-			DPRINTK("tag = %x", tag);
-			switch(tag) {
-				case ELS_FLOGI:
-					/* Letz use the Name Server instead */
-					fi->g.explore_fabric = TRUE;
-					fi->g.port_discovery = FALSE;
-					fi->g.alpa_list_index = MAX_NODES;
-					add_to_ox_id_list(fi, transaction_id, tag);
-					break;
-				case ELS_PLOGI:
-					if (fi->g.fabric_present && (fi->g.name_server == FALSE))
-						add_to_ox_id_list(fi,transaction_id,ELS_NS_PLOGI);
-					else
-						add_to_ox_id_list(fi, transaction_id, tag);
-					break;
-				case FC_SCSI_BAD_TARGET:
-					Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID];
-					hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL;
-					if (Cmnd != NULL) {
-						Cmnd->result = DID_BAD_TARGET << 16;
-						(*Cmnd->scsi_done) (Cmnd);
-					}
-					else
-						T_MSG("NULL Command out of handler!");
-					break;
-				default:
-					add_to_ox_id_list(fi, transaction_id, tag);
-			}
-		
-			if (fi->g.alpa_list_index >= MAX_NODES) {
-				if (fi->g.port_discovery == TRUE) {
-					fi->g.port_discovery = FALSE;
-					add_display_cache_timer(fi);
-				}
-				fi->g.alpa_list_index = MAX_NODES;
-			}
-			if (fi->g.port_discovery == TRUE) 
-				local_port_discovery(fi);
-		}
-		else {
-			/* An IP frame has been successfully transmitted.
-			 * Free the skb that was used for this IP frame.
-			 */
-			if ((status == 0) && (seq_count > 1)) {
-				dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
-				netif_wake_queue(fi->dev);
-			}
-		}
-	}
-	LEAVE("handle_OCI_interrupt");
-}
-
-/* Right now we discard OOO frames */
-static void handle_OOO_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-int queue_indx, offset, payload_size;
-int no_of_buffers = 1; /* header is in a separate buffer */
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN;
-	/* Calculate total number of buffers */
-	no_of_buffers += payload_size / MFS_BUFFER_SIZE;
-	if (payload_size % MFS_BUFFER_SIZE)
-		no_of_buffers++;
-
-	/* provide Tachyon will another set of buffers */
-	fi->g.mfs_buffer_count += no_of_buffers;
-	if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
-	int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
-		fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
-		update_MFSBQ_indx(fi, count);
-	}
-}
-
-static void handle_MFS_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry, *buff_addr;
-u_int type_of_frame, s_id;
-int queue_indx, offset, payload_size, starting_indx, starting_offset;
-u_short received_ox_id;
-int no_of_buffers = 1; /* header is in a separate buffer */
-struct sk_buff *skb;
-int wrap_around = FALSE, no_of_wrap_buffs = NO_OF_ENTRIES - 1;
-	ENTER("handle_MFS_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	DPRINTK("queue_indx = %d, offset  = %d\n", queue_indx, offset);
-	payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN;
-	DPRINTK("payload_size = %d", payload_size);
-	/* Calculate total number of buffers */
-	no_of_buffers += payload_size / MFS_BUFFER_SIZE;
-	if (payload_size % MFS_BUFFER_SIZE)
-		no_of_buffers++;
-	DPRINTK("no_of_buffers = %d", no_of_buffers);
-
-	if ((no_of_buffers - 1) <= offset) {
-		starting_offset = offset - (no_of_buffers - 1);
-		starting_indx = queue_indx;
-	}
-	else {
-	int temp = no_of_buffers - (offset + 1);
-	int no_of_queues = temp / NO_OF_ENTRIES;
-		starting_offset = temp % NO_OF_ENTRIES;
-		if (starting_offset != 0) {
-			no_of_wrap_buffs = starting_offset - 1; //exclude header
-			starting_offset = NO_OF_ENTRIES - starting_offset;
-			no_of_queues++;
-		}
-		starting_indx = queue_indx - no_of_queues;
-		if (starting_indx < 0) {
-			no_of_wrap_buffs -= (starting_indx + 1) * NO_OF_ENTRIES; 
-			starting_indx = MFSBQ_LENGTH + starting_indx;
-			wrap_around = TRUE;
-		}
-	}
-	
-	DPRINTK("starting_indx = %d, starting offset = %d no_of_wrap_buffs = %d\n", starting_indx, starting_offset, no_of_wrap_buffs);
-	/* Get Tachyon Header from first buffer */
-	buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base + starting_indx*NO_OF_ENTRIES + starting_offset)));
-	
-
-	/* extract Type of Frame */
-	type_of_frame = (u_int)ntohl(*(buff_addr + 4)) & 0xFF000000;
-	s_id = (u_int)ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
-	buff_addr += MFS_BUFFER_SIZE/4;
-	DPRINTK("type_of_frame = %x, s_id = %x, ox_id = %x", type_of_frame, s_id, received_ox_id);
-
- 	switch(type_of_frame) {
-	  case TYPE_LLC_SNAP:
-		skb = dev_alloc_skb(payload_size);
-		if (skb == NULL) {
-			printk(KERN_NOTICE "%s: In handle_MFS_interrupt() Memory squeeze, dropping packet.\n", fi->name);
-			fi->fc_stats.rx_dropped++;
-			fi->g.mfs_buffer_count += no_of_buffers;
-			if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
-				int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
-				fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
-				update_MFSBQ_indx(fi, count);
-			}
-			return;
-		}
-		if (wrap_around) {
-		int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE;
-		int tail_size = payload_size - wrap_size;
-			DPRINTK("wrap_size = %d, tail_size = %d\n", wrap_size, tail_size);
-			if (no_of_wrap_buffs) 
-				memcpy(skb_put(skb, wrap_size), buff_addr, wrap_size);
-			buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base)));
-			memcpy(skb_put(skb, tail_size), buff_addr, tail_size);
-		}
-		else
-			memcpy(skb_put(skb, payload_size), buff_addr, payload_size);
-		rx_net_mfs_packet(fi, skb);
-	  	break;
-	default:
-		T_MSG("Unknown Frame Type received. Type = %x", type_of_frame);
-	}
-
-	/* provide Tachyon will another set of buffers */
-	fi->g.mfs_buffer_count += no_of_buffers;
-	if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
-	int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
-		fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
-		update_MFSBQ_indx(fi, count);
-	}
-	LEAVE("handle_MFS_interrupt");
-}
-
-static void handle_Unknown_Frame_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-int queue_indx, offset;
-	ENTER("handle_Unknown_Frame_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	/* We discard the "unknown" frame */
-	/* provide Tachyon will another set of buffers */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_Unknown_Frame_interrupt");
-}
-
-static void handle_Busied_Frame_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-int queue_indx, offset;
-	ENTER("handle_Busied_Frame_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	/* We discard the "busied" frame */
-	/* provide Tachyon will another set of buffers */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_Busied_Frame_interrupt");
-}
-
-static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry, *buff_addr, *tach_header, *ptr_edb;
-u_int s_id, rctl, frame_class, burst_len, transfered_len, len = 0;
-int queue_indx, offset, payload_size, i;
-u_short ox_id, rx_id, x_id, mtu = 512;
-u_char target_id = 0xFF;
-
-	ENTER("handle_Bad_SCSI_Frame_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	payload_size = ntohl(*(ptr_imq_entry + 2));
-
-	buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
-
-	rctl = ntohl(*(buff_addr + 2)) & 0xFF000000;
-	s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	ox_id = ntohl(*(buff_addr + 6)) >> 16;
-	rx_id = ntohl(*(buff_addr + 6));
-	x_id = ox_id & MAX_SCSI_XID;
-
-	/* Any frame that comes in with OX_ID that matches an OX_ID 
-	 * that has been allocated for SCSI, will be called a Bad
-	 * SCSI frame if the Exchange is not valid any more.
-	 *
-	 * We will also get a Bad SCSI frame interrupt if we receive
-	 * a XFER_RDY with offset != 0. Tachyon washes its hands off
-	 * this Exchange. We have to take care of ourselves. Grrr...
-	 */
-	if (rctl == DATA_DESCRIPTOR) {
-	struct fc_node_info *q = fi->node_info_list;
-		while (q != NULL) {
-			if (q->d_id == s_id) {
-				target_id = q->target_id;
-				mtu = q->mtu;
-				break;
-			}
-			else
-				q = q->next;
-		}
-		frame_class = target_id;
-		transfered_len = ntohl(*(buff_addr + 8));
-		burst_len = ntohl(*(buff_addr + 9));
-
-		build_ODB(fi, fi->g.seq_id, s_id, burst_len, 0, mtu, ox_id, rx_id, 0, 0, frame_class << 16);
-		/* Update the SEQ_ID and Relative Offset in the 
-		 * Tachyon Header Structure.
-		 */
-		tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5)));
-		*(tach_header + 5) = htonl(fi->g.seq_id << 24);
-		*(tach_header + 7) = htonl(transfered_len);
-		fi->g.odb.hdr_addr = *(fi->q.ptr_sest[x_id] + 5);
-
-		/* Invalidate the EDBs used 
-		 */
-		ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7)));
-
-		for (i = 0; i < EDB_LEN; i++)
-			if (fi->q.ptr_edb[i] == ptr_edb)
-				break;
-		ptr_edb--;	
-		
-		if (i < EDB_LEN) {
-		int j;
-			do {
-				ptr_edb += 2;
-				len += (htonl(*ptr_edb) & 0xFFFF);
-				j = i;
-				fi->q.free_edb_list[i++] = EDB_FREE;
-				if (i == EDB_LEN) {
-					i = 0;
-					ptr_edb = fi->q.ptr_edb_base - 1;
-				}
-			} while (len < transfered_len);
-			if (len > transfered_len) {
-				ptr_edb--;
-				fi->q.free_edb_list[j] = EDB_BUSY;
-			}
-			else
-				ptr_edb++;
-		}
-		else {
-			T_MSG("EDB not found while freeing");
-			if (offset == (NO_OF_ENTRIES - 1))
-				update_SFSBQ_indx(fi);
-			return;
-		}
-
-		/* Update the EDB pointer in the ODB.
-		 */
-		fi->g.odb.edb_addr = htonl(virt_to_bus(ptr_edb));
-		memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB));
-		/* Update the EDB pointer in the SEST entry. We might need
-		 * this if get another XFER_RDY for the same Exchange.
-		 */
-		*(fi->q.ptr_sest[x_id] + 7) = htonl(virt_to_bus(ptr_edb));
-
-		update_OCQ_indx(fi);
-		if (fi->g.seq_id == MAX_SEQ_ID)
-			fi->g.seq_id = 0;
-		else
-			fi->g.seq_id++;
-	}
-	else 
-	/* Could be a BA_ACC or a BA_RJT.
-	 */
-	if (rctl == RCTL_BASIC_ACC) {
-	u_int bls_type = remove_from_ox_id_list(fi, ox_id);
-		DPRINTK1("BA_ACC received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type);
-		if (bls_type == RCTL_BASIC_ABTS) {
-		u_int STE_bit;
-			/* Invalidate resources for that Exchange.
-			 */
-			STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-			if (STE_bit & SEST_V) {
-				*(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
-				invalidate_SEST_entry(fi, ox_id);
-			}
-		}
-	}
-	else
-	if (rctl == RCTL_BASIC_RJT) {
-	u_int bls_type = remove_from_ox_id_list(fi, ox_id);
-		DPRINTK1("BA_RJT received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type);
-		if (bls_type == RCTL_BASIC_ABTS) {
-		u_int STE_bit;
-			/* Invalidate resources for that Exchange.
-			 */
-			STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-			if (STE_bit & SEST_V) {
-				*(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
-				invalidate_SEST_entry(fi, ox_id);
-			}
-		}
-	}
-	else
-		DPRINTK1("Frame with R_CTL = %x received from S_ID 0x%x with OX_ID %x", rctl, s_id, ox_id);
-
-	/* Else, discard the "Bad" SCSI frame.
-	 */
-
-	/* provide Tachyon will another set of buffers 
-	 */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_Bad_SCSI_Frame_interrupt");
-}
-
-static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi)
-{
-struct Scsi_Host *host = fi->host;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
-u_int *ptr_imq_entry, *buff_addr, *ptr_rsp_info, *ptr_sense_info = NULL;
-int queue_indx, offset, payload_size;
-u_short received_ox_id, x_id;
-Scsi_Cmnd *Cmnd;
-u_int fcp_status, fcp_rsp_info_len = 0, fcp_sense_info_len = 0, s_id;
-	ENTER("handle_SCSI_status_interrupt");
-
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
-	payload_size = ntohl(*(ptr_imq_entry + 2));
-	received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
-
-	buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
-
-	fcp_status = ntohl(*(buff_addr + 10));
-	ptr_rsp_info = buff_addr + 14;
-	if (fcp_status & FCP_STATUS_RSP_LEN)
-		fcp_rsp_info_len = ntohl(*(buff_addr + 13));
-		
-	if (fcp_status & FCP_STATUS_SENSE_LEN) {
-		ptr_sense_info = ptr_rsp_info + fcp_rsp_info_len / 4;
-		fcp_sense_info_len = ntohl(*(buff_addr + 12));
-		DPRINTK("sense_info = %x", (u_int)ntohl(*ptr_sense_info));
-	}
-	DPRINTK("fcp_status = %x, fcp_rsp_len = %x", fcp_status, fcp_rsp_info_len);
-	x_id = received_ox_id & MAX_SCSI_XID;
-	Cmnd = hostdata->cmnd_handler[x_id];
-	hostdata->cmnd_handler[x_id] = NULL;
-	if (Cmnd != NULL) {
-		memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer));
-		/* Check if there is a Sense field */
-		if (fcp_status & FCP_STATUS_SENSE_LEN) {
-		int size = sizeof(Cmnd->sense_buffer);
-			if (fcp_sense_info_len < size)
-				size = fcp_sense_info_len;
-			memcpy(Cmnd->sense_buffer, (char *)ptr_sense_info, size);
-		}
-		Cmnd->result = fcp_status & FCP_STATUS_MASK;
-		(*Cmnd->scsi_done) (Cmnd);
-	}
-	else
-		T_MSG("NULL Command out of handler!");
-
-	invalidate_SEST_entry(fi, received_ox_id);
-	s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	fi->q.free_scsi_oxid[x_id] = OXID_AVAILABLE;
-
-	/* provide Tachyon will another set of buffers */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_SCSI_status_interrupt");
-}
-
-static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id)
-{
-u_short x_id = received_ox_id & MAX_SCSI_XID;
-	/* Invalidate SEST entry if it is an OutBound SEST Entry 
-	 */
-	if (!(received_ox_id & SCSI_READ_BIT)) {
-	u_int *ptr_tach_header, *ptr_edb;
-	u_short temp_ox_id = NOT_SCSI_XID;
-	int i;
-		*(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
-
-		/* Invalidate the Tachyon Header structure 
-		 */
-		ptr_tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5)));
-		for (i = 0; i < NO_OF_TACH_HEADERS; i++) 
-			if(fi->q.ptr_tachyon_header[i] == ptr_tach_header)
-				break;
-		if (i < NO_OF_TACH_HEADERS) 
-			memset(ptr_tach_header, 0xFF, 32);
-		else
-			T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()");
-
-		/* Invalidate the EDB used 
-		 */
-		ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7)));
-		for (i = 0; i < EDB_LEN; i++)
-			if (fi->q.ptr_edb[i] == ptr_edb)
-				break;
-		ptr_edb--;	
-		if (i < EDB_LEN) {
-			do {
-				ptr_edb += 2;
-				fi->q.free_edb_list[i++] = EDB_FREE;
-				if (i == EDB_LEN) {
-					i = 0;
-					ptr_edb = fi->q.ptr_edb_base - 1;
-				}
-			} while ((htonl(*ptr_edb) & 0x80000000) != 0x80000000);
-		}
-		else
-			T_MSG("EDB not found while freeing in invalidate_SEST_entry()");
-		
-		/* Search for its other header structure and destroy it! 
-		 */
-		if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4)))
-			ptr_tach_header += 16;
-		else
-			ptr_tach_header = fi->q.ptr_tachyon_header_base;
-		while (temp_ox_id != x_id) {
-			temp_ox_id = ntohl(*(ptr_tach_header + 6)) >> 16;
-			if (temp_ox_id == x_id) {
-				/* Paranoid checking...
-				 */
-				for (i = 0; i < NO_OF_TACH_HEADERS; i++) 
-					if(fi->q.ptr_tachyon_header[i] == ptr_tach_header)
-						break;
-				if (i < NO_OF_TACH_HEADERS)
-					memset(ptr_tach_header, 0xFF, 32);
-				else
-					T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()");
-				break;
-			}
-			else {
-				if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4)))
-					ptr_tach_header += 16;
-				else
-					ptr_tach_header = fi->q.ptr_tachyon_header_base;
-			}
-		}
-	}
-	else {
-	u_short sdb_table_indx;
-		/* An Inbound Command has completed or needs to be Aborted. 
-	 	 * Clear up the SDB buffers.
-		 */
-		sdb_table_indx = *(fi->q.ptr_sest[x_id] + 5);
-		fi->q.sdb_slot_status[sdb_table_indx] = SDB_FREE;
-	}
-}
-
-static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry;
-int queue_indx, offset;
-	ENTER("handle_Inbound_SCSI_Command_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	/* We discard the SCSI frame as we shouldn't be receiving
-	 * a SCSI Command in the first place 
-	 */
-	/* provide Tachyon will another set of buffers */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_Inbound_SCSI_Command_interrupt");
-}
-
-static void handle_SFS_interrupt(struct fc_info *fi)
-{
-u_int *ptr_imq_entry, *buff_addr;
-u_int class_of_frame, type_of_frame, s_id, els_type = 0, rctl;
-int queue_indx, offset, payload_size, login_state;
-u_short received_ox_id, fs_cmnd_code;
-	ENTER("handle_SFS_interrupt");
-	ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
-	offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
-	queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
-	queue_indx = queue_indx >> 16;
-	DPRINTK("queue_indx = %d, offset  = %d\n", queue_indx, offset);
-	payload_size = ntohl(*(ptr_imq_entry + 2));
-	DPRINTK("payload_size = %d", payload_size);
-
-	buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
-
-	/* extract Type of Frame */
-	type_of_frame = ntohl(*(buff_addr + 4)) & 0xFF000000;
-	s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
-	switch(type_of_frame) {
-		case TYPE_BLS:
-			rctl = ntohl(*(buff_addr + 2)) & 0xFF000000;
-			switch(rctl) {
-				case RCTL_BASIC_ABTS:
-					/* As an Initiator, we should never be receiving 
-					 * this.
-		 			 */
-					DPRINTK1("ABTS received from S_ID 0x%x with OX_ID = %x", s_id, received_ox_id);
-					break;
-			}
-			break;
-		case TYPE_ELS:
-			class_of_frame = ntohl(*(buff_addr + 8));
-			login_state = sid_logged_in(fi, s_id);
-			switch(class_of_frame & 0xFF000000) {
-				case ELS_PLOGI:
-					if (s_id != fi->g.my_id) {
-						u_int ret_code;
-						DPRINTK1("PLOGI received from D_ID 0x%x with 0X_ID = %x", s_id, received_ox_id);
-						if ((ret_code = plogi_ok(fi, buff_addr, payload_size)) == 0){
-							tx_logi_acc(fi, ELS_ACC, s_id, received_ox_id);
-							add_to_address_cache(fi, buff_addr);
-						}
-						else {
-							u_short cmnd_code = ret_code >> 16;
-							u_short expln_code =  ret_code;
-							tx_ls_rjt(fi, s_id, received_ox_id, cmnd_code, expln_code);
-						}
-					}
-					break;
-				case ELS_ACC:
-					els_type = remove_from_ox_id_list(fi, received_ox_id);
-					DPRINTK1("ELS_ACC received from D_ID 0x%x in response to ELS %x", s_id, els_type);
-					switch(els_type) {
-						case ELS_PLOGI:
-							add_to_address_cache(fi, buff_addr);
-							tx_prli(fi, ELS_PRLI, s_id, OX_ID_FIRST_SEQUENCE);
-							break;
-						case ELS_FLOGI:
-							add_to_address_cache(fi, buff_addr);
-							fi->g.my_id = ntohl(*(buff_addr + 2)) & 0x00FFFFFF;
-							fi->g.fabric_present = TRUE;
-							fi->g.my_ddaa = fi->g.my_id & 0xFFFF00;
-							/* Login to the Name Server 
-							 */
-							tx_logi(fi, ELS_PLOGI, DIRECTORY_SERVER); 
-							break;
-						case ELS_NS_PLOGI:
-							fi->g.name_server = TRUE;
-							add_to_address_cache(fi, buff_addr);
-							tx_name_server_req(fi, FCS_RFC_4);
-							tx_scr(fi);
-							/* Some devices have a delay before 
-							 * registering with the Name Server 
-							 */
-							udelay(500); 
-							tx_name_server_req(fi, FCS_GP_ID4);
-							break;
-						case ELS_PRLI:
-							mark_scsi_sid(fi, buff_addr, ADD_ENTRY);
-							break;
-						case ELS_ADISC:
-							if (!(validate_login(fi, buff_addr)))
-								tx_logo(fi, s_id, OX_ID_FIRST_SEQUENCE);
-							break;
-					}
-					break;
-				case ELS_PDISC:
-					DPRINTK1("ELS_PDISC received from D_ID 0x%x", s_id);
-					tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_ADISC:
-					DPRINTK1("ELS_ADISC received from D_ID 0x%x", s_id);
-					if (node_logged_in_prev(fi, buff_addr))
-						tx_adisc(fi, ELS_ACC, s_id, received_ox_id);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_PRLI:
-					DPRINTK1("ELS_PRLI received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) {
-						tx_prli(fi, ELS_ACC, s_id, received_ox_id);
-						mark_scsi_sid(fi, buff_addr, ADD_ENTRY);
-					}
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_PRLO:
-					DPRINTK1("ELS_PRLO received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_OUT) || (login_state == NODE_NOT_PRESENT))
-						tx_logo(fi, s_id, received_ox_id);
-					else
-					if (login_state == NODE_LOGGED_IN)
-
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-					if (login_state == NODE_PROCESS_LOGGED_IN) {
-						tx_prli(fi, ELS_ACC, s_id, received_ox_id);
-						mark_scsi_sid(fi, buff_addr, DELETE_ENTRY);
-					}
-					break;
-				case ELS_LS_RJT:
-					els_type = remove_from_ox_id_list(fi, received_ox_id);
-					DPRINTK1("ELS_LS_RJT received from D_ID 0x%x in response to %x", s_id, els_type);
-					/* We should be chking the reason code.
-					 */
-					switch (els_type) {
-						case ELS_ADISC:
-							tx_logi(fi, ELS_PLOGI, s_id);
-							break;
-					}		
-					break;
-				case ELS_LOGO:
-					els_type = remove_from_ox_id_list(fi, received_ox_id);
-					DPRINTK1("ELS_LOGO received from D_ID 0x%x in response to %x", s_id, els_type);
-					remove_from_address_cache(fi, buff_addr, ELS_LOGO);
-					tx_acc(fi, s_id, received_ox_id);
-					if (els_type == ELS_ADISC)
-						tx_logi(fi, ELS_PLOGI, s_id);
-					break;
-				case ELS_RSCN:
-					DPRINTK1("ELS_RSCN received from D_ID 0x%x", s_id);
-					tx_acc(fi, s_id, received_ox_id);
-					remove_from_address_cache(fi, buff_addr, ELS_RSCN);
-					break;
-				case ELS_FARP_REQ:
-					/* We do not support FARP.
-					   So, silently discard it */
-					DPRINTK1("ELS_FARP_REQ received from D_ID 0x%x", s_id);
-					break;
-				case ELS_ABTX:
-					DPRINTK1("ELS_ABTX received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_FLOGI:
-					DPRINTK1("ELS_FLOGI received from D_ID 0x%x", s_id);
-					if (fi->g.ptp_up == TRUE) {
-						/* The node could have come up as an N_Port
-						 * in a Loop! So,try initializing as an NL_port
-						 */
-						take_tachyon_offline(fi);
-						/* write AL_TIME & E_D_TOV into the registers */
-						writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-						writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
-						DPRINTK1("FLOGI received, TACHYON initializing as L_Port...\n");
-						writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-					}
-					else {
-						if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-							tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-						else
-							tx_logo(fi, s_id, received_ox_id);
-					}
-					break;
-				case ELS_ADVC:
-					DPRINTK1("ELS_ADVC received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_ECHO:
-					DPRINTK1("ELS_ECHO received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_ESTC:
-					DPRINTK1("ELS_ESTC received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_ESTS:
-					DPRINTK1("ELS_ESTS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RCS:
-					DPRINTK1("ELS_RCS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RES:
-					DPRINTK1("ELS_RES received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RLS:
-					DPRINTK1("ELS_RLS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RRQ:
-					DPRINTK1("ELS_RRQ received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RSS:
-					DPRINTK1("ELS_RSS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RTV:
-					DPRINTK1("ELS_RTV received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RSI:
-					DPRINTK1("ELS_RSI received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_TEST:
-					/* No reply sequence */
-					DPRINTK1("ELS_TEST received from D_ID 0x%x", s_id);
-					break;
-				case ELS_RNC:
-					DPRINTK1("ELS_RNC received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_RVCS:
-					DPRINTK1("ELS_RVCS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_TPLS:
-					DPRINTK1("ELS_TPLS received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_GAID:
-					DPRINTK1("ELS_GAID received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_FACT:
-					DPRINTK1("ELS_FACT received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_FAN:
-					/* Hmmm... You don't support FAN ??? */
-					DPRINTK1("ELS_FAN received from D_ID 0x%x", s_id);
-					tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					break;
-				case ELS_FDACT:
-					DPRINTK1("ELS_FDACT received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_NACT:
-					DPRINTK1("ELS_NACT received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_NDACT:
-					DPRINTK1("ELS_NDACT received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_QoSR:
-					DPRINTK1("ELS_QoSR received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				case ELS_FDISC:
-					DPRINTK1("ELS_FDISC received from D_ID 0x%x", s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-				default:
-					DPRINTK1("ELS Frame %x received from D_ID 0x%x", class_of_frame, s_id);
-					if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
-						tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
-					else
-						tx_logo(fi, s_id, received_ox_id);
-					break;
-			}
-			break;
-		case TYPE_FC_SERVICES:
-			fs_cmnd_code = (ntohl(*(buff_addr + 10)) & 0xFFFF0000) >>16;
-			switch(fs_cmnd_code) {
-				case FCS_ACC:
-					els_type = remove_from_ox_id_list(fi, received_ox_id);
-					DPRINTK1("FCS_ACC received from D_ID 0x%x in response to %x", s_id, els_type);
-					if (els_type == FCS_GP_ID4) 
-						explore_fabric(fi, buff_addr);
-					break;
-				case FCS_REJECT:
-					DPRINTK1("FCS_REJECT received from D_ID 0x%x in response to %x", s_id, els_type);
-					break;
-			}
-			break;
-		case TYPE_LLC_SNAP:
-			rx_net_packet(fi, (u_char *)buff_addr, payload_size);
-			break;
-		default:
-			T_MSG("Frame Type %x received from %x", type_of_frame, s_id);
-	}
-
-	/* provide Tachyon will another set of buffers */
-	if (offset == (NO_OF_ENTRIES - 1))
-		update_SFSBQ_indx(fi);
-	LEAVE("handle_SFS_interrupt");
-}
-
-static void handle_FM_interrupt(struct fc_info *fi)
-{
-u_int fm_status;
-u_int tachyon_status;
-
-	ENTER("handle_FM_interrupt");
-	fm_status = readl(fi->t_r.ptr_fm_status_reg);
-	tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-	DPRINTK("FM_status = %x, Tachyon_status = %x", fm_status, tachyon_status);
-	if (fm_status & LINK_DOWN) {
-		T_MSG("Fibre Channel Link DOWN");
-		fm_status = readl(fi->t_r.ptr_fm_status_reg);
-		
-		del_timer(&fi->explore_timer);
-		del_timer(&fi->nport_timer);
-		del_timer(&fi->lport_timer);
-		del_timer(&fi->display_cache_timer);
-		fi->g.link_up = FALSE;
-		if (fi->g.ptp_up == TRUE)
-			fi->g.n_port_try = FALSE;
-		fi->g.ptp_up = FALSE;
-		fi->g.port_discovery = FALSE;
-		fi->g.explore_fabric = FALSE;
-		fi->g.perform_adisc = FALSE;
-
-		/* Logout will all nodes */
-		if (fi->node_info_list) {
-			struct fc_node_info *temp_list = fi->node_info_list;
-				while(temp_list) {
-					temp_list->login = LOGIN_ATTEMPTED;
-					temp_list = temp_list->next;
-				}
-				fi->num_nodes = 0;
-		}
-
-		if ((fi->g.n_port_try == FALSE) && (fi->g.dont_init == FALSE)){
-			take_tachyon_offline(fi);
-			/* write AL_TIME & E_D_TOV into the registers */
-			writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-			
-			if ((fi->g.fabric_present == TRUE) && (fi->g.loop_up == TRUE)) {
-			u_int al_pa = fi->g.my_id & 0xFF;
-				writel((al_pa << 24) | LOOP_INIT_FABRIC_ADDRESS | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg);
-			}
-			else 
-			if (fi->g.loop_up == TRUE) {
-			u_int al_pa = fi->g.my_id & 0xFF;
-				writel((al_pa << 24) | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg);
-			}
-			else 
-				writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
-			fi->g.loop_up = FALSE;
-			DPRINTK1("In LDWN TACHYON initializing as L_Port...\n");
-			writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-		}
-	}
-
-    if (fm_status & NON_PARTICIPATING) {
-	  	T_MSG("Did not acquire an AL_PA. I am not participating");
-    }
-	else
-	if ((fm_status & LINK_UP) && ((fm_status & LINK_DOWN) == 0)) {
-	  T_MSG("Fibre Channel Link UP");
-	  if ((fm_status & NON_PARTICIPATING) != TRUE) {
-		fi->g.link_up = TRUE;
-		if (tachyon_status & OSM_FROZEN) {
-			reset_tachyon(fi, ERROR_RELEASE);
-			reset_tachyon(fi, OCQ_RESET);
-		}
-		init_timer(&fi->explore_timer);
-		init_timer(&fi->nport_timer);
-		init_timer(&fi->lport_timer);
-		init_timer(&fi->display_cache_timer);
-		if ((fm_status & OLD_PORT) == 0) {
-			fi->g.loop_up = TRUE;
-			fi->g.ptp_up = FALSE;
-			fi->g.my_id = readl(fi->t_r.ptr_fm_config_reg) >> 24;
-			DPRINTK1("My AL_PA = %x", fi->g.my_id);
-			fi->g.port_discovery = TRUE;
-			fi->g.explore_fabric = FALSE;
-		}
-		else
-		if (((fm_status & 0xF0) == OLD_PORT) && ((fm_status & 0x0F) == PORT_STATE_ACTIVE)) {
-			fi->g.loop_up = FALSE;
-			fi->g.my_id = 0x0;
-			/* In a point-to-point configuration, we expect to be
-			 * connected to an F_Port. This driver does not yet support
-			 * a configuration where it is connected to another N_Port
-			 * directly.
-			 */
-			fi->g.explore_fabric = TRUE;
-			fi->g.port_discovery = FALSE;
-			if (fi->g.n_port_try == FALSE) {
-				take_tachyon_offline(fi);
-				/* write R_T_TOV & E_D_TOV into the registers */
-				writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-				writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg);
-				fi->g.n_port_try = TRUE;
-				DPRINTK1("In LUP TACHYON initializing as N_Port...\n");
-				writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-			}
-			else {
-				fi->g.ptp_up = TRUE;
-				tx_logi(fi, ELS_FLOGI, F_PORT); 
-			}
-		}
-		fi->g.my_ddaa = 0x0;
-		fi->g.fabric_present = FALSE; 
-		/* We havn't sent out any Name Server Reqs */
-		fi->g.name_server = FALSE;
-		fi->g.alpa_list_index = 0;
-		fi->g.ox_id = NOT_SCSI_XID;
-		fi->g.my_mtu = TACH_FRAME_SIZE;
-		
-		/* Implicitly LOGO with all logged-in nodes. 
-		 */
-		if (fi->node_info_list) {
-		struct fc_node_info *temp_list = fi->node_info_list;
-			while(temp_list) {
-				temp_list->login = LOGIN_ATTEMPTED;
-				temp_list = temp_list->next;
-			}
-			fi->num_nodes = 0;
-			fi->g.perform_adisc = TRUE;
-			//fi->g.perform_adisc = FALSE;
-			fi->g.port_discovery = FALSE;
-			tx_logi(fi, ELS_FLOGI, F_PORT); 
-		}
-		else { 
-			/* If Link coming up for the _first_ time or no nodes
-			 * were logged in before...
-			 */
-			fi->g.scsi_oxid = 0;
-			fi->g.seq_id = 0x00;
-			fi->g.perform_adisc = FALSE;
-		}
-
-		/* reset OX_ID table */
-		while (fi->ox_id_list) {
-		struct ox_id_els_map *temp = fi->ox_id_list;
-			fi->ox_id_list = fi->ox_id_list->next;
-			kfree(temp);
-		}
-		fi->ox_id_list = NULL;
-	  } /* End of if partipating */
-	}
-
-	if (fm_status & ELASTIC_STORE_ERROR) {
-		/* Too much junk on the Link 
-		 */
-		/* Trying to clear it up by Txing PLOGI to urself */
-		if (fi->g.link_up == TRUE)
-			tx_logi(fi, ELS_PLOGI, fi->g.my_id); 
-	}
-
-	if (fm_status & LOOP_UP) {
-		if (tachyon_status & OSM_FROZEN) {
-			reset_tachyon(fi, ERROR_RELEASE);
-			reset_tachyon(fi, OCQ_RESET);
-		}
-	}
-	
-	if (fm_status & NOS_OLS_RECEIVED){
-		if (fi->g.nport_timer_set == FALSE) {
-			DPRINTK("NOS/OLS Received");
-			DPRINTK("FM_status = %x", fm_status);
-			fi->nport_timer.function = nos_ols_timer;
-			fi->nport_timer.data = (unsigned long)fi;
-			fi->nport_timer.expires = RUN_AT((3*HZ)/100); /* 30 msec */
-			init_timer(&fi->nport_timer);
-			add_timer(&fi->nport_timer);
-			fi->g.nport_timer_set = TRUE;
-		}
-	}
-
-	if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) {
-		DPRINTK1("Link Fail-I in OLD-PORT.");
-		take_tachyon_offline(fi);
-		reset_tachyon(fi, SOFTWARE_RESET);
-	}
-
-	if (fm_status & LOOP_STATE_TIMEOUT){
-		if ((fm_status & 0xF0) == ARBITRATING) 
-			DPRINTK1("ED_TOV timesout.In ARBITRATING state...");
-		if ((fm_status & 0xF0) == ARB_WON)
-			DPRINTK1("ED_TOV timesout.In ARBITRATION WON state...");
-		if ((fm_status & 0xF0) == OPEN)
-			DPRINTK1("ED_TOV timesout.In OPEN state...");
-		if ((fm_status & 0xF0) == OPENED)
-			DPRINTK1("ED_TOV timesout.In OPENED state...");
-		if ((fm_status & 0xF0) == TX_CLS)
-			DPRINTK1("ED_TOV timesout.In XMITTED CLOSE state...");
-		if ((fm_status & 0xF0) == RX_CLS)
-			DPRINTK1("ED_TOV timesout.In RECEIVED CLOSE state...");
-		if ((fm_status & 0xF0) == INITIALIZING)
-			DPRINTK1("ED_TOV timesout.In INITIALIZING state...");
-		DPRINTK1("Initializing Loop...");
-		writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-	}
-	
-	if ((fm_status & BAD_ALPA) && (fi->g.loop_up == TRUE)) {
-	u_char bad_alpa = (readl(fi->t_r.ptr_fm_rx_al_pa_reg) & 0xFF00) >> 8;
-		if (tachyon_status & OSM_FROZEN) {
-			reset_tachyon(fi, ERROR_RELEASE);
-			reset_tachyon(fi, OCQ_RESET);
-		}
-		/* Fix for B34 */
-		tx_logi(fi, ELS_PLOGI, fi->g.my_id); 
-
-		if (!fi->g.port_discovery && !fi->g.perform_adisc) {
-			if (bad_alpa != 0xFE)
-				DPRINTK("Bad AL_PA = %x", bad_alpa);
-		}
-		else {
-			if ((fi->g.perform_adisc == TRUE) && (bad_alpa == 0x00)) {
-				DPRINTK1("Performing ADISC...");
-				fi->g.fabric_present = FALSE;
-				perform_adisc(fi);
-			}
-		}
-	}
-	
-	if (fm_status & LIPF_RECEIVED){
-		DPRINTK("LIP(F8) Received");
-	}
-
-	if (fm_status & LINK_FAILURE) {
-		if (fm_status & LOSS_OF_SIGNAL)
-			DPRINTK1("Detected Loss of Signal.");
-		if (fm_status & OUT_OF_SYNC)
-			DPRINTK1("Detected Loss of Synchronization.");
-	}
-
-	if (fm_status & TRANSMIT_PARITY_ERROR) {
-		/* Bad! Should not happen. Solution-> Hard Reset.
-		 */
-		T_MSG("Parity Error. Perform Hard Reset!");
-	}
-
-	if (fi->g.alpa_list_index >= MAX_NODES){
-		if (fi->g.port_discovery == TRUE) {
-			fi->g.port_discovery = FALSE;
-			add_display_cache_timer(fi);
-		}
-		fi->g.alpa_list_index = MAX_NODES;
-	}
-
-	if (fi->g.port_discovery == TRUE) 
-		local_port_discovery(fi);
-
-	LEAVE("handle_FM_interrupt");
-	return;
-}
-
-static void local_port_discovery(struct fc_info *fi)
-{
-	if (fi->g.loop_up == TRUE) {
-		/* If this is not here, some of the Bad AL_PAs are missed. 
-		 */
-		udelay(20); 
-		if ((fi->g.alpa_list_index == 0) && (fi->g.fabric_present == FALSE)){
-			tx_logi(fi, ELS_FLOGI, F_PORT); 
-		}
-		else {
-		int login_state = sid_logged_in(fi, fi->g.my_ddaa | alpa_list[fi->g.alpa_list_index]);
-			while ((fi->g.alpa_list_index == 0) || ((fi->g.alpa_list_index < MAX_NODES) && ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN) || (alpa_list[fi->g.alpa_list_index] == (fi->g.my_id & 0xFF)))))
-				fi->g.alpa_list_index++;
-			if (fi->g.alpa_list_index < MAX_NODES)
-				tx_logi(fi, ELS_PLOGI, alpa_list[fi->g.alpa_list_index]); 
-		}
-		fi->g.alpa_list_index++;
-		if (fi->g.alpa_list_index >= MAX_NODES){
-			if (fi->g.port_discovery == TRUE) {
-				fi->g.port_discovery = FALSE;
-				add_display_cache_timer(fi);
-			}
-			fi->g.alpa_list_index = MAX_NODES;
-		}
-	}
-}
-
-static void nos_ols_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info*)data;
-u_int fm_status;
-	fm_status = readl(fi->t_r.ptr_fm_status_reg);
-	DPRINTK1("FM_status in timer= %x", fm_status);
-	fi->g.nport_timer_set = FALSE;
-	del_timer(&fi->nport_timer);
-	if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE))
-		return;
-	if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_ACTIVE) || ((fm_status & 0x0F) == PORT_STATE_OFFLINE))) {
-		DPRINTK1("In OLD-PORT after E_D_TOV.");
-		take_tachyon_offline(fi);
-		/* write R_T_TOV & E_D_TOV into the registers */
-		writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-		writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg);
-		fi->g.n_port_try = TRUE;
-		DPRINTK1("In timer, TACHYON initializing as N_Port...\n");
-		writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-	}
-	else
-	if ((fi->g.lport_timer_set == FALSE) && ((fm_status & 0xF0) == LOOP_FAIL)) {
-		DPRINTK1("Loop Fail after E_D_TOV.");
-		fi->lport_timer.function = loop_timer;
-		fi->lport_timer.data = (unsigned long)fi;
-		fi->lport_timer.expires = RUN_AT((8*HZ)/100); 
-		init_timer(&fi->lport_timer);
-		add_timer(&fi->lport_timer);
-		fi->g.lport_timer_set = TRUE;
-		take_tachyon_offline(fi);
-		reset_tachyon(fi, SOFTWARE_RESET);
-	}
-	else
-	if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) {
-		DPRINTK1("Link Fail-II in OLD-PORT.");
-		take_tachyon_offline(fi);
-		reset_tachyon(fi, SOFTWARE_RESET);
-	}
-}
-
-static void loop_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info*)data;
-	fi->g.lport_timer_set = FALSE;
-	del_timer(&fi->lport_timer);
-	if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE))
-		return;
-}
-
-static void add_display_cache_timer(struct fc_info *fi)
-{
-	fi->display_cache_timer.function = display_cache_timer;
-	fi->display_cache_timer.data = (unsigned long)fi;
-	fi->display_cache_timer.expires = RUN_AT(fi->num_nodes * HZ); 
-	init_timer(&fi->display_cache_timer);
-	add_timer(&fi->display_cache_timer);
-}
-
-static void display_cache_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info*)data;
-	del_timer(&fi->display_cache_timer);
-	display_cache(fi);
-	return;
-}
-
-static void reset_tachyon(struct fc_info *fi, u_int value)
-{
-u_int tachyon_status, reset_done = OCQ_RESET_STATUS | SCSI_FREEZE_STATUS;
-int not_done = 1, i = 0;
-	writel(value, fi->t_r.ptr_tach_control_reg);
-	if (value == OCQ_RESET) 
-		fi->q.ocq_prod_indx = 0;
-	tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-
-	/* Software resets are immediately done, whereas other aren't. It 
-	about 30 clocks to do the reset */
-	if (value != SOFTWARE_RESET) {
-		while(not_done) {
-			if (i++ > 100000) {
-				T_MSG("Reset was unsuccessful! Tachyon Status = %x", tachyon_status);
-				break;
-			}
-			tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-			if ((tachyon_status & reset_done) == 0)
-				not_done = 0;
-		}
-	}
-	else {
-		write_to_tachyon_registers(fi);
-	}
-}
-
-static void take_tachyon_offline(struct fc_info *fi)
-{
-u_int fm_status = readl(fi->t_r.ptr_fm_status_reg);
-
-	/* The first two conditions will never be true. The Manual and
-	 * the errata say this. But the current implementation is
-	 * decently stable.
-	 */	 
-	//if ((fm_status & 0xF0) == LOOP_FAIL) {
-	if (fm_status == LOOP_FAIL) {
-		// workaround as in P. 89 
-		writel(HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
-		if (fi->g.loop_up == TRUE)
-			writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg);
-		else {
-			writel(OFFLINE, fi->t_r.ptr_fm_control_reg);
-			writel(EXIT_HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
-		}
-	}
-	else
-	//if ((fm_status & LOOP_UP) == LOOP_UP) {
-	if (fm_status == LOOP_UP) {
-		writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg);
-	}
-	else
-		writel(OFFLINE, fi->t_r.ptr_fm_control_reg);
-}
-
-
-static void read_novram(struct fc_info *fi)
-{
-int off = 0;
-	fi->n_r.ptr_novram_hw_control_reg = fi->i_r.ptr_ichip_hw_control_reg; 
-	fi->n_r.ptr_novram_hw_status_reg = fi->i_r.ptr_ichip_hw_status_reg; 
-	iph5526_nr_do_init(fi);
-	if (fi->clone_id == PCI_VENDOR_ID_INTERPHASE)
-		off = 32;
-	
-	fi->g.my_node_name_high = (fi->n_r.data[off] << 16) | fi->n_r.data[off+1];
-	fi->g.my_node_name_low = (fi->n_r.data[off+2] << 16) | fi->n_r.data[off+3];
-	fi->g.my_port_name_high = (fi->n_r.data[off+4] << 16) | fi->n_r.data[off+5];
-	fi->g.my_port_name_low = (fi->n_r.data[off+6] << 16) | fi->n_r.data[off+7];
-	DPRINTK("node_name = %x %x", fi->g.my_node_name_high, fi->g.my_node_name_low);
-	DPRINTK("port_name = %x %x", fi->g.my_port_name_high, fi->g.my_port_name_low);
-}
-
-static void reset_ichip(struct fc_info *fi)
-{
-	/* (i)chip reset */
-	writel(ICHIP_HCR_RESET, fi->i_r.ptr_ichip_hw_control_reg);
-	/*wait for chip to get reset */
-	mdelay(10);
-	/*de-assert reset */
-	writel(ICHIP_HCR_DERESET, fi->i_r.ptr_ichip_hw_control_reg);
-	
-	/* enable INT lines on the (i)chip */
-	writel(ICHIP_HCR_ENABLE_INTA , fi->i_r.ptr_ichip_hw_control_reg);
-	/* enable byte swap */
-	writel(ICHIP_HAMR_BYTE_SWAP_ADDR_TR, fi->i_r.ptr_ichip_hw_addr_mask_reg);
-}
-
-static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id)
-{
-int int_required = 1;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-u_int r_ctl = RCTL_ELS_UCTL;
-u_int type  = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_logi");
-	/* We don't want interrupted for our own logi. 
-	 * It screws up the port discovery process. 
-	 */
-	if (d_id == fi->g.my_id)
-		int_required = 0;
-	fill_login_frame(fi, logi);	
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN));
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, ox_id, logi);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_logi");
-	return;
-}
-
-static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id)
-{
-int int_required = 0;
-u_int r_ctl = RCTL_ELS_SCTL;
-u_int type  = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_logi_acc");
-	fill_login_frame(fi, logi);	
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN));
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, logi);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_logi_acc");
-	return;
-}
-
-static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id)
-{
-int int_required = 1;
-u_int r_ctl = RCTL_ELS_UCTL;
-u_int type  = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_prli");
-	if (command_code == ELS_PRLI)
-		fi->g.prli.cmnd_code = htons((ELS_PRLI | PAGE_LEN) >> 16);
-	else {
-		fi->g.prli.cmnd_code = htons((ELS_ACC | PAGE_LEN) >> 16);
-		int_required = 0;
-		type  = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
-		r_ctl = RCTL_ELS_SCTL;
-	}
-	fi->g.prli.payload_length = htons(PRLI_LEN);
-	fi->g.prli.type_code = htons(FCP_TYPE_CODE);
-	fi->g.prli.est_image_pair = htons(IMAGE_PAIR);
-	fi->g.prli.responder_pa = 0;
-	fi->g.prli.originator_pa = 0;
-	fi->g.prli.service_params = htonl(INITIATOR_FUNC | READ_XFER_RDY_DISABLED);
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.prli, sizeof(PRLI));
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]), sizeof(PRLI), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, command_code);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_prli");
-	return;
-}
-
-static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id)
-{
-int int_required = 1;
-u_int r_ctl = RCTL_ELS_UCTL;
-u_int type  = TYPE_ELS | EXCHANGE_RESPONDER | SEQUENCE_RESPONDER | FIRST_SEQUENCE | END_SEQUENCE | SEQUENCE_INITIATIVE;
-int size = sizeof(LOGO);
-char fc_id[3];
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_logo");
-	fi->g.logo.logo_cmnd = htonl(ELS_LOGO);
-	fi->g.logo.reserved = 0;
-	memcpy(fc_id, &(fi->g.my_id), 3);
-	fi->g.logo.n_port_id_0 = fc_id[0];
-	fi->g.logo.n_port_id_1 = fc_id[1];
-	fi->g.logo.n_port_id_2 = fc_id[2];
-	fi->g.logo.port_name_up = htonl(N_PORT_NAME_HIGH);
-	fi->g.logo.port_name_low = htonl(N_PORT_NAME_LOW);
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.logo, sizeof(LOGO));
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_LOGO);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_logo");
-}
-
-static void tx_adisc(struct fc_info *fi, u_int cmnd_code, u_int d_id, u_short received_ox_id)
-{
-int int_required = 0;
-u_int r_ctl = RCTL_ELS_SCTL;
-u_int type  = TYPE_ELS | EXCHANGE_RESPONDER | SEQUENCE_RESPONDER | FIRST_SEQUENCE | END_SEQUENCE;
-int size = sizeof(ADISC);
-u_int my_mtu = fi->g.my_mtu;
-	fi->g.adisc.ls_cmnd_code = htonl(cmnd_code);
-	fi->g.adisc.hard_address = htonl(0);
-	fi->g.adisc.port_name_high = htonl(N_PORT_NAME_HIGH);	
-	fi->g.adisc.port_name_low = htonl(N_PORT_NAME_LOW);	
-	fi->g.adisc.node_name_high = htonl(NODE_NAME_HIGH);	
-	fi->g.adisc.node_name_low = htonl(NODE_NAME_LOW);	
-	fi->g.adisc.n_port_id = htonl(fi->g.my_id);
-	if (cmnd_code == ELS_ADISC) {
-		int_required = 1;
-		r_ctl = RCTL_ELS_UCTL;
-		type  = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-	}
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.adisc, size);
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, cmnd_code);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-}
-
-static void tx_ls_rjt(struct fc_info *fi, u_int d_id, u_short received_ox_id, u_short reason_code, u_short expln_code)
-{
-int int_required = 0;
-u_int r_ctl = RCTL_ELS_SCTL;
-u_int type  = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
-int size = sizeof(LS_RJT);
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_ls_rjt");
-	fi->g.ls_rjt.cmnd_code = htonl(ELS_LS_RJT);
-	fi->g.ls_rjt.reason_code = htonl((reason_code << 16) | expln_code); 
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.ls_rjt, size);
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_LS_RJT);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_ls_rjt");
-}
-
-static void tx_abts(struct fc_info *fi, u_int d_id, u_short ox_id)
-{
-int int_required = 1;
-u_int r_ctl = RCTL_BASIC_ABTS;
-u_int type  = TYPE_BLS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-int size = 0;
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_abts");
-	fi->g.type_of_frame = FC_BLS;
-	tx_exchange(fi, NULL, size, r_ctl, type, d_id, my_mtu, int_required, ox_id, RCTL_BASIC_ABTS);
-	LEAVE("tx_abts");
-}
-
-static u_int plogi_ok(struct fc_info *fi, u_int *buff_addr, int size)
-{
-int ret_code = 0;
-u_short mtu = ntohl(*(buff_addr + 10)) & 0x00000FFF;
-u_short class3 = ntohl(*(buff_addr + 25)) >> 16;
-u_short class3_conc_seq = ntohl(*(buff_addr + 27)) >> 16;
-u_short open_seq = ntohl(*(buff_addr + 28)) >> 16;
-	DPRINTK1("mtu = %x class3 = %x conc_seq = %x open_seq = %x", mtu, class3, class3_conc_seq, open_seq);	
-	size -= TACHYON_HEADER_LEN;
-	if (!(class3 & 0x8000)) {
-		DPRINTK1("Received PLOGI with class3 = %x", class3);
-		ret_code = (LOGICAL_ERR << 16) | NO_EXPLN;
-		return ret_code;
-	}
-	if (mtu < 256) {
-		DPRINTK1("Received PLOGI with MTU set to %x", mtu);
-		ret_code = (LOGICAL_ERR << 16) | RECV_FIELD_SIZE;
-		return ret_code;
-	}
-	if (size != PLOGI_LEN) {	
-		DPRINTK1("Received PLOGI of size %x", size);
-		ret_code = (LOGICAL_ERR << 16) | INV_PAYLOAD_LEN;
-		return ret_code;
-	}
-	if (class3_conc_seq == 0) {	
-		DPRINTK1("Received PLOGI with conc_seq == 0");
-		ret_code = (LOGICAL_ERR << 16) | CONC_SEQ;
-		return ret_code;
-	}
-	if (open_seq == 0) {	
-		DPRINTK1("Received PLOGI with open_seq == 0");
-		ret_code = (LOGICAL_ERR << 16) | NO_EXPLN;
-		return ret_code;
-	}
-
-	/* Could potentially check for more fields, but might end up
-	   not talking to most of the devices. ;-) */
-	/* Things that could get checked are:
-	   common_features = 0x8800
-	   total_concurrent_seq = at least 1
-	*/
-	return ret_code;
-}
-
-static void tx_acc(struct fc_info *fi, u_int d_id, u_short received_ox_id)
-{
-int int_required = 0;
-u_int r_ctl = RCTL_ELS_SCTL;
-u_int type  = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
-int size = sizeof(ACC);
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_acc");
-	fi->g.acc.cmnd_code = htonl(ELS_ACC);
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.acc, size);
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_ACC);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_acc");
-}
-
-
-static void tx_name_server_req(struct fc_info *fi, u_int req)
-{
-int int_required = 1, i, size = 0;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-u_int type  = TYPE_FC_SERVICES | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_CONTROL;
-u_int my_mtu = fi->g.my_mtu, d_id = DIRECTORY_SERVER;
-CT_HDR ct_hdr;
-	ENTER("tx_name_server_req");
-	/* Fill up CT_Header */
-	ct_hdr.rev_in_id = htonl(FC_CT_REV);
-	ct_hdr.fs_type = DIRECTORY_SERVER_APP;
-	ct_hdr.fs_subtype = NAME_SERVICE;
-	ct_hdr.options = 0;
-	ct_hdr.resv1 = 0;
-	ct_hdr.cmnd_resp_code = htons(req >> 16);
-	ct_hdr.max_res_size = 0;
-	ct_hdr.resv2 = 0;
-	ct_hdr.reason_code = 0;
-	ct_hdr.expln_code = 0;
-	ct_hdr.vendor_unique = 0;
-	
-	fi->g.type_of_frame = FC_ELS;
-	switch(req) {
-		case FCS_RFC_4:
-			memcpy(&(fi->g.rfc_4.ct_hdr), &ct_hdr, sizeof(CT_HDR));
-			fi->g.rfc_4.s_id = htonl(fi->g.my_id);
-			for (i = 0; i < 32; i++)
-				fi->g.rfc_4.bit_map[i] = 0;
-			/* We support IP & SCSI */
-			fi->g.rfc_4.bit_map[2] = 0x01;
-			fi->g.rfc_4.bit_map[3] = 0x20;
-			size = sizeof(RFC_4);
-			memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.rfc_4, size);
-			tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, req);
-			break;
-		case FCS_GP_ID4:
-			memcpy(&(fi->g.gp_id4.ct_hdr), &ct_hdr, sizeof(CT_HDR));
-			fi->g.gp_id4.port_type = htonl(PORT_TYPE_NX_PORTS);
-			size = sizeof(GP_ID4);
-			memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.gp_id4, size);
-			tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, req);
-			break;
-	}
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_name_server_req");
-}
-
-static void tx_scr(struct fc_info *fi)
-{
-int int_required = 1, size = sizeof(SCR);
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-u_int type  = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
-u_int r_ctl = RCTL_ELS_UCTL;
-u_int my_mtu = fi->g.my_mtu, d_id = FABRIC_CONTROLLER;
-	ENTER("tx_scr");
-	fi->g.scr.cmnd_code = htonl(ELS_SCR);
-	fi->g.scr.reg_function = htonl(FULL_REGISTRATION);
-	fi->g.type_of_frame = FC_ELS;
-	memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.scr, size);
-	tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, ELS_SCR);
-	fi->g.e_i++;
-	if (fi->g.e_i == MAX_PENDING_FRAMES)
-		fi->g.e_i = 0;
-	LEAVE("tx_scr");
-}
-
-static void perform_adisc(struct fc_info *fi)
-{
-int count = 0;
-	/* Will be set to TRUE when timer expires in a PLDA environment. 
-	 */
-	fi->g.port_discovery = FALSE;
-
-	if (fi->node_info_list) {
-		struct fc_node_info *temp_list = fi->node_info_list;
-		while(temp_list) {
-			/* Tx ADISC to all non-fabric based 
-	 	 	 * entities.
-	 	 	 */
-			if ((temp_list->d_id & 0xFF0000) != 0xFF0000)
-				tx_adisc(fi, ELS_ADISC, temp_list->d_id, OX_ID_FIRST_SEQUENCE);
-			temp_list = temp_list->next;
-			udelay(20);
-			count++;
-		}
-	}
-	/* Perform Port Discovery after timer expires.
-	 * We are giving time for the ADISCed nodes to respond
-	 * so that we don't have to perform PLOGI to those whose
-	 * login are _still_ valid.
-	 */
-	fi->explore_timer.function = port_discovery_timer;
-	fi->explore_timer.data = (unsigned long)fi;
-	fi->explore_timer.expires = RUN_AT((count*3*HZ)/100); 
-	init_timer(&fi->explore_timer);
-	add_timer(&fi->explore_timer);
-}
-
-static void explore_fabric(struct fc_info *fi, u_int *buff_addr)
-{
-u_int *addr = buff_addr + 12; /* index into payload */
-u_char control_code;
-u_int d_id;
-int count = 0;
-	ENTER("explore_fabric");
-	DPRINTK1("entering explore_fabric");
-
-	/*fi->g.perform_adisc = TRUE;
-	fi->g.explore_fabric = TRUE;
-	perform_adisc(fi);*/
-	
-	do {
-		d_id = ntohl(*addr) & 0x00FFFFFF;
-		if (d_id != fi->g.my_id) {
-			if (sid_logged_in(fi, d_id) == NODE_NOT_PRESENT)
-				tx_logi(fi, ELS_PLOGI, d_id); 
-			else
-			if (sid_logged_in(fi, d_id) == NODE_LOGGED_OUT)
-				tx_adisc(fi, ELS_ADISC, d_id, OX_ID_FIRST_SEQUENCE); 
-			count++;
-		}
-		control_code = (ntohl(*addr) & 0xFF000000) >> 24;
-		addr++;
-		DPRINTK1("cc = %x, d_id = %x", control_code, d_id);
-	} while (control_code != 0x80);
-	
-	fi->explore_timer.function = fabric_explore_timer;
-	fi->explore_timer.data = (unsigned long)fi;
-	/* We give 30 msec for each device to respond and then send out
-	 * our SCSI enquiries. 
-	 */
-	fi->explore_timer.expires = RUN_AT((count*3*HZ)/100); 
-	init_timer(&fi->explore_timer);
-	add_timer(&fi->explore_timer);
-
-	DPRINTK1("leaving explore_fabric");
-	LEAVE("explore_fabric");
-}
-
-static void fabric_explore_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info*)data;
-	del_timer(&fi->explore_timer);
-
-	if ((fi->g.loop_up == TRUE) && (fi->g.ptp_up == FALSE)) {
-		/* Initiate Local Port Discovery on the Local Loop.
-		 */
-		fi->g.port_discovery = TRUE;
-		fi->g.alpa_list_index = 1;
-		local_port_discovery(fi);
-	}
-	fi->g.explore_fabric = FALSE;
-	return;
-}
-
-static void port_discovery_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info*)data;
-	del_timer(&fi->explore_timer);
-	
-	if ((fi->g.loop_up == TRUE) && (fi->g.explore_fabric != TRUE)) {
-		fi->g.port_discovery = TRUE;
-		fi->g.alpa_list_index = 1;
-		local_port_discovery(fi);
-	}
-	fi->g.perform_adisc = FALSE;
-	return;
-}
-
-static void add_to_ox_id_list(struct fc_info *fi, u_int transaction_id, u_int cmnd_code)
-{
-struct ox_id_els_map *p, *q = fi->ox_id_list, *r = NULL;
-int size = sizeof(struct ox_id_els_map);
-	while (q != NULL) {
-		r = q;
-		q = q->next;
-	}
-	p = (struct ox_id_els_map *)kmalloc(size, GFP_ATOMIC);
-	if (p == NULL) {
-		T_MSG("kmalloc failed in add_to_ox_id_list()");
-		return;
-	}
-	p->ox_id = transaction_id;
-	p->els = cmnd_code;
-	p->next = NULL;
-	if (fi->ox_id_list == NULL)
-		fi->ox_id_list = p;
-	else
-		r->next = p;
-	return;
-}
-
-static u_int remove_from_ox_id_list(struct fc_info *fi, u_short received_ox_id)
-{
-struct ox_id_els_map *p = fi->ox_id_list, *q = fi->ox_id_list;
-u_int els_type;
-	while (q != NULL) {
-		if (q->ox_id == received_ox_id) {
-
-			if (q == fi->ox_id_list) 
-				fi->ox_id_list = fi->ox_id_list->next;
-			else
-				if (q->next == NULL) 
-					p->next = NULL;
-			else 
-					p->next = q->next;
-
-			els_type = q->els;
-			kfree(q);
-			return els_type;
-		}
-		p = q;
-		q = q->next;
-	}
-	if (q == NULL)
-		DPRINTK2("Could not find ox_id %x in ox_id_els_map", received_ox_id);
-	return 0;
-}
-
-static void build_tachyon_header(struct fc_info *fi, u_int my_id, u_int r_ctl, u_int d_id, u_int type, u_char seq_id, u_char df_ctl, u_short ox_id, u_short rx_id, char *data)
-{
-u_char alpa = d_id & 0x0000FF;
-u_int dest_ddaa = d_id &0xFFFF00;
-
-	ENTER("build_tachyon_header");
-	DPRINTK("d_id = %x, my_ddaa = %x", d_id, fi->g.my_ddaa);
-	/* Does it have to go to/thru a Fabric? */
-	if ((dest_ddaa != 0) && ((d_id == F_PORT) || (fi->g.fabric_present && (dest_ddaa != fi->g.my_ddaa))))
-		alpa = 0x00;
-	fi->g.tach_header.resv = 0x00000000;
-	fi->g.tach_header.sof_and_eof = SOFI3 | EOFN;
-	fi->g.tach_header.dest_alpa = alpa;
-	/* Set LCr properly to have enuff credit */
-	if (alpa == REPLICATE)
-		fi->g.tach_header.lcr_and_time_stamp = htons(0xC00);/* LCr=3 */
-	else
-		fi->g.tach_header.lcr_and_time_stamp = 0;
-	fi->g.tach_header.r_ctl_and_d_id = htonl(r_ctl | d_id);
-	fi->g.tach_header.vc_id_and_s_id = htonl(my_id);
-	fi->g.tach_header.type_and_f_cntl = htonl(type);
-	fi->g.tach_header.seq_id = seq_id;
-	fi->g.tach_header.df_cntl = df_ctl;
-	fi->g.tach_header.seq_cnt = 0;
-	fi->g.tach_header.ox_id = htons(ox_id);
-	fi->g.tach_header.rx_id = htons(rx_id);
-	fi->g.tach_header.ro = 0;
-	if (data) {
-		/* We use the Seq_Count to keep track of IP frames in the
-		 * OCI_interrupt handler. Initial Seq_Count of IP frames is 1.
-		 */
-		if (fi->g.type_of_frame == FC_BROADCAST)
-			fi->g.tach_header.seq_cnt = htons(0x1);
-		else
-			fi->g.tach_header.seq_cnt = htons(0x2);
-		fi->g.tach_header.nw_header.d_naa = htons(0x1000);
-		fi->g.tach_header.nw_header.s_naa = htons(0x1000);
-		memcpy(&(fi->g.tach_header.nw_header.dest_high), data, 2);
-		memcpy(&(fi->g.tach_header.nw_header.dest_low), data + 2, 4);
-		memcpy(&(fi->g.tach_header.nw_header.source_high), data + 6, 2);
-		memcpy(&(fi->g.tach_header.nw_header.source_low), data + 8, 4);
-	}
-	LEAVE("build_tachyon_header");
-}
-
-static void build_EDB(struct fc_info *fi, char *data, u_short flags, u_short len)
-{
-	fi->g.edb.buf_addr = ntohl((u_int)virt_to_bus(data));
-	fi->g.edb.ehf = ntohs(flags);
-	if (len % 4)
-		len += (4 - (len % 4));
-	fi->g.edb.buf_len = ntohs(len);
-}
-
-static void build_ODB(struct fc_info *fi, u_char seq_id, u_int d_id, u_int len, u_int cntl, u_short mtu, u_short ox_id, u_short rx_id, int NW_header, int int_required, u_int frame_class)
-{
-	fi->g.odb.seq_d_id = htonl(seq_id << 24 | d_id);
-	fi->g.odb.tot_len = len;
-	if (NW_header)
-		fi->g.odb.tot_len += NW_HEADER_LEN;
-	if (fi->g.odb.tot_len % 4)
-		fi->g.odb.tot_len += (4 - (fi->g.odb.tot_len % 4));
-	fi->g.odb.tot_len = htonl(fi->g.odb.tot_len);
-	switch(int_required) {
-		case NO_COMP_AND_INT:
-			fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | ODB_NO_COMP | cntl);
-			break;
-		case INT_AND_COMP_REQ:
-			fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | cntl);
-			break;
-		case NO_INT_COMP_REQ:
-			fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | cntl);
-			break;
-	}
-	fi->g.odb.rx_id = htons(rx_id);
-	fi->g.odb.cs_enable = 0;
-	fi->g.odb.cs_seed = htons(1);
-
-	fi->g.odb.hdr_addr = htonl(virt_to_bus(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx]));
-	fi->g.odb.frame_len = htons(mtu);
-
-	if (NW_header) {
-		/* The pointer to the sk_buff is in here. Freed up when the
-		 * OCI_interrupt is received.
-		 */
-		fi->g.odb.trans_id = htonl(frame_class);
-		fi->g.odb.hdr_len = TACHYON_HEADER_LEN + NW_HEADER_LEN;
-	}
-	else {
-		/* helps in tracking transmitted OX_IDs */
-		fi->g.odb.trans_id = htonl((frame_class & 0xFFFF0000) | ox_id);
-		fi->g.odb.hdr_len = TACHYON_HEADER_LEN;
-	}
-	fi->g.odb.hdr_len = htons(fi->g.odb.hdr_len);
-		
-	fi->g.odb.edb_addr = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx]));
-}
-
-static void fill_login_frame(struct fc_info *fi, u_int logi)
-{
-int i;
-	fi->g.login.ls_cmnd_code= htonl(logi);
-	fi->g.login.fc_ph_version = htons(PH_VERSION);
-	if (fi->g.loop_up)
-		fi->g.login.buff_to_buff_credit = htons(LOOP_BB_CREDIT);
-	else
-	if (fi->g.ptp_up)
-		fi->g.login.buff_to_buff_credit = htons(PT2PT_BB_CREDIT);
-	if ((logi != ELS_FLOGI) || (logi == ELS_ACC))
-		fi->g.login.common_features = htons(PLOGI_C_F);
-	else
-	if (logi == ELS_FLOGI)
-		fi->g.login.common_features = htons(FLOGI_C_F);
-	fi->g.login.recv_data_field_size = htons(TACH_FRAME_SIZE);
-	fi->g.login.n_port_total_conc_seq = htons(CONCURRENT_SEQUENCES);
-	fi->g.login.rel_off_by_info_cat = htons(RO_INFO_CATEGORY);
-	fi->g.login.ED_TOV = htonl(E_D_TOV);
-	fi->g.login.n_port_name_high = htonl(N_PORT_NAME_HIGH);
-	fi->g.login.n_port_name_low = htonl(N_PORT_NAME_LOW);
-	fi->g.login.node_name_high = htonl(NODE_NAME_HIGH);
-	fi->g.login.node_name_low = htonl(NODE_NAME_LOW);
-	
-	/* Fill Class 1 parameters */
-	fi->g.login.c_of_s[0].service_options = htons(0);
-	fi->g.login.c_of_s[0].initiator_ctl = htons(0);
-	fi->g.login.c_of_s[0].recipient_ctl = htons(0);
-	fi->g.login.c_of_s[0].recv_data_field_size = htons(0);
-	fi->g.login.c_of_s[0].concurrent_sequences = htons(0);
-	fi->g.login.c_of_s[0].n_port_end_to_end_credit = htons(0);
-	fi->g.login.c_of_s[0].open_seq_per_exchange = htons(0);
-	fi->g.login.c_of_s[0].resv = htons(0);
-
-	/* Fill Class 2 parameters */
-	fi->g.login.c_of_s[1].service_options = htons(0);
-	fi->g.login.c_of_s[1].initiator_ctl = htons(0);
-	fi->g.login.c_of_s[1].recipient_ctl = htons(0);
-	fi->g.login.c_of_s[1].recv_data_field_size = htons(0);
-	fi->g.login.c_of_s[1].concurrent_sequences = htons(0);
-	fi->g.login.c_of_s[1].n_port_end_to_end_credit = htons(0);
-	fi->g.login.c_of_s[1].open_seq_per_exchange = htons(0);
-	fi->g.login.c_of_s[1].resv = htons(0);
-
-	/* Fill Class 3 parameters */
-	if (logi == ELS_FLOGI)
-		fi->g.login.c_of_s[2].service_options  = htons(SERVICE_VALID | SEQUENCE_DELIVERY);
-	else
-		fi->g.login.c_of_s[2].service_options  = htons(SERVICE_VALID);
-	fi->g.login.c_of_s[2].initiator_ctl = htons(0);
-	fi->g.login.c_of_s[2].recipient_ctl = htons(0);
-	fi->g.login.c_of_s[2].recv_data_field_size = htons(TACH_FRAME_SIZE);
-	fi->g.login.c_of_s[2].concurrent_sequences = htons(CLASS3_CONCURRENT_SEQUENCE);
-	fi->g.login.c_of_s[2].n_port_end_to_end_credit = htons(0);
-	fi->g.login.c_of_s[2].open_seq_per_exchange = htons(CLASS3_OPEN_SEQUENCE);
-	fi->g.login.c_of_s[2].resv = htons(0);
-	
-	for(i = 0; i < 4; i++) {
-		fi->g.login.resv[i] = 0;
-		fi->g.login.vendor_version_level[i] = 0;
-	}
-}
-
-
-/* clear the Interrupt Latch on the (i)chip, so that you can receive 
- * Interrupts from Tachyon in future 
- */
-static void reset_latch(struct fc_info *fi)
-{
-	writel(readl(fi->i_r.ptr_ichip_hw_status_reg) | ICHIP_HSR_INT_LATCH, fi->i_r.ptr_ichip_hw_status_reg);
-}
-
-static void update_OCQ_indx(struct fc_info *fi)
-{
-	fi->q.ocq_prod_indx++;
-	if (fi->q.ocq_prod_indx == OCQ_LENGTH)
-		fi->q.ocq_prod_indx = 0;
-	writel(fi->q.ocq_prod_indx, fi->t_r.ptr_ocq_prod_indx_reg);
-}
-
-static void update_IMQ_indx(struct fc_info *fi, int count)
-{
-	fi->q.imq_cons_indx += count;
-	if (fi->q.imq_cons_indx >= IMQ_LENGTH)
-		fi->q.imq_cons_indx -= IMQ_LENGTH;
-	writel(fi->q.imq_cons_indx, fi->t_r.ptr_imq_cons_indx_reg);
-}
-
-static void update_SFSBQ_indx(struct fc_info *fi)
-{
-	fi->q.sfsbq_prod_indx++;
-	if (fi->q.sfsbq_prod_indx == SFSBQ_LENGTH)
-		fi->q.sfsbq_prod_indx = 0;
-	writel(fi->q.sfsbq_prod_indx, fi->t_r.ptr_sfsbq_prod_reg);
-}
-
-static void update_MFSBQ_indx(struct fc_info *fi, int count)
-{
-	fi->q.mfsbq_prod_indx += count;
-	if (fi->q.mfsbq_prod_indx >= MFSBQ_LENGTH)
-		fi->q.mfsbq_prod_indx -= MFSBQ_LENGTH;
-	writel(fi->q.mfsbq_prod_indx, fi->t_r.ptr_mfsbq_prod_reg);
-}
-
-
-static void update_tachyon_header_indx(struct fc_info *fi)
-{
-	fi->q.tachyon_header_indx++;
-	if (fi->q.tachyon_header_indx == NO_OF_TACH_HEADERS)
-		fi->q.tachyon_header_indx = 0;
-}
-
-static void update_EDB_indx(struct fc_info *fi)
-{
-	fi->q.edb_buffer_indx++;
-	if (fi->q.edb_buffer_indx == EDB_LEN)
-		fi->q.edb_buffer_indx = 0;
-}
-
-static int iph5526_open(struct net_device *dev)
-{
-	netif_start_queue(dev);
-	return 0;
-}
-
-static int iph5526_close(struct net_device *dev)
-{
-	netif_stop_queue(dev);
-	return 0;
-}
-
-static void iph5526_timeout(struct net_device *dev)
-{
-	struct fc_info *fi = dev->priv;
-	printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
-	fi->fc_stats.tx_dropped++;
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-}
-
-static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct fc_info *fi = dev->priv;
-	int status = 0;
-	short type = 0;
-	u_long flags;
-	struct fcllc *fcllc;
-	
-	ENTER("iph5526_send_packet");
-	
-	netif_stop_queue(dev);
-	/* Strip off the pseudo header.
-	 */
-	skb->data = skb->data + 2*FC_ALEN; 
-	skb->len = skb->len - 2*FC_ALEN;
-	fcllc = (struct fcllc *)skb->data;
-	type = ntohs(fcllc->ethertype);
-
-	spin_lock_irqsave(&fi->fc_lock, flags);
-	switch(type) {
-		case ETH_P_IP:
-			status = tx_ip_packet(skb, skb->len, fi);
-			break;
-		case ETH_P_ARP:
-			status = tx_arp_packet(skb->data, skb->len, fi);
-			break;
-		default:
-			T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
-			fi->fc_stats.rx_dropped++;
-			break;
-	}
-	spin_unlock_irqrestore(&fi->fc_lock, flags);
-
-	if (status) {
-		fi->fc_stats.tx_bytes += skb->len;
-		fi->fc_stats.tx_packets++;
-	}
-	else
-		fi->fc_stats.tx_dropped++;
-	dev->trans_start = jiffies;
-	/* We free up the IP buffers in the OCI_interrupt handler.
-	 * status == 0 implies that the frame was not transmitted. So the
-	 * skb is freed here.
-	 */
-	if ((type == ETH_P_ARP) || (status == 0))
-		dev_kfree_skb(skb);
-	netif_wake_queue(dev);
-	LEAVE("iph5526_send_packet");
-	return 0;
-}
-
-static int iph5526_change_mtu(struct net_device *dev, int mtu)
-{
-	return 0;
-}
-
-static int tx_ip_packet(struct sk_buff *skb, unsigned long len, struct fc_info *fi)
-{
-u_int d_id;
-int int_required = 1;
-u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_DATA;
-u_int type = TYPE_LLC_SNAP;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-u_int mtu;
-struct fc_node_info *q;
-
-	ENTER("tx_ip_packet");
-	q = look_up_cache(fi, skb->data - 2*FC_ALEN);
-	if (q != NULL) {
-		d_id = q->d_id;
-		DPRINTK("Look-Up Cache Succeeded for d_id = %x", d_id);
-		mtu = q->mtu;
-		if (q->login == LOGIN_COMPLETED){
-			fi->g.type_of_frame = FC_IP;
-			return tx_exchange(fi, skb->data, len, r_ctl, type, d_id, mtu, int_required, ox_id, virt_to_bus(skb));
-		}
-		
-		if (q->d_id == BROADCAST) {
-		struct fc_node_info *p = fi->node_info_list;
-		int return_value = FALSE;
-			fi->g.type_of_frame = FC_BROADCAST;
-			/* Do unicast to local nodes.
-			 */
-			int_required = 0;
-			while(p != NULL) {
-				d_id = p->d_id;
-				if ((d_id & 0xFFFF00) == fi->g.my_ddaa)
-					return_value |= tx_exchange(fi, skb->data, len, r_ctl, type, d_id, fi->g.my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-				p = p->next;
-			}
-			kfree(q);
-			return return_value;
-		}
-		
-		if (q->login != LOGIN_COMPLETED) {	
-			DPRINTK1("Node not logged in... Txing PLOGI to %x", d_id);
-			/* FIXME: we are dumping the frame here */
-			tx_logi(fi, ELS_PLOGI, d_id); 
-		}
-	}
-	DPRINTK2("Look-Up Cache Failed");
-	LEAVE("tx_ip_packet");
-	return 0;
-}
-
-static int tx_arp_packet(char *data, unsigned long len, struct fc_info *fi)
-{
-u_int opcode = data[ARP_OPCODE_0]; 
-u_int d_id;
-int int_required = 0, return_value = FALSE;
-u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_DATA;
-u_int type = TYPE_LLC_SNAP;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-u_int my_mtu = fi->g.my_mtu;
-	ENTER("tx_arp_packet");
-
-	opcode = opcode << 8 | data[ARP_OPCODE_1];
-	fi->g.type_of_frame = FC_IP;
-
-	if (opcode == ARPOP_REQUEST) {
-	struct fc_node_info *q = fi->node_info_list;
-		d_id = BROADCAST;
-		return_value |= tx_exchange(fi, data, len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-		/* Some devices support HW_TYPE 0x01 */
-		memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN);
-		fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01;
-		return_value |= tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-
-		/* Do unicast to local nodes.
-		 */
-		while(q != NULL) {
-			fi->g.type_of_frame = FC_BROADCAST;
-			d_id = q->d_id;
-			if ((d_id & 0xFFFF00) == fi->g.my_ddaa) {
-				return_value |= tx_exchange(fi, data, len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-				// Some devices support HW_TYPE 0x01
-				memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN);
-				fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01;
-				return_value |= tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-			}
-			q = q->next;
-		}
-		return return_value;
-	}
-	else
-	if (opcode == ARPOP_REPLY) {
-	struct fc_node_info *q; u_int mtu;
-		DPRINTK("We are sending out an ARP reply");
-		q = look_up_cache(fi, data - 2*FC_ALEN);
-		if (q != NULL) {
-			d_id = q->d_id;
-			DPRINTK("Look-Up Cache Succeeded for d_id = %x", d_id);
-			mtu = q->mtu;
-			if (q->login == LOGIN_COMPLETED){
-				tx_exchange(fi, data, len, r_ctl, type, d_id, mtu, int_required, ox_id, TYPE_LLC_SNAP);
-				/* Some devices support HW_TYPE 0x01 */
-				memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN);
-				fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01;
-				return tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP);
-			}
-			else {
-				DPRINTK1("Node not logged in... Txing PLOGI to %x", d_id);
-				tx_logi(fi, ELS_PLOGI, d_id); /* FIXME: we are dumping the frame here */
-			}
-		}
-		DPRINTK2("Look-Up Cache Failed");
-	}
-	else {
-		T_MSG("Warning!!! Invalid Opcode in ARP Packet!");
-	}
-	LEAVE("tx_arp_packet");
-	return 0;
-}
-
-
-static void rx_net_packet(struct fc_info *fi, u_char *buff_addr, int payload_size)
-{
-struct net_device *dev = fi->dev;
-struct sk_buff *skb;
-u_int skb_size = 0;
-struct fch_hdr fch;
-	ENTER("rx_net_packet");
-	skb_size = payload_size - TACHYON_HEADER_LEN;
-	DPRINTK("skb_size = %d", skb_size);
-	fi->fc_stats.rx_bytes += skb_size - 2;
-	skb = dev_alloc_skb(skb_size);
-	if (skb == NULL) {
-		printk(KERN_NOTICE "%s: In rx_net_packet() Memory squeeze, dropping packet.\n", dev->name);
-		fi->fc_stats.rx_dropped++;
-		return;
-	}
-	/* Skip over the Tachyon Frame Header.
-	 */
-	buff_addr += TACHYON_HEADER_LEN; 
-
-	memcpy(fch.daddr, buff_addr + 2, FC_ALEN);
-	memcpy(fch.saddr, buff_addr + 10, FC_ALEN);
-	buff_addr += 2;
-	memcpy(buff_addr, fch.daddr, FC_ALEN);
-	memcpy(buff_addr + 6, fch.saddr, FC_ALEN);
-	skb_reserve(skb, 2);
-	memcpy(skb_put(skb, skb_size - 2), buff_addr, skb_size - 2);
-	skb->dev = dev;
-	skb->protocol = fc_type_trans(skb, dev);
-	DPRINTK("protocol = %x", skb->protocol);
-	
-	/* Hmmm... to accept HW Type 0x01 as well... 
-	 */
-	if (skb->protocol == ntohs(ETH_P_ARP))
-		skb->data[1] = 0x06;
-	netif_rx(skb);
-	dev->last_rx = jiffies;
-	fi->fc_stats.rx_packets++;
-	LEAVE("rx_net_packet");
-}
-
-
-static void rx_net_mfs_packet(struct fc_info *fi, struct sk_buff *skb)
-{
-struct net_device *dev = fi->dev;
-struct fch_hdr fch;
-	ENTER("rx_net_mfs_packet");
-	/* Construct your Hard Header */
-	memcpy(fch.daddr, skb->data + 2, FC_ALEN);
-	memcpy(fch.saddr, skb->data + 10, FC_ALEN);
-	skb_pull(skb, 2);
-	memcpy(skb->data, fch.daddr, FC_ALEN);
-	memcpy(skb->data + 6, fch.saddr, FC_ALEN);
-	skb->dev = dev;
-	skb->protocol = fc_type_trans(skb, dev);
-	DPRINTK("protocol = %x", skb->protocol);
-	netif_rx(skb);
-	dev->last_rx = jiffies;
-	LEAVE("rx_net_mfs_packet");
-}
-
-static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short tx_ox_id, u_int frame_class)
-{
-u_char df_ctl; 
-int NW_flag = 0, h_size, return_value;
-u_short rx_id = RX_ID_FIRST_SEQUENCE;
-u_int tachyon_status;
-u_int my_id = fi->g.my_id;
-	ENTER("tx_exchange");
-
-	tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-	DPRINTK("Tachyon Status = %x len = %d MTU = %d", tachyon_status, len, mtu);
-	if (tachyon_status & OSM_FROZEN) {
-		reset_tachyon(fi, ERROR_RELEASE);
-		reset_tachyon(fi, OCQ_RESET);
-		DPRINTK("Tachyon Status = %x len = %d MTU = %d", tachyon_status, len, mtu);
-	}
-	if (tx_ox_id == OX_ID_FIRST_SEQUENCE) {
-		switch(fi->g.type_of_frame) {
-			case FC_SCSI_READ:
-				tx_ox_id = fi->g.scsi_oxid | SCSI_READ_BIT;
-				break;
-			case FC_SCSI_WRITE:
-				tx_ox_id = fi->g.scsi_oxid;
-				break;
-			default:
-				tx_ox_id = fi->g.ox_id;
-				break;
-		}
-	}
-	else {
-		switch(fi->g.type_of_frame) {
-			case FC_SCSI_READ:
-				rx_id = fi->g.scsi_oxid | SCSI_READ_BIT;
-				break;
-			case FC_SCSI_WRITE:
-				rx_id = fi->g.scsi_oxid;
-				break;
-			case FC_BLS:
-				rx_id = RX_ID_FIRST_SEQUENCE;
-				break;
-			default:
-				rx_id = fi->g.ox_id;
-				break;
-		}
-	}
-
-	if (type == TYPE_LLC_SNAP) {
-		df_ctl = 0x20;
-		NW_flag = 1;
-		/* Multi Frame Sequence ? If yes, set RO bit */
-		if (len > mtu)
-			type |= RELATIVE_OFF_PRESENT;
-		build_tachyon_header(fi, my_id, r_ctl, d_id, type, fi->g.seq_id, df_ctl, tx_ox_id, rx_id, data - 2*FC_ALEN);
-	}
-	else {
-		df_ctl = 0;
-		/* Multi Frame Sequence ? If yes, set RO bit */
-		if (len > mtu)
-			type |= RELATIVE_OFF_PRESENT;
-		build_tachyon_header(fi, my_id, r_ctl, d_id, type, fi->g.seq_id, df_ctl, tx_ox_id, rx_id, NULL);
-	}
-
-	/* Get free Tachyon Headers and EDBs */
-	if (get_free_header(fi) || get_free_EDB(fi))
-		return 0;
-
-	if ((type & 0xFF000000) == TYPE_LLC_SNAP) {
-		h_size =  TACHYON_HEADER_LEN + NW_HEADER_LEN;
-		memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), h_size);
-	}
-	else 
-		memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), TACHYON_HEADER_LEN);
-
-	return_value = tx_sequence(fi, data, len, mtu, d_id, tx_ox_id, rx_id, fi->g.seq_id, NW_flag, int_required, frame_class);
-	
-	switch(fi->g.type_of_frame) {
-		case FC_SCSI_READ:
-		case FC_SCSI_WRITE:
-			update_scsi_oxid(fi);
-			break;
-		case FC_BLS:
-			break;
-		default:
-			fi->g.ox_id++;
-			if (fi->g.ox_id == 0xFFFF)
-				fi->g.ox_id = NOT_SCSI_XID;
-			break;
-	}
-
-	if (fi->g.seq_id == MAX_SEQ_ID)
-		fi->g.seq_id = 0;
-	else
-		fi->g.seq_id++;
-	LEAVE("tx_exchange");
-	return return_value;
-}
-
-static int tx_sequence(struct fc_info *fi, char *data, u_int len, u_int mtu, u_int d_id, u_short ox_id, u_short rx_id, u_char seq_id, int NW_flag, int int_required, u_int frame_class)
-{
-u_int cntl = 0;
-int return_value;
-	ENTER("tx_sequence");
-	build_EDB(fi, data, EDB_END, len);
-	memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB));
-	build_ODB(fi, seq_id, d_id, len, cntl, mtu, ox_id, rx_id, NW_flag, int_required, frame_class);
-	memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB));
-	if (fi->g.link_up != TRUE) {
-		DPRINTK2("Fibre Channel Link not up. Dropping Exchange!");
-		return_value = FALSE;
-	}
-	else {
-		/* To be on the safe side, a check should be included
-		 * at this point to check if we are overrunning 
-		 * Tachyon.
-		 */
-		update_OCQ_indx(fi);
-		return_value = TRUE;
-	}
-	update_EDB_indx(fi);
-	update_tachyon_header_indx(fi);
-	LEAVE("tx_sequence");
-	return return_value;
-}
-
-static int get_free_header(struct fc_info *fi)
-{
-u_short temp_ox_id;
-u_int *tach_header, initial_indx = fi->q.tachyon_header_indx;
-	/* Check if the header is in use.
-	 * We could have an outstanding command.
-	 * We should find a free slot as we can queue a
-	 * maximum of 32 SCSI commands only. 
-	 */
-	tach_header = fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx];
-	temp_ox_id = ntohl(*(tach_header + 6)) >> 16;
-	/* We care about the SCSI writes only. Those are the wicked ones
-	 * that need an additional set of buffers.
-	 */
-	while(temp_ox_id <= MAX_SCSI_XID) {
-		update_tachyon_header_indx(fi);
-		if (fi->q.tachyon_header_indx == initial_indx) {
-			/* Should never happen.
-			 */
-			T_MSG("No free Tachyon headers available");
-			reset_tachyon(fi, SOFTWARE_RESET);
-			return 1;
-		}
-		tach_header = fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx];
-		temp_ox_id = ntohl(*(tach_header + 6)) >> 16;
-	}
-	return 0;
-}
-
-static int get_free_EDB(struct fc_info *fi)
-{
-unsigned int initial_indx = fi->q.edb_buffer_indx;
-	/* Check if the EDB is in use.
-	 * We could have an outstanding SCSI Write command.
-	 * We should find a free slot as we can queue a
-	 * maximum of 32 SCSI commands only. 
-	 */
-	while (fi->q.free_edb_list[fi->q.edb_buffer_indx] != EDB_FREE) {
-		update_EDB_indx(fi);
-		if (fi->q.edb_buffer_indx == initial_indx) {
-			T_MSG("No free EDB buffers avaliable")
-			reset_tachyon(fi, SOFTWARE_RESET);
-			return 1;
-		}
-	}
-	return 0;
-}		
-
-static int validate_login(struct fc_info *fi, u_int *base_ptr)
-{
-struct fc_node_info *q = fi->node_info_list;
-char n_port_name[PORT_NAME_LEN];
-char node_name[NODE_NAME_LEN];
-u_int s_id;
-	ENTER("validate_login");
-	/*index to Port Name in the payload. We need the 8 byte Port Name */
-	memcpy(n_port_name, base_ptr + 10, PORT_NAME_LEN);
-	memcpy(node_name, base_ptr + 12, NODE_NAME_LEN);
-	s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF;
-	
-	/* check if Fibre Channel IDs have changed */
-	while(q != NULL) {	
-		if (memcmp(n_port_name, q->hw_addr, PORT_NAME_LEN) == 0) {
-			if ((s_id != q->d_id) || (memcmp(node_name, q->node_name, NODE_NAME_LEN) != 0)) {
-				DPRINTK1("Fibre Channel ID of Node has changed. Txing LOGO.");
-				return 0;
-			}
-			q->login = LOGIN_COMPLETED;
-#if DEBUG_5526_2
-			display_cache(fi);
-#endif
-			return 1;
-		}
-		q = q->next;
-	}
-	DPRINTK1("Port Name does not match. Txing LOGO.");
-	LEAVE("validate_login");
-       return 0;
-}
-
-static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr)
-{
-int size = sizeof(struct fc_node_info);
-struct fc_node_info *p, *q = fi->node_info_list, *r = NULL;
-char n_port_name[PORT_NAME_LEN];
-u_int s_id;
-	ENTER("add_to_address_cache");
-	/*index to Port Name in the payload. We need the 8 byte Port Name */
-	memcpy(n_port_name, base_ptr + 13, PORT_NAME_LEN);
-	s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF;
-	
-	/* check if info already exists */
-	while(q != NULL) {	
-		if (memcmp(n_port_name, q->hw_addr, PORT_NAME_LEN) == 0) {
-			if (s_id != q->d_id) {
-				memcpy(&(q->c_of_s[0]), base_ptr + 17, 3 * sizeof(CLASS_OF_SERVICE));
-				q->mtu = ntohl(*(base_ptr + 10)) & 0x00000FFF;
-				q->d_id = s_id;
-				memcpy(q->node_name, base_ptr + 15, NODE_NAME_LEN);
-			}
-			q->login = LOGIN_COMPLETED;
-			q->scsi = FALSE;
-			fi->num_nodes++;
-#if DEBUG_5526_2
-			display_cache(fi);
-#endif
-			return;
-		}
-		r = q;
-		q = q->next;
-	}
-	p = (struct fc_node_info *)kmalloc(size, GFP_ATOMIC);
-	if (p == NULL) {
-		T_MSG("kmalloc failed in add_to_address_cache()");
-		return;
-	}
-	memcpy(&(p->c_of_s[0]), base_ptr + 17, 3 * sizeof(CLASS_OF_SERVICE));
-	p->mtu = ntohl(*(base_ptr + 10)) & 0x00000FFF;
-	p->d_id = s_id;
-	memcpy(p->hw_addr, base_ptr + 13, PORT_NAME_LEN);
-	memcpy(p->node_name, base_ptr + 15, NODE_NAME_LEN);
-	p->login = LOGIN_COMPLETED;
-	p->scsi = FALSE;
-	p->target_id = 0xFF;
-	p->next = NULL;
-	if (fi->node_info_list == NULL)
-		fi->node_info_list = p;
-	else
-		r->next = p;
-	fi->num_nodes++;
-#if DEBUG_5526_2
-	display_cache(fi);
-#endif
-	LEAVE("add_to_address_cache");
-	return;
-}
-
-static void remove_from_address_cache(struct fc_info *fi, u_int *base_ptr, u_int cmnd_code)
-{
-struct fc_node_info *q = fi->node_info_list;
-u_int s_id;
-	ENTER("remove_from_address_cache");
-	s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF;
-	switch(cmnd_code) {
-		case ELS_LOGO:
-			/* check if info exists */
-			while (q != NULL) {
-				if (s_id == q->d_id) {
-					if (q->login == LOGIN_COMPLETED)
-						q->login = LOGIN_ATTEMPTED;
-					if (fi->num_nodes > 0)
-						fi->num_nodes--;
-#if DEBUG_5526_2
-					display_cache(fi);
-#endif
-					return;
-				}
-				q = q->next;
-			}
-			DPRINTK1("ELS_LOGO received from node 0x%x which is not logged-in", s_id);
-			break;
-		case ELS_RSCN:
-		{
-		int payload_len = ntohl(*(base_ptr + 8)) & 0xFF;
-		int no_of_pages, i;
-		u_char address_format;
-		u_short received_ox_id = ntohl(*(base_ptr + 6)) >> 16;
-		u_int node_id, mask, *page_ptr = base_ptr + 9;
-			if ((payload_len < 4) || (payload_len > 256)) {
-				DPRINTK1("RSCN with invalid payload length received");
-				tx_ls_rjt(fi, s_id, received_ox_id, LOGICAL_ERR, RECV_FIELD_SIZE);
-				return;
-			}
-			/* Page_size includes the Command Code */
-			no_of_pages = (payload_len / 4) - 1;
-			for (i = 0; i < no_of_pages; i++) {
-				address_format = ntohl(*page_ptr) >> 24; 
-				node_id = ntohl(*page_ptr) & 0x00FFFFFF;
-				switch(address_format) {
-					case PORT_ADDRESS_FORMAT:
-						rscn_handler(fi, node_id);
-						break;
-					case AREA_ADDRESS_FORMAT:
-					case DOMAIN_ADDRESS_FORMAT:
-						if (address_format == AREA_ADDRESS_FORMAT)
-							mask = 0xFFFF00;
-						else
-							mask = 0xFF0000;
-						while(q != NULL) {
-							if ((q->d_id & mask) == (node_id & mask)) 
-								rscn_handler(fi, q->d_id);
-							q = q->next;
-						}
-						/* There might be some new nodes to be 
-						 * discovered. But, some of the earlier 
-						 * requests as a result of the RSCN might be 
-						 * in progress. We don't want to duplicate that 
-						 * effort. So letz call SCR after a lag.
-						 */
-						fi->explore_timer.function = scr_timer;
-						fi->explore_timer.data = (unsigned long)fi;
-						fi->explore_timer.expires = RUN_AT((no_of_pages*3*HZ)/100); 
-						init_timer(&fi->explore_timer);
-						add_timer(&fi->explore_timer);
-						break;
-					default:
-						T_MSG("RSCN with invalid address format received");
-						tx_ls_rjt(fi, s_id, received_ox_id, LOGICAL_ERR, NO_EXPLN);
-				}
-				page_ptr += 1;
-			} /* end of for loop */
-		} /* end of case RSCN: */	
-		break;
-	}
-#if DEBUG_5526_2
-	display_cache(fi);
-#endif
-	LEAVE("remove_from_address_cache");
-}
-
-static void rscn_handler(struct fc_info *fi, u_int node_id)
-{
-struct fc_node_info *q = fi->node_info_list;
-int login_state = sid_logged_in(fi, node_id);
-	if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) {
-		while(q != NULL) {
-			if (q->d_id == node_id) {
-				q->login = LOGIN_ATTEMPTED;
-				if (fi->num_nodes > 0)
-					fi->num_nodes--;
-				break;
-			}
-			else
-				q = q->next;
-		}
-	}
-	else
-	if (login_state == NODE_LOGGED_OUT)
-		tx_adisc(fi, ELS_ADISC, node_id, OX_ID_FIRST_SEQUENCE); 
-	else
-	if (login_state == NODE_LOGGED_OUT)
-		tx_logi(fi, ELS_PLOGI, node_id);
-}
-
-static void scr_timer(unsigned long data)
-{
-struct fc_info *fi = (struct fc_info *)data;
-	del_timer(&fi->explore_timer);
-	tx_name_server_req(fi, FCS_GP_ID4);
-}
-
-static int sid_logged_in(struct fc_info *fi, u_int s_id)
-{
-struct fc_node_info *temp = fi->node_info_list;
-	while(temp != NULL)
-		if ((temp->d_id == s_id) && (temp->login == LOGIN_COMPLETED)) {
-			if (temp->scsi != FALSE)
-				return NODE_PROCESS_LOGGED_IN;
-			else
-				return NODE_LOGGED_IN;
-		}
-		else
-		if ((temp->d_id == s_id) && (temp->login != LOGIN_COMPLETED))
-			return NODE_LOGGED_OUT;
-		else
-			temp = temp->next;
-	return NODE_NOT_PRESENT;
-}
-
-static void mark_scsi_sid(struct fc_info *fi, u_int *buff_addr, u_char action)
-{
-struct fc_node_info *temp = fi->node_info_list;
-u_int s_id;
-u_int service_params;
-	s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	service_params = ntohl(*(buff_addr + 12)) & 0x000000F0;
-	while(temp != NULL)
-		if ((temp->d_id == s_id) && (temp->login == LOGIN_COMPLETED)) {
-			if (action == DELETE_ENTRY) {
-				temp->scsi = FALSE;
-#if DEBUG_5526_2
-				display_cache(fi);
-#endif
-				return;
-			}
-			/* Check if it is a SCSI Target */
-			if (!(service_params & TARGET_FUNC)) {
-				temp->scsi = INITIATOR;	
-#if DEBUG_5526_2
-				display_cache(fi);
-#endif
-				return;
-			}
-			temp->scsi = TARGET;
-			/* This helps to maintain the target_id no matter what your
-			 *  Fibre Channel ID is.
-			 */
-			if (temp->target_id == 0xFF) {
-				if (fi->g.no_of_targets <= MAX_SCSI_TARGETS)
-					temp->target_id = fi->g.no_of_targets++;
-				else
-					T_MSG("MAX TARGETS reached!");
-			}
-			else
-				DPRINTK1("Target_id %d already present", temp->target_id);
-#if DEBUG_5526_2
-			display_cache(fi);
-#endif
-			return;
-		}
-		else
-			temp = temp->next;
-	return;
-}
-
-static int node_logged_in_prev(struct fc_info *fi, u_int *buff_addr)
-{
-struct fc_node_info *temp;
-u_char *data = (u_char *)buff_addr;
-u_int s_id;
-char node_name[NODE_NAME_LEN];
-	s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
-	memcpy(node_name, buff_addr + 12, NODE_NAME_LEN);
-	/* point to port_name in the ADISC payload */
-	data += 10 * 4;
-	/* point to last 6 bytes of port_name */
-	data += 2;
-	temp = look_up_cache(fi, data);
-	if (temp != NULL) {
-		if ((temp->d_id == s_id) && (memcmp(node_name, temp->node_name, NODE_NAME_LEN) == 0)) {
-			temp->login = LOGIN_COMPLETED;
-#if DEBUG_5526_2
-			display_cache(fi);
-#endif
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-static struct fc_node_info *look_up_cache(struct fc_info *fi, char *data)
-{
-struct fc_node_info *temp_list = fi->node_info_list, *q;
-u_char n_port_name[FC_ALEN], temp_addr[FC_ALEN];
-	ENTER("look_up_cache");
-	memcpy(n_port_name, data, FC_ALEN);
-	while(temp_list) {
-		if (memcmp(n_port_name, &(temp_list->hw_addr[2]), FC_ALEN) == 0)
-			return temp_list;
-		else
-			temp_list = temp_list->next;
-	}
-	
-	/* Broadcast IP ?
-	 */
-	temp_addr[0] = temp_addr[1] = temp_addr[2] = 0xFF;
-	temp_addr[3] = temp_addr[4] = temp_addr[5] = 0xFF;
-	if (memcmp(n_port_name, temp_addr, FC_ALEN) == 0) {
-		q = (struct fc_node_info *)kmalloc(sizeof(struct fc_node_info), GFP_ATOMIC);
-		if (q == NULL) {
-			T_MSG("kmalloc failed in look_up_cache()");
-			return NULL;
-		}
-		q->d_id = BROADCAST;
-		return q;
-	}
-	LEAVE("look_up_cache");
-	return NULL;
-}
-
-static int display_cache(struct fc_info *fi)
-{
-struct fc_node_info *q = fi->node_info_list;
-#if DEBUG_5526_2
-struct ox_id_els_map *temp_ox_id_list = fi->ox_id_list;
-#endif
-int count = 0, j;
-	printk("\nFibre Channel Node Information for %s\n", fi->name);
-	printk("My FC_ID = %x, My WWN = %x %x, ", fi->g.my_id, fi->g.my_node_name_high, fi->g.my_node_name_low);
-	if (fi->g.ptp_up == TRUE)
-		printk("Port_Type = N_Port\n");
-	if (fi->g.loop_up == TRUE)
-		printk("Port_Type = L_Port\n");
-	while(q != NULL) {
-		printk("WWN = ");
-		for (j = 0; j < PORT_NAME_LEN; j++)
-			printk("%x ", q->hw_addr[j]); 
-		printk("FC_ID = %x, ", q->d_id);
-		printk("Login = ");
-		if (q->login == LOGIN_COMPLETED)
-			printk("ON ");
-		else
-			printk("OFF ");
-		if (q->scsi == TARGET)
-			printk("Target_ID = %d ", q->target_id);
-		printk("\n");
-		q = q->next;
-		count++;
-	}
-
-#if DEBUG_5526_2
-	printk("OX_ID -> ELS Map\n");
-	while(temp_ox_id_list) {
-			printk("ox_id = %x, ELS = %x\n", temp_ox_id_list->ox_id, temp_ox_id_list->els);
-			temp_ox_id_list = temp_ox_id_list->next;
-	}
-#endif
-
-	return 0;
-}
-
-static struct net_device_stats * iph5526_get_stats(struct net_device *dev)
-{	
-struct fc_info *fi = dev->priv;
-	return (struct net_device_stats *) &fi->fc_stats;
-}
-
-
-/* SCSI stuff starts here */
-
-int iph5526_detect(Scsi_Host_Template *tmpt)
-{
-	struct Scsi_Host *host = NULL;
-	struct iph5526_hostdata *hostdata;
-	struct fc_info *fi = NULL;
-	int no_of_hosts = 0, i, j, count = 0;
-	u_int pci_maddr = 0;
-	struct pci_dev *pdev = NULL;
-	unsigned long timeout;
-
-	tmpt->proc_name = "iph5526";
-
-	for (i = 0; i <= MAX_FC_CARDS; i++) 
-		fc[i] = NULL;
-
-	for (i = 0; clone_list[i].vendor_id != 0; i++)
-	while ((pdev = pci_find_device(clone_list[i].vendor_id, clone_list[i].device_id, pdev))) {
-		unsigned short pci_command;
-		if (pci_enable_device(pdev))
-			continue;
-		if (count < MAX_FC_CARDS) {
-			fc[count] = kmalloc(sizeof(struct fc_info), GFP_ATOMIC);
-			if (fc[count] == NULL) {
-				printk("iph5526.c: Unable to register card # %d\n", count + 1);
-				return no_of_hosts;
-			}
-			memset(fc[count], 0, sizeof(struct fc_info));
-		}
-		else {
-			printk("iph5526.c: Maximum Number of cards reached.\n");
-			return no_of_hosts;
-		}
-			
-		fi = fc[count];
-		sprintf(fi->name, "fc%d", count);
-
-		host = scsi_register(tmpt, sizeof(struct iph5526_hostdata));
-		if(host==NULL) {
-			kfree(fc[count]);
-			return no_of_hosts;
-		}
-			
-		hostdata = (struct iph5526_hostdata *)host->hostdata;
-		memset(hostdata, 0 , sizeof(struct iph5526_hostdata));
-		for (j = 0; j < MAX_SCSI_TARGETS; j++)
-			hostdata->tag_ages[j] = jiffies;
-		hostdata->fi = fi;
-		fi->host = host;
-		//host->max_id = MAX_SCSI_TARGETS;
-		host->max_id = 5;
-		host->this_id = tmpt->this_id;
-
-		pci_maddr = pci_resource_start(pdev, 0);
-		if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
-			printk("iph5526.c : Cannot find proper PCI device base address.\n");
-			scsi_unregister(host);
-			kfree(fc[count]);
-			fc[count] = NULL;
-			continue;
-		}
-		
-		DPRINTK("pci_maddr = %x", pci_maddr);
-		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-			
-		pci_irq_line = pdev->irq;
-		printk("iph5526.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", clone_list[i].name, pci_maddr, pci_irq_line);
-		fi->g.mem_base = ioremap(pci_maddr & PAGE_MASK, 1024);
-		
-		/* We use Memory Mapped IO. The initial space contains the
-		 * PCI Configuration registers followed by the (i) chip
-		 * registers followed by the Tachyon registers.
-		 */
-		/* Thatz where (i)chip maps Tachyon Address Space.
-		 */
-		fi->g.tachyon_base = (u_long)fi->g.mem_base + TACHYON_OFFSET + ( pci_maddr & ~PAGE_MASK );
-		DPRINTK("fi->g.tachyon_base = %x", (u_int)fi->g.tachyon_base);
-		if (fi->g.mem_base == NULL) {
-			printk("iph5526.c : ioremap failed!!!\n");
-			scsi_unregister(host);
-			kfree(fc[count]);
-			fc[count] = NULL;
-			continue;
-		}	
-		DPRINTK("IRQ1 = %d\n", pci_irq_line);
-		printk(version);
-		fi->base_addr = (long) pdev;
-
-		if (pci_irq_line) {
-		int irqval = 0;
-			/* Found it, get IRQ.
-			 */
-			irqval = request_irq(pci_irq_line, &tachyon_interrupt, pci_irq_line ? SA_SHIRQ : 0, fi->name, host);
-			if (irqval) {
-				printk("iph5526.c : Unable to get IRQ %d (irqval = %d).\n", pci_irq_line, irqval);
-				scsi_unregister(host);
-				kfree(fc[count]);
-				fc[count] = NULL;
-				continue;
-			}
-			host->irq = fi->irq = pci_irq_line;
-			pci_irq_line = 0;
-			fi->clone_id = clone_list[i].vendor_id;
-		}
-
-		if (!initialize_register_pointers(fi) || !tachyon_init(fi)) {
-			printk("iph5526.c: TACHYON initialization failed for card # %d!!!\n", count + 1);
-			free_irq(host->irq, host);
-			scsi_unregister(host);
-			if (fi) 
-				clean_up_memory(fi);
-			kfree(fc[count]);
-			fc[count] = NULL;
-			break;
-		}
-		DPRINTK1("Fibre Channel card initialized");
-		/* Wait for the Link to come up and the login process 
-		 * to complete. 
-		 */
-		for(timeout = jiffies + 10*HZ; time_before(jiffies, timeout) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));)
-		{
-			cpu_relax();
-			barrier();
-		}
-		
-		count++;
-		no_of_hosts++;
-	}
-	DPRINTK1("no_of_hosts = %d",no_of_hosts);
-	
-	/* This is to make sure that the ACC to the PRLI comes in 
-	 * for the last ALPA. 
-	 */
-	mdelay(1000); /* Ugly! Let the Gods forgive me */
-
-	DPRINTK1("leaving iph5526_detect\n");
-	return no_of_hosts;
-}
-
-
-int iph5526_biosparam(struct scsi_device *sdev, struct block_device *n,
-		sector_t capacity, int ip[])
-{
-int size = capacity;
-	ip[0] = 64;
-	ip[1] = 32;
-	ip[2] = size >> 11;
-	if (ip[2] > 1024) {
-		ip[0] = 255;
-		ip[1] = 63;
-		ip[2] = size / (ip[0] * ip[1]);
-	}
-	return 0;
-}
-
-int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *))
-{
-int int_required = 0;
-u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_COMMAND;
-u_int type = TYPE_FCP | SEQUENCE_INITIATIVE;
-u_int frame_class = Cmnd->device->id;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-struct Scsi_Host *host = Cmnd->device->host;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata*)host->hostdata;
-struct fc_info *fi = hostdata->fi;
-struct fc_node_info *q;
-u_long flags;
-	ENTER("iph5526_queuecommand");
-
-	spin_lock_irqsave(&fi->fc_lock, flags);
-	Cmnd->scsi_done = done;
-
-	if (Cmnd->device->tagged_supported) {
-		switch(Cmnd->tag) {
-			case SIMPLE_QUEUE_TAG:
-				hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_SIMPLE;
-				break;
-			case HEAD_OF_QUEUE_TAG:
-				hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_HEAD_OF_Q;
-				break;
-			case  ORDERED_QUEUE_TAG:
-				hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_ORDERED;
-				break;
-			default:
-				if ((jiffies - hostdata->tag_ages[Cmnd->device->id]) > (5 * HZ)) {
-					hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_ORDERED;
-					hostdata->tag_ages[Cmnd->device->id] = jiffies;
-				}
-				else
-					hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_SIMPLE;
-				break;
-		}
-	}
-	/*else
-		hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED;
-	*/
-
-	hostdata->cmnd.fcp_addr[3] = 0;
-	hostdata->cmnd.fcp_addr[2] = 0;
-	hostdata->cmnd.fcp_addr[1] = 0;
-	hostdata->cmnd.fcp_addr[0] = htons(Cmnd->device->lun);
-
-	memcpy(&hostdata->cmnd.fcp_cdb, Cmnd->cmnd, Cmnd->cmd_len);
-	hostdata->cmnd.fcp_data_len = htonl(Cmnd->request_bufflen);
-
-	/* Get an used OX_ID. We could have pending commands.
-	 */
-	if (get_scsi_oxid(fi)) {
-		spin_unlock_irqrestore(&fi->fc_lock, flags);
-		return 1;
-	}
-	fi->q.free_scsi_oxid[fi->g.scsi_oxid] = OXID_INUSE;	
-
-	/* Maintain a handler so that we can associate the done() function
-	 * on completion of the SCSI command. 
-	 */
-	hostdata->cmnd_handler[fi->g.scsi_oxid] = Cmnd;
-
-	switch(Cmnd->cmnd[0]) {
-		case WRITE_6:
-		case WRITE_10:
-		case WRITE_12:
-			fi->g.type_of_frame = FC_SCSI_WRITE;
-			hostdata->cmnd.fcp_cntl = htonl(FCP_CNTL_WRITE | hostdata->cmnd.fcp_cntl);
-			break;
-		default:
-			fi->g.type_of_frame = FC_SCSI_READ;
-			hostdata->cmnd.fcp_cntl = htonl(FCP_CNTL_READ | hostdata->cmnd.fcp_cntl);
-	}
-	
-	memcpy(fi->q.ptr_fcp_cmnd[fi->q.fcp_cmnd_indx], &(hostdata->cmnd), sizeof(fcp_cmd));	
-	
-	q = resolve_target(fi, Cmnd->device->id);
-
-	if (q == NULL) {
-	u_int bad_id = fi->g.my_ddaa | 0xFE;
-		/* We transmit to an non-existant AL_PA so that the "done" 
-		 * function can be called while receiving the interrupt 
-		 * due to a Timeout for a bad AL_PA. In a PTP configuration,
-		 * the int_required field is set, since there is no notion
-		 * of AL_PAs. This approach sucks, but works alright!
-		 */
-		if (fi->g.ptp_up == TRUE)
-			int_required = 1;
-		tx_exchange(fi, (char *)(&(hostdata->cmnd)), sizeof(fcp_cmd), r_ctl, type, bad_id, fi->g.my_mtu, int_required, ox_id, FC_SCSI_BAD_TARGET);
-		spin_unlock_irqrestore(&fi->fc_lock, flags);
-		DPRINTK1("Target ID %x not present", Cmnd->target);
-		return 0;
-	}
-	if (q->login == LOGIN_COMPLETED) {
-		if (add_to_sest(fi, Cmnd, q)) {
-			DPRINTK1("add_to_sest() failed.");
-			spin_unlock_irqrestore(&fi->fc_lock, flags);
-			return 0;
-		}
-		tx_exchange(fi, (char *)(fi->q.ptr_fcp_cmnd[fi->q.fcp_cmnd_indx]), sizeof(fcp_cmd), r_ctl, type, q->d_id, q->mtu, int_required, ox_id, frame_class << 16);
-		update_FCP_CMND_indx(fi);
-	}
-	spin_unlock_irqrestore(&fi->fc_lock, flags);
-	/* If q != NULL, then we have a SCSI Target. 
-	 * If q->login != LOGIN_COMPLETED, then that device could be 
-	 * offline temporarily. So we let the command to time-out. 
-	 */
-	LEAVE("iph5526_queuecommand");
-	return 0;
-}
-
-int iph5526_abort(Scsi_Cmnd *Cmnd)
-{
-struct Scsi_Host *host = Cmnd->device->host;
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
-struct fc_info *fi = hostdata->fi;
-struct fc_node_info *q;
-u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_COMMAND;
-u_int type = TYPE_FCP | SEQUENCE_INITIATIVE;
-u_short ox_id = OX_ID_FIRST_SEQUENCE;
-int int_required = 1, i, abort_status = FALSE;
-u_long flags;
-	
-	ENTER("iph5526_abort");
-	
-	spin_lock_irqsave(&fi->fc_lock, flags);
-	
-	q = resolve_target(fi, Cmnd->device->id);
-	if (q == NULL) {
-	u_int bad_id = fi->g.my_ddaa | 0xFE;
-		/* This should not happen as we should always be able to
-		 * resolve a target id. But, jus in case...
-		 * We transmit to an non-existant AL_PA so that the done 
-		 * function can be called while receiving the interrupt 
-		 * for a bad AL_PA. 
-		 */
-		DPRINTK1("Unresolved Target ID!");
-		tx_exchange(fi, (char *)(&(hostdata->cmnd)), sizeof(fcp_cmd), r_ctl, type, bad_id, fi->g.my_mtu, int_required, ox_id, FC_SCSI_BAD_TARGET);
-		DPRINTK1("Target ID %x not present", Cmnd->target);
-		spin_unlock_irqrestore(&fi->fc_lock, flags);
-		return FAILED;
-	}
-
-	/* If q != NULL, then we have a SCSI Target. If 
-	 * q->login != LOGIN_COMPLETED, then that device could 
-	 * be offline temporarily. So we let the command to time-out. 
-	 */
-
-	/* Get the OX_ID for the Command to be aborted.
-	 */
-	for (i = 0; i <= MAX_SCSI_XID; i++) {
-		if (hostdata->cmnd_handler[i] == Cmnd) {
-			hostdata->cmnd_handler[i] = NULL;
-			ox_id = i;
-			break;
-		}
-	}
-	if (i > MAX_SCSI_XID) {
-		T_MSG("Command could not be resolved to OX_ID");
-		spin_unlock_irqrestore(&fi->fc_lock, flags);
-		return FAILED;
-	}
-
-	switch(Cmnd->cmnd[0]) {
-		case WRITE_6:
-		case WRITE_10:
-		case WRITE_12:
-			break;
-		default:
-			ox_id |= SCSI_READ_BIT;
-	}
-	abort_status = abort_exchange(fi, ox_id);
-	
-	if ((q->login == LOGIN_COMPLETED) && (abort_status == TRUE)) {
-		/* Then, transmit an ABTS to the target. The rest 
-		 * is done when the BA_ACC is received for the ABTS.
- 	 	 */
-		tx_abts(fi, q->d_id, ox_id);
-	}
-	else {
-	u_int STE_bit;
-	u_short x_id;
-		/* Invalidate resources for that Exchange.
-		 */
-		x_id = ox_id & MAX_SCSI_XID;
-		STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-		if (STE_bit & SEST_V) {
-			*(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
-			invalidate_SEST_entry(fi, ox_id);
-		}
-	}
-
-	LEAVE("iph5526_abort");
-	spin_unlock_irqrestore(&fi->fc_lock, flags);
-	return SUCCESS;
-}
-
-static int abort_exchange(struct fc_info *fi, u_short ox_id)
-{
-u_short x_id;
-volatile u_int flush_SEST, STE_bit;
-	x_id = ox_id & MAX_SCSI_XID;
-	DPRINTK1("Aborting Exchange %x", ox_id);
-
-	STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-	/* Is the Exchange still active?.
-	 */
-	if (STE_bit & SEST_V) {
-		if (ox_id & SCSI_READ_BIT) {
-			/* If the Exchange to be aborted is Inbound, 
-			 * Flush the SEST Entry from Tachyon's Cache.
-			 */
-			*(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
-			flush_tachyon_cache(fi, ox_id);
-			flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg);
-			while ((flush_SEST & 0x80000000) != 0) 
-				flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg);
-			STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-			while ((STE_bit & 0x80000000) != 0)
-				STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
-			flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg);
-			invalidate_SEST_entry(fi, ox_id);
-		}
-		else {
-		int i;
-		u_int *ptr_edb;
-			/* For In-Order Reassembly, the following is done:
-			 * First, write zero as the buffer length in the EDB. 
-		 	 */
-			ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7)));
-			for (i = 0; i < EDB_LEN; i++)
-				if (fi->q.ptr_edb[i] == ptr_edb)
-					break;
-			if (i < EDB_LEN) 
-				*ptr_edb = *ptr_edb & 0x0000FFFF;
-			else
-				T_MSG("EDB not found while clearing in abort_exchange()");
-		}
-		DPRINTK1("Exchange %x invalidated", ox_id);
-		return TRUE;
-	}
-	else {
-		DPRINTK1("SEST Entry for exchange %x not valid", ox_id);
-		return FALSE;
-	}	
-}
-
-static void flush_tachyon_cache(struct fc_info *fi, u_short ox_id)
-{
-volatile u_int tachyon_status;
-	if (fi->g.loop_up == TRUE) {
-		writel(HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
-		/* Make sure that the Inbound FIFO is empty.
-		 */
-		do {
-			tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-			udelay(200);
-		}while ((tachyon_status & RECEIVE_FIFO_EMPTY) == 0);
-		/* Ok. Go ahead and flushhhhhhhhh!
-		 */
-		writel(0x80000000 | ox_id, fi->t_r.ptr_tach_flush_oxid_reg);
-		writel(EXIT_HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
-		return;
-	}
-	if (fi->g.ptp_up == TRUE) {
-		take_tachyon_offline(fi);
-		/* Make sure that the Inbound FIFO is empty.
-		 */
-		do {
-			tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
-			udelay(200);
-		}while ((tachyon_status & RECEIVE_FIFO_EMPTY) == 0);
-		writel(0x80000000 | ox_id, fi->t_r.ptr_tach_flush_oxid_reg);
-		/* Write the Initialize command to the FM Control reg.
-		 */
-		fi->g.n_port_try = TRUE;
-		DPRINTK1("In abort_exchange, TACHYON initializing as N_Port...\n");
-		writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-	}
-}
-
-static struct fc_node_info *resolve_target(struct fc_info *fi, u_char target)
-{
-struct fc_node_info *temp = fi->node_info_list;
-	while(temp != NULL)
-		if (temp->target_id == target) {
-			if ((temp->scsi == TARGET) && (temp->login == LOGIN_COMPLETED))
-				return temp;
-			else {
-				if (temp->login != LOGIN_COMPLETED) {
-					/* The Target is not currently logged in.
-					 * It could be a Target on the Local Loop or
-					 * on a Remote Loop connected through a switch.
-					 * In either case, we will know whenever the Target
-					 * comes On-Line again. We let the command to 
-					 * time-out so that it gets retried.
-					 */
-					T_MSG("Target %d not logged in.", temp->target_id);
-					tx_logi(fi, ELS_PLOGI, temp->d_id);
-					return temp;
-				}
-				else {
-					if (temp->scsi != TARGET) {
-						/* For some reason, we did not get a response to
-						 * PRLI. Letz try it again...
-						 */
-						DPRINTK1("Node not PRLIied. Txing PRLI...");
-						tx_prli(fi, ELS_PRLI, temp->d_id, OX_ID_FIRST_SEQUENCE);
-					}
-				}
-				return temp;
-			}
-		}
-		else
-			temp = temp->next;
-	return NULL;
-}
-
-static int add_to_sest(struct fc_info *fi, Scsi_Cmnd *Cmnd, struct fc_node_info *ni)
-{
-/* we have at least 1 buffer, the terminator */
-int no_of_sdb_buffers = 1, i; 
-int no_of_edb_buffers = 0; 
-u_int *req_buffer = (u_int *)Cmnd->request_buffer;
-u_int *ptr_sdb = NULL;
-struct scatterlist *sl1, *sl2 = NULL;
-int no_of_sg = 0;
-
-	switch(fi->g.type_of_frame) {
-		case FC_SCSI_READ:
-			fi->g.inb_sest_entry.flags_and_byte_offset = htonl(INB_SEST_VED);
-			fi->g.inb_sest_entry.byte_count = 0;
-			fi->g.inb_sest_entry.no_of_recvd_frames = 0;
-			fi->g.inb_sest_entry.no_of_expected_frames = 0;
-			fi->g.inb_sest_entry.last_fctl = 0;
-
-			if (Cmnd->use_sg) {
-				no_of_sg = Cmnd->use_sg;
-				sl1 = sl2 = (struct scatterlist *)Cmnd->request_buffer;
-				for (i = 0; i < no_of_sg; i++) {
-					no_of_sdb_buffers += sl1->length / SEST_BUFFER_SIZE;
-					if (sl1->length % SEST_BUFFER_SIZE)
-						no_of_sdb_buffers++;
-					sl1++;
-				}
-			}
-			else {
-				no_of_sdb_buffers += Cmnd->request_bufflen / SEST_BUFFER_SIZE;
-				if (Cmnd->request_bufflen % SEST_BUFFER_SIZE)
-					no_of_sdb_buffers++;
-			} /* if !use_sg */
-
-			/* We are working with the premise that at the max we would
-			 * get a scatter-gather buffer containing 63 buffers
-			 * of size 1024 bytes each. Is it a _bad_ assumption?
-			 */
-			if (no_of_sdb_buffers > 512) {
-				T_MSG("Number of SDB buffers needed = %d", no_of_sdb_buffers);
-				T_MSG("Disable Scatter-Gather!!!");
-				return 1;
-			}
-				
-
-			/* Store it in the sdb_table so that we can retrieve that
-			 * free up the memory when the Read Command completes.
-			 */
-			if (get_free_SDB(fi))
-				return 1;
-			ptr_sdb = fi->q.ptr_sdb_slot[fi->q.sdb_indx];
-			fi->q.sdb_slot_status[fi->q.sdb_indx] = SDB_BUSY;
-			fi->g.inb_sest_entry.sdb_address = htonl(virt_to_bus(ptr_sdb));
-
-			if (Cmnd->use_sg) {
-			int count = 0, j;
-				for(i = 0; i < no_of_sg; i++) {
-				char *addr_ptr = sl2->address;
-					count = sl2->length / SEST_BUFFER_SIZE;
-					if (sl2->length % SEST_BUFFER_SIZE)
-						count++;
-					for (j = 0; j < count; j++) {
-						*(ptr_sdb) = htonl(virt_to_bus(addr_ptr));
-						addr_ptr += SEST_BUFFER_SIZE;
-						ptr_sdb++;
-					}
-					count = 0;
-					sl2++;
-				}
-			}
-			else {
-				for (i = 0; i < no_of_sdb_buffers - 1; i++) {
-					*(ptr_sdb) = htonl(virt_to_bus(req_buffer));
-					req_buffer += SEST_BUFFER_SIZE/4;
-					ptr_sdb++;
-				}
-			}
-			*(ptr_sdb) = htonl(0x1); /* Terminator */
-			
-			/* The scratch pad is used to hold the index into the SDB.
-			 */
-			fi->g.inb_sest_entry.scratch_pad = fi->q.sdb_indx;
-			fi->g.inb_sest_entry.expected_ro = 0;
-			fi->g.inb_sest_entry.buffer_index = 0;
-			fi->g.inb_sest_entry.buffer_offset = 0;
-			memcpy(fi->q.ptr_sest[fi->g.scsi_oxid], &fi->g.inb_sest_entry, sizeof(INB_SEST_ENTRY));
-			break;
-		case FC_SCSI_WRITE:
-			fi->g.outb_sest_entry.flags_and_did = htonl(OUTB_SEST_VED | ni->d_id);
-			fi->g.outb_sest_entry.max_frame_len = htons(ni->mtu << 4);
-			fi->g.outb_sest_entry.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | ODB_NO_COMP);
-			fi->g.outb_sest_entry.total_seq_length = INV_SEQ_LEN;
-			fi->g.outb_sest_entry.link = htons(OUTB_SEST_LINK);
-			fi->g.outb_sest_entry.transaction_id = htonl(fi->g.scsi_oxid);
-			fi->g.outb_sest_entry.seq_id = fi->g.seq_id;
-			fi->g.outb_sest_entry.reserved = 0x0;
-			fi->g.outb_sest_entry.header_length = htons(TACHYON_HEADER_LEN);
-		
-			{
-			u_char df_ctl = 0;
-			u_short rx_id = RX_ID_FIRST_SEQUENCE;
-			u_int r_ctl = FC4_DEVICE_DATA | SOLICITED_DATA;
-			u_int type = TYPE_FCP | SEQUENCE_INITIATIVE;
-				/* Multi Frame Sequence ? If yes, set RO bit. 
-				 */
-				if (Cmnd->request_bufflen > ni->mtu)
-					type |= RELATIVE_OFF_PRESENT;
-				build_tachyon_header(fi, fi->g.my_id, r_ctl, ni->d_id, type, fi->g.seq_id, df_ctl, fi->g.scsi_oxid, rx_id, NULL);
-				if (get_free_header(fi) || get_free_EDB(fi))
-					return 1;
-				memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), TACHYON_HEADER_LEN);
-				fi->g.outb_sest_entry.header_address = htonl(virt_to_bus(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx]));
-				update_tachyon_header_indx(fi);
-			}
-
-			if (Cmnd->use_sg) {
-				no_of_sg = Cmnd->use_sg;
-				sl1 = sl2 = (struct scatterlist *)Cmnd->request_buffer;
-				for (i = 0; i < no_of_sg; i++) {
-					no_of_edb_buffers += sl1->length / SEST_BUFFER_SIZE;
-					if (sl1->length % SEST_BUFFER_SIZE)
-						no_of_edb_buffers++;
-					sl1++;
-				}
-			}
-			else {
-				no_of_edb_buffers += Cmnd->request_bufflen / SEST_BUFFER_SIZE;
-				if (Cmnd->request_bufflen % SEST_BUFFER_SIZE)
-					no_of_edb_buffers++;
-			} /* if !use_sg */
-
-
-			/* We need "no_of_edb_buffers" _contiguous_ EDBs 
-			 * that are FREE. Check for that first.
-			 */
-			for (i = 0; i < no_of_edb_buffers; i++) {
-			int j;
-				if ((fi->q.edb_buffer_indx + no_of_edb_buffers) >= EDB_LEN)
-					fi->q.edb_buffer_indx = 0;
-				if (fi->q.free_edb_list[fi->q.edb_buffer_indx + i] != EDB_FREE) {
-					for (j = 0; j < i; j++)
-						update_EDB_indx(fi);
-					if (get_free_EDB(fi))
-						return 1;
-					i = 0;
-				}
-			}
-
-			/* We got enuff FREE EDBs.
-			 */
-			if (Cmnd->use_sg) {
-				fi->g.outb_sest_entry.edb_address = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx]));
-				sl1 = (struct scatterlist *)Cmnd->request_buffer;
-				for(i = 0; i < no_of_sg; i++) {
-				int count = 0, j;
-					count = sl1->length / SEST_BUFFER_SIZE;
-					for (j = 0; j < count; j++) {
-						build_EDB(fi, (char *)sl1->address, 0, SEST_BUFFER_SIZE);
-						memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB));
-						/* Mark this EDB as being in use */
-						fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY;
-						/* We have already made sure that we have enuff
-				 	 	 * free EDBs that are contiguous. So this is 
-						 * safe.
-				 	 	 */
-						update_EDB_indx(fi);
-						sl1->address += SEST_BUFFER_SIZE;
-					}
-					/* Just in case itz not a multiple of 
-					 * SEST_BUFFER_SIZE bytes.
-					 */
-					if (sl1->length % SEST_BUFFER_SIZE) {
-						build_EDB(fi, (char *)sl1->address, 0, sl1->length % SEST_BUFFER_SIZE);
-						memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB));
-						fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY;
-						update_EDB_indx(fi);
-					}
-					sl1++;
-				}
-				/* The last EDB is special. It needs the "end bit" to
-				 * be set.
-				 */
-				*(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) = *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) | ntohs(EDB_END);
-			}
-			else {
-			int count = 0, j;
-				fi->g.outb_sest_entry.edb_address = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx]));
-				count = Cmnd->request_bufflen / SEST_BUFFER_SIZE;
-				for (j = 0; j < count; j++) {
-					build_EDB(fi, (char *)req_buffer, 0, SEST_BUFFER_SIZE);
-					memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB));
-					/* Mark this EDB as being in use */
-					fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY;
-					/* We have already made sure that we have enuff
-			 	 	 * free EDBs that are contiguous. So this is 
-					 * safe.
-			 	 	 */
-					update_EDB_indx(fi);
-					req_buffer += SEST_BUFFER_SIZE;
-				}
-				/* Just in case itz not a multiple of 
-				 * SEST_BUFFER_SIZE bytes.
-				 */
-				if (Cmnd->request_bufflen % SEST_BUFFER_SIZE) {
-					build_EDB(fi, (char *)req_buffer, EDB_END, Cmnd->request_bufflen % SEST_BUFFER_SIZE);
-					memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB));
-					fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY;
-					update_EDB_indx(fi);
-				}
-				else {
-					/* Mark the last EDB as the "end edb".
-					 */
-					*(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) = *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) | htons(EDB_END);
-				}
-			}
-
-			/* Finally we have something to send!.
-			 */
-			memcpy(fi->q.ptr_sest[fi->g.scsi_oxid], &fi->g.outb_sest_entry, sizeof(OUTB_SEST_ENTRY));
-			break;
-		}		
-	return 0;
-}
-
-static void update_FCP_CMND_indx(struct fc_info *fi)
-{
-	fi->q.fcp_cmnd_indx++;
-	if (fi->q.fcp_cmnd_indx == NO_OF_FCP_CMNDS)
-		fi->q.fcp_cmnd_indx = 0;
-}
-
-static int get_scsi_oxid(struct fc_info *fi)
-{
-u_short initial_oxid = fi->g.scsi_oxid;
-	/* Check if the OX_ID is in use.
-	 * We could have an outstanding SCSI command.
-	 */
-	while (fi->q.free_scsi_oxid[fi->g.scsi_oxid] != OXID_AVAILABLE) {
-		update_scsi_oxid(fi);
-		if (fi->g.scsi_oxid == initial_oxid) {
-			T_MSG("No free OX_IDs avaliable")
-			reset_tachyon(fi, SOFTWARE_RESET);
-			return 1;
-		}
-	}
-	return 0;
-}		
-
-static void update_scsi_oxid(struct fc_info *fi)
-{
-	fi->g.scsi_oxid++;
-	if (fi->g.scsi_oxid == (MAX_SCSI_XID + 1))
-		fi->g.scsi_oxid = 0;
-}
-
-static int get_free_SDB(struct fc_info *fi)
-{
-unsigned int initial_indx = fi->q.sdb_indx;
-	/* Check if the SDB is in use.
-	 * We could have an outstanding SCSI Read command.
-	 * We should find a free slot as we can queue a
-	 * maximum of 32 SCSI commands only. 
-	 */
-	while (fi->q.sdb_slot_status[fi->q.sdb_indx] != SDB_FREE) {
-		update_SDB_indx(fi);
-		if (fi->q.sdb_indx == initial_indx) {
-			T_MSG("No free SDB buffers avaliable")
-			reset_tachyon(fi, SOFTWARE_RESET);
-			return 1;
-		}
-	}
-	return 0;
-}		
-
-static void update_SDB_indx(struct fc_info *fi)
-{
-	fi->q.sdb_indx++;
-	if (fi->q.sdb_indx == NO_OF_SDB_ENTRIES)
-		fi->q.sdb_indx = 0;
-}
-
-int iph5526_release(struct Scsi_Host *host)
-{
-struct iph5526_hostdata *hostdata = (struct iph5526_hostdata*)host->hostdata;
-struct fc_info *fi = hostdata->fi;
-	free_irq(host->irq, host);
-	iounmap(fi->g.mem_base);
-	return 0;
-}
-
-const char *iph5526_info(struct Scsi_Host *host)
-{
-static char buf[80];
-	sprintf(buf, "Interphase 5526 Fibre Channel PCI SCSI Adapter using IRQ %d\n", host->irq);
-	return buf;
-}
-
-#define NAMELEN		8	/* # of chars for storing dev->name */
-
-static struct net_device *dev_fc[MAX_FC_CARDS];
-
-static int io;
-static int irq;
-static int bad;	/* 0xbad = bad sig or no reset ack */
-static int scsi_registered;
-
-
-static int __init iph5526_init(void)
-{
-	int i = 0;
-
-	driver_template.module = THIS_MODULE;
-	scsi_register_host(&driver_template);
-	if (driver_template.present)
-		scsi_registered = TRUE; 
-	else {
-		printk("iph5526: SCSI registeration failed!!!\n");
-		scsi_registered = FALSE;
-		scsi_unregister_host(&driver_template);
-	}
-
-	while(fc[i] != NULL) {
-		struct net_device *dev = alloc_fcdev(0);
-		int err;
-
-		if (!dev) {
-			printk("iph5526.c: init_fcdev failed for card #%d\n", i+1);
-			break;
-		}
-		dev->priv = fc[i];
-		iph5526_probe_pci(dev);
-		err = register_netdev(dev);
-		if (err < 0) {
-			free_netdev(dev);
-			printk("iph5526.c: init_fcdev failed for card #%d\n", i+1);
-			break;
-		}
-		dev_fc[i] = dev;
-		i++;
-	}
-	if (i == 0)
-		return -ENODEV;
-
-	return 0;
-}
-
-static void __exit iph5526_exit(void)
-{
-	int i = 0;
-	while(fc[i] != NULL) {
-		struct net_device *dev = fc[i]->dev;
-		void *priv = dev->priv;
-		fc[i]->g.dont_init = TRUE;
-		take_tachyon_offline(fc[i]);
-		unregister_netdev(dev);
-		clean_up_memory(fc[i]);
-		if (dev->priv)
-			kfree(priv);
-		free_netdev(dev);
-		dev = NULL;
-		i++;
-	}
-	if (scsi_registered == TRUE)
-		scsi_unregister_host(&driver_template); 
-}
-
-module_init(iph5526_init);
-module_exit(iph5526_exit);
-
-void clean_up_memory(struct fc_info *fi)
-{
-int i,j;
-	ENTER("clean_up_memory");
-	if (fi->q.ptr_mfsbq_base)
-		free_pages((u_long)bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base))), 5);
-	DPRINTK("after kfree2");
-	for (i = 0; i < SFSBQ_LENGTH; i++)
-		for (j = 0; j < NO_OF_ENTRIES; j++)
-			if (fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES + j])
-				kfree(fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES + j]);
-	DPRINTK("after kfree1");
-	if (fi->q.ptr_ocq_base)
-		free_page((u_long)fi->q.ptr_ocq_base);
-	if (fi->q.ptr_imq_base)
-		free_page((u_long)fi->q.ptr_imq_base);
-	if (fi->q.ptr_mfsbq_base)
-		free_page((u_long)fi->q.ptr_mfsbq_base);
-	if (fi->q.ptr_sfsbq_base)
-		free_page((u_long)fi->q.ptr_sfsbq_base);
-	if (fi->q.ptr_edb_base)
-		free_pages((u_long)fi->q.ptr_edb_base, 5);
-	if (fi->q.ptr_sest_base)
-		free_pages((u_long)fi->q.ptr_sest_base, 5);
-	if (fi->q.ptr_tachyon_header_base)
-		free_page((u_long)fi->q.ptr_tachyon_header_base);
-	if (fi->q.ptr_sdb_base)
-		free_pages((u_long)fi->q.ptr_sdb_base, 5);
-	if (fi->q.ptr_fcp_cmnd_base)
-		free_page((u_long)fi->q.ptr_fcp_cmnd_base);
-	DPRINTK("after free_pages"); 
-	if (fi->q.ptr_host_ocq_cons_indx)
-		kfree(fi->q.ptr_host_ocq_cons_indx);
-	if (fi->q.ptr_host_hpcq_cons_indx)
-		kfree(fi->q.ptr_host_hpcq_cons_indx);
-	if (fi->q.ptr_host_imq_prod_indx)
-		kfree(fi->q.ptr_host_imq_prod_indx);
-	DPRINTK("after kfree3");
-	while (fi->node_info_list) {
-	struct fc_node_info *temp_list = fi->node_info_list;
-		fi->node_info_list = fi->node_info_list->next;
-		kfree(temp_list);
-	}
-	while (fi->ox_id_list) {
-	struct ox_id_els_map *temp = fi->ox_id_list;
-		fi->ox_id_list = fi->ox_id_list->next;
-		kfree(temp);
-	}
-	LEAVE("clean_up_memory");
-}
-
-static int initialize_register_pointers(struct fc_info *fi)
-{
-ENTER("initialize_register_pointers");
-if(fi->g.tachyon_base == 0)
-	return -ENOMEM; 
-	
-fi->i_r.ptr_ichip_hw_control_reg	= ICHIP_HW_CONTROL_REG_OFF + fi->g.tachyon_base;
-fi->i_r.ptr_ichip_hw_status_reg = ICHIP_HW_STATUS_REG_OFF + fi->g.tachyon_base;
-fi->i_r.ptr_ichip_hw_addr_mask_reg = ICHIP_HW_ADDR_MASK_REG_OFF + fi->g.tachyon_base;
-fi->t_r.ptr_ocq_base_reg = OCQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_ocq_len_reg = OCQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_ocq_prod_indx_reg = OCQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_ocq_cons_indx_reg = OCQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_imq_base_reg = IMQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_imq_len_reg = IMQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_imq_cons_indx_reg = IMQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_imq_prod_indx_reg = IMQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_mfsbq_base_reg = MFSBQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_mfsbq_len_reg = MFSBQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_mfsbq_prod_reg = MFSBQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_mfsbq_cons_reg = MFSBQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_mfsbuff_len_reg = MFS_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sfsbq_base_reg = SFSBQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sfsbq_len_reg = SFSBQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sfsbq_prod_reg = SFSBQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sfsbq_cons_reg = SFSBQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sfsbuff_len_reg = SFS_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sest_base_reg = SEST_BASE_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_sest_len_reg = SEST_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_scsibuff_len_reg = SCSI_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_tach_config_reg = TACHYON_CONFIG_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_tach_control_reg = TACHYON_CONTROL_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_tach_status_reg = TACHYON_STATUS_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_tach_flush_oxid_reg = TACHYON_FLUSH_SEST_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_config_reg = FMGR_CONFIG_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_control_reg = FMGR_CONTROL_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_status_reg = FMGR_STATUS_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_tov_reg = FMGR_TIMER_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_wwn_hi_reg = FMGR_WWN_HI_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_wwn_low_reg = FMGR_WWN_LO_REGISTER_OFFSET + fi->g.tachyon_base;
-fi->t_r.ptr_fm_rx_al_pa_reg = FMGR_RCVD_ALPA_REGISTER_OFFSET + fi->g.tachyon_base;
-
-LEAVE("initialize_register_pointers");
-return 1;
-}
-
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c iph5526.c"
- *  version-control: t
- *  kept-new-versions: 5
- * End:
- */
diff --git a/drivers/net/fc/iph5526_ip.h b/drivers/net/fc/iph5526_ip.h
deleted file mode 100644
--- a/drivers/net/fc/iph5526_ip.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef IPH5526_IP_H
-#define IPH5526_IP_H
-
-#define LLC_SNAP_LEN		0x8
-
-/* Offsets into the ARP frame */
-#define ARP_OPCODE_0	(0x6 + LLC_SNAP_LEN)
-#define ARP_OPCODE_1	(0x7 + LLC_SNAP_LEN)
-
-int iph5526_probe(struct net_device *dev);
-static int fcdev_init(struct net_device *dev);
-static int iph5526_open(struct net_device *dev);
-static int iph5526_close(struct net_device *dev);
-static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats * iph5526_get_stats(struct net_device *dev);
-static int iph5526_change_mtu(struct net_device *dev, int mtu);
-
-
-static void rx_net_packet(struct fc_info *fi, u_char *buff_addr, int payload_size);
-static void rx_net_mfs_packet(struct fc_info *fi, struct sk_buff *skb);
-static int tx_ip_packet(struct sk_buff *skb, unsigned long len, struct fc_info *fi);
-static int tx_arp_packet(char *data, unsigned long len, struct fc_info *fi);
-#endif
-
diff --git a/drivers/net/fc/iph5526_novram.c b/drivers/net/fc/iph5526_novram.c
deleted file mode 100644
--- a/drivers/net/fc/iph5526_novram.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/********************************************************************** 
- * Reading the NVRAM on the Interphase 5526 PCI Fibre Channel Card. 
- * All contents in this file : courtesy Interphase Corporation.
- * Special thanks to Kevin Quick, kquick@iphase.com.
- **********************************************************************/
-
-#define FF_MAGIC        0x4646
-#define DB_MAGIC        0x4442
-#define DL_MAGIC        0x444d
-
-
-#define CMD_LEN         9
-
-/***********
- *
- *      Switches and defines for header files.
- *
- *      The following defines are used to turn on and off
- *      various options in the header files. Primarily useful
- *      for debugging.
- *
- ***********/
-
-static const unsigned short novram_default[4] = {
-    FF_MAGIC,
-    DB_MAGIC,
-    DL_MAGIC,
-    0 };
-
-
-/*
- * a list of the commands that can be sent to the NOVRAM
- */
-
-#define NR_EXTEND  0x100
-#define NR_WRITE   0x140
-#define NR_READ    0x180
-#define NR_ERASE   0x1c0
-
-#define EWDS    0x00
-#define WRAL    0x10
-#define ERAL    0x20
-#define EWEN    0x30
-
-/*
- * Defines for the pins on the NOVRAM
- */
-
-#define BIT(x)          (1 << (x))
-
-#define NVDI_B          31
-#define NVDI            BIT(NVDI_B)
-#define NVDO            BIT(9)
-#define NVCE            BIT(30)
-#define NVSK            BIT(29)
-#define NV_MANUAL       BIT(28)
-
-/***********
- *
- *      Include files.
- *
- ***********/
-
-#define KeStallExecutionProcessor(x)    {volatile int d, p;\
-		  for (d=0; d<x; d++) for (p=0; p<10; p++);\
-				     }
-
-
-/***********************
- *
- * This define ands the value and the current config register and puts
- * the result in the config register
- *
- ***********************/
-
-#define CFG_AND(val) { volatile int t; \
-			   t = readl(fi->n_r.ptr_novram_hw_control_reg);   \
-			   t &= (val);                                  \
-			   writel(t, fi->n_r.ptr_novram_hw_control_reg);   \
-		   }
-
-/***********************
- *
- * This define ors the value and the current config register and puts
- * the result in the config register
- *
- ***********************/
-
-#define CFG_OR(val) { volatile int t; \
-			   t = readl(fi->n_r.ptr_novram_hw_control_reg);   \
-			   t |= (val);                                  \
-			   writel(t, fi->n_r.ptr_novram_hw_control_reg);   \
-		   }
-
-/***********************
- *
- * Send a command to the NOVRAM, the command is in cmd.
- *
- * clear CE and SK. Then assert CE.
- * Clock each of the command bits out in the correct order with SK
- * exit with CE still asserted
- *
- ***********************/
-
-#define NVRAM_CMD(cmd) { int i; \
-			 int c = cmd; \
-			 CFG_AND(~(NVCE|NVSK)); \
-			 CFG_OR(NVCE); \
-			 for (i=0; i<CMD_LEN; i++) { \
-			     NVRAM_CLKOUT((c & (1 << (CMD_LEN - 1))) ? 1 : 0);\
-			     c <<= 1; } }
-
-/***********************
- *
- * clear the CE, this must be used after each command is complete
- *
- ***********************/
-
-#define NVRAM_CLR_CE    CFG_AND(~NVCE)
-
-/***********************
- *
- * clock the data bit in bitval out to the NOVRAM.  The bitval must be
- * a 1 or 0, or the clockout operation is undefined
- *
- ***********************/
-
-#define NVRAM_CLKOUT(bitval) {\
-			   CFG_AND(~NVDI); \
-			   CFG_OR((bitval) << NVDI_B); \
-			   KeStallExecutionProcessor(5);\
-			   CFG_OR(NVSK); \
-			   KeStallExecutionProcessor(5);\
-			   CFG_AND( ~NVSK); \
-			   }
-
-/***********************
- *
- * clock the data bit in and return a 1 or 0, depending on the value
- * that was received from the NOVRAM
- *
- ***********************/
-
-#define NVRAM_CLKIN(val)        {\
-		       CFG_OR(NVSK); \
-			   KeStallExecutionProcessor(5);\
-		       CFG_AND(~NVSK); \
-			   KeStallExecutionProcessor(5);\
-		       val = (readl(fi->n_r.ptr_novram_hw_status_reg) & NVDO) ? 1 : 0; \
-		       }
-
-/***********
- *
- *      Function Prototypes
- *
- ***********/
-
-static int iph5526_nr_get(struct fc_info *fi, int addr);
-static void iph5526_nr_do_init(struct fc_info *fi);
-static void iph5526_nr_checksum(struct fc_info *fi);
-
-
-/*******************************************************************
- *
- *      Local routine:  iph5526_nr_do_init
- *      Purpose:        initialize novram server
- *      Description:
- *
- *      iph5526_nr_do_init reads the novram into the temporary holding place.
- *      A checksum is done on the area and the Magic Cookies are checked.
- *      If any of them are bad, the NOVRAM is initialized with the 
- *      default values and a warning message is displayed.
- *
- *******************************************************************/
-
-static void iph5526_nr_do_init(struct fc_info *fi)
-{
-    int i;
-    unsigned short chksum = 0;
-    int bad = 0;
-
-    for (i=0; i<IPH5526_NOVRAM_SIZE; i++) {
-	fi->n_r.data[i] = iph5526_nr_get(fi, i);
-	chksum += fi->n_r.data[i];
-    }
-
-    if (chksum) 
-	bad = 1;
-
-    if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 4] != FF_MAGIC)
-	bad = 1;
-    if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 3] != DB_MAGIC)
-	bad = 1;                 
-	if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 2] != DL_MAGIC)
-	bad = 1;
-
-    if (bad) {
-	for (i=0; i<IPH5526_NOVRAM_SIZE; i++) {
-	    if (i < (IPH5526_NOVRAM_SIZE - 4)) {
-		fi->n_r.data[i] = 0xffff;
-	    } else {
-		fi->n_r.data[i] = novram_default[i - (IPH5526_NOVRAM_SIZE - 4)];
-	    }
-	}
-	iph5526_nr_checksum(fi);
-    }
-}
-
-
-/*******************************************************************
- *
- *      Local routine:  iph5526_nr_get
- *      Purpose:        read a single word of NOVRAM
- *      Description:
- *
- *      read the 16 bits that make up a word addr of the novram.  
- *      The 16 bits of data that are read are returned as the return value
- *
- *******************************************************************/
-
-static int iph5526_nr_get(struct fc_info *fi, int addr)
-{
-    int i;
-    int t;
-    int val = 0;
-
-    CFG_OR(NV_MANUAL);
-
-    /*
-     * read the first bit that was clocked with the falling edge of the
-     * the last command data clock
-     */
-
-    NVRAM_CMD(NR_READ + addr);
-
-    /*
-     * Now read the rest of the bits, the next bit read is D1, then D2,
-     * and so on
-     */
-
-    val = 0;
-    for (i=0; i<16; i++) {
-	NVRAM_CLKIN(t);
-	val <<= 1;
-	val |= t;
-    }
-    NVRAM_CLR_CE;
-
-    CFG_OR(NVDI);
-    CFG_AND(~NV_MANUAL);
-
-    return(val);
-}
-
-
-
-
-/*******************************************************************
- *
- *      Local routine:  iph5526_nr_checksum
- *      Purpose:        calculate novram checksum on fi->n_r.data
- *      Description:
- *
- *      calculate a checksum for the novram on the image that is
- *      currently in fi->n_r.data
- *
- *******************************************************************/
-
-static void iph5526_nr_checksum(struct fc_info *fi)
-{
-    int i;
-    unsigned short chksum = 0;
-
-    for (i=0; i<(IPH5526_NOVRAM_SIZE - 1); i++)
-	chksum += fi->n_r.data[i];
-
-    fi->n_r.data[i] = -chksum;
-}
diff --git a/drivers/net/fc/iph5526_scsi.h b/drivers/net/fc/iph5526_scsi.h
deleted file mode 100644
--- a/drivers/net/fc/iph5526_scsi.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef IPH5526_SCSI_H
-#define IPH5526_SCSI_H
-
-#define IPH5526_CAN_QUEUE	32
-#define IPH5526_SCSI_FC { 						 				\
-        .name                   = "Interphase 5526 Fibre Channel SCSI Adapter",   \
-        .detect                 = iph5526_detect,                  \
-        .release                = iph5526_release,                 \
-        .info                   = iph5526_info,                    \
-        .queuecommand           = iph5526_queuecommand,            \
-	.bios_param		= iph5526_biosparam,               \
-        .can_queue              = IPH5526_CAN_QUEUE,               \
-        .this_id                = -1,                              \
-        .sg_tablesize           = 255,                             \
-        .cmd_per_lun            = 8,                               \
-        .use_clustering         = DISABLE_CLUSTERING,              \
-        .eh_abort_handler       = iph5526_abort,                   \
-        .eh_device_reset_handler = NULL,                            \
-        .eh_bus_reset_handler   = NULL,                            \
-        .eh_host_reset_handler  = NULL,                            \
-}
-
-int iph5526_detect(Scsi_Host_Template *tmpt);
-int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *));
-int iph5526_release(struct Scsi_Host *host);
-int iph5526_abort(Scsi_Cmnd *Cmnd);
-const char *iph5526_info(struct Scsi_Host *host);
-int iph5526_biosparam(struct Scsi_Disk * disk, struct block_device *n, int ip[]);
-
-#endif
-
diff --git a/drivers/net/fc/tach.h b/drivers/net/fc/tach.h
deleted file mode 100644
--- a/drivers/net/fc/tach.h
+++ /dev/null
@@ -1,475 +0,0 @@
-/**********************************************************************
- * Defines for the Tachyon Fibre Channel Controller and the Interphase
- * (i)chip TPI. 
- *********************************************************************/
-
-#ifndef _TACH_H
-#define _TACH_H
-
-#define MY_PAGE_SIZE       4096
-#define REPLICATE          0xFF
-#define MAX_NODES          127
-#define BROADCAST          0xFFFFFF
-#define BROADCAST_ADDR     0xFFFFFFFFFFFF
-#define LOGIN_COMPLETED     2
-#define LOGIN_ATTEMPTED     1
-#define LOGIN_NOT_ATTEMPTED 0
-#define TRUE                1
-#define FALSE               0
-
-#define TACHYON_LIMIT       0x01EF
-#define TACHYON_OFFSET      0x200
-
-/* Offsets to the (i) chip */
-#define ICHIP_HW_CONTROL_REG_OFF    (0x080 - TACHYON_OFFSET)
-#define ICHIP_HW_STATUS_REG_OFF     (0x084 - TACHYON_OFFSET)
-#define ICHIP_HW_ADDR_MASK_REG_OFF  (0x090 - TACHYON_OFFSET)
-
-/* (i)chip Hardware Control Register defines */
-#define ICHIP_HCR_RESET         0x01
-#define ICHIP_HCR_DERESET       0x0
-#define ICHIP_HCR_ENABLE_INTA   0x0000003E 
-#define ICHIP_HCR_ENABLE_INTB   0x003E0000
-#define ICHIP_HCR_IWDATA_FIFO   0x800000
-
-/* (i)chip Hardware Status Register defines */
-#define ICHIP_HSR_INT_LATCH     0x02
-
-/* (i)chip Hardware Address Mask Register defines */
-#define ICHIP_HAMR_BYTE_SWAP_ADDR_TR    0x08
-#define ICHIP_HAMR_BYTE_SWAP_NO_ADDR_TR 0x04
-
-/* NOVRAM defines */
-#define IPH5526_NOVRAM_SIZE 64
-
-
-/* Offsets for the registers that correspond to the 
- * Qs on the Tachyon (As defined in the Tachyon Manual).
- */
-
-/* Outbound Command Queue (OCQ).
- */
-#define OCQ_BASE_REGISTER_OFFSET	0x000  
-#define OCQ_LENGTH_REGISTER_OFFSET	0x004
-#define OCQ_PRODUCER_REGISTER_OFFSET	0x008  
-#define OCQ_CONSUMER_REGISTER_OFFSET	0x00C 
-
-/* Inbound Message Queue (IMQ).
- */
-#define IMQ_BASE_REGISTER_OFFSET	0x080
-#define IMQ_LENGTH_REGISTER_OFFSET	0x084
-#define IMQ_CONSUMER_REGISTER_OFFSET	0x088
-#define IMQ_PRODUCER_REGISTER_OFFSET	0x08C
-
-/* Multiframe Sequence Buffer Queue (MFSBQ)
- */
-#define MFSBQ_BASE_REGISTER_OFFSET	0x0C0
-#define MFSBQ_LENGTH_REGISTER_OFFSET	0x0C4
-#define MFSBQ_PRODUCER_REGISTER_OFFSET	0x0C8
-#define MFSBQ_CONSUMER_REGISTER_OFFSET	0x0CC  
-#define MFS_LENGTH_REGISTER_OFFSET	0x0D0
-
-/* Single Frame Sequence Buffer Queue (SFSBQ)
- */
-#define SFSBQ_BASE_REGISTER_OFFSET	0x100
-#define SFSBQ_LENGTH_REGISTER_OFFSET	0x104
-#define SFSBQ_PRODUCER_REGISTER_OFFSET	0x108
-#define SFSBQ_CONSUMER_REGISTER_OFFSET	0x10C  
-#define SFS_LENGTH_REGISTER_OFFSET	0x110
-
-/* SCSI Exchange State Table (SEST)
- */
-#define SEST_BASE_REGISTER_OFFSET	0x140
-#define SEST_LENGTH_REGISTER_OFFSET	0x144
-#define SCSI_LENGTH_REGISTER_OFFSET	0x148
-
-/*  Length of the various Qs 
- */
-#define NO_OF_ENTRIES		8
-#define OCQ_LENGTH		(MY_PAGE_SIZE/32)
-#define IMQ_LENGTH		(MY_PAGE_SIZE/32)
-#define MFSBQ_LENGTH		8
-#define SFSBQ_LENGTH		8
-#define SEST_LENGTH		MY_PAGE_SIZE
-
-/* Size of the various buffers.
- */
-#define TACH_FRAME_SIZE         2048
-#define MFS_BUFFER_SIZE         TACH_FRAME_SIZE
-#define SFS_BUFFER_SIZE         (TACH_FRAME_SIZE + TACHYON_HEADER_LEN)
-#define SEST_BUFFER_SIZE        512
-#define TACH_HEADER_SIZE        64
-#define NO_OF_TACH_HEADERS      ((MY_PAGE_SIZE)/TACH_HEADER_SIZE)
-
-#define NO_OF_FCP_CMNDS         (MY_PAGE_SIZE/32)
-#define SDB_SIZE                2048
-#define NO_OF_SDB_ENTRIES       ((32*MY_PAGE_SIZE)/SDB_SIZE)
-
-
-/* Offsets to the other Tachyon registers.
- * (As defined in the Tachyon manual)
- */
-#define TACHYON_CONFIG_REGISTER_OFFSET          0x184
-#define TACHYON_CONTROL_REGISTER_OFFSET         0x188
-#define TACHYON_STATUS_REGISTER_OFFSET          0x18C
-#define TACHYON_FLUSH_SEST_REGISTER_OFFSET      0x190
-
-/* Defines for the Tachyon Configuration register.
- */
-#define SCSI_ENABLE             0x40000000     
-#define WRITE_STREAM_SIZE       0x800	/* size = 16 */         
-#define READ_STREAM_SIZE        0x300	/* size = 64 */      
-#define PARITY_EVEN             0x2         
-#define OOO_REASSEMBLY_DISABLE  0x40
-
-/* Defines for the Tachyon Control register.
- */
-#define SOFTWARE_RESET	0x80000000
-#define OCQ_RESET	0x4
-#define ERROR_RELEASE	0x2
-
-/* Defines for the Tachyon Status register.
- */
-#define RECEIVE_FIFO_EMPTY      0x10
-#define OSM_FROZEN              0x1
-#define OCQ_RESET_STATUS        0x20
-#define SCSI_FREEZE_STATUS      0x40
-
-
-/* Offsets to the Frame Manager registers.
- */
-#define FMGR_CONFIG_REGISTER_OFFSET 0x1C0
-#define FMGR_CONTROL_REGISTER_OFFSET 0x1C4
-#define FMGR_STATUS_REGISTER_OFFSET 0x1C8
-#define FMGR_TIMER_REGISTER_OFFSET 0x1CC
-#define FMGR_WWN_HI_REGISTER_OFFSET 0x1E0
-#define FMGR_WWN_LO_REGISTER_OFFSET 0x1E4
-#define FMGR_RCVD_ALPA_REGISTER_OFFSET 0x1E8
-
-/* Defines for the Frame Manager Configuration register.
- */
-#define BB_CREDIT                    0x10000
-#define NPORT                        0x8000 
-#define LOOP_INIT_FABRIC_ADDRESS     0x400  
-#define LOOP_INIT_PREVIOUS_ADDRESS   0x200  
-#define LOOP_INIT_SOFT_ADDRESS       0x80  
-
-/* Defines for the Frame Manager Control register.
- */
-#define HOST_CONTROL                 0x02   
-#define EXIT_HOST_CONTROL            0x03  
-#define OFFLINE                      0x05 
-#define INITIALIZE                   0x06 
-#define CLEAR_LF                     0x07
-
-/* Defines for the Frame Manager Status register.
- */
-#define LOOP_UP                 0x80000000
-#define TRANSMIT_PARITY_ERROR   0x40000000
-#define NON_PARTICIPATING       0x20000000
-#define OUT_OF_SYNC             0x02000000
-#define LOSS_OF_SIGNAL          0x01000000
-#define NOS_OLS_RECEIVED        0x00080000
-#define LOOP_STATE_TIMEOUT      0x00040000
-#define LIPF_RECEIVED           0x00020000
-#define BAD_ALPA                0x00010000
-#define LINK_FAILURE            0x00001000
-#define ELASTIC_STORE_ERROR     0x00000400
-#define LINK_UP                 0x00000200
-#define LINK_DOWN               0x00000100
-#define ARBITRATING             0x00000010
-#define ARB_WON                 0x00000020
-#define OPEN                    0x00000030
-#define OPENED                  0x00000040
-#define TX_CLS                  0x00000050
-#define RX_CLS                  0x00000060
-#define TRANSFER                0x00000070
-#define INITIALIZING            0x00000080
-#define LOOP_FAIL               0x000000D0
-#define OLD_PORT                0x000000F0
-#define PORT_STATE_ACTIVE       0x0000000F
-#define PORT_STATE_OFFLINE      0x00000000
-#define PORT_STATE_LF1          0x00000009
-#define PORT_STATE_LF2          0x0000000A
-
-/* Completion Message Types 
- * (defined in P.177 of the Tachyon manual)
- */
-#define OUTBOUND_COMPLETION             0x000
-#define OUTBOUND_COMPLETION_I           0x100
-#define OUT_HI_PRI_COMPLETION           0x001
-#define OUT_HI_PRI_COMPLETION_I         0x101
-#define INBOUND_MFS_COMPLETION          0x102
-#define INBOUND_OOO_COMPLETION          0x003
-#define INBOUND_SFS_COMPLETION          0x104
-#define INBOUND_C1_TIMEOUT              0x105
-#define INBOUND_UNKNOWN_FRAME_I         0x106
-#define INBOUND_BUSIED_FRAME            0x006
-#define SFS_BUF_WARN                    0x107
-#define MFS_BUF_WARN                    0x108
-#define IMQ_BUF_WARN                    0x109
-#define FRAME_MGR_INTERRUPT             0x10A
-#define READ_STATUS                     0x10B
-#define INBOUND_SCSI_DATA_COMPLETION    0x10C
-#define INBOUND_SCSI_COMMAND            0x10D
-#define BAD_SCSI_FRAME                  0x10E
-#define INB_SCSI_STATUS_COMPLETION      0x10F
-
-/* One of the things that we care about when we receive an
- * Outbound Completion Message (OCM).
- */
-#define OCM_TIMEOUT_OR_BAD_ALPA         0x0800
-
-/* Defines for the Tachyon Header structure.
- */
-#define SOFI3                0x70
-#define SOFN3                0xB0
-#define EOFN                 0x5
-
-/* R_CTL */
-#define FC4_DEVICE_DATA      0
-#define EXTENDED_LINK_DATA   0x20000000
-#define FC4_LINK_DATA        0x30000000
-#define BASIC_LINK_DATA      0x80000000
-#define LINK_CONTROL         0xC0000000
-#define SOLICITED_DATA       0x1000000
-#define UNSOLICITED_CONTROL  0x2000000
-#define SOLICITED_CONTROL    0x3000000
-#define UNSOLICITED_DATA     0x4000000
-#define DATA_DESCRIPTOR      0x5000000
-#define UNSOLICITED_COMMAND  0x6000000
-
-#define RCTL_ELS_UCTL          0x22000000
-#define RCTL_ELS_SCTL          0x23000000
-#define RCTL_BASIC_ABTS        0x81000000
-#define RCTL_BASIC_ACC         0x84000000
-#define RCTL_BASIC_RJT         0x85000000
-
-/* TYPE */
-#define TYPE_BLS               0x00000000
-#define TYPE_ELS               0x01000000
-#define TYPE_FC_SERVICES       0x20000000
-#define TYPE_LLC_SNAP          0x05000000
-#define TYPE_FCP               0x08000000
-
-/* F_CTL */
-#define EXCHANGE_RESPONDER     0x800000
-#define SEQUENCE_RESPONDER     0x400000
-#define FIRST_SEQUENCE         0x200000
-#define LAST_SEQUENCE          0x100000
-#define SEQUENCE_INITIATIVE    0x10000
-#define RELATIVE_OFF_PRESENT   0x8
-#define END_SEQUENCE           0x80000
-
-#define TACHYON_HEADER_LEN     32
-#define NW_HEADER_LEN          16
-/* Defines for the Outbound Descriptor Block (ODB).
- */
-#define ODB_CLASS_3          0xC000
-#define ODB_NO_COMP          0x400
-#define ODB_NO_INT           0x200
-#define ODB_EE_CREDIT        0xF
-
-/* Defines for the Extended Descriptor Block (EDB).
- */
-#define EDB_LEN              ((32*MY_PAGE_SIZE)/8) 
-#define EDB_END              0x8000
-#define EDB_FREE             0
-#define EDB_BUSY             1
-
-/* Command Codes */
-#define ELS_LS_RJT          0x01000000
-#define ELS_ACC             0x02000000
-#define ELS_PLOGI           0x03000000
-#define ELS_FLOGI           0x04000000
-#define ELS_LOGO            0x05000000
-#define ELS_TPRLO           0x24000000
-#define ELS_ADISC           0x52000000
-#define ELS_PDISC           0x50000000
-#define ELS_PRLI            0x20000000 
-#define ELS_PRLO            0x21000000
-#define ELS_SCR             0x62000000
-#define ELS_RSCN            0x61000000
-#define ELS_FARP_REQ        0x54000000
-#define ELS_ABTX            0x06000000
-#define ELS_ADVC            0x0D000000
-#define ELS_ECHO            0x10000000
-#define ELS_ESTC            0x0C000000
-#define ELS_ESTS            0x0B000000
-#define ELS_RCS             0x07000000
-#define ELS_RES             0x08000000
-#define ELS_RLS             0x0F000000
-#define ELS_RRQ             0x12000000
-#define ELS_RSS             0x09000000
-#define ELS_RTV             0x0E000000
-#define ELS_RSI             0x0A000000
-#define ELS_TEST            0x11000000
-#define ELS_RNC             0x53000000
-#define ELS_RVCS            0x41000000
-#define ELS_TPLS            0x23000000
-#define ELS_GAID            0x30000000
-#define ELS_FACT            0x31000000
-#define ELS_FAN             0x60000000
-#define ELS_FDACT           0x32000000
-#define ELS_NACT            0x33000000
-#define ELS_NDACT           0x34000000
-#define ELS_QoSR            0x40000000
-#define ELS_FDISC           0x51000000
-
-#define ELS_NS_PLOGI        0x03FFFFFC 
-
-/* LS_RJT reason codes.
- */
-#define INV_LS_CMND_CODE                0x0001
-#define LOGICAL_ERR                     0x0003
-#define LOGICAL_BUSY                    0x0005
-#define PROTOCOL_ERR                    0x0007
-#define UNABLE_TO_PERFORM               0x0009
-#define CMND_NOT_SUPP                   0x000B
-
-/* LS_RJT explanation codes.
- */
-#define NO_EXPLN                        0x0000
-#define RECV_FIELD_SIZE                 0x0700
-#define CONC_SEQ                        0x0900
-#define REQ_NOT_SUPPORTED               0x2C00
-#define INV_PAYLOAD_LEN                 0x2D00
-
-/* Payload Length defines. 
- */
-#define PLOGI_LEN				116
-
-#define CONCURRENT_SEQUENCES 0x01
-#define RO_INFO_CATEGORY     0xFE
-#define E_D_TOV              0x07D0 /* 2 Secs */
-#define AL_TIME	             0x0010 /* ~15 msec */
-#define TOV_VALUES           (AL_TIME << 16) | E_D_TOV
-#define RT_TOV               0x64   /* 100 msec */
-#define PTP_TOV_VALUES       (RT_TOV << 16) | E_D_TOV
-#define SERVICE_VALID        0x8000
-#define SEQUENCE_DELIVERY	 0x0800
-#define CLASS3_CONCURRENT_SEQUENCE    0x01
-#define CLASS3_OPEN_SEQUENCE          0x01
-
-/* These are retrieved from the NOVRAM.
- */
-#define WORLD_WIDE_NAME_LOW     fi->g.my_port_name_low
-#define WORLD_WIDE_NAME_HIGH    fi->g.my_port_name_high
-#define N_PORT_NAME_HIGH        fi->g.my_port_name_high
-#define N_PORT_NAME_LOW         fi->g.my_port_name_low
-#define NODE_NAME_HIGH          fi->g.my_node_name_high
-#define NODE_NAME_LOW           fi->g.my_node_name_low
-
-#define PORT_NAME_LEN           8
-#define NODE_NAME_LEN           8
-
-
-#define PH_VERSION        0x0909
-
-#define LOOP_BB_CREDIT  0x00
-#define PT2PT_BB_CREDIT 0x01
-#define FLOGI_C_F       0x0800 /* Alternate BB_Credit Mgmnt */ 
-#define PLOGI_C_F       0x8800 /* Continuously Increasing + Alternate BB_Credit Management */
-
-/* Fabric defines */
-#define DIRECTORY_SERVER        0xFFFFFC
-#define FABRIC_CONTROLLER       0xFFFFFD
-#define F_PORT                  0xFFFFFE
-
-#define FLOGI_DID				0xFFFE
-#define NS_PLOGI_DID			0xFFFC
-
-/* Fibre Channel Services defines */
-#define FCS_RFC_4           0x02170000
-#define FCS_GP_ID4          0x01A10000
-#define FCS_ACC             0x8002
-#define FCS_REJECT          0x8001
-
-/* CT Header defines */
-#define FC_CT_REV               0x01000000
-#define DIRECTORY_SERVER_APP    0xFC
-#define NAME_SERVICE            0x02
-
-/* Port Type defines */
-#define PORT_TYPE_IP            0x05000000
-#define PORT_TYPE_NX_PORTS      0x7F000000
-
-/* SCR defines */
-#define FABRIC_DETECTED_REG		0x00000001
-#define N_PORT_DETECTED_REG		0x00000002
-#define FULL_REGISTRATION		0x00000003
-#define CLEAR_REGISTRATION		0x000000FF
-
-/* Command structure has only one byte to address targets 
- */
-#define MAX_SCSI_TARGETS		0xFF 
-
-#define FC_SCSI_READ                    0x80
-#define FC_SCSI_WRITE                   0x81
-#define FC_ELS                          0x01
-#define FC_BLS                          0x00
-#define FC_IP                           0x05
-#define FC_BROADCAST                    0xFF
-
-/* SEST defines.
- */
-#define SEST_V                          0x80000000 /* V = 1 */
-#define INB_SEST_VED                    0xA0000000 /* V = 1, D = 1 */
-#define SEST_INV                        0x7FFFFFFF 
-#define OUTB_SEST_VED                   0x80000000 /* V = 1 */
-#define INV_SEQ_LEN                     0xFFFFFFFF
-#define OUTB_SEST_LINK                  0xFFFF
-
-/* PRLI defines. 
- */
-#define PAGE_LEN                0x100000 /* 3rd byte - 0x10 */
-#define PRLI_LEN                0x0014 /* 20 bytes */
-#define FCP_TYPE_CODE           0x0800 /* FCP-SCSI */
-#define IMAGE_PAIR              0x2000 /* establish image pair */
-#define INITIATOR_FUNC          0x00000020
-#define TARGET_FUNC             0x00000010
-#define READ_XFER_RDY_DISABLED  0x00000002
-
-#define NODE_PROCESS_LOGGED_IN  0x3
-#define NODE_NOT_PRESENT        0x2
-#define NODE_LOGGED_IN          0x1
-#define NODE_LOGGED_OUT         0x0
-
-/* Defines to determine what should be returned when a SCSI frame
- * times out.
- */
-#define FC_SCSI_BAD_TARGET		0xFFFE0000
-
-/* RSCN Address formats */
-#define PORT_ADDRESS_FORMAT             0x00
-#define AREA_ADDRESS_FORMAT             0x01
-#define DOMAIN_ADDRESS_FORMAT           0x02
-
-/* Defines used to determine whether a frame transmission should
- * be indicated by an interrupt or not.
- */
-#define NO_COMP_AND_INT			0
-#define INT_AND_COMP_REQ		1
-#define NO_INT_COMP_REQ			2
-
-/* Other junk...
- */
-#define SDB_FREE             0
-#define SDB_BUSY             1
-#define MAX_PENDING_FRAMES   15
-#define RX_ID_FIRST_SEQUENCE 0xFFFF
-#define OX_ID_FIRST_SEQUENCE 0xFFFF
-#define NOT_SCSI_XID            0x8000
-#define MAX_SCSI_XID            0x0FFF /* X_IDs are from 0-4095 */
-#define SCSI_READ_BIT           0x4000 
-#define MAX_SCSI_OXID           0x4FFF
-#define OXID_AVAILABLE          0
-#define OXID_INUSE              1
-#define MAX_SEQ_ID              0xFF
-
-#define INITIATOR             2
-#define TARGET                1
-#define DELETE_ENTRY          1
-#define ADD_ENTRY             2
-
-#endif /* _TACH_H */
diff --git a/drivers/net/fc/tach_structs.h b/drivers/net/fc/tach_structs.h
deleted file mode 100644
--- a/drivers/net/fc/tach_structs.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/**********************************************************************
- * iph5526.c: Structures for the Interphase 5526 PCI Fibre Channel 
- *			  IP/SCSI driver.
- * Copyright (C) 1999 Vineet M Abraham <vmabraham@hotmail.com>
- **********************************************************************/
-
-#ifndef _TACH_STRUCT_H
-#define _TACH_STRUCT_H
-
-typedef struct {
-	u_short cmnd_code;
-	u_short payload_length;
-	u_short type_code;
-	u_short est_image_pair;
-	u_int originator_pa;
-	u_int responder_pa;
-	u_int service_params;
-} PRLI;
-
-typedef struct {
-	u_int flags_and_byte_offset;
-	u_int byte_count;
-	u_short no_of_recvd_frames;
-	u_short no_of_expected_frames;
-	u_int last_fctl;
-	u_int sdb_address;
-	u_int scratch_pad;
-	u_int expected_ro;
-	u_short buffer_index;
-	u_short buffer_offset;
-	} INB_SEST_ENTRY;
-
-typedef struct {
-	u_int flags_and_did;
-	u_short max_frame_len;
-	u_short cntl;
-	u_int total_seq_length;
-	u_short link;
-	u_short rx_id;
-	u_int transaction_id;
-	u_int header_address;
-	u_char seq_id;
-	u_char reserved;
-	u_short header_length;
-	u_int edb_address;
-	} OUTB_SEST_ENTRY;
-
-typedef struct {
-	u_short d_naa;
-	u_short dest_high;
-	u_int dest_low;
-	u_short s_naa;
-	u_short source_high;
-	u_int source_low;
-	} NW_HEADER;
-
-typedef struct {
-	u_int resv;
-	u_char sof_and_eof;
-	u_char dest_alpa;
-	u_short lcr_and_time_stamp;
-	u_int r_ctl_and_d_id;
-	u_int vc_id_and_s_id;
-	u_int type_and_f_cntl;
-	u_char seq_id;
-	u_char df_cntl;
-	u_short seq_cnt;
-	u_short ox_id;
-	u_short rx_id;
-	u_int ro;
-	NW_HEADER nw_header;
-	} TACHYON_HEADER;
-
-typedef struct {
-	u_short service_options;
-	u_short initiator_ctl;
-	u_short recipient_ctl;
-	u_short recv_data_field_size;
-	u_short concurrent_sequences;
-	u_short n_port_end_to_end_credit;
-	u_short open_seq_per_exchange;
-	u_short resv;
-	}CLASS_OF_SERVICE;
-
-typedef struct {
-	u_int logo_cmnd;
-	u_char reserved;
-	u_char n_port_id_2;
-	u_char n_port_id_1;
-	u_char n_port_id_0;
-	u_int port_name_up;
-	u_int port_name_low;
-	} LOGO;
-
-typedef struct {
-	u_int ls_cmnd_code;
-	u_int hard_address;
-	u_int port_name_high;
-	u_int port_name_low;
-	u_int node_name_high;
-	u_int node_name_low;
-	u_int n_port_id;
-	} ADISC;
-	
-typedef struct {
-	u_int cmnd_code;
-	u_int reason_code;
-	} LS_RJT;
-
-typedef struct {
-	u_int cmnd_code;
-	} ACC;
-
-typedef struct  {
-	u_int seq_d_id;
-	u_int tot_len;
-	u_short cntl;
-	u_short rx_id;
-	u_short cs_enable;
-	u_short cs_seed;
-	u_int trans_id;
-	u_int hdr_addr;
-	u_short frame_len;
-	u_short hdr_len;
-	u_int edb_addr;
-	}ODB;
-
-typedef struct {
-	u_int cmnd_code;
-	u_int reg_function; /* in the last byte */
-	} SCR;
-
-typedef struct {
-	u_int rev_in_id;
-	u_char fs_type;
-	u_char fs_subtype;
-	u_char options;
-	u_char resv1;
-	u_short cmnd_resp_code;
-	u_short max_res_size;
-	u_char resv2;
-	u_char reason_code;
-	u_char expln_code;
-	u_char vendor_unique;
-	} CT_HDR;
-
-typedef struct {
-	CT_HDR	 ct_hdr;
-	u_int s_id;
-	u_char bit_map[32]; /* 32 byte bit map */
-	} RFC_4;
-
-typedef struct {
-	u_int ls_cmnd_code;
-	u_short fc_ph_version;
-	u_short buff_to_buff_credit;
-	u_short common_features;
-	u_short recv_data_field_size;
-	u_short n_port_total_conc_seq;
-	u_short rel_off_by_info_cat;
-	u_int ED_TOV;
-	u_int n_port_name_high;
-	u_int n_port_name_low;
-	u_int node_name_high;
-	u_int node_name_low;
-	CLASS_OF_SERVICE c_of_s[3];
-	u_int resv[4];
-	u_int vendor_version_level[4];
-	}LOGIN;
-
-typedef struct {
-	CT_HDR	 ct_hdr;
-	u_int port_type; /* in the first byte */
-	} GP_ID4;
-
-typedef struct  {
-	u_int   buf_addr;
-	u_short ehf;
-	u_short buf_len;
-	}EDB;
-
-/* (i)chip Registers */
-struct i_chip_regs {
-	u_int	ptr_ichip_hw_control_reg;
-	u_int	ptr_ichip_hw_status_reg;
-	u_int	ptr_ichip_hw_addr_mask_reg;
-};
-
-struct iph5526_novram {
-	u_int	ptr_novram_hw_control_reg;
-	u_int	ptr_novram_hw_status_reg;
-	u_short data[IPH5526_NOVRAM_SIZE];
-};
-
-/* Tachyon Registers */
-struct tachyon_regs {
-	u_int    ptr_ocq_base_reg;
-	u_int    ptr_ocq_len_reg;
-	u_int    ptr_ocq_prod_indx_reg;
-	u_int    ptr_ocq_cons_indx_reg;
-
-	u_int    ptr_imq_base_reg;
-	u_int    ptr_imq_len_reg;
-	u_int    ptr_imq_cons_indx_reg;
-	u_int    ptr_imq_prod_indx_reg;
-
-	u_int    ptr_mfsbq_base_reg;
-	u_int    ptr_mfsbq_len_reg;
-	u_int    ptr_mfsbq_prod_reg;
-	u_int    ptr_mfsbq_cons_reg;
-	u_int    ptr_mfsbuff_len_reg;
-
-	u_int    ptr_sfsbq_base_reg;
-	u_int    ptr_sfsbq_len_reg;
-	u_int    ptr_sfsbq_prod_reg;
-	u_int    ptr_sfsbq_cons_reg;
-	u_int    ptr_sfsbuff_len_reg;
-
-	u_int    ptr_sest_base_reg;
-	u_int    ptr_sest_len_reg;
-	u_int    ptr_scsibuff_len_reg;
-
-	u_int    ptr_tach_config_reg;
-	u_int    ptr_tach_control_reg;
-	u_int    ptr_tach_status_reg;
-	u_int    ptr_tach_flush_oxid_reg;
-
-	u_int    ptr_fm_config_reg;
-	u_int    ptr_fm_control_reg;
-	u_int    ptr_fm_status_reg;
-	u_int    ptr_fm_tov_reg;
-	u_int    ptr_fm_wwn_hi_reg;
-	u_int    ptr_fm_wwn_low_reg;
-	u_int    ptr_fm_rx_al_pa_reg;
-};
-
-struct globals {
-	u_long tachyon_base;
-	u_int *mem_base;
-	u_short ox_id; /* OX_ID used for IP and ELS frames */
-	u_short scsi_oxid; /* OX_ID for SEST entry */
-	u_char seq_id;
-	u_int my_id;
-	u_int my_ddaa; /* my domain and area in a fabric */
-	volatile u_char loop_up;
-	volatile u_char ptp_up; /* we have a point-to-point link */
-	volatile u_char link_up;
-	volatile u_char n_port_try;
-	volatile u_char nport_timer_set;
-	volatile u_char lport_timer_set;
-	/* Hmmm... We don't want to Initialize while closing */
-	u_char dont_init; 
-	u_int my_node_name_high;
-	u_int my_node_name_low;
-	u_int my_port_name_high;
-	u_int my_port_name_low;
-	u_char fabric_present;
-	u_char explore_fabric;
-	u_char name_server;  
-	u_int my_mtu;
-	u_int *els_buffer[MAX_PENDING_FRAMES]; /* temp space for ELS frames */
-	char *arp_buffer; /* temp space for ARP frames */
-	u_int mfs_buffer_count; /* keep track of MFS buffers used*/
-	u_char scsi_registered;
-	/* variables for port discovery */
-	volatile u_char port_discovery;
-	volatile u_char perform_adisc;
-	u_short alpa_list_index;
-	u_short type_of_frame; /* Could be IP/SCSI Read/SCSI Write*/	
-	u_char no_of_targets; /* used to assign target_ids */
-	u_long sem; /* to synchronize between IP and SCSI */
-	u_char e_i;
-
-	/* the frames */
-	TACHYON_HEADER tach_header;
-	LOGIN login;
-	PRLI prli;
-	LOGO logo;
-	ADISC adisc;
-	LS_RJT ls_rjt;
-	ODB	odb;
-	INB_SEST_ENTRY inb_sest_entry;
-	OUTB_SEST_ENTRY outb_sest_entry;
-	ACC	acc;
-	SCR	scr;
-	EDB	edb;
-	RFC_4 rfc_4;
-	GP_ID4 gp_id4;
-};
-
-struct queue_variables {
-	/* Indices maintained in host memory.
-	 */
-	u_int *host_ocq_cons_indx, *host_hpcq_cons_indx, *host_imq_prod_indx;
-	u_int *ptr_host_ocq_cons_indx, *ptr_host_hpcq_cons_indx, *ptr_host_imq_prod_indx;
-
-	/* Variables for Outbound Command Queue (OCQ).
-	 */
-	u_int *ptr_ocq_base;
-	u_int ocq_len, ocq_end;
-	u_int ocq_prod_indx;
-	u_int *ptr_odb[OCQ_LENGTH];
-
-	/* Variables for Inbound Message Queue (IMQ).
-	 */
-	u_int *ptr_imq_base;
-	u_int imq_len, imq_end;
-	u_int imq_cons_indx;
-	u_int imq_prod_indx;
-	u_int *ptr_imqe[IMQ_LENGTH];
-
-	u_int *ptr_mfsbq_base;
-	u_int mfsbq_len, mfsbq_end;
-	u_int mfsbq_prod_indx;
-	u_int mfsbq_cons_indx;
-	u_int mfsbuff_len, mfsbuff_end;
-
-	u_int *ptr_sfsbq_base;
-	u_int sfsbq_len, sfsbq_end;
-	u_int sfsbq_prod_indx;
-	u_int sfsbq_cons_indx;
-	u_int sfsbuff_len, sfsbuff_end;
-	u_int *ptr_sfs_buffers[SFSBQ_LENGTH * NO_OF_ENTRIES];
-
-	/* Tables for SCSI Transactions */
-	u_int *ptr_sest_base;
-	u_int *ptr_sest[SEST_LENGTH];
-	u_char free_scsi_oxid[SEST_LENGTH];
-	u_int *ptr_sdb_base;
-	u_int *ptr_sdb_slot[NO_OF_SDB_ENTRIES];
-	u_char sdb_slot_status[NO_OF_SDB_ENTRIES];
-	u_int sdb_indx;
-	u_int *ptr_fcp_cmnd_base;
-	u_int *ptr_fcp_cmnd[NO_OF_FCP_CMNDS];
-	u_int fcp_cmnd_indx;
-
-	/* Table for data to be transmitted.
-	 */
-	u_int *ptr_edb_base;
-	u_int *ptr_edb[EDB_LEN];
-	u_int edb_buffer_indx;
-	volatile u_char free_edb_list[EDB_LEN];
-
-	/* Table of Tachyon Headers.
-	 */
-	u_int *ptr_tachyon_header[NO_OF_TACH_HEADERS];
-	u_int *ptr_tachyon_header_base;
-	u_int tachyon_header_indx;
-};
-
-/* Used to match incoming ACCs to ELS requests sent out */
-struct ox_id_els_map {
-	u_short ox_id;
-	u_int els;
-	struct ox_id_els_map *next;
-};
-
-
-/* Carries info about individual nodes... stores the info got at login 
- * time. Also maintains mapping between MAC->FC addresses 
- */
-struct fc_node_info {
-	/* Itz the WWN (8 bytes), the last 6 bytes is the MAC address */
-	u_char hw_addr[PORT_NAME_LEN]; 
-	u_char node_name[NODE_NAME_LEN]; 
-	u_int d_id;  /*real FC address, 3 bytes */
-	int mtu;
-	/* login = 1 if login attempted
-	 * login = 2 if login completed 
-	 */
-	int login;    
-	u_char scsi; /*  = 1 if device is a SCSI Target */
-	u_char target_id;
-	CLASS_OF_SERVICE c_of_s[3];
-	struct fc_node_info *next;
-};
-
-struct fc_info {
-	char name[8];
-	u_long base_addr;
-	int irq;
-	struct net_device_stats fc_stats;
-	struct fc_node_info *node_info_list;
-	int num_nodes;
-	struct ox_id_els_map *ox_id_list;
-	struct i_chip_regs i_r;
-	struct tachyon_regs t_r;
-	struct queue_variables q;
-	struct globals g;
-	struct iph5526_novram n_r;
-	u_short clone_id;
-	struct timer_list nport_timer;
-	struct timer_list lport_timer;
-	struct timer_list explore_timer;
-	struct timer_list display_cache_timer;
-	struct net_device *dev;
-	struct Scsi_Host *host;
-	spinlock_t fc_lock;
-};
-
-struct iph5526_hostdata {
-	struct fc_info *fi;
-	fcp_cmd cmnd;
-	Scsi_Cmnd *cmnd_handler[SEST_LENGTH];
-	u_int tag_ages[MAX_SCSI_TARGETS];
-};
-
-/* List of valid AL_PAs */
-u_char alpa_list[127] = { 
-	0x00, 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 
-	0x18, 0x1B, 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 
-	0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 
-	0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A, 0x3C, 
-	0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 
-	0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 
-	0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 0x69, 
-	0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, 
-	0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 
-	0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 
-	0x9D, 0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 
-	0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 
-	0xB4, 0xB5, 0xB6, 0xB9, 0xBA, 0xBC, 0xC3, 0xC5, 
-	0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 
-	0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, 0xDA, 
-	0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
-};
-
-#endif /* _TACH_STRUCT_H */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -102,21 +102,6 @@ KERN_INFO DRV_NAME ".c:v" DRV_VERSION " 
 #define USE_IO_OPS
 #endif
 
-#ifdef USE_IO_OPS
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb inb
-#define readw inw
-#define readl inl
-#define writeb outb
-#define writew outw
-#define writel outl
-#endif
-
 /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. */
 /* This is only in the support-all-kernels source code. */
 
@@ -444,6 +429,7 @@ struct netdev_private {
 	int mii_cnt;		/* MII device addresses. */
 	unsigned char phys[2];	/* MII device addresses. */
 	struct mii_if_info mii;
+	void __iomem *mem;
 };
 
 
@@ -468,23 +454,23 @@ static int netdev_close(struct net_devic
 static void reset_rx_descriptors(struct net_device *dev);
 static void reset_tx_descriptors(struct net_device *dev);
 
-static void stop_nic_rx(long ioaddr, long crvalue)
+static void stop_nic_rx(void __iomem *ioaddr, long crvalue)
 {
 	int delay = 0x1000;
-	writel(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR);
+	iowrite32(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR);
 	while (--delay) {
-		if ( (readl(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP)
+		if ( (ioread32(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP)
 			break;
 	}
 }
 
 
-static void stop_nic_rxtx(long ioaddr, long crvalue)
+static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue)
 {
 	int delay = 0x1000;
-	writel(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR);
+	iowrite32(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR);
 	while (--delay) {
-		if ( (readl(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP))
+		if ( (ioread32(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP))
 					    == (CR_R_RXSTOP+CR_R_TXSTOP) )
 			break;
 	}
@@ -498,11 +484,17 @@ static int __devinit fealnx_init_one(str
 	int i, option, err, irq;
 	static int card_idx = -1;
 	char boardname[12];
-	long ioaddr;
+	void __iomem *ioaddr;
+	unsigned long len;
 	unsigned int chip_id = ent->driver_data;
 	struct net_device *dev;
 	void *ring_space;
 	dma_addr_t ring_dma;
+#ifdef USE_IO_OPS
+	int bar = 0;
+#else
+	int bar = 1;
+#endif
 	
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -520,14 +512,10 @@ static int __devinit fealnx_init_one(str
 	if (i) return i;
 	pci_set_master(pdev);
 	
-#ifdef USE_IO_OPS
-	ioaddr = pci_resource_len(pdev, 0);
-#else
-	ioaddr = pci_resource_len(pdev, 1);
-#endif
-	if (ioaddr < MIN_REGION_SIZE) {
+	len = pci_resource_len(pdev, bar);
+	if (len < MIN_REGION_SIZE) {
 		printk(KERN_ERR "%s: region size %ld too small, aborting\n",
-		       boardname, ioaddr);
+		       boardname, len);
 		return -ENODEV;
 	}
 
@@ -536,17 +524,12 @@ static int __devinit fealnx_init_one(str
 	
 	irq = pdev->irq;
 
-#ifdef USE_IO_OPS
-	ioaddr = pci_resource_start(pdev, 0);
-#else
-	ioaddr = (long) ioremap(pci_resource_start(pdev, 1),
-				pci_resource_len(pdev, 1));
+	ioaddr = pci_iomap(pdev, bar, len);
 	if (!ioaddr) {
 		err = -ENOMEM;
 		goto err_out_res;
 	}
-#endif
-	
+
 	dev = alloc_etherdev(sizeof(struct netdev_private));
 	if (!dev) {
 		err = -ENOMEM;
@@ -557,16 +540,17 @@ static int __devinit fealnx_init_one(str
 
 	/* read ethernet id */
 	for (i = 0; i < 6; ++i)
-		dev->dev_addr[i] = readb(ioaddr + PAR0 + i);
+		dev->dev_addr[i] = ioread8(ioaddr + PAR0 + i);
 
 	/* Reset the chip to erase previous misconfiguration. */
-	writel(0x00000001, ioaddr + BCR);
+	iowrite32(0x00000001, ioaddr + BCR);
 
-	dev->base_addr = ioaddr;
+	dev->base_addr = (unsigned long)ioaddr;
 	dev->irq = irq;
 
 	/* Make certain the descriptor lists are aligned. */
-	np = dev->priv;
+	np = netdev_priv(dev);
+	np->mem = ioaddr;
 	spin_lock_init(&np->lock);
 	np->pci_dev = pdev;
 	np->flags = skel_netdrv_tbl[chip_id].flags;
@@ -635,7 +619,7 @@ static int __devinit fealnx_init_one(str
 		np->phys[0] = 32;
 /* 89/6/23 add, (begin) */
 		/* get phy type */
-		if (readl(ioaddr + PHYIDENTIFIER) == MysonPHYID)
+		if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID)
 			np->PHYType = MysonPHY;
 		else
 			np->PHYType = OtherPHY;
@@ -670,7 +654,7 @@ static int __devinit fealnx_init_one(str
 		if (np->flags == HAS_MII_XCVR)
 			mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		else
-			writel(ADVERTISE_FULL, ioaddr + ANARANLPAR);
+			iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR);
 		np->mii.force_media = 1;
 	}
 
@@ -689,7 +673,7 @@ static int __devinit fealnx_init_one(str
 	if (err)
 		goto err_out_free_tx;
 
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
+	printk(KERN_INFO "%s: %s at %p, ",
 	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", dev->dev_addr[i]);
@@ -704,10 +688,8 @@ err_out_free_rx:
 err_out_free_dev:
 	free_netdev(dev);
 err_out_unmap:
-#ifndef USE_IO_OPS
-	iounmap((void *)ioaddr);
+	pci_iounmap(pdev, ioaddr);
 err_out_res:
-#endif
 	pci_release_regions(pdev);
 	return err;
 }
@@ -718,16 +700,14 @@ static void __devexit fealnx_remove_one(
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct netdev_private *np = dev->priv;
+		struct netdev_private *np = netdev_priv(dev);
 
 		pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
 			np->tx_ring_dma);
 		pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
 			np->rx_ring_dma);
 		unregister_netdev(dev);
-#ifndef USE_IO_OPS
-		iounmap((void *)dev->base_addr);
-#endif
+		pci_iounmap(pdev, np->mem);
 		free_netdev(dev);
 		pci_release_regions(pdev);
 		pci_set_drvdata(pdev, NULL);
@@ -736,14 +716,14 @@ static void __devexit fealnx_remove_one(
 }
 
 
-static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
+static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad)
 {
 	ulong miir;
 	int i;
 	unsigned int mask, data;
 
 	/* enable MII output */
-	miir = (ulong) readl(miiport);
+	miir = (ulong) ioread32(miiport);
 	miir &= 0xfffffff0;
 
 	miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
@@ -752,11 +732,11 @@ static ulong m80x_send_cmd_to_phy(long m
 	for (i = 0; i < 32; i++) {
 		/* low MDC; MDO is already high (miir) */
 		miir &= ~MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 
 		/* high MDC */
 		miir |= MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 	}
 
 	/* calculate ST+OP+PHYAD+REGAD+TA */
@@ -770,10 +750,10 @@ static ulong m80x_send_cmd_to_phy(long m
 		if (mask & data)
 			miir |= MASK_MIIR_MII_MDO;
 
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 		/* high MDC */
 		miir |= MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 		udelay(30);
 
 		/* next */
@@ -787,7 +767,8 @@ static ulong m80x_send_cmd_to_phy(long m
 
 static int mdio_read(struct net_device *dev, int phyad, int regad)
 {
-	long miiport = dev->base_addr + MANAGEMENT;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *miiport = np->mem + MANAGEMENT;
 	ulong miir;
 	unsigned int mask, data;
 
@@ -799,16 +780,16 @@ static int mdio_read(struct net_device *
 	while (mask) {
 		/* low MDC */
 		miir &= ~MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 
 		/* read MDI */
-		miir = readl(miiport);
+		miir = ioread32(miiport);
 		if (miir & MASK_MIIR_MII_MDI)
 			data |= mask;
 
 		/* high MDC, and wait */
 		miir |= MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 		udelay(30);
 
 		/* next */
@@ -817,7 +798,7 @@ static int mdio_read(struct net_device *
 
 	/* low MDC */
 	miir &= ~MASK_MIIR_MII_MDC;
-	writel(miir, miiport);
+	iowrite32(miir, miiport);
 
 	return data & 0xffff;
 }
@@ -825,7 +806,8 @@ static int mdio_read(struct net_device *
 
 static void mdio_write(struct net_device *dev, int phyad, int regad, int data)
 {
-	long miiport = dev->base_addr + MANAGEMENT;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *miiport = np->mem + MANAGEMENT;
 	ulong miir;
 	unsigned int mask;
 
@@ -838,11 +820,11 @@ static void mdio_write(struct net_device
 		miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
 		if (mask & data)
 			miir |= MASK_MIIR_MII_MDO;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 
 		/* high MDC */
 		miir |= MASK_MIIR_MII_MDC;
-		writel(miir, miiport);
+		iowrite32(miir, miiport);
 
 		/* next */
 		mask >>= 1;
@@ -850,29 +832,29 @@ static void mdio_write(struct net_device
 
 	/* low MDC */
 	miir &= ~MASK_MIIR_MII_MDC;
-	writel(miir, miiport);
+	iowrite32(miir, miiport);
 }
 
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	int i;
 
-	writel(0x00000001, ioaddr + BCR);	/* Reset */
+	iowrite32(0x00000001, ioaddr + BCR);	/* Reset */
 
 	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
 
 	for (i = 0; i < 3; i++)
-		writew(((unsigned short*)dev->dev_addr)[i],
+		iowrite16(((unsigned short*)dev->dev_addr)[i],
 				ioaddr + PAR0 + i*2);
 
 	init_ring(dev);
 
-	writel(np->rx_ring_dma, ioaddr + RXLBA);
-	writel(np->tx_ring_dma, ioaddr + TXLBA);
+	iowrite32(np->rx_ring_dma, ioaddr + RXLBA);
+	iowrite32(np->tx_ring_dma, ioaddr + TXLBA);
 
 	/* Initialize other registers. */
 	/* Configure the PCI bus bursts and FIFO thresholds.
@@ -933,12 +915,12 @@ static int netdev_open(struct net_device
 		np->crvalue |= CR_W_ENH;	/* set enhanced bit */
 		np->imrvalue |= ETI;
 	}
-	writel(np->bcrvalue, ioaddr + BCR);
+	iowrite32(np->bcrvalue, ioaddr + BCR);
 
 	if (dev->if_port == 0)
 		dev->if_port = np->default_port;
 
-	writel(0, ioaddr + RXPDR);
+	iowrite32(0, ioaddr + RXPDR);
 // 89/9/1 modify,
 //   np->crvalue = 0x00e40001;    /* tx store and forward, tx/rx enable */
 	np->crvalue |= 0x00e40001;	/* tx store and forward, tx/rx enable */
@@ -951,8 +933,8 @@ static int netdev_open(struct net_device
 	netif_start_queue(dev);
 
 	/* Clear and Enable interrupts by setting the interrupt mask. */
-	writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
-	writel(np->imrvalue, ioaddr + IMR);
+	iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
+	iowrite32(np->imrvalue, ioaddr + IMR);
 
 	if (debug)
 		printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
@@ -980,14 +962,14 @@ static void getlinkstatus(struct net_dev
 /* input   : dev... pointer to the adapter block.                            */
 /* output  : none.                                                           */
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned int i, DelayTime = 0x1000;
 
 	np->linkok = 0;
 
 	if (np->PHYType == MysonPHY) {
 		for (i = 0; i < DelayTime; ++i) {
-			if (readl(dev->base_addr + BMCRSR) & LinkIsUp2) {
+			if (ioread32(np->mem + BMCRSR) & LinkIsUp2) {
 				np->linkok = 1;
 				return;
 			}
@@ -1007,14 +989,14 @@ static void getlinkstatus(struct net_dev
 
 static void getlinktype(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	if (np->PHYType == MysonPHY) {	/* 3-in-1 case */
-		if (readl(dev->base_addr + TCRRCR) & CR_R_FD)
+		if (ioread32(np->mem + TCRRCR) & CR_R_FD)
 			np->duplexmode = 2;	/* full duplex */
 		else
 			np->duplexmode = 1;	/* half duplex */
-		if (readl(dev->base_addr + TCRRCR) & CR_R_PS10)
+		if (ioread32(np->mem + TCRRCR) & CR_R_PS10)
 			np->line_speed = 1;	/* 10M */
 		else
 			np->line_speed = 2;	/* 100M */
@@ -1110,7 +1092,7 @@ static void getlinktype(struct net_devic
 /* Take lock before calling this */
 static void allocate_rx_buffers(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	/*  allocate skb for rx buffers */
 	while (np->really_rx_count != RX_RING_SIZE) {
@@ -1136,16 +1118,16 @@ static void allocate_rx_buffers(struct n
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	int old_crvalue = np->crvalue;
 	unsigned int old_linkok = np->linkok;
 	unsigned long flags;
 
 	if (debug)
 		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
-		       "config %8.8x.\n", dev->name, readl(ioaddr + ISR),
-		       readl(ioaddr + TCRRCR));
+		       "config %8.8x.\n", dev->name, ioread32(ioaddr + ISR),
+		       ioread32(ioaddr + TCRRCR));
 
 	spin_lock_irqsave(&np->lock, flags);
 
@@ -1155,7 +1137,7 @@ static void netdev_timer(unsigned long d
 			getlinktype(dev);
 			if (np->crvalue != old_crvalue) {
 				stop_nic_rxtx(ioaddr, np->crvalue);
-				writel(np->crvalue, ioaddr + TCRRCR);
+				iowrite32(np->crvalue, ioaddr + TCRRCR);
 			}
 		}
 	}
@@ -1173,22 +1155,23 @@ static void netdev_timer(unsigned long d
 /* Reset chip and disable rx, tx and interrupts */
 static void reset_and_disable_rxtx(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	int delay=51;
 
 	/* Reset the chip's Tx and Rx processes. */
 	stop_nic_rxtx(ioaddr, 0);
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	writel(0, ioaddr + IMR);
+	iowrite32(0, ioaddr + IMR);
 
 	/* Reset the chip to erase previous misconfiguration. */
-	writel(0x00000001, ioaddr + BCR);
+	iowrite32(0x00000001, ioaddr + BCR);
 
 	/* Ueimor: wait for 50 PCI cycles (and flush posted writes btw). 
 	   We surely wait too long (address+data phase). Who cares? */
 	while (--delay) {
-		readl(ioaddr + BCR);
+		ioread32(ioaddr + BCR);
 		rmb();
 	}
 }
@@ -1198,33 +1181,33 @@ static void reset_and_disable_rxtx(struc
 /* Restore chip after reset */
 static void enable_rxtx(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 
 	reset_rx_descriptors(dev);
 
-	writel(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring),
+	iowrite32(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring),
 		ioaddr + TXLBA);
-	writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
+	iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
 		ioaddr + RXLBA);
 
-	writel(np->bcrvalue, ioaddr + BCR);
+	iowrite32(np->bcrvalue, ioaddr + BCR);
 
-	writel(0, ioaddr + RXPDR);
+	iowrite32(0, ioaddr + RXPDR);
 	__set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */
 
 	/* Clear and Enable interrupts by setting the interrupt mask. */
-	writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
-	writel(np->imrvalue, ioaddr + IMR);
+	iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
+	iowrite32(np->imrvalue, ioaddr + IMR);
 
-	writel(0, ioaddr + TXPDR);
+	iowrite32(0, ioaddr + TXPDR);
 }
 
 
 static void reset_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned long flags;
 
 	printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name);
@@ -1247,13 +1230,13 @@ static void reset_timer(unsigned long da
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	unsigned long flags;
 	int i;
 
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-	       " resetting...\n", dev->name, readl(ioaddr + ISR));
+	       " resetting...\n", dev->name, ioread32(ioaddr + ISR));
 
 	{
 		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
@@ -1282,7 +1265,7 @@ static void tx_timeout(struct net_device
 /* 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;
+	struct netdev_private *np = netdev_priv(dev);
 	int i;
 
 	/* initialize rx variables */
@@ -1346,7 +1329,7 @@ static void init_ring(struct net_device 
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&np->lock, flags);
@@ -1413,7 +1396,7 @@ static int start_tx(struct sk_buff *skb,
 	if (np->free_tx_count < 2)
 		netif_stop_queue(dev);
 	++np->really_tx_count;
-	writel(0, dev->base_addr + TXPDR);
+	iowrite32(0, np->mem + TXPDR);
 	dev->trans_start = jiffies;
 
 	spin_unlock_irqrestore(&np->lock, flags);
@@ -1425,7 +1408,7 @@ static int start_tx(struct sk_buff *skb,
 /* Chip probably hosed tx ring. Clean up. */
 static void reset_tx_descriptors(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct fealnx_desc *cur;
 	int i;
 
@@ -1460,7 +1443,7 @@ static void reset_tx_descriptors(struct 
 /* Take lock and stop rx before calling this */
 static void reset_rx_descriptors(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct fealnx_desc *cur = np->cur_rx;
 	int i;
 
@@ -1472,8 +1455,8 @@ static void reset_rx_descriptors(struct 
 		cur = cur->next_desc_logical;
 	}
 
-	writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
-		dev->base_addr + RXLBA);
+	iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
+		np->mem + RXLBA);
 }
 
 
@@ -1482,21 +1465,21 @@ static void reset_rx_descriptors(struct 
 static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	long boguscnt = max_interrupt_work;
 	unsigned int num_tx = 0;
 	int handled = 0;
 
 	spin_lock(&np->lock);
 
-	writel(0, ioaddr + IMR);
+	iowrite32(0, ioaddr + IMR);
 
 	do {
-		u32 intr_status = readl(ioaddr + ISR);
+		u32 intr_status = ioread32(ioaddr + ISR);
 
 		/* Acknowledge all of the current interrupt sources ASAP. */
-		writel(intr_status, ioaddr + ISR);
+		iowrite32(intr_status, ioaddr + ISR);
 
 		if (debug)
 			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name,
@@ -1517,15 +1500,15 @@ static irqreturn_t intr_handler(int irq,
 //      };
 
 		if (intr_status & TUNF)
-			writel(0, ioaddr + TXPDR);
+			iowrite32(0, ioaddr + TXPDR);
 
 		if (intr_status & CNTOVF) {
 			/* missed pkts */
-			np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff;
+			np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
 
 			/* crc error */
 			np->stats.rx_crc_errors +=
-			    (readl(ioaddr + TALLY) & 0x7fff0000) >> 16;
+			    (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 		}
 
 		if (intr_status & (RI | RBU)) {
@@ -1534,7 +1517,7 @@ static irqreturn_t intr_handler(int irq,
 			else {
 				stop_nic_rx(ioaddr, np->crvalue);
 				reset_rx_descriptors(dev);
-				writel(np->crvalue, ioaddr + TCRRCR);
+				iowrite32(np->crvalue, ioaddr + TCRRCR);
 			}				
 		}
 
@@ -1605,7 +1588,7 @@ static irqreturn_t intr_handler(int irq,
 		if (np->crvalue & CR_W_ENH) {
 			long data;
 
-			data = readl(ioaddr + TSR);
+			data = ioread32(ioaddr + TSR);
 			np->stats.tx_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_aborted_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_window_errors += (data & 0x00ff0000) >> 16;
@@ -1635,16 +1618,16 @@ static irqreturn_t intr_handler(int irq,
 
 	/* read the tally counters */
 	/* missed pkts */
-	np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff;
+	np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
 
 	/* crc error */
-	np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16;
+	np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 
 	if (debug)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-		       dev->name, readl(ioaddr + ISR));
+		       dev->name, ioread32(ioaddr + ISR));
 
-	writel(np->imrvalue, ioaddr + IMR);
+	iowrite32(np->imrvalue, ioaddr + IMR);
 
 	spin_unlock(&np->lock);
 
@@ -1656,8 +1639,8 @@ static irqreturn_t intr_handler(int irq,
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
 	while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) {
@@ -1725,7 +1708,7 @@ static int netdev_rx(struct net_device *
 				} else {        /* rx error, need to reset this chip */
 					stop_nic_rx(ioaddr, np->crvalue);
 					reset_rx_descriptors(dev);
-					writel(np->crvalue, ioaddr + TCRRCR);
+					iowrite32(np->crvalue, ioaddr + TCRRCR);
 				}
 				break;	/* exit the while loop */
 			}
@@ -1793,13 +1776,13 @@ static int netdev_rx(struct net_device *
 
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 
 	/* The chip only need report frame silently dropped. */
 	if (netif_running(dev)) {
-		np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff;
-		np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16;
+		np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
+		np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 	}
 
 	return &np->stats;
@@ -1809,7 +1792,7 @@ static struct net_device_stats *get_stat
 /* for dev->set_multicast_list */
 static void set_rx_mode(struct net_device *dev)
 {
-	spinlock_t *lp = &((struct netdev_private *)dev->priv)->lock;
+	spinlock_t *lp = &((struct netdev_private *)netdev_priv(dev))->lock;
 	unsigned long flags;
 	spin_lock_irqsave(lp, flags);
 	__set_rx_mode(dev);
@@ -1820,8 +1803,8 @@ static void set_rx_mode(struct net_devic
 /* Take lock before calling */
 static void __set_rx_mode(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	u32 rx_mode;
 
@@ -1851,16 +1834,16 @@ static void __set_rx_mode(struct net_dev
 
 	stop_nic_rxtx(ioaddr, np->crvalue);
 
-	writel(mc_filter[0], ioaddr + MAR0);
-	writel(mc_filter[1], ioaddr + MAR1);
+	iowrite32(mc_filter[0], ioaddr + MAR0);
+	iowrite32(mc_filter[1], ioaddr + MAR1);
 	np->crvalue &= ~CR_W_RXMODEMASK;
 	np->crvalue |= rx_mode;
-	writel(np->crvalue, ioaddr + TCRRCR);
+	iowrite32(np->crvalue, ioaddr + TCRRCR);
 }
 
 static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -1869,7 +1852,7 @@ static void netdev_get_drvinfo(struct ne
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&np->lock);
@@ -1881,7 +1864,7 @@ static int netdev_get_settings(struct ne
 
 static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&np->lock);
@@ -1893,13 +1876,13 @@ static int netdev_set_settings(struct ne
 
 static int netdev_nway_reset(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	return mii_nway_restart(&np->mii);
 }
 
 static u32 netdev_get_link(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	return mii_link_ok(&np->mii);
 }
 
@@ -1927,7 +1910,7 @@ static struct ethtool_ops netdev_ethtool
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int rc;
 
 	if (!netif_running(dev))
@@ -1943,14 +1926,14 @@ static int mii_ioctl(struct net_device *
 
 static int netdev_close(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->mem;
 	int i;
 
 	netif_stop_queue(dev);
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	writel(0x0000, ioaddr + IMR);
+	iowrite32(0x0000, ioaddr + IMR);
 
 	/* Stop the chip's Tx and Rx processes. */
 	stop_nic_rxtx(ioaddr, 0);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -81,6 +81,7 @@
  *			   cause DMA to kfree'd memory.
  *	0.31: 14 Nov 2004: ethtool support for getting/setting link
  *	                   capabilities.
+ *	0.32: 16 Apr 2005: RX_ERROR4 handling added.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -92,7 +93,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.31"
+#define FORCEDETH_VERSION		"0.32"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -109,6 +110,7 @@
 #include <linux/mii.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/if_vlan.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -1013,6 +1015,59 @@ static void nv_tx_timeout(struct net_dev
 	spin_unlock_irq(&np->lock);
 }
 
+/*
+ * Called when the nic notices a mismatch between the actual data len on the
+ * wire and the len indicated in the 802 header
+ */
+static int nv_getlen(struct net_device *dev, void *packet, int datalen)
+{
+	int hdrlen;	/* length of the 802 header */
+	int protolen;	/* length as stored in the proto field */
+
+	/* 1) calculate len according to header */
+	if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+		protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+		hdrlen = VLAN_HLEN;
+	} else {
+		protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
+		hdrlen = ETH_HLEN;
+	}
+	dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
+				dev->name, datalen, protolen, hdrlen);
+	if (protolen > ETH_DATA_LEN)
+		return datalen; /* Value in proto field not a len, no checks possible */
+
+	protolen += hdrlen;
+	/* consistency checks: */
+	if (datalen > ETH_ZLEN) {
+		if (datalen >= protolen) {
+			/* more data on wire than in 802 header, trim of
+			 * additional data.
+			 */
+			dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+					dev->name, protolen);
+			return protolen;
+		} else {
+			/* less data on wire than mentioned in header.
+			 * Discard the packet.
+			 */
+			dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
+					dev->name);
+			return -1;
+		}
+	} else {
+		/* short packet. Accept only if 802 values are also short */
+		if (protolen > ETH_ZLEN) {
+			dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
+					dev->name);
+			return -1;
+		}
+		dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+				dev->name, datalen);
+		return datalen;
+	}
+}
+
 static void nv_rx_process(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
@@ -1064,7 +1119,7 @@ static void nv_rx_process(struct net_dev
 				np->stats.rx_errors++;
 				goto next_pkt;
 			}
-			if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
+			if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
 				np->stats.rx_errors++;
 				goto next_pkt;
 			}
@@ -1078,22 +1133,24 @@ static void nv_rx_process(struct net_dev
 				np->stats.rx_errors++;
 				goto next_pkt;
 			}
-			if (Flags & NV_RX_ERROR) {
-				/* framing errors are soft errors, the rest is fatal. */
-				if (Flags & NV_RX_FRAMINGERR) {
-					if (Flags & NV_RX_SUBSTRACT1) {
-						len--;
-					}
-				} else {
+			if (Flags & NV_RX_ERROR4) {
+				len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+				if (len < 0) {
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
 			}
+			/* framing errors are soft errors. */
+			if (Flags & NV_RX_FRAMINGERR) {
+				if (Flags & NV_RX_SUBSTRACT1) {
+					len--;
+				}
+			}
 		} else {
 			if (!(Flags & NV_RX2_DESCRIPTORVALID))
 				goto next_pkt;
 
-			if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
+			if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
 				np->stats.rx_errors++;
 				goto next_pkt;
 			}
@@ -1107,17 +1164,19 @@ static void nv_rx_process(struct net_dev
 				np->stats.rx_errors++;
 				goto next_pkt;
 			}
-			if (Flags & NV_RX2_ERROR) {
-				/* framing errors are soft errors, the rest is fatal. */
-				if (Flags & NV_RX2_FRAMINGERR) {
-					if (Flags & NV_RX2_SUBSTRACT1) {
-						len--;
-					}
-				} else {
+			if (Flags & NV_RX2_ERROR4) {
+				len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+				if (len < 0) {
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
 			}
+			/* framing errors are soft errors */
+			if (Flags & NV_RX2_FRAMINGERR) {
+				if (Flags & NV_RX2_SUBSTRACT1) {
+					len--;
+				}
+			}
 			Flags &= NV_RX2_CHECKSUMMASK;
 			if (Flags == NV_RX2_CHECKSUMOK1 ||
 					Flags == NV_RX2_CHECKSUMOK2 ||
@@ -1480,6 +1539,13 @@ static void nv_do_nic_poll(unsigned long
 	enable_irq(dev->irq);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void nv_poll_controller(struct net_device *dev)
+{
+	nv_do_nic_poll((unsigned long) dev);
+}
+#endif
+
 static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct fe_priv *np = get_nvpriv(dev);
@@ -1962,6 +2028,9 @@ static int __devinit nv_probe(struct pci
 	dev->get_stats = nv_get_stats;
 	dev->change_mtu = nv_change_mtu;
 	dev->set_multicast_list = nv_set_multicast;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = nv_poll_controller;
+#endif
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->tx_timeout = nv_tx_timeout;
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -377,6 +377,8 @@ static int init_phy(struct net_device *d
 			ADVERTISED_1000baseT_Full);
 	mii_info->autoneg = 1;
 
+	spin_lock_init(&mii_info->mdio_lock);
+
 	mii_info->mii_id = priv->einfo->phyid;
 
 	mii_info->dev = dev;
diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
--- a/drivers/net/gt96100eth.h
+++ b/drivers/net/gt96100eth.h
@@ -214,7 +214,7 @@ typedef struct {
 	u32 cmdstat;
 	u32 next;
 	u32 buff_ptr;
-} gt96100_td_t __attribute__ ((packed));
+} __attribute__ ((packed)) gt96100_td_t;
 
 typedef struct {
 #ifdef DESC_BE
@@ -227,7 +227,7 @@ typedef struct {
 	u32 cmdstat;
 	u32 next;
 	u32 buff_ptr;
-} gt96100_rd_t __attribute__ ((packed));
+} __attribute__ ((packed)) gt96100_rd_t;
 
 
 /* Values for the Tx command-status descriptor entry. */
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -394,13 +394,11 @@ static void sp_bump(struct sixpack *sp, 
 	if ((skb = dev_alloc_skb(count)) == NULL)
 		goto out_mem;
 
-	skb->dev = sp->dev;
 	ptr = skb_put(skb, count);
 	*ptr++ = cmd;	/* KISS command */
 
 	memcpy(ptr, sp->cooked_buf + 1, count);
-	skb->mac.raw = skb->data;
-	skb->protocol = htons(ETH_P_AX25);
+	skb->protocol = ax25_type_trans(skb, sp->dev);
 	netif_rx(skb);
 	sp->dev->last_rx = jiffies;
 	sp->stats.rx_packets++;
@@ -756,12 +754,12 @@ static int sixpack_ioctl(struct tty_stru
 
 	switch(cmd) {
 	case SIOCGIFNAME:
-		err = copy_to_user((void *) arg, dev->name,
+		err = copy_to_user((void __user *) arg, dev->name,
 		                   strlen(dev->name) + 1) ? -EFAULT : 0;
 		break;
 
 	case SIOCGIFENCAP:
-		err = put_user(0, (int __user *)arg);
+		err = put_user(0, (int __user *) arg);
 		break;
 
 	case SIOCSIFENCAP:
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -45,7 +45,7 @@ config BPQETHER
 
 config DMASCC
 	tristate "High-speed (DMA) SCC driver for AX.25"
-	depends on ISA && AX25 && BROKEN_ON_SMP
+	depends on ISA && AX25 && BROKEN_ON_SMP && ISA_DMA_API
 	---help---
 	  This is a driver for high-speed SCC boards, i.e. those supporting
 	  DMA on one port. You usually use those boards to connect your
@@ -78,7 +78,7 @@ config DMASCC
 
 config SCC
 	tristate "Z8530 SCC driver"
-	depends on ISA && AX25
+	depends on ISA && AX25 && ISA_DMA_API
 	---help---
 	  These cards are used to connect your Linux box to an amateur radio
 	  in order to communicate with other computers. If you want to use
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -68,25 +68,7 @@
 /* --------------------------------------------------------------------- */
 
 static const char paranoia_str[] = KERN_ERR 
-"baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n";
-
-#define baycom_paranoia_check(dev,routine,retval)                                              \
-({                                                                                             \
-	if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \
-		printk(paranoia_str, routine);                                                 \
-		return retval;                                                                 \
-	}                                                                                      \
-})
-
-#define baycom_paranoia_check_void(dev,routine)                                                \
-({                                                                                             \
-	if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \
-		printk(paranoia_str, routine);                                                 \
-		return;                                                                        \
-	}                                                                                      \
-})
-
-/* --------------------------------------------------------------------- */
+	"baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n";
 
 static const char bc_drvname[] = "baycom_epp";
 static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
@@ -392,29 +374,6 @@ static inline void do_kiss_params(struct
 }
 
 /* --------------------------------------------------------------------- */
-/*
- * high performance HDLC encoder
- * yes, it's ugly, but generates pretty good code
- */
-
-#define ENCODEITERA(j)                         \
-({                                             \
-        if (!(notbitstream & (0x1f0 << j)))    \
-                goto stuff##j;                 \
-  encodeend##j:    	;                      \
-})
-
-#define ENCODEITERB(j)                                          \
-({                                                              \
-  stuff##j:                                                     \
-        bitstream &= ~(0x100 << j);                             \
-        bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |        \
-                ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);  \
-        numbit++;                                               \
-        notbitstream = ~bitstream;                              \
-        goto encodeend##j;                                      \
-})
-
 
 static void encode_hdlc(struct baycom_state *bc)
 {
@@ -423,6 +382,7 @@ static void encode_hdlc(struct baycom_st
 	int pkt_len;
         unsigned bitstream, notbitstream, bitbuf, numbit, crc;
 	unsigned char crcarr[2];
+	int j;
 	
 	if (bc->hdlctx.bufcnt > 0)
 		return;
@@ -447,24 +407,14 @@ static void encode_hdlc(struct baycom_st
 		pkt_len--;
 		if (!pkt_len)
 			bp = crcarr;
-		ENCODEITERA(0);
-		ENCODEITERA(1);
-		ENCODEITERA(2);
-		ENCODEITERA(3);
-		ENCODEITERA(4);
-		ENCODEITERA(5);
-		ENCODEITERA(6);
-		ENCODEITERA(7);
-		goto enditer;
-		ENCODEITERB(0);
-		ENCODEITERB(1);
-		ENCODEITERB(2);
-		ENCODEITERB(3);
-		ENCODEITERB(4);
-		ENCODEITERB(5);
-		ENCODEITERB(6);
-		ENCODEITERB(7);
-	enditer:
+		for (j = 0; j < 8; j++)
+			if (unlikely(!(notbitstream & (0x1f0 << j)))) {
+				bitstream &= ~(0x100 << j);
+ 				bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
+					((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);
+				numbit++;
+				notbitstream = ~bitstream;
+			}
 		numbit += 8;
 		while (numbit >= 8) {
 			*wp++ = bitbuf;
@@ -619,48 +569,15 @@ static void do_rxpacket(struct net_devic
 		bc->stats.rx_dropped++;
 		return;
 	}
-	skb->dev = dev;
 	cp = skb_put(skb, pktlen);
 	*cp++ = 0; /* KISS kludge */
 	memcpy(cp, bc->hdlcrx.buf, pktlen - 1);
-	skb->protocol = htons(ETH_P_AX25);
-	skb->mac.raw = skb->data;
+	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
 	dev->last_rx = jiffies;
 	bc->stats.rx_packets++;
 }
 
-#define DECODEITERA(j)                                                        \
-({                                                                            \
-        if (!(notbitstream & (0x0fc << j)))              /* flag or abort */  \
-                goto flgabrt##j;                                              \
-        if ((bitstream & (0x1f8 << j)) == (0xf8 << j))   /* stuffed bit */    \
-                goto stuff##j;                                                \
-  enditer##j:      ;                                                           \
-})
-
-#define DECODEITERB(j)                                                                 \
-({                                                                                     \
-  flgabrt##j:                                                                          \
-        if (!(notbitstream & (0x1fc << j))) {              /* abort received */        \
-                state = 0;                                                             \
-                goto enditer##j;                                                       \
-        }                                                                              \
-        if ((bitstream & (0x1fe << j)) != (0x0fc << j))   /* flag received */          \
-                goto enditer##j;                                                       \
-        if (state)                                                                     \
-                do_rxpacket(dev);                                                      \
-        bc->hdlcrx.bufcnt = 0;                                                         \
-        bc->hdlcrx.bufptr = bc->hdlcrx.buf;                                            \
-        state = 1;                                                                     \
-        numbits = 7-j;                                                                 \
-        goto enditer##j;                                                               \
-  stuff##j:                                                                            \
-        numbits--;                                                                     \
-        bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);        \
-        goto enditer##j;                                                               \
-})
-        
 static int receive(struct net_device *dev, int cnt)
 {
 	struct baycom_state *bc = netdev_priv(dev);
@@ -669,6 +586,7 @@ static int receive(struct net_device *de
 	unsigned char tmp[128];
         unsigned char *cp;
 	int cnt2, ret = 0;
+	int j;
         
         numbits = bc->hdlcrx.numbits;
 	state = bc->hdlcrx.state;
@@ -689,24 +607,32 @@ static int receive(struct net_device *de
 			bitbuf |= (*cp) << 8;
 			numbits += 8;
 			notbitstream = ~bitstream;
-			DECODEITERA(0);
-			DECODEITERA(1);
-			DECODEITERA(2);
-			DECODEITERA(3);
-			DECODEITERA(4);
-			DECODEITERA(5);
-			DECODEITERA(6);
-			DECODEITERA(7);
-			goto enddec;
-			DECODEITERB(0);
-			DECODEITERB(1);
-			DECODEITERB(2);
-			DECODEITERB(3);
-			DECODEITERB(4);
-			DECODEITERB(5);
-			DECODEITERB(6);
-			DECODEITERB(7);
-		enddec:
+			for (j = 0; j < 8; j++) {
+
+				/* flag or abort */
+			        if (unlikely(!(notbitstream & (0x0fc << j)))) {
+
+					/* abort received */
+					if (!(notbitstream & (0x1fc << j)))
+						state = 0;
+
+					/* not flag received */
+					else if (!(bitstream & (0x1fe << j)) != (0x0fc << j)) {
+						if (state)
+							do_rxpacket(dev);
+						bc->hdlcrx.bufcnt = 0;
+						bc->hdlcrx.bufptr = bc->hdlcrx.buf;
+						state = 1;
+						numbits = 7-j;
+						}
+					}
+
+				/* stuffed bit */
+				else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) {
+					numbits--;
+					bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);
+					}
+				}
 			while (state && numbits >= 8) {
 				if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
 					state = 0;
@@ -747,7 +673,6 @@ static void epp_bh(struct net_device *de
 	unsigned int time1 = 0, time2 = 0, time3 = 0;
 	int cnt, cnt2;
 	
-	baycom_paranoia_check_void(dev, "epp_bh");
 	bc = netdev_priv(dev);
 	if (!bc->work_running)
 		return;
@@ -863,10 +788,8 @@ static void epp_bh(struct net_device *de
 
 static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct baycom_state *bc;
+	struct baycom_state *bc = netdev_priv(dev);
 
-	baycom_paranoia_check(dev, "baycom_send_packet", 0);
-	bc = netdev_priv(dev);
 	if (skb->data[0] != 0) {
 		do_kiss_params(bc, skb->data, skb->len);
 		dev_kfree_skb(skb);
@@ -899,10 +822,8 @@ static int baycom_set_mac_address(struct
 
 static struct net_device_stats *baycom_get_stats(struct net_device *dev)
 {
-	struct baycom_state *bc;
+	struct baycom_state *bc = netdev_priv(dev);
 
-	baycom_paranoia_check(dev, "baycom_get_stats", NULL);
-	bc = netdev_priv(dev);
 	/* 
 	 * Get the current statistics.  This may be called with the
 	 * card open or closed. 
@@ -915,10 +836,8 @@ static struct net_device_stats *baycom_g
 static void epp_wakeup(void *handle)
 {
         struct net_device *dev = (struct net_device *)handle;
-        struct baycom_state *bc;
+        struct baycom_state *bc = netdev_priv(dev);
 
-	baycom_paranoia_check_void(dev, "epp_wakeup");
-        bc = netdev_priv(dev);
         printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name);
         if (!parport_claim(bc->pdev))
                 printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name);
@@ -937,16 +856,13 @@ static void epp_wakeup(void *handle)
 
 static int epp_open(struct net_device *dev)
 {
-	struct baycom_state *bc;
-        struct parport *pp;
+	struct baycom_state *bc = netdev_priv(dev);
+        struct parport *pp = parport_find_base(dev->base_addr);
 	unsigned int i, j;
 	unsigned char tmp[128];
 	unsigned char stat;
 	unsigned long tstart;
 	
-	baycom_paranoia_check(dev, "epp_open", -ENXIO);
-	bc = netdev_priv(dev);
-        pp = parport_find_base(dev->base_addr);
         if (!pp) {
                 printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr);
                 return -ENXIO;
@@ -1055,13 +971,10 @@ static int epp_open(struct net_device *d
 
 static int epp_close(struct net_device *dev)
 {
-	struct baycom_state *bc;
-	struct parport *pp;
+	struct baycom_state *bc = netdev_priv(dev);
+	struct parport *pp = bc->pdev->port;
 	unsigned char tmp[1];
 
-	baycom_paranoia_check(dev, "epp_close", -EINVAL);
-	bc = netdev_priv(dev);
-	pp = bc->pdev->port;
 	bc->work_running = 0;
 	flush_scheduled_work();
 	bc->stat = EPP_DCDBIT;
@@ -1117,11 +1030,9 @@ static int baycom_setmode(struct baycom_
 
 static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct baycom_state *bc;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct hdlcdrv_ioctl hi;
 
-	baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL);
-	bc = netdev_priv(dev);
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
 
@@ -1354,7 +1265,7 @@ static int __init init_baycomepp(void)
 			free_netdev(dev);
 			break;
 		}
-		if (set_hw && baycom_setmode(dev->priv, mode[i]))
+		if (set_hw && baycom_setmode(netdev_priv(dev), mode[i]))
 			set_hw = 0;
 		baycom_device[i] = dev;
 		found++;
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -85,6 +85,7 @@
 #include <linux/parport.h>
 #include <linux/bitops.h>
 
+#include <asm/bug.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -415,12 +416,11 @@ static int baycom_ioctl(struct net_devic
 	struct baycom_state *bc;
 	struct baycom_ioctl bi;
 
-	if (!dev || !dev->priv ||
-	    ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
-		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
+	if (!dev)
 		return -EINVAL;
-	}
+
 	bc = netdev_priv(dev);
+	BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -530,12 +530,11 @@ static int baycom_ioctl(struct net_devic
 	struct baycom_state *bc;
 	struct baycom_ioctl bi;
 
-	if (!dev || !dev->priv ||
-	    ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
-		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
+	if (!dev)
 		return -EINVAL;
-	}
+
 	bc = netdev_priv(dev);
+	BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -570,12 +570,11 @@ static int baycom_ioctl(struct net_devic
 	struct baycom_state *bc;
 	struct baycom_ioctl bi;
 
-	if (!dev || !dev->priv ||
-	    ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
-		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
+	if (!dev)
 		return -EINVAL;
-	}
+
 	bc = netdev_priv(dev);
+	BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -112,8 +112,6 @@ static struct notifier_block bpq_dev_not
 };
 
 
-#define MAXBPQDEV 100
-
 struct bpqdev {
 	struct list_head bpq_list;	/* list of bpq devices chain */
 	struct net_device *ethdev;	/* link to ethernet device */
@@ -134,7 +132,7 @@ static LIST_HEAD(bpq_devices);
  */
 static inline struct net_device *bpq_get_ether_dev(struct net_device *dev)
 {
-	struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+	struct bpqdev *bpq = netdev_priv(dev);
 
 	return bpq ? bpq->ethdev : NULL;
 }
@@ -191,7 +189,7 @@ static int bpq_rcv(struct sk_buff *skb, 
 	 * we check the source address of the sender.
 	 */
 
-	bpq = (struct bpqdev *)dev->priv;
+	bpq = netdev_priv(dev);
 
 	eth = eth_hdr(skb);
 
@@ -213,11 +211,7 @@ static int bpq_rcv(struct sk_buff *skb, 
 	ptr = skb_push(skb, 1);
 	*ptr = 0;
 
-	skb->dev = dev;
-	skb->protocol = htons(ETH_P_AX25);
-	skb->mac.raw = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
+	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
 	dev->last_rx = jiffies;
 unlock:
@@ -274,14 +268,12 @@ static int bpq_xmit(struct sk_buff *skb,
 		skb = newskb;
 	}
 
-	skb->protocol = htons(ETH_P_AX25);
-
 	ptr = skb_push(skb, 2);
 
 	*ptr++ = (size + 5) % 256;
 	*ptr++ = (size + 5) / 256;
 
-	bpq = (struct bpqdev *)dev->priv;
+	bpq = netdev_priv(dev);
 
 	if ((dev = bpq_get_ether_dev(dev)) == NULL) {
 		bpq->stats.tx_dropped++;
@@ -289,7 +281,7 @@ static int bpq_xmit(struct sk_buff *skb,
 		return -ENODEV;
 	}
 
-	skb->dev = dev;
+	skb->protocol = ax25_type_trans(skb, dev);
 	skb->nh.raw = skb->data;
 	dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
 	bpq->stats.tx_packets++;
@@ -305,7 +297,7 @@ static int bpq_xmit(struct sk_buff *skb,
  */
 static struct net_device_stats *bpq_get_stats(struct net_device *dev)
 {
-	struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+	struct bpqdev *bpq = netdev_priv(dev);
 
 	return &bpq->stats;
 }
@@ -332,15 +324,12 @@ static int bpq_set_mac_address(struct ne
 static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct bpq_ethaddr __user *ethaddr = ifr->ifr_data;
-	struct bpqdev *bpq = dev->priv;
+	struct bpqdev *bpq = netdev_priv(dev);
 	struct bpq_req req;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	if (bpq == NULL)		/* woops! */
-		return -ENODEV;
-
 	switch (cmd) {
 		case SIOCSBPQETHOPT:
 			if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)))
@@ -525,7 +514,7 @@ static int bpq_new_device(struct net_dev
 		return -ENOMEM;
 
 		
-	bpq = ndev->priv;
+	bpq = netdev_priv(ndev);
 	dev_hold(edev);
 	bpq->ethdev = edev;
 	bpq->axdev = ndev;
@@ -554,7 +543,7 @@ static int bpq_new_device(struct net_dev
 
 static void bpq_free_device(struct net_device *ndev)
 {
-	struct bpqdev *bpq = ndev->priv;
+	struct bpqdev *bpq = netdev_priv(ndev);
 
 	dev_put(bpq->ethdev);
 	list_del_rcu(&bpq->bpq_list);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1,6 +1,4 @@
 /*
- * $Id: dmascc.c,v 1.27 2000/06/01 14:46:23 oe1kib Exp $
- *
  * Driver for high-speed SCC boards (those with DMA support)
  * Copyright (C) 1997-2000 Klaus Kudielka
  *
@@ -19,7 +17,6 @@
  * You 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.
- *
  */
 
 
@@ -49,9 +46,9 @@
 
 /* Number of buffers per channel */
 
-#define NUM_TX_BUF      2          /* NUM_TX_BUF >= 1 (min. 2 recommended) */
-#define NUM_RX_BUF      6          /* NUM_RX_BUF >= 1 (min. 2 recommended) */
-#define BUF_SIZE        1576       /* BUF_SIZE >= mtu + hard_header_len */
+#define NUM_TX_BUF      2	/* NUM_TX_BUF >= 1 (min. 2 recommended) */
+#define NUM_RX_BUF      6	/* NUM_RX_BUF >= 1 (min. 2 recommended) */
+#define BUF_SIZE        1576	/* BUF_SIZE >= mtu + hard_header_len */
 
 
 /* Cards supported */
@@ -67,7 +64,7 @@
 
 #define HARDWARE        { HW_PI, HW_PI2, HW_TWIN, HW_S5 }
 
-#define TMR_0_HZ        25600      /* Frequency of timer 0 */
+#define TMR_0_HZ        25600	/* Frequency of timer 0 */
 
 #define TYPE_PI         0
 #define TYPE_PI2        1
@@ -164,69 +161,69 @@
 /* Data types */
 
 struct scc_param {
-  int pclk_hz;    /* frequency of BRG input (don't change) */
-  int brg_tc;     /* BRG terminal count; BRG disabled if < 0 */
-  int nrzi;       /* 0 (nrz), 1 (nrzi) */
-  int clocks;     /* see dmascc_cfg documentation */
-  int txdelay;    /* [1/TMR_0_HZ] */
-  int txtimeout;  /* [1/HZ] */
-  int txtail;     /* [1/TMR_0_HZ] */
-  int waittime;   /* [1/TMR_0_HZ] */
-  int slottime;   /* [1/TMR_0_HZ] */
-  int persist;    /* 1 ... 256 */
-  int dma;        /* -1 (disable), 0, 1, 3 */
-  int txpause;    /* [1/TMR_0_HZ] */
-  int rtsoff;     /* [1/TMR_0_HZ] */
-  int dcdon;      /* [1/TMR_0_HZ] */
-  int dcdoff;     /* [1/TMR_0_HZ] */
+	int pclk_hz;		/* frequency of BRG input (don't change) */
+	int brg_tc;		/* BRG terminal count; BRG disabled if < 0 */
+	int nrzi;		/* 0 (nrz), 1 (nrzi) */
+	int clocks;		/* see dmascc_cfg documentation */
+	int txdelay;		/* [1/TMR_0_HZ] */
+	int txtimeout;		/* [1/HZ] */
+	int txtail;		/* [1/TMR_0_HZ] */
+	int waittime;		/* [1/TMR_0_HZ] */
+	int slottime;		/* [1/TMR_0_HZ] */
+	int persist;		/* 1 ... 256 */
+	int dma;		/* -1 (disable), 0, 1, 3 */
+	int txpause;		/* [1/TMR_0_HZ] */
+	int rtsoff;		/* [1/TMR_0_HZ] */
+	int dcdon;		/* [1/TMR_0_HZ] */
+	int dcdoff;		/* [1/TMR_0_HZ] */
 };
 
 struct scc_hardware {
-  char *name;
-  int io_region;
-  int io_delta;
-  int io_size;
-  int num_devs;
-  int scc_offset;
-  int tmr_offset;
-  int tmr_hz;
-  int pclk_hz;
+	char *name;
+	int io_region;
+	int io_delta;
+	int io_size;
+	int num_devs;
+	int scc_offset;
+	int tmr_offset;
+	int tmr_hz;
+	int pclk_hz;
 };
 
 struct scc_priv {
-  int type;
-  int chip;
-  struct net_device *dev;
-  struct scc_info *info;
-  struct net_device_stats stats;
-  int channel;
-  int card_base, scc_cmd, scc_data;
-  int tmr_cnt, tmr_ctrl, tmr_mode;
-  struct scc_param param;
-  char rx_buf[NUM_RX_BUF][BUF_SIZE];
-  int rx_len[NUM_RX_BUF];
-  int rx_ptr;
-  struct work_struct rx_work;
-  int rx_head, rx_tail, rx_count;
-  int rx_over;
-  char tx_buf[NUM_TX_BUF][BUF_SIZE];
-  int tx_len[NUM_TX_BUF];
-  int tx_ptr;
-  int tx_head, tx_tail, tx_count;
-  int state;
-  unsigned long tx_start;
-  int rr0;
-  spinlock_t *register_lock;	/* Per scc_info */
-  spinlock_t ring_lock;
+	int type;
+	int chip;
+	struct net_device *dev;
+	struct scc_info *info;
+	struct net_device_stats stats;
+	int channel;
+	int card_base, scc_cmd, scc_data;
+	int tmr_cnt, tmr_ctrl, tmr_mode;
+	struct scc_param param;
+	char rx_buf[NUM_RX_BUF][BUF_SIZE];
+	int rx_len[NUM_RX_BUF];
+	int rx_ptr;
+	struct work_struct rx_work;
+	int rx_head, rx_tail, rx_count;
+	int rx_over;
+	char tx_buf[NUM_TX_BUF][BUF_SIZE];
+	int tx_len[NUM_TX_BUF];
+	int tx_ptr;
+	int tx_head, tx_tail, tx_count;
+	int state;
+	unsigned long tx_start;
+	int rr0;
+	spinlock_t *register_lock;	/* Per scc_info */
+	spinlock_t ring_lock;
 };
 
 struct scc_info {
-  int irq_used;
-  int twin_serial_cfg;
-  struct net_device *dev[2];
-  struct scc_priv priv[2];
-  struct scc_info *next;
-  spinlock_t register_lock;	/* Per device register lock */
+	int irq_used;
+	int twin_serial_cfg;
+	struct net_device *dev[2];
+	struct scc_priv priv[2];
+	struct scc_info *next;
+	spinlock_t register_lock;	/* Per device register lock */
 };
 
 
@@ -252,7 +249,7 @@ static void start_timer(struct scc_priv 
 static inline unsigned char random(void);
 
 static inline void z8530_isr(struct scc_info *info);
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
 static void rx_isr(struct scc_priv *priv);
 static void special_condition(struct scc_priv *priv, int rc);
 static void rx_bh(void *arg);
@@ -264,12 +261,15 @@ static void tm_isr(struct scc_priv *priv
 /* Initialization variables */
 
 static int io[MAX_NUM_DEVS] __initdata = { 0, };
+
 /* Beware! hw[] is also used in cleanup_module(). */
 static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
 static char ax25_broadcast[7] __initdata =
-  { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 };
+    { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1,
+'0' << 1 };
 static char ax25_test[7] __initdata =
-  { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 };
+    { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1,
+'1' << 1 };
 
 
 /* Global variables */
@@ -283,143 +283,164 @@ MODULE_DESCRIPTION("Driver for high-spee
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
 MODULE_LICENSE("GPL");
 
-static void __exit dmascc_exit(void) {
-  int i;
-  struct scc_info *info;
-
-  while (first) {
-    info = first;
-
-    /* Unregister devices */
-    for (i = 0; i < 2; i++)
-	unregister_netdev(info->dev[i]);
-
-    /* Reset board */
-    if (info->priv[0].type == TYPE_TWIN)
-      outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG);
-    write_scc(&info->priv[0], R9, FHWRES);
-    release_region(info->dev[0]->base_addr,
-		   hw[info->priv[0].type].io_size);
-
-    for (i = 0; i < 2; i++)
-	free_netdev(info->dev[i]);
-
-    /* Free memory */
-    first = info->next;
-    kfree(info);
-  }
+static void __exit dmascc_exit(void)
+{
+	int i;
+	struct scc_info *info;
+
+	while (first) {
+		info = first;
+
+		/* Unregister devices */
+		for (i = 0; i < 2; i++)
+			unregister_netdev(info->dev[i]);
+
+		/* Reset board */
+		if (info->priv[0].type == TYPE_TWIN)
+			outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG);
+		write_scc(&info->priv[0], R9, FHWRES);
+		release_region(info->dev[0]->base_addr,
+			       hw[info->priv[0].type].io_size);
+
+		for (i = 0; i < 2; i++)
+			free_netdev(info->dev[i]);
+
+		/* Free memory */
+		first = info->next;
+		kfree(info);
+	}
 }
 
 #ifndef MODULE
-void __init dmascc_setup(char *str, int *ints) {
-   int i;
+void __init dmascc_setup(char *str, int *ints)
+{
+	int i;
 
-   for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++)
-      io[i] = ints[i+1];
+	for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++)
+		io[i] = ints[i + 1];
 }
 #endif
 
-static int __init dmascc_init(void) {
-  int h, i, j, n;
-  int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS],
-    t1[MAX_NUM_DEVS];
-  unsigned t_val;
-  unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS],
-    counting[MAX_NUM_DEVS];
-
-  /* Initialize random number generator */
-  rand = jiffies;
-  /* Cards found = 0 */
-  n = 0;
-  /* Warning message */
-  if (!io[0]) printk(KERN_INFO "dmascc: autoprobing (dangerous)\n");
-
-  /* Run autodetection for each card type */
-  for (h = 0; h < NUM_TYPES; h++) {
-
-    if (io[0]) {
-      /* User-specified I/O address regions */
-      for (i = 0; i < hw[h].num_devs; i++) base[i] = 0;
-      for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
-	j = (io[i] - hw[h].io_region) / hw[h].io_delta;
-	if (j >= 0 &&
-	    j < hw[h].num_devs && 
-	    hw[h].io_region + j * hw[h].io_delta == io[i]) {
-	  base[j] = io[i];
-	}
-      }
-    } else {
-      /* Default I/O address regions */
-      for (i = 0; i < hw[h].num_devs; i++) {
-	base[i] = hw[h].io_region + i * hw[h].io_delta;
-      }
-    }
-
-    /* Check valid I/O address regions */
-    for (i = 0; i < hw[h].num_devs; i++)
-      if (base[i]) {
-	if (!request_region(base[i], hw[h].io_size, "dmascc"))
-	  base[i] = 0;
-	else {
-	  tcmd[i] = base[i] + hw[h].tmr_offset + TMR_CTRL;
-	  t0[i]   = base[i] + hw[h].tmr_offset + TMR_CNT0;
-	  t1[i]   = base[i] + hw[h].tmr_offset + TMR_CNT1;
-	}
-      }
-
-    /* Start timers */
-    for (i = 0; i < hw[h].num_devs; i++)
-      if (base[i]) {
-	/* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
-	outb(0x36, tcmd[i]);
-	outb((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0[i]);
-	outb((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0[i]);
-	/* Timer 1: LSB+MSB, Mode 0, HZ/10 */
-	outb(0x70, tcmd[i]);
-	outb((TMR_0_HZ/HZ*10) & 0xFF, t1[i]);
-	outb((TMR_0_HZ/HZ*10) >> 8, t1[i]);
-	start[i] = jiffies;
-	delay[i] = 0;
-	counting[i] = 1;
-	/* Timer 2: LSB+MSB, Mode 0 */
-	outb(0xb0, tcmd[i]);
-      }
-    time = jiffies;
-    /* Wait until counter registers are loaded */
-    udelay(2000000/TMR_0_HZ);
-
-    /* Timing loop */
-    while (jiffies - time < 13) {
-      for (i = 0; i < hw[h].num_devs; i++)
-	if (base[i] && counting[i]) {
-	  /* Read back Timer 1: latch; read LSB; read MSB */
-	  outb(0x40, tcmd[i]);
-	  t_val = inb(t1[i]) + (inb(t1[i]) << 8);
-	  /* Also check whether counter did wrap */
-	  if (t_val == 0 || t_val > TMR_0_HZ/HZ*10) counting[i] = 0;
-	  delay[i] = jiffies - start[i];
-	}
-    }
-
-    /* Evaluate measurements */
-    for (i = 0; i < hw[h].num_devs; i++)
-      if (base[i]) {
-	if ((delay[i] >= 9 && delay[i] <= 11)&& 
-	    /* Ok, we have found an adapter */
-	    (setup_adapter(base[i], h, n) == 0))
-	  n++;
-	else
-	  release_region(base[i], hw[h].io_size);
-      }
-
-  } /* NUM_TYPES */
+static int __init dmascc_init(void)
+{
+	int h, i, j, n;
+	int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS],
+	    t1[MAX_NUM_DEVS];
+	unsigned t_val;
+	unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS],
+	    counting[MAX_NUM_DEVS];
+
+	/* Initialize random number generator */
+	rand = jiffies;
+	/* Cards found = 0 */
+	n = 0;
+	/* Warning message */
+	if (!io[0])
+		printk(KERN_INFO "dmascc: autoprobing (dangerous)\n");
+
+	/* Run autodetection for each card type */
+	for (h = 0; h < NUM_TYPES; h++) {
+
+		if (io[0]) {
+			/* User-specified I/O address regions */
+			for (i = 0; i < hw[h].num_devs; i++)
+				base[i] = 0;
+			for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
+				j = (io[i] -
+				     hw[h].io_region) / hw[h].io_delta;
+				if (j >= 0 && j < hw[h].num_devs
+				    && hw[h].io_region +
+				    j * hw[h].io_delta == io[i]) {
+					base[j] = io[i];
+				}
+			}
+		} else {
+			/* Default I/O address regions */
+			for (i = 0; i < hw[h].num_devs; i++) {
+				base[i] =
+				    hw[h].io_region + i * hw[h].io_delta;
+			}
+		}
 
-  /* If any adapter was successfully initialized, return ok */
-  if (n) return 0;
+		/* Check valid I/O address regions */
+		for (i = 0; i < hw[h].num_devs; i++)
+			if (base[i]) {
+				if (!request_region
+				    (base[i], hw[h].io_size, "dmascc"))
+					base[i] = 0;
+				else {
+					tcmd[i] =
+					    base[i] + hw[h].tmr_offset +
+					    TMR_CTRL;
+					t0[i] =
+					    base[i] + hw[h].tmr_offset +
+					    TMR_CNT0;
+					t1[i] =
+					    base[i] + hw[h].tmr_offset +
+					    TMR_CNT1;
+				}
+			}
+
+		/* Start timers */
+		for (i = 0; i < hw[h].num_devs; i++)
+			if (base[i]) {
+				/* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
+				outb(0x36, tcmd[i]);
+				outb((hw[h].tmr_hz / TMR_0_HZ) & 0xFF,
+				     t0[i]);
+				outb((hw[h].tmr_hz / TMR_0_HZ) >> 8,
+				     t0[i]);
+				/* Timer 1: LSB+MSB, Mode 0, HZ/10 */
+				outb(0x70, tcmd[i]);
+				outb((TMR_0_HZ / HZ * 10) & 0xFF, t1[i]);
+				outb((TMR_0_HZ / HZ * 10) >> 8, t1[i]);
+				start[i] = jiffies;
+				delay[i] = 0;
+				counting[i] = 1;
+				/* Timer 2: LSB+MSB, Mode 0 */
+				outb(0xb0, tcmd[i]);
+			}
+		time = jiffies;
+		/* Wait until counter registers are loaded */
+		udelay(2000000 / TMR_0_HZ);
+
+		/* Timing loop */
+		while (jiffies - time < 13) {
+			for (i = 0; i < hw[h].num_devs; i++)
+				if (base[i] && counting[i]) {
+					/* Read back Timer 1: latch; read LSB; read MSB */
+					outb(0x40, tcmd[i]);
+					t_val =
+					    inb(t1[i]) + (inb(t1[i]) << 8);
+					/* Also check whether counter did wrap */
+					if (t_val == 0
+					    || t_val > TMR_0_HZ / HZ * 10)
+						counting[i] = 0;
+					delay[i] = jiffies - start[i];
+				}
+		}
 
-  /* If no adapter found, return error */
-  printk(KERN_INFO "dmascc: no adapters found\n");
-  return -EIO;
+		/* Evaluate measurements */
+		for (i = 0; i < hw[h].num_devs; i++)
+			if (base[i]) {
+				if ((delay[i] >= 9 && delay[i] <= 11) &&
+				    /* Ok, we have found an adapter */
+				    (setup_adapter(base[i], h, n) == 0))
+					n++;
+				else
+					release_region(base[i],
+						       hw[h].io_size);
+			}
+
+	}			/* NUM_TYPES */
+
+	/* If any adapter was successfully initialized, return ok */
+	if (n)
+		return 0;
+
+	/* If no adapter found, return error */
+	printk(KERN_INFO "dmascc: no adapters found\n");
+	return -EIO;
 }
 
 module_init(dmascc_init);
@@ -452,8 +473,8 @@ static int __init setup_adapter(int card
 	info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
 	if (!info) {
 		printk(KERN_ERR "dmascc: "
-			"could not allocate memory for %s at %#3x\n",
-			hw[type].name, card_base);
+		       "could not allocate memory for %s at %#3x\n",
+		       hw[type].name, card_base);
 		goto out;
 	}
 
@@ -463,16 +484,16 @@ static int __init setup_adapter(int card
 	info->dev[0] = alloc_netdev(0, "", dev_setup);
 	if (!info->dev[0]) {
 		printk(KERN_ERR "dmascc: "
-			"could not allocate memory for %s at %#3x\n",
-			hw[type].name, card_base);
+		       "could not allocate memory for %s at %#3x\n",
+		       hw[type].name, card_base);
 		goto out1;
 	}
 
 	info->dev[1] = alloc_netdev(0, "", dev_setup);
 	if (!info->dev[1]) {
 		printk(KERN_ERR "dmascc: "
-			"could not allocate memory for %s at %#3x\n",
-			hw[type].name, card_base);
+		       "could not allocate memory for %s at %#3x\n",
+		       hw[type].name, card_base);
 		goto out2;
 	}
 	spin_lock_init(&info->register_lock);
@@ -526,7 +547,8 @@ static int __init setup_adapter(int card
 	outb(0, tmr_base + TMR_CNT1);
 
 	/* Wait and detect IRQ */
-	time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ);
+	time = jiffies;
+	while (jiffies - time < 2 + HZ / TMR_0_HZ);
 	irq = probe_irq_off(irqs);
 
 	/* Clear pending interrupt, disable interrupts */
@@ -539,8 +561,9 @@ static int __init setup_adapter(int card
 	}
 
 	if (irq <= 0) {
-		printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n",
-			hw[type].name, card_base, irq);
+		printk(KERN_ERR
+		       "dmascc: could not find irq of %s at %#3x (irq=%d)\n",
+		       hw[type].name, card_base, irq);
 		goto out3;
 	}
 
@@ -568,7 +591,7 @@ static int __init setup_adapter(int card
 		priv->param.dma = -1;
 		INIT_WORK(&priv->rx_work, rx_bh, priv);
 		dev->priv = priv;
-		sprintf(dev->name, "dmascc%i", 2*n+i);
+		sprintf(dev->name, "dmascc%i", 2 * n + i);
 		SET_MODULE_OWNER(dev);
 		dev->base_addr = card_base;
 		dev->irq = irq;
@@ -583,820 +606,886 @@ static int __init setup_adapter(int card
 	}
 	if (register_netdev(info->dev[0])) {
 		printk(KERN_ERR "dmascc: could not register %s\n",
-				info->dev[0]->name);
+		       info->dev[0]->name);
 		goto out3;
 	}
 	if (register_netdev(info->dev[1])) {
 		printk(KERN_ERR "dmascc: could not register %s\n",
-				info->dev[1]->name);
+		       info->dev[1]->name);
 		goto out4;
 	}
 
 
 	info->next = first;
 	first = info;
-	printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name,
-	chipnames[chip], card_base, irq);
+	printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n",
+	       hw[type].name, chipnames[chip], card_base, irq);
 	return 0;
 
-out4:
+      out4:
 	unregister_netdev(info->dev[0]);
-out3:
+      out3:
 	if (info->priv[0].type == TYPE_TWIN)
 		outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG);
 	write_scc(&info->priv[0], R9, FHWRES);
 	free_netdev(info->dev[1]);
-out2:
+      out2:
 	free_netdev(info->dev[0]);
-out1:
+      out1:
 	kfree(info);
-out:
+      out:
 	return -1;
 }
 
 
 /* Driver functions */
 
-static void write_scc(struct scc_priv *priv, int reg, int val) {
-  unsigned long flags;
-  switch (priv->type) {
-  case TYPE_S5:
-    if (reg) outb(reg, priv->scc_cmd);
-    outb(val, priv->scc_cmd);
-    return;
-  case TYPE_TWIN:
-    if (reg) outb_p(reg, priv->scc_cmd);
-    outb_p(val, priv->scc_cmd);
-    return;
-  default:
-    spin_lock_irqsave(priv->register_lock, flags);
-    outb_p(0, priv->card_base + PI_DREQ_MASK);
-    if (reg) outb_p(reg, priv->scc_cmd);
-    outb_p(val, priv->scc_cmd);
-    outb(1, priv->card_base + PI_DREQ_MASK);
-    spin_unlock_irqrestore(priv->register_lock, flags);
-    return;
-  }
-}
-
-
-static void write_scc_data(struct scc_priv *priv, int val, int fast) {
-  unsigned long flags;
-  switch (priv->type) {
-  case TYPE_S5:
-    outb(val, priv->scc_data);
-    return;
-  case TYPE_TWIN:
-    outb_p(val, priv->scc_data);
-    return;
-  default:
-    if (fast) outb_p(val, priv->scc_data);
-    else {
-      spin_lock_irqsave(priv->register_lock, flags);
-      outb_p(0, priv->card_base + PI_DREQ_MASK);
-      outb_p(val, priv->scc_data);
-      outb(1, priv->card_base + PI_DREQ_MASK);
-      spin_unlock_irqrestore(priv->register_lock, flags);
-    }
-    return;
-  }
-}
-
-
-static int read_scc(struct scc_priv *priv, int reg) {
-  int rc;
-  unsigned long flags;
-  switch (priv->type) {
-  case TYPE_S5:
-    if (reg) outb(reg, priv->scc_cmd);
-    return inb(priv->scc_cmd);
-  case TYPE_TWIN:
-    if (reg) outb_p(reg, priv->scc_cmd);
-    return inb_p(priv->scc_cmd);
-  default:
-    spin_lock_irqsave(priv->register_lock, flags);
-    outb_p(0, priv->card_base + PI_DREQ_MASK);
-    if (reg) outb_p(reg, priv->scc_cmd);
-    rc = inb_p(priv->scc_cmd);
-    outb(1, priv->card_base + PI_DREQ_MASK);
-    spin_unlock_irqrestore(priv->register_lock, flags);
-    return rc;
-  }
-}
-
-
-static int read_scc_data(struct scc_priv *priv) {
-  int rc;
-  unsigned long flags;
-  switch (priv->type) {
-  case TYPE_S5:
-    return inb(priv->scc_data);
-  case TYPE_TWIN:
-    return inb_p(priv->scc_data);
-  default:
-    spin_lock_irqsave(priv->register_lock, flags);
-    outb_p(0, priv->card_base + PI_DREQ_MASK);
-    rc = inb_p(priv->scc_data);
-    outb(1, priv->card_base + PI_DREQ_MASK);
-    spin_unlock_irqrestore(priv->register_lock, flags);
-    return rc;
-  }
-}
-
-
-static int scc_open(struct net_device *dev) {
-  struct scc_priv *priv = dev->priv;
-  struct scc_info *info = priv->info;
-  int card_base = priv->card_base;
-
-  /* Request IRQ if not already used by other channel */
-  if (!info->irq_used) {
-    if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) {
-      return -EAGAIN;
-    }
-  }
-  info->irq_used++;
-
-  /* Request DMA if required */
-  if (priv->param.dma >= 0) {
-    if (request_dma(priv->param.dma, "dmascc")) {
-      if (--info->irq_used == 0) free_irq(dev->irq, info);
-      return -EAGAIN;
-    } else {
-      unsigned long flags = claim_dma_lock();
-      clear_dma_ff(priv->param.dma);
-      release_dma_lock(flags);
-    }
-  }
-
-  /* Initialize local variables */
-  priv->rx_ptr = 0;
-  priv->rx_over = 0;
-  priv->rx_head = priv->rx_tail = priv->rx_count = 0;
-  priv->state = IDLE;
-  priv->tx_head = priv->tx_tail = priv->tx_count = 0;
-  priv->tx_ptr = 0;
-
-  /* Reset channel */
-  write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
-  /* X1 clock, SDLC mode */
-  write_scc(priv, R4, SDLC | X1CLK);
-  /* DMA */
-  write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
-  /* 8 bit RX char, RX disable */
-  write_scc(priv, R3, Rx8);
-  /* 8 bit TX char, TX disable */
-  write_scc(priv, R5, Tx8);
-  /* SDLC address field */
-  write_scc(priv, R6, 0);
-  /* SDLC flag */
-  write_scc(priv, R7, FLAG);
-  switch (priv->chip) {
-  case Z85C30:
-    /* Select WR7' */
-    write_scc(priv, R15, SHDLCE);
-    /* Auto EOM reset */
-    write_scc(priv, R7, AUTOEOM);
-    write_scc(priv, R15, 0);
-    break;
-  case Z85230:
-    /* Select WR7' */
-    write_scc(priv, R15, SHDLCE);
-    /* The following bits are set (see 2.5.2.1):
-       - Automatic EOM reset
-       - Interrupt request if RX FIFO is half full
-         This bit should be ignored in DMA mode (according to the
-         documentation), but actually isn't. The receiver doesn't work if
-         it is set. Thus, we have to clear it in DMA mode.
-       - Interrupt/DMA request if TX FIFO is completely empty
-         a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30
-            compatibility).
-         b) If cleared, DMA requests may follow each other very quickly,
-            filling up the TX FIFO.
-            Advantage: TX works even in case of high bus latency.
-            Disadvantage: Edge-triggered DMA request circuitry may miss
-                          a request. No more data is delivered, resulting
-                          in a TX FIFO underrun.
-         Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared.
-         The PackeTwin doesn't. I don't know about the PI, but let's
-	 assume it behaves like the PI2.
-    */
-    if (priv->param.dma >= 0) {
-      if (priv->type == TYPE_TWIN) write_scc(priv, R7, AUTOEOM | TXFIFOE);
-      else write_scc(priv, R7, AUTOEOM);
-    } else {
-      write_scc(priv, R7, AUTOEOM | RXFIFOH);
-    }
-    write_scc(priv, R15, 0);
-    break;
-  }
-  /* Preset CRC, NRZ(I) encoding */
-  write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
-
-  /* Configure baud rate generator */
-  if (priv->param.brg_tc >= 0) {
-    /* Program BR generator */
-    write_scc(priv, R12, priv->param.brg_tc & 0xFF);
-    write_scc(priv, R13, (priv->param.brg_tc>>8) & 0xFF);
-    /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
-       PackeTwin, not connected on the PI2); set DPLL source to BRG */
-    write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL);
-    /* Enable DPLL */
-    write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
-  } else {
-    /* Disable BR generator */
-    write_scc(priv, R14, DTRREQ | BRSRC);
-  }
-
-  /* Configure clocks */
-  if (priv->type == TYPE_TWIN) {
-    /* Disable external TX clock receiver */
-    outb((info->twin_serial_cfg &=
-	    ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), 
-	   card_base + TWIN_SERIAL_CFG);
-  }
-  write_scc(priv, R11, priv->param.clocks);
-  if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
-    /* Enable external TX clock receiver */
-    outb((info->twin_serial_cfg |=
-	    (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
-	   card_base + TWIN_SERIAL_CFG);
-  }
-
-  /* Configure PackeTwin */
-  if (priv->type == TYPE_TWIN) {
-    /* Assert DTR, enable interrupts */
-    outb((info->twin_serial_cfg |= TWIN_EI |
-	    (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
-	   card_base + TWIN_SERIAL_CFG);
-  }
-
-  /* Read current status */
-  priv->rr0 = read_scc(priv, R0);
-  /* Enable DCD interrupt */
-  write_scc(priv, R15, DCDIE);
-
-  netif_start_queue(dev);
-
-  return 0;
-}
-
-
-static int scc_close(struct net_device *dev) {
-  struct scc_priv *priv = dev->priv;
-  struct scc_info *info = priv->info;
-  int card_base = priv->card_base;
-
-  netif_stop_queue(dev);
-
-  if (priv->type == TYPE_TWIN) {
-    /* Drop DTR */
-    outb((info->twin_serial_cfg &=
-	    (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
-	   card_base + TWIN_SERIAL_CFG);
-  }
-
-  /* Reset channel, free DMA and IRQ */
-  write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
-  if (priv->param.dma >= 0) {
-    if (priv->type == TYPE_TWIN) outb(0, card_base + TWIN_DMA_CFG);
-    free_dma(priv->param.dma);
-  }
-  if (--info->irq_used == 0) free_irq(dev->irq, info);
-
-  return 0;
-}
-
-
-static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) {
-  struct scc_priv *priv = dev->priv;
-  
-  switch (cmd) {
-  case SIOCGSCCPARAM:
-    if (copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)))
-      return -EFAULT;
-    return 0;
-  case SIOCSSCCPARAM:
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (netif_running(dev)) return -EAGAIN;
-    if (copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)))
-      return -EFAULT;
-    return 0;
-  default:
-    return -EINVAL;
-  }
-}
-
-
-static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) {
-  struct scc_priv *priv = dev->priv;
-  unsigned long flags;
-  int i;
-
-  /* Temporarily stop the scheduler feeding us packets */
-  netif_stop_queue(dev);
-
-  /* Transfer data to DMA buffer */
-  i = priv->tx_head;
-  memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
-  priv->tx_len[i] = skb->len-1;
-
-  /* Clear interrupts while we touch our circular buffers */
-
-  spin_lock_irqsave(&priv->ring_lock, flags);
-  /* Move the ring buffer's head */
-  priv->tx_head = (i + 1) % NUM_TX_BUF;
-  priv->tx_count++;
-
-  /* If we just filled up the last buffer, leave queue stopped.
-     The higher layers must wait until we have a DMA buffer
-     to accept the data. */
-  if (priv->tx_count < NUM_TX_BUF) netif_wake_queue(dev);
-
-  /* Set new TX state */
-  if (priv->state == IDLE) {
-    /* Assert RTS, start timer */
-    priv->state = TX_HEAD;
-    priv->tx_start = jiffies;
-    write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
-    write_scc(priv, R15, 0);
-    start_timer(priv, priv->param.txdelay, 0);
-  }
-
-  /* Turn interrupts back on and free buffer */
-  spin_unlock_irqrestore(&priv->ring_lock, flags);
-  dev_kfree_skb(skb);
-
-  return 0;
-}
-
-
-static struct net_device_stats *scc_get_stats(struct net_device *dev) {
-  struct scc_priv *priv = dev->priv;
-
-  return &priv->stats;
-}
-
-
-static int scc_set_mac_address(struct net_device *dev, void *sa) {
-  memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len);
-  return 0;
-}
-
-
-static inline void tx_on(struct scc_priv *priv) {
-  int i, n;
-  unsigned long flags;
-
-  if (priv->param.dma >= 0) {
-    n = (priv->chip == Z85230) ? 3 : 1;
-    /* Program DMA controller */
-    flags = claim_dma_lock();
-    set_dma_mode(priv->param.dma, DMA_MODE_WRITE);
-    set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n);
-    set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n);
-    release_dma_lock(flags);
-    /* Enable TX underrun interrupt */
-    write_scc(priv, R15, TxUIE);
-    /* Configure DREQ */
-    if (priv->type == TYPE_TWIN)
-      outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
-	   priv->card_base + TWIN_DMA_CFG);
-    else
-      write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
-    /* Write first byte(s) */
-    spin_lock_irqsave(priv->register_lock, flags);
-    for (i = 0; i < n; i++)
-      write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1);
-    enable_dma(priv->param.dma);
-    spin_unlock_irqrestore(priv->register_lock, flags);
-  } else {
-    write_scc(priv, R15, TxUIE);
-    write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
-    tx_isr(priv);
-  }
-  /* Reset EOM latch if we do not have the AUTOEOM feature */
-  if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L);
-}
-
-
-static inline void rx_on(struct scc_priv *priv) {
-  unsigned long flags;
-
-  /* Clear RX FIFO */
-  while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv);
-  priv->rx_over = 0;
-  if (priv->param.dma >= 0) {
-    /* Program DMA controller */
-    flags = claim_dma_lock();
-    set_dma_mode(priv->param.dma, DMA_MODE_READ);
-    set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]);
-    set_dma_count(priv->param.dma, BUF_SIZE);
-    release_dma_lock(flags);
-    enable_dma(priv->param.dma);
-    /* Configure PackeTwin DMA */
-    if (priv->type == TYPE_TWIN) {
-      outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
-	   priv->card_base + TWIN_DMA_CFG);
-    }
-    /* Sp. cond. intr. only, ext int enable, RX DMA enable */
-    write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx |
-	      WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
-  } else {
-    /* Reset current frame */
-    priv->rx_ptr = 0;
-    /* Intr. on all Rx characters and Sp. cond., ext int enable */
-    write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
-	      WT_FN_RDYFN);
-  }
-  write_scc(priv, R0, ERR_RES);
-  write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);
-}
-
-
-static inline void rx_off(struct scc_priv *priv) {
-  /* Disable receiver */
-  write_scc(priv, R3, Rx8);
-  /* Disable DREQ / RX interrupt */
-  if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
-    outb(0, priv->card_base + TWIN_DMA_CFG);
-  else
-    write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
-  /* Disable DMA */
-  if (priv->param.dma >= 0) disable_dma(priv->param.dma);
-}
-
-
-static void start_timer(struct scc_priv *priv, int t, int r15) {
-  unsigned long flags;
-
-  outb(priv->tmr_mode, priv->tmr_ctrl);
-  if (t == 0) {
-    tm_isr(priv);
-  } else if (t > 0) {
-    save_flags(flags);
-    cli();
-    outb(t & 0xFF, priv->tmr_cnt);
-    outb((t >> 8) & 0xFF, priv->tmr_cnt);
-    if (priv->type != TYPE_TWIN) {
-      write_scc(priv, R15, r15 | CTSIE);
-      priv->rr0 |= CTS;
-    }
-    restore_flags(flags);
-  }
-}
-
-
-static inline unsigned char random(void) {
-  /* See "Numerical Recipes in C", second edition, p. 284 */
-  rand = rand * 1664525L + 1013904223L;
-  return (unsigned char) (rand >> 24);
-}
-
-static inline void z8530_isr(struct scc_info *info) {
-  int is, i = 100;
-
-  while ((is = read_scc(&info->priv[0], R3)) && i--) {
-    if (is & CHARxIP) {
-      rx_isr(&info->priv[0]);
-    } else if (is & CHATxIP) {
-      tx_isr(&info->priv[0]);
-    } else if (is & CHAEXT) {
-      es_isr(&info->priv[0]);
-    } else if (is & CHBRxIP) {
-      rx_isr(&info->priv[1]);
-    } else if (is & CHBTxIP) {
-      tx_isr(&info->priv[1]);
-    } else {
-      es_isr(&info->priv[1]);
-    }
-    write_scc(&info->priv[0], R0, RES_H_IUS);
-    i++;
-  }
-  if (i < 0) {
-    printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", is);
-  }
-  /* Ok, no interrupts pending from this 8530. The INT line should
-     be inactive now. */
-}
-
-
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) {
-  struct scc_info *info = dev_id;
-
-  spin_lock(info->priv[0].register_lock);
-  /* At this point interrupts are enabled, and the interrupt under service
-     is already acknowledged, but masked off.
-
-     Interrupt processing: We loop until we know that the IRQ line is
-     low. If another positive edge occurs afterwards during the ISR,
-     another interrupt will be triggered by the interrupt controller
-     as soon as the IRQ level is enabled again (see asm/irq.h).
-
-     Bottom-half handlers will be processed after scc_isr(). This is
-     important, since we only have small ringbuffers and want new data
-     to be fetched/delivered immediately. */
-
-  if (info->priv[0].type == TYPE_TWIN) {
-    int is, card_base = info->priv[0].card_base;
-    while ((is = ~inb(card_base + TWIN_INT_REG)) &
-	   TWIN_INT_MSK) {
-      if (is & TWIN_SCC_MSK) {
-	z8530_isr(info);
-      } else if (is & TWIN_TMR1_MSK) {
-	inb(card_base + TWIN_CLR_TMR1);
-	tm_isr(&info->priv[0]);
-      } else {
-	inb(card_base + TWIN_CLR_TMR2);
-	tm_isr(&info->priv[1]);
-      }
-    }
-  } else z8530_isr(info);
-  spin_unlock(info->priv[0].register_lock);
-  return IRQ_HANDLED;
-}
-
-
-static void rx_isr(struct scc_priv *priv) {
-  if (priv->param.dma >= 0) {
-    /* Check special condition and perform error reset. See 2.4.7.5. */
-    special_condition(priv, read_scc(priv, R1));
-    write_scc(priv, R0, ERR_RES);
-  } else {
-    /* Check special condition for each character. Error reset not necessary.
-       Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
-    int rc;
-    while (read_scc(priv, R0) & Rx_CH_AV) {
-      rc = read_scc(priv, R1);
-      if (priv->rx_ptr < BUF_SIZE)
-	priv->rx_buf[priv->rx_head][priv->rx_ptr++] =
-	  read_scc_data(priv);
-      else {
-	priv->rx_over = 2;
-	read_scc_data(priv);
-      }
-      special_condition(priv, rc);
-    }
-  }
-}
-
-
-static void special_condition(struct scc_priv *priv, int rc) {
-  int cb;
-  unsigned long flags;
-
-  /* See Figure 2-15. Only overrun and EOF need to be checked. */
-  
-  if (rc & Rx_OVR) {
-    /* Receiver overrun */
-    priv->rx_over = 1;
-    if (priv->param.dma < 0) write_scc(priv, R0, ERR_RES);
-  } else if (rc & END_FR) {
-    /* End of frame. Get byte count */
-    if (priv->param.dma >= 0) {
-      flags = claim_dma_lock();
-      cb = BUF_SIZE - get_dma_residue(priv->param.dma) - 2;
-      release_dma_lock(flags);
-    } else {
-      cb = priv->rx_ptr - 2;
-    }
-    if (priv->rx_over) {
-      /* We had an overrun */
-      priv->stats.rx_errors++;
-      if (priv->rx_over == 2) priv->stats.rx_length_errors++;
-      else priv->stats.rx_fifo_errors++;
-      priv->rx_over = 0;
-    } else if (rc & CRC_ERR) {
-      /* Count invalid CRC only if packet length >= minimum */
-      if (cb >= 15) {
-	priv->stats.rx_errors++;
-	priv->stats.rx_crc_errors++;
-      }
-    } else {
-      if (cb >= 15) {
-	if (priv->rx_count < NUM_RX_BUF - 1) {
-	  /* Put good frame in FIFO */
-	  priv->rx_len[priv->rx_head] = cb;
-	  priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF;
-	  priv->rx_count++;
-	  schedule_work(&priv->rx_work);
+static void write_scc(struct scc_priv *priv, int reg, int val)
+{
+	unsigned long flags;
+	switch (priv->type) {
+	case TYPE_S5:
+		if (reg)
+			outb(reg, priv->scc_cmd);
+		outb(val, priv->scc_cmd);
+		return;
+	case TYPE_TWIN:
+		if (reg)
+			outb_p(reg, priv->scc_cmd);
+		outb_p(val, priv->scc_cmd);
+		return;
+	default:
+		spin_lock_irqsave(priv->register_lock, flags);
+		outb_p(0, priv->card_base + PI_DREQ_MASK);
+		if (reg)
+			outb_p(reg, priv->scc_cmd);
+		outb_p(val, priv->scc_cmd);
+		outb(1, priv->card_base + PI_DREQ_MASK);
+		spin_unlock_irqrestore(priv->register_lock, flags);
+		return;
+	}
+}
+
+
+static void write_scc_data(struct scc_priv *priv, int val, int fast)
+{
+	unsigned long flags;
+	switch (priv->type) {
+	case TYPE_S5:
+		outb(val, priv->scc_data);
+		return;
+	case TYPE_TWIN:
+		outb_p(val, priv->scc_data);
+		return;
+	default:
+		if (fast)
+			outb_p(val, priv->scc_data);
+		else {
+			spin_lock_irqsave(priv->register_lock, flags);
+			outb_p(0, priv->card_base + PI_DREQ_MASK);
+			outb_p(val, priv->scc_data);
+			outb(1, priv->card_base + PI_DREQ_MASK);
+			spin_unlock_irqrestore(priv->register_lock, flags);
+		}
+		return;
+	}
+}
+
+
+static int read_scc(struct scc_priv *priv, int reg)
+{
+	int rc;
+	unsigned long flags;
+	switch (priv->type) {
+	case TYPE_S5:
+		if (reg)
+			outb(reg, priv->scc_cmd);
+		return inb(priv->scc_cmd);
+	case TYPE_TWIN:
+		if (reg)
+			outb_p(reg, priv->scc_cmd);
+		return inb_p(priv->scc_cmd);
+	default:
+		spin_lock_irqsave(priv->register_lock, flags);
+		outb_p(0, priv->card_base + PI_DREQ_MASK);
+		if (reg)
+			outb_p(reg, priv->scc_cmd);
+		rc = inb_p(priv->scc_cmd);
+		outb(1, priv->card_base + PI_DREQ_MASK);
+		spin_unlock_irqrestore(priv->register_lock, flags);
+		return rc;
+	}
+}
+
+
+static int read_scc_data(struct scc_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+	switch (priv->type) {
+	case TYPE_S5:
+		return inb(priv->scc_data);
+	case TYPE_TWIN:
+		return inb_p(priv->scc_data);
+	default:
+		spin_lock_irqsave(priv->register_lock, flags);
+		outb_p(0, priv->card_base + PI_DREQ_MASK);
+		rc = inb_p(priv->scc_data);
+		outb(1, priv->card_base + PI_DREQ_MASK);
+		spin_unlock_irqrestore(priv->register_lock, flags);
+		return rc;
+	}
+}
+
+
+static int scc_open(struct net_device *dev)
+{
+	struct scc_priv *priv = dev->priv;
+	struct scc_info *info = priv->info;
+	int card_base = priv->card_base;
+
+	/* Request IRQ if not already used by other channel */
+	if (!info->irq_used) {
+		if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) {
+			return -EAGAIN;
+		}
+	}
+	info->irq_used++;
+
+	/* Request DMA if required */
+	if (priv->param.dma >= 0) {
+		if (request_dma(priv->param.dma, "dmascc")) {
+			if (--info->irq_used == 0)
+				free_irq(dev->irq, info);
+			return -EAGAIN;
+		} else {
+			unsigned long flags = claim_dma_lock();
+			clear_dma_ff(priv->param.dma);
+			release_dma_lock(flags);
+		}
+	}
+
+	/* Initialize local variables */
+	priv->rx_ptr = 0;
+	priv->rx_over = 0;
+	priv->rx_head = priv->rx_tail = priv->rx_count = 0;
+	priv->state = IDLE;
+	priv->tx_head = priv->tx_tail = priv->tx_count = 0;
+	priv->tx_ptr = 0;
+
+	/* Reset channel */
+	write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+	/* X1 clock, SDLC mode */
+	write_scc(priv, R4, SDLC | X1CLK);
+	/* DMA */
+	write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+	/* 8 bit RX char, RX disable */
+	write_scc(priv, R3, Rx8);
+	/* 8 bit TX char, TX disable */
+	write_scc(priv, R5, Tx8);
+	/* SDLC address field */
+	write_scc(priv, R6, 0);
+	/* SDLC flag */
+	write_scc(priv, R7, FLAG);
+	switch (priv->chip) {
+	case Z85C30:
+		/* Select WR7' */
+		write_scc(priv, R15, SHDLCE);
+		/* Auto EOM reset */
+		write_scc(priv, R7, AUTOEOM);
+		write_scc(priv, R15, 0);
+		break;
+	case Z85230:
+		/* Select WR7' */
+		write_scc(priv, R15, SHDLCE);
+		/* The following bits are set (see 2.5.2.1):
+		   - Automatic EOM reset
+		   - Interrupt request if RX FIFO is half full
+		   This bit should be ignored in DMA mode (according to the
+		   documentation), but actually isn't. The receiver doesn't work if
+		   it is set. Thus, we have to clear it in DMA mode.
+		   - Interrupt/DMA request if TX FIFO is completely empty
+		   a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30
+		   compatibility).
+		   b) If cleared, DMA requests may follow each other very quickly,
+		   filling up the TX FIFO.
+		   Advantage: TX works even in case of high bus latency.
+		   Disadvantage: Edge-triggered DMA request circuitry may miss
+		   a request. No more data is delivered, resulting
+		   in a TX FIFO underrun.
+		   Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared.
+		   The PackeTwin doesn't. I don't know about the PI, but let's
+		   assume it behaves like the PI2.
+		 */
+		if (priv->param.dma >= 0) {
+			if (priv->type == TYPE_TWIN)
+				write_scc(priv, R7, AUTOEOM | TXFIFOE);
+			else
+				write_scc(priv, R7, AUTOEOM);
+		} else {
+			write_scc(priv, R7, AUTOEOM | RXFIFOH);
+		}
+		write_scc(priv, R15, 0);
+		break;
+	}
+	/* Preset CRC, NRZ(I) encoding */
+	write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
+
+	/* Configure baud rate generator */
+	if (priv->param.brg_tc >= 0) {
+		/* Program BR generator */
+		write_scc(priv, R12, priv->param.brg_tc & 0xFF);
+		write_scc(priv, R13, (priv->param.brg_tc >> 8) & 0xFF);
+		/* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
+		   PackeTwin, not connected on the PI2); set DPLL source to BRG */
+		write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL);
+		/* Enable DPLL */
+		write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
 	} else {
-	  priv->stats.rx_errors++;
-	  priv->stats.rx_over_errors++;
+		/* Disable BR generator */
+		write_scc(priv, R14, DTRREQ | BRSRC);
+	}
+
+	/* Configure clocks */
+	if (priv->type == TYPE_TWIN) {
+		/* Disable external TX clock receiver */
+		outb((info->twin_serial_cfg &=
+		      ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
+		     card_base + TWIN_SERIAL_CFG);
+	}
+	write_scc(priv, R11, priv->param.clocks);
+	if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
+		/* Enable external TX clock receiver */
+		outb((info->twin_serial_cfg |=
+		      (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
+		     card_base + TWIN_SERIAL_CFG);
+	}
+
+	/* Configure PackeTwin */
+	if (priv->type == TYPE_TWIN) {
+		/* Assert DTR, enable interrupts */
+		outb((info->twin_serial_cfg |= TWIN_EI |
+		      (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
+		     card_base + TWIN_SERIAL_CFG);
+	}
+
+	/* Read current status */
+	priv->rr0 = read_scc(priv, R0);
+	/* Enable DCD interrupt */
+	write_scc(priv, R15, DCDIE);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+
+static int scc_close(struct net_device *dev)
+{
+	struct scc_priv *priv = dev->priv;
+	struct scc_info *info = priv->info;
+	int card_base = priv->card_base;
+
+	netif_stop_queue(dev);
+
+	if (priv->type == TYPE_TWIN) {
+		/* Drop DTR */
+		outb((info->twin_serial_cfg &=
+		      (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
+		     card_base + TWIN_SERIAL_CFG);
+	}
+
+	/* Reset channel, free DMA and IRQ */
+	write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+	if (priv->param.dma >= 0) {
+		if (priv->type == TYPE_TWIN)
+			outb(0, card_base + TWIN_DMA_CFG);
+		free_dma(priv->param.dma);
+	}
+	if (--info->irq_used == 0)
+		free_irq(dev->irq, info);
+
+	return 0;
+}
+
+
+static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct scc_priv *priv = dev->priv;
+
+	switch (cmd) {
+	case SIOCGSCCPARAM:
+		if (copy_to_user
+		    (ifr->ifr_data, &priv->param,
+		     sizeof(struct scc_param)))
+			return -EFAULT;
+		return 0;
+	case SIOCSSCCPARAM:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (netif_running(dev))
+			return -EAGAIN;
+		if (copy_from_user
+		    (&priv->param, ifr->ifr_data,
+		     sizeof(struct scc_param)))
+			return -EFAULT;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct scc_priv *priv = dev->priv;
+	unsigned long flags;
+	int i;
+
+	/* Temporarily stop the scheduler feeding us packets */
+	netif_stop_queue(dev);
+
+	/* Transfer data to DMA buffer */
+	i = priv->tx_head;
+	memcpy(priv->tx_buf[i], skb->data + 1, skb->len - 1);
+	priv->tx_len[i] = skb->len - 1;
+
+	/* Clear interrupts while we touch our circular buffers */
+
+	spin_lock_irqsave(&priv->ring_lock, flags);
+	/* Move the ring buffer's head */
+	priv->tx_head = (i + 1) % NUM_TX_BUF;
+	priv->tx_count++;
+
+	/* If we just filled up the last buffer, leave queue stopped.
+	   The higher layers must wait until we have a DMA buffer
+	   to accept the data. */
+	if (priv->tx_count < NUM_TX_BUF)
+		netif_wake_queue(dev);
+
+	/* Set new TX state */
+	if (priv->state == IDLE) {
+		/* Assert RTS, start timer */
+		priv->state = TX_HEAD;
+		priv->tx_start = jiffies;
+		write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+		write_scc(priv, R15, 0);
+		start_timer(priv, priv->param.txdelay, 0);
+	}
+
+	/* Turn interrupts back on and free buffer */
+	spin_unlock_irqrestore(&priv->ring_lock, flags);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+
+static struct net_device_stats *scc_get_stats(struct net_device *dev)
+{
+	struct scc_priv *priv = dev->priv;
+
+	return &priv->stats;
+}
+
+
+static int scc_set_mac_address(struct net_device *dev, void *sa)
+{
+	memcpy(dev->dev_addr, ((struct sockaddr *) sa)->sa_data,
+	       dev->addr_len);
+	return 0;
+}
+
+
+static inline void tx_on(struct scc_priv *priv)
+{
+	int i, n;
+	unsigned long flags;
+
+	if (priv->param.dma >= 0) {
+		n = (priv->chip == Z85230) ? 3 : 1;
+		/* Program DMA controller */
+		flags = claim_dma_lock();
+		set_dma_mode(priv->param.dma, DMA_MODE_WRITE);
+		set_dma_addr(priv->param.dma,
+			     (int) priv->tx_buf[priv->tx_tail] + n);
+		set_dma_count(priv->param.dma,
+			      priv->tx_len[priv->tx_tail] - n);
+		release_dma_lock(flags);
+		/* Enable TX underrun interrupt */
+		write_scc(priv, R15, TxUIE);
+		/* Configure DREQ */
+		if (priv->type == TYPE_TWIN)
+			outb((priv->param.dma ==
+			      1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
+			     priv->card_base + TWIN_DMA_CFG);
+		else
+			write_scc(priv, R1,
+				  EXT_INT_ENAB | WT_FN_RDYFN |
+				  WT_RDY_ENAB);
+		/* Write first byte(s) */
+		spin_lock_irqsave(priv->register_lock, flags);
+		for (i = 0; i < n; i++)
+			write_scc_data(priv,
+				       priv->tx_buf[priv->tx_tail][i], 1);
+		enable_dma(priv->param.dma);
+		spin_unlock_irqrestore(priv->register_lock, flags);
+	} else {
+		write_scc(priv, R15, TxUIE);
+		write_scc(priv, R1,
+			  EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
+		tx_isr(priv);
+	}
+	/* Reset EOM latch if we do not have the AUTOEOM feature */
+	if (priv->chip == Z8530)
+		write_scc(priv, R0, RES_EOM_L);
+}
+
+
+static inline void rx_on(struct scc_priv *priv)
+{
+	unsigned long flags;
+
+	/* Clear RX FIFO */
+	while (read_scc(priv, R0) & Rx_CH_AV)
+		read_scc_data(priv);
+	priv->rx_over = 0;
+	if (priv->param.dma >= 0) {
+		/* Program DMA controller */
+		flags = claim_dma_lock();
+		set_dma_mode(priv->param.dma, DMA_MODE_READ);
+		set_dma_addr(priv->param.dma,
+			     (int) priv->rx_buf[priv->rx_head]);
+		set_dma_count(priv->param.dma, BUF_SIZE);
+		release_dma_lock(flags);
+		enable_dma(priv->param.dma);
+		/* Configure PackeTwin DMA */
+		if (priv->type == TYPE_TWIN) {
+			outb((priv->param.dma ==
+			      1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
+			     priv->card_base + TWIN_DMA_CFG);
+		}
+		/* Sp. cond. intr. only, ext int enable, RX DMA enable */
+		write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx |
+			  WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
+	} else {
+		/* Reset current frame */
+		priv->rx_ptr = 0;
+		/* Intr. on all Rx characters and Sp. cond., ext int enable */
+		write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
+			  WT_FN_RDYFN);
+	}
+	write_scc(priv, R0, ERR_RES);
+	write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+}
+
+
+static inline void rx_off(struct scc_priv *priv)
+{
+	/* Disable receiver */
+	write_scc(priv, R3, Rx8);
+	/* Disable DREQ / RX interrupt */
+	if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
+		outb(0, priv->card_base + TWIN_DMA_CFG);
+	else
+		write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+	/* Disable DMA */
+	if (priv->param.dma >= 0)
+		disable_dma(priv->param.dma);
+}
+
+
+static void start_timer(struct scc_priv *priv, int t, int r15)
+{
+	unsigned long flags;
+
+	outb(priv->tmr_mode, priv->tmr_ctrl);
+	if (t == 0) {
+		tm_isr(priv);
+	} else if (t > 0) {
+		save_flags(flags);
+		cli();
+		outb(t & 0xFF, priv->tmr_cnt);
+		outb((t >> 8) & 0xFF, priv->tmr_cnt);
+		if (priv->type != TYPE_TWIN) {
+			write_scc(priv, R15, r15 | CTSIE);
+			priv->rr0 |= CTS;
+		}
+		restore_flags(flags);
+	}
+}
+
+
+static inline unsigned char random(void)
+{
+	/* See "Numerical Recipes in C", second edition, p. 284 */
+	rand = rand * 1664525L + 1013904223L;
+	return (unsigned char) (rand >> 24);
+}
+
+static inline void z8530_isr(struct scc_info *info)
+{
+	int is, i = 100;
+
+	while ((is = read_scc(&info->priv[0], R3)) && i--) {
+		if (is & CHARxIP) {
+			rx_isr(&info->priv[0]);
+		} else if (is & CHATxIP) {
+			tx_isr(&info->priv[0]);
+		} else if (is & CHAEXT) {
+			es_isr(&info->priv[0]);
+		} else if (is & CHBRxIP) {
+			rx_isr(&info->priv[1]);
+		} else if (is & CHBTxIP) {
+			tx_isr(&info->priv[1]);
+		} else {
+			es_isr(&info->priv[1]);
+		}
+		write_scc(&info->priv[0], R0, RES_H_IUS);
+		i++;
+	}
+	if (i < 0) {
+		printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n",
+		       is);
+	}
+	/* Ok, no interrupts pending from this 8530. The INT line should
+	   be inactive now. */
+}
+
+
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct scc_info *info = dev_id;
+
+	spin_lock(info->priv[0].register_lock);
+	/* At this point interrupts are enabled, and the interrupt under service
+	   is already acknowledged, but masked off.
+
+	   Interrupt processing: We loop until we know that the IRQ line is
+	   low. If another positive edge occurs afterwards during the ISR,
+	   another interrupt will be triggered by the interrupt controller
+	   as soon as the IRQ level is enabled again (see asm/irq.h).
+
+	   Bottom-half handlers will be processed after scc_isr(). This is
+	   important, since we only have small ringbuffers and want new data
+	   to be fetched/delivered immediately. */
+
+	if (info->priv[0].type == TYPE_TWIN) {
+		int is, card_base = info->priv[0].card_base;
+		while ((is = ~inb(card_base + TWIN_INT_REG)) &
+		       TWIN_INT_MSK) {
+			if (is & TWIN_SCC_MSK) {
+				z8530_isr(info);
+			} else if (is & TWIN_TMR1_MSK) {
+				inb(card_base + TWIN_CLR_TMR1);
+				tm_isr(&info->priv[0]);
+			} else {
+				inb(card_base + TWIN_CLR_TMR2);
+				tm_isr(&info->priv[1]);
+			}
+		}
+	} else
+		z8530_isr(info);
+	spin_unlock(info->priv[0].register_lock);
+	return IRQ_HANDLED;
+}
+
+
+static void rx_isr(struct scc_priv *priv)
+{
+	if (priv->param.dma >= 0) {
+		/* Check special condition and perform error reset. See 2.4.7.5. */
+		special_condition(priv, read_scc(priv, R1));
+		write_scc(priv, R0, ERR_RES);
+	} else {
+		/* Check special condition for each character. Error reset not necessary.
+		   Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
+		int rc;
+		while (read_scc(priv, R0) & Rx_CH_AV) {
+			rc = read_scc(priv, R1);
+			if (priv->rx_ptr < BUF_SIZE)
+				priv->rx_buf[priv->rx_head][priv->
+							    rx_ptr++] =
+				    read_scc_data(priv);
+			else {
+				priv->rx_over = 2;
+				read_scc_data(priv);
+			}
+			special_condition(priv, rc);
+		}
+	}
+}
+
+
+static void special_condition(struct scc_priv *priv, int rc)
+{
+	int cb;
+	unsigned long flags;
+
+	/* See Figure 2-15. Only overrun and EOF need to be checked. */
+
+	if (rc & Rx_OVR) {
+		/* Receiver overrun */
+		priv->rx_over = 1;
+		if (priv->param.dma < 0)
+			write_scc(priv, R0, ERR_RES);
+	} else if (rc & END_FR) {
+		/* End of frame. Get byte count */
+		if (priv->param.dma >= 0) {
+			flags = claim_dma_lock();
+			cb = BUF_SIZE - get_dma_residue(priv->param.dma) -
+			    2;
+			release_dma_lock(flags);
+		} else {
+			cb = priv->rx_ptr - 2;
+		}
+		if (priv->rx_over) {
+			/* We had an overrun */
+			priv->stats.rx_errors++;
+			if (priv->rx_over == 2)
+				priv->stats.rx_length_errors++;
+			else
+				priv->stats.rx_fifo_errors++;
+			priv->rx_over = 0;
+		} else if (rc & CRC_ERR) {
+			/* Count invalid CRC only if packet length >= minimum */
+			if (cb >= 15) {
+				priv->stats.rx_errors++;
+				priv->stats.rx_crc_errors++;
+			}
+		} else {
+			if (cb >= 15) {
+				if (priv->rx_count < NUM_RX_BUF - 1) {
+					/* Put good frame in FIFO */
+					priv->rx_len[priv->rx_head] = cb;
+					priv->rx_head =
+					    (priv->rx_head +
+					     1) % NUM_RX_BUF;
+					priv->rx_count++;
+					schedule_work(&priv->rx_work);
+				} else {
+					priv->stats.rx_errors++;
+					priv->stats.rx_over_errors++;
+				}
+			}
+		}
+		/* Get ready for new frame */
+		if (priv->param.dma >= 0) {
+			flags = claim_dma_lock();
+			set_dma_addr(priv->param.dma,
+				     (int) priv->rx_buf[priv->rx_head]);
+			set_dma_count(priv->param.dma, BUF_SIZE);
+			release_dma_lock(flags);
+		} else {
+			priv->rx_ptr = 0;
+		}
+	}
+}
+
+
+static void rx_bh(void *arg)
+{
+	struct scc_priv *priv = arg;
+	int i = priv->rx_tail;
+	int cb;
+	unsigned long flags;
+	struct sk_buff *skb;
+	unsigned char *data;
+
+	spin_lock_irqsave(&priv->ring_lock, flags);
+	while (priv->rx_count) {
+		spin_unlock_irqrestore(&priv->ring_lock, flags);
+		cb = priv->rx_len[i];
+		/* Allocate buffer */
+		skb = dev_alloc_skb(cb + 1);
+		if (skb == NULL) {
+			/* Drop packet */
+			priv->stats.rx_dropped++;
+		} else {
+			/* Fill buffer */
+			data = skb_put(skb, cb + 1);
+			data[0] = 0;
+			memcpy(&data[1], priv->rx_buf[i], cb);
+			skb->protocol = ax25_type_trans(skb, priv->dev);
+			netif_rx(skb);
+			priv->dev->last_rx = jiffies;
+			priv->stats.rx_packets++;
+			priv->stats.rx_bytes += cb;
+		}
+		spin_lock_irqsave(&priv->ring_lock, flags);
+		/* Move tail */
+		priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
+		priv->rx_count--;
+	}
+	spin_unlock_irqrestore(&priv->ring_lock, flags);
+}
+
+
+static void tx_isr(struct scc_priv *priv)
+{
+	int i = priv->tx_tail, p = priv->tx_ptr;
+
+	/* Suspend TX interrupts if we don't want to send anything.
+	   See Figure 2-22. */
+	if (p == priv->tx_len[i]) {
+		write_scc(priv, R0, RES_Tx_P);
+		return;
+	}
+
+	/* Write characters */
+	while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
+		write_scc_data(priv, priv->tx_buf[i][p++], 0);
+	}
+
+	/* Reset EOM latch of Z8530 */
+	if (!priv->tx_ptr && p && priv->chip == Z8530)
+		write_scc(priv, R0, RES_EOM_L);
+
+	priv->tx_ptr = p;
+}
+
+
+static void es_isr(struct scc_priv *priv)
+{
+	int i, rr0, drr0, res;
+	unsigned long flags;
+
+	/* Read status, reset interrupt bit (open latches) */
+	rr0 = read_scc(priv, R0);
+	write_scc(priv, R0, RES_EXT_INT);
+	drr0 = priv->rr0 ^ rr0;
+	priv->rr0 = rr0;
+
+	/* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since
+	   it might have already been cleared again by AUTOEOM. */
+	if (priv->state == TX_DATA) {
+		/* Get remaining bytes */
+		i = priv->tx_tail;
+		if (priv->param.dma >= 0) {
+			disable_dma(priv->param.dma);
+			flags = claim_dma_lock();
+			res = get_dma_residue(priv->param.dma);
+			release_dma_lock(flags);
+		} else {
+			res = priv->tx_len[i] - priv->tx_ptr;
+			priv->tx_ptr = 0;
+		}
+		/* Disable DREQ / TX interrupt */
+		if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
+			outb(0, priv->card_base + TWIN_DMA_CFG);
+		else
+			write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+		if (res) {
+			/* Update packet statistics */
+			priv->stats.tx_errors++;
+			priv->stats.tx_fifo_errors++;
+			/* Other underrun interrupts may already be waiting */
+			write_scc(priv, R0, RES_EXT_INT);
+			write_scc(priv, R0, RES_EXT_INT);
+		} else {
+			/* Update packet statistics */
+			priv->stats.tx_packets++;
+			priv->stats.tx_bytes += priv->tx_len[i];
+			/* Remove frame from FIFO */
+			priv->tx_tail = (i + 1) % NUM_TX_BUF;
+			priv->tx_count--;
+			/* Inform upper layers */
+			netif_wake_queue(priv->dev);
+		}
+		/* Switch state */
+		write_scc(priv, R15, 0);
+		if (priv->tx_count &&
+		    (jiffies - priv->tx_start) < priv->param.txtimeout) {
+			priv->state = TX_PAUSE;
+			start_timer(priv, priv->param.txpause, 0);
+		} else {
+			priv->state = TX_TAIL;
+			start_timer(priv, priv->param.txtail, 0);
+		}
+	}
+
+	/* DCD transition */
+	if (drr0 & DCD) {
+		if (rr0 & DCD) {
+			switch (priv->state) {
+			case IDLE:
+			case WAIT:
+				priv->state = DCD_ON;
+				write_scc(priv, R15, 0);
+				start_timer(priv, priv->param.dcdon, 0);
+			}
+		} else {
+			switch (priv->state) {
+			case RX_ON:
+				rx_off(priv);
+				priv->state = DCD_OFF;
+				write_scc(priv, R15, 0);
+				start_timer(priv, priv->param.dcdoff, 0);
+			}
+		}
+	}
+
+	/* CTS transition */
+	if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN)
+		tm_isr(priv);
+
+}
+
+
+static void tm_isr(struct scc_priv *priv)
+{
+	switch (priv->state) {
+	case TX_HEAD:
+	case TX_PAUSE:
+		tx_on(priv);
+		priv->state = TX_DATA;
+		break;
+	case TX_TAIL:
+		write_scc(priv, R5, TxCRC_ENAB | Tx8);
+		priv->state = RTS_OFF;
+		if (priv->type != TYPE_TWIN)
+			write_scc(priv, R15, 0);
+		start_timer(priv, priv->param.rtsoff, 0);
+		break;
+	case RTS_OFF:
+		write_scc(priv, R15, DCDIE);
+		priv->rr0 = read_scc(priv, R0);
+		if (priv->rr0 & DCD) {
+			priv->stats.collisions++;
+			rx_on(priv);
+			priv->state = RX_ON;
+		} else {
+			priv->state = WAIT;
+			start_timer(priv, priv->param.waittime, DCDIE);
+		}
+		break;
+	case WAIT:
+		if (priv->tx_count) {
+			priv->state = TX_HEAD;
+			priv->tx_start = jiffies;
+			write_scc(priv, R5,
+				  TxCRC_ENAB | RTS | TxENAB | Tx8);
+			write_scc(priv, R15, 0);
+			start_timer(priv, priv->param.txdelay, 0);
+		} else {
+			priv->state = IDLE;
+			if (priv->type != TYPE_TWIN)
+				write_scc(priv, R15, DCDIE);
+		}
+		break;
+	case DCD_ON:
+	case DCD_OFF:
+		write_scc(priv, R15, DCDIE);
+		priv->rr0 = read_scc(priv, R0);
+		if (priv->rr0 & DCD) {
+			rx_on(priv);
+			priv->state = RX_ON;
+		} else {
+			priv->state = WAIT;
+			start_timer(priv,
+				    random() / priv->param.persist *
+				    priv->param.slottime, DCDIE);
+		}
+		break;
 	}
-      }
-    }
-    /* Get ready for new frame */
-    if (priv->param.dma >= 0) {
-      flags = claim_dma_lock();
-      set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]);
-      set_dma_count(priv->param.dma, BUF_SIZE);
-      release_dma_lock(flags);
-    } else {
-      priv->rx_ptr = 0;
-    }
-  }
-}
-
-
-static void rx_bh(void *arg) {
-  struct scc_priv *priv = arg;
-  int i = priv->rx_tail;
-  int cb;
-  unsigned long flags;
-  struct sk_buff *skb;
-  unsigned char *data;
-
-  spin_lock_irqsave(&priv->ring_lock, flags);
-  while (priv->rx_count) {
-    spin_unlock_irqrestore(&priv->ring_lock, flags);
-    cb = priv->rx_len[i];
-    /* Allocate buffer */
-    skb = dev_alloc_skb(cb+1);
-    if (skb == NULL) {
-      /* Drop packet */
-      priv->stats.rx_dropped++;
-    } else {
-      /* Fill buffer */
-      data = skb_put(skb, cb+1);
-      data[0] = 0;
-      memcpy(&data[1], priv->rx_buf[i], cb);
-      skb->dev = priv->dev;
-      skb->protocol = ntohs(ETH_P_AX25);
-      skb->mac.raw = skb->data;
-      netif_rx(skb);
-      priv->dev->last_rx = jiffies;
-      priv->stats.rx_packets++;
-      priv->stats.rx_bytes += cb;
-    }
-    spin_lock_irqsave(&priv->ring_lock, flags);
-    /* Move tail */
-    priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
-    priv->rx_count--;
-  }
-  spin_unlock_irqrestore(&priv->ring_lock, flags);
-}
-
-
-static void tx_isr(struct scc_priv *priv) {
-  int i = priv->tx_tail, p = priv->tx_ptr;
-
-  /* Suspend TX interrupts if we don't want to send anything.
-     See Figure 2-22. */
-  if (p ==  priv->tx_len[i]) {
-    write_scc(priv, R0, RES_Tx_P);
-    return;
-  }
-
-  /* Write characters */
-  while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
-    write_scc_data(priv, priv->tx_buf[i][p++], 0);
-  }
-
-  /* Reset EOM latch of Z8530 */
-  if (!priv->tx_ptr && p && priv->chip == Z8530)
-    write_scc(priv, R0, RES_EOM_L);
-
-  priv->tx_ptr = p;
-}
-
-
-static void es_isr(struct scc_priv *priv) {
-  int i, rr0, drr0, res;
-  unsigned long flags;
-
-  /* Read status, reset interrupt bit (open latches) */
-  rr0 = read_scc(priv, R0);
-  write_scc(priv, R0, RES_EXT_INT);
-  drr0 = priv->rr0 ^ rr0;
-  priv->rr0 = rr0;
-
-  /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since
-     it might have already been cleared again by AUTOEOM. */
-  if (priv->state == TX_DATA) {
-    /* Get remaining bytes */
-    i = priv->tx_tail;
-    if (priv->param.dma >= 0) {
-      disable_dma(priv->param.dma);
-      flags = claim_dma_lock();
-      res = get_dma_residue(priv->param.dma);
-      release_dma_lock(flags);
-    } else {
-      res = priv->tx_len[i] - priv->tx_ptr;
-      priv->tx_ptr = 0;
-    }
-    /* Disable DREQ / TX interrupt */
-    if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
-      outb(0, priv->card_base + TWIN_DMA_CFG);
-    else
-      write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
-    if (res) {
-      /* Update packet statistics */
-      priv->stats.tx_errors++;
-      priv->stats.tx_fifo_errors++;
-      /* Other underrun interrupts may already be waiting */
-      write_scc(priv, R0, RES_EXT_INT);
-      write_scc(priv, R0, RES_EXT_INT);
-    } else {
-      /* Update packet statistics */
-      priv->stats.tx_packets++;
-      priv->stats.tx_bytes += priv->tx_len[i];
-      /* Remove frame from FIFO */
-      priv->tx_tail = (i + 1) % NUM_TX_BUF;
-      priv->tx_count--;
-      /* Inform upper layers */
-      netif_wake_queue(priv->dev);
-    }
-    /* Switch state */
-    write_scc(priv, R15, 0);
-    if (priv->tx_count &&
-	(jiffies - priv->tx_start) < priv->param.txtimeout) {
-      priv->state = TX_PAUSE;
-      start_timer(priv, priv->param.txpause, 0);
-    } else {
-      priv->state = TX_TAIL;
-      start_timer(priv, priv->param.txtail, 0);
-    }
-  }
-
-  /* DCD transition */
-  if (drr0 & DCD) {
-    if (rr0 & DCD) {
-      switch (priv->state) {
-      case IDLE:
-      case WAIT:
-	priv->state = DCD_ON;
-	write_scc(priv, R15, 0);
-	start_timer(priv, priv->param.dcdon, 0);
-      }
-    } else {
-      switch (priv->state) {
-      case RX_ON:
-	rx_off(priv);
-	priv->state = DCD_OFF;
-	write_scc(priv, R15, 0);
-	start_timer(priv, priv->param.dcdoff, 0);
-      }
-    }
-  }
-
-  /* CTS transition */
-  if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN)
-    tm_isr(priv);
-
-}
-
-
-static void tm_isr(struct scc_priv *priv) {
-  switch (priv->state) {
-  case TX_HEAD:
-  case TX_PAUSE:
-    tx_on(priv);
-    priv->state = TX_DATA;
-    break;
-  case TX_TAIL:
-    write_scc(priv, R5, TxCRC_ENAB | Tx8);
-    priv->state = RTS_OFF;
-    if (priv->type != TYPE_TWIN) write_scc(priv, R15, 0);
-    start_timer(priv, priv->param.rtsoff, 0);
-    break;
-  case RTS_OFF:
-    write_scc(priv, R15, DCDIE);
-    priv->rr0 = read_scc(priv, R0);
-    if (priv->rr0 & DCD) {
-      priv->stats.collisions++;
-      rx_on(priv);
-      priv->state = RX_ON;
-    } else {
-      priv->state = WAIT;
-      start_timer(priv, priv->param.waittime, DCDIE);
-    }
-    break;
-  case WAIT:
-    if (priv->tx_count) {
-      priv->state = TX_HEAD;
-      priv->tx_start = jiffies;
-      write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
-      write_scc(priv, R15, 0);
-      start_timer(priv, priv->param.txdelay, 0);
-    } else {
-      priv->state = IDLE;
-      if (priv->type != TYPE_TWIN) write_scc(priv, R15, DCDIE);
-    }
-    break;
-  case DCD_ON:
-  case DCD_OFF:
-    write_scc(priv, R15, DCDIE);
-    priv->rr0 = read_scc(priv, R0);
-    if (priv->rr0 & DCD) {
-      rx_on(priv);
-      priv->state = RX_ON;
-    } else {
-      priv->state = WAIT;
-      start_timer(priv,
-		  random()/priv->param.persist*priv->param.slottime,
-		  DCDIE);
-    }
-    break;
-  }
 }
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -174,12 +174,10 @@ static void hdlc_rx_flag(struct net_devi
 		s->stats.rx_dropped++;
 		return;
 	}
-	skb->dev = dev;
 	cp = skb_put(skb, pkt_len);
 	*cp++ = 0; /* KISS kludge */
 	memcpy(cp, s->hdlcrx.buffer, pkt_len - 1);
-	skb->protocol = htons(ETH_P_AX25);
-	skb->mac.raw = skb->data;
+	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
 	dev->last_rx = jiffies;
 	s->stats.rx_packets++;
@@ -427,27 +425,10 @@ void hdlcdrv_arbitrate(struct net_device
  * ===================== network driver interface =========================
  */
 
-static inline int hdlcdrv_paranoia_check(struct net_device *dev,
-					const char *routine)
-{
-	if (!dev || !dev->priv || 
-	    ((struct hdlcdrv_state *)dev->priv)->magic != HDLCDRV_MAGIC) {
-		printk(KERN_ERR "hdlcdrv: bad magic number for hdlcdrv_state "
-		       "struct in routine %s\n", routine);
-		return 1;
-	}
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
 static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct hdlcdrv_state *sm;
+	struct hdlcdrv_state *sm = netdev_priv(dev);
 
-	if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet"))
-		return 0;
-	sm = (struct hdlcdrv_state *)dev->priv;
 	if (skb->data[0] != 0) {
 		do_kiss_params(sm, skb->data, skb->len);
 		dev_kfree_skb(skb);
@@ -475,11 +456,8 @@ static int hdlcdrv_set_mac_address(struc
 
 static struct net_device_stats *hdlcdrv_get_stats(struct net_device *dev)
 {
-	struct hdlcdrv_state *sm;
+	struct hdlcdrv_state *sm = netdev_priv(dev);
 
-	if (hdlcdrv_paranoia_check(dev, "hdlcdrv_get_stats"))
-		return NULL;
-	sm = (struct hdlcdrv_state *)dev->priv;
 	/* 
 	 * Get the current statistics.  This may be called with the
 	 * card open or closed. 
@@ -499,13 +477,9 @@ static struct net_device_stats *hdlcdrv_
 
 static int hdlcdrv_open(struct net_device *dev)
 {
-	struct hdlcdrv_state *s;
+	struct hdlcdrv_state *s = netdev_priv(dev);
 	int i;
 
-	if (hdlcdrv_paranoia_check(dev, "hdlcdrv_open"))
-		return -EINVAL;
-	s = (struct hdlcdrv_state *)dev->priv;
-
 	if (!s->ops || !s->ops->open)
 		return -ENODEV;
 
@@ -540,13 +514,9 @@ static int hdlcdrv_open(struct net_devic
 
 static int hdlcdrv_close(struct net_device *dev)
 {
-	struct hdlcdrv_state *s;
+	struct hdlcdrv_state *s = netdev_priv(dev);
 	int i = 0;
 
-	if (hdlcdrv_paranoia_check(dev, "hdlcdrv_close"))
-		return -EINVAL;
-	s = (struct hdlcdrv_state *)dev->priv;
-
 	netif_stop_queue(dev);
 
 	if (s->ops && s->ops->close)
@@ -562,12 +532,8 @@ static int hdlcdrv_close(struct net_devi
 
 static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct hdlcdrv_state *s;
+	struct hdlcdrv_state *s = netdev_priv(dev);
 	struct hdlcdrv_ioctl bi;
-		
-	if (hdlcdrv_paranoia_check(dev, "hdlcdrv_ioctl"))
-		return -EINVAL;
-	s = (struct hdlcdrv_state *)dev->priv;
 
 	if (cmd != SIOCDEVPRIVATE) {
 		if (s->ops && s->ops->ioctl)
@@ -698,7 +664,7 @@ static void hdlcdrv_setup(struct net_dev
 	static const struct hdlcdrv_channel_params dflt_ch_params = { 
 		20, 2, 10, 40, 0 
 	};
-	struct hdlcdrv_state *s = dev->priv;
+	struct hdlcdrv_state *s = netdev_priv(dev);
 
 	/*
 	 * initialize the hdlcdrv_state struct
@@ -782,7 +748,7 @@ struct net_device *hdlcdrv_register(cons
 	/*
 	 * initialize part of the hdlcdrv_state struct
 	 */
-	s = dev->priv;
+	s = netdev_priv(dev);
 	s->magic = HDLCDRV_MAGIC;
 	s->ops = ops;
 	dev->base_addr = baseaddr;
@@ -803,7 +769,7 @@ struct net_device *hdlcdrv_register(cons
 
 void hdlcdrv_unregister(struct net_device *dev) 
 {
-	struct hdlcdrv_state *s = dev->priv;
+	struct hdlcdrv_state *s = netdev_priv(dev);
 
 	BUG_ON(s->magic != HDLCDRV_MAGIC);
 
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -332,12 +332,10 @@ static void ax_bump(struct ax_disp *ax)
 		return;
 	}
 
-	skb->dev      = ax->dev;
 	spin_lock_bh(&ax->buflock);
 	memcpy(skb_put(skb,count), ax->rbuff, count);
 	spin_unlock_bh(&ax->buflock);
-	skb->mac.raw  = skb->data;
-	skb->protocol = htons(ETH_P_AX25);
+	skb->protocol = ax25_type_trans(skb, ax->dev);
 	netif_rx(skb);
 	ax->dev->last_rx = jiffies;
 	ax->rx_packets++;
@@ -419,7 +417,7 @@ static void ax25_write_wakeup(struct tty
 /* Encapsulate an AX.25 packet and kick it into a TTY queue. */
 static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 
 	if (!netif_running(dev))  {
 		printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
@@ -483,7 +481,7 @@ static int ax_rebuild_header(struct sk_b
 /* Open the low-level part of the AX25 channel. Easy! */
 static int ax_open(struct net_device *dev)
 {
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 	unsigned long len;
 
 	if (ax->tty == NULL)
@@ -534,7 +532,7 @@ norbuff:
 /* Close the low-level part of the AX25 channel. Easy! */
 static int ax_close(struct net_device *dev)
 {
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 
 	if (ax->tty == NULL)
 		return -EBUSY;
@@ -634,7 +632,7 @@ static void ax25_close(struct tty_struct
 static struct net_device_stats *ax_get_stats(struct net_device *dev)
 {
 	static struct net_device_stats stats;
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 
 	memset(&stats, 0, sizeof(struct net_device_stats));
 
@@ -827,7 +825,7 @@ static int ax25_disp_ioctl(struct tty_st
 
 static int ax_open_dev(struct net_device *dev)
 {
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 
 	if (ax->tty == NULL)
 		return -ENODEV;
@@ -839,7 +837,7 @@ static int ax_open_dev(struct net_device
 /* Initialize the driver.  Called by network startup. */
 static int ax25_init(struct net_device *dev)
 {
-	struct ax_disp *ax = (struct ax_disp *) dev->priv;
+	struct ax_disp *ax = netdev_priv(dev);
 
 	static char ax25_bcast[AX25_ADDR_LEN] =
 		{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1630,10 +1630,7 @@ static void scc_net_rx(struct scc_channe
 	scc->dev_stat.rx_packets++;
 	scc->dev_stat.rx_bytes += skb->len;
 
-	skb->dev      = scc->dev;
-	skb->protocol = htons(ETH_P_AX25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
+	skb->protocol = ax25_type_trans(skb, scc->dev);
 	
 	netif_rx(skb);
 	scc->dev->last_rx = jiffies;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -442,7 +442,7 @@ static int fpga_download(int iobase, int
 
 static void yam_set_uart(struct net_device *dev)
 {
-	struct yam_port *yp = (struct yam_port *) dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 	int divisor = 115200 / yp->baudrate;
 
 	outb(0, IER(dev->base_addr));
@@ -522,12 +522,10 @@ static inline void yam_rx_flag(struct ne
 				++yp->stats.rx_dropped;
 			} else {
 				unsigned char *cp;
-				skb->dev = dev;
 				cp = skb_put(skb, pkt_len);
 				*cp++ = 0;		/* KISS kludge */
 				memcpy(cp, yp->rx_buf, pkt_len - 1);
-				skb->protocol = htons(ETH_P_AX25);
-				skb->mac.raw = skb->data;
+				skb->protocol = ax25_type_trans(skb, dev);
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				++yp->stats.rx_packets;
@@ -565,7 +563,7 @@ static void ptt_off(struct net_device *d
 
 static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct yam_port *yp = dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 
 	skb_queue_tail(&yp->send_queue, skb);
 	dev->trans_start = jiffies;
@@ -592,12 +590,11 @@ static inline unsigned short random_num(
 
 static void yam_arbitrate(struct net_device *dev)
 {
-	struct yam_port *yp = dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 
-	if (!yp || yp->magic != YAM_MAGIC
-		|| yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) {
+	if (yp->magic != YAM_MAGIC || yp->tx_state != TX_OFF ||
+	    skb_queue_empty(&yp->send_queue))
 		return;
-	}
 	/* tx_state is TX_OFF and there is data to send */
 
 	if (yp->dupmode) {
@@ -725,7 +722,7 @@ static irqreturn_t yam_interrupt(int irq
 
 	for (i = 0; i < NR_PORTS; i++) {
 		dev = yam_devs[i];
-		yp = dev->priv;
+		yp = netdev_priv(dev);
 
 		if (!netif_running(dev))
 			continue;
@@ -784,8 +781,8 @@ static void yam_seq_stop(struct seq_file
 
 static int yam_seq_show(struct seq_file *seq, void *v)
 {
-	const struct net_device *dev = v;
-	const struct yam_port *yp = dev->priv;
+	struct net_device *dev = v;
+	const struct yam_port *yp = netdev_priv(dev);
 
 	seq_printf(seq, "Device %s\n", dev->name);
 	seq_printf(seq, "  Up       %d\n", netif_running(dev));
@@ -838,10 +835,10 @@ static struct net_device_stats *yam_get_
 {
 	struct yam_port *yp;
 
-	if (!dev || !dev->priv)
+	if (!dev)
 		return NULL;
 
-	yp = (struct yam_port *) dev->priv;
+	yp = netdev_priv(dev);
 	if (yp->magic != YAM_MAGIC)
 		return NULL;
 
@@ -856,14 +853,14 @@ static struct net_device_stats *yam_get_
 
 static int yam_open(struct net_device *dev)
 {
-	struct yam_port *yp = (struct yam_port *) dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 	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);
 
-	if (!dev || !yp || !yp->bitrate)
+	if (!dev || !yp->bitrate)
 		return -ENXIO;
 	if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
 		dev->irq < 2 || dev->irq > 15) {
@@ -900,7 +897,7 @@ static int yam_open(struct net_device *d
 	/* Reset overruns for all ports - FPGA programming makes overruns */
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = yam_devs[i];
-		struct yam_port *yp = dev->priv;
+		struct yam_port *yp = netdev_priv(dev);
 		inb(LSR(dev->base_addr));
 		yp->stats.rx_fifo_errors = 0;
 	}
@@ -919,10 +916,11 @@ out_release_base:
 static int yam_close(struct net_device *dev)
 {
 	struct sk_buff *skb;
-	struct yam_port *yp = (struct yam_port *) dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 
-	if (!dev || !yp)
+	if (!dev)
 		return -EINVAL;
+
 	/*
 	 * disable interrupts
 	 */
@@ -944,7 +942,7 @@ static int yam_close(struct net_device *
 
 static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct yam_port *yp = (struct yam_port *) dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 	struct yamdrv_ioctl_cfg yi;
 	struct yamdrv_ioctl_mcs *ym;
 	int ioctl_cmd;
@@ -952,7 +950,7 @@ static int yam_ioctl(struct net_device *
 	if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int)))
 		 return -EFAULT;
 
-	if (yp == NULL || yp->magic != YAM_MAGIC)
+	if (yp->magic != YAM_MAGIC)
 		return -EINVAL;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -1091,7 +1089,7 @@ static int yam_set_mac_address(struct ne
 
 static void yam_setup(struct net_device *dev)
 {
-	struct yam_port *yp = dev->priv;
+	struct yam_port *yp = netdev_priv(dev);
 
 	yp->magic = YAM_MAGIC;
 	yp->bitrate = DEFAULT_BITRATE;
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -13,8 +13,8 @@
 ** This driver has only been tested with
 ** -- HP J2585B 10/100 Mbit/s PCI Busmaster
 ** -- HP J2585A 10/100 Mbit/s PCI 
-** -- HP J2970  10 Mbit/s PCI Combo 10base-T/BNC
-** -- HP J2973  10 Mbit/s PCI 10base-T
+** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC
+** -- HP J2973A 10 Mbit/s PCI 10base-T
 ** -- HP J2573  10/100 ISA
 ** -- Compex ReadyLink ENET100-VG4  10/100 Mbit/s PCI / EISA
 ** -- Compex FreedomLine 100/VG  10/100 Mbit/s ISA / EISA / PCI
diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h
--- a/drivers/net/ibm_emac/ibm_emac.h
+++ b/drivers/net/ibm_emac/ibm_emac.h
@@ -237,6 +237,10 @@ typedef struct emac_regs {
 #define EMAC_RWMR_DEFAULT		0x1000a200
 #define EMAC_TMR0_DEFAULT		EMAC_TMR0_TFAE_2_32
 #define EMAC_TMR1_DEFAULT		0xa00f0000
+#elif defined(CONFIG_440SP)
+#define EMAC_RWMR_DEFAULT		0x08002000
+#define EMAC_TMR0_DEFAULT		EMAC_TMR0_TFAE_128_2048
+#define EMAC_TMR1_DEFAULT		0xf8200000
 #else
 #define EMAC_RWMR_DEFAULT		0x0f002000
 #define EMAC_TMR0_DEFAULT		0x00000000
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -1041,7 +1041,7 @@ static int emac_adjust_to_link(struct oc
 	/* set speed (default is 10Mb) */
 	switch (speed) {
 	case SPEED_1000:
-		mode_reg |= EMAC_M1_JUMBO_ENABLE | EMAC_M1_RFS_16K;
+		mode_reg |= EMAC_M1_RFS_16K;
 		if (fep->rgmii_dev) {
 			struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev);
 
@@ -1118,6 +1118,7 @@ static int emac_change_mtu(struct net_de
 {
 	struct ocp_enet_private *fep = dev->priv;
 	int old_mtu = dev->mtu;
+	unsigned long mode_reg;
 	emac_t *emacp = fep->emacp;
 	u32 em0mr0;
 	int i, full;
@@ -1160,10 +1161,17 @@ static int emac_change_mtu(struct net_de
 			fep->rx_skb[i] = NULL;
 		}
 
-		/* Set new rx_buffer_size and advertise new mtu */
-		fep->rx_buffer_size =
-		    new_mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE;
+		/* Set new rx_buffer_size, jumbo cap, and advertise new mtu */
+		mode_reg = in_be32(&emacp->em0mr1);
+		if (new_mtu > ENET_DEF_MTU_SIZE) {
+			mode_reg |= EMAC_M1_JUMBO_ENABLE;
+			fep->rx_buffer_size = EMAC_MAX_FRAME;
+		} else {
+			mode_reg &= ~EMAC_M1_JUMBO_ENABLE;
+			fep->rx_buffer_size = ENET_DEF_BUF_SIZE;
+		}
 		dev->mtu = new_mtu;
+		out_be32(&emacp->em0mr1, mode_reg);
 
 		/* Re-init rx skbs */
 		fep->rx_slot = 0;
@@ -1587,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_o
 static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct ocp_enet_private *fep = dev->priv;
-	uint *data = (uint *) & rq->ifr_ifru;
+	uint16_t *data = (uint16_t *) & rq->ifr_ifru;
 
 	switch (cmd) {
 	case SIOCGMIIPHY:
diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h
--- a/drivers/net/ibm_emac/ibm_emac_core.h
+++ b/drivers/net/ibm_emac/ibm_emac_core.h
@@ -77,6 +77,8 @@
 
 #define ENET_HEADER_SIZE	14
 #define ENET_FCS_SIZE		4
+#define ENET_DEF_MTU_SIZE	1500
+#define ENET_DEF_BUF_SIZE	(ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE)
 #define EMAC_MIN_FRAME		64
 #define EMAC_MAX_FRAME		9018
 #define EMAC_MIN_MTU		(EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE)
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -133,13 +133,14 @@ static void dumpregs(struct net_device *
 
 static void dumpmem(struct net_device *dev, u32 start, u32 len)
 {
+	ibmlana_priv *priv = netdev_priv(dev);
 	int z;
 
 	printk("Address %04x:\n", start);
 	for (z = 0; z < len; z++) {
 		if ((z & 15) == 0)
 			printk("%04x:", z);
-		printk(" %02x", isa_readb(dev->mem_start + start + z));
+		printk(" %02x", readb(priv->base + start + z));
 		if ((z & 15) == 15)
 			printk("\n");
 	}
@@ -231,7 +232,7 @@ static void ResetBoard(struct net_device
 
 static void InitDscrs(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	u32 addr, baddr, raddr;
 	int z;
 	tda_t tda;
@@ -240,8 +241,8 @@ static void InitDscrs(struct net_device 
 
 	/* initialize RAM */
 
-	isa_memset_io(dev->mem_start, 0xaa,
-		      dev->mem_start - dev->mem_start);
+	memset_io(priv->base, 0xaa,
+		      dev->mem_start - dev->mem_start);	/* XXX: typo? */
 
 	/* setup n TX descriptors - independent of RAM size */
 
@@ -260,7 +261,7 @@ static void InitDscrs(struct net_device 
 		else
 			tda.link = addr + sizeof(tda_t);
 		tda.link |= 1;
-		isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t));
+		memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
 		addr += sizeof(tda_t);
 		baddr += PKTSIZE;
 	}
@@ -280,7 +281,7 @@ static void InitDscrs(struct net_device 
 		rra.starthi = 0;
 		rra.cntlo = PKTSIZE >> 1;
 		rra.cnthi = 0;
-		isa_memcpy_toio(dev->mem_start + raddr, &rra, sizeof(rra_t));
+		memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
 
 		rda.status = 0;
 		rda.length = 0;
@@ -292,7 +293,7 @@ static void InitDscrs(struct net_device 
 		else
 			rda.link = 1;
 		rda.inuse = 1;
-		isa_memcpy_toio(dev->mem_start + addr, &rda, sizeof(rda_t));
+		memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
 
 		baddr += PKTSIZE;
 		raddr += sizeof(rra_t);
@@ -313,7 +314,7 @@ static void InitDscrs(struct net_device 
 
 static int InitSONIC(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 
 	/* set up start & end of resource area */
 
@@ -379,6 +380,7 @@ static void putcam(camentry_t * cams, in
 
 static void InitBoard(struct net_device *dev)
 {
+	ibmlana_priv *priv = netdev_priv(dev);
 	int camcnt;
 	camentry_t cams[16];
 	u32 cammask;
@@ -429,8 +431,8 @@ static void InitBoard(struct net_device 
 
 	/* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
 
-	isa_memcpy_toio(dev->mem_start, cams, sizeof(camentry_t) * camcnt);
-	isa_memcpy_toio(dev->mem_start + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
+	memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
+	memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
 
 #ifdef DEBUG
 	printk("CAM setup:\n");
@@ -520,7 +522,7 @@ static void InitBoard(struct net_device 
 
 static void StartTx(struct net_device *dev, int descr)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	int addr;
 
 	addr = priv->tdastart + (descr * sizeof(tda_t));
@@ -543,7 +545,7 @@ static void StartTx(struct net_device *d
 
 static void irqrbe_handler(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 
 	/* point the SONIC back to the RRA start */
 
@@ -555,7 +557,7 @@ static void irqrbe_handler(struct net_de
 
 static void irqrx_handler(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	rda_t rda;
 	u32 rdaaddr, lrdaaddr;
 
@@ -566,7 +568,7 @@ static void irqrx_handler(struct net_dev
 
 		rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
 		lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
-		isa_memcpy_fromio(&rda, dev->mem_start + rdaaddr, sizeof(rda_t));
+		memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
 
 		/* iron out upper word halves of fields we use - SONIC will duplicate 
 		   bits 0..15 to 16..31 */
@@ -593,8 +595,8 @@ static void irqrx_handler(struct net_dev
 			else {
 				/* copy out data */
 
-				isa_memcpy_fromio(skb_put(skb, rda.length),
-					       dev->mem_start +
+				memcpy_fromio(skb_put(skb, rda.length),
+					       priv->base +
 					       rda.startlo, rda.length);
 
 				/* set up skb fields */
@@ -627,14 +629,14 @@ static void irqrx_handler(struct net_dev
 
 		rda.link = 1;
 		rda.inuse = 1;
-		isa_memcpy_toio(dev->mem_start + rdaaddr, &rda,
+		memcpy_toio(priv->base + rdaaddr, &rda,
 			     sizeof(rda_t));
 
 		/* set up link and EOL = 0 in currently last descriptor. Only write
 		   the link field since the SONIC may currently already access the
 		   other fields. */
 
-		isa_memcpy_toio(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4);
+		memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
 
 		/* advance indices */
 
@@ -648,11 +650,11 @@ static void irqrx_handler(struct net_dev
 
 static void irqtx_handler(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	tda_t tda;
 
 	/* fetch descriptor (we forgot the size ;-) */
-	isa_memcpy_fromio(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
+	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
 
 	/* update statistics */
 	priv->stat.tx_packets++;
@@ -672,11 +674,11 @@ static void irqtx_handler(struct net_dev
 
 static void irqtxerr_handler(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	tda_t tda;
 
 	/* fetch descriptor to check status */
-	isa_memcpy_fromio(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
+	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
 
 	/* update statistics */
 	priv->stat.tx_errors++;
@@ -753,9 +755,7 @@ static int ibmlana_getinfo(char *buf, in
 
 	if (dev == NULL)
 		return len;
-	if (dev->priv == NULL)
-		return len;
-	priv = (ibmlana_priv *) dev->priv;
+	priv = netdev_priv(dev);
 
 	/* print info */
 
@@ -778,7 +778,7 @@ static int ibmlana_getinfo(char *buf, in
 static int ibmlana_open(struct net_device *dev)
 {
 	int result;
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 
 	/* register resources - only necessary for IRQ */
 
@@ -814,7 +814,7 @@ static int ibmlana_close(struct net_devi
 
 static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	int retval = 0, tmplen, addr;
 	unsigned long flags;
 	tda_t tda;
@@ -834,7 +834,7 @@ static int ibmlana_tx(struct sk_buff *sk
 	if (tmplen < 60)
 		tmplen = 60;
 	baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
-	isa_memcpy_toio(dev->mem_start + baddr, skb->data, skb->len);
+	memcpy_toio(priv->base + baddr, skb->data, skb->len);
 
 	/* copy filler into RAM - in case we're filling up... 
 	   we're filling a bit more than necessary, but that doesn't harm
@@ -846,16 +846,16 @@ static int ibmlana_tx(struct sk_buff *sk
 		unsigned int destoffs = skb->len, l = strlen(fill);
 
 		while (destoffs < tmplen) {
-			isa_memcpy_toio(dev->mem_start + baddr + destoffs, fill, l);
+			memcpy_toio(priv->base + baddr + destoffs, fill, l);
 			destoffs += l;
 		}
 	}
 
 	/* set up the new frame descriptor */
 	addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
-	isa_memcpy_fromio(&tda, dev->mem_start + addr, sizeof(tda_t));
+	memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
 	tda.length = tda.fraglength = tmplen;
-	isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t));
+	memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
 
 	/* if there were no active descriptors, trigger the SONIC */
 	spin_lock_irqsave(&priv->lock, flags);
@@ -881,7 +881,7 @@ tx_done:
 
 static struct net_device_stats *ibmlana_stats(struct net_device *dev)
 {
-	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+	ibmlana_priv *priv = netdev_priv(dev);
 	return &priv->stat;
 }
 
@@ -903,7 +903,6 @@ static int startslot;		/* counts through
 
 static int ibmlana_probe(struct net_device *dev)
 {
-	int force_detect = 0;
 	int slot, z;
 	int base = 0, irq = 0, iobase = 0, memlen = 0;
 	ibmlana_priv *priv;
@@ -915,10 +914,6 @@ static int ibmlana_probe(struct net_devi
 	if (MCA_bus == 0)
 		return -ENODEV;
 
-	/* start address of 1 --> forced detection */
-	if (dev->mem_start == 1)
-		force_detect = 1;
-
 	base = dev->mem_start;
 	irq = dev->irq;
 
@@ -952,18 +947,12 @@ static int ibmlana_probe(struct net_devi
 		return -EBUSY;
 	}
 
-	/* make procfs entries */
-	mca_set_adapter_name(slot, "IBM LAN Adapter/A");
-	mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);
-
-	mca_mark_as_used(slot);
-
-	/* allocate structure */
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 	priv->slot = slot;
 	priv->realirq = irq;
 	priv->medium = medium;
 	spin_lock_init(&priv->lock);
+		
 
 	/* set base + irq for this device (irq not allocated so far) */
 
@@ -972,6 +961,20 @@ static int ibmlana_probe(struct net_devi
 	dev->mem_end = base + memlen;
 	dev->base_addr = iobase;
 
+	priv->base = ioremap(base, memlen);
+	if (!priv->base) {
+		printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
+		startslot = slot + 1;
+		release_region(iobase, IBM_LANA_IORANGE);
+		return -EBUSY;
+	}
+
+	/* make procfs entries */
+	mca_set_adapter_name(slot, "IBM LAN Adapter/A");
+	mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);
+
+	mca_mark_as_used(slot);
+
 	/* set methods */
 
 	dev->open = ibmlana_open;
@@ -1042,11 +1045,12 @@ int init_module(void)
 			break;
 		}
 		if (register_netdev(dev)) {
-			ibmlana_priv *priv = dev->priv;
+			ibmlana_priv *priv = netdev_priv(dev);
 			release_region(dev->base_addr, IBM_LANA_IORANGE);
 			mca_mark_as_unused(priv->slot);
 			mca_set_adapter_name(priv->slot, "");
 			mca_set_adapter_procfn(priv->slot, NULL, NULL);
+			iounmap(priv->base);
 			free_netdev(dev);
 			break;
 		}
@@ -1061,13 +1065,14 @@ void cleanup_module(void)
 	for (z = 0; z < DEVMAX; z++) {
 		struct net_device *dev = moddevs[z];
 		if (dev) {
-			ibmlana_priv *priv = (ibmlana_priv *) dev->priv;
+			ibmlana_priv *priv = netdev_priv(dev);
 			unregister_netdev(dev);
 			/*DeinitBoard(dev); */
 			release_region(dev->base_addr, IBM_LANA_IORANGE);
 			mca_mark_as_unused(priv->slot);
 			mca_set_adapter_name(priv->slot, "");
 			mca_set_adapter_procfn(priv->slot, NULL, NULL);
+			iounmap(priv->base);
 			free_netdev(dev);
 		}
 	}
diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ibmlana.h
@@ -37,6 +37,7 @@ typedef struct {
 		nexttxdescr,		/* last tx descriptor to be used    */
 		currtxdescr,		/* tx descriptor currently tx'ed    */
 		txused[TXBUFCNT];	/* busy flags                       */
+	void __iomem *base;
 	spinlock_t lock;
 } ibmlana_priv;
 
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -56,7 +56,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
-#include <linux/dp83840.h>
 #include <net/ip.h>
 
 #include <asm/byteorder.h>
@@ -463,6 +462,29 @@ static void ioc3_get_eaddr(struct ioc3_p
 	printk(".\n");
 }
 
+static void __ioc3_set_mac_address(struct net_device *dev)
+{
+	struct ioc3_private *ip = netdev_priv(dev);
+	struct ioc3 *ioc3 = ip->regs;
+
+	ioc3_w_emar_h((dev->dev_addr[5] <<  8) | dev->dev_addr[4]);
+	ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
+	              (dev->dev_addr[1] <<  8) | dev->dev_addr[0]);
+}
+
+static int ioc3_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct ioc3_private *ip = netdev_priv(dev);
+	struct sockaddr *sa = addr;
+
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+	spin_lock_irq(&ip->ioc3_lock);
+	__ioc3_set_mac_address(dev);
+	spin_unlock_irq(&ip->ioc3_lock);
+
+	return 0;
+}
 
 /*
  * Caller must hold the ioc3_lock ever for MII readers.  This is also
@@ -1014,9 +1036,7 @@ static void ioc3_init(struct net_device 
 	(void) ioc3_r_etcdc();			/* Clear on read */
 	ioc3_w_ercsr(15);			/* RX low watermark  */
 	ioc3_w_ertr(0);				/* Interrupt immediately */
-	ioc3_w_emar_h((dev->dev_addr[5] <<  8) | dev->dev_addr[4]);
-	ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
-	              (dev->dev_addr[1] <<  8) | dev->dev_addr[0]);
+	__ioc3_set_mac_address(dev);
 	ioc3_w_ehar_h(ip->ehar_h);
 	ioc3_w_ehar_l(ip->ehar_l);
 	ioc3_w_ersr(42);			/* XXX should be random */
@@ -1100,6 +1120,7 @@ static inline int ioc3_is_menet(struct p
 	       && dev->device == PCI_DEVICE_ID_SGI_IOC3;
 }
 
+#ifdef CONFIG_SERIAL_8250
 /*
  * Note about serial ports and consoles:
  * For console output, everyone uses the IOC3 UARTA (offset 0x178)
@@ -1121,15 +1142,14 @@ static inline int ioc3_is_menet(struct p
  * "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
+ * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
  * around ioc3 oddities in this respect.
  *
  * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
  * (IOC3_BAUD = (22000000 / (3*16)))
  */
 
-static inline void ioc3_serial_probe(struct pci_dev *pdev,
-				struct ioc3 *ioc3)
+static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
 {
 	struct serial_struct req;
 
@@ -1160,9 +1180,9 @@ static inline void ioc3_serial_probe(str
 	req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
 	register_serial(&req);
 }
+#endif
 
-static int __devinit ioc3_probe(struct pci_dev *pdev,
-	                        const struct pci_device_id *ent)
+static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	unsigned int sw_physid1, sw_physid2;
 	struct net_device *dev = NULL;
@@ -1170,11 +1190,39 @@ static int __devinit ioc3_probe(struct p
 	struct ioc3 *ioc3;
 	unsigned long ioc3_base, ioc3_size;
 	u32 vendor, model, rev;
-	int err;
+	int err, pci_using_dac;
+
+	/* Configure DMA attributes. */
+	err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+	if (!err) {
+		pci_using_dac = 1;
+		err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Unable to obtain 64 bit DMA "
+			       "for consistent allocations\n", pci_name(pdev));
+			goto out;
+		}
+	} else {
+		err = pci_set_dma_mask(pdev, 0xffffffffULL);
+		if (err) {
+			printk(KERN_ERR "%s: No usable DMA configuration, "
+			       "aborting.\n", pci_name(pdev));
+			goto out;
+		}
+		pci_using_dac = 0;
+	}
+
+	if (pci_enable_device(pdev))
+		return -ENODEV;
 
 	dev = alloc_etherdev(sizeof(struct ioc3_private));
-	if (!dev)
-		return -ENOMEM;
+	if (!dev) {
+		err = -ENOMEM;
+		goto out_disable;
+	}
+
+	if (pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
 
 	err = pci_request_regions(pdev, "ioc3");
 	if (err)
@@ -1237,6 +1285,7 @@ static int __devinit ioc3_probe(struct p
 	dev->get_stats		= ioc3_get_stats;
 	dev->do_ioctl		= ioc3_ioctl;
 	dev->set_multicast_list	= ioc3_set_multicast_list;
+	dev->set_mac_address	= ioc3_set_mac_address;
 	dev->ethtool_ops	= &ioc3_ethtool_ops;
 #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 	dev->features		= NETIF_F_IP_CSUM;
@@ -1269,6 +1318,12 @@ out_res:
 	pci_release_regions(pdev);
 out_free:
 	free_netdev(dev);
+out_disable:
+	/*
+	 * We should call pci_disable_device(pdev); here if the IOC3 wasn't
+	 * such a weird device ...
+	 */
+out:
 	return err;
 }
 
@@ -1282,6 +1337,10 @@ static void __devexit ioc3_remove_one (s
 	iounmap(ioc3);
 	pci_release_regions(pdev);
 	free_netdev(dev);
+	/*
+	 * We should call pci_disable_device(pdev); here if the IOC3 wasn't
+	 * such a weird device ...
+	 */
 }
 
 static struct pci_device_id ioc3_pci_tbl[] = {
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -310,7 +310,7 @@ config SIGMATEL_FIR
 
 config NSC_FIR
 	tristate "NSC PC87108/PC87338"
-	depends on IRDA && ISA
+	depends on IRDA && ISA_DMA_API
 	help
 	  Say Y here if you want to build support for the NSC PC87108 and
 	  PC87338 IrDA chipsets.  This driver supports SIR,
@@ -321,7 +321,7 @@ config NSC_FIR
 
 config WINBOND_FIR
 	tristate "Winbond W83977AF (IR)"
-	depends on IRDA && ISA
+	depends on IRDA && ISA_DMA_API
 	help
 	  Say Y here if you want to build IrDA support for the Winbond
 	  W83977AF super-io chipset.  This driver should be used for the IrDA
@@ -347,7 +347,7 @@ config AU1000_FIR
 
 config SMC_IRCC_FIR
 	tristate "SMSC IrCC (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && IRDA && ISA
+	depends on EXPERIMENTAL && IRDA && ISA_DMA_API
 	help
 	  Say Y here if you want to build support for the SMC Infrared
 	  Communications Controller.  It is used in a wide variety of
@@ -357,7 +357,7 @@ config SMC_IRCC_FIR
 
 config ALI_FIR
 	tristate "ALi M5123 FIR (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && IRDA && ISA
+	depends on EXPERIMENTAL && IRDA && ISA_DMA_API
 	help
 	  Say Y here if you want to build support for the ALi M5123 FIR
 	  Controller.  The ALi M5123 FIR Controller is embedded in ALi M1543C,
@@ -385,11 +385,11 @@ config SA1100_FIR
 
 config VIA_FIR
 	tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
-	depends on IRDA && ISA && PCI
+	depends on IRDA && ISA_DMA_API
 	help
 	  Say Y here if you want to build support for the VIA VT8231
 	  and VIA VT1211 IrDA controllers, found on the motherboards using
-	  those those VIA chipsets. To use this controller, you will need
+	  those VIA chipsets. To use this controller, you will need
 	  to plug a specific 5 pins FIR IrDA dongle in the specific
 	  motherboard connector. The driver provides support for SIR, MIR
 	  and FIR (4Mbps) speeds.
diff --git a/drivers/net/irda/act200l-sir.c b/drivers/net/irda/act200l-sir.c
--- a/drivers/net/irda/act200l-sir.c
+++ b/drivers/net/irda/act200l-sir.c
@@ -177,8 +177,7 @@ static int act200l_change_speed(struct s
 
 	/* Write control bytes */
 	sirdev_raw_write(dev, control, 3);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(5));
+	msleep(5);
 
 	/* Go back to normal mode */
 	sirdev_set_dtr_rts(dev, TRUE, TRUE);
@@ -241,7 +240,7 @@ static int act200l_reset(struct sir_dev 
 		dev->speed = 9600;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s(), unknown state %d\n", __FUNCTION__, state);
 		ret = -1;
 		break;
 	}
diff --git a/drivers/net/irda/act200l.c b/drivers/net/irda/act200l.c
--- a/drivers/net/irda/act200l.c
+++ b/drivers/net/irda/act200l.c
@@ -152,7 +152,8 @@ static int act200l_change_speed(struct i
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), resetting dongle timed out!\n",
+			     __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -197,7 +198,8 @@ static int act200l_change_speed(struct i
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -263,7 +265,8 @@ static int act200l_reset(struct irda_tas
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c
--- a/drivers/net/irda/actisys.c
+++ b/drivers/net/irda/actisys.c
@@ -227,7 +227,7 @@ static int actisys_reset(struct irda_tas
 	dongle_t *self = (dongle_t *) task->instance;
 	int ret = 0;
 
-	ASSERT(task != NULL, return -1;);
+	IRDA_ASSERT(task != NULL, return -1;);
 
 	self->reset_task = task;
 
@@ -254,7 +254,8 @@ static int actisys_reset(struct irda_tas
 		self->speed = 9600;	/* That's the default */
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -260,7 +260,8 @@ static int ali_ircc_open(int i, chipio_t
 		
 	dev = alloc_irdadev(sizeof(*self));
 	if (dev == NULL) {
-		ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate memory for control block!\n",
+			   __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -283,7 +284,7 @@ static int ali_ircc_open(int i, chipio_t
 	
 	/* Reserve the ioports that we need */
 	if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
-		WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__,
+		IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__,
 			self->io.fir_base);
 		err = -ENODEV;
 		goto err_out1;
@@ -345,14 +346,14 @@ static int ali_ircc_open(int i, chipio_t
 
 	err = register_netdev(dev);
 	if (err) {
-		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		goto err_out4;
 	}
-	MESSAGE("IrDA: Registered device %s\n", dev->name);
+	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	/* Check dongle id */
 	dongle_id = ali_ircc_read_dongle_id(i, info);
-	MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]);
+	IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]);
 		
 	self->io.dongle_id = dongle_id;
 	
@@ -391,7 +392,7 @@ static int __exit ali_ircc_close(struct 
 
 	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
         iobase = self->io.fir_base;
 
@@ -489,7 +490,7 @@ static int ali_ircc_probe_53(ali_chip_t 
 	info->dma = reg & 0x07;
 	
 	if(info->dma == 0x04)
-		WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__);
+		IRDA_WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__);
 	else
 		IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);
 	
@@ -546,11 +547,11 @@ static int ali_ircc_setup(chipio_t *info
 	/* Should be 0x00 in the M1535/M1535D */
 	if(version != 0x00)
 	{
-		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		IRDA_ERROR("%s, Wrong chip version %02x\n", driver_name, version);
 		return -1;
 	}
 	
-	// MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base);
+	// IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base);
 	
 	/* Set FIR FIFO Threshold Register */
 	switch_bank(iobase, BANK1);
@@ -581,7 +582,7 @@ static int ali_ircc_setup(chipio_t *info
 	/* Switch to SIR space */
 	FIR2SIR(iobase);
 	
-	MESSAGE("%s, driver loaded (Benjamin Kong)\n", driver_name);
+	IRDA_MESSAGE("%s, driver loaded (Benjamin Kong)\n", driver_name);
 	
 	/* Enable receive interrupts */ 
 	// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
@@ -645,7 +646,7 @@ static irqreturn_t ali_ircc_interrupt(in
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
  	if (!dev) {
-		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+		IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
 		return IRQ_NONE;
 	}	
 	
@@ -851,7 +852,7 @@ static void ali_ircc_sir_receive(struct 
 	int iobase;
 	
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
 
@@ -885,7 +886,7 @@ static void ali_ircc_sir_write_wakeup(st
 	int actual = 0;
 	int iobase;	
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 	
@@ -994,7 +995,7 @@ static void ali_ircc_fir_change_speed(st
 
 	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 		
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	dev = self->netdev;
 	iobase = self->io.fir_base;
@@ -1035,7 +1036,7 @@ static void ali_ircc_sir_change_speed(st
 	
 	IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __FUNCTION__ , speed);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
 	
@@ -1315,19 +1316,19 @@ static int ali_ircc_net_open(struct net_
 		
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	
 	self = (struct ali_ircc_cb *) dev->priv;
 	
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 	
 	/* Request IRQ and install Interrupt Handler */
 	if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) 
 	{
-		WARNING("%s, unable to allocate irq=%d\n", driver_name, 
-			self->io.irq);
+		IRDA_WARNING("%s, unable to allocate irq=%d\n", driver_name,
+			     self->io.irq);
 		return -EAGAIN;
 	}
 	
@@ -1336,8 +1337,8 @@ static int ali_ircc_net_open(struct net_
 	 * failure.
 	 */
 	if (request_dma(self->io.dma, dev->name)) {
-		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
-			self->io.dma);
+		IRDA_WARNING("%s, unable to allocate dma=%d\n", driver_name,
+			     self->io.dma);
 		free_irq(self->io.irq, self);
 		return -EAGAIN;
 	}
@@ -1376,10 +1377,10 @@ static int ali_ircc_net_close(struct net
 			
 	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 		
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = (struct ali_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
 	netif_stop_queue(dev);
@@ -1643,7 +1644,7 @@ static int  ali_ircc_dma_xmit_complete(s
 	if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
 	
 	{
-		ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__);	
+		IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__);	
 		self->stats.tx_errors++;
 		self->stats.tx_fifo_errors++;		
 	}
@@ -1890,8 +1891,9 @@ static int  ali_ircc_dma_receive_complet
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
 			{
-				WARNING("%s(), memory squeeze, "
-					"dropping frame.\n", __FUNCTION__);
+				IRDA_WARNING("%s(), memory squeeze, "
+					     "dropping frame.\n",
+					     __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				return FALSE;
@@ -1940,10 +1942,10 @@ static int ali_ircc_sir_hard_xmit(struct
 	
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 	
-	ASSERT(dev != NULL, return 0;);
+	IRDA_ASSERT(dev != NULL, return 0;);
 	
 	self = (struct ali_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.sir_base;
 
@@ -2008,11 +2010,11 @@ static int ali_ircc_net_ioctl(struct net
 	
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__ , dev->name, cmd);
 	
@@ -2065,7 +2067,7 @@ static int ali_ircc_is_receiving(struct 
 	
 	IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return FALSE;);
+	IRDA_ASSERT(self != NULL, return FALSE;);
 
 	spin_lock_irqsave(&self->lock, flags);
 
@@ -2109,7 +2111,7 @@ static void ali_ircc_suspend(struct ali_
 {
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
 	
-	MESSAGE("%s, Suspending\n", driver_name);
+	IRDA_MESSAGE("%s, Suspending\n", driver_name);
 
 	if (self->io.suspended)
 		return;
@@ -2130,7 +2132,7 @@ static void ali_ircc_wakeup(struct ali_i
 	
 	ali_ircc_net_open(self->netdev);
 	
-	MESSAGE("%s, Waking up\n", driver_name);
+	IRDA_MESSAGE("%s, Waking up\n", driver_name);
 
 	self->io.suspended = 0;
 	
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -587,9 +587,9 @@ toshoboe_startchip (struct toshoboe_cb *
   /*Find out where the rings live */
   physaddr = virt_to_bus (self->ring);
 
-  ASSERT ((physaddr & 0x3ff) == 0,
-          printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n");
-          return;);
+  IRDA_ASSERT ((physaddr & 0x3ff) == 0,
+	       printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n");
+	       return;);
 
   OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0);
   OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1);
@@ -994,7 +994,7 @@ toshoboe_hard_xmit (struct sk_buff *skb,
 
   self = (struct toshoboe_cb *) dev->priv;
 
-  ASSERT (self != NULL, return 0; );
+  IRDA_ASSERT (self != NULL, return 0; );
 
   IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __FUNCTION__
       ,skb->len,self->txpending,INB (OBOE_ENABLEH));
@@ -1360,10 +1360,10 @@ toshoboe_net_open (struct net_device *de
 
   IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
-  ASSERT (dev != NULL, return -1; );
+  IRDA_ASSERT (dev != NULL, return -1; );
   self = (struct toshoboe_cb *) dev->priv;
 
-  ASSERT (self != NULL, return 0; );
+  IRDA_ASSERT (self != NULL, return 0; );
 
   if (self->async)
     return -EBUSY;
@@ -1402,7 +1402,7 @@ toshoboe_net_close (struct net_device *d
 
   IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
-  ASSERT (dev != NULL, return -1; );
+  IRDA_ASSERT (dev != NULL, return -1; );
   self = (struct toshoboe_cb *) dev->priv;
 
   /* Stop device */
@@ -1439,11 +1439,11 @@ toshoboe_net_ioctl (struct net_device *d
   unsigned long flags;
   int ret = 0;
 
-  ASSERT (dev != NULL, return -1; );
+  IRDA_ASSERT (dev != NULL, return -1; );
 
   self = dev->priv;
 
-  ASSERT (self != NULL, return -1; );
+  IRDA_ASSERT (self != NULL, return -1; );
 
   IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 
@@ -1509,7 +1509,7 @@ toshoboe_close (struct pci_dev *pci_dev)
 
   IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
-  ASSERT (self != NULL, return; );
+  IRDA_ASSERT (self != NULL, return; );
 
   if (!self->stopped)
     {
@@ -1712,7 +1712,7 @@ freeself:
 }
 
 static int
-toshoboe_gotosleep (struct pci_dev *pci_dev, u32 crap)
+toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap)
 {
   struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
   unsigned long flags;
diff --git a/drivers/net/irda/girbil-sir.c b/drivers/net/irda/girbil-sir.c
--- a/drivers/net/irda/girbil-sir.c
+++ b/drivers/net/irda/girbil-sir.c
@@ -179,7 +179,7 @@ static int girbil_change_speed(struct si
 		break;
 
 	default:
-		ERROR("%s - undefined state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s - undefined state %d\n", __FUNCTION__, state);
 		ret = -EINVAL;
 		break;
 	}
@@ -241,7 +241,7 @@ static int girbil_reset(struct sir_dev *
 		break;
 
 	default:
-		ERROR("%s(), undefined state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state);
 		ret = -1;
 		break;
 	}
diff --git a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c
--- a/drivers/net/irda/girbil.c
+++ b/drivers/net/irda/girbil.c
@@ -123,7 +123,8 @@ static int girbil_change_speed(struct ir
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), resetting dongle timed out!\n",
+			     __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -162,7 +163,8 @@ static int girbil_change_speed(struct ir
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -215,7 +217,8 @@ static int girbil_reset(struct irda_task
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -251,7 +251,7 @@ static void irda_usb_change_speed_xbofs(
 	/* Grab the speed URB */
 	urb = self->speed_urb;
 	if (urb->status != 0) {
-		WARNING("%s(), URB still in use!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__);
 		return;
 	}
 
@@ -271,7 +271,7 @@ static void irda_usb_change_speed_xbofs(
 
 	/* Irq disabled -> GFP_ATOMIC */
 	if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
-		WARNING("%s(), failed Speed URB\n", __FUNCTION__);
+		IRDA_WARNING("%s(), failed Speed URB\n", __FUNCTION__);
 	}
 }
 
@@ -287,9 +287,9 @@ static void speed_bulk_callback(struct u
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	/* We should always be called for the speed URB */
-	ASSERT(urb == self->speed_urb, return;);
+	IRDA_ASSERT(urb == self->speed_urb, return;);
 
 	/* Check for timeout and other USB nasties */
 	if (urb->status != 0) {
@@ -374,7 +374,7 @@ static int irda_usb_hard_xmit(struct sk_
 	}
 
 	if (urb->status != 0) {
-		WARNING("%s(), URB still in use!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__);
 		goto drop;
 	}
 
@@ -385,7 +385,7 @@ static int irda_usb_hard_xmit(struct sk_
 	if (skb_headroom(skb) < USB_IRDA_HEADER) {
 		IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
 		if (skb_cow(skb, USB_IRDA_HEADER)) {
-			WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
+			IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
 			goto drop;
 		}
 	}
@@ -457,7 +457,7 @@ static int irda_usb_hard_xmit(struct sk_
 	
 	/* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */
 	if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {
-		WARNING("%s(), failed Tx URB\n", __FUNCTION__);
+		IRDA_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);*/
@@ -492,9 +492,9 @@ static void write_bulk_callback(struct u
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	/* We should always be called for the speed URB */
-	ASSERT(urb == self->tx_urb, return;);
+	IRDA_ASSERT(urb == self->tx_urb, return;);
 
 	/* Free up the skb */
 	dev_kfree_skb_any(skb);
@@ -566,14 +566,14 @@ static void irda_usb_net_timeout(struct 
 	int	done = 0;	/* If we have made any progress */
 
 	IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__);
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	/* Protect us from USB callbacks, net Tx and else. */
 	spin_lock_irqsave(&self->lock, flags);
 
 	/* self->present *MUST* be read under spinlock */
 	if (!self->present) {
-		WARNING("%s(), device not present!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&self->lock, flags);
 		return;
@@ -699,8 +699,8 @@ static void irda_usb_submit(struct irda_
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* This should never happen */
-	ASSERT(skb != NULL, return;);
-	ASSERT(urb != NULL, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(urb != NULL, return;);
 
 	/* Save ourselves in the skb */
 	cb = (struct irda_skb_cb *) skb->cb;
@@ -720,7 +720,8 @@ static void irda_usb_submit(struct irda_
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
-		WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret);
+		IRDA_WARNING("%s(), Failed to submit Rx URB %d\n",
+			     __FUNCTION__, ret);
 	}
 }
 
@@ -744,9 +745,9 @@ static void irda_usb_receive(struct urb 
 	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
-	ASSERT(cb != NULL, return;);
+	IRDA_ASSERT(cb != NULL, return;);
 	self = (struct irda_usb_cb *) cb->context;
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	/* If the network is closed or the device gone, stop everything */
 	if ((!self->netopen) || (!self->present)) {
@@ -777,7 +778,7 @@ static void irda_usb_receive(struct urb 
 	
 	/* Check for empty frames */
 	if (urb->actual_length <= USB_IRDA_HEADER) {
-		WARNING("%s(), empty frame!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__);
 		goto done;
 	}
 
@@ -910,13 +911,13 @@ static int irda_usb_net_open(struct net_
 	
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(netdev != NULL, return -1;);
+	IRDA_ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Can only open the device if it's there */
 	if(!self->present) {
-		WARNING("%s(), device not present!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), device not present!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -938,7 +939,7 @@ static int irda_usb_net_open(struct net_
 	 */
 	sprintf(hwname, "usb#%d", self->usbdev->devnum);
 	self->irlap = irlap_open(netdev, &self->qos, hwname);
-	ASSERT(self->irlap != NULL, return -1;);
+	IRDA_ASSERT(self->irlap != NULL, return -1;);
 
 	/* Allow IrLAP to send data to us */
 	netif_start_queue(netdev);
@@ -957,7 +958,8 @@ static int irda_usb_net_open(struct net_
 		if (!skb) {
 			/* If this ever happen, we are in deep s***.
 			 * Basically, we can't start the Rx path... */
-			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
+			IRDA_WARNING("%s(), Failed to allocate Rx skb\n",
+				     __FUNCTION__);
 			return -1;
 		}
 		//skb_reserve(newskb, USB_IRDA_HEADER - 1);
@@ -982,9 +984,9 @@ static int irda_usb_net_close(struct net
 
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(netdev != NULL, return -1;);
+	IRDA_ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Clear this flag *before* unlinking the urbs and *before*
 	 * stopping the network Tx queue - Jean II */
@@ -998,7 +1000,7 @@ static int irda_usb_net_close(struct net
 		struct urb *urb = self->rx_urb[i];
 		struct sk_buff *skb = (struct sk_buff *) urb->context;
 		/* Cancel the receive command */
-		usb_unlink_urb(urb);
+		usb_kill_urb(urb);
 		/* The skb is ours, free it */
 		if(skb) {
 			dev_kfree_skb(skb);
@@ -1030,9 +1032,9 @@ static int irda_usb_net_ioctl(struct net
 	struct irda_usb_cb *self;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = dev->priv;
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 
@@ -1239,7 +1241,7 @@ static inline int irda_usb_parse_endpoin
 				/* This is our interrupt endpoint */
 				self->bulk_int_ep = ep;
 			} else {
-				ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
+				IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
 			}
 		}
 	}
@@ -1247,7 +1249,7 @@ static inline int irda_usb_parse_endpoin
 	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, ;);
+	IRDA_ASSERT(self->bulk_out_mtu == 64, ;);
 
 	return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));
 }
@@ -1308,15 +1310,15 @@ static inline struct irda_class_desc *ir
 		IU_REQ_GET_CLASS_DESC,
 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0, intf->altsetting->desc.bInterfaceNumber, desc,
-		sizeof(*desc), msecs_to_jiffies(500));
+		sizeof(*desc), 500);
 	
 	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);
+		IRDA_WARNING("usb-irda: class_descriptor read %s (%d)\n",
+			     (ret<0) ? "failed" : "too short", ret);
 	}
 	else if (desc->bDescriptorType != USB_DT_IRDA) {
-		WARNING("usb-irda: bad class_descriptor type\n");
+		IRDA_WARNING("usb-irda: bad class_descriptor type\n");
 	}
 	else {
 #ifdef IU_DUMP_CLASS_DESC
@@ -1359,20 +1361,20 @@ static int irda_usb_probe(struct usb_int
 	 * don't need to check if the dongle is really ours.
 	 * Jean II */
 
-	MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
-		dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
-		le16_to_cpu(dev->descriptor.idProduct));
+	IRDA_MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
+		     dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+		     le16_to_cpu(dev->descriptor.idProduct));
 
 	net = alloc_irdadev(sizeof(*self));
 	if (!net) 
 		goto err_out;
 
+	SET_MODULE_OWNER(net);
+	SET_NETDEV_DEV(net, &intf->dev);
 	self = net->priv;
 	self->netdev = net;
 	spin_lock_init(&self->lock);
 
-	SET_MODULE_OWNER(net);
-
 	/* Create all of the needed urbs */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
 		self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
@@ -1421,7 +1423,7 @@ static int irda_usb_probe(struct usb_int
 	interface = intf->cur_altsetting;
 	if(!irda_usb_parse_endpoints(self, interface->endpoint,
 				     interface->desc.bNumEndpoints)) {
-		ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
+		IRDA_ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
 		ret = -EIO;
 		goto err_out_3;
 	}
@@ -1453,7 +1455,7 @@ static int irda_usb_probe(struct usb_int
 	if (ret) 
 		goto err_out_4;
 
-	MESSAGE("IrDA: Registered device %s\n", net->name);
+	IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
 	usb_set_intfdata(intf, self);
 	return 0;
 
@@ -1516,7 +1518,7 @@ static void irda_usb_disconnect(struct u
 		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]);
+			usb_kill_urb(self->rx_urb[i]);
 		/* Cancel Tx and speed URB.
 		 * Toggle flags to make sure it's synchronous. */
 		self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
@@ -1573,7 +1575,7 @@ static int __init usb_irda_init(void)
 	if (ret < 0)
 		return ret;
 
-	MESSAGE("USB IrDA support registered\n");
+	IRDA_MESSAGE("USB IrDA support registered\n");
 	return 0;
 }
 module_init(usb_irda_init);
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -87,50 +87,14 @@ static struct net_device_stats *irport_n
 static int irport_change_speed_complete(struct irda_task *task);
 static void irport_timeout(struct net_device *dev);
 
-EXPORT_SYMBOL(irport_open);
-EXPORT_SYMBOL(irport_close);
-EXPORT_SYMBOL(irport_start);
-EXPORT_SYMBOL(irport_stop);
-EXPORT_SYMBOL(irport_interrupt);
-EXPORT_SYMBOL(irport_hard_xmit);
-EXPORT_SYMBOL(irport_timeout);
-EXPORT_SYMBOL(irport_change_speed);
-EXPORT_SYMBOL(irport_net_open);
-EXPORT_SYMBOL(irport_net_close);
+static irqreturn_t irport_interrupt(int irq, void *dev_id,
+				    struct pt_regs *regs);
+static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+static void irport_change_speed(void *priv, __u32 speed);
+static int irport_net_open(struct net_device *dev);
+static int irport_net_close(struct net_device *dev);
 
-static int __init irport_init(void)
-{
- 	int i;
-
- 	for (i=0; (io[i] < 2000) && (i < 4); i++) {
- 		if (irport_open(i, io[i], irq[i]) != NULL)
- 			return 0;
- 	}
-	/* 
-	 * Maybe something failed, but we can still be usable for FIR drivers 
-	 */
- 	return 0;
-}
-
-/*
- * Function irport_cleanup ()
- *
- *    Close all configured ports
- *
- */
-static void __exit irport_cleanup(void)
-{
- 	int i;
-
-        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
-
-	for (i=0; i < 4; i++) {
- 		if (dev_self[i])
- 			irport_close(dev_self[i]);
- 	}
-}
-
-struct irport_cb *
+static struct irport_cb *
 irport_open(int i, unsigned int iobase, unsigned int irq)
 {
 	struct net_device *dev;
@@ -150,8 +114,8 @@ irport_open(int i, unsigned int iobase, 
 	 */
 	dev = alloc_irdadev(sizeof(struct irport_cb));
 	if (!dev) {
-		ERROR("%s(), can't allocate memory for "
-		      "irda device!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate memory for "
+			   "irda device!\n", __FUNCTION__);
 		goto err_out2;
 	}
 
@@ -183,8 +147,8 @@ irport_open(int i, unsigned int iobase, 
 	self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize,
 					    GFP_KERNEL);
 	if (self->rx_buff.skb == NULL) {
-		ERROR("%s(), can't allocate memory for "
-		      "receive buffer!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate memory for "
+			   "receive buffer!\n", __FUNCTION__);
 		goto err_out3;
 	}
 	skb_reserve(self->rx_buff.skb, 1);
@@ -204,8 +168,8 @@ irport_open(int i, unsigned int iobase, 
 		self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
 						      GFP_KERNEL);
 		if (self->tx_buff.head == NULL) {
-			ERROR("%s(), can't allocate memory for "
-			      "transmit buffer!\n", __FUNCTION__);
+			IRDA_ERROR("%s(), can't allocate memory for "
+				   "transmit buffer!\n", __FUNCTION__);
 			goto err_out4;
 		}
 		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
@@ -234,10 +198,10 @@ irport_open(int i, unsigned int iobase, 
 	dev->irq = irq;
 
 	if (register_netdev(dev)) {
-		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		goto err_out5;
 	}
-	MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
+	IRDA_MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
 		dev->name, iobase, irq);
 
 	return self;
@@ -254,9 +218,9 @@ irport_open(int i, unsigned int iobase, 
 	return NULL;
 }
 
-int irport_close(struct irport_cb *self)
+static int irport_close(struct irport_cb *self)
 {
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* We are not using any dongle anymore! */
 	if (self->dongle)
@@ -285,40 +249,40 @@ int irport_close(struct irport_cb *self)
 	return 0;
 }
 
-void irport_start(struct irport_cb *self)
+static void irport_stop(struct irport_cb *self)
 {
 	int iobase;
 
 	iobase = self->io.sir_base;
 
-	irport_stop(self);
-	
 	/* We can't lock, we may be called from a FIR driver - Jean II */
 
-	/* Initialize UART */
-	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
-	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
+	/* We are not transmitting any more */
+	self->transmitting = 0;
+
+	/* Reset UART */
+	outb(0, iobase+UART_MCR);
 	
-	/* Turn on interrups */
-	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
+	/* Turn off interrupts */
+	outb(0, iobase+UART_IER);
 }
 
-void irport_stop(struct irport_cb *self)
+static void irport_start(struct irport_cb *self)
 {
 	int iobase;
 
 	iobase = self->io.sir_base;
 
+	irport_stop(self);
+	
 	/* We can't lock, we may be called from a FIR driver - Jean II */
 
-	/* We are not transmitting any more */
-	self->transmitting = 0;
-
-	/* Reset UART */
-	outb(0, iobase+UART_MCR);
+	/* Initialize UART */
+	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
 	
-	/* Turn off interrupts */
-	outb(0, iobase+UART_IER);
+	/* Turn on interrups */
+	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
 }
 
 /*
@@ -368,7 +332,7 @@ static inline unsigned int irport_get_fc
  *
  * This function should be called with irq off and spin-lock.
  */
-void irport_change_speed(void *priv, __u32 speed)
+static void irport_change_speed(void *priv, __u32 speed)
 {
 	struct irport_cb *self = (struct irport_cb *) priv;
 	int iobase; 
@@ -376,8 +340,8 @@ void irport_change_speed(void *priv, __u
 	unsigned int lcr;    /* Line control reg */
 	int divisor;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(speed != 0, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(speed != 0, return;);
 
 	IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
 		    __FUNCTION__, speed, self->io.sir_base);
@@ -431,7 +395,7 @@ int __irport_change_speed(struct irda_ta
 
 	self = (struct irport_cb *) task->instance;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Locking notes : this function may be called from irq context with
 	 * spinlock, via irport_write_wakeup(), or from non-interrupt without
@@ -480,7 +444,7 @@ int __irport_change_speed(struct irda_ta
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
 		ret = -1;		
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -490,7 +454,8 @@ int __irport_change_speed(struct irda_ta
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		ret = -1;
 		break;
@@ -517,8 +482,8 @@ static int irport_change_speed_complete(
 
 	self = (struct irport_cb *) task->instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->netdev != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->netdev != NULL, return -1;);
 
 	/* Finished changing speed, so we are not busy any longer */
 	/* Signal network layer so it can try to send the frame */
@@ -543,10 +508,10 @@ static void irport_timeout(struct net_de
 	unsigned long flags;
 
 	self = (struct irport_cb *) dev->priv;
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	iobase = self->io.sir_base;
 	
-	WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n",
+	IRDA_WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n",
 		dev->name, jiffies, dev->trans_start);
 	spin_lock_irqsave(&self->lock, flags);
 
@@ -619,7 +584,7 @@ static void irport_wait_hw_transmitter_f
  *    waits until the next transmitt interrupt, and continues until the
  *    frame is transmitted.
  */
-int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct irport_cb *self;
 	unsigned long flags;
@@ -628,10 +593,10 @@ int irport_hard_xmit(struct sk_buff *skb
 
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return 0;);
+	IRDA_ASSERT(dev != NULL, return 0;);
 	
 	self = (struct irport_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.sir_base;
 
@@ -728,7 +693,7 @@ static inline void irport_write_wakeup(s
 	int iobase;
 	unsigned int fcr;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
@@ -789,7 +754,7 @@ static inline void irport_receive(struct
 	int boguscount = 0;
 	int iobase;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
 
@@ -814,7 +779,8 @@ static inline void irport_receive(struct
  *
  *    Interrupt handler
  */
-irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+static irqreturn_t irport_interrupt(int irq, void *dev_id,
+				    struct pt_regs *regs) 
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct irport_cb *self;
@@ -824,7 +790,7 @@ irqreturn_t irport_interrupt(int irq, vo
 	int handled = 0;
 
 	if (!dev) {
-		WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq);
+		IRDA_WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq);
 		return IRQ_NONE;
 	}
 	self = (struct irport_cb *) dev->priv;
@@ -861,8 +827,8 @@ irqreturn_t irport_interrupt(int irq, vo
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 10) {
-			WARNING("%s() irq handler looping : lsr=%02x\n",
-				__FUNCTION__, lsr);
+			IRDA_WARNING("%s() irq handler looping : lsr=%02x\n",
+				     __FUNCTION__, lsr);
 			break;
 		}
 
@@ -888,7 +854,7 @@ irqreturn_t irport_interrupt(int irq, vo
  *    Network device is taken up. Usually this is done by "ifconfig irda0 up" 
  *   
  */
-int irport_net_open(struct net_device *dev)
+static int irport_net_open(struct net_device *dev)
 {
 	struct irport_cb *self;
 	int iobase;
@@ -897,7 +863,7 @@ int irport_net_open(struct net_device *d
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
 
 	iobase = self->io.sir_base;
@@ -941,7 +907,7 @@ int irport_net_open(struct net_device *d
  *    Network device is taken down. Usually this is done by 
  *    "ifconfig irda0 down" 
  */
-int irport_net_close(struct net_device *dev)
+static int irport_net_close(struct net_device *dev)
 {
 	struct irport_cb *self;
 	int iobase;
@@ -949,10 +915,10 @@ int irport_net_close(struct net_device *
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	iobase = self->io.sir_base;
 
@@ -995,7 +961,7 @@ static int irport_set_dtr_rts(struct net
 	struct irport_cb *self = dev->priv;
 	int iobase;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	iobase = self->io.sir_base;
 
@@ -1015,7 +981,7 @@ static int irport_raw_write(struct net_d
 	int actual = 0;
 	int iobase;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	iobase = self->io.sir_base;
 
@@ -1049,11 +1015,11 @@ static int irport_net_ioctl(struct net_d
 	unsigned long flags;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
@@ -1134,6 +1100,38 @@ static struct net_device_stats *irport_n
 	return &self->stats;
 }
 
+static int __init irport_init(void)
+{
+ 	int i;
+
+ 	for (i=0; (io[i] < 2000) && (i < 4); i++) {
+ 		if (irport_open(i, io[i], irq[i]) != NULL)
+ 			return 0;
+ 	}
+	/* 
+	 * Maybe something failed, but we can still be usable for FIR drivers 
+	 */
+ 	return 0;
+}
+
+/*
+ * Function irport_cleanup ()
+ *
+ *    Close all configured ports
+ *
+ */
+static void __exit irport_cleanup(void)
+{
+ 	int i;
+
+        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+
+	for (i=0; i < 4; i++) {
+ 		if (dev_self[i])
+ 			irport_close(dev_self[i]);
+ 	}
+}
+
 MODULE_PARM(io, "1-4i");
 MODULE_PARM_DESC(io, "Base I/O addresses");
 MODULE_PARM(irq, "1-4i");
diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h
--- a/drivers/net/irda/irport.h
+++ b/drivers/net/irda/irport.h
@@ -77,14 +77,4 @@ struct irport_cb {
 	int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs);
 };
 
-struct irport_cb *irport_open(int i, unsigned int iobase, unsigned int irq);
-int  irport_close(struct irport_cb *self);
-void irport_start(struct irport_cb *self);
-void irport_stop(struct irport_cb *self);
-void irport_change_speed(void *priv, __u32 speed);
-irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-int  irport_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-int  irport_net_open(struct net_device *dev);
-int  irport_net_close(struct net_device *dev);
-
 #endif /* IRPORT_H */
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
+#include <linux/delay.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -59,8 +60,8 @@ static int irtty_chars_in_buffer(struct 
 {
 	struct sirtty_cb *priv = dev->priv;
 
-	ASSERT(priv != NULL, return -1;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+	IRDA_ASSERT(priv != NULL, return -1;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
 
 	return priv->tty->driver->chars_in_buffer(priv->tty);
 }
@@ -87,8 +88,8 @@ static void irtty_wait_until_sent(struct
 	struct sirtty_cb *priv = dev->priv;
 	struct tty_struct *tty;
 
-	ASSERT(priv != NULL, return;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return;);
+	IRDA_ASSERT(priv != NULL, return;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
 	tty = priv->tty;
 	if (tty->driver->wait_until_sent) {
@@ -97,8 +98,7 @@ static void irtty_wait_until_sent(struct
 		unlock_kernel();
 	}
 	else {
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		schedule_timeout(msecs_to_jiffies(USBSERIAL_TX_DONE_DELAY));
+		msleep(USBSERIAL_TX_DONE_DELAY);
 	}
 }
 
@@ -119,8 +119,8 @@ static int irtty_change_speed(struct sir
         struct termios old_termios;
 	int cflag;
 
-	ASSERT(priv != NULL, return -1;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+	IRDA_ASSERT(priv != NULL, return -1;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
 
 	tty = priv->tty;
 
@@ -183,8 +183,8 @@ static int irtty_set_dtr_rts(struct sir_
 	int set = 0;
 	int clear = 0;
 
-	ASSERT(priv != NULL, return -1;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+	IRDA_ASSERT(priv != NULL, return -1;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
 
 	if (rts)
 		set |= TIOCM_RTS;
@@ -201,7 +201,7 @@ static int irtty_set_dtr_rts(struct sir_
 	 * This function is not yet defined for all tty driver, so
 	 * let's be careful... Jean II
 	 */
-	ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);
+	IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);
 	priv->tty->driver->tiocmset(priv->tty, NULL, set, clear);
 
 	return 0;
@@ -220,8 +220,8 @@ static int irtty_do_write(struct sir_dev
 	struct tty_struct *tty;
 	int writelen;
 
-	ASSERT(priv != NULL, return -1;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+	IRDA_ASSERT(priv != NULL, return -1;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
 
 	tty = priv->tty;
 	if (!tty->driver->write)
@@ -262,15 +262,15 @@ static void irtty_receive_buf(struct tty
 	struct sirtty_cb *priv = tty->disc_data;
 	int	i;
 
-	ASSERT(priv != NULL, return;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return;);
+	IRDA_ASSERT(priv != NULL, return;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
 	if (unlikely(count==0))		/* yes, this happens */
 		return;
 
 	dev = priv->dev;
 	if (!dev) {
-		WARNING("%s(), not ready yet!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), not ready yet!\n", __FUNCTION__);
 		return;
 	}
 
@@ -298,8 +298,8 @@ static int irtty_receive_room(struct tty
 {
 	struct sirtty_cb *priv = tty->disc_data;
 
-	ASSERT(priv != NULL, return 0;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return 0;);
+	IRDA_ASSERT(priv != NULL, return 0;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return 0;);
 
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
@@ -315,8 +315,8 @@ static void irtty_write_wakeup(struct tt
 {
 	struct sirtty_cb *priv = tty->disc_data;
 
-	ASSERT(priv != NULL, return;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return;);
+	IRDA_ASSERT(priv != NULL, return;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
@@ -413,7 +413,7 @@ static int irtty_stop_dev(struct sir_dev
 
 /* ------------------------------------------------------- */
 
-struct sir_driver sir_tty_drv = {
+static struct sir_driver sir_tty_drv = {
 	.owner			= THIS_MODULE,
 	.driver_name		= "sir_tty",
 	.start_dev		= irtty_start_dev,
@@ -440,13 +440,13 @@ static int irtty_ioctl(struct tty_struct
 	struct sirtty_cb *priv = tty->disc_data;
 	int err = 0;
 
-	ASSERT(priv != NULL, return -ENODEV;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
+	IRDA_ASSERT(priv != NULL, return -ENODEV;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
 
 	IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __FUNCTION__, cmd);
 
 	dev = priv->dev;
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	switch (cmd) {
 	case TCGETS:
@@ -460,7 +460,7 @@ static int irtty_ioctl(struct tty_struct
 		break;
 
 	case IRTTY_IOCGET:
-		ASSERT(dev->netdev != NULL, return -1;);
+		IRDA_ASSERT(dev->netdev != NULL, return -1;);
 
 		memset(&info, 0, sizeof(info)); 
 		strncpy(info.name, dev->netdev->name, sizeof(info.name)-1);
@@ -558,8 +558,8 @@ static void irtty_close(struct tty_struc
 {
 	struct sirtty_cb *priv = tty->disc_data;
 
-	ASSERT(priv != NULL, return;);
-	ASSERT(priv->magic == IRTTY_MAGIC, return;);
+	IRDA_ASSERT(priv != NULL, return;);
+	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
 	/* Hm, with a dongle attached the dongle driver wants
 	 * to close the dongle - which requires the use of
@@ -617,8 +617,8 @@ static int __init irtty_sir_init(void)
 	int err;
 
 	if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)
-		ERROR("IrDA: can't register line discipline (err = %d)\n",
-			err);
+		IRDA_ERROR("IrDA: can't register line discipline (err = %d)\n",
+			   err);
 	return err;
 }
 
@@ -627,8 +627,8 @@ static void __exit irtty_sir_cleanup(voi
 	int err;
 
 	if ((err = tty_register_ldisc(N_IRDA, NULL))) {
-		ERROR("%s(), can't unregister line discipline (err = %d)\n",
-		      __FUNCTION__, err);
+		IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n",
+			   __FUNCTION__, err);
 	}
 }
 
diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c
--- a/drivers/net/irda/ma600-sir.c
+++ b/drivers/net/irda/ma600-sir.c
@@ -191,8 +191,7 @@ static int ma600_change_speed(struct sir
 	sirdev_raw_write(dev, &byte, sizeof(byte));
 
 	/* Wait at least 10ms: fake wait_until_sent - 10 bits at 9600 baud*/
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(15));		/* old ma600 uses 15ms */
+	msleep(15);					/* old ma600 uses 15ms */
 
 #if 1
 	/* read-back of the control byte. ma600 is the first dongle driver
@@ -202,9 +201,9 @@ static int ma600_change_speed(struct sir
 
 	sirdev_raw_read(dev, &byte, sizeof(byte));
 	if (byte != get_control_byte(speed))  {
-		WARNING("%s(): bad control byte read-back %02x != %02x\n",
-			__FUNCTION__, (unsigned) byte,
-			(unsigned) get_control_byte(speed));
+		IRDA_WARNING("%s(): bad control byte read-back %02x != %02x\n",
+			     __FUNCTION__, (unsigned) byte,
+			     (unsigned) get_control_byte(speed));
 		return -1;
 	}
 	else
@@ -215,8 +214,7 @@ static int ma600_change_speed(struct sir
 	sirdev_set_dtr_rts(dev, TRUE, TRUE);
 
 	/* Wait at least 10ms */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(10));
+	msleep(10);
 
 	/* dongle is now switched to the new speed */
 	dev->speed = speed;
@@ -245,13 +243,11 @@ int ma600_reset(struct sir_dev *dev)
 
 	/* Reset the dongle : set DTR low for 10 ms */
 	sirdev_set_dtr_rts(dev, FALSE, TRUE);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(10));
+	msleep(10);
 
 	/* Go back to normal mode */
 	sirdev_set_dtr_rts(dev, TRUE, TRUE);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(10));
+	msleep(10);
 
 	dev->speed = 9600;      /* That's the dongle-default */
 
diff --git a/drivers/net/irda/ma600.c b/drivers/net/irda/ma600.c
--- a/drivers/net/irda/ma600.c
+++ b/drivers/net/irda/ma600.c
@@ -209,7 +209,8 @@ static int ma600_change_speed(struct ird
 		break;
 
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), resetting dongle timed out!\n",
+			     __FUNCTION__);
 		ret = -1;
 		break;
 
@@ -267,7 +268,8 @@ static int ma600_change_speed(struct ird
 		break;
 
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -320,7 +322,8 @@ int ma600_reset(struct irda_task *task)
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);		
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/mcp2120-sir.c b/drivers/net/irda/mcp2120-sir.c
--- a/drivers/net/irda/mcp2120-sir.c
+++ b/drivers/net/irda/mcp2120-sir.c
@@ -155,7 +155,7 @@ static int mcp2120_change_speed(struct s
 		break;
 
 	default:
-		ERROR("%s(), undefine state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s(), undefine state %d\n", __FUNCTION__, state);
 		ret = -EINVAL;
 		break;
 	}
@@ -213,7 +213,7 @@ static int mcp2120_reset(struct sir_dev 
 		break;
 
 	default:
-		ERROR("%s(), undefined state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state);
 		ret = -EINVAL;
 		break;
 	}
diff --git a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c
--- a/drivers/net/irda/mcp2120.c
+++ b/drivers/net/irda/mcp2120.c
@@ -103,7 +103,8 @@ static int mcp2120_change_speed(struct i
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), resetting dongle timed out!\n",
+			     __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -151,7 +152,8 @@ static int mcp2120_change_speed(struct i
                 //printk("mcp2120_change_speed irda_task_wait\n");
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -206,7 +208,8 @@ static int mcp2120_reset(struct irda_tas
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -94,16 +94,13 @@ static nsc_chip_t chips[] = {
 	  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 Steffen Pingel - IBM X40 */
+	{ "PC8738x", { 0x164e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
 	/* Contributed by Jan Frey - IBM A30/A31 */
 	{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
 	{ NULL }
-#if 0
-	/* Probably bogus, "PC8739x" should be the real thing. Jean II */
-	/* Contributed by Kevin Thayer - OmniBook 6100 */
-	{ "PC87338?", { 0x2e, 0x15c, 0x398 }, 0x08, 0x00, 0xf8, 
-	  nsc_ircc_probe_338, nsc_ircc_init_338 },
-#endif
 };
 
 /* Max 4 instances for now */
@@ -253,18 +250,18 @@ static int __init nsc_ircc_open(int i, c
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
-		info->cfg_base);
+	IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
+		     info->cfg_base);
 
 	if ((nsc_ircc_setup(info)) == -1)
 		return -1;
 
-	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+	IRDA_MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
 
 	dev = alloc_irdadev(sizeof(struct nsc_ircc_cb));
 	if (dev == NULL) {
-		ERROR("%s(), can't allocate memory for "
-		       "control block!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate memory for "
+			   "control block!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -287,8 +284,8 @@ static int __init nsc_ircc_open(int i, c
 	/* Reserve the ioports that we need */
 	ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 	if (!ret) {
-		WARNING("%s(), can't get iobase of 0x%03x\n",
-			__FUNCTION__, self->io.fir_base);
+		IRDA_WARNING("%s(), can't get iobase of 0x%03x\n",
+			     __FUNCTION__, self->io.fir_base);
 		err = -ENODEV;
 		goto out1;
 	}
@@ -346,21 +343,21 @@ static int __init nsc_ircc_open(int i, c
 
 	err = register_netdev(dev);
 	if (err) {
-		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		goto out4;
 	}
-	MESSAGE("IrDA: Registered device %s\n", dev->name);
+	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	/* Check if user has supplied a valid dongle id or not */
 	if ((dongle_id <= 0) ||
 	    (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
 		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
 		
-		MESSAGE("%s, Found dongle: %s\n", driver_name,
-			dongle_types[dongle_id]);
+		IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
+			     dongle_types[dongle_id]);
 	} else {
-		MESSAGE("%s, Using dongle: %s\n", driver_name,
-			dongle_types[dongle_id]);
+		IRDA_MESSAGE("%s, Using dongle: %s\n", driver_name,
+			     dongle_types[dongle_id]);
 	}
 	
 	self->io.dongle_id = dongle_id;
@@ -397,7 +394,7 @@ static int __exit nsc_ircc_close(struct 
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
         iobase = self->io.fir_base;
 
@@ -444,7 +441,7 @@ static int nsc_ircc_init_108(nsc_chip_t 
 	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("%s(), invalid base_address", __FUNCTION__);
+	default: IRDA_ERROR("%s(), invalid base_address", __FUNCTION__);
 	}
 	
 	/* Control Signal Routing Register (CSRT) */
@@ -456,7 +453,7 @@ static int nsc_ircc_init_108(nsc_chip_t 
 	case 9:  temp = 0x05; break;
 	case 11: temp = 0x06; break;
 	case 15: temp = 0x07; break;
-	default: ERROR("%s(), invalid irq", __FUNCTION__);
+	default: IRDA_ERROR("%s(), invalid irq", __FUNCTION__);
 	}
 	outb(CFG_108_CSRT, cfg_base);
 	
@@ -464,7 +461,7 @@ static int nsc_ircc_init_108(nsc_chip_t 
 	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("%s(), invalid dma", __FUNCTION__);
+	default: IRDA_ERROR("%s(), invalid dma", __FUNCTION__);
 	}
 	
 	outb(CFG_108_MCTL, cfg_base);      /* Mode Control Register (MCTL) */
@@ -828,7 +825,8 @@ static int nsc_ircc_setup(chipio_t *info
 
 	/* Should be 0x2? */
 	if (0x20 != (version & 0xf0)) {
-		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		IRDA_ERROR("%s, Wrong chip version %02x\n",
+			   driver_name, version);
 		return -1;
 	}
 
@@ -1092,7 +1090,7 @@ static __u8 nsc_ircc_change_speed(struct
 
 	IRDA_DEBUG(2, "%s(), speed=%d\n", __FUNCTION__, speed);
 
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.fir_base;
 
@@ -1200,7 +1198,7 @@ static int nsc_ircc_hard_xmit_sir(struct
 	
 	self = (struct nsc_ircc_cb *) dev->priv;
 
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.fir_base;
 
@@ -1705,8 +1703,9 @@ static int nsc_ircc_dma_receive_complete
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				WARNING("%s(), memory squeeze, "
-					"dropping frame.\n", __FUNCTION__);
+				IRDA_WARNING("%s(), memory squeeze, "
+					     "dropping frame.\n",
+					     __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				/* Restore bank register */
@@ -1892,9 +1891,9 @@ static void nsc_ircc_fir_interrupt(struc
 					nsc_ircc_dma_receive(self);
 					self->ier = IER_SFIF_IE;
 				} else
-					WARNING("%s(), potential "
-						"Tx queue lockup !\n",
-						__FUNCTION__);
+					IRDA_WARNING("%s(), potential "
+						     "Tx queue lockup !\n",
+						     __FUNCTION__);
 			}
 		} else {
 			/*  Not finished yet, so interrupt on DMA again */
@@ -1927,7 +1926,8 @@ static irqreturn_t nsc_ircc_interrupt(in
 	int iobase;
 
 	if (!dev) {
-		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+		IRDA_WARNING("%s: irq %d for unknown device.\n",
+			     driver_name, irq);
 		return IRQ_NONE;
 	}
 	self = (struct nsc_ircc_cb *) dev->priv;
@@ -1972,7 +1972,7 @@ static int nsc_ircc_is_receiving(struct 
 	int iobase;
 	__u8 bank;
 
-	ASSERT(self != NULL, return FALSE;);
+	IRDA_ASSERT(self != NULL, return FALSE;);
 
 	spin_lock_irqsave(&self->lock, flags);
 
@@ -2010,16 +2010,16 @@ static int nsc_ircc_net_open(struct net_
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct nsc_ircc_cb *) dev->priv;
 	
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 	
 	if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
-		WARNING("%s, unable to allocate irq=%d\n", driver_name, 
-			self->io.irq);
+		IRDA_WARNING("%s, unable to allocate irq=%d\n",
+			     driver_name, self->io.irq);
 		return -EAGAIN;
 	}
 	/*
@@ -2027,8 +2027,8 @@ static int nsc_ircc_net_open(struct net_
 	 * failure.
 	 */
 	if (request_dma(self->io.dma, dev->name)) {
-		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
-			self->io.dma);
+		IRDA_WARNING("%s, unable to allocate dma=%d\n",
+			     driver_name, self->io.dma);
 		free_irq(self->io.irq, dev);
 		return -EAGAIN;
 	}
@@ -2072,10 +2072,10 @@ static int nsc_ircc_net_close(struct net
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = (struct nsc_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
 	netif_stop_queue(dev);
@@ -2118,11 +2118,11 @@ static int nsc_ircc_net_ioctl(struct net
 	unsigned long flags;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
@@ -2162,7 +2162,7 @@ static struct net_device_stats *nsc_ircc
 
 static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
 {
-	MESSAGE("%s, Suspending\n", driver_name);
+	IRDA_MESSAGE("%s, Suspending\n", driver_name);
 
 	if (self->io.suspended)
 		return;
@@ -2180,7 +2180,7 @@ static void nsc_ircc_wakeup(struct nsc_i
 	nsc_ircc_setup(&self->io);
 	nsc_ircc_net_open(self->netdev);
 	
-	MESSAGE("%s, Waking up\n", driver_name);
+	IRDA_MESSAGE("%s, Waking up\n", driver_name);
 
 	self->io.suspended = 0;
 }
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -291,7 +291,7 @@ static void sa1100_irda_shutdown(struct 
 /*
  * Suspend the IrDA interface.
  */
-static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level)
+static int sa1100_irda_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
 	struct net_device *dev = dev_get_drvdata(_dev);
 	struct sa1100_irda *si;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/delay.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/wrapper.h>
@@ -73,8 +74,7 @@ int sirdev_raw_write(struct sir_dev *dev
 	spin_lock_irqsave(&dev->tx_lock, flags);	/* serialize with other tx operations */
 	while (dev->tx_buff.len > 0) {			/* wait until tx idle */
 		spin_unlock_irqrestore(&dev->tx_lock, flags);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(msecs_to_jiffies(10));
+		msleep(10);
 		spin_lock_irqsave(&dev->tx_lock, flags);
 	}
 
@@ -154,7 +154,8 @@ void sirdev_write_complete(struct sir_de
 		}
 		else if (unlikely(actual<0)) {
 			/* could be dropped later when we have tx_timeout to recover */
-			ERROR("%s: drv->do_write failed (%d)\n", __FUNCTION__, actual);
+			IRDA_ERROR("%s: drv->do_write failed (%d)\n",
+				   __FUNCTION__, actual);
 			if ((skb=dev->tx_skb) != NULL) {
 				dev->tx_skb = NULL;
 				dev_kfree_skb_any(skb);
@@ -208,7 +209,8 @@ void sirdev_write_complete(struct sir_de
 			/* should never happen
 			 * forget the speed change and hope the stack recovers
 			 */
-			ERROR("%s - schedule speed change failed: %d\n", __FUNCTION__, err);
+			IRDA_ERROR("%s - schedule speed change failed: %d\n",
+				   __FUNCTION__, err);
 			netif_wake_queue(dev->netdev);
 		}
 		/* else: success
@@ -234,13 +236,13 @@ done:
 int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) 
 {
 	if (!dev || !dev->netdev) {
-		WARNING("%s(), not ready yet!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), not ready yet!\n", __FUNCTION__);
 		return -1;
 	}
 
 	if (!dev->irlap) {
-		WARNING("%s - too early: %p / %zd!\n",
-			__FUNCTION__, cp, count);
+		IRDA_WARNING("%s - too early: %p / %zd!\n",
+			     __FUNCTION__, cp, count);
 		return -1;
 	}
 
@@ -297,7 +299,7 @@ static int sirdev_hard_xmit(struct sk_bu
 	int err;
 	s32 speed;
 
-	ASSERT(dev != NULL, return 0;);
+	IRDA_ASSERT(dev != NULL, return 0;);
 
 	netif_stop_queue(ndev);
 
@@ -366,7 +368,8 @@ static int sirdev_hard_xmit(struct sk_bu
 	}
 	else if (unlikely(actual < 0)) {
 		/* could be dropped later when we have tx_timeout to recover */
-		ERROR("%s: drv->do_write failed (%d)\n", __FUNCTION__, actual);
+		IRDA_ERROR("%s: drv->do_write failed (%d)\n",
+			   __FUNCTION__, actual);
 		dev_kfree_skb_any(skb);
 		dev->stats.tx_errors++;		      
 		dev->stats.tx_dropped++;		      
@@ -385,7 +388,7 @@ static int sirdev_ioctl(struct net_devic
 	struct sir_dev *dev = ndev->priv;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, ndev->name, cmd);
 	
@@ -593,7 +596,7 @@ struct sir_dev * sirdev_get_instance(con
 	 */
 	ndev = alloc_irdadev(sizeof(*dev));
 	if (ndev == NULL) {
-		ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__);
+		IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__);
 		goto out;
 	}
 	dev = ndev->priv;
@@ -628,7 +631,7 @@ struct sir_dev * sirdev_get_instance(con
 	ndev->do_ioctl = sirdev_ioctl;
 
 	if (register_netdev(ndev)) {
-		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		goto out_freenetdev;
 	}
 
@@ -654,7 +657,7 @@ int sirdev_put_instance(struct sir_dev *
 	if (dev->dongle_drv)
 		err = sirdev_schedule_dongle_close(dev);
 	if (err)
-		ERROR("%s - error %d\n", __FUNCTION__, err);
+		IRDA_ERROR("%s - error %d\n", __FUNCTION__, err);
 
 	sirdev_close(dev->netdev);
 
diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c
--- a/drivers/net/irda/sir_kthread.c
+++ b/drivers/net/irda/sir_kthread.c
@@ -222,7 +222,7 @@ static int irda_tx_complete_fsm(struct s
 			return 0;
 
 		default:
-			ERROR("%s - undefined state\n", __FUNCTION__);
+			IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
 			return -EINVAL;
 		}
 		fsm->substate = next_state;
@@ -391,12 +391,12 @@ static void irda_config_fsm(void *data)
 			break;
 
 		default:
-			ERROR("%s - undefined state\n", __FUNCTION__);
+			IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
 			fsm->result = -EINVAL;
 			/* fall thru */
 
 		case SIRDEV_STATE_ERROR:
-			ERROR("%s - error: %d\n", __FUNCTION__, fsm->result);
+			IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result);
 
 #if 0	/* don't enable this before we have netdev->tx_timeout to recover */
 			netif_stop_queue(dev->netdev);
@@ -439,7 +439,7 @@ int sirdev_schedule_request(struct sir_d
 
 	if (fsm->state == SIRDEV_STATE_DEAD) {
 		/* race with sirdev_close should never happen */
-		ERROR("%s(), instance staled!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__);
 		up(&fsm->sem);
 		return -ESTALE;		/* or better EPIPE? */
 	}
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -203,7 +203,7 @@ static int smsc_ircc_pmproc(struct pm_de
 
 /* Transceivers for SMSC-ircc */
 
-smsc_transceiver_t smsc_transceivers[]=
+static smsc_transceiver_t smsc_transceivers[]=
 {
 	{ "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
 	{ "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
@@ -334,8 +334,8 @@ static int __init smsc_ircc_init(void)
 	dev_count=0;
  
 	if ((ircc_fir>0)&&(ircc_sir>0)) {
-		MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
-		MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+		IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
+		IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
 
 		if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
 			return 0;
@@ -345,7 +345,8 @@ static int __init smsc_ircc_init(void)
 
 	/* try user provided configuration register base address */
 	if (ircc_cfg>0) {
-	        MESSAGE(" Overriding configuration address 0x%04x\n", ircc_cfg);
+	        IRDA_MESSAGE(" Overriding configuration address 0x%04x\n",
+			     ircc_cfg);
 		if (!smsc_superio_fdc(ircc_cfg))
 			ret = 0;
 		if (!smsc_superio_lpc(ircc_cfg))
@@ -377,7 +378,7 @@ static int __init smsc_ircc_open(unsigne
 		
 	err = -ENOMEM;
 	if (dev_count > DIM(dev_self)) {
-	        WARNING("%s(), too many devices!\n", __FUNCTION__);
+	        IRDA_WARNING("%s(), too many devices!\n", __FUNCTION__);
 		goto err_out1;
 	}
 
@@ -386,7 +387,7 @@ static int __init smsc_ircc_open(unsigne
 	 */
 	dev = alloc_irdadev(sizeof(struct smsc_ircc_cb));
 	if (!dev) {
-		WARNING("%s() can't allocate net device\n", __FUNCTION__);
+		IRDA_WARNING("%s() can't allocate net device\n", __FUNCTION__);
 		goto err_out1;
 	}
 
@@ -420,8 +421,8 @@ static int __init smsc_ircc_open(unsigne
 		dma_alloc_coherent(NULL, self->rx_buff.truesize,
 				   &self->rx_buff_dma, GFP_KERNEL);
 	if (self->rx_buff.head == NULL) {
-		ERROR("%s, Can't allocate memory for receive buffer!\n",
-                      driver_name);
+		IRDA_ERROR("%s, Can't allocate memory for receive buffer!\n",
+			   driver_name);
 		goto err_out2;
 	}
 
@@ -429,8 +430,8 @@ static int __init smsc_ircc_open(unsigne
 		dma_alloc_coherent(NULL, self->tx_buff.truesize,
 				   &self->tx_buff_dma, GFP_KERNEL);
 	if (self->tx_buff.head == NULL) {
-		ERROR("%s, Can't allocate memory for transmit buffer!\n",
-                      driver_name);
+		IRDA_ERROR("%s, Can't allocate memory for transmit buffer!\n",
+			   driver_name);
 		goto err_out3;
 	}
 
@@ -456,8 +457,8 @@ static int __init smsc_ircc_open(unsigne
 
 	err = register_netdev(self->netdev);
 	if(err) {
-		ERROR("%s, Network device registration failed!\n",
-		      driver_name);
+		IRDA_ERROR("%s, Network device registration failed!\n",
+			   driver_name);
 		goto err_out4;
 	}
 
@@ -465,7 +466,7 @@ static int __init smsc_ircc_open(unsigne
 	if (self->pmdev)
 		self->pmdev->data = self;
 
-	MESSAGE("IrDA: Registered device %s\n", dev->name);
+	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	return 0;
  err_out4:
@@ -496,15 +497,15 @@ static int smsc_ircc_present(unsigned in
 
 	if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT,
 			    driver_name)) {
-		WARNING("%s: can't get fir_base of 0x%03x\n",
-			__FUNCTION__, fir_base);
+		IRDA_WARNING("%s: can't get fir_base of 0x%03x\n",
+			     __FUNCTION__, fir_base);
 		goto out1;
 	}
 
 	if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT,
 			    driver_name)) {
-		WARNING("%s: can't get sir_base of 0x%03x\n",
-			__FUNCTION__, sir_base);
+		IRDA_WARNING("%s: can't get sir_base of 0x%03x\n",
+			     __FUNCTION__, sir_base);
 		goto out2;
 	}
 
@@ -519,13 +520,13 @@ static int smsc_ircc_present(unsigned in
 	irq     = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
 
 	if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 
-	        WARNING("%s(), addr 0x%04x - no device found!\n",
-			__FUNCTION__, fir_base);
+	        IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
+			     __FUNCTION__, fir_base);
 		goto out3;
 	}
-	MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
-		"firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
-		chip & 0x0f, version, fir_base, sir_base, dma, irq);
+	IRDA_MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
+		     "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
+		     chip & 0x0f, version, fir_base, sir_base, dma, irq);
 
 	return 0;
  out3:
@@ -562,8 +563,8 @@ static void smsc_ircc_setup_io(struct sm
 
 	if (irq < 255) {
 		if (irq != chip_irq)
-			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
-				driver_name, chip_irq, irq);
+			IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
+				     driver_name, chip_irq, irq);
 		self->io.irq = irq;
 	}
 	else
@@ -571,8 +572,8 @@ static void smsc_ircc_setup_io(struct sm
 	
 	if (dma < 255) {
 		if (dma != chip_dma)
-			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
-				driver_name, chip_dma, dma);
+			IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
+				     driver_name, chip_dma, dma);
 		self->io.dma = dma;
 	}
 	else
@@ -609,7 +610,7 @@ static void smsc_ircc_init_chip(struct s
 {
 	int iobase, ir_mode, ctrl, fast; 
 	
-	ASSERT( self != NULL, return; );
+	IRDA_ASSERT( self != NULL, return; );
 	iobase = self->io.fir_base;
 
 	ir_mode = IRCC_CFGA_IRDA_SIR_A;
@@ -659,11 +660,11 @@ static int smsc_ircc_net_ioctl(struct ne
 	unsigned long flags;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
@@ -728,7 +729,8 @@ static void smsc_ircc_timeout(struct net
 
 	self = (struct smsc_ircc_cb *) dev->priv;
 	
-	WARNING("%s: transmit timed out, changing speed to: %d\n", dev->name, self->io.speed);
+	IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",
+		     dev->name, self->io.speed);
 	spin_lock_irqsave(&self->lock, flags);
 	smsc_ircc_sir_start(self);
 	smsc_ircc_change_speed(self, self->io.speed);
@@ -754,10 +756,10 @@ int smsc_ircc_hard_xmit_sir(struct sk_bu
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return 0;);
+	IRDA_ASSERT(dev != NULL, return 0;);
 	
 	self = (struct smsc_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.sir_base;
 
@@ -819,7 +821,7 @@ static void smsc_ircc_set_fir_speed(stru
 {
 	int fir_base, ir_mode, ctrl, fast;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	fir_base = self->io.fir_base;
 
 	self->io.speed = speed;
@@ -874,9 +876,9 @@ static void smsc_ircc_fir_start(struct s
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	dev = self->netdev;
-	ASSERT(dev != NULL, return;);
+	IRDA_ASSERT(dev != NULL, return;);
 
 	fir_base = self->io.fir_base;
 
@@ -922,7 +924,7 @@ static void smsc_ircc_fir_stop(struct sm
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 	
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	fir_base = self->io.fir_base;
 	register_bank(fir_base, 0);
@@ -948,7 +950,7 @@ static void smsc_ircc_change_speed(void 
 	
 	IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	dev = self->netdev;
 	iobase = self->io.fir_base;
 
@@ -1018,7 +1020,7 @@ void smsc_ircc_set_sir_speed(void *priv,
 
 	IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	iobase = self->io.sir_base;
 	
 	/* Update accounting for new speed */
@@ -1071,9 +1073,9 @@ static int smsc_ircc_hard_xmit_fir(struc
 	int iobase;
 	int mtt;
 
-	ASSERT(dev != NULL, return 0;);
+	IRDA_ASSERT(dev != NULL, return 0;);
 	self = (struct smsc_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.fir_base;
 
@@ -1325,15 +1327,15 @@ static void smsc_ircc_dma_receive_comple
 		len -= 4;
 
 	if ((len < 2) || (len > 2050)) {
-		WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
+		IRDA_WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
 		return;
 	}
 	IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
 
 	skb = dev_alloc_skb(len+1);
 	if (!skb)  {
-		WARNING("%s(), memory squeeze, dropping frame.\n",
-			__FUNCTION__);
+		IRDA_WARNING("%s(), memory squeeze, dropping frame.\n",
+			     __FUNCTION__);
 		return;
 	}			
 	/* Make sure IP header gets aligned */
@@ -1360,7 +1362,7 @@ static void smsc_ircc_sir_receive(struct
 	int boguscount = 0;
 	int iobase;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
 
@@ -1400,7 +1402,7 @@ static irqreturn_t smsc_ircc_interrupt(i
 		goto irq_ret;
 	}
 	self = (struct smsc_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return IRQ_NONE;);
+	IRDA_ASSERT(self != NULL, return IRQ_NONE;);
 
 	/* Serialise the interrupt handler in various CPUs, stop Tx path */
 	spin_lock(&self->lock);	
@@ -1521,7 +1523,7 @@ static int ircc_is_receiving(struct smsc
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return FALSE;);
+	IRDA_ASSERT(self != NULL, return FALSE;);
 
 	IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__,
 		   get_dma_residue(self->io.dma));
@@ -1548,9 +1550,9 @@ static int smsc_ircc_net_open(struct net
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct smsc_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 
@@ -1584,8 +1586,8 @@ static int smsc_ircc_net_open(struct net
 	if (request_dma(self->io.dma, dev->name)) {
 		smsc_ircc_net_close(dev);
 
-		WARNING("%s(), unable to allocate DMA=%d\n",
-			__FUNCTION__, self->io.dma);
+		IRDA_WARNING("%s(), unable to allocate DMA=%d\n",
+			     __FUNCTION__, self->io.dma);
 		return -EAGAIN;
 	}
 	
@@ -1607,9 +1609,9 @@ static int smsc_ircc_net_close(struct ne
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct smsc_ircc_cb *) dev->priv;	
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 
@@ -1633,7 +1635,7 @@ static int smsc_ircc_net_close(struct ne
 
 static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
 {
-	MESSAGE("%s, Suspending\n", driver_name);
+	IRDA_MESSAGE("%s, Suspending\n", driver_name);
 
 	if (self->io.suspended)
 		return;
@@ -1654,7 +1656,7 @@ static void smsc_ircc_wakeup(struct smsc
 
 	smsc_ircc_net_open(self->netdev);
 	
-	MESSAGE("%s, Waking up\n", driver_name);
+	IRDA_MESSAGE("%s, Waking up\n", driver_name);
 }
 
 static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
@@ -1686,7 +1688,7 @@ static int __exit smsc_ircc_close(struct
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	iobase = self->io.fir_base;
 
@@ -1761,9 +1763,9 @@ void smsc_ircc_sir_start(struct smsc_irc
 
 	IRDA_DEBUG(3, "%s\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);	
+	IRDA_ASSERT(self != NULL, return;);	
 	dev= self->netdev;
-	ASSERT(dev != NULL, return;);		
+	IRDA_ASSERT(dev != NULL, return;);		
 	dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
 
 	fir_base = self->io.fir_base;
@@ -1820,7 +1822,7 @@ static void smsc_ircc_sir_write_wakeup(s
 	int iobase;
 	int fcr;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	IRDA_DEBUG(4, "%s\n", __FUNCTION__);
 
@@ -1885,7 +1887,7 @@ static int smsc_ircc_sir_write(int iobas
 	
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
 		return 0;
 	}
         
@@ -1920,15 +1922,17 @@ static void smsc_ircc_probe_transceiver(
 {
 	unsigned int	i;
 	
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	
 	for(i=0; smsc_transceivers[i].name!=NULL; i++) 
 		if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
-			MESSAGE(" %s transceiver found\n", smsc_transceivers[i].name);
+			IRDA_MESSAGE(" %s transceiver found\n",
+				     smsc_transceivers[i].name);
 			self->transceiver= i+1;
 			return;
 		}
-	MESSAGE("No transceiver found. Defaulting to %s\n", smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
+	IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",
+		     smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
 			
 	self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
 }
@@ -2052,7 +2056,7 @@ static int __init smsc_superio_flat(cons
 	/*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/
 	
 	if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
-		WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
+		IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
 
 	outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
 	sirbase = inb(cfgbase+1) << 2;
@@ -2069,7 +2073,7 @@ static int __init smsc_superio_flat(cons
 	outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
 	irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
 
-	MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
+	IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
 
 	if (firbase) {
 		if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
@@ -2201,15 +2205,15 @@ static const smsc_chip_t * __init smsc_i
 			return NULL;
 	}
 
-	MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+	IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
 
 	if (chip->rev>rev){
-		MESSAGE("Revision higher than expected\n");	
+		IRDA_MESSAGE("Revision higher than expected\n");	
 		return NULL;
 	}
 	
 	if (chip->flags&NoIRDA)
-		MESSAGE("chipset does not support IRDA\n");
+		IRDA_MESSAGE("chipset does not support IRDA\n");
 
 	return chip;
 }
@@ -2219,8 +2223,8 @@ static int __init smsc_superio_fdc(unsig
 	int ret = -1;
 
 	if (!request_region(cfg_base, 2, driver_name)) {
-		WARNING("%s: can't get cfg_base of 0x%03x\n",
-			__FUNCTION__, cfg_base);
+		IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
+			     __FUNCTION__, cfg_base);
 	} else {
 		if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")
 		    ||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
@@ -2237,8 +2241,8 @@ static int __init smsc_superio_lpc(unsig
 	int ret = -1;
 
 	if (!request_region(cfg_base, 2, driver_name)) {
-		WARNING("%s: can't get cfg_base of 0x%03x\n",
-			__FUNCTION__, cfg_base);
+		IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
+			     __FUNCTION__, cfg_base);
 	} else {
 		if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")
 		    ||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
@@ -2275,8 +2279,8 @@ static void smsc_ircc_set_transceiver_sm
 	outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
 	while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
 	if(val)
-		WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
-			inb(fir_base+IRCC_ATC));
+		IRDA_WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
+			     inb(fir_base+IRCC_ATC));
 }
 
 /*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -208,7 +208,7 @@ static int write_reg(struct stir_cb *sti
 			       REQ_WRITE_SINGLE,
 			       USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
 			       value, reg, NULL, 0,
-			       msecs_to_jiffies(CTRL_TIMEOUT));
+			       CTRL_TIMEOUT);
 }
 
 /* Send control message to read multiple registers */
@@ -221,7 +221,7 @@ static inline int read_reg(struct stir_c
 			       REQ_READ_REG,
 			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			       0, reg, data, count,
-			       msecs_to_jiffies(CTRL_TIMEOUT));
+			       CTRL_TIMEOUT);
 }
 
 static inline int isfir(u32 speed)
@@ -671,7 +671,8 @@ static void turnaround_delay(const struc
 		return;
 
 	do_gettimeofday(&now);
-	us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC;
+	if (now.tv_sec - stir->rx_time.tv_sec > 0)
+		us -= USEC_PER_SEC;
 	us -= now.tv_usec - stir->rx_time.tv_usec;
 	if (us < 10)
 		return;
@@ -740,7 +741,7 @@ static void stir_send(struct stir_cb *st
 
 	if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
 			 stir->io_buf, wraplen,
-			 NULL, msecs_to_jiffies(TRANSMIT_TIMEOUT)))
+			 NULL, TRANSMIT_TIMEOUT))
 		stir->stats.tx_errors++;
 }
 
@@ -787,7 +788,7 @@ static int stir_transmit_thread(void *ar
 				stir_send(stir, skb);
 			dev_kfree_skb(skb);
 
-			if (stir->speed != new_speed) {
+			if ((new_speed != -1) && (stir->speed != new_speed)) {
 				if (fifo_txwait(stir, -1) ||
 				    change_speed(stir, new_speed))
 					break;
@@ -1127,8 +1128,8 @@ static void stir_disconnect(struct usb_i
 }
 
 #ifdef CONFIG_PM
-/* Power management suspend, so power off the transmitter/receiver */
-static int stir_suspend(struct usb_interface *intf, u32 state)
+/* USB suspend, so power off the transmitter/receiver */
+static int stir_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct stir_cb *stir = usb_get_intfdata(intf);
 
diff --git a/drivers/net/irda/tekram-sir.c b/drivers/net/irda/tekram-sir.c
--- a/drivers/net/irda/tekram-sir.c
+++ b/drivers/net/irda/tekram-sir.c
@@ -179,7 +179,7 @@ static int tekram_change_speed(struct si
 		break;
 
 	default:
-		ERROR("%s - undefined state %d\n", __FUNCTION__, state);
+		IRDA_ERROR("%s - undefined state %d\n", __FUNCTION__, state);
 		ret = -EINVAL;
 		break;
 	}
@@ -210,8 +210,7 @@ static int tekram_reset(struct sir_dev *
 	sirdev_set_dtr_rts(dev, FALSE, TRUE); 
 
 	/* Should sleep 1 ms */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(1));
+	msleep(1);
 
 	/* Set DTR, Set RTS */
 	sirdev_set_dtr_rts(dev, TRUE, TRUE);
diff --git a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c
--- a/drivers/net/irda/tekram.c
+++ b/drivers/net/irda/tekram.c
@@ -109,7 +109,7 @@ static int tekram_change_speed(struct ir
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(task != NULL, return -1;);
+	IRDA_ASSERT(task != NULL, return -1;);
 
 	if (self->speed_task && self->speed_task != task) {
 		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
@@ -155,7 +155,8 @@ static int tekram_change_speed(struct ir
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), resetting dongle timed out!\n",
+			     __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -181,7 +182,8 @@ static int tekram_change_speed(struct ir
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -210,7 +212,7 @@ int tekram_reset(struct irda_task *task)
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(task != NULL, return -1;);
+	IRDA_ASSERT(task != NULL, return -1;);
 
 	if (self->reset_task && self->reset_task != task) {
 		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
@@ -249,7 +251,8 @@ int tekram_reset(struct irda_task *task)
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
+		IRDA_ERROR("%s(), unknown state %d\n",
+			   __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);		
 		self->reset_task = NULL;
 		ret = -1;
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -83,7 +83,7 @@ static struct via_ircc_cb *dev_self[] = 
 
 /* Some prototypes */
 static int via_ircc_open(int i, chipio_t * info, unsigned int id);
-static int __exit via_ircc_close(struct via_ircc_cb *self);
+static int via_ircc_close(struct via_ircc_cb *self);
 static int via_ircc_dma_receive(struct via_ircc_cb *self);
 static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
 					 int iobase);
@@ -111,7 +111,7 @@ static void hwreset(struct via_ircc_cb *
 static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase);
 static int upload_rxdata(struct via_ircc_cb *self, int iobase);
 static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id);
-static void __exit via_remove_one (struct pci_dev *pdev);
+static void __devexit via_remove_one (struct pci_dev *pdev);
 
 /* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */
 static void iodelay(int udelay)
@@ -140,7 +140,7 @@ static struct pci_driver via_driver = {
 	.name		= VIA_MODULE_NAME,
 	.id_table	= via_pci_tbl,
 	.probe		= via_init_one,
-	.remove		= via_remove_one,
+	.remove		= __devexit_p(via_remove_one),
 };
 
 
@@ -273,7 +273,7 @@ static int __devinit via_init_one (struc
  *    Close all configured chips
  *
  */
-static void __exit via_ircc_clean(void)
+static void via_ircc_clean(void)
 {
 	int i;
 
@@ -285,7 +285,7 @@ static void __exit via_ircc_clean(void)
 	}
 }
 
-static void __exit via_remove_one (struct pci_dev *pdev)
+static void __devexit via_remove_one (struct pci_dev *pdev)
 {
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
@@ -441,7 +441,7 @@ static __devinit int via_ircc_open(int i
 	if (err)
 		goto err_out4;
 
-	MESSAGE("IrDA: Registered device %s (via-ircc)\n", dev->name);
+	IRDA_MESSAGE("IrDA: Registered device %s (via-ircc)\n", dev->name);
 
 	/* Initialise the hardware..
 	*/
@@ -468,13 +468,13 @@ static __devinit int via_ircc_open(int i
  *    Close driver instance
  *
  */
-static int __exit via_ircc_close(struct via_ircc_cb *self)
+static int via_ircc_close(struct via_ircc_cb *self)
 {
 	int iobase;
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	iobase = self->io.fir_base;
 
@@ -565,7 +565,7 @@ static int via_ircc_read_dongle_id(int i
 {
 	int dongle_id = 9;	/* Default to IBM */
 
-	ERROR("via-ircc: dongle probing not supported, please specify dongle_id module parameter.\n");
+	IRDA_ERROR("via-ircc: dongle probing not supported, please specify dongle_id module parameter.\n");
 	return dongle_id;
 }
 
@@ -707,8 +707,8 @@ static void via_ircc_change_dongle_speed
 		break;
 
 	default:
-		ERROR("%s: Error: dongle_id %d unsupported !\n",
-		      __FUNCTION__, dongle_id);
+		IRDA_ERROR("%s: Error: dongle_id %d unsupported !\n",
+			   __FUNCTION__, dongle_id);
 	}
 }
 
@@ -826,7 +826,7 @@ static int via_ircc_hard_xmit_sir(struct
 	__u32 speed;
 
 	self = (struct via_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	iobase = self->io.fir_base;
 
 	netif_stop_queue(dev);
@@ -1351,8 +1351,8 @@ static irqreturn_t via_ircc_interrupt(in
 	u8 iHostIntType, iRxIntType, iTxIntType;
 
 	if (!dev) {
-		WARNING("%s: irq %d for unknown device.\n", driver_name,
-			irq);
+		IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name,
+			     irq);
 		return IRQ_NONE;
 	}
 	self = (struct via_ircc_cb *) dev->priv;
@@ -1498,7 +1498,7 @@ static int via_ircc_is_receiving(struct 
 	int status = FALSE;
 	int iobase;
 
-	ASSERT(self != NULL, return FALSE;);
+	IRDA_ASSERT(self != NULL, return FALSE;);
 
 	iobase = self->io.fir_base;
 	if (CkRxRecv(iobase, self))
@@ -1524,14 +1524,14 @@ static int via_ircc_net_open(struct net_
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct via_ircc_cb *) dev->priv;
 	self->stats.rx_packets = 0;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	iobase = self->io.fir_base;
 	if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) {
-		WARNING("%s, unable to allocate irq=%d\n", driver_name,
-			self->io.irq);
+		IRDA_WARNING("%s, unable to allocate irq=%d\n", driver_name,
+			     self->io.irq);
 		return -EAGAIN;
 	}
 	/*
@@ -1539,15 +1539,15 @@ static int via_ircc_net_open(struct net_
 	 * failure.
 	 */
 	if (request_dma(self->io.dma, dev->name)) {
-		WARNING("%s, unable to allocate dma=%d\n", driver_name,
-			self->io.dma);
+		IRDA_WARNING("%s, unable to allocate dma=%d\n", driver_name,
+			     self->io.dma);
 		free_irq(self->io.irq, self);
 		return -EAGAIN;
 	}
 	if (self->io.dma2 != self->io.dma) {
 		if (request_dma(self->io.dma2, dev->name)) {
-			WARNING("%s, unable to allocate dma2=%d\n",
-				driver_name, self->io.dma2);
+			IRDA_WARNING("%s, unable to allocate dma2=%d\n",
+				     driver_name, self->io.dma2);
 			free_irq(self->io.irq, self);
 			return -EAGAIN;
 		}
@@ -1590,9 +1590,9 @@ static int via_ircc_net_close(struct net
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct via_ircc_cb *) dev->priv;
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
 	netif_stop_queue(dev);
@@ -1627,9 +1627,9 @@ static int via_ircc_net_ioctl(struct net
 	unsigned long flags;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = dev->priv;
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name,
 		   cmd);
 	/* Disable interrupts & save flags */
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -435,8 +435,8 @@ static struct vlsi_ring *vlsi_alloc_ring
 		if (rd->buf == NULL
 		    ||  !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) {
 			if (rd->buf) {
-				ERROR("%s: failed to create PCI-MAP for %p",
-					__FUNCTION__, rd->buf);
+				IRDA_ERROR("%s: failed to create PCI-MAP for %p",
+					   __FUNCTION__, rd->buf);
 				kfree(rd->buf);
 				rd->buf = NULL;
 			}
@@ -490,7 +490,8 @@ static int vlsi_create_hwif(vlsi_irda_de
 
 	ringarea = pci_alloc_consistent(idev->pdev, HW_RING_AREA_SIZE, &idev->busaddr);
 	if (!ringarea) {
-		ERROR("%s: insufficient memory for descriptor rings\n", __FUNCTION__);
+		IRDA_ERROR("%s: insufficient memory for descriptor rings\n",
+			   __FUNCTION__);
 		goto out;
 	}
 	memset(ringarea, 0, HW_RING_AREA_SIZE);
@@ -587,7 +588,7 @@ static int vlsi_process_rx(struct vlsi_r
 	}
 
 	if (!rd->skb) {
-		WARNING("%s: rx packet lost\n", __FUNCTION__);
+		IRDA_WARNING("%s: rx packet lost\n", __FUNCTION__);
 		ret |= VLSI_RX_DROP;
 		goto done;
 	}
@@ -617,8 +618,8 @@ static void vlsi_fill_rx(struct vlsi_rin
 
 	for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) {
 		if (rd_is_active(rd)) {
-			WARNING("%s: driver bug: rx descr race with hw\n",
-				__FUNCTION__);
+			IRDA_WARNING("%s: driver bug: rx descr race with hw\n",
+				     __FUNCTION__);
 			vlsi_ring_debug(r);
 			break;
 		}
@@ -677,7 +678,7 @@ static void vlsi_rx_interrupt(struct net
 
 	if (ring_first(r) == NULL) {
 		/* we are in big trouble, if this should ever happen */
-		ERROR("%s: rx ring exhausted!\n", __FUNCTION__);
+		IRDA_ERROR("%s: rx ring exhausted!\n", __FUNCTION__);
 		vlsi_ring_debug(r);
 	}
 	else
@@ -789,8 +790,8 @@ static int vlsi_set_baud(vlsi_irda_dev_t
 		config = IRCFG_SIR | IRCFG_SIRFILT  | IRCFG_RXANY;
 		switch(baudrate) {
 			default:
-				WARNING("%s: undefined baudrate %d - fallback to 9600!\n",
-					__FUNCTION__, baudrate);
+				IRDA_WARNING("%s: undefined baudrate %d - fallback to 9600!\n",
+					     __FUNCTION__, baudrate);
 				baudrate = 9600;
 				/* fallthru */
 			case 2400:
@@ -831,14 +832,14 @@ static int vlsi_set_baud(vlsi_irda_dev_t
 		config ^= IRENABLE_SIR_ON;
 
 	if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) {
-		WARNING("%s: failed to set %s mode!\n", __FUNCTION__,
+		IRDA_WARNING("%s: failed to set %s mode!\n", __FUNCTION__,
 			(mode==IFF_SIR)?"SIR":((mode==IFF_MIR)?"MIR":"FIR"));
 		ret = -1;
 	}
 	else {
 		if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) {
-			WARNING("%s: failed to apply baudrate %d\n",
-				__FUNCTION__, baudrate);
+			IRDA_WARNING("%s: failed to apply baudrate %d\n",
+				     __FUNCTION__, baudrate);
 			ret = -1;
 		}
 		else {
@@ -982,8 +983,8 @@ static int vlsi_hard_start_xmit(struct s
 		 */
 
 		if (len >= r->len-5)
-			 WARNING("%s: possible buffer overflow with SIR wrapping!\n",
-			 	__FUNCTION__);
+			 IRDA_WARNING("%s: possible buffer overflow with SIR wrapping!\n",
+				      __FUNCTION__);
 	}
 	else {
 		/* hw deals with MIR/FIR mode wrapping */
@@ -1050,7 +1051,7 @@ static int vlsi_hard_start_xmit(struct s
 drop_unlock:
 	spin_unlock_irqrestore(&idev->lock, flags);
 drop:
-	WARNING("%s: dropping packet - %s\n", __FUNCTION__, msg);
+	IRDA_WARNING("%s: dropping packet - %s\n", __FUNCTION__, msg);
 	dev_kfree_skb_any(skb);
 	idev->stats.tx_errors++;
 	idev->stats.tx_dropped++;
@@ -1188,7 +1189,8 @@ static int vlsi_start_clock(struct pci_d
 		}
 		if (count < 3) {
 			if (clksrc == 1) { /* explicitly asked for PLL hence bail out */
-				ERROR("%s: no PLL or failed to lock!\n", __FUNCTION__);
+				IRDA_ERROR("%s: no PLL or failed to lock!\n",
+					   __FUNCTION__);
 				clkctl = CLKCTL_CLKSTP;
 				pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
 				return -1;
@@ -1269,7 +1271,7 @@ static int vlsi_init_chip(struct pci_dev
 	/* start the clock and clean the registers */
 
 	if (vlsi_start_clock(pdev)) {
-		ERROR("%s: no valid clock source\n", __FUNCTION__);
+		IRDA_ERROR("%s: no valid clock source\n", __FUNCTION__);
 		return -1;
 	}
 	iobase = ndev->base_addr;
@@ -1400,8 +1402,8 @@ static void vlsi_tx_timeout(struct net_d
 		idev->new_baud = idev->baud;		/* keep current baudrate */
 
 	if (vlsi_start_hw(idev))
-		ERROR("%s: failed to restart hw - %s(%s) unusable!\n",
-			__FUNCTION__, PCIDEV_NAME(idev->pdev), ndev->name);
+		IRDA_ERROR("%s: failed to restart hw - %s(%s) unusable!\n",
+			   __FUNCTION__, PCIDEV_NAME(idev->pdev), ndev->name);
 	else
 		netif_start_queue(ndev);
 }
@@ -1445,7 +1447,8 @@ static int vlsi_ioctl(struct net_device 
 			irq->ifr_receiving = (fifocnt!=0) ? 1 : 0;
 			break;
 		default:
-			WARNING("%s: notsupp - cmd=%04x\n", __FUNCTION__, cmd);
+			IRDA_WARNING("%s: notsupp - cmd=%04x\n",
+				     __FUNCTION__, cmd);
 			ret = -EOPNOTSUPP;
 	}	
 	
@@ -1490,7 +1493,8 @@ static irqreturn_t vlsi_interrupt(int ir
 	spin_unlock_irqrestore(&idev->lock,flags);
 
 	if (boguscount <= 0)
-		MESSAGE("%s: too much work in interrupt!\n", __FUNCTION__);
+		IRDA_MESSAGE("%s: too much work in interrupt!\n",
+			     __FUNCTION__);
 	return IRQ_RETVAL(handled);
 }
 
@@ -1503,7 +1507,7 @@ static int vlsi_open(struct net_device *
 	char	hwname[32];
 
 	if (pci_request_regions(idev->pdev, drivername)) {
-		WARNING("%s: io resource busy\n", __FUNCTION__);
+		IRDA_WARNING("%s: io resource busy\n", __FUNCTION__);
 		goto errout;
 	}
 	ndev->base_addr = pci_resource_start(idev->pdev,0);
@@ -1517,7 +1521,8 @@ static int vlsi_open(struct net_device *
 
 	if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ,
 			drivername, ndev)) {
-		WARNING("%s: couldn't get IRQ: %d\n", __FUNCTION__, ndev->irq);
+		IRDA_WARNING("%s: couldn't get IRQ: %d\n",
+			     __FUNCTION__, ndev->irq);
 		goto errout_io;
 	}
 
@@ -1538,7 +1543,7 @@ static int vlsi_open(struct net_device *
 
 	netif_start_queue(ndev);
 
-	MESSAGE("%s: device %s operational\n", __FUNCTION__, ndev->name);
+	IRDA_MESSAGE("%s: device %s operational\n", __FUNCTION__, ndev->name);
 
 	return 0;
 
@@ -1572,7 +1577,7 @@ static int vlsi_close(struct net_device 
 
 	pci_release_regions(idev->pdev);
 
-	MESSAGE("%s: device %s stopped\n", __FUNCTION__, ndev->name);
+	IRDA_MESSAGE("%s: device %s stopped\n", __FUNCTION__, ndev->name);
 
 	return 0;
 }
@@ -1593,7 +1598,7 @@ static int vlsi_irda_init(struct net_dev
 
 	if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW)
 	    || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) {
-		ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __FUNCTION__);
+		IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1640,18 +1645,19 @@ vlsi_irda_probe(struct pci_dev *pdev, co
 	else
 		pdev->current_state = 0; /* hw must be running now */
 
-	MESSAGE("%s: IrDA PCI controller %s detected\n",
-		drivername, PCIDEV_NAME(pdev));
+	IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n",
+		     drivername, PCIDEV_NAME(pdev));
 
 	if ( !pci_resource_start(pdev,0)
 	     || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) {
-		ERROR("%s: bar 0 invalid", __FUNCTION__);
+		IRDA_ERROR("%s: bar 0 invalid", __FUNCTION__);
 		goto out_disable;
 	}
 
 	ndev = alloc_irdadev(sizeof(*idev));
 	if (ndev==NULL) {
-		ERROR("%s: Unable to allocate device memory.\n", __FUNCTION__);
+		IRDA_ERROR("%s: Unable to allocate device memory.\n",
+			   __FUNCTION__);
 		goto out_disable;
 	}
 
@@ -1666,7 +1672,7 @@ vlsi_irda_probe(struct pci_dev *pdev, co
 		goto out_freedev;
 
 	if (register_netdev(ndev) < 0) {
-		ERROR("%s: register_netdev failed\n", __FUNCTION__);
+		IRDA_ERROR("%s: register_netdev failed\n", __FUNCTION__);
 		goto out_freedev;
 	}
 
@@ -1675,7 +1681,8 @@ vlsi_irda_probe(struct pci_dev *pdev, co
 
 		ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root);
 		if (!ent) {
-			WARNING("%s: failed to create proc entry\n", __FUNCTION__);
+			IRDA_WARNING("%s: failed to create proc entry\n",
+				     __FUNCTION__);
 		} else {
 			ent->data = ndev;
 			ent->proc_fops = VLSI_PROC_FOPS;
@@ -1683,7 +1690,7 @@ vlsi_irda_probe(struct pci_dev *pdev, co
 		}
 		idev->proc_entry = ent;
 	}
-	MESSAGE("%s: registered device %s\n", drivername, ndev->name);
+	IRDA_MESSAGE("%s: registered device %s\n", drivername, ndev->name);
 
 	pci_set_drvdata(pdev, ndev);
 	up(&idev->sem);
@@ -1706,7 +1713,7 @@ static void __devexit vlsi_irda_remove(s
 	vlsi_irda_dev_t *idev;
 
 	if (!ndev) {
-		ERROR("%s: lost netdevice?\n", drivername);
+		IRDA_ERROR("%s: lost netdevice?\n", drivername);
 		return;
 	}
 
@@ -1724,7 +1731,7 @@ static void __devexit vlsi_irda_remove(s
 
 	pci_set_drvdata(pdev, NULL);
 
-	MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev));
+	IRDA_MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev));
 }
 
 #ifdef CONFIG_PM
@@ -1737,18 +1744,19 @@ static void __devexit vlsi_irda_remove(s
  */
 
 
-static int vlsi_irda_suspend(struct pci_dev *pdev, u32 state)
+static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
 	vlsi_irda_dev_t *idev;
 
 	if (state < 1 || state > 3 ) {
-		ERROR("%s - %s: invalid pm state request: %u\n",
-			__FUNCTION__, PCIDEV_NAME(pdev), state);
+		IRDA_ERROR("%s - %s: invalid pm state request: %u\n",
+			   __FUNCTION__, PCIDEV_NAME(pdev), state);
 		return 0;
 	}
 	if (!ndev) {
-		ERROR("%s - %s: no netdevice \n", __FUNCTION__, PCIDEV_NAME(pdev));
+		IRDA_ERROR("%s - %s: no netdevice \n",
+			   __FUNCTION__, PCIDEV_NAME(pdev));
 		return 0;
 	}
 	idev = ndev->priv;	
@@ -1759,8 +1767,7 @@ static int vlsi_irda_suspend(struct pci_
 			pdev->current_state = state;
 		}
 		else
-			ERROR("%s - %s: invalid suspend request %u -> %u\n",
-				__FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state);
+			IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state);
 		up(&idev->sem);
 		return 0;
 	}
@@ -1787,14 +1794,16 @@ static int vlsi_irda_resume(struct pci_d
 	vlsi_irda_dev_t	*idev;
 
 	if (!ndev) {
-		ERROR("%s - %s: no netdevice \n", __FUNCTION__, PCIDEV_NAME(pdev));
+		IRDA_ERROR("%s - %s: no netdevice \n",
+			   __FUNCTION__, PCIDEV_NAME(pdev));
 		return 0;
 	}
 	idev = ndev->priv;	
 	down(&idev->sem);
 	if (pdev->current_state == 0) {
 		up(&idev->sem);
-		WARNING("%s - %s: already resumed\n", __FUNCTION__, PCIDEV_NAME(pdev));
+		IRDA_WARNING("%s - %s: already resumed\n",
+			     __FUNCTION__, PCIDEV_NAME(pdev));
 		return 0;
 	}
 	
@@ -1813,7 +1822,7 @@ static int vlsi_irda_resume(struct pci_d
 		 * now we explicitly set pdev->current_state = 0 after enabling the
 		 * device and independently resume_ok should catch any garbage config.
 		 */
-		WARNING("%s - hm, nothing to resume?\n", __FUNCTION__);
+		IRDA_WARNING("%s - hm, nothing to resume?\n", __FUNCTION__);
 		up(&idev->sem);
 		return 0;
 	}
@@ -1850,7 +1859,7 @@ static int __init vlsi_mod_init(void)
 	int	i, ret;
 
 	if (clksrc < 0  ||  clksrc > 3) {
-		ERROR("%s: invalid clksrc=%d\n", drivername, clksrc);
+		IRDA_ERROR("%s: invalid clksrc=%d\n", drivername, clksrc);
 		return -1;
 	}
 
@@ -1863,8 +1872,7 @@ static int __init vlsi_mod_init(void)
 			case 64:
 				break;
 			default:
-				WARNING("%s: invalid %s ringsize %d, using default=8",
-					drivername, (i)?"rx":"tx", ringsize[i]);
+				IRDA_WARNING("%s: invalid %s ringsize %d, using default=8", drivername, (i)?"rx":"tx", ringsize[i]);
 				ringsize[i] = 8;
 				break;
 		}
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -656,7 +656,7 @@ static inline void rd_set_addr_status(st
 	 */
 
 	if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {
-		ERROR("%s: pci busaddr inconsistency!\n", __FUNCTION__);
+		IRDA_ERROR("%s: pci busaddr inconsistency!\n", __FUNCTION__);
 		dump_stack();
 		return;
 	}
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -245,10 +245,10 @@ int w83977af_open(int i, unsigned int io
 
 	err = register_netdev(dev);
 	if (err) {
-		ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__);
 		goto err_out3;
 	}
-	MESSAGE("IrDA: Registered device %s\n", dev->name);
+	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	/* Need to store self somewhere */
 	dev_self[i] = self;
@@ -401,8 +401,8 @@ int w83977af_probe( int iobase, int irq,
 			switch_bank(iobase, SET7);
 			outb(0x40, iobase+7);
 			
-			MESSAGE("W83977AF (IR) driver loaded. "
-				"Version: 0x%02x\n", version);
+			IRDA_MESSAGE("W83977AF (IR) driver loaded. "
+				     "Version: 0x%02x\n", version);
 			
 			return 0;
 		} else {
@@ -691,7 +691,7 @@ static void w83977af_dma_xmit_complete(s
 
 	IRDA_DEBUG(4, "%s(%ld)\n", __FUNCTION__ , jiffies);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	iobase = self->io.fir_base;
 
@@ -743,7 +743,7 @@ int w83977af_dma_receive(struct w83977af
 	unsigned long flags;
 	__u8 hcr;
 #endif
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(4, "%s\n", __FUNCTION__ );
 
@@ -945,7 +945,7 @@ static void w83977af_pio_receive(struct 
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	
 	iobase = self->io.fir_base;
 	
@@ -1163,7 +1163,7 @@ static int w83977af_is_receiving(struct 
 	int iobase;
 	__u8 set;
 
-	ASSERT(self != NULL, return FALSE;);
+	IRDA_ASSERT(self != NULL, return FALSE;);
 
 	if (self->io.speed > 115200) {
 		iobase = self->io.fir_base;
@@ -1197,10 +1197,10 @@ static int w83977af_net_open(struct net_
 	
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	self = (struct w83977af_ir *) dev->priv;
 	
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 
@@ -1260,11 +1260,11 @@ static int w83977af_net_close(struct net
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 	
 	self = (struct w83977af_ir *) dev->priv;
 	
-	ASSERT(self != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, return 0;);
 	
 	iobase = self->io.fir_base;
 
@@ -1307,11 +1307,11 @@ static int w83977af_net_ioctl(struct net
 	unsigned long flags;
 	int ret = 0;
 
-	ASSERT(dev != NULL, return -1;);
+	IRDA_ASSERT(dev != NULL, return -1;);
 
 	self = dev->priv;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__ , dev->name, cmd);
 	
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -802,13 +802,14 @@ static void veth_tx_timeout(struct net_d
 
 	spin_lock_irqsave(&port->pending_gate, flags);
 
+	if (!port->pending_lpmask) {
+		spin_unlock_irqrestore(&port->pending_gate, flags);
+		return;
+	}
+
 	printk(KERN_WARNING "%s: Tx timeout!  Resetting lp connections: %08x\n",
 	       dev->name, port->pending_lpmask);
 
-	/* If we've timed out the queue must be stopped, which should
-	 * only ever happen when there is a pending packet. */
-	WARN_ON(! port->pending_lpmask);
-
 	for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
 		struct veth_lpar_connection *cnx = veth_cnx[i];
 
@@ -924,7 +925,7 @@ static int veth_transmit_to_one(struct s
 
 	spin_lock_irqsave(&cnx->lock, flags);
 
-	if (! cnx->state & VETH_STATE_READY)
+	if (! (cnx->state & VETH_STATE_READY))
 		goto drop;
 
 	if ((skb->len - 14) > VETH_MAX_MTU)
@@ -1023,6 +1024,8 @@ static int veth_start_xmit(struct sk_buf
 
 	lpmask = veth_transmit_to_many(skb, lpmask, dev);
 
+	dev->trans_start = jiffies;
+
 	if (! lpmask) {
 		dev_kfree_skb(skb);
 	} else {
@@ -1262,13 +1265,18 @@ static void veth_receive(struct veth_lpa
 
 		vlan = skb->data[9];
 		dev = veth_dev[vlan];
-		if (! dev)
-			/* Some earlier versions of the driver sent
-			   broadcasts down all connections, even to
-			   lpars that weren't on the relevant vlan.
-			   So ignore packets belonging to a vlan we're
-			   not on. */
+		if (! dev) {
+			/*
+			 * Some earlier versions of the driver sent
+			 * broadcasts down all connections, even to lpars
+			 * that weren't on the relevant vlan. So ignore
+			 * packets belonging to a vlan we're not on.
+			 * We can also be here if we receive packets while
+			 * the driver is going down, because then dev is NULL.
+			 */
+			dev_kfree_skb_irq(skb);
 			continue;
+		}
 
 		port = (struct veth_port *)dev->priv;
 		dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
@@ -1381,18 +1389,25 @@ void __exit veth_module_cleanup(void)
 {
 	int i;
 
-	vio_unregister_driver(&veth_driver);
+	/* Stop the queues first to stop any new packets being sent. */
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
+		if (veth_dev[i])
+			netif_stop_queue(veth_dev[i]);
 
+	/* Stop the connections before we unregister the driver. This
+	 * ensures there's no skbs lying around holding the device open. */
 	for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
 		veth_stop_connection(i);
 
 	HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
 
 	/* Hypervisor callbacks may have scheduled more work while we
-	 * were destroying connections. Now that we've disconnected from
+	 * were stoping connections. Now that we've disconnected from
 	 * the hypervisor make sure everything's finished. */
 	flush_scheduled_work();
 
+	vio_unregister_driver(&veth_driver);
+
 	for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
 		veth_destroy_connection(i);
 
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -110,7 +110,7 @@ struct ixgb_adapter;
 #define IXGB_TX_QUEUE_WAKE 16
 
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define IXGB_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+#define IXGB_RX_BUFFER_WRITE	4	/* Must be power of 2 */
 
 /* only works for sizes that are powers of 2 */
 #define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
@@ -176,6 +176,7 @@ struct ixgb_adapter {
 	uint64_t hw_csum_tx_error;
 	uint32_t tx_int_delay;
 	boolean_t tx_int_delay_enable;
+	boolean_t detect_tx_hung;
 
 	/* RX */
 	struct ixgb_desc_ring rx_ring;
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -372,11 +372,11 @@ ixgb_update_eeprom_checksum(struct ixgb_
  *
  *****************************************************************************/
 void
-ixgb_write_eeprom(struct ixgb_hw *hw,
-		   uint16_t offset,
-		   uint16_t data)
+ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data)
 {
-	/*  Prepare the EEPROM for writing  */
+	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
+
+	/* Prepare the EEPROM for writing */
 	ixgb_setup_eeprom(hw);
 
 	/*  Send the 9-bit EWEN (write enable) command to the EEPROM (5-bit opcode
@@ -410,6 +410,9 @@ ixgb_write_eeprom(struct ixgb_hw *hw,
 	/*  Done with writing  */
 	ixgb_cleanup_eeprom(hw);
 
+	/* clear the init_ctrl_reg_1 to signify that the cache is invalidated */
+	ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+
 	return;
 }
 
@@ -478,6 +481,9 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
 
 	if (checksum != (uint16_t) EEPROM_SUM) {
 		DEBUGOUT("ixgb_ee: Checksum invalid.\n");
+		/* clear the init_ctrl_reg_1 to signify that the cache is
+		 * invalidated */
+		ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
 		return (FALSE);
 	}
 
@@ -573,7 +579,7 @@ ixgb_get_ee_compatibility(struct ixgb_hw
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->compatibility);
+		return (le16_to_cpu(ee_map->compatibility));
 
 	return(0);
 }
@@ -610,7 +616,7 @@ ixgb_get_ee_init_ctrl_reg_1(struct ixgb_
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->init_ctrl_reg_1);
+		return (le16_to_cpu(ee_map->init_ctrl_reg_1));
 
 	return(0);
 }
@@ -629,7 +635,7 @@ ixgb_get_ee_init_ctrl_reg_2(struct ixgb_
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->init_ctrl_reg_2);
+		return (le16_to_cpu(ee_map->init_ctrl_reg_2));
 
 	return(0);
 }
@@ -648,7 +654,7 @@ ixgb_get_ee_subsystem_id(struct ixgb_hw 
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-	   return(ee_map->subsystem_id);
+		return (le16_to_cpu(ee_map->subsystem_id));
 
 	return(0);
 }
@@ -667,7 +673,7 @@ ixgb_get_ee_subvendor_id(struct ixgb_hw 
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->subvendor_id);
+		return (le16_to_cpu(ee_map->subvendor_id));
 
 	return(0);
 }
@@ -686,7 +692,7 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->device_id);
+		return (le16_to_cpu(ee_map->device_id));
 
 	return(0);
 }
@@ -705,7 +711,7 @@ ixgb_get_ee_vendor_id(struct ixgb_hw *hw
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->vendor_id);
+		return (le16_to_cpu(ee_map->vendor_id));
 
 	return(0);
 }
@@ -724,7 +730,7 @@ ixgb_get_ee_swdpins_reg(struct ixgb_hw *
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->swdpins_reg);
+		return (le16_to_cpu(ee_map->swdpins_reg));
 
 	return(0);
 }
@@ -743,7 +749,7 @@ ixgb_get_ee_d3_power(struct ixgb_hw *hw)
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->d3_power);
+		return (le16_to_cpu(ee_map->d3_power));
 
 	return(0);
 }
@@ -762,7 +768,7 @@ ixgb_get_ee_d0_power(struct ixgb_hw *hw)
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
 	if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-		return(ee_map->d0_power);
+		return (le16_to_cpu(ee_map->d0_power));
 
 	return(0);
 }
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -63,6 +63,7 @@
 
 #define EEPROM_ICW1_SIGNATURE_MASK  0xC000
 #define EEPROM_ICW1_SIGNATURE_VALID 0x4000
+#define EEPROM_ICW1_SIGNATURE_CLEAR 0x0000
 
 /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
 #define EEPROM_SUM 0xBABA
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -63,6 +63,7 @@ static struct ixgb_stats ixgb_gstrings_s
 	{"tx_dropped", IXGB_STAT(net_stats.tx_dropped)},
 	{"multicast", IXGB_STAT(net_stats.multicast)},
 	{"collisions", IXGB_STAT(net_stats.collisions)},
+
 /*	{ "rx_length_errors", IXGB_STAT(net_stats.rx_length_errors) },	*/
 	{"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)},
 	{"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)},
@@ -98,6 +99,7 @@ static int
 ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
 	struct ixgb_adapter *adapter = netdev->priv;
+
 	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	ecmd->port = PORT_FIBRE;
@@ -119,6 +121,7 @@ static int
 ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
 	struct ixgb_adapter *adapter = netdev->priv;
+
 	if(ecmd->autoneg == AUTONEG_ENABLE ||
 	   ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
 		return -EINVAL;
@@ -249,7 +252,9 @@ ixgb_get_regs(struct net_device *netdev,
 	uint32_t *reg_start = reg;
 	uint8_t i;
 
-	regs->version = (adapter->hw.device_id << 16) | adapter->hw.subsystem_id;
+	/* the 1 (one) below indicates an attempt at versioning, if the
+	 * interface in ethtool or the driver this 1 should be incremented */
+	regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id;
 
 	/* General Registers */
 	*reg++ = IXGB_READ_REG(hw, CTRL0);	/*   0 */
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -29,6 +29,9 @@
 #include "ixgb.h"
 
 /* Change Log
+ * 1.0.88 01/05/05
+ * - include fix to the condition that determines when to quit NAPI - Robert Olsson
+ * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
  * 1.0.84 10/26/04
  * - reset buffer_info->dma in Tx resource cleanup logic
  * 1.0.83 10/12/04
@@ -38,13 +41,14 @@
 
 char ixgb_driver_name[] = "ixgb";
 char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
+
 #ifndef CONFIG_IXGB_NAPI
 #define DRIVERNAPI
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-char ixgb_driver_version[] = "1.0.87-k2"DRIVERNAPI;
-char ixgb_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char ixgb_driver_version[] = "1.0.95-k2"DRIVERNAPI;
+char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* ixgb_pci_tbl - PCI Device ID Table
  *
@@ -99,6 +103,7 @@ static int ixgb_change_mtu(struct net_de
 static int ixgb_set_mac(struct net_device *netdev, void *p);
 static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs);
 static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
+
 #ifdef CONFIG_IXGB_NAPI
 static int ixgb_clean(struct net_device *netdev, int *budget);
 static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter,
@@ -116,33 +121,20 @@ static void ixgb_vlan_rx_add_vid(struct 
 static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 static void ixgb_restore_vlan(struct ixgb_adapter *adapter);
 
-static int ixgb_notify_reboot(struct notifier_block *, unsigned long event,
-			      void *ptr);
-static int ixgb_suspend(struct pci_dev *pdev, uint32_t state);
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* for netdump / net console */
 static void ixgb_netpoll(struct net_device *dev);
 #endif
 
-struct notifier_block ixgb_notifier_reboot = {
-	.notifier_call = ixgb_notify_reboot,
-	.next = NULL,
-	.priority = 0
-};
-
 /* Exported from other modules */
 
 extern void ixgb_check_options(struct ixgb_adapter *adapter);
 
 static struct pci_driver ixgb_driver = {
-	.name = ixgb_driver_name,
+	.name     = ixgb_driver_name,
 	.id_table = ixgb_pci_tbl,
-	.probe = ixgb_probe,
-	.remove = __devexit_p(ixgb_remove),
-	/* Power Managment Hooks */
-	.suspend = NULL,
-	.resume = NULL
+	.probe    = ixgb_probe,
+	.remove   = __devexit_p(ixgb_remove),
 };
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -165,17 +157,12 @@ MODULE_LICENSE("GPL");
 static int __init
 ixgb_init_module(void)
 {
-	int ret;
 	printk(KERN_INFO "%s - version %s\n",
 	       ixgb_driver_string, ixgb_driver_version);
 
 	printk(KERN_INFO "%s\n", ixgb_copyright);
 
-	ret = pci_module_init(&ixgb_driver);
-	if(ret >= 0) {
-		register_reboot_notifier(&ixgb_notifier_reboot);
-	}
-	return ret;
+	return pci_module_init(&ixgb_driver);
 }
 
 module_init(ixgb_init_module);
@@ -190,7 +177,6 @@ module_init(ixgb_init_module);
 static void __exit
 ixgb_exit_module(void)
 {
-	unregister_reboot_notifier(&ixgb_notifier_reboot);
 	pci_unregister_driver(&ixgb_driver);
 }
 
@@ -220,8 +206,8 @@ ixgb_irq_enable(struct ixgb_adapter *ada
 {
 	if(atomic_dec_and_test(&adapter->irq_sem)) {
 		IXGB_WRITE_REG(&adapter->hw, IMS,
-			   IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
-			   IXGB_INT_RXO | IXGB_INT_LSC);
+			       IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
+			       IXGB_INT_LSC);
 		IXGB_WRITE_FLUSH(&adapter->hw);
 	}
 }
@@ -292,6 +278,9 @@ ixgb_up(struct ixgb_adapter *adapter)
 	mod_timer(&adapter->watchdog_timer, jiffies);
 	ixgb_irq_enable(adapter);
 
+#ifdef CONFIG_IXGB_NAPI
+	netif_poll_enable(netdev);
+#endif
 	return 0;
 }
 
@@ -309,6 +298,9 @@ ixgb_down(struct ixgb_adapter *adapter, 
 #endif
 	if(kill_watchdog)
 		del_timer_sync(&adapter->watchdog_timer);
+#ifdef CONFIG_IXGB_NAPI
+	netif_poll_disable(netdev);
+#endif
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 	netif_carrier_off(netdev);
@@ -709,14 +701,8 @@ ixgb_configure_tx(struct ixgb_adapter *a
 	IXGB_WRITE_REG(hw, TDH, 0);
 	IXGB_WRITE_REG(hw, TDT, 0);
 
-	/* don't set up txdctl, it induces performance problems if
-	 * configured incorrectly
-	 txdctl  = TXDCTL_PTHRESH_DEFAULT; // prefetch txds below this threshold
-	 txdctl |= (TXDCTL_HTHRESH_DEFAULT // only prefetch if there are this many ready
-	 << IXGB_TXDCTL_HTHRESH_SHIFT);
-	 IXGB_WRITE_REG (hw, TXDCTL, txdctl);
-	 */
-
+	/* don't set up txdctl, it induces performance problems if configured
+	 * incorrectly */
 	/* Set the Tx Interrupt Delay register */
 
 	IXGB_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
@@ -849,10 +835,17 @@ ixgb_configure_rx(struct ixgb_adapter *a
 	IXGB_WRITE_REG(hw, RDH, 0);
 	IXGB_WRITE_REG(hw, RDT, 0);
 
-						/* burst 16 or burst when RXT0*/
-	rxdctl =  RXDCTL_WTHRESH_DEFAULT << IXGB_RXDCTL_WTHRESH_SHIFT 
-			| RXDCTL_HTHRESH_DEFAULT << IXGB_RXDCTL_HTHRESH_SHIFT 
-			| RXDCTL_PTHRESH_DEFAULT << IXGB_RXDCTL_PTHRESH_SHIFT;
+	/* set up pre-fetching of receive buffers so we get some before we
+	 * run out (default hardware behavior is to run out before fetching
+	 * more).  This sets up to fetch if HTHRESH rx descriptors are avail
+	 * and the descriptors in hw cache are below PTHRESH.  This avoids
+	 * the hardware behavior of fetching <=512 descriptors in a single
+	 * burst that pre-empts all other activity, usually causing fifo
+	 * overflows. */
+	/* use WTHRESH to burst write 16 descriptors or burst when RXT0 */
+	rxdctl = RXDCTL_WTHRESH_DEFAULT << IXGB_RXDCTL_WTHRESH_SHIFT |
+	         RXDCTL_HTHRESH_DEFAULT << IXGB_RXDCTL_HTHRESH_SHIFT |
+	         RXDCTL_PTHRESH_DEFAULT << IXGB_RXDCTL_PTHRESH_SHIFT;
 	IXGB_WRITE_REG(hw, RXDCTL, rxdctl);
 
 	/* Enable Receive Checksum Offload for TCP and UDP */
@@ -1094,7 +1087,6 @@ ixgb_watchdog(unsigned long data)
 	struct ixgb_adapter *adapter = (struct ixgb_adapter *)data;
 	struct net_device *netdev = adapter->netdev;
 	struct ixgb_desc_ring *txdr = &adapter->tx_ring;
-	unsigned int i;
 
 	ixgb_check_for_link(&adapter->hw);
 
@@ -1137,12 +1129,8 @@ ixgb_watchdog(unsigned long data)
 		}
 	}
 
-	/* 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) &&
-	   !(IXGB_READ_REG(&adapter->hw, STATUS) & IXGB_STATUS_TXOFF))
-		netif_stop_queue(netdev);
+	/* Force detection of hung controller every watchdog period */
+	adapter->detect_tx_hung = TRUE;
 
 	/* generate an interrupt to force clean up of any stragglers */
 	IXGB_WRITE_REG(&adapter->hw, ICS, IXGB_INT_TXDW);
@@ -1155,7 +1143,7 @@ ixgb_watchdog(unsigned long data)
 #define IXGB_TX_FLAGS_VLAN		0x00000002
 #define IXGB_TX_FLAGS_TSO		0x00000004
 
-static inline boolean_t
+static inline int
 ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
 {
 #ifdef NETIF_F_TSO
@@ -1163,8 +1151,15 @@ ixgb_tso(struct ixgb_adapter *adapter, s
 	unsigned int i;
 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
 	uint16_t ipcse, tucse, mss;
+	int err;
 
 	if(likely(skb_shinfo(skb)->tso_size)) {
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (err)
+				return err;
+		}
+
 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
 		mss = skb_shinfo(skb)->tso_size;
 		skb->nh.iph->tot_len = 0;
@@ -1196,18 +1191,18 @@ ixgb_tso(struct ixgb_adapter *adapter, s
 						| IXGB_CONTEXT_DESC_CMD_TSE
 						| IXGB_CONTEXT_DESC_CMD_IP
 						| IXGB_CONTEXT_DESC_CMD_TCP
-						| IXGB_CONTEXT_DESC_CMD_RS
 						| IXGB_CONTEXT_DESC_CMD_IDE
 						| (skb->len - (hdr_len)));
 
+
 		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
 
-		return TRUE;
+		return 1;
 	}
 #endif
 
-	return FALSE;
+	return 0;
 }
 
 static inline boolean_t
@@ -1234,8 +1229,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapte
 		context_desc->mss = 0;
 		context_desc->cmd_type_len =
 			cpu_to_le32(IXGB_CONTEXT_DESC_TYPE
-					| IXGB_TX_DESC_CMD_RS 
-					| IXGB_TX_DESC_CMD_IDE);
+				    | IXGB_TX_DESC_CMD_IDE);
 
 		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
@@ -1260,6 +1254,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter
 
 	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
 	unsigned int f;
+
 	len -= skb->data_len;
 
 	i = tx_ring->next_to_use;
@@ -1378,6 +1373,7 @@ ixgb_xmit_frame(struct sk_buff *skb, str
 	unsigned int tx_flags = 0;
 	unsigned long flags;
 	int vlan_id = 0;
+	int tso;
 
 	if(skb->len <= 0) {
 		dev_kfree_skb_any(skb);
@@ -1399,7 +1395,13 @@ ixgb_xmit_frame(struct sk_buff *skb, str
 
 	first = adapter->tx_ring.next_to_use;
 	
-	if(ixgb_tso(adapter, skb))
+	tso = ixgb_tso(adapter, skb);
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (tso)
 		tx_flags |= IXGB_TX_FLAGS_TSO;
 	else if(ixgb_tx_csum(adapter, skb))
 		tx_flags |= IXGB_TX_FLAGS_CSUM;
@@ -1506,14 +1508,33 @@ ixgb_change_mtu(struct net_device *netde
 void
 ixgb_update_stats(struct ixgb_adapter *adapter)
 {
+	struct net_device *netdev = adapter->netdev;
+
+	if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
+	   (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
+		u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL);
+		u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL);
+		u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH);
+		u64 bcast = ((u64)bcast_h << 32) | bcast_l; 
+
+		multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32);
+		/* fix up multicast stats by removing broadcasts */
+		multi -= bcast;
+		
+		adapter->stats.mprcl += (multi & 0xFFFFFFFF);
+		adapter->stats.mprch += (multi >> 32);
+		adapter->stats.bprcl += bcast_l; 
+		adapter->stats.bprch += bcast_h;
+	} else {
+		adapter->stats.mprcl += IXGB_READ_REG(&adapter->hw, MPRCL);
+		adapter->stats.mprch += IXGB_READ_REG(&adapter->hw, MPRCH);
+		adapter->stats.bprcl += IXGB_READ_REG(&adapter->hw, BPRCL);
+		adapter->stats.bprch += IXGB_READ_REG(&adapter->hw, BPRCH);
+	}
 	adapter->stats.tprl += IXGB_READ_REG(&adapter->hw, TPRL);
 	adapter->stats.tprh += IXGB_READ_REG(&adapter->hw, TPRH);
 	adapter->stats.gprcl += IXGB_READ_REG(&adapter->hw, GPRCL);
 	adapter->stats.gprch += IXGB_READ_REG(&adapter->hw, GPRCH);
-	adapter->stats.bprcl += IXGB_READ_REG(&adapter->hw, BPRCL);
-	adapter->stats.bprch += IXGB_READ_REG(&adapter->hw, BPRCH);
-	adapter->stats.mprcl += IXGB_READ_REG(&adapter->hw, MPRCL);
-	adapter->stats.mprch += IXGB_READ_REG(&adapter->hw, MPRCH);
 	adapter->stats.uprcl += IXGB_READ_REG(&adapter->hw, UPRCL);
 	adapter->stats.uprch += IXGB_READ_REG(&adapter->hw, UPRCH);
 	adapter->stats.vprcl += IXGB_READ_REG(&adapter->hw, VPRCL);
@@ -1668,20 +1689,16 @@ ixgb_clean(struct net_device *netdev, in
 	int work_to_do = min(*budget, netdev->quota);
 	int tx_cleaned;
 	int work_done = 0;
-	
-	if (!netif_carrier_ok(netdev))
-		goto quit_polling;
 
 	tx_cleaned = ixgb_clean_tx_irq(adapter);
 	ixgb_clean_rx_irq(adapter, &work_done, work_to_do);
 
 	*budget -= work_done;
 	netdev->quota -= work_done;
-	
-	/* if no Tx cleanup and not enough Rx work done, exit the polling mode */
-	if((!tx_cleaned && (work_done < work_to_do)) || 
-				!netif_running(netdev)) {
-quit_polling:	netif_rx_complete(netdev);
+
+	/* if no Tx and not enough Rx work done, exit the polling mode */
+	if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+		netif_rx_complete(netdev);
 		ixgb_irq_enable(adapter);
 		return 0;
 	}
@@ -1742,6 +1759,17 @@ ixgb_clean_tx_irq(struct ixgb_adapter *a
 	}
 	spin_unlock(&adapter->tx_lock);
 
+	if(adapter->detect_tx_hung) {
+		/* detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i */
+		adapter->detect_tx_hung = FALSE;
+		if(tx_ring->buffer_info[i].dma &&
+		   time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ)
+		   && !(IXGB_READ_REG(&adapter->hw, STATUS) &
+			IXGB_STATUS_TXOFF))
+			netif_stop_queue(netdev);
+	}
+
 	return cleaned;
 }
 
@@ -1796,7 +1824,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 	struct pci_dev *pdev = adapter->pdev;
 	struct ixgb_rx_desc *rx_desc, *next_rxd;
 	struct ixgb_buffer *buffer_info, *next_buffer, *next2_buffer;
-	struct sk_buff *skb, *next_skb;
 	uint32_t length;
 	unsigned int i, j;
 	boolean_t cleaned = FALSE;
@@ -1806,6 +1833,8 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 	buffer_info = &rx_ring->buffer_info[i];
 
 	while(rx_desc->status & IXGB_RX_DESC_STATUS_DD) {
+		struct sk_buff *skb, *next_skb;
+		u8 status;
 
 #ifdef CONFIG_IXGB_NAPI
 		if(*work_done >= work_to_do)
@@ -1813,7 +1842,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 
 		(*work_done)++;
 #endif
+		status = rx_desc->status;
 		skb = buffer_info->skb;
+
 		prefetch(skb->data);
 
 		if(++i == rx_ring->count) i = 0;
@@ -1828,7 +1859,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 		next_skb = next_buffer->skb;
 		prefetch(next_skb);
 
-
 		cleaned = TRUE;
 
 		pci_unmap_single(pdev,
@@ -1838,7 +1868,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 
 		length = le16_to_cpu(rx_desc->length);
 
-		if(unlikely(!(rx_desc->status & IXGB_RX_DESC_STATUS_EOP))) {
+		if(unlikely(!(status & IXGB_RX_DESC_STATUS_EOP))) {
 
 			/* All receives must fit into a single buffer */
 
@@ -1846,12 +1876,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 					 "length<%x>\n", length);
 
 			dev_kfree_skb_irq(skb);
-			rx_desc->status = 0;
-			buffer_info->skb = NULL;
-
-			rx_desc = next_rxd;
-			buffer_info = next_buffer;
-			continue;
+			goto rxdesc_done;
 		}
 
 		if (unlikely(rx_desc->errors
@@ -1860,12 +1885,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 				IXGB_RX_DESC_ERRORS_RXE))) {
 
 			dev_kfree_skb_irq(skb);
-			rx_desc->status = 0;
-			buffer_info->skb = NULL;
-
-			rx_desc = next_rxd;
-			buffer_info = next_buffer;
-			continue;
+			goto rxdesc_done;
 		}
 
 		/* Good Receive */
@@ -1876,7 +1896,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 
 		skb->protocol = eth_type_trans(skb, netdev);
 #ifdef CONFIG_IXGB_NAPI
-		if(adapter->vlgrp && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) {
+		if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) {
 			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
 				le16_to_cpu(rx_desc->special) &
 					IXGB_RX_DESC_SPECIAL_VLAN_MASK);
@@ -1884,7 +1904,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 			netif_receive_skb(skb);
 		}
 #else /* CONFIG_IXGB_NAPI */
-		if(adapter->vlgrp && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) {
+		if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) {
 			vlan_hwaccel_rx(skb, adapter->vlgrp,
 				le16_to_cpu(rx_desc->special) &
 					IXGB_RX_DESC_SPECIAL_VLAN_MASK);
@@ -1894,9 +1914,12 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
 #endif /* CONFIG_IXGB_NAPI */
 		netdev->last_rx = jiffies;
 
+rxdesc_done:
+		/* clean up descriptor, might be written over by hw */
 		rx_desc->status = 0;
 		buffer_info->skb = NULL;
 
+		/* use prefetched values */
 		rx_desc = next_rxd;
 		buffer_info = next_buffer;
 	}
@@ -1932,8 +1955,8 @@ ixgb_alloc_rx_buffers(struct ixgb_adapte
 
 	num_group_tail_writes = IXGB_RX_BUFFER_WRITE;
 
-	/* leave one descriptor unused */
-	while(--cleancount > 0) {
+	/* leave three descriptors unused */
+	while(--cleancount > 2) {
 		rx_desc = IXGB_RX_DESC(*rx_ring, i);
 
 		skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
@@ -1960,6 +1983,10 @@ ixgb_alloc_rx_buffers(struct ixgb_adapte
 				   PCI_DMA_FROMDEVICE);
 
 		rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);
+		/* guarantee DD bit not set now before h/w gets descriptor
+		 * this is the rest of the workaround for h/w double 
+		 * writeback. */
+		rx_desc->status = 0;
 
 		if((i & ~(num_group_tail_writes- 1)) == i) {
 			/* Force memory writes to complete before letting h/w
@@ -2072,54 +2099,6 @@ ixgb_restore_vlan(struct ixgb_adapter *a
 	}
 }
 
-/**
- * ixgb_notify_reboot - handles OS notification of reboot event.
- * @param nb notifier block, unused
- * @param event Event being passed to driver to act upon
- * @param p A pointer to our net device
- **/
-static int
-ixgb_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:
-		while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
-			if (pci_dev_driver(pdev) == &ixgb_driver)
-				ixgb_suspend(pdev, 3);
-		}
-	}
-	return NOTIFY_DONE;
-}
-
-/**
- * ixgb_suspend - driver suspend function called from notify.
- * @param pdev pci driver structure used for passing to
- * @param state power state to enter 
- **/
-static int
-ixgb_suspend(struct pci_dev *pdev, uint32_t state)
-{
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgb_adapter *adapter = netdev->priv;
-
-	netif_device_detach(netdev);
-
-	if(netif_running(netdev))
-		ixgb_down(adapter, TRUE);
-
-	pci_save_state(pdev);
-
-	state = (state > 0) ? 3 : 0;
-	pci_set_power_state(pdev, state);
-	msec_delay(200);
-
-	return 0;
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling 'interrupt' - used by things like netconsole to send skbs
@@ -2130,6 +2109,7 @@ ixgb_suspend(struct pci_dev *pdev, uint3
 static void ixgb_netpoll(struct net_device *dev)
 {
 	struct ixgb_adapter *adapter = dev->priv;
+
 	disable_irq(adapter->pdev->irq);
 	ixgb_intr(adapter->pdev->irq, dev, NULL);
 	enable_irq(adapter->pdev->irq);
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
@@ -45,8 +45,7 @@
 				/* Don't mdelay in interrupt context! */ \
 	                	BUG(); \
 			} else { \
-				set_current_state(TASK_UNINTERRUPTIBLE); \
-				schedule_timeout((x * HZ)/1000 + 2); \
+				msleep(x); \
 			} } while(0)
 #endif
 
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 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 
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
@@ -28,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/device.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -37,7 +39,10 @@
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
 
-#define DRV_NAME "jazzsonic"
+static char jazz_sonic_string[] = "jazzsonic";
+static struct platform_device *jazz_sonic_device;
+
+#define SONIC_MEM_SIZE	0x100
 
 #define SREGS_PAD(n)    u16 n;
 
@@ -50,8 +55,8 @@
 
 #define SONIC_WRITE(reg,val)						\
 do {									\
-	*((volatile unsigned int *)base_addr+reg) = val;		\
-}
+	*((volatile unsigned int *)base_addr+(reg)) = (val);		\
+} while (0)
 
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -80,70 +85,7 @@ static unsigned short known_revisions[] 
 	0xffff			/* end of list */
 };
 
-/* Index to functions, as function prototypes. */
-
-static int sonic_probe1(struct net_device *dev, unsigned int base_addr,
-                        unsigned int irq);
-
-
-/*
- * Probe for a SONIC ethernet controller on a Mips Jazz board.
- * Actually probing is superfluous but we're paranoid.
- */
-struct net_device * __init sonic_probe(int unit)
-{
-	struct net_device *dev;
-	struct sonic_local *lp;
-	unsigned int base_addr;
-	int err = 0;
-	int i;
-
-	/*
-	 * Don't probe if we're not running on a Jazz board.
-	 */
-	if (mips_machgroup != MACH_GROUP_JAZZ)
-		return ERR_PTR(-ENODEV);
-
-	dev = alloc_etherdev(0);
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-	base_addr = dev->base_addr;
-
-	if (base_addr >= KSEG0)	{ /* Check a single specified location. */
-		err = sonic_probe1(dev, base_addr, dev->irq);
-	} else if (base_addr != 0) { /* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (i = 0; sonic_portlist[i].port; i++) {
-			int io = sonic_portlist[i].port;
-			if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
-				break;
-		}
-		if (!sonic_portlist[i].port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	lp = dev->priv;
-	vdma_free(lp->rba_laddr);
-	kfree(lp->rba);
-	vdma_free(lp->cda_laddr);
-	kfree(lp);
-	release_region(dev->base_addr, 0x100);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
+static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
                                unsigned int irq)
 {
 	static unsigned version_printed;
@@ -153,7 +95,7 @@ static int __init sonic_probe1(struct ne
 	int err = -ENODEV;
 	int i;
 
-	if (!request_region(base_addr, 0x100, DRV_NAME))
+	if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
 		return -EBUSY;
 	/*
 	 * get the Silicon Revision ID. If this is one of the known
@@ -233,7 +175,7 @@ static int __init sonic_probe1(struct ne
 		memset(lp, 0, sizeof(struct sonic_local));
 
 		/* get the virtual dma address */
-		lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
+		lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp));
 		if (lp->cda_laddr == ~0UL) {
 			printk("%s: couldn't get DMA page entry for "
 			       "descriptors\n", dev->name);
@@ -254,7 +196,7 @@ static int __init sonic_probe1(struct ne
 		}
 
 		/* get virtual dma address */
-		lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),
+		lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba),
 		                           SONIC_NUM_RRS * SONIC_RBSIZE);
 		if (lp->rba_laddr == ~0UL) {
 			printk("%s: couldn't get DMA page entry for receive "
@@ -291,7 +233,66 @@ out2:
 out1:
 	kfree(lp);
 out:
-	release_region(base_addr, 0x100);
+	release_region(base_addr, SONIC_MEM_SIZE);
+	return err;
+}
+
+/*
+ * Probe for a SONIC ethernet controller on a Mips Jazz board.
+ * Actually probing is superfluous but we're paranoid.
+ */
+static int __init jazz_sonic_probe(struct device *device)
+{
+	struct net_device *dev;
+	struct sonic_local *lp;
+	unsigned long base_addr;
+	int err = 0;
+	int i;
+
+	/*
+	 * Don't probe if we're not running on a Jazz board.
+	 */
+	if (mips_machgroup != MACH_GROUP_JAZZ)
+		return -ENODEV;
+
+	dev = alloc_etherdev(0);
+	if (!dev)
+		return -ENOMEM;
+
+	netdev_boot_setup_check(dev);
+	base_addr = dev->base_addr;
+
+	if (base_addr >= KSEG0)	{ /* Check a single specified location. */
+		err = sonic_probe1(dev, base_addr, dev->irq);
+	} else if (base_addr != 0) { /* Don't probe at all. */
+		err = -ENXIO;
+	} else {
+		for (i = 0; sonic_portlist[i].port; i++) {
+			int io = sonic_portlist[i].port;
+			if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
+				break;
+		}
+		if (!sonic_portlist[i].port)
+			err = -ENODEV;
+	}
+	if (err)
+		goto out;
+	err = register_netdev(dev);
+	if (err)
+		goto out1;
+
+	return 0;
+
+out1:
+	lp = dev->priv;
+	vdma_free(lp->rba_laddr);
+	kfree(lp->rba);
+	vdma_free(lp->cda_laddr);
+	kfree(lp);
+	release_region(dev->base_addr, SONIC_MEM_SIZE);
+out:
+	free_netdev(dev);
+
 	return err;
 }
 
@@ -304,3 +305,77 @@ out:
 #define sonic_chiptomem(x)      KSEG1ADDR(vdma_log2phys(x))
 
 #include "sonic.c"
+
+static int __devexit jazz_sonic_device_remove (struct device *device)
+{
+	struct net_device *dev = device->driver_data;
+
+	unregister_netdev (dev);
+	release_region (dev->base_addr, SONIC_MEM_SIZE);
+	free_netdev (dev);
+
+	return 0;
+}
+
+static struct device_driver jazz_sonic_driver = {
+	.name	= jazz_sonic_string,
+	.bus	= &platform_bus_type,
+	.probe	= jazz_sonic_probe,
+	.remove	= __devexit_p(jazz_sonic_device_remove),
+};
+                                                                                
+static void jazz_sonic_platform_release (struct device *device)
+{
+	struct platform_device *pldev;
+
+	/* free device */
+	pldev = to_platform_device (device);
+	kfree (pldev);
+}
+
+static int __init jazz_sonic_init_module(void)
+{
+	struct platform_device *pldev;
+
+	if (driver_register(&jazz_sonic_driver)) {
+		printk(KERN_ERR "Driver registration failed\n");
+		return -ENOMEM;
+	}
+
+	jazz_sonic_device = NULL;
+
+	if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
+		goto out_unregister;
+	}
+
+	memset(pldev, 0, sizeof (*pldev));
+	pldev->name		= jazz_sonic_string;
+	pldev->id		= 0;
+	pldev->dev.release	= jazz_sonic_platform_release;
+	jazz_sonic_device	= pldev;
+
+	if (platform_device_register (pldev)) {
+		kfree(pldev);
+		jazz_sonic_device = NULL;
+	}
+
+	return 0;
+
+out_unregister:
+	platform_device_unregister(pldev);
+
+	return -ENOMEM;
+}
+
+static void __exit jazz_sonic_cleanup_module(void)
+{
+	driver_unregister(&jazz_sonic_driver);
+
+	if (jazz_sonic_device) {
+		platform_device_unregister(jazz_sonic_device);
+		jazz_sonic_device = NULL;
+	}
+}
+
+module_init(jazz_sonic_init_module);
+module_exit(jazz_sonic_cleanup_module);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -47,6 +47,7 @@ static const char version[] = "lance.c:v
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)loopback.c	1.0.4b	08/16/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@scyld.com>
  *
@@ -184,7 +184,7 @@ static struct net_device_stats *get_stat
 	return stats;
 }
 
-u32 loopback_get_link(struct net_device *dev)
+static u32 loopback_get_link(struct net_device *dev)
 {
 	return 1;
 }
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -112,8 +112,10 @@ enum commands {
 	CmdDiagnose = 7
 };
 
-char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
-			"Tx", "TDR", "Dump", "Diagnose" };
+#if 0
+static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
+				     "Tx", "TDR", "Dump", "Diagnose" };
+#endif
 
 /* Status word bits */
 #define	STAT_CX		0x8000	/* The CU finished executing a command
@@ -960,7 +962,7 @@ static void print_eth(char *add) 
 		(unsigned char) add[12], (unsigned char) add[13]);
 }
 
-int __init lp486e_probe(struct net_device *dev) {
+static int __init lp486e_probe(struct net_device *dev) {
 	struct i596_private *lp;
 	unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
 	unsigned char *bios;
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -638,6 +638,7 @@ cleanup_module(void)
 #define vdma_free(baz)
 #define sonic_chiptomem(bat) (bat)
 #define PHYSADDR(quux) (quux)
+#define CPHYSADDR(quux) (quux)
 
 #define sonic_request_irq       request_irq
 #define sonic_free_irq          free_irq
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -27,7 +27,7 @@
 #include <linux/ip.h>          /* struct iphdr */
 #include <linux/tcp.h>         /* struct tcphdr */
 #include <linux/skbuff.h>
-#include <linux/mii.h> /*MII definitions */
+#include <linux/mii.h>         /* MII definitions */
 
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
@@ -105,27 +105,27 @@ static inline void load_eaddr(struct net
 		(int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = o2meth_eaddr[i];
-	mace_eth_write((*(u64*)o2meth_eaddr)>>16, mac_addr);
+	mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16;
 }
 
 /*
  * Waits for BUSY status of mdio bus to clear
  */
-#define WAIT_FOR_PHY(___rval)						\
-	while ((___rval = mace_eth_read(phy_data)) & MDIO_BUSY) {	\
-		udelay(25);						\
+#define WAIT_FOR_PHY(___rval)					\
+	while ((___rval = mace->eth.phy_data) & MDIO_BUSY) {	\
+		udelay(25);					\
 	}
 /*read phy register, return value read */
 static unsigned long mdio_read(struct meth_private *priv, unsigned long phyreg)
 {
 	unsigned long rval;
 	WAIT_FOR_PHY(rval);
-	mace_eth_write((priv->phy_addr << 5) | (phyreg & 0x1f), phy_regs);
+	mace->eth.phy_regs = (priv->phy_addr << 5) | (phyreg & 0x1f);
 	udelay(25);
-	mace_eth_write(1, phy_trans_go);
+	mace->eth.phy_trans_go = 1;
 	udelay(25);
 	WAIT_FOR_PHY(rval);
-	return rval&MDIO_DATA_MASK;
+	return rval & MDIO_DATA_MASK;
 }
 
 static int mdio_probe(struct meth_private *priv)
@@ -191,7 +191,7 @@ static void meth_check_link(struct net_d
 			priv->mac_ctrl |= METH_PHY_FDX;
 		else
 			priv->mac_ctrl &= ~METH_PHY_FDX;
-		mace_eth_write(priv->mac_ctrl, mac_ctrl);
+		mace->eth.mac_ctrl = priv->mac_ctrl;
 	}
 
 	if ((priv->mac_ctrl & METH_100MBIT) ^ speed) {
@@ -200,7 +200,7 @@ static void meth_check_link(struct net_d
 			priv->mac_ctrl |= METH_100MBIT;
 		else
 			priv->mac_ctrl &= ~METH_100MBIT;
-		mace_eth_write(priv->mac_ctrl, mac_ctrl);
+		mace->eth.mac_ctrl = priv->mac_ctrl;
 	}
 }
 
@@ -214,26 +214,28 @@ static int meth_init_tx_ring(struct meth
 		return -ENOMEM;
 	memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE);
 	priv->tx_count = priv->tx_read = priv->tx_write = 0;
-	mace_eth_write(priv->tx_ring_dma, tx_ring_base);
+	mace->eth.tx_ring_base = priv->tx_ring_dma;
 	/* 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));
+	memset(priv->tx_skbs, 0, sizeof(priv->tx_skbs));
+	memset(priv->tx_skb_dmas, 0, sizeof(priv->tx_skb_dmas));
 	return 0;
 }
 
 static int meth_init_rx_ring(struct meth_private *priv)
 {
 	int i;
-	for(i=0;i<RX_RING_ENTRIES;i++){
-		priv->rx_skbs[i]=alloc_skb(METH_RX_BUFF_SIZE,0);
-		/* 8byte status vector+3quad padding + 2byte padding,
-		   to put data on 64bit aligned boundary */
+
+	for (i = 0; i < RX_RING_ENTRIES; i++) {
+		priv->rx_skbs[i] = alloc_skb(METH_RX_BUFF_SIZE, 0);
+		/* 8byte status vector + 3quad padding + 2byte padding,
+		 * to put data on 64bit aligned boundary */
 		skb_reserve(priv->rx_skbs[i],METH_RX_HEAD);
 		priv->rx_ring[i]=(rx_packet*)(priv->rx_skbs[i]->head);
 		/* I'll need to re-sync it after each RX */
-		priv->rx_ring_dmas[i]=dma_map_single(NULL,priv->rx_ring[i],
-						     METH_RX_BUFF_SIZE,DMA_FROM_DEVICE);
-		mace_eth_write(priv->rx_ring_dmas[i], rx_fifo);
+		priv->rx_ring_dmas[i] = 
+			dma_map_single(NULL, priv->rx_ring[i],
+				       METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+		mace->eth.rx_fifo = priv->rx_ring_dmas[i];
 	}
         priv->rx_write = 0;
 	return 0;
@@ -257,10 +259,11 @@ static void meth_free_rx_ring(struct met
 {
 	int i;
 
-	for(i=0;i<RX_RING_ENTRIES;i++) {
-		dma_unmap_single(NULL,priv->rx_ring_dmas[i],METH_RX_BUFF_SIZE,DMA_FROM_DEVICE);
-		priv->rx_ring[i]=0;
-		priv->rx_ring_dmas[i]=0;
+	for (i = 0; i < RX_RING_ENTRIES; i++) {
+		dma_unmap_single(NULL, priv->rx_ring_dmas[i],
+				 METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+		priv->rx_ring[i] = 0;
+		priv->rx_ring_dmas[i] = 0;
 		kfree_skb(priv->rx_skbs[i]);
 	}
 }
@@ -270,8 +273,9 @@ int meth_reset(struct net_device *dev)
 	struct meth_private *priv = (struct meth_private *) dev->priv;
 
 	/* Reset card */
-	mace_eth_write(SGI_MAC_RESET, mac_ctrl);
-	mace_eth_write(0, mac_ctrl);
+	mace->eth.mac_ctrl = SGI_MAC_RESET;
+	udelay(1);
+	mace->eth.mac_ctrl = 0;
 	udelay(25);
 
 	/* Load ethernet address */
@@ -279,24 +283,24 @@ int meth_reset(struct net_device *dev)
 	/* Should load some "errata", but later */
 	
 	/* Check for device */
-	if(mdio_probe(priv) < 0) {
+	if (mdio_probe(priv) < 0) {
 		DPRINTK("Unable to find PHY\n");
 		return -ENODEV;
 	}
 
 	/* Initial mode: 10 | Half-duplex | Accept normal packets */
 	priv->mac_ctrl = METH_ACCEPT_MCAST | METH_DEFAULT_IPG;
-	if(dev->flags | IFF_PROMISC)
+	if (dev->flags | IFF_PROMISC)
 		priv->mac_ctrl |= METH_PROMISC;
-	mace_eth_write(priv->mac_ctrl, mac_ctrl);
+	mace->eth.mac_ctrl = priv->mac_ctrl;
 
 	/* Autonegotiate speed and duplex mode */
 	meth_check_link(dev);
 
 	/* Now set dma control, but don't enable DMA, yet */
-	priv->dma_ctrl= (4 << METH_RX_OFFSET_SHIFT) |
-		(RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT);
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	priv->dma_ctrl = (4 << METH_RX_OFFSET_SHIFT) |
+			 (RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
 	return 0;
 }
@@ -335,7 +339,7 @@ static int meth_open(struct net_device *
 	/* Start DMA */
 	priv->dma_ctrl |= METH_DMA_TX_EN | /*METH_DMA_TX_INT_EN |*/
 			  METH_DMA_RX_EN | METH_DMA_RX_INT_EN;
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
 	DPRINTK("About to start queue\n");
 	netif_start_queue(dev);
@@ -359,7 +363,7 @@ static int meth_release(struct net_devic
 	/* shut down DMA */
 	priv->dma_ctrl &= ~(METH_DMA_TX_EN | METH_DMA_TX_INT_EN |
 			    METH_DMA_RX_EN | METH_DMA_RX_INT_EN);
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 	free_irq(dev->irq, dev);
 	meth_free_tx_ring(priv);
 	meth_free_rx_ring(priv);
@@ -373,56 +377,57 @@ static int meth_release(struct net_devic
 static void meth_rx(struct net_device* dev, unsigned long int_status)
 {
 	struct sk_buff *skb;
+	unsigned long status;
 	struct meth_private *priv = (struct meth_private *) dev->priv;
-	unsigned long fifo_rptr=(int_status&METH_INT_RX_RPTR_MASK)>>8;
+	unsigned long fifo_rptr = (int_status & METH_INT_RX_RPTR_MASK) >> 8;
+
 	spin_lock(&priv->meth_lock);
-	priv->dma_ctrl&=~METH_DMA_RX_INT_EN;
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	priv->dma_ctrl &= ~METH_DMA_RX_INT_EN;
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 	spin_unlock(&priv->meth_lock);
 
-	if (int_status & METH_INT_RX_UNDERFLOW){
-		fifo_rptr=(fifo_rptr-1)&(0xF);
+	if (int_status & METH_INT_RX_UNDERFLOW) {
+		fifo_rptr = (fifo_rptr - 1) & 0x0f;
 	}
-	while(priv->rx_write != fifo_rptr) {
-		u64 status;
-		dma_unmap_single(NULL,priv->rx_ring_dmas[priv->rx_write],
-				 METH_RX_BUFF_SIZE,DMA_FROM_DEVICE);
-		status=priv->rx_ring[priv->rx_write]->status.raw;
+	while (priv->rx_write != fifo_rptr) {
+		dma_unmap_single(NULL, priv->rx_ring_dmas[priv->rx_write],
+				 METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+		status = priv->rx_ring[priv->rx_write]->status.raw;
 #if MFE_DEBUG
-		if(!(status&METH_RX_ST_VALID)) {
+		if (!(status & METH_RX_ST_VALID)) {
 			DPRINTK("Not received? status=%016lx\n",status);
 		}
 #endif
-		if((!(status&METH_RX_STATUS_ERRORS))&&(status&METH_RX_ST_VALID)){
-			int len=(status&0xFFFF) - 4; /* omit CRC */
+		if ((!(status & METH_RX_STATUS_ERRORS)) && (status & METH_RX_ST_VALID)) {
+			int len = (status & 0xffff) - 4; /* omit CRC */
 			/* length sanity check */
-			if(len < 60 || len > 1518) {
-				printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2lx.\n",
+			if (len < 60 || len > 1518) {
+				printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n",
 				       dev->name, priv->rx_write,
 				       priv->rx_ring[priv->rx_write]->status.raw);
 				priv->stats.rx_errors++;
 				priv->stats.rx_length_errors++;
-				skb=priv->rx_skbs[priv->rx_write];
+				skb = priv->rx_skbs[priv->rx_write];
 			} else {
-				skb=alloc_skb(METH_RX_BUFF_SIZE,GFP_ATOMIC|GFP_DMA);
-				if(!skb){
+				skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC | GFP_DMA);
+				if (!skb) {
 					/* Ouch! No memory! Drop packet on the floor */
 					DPRINTK("No mem: dropping packet\n");
 					priv->stats.rx_dropped++;
-					skb=priv->rx_skbs[priv->rx_write];
+					skb = priv->rx_skbs[priv->rx_write];
 				} else {
-					struct sk_buff *skb_c=priv->rx_skbs[priv->rx_write];
-					/* 8byte status vector+3quad padding + 2byte padding,
-					   to put data on 64bit aligned boundary */
-					skb_reserve(skb,METH_RX_HEAD);
+					struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write];
+					/* 8byte status vector + 3quad padding + 2byte padding,
+					 * to put data on 64bit aligned boundary */
+					skb_reserve(skb, METH_RX_HEAD);
 					/* Write metadata, and then pass to the receive level */
-					skb_put(skb_c,len);
-					priv->rx_skbs[priv->rx_write]=skb;
+					skb_put(skb_c, len);
+					priv->rx_skbs[priv->rx_write] = skb;
 					skb_c->dev = dev;
 					skb_c->protocol = eth_type_trans(skb_c, dev);
 					dev->last_rx = jiffies;
 					priv->stats.rx_packets++;
-					priv->stats.rx_bytes+=len;
+					priv->stats.rx_bytes += len;
 					netif_rx(skb_c);
 				}
 			}
@@ -445,18 +450,19 @@ static void meth_rx(struct net_device* d
 				printk(KERN_WARNING "Carrier Event Seen\n");
 #endif
 		}
-		priv->rx_ring[priv->rx_write]=(rx_packet*)skb->head;
-		priv->rx_ring[priv->rx_write]->status.raw=0;
-		priv->rx_ring_dmas[priv->rx_write]=dma_map_single(NULL,priv->rx_ring[priv->rx_write],
-								  METH_RX_BUFF_SIZE,DMA_FROM_DEVICE);
-		mace_eth_write(priv->rx_ring_dmas[priv->rx_write], rx_fifo);
+		priv->rx_ring[priv->rx_write] = (rx_packet*)skb->head;
+		priv->rx_ring[priv->rx_write]->status.raw = 0;
+		priv->rx_ring_dmas[priv->rx_write] = 
+			dma_map_single(NULL, priv->rx_ring[priv->rx_write],
+				       METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+		mace->eth.rx_fifo = priv->rx_ring_dmas[priv->rx_write];
 		ADVANCE_RX_PTR(priv->rx_write);
 	}
 	spin_lock(&priv->meth_lock);
 	/* In case there was underflow, and Rx DMA was disabled */
-	priv->dma_ctrl|=METH_DMA_RX_INT_EN|METH_DMA_RX_EN;
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
-	mace_eth_write(METH_INT_RX_THRESHOLD, int_stat);
+	priv->dma_ctrl |= METH_DMA_RX_INT_EN | METH_DMA_RX_EN;
+	mace->eth.dma_ctrl = priv->dma_ctrl;
+	mace->eth.int_stat = METH_INT_RX_THRESHOLD;
 	spin_unlock(&priv->meth_lock);
 }
 
@@ -464,31 +470,31 @@ static int meth_tx_full(struct net_devic
 {
 	struct meth_private *priv = (struct meth_private *) dev->priv;
 
-	return(priv->tx_count >= TX_RING_ENTRIES-1);
+	return (priv->tx_count >= TX_RING_ENTRIES - 1);
 }
 
 static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
 {
 	struct meth_private *priv = dev->priv;
-	u64 status;
+	unsigned long status;
 	struct sk_buff *skb;
-	unsigned long rptr=(int_status&TX_INFO_RPTR)>>16;
+	unsigned long rptr = (int_status&TX_INFO_RPTR) >> 16;
 
 	spin_lock(&priv->meth_lock);
 
 	/* Stop DMA notification */
 	priv->dma_ctrl &= ~(METH_DMA_TX_INT_EN);
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
-	while(priv->tx_read != rptr){
+	while (priv->tx_read != rptr) {
 		skb = priv->tx_skbs[priv->tx_read];
 		status = priv->tx_ring[priv->tx_read].header.raw;
 #if MFE_DEBUG>=1
-		if(priv->tx_read==priv->tx_write)
-			DPRINTK("Auchi! tx_read=%d,tx_write=%d,rptr=%d?\n",priv->tx_read,priv->tx_write,rptr);
+		if (priv->tx_read == priv->tx_write)
+			DPRINTK("Auchi! tx_read=%d,tx_write=%d,rptr=%d?\n", priv->tx_read, priv->tx_write,rptr);
 #endif
-		if(status & METH_TX_ST_DONE) {
-			if(status & METH_TX_ST_SUCCESS){
+		if (status & METH_TX_ST_DONE) {
+			if (status & METH_TX_ST_SUCCESS){
 				priv->stats.tx_packets++;
 				priv->stats.tx_bytes += skb->len;
 			} else {
@@ -518,19 +524,19 @@ static void meth_tx_cleanup(struct net_d
 		priv->tx_skbs[priv->tx_read] = NULL;
 		priv->tx_ring[priv->tx_read].header.raw = 0;
 		priv->tx_read = (priv->tx_read+1)&(TX_RING_ENTRIES-1);
-		priv->tx_count --;
+		priv->tx_count--;
 	}
 
 	/* wake up queue if it was stopped */
-	if (netif_queue_stopped(dev) && ! meth_tx_full(dev)) {
+	if (netif_queue_stopped(dev) && !meth_tx_full(dev)) {
 		netif_wake_queue(dev);
 	}
 
-	mace_eth_write(METH_INT_TX_EMPTY | METH_INT_TX_PKT, int_stat);
+	mace->eth.int_stat = METH_INT_TX_EMPTY | METH_INT_TX_PKT;
 	spin_unlock(&priv->meth_lock);
 }
 
-static void meth_error(struct net_device* dev, u32 status)
+static void meth_error(struct net_device* dev, unsigned status)
 {
 	struct meth_private *priv = (struct meth_private *) dev->priv;
 
@@ -548,17 +554,16 @@ static void meth_error(struct net_device
 	if (status & (METH_INT_RX_UNDERFLOW)) {
 		printk(KERN_WARNING "meth: Rx underflow\n");
 		spin_lock(&priv->meth_lock);
-		mace_eth_write(METH_INT_RX_UNDERFLOW, int_stat);
+		mace->eth.int_stat = METH_INT_RX_UNDERFLOW;
 		/* more underflow interrupts will be delivered, 
-		   effectively throwing us into an infinite loop.
-		   Thus I stop processing Rx in this case.
-		*/
-		priv->dma_ctrl&=~METH_DMA_RX_EN;
-		mace_eth_write(priv->dma_ctrl, dma_ctrl);
+		 * effectively throwing us into an infinite loop.
+		 *  Thus I stop processing Rx in this case. */
+		priv->dma_ctrl &= ~METH_DMA_RX_EN;
+		mace->eth.dma_ctrl = priv->dma_ctrl;
 		DPRINTK("Disabled meth Rx DMA temporarily\n");
 		spin_unlock(&priv->meth_lock);
 	}
-	mace_eth_write(METH_INT_ERROR, int_stat);
+	mace->eth.int_stat = METH_INT_ERROR;
 }
 
 /*
@@ -570,12 +575,12 @@ static irqreturn_t meth_interrupt(int ir
 	struct meth_private *priv = (struct meth_private *) dev->priv;
 	unsigned long status;
 
-	status = mace_eth_read(int_stat);
-	while (status & 0xFF) {
+	status = mace->eth.int_stat;
+	while (status & 0xff) {
 		/* First handle errors - if we get Rx underflow,
-		   Rx DMA will be disabled, and Rx handler will reenable
-		   it. I don't think it's possible to get Rx underflow,
-		   without getting Rx interrupt */
+		 * Rx DMA will be disabled, and Rx handler will reenable
+		 * it. I don't think it's possible to get Rx underflow,
+		 * without getting Rx interrupt */
 		if (status & METH_INT_ERROR) {
 			meth_error(dev, status);
 		}
@@ -589,7 +594,7 @@ static irqreturn_t meth_interrupt(int ir
 			/* send it to meth_rx for handling */
 			meth_rx(dev, status);
 		}
-		status = mace_eth_read(int_stat);
+		status = mace->eth.int_stat;
 	}
 
 	return IRQ_HANDLED;
@@ -601,45 +606,45 @@ static irqreturn_t meth_interrupt(int ir
 static void meth_tx_short_prepare(struct 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;
+	tx_packet *desc = &priv->tx_ring[priv->tx_write];
+	int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
 
-	desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16);
+	desc->header.raw = METH_TX_CMD_INT_EN | (len-1) | ((128-len) << 16);
 	/* 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);
+	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);
 }
 #define TX_CATBUF1 BIT(25)
 static void meth_tx_1page_prepare(struct meth_private *priv,
 				  struct sk_buff *skb)
 {
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
+	tx_packet *desc = &priv->tx_ring[priv->tx_write];
 	void *buffer_data = (void *)(((unsigned long)skb->data + 7) & ~7);
 	int unaligned_len = (int)((unsigned long)buffer_data - (unsigned long)skb->data);
 	int buffer_len = skb->len - unaligned_len;
 	dma_addr_t catbuf;
 
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1);
+	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),
+	if (unaligned_len) {
+		memcpy(desc->data.dt + (120 - unaligned_len),
 		       skb->data, unaligned_len);
-		desc->header.raw |= (128-unaligned_len) << 16;
+		desc->header.raw |= (128 - unaligned_len) << 16;
 	}
 
 	/* first page */
 	catbuf = dma_map_single(NULL, buffer_data, buffer_len,
 				DMA_TO_DEVICE);
 	desc->data.cat_buf[0].form.start_addr = catbuf >> 3;
-	desc->data.cat_buf[0].form.len = buffer_len-1;
+	desc->data.cat_buf[0].form.len = buffer_len - 1;
 }
 #define TX_CATBUF2 BIT(26)
 static void meth_tx_2page_prepare(struct meth_private *priv,
 				  struct sk_buff *skb)
 {
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
+	tx_packet *desc = &priv->tx_ring[priv->tx_write];
 	void *buffer1_data = (void *)(((unsigned long)skb->data + 7) & ~7);
 	void *buffer2_data = (void *)PAGE_ALIGN((unsigned long)skb->data);
 	int unaligned_len = (int)((unsigned long)buffer1_data - (unsigned long)skb->data);
@@ -647,44 +652,44 @@ static void meth_tx_2page_prepare(struct
 	int buffer2_len = skb->len - buffer1_len - unaligned_len;
 	dma_addr_t catbuf1, catbuf2;
 
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1);
+	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),
+	if (unaligned_len){
+		memcpy(desc->data.dt + (120 - unaligned_len),
 		       skb->data, unaligned_len);
-		desc->header.raw |= (128-unaligned_len) << 16;
+		desc->header.raw |= (128 - unaligned_len) << 16;
 	}
 
 	/* first page */
 	catbuf1 = dma_map_single(NULL, buffer1_data, buffer1_len,
 				 DMA_TO_DEVICE);
 	desc->data.cat_buf[0].form.start_addr = catbuf1 >> 3;
-	desc->data.cat_buf[0].form.len = buffer1_len-1;
+	desc->data.cat_buf[0].form.len = buffer1_len - 1;
 	/* second page */
 	catbuf2 = dma_map_single(NULL, buffer2_data, buffer2_len,
 				 DMA_TO_DEVICE);
 	desc->data.cat_buf[1].form.start_addr = catbuf2 >> 3;
-	desc->data.cat_buf[1].form.len = buffer2_len-1;
+	desc->data.cat_buf[1].form.len = buffer2_len - 1;
 }
 
 static void meth_add_to_tx_ring(struct meth_private *priv, struct sk_buff *skb)
 {
 	/* Remember the skb, so we can free it at interrupt time */
 	priv->tx_skbs[priv->tx_write] = skb;
-	if(skb->len <= 120) {
+	if (skb->len <= 120) {
 		/* Whole packet fits into descriptor */
-		meth_tx_short_prepare(priv,skb);
-	} else if(PAGE_ALIGN((unsigned long)skb->data) !=
-		  PAGE_ALIGN((unsigned long)skb->data+skb->len-1)) {
+		meth_tx_short_prepare(priv, skb);
+	} else if (PAGE_ALIGN((unsigned long)skb->data) !=
+		   PAGE_ALIGN((unsigned long)skb->data + skb->len - 1)) {
 		/* Packet crosses page boundary */
-		meth_tx_2page_prepare(priv,skb);
+		meth_tx_2page_prepare(priv, skb);
 	} else {
 		/* Packet is in one page */
-		meth_tx_1page_prepare(priv,skb);
+		meth_tx_1page_prepare(priv, skb);
 	}
-	priv->tx_write = (priv->tx_write+1) & (TX_RING_ENTRIES-1);
-	mace_eth_write(priv->tx_write, tx_info);
-	priv->tx_count ++;
+	priv->tx_write = (priv->tx_write + 1) & (TX_RING_ENTRIES - 1);
+	mace->eth.tx_info = priv->tx_write;
+	priv->tx_count++;
 }
 
 /*
@@ -695,10 +700,10 @@ static int meth_tx(struct sk_buff *skb, 
 	struct meth_private *priv = (struct meth_private *) dev->priv;
 	unsigned long flags;
 
-	spin_lock_irqsave(&priv->meth_lock,flags);
+	spin_lock_irqsave(&priv->meth_lock, flags);
 	/* Stop DMA notification */
 	priv->dma_ctrl &= ~(METH_DMA_TX_INT_EN);
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
 	meth_add_to_tx_ring(priv, skb);
 	dev->trans_start = jiffies; /* save the timestamp */
@@ -711,9 +716,9 @@ static int meth_tx(struct sk_buff *skb, 
 
 	/* Restart DMA notification */
 	priv->dma_ctrl |= METH_DMA_TX_INT_EN;
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
-	spin_unlock_irqrestore(&priv->meth_lock,flags);
+	spin_unlock_irqrestore(&priv->meth_lock, flags);
 
 	return 0;
 }
@@ -743,11 +748,11 @@ static void meth_tx_timeout(struct net_d
 	meth_init_rx_ring(priv);
 
 	/* Restart dma */
-	priv->dma_ctrl|=METH_DMA_TX_EN|METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
-	mace_eth_write(priv->dma_ctrl, dma_ctrl);
+	priv->dma_ctrl |= METH_DMA_TX_EN | METH_DMA_RX_EN | METH_DMA_RX_INT_EN;
+	mace->eth.dma_ctrl = priv->dma_ctrl;
 
 	/* Enable interrupt */
-	spin_unlock_irqrestore(&priv->meth_lock,flags);
+	spin_unlock_irqrestore(&priv->meth_lock, flags);
 
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
@@ -760,8 +765,14 @@ static void meth_tx_timeout(struct net_d
  */
 static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	DPRINTK("ioctl\n");
-	return 0;
+	/* XXX Not yet implemented */
+	switch(cmd) { 
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 /*
@@ -808,7 +819,7 @@ static struct net_device *meth_init(void
 	}
 
 	printk(KERN_INFO "%s: SGI MACE Ethernet rev. %d\n",
-	       dev->name, (unsigned int)mace_eth_read(mac_ctrl) >> 29);
+	       dev->name, (unsigned int)(mace->eth.mac_ctrl >> 29));
 	return 0;
 }
 
diff --git a/drivers/net/meth.h b/drivers/net/meth.h
--- a/drivers/net/meth.h
+++ b/drivers/net/meth.h
@@ -29,7 +29,7 @@
 #define RX_BUCKET_SIZE 256
 
 #undef BIT
-#define BIT(x)	(1 << (x))
+#define BIT(x)	(1UL << (x))
 
 /* For more detailed explanations of what each field menas,
    see Nick's great comments to #defines below (or docs, if
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -37,11 +37,15 @@ int mii_ethtool_gset(struct mii_if_info 
 {
 	struct net_device *dev = mii->dev;
 	u32 advert, bmcr, lpa, nego;
+	u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
 
 	ecmd->supported =
 	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
 	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+	if (mii->supports_gmii)
+		ecmd->supported |= SUPPORTED_1000baseT_Half |
+			SUPPORTED_1000baseT_Full;
 
 	/* only supports twisted-pair */
 	ecmd->port = PORT_MII;
@@ -54,6 +58,9 @@ int mii_ethtool_gset(struct mii_if_info 
 
 	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
 	advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+	if (mii->supports_gmii)
+		advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
+
 	if (advert & ADVERTISE_10HALF)
 		ecmd->advertising |= ADVERTISED_10baseT_Half;
 	if (advert & ADVERTISE_10FULL)
@@ -62,19 +69,31 @@ int mii_ethtool_gset(struct mii_if_info 
 		ecmd->advertising |= ADVERTISED_100baseT_Half;
 	if (advert & ADVERTISE_100FULL)
 		ecmd->advertising |= ADVERTISED_100baseT_Full;
+	if (advert2 & ADVERTISE_1000HALF)
+		ecmd->advertising |= ADVERTISED_1000baseT_Half;
+	if (advert2 & ADVERTISE_1000FULL)
+		ecmd->advertising |= ADVERTISED_1000baseT_Full;
 
 	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
 	lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+	if (mii->supports_gmii) {
+		bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
+		lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
+	}
 	if (bmcr & BMCR_ANENABLE) {
 		ecmd->advertising |= ADVERTISED_Autoneg;
 		ecmd->autoneg = AUTONEG_ENABLE;
 		
 		nego = mii_nway_result(advert & lpa);
-		if (nego == LPA_100FULL || nego == LPA_100HALF)
+		if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & 
+		    (lpa2 >> 2))
+			ecmd->speed = SPEED_1000;
+		else if (nego == LPA_100FULL || nego == LPA_100HALF)
 			ecmd->speed = SPEED_100;
 		else
 			ecmd->speed = SPEED_10;
-		if (nego == LPA_100FULL || nego == LPA_10FULL) {
+		if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
+		    nego == LPA_10FULL) {
 			ecmd->duplex = DUPLEX_FULL;
 			mii->full_duplex = 1;
 		} else {
@@ -84,7 +103,9 @@ int mii_ethtool_gset(struct mii_if_info 
 	} else {
 		ecmd->autoneg = AUTONEG_DISABLE;
 
-		ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+		ecmd->speed = ((bmcr & BMCR_SPEED1000 && 
+				(bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
+			       (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
 		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
 	}
 
@@ -97,7 +118,9 @@ int mii_ethtool_sset(struct mii_if_info 
 {
 	struct net_device *dev = mii->dev;
 
-	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+	if (ecmd->speed != SPEED_10 && 
+	    ecmd->speed != SPEED_100 && 
+	    ecmd->speed != SPEED_1000)
 		return -EINVAL;
 	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
 		return -EINVAL;
@@ -109,21 +132,30 @@ int mii_ethtool_sset(struct mii_if_info 
 		return -EINVAL;
 	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
 		return -EINVAL;
+	if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
+		return -EINVAL;
 				  
 	/* ignore supported, maxtxpkt, maxrxpkt */
 	
 	if (ecmd->autoneg == AUTONEG_ENABLE) {
 		u32 bmcr, advert, tmp;
+		u32 advert2 = 0, tmp2 = 0;
 
 		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
 					  ADVERTISED_10baseT_Full |
 					  ADVERTISED_100baseT_Half |
-					  ADVERTISED_100baseT_Full)) == 0)
+					  ADVERTISED_100baseT_Full |
+					  ADVERTISED_1000baseT_Half |
+					  ADVERTISED_1000baseT_Full)) == 0)
 			return -EINVAL;
 
 		/* advertise only what has been requested */
 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+		if (mii->supports_gmii) {
+			advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
+			tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+		}
 		if (ecmd->advertising & ADVERTISED_10baseT_Half)
 			tmp |= ADVERTISE_10HALF;
 		if (ecmd->advertising & ADVERTISED_10baseT_Full)
@@ -132,10 +164,18 @@ int mii_ethtool_sset(struct mii_if_info 
 			tmp |= ADVERTISE_100HALF;
 		if (ecmd->advertising & ADVERTISED_100baseT_Full)
 			tmp |= ADVERTISE_100FULL;
+		if (mii->supports_gmii) {
+			if (ecmd->advertising & ADVERTISED_1000baseT_Half)
+				tmp2 |= ADVERTISE_1000HALF;
+			if (ecmd->advertising & ADVERTISED_1000baseT_Full)
+				tmp2 |= ADVERTISE_1000FULL;
+		}
 		if (advert != tmp) {
 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
 			mii->advertising = tmp;
 		}
+		if ((mii->supports_gmii) && (advert2 != tmp2))
+			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
 		
 		/* turn on autonegotiation, and force a renegotiate */
 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
@@ -148,8 +188,11 @@ int mii_ethtool_sset(struct mii_if_info 
 
 		/* turn off auto negotiation, set speed and duplexity */
 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
-		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
-		if (ecmd->speed == SPEED_100)
+		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | 
+			       BMCR_SPEED1000 | BMCR_FULLDPLX);
+		if (ecmd->speed == SPEED_1000)
+			tmp |= BMCR_SPEED1000;
+		else if (ecmd->speed == SPEED_100)
 			tmp |= BMCR_SPEED100;
 		if (ecmd->duplex == DUPLEX_FULL) {
 			tmp |= BMCR_FULLDPLX;
@@ -207,6 +250,7 @@ unsigned int mii_check_media (struct mii
 {
 	unsigned int old_carrier, new_carrier;
 	int advertise, lpa, media, duplex;
+	int lpa2 = 0;
 
 	/* if forced media, go no further */
 	if (mii->force_media)
@@ -243,16 +287,20 @@ unsigned int mii_check_media (struct mii
 		mii->advertising = advertise;
 	}
 	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
+	if (mii->supports_gmii)
+		lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
 
 	/* figure out media and duplex from advertise and LPA values */
 	media = mii_nway_result(lpa & advertise);
 	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+	if (lpa2 & LPA_1000FULL)
+		duplex = 1;
 
 	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",
+		       lpa2 & (LPA_1000FULL | LPA_1000HALF) ? "1000" :
+		       media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10",
 		       duplex ? "full" : "half",
 		       lpa);
 
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1,5 +1,5 @@
 /*
- * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports
+ * drivers/net/mv643xx_eth.c - Driver for MV643XX ethernet ports
  * Copyright (C) 2002 Matthew Dharm <mdharm@momenco.com>
  *
  * Based on the 64360 driver from:
@@ -10,6 +10,12 @@
  *
  * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
  *
+ * Copyright (C) 2004-2005 MontaVista Software, Inc.
+ *			   Dale Farnsworth <dale@farnsworth.org>
+ *
+ * Copyright (C) 2004 Steven J. Hill <sjhill1@rockwellcollins.com>
+ *				     <sjhill@realitydiluted.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
@@ -24,80 +30,100 @@
  * 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/version.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ip.h>
 #include <linux/init.h>
-#include <linux/in.h>
-#include <linux/pci.h>
-#include <linux/workqueue.h>
-#include <asm/smp.h>
-#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
 #include <linux/tcp.h>
-#include <linux/netdevice.h>
+#include <linux/udp.h>
 #include <linux/etherdevice.h>
-#include <net/ip.h>
 
 #include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/delay.h>
 #include "mv643xx_eth.h"
 
 /*
- * The first part is the high level driver of the gigE ethernet ports. 
+ * The first part is the high level driver of the gigE ethernet ports.
  */
 
-/* Definition for configuring driver */
-#undef MV64340_RX_QUEUE_FILL_ON_TASK
-
 /* Constants */
-#define EXTRA_BYTES 32
-#define WRAP       ETH_HLEN + 2 + 4 + 16
-#define BUFFER_MTU dev->mtu + WRAP
+#define VLAN_HLEN		4
+#define FCS_LEN			4
+#define WRAP			NET_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN
+#define RX_SKB_SIZE		((dev->mtu + WRAP + 7) & ~0x7)
+
 #define INT_CAUSE_UNMASK_ALL		0x0007ffff
 #define INT_CAUSE_UNMASK_ALL_EXT	0x0011ffff
-#ifdef MV64340_RX_FILL_ON_TASK
+#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
 #define INT_CAUSE_MASK_ALL		0x00000000
 #define INT_CAUSE_CHECK_BITS		INT_CAUSE_UNMASK_ALL
 #define INT_CAUSE_CHECK_BITS_EXT	INT_CAUSE_UNMASK_ALL_EXT
 #endif
 
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+#define MAX_DESCS_PER_SKB	(MAX_SKB_FRAGS + 1)
+#else
+#define MAX_DESCS_PER_SKB	1
+#endif
+
+#define PHY_WAIT_ITERATIONS	1000	/* 1000 iterations * 10uS = 10mS max */
+#define PHY_WAIT_MICRO_SECONDS	10
+
 /* Static function declarations */
-static int mv64340_eth_real_open(struct net_device *);
-static int mv64340_eth_real_stop(struct net_device *);
-static int mv64340_eth_change_mtu(struct net_device *, int);
-static struct net_device_stats *mv64340_eth_get_stats(struct net_device *);
+static int eth_port_link_is_up(unsigned int eth_port_num);
+static void eth_port_uc_addr_get(struct net_device *dev,
+						unsigned char *MacAddr);
+static int mv643xx_eth_real_open(struct net_device *);
+static int mv643xx_eth_real_stop(struct net_device *);
+static int mv643xx_eth_change_mtu(struct net_device *, int);
+static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *);
 static void eth_port_init_mac_tables(unsigned int eth_port_num);
-#ifdef MV64340_NAPI
-static int mv64340_poll(struct net_device *dev, int *budget);
+#ifdef MV643XX_NAPI
+static int mv643xx_poll(struct net_device *dev, int *budget);
 #endif
+static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
+static int ethernet_phy_detect(unsigned int eth_port_num);
+static struct ethtool_ops mv643xx_ethtool_ops;
+
+static char mv643xx_driver_name[] = "mv643xx_eth";
+static char mv643xx_driver_version[] = "1.0";
+
+static void __iomem *mv643xx_eth_shared_base;
+
+/* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */
+static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED;
+
+static inline u32 mv_read(int offset)
+{
+	void __iomem *reg_base;
+
+	reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS;
+
+	return readl(reg_base + offset);
+}
+
+static inline void mv_write(int offset, u32 data)
+{
+	void __iomem *reg_base;
 
-unsigned char prom_mac_addr_base[6];
-unsigned long mv64340_sram_base;
+	reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS;
+	writel(data, reg_base + offset);
+}
 
 /*
  * Changes MTU (maximum transfer unit) of the gigabit ethenret port
  *
- * Input : pointer to ethernet interface network device structure
- *         new mtu size 
- * Output : 0 upon success, -EINVAL upon failure
+ * Input :	pointer to ethernet interface network device structure
+ *		new mtu size
+ * Output :	0 upon success, -EINVAL upon failure
  */
-static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu)
+static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&mp->lock, flags);
@@ -108,21 +134,21 @@ static int mv64340_eth_change_mtu(struct
 	}
 
 	dev->mtu = new_mtu;
-	/* 
+	/*
 	 * Stop then re-open the interface. This will allocate RX skb's with
 	 * the new MTU.
 	 * There is a possible danger that the open will not successed, due
 	 * to memory is full, which might fail the open function.
 	 */
 	if (netif_running(dev)) {
-		if (mv64340_eth_real_stop(dev))
+		if (mv643xx_eth_real_stop(dev))
 			printk(KERN_ERR
-			       "%s: Fatal error on stopping device\n",
-			       dev->name);
-		if (mv64340_eth_real_open(dev))
+				"%s: Fatal error on stopping device\n",
+				dev->name);
+		if (mv643xx_eth_real_open(dev))
 			printk(KERN_ERR
-			       "%s: Fatal error on opening device\n",
-			       dev->name);
+				"%s: Fatal error on opening device\n",
+				dev->name);
 	}
 
 	spin_unlock_irqrestore(&mp->lock, flags);
@@ -130,17 +156,17 @@ static int mv64340_eth_change_mtu(struct
 }
 
 /*
- * mv64340_eth_rx_task
- *								       
+ * mv643xx_eth_rx_task
+ *
  * Fills / refills RX queue on a certain gigabit ethernet port
  *
- * Input : pointer to ethernet interface network device structure
- * Output : N/A
+ * Input :	pointer to ethernet interface network device structure
+ * Output :	N/A
  */
-static void mv64340_eth_rx_task(void *data)
+static void mv643xx_eth_rx_task(void *data)
 {
-	struct net_device *dev = (struct net_device *) data;
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct net_device *dev = (struct net_device *)data;
+	struct mv643xx_private *mp = netdev_priv(dev);
 	struct pkt_info pkt_info;
 	struct sk_buff *skb;
 
@@ -148,28 +174,18 @@ static void mv64340_eth_rx_task(void *da
 		panic("%s: Error in test_set_bit / clear_bit", dev->name);
 
 	while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) {
-		/* The +8 for buffer allignment and another 32 byte extra */
-
-		skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES);
+		skb = dev_alloc_skb(RX_SKB_SIZE);
 		if (!skb)
-			/* Better luck next time */
 			break;
 		mp->rx_ring_skbs++;
 		pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;
-		pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES;
-		/* Allign buffer to 8 bytes */
-		if (pkt_info.byte_cnt & ~0x7) {
-			pkt_info.byte_cnt &= ~0x7;
-			pkt_info.byte_cnt += 8;
-		}
-		pkt_info.buf_ptr =
-		    pci_map_single(0, skb->data,
-				   dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES,
-				   PCI_DMA_FROMDEVICE);
+		pkt_info.byte_cnt = RX_SKB_SIZE;
+		pkt_info.buf_ptr = dma_map_single(NULL, skb->data, RX_SKB_SIZE,
+							DMA_FROM_DEVICE);
 		pkt_info.return_info = skb;
 		if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) {
 			printk(KERN_ERR
-			       "%s: Error allocating RX Ring\n", dev->name);
+				"%s: Error allocating RX Ring\n", dev->name);
 			break;
 		}
 		skb_reserve(skb, 2);
@@ -186,46 +202,45 @@ static void mv64340_eth_rx_task(void *da
 		add_timer(&mp->timeout);
 		mp->rx_timer_flag = 1;
 	}
-#if MV64340_RX_QUEUE_FILL_ON_TASK
+#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
 	else {
 		/* Return interrupts */
-		MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num),
-			 INT_CAUSE_UNMASK_ALL);
+		mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(mp->port_num),
+							INT_CAUSE_UNMASK_ALL);
 	}
 #endif
 }
 
 /*
- * mv64340_eth_rx_task_timer_wrapper
- *								       
+ * mv643xx_eth_rx_task_timer_wrapper
+ *
  * Timer routine to wake up RX queue filling task. This function is
  * used only in case the RX queue is empty, and all alloc_skb has
  * failed (due to out of memory event).
  *
- * Input : pointer to ethernet interface network device structure
- * Output : N/A
+ * Input :	pointer to ethernet interface network device structure
+ * Output :	N/A
  */
-static void mv64340_eth_rx_task_timer_wrapper(unsigned long data)
+static void mv643xx_eth_rx_task_timer_wrapper(unsigned long data)
 {
-	struct net_device *dev = (struct net_device *) data;
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct net_device *dev = (struct net_device *)data;
+	struct mv643xx_private *mp = netdev_priv(dev);
 
 	mp->rx_timer_flag = 0;
-	mv64340_eth_rx_task((void *) data);
+	mv643xx_eth_rx_task((void *)data);
 }
 
-
 /*
- * mv64340_eth_update_mac_address
- *								       
+ * mv643xx_eth_update_mac_address
+ *
  * Update the MAC address of the port in the address table
  *
- * Input : pointer to ethernet interface network device structure
- * Output : N/A
+ * Input :	pointer to ethernet interface network device structure
+ * Output :	N/A
  */
-static void mv64340_eth_update_mac_address(struct net_device *dev)
+static void mv643xx_eth_update_mac_address(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
 
 	eth_port_init_mac_tables(port_num);
@@ -234,64 +249,59 @@ static void mv64340_eth_update_mac_addre
 }
 
 /*
- * mv64340_eth_set_rx_mode
- *								       
+ * mv643xx_eth_set_rx_mode
+ *
  * Change from promiscuos to regular rx mode
  *
- * Input : pointer to ethernet interface network device structure
- * Output : N/A
+ * Input :	pointer to ethernet interface network device structure
+ * Output :	N/A
  */
-static void mv64340_eth_set_rx_mode(struct net_device *dev)
+static void mv643xx_eth_set_rx_mode(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
+	u32 config_reg;
 
-	if (dev->flags & IFF_PROMISC) {
-		ethernet_set_config_reg
-		    (mp->port_num,
-		     ethernet_get_config_reg(mp->port_num) |
-		     ETH_UNICAST_PROMISCUOUS_MODE);
-	} else {
-		ethernet_set_config_reg
-		    (mp->port_num,
-		     ethernet_get_config_reg(mp->port_num) &
-		     ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE);
-	}
+	config_reg = ethernet_get_config_reg(mp->port_num);
+	if (dev->flags & IFF_PROMISC)
+		config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+	else
+		config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+	ethernet_set_config_reg(mp->port_num, config_reg);
 }
 
-
 /*
- * mv64340_eth_set_mac_address
- *								       
+ * mv643xx_eth_set_mac_address
+ *
  * Change the interface's mac address.
  * No special hardware thing should be done because interface is always
  * put in promiscuous mode.
  *
- * Input : pointer to ethernet interface network device structure and
- *         a pointer to the designated entry to be added to the cache.
- * Output : zero upon success, negative upon failure
+ * Input :	pointer to ethernet interface network device structure and
+ *		a pointer to the designated entry to be added to the cache.
+ * Output :	zero upon success, negative upon failure
  */
-static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr)
+static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr)
 {
 	int i;
 
 	for (i = 0; i < 6; i++)
 		/* +2 is for the offset of the HW addr type */
-		dev->dev_addr[i] = ((unsigned char *) addr)[i + 2];
-	mv64340_eth_update_mac_address(dev);
+		dev->dev_addr[i] = ((unsigned char *)addr)[i + 2];
+	mv643xx_eth_update_mac_address(dev);
 	return 0;
 }
 
 /*
- * mv64340_eth_tx_timeout
- *								       
+ * mv643xx_eth_tx_timeout
+ *
  * Called upon a timeout on transmitting a packet
  *
- * Input : pointer to ethernet interface network device structure.
- * Output : N/A
+ * Input :	pointer to ethernet interface network device structure.
+ * Output :	N/A
  */
-static void mv64340_eth_tx_timeout(struct net_device *dev)
+static void mv643xx_eth_tx_timeout(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 
 	printk(KERN_INFO "%s: TX timeout  ", dev->name);
 
@@ -300,31 +310,31 @@ static void mv64340_eth_tx_timeout(struc
 }
 
 /*
- * mv64340_eth_tx_timeout_task
+ * mv643xx_eth_tx_timeout_task
  *
  * Actual routine to reset the adapter when a timeout on Tx has occurred
  */
-static void mv64340_eth_tx_timeout_task(struct net_device *dev)
+static void mv643xx_eth_tx_timeout_task(struct net_device *dev)
 {
-        struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 
-        netif_device_detach(dev);
-        eth_port_reset(mp->port_num);
-        eth_port_start(mp);
-        netif_device_attach(dev);
+	netif_device_detach(dev);
+	eth_port_reset(mp->port_num);
+	eth_port_start(mp);
+	netif_device_attach(dev);
 }
 
 /*
- * mv64340_eth_free_tx_queue
+ * mv643xx_eth_free_tx_queue
  *
- * Input : dev - a pointer to the required interface
+ * Input :	dev - a pointer to the required interface
  *
- * Output : 0 if was able to release skb , nonzero otherwise
+ * Output :	0 if was able to release skb , nonzero otherwise
  */
-static int mv64340_eth_free_tx_queue(struct net_device *dev,
-			      unsigned int eth_int_cause_ext)
+static int mv643xx_eth_free_tx_queue(struct net_device *dev,
+					unsigned int eth_int_cause_ext)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	struct net_device_stats *stats = &mp->stats;
 	struct pkt_info pkt_info;
 	int released = 1;
@@ -341,33 +351,36 @@ static int mv64340_eth_free_tx_queue(str
 			stats->tx_errors++;
 		}
 
-		/* 
+		/*
 		 * If return_info is different than 0, release the skb.
 		 * The case where return_info is not 0 is only in case
 		 * when transmitted a scatter/gather packet, where only
 		 * last skb releases the whole chain.
 		 */
 		if (pkt_info.return_info) {
-			dev_kfree_skb_irq((struct sk_buff *)
-					  pkt_info.return_info);
-			released = 0;
 			if (skb_shinfo(pkt_info.return_info)->nr_frags)
-				pci_unmap_page(NULL, pkt_info.buf_ptr,
-					pkt_info.byte_cnt, PCI_DMA_TODEVICE);
+				dma_unmap_page(NULL, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						DMA_TO_DEVICE);
+			else
+				dma_unmap_single(NULL, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						DMA_TO_DEVICE);
 
-			if (mp->tx_ring_skbs != 1)
-				mp->tx_ring_skbs--;
-		} else 
-			pci_unmap_page(NULL, pkt_info.buf_ptr,
-					pkt_info.byte_cnt, PCI_DMA_TODEVICE);
-
-		/* 
-		 * Decrement the number of outstanding skbs counter on
-		 * the TX queue.
-		 */
-		if (mp->tx_ring_skbs == 0)
-			panic("ERROR - TX outstanding SKBs counter is corrupted");
+			dev_kfree_skb_irq(pkt_info.return_info);
+			released = 0;
 
+			/*
+			 * Decrement the number of outstanding skbs counter on
+			 * the TX queue.
+			 */
+			if (mp->tx_ring_skbs == 0)
+				panic("ERROR - TX outstanding SKBs"
+						" counter is corrupted");
+			mp->tx_ring_skbs--;
+		} else
+			dma_unmap_page(NULL, pkt_info.buf_ptr,
+					pkt_info.byte_cnt, DMA_TO_DEVICE);
 	}
 
 	spin_unlock(&mp->lock);
@@ -376,60 +389,59 @@ static int mv64340_eth_free_tx_queue(str
 }
 
 /*
- * mv64340_eth_receive
+ * mv643xx_eth_receive
  *
  * This function is forward packets that are received from the port's
  * queues toward kernel core or FastRoute them to another interface.
  *
- * Input : dev - a pointer to the required interface
- *         max - maximum number to receive (0 means unlimted)
+ * Input :	dev - a pointer to the required interface
+ *		max - maximum number to receive (0 means unlimted)
  *
- * Output : number of served packets
+ * Output :	number of served packets
  */
-#ifdef MV64340_NAPI
-static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max,
-								int budget)
+#ifdef MV643XX_NAPI
+static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
 #else
-static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max)
+static int mv643xx_eth_receive_queue(struct net_device *dev)
 #endif
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	struct net_device_stats *stats = &mp->stats;
 	unsigned int received_packets = 0;
 	struct sk_buff *skb;
 	struct pkt_info pkt_info;
 
-#ifdef MV64340_NAPI
+#ifdef MV643XX_NAPI
 	while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
 #else
-	while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) {
+	while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #endif
 		mp->rx_ring_skbs--;
 		received_packets++;
-#ifdef MV64340_NAPI
+#ifdef MV643XX_NAPI
 		budget--;
 #endif
 		/* Update statistics. Note byte count includes 4 byte CRC count */
 		stats->rx_packets++;
 		stats->rx_bytes += pkt_info.byte_cnt;
-		skb = (struct sk_buff *) pkt_info.return_info;
+		skb = pkt_info.return_info;
 		/*
 		 * In case received a packet without first / last bits on OR
 		 * the error summary bit is on, the packets needs to be dropeed.
 		 */
 		if (((pkt_info.cmd_sts
-		      & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) !=
-		     (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC))
-		    || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) {
+				& (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) !=
+					(ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC))
+				|| (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) {
 			stats->rx_dropped++;
 			if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC |
-						 ETH_RX_LAST_DESC)) !=
-			    (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) {
+							ETH_RX_LAST_DESC)) !=
+				(ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) {
 				if (net_ratelimit())
 					printk(KERN_ERR
-					       "%s: Received packet spread on multiple"
-					       " descriptors\n",
-					       dev->name);
+						"%s: Received packet spread "
+						"on multiple descriptors\n",
+						dev->name);
 			}
 			if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)
 				stats->rx_errors++;
@@ -445,11 +457,11 @@ static int mv64340_eth_receive_queue(str
 
 			if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
-				skb->csum = htons((pkt_info.cmd_sts
-							& 0x0007fff8) >> 3);
+				skb->csum = htons(
+					(pkt_info.cmd_sts & 0x0007fff8) >> 3);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-#ifdef MV64340_NAPI
+#ifdef MV643XX_NAPI
 			netif_receive_skb(skb);
 #else
 			netif_rx(skb);
@@ -461,74 +473,74 @@ static int mv64340_eth_receive_queue(str
 }
 
 /*
- * mv64340_eth_int_handler
+ * mv643xx_eth_int_handler
  *
  * Main interrupt handler for the gigbit ethernet ports
  *
- * Input : irq - irq number (not used)
- *         dev_id - a pointer to the required interface's data structure
- *         regs   - not used
- * Output : N/A
+ * Input :	irq	- irq number (not used)
+ *		dev_id	- a pointer to the required interface's data structure
+ *		regs	- not used
+ * Output :	N/A
  */
 
-static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id,
-	struct pt_regs *regs)
+static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
+							struct pt_regs *regs)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct mv643xx_private *mp = netdev_priv(dev);
 	u32 eth_int_cause, eth_int_cause_ext = 0;
 	unsigned int port_num = mp->port_num;
 
 	/* Read interrupt cause registers */
-	eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) &
-			INT_CAUSE_UNMASK_ALL;
+	eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) &
+						INT_CAUSE_UNMASK_ALL;
 
 	if (eth_int_cause & BIT1)
-		eth_int_cause_ext =
-		MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
-		INT_CAUSE_UNMASK_ALL_EXT;
+		eth_int_cause_ext = mv_read(
+			MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
+						INT_CAUSE_UNMASK_ALL_EXT;
 
-#ifdef MV64340_NAPI
+#ifdef MV643XX_NAPI
 	if (!(eth_int_cause & 0x0007fffd)) {
-	/* Dont ack the Rx interrupt */
+		/* Dont ack the Rx interrupt */
 #endif
 		/*
-	 	 * Clear specific ethernet port intrerrupt registers by
+		 * Clear specific ethernet port intrerrupt registers by
 		 * acknowleding relevant bits.
 		 */
-		MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),
-			 ~eth_int_cause);
+		mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num),
+							~eth_int_cause);
 		if (eth_int_cause_ext != 0x0)
-			MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
-				 ~eth_int_cause_ext);
+			mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG
+					(port_num), ~eth_int_cause_ext);
 
 		/* UDP change : We may need this */
 		if ((eth_int_cause_ext & 0x0000ffff) &&
-		    (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) &&
-		    (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1))
-                                         netif_wake_queue(dev);
-#ifdef MV64340_NAPI
+		    (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) &&
+		    (mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB))
+			netif_wake_queue(dev);
+#ifdef MV643XX_NAPI
 	} else {
 		if (netif_rx_schedule_prep(dev)) {
 			/* Mask all the interrupts */
-			MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0);
-			MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
+			mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0);
+			mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG
+								(port_num), 0);
 			__netif_rx_schedule(dev);
 		}
 #else
-		{
 		if (eth_int_cause & (BIT2 | BIT11))
-			mv64340_eth_receive_queue(dev, 0);
+			mv643xx_eth_receive_queue(dev, 0);
 
 		/*
-		 * After forwarded received packets to upper layer,  add a task
+		 * After forwarded received packets to upper layer, add a task
 		 * in an interrupts enabled context that refills the RX ring
 		 * with skb's.
 		 */
-#if MV64340_RX_QUEUE_FILL_ON_TASK
+#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
 		/* Unmask all interrupts on ethernet port */
-		MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),
-		         INT_CAUSE_MASK_ALL);
+		mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+							INT_CAUSE_MASK_ALL);
 		queue_task(&mp->rx_task, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
 #else
@@ -538,25 +550,15 @@ static irqreturn_t mv64340_eth_int_handl
 	}
 	/* PHY status changed */
 	if (eth_int_cause_ext & (BIT16 | BIT20)) {
-		unsigned int phy_reg_data;
-
-		/* Check Link status on ethernet port */
-		eth_port_read_smi_reg(port_num, 1, &phy_reg_data);
-		if (!(phy_reg_data & 0x20)) {
-			netif_stop_queue(dev);
-		} else {
+		if (eth_port_link_is_up(port_num)) {
+			netif_carrier_on(dev);
 			netif_wake_queue(dev);
-
-			/*
-			 * Start all TX queues on ethernet port. This is good in
-			 * case of previous packets where not transmitted, due
-			 * to link down and this command re-enables all TX
-			 * queues.
-			 * Note that it is possible to get a TX resource error
-			 * interrupt after issuing this, since not all TX queues
-			 * are enabled, or has anything to send.
-			 */
-			MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1);
+			/* Start TX queue */
+			mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG
+								(port_num), 1);
+		} else {
+			netif_carrier_off(dev);
+			netif_stop_queue(dev);
 		}
 	}
 
@@ -570,7 +572,7 @@ static irqreturn_t mv64340_eth_int_handl
 	return IRQ_HANDLED;
 }
 
-#ifdef MV64340_COAL
+#ifdef MV643XX_COAL
 
 /*
  * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path
@@ -584,9 +586,9 @@ static irqreturn_t mv64340_eth_int_handl
  *	, and the required delay of the interrupt in usec.
  *
  * INPUT:
- *	unsigned int eth_port_num      Ethernet port number
- *	unsigned int t_clk        t_clk of the MV-643xx chip in HZ units
- *	unsigned int delay       Delay in usec
+ *	unsigned int eth_port_num	Ethernet port number
+ *	unsigned int t_clk		t_clk of the MV-643xx chip in HZ units
+ *	unsigned int delay		Delay in usec
  *
  * OUTPUT:
  *	Interrupt coalescing mechanism value is set in MV-643xx chip.
@@ -596,15 +598,15 @@ static irqreturn_t mv64340_eth_int_handl
  *
  */
 static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num,
-	unsigned int t_clk, unsigned int delay)
+					unsigned int t_clk, unsigned int delay)
 {
 	unsigned int coal = ((t_clk / 1000000) * delay) / 64;
 
 	/* Set RX Coalescing mechanism */
-	MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num),
-		 ((coal & 0x3fff) << 8) |
-		 (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num))
-		  & 0xffc000ff));
+	mv_write(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num),
+		((coal & 0x3fff) << 8) |
+		(mv_read(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num))
+			& 0xffc000ff));
 
 	return coal;
 }
@@ -618,13 +620,13 @@ static unsigned int eth_port_set_rx_coal
  *	This parameter is a timeout counter, that counts in 64 t_clk
  *	chunks ; that when timeout event occurs a maskable interrupt
  *	occurs.
- *	The parameter is calculated using the t_cLK frequency of the 
+ *	The parameter is calculated using the t_cLK frequency of the
  *	MV-643xx chip and the required delay in the interrupt in uSec
  *
  * INPUT:
- *	unsigned int eth_port_num      Ethernet port number
- *	unsigned int t_clk        t_clk of the MV-643xx chip in HZ units
- *	unsigned int delay       Delay in uSeconds
+ *	unsigned int eth_port_num	Ethernet port number
+ *	unsigned int t_clk		t_clk of the MV-643xx chip in HZ units
+ *	unsigned int delay		Delay in uSeconds
  *
  * OUTPUT:
  *	Interrupt coalescing mechanism value is set in MV-643xx chip.
@@ -634,48 +636,48 @@ static unsigned int eth_port_set_rx_coal
  *
  */
 static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num,
-	unsigned int t_clk, unsigned int delay)
+					unsigned int t_clk, unsigned int delay)
 {
 	unsigned int coal;
 	coal = ((t_clk / 1000000) * delay) / 64;
 	/* Set TX Coalescing mechanism */
-	MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num),
-		 coal << 4);
+	mv_write(MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num),
+								coal << 4);
 	return coal;
 }
 
 /*
- * mv64340_eth_open
+ * mv643xx_eth_open
  *
  * This function is called when openning the network device. The function
  * should initialize all the hardware, initialize cyclic Rx/Tx
  * descriptors chain and buffers and allocate an IRQ to the network
  * device.
  *
- * Input : a pointer to the network device structure
+ * Input :	a pointer to the network device structure
  *
- * Output : zero of success , nonzero if fails.
+ * Output :	zero of success , nonzero if fails.
  */
 
-static int mv64340_eth_open(struct net_device *dev)
+static int mv643xx_eth_open(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
-	int err = err;
+	int err;
 
 	spin_lock_irq(&mp->lock);
 
-	err = request_irq(dev->irq, mv64340_eth_int_handler,
-	                  SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev);
+	err = request_irq(dev->irq, mv643xx_eth_int_handler,
+			SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
 
 	if (err) {
-		printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n",
-		       port_num);
+		printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n",
+								port_num);
 		err = -EAGAIN;
 		goto out;
 	}
 
-	if (mv64340_eth_real_open(dev)) {
+	if (mv643xx_eth_real_open(dev)) {
 		printk("%s: Error opening interface\n", dev->name);
 		err = -EBUSY;
 		goto out_free;
@@ -698,66 +700,35 @@ out:
  * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory.
  *
  * DESCRIPTION:
- *       This function prepares a Rx chained list of descriptors and packet 
- *       buffers in a form of a ring. The routine must be called after port 
- *       initialization routine and before port start routine. 
- *       The Ethernet SDMA engine uses CPU bus addresses to access the various 
- *       devices in the system (i.e. DRAM). This function uses the ethernet 
- *       struct 'virtual to physical' routine (set by the user) to set the ring 
- *       with physical addresses.
+ *	This function prepares a Rx chained list of descriptors and packet
+ *	buffers in a form of a ring. The routine must be called after port
+ *	initialization routine and before port start routine.
+ *	The Ethernet SDMA engine uses CPU bus addresses to access the various
+ *	devices in the system (i.e. DRAM). This function uses the ethernet
+ *	struct 'virtual to physical' routine (set by the user) to set the ring
+ *	with physical addresses.
  *
  * INPUT:
- *	struct mv64340_private   *mp   Ethernet Port Control srtuct. 
- *      int 			rx_desc_num       Number of Rx descriptors
- *      int 			rx_buff_size      Size of Rx buffer
- *      unsigned int    rx_desc_base_addr  Rx descriptors memory area base addr.
- *      unsigned int    rx_buff_base_addr  Rx buffer memory area base addr.
+ *	struct mv643xx_private *mp	Ethernet Port Control srtuct.
  *
  * OUTPUT:
- *      The routine updates the Ethernet port control struct with information 
- *      regarding the Rx descriptors and buffers.
+ *	The routine updates the Ethernet port control struct with information
+ *	regarding the Rx descriptors and buffers.
  *
  * RETURN:
- *      false if the given descriptors memory area is not aligned according to
- *      Ethernet SDMA specifications.
- *      true otherwise.
+ *	None.
  */
-static int ether_init_rx_desc_ring(struct mv64340_private * mp,
-	unsigned long rx_buff_base_addr)
+static void ether_init_rx_desc_ring(struct mv643xx_private *mp)
 {
-	unsigned long buffer_addr = rx_buff_base_addr;
 	volatile struct eth_rx_desc *p_rx_desc;
 	int rx_desc_num = mp->rx_ring_size;
-	unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area;
-	int rx_buff_size = 1536;	/* Dummy, will be replaced later */
 	int i;
 
-	p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr;
-
-	/* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
-	if (rx_buff_base_addr & 0xf)
-		return 0;
-
-	/* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes  */
-	if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE))
-		return 0;
-
-	/* Rx buffers must be 64-bit aligned.       */
-	if ((rx_buff_base_addr + rx_buff_size) & 0x7)
-		return 0;
-
-	/* initialize the Rx descriptors ring */
+	/* initialize the next_desc_ptr links in the Rx descriptors ring */
+	p_rx_desc = (struct eth_rx_desc *)mp->p_rx_desc_area;
 	for (i = 0; i < rx_desc_num; i++) {
-		p_rx_desc[i].buf_size = rx_buff_size;
-		p_rx_desc[i].byte_cnt = 0x0000;
-		p_rx_desc[i].cmd_sts =
-			ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT;
 		p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma +
 			((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc);
-		p_rx_desc[i].buf_ptr = buffer_addr;
-
-		mp->rx_skb[i] = NULL;
-		buffer_addr += rx_buff_size;
 	}
 
 	/* Save Rx desc pointer to driver struct. */
@@ -766,293 +737,288 @@ static int ether_init_rx_desc_ring(struc
 
 	mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc);
 
+	/* Add the queue to the list of RX queues of this port */
 	mp->port_rx_queue_command |= 1;
-
-	return 1;
 }
 
 /*
  * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory.
  *
  * DESCRIPTION:
- *       This function prepares a Tx chained list of descriptors and packet 
- *       buffers in a form of a ring. The routine must be called after port 
- *       initialization routine and before port start routine. 
- *       The Ethernet SDMA engine uses CPU bus addresses to access the various 
- *       devices in the system (i.e. DRAM). This function uses the ethernet 
- *       struct 'virtual to physical' routine (set by the user) to set the ring 
- *       with physical addresses.
+ *	This function prepares a Tx chained list of descriptors and packet
+ *	buffers in a form of a ring. The routine must be called after port
+ *	initialization routine and before port start routine.
+ *	The Ethernet SDMA engine uses CPU bus addresses to access the various
+ *	devices in the system (i.e. DRAM). This function uses the ethernet
+ *	struct 'virtual to physical' routine (set by the user) to set the ring
+ *	with physical addresses.
  *
  * INPUT:
- *	struct mv64340_private   *mp   Ethernet Port Control srtuct. 
- *      int 		tx_desc_num        Number of Tx descriptors
- *      int 		tx_buff_size	   Size of Tx buffer
- *      unsigned int    tx_desc_base_addr  Tx descriptors memory area base addr.
+ *	struct mv643xx_private *mp	Ethernet Port Control srtuct.
  *
  * OUTPUT:
- *      The routine updates the Ethernet port control struct with information 
- *      regarding the Tx descriptors and buffers.
+ *	The routine updates the Ethernet port control struct with information
+ *	regarding the Tx descriptors and buffers.
  *
  * RETURN:
- *      false if the given descriptors memory area is not aligned according to
- *      Ethernet SDMA specifications.
- *      true otherwise.
+ *	None.
  */
-static int ether_init_tx_desc_ring(struct mv64340_private *mp)
+static void ether_init_tx_desc_ring(struct mv643xx_private *mp)
 {
-	unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area;
 	int tx_desc_num = mp->tx_ring_size;
 	struct eth_tx_desc *p_tx_desc;
 	int i;
 
-	/* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
-	if (tx_desc_base_addr & 0xf)
-		return 0;
-
-	/* save the first desc pointer to link with the last descriptor */
-	p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr;
-
-	/* Initialize the Tx descriptors ring */
+	/* Initialize the next_desc_ptr links in the Tx descriptors ring */
+	p_tx_desc = (struct eth_tx_desc *)mp->p_tx_desc_area;
 	for (i = 0; i < tx_desc_num; i++) {
-		p_tx_desc[i].byte_cnt	= 0x0000;
-		p_tx_desc[i].l4i_chk	= 0x0000;
-		p_tx_desc[i].cmd_sts	= 0x00000000;
 		p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma +
 			((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc);
-		p_tx_desc[i].buf_ptr	= 0x00000000;
-		mp->tx_skb[i]		= NULL;
 	}
 
-	/* Set Tx desc pointer in driver struct. */
 	mp->tx_curr_desc_q = 0;
 	mp->tx_used_desc_q = 0;
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-        mp->tx_first_desc_q = 0;
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+	mp->tx_first_desc_q = 0;
 #endif
-	/* Init Tx ring base and size parameters */
-	mp->tx_desc_area_size	= tx_desc_num * sizeof(struct eth_tx_desc);
+
+	mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc);
 
 	/* Add the queue to the list of Tx queues of this port */
 	mp->port_tx_queue_command |= 1;
-
-	return 1;
 }
 
-/* Helper function for mv64340_eth_open */
-static int mv64340_eth_real_open(struct net_device *dev)
+/* Helper function for mv643xx_eth_open */
+static int mv643xx_eth_real_open(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
-	u32 phy_reg_data;
 	unsigned int size;
 
 	/* Stop RX Queues */
-	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
-		 0x0000ff00);
+	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
 
 	/* Clear the ethernet port interrupts */
-	MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
-	MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
 
 	/* Unmask RX buffer and TX end interrupt */
-	MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),
-		 INT_CAUSE_UNMASK_ALL);
+	mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+						INT_CAUSE_UNMASK_ALL);
 
 	/* Unmask phy and link status changes interrupts */
-	MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
-		 INT_CAUSE_UNMASK_ALL_EXT);
+	mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+						INT_CAUSE_UNMASK_ALL_EXT);
 
 	/* Set the MAC Address */
 	memcpy(mp->port_mac_addr, dev->dev_addr, 6);
 
 	eth_port_init(mp);
 
-	INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev);
+	INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev);
 
 	memset(&mp->timeout, 0, sizeof(struct timer_list));
-	mp->timeout.function = mv64340_eth_rx_task_timer_wrapper;
-	mp->timeout.data = (unsigned long) dev;
+	mp->timeout.function = mv643xx_eth_rx_task_timer_wrapper;
+	mp->timeout.data = (unsigned long)dev;
 
 	mp->rx_task_busy = 0;
 	mp->rx_timer_flag = 0;
 
+	/* Allocate RX and TX skb rings */
+	mp->rx_skb = kmalloc(sizeof(*mp->rx_skb) * mp->rx_ring_size,
+								GFP_KERNEL);
+	if (!mp->rx_skb) {
+		printk(KERN_ERR "%s: Cannot allocate Rx skb ring\n", dev->name);
+		return -ENOMEM;
+	}
+	mp->tx_skb = kmalloc(sizeof(*mp->tx_skb) * mp->tx_ring_size,
+								GFP_KERNEL);
+	if (!mp->tx_skb) {
+		printk(KERN_ERR "%s: Cannot allocate Tx skb ring\n", dev->name);
+		kfree(mp->rx_skb);
+		return -ENOMEM;
+	}
+
 	/* Allocate TX ring */
 	mp->tx_ring_skbs = 0;
-	mp->tx_ring_size = MV64340_TX_QUEUE_SIZE;
 	size = mp->tx_ring_size * sizeof(struct eth_tx_desc);
 	mp->tx_desc_area_size = size;
 
-	/* Assumes allocated ring is 16 bytes alligned */
-	mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma);
+	if (mp->tx_sram_size) {
+		mp->p_tx_desc_area = ioremap(mp->tx_sram_addr,
+							mp->tx_sram_size);
+		mp->tx_desc_dma = mp->tx_sram_addr;
+	} else
+		mp->p_tx_desc_area = dma_alloc_coherent(NULL, size,
+							&mp->tx_desc_dma,
+							GFP_KERNEL);
+
 	if (!mp->p_tx_desc_area) {
 		printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
-		       dev->name, size);
+							dev->name, size);
+		kfree(mp->rx_skb);
+		kfree(mp->tx_skb);
 		return -ENOMEM;
 	}
-	memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size);
+	BUG_ON((u32) mp->p_tx_desc_area & 0xf);	/* check 16-byte alignment */
+	memset((void *)mp->p_tx_desc_area, 0, mp->tx_desc_area_size);
 
-	/* Dummy will be replaced upon real tx */
 	ether_init_tx_desc_ring(mp);
 
 	/* Allocate RX ring */
-	/* Meantime RX Ring are fixed - but must be configurable by user */
-	mp->rx_ring_size = MV64340_RX_QUEUE_SIZE;
 	mp->rx_ring_skbs = 0;
 	size = mp->rx_ring_size * sizeof(struct eth_rx_desc);
 	mp->rx_desc_area_size = size;
 
-	/* Assumes allocated ring is 16 bytes aligned */
-
-	mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma);
+	if (mp->rx_sram_size) {
+		mp->p_rx_desc_area = ioremap(mp->rx_sram_addr,
+							mp->rx_sram_size);
+		mp->rx_desc_dma = mp->rx_sram_addr;
+	} else
+		mp->p_rx_desc_area = dma_alloc_coherent(NULL, size,
+							&mp->rx_desc_dma,
+							GFP_KERNEL);
 
 	if (!mp->p_rx_desc_area) {
 		printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n",
-		       dev->name, size);
+							dev->name, size);
 		printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
-		       dev->name);
-		pci_free_consistent(0, mp->tx_desc_area_size,
-				    (void *) mp->p_tx_desc_area,
-				    mp->tx_desc_dma);
+							dev->name);
+		if (mp->rx_sram_size)
+			iounmap(mp->p_rx_desc_area);
+		else
+			dma_free_coherent(NULL, mp->tx_desc_area_size,
+					mp->p_tx_desc_area, mp->tx_desc_dma);
+		kfree(mp->rx_skb);
+		kfree(mp->tx_skb);
 		return -ENOMEM;
 	}
-	memset(mp->p_rx_desc_area, 0, size);
+	memset((void *)mp->p_rx_desc_area, 0, size);
 
-	if (!(ether_init_rx_desc_ring(mp, 0)))
-		panic("%s: Error initializing RX Ring", dev->name);
+	ether_init_rx_desc_ring(mp);
 
-	mv64340_eth_rx_task(dev);	/* Fill RX ring with skb's */
+	mv643xx_eth_rx_task(dev);	/* Fill RX ring with skb's */
 
 	eth_port_start(mp);
 
 	/* Interrupt Coalescing */
 
-#ifdef MV64340_COAL
+#ifdef MV643XX_COAL
 	mp->rx_int_coal =
-		eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL);
+		eth_port_set_rx_coal(port_num, 133000000, MV643XX_RX_COAL);
 #endif
 
 	mp->tx_int_coal =
-		eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL);  
+		eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL);
 
-	/* Increase the Rx side buffer size */
-
-	MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) |
-			(MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num))
-					& 0xfff1ffff));
-
-	/* Check Link status on phy */
-	eth_port_read_smi_reg(port_num, 1, &phy_reg_data);
-	if (!(phy_reg_data & 0x20))
-		netif_stop_queue(dev);
-	else
-		netif_start_queue(dev);
+	netif_start_queue(dev);
 
 	return 0;
 }
 
-static void mv64340_eth_free_tx_rings(struct net_device *dev)
+static void mv643xx_eth_free_tx_rings(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
 	unsigned int curr;
 
 	/* Stop Tx Queues */
-	MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
-		 0x0000ff00);
+	mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
 
-	/* Free TX rings */
 	/* Free outstanding skb's on TX rings */
-	for (curr = 0;
-	     (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE);
-	     curr++) {
+	for (curr = 0; mp->tx_ring_skbs && curr < mp->tx_ring_size; curr++) {
 		if (mp->tx_skb[curr]) {
 			dev_kfree_skb(mp->tx_skb[curr]);
 			mp->tx_ring_skbs--;
 		}
 	}
-	if (mp->tx_ring_skbs != 0)
+	if (mp->tx_ring_skbs)
 		printk("%s: Error on Tx descriptor free - could not free %d"
-		     " descriptors\n", dev->name,
-		     mp->tx_ring_skbs);
-	pci_free_consistent(0, mp->tx_desc_area_size,
-			    (void *) mp->p_tx_desc_area, mp->tx_desc_dma);
+				" descriptors\n", dev->name, mp->tx_ring_skbs);
+
+	/* Free TX ring */
+	if (mp->tx_sram_size)
+		iounmap(mp->p_tx_desc_area);
+	else
+		dma_free_coherent(NULL, mp->tx_desc_area_size,
+				mp->p_tx_desc_area, mp->tx_desc_dma);
 }
 
-static void mv64340_eth_free_rx_rings(struct net_device *dev)
+static void mv643xx_eth_free_rx_rings(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
 	int curr;
 
 	/* Stop RX Queues */
-	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
-		 0x0000ff00);
+	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
 
-	/* Free RX rings */
 	/* Free preallocated skb's on RX rings */
-	for (curr = 0;
-		mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE);
-		curr++) {
+	for (curr = 0; mp->rx_ring_skbs && curr < mp->rx_ring_size; curr++) {
 		if (mp->rx_skb[curr]) {
 			dev_kfree_skb(mp->rx_skb[curr]);
 			mp->rx_ring_skbs--;
 		}
 	}
 
-	if (mp->rx_ring_skbs != 0)
+	if (mp->rx_ring_skbs)
 		printk(KERN_ERR
-		       "%s: Error in freeing Rx Ring. %d skb's still"
-		       " stuck in RX Ring - ignoring them\n", dev->name,
-		       mp->rx_ring_skbs);
-	pci_free_consistent(0, mp->rx_desc_area_size,
-			    (void *) mp->p_rx_desc_area,
-			    mp->rx_desc_dma);
+			"%s: Error in freeing Rx Ring. %d skb's still"
+			" stuck in RX Ring - ignoring them\n", dev->name,
+			mp->rx_ring_skbs);
+	/* Free RX ring */
+	if (mp->rx_sram_size)
+		iounmap(mp->p_rx_desc_area);
+	else
+		dma_free_coherent(NULL, mp->rx_desc_area_size,
+				mp->p_rx_desc_area, mp->rx_desc_dma);
 }
 
 /*
- * mv64340_eth_stop
+ * mv643xx_eth_stop
  *
- * This function is used when closing the network device. 
- * It updates the hardware, 
+ * This function is used when closing the network device.
+ * It updates the hardware,
  * release all memory that holds buffers and descriptors and release the IRQ.
- * Input : a pointer to the device structure
- * Output : zero if success , nonzero if fails
+ * Input :	a pointer to the device structure
+ * Output :	zero if success , nonzero if fails
  */
 
-/* Helper function for mv64340_eth_stop */
+/* Helper function for mv643xx_eth_stop */
 
-static int mv64340_eth_real_stop(struct net_device *dev)
+static int mv643xx_eth_real_stop(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
 
+	netif_carrier_off(dev);
 	netif_stop_queue(dev);
 
-	mv64340_eth_free_tx_rings(dev);
-	mv64340_eth_free_rx_rings(dev);
+	mv643xx_eth_free_tx_rings(dev);
+	mv643xx_eth_free_rx_rings(dev);
 
 	eth_port_reset(mp->port_num);
 
 	/* Disable ethernet port interrupts */
-	MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
-	MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
 
 	/* Mask RX buffer and TX end interrupt */
-	MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0);
 
 	/* Mask phy and link status changes interrupts */
-	MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
 
 	return 0;
 }
 
-static int mv64340_eth_stop(struct net_device *dev)
+static int mv643xx_eth_stop(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 
 	spin_lock_irq(&mp->lock);
 
-	mv64340_eth_real_stop(dev);
+	mv643xx_eth_real_stop(dev);
 
 	free_irq(dev->irq, dev);
 	spin_unlock_irq(&mp->lock);
@@ -1060,59 +1026,64 @@ static int mv64340_eth_stop(struct net_d
 	return 0;
 }
 
-#ifdef MV64340_NAPI
-static void mv64340_tx(struct net_device *dev)
+#ifdef MV643XX_NAPI
+static void mv643xx_tx(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
-        struct pkt_info pkt_info;
+	struct mv643xx_private *mp = netdev_priv(dev);
+	struct pkt_info pkt_info;
 
 	while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {
 		if (pkt_info.return_info) {
-			dev_kfree_skb_irq((struct sk_buff *)
-                                                  pkt_info.return_info);
-			if (skb_shinfo(pkt_info.return_info)->nr_frags) 
-                                 pci_unmap_page(NULL, pkt_info.buf_ptr,
-                                             pkt_info.byte_cnt,
-                                             PCI_DMA_TODEVICE);
-
-                         if (mp->tx_ring_skbs != 1)
-                                  mp->tx_ring_skbs--;
-                } else 
-                       pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt,
-                                      PCI_DMA_TODEVICE);
+			if (skb_shinfo(pkt_info.return_info)->nr_frags)
+				dma_unmap_page(NULL, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						DMA_TO_DEVICE);
+			else
+				dma_unmap_single(NULL, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						DMA_TO_DEVICE);
+
+			dev_kfree_skb_irq(pkt_info.return_info);
+
+			if (mp->tx_ring_skbs)
+				mp->tx_ring_skbs--;
+		} else
+			dma_unmap_page(NULL, pkt_info.buf_ptr,
+					pkt_info.byte_cnt, DMA_TO_DEVICE);
 	}
 
 	if (netif_queue_stopped(dev) &&
-            MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)
-                       netif_wake_queue(dev);
+			mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB)
+		netif_wake_queue(dev);
 }
 
 /*
- * mv64340_poll
+ * mv643xx_poll
  *
  * This function is used in case of NAPI
  */
-static int mv64340_poll(struct net_device *dev, int *budget)
+static int mv643xx_poll(struct net_device *dev, int *budget)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
-	int	done = 1, orig_budget, work_done;
+	struct mv643xx_private *mp = netdev_priv(dev);
+	int done = 1, orig_budget, work_done;
 	unsigned int port_num = mp->port_num;
 	unsigned long flags;
 
-#ifdef MV64340_TX_FAST_REFILL
+#ifdef MV643XX_TX_FAST_REFILL
 	if (++mp->tx_clean_threshold > 5) {
 		spin_lock_irqsave(&mp->lock, flags);
-		mv64340_tx(dev);
+		mv643xx_tx(dev);
 		mp->tx_clean_threshold = 0;
 		spin_unlock_irqrestore(&mp->lock, flags);
 	}
 #endif
 
-	if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))                                      != (u32)mp->rx_used_desc_q) {
+	if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))
+						!= (u32) mp->rx_used_desc_q) {
 		orig_budget = *budget;
 		if (orig_budget > dev->quota)
 			orig_budget = dev->quota;
-		work_done = mv64340_eth_receive_queue(dev, 0, orig_budget);
+		work_done = mv643xx_eth_receive_queue(dev, orig_budget);
 		mp->rx_task.func(dev);
 		*budget -= work_done;
 		dev->quota -= work_done;
@@ -1123,12 +1094,12 @@ static int mv64340_poll(struct net_devic
 	if (done) {
 		spin_lock_irqsave(&mp->lock, flags);
 		__netif_rx_complete(dev);
-		MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0);
-                MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0);
-		MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 
+		mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+		mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+		mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
 						INT_CAUSE_UNMASK_ALL);
-		MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
-				                 INT_CAUSE_UNMASK_ALL_EXT);
+		mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+						INT_CAUSE_UNMASK_ALL_EXT);
 		spin_unlock_irqrestore(&mp->lock, flags);
 	}
 
@@ -1137,19 +1108,19 @@ static int mv64340_poll(struct net_devic
 #endif
 
 /*
- * mv64340_eth_start_xmit
+ * mv643xx_eth_start_xmit
  *
- * This function is queues a packet in the Tx descriptor for 
+ * This function is queues a packet in the Tx descriptor for
  * required port.
  *
- * Input : skb - a pointer to socket buffer
- *         dev - a pointer to the required port
+ * Input :	skb - a pointer to socket buffer
+ *		dev - a pointer to the required port
  *
- * Output : zero upon success
+ * Output :	zero upon success
  */
-static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 	struct net_device_stats *stats = &mp->stats;
 	ETH_FUNC_RET_STATUS status;
 	unsigned long flags;
@@ -1157,119 +1128,195 @@ static int mv64340_eth_start_xmit(struct
 
 	if (netif_queue_stopped(dev)) {
 		printk(KERN_ERR
-		       "%s: Tried sending packet when interface is stopped\n",
-		       dev->name);
+			"%s: Tried sending packet when interface is stopped\n",
+			dev->name);
 		return 1;
 	}
 
 	/* This is a hard error, log it. */
-	if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <=
-	    (skb_shinfo(skb)->nr_frags + 1)) {
+	if ((mp->tx_ring_size - mp->tx_ring_skbs) <=
+					(skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		printk(KERN_ERR
-		       "%s: Bug in mv64340_eth - Trying to transmit when"
-		       " queue full !\n", dev->name);
+			"%s: Bug in mv643xx_eth - Trying to transmit when"
+			" queue full !\n", dev->name);
 		return 1;
 	}
 
 	/* Paranoid check - this shouldn't happen */
 	if (skb == NULL) {
 		stats->tx_dropped++;
+		printk(KERN_ERR "mv64320_eth paranoid check failed\n");
 		return 1;
 	}
 
 	spin_lock_irqsave(&mp->lock, flags);
 
 	/* Update packet info data structure -- DMA owned, first last */
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-	if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) {
-#endif
-		pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-	    	                   ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+	if (!skb_shinfo(skb)->nr_frags) {
+linear:
+		if (skb->ip_summed != CHECKSUM_HW) {
+			pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+					ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
+			pkt_info.l4i_chk = 0;
+		} else {
+			u32 ipheader = skb->nh.iph->ihl << 11;
 
+			pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+					ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC |
+					ETH_GEN_TCP_UDP_CHECKSUM |
+					ETH_GEN_IP_V_4_CHECKSUM | ipheader;
+			/* CPU already calculated pseudo header checksum. */
+			if (skb->nh.iph->protocol == IPPROTO_UDP) {
+				pkt_info.cmd_sts |= ETH_UDP_FRAME;
+				pkt_info.l4i_chk = skb->h.uh->check;
+			} else if (skb->nh.iph->protocol == IPPROTO_TCP)
+				pkt_info.l4i_chk = skb->h.th->check;
+			else {
+				printk(KERN_ERR
+					"%s: chksum proto != TCP or UDP\n",
+					dev->name);
+				spin_unlock_irqrestore(&mp->lock, flags);
+				return 1;
+			}
+		}
 		pkt_info.byte_cnt = skb->len;
-		pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len,
-		                                  PCI_DMA_TODEVICE);
-
-
+		pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
+							DMA_TO_DEVICE);
 		pkt_info.return_info = skb;
+		mp->tx_ring_skbs++;
 		status = eth_port_send(mp, &pkt_info);
 		if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
 			printk(KERN_ERR "%s: Error on transmitting packet\n",
-				       dev->name);
-		mp->tx_ring_skbs++;
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+								dev->name);
+		stats->tx_bytes += pkt_info.byte_cnt;
 	} else {
-		unsigned int    frag;
-		u32		ipheader;
+		unsigned int frag;
+		u32 ipheader;
 
-                /* first frag which is skb header */
-                pkt_info.byte_cnt = skb_headlen(skb);
-                pkt_info.buf_ptr = pci_map_single(0, skb->data,
-                                        skb_headlen(skb), PCI_DMA_TODEVICE);
-                pkt_info.return_info = 0;
-                ipheader = skb->nh.iph->ihl << 11;
-                pkt_info.cmd_sts = ETH_TX_FIRST_DESC | 
-					ETH_GEN_TCP_UDP_CHECKSUM |
-					ETH_GEN_IP_V_4_CHECKSUM |
-                                        ipheader;
-		/* CPU already calculated pseudo header checksum. So, use it */
-                pkt_info.l4i_chk = skb->h.th->check;
-                status = eth_port_send(mp, &pkt_info);
+		/* Since hardware can't handle unaligned fragments smaller
+		 * than 9 bytes, if we find any, we linearize the skb
+		 * and start again.  When I've seen it, it's always been
+		 * the first frag (probably near the end of the page),
+		 * but we check all frags to be safe.
+		 */
+		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+			skb_frag_t *fragp;
+
+			fragp = &skb_shinfo(skb)->frags[frag];
+			if (fragp->size <= 8 && fragp->page_offset & 0x7) {
+				skb_linearize(skb, GFP_ATOMIC);
+				printk(KERN_DEBUG "%s: unaligned tiny fragment"
+						"%d of %d, fixed\n",
+						dev->name, frag,
+						skb_shinfo(skb)->nr_frags);
+				goto linear;
+			}
+		}
+
+		/* first frag which is skb header */
+		pkt_info.byte_cnt = skb_headlen(skb);
+		pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
+							skb_headlen(skb),
+							DMA_TO_DEVICE);
+		pkt_info.l4i_chk = 0;
+		pkt_info.return_info = 0;
+		pkt_info.cmd_sts = ETH_TX_FIRST_DESC;
+
+		if (skb->ip_summed == CHECKSUM_HW) {
+			ipheader = skb->nh.iph->ihl << 11;
+			pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
+					ETH_GEN_IP_V_4_CHECKSUM | ipheader;
+			/* CPU already calculated pseudo header checksum. */
+			if (skb->nh.iph->protocol == IPPROTO_UDP) {
+				pkt_info.cmd_sts |= ETH_UDP_FRAME;
+				pkt_info.l4i_chk = skb->h.uh->check;
+			} else if (skb->nh.iph->protocol == IPPROTO_TCP)
+				pkt_info.l4i_chk = skb->h.th->check;
+			else {
+				printk(KERN_ERR
+					"%s: chksum proto != TCP or UDP\n",
+					dev->name);
+				spin_unlock_irqrestore(&mp->lock, flags);
+				return 1;
+			}
+		}
+
+		status = eth_port_send(mp, &pkt_info);
 		if (status != ETH_OK) {
-	                if ((status == ETH_ERROR))
-        	                printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
-	                if (status == ETH_QUEUE_FULL)
-        	                printk("Error on Queue Full \n");
-                	if (status == ETH_QUEUE_LAST_RESOURCE)
-                        	printk("Tx resource error \n");
+			if ((status == ETH_ERROR))
+				printk(KERN_ERR
+					"%s: Error on transmitting packet\n",
+					dev->name);
+			if (status == ETH_QUEUE_FULL)
+				printk("Error on Queue Full \n");
+			if (status == ETH_QUEUE_LAST_RESOURCE)
+				printk("Tx resource error \n");
 		}
+		stats->tx_bytes += pkt_info.byte_cnt;
+
+		/* Check for the remaining frags */
+		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+			pkt_info.l4i_chk = 0x0000;
+			pkt_info.cmd_sts = 0x00000000;
+
+			/* Last Frag enables interrupt and frees the skb */
+			if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
+				pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
+							ETH_TX_LAST_DESC;
+				pkt_info.return_info = skb;
+				mp->tx_ring_skbs++;
+			} else {
+				pkt_info.return_info = 0;
+			}
+			pkt_info.l4i_chk = 0;
+			pkt_info.byte_cnt = this_frag->size;
 
-                /* Check for the remaining frags */
-                for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
-                        skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-                        pkt_info.l4i_chk = 0x0000;
-                        pkt_info.cmd_sts = 0x00000000;
-
-                        /* Last Frag enables interrupt and frees the skb */
-                        if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
-                                pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
-                                                        ETH_TX_LAST_DESC;
-                                pkt_info.return_info = skb;
-                                mp->tx_ring_skbs++;
-                        }
-                        else {
-                                pkt_info.return_info = 0;
-                        }
-                        pkt_info.byte_cnt = this_frag->size;
-                        if (this_frag->size < 8)
-                                printk("%d : \n", skb_shinfo(skb)->nr_frags);
-
-                        pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page,
-                                        this_frag->page_offset,
-                                        this_frag->size, PCI_DMA_TODEVICE);
+			pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page,
+							this_frag->page_offset,
+							this_frag->size,
+							DMA_TO_DEVICE);
 
-                        status = eth_port_send(mp, &pkt_info);
+			status = eth_port_send(mp, &pkt_info);
 
 			if (status != ETH_OK) {
-	                        if ((status == ETH_ERROR))
-        	                        printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
+				if ((status == ETH_ERROR))
+					printk(KERN_ERR "%s: Error on "
+							"transmitting packet\n",
+							dev->name);
 
-       		                 if (status == ETH_QUEUE_LAST_RESOURCE)
-                	                printk("Tx resource error \n");
+				if (status == ETH_QUEUE_LAST_RESOURCE)
+					printk("Tx resource error \n");
 
-                        	if (status == ETH_QUEUE_FULL)
-                                	printk("Queue is full \n");
+				if (status == ETH_QUEUE_FULL)
+					printk("Queue is full \n");
 			}
-                }
-        }
+			stats->tx_bytes += pkt_info.byte_cnt;
+		}
+	}
+#else
+	pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC |
+							ETH_TX_LAST_DESC;
+	pkt_info.l4i_chk = 0;
+	pkt_info.byte_cnt = skb->len;
+	pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
+								DMA_TO_DEVICE);
+	pkt_info.return_info = skb;
+	mp->tx_ring_skbs++;
+	status = eth_port_send(mp, &pkt_info);
+	if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
+		printk(KERN_ERR "%s: Error on transmitting packet\n",
+								dev->name);
+	stats->tx_bytes += pkt_info.byte_cnt;
 #endif
 
 	/* Check if TX queue can handle another skb. If not, then
 	 * signal higher layers to stop requesting TX
 	 */
-	if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1))
-		/* 
+	if (mp->tx_ring_size <= (mp->tx_ring_skbs + MAX_DESCS_PER_SKB))
+		/*
 		 * Stop getting skb's from upper layers.
 		 * Getting skb's from upper layers will be enabled again after
 		 * packets are released.
@@ -1277,7 +1324,6 @@ static int mv64340_eth_start_xmit(struct
 		netif_stop_queue(dev);
 
 	/* Update statistics and start of transmittion time */
-	stats->tx_bytes += skb->len;
 	stats->tx_packets++;
 	dev->trans_start = jiffies;
 
@@ -1287,214 +1333,302 @@ static int mv64340_eth_start_xmit(struct
 }
 
 /*
- * mv64340_eth_get_stats
+ * mv643xx_eth_get_stats
  *
  * Returns a pointer to the interface statistics.
  *
- * Input : dev - a pointer to the required interface
+ * Input :	dev - a pointer to the required interface
  *
- * Output : a pointer to the interface's statistics
+ * Output :	a pointer to the interface's statistics
  */
 
-static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev)
+static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct mv643xx_private *mp = netdev_priv(dev);
 
 	return &mp->stats;
 }
 
 /*/
- * mv64340_eth_init
- *								       
- * First function called after registering the network device. 
- * It's purpose is to initialize the device as an ethernet device, 
- * fill the structure that was given in registration with pointers
- * to functions, and setting the MAC address of the interface
+ * mv643xx_eth_probe
  *
- * Input : number of port to initialize
- * Output : -ENONMEM if failed , 0 if success
- */
-static struct net_device *mv64340_eth_init(int port_num)
-{
-	struct mv64340_private *mp;
+ * First function called after registering the network device.
+ * It's purpose is to initialize the device as an ethernet device,
+ * fill the ethernet device structure with pointers * to functions,
+ * and set the MAC address of the interface
+ *
+ * Input :	struct device *
+ * Output :	-ENOMEM if failed , 0 if success
+ */
+static int mv643xx_eth_probe(struct device *ddev)
+{
+	struct platform_device *pdev = to_platform_device(ddev);
+	struct mv643xx_eth_platform_data *pd;
+	int port_num = pdev->id;
+	struct mv643xx_private *mp;
 	struct net_device *dev;
+	u8 *p;
+	struct resource *res;
 	int err;
 
-	dev = alloc_etherdev(sizeof(struct mv64340_private));
+	dev = alloc_etherdev(sizeof(struct mv643xx_private));
 	if (!dev)
-		return NULL;
+		return -ENOMEM;
+
+	dev_set_drvdata(ddev, dev);
 
 	mp = netdev_priv(dev);
 
-	dev->irq = ETH_PORT0_IRQ_NUM + port_num;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	BUG_ON(!res);
+	dev->irq = res->start;
 
-	dev->open = mv64340_eth_open;
-	dev->stop = mv64340_eth_stop;
-	dev->hard_start_xmit = mv64340_eth_start_xmit;
-	dev->get_stats = mv64340_eth_get_stats;
-	dev->set_mac_address = mv64340_eth_set_mac_address;
-	dev->set_multicast_list = mv64340_eth_set_rx_mode;
+	mp->port_num = port_num;
+
+	dev->open = mv643xx_eth_open;
+	dev->stop = mv643xx_eth_stop;
+	dev->hard_start_xmit = mv643xx_eth_start_xmit;
+	dev->get_stats = mv643xx_eth_get_stats;
+	dev->set_mac_address = mv643xx_eth_set_mac_address;
+	dev->set_multicast_list = mv643xx_eth_set_rx_mode;
 
 	/* No need to Tx Timeout */
-	dev->tx_timeout = mv64340_eth_tx_timeout;
-#ifdef MV64340_NAPI
-        dev->poll = mv64340_poll;
-        dev->weight = 64;
+	dev->tx_timeout = mv643xx_eth_tx_timeout;
+#ifdef MV643XX_NAPI
+	dev->poll = mv643xx_poll;
+	dev->weight = 64;
 #endif
 
 	dev->watchdog_timeo = 2 * HZ;
-	dev->tx_queue_len = MV64340_TX_QUEUE_SIZE;
+	dev->tx_queue_len = mp->tx_ring_size;
 	dev->base_addr = 0;
-	dev->change_mtu = mv64340_eth_change_mtu;
+	dev->change_mtu = mv643xx_eth_change_mtu;
+	SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops);
 
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
 #ifdef MAX_SKB_FRAGS
-#ifndef CONFIG_JAGUAR_DMALOW
-        /*
-         * Zero copy can only work if we use Discovery II memory. Else, we will
-         * have to map the buffers to ISA memory which is only 16 MB
-         */
-        dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM;
-#endif
+	/*
+	 * Zero copy can only work if we use Discovery II memory. Else, we will
+	 * have to map the buffers to ISA memory which is only 16 MB
+	 */
+	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM;
 #endif
 #endif
 
-	mp->port_num = port_num;
-
 	/* Configure the timeout task */
-        INIT_WORK(&mp->tx_timeout_task,
-                  (void (*)(void *))mv64340_eth_tx_timeout_task, dev);
+	INIT_WORK(&mp->tx_timeout_task,
+			(void (*)(void *))mv643xx_eth_tx_timeout_task, dev);
 
 	spin_lock_init(&mp->lock);
 
-	/* set MAC addresses */
-	memcpy(dev->dev_addr, prom_mac_addr_base, 6);
-	dev->dev_addr[5] += port_num;
+	/* set default config values */
+	eth_port_uc_addr_get(dev, dev->dev_addr);
+	mp->port_config = MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE;
+	mp->port_config_extend = MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE;
+	mp->port_sdma_config = MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE;
+	mp->port_serial_control = MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE;
+	mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
+	mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
+
+	pd = pdev->dev.platform_data;
+	if (pd) {
+		if (pd->mac_addr != NULL)
+			memcpy(dev->dev_addr, pd->mac_addr, 6);
+
+		if (pd->phy_addr || pd->force_phy_addr)
+			ethernet_phy_set(port_num, pd->phy_addr);
+
+		if (pd->port_config || pd->force_port_config)
+			mp->port_config = pd->port_config;
+
+		if (pd->port_config_extend || pd->force_port_config_extend)
+			mp->port_config_extend = pd->port_config_extend;
+
+		if (pd->port_sdma_config || pd->force_port_sdma_config)
+			mp->port_sdma_config = pd->port_sdma_config;
+
+		if (pd->port_serial_control || pd->force_port_serial_control)
+			mp->port_serial_control = pd->port_serial_control;
+
+		if (pd->rx_queue_size)
+			mp->rx_ring_size = pd->rx_queue_size;
+
+		if (pd->tx_queue_size)
+			mp->tx_ring_size = pd->tx_queue_size;
+
+		if (pd->tx_sram_size) {
+			mp->tx_sram_size = pd->tx_sram_size;
+			mp->tx_sram_addr = pd->tx_sram_addr;
+		}
+
+		if (pd->rx_sram_size) {
+			mp->rx_sram_size = pd->rx_sram_size;
+			mp->rx_sram_addr = pd->rx_sram_addr;
+		}
+	}
+
+	err = ethernet_phy_detect(port_num);
+	if (err) {
+		pr_debug("MV643xx ethernet port %d: "
+					"No PHY detected at addr %d\n",
+					port_num, ethernet_phy_get(port_num));
+		return err;
+	}
 
 	err = register_netdev(dev);
 	if (err)
-		goto out_free_dev;
+		goto out;
 
-	printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
-		dev->name, port_num,
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	p = dev->dev_addr;
+	printk(KERN_NOTICE
+		"%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+		dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]);
 
 	if (dev->features & NETIF_F_SG)
-		printk("Scatter Gather Enabled  ");
+		printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name);
 
 	if (dev->features & NETIF_F_IP_CSUM)
-		printk("TX TCP/IP Checksumming Supported  \n");
+		printk(KERN_NOTICE "%s: TX TCP/IP Checksumming Supported\n",
+								dev->name);
 
-	printk("RX TCP/UDP Checksum Offload ON, \n");
-	printk("TX and RX Interrupt Coalescing ON \n");
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+	printk(KERN_NOTICE "%s: RX TCP/UDP Checksum Offload ON \n", dev->name);
+#endif
 
-#ifdef MV64340_NAPI
-	printk("RX NAPI Enabled \n");
+#ifdef MV643XX_COAL
+	printk(KERN_NOTICE "%s: TX and RX Interrupt Coalescing ON \n",
+								dev->name);
 #endif
 
-	return dev;
+#ifdef MV643XX_NAPI
+	printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name);
+#endif
 
-out_free_dev:
+	return 0;
+
+out:
 	free_netdev(dev);
 
-	return NULL;
+	return err;
 }
 
-static void mv64340_eth_remove(struct net_device *dev)
+static int mv643xx_eth_remove(struct device *ddev)
 {
-	struct mv64340_private *mp = netdev_priv(dev);
+	struct net_device *dev = dev_get_drvdata(ddev);
 
 	unregister_netdev(dev);
 	flush_scheduled_work();
+
 	free_netdev(dev);
+	dev_set_drvdata(ddev, NULL);
+	return 0;
 }
 
-static struct net_device *mv64340_dev0;
-static struct net_device *mv64340_dev1;
-static struct net_device *mv64340_dev2;
+static int mv643xx_eth_shared_probe(struct device *ddev)
+{
+	struct platform_device *pdev = to_platform_device(ddev);
+	struct resource *res;
+
+	printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENODEV;
+
+	mv643xx_eth_shared_base = ioremap(res->start,
+						MV643XX_ETH_SHARED_REGS_SIZE);
+	if (mv643xx_eth_shared_base == NULL)
+		return -ENOMEM;
+
+	return 0;
+
+}
+
+static int mv643xx_eth_shared_remove(struct device *ddev)
+{
+	iounmap(mv643xx_eth_shared_base);
+	mv643xx_eth_shared_base = NULL;
+
+	return 0;
+}
+
+static struct device_driver mv643xx_eth_driver = {
+	.name = MV643XX_ETH_NAME,
+	.bus = &platform_bus_type,
+	.probe = mv643xx_eth_probe,
+	.remove = mv643xx_eth_remove,
+};
+
+static struct device_driver mv643xx_eth_shared_driver = {
+	.name = MV643XX_ETH_SHARED_NAME,
+	.bus = &platform_bus_type,
+	.probe = mv643xx_eth_shared_probe,
+	.remove = mv643xx_eth_shared_remove,
+};
 
 /*
- * mv64340_init_module
+ * mv643xx_init_module
  *
  * Registers the network drivers into the Linux kernel
  *
- * Input : N/A
+ * Input :	N/A
  *
- * Output : N/A
+ * Output :	N/A
  */
-static int __init mv64340_init_module(void)
+static int __init mv643xx_init_module(void)
 {
-	printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
+	int rc;
 
-#ifdef CONFIG_MV643XX_ETH_0
-	mv64340_dev0 = mv64340_eth_init(0);
-	if (!mv64340_dev0) {
-		printk(KERN_ERR
-		       "Error registering MV-64360 ethernet port 0\n");
-	}
-#endif
-#ifdef CONFIG_MV643XX_ETH_1
-	mv64340_dev1 = mv64340_eth_init(1);
-	if (!mv64340_dev1) {
-		printk(KERN_ERR
-		       "Error registering MV-64360 ethernet port 1\n");
-	}
-#endif
-#ifdef CONFIG_MV643XX_ETH_2
-	mv64340_dev2 = mv64340_eth_init(2);
-	if (!mv64340_dev2) {
-		printk(KERN_ERR
-		       "Error registering MV-64360 ethernet port 2\n");
+	rc = driver_register(&mv643xx_eth_shared_driver);
+	if (!rc) {
+		rc = driver_register(&mv643xx_eth_driver);
+		if (rc)
+			driver_unregister(&mv643xx_eth_shared_driver);
 	}
-#endif
-	return 0;
+	return rc;
 }
 
 /*
- * mv64340_cleanup_module
+ * mv643xx_cleanup_module
  *
  * Registers the network drivers into the Linux kernel
  *
- * Input : N/A
+ * Input :	N/A
  *
- * Output : N/A
+ * Output :	N/A
  */
-static void __exit mv64340_cleanup_module(void)
+static void __exit mv643xx_cleanup_module(void)
 {
-	if (mv64340_dev2)
-		mv64340_eth_remove(mv64340_dev2);
-	if (mv64340_dev1)
-		mv64340_eth_remove(mv64340_dev1);
-	if (mv64340_dev0)
-		mv64340_eth_remove(mv64340_dev0);
+	driver_unregister(&mv643xx_eth_driver);
+	driver_unregister(&mv643xx_eth_shared_driver);
 }
 
-module_init(mv64340_init_module);
-module_exit(mv64340_cleanup_module);
+module_init(mv643xx_init_module);
+module_exit(mv643xx_cleanup_module);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani");
-MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340");
+MODULE_AUTHOR(	"Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani"
+		" and Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX");
 
 /*
- *  The second part is the low level driver of the gigE ethernet ports.
+ * The second part is the low level driver of the gigE ethernet ports.
  */
 
 /*
  * Marvell's Gigabit Ethernet controller low level driver
  *
  * DESCRIPTION:
- *       This file introduce low level API to Marvell's Gigabit Ethernet
+ *	This file introduce low level API to Marvell's Gigabit Ethernet
  *		controller. This Gigabit Ethernet Controller driver API controls
  *		1) Operations (i.e. port init, start, reset etc').
  *		2) Data flow (i.e. port send, receive etc').
  *		Each Gigabit Ethernet port is controlled via
- *              struct mv64340_private.
+ *		struct mv643xx_private.
  *		This struct includes user configuration information as well as
  *		driver internal data needed for its operations.
  *
- *		Supported Features:  
+ *		Supported Features:
  *		- This low level driver is OS independent. Allocating memory for
  *		  the descriptor rings and buffers are not within the scope of
  *		  this driver.
@@ -1511,12 +1645,12 @@ MODULE_DESCRIPTION("Ethernet driver for 
  *		- PHY access and control API.
  *		- Port control register configuration API.
  *		- Full control over Unicast and Multicast MAC configurations.
- *								   
+ *
  *		Operation flow:
  *
  *		Initialization phase
- *		This phase complete the initialization of the the mv64340_private
- *		struct. 
+ *		This phase complete the initialization of the the
+ *		mv643xx_private struct.
  *		User information regarding port configuration has to be set
  *		prior to calling the port initialization routine.
  *
@@ -1525,7 +1659,7 @@ MODULE_DESCRIPTION("Ethernet driver for 
  *		access to DRAM and internal SRAM memory spaces.
  *
  *		Driver ring initialization
- *		Allocating memory for the descriptor rings and buffers is not 
+ *		Allocating memory for the descriptor rings and buffers is not
  *		within the scope of this driver. Thus, the user is required to
  *		allocate memory for the descriptors ring and buffers. Those
  *		memory parameters are used by the Rx and Tx ring initialization
@@ -1533,49 +1667,50 @@ MODULE_DESCRIPTION("Ethernet driver for 
  *		of a ring.
  *		Note: Pay special attention to alignment issues when using
  *		cached descriptors/buffers. In this phase the driver store
- *		information in the mv64340_private struct regarding each queue
+ *		information in the mv643xx_private struct regarding each queue
  *		ring.
  *
- *		Driver start 
+ *		Driver start
  *		This phase prepares the Ethernet port for Rx and Tx activity.
- *		It uses the information stored in the mv64340_private struct to 
+ *		It uses the information stored in the mv643xx_private struct to
  *		initialize the various port registers.
  *
  *		Data flow:
  *		All packet references to/from the driver are done using
- *              struct pkt_info.
- *		This struct is a unified struct used with Rx and Tx operations. 
+ *		struct pkt_info.
+ *		This struct is a unified struct used with Rx and Tx operations.
  *		This way the user is not required to be familiar with neither
  *		Tx nor Rx descriptors structures.
  *		The driver's descriptors rings are management by indexes.
  *		Those indexes controls the ring resources and used to indicate
  *		a SW resource error:
- *		'current' 
- *		This index points to the current available resource for use. For 
- *		example in Rx process this index will point to the descriptor  
- *		that will be passed to the user upon calling the receive routine.
- *		In Tx process, this index will point to the descriptor
+ *		'current'
+ *		This index points to the current available resource for use. For
+ *		example in Rx process this index will point to the descriptor
+ *		that will be passed to the user upon calling the receive
+ *		routine.  In Tx process, this index will point to the descriptor
  *		that will be assigned with the user packet info and transmitted.
- *		'used'    
- *		This index points to the descriptor that need to restore its 
+ *		'used'
+ *		This index points to the descriptor that need to restore its
  *		resources. For example in Rx process, using the Rx buffer return
  *		API will attach the buffer returned in packet info to the
  *		descriptor pointed by 'used'. In Tx process, using the Tx
  *		descriptor return will merely return the user packet info with
- *		the command status of  the transmitted buffer pointed by the
+ *		the command status of the transmitted buffer pointed by the
  *		'used' index. Nevertheless, it is essential to use this routine
  *		to update the 'used' index.
  *		'first'
- *		This index supports Tx Scatter-Gather. It points to the first 
- *		descriptor of a packet assembled of multiple buffers. For example
- *		when in middle of Such packet we have a Tx resource error the 
- *		'curr' index get the value of 'first' to indicate that the ring 
- *		returned to its state before trying to transmit this packet.
+ *		This index supports Tx Scatter-Gather. It points to the first
+ *		descriptor of a packet assembled of multiple buffers. For
+ *		example when in middle of Such packet we have a Tx resource
+ *		error the 'curr' index get the value of 'first' to indicate
+ *		that the ring returned to its state before trying to transmit
+ *		this packet.
  *
  *		Receive operation:
  *		The eth_port_receive API set the packet information struct,
- *		passed by the caller, with received information from the 
- *		'current' SDMA descriptor. 
+ *		passed by the caller, with received information from the
+ *		'current' SDMA descriptor.
  *		It is the user responsibility to return this resource back
  *		to the Rx descriptor ring to enable the reuse of this source.
  *		Return Rx resource is done using the eth_rx_return_buff API.
@@ -1596,27 +1731,21 @@ MODULE_DESCRIPTION("Ethernet driver for 
  *
  *		EXTERNAL INTERFACE
  *
- *       Prior to calling the initialization routine eth_port_init() the user
- *	 must set the following fields under mv64340_private struct:
- *       port_num             User Ethernet port number.
- *       port_mac_addr[6]	    User defined port MAC address.
- *       port_config          User port configuration value.
- *       port_config_extend    User port config extend value.
- *       port_sdma_config      User port SDMA config value.
- *       port_serial_control   User port serial control value.
- *
- *       This driver introduce a set of default values:
- *       PORT_CONFIG_VALUE           Default port configuration value
- *       PORT_CONFIG_EXTEND_VALUE    Default port extend configuration value
- *       PORT_SDMA_CONFIG_VALUE      Default sdma control value
- *       PORT_SERIAL_CONTROL_VALUE   Default port serial control value
+ *	Prior to calling the initialization routine eth_port_init() the user
+ *	must set the following fields under mv643xx_private struct:
+ *	port_num		User Ethernet port number.
+ *	port_mac_addr[6]	User defined port MAC address.
+ *	port_config		User port configuration value.
+ *	port_config_extend	User port config extend value.
+ *	port_sdma_config	User port SDMA config value.
+ *	port_serial_control	User port serial control value.
  *
  *		This driver data flow is done using the struct pkt_info which
- *              is a unified struct for Rx and Tx operations:
+ *		is a unified struct for Rx and Tx operations:
  *
  *		byte_cnt	Tx/Rx descriptor buffer byte count.
  *		l4i_chk		CPU provided TCP Checksum. For Tx operation
- *                              only.
+ *				only.
  *		cmd_sts		Tx/Rx descriptor command status.
  *		buf_ptr		Tx/Rx descriptor buffer pointer.
  *		return_info	Tx/Rx user resource return information.
@@ -1625,70 +1754,44 @@ MODULE_DESCRIPTION("Ethernet driver for 
 /* defines */
 /* SDMA command macros */
 #define ETH_ENABLE_TX_QUEUE(eth_port) \
-	MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1)
-
-#define ETH_DISABLE_TX_QUEUE(eth_port) \
-	MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port),	\
-	         (1 << 8))
-
-#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \
-	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port),	\
-	         (1 << rx_queue))
-
-#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \
-	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port),	\
-	         (1 << (8 + rx_queue)))
-
-#define LINK_UP_TIMEOUT		100000
-#define PHY_BUSY_TIMEOUT	10000000
+	mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1)
 
 /* locals */
 
 /* PHY routines */
 static int ethernet_phy_get(unsigned int eth_port_num);
+static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
 
 /* Ethernet Port routines */
 static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble,
-	int option);
+								int option);
 
 /*
  * eth_port_init - Initialize the Ethernet port driver
  *
  * DESCRIPTION:
- *       This function prepares the ethernet port to start its activity:
- *       1) Completes the ethernet port driver struct initialization toward port
- *           start routine.
- *       2) Resets the device to a quiescent state in case of warm reboot.
- *       3) Enable SDMA access to all four DRAM banks as well as internal SRAM.
- *       4) Clean MAC tables. The reset status of those tables is unknown.
- *       5) Set PHY address. 
- *       Note: Call this routine prior to eth_port_start routine and after
- *       setting user values in the user fields of Ethernet port control
- *       struct.
+ *	This function prepares the ethernet port to start its activity:
+ *	1) Completes the ethernet port driver struct initialization toward port
+ *		start routine.
+ *	2) Resets the device to a quiescent state in case of warm reboot.
+ *	3) Enable SDMA access to all four DRAM banks as well as internal SRAM.
+ *	4) Clean MAC tables. The reset status of those tables is unknown.
+ *	5) Set PHY address.
+ *	Note: Call this routine prior to eth_port_start routine and after
+ *	setting user values in the user fields of Ethernet port control
+ *	struct.
  *
  * INPUT:
- *       struct mv64340_private *mp   Ethernet port control struct
+ *	struct mv643xx_private *mp	Ethernet port control struct
  *
  * OUTPUT:
- *       See description.
+ *	See description.
  *
  * RETURN:
- *       None.
+ *	None.
  */
-static void eth_port_init(struct mv64340_private * mp)
+static void eth_port_init(struct mv643xx_private *mp)
 {
-	mp->port_config = PORT_CONFIG_VALUE;
-	mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE;
-#if defined(__BIG_ENDIAN)
-	mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE;
-#elif defined(__LITTLE_ENDIAN)
-	mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE |
-		ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP;
-#else
-#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined!
-#endif
-	mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE;
-
 	mp->port_rx_queue_command = 0;
 	mp->port_tx_queue_command = 0;
 
@@ -1706,77 +1809,73 @@ static void eth_port_init(struct mv64340
  * eth_port_start - Start the Ethernet port activity.
  *
  * DESCRIPTION:
- *       This routine prepares the Ethernet port for Rx and Tx activity:
- *       1. Initialize Tx and Rx Current Descriptor Pointer for each queue that
- *          has been initialized a descriptor's ring (using
- *          ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx)
- *       2. Initialize and enable the Ethernet configuration port by writing to
- *          the port's configuration and command registers.
- *       3. Initialize and enable the SDMA by writing to the SDMA's 
- *          configuration and command registers.  After completing these steps,
- *          the ethernet port SDMA can starts to perform Rx and Tx activities.
+ *	This routine prepares the Ethernet port for Rx and Tx activity:
+ *	 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that
+ *	    has been initialized a descriptor's ring (using
+ *	    ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx)
+ *	 2. Initialize and enable the Ethernet configuration port by writing to
+ *	    the port's configuration and command registers.
+ *	 3. Initialize and enable the SDMA by writing to the SDMA's
+ *	    configuration and command registers.  After completing these steps,
+ *	    the ethernet port SDMA can starts to perform Rx and Tx activities.
  *
- *       Note: Each Rx and Tx queue descriptor's list must be initialized prior
- *       to calling this function (use ether_init_tx_desc_ring for Tx queues
- *       and ether_init_rx_desc_ring for Rx queues).
+ *	Note: Each Rx and Tx queue descriptor's list must be initialized prior
+ *	to calling this function (use ether_init_tx_desc_ring for Tx queues
+ *	and ether_init_rx_desc_ring for Rx queues).
  *
  * INPUT:
- *       struct mv64340_private 	*mp   Ethernet port control struct
+ *	struct mv643xx_private *mp	Ethernet port control struct
  *
  * OUTPUT:
- *       Ethernet port is ready to receive and transmit.
+ *	Ethernet port is ready to receive and transmit.
  *
  * RETURN:
- *       false if the port PHY is not up.
- *       true otherwise.
+ *	None.
  */
-static int eth_port_start(struct mv64340_private *mp)
+static void eth_port_start(struct mv643xx_private *mp)
 {
-	unsigned int eth_port_num = mp->port_num;
+	unsigned int port_num = mp->port_num;
 	int tx_curr_desc, rx_curr_desc;
-	unsigned int phy_reg_data;
 
 	/* Assignment of Tx CTRP of given queue */
 	tx_curr_desc = mp->tx_curr_desc_q;
-	MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num),
-	         (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc);
+	mv_write(MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port_num),
+		(u32)((struct eth_tx_desc *)mp->tx_desc_dma + tx_curr_desc));
 
 	/* Assignment of Rx CRDP of given queue */
 	rx_curr_desc = mp->rx_curr_desc_q;
-	MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num),
-		 (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc);
+	mv_write(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num),
+		(u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc));
 
 	/* Add the assigned Ethernet address to the port's address table */
-	eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr);
+	eth_port_uc_addr_set(port_num, mp->port_mac_addr);
 
 	/* Assign port configuration and command. */
-	MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num),
-		 mp->port_config);
+	mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config);
+
+	mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num),
+						mp->port_config_extend);
 
-	MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num),
-		 mp->port_config_extend);
 
-	MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num),
-		 mp->port_serial_control);
+	/* Increase the Rx side buffer size if supporting GigE */
+	if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000)
+		mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+			(mp->port_serial_control & 0xfff1ffff) | (0x5 << 17));
+	else
+		mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+						mp->port_serial_control);
 
-	MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num),
-			ETH_SERIAL_PORT_ENABLE);
+	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+		mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)) |
+						MV643XX_ETH_SERIAL_PORT_ENABLE);
 
 	/* Assign port SDMA configuration */
-	MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num),
-		 mp->port_sdma_config);
+	mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num),
+							mp->port_sdma_config);
 
 	/* Enable port Rx. */
-	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num),
-		 mp->port_rx_queue_command);
-
-	/* Check if link is up */
-	eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data);
-
-	if (!(phy_reg_data & 0x20))
-		return 0;
-
-	return 1;
+	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
+						mp->port_rx_queue_command);
 }
 
 /*
@@ -1786,29 +1885,29 @@ static int eth_port_start(struct mv64340
  *		This function Set the port Ethernet MAC address.
  *
  * INPUT:
- *	unsigned int eth_port_num     Port number.
- *	char *        p_addr		Address to be set 
+ *	unsigned int	eth_port_num	Port number.
+ *	char *		p_addr		Address to be set
  *
  * OUTPUT:
- *	Set MAC address low and high registers. also calls eth_port_uc_addr() 
- *       To set the unicast table with the proper information.
+ *	Set MAC address low and high registers. also calls eth_port_uc_addr()
+ *	To set the unicast table with the proper information.
  *
  * RETURN:
  *	N/A.
  *
  */
 static void eth_port_uc_addr_set(unsigned int eth_port_num,
-				 unsigned char *p_addr)
+							unsigned char *p_addr)
 {
 	unsigned int mac_h;
 	unsigned int mac_l;
 
 	mac_l = (p_addr[4] << 8) | (p_addr[5]);
-	mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) |
-	    (p_addr[2] << 8) | (p_addr[3] << 0);
+	mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
+							(p_addr[3] << 0);
 
-	MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
-	MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+	mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
+	mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
 
 	/* Accept frames of this address */
 	eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR);
@@ -1817,29 +1916,64 @@ static void eth_port_uc_addr_set(unsigne
 }
 
 /*
+ * eth_port_uc_addr_get - This function retrieves the port Unicast address
+ * (MAC address) from the ethernet hw registers.
+ *
+ * DESCRIPTION:
+ *		This function retrieves the port Ethernet MAC address.
+ *
+ * INPUT:
+ *	unsigned int	eth_port_num	Port number.
+ *	char		*MacAddr	pointer where the MAC address is stored
+ *
+ * OUTPUT:
+ *	Copy the MAC address to the location pointed to by MacAddr
+ *
+ * RETURN:
+ *	N/A.
+ *
+ */
+static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+	unsigned int mac_h;
+	unsigned int mac_l;
+
+	mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num));
+	mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num));
+
+	p_addr[0] = (mac_h >> 24) & 0xff;
+	p_addr[1] = (mac_h >> 16) & 0xff;
+	p_addr[2] = (mac_h >> 8) & 0xff;
+	p_addr[3] = mac_h & 0xff;
+	p_addr[4] = (mac_l >> 8) & 0xff;
+	p_addr[5] = mac_l & 0xff;
+}
+
+/*
  * eth_port_uc_addr - This function Set the port unicast address table
  *
  * DESCRIPTION:
- *	This function locates the proper entry in the Unicast table for the 
- *	specified MAC nibble and sets its properties according to function 
+ *	This function locates the proper entry in the Unicast table for the
+ *	specified MAC nibble and sets its properties according to function
  *	parameters.
  *
  * INPUT:
- *	unsigned int 	eth_port_num      Port number.
- *	unsigned char uc_nibble		Unicast MAC Address last nibble. 
- *	int 			option      0 = Add, 1 = remove address.
+ *	unsigned int	eth_port_num	Port number.
+ *	unsigned char	uc_nibble	Unicast MAC Address last nibble.
+ *	int 		option		0 = Add, 1 = remove address.
  *
  * OUTPUT:
  *	This function add/removes MAC addresses from the port unicast address
- *	table. 
+ *	table.
  *
  * RETURN:
  *	true is output succeeded.
  *	false if option parameter is invalid.
  *
  */
-static int eth_port_uc_addr(unsigned int eth_port_num,
-	unsigned char uc_nibble, int option)
+static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble,
+								int option)
 {
 	unsigned int unicast_reg;
 	unsigned int tbl_offset;
@@ -1852,29 +1986,26 @@ static int eth_port_uc_addr(unsigned int
 
 	switch (option) {
 	case REJECT_MAC_ADDR:
-		/* Clear accepts frame bit at specified unicast DA table entry */
-		unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
-				  (eth_port_num) + tbl_offset));
+		/* Clear accepts frame bit at given unicast DA table entry */
+		unicast_reg = mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+						(eth_port_num) + tbl_offset));
 
 		unicast_reg &= (0x0E << (8 * reg_offset));
 
-		MV_WRITE(
-			 (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
-			  (eth_port_num) + tbl_offset), unicast_reg);
+		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+				(eth_port_num) + tbl_offset), unicast_reg);
 		break;
 
 	case ACCEPT_MAC_ADDR:
 		/* Set accepts frame bit at unicast DA filter table entry */
 		unicast_reg =
-		    MV_READ(
-				 (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
-				  (eth_port_num) + tbl_offset));
+			mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+						(eth_port_num) + tbl_offset));
 
 		unicast_reg |= (0x01 << (8 * reg_offset));
 
-		MV_WRITE(
-			 (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
-			  (eth_port_num) + tbl_offset), unicast_reg);
+		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+				(eth_port_num) + tbl_offset), unicast_reg);
 
 		break;
 
@@ -1889,17 +2020,17 @@ static int eth_port_uc_addr(unsigned int
  * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables
  *
  * DESCRIPTION:
- *       Go through all the DA filter tables (Unicast, Special Multicast &
- *       Other Multicast) and set each entry to 0.
+ *	Go through all the DA filter tables (Unicast, Special Multicast &
+ *	Other Multicast) and set each entry to 0.
  *
  * INPUT:
- *	unsigned int    eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       Multicast and Unicast packets are rejected.
+ *	Multicast and Unicast packets are rejected.
  *
  * RETURN:
- *       None.
+ *	None.
  */
 static void eth_port_init_mac_tables(unsigned int eth_port_num)
 {
@@ -1907,18 +2038,16 @@ static void eth_port_init_mac_tables(uns
 
 	/* Clear DA filter unicast table (Ex_dFUT) */
 	for (table_index = 0; table_index <= 0xC; table_index += 4)
-		MV_WRITE(
-			 (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
-			  (eth_port_num) + table_index), 0);
+		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+					(eth_port_num) + table_index), 0);
 
 	for (table_index = 0; table_index <= 0xFC; table_index += 4) {
 		/* Clear DA filter special multicast table (Ex_dFSMT) */
-		MV_WRITE(
-			 (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
-			  (eth_port_num) + table_index), 0);
+		mv_write((MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
+					(eth_port_num) + table_index), 0);
 		/* Clear DA filter other multicast table (Ex_dFOMT) */
-		MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE
-			  (eth_port_num) + table_index), 0);
+		mv_write((MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE
+					(eth_port_num) + table_index), 0);
 	}
 }
 
@@ -1926,17 +2055,17 @@ static void eth_port_init_mac_tables(uns
  * eth_clear_mib_counters - Clear all MIB counters
  *
  * DESCRIPTION:
- *       This function clears all MIB counters of a specific ethernet port.
- *       A read from the MIB counter will reset the counter.
+ *	This function clears all MIB counters of a specific ethernet port.
+ *	A read from the MIB counter will reset the counter.
  *
  * INPUT:
- *	unsigned int    eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       After reading all MIB counters, the counters resets.
+ *	After reading all MIB counters, the counters resets.
  *
  * RETURN:
- *       MIB counter value.
+ *	MIB counter value.
  *
  */
 static void eth_clear_mib_counters(unsigned int eth_port_num)
@@ -1944,72 +2073,155 @@ static void eth_clear_mib_counters(unsig
 	int i;
 
 	/* Perform dummy reads from MIB counters */
-	for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4)
-		MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i);
+	for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION;
+									i += 4)
+		mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(eth_port_num) + i);
+}
+
+static inline u32 read_mib(struct mv643xx_private *mp, int offset)
+{
+	return mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(mp->port_num) + offset);
+}
+
+static void eth_update_mib_counters(struct mv643xx_private *mp)
+{
+	struct mv643xx_mib_counters *p = &mp->mib_counters;
+	int offset;
+
+	p->good_octets_received +=
+		read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_LOW);
+	p->good_octets_received +=
+		(u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH) << 32;
+
+	for (offset = ETH_MIB_BAD_OCTETS_RECEIVED;
+			offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS;
+			offset += 4)
+		*(u32 *)((char *)p + offset) = read_mib(mp, offset);
+
+	p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW);
+	p->good_octets_sent +=
+		(u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_HIGH) << 32;
+
+	for (offset = ETH_MIB_GOOD_FRAMES_SENT;
+			offset <= ETH_MIB_LATE_COLLISION;
+			offset += 4)
+		*(u32 *)((char *)p + offset) = read_mib(mp, offset);
 }
 
+/*
+ * ethernet_phy_detect - Detect whether a phy is present
+ *
+ * DESCRIPTION:
+ *	This function tests whether there is a PHY present on
+ *	the specified port.
+ *
+ * INPUT:
+ *	unsigned int	eth_port_num	Ethernet Port number.
+ *
+ * OUTPUT:
+ *	None
+ *
+ * RETURN:
+ *	0 on success
+ *	-ENODEV on failure
+ *
+ */
+static int ethernet_phy_detect(unsigned int port_num)
+{
+	unsigned int phy_reg_data0;
+	int auto_neg;
+
+	eth_port_read_smi_reg(port_num, 0, &phy_reg_data0);
+	auto_neg = phy_reg_data0 & 0x1000;
+	phy_reg_data0 ^= 0x1000;	/* invert auto_neg */
+	eth_port_write_smi_reg(port_num, 0, phy_reg_data0);
+
+	eth_port_read_smi_reg(port_num, 0, &phy_reg_data0);
+	if ((phy_reg_data0 & 0x1000) == auto_neg)
+		return -ENODEV;				/* change didn't take */
+
+	phy_reg_data0 ^= 0x1000;
+	eth_port_write_smi_reg(port_num, 0, phy_reg_data0);
+	return 0;
+}
 
 /*
  * ethernet_phy_get - Get the ethernet port PHY address.
  *
  * DESCRIPTION:
- *       This routine returns the given ethernet port PHY address.
+ *	This routine returns the given ethernet port PHY address.
  *
  * INPUT:
- *		unsigned int   eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       None.
+ *	None.
  *
  * RETURN:
- *       PHY address.
+ *	PHY address.
  *
  */
 static int ethernet_phy_get(unsigned int eth_port_num)
 {
 	unsigned int reg_data;
 
-	reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG);
+	reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG);
 
 	return ((reg_data >> (5 * eth_port_num)) & 0x1f);
 }
 
 /*
+ * ethernet_phy_set - Set the ethernet port PHY address.
+ *
+ * DESCRIPTION:
+ *	This routine sets the given ethernet port PHY address.
+ *
+ * INPUT:
+ *	unsigned int	eth_port_num	Ethernet Port number.
+ *	int		phy_addr	PHY address.
+ *
+ * OUTPUT:
+ *	None.
+ *
+ * RETURN:
+ *	None.
+ *
+ */
+static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr)
+{
+	u32 reg_data;
+	int addr_shift = 5 * eth_port_num;
+
+	reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG);
+	reg_data &= ~(0x1f << addr_shift);
+	reg_data |= (phy_addr & 0x1f) << addr_shift;
+	mv_write(MV643XX_ETH_PHY_ADDR_REG, reg_data);
+}
+
+/*
  * ethernet_phy_reset - Reset Ethernet port PHY.
  *
  * DESCRIPTION:
- *       This routine utilize the SMI interface to reset the ethernet port PHY.
- *       The routine waits until the link is up again or link up is timeout.
+ *	This routine utilizes the SMI interface to reset the ethernet port PHY.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       The ethernet port PHY renew its link.
+ *	The PHY is reset.
  *
  * RETURN:
- *       None.
+ *	None.
  *
  */
-static int ethernet_phy_reset(unsigned int eth_port_num)
+static void ethernet_phy_reset(unsigned int eth_port_num)
 {
-	unsigned int time_out = 50;
 	unsigned int phy_reg_data;
 
 	/* Reset the PHY */
 	eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data);
 	phy_reg_data |= 0x8000;	/* Set bit 15 to reset the PHY */
 	eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data);
-
-	/* Poll on the PHY LINK */
-	do {
-		eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data);
-
-		if (time_out-- == 0)
-			return 0;
-	} while (!(phy_reg_data & 0x20));
-
-	return 1;
 }
 
 /*
@@ -2017,381 +2229,358 @@ static int ethernet_phy_reset(unsigned i
  *
  * DESCRIPTION:
  * 	This routine resets the chip by aborting any SDMA engine activity and
- *      clearing the MIB counters. The Receiver and the Transmit unit are in 
- *      idle state after this command is performed and the port is disabled.
+ *	clearing the MIB counters. The Receiver and the Transmit unit are in
+ *	idle state after this command is performed and the port is disabled.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       Channel activity is halted.
+ *	Channel activity is halted.
  *
  * RETURN:
- *       None.
+ *	None.
  *
  */
-static void eth_port_reset(unsigned int eth_port_num)
+static void eth_port_reset(unsigned int port_num)
 {
 	unsigned int reg_data;
 
 	/* Stop Tx port activity. Check port Tx activity. */
-	reg_data =
-	    MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num));
+	reg_data = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num));
 
 	if (reg_data & 0xFF) {
 		/* Issue stop command for active channels only */
-		MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG
-			 (eth_port_num), (reg_data << 8));
+		mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
+							(reg_data << 8));
 
 		/* Wait for all Tx activity to terminate. */
-		do {
-			/* Check port cause register that all Tx queues are stopped */
-			reg_data =
-			    MV_READ
-			    (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG
-			     (eth_port_num));
-		}
-		while (reg_data & 0xFF);
+		/* Check port cause register that all Tx queues are stopped */
+		while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
+									& 0xFF)
+			udelay(10);
 	}
 
 	/* Stop Rx port activity. Check port Rx activity. */
-	reg_data =
-	    MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
-			 (eth_port_num));
+	reg_data = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num));
 
 	if (reg_data & 0xFF) {
 		/* Issue stop command for active channels only */
-		MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
-			 (eth_port_num), (reg_data << 8));
+		mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
+							(reg_data << 8));
 
 		/* Wait for all Rx activity to terminate. */
-		do {
-			/* Check port cause register that all Rx queues are stopped */
-			reg_data =
-			    MV_READ
-			    (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
-			     (eth_port_num));
-		}
-		while (reg_data & 0xFF);
+		/* Check port cause register that all Rx queues are stopped */
+		while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
+									& 0xFF)
+			udelay(10);
 	}
 
-
 	/* Clear all MIB counters */
-	eth_clear_mib_counters(eth_port_num);
+	eth_clear_mib_counters(port_num);
 
 	/* Reset the Enable bit in the Configuration Register */
-	reg_data =
-	    MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num));
-	reg_data &= ~ETH_SERIAL_PORT_ENABLE;
-	MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data);
-
-	return;
+	reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
+	reg_data &= ~MV643XX_ETH_SERIAL_PORT_ENABLE;
+	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
 }
 
 /*
  * ethernet_set_config_reg - Set specified bits in configuration register.
  *
  * DESCRIPTION:
- *       This function sets specified bits in the given ethernet 
- *       configuration register. 
+ *	This function sets specified bits in the given ethernet
+ *	configuration register.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
- *      unsigned int    value   32 bit value.
+ *	unsigned int	eth_port_num	Ethernet Port number.
+ *	unsigned int	value		32 bit value.
  *
  * OUTPUT:
- *      The set bits in the value parameter are set in the configuration 
- *      register.
+ *	The set bits in the value parameter are set in the configuration
+ *	register.
  *
  * RETURN:
- *      None.
+ *	None.
  *
  */
 static void ethernet_set_config_reg(unsigned int eth_port_num,
-				    unsigned int value)
+							unsigned int value)
 {
 	unsigned int eth_config_reg;
 
-	eth_config_reg =
-	    MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num));
+	eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num));
 	eth_config_reg |= value;
-	MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num),
-		 eth_config_reg);
+	mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg);
+}
+
+static int eth_port_autoneg_supported(unsigned int eth_port_num)
+{
+	unsigned int phy_reg_data0;
+
+	eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data0);
+
+	return phy_reg_data0 & 0x1000;
+}
+
+static int eth_port_link_is_up(unsigned int eth_port_num)
+{
+	unsigned int phy_reg_data1;
+
+	eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data1);
+
+	if (eth_port_autoneg_supported(eth_port_num)) {
+		if (phy_reg_data1 & 0x20)	/* auto-neg complete */
+			return 1;
+	} else if (phy_reg_data1 & 0x4)		/* link up */
+		return 1;
+
+	return 0;
 }
 
 /*
  * ethernet_get_config_reg - Get the port configuration register
  *
  * DESCRIPTION:
- *       This function returns the configuration register value of the given 
- *       ethernet port.
+ *	This function returns the configuration register value of the given
+ *	ethernet port.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
+ *	unsigned int	eth_port_num	Ethernet Port number.
  *
  * OUTPUT:
- *       None.
+ *	None.
  *
  * RETURN:
- *       Port configuration register value.
+ *	Port configuration register value.
  */
 static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
 {
 	unsigned int eth_config_reg;
 
-	eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG
-				      (eth_port_num));
+	eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG
+								(eth_port_num));
 	return eth_config_reg;
 }
 
-
 /*
  * eth_port_read_smi_reg - Read PHY registers
  *
  * DESCRIPTION:
- *       This routine utilize the SMI interface to interact with the PHY in 
- *       order to perform PHY register read.
+ *	This routine utilize the SMI interface to interact with the PHY in
+ *	order to perform PHY register read.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
- *       unsigned int   phy_reg   PHY register address offset.
- *       unsigned int   *value   Register value buffer.
+ *	unsigned int	port_num	Ethernet Port number.
+ *	unsigned int	phy_reg		PHY register address offset.
+ *	unsigned int	*value		Register value buffer.
  *
  * OUTPUT:
- *       Write the value of a specified PHY register into given buffer.
+ *	Write the value of a specified PHY register into given buffer.
  *
  * RETURN:
- *       false if the PHY is busy or read data is not in valid state.
- *       true otherwise.
+ *	false if the PHY is busy or read data is not in valid state.
+ *	true otherwise.
  *
  */
-static int eth_port_read_smi_reg(unsigned int eth_port_num,
-	unsigned int phy_reg, unsigned int *value)
+static void eth_port_read_smi_reg(unsigned int port_num,
+				unsigned int phy_reg, unsigned int *value)
 {
-	int phy_addr = ethernet_phy_get(eth_port_num);
-	unsigned int time_out = PHY_BUSY_TIMEOUT;
-	unsigned int reg_value;
-
-	/* first check that it is not busy */
-	do {
-		reg_value = MV_READ(MV64340_ETH_SMI_REG);
-		if (time_out-- == 0)
-			return 0;
-	} while (reg_value & ETH_SMI_BUSY);
-
-	/* not busy */
-
-	MV_WRITE(MV64340_ETH_SMI_REG,
-		 (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ);
-
-	time_out = PHY_BUSY_TIMEOUT;	/* initialize the time out var again */
+	int phy_addr = ethernet_phy_get(port_num);
+	unsigned long flags;
+	int i;
 
-	do {
-		reg_value = MV_READ(MV64340_ETH_SMI_REG);
-		if (time_out-- == 0)
-			return 0;
-	} while (reg_value & ETH_SMI_READ_VALID);
+	/* the SMI register is a shared resource */
+	spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
 
-	/* Wait for the data to update in the SMI register */
-	for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++);
+	/* wait for the SMI register to become available */
+	for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk("mv643xx PHY busy timeout, port %d\n", port_num);
+			goto out;
+		}
+		udelay(PHY_WAIT_MICRO_SECONDS);
+	}
 
-	reg_value = MV_READ(MV64340_ETH_SMI_REG);
+	mv_write(MV643XX_ETH_SMI_REG,
+		(phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ);
 
-	*value = reg_value & 0xffff;
+	/* now wait for the data to be valid */
+	for (i = 0; !(mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_READ_VALID); i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk("mv643xx PHY read timeout, port %d\n", port_num);
+			goto out;
+		}
+		udelay(PHY_WAIT_MICRO_SECONDS);
+	}
 
-	return 1;
+	*value = mv_read(MV643XX_ETH_SMI_REG) & 0xffff;
+out:
+	spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
 }
 
 /*
  * eth_port_write_smi_reg - Write to PHY registers
  *
  * DESCRIPTION:
- *       This routine utilize the SMI interface to interact with the PHY in 
- *       order to perform writes to PHY registers.
+ *	This routine utilize the SMI interface to interact with the PHY in
+ *	order to perform writes to PHY registers.
  *
  * INPUT:
- *	unsigned int   eth_port_num   Ethernet Port number.
- *      unsigned int   phy_reg   PHY register address offset.
- *      unsigned int    value   Register value.
+ *	unsigned int	eth_port_num	Ethernet Port number.
+ *	unsigned int	phy_reg		PHY register address offset.
+ *	unsigned int	value		Register value.
  *
  * OUTPUT:
- *      Write the given value to the specified PHY register.
+ *	Write the given value to the specified PHY register.
  *
  * RETURN:
- *      false if the PHY is busy.
- *      true otherwise.
+ *	false if the PHY is busy.
+ *	true otherwise.
  *
  */
-static int eth_port_write_smi_reg(unsigned int eth_port_num,
-	unsigned int phy_reg, unsigned int value)
+static void eth_port_write_smi_reg(unsigned int eth_port_num,
+				   unsigned int phy_reg, unsigned int value)
 {
-	unsigned int time_out = PHY_BUSY_TIMEOUT;
-	unsigned int reg_value;
 	int phy_addr;
+	int i;
+	unsigned long flags;
 
 	phy_addr = ethernet_phy_get(eth_port_num);
 
-	/* first check that it is not busy */
-	do {
-		reg_value = MV_READ(MV64340_ETH_SMI_REG);
-		if (time_out-- == 0)
-			return 0;
-	} while (reg_value & ETH_SMI_BUSY);
-
-	/* not busy */
-	MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
-		 ETH_SMI_OPCODE_WRITE | (value & 0xffff));
+	/* the SMI register is a shared resource */
+	spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
 
-	return 1;
+	/* wait for the SMI register to become available */
+	for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk("mv643xx PHY busy timeout, port %d\n",
+								eth_port_num);
+			goto out;
+		}
+		udelay(PHY_WAIT_MICRO_SECONDS);
+	}
+
+	mv_write(MV643XX_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
+				ETH_SMI_OPCODE_WRITE | (value & 0xffff));
+out:
+	spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
 }
 
 /*
  * eth_port_send - Send an Ethernet packet
  *
  * DESCRIPTION:
- *	This routine send a given packet described by p_pktinfo parameter. It 
- *      supports transmitting of a packet spaned over multiple buffers. The 
- *      routine updates 'curr' and 'first' indexes according to the packet 
- *      segment passed to the routine. In case the packet segment is first, 
- *      the 'first' index is update. In any case, the 'curr' index is updated. 
- *      If the routine get into Tx resource error it assigns 'curr' index as 
- *      'first'. This way the function can abort Tx process of multiple 
- *      descriptors per packet.
+ *	This routine send a given packet described by p_pktinfo parameter. It
+ *	supports transmitting of a packet spaned over multiple buffers. The
+ *	routine updates 'curr' and 'first' indexes according to the packet
+ *	segment passed to the routine. In case the packet segment is first,
+ *	the 'first' index is update. In any case, the 'curr' index is updated.
+ *	If the routine get into Tx resource error it assigns 'curr' index as
+ *	'first'. This way the function can abort Tx process of multiple
+ *	descriptors per packet.
  *
  * INPUT:
- *	struct mv64340_private   *mp   Ethernet Port Control srtuct. 
- *	struct pkt_info        *p_pkt_info       User packet buffer.
+ *	struct mv643xx_private	*mp		Ethernet Port Control srtuct.
+ *	struct pkt_info		*p_pkt_info	User packet buffer.
  *
  * OUTPUT:
- *	Tx ring 'curr' and 'first' indexes are updated. 
+ *	Tx ring 'curr' and 'first' indexes are updated.
  *
  * RETURN:
- *      ETH_QUEUE_FULL in case of Tx resource error.
+ *	ETH_QUEUE_FULL in case of Tx resource error.
  *	ETH_ERROR in case the routine can not access Tx desc ring.
  *	ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource.
- *      ETH_OK otherwise.
+ *	ETH_OK otherwise.
  *
  */
-#ifdef  MV64340_CHECKSUM_OFFLOAD_TX
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
 /*
  * Modified to include the first descriptor pointer in case of SG
  */
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp,
-                                         struct pkt_info * p_pkt_info)
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
+					 struct pkt_info *p_pkt_info)
 {
 	int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc;
-	volatile struct eth_tx_desc *current_descriptor;
-	volatile struct eth_tx_desc *first_descriptor;
-	u32 command_status, first_chip_ptr;
+	struct eth_tx_desc *current_descriptor;
+	struct eth_tx_desc *first_descriptor;
+	u32 command;
 
 	/* Do not process Tx ring in case of Tx ring resource error */
 	if (mp->tx_resource_err)
 		return ETH_QUEUE_FULL;
 
+	/*
+	 * The hardware requires that each buffer that is <= 8 bytes
+	 * in length must be aligned on an 8 byte boundary.
+	 */
+	if (p_pkt_info->byte_cnt <= 8 && p_pkt_info->buf_ptr & 0x7) {
+		printk(KERN_ERR
+			"mv643xx_eth port %d: packet size <= 8 problem\n",
+			mp->port_num);
+		return ETH_ERROR;
+	}
+
 	/* Get the Tx Desc ring indexes */
 	tx_desc_curr = mp->tx_curr_desc_q;
 	tx_desc_used = mp->tx_used_desc_q;
 
 	current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-	if (current_descriptor == NULL)
-		return ETH_ERROR;
 
-	tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE;
-	command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
+	tx_next_desc = (tx_desc_curr + 1) % mp->tx_ring_size;
+
+	current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+	current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+	current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
+	mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
 
-	if (command_status & ETH_TX_FIRST_DESC) {
+	command = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC |
+							ETH_BUFFER_OWNED_BY_DMA;
+	if (command & ETH_TX_FIRST_DESC) {
 		tx_first_desc = tx_desc_curr;
 		mp->tx_first_desc_q = tx_first_desc;
+		first_descriptor = current_descriptor;
+		mp->tx_first_command = command;
+	} else {
+		tx_first_desc = mp->tx_first_desc_q;
+		first_descriptor = &mp->p_tx_desc_area[tx_first_desc];
+		BUG_ON(first_descriptor == NULL);
+		current_descriptor->cmd_sts = command;
+	}
 
-                /* fill first descriptor */
-                first_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-                first_descriptor->l4i_chk = p_pkt_info->l4i_chk;
-                first_descriptor->cmd_sts = command_status;
-                first_descriptor->byte_cnt = p_pkt_info->byte_cnt;
-                first_descriptor->buf_ptr = p_pkt_info->buf_ptr;
-                first_descriptor->next_desc_ptr = mp->tx_desc_dma +
-			tx_next_desc * sizeof(struct eth_tx_desc);
+	if (command & ETH_TX_LAST_DESC) {
 		wmb();
-        } else {
-                tx_first_desc = mp->tx_first_desc_q;
-                first_descriptor = &mp->p_tx_desc_area[tx_first_desc];
-                if (first_descriptor == NULL) {
-                        printk("First desc is NULL !!\n");
-                        return ETH_ERROR;
-                }
-                if (command_status & ETH_TX_LAST_DESC)
-                        current_descriptor->next_desc_ptr = 0x00000000;
-                else {
-                        command_status |= ETH_BUFFER_OWNED_BY_DMA;
-                        current_descriptor->next_desc_ptr = mp->tx_desc_dma +
-				tx_next_desc * sizeof(struct eth_tx_desc);
-                }
-        }
-
-        if (p_pkt_info->byte_cnt < 8) {
-                printk(" < 8 problem \n");
-                return ETH_ERROR;
-        }
-
-        current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
-        current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
-        current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
-        current_descriptor->cmd_sts = command_status;
-
-        mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info;
-
-        wmb();
-
-        /* Set last desc with DMA ownership and interrupt enable. */
-        if (command_status & ETH_TX_LAST_DESC) {
-                current_descriptor->cmd_sts = command_status |
-                                        ETH_TX_ENABLE_INTERRUPT |
-                                        ETH_BUFFER_OWNED_BY_DMA;
+		first_descriptor->cmd_sts = mp->tx_first_command;
 
-		if (!(command_status & ETH_TX_FIRST_DESC))
-			first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA;
 		wmb();
-
-		first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num));
-
-		/* Apply send command */
-		if (first_chip_ptr == 0x00000000)
-			MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc);
-
-                ETH_ENABLE_TX_QUEUE(mp->port_num);
+		ETH_ENABLE_TX_QUEUE(mp->port_num);
 
 		/*
 		 * Finish Tx packet. Update first desc in case of Tx resource
 		 * error */
-                tx_first_desc = tx_next_desc;
-                mp->tx_first_desc_q = tx_first_desc;
-	} else {
-		if (! (command_status & ETH_TX_FIRST_DESC) ) {
-			current_descriptor->cmd_sts = command_status;
-			wmb();
-		}
+		tx_first_desc = tx_next_desc;
+		mp->tx_first_desc_q = tx_first_desc;
 	}
 
-        /* Check for ring index overlap in the Tx desc ring */
-        if (tx_next_desc == tx_desc_used) {
-                mp->tx_resource_err = 1;
-                mp->tx_curr_desc_q = tx_first_desc;
+	/* Check for ring index overlap in the Tx desc ring */
+	if (tx_next_desc == tx_desc_used) {
+		mp->tx_resource_err = 1;
+		mp->tx_curr_desc_q = tx_first_desc;
 
-                return ETH_QUEUE_LAST_RESOURCE;
+		return ETH_QUEUE_LAST_RESOURCE;
 	}
 
-        mp->tx_curr_desc_q = tx_next_desc;
-        wmb();
+	mp->tx_curr_desc_q = tx_next_desc;
 
-        return ETH_OK;
+	return ETH_OK;
 }
 #else
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp,
-					 struct pkt_info * p_pkt_info)
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
+					 struct pkt_info *p_pkt_info)
 {
 	int tx_desc_curr;
 	int tx_desc_used;
-	volatile struct eth_tx_desc* current_descriptor;
+	struct eth_tx_desc *current_descriptor;
 	unsigned int command_status;
 
 	/* Do not process Tx ring in case of Tx ring resource error */
@@ -2403,39 +2592,24 @@ static ETH_FUNC_RET_STATUS eth_port_send
 	tx_desc_used = mp->tx_used_desc_q;
 	current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
 
-	if (current_descriptor == NULL)
-		return ETH_ERROR;
-
 	command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
-
-/* XXX Is this for real ?!?!? */
-	/* Buffers with a payload smaller than 8 bytes must be aligned to a
-	 * 64-bit boundary. We use the memory allocated for Tx descriptor.
-	 * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the
-	 * Tx descriptor. */
-	if (p_pkt_info->byte_cnt <= 8) {
-		printk(KERN_ERR
-		       "You have failed in the < 8 bytes errata - fixme\n");
-		return ETH_ERROR;
-	}
 	current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
 	current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
-	mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info;
-
-	mb();
+	mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
 
 	/* Set last desc with DMA ownership and interrupt enable. */
+	wmb();
 	current_descriptor->cmd_sts = command_status |
 			ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT;
 
-	/* Apply send command */
+	wmb();
 	ETH_ENABLE_TX_QUEUE(mp->port_num);
 
 	/* Finish Tx packet. Update first desc in case of Tx resource error */
-	tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE;
+	tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size;
 
 	/* Update the current descriptor */
- 	mp->tx_curr_desc_q = tx_desc_curr;
+	mp->tx_curr_desc_q = tx_desc_curr;
 
 	/* Check for ring index overlap in the Tx desc ring */
 	if (tx_desc_curr == tx_desc_used) {
@@ -2452,62 +2626,55 @@ static ETH_FUNC_RET_STATUS eth_port_send
  *
  * DESCRIPTION:
  *	This routine returns the transmitted packet information to the caller.
- *      It uses the 'first' index to support Tx desc return in case a transmit 
- *      of a packet spanned over multiple buffer still in process.
- *      In case the Tx queue was in "resource error" condition, where there are 
- *      no available Tx resources, the function resets the resource error flag.
+ *	It uses the 'first' index to support Tx desc return in case a transmit
+ *	of a packet spanned over multiple buffer still in process.
+ *	In case the Tx queue was in "resource error" condition, where there are
+ *	no available Tx resources, the function resets the resource error flag.
  *
  * INPUT:
- *	struct mv64340_private   *mp   Ethernet Port Control srtuct. 
- *	struct pkt_info        *p_pkt_info       User packet buffer.
+ *	struct mv643xx_private	*mp		Ethernet Port Control srtuct.
+ *	struct pkt_info		*p_pkt_info	User packet buffer.
  *
  * OUTPUT:
- *	Tx ring 'first' and 'used' indexes are updated. 
+ *	Tx ring 'first' and 'used' indexes are updated.
  *
  * RETURN:
  *	ETH_ERROR in case the routine can not access Tx desc ring.
- *      ETH_RETRY in case there is transmission in process.
+ *	ETH_RETRY in case there is transmission in process.
  *	ETH_END_OF_JOB if the routine has nothing to release.
- *      ETH_OK otherwise.
+ *	ETH_OK otherwise.
  *
  */
-static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp,
-					      struct pkt_info * p_pkt_info)
+static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
+						struct pkt_info *p_pkt_info)
 {
-	int tx_desc_used, tx_desc_curr;
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-        int tx_first_desc;
+	int tx_desc_used;
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+	int tx_busy_desc = mp->tx_first_desc_q;
+#else
+	int tx_busy_desc = mp->tx_curr_desc_q;
 #endif
-	volatile struct eth_tx_desc *p_tx_desc_used;
+	struct eth_tx_desc *p_tx_desc_used;
 	unsigned int command_status;
 
 	/* Get the Tx Desc ring indexes */
-	tx_desc_curr = mp->tx_curr_desc_q;
 	tx_desc_used = mp->tx_used_desc_q;
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-        tx_first_desc = mp->tx_first_desc_q;
-#endif
+
 	p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used];
 
-	/* XXX Sanity check */
+	/* Sanity check */
 	if (p_tx_desc_used == NULL)
 		return ETH_ERROR;
 
+	/* Stop release. About to overlap the current available Tx descriptor */
+	if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err)
+		return ETH_END_OF_JOB;
+
 	command_status = p_tx_desc_used->cmd_sts;
 
 	/* Still transmitting... */
-#ifndef MV64340_CHECKSUM_OFFLOAD_TX
 	if (command_status & (ETH_BUFFER_OWNED_BY_DMA))
 		return ETH_RETRY;
-#endif
-	/* Stop release. About to overlap the current available Tx descriptor */
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-	if (tx_desc_used == tx_first_desc && !mp->tx_resource_err)
-		return ETH_END_OF_JOB;
-#else
-	if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err)
-		return ETH_END_OF_JOB;
-#endif
 
 	/* Pass the packet information to the caller */
 	p_pkt_info->cmd_sts = command_status;
@@ -2515,7 +2682,7 @@ static ETH_FUNC_RET_STATUS eth_tx_return
 	mp->tx_skb[tx_desc_used] = NULL;
 
 	/* Update the next descriptor to release. */
-	mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE;
+	mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size;
 
 	/* Any Tx return cancels the Tx resource error status */
 	mp->tx_resource_err = 0;
@@ -2527,30 +2694,30 @@ static ETH_FUNC_RET_STATUS eth_tx_return
  * eth_port_receive - Get received information from Rx ring.
  *
  * DESCRIPTION:
- * 	This routine returns the received data to the caller. There is no 
- *	data copying during routine operation. All information is returned 
- *	using pointer to packet information struct passed from the caller. 
- *      If the routine exhausts	Rx ring resources then the resource error flag 
- *      is set.  
+ * 	This routine returns the received data to the caller. There is no
+ *	data copying during routine operation. All information is returned
+ *	using pointer to packet information struct passed from the caller.
+ *	If the routine exhausts Rx ring resources then the resource error flag
+ *	is set.
  *
  * INPUT:
- *	struct mv64340_private   *mp   Ethernet Port Control srtuct. 
- *	struct pkt_info        *p_pkt_info       User packet buffer.
+ *	struct mv643xx_private	*mp		Ethernet Port Control srtuct.
+ *	struct pkt_info		*p_pkt_info	User packet buffer.
  *
  * OUTPUT:
- *	Rx ring current and used indexes are updated. 
+ *	Rx ring current and used indexes are updated.
  *
  * RETURN:
  *	ETH_ERROR in case the routine can not access Rx desc ring.
  *	ETH_QUEUE_FULL if Rx ring resources are exhausted.
  *	ETH_END_OF_JOB if there is no received data.
- *      ETH_OK otherwise.
+ *	ETH_OK otherwise.
  */
-static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp,
-					    struct pkt_info * p_pkt_info)
+static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,
+						struct pkt_info *p_pkt_info)
 {
 	int rx_next_curr_desc, rx_curr_desc, rx_used_desc;
-	volatile struct eth_rx_desc * p_rx_desc;
+	volatile struct eth_rx_desc *p_rx_desc;
 	unsigned int command_status;
 
 	/* Do not process Rx ring in case of Rx ring resource error */
@@ -2565,6 +2732,7 @@ static ETH_FUNC_RET_STATUS eth_port_rece
 
 	/* The following parameters are used to save readings from memory */
 	command_status = p_rx_desc->cmd_sts;
+	rmb();
 
 	/* Nothing to receive... */
 	if (command_status & (ETH_BUFFER_OWNED_BY_DMA))
@@ -2577,18 +2745,17 @@ static ETH_FUNC_RET_STATUS eth_port_rece
 	p_pkt_info->l4i_chk = p_rx_desc->buf_size;
 
 	/* Clean the return info field to indicate that the packet has been */
-	/* moved to the upper layers                                        */
+	/* moved to the upper layers					    */
 	mp->rx_skb[rx_curr_desc] = NULL;
 
 	/* Update current index in data structure */
-	rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE;
+	rx_next_curr_desc = (rx_curr_desc + 1) % mp->rx_ring_size;
 	mp->rx_curr_desc_q = rx_next_curr_desc;
 
 	/* Rx descriptors exhausted. Set the Rx ring resource error flag */
 	if (rx_next_curr_desc == rx_used_desc)
 		mp->rx_resource_err = 1;
 
-	mb();
 	return ETH_OK;
 }
 
@@ -2596,27 +2763,27 @@ static ETH_FUNC_RET_STATUS eth_port_rece
  * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring.
  *
  * DESCRIPTION:
- *	This routine returns a Rx buffer back to the Rx ring. It retrieves the 
- *      next 'used' descriptor and attached the returned buffer to it.
- *      In case the Rx ring was in "resource error" condition, where there are 
- *      no available Rx resources, the function resets the resource error flag.
+ *	This routine returns a Rx buffer back to the Rx ring. It retrieves the
+ *	next 'used' descriptor and attached the returned buffer to it.
+ *	In case the Rx ring was in "resource error" condition, where there are
+ *	no available Rx resources, the function resets the resource error flag.
  *
  * INPUT:
- *	struct mv64340_private *mp   Ethernet Port Control srtuct. 
- *      struct pkt_info        *p_pkt_info   Information on the returned buffer.
+ *	struct mv643xx_private	*mp		Ethernet Port Control srtuct.
+ *	struct pkt_info		*p_pkt_info	Information on returned buffer.
  *
  * OUTPUT:
  *	New available Rx resource in Rx descriptor ring.
  *
  * RETURN:
  *	ETH_ERROR in case the routine can not access Rx desc ring.
- *      ETH_OK otherwise.
+ *	ETH_OK otherwise.
  */
-static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp,
-	struct pkt_info * p_pkt_info)
+static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp,
+						struct pkt_info *p_pkt_info)
 {
 	int used_rx_desc;	/* Where to return Rx resource */
-	volatile struct eth_rx_desc* p_used_rx_desc;
+	volatile struct eth_rx_desc *p_used_rx_desc;
 
 	/* Get 'used' Rx descriptor */
 	used_rx_desc = mp->rx_used_desc_q;
@@ -2627,20 +2794,240 @@ static ETH_FUNC_RET_STATUS eth_rx_return
 	mp->rx_skb[used_rx_desc] = p_pkt_info->return_info;
 
 	/* Flush the write pipe */
-	mb();
 
 	/* Return the descriptor to DMA ownership */
+	wmb();
 	p_used_rx_desc->cmd_sts =
-		ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT;
-
-	/* Flush descriptor and CPU pipe */
-	mb();
+			ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT;
+	wmb();
 
 	/* Move the used descriptor pointer to the next descriptor */
-	mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE;
+	mp->rx_used_desc_q = (used_rx_desc + 1) % mp->rx_ring_size;
 
 	/* Any Rx return cancels the Rx resource error status */
 	mp->rx_resource_err = 0;
 
 	return ETH_OK;
 }
+
+/************* Begin ethtool support *************************/
+
+struct mv643xx_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define MV643XX_STAT(m) sizeof(((struct mv643xx_private *)0)->m), \
+		      offsetof(struct mv643xx_private, m)
+
+static const struct mv643xx_stats mv643xx_gstrings_stats[] = {
+	{ "rx_packets", MV643XX_STAT(stats.rx_packets) },
+	{ "tx_packets", MV643XX_STAT(stats.tx_packets) },
+	{ "rx_bytes", MV643XX_STAT(stats.rx_bytes) },
+	{ "tx_bytes", MV643XX_STAT(stats.tx_bytes) },
+	{ "rx_errors", MV643XX_STAT(stats.rx_errors) },
+	{ "tx_errors", MV643XX_STAT(stats.tx_errors) },
+	{ "rx_dropped", MV643XX_STAT(stats.rx_dropped) },
+	{ "tx_dropped", MV643XX_STAT(stats.tx_dropped) },
+	{ "good_octets_received", MV643XX_STAT(mib_counters.good_octets_received) },
+	{ "bad_octets_received", MV643XX_STAT(mib_counters.bad_octets_received) },
+	{ "internal_mac_transmit_err", MV643XX_STAT(mib_counters.internal_mac_transmit_err) },
+	{ "good_frames_received", MV643XX_STAT(mib_counters.good_frames_received) },
+	{ "bad_frames_received", MV643XX_STAT(mib_counters.bad_frames_received) },
+	{ "broadcast_frames_received", MV643XX_STAT(mib_counters.broadcast_frames_received) },
+	{ "multicast_frames_received", MV643XX_STAT(mib_counters.multicast_frames_received) },
+	{ "frames_64_octets", MV643XX_STAT(mib_counters.frames_64_octets) },
+	{ "frames_65_to_127_octets", MV643XX_STAT(mib_counters.frames_65_to_127_octets) },
+	{ "frames_128_to_255_octets", MV643XX_STAT(mib_counters.frames_128_to_255_octets) },
+	{ "frames_256_to_511_octets", MV643XX_STAT(mib_counters.frames_256_to_511_octets) },
+	{ "frames_512_to_1023_octets", MV643XX_STAT(mib_counters.frames_512_to_1023_octets) },
+	{ "frames_1024_to_max_octets", MV643XX_STAT(mib_counters.frames_1024_to_max_octets) },
+	{ "good_octets_sent", MV643XX_STAT(mib_counters.good_octets_sent) },
+	{ "good_frames_sent", MV643XX_STAT(mib_counters.good_frames_sent) },
+	{ "excessive_collision", MV643XX_STAT(mib_counters.excessive_collision) },
+	{ "multicast_frames_sent", MV643XX_STAT(mib_counters.multicast_frames_sent) },
+	{ "broadcast_frames_sent", MV643XX_STAT(mib_counters.broadcast_frames_sent) },
+	{ "unrec_mac_control_received", MV643XX_STAT(mib_counters.unrec_mac_control_received) },
+	{ "fc_sent", MV643XX_STAT(mib_counters.fc_sent) },
+	{ "good_fc_received", MV643XX_STAT(mib_counters.good_fc_received) },
+	{ "bad_fc_received", MV643XX_STAT(mib_counters.bad_fc_received) },
+	{ "undersize_received", MV643XX_STAT(mib_counters.undersize_received) },
+	{ "fragments_received", MV643XX_STAT(mib_counters.fragments_received) },
+	{ "oversize_received", MV643XX_STAT(mib_counters.oversize_received) },
+	{ "jabber_received", MV643XX_STAT(mib_counters.jabber_received) },
+	{ "mac_receive_error", MV643XX_STAT(mib_counters.mac_receive_error) },
+	{ "bad_crc_event", MV643XX_STAT(mib_counters.bad_crc_event) },
+	{ "collision", MV643XX_STAT(mib_counters.collision) },
+	{ "late_collision", MV643XX_STAT(mib_counters.late_collision) },
+};
+
+#define MV643XX_STATS_LEN	\
+	sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats)
+
+static int
+mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	struct mv643xx_private *mp = netdev->priv;
+	int port_num = mp->port_num;
+	int autoneg = eth_port_autoneg_supported(port_num);
+	int mode_10_bit;
+	int auto_duplex;
+	int half_duplex = 0;
+	int full_duplex = 0;
+	int auto_speed;
+	int speed_10 = 0;
+	int speed_100 = 0;
+	int speed_1000 = 0;
+
+	u32 pcs = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
+	u32 psr = mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num));
+
+	mode_10_bit = psr & MV643XX_ETH_PORT_STATUS_MODE_10_BIT;
+
+	if (mode_10_bit) {
+		ecmd->supported = SUPPORTED_10baseT_Half;
+	} else {
+		ecmd->supported = (SUPPORTED_10baseT_Half		|
+				   SUPPORTED_10baseT_Full		|
+				   SUPPORTED_100baseT_Half		|
+				   SUPPORTED_100baseT_Full		|
+				   SUPPORTED_1000baseT_Full		|
+				   (autoneg ? SUPPORTED_Autoneg : 0)	|
+				   SUPPORTED_TP);
+
+		auto_duplex = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX);
+		auto_speed = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII);
+
+		ecmd->advertising = ADVERTISED_TP;
+
+		if (autoneg) {
+			ecmd->advertising |= ADVERTISED_Autoneg;
+
+			if (auto_duplex) {
+				half_duplex = 1;
+				full_duplex = 1;
+			} else {
+				if (pcs & MV643XX_ETH_SET_FULL_DUPLEX_MODE)
+					full_duplex = 1;
+				else
+					half_duplex = 1;
+			}
+
+			if (auto_speed) {
+				speed_10 = 1;
+				speed_100 = 1;
+				speed_1000 = 1;
+			} else {
+				if (pcs & MV643XX_ETH_SET_GMII_SPEED_TO_1000)
+					speed_1000 = 1;
+				else if (pcs & MV643XX_ETH_SET_MII_SPEED_TO_100)
+					speed_100 = 1;
+				else
+					speed_10 = 1;
+			}
+
+			if (speed_10 & half_duplex)
+				ecmd->advertising |= ADVERTISED_10baseT_Half;
+			if (speed_10 & full_duplex)
+				ecmd->advertising |= ADVERTISED_10baseT_Full;
+			if (speed_100 & half_duplex)
+				ecmd->advertising |= ADVERTISED_100baseT_Half;
+			if (speed_100 & full_duplex)
+				ecmd->advertising |= ADVERTISED_100baseT_Full;
+			if (speed_1000)
+				ecmd->advertising |= ADVERTISED_1000baseT_Full;
+		}
+	}
+
+	ecmd->port = PORT_TP;
+	ecmd->phy_address = ethernet_phy_get(port_num);
+
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	if (netif_carrier_ok(netdev)) {
+		if (mode_10_bit)
+			ecmd->speed = SPEED_10;
+		else {
+			if (psr & MV643XX_ETH_PORT_STATUS_GMII_1000)
+				ecmd->speed = SPEED_1000;
+			else if (psr & MV643XX_ETH_PORT_STATUS_MII_100)
+				ecmd->speed = SPEED_100;
+			else
+				ecmd->speed = SPEED_10;
+		}
+
+		if (psr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+	return 0;
+}
+
+static void
+mv643xx_get_drvinfo(struct net_device *netdev,
+                       struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver,  mv643xx_driver_name, 32);
+	strncpy(drvinfo->version, mv643xx_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, "mv643xx", 32);
+	drvinfo->n_stats = MV643XX_STATS_LEN;
+}
+
+static int 
+mv643xx_get_stats_count(struct net_device *netdev)
+{
+	return MV643XX_STATS_LEN;
+}
+
+static void 
+mv643xx_get_ethtool_stats(struct net_device *netdev, 
+		struct ethtool_stats *stats, uint64_t *data)
+{
+	struct mv643xx_private *mp = netdev->priv;
+	int i;
+
+	eth_update_mib_counters(mp);
+
+	for(i = 0; i < MV643XX_STATS_LEN; i++) {
+		char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;	
+		data[i] = (mv643xx_gstrings_stats[i].sizeof_stat == 
+			sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
+	}
+}
+
+static void 
+mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
+{
+	int i;
+
+	switch(stringset) {
+	case ETH_SS_STATS:
+		for (i=0; i < MV643XX_STATS_LEN; i++) {
+			memcpy(data + i * ETH_GSTRING_LEN, 
+			mv643xx_gstrings_stats[i].stat_string,
+			ETH_GSTRING_LEN);
+		}
+		break;
+	}
+}
+
+static struct ethtool_ops mv643xx_ethtool_ops = {
+	.get_settings           = mv643xx_get_settings,
+	.get_drvinfo            = mv643xx_get_drvinfo,
+	.get_link               = ethtool_op_get_link,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_strings            = mv643xx_get_strings,
+	.get_stats_count        = mv643xx_get_stats_count,
+	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
+};
+
+/************* End ethtool support *************************/
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -1,5 +1,5 @@
-#ifndef __MV64340_ETH_H__
-#define __MV64340_ETH_H__
+#ifndef __MV643XX_ETH_H__
+#define __MV643XX_ETH_H__
 
 #include <linux/version.h>
 #include <linux/module.h>
@@ -46,17 +46,16 @@
  *  The first part is the high level driver of the gigE ethernet ports.
  */
 
-#define ETH_PORT0_IRQ_NUM 48			/* main high register, bit0 */
-#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1	/* main high register, bit1 */
-#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2	/* main high register, bit1 */
-
-/* Checksum offload for Tx works */
-#define  MV64340_CHECKSUM_OFFLOAD_TX
-#define	 MV64340_NAPI
-#define	 MV64340_TX_FAST_REFILL
-#undef	 MV64340_COAL
+/* Checksum offload for Tx works for most packets, but
+ * fails if previous packet sent did not use hw csum
+ */
+#undef	MV643XX_CHECKSUM_OFFLOAD_TX
+#define	MV643XX_NAPI
+#define	MV643XX_TX_FAST_REFILL
+#undef	MV643XX_RX_QUEUE_FILL_ON_TASK	/* Does not work, yet */
+#undef	MV643XX_COAL
 
-/* 
+/*
  * Number of RX / TX descriptors on RX / TX rings.
  * Note that allocating RX descriptors is done by allocating the RX
  * ring AND a preallocated RX buffers (skb's) for each descriptor.
@@ -65,89 +64,35 @@
  */
 
 /* Default TX ring size is 1000 descriptors */
-#define MV64340_TX_QUEUE_SIZE 1000
+#define MV643XX_DEFAULT_TX_QUEUE_SIZE 1000
 
 /* Default RX ring size is 400 descriptors */
-#define MV64340_RX_QUEUE_SIZE 400
+#define MV643XX_DEFAULT_RX_QUEUE_SIZE 400
 
-#define MV64340_TX_COAL 100
-#ifdef MV64340_COAL
-#define MV64340_RX_COAL 100
+#define MV643XX_TX_COAL 100
+#ifdef MV643XX_COAL
+#define MV643XX_RX_COAL 100
 #endif
 
-
 /*
- * The second part is the low level driver of the gigE ethernet ports.   *
+ * The second part is the low level driver of the gigE ethernet ports.
  */
 
-
 /*
- * Header File for : MV-643xx network interface header 
+ * Header File for : MV-643xx network interface header
  *
  * DESCRIPTION:
- *       This header file contains macros typedefs and function declaration for
- *       the Marvell Gig Bit Ethernet Controller. 
+ *	This header file contains macros typedefs and function declaration for
+ *	the Marvell Gig Bit Ethernet Controller.
  *
  * DEPENDENCIES:
- *       None.
+ *	None.
  *
  */
 
-/* Default port configuration value */
-#define PORT_CONFIG_VALUE                       \
-             ETH_UNICAST_NORMAL_MODE		|   \
-             ETH_DEFAULT_RX_QUEUE_0		|   \
-             ETH_DEFAULT_RX_ARP_QUEUE_0		|   \
-             ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP	|   \
-             ETH_RECEIVE_BC_IF_IP		|   \
-             ETH_RECEIVE_BC_IF_ARP 		|   \
-             ETH_CAPTURE_TCP_FRAMES_DIS		|   \
-             ETH_CAPTURE_UDP_FRAMES_DIS		|   \
-             ETH_DEFAULT_RX_TCP_QUEUE_0		|   \
-             ETH_DEFAULT_RX_UDP_QUEUE_0		|   \
-             ETH_DEFAULT_RX_BPDU_QUEUE_0
-
-/* Default port extend configuration value */
-#define PORT_CONFIG_EXTEND_VALUE		\
-             ETH_SPAN_BPDU_PACKETS_AS_NORMAL	|   \
-             ETH_PARTITION_DISABLE
-
-
-/* Default sdma control value */
-#define PORT_SDMA_CONFIG_VALUE			\
-			 ETH_RX_BURST_SIZE_16_64BIT 	|	\
-			 GT_ETH_IPG_INT_RX(0) 		|	\
-			 ETH_TX_BURST_SIZE_16_64BIT;
-
-#define GT_ETH_IPG_INT_RX(value)                \
-            ((value & 0x3fff) << 8)
-
-/* Default port serial control value */
-#define PORT_SERIAL_CONTROL_VALUE		\
-			ETH_FORCE_LINK_PASS 			|	\
-			ETH_ENABLE_AUTO_NEG_FOR_DUPLX		|	\
-			ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL 	|	\
-			ETH_ADV_SYMMETRIC_FLOW_CTRL 		|	\
-			ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 	|	\
-			ETH_FORCE_BP_MODE_NO_JAM 		|	\
-			BIT9 					|	\
-			ETH_DO_NOT_FORCE_LINK_FAIL 		|	\
-			ETH_RETRANSMIT_16_ATTEMPTS 		|	\
-			ETH_ENABLE_AUTO_NEG_SPEED_GMII	 	|	\
-			ETH_DTE_ADV_0 				|	\
-			ETH_DISABLE_AUTO_NEG_BYPASS		|	\
-			ETH_AUTO_NEG_NO_CHANGE 			|	\
-			ETH_MAX_RX_PACKET_9700BYTE 		|	\
-			ETH_CLR_EXT_LOOPBACK 			|	\
-			ETH_SET_FULL_DUPLEX_MODE 		|	\
-			ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
-
-#define RX_BUFFER_MAX_SIZE  0x4000000
-#define TX_BUFFER_MAX_SIZE  0x4000000
-
 /* MAC accepet/reject macros */
-#define ACCEPT_MAC_ADDR	    0
-#define REJECT_MAC_ADDR	    1
+#define ACCEPT_MAC_ADDR				0
+#define REJECT_MAC_ADDR				1
 
 /* Buffer offset from buffer pointer */
 #define RX_BUF_OFFSET				0x2
@@ -155,277 +100,132 @@
 /* Gigabit Ethernet Unit Global Registers */
 
 /* MIB Counters register definitions */
-#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW   0x0
-#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH  0x4
-#define ETH_MIB_BAD_OCTETS_RECEIVED        0x8
-#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR  0xc
-#define ETH_MIB_GOOD_FRAMES_RECEIVED       0x10
-#define ETH_MIB_BAD_FRAMES_RECEIVED        0x14
-#define ETH_MIB_BROADCAST_FRAMES_RECEIVED  0x18
-#define ETH_MIB_MULTICAST_FRAMES_RECEIVED  0x1c
-#define ETH_MIB_FRAMES_64_OCTETS           0x20
-#define ETH_MIB_FRAMES_65_TO_127_OCTETS    0x24
-#define ETH_MIB_FRAMES_128_TO_255_OCTETS   0x28
-#define ETH_MIB_FRAMES_256_TO_511_OCTETS   0x2c
-#define ETH_MIB_FRAMES_512_TO_1023_OCTETS  0x30
-#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS  0x34
-#define ETH_MIB_GOOD_OCTETS_SENT_LOW       0x38
-#define ETH_MIB_GOOD_OCTETS_SENT_HIGH      0x3c
-#define ETH_MIB_GOOD_FRAMES_SENT           0x40
-#define ETH_MIB_EXCESSIVE_COLLISION        0x44
-#define ETH_MIB_MULTICAST_FRAMES_SENT      0x48
-#define ETH_MIB_BROADCAST_FRAMES_SENT      0x4c
-#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50
-#define ETH_MIB_FC_SENT                    0x54
-#define ETH_MIB_GOOD_FC_RECEIVED           0x58
-#define ETH_MIB_BAD_FC_RECEIVED            0x5c
-#define ETH_MIB_UNDERSIZE_RECEIVED         0x60
-#define ETH_MIB_FRAGMENTS_RECEIVED         0x64
-#define ETH_MIB_OVERSIZE_RECEIVED          0x68
-#define ETH_MIB_JABBER_RECEIVED            0x6c
-#define ETH_MIB_MAC_RECEIVE_ERROR          0x70
-#define ETH_MIB_BAD_CRC_EVENT              0x74
-#define ETH_MIB_COLLISION                  0x78
-#define ETH_MIB_LATE_COLLISION             0x7c
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW	0x0
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH	0x4
+#define ETH_MIB_BAD_OCTETS_RECEIVED		0x8
+#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR	0xc
+#define ETH_MIB_GOOD_FRAMES_RECEIVED		0x10
+#define ETH_MIB_BAD_FRAMES_RECEIVED		0x14
+#define ETH_MIB_BROADCAST_FRAMES_RECEIVED	0x18
+#define ETH_MIB_MULTICAST_FRAMES_RECEIVED	0x1c
+#define ETH_MIB_FRAMES_64_OCTETS		0x20
+#define ETH_MIB_FRAMES_65_TO_127_OCTETS		0x24
+#define ETH_MIB_FRAMES_128_TO_255_OCTETS	0x28
+#define ETH_MIB_FRAMES_256_TO_511_OCTETS	0x2c
+#define ETH_MIB_FRAMES_512_TO_1023_OCTETS	0x30
+#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS	0x34
+#define ETH_MIB_GOOD_OCTETS_SENT_LOW		0x38
+#define ETH_MIB_GOOD_OCTETS_SENT_HIGH		0x3c
+#define ETH_MIB_GOOD_FRAMES_SENT		0x40
+#define ETH_MIB_EXCESSIVE_COLLISION		0x44
+#define ETH_MIB_MULTICAST_FRAMES_SENT		0x48
+#define ETH_MIB_BROADCAST_FRAMES_SENT		0x4c
+#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED	0x50
+#define ETH_MIB_FC_SENT				0x54
+#define ETH_MIB_GOOD_FC_RECEIVED		0x58
+#define ETH_MIB_BAD_FC_RECEIVED			0x5c
+#define ETH_MIB_UNDERSIZE_RECEIVED		0x60
+#define ETH_MIB_FRAGMENTS_RECEIVED		0x64
+#define ETH_MIB_OVERSIZE_RECEIVED		0x68
+#define ETH_MIB_JABBER_RECEIVED			0x6c
+#define ETH_MIB_MAC_RECEIVE_ERROR		0x70
+#define ETH_MIB_BAD_CRC_EVENT			0x74
+#define ETH_MIB_COLLISION			0x78
+#define ETH_MIB_LATE_COLLISION			0x7c
 
 /* Port serial status reg (PSR) */
-#define ETH_INTERFACE_GMII_MII                          0
-#define ETH_INTERFACE_PCM                               BIT0
-#define ETH_LINK_IS_DOWN                                0
-#define ETH_LINK_IS_UP                                  BIT1
-#define ETH_PORT_AT_HALF_DUPLEX                         0
-#define ETH_PORT_AT_FULL_DUPLEX                         BIT2
-#define ETH_RX_FLOW_CTRL_DISABLED                       0
-#define ETH_RX_FLOW_CTRL_ENBALED                        BIT3
-#define ETH_GMII_SPEED_100_10                           0
-#define ETH_GMII_SPEED_1000                             BIT4
-#define ETH_MII_SPEED_10                                0
-#define ETH_MII_SPEED_100                               BIT5
-#define ETH_NO_TX                                       0
-#define ETH_TX_IN_PROGRESS                              BIT7
-#define ETH_BYPASS_NO_ACTIVE                            0
-#define ETH_BYPASS_ACTIVE                               BIT8
-#define ETH_PORT_NOT_AT_PARTITION_STATE                 0
-#define ETH_PORT_AT_PARTITION_STATE                     BIT9
-#define ETH_PORT_TX_FIFO_NOT_EMPTY                      0
-#define ETH_PORT_TX_FIFO_EMPTY                          BIT10
-
-
-/* These macros describes the Port configuration reg (Px_cR) bits */
-#define ETH_UNICAST_NORMAL_MODE                         0
-#define ETH_UNICAST_PROMISCUOUS_MODE                    BIT0
-#define ETH_DEFAULT_RX_QUEUE_0                          0
-#define ETH_DEFAULT_RX_QUEUE_1                          BIT1
-#define ETH_DEFAULT_RX_QUEUE_2                          BIT2
-#define ETH_DEFAULT_RX_QUEUE_3                          (BIT2 | BIT1)
-#define ETH_DEFAULT_RX_QUEUE_4                          BIT3
-#define ETH_DEFAULT_RX_QUEUE_5                          (BIT3 | BIT1)
-#define ETH_DEFAULT_RX_QUEUE_6                          (BIT3 | BIT2)
-#define ETH_DEFAULT_RX_QUEUE_7                          (BIT3 | BIT2 | BIT1)
-#define ETH_DEFAULT_RX_ARP_QUEUE_0                      0
-#define ETH_DEFAULT_RX_ARP_QUEUE_1                      BIT4
-#define ETH_DEFAULT_RX_ARP_QUEUE_2                      BIT5
-#define ETH_DEFAULT_RX_ARP_QUEUE_3                      (BIT5 | BIT4)
-#define ETH_DEFAULT_RX_ARP_QUEUE_4                      BIT6
-#define ETH_DEFAULT_RX_ARP_QUEUE_5                      (BIT6 | BIT4)
-#define ETH_DEFAULT_RX_ARP_QUEUE_6                      (BIT6 | BIT5)
-#define ETH_DEFAULT_RX_ARP_QUEUE_7                      (BIT6 | BIT5 | BIT4)
-#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP                 0
-#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP                  BIT7
-#define ETH_RECEIVE_BC_IF_IP                            0
-#define ETH_REJECT_BC_IF_IP                             BIT8
-#define ETH_RECEIVE_BC_IF_ARP                           0
-#define ETH_REJECT_BC_IF_ARP                            BIT9
-#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY               BIT12
-#define ETH_CAPTURE_TCP_FRAMES_DIS                      0
-#define ETH_CAPTURE_TCP_FRAMES_EN                       BIT14
-#define ETH_CAPTURE_UDP_FRAMES_DIS                      0
-#define ETH_CAPTURE_UDP_FRAMES_EN                       BIT15
-#define ETH_DEFAULT_RX_TCP_QUEUE_0                      0
-#define ETH_DEFAULT_RX_TCP_QUEUE_1                      BIT16
-#define ETH_DEFAULT_RX_TCP_QUEUE_2                      BIT17
-#define ETH_DEFAULT_RX_TCP_QUEUE_3                      (BIT17 | BIT16)
-#define ETH_DEFAULT_RX_TCP_QUEUE_4                      BIT18
-#define ETH_DEFAULT_RX_TCP_QUEUE_5                      (BIT18 | BIT16)
-#define ETH_DEFAULT_RX_TCP_QUEUE_6                      (BIT18 | BIT17)
-#define ETH_DEFAULT_RX_TCP_QUEUE_7                      (BIT18 | BIT17 | BIT16)
-#define ETH_DEFAULT_RX_UDP_QUEUE_0                      0
-#define ETH_DEFAULT_RX_UDP_QUEUE_1                      BIT19
-#define ETH_DEFAULT_RX_UDP_QUEUE_2                      BIT20
-#define ETH_DEFAULT_RX_UDP_QUEUE_3                      (BIT20 | BIT19)
-#define ETH_DEFAULT_RX_UDP_QUEUE_4                      (BIT21
-#define ETH_DEFAULT_RX_UDP_QUEUE_5                      (BIT21 | BIT19)
-#define ETH_DEFAULT_RX_UDP_QUEUE_6                      (BIT21 | BIT20)
-#define ETH_DEFAULT_RX_UDP_QUEUE_7                      (BIT21 | BIT20 | BIT19)
-#define ETH_DEFAULT_RX_BPDU_QUEUE_0                      0
-#define ETH_DEFAULT_RX_BPDU_QUEUE_1                     BIT22
-#define ETH_DEFAULT_RX_BPDU_QUEUE_2                     BIT23
-#define ETH_DEFAULT_RX_BPDU_QUEUE_3                     (BIT23 | BIT22)
-#define ETH_DEFAULT_RX_BPDU_QUEUE_4                     BIT24
-#define ETH_DEFAULT_RX_BPDU_QUEUE_5                     (BIT24 | BIT22)
-#define ETH_DEFAULT_RX_BPDU_QUEUE_6                     (BIT24 | BIT23)
-#define ETH_DEFAULT_RX_BPDU_QUEUE_7                     (BIT24 | BIT23 | BIT22)
-
-
-/* These macros describes the Port configuration extend reg (Px_cXR) bits*/
-#define ETH_CLASSIFY_EN                                 BIT0
-#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL                 0
-#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7             BIT1
-#define ETH_PARTITION_DISABLE                           0
-#define ETH_PARTITION_ENABLE                            BIT2
-
-
-/* Tx/Rx queue command reg (RQCR/TQCR)*/
-#define ETH_QUEUE_0_ENABLE                              BIT0
-#define ETH_QUEUE_1_ENABLE                              BIT1
-#define ETH_QUEUE_2_ENABLE                              BIT2
-#define ETH_QUEUE_3_ENABLE                              BIT3
-#define ETH_QUEUE_4_ENABLE                              BIT4
-#define ETH_QUEUE_5_ENABLE                              BIT5
-#define ETH_QUEUE_6_ENABLE                              BIT6
-#define ETH_QUEUE_7_ENABLE                              BIT7
-#define ETH_QUEUE_0_DISABLE                             BIT8
-#define ETH_QUEUE_1_DISABLE                             BIT9
-#define ETH_QUEUE_2_DISABLE                             BIT10
-#define ETH_QUEUE_3_DISABLE                             BIT11
-#define ETH_QUEUE_4_DISABLE                             BIT12
-#define ETH_QUEUE_5_DISABLE                             BIT13
-#define ETH_QUEUE_6_DISABLE                             BIT14
-#define ETH_QUEUE_7_DISABLE                             BIT15
-
-
-/* These macros describes the Port Sdma configuration reg (SDCR) bits */
-#define ETH_RIFB                                        BIT0
-#define ETH_RX_BURST_SIZE_1_64BIT                       0
-#define ETH_RX_BURST_SIZE_2_64BIT                       BIT1
-#define ETH_RX_BURST_SIZE_4_64BIT                       BIT2
-#define ETH_RX_BURST_SIZE_8_64BIT                       (BIT2 | BIT1)
-#define ETH_RX_BURST_SIZE_16_64BIT                      BIT3
-#define ETH_BLM_RX_NO_SWAP                              BIT4
-#define ETH_BLM_RX_BYTE_SWAP                            0
-#define ETH_BLM_TX_NO_SWAP                              BIT5
-#define ETH_BLM_TX_BYTE_SWAP                            0
-#define ETH_DESCRIPTORS_BYTE_SWAP                       BIT6
-#define ETH_DESCRIPTORS_NO_SWAP                         0
-#define ETH_TX_BURST_SIZE_1_64BIT                       0
-#define ETH_TX_BURST_SIZE_2_64BIT                       BIT22
-#define ETH_TX_BURST_SIZE_4_64BIT                       BIT23
-#define ETH_TX_BURST_SIZE_8_64BIT                       (BIT23 | BIT22)
-#define ETH_TX_BURST_SIZE_16_64BIT                      BIT24
-
-
-
-/* These macros describes the Port serial control reg (PSCR) bits */
-#define ETH_SERIAL_PORT_DISABLE                         0
-#define ETH_SERIAL_PORT_ENABLE                          BIT0
-#define ETH_FORCE_LINK_PASS                             BIT1
-#define ETH_DO_NOT_FORCE_LINK_PASS                      0
-#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX                   0
-#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX                  BIT2
-#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL               0
-#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL              BIT3
-#define ETH_ADV_NO_FLOW_CTRL                            0
-#define ETH_ADV_SYMMETRIC_FLOW_CTRL                     BIT4
-#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX               0
-#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS                  BIT5
-#define ETH_FORCE_BP_MODE_NO_JAM                        0
-#define ETH_FORCE_BP_MODE_JAM_TX                        BIT7
-#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR              BIT8
-#define ETH_FORCE_LINK_FAIL                             0
-#define ETH_DO_NOT_FORCE_LINK_FAIL                      BIT10
-#define ETH_RETRANSMIT_16_ATTEMPTS                      0
-#define ETH_RETRANSMIT_FOREVER                          BIT11
-#define ETH_DISABLE_AUTO_NEG_SPEED_GMII                 BIT13
-#define ETH_ENABLE_AUTO_NEG_SPEED_GMII                  0
-#define ETH_DTE_ADV_0                                   0
-#define ETH_DTE_ADV_1                                   BIT14
-#define ETH_DISABLE_AUTO_NEG_BYPASS                     0
-#define ETH_ENABLE_AUTO_NEG_BYPASS                      BIT15
-#define ETH_AUTO_NEG_NO_CHANGE                          0
-#define ETH_RESTART_AUTO_NEG                            BIT16
-#define ETH_MAX_RX_PACKET_1518BYTE                      0
-#define ETH_MAX_RX_PACKET_1522BYTE                      BIT17
-#define ETH_MAX_RX_PACKET_1552BYTE                      BIT18
-#define ETH_MAX_RX_PACKET_9022BYTE                      (BIT18 | BIT17)
-#define ETH_MAX_RX_PACKET_9192BYTE                      BIT19
-#define ETH_MAX_RX_PACKET_9700BYTE                      (BIT19 | BIT17)
-#define ETH_SET_EXT_LOOPBACK                            BIT20
-#define ETH_CLR_EXT_LOOPBACK                            0
-#define ETH_SET_FULL_DUPLEX_MODE                        BIT21
-#define ETH_SET_HALF_DUPLEX_MODE                        0
-#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX       BIT22
-#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX      0
-#define ETH_SET_GMII_SPEED_TO_10_100                    0
-#define ETH_SET_GMII_SPEED_TO_1000                      BIT23
-#define ETH_SET_MII_SPEED_TO_10                         0
-#define ETH_SET_MII_SPEED_TO_100                        BIT24
-
+#define ETH_INTERFACE_GMII_MII			0
+#define ETH_INTERFACE_PCM			BIT0
+#define ETH_LINK_IS_DOWN			0
+#define ETH_LINK_IS_UP				BIT1
+#define ETH_PORT_AT_HALF_DUPLEX			0
+#define ETH_PORT_AT_FULL_DUPLEX			BIT2
+#define ETH_RX_FLOW_CTRL_DISABLED		0
+#define ETH_RX_FLOW_CTRL_ENBALED		BIT3
+#define ETH_GMII_SPEED_100_10			0
+#define ETH_GMII_SPEED_1000			BIT4
+#define ETH_MII_SPEED_10			0
+#define ETH_MII_SPEED_100			BIT5
+#define ETH_NO_TX				0
+#define ETH_TX_IN_PROGRESS			BIT7
+#define ETH_BYPASS_NO_ACTIVE			0
+#define ETH_BYPASS_ACTIVE			BIT8
+#define ETH_PORT_NOT_AT_PARTITION_STATE		0
+#define ETH_PORT_AT_PARTITION_STATE		BIT9
+#define ETH_PORT_TX_FIFO_NOT_EMPTY		0
+#define ETH_PORT_TX_FIFO_EMPTY			BIT10
+
+#define ETH_DEFAULT_RX_BPDU_QUEUE_3		(BIT23 | BIT22)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_4		BIT24
+#define ETH_DEFAULT_RX_BPDU_QUEUE_5		(BIT24 | BIT22)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_6		(BIT24 | BIT23)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_7		(BIT24 | BIT23 | BIT22)
 
 /* SMI reg */
-#define ETH_SMI_BUSY        	BIT28	/* 0 - Write, 1 - Read          */
-#define ETH_SMI_READ_VALID  	BIT27	/* 0 - Write, 1 - Read          */
+#define ETH_SMI_BUSY		BIT28	/* 0 - Write, 1 - Read		*/
+#define ETH_SMI_READ_VALID	BIT27	/* 0 - Write, 1 - Read		*/
 #define ETH_SMI_OPCODE_WRITE	0	/* Completion of Read operation */
-#define ETH_SMI_OPCODE_READ 	BIT26	/* Operation is in progress             */
+#define ETH_SMI_OPCODE_READ 	BIT26	/* Operation is in progress	*/
 
 /* SDMA command status fields macros */
 
 /* Tx & Rx descriptors status */
-#define ETH_ERROR_SUMMARY                   (BIT0)
+#define ETH_ERROR_SUMMARY			(BIT0)
 
 /* Tx & Rx descriptors command */
-#define ETH_BUFFER_OWNED_BY_DMA             (BIT31)
+#define ETH_BUFFER_OWNED_BY_DMA			(BIT31)
 
 /* Tx descriptors status */
-#define ETH_LC_ERROR                        (0	  )
-#define ETH_UR_ERROR                        (BIT1 )
-#define ETH_RL_ERROR                        (BIT2 )
-#define ETH_LLC_SNAP_FORMAT                 (BIT9 )
+#define ETH_LC_ERROR				(0    )
+#define ETH_UR_ERROR				(BIT1 )
+#define ETH_RL_ERROR				(BIT2 )
+#define ETH_LLC_SNAP_FORMAT			(BIT9 )
 
 /* Rx descriptors status */
-#define ETH_CRC_ERROR                       (0	  )
-#define ETH_OVERRUN_ERROR                   (BIT1 )
-#define ETH_MAX_FRAME_LENGTH_ERROR          (BIT2 )
-#define ETH_RESOURCE_ERROR                  ((BIT2 | BIT1))
-#define ETH_VLAN_TAGGED                     (BIT19)
-#define ETH_BPDU_FRAME                      (BIT20)
-#define ETH_TCP_FRAME_OVER_IP_V_4           (0    )
-#define ETH_UDP_FRAME_OVER_IP_V_4           (BIT21)
-#define ETH_OTHER_FRAME_TYPE                (BIT22)
-#define ETH_LAYER_2_IS_ETH_V_2              (BIT23)
-#define ETH_FRAME_TYPE_IP_V_4               (BIT24)
-#define ETH_FRAME_HEADER_OK                 (BIT25)
-#define ETH_RX_LAST_DESC                    (BIT26)
-#define ETH_RX_FIRST_DESC                   (BIT27)
-#define ETH_UNKNOWN_DESTINATION_ADDR        (BIT28)
-#define ETH_RX_ENABLE_INTERRUPT             (BIT29)
-#define ETH_LAYER_4_CHECKSUM_OK             (BIT30)
+#define ETH_CRC_ERROR				(0    )
+#define ETH_OVERRUN_ERROR			(BIT1 )
+#define ETH_MAX_FRAME_LENGTH_ERROR		(BIT2 )
+#define ETH_RESOURCE_ERROR			((BIT2 | BIT1))
+#define ETH_VLAN_TAGGED				(BIT19)
+#define ETH_BPDU_FRAME				(BIT20)
+#define ETH_TCP_FRAME_OVER_IP_V_4		(0    )
+#define ETH_UDP_FRAME_OVER_IP_V_4		(BIT21)
+#define ETH_OTHER_FRAME_TYPE			(BIT22)
+#define ETH_LAYER_2_IS_ETH_V_2			(BIT23)
+#define ETH_FRAME_TYPE_IP_V_4			(BIT24)
+#define ETH_FRAME_HEADER_OK			(BIT25)
+#define ETH_RX_LAST_DESC			(BIT26)
+#define ETH_RX_FIRST_DESC			(BIT27)
+#define ETH_UNKNOWN_DESTINATION_ADDR		(BIT28)
+#define ETH_RX_ENABLE_INTERRUPT			(BIT29)
+#define ETH_LAYER_4_CHECKSUM_OK			(BIT30)
 
 /* Rx descriptors byte count */
-#define ETH_FRAME_FRAGMENTED                (BIT2)
+#define ETH_FRAME_FRAGMENTED			(BIT2)
 
 /* Tx descriptors command */
 #define ETH_LAYER_4_CHECKSUM_FIRST_DESC		(BIT10)
-#define ETH_FRAME_SET_TO_VLAN               (BIT15)
-#define ETH_TCP_FRAME                       (0	  )
-#define ETH_UDP_FRAME                       (BIT16)
-#define ETH_GEN_TCP_UDP_CHECKSUM            (BIT17)
-#define ETH_GEN_IP_V_4_CHECKSUM             (BIT18)
-#define ETH_ZERO_PADDING                    (BIT19)
-#define ETH_TX_LAST_DESC                    (BIT20)
-#define ETH_TX_FIRST_DESC                   (BIT21)
-#define ETH_GEN_CRC                         (BIT22)
-#define ETH_TX_ENABLE_INTERRUPT             (BIT23)
-#define ETH_AUTO_MODE                       (BIT30)
+#define ETH_FRAME_SET_TO_VLAN			(BIT15)
+#define ETH_TCP_FRAME				(0    )
+#define ETH_UDP_FRAME				(BIT16)
+#define ETH_GEN_TCP_UDP_CHECKSUM		(BIT17)
+#define ETH_GEN_IP_V_4_CHECKSUM			(BIT18)
+#define ETH_ZERO_PADDING			(BIT19)
+#define ETH_TX_LAST_DESC			(BIT20)
+#define ETH_TX_FIRST_DESC			(BIT21)
+#define ETH_GEN_CRC				(BIT22)
+#define ETH_TX_ENABLE_INTERRUPT			(BIT23)
+#define ETH_AUTO_MODE				(BIT30)
 
 /* typedefs */
 
 typedef enum _eth_func_ret_status {
-	ETH_OK,			/* Returned as expected.                    */
-	ETH_ERROR,		/* Fundamental error.                       */
-	ETH_RETRY,		/* Could not process request. Try later.    */
-	ETH_END_OF_JOB,		/* Ring has nothing to process.             */
-	ETH_QUEUE_FULL,		/* Ring resource error.                     */
-	ETH_QUEUE_LAST_RESOURCE	/* Ring resources about to exhaust.         */
+	ETH_OK,			/* Returned as expected.		*/
+	ETH_ERROR,		/* Fundamental error.			*/
+	ETH_RETRY,		/* Could not process request. Try later.*/
+	ETH_END_OF_JOB,		/* Ring has nothing to process.		*/
+	ETH_QUEUE_FULL,		/* Ring resource error.			*/
+	ETH_QUEUE_LAST_RESOURCE	/* Ring resources about to exhaust.	*/
 } ETH_FUNC_RET_STATUS;
 
 typedef enum _eth_target {
@@ -441,66 +241,103 @@ typedef enum _eth_target {
  */
 #if defined(__BIG_ENDIAN)
 struct eth_rx_desc {
-	u16	byte_cnt;	/* Descriptor buffer byte count     */
-	u16	buf_size;	/* Buffer size                      */
-	u32	cmd_sts;	/* Descriptor command status        */
-	u32	next_desc_ptr;	/* Next descriptor pointer          */
-	u32	buf_ptr;	/* Descriptor buffer pointer        */
+	u16 byte_cnt;		/* Descriptor buffer byte count		*/
+	u16 buf_size;		/* Buffer size				*/
+	u32 cmd_sts;		/* Descriptor command status		*/
+	u32 next_desc_ptr;	/* Next descriptor pointer		*/
+	u32 buf_ptr;		/* Descriptor buffer pointer		*/
 };
 
 struct eth_tx_desc {
-	u16	byte_cnt;	/* buffer byte count */
-	u16	l4i_chk;	/* CPU provided TCP checksum */
-	u32	cmd_sts;	/* Command/status field */
-	u32	next_desc_ptr;	/* Pointer to next descriptor */
-	u32	buf_ptr;	/* pointer to buffer for this descriptor */
+	u16 byte_cnt;		/* buffer byte count			*/
+	u16 l4i_chk;		/* CPU provided TCP checksum		*/
+	u32 cmd_sts;		/* Command/status field			*/
+	u32 next_desc_ptr;	/* Pointer to next descriptor		*/
+	u32 buf_ptr;		/* pointer to buffer for this descriptor*/
 };
 
 #elif defined(__LITTLE_ENDIAN)
 struct eth_rx_desc {
-	u32	cmd_sts;	/* Descriptor command status        */
-	u16	buf_size;	/* Buffer size                      */
-	u16	byte_cnt;	/* Descriptor buffer byte count     */
-	u32	buf_ptr;	/* Descriptor buffer pointer        */
-	u32	next_desc_ptr;	/* Next descriptor pointer          */
+	u32 cmd_sts;		/* Descriptor command status		*/
+	u16 buf_size;		/* Buffer size				*/
+	u16 byte_cnt;		/* Descriptor buffer byte count		*/
+	u32 buf_ptr;		/* Descriptor buffer pointer		*/
+	u32 next_desc_ptr;	/* Next descriptor pointer		*/
 };
 
 struct eth_tx_desc {
-	u32	cmd_sts;	/* Command/status field */
-	u16	l4i_chk;	/* CPU provided TCP checksum */
-	u16	byte_cnt;	/* buffer byte count */
-	u32	buf_ptr;	/* pointer to buffer for this descriptor */
-	u32	next_desc_ptr;	/* Pointer to next descriptor */
+	u32 cmd_sts;		/* Command/status field			*/
+	u16 l4i_chk;		/* CPU provided TCP checksum		*/
+	u16 byte_cnt;		/* buffer byte count			*/
+	u32 buf_ptr;		/* pointer to buffer for this descriptor*/
+	u32 next_desc_ptr;	/* Pointer to next descriptor		*/
 };
 #else
 #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
 #endif
 
-/* Unified struct for Rx and Tx operations. The user is not required to */
-/* be familier with neither Tx nor Rx descriptors.                       */
+/* Unified struct for Rx and Tx operations. The user is not required to	*/
+/* be familier with neither Tx nor Rx descriptors.			*/
 struct pkt_info {
-	unsigned short	byte_cnt;	/* Descriptor buffer byte count     */
-	unsigned short	l4i_chk;	/* Tx CPU provided TCP Checksum     */
-	unsigned int	cmd_sts;	/* Descriptor command status        */
-	dma_addr_t	buf_ptr;	/* Descriptor buffer pointer        */
-	struct sk_buff	* return_info;	/* User resource return information */
+	unsigned short byte_cnt;	/* Descriptor buffer byte count	*/
+	unsigned short l4i_chk;		/* Tx CPU provided TCP Checksum	*/
+	unsigned int cmd_sts;		/* Descriptor command status	*/
+	dma_addr_t buf_ptr;		/* Descriptor buffer pointer	*/
+	struct sk_buff *return_info;	/* User resource return information */
 };
 
-
 /* Ethernet port specific infomation */
 
-struct mv64340_private {
-	int	port_num;		/* User Ethernet port number */
-	u8	port_mac_addr[6];	/* User defined port MAC address. */
-	u32	port_config;		/* User port configuration value */
-	u32	port_config_extend;	/* User port config extend value */
-	u32	port_sdma_config;	/* User port SDMA config value */
-	u32	port_serial_control;	/* User port serial control value */
-	u32	port_tx_queue_command;	/* Port active Tx queues summary */
-	u32	port_rx_queue_command;	/* Port active Rx queues summary */
+struct mv643xx_mib_counters {
+	u64 good_octets_received;
+	u32 bad_octets_received;
+	u32 internal_mac_transmit_err;
+	u32 good_frames_received;
+	u32 bad_frames_received;
+	u32 broadcast_frames_received;
+	u32 multicast_frames_received;
+	u32 frames_64_octets;
+	u32 frames_65_to_127_octets;
+	u32 frames_128_to_255_octets;
+	u32 frames_256_to_511_octets;
+	u32 frames_512_to_1023_octets;
+	u32 frames_1024_to_max_octets;
+	u64 good_octets_sent;
+	u32 good_frames_sent;
+	u32 excessive_collision;
+	u32 multicast_frames_sent;
+	u32 broadcast_frames_sent;
+	u32 unrec_mac_control_received;
+	u32 fc_sent;
+	u32 good_fc_received;
+	u32 bad_fc_received;
+	u32 undersize_received;
+	u32 fragments_received;
+	u32 oversize_received;
+	u32 jabber_received;
+	u32 mac_receive_error;
+	u32 bad_crc_event;
+	u32 collision;
+	u32 late_collision;
+};
+
+struct mv643xx_private {
+	int port_num;			/* User Ethernet port number	*/
+	u8 port_mac_addr[6];		/* User defined port MAC address.*/
+	u32 port_config;		/* User port configuration value*/
+	u32 port_config_extend;		/* User port config extend value*/
+	u32 port_sdma_config;		/* User port SDMA config value	*/
+	u32 port_serial_control;	/* User port serial control value */
+	u32 port_tx_queue_command;	/* Port active Tx queues summary*/
+	u32 port_rx_queue_command;	/* Port active Rx queues summary*/
+
+	u32 rx_sram_addr;		/* Base address of rx sram area */
+	u32 rx_sram_size;		/* Size of rx sram area		*/
+	u32 tx_sram_addr;		/* Base address of tx sram area */
+	u32 tx_sram_size;		/* Size of tx sram area		*/
 
-	int	rx_resource_err;	/* Rx ring resource error flag */
-	int	tx_resource_err;	/* Tx ring resource error flag */
+	int rx_resource_err;		/* Rx ring resource error flag */
+	int tx_resource_err;		/* Tx ring resource error flag */
 
 	/* Tx/Rx rings managment indexes fields. For driver use */
 
@@ -509,30 +346,32 @@ struct mv64340_private {
 
 	/* Next available and first returning Tx resource */
 	int tx_curr_desc_q, tx_used_desc_q;
-#ifdef MV64340_CHECKSUM_OFFLOAD_TX
-        int tx_first_desc_q;
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+	int tx_first_desc_q;
+	u32 tx_first_command;
 #endif
 
-#ifdef MV64340_TX_FAST_REFILL
-	u32	tx_clean_threshold;
+#ifdef MV643XX_TX_FAST_REFILL
+	u32 tx_clean_threshold;
 #endif
 
-	volatile struct eth_rx_desc	* p_rx_desc_area;
-	dma_addr_t			rx_desc_dma;
-	unsigned int			rx_desc_area_size;
-	struct sk_buff			* rx_skb[MV64340_RX_QUEUE_SIZE];
-
-	volatile struct eth_tx_desc	* p_tx_desc_area;
-	dma_addr_t			tx_desc_dma;
-	unsigned int			tx_desc_area_size;
-	struct sk_buff			* tx_skb[MV64340_TX_QUEUE_SIZE];
+	struct eth_rx_desc *p_rx_desc_area;
+	dma_addr_t rx_desc_dma;
+	unsigned int rx_desc_area_size;
+	struct sk_buff **rx_skb;
+
+	struct eth_tx_desc *p_tx_desc_area;
+	dma_addr_t tx_desc_dma;
+	unsigned int tx_desc_area_size;
+	struct sk_buff **tx_skb;
 
-	struct work_struct		tx_timeout_task;
+	struct work_struct tx_timeout_task;
 
 	/*
-	 * Former struct mv64340_eth_priv members start here
+	 * Former struct mv643xx_eth_priv members start here
 	 */
 	struct net_device_stats stats;
+	struct mv643xx_mib_counters mib_counters;
 	spinlock_t lock;
 	/* Size of Tx Ring per queue */
 	unsigned int tx_ring_size;
@@ -544,13 +383,13 @@ struct mv64340_private {
 	unsigned int rx_ring_skbs;
 
 	/*
-	 * rx_task used to fill RX ring out of bottom half context 
+	 * rx_task used to fill RX ring out of bottom half context
 	 */
 	struct work_struct rx_task;
 
-	/* 
-	 * Used in case RX Ring is empty, which can be caused when 
-	 * system does not have resources (skb's) 
+	/*
+	 * Used in case RX Ring is empty, which can be caused when
+	 * system does not have resources (skb's)
 	 */
 	struct timer_list timeout;
 	long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES)));
@@ -563,9 +402,9 @@ struct mv64340_private {
 /* ethernet.h API list */
 
 /* Port operation control routines */
-static void eth_port_init(struct mv64340_private *mp);
+static void eth_port_init(struct mv643xx_private *mp);
 static void eth_port_reset(unsigned int eth_port_num);
-static int eth_port_start(struct mv64340_private *mp);
+static void eth_port_start(struct mv643xx_private *mp);
 
 static void ethernet_set_config_reg(unsigned int eth_port_num,
 				    unsigned int value);
@@ -576,26 +415,24 @@ static void eth_port_uc_addr_set(unsigne
 				 unsigned char *p_addr);
 
 /* PHY and MIB routines */
-static int ethernet_phy_reset(unsigned int eth_port_num);
+static void ethernet_phy_reset(unsigned int eth_port_num);
+
+static void eth_port_write_smi_reg(unsigned int eth_port_num,
+				   unsigned int phy_reg, unsigned int value);
 
-static int eth_port_write_smi_reg(unsigned int eth_port_num,
-				   unsigned int phy_reg,
-				   unsigned int value);
-
-static int eth_port_read_smi_reg(unsigned int eth_port_num,
-				  unsigned int phy_reg,
-				  unsigned int *value);
+static void eth_port_read_smi_reg(unsigned int eth_port_num,
+				  unsigned int phy_reg, unsigned int *value);
 
 static void eth_clear_mib_counters(unsigned int eth_port_num);
 
 /* Port data flow control routines */
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp,
-					 struct pkt_info * p_pkt_info);
-static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp,
-					      struct pkt_info * p_pkt_info);
-static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp,
-					    struct pkt_info * p_pkt_info);
-static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp,
-					      struct pkt_info * p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
+					 struct pkt_info *p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
+					      struct pkt_info *p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,
+					    struct pkt_info *p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp,
+					      struct pkt_info *p_pkt_info);
 
-#endif  /* __MV64340_ETH_H__ */
+#endif				/* __MV643XX_ETH_H__ */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2433,9 +2433,9 @@ static void __set_rx_mode(struct net_dev
 		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],
-				ioaddr + RxFilterData);
+			writel(HASH_TABLE + i, ioaddr + RxFilterAddr);
+			writel((mc_filter[i + 1] << 8) + mc_filter[i],
+			       ioaddr + RxFilterData);
 		}
 	}
 	writel(rx_mode, ioaddr + RxFilterAddr);
@@ -3162,7 +3162,7 @@ static void __devexit natsemi_remove1 (s
  * Interrupts must be disabled, otherwise hands_off can cause irq storms.
  */
 
-static int natsemi_suspend (struct pci_dev *pdev, u32 state)
+static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -654,13 +654,13 @@ static void __devexit ne2k_pci_remove_on
 }
 
 #ifdef CONFIG_PM
-static int ne2k_pci_suspend (struct pci_dev *pdev, u32 state)
+static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 
 	netif_device_detach(dev);
 	pci_save_state(pdev);
-	pci_set_power_state(pdev, state);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
 	return 0;
 }
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -358,6 +358,7 @@ static struct eisa_driver ne3210_eisa_dr
 
 MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
 MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(eisa, ne3210_ids);
 
 int ne3210_init(void)
 {
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -60,6 +60,7 @@ static struct netpoll np = {
 	.local_port = 6665,
 	.remote_port = 6666,
 	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+	.drop = netpoll_queue,
 };
 static int configured = 0;
 
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -526,8 +526,7 @@ static int __init ni65_probe1(struct net
 			ni65_init_lance(p,dev->dev_addr,0,0);
 			irq_mask = probe_irq_on();
 			writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ/50);
+			msleep(20);
 			dev->irq = probe_irq_off(irq_mask);
 			if(!dev->irq)
 			{
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define _VERSION "0.20"
+#define VERSION "0.22"
 /* ns83820.c by Benjamin LaHaise with contributions.
  *
  * Questions/comments/discussion to linux-ns83820@kvack.org.
@@ -63,9 +63,11 @@
  *			     -	fix missed txok introduced during performance
  *				tuning
  *			0.20 -	fix stupid RFEN thinko.  i am such a smurf.
- *
  *	20040828	0.21 -	add hardware vlan accleration
  *				by Neil Horman <nhorman@redhat.com>
+ *	20050406	0.22 -	improved DAC ifdefs from Andi Kleen	
+ *			     -	removal of dead code from Adrian Bunk
+ *			     -	fix half duplex collision behaviour
  * Driver Overview
  * ===============
  *
@@ -129,18 +131,6 @@ static int lnksts = 0;		/* CFG_LNKSTS bi
 #undef Dprintk
 #define	Dprintk			dprintk
 
-#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
-#define USE_64BIT_ADDR	"+"
-#endif
-
-#if defined(USE_64BIT_ADDR)
-#define	VERSION	_VERSION USE_64BIT_ADDR
-#define TRY_DAC	1
-#else
-#define	VERSION	_VERSION
-#define TRY_DAC	0
-#endif
-
 /* tunables */
 #define RX_BUF_SIZE	1500	/* 8192 */
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -386,22 +376,16 @@ static int lnksts = 0;		/* CFG_LNKSTS bi
 #define LINK_DOWN		0x02
 #define LINK_UP			0x04
 
-#ifdef USE_64BIT_ADDR
-#define HW_ADDR_LEN	8
+#define HW_ADDR_LEN	sizeof(dma_addr_t) 
 #define desc_addr_set(desc, addr)				\
 	do {							\
-		u64 __addr = (addr);				\
-		(desc)[0] = cpu_to_le32(__addr);		\
-		(desc)[1] = cpu_to_le32(__addr >> 32);		\
+		((desc)[0] = cpu_to_le32(addr));		\
+		if (HW_ADDR_LEN == 8)		 		\
+			(desc)[1] = cpu_to_le32(((u64)addr) >> 32);	\
 	} while(0)
 #define desc_addr_get(desc)					\
-		(((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)[0] = cpu_to_le32(addr))
-#define desc_addr_get(desc)		(le32_to_cpu((desc)[0]))
-#endif
+	(le32_to_cpu((desc)[0]) | \
+	(HW_ADDR_LEN == 8 ? ((dma_addr_t)le32_to_cpu((desc)[1]))<<32 : 0))
 
 #define DESC_LINK		0
 #define DESC_BUFPTR		(DESC_LINK + HW_ADDR_LEN/4)
@@ -727,11 +711,23 @@ static void fastcall phy_intr(struct net
 		speed = ((cfg / CFG_SPDSTS0) & 3);
 		fullduplex = (cfg & CFG_DUPSTS);
 
-		if (fullduplex)
+		if (fullduplex) {
 			new_cfg |= CFG_SB;
+			writel(readl(dev->base + TXCFG)
+					| TXCFG_CSI | TXCFG_HBI,
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+			       dev->base + RXCFG);
+		} else {
+			writel(readl(dev->base + TXCFG)
+					& ~(TXCFG_CSI | TXCFG_HBI),
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) & ~(RXCFG_RX_FD),
+			       dev->base + RXCFG);
+		}
 
 		if ((cfg & CFG_LNKSTS) &&
-		    ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+		    ((new_cfg ^ dev->CFG_cache) != 0)) {
 			writel(new_cfg, dev->base + CFG);
 			dev->CFG_cache = new_cfg;
 		}
@@ -1189,7 +1185,6 @@ again:
 
 	for (;;) {
 		volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE);
-		u32 residue = 0;
 
 		dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
 			(unsigned long long)buf);
@@ -1199,17 +1194,11 @@ again:
 		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 = ((nr_frags) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
 		cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
 		cmdsts |= len;
 		desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
 
-		if (residue) {
-			buf += len;
-			len = residue;
-			continue;
-		}
-
 		if (!nr_frags)
 			break;
 
@@ -1841,7 +1830,8 @@ static int __devinit ns83820_init_one(st
 	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, 0xffffffffffffffffULL)) {
+	if (sizeof(dma_addr_t) == 8 && 
+	 	!pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
 		using_dac = 1;
 	} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
 		using_dac = 0;
@@ -1972,9 +1962,8 @@ static int __devinit ns83820_init_one(st
 	/* 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
+	if (sizeof(dma_addr_t) == 8) 
+		dev->CFG_cache |= CFG_M64ADDR;
 	if (using_dac)
 		dev->CFG_cache |= CFG_T64ADDR;
 
@@ -2007,8 +1996,7 @@ static int __devinit ns83820_init_one(st
 	if (reset_phy) {
 		printk(KERN_INFO "%s: resetting phy\n", ndev->name);
 		writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((HZ+99)/100);
+		msleep(10);
 		writel(dev->CFG_cache, dev->base + CFG);
 	}
 
@@ -2204,7 +2192,7 @@ static void __exit ns83820_exit(void)
 	pci_unregister_driver(&driver);
 }
 
-MODULE_AUTHOR("Benjamin LaHaise <bcrl@redhat.com>");
+MODULE_AUTHOR("Benjamin LaHaise <bcrl@kvack.org>");
 MODULE_DESCRIPTION("National Semiconductor DP83820 10/100/1000 driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1897,7 +1897,7 @@ static void netdrv_set_rx_mode (struct n
 
 #ifdef CONFIG_PM
 
-static int netdrv_suspend (struct pci_dev *pdev, u32 state)
+static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdrv_private *tp = dev->priv;
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *
 		spin_lock_irqsave(&lp->window_lock, flags);
 		update_stats(dev);
 		spin_unlock_irqrestore(&lp->window_lock, flags);
+
+		/* force interrupts off */
+		outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
 	}
 
 	link->open--;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -343,7 +343,8 @@ static void ibmtr_config(dev_link_t *lin
     CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem));
 
     ti->sram_base = mem.CardOffset >> 12;
-    ti->sram_virt = (u_long)ioremap(req.Base, req.Size);
+    ti->sram_virt = ioremap(req.Base, req.Size);
+    ti->sram_phys = req.Base;
 
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
 
@@ -401,7 +402,7 @@ static void ibmtr_release(dev_link_t *li
     pcmcia_release_irq(link->handle, &link->irq);
     if (link->win) {
 	struct tok_info *ti = netdev_priv(dev);
-	iounmap((void *)ti->mmio);
+	iounmap(ti->mmio);
 	pcmcia_release_window(link->win);
 	pcmcia_release_window(info->sram_win_handle);
     }
@@ -433,7 +434,7 @@ static int ibmtr_event(event_t event, in
         if (link->state & DEV_CONFIG) {
 	    /* set flag to bypass normal interrupt code */
 	    struct tok_info *priv = netdev_priv(dev);
-	    priv->sram_virt |= 1;
+	    priv->sram_phys |= 1;
 	    netif_device_detach(dev);
         }
         break;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -415,11 +415,6 @@ next_tuple(client_handle_t handle, tuple
 #define PutByte(reg,value) outb((value), ioaddr+(reg))
 #define PutWord(reg,value) outw((value), ioaddr+(reg))
 
-#define Wait(n) do { \
-	set_current_state(TASK_UNINTERRUPTIBLE); \
-	schedule_timeout(n); \
-} while (0)
-
 /*====== Functions used for debugging =================================*/
 #if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */
 static void
@@ -1707,12 +1702,12 @@ hardreset(struct net_device *dev)
     SelectPage(4);
     udelay(1);
     PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
-    Wait(HZ/25);		     /* wait 40 msec */
+    msleep(40);				     /* wait 40 msec */
     if (local->mohawk)
 	PutByte(XIRCREG4_GPR1, 1);	 /* set bit 0: power up */
     else
 	PutByte(XIRCREG4_GPR1, 1 | 4);	 /* set bit 0: power up, bit 2: AIC */
-    Wait(HZ/50);		     /* wait 20 msec */
+    msleep(20);			     /* wait 20 msec */
 }
 
 static void
@@ -1726,9 +1721,9 @@ do_reset(struct net_device *dev, int ful
 
     hardreset(dev);
     PutByte(XIRCREG_CR, SoftReset); /* set */
-    Wait(HZ/50);		     /* wait 20 msec */
+    msleep(20);			     /* wait 20 msec */
     PutByte(XIRCREG_CR, 0);	     /* clear */
-    Wait(HZ/25);		     /* wait 40 msec */
+    msleep(40);			     /* wait 40 msec */
     if (local->mohawk) {
 	SelectPage(4);
 	/* set pin GP1 and GP2 to output  (0x0c)
@@ -1739,7 +1734,7 @@ do_reset(struct net_device *dev, int ful
     }
 
     /* give the circuits some time to power up */
-    Wait(HZ/2);		/* about 500ms */
+    msleep(500);			/* about 500ms */
 
     local->last_ptr_value = 0;
     local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4
@@ -1758,7 +1753,7 @@ do_reset(struct net_device *dev, int ful
 	SelectPage(0x42);
 	PutByte(XIRCREG42_SWC1, 0x80);
     }
-    Wait(HZ/25);		     /* wait 40 msec to let it complete */
+    msleep(40);			     /* wait 40 msec to let it complete */
 
   #ifdef PCMCIA_DEBUG
     if (pc_debug) {
@@ -1817,7 +1812,7 @@ do_reset(struct net_device *dev, int ful
 	    printk(KERN_INFO "%s: MII selected\n", dev->name);
 	    SelectPage(2);
 	    PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
-	    Wait(HZ/50);
+	    msleep(20);
 	} else {
 	    printk(KERN_INFO "%s: MII detected; using 10mbs\n",
 		   dev->name);
@@ -1826,7 +1821,7 @@ do_reset(struct net_device *dev, int ful
 		PutByte(XIRCREG42_SWC1, 0xC0);
 	    else  /* enable 10BaseT */
 		PutByte(XIRCREG42_SWC1, 0x80);
-	    Wait(HZ/25);	/* wait 40 msec to let it complete */
+	    msleep(40);			/* wait 40 msec to let it complete */
 	}
 	if (full_duplex)
 	    PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex));
@@ -1919,7 +1914,7 @@ init_mii(struct net_device *dev)
 	 * Fixme: Better to use a timer here!
 	 */
 	for (i=0; i < 35; i++) {
-	    Wait(HZ/10);	 /* wait 100 msec */
+	    msleep(100);	 /* wait 100 msec */
 	    status = mii_rd(ioaddr,  0, 1);
 	    if ((status & 0x0020) && (status & 0x0004))
 		break;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -22,8 +22,8 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.30i"
-#define DRV_RELDATE	"06.28.2004"
+#define DRV_VERSION	"1.30j"
+#define DRV_RELDATE	"29.04.2005"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
@@ -256,6 +256,7 @@ static int homepna[MAX_UNITS];
  *	   homepna for selecting HomePNA mode for PCNet/Home 79C978.
  * v1.30h  24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32.
  * v1.30i  28 Jun 2004 Don Fry change to use module_param.
+ * v1.30j  29 Apr 2005 Don Fry fix skb/map leak with loopback test.
  */
 
 
@@ -395,6 +396,7 @@ static void pcnet32_led_blink_callback(s
 static int pcnet32_get_regs_len(struct net_device *dev);
 static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 	void *ptr);
+static void pcnet32_purge_tx_ring(struct net_device *dev);
 
 enum pci_flags_bit {
     PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -785,6 +787,7 @@ static int pcnet32_loopback_test(struct 
     }
 
 clean_up:
+    pcnet32_purge_tx_ring(dev);
     x = a->read_csr(ioaddr, 15) & 0xFFFF;
     a->write_csr(ioaddr, 15, (x & ~0x0044));	/* reset bits 6 and 2 */
 
@@ -1351,7 +1354,8 @@ pcnet32_probe1(unsigned long ioaddr, int
 	printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name);
     cards_found++;
 
-    a->write_bcr(ioaddr, 2, 0x1002);	/* enable LED writes */
+    /* enable LED writes */
+    a->write_bcr(ioaddr, 2, a->read_bcr(ioaddr, 2) | 0x1000);
 
     return 0;
 
@@ -1429,25 +1433,36 @@ pcnet32_open(struct net_device *dev)
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
 
-    /* 24 Jun 2004 according AMD, in order to change the PHY,
-     * DANAS (or DISPM for 79C976) must be set; then select the speed,
-     * duplex, and/or enable auto negotiation, and clear DANAS */
-    if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
-	lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
-	/* disable Auto Negotiation, set 10Mpbs, HD */
-	val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
-	if (lp->options & PCNET32_PORT_FD)
-	    val |= 0x10;
-	if (lp->options & PCNET32_PORT_100)
-	    val |= 0x08;
-	lp->a.write_bcr (ioaddr, 32, val);
+    /* Allied Telesyn AT 2700/2701 FX looses the link, so skip that */
+    if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT &&
+        (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX ||
+	 lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
+	printk(KERN_DEBUG "%s: Skipping PHY selection.\n", dev->name);
     } else {
-	if (lp->options & PCNET32_PORT_ASEL) {
-	    lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
-	    /* enable auto negotiate, setup, disable fd */
-	    val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
-	    val |= 0x20;
-	    lp->a.write_bcr(ioaddr, 32, val);
+	/*
+	 * 24 Jun 2004 according AMD, in order to change the PHY,
+	 * DANAS (or DISPM for 79C976) must be set; then select the speed,
+	 * duplex, and/or enable auto negotiation, and clear DANAS
+	 */
+	if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
+	    lp->a.write_bcr(ioaddr, 32,
+				lp->a.read_bcr(ioaddr, 32) | 0x0080);
+	    /* disable Auto Negotiation, set 10Mpbs, HD */
+	    val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
+	    if (lp->options & PCNET32_PORT_FD)
+		val |= 0x10;
+	    if (lp->options & PCNET32_PORT_100)
+		val |= 0x08;
+	    lp->a.write_bcr (ioaddr, 32, val);
+	} else {
+	    if (lp->options & PCNET32_PORT_ASEL) {
+		lp->a.write_bcr(ioaddr, 32,
+			lp->a.read_bcr(ioaddr, 32) | 0x0080);
+		/* enable auto negotiate, setup, disable fd */
+		val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
+		val |= 0x20;
+		lp->a.write_bcr(ioaddr, 32, val);
+	    }
 	}
     }
 
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -1000,7 +1000,7 @@ static void async_lcp_peek(struct asyncp
 	data += 4;
 	dlen -= 4;
 	/* data[0] is code, data[1] is length */
-	while (dlen >= 2 && dlen >= data[1]) {
+	while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) {
 		switch (data[0]) {
 		case LCP_MRU:
 			val = (data[2] << 8) + data[3];
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -87,8 +87,7 @@ static void z_comp_free(void *arg)
 
 	if (state) {
 		zlib_deflateEnd(&state->strm);
-		if (state->strm.workspace)
-			vfree(state->strm.workspace);
+		vfree(state->strm.workspace);
 		kfree(state);
 	}
 }
@@ -308,8 +307,7 @@ static void z_decomp_free(void *arg)
 
 	if (state) {
 		zlib_inflateEnd(&state->strm);
-		if (state->strm.workspace)
-			kfree(state->strm.workspace);
+		kfree(state->strm.workspace);
 		kfree(state);
 	}
 }
@@ -600,7 +598,7 @@ extern void ppp_unregister_compressor (s
 /*
  * Procedures exported to if_ppp.c.
  */
-struct compressor ppp_deflate = {
+static struct compressor ppp_deflate = {
 	.compress_proto =	CI_DEFLATE,
 	.comp_alloc =		z_comp_alloc,
 	.comp_free =		z_comp_free,
@@ -618,7 +616,7 @@ struct compressor ppp_deflate = {
 	.owner =		THIS_MODULE
 };
 
-struct compressor ppp_deflate_draft = {
+static struct compressor ppp_deflate_draft = {
 	.compress_proto =	CI_DEFLATE_DRAFT,
 	.comp_alloc =		z_comp_alloc,
 	.comp_free =		z_comp_free,
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2467,14 +2467,10 @@ static void ppp_destroy_interface(struct
 	skb_queue_purge(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
 #ifdef CONFIG_PPP_FILTER
-	if (ppp->pass_filter) {
-		kfree(ppp->pass_filter);
-		ppp->pass_filter = NULL;
-	}
-	if (ppp->active_filter) {
-		kfree(ppp->active_filter);
-		ppp->active_filter = NULL;
-	}
+	kfree(ppp->pass_filter);
+	ppp->pass_filter = NULL;
+	kfree(ppp->active_filter);
+	ppp->active_filter = NULL;
 #endif /* CONFIG_PPP_FILTER */
 
 	kfree(ppp);
@@ -2741,8 +2737,6 @@ EXPORT_SYMBOL(ppp_input_error);
 EXPORT_SYMBOL(ppp_output_wakeup);
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
-EXPORT_SYMBOL(all_ppp_units); /* for debugging */
-EXPORT_SYMBOL(all_channels); /* for debugging */
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(PPP_MAJOR);
 MODULE_ALIAS("/dev/ppp");
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -120,17 +120,17 @@ static int hash_item(unsigned long sid, 
 }
 
 /* zeroed because its in .bss */
-static struct pppox_opt *item_hash_table[PPPOE_HASH_SIZE];
+static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE];
 
 /**********************************************************************
  *
  *  Set/get/delete/rehash items  (internal versions)
  *
  **********************************************************************/
-static struct pppox_opt *__get_item(unsigned long sid, unsigned char *addr)
+static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr)
 {
 	int hash = hash_item(sid, addr);
-	struct pppox_opt *ret;
+	struct pppox_sock *ret;
 
 	ret = item_hash_table[hash];
 
@@ -140,10 +140,10 @@ static struct pppox_opt *__get_item(unsi
 	return ret;
 }
 
-static int __set_item(struct pppox_opt *po)
+static int __set_item(struct pppox_sock *po)
 {
 	int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
-	struct pppox_opt *ret;
+	struct pppox_sock *ret;
 
 	ret = item_hash_table[hash];
 	while (ret) {
@@ -161,10 +161,10 @@ static int __set_item(struct pppox_opt *
 	return 0;
 }
 
-static struct pppox_opt *__delete_item(unsigned long sid, char *addr)
+static struct pppox_sock *__delete_item(unsigned long sid, char *addr)
 {
 	int hash = hash_item(sid, addr);
-	struct pppox_opt *ret, **src;
+	struct pppox_sock *ret, **src;
 
 	ret = item_hash_table[hash];
 	src = &item_hash_table[hash];
@@ -187,26 +187,26 @@ static struct pppox_opt *__delete_item(u
  *  Set/get/delete/rehash items
  *
  **********************************************************************/
-static inline struct pppox_opt *get_item(unsigned long sid,
+static inline struct pppox_sock *get_item(unsigned long sid,
 					 unsigned char *addr)
 {
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 
 	read_lock_bh(&pppoe_hash_lock);
 	po = __get_item(sid, addr);
 	if (po)
-		sock_hold(po->sk);
+		sock_hold(sk_pppox(po));
 	read_unlock_bh(&pppoe_hash_lock);
 
 	return po;
 }
 
-static inline struct pppox_opt *get_item_by_addr(struct sockaddr_pppox *sp)
+static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
 {
 	return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote);
 }
 
-static inline int set_item(struct pppox_opt *po)
+static inline int set_item(struct pppox_sock *po)
 {
 	int i;
 
@@ -220,9 +220,9 @@ static inline int set_item(struct pppox_
 	return i;
 }
 
-static inline struct pppox_opt *delete_item(unsigned long sid, char *addr)
+static inline struct pppox_sock *delete_item(unsigned long sid, char *addr)
 {
-	struct pppox_opt *ret;
+	struct pppox_sock *ret;
 
 	write_lock_bh(&pppoe_hash_lock);
 	ret = __delete_item(sid, addr);
@@ -248,11 +248,11 @@ static void pppoe_flush_dev(struct net_d
 
 	read_lock_bh(&pppoe_hash_lock);
 	for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) {
-		struct pppox_opt *po = item_hash_table[hash];
+		struct pppox_sock *po = item_hash_table[hash];
 
 		while (po != NULL) {
 			if (po->pppoe_dev == dev) {
-				struct sock *sk = po->sk;
+				struct sock *sk = sk_pppox(po);
 
 				sock_hold(sk);
 				po->pppoe_dev = NULL;
@@ -331,14 +331,16 @@ static struct notifier_block pppoe_notif
  ***********************************************************************/
 static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
 {
-	struct pppox_opt *po = pppox_sk(sk);
-	struct pppox_opt *relay_po = NULL;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pppox_sock *relay_po = NULL;
 
 	if (sk->sk_state & PPPOX_BOUND) {
 		struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
 		int len = ntohs(ph->length);
 		skb_pull(skb, sizeof(struct pppoe_hdr));
-		skb_trim(skb, len);
+		skb_postpull_rcsum(skb, ph, sizeof(*ph));
+		if (pskb_trim_rcsum(skb, len))
+			goto abort_kfree;
 
 		ppp_input(&po->chan, skb);
 	} else if (sk->sk_state & PPPOX_RELAY) {
@@ -347,11 +349,11 @@ static int pppoe_rcv_core(struct sock *s
 		if (relay_po == NULL)
 			goto abort_kfree;
 
-		if ((relay_po->sk->sk_state & PPPOX_CONNECTED) == 0)
+		if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
 			goto abort_put;
 
 		skb_pull(skb, sizeof(struct pppoe_hdr));
-		if (!__pppoe_xmit( relay_po->sk, skb))
+		if (!__pppoe_xmit(sk_pppox(relay_po), skb))
 			goto abort_put;
 	} else {
 		if (sock_queue_rcv_skb(sk, skb))
@@ -361,7 +363,7 @@ static int pppoe_rcv_core(struct sock *s
 	return NET_RX_SUCCESS;
 
 abort_put:
-	sock_put(relay_po->sk);
+	sock_put(sk_pppox(relay_po));
 
 abort_kfree:
 	kfree_skb(skb);
@@ -379,7 +381,7 @@ static int pppoe_rcv(struct sk_buff *skb
 
 {
 	struct pppoe_hdr *ph;
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 	struct sock *sk;
 	int ret;
 
@@ -395,7 +397,7 @@ static int pppoe_rcv(struct sk_buff *skb
 	if (!po) 
 		goto drop;
 
-	sk = po->sk;
+	sk = sk_pppox(po);
 	bh_lock_sock(sk);
 
 	/* Socket state is unknown, must put skb into backlog. */
@@ -428,7 +430,7 @@ static int pppoe_disc_rcv(struct sk_buff
 
 {
 	struct pppoe_hdr *ph;
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 
 	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
 		goto abort;
@@ -442,7 +444,7 @@ static int pppoe_disc_rcv(struct sk_buff
 
 	po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source);
 	if (po) {
-		struct sock *sk = po->sk;
+		struct sock *sk = sk_pppox(po);
 
 		bh_lock_sock(sk);
 
@@ -478,19 +480,11 @@ static struct packet_type pppoed_ptype =
 	.func	= pppoe_disc_rcv,
 };
 
-/***********************************************************************
- *
- * Really kill the socket. (Called from pppox_sk_free if refcnt == 0.)
- *
- **********************************************************************/
-static void pppoe_sk_free(struct sock *sk)
-{
-	struct pppox_opt *po = pppox_sk(sk);
-
-	if (po)
-		kfree(po);
-}
-
+static struct proto pppoe_sk_proto = {
+	.name	  = "PPPOE",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct pppox_sock),
+};
 
 /***********************************************************************
  *
@@ -501,14 +495,13 @@ static int pppoe_create(struct socket *s
 {
 	int error = -ENOMEM;
 	struct sock *sk;
-	struct pppox_opt *po;
 
-	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
 	if (!sk)
 		goto out;
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
+
 	sock->state = SS_UNCONNECTED;
 	sock->ops   = &pppoe_ops;
 
@@ -517,23 +510,15 @@ static int pppoe_create(struct socket *s
 	sk->sk_type	   = SOCK_STREAM;
 	sk->sk_family	   = PF_PPPOX;
 	sk->sk_protocol	   = PX_PROTO_OE;
-	sk->sk_destruct	   = pppoe_sk_free;
 
-	po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL);
-	if (!po)
-		goto frees;
-	memset(po, 0, sizeof(*po));
-	po->sk = sk;
 	error = 0;
 out:	return error;
-frees:	sk_free(sk);
-	goto out;
 }
 
 static int pppoe_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 	int error = 0;
 
 	if (!sk)
@@ -573,7 +558,7 @@ static int pppoe_connect(struct socket *
 	struct sock *sk = sock->sk;
 	struct net_device *dev = NULL;
 	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
-	struct pppox_opt *po = pppox_sk(sk);
+	struct pppox_sock *po = pppox_sk(sk);
 	int error;
 
 	lock_sock(sk);
@@ -602,8 +587,8 @@ static int pppoe_connect(struct socket *
 		if(po->pppoe_dev)
 			dev_put(po->pppoe_dev);
 
-		memset(po, 0, sizeof(struct pppox_opt));
-		po->sk = sk;
+		memset(sk_pppox(po) + 1, 0,
+		       sizeof(struct pppox_sock) - sizeof(struct sock));
 
 		sk->sk_state = PPPOX_NONE;
 	}
@@ -679,7 +664,7 @@ static int pppoe_ioctl(struct socket *so
 		unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	struct pppox_opt *po = pppox_sk(sk);
+	struct pppox_sock *po = pppox_sk(sk);
 	int val = 0;
 	int err = 0;
 
@@ -725,7 +710,7 @@ static int pppoe_ioctl(struct socket *so
 
 	case PPPOEIOCSFWD:
 	{
-		struct pppox_opt *relay_po;
+		struct pppox_sock *relay_po;
 
 		err = -EBUSY;
 		if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD))
@@ -755,7 +740,7 @@ static int pppoe_ioctl(struct socket *so
 		if (!relay_po)
 			break;
 
-		sock_put(relay_po->sk);
+		sock_put(sk_pppox(relay_po));
 		sk->sk_state |= PPPOX_RELAY;
 		err = 0;
 		break;
@@ -782,7 +767,7 @@ static int pppoe_sendmsg(struct kiocb *i
 {
 	struct sk_buff *skb = NULL;
 	struct sock *sk = sock->sk;
-	struct pppox_opt *po = pppox_sk(sk);
+	struct pppox_sock *po = pppox_sk(sk);
 	int error = 0;
 	struct pppoe_hdr hdr;
 	struct pppoe_hdr *ph;
@@ -857,7 +842,7 @@ end:
  ***********************************************************************/
 static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
 {
-	struct pppox_opt *po = pppox_sk(sk);
+	struct pppox_sock *po = pppox_sk(sk);
 	struct net_device *dev = po->pppoe_dev;
 	struct pppoe_hdr hdr;
 	struct pppoe_hdr *ph;
@@ -984,7 +969,7 @@ end:
 #ifdef CONFIG_PROC_FS
 static int pppoe_seq_show(struct seq_file *seq, void *v)
 {
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 	char *dev_name;
 
 	if (v == SEQ_START_TOKEN) {
@@ -1004,9 +989,9 @@ out:
 	return 0;
 }
 
-static __inline__ struct pppox_opt *pppoe_get_idx(loff_t pos)
+static __inline__ struct pppox_sock *pppoe_get_idx(loff_t pos)
 {
-	struct pppox_opt *po = NULL;
+	struct pppox_sock *po = NULL;
 	int i = 0;
 
 	for (; i < PPPOE_HASH_SIZE; i++) {
@@ -1031,7 +1016,7 @@ static void *pppoe_seq_start(struct seq_
 
 static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct pppox_opt *po;
+	struct pppox_sock *po;
 
 	++*pos;
 	if (v == SEQ_START_TOKEN) {
@@ -1059,7 +1044,7 @@ static void pppoe_seq_stop(struct seq_fi
 	read_unlock_bh(&pppoe_hash_lock);
 }
 
-struct seq_operations pppoe_seq_ops = {
+static struct seq_operations pppoe_seq_ops = {
 	.start		= pppoe_seq_start,
 	.next		= pppoe_seq_next,
 	.stop		= pppoe_seq_stop,
@@ -1124,22 +1109,29 @@ static struct pppox_proto pppoe_proto = 
 
 static int __init pppoe_init(void)
 {
- 	int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
+	int err = proto_register(&pppoe_sk_proto, 0);
 
 	if (err)
 		goto out;
 
+ 	err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
+	if (err)
+		goto out_unregister_pppoe_proto;
+
 	err = pppoe_proc_init();
-	if (err) {
-		unregister_pppox_proto(PX_PROTO_OE);
-		goto out;
-	}
+	if (err)
+		goto out_unregister_pppox_proto;
 	
 	dev_add_pack(&pppoes_ptype);
 	dev_add_pack(&pppoed_ptype);
 	register_netdevice_notifier(&pppoe_notifier);
 out:
 	return err;
+out_unregister_pppox_proto:
+	unregister_pppox_proto(PX_PROTO_OE);
+out_unregister_pppoe_proto:
+	proto_unregister(&pppoe_sk_proto);
+	goto out;
 }
 
 static void __exit pppoe_exit(void)
@@ -1149,6 +1141,7 @@ static void __exit pppoe_exit(void)
 	dev_remove_pack(&pppoed_ptype);
 	unregister_netdevice_notifier(&pppoe_notifier);
 	remove_proc_entry("pppoe", proc_net);
+	proto_unregister(&pppoe_sk_proto);
 }
 
 module_init(pppoe_init);
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -72,7 +72,7 @@ static int pppox_ioctl(struct socket* so
 		       unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	struct pppox_opt *po = pppox_sk(sk);
+	struct pppox_sock *po = pppox_sk(sk);
 	int rc = 0;
 
 	lock_sock(sk);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -415,7 +415,7 @@ struct rtl8169_private {
 	struct work_struct task;
 };
 
-MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@oss.sgi.com>");
+MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
 module_param_array(media, int, &num_media, 0);
 module_param(rx_copybreak, int, 0);
@@ -1180,7 +1180,7 @@ rtl8169_init_board(struct pci_dev *pdev,
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
 	rc = pci_enable_device(pdev);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name);
+		printk(KERN_ERR PFX "%s: enable failure\n", pci_name(pdev));
 		goto err_out_free_dev;
 	}
 
@@ -1218,7 +1218,7 @@ rtl8169_init_board(struct pci_dev *pdev,
 	rc = pci_request_regions(pdev, MODULENAME);
 	if (rc) {
 		printk(KERN_ERR PFX "%s: could not request regions.\n",
-		       pdev->slot_name);
+		       pci_name(pdev));
 		goto err_out_mwi;
 	}
 
@@ -1449,7 +1449,7 @@ rtl8169_remove_one(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
-static int rtl8169_suspend(struct pci_dev *pdev, u32 state)
+static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
 	RTL_W8(EarlyTxThres, EarlyTxThld);
 
-	/* For gigabit rtl8169, MTU + header + CRC + VLAN */
-	RTL_W16(RxMaxSize, tp->rx_buf_sz);
+	/* Low hurts. Let's disable the filtering. */
+	RTL_W16(RxMaxSize, 16383);
 
 	/* Set Rx Config register */
 	i = rtl8169_rx_config |
@@ -1683,16 +1683,19 @@ static void rtl8169_free_rx_skb(struct r
 	rtl8169_make_unusable_by_asic(desc);
 }
 
-static inline void rtl8169_return_to_asic(struct RxDesc *desc, int rx_buf_sz)
+static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
 {
-	desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
+	u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
+
+	desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
 }
 
-static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping,
-					int rx_buf_sz)
+static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
+				       u32 rx_buf_sz)
 {
 	desc->addr = cpu_to_le64(mapping);
-	desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
+	wmb();
+	rtl8169_mark_to_asic(desc, rx_buf_sz);
 }
 
 static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
@@ -1712,7 +1715,7 @@ static int rtl8169_alloc_rx_skb(struct p
 	mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
 				 PCI_DMA_FROMDEVICE);
 
-	rtl8169_give_to_asic(desc, mapping, rx_buf_sz);
+	rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
 
 out:
 	return ret;
@@ -2124,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *
 	}
 }
 
+static inline int rtl8169_fragmented_frame(u32 status)
+{
+	return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
+}
+
 static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
 {
 	u32 opts1 = le32_to_cpu(desc->opts1);
@@ -2150,7 +2158,7 @@ static inline int rtl8169_try_rx_copy(st
 			skb_reserve(skb, NET_IP_ALIGN);
 			eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
 			*sk_buff = skb;
-			rtl8169_return_to_asic(desc, rx_buf_sz);
+			rtl8169_mark_to_asic(desc, rx_buf_sz);
 			ret = 0;
 		}
 	}
@@ -2174,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *
 
 	while (rx_left > 0) {
 		unsigned int entry = cur_rx % NUM_RX_DESC;
+		struct RxDesc *desc = tp->RxDescArray + entry;
 		u32 status;
 
 		rmb();
-		status = le32_to_cpu(tp->RxDescArray[entry].opts1);
+		status = le32_to_cpu(desc->opts1);
 
 		if (status & DescOwn)
 			break;
 		if (status & RxRES) {
-			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
+			printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
+			       dev->name, status);
 			tp->stats.rx_errors++;
 			if (status & (RxRWT | RxRUNT))
 				tp->stats.rx_length_errors++;
 			if (status & RxCRC)
 				tp->stats.rx_crc_errors++;
+			rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
 		} else {
-			struct RxDesc *desc = tp->RxDescArray + entry;
 			struct sk_buff *skb = tp->Rx_skbuff[entry];
 			int pkt_size = (status & 0x00001FFF) - 4;
 			void (*pci_action)(struct pci_dev *, dma_addr_t,
 				size_t, int) = pci_dma_sync_single_for_device;
 
+			/*
+			 * The driver does not support incoming fragmented
+			 * frames. They are seen as a symptom of over-mtu
+			 * sized frames.
+			 */
+			if (unlikely(rtl8169_fragmented_frame(status))) {
+				tp->stats.rx_dropped++;
+				tp->stats.rx_length_errors++;
+				rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+				goto move_on;
+			}
+
 			rtl8169_rx_csum(skb, desc);
 			
 			pci_dma_sync_single_for_cpu(tp->pci_dev,
@@ -2221,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *
 			tp->stats.rx_bytes += pkt_size;
 			tp->stats.rx_packets++;
 		}
-		
+move_on:		
 		cur_rx++; 
 		rx_left--;
 	}
@@ -2382,7 +2404,7 @@ core_down:
 	}
 
 	/* Give a racing hard_start_xmit a few cycles to complete. */
-	synchronize_kernel();
+	synchronize_sched();  /* FIXME: should this be synchronize_irq()? */
 
 	/*
 	 * And now for the 50k$ question: are IRQ disabled or not ?
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * regs.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
- * Copyright 2002 Raghavendra Koushik (raghavendra.koushik@s2io.com)
+ * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
- * Copyright(c) 2002-2005 S2IO Technologies
+ * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -36,28 +36,29 @@
  * in PCI Configuration space.
  ************************************************************************/
 
-#include<linux/config.h>
-#include<linux/module.h>
-#include<linux/types.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/init.h>
-#include<linux/delay.h>
-#include<linux/stddef.h>
-#include<linux/ioctl.h>
-#include<linux/timex.h>
-#include<linux/sched.h>
-#include<linux/ethtool.h>
-#include<asm/system.h>
-#include<asm/uaccess.h>
-#include<linux/version.h>
-#include<asm/io.h>
-#include<linux/workqueue.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.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/init.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioctl.h>
+#include <linux/timex.h>
+#include <linux/sched.h>
+#include <linux/ethtool.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
 
 /* local include */
 #include "s2io.h"
@@ -65,7 +66,7 @@
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "s2io";
-static char s2io_driver_version[] = "Version 1.7.5.1";
+static char s2io_driver_version[] = "Version 1.7.7.1";
 
 /* 
  * Cards with following subsystem_id have a link state indication
@@ -244,6 +245,10 @@ static struct pci_device_id s2io_tbl[] _
 	 PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
 	 PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
+	 PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
+	 PCI_ANY_ID, PCI_ANY_ID},
 	{0,}
 };
 
@@ -619,87 +624,22 @@ static int init_nic(struct s2io_nic *nic
 	mac_info_t *mac_control;
 	struct config_param *config;
 	int mdio_cnt = 0, dtx_cnt = 0;
-	unsigned long long print_var, mem_share;
+	unsigned long long mem_share;
 
 	mac_control = &nic->mac_control;
 	config = &nic->config;
 
-	/* 
-	 * Set proper endian settings and verify the same by 
-	 * reading the PIF Feed-back register.
-	 */
-#ifdef  __BIG_ENDIAN
-	/*
-	 * The device by default set to a big endian format, so 
-	 * a big endian driver need not set anything.
-	 */
-	writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl);
-	val64 = (SWAPPER_CTRL_PIF_R_FE |
-		 SWAPPER_CTRL_PIF_R_SE |
-		 SWAPPER_CTRL_PIF_W_FE |
-		 SWAPPER_CTRL_PIF_W_SE |
-		 SWAPPER_CTRL_TXP_FE |
-		 SWAPPER_CTRL_TXP_SE |
-		 SWAPPER_CTRL_TXD_R_FE |
-		 SWAPPER_CTRL_TXD_W_FE |
-		 SWAPPER_CTRL_TXF_R_FE |
-		 SWAPPER_CTRL_RXD_R_FE |
-		 SWAPPER_CTRL_RXD_W_FE |
-		 SWAPPER_CTRL_RXF_W_FE |
-		 SWAPPER_CTRL_XMSI_FE |
-		 SWAPPER_CTRL_XMSI_SE |
-		 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
-	writeq(val64, &bar0->swapper_ctrl);
-#else
-	/* 
-	 * Initially we enable all bits to make it accessible by 
-	 * the driver, then we selectively enable only those bits 
-	 * that we want to set.
-	 */
-	writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl);
-	val64 = (SWAPPER_CTRL_PIF_R_FE |
-		 SWAPPER_CTRL_PIF_R_SE |
-		 SWAPPER_CTRL_PIF_W_FE |
-		 SWAPPER_CTRL_PIF_W_SE |
-		 SWAPPER_CTRL_TXP_FE |
-		 SWAPPER_CTRL_TXP_SE |
-		 SWAPPER_CTRL_TXD_R_FE |
-		 SWAPPER_CTRL_TXD_R_SE |
-		 SWAPPER_CTRL_TXD_W_FE |
-		 SWAPPER_CTRL_TXD_W_SE |
-		 SWAPPER_CTRL_TXF_R_FE |
-		 SWAPPER_CTRL_RXD_R_FE |
-		 SWAPPER_CTRL_RXD_R_SE |
-		 SWAPPER_CTRL_RXD_W_FE |
-		 SWAPPER_CTRL_RXD_W_SE |
-		 SWAPPER_CTRL_RXF_W_FE |
-		 SWAPPER_CTRL_XMSI_FE |
-		 SWAPPER_CTRL_XMSI_SE |
-		 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
-	writeq(val64, &bar0->swapper_ctrl);
-#endif
-
-	/* 
-	 * Verifying if endian settings are accurate by 
-	 * reading a feedback register.
-	 */
-	val64 = readq(&bar0->pif_rd_swapper_fb);
-	if (val64 != 0x0123456789ABCDEFULL) {
-		/* Endian settings are incorrect, calls for another dekko. */
-		print_var = (unsigned long long) val64;
-		DBG_PRINT(INIT_DBG, "%s: Endian settings are wrong",
-			  dev->name);
-		DBG_PRINT(ERR_DBG, ", feedback read %llx\n", print_var);
-
-		return FAILURE;
+	/* Initialize swapper control register */
+	if (s2io_set_swapper(nic)) {
+		DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
+		return -1;
 	}
 
 	/* Remove XGXS from reset state */
 	val64 = 0;
 	writeq(val64, &bar0->sw_reset);
 	val64 = readq(&bar0->sw_reset);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 2);
+	msleep(500);
 
 	/*  Enable Receiving broadcasts */
 	add = &bar0->mac_cfg;
@@ -920,11 +860,15 @@ static int init_nic(struct s2io_nic *nic
 	 * Initializing the Transmit and Receive Traffic Interrupt 
 	 * Scheme.
 	 */
-	/* TTI Initialization */
-	val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0xFFF) |
+	/* TTI Initialization. Default Tx timer gets us about
+	 * 250 interrupts per sec. Continuous interrupts are enabled
+	 * by default.
+	 */
+	val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078) |
 	    TTI_DATA1_MEM_TX_URNG_A(0xA) |
 	    TTI_DATA1_MEM_TX_URNG_B(0x10) |
-	    TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
+	    TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN |
+		TTI_DATA1_MEM_TX_TIMER_CI_EN;
 	writeq(val64, &bar0->tti_data1_mem);
 
 	val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
@@ -952,8 +896,7 @@ static int init_nic(struct s2io_nic *nic
 				  dev->name);
 			return -1;
 		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 		time++;
 	}
 
@@ -991,8 +934,7 @@ static int init_nic(struct s2io_nic *nic
 			return -1;
 		}
 		time++;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 	}
 
 	/* 
@@ -1352,7 +1294,7 @@ static int verify_xena_quiescence(u64 va
  *
  */
 
-void fix_mac_address(nic_t * sp)
+static void fix_mac_address(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	u64 val64;
@@ -1421,8 +1363,7 @@ static int start_nic(struct s2io_nic *ni
 	SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
 	val64 = readq(&bar0->mc_rldram_mrs);
 
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 10);	/* Delay by around 100 ms. */
+	msleep(100);			/* Delay by around 100 ms. */
 
 	/* Enabling ECC Protection. */
 	val64 = readq(&bar0->adapter_control);
@@ -1509,7 +1450,7 @@ static int start_nic(struct s2io_nic *ni
  *  Return Value: void 
 */
 
-void free_tx_buffers(struct s2io_nic *nic)
+static void free_tx_buffers(struct s2io_nic *nic)
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *skb;
@@ -1600,7 +1541,7 @@ static void stop_nic(struct s2io_nic *ni
  *  SUCCESS on success or an appropriate -ve value on failure.
  */
 
-int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *skb;
@@ -2425,7 +2366,7 @@ static void alarm_intr_handler(struct s2
  *   SUCCESS on success and FAILURE on failure.
  */
 
-int wait_for_cmd_complete(nic_t * sp)
+static int wait_for_cmd_complete(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	int ret = FAILURE, cnt = 0;
@@ -2437,8 +2378,7 @@ int wait_for_cmd_complete(nic_t * sp)
 			ret = SUCCESS;
 			break;
 		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 		if (cnt++ > 10)
 			break;
 	}
@@ -2456,7 +2396,7 @@ int wait_for_cmd_complete(nic_t * sp)
  *  void.
  */
 
-void s2io_reset(nic_t * sp)
+static void s2io_reset(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	u64 val64;
@@ -2477,15 +2417,13 @@ void s2io_reset(nic_t * sp)
 	 * As of now I'am just giving a 250ms delay and hoping that the
 	 * PCI write to sw_reset register is done by this time.
 	 */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 4);
+	msleep(250);
 
 	/* Restore the PCI state saved during initializarion. */
 	pci_restore_state(sp->pdev);
 	s2io_init_pci(sp);
 
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 4);
+	msleep(250);
 
 	/* SXE-002: Configure link and activity LED to turn it off */
 	subid = sp->pdev->subsystem_device;
@@ -2510,27 +2448,78 @@ void s2io_reset(nic_t * sp)
  *  SUCCESS on success and FAILURE on failure.
  */
 
-int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(nic_t * sp)
 {
 	struct net_device *dev = sp->dev;
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
-	u64 val64;
+	u64 val64, valt, valr;
 
 	/* 
 	 * Set proper endian settings and verify the same by reading
 	 * the PIF Feed-back register.
 	 */
+
+	val64 = readq(&bar0->pif_rd_swapper_fb);
+	if (val64 != 0x0123456789ABCDEFULL) {
+		int i = 0;
+		u64 value[] = { 0xC30000C3C30000C3ULL,   /* FE=1, SE=1 */
+				0x8100008181000081ULL,  /* FE=1, SE=0 */
+				0x4200004242000042ULL,  /* FE=0, SE=1 */
+				0};                     /* FE=0, SE=0 */
+
+		while(i<4) {
+			writeq(value[i], &bar0->swapper_ctrl);
+			val64 = readq(&bar0->pif_rd_swapper_fb);
+			if (val64 == 0x0123456789ABCDEFULL)
+				break;
+			i++;
+		}
+		if (i == 4) {
+			DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
+				dev->name);
+			DBG_PRINT(ERR_DBG, "feedback read %llx\n",
+				(unsigned long long) val64);
+			return FAILURE;
+		}
+		valr = value[i];
+	} else {
+		valr = readq(&bar0->swapper_ctrl);
+	}
+
+	valt = 0x0123456789ABCDEFULL;
+	writeq(valt, &bar0->xmsi_address);
+	val64 = readq(&bar0->xmsi_address);
+
+	if(val64 != valt) {
+		int i = 0;
+		u64 value[] = { 0x00C3C30000C3C300ULL,  /* FE=1, SE=1 */
+				0x0081810000818100ULL,  /* FE=1, SE=0 */
+				0x0042420000424200ULL,  /* FE=0, SE=1 */
+				0};                     /* FE=0, SE=0 */
+
+		while(i<4) {
+			writeq((value[i] | valr), &bar0->swapper_ctrl);
+			writeq(valt, &bar0->xmsi_address);
+			val64 = readq(&bar0->xmsi_address);
+			if(val64 == valt)
+				break;
+			i++;
+		}
+		if(i == 4) {
+			DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
+			DBG_PRINT(ERR_DBG, "reads:0x%llx\n",val64);
+			return FAILURE;
+		}
+	}
+	val64 = readq(&bar0->swapper_ctrl);
+	val64 &= 0xFFFF000000000000ULL;
+
 #ifdef  __BIG_ENDIAN
 	/* 
 	 * The device by default set to a big endian format, so a 
 	 * big endian driver need not set anything.
 	 */
-	writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl);
-	val64 = (SWAPPER_CTRL_PIF_R_FE |
-		 SWAPPER_CTRL_PIF_R_SE |
-		 SWAPPER_CTRL_PIF_W_FE |
-		 SWAPPER_CTRL_PIF_W_SE |
-		 SWAPPER_CTRL_TXP_FE |
+	val64 |= (SWAPPER_CTRL_TXP_FE |
 		 SWAPPER_CTRL_TXP_SE |
 		 SWAPPER_CTRL_TXD_R_FE |
 		 SWAPPER_CTRL_TXD_W_FE |
@@ -2548,12 +2537,7 @@ int s2io_set_swapper(nic_t * sp)
 	 * driver, then we selectively enable only those bits that 
 	 * we want to set.
 	 */
-	writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl);
-	val64 = (SWAPPER_CTRL_PIF_R_FE |
-		 SWAPPER_CTRL_PIF_R_SE |
-		 SWAPPER_CTRL_PIF_W_FE |
-		 SWAPPER_CTRL_PIF_W_SE |
-		 SWAPPER_CTRL_TXP_FE |
+	val64 |= (SWAPPER_CTRL_TXP_FE |
 		 SWAPPER_CTRL_TXP_SE |
 		 SWAPPER_CTRL_TXD_R_FE |
 		 SWAPPER_CTRL_TXD_R_SE |
@@ -2570,6 +2554,7 @@ int s2io_set_swapper(nic_t * sp)
 		 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
 	writeq(val64, &bar0->swapper_ctrl);
 #endif
+	val64 = readq(&bar0->swapper_ctrl);
 
 	/* 
 	 * Verifying if endian settings are accurate by reading a 
@@ -2604,7 +2589,7 @@ int s2io_set_swapper(nic_t * sp)
  *   file on failure.
  */
 
-int s2io_open(struct net_device *dev)
+static int s2io_open(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	int err = 0;
@@ -2656,7 +2641,7 @@ int s2io_open(struct net_device *dev)
  *  file on failure.
  */
 
-int s2io_close(struct net_device *dev)
+static int s2io_close(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 
@@ -2683,7 +2668,7 @@ int s2io_close(struct net_device *dev)
  *  0 on success & 1 on failure.
  */
 
-int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
+static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
@@ -2903,7 +2888,7 @@ static irqreturn_t s2io_isr(int irq, voi
  *  pointer to the updated net_device_stats structure.
  */
 
-struct net_device_stats *s2io_get_stats(struct net_device *dev)
+static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	mac_info_t *mac_control;
@@ -3156,7 +3141,7 @@ static int s2io_ethtool_sset(struct net_
  * return 0 on success.
  */
 
-int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
+static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 {
 	nic_t *sp = dev->priv;
 	info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
@@ -3197,7 +3182,7 @@ static void s2io_ethtool_gdrvinfo(struct
 	strncpy(info->version, s2io_driver_version,
 		sizeof(s2io_driver_version));
 	strncpy(info->fw_version, "", 32);
-	strncpy(info->bus_info, sp->pdev->slot_name, 32);
+	strncpy(info->bus_info, pci_name(sp->pdev), 32);
 	info->regdump_len = XENA_REG_SPACE;
 	info->eedump_len = XENA_EEPROM_SPACE;
 	info->testinfo_len = S2IO_TEST_LEN;
@@ -3303,11 +3288,10 @@ static int s2io_ethtool_idnic(struct net
 		sp->id_timer.data = (unsigned long) sp;
 	}
 	mod_timer(&sp->id_timer, jiffies);
-	set_current_state(TASK_INTERRUPTIBLE);
 	if (data)
-		schedule_timeout(data * HZ);
+		msleep(data * 1000);
 	else
-		schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+		msleep(0xFFFFFFFF);
 	del_timer_sync(&sp->id_timer);
 
 	if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
@@ -3354,8 +3338,8 @@ static void s2io_ethtool_getpause_data(s
  * int, returns 0 on Success
  */
 
-int s2io_ethtool_setpause_data(struct net_device *dev,
-			       struct ethtool_pauseparam *ep)
+static int s2io_ethtool_setpause_data(struct net_device *dev,
+				      struct ethtool_pauseparam *ep)
 {
 	u64 val64;
 	nic_t *sp = dev->priv;
@@ -3410,8 +3394,7 @@ static int read_eeprom(nic_t * sp, int o
 			ret = 0;
 			break;
 		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 		exit_cnt++;
 	}
 
@@ -3451,8 +3434,7 @@ static int write_eeprom(nic_t * sp, int 
 				ret = 0;
 			break;
 		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 		exit_cnt++;
 	}
 
@@ -3472,8 +3454,8 @@ static int write_eeprom(nic_t * sp, int 
  *  int  0 on success
  */
 
-int s2io_ethtool_geeprom(struct net_device *dev,
-			 struct ethtool_eeprom *eeprom, u8 * data_buf)
+static int s2io_ethtool_geeprom(struct net_device *dev,
+				struct ethtool_eeprom *eeprom, u8 * data_buf)
 {
 	u32 data, i, valid;
 	nic_t *sp = dev->priv;
@@ -3708,8 +3690,7 @@ static int s2io_bist_test(nic_t * sp, ui
 			ret = 0;
 			break;
 		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 10);
+		msleep(100);
 		cnt++;
 	}
 
@@ -3810,8 +3791,7 @@ static int s2io_rldram_test(nic_t * sp, 
 			val64 = readq(&bar0->mc_rldram_test_ctrl);
 			if (val64 & MC_RLDRAM_TEST_DONE)
 				break;
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 5);
+			msleep(200);
 		}
 
 		if (cnt == 5)
@@ -3827,8 +3807,7 @@ static int s2io_rldram_test(nic_t * sp, 
 			val64 = readq(&bar0->mc_rldram_test_ctrl);
 			if (val64 & MC_RLDRAM_TEST_DONE)
 				break;
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 2);
+			msleep(500);
 		}
 
 		if (cnt == 5)
@@ -3932,60 +3911,61 @@ static void s2io_get_ethtool_stats(struc
 	nic_t *sp = dev->priv;
 	StatInfo_t *stat_info = sp->mac_control.stats_info;
 
-	tmp_stats[i++] = stat_info->tmac_frms;
-	tmp_stats[i++] = stat_info->tmac_data_octets;
-	tmp_stats[i++] = stat_info->tmac_drop_frms;
-	tmp_stats[i++] = stat_info->tmac_mcst_frms;
-	tmp_stats[i++] = stat_info->tmac_bcst_frms;
-	tmp_stats[i++] = stat_info->tmac_pause_ctrl_frms;
-	tmp_stats[i++] = stat_info->tmac_any_err_frms;
-	tmp_stats[i++] = stat_info->tmac_vld_ip_octets;
-	tmp_stats[i++] = stat_info->tmac_vld_ip;
-	tmp_stats[i++] = stat_info->tmac_drop_ip;
-	tmp_stats[i++] = stat_info->tmac_icmp;
-	tmp_stats[i++] = stat_info->tmac_rst_tcp;
-	tmp_stats[i++] = stat_info->tmac_tcp;
-	tmp_stats[i++] = stat_info->tmac_udp;
-	tmp_stats[i++] = stat_info->rmac_vld_frms;
-	tmp_stats[i++] = stat_info->rmac_data_octets;
-	tmp_stats[i++] = stat_info->rmac_fcs_err_frms;
-	tmp_stats[i++] = stat_info->rmac_drop_frms;
-	tmp_stats[i++] = stat_info->rmac_vld_mcst_frms;
-	tmp_stats[i++] = stat_info->rmac_vld_bcst_frms;
-	tmp_stats[i++] = stat_info->rmac_in_rng_len_err_frms;
-	tmp_stats[i++] = stat_info->rmac_long_frms;
-	tmp_stats[i++] = stat_info->rmac_pause_ctrl_frms;
-	tmp_stats[i++] = stat_info->rmac_discarded_frms;
-	tmp_stats[i++] = stat_info->rmac_usized_frms;
-	tmp_stats[i++] = stat_info->rmac_osized_frms;
-	tmp_stats[i++] = stat_info->rmac_frag_frms;
-	tmp_stats[i++] = stat_info->rmac_jabber_frms;
-	tmp_stats[i++] = stat_info->rmac_ip;
-	tmp_stats[i++] = stat_info->rmac_ip_octets;
-	tmp_stats[i++] = stat_info->rmac_hdr_err_ip;
-	tmp_stats[i++] = stat_info->rmac_drop_ip;
-	tmp_stats[i++] = stat_info->rmac_icmp;
-	tmp_stats[i++] = stat_info->rmac_tcp;
-	tmp_stats[i++] = stat_info->rmac_udp;
-	tmp_stats[i++] = stat_info->rmac_err_drp_udp;
-	tmp_stats[i++] = stat_info->rmac_pause_cnt;
-	tmp_stats[i++] = stat_info->rmac_accepted_ip;
-	tmp_stats[i++] = stat_info->rmac_err_tcp;
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_data_octets);
+	tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_mcst_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_bcst_frms);
+	tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_any_err_frms);
+	tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_vld_ip);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_drop_ip);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_icmp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_rst_tcp);
+	tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->tmac_udp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_data_octets);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_mcst_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_bcst_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_discarded_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_usized_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_osized_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_frag_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_jabber_frms);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ip);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_drop_ip);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_icmp);
+	tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_udp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_drp_udp);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pause_cnt);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_accepted_ip);
+	tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
 }
 
-int s2io_ethtool_get_regs_len(struct net_device *dev)
+static int s2io_ethtool_get_regs_len(struct net_device *dev)
 {
 	return (XENA_REG_SPACE);
 }
 
 
-u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
+static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
 	nic_t *sp = dev->priv;
 
 	return (sp->rx_csum);
 }
-int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+
+static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
 	nic_t *sp = dev->priv;
 
@@ -3996,17 +3976,19 @@ int s2io_ethtool_set_rx_csum(struct net_
 
 	return 0;
 }
-int s2io_get_eeprom_len(struct net_device *dev)
+
+static int s2io_get_eeprom_len(struct net_device *dev)
 {
 	return (XENA_EEPROM_SPACE);
 }
 
-int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_ethtool_self_test_count(struct net_device *dev)
 {
 	return (S2IO_TEST_LEN);
 }
-void s2io_ethtool_get_strings(struct net_device *dev,
-			      u32 stringset, u8 * data)
+
+static void s2io_ethtool_get_strings(struct net_device *dev,
+				     u32 stringset, u8 * data)
 {
 	switch (stringset) {
 	case ETH_SS_TEST:
@@ -4017,12 +3999,13 @@ void s2io_ethtool_get_strings(struct net
 		       sizeof(ethtool_stats_keys));
 	}
 }
+
 static int s2io_ethtool_get_stats_count(struct net_device *dev)
 {
 	return (S2IO_STAT_LEN);
 }
 
-int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 {
 	if (data)
 		dev->features |= NETIF_F_IP_CSUM;
@@ -4078,7 +4061,7 @@ static struct ethtool_ops netdev_ethtool
  *  function returns OP NOT SUPPORTED value.
  */
 
-int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	return -EOPNOTSUPP;
 }
@@ -4094,7 +4077,7 @@ int s2io_ioctl(struct net_device *dev, s
  *   file on failure.
  */
 
-int s2io_change_mtu(struct net_device *dev, int new_mtu)
+static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
 	nic_t *sp = dev->priv;
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -4188,8 +4171,7 @@ static void s2io_set_link(unsigned long 
 	 * Allow a small delay for the NICs self initiated 
 	 * cleanup to complete.
 	 */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 10);
+	msleep(100);
 
 	val64 = readq(&bar0->adapter_status);
 	if (verify_xena_quiescence(val64, nic->device_enabled_once)) {
@@ -4243,10 +4225,8 @@ static void s2io_card_down(nic_t * sp)
 	register u64 val64 = 0;
 
 	/* If s2io_set_link task is executing, wait till it completes. */
-	while (test_and_set_bit(0, &(sp->link_state))) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
-	}
+	while (test_and_set_bit(0, &(sp->link_state)))
+		msleep(50);
 	atomic_set(&sp->card_state, CARD_DOWN);
 
 	/* disable Tx and Rx traffic on the NIC */
@@ -4262,8 +4242,7 @@ static void s2io_card_down(nic_t * sp)
 			break;
 		}
 
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
+		msleep(50);
 		cnt++;
 		if (cnt == 10) {
 			DBG_PRINT(ERR_DBG,
@@ -4492,7 +4471,7 @@ static int rx_osm_handler(nic_t * sp, Rx
  *  void.
  */
 
-void s2io_link(nic_t * sp, int link)
+static void s2io_link(nic_t * sp, int link)
 {
 	struct net_device *dev = (struct net_device *) sp->dev;
 
@@ -4509,23 +4488,6 @@ void s2io_link(nic_t * sp, int link)
 }
 
 /**
- *  get_xena_rev_id - to identify revision ID of xena. 
- *  @pdev : PCI Dev structure
- *  Description:
- *  Function to identify the Revision ID of xena.
- *  Return value:
- *  returns the revision ID of the device.
- */
-
-int get_xena_rev_id(struct pci_dev *pdev)
-{
-	u8 id = 0;
-	int ret;
-	ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
-	return id;
-}
-
-/**
  *  s2io_init_pci -Initialization of PCI and PCI-X configuration registers . 
  *  @sp : private member of the device structure, which is a pointer to the 
  *  s2io_nic structure.
@@ -4576,7 +4538,7 @@ static void s2io_init_pci(nic_t * sp)
 			     &(sp->pcix_cmd));
 }
 
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@s2io.com>");
+MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
 MODULE_LICENSE("GPL");
 module_param(tx_fifo_num, int, 0);
 module_param_array(tx_fifo_len, int, NULL, 0);
@@ -4978,7 +4940,7 @@ int __init s2io_starter(void)
  * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
  */
 
-void s2io_closer(void)
+static void s2io_closer(void)
 {
 	pci_unregister_driver(&s2io_driver);
 	DBG_PRINT(INIT_DBG, "cleanup done\n");
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
- * Copyright 2002 Raghavendra Koushik (raghavendra.koushik@s2io.com)
+ * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -73,121 +73,6 @@ static int debug_level = ERR_DBG;	/* Def
 
 /* The statistics block of Xena */
 typedef struct stat_block {
-#ifdef  __BIG_ENDIAN
-/* Tx MAC statistics counters. */
-	u32 tmac_frms;
-	u32 tmac_data_octets;
-	u64 tmac_drop_frms;
-	u32 tmac_mcst_frms;
-	u32 tmac_bcst_frms;
-	u64 tmac_pause_ctrl_frms;
-	u32 tmac_ttl_octets;
-	u32 tmac_ucst_frms;
-	u32 tmac_nucst_frms;
-	u32 tmac_any_err_frms;
-	u64 tmac_ttl_less_fb_octets;
-	u64 tmac_vld_ip_octets;
-	u32 tmac_vld_ip;
-	u32 tmac_drop_ip;
-	u32 tmac_icmp;
-	u32 tmac_rst_tcp;
-	u64 tmac_tcp;
-	u32 tmac_udp;
-	u32 reserved_0;
-
-/* Rx MAC Statistics counters. */
-	u32 rmac_vld_frms;
-	u32 rmac_data_octets;
-	u64 rmac_fcs_err_frms;
-	u64 rmac_drop_frms;
-	u32 rmac_vld_mcst_frms;
-	u32 rmac_vld_bcst_frms;
-	u32 rmac_in_rng_len_err_frms;
-	u32 rmac_out_rng_len_err_frms;
-	u64 rmac_long_frms;
-	u64 rmac_pause_ctrl_frms;
-	u64 rmac_unsup_ctrl_frms;
-	u32 rmac_ttl_octets;
-	u32 rmac_accepted_ucst_frms;
-	u32 rmac_accepted_nucst_frms;
-	u32 rmac_discarded_frms;
-	u32 rmac_drop_events;
-	u32 reserved_1;
-	u64 rmac_ttl_less_fb_octets;
-	u64 rmac_ttl_frms;
-	u64 reserved_2;
-	u32 reserved_3;
-	u32 rmac_usized_frms;
-	u32 rmac_osized_frms;
-	u32 rmac_frag_frms;
-	u32 rmac_jabber_frms;
-	u32 reserved_4;
-	u64 rmac_ttl_64_frms;
-	u64 rmac_ttl_65_127_frms;
-	u64 reserved_5;
-	u64 rmac_ttl_128_255_frms;
-	u64 rmac_ttl_256_511_frms;
-	u64 reserved_6;
-	u64 rmac_ttl_512_1023_frms;
-	u64 rmac_ttl_1024_1518_frms;
-	u32 reserved_7;
-	u32 rmac_ip;
-	u64 rmac_ip_octets;
-	u32 rmac_hdr_err_ip;
-	u32 rmac_drop_ip;
-	u32 rmac_icmp;
-	u32 reserved_8;
-	u64 rmac_tcp;
-	u32 rmac_udp;
-	u32 rmac_err_drp_udp;
-	u64 rmac_xgmii_err_sym;
-	u64 rmac_frms_q0;
-	u64 rmac_frms_q1;
-	u64 rmac_frms_q2;
-	u64 rmac_frms_q3;
-	u64 rmac_frms_q4;
-	u64 rmac_frms_q5;
-	u64 rmac_frms_q6;
-	u64 rmac_frms_q7;
-	u16 rmac_full_q0;
-	u16 rmac_full_q1;
-	u16 rmac_full_q2;
-	u16 rmac_full_q3;
-	u16 rmac_full_q4;
-	u16 rmac_full_q5;
-	u16 rmac_full_q6;
-	u16 rmac_full_q7;
-	u32 rmac_pause_cnt;
-	u32 reserved_9;
-	u64 rmac_xgmii_data_err_cnt;
-	u64 rmac_xgmii_ctrl_err_cnt;
-	u32 rmac_accepted_ip;
-	u32 rmac_err_tcp;
-
-/* PCI/PCI-X Read transaction statistics. */
-	u32 rd_req_cnt;
-	u32 new_rd_req_cnt;
-	u32 new_rd_req_rtry_cnt;
-	u32 rd_rtry_cnt;
-	u32 wr_rtry_rd_ack_cnt;
-
-/* PCI/PCI-X write transaction statistics. */
-	u32 wr_req_cnt;
-	u32 new_wr_req_cnt;
-	u32 new_wr_req_rtry_cnt;
-	u32 wr_rtry_cnt;
-	u32 wr_disc_cnt;
-	u32 rd_rtry_wr_ack_cnt;
-
-/*	DMA Transaction statistics. */
-	u32 txp_wr_cnt;
-	u32 txd_rd_cnt;
-	u32 txd_wr_cnt;
-	u32 rxd_rd_cnt;
-	u32 rxd_wr_cnt;
-	u32 txf_rd_cnt;
-	u32 rxf_wr_cnt;
-#else
 /* Tx MAC statistics counters. */
 	u32 tmac_data_octets;
 	u32 tmac_frms;
@@ -301,7 +186,6 @@ typedef struct stat_block {
 	u32 rxd_rd_cnt;
 	u32 rxf_wr_cnt;
 	u32 txf_rd_cnt;
-#endif
 } StatInfo_t;
 
 /* Structures representing different init time configuration
@@ -848,7 +732,7 @@ static void tx_intr_handler(struct s2io_
 static void alarm_intr_handler(struct s2io_nic *sp);
 
 static int s2io_starter(void);
-void s2io_closer(void);
+static void s2io_closer(void);
 static void s2io_tx_watchdog(struct net_device *dev);
 static void s2io_tasklet(unsigned long dev_addr);
 static void s2io_set_multicast(struct net_device *dev);
@@ -858,17 +742,18 @@ static int rx_osm_handler(nic_t * sp, u1
 static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
 			  buffAdd_t * ba);
 #endif
-void s2io_link(nic_t * sp, int link);
-void s2io_reset(nic_t * sp);
+static void s2io_link(nic_t * sp, int link);
+static void s2io_reset(nic_t * sp);
 #ifdef CONFIG_S2IO_NAPI
 static int s2io_poll(struct net_device *dev, int *budget);
 #endif
 static void s2io_init_pci(nic_t * sp);
-int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
 static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
 static int verify_xena_quiescence(u64 val64, int flag);
 static struct ethtool_ops netdev_ethtool_ops;
 static void s2io_set_link(unsigned long data);
+static int s2io_set_swapper(nic_t * sp);
 static void s2io_card_down(nic_t * nic);
 static int s2io_card_up(nic_t * nic);
 
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -57,9 +57,9 @@ static char version[] = "sb1000.c:v1.1.2
 #include <asm/uaccess.h>
 
 #ifdef SB1000_DEBUG
-int sb1000_debug = SB1000_DEBUG;
+static int sb1000_debug = SB1000_DEBUG;
 #else
-int sb1000_debug = 1;
+static int sb1000_debug = 1;
 #endif
 
 static const int SB1000_IO_EXTENT = 8;
@@ -116,15 +116,15 @@ static inline int sb1000_start_get_set_c
 static inline int sb1000_end_get_set_command(const int ioaddr[],
 	const char* name);
 static inline int sb1000_activate(const int ioaddr[], const char* name);
-static inline int sb1000_get_firmware_version(const int ioaddr[],
+static int sb1000_get_firmware_version(const int ioaddr[],
 	const char* name, unsigned char version[], int do_end);
-static inline int sb1000_get_frequency(const int ioaddr[], const char* name,
+static int sb1000_get_frequency(const int ioaddr[], const char* name,
 	int* frequency);
-static inline int sb1000_set_frequency(const int ioaddr[], const char* name,
+static int sb1000_set_frequency(const int ioaddr[], const char* name,
 	int frequency);
-static inline int sb1000_get_PIDs(const int ioaddr[], const char* name,
+static int sb1000_get_PIDs(const int ioaddr[], const char* name,
 	short PID[]);
-static inline int sb1000_set_PIDs(const int ioaddr[], const char* name,
+static int sb1000_set_PIDs(const int ioaddr[], const char* name,
 	const short PID[]);
 
 /* SB1000 commands for frame rx interrupt */
@@ -252,7 +252,7 @@ static struct pnp_driver sb1000_driver =
  * SB1000 hardware routines to be used during open/configuration phases
  */
 
-const int TimeOutJiffies = (875 * HZ) / 100;
+static const int TimeOutJiffies = (875 * HZ) / 100;
 
 static inline void nicedelay(unsigned long usecs)
 {
@@ -363,7 +363,7 @@ card_send_command(const int ioaddr[], co
 /*
  * SB1000 hardware routines to be used during frame rx interrupt
  */
-const int Sb1000TimeOutJiffies = 7 * HZ;
+static const int Sb1000TimeOutJiffies = 7 * HZ;
 
 /* Card Wait For Ready (to be used during frame rx) */
 static inline int
@@ -552,7 +552,7 @@ sb1000_activate(const int ioaddr[], cons
 }
 
 /* get SB1000 firmware version */
-static inline int
+static int
 sb1000_get_firmware_version(const int ioaddr[], const char* name,
 	unsigned char version[], int do_end)
 {
@@ -575,7 +575,7 @@ sb1000_get_firmware_version(const int io
 }
 
 /* get SB1000 frequency */
-static inline int
+static int
 sb1000_get_frequency(const int ioaddr[], const char* name, int* frequency)
 {
 	unsigned char st[7];
@@ -592,7 +592,7 @@ sb1000_get_frequency(const int ioaddr[],
 }
 
 /* set SB1000 frequency */
-static inline int
+static int
 sb1000_set_frequency(const int ioaddr[], const char* name, int frequency)
 {
 	unsigned char st[7];
@@ -622,7 +622,7 @@ sb1000_set_frequency(const int ioaddr[],
 }
 
 /* get SB1000 PIDs */
-static inline int
+static int
 sb1000_get_PIDs(const int ioaddr[], const char* name, short PID[])
 {
 	unsigned char st[7];
@@ -656,7 +656,7 @@ sb1000_get_PIDs(const int ioaddr[], cons
 }
 
 /* set SB1000 PIDs */
-static inline int
+static int
 sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[])
 {
 	unsigned char st[7];
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -14,47 +14,11 @@
  * You 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 driver is designed for the Broadcom SiByte SOC built-in
+ * Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp.
  */
-
-/*
-  This driver is designed for the Broadcom SiByte SOC built-in
-  Ethernet controllers.
-  
-  Written by Mitch Lichtenberg at Broadcom Corp.
-*/
-
-
-
-#define CONFIG_SBMAC_COALESCE
-
-/* A few user-configurable values.
-   These may be modified when a driver module is loaded. */
-
-static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
-static int noisy_mii = 1;		/* mii status msgs */
-
-/* Used to pass the media type, etc.
-   Both 'options[]' and 'full_duplex[]' should exist for driver
-   interoperability.
-   The media type is usually passed in 'options[]'.
-*/
-
-#define MAX_UNITS 3		/* More are supported, limit only on options */
-#ifdef MODULE
-static int options[MAX_UNITS] = {-1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1};
-#endif
-
-#ifdef CONFIG_SBMAC_COALESCE
-static int int_pktcnt = 0;
-static int int_timeout = 0;
-#endif
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -89,16 +53,56 @@ static char version1[] __devinitdata =
 #endif
 
 
+/* Operational parameters that usually are not changed. */
+
+#define CONFIG_SBMAC_COALESCE
+
+#define MAX_UNITS 3		/* More are supported, limit only on options */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
 
 MODULE_AUTHOR("Mitch Lichtenberg (Broadcom Corp.)");
 MODULE_DESCRIPTION("Broadcom SiByte SOC GB Ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(noisy_mii, "i");
-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");
+/* A few user-configurable values which may be modified when a driver
+   module is loaded. */
+
+/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int debug = 1;
+module_param(debug, int, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug messages");
+
+/* mii status msgs */
+static int noisy_mii = 1;
+module_param(noisy_mii, int, S_IRUGO);
+MODULE_PARM_DESC(noisy_mii, "MII status messages");
+
+/* Used to pass the media type, etc.
+   Both 'options[]' and 'full_duplex[]' should exist for driver
+   interoperability.
+   The media type is usually passed in 'options[]'.
+*/
+#ifdef MODULE
+static int options[MAX_UNITS] = {-1, -1, -1};
+module_param_array(options, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
+
+static int full_duplex[MAX_UNITS] = {-1, -1, -1};
+module_param_array(full_duplex, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
+#endif
+
+#ifdef CONFIG_SBMAC_COALESCE
+static int int_pktcnt = 0;
+module_param(int_pktcnt, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt, "Packet count");
+
+static int int_timeout = 0;
+module_param(int_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout, "Timeout value");
+#endif
 
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_defs.h>
@@ -1811,8 +1815,6 @@ static void sbmac_set_iphdr_offset(struc
 	
 	/* read system identification to determine revision */
 	if (periph_rev >= 2) {
-		printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
-		       sc->sbm_dev->name);
 		sc->rx_hw_checksum = ENABLE;
 	} else {
 		sc->rx_hw_checksum = DISABLE;
@@ -2417,6 +2419,11 @@ static int sbmac_init(struct net_device 
 	if (err)
 		goto out_uninit;
 
+	if (periph_rev >= 2) {
+		printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
+			sc->sbm_dev->name);
+	}
+
 	/*
 	 * Display Ethernet address (this is called during the config
 	 * process so we need to finish off the config message that
@@ -2879,12 +2886,12 @@ sbmac_init_module(void)
 		dev->mem_end = 0;
 		if (sbmac_init(dev, idx)) {
 			port = A_MAC_CHANNEL_BASE(idx);
-			SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR),
-					sbmac_orig_hwaddr[idx] );
+			SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),
+				       sbmac_orig_hwaddr[idx]);
 			free_netdev(dev);
 			continue;
 		}
-		dev_sbmac[idx++] = dev;
+		dev_sbmac[idx] = dev;
 	}
 	return 0;
 }
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -136,9 +136,10 @@ static inline void seeq_go(struct sgisee
 	hregs->rx_ctrl = HPC3_ERXCTRL_ACTIVE;
 }
 
-static inline void seeq_load_eaddr(struct net_device *dev,
-				   struct sgiseeq_regs *sregs)
+static inline void __sgiseeq_set_mac_address(struct net_device *dev)
 {
+	struct sgiseeq_private *sp = netdev_priv(dev);
+	struct sgiseeq_regs *sregs = sp->sregs;
 	int i;
 
 	sregs->tstat = SEEQ_TCMD_RB0;
@@ -146,6 +147,20 @@ static inline void seeq_load_eaddr(struc
 		sregs->rw.eth_addr[i] = dev->dev_addr[i];
 }
 
+static int sgiseeq_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sgiseeq_private *sp = netdev_priv(dev);
+	struct sockaddr *sa = addr;
+
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+	spin_lock_irq(&sp->tx_lock);
+	__sgiseeq_set_mac_address(dev);
+	spin_unlock_irq(&sp->tx_lock);
+
+	return 0;
+}
+
 #define TCNTINFO_INIT (HPCDMA_EOX | HPCDMA_ETXD)
 #define RCNTCFG_INIT  (HPCDMA_OWN | HPCDMA_EORP | HPCDMA_XIE)
 #define RCNTINFO_INIT (RCNTCFG_INIT | (PKT_BUF_SZ & HPCDMA_BCNT))
@@ -159,13 +174,7 @@ static int seeq_init_ring(struct net_dev
 	sp->rx_new = sp->tx_new = 0;
 	sp->rx_old = sp->tx_old = 0;
 
-	seeq_load_eaddr(dev, sp->sregs);
-
-	/* XXX for now just accept packets directly to us
-	 * XXX and ether-broadcast.  Will do multicast and
-	 * XXX promiscuous mode later. -davem
-	 */
-	sp->mode = SEEQ_RCMD_RBCAST;
+	__sgiseeq_set_mac_address(dev);
 
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
@@ -175,7 +184,7 @@ static int seeq_init_ring(struct net_dev
 			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
 			if (!buffer)
 				return -ENOMEM;
-			sp->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
+			sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
 			sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer);
 		}
 		sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
@@ -189,7 +198,7 @@ static int seeq_init_ring(struct net_dev
 			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
 			if (!buffer)
 				return -ENOMEM;
-			sp->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
+			sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
 			sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer);
 		}
 		sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
@@ -331,10 +340,17 @@ static inline void sgiseeq_rx(struct net
 				/* Copy out of kseg1 to avoid silly cache flush. */
 				eth_copy_and_sum(skb, pkt_pointer + 2, len, 0);
 				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				sp->stats.rx_packets++;
-				sp->stats.rx_bytes += len;
+
+				/* We don't want to receive our own packets */
+				if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
+					netif_rx(skb);
+					dev->last_rx = jiffies;
+					sp->stats.rx_packets++;
+					sp->stats.rx_bytes += len;
+				} else {
+					/* Silently drop my own packets */
+					dev_kfree_skb_irq(skb);
+				}
 			} else {
 				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
@@ -373,7 +389,7 @@ static inline void kick_tx(struct sgisee
 	 */
 	while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
 	      (HPCDMA_XIU | HPCDMA_ETXD))
-		td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext);
+		td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext);
 	if (td->tdma.cntinfo & HPCDMA_XIU) {
 		hregs->tx_ndptr = CPHYSADDR(td);
 		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
@@ -583,6 +599,22 @@ static struct net_device_stats *sgiseeq_
 
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
+	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	unsigned char oldmode = sp->mode;
+
+	if(dev->flags & IFF_PROMISC)
+		sp->mode = SEEQ_RCMD_RANY;
+	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count)
+		sp->mode = SEEQ_RCMD_RBMCAST;
+	else
+		sp->mode = SEEQ_RCMD_RBCAST;
+
+	/* XXX I know this sucks, but is there a better way to reprogram
+	 * XXX the receiver? At least, this shouldn't happen too often.
+	 */
+
+	if (oldmode != sp->mode)
+		sgiseeq_reset(dev);
 }
 
 static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
@@ -651,13 +683,14 @@ static int sgiseeq_init(struct hpc3_regs
 	sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
 	sp->hregs = &hpc3c0->ethregs;
 	sp->name = sgiseeqstr;
+	sp->mode = SEEQ_RCMD_RBCAST;
 
 	sp->rx_desc = (struct sgiseeq_rx_desc *)
-	              KSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
+	              CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
 	dma_cache_wback_inv((unsigned long)&sp->srings->rxvector,
 	                    sizeof(sp->srings->rxvector));
 	sp->tx_desc = (struct sgiseeq_tx_desc *)
-	              KSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
+	              CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
 	dma_cache_wback_inv((unsigned long)&sp->srings->txvector,
 	                    sizeof(sp->srings->txvector));
 
@@ -681,6 +714,7 @@ static int sgiseeq_init(struct hpc3_regs
 	dev->watchdog_timeo	= (200 * HZ) / 1000;
 	dev->get_stats		= sgiseeq_get_stats;
 	dev->set_multicast_list	= sgiseeq_set_multicast;
+	dev->set_mac_address	= sgiseeq_set_mac_address;
 	dev->irq		= irq;
 
 	if (register_netdev(dev)) {
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -96,39 +96,12 @@ struct shaper_cb { 
 }; 
 #define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
 
-int sh_debug;		/* Debug flag */
+static int sh_debug;		/* Debug flag */
 
 #define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
 
-/*
- *	Locking
- */
- 
-static int shaper_lock(struct shaper *sh)
-{
-	/*
-	 *	Lock in an interrupt must fail
-	 */
-	while (test_and_set_bit(0, &sh->locked))
-	{
-		if (!in_interrupt())
-			sleep_on(&sh->wait_queue);
-		else
-			return 0;
-			
-	}
-	return 1;
-}
-
 static void shaper_kick(struct shaper *sh);
 
-static void shaper_unlock(struct shaper *sh)
-{
-	clear_bit(0, &sh->locked);
-	wake_up(&sh->wait_queue);
-	shaper_kick(sh);
-}
-
 /*
  *	Compute clocks on a buffer
  */
@@ -157,17 +130,15 @@ static void shaper_setspeed(struct shape
  *	Throw a frame at a shaper.
  */
   
-static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
+
+static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	struct shaper *shaper = dev->priv;
  	struct sk_buff *ptr;
    
- 	/*
- 	 *	Get ready to work on this shaper. Lock may fail if its
- 	 *	an interrupt and locked.
- 	 */
- 	 
- 	if(!shaper_lock(shaper))
- 		return -1;
+	if (down_trylock(&shaper->sem))
+		return -1;
+
  	ptr=shaper->sendq.prev;
  	
  	/*
@@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *
                 dev_kfree_skb(ptr);
                 shaper->stats.collisions++;
  	}
- 	shaper_unlock(shaper);
+	shaper_kick(shaper);
+	up(&shaper->sem);
  	return 0;
 }
 
@@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct sha
  
 static void shaper_timer(unsigned long data)
 {
-	struct shaper *sh=(struct shaper *)data;
-	shaper_kick(sh);
+	struct shaper *shaper = (struct shaper *)data;
+
+	if (!down_trylock(&shaper->sem)) {
+		shaper_kick(shaper);
+		up(&shaper->sem);
+	} else
+		mod_timer(&shaper->timer, jiffies);
 }
 
 /*
@@ -311,19 +288,6 @@ static void shaper_kick(struct shaper *s
 	struct sk_buff *skb;
 	
 	/*
-	 *	Shaper unlock will kick
-	 */
-	 
-	if (test_and_set_bit(0, &shaper->locked))
-	{
-		if(sh_debug)
-			printk("Shaper locked.\n");
-		mod_timer(&shaper->timer, jiffies);
-		return;
-	}
-
-		
-	/*
 	 *	Walk the list (may be empty)
 	 */
 	 
@@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *s
 	 
 	if(skb!=NULL)
 		mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
-
-	clear_bit(0, &shaper->locked);
 }
 
 
@@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *s
 static void shaper_flush(struct shaper *shaper)
 {
 	struct sk_buff *skb;
- 	if(!shaper_lock(shaper))
-	{
-		printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n");
- 		return;
-	}
+
+	down(&shaper->sem);
 	while((skb=skb_dequeue(&shaper->sendq))!=NULL)
 		dev_kfree_skb(skb);
-	shaper_unlock(shaper);
+	shaper_kick(shaper);
+	up(&shaper->sem);
 }
 
 /*
@@ -426,13 +386,6 @@ static int shaper_close(struct net_devic
  *	ARP and other resolutions and not before.
  */
 
-
-static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct shaper *sh=dev->priv;
-	return shaper_qframe(sh, skb);
-}
-
 static struct net_device_stats *shaper_get_stats(struct net_device *dev)
 {
      	struct shaper *sh=dev->priv;
@@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_
 	init_timer(&sh->timer);
 	sh->timer.function=shaper_timer;
 	sh->timer.data=(unsigned long)sh;
-	init_waitqueue_head(&sh->wait_queue);
 }
 
 /*
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -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.06 Sep. 24 2002
+   Revision:	1.08.08 Jan. 22 2005
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -16,8 +16,8 @@
    preliminary Rev. 1.0 Nov. 10, 1998
    SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
    preliminary Rev. 1.0 Jan. 18, 1998
-   http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.08 Jan. 22 2005 Daniele Venzano use netif_msg for debugging messages
    Rev 1.08.07 Nov.  2 2003 Daniele Venzano <webvenza@libero.it> add suspend/resume support
    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
@@ -69,12 +69,13 @@
 
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/uaccess.h>	/* User space memory access functions */
 
 #include "sis900.h"
 
 #define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.07 11/02/2003"
+#define SIS900_DRV_VERSION "v1.08.08 Jan. 22 2005"
 
 static char version[] __devinitdata =
 KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -82,8 +83,13 @@ KERN_INFO "sis900.c: " SIS900_DRV_VERSIO
 static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
 
-#define sis900_debug debug
-static int sis900_debug;
+static int sis900_debug = -1; /* Use SIS900_DEF_MSG as value */
+
+#define SIS900_DEF_MSG \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
@@ -156,10 +162,13 @@ struct sis900_private {
 	struct mii_phy * mii;
 	struct mii_phy * first_mii; /* record the first mii structure */
 	unsigned int cur_phy;
+	struct mii_if_info mii_info;
 
 	struct timer_list timer; /* Link status detection timer. */
 	u8 autong_complete; /* 1: auto-negotiate complete  */
 
+	u32 msg_enable;
+
 	unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */
 	unsigned int cur_tx, dirty_tx;
 
@@ -174,6 +183,7 @@ struct sis900_private {
 
 	unsigned int tx_full; /* The Tx queue is full. */
 	u8 host_bridge_rev;
+	u8 chipset_rev;
 };
 
 MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
@@ -182,16 +192,19 @@ MODULE_LICENSE("GPL");
 
 module_param(multicast_filter_limit, int, 0444);
 module_param(max_interrupt_work, int, 0444);
-module_param(debug, int, 0444);
+module_param(sis900_debug, int, 0444);
 MODULE_PARM_DESC(multicast_filter_limit, "SiS 900/7016 maximum number of filtered multicast addresses");
 MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum events handled per interrupt");
-MODULE_PARM_DESC(debug, "SiS 900/7016 debug level (2-4)");
+MODULE_PARM_DESC(sis900_debug, "SiS 900/7016 bitmapped debugging message level");
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sis900_poll(struct net_device *dev);
+#endif
 static int sis900_open(struct net_device *net_dev);
 static int sis900_mii_probe (struct net_device * net_dev);
 static void sis900_init_rxfilter (struct net_device * net_dev);
 static u16 read_eeprom(long ioaddr, int location);
-static u16 mdio_read(struct net_device *net_dev, int phy_id, int location);
+static int mdio_read(struct net_device *net_dev, int phy_id, int location);
 static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val);
 static void sis900_timer(unsigned long data);
 static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy);
@@ -235,8 +248,8 @@ static int __devinit sis900_get_mac_addr
 	/* check to see if we have sane EEPROM */
 	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
 	if (signature == 0xffff || signature == 0x0000) {
-		printk (KERN_INFO "%s: Error EERPOM read %x\n", 
-			net_dev->name, signature);
+		printk (KERN_WARNING "%s: Error EERPOM read %x\n", 
+			pci_name(pci_dev), signature);
 		return 0;
 	}
 
@@ -268,7 +281,8 @@ static int __devinit sis630e_get_mac_add
 	if (!isa_bridge)
 		isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge);
 	if (!isa_bridge) {
-		printk("%s: Can not find ISA bridge\n", net_dev->name);
+		printk(KERN_WARNING "%s: Can not find ISA bridge\n",
+		       pci_name(pci_dev));
 		return 0;
 	}
 	pci_read_config_byte(isa_bridge, 0x48, &reg);
@@ -386,8 +400,8 @@ static int __devinit sis900_probe(struct
 	void *ring_space;
 	long ioaddr;
 	int i, ret;
-	u8 revision;
 	char *card_name = card_names[pci_id->driver_data];
+	const char *dev_name = pci_name(pci_dev);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -456,37 +470,55 @@ static int __devinit sis900_probe(struct
 	net_dev->tx_timeout = sis900_tx_timeout;
 	net_dev->watchdog_timeo = TX_TIMEOUT;
 	net_dev->ethtool_ops = &sis900_ethtool_ops;
-	
-	ret = register_netdev(net_dev);
-	if (ret)
-		goto err_unmap_rx;
-		
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+        net_dev->poll_controller = &sis900_poll;
+#endif
+
+	if (sis900_debug > 0)
+		sis_priv->msg_enable = sis900_debug;
+	else
+		sis_priv->msg_enable = SIS900_DEF_MSG;
+
+	sis_priv->mii_info.dev = net_dev;
+	sis_priv->mii_info.mdio_read = mdio_read;
+	sis_priv->mii_info.mdio_write = mdio_write;
+	sis_priv->mii_info.phy_id_mask = 0x1f;
+	sis_priv->mii_info.reg_num_mask = 0x1f;
+
 	/* Get Mac address according to the chip revision */
-	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev));
+	if(netif_msg_probe(sis_priv))
+		printk(KERN_DEBUG "%s: detected revision %2.2x, "
+				"trying to get MAC address...\n",
+				dev_name, sis_priv->chipset_rev);
+	
 	ret = 0;
-
-	if (revision == SIS630E_900_REV)
+	if (sis_priv->chipset_rev == SIS630E_900_REV)
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
-	else if ((revision > 0x81) && (revision <= 0x90) )
+	else if ((sis_priv->chipset_rev > 0x81) && (sis_priv->chipset_rev <= 0x90) )
 		ret = sis635_get_mac_addr(pci_dev, net_dev);
-	else if (revision == SIS96x_900_REV)
+	else if (sis_priv->chipset_rev == SIS96x_900_REV)
 		ret = sis96x_get_mac_addr(pci_dev, net_dev);
 	else
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
 	if (ret == 0) {
+		printk(KERN_WARNING "%s: Cannot read MAC address.\n", dev_name);
 		ret = -ENODEV;
-		goto err_out_unregister;
+		goto err_unmap_rx;
 	}
 	
 	/* 630ET : set the mii access mode as software-mode */
-	if (revision == SIS630ET_900_REV)
+	if (sis_priv->chipset_rev == SIS630ET_900_REV)
 		outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
 
 	/* probe for mii transceiver */
 	if (sis900_mii_probe(net_dev) == 0) {
+		printk(KERN_WARNING "%s: Error probing MII device.\n",
+		       dev_name);
 		ret = -ENODEV;
-		goto err_out_unregister;
+		goto err_unmap_rx;
 	}
 
 	/* save our host bridge revision */
@@ -496,6 +528,10 @@ static int __devinit sis900_probe(struct
 		pci_dev_put(dev);
 	}
 
+	ret = register_netdev(net_dev);
+	if (ret)
+		goto err_unmap_rx;
+
 	/* print some information about our NIC */
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
 	       card_name, ioaddr, net_dev->irq);
@@ -505,8 +541,6 @@ static int __devinit sis900_probe(struct
 
 	return 0;
 
- err_out_unregister:
- 	unregister_netdev(net_dev);
  err_unmap_rx:
 	pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring,
 		sis_priv->rx_ring_dma);
@@ -533,10 +567,10 @@ static int __devinit sis900_probe(struct
 static int __init sis900_mii_probe(struct net_device * net_dev)
 {
 	struct sis900_private * sis_priv = net_dev->priv;
+	const char *dev_name = pci_name(sis_priv->pci_dev);
 	u16 poll_bit = MII_STAT_LINK, status = 0;
 	unsigned long timeout = jiffies + 5 * HZ;
 	int phy_addr;
-	u8 revision;
 
 	sis_priv->mii = NULL;
 
@@ -550,12 +584,16 @@ static int __init sis900_mii_probe(struc
 		for(i = 0; i < 2; i++)
 			mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
-		if (mii_status == 0xffff || mii_status == 0x0000)
-			/* the mii is not accessible, try next one */
+		if (mii_status == 0xffff || mii_status == 0x0000) {
+			if (netif_msg_probe(sis_priv))
+				printk(KERN_DEBUG "%s: MII at address %d"
+						" not accessible\n",
+						dev_name, phy_addr);
 			continue;
+		}
 		
 		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
-			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
+			printk(KERN_WARNING "Cannot allocate mem for struct mii_phy\n");
 			mii_phy = sis_priv->first_mii;
 			while (mii_phy) {
 				struct mii_phy *phy;
@@ -581,22 +619,23 @@ static int __init sis900_mii_probe(struc
 				if (mii_chip_table[i].phy_types == MIX)
 					mii_phy->phy_types =
 					    (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME;
-				printk(KERN_INFO "%s: %s transceiver found at address %d.\n",
-				       net_dev->name, mii_chip_table[i].name,
-				       phy_addr);
+				printk(KERN_INFO "%s: %s transceiver found "
+							"at address %d.\n",
+							dev_name,
+							mii_chip_table[i].name,
+							phy_addr);
 				break;
 			}
 			
 		if( !mii_chip_table[i].phy_id1 ) {
 			printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
-			       net_dev->name, phy_addr);
+			       dev_name, phy_addr);
 			mii_phy->phy_types = UNKNOWN;
 		}
 	}
 	
 	if (sis_priv->mii == NULL) {
-		printk(KERN_INFO "%s: No MII transceivers found!\n",
-			net_dev->name);
+		printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);
 		return 0;
 	}
 
@@ -621,14 +660,13 @@ static int __init sis900_mii_probe(struc
 			poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);
 			if (time_after_eq(jiffies, timeout)) {
 				printk(KERN_WARNING "%s: reset phy and link down now\n",
-					net_dev->name);
+				       dev_name);
 				return -ETIME;
 			}
 		}
 	}
 
-	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if (revision == SIS630E_900_REV) {
+	if (sis_priv->chipset_rev == SIS630E_900_REV) {
 		/* SiS 630E has some bugs on default value of PHY registers */
 		mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1);
 		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);
@@ -691,9 +729,11 @@ static u16 sis900_default_phy(struct net
 		sis_priv->mii = default_phy;
 		sis_priv->cur_phy = default_phy->phy_addr;
 		printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",
-					net_dev->name,sis_priv->cur_phy);
+		       pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
 	}
 	
+	sis_priv->mii_info.phy_id = sis_priv->cur_phy;
+
 	status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
 	status &= (~MII_CNTL_ISOLATE);
 
@@ -821,7 +861,7 @@ static void mdio_reset(long mdio_addr)
  *	Please see SiS7014 or ICS spec
  */
 
-static u16 mdio_read(struct net_device *net_dev, int phy_id, int location)
+static int mdio_read(struct net_device *net_dev, int phy_id, int location)
 {
 	long mdio_addr = net_dev->base_addr + mear;
 	int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
@@ -930,6 +970,20 @@ static u16 sis900_reset_phy(struct net_d
 	return status;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+*/
+static void sis900_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	sis900_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 /**
  *	sis900_open - open sis900 device
  *	@net_dev: the net device to open
@@ -943,15 +997,13 @@ sis900_open(struct net_device *net_dev)
 {
 	struct sis900_private *sis_priv = net_dev->priv;
 	long ioaddr = net_dev->base_addr;
-	u8 revision;
 	int ret;
 
 	/* Soft reset the chip. */
 	sis900_reset(net_dev);
 
 	/* Equalizer workaround Rule */
-	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	sis630_set_eq(net_dev, revision);
+	sis630_set_eq(net_dev, sis_priv->chipset_rev);
 
 	ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ,
 						net_dev->name, net_dev);
@@ -999,6 +1051,7 @@ sis900_open(struct net_device *net_dev)
 static void
 sis900_init_rxfilter (struct net_device * net_dev)
 {
+	struct sis900_private *sis_priv = net_dev->priv;
 	long ioaddr = net_dev->base_addr;
 	u32 rfcrSave;
 	u32 i;
@@ -1016,8 +1069,8 @@ sis900_init_rxfilter (struct net_device 
 		outl((i << RFADDR_shift), ioaddr + rfcr);
 		outl(w, ioaddr + rfdr);
 
-		if (sis900_debug > 2) {
-			printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n",
+		if (netif_msg_hw(sis_priv)) {
+			printk(KERN_DEBUG "%s: Receive Filter Addrss[%d]=%x\n",
 			       net_dev->name, i, inl(ioaddr + rfdr));
 		}
 	}
@@ -1054,8 +1107,8 @@ sis900_init_tx_ring(struct net_device *n
 
 	/* load Transmit Descriptor Register */
 	outl(sis_priv->tx_ring_dma, ioaddr + txdp);
-	if (sis900_debug > 2)
-		printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n",
+	if (netif_msg_hw(sis_priv))
+		printk(KERN_DEBUG "%s: TX descriptor register loaded with: %8.8x\n",
 		       net_dev->name, inl(ioaddr + txdp));
 }
 
@@ -1108,8 +1161,8 @@ sis900_init_rx_ring(struct net_device *n
 
 	/* load Receive Descriptor Register */
 	outl(sis_priv->rx_ring_dma, ioaddr + rxdp);
-	if (sis900_debug > 2)
-		printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n",
+	if (netif_msg_hw(sis_priv))
+		printk(KERN_DEBUG "%s: RX descriptor register loaded with: %8.8x\n",
 		       net_dev->name, inl(ioaddr + rxdp));
 }
 
@@ -1219,7 +1272,6 @@ static void sis900_timer(unsigned long d
 	struct mii_phy *mii_phy = sis_priv->mii;
 	static int next_tick = 5*HZ;
 	u16 status;
-	u8 revision;
 
 	if (!sis_priv->autong_complete){
 		int speed, duplex = 0;
@@ -1227,9 +1279,7 @@ static void sis900_timer(unsigned long d
 		sis900_read_mode(net_dev, &speed, &duplex);
 		if (duplex){
 			sis900_set_mode(net_dev->base_addr, speed, duplex);
-			pci_read_config_byte(sis_priv->pci_dev,
-						PCI_CLASS_REVISION, &revision);
-			sis630_set_eq(net_dev, revision);
+			sis630_set_eq(net_dev, sis_priv->chipset_rev);
 			netif_start_queue(net_dev);
 		}
 
@@ -1256,16 +1306,15 @@ static void sis900_timer(unsigned long d
 	/* Link ON -> OFF */
                 if (!(status & MII_STAT_LINK)){
                 	netif_carrier_off(net_dev);
-                	printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+			if(netif_msg_link(sis_priv))
+                		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
 
                 	/* Change mode issue */
                 	if ((mii_phy->phy_id0 == 0x001D) && 
 			    ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
                			sis900_reset_phy(net_dev,  sis_priv->cur_phy);
   
-                	pci_read_config_byte(sis_priv->pci_dev,
-					PCI_CLASS_REVISION, &revision);
-			sis630_set_eq(net_dev, revision);
+			sis630_set_eq(net_dev, sis_priv->chipset_rev);
   
                 	goto LookForLink;
                 }
@@ -1371,7 +1420,8 @@ static void sis900_auto_negotiate(struct
 		status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
 	if (!(status & MII_STAT_LINK)){
-		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+		if(netif_msg_link(sis_priv))
+			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
 		sis_priv->autong_complete = 1;
 		netif_carrier_off(net_dev);
 		return;
@@ -1433,7 +1483,8 @@ static void sis900_read_mode(struct net_
 			*speed = HW_SPEED_100_MBPS;
 	}
 
-	printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
+	if(netif_msg_link(sis_priv))
+		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
 	       				net_dev->name,
 	       				*speed == HW_SPEED_100_MBPS ?
 	       					"100mbps" : "10mbps",
@@ -1456,8 +1507,9 @@ static void sis900_tx_timeout(struct net
 	unsigned long flags;
 	int i;
 
-	printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
-	       net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
+	if(netif_msg_tx_err(sis_priv))
+		printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
+	       		net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x0000, ioaddr + imr);
@@ -1558,8 +1610,8 @@ sis900_start_xmit(struct sk_buff *skb, s
 
 	net_dev->trans_start = jiffies;
 
-	if (sis900_debug > 3)
-		printk(KERN_INFO "%s: Queued Tx packet at %p size %d "
+	if (netif_msg_tx_queued(sis_priv))
+		printk(KERN_DEBUG "%s: Queued Tx packet at %p size %d "
 		       "to slot %d.\n",
 		       net_dev->name, skb->data, (int)skb->len, entry);
 
@@ -1606,20 +1658,22 @@ static irqreturn_t sis900_interrupt(int 
 
 		/* something strange happened !!! */
 		if (status & HIBERR) {
-			printk(KERN_INFO "%s: Abnormal interrupt,"
-			       "status %#8.8x.\n", net_dev->name, status);
+			if(netif_msg_intr(sis_priv))
+				printk(KERN_INFO "%s: Abnormal interrupt,"
+					"status %#8.8x.\n", net_dev->name, status);
 			break;
 		}
 		if (--boguscnt < 0) {
-			printk(KERN_INFO "%s: Too much work at interrupt, "
-			       "interrupt status = %#8.8x.\n",
-			       net_dev->name, status);
+			if(netif_msg_intr(sis_priv))
+				printk(KERN_INFO "%s: Too much work at interrupt, "
+					"interrupt status = %#8.8x.\n",
+					net_dev->name, status);
 			break;
 		}
 	} while (1);
 
-	if (sis900_debug > 3)
-		printk(KERN_INFO "%s: exiting interrupt, "
+	if(netif_msg_intr(sis_priv))
+		printk(KERN_DEBUG "%s: exiting interrupt, "
 		       "interrupt status = 0x%#8.8x.\n",
 		       net_dev->name, inl(ioaddr + isr));
 	
@@ -1644,8 +1698,8 @@ static int sis900_rx(struct net_device *
 	unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;
 	u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
 
-	if (sis900_debug > 3)
-		printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
+	if (netif_msg_rx_status(sis_priv))
+		printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
 		       "status:0x%8.8x\n",
 		       sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
 
@@ -1656,8 +1710,8 @@ static int sis900_rx(struct net_device *
 
 		if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
 			/* corrupted packet received */
-			if (sis900_debug > 3)
-				printk(KERN_INFO "%s: Corrupted packet "
+			if (netif_msg_rx_err(sis_priv))
+				printk(KERN_DEBUG "%s: Corrupted packet "
 				       "received, buffer status = 0x%8.8x.\n",
 				       net_dev->name, rx_status);
 			sis_priv->stats.rx_errors++;
@@ -1678,9 +1732,10 @@ static int sis900_rx(struct net_device *
 			   some unknow bugs, it is possible that
 			   we are working on NULL sk_buff :-( */
 			if (sis_priv->rx_skbuff[entry] == NULL) {
-				printk(KERN_INFO "%s: NULL pointer " 
-				       "encountered in Rx ring, skipping\n",
-				       net_dev->name);
+				if (netif_msg_rx_err(sis_priv))
+					printk(KERN_INFO "%s: NULL pointer " 
+						"encountered in Rx ring, skipping\n",
+						net_dev->name);
 				break;
 			}
 
@@ -1707,9 +1762,10 @@ static int sis900_rx(struct net_device *
 				 * "hole" on the buffer ring, it is not clear
 				 * how the hardware will react to this kind
 				 * of degenerated buffer */
-				printk(KERN_INFO "%s: Memory squeeze,"
-				       "deferring packet.\n",
-				       net_dev->name);
+				if (netif_msg_rx_status(sis_priv))
+					printk(KERN_INFO "%s: Memory squeeze,"
+						"deferring packet.\n",
+						net_dev->name);
 				sis_priv->rx_skbuff[entry] = NULL;
 				/* reset buffer descriptor state */
 				sis_priv->rx_ring[entry].cmdsts = 0;
@@ -1743,9 +1799,10 @@ static int sis900_rx(struct net_device *
 				 * "hole" on the buffer ring, it is not clear
 				 * how the hardware will react to this kind
 				 * of degenerated buffer */
-				printk(KERN_INFO "%s: Memory squeeze,"
-				       "deferring packet.\n",
-				       net_dev->name);
+				if (netif_msg_rx_err(sis_priv))
+					printk(KERN_INFO "%s: Memory squeeze,"
+						"deferring packet.\n",
+						net_dev->name);
 				sis_priv->stats.rx_dropped++;
 				break;
 			}
@@ -1794,8 +1851,8 @@ static void sis900_finish_xmit (struct n
 
 		if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
 			/* packet unsuccessfully transmitted */
-			if (sis900_debug > 3)
-				printk(KERN_INFO "%s: Transmit "
+			if (netif_msg_tx_err(sis_priv))
+				printk(KERN_DEBUG "%s: Transmit "
 				       "error, Tx status %8.8x.\n",
 				       net_dev->name, tx_status);
 			sis_priv->stats.tx_errors++;
@@ -1906,8 +1963,59 @@ static void sis900_get_drvinfo(struct ne
 	strcpy (info->bus_info, pci_name(sis_priv->pci_dev));
 }
 
+static u32 sis900_get_msglevel(struct net_device *net_dev)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	return sis_priv->msg_enable;
+}
+  
+static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	sis_priv->msg_enable = value;
+}
+
+static u32 sis900_get_link(struct net_device *net_dev)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	return mii_link_ok(&sis_priv->mii_info);
+}
+
+static int sis900_get_settings(struct net_device *net_dev,
+				struct ethtool_cmd *cmd)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	spin_lock_irq(&sis_priv->lock);
+	mii_ethtool_gset(&sis_priv->mii_info, cmd);
+	spin_unlock_irq(&sis_priv->lock);
+	return 0;
+}
+
+static int sis900_set_settings(struct net_device *net_dev,
+				struct ethtool_cmd *cmd)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	int rt;
+	spin_lock_irq(&sis_priv->lock);
+	rt = mii_ethtool_sset(&sis_priv->mii_info, cmd);
+	spin_unlock_irq(&sis_priv->lock);
+	return rt;
+}
+
+static int sis900_nway_reset(struct net_device *net_dev)
+{
+	struct sis900_private *sis_priv = net_dev->priv;
+	return mii_nway_restart(&sis_priv->mii_info);
+}
+
 static struct ethtool_ops sis900_ethtool_ops = {
-	.get_drvinfo =		sis900_get_drvinfo,
+	.get_drvinfo 	= sis900_get_drvinfo,
+	.get_msglevel	= sis900_get_msglevel,
+	.set_msglevel	= sis900_set_msglevel,
+	.get_link	= sis900_get_link,
+	.get_settings	= sis900_get_settings,
+	.set_settings	= sis900_set_settings,
+	.nway_reset	= sis900_nway_reset,
 };
 
 /**
@@ -2048,12 +2156,10 @@ static int sis900_set_config(struct net_
 		case IF_PORT_AUI: /* AUI */
 		case IF_PORT_100BASEFX: /* 100BaseFx */
                 	/* These Modes are not supported (are they?)*/
-			printk(KERN_INFO "Not supported");
 			return -EOPNOTSUPP;
 			break;
             
 		default:
-			printk(KERN_INFO "Invalid");
 			return -EINVAL;
 		}
 	}
@@ -2099,11 +2205,10 @@ static void set_rx_mode(struct net_devic
 	u16 mc_filter[16] = {0};	/* 256/128 bits multicast hash table */
 	int i, table_entries;
 	u32 rx_mode;
-	u8 revision;
 
 	/* 635 Hash Table entires = 256(2^16) */
-	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if((revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV))
+	if((sis_priv->chipset_rev >= SIS635A_900_REV) ||
+			(sis_priv->chipset_rev == SIS900B_900_REV))
 		table_entries = 16;
 	else
 		table_entries = 8;
@@ -2129,7 +2234,7 @@ static void set_rx_mode(struct net_devic
 			mclist && i < net_dev->mc_count;
 			i++, mclist = mclist->next) {
 			unsigned int bit_nr =
-				sis900_mcast_bitnr(mclist->dmi_addr, revision);
+				sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev);
 			mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
 		}
 	}
@@ -2175,7 +2280,6 @@ static void sis900_reset(struct net_devi
 	long ioaddr = net_dev->base_addr;
 	int i = 0;
 	u32 status = TxRCMP | RxRCMP;
-	u8  revision;
 
 	outl(0, ioaddr + ier);
 	outl(0, ioaddr + imr);
@@ -2188,8 +2292,8 @@ static void sis900_reset(struct net_devi
 		status ^= (inl(isr + ioaddr) & status);
 	}
 
-	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if( (revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV) )
+	if( (sis_priv->chipset_rev >= SIS635A_900_REV) ||
+			(sis_priv->chipset_rev == SIS900B_900_REV) )
 		outl(PESEL | RND_CNT, ioaddr + cfg);
 	else
 		outl(PESEL, ioaddr + cfg);
@@ -2226,7 +2330,7 @@ static void __devexit sis900_remove(stru
 
 #ifdef CONFIG_PM
 
-static int sis900_suspend(struct pci_dev *pci_dev, u32 state)
+static int sis900_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
 	struct net_device *net_dev = pci_get_drvdata(pci_dev);
 	long ioaddr = net_dev->base_addr;
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -69,6 +69,7 @@ typedef struct s_AC	SK_AC;
 #include <linux/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
--- a/drivers/net/sk98lin/skethtool.c
+++ b/drivers/net/sk98lin/skethtool.c
@@ -257,7 +257,7 @@ static void getDriverInfo(struct net_dev
 	strlcpy(info->driver, DRIVER_FILE_NAME, sizeof(info->driver));
 	strcpy(info->version, vers);
 	strcpy(info->fw_version, "N/A");
-	strlcpy(info->bus_info, pAC->PciDev->slot_name, ETHTOOL_BUSINFO_LEN);
+	strlcpy(info->bus_info, pci_name(pAC->PciDev), ETHTOOL_BUSINFO_LEN);
 }
 
 /*
@@ -437,9 +437,6 @@ static int locateDevice(struct net_devic
 	pAC->LedsOn = 0;
 	mod_timer(&pAC->BlinkTimer, jiffies);
 	msleep_interruptible(data * 1000);
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(data * HZ);
 	del_timer_sync(&pAC->BlinkTimer);
 	toggleLeds(pNet, 0);
 
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -3058,7 +3058,7 @@ fault_gen:
 		*/
 		* ((SK_U32 *)pMemBuf) = 0;
 		* ((SK_U32 *)pMemBuf + 1) = pdev->bus->number;
-		* ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pdev->slot_name);
+		* ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pci_name(pdev));
 		if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
 			Err = -EFAULT;
 			goto fault_diag;
@@ -5152,8 +5152,10 @@ static struct pci_device_id skge_pci_tbl
 	{ 0, }
 };
 
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
 static struct pci_driver skge_driver = {
-	.name		= "skge",
+	.name		= "sk98lin",
 	.id_table	= skge_pci_tbl,
 	.probe		= skge_probe_one,
 	.remove		= __devexit_p(skge_remove_one),
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -127,12 +127,13 @@ static unsigned char poly[] =
 #ifdef DEBUG
 static void dumpmem(struct net_device *dev, u32 start, u32 len)
 {
+	skmca_priv *priv = netdev_priv(dev);
 	int z;
 
 	for (z = 0; z < len; z++) {
 		if ((z & 15) == 0)
 			printk("%04x:", z);
-		printk(" %02x", SKMCA_READB(dev->mem_start + start + z));
+		printk(" %02x", readb(priv->base + start + z));
 		if ((z & 15) == 15)
 			printk("\n");
 	}
@@ -220,21 +221,21 @@ static int __init dofind(int *junior, in
 
 static void ResetBoard(struct net_device *dev)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 
-	SKMCA_WRITEB(CTRL_RESET_ON, priv->ctrladdr);
+	writeb(CTRL_RESET_ON, priv->ctrladdr);
 	udelay(10);
-	SKMCA_WRITEB(CTRL_RESET_OFF, priv->ctrladdr);
+	writeb(CTRL_RESET_OFF, priv->ctrladdr);
 }
 
 /* wait for LANCE interface to become not busy */
 
 static int WaitLANCE(struct net_device *dev)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	int t = 0;
 
-	while ((SKMCA_READB(priv->ctrladdr) & STAT_IO_BUSY) ==
+	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
 	       STAT_IO_BUSY) {
 		udelay(1);
 		if (++t > 1000) {
@@ -250,7 +251,7 @@ static int WaitLANCE(struct net_device *
 
 static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 
 	/* disable interrupts */
@@ -263,19 +264,17 @@ static void SetLANCE(struct net_device *
 
 	/* transfer register address to RAP */
 
-	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
-		     priv->ctrladdr);
-	SKMCA_WRITEW(addr, priv->ioregaddr);
-	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
+	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+	writew(addr, priv->ioregaddr);
+	writeb(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
 	WaitLANCE(dev);
 
 	/* transfer data to register */
 
-	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA,
-		     priv->ctrladdr);
-	SKMCA_WRITEW(value, priv->ioregaddr);
-	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
+	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
+	writew(value, priv->ioregaddr);
+	writeb(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
 	WaitLANCE(dev);
 
@@ -288,7 +287,7 @@ static void SetLANCE(struct net_device *
 
 static u16 GetLANCE(struct net_device *dev, u16 addr)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 	unsigned int res;
 
@@ -302,21 +301,19 @@ static u16 GetLANCE(struct net_device *d
 
 	/* transfer register address to RAP */
 
-	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
-		     priv->ctrladdr);
-	SKMCA_WRITEW(addr, priv->ioregaddr);
-	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
+	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+	writew(addr, priv->ioregaddr);
+	writeb(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
 	WaitLANCE(dev);
 
 	/* transfer data from register */
 
-	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA,
-		     priv->ctrladdr);
-	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
+	writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
+	writeb(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
 	WaitLANCE(dev);
-	res = SKMCA_READW(priv->ioregaddr);
+	res = readw(priv->ioregaddr);
 
 	/* reenable interrupts */
 
@@ -329,6 +326,7 @@ static u16 GetLANCE(struct net_device *d
 
 static void InitDscrs(struct net_device *dev)
 {
+	skmca_priv *priv = netdev_priv(dev);
 	u32 bufaddr;
 
 	/* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
@@ -344,11 +342,10 @@ static void InitDscrs(struct net_device 
 			descr.Flags = 0;
 			descr.Len = 0xf000;
 			descr.Status = 0;
-			SKMCA_TOIO(dev->mem_start + RAM_TXBASE +
+			memcpy_toio(priv->base + RAM_TXBASE +
 				   (z * sizeof(LANCE_TxDescr)), &descr,
 				   sizeof(LANCE_TxDescr));
-			SKMCA_SETIO(dev->mem_start + bufaddr, 0,
-				    RAM_BUFSIZE);
+			memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
 			bufaddr += RAM_BUFSIZE;
 		}
 	}
@@ -364,11 +361,10 @@ static void InitDscrs(struct net_device 
 			descr.Flags = RXDSCR_FLAGS_OWN;
 			descr.MaxLen = -RAM_BUFSIZE;
 			descr.Len = 0;
-			SKMCA_TOIO(dev->mem_start + RAM_RXBASE +
+			memcpy_toio(priv->base + RAM_RXBASE +
 				   (z * sizeof(LANCE_RxDescr)), &descr,
 				   sizeof(LANCE_RxDescr));
-			SKMCA_SETIO(dev->mem_start + bufaddr, 0,
-				    RAM_BUFSIZE);
+			memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
 			bufaddr += RAM_BUFSIZE;
 		}
 	}
@@ -425,7 +421,7 @@ static unsigned int GetHash(char *addres
 
 static void InitLANCE(struct net_device *dev)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 
 	/* build up descriptors. */
 
@@ -478,6 +474,7 @@ static void StopLANCE(struct net_device 
 
 static void InitBoard(struct net_device *dev)
 {
+	skmca_priv *priv = netdev_priv(dev);
 	LANCE_InitBlock block;
 
 	/* Lay out the shared RAM - first we create the init block for the LANCE.
@@ -492,7 +489,7 @@ static void InitBoard(struct net_device 
 	block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
 	block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
 
-	SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+	memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
 
 	/* initialize LANCE. Implicitly sets up other structures in RAM. */
 
@@ -572,7 +569,7 @@ static u16 irqstart_handler(struct net_d
 
 static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 
 	/* update statistics */
 
@@ -588,7 +585,7 @@ static u16 irqmiss_handler(struct net_de
 
 static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	LANCE_RxDescr descr;
 	unsigned int descraddr;
 
@@ -597,7 +594,7 @@ static u16 irqrx_handler(struct net_devi
 	descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
 	while (1) {
 		/* read descriptor */
-		SKMCA_FROMIO(&descr, dev->mem_start + descraddr,
+		memcpy_fromio(&descr, priv->base + descraddr,
 			     sizeof(LANCE_RxDescr));
 
 		/* if we reach a descriptor we do not own, we're done */
@@ -629,8 +626,8 @@ static u16 irqrx_handler(struct net_devi
 			if (skb == NULL)
 				priv->stat.rx_dropped++;
 			else {
-				SKMCA_FROMIO(skb_put(skb, descr.Len),
-					     dev->mem_start +
+				memcpy_fromio(skb_put(skb, descr.Len),
+					     priv->base +
 					     descr.LowAddr, descr.Len);
 				skb->dev = dev;
 				skb->protocol = eth_type_trans(skb, dev);
@@ -647,7 +644,7 @@ static u16 irqrx_handler(struct net_devi
 		descr.Flags |= RXDSCR_FLAGS_OWN;
 
 		/* update descriptor in shared RAM */
-		SKMCA_TOIO(dev->mem_start + descraddr, &descr,
+		memcpy_toio(priv->base + descraddr, &descr,
 			   sizeof(LANCE_RxDescr));
 
 		/* go to next descriptor */
@@ -669,7 +666,7 @@ static u16 irqrx_handler(struct net_devi
 
 static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	LANCE_TxDescr descr;
 	unsigned int descraddr;
 
@@ -679,7 +676,7 @@ static u16 irqtx_handler(struct net_devi
 	    RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
 	while (priv->txbusy > 0) {
 		/* read descriptor */
-		SKMCA_FROMIO(&descr, dev->mem_start + descraddr,
+		memcpy_fromio(&descr, priv->base + descraddr,
 			     sizeof(LANCE_TxDescr));
 
 		/* if the LANCE still owns this one, we've worked out all sent packets */
@@ -798,9 +795,7 @@ static int skmca_getinfo(char *buf, int 
 
 	if (dev == NULL)
 		return len;
-	if (dev->priv == NULL)
-		return len;
-	priv = (skmca_priv *) dev->priv;
+	priv = netdev_priv(dev);
 
 	/* print info */
 
@@ -825,7 +820,7 @@ static int skmca_getinfo(char *buf, int 
 static int skmca_open(struct net_device *dev)
 {
 	int result;
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 
 	/* register resources - only necessary for IRQ */
 	result =
@@ -868,7 +863,7 @@ static int skmca_close(struct net_device
 
 static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	LANCE_TxDescr descr;
 	unsigned int address;
 	int tmplen, retval = 0;
@@ -894,8 +889,7 @@ static int skmca_tx(struct sk_buff *skb,
 
 	/* get TX descriptor */
 	address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
-	SKMCA_FROMIO(&descr, dev->mem_start + address,
-		     sizeof(LANCE_TxDescr));
+	memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
 
 	/* enter packet length as 2s complement - assure minimum length */
 	tmplen = skb->len;
@@ -911,14 +905,14 @@ static int skmca_tx(struct sk_buff *skb,
 		unsigned int destoffs = 0, l = strlen(fill);
 
 		while (destoffs < tmplen) {
-			SKMCA_TOIO(dev->mem_start + descr.LowAddr +
+			memcpy_toio(priv->base + descr.LowAddr +
 				   destoffs, fill, l);
 			destoffs += l;
 		}
 	}
 
 	/* do the real data copying */
-	SKMCA_TOIO(dev->mem_start + descr.LowAddr, skb->data, skb->len);
+	memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
 
 	/* hand descriptor over to LANCE - this is the first and last chunk */
 	descr.Flags =
@@ -945,8 +939,7 @@ static int skmca_tx(struct sk_buff *skb,
 		netif_stop_queue(dev);
 
 	/* write descriptor back to RAM */
-	SKMCA_TOIO(dev->mem_start + address, &descr,
-		   sizeof(LANCE_TxDescr));
+	memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
 
 	/* if no descriptors were active, give the LANCE a hint to read it
 	   immediately */
@@ -967,7 +960,7 @@ static int skmca_tx(struct sk_buff *skb,
 
 static struct net_device_stats *skmca_stats(struct net_device *dev)
 {
-	skmca_priv *priv = (skmca_priv *) dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 
 	return &(priv->stat);
 }
@@ -977,13 +970,14 @@ static struct net_device_stats *skmca_st
 
 static void skmca_set_multicast_list(struct net_device *dev)
 {
+	skmca_priv *priv = netdev_priv(dev);
 	LANCE_InitBlock block;
 
 	/* first stop the LANCE... */
 	StopLANCE(dev);
 
 	/* ...then modify the initialization block... */
-	SKMCA_FROMIO(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
+	memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
 	if (dev->flags & IFF_PROMISC)
 		block.Mode |= LANCE_INIT_PROM;
 	else
@@ -1003,7 +997,7 @@ static void skmca_set_multicast_list(str
 		}
 	}
 
-	SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+	memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
 
 	/* ...then reinit LANCE with the correct flags */
 	InitLANCE(dev);
@@ -1017,10 +1011,11 @@ static int startslot;		/* counts through
 
 static void cleanup_card(struct net_device *dev)
 {
-	skmca_priv *priv = dev->priv;
+	skmca_priv *priv = netdev_priv(dev);
 	DeinitBoard(dev);
 	if (dev->irq != 0)
 		free_irq(dev->irq, dev);
+	iounmap(priv->base);
 	mca_mark_as_unused(priv->slot);
 	mca_set_adapter_procfn(priv->slot, NULL, NULL);
 }
@@ -1104,13 +1099,20 @@ struct net_device * __init skmca_probe(i
 	printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
 	       junior ? "Junior MC2" : "MC2+", slot + 1);
 
-	/* allocate structure */
-	priv = dev->priv;
+	priv = netdev_priv(dev);
+	priv->base = ioremap(base, 0x4000);
+	if (!priv->base) {
+		mca_set_adapter_procfn(slot, NULL, NULL);
+		mca_mark_as_unused(slot);
+		free_netdev(dev);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	priv->slot = slot;
-	priv->macbase = base + 0x3fc0;
-	priv->ioregaddr = base + 0x3ff0;
-	priv->ctrladdr = base + 0x3ff2;
-	priv->cmdaddr = base + 0x3ff3;
+	priv->macbase = priv->base + 0x3fc0;
+	priv->ioregaddr = priv->base + 0x3ff0;
+	priv->ctrladdr = priv->base + 0x3ff2;
+	priv->cmdaddr = priv->base + 0x3ff3;
 	priv->medium = medium;
 	memset(&priv->stat, 0, sizeof(struct net_device_stats));
 	spin_lock_init(&priv->lock);
@@ -1147,7 +1149,7 @@ struct net_device * __init skmca_probe(i
 
 	/* copy out MAC address */
 	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1));
+		dev->dev_addr[i] = readb(priv->macbase + (i << 1));
 
 	/* print config */
 	printk("%s: IRQ %d, memory %#lx-%#lx, "
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
--- a/drivers/net/sk_mca.h
+++ b/drivers/net/sk_mca.h
@@ -5,16 +5,6 @@
 
 #ifdef _SK_MCA_DRIVER_
 
-/* version-dependent functions/structures */
-
-#define SKMCA_READB(addr) isa_readb(addr)
-#define SKMCA_READW(addr) isa_readw(addr)
-#define SKMCA_WRITEB(data, addr) isa_writeb(data, addr)
-#define SKMCA_WRITEW(data, addr) isa_writew(data, addr)
-#define SKMCA_TOIO(dest, src, len) isa_memcpy_toio(dest, src, len)
-#define SKMCA_FROMIO(dest, src, len) isa_memcpy_fromio(dest, src, len)
-#define SKMCA_SETIO(dest, val, len) isa_memset_io(dest, val, len)
-
 /* Adapter ID's */
 #define SKNET_MCA_ID 0x6afd
 #define SKNET_JUNIOR_MCA_ID 0x6be9
@@ -29,10 +19,11 @@ typedef enum { Media_10Base2, Media_10Ba
 /* private structure */
 typedef struct {
 	unsigned int slot;	/* MCA-Slot-#                       */
-	unsigned int macbase;	/* base address of MAC address PROM */
-	unsigned int ioregaddr;	/* address of I/O-register (Lo)     */
-	unsigned int ctrladdr;	/* address of control/stat register */
-	unsigned int cmdaddr;	/* address of I/O-command register  */
+	void __iomem *base;
+	void __iomem *macbase;	/* base address of MAC address PROM */
+	void __iomem *ioregaddr;/* address of I/O-register (Lo)     */
+	void __iomem *ctrladdr;	/* address of control/stat register */
+	void __iomem *cmdaddr;	/* address of I/O-command register  */
 	int nextrx;		/* index of next RX descriptor to
 				   be read                          */
 	int nexttxput;		/* index of next free TX descriptor */
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -693,33 +693,6 @@ slhc_toss(struct slcompress *comp)
 }
 
 
-void slhc_i_status(struct slcompress *comp)
-{
-	if (comp != NULLSLCOMPR) {
-		printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n",
-			comp->sls_i_compressed,
-			comp->sls_i_uncompressed,
-			comp->sls_i_error,
-			comp->sls_i_tossed);
-	}
-}
-
-
-void slhc_o_status(struct slcompress *comp)
-{
-	if (comp != NULLSLCOMPR) {
-		printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n",
-			comp->sls_o_compressed,
-			comp->sls_o_uncompressed,
-			comp->sls_o_tcp,
-			comp->sls_o_nontcp);
-		printk("\t%10d Searches, %10d Misses\n",
-			comp->sls_o_searches,
-			comp->sls_o_misses);
-	}
-}
-
-/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
 /* VJ header compression */
 EXPORT_SYMBOL(slhc_init);
 EXPORT_SYMBOL(slhc_free);
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -185,15 +185,12 @@ sl_alloc_bufs(struct slip *sl, int mtu)
 	/* Cleanup */
 err_exit:
 #ifdef SL_INCLUDE_CSLIP
-	if (cbuff)
-		kfree(cbuff);
+	kfree(cbuff);
 	if (slcomp)
 		slhc_free(slcomp);
 #endif
-	if (xbuff)
-		kfree(xbuff);
-	if (rbuff)
-		kfree(rbuff);
+	kfree(xbuff);
+	kfree(rbuff);
 	return err;
 }
 
@@ -204,13 +201,13 @@ sl_free_bufs(struct slip *sl)
 	void * tmp;
 
 	/* Free all SLIP frame buffers. */
-	if ((tmp = xchg(&sl->rbuff, NULL)) != NULL)
-		kfree(tmp);
-	if ((tmp = xchg(&sl->xbuff, NULL)) != NULL)
-		kfree(tmp);
+	tmp = xchg(&sl->rbuff, NULL);
+	kfree(tmp);
+	tmp = xchg(&sl->xbuff, NULL);
+	kfree(tmp);
 #ifdef SL_INCLUDE_CSLIP
-	if ((tmp = xchg(&sl->cbuff, NULL)) != NULL)
-		kfree(tmp);
+	tmp = xchg(&sl->cbuff, NULL);
+	kfree(tmp);
 	if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)
 		slhc_free(tmp);
 #endif
@@ -297,13 +294,10 @@ done_on_bh:
 	spin_unlock_bh(&sl->lock);
 
 done:
-	if (xbuff)
-		kfree(xbuff);
-	if (rbuff)
-		kfree(rbuff);
+	kfree(xbuff);
+	kfree(rbuff);
 #ifdef SL_INCLUDE_CSLIP
-	if (cbuff)
-		kfree(cbuff);
+	kfree(cbuff);
 #endif
 	return err;
 }
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -310,9 +310,13 @@ int __init ultramca_probe(struct device 
 	ei_status.rx_start_page = START_PG + TX_PAGES;
 	ei_status.stop_page = num_pages;
 
-	ei_status.rmem_start = dev->mem_start + TX_PAGES * 256;
-	dev->mem_end = ei_status.rmem_end =
-	dev->mem_start + (ei_status.stop_page - START_PG) * 256;
+	ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG) * 256);
+	if (!ei_status.mem) {
+		rc = -ENOMEM;
+		goto err_release_region;
+	}
+
+	dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG) * 256;
 
 	printk(", IRQ %d memory %#lx-%#lx.\n",
 	dev->irq, dev->mem_start, dev->mem_end - 1);
@@ -334,10 +338,12 @@ int __init ultramca_probe(struct device 
 
 	rc = register_netdev(dev);
 	if (rc)
-		goto err_release_region;
+		goto err_unmap;
 
 	return 0;
 
+err_unmap:
+	iounmap(ei_status.mem);
 err_release_region:
 	release_region(ioaddr, ULTRA_IO_EXTENT);
 err_unclaim:
@@ -395,13 +401,13 @@ static void ultramca_reset_8390(struct n
 
 static void ultramca_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
-	unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG) << 8);
+	void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG) << 8);
 
 #ifdef notdef
 	/* Officially this is what we are doing, but the readl() is faster */
-	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 #else
-	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
+	((unsigned int*)hdr)[0] = readl(hdr_start);
 #endif
 }
 
@@ -411,17 +417,17 @@ static void ultramca_get_8390_hdr(struct
 
 static void ultramca_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
-	unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
+	void __iomem *xfer_start = ei_status.mem + ring_offset - START_PG * 256;
 
-	if (xfer_start + count > ei_status.rmem_end) {
+	if (ring_offset + count > ei_status.stop_page * 256) {
 		/* We must wrap the input move. */
-		int semi_count = ei_status.rmem_end - xfer_start;
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		int semi_count = ei_status.stop_page * 256 - ring_offset;
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 
 }
@@ -429,9 +435,9 @@ static void ultramca_block_input(struct 
 static void ultramca_block_output(struct net_device *dev, int count, const unsigned char *buf,
                 int start_page)
 {
-	unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8);
+	void __iomem *shmem = ei_status.mem + ((start_page - START_PG) << 8);
 
-	isa_memcpy_toio(shmem, buf, count);
+	memcpy_toio(shmem, buf, count);
 }
 
 static int ultramca_close_card(struct net_device *dev)
@@ -466,6 +472,7 @@ static int ultramca_remove(struct device
 		unregister_netdev(dev);
 		mca_device_set_claim(mca_dev, 0);
 		release_region(ioaddr, ULTRA_IO_EXTENT);
+		iounmap(ei_status.mem);
 		free_netdev(dev);
 	}
 	return 0;
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -176,6 +176,7 @@ static void cleanup_card(struct net_devi
 		pnp_device_detach(idev);
 #endif
 	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
+	iounmap(ei_status.mem);
 }
 
 #ifndef MODULE
@@ -294,9 +295,14 @@ static int __init ultra_probe1(struct ne
 	ei_status.rx_start_page = START_PG + TX_PAGES;
 	ei_status.stop_page = num_pages;
 
-	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = ei_status.rmem_end
-		= dev->mem_start + (ei_status.stop_page - START_PG)*256;
+	ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256);
+	if (!ei_status.mem) {
+		printk(", failed to ioremap.\n");
+		retval =  -ENOMEM;
+		goto out;
+	}
+
+	dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256;
 
 	if (piomode) {
 		printk(",%s IRQ %d programmed-I/O mode.\n",
@@ -430,16 +436,16 @@ ultra_reset_8390(struct net_device *dev)
 static void
 ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
-	unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
+	void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG)<<8);
 
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);	/* shmem on */
 #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));
+	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);
+	((unsigned int*)hdr)[0] = readl(hdr_start);
 #endif
 	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
 }
@@ -450,20 +456,20 @@ ultra_get_8390_hdr(struct net_device *de
 static void
 ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
-	unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG<<8);
+	void __iomem *xfer_start = ei_status.mem + ring_offset - (START_PG<<8);
 
 	/* Enable shared memory. */
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
 
-	if (xfer_start + count > ei_status.rmem_end) {
+	if (ring_offset + count > ei_status.stop_page*256) {
 		/* We must wrap the input move. */
-		int semi_count = ei_status.rmem_end - xfer_start;
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		int semi_count = ei_status.stop_page*256 - ring_offset;
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 
 	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET);	/* Disable memory. */
@@ -473,12 +479,12 @@ static void
 ultra_block_output(struct net_device *dev, int count, const unsigned char *buf,
 				int start_page)
 {
-	unsigned long shmem = dev->mem_start + ((start_page - START_PG)<<8);
+	void __iomem *shmem = ei_status.mem + ((start_page - START_PG)<<8);
 
 	/* Enable shared memory. */
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
 
-	isa_memcpy_toio(shmem, buf, count);
+	memcpy_toio(shmem, buf, count);
 
 	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
 }
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -104,6 +104,7 @@ static void cleanup_card(struct net_devi
 	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
 	/* NB: ultra32_close_card() does free_irq */
 	release_region(ioaddr, ULTRA32_IO_EXTENT);
+	iounmap(ei_status.mem);
 }
 
 /*	Probe for the Ultra32.  This looks like a 8013 with the station
@@ -259,8 +260,13 @@ static int __init ultra32_probe1(struct 
 	/* All Ultra32 cards have 32KB memory with an 8KB window. */
 	ei_status.stop_page = 128;
 
-	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = ei_status.rmem_end = dev->mem_start + 0x1fff;
+	ei_status.mem = ioremap(dev->mem_start, 0x2000);
+	if (!ei_status.mem) {
+		printk(", failed to ioremap.\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	dev->mem_end = dev->mem_start + 0x1fff;
 
 	printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
 	       dev->irq, dev->mem_start, dev->mem_end);
@@ -345,7 +351,7 @@ static void ultra32_get_8390_hdr(struct 
 				 struct e8390_pkt_hdr *hdr,
 				 int ring_page)
 {
-	unsigned long hdr_start = dev->mem_start + ((ring_page & 0x1f) << 8);
+	void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
 	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
 
 	/* Select correct 8KB Window. */
@@ -354,10 +360,10 @@ static void ultra32_get_8390_hdr(struct 
 #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));
+	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);
+	((unsigned int*)hdr)[0] = readl(hdr_start);
 #endif
 }
 
@@ -371,26 +377,26 @@ static void ultra32_block_input(struct n
 				struct sk_buff *skb,
 				int ring_offset)
 {
-	unsigned long xfer_start = dev->mem_start + (ring_offset & 0x1fff);
+	void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
 	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
 
 	if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
 		int semi_count = 8192 - (ring_offset & 0x1FFF);
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
 		if (ring_offset < 96*256) {
 			/* Select next 8KB Window. */
 			ring_offset += semi_count;
 			outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
-			isa_memcpy_fromio(skb->data + semi_count, dev->mem_start, count);
+			memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
 		} else {
 			/* Select first 8KB Window. */
 			outb(ei_status.reg0, RamReg);
-			isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+			memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 		}
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 }
 
@@ -399,13 +405,13 @@ static void ultra32_block_output(struct 
 				 const unsigned char *buf,
 				 int start_page)
 {
-	unsigned long xfer_start = dev->mem_start + (start_page<<8);
+	void __iomem *xfer_start = ei_status.mem + (start_page<<8);
 	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
 
 	/* Select first 8KB Window. */
 	outb(ei_status.reg0, RamReg);
 
-	isa_memcpy_toio(xfer_start, buf, count);
+	memcpy_toio(xfer_start, buf, count);
 }
 
 #ifdef MODULE
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -210,10 +210,15 @@ struct smc_local {
 
 	spinlock_t lock;
 
+#ifdef SMC_CAN_USE_DATACS
+	u32	__iomem *datacs;
+#endif
+
 #ifdef SMC_USE_PXA_DMA
 	/* DMA needs the physical address of the chip */
 	u_long physaddr;
 #endif
+	void __iomem *base;
 };
 
 #if SMC_DEBUG > 0
@@ -307,8 +312,8 @@ static void PRINT_PKT(u_char *buf, int l
  */
 static void smc_reset(struct net_device *dev)
 {
-	unsigned long ioaddr = dev->base_addr;
 	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int ctl, cfg;
 
 	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
@@ -399,8 +404,8 @@ static void smc_reset(struct net_device 
  */
 static void smc_enable(struct net_device *dev)
 {
-	unsigned long ioaddr = dev->base_addr;
 	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	int mask;
 
 	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
@@ -433,8 +438,8 @@ static void smc_enable(struct net_device
  */
 static void smc_shutdown(struct net_device *dev)
 {
-	unsigned long ioaddr = dev->base_addr;
 	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 
 	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
@@ -462,7 +467,7 @@ static void smc_shutdown(struct net_devi
 static inline void  smc_rcv(struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	unsigned int packet_number, status, packet_len;
 
 	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
@@ -483,7 +488,19 @@ static inline void  smc_rcv(struct net_d
 		dev->name, packet_number, status,
 		packet_len, packet_len);
 
-	if (unlikely(status & RS_ERRORS)) {
+	back:
+	if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
+		if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
+			/* accept VLAN packets */
+			status &= ~RS_TOOLONG;
+			goto back;
+		}
+		if (packet_len < 6) {
+			/* bloody hardware */
+			printk(KERN_ERR "%s: fubar (rxlen %u status %x\n",
+					dev->name, packet_len, status);
+			status |= RS_TOOSHORT;
+		}
 		SMC_WAIT_MMU_BUSY();
 		SMC_SET_MMU_CMD(MC_RELEASE);
 		lp->stats.rx_errors++;
@@ -508,7 +525,7 @@ static inline void  smc_rcv(struct net_d
 		 * (2 bytes, possibly containing the payload odd byte).
 		 * Furthermore, we add 2 bytes to allow rounding up to
 		 * multiple of 4 bytes on 32 bit buses.
-		 * Ence packet_len - 6 + 2 + 2 + 2.
+		 * Hence packet_len - 6 + 2 + 2 + 2.
 		 */
 		skb = dev_alloc_skb(packet_len);
 		if (unlikely(skb == NULL)) {
@@ -596,7 +613,7 @@ static void smc_hardware_send_pkt(unsign
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	struct sk_buff *skb;
 	unsigned int packet_no, len;
 	unsigned char *buf;
@@ -680,7 +697,7 @@ done:	if (!THROTTLE_TX_PKTS)
 static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	unsigned int numPages, poll_count, status;
 
 	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
@@ -752,8 +769,8 @@ static int smc_hard_start_xmit(struct sk
  */
 static void smc_tx(struct net_device *dev)
 {
-	unsigned long ioaddr = dev->base_addr;
 	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int saved_packet, packet_no, tx_status, pkt_len;
 
 	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
@@ -809,7 +826,8 @@ static void smc_tx(struct net_device *de
 
 static void smc_mii_out(struct net_device *dev, unsigned int val, int bits)
 {
-	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int mii_reg, mask;
 
 	mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO);
@@ -830,7 +848,8 @@ static void smc_mii_out(struct net_devic
 
 static unsigned int smc_mii_in(struct net_device *dev, int bits)
 {
-	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int mii_reg, mask, val;
 
 	mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO);
@@ -854,7 +873,8 @@ static unsigned int smc_mii_in(struct ne
  */
 static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
 {
-	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int phydata;
 
 	SMC_SELECT_BANK(3);
@@ -884,7 +904,8 @@ static int smc_phy_read(struct net_devic
 static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
 			  int phydata)
 {
-	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 
 	SMC_SELECT_BANK(3);
 
@@ -946,7 +967,7 @@ static void smc_phy_detect(struct net_de
 static int smc_phy_fixed(struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	int phyaddr = lp->mii.phy_id;
 	int bmcr, cfg1;
 
@@ -1017,13 +1038,29 @@ static int smc_phy_reset(struct net_devi
 /*
  * smc_phy_powerdown - powerdown phy
  * @dev: net device
- * @phy: phy address
  *
  * Power down the specified PHY
  */
-static void smc_phy_powerdown(struct net_device *dev, int phy)
+static void smc_phy_powerdown(struct net_device *dev)
 {
+	struct smc_local *lp = netdev_priv(dev);
 	unsigned int bmcr;
+	int phy = lp->mii.phy_id;
+
+	if (lp->phy_type == 0)
+		return;
+
+	/* We need to ensure that no calls to smc_phy_configure are
+	   pending.
+
+	   flush_scheduled_work() cannot be called because we are
+	   running with the netlink semaphore held (from
+	   devinet_ioctl()) and the pending work queue contains
+	   linkwatch_event() (scheduled by netif_carrier_off()
+	   above). linkwatch_event() also wants the netlink semaphore.
+	*/
+	while(lp->work_pending)
+		schedule();
 
 	bmcr = smc_phy_read(dev, phy, MII_BMCR);
 	smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1040,7 +1077,7 @@ static void smc_phy_powerdown(struct net
 static void smc_phy_check_media(struct net_device *dev, int init)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 
 	if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
 		/* duplex state has changed */
@@ -1068,7 +1105,7 @@ static void smc_phy_configure(void *data
 {
 	struct net_device *dev = data;
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	int phyaddr = lp->mii.phy_id;
 	int my_phy_caps; /* My PHY capabilities */
 	int my_ad_caps; /* My Advertised capabilities */
@@ -1193,7 +1230,7 @@ static void smc_phy_interrupt(struct net
 static void smc_10bt_check_media(struct net_device *dev, int init)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	unsigned int old_carrier, new_carrier;
 
 	old_carrier = netif_carrier_ok(dev) ? 1 : 0;
@@ -1216,7 +1253,8 @@ static void smc_10bt_check_media(struct 
 
 static void smc_eph_interrupt(struct net_device *dev)
 {
-	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	unsigned int ctl;
 
 	smc_10bt_check_media(dev, 0);
@@ -1235,8 +1273,8 @@ static void smc_eph_interrupt(struct net
 static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
-	unsigned long ioaddr = dev->base_addr;
 	struct smc_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
 	int status, mask, timeout, card_stats;
 	int saved_pointer;
 
@@ -1350,7 +1388,7 @@ static void smc_poll_controller(struct n
 static void smc_timeout(struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	int status, mask, meminfo, fifo;
 
 	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
@@ -1394,7 +1432,7 @@ static void smc_timeout(struct net_devic
 static void smc_set_multicast_list(struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
-	unsigned long ioaddr = dev->base_addr;
+	void __iomem *ioaddr = lp->base;
 	unsigned char multicast_table[8];
 	int update_multicast = 0;
 
@@ -1561,21 +1599,7 @@ static int smc_close(struct net_device *
 	/* clear everything */
 	smc_shutdown(dev);
 
-	if (lp->phy_type != 0) {
-		/* We need to ensure that no calls to
-		   smc_phy_configure are pending.
-
-		   flush_scheduled_work() cannot be called because we
-		   are running with the netlink semaphore held (from
-		   devinet_ioctl()) and the pending work queue
-		   contains linkwatch_event() (scheduled by
-		   netif_carrier_off() above). linkwatch_event() also
-		   wants the netlink semaphore.
-		*/
-		while(lp->work_pending)
-			schedule();
-		smc_phy_powerdown(dev, lp->mii.phy_id);
-	}
+	smc_phy_powerdown(dev);
 
 	if (lp->pending_tx_skb) {
 		dev_kfree_skb(lp->pending_tx_skb);
@@ -1723,7 +1747,7 @@ static struct ethtool_ops smc_ethtool_op
  * I just deleted auto_irq.c, since it was never built...
  *   --jgarzik
  */
-static int __init smc_findirq(unsigned long ioaddr)
+static int __init smc_findirq(void __iomem *ioaddr)
 {
 	int timeout = 20;
 	unsigned long cookie;
@@ -1796,7 +1820,7 @@ static int __init smc_findirq(unsigned l
  * o  actually GRAB the irq.
  * o  GRAB the region
  */
-static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
+static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
 {
 	struct smc_local *lp = netdev_priv(dev);
 	static int version_printed = 0;
@@ -1813,7 +1837,7 @@ static int __init smc_probe(struct net_d
 		if ((val & 0xFF) == 0x33) {
 			printk(KERN_WARNING
 				"%s: Detected possible byte-swapped interface"
-				" at IOADDR 0x%lx\n", CARDNAME, ioaddr);
+				" at IOADDR %p\n", CARDNAME, ioaddr);
 		}
 		retval = -ENODEV;
 		goto err_out;
@@ -1839,8 +1863,8 @@ static int __init smc_probe(struct net_d
 	SMC_SELECT_BANK(1);
 	val = SMC_GET_BASE();
 	val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
-	if ((ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val) {
-		printk("%s: IOADDR %lx doesn't match configuration (%x).\n",
+	if (((unsigned long)ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val) { /*XXX: WTF? */
+		printk("%s: IOADDR %p doesn't match configuration (%x).\n",
 			CARDNAME, ioaddr, val);
 	}
 
@@ -1855,7 +1879,7 @@ static int __init smc_probe(struct net_d
 	version_string = chip_ids[ (revision_register >> 4) & 0xF];
 	if (!version_string || (revision_register & 0xff00) != 0x3300) {
 		/* I don't recognize this chip, so... */
-		printk("%s: IO 0x%lx: Unrecognized revision register 0x%04x"
+		printk("%s: IO %p: Unrecognized revision register 0x%04x"
 			", Contact author.\n", CARDNAME,
 			ioaddr, revision_register);
 
@@ -1868,7 +1892,8 @@ static int __init smc_probe(struct net_d
 		printk("%s", version);
 
 	/* fill in some of the fields */
-	dev->base_addr = ioaddr;
+	dev->base_addr = (unsigned long)ioaddr;
+	lp->base = ioaddr;
 	lp->version = revision_register & 0xff;
 	spin_lock_init(&lp->lock);
 
@@ -1974,9 +1999,9 @@ static int __init smc_probe(struct net_d
 	retval = register_netdev(dev);
 	if (retval == 0) {
 		/* now, print out the card info, in a short format.. */
-		printk("%s: %s (rev %d) at %#lx IRQ %d",
+		printk("%s: %s (rev %d) at %p IRQ %d",
 			dev->name, version_string, revision_register & 0x0f,
-			dev->base_addr, dev->irq);
+			lp->base, dev->irq);
 
 		if (dev->dma != (unsigned char)-1)
 			printk(" DMA %d", dev->dma);
@@ -2012,16 +2037,21 @@ err_out:
 	return retval;
 }
 
-static int smc_enable_device(unsigned long attrib_phys)
+static int smc_enable_device(struct platform_device *pdev)
 {
 	unsigned long flags;
 	unsigned char ecor, ecsr;
-	void *addr;
+	void __iomem *addr;
+	struct resource * res;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+	if (!res)
+		return 0;
 
 	/*
 	 * Map the attribute space.  This is overkill, but clean.
 	 */
-	addr = ioremap(attrib_phys, ATTRIB_SIZE);
+	addr = ioremap(res->start, ATTRIB_SIZE);
 	if (!addr)
 		return -ENOMEM;
 
@@ -2069,6 +2099,62 @@ static int smc_enable_device(unsigned lo
 	return 0;
 }
 
+static int smc_request_attrib(struct platform_device *pdev)
+{
+	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+
+	if (!res)
+		return 0;
+
+	if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))
+		return -EBUSY;
+
+	return 0;
+}
+
+static void smc_release_attrib(struct platform_device *pdev)
+{
+	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+
+	if (res)
+		release_mem_region(res->start, ATTRIB_SIZE);
+}
+
+#ifdef SMC_CAN_USE_DATACS
+static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+	struct smc_local *lp = netdev_priv(ndev);
+
+	if (!res)
+		return;
+
+	if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) {
+		printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME);
+		return;
+	}
+
+	lp->datacs = ioremap(res->start, SMC_DATA_EXTENT);
+}
+
+static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+	struct smc_local *lp = netdev_priv(ndev);
+	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+
+	if (lp->datacs)
+		iounmap(lp->datacs);
+
+	lp->datacs = NULL;
+
+	if (res)
+		release_mem_region(res->start, SMC_DATA_EXTENT);
+}
+#else
+static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) {}
+static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) {}
+#endif
+
 /*
  * smc_init(void)
  *   Input parameters:
@@ -2084,20 +2170,20 @@ static int smc_drv_probe(struct device *
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct net_device *ndev;
-	struct resource *res, *ext = NULL;
-	unsigned int *addr;
+	struct resource *res;
+	unsigned int __iomem *addr;
 	int ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+	if (!res)
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		ret = -ENODEV;
 		goto out;
 	}
 
-	/*
-	 * Request the regions.
-	 */
-	if (!request_mem_region(res->start, SMC_IO_EXTENT, "smc91x")) {
+
+	if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
 		ret = -EBUSY;
 		goto out;
 	}
@@ -2106,7 +2192,7 @@ static int smc_drv_probe(struct device *
 	if (!ndev) {
 		printk("%s: could not allocate device.\n", CARDNAME);
 		ret = -ENOMEM;
-		goto release_1;
+		goto out_release_io;
 	}
 	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, dev);
@@ -2114,42 +2200,26 @@ static int smc_drv_probe(struct device *
 	ndev->dma = (unsigned char)-1;
 	ndev->irq = platform_get_irq(pdev, 0);
 
-	ext = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (ext) {
-		if (!request_mem_region(ext->start, ATTRIB_SIZE, ndev->name)) {
-			ret = -EBUSY;
-			goto release_1;
-		}
-
+	ret = smc_request_attrib(pdev);
+	if (ret)
+		goto out_free_netdev;
 #if defined(CONFIG_SA1100_ASSABET)
-		NCR_0 |= NCR_ENET_OSC_EN;
+	NCR_0 |= NCR_ENET_OSC_EN;
 #endif
-
-		ret = smc_enable_device(ext->start);
-		if (ret)
-			goto release_both;
-	}
+	ret = smc_enable_device(pdev);
+	if (ret)
+		goto out_release_attrib;
 
 	addr = ioremap(res->start, SMC_IO_EXTENT);
 	if (!addr) {
 		ret = -ENOMEM;
-		goto release_both;
+		goto out_release_attrib;
 	}
 
 	dev_set_drvdata(dev, ndev);
-	ret = smc_probe(ndev, (unsigned long)addr);
-	if (ret != 0) {
-		dev_set_drvdata(dev, NULL);
-		iounmap(addr);
- release_both:
-		if (ext)
-			release_mem_region(ext->start, ATTRIB_SIZE);
-		free_netdev(ndev);
- release_1:
-		release_mem_region(res->start, SMC_IO_EXTENT);
- out:
-		printk("%s: not found (%d).\n", CARDNAME, ret);
-	}
+	ret = smc_probe(ndev, addr);
+	if (ret != 0)
+		goto out_iounmap;
 #ifdef SMC_USE_PXA_DMA
 	else {
 		struct smc_local *lp = netdev_priv(ndev);
@@ -2157,6 +2227,22 @@ static int smc_drv_probe(struct device *
 	}
 #endif
 
+	smc_request_datacs(pdev, ndev);
+
+	return 0;
+
+ out_iounmap:
+	dev_set_drvdata(dev, NULL);
+	iounmap(addr);
+ out_release_attrib:
+	smc_release_attrib(pdev);
+ out_free_netdev:
+	free_netdev(ndev);
+ out_release_io:
+	release_mem_region(res->start, SMC_IO_EXTENT);
+ out:
+	printk("%s: not found (%d).\n", CARDNAME, ret);
+
 	return ret;
 }
 
@@ -2164,6 +2250,7 @@ static int smc_drv_remove(struct device 
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct net_device *ndev = dev_get_drvdata(dev);
+	struct smc_local *lp = netdev_priv(ndev);
 	struct resource *res;
 
 	dev_set_drvdata(dev, NULL);
@@ -2176,11 +2263,14 @@ static int smc_drv_remove(struct device 
 	if (ndev->dma != (unsigned char)-1)
 		pxa_free_dma(ndev->dma);
 #endif
-	iounmap((void *)ndev->base_addr);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (res)
-		release_mem_region(res->start, ATTRIB_SIZE);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(lp->base);
+
+	smc_release_datacs(pdev,ndev);
+	smc_release_attrib(pdev);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+	if (!res)
+		platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(res->start, SMC_IO_EXTENT);
 
 	free_netdev(ndev);
@@ -2188,7 +2278,7 @@ static int smc_drv_remove(struct device 
 	return 0;
 }
 
-static int smc_drv_suspend(struct device *dev, u32 state, u32 level)
+static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 
@@ -2196,6 +2286,7 @@ static int smc_drv_suspend(struct device
 		if (netif_running(ndev)) {
 			netif_device_detach(ndev);
 			smc_shutdown(ndev);
+			smc_phy_powerdown(ndev);
 		}
 	}
 	return 0;
@@ -2208,9 +2299,7 @@ static int smc_drv_resume(struct device 
 
 	if (ndev && level == RESUME_ENABLE) {
 		struct smc_local *lp = netdev_priv(ndev);
-
-		if (pdev->num_resources == 3)
-			smc_enable_device(pdev->resource[2].start);
+		smc_enable_device(pdev);
 		if (netif_running(ndev)) {
 			smc_reset(ndev);
 			smc_enable(ndev);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -162,6 +162,45 @@ SMC_outw(u16 val, unsigned long ioaddr, 
 	}
 }
 
+#elif	defined(CONFIG_ARCH_OMAP)
+
+/* We can only do 16-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+#define SMC_IO_SHIFT		0
+#define SMC_NOWAIT		1
+
+#define SMC_inb(a, r)		readb((a) + (r))
+#define SMC_outb(v, a, r)	writeb(v, (a) + (r))
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_outw(v, a, r)	writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+#define SMC_inl(a, r)		readl((a) + (r))
+#define SMC_outl(v, a, r)	writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
+
+#elif	defined(CONFIG_SH_SH4202_MICRODEV)
+
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+
+#define SMC_inb(a, r)		inb((a) + (r) - 0xa0000000)
+#define SMC_inw(a, r)		inw((a) + (r) - 0xa0000000)
+#define SMC_inl(a, r)		inl((a) + (r) - 0xa0000000)
+#define SMC_outb(v, a, r)	outb(v, (a) + (r) - 0xa0000000)
+#define SMC_outw(v, a, r)	outw(v, (a) + (r) - 0xa0000000)
+#define SMC_outl(v, a, r)	outl(v, (a) + (r) - 0xa0000000)
+#define SMC_insl(a, r, p, l)	insl((a) + (r) - 0xa0000000, p, l)
+#define SMC_outsl(a, r, p, l)	outsl((a) + (r) - 0xa0000000, p, l)
+#define SMC_insw(a, r, p, l)	insw((a) + (r) - 0xa0000000, p, l)
+#define SMC_outsw(a, r, p, l)	outsw((a) + (r) - 0xa0000000, p, l)
+
+#define set_irq_type(irq, type)	do {} while(0)
+
 #elif	defined(CONFIG_ISA)
 
 #define SMC_CAN_USE_8BIT	1
@@ -362,7 +401,7 @@ smc_pxa_dma_irq(int dma, void *dummy, st
 #define SMC_IO_SHIFT	0
 #endif
 #define SMC_IO_EXTENT	(16 << SMC_IO_SHIFT)
-
+#define SMC_DATA_EXTENT (4)
 
 /*
  . Bank Select Register:
@@ -883,7 +922,7 @@ static const char * chip_ids[ 16 ] =  {
 #endif
 
 #if SMC_CAN_USE_32BIT
-#define SMC_PUSH_DATA(p, l)						\
+#define _SMC_PUSH_DATA(p, l)						\
 	do {								\
 		char *__ptr = (p);					\
 		int __len = (l);					\
@@ -898,7 +937,7 @@ static const char * chip_ids[ 16 ] =  {
 			SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG );	\
 		}							\
 	} while (0)
-#define SMC_PULL_DATA(p, l)						\
+#define _SMC_PULL_DATA(p, l)						\
 	do {								\
 		char *__ptr = (p);					\
 		int __len = (l);					\
@@ -918,11 +957,11 @@ static const char * chip_ids[ 16 ] =  {
 		SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2);		\
 	} while (0)
 #elif SMC_CAN_USE_16BIT
-#define SMC_PUSH_DATA(p, l)	SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 )
-#define SMC_PULL_DATA(p, l)	SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 )
+#define _SMC_PUSH_DATA(p, l)	SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 )
+#define _SMC_PULL_DATA(p, l)	SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 )
 #elif SMC_CAN_USE_8BIT
-#define SMC_PUSH_DATA(p, l)	SMC_outsb( ioaddr, DATA_REG, p, l )
-#define SMC_PULL_DATA(p, l)	SMC_insb ( ioaddr, DATA_REG, p, l )
+#define _SMC_PUSH_DATA(p, l)	SMC_outsb( ioaddr, DATA_REG, p, l )
+#define _SMC_PULL_DATA(p, l)	SMC_insb ( ioaddr, DATA_REG, p, l )
 #endif
 
 #if ! SMC_CAN_USE_16BIT
@@ -941,6 +980,51 @@ static const char * chip_ids[ 16 ] =  {
 	})
 #endif
 
+#if SMC_CAN_USE_DATACS
+#define SMC_PUSH_DATA(p, l)						\
+	if ( lp->datacs ) {						\
+		unsigned char *__ptr = (p);				\
+		int __len = (l);					\
+ 		if (__len >= 2 && (unsigned long)__ptr & 2) {		\
+ 			__len -= 2;					\
+ 			SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG );	\
+ 			__ptr += 2;					\
+ 		}							\
+		outsl(lp->datacs, __ptr, __len >> 2);			\
+ 		if (__len & 2) {					\
+ 			__ptr += (__len & ~3);				\
+ 			SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG );	\
+ 		}							\
+	} else {							\
+		_SMC_PUSH_DATA(p, l);					\
+	}
+
+#define SMC_PULL_DATA(p, l)						\
+	if ( lp->datacs ) { 						\
+		unsigned char *__ptr = (p);				\
+		int __len = (l);					\
+		if ((unsigned long)__ptr & 2) {			 	\
+			/*						\
+			 * We want 32bit alignment here.		\
+			 * Since some buses perform a full 32bit	\
+			 * fetch even for 16bit data we can't use	\
+			 * SMC_inw() here.  Back both source (on chip	\
+			 * and destination) pointers of 2 bytes.	\
+			 */						\
+			__ptr -= 2;					\
+			__len += 2;					\
+			SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); 	\
+		}							\
+		__len += 2;						\
+		insl( lp->datacs, __ptr, __len >> 2);			\
+	} else {							\
+		_SMC_PULL_DATA(p, l);					\
+	}
+#else
+#define SMC_PUSH_DATA(p, l) _SMC_PUSH_DATA(p, l)
+#define SMC_PULL_DATA(p, l) _SMC_PULL_DATA(p, l)
+#endif
+
 #if !defined (SMC_INTERRUPT_PREAMBLE)
 # define SMC_INTERRUPT_PREAMBLE
 #endif
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -116,7 +116,7 @@ static int sonic_send_packet(struct sk_b
 	/*
 	 * Map the packet data into the logical DMA address space
 	 */
-	if ((laddr = vdma_alloc(PHYSADDR(skb->data), skb->len)) == ~0UL) {
+	if ((laddr = vdma_alloc(CPHYSADDR(skb->data), skb->len)) == ~0UL) {
 		printk("%s: no VDMA entry for transmit available.\n",
 		       dev->name);
 		dev_kfree_skb(skb);
@@ -223,7 +223,7 @@ static irqreturn_t sonic_interrupt(int i
 
 			/* We must free the original skb */
 			if (lp->tx_skb[entry]) {
-				dev_kfree_skb(lp->tx_skb[entry]);
+				dev_kfree_skb_irq(lp->tx_skb[entry]);
 				lp->tx_skb[entry] = 0;
 			}
 			/* and the VDMA address */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -37,8 +37,18 @@
 
 #include "sunbmac.h"
 
+#define DRV_NAME	"sunbmac"
+#define DRV_VERSION	"2.0"
+#define DRV_RELDATE	"11/24/03"
+#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
+
 static char version[] __initdata =
-        "sunbmac.c:v2.0 24/Nov/03 David S. Miller (davem@redhat.com)\n";
+	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION("Sun BigMAC 100baseT ethernet driver");
+MODULE_LICENSE("GPL");
 
 #undef DEBUG_PROBE
 #undef DEBUG_TX
@@ -1321,4 +1331,3 @@ static void __exit bigmac_cleanup(void)
 
 module_init(bigmac_probe);
 module_exit(bigmac_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1210,9 +1210,11 @@ static irqreturn_t intr_handler(int irq,
 				}
 				/* Yup, this is a documentation bug.  It cost me *hours*. */
 				iowrite16 (0, ioaddr + TxStatus);
-				tx_status = ioread16 (ioaddr + TxStatus);
-				if (tx_cnt < 0)
+				if (tx_cnt < 0) {
+					iowrite32(5000, ioaddr + DownCounter);
 					break;
+				}
+				tx_status = ioread16 (ioaddr + TxStatus);
 			}
 			hw_frame_id = (tx_status >> 8) & 0xff;
 		} else 	{
@@ -1278,7 +1280,6 @@ static irqreturn_t intr_handler(int irq,
 	if (netif_msg_intr(np))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, ioread16(ioaddr + IntrStatus));
-	iowrite32(5000, ioaddr + DownCounter);
 	return IRQ_RETVAL(handled);
 }
 
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -3,16 +3,32 @@
  *
  * Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem@redhat.com)
  * 
- * Support for Apple GMAC and assorted PHYs by
- * Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * Support for Apple GMAC and assorted PHYs, WOL, Power Management
+ * (C) 2001,2002,2003 Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * (C) 2004,2005 Benjamin Herrenscmidt, IBM Corp.
  *
  * NAPI and NETPOLL support
  * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com)
  * 
  * TODO: 
- *  - Get rid of all those nasty mdelay's and replace them
- * with schedule_timeout.
- *  - Implement WOL
+ *  - Now that the driver was significantly simplified, I need to rework
+ *    the locking. I'm sure we don't need _2_ spinlocks, and we probably
+ *    can avoid taking most of them for so long period of time (and schedule
+ *    instead). The main issues at this point are caused by the netdev layer
+ *    though:
+ *    
+ *    gem_change_mtu() and gem_set_multicast() are called with a read_lock()
+ *    help by net/core/dev.c, thus they can't schedule. That means they can't
+ *    call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
+ *    where it could have been dropped. change_mtu especially would love also to
+ *    be able to msleep instead of horrid locked delays when resetting the HW,
+ *    but that read_lock() makes it impossible, unless I defer it's action to
+ *    the reset task, which means it'll be asynchronous (won't take effect until
+ *    the system schedules a bit).
+ *
+ *    Also, it would probably be possible to also remove most of the long-life
+ *    locking in open/resume code path (gem_reinit_chip) by beeing more careful
+ *    about when we can start taking interrupts or get xmit() called...
  */
 
 #include <linux/module.h>
@@ -109,6 +125,8 @@ static struct pci_device_id gem_pci_tbl[
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_GMAC,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_SUNGEM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
@@ -196,6 +214,33 @@ static inline void gem_disable_ints(stru
 	writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
 }
 
+static void gem_get_cell(struct gem *gp)
+{
+	BUG_ON(gp->cell_enabled < 0);
+	gp->cell_enabled++;
+#ifdef CONFIG_PPC_PMAC
+	if (gp->cell_enabled == 1) {
+		mb();
+		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
+		udelay(10);
+	}
+#endif /* CONFIG_PPC_PMAC */
+}
+
+/* Turn off the chip's clock */
+static void gem_put_cell(struct gem *gp)
+{
+	BUG_ON(gp->cell_enabled <= 0);
+	gp->cell_enabled--;
+#ifdef CONFIG_PPC_PMAC
+	if (gp->cell_enabled == 0) {
+		mb();
+		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+		udelay(10);
+	}
+#endif /* CONFIG_PPC_PMAC */
+}
+
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
 {
 	if (netif_msg_intr(gp))
@@ -319,7 +364,19 @@ static int gem_rxmac_reset(struct gem *g
 	u64 desc_dma;
 	u32 val;
 
-	/* First, reset MAC RX. */
+	/* First, reset & disable MAC RX. */
+	writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
+	for (limit = 0; limit < 5000; limit++) {
+		if (!(readl(gp->regs + MAC_RXRST) & MAC_RXRST_CMD))
+			break;
+		udelay(10);
+	}
+	if (limit == 5000) {
+		printk(KERN_ERR "%s: RX MAC will not reset, resetting whole "
+                       "chip.\n", dev->name);
+		return 1;
+	}
+
 	writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB,
 	       gp->regs + MAC_RXCFG);
 	for (limit = 0; limit < 5000; limit++) {
@@ -597,7 +654,7 @@ static int gem_abnormal_irq(struct net_d
 	return 0;
 
 do_reset:
-	gp->reset_task_pending = 2;
+	gp->reset_task_pending = 1;
 	schedule_work(&gp->reset_task);
 
 	return 1;
@@ -823,6 +880,9 @@ static int gem_poll(struct net_device *d
 	struct gem *gp = dev->priv;
 	unsigned long flags;
 
+	/*
+	 * NAPI locking nightmare: See comment at head of driver 
+	 */
 	spin_lock_irqsave(&gp->lock, flags);
 
 	do {
@@ -874,8 +934,11 @@ static irqreturn_t gem_interrupt(int irq
 	struct gem *gp = dev->priv;
 	unsigned long flags;
 
-	/* Swallow interrupts when shutting the chip down */
-	if (!gp->hw_running)
+	/* Swallow interrupts when shutting the chip down, though
+	 * that shouldn't happen, we should have done free_irq() at
+	 * this point...
+	 */
+	if (!gp->running)
 		return IRQ_HANDLED;
 
 	spin_lock_irqsave(&gp->lock, flags);
@@ -916,7 +979,7 @@ static void gem_tx_timeout(struct net_de
 	struct gem *gp = dev->priv;
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
-	if (!gp->hw_running) {
+	if (!gp->running) {
 		printk("%s: hrm.. hw not running !\n", dev->name);
 		return;
 	}
@@ -934,7 +997,7 @@ static void gem_tx_timeout(struct net_de
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
 
-	gp->reset_task_pending = 2;
+	gp->reset_task_pending = 1;
 	schedule_work(&gp->reset_task);
 
 	spin_unlock(&gp->tx_lock);
@@ -975,6 +1038,11 @@ static int gem_start_xmit(struct sk_buff
 		local_irq_restore(flags);
 		return NETDEV_TX_LOCKED;
 	}
+	/* We raced with gem_do_stop() */
+	if (!gp->running) {
+		spin_unlock_irqrestore(&gp->tx_lock, flags);
+		return NETDEV_TX_BUSY;
+	}
 
 	/* This is a hard error, log it. */
 	if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
@@ -1073,46 +1141,10 @@ static int gem_start_xmit(struct sk_buff
 	return NETDEV_TX_OK;
 }
 
-/* Jumbo-grams don't seem to work :-( */
-#define GEM_MIN_MTU	68
-#if 1
-#define GEM_MAX_MTU	1500
-#else
-#define GEM_MAX_MTU	9000
-#endif
-
-static int gem_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct gem *gp = dev->priv;
-
-	if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
-		return -EINVAL;
-
-	if (!netif_running(dev) || !netif_device_present(dev)) {
-		/* We'll just catch it later when the
-		 * device is up'd or resumed.
-		 */
-		dev->mtu = new_mtu;
-		return 0;
-	}
-
-	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
-	dev->mtu = new_mtu;
-	gp->reset_task_pending = 1;
-	schedule_work(&gp->reset_task);
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
-
-	flush_scheduled_work();
-
-	return 0;
-}
-
 #define STOP_TRIES 32
 
 /* Must be invoked under gp->lock and gp->tx_lock. */
-static void gem_stop(struct gem *gp)
+static void gem_reset(struct gem *gp)
 {
 	int limit;
 	u32 val;
@@ -1140,7 +1172,7 @@ static void gem_stop(struct gem *gp)
 /* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_start_dma(struct gem *gp)
 {
-	unsigned long val;
+	u32 val;
 	
 	/* We are ready to rock, turn everything on. */
 	val = readl(gp->regs + TXDMA_CFG);
@@ -1155,10 +1187,31 @@ static void gem_start_dma(struct gem *gp
 	(void) readl(gp->regs + MAC_RXCFG);
 	udelay(100);
 
-	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
+	gem_enable_ints(gp);
 
 	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+}
+
+/* Must be invoked under gp->lock and gp->tx_lock. DMA won't be
+ * actually stopped before about 4ms tho ...
+ */
+static void gem_stop_dma(struct gem *gp)
+{
+	u32 val;
+
+	/* We are done rocking, turn everything off. */
+	val = readl(gp->regs + TXDMA_CFG);
+	writel(val & ~TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
+	val = readl(gp->regs + RXDMA_CFG);
+	writel(val & ~RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+	val = readl(gp->regs + MAC_TXCFG);
+	writel(val & ~MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG);
+	val = readl(gp->regs + MAC_RXCFG);
+	writel(val & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+	(void) readl(gp->regs + MAC_RXCFG);
 
+	/* Need to wait a bit ... done by the caller */
 }
 
 
@@ -1219,10 +1272,10 @@ start_aneg:
 	if (speed == 0)
 		speed = SPEED_10;
 	
-	/* If HW is down, we don't try to actually setup the PHY, we
+	/* If we are asleep, we don't try to actually setup the PHY, we
 	 * just store the settings
 	 */
-	if (!gp->hw_running) {
+	if (gp->asleep) {
 		gp->phy_mii.autoneg = gp->want_autoneg = autoneg;
 		gp->phy_mii.speed = speed;
 		gp->phy_mii.duplex = duplex;
@@ -1279,6 +1332,9 @@ static int gem_set_link_modes(struct gem
 		printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
 			gp->dev->name, speed, (full_duplex ? "full" : "half"));
 
+	if (!gp->running)
+		return 0;
+
 	val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU);
 	if (full_duplex) {
 		val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL);
@@ -1405,48 +1461,19 @@ static int gem_mdio_link_not_up(struct g
 	}
 }
 
-static void gem_init_rings(struct gem *);
-static void gem_init_hw(struct gem *, int);
-
-static void gem_reset_task(void *data)
-{
-	struct gem *gp = (struct gem *) data;
-
-	netif_poll_disable(gp->dev);
-	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
-
-	if (gp->hw_running && gp->opened) {
-		netif_stop_queue(gp->dev);
-
-		/* Reset the chip & rings */
-		gem_stop(gp);
-		gem_init_rings(gp);
-
-		gem_init_hw(gp,
-			    (gp->reset_task_pending == 2));
-
-		netif_wake_queue(gp->dev);
-	}
-	gp->reset_task_pending = 0;
-
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
-	netif_poll_enable(gp->dev);
-}
-
 static void gem_link_timer(unsigned long data)
 {
 	struct gem *gp = (struct gem *) data;
 	int restart_aneg = 0;
 		
-	if (!gp->hw_running)
+	if (gp->asleep)
 		return;
 
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
+	gem_get_cell(gp);
 
-	/* If the link of task is still pending, we just
+	/* If the reset task is still pending, we just
 	 * reschedule the link timer
 	 */
 	if (gp->reset_task_pending)
@@ -1462,8 +1489,7 @@ static void gem_link_timer(unsigned long
 		if ((val & PCS_MIISTAT_LS) != 0) {
 			gp->lstate = link_up;
 			netif_carrier_on(gp->dev);
-			if (gp->opened)
-				(void)gem_set_link_modes(gp);
+			(void)gem_set_link_modes(gp);
 		}
 		goto restart;
 	}
@@ -1484,7 +1510,7 @@ static void gem_link_timer(unsigned long
 		} else if (gp->lstate != link_up) {
 			gp->lstate = link_up;
 			netif_carrier_on(gp->dev);
-			if (gp->opened && gem_set_link_modes(gp))
+			if (gem_set_link_modes(gp))
 				restart_aneg = 1;
 		}
 	} else {
@@ -1497,7 +1523,7 @@ static void gem_link_timer(unsigned long
 				printk(KERN_INFO "%s: Link down\n",
 					gp->dev->name);
 			netif_carrier_off(gp->dev);
-			gp->reset_task_pending = 2;
+			gp->reset_task_pending = 1;
 			schedule_work(&gp->reset_task);
 			restart_aneg = 1;
 		} else if (++gp->timer_ticks > 10) {
@@ -1514,6 +1540,7 @@ static void gem_link_timer(unsigned long
 restart:
 	mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
 out_unlock:
+	gem_put_cell(gp);
 	spin_unlock(&gp->tx_lock);
 	spin_unlock_irq(&gp->lock);
 }
@@ -1619,59 +1646,40 @@ static void gem_init_rings(struct gem *g
 	wmb();
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
+/* Init PHY interface and start link poll state machine */
 static void gem_init_phy(struct gem *gp)
 {
 	u32 mifcfg;
-	
+
 	/* Revert MIF CFG setting done on stop_phy */
 	mifcfg = readl(gp->regs + MIF_CFG);
 	mifcfg &= ~MIF_CFG_BBMODE;
 	writel(mifcfg, gp->regs + MIF_CFG);
 	
-#ifdef CONFIG_PPC_PMAC
 	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-		int i, j;
+		int i;
 
 		/* Those delay sucks, the HW seem to love them though, I'll
 		 * serisouly consider breaking some locks here to be able
 		 * to schedule instead
 		 */
-		pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
-		for (j = 0; j < 3; j++) {
+		for (i = 0; i < 3; i++) {
+#ifdef CONFIG_PPC_PMAC
+			pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
+			msleep(20);
+#endif
 			/* Some PHYs used by apple have problem getting back to us,
-			 * we _know_ it's actually at addr 0 or 1, that's a hack, but
-			 * it helps to do that reset now. I suspect some motherboards
-			 * don't wire the PHY reset line properly, thus the PHY doesn't
-			 * come back with the above pmac_call_feature.
+			 * we do an additional reset here
 			 */
-			gp->mii_phy_addr = 0;
-			phy_write(gp, MII_BMCR, BMCR_RESET);
-			gp->mii_phy_addr = 1;
 			phy_write(gp, MII_BMCR, BMCR_RESET);
-			/* We should probably break some locks here and schedule... */
-			mdelay(10);
-			
-			/* On K2, we only probe the internal PHY at address 1, other
-			 * addresses tend to return garbage.
-			 */
-			if (gp->pdev->device == PCI_DEVICE_ID_APPLE_K2_GMAC)
+			msleep(20);
+			if (phy_read(gp, MII_BMCR) != 0xffff)
 				break;
-
-			for (i = 0; i < 32; i++) {
-				gp->mii_phy_addr = i;
-				if (phy_read(gp, MII_BMCR) != 0xffff)
-					break;
-			}
-			if (i == 32) {
+			if (i == 2)
 				printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
 				       gp->dev->name);
-				gp->mii_phy_addr = 0;
-			} else
-				break;
 		}
 	}
-#endif /* CONFIG_PPC_PMAC */
 
 	if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
 	    gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
@@ -1755,6 +1763,16 @@ static void gem_init_phy(struct gem *gp)
 			val |= PCS_SCTRL_LOOP;
 		writel(val, gp->regs + PCS_SCTRL);
 	}
+
+	/* Default aneg parameters */
+	gp->timer_ticks = 0;
+	gp->lstate = link_down;
+	netif_carrier_off(gp->dev);
+
+	/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+	spin_lock_irq(&gp->lock);
+	gem_begin_auto_negotiation(gp, NULL);
+	spin_unlock_irq(&gp->lock);
 }
 
 /* Must be invoked under gp->lock and gp->tx_lock. */
@@ -1796,8 +1814,7 @@ static void gem_init_dma(struct gem *gp)
 }
 
 /* Must be invoked under gp->lock and gp->tx_lock. */
-static u32
-gem_setup_multicast(struct gem *gp)
+static u32 gem_setup_multicast(struct gem *gp)
 {
 	u32 rxcfg = 0;
 	int i;
@@ -1914,6 +1931,11 @@ static void gem_init_mac(struct gem *gp)
 	 * make no use of those events other than to record them.
 	 */
 	writel(0xffffffff, gp->regs + MAC_MCMASK);
+
+	/* Don't enable GEM's WOL in normal operations
+	 */
+	if (gp->has_wol)
+		writel(0, gp->regs + WOL_WAKECSR);
 }
 
 /* Must be invoked under gp->lock and gp->tx_lock. */
@@ -1975,6 +1997,23 @@ static int gem_check_invariants(struct g
 		gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
 		gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
 		gp->swrst_base = 0;
+
+		mif_cfg = readl(gp->regs + MIF_CFG);
+		mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
+		mif_cfg |= MIF_CFG_MDI0;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+		writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+		writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+
+		/* We hard-code the PHY address so we can properly bring it out of
+		 * reset later on, we can't really probe it at this point, though
+		 * that isn't an issue.
+		 */
+		if (gp->pdev->device == PCI_DEVICE_ID_APPLE_K2_GMAC)
+			gp->mii_phy_addr = 1;
+		else
+			gp->mii_phy_addr = 0;
+
 		return 0;
 	}
 
@@ -2053,68 +2092,28 @@ static int gem_check_invariants(struct g
 }
 
 /* Must be invoked under gp->lock and gp->tx_lock. */
-static void gem_init_hw(struct gem *gp, int restart_link)
+static void gem_reinit_chip(struct gem *gp)
 {
-	/* On Apple's gmac, I initialize the PHY only after
-	 * setting up the chip. It appears the gigabit PHYs
-	 * don't quite like beeing talked to on the GII when
-	 * the chip is not running, I suspect it might not
-	 * be clocked at that point. --BenH
-	 */
-	if (restart_link)
-		gem_init_phy(gp);
-	gem_init_pause_thresholds(gp);
-	gem_init_dma(gp);
-	gem_init_mac(gp);
-
-	if (restart_link) {
-		/* Default aneg parameters */
-		gp->timer_ticks = 0;
-		gp->lstate = link_down;
-		netif_carrier_off(gp->dev);
-
-		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
-		gem_begin_auto_negotiation(gp, NULL);
-	} else {
-		if (gp->lstate == link_up) {
-			netif_carrier_on(gp->dev);
-			gem_set_link_modes(gp);
-		}
-	}
-}
+	/* Reset the chip */
+	gem_reset(gp);
 
-#ifdef CONFIG_PPC_PMAC
-/* Enable the chip's clock and make sure it's config space is
- * setup properly. There appear to be no need to restore the
- * base addresses.
- */
-static void gem_apple_powerup(struct gem *gp)
-{
-	u32 mif_cfg;
+	/* Make sure ints are disabled */
+	gem_disable_ints(gp);
 
-	mb();
-	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
+	/* Allocate & setup ring buffers */
+	gem_init_rings(gp);
 
-	udelay(3);
-	
-	mif_cfg = readl(gp->regs + MIF_CFG);
-	mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
-	mif_cfg |= MIF_CFG_MDI0;
-	writel(mif_cfg, gp->regs + MIF_CFG);
-	writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
-	writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
-}
+	/* Configure pause thresholds */
+	gem_init_pause_thresholds(gp);
 
-/* Turn off the chip's clock */
-static void gem_apple_powerdown(struct gem *gp)
-{
-	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+	/* Init DMA & MAC engines */
+	gem_init_dma(gp);
+	gem_init_mac(gp);
 }
 
-#endif /* CONFIG_PPC_PMAC */
 
 /* Must be invoked with no lock held. */
-static void gem_stop_phy(struct gem *gp)
+static void gem_stop_phy(struct gem *gp, int wol)
 {
 	u32 mifcfg;
 	unsigned long flags;
@@ -2131,8 +2130,22 @@ static void gem_stop_phy(struct gem *gp)
 	mifcfg &= ~MIF_CFG_POLL;
 	writel(mifcfg, gp->regs + MIF_CFG);
 
-	if (gp->wake_on_lan) {
-		/* Setup wake-on-lan */
+	if (wol && gp->has_wol) {
+		unsigned char *e = &gp->dev->dev_addr[0];
+		u32 csr;
+
+		/* Setup wake-on-lan for MAGIC packet */
+		writel(MAC_RXCFG_HFE | MAC_RXCFG_SFCS | MAC_RXCFG_ENAB,
+		       gp->regs + MAC_RXCFG);	
+		writel((e[4] << 8) | e[5], gp->regs + WOL_MATCH0);
+		writel((e[2] << 8) | e[3], gp->regs + WOL_MATCH1);
+		writel((e[0] << 8) | e[1], gp->regs + WOL_MATCH2);
+
+		writel(WOL_MCOUNT_N | WOL_MCOUNT_M, gp->regs + WOL_MCOUNT);
+		csr = WOL_WAKECSR_ENABLE;
+		if ((readl(gp->regs + MAC_XIFCFG) & MAC_XIFCFG_GMII) == 0)
+			csr |= WOL_WAKECSR_MII;
+		writel(csr, gp->regs + WOL_WAKECSR);
 	} else {
 		writel(0, gp->regs + MAC_RXCFG);
 		(void)readl(gp->regs + MAC_RXCFG);
@@ -2148,20 +2161,20 @@ static void gem_stop_phy(struct gem *gp)
 	writel(0, gp->regs + TXDMA_CFG);
 	writel(0, gp->regs + RXDMA_CFG);
 
-	if (!gp->wake_on_lan) {
+	if (!wol) {
 		spin_lock_irqsave(&gp->lock, flags);
 		spin_lock(&gp->tx_lock);
-		gem_stop(gp);
+		gem_reset(gp);
 		writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
 		writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
 		spin_unlock(&gp->tx_lock);
 		spin_unlock_irqrestore(&gp->lock, flags);
-	}
 
-	if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend)
-		gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */);
+		/* No need to take the lock here */
+
+		if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend)
+			gp->phy_mii.def->ops->suspend(&gp->phy_mii);
 
-	if (!gp->wake_on_lan) {
 		/* According to Apple, we must set the MDIO pins to this begnign
 		 * state or we may 1) eat more current, 2) damage some PHYs
 		 */
@@ -2174,181 +2187,160 @@ static void gem_stop_phy(struct gem *gp)
 	}
 }
 
-/* Shut down the chip, must be called with pm_sem held.  */
-static void gem_shutdown(struct gem *gp)
+
+static int gem_do_start(struct net_device *dev)
 {
-	/* Make us not-running to avoid timers respawning
-	 * and swallow irqs 
-	 */
-	gp->hw_running = 0;
-	wmb();
+	struct gem *gp = dev->priv;
+	unsigned long flags;
 
-	/* Stop the link timer */
-	del_timer_sync(&gp->link_timer);
+	spin_lock_irqsave(&gp->lock, flags);
+	spin_lock(&gp->tx_lock);
 
-	/* Stop the reset task */
-	while (gp->reset_task_pending)
-		yield();
-	
-	/* Actually stop the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-		gem_stop_phy(gp);
+	/* Enable the cell */
+	gem_get_cell(gp);
 
-#ifdef CONFIG_PPC_PMAC
-		/* Power down the chip */
-		gem_apple_powerdown(gp);
-#endif /* CONFIG_PPC_PMAC */
-	} else{
-		unsigned long flags;
+	/* Init & setup chip hardware */
+	gem_reinit_chip(gp);
+
+	gp->running = 1;
+
+	if (gp->lstate == link_up) {
+		netif_carrier_on(gp->dev);
+		gem_set_link_modes(gp);
+	}
+
+	netif_wake_queue(gp->dev);
+
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irqrestore(&gp->lock, flags);
+
+	if (request_irq(gp->pdev->irq, gem_interrupt,
+				   SA_SHIRQ, dev->name, (void *)dev)) {
+		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
 
 		spin_lock_irqsave(&gp->lock, flags);
 		spin_lock(&gp->tx_lock);
-		gem_stop(gp);
+
+		gp->running =  0;
+		gem_reset(gp);
+		gem_clean_rings(gp);
+		gem_put_cell(gp);
+		
 		spin_unlock(&gp->tx_lock);
 		spin_unlock_irqrestore(&gp->lock, flags);
+
+		return -EAGAIN;
 	}
+
+	return 0;
 }
 
-static void gem_pm_task(void *data)
+static void gem_do_stop(struct net_device *dev, int wol)
 {
-	struct gem *gp = (struct gem *) data;
+	struct gem *gp = dev->priv;
+	unsigned long flags;
 
-	/* We assume if we can't lock the pm_sem, then open() was
-	 * called again (or suspend()), and we can safely ignore
-	 * the PM request
-	 */
-	if (down_trylock(&gp->pm_sem))
-		return;
+	spin_lock_irqsave(&gp->lock, flags);
+	spin_lock(&gp->tx_lock);
 
-	/* Driver was re-opened or already shut down */
-	if (gp->opened || !gp->hw_running) {
-		up(&gp->pm_sem);
-		return;
-	}
+	gp->running = 0;
+
+	/* Stop netif queue */
+	netif_stop_queue(dev);
 
-	gem_shutdown(gp);
+	/* Make sure ints are disabled */
+	gem_disable_ints(gp);
 
-	up(&gp->pm_sem);
-}
+	/* We can drop the lock now */
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irqrestore(&gp->lock, flags);
 
-static void gem_pm_timer(unsigned long data)
-{
-	struct gem *gp = (struct gem *) data;
+	/* If we are going to sleep with WOL */
+	gem_stop_dma(gp);
+	msleep(10);
+	if (!wol)
+		gem_reset(gp);
+	msleep(10);
+
+	/* Get rid of rings */
+	gem_clean_rings(gp);
 
-	schedule_work(&gp->pm_task);
+	/* No irq needed anymore */
+	free_irq(gp->pdev->irq, (void *) dev);
+
+	/* Cell not needed neither if no WOL */
+	if (!wol) {
+		spin_lock_irqsave(&gp->lock, flags);
+		gem_put_cell(gp);
+		spin_unlock_irqrestore(&gp->lock, flags);
+	}
 }
 
-static int gem_open(struct net_device *dev)
+static void gem_reset_task(void *data)
 {
-	struct gem *gp = dev->priv;
-	int hw_was_up;
+	struct gem *gp = (struct gem *) data;
 
 	down(&gp->pm_sem);
 
-	hw_was_up = gp->hw_running;
+	netif_poll_disable(gp->dev);
 
-	/* Stop the PM timer/task */
-	del_timer(&gp->pm_timer);
-	flush_scheduled_work();
+	spin_lock_irq(&gp->lock);
+	spin_lock(&gp->tx_lock);
 
-	/* The power-management semaphore protects the hw_running
-	 * etc. state so it is safe to do this bit without gp->lock
-	 */
-	if (!gp->hw_running) {
-#ifdef CONFIG_PPC_PMAC
-		/* First, we need to bring up the chip */
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-			gem_apple_powerup(gp);
-			gem_check_invariants(gp);
-		}
-#endif /* CONFIG_PPC_PMAC */
+	if (gp->running == 0)
+		goto not_running;
 
-		/* Reset the chip */
-		spin_lock_irq(&gp->lock);
-		spin_lock(&gp->tx_lock);
-		gem_stop(gp);
-		spin_unlock(&gp->tx_lock);
-		spin_unlock_irq(&gp->lock);
+	if (gp->running) {
+		netif_stop_queue(gp->dev);
 
-		gp->hw_running = 1;
+		/* Reset the chip & rings */
+		gem_reinit_chip(gp);
+		if (gp->lstate == link_up)
+			gem_set_link_modes(gp);
+		netif_wake_queue(gp->dev);
 	}
+ not_running:
+	gp->reset_task_pending = 0;
 
-	/* We can now request the interrupt as we know it's masked
-	 * on the controller
-	 */
-	if (request_irq(gp->pdev->irq, gem_interrupt,
-			SA_SHIRQ, dev->name, (void *)dev)) {
-		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
-
-		spin_lock_irq(&gp->lock);
-		spin_lock(&gp->tx_lock);
-#ifdef CONFIG_PPC_PMAC
-		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-			gem_apple_powerdown(gp);
-#endif /* CONFIG_PPC_PMAC */
-		/* Fire the PM timer that will shut us down in about 10 seconds */
-		gp->pm_timer.expires = jiffies + 10*HZ;
-		add_timer(&gp->pm_timer);
-		up(&gp->pm_sem);
-		spin_unlock(&gp->tx_lock);
-		spin_unlock_irq(&gp->lock);
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irq(&gp->lock);
 
-		return -EAGAIN;
-	}
+	netif_poll_enable(gp->dev);
 
-       	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
+	up(&gp->pm_sem);
+}
 
-	/* Allocate & setup ring buffers */
-	gem_init_rings(gp);
 
-	/* Init & setup chip hardware */
-	gem_init_hw(gp, !hw_was_up);
+static int gem_open(struct net_device *dev)
+{
+	struct gem *gp = dev->priv;
+	int rc = 0;
 
-	gp->opened = 1;
+	down(&gp->pm_sem);
 
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
+	/* We need the cell enabled */
+	if (!gp->asleep)
+		rc = gem_do_start(dev);
+	gp->opened = (rc == 0);
 
 	up(&gp->pm_sem);
 
-	return 0;
+	return rc;
 }
 
 static int gem_close(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
 
-	/* Make sure we don't get distracted by suspend/resume */
-	down(&gp->pm_sem);
-
 	/* Note: we don't need to call netif_poll_disable() here because
 	 * our caller (dev_close) already did it for us
 	 */
 
-	/* Stop traffic, mark us closed */
-	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
+	down(&gp->pm_sem);
 
 	gp->opened = 0;	
-
-	netif_stop_queue(dev);
-
-	/* Stop chip */
-	gem_stop(gp);
-
-	/* Get rid of rings */
-	gem_clean_rings(gp);
-
-	/* Bye, the pm timer will finish the job */
-	free_irq(gp->pdev->irq, (void *) dev);
-
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
-
-	/* Fire the PM timer that will shut us down in about 10 seconds */
-	gp->pm_timer.expires = jiffies + 10*HZ;
-	add_timer(&gp->pm_timer);
+	if (!gp->asleep)
+		gem_do_stop(dev, 0);
 
 	up(&gp->pm_sem);
 	
@@ -2356,49 +2348,66 @@ static int gem_close(struct net_device *
 }
 
 #ifdef CONFIG_PM
-static int gem_suspend(struct pci_dev *pdev, u32 state)
+static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct gem *gp = dev->priv;
+	unsigned long flags;
 
-	netif_poll_disable(dev);
-
-	/* We hold the PM semaphore during entire driver
-	 * sleep time
-	 */
 	down(&gp->pm_sem);
 
+	netif_poll_disable(dev);
+
 	printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
-	       dev->name, gp->wake_on_lan ? "enabled" : "disabled");
+	       dev->name,
+	       (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
 	
-	/* If the driver is opened, we stop the DMA */
-	if (gp->opened) {
-		spin_lock_irq(&gp->lock);
-		spin_lock(&gp->tx_lock);
+	/* Keep the cell enabled during the entire operation */
+	spin_lock_irqsave(&gp->lock, flags);
+	spin_lock(&gp->tx_lock);
+	gem_get_cell(gp);
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irqrestore(&gp->lock, flags);
 
+	/* If the driver is opened, we stop the MAC */
+	if (gp->opened) {
 		/* Stop traffic, mark us closed */
 		netif_device_detach(dev);
 
-		/* Stop chip */
-		gem_stop(gp);
+		/* Switch off MAC, remember WOL setting */
+		gp->asleep_wol = gp->wake_on_lan;
+		gem_do_stop(dev, gp->asleep_wol);
+	} else
+		gp->asleep_wol = 0;
 
-		/* Get rid of ring buffers */
-		gem_clean_rings(gp);
+	/* Mark us asleep */
+	gp->asleep = 1;
+	wmb();
 
-		spin_unlock(&gp->tx_lock);
-		spin_unlock_irq(&gp->lock);
+	/* Stop the link timer */
+	del_timer_sync(&gp->link_timer);
 
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-			disable_irq(gp->pdev->irq);
-	}
+	/* Now we release the semaphore to not block the reset task who
+	 * can take it too. We are marked asleep, so there will be no
+	 * conflict here
+	 */
+	up(&gp->pm_sem);
 
-	if (gp->hw_running) {
-		/* Kill PM timer if any */
-		del_timer_sync(&gp->pm_timer);
-		flush_scheduled_work();
+	/* Wait for a pending reset task to complete */
+	while (gp->reset_task_pending)
+		yield();
+	flush_scheduled_work();
 
-		gem_shutdown(gp);
-	}
+	/* Shut the PHY down eventually and setup WOL */
+	gem_stop_phy(gp, gp->asleep_wol);
+
+	/* Make sure bus master is disabled */
+	pci_disable_device(gp->pdev);
+
+	/* Release the cell, no need to take a lock at this point since
+	 * nothing else can happen now
+	 */
+	gem_put_cell(gp);
 
 	return 0;
 }
@@ -2407,36 +2416,74 @@ static int gem_resume(struct pci_dev *pd
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct gem *gp = dev->priv;
+	unsigned long flags;
 
 	printk(KERN_INFO "%s: resuming\n", dev->name);
 
-	if (gp->opened) {
-#ifdef CONFIG_PPC_PMAC
-		/* First, we need to bring up the chip */
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-			gem_apple_powerup(gp);
-			gem_check_invariants(gp);
-		}
-#endif /* CONFIG_PPC_PMAC */
-		spin_lock_irq(&gp->lock);
-		spin_lock(&gp->tx_lock);
+	down(&gp->pm_sem);
 
-		gem_stop(gp);
-		gp->hw_running = 1;
-		gem_init_rings(gp);
-		gem_init_hw(gp, 1);
+	/* Keep the cell enabled during the entire operation, no need to
+	 * take a lock here tho since nothing else can happen while we are
+	 * marked asleep
+	 */
+	gem_get_cell(gp);
+
+	/* Make sure PCI access and bus master are enabled */
+	if (pci_enable_device(gp->pdev)) {
+		printk(KERN_ERR "%s: Can't re-enable chip !\n",
+		       dev->name);
+		/* Put cell and forget it for now, it will be considered as
+		 * still asleep, a new sleep cycle may bring it back
+		 */
+		gem_put_cell(gp);
+		up(&gp->pm_sem);
+		return 0;
+	}
+	pci_set_master(gp->pdev);
 
-		spin_unlock(&gp->tx_lock);
-		spin_unlock_irq(&gp->lock);
+	/* Reset everything */
+	gem_reset(gp);
+
+	/* Mark us woken up */
+	gp->asleep = 0;
+	wmb();
 
+	/* Bring the PHY back. Again, lock is useless at this point as
+	 * nothing can be happening until we restart the whole thing
+	 */
+	gem_init_phy(gp);
+
+	/* If we were opened, bring everything back */
+	if (gp->opened) {
+		/* Restart MAC */
+		gem_do_start(dev);
+
+		/* Re-attach net device */
 		netif_device_attach(dev);
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-			enable_irq(gp->pdev->irq);
+
 	}
-	up(&gp->pm_sem);
+
+	spin_lock_irqsave(&gp->lock, flags);
+	spin_lock(&gp->tx_lock);
+
+	/* If we had WOL enabled, the cell clock was never turned off during
+	 * sleep, so we end up beeing unbalanced. Fix that here
+	 */
+	if (gp->asleep_wol)
+		gem_put_cell(gp);
+
+	/* This function doesn't need to hold the cell, it will be held if the
+	 * driver is open by gem_do_start().
+	 */
+	gem_put_cell(gp);
+
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irqrestore(&gp->lock, flags);
 
 	netif_poll_enable(dev);
 	
+	up(&gp->pm_sem);
+
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -2449,7 +2496,10 @@ static struct net_device_stats *gem_get_
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
 
-	if (gp->hw_running) {
+	/* I have seen this being called while the PM was in progress,
+	 * so we shield against this
+	 */
+	if (gp->running) {
 		stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
 		writel(0, gp->regs + MAC_FCSERR);
 
@@ -2479,12 +2529,13 @@ static void gem_set_multicast(struct net
 	u32 rxcfg, rxcfg_new;
 	int limit = 10000;
 	
-	if (!gp->hw_running)
-		return;
-		
+
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
 
+	if (!gp->running)
+		goto bail;
+
 	netif_stop_queue(dev);
 
 	rxcfg = readl(gp->regs + MAC_RXCFG);
@@ -2508,10 +2559,50 @@ static void gem_set_multicast(struct net
 
 	netif_wake_queue(dev);
 
+ bail:
 	spin_unlock(&gp->tx_lock);
 	spin_unlock_irq(&gp->lock);
 }
 
+/* Jumbo-grams don't seem to work :-( */
+#define GEM_MIN_MTU	68
+#if 1
+#define GEM_MAX_MTU	1500
+#else
+#define GEM_MAX_MTU	9000
+#endif
+
+static int gem_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct gem *gp = dev->priv;
+
+	if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
+		return -EINVAL;
+
+	if (!netif_running(dev) || !netif_device_present(dev)) {
+		/* We'll just catch it later when the
+		 * device is up'd or resumed.
+		 */
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	down(&gp->pm_sem);
+	spin_lock_irq(&gp->lock);
+	spin_lock(&gp->tx_lock);
+	dev->mtu = new_mtu;
+	if (gp->running) {
+		gem_reinit_chip(gp);
+		if (gp->lstate == link_up)
+			gem_set_link_modes(gp);
+	}
+	spin_unlock(&gp->tx_lock);
+	spin_unlock_irq(&gp->lock);
+	up(&gp->pm_sem);
+
+	return 0;
+}
+
 static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct gem *gp = dev->priv;
@@ -2540,7 +2631,6 @@ static int gem_get_settings(struct net_d
 
 		/* Return current PHY settings */
 		spin_lock_irq(&gp->lock);
-		spin_lock(&gp->tx_lock);
 		cmd->autoneg = gp->want_autoneg;
 		cmd->speed = gp->phy_mii.speed;
 		cmd->duplex = gp->phy_mii.duplex;			
@@ -2552,7 +2642,6 @@ static int gem_get_settings(struct net_d
 		 */
 		if (cmd->advertising == 0)
 			cmd->advertising = cmd->supported;
-		spin_unlock(&gp->tx_lock);
 		spin_unlock_irq(&gp->lock);
 	} else { // XXX PCS ?
 		cmd->supported =
@@ -2592,9 +2681,9 @@ static int gem_set_settings(struct net_d
 	      
 	/* Apply settings and restart link process. */
 	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
+	gem_get_cell(gp);
 	gem_begin_auto_negotiation(gp, cmd);
-	spin_unlock(&gp->tx_lock);
+	gem_put_cell(gp);
 	spin_unlock_irq(&gp->lock);
 
 	return 0;
@@ -2609,9 +2698,9 @@ static int gem_nway_reset(struct net_dev
 
 	/* Restart link process. */
 	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
+	gem_get_cell(gp);
 	gem_begin_auto_negotiation(gp, NULL);
-	spin_unlock(&gp->tx_lock);
+	gem_put_cell(gp);
 	spin_unlock_irq(&gp->lock);
 
 	return 0;
@@ -2628,7 +2717,37 @@ static void gem_set_msglevel(struct net_
 	struct gem *gp = dev->priv;
 	gp->msg_enable = value;
 }
-  
+
+
+/* Add more when I understand how to program the chip */
+/* like WAKE_UCAST | WAKE_MCAST | WAKE_BCAST */
+
+#define WOL_SUPPORTED_MASK	(WAKE_MAGIC)
+
+static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct gem *gp = dev->priv;
+
+	/* Add more when I understand how to program the chip */
+	if (gp->has_wol) {
+		wol->supported = WOL_SUPPORTED_MASK;
+		wol->wolopts = gp->wake_on_lan;
+	} else {
+		wol->supported = 0;
+		wol->wolopts = 0;
+	}
+}
+
+static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct gem *gp = dev->priv;
+
+	if (!gp->has_wol)
+		return -EOPNOTSUPP;
+	gp->wake_on_lan = wol->wolopts & WOL_SUPPORTED_MASK;
+	return 0;
+}
+
 static struct ethtool_ops gem_ethtool_ops = {
 	.get_drvinfo		= gem_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
@@ -2637,6 +2756,8 @@ static struct ethtool_ops gem_ethtool_op
 	.nway_reset		= gem_nway_reset,
 	.get_msglevel		= gem_get_msglevel,
 	.set_msglevel		= gem_set_msglevel,
+	.get_wol		= gem_get_wol,
+	.set_wol		= gem_set_wol,
 };
 
 static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -2644,22 +2765,28 @@ static int gem_ioctl(struct net_device *
 	struct gem *gp = dev->priv;
 	struct mii_ioctl_data *data = if_mii(ifr);
 	int rc = -EOPNOTSUPP;
-	
+	unsigned long flags;
+
 	/* Hold the PM semaphore while doing ioctl's or we may collide
-	 * with open/close and power management and oops.
+	 * with power management.
 	 */
 	down(&gp->pm_sem);
-	
+		
+	spin_lock_irqsave(&gp->lock, flags);
+	gem_get_cell(gp);
+	spin_unlock_irqrestore(&gp->lock, flags);
+
 	switch (cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 		data->phy_id = gp->mii_phy_addr;
 		/* Fallthrough... */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-		if (!gp->hw_running)
-			rc = -EIO;
+		if (!gp->running)
+			rc = -EAGAIN;
 		else {
-			data->val_out = __phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f);
+			data->val_out = __phy_read(gp, data->phy_id & 0x1f,
+						   data->reg_num & 0x1f);
 			rc = 0;
 		}
 		break;
@@ -2667,14 +2794,19 @@ static int gem_ioctl(struct net_device *
 	case SIOCSMIIREG:		/* Write MII PHY register. */
 		if (!capable(CAP_NET_ADMIN))
 			rc = -EPERM;
-		else if (!gp->hw_running)
-			rc = -EIO;
+		else if (!gp->running)
+			rc = -EAGAIN;
 		else {
-			__phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+			__phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
+				    data->val_in);
 			rc = 0;
 		}
 		break;
 	};
+	
+	spin_lock_irqsave(&gp->lock, flags);
+	gem_put_cell(gp);
+	spin_unlock_irqrestore(&gp->lock, flags);
 
 	up(&gp->pm_sem);
 	
@@ -2779,6 +2911,47 @@ static int __devinit gem_get_device_addr
 	return 0;
 }
 
+static void __devexit gem_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		struct gem *gp = dev->priv;
+
+		unregister_netdev(dev);
+
+		/* Stop the link timer */
+		del_timer_sync(&gp->link_timer);
+
+		/* We shouldn't need any locking here */
+		gem_get_cell(gp);
+
+		/* Wait for a pending reset task to complete */
+		while (gp->reset_task_pending)
+			yield();
+		flush_scheduled_work();
+
+		/* Shut the PHY down */
+		gem_stop_phy(gp, 0);
+
+		gem_put_cell(gp);
+
+		/* Make sure bus master is disabled */
+		pci_disable_device(gp->pdev);
+
+		/* Free resources */
+		pci_free_consistent(pdev,
+				    sizeof(struct gem_init_block),
+				    gp->init_block,
+				    gp->gblock_dvma);
+		iounmap(gp->regs);
+		pci_release_regions(pdev);
+		free_netdev(dev);
+
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
 static int __devinit gem_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
@@ -2827,7 +3000,7 @@ static int __devinit gem_init_one(struct
 		}
 		pci_using_dac = 0;
 	}
-
+	
 	gemreg_base = pci_resource_start(pdev, 0);
 	gemreg_len = pci_resource_len(pdev, 0);
 
@@ -2870,11 +3043,6 @@ static int __devinit gem_init_one(struct
 	gp->link_timer.function = gem_link_timer;
 	gp->link_timer.data = (unsigned long) gp;
 
-	init_timer(&gp->pm_timer);
-	gp->pm_timer.function = gem_pm_timer;
-	gp->pm_timer.data = (unsigned long) gp;
-
-	INIT_WORK(&gp->pm_task, gem_pm_task, gp);
 	INIT_WORK(&gp->reset_task, gem_reset_task, gp);
 	
 	gp->lstate = link_down;
@@ -2889,20 +3057,22 @@ static int __devinit gem_init_one(struct
 		goto err_out_free_res;
 	}
 
-	/* On Apple, we power the chip up now in order for check
-	 * invariants to work, but also because the firmware might
-	 * not have properly shut down the PHY.
+	/* On Apple, we want a reference to the Open Firmware device-tree
+	 * node. We use it for clock control.
 	 */
 #ifdef CONFIG_PPC_PMAC
 	gp->of_node = pci_device_to_OF_node(pdev);
-	if (pdev->vendor == PCI_VENDOR_ID_APPLE)
-		gem_apple_powerup(gp);
 #endif
-	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
-	gem_stop(gp);
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
+
+	/* Only Apple version supports WOL afaik */
+	if (pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gp->has_wol = 1;
+
+	/* Make sure cell is enabled */
+	gem_get_cell(gp);
+
+	/* Make sure everything is stopped and in init state */
+	gem_reset(gp);
 
 	/* Fill up the mii_phy structure (even if we won't use it) */
 	gp->phy_mii.dev = dev;
@@ -2911,7 +3081,8 @@ static int __devinit gem_init_one(struct
 
 	/* By default, we start with autoneg */
 	gp->want_autoneg = 1;
-	
+
+	/* Check fifo sizes, PHY type, etc... */
 	if (gem_check_invariants(gp)) {
 		err = -ENODEV;
 		goto err_out_iounmap;
@@ -2951,6 +3122,19 @@ static int __devinit gem_init_one(struct
 	dev->poll_controller = gem_poll_controller;
 #endif
 
+	/* Set that now, in case PM kicks in now */
+	pci_set_drvdata(pdev, dev);
+
+	/* Detect & init PHY, start autoneg, we release the cell now
+	 * too, it will be managed by whoever needs it
+	 */
+	gem_init_phy(gp);
+
+	spin_lock_irq(&gp->lock);
+	gem_put_cell(gp);
+	spin_unlock_irq(&gp->lock);
+
+	/* Register with kernel */
 	if (register_netdev(dev)) {
 		printk(KERN_ERR PFX "Cannot register net device, "
 		       "aborting.\n");
@@ -2965,48 +3149,22 @@ static int __devinit gem_init_one(struct
 		       i == 5 ? ' ' : ':');
 	printk("\n");
 
-	/* Detect & init PHY, start autoneg */
-	spin_lock_irq(&gp->lock);
-	spin_lock(&gp->tx_lock);
-	gp->hw_running = 1;
-	gem_init_phy(gp);
-	gem_begin_auto_negotiation(gp, NULL);
-	spin_unlock(&gp->tx_lock);
-	spin_unlock_irq(&gp->lock);
-
 	if (gp->phy_type == phy_mii_mdio0 ||
      	    gp->phy_type == phy_mii_mdio1)
 		printk(KERN_INFO "%s: Found %s PHY\n", dev->name, 
 			gp->phy_mii.def ? gp->phy_mii.def->name : "no");
 
-	pci_set_drvdata(pdev, dev);
-
 	/* GEM can do it all... */
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX;
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
-	/* Fire the PM timer that will shut us down in about 10 seconds */
-	gp->pm_timer.expires = jiffies + 10*HZ;
-	add_timer(&gp->pm_timer);
-
 	return 0;
 
 err_out_free_consistent:
-	pci_free_consistent(pdev,
-			    sizeof(struct gem_init_block),
-			    gp->init_block,
-			    gp->gblock_dvma);
-
+	gem_remove_one(pdev);
 err_out_iounmap:
-	down(&gp->pm_sem);
-	/* Stop the PM timer & task */
-	del_timer_sync(&gp->pm_timer);
-	flush_scheduled_work();
-	if (gp->hw_running)
-		gem_shutdown(gp);
-	up(&gp->pm_sem);
-
+	gem_put_cell(gp);
 	iounmap(gp->regs);
 
 err_out_free_res:
@@ -3020,34 +3178,6 @@ err_disable_device:
 
 }
 
-static void __devexit gem_remove_one(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-
-	if (dev) {
-		struct gem *gp = dev->priv;
-
-		unregister_netdev(dev);
-
-		down(&gp->pm_sem);
-		/* Stop the PM timer & task */
-		del_timer_sync(&gp->pm_timer);
-		flush_scheduled_work();
-		if (gp->hw_running)
-			gem_shutdown(gp);
-		up(&gp->pm_sem);
-
-		pci_free_consistent(pdev,
-				    sizeof(struct gem_init_block),
-				    gp->init_block,
-				    gp->gblock_dvma);
-		iounmap(gp->regs);
-		pci_release_regions(pdev);
-		free_netdev(dev);
-
-		pci_set_drvdata(pdev, NULL);
-	}
-}
 
 static struct pci_driver gem_driver = {
 	.name		= GEM_MODULE_NAME,
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -170,6 +170,27 @@
  * them later. -DaveM
  */
 
+/* WakeOnLan Registers	*/
+#define WOL_MATCH0	0x3000UL
+#define WOL_MATCH1	0x3004UL
+#define WOL_MATCH2	0x3008UL
+#define WOL_MCOUNT	0x300CUL
+#define WOL_WAKECSR	0x3010UL
+
+/* WOL Match count register
+ */
+#define WOL_MCOUNT_N		0x00000010
+#define WOL_MCOUNT_M		0x00000000 /* 0 << 8 */
+
+#define WOL_WAKECSR_ENABLE	0x00000001
+#define WOL_WAKECSR_MII		0x00000002
+#define WOL_WAKECSR_SEEN	0x00000004
+#define WOL_WAKECSR_FILT_UCAST	0x00000008
+#define WOL_WAKECSR_FILT_MCAST	0x00000010
+#define WOL_WAKECSR_FILT_BCAST	0x00000020
+#define WOL_WAKECSR_FILT_SEEN	0x00000040
+
+
 /* Receive DMA Registers */
 #define RXDMA_CFG	0x4000UL	/* RX Configuration Register	*/
 #define RXDMA_DBLOW	0x4004UL	/* RX Descriptor Base Low	*/
@@ -952,45 +973,38 @@ enum link_state {
 };
 
 struct gem {
-	spinlock_t lock;
-	spinlock_t tx_lock;
-	void __iomem *regs;
-	int rx_new, rx_old;
-	int tx_new, tx_old;
-
-	/* Set when chip is actually in operational state
-	 * (ie. not power managed)
-	 */
-	int hw_running;
-	int opened;
-	struct semaphore pm_sem;
-	struct work_struct pm_task;
-	struct timer_list pm_timer;
-
-	struct gem_init_block *init_block;
-
-	struct sk_buff *rx_skbs[RX_RING_SIZE];
-	struct sk_buff *tx_skbs[RX_RING_SIZE];
+	spinlock_t		lock;
+	spinlock_t		tx_lock;
+	void __iomem		*regs;
+	int			rx_new, rx_old;
+	int			tx_new, tx_old;
+
+	unsigned int has_wol : 1;	/* chip supports wake-on-lan */
+	unsigned int asleep : 1;	/* chip asleep, protected by pm_sem */
+	unsigned int asleep_wol : 1;	/* was asleep with WOL enabled */
+	unsigned int opened : 1;	/* driver opened, protected by pm_sem */
+	unsigned int running : 1;	/* chip running, protected by lock */
+	
+	/* cell enable count, protected by lock */
+	int			cell_enabled;  
+	
+	struct semaphore	pm_sem;
 
 	u32			msg_enable;
 	u32			status;
 
 	struct net_device_stats net_stats;
 
-	enum gem_phy_type	phy_type;
-	struct mii_phy		phy_mii;
-	
 	int			tx_fifo_sz;
 	int			rx_fifo_sz;
 	int			rx_pause_off;
 	int			rx_pause_on;
 	int			rx_buf_sz;
-	int			mii_phy_addr;
-
+	u64			pause_entered;
+	u16			pause_last_time_recvd;
 	u32			mac_rx_cfg;
 	u32			swrst_base;
 
-	/* Autoneg & PHY control */
 	int			want_autoneg;
 	int			last_forced_speed;
 	enum link_state		lstate;
@@ -999,14 +1013,18 @@ struct gem {
 	int			wake_on_lan;
 	struct work_struct	reset_task;
 	volatile int		reset_task_pending;
-	
-	/* Diagnostic counters and state. */
-	u64			pause_entered;
-	u16			pause_last_time_recvd;
 
-	dma_addr_t gblock_dvma;
-	struct pci_dev *pdev;
-	struct net_device *dev;
+	enum gem_phy_type	phy_type;
+	struct mii_phy		phy_mii;
+	int			mii_phy_addr;
+		
+	struct gem_init_block	*init_block;
+	struct sk_buff		*rx_skbs[RX_RING_SIZE];
+	struct sk_buff		*tx_skbs[RX_RING_SIZE];
+	dma_addr_t		gblock_dvma;
+
+	struct pci_dev		*pdev;
+	struct net_device	*dev;
 #ifdef CONFIG_PPC_PMAC
 	struct device_node	*of_node;
 #endif
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -98,25 +98,15 @@ static int bcm5201_init(struct mii_phy* 
 	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
 	phy_write(phy, MII_BCM5201_MULTIPHY, data);
 
+	phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+
 	return 0;
 }
 
-static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5201_suspend(struct mii_phy* phy)
 {
-	if (!wol_options)
-		phy_write(phy, MII_BCM5201_INTERRUPT, 0);
-
-	/* Here's a strange hack used by both MacOS 9 and X */
-	phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
-	
-	if (!wol_options) {
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-		u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
-		phy_write(phy, MII_BCM5201_AUXMODE2,
-			  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
-#endif			
-		phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-	}
+	phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+	phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
 	return 0;
 }
@@ -144,6 +134,21 @@ static int bcm5221_init(struct mii_phy* 
 	return 0;
 }
 
+static int bcm5221_suspend(struct mii_phy* phy)
+{
+	u16 data;
+
+	data = phy_read(phy, MII_BCM5221_TEST);
+	phy_write(phy, MII_BCM5221_TEST,
+		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+	data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+	phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+		  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
+
+	return 0;
+}
+
 static int bcm5400_init(struct mii_phy* phy)
 {
 	u16 data;
@@ -173,7 +178,7 @@ static int bcm5400_init(struct mii_phy* 
 	return 0;
 }
 
-static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5400_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
 	phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -229,7 +234,7 @@ static int bcm5401_init(struct mii_phy* 
 	return 0;
 }
 
-static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5401_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
 	phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -266,7 +271,7 @@ static int bcm5411_init(struct mii_phy* 
 	return 0;
 }
 
-static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
+static int bcm5411_suspend(struct mii_phy* phy)
 {
 	phy_write(phy, MII_BMCR, BMCR_PDOWN);
 
@@ -662,7 +667,7 @@ static struct mii_phy_def bcm5201_phy_de
 
 /* Broadcom BCM 5221 */
 static struct mii_phy_ops bcm5221_phy_ops = {
-	.suspend	= bcm5201_suspend,
+	.suspend	= bcm5221_suspend,
 	.init		= bcm5221_init,
 	.setup_aneg	= genmii_setup_aneg,
 	.setup_forced	= genmii_setup_forced,
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -7,7 +7,7 @@ struct mii_phy;
 struct mii_phy_ops
 {
 	int		(*init)(struct mii_phy *phy);
-	int		(*suspend)(struct mii_phy *phy, int wol_options);
+	int		(*suspend)(struct mii_phy *phy);
 	int		(*setup_aneg)(struct mii_phy *phy, u32 advertise);
 	int		(*setup_forced)(struct mii_phy *phy, int speed, int fd);
 	int		(*poll_link)(struct mii_phy *phy);
@@ -80,6 +80,7 @@ extern int mii_phy_probe(struct mii_phy 
 #define MII_BCM5221_SHDOW_AUX_STAT2		0x1b
 #define MII_BCM5221_SHDOW_AUX_STAT2_APD		0x0020
 #define MII_BCM5221_SHDOW_AUX_MODE4		0x1a
+#define MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE	0x0001
 #define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR	0x0004
 
 /* MII BCM5400 1000-BASET Control register */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -13,9 +13,6 @@
  *     argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
  */
 
-static char version[] =
-        "sunhme.c:v2.02 24/Aug/2003 David S. Miller (davem@redhat.com)\n";
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -67,15 +64,24 @@ static char version[] =
 
 #include "sunhme.h"
 
+#define DRV_NAME	"sunhme"
+#define DRV_VERSION	"2.02"
+#define DRV_RELDATE	"8/24/03"
+#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
 
-#define DRV_NAME "sunhme"
+static char version[] =
+	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION("Sun HappyMealEthernet(HME) 10/100baseT ethernet driver");
+MODULE_LICENSE("GPL");
 
 static int macaddr[6];
 
 /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
 module_param_array(macaddr, int, NULL, 0);
 MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
-MODULE_LICENSE("GPL");
 
 static struct happy_meal *root_happy_dev;
 
@@ -175,13 +181,13 @@ static __inline__ void tx_dump_ring(stru
 #define DEFAULT_IPG2       4 /* For all modes */
 #define DEFAULT_JAMSIZE    4 /* Toe jam */
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(MODULE)
 /* This happy_pci_ids is declared __initdata because it is only used
    as an advisory to depmod.  If this is ported to the new PCI interface
    where it could be referenced at any time due to hot plugging,
    the __initdata reference should be removed. */
 
-struct pci_device_id happymeal_pci_ids[] = {
+static struct pci_device_id happymeal_pci_ids[] = {
 	{
 	  .vendor	= PCI_VENDOR_ID_SUN,
 	  .device	= PCI_DEVICE_ID_SUN_HAPPYMEAL,
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -69,9 +69,6 @@
 
 #undef DEBUG_DRIVER
 
-static char version[] =
-	"sunlance.c:v2.02 24/Aug/03 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
-
 static char lancestr[] = "LANCE";
 
 #include <linux/config.h>
@@ -108,6 +105,19 @@ static char lancestr[] = "LANCE";
 #include <asm/auxio.h>		/* For tpe-link-test? setting */
 #include <asm/irq.h>
 
+#define DRV_NAME	"sunlance"
+#define DRV_VERSION	"2.02"
+#define DRV_RELDATE	"8/24/03"
+#define DRV_AUTHOR	"Miguel de Icaza (miguel@nuclecu.unam.mx)"
+
+static char version[] =
+	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION("Sun Lance ethernet driver");
+MODULE_LICENSE("GPL");
+
 /* Define: 2^4 Tx buffers and 2^4 Rx buffers */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
@@ -1611,4 +1621,3 @@ static void __exit sparc_lance_cleanup(v
 
 module_init(sparc_lance_probe);
 module_exit(sparc_lance_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -7,9 +7,6 @@
  * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
  */
 
-static char version[] =
-        "sunqe.c:v3.0 8/24/03 David S. Miller (davem@redhat.com)\n";
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -43,6 +40,19 @@ static char version[] =
 
 #include "sunqe.h"
 
+#define DRV_NAME	"sunqe"
+#define DRV_VERSION	"3.0"
+#define DRV_RELDATE	"8/24/03"
+#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
+
+static char version[] =
+	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION("Sun QuadEthernet 10baseT SBUS card driver");
+MODULE_LICENSE("GPL");
+
 static struct sunqec *root_qec_dev;
 
 static void qe_set_multicast(struct net_device *dev);
@@ -1040,4 +1050,3 @@ static void __exit qec_cleanup(void)
 
 module_init(qec_probe);
 module_exit(qec_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4,9 +4,15 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
+ * Copyright (C) 2005 Broadcom Corporation.
  *
  * Firmware is:
- * 	Copyright (C) 2000-2003 Broadcom Corporation.
+ *	Derived from proprietary unpublished source code,
+ *	Copyright (C) 2000-2003 Broadcom Corporation.
+ *
+ *	Permission is hereby granted for the distribution of this firmware
+ *	data in hexadecimal or equivalent format, provided this copyright
+ *	notice is accompanying it.
  */
 
 #include <linux/config.h>
@@ -60,8 +66,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.23"
-#define DRV_MODULE_RELDATE	"February 15, 2005"
+#define DRV_MODULE_VERSION	"3.31"
+#define DRV_MODULE_RELDATE	"June 8, 2005"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -84,8 +90,7 @@
 /* hardware minimum and maximum for a single frame's data payload */
 #define TG3_MIN_MTU			60
 #define TG3_MAX_MTU(tp)	\
-	((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && \
-	  GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) ? 9000 : 1500)
+	(!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 9000 : 1500)
 
 /* These numbers seem to be hard coded in the NIC firmware somehow.
  * You can't change the ring sizes, but you can change where you place
@@ -103,9 +108,7 @@
  * replace things like '% foo' with '& (foo - 1)'.
  */
 #define TG3_RX_RCB_RING_SIZE(tp)	\
-	((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || \
-	  GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ? \
-	 512 : 1024)
+	((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ?  512 : 1024)
 
 #define TG3_TX_RING_SIZE		512
 #define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
@@ -135,6 +138,8 @@
 /* number of ETHTOOL_GSTATS u64's */
 #define TG3_NUM_STATS		(sizeof(struct tg3_ethtool_stats)/sizeof(u64))
 
+#define TG3_NUM_TEST		6
+
 static char version[] __devinitdata =
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
@@ -206,6 +211,10 @@ static struct pci_device_id tg3_pci_tbl[
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
@@ -314,6 +323,17 @@ static struct {
 	{ "nic_tx_threshold_hit" }
 };
 
+static struct {
+	const char string[ETH_GSTRING_LEN];
+} ethtool_test_keys[TG3_NUM_TEST] = {
+	{ "nvram test     (online) " },
+	{ "link test      (online) " },
+	{ "register test  (offline)" },
+	{ "memory test    (offline)" },
+	{ "loopback test  (offline)" },
+	{ "interrupt test (offline)" },
+};
+
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
 	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
@@ -420,24 +440,54 @@ static void tg3_enable_ints(struct tg3 *
 {
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
-	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+		     (tp->last_tag << 24));
 	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 
 	tg3_cond_int(tp);
 }
 
+static inline unsigned int tg3_has_work(struct tg3 *tp)
+{
+	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned int work_exists = 0;
+
+	/* check for phy events */
+	if (!(tp->tg3_flags &
+	      (TG3_FLAG_USE_LINKCHG_REG |
+	       TG3_FLAG_POLL_SERDES))) {
+		if (sblk->status & SD_STATUS_LINK_CHG)
+			work_exists = 1;
+	}
+	/* check for RX/TX work to do */
+	if (sblk->idx[0].tx_consumer != tp->tx_cons ||
+	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+		work_exists = 1;
+
+	return work_exists;
+}
+
 /* tg3_restart_ints
- *  similar to tg3_enable_ints, but it can return without flushing the
- *  PIO write which reenables interrupts
+ *  similar to tg3_enable_ints, but it accurately determines whether there
+ *  is new work pending and can return without flushing the PIO write
+ *  which reenables interrupts 
  */
 static void tg3_restart_ints(struct tg3 *tp)
 {
 	tw32(TG3PCI_MISC_HOST_CTRL,
 		(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
-	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+		     tp->last_tag << 24);
 	mmiowb();
 
-	tg3_cond_int(tp);
+	/* When doing tagged status, this work check is unnecessary.
+	 * The last_tag we write above tells the chip which piece of
+	 * work we've completed.
+	 */
+	if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
+	    tg3_has_work(tp))
+		tw32(HOSTCC_MODE, tp->coalesce_mode |
+		     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
 }
 
 static inline void tg3_netif_stop(struct tg3 *tp)
@@ -468,8 +518,7 @@ static void tg3_switch_clocks(struct tg3
 		       0x1f);
 	tp->pci_clock_ctrl = clock_ctrl;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) {
 			tw32_f(TG3PCI_CLOCK_CTRL,
 			       clock_ctrl | CLOCK_CTRL_625_CORE);
@@ -862,8 +911,7 @@ out:
 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 		/* Cannot do read-modify-write on 5401 */
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-		   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	} else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		u32 phy_reg;
 
 		/* Set bit 14 with read-modify-write to preserve other bits */
@@ -871,6 +919,18 @@ out:
 		    !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg))
 			tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
 	}
+
+	/* Set phy register 0x10 bit 0 to high fifo elasticity to support
+	 * jumbo frames transmission.
+	 */
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+		u32 phy_reg;
+
+		if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg))
+		    tg3_writephy(tp, MII_TG3_EXT_CTRL,
+				 phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
+	}
+
 	tg3_phy_set_wirespeed(tp);
 	return 0;
 }
@@ -969,6 +1029,7 @@ static int tg3_setup_phy(struct tg3 *, i
 #define RESET_KIND_SUSPEND	2
 
 static void tg3_write_sig_post_reset(struct tg3 *, int);
+static int tg3_halt_cpu(struct tg3 *, u32);
 
 static int tg3_set_power_state(struct tg3 *tp, int state)
 {
@@ -994,8 +1055,13 @@ static int tg3_set_power_state(struct tg
 		pci_write_config_word(tp->pdev,
 				      pm + PCI_PM_CTRL,
 				      power_control);
-		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
-		udelay(100);
+		udelay(100);	/* Delay after power state change */
+
+		/* Switch out of Vaux if it is not a LOM */
+		if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) {
+			tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+			udelay(100);
+		}
 
 		return 0;
 
@@ -1056,7 +1122,7 @@ static int tg3_set_power_state(struct tg
 			mac_mode = MAC_MODE_PORT_MODE_TBI;
 		}
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)
+		if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
 			tw32(MAC_LED_CTRL, tp->led_ctrl);
 
 		if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
@@ -1083,7 +1149,7 @@ static int tg3_set_power_state(struct tg
 		     CLOCK_CTRL_ALTCLK |
 		     CLOCK_CTRL_PWRDOWN_PLL133);
 		udelay(40);
-	} else if (!((GET_ASIC_REV(tp->pci_chip_rev_id) == 5750) &&
+	} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
 		     (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) {
 		u32 newbits1, newbits2;
 
@@ -1093,8 +1159,7 @@ static int tg3_set_power_state(struct tg
 				    CLOCK_CTRL_TXCLK_DISABLE |
 				    CLOCK_CTRL_ALTCLK);
 			newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-			   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+		} else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 			newbits1 = CLOCK_CTRL_625_CORE;
 			newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
 		} else {
@@ -1108,8 +1173,7 @@ static int tg3_set_power_state(struct tg
 		tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2);
 		udelay(40);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+		if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 			u32 newbits3;
 
 			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -1129,8 +1193,20 @@ static int tg3_set_power_state(struct tg
 
 	tg3_frob_aux_power(tp);
 
+	/* Workaround for unstable PLL clock */
+	if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
+		u32 val = tr32(0x7d00);
+
+		val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
+		tw32(0x7d00, val);
+		if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+			tg3_halt_cpu(tp, RX_CPU_BASE);
+	}
+
 	/* Finally, set the new power state. */
 	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
+	udelay(100);	/* Delay after power state change */
 
 	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
 
@@ -2448,11 +2524,10 @@ static int tg3_setup_phy(struct tg3 *tp,
 		      (6 << TX_LENGTHS_IPG_SHIFT) |
 		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		if (netif_carrier_ok(tp->dev)) {
 			tw32(HOSTCC_STAT_COAL_TICKS,
-			     DEFAULT_STAT_COAL_TICKS);
+			     tp->coal.stats_block_coalesce_usecs);
 		} else {
 			tw32(HOSTCC_STAT_COAL_TICKS, 0);
 		}
@@ -2661,8 +2736,8 @@ static int tg3_vlan_rx(struct tg3 *tp, s
 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;
+	u32 sw_idx = tp->rx_rcb_ptr;
+	u16 hw_idx;
 	int received;
 
 	hw_idx = tp->hw_status->idx[0].rx_producer;
@@ -2671,7 +2746,6 @@ static int tg3_rx(struct tg3 *tp, int bu
 	 * the opaque cookie.
 	 */
 	rmb();
-	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp);
 	work_mask = 0;
 	received = 0;
 	while (sw_idx != hw_idx && budget > 0) {
@@ -2776,14 +2850,19 @@ static int tg3_rx(struct tg3 *tp, int bu
 next_pkt:
 		(*post_ptr)++;
 next_pkt_nopost:
-		rx_rcb_ptr++;
-		sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp);
+		sw_idx++;
+		sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
+
+		/* Refresh hw_idx to see if there is new work */
+		if (sw_idx == hw_idx) {
+			hw_idx = tp->hw_status->idx[0].rx_producer;
+			rmb();
+		}
 	}
 
 	/* ACK the status ring. */
-	tp->rx_rcb_ptr = rx_rcb_ptr;
-	tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
-		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp)));
+	tp->rx_rcb_ptr = sw_idx;
+	tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, sw_idx);
 
 	/* Refill RX ring(s). */
 	if (work_mask & RXD_OPAQUE_RING_STD) {
@@ -2834,7 +2913,6 @@ static int tg3_poll(struct net_device *n
 	 * All RX "locking" is done by ensuring outside
 	 * code synchronizes with dev->poll()
 	 */
-	done = 1;
 	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
 		int orig_budget = *budget;
 		int work_done;
@@ -2846,12 +2924,14 @@ static int tg3_poll(struct net_device *n
 
 		*budget -= work_done;
 		netdev->quota -= work_done;
-
-		if (work_done >= orig_budget)
-			done = 0;
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+		tp->last_tag = sblk->status_tag;
+	rmb();
+
 	/* if no more work, tell net stack and NIC we're done */
+	done = !tg3_has_work(tp);
 	if (done) {
 		spin_lock_irqsave(&tp->lock, flags);
 		__netif_rx_complete(netdev);
@@ -2862,24 +2942,40 @@ static int tg3_poll(struct net_device *n
 	return (done ? 0 : 1);
 }
 
-static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp)
+/* MSI ISR - No need to check for interrupt sharing and no need to
+ * flush status block and interrupt mailbox. PCI ordering rules
+ * guarantee that MSI will arrive after the status block.
+ */
+static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = netdev_priv(dev);
 	struct tg3_hw_status *sblk = tp->hw_status;
-	unsigned int work_exists = 0;
+	unsigned long flags;
 
-	/* check for phy events */
-	if (!(tp->tg3_flags &
-	      (TG3_FLAG_USE_LINKCHG_REG |
-	       TG3_FLAG_POLL_SERDES))) {
-		if (sblk->status & SD_STATUS_LINK_CHG)
-			work_exists = 1;
+	spin_lock_irqsave(&tp->lock, flags);
+
+	/*
+	 * Writing any value to intr-mbox-0 clears PCI INTA# and
+	 * chip-internal interrupt pending events.
+	 * Writing non-zero to intr-mbox-0 additional tells the
+	 * NIC to stop sending us irqs, engaging "in-intr-handler"
+	 * event coalescing.
+	 */
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	tp->last_tag = sblk->status_tag;
+	sblk->status &= ~SD_STATUS_UPDATED;
+	if (likely(tg3_has_work(tp)))
+		netif_rx_schedule(dev);		/* schedule NAPI poll */
+	else {
+		/* No work, re-enable interrupts.  */
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     tp->last_tag << 24);
 	}
-	/* check for RX/TX work to do */
-	if (sblk->idx[0].tx_consumer != tp->tx_cons ||
-	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
-		work_exists = 1;
 
-	return work_exists;
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return IRQ_RETVAL(1);
 }
 
 static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2892,31 +2988,78 @@ static irqreturn_t tg3_interrupt(int irq
 
 	spin_lock_irqsave(&tp->lock, flags);
 
-	if (sblk->status & SD_STATUS_UPDATED) {
+	/* In INTx mode, it is possible for the interrupt to arrive at
+	 * the CPU before the status block posted prior to the interrupt.
+	 * Reading the PCI State register will confirm whether the
+	 * interrupt is ours and will flush the status block.
+	 */
+	if ((sblk->status & SD_STATUS_UPDATED) ||
+	    !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
 		/*
-		 * writing any value to intr-mbox-0 clears PCI INTA# and
+		 * Writing any value to intr-mbox-0 clears PCI INTA# and
 		 * chip-internal interrupt pending events.
-		 * writing non-zero to intr-mbox-0 additional tells the
+		 * Writing non-zero to intr-mbox-0 additional tells the
 		 * NIC to stop sending us irqs, engaging "in-intr-handler"
 		 * event coalescing.
 		 */
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 			     0x00000001);
+		sblk->status &= ~SD_STATUS_UPDATED;
+		if (likely(tg3_has_work(tp)))
+			netif_rx_schedule(dev);		/* schedule NAPI poll */
+		else {
+			/* No work, shared interrupt perhaps?  re-enable
+			 * interrupts, and flush that PCI write
+			 */
+			tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     	0x00000000);
+			tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		}
+	} else {	/* shared interrupt */
+		handled = 0;
+	}
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = netdev_priv(dev);
+	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
+	unsigned int handled = 1;
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	/* In INTx mode, it is possible for the interrupt to arrive at
+	 * the CPU before the status block posted prior to the interrupt.
+	 * Reading the PCI State register will confirm whether the
+	 * interrupt is ours and will flush the status block.
+	 */
+	if ((sblk->status & SD_STATUS_UPDATED) ||
+	    !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
 		/*
-		 * Flush PCI write.  This also guarantees that our
-		 * status block has been flushed to host memory.
+		 * writing any value to intr-mbox-0 clears PCI INTA# and
+		 * chip-internal interrupt pending events.
+		 * writing non-zero to intr-mbox-0 additional tells the
+		 * NIC to stop sending us irqs, engaging "in-intr-handler"
+		 * event coalescing.
 		 */
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000001);
+		tp->last_tag = sblk->status_tag;
 		sblk->status &= ~SD_STATUS_UPDATED;
-
-		if (likely(tg3_has_work(dev, tp)))
+		if (likely(tg3_has_work(tp)))
 			netif_rx_schedule(dev);		/* schedule NAPI poll */
 		else {
 			/* no work, shared interrupt perhaps?  re-enable
 			 * interrupts, and flush that PCI write
 			 */
 			tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     	0x00000000);
+				     tp->last_tag << 24);
 			tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 		}
 	} else {	/* shared interrupt */
@@ -2928,13 +3071,31 @@ static irqreturn_t tg3_interrupt(int irq
 	return IRQ_RETVAL(handled);
 }
 
+/* ISR for interrupt test */
+static irqreturn_t tg3_test_isr(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = netdev_priv(dev);
+	struct tg3_hw_status *sblk = tp->hw_status;
+
+	if (sblk->status & SD_STATUS_UPDATED) {
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000001);
+		return IRQ_RETVAL(1);
+	}
+	return IRQ_RETVAL(0);
+}
+
 static int tg3_init_hw(struct tg3 *);
-static int tg3_halt(struct tg3 *);
+static int tg3_halt(struct tg3 *, int, int);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void tg3_poll_controller(struct net_device *dev)
 {
-	tg3_interrupt(dev->irq, dev, NULL);
+	struct tg3 *tp = netdev_priv(dev);
+
+	tg3_interrupt(tp->pdev->irq, dev, NULL);
 }
 #endif
 
@@ -2951,7 +3112,7 @@ static void tg3_reset_task(void *_data)
 	restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
 	tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
 
-	tg3_halt(tp);
+	tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
 	tg3_init_hw(tp);
 
 	tg3_netif_start(tp);
@@ -3017,6 +3178,7 @@ static int tigon3_4gb_hwbug_workaround(s
 			tp->tx_buffers[entry].skb = NULL;
 		}
 		entry = NEXT_TX(entry);
+		i++;
 	}
 
 	dev_kfree_skb(skb);
@@ -3110,6 +3272,12 @@ static int tg3_start_xmit(struct sk_buff
 	    (mss = skb_shinfo(skb)->tso_size) != 0) {
 		int tcp_opt_len, ip_tcp_len;
 
+		if (skb_header_cloned(skb) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			goto out_unlock;
+		}
+
 		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
 		ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
 
@@ -3290,7 +3458,7 @@ static int tg3_change_mtu(struct net_dev
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
-	tg3_halt(tp);
+	tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 
 	tg3_set_mtu(dev, tp, new_mtu);
 
@@ -3557,13 +3725,12 @@ err_out:
 /* To stop a block, clear the enable bit and poll till it
  * clears.  tp->lock is held.
  */
-static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit)
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int silent)
 {
 	unsigned int i;
 	u32 val;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		switch (ofs) {
 		case RCVLSC_MODE:
 		case DMAC_MODE:
@@ -3591,7 +3758,7 @@ static int tg3_stop_block(struct tg3 *tp
 			break;
 	}
 
-	if (i == MAX_WAIT_CNT) {
+	if (i == MAX_WAIT_CNT && !silent) {
 		printk(KERN_ERR PFX "tg3_stop_block timed out, "
 		       "ofs=%lx enable_bit=%x\n",
 		       ofs, enable_bit);
@@ -3602,7 +3769,7 @@ static int tg3_stop_block(struct tg3 *tp
 }
 
 /* tp->lock is held. */
-static int tg3_abort_hw(struct tg3 *tp)
+static int tg3_abort_hw(struct tg3 *tp, int silent)
 {
 	int i, err;
 
@@ -3612,22 +3779,20 @@ static int tg3_abort_hw(struct tg3 *tp)
 	tw32_f(MAC_RX_MODE, tp->rx_mode);
 	udelay(10);
 
-	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE);
-
-	err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, DMAC_MODE, DMAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE);
-	if (err)
-		goto out;
+	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE, silent);
+
+	err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, DMAC_MODE, DMAC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE, silent);
 
 	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
 	tw32_f(MAC_MODE, tp->mac_mode);
@@ -3645,27 +3810,24 @@ static int tg3_abort_hw(struct tg3 *tp)
 		printk(KERN_ERR PFX "tg3_abort_hw timed out for %s, "
 		       "TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n",
 		       tp->dev->name, tr32(MAC_TX_MODE));
-		return -ENODEV;
+		err |= -ENODEV;
 	}
 
-	err  = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
+	err |= tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE, silent);
 
 	tw32(FTQ_RESET, 0xffffffff);
 	tw32(FTQ_RESET, 0x00000000);
 
-	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
-	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
-	if (err)
-		goto out;
+	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent);
+	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent);
 
 	if (tp->hw_status)
 		memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 	if (tp->hw_stats)
 		memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
 
-out:
 	return err;
 }
 
@@ -3695,10 +3857,33 @@ static void tg3_nvram_unlock(struct tg3 
 }
 
 /* tp->lock is held. */
+static void tg3_enable_nvram_access(struct tg3 *tp)
+{
+	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+	    !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
+		u32 nvaccess = tr32(NVRAM_ACCESS);
+
+		tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+	}
+}
+
+/* tp->lock is held. */
+static void tg3_disable_nvram_access(struct tg3 *tp)
+{
+	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+	    !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
+		u32 nvaccess = tr32(NVRAM_ACCESS);
+
+		tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+	}
+}
+
+/* tp->lock is held. */
 static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 {
-	tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
-		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
+		tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
+			      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
 
 	if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
 		switch (kind) {
@@ -3804,8 +3989,7 @@ static int tg3_chip_reset(struct tg3 *tp
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
 		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
 	tw32(GRC_MISC_CFG, val);
 
@@ -3902,19 +4086,20 @@ static int tg3_chip_reset(struct tg3 *tp
 		tw32_f(MAC_MODE, 0);
 	udelay(40);
 
-	/* Wait for firmware initialization to complete. */
-	for (i = 0; i < 100000; i++) {
-		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
-		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
-			break;
-		udelay(10);
-	}
-	if (i >= 100000 &&
-	    !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
-		printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
-		       "firmware will not restart magic=%08x\n",
-		       tp->dev->name, val);
-		return -ENODEV;
+	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
+		/* Wait for firmware initialization to complete. */
+		for (i = 0; i < 100000; i++) {
+			tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+			if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+				break;
+			udelay(10);
+		}
+		if (i >= 100000) {
+			printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
+			       "firmware will not restart magic=%08x\n",
+			       tp->dev->name, val);
+			return -ENODEV;
+		}
 	}
 
 	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
@@ -3934,7 +4119,7 @@ static int tg3_chip_reset(struct tg3 *tp
 		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
 		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
 			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+			if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 				tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
 		}
 	}
@@ -3964,19 +4149,19 @@ static void tg3_stop_fw(struct tg3 *tp)
 }
 
 /* tp->lock is held. */
-static int tg3_halt(struct tg3 *tp)
+static int tg3_halt(struct tg3 *tp, int kind, int silent)
 {
 	int err;
 
 	tg3_stop_fw(tp);
 
-	tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN);
+	tg3_write_sig_pre_reset(tp, kind);
 
-	tg3_abort_hw(tp);
+	tg3_abort_hw(tp, silent);
 	err = tg3_chip_reset(tp);
 
-	tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN);
-	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+	tg3_write_sig_legacy(tp, kind);
+	tg3_write_sig_post_reset(tp, kind);
 
 	if (err)
 		return err;
@@ -4119,7 +4304,7 @@ static int tg3_halt_cpu(struct tg3 *tp, 
 	int i;
 
 	if (offset == TX_CPU_BASE &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+	    (tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		BUG();
 
 	if (offset == RX_CPU_BASE) {
@@ -4173,14 +4358,14 @@ static int tg3_load_firmware_cpu(struct 
 	void (*write_op)(struct tg3 *, u32, u32);
 
 	if (cpu_base == TX_CPU_BASE &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+	    (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		printk(KERN_ERR PFX "tg3_load_firmware_cpu: Trying to load "
 		       "TX cpu firmware on %s which is 5705.\n",
 		       tp->dev->name);
 		return -EINVAL;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
 		write_op = tg3_write_mem;
 	else
 		write_op = tg3_write_indirect_reg32;
@@ -4190,7 +4375,12 @@ static int tg3_load_firmware_cpu(struct 
 	 */
 	tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
 
+	/* It is possible that bootcode is still loading at this point.
+	 * Get the nvram lock first before halting the cpu.
+	 */
+	tg3_nvram_lock(tp);
 	err = tg3_halt_cpu(tp, cpu_base);
+	tg3_nvram_unlock(tp);
 	if (err)
 		goto out;
 
@@ -4920,14 +5110,34 @@ static void tg3_set_bdinfo(struct tg3 *t
 		      (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
 		       maxlen_flags);
 
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750))
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		tg3_write_mem(tp,
 			      (bdinfo_addr + TG3_BDINFO_NIC_ADDR),
 			      nic_addr);
 }
 
 static void __tg3_set_rx_mode(struct net_device *);
+static void tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
+{
+	tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs);
+	tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs);
+	tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames);
+	tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames);
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+		tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq);
+		tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq);
+	}
+	tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq);
+	tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq);
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+		u32 val = ec->stats_block_coalesce_usecs;
+
+		if (!netif_carrier_ok(tp->dev))
+			val = 0;
+
+		tw32(HOSTCC_STAT_COAL_TICKS, val);
+	}
+}
 
 /* tp->lock is held. */
 static int tg3_reset_hw(struct tg3 *tp)
@@ -4942,9 +5152,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tg3_write_sig_pre_reset(tp, RESET_KIND_INIT);
 
 	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
-		err = tg3_abort_hw(tp);
-		if (err)
-			return err;
+		tg3_abort_hw(tp, 1);
 	}
 
 	err = tg3_chip_reset(tp);
@@ -5009,7 +5217,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32(GRC_MISC_CFG, val);
 
 	/* Initialize MBUF/DESC pool. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
 		/* Do nothing.  */
 	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
 		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
@@ -5099,8 +5307,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	/* Don't even try to program the JUMBO/MINI buffer descriptor
 	 * configs on 5705.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
 		     RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT);
 	} else {
@@ -5132,8 +5339,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	/* There is only one send ring on 5705/5750, no need to explicitly
 	 * disable the others.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		/* Clear out send RCB ring in SRAM. */
 		for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
 			tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
@@ -5154,8 +5360,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	/* There is only one receive return ring on 5705/5750, no need
 	 * to explicitly disable the others.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK;
 		     i += TG3_BDINFO_SIZE) {
 			tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
@@ -5209,6 +5414,8 @@ static int tg3_reset_hw(struct tg3 *tp)
 		      RDMAC_MODE_LNGREAD_ENAB);
 	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
 		rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
+
+	/* If statement applies to 5705 and 5750 PCI devices only */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
 	     tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) {
@@ -5222,6 +5429,9 @@ static int tg3_reset_hw(struct tg3 *tp)
 		}
 	}
 
+	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+		rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+
 #if TG3_TSO_SUPPORT != 0
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
 		rdmac_mode |= (1 << 27);
@@ -5250,17 +5460,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 		udelay(10);
 	}
 
-	tw32(HOSTCC_RXCOL_TICKS, 0);
-	tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS);
-	tw32(HOSTCC_RXMAX_FRAMES, 1);
-	tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
-		tw32(HOSTCC_RXCOAL_TICK_INT, 0);
-		tw32(HOSTCC_TXCOAL_TICK_INT, 0);
-	}
-	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
-	tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
+	tg3_set_coalesce(tp, &tp->coal);
 
 	/* set status block DMA address */
 	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -5268,14 +5468,11 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
 	     ((u64) tp->status_mapping & 0xffffffff));
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		/* Status/statistics block address.  See tg3_timer,
 		 * the tg3_periodic_fetch_stats call there, and
 		 * tg3_get_stats to see how this works for 5705/5750 chips.
 		 */
-		tw32(HOSTCC_STAT_COAL_TICKS,
-		     DEFAULT_STAT_COAL_TICKS);
 		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
 		     ((u64) tp->stats_mapping >> 32));
 		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
@@ -5288,8 +5485,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 
 	tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE);
 	tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
 
 	/* Clear statistics/status block in chip, and status block in ram. */
@@ -5306,18 +5502,36 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
 	udelay(40);
 
-	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 is partially set up during tg3_get_invariants().
+	 * If TG3_FLAG_EEPROM_WRITE_PROT is set, we should read the
+	 * register to preserve the GPIO settings for LOMs. The GPIOs,
+	 * whether used as inputs or outputs, are set by boot code after
+	 * reset.
+	 */
+	if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+		u32 gpio_mask;
+
+		gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE2 |
+			    GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT2;
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+			gpio_mask |= GRC_LCLCTRL_GPIO_OE3 |
+				     GRC_LCLCTRL_GPIO_OUTPUT3;
+
+		tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask;
+
+		/* GPIO1 must be driven high for eeprom write protect */
 		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
 				       GRC_LCLCTRL_GPIO_OUTPUT1);
+	}
 	tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
 	udelay(100);
 
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
-	tr32(MAILBOX_INTERRUPT_0);
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+	tp->last_tag = 0;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) {
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
 		tw32_f(DMAC_MODE, DMAC_MODE_ENABLE);
 		udelay(40);
 	}
@@ -5328,6 +5542,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	       WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
 	       WDMAC_MODE_LNGREAD_ENAB);
 
+	/* If statement applies to 5705 and 5750 PCI devices only */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
 	     tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
@@ -5364,8 +5579,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	udelay(40);
 
 	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
 	tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
 	tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
@@ -5469,8 +5683,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
 	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
 		limit = 8;
 	else
 		limit = 16;
@@ -5594,32 +5807,33 @@ static void tg3_timer(unsigned long __op
 	spin_lock_irqsave(&tp->lock, flags);
 	spin_lock(&tp->tx_lock);
 
-	/* 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 (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
+		/* 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)) {
-		tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
-		spin_unlock(&tp->tx_lock);
-		spin_unlock_irqrestore(&tp->lock, flags);
-		schedule_work(&tp->reset_task);
-		return;
+		if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+			tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
+			spin_unlock(&tp->tx_lock);
+			spin_unlock_irqrestore(&tp->lock, flags);
+			schedule_work(&tp->reset_task);
+			return;
+		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
-		tg3_periodic_fetch_stats(tp);
-
 	/* This part only runs once per second. */
 	if (!--tp->timer_counter) {
+		if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+			tg3_periodic_fetch_stats(tp);
+
 		if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
 			u32 mac_stat;
 			int phy_event;
@@ -5684,69 +5898,255 @@ static void tg3_timer(unsigned long __op
 	add_timer(&tp->timer);
 }
 
-static int tg3_open(struct net_device *dev)
+static int tg3_test_interrupt(struct tg3 *tp)
 {
-	struct tg3 *tp = netdev_priv(dev);
-	int err;
+	struct net_device *dev = tp->dev;
+	int err, i;
+	u32 int_mbox = 0;
 
-	spin_lock_irq(&tp->lock);
-	spin_lock(&tp->tx_lock);
+	if (!netif_running(dev))
+		return -ENODEV;
 
 	tg3_disable_ints(tp);
-	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
-	spin_unlock(&tp->tx_lock);
-	spin_unlock_irq(&tp->lock);
+	free_irq(tp->pdev->irq, dev);
 
-	/* The placement of this call is tied
-	 * to the setup and use of Host TX descriptors.
-	 */
-	err = tg3_alloc_consistent(tp);
+	err = request_irq(tp->pdev->irq, tg3_test_isr,
+			  SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
 	if (err)
 		return err;
 
-	err = request_irq(dev->irq, tg3_interrupt,
-			  SA_SHIRQ, dev->name, dev);
-
-	if (err) {
-		tg3_free_consistent(tp);
-		return err;
-	}
+	tg3_enable_ints(tp);
 
-	spin_lock_irq(&tp->lock);
-	spin_lock(&tp->tx_lock);
+	tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+	       HOSTCC_MODE_NOW);
 
-	err = tg3_init_hw(tp);
-	if (err) {
-		tg3_halt(tp);
-		tg3_free_rings(tp);
-	} else {
-		tp->timer_offset = HZ / 10;
-		tp->timer_counter = tp->timer_multiplier = 10;
-		tp->asf_counter = tp->asf_multiplier = (10 * 120);
+	for (i = 0; i < 5; i++) {
+		int_mbox = tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		if (int_mbox != 0)
+			break;
+		msleep(10);
+	}
 
-		init_timer(&tp->timer);
-		tp->timer.expires = jiffies + tp->timer_offset;
-		tp->timer.data = (unsigned long) tp;
-		tp->timer.function = tg3_timer;
-		add_timer(&tp->timer);
+	tg3_disable_ints(tp);
 
-		tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+	free_irq(tp->pdev->irq, dev);
+	
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
+		err = request_irq(tp->pdev->irq, tg3_msi,
+				  SA_SAMPLE_RANDOM, dev->name, dev);
+	else {
+		irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+			fn = tg3_interrupt_tagged;
+		err = request_irq(tp->pdev->irq, fn,
+				  SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
 	}
 
-	spin_unlock(&tp->tx_lock);
-	spin_unlock_irq(&tp->lock);
-
-	if (err) {
-		free_irq(dev->irq, dev);
-		tg3_free_consistent(tp);
+	if (err)
 		return err;
-	}
 
-	spin_lock_irq(&tp->lock);
-	spin_lock(&tp->tx_lock);
+	if (int_mbox != 0)
+		return 0;
 
-	tg3_enable_ints(tp);
+	return -EIO;
+}
+
+/* Returns 0 if MSI test succeeds or MSI test fails and INTx mode is
+ * successfully restored
+ */
+static int tg3_test_msi(struct tg3 *tp)
+{
+	struct net_device *dev = tp->dev;
+	int err;
+	u16 pci_cmd;
+
+	if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI))
+		return 0;
+
+	/* Turn off SERR reporting in case MSI terminates with Master
+	 * Abort.
+	 */
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+	pci_write_config_word(tp->pdev, PCI_COMMAND,
+			      pci_cmd & ~PCI_COMMAND_SERR);
+
+	err = tg3_test_interrupt(tp);
+
+	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+
+	if (!err)
+		return 0;
+
+	/* other failures */
+	if (err != -EIO)
+		return err;
+
+	/* MSI test failed, go back to INTx mode */
+	printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
+	       "switching to INTx mode. Please report this failure to "
+	       "the PCI maintainer and include system chipset information.\n",
+		       tp->dev->name);
+
+	free_irq(tp->pdev->irq, dev);
+	pci_disable_msi(tp->pdev);
+
+	tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+
+	{
+		irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+			fn = tg3_interrupt_tagged;
+
+		err = request_irq(tp->pdev->irq, fn,
+				  SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+	}
+	if (err)
+		return err;
+
+	/* Need to reset the chip because the MSI cycle may have terminated
+	 * with Master Abort.
+	 */
+	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+
+	tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+	err = tg3_init_hw(tp);
+
+	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->lock);
+
+	if (err)
+		free_irq(tp->pdev->irq, dev);
+
+	return err;
+}
+
+static int tg3_open(struct net_device *dev)
+{
+	struct tg3 *tp = netdev_priv(dev);
+	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);
+
+	/* The placement of this call is tied
+	 * to the setup and use of Host TX descriptors.
+	 */
+	err = tg3_alloc_consistent(tp);
+	if (err)
+		return err;
+
+	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) {
+		/* All MSI supporting chips should support tagged
+		 * status.  Assert that this is the case.
+		 */
+		if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
+			printk(KERN_WARNING PFX "%s: MSI without TAGGED? "
+			       "Not using MSI.\n", tp->dev->name);
+		} else if (pci_enable_msi(tp->pdev) == 0) {
+			u32 msi_mode;
+
+			msi_mode = tr32(MSGINT_MODE);
+			tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
+			tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
+		}
+	}
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
+		err = request_irq(tp->pdev->irq, tg3_msi,
+				  SA_SAMPLE_RANDOM, dev->name, dev);
+	else {
+		irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+			fn = tg3_interrupt_tagged;
+
+		err = request_irq(tp->pdev->irq, fn,
+				  SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+	}
+
+	if (err) {
+		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+			pci_disable_msi(tp->pdev);
+			tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+		}
+		tg3_free_consistent(tp);
+		return err;
+	}
+
+	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+
+	err = tg3_init_hw(tp);
+	if (err) {
+		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+		tg3_free_rings(tp);
+	} else {
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+			tp->timer_offset = HZ;
+		else
+			tp->timer_offset = HZ / 10;
+
+		BUG_ON(tp->timer_offset > HZ);
+		tp->timer_counter = tp->timer_multiplier =
+			(HZ / tp->timer_offset);
+		tp->asf_counter = tp->asf_multiplier =
+			((HZ / tp->timer_offset) * 120);
+
+		init_timer(&tp->timer);
+		tp->timer.expires = jiffies + tp->timer_offset;
+		tp->timer.data = (unsigned long) tp;
+		tp->timer.function = tg3_timer;
+	}
+
+	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->lock);
+
+	if (err) {
+		free_irq(tp->pdev->irq, dev);
+		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+			pci_disable_msi(tp->pdev);
+			tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+		}
+		tg3_free_consistent(tp);
+		return err;
+	}
+
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+		err = tg3_test_msi(tp);
+
+		if (err) {
+			spin_lock_irq(&tp->lock);
+			spin_lock(&tp->tx_lock);
+
+			if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+				pci_disable_msi(tp->pdev);
+				tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+			}
+			tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+			tg3_free_rings(tp);
+			tg3_free_consistent(tp);
+
+			spin_unlock(&tp->tx_lock);
+			spin_unlock_irq(&tp->lock);
+
+			return err;
+		}
+	}
+
+	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+
+	add_timer(&tp->timer);
+	tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+	tg3_enable_ints(tp);
 
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
@@ -6003,7 +6403,7 @@ static int tg3_close(struct net_device *
 
 	tg3_disable_ints(tp);
 
-	tg3_halt(tp);
+	tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 	tg3_free_rings(tp);
 	tp->tg3_flags &=
 		~(TG3_FLAG_INIT_COMPLETE |
@@ -6013,7 +6413,11 @@ static int tg3_close(struct net_device *
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
-	free_irq(dev->irq, dev);
+	free_irq(tp->pdev->irq, dev);
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+		pci_disable_msi(tp->pdev);
+		tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+	}
 
 	memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
 	       sizeof(tp->net_stats_prev));
@@ -6487,10 +6891,12 @@ static int tg3_set_eeprom(struct net_dev
 		start = cpu_to_le32(start);
 		len += b_offset;
 		offset &= ~3;
+		if (len < 4)
+			len = 4;
 	}
 
 	odd_len = 0;
-	if ((len & 3) && ((len > 4) || (b_offset == 0))) {
+	if (len & 3) {
 		/* adjustments to end on required 4 byte boundary */
 		odd_len = 1;
 		len = (len + 3) & ~3;
@@ -6524,10 +6930,6 @@ static int tg3_get_settings(struct net_d
 {
   	struct tg3 *tp = netdev_priv(dev);
   
-	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-					tp->link_config.phy_is_low_power)
-		return -EAGAIN;
-
 	cmd->supported = (SUPPORTED_Autoneg);
 
 	if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
@@ -6544,8 +6946,10 @@ static int tg3_get_settings(struct net_d
 		cmd->supported |= SUPPORTED_FIBRE;
   
 	cmd->advertising = tp->link_config.advertising;
-	cmd->speed = tp->link_config.active_speed;
-	cmd->duplex = tp->link_config.active_duplex;
+	if (netif_running(dev)) {
+		cmd->speed = tp->link_config.active_speed;
+		cmd->duplex = tp->link_config.active_duplex;
+	}
 	cmd->port = 0;
 	cmd->phy_address = PHY_ADDR;
 	cmd->transceiver = 0;
@@ -6559,10 +6963,6 @@ static int tg3_set_settings(struct net_d
 {
 	struct tg3 *tp = netdev_priv(dev);
   
-	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-	    tp->link_config.phy_is_low_power)
-		return -EAGAIN;
-
 	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
 		/* These are the only valid advertisement bits allowed.  */
 		if (cmd->autoneg == AUTONEG_ENABLE &&
@@ -6587,7 +6987,9 @@ static int tg3_set_settings(struct net_d
 		tp->link_config.duplex = cmd->duplex;
   	}
   
-	tg3_setup_phy(tp, 1);
+	if (netif_running(dev))
+		tg3_setup_phy(tp, 1);
+
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
   
@@ -6667,6 +7069,9 @@ static int tg3_nway_reset(struct net_dev
 	u32 bmcr;
 	int r;
   
+	if (!netif_running(dev))
+		return -EAGAIN;
+
 	spin_lock_irq(&tp->lock);
 	r = -EINVAL;
 	tg3_readphy(tp, MII_BMCR, &bmcr);
@@ -6703,7 +7108,9 @@ static int tg3_set_ringparam(struct net_
 	    (ering->tx_pending > TG3_TX_RING_SIZE - 1))
 		return -EINVAL;
   
-	tg3_netif_stop(tp);
+	if (netif_running(dev))
+		tg3_netif_stop(tp);
+
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
   
@@ -6715,9 +7122,12 @@ static int tg3_set_ringparam(struct net_
 	tp->rx_jumbo_pending = ering->rx_jumbo_pending;
 	tp->tx_pending = ering->tx_pending;
 
-	tg3_halt(tp);
-	tg3_init_hw(tp);
-	tg3_netif_start(tp);
+	if (netif_running(dev)) {
+		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+		tg3_init_hw(tp);
+		tg3_netif_start(tp);
+	}
+
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
   
@@ -6737,7 +7147,9 @@ static int tg3_set_pauseparam(struct net
 {
 	struct tg3 *tp = netdev_priv(dev);
   
-	tg3_netif_stop(tp);
+	if (netif_running(dev))
+		tg3_netif_stop(tp);
+
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 	if (epause->autoneg)
@@ -6752,9 +7164,12 @@ static int tg3_set_pauseparam(struct net
 		tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
 	else
 		tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
-	tg3_halt(tp);
-	tg3_init_hw(tp);
-	tg3_netif_start(tp);
+
+	if (netif_running(dev)) {
+		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+		tg3_init_hw(tp);
+		tg3_netif_start(tp);
+	}
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
   
@@ -6802,31 +7217,549 @@ static int tg3_set_tx_csum(struct net_de
 	else
 		dev->features &= ~NETIF_F_IP_CSUM;
 
-	return 0;
-}
+	return 0;
+}
+
+static int tg3_get_stats_count (struct net_device *dev)
+{
+	return TG3_NUM_STATS;
+}
+
+static int tg3_get_test_count (struct net_device *dev)
+{
+	return TG3_NUM_TEST;
+}
+
+static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+		break;
+	case ETH_SS_TEST:
+		memcpy(buf, &ethtool_test_keys, sizeof(ethtool_test_keys));
+		break;
+	default:
+		WARN_ON(1);	/* we need a WARN() */
+		break;
+	}
+}
+
+static void tg3_get_ethtool_stats (struct net_device *dev,
+				   struct ethtool_stats *estats, u64 *tmp_stats)
+{
+	struct tg3 *tp = netdev_priv(dev);
+	memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
+}
+
+#define NVRAM_TEST_SIZE 0x100
+
+static int tg3_test_nvram(struct tg3 *tp)
+{
+	u32 *buf, csum;
+	int i, j, err = 0;
+
+	buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) {
+		u32 val;
+
+		if ((err = tg3_nvram_read(tp, i, &val)) != 0)
+			break;
+		buf[j] = cpu_to_le32(val);
+	}
+	if (i < NVRAM_TEST_SIZE)
+		goto out;
+
+	err = -EIO;
+	if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC)
+		goto out;
+
+	/* Bootstrap checksum at offset 0x10 */
+	csum = calc_crc((unsigned char *) buf, 0x10);
+	if(csum != cpu_to_le32(buf[0x10/4]))
+		goto out;
+
+	/* Manufacturing block starts at offset 0x74, checksum at 0xfc */
+	csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
+	if (csum != cpu_to_le32(buf[0xfc/4]))
+		 goto out;
+
+	err = 0;
+
+out:
+	kfree(buf);
+	return err;
+}
+
+#define TG3_SERDES_TIMEOUT_SEC	2
+#define TG3_COPPER_TIMEOUT_SEC	6
+
+static int tg3_test_link(struct tg3 *tp)
+{
+	int i, max;
+
+	if (!netif_running(tp->dev))
+		return -ENODEV;
+
+	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+		max = TG3_SERDES_TIMEOUT_SEC;
+	else
+		max = TG3_COPPER_TIMEOUT_SEC;
+
+	for (i = 0; i < max; i++) {
+		if (netif_carrier_ok(tp->dev))
+			return 0;
+
+		if (msleep_interruptible(1000))
+			break;
+	}
+
+	return -EIO;
+}
+
+/* Only test the commonly used registers */
+static int tg3_test_registers(struct tg3 *tp)
+{
+	int i, is_5705;
+	u32 offset, read_mask, write_mask, val, save_val, read_val;
+	static struct {
+		u16 offset;
+		u16 flags;
+#define TG3_FL_5705	0x1
+#define TG3_FL_NOT_5705	0x2
+#define TG3_FL_NOT_5788	0x4
+		u32 read_mask;
+		u32 write_mask;
+	} reg_tbl[] = {
+		/* MAC Control Registers */
+		{ MAC_MODE, TG3_FL_NOT_5705,
+			0x00000000, 0x00ef6f8c },
+		{ MAC_MODE, TG3_FL_5705,
+			0x00000000, 0x01ef6b8c },
+		{ MAC_STATUS, TG3_FL_NOT_5705,
+			0x03800107, 0x00000000 },
+		{ MAC_STATUS, TG3_FL_5705,
+			0x03800100, 0x00000000 },
+		{ MAC_ADDR_0_HIGH, 0x0000,
+			0x00000000, 0x0000ffff },
+		{ MAC_ADDR_0_LOW, 0x0000,
+		       	0x00000000, 0xffffffff },
+		{ MAC_RX_MTU_SIZE, 0x0000,
+			0x00000000, 0x0000ffff },
+		{ MAC_TX_MODE, 0x0000,
+			0x00000000, 0x00000070 },
+		{ MAC_TX_LENGTHS, 0x0000,
+			0x00000000, 0x00003fff },
+		{ MAC_RX_MODE, TG3_FL_NOT_5705,
+			0x00000000, 0x000007fc },
+		{ MAC_RX_MODE, TG3_FL_5705,
+			0x00000000, 0x000007dc },
+		{ MAC_HASH_REG_0, 0x0000,
+			0x00000000, 0xffffffff },
+		{ MAC_HASH_REG_1, 0x0000,
+			0x00000000, 0xffffffff },
+		{ MAC_HASH_REG_2, 0x0000,
+			0x00000000, 0xffffffff },
+		{ MAC_HASH_REG_3, 0x0000,
+			0x00000000, 0xffffffff },
+
+		/* Receive Data and Receive BD Initiator Control Registers. */
+		{ RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705,
+			0x00000000, 0x00000003 },
+		{ RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ RCVDBDI_STD_BD+0, 0x0000,
+			0x00000000, 0xffffffff },
+		{ RCVDBDI_STD_BD+4, 0x0000,
+			0x00000000, 0xffffffff },
+		{ RCVDBDI_STD_BD+8, 0x0000,
+			0x00000000, 0xffff0002 },
+		{ RCVDBDI_STD_BD+0xc, 0x0000,
+			0x00000000, 0xffffffff },
+	
+		/* Receive BD Initiator Control Registers. */
+		{ RCVBDI_STD_THRESH, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ RCVBDI_STD_THRESH, TG3_FL_5705,
+			0x00000000, 0x000003ff },
+		{ RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+	
+		/* Host Coalescing Control Registers. */
+		{ HOSTCC_MODE, TG3_FL_NOT_5705,
+			0x00000000, 0x00000004 },
+		{ HOSTCC_MODE, TG3_FL_5705,
+			0x00000000, 0x000000f6 },
+		{ HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_RXCOL_TICKS, TG3_FL_5705,
+			0x00000000, 0x000003ff },
+		{ HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_TXCOL_TICKS, TG3_FL_5705,
+			0x00000000, 0x000003ff },
+		{ HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
+			0x00000000, 0x000000ff },
+		{ HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
+			0x00000000, 0x000000ff },
+		{ HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
+			0x00000000, 0x000000ff },
+		{ HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
+			0x00000000, 0x000000ff },
+		{ HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000,
+			0x00000000, 0xffffffff },
+		{ HOSTCC_STATS_BLK_NIC_ADDR, 0x0000,
+			0xffffffff, 0x00000000 },
+		{ HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000,
+			0xffffffff, 0x00000000 },
+
+		/* Buffer Manager Control Registers. */
+		{ BUFMGR_MB_POOL_ADDR, 0x0000,
+			0x00000000, 0x007fff80 },
+		{ BUFMGR_MB_POOL_SIZE, 0x0000,
+			0x00000000, 0x007fffff },
+		{ BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
+			0x00000000, 0x0000003f },
+		{ BUFMGR_MB_MACRX_LOW_WATER, 0x0000,
+			0x00000000, 0x000001ff },
+		{ BUFMGR_MB_HIGH_WATER, 0x0000,
+			0x00000000, 0x000001ff },
+		{ BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705,
+			0xffffffff, 0x00000000 },
+		{ BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705,
+			0xffffffff, 0x00000000 },
+	
+		/* Mailbox Registers */
+		{ GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000,
+			0x00000000, 0x000001ff },
+		{ GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705,
+			0x00000000, 0x000001ff },
+		{ GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000,
+			0x00000000, 0x000007ff },
+		{ GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000,
+			0x00000000, 0x000001ff },
+
+		{ 0xffff, 0x0000, 0x00000000, 0x00000000 },
+	};
+
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+		is_5705 = 1;
+	else
+		is_5705 = 0;
+
+	for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
+		if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
+			continue;
+
+		if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705))
+			continue;
+
+		if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
+		    (reg_tbl[i].flags & TG3_FL_NOT_5788))
+			continue;
+
+		offset = (u32) reg_tbl[i].offset;
+		read_mask = reg_tbl[i].read_mask;
+		write_mask = reg_tbl[i].write_mask;
+
+		/* Save the original register content */
+		save_val = tr32(offset);
+
+		/* Determine the read-only value. */
+		read_val = save_val & read_mask;
+
+		/* Write zero to the register, then make sure the read-only bits
+		 * are not changed and the read/write bits are all zeros.
+		 */
+		tw32(offset, 0);
+
+		val = tr32(offset);
+
+		/* Test the read-only and read/write bits. */
+		if (((val & read_mask) != read_val) || (val & write_mask))
+			goto out;
+
+		/* Write ones to all the bits defined by RdMask and WrMask, then
+		 * make sure the read-only bits are not changed and the
+		 * read/write bits are all ones.
+		 */
+		tw32(offset, read_mask | write_mask);
+
+		val = tr32(offset);
+
+		/* Test the read-only bits. */
+		if ((val & read_mask) != read_val)
+			goto out;
+
+		/* Test the read/write bits. */
+		if ((val & write_mask) != write_mask)
+			goto out;
+
+		tw32(offset, save_val);
+	}
+
+	return 0;
+
+out:
+	printk(KERN_ERR PFX "Register test failed at offset %x\n", offset);
+	tw32(offset, save_val);
+	return -EIO;
+}
+
+static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
+{
+	static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a };
+	int i;
+	u32 j;
+
+	for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+		for (j = 0; j < len; j += 4) {
+			u32 val;
+
+			tg3_write_mem(tp, offset + j, test_pattern[i]);
+			tg3_read_mem(tp, offset + j, &val);
+			if (val != test_pattern[i])
+				return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int tg3_test_memory(struct tg3 *tp)
+{
+	static struct mem_entry {
+		u32 offset;
+		u32 len;
+	} mem_tbl_570x[] = {
+		{ 0x00000000, 0x01000},
+		{ 0x00002000, 0x1c000},
+		{ 0xffffffff, 0x00000}
+	}, mem_tbl_5705[] = {
+		{ 0x00000100, 0x0000c},
+		{ 0x00000200, 0x00008},
+		{ 0x00000b50, 0x00400},
+		{ 0x00004000, 0x00800},
+		{ 0x00006000, 0x01000},
+		{ 0x00008000, 0x02000},
+		{ 0x00010000, 0x0e000},
+		{ 0xffffffff, 0x00000}
+	};
+	struct mem_entry *mem_tbl;
+	int err = 0;
+	int i;
+
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+		mem_tbl = mem_tbl_5705;
+	else
+		mem_tbl = mem_tbl_570x;
+
+	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
+		if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset,
+		    mem_tbl[i].len)) != 0)
+			break;
+	}
+	
+	return err;
+}
+
+static int tg3_test_loopback(struct tg3 *tp)
+{
+	u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key;
+	u32 desc_idx;
+	struct sk_buff *skb, *rx_skb;
+	u8 *tx_data;
+	dma_addr_t map;
+	int num_pkts, tx_len, rx_len, i, err;
+	struct tg3_rx_buffer_desc *desc;
+
+	if (!netif_running(tp->dev))
+		return -ENODEV;
+
+	err = -EIO;
+
+	tg3_abort_hw(tp, 1);
+
+	/* Clearing this flag to keep interrupts disabled */
+	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+	tg3_reset_hw(tp);
+
+	mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+		   MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
+		   MAC_MODE_PORT_MODE_GMII;
+	tw32(MAC_MODE, mac_mode);
+
+	tx_len = 1514;
+	skb = dev_alloc_skb(tx_len);
+	tx_data = skb_put(skb, tx_len);
+	memcpy(tx_data, tp->dev->dev_addr, 6);
+	memset(tx_data + 6, 0x0, 8);
+
+	tw32(MAC_RX_MTU_SIZE, tx_len + 4);
+
+	for (i = 14; i < tx_len; i++)
+		tx_data[i] = (u8) (i & 0xff);
+
+	map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE);
+
+	tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+	     HOSTCC_MODE_NOW);
+
+	udelay(10);
+
+	rx_start_idx = tp->hw_status->idx[0].rx_producer;
+
+	send_idx = 0;
+	num_pkts = 0;
+
+	tg3_set_txd(tp, send_idx, map, tx_len, 0, 1);
+
+	send_idx++;
+	num_pkts++;
+
+	tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx);
+	tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
+
+	udelay(10);
+
+	for (i = 0; i < 10; i++) {
+		tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+		       HOSTCC_MODE_NOW);
+
+		udelay(10);
 
-static int tg3_get_stats_count (struct net_device *dev)
-{
-	return TG3_NUM_STATS;
-}
+		tx_idx = tp->hw_status->idx[0].tx_consumer;
+		rx_idx = tp->hw_status->idx[0].rx_producer;
+		if ((tx_idx == send_idx) &&
+		    (rx_idx == (rx_start_idx + num_pkts)))
+			break;
+	}
 
-static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
-{
-	switch (stringset) {
-	case ETH_SS_STATS:
-		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
-		break;
-	default:
-		WARN_ON(1);	/* we need a WARN() */
-		break;
+	pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
+	dev_kfree_skb(skb);
+
+	if (tx_idx != send_idx)
+		goto out;
+
+	if (rx_idx != rx_start_idx + num_pkts)
+		goto out;
+
+	desc = &tp->rx_rcb[rx_start_idx];
+	desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
+	opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
+	if (opaque_key != RXD_OPAQUE_RING_STD)
+		goto out;
+
+	if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
+	    (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII))
+		goto out;
+
+	rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4;
+	if (rx_len != tx_len)
+		goto out;
+
+	rx_skb = tp->rx_std_buffers[desc_idx].skb;
+
+	map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping);
+	pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE);
+
+	for (i = 14; i < tx_len; i++) {
+		if (*(rx_skb->data + i) != (u8) (i & 0xff))
+			goto out;
 	}
+	err = 0;
+	
+	/* tg3_free_rings will unmap and free the rx_skb */
+out:
+	return err;
 }
 
-static void tg3_get_ethtool_stats (struct net_device *dev,
-				   struct ethtool_stats *estats, u64 *tmp_stats)
+static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
+			  u64 *data)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
+
+	memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
+
+	if (tg3_test_nvram(tp) != 0) {
+		etest->flags |= ETH_TEST_FL_FAILED;
+		data[0] = 1;
+	}
+	if (tg3_test_link(tp) != 0) {
+		etest->flags |= ETH_TEST_FL_FAILED;
+		data[1] = 1;
+	}
+	if (etest->flags & ETH_TEST_FL_OFFLINE) {
+		if (netif_running(dev))
+			tg3_netif_stop(tp);
+
+		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
+
+		tg3_halt(tp, RESET_KIND_SUSPEND, 1);
+		tg3_nvram_lock(tp);
+		tg3_halt_cpu(tp, RX_CPU_BASE);
+		if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+			tg3_halt_cpu(tp, TX_CPU_BASE);
+		tg3_nvram_unlock(tp);
+
+		if (tg3_test_registers(tp) != 0) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			data[2] = 1;
+		}
+		if (tg3_test_memory(tp) != 0) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			data[3] = 1;
+		}
+		if (tg3_test_loopback(tp) != 0) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			data[4] = 1;
+		}
+
+		spin_unlock(&tp->tx_lock);
+		spin_unlock_irq(&tp->lock);
+		if (tg3_test_interrupt(tp) != 0) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			data[5] = 1;
+		}
+		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
+
+		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+		if (netif_running(dev)) {
+			tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+			tg3_init_hw(tp);
+			tg3_netif_start(tp);
+		}
+		spin_unlock(&tp->tx_lock);
+		spin_unlock_irq(&tp->lock);
+	}
 }
 
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -6905,6 +7838,14 @@ static void tg3_vlan_rx_kill_vid(struct 
 }
 #endif
 
+static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
+{
+	struct tg3 *tp = netdev_priv(dev);
+
+	memcpy(ec, &tp->coal, sizeof(*ec));
+	return 0;
+}
+
 static struct ethtool_ops tg3_ethtool_ops = {
 	.get_settings		= tg3_get_settings,
 	.set_settings		= tg3_set_settings,
@@ -6934,9 +7875,12 @@ static struct ethtool_ops tg3_ethtool_op
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= tg3_set_tso,
 #endif
+	.self_test_count	= tg3_get_test_count,
+	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
 	.get_stats_count	= tg3_get_stats_count,
 	.get_ethtool_stats	= tg3_get_ethtool_stats,
+	.get_coalesce		= tg3_get_coalesce,
 };
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -7036,6 +7980,67 @@ static void __devinit tg3_get_nvram_info
 	}
 }
 
+static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp)
+{
+	u32 nvcfg1;
+
+	nvcfg1 = tr32(NVRAM_CFG1);
+
+	/* NVRAM protection for TPM */
+	if (nvcfg1 & (1 << 27))
+		tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+
+	switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
+		case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ:
+		case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ:
+			tp->nvram_jedecnum = JEDEC_ATMEL;
+			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+			break;
+		case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+			tp->nvram_jedecnum = JEDEC_ATMEL;
+			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+			tp->tg3_flags2 |= TG3_FLG2_FLASH;
+			break;
+		case FLASH_5752VENDOR_ST_M45PE10:
+		case FLASH_5752VENDOR_ST_M45PE20:
+		case FLASH_5752VENDOR_ST_M45PE40:
+			tp->nvram_jedecnum = JEDEC_ST;
+			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+			tp->tg3_flags2 |= TG3_FLG2_FLASH;
+			break;
+	}
+
+	if (tp->tg3_flags2 & TG3_FLG2_FLASH) {
+		switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) {
+			case FLASH_5752PAGE_SIZE_256:
+				tp->nvram_pagesize = 256;
+				break;
+			case FLASH_5752PAGE_SIZE_512:
+				tp->nvram_pagesize = 512;
+				break;
+			case FLASH_5752PAGE_SIZE_1K:
+				tp->nvram_pagesize = 1024;
+				break;
+			case FLASH_5752PAGE_SIZE_2K:
+				tp->nvram_pagesize = 2048;
+				break;
+			case FLASH_5752PAGE_SIZE_4K:
+				tp->nvram_pagesize = 4096;
+				break;
+			case FLASH_5752PAGE_SIZE_264:
+				tp->nvram_pagesize = 264;
+				break;
+		}
+	}
+	else {
+		/* For eeprom, set pagesize to maximum eeprom size */
+		tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+
+		nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+		tw32(NVRAM_CFG1, nvcfg1);
+	}
+}
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
@@ -7062,20 +8067,16 @@ static void __devinit tg3_nvram_init(str
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
 		tp->tg3_flags |= TG3_FLAG_NVRAM;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-			u32 nvaccess = tr32(NVRAM_ACCESS);
+		tg3_enable_nvram_access(tp);
 
-			tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
-		}
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+			tg3_get_5752_nvram_info(tp);
+		else
+			tg3_get_nvram_info(tp);
 
-		tg3_get_nvram_info(tp);
 		tg3_get_nvram_size(tp);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-			u32 nvaccess = tr32(NVRAM_ACCESS);
-
-			tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
-		}
+		tg3_disable_nvram_access(tp);
 
 	} else {
 		tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
@@ -7164,11 +8165,7 @@ static int tg3_nvram_read(struct tg3 *tp
 
 	tg3_nvram_lock(tp);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-		u32 nvaccess = tr32(NVRAM_ACCESS);
-
-		tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
-	}
+	tg3_enable_nvram_access(tp);
 
 	tw32(NVRAM_ADDR, offset);
 	ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
@@ -7179,11 +8176,7 @@ static int tg3_nvram_read(struct tg3 *tp
 
 	tg3_nvram_unlock(tp);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-		u32 nvaccess = tr32(NVRAM_ACCESS);
-
-		tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
-	}
+	tg3_disable_nvram_access(tp);
 
 	return ret;
 }
@@ -7246,7 +8239,7 @@ static int tg3_nvram_write_block_unbuffe
 
 	while (len) {
 		int j;
-		u32 phy_addr, page_off, size, nvaccess;
+		u32 phy_addr, page_off, size;
 
 		phy_addr = offset & ~pagemask;
 	
@@ -7269,8 +8262,7 @@ static int tg3_nvram_write_block_unbuffe
 
 		offset = offset + (pagesize - page_off);
 
-		nvaccess = tr32(NVRAM_ACCESS);
-		tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+		tg3_enable_nvram_access(tp);
 
 		/*
 		 * Before we can erase the flash page, we need
@@ -7394,8 +8386,8 @@ static int tg3_nvram_write_block(struct 
 	}
 
 	if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
-		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
-		       GRC_LCLCTRL_GPIO_OE1);
+		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
+		       ~GRC_LCLCTRL_GPIO_OUTPUT1);
 		udelay(40);
 	}
 
@@ -7407,13 +8399,10 @@ static int tg3_nvram_write_block(struct 
 
 		tg3_nvram_lock(tp);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-			u32 nvaccess = tr32(NVRAM_ACCESS);
-
-			tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
-
+		tg3_enable_nvram_access(tp);
+		if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+		    !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM))
 			tw32(NVRAM_WRITE1, 0x406);
-		}
 
 		grc_mode = tr32(GRC_MODE);
 		tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
@@ -7432,17 +8421,12 @@ static int tg3_nvram_write_block(struct 
 		grc_mode = tr32(GRC_MODE);
 		tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-			u32 nvaccess = tr32(NVRAM_ACCESS);
-
-			tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
-		}
+		tg3_disable_nvram_access(tp);
 		tg3_nvram_unlock(tp);
 	}
 
 	if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
-		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
-		       GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1);
+		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
 		udelay(40);
 	}
 
@@ -7506,21 +8490,27 @@ static inline struct subsys_tbl_ent *loo
 	return NULL;
 }
 
-static int __devinit tg3_phy_probe(struct tg3 *tp)
+/* Since this function may be called in D3-hot power state during
+ * tg3_init_one(), only config cycles are allowed.
+ */
+static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
 {
-	u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
-	u32 hw_phy_id, hw_phy_id_masked;
 	u32 val;
-	int eeprom_signature_found, eeprom_phy_serdes, err;
+
+	/* Make sure register accesses (indirect or otherwise)
+	 * will function correctly.
+	 */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
 
 	tp->phy_id = PHY_ID_INVALID;
-	eeprom_phy_id = PHY_ID_INVALID;
-	eeprom_phy_serdes = 0;
-	eeprom_signature_found = 0;
+	tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+
 	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
 	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
 		u32 nic_cfg, led_cfg;
-		u32 nic_phy_id, ver, cfg2 = 0;
+		u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id;
+		int eeprom_phy_serdes = 0;
 
 		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
 		tp->nic_sram_data_cfg = nic_cfg;
@@ -7533,8 +8523,6 @@ static int __devinit tg3_phy_probe(struc
 		    (ver > 0) && (ver < 0x100))
 			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
 
-		eeprom_signature_found = 1;
-
 		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
 		    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
 			eeprom_phy_serdes = 1;
@@ -7550,10 +8538,14 @@ static int __devinit tg3_phy_probe(struc
 		} else
 			eeprom_phy_id = 0;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+		tp->phy_id = eeprom_phy_id;
+		if (eeprom_phy_serdes)
+			tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+
+		if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 			led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
 				    SHASTA_EXT_LED_MODE_MASK);
-		} else
+		else
 			led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK;
 
 		switch (led_cfg) {
@@ -7568,6 +8560,16 @@ static int __devinit tg3_phy_probe(struc
 
 		case NIC_SRAM_DATA_CFG_LED_MODE_MAC:
 			tp->led_ctrl = LED_CTRL_MODE_MAC;
+
+			/* Default to PHY_1_MODE if 0 (MAC_MODE) is
+			 * read on some older 5700/5701 bootcode.
+			 */
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+			    ASIC_REV_5700 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) ==
+			    ASIC_REV_5701)
+				tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+
 			break;
 
 		case SHASTA_EXT_LED_SHARED:
@@ -7603,7 +8605,7 @@ static int __devinit tg3_phy_probe(struc
 
 		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
 			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+			if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 				tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
 		}
 		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
@@ -7617,6 +8619,13 @@ static int __devinit tg3_phy_probe(struc
 		if (cfg2 & (1 << 18))
 			tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
 	}
+}
+
+static int __devinit tg3_phy_probe(struct tg3 *tp)
+{
+	u32 hw_phy_id_1, hw_phy_id_2;
+	u32 hw_phy_id, hw_phy_id_masked;
+	int err;
 
 	/* Reading the PHY ID register can conflict with ASF
 	 * firwmare access to the PHY hardware.
@@ -7645,10 +8654,10 @@ static int __devinit tg3_phy_probe(struc
 		if (hw_phy_id_masked == PHY_ID_BCM8002)
 			tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
 	} else {
-		if (eeprom_signature_found) {
-			tp->phy_id = eeprom_phy_id;
-			if (eeprom_phy_serdes)
-				tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+		if (tp->phy_id != PHY_ID_INVALID) {
+			/* Do nothing, phy ID already set up in
+			 * tg3_get_eeprom_hw_cfg().
+			 */
 		} else {
 			struct subsys_tbl_ent *p;
 
@@ -7719,9 +8728,6 @@ skip_phy_reset:
 		err = tg3_init_5401phy_dsp(tp);
 	}
 
-	if (!eeprom_signature_found)
-		tp->led_ctrl = LED_CTRL_MODE_PHY_1;
-
 	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
 		tp->link_config.advertising =
 			(ADVERTISED_1000baseT_Half |
@@ -7829,6 +8835,19 @@ static int __devinit tg3_is_sun_570X(str
 
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
+	static struct pci_device_id write_reorder_chipsets[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+		             PCI_DEVICE_ID_INTEL_82801AA_8) },
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+		             PCI_DEVICE_ID_INTEL_82801AB_8) },
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+		             PCI_DEVICE_ID_INTEL_82801BA_11) },
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+		             PCI_DEVICE_ID_INTEL_82801BA_6) },
+		{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
+		             PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+		{ },
+	};
 	u32 misc_ctrl_reg;
 	u32 cacheline_sz_reg;
 	u32 pci_state_reg, grc_misc_cfg;
@@ -7847,16 +8866,7 @@ static int __devinit tg3_get_invariants(
 	 * 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_INTEL,
-			    PCI_DEVICE_ID_INTEL_82801BA_11, NULL) ||
-	    pci_find_device(PCI_VENDOR_ID_INTEL,
-			    PCI_DEVICE_ID_INTEL_82801BA_6, NULL) ||
-	    pci_find_device(PCI_VENDOR_ID_AMD,
-			    PCI_DEVICE_ID_AMD_FE_GATE_700C, NULL))
+	if (pci_dev_present(write_reorder_chipsets))
 		tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
 
 	/* Force memory write invalidate off.  If we leave it on,
@@ -7882,6 +8892,12 @@ static int __devinit tg3_get_invariants(
 	tp->pci_chip_rev_id = (misc_ctrl_reg >>
 			       MISC_HOST_CTRL_CHIPREV_SHIFT);
 
+	/* Wrong chip ID in 5752 A0. This code can be removed later
+	 * as A0 is not in production.
+	 */
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+		tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+
 	/* Initialize misc host control in PCI block. */
 	tp->misc_host_ctrl |= (misc_ctrl_reg &
 			       MISC_HOST_CTRL_CHIPREV);
@@ -7896,7 +8912,15 @@ static int __devinit tg3_get_invariants(
 	tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
 	tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
+
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) ||
+	    (tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
+		tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
+
+	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 		tp->tg3_flags2 |= TG3_FLG2_HW_TSO;
 
 	if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
@@ -7974,6 +8998,31 @@ static int __devinit tg3_get_invariants(
 		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
 	}
 
+	/* Get eeprom hw config before calling tg3_set_power_state().
+	 * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be
+	 * determined before calling tg3_set_power_state() so that
+	 * we know whether or not to switch out of Vaux power.
+	 * When the flag is set, it means that GPIO1 is used for eeprom
+	 * write protect and also implies that it is a LOM where GPIOs
+	 * are not used to switch power.
+	 */ 
+	tg3_get_eeprom_hw_cfg(tp);
+
+	/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
+	 * GPIO1 driven high will bring 5700's external PHY out of reset.
+	 * It is also used as eeprom write protect on LOMs.
+	 */
+	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->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT))
+		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+				       GRC_LCLCTRL_GPIO_OUTPUT1);
+	/* Unused GPIO3 must be driven as output on 5752 because there
+	 * are no pull-up resistors on unused GPIO pins.
+	 */
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
+
 	/* Force the chip into D0. */
 	err = tg3_set_power_state(tp, 0);
 	if (err) {
@@ -8026,19 +9075,10 @@ static int __devinit tg3_get_invariants(
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
 		tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
 		tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
 
-	/* Only 5701 and later support tagged irq status mode.
-	 * Also, 5788 chips cannot use tagged irq status.
-	 *
-	 * 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;
@@ -8102,6 +9142,18 @@ static int __devinit tg3_get_invariants(
 	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
 		tp->tg3_flags2 |= TG3_FLG2_IS_5788;
 
+	if (!(tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700))
+		tp->tg3_flags |= TG3_FLAG_TAGGED_STATUS;
+	if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+		tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD |
+				      HOSTCC_MODE_CLRTICK_TXBD);
+
+		tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
+		pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+				       tp->misc_host_ctrl);
+	}
+
 	/* these are limited to 10/100 only */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
 	     (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
@@ -8279,6 +9331,146 @@ static int __devinit tg3_get_device_addr
 	return 0;
 }
 
+#define BOUNDARY_SINGLE_CACHELINE	1
+#define BOUNDARY_MULTI_CACHELINE	2
+
+static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
+{
+	int cacheline_size;
+	u8 byte;
+	int goal;
+
+	pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte);
+	if (byte == 0)
+		cacheline_size = 1024;
+	else
+		cacheline_size = (int) byte * 4;
+
+	/* On 5703 and later chips, the boundary bits have no
+	 * effect.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+	    !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+		goto out;
+
+#if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC)
+	goal = BOUNDARY_MULTI_CACHELINE;
+#else
+#if defined(CONFIG_SPARC64) || defined(CONFIG_ALPHA)
+	goal = BOUNDARY_SINGLE_CACHELINE;
+#else
+	goal = 0;
+#endif
+#endif
+
+	if (!goal)
+		goto out;
+
+	/* PCI controllers on most RISC systems tend to disconnect
+	 * when a device tries to burst across a cache-line boundary.
+	 * Therefore, letting tg3 do so just wastes PCI bandwidth.
+	 *
+	 * Unfortunately, for PCI-E there are only limited
+	 * write-side controls for this, and thus for reads
+	 * we will still get the disconnects.  We'll also waste
+	 * these PCI cycles for both read and write for chips
+	 * other than 5700 and 5701 which do not implement the
+	 * boundary bits.
+	 */
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+	    !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
+		switch (cacheline_size) {
+		case 16:
+		case 32:
+		case 64:
+		case 128:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val |= (DMA_RWCTRL_READ_BNDRY_128_PCIX |
+					DMA_RWCTRL_WRITE_BNDRY_128_PCIX);
+			} else {
+				val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
+					DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
+			}
+			break;
+
+		case 256:
+			val |= (DMA_RWCTRL_READ_BNDRY_256_PCIX |
+				DMA_RWCTRL_WRITE_BNDRY_256_PCIX);
+			break;
+
+		default:
+			val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
+				DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
+			break;
+		};
+	} else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+		switch (cacheline_size) {
+		case 16:
+		case 32:
+		case 64:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
+				val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE;
+				break;
+			}
+			/* fallthrough */
+		case 128:
+		default:
+			val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
+			val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
+			break;
+		};
+	} else {
+		switch (cacheline_size) {
+		case 16:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val |= (DMA_RWCTRL_READ_BNDRY_16 |
+					DMA_RWCTRL_WRITE_BNDRY_16);
+				break;
+			}
+			/* fallthrough */
+		case 32:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val |= (DMA_RWCTRL_READ_BNDRY_32 |
+					DMA_RWCTRL_WRITE_BNDRY_32);
+				break;
+			}
+			/* fallthrough */
+		case 64:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val |= (DMA_RWCTRL_READ_BNDRY_64 |
+					DMA_RWCTRL_WRITE_BNDRY_64);
+				break;
+			}
+			/* fallthrough */
+		case 128:
+			if (goal == BOUNDARY_SINGLE_CACHELINE) {
+				val |= (DMA_RWCTRL_READ_BNDRY_128 |
+					DMA_RWCTRL_WRITE_BNDRY_128);
+				break;
+			}
+			/* fallthrough */
+		case 256:
+			val |= (DMA_RWCTRL_READ_BNDRY_256 |
+				DMA_RWCTRL_WRITE_BNDRY_256);
+			break;
+		case 512:
+			val |= (DMA_RWCTRL_READ_BNDRY_512 |
+				DMA_RWCTRL_WRITE_BNDRY_512);
+			break;
+		case 1024:
+		default:
+			val |= (DMA_RWCTRL_READ_BNDRY_1024 |
+				DMA_RWCTRL_WRITE_BNDRY_1024);
+			break;
+		};
+	}
+
+out:
+	return val;
+}
+
 static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma, int size, int to_device)
 {
 	struct tg3_internal_buffer_desc test_desc;
@@ -8360,12 +9552,12 @@ static int __devinit tg3_do_test_dma(str
 	return ret;
 }
 
-#define TEST_BUFFER_SIZE	0x400
+#define TEST_BUFFER_SIZE	0x2000
 
 static int __devinit tg3_test_dma(struct tg3 *tp)
 {
 	dma_addr_t buf_dma;
-	u32 *buf;
+	u32 *buf, saved_dma_rwctrl;
 	int ret;
 
 	buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma);
@@ -8377,46 +9569,7 @@ static int __devinit tg3_test_dma(struct
 	tp->dma_rwctrl = ((0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
 			  (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT));
 
-#ifndef CONFIG_X86
-	{
-		u8 byte;
-		int cacheline_size;
-		pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte);
-
-		if (byte == 0)
-			cacheline_size = 1024;
-		else
-			cacheline_size = (int) byte * 4;
-
-		switch (cacheline_size) {
-		case 16:
-		case 32:
-		case 64:
-		case 128:
-			if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
-			    !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
-				tp->dma_rwctrl |=
-					DMA_RWCTRL_WRITE_BNDRY_384_PCIX;
-				break;
-			} else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
-				tp->dma_rwctrl &=
-					~(DMA_RWCTRL_PCI_WRITE_CMD);
-				tp->dma_rwctrl |=
-					DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
-				break;
-			}
-			/* fallthrough */
-		case 256:
-			if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
-			    !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
-				tp->dma_rwctrl |=
-					DMA_RWCTRL_WRITE_BNDRY_256;
-			else if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
-				tp->dma_rwctrl |=
-					DMA_RWCTRL_WRITE_BNDRY_256_PCIX;
-		};
-	}
-#endif
+	tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
 
 	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
 		/* DMA read watermark not used on PCIE */
@@ -8435,7 +9588,7 @@ static int __devinit tg3_test_dma(struct
 			if (ccval == 0x6 || ccval == 0x7)
 				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
 
-			/* Set bit 23 to renable PCIX hw bug fix */
+			/* Set bit 23 to enable PCIX hw bug fix */
 			tp->dma_rwctrl |= 0x009f0000;
 		} else {
 			tp->dma_rwctrl |= 0x001b000f;
@@ -8476,6 +9629,13 @@ static int __devinit tg3_test_dma(struct
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
 		goto out;
 
+	/* It is best to perform DMA test with maximum write burst size
+	 * to expose the 5700/5701 write DMA bug.
+	 */
+	saved_dma_rwctrl = tp->dma_rwctrl;
+	tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
 	while (1) {
 		u32 *p = buf, i;
 
@@ -8514,8 +9674,9 @@ static int __devinit tg3_test_dma(struct
 			if (p[i] == i)
 				continue;
 
-			if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) ==
-			    DMA_RWCTRL_WRITE_BNDRY_DISAB) {
+			if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+			    DMA_RWCTRL_WRITE_BNDRY_16) {
+				tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
 				tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
 				tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
 				break;
@@ -8532,6 +9693,28 @@ static int __devinit tg3_test_dma(struct
 			break;
 		}
 	}
+	if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+	    DMA_RWCTRL_WRITE_BNDRY_16) {
+		static struct pci_device_id dma_wait_state_chipsets[] = {
+			{ PCI_DEVICE(PCI_VENDOR_ID_APPLE,
+				     PCI_DEVICE_ID_APPLE_UNI_N_PCI15) },
+			{ },
+		};
+
+		/* DMA test passed without adjusting DMA boundary,
+		 * now look for chipsets that are known to expose the
+		 * DMA bug without failing the test.
+		 */
+		if (pci_dev_present(dma_wait_state_chipsets)) {
+			tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+			tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
+		}
+		else
+			/* Safe to use the calculated DMA boundary. */
+			tp->dma_rwctrl = saved_dma_rwctrl;
+
+		tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+	}
 
 out:
 	pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
@@ -8589,6 +9772,7 @@ static char * __devinit tg3_phy_string(s
 	case PHY_ID_BCM5704:	return "5704";
 	case PHY_ID_BCM5705:	return "5705";
 	case PHY_ID_BCM5750:	return "5750";
+	case PHY_ID_BCM5752:	return "5752";
 	case PHY_ID_BCM8002:	return "8002/serdes";
 	case 0:			return "serdes";
 	default:		return "unknown";
@@ -8618,6 +9802,31 @@ static struct pci_dev * __devinit tg3_fi
 	return peer;
 }
 
+static void __devinit tg3_init_coal(struct tg3 *tp)
+{
+	struct ethtool_coalesce *ec = &tp->coal;
+
+	memset(ec, 0, sizeof(*ec));
+	ec->cmd = ETHTOOL_GCOALESCE;
+	ec->rx_coalesce_usecs = LOW_RXCOL_TICKS;
+	ec->tx_coalesce_usecs = LOW_TXCOL_TICKS;
+	ec->rx_max_coalesced_frames = LOW_RXMAX_FRAMES;
+	ec->tx_max_coalesced_frames = LOW_TXMAX_FRAMES;
+	ec->rx_coalesce_usecs_irq = DEFAULT_RXCOAL_TICK_INT;
+	ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT;
+	ec->rx_max_coalesced_frames_irq = DEFAULT_RXCOAL_MAXF_INT;
+	ec->tx_max_coalesced_frames_irq = DEFAULT_TXCOAL_MAXF_INT;
+	ec->stats_block_coalesce_usecs = DEFAULT_STAT_COAL_TICKS;
+
+	if (tp->coalesce_mode & (HOSTCC_MODE_CLRTICK_RXBD |
+				 HOSTCC_MODE_CLRTICK_TXBD)) {
+		ec->rx_coalesce_usecs = LOW_RXCOL_TICKS_CLRTCKS;
+		ec->rx_coalesce_usecs_irq = DEFAULT_RXCOAL_TICK_INT_CLRTCKS;
+		ec->tx_coalesce_usecs = LOW_TXCOL_TICKS_CLRTCKS;
+		ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS;
+	}
+}
+
 static int __devinit tg3_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
@@ -8783,8 +9992,7 @@ static int __devinit tg3_init_one(struct
 		goto err_out_iounmap;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		tp->bufmgr_config.mbuf_read_dma_low_water =
 			DEFAULT_MB_RDMA_LOW_WATER_5705;
 		tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -8840,7 +10048,7 @@ static int __devinit tg3_init_one(struct
 	    (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
 		pci_save_state(tp->pdev);
 		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
-		tg3_halt(tp);
+		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 	}
 
 	err = tg3_test_dma(tp);
@@ -8864,6 +10072,8 @@ static int __devinit tg3_init_one(struct
 	/* flow control autonegotiation is default behavior */
 	tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
 
+	tg3_init_coal(tp);
+
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot register net device, "
@@ -8906,6 +10116,8 @@ static int __devinit tg3_init_one(struct
 	       (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0,
 	       (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0,
 	       (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
+	printk(KERN_INFO "%s: dma_rwctrl[%08x]\n",
+	       dev->name, tp->dma_rwctrl);
 
 	return 0;
 
@@ -8940,7 +10152,7 @@ static void __devexit tg3_remove_one(str
 	}
 }
 
-static int tg3_suspend(struct pci_dev *pdev, u32 state)
+static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct tg3 *tp = netdev_priv(dev);
@@ -8963,11 +10175,11 @@ static int tg3_suspend(struct pci_dev *p
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
-	tg3_halt(tp);
+	tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
-	err = tg3_set_power_state(tp, state);
+	err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
 	if (err) {
 		spin_lock_irq(&tp->lock);
 		spin_lock(&tp->tx_lock);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -125,6 +125,9 @@
 #define  CHIPREV_ID_5750_A0		 0x4000
 #define  CHIPREV_ID_5750_A1		 0x4001
 #define  CHIPREV_ID_5750_A3		 0x4003
+#define  CHIPREV_ID_5752_A0_HW		 0x5000
+#define  CHIPREV_ID_5752_A0		 0x6000
+#define  CHIPREV_ID_5752_A1		 0x6001
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
@@ -132,6 +135,7 @@
 #define   ASIC_REV_5704			 0x02
 #define   ASIC_REV_5705			 0x03
 #define   ASIC_REV_5750			 0x04
+#define   ASIC_REV_5752			 0x06
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -140,6 +144,8 @@
 #define   CHIPREV_5703_AX		 0x10
 #define   CHIPREV_5704_AX		 0x20
 #define   CHIPREV_5704_BX		 0x21
+#define   CHIPREV_5750_AX		 0x40
+#define   CHIPREV_5750_BX		 0x41
 #define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
 #define   METAL_REV_A0			 0x00
 #define   METAL_REV_A1			 0x01
@@ -870,10 +876,12 @@
 #define  HOSTCC_STATUS_ERROR_ATTN	 0x00000004
 #define HOSTCC_RXCOL_TICKS		0x00003c08
 #define  LOW_RXCOL_TICKS		 0x00000032
+#define  LOW_RXCOL_TICKS_CLRTCKS	 0x00000014
 #define  DEFAULT_RXCOL_TICKS		 0x00000048
 #define  HIGH_RXCOL_TICKS		 0x00000096
 #define HOSTCC_TXCOL_TICKS		0x00003c0c
 #define  LOW_TXCOL_TICKS		 0x00000096
+#define  LOW_TXCOL_TICKS_CLRTCKS	 0x00000048
 #define  DEFAULT_TXCOL_TICKS		 0x0000012c
 #define  HIGH_TXCOL_TICKS		 0x00000145
 #define HOSTCC_RXMAX_FRAMES		0x00003c10
@@ -886,8 +894,10 @@
 #define  HIGH_TXMAX_FRAMES		 0x00000052
 #define HOSTCC_RXCOAL_TICK_INT		0x00003c18
 #define  DEFAULT_RXCOAL_TICK_INT	 0x00000019
+#define  DEFAULT_RXCOAL_TICK_INT_CLRTCKS 0x00000014
 #define HOSTCC_TXCOAL_TICK_INT		0x00003c1c
 #define  DEFAULT_TXCOAL_TICK_INT	 0x00000019
+#define  DEFAULT_TXCOAL_TICK_INT_CLRTCKS 0x00000014
 #define HOSTCC_RXCOAL_MAXF_INT		0x00003c20
 #define  DEFAULT_RXCOAL_MAXF_INT	 0x00000005
 #define HOSTCC_TXCOAL_MAXF_INT		0x00003c24
@@ -1305,6 +1315,9 @@
 #define  GRC_LCLCTRL_CLEARINT		0x00000002
 #define  GRC_LCLCTRL_SETINT		0x00000004
 #define  GRC_LCLCTRL_INT_ON_ATTN	0x00000008
+#define  GRC_LCLCTRL_GPIO_INPUT3	0x00000020
+#define  GRC_LCLCTRL_GPIO_OE3		0x00000040
+#define  GRC_LCLCTRL_GPIO_OUTPUT3	0x00000080
 #define  GRC_LCLCTRL_GPIO_INPUT0	0x00000100
 #define  GRC_LCLCTRL_GPIO_INPUT1	0x00000200
 #define  GRC_LCLCTRL_GPIO_INPUT2	0x00000400
@@ -1390,6 +1403,20 @@
 #define  FLASH_VENDOR_SAIFUN		 0x01000003
 #define  FLASH_VENDOR_SST_SMALL		 0x00000001
 #define  FLASH_VENDOR_SST_LARGE		 0x02000001
+#define  NVRAM_CFG1_5752VENDOR_MASK	 0x03c00003
+#define  FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ	 0x00000000
+#define  FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ	 0x02000000
+#define  FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED	 0x02000003
+#define  FLASH_5752VENDOR_ST_M45PE10	 0x02400000
+#define  FLASH_5752VENDOR_ST_M45PE20	 0x02400002
+#define  FLASH_5752VENDOR_ST_M45PE40	 0x02400001
+#define  NVRAM_CFG1_5752PAGE_SIZE_MASK	 0x70000000
+#define  FLASH_5752PAGE_SIZE_256	 0x00000000
+#define  FLASH_5752PAGE_SIZE_512	 0x10000000
+#define  FLASH_5752PAGE_SIZE_1K		 0x20000000
+#define  FLASH_5752PAGE_SIZE_2K		 0x30000000
+#define  FLASH_5752PAGE_SIZE_4K		 0x40000000
+#define  FLASH_5752PAGE_SIZE_264	 0x50000000
 #define NVRAM_CFG2			0x00007018
 #define NVRAM_CFG3			0x0000701c
 #define NVRAM_SWARB			0x00007020
@@ -1516,6 +1543,7 @@
 #define  MII_TG3_CTRL_ENABLE_AS_MASTER	0x1000
 
 #define MII_TG3_EXT_CTRL		0x10 /* Extended control register */
+#define  MII_TG3_EXT_CTRL_FIFO_ELASTIC	0x0001
 #define  MII_TG3_EXT_CTRL_LNK3_LED_MODE	0x0002
 #define  MII_TG3_EXT_CTRL_TBI		0x8000
 
@@ -1548,20 +1576,6 @@
 #define MII_TG3_INT_DUPLEXCHG		0x0008
 #define MII_TG3_INT_ANEG_PAGE_RX	0x0400
 
-/* XXX Add this to mii.h */
-#ifndef ADVERTISE_PAUSE
-#define ADVERTISE_PAUSE_CAP		0x0400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-#define ADVERTISE_PAUSE_ASYM		0x0800
-#endif
-#ifndef LPA_PAUSE
-#define LPA_PAUSE_CAP			0x0400
-#endif
-#ifndef LPA_PAUSE_ASYM
-#define LPA_PAUSE_ASYM			0x0800
-#endif
-
 /* There are two ways to manage the TX descriptors on the tigon3.
  * Either the descriptors are in host DMA'able memory, or they
  * exist only in the cards on-chip SRAM.  All 16 send bds are under
@@ -2013,6 +2027,7 @@ struct tg3 {
 
 	struct tg3_hw_status		*hw_status;
 	dma_addr_t			status_mapping;
+	u32				last_tag;
 
 	u32				msg_enable;
 
@@ -2058,6 +2073,7 @@ struct tg3 {
 
 	u32				rx_offset;
 	u32				tg3_flags;
+#define TG3_FLAG_TAGGED_STATUS		0x00000001
 #define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
 #define TG3_FLAG_RX_CHECKSUMS		0x00000004
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
@@ -2110,6 +2126,10 @@ struct tg3 {
 #define TG3_FLG2_FLASH			0x00008000
 #define TG3_FLG2_HW_TSO			0x00010000
 #define TG3_FLG2_SERDES_PREEMPHASIS	0x00020000
+#define TG3_FLG2_5705_PLUS		0x00040000
+#define TG3_FLG2_5750_PLUS		0x00080000
+#define TG3_FLG2_PROTECTED_NVRAM	0x00100000
+#define TG3_FLG2_USING_MSI		0x00200000
 
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
@@ -2155,6 +2175,7 @@ struct tg3 {
 #define PHY_ID_BCM5704			0x60008190
 #define PHY_ID_BCM5705			0x600081a0
 #define PHY_ID_BCM5750			0x60008180
+#define PHY_ID_BCM5752			0x60008100
 #define PHY_ID_BCM8002			0x60010140
 #define PHY_ID_INVALID			0xffffffff
 #define PHY_ID_REV_MASK			0x0000000f
@@ -2210,7 +2231,7 @@ struct tg3 {
 
 #define SST_25VF0X0_PAGE_SIZE		4098
 
-
+	struct ethtool_coalesce		coal;
 };
 
 #endif /* !(_T3_H) */
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -193,6 +193,12 @@ static  int aui[MAX_TLAN_BOARDS];
 static  int duplex[MAX_TLAN_BOARDS];
 static  int speed[MAX_TLAN_BOARDS];
 static  int boards_found;
+module_param_array(aui, int, NULL, 0);
+module_param_array(duplex, int, NULL, 0);
+module_param_array(speed, int, NULL, 0);
+MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)");
+MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)");
+MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)");
 
 MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>");
 MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
@@ -204,8 +210,13 @@ MODULE_LICENSE("GPL");
 
 /* Turn on debugging. See Documentation/networking/tlan.txt for details */
 static  int		debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
 
 static	int		bbuf;
+module_param(bbuf, int, 0);
+MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
+
 static	u8		*TLanPadBuffer;
 static  dma_addr_t	TLanPadBufferDMA;
 static	char		TLanSignature[] = "TLAN";
@@ -2381,6 +2392,7 @@ TLan_FinishReset( struct net_device *dev
 		TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
 		return;
 	}
+	TLan_SetMulticastList(dev);
 
 } /* TLan_FinishReset */
 
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -227,7 +227,7 @@ static void __devinit PrtChanID(char *pc
 	printk("\n");
 }
 
-static void __devinit HWPrtChanID(void * pcid, short stride)
+static void __devinit HWPrtChanID(void __iomem *pcid, short stride)
 {
 	short i, j;
 	for (i = 0, j = 0; i < 24; i++, j += stride)
@@ -239,15 +239,16 @@ static void __devinit HWPrtChanID(void *
  * going away. 
  */
 
-static void __devinit find_turbo_adapters(int *iolist) {
+static void __devinit find_turbo_adapters(int *iolist)
+{
 	int ram_addr;
 	int index=0;
-	void *chanid;
+	void __iomem *chanid;
 	int found_turbo=0;
 	unsigned char *tchanid, ctemp;
 	int i, j;
 	unsigned long jif;
-	void *ram_mapped ;   
+	void __iomem *ram_mapped ;   
 
 	if (turbo_searched == 1) return;
 	turbo_searched=1;
@@ -328,8 +329,8 @@ static void ibmtr_cleanup_card(struct ne
 
 	{ 
 		struct tok_info *ti = (struct tok_info *) dev->priv;
-		iounmap((u32 *)ti->mmio);
-		iounmap((u32 *)ti->sram_virt);
+		iounmap(ti->mmio);
+		iounmap(ti->sram_virt);
 	}
 #endif		
 }
@@ -383,9 +384,9 @@ static int __devinit ibmtr_probe1(struct
 {
 
 	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
-	void * t_mmio = NULL;
+	void __iomem * t_mmio = NULL;
 	struct tok_info *ti = dev->priv;
-	void *cd_chanid;
+	void __iomem *cd_chanid;
 	unsigned char *tchanid, ctemp;
 #ifndef PCMCIA
 	unsigned char t_irq=0;
@@ -428,7 +429,7 @@ static int __devinit ibmtr_probe1(struct
 	 */
 #ifdef PCMCIA
 	iounmap(t_mmio);
-	t_mmio = (void *)ti->mmio;	/*BMS to get virtual address */
+	t_mmio = ti->mmio;	/*BMS to get virtual address */
 	irq = ti->irq;		/*BMS to display the irq!   */
 #endif
 	cd_chanid = (CHANNEL_ID + t_mmio);	/* for efficiency */
@@ -515,7 +516,7 @@ static int __devinit ibmtr_probe1(struct
 		if (intr == 3) irq = 11;
 		ti->global_int_enable = 0;
 		ti->adapter_int_enable = 0;
-		ti->sram_virt=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12;
+		ti->sram_phys=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12;
 		break;
 	case TR_ISAPNP:
 		if (!t_irq) {
@@ -533,7 +534,7 @@ static int __devinit ibmtr_probe1(struct
 			kfree(ti);
 			return -ENODEV;
 		}
-		ti->sram_virt =
+		ti->sram_phys =
 		     ((__u32)readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_EVEN)<<12);
 		ti->adapter_int_enable = PIOaddr + ADAPTINTREL;
 		break;
@@ -542,7 +543,7 @@ static int __devinit ibmtr_probe1(struct
 
 	if (ibmtr_debug_trace & TRC_INIT) {	/* just report int */
 		DPRINTK("irq=%d", irq);
-		printk(", sram_virt=0x%x", ti->sram_virt);
+		printk(", sram_phys=0x%x", ti->sram_phys);
 		if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */
 			DPRINTK(", ti->mmio=%p", ti->mmio);
 			printk(", segment=%02X", segment);
@@ -681,7 +682,7 @@ static int __devinit ibmtr_probe1(struct
 			ibmtr_mem_base = chk_base;
 		}
 	}
-	else  ti->sram_base = ti->sram_virt >> 12;
+	else  ti->sram_base = ti->sram_phys >> 12;
 
 	/* The PCMCIA has already got the interrupt line and the io port, 
 	   so no chance of anybody else getting it - MLP */
@@ -893,7 +894,7 @@ static int tok_open(struct net_device *d
 	*/
 	dev->flags &= ~IFF_RUNNING;
 
-	ti->sram_virt &= ~1; /* to reverse what we do in tok_close */
+	ti->sram_phys &= ~1; /* to reverse what we do in tok_close */
 	/* init the spinlock */
 	spin_lock_init(&ti->lock);
 	init_timer(&ti->tr_timer);
@@ -1068,7 +1069,7 @@ static int tok_close(struct net_device *
 	/* unloading the module from memory, and then if a timer pops, ouch */
 	del_timer_sync(&ti->tr_timer);
 	outb(0, dev->base_addr + ADAPTRESET);
-	ti->sram_virt |= 1;
+	ti->sram_phys |= 1;
 	ti->open_status = CLOSED;
 
 	netif_stop_queue(dev);
@@ -1094,30 +1095,33 @@ static char *printerror[]={"Function fai
 		"IMPL force received","Duplicate modifier",
 		"No monitor detected","Monitor contention failed for RPL"};
 
-void dir_open_adapter (struct net_device *dev) {
+static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page)
+{
+	if (ti->page_mask) {
+		*page = (index >> 8) & ti->page_mask;
+		index &= ~(ti->page_mask << 8);
+	}
+	return ti->sram_virt + index;
+}
 
+void dir_open_adapter (struct net_device *dev)
+{
         struct tok_info *ti = (struct tok_info *) dev->priv;
         unsigned char ret_code;
         __u16 err;
 
-        ti->srb = ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST));
-        ti->ssb = ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST));
-        ti->arb = ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST));
-        ti->asb = ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST));
-        if (ti->page_mask) {
-                ti->srb_page = (ti->srb >> 8) & ti->page_mask;
-                ti->srb &= ~(ti->page_mask << 8);
-                ti->ssb_page = (ti->ssb >> 8) & ti->page_mask;
-                ti->ssb &= ~(ti->page_mask << 8);
-                ti->arb_page = (ti->arb >> 8) & ti->page_mask;
-                ti->arb &= ~(ti->page_mask << 8);
-                ti->asb_page = (ti->asb >> 8) & ti->page_mask;
-                ti->asb &= ~(ti->page_mask << 8);
-        }
-        ti->srb += ti->sram_virt;
-        ti->ssb += ti->sram_virt;
-        ti->arb += ti->sram_virt;
-        ti->asb += ti->sram_virt;
+        ti->srb = map_address(ti,
+		ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST)),
+		&ti->srb_page);
+        ti->ssb = map_address(ti,
+		ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST)),
+		&ti->ssb_page);
+        ti->arb = map_address(ti,
+		ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST)),
+		&ti->arb_page);
+        ti->asb = map_address(ti,
+		ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST)),
+		&ti->asb_page);
         ti->current_skb = NULL;
         ret_code = readb(ti->init_srb + RETCODE_OFST);
         err = ntohs(readw(ti->init_srb + OPEN_ERROR_CODE_OFST));
@@ -1188,7 +1192,7 @@ irqreturn_t tok_interrupt(int irq, void 
 	DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
 #endif
 	ti = (struct tok_info *) dev->priv;
-	if (ti->sram_virt & 1)
+	if (ti->sram_phys & 1)
 		return IRQ_NONE;         /* PCMCIA card extraction flag */
 	spin_lock(&(ti->lock));
 #ifdef ENABLE_PAGING
@@ -1220,15 +1224,11 @@ irqreturn_t tok_interrupt(int irq, void 
 
 	if (status & ADAP_CHK_INT) {
 		int i;
-		__u32 check_reason;
+		void __iomem *check_reason;
 		__u8 check_reason_page = 0;
-		check_reason =
-			ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN));
-		if (ti->page_mask) {
-			check_reason_page = (check_reason >> 8) & ti->page_mask;
-			check_reason &= ~(ti->page_mask << 8);
-		}
-		check_reason += ti->sram_virt;
+		check_reason = map_address(ti,
+			ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN)),
+			&check_reason_page);
 		SET_PAGE(check_reason_page);
 
 		DPRINTK("Adapter check interrupt\n");
@@ -1517,23 +1517,20 @@ static void initial_tok_int(struct net_d
 	/* we assign the shared-ram address for ISA devices */
 	writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
 #ifndef PCMCIA
-        ti->sram_virt = (u32)ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram);
+        ti->sram_virt = ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram);
 #endif
-	ti->init_srb = ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN));
-	if (ti->page_mask) {
-		ti->init_srb_page = (ti->init_srb >> 8) & ti->page_mask;
-		ti->init_srb &= ~(ti->page_mask << 8);
-	}
-	ti->init_srb += ti->sram_virt;
+	ti->init_srb = map_address(ti,
+		ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN)),
+		&ti->init_srb_page);
 	if (ti->page_mask && ti->avail_shared_ram == 127) {
-		int last_512 = 0xfe00, i;
-		int last_512_page=0;
-		last_512_page=(last_512>>8)&ti->page_mask;
-		last_512 &= ~(ti->page_mask << 8);
+		void __iomem *last_512;
+		__u8 last_512_page=0;
+		int i;
+		last_512 = map_address(ti, 0xfe00, &last_512_page);
 		/* initialize high section of ram (if necessary) */
 		SET_PAGE(last_512_page);
 		for (i = 0; i < 512; i++)
-			writeb(0, ti->sram_virt + last_512 + i);
+			writeb(0, last_512 + i);
 	}
 	SET_PAGE(ti->init_srb_page);
 
@@ -1542,7 +1539,7 @@ static void initial_tok_int(struct net_d
 	int i;
 
 	DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page);
-	DPRINTK("init_srb(%x):", (ti->init_srb) );
+	DPRINTK("init_srb(%p):", ti->init_srb );
 	for (i = 0; i < 20; i++)
 		printk("%02X ", (int) readb(ti->init_srb + i));
 	printk("\n");
@@ -1579,6 +1576,7 @@ static void tr_tx(struct net_device *dev
 	struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
 	unsigned int hdr_len;
 	__u32 dhb=0,dhb_base;
+	void __iomem *dhbuf = NULL;
 	unsigned char xmit_command;
 	int i,dhb_len=0x4000,src_len,src_offset;
 	struct trllc *llc;
@@ -1600,7 +1598,7 @@ static void tr_tx(struct net_device *dev
 		dhb_page = (dhb_base >> 8) & ti->page_mask;
 		dhb=dhb_base & ~(ti->page_mask << 8);
 	}
-	dhb += ti->sram_virt;
+	dhbuf = ti->sram_virt + dhb;
 
 	/* Figure out the size of the 802.5 header */
 	if (!(trhdr->saddr[0] & 0x80))	/* RIF present? */
@@ -1626,12 +1624,12 @@ static void tr_tx(struct net_device *dev
 		writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST);
 		writeb(0x0e, ti->asb + HEADER_LENGTH_OFST);
 		SET_PAGE(dhb_page);
-		writeb(AC, dhb);
-		writeb(LLC_FRAME, dhb + 1);
+		writeb(AC, dhbuf);
+		writeb(LLC_FRAME, dhbuf + 1);
 		for (i = 0; i < TR_ALEN; i++)
-			writeb((int) 0x0FF, dhb + i + 2);
+			writeb((int) 0x0FF, dhbuf + i + 2);
 		for (i = 0; i < TR_ALEN; i++)
-			writeb(0, dhb + i + TR_ALEN + 2);
+			writeb(0, dhbuf + i + TR_ALEN + 2);
 		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
 		return;
 	}
@@ -1650,10 +1648,10 @@ static void tr_tx(struct net_device *dev
 			dhb=dhb & ~(ti->page_mask << 8);
 			dhb_len=0x4000-dhb; /* remaining size of this page */
 		}
-		dhb+=ti->sram_virt;
+		dhbuf = ti->sram_virt + dhb;
 		SET_PAGE(dhb_page);
 		if (src_len > dhb_len) {
-			memcpy_toio(dhb,&ti->current_skb->data[src_offset],
+			memcpy_toio(dhbuf,&ti->current_skb->data[src_offset],
 					dhb_len);
 			src_len -= dhb_len;
 			src_offset += dhb_len;
@@ -1661,7 +1659,7 @@ static void tr_tx(struct net_device *dev
 			dhb=dhb_base;
 			continue;
 		}
-		memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len);
+		memcpy_toio(dhbuf, &ti->current_skb->data[src_offset], src_len);
 		break;
 	}
 	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
@@ -1689,9 +1687,9 @@ static void tr_tx(struct net_device *dev
 static void tr_rx(struct net_device *dev)
 {
 	struct tok_info *ti = (struct tok_info *) dev->priv;
-	__u32 rbuffer, rbufdata;
+	__u32 rbuffer;
+	void __iomem *rbuf, *rbufdata, *llc;
 	__u8 rbuffer_page = 0;
-	__u32 llc;
 	unsigned char *data;
 	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
 	unsigned char dlc_hdr_len;
@@ -1705,11 +1703,7 @@ static void tr_rx(struct net_device *dev
 	SET_PAGE(ti->arb_page);
 	memcpy_fromio(&rarb, ti->arb, sizeof(rarb));
 	rbuffer = ntohs(rarb.rec_buf_addr) ;
-	if (ti->page_mask) {
-		rbuffer_page = (rbuffer >> 8) & ti->page_mask;
-		rbuffer &= ~(ti->page_mask << 8);
-	}
-	rbuffer += ti->sram_virt;
+	rbuf = map_address(ti, rbuffer, &rbuffer_page);
 
 	SET_PAGE(ti->asb_page);
 
@@ -1728,7 +1722,7 @@ static void tr_rx(struct net_device *dev
 	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
 
 	SET_PAGE(rbuffer_page);
-	llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
+	llc = rbuf + offsetof(struct rec_buf, data) + lan_hdr_len;
 
 #if TR_VERBOSE
 	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
@@ -1759,9 +1753,7 @@ static void tr_rx(struct net_device *dev
 
 	if (!IPv4_p) {
 
-		__u32 trhhdr;
-
-		trhhdr = (rbuffer + offsetof(struct rec_buf, data));
+		void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data);
 
 		DPRINTK("Probably non-IP frame received.\n");
 		DPRINTK("ssap: %02X dsap: %02X "
@@ -1793,8 +1785,8 @@ static void tr_rx(struct net_device *dev
 	skb_put(skb, length);
 	skb->dev = dev;
 	data = skb->data;
-	rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
-	rbufdata = rbuffer + offsetof(struct rec_buf, data);
+	rbuffer_len = ntohs(readw(rbuf + offsetof(struct rec_buf, buf_len)));
+	rbufdata = rbuf + offsetof(struct rec_buf, data);
 
 	if (IPv4_p) {
 		/* Copy the headers without checksumming */
@@ -1822,20 +1814,16 @@ static void tr_rx(struct net_device *dev
 			    data,length<rbuffer_len?length:rbuffer_len,chksum);
 		else
 			memcpy_fromio(data, rbufdata, rbuffer_len);
-		rbuffer = ntohs(readw(rbuffer+BUFFER_POINTER_OFST)) ;
+		rbuffer = ntohs(readw(rbuf+BUFFER_POINTER_OFST)) ;
 		if (!rbuffer)
 			break;
 		rbuffer -= 2;
 		length -= rbuffer_len;
 		data += rbuffer_len;
-		if (ti->page_mask) {
-			rbuffer_page = (rbuffer >> 8) & ti->page_mask;
-			rbuffer &= ~(ti->page_mask << 8);
-		}
-		rbuffer += ti->sram_virt;
+		rbuf = map_address(ti, rbuffer, &rbuffer_page);
 		SET_PAGE(rbuffer_page);
-		rbuffer_len = ntohs(readw(rbuffer + BUFFER_LENGTH_OFST));
-		rbufdata = rbuffer + offsetof(struct rec_buf, data);
+		rbuffer_len = ntohs(readw(rbuf + BUFFER_LENGTH_OFST));
+		rbufdata = rbuf + offsetof(struct rec_buf, data);
 	}
 
 	SET_PAGE(ti->asb_page);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1927,7 +1927,7 @@ bad_srom:
 	goto fill_defaults;
 }
 
-static int __devinit de_init_one (struct pci_dev *pdev,
+static int __init de_init_one (struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
 	struct net_device *dev;
@@ -2102,7 +2102,7 @@ static void __exit de_remove_one (struct
 
 #ifdef CONFIG_PM
 
-static int de_suspend (struct pci_dev *pdev, u32 state)
+static int de_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct de_private *de = dev->priv;
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -2124,6 +2124,7 @@ static struct eisa_driver de4x5_eisa_dri
                 .remove  = __devexit_p (de4x5_eisa_remove),
         }
 };
+MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
 #endif
 
 #ifdef CONFIG_PCI
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -26,7 +26,7 @@ unsigned int tulip_max_interrupt_work;
 #define MIT_SIZE 15
 #define MIT_TABLE 15 /* We use 0 or max */
 
-unsigned int mit_table[MIT_SIZE+1] =
+static unsigned int mit_table[MIT_SIZE+1] =
 {
         /*  CRS11 21143 hardware Mitigation Control Interrupt
             We use only RX mitigation we other techniques for
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -88,7 +88,7 @@ int tulip_mdio_read(struct net_device *d
 		value = ioread32(ioaddr + CSR9);
 		iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9);
 		
-		value = (phy_id << 21) | (location << 16) | 0x80000000;
+		value = (phy_id << 21) | (location << 16) | 0x08000000;
 		iowrite32(value, ioaddr + CSR10);
 		
 		while(--i > 0) {
@@ -166,7 +166,7 @@ void tulip_mdio_write(struct net_device 
 		value = ioread32(ioaddr + CSR9);
 		iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9);
 		
-		value = (phy_id << 21) | (location << 16) | 0x40000000 | (val & 0xFFFF);
+		value = (phy_id << 21) | (location << 16) | 0x04000000 | (val & 0xFFFF);
 		iowrite32(value, ioaddr + CSR10);
 		
 		while(--i > 0) {
@@ -174,6 +174,7 @@ void tulip_mdio_write(struct net_device 
 				break;
 		}
 		spin_unlock_irqrestore(&tp->mii_lock, flags);
+		return;
 	}
 		
 	/* Establish sync by sending 32 logic ones. */
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -476,7 +476,7 @@ static inline void tulip_stop_rxtx(struc
 
 		if (!i)
 			printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
-					tp->pdev->slot_name);
+					pci_name(tp->pdev));
 	}
 }
 
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1102,15 +1102,18 @@ static void set_rx_mode(struct net_devic
 			entry = tp->cur_tx++ % TX_RING_SIZE;
 
 			if (entry != 0) {
-				/* Avoid a chip errata by prefixing a dummy entry. */
-				tp->tx_buffers[entry].skb = NULL;
-				tp->tx_buffers[entry].mapping = 0;
-				tp->tx_ring[entry].length =
-					(entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
-				tp->tx_ring[entry].buffer1 = 0;
-				/* Must set DescOwned later to avoid race with chip */
-				dummy = entry;
-				entry = tp->cur_tx++ % TX_RING_SIZE;
+				/* Avoid a chip errata by prefixing a dummy entry. Don't do
+				   this on the ULI526X as it triggers a different problem */
+				if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) {
+					tp->tx_buffers[entry].skb = NULL;
+					tp->tx_buffers[entry].mapping = 0;
+					tp->tx_ring[entry].length =
+						(entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
+					tp->tx_ring[entry].buffer1 = 0;
+					/* Must set DescOwned later to avoid race with chip */
+					dummy = entry;
+					entry = tp->cur_tx++ % TX_RING_SIZE;
+				}
 			}
 
 			tp->tx_buffers[entry].skb = NULL;
@@ -1749,7 +1752,7 @@ err_out_free_netdev:
 
 #ifdef CONFIG_PM
 
-static int tulip_suspend (struct pci_dev *pdev, u32 state)
+static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1620,7 +1620,7 @@ static void __devexit w840_remove1 (stru
  * Detach must occur under spin_unlock_irq(), interrupts from a detached
  * device would cause an irq storm.
  */
-static int w840_suspend (struct pci_dev *pdev, u32 state)
+static int w840_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -1655,7 +1655,7 @@ MODULE_DEVICE_TABLE(pci, xircom_pci_tabl
 
 
 #ifdef CONFIG_PM
-static int xircom_suspend(struct pci_dev *pdev, u32 state)
+static int xircom_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct xircom_private *tp = netdev_priv(dev);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -226,22 +226,26 @@ static __inline__ ssize_t tun_get_user(s
 {
 	struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
 	struct sk_buff *skb;
-	size_t len = count;
+	size_t len = count, align = 0;
 
 	if (!(tun->flags & TUN_NO_PI)) {
-		if ((len -= sizeof(pi)) > len)
+		if ((len -= sizeof(pi)) > count)
 			return -EINVAL;
 
 		if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
 			return -EFAULT;
 	}
+
+	if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV)
+		align = NET_IP_ALIGN;
  
-	if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
+	if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
 		tun->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 
-	skb_reserve(skb, 2);
+	if (align)
+		skb_reserve(skb, align);
 	if (memcpy_fromiovec(skb_put(skb, len), iv, len))
 		return -EFAULT;
 
@@ -843,7 +847,7 @@ static struct ethtool_ops tun_ethtool_op
 	.set_rx_csum	= tun_set_rx_csum
 };
 
-int __init tun_init(void)
+static int __init tun_init(void)
 {
 	int ret = 0;
 
@@ -856,7 +860,7 @@ int __init tun_init(void)
 	return ret;
 }
 
-void tun_cleanup(void)
+static void tun_cleanup(void)
 {
 	struct tun_struct *tun, *nxt;
 
diff --git a/drivers/net/typhoon-firmware.h b/drivers/net/typhoon-firmware.h
--- a/drivers/net/typhoon-firmware.h
+++ b/drivers/net/typhoon-firmware.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2003 3Com Corporation.  All Rights Reserved.    
+ * Copyright 1999-2004 3Com Corporation.  All Rights Reserved.    
  *
  * Redistribution and use in source and binary forms of the 3c990img.h
  * microcode software are permitted provided that the following conditions
@@ -31,14 +31,15 @@
  * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
  */ 
 
-const u8 typhoon_firmware_image[] = {
+ /* ver 03.001.008 */
+static const u8 typhoon_firmware_image[] = {
 0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00, 
-0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xcd, 0x57, 0xc3, 
-0xba, 0x01, 0x2c, 0xe8, 0xcd, 0xef, 0xa9, 0xd9, 0x6f, 0xbb, 0x76, 0x2f, 
-0x86, 0x49, 0xac, 0x1b, 0x40, 0x01, 0x00, 0x00, 0x8a, 0xe4, 0x00, 0x00, 
+0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4, 
+0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13, 
+0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00, 
 0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea, 
 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, 
-0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc0, 0x14, 0x00, 0xea, 
+0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea, 
 0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1, 
 0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea, 
 0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1, 
@@ -50,7 +51,7 @@ const u8 typhoon_firmware_image[] = {
 0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 
 0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 
 0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 
-0x6c, 0xd0, 0x9f, 0xe5, 0x96, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3, 
+0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3, 
 0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 
 0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb, 
 0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3, 
@@ -58,21 +59,21 @@ const u8 typhoon_firmware_image[] = {
 0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1, 
 0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb, 
 0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea, 
-0x01, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00, 
+0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00, 
 0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80, 
 0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, 
-0xad, 0xde, 0xad, 0xde, 0x5c, 0xbc, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40, 
-0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0x8d, 0xd2, 0x21, 0x40, 
+0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40, 
+0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40, 
 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x44, 0x57, 0x00, 0x00, 0x71, 0xaf, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff, 
-0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x00, 0x25, 0x20, 0x68, 0x00, 0x28, 
-0x1d, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x71, 0xfd, 0x21, 0x68, 
-0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x14, 0xd0, 0x38, 0x01, 0x0d, 0x49, 
+0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff, 
+0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28, 
+0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68, 
+0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49, 
 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29, 
-0x0b, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x20, 0x68, 0xc1, 0x69, 0xc0, 0x46, 
-0x21, 0x60, 0x39, 0x07, 0x41, 0x60, 0xc7, 0x62, 0xb0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x28, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0xe8, 0x17, 0x00, 0x80, 
+0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46, 
+0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80, 
 0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 
 0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47, 
 0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
@@ -91,7 +92,7 @@ const u8 typhoon_firmware_image[] = {
 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0, 
 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3, 
 0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63, 
-0x04, 0x49, 0x05, 0xf0, 0xf7, 0xfa, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc, 
+0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00, 
 0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2, 
 0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc, 
@@ -104,7 +105,7 @@ const u8 typhoon_firmware_image[] = {
 0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2, 
 0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 
-0x38, 0x6b, 0x02, 0xf0, 0x23, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xde, 0xfa, 
+0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa, 
 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49, 
 0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18, 
 0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 
@@ -333,8 +334,8 @@ const u8 typhoon_firmware_image[] = {
 0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43, 
 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42, 
 0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 
-0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xd0, 0xf8, 0x38, 0x1c, 0x01, 0xf0, 
-0x8b, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49, 
+0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0, 
+0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49, 
 0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18, 
 0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7, 
 0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 
@@ -370,7 +371,7 @@ const u8 typhoon_firmware_image[] = {
 0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30, 
 0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc, 
 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 
-0x1c, 0xad, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31, 
+0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31, 
 0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32, 
 0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18, 
 0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, 
@@ -381,7 +382,7 @@ const u8 typhoon_firmware_image[] = {
 0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30, 
 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c, 
 0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c, 
-0x01, 0xf0, 0xf8, 0xff, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23, 
+0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23, 
 0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 
 0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8, 
 0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43, 
@@ -398,7 +399,7 @@ const u8 typhoon_firmware_image[] = {
 0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18, 
 0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a, 
 0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0, 
-0x29, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69, 
+0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69, 
 0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58, 
 0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28, 
 0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 
@@ -419,7 +420,7 @@ const u8 typhoon_firmware_image[] = {
 0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a, 
 0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b, 
 0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69, 
-0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x1c, 0xf9, 0x28, 0x6b, 0x79, 0x69, 
+0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69, 
 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b, 
 0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50, 
 0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00, 
@@ -429,7 +430,7 @@ const u8 typhoon_firmware_image[] = {
 0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28, 
 0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a, 
 0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0, 
-0x5d, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98, 
+0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98, 
 0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28, 
 0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 
 0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60, 
@@ -470,10 +471,10 @@ const u8 typhoon_firmware_image[] = {
 0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20, 
 0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1, 
 0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd, 
-0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x66, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc, 
+0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00, 
 0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80, 
-0x1c, 0xad, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80, 
+0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80, 
 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48, 
 0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31, 
 0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22, 
@@ -485,7 +486,7 @@ const u8 typhoon_firmware_image[] = {
 0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46, 
 0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46, 
 0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a, 
-0x01, 0xf0, 0x28, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 
+0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 
 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
 0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a, 
@@ -546,7 +547,7 @@ const u8 typhoon_firmware_image[] = {
 0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61, 
 0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b, 
 0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83, 
-0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xb8, 0xf8, 
+0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8, 
 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 
 0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20, 
 0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30, 
@@ -555,1331 +556,1331 @@ const u8 typhoon_firmware_image[] = {
 0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0, 
 0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
 0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69, 
-0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0x9e, 0xfc, 
-0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x50, 0xf8, 
+0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc, 
+0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8, 
 0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80, 
-0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x00, 0x25, 
-0x00, 0x28, 0x03, 0xd1, 0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xc4, 0x23, 0x48, 0x68, 0x18, 0x40, 0x01, 0x24, 0x00, 0x28, 0x03, 0xd1, 
-0x38, 0x6a, 0x00, 0xf0, 0x09, 0xfc, 0x2f, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 
-0x19, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x78, 0xfa, 0xb8, 0x68, 0xc0, 0x08, 
-0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xce, 0xfb, 0xb8, 0x68, 0x39, 0x6a, 
-0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60, 0x0f, 0x48, 
-0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29, 0x09, 0xd1, 
-0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 
-0x41, 0x60, 0x00, 0xf0, 0x11, 0xf8, 0x0b, 0xe0, 0x39, 0x6a, 0xc0, 0x46, 
-0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68, 0xc0, 0x46, 
-0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c, 0xc0, 0xe7, 
-0x6c, 0x06, 0x00, 0x80, 0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 
-0x0f, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 
-0x60, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
-0xc3, 0xfb, 0x00, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 
-0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 
-0xfe, 0x1d, 0x49, 0x36, 0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 
-0x33, 0x4c, 0x34, 0x4b, 0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 
-0x2a, 0x1c, 0x00, 0xf0, 0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 
-0x69, 0x43, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 
-0x00, 0x04, 0x00, 0x0c, 0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 
-0xc0, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 
-0x09, 0x7b, 0xea, 0x1d, 0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 
-0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 
-0x05, 0x31, 0x00, 0x20, 0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 
-0x06, 0x28, 0xfa, 0xd3, 0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 
-0x09, 0x18, 0x78, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 
-0x61, 0x89, 0xe2, 0x88, 0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 
-0xfe, 0xf7, 0x64, 0xff, 0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43, 
-0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x5c, 0xff, 0x01, 0x22, 0x52, 0x04, 
-0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 
-0xfe, 0xf7, 0x54, 0xff, 0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 
-0x4f, 0xff, 0x01, 0x20, 0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 
-0xea, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0xd9, 0xe7, 0x98, 0xad, 0x20, 0x40, 
-0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
-0x54, 0x00, 0x03, 0x00, 0x84, 0xad, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 
-0xf0, 0xb5, 0x83, 0xb0, 0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 
-0x51, 0x62, 0x01, 0x21, 0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 
-0xc1, 0x1d, 0x19, 0x31, 0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 
-0x00, 0x68, 0x03, 0xf0, 0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 
-0xfc, 0x1d, 0x49, 0x34, 0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 
-0x44, 0x4a, 0x92, 0x6a, 0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 
-0x9b, 0x07, 0xea, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 
-0x2b, 0x43, 0x1d, 0x68, 0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 
-0x3c, 0x4d, 0x01, 0x2b, 0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 
-0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 
-0xc5, 0xfc, 0x20, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 
-0x41, 0x18, 0x00, 0x20, 0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 
-0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 
-0x69, 0x46, 0x00, 0x20, 0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 
-0x01, 0x30, 0x06, 0x28, 0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 
-0x11, 0x0a, 0x29, 0xd3, 0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 
-0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 
-0x49, 0x00, 0xc9, 0x19, 0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 
-0x00, 0x21, 0x4d, 0x00, 0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 
-0x06, 0x29, 0xf8, 0xd3, 0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 
-0x00, 0x9d, 0x55, 0x40, 0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 
-0x89, 0x6a, 0x08, 0x18, 0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 
-0x51, 0x40, 0x41, 0x65, 0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 
-0x0d, 0xd0, 0x38, 0x1c, 0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 
-0x08, 0x4a, 0x50, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 
-0x00, 0xf0, 0xa4, 0xfa, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 
-0x01, 0xf0, 0xde, 0xfa, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 
-0x4c, 0x2a, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 
-0x08, 0x83, 0x20, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 
-0x58, 0x23, 0x5a, 0x43, 0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 
-0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 
-0x43, 0x68, 0x1c, 0x04, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 
-0x33, 0x43, 0x1b, 0x68, 0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 
-0xff, 0x26, 0x36, 0x02, 0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 
-0x74, 0xd1, 0x6b, 0x0c, 0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 
+0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24, 
+0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1, 
+0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e, 
+0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40, 
+0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c, 
+0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68, 
+0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68, 
+0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60, 
+0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29, 
+0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46, 
+0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a, 
+0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68, 
+0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c, 
+0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
+0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c, 
+0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68, 
+0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00, 
+0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36, 
+0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b, 
+0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 
+0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18, 
+0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 
+0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d, 
+0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d, 
+0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30, 
+0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 
+0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3, 
+0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68, 
+0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88, 
+0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff, 
+0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43, 
+0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04, 
+0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff, 
+0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20, 
+0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32, 
+0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00, 
+0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 
+0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0, 
+0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21, 
+0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31, 
+0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0, 
+0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34, 
+0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a, 
+0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d, 
+0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68, 
+0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b, 
+0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 
+0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78, 
+0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20, 
+0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30, 
+0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20, 
+0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28, 
+0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3, 
+0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 
+0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19, 
+0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00, 
+0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3, 
+0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40, 
+0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18, 
+0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65, 
+0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c, 
+0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68, 
+0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa, 
+0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa, 
+0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 
+0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 
+0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43, 
+0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07, 
+0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04, 
+0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68, 
+0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02, 
+0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c, 
+0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 
 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89, 
-0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 
-0x01, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 
-0x33, 0x43, 0x1b, 0x68, 0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 
-0x05, 0x2c, 0xf0, 0xd3, 0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 
-0xde, 0x1d, 0x1d, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 
-0x00, 0x9e, 0x76, 0x18, 0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 
-0x06, 0xe0, 0x00, 0x23, 0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 
-0x0c, 0x60, 0x23, 0x1c, 0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 
-0x1b, 0x79, 0x10, 0x33, 0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 
-0x0f, 0x89, 0xdb, 0x1b, 0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
-0x35, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 
-0x9b, 0x07, 0xd4, 0x1d, 0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
-0x0b, 0x64, 0xab, 0x0e, 0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
-0x3d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 
-0x9b, 0x07, 0xd4, 0x1d, 0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
-0x8b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 
-0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
-0x41, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 
-0x0f, 0xe0, 0xfb, 0x1f, 0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 
-0xff, 0x18, 0x03, 0x69, 0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 
-0x2c, 0xe0, 0x00, 0x23, 0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 
-0x8b, 0x80, 0x0b, 0x81, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 
-0x4b, 0x81, 0x7b, 0x00, 0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 
-0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 
-0x05, 0x28, 0xf2, 0xd3, 0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 
-0x1d, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 
-0xbb, 0x62, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 
-0x3b, 0x0c, 0x18, 0xd2, 0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 
-0x52, 0x6d, 0xc0, 0x46, 0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 
-0x02, 0x61, 0xd8, 0x68, 0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 
-0x48, 0x80, 0x18, 0x69, 0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 
-0xc8, 0x80, 0x80, 0xbc, 0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 
-0x1a, 0x43, 0xc2, 0x60, 0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 
-0x01, 0x61, 0xf2, 0xe7, 0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 
-0x00, 0x22, 0x08, 0x98, 0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 
-0x02, 0xd3, 0x01, 0x27, 0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 
-0x00, 0x2b, 0x19, 0xd0, 0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 
-0x63, 0x43, 0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 
-0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 
-0x1f, 0x43, 0x07, 0xe0, 0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23, 
+0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18, 
+0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 
+0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 
+0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36, 
+0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18, 
+0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23, 
+0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c, 
+0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33, 
+0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b, 
+0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e, 
+0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23, 
+0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
+0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f, 
+0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69, 
+0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23, 
+0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81, 
+0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 
+0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00, 
+0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 
+0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3, 
+0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23, 
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30, 
+0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2, 
+0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46, 
+0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68, 
+0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69, 
+0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc, 
+0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60, 
+0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7, 
+0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98, 
+0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27, 
+0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0, 
+0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18, 
+0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 
+0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0, 
+0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23, 
 0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b, 
-0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 
-0x58, 0x23, 0x63, 0x43, 0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 
-0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 
-0x0f, 0x43, 0x07, 0xe0, 0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 
-0x1f, 0x43, 0x01, 0xe0, 0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 
-0x07, 0x91, 0x4b, 0x89, 0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 
-0x08, 0x9d, 0x2d, 0x68, 0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 
-0x1a, 0xd3, 0x1a, 0x1c, 0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 
-0x92, 0x89, 0xc0, 0x46, 0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 
-0x02, 0x86, 0x04, 0x87, 0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 
-0x19, 0x71, 0x08, 0x9b, 0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 
-0x1b, 0x04, 0x1b, 0x0c, 0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 
-0x07, 0x9b, 0x5b, 0x89, 0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 
-0x07, 0x9b, 0x9b, 0x89, 0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 
-0x2e, 0x1c, 0x55, 0x00, 0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 
-0x01, 0xd0, 0xc3, 0x8a, 0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 
-0xc0, 0x46, 0xab, 0x83, 0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 
+0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 
+0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 
+0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0, 
+0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0, 
+0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89, 
+0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68, 
+0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c, 
+0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46, 
+0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87, 
+0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b, 
+0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 
+0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89, 
+0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89, 
+0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00, 
+0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a, 
+0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83, 
+0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23, 
+0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07, 
+0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31, 
+0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 
+0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b, 
+0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 
+0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33, 
+0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07, 
+0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b, 
+0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07, 
+0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95, 
+0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46, 
+0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43, 
+0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00, 
+0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b, 
+0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e, 
+0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 
+0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40, 
+0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c, 
+0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78, 
+0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3, 
+0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00, 
+0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33, 
+0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93, 
 0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 
-0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 
-0x01, 0xd1, 0x08, 0x31, 0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 
-0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 
-0x24, 0x0c, 0x05, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 
-0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 
-0x2b, 0x78, 0x02, 0x33, 0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 
-0xbb, 0x08, 0x9b, 0x07, 0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 
-0x19, 0x72, 0x01, 0x9b, 0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 
-0x1b, 0x68, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 
-0x33, 0x73, 0x00, 0x95, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 
-0x04, 0x9d, 0xc0, 0x46, 0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 
-0x1b, 0x02, 0x1d, 0x43, 0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 
-0x2b, 0x43, 0x55, 0x00, 0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 
-0x59, 0x72, 0x04, 0x9b, 0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 
-0x6b, 0x73, 0x33, 0x8e, 0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 
-0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 
-0x04, 0x25, 0x3d, 0x40, 0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 
-0xb3, 0x83, 0x13, 0x1c, 0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 
-0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 
-0x3b, 0x09, 0x37, 0xd3, 0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 
-0x03, 0x8b, 0x55, 0x00, 0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 
-0x03, 0x93, 0x20, 0x33, 0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 
-0x1b, 0x18, 0x02, 0x93, 0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 
-0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 
+0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 
 0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0, 
-0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 
-0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 
-0x02, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 
-0x10, 0x3b, 0x9b, 0x7b, 0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 
-0x07, 0x9b, 0xc0, 0x46, 0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 
-0x19, 0x70, 0x07, 0x61, 0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 
-0x1b, 0x18, 0x99, 0x83, 0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 
-0xff, 0xff, 0x00, 0x00, 0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 
-0x12, 0x48, 0x01, 0x68, 0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 
-0x00, 0x90, 0x78, 0x68, 0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 
-0x02, 0x90, 0x0d, 0x48, 0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 
-0x38, 0x1c, 0x00, 0xf0, 0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 
-0x10, 0x23, 0x02, 0x98, 0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 
-0xe1, 0xff, 0x68, 0x46, 0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
-0x00, 0xb5, 0x8c, 0xb0, 0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 
-0x05, 0x4b, 0x19, 0x43, 0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 
-0x02, 0xf0, 0x84, 0xfe, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xa0, 0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 
-0x40, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 
-0x90, 0x80, 0xc8, 0x68, 0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 
-0x10, 0x81, 0x88, 0x68, 0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 
-0x90, 0x73, 0x08, 0x69, 0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 
-0x08, 0x68, 0x00, 0x28, 0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 
-0x0a, 0x60, 0xfa, 0xe7, 0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 
-0xc0, 0x46, 0xc2, 0x60, 0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 
-0xb0, 0xb4, 0x00, 0x22, 0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 
-0x03, 0x23, 0xfc, 0x1d, 0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 
-0x0e, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 
-0x10, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 
-0xc0, 0x46, 0xfb, 0x62, 0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 
-0x99, 0x60, 0x58, 0x60, 0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 
-0x10, 0x1c, 0x38, 0x64, 0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 
-0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 
-0x40, 0x01, 0x18, 0x00, 0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 
-0x47, 0x4d, 0x07, 0x23, 0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 
-0x20, 0x6b, 0x01, 0x30, 0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 
-0x43, 0x48, 0x41, 0x69, 0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 
-0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 
-0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 
-0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe, 
+0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1, 
+0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46, 
+0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 
+0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46, 
+0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61, 
+0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83, 
+0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 
+0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68, 
+0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68, 
+0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48, 
+0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98, 
+0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46, 
+0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0, 
+0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 
+0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe, 
+0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 
+0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46, 
+0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68, 
+0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68, 
+0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69, 
+0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28, 
+0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7, 
+0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60, 
+0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22, 
+0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d, 
+0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68, 
+0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68, 
+0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62, 
+0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60, 
+0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64, 
+0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
+0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00, 
+0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23, 
+0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30, 
+0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69, 
+0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 
+0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 
+0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe, 
 0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29, 
-0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 
-0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 
-0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 
-0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 
-0x02, 0x28, 0x2f, 0xd1, 0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 
-0x00, 0x28, 0x03, 0xd0, 0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 
-0x30, 0x7b, 0x00, 0x28, 0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 
-0x1b, 0x23, 0xdb, 0x01, 0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 
-0xe0, 0x6a, 0xb0, 0x42, 0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 
-0x19, 0x28, 0x11, 0xd3, 0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 
-0xff, 0x30, 0x41, 0x30, 0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 
-0x02, 0xf0, 0x90, 0xff, 0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 
-0x00, 0x20, 0xf8, 0x60, 0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 
-0x79, 0x34, 0xe0, 0x6b, 0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 
-0x07, 0xfc, 0x02, 0x23, 0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 
-0x01, 0x30, 0x38, 0x60, 0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 
-0xa0, 0x82, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 
-0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 
-0xb0, 0xb4, 0x1d, 0x48, 0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 
-0x09, 0x31, 0x01, 0x27, 0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 
-0xa3, 0x42, 0x10, 0xd0, 0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 
-0x00, 0x2b, 0x0a, 0xd0, 0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 
-0x13, 0x4b, 0xc0, 0x46, 0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 
-0x93, 0x82, 0xc3, 0x8b, 0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 
-0x0e, 0xdb, 0x84, 0x8a, 0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 
-0x44, 0x8a, 0xc5, 0x8a, 0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 
-0x4f, 0x70, 0x43, 0x82, 0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 
-0x51, 0x82, 0x80, 0x8a, 0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 
-0xe8, 0x0e, 0x00, 0x80, 0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 
-0xf7, 0xb5, 0x91, 0xb0, 0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 
-0x1a, 0xd9, 0x00, 0x20, 0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 
-0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 
-0x05, 0x20, 0x87, 0x00, 0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 
-0x0f, 0x1c, 0xbf, 0x00, 0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 
-0x00, 0x0e, 0x10, 0x28, 0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 
-0x63, 0x58, 0xc0, 0x46, 0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 
-0x06, 0x28, 0xf6, 0xd3, 0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 
-0xa0, 0x72, 0x20, 0x73, 0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 
-0x69, 0x46, 0x8e, 0x1c, 0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 
-0x14, 0x39, 0x0d, 0x06, 0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 
-0xf0, 0x19, 0x10, 0xa9, 0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0, 
+0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0, 
+0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31, 
+0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1, 
+0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0, 
+0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28, 
+0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01, 
+0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42, 
+0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3, 
+0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30, 
+0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff, 
+0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60, 
+0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b, 
+0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23, 
+0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60, 
+0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80, 
+0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48, 
+0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27, 
+0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0, 
+0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0, 
+0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46, 
+0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b, 
+0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a, 
+0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a, 
+0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82, 
+0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a, 
+0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80, 
+0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0, 
+0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20, 
+0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06, 
+0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00, 
+0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00, 
+0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 
+0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46, 
+0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3, 
+0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73, 
+0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c, 
+0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06, 
+0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9, 
+0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0, 
 0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22, 
-0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 
-0x00, 0x0e, 0x10, 0xa9, 0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 
-0x00, 0x78, 0x38, 0x18, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 
-0x68, 0x46, 0xe2, 0x1d, 0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 
-0x08, 0xd0, 0x8b, 0x00, 0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 
-0x09, 0x06, 0x09, 0x0e, 0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 
-0x4b, 0x1c, 0x08, 0xd0, 0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 
-0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 
-0x70, 0x47, 0x80, 0xb4, 0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 
-0x01, 0x27, 0x01, 0x2a, 0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 
-0xc0, 0x46, 0x08, 0x70, 0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 
-0x01, 0x31, 0x01, 0x72, 0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 
-0x03, 0xd0, 0x06, 0x2a, 0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 
-0x80, 0xbc, 0x70, 0x47, 0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 
-0x00, 0xb5, 0x0f, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 
-0x1a, 0x09, 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 
-0x91, 0x61, 0x19, 0x1c, 0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 
-0xdb, 0x01, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 
-0x61, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 
-0x41, 0x80, 0xf8, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 
-0xe0, 0x82, 0x20, 0x40, 0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 
-0x95, 0x4a, 0xd0, 0x68, 0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 
-0x38, 0x89, 0x00, 0x28, 0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 
-0x99, 0x43, 0x01, 0x60, 0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 
-0x8e, 0x48, 0xc3, 0x6b, 0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 
-0xdb, 0x01, 0xd4, 0x18, 0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 
-0x81, 0x42, 0x05, 0xd1, 0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0xf3, 0xe0, 0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 
-0x01, 0x20, 0x00, 0x21, 0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 
-0x58, 0x70, 0xb9, 0x82, 0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 
-0x05, 0x93, 0x5b, 0x69, 0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 
-0xc0, 0x46, 0x39, 0x61, 0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 
-0x4b, 0x68, 0x1e, 0x0c, 0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 
-0x05, 0xd1, 0x3b, 0x2a, 0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 
-0x01, 0xd9, 0xa8, 0x73, 0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 
-0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 
-0x01, 0x31, 0x09, 0x04, 0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 
-0x09, 0x06, 0x09, 0x0e, 0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 
-0x43, 0x6a, 0xc0, 0x46, 0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 
-0xc2, 0x1d, 0x11, 0x32, 0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 
-0xb3, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20, 
+0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9, 
+0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18, 
+0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d, 
+0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00, 
+0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e, 
+0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0, 
+0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06, 
+0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4, 
+0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a, 
+0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70, 
+0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72, 
+0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a, 
+0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47, 
+0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48, 
+0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61, 
+0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c, 
+0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 
+0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc, 
+0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40, 
+0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68, 
+0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28, 
+0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 
+0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b, 
+0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18, 
+0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1, 
+0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0, 
+0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21, 
+0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82, 
+0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69, 
+0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61, 
+0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c, 
+0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a, 
+0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73, 
+0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04, 
+0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e, 
+0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46, 
+0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32, 
+0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43, 
+0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20, 
 0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b, 
-0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 
-0x01, 0x20, 0x09, 0x01, 0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 
-0x65, 0xd1, 0x51, 0x49, 0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 
-0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 
-0x08, 0x60, 0x00, 0xf0, 0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 
-0x22, 0x6a, 0xa3, 0x6b, 0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 
-0x22, 0x6b, 0xc0, 0x46, 0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 
-0x00, 0x22, 0xfa, 0x61, 0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 
-0x01, 0x22, 0x00, 0xe0, 0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 
-0x7a, 0x68, 0xc0, 0x46, 0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 
-0x04, 0xdc, 0xb0, 0x83, 0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 
-0x60, 0x20, 0xb0, 0x83, 0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 
-0x9a, 0x42, 0x03, 0xd8, 0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 
-0x21, 0x6b, 0xc0, 0x46, 0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 
-0x2d, 0x49, 0x78, 0x6b, 0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 
-0xc0, 0x46, 0xfa, 0x60, 0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 
-0xc0, 0x46, 0xb8, 0x61, 0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 
-0x37, 0xf9, 0x04, 0x98, 0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 
-0x78, 0x8a, 0xf1, 0x8b, 0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 
-0x04, 0xe0, 0x38, 0xe0, 0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 
-0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 
-0x09, 0x1a, 0xa2, 0x6b, 0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 
-0x20, 0x62, 0xe8, 0x7b, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 
-0x05, 0x99, 0x48, 0x69, 0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 
-0x73, 0xfa, 0x18, 0x48, 0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 
-0x0a, 0xd1, 0x20, 0x6a, 0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 
-0x88, 0x42, 0x03, 0xd0, 0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x01, 0x20, 0x40, 0x04, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 
-0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 
-0xa8, 0x73, 0xed, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 
-0xa4, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 
-0x55, 0x55, 0x55, 0x55, 0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 
-0xc4, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 
-0x78, 0x6a, 0x40, 0x89, 0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 
-0x02, 0xd1, 0x81, 0x6c, 0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 
-0x49, 0x0b, 0x02, 0xd2, 0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 
-0x41, 0x6a, 0x01, 0x31, 0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 
-0x48, 0x62, 0x38, 0x6b, 0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 
-0xb3, 0xf8, 0x01, 0x20, 0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
-0x18, 0x1a, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 
-0x61, 0x31, 0x0d, 0x1c, 0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89, 
+0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01, 
+0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49, 
+0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30, 
+0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 
+0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b, 
+0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46, 
+0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61, 
+0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0, 
+0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46, 
+0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83, 
+0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83, 
+0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8, 
+0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46, 
+0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b, 
+0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60, 
+0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61, 
+0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98, 
+0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b, 
+0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0, 
+0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0, 
+0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b, 
+0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b, 
+0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69, 
+0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48, 
+0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a, 
+0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0, 
+0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04, 
+0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28, 
+0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 
+0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89, 
+0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c, 
+0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2, 
+0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31, 
+0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b, 
+0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20, 
+0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80, 
+0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c, 
+0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89, 
 0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7, 
-0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 
-0x00, 0x09, 0x1f, 0xd3, 0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 
-0x43, 0x00, 0xcc, 0x5a, 0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 
-0xf3, 0x18, 0x1b, 0x88, 0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 
-0xc0, 0x46, 0x88, 0x61, 0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 
-0x38, 0x1c, 0x00, 0xf0, 0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 
-0x46, 0xe0, 0x01, 0x30, 0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 
-0x5c, 0x18, 0xe4, 0x88, 0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 
-0xf3, 0x18, 0x1b, 0x88, 0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 
-0xd8, 0x42, 0xf0, 0xdc, 0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 
-0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 
-0x7d, 0x63, 0x00, 0x98, 0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 
-0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 
-0x17, 0xd0, 0xfe, 0x1d, 0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 
-0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 
-0x7b, 0xfc, 0x01, 0x28, 0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 
-0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 
-0x01, 0xe0, 0x01, 0x2a, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 
-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 
-0xc0, 0x46, 0x88, 0x61, 0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 
-0x78, 0x6a, 0x40, 0x89, 0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 
-0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 
-0x38, 0x1c, 0x00, 0xf0, 0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 
-0x02, 0xe0, 0x38, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 
-0x01, 0x60, 0x70, 0x47, 0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 
-0x89, 0x08, 0x09, 0x04, 0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 
-0x00, 0x20, 0x00, 0x29, 0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 
-0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 
-0x00, 0x04, 0x00, 0x0c, 0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 
-0xf0, 0xb5, 0xa0, 0xb0, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 
-0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 
-0x19, 0x43, 0x1f, 0x91, 0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 
-0x1e, 0x92, 0x17, 0xab, 0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 
-0x0a, 0x6a, 0x13, 0x43, 0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 
-0x09, 0x0b, 0x22, 0x69, 0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 
-0x39, 0x34, 0x64, 0x8b, 0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 
-0x1c, 0x94, 0x56, 0x1a, 0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 
-0x00, 0x92, 0x01, 0x26, 0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 
-0x32, 0x1c, 0x0b, 0xe0, 0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 
-0xb5, 0x18, 0x00, 0xe0, 0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42, 
+0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3, 
+0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a, 
+0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88, 
+0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, 
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30, 
+0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88, 
+0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88, 
+0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc, 
+0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02, 
+0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98, 
+0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01, 
+0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d, 
+0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 
+0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28, 
+0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01, 
+0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a, 
+0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 
+0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, 
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89, 
+0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08, 
+0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 
+0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 
+0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47, 
+0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04, 
+0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29, 
+0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 
+0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0, 
+0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91, 
+0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab, 
+0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43, 
+0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69, 
+0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b, 
+0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a, 
+0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26, 
+0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0, 
+0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0, 
+0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42, 
 0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43, 
-0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 
-0x01, 0x1d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 
-0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 
-0x09, 0x68, 0x1e, 0x9a, 0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 
-0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 
-0x11, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 
-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 
-0x17, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 
-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 
-0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 
-0x0b, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 
-0xf8, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 
-0x91, 0x42, 0x00, 0xdd, 0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 
-0x01, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 
-0x33, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 
-0xe1, 0x6d, 0x41, 0x18, 0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 
-0x72, 0x6a, 0x02, 0xf0, 0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 
-0xb1, 0x6a, 0x81, 0x42, 0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 
-0x2f, 0x23, 0x9b, 0x01, 0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 
-0x92, 0x00, 0x27, 0x4b, 0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 
-0x4a, 0x08, 0x05, 0xd3, 0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 
-0x01, 0xf0, 0xd6, 0xff, 0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 
-0x0b, 0x78, 0x00, 0x2b, 0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 
-0x1e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 
-0xc3, 0x18, 0x05, 0xce, 0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 
-0xc7, 0xfe, 0x14, 0x48, 0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 
-0x00, 0xd3, 0x25, 0x60, 0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 
-0x3a, 0x6b, 0xc0, 0x46, 0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 
-0x81, 0x68, 0x00, 0x29, 0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 
-0x04, 0xe0, 0x39, 0x6b, 0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 
-0xc0, 0x46, 0xc1, 0x60, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xea, 0x05, 0x00, 0x00, 0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 
-0x68, 0x0e, 0x00, 0x80, 0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 
-0x04, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 
-0xff, 0x25, 0x01, 0x35, 0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 
-0x01, 0x38, 0x78, 0x61, 0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 
-0xc0, 0x46, 0xb8, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 
-0x00, 0xf0, 0x04, 0xfa, 0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 
-0xe9, 0xd1, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 
-0x01, 0x31, 0xc1, 0x71, 0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
-0x28, 0x1b, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40, 
+0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43, 
+0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 
+0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a, 
+0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43, 
+0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43, 
+0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43, 
+0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c, 
+0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c, 
+0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c, 
+0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd, 
+0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d, 
+0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46, 
+0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18, 
+0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0, 
+0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42, 
+0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01, 
+0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b, 
+0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3, 
+0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff, 
+0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b, 
+0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46, 
+0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce, 
+0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48, 
+0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60, 
+0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46, 
+0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29, 
+0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b, 
+0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 
+0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 
+0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 
+0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02, 
+0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35, 
+0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61, 
+0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60, 
+0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa, 
+0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71, 
+0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80, 
+0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40, 
 0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47, 
-0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 
-0x38, 0x68, 0xc0, 0x08, 0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 
-0x01, 0x62, 0x20, 0x30, 0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 
-0xf3, 0xfd, 0x01, 0x23, 0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 
-0x00, 0x68, 0x16, 0x4c, 0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 
-0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 
-0x00, 0xf0, 0x22, 0xf8, 0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 
-0x05, 0xd0, 0x01, 0x21, 0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 
-0xf2, 0xd0, 0x51, 0x21, 0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 
-0x02, 0xd1, 0x60, 0x6b, 0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 
-0x08, 0x60, 0xf7, 0xe7, 0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 
-0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 
-0x09, 0x04, 0x09, 0x0c, 0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 
-0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 
-0x4b, 0x6b, 0x9a, 0x42, 0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 
-0xe8, 0x1a, 0x00, 0x80, 0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 
-0x01, 0xd3, 0x00, 0xf0, 0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xe8, 0x1a, 0x00, 0x80, 0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 
-0x11, 0xd1, 0x0b, 0x49, 0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 
-0x0b, 0xd0, 0x01, 0x20, 0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 
-0x07, 0x48, 0x42, 0x68, 0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 
-0xdf, 0xfd, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 
-0xe1, 0x2c, 0xff, 0xff, 0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 
-0x44, 0x80, 0x20, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 
-0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 
-0x02, 0xf0, 0x4c, 0xfc, 0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 
-0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 
-0x1b, 0x01, 0xf9, 0x18, 0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 
-0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 
-0xf8, 0xb5, 0x37, 0x48, 0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 
-0x35, 0x4d, 0x10, 0x29, 0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 
-0xc1, 0x6c, 0x00, 0x6e, 0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 
-0x00, 0x24, 0x68, 0x6a, 0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 
-0x81, 0x42, 0x2a, 0xd2, 0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 
-0x68, 0x6a, 0xb8, 0x42, 0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 
-0x03, 0xd2, 0xc4, 0x1b, 0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 
-0x30, 0x01, 0x25, 0x49, 0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 
-0x23, 0x48, 0x00, 0x2c, 0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 
-0x09, 0x6e, 0x8c, 0x18, 0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 
-0xe4, 0x1a, 0x1e, 0x4b, 0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18, 
+0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08, 
+0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30, 
+0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23, 
+0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c, 
+0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68, 
+0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8, 
+0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21, 
+0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21, 
+0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b, 
+0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7, 
+0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07, 
+0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 
+0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 
+0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42, 
+0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 
+0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0, 
+0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 
+0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49, 
+0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20, 
+0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68, 
+0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff, 
+0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 
+0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60, 
+0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc, 
+0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0, 
+0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18, 
+0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23, 
+0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48, 
+0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29, 
+0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e, 
+0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a, 
+0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2, 
+0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42, 
+0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b, 
+0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49, 
+0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c, 
+0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18, 
+0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b, 
+0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18, 
 0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31, 
-0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 
-0x52, 0x05, 0x3a, 0x43, 0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 
-0x09, 0x6e, 0x51, 0x18, 0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 
-0x02, 0xf0, 0x4a, 0xfd, 0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 
-0xe9, 0x6a, 0x2a, 0x6b, 0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 
-0xc0, 0x46, 0x04, 0x66, 0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 
-0x68, 0x0e, 0x00, 0x80, 0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 
-0x49, 0x2e, 0xff, 0xff, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 
-0xa0, 0x82, 0x20, 0x40, 0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 
-0xd1, 0x60, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 
-0x01, 0x20, 0x80, 0x02, 0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 
-0x1b, 0x4e, 0x33, 0x23, 0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 
-0x1d, 0xd9, 0x19, 0x4c, 0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 
-0x68, 0x46, 0x00, 0xf0, 0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 
-0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 
-0x01, 0x30, 0x60, 0x73, 0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 
-0x00, 0x68, 0x02, 0xf0, 0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 
-0xe2, 0xd8, 0xbb, 0x23, 0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 
-0x03, 0xd0, 0x00, 0x21, 0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 
-0xe3, 0xfe, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 
-0x08, 0x83, 0x20, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 
-0x90, 0xb4, 0x17, 0x4f, 0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 
-0xcb, 0x68, 0x00, 0x2b, 0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 
-0x9b, 0x01, 0xff, 0x18, 0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 
-0x04, 0x68, 0xc0, 0x46, 0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 
-0x84, 0x68, 0xc0, 0x46, 0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 
-0x1a, 0x65, 0x08, 0x69, 0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 
-0x38, 0x6a, 0xc0, 0x46, 0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 
-0x18, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 
-0xc8, 0x69, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 
-0x06, 0xd0, 0x01, 0x3b, 0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 
-0xca, 0x61, 0x70, 0x47, 0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 
-0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 
-0x01, 0x65, 0xd0, 0x61, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 
-0x06, 0x4a, 0xd1, 0x68, 0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 
-0x01, 0xd0, 0x91, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 
-0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, 
+0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43, 
+0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18, 
+0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd, 
+0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b, 
+0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66, 
+0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80, 
+0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff, 
+0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40, 
+0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23, 
+0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02, 
+0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23, 
+0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c, 
+0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0, 
+0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30, 
+0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73, 
+0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0, 
+0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23, 
+0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21, 
+0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
+0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40, 
+0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f, 
+0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b, 
+0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18, 
+0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46, 
+0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46, 
+0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69, 
+0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46, 
+0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc, 
+0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23, 
+0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b, 
+0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47, 
+0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29, 
+0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61, 
+0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68, 
+0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69, 
+0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00, 
+0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, 
 0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a, 
-0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 
-0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 
-0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 
-0x03, 0x2b, 0x02, 0xd0, 0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 
-0x04, 0x29, 0xe4, 0xd3, 0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 
-0xf7, 0xb5, 0x86, 0xb0, 0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 
-0x03, 0x1c, 0x14, 0x6a, 0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 
-0x77, 0x40, 0xcf, 0x40, 0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 
-0xa3, 0x40, 0x00, 0x25, 0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 
-0x5d, 0xd9, 0x1c, 0x1c, 0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 
-0x33, 0x1c, 0x03, 0x96, 0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 
-0xc0, 0x46, 0x01, 0x92, 0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 
-0x05, 0x9c, 0xe3, 0x40, 0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 
-0xca, 0x40, 0x14, 0x1c, 0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 
-0xd2, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 
-0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 
-0x9b, 0x07, 0xd6, 0x1d, 0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 
-0x1e, 0x40, 0x00, 0x96, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 
-0x33, 0x43, 0x1b, 0x68, 0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 
-0xd6, 0x1d, 0x4d, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 
-0x12, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 
-0x12, 0x0c, 0x08, 0x9b, 0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 
-0x20, 0x04, 0x00, 0x14, 0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 
-0x01, 0x2a, 0xf7, 0xd0, 0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 
-0x00, 0x27, 0x04, 0x9a, 0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 
-0xc0, 0x43, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 
-0x68, 0x69, 0x00, 0x28, 0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 
-0x2b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 
-0xa0, 0x68, 0x23, 0x4f, 0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 
-0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 
-0xfd, 0xf7, 0xe8, 0xfe, 0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 
-0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 
-0x38, 0x79, 0x00, 0x28, 0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 
-0x01, 0x20, 0xa0, 0x60, 0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 
-0x68, 0x68, 0x00, 0x28, 0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 
-0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 
-0xa6, 0x60, 0xfd, 0xf7, 0xc3, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 
-0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 
-0xbd, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 
-0x6c, 0x06, 0x00, 0x80, 0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 
-0x8c, 0x06, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
+0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23, 
+0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07, 
+0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0, 
+0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3, 
+0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0, 
+0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a, 
+0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40, 
+0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25, 
+0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c, 
+0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96, 
+0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92, 
+0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40, 
+0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c, 
+0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 
+0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 
+0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96, 
+0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68, 
+0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36, 
+0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23, 
+0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b, 
+0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14, 
+0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0, 
+0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a, 
+0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28, 
+0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f, 
+0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 
+0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe, 
+0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 
+0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28, 
+0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60, 
+0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28, 
+0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28, 
+0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7, 
+0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 
+0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79, 
+0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 
+0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80, 
+0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 
-0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 
-0x89, 0x00, 0x18, 0x4a, 0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 
-0xc0, 0x46, 0x79, 0x65, 0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 
-0xfa, 0x6c, 0x89, 0x18, 0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 
-0x3b, 0x6d, 0xd2, 0x18, 0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 
-0x51, 0x71, 0x79, 0x6d, 0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 
-0xfc, 0xf7, 0xd4, 0xff, 0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 
-0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 
-0x01, 0xf0, 0xc6, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 
-0xf0, 0xb5, 0x40, 0x20, 0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 
-0x59, 0xfc, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 
-0x06, 0x0f, 0x70, 0x01, 0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 
-0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 
-0x80, 0x6f, 0x05, 0x1d, 0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 
-0x89, 0xf9, 0x38, 0x1c, 0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 
-0x20, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 
-0x5c, 0x2b, 0x00, 0x80, 0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 
-0xcf, 0x63, 0x05, 0x68, 0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 
-0x9c, 0x00, 0x2e, 0x59, 0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 
-0x01, 0x33, 0x9c, 0x42, 0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 
-0x1d, 0x1c, 0x0f, 0x1c, 0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 
-0xf9, 0x1d, 0x51, 0x31, 0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 
-0x67, 0xfc, 0xf8, 0x6d, 0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 
-0x43, 0x7b, 0x1b, 0x02, 0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 
-0x0b, 0x0a, 0x43, 0x73, 0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x56, 0xfc, 
-0xb8, 0x6d, 0xc0, 0x46, 0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 
-0x40, 0x09, 0x20, 0xd2, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 
-0x01, 0xf0, 0xcc, 0xfc, 0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 
-0x20, 0x1c, 0x01, 0xf0, 0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 
-0x3d, 0x64, 0x7d, 0x64, 0x20, 0x1c, 0xfc, 0xf7, 0x3b, 0xff, 0x38, 0x88, 
-0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 
-0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 
-0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 
-0x78, 0x64, 0x60, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 
-0xc1, 0x1d, 0x0d, 0x31, 0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 
-0x0e, 0xe0, 0x41, 0x19, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 
-0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 
-0x09, 0x0c, 0x81, 0x42, 0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 
+0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68, 
+0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a, 
+0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65, 
+0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18, 
+0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18, 
+0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d, 
+0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff, 
+0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 
+0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
+0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20, 
+0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c, 
+0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01, 
+0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46, 
+0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d, 
+0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c, 
+0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 
+0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68, 
+0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59, 
+0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42, 
+0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c, 
+0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31, 
+0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d, 
+0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02, 
+0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73, 
+0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46, 
+0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2, 
+0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc, 
+0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0, 
+0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64, 
+0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 
+0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c, 
+0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 
+0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68, 
+0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31, 
+0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19, 
+0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 
+0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42, 
+0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 
+0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61, 
+0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b, 
+0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0, 
+0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62, 
+0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c, 
+0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 
+0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18, 
+0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9, 
+0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 
+0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8, 
+0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 
+0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68, 
+0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c, 
+0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 
+0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 
 0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61, 
 0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b, 
-0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 
-0x20, 0x1c, 0x00, 0xf0, 0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 
-0x00, 0x25, 0x78, 0x62, 0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 
-0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
-0x01, 0x00, 0x00, 0xc0, 0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 
-0xf9, 0x6b, 0x0d, 0x18, 0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 
-0x00, 0x2a, 0x0b, 0xd9, 0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 
-0x33, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 
-0x82, 0x42, 0xf3, 0xd8, 0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 
-0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 
-0xf9, 0x61, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 
-0x01, 0x68, 0x78, 0x6c, 0xfc, 0xf7, 0x9f, 0xff, 0x78, 0x64, 0x60, 0x68, 
-0x01, 0x04, 0x09, 0x0c, 0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 
-0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 
-0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 
-0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 
-0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0xb9, 0x68, 0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 
-0x38, 0x1c, 0x00, 0xf0, 0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 
-0x01, 0xf8, 0xef, 0xe7, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 
-0x8e, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 
-0x61, 0x68, 0x08, 0x40, 0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 
-0x11, 0x18, 0xfb, 0x68, 0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 
-0x05, 0x3b, 0x38, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 
-0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 
-0x01, 0x04, 0x09, 0x0c, 0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 
-0x7d, 0x4e, 0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 
-0x19, 0xd0, 0x00, 0x25, 0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 
-0x00, 0x28, 0x12, 0xd0, 0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 
-0xd2, 0x18, 0xd2, 0x68, 0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 
-0x01, 0x35, 0xa8, 0x00, 0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 
-0xc0, 0x68, 0x00, 0x28, 0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 
-0xfa, 0x63, 0xfa, 0x68, 0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 
-0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c, 0xfc, 0xf7, 0x1a, 0xff, 0x03, 0x90, 
-0xf9, 0x6b, 0x3a, 0x6e, 0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 
-0x7a, 0x6e, 0x8d, 0x18, 0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 
-0xe0, 0x60, 0xb1, 0x88, 0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 
-0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 
-0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 
-0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 
-0x38, 0x61, 0xa8, 0x89, 0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61, 
+0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c, 
+0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68, 
+0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 
+0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7, 
+0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69, 
+0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40, 
+0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68, 
+0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 
+0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c, 
+0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c, 
+0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23, 
+0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25, 
+0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0, 
+0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68, 
+0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00, 
+0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28, 
+0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68, 
+0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 
+0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e, 
+0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18, 
+0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88, 
+0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04, 
+0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 
+0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 
+0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89, 
+0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61, 
 0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46, 
-0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 
-0x70, 0x81, 0x68, 0x60, 0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 
-0xf2, 0xfe, 0x38, 0x86, 0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 
-0x0d, 0xff, 0x78, 0x86, 0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 
-0xd2, 0xfe, 0x00, 0x90, 0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 
-0x41, 0x1a, 0x09, 0x04, 0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 
-0x1b, 0x0c, 0x1a, 0x02, 0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 
-0xba, 0x68, 0x82, 0x42, 0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 
-0xb8, 0x60, 0x08, 0x02, 0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 
-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 
-0xfc, 0xf7, 0xad, 0xfe, 0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 
-0xa8, 0xfe, 0x06, 0x1c, 0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 
-0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 
-0x81, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0x99, 0xfe, 0x79, 0x69, 0x01, 0x31, 
-0xc0, 0x43, 0x79, 0x61, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 
-0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 
-0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 
-0x01, 0x43, 0x30, 0x1c, 0xfc, 0xf7, 0x81, 0xfe, 0x39, 0x69, 0x7a, 0x68, 
-0x89, 0x18, 0x39, 0x61, 0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 
-0x89, 0x89, 0xba, 0x69, 0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 
-0xb9, 0x69, 0xfc, 0xf7, 0x70, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 
-0xf8, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 
-0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 
-0x21, 0x68, 0xc0, 0x46, 0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 
-0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 
-0xc0, 0x46, 0x88, 0x81, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x0c, 0x2b, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 
-0x6e, 0x4d, 0x28, 0x69, 0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 
-0x28, 0x61, 0x04, 0x98, 0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 
-0x69, 0x49, 0x44, 0x18, 0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 
-0x00, 0x28, 0x01, 0xd1, 0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 
-0x01, 0x31, 0x41, 0x61, 0x04, 0x98, 0xfc, 0xf7, 0x13, 0xfd, 0x07, 0x1c, 
-0x03, 0xd1, 0x28, 0x69, 0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 
-0x65, 0x68, 0xa8, 0x42, 0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 
-0x16, 0xd2, 0x40, 0x1a, 0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 
-0xa6, 0x60, 0xa6, 0x62, 0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 
-0x0d, 0x1c, 0x09, 0xd1, 0x38, 0x1c, 0xfc, 0xf7, 0x23, 0xfd, 0x03, 0x20, 
-0x60, 0x80, 0x66, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 
-0xe1, 0x68, 0x38, 0x68, 0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 
-0x02, 0x39, 0x2a, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 
-0xd7, 0xf9, 0xe0, 0x68, 0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 
-0x04, 0x98, 0x31, 0x1c, 0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98, 
+0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60, 
+0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86, 
+0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86, 
+0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90, 
+0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04, 
+0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02, 
+0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42, 
+0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02, 
+0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 
+0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe, 
+0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c, 
+0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43, 
+0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c, 
+0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61, 
+0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22, 
+0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 
+0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c, 
+0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61, 
+0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69, 
+0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7, 
+0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08, 
+0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04, 
+0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 
+0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 
+0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81, 
+0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 
+0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69, 
+0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98, 
+0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18, 
+0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1, 
+0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 
+0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69, 
+0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42, 
+0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a, 
+0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62, 
+0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1, 
+0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60, 
+0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68, 
+0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c, 
+0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68, 
+0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c, 
+0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98, 
 0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e, 
-0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 
-0x12, 0x0a, 0x11, 0x43, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 
-0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 
-0x41, 0x80, 0x20, 0x8e, 0xfc, 0xf7, 0xd5, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 
-0x02, 0x99, 0xfc, 0xf7, 0xd0, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 
-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 
-0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xc1, 0xfd, 
-0x61, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 
-0x48, 0x81, 0x60, 0x6e, 0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 
-0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 
-0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 
-0x71, 0x60, 0x03, 0x98, 0xfc, 0xf7, 0xa5, 0xfd, 0x21, 0x69, 0x49, 0x19, 
-0x21, 0x61, 0xa1, 0x68, 0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 
-0xa2, 0x69, 0x11, 0x43, 0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x97, 0xfd, 
-0x38, 0x82, 0x61, 0x6e, 0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 
-0xe2, 0x68, 0x00, 0x99, 0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 
-0x78, 0x82, 0xe0, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 
-0x78, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 
-0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 
-0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 
-0x39, 0x68, 0xc0, 0x46, 0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 
-0x0c, 0x2b, 0x00, 0x80, 0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 
-0x1c, 0x68, 0x26, 0x04, 0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x5b, 0xfd, 
-0x40, 0xc7, 0x02, 0x9a, 0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 
-0x02, 0x92, 0x00, 0x29, 0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 
-0x0a, 0x43, 0x11, 0x1c, 0x16, 0x1c, 0xfc, 0xf7, 0x4a, 0xfd, 0x40, 0xc7, 
-0x02, 0x99, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 
-0x89, 0x00, 0x03, 0x32, 0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 
-0x08, 0xc9, 0x08, 0xc0, 0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 
-0x70, 0x47, 0xff, 0xb5, 0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 
-0x80, 0x6c, 0xc0, 0x1b, 0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 
-0xc0, 0x05, 0x06, 0x99, 0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 
-0x4c, 0x6b, 0x67, 0xe0, 0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 
-0xc0, 0x46, 0x03, 0x91, 0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 
-0x49, 0x88, 0xb9, 0x42, 0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 
-0x49, 0x88, 0x7f, 0x1a, 0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 
-0x02, 0xa9, 0x49, 0x88, 0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 
-0x00, 0x27, 0x01, 0x21, 0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 
-0x0d, 0xd0, 0xeb, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 
-0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a, 
+0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43, 
+0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43, 
+0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e, 
+0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7, 
+0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 
+0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 
+0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31, 
+0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e, 
+0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 
+0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 
+0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98, 
+0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68, 
+0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43, 
+0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e, 
+0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99, 
+0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d, 
+0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38, 
+0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 
+0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04, 
+0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 
+0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 
+0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04, 
+0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a, 
+0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 
+0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c, 
+0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e, 
+0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32, 
+0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0, 
+0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5, 
+0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b, 
+0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99, 
+0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0, 
+0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91, 
+0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42, 
+0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a, 
+0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88, 
+0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21, 
+0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06, 
+0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1, 
+0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a, 
 0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c, 
-0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 
-0x07, 0x9b, 0x01, 0xf0, 0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 
-0x00, 0x2e, 0x0a, 0xd0, 0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 
-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 
-0x00, 0x26, 0x02, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 
-0x40, 0x19, 0x03, 0x90, 0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 
-0xc0, 0x46, 0x60, 0x60, 0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 
-0x01, 0x98, 0x01, 0x38, 0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 
-0x44, 0x63, 0x01, 0x98, 0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 
-0x00, 0x2f, 0x02, 0xd0, 0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 
-0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 
-0x09, 0x9b, 0x01, 0xf0, 0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 
-0x04, 0x00, 0x53, 0x02, 0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 
-0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 
-0xfc, 0xf7, 0x8f, 0xfc, 0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 
-0x78, 0x8a, 0x39, 0x68, 0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 
-0x8b, 0xf9, 0x38, 0x1c, 0xfc, 0xf7, 0x96, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 
-0x33, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 
-0x8a, 0x09, 0x21, 0xd3, 0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 
-0x00, 0x21, 0x01, 0x80, 0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 
-0x19, 0x32, 0x51, 0x71, 0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 
-0xc0, 0x46, 0x10, 0x60, 0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 
-0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 
-0x38, 0x1c, 0x00, 0xf0, 0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x80, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 
-0x00, 0xf0, 0xb0, 0xf8, 0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 
-0xf0, 0xb5, 0x07, 0x1c, 0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 
-0x00, 0x2b, 0x19, 0xd0, 0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 
-0x0c, 0x19, 0x41, 0x68, 0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 
-0xb9, 0x60, 0xc1, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 
-0xe9, 0x6a, 0x81, 0x42, 0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 
-0x31, 0x1c, 0x01, 0x3e, 0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 
-0x00, 0x2a, 0x01, 0xd1, 0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 
-0xd0, 0x61, 0x48, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 
-0x03, 0x49, 0x08, 0x68, 0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 
-0x0a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 
-0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 
-0xca, 0x68, 0xc0, 0x46, 0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 
-0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 
-0x82, 0x6f, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80, 
+0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0, 
+0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0, 
+0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8, 
+0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90, 
+0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60, 
+0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38, 
+0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98, 
+0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0, 
+0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92, 
+0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0, 
+0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02, 
+0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07, 
+0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc, 
+0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68, 
+0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c, 
+0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3, 
+0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80, 
+0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71, 
+0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60, 
+0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00, 
+0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0, 
+0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43, 
+0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8, 
+0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 
+0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0, 
+0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68, 
+0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68, 
+0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42, 
+0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e, 
+0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 
+0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60, 
+0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68, 
+0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47, 
+0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68, 
+0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 
+0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 
+0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46, 
+0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80, 
 0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7, 
-0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 
-0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 
-0x89, 0x00, 0x0d, 0x4b, 0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 
-0x11, 0x1c, 0xff, 0xf7, 0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 
-0x02, 0xd1, 0xff, 0xf7, 0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 
-0xff, 0xf7, 0x4e, 0xfb, 0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 
-0x01, 0x65, 0xee, 0xe7, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 
-0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0xff, 0xf7, 0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 
-0x20, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 
-0x01, 0x80, 0x01, 0x88, 0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 
-0x08, 0xbc, 0x18, 0x47, 0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 
-0xf8, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 
-0x98, 0xb5, 0x07, 0x1c, 0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 
-0xc3, 0x1d, 0x41, 0x33, 0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 
-0x00, 0x0b, 0x9c, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 
-0x98, 0x42, 0x00, 0xd1, 0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 
-0x59, 0x1a, 0x41, 0x18, 0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 
-0x00, 0xd8, 0x00, 0x20, 0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 
-0xc0, 0x46, 0x08, 0x60, 0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 
-0x10, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 
-0x03, 0x20, 0x39, 0x6a, 0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 
-0x18, 0x43, 0x38, 0x80, 0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 
-0x38, 0x1c, 0xff, 0xf7, 0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 
-0x55, 0x55, 0x55, 0x55, 0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 
-0x7c, 0x29, 0x00, 0x80, 0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0x00, 0xf0, 0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 
-0x1b, 0x07, 0x18, 0x40, 0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 
-0x26, 0x49, 0x44, 0x18, 0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 
-0x20, 0x88, 0x41, 0x08, 0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 
-0xa0, 0x6c, 0xe1, 0x6c, 0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 
-0xa1, 0x6b, 0x22, 0x6d, 0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 
-0xc0, 0x46, 0x60, 0x65, 0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 
-0x78, 0x60, 0x61, 0x68, 0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 
-0x18, 0x43, 0x78, 0x60, 0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 
-0x78, 0x60, 0x94, 0x20, 0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 
-0x12, 0x0c, 0x20, 0x1c, 0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 
-0x02, 0x20, 0x60, 0x80, 0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xfc, 0xf7, 0x11, 0xfa, 0x28, 0x01, 
-0x06, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 
-0x01, 0x39, 0x41, 0x63, 0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
+0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68, 
+0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b, 
+0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7, 
+0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7, 
+0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb, 
+0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7, 
+0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7, 
+0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43, 
+0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88, 
+0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c, 
+0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33, 
+0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68, 
+0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1, 
+0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18, 
+0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20, 
+0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60, 
+0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46, 
+0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a, 
+0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80, 
+0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7, 
+0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23, 
+0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 
+0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80, 
+0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 
+0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 
+0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18, 
+0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08, 
+0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c, 
+0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d, 
+0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 
+0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68, 
+0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60, 
+0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20, 
+0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c, 
+0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80, 
+0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18, 
+0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 
+0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27, 
-0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 
-0x42, 0x63, 0x00, 0x2a, 0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 
-0xc0, 0x6a, 0x01, 0xf0, 0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 
-0x38, 0x01, 0x00, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 
-0x00, 0x29, 0xe9, 0xd1, 0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
-0x00, 0x00, 0x00, 0xb0, 0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 
-0x0f, 0x49, 0xc8, 0x68, 0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 
-0x02, 0x89, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 
-0x00, 0x2a, 0x0d, 0xd1, 0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 
-0x02, 0x23, 0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 
-0x01, 0x21, 0x00, 0xe0, 0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 
-0x08, 0x83, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 
-0x01, 0x23, 0xf8, 0x1d, 0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 
-0x79, 0x32, 0x54, 0x8a, 0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 
-0xac, 0x42, 0x04, 0xdb, 0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 
-0xd1, 0x83, 0x01, 0x23, 0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 
-0xc0, 0x46, 0xba, 0x61, 0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 
-0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x79, 0x61, 0x41, 0x69, 0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 
-0x00, 0x05, 0xc1, 0x60, 0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 
-0xf9, 0x69, 0x41, 0x1a, 0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 
-0x00, 0xf0, 0x0e, 0xf8, 0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 
-0x81, 0x42, 0xe2, 0xd3, 0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 
-0x0f, 0x1c, 0xff, 0x23, 0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 
-0x21, 0x37, 0xe1, 0x6e, 0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 
-0x00, 0x28, 0x13, 0xd1, 0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 
-0x19, 0x43, 0x01, 0x72, 0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 
-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 
-0x00, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 
-0x20, 0x61, 0x23, 0x49, 0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 
-0x51, 0x18, 0xc0, 0x31, 0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 
-0x89, 0x0f, 0x01, 0x63, 0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 
-0x03, 0xd8, 0x23, 0x22, 0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 
-0x7e, 0x1a, 0x07, 0xd1, 0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 
-0x61, 0x6e, 0x09, 0x18, 0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 
-0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 
-0x2b, 0x1c, 0x01, 0xf0, 0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 
-0x00, 0x92, 0x61, 0x6e, 0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 
-0x73, 0xfc, 0x20, 0x6b, 0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 
-0x81, 0x42, 0x00, 0xd8, 0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7, 
+0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a, 
+0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0, 
+0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19, 
+0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1, 
+0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 
+0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68, 
+0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a, 
+0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1, 
+0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68, 
+0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0, 
+0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d, 
+0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a, 
+0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb, 
+0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23, 
+0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61, 
+0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69, 
+0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60, 
+0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a, 
+0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 
+0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3, 
+0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23, 
+0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e, 
+0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1, 
+0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72, 
+0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49, 
+0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31, 
+0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63, 
+0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22, 
+0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1, 
+0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18, 
+0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92, 
+0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0, 
+0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e, 
+0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b, 
+0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8, 
+0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7, 
 0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80, 
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 
-0xc0, 0x03, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 
-0x49, 0x30, 0x02, 0x7a, 0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 
-0x08, 0x1c, 0xff, 0xf7, 0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 
-0x02, 0x7a, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 
-0x2d, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 
-0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 
-0x10, 0x20, 0x18, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 
-0xf8, 0x60, 0x16, 0x48, 0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 
-0x09, 0x18, 0xc0, 0x31, 0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 
-0x51, 0x64, 0x61, 0x6b, 0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 
-0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 
-0x01, 0x23, 0x78, 0x68, 0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 
-0x80, 0x07, 0x80, 0x0f, 0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 
-0x00, 0x28, 0x02, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 
-0x90, 0xb5, 0x07, 0x1c, 0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 
-0xb8, 0x6a, 0xc0, 0x68, 0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 
-0x78, 0x6f, 0xfc, 0xf7, 0x63, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 
-0xf9, 0x1d, 0x19, 0x31, 0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xf8, 0x6c, 0x2f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 
-0x21, 0x1c, 0x00, 0xf0, 0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 
-0x20, 0x1c, 0x00, 0xf0, 0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 
-0x09, 0x18, 0x09, 0x09, 0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 
-0x89, 0x1a, 0xa1, 0x62, 0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 
-0x00, 0x2a, 0x07, 0xd0, 0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 
-0x80, 0x00, 0xb9, 0x6a, 0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 
-0x80, 0x00, 0xc0, 0x19, 0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 
-0x41, 0x64, 0xb8, 0x6a, 0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 
-0x40, 0x1a, 0xb8, 0x62, 0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 
-0x40, 0x18, 0xb8, 0x62, 0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 
-0x00, 0x29, 0xb8, 0xd1, 0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 
-0x3a, 0x6c, 0x91, 0x42, 0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 
-0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 
-0x00, 0x28, 0x01, 0xd0, 0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 
-0xa1, 0xd0, 0x01, 0x38, 0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 
-0x00, 0x00, 0x00, 0xb0, 0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 
-0x00, 0x20, 0x05, 0x90, 0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 
-0xc0, 0x6a, 0xc0, 0x46, 0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 
-0x49, 0x6b, 0xc0, 0x46, 0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 
-0xc0, 0x46, 0xa8, 0x60, 0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 
-0xf0, 0x48, 0xc0, 0x46, 0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a, 
+0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 
+0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 
+0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a, 
+0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80, 
+0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48, 
+0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31, 
+0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b, 
+0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00, 
+0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68, 
+0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f, 
+0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1, 
+0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 
+0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68, 
+0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7, 
+0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31, 
+0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0, 
+0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0, 
+0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09, 
+0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62, 
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0, 
+0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a, 
+0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19, 
+0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a, 
+0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62, 
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62, 
+0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1, 
+0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42, 
+0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19, 
+0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0, 
+0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38, 
+0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 
+0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90, 
+0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46, 
+0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46, 
+0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60, 
+0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46, 
+0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a, 
 0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46, 
-0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 
-0x91, 0x42, 0x01, 0xd3, 0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 
-0x1e, 0xd2, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 
-0x03, 0x99, 0x01, 0xf0, 0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 
-0xd8, 0x6b, 0x01, 0x30, 0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 
-0x68, 0x60, 0xaf, 0x61, 0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 
-0x01, 0x6d, 0x42, 0x6d, 0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 
-0x38, 0x1c, 0x5c, 0xe3, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 
-0x7b, 0xfc, 0x07, 0x1c, 0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 
-0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 
-0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 
-0x18, 0x40, 0x58, 0xd1, 0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 
-0x88, 0x42, 0x02, 0xd2, 0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 
-0x88, 0x68, 0x00, 0xf0, 0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 
-0x28, 0x1c, 0x39, 0x1c, 0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 
-0x2e, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 
-0x03, 0xd0, 0xc1, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 
-0x00, 0x28, 0x03, 0xd0, 0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 
-0x7a, 0x68, 0xc0, 0x46, 0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 
-0x30, 0x1c, 0xb8, 0x49, 0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 
-0x17, 0xd1, 0x30, 0x1c, 0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 
-0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 
-0x27, 0xfc, 0x07, 0x1c, 0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 
-0x00, 0x20, 0xa8, 0x61, 0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 
-0xb0, 0xe0, 0xa8, 0x69, 0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 
-0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 
-0xa4, 0xe0, 0x10, 0x28, 0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 
-0x18, 0x40, 0x01, 0x0f, 0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 
-0x82, 0x18, 0x01, 0x92, 0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 
-0x2f, 0xd3, 0x9d, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 
-0xc0, 0x46, 0x10, 0x80, 0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 
-0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 
-0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 
-0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 
-0x8f, 0x49, 0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 
-0x50, 0x68, 0x36, 0x30, 0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 
-0x94, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 
-0x58, 0xe0, 0x7a, 0x88, 0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 
-0x03, 0x90, 0x23, 0xe0, 0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 
-0x1d, 0xd0, 0x03, 0x93, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 
-0x50, 0x60, 0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 
-0x01, 0x9a, 0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 
+0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3, 
+0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20, 
+0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0, 
+0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30, 
+0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 
+0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3, 
+0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c, 
+0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07, 
+0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06, 
+0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1, 
+0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2, 
+0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0, 
+0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c, 
+0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68, 
+0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49, 
+0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0, 
+0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46, 
+0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49, 
+0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c, 
+0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a, 
+0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c, 
+0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 
+0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69, 
+0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a, 
+0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28, 
+0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f, 
+0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92, 
+0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48, 
+0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80, 
+0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 
+0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 
+0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18, 
+0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30, 
+0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61, 
+0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88, 
+0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0, 
+0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93, 
+0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68, 
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46, 
+0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 
 0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49, 
-0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 
-0x02, 0xe0, 0x33, 0xe0, 0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 
-0xc0, 0x46, 0x48, 0x71, 0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 
-0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 
-0x00, 0xf0, 0x92, 0xfb, 0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 
-0x09, 0x01, 0x40, 0x18, 0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 
-0x7d, 0xfb, 0x01, 0x9a, 0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 
-0xc0, 0x46, 0x13, 0x65, 0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 
-0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 
-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 
-0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 
-0xa8, 0x69, 0x03, 0x99, 0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 
-0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 
-0x04, 0xd3, 0x30, 0x1c, 0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 
-0x41, 0x49, 0x00, 0x20, 0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 
-0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 
-0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 
-0xaf, 0x61, 0x3a, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 
-0x42, 0x6d, 0x39, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 
-0x15, 0xe2, 0x05, 0x98, 0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 
-0x0c, 0x90, 0x0b, 0x90, 0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 
-0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 
-0x00, 0x26, 0x00, 0x20, 0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 
-0x01, 0x38, 0x0d, 0x90, 0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 
-0x12, 0x0c, 0x90, 0x42, 0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 
-0x00, 0x0c, 0x08, 0x90, 0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 
-0x07, 0xd1, 0x0d, 0x98, 0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 
-0x30, 0x18, 0x88, 0x42, 0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 
-0x1c, 0xe0, 0x11, 0x20, 0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 
-0x18, 0x40, 0x02, 0xd1, 0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 
-0x89, 0x0f, 0x0f, 0xd0, 0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 
-0x1e, 0x28, 0x09, 0xdb, 0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 
-0x01, 0xe0, 0x02, 0x29, 0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 
-0x0a, 0x9a, 0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 
-0x18, 0x43, 0x06, 0x90, 0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 
-0x00, 0x90, 0x04, 0x98, 0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 
-0xed, 0x48, 0xff, 0xff, 0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 
-0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 
-0x60, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 
-0x41, 0x32, 0xff, 0xff, 0x58, 0x5f, 0x21, 0x40, 0xf9, 0x3c, 0xff, 0xff, 
-0xb9, 0x31, 0xff, 0xff, 0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 
-0x06, 0xca, 0x01, 0xf0, 0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98, 
+0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0, 
+0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 
+0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37, 
+0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb, 
+0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18, 
+0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a, 
+0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65, 
+0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 
+0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 
+0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07, 
+0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99, 
+0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c, 
+0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c, 
+0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20, 
+0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 
+0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 
+0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b, 
+0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98, 
+0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90, 
+0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 
+0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20, 
+0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90, 
+0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42, 
+0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90, 
+0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98, 
+0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42, 
+0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20, 
+0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1, 
+0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0, 
+0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb, 
+0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29, 
+0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a, 
+0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 
+0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98, 
+0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff, 
+0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80, 
+0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff, 
+0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff, 
+0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98, 
 0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1, 
-0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 
-0x06, 0x90, 0x06, 0x98, 0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 
-0x83, 0x19, 0xc1, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 
-0x51, 0xf9, 0x00, 0x20, 0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 
-0x0b, 0x9b, 0x01, 0x3b, 0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 
-0x0c, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 
-0x78, 0x68, 0x07, 0x9a, 0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 
-0x80, 0x1a, 0x78, 0x80, 0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 
-0x0a, 0x92, 0x0c, 0x98, 0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 
-0xb1, 0x42, 0x00, 0xd9, 0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 
-0xa8, 0x68, 0x01, 0x09, 0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 
-0x0c, 0x99, 0x0a, 0x9a, 0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 
-0x0c, 0xd0, 0x08, 0x9a, 0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 
-0x06, 0xdb, 0x1e, 0x2a, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 
-0x02, 0x29, 0x02, 0xd2, 0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 
+0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98, 
+0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48, 
+0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20, 
+0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b, 
+0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c, 
+0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a, 
+0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80, 
+0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98, 
+0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9, 
+0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09, 
+0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a, 
+0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a, 
+0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a, 
+0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2, 
+0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 
+0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22, 
+0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d, 
+0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90, 
+0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 
+0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a, 
 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 
-0x06, 0xca, 0x01, 0xf0, 0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 
-0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 
-0x92, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 
-0x8e, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 
-0x00, 0x20, 0x02, 0x90, 0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 
-0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 
-0x00, 0xe0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 
-0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 
-0x36, 0x18, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 
-0x00, 0xf0, 0x14, 0xfa, 0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 
-0x0a, 0x98, 0xc0, 0x46, 0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 
-0x0d, 0x98, 0x09, 0x99, 0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 
-0x5f, 0xe0, 0x5e, 0xe0, 0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 
-0xa9, 0x68, 0x8c, 0x23, 0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 
-0x1a, 0x43, 0xb1, 0x07, 0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 
-0x08, 0xd0, 0x1e, 0x2b, 0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 
-0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 
-0x02, 0x1c, 0x09, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 
-0x1a, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 
-0x06, 0xca, 0x01, 0xf0, 0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 
-0x02, 0x98, 0x00, 0x28, 0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 
-0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 
-0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 
-0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 
-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 
-0x07, 0x1c, 0x09, 0x98, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90, 
+0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37, 
+0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa, 
+0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46, 
+0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99, 
+0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0, 
+0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23, 
+0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07, 
+0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 
+0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 
+0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98, 
+0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28, 
+0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 
+0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 
+0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42, 
+0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98, 
+0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90, 
 0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04, 
-0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 
-0x7b, 0xfa, 0x28, 0xe0, 0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 
-0x68, 0x68, 0x80, 0x0e, 0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 
-0x01, 0x9a, 0x50, 0x6b, 0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 
-0x89, 0xf9, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 
-0xc0, 0x46, 0x93, 0x63, 0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 
-0x5d, 0xfa, 0x68, 0x68, 0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 
-0x05, 0xd9, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 
-0xae, 0x61, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 
-0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 
-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 
-0x9b, 0x07, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 
-0xe1, 0x69, 0x81, 0x42, 0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 
-0x41, 0x1a, 0x01, 0xd5, 0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 
-0x3f, 0xfb, 0xe1, 0x69, 0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 
-0x24, 0xd3, 0x40, 0x1a, 0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 
-0x20, 0x69, 0x02, 0x28, 0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 
-0x41, 0x69, 0xe2, 0x6c, 0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 
-0x99, 0x43, 0x81, 0x61, 0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 
-0xc0, 0x46, 0x08, 0x61, 0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 
-0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 
-0xff, 0xf7, 0xcc, 0xfa, 0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 
-0x05, 0x99, 0x40, 0x18, 0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 
-0x08, 0x60, 0x00, 0xf0, 0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 
-0xa0, 0x6f, 0x00, 0xf0, 0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 
-0x48, 0x71, 0x79, 0x68, 0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 
-0x24, 0x49, 0x40, 0x18, 0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 
-0x01, 0x60, 0x36, 0xe0, 0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 
-0x11, 0x60, 0x20, 0x4e, 0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 
-0x19, 0x43, 0xe9, 0x63, 0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 
-0xb9, 0x6a, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 
-0x04, 0xd1, 0xa9, 0x6b, 0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 
-0xa8, 0x63, 0x01, 0x20, 0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 
-0x40, 0x00, 0xe8, 0x63, 0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 
-0x1b, 0x02, 0xf1, 0x18, 0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 
-0x04, 0xd2, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 
-0x38, 0x1c, 0x00, 0xf0, 0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x10, 0xfc, 
-0x20, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00, 
+0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0, 
+0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e, 
+0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b, 
+0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a, 
+0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63, 
+0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68, 
+0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04, 
+0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68, 
+0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92, 
+0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d, 
+0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42, 
+0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5, 
+0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69, 
+0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a, 
+0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28, 
+0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c, 
+0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61, 
+0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61, 
+0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 
+0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa, 
+0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18, 
+0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 
+0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80, 
+0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 
+0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0, 
+0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68, 
+0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18, 
+0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0, 
+0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e, 
+0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63, 
+0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e, 
+0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b, 
+0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20, 
+0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63, 
+0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18, 
+0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c, 
+0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 
+0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0, 
+0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 
+0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00, 
 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30, 
-0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 
-0x01, 0x71, 0x38, 0x1c, 0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 
-0x0d, 0xd0, 0xb8, 0x68, 0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 
-0x11, 0xd0, 0xb8, 0x6a, 0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 
-0x10, 0x1a, 0x88, 0x42, 0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 
-0xf8, 0xe7, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 
-0xb8, 0x62, 0xf1, 0xe7, 0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 
-0xc0, 0x46, 0x00, 0x90, 0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 
-0xe8, 0x18, 0x80, 0x69, 0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 
-0x52, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 
-0x00, 0xf0, 0x92, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 
-0x40, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 
-0xea, 0xd1, 0x01, 0xe0, 0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 
-0x9d, 0xf9, 0x07, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 
-0x16, 0x49, 0x01, 0xd0, 0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 
-0x0c, 0x22, 0xa4, 0x18, 0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 
-0x1c, 0x22, 0x0b, 0x68, 0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 
-0x00, 0x2d, 0x13, 0xd0, 0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 
-0x5b, 0x06, 0x1a, 0x43, 0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 
-0x00, 0x92, 0x4a, 0x68, 0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 
-0xdf, 0xfe, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 
-0x1a, 0x43, 0xf1, 0xe7, 0x3c, 0xef, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 
-0xf8, 0x0e, 0x00, 0x80, 0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 
-0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 
-0xd0, 0x61, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 
-0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 
-0x8a, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 
-0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 
-0x0a, 0x69, 0x01, 0x3a, 0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 
-0x53, 0x6b, 0xc0, 0x46, 0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 
-0x49, 0x6c, 0x53, 0x6c, 0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 
-0x92, 0x00, 0x52, 0x18, 0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 
-0x3d, 0x30, 0x0a, 0x68, 0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 
-0x9a, 0x1a, 0x02, 0x60, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 
-0xca, 0x68, 0x01, 0x32, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 
-0x40, 0x18, 0x0a, 0x61, 0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 
-0xb8, 0xb5, 0x04, 0x1c, 0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 
-0xff, 0xf7, 0xd9, 0xff, 0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 
-0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 
-0x00, 0x20, 0xa0, 0x61, 0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 
+0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c, 
+0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68, 
+0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a, 
+0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42, 
+0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68, 
+0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7, 
+0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90, 
+0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69, 
+0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23, 
+0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb, 
+0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23, 
+0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 
+0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0, 
+0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18, 
+0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68, 
+0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0, 
+0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43, 
+0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68, 
+0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7, 
+0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80, 
+0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 
+0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60, 
+0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68, 
+0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47, 
+0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 
+0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a, 
+0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46, 
+0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c, 
+0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18, 
+0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68, 
+0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60, 
+0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32, 
+0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61, 
+0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c, 
+0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff, 
+0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d, 
+0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61, 
+0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 
 0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe, 
-0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 
+0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02, 
+0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68, 
+0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 
+0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 
+0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00, 
 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 
 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 
 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
-0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 
-0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 
-0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 
-0xa0, 0x82, 0x20, 0x40, 0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 
-0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 
-0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 
-0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 
-0x01, 0x31, 0x41, 0x71, 0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 
-0x90, 0xb4, 0x82, 0x00, 0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 
-0x89, 0x08, 0x0b, 0x1d, 0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 
-0xd7, 0x68, 0x12, 0x4c, 0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 
-0x03, 0xd1, 0x81, 0x42, 0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 
-0xb9, 0x42, 0x09, 0xd9, 0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 
-0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 
-0x81, 0x42, 0x05, 0xd8, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 
-0x98, 0x42, 0x02, 0xd8, 0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 
-0x05, 0x30, 0xfa, 0xe7, 0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 
-0x0f, 0x4a, 0x17, 0x58, 0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 
-0x01, 0xe0, 0x88, 0x08, 0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 
-0x09, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 
+0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 
+0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 
+0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71, 
+0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00, 
+0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d, 
+0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c, 
+0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42, 
+0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9, 
+0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 
+0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8, 
+0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8, 
+0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7, 
+0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58, 
+0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08, 
+0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68, 
+0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, 
+0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0, 
+0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40, 
+0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40, 
+0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04, 
+0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a, 
+0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68, 
 0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 
-0x38, 0x69, 0x00, 0xf0, 0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 
-0x09, 0x07, 0x01, 0x40, 0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 
-0x92, 0x07, 0x02, 0x40, 0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 
-0x89, 0x0f, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 
-0x01, 0x30, 0x00, 0x2a, 0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 
-0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 
-0xf9, 0x60, 0x81, 0x00, 0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 
-0x0f, 0x48, 0x00, 0x69, 0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 
-0x02, 0xd0, 0x20, 0x1c, 0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 
-0x19, 0x30, 0x03, 0x79, 0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 
-0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 
-0x08, 0x1c, 0xff, 0xf7, 0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x70, 0x04, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 
-0xe4, 0x2c, 0x00, 0x80, 0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 
-0x03, 0xd1, 0x41, 0x68, 0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, 
+0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69, 
+0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c, 
+0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79, 
+0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30, 
+0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7, 
+0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80, 
+0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 
+0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68, 
+0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, 
 0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21, 
-0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 
-0x87, 0x68, 0xbb, 0x0a, 0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 
-0x01, 0x31, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 
-0xf8, 0x00, 0x1d, 0x4c, 0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 
-0x00, 0x79, 0x01, 0x28, 0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 
-0x10, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 
-0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 
-0xc0, 0x18, 0x03, 0x6b, 0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 
-0xdb, 0x00, 0xeb, 0x18, 0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 
-0x01, 0x31, 0x81, 0x63, 0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 
-0x21, 0x60, 0x01, 0x6b, 0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 
-0xdf, 0xe7, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
-0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 
-0x36, 0xd1, 0x00, 0x24, 0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 
-0xb0, 0x60, 0x32, 0x68, 0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 
-0x00, 0xd3, 0xb4, 0x60, 0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 
-0xc0, 0x18, 0x87, 0x6b, 0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 
-0xaa, 0x02, 0x92, 0x19, 0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 
-0xca, 0x6a, 0x09, 0x6b, 0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 
-0xc4, 0x62, 0x00, 0x2f, 0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 
-0xdb, 0x43, 0x37, 0x68, 0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 
-0x43, 0x63, 0x10, 0x1c, 0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 
-0x00, 0x28, 0xc9, 0xd0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 
-0x00, 0x27, 0x2e, 0x4b, 0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 
-0x01, 0x30, 0xd8, 0x62, 0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 
-0x02, 0x69, 0x53, 0x1c, 0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 
-0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 
-0x07, 0x61, 0x0f, 0x29, 0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x08, 0x1c, 0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 
-0x6e, 0x1c, 0xad, 0x00, 0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 
-0x01, 0x35, 0x55, 0x61, 0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 
-0x0f, 0x2d, 0x00, 0xd3, 0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 
-0x3a, 0x6f, 0xfd, 0x68, 0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 
-0xdb, 0x6d, 0x5b, 0x08, 0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 
-0xfd, 0x6f, 0x03, 0x3b, 0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 
-0x0b, 0x81, 0x10, 0x60, 0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 
-0x00, 0xd0, 0x01, 0x38, 0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 
-0x00, 0xd8, 0x07, 0x4a, 0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 
-0x82, 0x61, 0x3a, 0x67, 0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 
-0xa0, 0x1c, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 
+0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a, 
+0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68, 
+0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c, 
+0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28, 
+0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0, 
+0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 
+0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b, 
+0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18, 
+0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 
+0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b, 
+0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00, 
+0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 
+0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24, 
+0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68, 
+0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60, 
+0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b, 
+0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19, 
+0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b, 
+0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f, 
+0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68, 
+0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c, 
+0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 
+0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b, 
+0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62, 
+0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c, 
+0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31, 
+0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29, 
+0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c, 
+0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00, 
+0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61, 
+0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3, 
+0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68, 
+0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08, 
+0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b, 
+0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60, 
+0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38, 
+0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a, 
+0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67, 
+0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 
+0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 
 0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49, 
-0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 
-0x67, 0x69, 0x00, 0x2f, 0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 
-0x00, 0x19, 0xe1, 0x60, 0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 
-0xe0, 0x68, 0x0f, 0x28, 0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 
-0x00, 0x19, 0x80, 0x69, 0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 
-0x67, 0x61, 0x03, 0xe0, 0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 
-0x65, 0x60, 0x20, 0x68, 0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
-0xa0, 0x1c, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 
-0xb0, 0xb4, 0x10, 0x23, 0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 
-0x15, 0xd0, 0x0c, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 
-0x02, 0x68, 0x15, 0x68, 0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 
-0x02, 0x60, 0x20, 0xc2, 0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 
-0x01, 0x23, 0x9b, 0x07, 0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 
-0xb0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 
-0x53, 0x09, 0x34, 0xd3, 0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 
-0x16, 0x43, 0x03, 0x68, 0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 
-0x04, 0x3b, 0x03, 0x60, 0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 
-0x43, 0x68, 0x1f, 0x1d, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 
-0xcb, 0x6b, 0x18, 0x1f, 0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 
-0x1f, 0x1d, 0x03, 0x1d, 0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 
-0x1f, 0x60, 0x1f, 0x1d, 0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 
-0x23, 0x43, 0x3b, 0x60, 0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 
-0x78, 0x60, 0x08, 0x6e, 0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 
-0x48, 0x66, 0x00, 0x20, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 
-0x80, 0xb4, 0x81, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 
-0x1a, 0x43, 0x12, 0x68, 0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 
-0xc0, 0x46, 0xcb, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 
-0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 
-0x1b, 0x68, 0x0c, 0xc1, 0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 
-0x04, 0x23, 0x81, 0x69, 0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 
-0x91, 0x61, 0x81, 0x6a, 0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 
-0x91, 0x62, 0xc1, 0x1d, 0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 
-0x49, 0x8b, 0x02, 0x6b, 0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 
-0xc1, 0x81, 0xc1, 0x68, 0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 
-0x80, 0xbc, 0x70, 0x47, 0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 
-0x20, 0x47, 0x28, 0x47, 0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 
-0x0c, 0xc0, 0x9d, 0xe5, 0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 
-0x1e, 0x00, 0x00, 0x0a, 0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 
-0x64, 0x51, 0x9f, 0xe5, 0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 
-0x14, 0x40, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 
-0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5, 
+0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f, 
+0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60, 
+0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28, 
+0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69, 
+0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0, 
+0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68, 
+0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23, 
+0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b, 
+0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68, 
+0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2, 
+0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07, 
+0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47, 
+0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3, 
+0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68, 
+0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60, 
+0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d, 
+0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f, 
+0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d, 
+0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d, 
+0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60, 
+0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e, 
+0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20, 
+0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a, 
+0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 
+0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60, 
+0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
+0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1, 
+0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69, 
+0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a, 
+0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d, 
+0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b, 
+0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68, 
+0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 
+0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47, 
+0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5, 
+0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a, 
+0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5, 
+0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5, 
+0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 
+0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5, 
 0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, 
-0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 
-0x04, 0x10, 0x90, 0xe5, 0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 
-0x00, 0x00, 0xa0, 0xe3, 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 
-0x00, 0x30, 0x93, 0xe5, 0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 
-0x02, 0x36, 0x83, 0xe3, 0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 
-0xf2, 0xff, 0xff, 0x1a, 0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 
-0x01, 0x06, 0x1c, 0xe3, 0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 
-0x02, 0xc6, 0xcc, 0xe3, 0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 
-0x50, 0x10, 0x91, 0xe5, 0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 
-0x20, 0xc0, 0x9d, 0xe5, 0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 
-0x25, 0x00, 0x00, 0x0a, 0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 
-0x94, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 
-0x04, 0x80, 0x90, 0xe5, 0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 
-0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 
-0x14, 0xa0, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 
-0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 
-0x09, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 
-0x15, 0x00, 0x00, 0x0a, 0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 
-0x20, 0x30, 0x83, 0xe2, 0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 
-0x01, 0x70, 0x87, 0xe2, 0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 
-0x20, 0x00, 0x56, 0xe3, 0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 
-0x01, 0xc0, 0x46, 0xe2, 0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 
-0xe7, 0xff, 0xff, 0xea, 0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 
-0xf0, 0x47, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 
-0x0a, 0x00, 0x55, 0xe1, 0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 
-0x01, 0x10, 0xa0, 0xe3, 0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 
-0x0b, 0x92, 0xa0, 0xe3, 0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 
-0x0e, 0xf0, 0xa0, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
-0x3f, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 
-0x12, 0x00, 0x50, 0xe3, 0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 
-0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 
-0x00, 0x40, 0x99, 0xe5, 0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 
-0x53, 0x00, 0x00, 0x1b, 0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 
-0x20, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 
-0x59, 0x00, 0x00, 0x1b, 0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 
-0x08, 0x00, 0x14, 0xe3, 0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 
-0x4a, 0x00, 0x00, 0x1b, 0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 
-0xe5, 0x0e, 0x14, 0xe3, 0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 
-0x0c, 0x10, 0x98, 0xe5, 0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 
-0x04, 0x30, 0x88, 0xe5, 0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1, 
+0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5, 
+0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 
+0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5, 
+0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3, 
+0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a, 
+0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3, 
+0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3, 
+0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5, 
+0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5, 
+0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a, 
+0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0, 
+0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5, 
+0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3, 
+0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5, 
+0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 
+0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1, 
+0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a, 
+0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2, 
+0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2, 
+0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3, 
+0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2, 
+0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea, 
+0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8, 
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1, 
+0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3, 
+0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 
+0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3, 
+0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1, 
+0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9, 
+0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3, 
+0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5, 
+0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b, 
+0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3, 
+0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 
+0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3, 
+0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b, 
+0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3, 
+0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5, 
+0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5, 
+0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1, 
 0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a, 
-0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 
-0x00, 0x00, 0x14, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 
-0x00, 0x00, 0x14, 0xe1, 0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 
-0x98, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 
-0x02, 0x04, 0x14, 0xe3, 0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 
-0x10, 0xff, 0x2f, 0x11, 0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 
-0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 
-0x00, 0x00, 0x14, 0xe1, 0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 
-0x04, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
-0x02, 0x0a, 0x14, 0xe3, 0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
-0x02, 0x09, 0x14, 0xe3, 0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
-0x01, 0x02, 0x14, 0xe3, 0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
-0x01, 0x04, 0x14, 0xe3, 0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
-0x01, 0x0a, 0x14, 0xe3, 0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 
-0x0e, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 
-0x1c, 0x00, 0x00, 0x1b, 0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 
-0x00, 0x40, 0x94, 0xe2, 0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 
-0x04, 0xf0, 0x5e, 0xe2, 0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 
-0xfa, 0xff, 0xff, 0xea, 0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 
-0x11, 0xff, 0x2f, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 
-0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 
-0x00, 0x00, 0xa0, 0xe3, 0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 
-0x11, 0xff, 0x2f, 0xe1, 0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
-0x2c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 
-0x11, 0xff, 0x2f, 0xe1, 0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
-0xfe, 0xff, 0xff, 0xea, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 
-0x18, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 
-0x3c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
-0x64, 0x20, 0x9f, 0xe5, 0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 
-0x0a, 0x00, 0x00, 0xba, 0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 
-0x08, 0x30, 0x92, 0xe5, 0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 
-0x03, 0x10, 0x80, 0xe7, 0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 
-0x08, 0x30, 0x82, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 
-0x3c, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 
-0x00, 0x00, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 
-0x10, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 
-0x3c, 0x10, 0xa0, 0xb3, 0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
-0xe4, 0x2d, 0x00, 0x80, 0xcc, 0x04, 0x00, 0x80, 0x5d, 0x2b, 0xff, 0xff, 
-0xbd, 0x3d, 0xff, 0xff, 0xb5, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 
-0xc9, 0x1c, 0x89, 0x08, 0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 
-0x18, 0x43, 0x13, 0x68, 0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 
-0x5b, 0x1a, 0x18, 0x47, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 
+0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 
+0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15, 
+0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3, 
+0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 
+0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 
+0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 
+0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3, 
+0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3, 
+0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3, 
+0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3, 
+0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3, 
+0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3, 
+0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b, 
+0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b, 
+0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2, 
+0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, 
+0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea, 
+0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 
+0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea, 
+0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 
+0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5, 
+0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba, 
+0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5, 
+0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7, 
+0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5, 
+0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5, 
+0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5, 
+0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5, 
+0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3, 
+0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80, 
+0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff, 
+0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08, 
+0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68, 
+0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47, 
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
@@ -1921,204 +1922,143 @@ const u8 typhoon_firmware_image[] = {
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
-0x04, 0x20, 0xa0, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80, 
 0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 
-0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 
+0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 
+0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 
+0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5, 
+0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5, 
+0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 
 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 
 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 
-0x78, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 
-0x74, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 
+0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5, 
+0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5, 
 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 
 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 
-0xf8, 0xff, 0xff, 0xea, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 
-0x4c, 0x00, 0x9f, 0xe5, 0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 
-0x2c, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 
-0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 
-0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 
-0x00, 0x20, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 
-0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 
-0xfc, 0x37, 0x00, 0x80, 0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 
-0xfc, 0x3f, 0x00, 0x80, 0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 
-0x78, 0x47, 0x00, 0x00, 0x76, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 
-0x39, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 
-0x78, 0x47, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 
-0x70, 0xea, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x80, 0x28, 0x04, 0x00, 0x00, 0x95, 0x22, 0x00, 0x00, 
-0x00, 0x01, 0x00, 0x80, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xb9, 0x0b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 
-0x03, 0xff, 0x06, 0x54, 0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 
-0x03, 0x00, 0x00, 0x00, 0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0xf1, 0x05, 0xff, 0xff, 0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 
-0x39, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 
-0x01, 0xff, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 
-0x00, 0x00, 0x00, 0x00, 0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0xf1, 0x02, 0xff, 0xff, 0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 
-0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x50, 0xff, 0xff, 
-0x6d, 0x50, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80, 
+0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 
+0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80, 
+0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00, 
+0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea, 
+0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 
+0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 
+0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54, 
+0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00, 
+0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff, 
+0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00, 
+0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 
+0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff, 
+0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff, 
 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x48, 0x05, 0x00, 0x80, 0x19, 0x78, 0x21, 0x40, 
-0x23, 0x78, 0x21, 0x40, 0x39, 0x78, 0x21, 0x40, 0x51, 0x78, 0x21, 0x40, 
-0x5d, 0x78, 0x21, 0x40, 0x6b, 0x78, 0x21, 0x40, 0x85, 0x78, 0x21, 0x40, 
-0xb1, 0x78, 0x21, 0x40, 0x75, 0x79, 0x21, 0x40, 
-0xcd, 0x79, 0x21, 0x40, 0xdb, 0x79, 0x21, 0x40, 0xe5, 0x79, 0x21, 0x40, 
-0xef, 0x79, 0x21, 0x40, 0x8d, 0x7a, 0x21, 0x40, 0x9b, 0x7a, 0x21, 0x40, 
-0xa9, 0x7a, 0x21, 0x40, 0x51, 0x7b, 0x21, 0x40, 0x4f, 0x7f, 0x21, 0x40, 
-0xc9, 0x7f, 0x21, 0x40, 0x69, 0x80, 0x21, 0x40, 0x9d, 0x81, 0x21, 0x40, 
-0xa9, 0x81, 0x21, 0x40, 0x09, 0x82, 0x21, 0x40, 0x6d, 0x82, 0x21, 0x40, 
-0x99, 0x82, 0x21, 0x40, 0xbd, 0x82, 0x21, 0x40, 0xfd, 0x82, 0x21, 0x40, 
-0x25, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0x7d, 0x83, 0x21, 0x40, 
-0xa5, 0x83, 0x21, 0x40, 0xb5, 0x83, 0x21, 0x40, 0xfd, 0x83, 0x21, 0x40, 
-0x3b, 0x84, 0x21, 0x40, 0x91, 0x84, 0x21, 0x40, 0xf1, 0x84, 0x21, 0x40, 
-0xfb, 0x84, 0x21, 0x40, 0xff, 0x84, 0x21, 0x40, 0x6d, 0x85, 0x21, 0x40, 
-0xb9, 0x85, 0x21, 0x40, 0x11, 0x86, 0x21, 0x40, 0x4d, 0x86, 0x21, 0x40, 
-0xb1, 0x86, 0x21, 0x40, 0xe9, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 
-0x31, 0x87, 0x21, 0x40, 0x41, 0x87, 0x21, 0x40, 0x55, 0x87, 0x21, 0x40, 
-0x7d, 0x87, 0x21, 0x40, 0x87, 0x87, 0x21, 0x40, 0x91, 0x87, 0x21, 0x40, 
-0xf5, 0x87, 0x21, 0x40, 0x25, 0x88, 0x21, 0x40, 0x31, 0x88, 0x21, 0x40, 
-0xa5, 0x88, 0x21, 0x40, 0xaf, 0x88, 0x21, 0x40, 0xb9, 0x88, 0x21, 0x40, 
-0xc3, 0x88, 0x21, 0x40, 0xcd, 0x88, 0x21, 0x40, 0xd7, 0x88, 0x21, 0x40, 
-0xe1, 0x88, 0x21, 0x40, 0xeb, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40, 
-0xe9, 0x8b, 0x21, 0x40, 0xff, 0x88, 0x21, 0x40, 0x09, 0x89, 0x21, 0x40, 
-0x13, 0x89, 0x21, 0x40, 0x1d, 0x89, 0x21, 0x40, 0x45, 0x89, 0x21, 0x40, 
-0x4f, 0x89, 0x21, 0x40, 0xb1, 0x89, 0x21, 0x40, 0xbb, 0x89, 0x21, 0x40, 
-0xc5, 0x89, 0x21, 0x40, 0xcf, 0x89, 0x21, 0x40, 0xd9, 0x89, 0x21, 0x40, 
-0xa5, 0x77, 0x21, 0x40, 0xe3, 0x89, 0x21, 0x40, 0x49, 0x8a, 0x21, 0x40, 
-0x95, 0x8a, 0x21, 0x40, 0xe1, 0x8a, 0x21, 0x40, 0xf1, 0x8a, 0x21, 0x40, 
-0xa5, 0x77, 0x21, 0x40, 0x3d, 0x8b, 0x21, 0x40, 0x41, 0x8b, 0x21, 0x40, 
-0x45, 0x8b, 0x21, 0x40, 0x9d, 0x8b, 0x21, 0x40, 0xc5, 0x8b, 0x21, 0x40, 
-0xd1, 0x8b, 0x21, 0x40, 0xd5, 0x8b, 0x21, 0x40, 0xd9, 0x8b, 0x21, 0x40, 
-0xdd, 0x8b, 0x21, 0x40, 0xe1, 0x8b, 0x21, 0x40, 0xe5, 0x8b, 0x21, 0x40, 
-0x0d, 0x88, 0x21, 0x40, 0x69, 0x88, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 
-0xa5, 0x77, 0x21, 0x40, 0xf5, 0x8b, 0x21, 0x40, 0xe1, 0xc9, 0x21, 0x40, 
-0xe9, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 
-0xdd, 0xca, 0x21, 0x40, 0x13, 0xcb, 0x21, 0x40, 0x45, 0xcb, 0x21, 0x40, 
-0x4d, 0x8c, 0x21, 0x40, 0x5b, 0x7b, 0x21, 0x40, 0xe5, 0x7e, 0x21, 0x40, 
-0x21, 0x7f, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 
-0x58, 0x01, 0x18, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 
-0x68, 0x01, 0x18, 0x40, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 
-0x78, 0x01, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40, 
-0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 
-0x0c, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 
-0xa4, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0xa5, 0xb9, 0x21, 0x40, 0x01, 0xbb, 0x21, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0x91, 0x73, 0x21, 0x40, 0x19, 0xb2, 0x21, 0x40, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xa7, 0x99, 0x21, 0x40, 0xa5, 0xb9, 0x21, 0x40, 
-0xb1, 0x2f, 0xff, 0xff, 0xf1, 0x20, 0xff, 0xff, 0xdb, 0x20, 0xff, 0xff, 
-0x2d, 0xb8, 0x21, 0x40, 0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 
-0x5c, 0x2e, 0x00, 0x80, 0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 
-0x00, 0x30, 0x37, 0x2f, 0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 
-0x30, 0x30, 0x31, 0x35, 0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 
-0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 
-0x31, 0x20, 0x33, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 
-0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x00, 0x02, 0x10, 0x00, 0x03, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x78, 0x53, 0xff, 0xff, 0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 
-0xda, 0x0e, 0x82, 0x00, 0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 
-0xe4, 0x2c, 0x00, 0x80, 0x55, 0x3e, 0xff, 0xff, 0xb5, 0x4f, 0xff, 0xff, 
-0xc1, 0x24, 0xff, 0xff, 0xb5, 0x3b, 0xff, 0xff, 0x15, 0x3c, 0xff, 0xff, 
-0x05, 0x1a, 0xff, 0xff, 0x65, 0x11, 0xff, 0xff, 0xb8, 0x53, 0xff, 0xff, 
-0x0d, 0x40, 0xff, 0xff, 0x91, 0x73, 0x21, 0x40, 0x51, 0x75, 0x21, 0x40, 
-0xc5, 0x3f, 0xff, 0xff, 0x71, 0xaa, 0x21, 0x40, 0x71, 0x24, 0xff, 0xff, 
-0x50, 0x53, 0xff, 0xff, 0x78, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0xff, 0xff, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0xec, 0x68, 0x00, 0x00, 
-0x10, 0x5c, 0x00, 0x00, 0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
-0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
-0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
-0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
-0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
-0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 
-0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 
-0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x9a, 0x21, 0x40, 
-0xdb, 0x99, 0x21, 0x40, 0xf5, 0x9c, 0x21, 0x40, 0x55, 0x9d, 0x21, 0x40, 
-0x1d, 0x9e, 0x21, 0x40, 0xdb, 0x9b, 0x21, 0x40, 0xf9, 0x9e, 0x21, 0x40, 
-0x65, 0x9f, 0x21, 0x40, 0xb9, 0x9b, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40, 
+0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40, 
+0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40, 
+0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40, 
+0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40, 
+0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40, 
+0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40, 
+0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40, 
+0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40, 
+0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40, 
+0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40, 
+0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40, 
+0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40, 
+0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40, 
+0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40, 
+0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40, 
+0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40, 
+0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40, 
+0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40, 
+0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40, 
+0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40, 
+0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40, 
+0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40, 
+0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40, 
+0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40, 
+0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 
+0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40, 
+0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 
+0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40, 
+0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40, 
+0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40, 
+0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40, 
+0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 
+0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40, 
+0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 
+0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 
+0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40, 
+0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40, 
+0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40, 
+0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00, 
+0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 
+0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff, 
+0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40, 
+0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80, 
+0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f, 
+0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35, 
+0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 
+0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43, 
+0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 
+0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff, 
+0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00, 
+0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 
+0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff, 
+0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff, 
+0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff, 
+0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff, 
+0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff, 
+0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00, 
+0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40, 
+0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40, 
+0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
-0xe9, 0xd6, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xcb, 0x21, 0x40, 
-0x55, 0xcd, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x25, 0xd5, 0x21, 0x40, 
-0x8d, 0xd5, 0x21, 0x40, 0xf9, 0xd5, 0x21, 0x40, 0x09, 0x29, 0x09, 0xd1, 
-0x20, 0x28, 0x07, 0xd2, 0x04, 0x48, 0x01, 0x78, 0x00, 0x29, 0x03, 0xd1, 
-0x01, 0x21, 0x01, 0x70, 0x02, 0x48, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 
-0x00, 0x6e, 0x21, 0x40, 0x24, 0xab, 0x20, 0x40, 0x03, 0x49, 0x88, 0x42, 
-0x03, 0xd1, 0x00, 0x20, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x70, 0x70, 0x47, 
-0x24, 0xab, 0x20, 0x40, 0x00, 0x6e, 0x21, 0x40, 0x00, 0xb5, 0x00, 0x20, 
-0x0b, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23, 0x9b, 0x01, 
-0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32, 0xc8, 0x60, 
-0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x05, 0x48, 0xc0, 0x46, 0x48, 0x60, 
-0x88, 0x60, 0x05, 0xf0, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 
-0x0c, 0x1c, 0x05, 0x1c, 0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xda, 0xff, 
-0x68, 0x49, 0x0b, 0x23, 0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40, 
+0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40, 
+0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23, 
+0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32, 
+0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46, 
+0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c, 
+0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23, 
+0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40, 
 0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61, 
 0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a, 
 0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68, 
 0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20, 
-0x00, 0x06, 0x00, 0x0e, 0x04, 0xf0, 0xc8, 0xf9, 0xf8, 0x68, 0x00, 0x28, 
+0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28, 
 0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23, 
 0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95, 
 0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0, 
@@ -2138,300 +2078,301 @@ const u8 typhoon_firmware_image[] = {
 0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1, 
 0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69, 
 0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0, 
-0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 
-0x03, 0xd2, 0x30, 0x20, 0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 
-0x78, 0x69, 0x00, 0x28, 0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 
-0x78, 0x61, 0x00, 0x20, 0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 
-0x23, 0x40, 0x10, 0xd0, 0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 
-0x5b, 0x19, 0x9d, 0x78, 0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 
-0x9b, 0x00, 0x9e, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 
-0x01, 0x31, 0x64, 0x00, 0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 
-0x09, 0x28, 0xe1, 0xd3, 0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 
-0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1c, 0x53, 0xff, 0xff, 
-0x00, 0x01, 0x00, 0x80, 0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 
-0x78, 0x47, 0xc0, 0x46, 0x34, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 
-0x78, 0x47, 0xc0, 0x46, 0x2c, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 
-0x78, 0x47, 0xc0, 0x46, 0x24, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 
-0xc0, 0x46, 0xff, 0xb4, 0x75, 0x46, 0x20, 0xb4, 0x01, 0x21, 0x08, 0x43, 
-0x01, 0xa4, 0xa6, 0x46, 0x00, 0x47, 0xc0, 0x46, 0x20, 0xbc, 0xae, 0x46, 
-0xff, 0xbc, 0xf7, 0x46, 0x24, 0x52, 0xff, 0xff, 0x74, 0x51, 0xff, 0xff, 
-0x51, 0xc0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20, 0x1a, 0x49, 0x01, 0x25, 
-0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01, 0xf8, 0x18, 0x05, 0x73, 
-0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20, 0x7a, 0x6e, 0x17, 0x4b, 
-0x8a, 0x42, 0x1d, 0xd0, 0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 
-0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 
-0xb0, 0x60, 0x10, 0x20, 0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 
-0xb5, 0xff, 0x00, 0x28, 0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 
-0x18, 0x43, 0xb8, 0x61, 0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 
-0xb8, 0x61, 0x20, 0x61, 0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 
-0x0c, 0x55, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 
-0x39, 0x6c, 0x15, 0x48, 0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 
-0x14, 0x4d, 0xa1, 0x42, 0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 
-0xb9, 0x6b, 0x09, 0x18, 0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 
-0x22, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 
-0x2b, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 
-0x02, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 
-0xff, 0xf7, 0x74, 0xff, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 
-0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 
-0xb8, 0x68, 0x79, 0x68, 0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 
-0x55, 0xff, 0x01, 0x20, 0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 
-0xb9, 0x68, 0x38, 0x1c, 0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 
-0x79, 0x37, 0x00, 0x29, 0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 
-0x03, 0xd2, 0x04, 0x73, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1, 0x05, 0x1c, 0x40, 0x68, 
-0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x67, 0xf8, 0x00, 0x28, 
-0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff, 0x22, 0xe0, 0x09, 0x01, 
-0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a, 0x17, 0x49, 0xff, 0xf7, 
-0x27, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73, 0x04, 0x23, 0xa8, 0x69, 
-0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61, 0xda, 0xe7, 0x10, 0x20, 
-0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60, 0xff, 0xf7, 0x82, 0xff, 
-0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x17, 0xf9, 0x30, 0x68, 
-0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0, 0x02, 0x23, 0xf8, 0x6b, 
-0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 
-0x91, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 
-0xe4, 0x01, 0x00, 0x80, 0x0c, 0x55, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, 
-0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49, 0x00, 0x27, 0x08, 0x60, 
-0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x47, 0x70, 0xe0, 0x69, 
-0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0, 0xd7, 0xf8, 0xe0, 0x69, 
-0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0, 0x01, 0x20, 0xe0, 0x61, 
-0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x27, 0x73, 
-0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80, 0xe8, 0x0e, 0x00, 0x80, 
-0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88, 0x6d, 0x28, 0x03, 0xdb, 
-0x38, 0x1c, 0x00, 0xf0, 0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 
-0x09, 0x58, 0x38, 0x1c, 0xff, 0xf7, 0xbd, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 
-0x39, 0x78, 0xc9, 0x09, 0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 
-0xcf, 0xf8, 0x68, 0x46, 0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 
-0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 
-0x02, 0x1c, 0x41, 0x4b, 0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 
-0x00, 0x2f, 0x01, 0xd0, 0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 
-0x2f, 0x78, 0xfb, 0x00, 0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 
-0x40, 0x78, 0x00, 0x01, 0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 
-0xd6, 0x58, 0xc0, 0x46, 0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 
-0x00, 0x29, 0x0f, 0xd0, 0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 
-0x0b, 0xd9, 0x13, 0x1c, 0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 
-0x01, 0x9b, 0x01, 0x30, 0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 
-0x10, 0x27, 0x2b, 0x48, 0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 
-0x03, 0xd8, 0x82, 0x1a, 0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 
-0xba, 0x42, 0x05, 0xd8, 0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 
-0x01, 0x20, 0x37, 0xe0, 0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 
-0x22, 0x4a, 0x3a, 0x43, 0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 
-0x92, 0x6c, 0x23, 0x1c, 0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 
-0x49, 0x6c, 0x09, 0x18, 0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 
-0xff, 0xf7, 0x50, 0xfe, 0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 
-0xa3, 0x19, 0x14, 0x48, 0x82, 0x6c, 0x41, 0x6c, 
-0x03, 0x20, 0xff, 0xf7, 0x45, 0xfe, 0x01, 0x20, 0x0d, 0x49, 0xc0, 0x46, 
-0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18, 0x17, 0x61, 0x8a, 0x69, 
-0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61, 0x00, 0xe0, 0x88, 0x61, 
-0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x00, 0x20, 
-0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73, 0x02, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80, 0xfc, 0xba, 0x20, 0x40, 
-0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
-0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80, 0x18, 0x1a, 0x00, 0x80, 
-0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a, 0xd2, 0x6c, 0x13, 0x04, 
-0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a, 0x88, 0x66, 0x88, 0x6e, 
-0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 
-0x7c, 0x29, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x06, 0x49, 0x4a, 0x6e, 
-0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42, 0x00, 0xd8, 0x80, 0x1a, 
-0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x61, 0x70, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 
-0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46, 0x8a, 0x80, 0x00, 0x22, 
-0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80, 0xca, 0x80, 0x8a, 0x60, 
-0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60, 0x00, 0x22, 0x82, 0x80, 
-0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60, 0xc2, 0x60, 0x70, 0x47, 
-0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48, 0x41, 0x6b, 0x01, 0x31, 
-0x41, 0x63, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 
-0xc0, 0x46, 0x00, 0x90, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 
-0xdf, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 
-0x01, 0xd1, 0x38, 0x1c, 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 
-0xc1, 0x88, 0x09, 0x4a, 0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 
-0xbd, 0xff, 0x01, 0x20, 0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0xff, 0xf7, 0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 
-0xc3, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 
-0x08, 0x71, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 
-0x28, 0x0f, 0x00, 0x80, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 
-0xff, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 
-0x28, 0x0f, 0x00, 0x80, 0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 
-0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 
-0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 
-0xa1, 0x21, 0x49, 0x03, 0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 
-0x00, 0x20, 0x70, 0x47, 0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 
-0x08, 0x49, 0x0f, 0x6b, 0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 
-0xc0, 0x0e, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
-0xa9, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x80, 0x00, 0x14, 0x40, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
-0x38, 0x1c, 0xff, 0xf7, 0x5b, 0xff, 0xf8, 0x88, 
-0x04, 0xa9, 0x05, 0xf0, 0xf7, 0xf9, 0x01, 0xab, 0x58, 0x80, 0x01, 0xa8, 
-0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8, 0x40, 0x88, 0x80, 0x08, 
-0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b, 0x58, 0x70, 0x04, 0x98, 
-0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68, 0xc0, 0x46, 0x03, 0x90, 
-0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
-0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31, 0x68, 0x46, 0xff, 0xf7, 
-0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b, 0x00, 0x29, 0x20, 0xd1, 
-0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x00, 0x29, 0x1a, 0xd1, 
-0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22, 0x00, 0xab, 0x5a, 0x80, 
-0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70, 0x00, 0x24, 0xdc, 0x80, 
-0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68, 0xc0, 0x46, 0x03, 0x90, 
-0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31, 0xff, 0xf7, 0x4c, 0xfe, 
-0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 
-0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
-0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48, 0x00, 0x2a, 0x05, 0xd1, 
-0x0d, 0x49, 0xff, 0xf7, 0xd6, 0xfc, 0x00, 0x28, 0x0c, 0xda, 0x05, 0xe0, 
-0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xd1, 0xfc, 0x00, 0x28, 0x05, 0xda, 
-0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x22, 0xfe, 
-0x00, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xff, 0xff, 0x00, 0x00, 0x15, 0x79, 0x21, 0x40, 0x8d, 0xd5, 0x21, 0x40, 
-0x25, 0xd5, 0x21, 0x40, 0x00, 0xb5, 0xc0, 0x88, 0x05, 0xf0, 0x5c, 0xf9, 
-0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 
-0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0x04, 0x1c, 0x08, 0x1c, 
-0x69, 0x46, 0xff, 0xf7, 0xb5, 0xfe, 0x1c, 0x48, 0xff, 0xf7, 0x96, 0xfc, 
-0x07, 0x1c, 0x1b, 0x4a, 0x00, 0x21, 0x20, 0x1c, 0xff, 0xf7, 0x92, 0xfc, 
-0x00, 0x28, 0x1d, 0xd0, 0x04, 0xa9, 0x18, 0x4a, 0x20, 0x1c, 0xff, 0xf7, 
-0x8b, 0xfc, 0x04, 0x98, 0x04, 0x28, 0x05, 0xd9, 0x04, 0x98, 0x80, 0x08, 
-0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x00, 0xe0, 0x00, 0x20, 0x00, 0xab, 
-0x58, 0x70, 0x06, 0xa8, 0x00, 0x78, 0xc0, 0x46, 0xd8, 0x80, 0x04, 0x98, 
-0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46, 0x03, 0x90, 0x04, 0x33, 
-0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, 
-0x38, 0x1c, 0xff, 0xf7, 0x6a, 0xfc, 0x68, 0x46, 0x29, 0x1c, 0xff, 0xf7, 
-0xc1, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x24, 0x02, 0xff, 0xff, 0xcd, 0xc0, 0x21, 0x40, 0x29, 0xbf, 0x21, 0x40, 
-0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 
-0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 
-0xff, 0xf7, 0xac, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 
-0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 
-0xc6, 0xb0, 0x0f, 0x1c, 0x69, 0x46, 0x38, 0x1c, 
-0xff, 0xf7, 0x58, 0xfe, 0x20, 0x48, 0xff, 0xf7, 0x39, 0xfc, 0x04, 0x1c, 
-0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a, 0x23, 0xd8, 
-0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 
-0xc0, 0x46, 0x04, 0x90, 0x05, 0xa9, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 
-0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd, 0x40, 0xcb, 0x40, 0xc1, 0x40, 0xcb, 
-0x40, 0xc1, 0x40, 0xcb, 0x40, 0xc1, 0x40, 0xcb, 0x40, 0xc1, 0x01, 0x30, 
-0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78, 0x86, 0x42, 0xf1, 0xdc, 0x46, 0x98, 
-0x04, 0xa9, 0x2b, 0x1c, 0xff, 0xf7, 0x20, 0xfc, 0x00, 0x28, 0x05, 0xd0, 
-0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 
-0x07, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x05, 0xfc, 0x68, 0x46, 0x00, 0x21, 
-0xff, 0xf7, 0x5c, 0xfd, 0x01, 0x20, 0x48, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 
-0x00, 0xb5, 0xff, 0xf7, 0x27, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
-0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d, 0x68, 0x68, 0x01, 0x30, 
-0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7, 0x01, 0xfe, 0x10, 0x2c, 
-0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
-0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0, 0x78, 0x78, 0x82, 0x00, 
-0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68, 0x00, 0x2a, 0x15, 0xd9, 
-0x40, 0xcb, 0x0f, 0x1c, 0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 
-0x12, 0x78, 0x40, 0x23, 0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 
-0xda, 0x80, 0x02, 0x90, 0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 
-0x15, 0xe0, 0x01, 0x30, 0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 
-0x02, 0x94, 0x69, 0x68, 0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 
-0x10, 0x33, 0x00, 0x2a, 0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 
-0x01, 0x31, 0x90, 0x42, 0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 
-0x03, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x9c, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 
-0x42, 0x09, 0x00, 0xd3, 0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 
-0x00, 0xd2, 0x02, 0x22, 0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 
-0x01, 0x2b, 0x2e, 0xd1, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 
-0x20, 0x1c, 0x1b, 0x23, 0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 
-0x00, 0xd2, 0x04, 0x27, 0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 
-0x07, 0xd2, 0xd1, 0x1d, 0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 
-0x01, 0xd3, 0x08, 0x23, 0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 
-0x89, 0x79, 0x03, 0x29, 0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 
-0x0b, 0x49, 0x09, 0x6a, 0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 
-0x10, 0x43, 0x89, 0x07, 0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 
-0x70, 0x47, 0x40, 0x0c, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 
-0xec, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0xc0, 0x00, 0x18, 0x40, 0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x05, 0xf0, 
-0x75, 0xfc, 0x39, 0x48, 0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 
-0x37, 0x4e, 0xc5, 0x1d, 0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 
-0x5b, 0x5c, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, 
-0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20, 0xb8, 0x71, 0x00, 0x20, 
-0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23, 0x98, 0x43, 0x00, 0xf0, 
-0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff, 0xc0, 0x08, 0x06, 0xd3, 
-0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28, 0x03, 0xd9, 0x04, 0x20, 
-0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22, 0x20, 0x1c, 0x2b, 0xe0, 
-0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
-0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a, 0x00, 0x21, 0x05, 0xf0, 
-0x07, 0xfc, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 
-0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68, 0x04, 0x23, 0x0a, 0x68, 
-0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
-0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43, 0x00, 0xf0, 0x34, 0xf8, 
-0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x05, 0xf0, 0xe5, 0xfb, 0xe5, 0xe7, 
-0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43, 0x00, 0xf0, 0x28, 0xf8, 
-0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23, 0x0a, 0x68, 0x9a, 0x43, 
-0x0a, 0x60, 0xff, 0xf7, 0xe1, 0xfa, 0xd5, 0xe7, 0x06, 0x20, 0xb8, 0x71, 
-0xd2, 0xe7, 0x00, 0x00, 0x99, 0x7c, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 
-0x00, 0xb5, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 
-0x01, 0x22, 0x00, 0x21, 0x05, 0xf0, 0xbc, 0xfb, 0x08, 0xbc, 0x18, 0x47, 
-0x98, 0x1c, 0x00, 0x80, 0x99, 0x7c, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 
-0x31, 0x48, 0x00, 0x68, 0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 
-0x99, 0x43, 0x01, 0xe0, 0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 
-0x01, 0x2a, 0x05, 0xd1, 0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 
-0x9b, 0x02, 0x19, 0x43, 0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 
-0x01, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 
-0xe0, 0x18, 0x80, 0x8b, 0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 
-0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 
-0x02, 0xd0, 0x00, 0x20, 0x03, 0xf0, 0xca, 0xf9, 0x38, 0x09, 0x07, 0xd3, 
-0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 
-0x00, 0x68, 0x00, 0xe0, 0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 
-0x01, 0x60, 0x15, 0x48, 0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 
-0x01, 0x30, 0x08, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 
-0x98, 0x43, 0x80, 0x08, 0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 
-0x10, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 
-0xe1, 0x68, 0x01, 0x29, 0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 
-0x04, 0x33, 0x18, 0x40, 0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
-0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 
-0x80, 0xb5, 0xff, 0xf7, 0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 
-0xe3, 0x23, 0x1b, 0x01, 0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 
-0x01, 0x22, 0x4a, 0x71, 0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 
-0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x08, 0x48, 
-0x06, 0xe0, 0x02, 0x20, 0x03, 0xf0, 0x7e, 0xfb, 0x07, 0x20, 0x03, 0xf0, 
-0x4d, 0xfb, 0x38, 0x1c, 0xff, 0xf7, 0x34, 0xfa, 0xf5, 0xe7, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf4, 0x01, 0xff, 0xff, 
-0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 0x43, 0xfc, 0xff, 0xf7, 
-0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48, 0x00, 0x68, 0xc0, 0x46, 
-0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 
-0x00, 0x21, 0xff, 0xf7, 0x73, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 
-0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
-0x23, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff, 0xff, 0xf7, 0x62, 0xfe, 
-0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x58, 0xfb, 
-0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 
-0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7, 0x0d, 0xfc, 0x01, 0x24, 
-0x16, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0x17, 0xe0, 0x10, 0x48, 0xff, 0xf7, 0xdf, 0xf9, 0x05, 0x1c, 
-0x0f, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0xdb, 0xf9, 0x0e, 0x49, 
-0x28, 0x1c, 0xff, 0xf7, 0xd6, 0xf9, 0x10, 0x20, 0x00, 0xab, 0x58, 0x70, 
-0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46, 0x03, 0x90, 
-0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x24, 0xfb, 0x20, 0x1c, 0x46, 0xb0, 
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 
-0x24, 0x02, 0xff, 0xff, 0x29, 0xbf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 
+0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20, 
+0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28, 
+0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20, 
+0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0, 
+0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78, 
+0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19, 
+0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00, 
+0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3, 
+0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01, 
+0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80, 
+0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46, 
+0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 
+0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 
+0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff, 
+0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20, 
+0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01, 
+0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20, 
+0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0, 
+0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 
+0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20, 
+0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28, 
+0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 
+0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61, 
+0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 
+0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff, 
+0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48, 
+0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42, 
+0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 
+0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92, 
+0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7, 
+0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92, 
+0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff, 
+0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80, 
+0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 
+0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68, 
+0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20, 
+0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c, 
+0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29, 
+0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1, 
+0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0, 
+0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff, 
+0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a, 
+0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73, 
+0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61, 
+0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60, 
+0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 
+0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0, 
+0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00, 
+0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0, 
+0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff, 
+0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49, 
+0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30, 
+0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0, 
+0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0, 
+0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 
+0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80, 
+0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88, 
+0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0, 
+0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c, 
+0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09, 
+0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46, 
+0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20, 
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b, 
+0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0, 
+0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00, 
+0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01, 
+0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46, 
+0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0, 
+0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c, 
+0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30, 
+0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48, 
+0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a, 
+0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8, 
+0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0, 
+0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43, 
+0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c, 
+0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18, 
+0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe, 
+0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48, 
+0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20, 
+0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18, 
+0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61, 
+0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 
+0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73, 
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80, 
+0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80, 
+0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a, 
+0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a, 
+0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47, 
+0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 
+0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42, 
+0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46, 
+0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 
+0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46, 
+0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80, 
+0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60, 
+0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60, 
+0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48, 
+0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46, 
+0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 
+0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c, 
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a, 
+0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20, 
+0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21, 
+0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80, 
+0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22, 
+0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80, 
+0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 
+0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 
+0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03, 
+0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47, 
+0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b, 
+0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20, 
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40, 
+0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
+0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab, 
+0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8, 
+0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b, 
+0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68, 
+0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
+0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31, 
+0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b, 
+0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 
+0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22, 
+0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70, 
+0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68, 
+0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31, 
+0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 
+0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
+0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48, 
+0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28, 
+0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc, 
+0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40, 
+0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
+0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7, 
+0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a, 
+0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0, 
+0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8, 
+0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21, 
+0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29, 
+0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0, 
+0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46, 
+0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46, 
+0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 
+0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46, 
+0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40, 
+0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c, 
+0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 
+0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c, 
+0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc, 
+0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a, 
+0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c, 
+0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d, 
+0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd, 
+0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 
+0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78, 
+0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7, 
+0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23, 
+0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7, 
+0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20, 
+0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 
+0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc, 
+0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d, 
+0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7, 
+0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
+0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0, 
+0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68, 
+0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c, 
+0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23, 
+0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90, 
+0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30, 
+0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68, 
+0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a, 
+0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42, 
+0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20, 
+0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80, 
+0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3, 
+0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22, 
+0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1, 
+0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23, 
+0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27, 
+0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d, 
+0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23, 
+0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29, 
+0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a, 
+0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07, 
+0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c, 
+0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 
+0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48, 
+0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d, 
+0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00, 
+0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20, 
+0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23, 
+0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff, 
+0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28, 
+0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22, 
+0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68, 
+0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a, 
+0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68, 
+0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68, 
+0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68, 
+0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43, 
+0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0, 
+0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43, 
+0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23, 
+0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7, 
+0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00, 
+0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20, 
+0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 
+0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80, 
+0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68, 
+0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0, 
+0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1, 
+0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 
+0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68, 
+0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b, 
+0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43, 
+0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20, 
+0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23, 
+0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0, 
+0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48, 
+0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43, 
+0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08, 
+0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42, 
+0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29, 
+0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40, 
+0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7, 
+0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01, 
+0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71, 
+0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43, 
+0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc, 
+0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa, 
+0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 
+0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48, 
+0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46, 
+0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
+0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
+0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff, 
+0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7, 
+0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8, 
+0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 
+0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7, 
+0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 
+0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f, 
+0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22, 
+0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab, 
+0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46, 
+0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c, 
+0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00, 
+0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 
 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
-0xcf, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x02, 0xd1, 
-0x43, 0x01, 0x9c, 0x42, 0x09, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 
-0x27, 0xe0, 0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 
-0x05, 0x90, 0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 
-0x00, 0x28, 0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 
-0x00, 0x04, 0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 
-0x09, 0x0c, 0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0a, 0x48, 0xff, 0xf7, 
-0x83, 0xf9, 0x07, 0x1c, 0x09, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 
-0x7f, 0xf9, 0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x7a, 0xf9, 0x68, 0x46, 
-0x00, 0x21, 0xff, 0xf7, 0xd1, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x51, 0xbf, 0x21, 0x40, 
+0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1, 
+0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 
+0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0, 
+0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 
+0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28, 
+0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04, 
+0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c, 
+0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9, 
+0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9, 
+0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40, 
 0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27, 
 0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0, 
 0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0, 
@@ -2439,110 +2380,110 @@ const u8 typhoon_firmware_image[] = {
 0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, 
 0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0, 
 0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0, 
-0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 
-0xff, 0x23, 0x01, 0x33, 0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 
-0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 
-0x00, 0xe0, 0x01, 0x22, 0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 
-0xff, 0x23, 0xe1, 0x33, 0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 
-0xff, 0x33, 0x9e, 0x42, 0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 
-0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 
-0x20, 0xe0, 0x01, 0x21, 0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 
-0x0a, 0xd1, 0x40, 0x88, 0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 
-0x00, 0x2a, 0x13, 0xd0, 0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 
-0x00, 0x2e, 0x0d, 0xd1, 0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 
-0x81, 0x33, 0x19, 0x43, 0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 
-0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x03, 0xf0, 
-0x2d, 0xf8, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0x03, 0xf0, 0x28, 0xf8, 
-0x00, 0x2f, 0x02, 0xd1, 0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 
-0x20, 0x1c, 0xff, 0xf7, 0x03, 0xfb, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0x36, 0xfa, 0x28, 0x1c, 0x04, 0xb0, 
+0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33, 
+0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02, 
+0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22, 
+0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33, 
+0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42, 
+0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1, 
+0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21, 
+0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88, 
+0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0, 
+0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1, 
+0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43, 
+0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0, 
+0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21, 
+0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1, 
+0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 
+0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
+0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 
+0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0, 
 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
 0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62, 
 0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28, 
 0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21, 
 0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, 
 0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0, 
-0xeb, 0xff, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80, 
+0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80, 
 0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 
 0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20, 
-0x02, 0xf0, 0xd8, 0xff, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28, 
 0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23, 
 0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 
 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c, 
-0x10, 0x20, 0x02, 0xf0, 0xb9, 0xff, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01, 
+0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01, 
 0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 
 0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02, 
-0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xa6, 0xff, 0x00, 0x20, 0x80, 0xbc, 
+0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 
-0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x7d, 0xfa, 0xb8, 0x05, 
+0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05, 
 0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
-0xb5, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
 0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49, 
 0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49, 
 0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40, 
-0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 
-0x0d, 0x49, 0x0f, 0x6a, 0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 
-0x02, 0x2f, 0x01, 0xd1, 0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 
-0x01, 0x27, 0xff, 0x02, 0x69, 0x46, 0xff, 0xf7, 0x49, 0xfa, 0x01, 0xab, 
-0x5f, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x83, 0xf9, 0x01, 0x20, 
-0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 
-0xc2, 0x88, 0xa1, 0x20, 0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 
-0x9a, 0x42, 0x01, 0xd1, 0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 
-0x9a, 0x42, 0x02, 0xd1, 0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 
-0x08, 0x1c, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 
-0x57, 0xff, 0x69, 0x46, 0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x1e, 0xfa, 
-0x01, 0xab, 0x5c, 0x80, 0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 
-0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x54, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 
-0xc0, 0x0f, 0x05, 0x49, 0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 
-0x68, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 
-0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 
-0x69, 0x46, 0xff, 0xf7, 0xf7, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab, 
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x2f, 0xf9, 0x01, 0x20, 
+0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a, 
+0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1, 
+0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02, 
+0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20, 
+0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1, 
+0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1, 
+0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47, 
+0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46, 
+0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80, 
+0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49, 
+0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80, 
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 
+0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 
+0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20, 
 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, 
 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47, 
 0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68, 
-0xff, 0xf7, 0xda, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49, 
+0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49, 
 0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0, 
 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 
 0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
-0x03, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
 0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68, 
-0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0xcf, 0xfe, 0x00, 0x20, 
-0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0xae, 0xf9, 0x00, 0xa8, 0x00, 0x78, 
+0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20, 
+0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78, 
 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 
-0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xe1, 0xf8, 0x01, 0x20, 
+0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20, 
 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88, 
-0x69, 0x46, 0xff, 0xf7, 0x97, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x78, 0xff, 
-0x02, 0x20, 0x39, 0x1c, 0x03, 0xf0, 0x3c, 0xfe, 0x00, 0x28, 0x06, 0xd0, 
-0x02, 0x20, 0x39, 0x1c, 0x03, 0xf0, 0x8c, 0xfd, 0x01, 0xab, 0x58, 0x80, 
+0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff, 
+0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0, 
+0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80, 
 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c, 
-0xfe, 0xf7, 0x65, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xbc, 0xf8, 
+0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8, 
 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0, 
-0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x6b, 0xf9, 0x10, 0x48, 
-0xfe, 0xf7, 0x4c, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7, 
-0x49, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c, 
-0x22, 0x1c, 0xfe, 0xf7, 0x42, 0xff, 0x02, 0xe0, 
-0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 
-0x38, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x8f, 0xf8, 0x01, 0x20, 
-0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 
-0xcd, 0xc0, 0x21, 0x40, 0xd9, 0xbf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 
-0x00, 0xb5, 0xff, 0xf7, 0x57, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 
-0x70, 0x47, 0x80, 0xb4, 0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 
-0x00, 0x2a, 0x03, 0xd1, 0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 
-0x01, 0x2a, 0x04, 0xd1, 0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 
-0x1f, 0xe0, 0x02, 0x2a, 0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 
-0x3b, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 
-0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 
-0x00, 0x20, 0x13, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 
-0xc7, 0x1d, 0x19, 0x37, 0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 
-0x00, 0x0c, 0x20, 0x28, 0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 
-0x80, 0x00, 0x14, 0x40, 0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 
-0x12, 0x0a, 0x10, 0x43, 0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 
-0x02, 0x60, 0x0c, 0x4b, 0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02, 
+0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48, 
+0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7, 
+0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c, 
+0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 
+0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40, 
+0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 
+0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4, 
+0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1, 
+0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1, 
+0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a, 
+0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40, 
+0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30, 
+0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c, 
+0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37, 
+0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 
+0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40, 
+0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43, 
+0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b, 
+0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02, 
 0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80, 
 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04, 
 0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 
@@ -2551,8 +2492,8 @@ const u8 typhoon_firmware_image[] = {
 0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02, 
 0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 
 0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c, 
-0xff, 0xf7, 0xc2, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43, 
-0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xf9, 0xff, 0x01, 0x20, 
+0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43, 
+0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20, 
 0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, 
 0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04, 
 0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02, 
@@ -2566,415 +2507,126 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b, 
 0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04, 
 0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 
-0xa9, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
 0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a, 
-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 
-0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 
-0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 
-0x8d, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 
-0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 
-0x0b, 0x49, 0x0a, 0x6a, 0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 
-0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 
-0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 
-0x69, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 
-0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 
-0x02, 0x49, 0xfe, 0xf7, 0xfa, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 
-0x75, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 
-0x0b, 0xf8, 0x06, 0x48, 0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0xfe, 0xf7, 0x43, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 
-0x11, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x0c, 0xf8, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x07, 0xf8, 0x08, 0xbc, 
-0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xcc, 0xfd, 
+0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 
+0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 
+0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47, 
+0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a, 
+0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 
+0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 
+0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47, 
+0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7, 
+0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff, 
+0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48, 
+0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 
+0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd, 
 0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21, 
 0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c, 
 0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 
 0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48, 
 0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x21, 0xa5, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
+0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20, 
 0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff, 
 0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20, 
 0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff, 
-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x02, 0xf0, 
-0xf3, 0xfe, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 
-0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xf8, 0xff, 0x00, 0x28, 0x0c, 0xd1, 
-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x96, 0xff, 0x06, 0x48, 0x01, 0xab, 
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xcf, 0xfe, 0x01, 0x20, 
+0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 
+0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 
+0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1, 
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20, 
 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xff, 0xff, 0x00, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 
-0x81, 0xff, 0x04, 0xf0, 0x47, 0xfa, 0x01, 0xab, 0x58, 0x80, 0x09, 0x48, 
-0x81, 0x89, 0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 
-0x09, 0x04, 0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 
-0xfe, 0xf7, 0xae, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x7d, 0xff, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x78, 0xff, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0xb5, 0xfe, 0xf7, 0x73, 0xff, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x6e, 0xff, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
-0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
-0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x5a, 0xff, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x55, 0xff, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
-0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 
-0x08, 0xa9, 0xfe, 0xf7, 0x27, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x04, 0xf0, 
-0x75, 0xfa, 0x02, 0x20, 0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 
-0xfe, 0xf7, 0x5c, 0xfe, 0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0xb5, 0xfe, 0xf7, 0x2d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 
-0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x0c, 0xff, 
-0xfa, 0x88, 0x12, 0x49, 0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 
-0x0f, 0xd0, 0x04, 0x70, 0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 
-0xc8, 0x82, 0xb8, 0x68, 0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 
-0x48, 0x83, 0xf8, 0x68, 0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21, 
+0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 
+0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89, 
+0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04, 
+0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 
+0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7, 
+0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20, 
+0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe, 
+0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49, 
+0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70, 
+0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68, 
+0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68, 
+0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21, 
 0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0xfe, 0xf7, 0x2b, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, 
+0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 
-0x00, 0xb5, 0xfe, 0xf7, 0xf7, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
-0xfe, 0xf7, 0xf2, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
-0xed, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xe8, 0xfe, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 
+0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc, 
 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 
-0xfe, 0xf7, 0xc2, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43, 
+0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43, 
 0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42, 
 0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 
-0xfe, 0xf7, 0xf0, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68, 
+0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68, 
 0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80, 
-0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xe0, 0xfd, 
+0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd, 
 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 
-0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x8f, 0xfe, 0xf8, 0x88, 
+0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88, 
 0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b, 
 0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0xfe, 0xf7, 0xbf, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68, 
+0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68, 
 0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 
 0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 
-0x80, 0xb5, 0x86, 0xb0, 0x07, 0x1c, 0x04, 0xf0, 0x33, 0xf9, 0x38, 0x1c, 
-0x02, 0xa9, 0xfe, 0xf7, 0x67, 0xfe, 0x01, 0x27, 0x02, 0xab, 0x5f, 0x70, 
-0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68, 0xc0, 0x46, 0x04, 0x91, 
-0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68, 
+0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27, 
+0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68, 
+0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68, 
 0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46, 
-0x02, 0xa8, 0xfe, 0xf7, 0x91, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc, 
+0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68, 
-0x80, 0x68, 0xfe, 0xf7, 0x49, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 
+0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 
 0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 
-0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x46, 0xfe, 0x01, 0xab, 0x5c, 0x80, 
-0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x71, 0xfd, 0x04, 0xb0, 
+0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80, 
+0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0, 
 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 
-0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x34, 0xfe, 0x01, 0xab, 0x5f, 0x80, 
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x60, 0xfd, 0x04, 0xb0, 0x80, 0xbc, 
+0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
 0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a, 
 0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0, 
 0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27, 
 0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27, 
-0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xfc, 0xfd, 0x01, 0xab, 0x5f, 0x80, 
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x36, 0xfd, 0x20, 0x1c, 0x04, 0xb0, 
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
-0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 
-0xe7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
-0x00, 0x21, 0xfe, 0xf7, 0x1f, 0xfd, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 
-0xed, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
+0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0, 
+0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 
+0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47, 
+0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
-0xdb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x85, 0xb0, 
-0x01, 0xa9, 0xfe, 0xf7, 0xbb, 0xfd, 0x00, 0x20, 0x01, 0xab, 0x58, 0x70, 
-0x10, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29, 0x0a, 0xd1, 0x04, 0xf0, 
-0xc7, 0xf8, 0x03, 0x90, 0x04, 0x97, 0x03, 0x98, 0x00, 0x28, 0x06, 0xd0, 
-0x68, 0x46, 0x02, 0xf0, 0xe5, 0xfb, 0x04, 0xe0, 0x03, 0x97, 0x04, 0x90, 
-0xf8, 0xe7, 0x00, 0x20, 0x00, 0x90, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46, 
-0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xdb, 0xfc, 0x38, 0x1c, 
+0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20, 
+0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29, 
+0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90, 
+0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46, 
+0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c, 
 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
-0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 
-0x8d, 0xfd, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 0x01, 0x24, 0x20, 0x1c, 
-0x12, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, 0x00, 0x20, 0x00, 0x06, 
-0x00, 0x0e, 0x13, 0xd0, 0xf8, 0x88, 0x0f, 0x4a, 0x90, 0x42, 0x02, 0xd0, 
-0x0e, 0x4b, 0x98, 0x42, 0x08, 0xd1, 0xb9, 0x68, 0x27, 0x1c, 0x90, 0x42, 
-0x00, 0xd0, 0x00, 0x27, 0x38, 0x06, 0x00, 0x0e, 0x04, 0xf0, 0x88, 0xf8, 
-0x04, 0xf0, 0x84, 0xf8, 0x02, 0x90, 0x00, 0xe0, 0x02, 0x94, 0x68, 0x46, 
-0x00, 0x21, 0xfe, 0xf7, 0xa7, 0xfc, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xed, 0xfe, 0x00, 0x00, 
-0xfe, 0xca, 0x00, 0x00, 0xf1, 0xb5, 0xd6, 0xb0, 
-0x00, 0x20, 0x81, 0x00, 0x56, 0x9c, 0x0a, 0x19, 0x12, 0x6a, 0x6b, 0x46, 
-0x5a, 0x50, 0x01, 0x30, 0x10, 0x28, 0xf6, 0xdb, 0x10, 0x20, 0x82, 0x00, 
-0x11, 0x1c, 0x69, 0x44, 0x40, 0x39, 0x4b, 0x6b, 0x0f, 0x6a, 0x7b, 0x40, 
-0x8f, 0x68, 0x7b, 0x40, 0x09, 0x68, 0x59, 0x40, 0x4b, 0x00, 0xc9, 0x0f, 
-0x19, 0x43, 0x6b, 0x46, 0x99, 0x50, 0x01, 0x30, 0x50, 0x28, 0xec, 0xdb, 
-0x56, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x55, 0x91, 0x42, 0x68, 0xc0, 0x46, 
-0x54, 0x92, 0x86, 0x68, 0xc0, 0x46, 0x53, 0x96, 0xc5, 0x68, 0xc0, 0x46, 
-0x52, 0x95, 0x04, 0x69, 0xc0, 0x46, 0x51, 0x94, 0x48, 0x01, 0xcb, 0x0e, 
-0x18, 0x43, 0x13, 0x1c, 0x33, 0x40, 0x07, 0x1c, 0x28, 0x1c, 0x90, 0x43, 
-0x18, 0x43, 0x38, 0x18, 0x00, 0x19, 0x00, 0x9b, 0xc0, 0x18, 0xcf, 0x4b, 
-0xc0, 0x18, 0x93, 0x07, 0x92, 0x08, 0x13, 0x43, 0x42, 0x01, 0x1f, 0x1c, 
-0xc3, 0x0e, 0x1a, 0x43, 0x0b, 0x1c, 0x3b, 0x40, 0x14, 0x1c, 0x32, 0x1c, 
-0x8a, 0x43, 0x1a, 0x43, 0xa2, 0x18, 0x52, 0x19, 0x01, 0x9b, 0xd2, 0x18, 
-0xc5, 0x4b, 0xd4, 0x18, 0x8a, 0x07, 0x89, 0x08, 0x11, 0x43, 0x62, 0x01, 
-0xe3, 0x0e, 0x1a, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x15, 0x1c, 0x3a, 0x1c, 
-0x82, 0x43, 0x1a, 0x43, 0xaa, 0x18, 0x92, 0x19, 0x02, 0x9b, 0xd2, 0x18, 
-0xbc, 0x4b, 0xd2, 0x18, 0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, 
-0x57, 0x01, 0xd5, 0x0e, 0x3d, 0x43, 0x27, 0x1c, 0x07, 0x40, 0x0e, 0x1c, 
-0xa6, 0x43, 0x37, 0x43, 0xed, 0x19, 0xeb, 0x18, 0x03, 0x9f, 0xdf, 0x19, 
-0xb3, 0x4b, 0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, 
-0xfd, 0x0e, 0x2b, 0x43, 0x15, 0x1c, 0x25, 0x40, 0x1e, 0x1c, 0x03, 0x1c, 
-0x93, 0x43, 0x2b, 0x43, 0xf3, 0x18, 0x59, 0x18, 0x04, 0x9b, 0xc9, 0x18, 
-0xaa, 0x4b, 0xc9, 0x18, 0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, 
-0xcd, 0x0e, 0x1d, 0x43, 0x3e, 0x1c, 0x16, 0x40, 0x23, 0x1c, 0xbb, 0x43, 
-0x33, 0x43, 0xeb, 0x18, 0x18, 0x18, 0x05, 0x9b, 0xc0, 0x18, 0xa2, 0x4b, 
-0xc0, 0x18, 0xbb, 0x07, 0xbf, 0x08, 0x1f, 0x43, 0x43, 0x01, 0xc5, 0x0e, 
-0x2b, 0x43, 0x0d, 0x1c, 0x3d, 0x40, 0x1e, 0x1c, 0x13, 0x1c, 0x8b, 0x43, 
-0x2b, 0x43, 0xf3, 0x18, 0x1b, 0x19, 0x06, 0x9c, 0x1c, 0x19, 0x99, 0x4b, 
-0xe4, 0x18, 0x8b, 0x07, 0x89, 0x08, 0x19, 0x43, 0x63, 0x01, 0xe5, 0x0e, 
-0x1d, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x3e, 0x1c, 0x86, 0x43, 0x33, 0x43, 
-0xeb, 0x18, 0x9a, 0x18, 0x07, 0x9b, 0xd2, 0x18, 0x90, 0x4b, 0xd2, 0x18, 
-0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, 0x57, 0x01, 0xd5, 0x0e, 
-0x2f, 0x43, 0x25, 0x1c, 0x05, 0x40, 0x3e, 0x1c, 0x0f, 0x1c, 0xa7, 0x43, 
-0x2f, 0x43, 0xf5, 0x19, 0xeb, 0x18, 0x08, 0x9f, 0xdf, 0x19, 0x87, 0x4b, 
-0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, 0xfd, 0x0e, 
-0x1d, 0x43, 0x16, 0x1c, 0x26, 0x40, 0x03, 0x1c, 0x93, 0x43, 0x33, 0x43, 
-0xeb, 0x18, 0x59, 0x18, 0x09, 0x9b, 0xc9, 0x18, 0x7e, 0x4b, 0xc9, 0x18, 
-0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, 0xcd, 0x0e, 0x1d, 0x43, 
-0x3b, 0x1c, 0x13, 0x40, 0x26, 0x1c, 0xbe, 0x43, 0x33, 0x43, 0xeb, 0x18, 
-0x18, 0x18, 0x0a, 0x9b, 0xc0, 0x18, 0x76, 0x4b, 0xc0, 0x18, 0x23, 0x1c, 
-0xbc, 0x07, 0xbf, 0x08, 0x27, 0x43, 0x44, 0x01, 0xc5, 0x0e, 0x2c, 0x43, 
-0x0d, 0x1c, 0x3d, 0x40, 0x26, 0x1c, 0x14, 0x1c, 0x8c, 0x43, 0x2c, 0x43, 
-0x35, 0x19, 0xeb, 0x18, 0x0b, 0x9c, 0x1c, 0x19, 
-0x6c, 0x4b, 0xe4, 0x18, 0x8b, 0x07, 0x89, 0x08, 0x19, 0x43, 0x63, 0x01, 
-0xe5, 0x0e, 0x1d, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x3e, 0x1c, 0x86, 0x43, 
-0x33, 0x43, 0xeb, 0x18, 0x9a, 0x18, 0x0c, 0x9b, 0xd2, 0x18, 0x64, 0x4b, 
-0xd2, 0x18, 0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, 0x57, 0x01, 
-0xd5, 0x0e, 0x3d, 0x43, 0x27, 0x1c, 0x07, 0x40, 0x0e, 0x1c, 0xa6, 0x43, 
-0x37, 0x43, 0xed, 0x19, 0xeb, 0x18, 0x0d, 0x9f, 0xdf, 0x19, 0x5b, 0x4b, 
-0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, 0xfd, 0x0e, 
-0x1d, 0x43, 0x13, 0x1c, 0x23, 0x40, 0x06, 0x1c, 0x96, 0x43, 0x33, 0x43, 
-0xeb, 0x18, 0x59, 0x18, 0x0e, 0x9b, 0xc9, 0x18, 0x52, 0x4b, 0xc9, 0x18, 
-0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, 0xcd, 0x0e, 0x2b, 0x43, 
-0x3d, 0x1c, 0x15, 0x40, 0x1e, 0x1c, 0x23, 0x1c, 0xbb, 0x43, 0x2b, 0x43, 
-0xf3, 0x18, 0x18, 0x18, 0x0f, 0x9b, 0xc0, 0x18, 0x49, 0x4b, 0xc0, 0x18, 
-0x23, 0x1c, 0xbc, 0x07, 0xbf, 0x08, 0x27, 0x43, 0x10, 0x24, 0x50, 0x94, 
-0x44, 0x01, 0xc5, 0x0e, 0x25, 0x43, 0x0e, 0x1c, 0x3e, 0x40, 0x14, 0x1c, 
-0x8c, 0x43, 0x34, 0x43, 0x2c, 0x19, 0xe3, 0x18, 0x50, 0x9c, 0xa5, 0x00, 
-0x6c, 0x46, 0x64, 0x59, 0x1c, 0x19, 0x3e, 0x4b, 0xe4, 0x18, 0x13, 0x1c, 
-0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 0x0f, 0x43, 0x01, 0x1c, 0x20, 0x1c, 
-0x50, 0x9c, 0x01, 0x34, 0x50, 0x94, 0x14, 0x2c, 0xe2, 0xdb, 0x14, 0x24, 
-0x45, 0x01, 0xc6, 0x0e, 0x2e, 0x43, 0x0d, 0x1c, 0x7d, 0x40, 0x55, 0x40, 
-0x75, 0x19, 0xeb, 0x18, 0xa5, 0x00, 0x6e, 0x46, 0x75, 0x59, 0x5d, 0x19, 
-0x31, 0x4b, 0xed, 0x18, 0x13, 0x1c, 0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 
-0x0f, 0x43, 0x01, 0x1c, 0x28, 0x1c, 0x01, 0x34, 0x28, 0x2c, 0xe7, 0xdb, 
-0x28, 0x24, 0x50, 0x94, 0x44, 0x01, 0xc5, 0x0e, 0x25, 0x43, 0x3c, 0x1c, 
-0x14, 0x43, 0x0c, 0x40, 0x3e, 0x1c, 0x16, 0x40, 0x34, 0x43, 0x2c, 0x19, 
-0xe3, 0x18, 0x50, 0x9c, 0xa5, 0x00, 0x6c, 0x46, 0x64, 0x59, 0x1c, 0x19, 
-0x23, 0x4b, 0xe4, 0x18, 0x13, 0x1c, 0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 
-0x0f, 0x43, 0x01, 0x1c, 0x20, 0x1c, 0x50, 0x9c, 0x01, 0x34, 0x50, 0x94, 
-0x3c, 0x2c, 0xe1, 0xdb, 0x3c, 0x24, 0x45, 0x01, 0xc6, 0x0e, 0x2e, 0x43, 
-0x0d, 0x1c, 0x7d, 0x40, 0x55, 0x40, 0x75, 0x19, 0xeb, 0x18, 0xa6, 0x00, 
-0x6d, 0x46, 0xad, 0x59, 0x5d, 0x19, 0x17, 0x4b, 0xed, 0x18, 0x13, 0x1c, 
-0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 0x0f, 0x43, 0x01, 0x1c, 0x28, 0x1c, 
-0x01, 0x34, 0x50, 0x2c, 0xe7, 0xdb, 0x55, 0x9c, 0x20, 0x18, 0x56, 0x9c, 
-0xc0, 0x46, 0x20, 0x60, 0x54, 0x98, 0x40, 0x18, 0x56, 0x9c, 0xc0, 0x46, 
-0x60, 0x60, 0x53, 0x9e, 0xf0, 0x19, 0x56, 0x9c, 0xc0, 0x46, 0xa0, 0x60, 
-0x52, 0x9d, 0xa8, 0x18, 0x56, 0x9c, 0xc0, 0x46, 0xe0, 0x60, 0x51, 0x9c, 
-0xe0, 0x18, 0x56, 0x9c, 0xc0, 0x46, 0x20, 0x61, 0x57, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x99, 0x79, 0x82, 0x5a, 0xa1, 0xeb, 0xd9, 0x6e, 
-0xdc, 0xbc, 0x1b, 0x8f, 0xd6, 0xc1, 0x62, 0xca, 0x88, 0xb4, 0x8a, 0x08, 
-0x89, 0x07, 0x00, 0xd0, 0x01, 0x32, 0x00, 0x21, 0x00, 0x2a, 0x1e, 0xdd, 
-0x07, 0x78, 0x00, 0xab, 0x1f, 0x70, 0x47, 0x78, 0xc0, 0x46, 0x5f, 0x70, 
-0x87, 0x78, 0xc0, 0x46, 0x9f, 0x70, 0xc7, 0x78, 0xc0, 0x46, 0xdf, 0x70, 
-0xdb, 0x78, 0xc0, 0x46, 0x03, 0x70, 0x00, 0xab, 0x9b, 0x78, 0xc0, 0x46, 
-0x43, 0x70, 0x00, 0xab, 0x5b, 0x78, 0xc0, 0x46, 
-0x83, 0x70, 0x00, 0xab, 0x1b, 0x78, 0xc0, 0x46, 0xc3, 0x70, 0x04, 0x30, 
-0x01, 0x31, 0x91, 0x42, 0xe0, 0xdb, 0x88, 0xbc, 0x70, 0x47, 0x00, 0x21, 
-0xc1, 0x61, 0x09, 0x4a, 0xc0, 0x46, 0x02, 0x60, 0x08, 0x4a, 0xc0, 0x46, 
-0x42, 0x60, 0x08, 0x4a, 0xc0, 0x46, 0x82, 0x60, 0x07, 0x4a, 0xc0, 0x46, 
-0xc2, 0x60, 0x07, 0x4a, 0xc0, 0x46, 0x02, 0x61, 0x41, 0x61, 0x81, 0x61, 
-0x70, 0x47, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 
-0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xf0, 0xe1, 0xd2, 0xc3, 
-0xf0, 0xb5, 0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0xe1, 0x00, 0x78, 0x69, 
-0x41, 0x18, 0x81, 0x42, 0x02, 0xd2, 0xb8, 0x69, 0x01, 0x30, 0xb8, 0x61, 
-0x79, 0x61, 0x61, 0x0f, 0xb8, 0x69, 0x40, 0x18, 0xb8, 0x61, 0x40, 0x2c, 
-0x14, 0xdb, 0xfe, 0x1d, 0x19, 0x36, 0x00, 0x20, 0x29, 0x78, 0x3a, 0x18, 
-0x20, 0x32, 0x11, 0x70, 0x01, 0x35, 0x01, 0x30, 0x40, 0x28, 0xf7, 0xd3, 
-0x40, 0x21, 0x30, 0x1c, 0xff, 0xf7, 0x96, 0xff, 0x38, 0x1c, 0xff, 0xf7, 
-0xaf, 0xfd, 0x40, 0x3c, 0x40, 0x2c, 0xec, 0xda, 0x00, 0x20, 0x00, 0x2c, 
-0x07, 0xd9, 0x29, 0x78, 0x3a, 0x18, 0x20, 0x32, 0x11, 0x70, 0x01, 0x35, 
-0x01, 0x30, 0xa0, 0x42, 0xf7, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xf8, 0xb5, 0x07, 0x1c, 0xd3, 0x00, 0x78, 0x69, 0xc6, 0x18, 0x86, 0x42, 
-0x02, 0xd2, 0xb8, 0x69, 0x01, 0x30, 0xb8, 0x61, 0x7e, 0x61, 0x53, 0x0f, 
-0xb8, 0x69, 0xc0, 0x18, 0xb8, 0x61, 0x00, 0x90, 0x00, 0x20, 0x00, 0x2a, 
-0x07, 0xdd, 0x0b, 0x78, 0x3c, 0x18, 0x20, 0x34, 0x23, 0x70, 0x01, 0x31, 
-0x01, 0x30, 0x90, 0x42, 0xf7, 0xdb, 0x80, 0x20, 0xd1, 0x19, 0x20, 0x31, 
-0x08, 0x70, 0x54, 0x1c, 0xfd, 0x1d, 0x19, 0x35, 0x38, 0x2c, 0x1c, 0xdd, 
-0x38, 0x19, 0x20, 0x30, 0x00, 0x21, 0x40, 0x22, 0x12, 0x1b, 0x00, 0x2a, 
-0x05, 0xdd, 0x00, 0x23, 0x03, 0x70, 0x01, 0x30, 0x01, 0x31, 0x8a, 0x42, 
-0xfa, 0xdc, 0x28, 0x1c, 0x21, 0x1c, 0xff, 0xf7, 0x4d, 0xff, 0x38, 0x1c, 
-0xff, 0xf7, 0x66, 0xfd, 0x28, 0x1c, 0x00, 0x21, 0x00, 0x23, 0x03, 0x70, 
-0x01, 0x30, 0x01, 0x31, 0x38, 0x29, 0xfa, 0xdb, 0x0c, 0xe0, 0x38, 0x19, 
-0x20, 0x30, 0x00, 0x21, 0x38, 0x22, 0x12, 0x1b, 0x00, 0x2a, 0x05, 0xdd, 
-0x00, 0x23, 0x03, 0x70, 0x01, 0x30, 0x01, 0x31, 0x8a, 0x42, 0xfa, 0xdc, 
-0x28, 0x1c, 0x21, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x00, 0x98, 0xc0, 0x46, 
-0xb8, 0x65, 0xfe, 0x65, 0x38, 0x1c, 0xff, 0xf7, 0x45, 0xfd, 0x01, 0x20, 
-0xf8, 0x61, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x0c, 0x1c, 
-0x05, 0x1c, 0x17, 0x1c, 0x38, 0x1c, 0x00, 0x2f, 0x04, 0xda, 0x40, 0x42, 
-0x80, 0x06, 0x80, 0x0e, 0x40, 0x42, 0x01, 0xe0, 0x80, 0x06, 0x80, 0x0e, 
-0x00, 0x28, 0x07, 0xd1, 0x28, 0x1c, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 
-0x57, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0x00, 0x2f, 
-0x00, 0xda, 0x3f, 0x30, 0x80, 0x11, 0x00, 0x28, 0x07, 0xdd, 0x86, 0x01, 
-0x28, 0x1c, 0x21, 0x1c, 0x32, 0x1c, 0xff, 0xf7, 0x47, 0xff, 0xa4, 0x19, 
-0xbf, 0x1b, 0x00, 0x2f, 0xeb, 0xd0, 0x28, 0x1c, 0x21, 0x1c, 0x3a, 0x1c, 
-0xff, 0xf7, 0x74, 0xff, 0xe5, 0xe7, 0x98, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 
-0x30, 0x20, 0x00, 0xab, 0x18, 0x70, 0xf8, 0x69, 0x00, 0x28, 0x04, 0xd1, 
-0x69, 0x46, 0x00, 0x22, 0x38, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0x14, 0x21, 
-0x38, 0x1c, 0xff, 0xf7, 0xe3, 0xfe, 0x00, 0x20, 
-0x81, 0x00, 0x79, 0x58, 0x02, 0xc4, 0x01, 0x30, 0x05, 0x28, 0xf9, 0xdb, 
-0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0x98, 0xb0, 0x07, 0x1c, 
-0x78, 0x68, 0x40, 0x28, 0x10, 0xd9, 0x68, 0x46, 0xff, 0xf7, 0xf9, 0xfe, 
-0x68, 0x46, 0x06, 0xcf, 0x08, 0x3f, 0xff, 0xf7, 0xa7, 0xff, 0xf8, 0x1d, 
-0xc5, 0x30, 0x69, 0x46, 0x04, 0x1c, 0xff, 0xf7, 0xd0, 0xff, 0x14, 0x20, 
-0x78, 0x60, 0x3c, 0x60, 0x00, 0x20, 0x00, 0x24, 0x39, 0x18, 0xca, 0x1d, 
-0x39, 0x32, 0x14, 0x72, 0x80, 0x31, 0x4c, 0x72, 0x7b, 0x68, 0x83, 0x42, 
-0x06, 0xd9, 0x3b, 0x68, 0x5d, 0x1c, 0x3d, 0x60, 0x1b, 0x78, 0xc0, 0x46, 
-0x13, 0x72, 0x4b, 0x72, 0x15, 0x7a, 0x36, 0x23, 0x6b, 0x40, 0x13, 0x72, 
-0x4a, 0x7a, 0x5c, 0x23, 0x5a, 0x40, 0x4a, 0x72, 0x01, 0x30, 0x40, 0x28, 
-0xe4, 0xd3, 0x18, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 
-0xe0, 0xb0, 0x14, 0x1c, 0x0f, 0x1c, 0x00, 0x25, 0xae, 0x00, 0x01, 0x20, 
-0xf1, 0x1d, 0x1d, 0x31, 0x02, 0xf0, 0x10, 0xfe, 0x01, 0x04, 0x00, 0x91, 
-0x01, 0x20, 0xf1, 0x1d, 0x1b, 0x31, 0x02, 0xf0, 0x09, 0xfe, 0x00, 0x99, 
-0x08, 0x43, 0x19, 0xa9, 0x71, 0x18, 0x88, 0x60, 0x01, 0x35, 0x10, 0x2d, 
-0xea, 0xd3, 0x1b, 0xa8, 0x19, 0x90, 0x40, 0x20, 0x1a, 0x90, 0x19, 0xa8, 
-0xff, 0xf7, 0xa7, 0xff, 0x01, 0xa8, 0xff, 0xf7, 0xa6, 0xfe, 0x40, 0x22, 
-0x01, 0xa8, 0x2b, 0xa9, 0xff, 0xf7, 0x54, 0xff, 0x00, 0x2f, 0x0b, 0xd0, 
-0x40, 0x2f, 0x01, 0xd9, 0x40, 0x25, 0x00, 0xe0, 0x3d, 0x1c, 0x60, 0x99, 
-0x01, 0xa8, 0x2a, 0x1c, 0xff, 0xf7, 0x48, 0xff, 0x7f, 0x1b, 0xf3, 0xd1, 
-0x51, 0xa8, 0x01, 0xa9, 0x07, 0x1c, 0xff, 0xf7, 0x70, 0xff, 0x01, 0xa8, 
-0xff, 0xf7, 0x8b, 0xfe, 0x40, 0x22, 0x01, 0xa8, 0x3b, 0xa9, 0x01, 0x31, 
-0xff, 0xf7, 0x38, 0xff, 0x14, 0x22, 0x01, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 
-0x33, 0xff, 0x56, 0xa8, 0x01, 0xa9, 0xff, 0xf7, 0x5e, 0xff, 0x00, 0x20, 
-0x82, 0x00, 0x19, 0xa9, 0x51, 0x18, 0xc0, 0x31, 0x49, 0x6b, 0x02, 0xc4, 
-0x01, 0x30, 0x05, 0x28, 0xf6, 0xd3, 0x63, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 0x00, 0x24, 0x00, 0x2f, 
-0x04, 0xd3, 0x04, 0xf0, 0x15, 0xf9, 0x01, 0x34, 0xbc, 0x42, 0xfa, 0xd9, 
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x14, 0x1c, 0x0d, 0x1c, 
-0x06, 0x1c, 0x1f, 0x1c, 0x1b, 0x4b, 0x32, 0x04, 0x12, 0x0c, 0x3c, 0x21, 
-0x02, 0x20, 0xfd, 0xf7, 0x8a, 0xff, 0x32, 0x0c, 0x17, 0x4b, 0x3e, 0x21, 
-0x02, 0x20, 0xfd, 0xf7, 0x84, 0xff, 0x15, 0x4b, 0x2a, 0x04, 0x12, 0x0c, 
-0x40, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x7d, 0xff, 0x2a, 0x0c, 0x11, 0x4b, 
-0x42, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x77, 0xff, 0x0e, 0x4b, 0x22, 0x04, 
-0x12, 0x0c, 0x44, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x70, 0xff, 0x22, 0x0c, 
-0x0a, 0x4b, 0x46, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x6a, 0xff, 0x08, 0x4b, 
-0x3a, 0x04, 0x12, 0x0c, 0x48, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x63, 0xff, 
-0x3a, 0x0c, 0x04, 0x4b, 0x4a, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x5d, 0xff, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xd9, 0xbf, 0x21, 0x40, 
-0x88, 0xb5, 0x11, 0x27, 0x3f, 0x04, 0x38, 0x62, 0x79, 0x62, 0xba, 0x62, 
-0xfb, 0x62, 0x04, 0x20, 0xff, 0xf7, 0xaa, 0xff, 0x07, 0x48, 0x40, 0x6b, 
-0xc0, 0x46, 0x00, 0x90, 0x00, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, 
-0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 
-0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 
-0xf0, 0xb5, 0x8a, 0xb0, 0x00, 0x24, 0x05, 0x94, 0x69, 0x49, 0xc9, 0x68, 
-0xc0, 0x46, 0x00, 0x91, 0x68, 0x4a, 0x11, 0x68, 0x01, 0x22, 0x12, 0x04, 
-0x0a, 0x40, 0x17, 0x21, 0x66, 0x4e, 0x00, 0x2a, 0x06, 0xd1, 0x64, 0x4a, 
-0x13, 0x68, 0x1b, 0x0c, 0x04, 0xd1, 0x12, 0x68, 0x92, 0x0a, 0x01, 0xd3, 
-0xf1, 0x60, 0x02, 0xe0, 0x61, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0x61, 0x49, 
-0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x03, 0x29, 0x54, 0xd1, 0xe9, 0x21, 
-0x01, 0x91, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, 0x06, 0x94, 0x06, 0x99, 
-0x8a, 0x00, 0x5b, 0x49, 0x8a, 0x58, 0x00, 0x2a, 0x73, 0xd0, 0x80, 0x20, 
-0x02, 0x90, 0x06, 0x98, 0x81, 0x00, 0x57, 0x48, 0x41, 0x58, 0x02, 0x9a, 
-0x11, 0x43, 0x02, 0x91, 0x00, 0x24, 0x00, 0x27, 0x25, 0x02, 0x28, 0x1c, 
-0x38, 0x43, 0x09, 0x90, 0x09, 0x98, 0x00, 0x04, 0x51, 0x4b, 0x18, 0x43, 
-0x04, 0x90, 0x09, 0x98, 0xef, 0x23, 0xdb, 0x05, 0x18, 0x43, 0x03, 0x90, 
-0x06, 0x98, 0x80, 0x00, 0x4b, 0x49, 0x08, 0x58, 0x00, 0x04, 0x03, 0x99, 
-0x08, 0x43, 0x03, 0x90, 0x00, 0x2f, 0x02, 0xd1, 0x03, 0x98, 0xc0, 0x46, 
-0x70, 0x60, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, 
-0x89, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, 
-0x03, 0x99, 0xc0, 0x46, 0x71, 0x60, 0x5c, 0xe0, 0x79, 0x1c, 0x0f, 0x04, 
-0x3f, 0x0c, 0x17, 0x2f, 0xd1, 0xdd, 0x61, 0x1c, 0x0c, 0x04, 0x24, 0x0c, 
-0x16, 0x2c, 0xca, 0xdd, 0x06, 0x99, 0x01, 0x31, 0x06, 0x91, 0x06, 0x99, 
-0x89, 0x00, 0x37, 0x4a, 0x51, 0x58, 0x00, 0x29, 0xb7, 0xd1, 0x48, 0xe0, 
-0xbf, 0x21, 0xc9, 0x43, 0x04, 0x91, 0xff, 0x21, 0x02, 0x91, 0x97, 0x21, 
-0x01, 0x91, 0x06, 0x94, 0x06, 0x99, 0x89, 0x00, 0x31, 0x4f, 0x79, 0x58, 
-0x00, 0x29, 0x1c, 0xd0, 0x09, 0x94, 0x08, 0x94, 0x06, 0x98, 0x80, 0x00, 
-0x38, 0x58, 0xc0, 0x46, 0x07, 0x90, 0x07, 0x98, 0x00, 0x04, 0x26, 0xe0, 
-0x05, 0x98, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x03, 0x90, 0x01, 0x9b, 
-0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, 0x49, 0xff, 0x00, 0x28, 
-0x23, 0xd1, 0x09, 0x99, 0x01, 0x31, 0x09, 0x91, 0x17, 0x29, 0x06, 0xd8, 
-0x00, 0xe0, 0x1c, 0xe0, 0x08, 0x98, 0x00, 0x02, 0x09, 0x99, 0x08, 0x43, 
-0x07, 0xe0, 0x08, 0x99, 0x01, 0x31, 0x08, 0x91, 0x17, 0x29, 0x0a, 0xd8, 
-0x09, 0x94, 0x08, 0x98, 0x00, 0x02, 0x07, 0x99, 0x09, 0x04, 0x08, 0x43, 
-0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x05, 0x90, 0xd6, 0xe7, 0x06, 0x99, 
-0x01, 0x31, 0x06, 0x91, 0x06, 0x99, 0x89, 0x00, 0x79, 0x58, 0x00, 0x29, 
-0xc4, 0xd1, 0x0c, 0x4a, 0x11, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x11, 0x68, 
-0x09, 0x0c, 0x06, 0xd1, 0x11, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x00, 0x99, 
-0xc0, 0x46, 0xf1, 0x60, 0x03, 0xe0, 0x00, 0x99, 0x06, 0x4a, 0xc0, 0x46, 
-0x11, 0x64, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x40, 0x01, 0x18, 0x40, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x18, 0x40, 0x30, 0x6e, 0x21, 0x40, 
-0x43, 0xff, 0x00, 0x00, 0x0c, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x82, 0xb0, 
-0x00, 0x20, 0x01, 0x90, 0x1e, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x1b, 0xd1, 
-0x40, 0x88, 0x00, 0x28, 0x18, 0xd1, 0x68, 0x46, 0x01, 0xf0, 0x9a, 0xfe, 
-0x00, 0x28, 0x13, 0xd1, 0xa8, 0x20, 0x01, 0xf0, 
-0xdb, 0xfe, 0x18, 0x4f, 0x00, 0x28, 0x11, 0xd0, 0x04, 0x20, 0xff, 0xf7, 
-0x97, 0xfe, 0x78, 0x6b, 0xc0, 0x46, 0x01, 0x90, 0x01, 0x98, 0x80, 0x07, 
-0x80, 0x0f, 0x03, 0x28, 0x06, 0xd1, 0x00, 0x20, 0x01, 0xf0, 0xca, 0xfe, 
-0x02, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23, 0x00, 0x22, 
-0x00, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfe, 0x00, 0x23, 0xdb, 0x43, 
-0x18, 0x1c, 0x19, 0x1c, 0x1a, 0x1c, 0xff, 0xf7, 0xc7, 0xfe, 0x00, 0x28, 
-0x03, 0xd1, 0xff, 0xf7, 0xdf, 0xfe, 0x00, 0x28, 0xe5, 0xd0, 0x38, 0x6a, 
-0x79, 0x6a, 0xba, 0x6a, 0xfb, 0x6a, 0xff, 0xf7, 0x7c, 0xfe, 0xde, 0xe7, 
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x11, 0x40, 0xff, 0xb5, 0x85, 0xb0, 
-0x14, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x01, 0x23, 0x5b, 0x04, 
-0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x82, 0xe0, 0x26, 0x1c, 0x43, 0x4d, 
-0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x41, 0x48, 
-0x41, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, 
-0x00, 0xd8, 0x3d, 0x1c, 0x3e, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, 
-0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0xff, 0x23, 0x01, 0x33, 0x19, 0x43, 
-0x39, 0x4b, 0xc0, 0x46, 0x59, 0x61, 0xff, 0x23, 0x01, 0x33, 0x9a, 0x43, 
-0x36, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 
-0x33, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x31, 0x4a, 
-0xff, 0x23, 0x01, 0x33, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, 0x01, 0x22, 
-0x12, 0x05, 0x11, 0x61, 0x85, 0x21, 0x89, 0x04, 0x04, 0x91, 0x00, 0x2f, 
-0x34, 0xd0, 0x28, 0x48, 0x86, 0x42, 0x04, 0xd1, 0x30, 0x1c, 0x21, 0x1c, 
-0x2a, 0x1c, 0x03, 0xf0, 0x4f, 0xff, 0x2a, 0x1c, 0x04, 0x98, 0x02, 0x43, 
-0x00, 0x92, 0x01, 0x20, 0x06, 0x99, 0x05, 0x9a, 0x33, 0x1c, 0xfd, 0xf7, 
-0xbd, 0xfd, 0x22, 0x48, 0x22, 0x49, 0x4a, 0x68, 0x52, 0x0a, 0x09, 0xd3, 
-0xff, 0x21, 0x01, 0x31, 0x20, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x00, 0x28, 
-0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x13, 0xe0, 0x01, 0x38, 0xf0, 0xd1, 
-0xf9, 0xe7, 0x7f, 0x1b, 0x0e, 0xd0, 0x15, 0x48, 0x86, 0x42, 0x01, 0xd1, 
-0x64, 0x19, 0x00, 0xe0, 0x76, 0x19, 0x06, 0x99, 0x49, 0x19, 0x06, 0x91, 
-0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, 0x05, 0x1c, 0xca, 0xe7, 
-0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 
-0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 
-0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, 
-0x81, 0x61, 0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x50, 0xab, 0x20, 0x40, 
-0x00, 0x00, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 
-0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0xb0, 0xff, 0xb5, 0x85, 0xb0, 
-0x04, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x01, 0x23, 0x5b, 0x04, 
-0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x7d, 0xe0, 0x26, 0x1c, 0x40, 0x4d, 
-0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x3e, 0x48, 
-0x3e, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, 
-0x00, 0xd8, 0x3d, 0x1c, 0x3b, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, 
-0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0x10, 0x23, 0x19, 0x43, 0x37, 0x4b, 
-0xc0, 0x46, 0x59, 0x61, 0x10, 0x23, 0x9a, 0x43, 
-0x34, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 
-0x31, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x2f, 0x4a, 
-0x10, 0x23, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, 0x1a, 0x04, 0x11, 0x61, 
-0x21, 0x21, 0x09, 0x05, 0x04, 0x91, 0x00, 0x2f, 0x33, 0xd0, 0x2a, 0x1c, 
-0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x00, 0x20, 0x06, 0x99, 0x07, 0x9a, 
-0x33, 0x1c, 0xfd, 0xf7, 0x27, 0xfd, 0x25, 0x48, 0x25, 0x49, 0x4a, 0x68, 
-0x52, 0x09, 0x08, 0xd3, 0x10, 0x21, 0x24, 0x4a, 0xc0, 0x46, 0x11, 0x60, 
-0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x1b, 0xe0, 0x01, 0x38, 
-0xf1, 0xd1, 0xf9, 0xe7, 0x19, 0x48, 0x86, 0x42, 0x04, 0xd1, 0x20, 0x1c, 
-0x31, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0x96, 0xfe, 0x7f, 0x1b, 0x0e, 0xd0, 
-0x14, 0x48, 0x86, 0x42, 0x01, 0xd0, 0x76, 0x19, 0x00, 0xe0, 0x64, 0x19, 
-0x06, 0x99, 0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, 
-0x28, 0x1c, 0x05, 0x1c, 0xcb, 0xe7, 0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, 
-0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, 
-0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, 
-0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, 0x11, 0x61, 0x01, 0x98, 
-0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xff, 0x00, 0x00, 
-0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0xb0, 
 0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30, 
 0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40, 
 0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42, 
@@ -2987,7 +2639,7 @@ const u8 typhoon_firmware_image[] = {
 0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69, 
 0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc, 
 0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb, 
-0x38, 0x1c, 0xf6, 0xe7, 0xd0, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0, 
+0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0, 
 0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0, 
 0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58, 
 0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0, 
@@ -2998,12 +2650,12 @@ const u8 typhoon_firmware_image[] = {
 0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06, 
 0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c, 
 0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22, 
-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 
-0x00, 0xf0, 0x68, 0xfa, 0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 
-0x49, 0x0c, 0x89, 0x05, 0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 
-0x45, 0x9b, 0x9a, 0x42, 0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 
-0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 
-0x00, 0xf0, 0x50, 0xfa, 0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06, 
+0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa, 
+0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 
+0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42, 
+0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92, 
+0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa, 
+0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06, 
 0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22, 
 0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 
 0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1, 
@@ -3019,7 +2671,7 @@ const u8 typhoon_firmware_image[] = {
 0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21, 
 0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60, 
 0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20, 
-0xf9, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23, 
+0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23, 
 0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06, 
 0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06, 
 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28, 
@@ -3041,12 +2693,12 @@ const u8 typhoon_firmware_image[] = {
 0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43, 
 0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21, 
 0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99, 
-0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 
-0x08, 0x43, 0x05, 0x90, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 
-0x00, 0xf0, 0xca, 0xf9, 0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 
-0x50, 0x50, 0xc1, 0x43, 0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 
-0x61, 0x61, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb, 
+0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90, 
+0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9, 
+0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43, 
+0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 
+0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb, 
 0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d, 
 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0, 
 0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0, 
@@ -3054,7 +2706,7 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b, 
 0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19, 
 0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00, 
-0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 
+0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 
 0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49, 
 0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43, 
 0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c, 
@@ -3070,7 +2722,7 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 
 0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98, 
 0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98, 
-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, 
+0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40, 
 0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91, 
 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58, 
 0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda, 
@@ -3084,12 +2736,12 @@ const u8 typhoon_firmware_image[] = {
 0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c, 
 0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19, 
 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b, 
-0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 
-0x01, 0x1c, 0x00, 0x9e, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 
-0xcb, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 
-0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 
-0x00, 0x27, 0x00, 0x2f, 0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0, 
+0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e, 
+0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68, 
+0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 
+0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f, 
+0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0, 
 0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00, 
 0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2, 
 0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09, 
@@ -3098,222 +2750,222 @@ const u8 typhoon_firmware_image[] = {
 0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1, 
 0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06, 
 0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c, 
-0xdb, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20, 
+0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20, 
 0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47, 
-0xd0, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x01, 0xfa, 0x57, 0x20, 
-0x02, 0xf0, 0x5e, 0xf9, 0x02, 0xf0, 0xd2, 0xf8, 0x00, 0x0a, 0xfb, 0xd3, 
-0x02, 0xf0, 0xe0, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0, 
+0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20, 
+0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3, 
+0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0, 
 0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23, 
 0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32, 
 0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c, 
-0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0xdd, 0xf9, 0x53, 0x20, 
-0x02, 0xf0, 0x3a, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0, 
-0x35, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x32, 0xf9, 0x30, 0x1c, 0x02, 0xf0, 
-0x2f, 0xf9, 0x02, 0xf0, 0xb5, 0xf9, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0, 
-0xc9, 0xf9, 0x54, 0x20, 0x02, 0xf0, 0x26, 0xf9, 0x00, 0x98, 0x02, 0xf0, 
-0x23, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x20, 0xf9, 0x30, 0x1c, 0x14, 0xe0, 
-0x02, 0xf0, 0xbc, 0xf9, 0x52, 0x20, 0x02, 0xf0, 0x19, 0xf9, 0x01, 0x98, 
-0x02, 0xf0, 0x16, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x13, 0xf9, 0x30, 0x1c, 
-0x02, 0xf0, 0x10, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x0d, 0xf9, 0x00, 0x20, 
-0x02, 0xf0, 0x0a, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x07, 0xf9, 0x00, 0x20, 
-0x02, 0xf0, 0x04, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0x76, 0xf8, 
-0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0x82, 0xf9, 
+0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20, 
+0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0, 
+0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0, 
+0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0, 
+0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0, 
+0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0, 
+0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98, 
+0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c, 
+0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20, 
+0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20, 
+0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8, 
+0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9, 
 0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
-0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x40, 0x02, 0x08, 0x43, 
-0x05, 0x1c, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 
-0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
-0x02, 0xf0, 0x7a, 0xf9, 0x53, 0x20, 0x02, 0xf0, 0xd7, 0xf8, 0x28, 0x0c, 
-0x06, 0x1c, 0x02, 0xf0, 0xd3, 0xf8, 0x28, 0x0a, 0x01, 0x90, 0x00, 0x90, 
-0x02, 0xf0, 0xce, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xcb, 0xf8, 0x02, 0xf0, 
-0x51, 0xf9, 0xff, 0xf7, 0x63, 0xff, 0x02, 0xf0, 0x65, 0xf9, 0x84, 0x20, 
-0x02, 0xf0, 0xc2, 0xf8, 0x30, 0x1c, 0x02, 0xf0, 
-0xbf, 0xf8, 0x00, 0x98, 0x02, 0xf0, 0xbc, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 
-0xb9, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0, 
-0xb3, 0xf8, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0x37, 0xf9, 0x02, 0xf0, 
-0x4d, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0xaa, 0xf8, 0x30, 0x1c, 0x02, 0xf0, 
-0xa7, 0xf8, 0x01, 0x98, 0x02, 0xf0, 0xa4, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 
-0xa1, 0xf8, 0x02, 0xf0, 0x27, 0xf9, 0xff, 0xf7, 0x39, 0xff, 0x07, 0x49, 
-0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 
-0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x02, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 
-0x80, 0xb5, 0x01, 0xf0, 0x91, 0xf8, 0x06, 0x4f, 0xc0, 0x46, 0xf8, 0x60, 
-0x01, 0xf0, 0xf4, 0xf8, 0x78, 0x80, 0x01, 0xf0, 0xb3, 0xf8, 0x38, 0x71, 
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
-0x00, 0xb5, 0x01, 0xf0, 0x07, 0xf9, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x80, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0xc1, 0x68, 
-0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23, 0x0a, 0x68, 0x1a, 0x43, 
-0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 
-0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 
-0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
-0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32, 0x00, 0x20, 0x00, 0x27, 
-0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28, 0xfa, 0xd3, 0x46, 0x4c, 
-0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 
-0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x20, 0x28, 
-0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65, 0x8f, 0x65, 0x3f, 0x4d, 
-0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60, 0xaf, 0x61, 0xef, 0x60, 
-0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00, 0x09, 0x18, 0x49, 0x01, 
-0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d, 0xf9, 0x33, 0x34, 0x4c, 
-0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01, 0xcb, 0x18, 0x63, 0x63, 
-0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18, 0xe3, 0x63, 0x23, 0x23, 
-0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30, 0x02, 0x28, 0xe4, 0xdb, 
-0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c, 0xc0, 0x46, 0xa1, 0x62, 
-0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62, 0xc1, 0x18, 0x91, 0x62, 
-0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21, 0xe1, 0x64, 0x25, 0x49, 
-0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69, 0xc0, 0x46, 0x63, 0x65, 
-0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66, 0x8b, 0x68, 0xc0, 0x46, 
-0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66, 0x1e, 0x4b, 0xc0, 0x46, 
-0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01, 0xc3, 0x18, 0xa3, 0x67, 
-0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33, 0x66, 0x61, 0xe7, 0x61, 
-0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b, 0xc0, 0x46, 0x13, 0x65, 
-0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d, 0x51, 0x33, 0xd3, 0x65, 
-0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46, 0x53, 0x66, 0x89, 0x69, 
-0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46, 0xd1, 0x66, 0x16, 0x67, 
-0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67, 0x56, 0x67, 0xd7, 0x61, 
-0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73, 
+0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43, 
+0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23, 
+0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68, 
+0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0, 
+0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a, 
+0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 
+0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0, 
+0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0, 
+0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 
+0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0, 
+0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0, 
+0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0, 
+0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9, 
+0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7, 
+0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43, 
+0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f, 
+0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0, 
+0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49, 
+0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23, 
+0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68, 
+0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68, 
+0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00, 
+0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32, 
+0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28, 
+0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30, 
+0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50, 
+0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65, 
+0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60, 
+0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00, 
+0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d, 
+0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01, 
+0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18, 
+0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30, 
+0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c, 
+0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62, 
+0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21, 
+0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69, 
+0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66, 
+0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66, 
+0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01, 
+0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33, 
+0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b, 
+0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d, 
+0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46, 
+0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46, 
+0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67, 
+0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73, 
 0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 
-0x64, 0x2d, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00, 
-0x7c, 0x29, 0x00, 0x80, 0xec, 0x54, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00, 
-0xfc, 0x54, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23, 
-0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23, 0xdb, 0x01, 0xd0, 0x18, 
-0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18, 0xc1, 0x61, 0x1c, 0x70, 
-0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60, 0xb9, 0x73, 0x59, 0x61, 
-0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60, 0x13, 0x4b, 0x51, 0x27, 
-0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69, 0xe4, 0x18, 0x44, 0x63, 
-0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02, 0x84, 0x63, 0x0e, 0x4c, 
-0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46, 0x44, 0x62, 0x84, 0x69, 
-0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60, 0x03, 0x6b, 0xc0, 0x46, 
-0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62, 0xc1, 0x63, 0x51, 0x64, 
-0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0xfc, 0x07, 0x00, 0x00, 
-0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22, 0x1b, 0x49, 0xc9, 0x23, 
-0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 
-0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c, 0x00, 0x27, 0xdc, 0x1d, 
-0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37, 0x3f, 0x2f, 0xf8, 0xd3, 
-0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18, 0x33, 0x23, 0x9b, 0x01, 
-0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20, 0xf8, 0x60, 0xda, 0x61, 
-0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48, 0xc0, 0x46, 0xc2, 0x60, 
-0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e, 0xf8, 0x63, 0x0a, 0x48, 
-0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68, 0xc0, 0x46, 0x59, 0x80, 
-0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x3c, 0xbd, 0x20, 0x40, 0x3c, 0xef, 0x20, 0x40, 
-0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40, 0x00, 0x20, 0x0a, 0x49, 
-0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33, 0x3a, 0x33, 0x88, 0x61, 
-0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46, 0x10, 0x65, 0x50, 0x66, 
-0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23, 0x1b, 0x01, 0xd1, 0x18, 
-0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 
-0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46, 0x11, 0x61, 0x01, 0x23, 
-0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48, 0xc0, 0x46, 0x10, 0x62, 
-0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23, 0x13, 0x63, 0x53, 0x63, 
-0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34, 0xfa, 0x34, 0x14, 0xc7, 
-0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61, 0x26, 0x4f, 0xc0, 0x46, 
-0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62, 0x3b, 0x63, 0x7b, 0x64, 
-0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d, 0xf9, 0x36, 0x22, 0x4d, 
-0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26, 0xb6, 0x03, 0x37, 0x61, 
-0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67, 0x1d, 0x4d, 0x09, 0x27, 
-0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60, 0x3d, 0x60, 0x1b, 0x4c, 
-0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36, 0x7e, 0x61, 0x19, 0x4f, 
-0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c, 
+0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00, 
+0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00, 
+0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23, 
+0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23, 
+0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18, 
+0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60, 
+0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60, 
+0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69, 
+0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02, 
+0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46, 
+0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60, 
+0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62, 
+0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 
+0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22, 
+0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20, 
+0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c, 
+0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37, 
+0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18, 
+0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20, 
+0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48, 
+0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e, 
+0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68, 
+0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40, 
+0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40, 
+0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33, 
+0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46, 
+0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23, 
+0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80, 
+0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46, 
+0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48, 
+0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23, 
+0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34, 
+0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61, 
+0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62, 
+0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d, 
+0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26, 
+0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67, 
+0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60, 
+0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36, 
+0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c, 
 0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50, 
 0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27, 
 0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3, 
 0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3, 
-0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40, 0x40, 0x01, 0x18, 0x00, 
-0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x80, 0x01, 0x18, 0x00, 
-0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0x08, 0x04, 0x00, 0x80, 
-0xb8, 0xb5, 0x2c, 0x48, 0xfc, 0xf7, 0x0a, 0xff, 0x01, 0x20, 0x2b, 0x49, 
-0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 
-0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x04, 0x06, 0x24, 0x0e, 
-0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23, 0x00, 0x20, 0x9d, 0x00, 
-0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3, 0x01, 0x27, 0x3f, 0x05, 
-0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61, 0x00, 0x23, 0xdb, 0x43, 
-0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62, 0x00, 0x27, 0x1b, 0x4b, 
-0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69, 0xc0, 0x46, 0x00, 0x95, 
-0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x9d, 0x6b, 
-0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x1d, 0x6b, 
-0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f, 0xe8, 0xd3, 0x00, 0x27, 
-0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43, 0x01, 0xe0, 0x20, 0x60, 
-0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2, 0x80, 0x2f, 0xf8, 0xd3, 
-0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49, 0x4b, 0x6e, 0x01, 0x33, 
-0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x00, 0x21, 
-0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01, 0x64, 0x1a, 0xa4, 0x00, 
-0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64, 0x58, 0x64, 0x10, 0x53, 
-0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67, 0xdc, 0x62, 0x01, 0x31, 
-0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x48, 0x60, 
-0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 
-0x58, 0x67, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, 
-0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63, 0x00, 0x21, 0xc9, 0x43, 
-0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63, 0x01, 0x64, 0x70, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20, 0x40, 0x02, 0x0a, 0x49, 
-0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60, 0x88, 0x60, 0x08, 0x48, 
-0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a, 0x87, 0x00, 0xcb, 0x68, 
-0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28, 0xf8, 0xd3, 0x80, 0xbc, 
-0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xf4, 0x2d, 0x00, 0x80, 
-0x49, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48, 0x67, 0x23, 0x9b, 0x01, 
-0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b, 0xca, 0x18, 0xc1, 0x60, 
-0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48, 0xa7, 0x23, 0x9b, 0x01, 
-0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b, 0xca, 0x18, 0xc1, 0x60, 
-0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49, 
+0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40, 
+0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 
+0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 
+0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd, 
+0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68, 
+0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20, 
+0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23, 
+0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3, 
+0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61, 
+0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62, 
+0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69, 
+0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46, 
+0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46, 
+0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f, 
+0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43, 
+0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2, 
+0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49, 
+0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40, 
+0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01, 
+0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64, 
+0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67, 
+0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80, 
+0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63, 
+0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63, 
+0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20, 
+0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60, 
+0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a, 
+0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28, 
+0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 
+0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48, 
+0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b, 
+0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48, 
+0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b, 
+0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49, 
 0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b, 
 0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00, 
-0x58, 0x1f, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00, 
-0x58, 0xef, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00, 
-0x58, 0x3f, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, 
-0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19, 0x19, 0x23, 0xdb, 0x01, 
-0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63, 0x90, 0x63, 0x01, 0x31, 
-0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46, 0x08, 0x63, 0x48, 0x63, 
-0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d, 0x59, 0x33, 0x60, 0x60, 
-0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72, 0x59, 0x71, 0x58, 0x72, 
-0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32, 0x11, 0x73, 0x19, 0x70, 
-0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70, 0xd0, 0x73, 0xd8, 0x70, 
-0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72, 0x50, 0x71, 0x50, 0x72, 
-0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22, 0xe7, 0x1d, 0x69, 0x37, 
-0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73, 0x78, 0x70, 0xd8, 0x73, 
-0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 
-0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73, 0xe3, 0x1d, 0x79, 0x33, 
-0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 
-0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71, 0x9a, 0x72, 0x58, 0x71, 
-0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73, 0xe7, 0x1d, 0x89, 0x37, 
-0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73, 0x7a, 0x70, 0xd9, 0x73, 
-0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 
-0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73, 0xe3, 0x1d, 0x99, 0x33, 
-0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 
-0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71, 0x99, 0x72, 0x58, 0x71, 
-0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61, 0xe0, 0x60, 0x60, 0x61, 
-0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 
-0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02, 0x01, 0x49, 0xc0, 0x46, 
-0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x09, 0x49, 0x0a, 0x4b, 
-0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60, 0x00, 0x21, 0xc2, 0x1d, 
-0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31, 0x08, 0x29, 0xf8, 0xd3, 
-0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61, 0x70, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00, 0x06, 0x48, 0x07, 0x49, 
-0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20, 0x88, 0x80, 0xc8, 0x80, 
-0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x88, 0x61, 0x70, 0x47, 
-0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
-0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32, 0xc1, 0x60, 0x01, 0x61, 
-0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 
-0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x09, 0x48, 0x0a, 0x4b, 
-0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d, 0x4d, 0x32, 0xc2, 0x60, 
-0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x4d, 0x39, 
-0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60, 0x70, 0x47, 0x00, 0x00, 
-0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
-0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfc, 0xf7, 0x3a, 0xfd, 0x0b, 0x48, 
+0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00, 
+0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00, 
+0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80, 
+0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19, 
+0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63, 
+0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46, 
+0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d, 
+0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72, 
+0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32, 
+0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70, 
+0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72, 
+0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22, 
+0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73, 
+0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 
+0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73, 
+0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73, 
+0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71, 
+0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73, 
+0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73, 
+0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 
+0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73, 
+0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73, 
+0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71, 
+0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61, 
+0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 
+0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02, 
+0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 
+0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60, 
+0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31, 
+0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61, 
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00, 
+0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20, 
+0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61, 
+0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 
+0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32, 
+0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30, 
+0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 
+0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d, 
+0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3, 
+0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60, 
+0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 
+0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48, 
 0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46, 
 0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f, 
 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47, 
-0x8d, 0xd5, 0x21, 0x40, 0xc1, 0xa8, 0x21, 0x40, 0xc0, 0x00, 0x18, 0x40, 
-0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x0f, 0x48, 
-0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68, 
-0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48, 0x0c, 0x4a, 0x00, 0x21, 
-0xfc, 0xf7, 0x0f, 0xfd, 0x0b, 0x48, 0x41, 0x8d, 0x01, 0x31, 0x41, 0x85, 
-0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 
-0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x08, 0xbc, 0x18, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0x25, 0xd5, 0x21, 0x40, 0xc1, 0xa8, 0x21, 0x40, 
-0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 
-0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0xfe, 0xf7, 0x9b, 0xfe, 0x1b, 0x4c, 
+0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40, 
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f, 
+0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48, 
+0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d, 
+0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a, 
+0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40, 
+0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c, 
 0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28, 
 0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67, 
 0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18, 
@@ -3342,12 +2994,12 @@ const u8 typhoon_firmware_image[] = {
 0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b, 
 0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33, 
 0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43, 
-0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 
-0x01, 0x23, 0x9b, 0x07, 0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 
-0x63, 0x60, 0x08, 0x30, 0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 
-0x3f, 0x48, 0x03, 0x03, 0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 
-0x01, 0x23, 0x1b, 0x03, 0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 
-0x01, 0x33, 0x63, 0x62, 0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a, 
+0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07, 
+0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30, 
+0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03, 
+0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03, 
+0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62, 
+0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a, 
 0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34, 
 0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c, 
 0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42, 
@@ -3363,12 +3015,12 @@ const u8 typhoon_firmware_image[] = {
 0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44, 
 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03, 
 0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b, 
-0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfc, 0xf7, 0xc2, 0xfb, 0x41, 0xb0, 
+0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0, 
 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
 0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40, 
 0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 
 0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, 
-0xb5, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22, 
+0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22, 
 0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33, 
 0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61, 
 0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61, 
@@ -3385,12 +3037,12 @@ const u8 typhoon_firmware_image[] = {
 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 
 0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 
 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25, 
-0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 
-0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 
-0x04, 0x23, 0x03, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 
-0x00, 0x25, 0x3d, 0x61, 0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 
-0x00, 0x20, 0x3d, 0x61, 0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 
-0x02, 0x23, 0x33, 0x40, 0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30, 
+0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 
+0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43, 
+0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61, 
+0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61, 
+0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40, 
+0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30, 
 0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61, 
 0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08, 
 0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 
@@ -3419,21 +3071,21 @@ const u8 typhoon_firmware_image[] = {
 0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61, 
 0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 
 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d, 
-0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfc, 0xf7, 0x75, 0xfa, 0x4d, 0x4c, 
+0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c, 
 0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20, 
-0x2a, 0x1c, 0xfc, 0xf7, 0x6b, 0xfa, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28, 
+0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28, 
 0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1, 
 0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02, 
 0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28, 
 0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21, 
 0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26, 
 0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe, 
-0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 
-0x00, 0x25, 0x05, 0xe0, 0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 
-0x2b, 0xff, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 
-0x01, 0xd2, 0xb5, 0x42, 0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 
-0xff, 0x23, 0xe1, 0x33, 0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 
-0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01, 
+0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0, 
+0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35, 
+0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42, 
+0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33, 
+0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33, 
+0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01, 
 0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28, 
 0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23, 
 0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28, 
@@ -3445,7 +3097,7 @@ const u8 typhoon_firmware_image[] = {
 0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f, 
 0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19, 
 0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f, 
-0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0xbf, 0x21, 0x40, 
+0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40, 
 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48, 
 0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91, 
 0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91, 
@@ -3471,12 +3123,12 @@ const u8 typhoon_firmware_image[] = {
 0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b, 
 0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1, 
 0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40, 
-0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 
-0x98, 0x43, 0xf8, 0x83, 0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 
-0x1f, 0xd0, 0xb9, 0x8b, 0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 
-0xff, 0x23, 0x01, 0x98, 0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 
-0x00, 0x98, 0x01, 0x28, 0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 
-0x02, 0xd1, 0x01, 0x23, 0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0, 
+0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83, 
+0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b, 
+0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98, 
+0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28, 
+0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 
+0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0, 
 0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20, 
 0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2, 
 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20, 
@@ -3504,7 +3156,7 @@ const u8 typhoon_firmware_image[] = {
 0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20, 
 0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab, 
 0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91, 
-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfc, 0xf7, 0xd5, 0xf9, 0x04, 0xb0, 
+0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0, 
 0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68, 
 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, 
 0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, 
@@ -3514,12 +3166,12 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 
 0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24, 
 0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68, 
-0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 
-0x00, 0xd2, 0x00, 0x21, 0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 
-0x02, 0xd0, 0x38, 0x68, 0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 
-0x00, 0x0c, 0x10, 0x4b, 0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 
-0x05, 0xd0, 0x0e, 0x4b, 0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 
-0x0c, 0xd1, 0x00, 0x29, 0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0, 
+0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21, 
+0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68, 
+0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b, 
+0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b, 
+0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29, 
+0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0, 
 0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e, 
 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40, 
 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00, 
@@ -3549,47 +3201,36 @@ const u8 typhoon_firmware_image[] = {
 0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03, 
 0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21, 
 0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e, 
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x98, 0x6e, 0x21, 0x40, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40, 
 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 
-0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x83, 0xb0, 
-0x07, 0x1c, 0x01, 0x20, 0x02, 0x90, 0x01, 0x25, 0x02, 0x24, 0x10, 0x26, 
-0x20, 0x21, 0x00, 0x91, 0xff, 0xf7, 0xe2, 0xfe, 0x01, 0x28, 0x4d, 0xd1, 
-0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x3a, 0xd1, 0x2e, 0x4e, 0x3c, 0x21, 
-0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 0x4c, 0xff, 0x3e, 0x21, 0x05, 0x1c, 
-0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 0x46, 0xff, 0x00, 0x04, 0x05, 0x43, 
-0x40, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 
-0x3f, 0xff, 0x01, 0x90, 0x42, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 
-0x39, 0xff, 0x00, 0x04, 0x01, 0x99, 0x08, 0x43, 0x06, 0x1c, 0xa8, 0x2f, 
-0x1b, 0xd1, 0x1f, 0x4a, 0x44, 0x21, 0x02, 0x20, 0xfb, 0xf7, 0x2e, 0xff, 
-0x04, 0x1c, 0x1c, 0x4a, 0x46, 0x21, 0x02, 0x20, 0xfb, 0xf7, 0x28, 0xff, 
-0x00, 0x04, 0x04, 0x43, 0x18, 0x4a, 0x48, 0x21, 0x02, 0x20, 0xfb, 0xf7, 
-0x21, 0xff, 0x00, 0x90, 0x15, 0x4a, 0x4a, 0x21, 0x02, 0x20, 0xfb, 0xf7, 
-0x1b, 0xff, 0x00, 0x04, 0x00, 0x99, 0x01, 0x43, 0x00, 0x91, 0x28, 0x1c, 
-0x30, 0x43, 0x20, 0x43, 0x00, 0x99, 0x08, 0x43, 0x00, 0xd1, 0x16, 0xe0, 
-0x11, 0x20, 0x00, 0x04, 0x05, 0x62, 0x46, 0x62, 0x84, 0x62, 0x00, 0x99, 
-0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x0a, 0x48, 0xc0, 0x46, 0x01, 0x60, 
-0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21, 0x01, 0x60, 
-0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x02, 0x98, 0x03, 0xb0, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x79, 0xbf, 0x21, 0x40, 
-0x98, 0x6e, 0x21, 0x40, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
-0x90, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 
-0x0b, 0xd0, 0x00, 0x23, 0x21, 0x1c, 0xe2, 0x1d, 0xc5, 0x32, 0x00, 0xe0, 
-0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xcc, 0x20, 0xa0, 0x80, 
+0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0, 
+0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28, 
+0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26, 
+0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96, 
+0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62, 
+0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46, 
+0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21, 
+0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98, 
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40, 
+0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 
+0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23, 
+0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0, 
+0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80, 
 0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48, 
 0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19, 
 0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80, 
 0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80, 
-0xee, 0xff, 0xc0, 0xd0, 0x02, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a, 
-0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7b, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23, 
-0x0b, 0x73, 0x07, 0x1c, 0x08, 0x7b, 0x43, 0x1c, 0x0b, 0x73, 0x80, 0x18, 
-0x90, 0x30, 0x47, 0x73, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80, 
+0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a, 
+0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23, 
+0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18, 
+0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80, 
 0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20, 
 0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68, 
 0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40, 
 0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7, 
-0xab, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42, 
-0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfb, 0xf7, 
-0xdf, 0xff, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x67, 0x21, 0x40, 
+0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42, 
+0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7, 
+0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40, 
 0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c, 
 0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89, 
 0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c, 
@@ -3600,23 +3241,23 @@ const u8 typhoon_firmware_image[] = {
 0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22, 
 0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88, 
 0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23, 
-0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 
-0x15, 0xd1, 0x58, 0x49, 0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 
-0xc0, 0x46, 0x42, 0x81, 0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 
-0xf0, 0x80, 0x58, 0x20, 0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 
-0x8d, 0xfa, 0xf0, 0x88, 0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 
-0x01, 0x35, 0x2d, 0x04, 0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 
-0x00, 0x25, 0x1d, 0x80, 0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 
-0xce, 0xdc, 0x81, 0xe0, 0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 
-0xf9, 0x7a, 0x00, 0x29, 0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 
-0x79, 0x64, 0x2a, 0xd0, 0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 
-0x01, 0x31, 0xe1, 0x80, 0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 
-0xdb, 0x03, 0x78, 0x6c, 0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 
-0x00, 0xe0, 0x63, 0xe0, 0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 
-0x49, 0x01, 0x40, 0x18, 0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 
-0x79, 0xfa, 0xe0, 0x6a, 0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 
-0x80, 0x18, 0x01, 0x39, 0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 
-0xf3, 0xfa, 0xb6, 0xe7, 0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04, 
+0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49, 
+0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81, 
+0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20, 
+0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88, 
+0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04, 
+0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80, 
+0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0, 
+0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29, 
+0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0, 
+0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80, 
+0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c, 
+0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0, 
+0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 
+0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a, 
+0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39, 
+0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7, 
+0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04, 
 0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80, 
 0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b, 
 0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d, 
@@ -3624,14 +3265,14 @@ const u8 typhoon_firmware_image[] = {
 0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88, 
 0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30, 
 0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19, 
-0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfa, 0x71, 0x88, 
+0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88, 
 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0, 
-0xb7, 0xfa, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35, 
+0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35, 
 0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25, 
 0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc, 
 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc, 
 0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 
-0x70, 0x67, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03, 
+0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03, 
 0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d, 
 0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a, 
 0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e, 
@@ -3643,23 +3284,23 @@ const u8 typhoon_firmware_image[] = {
 0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a, 
 0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a, 
 0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88, 
-0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 
-0x88, 0x81, 0x24, 0x49, 0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 
-0x00, 0x2e, 0x38, 0xd9, 0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 
-0x00, 0x2b, 0x2c, 0xd0, 0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 
-0xad, 0x6a, 0x58, 0x23, 0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 
-0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 
-0xce, 0x81, 0xa8, 0x60, 0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 
-0xed, 0x18, 0xe8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 
-0xed, 0x18, 0x68, 0x64, 0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 
-0xeb, 0x18, 0xd8, 0x64, 0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 
-0xc0, 0x46, 0x48, 0x81, 0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 
-0x03, 0xe0, 0x17, 0x80, 0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 
-0x01, 0x32, 0xca, 0x81, 0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
-0x0c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 
-0x41, 0x60, 0x10, 0x49, 0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 
-0x00, 0x2a, 0x04, 0xd0, 0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 
-0x08, 0xd0, 0x4a, 0x69, 0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61, 
+0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49, 
+0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9, 
+0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0, 
+0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23, 
+0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 
+0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60, 
+0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63, 
+0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64, 
+0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64, 
+0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81, 
+0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80, 
+0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81, 
+0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 
+0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49, 
+0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0, 
+0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69, 
+0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61, 
 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a, 
 0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46, 
 0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 
@@ -3677,32 +3318,32 @@ const u8 typhoon_firmware_image[] = {
 0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00, 
 0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29, 
 0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 
+0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40, 
 0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 
 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00, 
 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe, 
 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36, 
 0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d, 
-0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfb, 0xf7, 
-0x50, 0xfc, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c, 
-0x11, 0x4a, 0x01, 0x20, 0xfb, 0xf7, 0x47, 0xfc, 0x29, 0x1c, 0x23, 0x1c, 
-0x0e, 0x4a, 0x00, 0x20, 0xfb, 0xf7, 0x41, 0xfc, 
-0x39, 0x1c, 0x23, 0x1c, 0x0c, 0x4a, 0x01, 0x20, 0xfb, 0xf7, 0x3b, 0xfc, 
-0x00, 0x21, 0x0b, 0x48, 0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 
-0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x1c, 0xad, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 
-0x28, 0x00, 0x03, 0x00, 0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 
-0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 
-0x9b, 0x07, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 
-0x33, 0x4b, 0x01, 0x29, 0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 
-0x9f, 0x42, 0x04, 0xd1, 0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x23, 0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 
-0x3c, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 
-0x02, 0x23, 0x18, 0x43, 0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 
-0x08, 0x23, 0xc2, 0x68, 0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 
-0x00, 0x2b, 0x02, 0xd0, 0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 
-0x22, 0x4c, 0xc0, 0x46, 0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 
-0x54, 0x83, 0x20, 0x4c, 0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00, 
+0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 
+0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c, 
+0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c, 
+0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c, 
+0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48, 
+0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30, 
+0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00, 
+0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80, 
+0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 
+0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29, 
+0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1, 
+0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23, 
+0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33, 
+0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43, 
+0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68, 
+0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0, 
+0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46, 
+0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c, 
+0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00, 
 0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35, 
 0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2, 
 0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32, 
@@ -3710,26 +3351,51 @@ const u8 typhoon_firmware_image[] = {
 0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31, 
 0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43, 
 0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46, 
-0x50, 0x61, 0x09, 0x48, 0xfb, 0xf7, 0xb0, 0xfb, 0xa4, 0xe7, 0x00, 0x00, 
+0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00, 
 0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01, 
-0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00, 
-0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x30, 0xff, 0xff, 0x80, 0xb5, 0x87, 0xb0, 
-0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x48, 0xf8, 0x0e, 0x49, 0xc8, 0x68, 
-0x02, 0x04, 0x89, 0x69, 0x4a, 0x40, 0x05, 0x92, 0x09, 0x04, 0xc9, 0x43, 
-0xc0, 0x43, 0x48, 0x40, 0x06, 0x90, 0x08, 0x21, 0x6a, 0x46, 0x05, 0xa8, 
-0xfd, 0xf7, 0x8b, 0xfb, 0x00, 0x98, 0xc0, 0x46, 0x38, 0x65, 0x03, 0x98, 
-0xc0, 0x46, 0x78, 0x65, 0x04, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 
-0x07, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x83, 0x20, 0x40, 
-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x20, 0x1c, 
-0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68, 0x01, 0x0e, 0xff, 0x22, 
-0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 
-0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x65, 
-0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69, 0xc0, 0x46, 0xb8, 0x65, 
-0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x22, 
-0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18, 0x5f, 0x62, 0x01, 0x32, 
-0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08, 0x03, 0xd3, 0x00, 0x23, 
-0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b, 
+0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00, 
+0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c, 
+0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20, 
+0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60, 
+0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61, 
+0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61, 
+0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62, 
+0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62, 
+0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63, 
+0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63, 
+0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64, 
+0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64, 
+0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04, 
+0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43, 
+0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60, 
+0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 
+0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c, 
+0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c, 
+0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c, 
+0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30, 
+0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65, 
+0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd, 
+0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf, 
+0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02, 
+0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42, 
+0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e, 
+0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85, 
+0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40, 
+0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 
+0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 
+0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89, 
+0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 
+0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68, 
+0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 
+0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 
+0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69, 
+0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 
+0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18, 
+0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08, 
+0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b, 
 0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b, 
 0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c, 
 0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88, 
@@ -3740,7 +3406,7 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3, 
 0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a, 
 0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c, 
-0xff, 0xf7, 0x0e, 0xfe, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23, 
+0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23, 
 0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 
 0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 
 0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40, 
@@ -3754,458 +3420,283 @@ const u8 typhoon_firmware_image[] = {
 0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78, 
 0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43, 
 0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c, 
-0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x8c, 0xf8, 
-0x00, 0xf0, 0x9e, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xad, 0xfa, 0x3d, 0x70, 
+0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8, 
+0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70, 
 0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x85, 0xf8, 0x00, 0xf0, 
-0x8d, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0x9c, 0xfa, 0x38, 0x0a, 0xf6, 0xd3, 
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, 0x41, 0x02, 
-0x53, 0x20, 0x00, 0xf0, 0x57, 0xf8, 0x00, 0xf0, 0x8f, 0xfa, 0xff, 0xf7, 
-0xe9, 0xff, 0x00, 0x24, 0x00, 0x26, 0x00, 0x25, 0x00, 0x27, 0x30, 0x1c, 
-0x01, 0x36, 0x00, 0xf0, 0x5f, 0xf8, 0x00, 0xf0, 0x71, 0xf9, 0x00, 0x90, 
-0x00, 0xf0, 0x80, 0xfa, 0xf8, 0x00, 0x00, 0x99, 0x81, 0x40, 0x0d, 0x43, 
-0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xee, 0xd3, 0x02, 0x99, 0x20, 0xc1, 
-0x02, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42, 0xe5, 0xd3, 0x03, 0xb0, 
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 
-0x16, 0x48, 0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 
-0x00, 0x26, 0x20, 0xcf, 0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 
-0x28, 0x1c, 0x00, 0xf0, 0xd3, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xd0, 0xf9, 
-0x28, 0x0c, 0x00, 0xf0, 0xcd, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xca, 0xf9, 
-0x00, 0xf0, 0x50, 0xfa, 0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 
-0x83, 0x20, 0x00, 0xf0, 0x0f, 0xf8, 0x00, 0xf0, 
-0x47, 0xfa, 0xff, 0xf7, 0xa1, 0xff, 0x04, 0x48, 0xc0, 0x6f, 0x40, 0x23, 
-0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x00, 0xf0, 
-0x4d, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xaa, 0xf9, 0x38, 0x0c, 0x00, 0xf0, 
-0xa7, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xa4, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 
-0xa1, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 
-0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x96, 0xf9, 
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 0x31, 0xfa, 0x57, 0x20, 
-0x00, 0xf0, 0x8e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x08, 0x4f, 
-0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 
-0xff, 0xf7, 0x73, 0xff, 0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 
-0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0, 
+0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98, 
+0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa, 
+0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20, 
+0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1, 
+0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26, 
+0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8, 
+0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00, 
+0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3, 
+0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42, 
+0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f, 
+0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf, 
+0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0, 
+0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0, 
+0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa, 
+0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0, 
+0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48, 
+0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 
+0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 
+0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9, 
+0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20, 
+0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 
+0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47, 
 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43, 
-0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x89, 0xff, 0xf8, 0x6f, 0x20, 0x23, 
+0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23, 
 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x6f, 
-0x20, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0x41, 0x02, 0x53, 0x20, 
-0xff, 0xf7, 0xa6, 0xff, 0x00, 0xf0, 0xde, 0xf9, 0xff, 0xf7, 0x38, 0xff, 
-0xf8, 0x1d, 0x05, 0x30, 0x44, 0x1c, 0xff, 0xf7, 0xb1, 0xff, 0x00, 0xf0, 
-0xc3, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0xd2, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 
-0xa9, 0xff, 0x00, 0xf0, 0xbb, 0xf8, 0x04, 0x1c, 0x00, 0xf0, 0xca, 0xf9, 
-0xe8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x21, 0x02, 
-0x39, 0x43, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 
-0x17, 0x1c, 0x61, 0x02, 0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 
-0x9a, 0x43, 0x02, 0x60, 0x53, 0x20, 0xff, 0xf7, 0x73, 0xff, 0x00, 0xf0, 
-0xab, 0xf9, 0xff, 0xf7, 0x05, 0xff, 0x68, 0x46, 0xff, 0xf7, 0xec, 0xfe, 
-0x6a, 0x46, 0xe8, 0x1d, 0x05, 0x30, 0x17, 0x54, 0x39, 0x0a, 0x68, 0x44, 
-0x41, 0x70, 0x68, 0x46, 0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xd0, 0xfe, 
-0x02, 0xab, 0x18, 0x70, 0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21, 
-0xff, 0xf7, 0xc8, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x20, 0x1c, 
-0xff, 0xf7, 0x1f, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 
+0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 
+0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff, 
+0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c, 
+0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43, 
+0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0, 
+0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c, 
+0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c, 
+0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 
+0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8, 
+0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 
+0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0, 
+0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02, 
+0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 
+0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7, 
+0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d, 
+0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46, 
+0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70, 
+0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21, 
+0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c, 
+0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 
 0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x6b, 0x46, 
-0x00, 0x20, 0xc4, 0x43, 0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 
-0x68, 0x46, 0x0c, 0x30, 0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 
-0x0e, 0x88, 0xc0, 0x46, 0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 
-0x02, 0x30, 0x02, 0x31, 0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 
-0x18, 0x1c, 0x11, 0x1c, 0xff, 0xf7, 0x96, 0xfe, 0x04, 0x1c, 0x00, 0x20, 
-0x01, 0x90, 0x02, 0xab, 0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 
-0x0c, 0x21, 0xff, 0xf7, 0x8b, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 
-0x1d, 0x06, 0x2d, 0x0e, 0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 
-0xff, 0xf7, 0x4a, 0xff, 0x01, 0x20, 0xac, 0x42, 
-0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02, 0x14, 0x4c, 0xe0, 0x6f, 
-0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0x53, 0x20, 0xff, 0xf7, 
-0xfb, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7, 0x8d, 0xfe, 0x68, 0x46, 
-0xff, 0xf7, 0x74, 0xfe, 0xe0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 
-0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24, 0x02, 0xab, 0x5c, 0x70, 
-0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x56, 0xfe, 0xa8, 0x42, 0x02, 0xd1, 
-0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c, 0x00, 0xe0, 0x01, 0x20, 
-0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
-0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3, 0xb4, 0x22, 0x9f, 0xe5, 
-0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f, 
+0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43, 
+0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30, 
+0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46, 
+0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31, 
+0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c, 
+0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab, 
+0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 
+0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e, 
+0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff, 
+0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02, 
+0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 
+0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7, 
+0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23, 
+0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24, 
+0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe, 
+0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c, 
+0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3, 
+0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
+0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x03, 0x80, 0xe1, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1, 
 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
-0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x02, 0x80, 0xe1, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1, 
 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
+0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
-0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 
+0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1, 
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x00, 0x80, 0xe1, 
+0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x93, 0xe5, 0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 
-0xfc, 0x46, 0x60, 0x47, 0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 
-0xa0, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1, 
 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x82, 0xe5, 0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x20, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x11, 0xa0, 0xe1, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1, 
 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
-0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
-0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
-0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5, 0x3c, 0x30, 0x9f, 0xe5, 
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5, 
+0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
-0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40, 0x04, 0x01, 0x18, 0x40, 
-0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40, 0x02, 0x1c, 0x00, 0x20, 
-0x00, 0x29, 0x07, 0xdd, 0x13, 0x78, 0xc0, 0x18, 0x00, 0x06, 0x00, 0x0e, 
-0x01, 0x32, 0x01, 0x39, 0x00, 0x29, 0xf7, 0xdc, 0x70, 0x47, 0x09, 0x4b, 
-0xc9, 0x18, 0x04, 0x29, 0x08, 0xd8, 0x8c, 0x22, 0x4a, 0x43, 0x07, 0x4b, 
-0xd2, 0x18, 0x13, 0x7a, 0x09, 0x06, 0x09, 0x0e, 0x8b, 0x42, 0x01, 0xd0, 
-0x14, 0x20, 0x70, 0x47, 0x02, 0x60, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 
-0xf3, 0x0f, 0x01, 0x35, 0xb0, 0x6e, 0x21, 0x40, 0x01, 0x1c, 0x00, 0x22, 
-0x06, 0x48, 0x03, 0x7a, 0xff, 0x2b, 0x04, 0xd0, 0x8c, 0x30, 0x01, 0x32, 
-0x04, 0x2a, 0xf8, 0xd3, 0x01, 0xe0, 0x04, 0x2a, 0x00, 0xd3, 0x00, 0x20, 
-0x0a, 0x60, 0x70, 0x47, 0xb0, 0x6e, 0x21, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 
-0x00, 0x24, 0x00, 0x2f, 0x21, 0xd0, 0x00, 0x26, 0xf8, 0x79, 0x00, 0x28, 
-0x1b, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, 0x05, 0x35, 0x00, 0x7b, 
-0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x9e, 0xfb, 0x01, 0x1c, 0x8b, 0x68, 
-0x00, 0x2b, 0x08, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xca, 0x68, 
-0xa9, 0x68, 0xfa, 0xf7, 0x4e, 0xff, 0x00, 0x20, 0x68, 0x60, 0x70, 0x1c, 
-0x06, 0x06, 0x36, 0x0e, 0xf8, 0x79, 0xb0, 0x42, 0xe3, 0xdc, 0xff, 0x20, 
-0x38, 0x72, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, 0x0f, 0x1c, 0x68, 0x46, 0xff, 0xf7, 
-0xbd, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, 0x37, 0xe0, 0xb9, 0x88, 
-0xc0, 0x46, 0x01, 0x80, 0xf9, 0x88, 0xc0, 0x46, 0x41, 0x80, 0xb9, 0x7a, 
-0xc0, 0x46, 0x41, 0x71, 0xf9, 0x7a, 0xc0, 0x46, 0x81, 0x71, 0x8c, 0x21, 
-0x01, 0x71, 0x3d, 0x7e, 0x00, 0x21, 0x00, 0x23, 0x00, 0x2d, 0x1f, 0xdd, 
-0x1a, 0x01, 0xd2, 0x19, 0x1c, 0x32, 0x16, 0x78, 0x05, 0x2e, 0x0d, 0xdc, 
-0x0c, 0x01, 0x24, 0x18, 0x26, 0x73, 0x96, 0x68, 0xc0, 0x46, 0x66, 0x61, 
-0xd6, 0x68, 0xc0, 0x46, 0x26, 0x61, 0x00, 0x24, 0x01, 0x31, 0x09, 0x06, 
-0x09, 0x0e, 0xd4, 0x60, 0x5a, 0x1c, 0x13, 0x06, 0x1b, 0x0e, 0xab, 0x42, 
-0xe6, 0xdb, 0x00, 0x29, 0x04, 0xd0, 0xc1, 0x71, 0x00, 0x99, 0xc0, 0x46, 
-0x01, 0x72, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x99, 0xc0, 0x46, 0x08, 0x60, 
-0x00, 0x20, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
-0x07, 0x1c, 0x38, 0x7e, 0x00, 0x28, 0x28, 0xd0, 0x01, 0x38, 0x05, 0x06, 
-0x2d, 0x0e, 0x00, 0x26, 0xff, 0x2d, 0x21, 0xd0, 0x28, 0x01, 0xc0, 0x19, 
-0xc4, 0x1d, 0x15, 0x34, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 
-0x2b, 0xfb, 0x01, 0x1c, 0x11, 0xd0, 0x8a, 0x68, 0x00, 0x2a, 0x0c, 0xd0, 
-0xe0, 0x68, 0x00, 0x28, 0x09, 0xd0, 0x00, 0x23, 0xcb, 0x56, 0x05, 0x2b, 
-0x05, 0xdc, 0x13, 0x1c, 0xca, 0x68, 0xa1, 0x68, 0xfa, 0xf7, 0xd5, 0xfe, 
-0xe6, 0x60, 0xff, 0x20, 0x20, 0x70, 0x68, 0x1e, 0x05, 0x06, 0x2d, 0x0e, 
-0xff, 0x2d, 0xdd, 0xd1, 0x3e, 0x76, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x13, 0x20, 0x70, 0x47, 0xf0, 0xb5, 0x82, 0xb0, 0x07, 0x1c, 0xf8, 0x1d, 
-0xd5, 0x30, 0x39, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x00, 0x90, 0x00, 0x98, 
-0x00, 0x28, 0x3b, 0xd1, 0x38, 0x7e, 0xc0, 0x46, 0x01, 0x90, 0x00, 0x26, 
-0x01, 0x98, 0x00, 0x28, 0x2d, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, 
-0x15, 0x35, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0xf0, 0xfa, 
-0x04, 0x1c, 0x20, 0x69, 0x00, 0x28, 0x17, 0xd0, 0x28, 0x78, 0x05, 0x28, 
-0x0d, 0xdd, 0xe9, 0x68, 0xaa, 0x68, 0x60, 0x68, 0x40, 0x08, 0x40, 0x00, 
-0x01, 0xf0, 0x2c, 0xf8, 0x09, 0x22, 0xe8, 0x68, 0xa9, 0x68, 0xfa, 0xf7, 
-0x8b, 0xfd, 0x00, 0x20, 0xe8, 0x60, 0x21, 0x69, 0x28, 0x1c, 0xfa, 0xf7, 
-0x90, 0xfe, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x90, 0x00, 0x98, 0x00, 0x28, 
-0x0c, 0xd1, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0x01, 0x98, 0x86, 0x42, 
-0xd1, 0xdb, 0x00, 0x20, 0x38, 0x76, 0x00, 0x98, 0x02, 0xb0, 0xf0, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x82, 0xff, 0xf6, 0xe7, 
-0xc1, 0x1d, 0x79, 0x31, 0x4a, 0x6b, 0xc0, 0x46, 0xca, 0x63, 0xc1, 0x1d, 
-0xb9, 0x31, 0x0a, 0x60, 0x00, 0x22, 0x8a, 0x60, 0x04, 0x4a, 0xc0, 0x46, 
-0x4a, 0x61, 0x8a, 0x61, 0x01, 0x21, 0xd0, 0x30, 0x41, 0x70, 0x08, 0x1c, 
-0x70, 0x47, 0x00, 0x00, 0xb1, 0xc5, 0x21, 0x40, 0xf8, 0xb5, 0x07, 0x1c, 
-0x00, 0x20, 0x00, 0x90, 0xfe, 0x1d, 0xc9, 0x36, 0x30, 0x78, 0x00, 0x01, 
-0xc0, 0x19, 0xc4, 0x1d, 0x15, 0x34, 0x80, 0x6a, 0x45, 0x08, 0x6d, 0x00, 
-0x04, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xb2, 0xfe, 0x31, 0x78, 0x40, 0x18, 
-0x01, 0x06, 0x09, 0x0e, 0x00, 0x20, 0xa2, 0x68, 0x00, 0x2a, 0x0a, 0xd9, 
-0x2a, 0x78, 0x4a, 0x40, 0x2a, 0x70, 0x01, 0x30, 0x09, 0x18, 0x09, 0x06, 
-0x09, 0x0e, 0xa2, 0x68, 0x01, 0x35, 0x82, 0x42, 
-0xf4, 0xd8, 0xe0, 0x68, 0xa1, 0x68, 0x40, 0x08, 0x40, 0x00, 0xff, 0xf7, 
-0x99, 0xfe, 0x61, 0x78, 0x81, 0x42, 0x0a, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 
-0x0f, 0xf8, 0xf8, 0x1d, 0x79, 0x30, 0x80, 0x6b, 0xf9, 0x1d, 0xb9, 0x31, 
-0xc8, 0x60, 0x0c, 0x20, 0x00, 0x90, 0x30, 0x78, 0x01, 0x30, 0x30, 0x70, 
-0x00, 0x98, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 0xc9, 0x32, 
-0x11, 0x78, 0x09, 0x01, 0x09, 0x18, 0x09, 0x6a, 0xc3, 0x1d, 0x79, 0x33, 
-0xd9, 0x63, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, 0x5b, 0x6a, 0xcb, 0x18, 
-0xc1, 0x1d, 0xb9, 0x31, 0x0b, 0x60, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, 
-0x9b, 0x6a, 0xc0, 0x46, 0x8b, 0x60, 0x07, 0x4b, 0xc0, 0x46, 0x4b, 0x61, 
-0x12, 0x78, 0x00, 0x7e, 0x01, 0x32, 0x82, 0x42, 0x01, 0xdb, 0x04, 0x48, 
-0x00, 0xe0, 0x04, 0x48, 0xc0, 0x46, 0x88, 0x61, 0x00, 0x20, 0x70, 0x47, 
-0x79, 0xc6, 0x21, 0x40, 0x4d, 0xc6, 0x21, 0x40, 0xf9, 0xc6, 0x21, 0x40, 
-0xf8, 0xb5, 0x04, 0x1c, 0x00, 0x20, 0x00, 0x90, 0x25, 0x7e, 0x29, 0x01, 
-0xe0, 0x1d, 0x15, 0x30, 0xff, 0xf7, 0x4e, 0xfe, 0xa1, 0x7e, 0x81, 0x42, 
-0x0a, 0xd0, 0x20, 0x1c, 0x00, 0xf0, 0x61, 0xf8, 0xe0, 0x1d, 0x79, 0x30, 
-0x80, 0x6b, 0xe1, 0x1d, 0xb9, 0x31, 0xc8, 0x60, 0x0b, 0x20, 0x55, 0xe0, 
-0x00, 0x27, 0x00, 0x2d, 0x0f, 0xdd, 0x38, 0x01, 0x00, 0x19, 0x00, 0x7f, 
-0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x1c, 0xfa, 0x00, 0x28, 0x01, 0xd1, 
-0x09, 0x20, 0x47, 0xe0, 0x78, 0x1c, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 
-0xef, 0xdb, 0x00, 0x26, 0x00, 0x2d, 0x38, 0xdd, 0x30, 0x01, 0x00, 0x19, 
-0xc7, 0x1d, 0x15, 0x37, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 
-0x07, 0xfa, 0x00, 0x23, 0xc1, 0x56, 0x05, 0x29, 0x0c, 0xdc, 0x42, 0x68, 
-0x00, 0x2a, 0x04, 0xd0, 0xc1, 0x68, 0xb8, 0x68, 0xfa, 0xf7, 0xb6, 0xfd, 
-0xf8, 0x60, 0xf8, 0x68, 0x00, 0x28, 0x1b, 0xd1, 0x0e, 0x20, 0x17, 0xe0, 
-0xc0, 0x68, 0x00, 0x28, 0x07, 0xd0, 0xfa, 0xf7, 0xa9, 0xfd, 0x00, 0x28, 
-0x05, 0xda, 0x40, 0x42, 0xb9, 0x68, 0x81, 0x42, 0x04, 0xd0, 0x05, 0x20, 
-0x0a, 0xe0, 0xb9, 0x68, 0x81, 0x42, 0xfa, 0xd8, 0x09, 0x21, 0xb8, 0x68, 
-0xfa, 0xf7, 0x7e, 0xfc, 0xf8, 0x60, 0x00, 0x28, 0x02, 0xd1, 0x06, 0x20, 
-0x00, 0x90, 0x07, 0xe0, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0xae, 0x42, 
-0xc6, 0xdb, 0x00, 0x98, 0x00, 0x28, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 
-0x92, 0xfe, 0x00, 0x98, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 
-0x79, 0x32, 0x41, 0x69, 0xc0, 0x46, 0xd1, 0x63, 0x02, 0x7e, 0x12, 0x01, 
-0x8a, 0x18, 0xc1, 0x1d, 0xb9, 0x31, 0x0a, 0x60, 0xc2, 0x1d, 0x15, 0x32, 
-0x8a, 0x60, 0x05, 0x4a, 0xc0, 0x46, 0x4a, 0x61, 0x04, 0x4a, 0xc0, 0x46, 
-0x8a, 0x61, 0x00, 0x21, 0xd0, 0x30, 0x01, 0x70, 0x08, 0x1c, 0x70, 0x47, 
-0x51, 0xc7, 0x21, 0x40, 0xf9, 0xc6, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 
-0x38, 0x68, 0x1d, 0x4b, 0x98, 0x42, 0x03, 0xd0, 0x03, 0x20, 0x90, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x1c, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xbc, 0xfd, 
-0xfc, 0x1d, 0x79, 0x34, 0x00, 0x28, 0x09, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 
-0x2d, 0xf8, 0xf9, 0x1d, 0xb9, 0x31, 0xa0, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 
-0x0a, 0x20, 0xea, 0xe7, 0x38, 0x7a, 0x1c, 0x28, 0x04, 0xd0, 0x78, 0x7a, 
-0x10, 0x28, 0x01, 0xd0, 0x04, 0x20, 0xe2, 0xe7, 0xb8, 0x7a, 0x01, 0x28, 
-0x01, 0xd0, 0x07, 0x20, 0xdd, 0xe7, 0x60, 0x6b, 
-0xf9, 0x68, 0x88, 0x42, 0x01, 0xd0, 0x05, 0x20, 0xd7, 0xe7, 0x38, 0x69, 
-0x00, 0x28, 0x04, 0xd0, 0x06, 0x4b, 0x98, 0x42, 0x01, 0xd0, 0x08, 0x20, 
-0xcf, 0xe7, 0x38, 0x7e, 0x08, 0x28, 0x01, 0xdd, 0x12, 0x20, 0xca, 0xe7, 
-0x00, 0x20, 0xc8, 0xe7, 0x73, 0x6e, 0x69, 0x70, 0x02, 0x10, 0x00, 0x03, 
-0xb8, 0xb5, 0x07, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x2a, 0xfe, 0x00, 0x25, 
-0xf8, 0x1d, 0xc9, 0x30, 0x45, 0x70, 0xfc, 0x1d, 0xb9, 0x34, 0xe5, 0x61, 
-0x68, 0x46, 0xff, 0xf7, 0x9d, 0xfd, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, 
-0x0d, 0xe0, 0xf8, 0x1d, 0x79, 0x30, 0x85, 0x63, 0xc5, 0x63, 0x1b, 0x20, 
-0x20, 0x60, 0xa7, 0x60, 0x04, 0x48, 0xc0, 0x46, 0x60, 0x61, 0x04, 0x48, 
-0xc0, 0x46, 0xa0, 0x61, 0x28, 0x1c, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x6d, 0xc8, 0x21, 0x40, 0x33, 0xc8, 0x21, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 
-0x07, 0x1c, 0x00, 0x20, 0xfd, 0x1d, 0x79, 0x35, 0xfc, 0x1d, 0xb9, 0x34, 
-0xe9, 0x6a, 0xc0, 0x46, 0x61, 0x60, 0x62, 0x68, 0xe9, 0x6b, 0x8a, 0x42, 
-0x03, 0xd2, 0x61, 0x60, 0x2a, 0x6b, 0x91, 0x42, 0x34, 0xd2, 0x66, 0x68, 
-0xc0, 0x46, 0x01, 0x96, 0xe9, 0x6b, 0x73, 0x1a, 0xe9, 0x6a, 0x71, 0x1a, 
-0x26, 0x68, 0x2a, 0x6b, 0x96, 0x42, 0x00, 0xd2, 0x32, 0x1c, 0x01, 0x9e, 
-0x96, 0x1b, 0xa2, 0x68, 0xc0, 0x46, 0x00, 0x92, 0x00, 0x2a, 0x09, 0xd0, 
-0x28, 0x6a, 0x6a, 0x6a, 0x41, 0x18, 0x00, 0x98, 0xc0, 0x18, 0x33, 0x1c, 
-0xfc, 0xf7, 0x68, 0xff, 0x00, 0x28, 0x1b, 0xd1, 0x61, 0x68, 0x89, 0x19, 
-0x61, 0x60, 0x22, 0x68, 0x91, 0x42, 0x0d, 0xd1, 0x61, 0x69, 0x38, 0x1c, 
-0xfa, 0xf7, 0xc5, 0xfc, 0x00, 0x06, 0x00, 0x0e, 0x0e, 0xd1, 0xa1, 0x69, 
-0x38, 0x1c, 0xfa, 0xf7, 0xbe, 0xfc, 0x00, 0x06, 0x00, 0x0e, 0x07, 0xd1, 
-0x61, 0x68, 0x2a, 0x6b, 0x91, 0x42, 0xc2, 0xd3, 0xa9, 0x6b, 0xaa, 0x6a, 
-0x89, 0x18, 0xa9, 0x63, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0xf0, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfa, 0xf7, 
-0xc3, 0xfe, 0xfa, 0x1d, 0x09, 0x32, 0x37, 0x49, 0x00, 0x20, 0xc0, 0x43, 
-0xcc, 0x1d, 0xb9, 0x34, 0xe0, 0x60, 0xf8, 0x88, 0xcb, 0x1d, 0x89, 0x33, 
-0x18, 0x73, 0xc8, 0x1d, 0x79, 0x30, 0xbd, 0x68, 0xc0, 0x46, 0x05, 0x62, 
-0xff, 0x68, 0xc0, 0x46, 0x47, 0x62, 0x17, 0x68, 0xc0, 0x46, 0x87, 0x62, 
-0x57, 0x68, 0xc0, 0x46, 0xc7, 0x62, 0x92, 0x68, 0xc0, 0x46, 0x42, 0x63, 
-0xc2, 0x6a, 0x87, 0x6a, 0xd2, 0x19, 0x02, 0x63, 0x1a, 0x7b, 0x28, 0x4d, 
-0x01, 0x2a, 0x0d, 0xd0, 0x02, 0x2a, 0x1c, 0xd0, 0x03, 0x2a, 0x35, 0xd1, 
-0xca, 0x1d, 0xc9, 0x32, 0x52, 0x78, 0x00, 0x2a, 0x08, 0xd1, 0x10, 0x27, 
-0x80, 0x6b, 0xc0, 0x46, 0xe0, 0x60, 0x2c, 0xe0, 0x08, 0x1c, 0xff, 0xf7, 
-0x4b, 0xff, 0x22, 0xe0, 0x08, 0x1c, 0xff, 0xf7, 0xa9, 0xfd, 0x07, 0x1c, 
-0x23, 0xd1, 0xe0, 0x69, 0x00, 0x28, 0x1c, 0xd0, 0x00, 0x7a, 0x1a, 0x4b, 
-0xc0, 0x18, 0x02, 0x90, 0x17, 0xe0, 0x82, 0x6a, 0xc3, 0x6a, 0x9f, 0x18, 
-0x46, 0x6b, 0xb7, 0x42, 0x05, 0xd8, 0x00, 0x2a, 0x03, 0xd0, 0x9f, 0x07, 
-0x01, 0xd1, 0x92, 0x07, 0x01, 0xd0, 0x0f, 0x27, 0x0d, 0xe0, 0x80, 0x6b, 
-0x98, 0x42, 0x01, 0xd0, 0xe0, 0x60, 0xf8, 0xe7, 0x08, 0x1c, 0xff, 0xf7, 
-0x4f, 0xff, 0x07, 0x1c, 0x03, 0xd1, 0x00, 0xf0, 0x1f, 0xfe, 0x01, 0xe0, 
-0x10, 0x27, 0x00, 0x20, 0x28, 0x65, 0x01, 0xab, 0x5f, 0x80, 0xe0, 0x68, 
-0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 
-0xfa, 0xf7, 0x98, 0xfd, 0x01, 0x20, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x3c, 0xac, 0x20, 0x40, 0x00, 0x00, 0x00, 0x80, 
-0x0d, 0xf0, 0xfe, 0xca, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 
-0x01, 0xa9, 0xfa, 0xf7, 0x45, 0xfe, 0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, 
-0x94, 0xfc, 0x00, 0x28, 0x02, 0xd1, 0x00, 0x98, 0xff, 0xf7, 0xb8, 0xfc, 
-0x02, 0xab, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, 0x76, 0xfd, 
-0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 
-0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, 0x2a, 0xfe, 
-0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, 0x79, 0xfc, 0x00, 0x28, 0x00, 0xd1, 
-0x02, 0x20, 0x02, 0xab, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, 
-0x5d, 0xfd, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x90, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, 
-0x11, 0xfe, 0x3c, 0x69, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, 0x0c, 0xfe, 
-0x68, 0x46, 0x21, 0x1c, 0xff, 0xf7, 0x5b, 0xfc, 0x8c, 0x24, 0x00, 0x28, 
-0x0e, 0xd1, 0xb9, 0x68, 0x00, 0x29, 0x02, 0xd1, 0xfa, 0x68, 0x00, 0x2a, 
-0x08, 0xd0, 0xf8, 0x88, 0x23, 0x1c, 0x8c, 0x28, 0x00, 0xd8, 0x03, 0x1c, 
-0xf8, 0x68, 0x00, 0x9a, 0xfc, 0xf7, 0xd0, 0xfd, 0x02, 0xab, 0x58, 0x80, 
-0x03, 0x94, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, 0x2f, 0xfd, 0x01, 0x20, 
-0x05, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0x04, 0x48, 
-0xff, 0x22, 0x02, 0x72, 0x8c, 0x30, 0x01, 0x31, 0x04, 0x29, 0xfa, 0xd3, 
-0x70, 0x47, 0x00, 0x00, 0xb0, 0x6e, 0x21, 0x40, 0x02, 0x48, 0x03, 0x49, 
-0x40, 0x1a, 0x40, 0x42, 0x70, 0x47, 0x00, 0x00, 0xed, 0xd6, 0x21, 0x40, 
-0xe9, 0xd6, 0x21, 0x40, 0x00, 0x21, 0x08, 0x4a, 0x8b, 0x00, 0x5b, 0x18, 
-0x9b, 0x00, 0xd3, 0x56, 0x83, 0x42, 0x04, 0xd1, 0x88, 0x00, 0x40, 0x18, 
-0x80, 0x00, 0x80, 0x18, 0x70, 0x47, 0x01, 0x31, 0x01, 0x29, 0xf1, 0xd3, 
-0x00, 0x20, 0xf9, 0xe7, 0xe0, 0x70, 0x21, 0x40, 0x80, 0xb5, 0x00, 0xf0, 
-0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0, 0x45, 0xf8, 0x78, 0x1c, 
-0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd, 0x80, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x1c, 0x48, 0x02, 0x68, 0x1c, 0x49, 0x8b, 0x69, 0xd2, 0x18, 
-0x02, 0x60, 0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 
-0x02, 0xd2, 0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 
-0xd2, 0x18, 0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 
-0xc2, 0x69, 0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 
-0xd2, 0x18, 0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 
-0x02, 0x6b, 0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 
-0x9b, 0x18, 0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 
-0x82, 0x63, 0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 
-0xc9, 0x6a, 0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0xa4, 0x2a, 0x00, 0x80, 
+0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40, 
+0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40, 
+0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0, 
+0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48, 
+0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66, 
+0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2, 
+0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18, 
+0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69, 
+0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18, 
+0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b, 
+0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18, 
+0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63, 
+0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a, 
+0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 
 0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8, 
 0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22, 
 0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42, 
 0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 
-0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x22, 0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 
-0x02, 0x28, 0x0c, 0xd0, 0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 
-0x08, 0x60, 0x10, 0x1c, 0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 
-0x50, 0x22, 0x08, 0x60, 0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 
-0xf3, 0xe7, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 
-0x0c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x00, 0x27, 
-0x68, 0x46, 0xfe, 0xf7, 0x6f, 0xfb, 0x10, 0x4c, 0x00, 0x28, 0x0b, 0xd0, 
-0x00, 0xf0, 0x44, 0xf8, 0x00, 0x28, 0x07, 0xd0, 0x01, 0x27, 0x10, 0x23, 
-0x60, 0x68, 0x18, 0x43, 0x60, 0x60, 0xa0, 0x68, 0x18, 0x43, 0x0b, 0xe0, 
-0x10, 0x23, 0xe0, 0x68, 0x98, 0x43, 0xe0, 0x60, 0x60, 0x69, 0x98, 0x43, 
-0x60, 0x61, 0x60, 0x68, 0x98, 0x43, 0x60, 0x60, 0xa0, 0x68, 0x98, 0x43, 
-0xa0, 0x60, 0x38, 0x1c, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
-0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0x00, 0xf0, 0xc7, 0xfc, 0x04, 0x49, 
-0x09, 0x6d, 0x08, 0x43, 0xfe, 0xf7, 0x8a, 0xfb, 0x00, 0x20, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x14, 0x24, 
-0x00, 0x25, 0x00, 0x27, 0x08, 0x4e, 0x02, 0x20, 0x21, 0x1c, 0x32, 0x1c, 
-0xfa, 0xf7, 0xde, 0xfa, 0x78, 0x40, 0x07, 0x04, 0x3f, 0x0c, 0x02, 0x34, 
-0x01, 0x35, 0x03, 0x2d, 0xf3, 0xd3, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x79, 0xbf, 0x21, 0x40, 0x01, 0x20, 0x70, 0x47, 
-0xb0, 0xb5, 0x01, 0x27, 0x3a, 0x1c, 0x18, 0x4b, 0xdb, 0x68, 0x01, 0x2b, 
-0x00, 0xd0, 0x00, 0x22, 0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0x00, 0x2a, 
-0x23, 0xd0, 0x14, 0x4a, 0x53, 0x68, 0x1b, 0x04, 0x1b, 0x0c, 0x1d, 0x02, 
-0x1b, 0x12, 0x2b, 0x43, 0x92, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x15, 0x02, 
-0x12, 0x12, 0x2a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x1b, 0x04, 0x1a, 0x43, 
-0x51, 0x40, 0x01, 0x31, 0x0f, 0xd1, 0x00, 0x28, 0x02, 0xd0, 0xff, 0xf7, 
-0xc1, 0xff, 0xc4, 0x43, 0x22, 0x04, 0x12, 0x0c, 0x07, 0x4b, 0x3a, 0x21, 
-0x02, 0x20, 0xfa, 0xf7, 0xa2, 0xfa, 0x38, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
-0x40, 0x00, 0x14, 0x40, 0xd9, 0xbf, 0x21, 0x40, 0x80, 0xb4, 0x03, 0x22, 
-0xc2, 0x80, 0x15, 0x4a, 0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 
-0x01, 0x32, 0xc2, 0x60, 0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 
-0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 
-0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 
-0x0f, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 
-0x01, 0x31, 0x00, 0x20, 0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 
-0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 
-0x80, 0xbc, 0x70, 0x47, 0x02, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 
-0x7c, 0x04, 0x00, 0x80, 0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 
-0x00, 0xb5, 0x01, 0x23, 0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 
-0x00, 0x22, 0x0a, 0x70, 0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 
-0x43, 0x83, 0x7d, 0x21, 0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 
-0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x38, 0xfb, 0x08, 0xbc, 0x18, 0x47, 
-0x68, 0x0e, 0x00, 0x80, 0xa1, 0x22, 0xff, 0xff, 
-0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48, 0x02, 0x22, 0x00, 0x21, 
-0x00, 0xf0, 0x2a, 0xfb, 0x01, 0x23, 0xd8, 0x42, 0x0a, 0xd1, 0x10, 0x48, 
-0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32, 0xca, 0x80, 0x81, 0x79, 
-0x01, 0x31, 0x81, 0x71, 0xfc, 0xf7, 0x5c, 0xfd, 0x0b, 0x48, 0xc0, 0x68, 
-0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22, 0xd2, 0x00, 0x00, 0x21, 
-0x00, 0xf0, 0x12, 0xfb, 0x08, 0x48, 0xfa, 0xf7, 0x1b, 0xfa, 0x08, 0x48, 
-0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x0a, 0xfb, 0x08, 0xbc, 0x18, 0x47, 
-0x65, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0x95, 0x7e, 0x21, 0x40, 0x81, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 
-0x00, 0xb5, 0x10, 0x20, 0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 
-0x0f, 0x48, 0x64, 0x21, 0xfa, 0xf7, 0x00, 0xfa, 0x0e, 0x48, 0x01, 0x22, 
-0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 
-0x02, 0x68, 0x12, 0x0c, 0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 
-0x08, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 
-0xc0, 0x46, 0x01, 0x64, 0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
-0x91, 0x55, 0xff, 0xff, 0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 
-0x01, 0x22, 0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 
-0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 
-0x03, 0xd3, 0x21, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 
-0xc0, 0x46, 0x01, 0x64, 0x1f, 0x48, 0xfa, 0xf7, 0xc1, 0xf9, 0x1f, 0x48, 
-0xc1, 0x6b, 0xff, 0x29, 0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 
-0x0f, 0x1c, 0x1c, 0x4c, 0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 
-0xa1, 0x69, 0x99, 0x43, 0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 
-0xc0, 0x46, 0x28, 0x61, 0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfa, 0xf7, 
-0xa9, 0xf9, 0x16, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 
-0x39, 0x1c, 0x32, 0x1c, 0xfa, 0xf7, 0xa8, 0xf9, 0x13, 0x48, 0xc1, 0x68, 
-0x08, 0x29, 0xfc, 0xd1, 0x12, 0x48, 0xfa, 0xf7, 0x97, 0xf9, 0x10, 0x23, 
-0x60, 0x69, 0x98, 0x43, 0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 
-0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
-0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0x04, 0x02, 0xff, 0xff, 0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 
-0x0c, 0x55, 0xff, 0xff, 0x2d, 0xcf, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 
-0x44, 0x80, 0x20, 0x40, 0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 
-0x00, 0xb5, 0xfd, 0xf7, 0xeb, 0xfa, 0x06, 0x48, 0xfa, 0xf7, 0x6c, 0xf9, 
-0xfd, 0xf7, 0xc0, 0xfa, 0xfd, 0xf7, 0xee, 0xfb, 0xfd, 0xf7, 0x00, 0xfc, 
-0xfd, 0xf7, 0x0e, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 
-0x90, 0xb5, 0xfd, 0xf7, 0x55, 0xf8, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 
-0xf8, 0x1d, 0x79, 0x30, 0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 
-0xf9, 0x67, 0x31, 0x49, 0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 
-0x0c, 0x60, 0x4c, 0x60, 0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 
-0x8c, 0x61, 0x04, 0xe0, 0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 
-0x08, 0x38, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 
-0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 
-0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 
-0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x38, 0xf8, 0x00, 0xf0, 0x08, 0xf9, 
-0xfc, 0xf7, 0x5f, 0xfc, 0xff, 0xf7, 0x84, 0xfd, 0xfd, 0xf7, 0x18, 0xfa, 
-0xfd, 0xf7, 0xa0, 0xf9, 0xfd, 0xf7, 0xac, 0xfa, 0xfd, 0xf7, 0x3e, 0xf9, 
-0xfd, 0xf7, 0xf4, 0xf8, 0xfd, 0xf7, 0x7e, 0xf9, 0x00, 0xf0, 0xc4, 0xf9, 
-0xfd, 0xf7, 0x86, 0xfb, 0xfd, 0xf7, 0xf4, 0xfa, 0xfd, 0xf7, 0xbc, 0xfa, 
-0xfd, 0xf7, 0x26, 0xf8, 0xfa, 0xf7, 0x12, 0xf8, 0xff, 0xf7, 0x40, 0xfd, 
-0x00, 0x20, 0xff, 0xf7, 0x17, 0xfe, 0xff, 0xf7, 0x97, 0xff, 0x71, 0x23, 
-0x5b, 0x01, 0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 
-0xf8, 0x18, 0x04, 0x63, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 
-0xc3, 0xf9, 0x08, 0x48, 0xfa, 0xf7, 0xf8, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 
-0x04, 0x01, 0x11, 0x40, 0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 
-0x65, 0x9f, 0x21, 0x40, 0x00, 0xb5, 0x04, 0x48, 0xfa, 0xf7, 0xe4, 0xf8, 
-0xfd, 0xf7, 0x48, 0xfb, 0xfd, 0xf7, 0x0e, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
-0x61, 0xa9, 0x21, 0x40, 0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 
-0x40, 0x21, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 
-0x07, 0x48, 0x41, 0x69, 0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 
-0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 
-0xc0, 0x46, 0x10, 0x61, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
-0xfe, 0xaf, 0x9a, 0x10, 0x00, 0xb5, 0x02, 0x48, 0xfa, 0xf7, 0xba, 0xf8, 
-0x08, 0xbc, 0x18, 0x47, 0xb4, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 
-0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 
-0x22, 0x4d, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 
-0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 
-0x1d, 0x48, 0xfa, 0xf7, 0x9f, 0xf8, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 
-0x01, 0x30, 0x88, 0x61, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 
-0x00, 0x28, 0x1f, 0xd0, 0x19, 0x48, 0xfa, 0xf7, 0x91, 0xf8, 0x19, 0x48, 
-0xfa, 0xf7, 0x8e, 0xf8, 0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 
-0x02, 0xd0, 0x16, 0x48, 0xfa, 0xf7, 0x86, 0xf8, 0x01, 0x21, 0x09, 0x04, 
-0x20, 0x68, 0x01, 0x40, 0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 
-0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 
-0x01, 0xe0, 0x28, 0x64, 0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0xdd, 0xfc, 
-0x0b, 0x48, 0xfa, 0xf7, 0x6f, 0xf8, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 
-0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0x04, 0x02, 0xff, 0xff, 0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 
-0xf4, 0x01, 0xff, 0xff, 0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 
-0xe9, 0xaf, 0x21, 0x40, 0x00, 0xb5, 0x16, 0x49, 0x01, 0x22, 0x12, 0x04, 
+0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22, 
+0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0, 
+0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c, 
+0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60, 
+0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00, 
+0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a, 
+0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60, 
+0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 
+0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31, 
+0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30, 
+0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 
+0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 
+0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47, 
+0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80, 
+0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23, 
+0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70, 
+0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21, 
+0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 
+0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48, 
+0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42, 
+0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32, 
+0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9, 
+0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22, 
+0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7, 
+0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb, 
+0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40, 
+0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20, 
+0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21, 
+0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68, 
+0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c, 
+0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46, 
+0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64, 
+0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff, 
+0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04, 
+0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 
+0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48, 
+0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64, 
+0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29, 
+0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c, 
+0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43, 
+0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61, 
+0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c, 
+0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1, 
+0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43, 
+0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18, 
+0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40, 
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff, 
+0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff, 
+0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40, 
+0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7, 
+0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe, 
+0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8, 
+0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7, 
+0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30, 
+0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49, 
+0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60, 
+0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0, 
+0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68, 
+0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23, 
+0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68, 
+0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc, 
+0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe, 
+0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe, 
+0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd, 
+0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff, 
+0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa, 
+0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01, 
+0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18, 
+0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7, 
+0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa, 
+0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40, 
+0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40, 
+0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff, 
+0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40, 
+0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62, 
+0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69, 
+0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61, 
+0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10, 
+0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47, 
+0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04, 
+0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29, 
+0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a, 
+0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7, 
+0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61, 
+0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0, 
+0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb, 
+0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48, 
+0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40, 
+0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 
+0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64, 
+0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7, 
+0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40, 
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff, 
+0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff, 
+0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40, 
+0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60, 
+0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21, 
+0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21, 
+0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0, 
+0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9, 
+0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09, 
+0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22, 
+0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68, 
+0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49, 
+0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64, 
+0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04, 
 0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68, 
-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x10, 0x49, 
-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x0f, 0x49, 0xc0, 0x46, 0x08, 0x64, 
-0x03, 0x20, 0xfe, 0xf7, 0x55, 0xf9, 0xfa, 0xf7, 
-0x9d, 0xfc, 0x01, 0x23, 0x18, 0x43, 0xfa, 0xf7, 0x77, 0xfd, 0xff, 0xf7, 
-0xd7, 0xfe, 0xff, 0xf7, 0x5b, 0xfe, 0xff, 0xf7, 0x4b, 0xff, 0xff, 0xf7, 
-0x5f, 0xff, 0xff, 0xf7, 0xf1, 0xfd, 0xff, 0xf7, 0x77, 0xff, 0x08, 0xbc, 
+0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49, 
+0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64, 
+0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23, 
+0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7, 
+0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7, 
+0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc, 
 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 
 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03, 
 0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88, 
@@ -4231,7 +3722,7 @@ const u8 typhoon_firmware_image[] = {
 0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51, 
 0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00, 
 0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 
-0xec, 0xd6, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 
+0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 
 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00, 
 0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 
 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 
@@ -4239,14 +3730,14 @@ const u8 typhoon_firmware_image[] = {
 0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
 0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18, 
 0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61, 
-0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05, 0x87, 0x61, 0xda, 0x60, 
-0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20, 0x40, 0x03, 0x81, 0x61, 
-0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0xff, 0xf7, 
-0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8, 0x00, 0x20, 0x09, 0x49, 
-0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xfb, 0x18, 
-0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3, 0x04, 0x48, 0x01, 0x22, 
-0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc, 
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x09, 0x3e, 0xff, 0xff, 
+0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05, 
+0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20, 
+0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8, 
+0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23, 
+0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3, 
+0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff, 
 0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
 0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b, 
 0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c, 
@@ -4280,17 +3771,8 @@ const u8 typhoon_firmware_image[] = {
 0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69, 
 0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a, 
 0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47, 
-0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x43, 0x1a, 0x93, 0x42, 
-0x30, 0xd3, 0x84, 0x46, 0x8b, 0x07, 0x07, 0xd0, 0x52, 0x1e, 0x29, 0xd3, 
-0x0b, 0x78, 0x03, 0x70, 0x40, 0x1c, 0x49, 0x1c, 0x8b, 0x07, 0xf7, 0xd1, 
-0x83, 0x07, 0x17, 0xd1, 0x10, 0x3a, 0x05, 0xd3, 0xb0, 0xb4, 0xb8, 0xc9, 
-0xb8, 0xc0, 0x10, 0x3a, 0xfb, 0xd2, 0xb0, 0xbc, 0x0c, 0x32, 0x0f, 0xd3, 
-0x08, 0xc9, 0x08, 0xc0, 0x12, 0x1f, 0xfb, 0xd2, 0x0a, 0xe0, 0x08, 0xc9, 
-0x03, 0x70, 0x1b, 0x0a, 0x43, 0x70, 0x1b, 0x0a, 0x83, 0x70, 0x1b, 0x0a, 
-0xc3, 0x70, 0x00, 0x1d, 0x12, 0x1f, 0xf4, 0xd2, 0xd2, 0x1c, 0x05, 0xd3, 
-0x0b, 0x78, 0x03, 0x70, 0x49, 0x1c, 0x40, 0x1c, 
-0x52, 0x1e, 0xf9, 0xd2, 0x60, 0x46, 0x70, 0x47, 0x03, 0x1c, 0x0b, 0x43, 
-0x13, 0x43, 0x9b, 0x07, 0x04, 0xd1, 0x12, 0x1f, 0x8b, 0x58, 0x83, 0x50, 
-0xfb, 0xd1, 0x70, 0x47, 0x52, 0x1e, 0x8b, 0x5c, 0x83, 0x54, 0xfb, 0xd1, 
-0x70, 0x47, 0x00, 0x00, 0x00, 0x20, 0x70, 0x47, 
+0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 
+0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34, 
+0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 
 };
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -50,6 +50,13 @@
  */
 static int rx_copybreak = 200;
 
+/* Should we use MMIO or Port IO?
+ * 0: Port IO
+ * 1: MMIO
+ * 2: Try MMIO, fallback to Port IO
+ */
+static unsigned int use_mmio = 2;
+
 /* end user-configurable values */
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
@@ -93,8 +100,8 @@ static const int multicast_filter_limit 
 #define PKT_BUF_SZ		1536
 
 #define DRV_MODULE_NAME		"typhoon"
-#define DRV_MODULE_VERSION 	"1.5.4"
-#define DRV_MODULE_RELDATE	"04/09/09"
+#define DRV_MODULE_VERSION 	"1.5.7"
+#define DRV_MODULE_RELDATE	"05/01/07"
 #define PFX			DRV_MODULE_NAME ": "
 #define ERR_PFX			KERN_ERR PFX
 
@@ -131,9 +138,16 @@ static char version[] __devinitdata =
     "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
+MODULE_VERSION(DRV_MODULE_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
-MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
+			       "the buffer given back to the NIC. Default "
+			       "is 200.");
+MODULE_PARM_DESC(use_mmio, "Use MMIO (1) or PIO(0) to access the NIC. "
+			   "Default is to try MMIO and fallback to PIO.");
+module_param(rx_copybreak, int, 0);
+module_param(use_mmio, int, 0);
 
 #if defined(NETIF_F_TSO) && MAX_SKB_FRAGS > 32
 #warning Typhoon only supports 32 entries in its SG list for TSO, disabling TSO
@@ -310,7 +324,7 @@ enum state_values {
  * cannot pass a read, so this forces current writes to post.
  */
 #define typhoon_post_pci_writes(x) \
-	do { readl(x + TYPHOON_REG_HEARTBEAT); } while(0)
+	do { if(likely(use_mmio)) ioread32(x+TYPHOON_REG_HEARTBEAT); } while(0)
 
 /* We'll wait up to six seconds for a reset, and half a second normally.
  */
@@ -391,17 +405,17 @@ typhoon_reset(void __iomem *ioaddr, int 
 	else
 		timeout = TYPHOON_RESET_TIMEOUT_SLEEP;
 
-	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
-	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
 
-	writel(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET);
+	iowrite32(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET);
 	typhoon_post_pci_writes(ioaddr);
 	udelay(1);
-	writel(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET);
+	iowrite32(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET);
 
 	if(wait_type != NoWait) {
 		for(i = 0; i < timeout; i++) {
-			if(readl(ioaddr + TYPHOON_REG_STATUS) ==
+			if(ioread32(ioaddr + TYPHOON_REG_STATUS) ==
 			   TYPHOON_STATUS_WAITING_FOR_HOST)
 				goto out;
 
@@ -416,8 +430,8 @@ typhoon_reset(void __iomem *ioaddr, int 
 	}
 
 out:
-	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
-	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
 
 	/* The 3XP seems to need a little extra time to complete the load
 	 * of the sleep image before we can reliably boot it. Failure to
@@ -442,7 +456,7 @@ typhoon_wait_status(void __iomem *ioaddr
 	int i, err = 0;
 
 	for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
-		if(readl(ioaddr + TYPHOON_REG_STATUS) == wait_value)
+		if(ioread32(ioaddr + TYPHOON_REG_STATUS) == wait_value)
 			goto out;
 		udelay(TYPHOON_UDELAY);
 	}
@@ -478,7 +492,7 @@ typhoon_hello(struct typhoon *tp)
 
 		INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP);
 		smp_wmb();
-		writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
+		iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
 		spin_unlock(&tp->command_lock);
 	}
 }
@@ -633,7 +647,7 @@ typhoon_issue_command(struct typhoon *tp
 	/* "I feel a presence... another warrior is on the the mesa."
 	 */
 	wmb();
-	writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
+	iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
 	typhoon_post_pci_writes(tp->ioaddr);
 
 	if((cmd->flags & TYPHOON_CMD_RESPOND) == 0)
@@ -687,7 +701,7 @@ out:
 		 * is the case.
 		 */
 		if(indexes->respCleared != indexes->respReady)
-			writel(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT);
+			iowrite32(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT);
 	}
 
 	spin_unlock(&tp->command_lock);
@@ -889,7 +903,7 @@ typhoon_start_tx(struct sk_buff *skb, st
 	/* Kick the 3XP
 	 */
 	wmb();
-	writel(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister);
+	iowrite32(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister);
 
 	dev->trans_start = jiffies;
 
@@ -1058,8 +1072,10 @@ typhoon_get_drvinfo(struct net_device *d
 		if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
 			strcpy(info->fw_version, "Unknown runtime");
 		} else {
-			strncpy(info->fw_version, (char *) &xp_resp[1], 32);
-			info->fw_version[31] = 0;
+			u32 sleep_ver = xp_resp[0].parm2;
+			snprintf(info->fw_version, 32, "%02x.%03x.%03x",
+				 sleep_ver >> 24, (sleep_ver >> 12) & 0xfff, 
+				 sleep_ver & 0xfff);
 		}
 	}
 
@@ -1251,7 +1267,7 @@ typhoon_wait_interrupt(void __iomem *ioa
 	int i, err = 0;
 
 	for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
-		if(readl(ioaddr + TYPHOON_REG_INTR_STATUS) &
+		if(ioread32(ioaddr + TYPHOON_REG_INTR_STATUS) &
 		   TYPHOON_INTR_BOOTCMD)
 			goto out;
 		udelay(TYPHOON_UDELAY);
@@ -1260,7 +1276,7 @@ typhoon_wait_interrupt(void __iomem *ioa
 	err = -ETIMEDOUT;
 
 out:
-	writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
 	return err;
 }
 
@@ -1394,11 +1410,11 @@ typhoon_download_firmware(struct typhoon
 		goto err_out;
 	}
 
-	irqEnabled = readl(ioaddr + TYPHOON_REG_INTR_ENABLE);
-	writel(irqEnabled | TYPHOON_INTR_BOOTCMD,
+	irqEnabled = ioread32(ioaddr + TYPHOON_REG_INTR_ENABLE);
+	iowrite32(irqEnabled | TYPHOON_INTR_BOOTCMD,
 	       ioaddr + TYPHOON_REG_INTR_ENABLE);
-	irqMasked = readl(ioaddr + TYPHOON_REG_INTR_MASK);
-	writel(irqMasked | TYPHOON_INTR_BOOTCMD,
+	irqMasked = ioread32(ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(irqMasked | TYPHOON_INTR_BOOTCMD,
 	       ioaddr + TYPHOON_REG_INTR_MASK);
 
 	err = -ETIMEDOUT;
@@ -1410,24 +1426,24 @@ typhoon_download_firmware(struct typhoon
 	numSections = le32_to_cpu(fHdr->numSections);
 	load_addr = le32_to_cpu(fHdr->startAddr);
 
-	writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
-	writel(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR);
+	iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR);
 	hmac = le32_to_cpu(fHdr->hmacDigest[0]);
-	writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0);
+	iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0);
 	hmac = le32_to_cpu(fHdr->hmacDigest[1]);
-	writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1);
+	iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1);
 	hmac = le32_to_cpu(fHdr->hmacDigest[2]);
-	writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2);
+	iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2);
 	hmac = le32_to_cpu(fHdr->hmacDigest[3]);
-	writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3);
+	iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3);
 	hmac = le32_to_cpu(fHdr->hmacDigest[4]);
-	writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4);
+	iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4);
 	typhoon_post_pci_writes(ioaddr);
-	writel(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND);
+	iowrite32(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND);
 
 	image_data += sizeof(struct typhoon_file_header);
 
-	/* The readl() in typhoon_wait_interrupt() will force the
+	/* The ioread32() in typhoon_wait_interrupt() will force the
 	 * last write to the command register to post, so
 	 * we don't need a typhoon_post_pci_writes() after it.
 	 */
@@ -1441,7 +1457,7 @@ typhoon_download_firmware(struct typhoon
 			len = min_t(u32, section_len, PAGE_SIZE);
 
 			if(typhoon_wait_interrupt(ioaddr) < 0 ||
-			   readl(ioaddr + TYPHOON_REG_STATUS) !=
+			   ioread32(ioaddr + TYPHOON_REG_STATUS) !=
 			   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
 				printk(KERN_ERR "%s: segment ready timeout\n",
 				       tp->name);
@@ -1458,13 +1474,14 @@ typhoon_download_firmware(struct typhoon
 			csum = csum_fold(csum);
 			csum = le16_to_cpu(csum);
 
-			writel(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
-			writel(csum, ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
-			writel(load_addr, ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
-			writel(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
-			writel(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
+			iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
+			iowrite32(csum, ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
+			iowrite32(load_addr,
+					ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
+			iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
+			iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
 			typhoon_post_pci_writes(ioaddr);
-			writel(TYPHOON_BOOTCMD_SEG_AVAILABLE,
+			iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
 			       ioaddr + TYPHOON_REG_COMMAND);
 
 			image_data += len;
@@ -1474,25 +1491,25 @@ typhoon_download_firmware(struct typhoon
 	}
 
 	if(typhoon_wait_interrupt(ioaddr) < 0 ||
-	   readl(ioaddr + TYPHOON_REG_STATUS) !=
+	   ioread32(ioaddr + TYPHOON_REG_STATUS) !=
 	   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
 		printk(KERN_ERR "%s: final segment ready timeout\n", tp->name);
 		goto err_out_irq;
 	}
 
-	writel(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
+	iowrite32(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
 
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
 		printk(KERN_ERR "%s: boot ready timeout, status 0x%0x\n",
-		       tp->name, readl(ioaddr + TYPHOON_REG_STATUS));
+		       tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
 		goto err_out_irq;
 	}
 
 	err = 0;
 
 err_out_irq:
-	writel(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
-	writel(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);
+	iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);
 
 	pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma);
 
@@ -1510,24 +1527,25 @@ typhoon_boot_3XP(struct typhoon *tp, u32
 		goto out_timeout;
 	}
 
-	writel(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI);
-	writel(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO);
+	iowrite32(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI);
+	iowrite32(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO);
 	typhoon_post_pci_writes(ioaddr);
-	writel(TYPHOON_BOOTCMD_REG_BOOT_RECORD, ioaddr + TYPHOON_REG_COMMAND);
+	iowrite32(TYPHOON_BOOTCMD_REG_BOOT_RECORD,
+				ioaddr + TYPHOON_REG_COMMAND);
 
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) {
 		printk(KERN_ERR "%s: boot finish timeout (status 0x%x)\n",
-		       tp->name, readl(ioaddr + TYPHOON_REG_STATUS));
+		       tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
 		goto out_timeout;
 	}
 
 	/* Clear the Transmit and Command ready registers
 	 */
-	writel(0, ioaddr + TYPHOON_REG_TX_HI_READY);
-	writel(0, ioaddr + TYPHOON_REG_CMD_READY);
-	writel(0, ioaddr + TYPHOON_REG_TX_LO_READY);
+	iowrite32(0, ioaddr + TYPHOON_REG_TX_HI_READY);
+	iowrite32(0, ioaddr + TYPHOON_REG_CMD_READY);
+	iowrite32(0, ioaddr + TYPHOON_REG_TX_LO_READY);
 	typhoon_post_pci_writes(ioaddr);
-	writel(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND);
+	iowrite32(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND);
 
 	return 0;
 
@@ -1806,7 +1824,8 @@ typhoon_poll(struct net_device *dev, int
 
 	if(done) {
 		netif_rx_complete(dev);
-		writel(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK);
+		iowrite32(TYPHOON_INTR_NONE,
+				tp->ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(tp->ioaddr);
 	}
 
@@ -1821,14 +1840,14 @@ typhoon_interrupt(int irq, void *dev_ins
 	void __iomem *ioaddr = tp->ioaddr;
 	u32 intr_status;
 
-	intr_status = readl(ioaddr + TYPHOON_REG_INTR_STATUS);
+	intr_status = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
 	if(!(intr_status & TYPHOON_INTR_HOST_INT))
 		return IRQ_NONE;
 
-	writel(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
 
 	if(netif_rx_schedule_prep(dev)) {
-		writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+		iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(ioaddr);
 		__netif_rx_schedule(dev);
 	} else {
@@ -1855,7 +1874,7 @@ typhoon_free_rx_rings(struct typhoon *tp
 }
 
 static int
-typhoon_sleep(struct typhoon *tp, int state, u16 events)
+typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
 {
 	struct pci_dev *pdev = tp->pdev;
 	void __iomem *ioaddr = tp->ioaddr;
@@ -1887,7 +1906,7 @@ typhoon_sleep(struct typhoon *tp, int st
 	 */
 	netif_carrier_off(tp->dev);
 
-	pci_enable_wake(tp->pdev, state, 1);
+	pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1);
 	pci_disable_device(pdev);
 	return pci_set_power_state(pdev, pci_choose_state(pdev, state));
 }
@@ -1905,7 +1924,7 @@ typhoon_wakeup(struct typhoon *tp, int w
 	 * we can download the Runtime Image. But let's not make users of
 	 * the old firmware pay for the reset.
 	 */
-	writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
+	iowrite32(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0 ||
 			(tp->capabilities & TYPHOON_WAKEUP_NEEDS_RESET))
 		return typhoon_reset(ioaddr, wait_type);
@@ -1994,8 +2013,8 @@ typhoon_start_runtime(struct typhoon *tp
 	tp->card_state = Running;
 	smp_wmb();
 
-	writel(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
-	writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
+	iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK);
 	typhoon_post_pci_writes(ioaddr);
 
 	return 0;
@@ -2020,7 +2039,7 @@ typhoon_stop_runtime(struct typhoon *tp,
 	 * when called with !netif_running(). This will be posted
 	 * when we force the posting of the command.
 	 */
-	writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
+	iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_DISABLE);
 	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
@@ -2136,7 +2155,7 @@ out_sleep:
 		goto out;
 	}
 
-	if(typhoon_sleep(tp, 3, 0) < 0) 
+	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) 
 		printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
 
 out:
@@ -2163,7 +2182,7 @@ typhoon_close(struct net_device *dev)
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
 		printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
 
-	if(typhoon_sleep(tp, 3, 0) < 0)
+	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
 		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
 
 	return 0;
@@ -2203,7 +2222,7 @@ reset:
 }
 
 static int
-typhoon_suspend(struct pci_dev *pdev, u32 state)
+typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct typhoon *tp = netdev_priv(dev);
@@ -2268,21 +2287,66 @@ need_resume:
 }
 
 static int
-typhoon_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+typhoon_enable_wake(struct pci_dev *pdev, pci_power_t state, int enable)
 {
 	return pci_enable_wake(pdev, state, enable);
 }
 #endif
 
 static int __devinit
+typhoon_test_mmio(struct pci_dev *pdev)
+{
+	void __iomem *ioaddr = pci_iomap(pdev, 1, 128);
+	int mode = 0;
+	u32 val;
+
+	if(!ioaddr)
+		goto out;
+
+	if(ioread32(ioaddr + TYPHOON_REG_STATUS) !=
+				TYPHOON_STATUS_WAITING_FOR_HOST)
+		goto out_unmap;
+
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
+
+	/* Ok, see if we can change our interrupt status register by
+	 * sending ourselves an interrupt. If so, then MMIO works.
+	 * The 50usec delay is arbitrary -- it could probably be smaller.
+	 */
+	val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
+	if((val & TYPHOON_INTR_SELF) == 0) {
+		iowrite32(1, ioaddr + TYPHOON_REG_SELF_INTERRUPT);
+		ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
+		udelay(50);
+		val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
+		if(val & TYPHOON_INTR_SELF)
+			mode = 1;
+	}
+
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+	iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
+	ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
+
+out_unmap:
+	pci_iounmap(pdev, ioaddr);
+
+out:
+	if(!mode)
+		printk(KERN_INFO PFX "falling back to port IO\n");
+	return mode;
+}
+
+static int __devinit
 typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int did_version = 0;
 	struct net_device *dev;
 	struct typhoon *tp;
 	int card_id = (int) ent->driver_data;
-	unsigned long ioaddr;
-	void __iomem *ioaddr_mapped;
+	void __iomem *ioaddr;
 	void *shared;
 	dma_addr_t shared_dma;
 	struct cmd_desc xp_cmd;
@@ -2323,8 +2387,21 @@ typhoon_init_one(struct pci_dev *pdev, c
 		goto error_out_mwi;
 	}
 
-	/* sanity checks, resource #1 is our mmio area
+	/* sanity checks on IO and MMIO BARs
 	 */
+	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+		printk(ERR_PFX
+		       "%s: region #1 not a PCI IO resource, aborting\n",
+		       pci_name(pdev));
+		err = -ENODEV;
+		goto error_out_mwi;
+	}
+	if(pci_resource_len(pdev, 0) < 128) {
+		printk(ERR_PFX "%s: Invalid PCI IO region size, aborting\n",
+		       pci_name(pdev));
+		err = -ENODEV;
+		goto error_out_mwi;
+	}
 	if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
 		printk(ERR_PFX
 		       "%s: region #1 not a PCI MMIO resource, aborting\n",
@@ -2346,12 +2423,14 @@ typhoon_init_one(struct pci_dev *pdev, c
 		goto error_out_mwi;
 	}
 
-	/* map our MMIO region
+	/* map our registers
 	 */
-	ioaddr = pci_resource_start(pdev, 1);
-	ioaddr_mapped = ioremap(ioaddr, 128);
-	if (!ioaddr_mapped) {
-		printk(ERR_PFX "%s: cannot remap MMIO, aborting\n",
+	if(use_mmio != 0 && use_mmio != 1)
+		use_mmio = typhoon_test_mmio(pdev);
+
+	ioaddr = pci_iomap(pdev, use_mmio, 128);
+	if (!ioaddr) {
+		printk(ERR_PFX "%s: cannot remap registers, aborting\n",
 		       pci_name(pdev));
 		err = -EIO;
 		goto error_out_regions;
@@ -2374,13 +2453,10 @@ typhoon_init_one(struct pci_dev *pdev, c
 	tp->shared_dma = shared_dma;
 	tp->pdev = pdev;
 	tp->tx_pdev = pdev;
-	tp->ioaddr = ioaddr_mapped;
-	tp->tx_ioaddr = ioaddr_mapped;
+	tp->ioaddr = ioaddr;
+	tp->tx_ioaddr = ioaddr;
 	tp->dev = dev;
 
-	/* need to be able to restore PCI state after a suspend */
-	pci_save_state(pdev);
-
 	/* Init sequence:
 	 * 1) Reset the adapter to clear any bad juju
 	 * 2) Reload the sleep image
@@ -2388,16 +2464,18 @@ typhoon_init_one(struct pci_dev *pdev, c
 	 * 4) Get the hardware address.
 	 * 5) Put the card to sleep.
 	 */
-	if (typhoon_reset(ioaddr_mapped, WaitSleep) < 0) {
+	if (typhoon_reset(ioaddr, WaitSleep) < 0) {
 		printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev));
 		err = -EIO;
 		goto error_out_dma;
 	}
 
 	/* Now that we've reset the 3XP and are sure it's not going to
-	 * write all over memory, enable bus mastering.
+	 * write all over memory, enable bus mastering, and save our
+	 * state for resuming after a suspend.
 	 */
 	pci_set_master(pdev);
+	pci_save_state(pdev);
 
 	/* dev->name is not valid until we register, but we need to
 	 * use some common routines to initialize the card. So that those
@@ -2438,7 +2516,7 @@ typhoon_init_one(struct pci_dev *pdev, c
 	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
 		printk(ERR_PFX "%s: Could not get Sleep Image version\n",
-			pdev->slot_name);
+			pci_name(pdev));
 		goto error_out_reset;
 	}
 
@@ -2454,7 +2532,7 @@ typhoon_init_one(struct pci_dev *pdev, c
 	if(xp_resp[0].numDesc != 0)
 		tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
 
-	if(typhoon_sleep(tp, 3, 0) < 0) {
+	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) {
 		printk(ERR_PFX "%s: cannot put adapter to sleep\n",
 		       pci_name(pdev));
 		err = -EIO;
@@ -2491,8 +2569,9 @@ typhoon_init_one(struct pci_dev *pdev, c
 
 	pci_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
-	       dev->name, typhoon_card_info[card_id].name, ioaddr);
+	printk(KERN_INFO "%s: %s at %s 0x%lx, ",
+	       dev->name, typhoon_card_info[card_id].name,
+	       use_mmio ? "MMIO" : "IO", pci_resource_start(pdev, use_mmio));
 	for(i = 0; i < 5; i++)
 		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x\n", dev->dev_addr[i]);
@@ -2515,7 +2594,8 @@ typhoon_init_one(struct pci_dev *pdev, c
 		u8 *ver_string = (u8 *) &xp_resp[1];
 		ver_string[25] = 0;
 		printk(KERN_INFO "%s: Typhoon 1.1+ Sleep Image version "
-			"%u.%u.%u.%u %s\n", dev->name, HIPQUAD(sleep_ver),
+			"%02x.%03x.%03x %s\n", dev->name, sleep_ver >> 24,
+			(sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff,
 			ver_string);
 	} else {
 		printk(KERN_WARNING "%s: Unknown Sleep Image version "
@@ -2526,13 +2606,13 @@ typhoon_init_one(struct pci_dev *pdev, c
 	return 0;
 
 error_out_reset:
-	typhoon_reset(ioaddr_mapped, NoWait);
+	typhoon_reset(ioaddr, NoWait);
 
 error_out_dma:
 	pci_free_consistent(pdev, sizeof(struct typhoon_shared),
 			    shared, shared_dma);
 error_out_remap:
-	iounmap(ioaddr_mapped);
+	pci_iounmap(pdev, ioaddr);
 error_out_regions:
 	pci_release_regions(pdev);
 error_out_mwi:
@@ -2555,7 +2635,7 @@ typhoon_remove_one(struct pci_dev *pdev)
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 	typhoon_reset(tp->ioaddr, NoWait);
-	iounmap(tp->ioaddr);
+	pci_iounmap(pdev, tp->ioaddr);
 	pci_free_consistent(pdev, sizeof(struct typhoon_shared),
 			    tp->shared, tp->shared_dma);
 	pci_release_regions(pdev);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -390,7 +390,7 @@ enum backoff_bits {
 
 #ifdef USE_MMIO
 /* Registers we check that mmio and reg are the same. */
-int mmio_verify_registers[] = {
+static const int mmio_verify_registers[] = {
 	RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD,
 	0
 };
@@ -1197,8 +1197,10 @@ static int rhine_open(struct net_device 
 		       dev->name, rp->pdev->irq);
 
 	rc = alloc_ring(dev);
-	if (rc)
+	if (rc) {
+		free_irq(rp->pdev->irq, dev);
 		return rc;
+	}
 	alloc_rbufs(dev);
 	alloc_tbufs(dev);
 	rhine_chip_reset(dev);
@@ -1899,6 +1901,9 @@ static void rhine_shutdown (struct devic
 	struct rhine_private *rp = netdev_priv(dev);
 	void __iomem *ioaddr = rp->base;
 
+	if (!(rp->quirks & rqWOL))
+		return; /* Nothing to do for non-WOL adapters */
+
 	rhine_power_init(dev);
 
 	/* Make sure we use pattern 0, 1 and not 4, 5 */
@@ -1937,7 +1942,7 @@ static void rhine_shutdown (struct devic
 }
 
 #ifdef CONFIG_PM
-static int rhine_suspend(struct pci_dev *pdev, u32 state)
+static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct rhine_private *rp = netdev_priv(dev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -263,7 +263,7 @@ static int velocity_set_media_mode(struc
 
 #ifdef CONFIG_PM
 
-static int velocity_suspend(struct pci_dev *pdev, u32 state);
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
 static int velocity_resume(struct pci_dev *pdev);
 
 static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
@@ -2898,7 +2898,7 @@ static void velocity_get_drvinfo(struct 
 	struct velocity_info *vptr = dev->priv;
 	strcpy(info->driver, VELOCITY_NAME);
 	strcpy(info->version, VELOCITY_VERSION);
-	strcpy(info->bus_info, vptr->pdev->slot_name);
+	strcpy(info->bus_info, pci_name(vptr->pdev));
 }
 
 static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -3096,7 +3096,7 @@ static void velocity_restore_context(str
  *	we are interested in.
  */
 
-u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
 {
 	u16 crc = 0xFFFF;
 	u8 mask;
@@ -3210,9 +3210,10 @@ static int velocity_set_wol(struct veloc
 	return 0;
 }
 
-static int velocity_suspend(struct pci_dev *pdev, u32 state)
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct velocity_info *vptr = netdev_priv(dev);
 	unsigned long flags;
 
 	if(!netif_running(vptr->dev))
@@ -3245,7 +3246,8 @@ static int velocity_suspend(struct pci_d
 
 static int velocity_resume(struct pci_dev *pdev)
 {
-	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct velocity_info *vptr = netdev_priv(dev);
 	unsigned long flags;
 	int i;
 
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -26,7 +26,7 @@ config WAN
 # There is no way to detect a comtrol sv11 - force it modular for now.
 config HOSTESS_SV11
 	tristate "Comtrol Hostess SV-11 support"
-	depends on WAN && ISA && m
+	depends on WAN && ISA && m && ISA_DMA_API
 	help
 	  Driver for Comtrol Hostess SV-11 network card which
 	  operates on low speed synchronous serial links at up to
@@ -38,7 +38,7 @@ config HOSTESS_SV11
 # The COSA/SRP driver has not been tested as non-modular yet.
 config COSA
 	tristate "COSA/SRP sync serial boards support"
-	depends on WAN && ISA && m
+	depends on WAN && ISA && m && ISA_DMA_API
 	---help---
 	  Driver for COSA and SRP synchronous serial boards.
 
@@ -127,7 +127,7 @@ config LANMEDIA
 # There is no way to detect a Sealevel board. Force it modular
 config SEALEVEL_4021
 	tristate "Sealevel Systems 4021 support"
-	depends on WAN && ISA && m
+	depends on WAN && ISA && m && ISA_DMA_API
 	help
 	  This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
 
@@ -155,7 +155,8 @@ config HDLC
 	  Network) card supported by this driver and you are planning to
 	  connect the box to a WAN.
 
-	  You will need supporting software from <http://hq.pm.waw.pl/hdlc/>.
+	  You will need supporting software from
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
 	  Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
 	  Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
 
@@ -225,7 +226,7 @@ config PCI200SYN
 	  Driver for PCI200SYN cards by Goramo sp. j.
 
 	  If you have such a card, say Y here and see
-	  <http://hq.pm.waw.pl/hdlc/>.
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
 
 	  To compile this as a module, choose M here: the
 	  module will be called pci200syn.
@@ -239,7 +240,7 @@ config WANXL
 	  Driver for wanXL PCI cards by SBE Inc.
 
 	  If you have such a card, say Y here and see
-	  <http://hq.pm.waw.pl/hdlc/>.
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
 
 	  To compile this as a module, choose M here: the
 	  module will be called wanxl.
@@ -292,7 +293,7 @@ config N2
 	  SDL Communications Inc.
 
 	  If you have such a card, say Y here and see
-	  <http://hq.pm.waw.pl/hdlc/>.
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
 
 	  Note that N2csu and N2dds cards are not supported by this driver.
 
@@ -308,7 +309,7 @@ config C101
 	  Driver for C101 SuperSync ISA cards by Moxa Technologies Co., Ltd.
 
 	  If you have such a card, say Y here and see
-	  <http://hq.pm.waw.pl/pub/hdlc/>
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called c101.
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -543,7 +543,7 @@ static int cosa_probe(int base, int irq,
 		 * FIXME: When this code is not used as module, we should
 		 * probably call udelay() instead of the interruptible sleep.
 		 */
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		cosa_putstatus(cosa, SR_TX_INT_ENA);
 		schedule_timeout(30);
 		irq = probe_irq_off(irqs);
@@ -1564,8 +1564,7 @@ static int cosa_reset_and_read_id(struct
 	cosa_getdata8(cosa);
 	cosa_putstatus(cosa, SR_RST);
 #ifdef MODULE
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ/2);
+	msleep(500);
 #else
 	udelay(5*100000);
 #endif
@@ -1618,7 +1617,7 @@ static int get_wait_data(struct cosa_dat
 			return r;
 		}
 		/* sleep if not ready to read */
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 	}
 	printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n",
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -436,9 +436,7 @@ static int cycx_wan_new_if(struct wan_de
 	}
 
 	if (err) {
-		if (chan->local_addr)
-			kfree(chan->local_addr);
-
+		kfree(chan->local_addr);
 		kfree(chan);
 		return err;
 	}
@@ -458,9 +456,7 @@ static int cycx_wan_del_if(struct wan_de
 		struct cycx_x25_channel *chan = dev->priv;
 
 		if (chan->svc) {
-			if (chan->local_addr)
-				kfree(chan->local_addr);
-
+			kfree(chan->local_addr);
 			if (chan->state == WAN_CONNECTED)
 				del_timer(&chan->timer);
 		}
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -315,7 +315,7 @@ static inline void sca_rx(card_t *card, 
 #endif
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
-	skb->dev->last_rx = jiffies;
+	dev->last_rx = jiffies;
 	skb->protocol = hdlc_type_trans(skb, dev);
 	netif_rx(skb);
 }
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3427,7 +3427,7 @@ cpc_init_one(struct pci_dev *pdev, const
 {
 	static int first_time = 1;
 	ucchar cpc_rev_id;
-	int err = 0, eeprom_outdated = 0;
+	int err, eeprom_outdated = 0;
 	ucshort device_id;
 	pc300_t *card;
 
@@ -3439,15 +3439,21 @@ cpc_init_one(struct pci_dev *pdev, const
 #endif
 	}
 
+	if ((err = pci_enable_device(pdev)) < 0)
+		return err;
+
 	card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk("PC300 found at RAM 0x%08lx, "
 		       "but could not allocate card structure.\n",
 		       pci_resource_start(pdev, 3));
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto err_disable_dev;
 	}
 	memset(card, 0, sizeof(pc300_t));
 
+	err = -ENODEV;
+
 	/* read PCI configuration area */
 	device_id = ent->device;
 	card->hw.irq = pdev->irq;
@@ -3507,7 +3513,6 @@ cpc_init_one(struct pci_dev *pdev, const
 		printk("PC300 found at RAM 0x%08x, "
 		       "but could not allocate PLX mem region.\n",
 		       card->hw.ramphys);
-		err = -ENODEV;
 		goto err_release_io;
 	}
 	if (!request_mem_region(card->hw.ramphys, card->hw.alloc_ramsize,
@@ -3515,7 +3520,6 @@ cpc_init_one(struct pci_dev *pdev, const
 		printk("PC300 found at RAM 0x%08x, "
 		       "but could not allocate RAM mem region.\n",
 		       card->hw.ramphys);
-		err = -ENODEV;
 		goto err_release_plx;
 	}
 	if (!request_mem_region(card->hw.scaphys, card->hw.scasize,
@@ -3523,13 +3527,9 @@ cpc_init_one(struct pci_dev *pdev, const
 		printk("PC300 found at RAM 0x%08x, "
 		       "but could not allocate SCA mem region.\n",
 		       card->hw.ramphys);
-		err = -ENODEV;
 		goto err_release_ram;
 	}
 
-	if ((err = pci_enable_device(pdev)) != 0)
-		goto err_release_sca;
-
 	card->hw.plxbase = ioremap(card->hw.plxphys, card->hw.plxsize);
 	card->hw.rambase = ioremap(card->hw.ramphys, card->hw.alloc_ramsize);
 	card->hw.scabase = ioremap(card->hw.scaphys, card->hw.scasize);
@@ -3619,7 +3619,6 @@ err_io_unmap:
 		iounmap(card->hw.falcbase);
 		release_mem_region(card->hw.falcphys, card->hw.falcsize);
 	}
-err_release_sca:
 	release_mem_region(card->hw.scaphys, card->hw.scasize);
 err_release_ram:
 	release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize);
@@ -3628,7 +3627,9 @@ err_release_plx:
 err_release_io:
 	release_region(card->hw.iophys, card->hw.iosize);
 	kfree(card);
-	return -ENODEV;
+err_disable_dev:
+	pci_disable_device(pdev);
+	return err;
 }
 
 static void __devexit cpc_remove_one(struct pci_dev *pdev)
@@ -3662,6 +3663,7 @@ static void __devexit cpc_remove_one(str
 		if (card->hw.irq)
 			free_irq(card->hw.irq, card);
 		kfree(card);
+		pci_disable_device(pdev);
 	}
 }
 
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -400,10 +400,8 @@ static void cpc_tty_close(struct tty_str
 		cpc_tty->buf_rx.last = NULL;
 	}
 	
-	if (cpc_tty->buf_tx) {
-		kfree(cpc_tty->buf_tx);
-		cpc_tty->buf_tx = NULL;
-	}
+	kfree(cpc_tty->buf_tx);
+	cpc_tty->buf_tx = NULL;
 
 	CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);
 	
@@ -666,7 +664,7 @@ static void cpc_tty_rx_work(void * data)
 	unsigned long port;
 	int i, j;
 	st_cpc_tty_area *cpc_tty; 
-	volatile st_cpc_rx_buf * buf;
+	volatile st_cpc_rx_buf *buf;
 	char flags=0,flg_rx=1; 
 	struct tty_ldisc *ld;
 
@@ -680,9 +678,9 @@ static void cpc_tty_rx_work(void * data)
 			cpc_tty = &cpc_tty_area[port];
 		
 			if ((buf=cpc_tty->buf_rx.first) != 0) {
-				if(cpc_tty->tty) {
+				if (cpc_tty->tty) {
 					ld = tty_ldisc_ref(cpc_tty->tty);
-					if(ld) {
+					if (ld) {
 						if (ld->receive_buf) {
 							CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
 							ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
@@ -691,7 +689,7 @@ static void cpc_tty_rx_work(void * data)
 					}
 				}	
 				cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
-				kfree((unsigned char *)buf);
+				kfree(buf);
 				buf = cpc_tty->buf_rx.first;
 				flg_rx = 1;
 			}
@@ -733,7 +731,7 @@ static void cpc_tty_rx_disc_frame(pc300c
 
 void cpc_tty_receive(pc300dev_t *pc300dev)
 {
-	st_cpc_tty_area    *cpc_tty; 
+	st_cpc_tty_area *cpc_tty; 
 	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 
 	pc300_t *card = (pc300_t *)pc300chan->card; 
 	int ch = pc300chan->channel; 
@@ -742,7 +740,7 @@ void cpc_tty_receive(pc300dev_t *pc300de
 	int rx_len, rx_aux; 
 	volatile unsigned char status; 
 	unsigned short first_bd = pc300chan->rx_first_bd;
-	st_cpc_rx_buf	*new=NULL;
+	st_cpc_rx_buf *new = NULL;
 	unsigned char dsr_rx;
 
 	if (pc300dev->cpc_tty == NULL) { 
@@ -762,7 +760,7 @@ void cpc_tty_receive(pc300dev_t *pc300de
 			if (status & DST_EOM) {
 				break;
 			}
-			ptdescr=(pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next));
+			ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next));
 		}
 			
 		if (!rx_len) { 
@@ -771,10 +769,7 @@ void cpc_tty_receive(pc300dev_t *pc300de
 				cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), 
 						RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 
 			}
-			if (new) {
-				kfree(new);
-				new = NULL;
-			}
+			kfree(new);
 			return; 
 		}
 		
@@ -787,7 +782,7 @@ void cpc_tty_receive(pc300dev_t *pc300de
 			continue;
 		} 
 		
-		new = (st_cpc_rx_buf *) kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
+		new = (st_cpc_rx_buf *)kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
 		if (new == 0) {
 			cpc_tty_rx_disc_frame(pc300chan);
 			continue;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -176,7 +176,7 @@ static u32	mac[  SBNI_MAX_NUM_CARDS ] __
 
 #ifndef MODULE
 typedef u32  iarr[];
-static iarr  *dest[5] = { &io, &irq, &baud, &rxl, &mac };
+static iarr __initdata *dest[5] = { &io, &irq, &baud, &rxl, &mac };
 #endif
 
 /* A zero-terminated list of I/O addresses to be probed on ISA bus */
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
--- a/drivers/net/wan/sdla_chdlc.c
+++ b/drivers/net/wan/sdla_chdlc.c
@@ -3664,15 +3664,10 @@ static void wanpipe_tty_close(struct tty
 		chdlc_disable_comm_shutdown(card);
 		unlock_adapter_irq(&card->wandev.lock,&smp_flags);
 
-		if (card->tty_buf){
-			kfree(card->tty_buf);
-			card->tty_buf=NULL;			
-		}
-
-		if (card->tty_rx){
-			kfree(card->tty_rx);
-			card->tty_rx=NULL;
-		}
+		kfree(card->tty_buf);
+		card->tty_buf = NULL;			
+		kfree(card->tty_rx);
+		card->tty_rx = NULL;
 	}
 	return;
 }
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -72,7 +72,7 @@ typedef struct card_t {
 	u8 irq;
 
 	u8 __iomem *plx;	/* PLX PCI9060 virtual base address */
-	struct pci_dev *pdev;	/* for pdev->slot_name */
+	struct pci_dev *pdev;	/* for pci_name(pdev) */
 	int rx_in;
 	struct sk_buff *rx_skbs[RX_QUEUE_LENGTH];
 	card_status_t *status;	/* shared between host and card */
@@ -88,12 +88,6 @@ static inline port_t* dev_to_port(struct
 }
 
 
-static inline const char* card_name(struct pci_dev *pdev)
-{
-	return pdev->slot_name;
-}
-
-
 static inline port_status_t* get_status(port_t *port)
 {
 	return &port->card->status->port_status[port->node];
@@ -107,7 +101,7 @@ static inline dma_addr_t pci_map_single_
 	dma_addr_t addr = pci_map_single(pdev, ptr, size, direction);
 	if (addr + size > 0x100000000LL)
 		printk(KERN_CRIT "wanXL %s: pci_map_single() returned memory"
-		       " at 0x%LX!\n", card_name(pdev),
+		       " at 0x%LX!\n", pci_name(pdev),
 		       (unsigned long long)addr);
 	return addr;
 }
@@ -201,7 +195,7 @@ static inline void wanxl_rx_intr(card_t 
 	       desc->stat != PACKET_EMPTY) {
 		if ((desc->stat & PACKET_PORT_MASK) > card->n_ports)
 			printk(KERN_CRIT "wanXL %s: received packet for"
-			       " nonexistent port\n", card_name(card->pdev));
+			       " nonexistent port\n", pci_name(card->pdev));
 		else {
 			struct sk_buff *skb = card->rx_skbs[card->rx_in];
 			port_t *port = &card->ports[desc->stat &
@@ -604,7 +598,7 @@ static int __devinit wanxl_pci_init_one(
 	card = kmalloc(alloc_size, GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
-		       card_name(pdev));
+		       pci_name(pdev));
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		return -ENOBUFS;
@@ -623,7 +617,7 @@ static int __devinit wanxl_pci_init_one(
 
 #ifdef DEBUG_PCI
 	printk(KERN_DEBUG "wanXL %s: pci_alloc_consistent() returned memory"
-	       " at 0x%LX\n", card_name(pdev),
+	       " at 0x%LX\n", pci_name(pdev),
 	       (unsigned long long)card->status_address);
 #endif
 
@@ -649,7 +643,7 @@ static int __devinit wanxl_pci_init_one(
 	while ((stat = readl(card->plx + PLX_MAILBOX_0)) != 0) {
 		if (time_before(timeout, jiffies)) {
 			printk(KERN_WARNING "wanXL %s: timeout waiting for"
-			       " PUTS to complete\n", card_name(pdev));
+			       " PUTS to complete\n", pci_name(pdev));
 			wanxl_pci_remove_one(pdev);
 			return -ENODEV;
 		}
@@ -661,7 +655,7 @@ static int __devinit wanxl_pci_init_one(
 
 		default:
 			printk(KERN_WARNING "wanXL %s: PUTS test 0x%X"
-			       " failed\n", card_name(pdev), stat & 0x30);
+			       " failed\n", pci_name(pdev), stat & 0x30);
 			wanxl_pci_remove_one(pdev);
 			return -ENODEV;
 		}
@@ -681,7 +675,7 @@ static int __devinit wanxl_pci_init_one(
 	    (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * ports) {
 		printk(KERN_WARNING "wanXL %s: no enough on-board RAM"
 		       " (%u bytes detected, %u bytes required)\n",
-		       card_name(pdev), ramsize, BUFFERS_ADDR +
+		       pci_name(pdev), ramsize, BUFFERS_ADDR +
 		       (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * ports);
 		wanxl_pci_remove_one(pdev);
 		return -ENODEV;
@@ -689,7 +683,7 @@ static int __devinit wanxl_pci_init_one(
 
 	if (wanxl_puts_command(card, MBX1_CMD_BSWAP)) {
 		printk(KERN_WARNING "wanXL %s: unable to Set Byte Swap"
-		       " Mode\n", card_name(pdev));
+		       " Mode\n", pci_name(pdev));
 		wanxl_pci_remove_one(pdev);
 		return -ENODEV;
 	}
@@ -720,7 +714,7 @@ static int __devinit wanxl_pci_init_one(
 
 	if (wanxl_puts_command(card, MBX1_CMD_ABORTJ)) {
 		printk(KERN_WARNING "wanXL %s: unable to Abort and Jump\n",
-		       card_name(pdev));
+		       pci_name(pdev));
 		wanxl_pci_remove_one(pdev);
 		return -ENODEV;
 	}
@@ -735,7 +729,7 @@ static int __devinit wanxl_pci_init_one(
 
 	if (!stat) {
 		printk(KERN_WARNING "wanXL %s: timeout while initializing card"
-		       "firmware\n", card_name(pdev));
+		       "firmware\n", pci_name(pdev));
 		wanxl_pci_remove_one(pdev);
 		return -ENODEV;
 	}
@@ -745,12 +739,12 @@ static int __devinit wanxl_pci_init_one(
 #endif
 
 	printk(KERN_INFO "wanXL %s: at 0x%X, %u KB of RAM at 0x%X, irq %u\n",
-	       card_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq);
+	       pci_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq);
 
 	/* Allocate IRQ */
 	if (request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) {
 		printk(KERN_WARNING "wanXL %s: could not allocate IRQ%i.\n",
-		       card_name(pdev), pdev->irq);
+		       pci_name(pdev), pdev->irq);
 		wanxl_pci_remove_one(pdev);
 		return -EBUSY;
 	}
@@ -762,7 +756,7 @@ static int __devinit wanxl_pci_init_one(
 		struct net_device *dev = alloc_hdlcdev(port);
 		if (!dev) {
 			printk(KERN_ERR "wanXL %s: unable to allocate"
-			       " memory\n", card_name(pdev));
+			       " memory\n", pci_name(pdev));
 			wanxl_pci_remove_one(pdev);
 			return -ENOMEM;
 		}
@@ -783,7 +777,7 @@ static int __devinit wanxl_pci_init_one(
 		get_status(port)->clocking = CLOCK_EXT;
 		if (register_hdlc_device(dev)) {
 			printk(KERN_ERR "wanXL %s: unable to register hdlc"
-			       " device\n", card_name(pdev));
+			       " device\n", pci_name(pdev));
 			free_netdev(dev);
 			wanxl_pci_remove_one(pdev);
 			return -ENOBUFS;
@@ -791,7 +785,7 @@ static int __devinit wanxl_pci_init_one(
 		card->n_ports++;
 	}
 
-	printk(KERN_INFO "wanXL %s: port", card_name(pdev));
+	printk(KERN_INFO "wanXL %s: port", pci_name(pdev));
 	for (i = 0; i < ports; i++)
 		printk("%s #%i: %s", i ? "," : "", i,
 		       card->ports[i].dev->name);
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -107,13 +107,9 @@ static struct x25_asy *x25_asy_alloc(voi
 static void x25_asy_free(struct x25_asy *sl)
 {
 	/* Free all X.25 frame buffers. */
-	if (sl->rbuff)  {
-		kfree(sl->rbuff);
-	}
+	kfree(sl->rbuff);
 	sl->rbuff = NULL;
-	if (sl->xbuff)  {
-		kfree(sl->xbuff);
-	}
+	kfree(sl->xbuff);
 	sl->xbuff = NULL;
 
 	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
@@ -134,10 +130,8 @@ static int x25_asy_change_mtu(struct net
 	{
 		printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
 		       dev->name);
-		if (xbuff != NULL)  
-			kfree(xbuff);
-		if (rbuff != NULL)  
-			kfree(rbuff);
+		kfree(xbuff);
+		kfree(rbuff);
 		return -ENOMEM;
 	}
 
@@ -169,10 +163,8 @@ static int x25_asy_change_mtu(struct net
 
 	spin_unlock_bh(&sl->lock);
 
-	if (xbuff != NULL) 
-		kfree(xbuff);
-	if (rbuff != NULL)
-		kfree(rbuff);
+	kfree(xbuff);
+	kfree(rbuff);
 	return 0;
 }
 
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -734,7 +734,7 @@ irqreturn_t z8530_interrupt(int irq, voi
 	u8 intr;
 	static volatile int locker=0;
 	int work=0;
-	struct z8530_irqhandler *irqs=dev->chanA.irqs;
+	struct z8530_irqhandler *irqs;
 	
 	if(locker)
 	{
@@ -758,6 +758,8 @@ irqreturn_t z8530_interrupt(int irq, voi
 		/* Now walk the chip and see what it is wanting - it may be
 		   an IRQ for someone else remember */
 		   
+		irqs=dev->chanA.irqs;
+
 		if(intr & (CHARxIP|CHATxIP|CHAEXT))
 		{
 			if(intr&CHARxIP)
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -131,6 +131,7 @@ static void cleanup_card(struct net_devi
 {
 	free_irq(dev->irq, dev);
 	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
+	iounmap(ei_status.mem);
 }
 
 #ifndef MODULE
@@ -317,16 +318,22 @@ static int __init wd_probe1(struct net_d
 	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 
 	/* Don't map in the shared memory until the board is actually opened. */
-	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 
 	/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
 	if (dev->mem_end != 0) {
 		ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+		ei_status.priv = dev->mem_end - dev->mem_start;
 	} else {
 		ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 		dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
+		ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
+	}
+
+	ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
+	if (!ei_status.mem) {
+		free_irq(dev->irq, dev);
+		return -ENOMEM;
 	}
-	ei_status.rmem_end = dev->mem_end;
 
 	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
@@ -397,7 +404,7 @@ wd_get_8390_hdr(struct net_device *dev, 
 {
 
 	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	unsigned long hdr_start = dev->mem_start + ((ring_page - WD_START_PG)<<8);
+	void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
 
 	/* We'll always get a 4 byte header read followed by a packet read, so
 	   we enable 16 bit mode before the header, and disable after the body. */
@@ -407,10 +414,10 @@ wd_get_8390_hdr(struct net_device *dev, 
 #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));
+	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);
+	((unsigned int*)hdr)[0] = readl(hdr_start);
 #endif
 }
 
@@ -423,17 +430,18 @@ static void
 wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
 	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
+	unsigned long offset = ring_offset - (WD_START_PG<<8);
+	void __iomem *xfer_start = ei_status.mem + offset;
 
-	if (xfer_start + count > ei_status.rmem_end) {
+	if (offset + count > ei_status.priv) {
 		/* We must wrap the input move. */
-		int semi_count = ei_status.rmem_end - xfer_start;
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		int semi_count = ei_status.priv - offset;
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 
 	/* Turn off 16 bit access so that reboot works.	 ISA brain-damage */
@@ -446,16 +454,16 @@ wd_block_output(struct net_device *dev, 
 				int start_page)
 {
 	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
+	void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
 
 
 	if (ei_status.word16) {
 		/* Turn on and off 16 bit access so that reboot works. */
 		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-		isa_memcpy_toio(shmem, buf, count);
+		memcpy_toio(shmem, buf, count);
 		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 	} else
-		isa_memcpy_toio(shmem, buf, count);
+		memcpy_toio(shmem, buf, count);
 }
 
 
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -323,7 +323,7 @@ config PRISM54
 	  For a complete list of supported cards visit <http://prism54.org>.
 	  Here is the latest confirmed list of supported cards:
 
-	  3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72
+	  3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1)
 	  Allnet ALL0271 PCI Card
 	  Compex WL54G Cardbus Card
 	  Corega CG-WLCB54GT Cardbus Card
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -61,7 +61,7 @@ MODULE_DEVICE_TABLE(pci, card_ids);
 
 static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
 static void airo_pci_remove(struct pci_dev *);
-static int airo_pci_suspend(struct pci_dev *pdev, u32 state);
+static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
 static int airo_pci_resume(struct pci_dev *pdev);
 
 static struct pci_driver airo_driver = {
@@ -754,7 +754,7 @@ typedef struct {
   u8 zero;
   u8 ssidLen;
   u8 ssid[32];
-  u16 rssi;
+  u16 dBm;
 #define CAP_ESS (1<<0)
 #define CAP_IBSS (1<<1)
 #define CAP_PRIVACY (1<<4)
@@ -1125,6 +1125,9 @@ static int 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);
 
+static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
+static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
+
 #include <linux/crypto.h>
 #endif
 
@@ -1698,9 +1701,8 @@ static int readBSSListRid(struct airo_in
 			issuecommand(ai, &cmd, &rsp);
 			up(&ai->sem);
 			/* Let the command take effect */
-			set_current_state (TASK_INTERRUPTIBLE);
 			ai->task = current;
-			schedule_timeout (3*HZ);
+			ssleep(3);
 			ai->task = NULL;
 		}
 	rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
@@ -1714,6 +1716,7 @@ static int readBSSListRid(struct airo_in
 	list->fh.dwell = le16_to_cpu(list->fh.dwell);
 	list->dsChannel = le16_to_cpu(list->dsChannel);
 	list->atimWindow = le16_to_cpu(list->atimWindow);
+	list->dBm = le16_to_cpu(list->dBm);
 	return rc;
 }
 
@@ -2685,11 +2688,9 @@ int reset_card( struct net_device *dev ,
 		return -1;
 	waitbusy (ai);
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ/5);
+	msleep(200);
 	waitbusy (ai);
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ/5);
+	msleep(200);
 	if (lock)
 		up(&ai->sem);
 	return 0;
@@ -3248,7 +3249,10 @@ badrx:
 					wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
 				else
 					wstats.level = (hdr.rssi[1] + 321) / 2;
-				wstats.updated = 3;	
+				wstats.noise = apriv->wstats.qual.noise;
+				wstats.updated = IW_QUAL_LEVEL_UPDATED
+					| IW_QUAL_QUAL_UPDATED
+					| IW_QUAL_NOISE_UPDATED;
 				/* Update spy records */
 				wireless_spy_update(dev, sa, &wstats);
 			}
@@ -3443,7 +3447,7 @@ static void mpi_receive_802_3(struct air
 	/* Make sure we got something */
 	if (rxd.rdy && rxd.valid == 0) {
 		len = rxd.len + 12;
-		if (len < 12 && len > 2048)
+		if (len < 12 || len > 2048)
 			goto badrx;
 
 		skb = dev_alloc_skb(len);
@@ -3591,7 +3595,10 @@ void mpi_receive_802_11 (struct airo_inf
 			wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
 		else
 			wstats.level = (hdr.rssi[1] + 321) / 2;
-		wstats.updated = 3;
+		wstats.noise = ai->wstats.qual.noise;
+		wstats.updated = IW_QUAL_QUAL_UPDATED
+			| IW_QUAL_LEVEL_UPDATED
+			| IW_QUAL_NOISE_UPDATED;
 		/* Update spy records */
 		wireless_spy_update(ai->dev, sa, &wstats);
 	}
@@ -3682,7 +3689,7 @@ static u16 setup_card(struct airo_info *
 		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
 		if ( status == SUCCESS ) {
 			if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
-				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
+				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
 		}
 		else {
 			if (ai->rssi) {
@@ -5351,7 +5358,7 @@ static int proc_BSSList_open( struct ino
 				(int)BSSList_rid.bssid[5],
 				(int)BSSList_rid.ssidLen,
 				BSSList_rid.ssid,
-				(int)BSSList_rid.rssi);
+				(int)BSSList_rid.dBm);
 		ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
 				(int)BSSList_rid.dsChannel,
 				BSSList_rid.cap & CAP_ESS ? "ESS" : "",
@@ -5467,7 +5474,7 @@ static void __devexit airo_pci_remove(st
 {
 }
 
-static int airo_pci_suspend(struct pci_dev *pdev, u32 state)
+static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct airo_info *ai = dev->priv;
@@ -5516,12 +5523,12 @@ static int airo_pci_resume(struct pci_de
 	} else {
 		OUT4500(ai, EVACK, EV_AWAKEN);
 		OUT4500(ai, EVACK, EV_AWAKEN);
-		schedule_timeout(HZ/10);
+		msleep(100);
 	}
 
 	set_bit (FLAG_COMMIT, &ai->flags);
 	disable_MAC(ai, 0);
-        schedule_timeout (HZ/5);
+        msleep(200);
 	if (ai->SSID) {
 		writeSsidRid(ai, ai->SSID, 0);
 		kfree(ai->SSID);
@@ -5596,6 +5603,29 @@ static void __exit airo_cleanup_module( 
  * would not work at all... - Jean II
  */
 
+static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
+{
+	if( !rssi_rid )
+		return 0;
+
+	return (0x100 - rssi_rid[rssi].rssidBm);
+}
+
+static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
+{
+	int i;
+
+	if( !rssi_rid )
+		return 0;
+
+	for( i = 0; i < 256; i++ )
+		if (rssi_rid[i].rssidBm == dbm)
+			return rssi_rid[i].rssipct;
+
+	return 0;
+}
+
+
 static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
 {
 	int quality = 0;
@@ -6446,11 +6476,29 @@ static int airo_get_range(struct net_dev
 	}
 	range->num_frequency = k;
 
+	range->sensitivity = 65535;
+
 	/* Hum... Should put the right values there */
-	range->max_qual.qual = airo_get_max_quality(&cap_rid);
-	range->max_qual.level = 0x100 - 120;	/* -120 dBm */
+	if (local->rssi)
+		range->max_qual.qual = 100;	/* % */
+	else
+		range->max_qual.qual = airo_get_max_quality(&cap_rid);
+	range->max_qual.level = 0;	/* 0 means we use dBm  */
 	range->max_qual.noise = 0;
-	range->sensitivity = 65535;
+	range->max_qual.updated = 0;
+
+	/* Experimental measurements - boundary 11/5.5 Mb/s */
+	/* Note : with or without the (local->rssi), results
+	 * are somewhat different. - Jean II */
+	if (local->rssi) {
+		range->avg_qual.qual = 50;	/* % */
+		range->avg_qual.level = 186;	/* -70 dBm */
+	} else {
+		range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
+		range->avg_qual.level = 176;	/* -80 dBm */
+	}
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = 0;
 
 	for(i = 0 ; i < 8 ; i++) {
 		range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
@@ -6511,15 +6559,6 @@ static int airo_get_range(struct net_dev
 	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 = airo_get_avg_quality(&cap_rid);
-	if (local->rssi)
-		range->avg_qual.level = 186;	/* -70 dBm */
-	else
-		range->avg_qual.level = 176;	/* -80 dBm */
-	range->avg_qual.noise = 0;
 
 	/* Event capability (kernel + driver) */
 	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
@@ -6679,12 +6718,18 @@ static int airo_get_aplist(struct net_de
 		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 (local->rssi) {
+			qual[i].level = 0x100 - BSSList.dBm;
+			qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
+			qual[i].updated = IW_QUAL_QUAL_UPDATED;
+		} else {
+			qual[i].level = (BSSList.dBm + 321) / 2;
+			qual[i].qual = 0;
+			qual[i].updated = IW_QUAL_QUAL_INVALID;
+		}
+		qual[i].noise = local->wstats.qual.noise;
+		qual[i].updated = IW_QUAL_LEVEL_UPDATED
+				| IW_QUAL_NOISE_UPDATED;
 		if (BSSList.index == 0xffff)
 			break;
 	}
@@ -6763,7 +6808,7 @@ static int airo_set_scan(struct net_devi
 static inline char *airo_translate_scan(struct net_device *dev,
 					char *current_ev,
 					char *end_buf,
-					BSSListRid *list)
+					BSSListRid *bss)
 {
 	struct airo_info *ai = dev->priv;
 	struct iw_event		iwe;		/* Temporary buffer */
@@ -6774,22 +6819,22 @@ static inline char *airo_translate_scan(
 	/* 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);
+	memcpy(iwe.u.ap_addr.sa_data, bss->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;
+	iwe.u.data.length = bss->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);
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
 
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
-	capabilities = le16_to_cpu(list->cap);
+	capabilities = le16_to_cpu(bss->cap);
 	if(capabilities & (CAP_ESS | CAP_IBSS)) {
 		if(capabilities & CAP_ESS)
 			iwe.u.mode = IW_MODE_MASTER;
@@ -6800,19 +6845,25 @@ static inline char *airo_translate_scan(
 
 	/* Add frequency */
 	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = le16_to_cpu(list->dsChannel);
+	iwe.u.freq.m = le16_to_cpu(bss->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;
+	if (ai->rssi) {
+		iwe.u.qual.level = 0x100 - bss->dBm;
+		iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
+		iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
+	} else {
+		iwe.u.qual.level = (bss->dBm + 321) / 2;
+		iwe.u.qual.qual = 0;
+		iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
+	}
+	iwe.u.qual.noise = ai->wstats.qual.noise;
+	iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
+			| IW_QUAL_NOISE_UPDATED;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
 	/* Add encryption capability */
@@ -6822,7 +6873,7 @@ static inline char *airo_translate_scan(
 	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);
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
 
 	/* Rate : stuffing multiple values in a single event require a bit
 	 * more of magic - Jean II */
@@ -6834,10 +6885,10 @@ static inline char *airo_translate_scan(
 	/* Max 8 values */
 	for(i = 0 ; i < 8 ; i++) {
 		/* NULL terminated */
-		if(list->rates[i] == 0)
+		if(bss->rates[i] == 0)
 			break;
 		/* Bit rate given in 500 kb/s units (+ 0x80) */
-		iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000);
+		iwe.u.bitrate.value = ((bss->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);
 	}
@@ -7156,18 +7207,22 @@ static void airo_read_wireless_stats(str
 	/* The status */
 	local->wstats.status = status_rid.mode;
 
-	/* Signal quality and co. But where is the noise level ??? */
-	local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
-	if (local->rssi)
-		local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
-	else
+	/* Signal quality and co */
+	if (local->rssi) {
+		local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
+		/* normalizedSignalStrength appears to be a percentage */
+		local->wstats.qual.qual = status_rid.normalizedSignalStrength;
+	} else {
 		local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
+		local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
+	}
+	local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
 	if (status_rid.len >= 124) {
-		local->wstats.qual.noise = 256 - status_rid.noisedBm;
-		local->wstats.qual.updated = 7;
+		local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
+		local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
 	} else {
 		local->wstats.qual.noise = 0;
-		local->wstats.qual.updated = 3;
+		local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
 	}
 
 	/* Packets discarded in the wireless adapter due to wireless
@@ -7470,8 +7525,7 @@ int cmdreset(struct airo_info *ai) {
 
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
 
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ);          /* WAS 600 12/7/00 */
+	ssleep(1);			/* WAS 600 12/7/00 */
 
 	if(!waitbusy (ai)){
 		printk(KERN_INFO "Waitbusy hang AFTER RESET\n");
@@ -7498,8 +7552,7 @@ int setflashmode (struct airo_info *ai) 
 		OUT4500(ai, SWS3, FLASH_COMMAND);
 		OUT4500(ai, COMMAND,0);
 	}
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ/2); /* 500ms delay */
+	msleep(500);		/* 500ms delay */
 
 	if(!waitbusy(ai)) {
 		clear_bit (FLAG_FLASHING, &ai->flags);
@@ -7609,8 +7662,7 @@ int flashputbuf(struct airo_info *ai){
 int flashrestart(struct airo_info *ai,struct net_device *dev){
 	int    i,status;
 
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ);          /* Added 12/7/00 */
+	ssleep(1);			/* Added 12/7/00 */
 	clear_bit (FLAG_FLASHING, &ai->flags);
 	if (test_bit(FLAG_MPI, &ai->flags)) {
 		status = mpi_init_descriptors(ai);
@@ -7625,8 +7677,7 @@ int flashrestart(struct airo_info *ai,st
 				( ai, 2312, i >= MAX_FIDS / 2 );
 		}
 
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	schedule_timeout (HZ);          /* Added 12/7/00 */
+	ssleep(1);			/* Added 12/7/00 */
 	return status;
 }
 #endif /* CISCO_EXT */
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -28,7 +28,6 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -45,13 +44,13 @@
 
 struct airport {
 	struct macio_dev *mdev;
-	void *vaddr;
+	void __iomem *vaddr;
 	int irq_requested;
 	int ndev_registered;
 };
 
 static int
-airport_suspend(struct macio_dev *mdev, u32 state)
+airport_suspend(struct macio_dev *mdev, pm_message_t state)
 {
 	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -150,7 +149,7 @@ airport_detach(struct macio_dev *mdev)
 	ssleep(1);
 
 	macio_set_drvdata(mdev, NULL);
-	free_netdev(dev);
+	free_orinocodev(dev);
 
 	return 0;
 }
@@ -194,14 +193,14 @@ airport_attach(struct macio_dev *mdev, c
 	hermes_t *hw;
 
 	if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
-		printk(KERN_ERR PFX "wrong interrupt/addresses in OF tree\n");
+		printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
 		return -ENODEV;
 	}
 
 	/* Allocate space for private device-specific data */
 	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
 	if (! dev) {
-		printk(KERN_ERR PFX "can't allocate device datas\n");
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		return -ENODEV;
 	}
 	priv = netdev_priv(dev);
@@ -212,7 +211,7 @@ airport_attach(struct macio_dev *mdev, c
 
 	if (macio_request_resource(mdev, 0, "airport")) {
 		printk(KERN_ERR PFX "can't request IO resource !\n");
-		free_netdev(dev);
+		free_orinocodev(dev);
 		return -EBUSY;
 	}
 
@@ -224,16 +223,15 @@ airport_attach(struct macio_dev *mdev, c
 	/* Setup interrupts & base address */
 	dev->irq = macio_irq(mdev, 0);
 	phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
-	printk(KERN_DEBUG PFX "Airport at physical address %lx\n", phys_addr);
+	printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
 	dev->base_addr = phys_addr;
 	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
 	if (!card->vaddr) {
-		printk(PFX "ioremap() failed\n");
+		printk(KERN_ERR PFX "ioremap() failed\n");
 		goto failed;
 	}
 
-	hermes_struct_init(hw, (ulong)card->vaddr,
-			HERMES_MEM, HERMES_16BIT_REGSPACING);
+	hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
 		
 	/* Power up card */
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
@@ -242,7 +240,7 @@ airport_attach(struct macio_dev *mdev, c
 	/* Reset it before we get the interrupt */
 	hermes_init(hw);
 
-	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) {
+	if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
 		printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
 		goto failed;
 	}
@@ -253,7 +251,7 @@ airport_attach(struct macio_dev *mdev, c
 		printk(KERN_ERR PFX "register_netdev() failed\n");
 		goto failed;
 	}
-	printk(KERN_DEBUG PFX "card registered for interface %s\n", dev->name);
+	printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
 	return 0;
  failed:
diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h
--- a/drivers/net/wireless/arlan.h
+++ b/drivers/net/wireless/arlan.h
@@ -43,8 +43,8 @@
 extern int init_arlan_proc(void);
 extern void cleanup_arlan_proc(void);
 #else
-#define init_arlan_proc()	(0)
-#define cleanup_arlan_proc()	do { } while (0);
+#define init_arlan_proc()	({ 0; })
+#define cleanup_arlan_proc()	do { } while (0)
 #endif
 
 extern struct net_device *arlan_device[MAX_ARLANS];
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -69,6 +69,7 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include "ieee802_11.h"
+#include "atmel.h"
 
 #define DRIVER_MAJOR 0
 #define DRIVER_MINOR 96
@@ -83,6 +84,23 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x 
 static char *firmware = NULL;
 module_param(firmware, charp, 0);
 
+/* table of firmware file names */
+static struct { 
+	AtmelFWType fw_type;
+	const char *fw_file;
+	const char *fw_file_ext;
+} fw_table[] = {
+	{ ATMEL_FW_TYPE_502,      "atmel_at76c502",      "bin" },
+	{ ATMEL_FW_TYPE_502D,     "atmel_at76c502d",     "bin" },
+	{ ATMEL_FW_TYPE_502E,     "atmel_at76c502e",     "bin" },
+	{ ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" },
+	{ ATMEL_FW_TYPE_504,      "atmel_at76c504",      "bin" },
+	{ ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" },
+	{ ATMEL_FW_TYPE_504A_2958,"atmel_at76c504a_2958","bin" },
+	{ ATMEL_FW_TYPE_506,      "atmel_at76c506",      "bin" },
+	{ ATMEL_FW_TYPE_NONE,      NULL,                  NULL }
+};
+
 #define MAX_SSID_LENGTH 32
 #define MGMT_JIFFIES (256 * HZ / 100)
 
@@ -458,8 +476,8 @@ struct atmel_private {
 	void *card; /* Bus dependent stucture varies for PCcard */
 	int (*present_callback)(void *); /* And callback which uses it */
 	char firmware_id[32];
-	char firmware_template[32];
-	unsigned char *firmware;
+	AtmelFWType firmware_type;
+	u8 *firmware;
 	int firmware_length;
 	struct timer_list management_timer;
 	struct net_device *dev;
@@ -1293,17 +1311,21 @@ static struct iw_statistics *atmel_get_w
 	if (priv->operating_mode == IW_MODE_INFRA) {
 		if (priv->station_state != STATION_STATE_READY) {
 			priv->wstats.qual.qual = 0;
-			priv->wstats.qual.level	= 0;
+			priv->wstats.qual.level = 0;
+			priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID
+					| IW_QUAL_LEVEL_INVALID);
 		}
 		priv->wstats.qual.noise = 0;
-		priv->wstats.qual.updated = 7;
+		priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
 	} else {
 		/* Quality levels cannot be determined in ad-hoc mode,
 		   because we can 'hear' more that one remote station. */
 		priv->wstats.qual.qual = 0;
 		priv->wstats.qual.level	= 0;
 		priv->wstats.qual.noise	= 0;
-		priv->wstats.qual.updated = 0;
+		priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID
+					| IW_QUAL_LEVEL_INVALID
+					| IW_QUAL_NOISE_INVALID;
 		priv->wstats.miss.beacon = 0;
 	}
 	
@@ -1482,7 +1504,7 @@ static int atmel_read_proc(char *page, c
         return len;
 }
 
-struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware_id,  
+struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWType fw_type,  
 				    struct device *sys_dev, int (*card_present)(void *), void *card)
 {
 	struct net_device *dev;
@@ -1507,11 +1529,9 @@ struct net_device *init_atmel_card( unsi
 	priv->card = card;
 	priv->firmware = NULL;
 	priv->firmware_id[0] = '\0';
-	priv->firmware_template[0] = '\0';
+	priv->firmware_type = fw_type;
 	if (firmware) /* module parameter */
 		strcpy(priv->firmware_id, firmware);
-	else if (firmware_id) /* from PCMCIA card-matching or PCI */
-		strcpy(priv->firmware_template, firmware_id);
 	priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI;
 	priv->station_state = STATION_STATE_DOWN;
 	priv->do_rx_crc = 0;
@@ -1579,6 +1599,8 @@ struct net_device *init_atmel_card( unsi
 	dev->irq = irq;
 	dev->base_addr = port;
 	
+	SET_NETDEV_DEV(dev, sys_dev);
+	
 	if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) {
 		printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc );
 		goto err_out_free;
@@ -2218,6 +2240,13 @@ static int atmel_get_range(struct net_de
 	range->max_qual.qual = 100;
 	range->max_qual.level = 100;
 	range->max_qual.noise = 0;
+	range->max_qual.updated = IW_QUAL_NOISE_INVALID;
+
+	range->avg_qual.qual = 50;
+	range->avg_qual.level = 50;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
+
 	range->sensitivity = 0;
 
 	range->bitrate[0] =  1000000;
@@ -2247,9 +2276,6 @@ static int atmel_get_range(struct net_de
 	range->r_time_flags = 0;
 	range->min_retry = 1;
 	range->max_retry = 65535;
-	range->avg_qual.qual = 50;
-	range->avg_qual.level = 50;
-	range->avg_qual.noise = 0;
 
 	return 0;
 }
@@ -3025,16 +3051,23 @@ static void restart_search(struct atmel_
 static void smooth_rssi(struct atmel_private *priv, u8 rssi)
 {
 	u8 old = priv->wstats.qual.level;
+	u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */
 
-	/* 502-rmfd-revd gives max signal level as 42, by experiment.
-	   This is going to break for other hardware variants. */
+	switch (priv->firmware_type) {
+		case ATMEL_FW_TYPE_502E:
+			max_rssi = 63; /* 502-rmfd-reve max by experiment */
+			break;
+		default:
+			break;
+	}
 
-	rssi = rssi * 100 / 42;
+	rssi = rssi * 100 / max_rssi;
 	if((rssi + old) % 2)
 		priv->wstats.qual.level =  ((rssi + old)/2) + 1;
 	else
 		priv->wstats.qual.level =  ((rssi + old)/2);		
-	
+	priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
+	priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID;
 }
 
 static void atmel_smooth_qual(struct atmel_private *priv)
@@ -3047,8 +3080,10 @@ static void atmel_smooth_qual(struct atm
 			priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000;
 		priv->beacons_this_sec = 0;
 	}
+	priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
+	priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID;
 }
-	
+
 /* deals with incoming managment frames. */
 static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, 
 		      u16 frame_len, u8 rssi)
@@ -3611,8 +3646,8 @@ static int reset_atmel_card(struct net_d
 		const struct firmware *fw_entry = NULL;
 		unsigned char *fw;
 		int len = priv->firmware_length;
-		if (!(fw = priv->firmware)) { 
-			if (strlen(priv->firmware_template) == 0) {	
+		if (!(fw = priv->firmware)) {
+			if (priv->firmware_type == ATMEL_FW_TYPE_NONE) {
 				if (strlen(priv->firmware_id) == 0) {
 					printk(KERN_INFO
 					       "%s: card type is unknown: assuming at76c502 firmware is OK.\n",
@@ -3627,24 +3662,36 @@ static int reset_atmel_card(struct net_d
 					       "%s: firmware %s is missing, cannot continue.\n", 
 					       dev->name, priv->firmware_id);
 					return 0;
-					
-				} 
+				}
 			} else {
-				int i;
+				int fw_index = 0;
+				int success = 0;
+
+				/* get firmware filename entry based on firmware type ID */
+				while (fw_table[fw_index].fw_type != priv->firmware_type
+						&& fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE)
+					fw_index++;
 				
-				for (i = 0; firmware_modifier[i]; i++) {
-					sprintf(priv->firmware_id, priv->firmware_template, firmware_modifier[i]);
-					if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) 
-						break;
+				/* construct the actual firmware file name */
+				if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) {
+					int i;
+					for (i = 0; firmware_modifier[i]; i++) {
+						snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file,
+							firmware_modifier[i], fw_table[fw_index].fw_file_ext);
+						priv->firmware_id[31] = '\0';
+						if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) {
+							success = 1;
+							break;
+						}
+					}
 				}
-				if (!firmware_modifier[i]) {
+				if (!success) {
 					printk(KERN_ALERT 
 					       "%s: firmware %s is missing, cannot start.\n", 
 					       dev->name, priv->firmware_id);
 					priv->firmware_id[0] = '\0';
 					return 0;	
 				}
-				priv->firmware_template[0] = '\0';	
 			}
 			
 			fw = fw_entry->data;
diff --git a/drivers/net/wireless/atmel.h b/drivers/net/wireless/atmel.h
new file mode 100644
--- /dev/null
+++ b/drivers/net/wireless/atmel.h
@@ -0,0 +1,43 @@
+/*** -*- linux-c -*- **********************************************************
+
+     Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
+
+         Copyright 2005 Dan Williams and 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.
+
+    This software 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 Atmel wireless lan drivers; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+******************************************************************************/
+
+#ifndef _ATMEL_H
+#define _ATMEL_H
+
+typedef enum {
+	ATMEL_FW_TYPE_NONE = 0,
+	ATMEL_FW_TYPE_502,
+	ATMEL_FW_TYPE_502D,
+	ATMEL_FW_TYPE_502E,
+	ATMEL_FW_TYPE_502_3COM,
+	ATMEL_FW_TYPE_504,
+	ATMEL_FW_TYPE_504_2958,
+	ATMEL_FW_TYPE_504A_2958,
+	ATMEL_FW_TYPE_506
+} AtmelFWType;
+
+struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *, 
+				    int (*present_func)(void *), void * );
+void stop_atmel_card( struct net_device *, int );
+int atmel_open( struct net_device * );
+
+#endif
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -55,6 +55,7 @@
 #include <asm/system.h>
 #include <linux/wireless.h>
 
+#include "atmel.h"
 
 /*
    All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
@@ -90,11 +91,6 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x 
    event handler. 
 */
 
-struct net_device *init_atmel_card(int, int, char *, struct device *, 
-				    int (*present_func)(void *), void * );
-void stop_atmel_card( struct net_device *, int );
-int atmel_open( struct net_device * );
-
 static void atmel_config(dev_link_t *link);
 static void atmel_release(dev_link_t *link);
 static int atmel_event(event_t event, int priority,
@@ -307,28 +303,30 @@ static int card_present(void *arg)
 static struct { 
 	int manf, card;
 	char *ver1;
-	char *firmware;
+	AtmelFWType firmware;
 	char *name;
 } card_table[] = {
-	{ 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d%s.bin", "Actiontec 802CAT1" },  
-	{ 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502%s.bin", "NoName-RFMD" }, 
-	{ 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d%s.bin", "NoName-revD" }, 
-	{ 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e%s.bin", "NoName-revE" },
-	{ 0, 0, "ATMEL/AT76C504", "atmel_at76c504%s.bin", "NoName-504" },
-	{ 0, 0, "ATMEL/AT76C504A", "atmel_at76c504a_2958%s.bin", "NoName-504a-2958" },
-	{ 0, 0, "ATMEL/AT76C504_R", "atmel_at76c504_2958%s.bin", "NoName-504-2958" },
-	{ MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRWE62092B" }, 
-	{ MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRSHPW196" }, 
-	{ 0, 0, "SMC/2632W-V2", "atmel_at76c502%s.bin", "SMC 2632W-V2" },
-        { 0, 0, "SMC/2632W", "atmel_at76c502d%s.bin", "SMC 2632W-V3" },
-	{ 0xd601, 0x0007, NULL, "atmel_at76c502%s.bin", "Sitecom WLAN-011" }, 
-	{ 0x01bf, 0x3302, NULL, "atmel_at76c502e%s.bin", "Belkin F5D6020-V2" }, 
-	{ 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502%s.bin", "BT Voyager 1020" },
-        { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502%s.bin", "Siemens Gigaset PC Card II" },
-	{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e%s.bin", "CNet CNWLC-811ARL" },
-	{ 0, 0, "Wireless/PC_CARD", "atmel_at76c502d%s.bin", "Planet WL-3552" },
-	{ 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", "atmel_at76c502%s.bin", "OEM 11Mbps WLAN PCMCIA Card" },
-	{ 0, 0, "11WAVE/11WP611AL-E", "atmel_at76c502e%s.bin", "11WAVE WaveBuddy" } 
+	{ 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" },  
+	{ 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" }, 
+	{ 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" }, 
+	{ 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" },
+	{ 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" },
+	{ 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" },
+	{ 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" },
+	{ MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" }, 
+	{ MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" }, 
+	{ 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" },
+	{ 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" },
+	{ 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" }, 
+	{ 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" }, 
+	{ 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
+	{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
+	{ 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
+	{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
+	{ 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
+	{ 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },
+	{ 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" },
+	{ 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" },
 };
 
 static void atmel_config(dev_link_t *link)
@@ -520,7 +518,7 @@ static void atmel_config(dev_link_t *lin
 	((local_info_t*)link->priv)->eth_dev = 
 		init_atmel_card(link->irq.AssignedIRQ,
 				link->io.BasePort1,
-				card_index == -1 ? NULL :  card_table[card_index].firmware,
+				card_index == -1 ? ATMEL_FW_TYPE_NONE :  card_table[card_index].firmware,
 				&handle_to_dev(handle),
 				card_present, 
 				link);
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
+#include "atmel.h"
 
 MODULE_AUTHOR("Simon Kelley");
 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
@@ -40,9 +41,6 @@ MODULE_DEVICE_TABLE(pci, card_ids);
 
 static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *);
 static void atmel_pci_remove(struct pci_dev *);
-struct net_device *init_atmel_card(int, int, char *, struct device *, 
-				   int (*present_func)(void *), void * );
-void stop_atmel_card( struct net_device *, int );
 
 static struct pci_driver atmel_driver = {
 	.name     = "atmel",
@@ -63,7 +61,7 @@ static int __devinit atmel_pci_probe(str
 	pci_set_master(pdev);
 	
 	dev = init_atmel_card(pdev->irq, pdev->resource[1].start, 
-			      "atmel_at76c506%s.bin",
+			      ATMEL_FW_TYPE_506,
 			      &pdev->dev, NULL, NULL);
 	if (!dev)
 		return -ENODEV;
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/hermes.c
@@ -48,6 +48,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/net.h>
 #include <asm/errno.h>
 
 #include "hermes.h"
@@ -67,8 +68,7 @@ MODULE_LICENSE("Dual MPL/GPL");
  * Debugging helpers
  */
 
-#define IO_TYPE(hw)	((hw)->io_space ? "IO " : "MEM ")
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %s0x%x: " , IO_TYPE(hw), hw->iobase); \
+#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
 			printk(stuff);} while (0)
 
 #undef HERMES_DEBUG
@@ -123,11 +123,9 @@ static int hermes_issue_cmd(hermes_t *hw
  * Function definitions
  */
 
-void hermes_struct_init(hermes_t *hw, ulong address,
-			int io_space, int reg_spacing)
+void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 {
 	hw->iobase = address;
-	hw->io_space = io_space;
 	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
 
@@ -200,9 +198,9 @@ int hermes_init(hermes_t *hw)
 	}
 		
 	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ %s0x%lx: " 
+		printk(KERN_ERR "hermes @ %p: " 
 		       "Timeout waiting for card to reset (reg=0x%04x)!\n",
-		       IO_TYPE(hw), hw->iobase, reg);
+		       hw->iobase, reg);
 		err = -ETIMEDOUT;
 		goto out;
 	}
@@ -235,13 +233,16 @@ int hermes_docmd_wait(hermes_t *hw, u16 
 	err = hermes_issue_cmd(hw, cmd, parm0);
 	if (err) {
 		if (! hermes_present(hw)) {
-			printk(KERN_WARNING "hermes @ %s0x%lx: "
-			       "Card removed while issuing command.\n",
-			       IO_TYPE(hw), hw->iobase);
+			if (net_ratelimit())
+				printk(KERN_WARNING "hermes @ %p: "
+				       "Card removed while issuing command "
+				       "0x%04x.\n", hw->iobase, cmd);
 			err = -ENODEV;
 		} else 
-			printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n",
-			       IO_TYPE(hw), hw->iobase, err);
+			if (net_ratelimit())
+				printk(KERN_ERR "hermes @ %p: "
+				       "Error %d issuing command 0x%04x.\n",
+				       hw->iobase, err, cmd);
 		goto out;
 	}
 
@@ -254,17 +255,16 @@ int hermes_docmd_wait(hermes_t *hw, u16 
 	}
 
 	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
-		       "Card removed while waiting for command completion.\n",
-		       IO_TYPE(hw), hw->iobase);
+		printk(KERN_WARNING "hermes @ %p: Card removed "
+		       "while waiting for command 0x%04x completion.\n",
+		       hw->iobase, cmd);
 		err = -ENODEV;
 		goto out;
 	}
 		
 	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ %s0x%lx: "
-		       "Timeout waiting for command completion.\n",
-		       IO_TYPE(hw), hw->iobase);
+		printk(KERN_ERR "hermes @ %p: Timeout waiting for "
+		       "command 0x%04x completion.\n", hw->iobase, cmd);
 		err = -ETIMEDOUT;
 		goto out;
 	}
@@ -309,16 +309,16 @@ int hermes_allocate(hermes_t *hw, u16 si
 	}
 	
 	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		printk(KERN_WARNING "hermes @ %p: "
 		       "Card removed waiting for frame allocation.\n",
-		       IO_TYPE(hw), hw->iobase);
+		       hw->iobase);
 		return -ENODEV;
 	}
 		
 	if (! (reg & HERMES_EV_ALLOC)) {
-		printk(KERN_ERR "hermes @ %s0x%lx: "
+		printk(KERN_ERR "hermes @ %p: "
 		       "Timeout waiting for frame allocation\n",
-		       IO_TYPE(hw), hw->iobase);
+		       hw->iobase);
 		return -ETIMEDOUT;
 	}
 
@@ -383,12 +383,17 @@ static int hermes_bap_seek(hermes_t *hw,
 		reg = hermes_read_reg(hw, oreg);
 	}
 
-	if (reg & HERMES_OFFSET_BUSY) {
-		return -ETIMEDOUT;
-	}
+	if (reg != offset) {
+		printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
+		       "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
+		       (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
+		       reg, id, offset);
+
+		if (reg & HERMES_OFFSET_BUSY) {
+			return -ETIMEDOUT;
+		}
 
-	if (reg & HERMES_OFFSET_ERR) {
-		return -EIO;
+		return -EIO;		/* error or wrong offset */
 	}
 
 	return 0;
@@ -476,7 +481,7 @@ int hermes_read_ltv(hermes_t *hw, int ba
 	rlength = hermes_read_reg(hw, dreg);
 
 	if (! rlength)
-		return -ENOENT;
+		return -ENODATA;
 
 	rtype = hermes_read_reg(hw, dreg);
 
@@ -484,14 +489,13 @@ int hermes_read_ltv(hermes_t *hw, int ba
 		*length = rlength;
 
 	if (rtype != rid)
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
-		       "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)\n",
-		       IO_TYPE(hw), hw->iobase, rid, rtype);
+		printk(KERN_WARNING "hermes @ %p: %s(): "
+		       "rid (0x%04x) does not match type (0x%04x)\n",
+		       hw->iobase, __FUNCTION__, rid, rtype);
 	if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		printk(KERN_WARNING "hermes @ %p: "
 		       "Truncating LTV record from %d to %d bytes. "
-		       "(rid=0x%04x, len=0x%04x)\n",
-		       IO_TYPE(hw), hw->iobase,
+		       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
 		       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
 
 	nwords = min((unsigned)rlength - 1, bufsize / 2);
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
--- a/drivers/net/wireless/hermes.h
+++ b/drivers/net/wireless/hermes.h
@@ -340,14 +340,11 @@ struct hermes_debug_entry {
 #ifdef __KERNEL__
 
 /* Timeouts */
-#define HERMES_BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
+#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
 
 /* Basic control structure */
 typedef struct hermes {
-	unsigned long iobase;
-	int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
-#define HERMES_IO	1
-#define HERMES_MEM	0
+	void __iomem *iobase;
 	int reg_spacing;
 #define HERMES_16BIT_REGSPACING	0
 #define HERMES_32BIT_REGSPACING	1
@@ -362,21 +359,15 @@ typedef struct hermes {
 } hermes_t;
 
 /* Register access convenience macros */
-#define hermes_read_reg(hw, off) ((hw)->io_space ? \
-	inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
-	readw((hw)->iobase + ( (off) << (hw)->reg_spacing )))
-#define hermes_write_reg(hw, off, val) do { \
-	if ((hw)->io_space) \
-		outw_p((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \
-	else \
-		writew((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \
-	} while (0)
+#define hermes_read_reg(hw, off) \
+	(ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#define hermes_write_reg(hw, off, val) \
+	(iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
 #define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
 #define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val))
 
 /* Function prototypes */
-void hermes_struct_init(hermes_t *hw, ulong address, int io_space,
-			int reg_spacing);
+void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
 int hermes_init(hermes_t *hw);
 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
 		      struct hermes_response *resp);
@@ -430,41 +421,13 @@ static inline int hermes_inquire(hermes_
 static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;
-
-	if (hw->io_space) {
-		insw(hw->iobase + off, buf, count);
-	} else {
-		unsigned i;
-		u16 *p;
-
-		/* This needs to *not* byteswap (like insw()) but
-		 * readw() does byteswap hence the conversion.  I hope
-		 * gcc is smart enough to fold away the two swaps on
-		 * big-endian platforms. */
-		for (i = 0, p = buf; i < count; i++) {
-			*p++ = cpu_to_le16(readw(hw->iobase + off));
-		}
-	}
+	ioread16_rep(hw->iobase + off, buf, count);
 }
 
 static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;
-
-	if (hw->io_space) {
-		outsw(hw->iobase + off, buf, count);
-	} else {
-		unsigned i;
-		const u16 *p;
-
-		/* This needs to *not* byteswap (like outsw()) but
-		 * writew() does byteswap hence the conversion.  I
-		 * hope gcc is smart enough to fold away the two swaps
-		 * on big-endian platforms. */
-		for (i = 0, p = buf; i < count; i++) {
-			writew(le16_to_cpu(*p++), hw->iobase + off);
-		}
-	}
+	iowrite16_rep(hw->iobase + off, buf, count);
 }
 
 static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
@@ -473,13 +436,8 @@ static inline void hermes_clear_words(st
 
 	off = off << hw->reg_spacing;
 
-	if (hw->io_space) {
-		for (i = 0; i < count; i++)
-			outw(0, hw->iobase + off);
-	} else {
-		for (i = 0; i < count; i++)
-			writew(0, hw->iobase + off);
-	}
+	for (i = 0; i < count; i++)
+		iowrite16(0, hw->iobase + off);
 }
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -393,6 +393,29 @@
  *	  in the rx_dropped statistics.
  *	o Provided a module parameter to suppress linkstatus messages.
  *
+ * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
+ *	o Replaced priv->connected logic with netif_carrier_on/off()
+ *	  calls.
+ *	o Remove has_ibss_any and never set the CREATEIBSS RID when
+ *	  the ESSID is empty.  Too many firmwares break if we do.
+ *	o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
+ *	  __devinitdata from PCI ID tables, use free_netdev().
+ *	o Enabled shared-key authentication for Agere firmware (from
+ *	  Robert J. Moore <Robert.J.Moore AT allanbank.com>
+ *	o Move netif_wake_queue() (back) to the Tx completion from the
+ *	  ALLOC event.  This seems to prevent/mitigate the rolling
+ *	  error -110 problems at least on some Intersil firmwares.
+ *	  Theoretically reduces performance, but I can't measure it.
+ *	  Patch from Andrew Tridgell <tridge AT samba.org>
+ *
+ * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
+ *	o Correctly turn off shared-key authentication when requested
+ *	  (bugfix from Robert J. Moore).
+ *	o Correct airport sleep interfaces for current 2.6 kernels.
+ *	o Add code for key change without disabling/enabling the MAC
+ *	  port.  This is supposed to allow 802.1x to work sanely, but
+ *	  doesn't seem to yet.
+ *
  * TODO
  *	o New wireless extensions API (patch from Moustafa
  *	  Youssef, updated by Jim Carter and Pavel Roskin).
@@ -461,12 +484,14 @@ MODULE_LICENSE("Dual MPL/GPL");
 /* Level of debugging. Used in the macros in orinoco.h */
 #ifdef ORINOCO_DEBUG
 int orinoco_debug = ORINOCO_DEBUG;
-module_param(orinoco_debug, int, 0);
+module_param(orinoco_debug, int, 0644);
+MODULE_PARM_DESC(orinoco_debug, "Debug level");
 EXPORT_SYMBOL(orinoco_debug);
 #endif
 
 static int suppress_linkstatus; /* = 0 */
-module_param(suppress_linkstatus, bool, 0);
+module_param(suppress_linkstatus, bool, 0644);
+MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
 
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
@@ -784,7 +809,7 @@ static int orinoco_xmit(struct sk_buff *
 		return 1;
 	}
 
-	if (! priv->connected) {
+	if (! netif_carrier_ok(dev)) {
 		/* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -805,8 +830,9 @@ static int orinoco_xmit(struct sk_buff *
  	desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
 	err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
 	if (err) {
-		printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n",
-		       dev->name, err);
+		if (net_ratelimit())
+			printk(KERN_ERR "%s: Error %d writing Tx descriptor "
+			       "to BAP\n", dev->name, err);
 		stats->tx_errors++;
 		goto fail;
 	}
@@ -836,8 +862,9 @@ static int orinoco_xmit(struct sk_buff *
 		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
 					 txfid, HERMES_802_3_OFFSET);
 		if (err) {
-			printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
-			       dev->name, err);
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing packet "
+				       "header to BAP\n", dev->name, err);
 			stats->tx_errors++;
 			goto fail;
 		}
@@ -897,8 +924,6 @@ static void __orinoco_ev_alloc(struct ne
 			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
 			       dev->name, fid);
 		return;
-	} else {
-		netif_wake_queue(dev);
 	}
 
 	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
@@ -911,6 +936,8 @@ static void __orinoco_ev_tx(struct net_d
 
 	stats->tx_packets++;
 
+	netif_wake_queue(dev);
+
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
@@ -937,6 +964,7 @@ static void __orinoco_ev_txexc(struct ne
 	
 	stats->tx_errors++;
 
+	netif_wake_queue(dev);
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
@@ -962,15 +990,17 @@ static void orinoco_tx_timeout(struct ne
 
 /* Does the frame have a SNAP header indicating it should be
  * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(struct header_struct *hdr)
+static inline int is_ethersnap(void *_hdr)
 {
+	u8 *hdr = _hdr;
+
 	/* We de-encapsulate all packets which, a) have SNAP headers
 	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
 	 * and where b) the OUI of the SNAP header is 00:00:00 or
 	 * 00:00:f8 - we need both because different APs appear to use
 	 * different OUIs for some reason */
-	return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
-		&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
+	return (memcmp(hdr, &encaps_hdr, 5) == 0)
+		&& ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) );
 }
 
 static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
@@ -1269,6 +1299,7 @@ static void __orinoco_ev_info(struct net
 	case HERMES_INQ_LINKSTATUS: {
 		struct hermes_linkstatus linkstatus;
 		u16 newstatus;
+		int connected;
 
 		if (len != sizeof(linkstatus)) {
 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
@@ -1280,15 +1311,14 @@ static void __orinoco_ev_info(struct net
 				  len / 2);
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
-		if ( (newstatus == HERMES_LINKSTATUS_CONNECTED)
-		     || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
-		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) )
-			priv->connected = 1;
-		else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED)
-			  || (newstatus == HERMES_LINKSTATUS_DISCONNECTED)
-			  || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE)
-			  || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) )
-			priv->connected = 0;
+		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
+			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
+
+		if (connected)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
 
 		if (newstatus != priv->last_linkstatus)
 			print_linkstatus(dev, newstatus);
@@ -1297,8 +1327,8 @@ static void __orinoco_ev_info(struct net
 	}
 	break;
 	default:
-		printk(KERN_DEBUG "%s: Unknown information frame received "
-		       "(type %04x).\n", dev->name, type);
+		printk(KERN_DEBUG "%s: Unknown information frame received: "
+		       "type 0x%04x, length %d\n", dev->name, type, len);
 		/* We don't actually do anything about it */
 		break;
 	}
@@ -1307,7 +1337,7 @@ static void __orinoco_ev_info(struct net
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
 	if (net_ratelimit())
-		printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
+		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
 }
 
 /********************************************************************/
@@ -1366,8 +1396,8 @@ int __orinoco_down(struct net_device *de
 	}
 	
 	/* firmware will have to reassociate */
+	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
-	priv->connected = 0;
 
 	return 0;
 }
@@ -1430,55 +1460,46 @@ static int __orinoco_hw_set_bitrate(stru
 	return err;
 }
 
-static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
+/* Change the WEP keys and/or the current keys.  Can be called
+ * either from __orinoco_hw_setup_wep() or directly from
+ * orinoco_ioctl_setiwencode().  In the later case the association
+ * with the AP is not broken (if the firmware can handle it),
+ * which is needed for 802.1x implementations. */
+static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	int	master_wep_flag;
-	int	auth_flag;
 
 	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
-		if (priv->wep_on) {
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFTXKEY_AGERE,
-						   priv->tx_key);
-			if (err)
-				return err;
-			
-			err = HERMES_WRITE_RECORD(hw, USER_BAP,
-						  HERMES_RID_CNFWEPKEYS_AGERE,
-						  &priv->keys);
-			if (err)
-				return err;
-		}
+	case FIRMWARE_TYPE_AGERE:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFWEPKEYS_AGERE,
+					  &priv->keys);
+		if (err)
+			return err;
 		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFWEPENABLED_AGERE,
-					   priv->wep_on);
+					   HERMES_RID_CNFTXKEY_AGERE,
+					   priv->tx_key);
 		if (err)
 			return err;
 		break;
-
-	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-		master_wep_flag = 0;		/* Off */
-		if (priv->wep_on) {
+	case FIRMWARE_TYPE_INTERSIL:
+	case FIRMWARE_TYPE_SYMBOL:
+		{
 			int keylen;
 			int i;
 
-			/* Fudge around firmware weirdness */
+			/* Force uniform key length to work around firmware bugs */
 			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
 			
+			if (keylen > LARGE_KEY_SIZE) {
+				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
+				       priv->ndev->name, priv->tx_key, keylen);
+				return -E2BIG;
+			}
+
 			/* Write all 4 keys */
 			for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
-/*  				int keylen = le16_to_cpu(priv->keys[i].len); */
-				
-				if (keylen > LARGE_KEY_SIZE) {
-					printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
-					       priv->ndev->name, i, keylen);
-					return -E2BIG;
-				}
-
 				err = hermes_write_ltv(hw, USER_BAP,
 						       HERMES_RID_CNFDEFAULTKEY0 + i,
 						       HERMES_BYTES_TO_RECLEN(keylen),
@@ -1493,27 +1514,63 @@ static int __orinoco_hw_setup_wep(struct
 						   priv->tx_key);
 			if (err)
 				return err;
-			
-			if (priv->wep_restrict) {
-				auth_flag = 2;
-				master_wep_flag = 3;
-			} else {
-				/* Authentication is where Intersil and Symbol
-				 * firmware differ... */
-				auth_flag = 1;
-				if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-					master_wep_flag = 3; /* Symbol */ 
-				else 
-					master_wep_flag = 1; /* Intersil */
-			}
+		}
+		break;
+	}
 
+	return 0;
+}
+
+static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int master_wep_flag;
+	int auth_flag;
+
+	if (priv->wep_on)
+		__orinoco_hw_setup_wepkeys(priv);
+
+	if (priv->wep_restrict)
+		auth_flag = HERMES_AUTH_SHARED_KEY;
+	else
+		auth_flag = HERMES_AUTH_OPEN;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
+		if (priv->wep_on) {
+			/* Enable the shared-key authentication. */
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFAUTHENTICATION_AGERE,
+						   auth_flag);
+		}
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPENABLED_AGERE,
+					   priv->wep_on);
+		if (err)
+			return err;
+		break;
+
+	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+		if (priv->wep_on) {
+			if (priv->wep_restrict ||
+			    (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
+						  HERMES_WEP_EXCL_UNENCRYPTED;
+			else
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
 
 			err = hermes_write_wordrec(hw, USER_BAP,
 						   HERMES_RID_CNFAUTHENTICATION,
 						   auth_flag);
 			if (err)
 				return err;
-		}
+		} else
+			master_wep_flag = 0;
+
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
 
 		/* Master WEP setting : on/off */
 		err = hermes_write_wordrec(hw, USER_BAP,
@@ -1523,13 +1580,6 @@ static int __orinoco_hw_setup_wep(struct
 			return err;	
 
 		break;
-
-	default:
-		if (priv->wep_on) {
-			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
-			       priv->ndev->name);
-			return -EINVAL;
-		}
 	}
 
 	return 0;
@@ -1574,21 +1624,26 @@ static int __orinoco_program_rids(struct
 	}
 
 	if (priv->has_ibss) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFCREATEIBSS,
-					   priv->createibss);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err);
-			return err;
-		}
+		u16 createibss;
 
-		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)
-		   && (!priv->has_ibss_any)) {
+		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
 			printk(KERN_WARNING "%s: This firmware requires an "
 			       "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
 			/* With wvlan_cs, in this case, we would crash.
 			 * hopefully, this driver will behave better...
 			 * Jean II */
+			createibss = 0;
+		} else {
+			createibss = priv->createibss;
+		}
+		
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFCREATEIBSS,
+					   createibss);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+			       dev->name, err);
+			return err;
 		}
 	}
 
@@ -1785,7 +1840,8 @@ __orinoco_set_multicast_list(struct net_
 		}
 		
 		if (p)
-			printk(KERN_WARNING "Multicast list is longer than mc_count\n");
+			printk(KERN_WARNING "%s: Multicast list is "
+			       "longer than mc_count\n", dev->name);
 
 		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
 				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
@@ -1878,7 +1934,7 @@ static void orinoco_reset(struct net_dev
 
 	priv->hw_unavailable++;
 	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
-	priv->connected = 0;
+	netif_carrier_off(dev);
 
 	orinoco_unlock(priv, &flags);
 
@@ -2014,51 +2070,81 @@ irqreturn_t orinoco_interrupt(int irq, v
 /* Initialization                                                   */
 /********************************************************************/
 
-struct sta_id {
+struct comp_id {
 	u16 id, variant, major, minor;
 } __attribute__ ((packed));
 
-static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
 {
-	/* FIXME: this is fundamentally broken */
-	unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
-	
-	if (sta_id->variant == 1)
+	if (nic_id->id < 0x8000)
 		return FIRMWARE_TYPE_AGERE;
-	else if ((sta_id->variant == 2) &&
-		   ((firmver == 0x10001) || (firmver == 0x20001)))
+	else if (nic_id->id == 0x8000 && nic_id->major == 0)
 		return FIRMWARE_TYPE_SYMBOL;
 	else
 		return FIRMWARE_TYPE_INTERSIL;
 }
 
-static void determine_firmware(struct net_device *dev)
+/* Set priv->firmware type, determine firmware properties */
+static int determine_firmware(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err;
-	struct sta_id sta_id;
+	struct comp_id nic_id, sta_id;
 	unsigned int firmver;
 	char tmp[SYMBOL_MAX_VER_LEN+1];
 
+	/* Get the hardware version */
+	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
+		       dev->name, err);
+		return err;
+	}
+
+	le16_to_cpus(&nic_id.id);
+	le16_to_cpus(&nic_id.variant);
+	le16_to_cpus(&nic_id.major);
+	le16_to_cpus(&nic_id.minor);
+	printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
+	       dev->name, nic_id.id, nic_id.variant,
+	       nic_id.major, nic_id.minor);
+
+	priv->firmware_type = determine_firmware_type(&nic_id);
+
 	/* Get the firmware version */
 	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
 	if (err) {
-		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
+		printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
 		       dev->name, err);
-		memset(&sta_id, 0, sizeof(sta_id));
+		return err;
 	}
 
 	le16_to_cpus(&sta_id.id);
 	le16_to_cpus(&sta_id.variant);
 	le16_to_cpus(&sta_id.major);
 	le16_to_cpus(&sta_id.minor);
-	printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
+	printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
 	       dev->name, sta_id.id, sta_id.variant,
 	       sta_id.major, sta_id.minor);
 
-	if (! priv->firmware_type)
-		priv->firmware_type = determine_firmware_type(dev, &sta_id);
+	switch (sta_id.id) {
+	case 0x15:
+		printk(KERN_ERR "%s: Primary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x14b:
+		printk(KERN_ERR "%s: Tertiary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x1f:	/* Intersil, Agere, Symbol Spectrum24 */
+	case 0x21:	/* Symbol Spectrum24 Trilogy */
+		break;
+	default:
+		printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
+		       dev->name);
+		break;
+	}
 
 	/* Default capabilities */
 	priv->has_sensitivity = 1;
@@ -2066,7 +2152,6 @@ static void determine_firmware(struct ne
 	priv->has_preamble = 0;
 	priv->has_port3 = 1;
 	priv->has_ibss = 1;
-	priv->has_ibss_any = 0;
 	priv->has_wep = 0;
 	priv->has_big_wep = 0;
 
@@ -2075,14 +2160,12 @@ static void determine_firmware(struct ne
 	case FIRMWARE_TYPE_AGERE:
 		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
 		   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-		printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware "
-		       "version %d.%02d\n", dev->name,
-		       sta_id.major, sta_id.minor);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
 
 		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
 
 		priv->has_ibss = (firmver >= 0x60006);
-		priv->has_ibss_any = (firmver >= 0x60010);
 		priv->has_wep = (firmver >= 0x40020);
 		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
 					  Gold cards from the others? */
@@ -2121,14 +2204,15 @@ static void determine_firmware(struct ne
 			tmp[SYMBOL_MAX_VER_LEN] = '\0';
 		}
 
-		printk(KERN_DEBUG "%s: Looks like a Symbol firmware "
-		       "version [%s] (parsing to %X)\n", dev->name,
-		       tmp, firmver);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Symbol %s", tmp);
 
 		priv->has_ibss = (firmver >= 0x20000);
 		priv->has_wep = (firmver >= 0x15012);
 		priv->has_big_wep = (firmver >= 0x20000);
-		priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000);
+		priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
+			       (firmver >= 0x29000 && firmver < 0x30000) ||
+			       firmver >= 0x31000;
 		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
 		/* Tested with Intel firmware : 0x20015 => Jean II */
@@ -2140,9 +2224,9 @@ static void determine_firmware(struct ne
 		 * different and less well tested */
 		/* D-Link MAC : 00:40:05:* */
 		/* Addtron MAC : 00:90:D1:* */
-		printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
-		       "version %d.%d.%d\n", dev->name,
-		       sta_id.major, sta_id.minor, sta_id.variant);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+			 sta_id.variant);
 
 		firmver = ((unsigned long)sta_id.major << 16) |
 			((unsigned long)sta_id.minor << 8) | sta_id.variant;
@@ -2160,9 +2244,11 @@ static void determine_firmware(struct ne
 			priv->ibss_port = 1;
 		}
 		break;
-	default:
-		break;
 	}
+	printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
+	       priv->fw_name);
+
+	return 0;
 }
 
 static int orinoco_init(struct net_device *dev)
@@ -2188,7 +2274,12 @@ static int orinoco_init(struct net_devic
 		goto out;
 	}
 
-	determine_firmware(dev);
+	err = determine_firmware(dev);
+	if (err != 0) {
+		printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+		       dev->name);
+		goto out;
+	}
 
 	if (priv->has_port3)
 		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
@@ -2388,13 +2479,18 @@ struct net_device *alloc_orinocodev(int 
 				   * hardware */
 	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
 
+	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
-	priv->connected = 0;
 
 	return dev;
 
 }
 
+void free_orinocodev(struct net_device *dev)
+{
+	free_netdev(dev);
+}
+
 /********************************************************************/
 /* Wireless extensions                                              */
 /********************************************************************/
@@ -2553,9 +2649,8 @@ static int orinoco_ioctl_getiwrange(stru
 
 	TRACE_ENTER(dev->name);
 
-	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
-	if (err)
-		return err;
+	if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
+		return -EFAULT;
 
 	rrq->length = sizeof(range);
 
@@ -2686,11 +2781,17 @@ static int orinoco_ioctl_setiwencode(str
 	int err = 0;
 	char keybuf[ORINOCO_MAX_KEY_SIZE];
 	unsigned long flags;
-	
+
+	if (! priv->has_wep)
+		return -EOPNOTSUPP;
+
 	if (erq->pointer) {
-		/* We actually have a key to set */
-		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) )
-			return -EINVAL;
+		/* We actually have a key to set - check its length */
+		if (erq->length > LARGE_KEY_SIZE)
+			return -E2BIG;
+
+		if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
+			return -E2BIG;
 		
 		if (copy_from_user(keybuf, erq->pointer, erq->length))
 			return -EFAULT;
@@ -2698,19 +2799,8 @@ static int orinoco_ioctl_setiwencode(str
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
-	
+
 	if (erq->pointer) {
-		if (erq->length > ORINOCO_MAX_KEY_SIZE) {
-			err = -E2BIG;
-			goto out;
-		}
-		
-		if ( (erq->length > LARGE_KEY_SIZE)
-		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
-			err = -EINVAL;
-			goto out;
-		}
-		
 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 			index = priv->tx_key;
 
@@ -2721,7 +2811,7 @@ static int orinoco_ioctl_setiwencode(str
 			xlen = SMALL_KEY_SIZE;
 		} else
 			xlen = 0;
-		
+
 		/* Switch on WEP if off */
 		if ((!enable) && (xlen > 0)) {
 			setindex = index;
@@ -2745,10 +2835,9 @@ static int orinoco_ioctl_setiwencode(str
 			setindex = index;
 		}
 	}
-	
+
 	if (erq->flags & IW_ENCODE_DISABLED)
 		enable = 0;
-	/* Only for Prism2 & Symbol cards (so far) - Jean II */
 	if (erq->flags & IW_ENCODE_OPEN)
 		restricted = 0;
 	if (erq->flags & IW_ENCODE_RESTRICTED)
@@ -2761,6 +2850,15 @@ static int orinoco_ioctl_setiwencode(str
 		memcpy(priv->keys[index].data, keybuf, erq->length);
 	}
 	priv->tx_key = setindex;
+
+	/* Try fast key change if connected and only keys are changed */
+	if (priv->wep_on && enable && (priv->wep_restrict == restricted) &&
+	    netif_carrier_ok(dev)) {
+		err = __orinoco_hw_setup_wepkeys(priv);
+		/* No need to commit if successful */
+		goto out;
+	}
+
 	priv->wep_on = enable;
 	priv->wep_restrict = restricted;
 
@@ -2778,6 +2876,9 @@ static int orinoco_ioctl_getiwencode(str
 	char keybuf[ORINOCO_MAX_KEY_SIZE];
 	unsigned long flags;
 
+	if (! priv->has_wep)
+		return -EOPNOTSUPP;
+
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
@@ -2788,23 +2889,18 @@ static int orinoco_ioctl_getiwencode(str
 	if (! priv->wep_on)
 		erq->flags |= IW_ENCODE_DISABLED;
 	erq->flags |= index + 1;
-	
-	/* Only for symbol cards - Jean II */
-	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-		if(priv->wep_restrict)
-			erq->flags |= IW_ENCODE_RESTRICTED;
-		else
-			erq->flags |= IW_ENCODE_OPEN;
-	}
+
+	if (priv->wep_restrict)
+		erq->flags |= IW_ENCODE_RESTRICTED;
+	else
+		erq->flags |= IW_ENCODE_OPEN;
 
 	xlen = le16_to_cpu(priv->keys[index].len);
 
 	erq->length = xlen;
 
-	if (erq->pointer) {
-		memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
-	}
-	
+	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
+
 	orinoco_unlock(priv, &flags);
 
 	if (erq->pointer) {
@@ -3045,8 +3141,9 @@ static int orinoco_ioctl_setfrag(struct 
 			priv->mwo_robust = 0;
 		else {
 			if (frq->fixed)
-				printk(KERN_WARNING "%s: Fixed fragmentation not \
-supported on this firmware. Using MWO robust instead.\n", dev->name);
+				printk(KERN_WARNING "%s: Fixed fragmentation is "
+				       "not supported on this firmware. "
+				       "Using MWO robust instead.\n", dev->name);
 			priv->mwo_robust = 1;
 		}
 	} else {
@@ -3518,7 +3615,7 @@ static int orinoco_ioctl_getspy(struct n
 		}
 		/* Copy stats */
 		/* In theory, we should disable irqs while copying the stats
-		 * because the rx path migh update it in the middle...
+		 * because the rx path might update it in the middle...
 		 * Bah, who care ? - Jean II */
 		memcpy(&spy_stat, priv->spy_stat,
 		       sizeof(struct iw_quality) * IW_MAX_SPY);
@@ -3609,22 +3706,12 @@ orinoco_ioctl(struct net_device *dev, st
 		break;
 
 	case SIOCSIWENCODE:
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
-
 		err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWENCODE:
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
-
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
@@ -4127,6 +4214,7 @@ static void show_rx_frame(struct orinoco
 /********************************************************************/
 
 EXPORT_SYMBOL(alloc_orinocodev);
+EXPORT_SYMBOL(free_orinocodev);
 
 EXPORT_SYMBOL(__orinoco_up);
 EXPORT_SYMBOL(__orinoco_down);
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,7 +7,7 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
-#define DRIVER_VERSION "0.13e"
+#define DRIVER_VERSION "0.14alpha2"
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
@@ -30,6 +30,12 @@ struct orinoco_key {
 	char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+typedef enum {
+	FIRMWARE_TYPE_AGERE,
+	FIRMWARE_TYPE_INTERSIL,
+	FIRMWARE_TYPE_SYMBOL
+} fwtype_t;
+
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
 	int (*hard_reset)(struct orinoco_private *);
@@ -42,7 +48,6 @@ struct orinoco_private {
 	/* driver state */
 	int open;
 	u16 last_linkstatus;
-	int connected;
 
 	/* Net device stuff */
 	struct net_device *ndev;
@@ -54,19 +59,22 @@ struct orinoco_private {
 	u16 txfid;
 
 	/* Capabilities of the hardware/firmware */
-	int firmware_type;
-#define FIRMWARE_TYPE_AGERE 1
-#define FIRMWARE_TYPE_INTERSIL 2
-#define FIRMWARE_TYPE_SYMBOL 3
-	int has_ibss, has_port3, has_ibss_any, ibss_port;
-	int has_wep, has_big_wep;
-	int has_mwo;
-	int has_pm;
-	int has_preamble;
-	int has_sensitivity;
+	fwtype_t firmware_type;
+	char fw_name[32];
+	int ibss_port;
 	int nicbuf_size;
 	u16 channel_mask;
-	int broken_disableport;
+
+	/* Boolean capabilities */
+	unsigned int has_ibss:1;
+	unsigned int has_port3:1;
+	unsigned int has_wep:1;
+	unsigned int has_big_wep:1;
+	unsigned int has_mwo:1;
+	unsigned int has_pm:1;
+	unsigned int has_preamble:1;
+	unsigned int has_sensitivity:1;
+	unsigned int broken_disableport:1;
 
 	/* Configuration paramaters */
 	u32 iw_mode;
@@ -108,6 +116,7 @@ extern int orinoco_debug;
 
 extern struct net_device *alloc_orinocodev(int sizeof_card,
 					   int (*hard_reset)(struct orinoco_private *));
+extern void free_orinocodev(struct net_device *dev);
 extern int __orinoco_up(struct net_device *dev);
 extern int __orinoco_down(struct net_device *dev);
 extern int orinoco_stop(struct net_device *dev);
@@ -127,7 +136,7 @@ extern inline int orinoco_lock(struct or
 {
 	spin_lock_irqsave(&priv->lock, *flags);
 	if (priv->hw_unavailable) {
-		printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable (dev=%p)\n",
+		DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
 		       priv->ndev);
 		spin_unlock_irqrestore(&priv->lock, *flags);
 		return -EBUSY;
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -57,8 +57,8 @@ MODULE_LICENSE("Dual MPL/GPL");
 /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  * don't have any CIS entry for it. This workaround it... */
 static int ignore_cis_vcc; /* = 0 */
-
 module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
 
 /********************************************************************/
 /* Magic constants						    */
@@ -128,6 +128,7 @@ orinoco_cs_hard_reset(struct orinoco_pri
 	if (err)
 		return err;
 
+	msleep(100);
 	clear_bit(0, &card->hard_reset_in_progress);
 
 	return 0;
@@ -166,9 +167,10 @@ orinoco_cs_attach(void)
 	link->priv = dev;
 
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
 	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-	link->irq.Handler = NULL;
+	link->irq.Handler = orinoco_interrupt;
+	link->irq.Instance = dev; 
 
 	/* General socket configuration defaults can go here.  In this
 	 * client, we assume very little, and rely on the CIS for
@@ -235,7 +237,7 @@ static void orinoco_cs_detach(dev_link_t
 		      dev);
 		unregister_netdev(dev);
 	}
-	free_netdev(dev);
+	free_orinocodev(dev);
 }				/* orinoco_cs_detach */
 
 /*
@@ -262,6 +264,7 @@ orinoco_cs_config(dev_link_t *link)
 	cisinfo_t info;
 	tuple_t tuple;
 	cisparse_t parse;
+	void __iomem *mem;
 
 	CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
 
@@ -308,8 +311,8 @@ orinoco_cs_config(dev_link_t *link)
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 		cistpl_cftable_entry_t dflt = { .index = 0 };
 
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
+		    || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
 			goto next_entry;
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
@@ -348,8 +351,7 @@ orinoco_cs_config(dev_link_t *link)
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
 		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
+		link->conf.Attributes |= CONF_ENABLE_IRQ;
 
 		/* IO window settings */
 		link->io.NumPorts1 = link->io.NumPorts2 = 0;
@@ -390,7 +392,7 @@ orinoco_cs_config(dev_link_t *link)
 		last_ret = pcmcia_get_next_tuple(handle, &tuple);
 		if (last_ret  == CS_NO_MORE_ITEMS) {
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
-			       "CIS configuration, maybe you need the "
+			       "CIS configuration.  Maybe you need the "
 			       "ignore_cis_vcc=1 parameter.\n");
 			goto cs_failed;
 		}
@@ -401,20 +403,16 @@ orinoco_cs_config(dev_link_t *link)
 	 * a handler to the interrupt, unless the 'Handler' member of
 	 * the irq structure is initialized.
 	 */
-	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-		link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-  		link->irq.Handler = orinoco_interrupt; 
-  		link->irq.Instance = dev; 
-		
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	}
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
 
 	/* We initialize the hermes structure before completing PCMCIA
 	 * configuration just in case the interrupt handler gets
 	 * called. */
-	hermes_struct_init(hw, link->io.BasePort1,
-				HERMES_IO, HERMES_16BIT_REGSPACING);
+	mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+	if (!mem)
+		goto cs_failed;
+
+	hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
 
 	/*
 	 * This actually configures the PCMCIA socket -- setting up
@@ -430,8 +428,6 @@ orinoco_cs_config(dev_link_t *link)
 	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
-	/* register_netdev will give us an ethX name */
-	dev->name[0] = '\0';
 	SET_NETDEV_DEV(dev, &handle_to_dev(handle));
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
@@ -454,8 +450,7 @@ orinoco_cs_config(dev_link_t *link)
 	if (link->conf.Vpp1)
 		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
 		       link->conf.Vpp1 % 10);
-	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		printk(", irq %d", link->irq.AssignedIRQ);
+	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);
@@ -498,6 +493,8 @@ orinoco_cs_release(dev_link_t *link)
 	if (link->irq.AssignedIRQ)
 		pcmcia_release_irq(link->handle, &link->irq);
 	link->state &= ~DEV_CONFIG;
+	if (priv->hw.iobase)
+		ioport_unmap(priv->hw.iobase);
 }				/* orinoco_cs_release */
 
 /*
@@ -519,12 +516,12 @@ orinoco_cs_event(event_t event, int prio
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			orinoco_lock(priv, &flags);
+			unsigned long flags;
 
+			spin_lock_irqsave(&priv->lock, flags);
 			netif_device_detach(dev);
 			priv->hw_unavailable++;
-
-			orinoco_unlock(priv, &flags);
+			spin_unlock_irqrestore(&priv->lock, flags);
 		}
 		break;
 
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -129,6 +129,11 @@
 #define HERMES_PCI_COR_OFFT	(500)		/* ms */
 #define HERMES_PCI_COR_BUSYT	(500)		/* ms */
 
+/* Orinoco PCI specific data */
+struct orinoco_pci_card {
+	void __iomem *pci_ioaddr;
+};
+
 /*
  * Do a soft reset of the PCI card using the Configuration Option Register
  * We need this to get going...
@@ -151,25 +156,11 @@ orinoco_pci_cor_reset(struct orinoco_pri
 
 	/* Assert the reset until the card notice */
 	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
-	printk(KERN_NOTICE "Reset done");
-	timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000);
-	while(time_before(jiffies, timeout)) {
-		printk(".");
-		mdelay(1);
-	}
-	printk(";\n");
-	//mdelay(HERMES_PCI_COR_ONT);
+	mdelay(HERMES_PCI_COR_ONT);
 
 	/* Give time for the card to recover from this hard effort */
 	hermes_write_regn(hw, PCI_COR, 0x0000);
-	printk(KERN_NOTICE "Clear Reset");
-	timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000);
-	while(time_before(jiffies, timeout)) {
-		printk(".");
-		mdelay(1);
-	}
-	printk(";\n");
-	//mdelay(HERMES_PCI_COR_OFFT);
+	mdelay(HERMES_PCI_COR_OFFT);
 
 	/* The card is ready when it's no longer busy */
 	timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
@@ -178,12 +169,12 @@ orinoco_pci_cor_reset(struct orinoco_pri
 		mdelay(1);
 		reg = hermes_read_regn(hw, CMD);
 	}
-	/* Did we timeout ? */
-	if(time_after_eq(jiffies, timeout)) {
+
+	/* Still busy? */
+	if (reg & HERMES_CMD_BUSY) {
 		printk(KERN_ERR PFX "Busy timeout\n");
 		return -ETIMEDOUT;
 	}
-	printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies);
 
 	return 0;
 }
@@ -196,84 +187,93 @@ static int orinoco_pci_init_one(struct p
 {
 	int err = 0;
 	unsigned long pci_iorange;
-	u16 *pci_ioaddr = NULL;
+	u16 __iomem *pci_ioaddr = NULL;
 	unsigned long pci_iolen;
 	struct orinoco_private *priv = NULL;
+	struct orinoco_pci_card *card;
 	struct net_device *dev = NULL;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return err;
+	}
+
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
+	}
 
 	/* Resource 0 is mapped to the hermes registers */
 	pci_iorange = pci_resource_start(pdev, 0);
 	pci_iolen = pci_resource_len(pdev, 0);
 	pci_ioaddr = ioremap(pci_iorange, pci_iolen);
-	if (! pci_iorange)
-		goto fail;
+	if (!pci_iorange) {
+		printk(KERN_ERR PFX "Cannot remap hardware registers\n");
+		goto fail_map;
+	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
+	dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
 	if (! dev) {
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
-	dev->base_addr = (unsigned long) pci_ioaddr;
+	card = priv->card;
+	card->pci_ioaddr = pci_ioaddr;
 	dev->mem_start = pci_iorange;
 	dev->mem_end = pci_iorange + pci_iolen - 1;
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	printk(KERN_DEBUG PFX
-	       "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n",
-	       pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
+	hermes_struct_init(&priv->hw, pci_ioaddr, HERMES_32BIT_REGSPACING);
 
-	hermes_struct_init(&priv->hw, dev->base_addr,
-			   HERMES_MEM, HERMES_32BIT_REGSPACING);
-	pci_set_drvdata(pdev, dev);
+	printk(KERN_DEBUG PFX "Detected device %s, mem:0x%lx-0x%lx, irq %d\n",
+	       pci_name(pdev), dev->mem_start, dev->mem_end, pdev->irq);
 
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n",
-		       pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
 	/* Perform a COR reset to start the card */
-	if(orinoco_pci_cor_reset(priv) != 0) {
-		printk(KERN_ERR "%s: Failed to start the card\n", dev->name);
-		err = -ETIMEDOUT;
+	err = orinoco_pci_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
 		goto fail;
 	}
 
-	/* Override the normal firmware detection - the Prism 2.5 PCI
-	 * cards look like Lucent firmware but are actually Intersil */
-	priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
-
 	err = register_netdev(dev);
 	if (err) {
-		printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
+		printk(KERN_ERR PFX "Failed to register net device\n");
 		goto fail;
 	}
 
+	pci_set_drvdata(pdev, dev);
+
 	return 0;
 
  fail:
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 
-		free_netdev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
 
-	if (pci_ioaddr)
-		iounmap(pci_ioaddr);
+ fail_alloc:
+	iounmap(pci_ioaddr);
 
+ fail_map:
+	pci_release_regions(pdev);
+
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -283,22 +283,18 @@ static void __devexit orinoco_pci_remove
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_pci_card *card = priv->card;
 
 	unregister_netdev(dev);
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-
-	if (priv->hw.iobase)
-		iounmap((unsigned char *) priv->hw.iobase);
-
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-	free_netdev(dev);
-
+	free_orinocodev(dev);
+	iounmap(card->pci_ioaddr);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
-static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state)
+static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -326,6 +322,9 @@ static int orinoco_pci_suspend(struct pc
 	
 	orinoco_unlock(priv, &flags);
 
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
 	return 0;
 }
 
@@ -338,6 +337,9 @@ static int orinoco_pci_resume(struct pci
 
 	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
 
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev);
+
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
@@ -368,6 +370,8 @@ static struct pci_device_id orinoco_pci_
 	{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
 	/* Intersil Prism 2.5 */
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
+	/* Samsung MagicLAN SWL-2210P */
+	{0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,},
 };
 
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -142,146 +142,199 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-#define COR_OFFSET	(0x3e0/2) /* COR attribute offset of Prism2 PC card */
+#define COR_OFFSET	(0x3e0)	/* COR attribute offset of Prism2 PC card */
 #define COR_VALUE	(COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)	/* reset bit in the COR register */
+#define PLX_RESET_TIME	(500)	/* milliseconds */
 
 #define PLX_INTCSR		0x4c /* Interrupt Control & Status Register */
 #define PLX_INTCSR_INTEN	(1<<6) /* Interrupt Enable bit */
 
-static const u16 cis_magic[] = {
-	0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067
+static const u8 cis_magic[] = {
+	0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
 };
 
+/* Orinoco PLX specific data */
+struct orinoco_plx_card {
+	void __iomem *attr_mem;
+};
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_plx_cor_reset(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	struct orinoco_plx_card *card = priv->card;
+	u8 __iomem *attr_mem = card->attr_mem;
+	unsigned long timeout;
+	u16 reg;
+
+	writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET);
+	mdelay(1);
+
+	writeb(COR_VALUE, attr_mem + COR_OFFSET);
+	mdelay(1);
+
+	/* Just in case, wait more until the card is no longer busy */
+	timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
+	reg = hermes_read_regn(hw, CMD);
+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+		mdelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+
+	/* Did we timeout ? */
+	if (reg & HERMES_CMD_BUSY) {
+		printk(KERN_ERR PFX "Busy timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+
 static int orinoco_plx_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
 	int err = 0;
-	u16 *attr_mem = NULL;
-	u32 reg, addr;
+	u8 __iomem *attr_mem = NULL;
+	u32 csr_reg, plx_addr;
 	struct orinoco_private *priv = NULL;
+	struct orinoco_plx_card *card;
 	unsigned long pccard_ioaddr = 0;
 	unsigned long pccard_iolen = 0;
 	struct net_device *dev = NULL;
+	void __iomem *mem;
 	int i;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
-
-	/* Resource 2 is mapped to the PCMCIA space */
-	attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE);
-	if (! attr_mem)
-		goto fail;
-
-	printk(KERN_DEBUG "orinoco_plx: CIS: ");
-	for (i = 0; i < 16; i++) {
-		printk("%02X:", (int)attr_mem[i]);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return err;
 	}
-	printk("\n");
 
-	/* Verify whether PC card is present */
-	/* FIXME: we probably need to be smarted about this */
-	if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) {
-		printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n");
-		err = -EIO;
-		goto fail;
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
 	}
 
-	/* PCMCIA COR is the first byte following CIS: this write should
-	 * enable I/O mode and select level-triggered interrupts */
-	attr_mem[COR_OFFSET] = COR_VALUE;
-	mdelay(1);
-	reg = attr_mem[COR_OFFSET];
-	if (reg != COR_VALUE) {
-		printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg);
-		goto fail;
-	}			
-
-	iounmap(attr_mem);
-	attr_mem = NULL; /* done with this now, it seems */
+	/* Resource 1 is mapped to PLX-specific registers */
+	plx_addr = pci_resource_start(pdev, 1);
 
-	/* bjoern: We need to tell the card to enable interrupts, in
-	   case the serial eprom didn't do this already. See the
-	   PLX9052 data book, p8-1 and 8-24 for reference. */
-	addr = pci_resource_start(pdev, 1);
-	reg = 0;
-	reg = inl(addr+PLX_INTCSR);
-	if (reg & PLX_INTCSR_INTEN)
-		printk(KERN_DEBUG "orinoco_plx: "
-		       "Local Interrupt already enabled\n");
-	else {
-		reg |= PLX_INTCSR_INTEN;
-		outl(reg, addr+PLX_INTCSR);
-		reg = inl(addr+PLX_INTCSR);
-		if(!(reg & PLX_INTCSR_INTEN)) {
-			printk(KERN_ERR "orinoco_plx: "
-			       "Couldn't enable Local Interrupts\n");
-			goto fail;
-		}
+	/* Resource 2 is mapped to the PCMCIA attribute memory */
+	attr_mem = ioremap(pci_resource_start(pdev, 2),
+			   pci_resource_len(pdev, 2));
+	if (!attr_mem) {
+		printk(KERN_ERR PFX "Cannot remap PCMCIA space\n");
+		goto fail_map_attr;
 	}
 
-	/* and 3 to the PCMCIA slot I/O address space */
+	/* Resource 3 is mapped to the PCMCIA I/O address space */
 	pccard_ioaddr = pci_resource_start(pdev, 3);
 	pccard_iolen = pci_resource_len(pdev, 3);
-	if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) {
-		printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n",
-		       pccard_iolen, pccard_ioaddr);
-		pccard_ioaddr = 0;
-		err = -EBUSY;
-		goto fail;
+
+	mem = pci_iomap(pdev, 3, 0);
+	if (!mem) {
+		err = -ENOMEM;
+		goto fail_map_io;
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
-	if (! dev) {
+	dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset);
+	if (!dev) {
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
+	card = priv->card;
+	card->attr_mem = attr_mem;
 	dev->base_addr = pccard_ioaddr;
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
+	hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING);
+
 	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device "
 	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
 	       pccard_ioaddr);
 
-	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO,
-			   HERMES_16BIT_REGSPACING);
-	pci_set_drvdata(pdev, dev);
-
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
+	/* bjoern: We need to tell the card to enable interrupts, in
+	   case the serial eprom didn't do this already.  See the
+	   PLX9052 data book, p8-1 and 8-24 for reference. */
+	csr_reg = inl(plx_addr + PLX_INTCSR);
+	if (!(csr_reg & PLX_INTCSR_INTEN)) {
+		csr_reg |= PLX_INTCSR_INTEN;
+		outl(csr_reg, plx_addr + PLX_INTCSR);
+		csr_reg = inl(plx_addr + PLX_INTCSR);
+		if (!(csr_reg & PLX_INTCSR_INTEN)) {
+			printk(KERN_ERR PFX "Cannot enable interrupts\n");
+			goto fail;
+		}
+	}
+
+	err = orinoco_plx_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
+		goto fail;
+	}
+
+	printk(KERN_DEBUG PFX "CIS: ");
+	for (i = 0; i < 16; i++) {
+		printk("%02X:", readb(attr_mem + 2*i));
+	}
+	printk("\n");
+
+	/* Verify whether a supported PC card is present */
+	/* FIXME: we probably need to be smarted about this */
+	for (i = 0; i < sizeof(cis_magic); i++) {
+		if (cis_magic[i] != readb(attr_mem +2*i)) {
+			printk(KERN_ERR PFX "The CIS value of Prism2 PC "
+			       "card is unexpected\n");
+			err = -EIO;
+			goto fail;
+		}
+	}
+
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register network device\n");
 		goto fail;
+	}
+
+	pci_set_drvdata(pdev, dev);
 
 	return 0;
 
  fail:
-	printk(KERN_DEBUG PFX "init_one(), FAIL!\n");
+	free_irq(pdev->irq, dev);
 
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-		
-		free_netdev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
 
-	if (pccard_ioaddr)
-		release_region(pccard_ioaddr, pccard_iolen);
+ fail_alloc:
+	pci_iounmap(pdev, mem);
+
+ fail_map_io:
+	iounmap(attr_mem);
 
-	if (attr_mem)
-		iounmap(attr_mem);
+ fail_map_attr:
+	pci_release_regions(pdev);
 
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -290,20 +343,19 @@ static int orinoco_plx_init_one(struct p
 static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_plx_card *card = priv->card;
+	u8 __iomem *attr_mem = card->attr_mem;
 
 	BUG_ON(! dev);
 
 	unregister_netdev(dev);
-		
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-		
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-
-	free_netdev(dev);
-
-	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
-
+	free_orinocodev(dev);
+	pci_iounmap(pdev, priv->hw.iobase);
+	iounmap(attr_mem);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
@@ -352,8 +404,7 @@ static int __init orinoco_plx_init(void)
 static void __exit orinoco_plx_exit(void)
 {
 	pci_unregister_driver(&orinoco_plx_driver);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
+	ssleep(1);
 }
 
 module_init(orinoco_plx_init);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -79,90 +79,137 @@
 #include "orinoco.h"
 
 #define COR_VALUE	(COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)	/* reset bit in the COR register */
+#define TMD_RESET_TIME	(500)	/* milliseconds */
+
+/* Orinoco TMD specific data */
+struct orinoco_tmd_card {
+	u32 tmd_io;
+};
+
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	struct orinoco_tmd_card *card = priv->card;
+	u32 addr = card->tmd_io;
+	unsigned long timeout;
+	u16 reg;
+
+	outb(COR_VALUE | COR_RESET, addr);
+	mdelay(1);
+
+	outb(COR_VALUE, addr);
+	mdelay(1);
+
+	/* Just in case, wait more until the card is no longer busy */
+	timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
+	reg = hermes_read_regn(hw, CMD);
+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+		mdelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+
+	/* Did we timeout ? */
+	if (reg & HERMES_CMD_BUSY) {
+		printk(KERN_ERR PFX "Busy timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 
 static int orinoco_tmd_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
 	int err = 0;
-	u32 reg, addr;
 	struct orinoco_private *priv = NULL;
-	unsigned long pccard_ioaddr = 0;
-	unsigned long pccard_iolen = 0;
+	struct orinoco_tmd_card *card;
 	struct net_device *dev = NULL;
+	void __iomem *mem;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return err;
+	}
 
-	printk(KERN_DEBUG PFX "TMD setup\n");
-	pccard_ioaddr = pci_resource_start(pdev, 2);
-	pccard_iolen = pci_resource_len(pdev, 2);
-	if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) {
-		printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n",
-			pccard_ioaddr, pccard_iolen);
-		pccard_ioaddr = 0;
-		err = -EBUSY;
-		goto fail;
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
 	}
-	addr = pci_resource_start(pdev, 1);
-	outb(COR_VALUE, addr);
-	mdelay(1);
-	reg = inb(addr);
-	if (reg != COR_VALUE) {
-		printk(KERN_ERR PFX "Error setting TMD COR values %x should be %x\n", reg, COR_VALUE);
-		err = -EIO;
-		goto fail;
+
+	mem = pci_iomap(pdev, 2, 0);
+	if (! mem) {
+		err = -ENOMEM;
+		goto fail_iomap;
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
+	dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
 	if (! dev) {
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
-	dev->base_addr = pccard_ioaddr;
+	card = priv->card;
+	card->tmd_io = pci_resource_start(pdev, 1);
+	dev->base_addr = pci_resource_start(pdev, 2);
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
+	hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING);
+
 	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device "
 	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
-	       pccard_ioaddr);
-
-	hermes_struct_init(&(priv->hw), dev->base_addr,
-			HERMES_IO, HERMES_16BIT_REGSPACING);
-	pci_set_drvdata(pdev, dev);
+	       dev->base_addr);
 
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n",
-		       pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
+	err = orinoco_tmd_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
+		goto fail;
+	}
+
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register network device\n");
 		goto fail;
+	}
+
+	pci_set_drvdata(pdev, dev);
 
 	return 0;
 
  fail:
-	printk(KERN_DEBUG PFX "init_one(), FAIL!\n");
+	free_irq(pdev->irq, dev);
 
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-		
-		free_netdev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
+
+ fail_alloc:
+	pci_iounmap(pdev, mem);
 
-	if (pccard_ioaddr)
-		release_region(pccard_ioaddr, pccard_iolen);
+ fail_iomap:
+	pci_release_regions(pdev);
 
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -171,20 +218,16 @@ static int orinoco_tmd_init_one(struct p
 static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
 
 	BUG_ON(! dev);
 
 	unregister_netdev(dev);
-		
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-		
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-
-	free_netdev(dev);
-
-	release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
-
+	free_orinocodev(dev);
+	pci_iounmap(pdev, priv->hw.iobase);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
@@ -218,8 +261,7 @@ static int __init orinoco_tmd_init(void)
 static void __exit orinoco_tmd_exit(void)
 {
 	pci_unregister_driver(&orinoco_tmd_driver);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
+	ssleep(1);
 }
 
 module_init(orinoco_tmd_init);
diff --git a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile
--- a/drivers/net/wireless/prism54/Makefile
+++ b/drivers/net/wireless/prism54/Makefile
@@ -6,5 +6,3 @@ prism54-objs := islpci_eth.o islpci_mgt.
 
 obj-$(CONFIG_PRISM54) += prism54.o
 
-EXTRA_CFLAGS = -I$(PWD) #-DCONFIG_PRISM54_WDS
-
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -125,11 +125,11 @@ isl38xx_trigger_device(int asleep, void 
 #if VERBOSE > SHOW_ERROR_MESSAGES
 		do_gettimeofday(&current_time);
 		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
-		      current_time.tv_sec, current_time.tv_usec);
+		      current_time.tv_sec, (long)current_time.tv_usec);
 #endif
 
 		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-		      current_time.tv_sec, current_time.tv_usec,
+		      current_time.tv_sec, (long)current_time.tv_usec,
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
 		udelay(ISL38XX_WRITEIO_DELAY);
 
@@ -139,7 +139,7 @@ isl38xx_trigger_device(int asleep, void 
 			do_gettimeofday(&current_time);
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device register abadface\n",
-			      current_time.tv_sec, current_time.tv_usec);
+			      current_time.tv_sec, (long)current_time.tv_usec);
 #endif
 			/* read the Device Status Register until Sleepmode bit is set */
 			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
@@ -150,7 +150,7 @@ isl38xx_trigger_device(int asleep, void 
 
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device register read %08x\n",
-			      current_time.tv_sec, current_time.tv_usec,
+			      current_time.tv_sec, (long)current_time.tv_usec,
 			      readl(device_base + ISL38XX_CTRL_STAT_REG));
 			udelay(ISL38XX_WRITEIO_DELAY);
 
@@ -158,7 +158,7 @@ isl38xx_trigger_device(int asleep, void 
 			do_gettimeofday(&current_time);
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device asleep counter %i\n",
-			      current_time.tv_sec, current_time.tv_usec,
+			      current_time.tv_sec, (long)current_time.tv_usec,
 			      counter);
 #endif
 		}
@@ -174,7 +174,7 @@ isl38xx_trigger_device(int asleep, void 
 #if VERBOSE > SHOW_ERROR_MESSAGES
 		do_gettimeofday(&current_time);
 		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-		      current_time.tv_sec, current_time.tv_usec, reg);
+		      current_time.tv_sec, (long)current_time.tv_usec, reg);
 #endif
 	} else {
 		/* device is (still) awake  */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -36,6 +36,14 @@
 
 #include <net/iw_handler.h>	/* New driver API */
 
+
+static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+				u8 *wpa_ie, size_t wpa_ie_len);
+static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
+				__u32 *, char *);
+
+
 /**
  * prism54_mib_mode_helper - MIB change mode helper function
  * @mib: the &struct islpci_mib object to modify
@@ -47,7 +55,7 @@
  *  Wireless API modes to Device firmware modes. It also checks for 
  *  correct valid Linux wireless modes. 
  */
-int
+static int
 prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
 {
 	u32 config = INL_CONFIG_MANUALRUN;
@@ -647,7 +655,7 @@ prism54_translate_bss(struct net_device 
 	return current_ev;
 }
 
-int
+static int
 prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
 		 struct iw_point *dwrq, char *extra)
 {
@@ -1586,7 +1594,7 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 
-void
+static void
 prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
 		   u8 *wpa_ie, size_t wpa_ie_len)
 {
@@ -1653,7 +1661,7 @@ prism54_wpa_ie_add(islpci_private *priv,
 	up(&priv->wpa_sem);
 }
 
-size_t
+static size_t
 prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 {
 	struct list_head *ptr;
@@ -1740,7 +1748,7 @@ handle_request(islpci_private *priv, str
 	}
 }
 
-int
+static int
 prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
 			    char *data)
 {
@@ -1750,7 +1758,7 @@ prism54_process_trap_helper(islpci_priva
 	u8 wpa_ie[MAX_WPA_IE_LEN];
 	int wpa_ie_len;
 	size_t len = 0; /* u16, better? */
-	u8 *payload = 0, *pos = 0;
+	u8 *payload = NULL, *pos = NULL;
 	int ret;
 
 	/* I think all trapable objects are listed here.
@@ -2318,7 +2326,7 @@ prism54_hostapd(struct net_device *ndev,
        return ret;
 }
 
-int
+static int
 prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
 		__u32 * uwrq, char *extra)
 {
@@ -2362,7 +2370,7 @@ prism54_set_wpa(struct net_device *ndev,
 	return 0;
 }
 
-int
+static int
 prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
 		__u32 * uwrq, char *extra)
 {
@@ -2371,7 +2379,7 @@ prism54_get_wpa(struct net_device *ndev,
 	return 0;
 }
 
-int
+static int
 prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
 		     __u32 * uwrq, char *extra)
 {
@@ -2384,7 +2392,7 @@ prism54_set_prismhdr(struct net_device *
 	return 0;
 }
 
-int
+static int
 prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
 		     __u32 * uwrq, char *extra)
 {
@@ -2393,7 +2401,7 @@ prism54_get_prismhdr(struct net_device *
 	return 0;
 }
 
-int
+static int
 prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
 		  __u32 * uwrq, char *extra)
 {
@@ -2405,7 +2413,7 @@ prism54_debug_oid(struct net_device *nde
 	return 0;
 }
 
-int
+static int
 prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
 		      struct iw_point *data, char *extra)
 {
@@ -2441,7 +2449,7 @@ prism54_debug_get_oid(struct net_device 
 	return ret;
 }
 
-int
+static int
 prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
 		      struct iw_point *data, char *extra)
 {
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -41,15 +41,10 @@ void prism54_process_trap(void *);
 
 void prism54_wpa_ie_init(islpci_private *priv);
 void prism54_wpa_ie_clean(islpci_private *priv);
-void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
-			u8 *wpa_ie, size_t wpa_ie_len);
-size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
 
 int prism54_set_mac_address(struct net_device *, void *);
 
 int prism54_ioctl(struct net_device *, struct ifreq *, int);
-int prism54_set_wpa(struct net_device *, struct iw_request_info *, 
-			__u32 *, char *);
 
 extern const struct iw_handler_def prism54_handler_def;
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -44,6 +44,7 @@
 
 static int prism54_bring_down(islpci_private *);
 static int islpci_alloc_memory(islpci_private *);
+static struct net_device_stats *islpci_statistics(struct net_device *);
 
 /* Temporary dummy MAC address to use until firmware is loaded.
  * The idea there is that some tools (such as nameif) may query
@@ -52,7 +53,7 @@ static int islpci_alloc_memory(islpci_pr
  * Of course, this is not the final/real MAC address. It doesn't
  * matter, as you are suppose to be able to change it anytime via
  * ndev->set_mac_address. Jean II */
-const unsigned char	dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };
+static const unsigned char	dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };
 
 static int
 isl_upload_firmware(islpci_private *priv)
@@ -607,7 +608,7 @@ islpci_reset(islpci_private *priv, int r
 	return rc;
 }
 
-struct net_device_stats *
+static struct net_device_stats *
 islpci_statistics(struct net_device *ndev)
 {
 	islpci_private *priv = netdev_priv(ndev);
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,8 +211,6 @@ islpci_trigger(islpci_private *priv)
 			       priv->device_base);
 }
 
-struct net_device_stats *islpci_statistics(struct net_device *);
-
 int islpci_free_memory(islpci_private *);
 struct net_device *islpci_setup(struct pci_dev *);
 #endif				/* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -81,7 +81,7 @@ MODULE_DEVICE_TABLE(pci, prism54_id_tbl)
 
 static int prism54_probe(struct pci_dev *, const struct pci_device_id *);
 static void prism54_remove(struct pci_dev *);
-static int prism54_suspend(struct pci_dev *, u32 state);
+static int prism54_suspend(struct pci_dev *, pm_message_t state);
 static int prism54_resume(struct pci_dev *);
 
 static struct pci_driver prism54_driver = {
@@ -261,7 +261,7 @@ prism54_remove(struct pci_dev *pdev)
 }
 
 int
-prism54_suspend(struct pci_dev *pdev, u32 state)
+prism54_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
 	islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -44,6 +44,7 @@ module_param(pc_debug, int, 0);
 /******************************************************************************
     Driver general functions
 ******************************************************************************/
+#if VERBOSE > SHOW_ERROR_MESSAGES
 void
 display_buffer(char *buffer, int length)
 {
@@ -58,6 +59,7 @@ display_buffer(char *buffer, int length)
 
 	printk("\n");
 }
+#endif
 
 /*****************************************************************************
     Queue handling for management frames
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -24,8 +24,8 @@
 #include "isl_ioctl.h"
 
 /* to convert between channel and freq */
-const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484
+static const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432,
+	2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484
 };
 
 int
@@ -730,6 +730,7 @@ mgt_commit(islpci_private *priv)
  *
  * The way to do this is to set ESSID. Note though that they may get 
  * unlatch before though by setting another OID. */
+#if 0
 void
 mgt_unlatch_all(islpci_private *priv)
 {
@@ -756,6 +757,7 @@ mgt_unlatch_all(islpci_private *priv)
 	if (rvalue)
 		printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
 }
+#endif
 
 /* This will tell you if you are allowed to answer a mlme(ex) request .*/
 
diff --git a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h
--- a/drivers/net/wireless/prism54/oid_mgt.h
+++ b/drivers/net/wireless/prism54/oid_mgt.h
@@ -28,8 +28,7 @@ int mgt_init(islpci_private *);
 
 void mgt_clean(islpci_private *);
 
-/* I don't know where to put these 3 */
-extern const int frequency_list_bg[];
+/* I don't know where to put these 2 */
 extern const int frequency_list_a[];
 int channel_of_freq(int);
 
@@ -49,7 +48,6 @@ void mgt_set(islpci_private *, enum oid_
 void mgt_get(islpci_private *, enum oid_num_t, void *);
 
 int mgt_commit(islpci_private *);
-void mgt_unlatch_all(islpci_private *);
 
 int mgt_mlme_answer(islpci_private *);
 
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1215,6 +1215,9 @@ static int ray_dev_ioctl(struct net_devi
 #if WIRELESS_EXT > 7
     struct iwreq *wrq = (struct iwreq *) ifr;
 #endif	/* WIRELESS_EXT > 7 */
+#ifdef WIRELESS_SPY
+    struct sockaddr	address[IW_MAX_SPY];
+#endif	/* WIRELESS_SPY */
 
     if (!(link->state & DEV_PRESENT)) {
         DEBUG(2,"ray_dev_ioctl - device not present\n");
@@ -1511,7 +1514,6 @@ static int ray_dev_ioctl(struct net_devi
       /* If there is some addresses to copy */
       if(local->spy_number > 0)
 	{
-	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
 	  /* Copy addresses to the driver */
@@ -1551,7 +1553,6 @@ static int ray_dev_ioctl(struct net_devi
       /* If the user want to have the addresses back... */
       if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
 	{
-	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
 	  /* Copy addresses from the lp structure */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -876,7 +876,7 @@ static int allocate_buffers(struct strip
  */
 static int strip_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct strip *strip_info = dev->priv;
+	struct strip *strip_info = netdev_priv(dev);
 	int old_mtu = strip_info->mtu;
 	unsigned char *orbuff = strip_info->rx_buff;
 	unsigned char *osbuff = strip_info->sx_buff;
@@ -1563,7 +1563,7 @@ static void strip_send(struct strip *str
 /* Encapsulate a datagram and kick it into a TTY queue. */
 static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct strip *strip_info = (struct strip *) (dev->priv);
+	struct strip *strip_info = netdev_priv(dev);
 
 	if (!netif_running(dev)) {
 		printk(KERN_ERR "%s: xmit call when iface is down\n",
@@ -1639,7 +1639,7 @@ static int strip_header(struct sk_buff *
 			unsigned short type, void *daddr, void *saddr,
 			unsigned len)
 {
-	struct strip *strip_info = (struct strip *) (dev->priv);
+	struct strip *strip_info = netdev_priv(dev);
 	STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
 
 	/*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type,
@@ -1648,7 +1648,7 @@ static int strip_header(struct sk_buff *
 	header->src_addr = strip_info->true_dev_addr;
 	header->protocol = htons(type);
 
-	/*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len); */
+	/*HexDump("strip_header", netdev_priv(dev), skb->data, skb->data + skb->len); */
 
 	if (!daddr)
 		return (-dev->hard_header_len);
@@ -2400,7 +2400,7 @@ static int set_mac_address(struct strip 
 
 static int strip_set_mac_address(struct net_device *dev, void *addr)
 {
-	struct strip *strip_info = (struct strip *) (dev->priv);
+	struct strip *strip_info = netdev_priv(dev);
 	struct sockaddr *sa = addr;
 	printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name);
 	set_mac_address(strip_info, (MetricomAddress *) sa->sa_data);
@@ -2409,8 +2409,8 @@ static int strip_set_mac_address(struct 
 
 static struct net_device_stats *strip_get_stats(struct net_device *dev)
 {
+	struct strip *strip_info = netdev_priv(dev);
 	static struct net_device_stats stats;
-	struct strip *strip_info = (struct strip *) (dev->priv);
 
 	memset(&stats, 0, sizeof(struct net_device_stats));
 
@@ -2454,7 +2454,7 @@ static struct net_device_stats *strip_ge
 
 static int strip_open_low(struct net_device *dev)
 {
-	struct strip *strip_info = (struct strip *) (dev->priv);
+	struct strip *strip_info = netdev_priv(dev);
 
 	if (strip_info->tty == NULL)
 		return (-ENODEV);
@@ -2487,7 +2487,7 @@ static int strip_open_low(struct net_dev
 
 static int strip_close_low(struct net_device *dev)
 {
-	struct strip *strip_info = (struct strip *) (dev->priv);
+	struct strip *strip_info = netdev_priv(dev);
 
 	if (strip_info->tty == NULL)
 		return -EBUSY;
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -34,9 +34,9 @@
  
 static LIST_HEAD(dying_tasks);
 static LIST_HEAD(dead_tasks);
-cpumask_t marked_cpus = CPU_MASK_NONE;
+static cpumask_t marked_cpus = CPU_MASK_NONE;
 static DEFINE_SPINLOCK(task_mortuary);
-void process_task_mortuary(void);
+static void process_task_mortuary(void);
 
 
 /* Take ownership of the task struct and place it on the
@@ -422,7 +422,7 @@ static void increment_tail(struct oprofi
  * and to have reached the list, it must have gone through
  * one full sync already.
  */
-void process_task_mortuary(void)
+static void process_task_mortuary(void)
 {
 	struct list_head * pos;
 	struct list_head * pos2;
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -32,7 +32,7 @@ struct oprofile_cpu_buffer cpu_buffer[NR
 static void wq_sync_buffer(void *);
 
 #define DEFAULT_TIMER_EXPIRE (HZ / 10)
-int work_enabled;
+static int work_enabled;
 
 void free_cpu_buffers(void)
 {
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -94,7 +94,7 @@ void free_event_buffer(void)
 }
 
  
-int event_buffer_open(struct inode * inode, struct file * file)
+static int event_buffer_open(struct inode * inode, struct file * file)
 {
 	int err = -EPERM;
 
@@ -130,7 +130,7 @@ out:
 }
 
 
-int event_buffer_release(struct inode * inode, struct file * file)
+static int event_buffer_release(struct inode * inode, struct file * file)
 {
 	oprofile_stop();
 	oprofile_shutdown();
@@ -142,7 +142,8 @@ int event_buffer_release(struct inode * 
 }
 
 
-ssize_t event_buffer_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
+static ssize_t event_buffer_read(struct file * file, char __user * buf,
+				 size_t count, loff_t * offset)
 {
 	int retval = -EINVAL;
 	size_t const max = buffer_size * sizeof(unsigned long);
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -18,13 +18,13 @@ unsigned long fs_buffer_size = 131072;
 unsigned long fs_cpu_buffer_size = 8192;
 unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
 
-static ssize_t depth_read(struct file * file, char * buf, size_t count, loff_t * offset)
+static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
 {
 	return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset);
 }
 
 
-static ssize_t depth_write(struct file * file, char const * buf, size_t count, loff_t * offset)
+static ssize_t depth_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
 {
 	unsigned long val;
 	int retval;
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -110,6 +110,14 @@ config IOMMU_SBA
 #	help
 #	  Say Y here for V-class PCI, DMA/IOMMU, IRQ subsystem support.
 
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "PA-RISC specific drivers"
+
 config SUPERIO
 	bool "SuperIO (SuckyIO) support"
 	depends on PCI_LBA
@@ -144,9 +152,18 @@ config PDC_CHASSIS
 	  
 	  If unsure, say Y.
 
-source "drivers/pcmcia/Kconfig"
-
-source "drivers/pci/hotplug/Kconfig"
-
+config PDC_STABLE
+	tristate "PDC Stable Storage support"
+	depends on SYSFS
+	default y
+	help
+	  Say Y here if you want to enable support for accessing Stable Storage
+	  variables (PDC non volatile variables such as Primary Boot Path,
+	  Console Path, Autoboot, Autosearch, etc) through SysFS.
+	
+	  If unsure, say Y.
+	
+	  To compile this driver as a module, choose M here.
+	  The module will be called pdc_stable.
 
 endmenu
diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile
--- a/drivers/parisc/Makefile
+++ b/drivers/parisc/Makefile
@@ -22,5 +22,6 @@ obj-$(CONFIG_EISA)		+= eisa.o eisa_enume
 
 obj-$(CONFIG_SUPERIO)		+= superio.o
 obj-$(CONFIG_CHASSIS_LCD_LED)	+= led.o
+obj-$(CONFIG_PDC_STABLE)	+= pdc_stable.o
 obj-y				+= power.o
 
diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c
--- a/drivers/parisc/asp.c
+++ b/drivers/parisc/asp.c
@@ -30,6 +30,8 @@
 
 #define VIPER_INT_WORD  0xFFFBF088      /* addr of viper interrupt word */
 
+static struct gsc_asic asp;
+
 static void asp_choose_irq(struct parisc_device *dev, void *ctrl)
 {
 	int irq;
@@ -51,6 +53,14 @@ static void asp_choose_irq(struct parisc
 	}
 
 	gsc_asic_assign_irq(ctrl, irq, &dev->irq);
+
+	switch (dev->id.sversion) {
+	case 0x73:	irq =  2; break; /* i8042 High-priority */
+	case 0x76:	irq =  0; break; /* EISA BA */
+	default:	return;		 /* Other */
+	}
+
+	gsc_asic_assign_irq(ctrl, irq, &dev->aux_irq);
 }
 
 /* There are two register ranges we're interested in.  Interrupt /
@@ -64,20 +74,15 @@ static void asp_choose_irq(struct parisc
 int __init
 asp_init_chip(struct parisc_device *dev)
 {
-	struct gsc_asic *asp;
 	struct gsc_irq gsc_irq;
 	int ret;
 
-	asp = kmalloc(sizeof(*asp), 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;
+	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);
+		asp.name, asp.version, dev->hpa);
 
 	/* the IRQ ASP should use */
 	ret = -EBUSY;
@@ -87,9 +92,9 @@ asp_init_chip(struct parisc_device *dev)
 		goto out;
 	}
 
-	asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+	asp.eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
 
-	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "asp", asp);
+	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "asp", &asp);
 	if (ret < 0)
 		goto out;
 
@@ -97,13 +102,13 @@ asp_init_chip(struct parisc_device *dev)
 	gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);
 
 	/* Done init'ing, register this driver */
-	ret = gsc_common_setup(dev, asp);
+	ret = gsc_common_setup(dev, &asp);
 	if (ret)
 		goto out;
 
-	gsc_fixup_irqs(dev, asp, asp_choose_irq);
+	gsc_fixup_irqs(dev, &asp, asp_choose_irq);
 	/* Mongoose is a sibling of Asp, not a child... */
-	gsc_fixup_irqs(parisc_parent(dev), asp, asp_choose_irq);
+	gsc_fixup_irqs(parisc_parent(dev), &asp, asp_choose_irq);
 
 	/* initialize the chassis LEDs */ 
 #ifdef CONFIG_CHASSIS_LCD_LED	
@@ -111,10 +116,7 @@ asp_init_chip(struct parisc_device *dev)
 		    ASP_LED_ADDR);
 #endif
 
-	return 0;
-
-out:
-	kfree(asp);
+ out:
 	return ret;
 }
 
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -262,8 +262,6 @@ struct ioc {
 	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 ioc *ioc_list;
 static int ioc_count;
 
@@ -559,7 +557,7 @@ void CCIO_INLINE
 ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
 		   unsigned long hints)
 {
-	register unsigned long pa = (volatile unsigned long) vba;
+	register unsigned long pa;
 	register unsigned long ci; /* coherent index */
 
 	/* We currently only support kernel addresses */
@@ -1243,6 +1241,21 @@ ccio_get_iotlb_size(struct parisc_device
 #define CCIO_CHAINID_MASK	0xff
 #endif /* 0 */
 
+/* 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, }
+};
+
+static int ccio_probe(struct parisc_device *dev);
+
+static struct parisc_driver ccio_driver = {
+	.name =		"U2:Uturn",
+	.id_table =	ccio_tbl,
+	.probe =	ccio_probe,
+};
+
 /**
  * ccio_ioc_init - Initalize the I/O Controller
  * @ioc: The I/O Controller.
@@ -1254,9 +1267,9 @@ ccio_get_iotlb_size(struct parisc_device
 static void
 ccio_ioc_init(struct ioc *ioc)
 {
-	int i, iov_order;
+	int i;
+	unsigned int iov_order;
 	u32 iova_space_size;
-	unsigned long physmem;
 
 	/*
 	** Determine IOVA Space size from memory size.
@@ -1269,17 +1282,16 @@ ccio_ioc_init(struct ioc *ioc)
 	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
 	*/
 
+	iova_space_size = (u32) (num_physpages / count_parisc_driver(&ccio_driver));
+
 	/* limit IOVA space size to 1MB-1GB */
 
-	physmem = num_physpages << PAGE_SHIFT;
-	if(physmem < (ccio_mem_ratio * 1024 * 1024)) {
-		iova_space_size = 1024 * 1024;
+	if (iova_space_size < (1 << (20 - PAGE_SHIFT))) {
+		iova_space_size =  1 << (20 - PAGE_SHIFT);
 #ifdef __LP64__
-	} else if(physmem > (ccio_mem_ratio * 512 * 1024 * 1024)) {
-		iova_space_size = 512 * 1024 * 1024;
+	} else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) {
+		iova_space_size =  1 << (30 - PAGE_SHIFT);
 #endif
-	} else {
-		iova_space_size = (u32)(physmem / ccio_mem_ratio);
 	}
 
 	/*
@@ -1295,10 +1307,10 @@ ccio_ioc_init(struct ioc *ioc)
 	**   this is the case under linux."
 	*/
 
-	iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT);
-	BUG_ON(iov_order > (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
-	BUG_ON(iov_order < (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
-	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
+	iov_order = get_order(iova_space_size << PAGE_SHIFT);
+
+	/* iova_space_size is now bytes, not pages */
+	iova_space_size = 1 << (iov_order + PAGE_SHIFT);
 
 	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
@@ -1307,9 +1319,12 @@ ccio_ioc_init(struct ioc *ioc)
 	/* Verify it's a power of two */
 	BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT));
 
-	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);
+	DBG_INIT("%s() hpa 0x%lx mem %luMB IOV %dMB (%d bits)\n",
+			__FUNCTION__,
+			ioc->ioc_hpa,
+			(unsigned long) num_physpages >> (20 - PAGE_SHIFT),
+			iova_space_size>>20,
+			iov_order + PAGE_SHIFT);
 
 	ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, 
 						 get_order(ioc->pdir_size));
@@ -1566,19 +1581,6 @@ static int ccio_probe(struct parisc_devi
 	return 0;
 }
 
-/* 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, }
-};
-
-static struct parisc_driver ccio_driver = {
-	.name =		"U2:Uturn",
-	.id_table =	ccio_tbl,
-	.probe =	ccio_probe,
-};
-
 /**
  * ccio_init - ccio initalization procedure.
  *
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -653,14 +653,13 @@ dino_fixup_bus(struct pci_bus *bus)
 				      PCI_INTERRUPT_PIN, 1, &irq_pin);
 			irq_pin = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
 			printk(KERN_WARNING "Device %s has undefined IRQ, "
-					"setting to %d\n", dev->slot_name,
-					irq_pin);
+					"setting to %d\n", pci_name(dev), irq_pin);
 			dino_cfg_write(dev->bus, dev->devfn, 
 				       PCI_INTERRUPT_LINE, 1, irq_pin);
 			dino_assign_irq(dino_dev, irq_pin, &dev->irq);
 #else
 			dev->irq = 65535;
-			printk(KERN_WARNING "Device %s has unassigned IRQ\n", dev->slot_name);	
+			printk(KERN_WARNING "Device %s has unassigned IRQ\n", pci_name(dev));
 #endif
 		} else {
 
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -44,6 +44,7 @@
 #include <asm/parisc-device.h>
 #include <asm/delay.h>
 #include <asm/eisa_bus.h>
+#include <asm/eisa_eeprom.h>
 
 #if 0
 #define EISA_DBG(msg, arg... ) printk(KERN_DEBUG "eisa: " msg , ## arg )
@@ -56,6 +57,8 @@
 
 static DEFINE_SPINLOCK(eisa_irq_lock);
 
+void __iomem *eisa_eeprom_addr;
+
 /* We can only have one EISA adapter in the system because neither
  * implementation can be flexed.
  */
@@ -351,6 +354,7 @@ static int __devinit eisa_probe(struct p
 	}
 	
 	EISA_bus = 1;
+
 	if (dev->num_addrs) {
 		/* newer firmware hand out the eeprom address */
 		eisa_dev.eeprom_addr = dev->addr[0];
@@ -362,8 +366,9 @@ static int __devinit eisa_probe(struct p
 			eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR;
 		}
 	}
-	eisa_eeprom_init(eisa_dev.eeprom_addr);
-	result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space);
+	eisa_eeprom_addr = ioremap(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH);
+	result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space,
+			&eisa_dev.hba.lmmio_space);
 	init_eisa_pic();
 
 	if (result >= 0) {
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -19,7 +19,6 @@
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -32,8 +31,6 @@
 
 #define 	EISA_EEPROM_MINOR 241
 
-static unsigned long eeprom_addr;
-
 static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin )
 {
 	switch (origin) {
@@ -64,7 +61,7 @@ static ssize_t eisa_eeprom_read(struct f
 	tmp = kmalloc(count, GFP_KERNEL);
 	if (tmp) {
 		for (i = 0; i < count; i++)
-			tmp[i] = gsc_readb(eeprom_addr+(*ppos)++);
+			tmp[i] = readb(eisa_eeprom_addr+(*ppos)++);
 
 		if (copy_to_user (buf, tmp, count))
 			ret = -EFAULT;
@@ -86,7 +83,7 @@ static int eisa_eeprom_ioctl(struct inod
 
 static int eisa_eeprom_open(struct inode *inode, struct file *file)
 {
-	if (file->f_mode & 2 || eeprom_addr == 0)
+	if (file->f_mode & 2)
 		return -EINVAL;
    
 	return 0;
@@ -109,22 +106,18 @@ static struct file_operations eisa_eepro
 	.release =	eisa_eeprom_release,
 };
 
-static struct miscdevice eisa_eeprom_dev=
-{
+static struct miscdevice eisa_eeprom_dev = {
 	EISA_EEPROM_MINOR,
-	"eisa eeprom",
+	"eisa_eeprom",
 	&eisa_eeprom_fops
 };
 
-int __init eisa_eeprom_init(unsigned long addr)
+static int __init eisa_eeprom_init(void)
 {
 	int retval;
 
-	/* XXX why return success when we haven't done anything? */
-	if (!addr)
-		return 0;
-
-	eeprom_addr = addr;
+	if (!eisa_eeprom_addr)
+		return -ENODEV;
 
 	retval = misc_register(&eisa_eeprom_dev);
 	if (retval < 0) {
@@ -132,8 +125,10 @@ int __init eisa_eeprom_init(unsigned lon
 		return retval;
 	}
 
-	printk(KERN_INFO "EISA EEPROM at 0x%lx\n", eeprom_addr);
+	printk(KERN_INFO "EISA EEPROM at 0x%p\n", eisa_eeprom_addr);
 	return 0;
 }
 
 MODULE_LICENSE("GPL");
+
+module_init(eisa_eeprom_init);
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -38,14 +38,14 @@
 
 int gsc_alloc_irq(struct gsc_irq *i)
 {
-	int irq = txn_alloc_irq();
+	int irq = txn_alloc_irq(GSC_EIM_WIDTH);
 	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->txn_data = txn_alloc_data(irq);
 	i->irq = irq;
 
 	return irq;
@@ -64,7 +64,7 @@ int gsc_claim_irq(struct gsc_irq *i, int
 	}
 
 	i->txn_addr = txn_alloc_addr(irq);
-	i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH);
+	i->txn_data = txn_alloc_data(irq);
 	i->irq = irq;
 
 	return irq;
@@ -171,12 +171,16 @@ int gsc_assign_irq(struct hw_interrupt_t
 
 void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp)
 {
-	int irq = gsc_assign_irq(&gsc_asic_interrupt_type, asic);
-	if (irq == NO_IRQ)
-		return;
+	int irq = asic->global_irq[local_irq];
+	
+	if (irq <= 0) {
+		irq = gsc_assign_irq(&gsc_asic_interrupt_type, asic);
+		if (irq == NO_IRQ)
+			return;
 
+		asic->global_irq[local_irq] = irq;
+	}
 	*irqp = irq;
-	asic->global_irq[local_irq] = irq;
 }
 
 void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
@@ -198,9 +202,15 @@ void gsc_fixup_irqs(struct parisc_device
 int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
 {
 	struct resource *res;
+	int i;
 
 	gsc_asic->gsc = parent;
 
+	/* Initialise local irq -> global irq mapping */
+	for (i = 0; i < 32; i++) {
+		gsc_asic->global_irq[i] = NO_IRQ;
+	}
+
 	/* allocate resource region */
 	res = request_mem_region(gsc_asic->hpa, 0x100000, gsc_asic->name);
 	if (res) {
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -16,7 +16,6 @@
 **
 */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -158,31 +158,9 @@
 
 
 #ifdef DEBUG_IOSAPIC
-static char assert_buf[128];
-
-static int
-assert_failed (char *a, char *f, int l)
-{
-        sprintf(assert_buf,
-			"ASSERT(%s) failed!\nline %d in %s\n",
-			a,      /* assertion text */
-			l,      /* line number */
-			f);     /* file name */
-        panic(assert_buf);
-	return 0;
-}
-
-#undef ASSERT
-#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); }
-
 #define DBG(x...) printk(x)
-
 #else /* DEBUG_IOSAPIC */
-
 #define DBG(x...)
-#undef	ASSERT
-#define ASSERT(EX)
-
 #endif /* DEBUG_IOSAPIC */
 
 #ifdef DEBUG_IOSAPIC_IRT
@@ -191,6 +169,12 @@ assert_failed (char *a, char *f, int l)
 #define DBG_IRT(x...)
 #endif
 
+#ifdef CONFIG_64BIT
+#define COMPARE_IRTE_ADDR(irte, hpa)	((irte)->dest_iosapic_addr == (hpa))
+#else
+#define COMPARE_IRTE_ADDR(irte, hpa)	\
+		((irte)->dest_iosapic_addr == ((hpa) | 0xffffffff00000000ULL))
+#endif
 
 #define IOSAPIC_REG_SELECT              0x00
 #define IOSAPIC_REG_WINDOW              0x10
@@ -201,33 +185,18 @@ assert_failed (char *a, char *f, int l)
 #define IOSAPIC_IRDT_ENTRY(idx)		(0x10+(idx)*2)
 #define IOSAPIC_IRDT_ENTRY_HI(idx)	(0x11+(idx)*2)
 
-static inline unsigned int iosapic_read(unsigned long iosapic, unsigned int reg)
+static inline unsigned int iosapic_read(void __iomem *iosapic, unsigned int reg)
 {
 	writel(reg, iosapic + IOSAPIC_REG_SELECT);
 	return readl(iosapic + IOSAPIC_REG_WINDOW);
 }
 
-static inline void iosapic_write(unsigned long iosapic, unsigned int reg, u32 val)
+static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 val)
 {
 	writel(reg, iosapic + IOSAPIC_REG_SELECT);
 	writel(val, iosapic + IOSAPIC_REG_WINDOW);
 }
 
-/*
-**     GFP_KERNEL includes __GFP_WAIT flag and that may not
-**     be acceptable. Since this is boot time, we shouldn't have
-**     to wait ever and this code should (will?) never get called
-**     from the interrrupt context.
-*/
-#define	IOSAPIC_KALLOC(a_type, cnt) \
-			(a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL)
-#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr)
-
-
-#define	IOSAPIC_LOCK(lck)	spin_lock_irqsave(lck, irqflags)
-#define	IOSAPIC_UNLOCK(lck)	spin_unlock_irqrestore(lck, irqflags)
-
-
 #define IOSAPIC_VERSION_MASK	0x000000ff
 #define	IOSAPIC_VERSION(ver)	((int) (ver & IOSAPIC_VERSION_MASK))
 
@@ -265,52 +234,64 @@ static inline void iosapic_eoi(void __io
 static struct irt_entry *irt_cell;
 static size_t irt_num_entry;
 
+static struct irt_entry *iosapic_alloc_irt(int num_entries)
+{
+	unsigned long a;
 
+	/* The IRT needs to be 8-byte aligned for the PDC call. 
+	 * Normally kmalloc would guarantee larger alignment, but
+	 * if CONFIG_DEBUG_SLAB is enabled, then we can get only
+	 * 4-byte alignment on 32-bit kernels
+	 */
+	a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL);
+	a = (a + 7) & ~7;
+	return (struct irt_entry *)a;
+}
 
-/*
-** iosapic_load_irt
-**
-** The "Get PCI INT Routing Table Size" option returns the number of 
-** entries in the PCI interrupt routing table for the cell specified 
-** in the cell_number argument.  The cell number must be for a cell 
-** within the caller's protection domain.
-**
-** The "Get PCI INT Routing Table" option returns, for the cell 
-** specified in the cell_number argument, the PCI interrupt routing 
-** table in the caller allocated memory pointed to by mem_addr.
-** We assume the IRT only contains entries for I/O SAPIC and
-** calculate the size based on the size of I/O sapic entries.
-**
-** The PCI interrupt routing table entry format is derived from the
-** IA64 SAL Specification 2.4.   The PCI interrupt routing table defines
-** the routing of PCI interrupt signals between the PCI device output
-** "pins" and the IO SAPICs' input "lines" (including core I/O PCI
-** devices).  This table does NOT include information for devices/slots
-** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
-** for the architected method of routing of IRQ's behind PPB's.
-*/
+/**
+ * iosapic_load_irt - Fill in the interrupt routing table
+ * @cell_num: The cell number of the CPU we're currently executing on
+ * @irt: The address to place the new IRT at
+ * @return The number of entries found
+ *
+ * The "Get PCI INT Routing Table Size" option returns the number of 
+ * entries in the PCI interrupt routing table for the cell specified 
+ * in the cell_number argument.  The cell number must be for a cell 
+ * within the caller's protection domain.
+ *
+ * The "Get PCI INT Routing Table" option returns, for the cell 
+ * specified in the cell_number argument, the PCI interrupt routing 
+ * table in the caller allocated memory pointed to by mem_addr.
+ * We assume the IRT only contains entries for I/O SAPIC and
+ * calculate the size based on the size of I/O sapic entries.
+ *
+ * The PCI interrupt routing table entry format is derived from the
+ * IA64 SAL Specification 2.4.   The PCI interrupt routing table defines
+ * the routing of PCI interrupt signals between the PCI device output
+ * "pins" and the IO SAPICs' input "lines" (including core I/O PCI
+ * devices).  This table does NOT include information for devices/slots
+ * behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
+ * for the architected method of routing of IRQ's behind PPB's.
+ */
 
 
-static int __init /* return number of entries as success/fail flag */
+static int __init
 iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
 {
 	long status;              /* PDC return value status */
 	struct irt_entry *table;  /* start of interrupt routing tbl */
 	unsigned long num_entries = 0UL;
 
-	ASSERT(NULL != irt);
+	BUG_ON(!irt);
 
 	if (is_pdc_pat()) {
-
 		/* 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);
 
-		ASSERT(status == PDC_OK);
-
-		/* save the number of entries in the table */
-		ASSERT(0UL != num_entries);
+		BUG_ON(status != PDC_OK);
+		BUG_ON(num_entries == 0);
 
 		/*
 		** allocate memory for interrupt routing table
@@ -318,45 +299,47 @@ iosapic_load_irt(unsigned long cell_num,
 		** the contents of the table are exclusively
 		** for I/O sapic devices.
 		*/
-		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
+		table = iosapic_alloc_irt(num_entries);
 		if (table == NULL) {
-			printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+			printk(KERN_WARNING MODULE_NAME ": read_irt : can "
+					"not alloc mem for IRT\n");
 			return 0;
 		}
 
 		/* get PCI INT routing table */
 		status = pdc_pat_get_irt(table, cell_num);
 		DBG("pdc_pat_get_irt: %ld\n", status);
-		ASSERT(status == PDC_OK);
+		WARN_ON(status != PDC_OK);
 	} else {
 		/*
 		** 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)
+		if (irt_cell)
 			return 0;
 
 		/* 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_OK != status) {
+		if (status != PDC_OK) {
 			/* Not a "legacy" system with I/O SAPIC either */
 			return 0;
 		}
 
-		ASSERT(0UL != num_entries);
+		BUG_ON(num_entries == 0);
 
-		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
-		if (table == NULL) {
-			printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+		table = iosapic_alloc_irt(num_entries);
+		if (!table) {
+			printk(KERN_WARNING MODULE_NAME ": read_irt : can "
+					"not alloc mem for IRT\n");
 			return 0;
 		}
 
 		/* HPA ignored by this call too. */
 		status = pdc_pci_irt(num_entries, 0, table);
-		ASSERT(PDC_OK == status);
+		BUG_ON(status != PDC_OK);
 	}
 
 	/* return interrupt table address */
@@ -390,16 +373,10 @@ iosapic_load_irt(unsigned long cell_num,
 
 
 
-void __init
-iosapic_init(void)
+void __init iosapic_init(void)
 {
 	unsigned long cell = 0;
 
-	/* init global data */
-	spin_lock_init(&iosapic_lock);
-        iosapic_list = (struct iosapic_info *) NULL;
-	iosapic_count = 0;
-
 	DBG("iosapic_init()\n");
 
 #ifdef __LP64__
@@ -414,11 +391,9 @@ iosapic_init(void)
 	}
 #endif
 
-	/*
-	**  get IRT for this cell.
-	*/
-	irt_num_entry =  iosapic_load_irt(cell, &irt_cell);
-	if (0 == irt_num_entry)
+	/* get interrupt routing table for this cell */
+	irt_num_entry = iosapic_load_irt(cell, &irt_cell);
+	if (irt_num_entry == 0)
 		irt_cell = NULL;	/* old PDC w/o iosapic */
 }
 
@@ -459,10 +434,7 @@ irt_find_irqline(struct iosapic_info *is
 			continue;
 		}
 
-		/*
-		** Compare: dest_iosapic_addr, src_bus_irq_devno
-		*/
-		if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))
+		if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa))
 			continue;
 
 		if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)
@@ -506,10 +478,10 @@ iosapic_xlate_pin(struct iosapic_info *i
 
 	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(%s) SLOT %d pin %d\n",
+		pcidev->slot_name, PCI_SLOT(pcidev->devfn), intr_pin);
 
-	if (0 == intr_pin) {
+	if (intr_pin == 0) {
 		/* The device does NOT support/use IRQ lines.  */
 		return NULL;
 	}
@@ -606,7 +578,6 @@ iosapic_set_irt_data( struct vector_info
 {
 	u32 mode = 0;
 	struct irt_entry *p = vi->irte;
-	ASSERT(NULL != vi->irte);
 
 	if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
 		mode |= IOSAPIC_IRDT_PO_LOW;
@@ -619,7 +590,6 @@ iosapic_set_irt_data( struct vector_info
 	** PA doesn't support EXTINT or LPRIO bits.
 	*/
 
-	ASSERT(vi->txn_data);
 	*dp0 = mode | (u32) vi->txn_data;
 
 	/*
@@ -802,22 +772,23 @@ int iosapic_fixup_irq(void *isi_obj, str
 
 	vi->irte = irte;
 
-	/* Allocate processor IRQ */
-	vi->txn_irq = txn_alloc_irq();
-
 	/*
+	 * Allocate processor IRQ
+	 *
 	 * XXX/FIXME The txn_alloc_irq() code and related code should be
 	 * moved to enable_irq(). That way we only allocate processor IRQ
 	 * bits for devices that actually have drivers claiming them.
 	 * Right now we assign an IRQ to every PCI device present,
 	 * regardless of whether it's used or not.
 	 */
+	vi->txn_irq = txn_alloc_irq(8);
+
 	if (vi->txn_irq < 0)
 		panic("I/O sapic: couldn't get TXN IRQ\n");
 
 	/* enable_irq() will use txn_* to program IRdT */
 	vi->txn_addr = txn_alloc_addr(vi->txn_irq);
-	vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
+	vi->txn_data = txn_alloc_data(vi->txn_irq);
 
 	vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
 	vi->eoi_data = cpu_to_le32(vi->txn_data);
@@ -841,10 +812,7 @@ int iosapic_fixup_irq(void *isi_obj, str
 static unsigned int
 iosapic_rd_version(struct iosapic_info *isi)
 {
-	ASSERT(isi);
-	ASSERT(isi->isi_hpa);
-
-	return iosapic_read(isi->isi_hpa, IOSAPIC_REG_VERSION);
+	return iosapic_read(isi->addr, IOSAPIC_REG_VERSION);
 }
 
 
@@ -866,44 +834,38 @@ void *iosapic_register(unsigned long hpa
 	int cnt;	/* track how many entries we've looked at */
 
 	/*
-	** Astro based platforms can't support PCI OLARD if they
-	** implement the legacy PDC (not PAT). Though Legacy PDC
-	** supports an IRT, LBA's with no device under them
-	** are *not* listed in the IRT.
-	** Search the IRT and ignore iosapic's which aren't
-	** in the IRT.
-	*/
-	ASSERT(NULL != irte);	/* always have built-in devices */
+	 * Astro based platforms can only support PCI OLARD if they implement
+	 * PAT PDC.  Legacy PDC omits LBAs with no PCI devices from the IRT.
+	 * Search the IRT and ignore iosapic's which aren't in the IRT.
+	 */
 	for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
-		ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type);
-		/*
-		** We need sign extension of the hpa on 32-bit kernels.
-		** The address in the IRT is *always* 64 bit and really
-		** is an unsigned quantity (like all physical addresses).
-		*/ 
-		if (irte->dest_iosapic_addr == (s64) ((long) hpa))
+		WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type);
+		if (COMPARE_IRTE_ADDR(irte, hpa))
 			break;
 	}
 
-	if (cnt  >= irt_num_entry)
-		return (NULL);
+	if (cnt >= irt_num_entry) {
+		DBG("iosapic_register() ignoring 0x%lx (NOT FOUND)\n", hpa);
+		return NULL;
+	}
 
-	if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) {
+	isi = (struct iosapic_info *)kmalloc(sizeof(struct iosapic_info), GFP_KERNEL);
+	if (!isi) {
 		BUG();
-		return (NULL);
+		return NULL;
 	}
 
 	memset(isi, 0, sizeof(struct iosapic_info));
 
-	isi->isi_hpa         = hpa;
-	isi->isi_version     = iosapic_rd_version(isi);
+	isi->addr = ioremap(hpa, 4096);
+	isi->isi_hpa = hpa;
+	isi->isi_version = iosapic_rd_version(isi);
 	isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
 
-	vip = isi->isi_vector =
-		 IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors);
-
+	vip = isi->isi_vector = (struct vector_info *)
+		kmalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
 	if (vip == NULL) {
-		IOSAPIC_FREE(isi, struct iosapic_info, 1);
+		kfree(isi);
 		return NULL;
 	}
 
@@ -924,7 +886,6 @@ iosapic_prt_irt(void *irt, long num_entr
 {
 	unsigned int i, *irp = (unsigned int *) irt;
 
-	ASSERT(NULL != irt);
 
 	printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry);
 
@@ -938,8 +899,6 @@ iosapic_prt_irt(void *irt, long num_entr
 static void
 iosapic_prt_vi(struct vector_info *vi)
 {
-	ASSERT(NULL != vi);
-
 	printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
 	printk(KERN_DEBUG "\t\tstatus:	 %.4x\n", vi->status);
 	printk(KERN_DEBUG "\t\ttxn_irq:  %d\n",  vi->txn_irq);
@@ -953,10 +912,9 @@ iosapic_prt_vi(struct vector_info *vi)
 static void
 iosapic_prt_isi(struct iosapic_info *isi)
 {
-	ASSERT(NULL != isi);
 	printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
 	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_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 --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -139,7 +139,7 @@ void __init lasi_led_init(unsigned long 
 		break;
 	}
 
-	register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, (char *)datareg);
+	register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, datareg);
 }
 #endif
 
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -51,11 +51,6 @@
 #include <asm/iosapic.h>	/* for iosapic_register() */
 #include <asm/io.h>		/* read/write stuff */
 
-#ifndef TRUE
-#define TRUE (1 == 1)
-#define FALSE (1 == 0)
-#endif
-
 #undef DEBUG_LBA	/* general stuff */
 #undef DEBUG_LBA_PORT	/* debug I/O Port access */
 #undef DEBUG_LBA_CFG	/* debug Config Space Access (ie PCI Bus walk) */
@@ -88,18 +83,6 @@
 #define DBG_PAT(x...)
 #endif
 
-#ifdef DEBUG_LBA
-#undef ASSERT
-#define ASSERT(expr) \
-	if(!(expr)) { \
-		printk("\n%s:%d: Assertion " #expr " failed!\n", \
-				__FILE__, __LINE__); \
-		panic(#expr); \
-	}
-#else
-#define ASSERT(expr)
-#endif
-
 
 /*
 ** Config accessor functions only pass in the 8-bit bus number and not
@@ -184,6 +167,7 @@
 
 /* non-postable I/O port space, densely packed */
 #define LBA_PORT_BASE	(PCI_F_EXTEND | 0xfee00000UL)
+static void __iomem *astro_iop_base;
 
 #define ELROY_HVERS	0x782
 #define MERCURY_HVERS	0x783
@@ -214,8 +198,8 @@ struct lba_device {
 	spinlock_t	lba_lock;
 	void		*iosapic_obj;
 
-#ifdef CONFIG_PARISC64
-	unsigned long	iop_base;    /* PA_VIEW - for IO port accessor funcs */
+#ifdef CONFIG_64BIT
+	void __iomem *	iop_base;    /* PA_VIEW - for IO port accessor funcs */
 #endif
 
 	int		flags;       /* state/functionality enabled */
@@ -225,15 +209,9 @@ struct lba_device {
 
 static u32 lba_t32;
 
-/*
-** lba "flags"
-*/
-#define LBA_FLAG_NO_DMA_DURING_CFG	0x01
+/* lba flags */
 #define LBA_FLAG_SKIP_PROBE	0x10
 
-/* Tape Release 4 == hw_rev 5 */
-#define LBA_TR4PLUS(d)      ((d)->hw_rev > 0x4)
-#define LBA_DMA_DURING_CFG_DISABLED(d) ((d)->flags & LBA_FLAG_NO_DMA_DURING_CFG)
 #define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE)
 
 
@@ -293,7 +271,7 @@ lba_dump_res(struct resource *r, int d)
 
 	printk(KERN_DEBUG "(%p)", r->parent);
 	for (i = d; i ; --i) printk(" ");
-	printk(KERN_DEBUG "%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
+	printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, r->start, r->end, r->flags);
 	lba_dump_res(r->child, d+2);
 	lba_dump_res(r->sibling, d);
 }
@@ -303,7 +281,7 @@ lba_dump_res(struct resource *r, int d)
 ** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex
 ** workaround for cfg cycles:
 **	-- preserve  LBA state
-**	-- LBA_FLAG_NO_DMA_DURING_CFG workaround
+**	-- prevent any DMA from occurring
 **	-- turn on smart mode
 **	-- probe with config writes before doing config reads
 **	-- check ERROR_STATUS
@@ -313,25 +291,18 @@ lba_dump_res(struct resource *r, int d)
 ** The workaround is only used for device discovery.
 */
 
-static int
-lba_device_present( u8 bus, u8 dfn, struct lba_device *d)
+static int lba_device_present(u8 bus, u8 dfn, struct lba_device *d)
 {
 	u8 first_bus = d->hba.hba_bus->secondary;
 	u8 last_sub_bus = d->hba.hba_bus->subordinate;
 
-	ASSERT(bus >= first_bus);
-	ASSERT(bus <= last_sub_bus);
-	ASSERT((bus - first_bus) < LBA_MAX_NUM_BUSES);
-
 	if ((bus < first_bus) ||
 	    (bus > last_sub_bus) ||
-	    ((bus - first_bus) >= LBA_MAX_NUM_BUSES))
-	{
-	    /* devices that fall into any of these cases won't get claimed */
-	    return(FALSE);
+	    ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) {
+		return 0;
 	}
 
-	return TRUE;
+	return 1;
 }
 
 
@@ -346,7 +317,6 @@ lba_device_present( u8 bus, u8 dfn, stru
     /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA		\
     ** arbitration for full bus walks.					\
     */									\
-    if (LBA_DMA_DURING_CFG_DISABLED(d)) {				\
 	/* Save contents of arb mask register. */			\
 	arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK);		\
 \
@@ -354,8 +324,7 @@ lba_device_present( u8 bus, u8 dfn, stru
 	 * Turn off all device arbitration bits (i.e. everything	\
 	 * except arbitration enable bit).				\
 	 */								\
-	WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK);			\
-    }									\
+	WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK);		\
 \
     /*									\
      * Set the smart mode bit so that master aborts don't cause		\
@@ -375,7 +344,7 @@ lba_device_present( u8 bus, u8 dfn, stru
      * Read address register to ensure that LBA is the bus master,	\
      * which implies that DMA traffic has stopped when DMA arb is off.	\
      */									\
-    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);		\
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
     /*									\
      * Generate a cfg write cycle (will have no affect on		\
      * Vendor ID register since read-only).				\
@@ -385,7 +354,7 @@ lba_device_present( u8 bus, u8 dfn, stru
      * Make sure write has completed before proceeding further,		\
      * i.e. before setting clear enable.				\
      */									\
-    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);		\
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
 }
 
 
@@ -439,20 +408,16 @@ lba_device_present( u8 bus, u8 dfn, stru
     }									\
 }
 
-#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \
-    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \
-    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR)
+#define LBA_CFG_TR4_ADDR_SETUP(d, addr)					\
+	WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR);
 
-#define LBA_CFG_ADDR_SETUP(d, addr) {				\
+#define LBA_CFG_ADDR_SETUP(d, addr) {					\
     WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
     /*									\
-     * HPREVISIT:							\
-     *       --	Potentially could skip this once DMA bug fixed.		\
-     *									\
      * Read address register to ensure that LBA is the bus master,	\
      * which implies that DMA traffic has stopped when DMA arb is off.	\
      */									\
-    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);		\
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);	\
 }
 
 
@@ -465,12 +430,10 @@ lba_device_present( u8 bus, u8 dfn, stru
      * Restore error config register (turn off smart mode).		\
      */									\
     WRITE_REG32(error_config, base + LBA_ERROR_CONFIG);			\
-    if (LBA_DMA_DURING_CFG_DISABLED(d)) {				\
 	/*								\
 	 * Restore arb mask register (reenables DMA arbitration).	\
 	 */								\
 	WRITE_REG32(arb_mask, base + LBA_ARB_MASK);			\
-    }									\
 }
 
 
@@ -478,39 +441,23 @@ lba_device_present( u8 bus, u8 dfn, stru
 static unsigned int
 lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
 {
-	u32 data = ~0;
+	u32 data = ~0U;
 	int error = 0;
 	u32 arb_mask = 0;	/* used by LBA_CFG_SETUP/RESTORE */
 	u32 error_config = 0;	/* used by LBA_CFG_SETUP/RESTORE */
 	u32 status_control = 0;	/* used by LBA_CFG_SETUP/RESTORE */
 
-	ASSERT((size == sizeof(u8)) ||
-		(size == sizeof(u16)) ||
-		(size == sizeof(u32)));
-
-	if ((size != sizeof(u8)) &&
-		(size != sizeof(u16)) &&
-		(size != sizeof(u32))) {
-		return(data);
-	}
-
 	LBA_CFG_SETUP(d, tok);
 	LBA_CFG_PROBE(d, tok);
 	LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error);
 	if (!error) {
+		void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
+
 		LBA_CFG_ADDR_SETUP(d, tok | reg);
 		switch (size) {
-		case sizeof(u8):
-			data = (u32) READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 3));
-			break;
-		case sizeof(u16):
-			data = (u32) READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 2));
-			break;
-		case sizeof(u32):
-			data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
-			break;
-		default:
-			break; /* leave data as -1 */
+		case 1: data = (u32) READ_REG8(data_reg + (reg & 3)); break;
+		case 2: data = (u32) READ_REG16(data_reg+ (reg & 2)); break;
+		case 4: data = READ_REG32(data_reg); break;
 		}
 	}
 	LBA_CFG_RESTORE(d, d->hba.base_addr);
@@ -518,142 +465,26 @@ lba_rd_cfg(struct lba_device *d, u32 tok
 }
 
 
-#if USE_PAT_PDC_CFG
-
-/* PAT PDC needs to be relocated in order to perform properly.
- * tg3 driver does about 1600 PCI Cfg writes to initialize the card.
- * On 440Mhz A500, PDC takes ~20ms/write, or ~30 seconds per card.
- * On PA8800, that takes about 5ms/write (8 seconds).
- * But relocating PDC will burn at least 4MB of RAM.
- * Easier/Cheaper to just maintain our own mercury cfg ops.
- */
-#define pat_cfg_addr(bus, devfn, addr) (((bus) << 16) | ((devfn) << 8) | (addr))
-
-static int pat_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
-{
-	int tok = pat_cfg_addr(bus->number, devfn, pos);
-	u32 tmp;
-	int ret = pdc_pat_io_pci_cfg_read(tok, size, &tmp);
-
-	DBG_CFG("%s(%d:%d.%d+0x%02x) -> 0x%x %d\n", __FUNCTION__, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), pos, tmp, ret);
-
-	switch (size) {
-		case 1: *data = (u8)  tmp; return (tmp == (u8)  ~0);
-		case 2: *data = (u16) tmp; return (tmp == (u16) ~0);
-		case 4: *data = (u32) tmp; return (tmp == (u32) ~0);
-	}
-	*data = ~0;
-	return (ret);
-}
-
-static int pat_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
-{
-	int tok = pat_cfg_addr(bus->number, devfn, pos);
-	int ret = pdc_pat_io_pci_cfg_write(tok, size, data);
-
-	DBG_CFG("%s(%d:%d.%d+0x%02x, 0x%lx/%d)\n", __FUNCTION__, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), pos, data, size);
-	return (ret);
-}
-
-static struct pci_ops pat_cfg_ops = {
-	.read =		pat_cfg_read,
-	.write =	pat_cfg_write,
-};
-#endif
-
-
-#ifdef CONFIG_PARISC64
-static int mercury_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
+static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
 	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
 	u32 tok = LBA_CFG_TOK(local_bus, devfn);
+	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
 
-	/* Basic Algorithm
-	** Should only get here on fully working LBA rev.
-	** This is how simple the original LBA code should have been.
-	*/
-	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
-	switch(size) {
-	case 1: *(u8 *)  data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA
-							+ (pos & 3));
-		DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos,
-				*(u8 *)data);
-		return(*(u8 *)data == (u8) ~0U);
-	case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA
-							+ (pos & 2));
-		DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos,
-				*(u16 *)data);
-		return(*(u16 *)data == (u16) ~0U);
-	case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
-		DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data);
-		return(*data == ~0U);
-	}
-	DBG_CFG("%s(%x+%2x) -> bad size (%d)\n", __FUNCTION__, tok, pos, size);
-	*data = ~0U;
-	return(!PCIBIOS_SUCCESSFUL);	/* failed */
-}
-
-/*
- * LBA 4.0 config write code implements non-postable semantics
- * by doing a read of CONFIG ADDR after the write.
- */
-
-static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
-{
-	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
-	unsigned long data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
-	u32 tok = LBA_CFG_TOK(local_bus,devfn);
-
- 	ASSERT((tok & 0xff) == 0);
-	ASSERT(pos < 0x100);
-
-	DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __FUNCTION__, tok, pos, data);
-
-	/* Basic Algorithm */
-	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
-	switch(size) {
-	case 1:		WRITE_REG8 (data, data_reg + (pos & 3)); break;
-	case 2:		WRITE_REG16(data, data_reg + (pos & 2)); break;
-	case 4:		WRITE_REG32(data, data_reg);             break;
-	default: 
-		DBG_CFG("%s(%x+%2x) WTF! size %d\n", __FUNCTION__, tok, pos,
-				size);
-	}
-
-	/* flush posted write */
-	lba_t32 = READ_U32(d->hba.base_addr + LBA_PCI_CFG_ADDR);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-
-static struct pci_ops mercury_cfg_ops = {
-	.read =		mercury_cfg_read,
-	.write =	mercury_cfg_write,
-};
-#else
-#define mercury_cfg_ops lba_cfg_ops
-#endif /* CONFIG_PARISC64 */
-
-
-static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
-{
-	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
-	u32 tok = LBA_CFG_TOK(local_bus, devfn);
+	if ((pos > 255) || (devfn > 255))
+		return -EINVAL;
 
 /* FIXME: B2K/C3600 workaround is always use old method... */
-	/* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ {
+	/* if (!LBA_SKIP_PROBE(d)) */ {
 		/* original - Generate config cycle on broken elroy
 		  with risk we will miss PCI bus errors. */
 		*data = lba_rd_cfg(d, tok, pos, size);
 		DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data);
-		return(*data == ~0U);
+		return 0;
 	}
 
-	if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d)))
-	{
+	if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->secondary, devfn, d)) {
 		DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __FUNCTION__, tok, pos);
 		/* either don't want to look or know device isn't present. */
 		*data = ~0U;
@@ -664,52 +495,32 @@ static int lba_cfg_read(struct pci_bus *
 	** Should only get here on fully working LBA rev.
 	** This is how simple the code should have been.
 	*/
-	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+	LBA_CFG_ADDR_SETUP(d, tok | pos);
 	switch(size) {
-	case 1: *(u8 *)  data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3));
-		break;
-	case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2));
-		break;
-	case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
-	   break;
+	case 1: *data = READ_REG8 (data_reg + (pos & 3)); break;
+	case 2: *data = READ_REG16(data_reg + (pos & 2)); break;
+	case 4: *data = READ_REG32(data_reg); break;
 	}
 	DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data);
-	return(*data == ~0U);
+	return 0;
 }
 
 
 static void
-lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
+lba_wr_cfg(struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
 {
 	int error = 0;
 	u32 arb_mask = 0;
 	u32 error_config = 0;
 	u32 status_control = 0;
-
-	ASSERT((size == sizeof(u8)) ||
-		(size == sizeof(u16)) ||
-		(size == sizeof(u32)));
-
-	if ((size != sizeof(u8)) &&
-		(size != sizeof(u16)) &&
-		(size != sizeof(u32))) {
-			return;
-	}
+	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
 
 	LBA_CFG_SETUP(d, tok);
 	LBA_CFG_ADDR_SETUP(d, tok | reg);
 	switch (size) {
-	case sizeof(u8):
-		WRITE_REG8((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA + (reg&3));
-		break;
-	case sizeof(u16):
-		WRITE_REG16((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA +(reg&2));
-		break;
-	case sizeof(u32):
-		WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA);
-		break;
-	default:
-		break;
+	case 1: WRITE_REG8 (data, data_reg + (reg & 3)); break;
+	case 2: WRITE_REG16(data, data_reg + (reg & 2)); break;
+	case 4: WRITE_REG32(data, data_reg);             break;
 	}
 	LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error);
 	LBA_CFG_RESTORE(d, d->hba.base_addr);
@@ -721,16 +532,16 @@ lba_wr_cfg( struct lba_device *d, u32 to
  * by doing a read of CONFIG ADDR after the write.
  */
 
-static int lba_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
+static int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
 	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
 	u32 tok = LBA_CFG_TOK(local_bus,devfn);
 
- 	ASSERT((tok & 0xff) == 0);
-	ASSERT(pos < 0x100);
+	if ((pos > 255) || (devfn > 255))
+		return -EINVAL;
 
-	if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) {
+	if (!LBA_SKIP_PROBE(d)) {
 		/* Original Workaround */
 		lba_wr_cfg(d, tok, pos, (u32) data, size);
 		DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __FUNCTION__, tok, pos,data);
@@ -745,7 +556,7 @@ static int lba_cfg_write(struct pci_bus 
 	DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __FUNCTION__, tok, pos, data);
 
 	/* Basic Algorithm */
-	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+	LBA_CFG_ADDR_SETUP(d, tok | pos);
 	switch(size) {
 	case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3));
 		   break;
@@ -760,9 +571,82 @@ static int lba_cfg_write(struct pci_bus 
 }
 
 
-static struct pci_ops lba_cfg_ops = {
-	.read =		lba_cfg_read,
-	.write =	lba_cfg_write,
+static struct pci_ops elroy_cfg_ops = {
+	.read =		elroy_cfg_read,
+	.write =	elroy_cfg_write,
+};
+
+/*
+ * The mercury_cfg_ops are slightly misnamed; they're also used for Elroy
+ * TR4.0 as no additional bugs were found in this areea between Elroy and
+ * Mercury
+ */
+
+static int mercury_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
+{
+	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 tok = LBA_CFG_TOK(local_bus, devfn);
+	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
+
+	if ((pos > 255) || (devfn > 255))
+		return -EINVAL;
+
+	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+	switch(size) {
+	case 1:
+		*data = READ_REG8(data_reg + (pos & 3));
+		break;
+	case 2:
+		*data = READ_REG16(data_reg + (pos & 2));
+		break;
+	case 4:
+		*data = READ_REG32(data_reg);             break;
+		break;
+	}
+
+	DBG_CFG("mercury_cfg_read(%x+%2x) -> 0x%x\n", tok, pos, *data);
+	return 0;
+}
+
+/*
+ * LBA 4.0 config write code implements non-postable semantics
+ * by doing a read of CONFIG ADDR after the write.
+ */
+
+static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
+{
+	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
+	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 tok = LBA_CFG_TOK(local_bus,devfn);
+
+	if ((pos > 255) || (devfn > 255))
+		return -EINVAL;
+
+	DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __FUNCTION__, tok, pos, data);
+
+	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+	switch(size) {
+	case 1:
+		WRITE_REG8 (data, data_reg + (pos & 3));
+		break;
+	case 2:
+		WRITE_REG16(data, data_reg + (pos & 2));
+		break;
+	case 4:
+		WRITE_REG32(data, data_reg);
+		break;
+	}
+
+	/* flush posted write */
+	lba_t32 = READ_U32(d->hba.base_addr + LBA_PCI_CFG_ADDR);
+	return 0;
+}
+
+static struct pci_ops mercury_cfg_ops = {
+	.read =		mercury_cfg_read,
+	.write =	mercury_cfg_write,
 };
 
 
@@ -773,7 +657,7 @@ lba_bios_init(void)
 }
 
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 
 /*
 ** Determine if a device is already configured.
@@ -802,11 +686,11 @@ lba_claim_dev_resources(struct pci_dev *
 	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
 		if (dev->resource[i].flags & srch_flags) {
 			pci_claim_resource(dev, i);
-			DBG("   claimed %s %d [%lx,%lx]/%x\n",
+			DBG("   claimed %s %d [%lx,%lx]/%lx\n",
 				pci_name(dev), i,
 				dev->resource[i].start,
 				dev->resource[i].end,
-				(int) dev->resource[i].flags
+				dev->resource[i].flags
 				);
 		}
 	}
@@ -835,7 +719,7 @@ lba_fixup_bus(struct pci_bus *bus)
 	struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
 	int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
 
-	DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
+	DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n",
 		bus, bus->secondary, bus->bridge->platform_data);
 
 	/*
@@ -849,14 +733,14 @@ lba_fixup_bus(struct pci_bus *bus)
 		/* Host-PCI Bridge */
 		int err, i;
 
-		DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
+		DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n",
 			ldev->hba.io_space.name,
 			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.io_space.flags);
+		DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n",
 			ldev->hba.lmmio_space.name,
 			ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end,
-			(int) ldev->hba.lmmio_space.flags);
+			ldev->hba.lmmio_space.flags);
 
 		err = request_resource(&ioport_resource, &(ldev->hba.io_space));
 		if (err < 0) {
@@ -895,7 +779,7 @@ lba_fixup_bus(struct pci_bus *bus)
 			/* lba_dump_res(&iomem_resource, 2); */
 		}
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 		/* GMMIO is  distributed range. Every LBA/Rope gets part it. */
 		if (ldev->hba.gmmio_space.flags) {
 			err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space));
@@ -1035,7 +919,7 @@ struct pci_bios_ops lba_bios_ops = {
 static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
 { \
 	u##size t; \
-	t = READ_REG##size(LBA_PORT_BASE + addr); \
+	t = READ_REG##size(astro_iop_base + addr); \
 	DBG_PORT(" 0x%x\n", t); \
 	return (t); \
 }
@@ -1075,9 +959,8 @@ LBA_PORT_IN(32, 0)
 #define LBA_PORT_OUT(size, mask) \
 static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
 { \
-	ASSERT(d != NULL); \
 	DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
-	WRITE_REG##size(val, LBA_PORT_BASE + addr); \
+	WRITE_REG##size(val, astro_iop_base + addr); \
 	if (LBA_DEV(d)->hw_rev < 3) \
 		lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
 }
@@ -1097,7 +980,7 @@ static struct pci_port_ops lba_astro_por
 };
 
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 #define PIOP_TO_GMMIO(lba, addr) \
 	((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))
 
@@ -1215,16 +1098,19 @@ lba_pat_resources(struct parisc_device *
 		case PAT_LMMIO:
 			/* used to fix up pre-initialized MEM BARs */
 			if (!lba_dev->hba.lmmio_space.start) {
-				sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
-					(int) lba_dev->hba.bus_num.start);
-				lba_dev->hba.lmmio_space_offset = p->start - io->start;
-				r = &(lba_dev->hba.lmmio_space);
-				r->name  = lba_dev->hba.lmmio_name;
+				sprintf(lba_dev->hba.lmmio_name,
+						"PCI%02lx LMMIO",
+						lba_dev->hba.bus_num.start);
+				lba_dev->hba.lmmio_space_offset = p->start -
+					io->start;
+				r = &lba_dev->hba.lmmio_space;
+				r->name = lba_dev->hba.lmmio_name;
 			} else if (!lba_dev->hba.elmmio_space.start) {
-				sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
-					(int) lba_dev->hba.bus_num.start);
-				r = &(lba_dev->hba.elmmio_space);
-				r->name  = lba_dev->hba.elmmio_name;
+				sprintf(lba_dev->hba.elmmio_name,
+						"PCI%02lx ELMMIO",
+						lba_dev->hba.bus_num.start);
+				r = &lba_dev->hba.elmmio_space;
+				r->name = lba_dev->hba.elmmio_name;
 			} else {
 				printk(KERN_WARNING MODULE_NAME
 					" only supports 2 LMMIO resources!\n");
@@ -1239,9 +1125,9 @@ lba_pat_resources(struct parisc_device *
 
 		case PAT_GMMIO:
 			/* MMIO space > 4GB phys addr; for 64-bit BAR */
-			sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO",
-					(int) lba_dev->hba.bus_num.start);
-			r = &(lba_dev->hba.gmmio_space);
+			sprintf(lba_dev->hba.gmmio_name, "PCI%02lx GMMIO",
+					lba_dev->hba.bus_num.start);
+			r = &lba_dev->hba.gmmio_space;
 			r->name  = lba_dev->hba.gmmio_name;
 			r->start  = p->start;
 			r->end    = p->end;
@@ -1260,11 +1146,11 @@ lba_pat_resources(struct parisc_device *
 			** Postable I/O port space is per PCI host adapter.
 			** base of 64MB PIOP region
 			*/
-			lba_dev->iop_base = p->start;
+			lba_dev->iop_base = ioremap(p->start, 64 * 1024 * 1024);
 
-			sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
-					(int) lba_dev->hba.bus_num.start);
-			r = &(lba_dev->hba.io_space);
+			sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
+					lba_dev->hba.bus_num.start);
+			r = &lba_dev->hba.io_space;
 			r->name  = lba_dev->hba.io_name;
 			r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);
 			r->end    = r->start + HBA_PORT_SPACE_SIZE - 1;
@@ -1284,7 +1170,7 @@ lba_pat_resources(struct parisc_device *
 /* keep compiler from complaining about missing declarations */
 #define lba_pat_port_ops lba_astro_port_ops
 #define lba_pat_resources(pa_dev, lba_dev)
-#endif	/* CONFIG_PARISC64 */
+#endif	/* CONFIG_64BIT */
 
 
 extern void sba_distributed_lmmio(struct parisc_device *, struct resource *);
@@ -1306,7 +1192,7 @@ lba_legacy_resources(struct parisc_devic
 	** 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(pa_dev->hpa + LBA_FW_SCRATCH);
+	lba_num = READ_REG32(lba_dev->hba.base_addr + LBA_FW_SCRATCH);
 	r = &(lba_dev->hba.bus_num);
 	r->name = "LBA PCI Busses";
 	r->start = lba_num & 0xff;
@@ -1316,8 +1202,8 @@ lba_legacy_resources(struct parisc_devic
 	** Legacy boxes but it's nice to see in /proc/iomem.
 	*/
 	r = &(lba_dev->hba.lmmio_space);
-	sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
-					(int) lba_dev->hba.bus_num.start);
+	sprintf(lba_dev->hba.lmmio_name, "PCI%02lx LMMIO",
+					lba_dev->hba.bus_num.start);
 	r->name  = lba_dev->hba.lmmio_name;
 
 #if 1
@@ -1387,7 +1273,7 @@ lba_legacy_resources(struct parisc_devic
 	 *
 	 * All is well now.
 	 */
-	r->start = (long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE);
+	r->start = READ_REG32(lba_dev->hba.base_addr + LBA_LMMIO_BASE);
 	if (r->start & 1) {
 		unsigned long rsize;
 
@@ -1395,7 +1281,7 @@ lba_legacy_resources(struct parisc_devic
 		/* mmio_mask also clears Enable bit */
 		r->start &= mmio_mask;
 		r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
-		rsize = ~ READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK);
+		rsize = ~ READ_REG32(lba_dev->hba.base_addr + LBA_LMMIO_MASK);
 
 		/*
 		** Each rope only gets part of the distributed range.
@@ -1425,15 +1311,15 @@ lba_legacy_resources(struct parisc_devic
 	** an existing (but unused portion of) distributed range.
 	*/
 	r = &(lba_dev->hba.elmmio_space);
-	sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
-					(int) lba_dev->hba.bus_num.start);
+	sprintf(lba_dev->hba.elmmio_name, "PCI%02lx ELMMIO",
+					lba_dev->hba.bus_num.start);
 	r->name  = lba_dev->hba.elmmio_name;
 
 #if 1
 	/* See comment which precedes call to sba_directed_lmmio() */
 	sba_directed_lmmio(pa_dev, r);
 #else
-	r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);
+	r->start = READ_REG32(lba_dev->hba.base_addr + LBA_ELMMIO_BASE);
 
 	if (r->start & 1) {
 		unsigned long rsize;
@@ -1441,18 +1327,18 @@ lba_legacy_resources(struct parisc_devic
 		/* mmio_mask also clears Enable bit */
 		r->start &= mmio_mask;
 		r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
-		rsize = READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
+		rsize = READ_REG32(lba_dev->hba.base_addr + LBA_ELMMIO_MASK);
 		r->end = r->start + ~rsize;
 	}
 #endif
 
 	r = &(lba_dev->hba.io_space);
-	sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
-					(int) lba_dev->hba.bus_num.start);
+	sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
+					lba_dev->hba.bus_num.start);
 	r->name  = lba_dev->hba.io_name;
 	r->flags = IORESOURCE_IO;
-	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));
+	r->start = READ_REG32(lba_dev->hba.base_addr + LBA_IOS_BASE) & ~1L;
+	r->end   = r->start + (READ_REG32(lba_dev->hba.base_addr + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));
 
 	/* Virtualize the I/O Port space ranges */
 	lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num);
@@ -1501,7 +1387,7 @@ lba_hw_init(struct lba_device *d)
 	printk("\n");
 #endif	/* DEBUG_LBA_PAT */
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 /*
  * FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
  * Only N-Class and up can really make use of Get slot status.
@@ -1558,23 +1444,6 @@ lba_hw_init(struct lba_device *d)
 
 
 
-static void __init
-lba_common_init(struct lba_device *lba_dev)
-{
-	pci_bios = &lba_bios_ops;
-	pcibios_register_hba(HBA_DATA(lba_dev));
-	spin_lock_init(&lba_dev->lba_lock);
-
-	/*
-	** Set flags which depend on hw_rev
-	*/
-	if (!LBA_TR4PLUS(lba_dev)) {
-		lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG;
-	}
-}
-
-
-
 /*
 ** Determine if lba should claim this chip (return 0) or not (return 1).
 ** If so, initialize the chip and tell other partners in crime they
@@ -1585,12 +1454,14 @@ lba_driver_probe(struct parisc_device *d
 {
 	struct lba_device *lba_dev;
 	struct pci_bus *lba_bus;
+	struct pci_ops *cfg_ops;
 	u32 func_class;
 	void *tmp_obj;
 	char *version;
+	void __iomem *addr = ioremap(dev->hpa, 4096);
 
 	/* Read HW Rev First */
-	func_class = READ_REG32(dev->hpa + LBA_FCLASS);
+	func_class = READ_REG32(addr + LBA_FCLASS);
 
 	if (IS_ELROY(dev)) {	
 		func_class &= 0xf;
@@ -1603,24 +1474,40 @@ lba_driver_probe(struct parisc_device *d
 		case 5:	version = "TR4.0"; break;
 		default: version = "TR4+";
 		}
+
 		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) {
+			printk(KERN_WARNING "Can't support LBA older than "
+				"TR2.1 - continuing under adversity.\n");
+		}
+
+#if 0
+/* Elroy TR4.0 should work with simple algorithm.
+   But it doesn't.  Still missing something. *sigh*
+*/
+		if (func_class > 4) {
+			cfg_ops = &mercury_cfg_ops;
+		} else
+#endif
+		{
+			cfg_ops = &elroy_cfg_ops;
+		}
+
 	} else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
 		func_class &= 0xff;
 		version = kmalloc(6, GFP_KERNEL);
 		sprintf(version,"TR%d.%d",(func_class >> 4),(func_class & 0xf));
-		/* We could use one printk for both and have it outside,
+		/* We could use one printk for both Elroy and Mercury,
                  * but for the mask for func_class.
                  */ 
 		printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
 			MODULE_NAME, version, func_class & 0xff, dev->hpa);
-	}
-
-	if (func_class < 2) {
-		printk(KERN_WARNING "Can't support LBA older than TR2.1"
-				" - continuing under adversity.\n");
+		cfg_ops = &mercury_cfg_ops;
+	} else {
+		printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa);
+		return -ENODEV;
 	}
 
 	/*
@@ -1633,8 +1520,7 @@ lba_driver_probe(struct parisc_device *d
 	*/
 	
 	lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
-	if (NULL == lba_dev)
-	{
+	if (!lba_dev) {
 		printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");
 		return(1);
 	}
@@ -1644,19 +1530,16 @@ lba_driver_probe(struct parisc_device *d
 
 	/* ---------- First : initialize data we already have --------- */
 
-	/*
-	** Need hw_rev to adjust configuration space behavior.
-	** LBA_TR4PLUS macro uses hw_rev field.
-	*/
 	lba_dev->hw_rev = func_class;
-
-	lba_dev->hba.base_addr = dev->hpa;  /* faster access */
+	lba_dev->hba.base_addr = addr;
 	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);
+	pci_bios = &lba_bios_ops;
+	pcibios_register_hba(HBA_DATA(lba_dev));
+	spin_lock_init(&lba_dev->lba_lock);
 
 	if (lba_hw_init(lba_dev))
 		return(1);
@@ -1669,8 +1552,11 @@ lba_driver_probe(struct parisc_device *d
 		/* Go ask PDC PAT what resources this LBA has */
 		lba_pat_resources(dev, lba_dev);
 	} else {
-		/* Sprockets PDC uses NPIOP region */
-		pci_port = &lba_astro_port_ops;
+		if (!astro_iop_base) {
+			/* Sprockets PDC uses NPIOP region */
+			astro_iop_base = ioremap(LBA_PORT_BASE, 64 * 1024);
+			pci_port = &lba_astro_port_ops;
+		}
 
 		/* Poke the chip a bit for /proc output */
 		lba_legacy_resources(dev, lba_dev);
@@ -1683,8 +1569,7 @@ lba_driver_probe(struct parisc_device *d
 	dev->dev.platform_data = lba_dev;
 	lba_bus = lba_dev->hba.hba_bus =
 		pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
-				IS_ELROY(dev) ? &lba_cfg_ops : &mercury_cfg_ops,
-				NULL);
+				cfg_ops, NULL);
 
 	/* This is in lieu of calling pci_assign_unassigned_resources() */
 	if (is_pdc_pat()) {
@@ -1711,7 +1596,7 @@ lba_driver_probe(struct parisc_device *d
 	** space is restricted. Avoids master aborts on config cycles.
 	** Early LBA revs go fatal on *any* master abort.
 	*/
-	if (!LBA_TR4PLUS(lba_dev)) {
+	if (cfg_ops == &elroy_cfg_ops) {
 		lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
 	}
 
@@ -1746,18 +1631,19 @@ void __init lba_init(void)
 ** 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_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
+void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
 {
-	unsigned long base_addr = lba->hpa;
+	void __iomem * base_addr = ioremap(lba->hpa, 4096);
 
 	imask <<= 2;	/* adjust for hints - 2 more bits */
 
-	ASSERT((ibase & 0x003fffff) == 0);
-	ASSERT((imask & 0x003fffff) == 0);
+	/* Make sure we aren't trying to set bits that aren't writeable. */
+	WARN_ON((ibase & 0x001fffff) != 0);
+	WARN_ON((imask & 0x001fffff) != 0);
 	
 	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);
+	iounmap(base_addr);
 }
 
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -77,8 +77,8 @@ struct lcd_block {
 struct pdc_chassis_lcd_info_ret_block {
 	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) */
+	unsigned long lcd_cmd_reg_addr;	/* ptr to LCD cmd-register & data ptr for LED */
+	unsigned long lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */
 	unsigned int min_cmd_delay;	/* delay in uS after cmd-write (LCD only) */
 	unsigned char reset_cmd1;	/* command #1 for writing LCD string (LCD only) */
 	unsigned char reset_cmd2;	/* command #2 for writing LCD string (LCD only) */
@@ -102,8 +102,8 @@ lcd_info __attribute__((aligned(8))) =
 {
 	.model =		DISPLAY_MODEL_LCD,
 	.lcd_width =		16,
-	.lcd_cmd_reg_addr =	(char *) KITTYHAWK_LCD_CMD,
-	.lcd_data_reg_addr =	(char *) KITTYHAWK_LCD_DATA,
+	.lcd_cmd_reg_addr =	KITTYHAWK_LCD_CMD,
+	.lcd_data_reg_addr =	KITTYHAWK_LCD_DATA,
 	.min_cmd_delay =	40,
 	.reset_cmd1 =		0x80,
 	.reset_cmd2 =		0xc0,
@@ -540,20 +540,20 @@ static int led_halt(struct notifier_bloc
    ** 
  */
 
-int __init register_led_driver(int model, char *cmd_reg, char *data_reg)
+int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg)
 {
 	static int initialized;
 	
 	if (initialized || !data_reg)
-	    return 1;
+		return 1;
 	
 	lcd_info.model = model;		/* store the values */
-	LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? NULL : cmd_reg;
+	LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? 0 : cmd_reg;
 
 	switch (lcd_info.model) {
 	case DISPLAY_MODEL_LCD:
 		LCD_DATA_REG = data_reg;
-		printk(KERN_INFO "LCD display at %p,%p registered\n", 
+		printk(KERN_INFO "LCD display at %lx,%lx registered\n", 
 			LCD_CMD_REG , LCD_DATA_REG);
 		led_func_ptr = led_LCD_driver;
 		lcd_print( lcd_text_default );
@@ -563,14 +563,14 @@ int __init register_led_driver(int model
 	case DISPLAY_MODEL_LASI:
 		LED_DATA_REG = data_reg;
 		led_func_ptr = led_LASI_driver;
-		printk(KERN_INFO "LED display at %p registered\n", LED_DATA_REG);
+		printk(KERN_INFO "LED display at %lx registered\n", LED_DATA_REG);
 		led_type = LED_NOLCD;
 		break;
 
 	case DISPLAY_MODEL_OLD_ASP:
 		LED_DATA_REG = data_reg;
 		led_func_ptr = led_ASP_driver;
-		printk(KERN_INFO "LED (ASP-style) display at %p registered\n", 
+		printk(KERN_INFO "LED (ASP-style) display at %lx registered\n", 
 		    LED_DATA_REG);
 		led_type = LED_NOLCD;
 		break;
@@ -695,7 +695,8 @@ int __init led_init(void)
 	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) {
+	ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info));
+	if (ret == 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",
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
new file mode 100644
--- /dev/null
+++ b/drivers/parisc/pdc_stable.c
@@ -0,0 +1,735 @@
+/* 
+ *    Interfaces to retrieve and set PDC Stable options (firmware)
+ *
+ *    Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.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 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
+ *
+ *
+ *    DEV NOTE: the PDC Procedures reference states that:
+ *    "A minimum of 96 bytes of Stable Storage is required. Providing more than
+ *    96 bytes of Stable Storage is optional [...]. Failure to provide the
+ *    optional locations from 96 to 192 results in the loss of certain
+ *    functionality during boot."
+ *
+ *    Since locations between 96 and 192 are the various paths, most (if not
+ *    all) PA-RISC machines should have them. Anyway, for safety reasons, the
+ *    following code can deal with only 96 bytes of Stable Storage, and all
+ *    sizes between 96 and 192 bytes (provided they are multiple of struct
+ *    device_path size, eg: 128, 160 and 192) to provide full information.
+ *    The code makes no use of data above 192 bytes. One last word: there's one
+ *    path we can always count on: the primary path.
+ */
+
+#undef PDCS_DEBUG
+#ifdef PDCS_DEBUG
+#define DPRINTK(fmt, args...)	printk(KERN_DEBUG fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>		/* for capable() */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+
+#include <asm/pdc.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+
+#define PDCS_VERSION	"0.09"
+
+#define PDCS_ADDR_PPRI	0x00
+#define PDCS_ADDR_OSID	0x40
+#define PDCS_ADDR_FSIZ	0x5C
+#define PDCS_ADDR_PCON	0x60
+#define PDCS_ADDR_PALT	0x80
+#define PDCS_ADDR_PKBD	0xA0
+
+MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
+MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PDCS_VERSION);
+
+static unsigned long pdcs_size = 0;
+
+/* This struct defines what we need to deal with a parisc pdc path entry */
+struct pdcspath_entry {
+	short ready;			/* entry record is valid if != 0 */
+	unsigned long addr;		/* entry address in stable storage */
+	char *name;			/* entry name */
+	struct device_path devpath;	/* device path in parisc representation */
+	struct device *dev;		/* corresponding device */
+	struct kobject kobj;
+};
+
+struct pdcspath_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct pdcspath_entry *entry, char *buf);
+	ssize_t (*store)(struct pdcspath_entry *entry, const char *buf, size_t count);
+};
+
+#define PDCSPATH_ENTRY(_addr, _name) \
+struct pdcspath_entry pdcspath_entry_##_name = { \
+	.ready = 0, \
+	.addr = _addr, \
+	.name = __stringify(_name), \
+};
+
+#define PDCS_ATTR(_name, _mode, _show, _store) \
+struct subsys_attribute pdcs_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+	.show = _show, \
+	.store = _store, \
+};
+
+#define PATHS_ATTR(_name, _mode, _show, _store) \
+struct pdcspath_attribute paths_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+	.show = _show, \
+	.store = _store, \
+};
+
+#define to_pdcspath_attribute(_attr) container_of(_attr, struct pdcspath_attribute, attr)
+#define to_pdcspath_entry(obj)  container_of(obj, struct pdcspath_entry, kobj)
+
+/**
+ * pdcspath_fetch - This function populates the path entry structs.
+ * @entry: A pointer to an allocated pdcspath_entry.
+ * 
+ * The general idea is that you don't read from the Stable Storage every time
+ * you access the files provided by the facilites. We store a copy of the
+ * content of the stable storage WRT various paths in these structs. We read
+ * these structs when reading the files, and we will write to these structs when
+ * writing to the files, and only then write them back to the Stable Storage.
+ */
+static int
+pdcspath_fetch(struct pdcspath_entry *entry)
+{
+	struct device_path *devpath;
+
+	if (!entry)
+		return -EINVAL;
+
+	devpath = &entry->devpath;
+	
+	DPRINTK("%s: fetch: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
+			entry, devpath, entry->addr);
+
+	/* addr, devpath and count must be word aligned */
+	if (pdc_stable_read(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
+		return -EIO;
+		
+	/* Find the matching device.
+	   NOTE: hardware_path overlays with device_path, so the nice cast can
+	   be used */
+	entry->dev = hwpath_to_device((struct hardware_path *)devpath);
+
+	entry->ready = 1;
+	
+	DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
+	
+	return 0;
+}
+
+/**
+ * pdcspath_store - This function writes a path to stable storage.
+ * @entry: A pointer to an allocated pdcspath_entry.
+ * 
+ * It can be used in two ways: either by passing it a preset devpath struct
+ * containing an already computed hardware path, or by passing it a device
+ * pointer, from which it'll find out the corresponding hardware path.
+ * For now we do not handle the case where there's an error in writing to the
+ * Stable Storage area, so you'd better not mess up the data :P
+ */
+static int
+pdcspath_store(struct pdcspath_entry *entry)
+{
+	struct device_path *devpath;
+
+	if (!entry)
+		return -EINVAL;
+
+	devpath = &entry->devpath;
+	
+	/* We expect the caller to set the ready flag to 0 if the hardware
+	   path struct provided is invalid, so that we know we have to fill it.
+	   First case, we don't have a preset hwpath... */
+	if (!entry->ready) {
+		/* ...but we have a device, map it */
+		if (entry->dev)
+			device_to_hwpath(entry->dev, (struct hardware_path *)devpath);
+		else
+			return -EINVAL;
+	}
+	/* else, we expect the provided hwpath to be valid. */
+	
+	DPRINTK("%s: store: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
+			entry, devpath, entry->addr);
+
+	/* addr, devpath and count must be word aligned */
+	if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK) {
+		printk(KERN_ERR "%s: an error occured when writing to PDC.\n"
+				"It is likely that the Stable Storage data has been corrupted.\n"
+				"Please check it carefully upon next reboot.\n", __func__);
+		return -EIO;
+	}
+		
+	entry->ready = 1;
+	
+	DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
+	
+	return 0;
+}
+
+/**
+ * pdcspath_hwpath_read - This function handles hardware path pretty printing.
+ * @entry: An allocated and populated pdscpath_entry struct.
+ * @buf: The output buffer to write to.
+ * 
+ * We will call this function to format the output of the hwpath attribute file.
+ */
+static ssize_t
+pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
+{
+	char *out = buf;
+	struct device_path *devpath;
+	unsigned short i;
+
+	if (!entry || !buf)
+		return -EINVAL;
+
+	devpath = &entry->devpath;
+
+	if (!entry->ready)
+		return -ENODATA;
+	
+	for (i = 0; i < 6; i++) {
+		if (devpath->bc[i] >= 128)
+			continue;
+		out += sprintf(out, "%u/", (unsigned char)devpath->bc[i]);
+	}
+	out += sprintf(out, "%u\n", (unsigned char)devpath->mod);
+	
+	return out - buf;
+}
+
+/**
+ * pdcspath_hwpath_write - This function handles hardware path modifying.
+ * @entry: An allocated and populated pdscpath_entry struct.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ * 
+ * We will call this function to change the current hardware path.
+ * Hardware paths are to be given '/'-delimited, without brackets.
+ * We take care to make sure that the provided path actually maps to an existing
+ * device, BUT nothing would prevent some foolish user to set the path to some
+ * PCI bridge or even a CPU...
+ * A better work around would be to make sure we are at the end of a device tree
+ * for instance, but it would be IMHO beyond the simple scope of that driver.
+ * The aim is to provide a facility. Data correctness is left to userland.
+ */
+static ssize_t
+pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count)
+{
+	struct hardware_path hwpath;
+	unsigned short i;
+	char in[count+1], *temp;
+	struct device *dev;
+
+	if (!entry || !buf || !count)
+		return -EINVAL;
+
+	/* We'll use a local copy of buf */
+	memset(in, 0, count+1);
+	strncpy(in, buf, count);
+	
+	/* Let's clean up the target. 0xff is a blank pattern */
+	memset(&hwpath, 0xff, sizeof(hwpath));
+	
+	/* First, pick the mod field (the last one of the input string) */
+	if (!(temp = strrchr(in, '/')))
+		return -EINVAL;
+			
+	hwpath.mod = simple_strtoul(temp+1, NULL, 10);
+	in[temp-in] = '\0';	/* truncate the remaining string. just precaution */
+	DPRINTK("%s: mod: %d\n", __func__, hwpath.mod);
+	
+	/* Then, loop for each delimiter, making sure we don't have too many.
+	   we write the bc fields in a down-top way. No matter what, we stop
+	   before writing the last field. If there are too many fields anyway,
+	   then the user is a moron and it'll be caught up later when we'll
+	   check the consistency of the given hwpath. */
+	for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
+		hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
+		in[temp-in] = '\0';
+		DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
+	}
+	
+	/* Store the final field */		
+	hwpath.bc[i] = simple_strtoul(in, NULL, 10);
+	DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
+	
+	/* Now we check that the user isn't trying to lure us */
+	if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
+		printk(KERN_WARNING "%s: attempt to set invalid \"%s\" "
+			"hardware path: %s\n", __func__, entry->name, buf);
+		return -EINVAL;
+	}
+	
+	/* So far so good, let's get in deep */
+	entry->ready = 0;
+	entry->dev = dev;
+	
+	/* Now, dive in. Write back to the hardware */
+	WARN_ON(pdcspath_store(entry));	/* this warn should *NEVER* happen */
+	
+	/* Update the symlink to the real device */
+	sysfs_remove_link(&entry->kobj, "device");
+	sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+	
+	printk(KERN_INFO "PDC Stable Storage: changed \"%s\" path to \"%s\"\n",
+		entry->name, buf);
+	
+	return count;
+}
+
+/**
+ * pdcspath_layer_read - Extended layer (eg. SCSI ids) pretty printing.
+ * @entry: An allocated and populated pdscpath_entry struct.
+ * @buf: The output buffer to write to.
+ * 
+ * We will call this function to format the output of the layer attribute file.
+ */
+static ssize_t
+pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
+{
+	char *out = buf;
+	struct device_path *devpath;
+	unsigned short i;
+
+	if (!entry || !buf)
+		return -EINVAL;
+	
+	devpath = &entry->devpath;
+
+	if (!entry->ready)
+		return -ENODATA;
+	
+	for (i = 0; devpath->layers[i] && (likely(i < 6)); i++)
+		out += sprintf(out, "%u ", devpath->layers[i]);
+
+	out += sprintf(out, "\n");
+	
+	return out - buf;
+}
+
+/**
+ * pdcspath_layer_write - This function handles extended layer modifying.
+ * @entry: An allocated and populated pdscpath_entry struct.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ * 
+ * We will call this function to change the current layer value.
+ * Layers are to be given '.'-delimited, without brackets.
+ * XXX beware we are far less checky WRT input data provided than for hwpath.
+ * Potential harm can be done, since there's no way to check the validity of
+ * the layer fields.
+ */
+static ssize_t
+pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count)
+{
+	unsigned int layers[6]; /* device-specific info (ctlr#, unit#, ...) */
+	unsigned short i;
+	char in[count+1], *temp;
+
+	if (!entry || !buf || !count)
+		return -EINVAL;
+
+	/* We'll use a local copy of buf */
+	memset(in, 0, count+1);
+	strncpy(in, buf, count);
+	
+	/* Let's clean up the target. 0 is a blank pattern */
+	memset(&layers, 0, sizeof(layers));
+	
+	/* First, pick the first layer */
+	if (unlikely(!isdigit(*in)))
+		return -EINVAL;
+	layers[0] = simple_strtoul(in, NULL, 10);
+	DPRINTK("%s: layer[0]: %d\n", __func__, layers[0]);
+	
+	temp = in;
+	for (i=1; ((temp = strchr(temp, '.'))) && (likely(i<6)); i++) {
+		if (unlikely(!isdigit(*(++temp))))
+			return -EINVAL;
+		layers[i] = simple_strtoul(temp, NULL, 10);
+		DPRINTK("%s: layer[%d]: %d\n", __func__, i, layers[i]);
+	}
+		
+	/* So far so good, let's get in deep */
+	
+	/* First, overwrite the current layers with the new ones, not touching
+	   the hardware path. */
+	memcpy(&entry->devpath.layers, &layers, sizeof(layers));
+	
+	/* Now, dive in. Write back to the hardware */
+	WARN_ON(pdcspath_store(entry));	/* this warn should *NEVER* happen */
+	
+	printk(KERN_INFO "PDC Stable Storage: changed \"%s\" layers to \"%s\"\n",
+		entry->name, buf);
+	
+	return count;
+}
+
+/**
+ * pdcspath_attr_show - Generic read function call wrapper.
+ * @kobj: The kobject to get info from.
+ * @attr: The attribute looked upon.
+ * @buf: The output buffer.
+ */
+static ssize_t
+pdcspath_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
+	struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
+	ssize_t ret = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (pdcs_attr->show)
+		ret = pdcs_attr->show(entry, buf);
+
+	return ret;
+}
+
+/**
+ * pdcspath_attr_store - Generic write function call wrapper.
+ * @kobj: The kobject to write info to.
+ * @attr: The attribute to be modified.
+ * @buf: The input buffer.
+ * @count: The size of the buffer.
+ */
+static ssize_t
+pdcspath_attr_store(struct kobject *kobj, struct attribute *attr,
+			const char *buf, size_t count)
+{
+	struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
+	struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
+	ssize_t ret = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (pdcs_attr->store)
+		ret = pdcs_attr->store(entry, buf, count);
+
+	return ret;
+}
+
+static struct sysfs_ops pdcspath_attr_ops = {
+	.show = pdcspath_attr_show,
+	.store = pdcspath_attr_store,
+};
+
+/* These are the two attributes of any PDC path. */
+static PATHS_ATTR(hwpath, 0600, pdcspath_hwpath_read, pdcspath_hwpath_write);
+static PATHS_ATTR(layer, 0600, pdcspath_layer_read, pdcspath_layer_write);
+
+static struct attribute *paths_subsys_attrs[] = {
+	&paths_attr_hwpath.attr,
+	&paths_attr_layer.attr,
+	NULL,
+};
+
+/* Specific kobject type for our PDC paths */
+static struct kobj_type ktype_pdcspath = {
+	.sysfs_ops = &pdcspath_attr_ops,
+	.default_attrs = paths_subsys_attrs,
+};
+
+/* We hard define the 4 types of path we expect to find */
+static PDCSPATH_ENTRY(PDCS_ADDR_PPRI, primary);
+static PDCSPATH_ENTRY(PDCS_ADDR_PCON, console);
+static PDCSPATH_ENTRY(PDCS_ADDR_PALT, alternative);
+static PDCSPATH_ENTRY(PDCS_ADDR_PKBD, keyboard);
+
+/* An array containing all PDC paths we will deal with */
+static struct pdcspath_entry *pdcspath_entries[] = {
+	&pdcspath_entry_primary,
+	&pdcspath_entry_alternative,
+	&pdcspath_entry_console,
+	&pdcspath_entry_keyboard,
+	NULL,
+};
+
+/**
+ * pdcs_info_read - Pretty printing of the remaining useful data.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ * 
+ * We will call this function to format the output of the 'info' attribute file.
+ * Please refer to PDC Procedures documentation, section PDC_STABLE to get a
+ * better insight of what we're doing here.
+ */
+static ssize_t
+pdcs_info_read(struct subsystem *entry, char *buf)
+{
+	char *out = buf;
+	__u32 result;
+	struct device_path devpath;
+	char *tmpstr = NULL;
+	
+	if (!entry || !buf)
+		return -EINVAL;
+		
+	/* show the size of the stable storage */
+	out += sprintf(out, "Stable Storage size: %ld bytes\n", pdcs_size);
+
+	/* deal with flags */
+	if (pdc_stable_read(PDCS_ADDR_PPRI, &devpath, sizeof(devpath)) != PDC_OK)
+		return -EIO;
+	
+	out += sprintf(out, "Autoboot: %s\n", (devpath.flags & PF_AUTOBOOT) ? "On" : "Off");
+	out += sprintf(out, "Autosearch: %s\n", (devpath.flags & PF_AUTOSEARCH) ? "On" : "Off");
+	out += sprintf(out, "Timer: %u s\n", (devpath.flags & PF_TIMER) ? (1 << (devpath.flags & PF_TIMER)) : 0);
+
+	/* get OSID */
+	if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+		return -EIO;
+
+	/* the actual result is 16 bits away */
+	switch (result >> 16) {
+		case 0x0000:	tmpstr = "No OS-dependent data"; break;
+		case 0x0001:	tmpstr = "HP-UX dependent data"; break;
+		case 0x0002:	tmpstr = "MPE-iX dependent data"; break;
+		case 0x0003:	tmpstr = "OSF dependent data"; break;
+		case 0x0004:	tmpstr = "HP-RT dependent data"; break;
+		case 0x0005:	tmpstr = "Novell Netware dependent data"; break;
+		default:	tmpstr = "Unknown"; break;
+	}
+	out += sprintf(out, "OS ID: %s (0x%.4x)\n", tmpstr, (result >> 16));
+
+	/* get fast-size */
+	if (pdc_stable_read(PDCS_ADDR_FSIZ, &result, sizeof(result)) != PDC_OK)
+		return -EIO;
+
+	out += sprintf(out, "Memory tested: ");
+	if ((result & 0x0F) < 0x0E)
+		out += sprintf(out, "%.3f MB", 0.256*(1<<(result & 0x0F)));
+	else
+		out += sprintf(out, "All");
+	out += sprintf(out, "\n");
+	
+	return out - buf;
+}
+
+/**
+ * pdcs_info_write - This function handles boot flag modifying.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ * 
+ * We will call this function to change the current boot flags.
+ * We expect a precise syntax:
+ *	\"n n\" (n == 0 or 1) to toggle respectively AutoBoot and AutoSearch
+ *
+ * As of now there is no incentive on my side to provide more "knobs" to that
+ * interface, since modifying the rest of the data is pretty meaningless when
+ * the machine is running and for the expected use of that facility, such as
+ * PALO setting up the boot disk when installing a Linux distribution...
+ */
+static ssize_t
+pdcs_info_write(struct subsystem *entry, const char *buf, size_t count)
+{
+	struct pdcspath_entry *pathentry;
+	unsigned char flags;
+	char in[count+1], *temp;
+	char c;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (!entry || !buf || !count)
+		return -EINVAL;
+
+	/* We'll use a local copy of buf */
+	memset(in, 0, count+1);
+	strncpy(in, buf, count);
+
+	/* Current flags are stored in primary boot path entry */
+	pathentry = &pdcspath_entry_primary;
+	
+	/* Be nice to the existing flag record */
+	flags = pathentry->devpath.flags;
+	
+	DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
+			
+	temp = in;
+	
+	while (*temp && isspace(*temp))
+		temp++;
+	
+	c = *temp++ - '0';
+	if ((c != 0) && (c != 1))
+		goto parse_error;
+	if (c == 0)
+		flags &= ~PF_AUTOBOOT;
+	else
+		flags |= PF_AUTOBOOT;
+	
+	if (*temp++ != ' ')
+		goto parse_error;
+	
+	c = *temp++ - '0';
+	if ((c != 0) && (c != 1))
+		goto parse_error;
+	if (c == 0)
+		flags &= ~PF_AUTOSEARCH;
+	else
+		flags |= PF_AUTOSEARCH;
+	
+	DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
+		
+	/* So far so good, let's get in deep */
+	
+	/* Change the path entry flags first */
+	pathentry->devpath.flags = flags;
+		
+	/* Now, dive in. Write back to the hardware */
+	WARN_ON(pdcspath_store(pathentry));	/* this warn should *NEVER* happen */
+	
+	printk(KERN_INFO "PDC Stable Storage: changed flags to \"%s\"\n", buf);
+	
+	return count;
+
+parse_error:
+	printk(KERN_WARNING "%s: Parse error: expect \"n n\" (n == 0 or 1) for AB and AS\n", __func__);
+	return -EINVAL;
+}
+
+/* The last attribute (the 'root' one actually) with all remaining data. */
+static PDCS_ATTR(info, 0600, pdcs_info_read, pdcs_info_write);
+
+static struct subsys_attribute *pdcs_subsys_attrs[] = {
+	&pdcs_attr_info,
+	NULL,	/* maybe more in the future? */
+};
+
+static decl_subsys(paths, &ktype_pdcspath, NULL);
+static decl_subsys(pdc, NULL, NULL);
+
+/**
+ * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
+ * 
+ * It creates kobjects corresponding to each path entry with nice sysfs
+ * links to the real device. This is where the magic takes place: when
+ * registering the subsystem attributes during module init, each kobject hereby
+ * created will show in the sysfs tree as a folder containing files as defined
+ * by path_subsys_attr[].
+ */
+static inline int __init
+pdcs_register_pathentries(void)
+{
+	unsigned short i;
+	struct pdcspath_entry *entry;
+	
+	for (i = 0; (entry = pdcspath_entries[i]); i++) {
+		if (pdcspath_fetch(entry) < 0)
+			continue;
+
+		kobject_set_name(&entry->kobj, "%s", entry->name);
+		kobj_set_kset_s(entry, paths_subsys);
+		kobject_register(&entry->kobj);
+
+		if (!entry->dev)
+			continue;
+
+		/* Add a nice symlink to the real device */
+		sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+	}
+	
+	return 0;
+}
+
+/**
+ * pdcs_unregister_pathentries - Routine called when unregistering the module.
+ */
+static inline void __exit
+pdcs_unregister_pathentries(void)
+{
+	unsigned short i;
+	struct pdcspath_entry *entry;
+	
+	for (i = 0; (entry = pdcspath_entries[i]); i++)
+		if (entry->ready)
+			kobject_unregister(&entry->kobj);	
+}
+
+/*
+ * For now we register the pdc subsystem with the firmware subsystem
+ * and the paths subsystem with the pdc subsystem
+ */
+static int __init
+pdc_stable_init(void)
+{
+	struct subsys_attribute *attr;
+	int i, rc = 0, error = 0;
+
+	/* find the size of the stable storage */
+	if (pdc_stable_get_size(&pdcs_size) != PDC_OK) 
+		return -ENODEV;
+
+	printk(KERN_INFO "PDC Stable Storage facility v%s\n", PDCS_VERSION);
+
+	/* For now we'll register the pdc subsys within this driver */
+	if ((rc = firmware_register(&pdc_subsys)))
+		return rc;
+
+	/* Don't forget the info entry */
+	for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
+		if (attr->show)
+			error = subsys_create_file(&pdc_subsys, attr);
+	
+	/* register the paths subsys as a subsystem of pdc subsys */
+	kset_set_kset_s(&paths_subsys, pdc_subsys);
+	subsystem_register(&paths_subsys);
+
+	/* now we create all "files" for the paths subsys */
+	pdcs_register_pathentries();
+	
+	return 0;
+}
+
+static void __exit
+pdc_stable_exit(void)
+{
+	pdcs_unregister_pathentries();
+	subsystem_unregister(&paths_subsys);
+
+	firmware_unregister(&pdc_subsys);
+}
+
+
+module_init(pdc_stable_init);
+module_exit(pdc_stable_exit);
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -47,7 +47,6 @@
 #include <linux/workqueue.h>
 
 #include <asm/pdc.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/led.h>
 #include <asm/uaccess.h>
@@ -126,11 +125,11 @@ static void process_shutdown(void)
 	
 	/* wait until the button was pressed for 1 second */
 	if (shutdown_timer == HZ) {
+#if defined (DEBUG) || defined(CONFIG_CHASSIS_LCD_LED)
 		static char msg[] = "Shutting down...";
+#endif
 		DPRINTK(KERN_INFO "%s\n", msg);
-#ifdef CONFIG_CHASSIS_LCD_LED
 		lcd_print(msg);
-#endif
 		poweroff();
 	}
 }
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -58,7 +58,6 @@ extern struct proc_dir_entry * proc_mcki
 ** Don't even think about messing with it unless you have
 ** plenty of 710's to sacrifice to the computer gods. :^)
 */
-#undef DEBUG_SBA_ASSERT
 #undef DEBUG_SBA_INIT
 #undef DEBUG_SBA_RUN
 #undef DEBUG_SBA_RUN_SG
@@ -92,19 +91,6 @@ extern struct proc_dir_entry * proc_mcki
 #define DBG_RES(x...)
 #endif
 
-#ifdef DEBUG_SBA_ASSERT
-#undef ASSERT
-#define ASSERT(expr) \
-	if(!(expr)) { \
-		printk("\n%s:%d: Assertion " #expr " failed!\n", \
-				__FILE__, __LINE__); \
-		panic(#expr); \
-	}
-#else
-#define ASSERT(expr)
-#endif
-
-
 #if defined(__LP64__) && !defined(CONFIG_PDC_NARROW)
 /* "low end" PA8800 machines use ZX1 chipset */
 #define ZX1_SUPPORT
@@ -125,39 +111,24 @@ extern struct proc_dir_entry * proc_mcki
 #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
-
 #define REO_MERCED_PORT		0x804
-#define REO_ROPES_PORT		0x782
-
 #define REOG_MERCED_PORT	0x805
-#define REOG_ROPES_PORT		0x783
-
 #define PLUTO_MCKINLEY_PORT	0x880
-#define PLUTO_ROPES_PORT	0x784
 
 #define SBA_FUNC_ID	0x0000	/* function id */
 #define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
 
-#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 IS_PLUTO(id) \
-(((id)->hversion == PLUTO_MCKINLEY_PORT) || ((id)->hversion == PLUTO_ROPES_PORT))
+#define IS_ASTRO(id)		((id)->hversion == ASTRO_RUNWAY_PORT)
+#define IS_IKE(id)		((id)->hversion == IKE_MERCED_PORT)
+#define IS_PLUTO(id)		((id)->hversion == PLUTO_MCKINLEY_PORT)
 
 #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)*SBA_FUNC_SIZE)
-
-#define PLUTO_IOC_OFFSET 0x1000
+#define ASTRO_IOC_OFFSET	(32 * SBA_FUNC_SIZE)
+#define PLUTO_IOC_OFFSET	(1 * SBA_FUNC_SIZE)
+/* Ike's IOC's occupy functions 2 and 3 */
+#define IKE_IOC_OFFSET(p)	((p+2) * SBA_FUNC_SIZE)
 
 #define IOC_CTRL          0x8	/* IOC_CTRL offset */
 #define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
@@ -165,6 +136,8 @@ extern struct proc_dir_entry * proc_mcki
 #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 IOC_CTRL_D4       (1 << 11) /* Disable 4-byte coalescing */
+#define IOC_CTRL_DD       (1 << 13) /* Disable distr. LMMIO range coalescing */
 
 #define MAX_IOC		2	/* per Ike. Pluto/Astro only have 1. */
 
@@ -246,9 +219,9 @@ extern struct proc_dir_entry * proc_mcki
 
 
 struct ioc {
-	unsigned long	ioc_hpa;	/* I/O MMU base address */
-	char	*res_map;	/* resource map, bit == pdir entry */
-	u64	*pdir_base;	/* physical base address */
+	void __iomem	*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 - shared w/lba_pci */
 	unsigned long	imask;	/* pdir IOV Space mask - shared w/lba_pci */
 #ifdef ZX1_SUPPORT
@@ -295,7 +268,7 @@ struct sba_device {
 	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 */
+	void __iomem		*sba_hpa; /* base address */
 	spinlock_t		sba_lock;
 	unsigned int		flags;  /* state/functionality enabled */
 	unsigned int		hw_rev;  /* HW revision of chip */
@@ -312,9 +285,6 @@ static struct sba_device *sba_list;
 
 static unsigned long ioc_needs_fdc = 0;
 
-/* Ratio of Host MEM to IOV Space size */
-static unsigned long sba_mem_ratio = 8;
-
 /* global count of IOMMUs in the system */
 static unsigned int global_ioc_cnt = 0;
 
@@ -364,9 +334,9 @@ static int reserve_sba_gart = 1;
  * IO Adapter (aka Bus Converter).
  */
 static void
-sba_dump_ranges(unsigned long hpa)
+sba_dump_ranges(void __iomem *hpa)
 {
-	DBG_INIT("SBA at 0x%lx\n", hpa);
+	DBG_INIT("SBA at 0x%p\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));
@@ -382,10 +352,9 @@ sba_dump_ranges(unsigned long hpa)
  *
  * Print the size/location of the IO MMU PDIR.
  */
-static void
-sba_dump_tlb(unsigned long hpa)
+static void sba_dump_tlb(void __iomem *hpa)
 {
-	DBG_INIT("IO TLB at 0x%lx\n", hpa);
+	DBG_INIT("IO TLB at 0x%p\n", hpa);
 	DBG_INIT("IOC_IBASE    : 0x%Lx\n", READ_REG64(hpa+IOC_IBASE));
 	DBG_INIT("IOC_IMASK    : 0x%Lx\n", READ_REG64(hpa+IOC_IMASK));
 	DBG_INIT("IOC_TCNFG    : 0x%Lx\n", READ_REG64(hpa+IOC_TCNFG));
@@ -547,8 +516,6 @@ sba_search_bitmap(struct ioc *ioc, unsig
 	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) {
@@ -583,8 +550,8 @@ sba_search_bitmap(struct ioc *ioc, unsig
 		while(res_ptr < res_end)
 		{ 
 			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
-			BUG_ON(0 == mask);
-			if(0 == ((*res_ptr) & mask)) {
+			WARN_ON(mask == 0);
+			if(((*res_ptr) & mask) == 0) {
 				*res_ptr |= mask;     /* mark resources busy! */
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
@@ -593,7 +560,7 @@ sba_search_bitmap(struct ioc *ioc, unsig
 			}
 			mask >>= o;
 			bitshiftcnt += o;
-			if (0 == mask) {
+			if (mask == 0) {
 				mask = RESMAP_MASK(bits_wanted);
 				bitshiftcnt=0;
 				res_ptr++;
@@ -631,21 +598,11 @@ sba_alloc_range(struct ioc *ioc, size_t 
 #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...
-	** ggg sacrifices another 710 to the computer gods.
-	*/
-
 	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("%s: I/O MMU @ %lx is out of mapping resources\n",
+			panic("%s: I/O MMU @ %p is out of mapping resources\n",
 			      __FILE__, ioc->ioc_hpa);
 	}
 
@@ -707,11 +664,6 @@ sba_free_range(struct ioc *ioc, dma_addr
 	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;
 }
 
@@ -732,8 +684,9 @@ typedef unsigned long space_t;
 /**
  * sba_io_pdir_entry - fill in one IO PDIR entry
  * @pdir_ptr:  pointer to IO PDIR entry
- * @sid: process Space ID
+ * @sid: process Space ID - currently only support KERNEL_SPACE
  * @vba: Virtual CPU address of buffer to map
+ * @hint: DMA hint set to use for this mapping
  *
  * SBA Mapping Routine
  *
@@ -768,7 +721,6 @@ typedef unsigned long space_t;
  * IOMMU uses little endian for the pdir.
  */
 
-
 void SBA_INLINE
 sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
 		  unsigned long hint)
@@ -776,12 +728,6 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t
 	u64 pa; /* physical address */
 	register unsigned ci; /* coherent index */
 
-	/* 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 &= IOVP_MASK;
 
@@ -830,10 +776,6 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
 	*/
 	int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
 
-	/* 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 (0x80 != (((u8 *) ioc->pdir_base)[off])) {
@@ -843,8 +785,6 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
 
 	if (byte_cnt <= IOVP_SIZE)
 	{
-		ASSERT( off < ioc->pdir_size);
-
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
 		/*
@@ -858,11 +798,7 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
 		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(0x80 == (((u8 *) ioc->pdir_base)[off] & 0x80));
 			/* clear I/O Pdir entry "valid" bit first */
 			((u8 *)(ioc->pdir_base))[off] = 0;
 			off += sizeof(u64);
@@ -880,17 +816,21 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
  *
  * See Documentation/DMA-mapping.txt
  */
-static int
-sba_dma_supported( struct device *dev, u64 mask)
+static int sba_dma_supported( struct device *dev, u64 mask)
 {
+	struct ioc *ioc;
 	if (dev == NULL) {
 		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return(0);
 	}
 
-	/* only support 32-bit PCI devices - no DAC support (yet) */
-	return((int) (mask == 0xffffffffUL));
+	ioc = GET_IOC(dev);
+
+	/* check if mask is > than the largest IO Virt Address */
+
+	return((int) (mask >= (ioc->ibase +
+				(ioc->pdir_size / sizeof(u64) * IOVP_SIZE) )));
 }
 
 
@@ -914,11 +854,7 @@ sba_map_single(struct device *dev, void 
 	u64 *pdir_start;
 	int pide;
 
-	ASSERT(size > 0);
-	ASSERT(size <= DMA_CHUNK_SIZE);
-
 	ioc = GET_IOC(dev);
-	ASSERT(ioc);
 
 	/* save offset bits */
 	offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
@@ -944,7 +880,6 @@ sba_map_single(struct device *dev, void 
 	pdir_start = &(ioc->pdir_base[pide]);
 
 	while (size > 0) {
-		ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
 		sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0);
 
 		DBG_RUN("	pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n",
@@ -992,14 +927,10 @@ sba_unmap_single(struct device *dev, dma
 	unsigned long flags; 
 	dma_addr_t offset;
 
-	ioc = GET_IOC(dev);
-	ASSERT(ioc);
+	DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size);
 
+	ioc = GET_IOC(dev);
 	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);
@@ -1131,7 +1062,6 @@ sba_map_sg(struct device *dev, struct sc
 	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
 
 	ioc = GET_IOC(dev);
-	ASSERT(ioc);
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
@@ -1186,7 +1116,6 @@ sba_map_sg(struct device *dev, struct sc
 
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
-	ASSERT(coalesced == filled);
 	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
 
 	return filled;
@@ -1215,7 +1144,6 @@ sba_unmap_sg(struct device *dev, struct 
 		__FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
-	ASSERT(ioc);
 
 #ifdef SBA_COLLECT_STATS
 	ioc->usg_calls++;
@@ -1394,16 +1322,27 @@ sba_alloc_pdir(unsigned int pdir_size)
 	return (void *) pdir_base;
 }
 
-static void
-sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
+/* setup Mercury or Elroy IBASE/IMASK registers. */
+static void setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
 {
-        /* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */
+        /* lba_set_iregs() is in drivers/parisc/lba_pci.c */
         extern void lba_set_iregs(struct parisc_device *, u32, u32);
+	struct device *dev;
+
+	list_for_each_entry(dev, &sba->dev.children, node) {
+		struct parisc_device *lba = to_parisc_device(dev);
+		int rope_num = (lba->hpa >> 13) & 0xf;
+		if (rope_num >> 3 == ioc_num)
+			lba_set_iregs(lba, ioc->ibase, ioc->imask);
+	}
+}
 
+static void
+sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
+{
 	u32 iova_space_mask;
 	u32 iova_space_size;
 	int iov_order, tcnfg;
-	struct parisc_device *lba;
 #if SBA_AGP_SUPPORT
 	int agp_found = 0;
 #endif
@@ -1449,7 +1388,7 @@ sba_ioc_init_pluto(struct parisc_device 
 		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
 #endif
 
-	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WARN_ON((((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);
 
 	/* build IMASK for IOC and Elroy */
@@ -1461,14 +1400,7 @@ sba_ioc_init_pluto(struct parisc_device 
 #endif
 	sba_dump_tlb(ioc->ioc_hpa);
 
-	/*
-	** setup Mercury IBASE/IMASK registers as well.
-	*/
-	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);
-	}
+	setup_ibase_imask(sba, ioc, ioc_num);
 
 	WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);
 
@@ -1534,13 +1466,8 @@ sba_ioc_init_pluto(struct parisc_device 
 static void
 sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
 {
-	/* 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;
-	int pdir_size, iov_order;
-	unsigned long physmem;
-	struct parisc_device *lba;
+	unsigned int pdir_size, iov_order;
 
 	/*
 	** Determine IOVA Space size from memory size.
@@ -1556,16 +1483,15 @@ sba_ioc_init(struct parisc_device *sba, 
 	** for DMA hints - ergo only 30 bits max.
 	*/
 
-	physmem = num_physpages << PAGE_SHIFT;
-	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));
+	iova_space_size = (u32) (num_physpages/global_ioc_cnt);
 
 	/* limit IOVA space size to 1MB-1GB */
-	if (iova_space_size < 1024*1024) {
-		iova_space_size = 1024*1024;
+	if (iova_space_size < (1 << (20 - PAGE_SHIFT))) {
+		iova_space_size = 1 << (20 - PAGE_SHIFT);
 	}
 #ifdef __LP64__
-	else if (iova_space_size > 512*1024*1024) {
-		iova_space_size = 512*1024*1024;
+	else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) {
+		iova_space_size = 1 << (30 - PAGE_SHIFT);
 	}
 #endif
 
@@ -1574,21 +1500,19 @@ sba_ioc_init(struct parisc_device *sba, 
 	** 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 */
-	ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
-	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
+	iov_order = get_order(iova_space_size << PAGE_SHIFT);
 
-	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+	/* iova_space_size is now bytes, not pages */
+	iova_space_size = 1 << (iov_order + PAGE_SHIFT);
 
-	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));
+	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
 
-	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);
+	DBG_INIT("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n",
+			__FUNCTION__,
+			ioc->ioc_hpa,
+			(unsigned long) num_physpages >> (20 - PAGE_SHIFT),
+			iova_space_size>>20,
+			iov_order + PAGE_SHIFT);
 
 	ioc->pdir_base = sba_alloc_pdir(pdir_size);
 
@@ -1604,7 +1528,6 @@ sba_ioc_init(struct parisc_device *sba, 
 			ioc->hint_shift_pdir, ioc->hint_mask_pdir);
 #endif
 
-	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 */
@@ -1630,14 +1553,7 @@ sba_ioc_init(struct parisc_device *sba, 
 	** can't reprogram them the way drivers want.
 	*/
 
-	/*
-	** setup Elroy IBASE/IMASK registers as well.
-	*/
-	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);
-	}
+	setup_ibase_imask(sba, ioc, ioc_num);
 
 	/*
 	** Program the IOC's ibase and enable IOVA translation
@@ -1672,8 +1588,12 @@ sba_ioc_init(struct parisc_device *sba, 
 **
 **************************************************************************/
 
-static void
-sba_hw_init(struct sba_device *sba_dev)
+static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset)
+{
+	return ioremap(sba_dev->dev->hpa + offset, SBA_FUNC_SIZE);
+}
+
+static void sba_hw_init(struct sba_device *sba_dev)
 { 
 	int i;
 	int num_ioc;
@@ -1682,24 +1602,55 @@ sba_hw_init(struct sba_device *sba_dev)
 	if (!is_pdc_pat()) {
 		/* Shutdown the USB controller on Astro-based workstations.
 		** Once we reprogram the IOMMU, the next DMA performed by
-		** USB will HPMC the box.
+		** USB will HPMC the box. USB is only enabled if a
+		** keyboard is present and found.
+		**
+		** With serial console, j6k v5.0 firmware says:
+		**   mem_kbd hpa 0xfee003f8 sba 0x0 pad 0x0 cl_class 0x7
+		**
+		** FIXME: Using GFX+USB console at power up but direct
+		**	linux to serial console is still broken.
+		**	USB could generate DMA so we must reset USB.
+		**	The proper sequence would be:
+		**	o block console output
+		**	o reset USB device
+		**	o reprogram serial port
+		**	o unblock console output
 		*/
-		pdc_io_reset_devices();
+		if (PAGE0->mem_kbd.cl_class == CL_KEYBD) {
+			pdc_io_reset_devices();
+		}
 
-		/*
-		** XXX May need something more sophisticated to deal
-		**     with DMA from LAN. Maybe use page zero boot device
-		**     as a handle to talk to PDC about which device to
-		**     shutdown. This also needs to work for is_pdc_pat(). 
-		*/
 	}
 
+
+#if 0
+printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
+	PAGE0->mem_boot.spa, PAGE0->mem_boot.pad, PAGE0->mem_boot.cl_class);
+
+	/*
+	** Need to deal with DMA from LAN.
+	**	Maybe use page zero boot device as a handle to talk
+	**	to PDC about which device to shutdown.
+	**
+	** Netbooting, j6k v5.0 firmware says:
+	** 	mem_boot hpa 0xf4008000 sba 0x0 pad 0x0 cl_class 0x1002
+	** ARGH! invalid class.
+	*/
+	if ((PAGE0->mem_boot.cl_class != CL_RANDOM)
+		&& (PAGE0->mem_boot.cl_class != CL_SEQU)) {
+			pdc_io_reset();
+	}
+#endif
+
 	if (!IS_PLUTO(sba_dev->iodc)) {
 		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 |= IOC_CTRL_DD | IOC_CTRL_D4 | IOC_CTRL_TC;
+			/* j6700 v1.6 firmware sets 0x294f */
+			/* A500 firmware sets 0x4d */
 
 		WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
 
@@ -1712,7 +1663,7 @@ sba_hw_init(struct sba_device *sba_dev)
 	if (IS_ASTRO(sba_dev->iodc)) {
 		int err;
 		/* PAT_PDC (L-class) also reports the same goofy base */
-		sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET;
+		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
 		num_ioc = 1;
 
 		sba_dev->chip_resv.name = "Astro Intr Ack";
@@ -1730,32 +1681,32 @@ sba_hw_init(struct sba_device *sba_dev)
                  * corrected when we add it with IKE's IOC offset.
 		 * Doesnt look clean, but fewer code. 
                  */
-		sba_dev->ioc[0].ioc_hpa = -PLUTO_IOC_OFFSET;
+		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
 		num_ioc = 1;
 
 		sba_dev->chip_resv.name = "Pluto Intr/PIOP/VGA";
 		sba_dev->chip_resv.start = PCI_F_EXTEND | 0xfee00000UL;
 		sba_dev->chip_resv.end   = PCI_F_EXTEND | (0xff200000UL - 1);
 		err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
-		BUG_ON(err < 0);
+		WARN_ON(err < 0);
 
 		sba_dev->iommu_resv.name = "IOVA Space";
 		sba_dev->iommu_resv.start = 0x40000000UL;
 		sba_dev->iommu_resv.end   = 0x50000000UL - 1;
 		err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
-		BUG_ON(err < 0);
+		WARN_ON(err < 0);
 	} else {
 		/* IS_IKE (ie N-class, L3000, L1500) */
-		sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;
+		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
+		sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
 		num_ioc = 2;
 
 		/* TODO - LOOKUP Ike/Stretch chipset mem map */
 	}
+	/* XXX: What about Reo? */
 
 	sba_dev->num_ioc = num_ioc;
 	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.
 		*/
@@ -1771,6 +1722,16 @@ sba_hw_init(struct sba_device *sba_dev)
 		/* flush out the writes */
 		READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
 
+		DBG_INIT("	ioc[%d] ROPE_CFG 0x%Lx  ROPE_DBG 0x%Lx\n",
+				i,
+				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40),
+				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50)
+			);
+		DBG_INIT("	STATUS_CONTROL 0x%Lx  FLUSH_CTRL 0x%Lx\n",
+				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108),
+				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
+			);
+
 		if (IS_PLUTO(sba_dev->iodc)) {
 			sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
 		} else {
@@ -1984,16 +1945,6 @@ static struct parisc_device_id sba_tbl[]
 	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
 	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },
 	{ HPHW_IOA, HVERSION_REV_ANY_ID, PLUTO_MCKINLEY_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 },
- */
-/* We shall also comment out Pluto Ropes Port since bus walk doesnt
- * report it yet. 
- *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, PLUTO_ROPES_PORT, 0xc },
- */
 	{ 0, }
 };
 
@@ -2017,18 +1968,19 @@ sba_driver_callback(struct parisc_device
 	u32 func_class;
 	int i;
 	char *version;
+	void __iomem *sba_addr = ioremap(dev->hpa, SBA_FUNC_SIZE);
 
-	sba_dump_ranges(dev->hpa);
+	sba_dump_ranges(sba_addr);
 
 	/* Read HW Rev First */
-	func_class = READ_REG(dev->hpa + SBA_FCLASS);
+	func_class = READ_REG(sba_addr + SBA_FCLASS);
 
 	if (IS_ASTRO(&dev->id)) {
 		unsigned long fclass;
 		static char astro_rev[]="Astro ?.?";
 
 		/* Astro is broken...Read HW Rev First */
-		fclass = READ_REG(dev->hpa);
+		fclass = READ_REG(sba_addr);
 
 		astro_rev[6] = '1' + (char) (fclass & 0x7);
 		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
@@ -2061,12 +2013,12 @@ sba_driver_callback(struct parisc_device
 		MODULE_NAME, version, dev->hpa);
 
 	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
-	if (NULL == sba_dev) {
+	if (!sba_dev) {
 		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
-		return(1);
+		return -ENOMEM;
 	}
 
-	dev->sysdata = (void *) sba_dev;
+	parisc_set_drvdata(dev, sba_dev);
 	memset(sba_dev, 0, sizeof(struct sba_device));
 
 	for(i=0; i<MAX_IOC; i++)
@@ -2076,7 +2028,7 @@ sba_driver_callback(struct parisc_device
 	sba_dev->hw_rev = func_class;
 	sba_dev->iodc = &dev->id;
 	sba_dev->name = dev->name;
-	sba_dev->sba_hpa = dev->hpa;  /* faster access */
+	sba_dev->sba_hpa = sba_addr;
 
 	sba_get_pat_resources(sba_dev);
 	sba_hw_init(sba_dev);
@@ -2100,7 +2052,7 @@ sba_driver_callback(struct parisc_device
 #endif
 	parisc_vmerge_boundary = IOVP_SIZE;
 	parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG;
-
+	parisc_has_iommu();
 	return 0;
 }
 
@@ -2129,7 +2081,7 @@ void * sba_get_iommu(struct parisc_devic
 	char t = sba_dev->id.hw_type;
 	int iocnum = (pci_hba->hw_path >> 3);	/* rope # */
 
-	BUG_ON((t != HPHW_IOA) && (t != HPHW_BCPORT));
+	WARN_ON((t != HPHW_IOA) && (t != HPHW_BCPORT));
 
 	return &(sba->ioc[iocnum]);
 }
@@ -2159,7 +2111,7 @@ void sba_directed_lmmio(struct parisc_de
 	/* Astro has 4 directed ranges. Not sure about Ike/Pluto/et al */
 	for (i=0; i<4; i++) {
 		int base, size;
-		unsigned long reg = sba->sba_hpa + i*0x18;
+		void __iomem *reg = sba->sba_hpa + i*0x18;
 
 		base = READ_REG32(reg + LMMIO_DIRECT0_BASE);
 		if ((base & 1) == 0)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -495,7 +495,7 @@ static struct pci_driver superio_driver 
 
 static int __init superio_modinit(void)
 {
-	return pci_module_init(&superio_driver);
+	return pci_register_driver(&superio_driver);
 }
 
 static void __exit superio_exit(void)
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -25,20 +25,27 @@
 #include "gsc.h"
 
 #define WAX_GSC_IRQ	7	/* Hardcoded Interrupt for GSC */
-#define WAX_GSC_NMI_IRQ	29
 
 static void wax_choose_irq(struct parisc_device *dev, void *ctrl)
 {
 	int irq;
 
 	switch (dev->id.sversion) {
-		case 0x73:	irq =  1; break; /* HIL */
-		case 0x8c:	irq =  6; break; /* RS232 */
-		case 0x90:	irq = 10; break; /* WAX EISA BA */
+		case 0x73:	irq =  1; break; /* i8042 General */
+		case 0x8c:	irq =  6; break; /* Serial */
+		case 0x90:	irq = 10; break; /* EISA */
 		default:	return;		 /* Unknown */
 	}
 
 	gsc_asic_assign_irq(ctrl, irq, &dev->irq);
+
+	switch (dev->id.sversion) {
+		case 0x73:	irq =  2; break; /* i8042 High-priority */
+		case 0x90:	irq =  0; break; /* EISA NMI */
+		default:	return;		 /* No secondary IRQ */
+	}
+
+	gsc_asic_assign_irq(ctrl, irq, &dev->aux_irq);
 }
 
 static void __init
@@ -46,7 +53,7 @@ wax_init_irq(struct gsc_asic *wax)
 {
 	unsigned long base = wax->hpa;
 
-	/* Stop WAX barking for a bit */
+	/* Wax-off */
 	gsc_writel(0x00000000, base+OFFSET_IMR);
 
 	/* clear pending interrupts */
@@ -59,11 +66,6 @@ wax_init_irq(struct gsc_asic *wax)
 	/* 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
@@ -78,7 +80,7 @@ wax_init_chip(struct parisc_device *dev)
 	if (!wax)
 		return -ENOMEM;
 
-	wax->name = "Wax";
+	wax->name = "wax";
 	wax->hpa = dev->hpa;
 
 	wax->version = 0;   /* gsc_readb(wax->hpa+WAX_VER); */
@@ -132,7 +134,7 @@ static struct parisc_device_id wax_tbl[]
 MODULE_DEVICE_TABLE(parisc, wax_tbl);
 
 struct parisc_driver wax_driver = {
-	.name =		"Wax",
+	.name =		"wax",
 	.id_table =	wax_tbl,
 	.probe =	wax_init_chip,
 };
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -34,7 +34,7 @@ config PARPORT
 
 config PARPORT_PC
 	tristate "PC-style hardware"
-	depends on PARPORT && (!SPARC64 || PCI) && (!SPARC32 || BROKEN)
+	depends on PARPORT && (!SPARC64 || PCI) && !SPARC32
 	---help---
 	  You should say Y here if you have a PC-style parallel port. All
 	  IBM PC compatible computers and some Alphas have PC-style
@@ -46,15 +46,9 @@ config PARPORT_PC
 
 	  If unsure, say Y.
 
-config PARPORT_PC_CML1
-	tristate
-	depends on PARPORT!=n && PARPORT_PC!=n
-	default PARPORT_PC if SERIAL_8250=y
-	default m if SERIAL_8250=m
-
 config PARPORT_SERIAL
 	tristate "Multi-IO cards (parallel and serial)"
-	depends on SERIAL_8250!=n && PARPORT_PC_CML1 && PCI
+	depends on SERIAL_8250 && PARPORT_PC && PCI
 	help
 	  This adds support for multi-IO PCI cards that have parallel and
 	  serial ports.  You should say Y or M here.  If you say M, the module
@@ -88,13 +82,18 @@ config PARPORT_PC_PCMCIA
 	  Say Y here if you need PCMCIA support for your PC-style parallel
 	  ports. If unsure, say N.
 
+config PARPORT_NOT_PC
+	bool
+
 config PARPORT_ARC
 	tristate "Archimedes hardware"
 	depends on ARM && PARPORT
+	select PARPORT_NOT_PC
 
 config PARPORT_AMIGA
 	tristate "Amiga builtin port"
 	depends on AMIGA && PARPORT
+	select PARPORT_NOT_PC
 	help
 	  Say Y here if you need support for the parallel port hardware on
 	  Amiga machines. This code is also available as a module (say M),
@@ -103,6 +102,7 @@ config PARPORT_AMIGA
 config PARPORT_MFC3
 	tristate "Multiface III parallel port"
 	depends on ZORRO && PARPORT
+	select PARPORT_NOT_PC
 	help
 	  Say Y here if you need parallel port support for the MFC3 card.
 	  This code is also available as a module (say M), called
@@ -111,6 +111,7 @@ config PARPORT_MFC3
 config PARPORT_ATARI
 	tristate "Atari hardware"
 	depends on ATARI && PARPORT
+	select PARPORT_NOT_PC
 	help
 	  Say Y here if you need support for the parallel port hardware on
 	  Atari machines. This code is also available as a module (say M),
@@ -118,27 +119,18 @@ config PARPORT_ATARI
 
 config PARPORT_GSC
 	tristate
-	depends on GSC
-	default PARPORT
+	default GSC
+	depends on PARPORT
 
 config PARPORT_SUNBPP
 	tristate "Sparc hardware (EXPERIMENTAL)"
-	depends on SBUS && EXPERIMENTAL && PARPORT
+	depends on SBUS && PARPORT && EXPERIMENTAL
+	select PARPORT_NOT_PC
 	help
 	  This driver provides support for the bidirectional parallel port
 	  found on many Sun machines. Note that many of the newer Ultras
 	  actually have pc style hardware instead.
 
-# If exactly one hardware type is selected then parport will optimise away
-# support for loading any others.  Defeat this if the user is keen.
-config PARPORT_OTHER
-	bool "Support foreign hardware"
-	depends on PARPORT
-	help
-	  Say Y here if you want to be able to load driver modules to support
-	  other non-standard types of parallel ports. This causes a
-	  performance loss, so most people say N.
-
 config PARPORT_1284
 	bool "IEEE 1284 transfer modes"
 	depends on PARPORT
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -1,7 +1,7 @@
 /* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
  * IEEE-1284 implementation for parport.
  *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *	    Jose Renau <renau@acm.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
diff --git a/drivers/parport/parport_arc.c b/drivers/parport/parport_arc.c
--- a/drivers/parport/parport_arc.c
+++ b/drivers/parport/parport_arc.c
@@ -1,6 +1,6 @@
 /* Low-level parallel port routines for Archimedes onboard hardware
  *
- * Author: Phil Blundell <Philip.Blundell@pobox.com>
+ * Author: Phil Blundell <philb@gnu.org>
  */
 
 /* This driver is for the parallel port hardware found on Acorn's old
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -12,7 +12,7 @@
  * 
  * based on parport_pc.c by 
  * 	    Grant Guenther <grant@torque.net>
- * 	    Phil Blundell <Philip.Blundell@pobox.com>
+ * 	    Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
@@ -42,7 +42,7 @@
 #include <asm/pdc.h>
 #include <asm/parisc-device.h>
 #include <asm/hardware.h>
-#include <asm/parport_gsc.h>
+#include "parport_gsc.h"
 
 
 MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
@@ -87,95 +87,6 @@ static irqreturn_t parport_gsc_interrupt
 	return IRQ_HANDLED;
 }
 
-void parport_gsc_write_data(struct parport *p, unsigned char d)
-{
-	parport_writeb (d, DATA (p));
-}
-
-unsigned char parport_gsc_read_data(struct parport *p)
-{
-	unsigned char c = parport_readb (DATA (p));
-	return c;
-}
-
-void parport_gsc_write_control(struct parport *p, unsigned char d)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to the newer interface. */
-	if (d & 0x20) {
-		pr_debug("%s (%s): use data_reverse for this!\n",
-			    p->name, p->cad->name);
-		parport_gsc_data_reverse (p);
-	}
-
-	__parport_gsc_frob_control (p, wm, d & wm);
-}
-
-unsigned char parport_gsc_read_control(struct parport *p)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-	const struct parport_gsc_private *priv = p->physport->private_data;
-	return priv->ctr & wm; /* Use soft copy */
-}
-
-unsigned char parport_gsc_frob_control (struct parport *p, unsigned char mask,
-				       unsigned char val)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to the newer interface. */
-	if (mask & 0x20) {
-		pr_debug("%s (%s): use data_%s for this!\n",
-			p->name, p->cad->name,
-			(val & 0x20) ? "reverse" : "forward");
-		if (val & 0x20)
-			parport_gsc_data_reverse (p);
-		else
-			parport_gsc_data_forward (p);
-	}
-
-	/* Restrict mask and val to control lines. */
-	mask &= wm;
-	val &= wm;
-
-	return __parport_gsc_frob_control (p, mask, val);
-}
-
-unsigned char parport_gsc_read_status(struct parport *p)
-{
-	return parport_readb (STATUS (p));
-}
-
-void parport_gsc_disable_irq(struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x10, 0);
-}
-
-void parport_gsc_enable_irq(struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x10, 0x10);
-}
-
-void parport_gsc_data_forward (struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x20, 0);
-}
-
-void parport_gsc_data_reverse (struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x20, 0x20);
-}
-
 void parport_gsc_init_state(struct pardevice *dev, struct parport_state *s)
 {
 	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h
new file mode 100644
--- /dev/null
+++ b/drivers/parport/parport_gsc.h
@@ -0,0 +1,222 @@
+/*
+ *	Low-level parallel-support for PC-style hardware integrated in the
+ *	LASI-Controller (on GSC-Bus) for HP-PARISC Workstations
+ *
+ *	(C) 1999-2001 by 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.
+ *
+ *	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
+ *
+ * based on parport_pc.c by
+ * 	    Grant Guenther <grant@torque.net>
+ * 	    Phil Blundell <Philip.Blundell@pobox.com>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *	    Jose Renau <renau@acm.org>
+ *          David Campbell <campbell@torque.net>
+ *          Andrea Arcangeli
+ */
+
+#ifndef	__DRIVERS_PARPORT_PARPORT_GSC_H
+#define	__DRIVERS_PARPORT_PARPORT_GSC_H
+
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#undef	DEBUG_PARPORT	/* undefine for production */
+#define DELAY_TIME 	0
+
+#if DELAY_TIME == 0
+#define parport_readb	gsc_readb
+#define parport_writeb	gsc_writeb
+#else
+static __inline__ unsigned char parport_readb( unsigned long port )
+{
+    udelay(DELAY_TIME);
+    return gsc_readb(port);
+}
+
+static __inline__ void parport_writeb( unsigned char value, unsigned long port )
+{
+    gsc_writeb(value,port);
+    udelay(DELAY_TIME);
+}
+#endif
+
+/* --- register definitions ------------------------------- */
+
+#define EPPDATA(p)  ((p)->base    + 0x4)
+#define EPPADDR(p)  ((p)->base    + 0x3)
+#define CONTROL(p)  ((p)->base    + 0x2)
+#define STATUS(p)   ((p)->base    + 0x1)
+#define DATA(p)     ((p)->base    + 0x0)
+
+struct parport_gsc_private {
+	/* Contents of CTR. */
+	unsigned char ctr;
+
+	/* Bitmask of writable CTR bits. */
+	unsigned char ctr_writable;
+
+	/* Number of bytes per portword. */
+	int pword;
+
+	/* Not used yet. */
+	int readIntrThreshold;
+	int writeIntrThreshold;
+
+	/* buffer suitable for DMA, if DMA enabled */
+	char *dma_buf;
+	dma_addr_t dma_handle;
+	struct pci_dev *dev;
+};
+
+static inline void parport_gsc_write_data(struct parport *p, unsigned char d)
+{
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG "parport_gsc_write_data(%p,0x%02x)\n", p, d);
+#endif
+	parport_writeb(d, DATA(p));
+}
+
+static inline unsigned char parport_gsc_read_data(struct parport *p)
+{
+	unsigned char val = parport_readb (DATA (p));
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG "parport_gsc_read_data(%p) = 0x%02x\n",
+		p, val);
+#endif
+	return val;
+}
+
+/* __parport_gsc_frob_control differs from parport_gsc_frob_control in that
+ * it doesn't do any extra masking. */
+static inline unsigned char __parport_gsc_frob_control(struct parport *p,
+							unsigned char mask,
+							unsigned char val)
+{
+	struct parport_gsc_private *priv = p->physport->private_data;
+	unsigned char ctr = priv->ctr;
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG
+		"__parport_gsc_frob_control(%02x,%02x): %02x -> %02x\n",
+		mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
+#endif
+	ctr = (ctr & ~mask) ^ val;
+	ctr &= priv->ctr_writable; /* only write writable bits. */
+	parport_writeb (ctr, CONTROL (p));
+	priv->ctr = ctr;	/* Update soft copy */
+	return ctr;
+}
+
+static inline void parport_gsc_data_reverse(struct parport *p)
+{
+	__parport_gsc_frob_control (p, 0x20, 0x20);
+}
+
+static inline void parport_gsc_data_forward(struct parport *p)
+{
+	__parport_gsc_frob_control (p, 0x20, 0x00);
+}
+
+static inline void parport_gsc_write_control(struct parport *p,
+						 unsigned char d)
+{
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to newer interface. */
+	if (d & 0x20) {
+		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+			p->name, p->cad->name);
+		parport_gsc_data_reverse (p);
+	}
+
+	__parport_gsc_frob_control (p, wm, d & wm);
+}
+
+static inline unsigned char parport_gsc_read_control(struct parport *p)
+{
+	const unsigned char rm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+	const struct parport_gsc_private *priv = p->physport->private_data;
+	return priv->ctr & rm; /* Use soft copy */
+}
+
+static inline unsigned char parport_gsc_frob_control(struct parport *p,
+							unsigned char mask,
+							unsigned char val)
+{
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to newer interface. */
+	if (mask & 0x20) {
+		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+			p->name, p->cad->name,
+			(val & 0x20) ? "reverse" : "forward");
+		if (val & 0x20)
+			parport_gsc_data_reverse (p);
+		else
+			parport_gsc_data_forward (p);
+	}
+
+	/* Restrict mask and val to control lines. */
+	mask &= wm;
+	val &= wm;
+
+	return __parport_gsc_frob_control (p, mask, val);
+}
+
+static inline unsigned char parport_gsc_read_status(struct parport *p)
+{
+	return parport_readb (STATUS(p));
+}
+
+static inline void parport_gsc_disable_irq(struct parport *p)
+{
+	__parport_gsc_frob_control (p, 0x10, 0x00);
+}
+
+static inline void parport_gsc_enable_irq(struct parport *p)
+{
+	__parport_gsc_frob_control (p, 0x10, 0x10);
+}
+
+extern void parport_gsc_release_resources(struct parport *p);
+
+extern int parport_gsc_claim_resources(struct parport *p);
+
+extern void parport_gsc_init_state(struct pardevice *, struct parport_state *s);
+
+extern void parport_gsc_save_state(struct parport *p, struct parport_state *s);
+
+extern void parport_gsc_restore_state(struct parport *p, struct parport_state *s);
+
+extern void parport_gsc_inc_use_count(void);
+
+extern void parport_gsc_dec_use_count(void);
+
+extern struct parport *parport_gsc_probe_port(unsigned long base,
+						unsigned long base_hi,
+						int irq, int dma,
+						struct pci_dev *dev);
+
+#endif	/* __DRIVERS_PARPORT_PARPORT_GSC_H */
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1,6 +1,6 @@
 /* Low-level parallel-port routines for 8255-based PC-style hardware.
  * 
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
@@ -67,6 +67,10 @@
 
 #define PARPORT_PC_MAX_PORTS PARPORT_MAX
 
+#ifdef CONFIG_ISA_DMA_API
+#define HAS_DMA
+#endif
+
 /* ECR modes */
 #define ECR_SPP 00
 #define ECR_PS2 01
@@ -610,6 +614,7 @@ dump_parport_state ("leave fifo_write_bl
 	return length - left;
 }
 
+#ifdef HAS_DMA
 static size_t parport_pc_fifo_write_block_dma (struct parport *port,
 					       const void *buf, size_t length)
 {
@@ -732,6 +737,17 @@ dump_parport_state ("enter fifo_write_bl
 dump_parport_state ("leave fifo_write_block_dma", port);
 	return length - left;
 }
+#endif
+
+static inline size_t parport_pc_fifo_write_block(struct parport *port,
+					       const void *buf, size_t length)
+{
+#ifdef HAS_DMA
+	if (port->dma != PARPORT_DMA_NONE)
+		return parport_pc_fifo_write_block_dma (port, buf, length);
+#endif
+	return parport_pc_fifo_write_block_pio (port, buf, length);
+}
 
 /* Parallel Port FIFO mode (ECP chipsets) */
 static size_t parport_pc_compat_write_block_pio (struct parport *port,
@@ -758,10 +774,7 @@ static size_t parport_pc_compat_write_bl
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* Write the data to the FIFO. */
-	if (port->dma != PARPORT_DMA_NONE)
-		written = parport_pc_fifo_write_block_dma (port, buf, length);
-	else
-		written = parport_pc_fifo_write_block_pio (port, buf, length);
+	written = parport_pc_fifo_write_block(port, buf, length);
 
 	/* Finish up. */
 	/* For some hardware we don't want to touch the mode until
@@ -856,10 +869,7 @@ static size_t parport_pc_ecp_write_block
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* Write the data to the FIFO. */
-	if (port->dma != PARPORT_DMA_NONE)
-		written = parport_pc_fifo_write_block_dma (port, buf, length);
-	else
-		written = parport_pc_fifo_write_block_pio (port, buf, length);
+	written = parport_pc_fifo_write_block(port, buf, length);
 
 	/* Finish up. */
 	/* For some hardware we don't want to touch the mode until
@@ -2285,6 +2295,7 @@ struct parport *parport_pc_probe_port (u
 		}
 
 #ifdef CONFIG_PARPORT_PC_FIFO
+#ifdef HAS_DMA
 		if (p->dma != PARPORT_DMA_NONE) {
 			if (request_dma (p->dma, p->name)) {
 				printk (KERN_WARNING "%s: dma %d in use, "
@@ -2306,7 +2317,8 @@ struct parport *parport_pc_probe_port (u
 				}
 			}
 		}
-#endif /* CONFIG_PARPORT_PC_FIFO */
+#endif
+#endif
 	}
 
 	/* Done probing.  Now put the port into a sensible start-up state. */
@@ -2367,11 +2379,13 @@ void parport_pc_unregister_port (struct 
 	if (p->modes & PARPORT_MODE_ECP)
 		release_region(p->base_hi, 3);
 #ifdef CONFIG_PARPORT_PC_FIFO
+#ifdef HAS_DMA
 	if (priv->dma_buf)
 		pci_free_consistent(priv->dev, PAGE_SIZE,
 				    priv->dma_buf,
 				    priv->dma_handle);
-#endif /* CONFIG_PARPORT_PC_FIFO */
+#endif
+#endif
 	kfree (p->private_data);
 	parport_put_port(p);
 	kfree (ops); /* hope no-one cached it */
@@ -2733,13 +2747,11 @@ enum parport_pc_pci_cards {
 	aks_0100,
 	mobility_pp,
 	netmos_9705,
+	netmos_9715,
+	netmos_9755,
 	netmos_9805,
 	netmos_9815,
 	netmos_9855,
-	netmos_9735,
-	netmos_9835,
-	netmos_9755,
-	netmos_9715
 };
 
 
@@ -2810,13 +2822,11 @@ static struct parport_pc_pci {
 	/* aks_0100 */                  { 1, { { 0, -1 }, } },
 	/* mobility_pp */		{ 1, { { 0, 1 }, } },
 	/* netmos_9705 */               { 1, { { 0, -1 }, } }, /* untested */
+        /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
+        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
 	/* netmos_9805 */               { 1, { { 0, -1 }, } }, /* untested */
 	/* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
 	/* netmos_9855 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
-	/* netmos_9735 */               { 1, { { 2, 3 }, } },  /* untested */
-	/* netmos_9835 */               { 1, { { 2, 3 }, } },  /* untested */
-        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
-        /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
 };
 
 static struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2889,28 +2899,30 @@ static struct pci_device_id parport_pc_p
 	/* NetMos communication controllers */
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9805,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
-	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 },
-	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 },
-	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
-	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
 
+struct pci_parport_data {
+	int num;
+	struct parport *ports[2];
+};
+
 static int parport_pc_pci_probe (struct pci_dev *dev,
 					   const struct pci_device_id *id)
 {
 	int err, count, n, i = id->driver_data;
+	struct pci_parport_data *data;
 
 	if (i < last_sio)
 		/* This is an onboard Super-IO and has already been probed */
@@ -2922,9 +2934,15 @@ static int parport_pc_pci_probe (struct 
 	if ((err = pci_enable_device (dev)) != 0)
 		return err;
 
+	data = kmalloc(sizeof(struct pci_parport_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	if (cards[i].preinit_hook &&
-	    cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+	    cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) {
+		kfree(data);
 		return -ENODEV;
+	}
 
 	for (n = 0; n < cards[i].numports; n++) {
 		int lo = cards[i].addr[n].lo;
@@ -2943,21 +2961,48 @@ static int parport_pc_pci_probe (struct 
 			"I/O at %#lx(%#lx)\n",
 			parport_pc_pci_tbl[i + last_sio].vendor,
 			parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi);
-		if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
-					   PARPORT_DMA_NONE, dev))
+		data->ports[count] =
+			parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
+					       PARPORT_DMA_NONE, dev);
+		if (data->ports[count])
 			count++;
 	}
 
+	data->num = count;
+
 	if (cards[i].postinit_hook)
 		cards[i].postinit_hook (dev, count == 0);
 
-	return count == 0 ? -ENODEV : 0;
+	if (count) {
+		pci_set_drvdata(dev, data);
+		return 0;
+	}
+
+	kfree(data);
+
+	return -ENODEV;
+}
+
+static void __devexit parport_pc_pci_remove(struct pci_dev *dev)
+{
+	struct pci_parport_data *data = pci_get_drvdata(dev);
+	int i;
+
+	pci_set_drvdata(dev, NULL);
+
+	if (data) {
+		for (i = data->num - 1; i >= 0; i--)
+			parport_pc_unregister_port(data->ports[i]);
+
+		kfree(data);
+	}
 }
 
 static struct pci_driver parport_pc_pci_driver = {
 	.name		= "parport_pc",
 	.id_table	= parport_pc_pci_tbl,
 	.probe		= parport_pc_pci_probe,
+	.remove		= __devexit_p(parport_pc_pci_remove),
 };
 
 static int __init parport_pc_init_superio (int autoirq, int autodma)
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -33,8 +33,7 @@
 enum parport_pc_pci_cards {
 	titan_110l = 0,
 	titan_210l,
-	netmos_9735,
-	netmos_9835,
+	netmos_9xx5_combo,
 	avlab_1s1p,
 	avlab_1s1p_650,
 	avlab_1s1p_850,
@@ -51,9 +50,8 @@ enum parport_pc_pci_cards {
 	siig_2s1p_20x,
 };
 
-
 /* each element directly indexed from enum list, above */
-static struct parport_pc_pci {
+struct parport_pc_pci {
 	int numports;
 	struct { /* BAR (base address registers) numbers in the config
                     space header */
@@ -65,16 +63,30 @@ static struct parport_pc_pci {
 	/* If set, this is called immediately after pci_enable_device.
 	 * If it returns non-zero, no probing will take place and the
 	 * ports will not be used. */
-	int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
+	int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,
+				int autoirq, int autodma);
 
 	/* If set, this is called after probing for ports.  If 'failed'
 	 * is non-zero we couldn't use any of the ports. */
-	void (*postinit_hook) (struct pci_dev *pdev, int failed);
-} cards[] __devinitdata = {
+	void (*postinit_hook) (struct pci_dev *pdev,
+				struct parport_pc_pci *card, int failed);
+};
+
+static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma)
+{
+	/*
+	 * Netmos uses the subdevice ID to indicate the number of parallel
+	 * and serial ports.  The form is 0x00PS, where <P> is the number of
+	 * parallel ports and <S> is the number of serial ports.
+	 */
+	card->numports = (dev->subsystem_device & 0xf0) >> 4;
+	return 0;
+}
+
+static struct parport_pc_pci cards[] __devinitdata = {
 	/* titan_110l */		{ 1, { { 3, -1 }, } },
 	/* titan_210l */		{ 1, { { 3, -1 }, } },
-	/* netmos_9735 (not tested) */	{ 1, { { 2, -1 }, } },
-	/* netmos_9835 */		{ 1, { { 2, -1 }, } },
+	/* netmos_9xx5_combo */		{ 1, { { 2, -1 }, }, netmos_parallel_init },
 	/* avlab_1s1p     */		{ 1, { { 1, 2}, } },
 	/* avlab_1s1p_650 */		{ 1, { { 1, 2}, } },
 	/* avlab_1s1p_850 */		{ 1, { { 1, 2}, } },
@@ -98,9 +110,17 @@ static struct pci_device_id parport_seri
 	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 },
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
 	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 },
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
 	/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
 	{ 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p},
 	{ 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650},
@@ -167,6 +187,12 @@ static int __devinit siig20x_init_fn(str
 	return pci_siig20x_fn(dev, enable);
 }
 
+static int __devinit netmos_serial_init(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
+{
+	board->num_ports = dev->subsystem_device & 0xf;
+	return 0;
+}
+
 static struct pci_board_no_ids pci_boards[] __devinitdata = {
 	/*
 	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
@@ -180,8 +206,7 @@ static struct pci_board_no_ids pci_board
 
 /* titan_110l */	{ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
 /* titan_210l */	{ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-/* netmos_9735 (n/t)*/	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* netmos_9835 */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* netmos_9xx5_combo */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init },
 /* avlab_1s1p (n/t) */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
 /* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
 /* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
@@ -204,6 +229,7 @@ struct parport_serial_private {
 	struct pci_board_no_ids ser;
 	int num_par;
 	struct parport *port[PARPORT_MAX];
+	struct parport_pc_pci par;
 };
 
 static int __devinit get_pci_port (struct pci_dev *dev,
@@ -271,14 +297,15 @@ static int __devinit get_pci_port (struc
 static int __devinit serial_register (struct pci_dev *dev,
 				      const struct pci_device_id *id)
 {
-	struct pci_board_no_ids *board = &pci_boards[id->driver_data];
+	struct pci_board_no_ids *board;
 	struct parport_serial_private *priv = pci_get_drvdata (dev);
 	struct serial_struct serial_req;
 	int base_baud;
 	int k;
 	int success = 0;
 
-	priv->ser = *board;
+	priv->ser = pci_boards[id->driver_data];
+	board = &priv->ser;
 	if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
 		return 1;
 
@@ -289,6 +316,15 @@ static int __devinit serial_register (st
 
 	for (k = 0; k < board->num_ports; k++) {
 		int line;
+
+		if (priv->num_ser == ARRAY_SIZE (priv->line)) {
+			printk (KERN_WARNING
+				"parport_serial: %s: only %u serial lines "
+				"supported (%d reported)\n", pci_name (dev),
+				ARRAY_SIZE (priv->line), board->num_ports);
+			break;
+		}
+
 		serial_req.irq = dev->irq;
 		if (get_pci_port (dev, board, &serial_req, k))
 			break;
@@ -311,19 +347,31 @@ static int __devinit serial_register (st
 static int __devinit parport_register (struct pci_dev *dev,
 				       const struct pci_device_id *id)
 {
+	struct parport_pc_pci *card;
 	struct parport_serial_private *priv = pci_get_drvdata (dev);
 	int i = id->driver_data, n;
 	int success = 0;
 
-	if (cards[i].preinit_hook &&
-	    cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+	priv->par = cards[id->driver_data];
+	card = &priv->par;
+	if (card->preinit_hook &&
+	    card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
 		return -ENODEV;
 
-	for (n = 0; n < cards[i].numports; n++) {
+	for (n = 0; n < card->numports; n++) {
 		struct parport *port;
-		int lo = cards[i].addr[n].lo;
-		int hi = cards[i].addr[n].hi;
+		int lo = card->addr[n].lo;
+		int hi = card->addr[n].hi;
 		unsigned long io_lo, io_hi;
+
+		if (priv->num_par == ARRAY_SIZE (priv->port)) {
+			printk (KERN_WARNING
+				"parport_serial: %s: only %u parallel ports "
+				"supported (%d reported)\n", pci_name (dev),
+				ARRAY_SIZE (priv->port), card->numports);
+			break;
+		}
+
 		io_lo = pci_resource_start (dev, lo);
 		io_hi = 0;
 		if ((hi >= 0) && (hi <= 6))
@@ -345,8 +393,8 @@ static int __devinit parport_register (s
 		}
 	}
 
-	if (cards[i].postinit_hook)
-		cards[i].postinit_hook (dev, !success);
+	if (card->postinit_hook)
+		card->postinit_hook (dev, card, !success);
 
 	return success ? 0 : 1;
 }
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -4,7 +4,7 @@
  * Author: Derrick J. Brashear <shadow@dementia.org>
  *
  * based on work by:
- *          Phil Blundell <Philip.Blundell@pobox.com>
+ *          Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@tirian.che.curtin.edu.au>
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -2,7 +2,7 @@
  * Parallel port device probing code
  *
  * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
+ *             Philip Blundell <philb@gnu.org>
  */
 
 #include <linux/module.h>
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -3,8 +3,8 @@
 #
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
+	depends on PCI
 	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
-	default n
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
@@ -47,3 +47,13 @@ config PCI_NAMES
 
 	  When in doubt, say Y.
 
+config PCI_DEBUG
+	bool "PCI Debugging"
+	depends on PCI && DEBUG_KERNEL
+	help
+	  Say Y here if you want the PCI core to produce a bunch of debug
+	  messages to the system log.  Select this if you are having a
+	  problem with PCI support and want to see more of what is going on.
+
+	  When in doubt, say N.
+
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -41,6 +41,10 @@ ifndef CONFIG_X86
 obj-y += syscall.o
 endif
 
+ifeq ($(CONFIG_PCI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
 hostprogs-y := gen-devlist
 
 # Dependencies on generated files need to be listed explicitly
diff --git a/drivers/pci/gen-devlist.c b/drivers/pci/gen-devlist.c
--- a/drivers/pci/gen-devlist.c
+++ b/drivers/pci/gen-devlist.c
@@ -7,7 +7,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#define MAX_NAME_SIZE 89
+#define MAX_NAME_SIZE 200
 
 static void
 pq(FILE *f, const char *c, int len)
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -1,15 +1,8 @@
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include "pci.h"
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
 int pci_hotplug (struct device *dev, char **envp, int num_envp,
 		 char *buffer, int buffer_size)
 {
@@ -59,114 +52,17 @@ int pci_hotplug (struct device *dev, cha
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
 
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length,
+			    "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
+			    pdev->vendor, pdev->device,
+			    pdev->subsystem_vendor, pdev->subsystem_device,
+			    (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
+			    (u8)(pdev->class));
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+
 	envp[i] = NULL;
 
 	return 0;
 }
-
-static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
-{
-	struct list_head *ln;
-	struct pci_dev *dev;
-	struct pci_dev_wrapped wrapped_dev;
-	int result = 0;
-
-	DBG("scanning bus %02x\n", wrapped_bus->bus->number);
-
-	if (fn->pre_visit_pci_bus) {
-		result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
-		if (result)
-			return result;
-	}
-
-	ln = wrapped_bus->bus->devices.next; 
-	while (ln != &wrapped_bus->bus->devices) {
-		dev = pci_dev_b(ln);
-		ln = ln->next;
-
-		memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
-		wrapped_dev.dev = dev;
-
-		result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
-		if (result)
-			return result;
-	}
-
-	if (fn->post_visit_pci_bus)
-		result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
-
-	return result;
-}
-
-static int pci_visit_bridge (struct pci_visit * fn,
-			     struct pci_dev_wrapped *wrapped_dev,
-			     struct pci_bus_wrapped *wrapped_parent)
-{
-	struct pci_bus *bus;
-	struct pci_bus_wrapped wrapped_bus;
-	int result = 0;
-
-	DBG("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
-	    PCI_FUNC(wrapped_dev->dev->devfn));
-
-	if (fn->visit_pci_dev) {
-		result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
-		if (result)
-			return result;
-	}
-
-	bus = wrapped_dev->dev->subordinate;
-	if (bus) {
-		memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
-		wrapped_bus.bus = bus;
-
-		result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
-	}
-	return result;
-}
-
-/**
- * pci_visit_dev - scans the pci buses.
- * Every bus and every function is presented to a custom
- * function that can act upon it.
- */
-int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
-		  struct pci_bus_wrapped *wrapped_parent)
-{
-	struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
-	int result = 0;
-
-	if (!dev)
-		return 0;
-
-	if (fn->pre_visit_pci_dev) {
-		result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
-		if (result)
-			return result;
-	}
-
-	switch (dev->class >> 8) {
-		case PCI_CLASS_BRIDGE_PCI:
-			result = pci_visit_bridge(fn, wrapped_dev,
-						  wrapped_parent);
-			if (result)
-				return result;
-			break;
-		default:
-			DBG("scanning device %02x, %02x\n",
-			    PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-			if (fn->visit_pci_dev) {
-				result = fn->visit_pci_dev (wrapped_dev,
-							    wrapped_parent);
-				if (result)
-					return result;
-			}
-	}
-
-	if (fn->post_visit_pci_dev)
-		result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
-
-	return result;
-}
-EXPORT_SYMBOL(pci_visit_dev);
-
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -31,7 +31,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-/* PICMG 2.12 R2.0 HS CSR bits: */
+/* PICMG 2.1 R2.0 HS CSR bits: */
 #define HS_CSR_INS	0x0080
 #define HS_CSR_EXT	0x0040
 #define HS_CSR_PI	0x0030
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -1,7 +1,7 @@
 /*
  * CompactPCI Hot Plug Driver
  *
- * Copyright (C) 2002 SOMA Networks, Inc.
+ * Copyright (C) 2002,2005 SOMA Networks, Inc.
  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2001 IBM Corp.
  *
@@ -33,11 +33,11 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
+#include <asm/atomic.h>
 #include <linux/delay.h>
 #include "pci_hotplug.h"
 #include "cpci_hotplug.h"
 
-#define DRIVER_VERSION	"0.2"
 #define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
 #define DRIVER_DESC	"CompactPCI Hot Plug Core"
 
@@ -45,18 +45,19 @@
 
 #define dbg(format, arg...)					\
 	do {							\
-		if(cpci_debug)					\
+		if (cpci_debug)					\
 			printk (KERN_DEBUG "%s: " format "\n",	\
 				MY_NAME , ## arg); 		\
-	} while(0)
+	} 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)
 
 /* local variables */
-static spinlock_t list_lock;
+static DECLARE_RWSEM(list_rwsem);
 static LIST_HEAD(slot_list);
 static int slots;
+static atomic_t extracting;
 int cpci_debug;
 static struct cpci_hp_controller *controller;
 static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
@@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_s
 static int set_attention_status(struct hotplug_slot *slot, u8 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_adapter_status(struct hotplug_slot *slot, u8 * value);
+static int get_latch_status(struct hotplug_slot *slot, u8 * value);
 
 static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
 	.owner = THIS_MODULE,
@@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotp
 	.set_attention_status = set_attention_status,
 	.get_power_status = get_power_status,
 	.get_attention_status = get_attention_status,
+	.get_adapter_status = get_adapter_status,
+	.get_latch_status = get_latch_status,
 };
 
 static int
@@ -106,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug
 
 	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	if(controller->ops->set_power) {
+	if (controller->ops->set_power)
 		retval = controller->ops->set_power(slot, 1);
-	}
-
 	return retval;
 }
 
@@ -121,35 +124,41 @@ disable_slot(struct hotplug_slot *hotplu
 
 	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
+	down_write(&list_rwsem);
+
 	/* Unconfigure device */
 	dbg("%s - unconfiguring slot %s",
 	    __FUNCTION__, slot->hotplug_slot->name);
-	if((retval = cpci_unconfigure_slot(slot))) {
+	if ((retval = cpci_unconfigure_slot(slot))) {
 		err("%s - could not unconfigure slot %s",
 		    __FUNCTION__, slot->hotplug_slot->name);
-		return retval;
+		goto disable_error;
 	}
 	dbg("%s - finished unconfiguring slot %s",
 	    __FUNCTION__, slot->hotplug_slot->name);
 
 	/* Clear EXT (by setting it) */
-	if(cpci_clear_ext(slot)) {
+	if (cpci_clear_ext(slot)) {
 		err("%s - could not clear EXT for slot %s",
 		    __FUNCTION__, slot->hotplug_slot->name);
 		retval = -ENODEV;
+		goto disable_error;
 	}
 	cpci_led_on(slot);
 
-	if(controller->ops->set_power) {
-		retval = controller->ops->set_power(slot, 0);
-	}
+	if (controller->ops->set_power)
+		if ((retval = controller->ops->set_power(slot, 0)))
+			goto disable_error;
 
-	if(update_adapter_status(slot->hotplug_slot, 0)) {
+	if (update_adapter_status(slot->hotplug_slot, 0))
 		warn("failure to update adapter file");
-	}
-
-	slot->extracting = 0;
 
+	if (slot->extracting) {
+		slot->extracting = 0;
+		atomic_dec(&extracting);
+	}
+disable_error:
+	up_write(&list_rwsem);
 	return retval;
 }
 
@@ -158,9 +167,8 @@ cpci_get_power_status(struct slot *slot)
 {
 	u8 power = 1;
 
-	if(controller->ops->get_power) {
+	if (controller->ops->get_power)
 		power = controller->ops->get_power(slot);
-	}
 	return power;
 }
 
@@ -188,6 +196,20 @@ set_attention_status(struct hotplug_slot
 	return cpci_set_attention_status(hotplug_slot->private, status);
 }
 
+static int
+get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	*value = hotplug_slot->info->adapter_status;
+	return 0;
+}
+
+static int
+get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	*value = hotplug_slot->info->latch_status;
+	return 0;
+}
+
 static void release_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = hotplug_slot->private;
@@ -195,6 +217,8 @@ static void release_slot(struct hotplug_
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
+	if (slot->dev)
+		pci_dev_put(slot->dev);
 	kfree(slot);
 }
 
@@ -216,9 +240,8 @@ cpci_hp_register_bus(struct pci_bus *bus
 	int status = -ENOMEM;
 	int i;
 
-	if(!(controller && bus)) {
+	if (!(controller && bus))
 		return -ENODEV;
-	}
 
 	/*
 	 * Create a structure for each slot, and register that slot
@@ -273,10 +296,10 @@ cpci_hp_register_bus(struct pci_bus *bus
 		}
 
 		/* Add slot to our internal list */
-		spin_lock(&list_lock);
+		down_write(&list_rwsem);
 		list_add(&slot->slot_list, &slot_list);
 		slots++;
-		spin_unlock(&list_lock);
+		up_write(&list_rwsem);
 	}
 	return 0;
 error_name:
@@ -295,32 +318,30 @@ int
 cpci_hp_unregister_bus(struct pci_bus *bus)
 {
 	struct slot *slot;
-	struct list_head *tmp;
-	struct list_head *next;
-	int status;
+	struct slot *tmp;
+	int status = 0;
 
-	spin_lock(&list_lock);
-	if(!slots) {
-		spin_unlock(&list_lock);
+	down_write(&list_rwsem);
+	if (!slots) {
+		up_write(&list_rwsem);
 		return -1;
 	}
-	list_for_each_safe(tmp, next, &slot_list) {
-		slot = list_entry(tmp, struct slot, slot_list);
-		if(slot->bus == bus) {
+	list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
+		if (slot->bus == bus) {
+			list_del(&slot->slot_list);
+			slots--;
+
 			dbg("deregistering slot %s", slot->hotplug_slot->name);
 			status = pci_hp_deregister(slot->hotplug_slot);
-			if(status) {
+			if (status) {
 				err("pci_hp_deregister failed with error %d",
 				    status);
-				return status;
+				break;
 			}
-
-			list_del(&slot->slot_list);
-			slots--;
 		}
 	}
-	spin_unlock(&list_lock);
-	return 0;
+	up_write(&list_rwsem);
+	return status;
 }
 
 /* This is the interrupt mode interrupt handler */
@@ -330,7 +351,7 @@ cpci_hp_intr(int irq, void *data, struct
 	dbg("entered cpci_hp_intr");
 
 	/* Check to see if it was our interrupt */
-	if((controller->irq_flags & SA_SHIRQ) &&
+	if ((controller->irq_flags & SA_SHIRQ) &&
 	    !controller->ops->check_irq(controller->dev_id)) {
 		dbg("exited cpci_hp_intr, not our interrupt");
 		return IRQ_NONE;
@@ -347,46 +368,38 @@ cpci_hp_intr(int irq, void *data, struct
 }
 
 /*
- * According to PICMG 2.12 R2.0, section 6.3.2, upon
+ * According to PICMG 2.1 R2.0, section 6.3.2, upon
  * initialization, the system driver shall clear the
  * INS bits of the cold-inserted devices.
  */
 static int
-init_slots(void)
+init_slots(int clear_ins)
 {
 	struct slot *slot;
-	struct list_head *tmp;
 	struct pci_dev* dev;
 
 	dbg("%s - enter", __FUNCTION__);
-	spin_lock(&list_lock);
-	if(!slots) {
-		spin_unlock(&list_lock);
+	down_read(&list_rwsem);
+	if (!slots) {
+		up_read(&list_rwsem);
 		return -1;
 	}
-	list_for_each(tmp, &slot_list) {
-		slot = list_entry(tmp, struct slot, slot_list);
+	list_for_each_entry(slot, &slot_list, slot_list) {
 		dbg("%s - looking at slot %s",
 		    __FUNCTION__, slot->hotplug_slot->name);
-		if(cpci_check_and_clear_ins(slot)) {
+		if (clear_ins && cpci_check_and_clear_ins(slot))
 			dbg("%s - cleared INS for slot %s",
 			    __FUNCTION__, slot->hotplug_slot->name);
-			dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
-			if(dev) {
-				if(update_adapter_status(slot->hotplug_slot, 1)) {
-					warn("failure to update adapter file");
-				}
-				if(update_latch_status(slot->hotplug_slot, 1)) {
-					warn("failure to update latch file");
-				}
-				slot->dev = dev;
-			} else {
-				err("%s - no driver attached to device in slot %s",
-				    __FUNCTION__, slot->hotplug_slot->name);
-			}
+		dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
+		if (dev) {
+			if (update_adapter_status(slot->hotplug_slot, 1))
+				warn("failure to update adapter file");
+			if (update_latch_status(slot->hotplug_slot, 1))
+				warn("failure to update latch file");
+			slot->dev = dev;
 		}
 	}
-	spin_unlock(&list_lock);
+	up_read(&list_rwsem);
 	dbg("%s - exit", __FUNCTION__);
 	return 0;
 }
@@ -395,27 +408,28 @@ static int
 check_slots(void)
 {
 	struct slot *slot;
-	struct list_head *tmp;
 	int extracted;
 	int inserted;
+	u16 hs_csr;
 
-	spin_lock(&list_lock);
-	if(!slots) {
-		spin_unlock(&list_lock);
+	down_read(&list_rwsem);
+	if (!slots) {
+		up_read(&list_rwsem);
 		err("no slots registered, shutting down");
 		return -1;
 	}
 	extracted = inserted = 0;
-	list_for_each(tmp, &slot_list) {
-		slot = list_entry(tmp, struct slot, slot_list);
+	list_for_each_entry(slot, &slot_list, slot_list) {
 		dbg("%s - looking at slot %s",
 		    __FUNCTION__, slot->hotplug_slot->name);
-		if(cpci_check_and_clear_ins(slot)) {
-			u16 hs_csr;
-
-			/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
-			if(slot->dev) {
-				warn("slot %s already inserted", slot->hotplug_slot->name);
+		if (cpci_check_and_clear_ins(slot)) {
+			/*
+			 * Some broken hardware (e.g. PLX 9054AB) asserts
+			 * ENUM# twice...
+			 */
+			if (slot->dev) {
+				warn("slot %s already inserted",
+				     slot->hotplug_slot->name);
 				inserted++;
 				continue;
 			}
@@ -432,7 +446,7 @@ check_slots(void)
 			/* Configure device */
 			dbg("%s - configuring slot %s",
 			    __FUNCTION__, slot->hotplug_slot->name);
-			if(cpci_configure_slot(slot)) {
+			if (cpci_configure_slot(slot)) {
 				err("%s - could not configure slot %s",
 				    __FUNCTION__, slot->hotplug_slot->name);
 				continue;
@@ -445,13 +459,11 @@ check_slots(void)
 			dbg("%s - slot %s HS_CSR (2) = %04x",
 			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
 
-			if(update_latch_status(slot->hotplug_slot, 1)) {
+			if (update_latch_status(slot->hotplug_slot, 1))
 				warn("failure to update latch file");
-			}
 
-			if(update_adapter_status(slot->hotplug_slot, 1)) {
+			if (update_adapter_status(slot->hotplug_slot, 1))
 				warn("failure to update adapter file");
-			}
 
 			cpci_led_off(slot);
 
@@ -461,9 +473,7 @@ check_slots(void)
 			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
 
 			inserted++;
-		} else if(cpci_check_ext(slot)) {
-			u16 hs_csr;
-
+		} else if (cpci_check_ext(slot)) {
 			/* Process extraction request */
 			dbg("%s - slot %s extracted",
 			    __FUNCTION__, slot->hotplug_slot->name);
@@ -473,23 +483,40 @@ check_slots(void)
 			dbg("%s - slot %s HS_CSR = %04x",
 			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
 
-			if(!slot->extracting) {
-				if(update_latch_status(slot->hotplug_slot, 0)) {
+			if (!slot->extracting) {
+				if (update_latch_status(slot->hotplug_slot, 0)) {
 					warn("failure to update latch file");
 				}
 				slot->extracting = 1;
+				atomic_inc(&extracting);
 			}
 			extracted++;
+		} else if (slot->extracting) {
+			hs_csr = cpci_get_hs_csr(slot);
+			if (hs_csr == 0xffff) {
+				/*
+				 * Hmmm, we're likely hosed at this point, should we
+				 * bother trying to tell the driver or not?
+				 */
+				err("card in slot %s was improperly removed",
+				    slot->hotplug_slot->name);
+				if (update_adapter_status(slot->hotplug_slot, 0))
+					warn("failure to update adapter file");
+				slot->extracting = 0;
+				atomic_dec(&extracting);
+			}
 		}
 	}
-	spin_unlock(&list_lock);
-	if(inserted || extracted) {
+	up_read(&list_rwsem);
+	dbg("inserted=%d, extracted=%d, extracting=%d",
+	    inserted, extracted, atomic_read(&extracting));
+	if (inserted || extracted)
 		return extracted;
-	}
-	else {
+	else if (!atomic_read(&extracting)) {
 		err("cannot find ENUM# source, shutting down");
 		return -1;
 	}
+	return 0;
 }
 
 /* This is the interrupt mode worker thread body */
@@ -497,54 +524,37 @@ static int
 event_thread(void *data)
 {
 	int rc;
-	struct slot *slot;
-	struct list_head *tmp;
 
 	lock_kernel();
 	daemonize("cpci_hp_eventd");
 	unlock_kernel();
 
 	dbg("%s - event thread started", __FUNCTION__);
-	while(1) {
+	while (1) {
 		dbg("event thread sleeping");
 		down_interruptible(&event_semaphore);
 		dbg("event thread woken, thread_finished = %d",
 		    thread_finished);
-		if(thread_finished || signal_pending(current))
+		if (thread_finished || signal_pending(current))
 			break;
-		while(controller->ops->query_enum()) {
+		do {
 			rc = check_slots();
-			if (rc > 0)
+			if (rc > 0) {
 				/* Give userspace a chance to handle extraction */
 				msleep(500);
-			else if (rc < 0) {
+			} else if (rc < 0) {
 				dbg("%s - error checking slots", __FUNCTION__);
 				thread_finished = 1;
 				break;
 			}
-		}
-		/* Check for someone yanking out a board */
-		list_for_each(tmp, &slot_list) {
-			slot = list_entry(tmp, struct slot, slot_list);
-			if(slot->extracting) {
-				/*
-				 * Hmmm, we're likely hosed at this point, should we
-				 * bother trying to tell the driver or not?
-				 */
-				err("card in slot %s was improperly removed",
-				    slot->hotplug_slot->name);
-				if(update_adapter_status(slot->hotplug_slot, 0)) {
-					warn("failure to update adapter file");
-				}
-				slot->extracting = 0;
-			}
-		}
+		} while (atomic_read(&extracting) && !thread_finished);
+		if (thread_finished)
+			break;
 
 		/* Re-enable ENUM# interrupt */
 		dbg("%s - re-enabling irq", __FUNCTION__);
 		controller->ops->enable_irq();
 	}
-
 	dbg("%s - event thread signals exit", __FUNCTION__);
 	up(&thread_exit);
 	return 0;
@@ -555,45 +565,27 @@ static int
 poll_thread(void *data)
 {
 	int rc;
-	struct slot *slot;
-	struct list_head *tmp;
 
 	lock_kernel();
 	daemonize("cpci_hp_polld");
 	unlock_kernel();
 
-	while(1) {
-		if(thread_finished || signal_pending(current))
+	while (1) {
+		if (thread_finished || signal_pending(current))
 			break;
-
-		while(controller->ops->query_enum()) {
-			rc = check_slots();
-			if(rc > 0)
-				/* Give userspace a chance to handle extraction */
-				msleep(500);
-			else if (rc < 0) {
-				dbg("%s - error checking slots", __FUNCTION__);
-				thread_finished = 1;
-				break;
-			}
-		}
-		/* Check for someone yanking out a board */
-		list_for_each(tmp, &slot_list) {
-			slot = list_entry(tmp, struct slot, slot_list);
-			if(slot->extracting) {
-				/*
-				 * Hmmm, we're likely hosed at this point, should we
-				 * bother trying to tell the driver or not?
-				 */
-				err("card in slot %s was improperly removed",
-				    slot->hotplug_slot->name);
-				if(update_adapter_status(slot->hotplug_slot, 0)) {
-					warn("failure to update adapter file");
+		if (controller->ops->query_enum()) {
+			do {
+				rc = check_slots();
+				if (rc > 0) {
+					/* Give userspace a chance to handle extraction */
+					msleep(500);
+				} else if (rc < 0) {
+					dbg("%s - error checking slots", __FUNCTION__);
+					thread_finished = 1;
+					break;
 				}
-				slot->extracting = 0;
-			}
+			} while (atomic_read(&extracting) && !thread_finished);
 		}
-
 		msleep(100);
 	}
 	dbg("poll thread signals exit");
@@ -611,12 +603,11 @@ cpci_start_thread(void)
 	init_MUTEX_LOCKED(&thread_exit);
 	thread_finished = 0;
 
-	if(controller->irq) {
+	if (controller->irq)
 		pid = kernel_thread(event_thread, NULL, 0);
-	} else {
+	else
 		pid = kernel_thread(poll_thread, NULL, 0);
-	}
-	if(pid < 0) {
+	if (pid < 0) {
 		err("Can't start up our thread");
 		return -1;
 	}
@@ -629,9 +620,8 @@ cpci_stop_thread(void)
 {
 	thread_finished = 1;
 	dbg("thread finish command given");
-	if(controller->irq) {
+	if (controller->irq)
 		up(&event_semaphore);
-	}
 	dbg("wait for thread to exit");
 	down(&thread_exit);
 }
@@ -641,42 +631,67 @@ cpci_hp_register_controller(struct cpci_
 {
 	int status = 0;
 
-	if(!controller) {
-		controller = new_controller;
-		if(controller->irq) {
-			if(request_irq(controller->irq,
-					cpci_hp_intr,
-					controller->irq_flags,
-					MY_NAME, controller->dev_id)) {
-				err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
-				status = -ENODEV;
-			}
-			dbg("%s - acquired controller irq %d", __FUNCTION__,
-			    controller->irq);
+	if (controller)
+		return -1;
+	if (!(new_controller && new_controller->ops))
+		return -EINVAL;
+	if (new_controller->irq) {
+		if (!(new_controller->ops->enable_irq &&
+		     new_controller->ops->disable_irq))
+			status = -EINVAL;
+		if (request_irq(new_controller->irq,
+			       cpci_hp_intr,
+			       new_controller->irq_flags,
+			       MY_NAME,
+			       new_controller->dev_id)) {
+			err("Can't get irq %d for the hotplug cPCI controller",
+			    new_controller->irq);
+			status = -ENODEV;
 		}
-	} else {
-		err("cPCI hotplug controller already registered");
-		status = -1;
+		dbg("%s - acquired controller irq %d",
+		    __FUNCTION__, new_controller->irq);
 	}
+	if (!status)
+		controller = new_controller;
 	return status;
 }
 
+static void
+cleanup_slots(void)
+{
+	struct slot *slot;
+	struct slot *tmp;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 */
+	down_write(&list_rwsem);
+	if (!slots)
+		goto cleanup_null;
+	list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+	}
+cleanup_null:
+	up_write(&list_rwsem);
+	return;
+}
+
 int
 cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
 {
 	int status = 0;
 
-	if(controller) {
-		if(!thread_finished) {
+	if (controller) {
+		if (!thread_finished)
 			cpci_stop_thread();
-		}
-		if(controller->irq) {
+		if (controller->irq)
 			free_irq(controller->irq, controller->dev_id);
-		}
 		controller = NULL;
-	} else {
+		cleanup_slots();
+	} else
 		status = -ENODEV;
-	}
 	return status;
 }
 
@@ -687,32 +702,28 @@ cpci_hp_start(void)
 	int status;
 
 	dbg("%s - enter", __FUNCTION__);
-	if(!controller) {
+	if (!controller)
 		return -ENODEV;
-	}
 
-	spin_lock(&list_lock);
-	if(!slots) {
-		spin_unlock(&list_lock);
+	down_read(&list_rwsem);
+	if (list_empty(&slot_list)) {
+		up_read(&list_rwsem);
 		return -ENODEV;
 	}
-	spin_unlock(&list_lock);
+	up_read(&list_rwsem);
 
-	if(first) {
-		status = init_slots();
-		if(status) {
-			return status;
-		}
+	status = init_slots(first);
+	if (first)
 		first = 0;
-	}
+	if (status)
+		return status;
 
 	status = cpci_start_thread();
-	if(status) {
+	if (status)
 		return status;
-	}
 	dbg("%s - thread started", __FUNCTION__);
 
-	if(controller->irq) {
+	if (controller->irq) {
 		/* Start enum interrupt processing */
 		dbg("%s - enabling irq", __FUNCTION__);
 		controller->ops->enable_irq();
@@ -724,11 +735,9 @@ cpci_hp_start(void)
 int
 cpci_hp_stop(void)
 {
-	if(!controller) {
+	if (!controller)
 		return -ENODEV;
-	}
-
-	if(controller->irq) {
+	if (controller->irq) {
 		/* Stop enum interrupt processing */
 		dbg("%s - disabling irq", __FUNCTION__);
 		controller->ops->disable_irq();
@@ -737,41 +746,10 @@ cpci_hp_stop(void)
 	return 0;
 }
 
-static void __exit
-cleanup_slots(void)
-{
-	struct list_head *tmp;
-	struct slot *slot;
-
-	/*
-	 * Unregister all of our slots with the pci_hotplug subsystem,
-	 * and free up all memory that we had allocated.
-	 */
-	spin_lock(&list_lock);
-	if(!slots) {
-		goto null_cleanup;
-	}
-	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);
-	}
-      null_cleanup:
-	spin_unlock(&list_lock);
-	return;
-}
-
 int __init
 cpci_hotplug_init(int debug)
 {
-	spin_lock_init(&list_lock);
 	cpci_debug = debug;
-
-	info(DRIVER_DESC " version: " DRIVER_VERSION);
 	return 0;
 }
 
@@ -781,7 +759,8 @@ cpci_hotplug_exit(void)
 	/*
 	 * Clean everything up.
 	 */
-	cleanup_slots();
+	cpci_hp_stop();
+	cpci_hp_unregister_controller(controller);
 }
 
 EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -1,7 +1,7 @@
 /*
  * CompactPCI Hot Plug Driver PCI functions
  *
- * Copyright (C) 2002 by SOMA Networks, Inc.
+ * Copyright (C) 2002,2005 by SOMA Networks, Inc.
  *
  * All rights reserved.
  *
@@ -32,20 +32,16 @@
 #include "pci_hotplug.h"
 #include "cpci_hotplug.h"
 
-#if !defined(MODULE)
 #define MY_NAME	"cpci_hotplug"
-#else
-#define MY_NAME	THIS_MODULE->name
-#endif
 
 extern int cpci_debug;
 
 #define dbg(format, arg...)					\
 	do {							\
-		if(cpci_debug)					\
+		if (cpci_debug)					\
 			printk (KERN_DEBUG "%s: " format "\n",	\
 				MY_NAME , ## arg); 		\
-	} while(0)
+	} 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)
@@ -61,16 +57,15 @@ u8 cpci_get_attention_status(struct slot
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return 0;
-	}
 
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return 0;
-	}
+
 	return hs_csr & 0x0008 ? 1 : 0;
 }
 
@@ -82,27 +77,22 @@ int cpci_set_attention_status(struct slo
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return 0;
-	}
-
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return 0;
-	}
-	if(status) {
+	if (status)
 		hs_csr |= HS_CSR_LOO;
-	} else {
+	else
 		hs_csr &= ~HS_CSR_LOO;
-	}
-	if(pci_bus_write_config_word(slot->bus,
+	if (pci_bus_write_config_word(slot->bus,
 				      slot->devfn,
 				      hs_cap + 2,
-				      hs_csr)) {
+				      hs_csr))
 		return 0;
-	}
 	return 1;
 }
 
@@ -114,51 +104,16 @@ u16 cpci_get_hs_csr(struct slot* slot)
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return 0xFFFF;
-	}
-
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return 0xFFFF;
-	}
 	return hs_csr;
 }
 
-#if 0
-u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
-{
-	int hs_cap;
-	u16 new_hs_csr;
-
-	hs_cap = pci_bus_find_capability(slot->bus,
-					 slot->devfn,
-					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
-		return 0xFFFF;
-	}
-
-	/* Write out the new value */
-	if(pci_bus_write_config_word(slot->bus,
-				      slot->devfn,
-				      hs_cap + 2,
-				      hs_csr)) {
-		return 0xFFFF;
-	}
-
-	/* Read back what we just wrote out */
-	if(pci_bus_read_config_word(slot->bus,
-				     slot->devfn,
-				     hs_cap + 2,
-				     &new_hs_csr)) {
-		return 0xFFFF;
-	}
-	return new_hs_csr;
-}
-#endif
-
 int cpci_check_and_clear_ins(struct slot* slot)
 {
 	int hs_cap;
@@ -168,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return 0;
-	}
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return 0;
-	}
-	if(hs_csr & HS_CSR_INS) {
+	if (hs_csr & HS_CSR_INS) {
 		/* Clear INS (by setting it) */
-		if(pci_bus_write_config_word(slot->bus,
+		if (pci_bus_write_config_word(slot->bus,
 					      slot->devfn,
 					      hs_cap + 2,
-					      hs_csr)) {
+					      hs_csr))
 			ins = 0;
-		}
-		ins = 1;
+		else
+			ins = 1;
 	}
 	return ins;
 }
@@ -199,18 +152,15 @@ int cpci_check_ext(struct slot* slot)
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return 0;
-	}
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return 0;
-	}
-	if(hs_csr & HS_CSR_EXT) {
+	if (hs_csr & HS_CSR_EXT)
 		ext = 1;
-	}
 	return ext;
 }
 
@@ -222,23 +172,20 @@ int cpci_clear_ext(struct slot* slot)
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return -ENODEV;
-	}
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return -ENODEV;
-	}
-	if(hs_csr & HS_CSR_EXT) {
+	if (hs_csr & HS_CSR_EXT) {
 		/* Clear EXT (by setting it) */
-		if(pci_bus_write_config_word(slot->bus,
+		if (pci_bus_write_config_word(slot->bus,
 					      slot->devfn,
 					      hs_cap + 2,
-					      hs_csr)) {
+					      hs_csr))
 			return -ENODEV;
-		}
 	}
 	return 0;
 }
@@ -251,19 +198,16 @@ int cpci_led_on(struct slot* slot)
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return -ENODEV;
-	}
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return -ENODEV;
-	}
-	if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
-		/* Set LOO */
+	if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
 		hs_csr |= HS_CSR_LOO;
-		if(pci_bus_write_config_word(slot->bus,
+		if (pci_bus_write_config_word(slot->bus,
 					      slot->devfn,
 					      hs_cap + 2,
 					      hs_csr)) {
@@ -283,19 +227,16 @@ int cpci_led_off(struct slot* slot)
 	hs_cap = pci_bus_find_capability(slot->bus,
 					 slot->devfn,
 					 PCI_CAP_ID_CHSWP);
-	if(!hs_cap) {
+	if (!hs_cap)
 		return -ENODEV;
-	}
-	if(pci_bus_read_config_word(slot->bus,
+	if (pci_bus_read_config_word(slot->bus,
 				     slot->devfn,
 				     hs_cap + 2,
-				     &hs_csr)) {
+				     &hs_csr))
 		return -ENODEV;
-	}
-	if(hs_csr & HS_CSR_LOO) {
-		/* Clear LOO */
+	if (hs_csr & HS_CSR_LOO) {
 		hs_csr &= ~HS_CSR_LOO;
-		if(pci_bus_write_config_word(slot->bus,
+		if (pci_bus_write_config_word(slot->bus,
 					      slot->devfn,
 					      hs_cap + 2,
 					      hs_csr)) {
@@ -312,268 +253,21 @@ int cpci_led_off(struct slot* slot)
  * Device configuration functions
  */
 
-static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev)
-{
-	u8 irq_pin;
-	int r;
-
-	dbg("%s - enter", __FUNCTION__);
-
-	/* NOTE: device already setup from prior scan */
-
-	/* FIXME: How would we know if we need to enable the expansion ROM? */
-	pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
-
-	/* Assign resources */
-	dbg("assigning resources for %02x:%02x.%x",
-	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	for (r = 0; r < 6; r++) {
-		struct resource *res = dev->resource + r;
-		if(res->flags)
-			pci_assign_resource(dev, r);
-	}
-	dbg("finished assigning resources for %02x:%02x.%x",
-	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-
-	/* Does this function have an interrupt at all? */
-	dbg("checking for function interrupt");
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
-	if(irq_pin) {
-		dbg("function uses interrupt pin %d", irq_pin);
-	}
-
-	/*
-	 * Need to explicitly set irq field to 0 so that it'll get assigned
-	 * by the pcibios platform dependent code called by pci_enable_device.
-	 */
-	dev->irq = 0;
-
-	dbg("enabling device");
-	pci_enable_device(dev);	/* XXX check return */
-	dbg("now dev->irq = %d", dev->irq);
-	if(irq_pin && dev->irq) {
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-
-	/* Can't use pci_insert_device at the moment, do it manually for now */
-	pci_proc_attach_device(dev);
-	dbg("notifying drivers");
-	//pci_announce_device_to_drivers(dev);
-	dbg("%s - exit", __FUNCTION__);
-	return 0;
-}
-
-static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
-{
-	int rc;
-	struct pci_bus* child;
-	struct resource* r;
-	u8 max, n;
-	u16 command;
-
-	dbg("%s - enter", __FUNCTION__);
-
-	/* Do basic bridge initialization */
-	rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-	if(rc) {
-		printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
-	}
-	rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
-	if(rc) {
-		printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
-	}
-	rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
-	if(rc) {
-		printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
-	}
-
-	/*
-	 * Set parent bridge's subordinate field so that configuration space
-	 * access will work in pci_scan_bridge and friends.
-	 */
-	max = pci_max_busnr();
-	bus->subordinate = max + 1;
-	pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
-
-	/* Scan behind bridge */
-	n = pci_scan_bridge(bus, dev, max, 2);
-	child = pci_find_bus(0, max + 1);
-	if (!child)
-		return -ENODEV;
-	pci_proc_attach_bus(child);
-
-	/*
-	 * Update parent bridge's subordinate field if there were more bridges
-	 * behind the bridge that was scanned.
-	 */
-	if(n > max) {
-		bus->subordinate = n;
-		pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
-	}
-
-	/*
-	 * Update the bridge resources of the bridge to accommodate devices
-	 * behind it.
-	 */
-	pci_bus_size_bridges(child);
-	pci_bus_assign_resources(child);
-
-	/* Enable resource mapping via command register */
-	command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
-	r = child->resource[0];
-	if(r && r->start) {
-		command |= PCI_COMMAND_IO;
-	}
-	r = child->resource[1];
-	if(r && r->start) {
-		command |= PCI_COMMAND_MEMORY;
-	}
-	r = child->resource[2];
-	if(r && r->start) {
-		command |= PCI_COMMAND_MEMORY;
-	}
-	rc = pci_write_config_word(dev, PCI_COMMAND, command);
-	if(rc) {
-		err("Error setting command register");
-		return rc;
-	}
-
-	/* Set bridge control register */
-	command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
-	rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
-	if(rc) {
-		err("Error setting bridge control register");
-		return rc;
-	}
-	dbg("%s - exit", __FUNCTION__);
-	return 0;
-}
-
-static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
-				   struct pci_bus_wrapped *wrapped_bus)
-{
-	int rc;
-	struct pci_dev *dev = wrapped_dev->dev;
-	struct pci_bus *bus = wrapped_bus->bus;
-	struct slot* slot;
-
-	dbg("%s - enter", __FUNCTION__);
-
-	/*
-	 * We need to fix up the hotplug representation with the Linux
-	 * representation.
-	 */
-	if(wrapped_dev->data) {
-		slot = (struct slot*) wrapped_dev->data;
-		slot->dev = dev;
-	}
-
-	/* If it's a bridge, scan behind it for devices */
-	if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-		rc = cpci_configure_bridge(bus, dev);
-		if(rc)
-			return rc;
-	}
-
-	/* Actually configure device */
-	if(dev) {
-		rc = cpci_configure_dev(bus, dev);
-		if(rc)
-			return rc;
-	}
-	dbg("%s - exit", __FUNCTION__);
-	return 0;
-}
-
-static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
-					    struct pci_bus_wrapped *wrapped_bus)
-{
-	struct pci_dev *dev = wrapped_dev->dev;
-	struct slot* slot;
-
-	dbg("%s - enter", __FUNCTION__);
-	if(!dev)
-		return -ENODEV;
-
-	/* Remove the Linux representation */
-	if(pci_remove_device_safe(dev)) {
-		err("Could not remove device\n");
-		return -1;
-	}
-
-	/*
-	 * Now remove the hotplug representation.
-	 */
-	if(wrapped_dev->data) {
-		slot = (struct slot*) wrapped_dev->data;
-		slot->dev = NULL;
-	} else {
-		dbg("No hotplug representation for %02x:%02x.%x",
-		    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	}
-	dbg("%s - exit", __FUNCTION__);
-	return 0;
-}
-
-static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
-					    struct pci_dev_wrapped *wrapped_dev)
-{
-	struct pci_bus *bus = wrapped_bus->bus;
-	struct pci_bus *parent = bus->self->bus;
-
-	dbg("%s - enter", __FUNCTION__);
-
-	/* The cleanup code for proc entries regarding buses should be in the kernel... */
-	if(bus->procdir)
-		dbg("detach_pci_bus %s", bus->procdir->name);
-	pci_proc_detach_bus(bus);
-
-	/* 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);
-
-	/* Update parent's subordinate field */
-	if(parent) {
-		u8 n = pci_bus_max_busnr(parent);
-		if(n < parent->subordinate) {
-			parent->subordinate = n;
-			pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
-		}
-	}
-	dbg("%s - exit", __FUNCTION__);
-	return 0;
-}
-
-static struct pci_visit configure_functions = {
-	.visit_pci_dev = configure_visit_pci_dev,
-};
-
-static struct pci_visit unconfigure_functions_phase2 = {
-	.post_visit_pci_bus = unconfigure_visit_pci_bus_phase2,
-	.post_visit_pci_dev = unconfigure_visit_pci_dev_phase2
-};
-
-
 int cpci_configure_slot(struct slot* slot)
 {
-	int rc = 0;
+	unsigned char busnr;
+	struct pci_bus *child;
 
 	dbg("%s - enter", __FUNCTION__);
 
-	if(slot->dev == NULL) {
+	if (slot->dev == NULL) {
 		dbg("pci_dev null, finding %02x:%02x:%x",
 		    slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
-		slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+		slot->dev = pci_get_slot(slot->bus, slot->devfn);
 	}
 
 	/* Still NULL? Well then scan for it! */
-	if(slot->dev == NULL) {
+	if (slot->dev == NULL) {
 		int n;
 		dbg("pci_dev still null");
 
@@ -583,79 +277,50 @@ int cpci_configure_slot(struct slot* slo
 		 */
 		n = pci_scan_slot(slot->bus, slot->devfn);
 		dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
-		if(n > 0)
+		if (n > 0)
 			pci_bus_add_devices(slot->bus);
-		slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
-		if(slot->dev == NULL) {
+		slot->dev = pci_get_slot(slot->bus, slot->devfn);
+		if (slot->dev == NULL) {
 			err("Could not find PCI device for slot %02x", slot->number);
-			return 0;
+			return 1;
 		}
 	}
-	dbg("slot->dev = %p", slot->dev);
-	if(slot->dev) {
-		struct pci_dev *dev;
-		struct pci_dev_wrapped wrapped_dev;
-		struct pci_bus_wrapped wrapped_bus;
-		int i;
-
-		memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
-		memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
-
-		for (i = 0; i < 8; i++) {
-			dev = pci_find_slot(slot->bus->number,
-					    PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
-			if(!dev)
-				continue;
-			wrapped_dev.dev = dev;
-			wrapped_bus.bus = slot->dev->bus;
-			if(i)
-				wrapped_dev.data = NULL;
-			else
-				wrapped_dev.data = (void*) slot;
-			rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
-		}
+
+	if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr);
+		child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr);
+		pci_do_scan_bus(child);
+		pci_bus_size_bridges(child);
 	}
 
-	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
-	return rc;
+	pci_bus_assign_resources(slot->dev->bus);
+
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
 }
 
 int cpci_unconfigure_slot(struct slot* slot)
 {
-	int rc = 0;
 	int i;
-	struct pci_dev_wrapped wrapped_dev;
-	struct pci_bus_wrapped wrapped_bus;
 	struct pci_dev *dev;
 
 	dbg("%s - enter", __FUNCTION__);
-
-	if(!slot->dev) {
+	if (!slot->dev) {
 		err("No device for slot %02x\n", slot->number);
 		return -ENODEV;
 	}
 
-	memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
-	memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
-
 	for (i = 0; i < 8; i++) {
-		dev = pci_find_slot(slot->bus->number,
+		dev = pci_get_slot(slot->bus,
 				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
-		if(dev) {
-			wrapped_dev.dev = dev;
-			wrapped_bus.bus = dev->bus;
- 			if(i)
- 				wrapped_dev.data = NULL;
- 			else
- 				wrapped_dev.data = (void*) slot;
-			dbg("%s - unconfigure phase 2", __FUNCTION__);
-			rc = pci_visit_dev(&unconfigure_functions_phase2,
-					   &wrapped_dev,
-					   &wrapped_bus);
-			if(rc)
-				break;
+		if (dev) {
+			pci_remove_bus_device(dev);
+			pci_dev_put(dev);
 		}
 	}
-	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
-	return rc;
+	pci_dev_put(slot->dev);
+	slot->dev = NULL;
+
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
 }
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -577,11 +577,11 @@ cpqhp_set_attention_status(struct contro
 {
 	u8 hp_slot;
 
-	hp_slot = func->device - ctrl->slot_device_offset;
-
 	if (func == NULL)
 		return(1);
 
+	hp_slot = func->device - ctrl->slot_device_offset;
+
 	// Wait for exclusive access to hardware
 	down(&ctrl->crit_sect);
 
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
--- a/drivers/pci/hotplug/ibmphp.h
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -196,7 +196,7 @@ struct ebda_hpc_bus {
 
 
 /********************************************************************
-*   THREE TYPE OF HOT PLUG CONTROLER                                *
+*   THREE TYPE OF HOT PLUG CONTROLLER                                *
 ********************************************************************/
 
 struct isa_ctlr_access {
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -64,7 +64,7 @@ static int to_debug = FALSE;
 #define WPG_I2C_OR		0x2000	// I2C OR operation
 
 //----------------------------------------------------------------------------
-// Command set for I2C Master Operation Setup Regisetr
+// Command set for I2C Master Operation Setup Register
 //----------------------------------------------------------------------------
 #define WPG_READATADDR_MASK	0x00010000	// read,bytes,I2C shifted,index
 #define WPG_WRITEATADDR_MASK	0x40010000	// write,bytes,I2C shifted,index
@@ -835,7 +835,7 @@ static void poll_hpc (void)
 		if (ibmphp_shutdown) 
 			break;
 		
-		/* try to get the lock to do some kind of harware access */
+		/* try to get the lock to do some kind of hardware access */
 		down (&semOperations);
 
 		switch (poll_state) {
@@ -906,7 +906,7 @@ static void poll_hpc (void)
 				poll_state = POLL_LATCH_REGISTER;
 			break;
 		}	
-		/* give up the harware semaphore */
+		/* give up the hardware semaphore */
 		up (&semOperations);
 		/* sleep for a short time just for good measure */
 		msleep(100);
diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c
--- a/drivers/pci/hotplug/ibmphp_pci.c
+++ b/drivers/pci/hotplug/ibmphp_pci.c
@@ -1310,41 +1310,37 @@ static int unconfigure_boot_device (u8 b
 			/* This is Memory */
 			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
 				/* pfmem */
-				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
 				debug ("start address of pfmem is %x\n", start_address);
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
 
 				if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) {
 					err ("cannot find corresponding PFMEM resource to remove\n");
 					return -EIO;
 				}
-				if (pfmem)
+				if (pfmem) {
 					debug ("pfmem->start = %x\n", pfmem->start);
 
-				ibmphp_remove_resource (pfmem);
-
-				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-					/* takes up another dword */
-					count += 1;
+					ibmphp_remove_resource(pfmem);
 				}
-
 			} else {
 				/* regular memory */
-				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
 				debug ("start address of mem is %x\n", start_address);
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+
 				if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) {
 					err ("cannot find corresponding MEM resource to remove\n");
 					return -EIO;
 				}
-				if (mem)
+				if (mem) {
 					debug ("mem->start = %x\n", mem->start);
 
-				ibmphp_remove_resource (mem);
-
-				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-					/* takes up another dword */
-					count += 1;
+					ibmphp_remove_resource(mem);
 				}
 			}
+			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+				/* takes up another dword */
+				count += 1;
+			}
 		}	/* end of mem */
 	}	/* end of for */
 
@@ -1384,9 +1380,6 @@ static int unconfigure_boot_bridge (u8 b
 		return -EINVAL;
 	}
 
-	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
-	sec_no = (int) sec_no;
-
 	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number);
 	sub_no = (int) sub_number;
 	debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no);
@@ -1438,16 +1431,11 @@ static int unconfigure_boot_bridge (u8 b
 					err ("cannot find corresponding PFMEM resource to remove\n");
 					return -EINVAL;
 				}
-				if (pfmem)
+				if (pfmem) {
 					debug ("pfmem->start = %x\n", pfmem->start);
 
-				ibmphp_remove_resource (pfmem);
-
-				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-					/* takes up another dword */
-					count += 1;
+					ibmphp_remove_resource(pfmem);
 				}
-
 			} else {
 				/* regular memory */
 				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
@@ -1455,16 +1443,16 @@ static int unconfigure_boot_bridge (u8 b
 					err ("cannot find corresponding MEM resource to remove\n");
 					return -EINVAL;
 				}
-				if (mem)
+				if (mem) {
 					debug ("mem->start = %x\n", mem->start);
 
-				ibmphp_remove_resource (mem);
-
-				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-					/* takes up another dword */
-					count += 1;
+					ibmphp_remove_resource(mem);
 				}
 			}
+			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+				/* takes up another dword */
+				count += 1;
+			}
 		}	/* end of mem */
 	}	/* end of for */
 	debug ("%s - exiting, returning success\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h
--- a/drivers/pci/hotplug/pci_hotplug.h
+++ b/drivers/pci/hotplug/pci_hotplug.h
@@ -150,8 +150,10 @@ struct hotplug_slot_info {
  * @name: the name of the slot being registered.  This string must
  * be unique amoung slots registered on this system.
  * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
- * @info: pointer to the &struct hotplug_slot_info for the inital values for
+ * @info: pointer to the &struct hotplug_slot_info for the initial values for
  * this slot.
+ * @release: called during pci_hp_deregister to free memory allocated in a
+ * hotplug_slot structure.
  * @private: used by the hotplug pci controller driver to store whatever it
  * needs.
  */
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -567,6 +567,11 @@ int pci_hp_register (struct hotplug_slot
 		return -ENODEV;
 	if ((slot->info == NULL) || (slot->ops == NULL))
 		return -EINVAL;
+	if (slot->release == NULL) {
+		dbg("Why are you trying to register a hotplug slot"
+		    "without a proper release function?\n");
+		return -EINVAL;
+	}
 
 	kobject_set_name(&slot->kobj, "%s", slot->name);
 	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -130,6 +130,7 @@ struct controller {
 	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
 	u8 ctrlcap;
 	u16 vendor_id;
+	u8 cap_base;
 };
 
 struct irq_mapping {
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -90,6 +90,22 @@ static struct hotplug_slot_ops pciehp_ho
   	.get_cur_bus_speed =	get_cur_bus_speed,
 };
 
+/**
+ * release_slot - free up the memory used by a slot
+ * @hotplug_slot: slot to free
+ */
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
 static int init_slots(struct controller *ctrl)
 {
 	struct slot *new_slot;
@@ -139,7 +155,8 @@ static int init_slots(struct controller 
 
 		/* register this slot with the hotplug pci core */
 		new_slot->hotplug_slot->private = new_slot;
-		make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->release = &release_slot;
+		make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
 		new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops;
 
 		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
@@ -188,10 +205,6 @@ static int cleanup_slots (struct control
 	while (old_slot) {
 		next_slot = old_slot->next;
 		pci_hp_deregister (old_slot->hotplug_slot);
-		kfree(old_slot->hotplug_slot->info);
-		kfree(old_slot->hotplug_slot->name);
-		kfree(old_slot->hotplug_slot);
-		kfree(old_slot);
 		old_slot = next_slot;
 	}
 
@@ -578,7 +591,7 @@ static void pciehp_remove (struct pcie_d
 }
 
 #ifdef CONFIG_PM
-static int pciehp_suspend (struct pcie_device *dev, u32 state)
+static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
 {
 	printk("%s ENTRY\n", __FUNCTION__);	
 	return 0;
@@ -594,7 +607,7 @@ static int pciehp_resume (struct pcie_de
 static struct pcie_port_service_id port_pci_ids[] = { { 
 	.vendor = PCI_ANY_ID, 
 	.device = PCI_ANY_ID,
-	.port_type = PCIE_RC_PORT, 
+	.port_type = PCIE_ANY_PORT,
 	.service_type = PCIE_PORT_SERVICE_HP,
 	.driver_data =	0, 
 	}, { /* end: all zeroes */ }
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -1354,10 +1354,11 @@ static u32 remove_board(struct pci_func 
 				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
 					ctrl->seg, func->bus, func->device, func->function);
 				bridge_slot_remove(func);
-			} else
+			} else {
 				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
 					ctrl->seg, func->bus, func->device, func->function);
 				slot_remove(func);
+			}
 
 			func = pciehp_slot_find(ctrl->slot_bus, device, 0);
 		}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -109,20 +109,20 @@ enum ctrl_offsets {
 };
 static int pcie_cap_base = 0;		/* Base of the PCI Express capability item structure */ 
 
-#define PCIE_CAP_ID	( pcie_cap_base + PCIECAPID )
-#define NXT_CAP_PTR	( pcie_cap_base + NXTCAPPTR )
-#define CAP_REG		( pcie_cap_base + CAPREG )
-#define DEV_CAP		( pcie_cap_base + DEVCAP )
-#define DEV_CTRL	( pcie_cap_base + DEVCTRL )
-#define DEV_STATUS	( pcie_cap_base + DEVSTATUS )
-#define LNK_CAP		( pcie_cap_base + LNKCAP )
-#define LNK_CTRL	( pcie_cap_base + LNKCTRL )
-#define LNK_STATUS	( pcie_cap_base + LNKSTATUS )
-#define SLOT_CAP	( pcie_cap_base + SLOTCAP )
-#define SLOT_CTRL	( pcie_cap_base + SLOTCTRL )
-#define SLOT_STATUS	( pcie_cap_base + SLOTSTATUS )
-#define ROOT_CTRL	( pcie_cap_base + ROOTCTRL )
-#define ROOT_STATUS	( pcie_cap_base + ROOTSTATUS )
+#define PCIE_CAP_ID(cb)	( cb + PCIECAPID )
+#define NXT_CAP_PTR(cb)	( cb + NXTCAPPTR )
+#define CAP_REG(cb)	( cb + CAPREG )
+#define DEV_CAP(cb)	( cb + DEVCAP )
+#define DEV_CTRL(cb)	( cb + DEVCTRL )
+#define DEV_STATUS(cb)	( cb + DEVSTATUS )
+#define LNK_CAP(cb)	( cb + LNKCAP )
+#define LNK_CTRL(cb)	( cb + LNKCTRL )
+#define LNK_STATUS(cb)	( cb + LNKSTATUS )
+#define SLOT_CAP(cb)	( cb + SLOTCAP )
+#define SLOT_CTRL(cb)	( cb + SLOTCTRL )
+#define SLOT_STATUS(cb)	( cb + SLOTSTATUS )
+#define ROOT_CTRL(cb)	( cb + ROOTCTRL )
+#define ROOT_STATUS(cb)	( cb + ROOTSTATUS )
 
 #define hp_register_read_word(pdev, reg , value)		\
 	pci_read_config_word(pdev, reg, &value)
@@ -303,7 +303,7 @@ static int pcie_write_cmd(struct slot *s
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
 	if (retval) {
 			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 			return retval;
@@ -317,7 +317,7 @@ static int pcie_write_cmd(struct slot *s
 	}
 
 	dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
-	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE);
+	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
 	if (retval) {
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
@@ -342,7 +342,7 @@ static int hpc_check_lnk_status(struct c
 		return -1;
 	}
 	
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -376,14 +376,14 @@ static int hpc_get_attention_status(stru
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
 
-	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl);
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
 
@@ -423,13 +423,13 @@ static int hpc_get_power_status(struct s
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
 
@@ -463,7 +463,7 @@ static int hpc_get_latch_status(struct s
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
@@ -490,7 +490,7 @@ static int hpc_get_adapter_status(struct
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
@@ -518,7 +518,7 @@ static int hpc_query_power_fault(struct 
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
@@ -549,7 +549,7 @@ static int hpc_set_attention_status(stru
 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
 		return -1;
 	}
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
@@ -574,7 +574,7 @@ static int hpc_set_attention_status(stru
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 
 	pcie_write_cmd(slot, slot_cmd);
-	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 	
 	return rc;
 }
@@ -598,7 +598,7 @@ static void hpc_set_green_led_on(struct 
 		return ;
 	}
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
@@ -611,7 +611,7 @@ static void hpc_set_green_led_on(struct 
 
 	pcie_write_cmd(slot, slot_cmd);
 
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 	return;
 }
 
@@ -633,7 +633,7 @@ static void hpc_set_green_led_off(struct
 		return ;
 	}
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
@@ -646,7 +646,7 @@ static void hpc_set_green_led_off(struct
 	if (!pciehp_poll_mode)
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 	pcie_write_cmd(slot, slot_cmd);
-	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
 	return;
 }
@@ -669,7 +669,7 @@ static void hpc_set_green_led_blink(stru
 		return ;
 	}
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
@@ -683,7 +683,7 @@ static void hpc_set_green_led_blink(stru
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 	pcie_write_cmd(slot, slot_cmd);
 
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 	return;
 }
 
@@ -707,7 +707,7 @@ int pcie_get_ctlr_slot_config(struct con
 	*first_device_num = 0;
 	*num_ctlr_slots = 1; 
 
-	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
 
 	if (rc) {
 		err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
@@ -793,13 +793,13 @@ static int hpc_power_on_slot(struct slot
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, 
+	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
 		slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
@@ -813,7 +813,7 @@ static int hpc_power_on_slot(struct slot
 		err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
 		return -1;
 	}
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
 	DBG_LEAVE_ROUTINE
 
@@ -842,13 +842,13 @@ static int hpc_power_off_slot(struct slo
 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
 		return -1;
 	}
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
 	if (retval) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, 
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
 		slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
@@ -862,7 +862,7 @@ static int hpc_power_off_slot(struct slo
 		err("%s: Write command failed!\n", __FUNCTION__);
 		return -1;
 	}
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
 	DBG_LEAVE_ROUTINE
 
@@ -900,7 +900,7 @@ static irqreturn_t pcie_isr(int IRQ, voi
 		return IRQ_NONE;
 	}
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 		return IRQ_NONE;
@@ -918,7 +918,7 @@ static irqreturn_t pcie_isr(int IRQ, voi
 	dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
 	/* Mask Hot-plug Interrupt Enable */
 	if (!pciehp_poll_mode) {
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -928,14 +928,14 @@ static irqreturn_t pcie_isr(int IRQ, voi
 		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
 		}
 		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 		if (rc) {
 			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -944,7 +944,7 @@ static irqreturn_t pcie_isr(int IRQ, voi
 		
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1f;
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -975,14 +975,14 @@ static irqreturn_t pcie_isr(int IRQ, voi
 
 	/* Clear all events after serving them */
 	temp_word = 0x1F;
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 		return IRQ_NONE;
 	}
 	/* Unmask Hot-plug Interrupt Enable */
 	if (!pciehp_poll_mode) {
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -992,14 +992,14 @@ static irqreturn_t pcie_isr(int IRQ, voi
 		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
 		}
 		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); 	
 	
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 		if (rc) {
 			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -1008,7 +1008,7 @@ static irqreturn_t pcie_isr(int IRQ, voi
 		
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1F;
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
 		if (rc) {
 			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 			return IRQ_NONE;
@@ -1038,7 +1038,7 @@ static int hpc_get_max_lnk_speed (struct
 		return -1;
 	}
 
-	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
 
 	if (retval) {
 		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
@@ -1079,7 +1079,7 @@ static int hpc_get_max_lnk_width (struct
 		return -1;
 	}
 
-	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
 
 	if (retval) {
 		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
@@ -1141,7 +1141,7 @@ static int hpc_get_cur_lnk_speed (struct
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -1182,7 +1182,7 @@ static int hpc_get_cur_lnk_width (struct
 		return -1;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
 
 	if (retval) {
 		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -1292,47 +1292,48 @@ int pcie_init(struct controller * ctrl,
 		goto abort_free_ctlr;
 	}
 
-	pcie_cap_base = cap_base;
+	ctrl->cap_base = cap_base;
 
 	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
 
-	rc = hp_register_read_word(pdev, CAP_REG, cap_reg);
+	rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
 	if (rc) {
 		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg);
+	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
 
-	if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){
+	if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+		&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
 		dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
-	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
 	if (rc) {
 		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap);
+	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
 
 	if (!(slot_cap & HP_CAP)) {
 		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 	/* For debugging purpose */
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
 
 	if (first) {
 		spin_lock_init(&hpc_event_lock);
@@ -1372,36 +1373,37 @@ int pcie_init(struct controller * ctrl,
 	php_ctlr->num_slots = 1;
 
 	/* Mask Hot-plug Interrupt Enable */
-	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
-	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
 	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
-	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 	dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base)
+		, slot_status);
 
 	temp_word = 0x1F; /* Clear all events */
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
 
 	if (pciehp_poll_mode)  {/* Install interrupt polling code */
 		/* Install and start the interrupt polling timer */
@@ -1417,12 +1419,12 @@ int pcie_init(struct controller * ctrl,
 		}
 	}
 
-	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
 	dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap);
 
 	intr_enable = intr_enable | PRSN_DETECT_ENABLE;
@@ -1446,27 +1448,27 @@ int pcie_init(struct controller * ctrl,
 	dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
 
 	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
-	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 	dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 	dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
-		SLOT_STATUS, slot_status);
+		SLOT_STATUS(ctrl->cap_base), slot_status);
 	
 	temp_word =  0x1F; /* Clear all events */
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
 	if (rc) {
 		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
 	
 	/*  Add this HPC instance into the HPC list */
 	spin_lock(&list_lock);
diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c
--- a/drivers/pci/hotplug/pciehprm_acpi.c
+++ b/drivers/pci/hotplug/pciehprm_acpi.c
@@ -254,10 +254,9 @@ static int acpi_run_oshp ( struct acpi_b
 {
 	acpi_status		status;
 	u8			*path_name = acpi_path_name(ab->handle);
-	struct acpi_buffer	ret_buf = { 0, NULL};
 
 	/* run OSHP */
-	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
 	if (ACPI_FAILURE(status)) {
 		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
 		oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED;
diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
--- a/drivers/pci/hotplug/pcihp_skeleton.c
+++ b/drivers/pci/hotplug/pcihp_skeleton.c
@@ -297,7 +297,7 @@ static int __init init_slots(void)
 		hotplug_slot->ops = &skel_hotplug_slot_ops;
 		
 		/*
-		 * Initilize the slot info structure with some known
+		 * Initialize the slot info structure with some known
 		 * good values.
 		 */
 		info->power_status = get_power_status(slot);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -142,7 +142,7 @@ static int pci_add_secondary_bus(struct 
 	child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno);
 	if (!child) {
 		printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__);
-		return 1;
+		return -ENOMEM;
 	}
 
 	sprintf(child->name, "PCI Bus #%02x", child->number);
@@ -204,7 +204,7 @@ static int dlpar_pci_remove_bus(struct p
 	if (!bridge_dev) {
 		printk(KERN_ERR "%s: unexpected null device\n",
 			__FUNCTION__);
-		return 1;
+		return -EINVAL;
 	}
 
 	secondary_bus = bridge_dev->subordinate;
@@ -212,7 +212,7 @@ static int dlpar_pci_remove_bus(struct p
 	if (unmap_bus_range(secondary_bus)) {
 		printk(KERN_ERR "%s: failed to unmap bus range\n",
 			__FUNCTION__);
-		return 1;
+		return -ERANGE;
 	}
 
 	pci_remove_bus_device(bridge_dev);
@@ -282,7 +282,7 @@ static int dlpar_remove_phb(struct slot 
 	}
 
 	rc = dlpar_remove_root_bus(phb);
-	if (rc)
+	if (rc < 0)
 		return rc;
 
 	return 0;
@@ -294,7 +294,7 @@ static int dlpar_add_phb(struct device_n
 
 	phb = init_phb_dynamic(dn);
 	if (!phb)
-		return 1;
+		return -EINVAL;
 
 	return 0;
 }
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -45,11 +45,6 @@
 #define LED_ID		2	/* slow blinking */
 #define LED_ACTION	3	/* fast blinking */
 
-/* Error status from rtas_get-sensor */
-#define NEED_POWER    -9000	/* slot must be power up and unisolated to get state */
-#define PWR_ONLY      -9001	/* slot must be powerd up to get state, leave isolated */
-#define ERR_SENSE_USE -9002	/* No DR operation will succeed, slot is unusable  */
-
 /* Sensor values from rtas_get-sensor */
 #define EMPTY           0	/* No card in slot */
 #define PRESENT         1	/* Card in slot */
@@ -99,7 +94,7 @@ struct slot {
 				/* dn has phb info */
 	struct pci_dev *bridge;	/* slot's pci_dev in pci_devices */
 	union {
-		struct list_head pci_funcs; /* pci_devs in PCI slot */ 
+		struct list_head *pci_devs; /* pci_devs in PCI slot */
 		struct vio_dev *vio_dev; /* vio_dev in VIO slot */
 	} dev;
 	struct hotplug_slot *hotplug_slot;
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -256,12 +256,12 @@ int rpaphp_get_drc_props(struct device_n
 	my_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
 	if (!my_index) {
 		/* Node isn't DLPAR/hotplug capable */
-		return 1;
+		return -EINVAL;
 	}
 
 	rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
 	if (rc < 0) {
-		return 1;
+		return -EINVAL;
 	}
 
 	name_tmp = (char *) &names[1];
@@ -284,7 +284,7 @@ int rpaphp_get_drc_props(struct device_n
 		type_tmp += (strlen(type_tmp) + 1);
 	}
 
-	return 1;
+	return -EINVAL;
 }
 
 static int is_php_type(char *drc_type)
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -81,8 +81,8 @@ static int rpaphp_get_sensor_state(struc
 
 	rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
 
-	if (rc) {
-		if (rc == NEED_POWER || rc == PWR_ONLY) {
+	if (rc < 0) {
+		if (rc == -EFAULT || rc == -EEXIST) {
 			dbg("%s: slot must be power up to get sensor-state\n",
 			    __FUNCTION__);
 
@@ -91,14 +91,14 @@ static int rpaphp_get_sensor_state(struc
 			 */
 			rc = rtas_set_power_level(slot->power_domain, POWER_ON,
 						  &setlevel);
-			if (rc) {
+			if (rc < 0) {
 				dbg("%s: power on slot[%s] failed rc=%d.\n",
 				    __FUNCTION__, slot->name, rc);
 			} else {
 				rc = rtas_get_sensor(DR_ENTITY_SENSE,
 						     slot->index, state);
 			}
-		} else if (rc == ERR_SENSE_USE)
+		} else if (rc == -ENODEV)
 			info("%s: slot is unusable\n", __FUNCTION__);
 		else
 			err("%s failed to get sensor state\n", __FUNCTION__);
@@ -130,11 +130,11 @@ int rpaphp_get_pci_adapter_status(struct
  		*value = EMPTY;
  	}
  	else if (state == PRESENT) {
-		if (!is_init)
+		if (!is_init) {
 			/* at run-time slot->state can be changed by */
 			/* config/unconfig adapter */
 			*value = slot->state;
-		else {
+		} else {
  			child_dn = slot->dn->child;
  			if (child_dn)
  				child_dev = rpaphp_find_pci_dev(child_dn);
@@ -263,56 +263,17 @@ static void enable_eeh(struct device_nod
 	
 }
 
-#ifdef DEBUG
 static void print_slot_pci_funcs(struct slot *slot)
 {
-	struct list_head *l;
+	struct pci_dev *dev;
 
 	if (slot->dev_type == PCI_DEV) {
-		printk("pci_funcs of slot[%s]\n", slot->name);
-		if (list_empty(&slot->dev.pci_funcs))
-			printk("	pci_funcs is EMPTY\n");
-
-		list_for_each (l, &slot->dev.pci_funcs) {
-			struct rpaphp_pci_func *func =
-				list_entry(l, struct rpaphp_pci_func, sibling);
-			printk("	FOUND dev=%s\n", pci_name(func->pci_dev));
-		}
+		dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->name);
+		list_for_each_entry (dev, slot->dev.pci_devs, bus_list)
+			dbg("\t%s\n", pci_name(dev));
 	}
 	return;
 }
-#else
-static void print_slot_pci_funcs(struct slot *slot)
-{
-	return;
-}
-#endif
-
-static int init_slot_pci_funcs(struct slot *slot)
-{
-	struct device_node *child;
-
-	for (child = slot->dn->child; child != NULL; child = child->sibling) {
-		struct pci_dev *pdev = rpaphp_find_pci_dev(child);
-
-		if (pdev) {
-			struct rpaphp_pci_func *func;
-			func = kmalloc(sizeof(struct rpaphp_pci_func), GFP_KERNEL);
-			if (!func) 
-				return -ENOMEM;
-			memset(func, 0, sizeof(struct rpaphp_pci_func));
-			INIT_LIST_HEAD(&func->sibling);
-			func->pci_dev = pdev;
-			list_add_tail(&func->sibling, &slot->dev.pci_funcs);
-			print_slot_pci_funcs(slot);
-		} else {
-			err("%s: dn=%s has no pci_dev\n", 
-				__FUNCTION__, child->full_name);
-			return -EIO;
-		}
-	}
-	return 0;
-}
 
 static int rpaphp_config_pci_adapter(struct slot *slot)
 {
@@ -335,13 +296,8 @@ static int rpaphp_config_pci_adapter(str
 			err("%s: can't find any devices.\n", __FUNCTION__);
 			goto exit;
 		}
-		/* associate corresponding pci_dev */	
-		rc = init_slot_pci_funcs(slot);
-		if (rc)
-			goto exit;
 		print_slot_pci_funcs(slot);
-		if (!list_empty(&slot->dev.pci_funcs)) 
-			rc = 0;
+		rc = 0;
 	} else {
 		/* slot is not enabled */
 		err("slot doesn't have pci_dev structure\n");
@@ -371,34 +327,16 @@ static void rpaphp_eeh_remove_bus_device
 
 int rpaphp_unconfig_pci_adapter(struct slot *slot)
 {
+	struct pci_dev *dev;
 	int retval = 0;
-	struct list_head *ln, *tmp;
 
-	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
-	if (list_empty(&slot->dev.pci_funcs)) {
-		err("%s: slot[%s] doesn't have any devices.\n", __FUNCTION__, 
-			slot->name);
+	list_for_each_entry(dev, slot->dev.pci_devs, bus_list)
+		rpaphp_eeh_remove_bus_device(dev);
 
-		retval = -EINVAL;
-		goto exit;
-	}
-	/* remove the devices from the pci core */
-	list_for_each_safe (ln, tmp, &slot->dev.pci_funcs) {
-		struct rpaphp_pci_func *func;
-	
-		func = list_entry(ln, struct rpaphp_pci_func, sibling);
-		if (func->pci_dev) {
-			pci_remove_bus_device(func->pci_dev); 
-			rpaphp_eeh_remove_bus_device(func->pci_dev);
-		}
-		kfree(func);
-	}
-	INIT_LIST_HEAD(&slot->dev.pci_funcs);
+	pci_remove_behind_bridge(slot->bridge);
 	slot->state = NOT_CONFIGURED;
 	info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
 	     slot->name);
-exit:
-	dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
 	return retval;
 }
 
@@ -413,7 +351,7 @@ static int setup_pci_hotplug_slot_info(s
 	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
 		err("%s: NOT_VALID: skip dn->full_name=%s\n",
 		    __FUNCTION__, slot->dn->full_name);
-		return -1;
+		return -EINVAL;
 	}
 	return 0;
 }
@@ -426,15 +364,15 @@ static int set_phb_slot_name(struct slot
 
 	dn = slot->dn;
 	if (!dn) {
-		return 1;
+		return -EINVAL;
 	}
 	phb = dn->phb;
 	if (!phb) {
-		return 1;
+		return -EINVAL;
 	}
 	bus = phb->bus;
 	if (!bus) {
-		return 1;
+		return -EINVAL;
 	}
 
 	sprintf(slot->name, "%04x:%02x:%02x.%x", pci_domain_nr(bus),
@@ -444,11 +382,12 @@ static int set_phb_slot_name(struct slot
 
 static int setup_pci_slot(struct slot *slot)
 {
+	struct pci_bus *bus;
 	int rc;
 
 	if (slot->type == PHB) {
 		rc = set_phb_slot_name(slot);
-		if (rc) {
+		if (rc < 0) {
 			err("%s: failed to set phb slot name\n", __FUNCTION__);
 			goto exit_rc;
 		}
@@ -460,6 +399,12 @@ static int setup_pci_slot(struct slot *s
 					__FUNCTION__, slot->name);
 			goto exit_rc;
 		}
+
+		bus = slot->bridge->subordinate;
+		if (!bus)
+			goto exit_rc;
+		slot->dev.pci_devs = &bus->devices;
+
 		dbg("%s set slot->name to %s\n",  __FUNCTION__,
 				pci_name(slot->bridge));
 		strcpy(slot->name, pci_name(slot->bridge));
@@ -484,22 +429,15 @@ static int setup_pci_slot(struct slot *s
 				err("%s: CONFIG pci adapter failed\n", __FUNCTION__);
 				goto exit_rc;		
 			}
-		} else if (slot->hotplug_slot->info->adapter_status == CONFIGURED) {
-			if (init_slot_pci_funcs(slot)) {
-				err("%s: init_slot_pci_funcs failed\n", __FUNCTION__);
-				goto exit_rc;
-			}
 
-		} else {
+		} else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
 			err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
 				__FUNCTION__, slot->name);
 			goto exit_rc;
 		}
-		
 		print_slot_pci_funcs(slot);
-		if (!list_empty(&slot->dev.pci_funcs)) {
+		if (!list_empty(slot->dev.pci_devs)) {
 			slot->state = CONFIGURED;
-	
 		} else {
 			/* DLPAR add as opposed to 
 		 	 * boot time */
@@ -509,19 +447,18 @@ static int setup_pci_slot(struct slot *s
 	return 0;
 exit_rc:
 	dealloc_slot_struct(slot);
-	return 1;
+	return -EINVAL;
 }
 
 int register_pci_slot(struct slot *slot)
 {
-	int rc = 1;
+	int rc = -EINVAL;
 
 	slot->dev_type = PCI_DEV;
 	if ((slot->type == EMBEDDED) || (slot->type == PHB))
 		slot->removable = 0;
 	else
 		slot->removable = 1;
-	INIT_LIST_HEAD(&slot->dev.pci_funcs);
 	if (setup_pci_hotplug_slot_info(slot))
 		goto exit_rc;
 	if (setup_pci_slot(slot))
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -98,17 +98,6 @@ static void rpaphp_release_slot(struct h
 
 void dealloc_slot_struct(struct slot *slot)
 {
-	struct list_head *ln, *n;
-
-	if (slot->dev_type == PCI_DEV) {
-		list_for_each_safe (ln, n, &slot->dev.pci_funcs) {
-			struct rpaphp_pci_func *func;
-
-			func = list_entry(ln, struct rpaphp_pci_func, sibling);
-			kfree(func);
-		}
-	}
-
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
@@ -211,7 +200,7 @@ int register_slot(struct slot *slot)
 	if (is_registered(slot)) { /* should't be here */
 		err("register_slot: slot[%s] is already registered\n", slot->name);
 		rpaphp_release_slot(slot->hotplug_slot);
-		return 1;
+		return -EAGAIN;
 	}	
 	retval = pci_hp_register(slot->hotplug_slot);
 	if (retval) {
@@ -270,7 +259,7 @@ int rpaphp_set_attention_status(struct s
 
 	/* status: LED_OFF or LED_ON */
 	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
-	if (rc)
+	if (rc < 0)
 		err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
 		    slot->name, slot->location, slot->index, status, rc);
 
diff --git a/drivers/pci/hotplug/rpaphp_vio.c b/drivers/pci/hotplug/rpaphp_vio.c
--- a/drivers/pci/hotplug/rpaphp_vio.c
+++ b/drivers/pci/hotplug/rpaphp_vio.c
@@ -71,11 +71,11 @@ int register_vio_slot(struct device_node
 {
 	u32 *index;
 	char *name;
-	int rc = 1;
+	int rc = -EINVAL;
 	struct slot *slot = NULL;
 	
 	rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL);
-	if (rc)
+	if (rc < 0)
 		goto exit_rc;
 	index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
 	if (!index)
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -95,7 +95,7 @@ static struct hotplug_slot_ops shpchp_ho
  */
 static void release_slot(struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = (struct slot *)hotplug_slot->private;
+	struct slot *slot = hotplug_slot->private;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -1885,7 +1885,7 @@ int shpchp_enable_slot (struct slot *p_s
 	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
 	if (!func) {
 		dbg("%s: Error! slot NULL\n", __FUNCTION__);
-		return 1;
+		return -ENODEV;
 	}
 
 	/* Check to see if (latch closed, card present, power off) */
@@ -1894,19 +1894,19 @@ int shpchp_enable_slot (struct slot *p_s
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -1914,7 +1914,7 @@ int shpchp_enable_slot (struct slot *p_s
 
 	func = shpchp_slot_create(p_slot->bus);
 	if (func == NULL)
-		return 1;
+		return -ENOMEM;
 
 	func->bus = p_slot->bus;
 	func->device = p_slot->device;
@@ -1939,7 +1939,7 @@ int shpchp_enable_slot (struct slot *p_s
 		/* Setup slot structure with entry for empty slot */
 		func = shpchp_slot_create(p_slot->bus);
 		if (func == NULL)
-			return (1);	/* Out of memory */
+			return -ENOMEM;	/* Out of memory */
 
 		func->bus = p_slot->bus;
 		func->device = p_slot->device;
@@ -1972,7 +1972,7 @@ int shpchp_disable_slot (struct slot *p_
 	struct pci_func *func;
 
 	if (!p_slot->ctrl)
-		return 1;
+		return -ENODEV;
 
 	pci_bus = p_slot->ctrl->pci_dev->subordinate;
 
@@ -1983,19 +1983,19 @@ int shpchp_disable_slot (struct slot *p_
 	if (ret || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (ret || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (ret || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 1;
+		return -ENODEV;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -2011,7 +2011,7 @@ int shpchp_disable_slot (struct slot *p_
 		/* Check the Class Code */
 		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
 		if (rc)
-			return rc;
+			return -ENODEV;
 
 		if (class_code == PCI_BASE_CLASS_DISPLAY) {
 			/* Display/Video adapter (not supported) */
@@ -2020,13 +2020,13 @@ int shpchp_disable_slot (struct slot *p_
 			/* See if it's a bridge */
 			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 			if (rc)
-				return rc;
+				return -ENODEV;
 
 			/* If it's a bridge, check the VGA Enable bit */
 			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
 				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
 				if (rc)
-					return rc;
+					return -ENODEV;
 
 				/* If the VGA Enable bit is set, remove isn't supported */
 				if (BCR & PCI_BRIDGE_CTL_VGA) {
@@ -2042,12 +2042,12 @@ int shpchp_disable_slot (struct slot *p_
 	if ((func != NULL) && !rc) {
 		rc = remove_board(func, p_slot->ctrl);
 	} else if (!rc)
-		rc = 1;
+		rc = -ENODEV;
 
 	if (p_slot)
 		update_slot_info(p_slot);
 
-	return(rc);
+	return rc;
 }
 
 
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c
--- a/drivers/pci/hotplug/shpchprm_acpi.c
+++ b/drivers/pci/hotplug/shpchprm_acpi.c
@@ -242,10 +242,9 @@ static void acpi_run_oshp ( struct acpi_
 {
 	acpi_status		status;
 	u8			*path_name = acpi_path_name(ab->handle);
-	struct acpi_buffer	ret_buf = { 0, NULL};
 
 	/* run OSHP */
-	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
 	if (ACPI_FAILURE(status)) {
 		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
 	} else
@@ -1627,7 +1626,7 @@ int shpchprm_set_hpp(
 	pci_bus->number = func->bus;
 	devfn = PCI_DEVFN(func->device, func->function);
 
-	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
 
 	if (ab) {
 		if (ab->_hpp) {
@@ -1682,7 +1681,7 @@ void shpchprm_enable_card(
 		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
 	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
 
-	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
 	if (ab) {
 		if (ab->_hpp) {
 			if (ab->_hpp->enable_perr) {
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -20,6 +20,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 
+#include "pci.h"
 #include "msi.h"
 
 static DEFINE_SPINLOCK(msi_lock);
@@ -66,7 +67,7 @@ static void msi_set_mask_bit(unsigned in
 		int		pos;
 		u32		mask_bits;
 
-		pos = (int)entry->mask_base;
+		pos = (long)entry->mask_base;
 		pci_read_config_dword(entry->dev, pos, &mask_bits);
 		mask_bits &= ~(1);
 		mask_bits |= flag;
@@ -372,6 +373,13 @@ static int msi_init(void)
 	if (!status)
 		return status;
 
+	if (pci_msi_quirk) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -514,7 +522,7 @@ void pci_scan_msi_device(struct pci_dev 
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
  *
- * Setup the MSI capability structure of device funtion with a single
+ * Setup the MSI capability structure of device function with a single
  * MSI vector, regardless of device function is capable of handling
  * multiple messages. A return of zero indicates the successful setup
  * of an entry zero with the new MSI vector or non-zero for otherwise.
@@ -547,7 +555,7 @@ static int msi_capability_init(struct pc
 	dev->irq = vector;
 	entry->dev = dev;
 	if (is_mask_bit_support(control)) {
-		entry->mask_base = (void __iomem *)msi_mask_bits_reg(pos,
+		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
 	/* Replace with MSI handler */
@@ -591,7 +599,7 @@ static int msi_capability_init(struct pc
  * msix_capability_init - configure device's MSI-X capability
  * @dev: pointer to the pci_dev data structure of MSI-X device function
  *
- * Setup the MSI-X capability structure of device funtion with a
+ * Setup the MSI-X capability structure of device function with a
  * single MSI-X vector. A return of zero indicates the successful setup of
  * requested MSI-X entries with allocated vectors or non-zero for otherwise.
  **/
@@ -616,15 +624,10 @@ static int msix_capability_init(struct p
 	bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
 	phys_addr = pci_resource_start (dev, bir);
 	phys_addr += (u32)(table_offset & ~PCI_MSIX_FLAGS_BIRMASK);
-	if (!request_mem_region(phys_addr,
-		nr_entries * PCI_MSIX_ENTRY_SIZE,
-		"MSI-X vector table"))
-		return -ENOMEM;
 	base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
-	if (base == NULL) {
-		release_mem_region(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
+	if (base == NULL)
 		return -ENOMEM;
-	}
+
 	/* MSI-X Table Initialization */
 	for (i = 0; i < nvec; i++) {
 		entry = alloc_msi_entry();
@@ -700,12 +703,14 @@ static int msix_capability_init(struct p
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-	int pos, temp = dev->irq, status = -EINVAL;
+	int pos, temp, status = -EINVAL;
 	u16 control;
 
 	if (!pci_msi_enable || !dev)
  		return status;
 
+	temp = dev->irq;
+
 	if ((status = msi_init()) < 0)
 		return status;
 
@@ -859,8 +864,6 @@ static int msi_free_vector(struct pci_de
 			phys_addr += (u32)(table_offset &
 				~PCI_MSIX_FLAGS_BIRMASK);
 			iounmap(base);
-			release_mem_region(phys_addr,
-				nr_entries * PCI_MSIX_ENTRY_SIZE);
 		}
 	}
 
@@ -1071,7 +1074,7 @@ void pci_disable_msix(struct pci_dev* de
  * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
  * @dev: pointer to the pci_dev data structure of MSI(X) device function
  *
- * Being called during hotplug remove, from which the device funciton
+ * Being called during hotplug remove, from which the device function
  * is hot-removed. All previous assigned MSI/MSI-X vectors, if
  * allocated for this device function, are reclaimed to unused state,
  * which may be used later on.
@@ -1133,8 +1136,6 @@ void msi_remove_pci_irq_vectors(struct p
 			phys_addr += (u32)(table_offset &
 				~PCI_MSIX_FLAGS_BIRMASK);
 			iounmap(base);
-			release_mem_region(phys_addr, PCI_MSIX_ENTRY_SIZE *
-				multi_msix_capable(control));
 			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
 			       "called without free_irq() on all MSI-X vectors\n",
 			       pci_name(dev));
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -19,7 +19,7 @@
 
 static u32 ctrlset_buf[3] = {0, 0, 0};
 static u32 global_ctrlsets = 0;
-u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
+static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
 
 static acpi_status  
 acpi_query_osc (
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -49,13 +49,6 @@ pci_device_probe_dynamic(struct pci_driv
 	return error;
 }
 
-static inline void
-dynid_init(struct dynid *dynid)
-{
-	memset(dynid, 0, sizeof(*dynid));
-	INIT_LIST_HEAD(&dynid->node);
-}
-
 /**
  * store_new_id
  *
@@ -82,8 +75,9 @@ store_new_id(struct device_driver *drive
 	dynid = kmalloc(sizeof(*dynid), GFP_KERNEL);
 	if (!dynid)
 		return -ENOMEM;
-	dynid_init(dynid);
 
+	memset(dynid, 0, sizeof(*dynid));
+	INIT_LIST_HEAD(&dynid->node);
 	dynid->id.vendor = vendor;
 	dynid->id.device = device;
 	dynid->id.subvendor = subvendor;
@@ -115,7 +109,6 @@ static DRIVER_ATTR(new_id, S_IWUSR, NULL
 static inline void
 pci_init_dynids(struct pci_dynids *dynids)
 {
-	memset(dynids, 0, sizeof(*dynids));
 	spin_lock_init(&dynids->lock);
 	INIT_LIST_HEAD(&dynids->list);
 }
@@ -168,7 +161,6 @@ static inline int pci_device_probe_dynam
 {
 	return -ENODEV;
 }
-static inline void dynid_init(struct dynid *dynid) {}
 static inline void pci_init_dynids(struct pci_dynids *dynids) {}
 static inline void pci_free_dynids(struct pci_driver *drv) {}
 static inline int pci_create_newid_file(struct pci_driver *drv)
@@ -326,6 +318,14 @@ static int pci_device_resume(struct devi
 	return 0;
 }
 
+static void pci_device_shutdown(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct pci_driver *drv = pci_dev->driver;
+
+	if (drv && drv->shutdown)
+		drv->shutdown(pci_dev);
+}
 
 #define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
 #define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
@@ -381,7 +381,7 @@ pci_populate_driver_dir(struct pci_drive
  * 
  * Adds the driver structure to the list of registered drivers.
  * Returns a negative value on error, otherwise 0. 
- * If no error occured, the driver remains registered even if 
+ * If no error occurred, the driver remains registered even if 
  * no device was claimed during registration.
  */
 int pci_register_driver(struct pci_driver *drv)
@@ -393,6 +393,10 @@ int pci_register_driver(struct pci_drive
 	drv->driver.bus = &pci_bus_type;
 	drv->driver.probe = pci_device_probe;
 	drv->driver.remove = pci_device_remove;
+	/* FIXME, once all of the existing PCI drivers have been fixed to set
+	 * the pci shutdown function, this test can go away. */
+	if (!drv->driver.shutdown)
+		drv->driver.shutdown = pci_device_shutdown,
 	drv->driver.owner = drv->owner;
 	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 	pci_init_dynids(&drv->dynids);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -46,7 +46,7 @@ pci_config_attr(irq, "%u\n");
 
 static ssize_t local_cpus_show(struct device *dev, char *buf)
 {		
-	cpumask_t mask = pcibus_to_cpumask(to_pci_dev(dev)->bus->number);
+	cpumask_t mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
 	int len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
 	strcat(buf,"\n"); 
 	return 1+len;
@@ -73,6 +73,17 @@ resource_show(struct device * dev, char 
 	return (str - buf);
 }
 
+static ssize_t modalias_show(struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+
+	return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
+		       pci_dev->vendor, pci_dev->device,
+		       pci_dev->subsystem_vendor, pci_dev->subsystem_device,
+		       (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
+		       (u8)(pci_dev->class));
+}
+
 struct device_attribute pci_dev_attrs[] = {
 	__ATTR_RO(resource),
 	__ATTR_RO(vendor),
@@ -82,6 +93,7 @@ struct device_attribute pci_dev_attrs[] 
 	__ATTR_RO(class),
 	__ATTR_RO(irq),
 	__ATTR_RO(local_cpus),
+	__ATTR_RO(modalias),
 	__ATTR_NULL,
 };
 
@@ -91,6 +103,7 @@ pci_read_config(struct kobject *kobj, ch
 	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
 	unsigned int size = 64;
 	loff_t init_off = off;
+	u8 *data = (u8*) buf;
 
 	/* Several chips lock up trying to read undefined config space */
 	if (capable(CAP_SYS_ADMIN)) {
@@ -108,30 +121,47 @@ pci_read_config(struct kobject *kobj, ch
 		size = count;
 	}
 
-	while (off & 3) {
-		unsigned char val;
+	if ((off & 1) && size) {
+		u8 val;
 		pci_read_config_byte(dev, off, &val);
-		buf[off - init_off] = val;
+		data[off - init_off] = val;
 		off++;
-		if (--size == 0)
-			break;
+		size--;
+	}
+
+	if ((off & 3) && size > 2) {
+		u16 val;
+		pci_read_config_word(dev, off, &val);
+		data[off - init_off] = val & 0xff;
+		data[off - init_off + 1] = (val >> 8) & 0xff;
+		off += 2;
+		size -= 2;
 	}
 
 	while (size > 3) {
-		unsigned int val;
+		u32 val;
 		pci_read_config_dword(dev, off, &val);
-		buf[off - init_off] = val & 0xff;
-		buf[off - init_off + 1] = (val >> 8) & 0xff;
-		buf[off - init_off + 2] = (val >> 16) & 0xff;
-		buf[off - init_off + 3] = (val >> 24) & 0xff;
+		data[off - init_off] = val & 0xff;
+		data[off - init_off + 1] = (val >> 8) & 0xff;
+		data[off - init_off + 2] = (val >> 16) & 0xff;
+		data[off - init_off + 3] = (val >> 24) & 0xff;
 		off += 4;
 		size -= 4;
 	}
 
-	while (size > 0) {
-		unsigned char val;
+	if (size >= 2) {
+		u16 val;
+		pci_read_config_word(dev, off, &val);
+		data[off - init_off] = val & 0xff;
+		data[off - init_off + 1] = (val >> 8) & 0xff;
+		off += 2;
+		size -= 2;
+	}
+
+	if (size > 0) {
+		u8 val;
 		pci_read_config_byte(dev, off, &val);
-		buf[off - init_off] = val;
+		data[off - init_off] = val;
 		off++;
 		--size;
 	}
@@ -145,6 +175,7 @@ pci_write_config(struct kobject *kobj, c
 	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
 	unsigned int size = count;
 	loff_t init_off = off;
+	u8 *data = (u8*) buf;
 
 	if (off > dev->cfg_size)
 		return 0;
@@ -152,26 +183,41 @@ pci_write_config(struct kobject *kobj, c
 		size = dev->cfg_size - off;
 		count = size;
 	}
-
-	while (off & 3) {
-		pci_write_config_byte(dev, off, buf[off - init_off]);
+	
+	if ((off & 1) && size) {
+		pci_write_config_byte(dev, off, data[off - init_off]);
 		off++;
-		if (--size == 0)
-			break;
+		size--;
 	}
+	
+	if ((off & 3) && size > 2) {
+		u16 val = data[off - init_off];
+		val |= (u16) data[off - init_off + 1] << 8;
+                pci_write_config_word(dev, off, val);
+                off += 2;
+                size -= 2;
+        }
 
 	while (size > 3) {
-		unsigned int val = buf[off - init_off];
-		val |= (unsigned int) buf[off - init_off + 1] << 8;
-		val |= (unsigned int) buf[off - init_off + 2] << 16;
-		val |= (unsigned int) buf[off - init_off + 3] << 24;
+		u32 val = data[off - init_off];
+		val |= (u32) data[off - init_off + 1] << 8;
+		val |= (u32) data[off - init_off + 2] << 16;
+		val |= (u32) data[off - init_off + 3] << 24;
 		pci_write_config_dword(dev, off, val);
 		off += 4;
 		size -= 4;
 	}
+	
+	if (size >= 2) {
+		u16 val = data[off - init_off];
+		val |= (u16) data[off - init_off + 1] << 8;
+		pci_write_config_word(dev, off, val);
+		off += 2;
+		size -= 2;
+	}
 
-	while (size > 0) {
-		pci_write_config_byte(dev, off, buf[off - init_off]);
+	if (size) {
+		pci_write_config_byte(dev, off, data[off - init_off]);
 		off++;
 		--size;
 	}
@@ -481,7 +527,7 @@ static int __init pci_sysfs_init(void)
 	struct pci_dev *pdev = NULL;
 	
 	sysfs_initialized = 1;
-	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL)
+	for_each_pci_dev(pdev)
 		pci_create_sysfs_dev_files(pdev);
 
 	return 0;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -9,20 +9,15 @@
  *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
  */
 
+#include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
+#include "pci.h"
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
 
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
@@ -271,7 +266,7 @@ pci_set_power_state(struct pci_dev *dev,
 	if ((pmc & PCI_PM_CAP_VER_MASK) > 2) {
 		printk(KERN_DEBUG
 		       "PCI: %s has unsupported PM cap regs version (%u)\n",
-		       dev->slot_name, pmc & PCI_PM_CAP_VER_MASK);
+		       pci_name(dev), pmc & PCI_PM_CAP_VER_MASK);
 		return -EIO;
 	}
 
@@ -312,22 +307,24 @@ pci_set_power_state(struct pci_dev *dev,
 /**
  * pci_choose_state - Choose the power state of a PCI device
  * @dev: PCI device to be suspended
- * @state: target sleep state for the whole system
+ * @state: target sleep state for the whole system. This is the value
+ *	that is passed to suspend() function.
  *
  * Returns PCI power state suitable for given device and given system
  * message.
  */
 
-pci_power_t pci_choose_state(struct pci_dev *dev, u32 state)
+pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 {
 	if (!pci_find_capability(dev, PCI_CAP_ID_PM))
 		return PCI_D0;
 
 	switch (state) {
-	case 0:	return PCI_D0;
-	case 2: return PCI_D2;
+	case 0: return PCI_D0;
 	case 3: return PCI_D3hot;
-	default: BUG();
+	default:
+		printk("They asked me for state %d\n", state);
+		BUG();
 	}
 	return PCI_D0;
 }
@@ -402,10 +399,10 @@ pci_enable_device(struct pci_dev *dev)
 {
 	int err;
 
-	dev->is_enabled = 1;
 	if ((err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1)))
 		return err;
 	pci_fixup_device(pci_fixup_enable, dev);
+	dev->is_enabled = 1;
 	return 0;
 }
 
@@ -431,16 +428,15 @@ pci_disable_device(struct pci_dev *dev)
 {
 	u16 pci_command;
 	
-	dev->is_enabled = 0;
-	dev->is_busmaster = 0;
-
 	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
 	if (pci_command & PCI_COMMAND_MASTER) {
 		pci_command &= ~PCI_COMMAND_MASTER;
 		pci_write_config_word(dev, PCI_COMMAND, pci_command);
 	}
+	dev->is_busmaster = 0;
 
 	pcibios_disable_device(dev);
+	dev->is_enabled = 0;
 }
 
 /**
@@ -633,7 +629,7 @@ pci_set_master(struct pci_dev *dev)
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	if (! (cmd & PCI_COMMAND_MASTER)) {
-		DBG("PCI: Enabling bus mastering for device %s\n", pci_name(dev));
+		pr_debug("PCI: Enabling bus mastering for device %s\n", pci_name(dev));
 		cmd |= PCI_COMMAND_MASTER;
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
@@ -711,7 +707,7 @@ pci_set_mwi(struct pci_dev *dev)
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	if (! (cmd & PCI_COMMAND_INVALIDATE)) {
-		DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev));
+		pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev));
 		cmd |= PCI_COMMAND_INVALIDATE;
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
@@ -753,17 +749,6 @@ pci_set_dma_mask(struct pci_dev *dev, u6
 }
     
 int
-pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-	if (!pci_dac_dma_supported(dev, mask))
-		return -EIO;
-
-	dev->dma_mask = mask;
-
-	return 0;
-}
-
-int
 pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
 {
 	if (!pci_dma_supported(dev, mask))
@@ -825,7 +810,6 @@ EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
 EXPORT_SYMBOL(pci_set_dma_mask);
-EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_find_parent_resource);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -32,38 +32,17 @@ extern unsigned char pci_max_busnr(void)
 extern unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
 
-struct pci_dev_wrapped {
-	struct pci_dev	*dev;
-	void		*data;
-};
-
-struct pci_bus_wrapped {
-	struct pci_bus	*bus;
-	void		*data;
-};
-
-struct pci_visit {
-	int (* pre_visit_pci_bus)	(struct pci_bus_wrapped *,
-					 struct pci_dev_wrapped *);
-	int (* post_visit_pci_bus)	(struct pci_bus_wrapped *,
-					 struct pci_dev_wrapped *);
-
-	int (* pre_visit_pci_dev)	(struct pci_dev_wrapped *,
-					 struct pci_bus_wrapped *);
-	int (* visit_pci_dev)		(struct pci_dev_wrapped *,
-					 struct pci_bus_wrapped *);
-	int (* post_visit_pci_dev)	(struct pci_dev_wrapped *,
-					 struct pci_bus_wrapped *);
-};
-
-extern int pci_visit_dev(struct pci_visit *fn,
-			 struct pci_dev_wrapped *wrapped_dev,
-			 struct pci_bus_wrapped *wrapped_parent);
 extern void pci_remove_legacy_files(struct pci_bus *bus);
 
 /* Lock for read/write access to pci device and bus lists */
 extern spinlock_t pci_bus_lock;
 
+#ifdef CONFIG_X86_IO_APIC
+extern int pci_msi_quirk;
+#else
+#define pci_msi_quirk 0
+#endif
+
 extern int pcie_mch_quirk;
 extern struct device_attribute pci_dev_attrs[];
 extern struct class_device_attribute class_device_attr_cpuaffinity;
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -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.
 #
-#	Daily snapshot on Mon 2004-07-12 10:00:27
+#	Daily snapshot on Tue 2005-03-08 10:11:48
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -28,6 +28,9 @@
 	4001  WinTV PVR-250 (v1)
 	4009  WinTV PVR-250
 	4801  WinTV PVR-250 MCE
+0071  Nebula Electronics Ltd.
+0095  Silicon Image, Inc. (Wrong ID)
+	0680  Ultra ATA/133 IDE RAID CONTROLLER CARD
 0100  Ncipher Corp Ltd
 # 018a is not LevelOne but there is a board misprogrammed
 018a  LevelOne
@@ -41,6 +44,12 @@
 # SpeedStream is Efficient Networks, Inc, a Siemens Company
 02ac  SpeedStream
 	1012  1012 PCMCIA 10/100 Ethernet Card [RTL81xx]
+0357  TTTech AG
+	000a  TTP-Monitoring Card V2.0
+0432  SCM Microsystems, Inc.
+	0001  Pluto2 DVB-T Receiver for PCMCIA [EasyWatch MobilSet]
+05e3  CyberDoor
+	0701  CBD516
 0675  Dynalink
 	1700  IS64PH ISDN Adapter
 	1702  IS64PH ISDN Adapter
@@ -49,6 +58,9 @@
 09c1  Arris
 	0704  CM 200E Cable Modem
 0a89  BREA Technologies Inc
+0b49  ASCII Corporation
+# see http://homepage1.nifty.com/mcn/lab/machines/trance_vibrator/usbview.vib.txt
+	064f  Trance Vibrator
 0e11  Compaq Computer Corporation
 	0001  PCI to EISA Bridge
 	0002  PCI to ISA Bridge
@@ -150,6 +162,8 @@
 		0e11 4082  Smart Array 532
 		0e11 4083  Smart Array 5312
 	b1a4  NC7131 Gigabit Server Adapter
+# HP Memory Hot-Plug Controller
+	b200  Memory Hot-Plug Controller
 	b203  Integrated Lights Out Controller
 	b204  Integrated Lights Out  Processor
 	f130  NetFlex-3/P ThunderLAN 1.0
@@ -169,6 +183,7 @@
 	000a  53c1510
 		1000 1000  LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode)
 	000b  53C896/897
+		0e11 6004  EOB003 Series SCSI host adapter
 		1000 1000  LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller
 		1000 1010  LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter
 		1000 1020  LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter
@@ -191,7 +206,7 @@
 		4c53 1050  CT7 mainboard
 	0010  53C1510
 		0e11 4040  Integrated Array Controller
-		0e11 4048  Integrated Array Controller
+		0e11 4048  RAID LC2 Controller
 		1000 1000  53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode)
 	0012  53c895a
 		1000 1000  LSI53C895A PCI to Ultra2 SCSI Controller
@@ -202,6 +217,7 @@
 		1de1 1020  DC-390U3W
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
 		1000 1000  LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller
+		1000 1010  Asus TR-DLS onboard 53C1010-66
 		124b 1070  PMC-USCSI3
 		4c53 1080  CT8 mainboard
 		4c53 1300  P017 mezzanine (32-bit PMC)
@@ -209,6 +225,8 @@
 	0030  53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI
 		1028 0123  PowerEdge 2600
 		1028 014a  PowerEdge 1750
+		1028 016c  PowerEdge 1850 MPT Fusion SCSI/RAID (Perc 4)
+		1028 0183  PowerEdge 1800
 		1028 1010  LSI U320 SCSI Controller
 	0031  53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI
 	0032  53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI
@@ -226,21 +244,23 @@
 		1000 0531  MegaRAID 531 SCSI 320-4X RAID Controller
 		1000 0532  MegaRAID 532 SCSI 320-2X RAID Controller
 		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+		1028 0533  PowerEdge Expandable RAID Controller 4/QC
 		8086 0530  MegaRAID Intel RAID Controller SRCZCRX
 		8086 0532  MegaRAID Intel RAID Controller SRCU42X
 	0408  MegaRAID
 		1000 0001  MegaRAID SCSI 320-1E RAID Controller
 		1000 0002  MegaRAID SCSI 320-2E RAID Controller
-		1028 0001  Dell PowerEdge RAID Controller PERC4e/SC
-		1028 0002  Dell PowerEdge RAID Controller PERC4e/DC
+		1025 004d  MegaRAID ACER ROMB-2E RAID Controller
+		1028 0001  PowerEdge RAID Controller PERC4e/SC
+		1028 0002  PowerEdge RAID Controller PERC4e/DC
 		1734 1065  FSC MegaRAID PCI Express ROMB
 		8086 0002  MegaRAID Intel RAID Controller SRCU42E
 	0409  MegaRAID
 		1000 3004  MegaRAID SATA 300-4X RAID Controller
 		1000 3008  MegaRAID SATA 300-8X RAID Controller
-		8086 3008  MegaRAID Intel RAID Controller SRCS28X
-		8086 3431  MegaRAID Intel RAID Controller Alief SROMBU42E
-		8086 3499  MegaRAID Intel RAID Controller Harwich SROMBU42E
+		8086 3008  MegaRAID RAID Controller SRCS28X
+		8086 3431  MegaRAID RAID Controller Alief SROMBU42E
+		8086 3499  MegaRAID RAID Controller Harwich SROMBU42E
 	0621  FC909 Fibre Channel Adapter
 	0622  FC929 Fibre Channel Adapter
 		1000 1020  44929 O Dual Fibre Channel card
@@ -272,8 +292,8 @@
 		1028 0520  MegaRAID 520 DELL PERC 4/SC RAID Controller
 		1028 0531  PowerEdge Expandable RAID Controller 4/QC
 		1028 0533  PowerEdge Expandable RAID Controller 4/QC
-		8086 0520  MegaRAID Intel RAID Controller SRCU41L
-		8086 0523  MegaRAID Intel RAID Controller SRCS16
+		8086 0520  MegaRAIDRAID Controller SRCU41L
+		8086 0523  MegaRAID RAID Controller SRCS16
 1001  Kolter Electronic
 	0010  PCI 1616 Measurement card with 32 digital I/O lines
 	0011  OPTO-PCI Opto-Isolated digital I/O board
@@ -285,7 +305,13 @@
 	0017  PROTO-3 PCI Prototyping board
 	9100  INI-9100/9100W SCSI Host
 1002  ATI Technologies Inc
+	3150  M24 1P [Radeon Mobility X600]
+	3154  M24 1T [FireGL M24 GL]
+	3e50  RV380 0x3e50 [Radeon X600]
+	3e54  RV380 0x3e54 [FireGL V3200]
+	3e70  RV380 [Radeon X600] Secondary
 	4136  Radeon IGP 320 M
+	4137  Radeon IGP330/340/350
 	4144  R300 AD [Radeon 9500 Pro]
 # New PCI ID provided by ATI developer relations (correction to above)
 	4145  R300 AE [Radeon 9700 Pro]
@@ -294,19 +320,29 @@
 	4147  R300 AG [FireGL Z1/X1]
 	4148  R350 AH [Radeon 9800]
 	4149  R350 AI [Radeon 9800]
-	414b  R350 AK [Fire GL ??]
+	414a  R350 AJ [Radeon 9800]
+	414b  R350 AK [Fire GL X2]
 # New PCI ID provided by ATI developer relations
 	4150  RV350 AP [Radeon 9600]
+		1002 0002  R9600 Pro primary (Asus OEM for HP)
+		1002 0003  R9600 Pro secondary (Asus OEM for HP)
 		1458 4024  Giga-Byte GV-R96128D Primary
 		148c 2064  PowerColor R96A-C3N
 		148c 2066  PowerColor R96A-C3N
 		174b 7c19  Sapphire Atlantis Radeon 9600 Pro
 		174b 7c29  GC-R9600PRO Primary [Sapphire]
+		17ee 2002  Radeon 9600 256Mb Primary
 		18bc 0101  GC-R9600PRO Primary
 # New PCI ID provided by ATI developer relations
 	4151  RV350 AQ [Radeon 9600]
+		1043 c004  A9600SE
 # New PCI ID provided by ATI developer relations
 	4152  RV350 AR [Radeon 9600]
+		1002 0002  Radeon 9600XT
+		1043 c002  Radeon 9600 XT TVD
+		174b 7c29  Sapphire Radeon 9600XT
+		1787 4002  Radeon 9600 XT
+	4153  RV350 AS [Radeon 9600 AS]
 	4154  RV350 AT [Fire GL T2]
 	4155  RV350 AU [Fire GL T2]
 	4156  RV350 AV [Fire GL T2]
@@ -325,20 +361,43 @@
 		1458 4025  Giga-Byte GV-R96128D Secondary
 		148c 2067  PowerColor R96A-C3N (Secondary)
 		174b 7c28  GC-R9600PRO Secondary [Sapphire]
+		17ee 2003  Radeon 9600 256Mb Secondary
 		18bc 0100  GC-R9600PRO Secondary
 # New PCI ID provided by ATI developer relations (correction to above)
 	4171  RV350 AQ [Radeon 9600] (Secondary)
+		1043 c005  A9600SE (Secondary)
 # New PCI ID provided by ATI developer relations (correction to above)
 	4172  RV350 AR [Radeon 9600] (Secondary)
+		1002 0003  Radeon 9600XT (Secondary)
+		1043 c003  A9600XT (Secondary)
+		174b 7c28  Sapphire Radeon 9600XT (Secondary)
+		1787 4003  Radeon 9600 XT (Secondary)
+	4173  RV350 ?? [Radeon 9550] (Secondary)
+	4237  Radeon 7000 IGP
 	4242  R200 BB [Radeon All in Wonder 8500DV]
 		1002 02aa  Radeon 8500 AIW DV Edition
+	4243  R200 BC [Radeon All in Wonder 8500]
 	4336  Radeon Mobility U1
-	4337  Radeon IGP 340M
+		103c 0024  Pavilion ze4400 builtin Video
+	4337  Radeon IGP 330M/340M/350M
+		1014 053a  ThinkPad R40e (2684-HVG) builtin VGA controller
+		103c 0850  Radeon IGP 345M
 	4341  IXP150 AC'97 Audio Controller
-# Radeon 9100 IGP integrated
+	4345  EHCI USB Controller
+	4347  OHCI USB Controller #1
+	4348  OHCI USB Controller #2
+	4349  ATI Dual Channel Bus Master PCI IDE Controller
+	434d  IXP AC'97 Modem
 	4353  ATI SMBus
 	4354  215CT [Mach64 CT]
 	4358  210888CX [Mach64 CX]
+	4363  ATI SMBus
+	436e  ATI 436E Serial ATA Controller
+	4372  ATI SMBus
+	4376  Standard Dual Channel PCI IDE Controller ATI
+	4379  ATI 4379 Serial ATA Controller
+	437a  ATI 437A Serial ATA Controller
+	4437  Radeon Mobility 7000 IGP
 	4554  210888ET [Mach64 ET]
 	4654  Mach64 VT
 	4742  3D Rage Pro AGP 1X/2X
@@ -389,6 +448,7 @@
 		1002 8008  Rage XL
 		1028 00ce  PowerEdge 1400
 		1028 00d1  PowerEdge 2550
+		1028 00d9  PowerEdge 2500
 		8086 3411  SDS2 Mainboard
 		8086 3427  S875WP1-E mainboard
 	4753  Rage XC
@@ -406,6 +466,7 @@
 	4758  210888GX [Mach64 GX]
 	4759  3D Rage IIC
 	475a  3D Rage IIC AGP
+		1002 0084  Rage 3D Pro AGP 2x XPERT 98
 		1002 0087  Rage 3D IIC
 		1002 475a  Rage IIC AGP
 	4964  Radeon RV250 Id [Radeon 9000]
@@ -422,6 +483,15 @@
 		17af 2006  RV250 If [Excalibur Radeon 9000]
 	4967  Radeon RV250 Ig [Radeon 9000]
 	496e  Radeon RV250 [Radeon 9000] (Secondary)
+	4a48  R420 JH [Radeon X800]
+	4a49  R420 JI [Radeon X800PRO]
+	4a4a  R420 JJ [Radeon X800SE]
+	4a4b  R420 JK [Radeon X800]
+	4a4c  R420 JL [Radeon X800]
+	4a4d  R420 JM [FireGL X3]
+	4a4e  M18 JN [Radeon Mobility 9800]
+	4a50  R420 JP [Radeon X800XT]
+	4a70  R420 [X800XT-PE] (Secondary)
 	4c42  3D Rage LT Pro AGP-133
 		0e11 b0e7  Rage LT Pro (Compaq Presario 5240)
 		0e11 b0e8  Rage 3D LT Pro
@@ -447,11 +517,13 @@
 		1002 0084  Xpert 98 AGP 2X (Mobility)
 		1014 0154  ThinkPad A20m
 		1028 00aa  Latitude CPt
+		1028 00bb  Latitude CPx
 	4c4e  Rage Mobility L AGP 2x
 	4c50  3D Rage LT Pro
 		1002 4c50  Rage LT Pro
 	4c51  3D Rage LT Pro
 	4c52  Rage Mobility P/M
+		1033 8112  Versa Note VXi
 	4c53  Rage Mobility L
 	4c54  264LT [Mach64 LT]
 	4c57  Radeon Mobility M7 LW [Radeon Mobility 7500]
@@ -467,7 +539,7 @@
 	4c5a  Radeon Mobility M6 LZ
 	4c64  Radeon R250 Ld [Radeon Mobility 9000 M9]
 	4c65  Radeon R250 Le [Radeon Mobility 9000 M9]
-	4c66  Radeon R250 Lf [Radeon Mobility 9000 M9]
+	4c66  Radeon R250 Lf [FireGL 9000]
 	4c67  Radeon R250 Lg [Radeon Mobility 9000 M9]
 # Secondary chip to the Lf
 	4c6e  Radeon R250 Ln [Radeon Mobility 9000 M9] [Secondary]
@@ -488,9 +560,15 @@
 	4e4b  R350 NK [Fire GL X2]
 # New PCI ID provided by ATI developer relations
 	4e50  RV350 [Mobility Radeon 9600 M10]
-# New PCI ID provided by ATI developer relations
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1734 1055  Amilo M1420W
+	4e51  M10 NQ [Radeon Mobility 9600]
 	4e52  RV350 [Mobility Radeon 9600 M10]
+	4e53  M10 NS [Radeon Mobility 9600]
 	4e54  M10 NT [FireGL Mobility T2]
+	4e56  M11 NV [FireGL Mobility T2e]
 	4e64  Radeon R300 [Radeon 9700 Pro] (Secondary)
 	4e65  Radeon R300 [Radeon 9500 Pro] (Secondary)
 		1002 0003  Radeon R300 NE [Radeon 9500 Pro]
@@ -503,6 +581,7 @@
 # New PCI ID provided by ATI developer relations
 	4e69  Radeon R350 [Radeon 9800] (Secondary)
 	4e6a  RV350 NJ [Radeon 9800 XT] (Secondary)
+		1002 4e71  ATI Technologies Inc M10 NQ [Radeon Mobility 9600]
 	5041  Rage 128 PA/PRO
 	5042  Rage 128 PB/PRO AGP 2x
 	5043  Rage 128 PC/PRO AGP 4x
@@ -568,6 +647,7 @@
 		1002 003a  Radeon R200 QL [Radeon 8500 LE]
 		1002 013a  Radeon 8500
 		148c 2026  R200 QL [Radeon 8500 Evil Master II Multi Display Edition]
+		1681 0010  Radeon 8500 [3D Prophet 8500 128Mb]
 		174b 7149  Radeon R200 QL [Sapphire Radeon 8500 LE]
 	514d  Radeon R200 QM [Radeon 9100]
 	514e  Radeon R200 QN [Radeon 8500LE]
@@ -576,6 +656,7 @@
 	5155  R200 QU [Radeon 9100]
 	5157  Radeon RV200 QW [Radeon 7500]
 		1002 013a  Radeon 7500
+		1002 103a  Dell Optiplex GX260
 		1458 4000  RV200 QW [RADEON 7500 PRO MAYA AR]
 		148c 2024  RV200 QW [Radeon 7500LE Dual Display]
 		148c 2025  RV200 QW [Radeon 7500 Evil Master Multi Display Edition]
@@ -596,6 +677,7 @@
 		148c 2003  RV100 QY [Radeon 7000 Multi-Display Edition]
 		148c 2023  RV100 QY [Radeon 7000 Evil Master Multi-Display]
 		174b 7112  RV100 QY [Sapphire Radeon VE 7000]
+		174b 7c28  Sapphire Radeon VE 7000 DDR
 		1787 0202  RV100 QY [Excalibur Radeon 7000]
 	515a  Radeon RV100 QZ [Radeon 7000/VE]
 	5168  Radeon R200 Qh
@@ -650,29 +732,82 @@
 	5453  Rage 128 Pro Ultra TS
 	5454  Rage 128 Pro Ultra TT
 	5455  Rage 128 Pro Ultra TU
+	5460  M22 [Radeon Mobility M300]
+	5464  M22 [FireGL GL]
+	5548  R423 UH [Radeon X800 (PCIE)]
+	5549  R423 UI [Radeon X800PRO (PCIE)]
+	554a  R423 UJ [Radeon X800LE (PCIE)]
+	554b  R423 UK [Radeon X800SE (PCIE)]
+	5551  R423 UQ [FireGL V7200 (PCIE)]
+	5552  R423 UR [FireGL V5100 (PCIE)]
+	5554  R423 UT [FireGL V7100 (PCIE)]
+	556b  Radeon R423 UK (PCIE) [X800 SE] (Secondary)
 	5654  264VT [Mach64 VT]
 		1002 5654  Mach64VT Reference
 	5655  264VT3 [Mach64 VT3]
 	5656  264VT4 [Mach64 VT4]
+	5830  RS300 Host Bridge
+	5831  RS300 Host Bridge
+	5832  RS300 Host Bridge
+	5833  Radeon 9100 IGP Host Bridge
+	5834  Radeon 9100 IGP
+	5835  RS300M AGP [Radeon Mobility 9100IGP]
+	5838  Radeon 9100 IGP AGP Bridge
 	5941  RV280 [Radeon 9200] (Secondary)
+		1458 4019  Gigabyte Radeon 9200
+		174b 7c12  Sapphire Radeon 9200
 # http://www.hightech.com.hk/html/9200.htm
 		17af 200d  Excalibur Radeon 9200
 		18bc 0050  GeXcube GC-R9200-C3 (Secondary)
+	5944  RV280 [Radeon 9200 SE (PCI)]
 	5960  RV280 [Radeon 9200 PRO]
 	5961  RV280 [Radeon 9200]
+		1002 2f72  All-in-Wonder 9200 Series
+		1019 4c30  Radeon 9200 VIVO
+		12ab 5961  YUAN SMARTVGA Radeon 9200
+		1458 4018  Gigabyte Radeon 9200
+		174b 7c13  Sapphire Radeon 9200
 # http://www.hightech.com.hk/html/9200.htm
 		17af 200c  Excalibur Radeon 9200
+		18bc 0050  Radeon 9200 Game Buster
 		18bc 0051  GeXcube GC-R9200-C3
+		18bc 0053  Radeon 9200 Game Buster VIVO
+	5962  RV280 [Radeon 9200]
 	5964  RV280 [Radeon 9200 SE]
+		1043 c006  ASUS Radeon 9200 SE / TD / 128M
+		1458 4018  Radeon 9200 SE
 		148c 2073  CN-AG92E
-	5c61  RV250 5c61 [Radeon Mobility 9200 M9+]
-	5c63  RV250 5c63 [Radeon Mobility 9200 M9+]
+		174b 7c13  Sapphire Radeon 9200 SE
+		1787 5964  Excalibur 9200SE VIVO 128M
+		17af 2012  Radeon 9200 SE Excalibur
+		18bc 0170  Sapphire Radeon 9200 SE 128MB Game Buster
+# 128MB DDR, DVI/VGA/TV out
+		18bc 0173  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]
+	5b60  RV370 5B60 [Radeon X300 (PCIE)]
+		1043 002a  Extreme AX300SE-X
+		1043 032e  Extreme AX300/TD
+	5b62  RV370 5B62 [Radeon X600 (PCIE)]
+	5b64  RV370 5B64 [FireGL V3100 (PCIE)]
+	5b65  RV370 5B65 [FireGL D1100 (PCIE)]
+	5c61  M9+ 5C61 [Radeon Mobility 9200 (AGP)]
+	5c63  M9+ 5C63 [Radeon Mobility 9200 (AGP)]
 	5d44  RV280 [Radeon 9200 SE] (Secondary)
+		1458 4019  Radeon 9200 SE (Secondary)
+		174b 7c12  Sapphire Radeon 9200 SE (Secondary)
+		1787 5965  Excalibur 9200SE VIVO 128M (Secondary)
+		17af 2013  Radeon 9200 SE Excalibur (Secondary)
+		18bc 0171  Radeon 9200 SE 128MB Game Buster (Secondary)
+		18bc 0172  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]
+	5d4d  R480 [Radeon X850XT Platinum]
+	5d57  R423 5F57 [Radeon X800XT (PCIE)]
 	700f  PCI Bridge [IGP 320M]
 	7010  PCI Bridge [IGP 340M]
+	7834  Radeon 9100 PRO IGP
+	7835  Radeon Mobility 9200 IGP
 	7c37  RV350 AQ [Radeon 9600 SE]
 	cab0  AGP Bridge [IGP 320M]
 	cab2  RS200/RS200M AGP Bridge [IGP 340M]
+	cbb2  RS200/RS200M AGP Bridge [IGP 340M]
 1003  ULSI Systems
 	0201  US201
 1004  VLSI Technology Inc
@@ -726,20 +861,26 @@
 	0011  NS87560 National PCI System I/O
 	0012  USB Controller
 	0020  DP83815 (MacPhyter) Ethernet Controller
+		103c 0024  Pavilion ze4400 builtin Network
 		1385 f311  FA311 / FA312 (FA311 with WoL HW)
 	0022  DP83820 10/100/1000 Ethernet Controller
-	0028  CS5535 Host bridge
+	0028  Geode GX2 Host Bridge
+	002a  CS5535 South Bridge
 	002b  CS5535 ISA bridge
 	002d  CS5535 IDE
 	002e  CS5535 Audio
 	002f  CS5535 USB
-	0030  CS5535 Video
+	0030  Geode GX2 Graphics Processor
+	0035  DP83065 [Saturn] 10/100/1000 Ethernet Controller
 	0500  SCx200 Bridge
 	0501  SCx200 SMI
 	0502  SCx200 IDE
 	0503  SCx200 Audio
 	0504  SCx200 Video
 	0505  SCx200 XBus
+	0510  SC1100 Bridge
+	0511  SC1100 SMI
+	0515  SC1100 XBus
 	d001  87410 IDE
 100c  Tseng Labs Inc
 	3202  ET4000/W32p rev A
@@ -820,6 +961,7 @@
 		1385 2100  FA510
 		1395 0001  10/100 Ethernet CardBus PC Card
 		13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)
+		14cb 0100  LNDL-100N 100Base-TX Ethernet PC Card
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
 	001a  Farallon PN9000SX Gigabit Ethernet
 	0021  DECchip 21052
@@ -875,11 +1017,13 @@
 	1200  GD 7542 [Nordic]
 	1202  GD 7543 [Viking]
 	1204  GD 7541 [Nordic Light]
+	4000  MD 5620 [CLM Data Fax Voice]
 	4400  CD 4400
 	6001  CS 4610/11 [CrystalClear SoundFusion Audio Accelerator]
 		1014 1010  CS4610 SoundFusion Audio Accelerator
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 		1013 4280  Crystal SoundFusion PCI Audio Accelerator
+		153b 1136  SiXPack 5.1+
 		1681 0050  Game Theater XP
 		1681 a011  Fortissimo III 7.1
 	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
@@ -915,6 +1059,7 @@
 # AS400 iSeries PCI sync serial card
 		1014 0031  2721 WAN IOA - 2 Port Sync Serial Adapter
 	0036  Miami
+	0037  82660 CPU to PCI Bridge
 	003a  CPU to PCI Bridge
 	003c  GXT250P/GXT255P Graphics Adapter
 	003e  16/4 Token ring UTP/STP controller
@@ -940,6 +1085,7 @@
 	005e  GXT800P Graphics Adapter
 	007c  ATM Controller (14107c00)
 	007d  3780IDSP [MWave]
+	008b  EADS PCI to PCI Bridge
 	008e  GXT3000P Graphics Adapter
 	0090  GXT 3000P
 		1014 008e  GXT-3000P
@@ -953,6 +1099,7 @@
 	00a5  ATM Controller (1410a500)
 	00a6  ATM 155MBPS MM Controller (1410a600)
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
+		1092 00b8  FireGL1 AGP 32Mb
 	00b8  GXT2000P Graphics Adapter
 	00be  ATM 622MBPS Controller (1410be00)
 	00dc  Advanced Systems Management Adapter (ASMA)
@@ -973,7 +1120,7 @@
 	0180  Snipe chipset SCSI controller
 		1014 0241  iSeries 2757 DASD IOA
 		1014 0264  Quad Channel PCI-X U320 SCSI RAID Adapter (2780)
-		1014 02BD  Quad Channel PCI-X U320 DDR SCSI RAID Adapter (570F)
+	0188  EADS-X PCI-X to PCI-X Bridge
 	01a7  PCI-X to PCI-X Bridge
 	01bd  ServeRAID Controller
 		1014 01be  ServeRAID-4M
@@ -996,9 +1143,12 @@
 	0266  PCI-X Dual Channel SCSI
 	0268  Gigabit Ethernet-SX Adapter (PCI-X)
 	0269  10/100/1000 Base-TX Ethernet Adapter (PCI-X)
-	028C  Citrine chipset SCSI controller
-		1014 02BE  Dual Channel PCI-X U320 DDR SCSI RAID Adapter (571B)
+	028c  Citrine chipset SCSI controller
+		1014 028D  Dual Channel PCI-X DDR SAS RAID Adapter (572E)
+		1014 02BE  Dual Channel PCI-X DDR U320 SCSI RAID Adapter (571B)
+		1014 02C0  Dual Channel PCI-X DDR U320 SCSI Adapter (571A)
 	0302  X-Architecture Bridge [Summit]
+	0314  ZISC 036 Neural accelerator card
 	ffff  MPIC-2 interrupt controller
 1015  LSI Logic Corp of Canada
 1016  ICL Personal Systems
@@ -1048,10 +1198,10 @@
 1020  Hitachi Computer Products
 1021  OKI Electric Industry Co. Ltd.
 1022  Advanced Micro Devices [AMD]
-	1100  K8 NorthBridge
-	1101  K8 NorthBridge
-	1102  K8 NorthBridge
-	1103  K8 NorthBridge
+	1100  K8 [Athlon64/Opteron] HyperTransport Technology Configuration
+	1101  K8 [Athlon64/Opteron] Address Map
+	1102  K8 [Athlon64/Opteron] DRAM Controller
+	1103  K8 [Athlon64/Opteron] Miscellaneous Control
 	2000  79c970 [PCnet32 LANCE]
 		1014 2000  NetFinity 10/100 Fast Ethernet
 		1022 2000  PCnet - Fast 79C971
@@ -1081,6 +1231,8 @@
 	3000  ELanSC520 Microcontroller
 	7006  AMD-751 [Irongate] System Controller
 	7007  AMD-751 [Irongate] AGP Bridge
+	700a  AMD-IGR4 AGP Host to PCI Bridge
+	700b  AMD-IGR4 PCI to PCI Bridge
 	700c  AMD-760 MP [IGD4-2P] System Controller
 	700d  AMD-760 MP [IGD4-2P] AGP Bridge
 	700e  AMD-760 [IGD4-1P] System Controller
@@ -1133,6 +1285,7 @@
 	2001  4DWave NX
 		122d 1400  Trident PCI288-Q3DII (NX)
 	2100  CyberBlade XP4m32
+	2200  XGI Volari XP5
 	8400  CyberBlade/i7
 		1023 8400  CyberBlade i7 AGP
 	8420  CyberBlade/i7d
@@ -1209,6 +1362,8 @@
 	1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]
 	1641  M1641 Northbridge [Aladdin-Pro IV]
 	1647  M1647 [MaGiK1] PCI North Bridge
+	1671  M1671 Northbridge [ALADDiN-P4]
+	1672  Northbridge [CyberALADDiN-P4]
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -1353,6 +1508,7 @@
 		102b 07c1  Millennium G450 SDR Dual Head LE
 		102b 0d41  Millennium G450 Dual Head PCI
 		102b 0d42  Millennium G450 Dual Head LX PCI
+		102b 0d43  Millennium G450 32Mb Dual Head PCI
 		102b 0e00  Marvel G450 eTV
 		102b 0e01  Marvel G450 eTV
 		102b 0e02  Marvel G450 eTV
@@ -1436,13 +1592,18 @@
 102e  Olivetti Advanced Technology
 102f  Toshiba America
 	0009  r4x00
+	000a  TX3927 MIPS RISC PCI Controller
 	0020  ATM Meteor 155
 		102f 00f8  ATM Meteor 155
+	0030  TC35815CF PCI 10/100 Mbit Ethernet Controller
+	0031  TC35815CF PCI 10/100 Mbit Ethernet Controller with WOL
 	0105  TC86C001 [goku-s] IDE
 	0106  TC86C001 [goku-s] USB 1.1 Host
 	0107  TC86C001 [goku-s] USB Device Controller
 	0108  TC86C001 [goku-s] I2C/SIO/GPIO Controller
-	0180  TX4927
+	0180  TX4927/38 MIPS RISC PCI Controller
+	0181  TX4925 MIPS RISC PCI Controller
+	0182  TX4937 MIPS RISC PCI Controller
 1030  TMC Research
 1031  Miro Computer Products AG
 	5601  DC20 ASIC
@@ -1487,6 +1648,7 @@
 		1010 00a0  PowerVR Neon 250 AGP 32Mb
 		1010 00a8  PowerVR Neon 250 32Mb
 		1010 0120  PowerVR Neon 250 AGP 32Mb
+	0072  uPD72874 IEEE1394 OHCI 1.1 3-port PHY-Link Ctrlr
 	0074  56k Voice Modem
 		1033 8014  RCV56ACF 56k Voice Modem
 	009b  Vrc5476
@@ -1517,7 +1679,12 @@
 	0006  85C501/2/3
 	0008  SiS85C503/5513 (LPC Bridge)
 	0009  ACPI
+# source: http://members.datafast.net.au/dft0802/downloads/pcidevs.txt
+	0016  SiS961/2 SMBus Controller
 	0018  SiS85C503/5513 (LPC Bridge)
+# Controller for 2 PATA and 2 SATA channels
+	0180  RAID bus controller 180 SATA/PATA  [SiS]
+	0181  SiS SATA
 	0200  5597/5598/6326 VGA
 		1039 0000  SiS5597 SVGA (Shared RAM)
 	0204  82C204
@@ -1557,6 +1724,7 @@
 	0755  755 Host
 	0760  760/M760 Host
 	0900  SiS900 PCI Fast Ethernet
+		1019 0a14  K7S5A motherboard
 		1039 0900  SiS900 10/100 Ethernet Adapter
 		1043 8035  CUSI-FX motherboard
 	0961  SiS961 [MuTIOL Media IO]
@@ -1575,7 +1743,6 @@
 		1039 5513  SiS5513 EIDE Controller (A,B step)
 		1043 8035  CUSI-FX motherboard
 	5517  5517
-	5518  5518 [IDE]
 	5571  5571
 	5581  5581 Pentium Chipset
 	5582  5582
@@ -1599,9 +1766,10 @@
 		1092 4910  SpeedStar A70
 		1092 4920  SpeedStar A70
 		1569 6326  SiS6326 GUI Accelerator
-	6330  661FX/M661FX/M661MX/741/M741/760/M760 PCI/AGP
-		1039 6330  [M]661FX/M661MX/[M]741/[M]760 PCI/AGP VGA Display Adapter
+	6330  661/741/760 PCI/AGP VGA Display Adapter
+		1039 6330  [M]661xX/[M]741[GX]/[M]760 PCI/AGP VGA Adapter
 	7001  USB 1.0 Controller
+		1019 0a14  K7S5A motherboard
 		1039 7000  Onboard USB Controller
 	7002  USB 2.0 Controller
 		1509 7002  Onboard USB Controller
@@ -1667,11 +1835,14 @@
 		103c 1226  Keystone SP2
 		103c 1227  Powerbar SP2
 		103c 1282  Everest SP2
+		103c 1301  Diva RMP3
 	1054  PCI Local Bus Adapter
 	1064  79C970 PCnet Ethernet Controller
 	108b  Visualize FXe
 	10c1  NetServer Smart IRQ Router
 	10ed  TopTools Remote Control
+	10f0  rio System Bus Adapter
+	10f1  rio I/O Controller
 	1200  82557B 10/100 NIC
 	1219  NetServer PCI Hot-Plug Controller
 	121a  NetServer SMIC Controller
@@ -1682,6 +1853,7 @@
 	122e  zx1 Local Bus Adapter
 	127c  sx1000 I/O Controller
 	1290  Auxiliary Diva Serial Port
+	12b4  zx1 QuickSilver AGP8x Local Bus Adapter
 	2910  E2910A PCIBus Exerciser
 	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
@@ -1694,13 +1866,16 @@
 	3000  Samurai_0
 	3010  Samurai_1
 	3020  Samurai_IDE
-1043  Asustek Computer, Inc.
+1043  ASUSTeK Computer Inc.
 	0675  ISDNLink P-IN100-ST-D
 	4015  v7100 SDRAM [GeForce2 MX]
 	4021  v7100 Combo Deluxe [GeForce2 MX + TV tuner]
 	4057  v8200 GeForce 3
 	8043  v8240 PAL 128M [P4T] Motherboard
 	807b  v9280/TD [Geforce4 TI4200 8X With TV-Out and DVI]
+	80bb  v9180 Magic/T [GeForce4 MX440 AGP 8x 64MB TV-out]
+	80c5  nForce3 chipset motherboard [SK8N]
+	80df  v9520 Magic/T
 1044  Adaptec (formerly DPT)
 	1012  Domino RAID Engine
 	a400  SmartCache/Raid I-IV Controller
@@ -1739,7 +1914,7 @@
 		1044 c05a  2400A UDMA Four Channel
 		1044 c05b  2400A UDMA Four Channel DAC
 		1044 c064  3010S Ultra3 Dual Channel
-		1044 c065  3010S Ultra3 Four Channel
+		1044 c065  3410S Ultra160 Four Channel
 		1044 c066  3010S Fibre Channel
 	a511  SmartRAID V Controller
 		1044 c032  ASR-2005S I2O Zero Channel
@@ -1769,9 +1944,11 @@
 1046  IPC Corporation, Ltd.
 1047  Genoa Systems Corp
 1048  Elsa AG
+	0c60  Gladiac MX
 	0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]
 	1000  QuickStep 1000
 	3000  QuickStep 3000
+	8901  Gloria XL
 1049  Fountain Technologies, Inc.
 # # nee SGS Thomson Microelectronics
 104a  STMicroelectronics
@@ -1834,22 +2011,37 @@
 		11bd 000e  Studio DV
 		e4bf 1010  CF2-1-CYMBAL
 	8020  TSB12LV26 IEEE-1394 Controller (Link)
+		11bd 000f  Studio DV500-1394
 	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
 		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)
+		103c 088c  nc8000 laptop
 	8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
 	8025  TSB82AA2 IEEE-1394b Link Layer Controller
+		55aa 55aa  FireWire 800 PCI Card
 	8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)
 	8027  PCI4451 IEEE-1394 Controller
 		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
 	8029  PCI4510 IEEE-1394 Controller
+		1028 0163  Latitude D505
 		1071 8160  MIM2900
+	802b  PCI7410,7510,7610 OHCI-Lynx Controller
+		1028 014e  PCI7410,7510,7610 OHCI-Lynx Controller (Dell Latitude D800)
 	802e  PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller
+	8031  Texas Instruments PCIxx21/x515 Cardbus Controller
+	8032  Texas Instruments OHCI Compliant IEEE 1394 Host Controller
+	8033  Texas Instruments PCIxx21 Integrated FlashMedia Controller
+	8034  Texas Instruments PCI6411, PCI6421, PCI6611, PCI6621, PCI7411, PCI7421, PCI7611, PCI7621 Secure Digital (SD) Controller
+	8035  Texas Instruments PCI6411, PCI6421, PCI6611, PCI6621, PCI7411, PCI7421, PCI7611, PCI7621 Smart Card Controller (SMC)
+	8201  PCI1620 Firmware Loading Function
+	8204  PCI7410,7510,7610 PCI Firmware Loading Function
+		1028 014e  Latitude D800
 	8400  ACX 100 22Mbps Wireless Interface
 		00fc 16ec  U.S. Robotics 22 Mbps Wireless PC Card (model 2210)
 		00fd 16ec  U.S. Robotics 22Mbps Wireless PCI Adapter (model 2216)
+		1186 3b00  DWL-650+ PC Card cardbus 22Mbs Wireless Adapter [AirPlus]
 		1186 3b01  DWL-520+ 22Mbps PCI Wireless Adapter
 	8401  ACX 100 22Mbps Wireless Interface
 # OK, this info is almost useless as is, but at least it's known that it's a wireless card. More info requested from reporter (whi
@@ -1891,30 +2083,39 @@
 	ac42  PCI4451 PC card Cardbus Controller
 		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
 	ac44  PCI4510 PC card Cardbus Controller
+		1028 0163  Latitude D505
 		1071 8160  MIM2000
 	ac46  PCI4520 PC card Cardbus Controller
+	ac47  PCI7510 PC card Cardbus Controller
+		1028 014e  Latitude D800
+	ac4a  PCI7510,7610 PC card Cardbus Controller
+		1028 014e  Latitude D800
 	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
 		1014 023b  ThinkPad T23 (2647-4MG)
 		1028 00b1  Latitude C600
 		1028 012a  Latitude C640
+		1033 80cd  Versa Note VXi
 		10cf 1095  Lifebook C6155
 		e4bf 1000  CP2-2-HIPHOP
 	ac52  PCI1451 PC card Cardbus Controller
 	ac53  PCI1421 PC card Cardbus Controller
+	ac54  PCI1620 PC Card Controller
 	ac55  PCI1520 PC card Cardbus Controller
 		1014 0512  ThinkPad T30/T40
 	ac56  PCI1510 PC card Cardbus Controller
+		1014 0528  ThinkPad R40e (2684-HVG) Cardbus Controller
 	ac60  PCI2040 PCI to DSP Bridge Controller
 		175c 5100  ASI51xx Audio Adapter
 		175c 6100  ASI61xx Audio Adapter
 		175c 6200  ASI62xx Audio Adapter
 	ac8d  PCI 7620
 	ac8e  PCI7420 CardBus Controller
-	ac8f  PCI7420 Flash Media Controller
+	ac8f  PCI7420/PCI7620 Dual Socket CardBus and Smart Card Cont. w/ 1394a-2000 OHCI Two-Port  PHY/Link-Layer Cont. and SD/MS-Pro Sockets
 	fe00  FireWire Host Controller
 	fe03  12C01A FireWire Host Controller
 104d  Sony Corporation
+	8004  DTL-H2500 [Playstation development board]
 	8009  CXD1947Q i.LINK Controller
 	8039  CXD3222 i.LINK Controller
 	8056  Rockwell HCF 56K modem
@@ -1937,6 +2138,8 @@
 	0940  W89C940
 	5a5a  W89C940F
 	6692  W6692
+	9921  W99200F MPEG-1 Video Encoder
+	9922  W99200F/W9922PF MPEG-1/2 Video Encoder
 	9970  W9970CF
 1051  Anigma, Inc.
 1052  ?Young Micro Systems
@@ -1973,8 +2176,32 @@
 		175c 4200  ASI4215 Audio Adapter
 		175c 4300  ASI43xx Audio Adapter
 		175c 4400  ASI4401 Audio Adapter
-		ecc0 0030  Layla
+		ecc0 0010  Darla
+		ecc0 0020  Gina
+		ecc0 0030  Layla rev.0
+		ecc0 0031  Layla rev.1
+		ecc0 0040  Darla24 rev.0
+		ecc0 0041  Darla24 rev.1
+		ecc0 0050  Gina24 rev.0
+		ecc0 0051  Gina24 rev.1
+		ecc0 0070  Mona rev.0
+		ecc0 0071  Mona rev.1
+		ecc0 0072  Mona rev.2
 	18c0  MPC8265A/MPC8266
+	18c1  MPC8271/MPC8272
+	3410  DSP56361 Digital Signal Processor
+		ecc0 0050  Gina24 rev.0
+		ecc0 0051  Gina24 rev.1
+		ecc0 0060  Layla24
+		ecc0 0070  Mona rev.0
+		ecc0 0071  Mona rev.1
+		ecc0 0072  Mona rev.2
+		ecc0 0080  Mia rev.0
+		ecc0 0081  Mia rev.1
+		ecc0 0090  Indigo
+		ecc0 00a0  Indigo IO
+		ecc0 00b0  Indigo DJ
+		ecc0 0100  3G
 	4801  Raven
 	4802  Falcon
 	4803  Hawk
@@ -1998,7 +2225,9 @@
 		14c8 0302  SM56 PCI Fax Modem
 		1668 0300  SM56 PCI Speakerphone Modem
 		1668 0302  SM56 PCI Fax Modem
+	5803  MPC5200
 	6400  MPC190 Security Processor (S1 family, encryption)
+	6405  MPC184 Security Processor (S1 family)
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
@@ -2013,11 +2242,14 @@
 		8086 3427  S875WP1-E mainboard
 	3371  PDC20371 (FastTrak S150 TX2plus)
 	3373  PDC20378 (FastTrak 378/SATA 378)
-		1043 80f5  PC-DL Deluxe motherboard
+		1043 80f5  K8V Deluxe/PC-DL Deluxe motherboard
 		1462 702e  K8T NEO FIS2R motherboard
 	3375  PDC20375 (SATA150 TX2plus)
 	3376  PDC20376 (FastTrak 376)
 		1043 809e  A7V8X motherboard
+	3574  PDC20579 SATAII 150 IDE Controller
+	3d18  PDC20518/PDC40518 (SATAII 150 TX4)
+	3d75  PDC20575 (SATAII150 TX2plus)
 	4d30  PDC20267 (FastTrak100/Ultra100)
 		105a 4d33  Ultra100
 		105a 4d39  FastTrak100
@@ -2138,8 +2370,8 @@
 		1014 0242  iSeries 2872 DASD IOA
 		1014 0266  Dual Channel PCI-X U320 SCSI Adapter
 		1014 0278  Dual Channel PCI-X U320 SCSI RAID Adapter
-		1014 02D3  Dual Channel PCI-X U320 SCSI Adapter
-		1014 02D4  Dual Channel PCI-X U320 SCSI RAID Adapter
+		1014 02d3  Dual Channel PCI-X U320 SCSI Adapter
+		1014 02d4  Dual Channel PCI-X U320 SCSI RAID Adapter
 	ba55  eXtremeRAID 1100 support Device
 	ba56  eXtremeRAID 2000/3000 support Device
 106a  Aten Research Inc
@@ -2149,6 +2381,7 @@
 	0003  Control Video
 	0004  PlanB Video-In
 	0007  O'Hare I/O
+	000c  DOS on Mac
 	000e  Hydra Mac I/O
 	0010  Heathrow Mac I/O
 	0017  Paddington Mac I/O
@@ -2189,8 +2422,16 @@
 	0049  K2 HT-PCI Bridge
 	004b  U3 AGP
 	004c  K2 GMAC (Sun GEM)
+	004f  Shasta Mac I/O
+	0050  Shasta IDE
+	0051  Shasta (Sun GEM)
+	0052  Shasta Firewire
+	0053  Shasta PCI Bridge
+	0054  Shasta PCI Bridge
+	0055  Shasta PCI Bridge
+	0058  U3L AGP Bridge
 	1645  Tigon3 Gigabit Ethernet NIC (BCM5701)
-106c  Hyundai Electronics America
+106c  Hynix Semiconductor
 	8801  Dual Pentium ISA/PCI Motherboard
 	8802  PowerPC ISA/PCI Motherboard
 	8803  Dual Window Graphics Accelerator
@@ -2270,6 +2511,7 @@
 107d  LeadTek Research Inc.
 	0000  P86C850
 	2134  WinFast 3D S320 II
+	2971  [GeForce FX 5900] WinFast A350 TDH MyViVo
 107e  Interphase Corporation
 	0001  5515 ATM Adapter [Flipper]
 	0002  100 VG AnyLan Controller
@@ -2339,14 +2581,17 @@
 	1101  RIO GEM
 	1102  RIO 1394
 	1103  RIO USB
+	1648  [bge] Gigabit Ethernet
 	2bad  GEM
 	5000  Simba Advanced PCI Bridge
 	5043  SunPCI Co-processor
 	8000  Psycho PCI Bus Module
 	8001  Schizo PCI Bus Module
+	8002  Schizo+ PCI Bus Module
 	a000  Ultra IIi
 	a001  Ultra IIe
 	a801  Tomatillo PCI Bus Module
+	abba  Cassini 10/100/1000
 108f  Systemsoft
 1090  Encore Computer Corporation
 1091  Intergraph Corporation
@@ -2357,6 +2602,8 @@
 	0060  Proprietary bus bridge
 	00e4  Powerstorm 4D50T
 	0720  Motion JPEG codec
+	07a0  Sun Expert3D-Lite Graphics Accelerator
+	1091  Sun Expert3D Graphics Accelerator
 1092  Diamond Multimedia Systems
 	00a0  Speedstar Pro SE
 	00a8  Speedstar 64
@@ -2384,11 +2631,23 @@
 	1170  PCI-MIO-16XE-10
 	1180  PCI-MIO-16E-1
 	1190  PCI-MIO-16E-4
+	1310  PCI-6602
 	1330  PCI-6031E
 	1350  PCI-6071E
+	14e0  PCI-6110
+	14f0  PCI-6111
 	17d0  PCI-6503
+	1870  PCI-6713
+	1880  PCI-6711
+	18b0  PCI-6052E
 	2410  PCI-6733
+	2890  PCI-6036E
 	2a60  PCI-6023E
+	2a70  PCI-6024E
+	2a80  PCI-6025E
+	2c80  PCI-6035E
+	2ca0  PCI-6034E
+	70b8  PCI-6251 [M Series - High Speed Multifunction DAQ]
 	b001  IMAQ-PCI-1408
 	b011  IMAQ-PXI-1408
 	b021  IMAQ-PCI-1424
@@ -2403,13 +2662,13 @@
 	c831  PCI-GPIB bridge
 1094  First International Computers [FIC]
 1095  Silicon Image, Inc. (formerly CMD Technology Inc)
-	0240  Adaptec AAR-1210SA SATA HostRAID
+	0240  Adaptec AAR-1210SA SATA HostRAID Controller
 	0640  PCI0640
 	0643  PCI0643
 	0646  PCI0646
 	0647  PCI0647
 	0648  PCI0648
-	0649  PCI0649
+	0649  SiI 0649 Ultra ATA/100 PCI to ATA Host Controller
 		0e11 005d  Integrated Ultra ATA-100 Dual Channel Controller
 		0e11 007e  Integrated Ultra ATA-100 IDE RAID Controller
 		101e 0649  AMI MegaRAID IDE 100 Controller
@@ -2420,9 +2679,16 @@
 	0680  PCI0680 Ultra ATA-133 Host Controller
 		1095 3680  Winic W-680 (Silicon Image 680 based)
 	3112  SiI 3112 [SATALink/SATARaid] Serial ATA Controller
-		1095 6112  Asus A7N8X
+		1095 3112  SiI 3112 SATALink Controller
+		1095 6112  SiI 3112 SATARaid Controller
 	3114  SiI 3114 [SATALink/SATARaid] Serial ATA Controller
+		1095 3114  SiI 3114 SATALink Controller
+		1095 6114  SiI 3114 SATARaid Controller
+	3124  SiI 3124 PCI-X Serial ATA Controller
+		1095 3124  SiI 3124 PCI-X Serial ATA Controller
 	3512  SiI 3512 [SATALink/SATARaid] Serial ATA Controller
+		1095 3512  SiI 3512 SATALink Controller
+		1095 6512  SiI 3512 SATARaid Controller
 1096  Alacron
 1097  Appian Technology
 1098  Quantum Designs (H.K.) Ltd
@@ -2444,6 +2710,7 @@
 	036e  Bt878 Video Capture
 		0070 13eb  WinTV Series
 		0070 ff01  Viewcast Osprey 200
+		0071 0101  DigiTV PCI
 		107d 6606  WinFast TV 2000
 		11bd 0012  PCTV pro (TV + FM stereo receiver)
 		11bd 001c  PCTV Sat (DBC receiver)
@@ -2453,7 +2720,9 @@
 		127a 0048  Bt878/832 Mediastream Controller
 		144f 3000  MagicTView CPH060 - Video
 		1461 0002  TV98 Series (TV/No FM/Remote)
+		1461 0003  AverMedia UltraTV PCI 350
 		1461 0004  AVerTV WDM Video Capture
+		1461 0761  AverTV DVB-T
 		14f1 0001  Bt878 Mediastream Controller NTSC
 		14f1 0002  Bt878 Mediastream Controller PAL BG
 		14f1 0003  Bt878a Mediastream Controller PAL BG
@@ -2462,6 +2731,7 @@
 		1851 1850  FlyVideo'98 - Video
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
+		270f fc00  Digitop DTT-1000
 		bd11 1200  PCTV pro (TV + FM stereo receiver)
 	036f  Bt879 Video Capture
 		127a 0044  Bt879 Video Capture NTSC
@@ -2500,6 +2770,7 @@
 	0878  Bt878 Audio Capture
 		0070 13eb  WinTV Series
 		0070 ff01  Viewcast Osprey 200
+		0071 0101  DigiTV PCI
 		1002 0001  TV-Wonder
 		1002 0003  TV-Wonder/VE
 		11bd 0012  PCTV pro (TV + FM stereo receiver, audio section)
@@ -2511,11 +2782,13 @@
 		13e9 0070  Win/TV (Audio Section)
 		144f 3000  MagicTView CPH060 - Audio
 		1461 0004  AVerTV WDM Audio Capture
+		1461 0761  AVerTV DVB-T
 		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)
 		1822 0001  VisionPlus DVB Card
+		270f fc00  Digitop DTT-1000
 		bd11 1200  PCTV pro (TV + FM stereo receiver, audio section)
 	0879  Bt879 Audio Capture
 		127a 0044  Bt879 Video Capture (Audio Section)
@@ -2623,20 +2896,27 @@
 	1146  VScom 010 1 port parallel adaptor
 	1147  VScom 020 2 port parallel adaptor
 	2724  Thales PCSM Security Card
+	8516  PEX 8516  Versatile PCI Express Switch
+	8532  PEX 8532  Versatile PCI Express Switch
 	9030  PCI <-> IOBus Bridge Hot Swap
 		10b5 2862  Alpermann+Velte PCL PCI LV (3V/5V): Timecode Reader Board
 		10b5 2906  Alpermann+Velte PCI TS (3V/5V): Time Synchronisation Board
 		10b5 2940  Alpermann+Velte PCL PCI D (3V/5V): Timecode Reader Board
+		10b5 3025  Alpermann+Velte PCL PCI L (3V/5V): Timecode Reader Board
+		10b5 3068  Alpermann+Velte PCL PCI HD (3V/5V): Timecode Reader Board
 		15ed 1002  MCCS 8-port Serial Hot Swap
 		15ed 1003  MCCS 16-port Serial Hot Swap
 	9036  9036
 	9050  PCI <-> IOBus Bridge
+		10b5 1067  IXXAT CAN i165
+		10b5 1172  IK220 (Heidenhain)
 		10b5 2036  SatPak GPS
 		10b5 2221  Alpermann+Velte PCL PCI LV: Timecode Reader Board
 		10b5 2273  SH-ARC SoHard ARCnet card
 		10b5 2431  Alpermann+Velte PCL PCI D: Timecode Reader Board
 		10b5 2905  Alpermann+Velte PCI TS: Time Synchronisation Board
 		10b5 9050  MP9050
+		1498 0362  TPMC866 8 Channel Serial 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
@@ -2689,6 +2969,8 @@
 		125c 0640  Aries 16000P
 	906e  9060ES
 	9080  9080
+		103c 10eb  (Agilent) E2777B 83K Series PCI based Optical Communication Interface
+		103c 10ec  (Agilent) E6978-66442 PCI CIC
 		10b5 9080  9080 [real subsystem ID not set]
 		129d 0002  Aculab PCI Prosidy card
 		12d9 0002  PCI Prosody Card
@@ -2721,6 +3003,8 @@
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
 	0001  3c985 1000BaseSX (SX/TX)
+	0013  AR5212 802.11abg NIC (3CRDAG675)
+		10b7 2031  3CRDAG675 11a/b/g Wireless PCI Adapter
 	0910  3C910-A01
 	1006  MINI PCI type 3B Data Fax Modem
 	1007  Mini PCI 56k Winmodem
@@ -2728,9 +3012,10 @@
 	1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
 	1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
 	1700  3c940 10/100/1000Base-T [Marvell]
-		1043 80eb  P4P800 Mainboard
+		1043 80eb  P4P800/K8V Deluxe motherboard
 		10b7 0010  3C940 Gigabit LOM Ethernet Adapter
 		10b7 0020  3C941 Gigabit LOM Ethernet Adapter
+		147b 1407  KV8-MAX3 motherboard
 	3390  3c339 TokenLink Velocity
 	3590  3c359 TokenLink Velocity XL
 		10b7 3590  TokenLink Velocity XL Adapter (3C359/359B)
@@ -2769,6 +3054,7 @@
 	7940  3c803 FDDILink UTP Controller
 	7980  3c804 FDDILink SAS Controller
 	7990  3c805 FDDILink DAS Controller
+	80eb  3c940B 10/100/1000Base-T
 	8811  Token ring
 	9000  3c900 10BaseT [Boomerang]
 	9001  3c900 10Mbps Combo [Boomerang]
@@ -2808,6 +3094,7 @@
 	9200  3c905C-TX/TX-M [Tornado]
 		1028 0095  3C920 Integrated Fast Ethernet Controller
 		1028 0097  3C920 Integrated Fast Ethernet Controller
+		1028 00fe  Optiplex GX240
 		1028 012a  3C920 Integrated Fast Ethernet Controller [Latitude C640]
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 7000  10/100 Mini PCI Ethernet Adapter
@@ -2820,6 +3107,8 @@
 	9800  3c980-TX Fast Etherlink XL Server Adapter [Cyclone]
 		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
 	9805  3c980-C 10/100baseTX NIC [Python-T]
+		10b7 1201  EtherLink Server 10/100 Dual Port A
+		10b7 1202  EtherLink Server 10/100 Dual Port B
 		10b7 9805  3c980 10/100baseTX NIC [Python-T]
 		10f1 2462  Thunder K7 S2462
 	9900  3C990-TX [Typhoon]
@@ -2861,8 +3150,11 @@
 	a011  83C170QF
 	b106  SMC34C90
 10b9  ALi Corporation
+	0101  CMI8338/C3DX PCI Audio Device
 	0111  C-Media CMI8738/C3DX Audio Device (OEM)
 		10b9 0111  C-Media CMI8738/C3DX Audio Device (OEM)
+	0780  Multi-IO Card
+	0782  Multi-IO Card
 	1435  M1435
 	1445  M1445
 	1449  M1449
@@ -2878,6 +3170,7 @@
 		10b9 1523  ALI M1523 ISA Bridge
 	1531  M1531 [Aladdin IV]
 	1533  M1533 PCI to ISA Bridge [Aladdin IV]
+		1014 053b  ThinkPad R40e (2684-HVG) PCI to ISA Bridge
 		10b9 1533  ALI M1533 Aladdin IV ISA Bridge
 	1541  M1541
 		10b9 1541  ALI M1541 Aladdin V/V+ AGP System Controller
@@ -2892,8 +3185,10 @@
 	1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]
 	1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]
 	1671  M1671 Super P4 Northbridge [AGP4X,PCI and SDR/DDR]
+	1672  M1672 Northbridge [CyberALADDiN-P4]
 	1681  M1681 P4 Northbridge [AGP8X,HyperTransport and SDR/DDR]
 	1687  M1687 K8 Northbridge [AGP8X and HyperTransport]
+	1689  M1689 K8 Northbridge [Super K8 Single Chip]
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -2908,24 +3203,39 @@
 	5217  M5217H
 	5219  M5219
 	5225  M5225
+	5228  M5228 ALi ATA/RAID Controller
 	5229  M5229 IDE
 		1014 050f  ThinkPad R30
+		1014 053d  ThinkPad R40e (2684-HVG) builtin IDE
+		103c 0024  Pavilion ze4400 builtin IDE
 		1043 8053  A7A266 Motherboard IDE
 	5235  M5225
 	5237  USB 1.1 Controller
+		1014 0540  ThinkPad R40e (2684-HVG) builtin USB
+		103c 0024  Pavilion ze4400 builtin USB
 	5239  USB 2.0 Controller
 	5243  M1541 PCI to AGP Controller
+	5246  AGP8X Controller
 	5247  PCI to AGP Controller
 	5249  M5249 HTT to PCI Bridge
 	5251  M5251 P1394 OHCI 1.0 Controller
 	5253  M5253 P1394 OHCI 1.1 Controller
 	5261  M5261 Ethernet Controller
+	5263  M5263 Ethernet Controller
+	5281  ALi M5281 Serial ATA / RAID Host Controller
+	5287  ULi 5287 SATA
+	5289  ULi 5289 SATA
 	5450  Lucent Technologies Soft Modem AMR
 	5451  M5451 PCI AC-Link Controller Audio Device
 		1014 0506  ThinkPad R30
+		1014 053e  ThinkPad R40e (2684-HVG) builtin Audio
+		103c 0024  Pavilion ze4400 builtin Audio
+		10b9 5451  HP Compaq nc4010 (DY885AA#ABN)
 	5453  M5453 PCI AC-Link Controller Modem Device
 	5455  M5455 PCI AC-Link Controller Audio Device
 	5457  M5457 AC'97 Modem Controller
+		1014 0535  ThinkPad R40e (2684-HVG) builtin modem
+		103c 0024  Pavilion ze4400 builtin Modem Device
 # Same but more usefull for driver's lookup
 	5459  SmartLink SmartPCI561 56K Modem
 # SmartLink PCI SoftModem
@@ -2934,6 +3244,8 @@
 	5473  M5473 SD-MMC Controller
 	7101  M7101 Power Management Controller [PMU]
 		1014 0510  ThinkPad R30
+		1014 053c  ThinkPad R40e (2684-HVG) Power Management Controller
+		103c 0024  Pavilion ze4400
 10ba  Mitsubishi Electric Corp.
 	0301  AccelGraphics AccelECLIPSE
 	0304  AccelGALAXY A2100 [OEM Evans & Sutherland]
@@ -2979,7 +3291,7 @@
 		10f7 8312  MagicGraph 128XD
 	0005  NM2200 [MagicGraph 256AV]
 		1014 00dd  ThinkPad 570
-		1028 0088  Latitude CPi A400XT
+		1028 0088  Latitude CPi A
 	0006  NM2360 [MagicMedia 256ZX]
 	0016  NM2380 [MagicMedia 256XL+]
 		10c8 0016  MagicMedia 256XL+
@@ -2990,6 +3302,7 @@
 		0e11 b126  MagicMedia 256AV Audio Device on Durango
 		1014 00dd  MagicMedia 256AV Audio Device on BlackTip Thinkpad
 		1025 1003  MagicMedia 256AV Audio Device on TravelMate 720
+		1028 0088  Latitude CPi A
 		1028 008f  MagicMedia 256AV Audio Device on Colorado Inspiron
 		103c 0007  MagicMedia 256AV Audio Device on Voyager II
 		103c 0008  MagicMedia 256AV Audio Device on Voyager III
@@ -3026,6 +3339,7 @@
 10d7  BCM Advanced Research
 10d8  Advanced Peripherals Labs
 10d9  Macronix, Inc. [MXIC]
+	0431  MX98715
 	0512  MX98713
 	0531  MX987x5
 		1186 1200  DFE-540TX ProFAST 10/100 Adapter
@@ -3074,6 +3388,7 @@
 		1043 0205  PCI-V3800
 		1043 4000  AGP-V3800PRO
 		1048 0c21  Synergy II
+		1048 0c31  Erazor III
 		107d 2134  WinFast 3D S320 II + TV-Out
 		1092 4804  Viper V770
 		1092 4a00  Viper V770
@@ -3113,9 +3428,39 @@
 		1102 102c  CT6931 RIVA TNT2 Value [Jumper]
 		1462 8808  MSI-8808
 		1554 1041  Pixelview RIVA TNT2 M64
+		1569 002d  Palit Microsystems Daytona TNT2 M64
 	002e  NV6 [Vanta]
 	002f  NV6 [Vanta]
-	0041  NV40 OS1RT00B30
+	0034  MCP04 SMBus
+	0035  MCP04 IDE
+	0036  MCP04 Serial ATA Controller
+	0037  MCP04 Ethernet Controller
+	0038  MCP04 Ethernet Controller
+	003a  MCP04 AC'97 Audio Controller
+	003b  MCP04 USB Controller
+	003c  MCP04 USB Controller
+	003d  MCP04 PCI Bridge
+	003e  MCP04 Serial ATA Controller
+	0040  nv40 [GeForce 6800 Ultra]
+	0041  NV40 [GeForce 6800]
+	0042  NV40.2
+	0043  NV40.3
+	0045  NV40 [GeForce 6800 GT]
+	0049  NV40GL
+	004e  NV40GL [Quadro FX 4000]
+	0051  CK804 ISA Bridge
+	0052  CK804 SMBus
+	0053  CK804 IDE
+	0054  CK804 Serial ATA Controller
+	0055  CK804 Serial ATA Controller
+	0056  CK804 Ethernet Controller
+	0057  CK804 Ethernet Controller
+	0059  CK804 AC'97 Audio Controller
+	005a  CK804 USB Controller
+	005b  CK804 USB Controller
+	005c  CK804 PCI Bridge
+	005d  CK804 PCIE Bridge
+	005e  CK804 Memory Controller
 	0060  nForce2 ISA Bridge
 		1043 80ad  A7N8X Mainboard
 	0064  nForce2 SMBus (MCP)
@@ -3127,15 +3472,31 @@
 	0068  nForce2 USB Controller
 		1043 0c11  A7N8X Mainboard
 	006a  nForce2 AC97 Audio Controler (MCP)
-	006b  nForce MultiMedia audio [Via VT82C686B]
+	006b  nForce Audio Processing Unit
+		10de 006b  nForce2 MCP Audio Processing Unit
 	006c  nForce2 External PCI Bridge
 	006d  nForce2 PCI Bridge
 	006e  nForce2 FireWire (IEEE 1394) Controller
+	0084  MCP2A SMBus
+	0085  MCP2A IDE
+	0086  MCP2A Ethernet Controller
+	0087  MCP2A USB Controller
+	0088  MCP2A USB Controller
+	008a  MCP2S AC'97 Audio Controller
+	008b  MCP2A PCI Bridge
+	008c  MCP2A Ethernet Controller
+	008e  nForce2 Serial ATA Controller
 	00a0  NV5 [Aladdin TNT2]
 		14af 5810  Maxi Gamer Xentor
+	00c0  NV41.0
+	00c1  NV41.1
+	00c2  NV41.2
+	00c8  NV41.8
+	00ce  NV41GL
 	00d0  nForce3 LPC Bridge
 	00d1  nForce3 Host Bridge
 	00d2  nForce3 AGP Bridge
+	00d3  CK804 Memory Controller
 	00d4  nForce3 SMBus
 	00d5  nForce3 IDE
 	00d6  nForce3 Ethernet
@@ -3143,6 +3504,31 @@
 	00d8  nForce3 USB 2.0
 	00da  nForce3 Audio
 	00dd  nForce3 PCI Bridge
+	00df  CK8S Ethernet Controller
+	00e0  nForce3 250Gb LPC Bridge
+	00e1  nForce3 250Gb Host Bridge
+	00e2  nForce3 250Gb AGP Host to PCI Bridge
+	00e3  CK8S Serial ATA Controller (v2.5)
+	00e4  nForce 250Gb PCI System Management
+	00e5  CK8S Parallel ATA Controller (v2.5)
+	00e6  CK8S Ethernet Controller
+	00e7  CK8S USB Controller
+	00e8  nForce3 EHCI USB 2.0 Controller
+	00ea  nForce3 250Gb AC'97 Audio Controller
+	00ed  nForce3 250Gb PCI-to-PCI Bridge
+	00ee  CK8S Serial ATA Controller (v2.5)
+	00f0  NV40 [GeForce 6800/GeForce 6800 Ultra]
+	00f1  NV43 [GeForce 6600/GeForce 6600 GT]
+	00f2  NV43 [GeForce 6600 GT]
+	00f8  NV45GL [Quadro FX 3400]
+	00f9  NV40 [GeForce 6800 Ultra/GeForce 6800 GT]
+		1682 2120  GEFORCE 6800 GT PCI-E
+	00fa  NV36 [GeForce PCX 5750]
+	00fb  NV35 [GeForce PCX 5900]
+	00fc  NV37GL [Quadro FX 330/GeForce PCX 5300]
+	00fd  NV37GL [Quadro FX 330]
+	00fe  NV38GL [Quadro FX 1300]
+	00ff  NV18 [GeForce PCX 4300]
 	0100  NV10 [GeForce 256 SDR]
 		1043 0200  AGP-V6600 SGRAM
 		1043 0201  AGP-V6600 SDRAM
@@ -3161,12 +3547,15 @@
 	0110  NV11 [GeForce2 MX/MX 400]
 		1043 4015  AGP-V7100 Pro
 		1043 4031  V7100 Pro with TV output
+		10de 0091  Dell OEM GeForce 2 MX 400
 		1462 8817  MSI GeForce2 MX400 Pro32S [MS-8817]
 		14af 7102  3D Prophet II MX
 		14af 7103  3D Prophet II MX Dual-Display
 	0111  NV11DDR [GeForce2 MX 100 DDR/200 DDR]
 	0112  NV11 [GeForce2 Go]
 	0113  NV11GL [Quadro2 MXR/EX]
+	0140  NV43 [MSI NX6600GT-TD128E]
+	014f  NV43 [GeForce 6200]
 	0150  NV15 [GeForce2 GTS/Pro]
 		1043 4016  V7700 AGP Video Card
 		107d 2840  WinFast GeForce2 GTS with TV output
@@ -3197,6 +3586,7 @@
 	017a  NV17GL [Quadro4 200/400 NVS]
 	017b  NV17GL [Quadro4 550 XGL]
 	017c  NV17GL [Quadro4 550 GoGL]
+	017d  NV17 [GeForce4 410 Go 16M]
 	0181  NV18 [GeForce4 MX 440 AGP 8x]
 		1043 806f  V9180 Magic
 		1462 8880  MS-StarForce GeForce4 MX 440 with AGP8X
@@ -3206,14 +3596,18 @@
 	0182  NV18 [GeForce4 MX 440SE AGP 8x]
 	0183  NV18 [GeForce4 MX 420 AGP 8x]
 	0185  NV18 [GeForce4 MX 4000 AGP 8x]
+	0186  NV18M [GeForce4 448 Go]
+	0187  NV18M [GeForce4 488 Go]
 	0188  NV18GL [Quadro4 580 XGL]
 	018a  NV18GL [Quadro4 NVS AGP 8x]
 	018b  NV18GL [Quadro4 380 XGL]
+	018d  NV18M [GeForce4 448 Go]
 	01a0  NVCrush11 [GeForce2 MX Integrated Graphics]
 	01a4  nForce CPU bridge
 	01ab  nForce 420 Memory Controller (DDR)
 	01ac  nForce 220/420 Memory Controller
 	01ad  nForce 220/420 Memory Controller
+	01b0  nForce Audio
 	01b1  nForce Audio
 	01b2  nForce ISA Bridge
 	01b4  nForce PCI System Management
@@ -3239,8 +3633,25 @@
 		1043 405b  V8200 T5
 		1545 002f  Xtasy 6964
 	0203  NV20DCC [Quadro DCC]
+	0240  C51 PCI Express Bridge
+	0241  C51 PCI Express Bridge
+	0242  C51 PCI Express Bridge
+	0243  C51 PCI Express Bridge
+	0244  C51 PCI Express Bridge
+	0245  C51 PCI Express Bridge
+	0246  C51 PCI Express Bridge
+	0247  C51 PCI Express Bridge
+	0248  C51 PCI Express Bridge
+	0249  C51 PCI Express Bridge
+	024a  C51 PCI Express Bridge
+	024b  C51 PCI Express Bridge
+	024c  C51 PCI Express Bridge
+	024d  C51 PCI Express Bridge
+	024e  C51 PCI Express Bridge
+	024f  C51 PCI Express Bridge
 	0250  NV25 [GeForce4 Ti 4600]
 	0251  NV25 [GeForce4 Ti 4400]
+		1043 8023  v8440 GeForce 4 Ti4400
 	0252  NV25 [GeForce4 Ti]
 	0253  NV25 [GeForce4 Ti 4200]
 		107d 2896  WinFast A250 LE TD (Dual VGA/TV-out/DVI)
@@ -3248,12 +3659,50 @@
 	0258  NV25GL [Quadro4 900 XGL]
 	0259  NV25GL [Quadro4 750 XGL]
 	025b  NV25GL [Quadro4 700 XGL]
+	0260  MCP51 LPC Bridge
+	0261  MCP51 LPC Bridge
+	0262  MCP51 LPC Bridge
+	0263  MCP51 LPC Bridge
+	0264  MCP51 SMBus
+	0265  MCP51 IDE
+	0266  MCP51 Serial ATA Controller
+	0267  MCP51 Serial ATA Controller
+	0268  MCP51 Ethernet Controller
+	0269  MCP51 Ethernet Controller
+	026a  MCP51 MCI
+	026b  MCP51 AC97 Audio Controller
+	026c  MCP51 High Definition Audio
+	026d  MCP51 USB Controller
+	026e  MCP51 USB Controller
+	026f  MCP51 PCI Bridge
+	0270  MCP51 Host Bridge
+	0271  MCP51 PMU
+	0272  MCP51 Memory Controller 0
+	027e  C51 Memory Controller 2
+	027f  C51 Memory Controller 3
 	0280  NV28 [GeForce4 Ti 4800]
 	0281  NV28 [GeForce4 Ti 4200 AGP 8x]
 	0282  NV28 [GeForce4 Ti 4800 SE]
 	0286  NV28 [GeForce4 Ti 4200 Go AGP 8x]
 	0288  NV28GL [Quadro4 980 XGL]
 	0289  NV28GL [Quadro4 780 XGL]
+	028c  NV28GLM [Quadro4 700 GoGL]
+	02f0  C51 Host Bridge
+	02f1  C51 Host Bridge
+	02f2  C51 Host Bridge
+	02f3  C51 Host Bridge
+	02f4  C51 Host Bridge
+	02f5  C51 Host Bridge
+	02f6  C51 Host Bridge
+	02f7  C51 Host Bridge
+	02f8  C51 Memory Controller 5
+	02f9  C51 Memory Controller 4
+	02fa  C51 Memory Controller 0
+	02fb  C51 PCI Express Bridge
+	02fc  C51 PCI Express Bridge
+	02fd  C51 PCI Express Bridge
+	02fe  C51 Memory Controller 1
+	02ff  C51 Host Bridge
 	0300  NV30 [GeForce FX]
 	0301  NV30 [GeForce FX 5800 Ultra]
 	0302  NV30 [GeForce FX 5800]
@@ -3261,42 +3710,77 @@
 	0309  NV30GL [Quadro FX 1000]
 	0311  NV31 [GeForce FX 5600 Ultra]
 	0312  NV31 [GeForce FX 5600]
+	0313  NV31
 	0314  NV31 [GeForce FX 5600XT]
+		1043 814a  V9560XT/TD
+	0316  NV31
+	0317  NV31
 	031a  NV31M [GeForce FX Go 5600]
+	031b  NV31M [GeForce FX Go5650]
 	031c  NVIDIA Quadro FX 700 Go
+	031d  NV31
+	031e  NV31
+	031f  NV31
+	0320  NV34 [GeForce FX 5200]
 	0321  NV34 [GeForce FX 5200 Ultra]
 	0322  NV34 [GeForce FX 5200]
 		1462 9171  MS-8917 (FX5200-T128)
+	0323  NV34 [GeForce FX 5200LE]
 	0324  NV34M [GeForce FX Go 5200]
 		1071 8160  MIM2000
+	0325  NV34M [GeForce FX Go5250]
+	0326  NV34 [GeForce FX 5500]
+	0327  NV34 [GeForce FX 5100]
 	0328  NV34M [GeForce FX Go 5200]
 	0329  NV34M [GeForce FX Go5200]
-	032b  NV34GL [Quadro FX 500]
+	032a  NV34GL [Quadro NVS 280 PCI]
+	032b  NV34GL [Quadro FX 500/600 PCI]
 	032c  NV34GLM [GeForce FX Go 5300]
+	032d  NV34 [GeForce FX Go5100]
+	032f  NV34
 	0330  NV35 [GeForce FX 5900 Ultra]
 	0331  NV35 [GeForce FX 5900]
+		1043 8145  V9950GE
 	0332  NV35 [GeForce FX 5900XT]
 	0333  NV38 [GeForce FX 5950 Ultra]
+	0334  NV35 [GeForce FX 5900ZT]
 	0338  NV35GL [Quadro FX 3000]
-	0341  NV 36 [GeForce 5700 Ultra]
-	0342  NV 36 [GeForce 5700]
+	033f  NV35GL [Quadro FX 700]
+	0341  NV36.1 [GeForce FX 5700 Ultra]
+	0342  NV36.2 [GeForce FX 5700]
+	0343  NV36 [GeForce FX 5700LE]
+	0344  NV36.4 [GeForce FX 5700VE]
+	0345  NV36.5
+	0347  NV36 [GeForce FX Go5700]
+	0348  NV36 [GeForce FX Go5700]
+	0349  NV36
+	034b  NV36
+	034c  NV36 [Quadro FX Go1000]
+	034e  NV36GL [Quadro FX 1100]
+	034f  NV36GL
 10df  Emulex Corporation
 	1ae5  LP6000 Fibre Channel Host Adapter
 	1ae6  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
 	1ae7  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:2-3)
-	f085  LP850 Fibre Channel Adapter
-	f095  LP952 Fibre Channel Adapter
-	f098  LP982 Fibre Channel Adapter
+	f005  LP1150e Fibre Channel Host Adapter
+	f085  LP850 Fibre Channel Host Adapter
+	f095  LP952 Fibre Channel Host Adapter
+	f098  LP982 Fibre Channel Host Adapter
+	f0a5  LP1050 Fibre Channel Host Adapter
+	f0d5  LP1150 Fibre Channel Host Adapter
+	f100  LP11000e Fibre Channel Host Adapter
 	f700  LP7000 Fibre Channel Host Adapter
 	f701  LP 7000EFibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
 	f800  LP8000 Fibre Channel Host Adapter
 	f801  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
 	f900  LP9000 Fibre Channel Host Adapter
 	f901  LP 9000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
-	f980  LP9802 Fibre Channel Adapter
+	f980  LP9802 Fibre Channel Host Adapter
 	f981  LP 9802 Fibre Channel Host Adapter Alternate ID
 	f982  LP 9802 Fibre Channel Host Adapter Alternate ID
 	fa00  LP10000 Fibre Channel Host Adapter
+	fa01  LP101 Fibre Channel Host Adapter
+	fd00  LP11000 Fibre Channel Host Adapter
 10e0  Integrated Micro Solutions Inc.
 	5026  IMS5026/27/28
 	5027  IMS5027
@@ -3314,6 +3798,8 @@
 	0000  CA91C042 [Universe]
 	0860  CA91C860 [QSpan]
 	0862  CA91C862A [QSpan-II]
+	8260  CA91L8200B [Dual PCI PowerSpan II]
+	8261  CA91L8260B [Single PCI PowerSpan II]
 10e4  Tandem Computers
 10e5  Micro Industries Corporation
 10e6  Gainbery Computer Products Inc.
@@ -3333,8 +3819,18 @@
 	80d9  PCI-9118
 	80da  PCI-9812
 	811a  PCI-IEEE1355-DS-DE Interface
+	814c  Fastcom ESCC-PCI (Commtech, Inc.)
 	8170  S5933 [Matchmaker] (Chipset Development Tool)
+# sold with Roper Scientifc(Photometrics) CoolSnap HQ camera
+	81e6  Multimedia video controller
+	8291  Fastcom 232/8-PCI (Commtech, Inc.)
+	82c4  Fastcom 422/4-PCI (Commtech, Inc.)
+	82c5  Fastcom 422/2-PCI (Commtech, Inc.)
+	82c6  Fastcom IG422/1-PCI (Commtech, Inc.)
+	82c7  Fastcom IG232/2-PCI (Commtech, Inc.)
+	82ca  Fastcom 232/4-PCI (Commtech, Inc.)
 	82db  AJA HDNTV HD SDI Framestore
+	82e2  Fastcom DIO24H-PCI (Commtech, Inc.)
 	8851  S5933 on Innes Corp FM Radio Capture card
 10e9  Alps Electric Co., Ltd.
 10ea  Intergraphics Systems
@@ -3363,6 +3859,8 @@
 	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
 		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
 	8139  RTL-8139/8139C/8139C+
+		0357 000a  TTP-Monitoring Card V2.0
+		1025 005a  TravelMate 290
 		1025 8920  ALN-325
 		1025 8921  ALN-325
 		1071 8160  MIM2000
@@ -3378,19 +3876,23 @@
 		1429 d010  ND010
 		1432 9130  EN-9130TX
 		1436 8139  RT8139
-		1458 e000  GA-7VM400M Motherboard
+		1458 e000  GA-7VM400M/7VT600 Motherboard
 		146c 1439  FE-1439TX
 		1489 6001  GF100TXRII
 		1489 6002  GF100TXRA
 		149c 139a  LFE-8139ATX
 		149c 8139  LFE-8139TX
+		14cb 0200  LNR-100 Family 10/100 Base-TX Ethernet
 		1799 5000  F5D5000 PCI Card/Desktop Network PCI Card
 		2646 0001  EtheRx
 		8e2e 7000  KF-230TX
 		8e2e 7100  KF-230TX/2
 		a0a0 0007  ALN-325C
 	8169  RTL-8169 Gigabit Ethernet
+		1259 c107  CG-LAPCIGT
 		1371 434e  ProG-2000L
+		1458 e000  GA-K8VT800 Pro Motherboard
+		1462 702c  K8T NEO 2 motherboard
 	8180  RTL8180L 802.11b MAC
 	8197  SmartLAN56 56K Modem
 10ed  Ascii Corporation
@@ -3455,13 +3957,19 @@
 		1102 8061  SBLive! Player 5.1
 		1102 8064  SB Live! 5.1 Model SB0100
 		1102 8065  SBLive! 5.1 Digital Model SB0220
+		1102 8067  SBLive! 5.1 eMicro 28028
 	0004  SB Audigy
 		1102 0051  SB0090 Audigy Player
 		1102 0053  SB0090 Audigy Player/OEM
 		1102 0058  SB0090 Audigy Player/OEM
+		1102 1007  SB0240 Audigy 2 Platinum 6.1
 		1102 2002  SB Audigy 2 ZS (SB0350)
 	0006  [SB Live! Value] EMU10k1X
 	0007  SB Audigy LS
+		1102 1001  SB0310 Audigy LS
+		1102 1002  SB0312 Audigy LS
+		1102 1006  SB0410 SBLive! 24-bit
+	0008  SB0400 Audigy2 Value
 	4001  SB Audigy FireWire Port
 		1102 0010  SB Audigy FireWire Port
 	7002  SB Live! MIDI/Game Port
@@ -3470,17 +3978,38 @@
 		1102 0040  SB Audigy MIDI/Game Port
 	7004  [SB Live! Value] Input device controller
 	7005  SB Audigy LS MIDI/Game port
+		1102 1001  SB0310 Audigy LS MIDI/Game port
+		1102 1002  SB0312 Audigy LS MIDI/Game port
 	8064  SB0100 [SBLive! 5.1 OEM]
 	8938  Ectiva EV1938
+		1033 80e5  SlimTower-Jim (NEC)
+		1071 7150  Mitac 7150
+		110a 5938  Siemens Scenic Mobile 510PIII
+		13bd 100c  Ceres-C (Sharp, Intel BX)
+		13bd 100d  Sharp, Intel Banister
+		13bd 100e  TwinHead P09S/P09S3 (Sharp)
+		13bd f6f1  Marlin (Sharp)
+		14ff 0e70  P88TE (TWINHEAD INTERNATIONAL Corp)
+		14ff c401  Notebook 9100/9200/2000 (TWINHEAD INTERNATIONAL Corp)
+		156d b400  G400 - Geo (AlphaTop (Taiwan))
+		156d b550  G560  (AlphaTop (Taiwan))
+		156d b560  G560  (AlphaTop (Taiwan))
+		156d b700  G700/U700  (AlphaTop (Taiwan))
+		156d b795  G795  (AlphaTop (Taiwan))
+		156d b797  G797  (AlphaTop (Taiwan))
 1103  Triones Technologies, Inc.
 	0003  HPT343
-# Revisions: 01=HPT366, 03=HPT370, 04=HPT370A, 05=HPT372
-	0004  HPT366/368/370/370A/372
+	0004  HPT366/368/370/370A/372/372N
 		1103 0001  HPT370A
+		1103 0003  HPT343 / HPT345 / HPT363 UDMA33
+		1103 0004  HPT366 UDMA66 (r1) / HPT368 UDMA66 (r2) / HPT370 UDMA100 (r3) / HPT370 UDMA100 RAID (r4)
 		1103 0005  HPT370 UDMA100
-	0005  HPT372A
+		1103 0006  HPT302
+		1103 0007  HPT371 UDMA133
+		1103 0008  HPT374 UDMA/ATA133 RAID Controller
+	0005  HPT372A/372N
 	0006  HPT302
-	0007  HPT371
+	0007  HPT371/371N
 	0008  HPT374
 	0009  HPT372N
 1104  RasterOps Corp.
@@ -3519,6 +4048,9 @@
 		1179 0001  Magnia Z310
 		1297 f641  FX41 motherboard
 		1458 5002  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		1849 0571  K7VT2 motherboard
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -3555,6 +4087,7 @@
 	1106  VT82C570MV
 	1571  VT82C576M/VT82C586
 	1595  VT82C595/97 [Apollo VP2/97]
+	3022  CLE266
 # This is *not* USB 2.0 as the existing entry suggests
 	3038  VT82xxxxx UHCI USB 1.1 Controller
 		0925 1234  USB Controller
@@ -3565,12 +4098,18 @@
 		1043 80ed  A7V600 motherboard
 		1179 0001  Magnia Z310
 		1458 5004  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		182d 201d  CN-029 USB2.0 4 port PCI Card
 	3040  VT82C586B ACPI
 	3043  VT86C100A [Rhine]
 		10bd 0000  VT86C100A Fast Ethernet Adapter
 		1106 0100  VT86C100A Fast Ethernet Adapter
 		1186 1400  DFE-530TX rev A
 	3044  IEEE 1394 Host Controller
+		1025 005a  TravelMate 290
+		1458 1000  GA-7VT600-1394 Motherboard
+		1462 702d  K8T NEO 2 motherboard
 	3050  VT82C596 Power Management
 	3051  VT82C596 Power Management
 	3053  VT6105M [Rhine-III]
@@ -3595,18 +4134,22 @@
 		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
 		1043 8095  A7V8X Motherboard (Realtek ALC650 codec)
 		1043 80a1  A7V8X-X Motherboard
-		1043 80b0  A7V600 motherboard (ADI AD1980 codec [SoundMAX])
+		1043 80b0  A7V600/K8V Deluxe motherboard (ADI AD1980 codec [SoundMAX])
 		1106 3059  L7VMM2 Motherboard
+		1106 4161  K7VT2 motherboard
 		1297 c160  FX41 motherboard (Realtek ALC650 codec)
 		1458 a002  GA-7VAX Onboard Audio (Realtek ALC650)
+		1462 0080  K8T NEO 2 motherboard
 		1462 3800  KT266 onboard audio
+		147b 1407  KV8-MAX3 motherboard
 	3065  VT6102 [Rhine-II]
 		1043 80a1  A7V8X-X Motherboard
 		1106 0102  VT6102 [Rhine II] Embeded Ethernet Controller on VT8235
 		1186 1400  DFE-530TX rev A
 		1186 1401  DFE-530TX rev B
 		13b9 1421  LD-10/100AL PCI Fast Ethernet Adapter (rev.B)
-	3068  Intel 537 [AC97 Modem]
+# This hosts more than just the Intel 537 codec, it also hosts PCtel (SIL33) and SmartLink (SIL34) codecs
+	3068  AC'97 Modem Controller
 		1462 309e  MS-6309 Saturn Motherboard
 	3074  VT8233 PCI to ISA Bridge
 		1043 8052  VT8233A
@@ -3614,6 +4157,7 @@
 	3099  VT8366/A/7 [Apollo KT266/A/333]
 		1043 8064  A7V266-E Mainboard
 		1043 807f  A7V333 Mainboard
+		1849 3099  K7VT2 motherboard
 	3101  VT8653 Host Bridge
 	3102  VT8662 Host Bridge
 	3103  VT8615 Host Bridge
@@ -3624,12 +4168,18 @@
 		1043 80ed  A7V600 motherboard
 		1297 f641  FX41 motherboard
 		1458 5004  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		182d 201d  CN-029 USB 2.0 4 port PCI Card
 	3106  VT6105 [Rhine-III]
 		1186 1403  DFE-530TX rev C
+	3108  S3 Unichrome Pro VGA Adapter
 	3109  VT8233C PCI to ISA Bridge
 	3112  VT8361 [KLE133] Host Bridge
 	3116  VT8375 [KM266/KL266] Host Bridge
 		1297 f641  FX41 motherboard
+	3118  S3 Unichrome Pro VGA Adapter
+	3119  VT6120/VT6121/VT6122 Gigabit Ethernet Adapter
 # found on EPIA M6000/9000 mainboard
 	3122  VT8623 [Apollo CLE266] integrated CastleRock graphics
 # found on EPIA M6000/9000 mainboard
@@ -3639,8 +4189,10 @@
 	3147  VT8233A ISA Bridge
 	3148  P4M266 Host Bridge
 	3149  VIA VT6420 SATA RAID Controller
-		1043 80ed  A7V600 motherboard
-		1462 7020  MSI Neo K8T FIS2R mainboard
+		1043 80ed  A7V600/K8V Deluxe motherboard
+		1458 b003  GA-7VM400AM(F) Motherboard
+		1462 7020  K8T Neo 2 Motherboard
+		147b 1407  KV8-MAX3 motherboard
 	3156  P/KN266 Host Bridge
 # on ASUS P4P800
 	3164  VT6410 ATA133 RAID controller
@@ -3651,20 +4203,31 @@
 		1043 80a1  A7V8X-X motherboard
 		1297 f641  FX41 motherboard
 		1458 5001  GA-7VAX Mainboard
+		1849 3177  K7VT2 motherboard
+	3178  ProSavageDDR P4N333 Host Bridge
 	3188  VT8385 [K8T800 AGP] Host Bridge
+		1043 80a3  K8V Deluxe motherboard
+		147b 1407  KV8-MAX3 motherboard
 	3189  VT8377 [KT400/KT600 AGP] Host Bridge
 		1043 807f  A7V8X motherboard
 		1458 5000  GA-7VAX Mainboard
-# Updated the entry to the proper "chip [name] desc" format
-	3205  VT8378 [KM400] Chipset Host Bridge
+	3204  K8M800
+	3205  VT8378 [KM400/A] Chipset Host Bridge
 		1458 5000  GA-7VM400M Motherboard
-	3227  VT8237 ISA bridge [K8T800 South]
+	3218  K8T800M Host Bridge
+	3227  VT8237 ISA bridge [KT600/K8T800 South]
 		1043 80ed  A7V600 motherboard
+		1106 3227  DFI KT600-AL Motherboard
+		1458 5001  GA-7VT600 Motherboard
+		147b 1407  KV8-MAX3 motherboard
+	3249  VT6421 IDE RAID Controller
+	4149  VIA VT6420 (ATA133) Controller
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
+	7204  K8M800
 # S3 Graphics UniChromeâ„¢ 2D/3D Graphics with motion compensation
 	7205  VT8378 [S3 UniChrome] Integrated Video
-		1458 d000  GA-7VM400M Motherboard
+		1458 d000  Gigabyte GA-7VM400(A)M(F) Motherboard
 	8231  VT8231 [PCI-to-ISA Bridge]
 	8235  VT8235 ACPI
 	8305  VT8363/8365 [KT133/KM133 AGP]
@@ -3686,6 +4249,7 @@
 	b112  VT8361 [KLE133] AGP Bridge
 	b168  VT8235 PCI Bridge
 	b188  VT8237 PCI bridge [K8T800 South]
+		147b 1407  KV8-MAX3 motherboard
 	b198  VT8237 PCI Bridge
 # 32-Bit PCI bus master Ethernet MAC with standard MII interface
 	d104  VT8237 Integrated Fast Ethernet Controller
@@ -3711,9 +4275,12 @@
 	007b  FSC Remote Service Controller, mailbox device
 	007c  FSC Remote Service Controller, shared memory device
 	007d  FSC Remote Service Controller, SMIC device
-	2102  DSCC4 WAN adapter
+# Superfastcom-PCI (Commtech, Inc.) or DSCC4 WAN Adapter
+	2102  DSCC4 PEB/PEF 20534 DMA Supported Serial Communication Controller with 4 Channels
 	2104  Eicon Diva 2.02 compatible passive ISDN card
+	3142  SIMATIC NET CP 5613A1 (Profibus Adapter)
 	4021  SIMATIC NET CP 5512 (Profibus and MPI Cardbus Adapter)
+	4029  SIMATIC NET CP 5613A2 (Profibus Adapter)
 	4942  FPGA I-Bus Tracer for MBD
 	6120  SZB6120
 110b  Chromatic Research Inc.
@@ -3745,6 +4312,8 @@
 	9211  EN-1207D Fast Ethernet Adapter
 		1113 9211  EN-1207D Fast Ethernet Adapter
 	9511  21x4x DEC-Tulip compatible Fast Ethernet
+	d301  CPWNA100 (Philips wireless PCMCIA)
+	ec02  SMC 1244TX v3
 1114  Atmel Corporation
 	0506  802.11b Wireless Network Adaptor (at76c506)
 1115  3D Labs
@@ -3854,9 +4423,11 @@
 111b  Teledyne Electronic Systems
 111c  Tricord Systems Inc.
 	0001  Powerbis Bridge
-111d  Integrated Device Tech
-	0001  IDT77211 ATM Adapter
-	0003  IDT77252 ATM network controller
+111d  Integrated Device Technology, Inc.
+	0001  IDT77201/77211 155Mbps ATM SAR Controller [NICStAR]
+	0003  IDT77222/77252 155Mbps ATM MICRO ABR SAR Controller
+	0004  IDT77V252 155Mbps ATM MICRO ABR SAR Controller
+	0005  IDT77V222 155Mbps ATM MICRO ABR SAR Controller
 111e  Eldec
 111f  Precision Digital Images
 	4a47  Precision MX Video engine interface
@@ -3890,12 +4461,18 @@
 	1561  USB 1.1 Host Controller
 	1562  USB 2.0 Host Controller
 	3400  SmartPCI56(UCB1500) 56K Modem
+	5400  TriMedia TM1000/1100
+	5402  TriMedia TM-1300
+		1244 0f00  Fritz!Card DSL
 	7130  SAA7130 Video Broadcast Decoder
 		5168 0138  LiveView FlyVideo 2000
-	7133  SAA7133 Audio+video broadcast decoder
+	7133  SAA713X Audio+video broadcast decoder
 		5168 0138  LifeView FlyVideo 3000
+		5168 0212  LifeView FlyTV Platinum mini
+		5168 0502  LifeView FlyDVB-T Duo CardBus
 # PCI audio and video broadcast decoder (http://www.semiconductors.philips.com/pip/saa7134hl)
 	7134  SAA7134
+		1043 4842  TV-FM Card 7134
 	7135  SAA7135 Audio+video broadcast decoder
 	7145  SAA7145
 	7146  SAA7146
@@ -3906,7 +4483,8 @@
 		114b 2003  DVRaptor Video Edit/Capture Card
 		11bd 0006  DV500 Overlay
 		11bd 000a  DV500 Overlay
-		13c2 0000  Siemens/Technotrend/Hauppauge DVB card rev1.3
+		11bd 000f  DV500 Overlay
+		13c2 0000  Siemens/Technotrend/Hauppauge DVB card rev1.3 or rev1.5
 		13c2 0001  Technotrend/Hauppauge DVB card rev1.3 or rev1.6
 		13c2 0002  Technotrend/Hauppauge DVB card rev2.1
 		13c2 0003  Technotrend/Hauppauge DVB card rev2.1
@@ -3956,37 +4534,45 @@
 	e011  Diva Server BRI S/T Rev 2
 	e012  Diva Server 4BRI-8M PCI
 		8001 0014  Diva Server 4BRI-8M PCI Cornet NQ
-	e013  Diva Server 4BRI-8M Rev 2
-		8001 0014  Diva Server 4BRI-8M Cornet NQ 2
+	e013  Diva Server 4BRI Rev 2
+		1133 1300  Diva Server V-4BRI-8
+		1133 e013  Diva Server 4BRI-8M 2.0 PCI
+		8001 0014  Diva Server 4BRI-8M 2.0 PCI Cornet NQ
 	e014  Diva Server PRI-30M PCI
 		0008 0100  Diva Server PRI-30M PCI
 		8001 0014  Diva Server PRI-30M PCI Cornet NQ
-	e015  DIVA Server PRI-30M 2.0
-		8001 0014  Diva Server PRI Cornet NQ 2
+	e015  DIVA Server PRI Rev 2
+		1133 e015  Diva Server PRI 2.0 PCI
+		8001 0014  Diva Server PRI 2.0 PCI Cornet NQ
 	e016  Diva Server Voice 4BRI PCI
 		8001 0014  Diva Server PRI Cornet NQ
-	e017  Diva Server Voice 4BRI PCI Rev 2
-		8001 0014  Diva Server Voice 4BRI PCI Cornet NQ 2
-	e018  Diva Server BRI 2M Revision 2
-		8001 0014  Diva Server BRI 2M Cornet NQ 2
-	e019  Diva Server Voice PRI PCI Rev 2
-		8001 0014  Diva Server Voice PRI PCI Cornet NQ 2
+	e017  Diva Server Voice 4BRI Rev 2
+		1133 e017  Diva Server Voice 4BRI-8M 2.0 PCI
+		8001 0014  Diva Server Voice 4BRI-8M 2.0 PCI Cornet NQ
+	e018  Diva Server BRI-2M 2.0 PCI
+		1133 1800  Diva Server V-BRI-2
+		1133 e018  Diva Server BRI-2M 2.0 PCI
+		8001 0014  Diva Server BRI-2M 2.0 PCI Cornet NQ
+	e019  Diva Server Voice PRI Rev 2
+		1133 e019  Diva Server Voice PRI 2.0 PCI
+		8001 0014  Diva Server Voice PRI 2.0 PCI Cornet NQ
 	e01a  Diva Server 2FX
-	e01b  Diva Server BRI-2M Voice Revision 2
-		8001 0014  Diva Server BRI-2M Voice Cornet NQ 2
-	e01c  Diva Server PRI Rev 3.0
-		1133 1c01  Diva Server PRI/E1/T1-8 Rev 3.0
-		1133 1c02  Diva Server PRI/T1-24 Rev 3.0
-		1133 1c03  Diva Server PRI/E1-30 Rev 3.0
-		1133 1c04  Diva Server V-PRI/E1/T1 Rev 3.0
-		1133 1c05  Diva Server V-PRI/T1-24 Rev 3.0
-		1133 1c06  Diva Server V-PRI/E1-30 Rev 3.0
-		1133 1c07  Diva Server PRI/E1/T1-8 Cornet NQ 3
-		1133 1c08  Diva Server PRI/T1-24 Cornet NQ 3
-		1133 1c09  Diva Server PRI/E1-30 Cornet NQ 3
-		1133 1c0a  Diva Server V-PRI/E1/T1 Cornet NQ 3
-		1133 1c0b  Diva Server V-PRI/T1-24 Cornet NQ 3
-		1133 1c0c  Diva Server V-PRI/E1-30 Cornet NQ 3
+	e01b  Diva Server Voice BRI-2M 2.0 PCI
+		1133 e01b  Diva Server Voice BRI-2M 2.0 PCI
+		8001 0014  Diva Server Voice BRI-2M 2.0 PCI Cornet NQ
+	e01c  Diva Server PRI Rev 3
+		1133 1c01  Diva Server PRI/E1/T1-8
+		1133 1c02  Diva Server PRI/T1-24
+		1133 1c03  Diva Server PRI/E1-30
+		1133 1c04  Diva Server PRI/E1/T1
+		1133 1c05  Diva Server V-PRI/T1-24
+		1133 1c06  Diva Server V-PRI/E1-30
+		1133 1c07  Diva Server PRI/E1/T1-8 Cornet NQ
+		1133 1c08  Diva Server PRI/T1-24 Cornet NQ
+		1133 1c09  Diva Server PRI/E1-30 Cornet NQ
+		1133 1c0a  Diva Server PRI/E1/T1 Cornet NQ
+		1133 1c0b  Diva Server V-PRI/T1-24 Cornet NQ
+		1133 1c0c  Diva Server V-PRI/E1-30 Cornet NQ
 	e01e  Diva Server 2PRI
 		1133 1e00  Diva Server V-2PRI/E1-60
 		1133 1e01  Diva Server V-2PRI/T1-48
@@ -3998,9 +4584,14 @@
 		1133 2002  Diva Server 4PRI/E1-120
 		1133 2003  Diva Server 4PRI/T1-96
 	e024  Diva Server Analog-4P
+		1133 2400  Diva Server V-Analog-4P
+		1133 e024  Diva Server Analog-4P
 	e028  Diva Server Analog-8P
+		1133 2800  Diva Server V-Analog-8P
+		1133 e028  Diva Server Analog-8P
 1134  Mercury Computer Systems
 	0001  Raceway Bridge
+	0002  Dual PCI to RapidIO Bridge
 1135  Fuji Xerox Co Ltd
 	0001  Printer controller
 1136  Momentum Data Systems
@@ -4048,7 +4639,8 @@
 	f015  NinjaSCSI-32 Melco
 1146  Force Computers
 1147  Interface Corp
-1148  Syskonnect (Schneider & Koch)
+# Formerly (Schneider & Koch)
+1148  SysKonnect
 	4000  FDDI Adapter
 		0e11 b03b  Netelligent 100 FDDI DAS Fibre SC
 		0e11 b03c  Netelligent 100 FDDI SAS Fibre SC
@@ -4106,6 +4698,16 @@
 		1148 9521  SK-9521 10/100/1000Base-T Adapter
 	4400  SK-9Dxx Gigabit Ethernet Adapter
 	4500  SK-9Mxx Gigabit Ethernet Adapter
+	9000  SK-9Sxx Gigabit Ethernet Server Adapter PCI-X
+	9843  [Fujitsu] Gigabit Ethernet
+	9e00  SK-9Exx 10/100/1000Base-T Adapter
+		1148 2100  SK-9E21 Server Adapter
+		1148 21d0  SK-9E21D 10/100/1000Base-T Adapter
+		1148 2200  SK-9E22 Server Adapter
+		1148 8100  SK-9E81 Server Adapter
+		1148 8200  SK-9E82 Server Adapter
+		1148 9100  SK-9E91 Server Adapter
+		1148 9200  SK-9E92 Server Adapter
 1149  Win System Corporation
 114a  VMIC
 	5579  VMIPCI-5579 (Reflective Memory Card)
@@ -4259,6 +4861,7 @@
 	0212  CSB5 IDE Controller
 		4c53 1080  CT8 mainboard
 	0213  CSB6 RAID/IDE Controller
+	0217  CSB6 IDE Controller
 	0220  OSB4/CSB5 OHCI USB Controller
 		4c53 1080  CT8 mainboard
 	0221  CSB6 OHCI USB Controller
@@ -4268,6 +4871,9 @@
 	0227  GCLE-2 Host Bridge
 	0230  CSB5 LPC bridge
 		4c53 1080  CT8 mainboard
+	0240  K2 SATA
+	0241  K2 SATA
+	0242  K2 SATA
 1167  Mutoh Industries Inc
 1168  Thine Electronics Inc
 1169  Centre for Development of Advanced Computing
@@ -4296,11 +4902,11 @@
 	0404  DVD Decoder card
 	0406  Tecra Video Capture device
 	0407  DVD Decoder card (Version 2)
-	0601  601
+	0601  CPU to PCI bridge
 	0603  ToPIC95 PCI to CardBus Bridge for Notebooks
 	060a  ToPIC95
 	060f  ToPIC97
-	0617  ToPIC95 PCI to Cardbus Bridge with ZV Support
+	0617  ToPIC100 PCI to Cardbus Bridge with ZV Support
 	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
@@ -4333,6 +4939,8 @@
 		144d c006  vpr Matrix 170B4
 	0552  R5C552 IEEE 1394 Controller
 		1014 0511  ThinkPad A/T/X Series
+	0576  R5C576 SD Bus Host Adapter
+	0592  R5C592 Memory Stick Bus Host Adapter
 1181  Telmatics International
 1183  Fujikura Ltd
 1184  Forks Inc
@@ -4342,16 +4950,34 @@
 	1002  DL10050 Sundance Ethernet
 		1186 1002  DFE-550TX
 		1186 1012  DFE-580TX
+	1025  AirPlus Xtreme G DWL-G650 Adapter
+	1026  AirXpert DWL-AG650 Wireless Cardbus Adapter
+	1043  AirXpert DWL-AG650 Wireless Cardbus Adapter
 	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
 	1541  DFE-680TXD CardBus PC Card
 	1561  DRP-32TXD Cardbus PC Card
+	2027  AirPlus Xtreme G DWL-G520 Adapter
+	3203  AirPlus Xtreme G DWL-G520 Adapter
 	3300  DWL-510 2.4GHz Wireless PCI Adapter
+	3a03  AirPro DWL-A650 Wireless Cardbus Adapter(rev.B)
+	3a04  AirPro DWL-AB650 Multimode Wireless Cardbus Adapter
+	3a05  AirPro DWL-AB520 Multimode Wireless PCI Adapter
+	3a07  AirXpert DWL-AG650 Wireless Cardbus Adapter
+	3a08  AirXpert DWL-AG520 Wireless PCI Adapter
+	3a10  AirXpert DWL-AG650 Wireless Cardbus Adapter(rev.B)
+	3a11  AirXpert DWL-AG520 Wireless PCI Adapter(rev.B)
+	3a12  AirPlus DWL-G650 Wireless Cardbus Adapter(rev.C)
+	3a13  AirPlus DWL-G520 Wireless PCI Adapter(rev.B)
+	3a14  AirPremier DWL-AG530 Wireless PCI Adapter
+	3a63  AirXpert DWL-AG660 Wireless Cardbus Adapter
 	3b05  DWL-G650+ CardBus PC Card
 	4000  DL2000-based Gigabit Ethernet
+	4300  DGE-528T Gigabit Ethernet Adapter
 	4c00  Gigabit Ethernet Adapter
+		1186 4c00  DGE-530T Gigabit Ethernet Adapter
 	8400  D-Link DWL-650+ CardBus PC Card
 1187  Advanced Technology Laboratories, Inc.
 1188  Shima Seiki Manufacturing Ltd.
@@ -4397,6 +5023,10 @@
 	8030  AEC6712S SCSI
 	8040  AEC6712D SCSI
 	8050  AEC6712SUW SCSI
+	8060  AEC6712 SCSI
+	8080  AEC67160 SCSI
+	8081  AEC67160S SCSI
+	808a  AEC67162 2-ch. LVD SCSI
 1192  Densan Company Ltd
 1193  Zeitnet Inc.
 	0001  1221
@@ -4432,12 +5062,122 @@
 # Formerly Galileo Technology, Inc.
 11ab  Marvell Technology Group Ltd.
 	0146  GT-64010/64010A System Controller
+	138f  W8300 802.11 Adapter (rev 07)
 	1fa6  Marvell W8300 802.11 Adapter
-	4146  GT-64011/GT-64111 System Controller
-	4320  Yukon Gigabit Ethernet 10/100/1000Base-T Adapter
+	1fa7  88W8310 and 88W8000G [Libertas] 802.11g client chipset
+	4320  Gigabit Ethernet Controller
+		1019 0f38  Marvell 88E8001 Gigabit Ethernet Controller (ECS)
+		1019 8001  Marvell 88E8001 Gigabit Ethernet Controller (ECS)
+		1043 173c  Marvell 88E8001 Gigabit Ethernet Controller (Asus)
+		1043 811a  Marvell 88E8001 Gigabit Ethernet Controller (Asus)
+		105b 0c19  Marvell 88E8001 Gigabit Ethernet Controller (Foxconn)
+		10b8 b452  SMC EZ Card 1000 (SMC9452TXV.2)
+		11ab 0121  Marvell RDK-8001
+		11ab 0321  Marvell RDK-8003
+		11ab 1021  Marvell RDK-8010
+		11ab 5021  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (64 bit)
+		11ab 9521  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (32 bit)
+		1458 e000  Marvell 88E8001 Gigabit Ethernet Controller (Gigabyte)
+		147b 1406  Marvell 88E8001 Gigabit Ethernet Controller (Abit)
+		15d4 0047  Marvell 88E8001 Gigabit Ethernet Controller (Iwill)
+		1695 9025  Marvell 88E8001 Gigabit Ethernet Controller (Epox)
+		17f2 1c03  Marvell 88E8001 Gigabit Ethernet Controller (Albatron)
+		270f 2803  Marvell 88E8001 Gigabit Ethernet Controller (Chaintech)
+	4350  Fast Ethernet Controller
+		1179 0001  Marvell 88E8035 Fast Ethernet Controller (Toshiba)
+		11ab 3521  Marvell RDK-8035
+		1854 000d  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 000e  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 000f  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0011  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0012  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0016  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0017  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0018  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0019  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 001c  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 001e  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0020  Marvell 88E8035 Fast Ethernet Controller (LGE)
+	4351  Fast Ethernet Controller
+		107b 4009  Marvell 88E8036 Fast Ethernet Controller (Wistron)
+		10f7 8338  Marvell 88E8036 Fast Ethernet Controller (Panasonic)
+		1179 0001  Marvell 88E8036 Fast Ethernet Controller (Toshiba)
+		1179 ff00  Marvell 88E8036 Fast Ethernet Controller (Compal)
+		1179 ff10  Marvell 88E8036 Fast Ethernet Controller (Inventec)
+		11ab 3621  Marvell RDK-8036
+		13d1 ac12  Abocom EFE3K - 10/100 Ethernet Expresscard
+		161f 203d  Marvell 88E8036 Fast Ethernet Controller (Arima)
+		1854 000d  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 000e  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 000f  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0011  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0012  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0016  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0017  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0018  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0019  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 001c  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 001e  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0020  Marvell 88E8036 Fast Ethernet Controller (LGE)
+	4360  Gigabit Ethernet Controller
+		1043 8134  Marvell 88E8052 Gigabit Ethernet Controller (Asus)
+		107b 4009  Marvell 88E8052 Gigabit Ethernet Controller (Wistron)
+		11ab 5221  Marvell RDK-8052
+		1458 e000  Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte)
+		1462 052c  Marvell 88E8052 Gigabit Ethernet Controller (MSI)
+		1849 8052  Marvell 88E8052 Gigabit Ethernet Controller (ASRock)
+		1940 e000  Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte)
+		a0a0 0509  Marvell 88E8052 Gigabit Ethernet Controller (Aopen)
+	4361  Gigabit Ethernet Controller
+		107b 3015  Marvell 88E8050 Gigabit Ethernet Controller (Gateway)
+		11ab 5021  Marvell 88E8050 Gigabit Ethernet Controller (Intel)
+		8086 3063  D925XCVLK mainboard
+	4362  Gigabit Ethernet Controller
+		103c 2a0d  Marvell 88E8053 Gigabit Ethernet Controller (Asus)
+		1043 8142  Marvell 88E8053 Gigabit Ethernet Controller (Asus)
+		109f 3197  Marvell 88E8053 Gigabit Ethernet Controller (Trigem)
+		10f7 8338  Marvell 88E8053 Gigabit Ethernet Controller (Panasonic)
+		10fd a430  Marvell 88E8053 Gigabit Ethernet Controller (SOYO)
+		1179 0001  Marvell 88E8053 Gigabit Ethernet Controller (Toshiba)
+		1179 ff00  Marvell 88E8053 Gigabit Ethernet Controller (Compal)
+		1179 ff10  Marvell 88E8053 Gigabit Ethernet Controller (Inventec)
+		11ab 5321  Marvell RDK-8053
+		1297 c240  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c241  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c242  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c243  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c244  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		13d1 ac11  Abocom EGE5K - Giga Ethernet Expresscard
+		1458 e000  Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte)
+		1462 058c  Marvell 88E8053 Gigabit Ethernet Controller (MSI)
+		14c0 0012  Marvell 88E8053 Gigabit Ethernet Controller (Compal)
+		1558 04a0  Marvell 88E8053 Gigabit Ethernet Controller (Clevo)
+		15bd 1003  Marvell 88E8053 Gigabit Ethernet Controller (DFI)
+		161f 203c  Marvell 88E8053 Gigabit Ethernet Controller (Arima)
+		161f 203d  Marvell 88E8053 Gigabit Ethernet Controller (Arima)
+		1695 9029  Marvell 88E8053 Gigabit Ethernet Controller (Epox)
+		17f2 2c08  Marvell 88E8053 Gigabit Ethernet Controller (Albatron)
+		17ff 0585  Marvell 88E8053 Gigabit Ethernet Controller (Quanta)
+		1849 8053  Marvell 88E8053 Gigabit Ethernet Controller (ASRock)
+		1854 000b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 000c  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0010  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0013  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0014  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0015  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001a  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001d  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001f  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0021  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0022  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1940 e000  Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte)
+		270f 2801  Marvell 88E8053 Gigabit Ethernet Controller (Chaintech)
+		a0a0 0506  Marvell 88E8053 Gigabit Ethernet Controller (Aopen)
 	4611  GT-64115 System Controller
 	4620  GT-64120/64120A/64121A System Controller
 	4801  GT-48001
+	5005  Belkin F5D5005 Gigabit Desktop Network PCI Card
 	5040  MV88SX5040 4-port SATA I PCI-X Controller
 	5041  MV88SX5041 4-port SATA I PCI-X Controller
 	5080  MV88SX5080 8-port SATA I PCI-X Controller
@@ -4483,7 +5223,7 @@
 11be  International Microcircuits Inc
 11bf  Astrodesign, Inc.
 11c0  Hewlett Packard
-11c1  Lucent Microelectronics
+11c1  Agere Systems (former Lucent Microelectronics)
 	0440  56k WinModem
 		1033 8015  LT WinModem 56k Data+Fax+Voice+Dsvd
 		1033 8047  LT WinModem 56k Data+Fax+Voice+Dsvd
@@ -4586,12 +5326,25 @@
 	0462  V90 WildWire Modem
 	0480  Venus Modem (V90, 56KFlex)
 	048c  V.92 56K WinModem
+# InPorte Home Internal 56k Modem/fax/answering machine/SMS Features
+	048f  V.92 56k WinModem
 	5801  USB
 	5802  USS-312 USB Controller
 # 4 port PCI USB Controller made by Agere (formely Lucent)
 	5803  USS-344S USB Controller
 	5811  FW323
+		8086 524c  D865PERL mainboard
 		dead 0800  FireWire Host Bus Adapter
+	ab10  WL60010 Wireless LAN MAC
+	ab11  WL60040 Multimode Wireles LAN MAC
+		11c1 ab12  WaveLAN 11abg Cardbus card (Model 1102)
+		11c1 ab13  WaveLAN 11abg MiniPCI card (Model 0512)
+		11c1 ab15  WaveLAN 11abg Cardbus card (Model 1106)
+		11c1 ab16  WaveLAN 11abg MiniPCI card (Model 0516)
+	ab20  ORiNOCO PCI Adapter
+	ab21  Agere Wireless PCI Adapter
+	ab30  Hermes2 Mini-PCI WaveLAN a/b/g
+		14cd 2012  Hermes2 Mini-PCI WaveLAN a/b/g
 11c2  Sand Microelectronics
 11c3  NEC Corporation
 11c4  Document Technologies, Inc
@@ -4717,6 +5470,7 @@
 	0903  RocketPort Compact PCI 16 port w/external I/F
 	8015  RocketPort 4-port UART 16954
 11ff  Scion Corporation
+	0003  AG-5
 1200  CSS Corporation
 1201  Vista Controls Corp
 1202  Network General Corp.
@@ -4764,23 +5518,29 @@
 1217  O2 Micro, Inc.
 	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
+	6832  OZ6832/6833 CardBus Controller
+	6836  OZ6836/6860 CardBus Controller
+	6872  OZ6812 CardBus Controller
+	6925  OZ6922 CardBus Controller
+	6933  OZ6933/711E1 CardBus/SmartCardBus Controller
 		1025 1016  Travelmate 612 TX
-	6972  OZ6912 Cardbus Controller
+	6972  OZ601/6912/711E0 CardBus/SmartCardBus Controller
 		1014 020c  ThinkPad R30
 		1179 0001  Magnia Z310
-	7110  OZ711Mx MultiMediaBay Accelerator
-	7112  OZ711EC1/M1 SmartCardBus MultiMediaBay Controller
+	7110  OZ711Mx 4-in-1 MemoryCardBus Accelerator
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	7112  OZ711EC1/M1 SmartCardBus/MemoryCardBus Controller
 	7113  OZ711EC1 SmartCardBus Controller
-	7114  OZ711M1 SmartCardBus MultiMediaBay Controller
+	7114  OZ711M1/MC1 4-in-1 MemoryCardBus Controller
+	7134  OZ711MP1/MS1 MemoryCardBus Controller
 	71e2  OZ711E2 SmartCardBus Controller
-	7212  OZ711M2 SmartCardBus MultiMediaBay Controller
+	7212  OZ711M2 4-in-1 MemoryCardBus Controller
 	7213  OZ6933E CardBus Controller
-	7223  OZ711M3 SmartCardBus MultiMediaBay Controller
+	7223  OZ711M3/MC3 4-in-1 MemoryCardBus Controller
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	7233  OZ711MP3/MS3 4-in-1 MemoryCardBus Controller
 1218  Hybricon Corp.
 1219  First Virtual Corporation
 121a  3Dfx Interactive, Inc.
@@ -4808,7 +5568,7 @@
 		121a 0030  Voodoo3 AGP
 		121a 0031  Voodoo3 AGP
 		121a 0034  Voodoo3 AGP
-		121a 0036  Voodoo3
+		121a 0036  Voodoo3 2000 PCI
 		121a 0037  Voodoo3 AGP
 		121a 0038  Voodoo3 AGP
 		121a 003a  Voodoo3 AGP
@@ -4889,6 +5649,7 @@
 	8120  E4?
 		11bd 0006  DV500 E4
 		11bd 000a  DV500 E4
+		11bd 000f  DV500 E4
 	8888  Cinemaster C 3.0 DVD Decoder
 		1002 0001  Cinemaster C 3.0 DVD Decoder
 		1002 0002  Cinemaster C 3.0 DVD Decoder
@@ -4913,6 +5674,7 @@
 	1100  C2 ISDN
 	1200  T1 ISDN
 	2700  Fritz!Card DSL SL
+	2900  Fritz!Card DSL v2.0
 1245  A.P.D., S.A.
 1246  Dipix Technologies, Inc.
 1247  Xylon Research, Inc.
@@ -4929,7 +5691,7 @@
 	0003  EasyIO
 	0004  EasyConnection/RA
 124e  Cylink
-124f  Infotrend Technology, Inc.
+124f  Infortrend Technology, Inc.
 	0041  IFT-2000 Series RAID Controller
 1250  Hitachi Microcomputer System Ltd
 1251  VLSI Solutions Oy
@@ -4966,6 +5728,7 @@
 	1969  ES1969 Solo-1 Audiodrive
 		1014 0166  ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard
 		125d 8888  Solo-1 Audio Adapter
+		153b 111b  Terratec 128i PCI
 	1978  ES1978 Maestro 2E
 		0e11 b112  Armada M700/E500
 		1033 803c  ES1978 Maestro-2E Audiodrive
@@ -4998,6 +5761,8 @@
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
 1260  Intersil Corporation
+	3872  Prism 2.5 Wavelan chipset
+		1468 0202  LAN-Express IEEE 802.11b Wireless LAN
 	3873  Prism 2.5 Wavelan chipset
 		1186 3501  DWL-520 Wireless PCI Adapter
 		1186 3700  DWL-520 Wireless PCI Adapter, Rev E1
@@ -5007,10 +5772,19 @@
 		1737 3874  WMP11 Wireless 802.11b PCI Adapter
 		8086 2513  Wireless 802.11b MiniPCI Adapter
 	3886  ISL3886 [Prism Javelin/Prism Xbow]
+		17cf 0037  Z-Com XG-901 and clones Wireless Adapter
 	3890  Intersil ISL3890 [Prism GT/Prism Duette]
+		10b8 2802  SMC2802W Wireless PCI Adapter
+		10b8 2835  SMC2835W Wireless Cardbus Adapter
 		10b8 a835  SMC2835W V2 Wireless Cardbus Adapter
+		1113 ee03  SMC2802W V2 Wireless PCI Adapter
+		1113 ee08  SMC2835W V3 EU Wireless Cardbus Adapter
+		1186 3202  DWL-G650 A1 Wireless Adapter
+		1259 c104  CG-WLCB54GT Wireless Adapter
+		1385 4800  WG511 Wireless Adapter
 		16a5 1605  ALLNET ALL0271 Wireless PCI Adapter
-		17cf 0014  Ovislink WL-5400PCM, Prism GT
+		17cf 0014  Z-Com XG-600 and clones Wireless Adapter
+		17cf 0020  Z-Com XG-900 and clones Wireless Adapter
 	8130  HMP8130 NTSC/PAL Video Decoder
 	8131  HMP8131 NTSC/PAL Video Decoder
 1261  Matsushita-Kotobuki Electronics Industries, Ltd.
@@ -5154,6 +5928,7 @@
 		1048 1500  MicroLink 56k Modem
 		10cf 1059  Fujitsu 229-DFRT
 	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		1005 127a  AOpen FM56-P
 		1033 8029  229-DFSV
 		1033 8054  Modem
 		10cf 103c  Fujitsu
@@ -5255,7 +6030,8 @@
 	9132  Ethernet 100/10 MBit
 1283  Integrated Technology Express, Inc.
 	673a  IT8330G
-	8212  IT/ITE8212 Dual channel ATA RAID controller
+	8212  IT/ITE8212 Dual channel ATA RAID controller (PCI version seems to be IT8212, embedded seems to be ITE8212)
+		1283 0001  IT/ITE8212 Dual channel ATA RAID controller
 	8330  IT8330G
 	8872  IT8874F PCI Dual Serial Port Controller
 	8888  IT8888F PCI to ISA Bridge with SMB
@@ -5312,11 +6088,13 @@
 12a9  Xiotech Corporation
 12aa  SDL Communications, Inc.
 12ab  Yuan Yuan Enterprise Co., Ltd.
+	0002  AU8830 [Vortex2] Based Sound Card With A3D Support
 	3000  MPG-200C PCI DVD Decoder Card
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
 	0001  AceNIC Gigabit Ethernet
+		1014 0104  Gigabit Ethernet-SX PCI Adapter
 		12ae 0001  Gigabit Ethernet-SX (Universal)
 		1410 0104  Gigabit Ethernet-SX PCI Adapter
 	0002  AceNIC Gigabit Ethernet (Copper)
@@ -5333,7 +6111,7 @@
 12b6  Natural Microsystems
 12b7  Cognex Modular Vision Systems Div. - Acumen Inc.
 12b8  Korg
-12b9  5610 56K FaxModem
+12b9  3Com Corp, Modem Division (formerly US Robotics)
 	1006  WinModem
 		12b9 005c  USR 56k Internal Voice WinModem (Model 3472)
 		12b9 005e  USR 56k Internal WinModem (Models 662975)
@@ -5368,6 +6146,34 @@
 	0058  PCI NE2K Ethernet
 	5598  PCI NE2K Ethernet
 12c4  Connect Tech Inc
+	0001  Blue HEAT/PCI 8 (RS232/CL/RJ11)
+	0002  Blue HEAT/PCI 4 (RS232)
+	0003  Blue HEAT/PCI 2 (RS232)
+	0004  Blue HEAT/PCI 8 (UNIV, RS485)
+	0005  Blue HEAT/PCI 4+4/6+2 (UNIV, RS232/485)
+	0006  Blue HEAT/PCI 4 (OPTO, RS485)
+	0007  Blue HEAT/PCI 2+2 (RS232/485)
+	0008  Blue HEAT/PCI 2 (OPTO, Tx, RS485)
+	0009  Blue HEAT/PCI 2+6 (RS232/485)
+	000a  Blue HEAT/PCI 8 (Tx, RS485)
+	000b  Blue HEAT/PCI 4 (Tx, RS485)
+	000c  Blue HEAT/PCI 2 (20 MHz, RS485)
+	000d  Blue HEAT/PCI 2 PTM
+	0100  NT960/PCI
+	0201  cPCI Titan - 2 Port
+	0202  cPCI Titan - 4 Port
+	0300  CTI PCI UART 2 (RS232)
+	0301  CTI PCI UART 4 (RS232)
+	0302  CTI PCI UART 8 (RS232)
+	0310  CTI PCI UART 1+1 (RS232/485)
+	0311  CTI PCI UART 2+2 (RS232/485)
+	0312  CTI PCI UART 4+4 (RS232/485)
+	0320  CTI PCI UART 2
+	0321  CTI PCI UART 4
+	0322  CTI PCI UART 8
+	0330  CTI PCI UART 2 (RS485)
+	0331  CTI PCI UART 4 (RS485)
+	0332  CTI PCI UART 8 (RS485)
 12c5  Picture Elements Incorporated
 	007e  Imaging/Scanning Subsystem Engine
 	007f  Imaging/Scanning Subsystem Engine
@@ -5417,7 +6223,9 @@
 12d3  Vingmed Sound A/S
 12d4  Ulticom (Formerly DGM&S)
 	0200  T1 Card
-12d5  Equator Technologies
+12d5  Equator Technologies Inc
+	0003  BSP16
+	1000  BSP15
 12d6  Analogic Corp
 12d7  Biotronic SRL
 12d8  Pericom Semiconductor
@@ -5546,6 +6354,7 @@
 	004c  PCI-DAS1000
 	004d  PCI-QUAD04
 	0052  PCI-DAS4020/12
+	005e  PCI-DAS6025
 1308  Jato Technologies Inc.
 	0001  NetCelerator Adapter
 		1308 0001  NetCelerator Adapter
@@ -5569,6 +6378,7 @@
 	8201  ADMtek ADM8211 802.11b Wireless Interface
 		10b8 2635  SMC2635W 802.11b (11Mbps) wireless lan pcmcia (cardbus) card
 		1317 8201  SMC2635W 802.11b (11mbps) wireless lan pcmcia (cardbus) card
+	8211  ADMtek ADM8211 802.11b Wireless Interface
 	9511  21x4x DEC-Tulip compatible 10/100 Ethernet
 1318  Packet Engines Inc.
 	0911  GNIC-II PCI Gigabit Ethernet [Hamachi]
@@ -5620,6 +6430,7 @@
 	2060  Trio 2S(16550)+1P
 	2061  Trio 2S(16650)+1P
 	2062  Trio 2S(16850)+1P
+	2081  CyberSerial (8-port) ST16654
 1320  Crypto AG
 1321  Arcobel Graphics BV
 1322  MTT Co., Ltd
@@ -5636,6 +6447,7 @@
 132d  Integrated Silicon Solution, Inc.
 1330  MMC Networks
 1331  Radisys Corp.
+	0030  ENP-2611
 	8200  82600 Host Bridge
 	8201  82600 IDE
 	8202  82600 USB
@@ -5667,6 +6479,8 @@
 134b  ARK Research Corp.
 134c  Chori Joho System Co. Ltd
 134d  PCTel Inc
+	2189  HSP56 MicroModem
+	2486  2304WT V.92 MDC Modem
 	7890  HSP MicroModem 56
 		134d 0001  PCT789 adapter
 	7891  HSP MicroModem 56
@@ -5715,9 +6529,17 @@
 	7401  Four Port RS-232 Interface
 	7402  Four Port RS-422/485 Interface
 	7801  Eight Port RS-232 Interface
+	7804  Eight Port RS-232/422/485 Interface
 	8001  8001 Digital I/O Adapter
 135f  I-Data International A-S
 1360  Meinberg Funkuhren
+	0101  PCI32 DCF77 Radio Clock
+	0102  PCI509 DCF77 Radio Clock
+	0103  PCI510 DCF77 Radio Clock
+	0201  GPS167PCI GPS Receiver
+	0202  GPS168PCI GPS Receiver
+	0203  GPS169PCI GPS Receiver
+	0301  TCR510PCI IRIG Receiver
 1361  Soliton Systems K.K.
 1362  Fujifacom Corporation
 1363  Phoenix Technology Ltd
@@ -5736,6 +6558,7 @@
 1370  ATL Products
 1371  CNet Technology Inc
 	434e  GigaCard Network Adapter
+		1371 434e  N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
 1373  Silicon Vision Inc
 1374  Silicom Ltd
 1375  Argosystems Inc
@@ -5753,13 +6576,29 @@
 1380  Sanritz Automation Co Ltd
 1381  Brains Co. Ltd
 1382  Marian - Electronic & Software
-	2088  Marc-8 MIDI 8 channel audio card
+	0001  ARC88 audio recording card
+	2008  Prodif 96 Pro sound system
+	2088  Marc 8 Midi sound system
+	20c8  Marc A sound system
+	4008  Marc 2 sound system
+	4010  Marc 2 Pro sound system
+	4048  Marc 4 MIDI sound system
+	4088  Marc 4 Digi sound system
+	4248  Marc X sound system
 1383  Controlnet Inc
 1384  Reality Simulation Systems Inc
 1385  Netgear
+# Note: This lists as Atheros Communications, Inc. AR5212 802.11abg NIC because of Madwifi
+	0013  WG311T
+	311a  GA511 Gigabit Ethernet
 	4100  802.11b Wireless Adapter (MA301)
 	4105  MA311 802.11b wireless adapter
-	4a00  WAG311 802.11abg Wireless Adapter
+	4400  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4600  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4601  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4610  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4a00  WAG311 802.11a/g Wireless PCI Adapter
+	4c00  WG311v2 54 Mbps Wireless PCI Adapter
 	620a  GA620 Gigabit Ethernet
 	622a  GA622
 	630a  GA630 Gigabit Ethernet
@@ -5817,6 +6656,8 @@
 	0016  8065 Security Processor
 	0017  8165 Security Processor
 	0018  8154 Security Processor
+	001d  7956 Security Processor
+	0020  7955 Security Processor
 13a4  Rascom Inc
 13a5  Audio Digital Imaging Inc
 13a6  Videonics Inc
@@ -5853,10 +6694,10 @@
 	0030  SyncLink Multiport Adapter
 	0210  SyncLink Adapter v2
 13c1  3ware Inc
-	1000  3ware ATA-RAID
-	1001  3ware 7000-series ATA-RAID
+	1000  3ware Inc 3ware 5xxx/6xxx-series PATA-RAID
+	1001  3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID
 		13c1 1001  3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID
-	1002  3ware ATA-RAID
+	1002  3ware Inc 3ware 9xxx-series SATA-RAID
 13c2  Technotrend Systemtechnik GmbH
 13c3  Janz Computer AG
 13c4  Phase Metrics
@@ -5944,6 +6785,7 @@
 13fc  Computer Peripherals International
 13fd  Micro Science Inc
 13fe  Advantech Co. Ltd
+	1240  PCI-1240 4-channel stepper motor controller card w.  Nova Electronics MCX314
 	1600  PCI-1612 4-port RS-232/422/485 PCI Communication Card
 	1752  PCI-1752
 	1754  PCI-1754
@@ -5961,6 +6803,8 @@
 	0100  Lava Dual Serial
 	0101  Lava Quatro A
 	0102  Lava Quatro B
+	0110  Lava DSerial-PCI Port A
+	0111  Lava DSerial-PCI Port B
 	0120  Quattro-PCI A
 	0121  Quattro-PCI B
 	0180  Lava Octo A
@@ -5991,17 +6835,47 @@
 # formerly IC Ensemble Inc.
 1412  VIA Technologies Inc.
 	1712  ICE1712 [Envy24] PCI Multi-Channel I/O Controller
+		1412 1712  Hoontech ST Audio DSP 24
+		1412 d630  M-Audio Delta 1010
+		1412 d631  M-Audio Delta DiO
+		1412 d632  M-Audio Delta 66
+		1412 d633  M-Audio Delta 44
+		1412 d634  M-Audio Delta Audiophile
+		1412 d635  M-Audio Delta TDIF
+		1412 d637  M-Audio Delta RBUS
 		1412 d638  M-Audio Delta 410
+		1412 d63b  M-Audio Delta 1010LT
+		1412 d63c  Digigram VX442
+		1416 1712  Hoontech ST Audio DSP 24 Media 7.1
+		153b 1115  EWS88 MT
+		153b 1125  EWS88 MT (Master)
+		153b 112b  EWS88 D
+		153b 112c  EWS88 D (Master)
+		153b 1130  EWX 24/96
+		153b 1138  DMX 6fire 24/96
+		153b 1151  PHASE88
+		16ce 1040  Edirol DA-2496
 	1724  VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller
+		1412 1724  AMP Ltd AUDIO2000
+		1412 3630  M-Audio Revolution 7.1
+		153b 1145  Aureon 7.1 Space
+		153b 1147  Aureon 5.1 Sky
+		153b 1153  Aureon 7.1 Universe
+		270f f641  ZNF3-150
+		270f f645  ZNF3-250
 1413  Addonics
 1414  Microsoft Corporation
 1415  Oxford Semiconductor Ltd
 	8403  VScom 011H-EP1 1 port parallel adaptor
 	9501  OX16PCI954 (Quad 16950 UART) function 0
+		131f 2050  CyberPro (4-port)
+# Model IO1085, Part No: JJ-P46012
+		131f 2051  CyberSerial 4S Plus
 		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
+	9510  OX16PCI954 (Quad 16950 UART) function 1 (Disabled)
 	9511  OX16PCI954 (Quad 16950 UART) function 1
 		15ed 2000  MCCR Serial p4-7 of 8
 		15ed 2001  MCCR Serial p4-15 of 16
@@ -6022,7 +6896,7 @@
 1422  Ygrec Systems Co Ltd
 1423  Custom Technology Corp.
 1424  Videoserver Connections
-1425  ASIC Designers Inc
+1425  Chelsio Communications Inc
 1426  Storage Technology Corp.
 1427  Better On-Line Solutions
 1428  Edec Co Ltd
@@ -6067,6 +6941,7 @@
 	7434  PCI-7434
 	7841  PCI-7841
 	8133  PCI-8133
+	8164  PCI-8164
 	8554  PCI-8554
 	9111  PCI-9111
 	9113  PCI-9113
@@ -6084,6 +6959,7 @@
 1456  Advanced Hardware Architectures
 1457  Nuera Communications Inc
 1458  Giga-byte Technology
+	0c11  K8NS Pro Mainboard
 1459  DOOIN Electronics
 145a  Escalate Networks Inc
 145b  PRAIM SRL
@@ -6095,11 +6971,15 @@
 1460  DYNARC INC
 1461  Avermedia Technologies Inc
 1462  Micro-Star International Co., Ltd.
+# MSI CB54G Wireless PC Card that seems to use the Broadcom 4306 Chipset
+	6819  Broadcom Corporation BCM4306 802.11b/g Wireless LAN Controller [MSI CB54G]
 	6825  PCI Card wireless 11g [PC54G]
 	8725  NVIDIA NV25 [GeForce4 Ti 4600] VGA Adapter
 # MSI G4Ti4800, 128MB DDR SDRAM, TV-Out, DVI-I
 	9000  NVIDIA NV28 [GeForce4 Ti 4800] VGA Adapter
+	9110  GeFORCE FX5200
 	9119  NVIDIA NV31 [GeForce FX 5600XT] VGA Adapter
+	9591  nVidia Corporation NV36 [GeForce FX 5700LE]
 1463  Fast Corporation
 1464  Interactive Circuits & Systems Ltd
 1465  GN NETTEST Telecom DIV.
@@ -6156,6 +7036,7 @@
 1496  JOYTECH Computer Co., Ltd.
 1497  SMA Regelsysteme GmBH
 1498  TEWS Datentechnik GmBH
+	30c8  TPCI200
 1499  EMTEC CO., Ltd
 149a  ANDOR Technology Ltd
 149b  SEIKO Instruments Inc
@@ -6205,9 +7086,10 @@
 	0340  PC4800
 	0350  PC4800
 	4500  PC4500
-	4800  Cisco Aironet 340 802.11b WLAN Adapter/Aironet PC4800
+	4800  Cisco Aironet 340 802.11b Wireless LAN Adapter/Aironet PC4800
 	a504  Cisco Aironet Wireless 802.11b
 	a505  Cisco Aironet CB20a 802.11a Wireless LAN Adapter
+	a506  Cisco Aironet Mini PCI b/g
 14ba  INTERNIX Inc.
 14bb  SEMTECH Corporation
 14bc  Globespan Semiconductor Inc.
@@ -6259,6 +7141,7 @@
 # Formerly SiPackets, Inc., formerly API NetWorks, Inc., formerly Alpha Processor, Inc.
 14d9  Alliance Semiconductor Corporation
 	0010  AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon]
+	9000  AS90L10204/10208 HyperTransport to PCI-X Bridge
 14da  National Aerospace Laboratories
 14db  AFAVLAB Technology Inc
 	2120  TK9902
@@ -6290,6 +7173,7 @@
 	080f  Sentry5 DDR/SDR RAM Controller
 	0811  Sentry5 External Interface Core
 	0816  BCM3302 Sentry5 MIPS32 CPU
+	1600  NetXtreme BCM5752 Gigabit Ethernet PCI Express
 	1644  NetXtreme BCM5700 Gigabit Ethernet
 		1014 0277  Broadcom Vigil B5700 1000Base-T
 		1028 00d1  Broadcom BCM5700
@@ -6353,17 +7237,28 @@
 		10b7 2000  3C998-T Dual Port 10/100/1000 PCI-X
 		10b7 3000  3C999-T Quad Port 10/100/1000 PCI-X
 		1166 1648  NetXtreme CIOB-E 1000Base-T
+	164a  NetXtreme II BCM5706 Gigabit Ethernet
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	1653  NetXtreme BCM5705 Gigabit Ethernet
+		0e11 00e3  NC7761 Gigabit Server Adapter
 	1654  NetXtreme BCM5705_2 Gigabit Ethernet
+		0e11 00e3  NC7761 Gigabit Server Adapter
+		103c 3100  NC1020 HP ProLiant Gigabit Server Adapter 32 PCI
 	1659  NetXtreme BCM5721 Gigabit Ethernet PCI Express
 	165d  NetXtreme BCM5705M Gigabit Ethernet
 	165e  NetXtreme BCM5705M_2 Gigabit Ethernet
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	166e  570x 10/100 Integrated Controller
 	1677  NetXtreme BCM5751 Gigabit Ethernet PCI Express
+		1028 0179  Optiplex GX280
+	167d  NetXtreme BCM5751M Gigabit Ethernet PCI Express
+	167e  NetXtreme BCM5751F Fast Ethernet PCI Express
 	1696  NetXtreme BCM5782 Gigabit Ethernet
 		103c 12bc  HP d530 CMT (DG746A)
 		14e4 000d  NetXtreme BCM5782 1000Base-T
 	169c  NetXtreme BCM5788 Gigabit Ethernet
+	169d  NetLink BCM5789 Gigabit Ethernet PCI Express
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 		0e11 00bb  NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
 		1028 0126  BCM5702 1000Base-T
@@ -6378,39 +7273,67 @@
 		14e4 800a  NetXtreme BCM5703 1000Base-T
 	16a8  NetXtreme BCM5704S Gigabit Ethernet
 		10b7 2001  3C998-SX Dual Port 1000-SX PCI-X
+	16aa  NetXtreme II BCM5706S Gigabit Ethernet
 	16c6  NetXtreme BCM5702A3 Gigabit Ethernet
 		10b7 1100  3C1000B-T 10/100/1000 PCI
 		14e4 000c  BCM5702 1000Base-T
 		14e4 8009  BCM5702 1000Base-T
 	16c7  NetXtreme BCM5703 Gigabit Ethernet
+		0e11 00ca  NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		0e11 00cb  NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
 		103c 12c3  HP Combo FC/GigE-SX [A9782A]
 		103c 12ca  HP Combo FC/GigE-T [A9784A]
 		14e4 0009  NetXtreme BCM5703 1000Base-T
 		14e4 000a  NetXtreme BCM5703 1000Base-SX
+	16dd  NetLink BCM5781 Gigabit Ethernet PCI Express
+	16f7  NetXtreme BCM5753 Gigabit Ethernet PCI Express
+	16fd  NetXtreme BCM5753M Gigabit Ethernet PCI Express
+	16fe  NetXtreme BCM5753F Fast Ethernet PCI Express
 	170c  BCM4401-B0 100Base-TX
 	170d  NetXtreme BCM5901 100Base-TX
+		1014 0545  ThinkPad R40e (2684-HVG) builtin ethernet controller
 	170e  NetXtreme BCM5901 100Base-TX
 	3352  BCM3352
 	3360  BCM3360
 	4210  BCM4210 iLine10 HomePNA 2.0
 	4211  BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem
 	4212  BCM4212 v.90 56k modem
-	4301  BCM4301 802.11b
+	4301  BCM4303 802.11b Wireless LAN Controller
+		1028 0407  TrueMobile 1180 Onboard WLAN
+		1043 0120  WL-103b Wireless LAN PC Card
+	4305  BCM4307 V.90 56k Modem
+	4306  BCM4307 Ethernet Controller
 	4307  BCM4307 802.11b Wireless LAN Controller
+	4310  BCM4310 Chipcommon I/OController
+	4312  BCM4310 UART
+	4313  BCM4310 Ethernet Controller
+	4315  BCM4310 USB Controller
 	4320  BCM4306 802.11b/g Wireless LAN Controller
 		1028 0001  TrueMobile 1300 WLAN Mini-PCI Card
+		1028 0003  Wireless 1350 WLAN Mini-PCI Card
+		1043 100f  WL-100G
+		14e4 4320  Linksys WMP54G PCI
 		1737 4320  WPC54G
+		1799 7010  Belkin F5D7010 54g Wireless Network card
+	4321  BCM4306 802.11a Wireless LAN Controller
+	4322  BCM4306 UART
 	4324  BCM4309 802.11a/b/g
 		1028 0001  Truemobile 1400
+		1028 0003  Truemobile 1450 MiniPCI
+	4325  BCM43xG 802.11b/g
+		1414 0003  Wireless Notebook Adapter MN-720
+		1414 0004  Wireless PCI Adapter MN-730
+# probably this is a correct ID...
+	4326  BCM4307 Chipcommon I/O Controller?
 	4401  BCM4401 100Base-T
 		1043 80a8  A7V8X motherboard
 	4402  BCM4402 Integrated 10/100BaseT
 	4403  BCM4402 V.90 56k Modem
 	4410  BCM4413 iLine32 HomePNA 2.0
 	4411  BCM4413 V.90 56k modem
-	4412  BCM4413 10/100BaseT
+	4412  BCM4412 10/100BaseT
 	4430  BCM44xx CardBus iLine32 HomePNA 2.0
-	4432  BCM44xx CardBus 10/100BaseT
+	4432  BCM4432 CardBus 10/100BaseT
 	4610  BCM4610 Sentry5 PCI to SB Bridge
 	4611  BCM4610 Sentry5 iLine32 HomePNA 1.0
 	4612  BCM4610 Sentry5 V.90 56k Modem
@@ -6418,16 +7341,20 @@
 	4614  BCM4610 Sentry5 External Interface
 	4615  BCM4610 Sentry5 USB Controller
 	4704  BCM4704 PCI to SB Bridge
-	4708  BCM4708 Sentry5 PCI to SB Bridge
+	4705  BCM4704 Sentry5 802.11b Wireless LAN Controller
+	4706  BCM4704 Sentry5 Ethernet Controller
+	4707  BCM4704 Sentry5 USB Controller
+	4708  BCM4704 Crypto Accelerator
 	4710  BCM4710 Sentry5 PCI to SB Bridge
 	4711  BCM47xx Sentry5 iLine32 HomePNA 2.0
-	4712  Sentry5 UART
+	4712  BCM47xx V.92 56k modem
 	4713  Sentry5 Ethernet Controller
 	4714  BCM47xx Sentry5 External Interface
 	4715  Sentry5 USB Controller
 	4716  BCM47xx Sentry5 USB Host Controller
 	4717  BCM47xx Sentry5 USB Device Controller
 	4718  Sentry5 Crypto Accelerator
+	4720  BCM4712 MIPS CPU
 	5365  BCM5365P Sentry5 Host Bridge
 	5600  BCM5600 StrataSwitch 24+2 Ethernet Switch Controller
 	5605  BCM5605 StrataSwitch 24+2 Ethernet Switch Controller
@@ -6595,20 +7522,29 @@
 		13e0 8d84  IBM HSFi V.90
 		13e0 8d85  Compaq Stinger
 		14f1 2004  Dynalink 56PMi
+	2f02  HSF 56k HSFi Data/Fax
+	2f11  HSF 56k HSFi Modem
 	8234  RS8234 ATM SAR Controller [ServiceSAR Plus]
-	8800  Winfast TV2000 XP
+	8800  CX22702 DVB-T 2k/8k
+		17de 08a1  XPert DVB-T PCI BDA DVBT 23880 Video Capture
+	8802  CX23883 Broadcast Decoder
+		17de 08a1  Xpert DVB-T PCI 2388x Transport Stream Capture
 14f2  MOBILITY Electronics
 	0120  EV1000 bridge
 	0121  EV1000 Parallel port
 	0122  EV1000 Serial port
 	0123  EV1000 Keyboard controller
 	0124  EV1000 Mouse controller
-14f3  BROADLOGIC
+14f3  BroadLogic
+	2030  2030 DVB-S Satellite Reciever
+	2050  2050 DVB-T Terrestrial (Cable) Reciever
+	2060  2060 ATSC Terrestrial (Cable) Reciever
 14f4  TOKYO Electronic Industry CO Ltd
 14f5  SOPAC Ltd
 14f6  COYOTE Technologies LLC
 14f7  WOLF Technology Inc
 14f8  AUDIOCODES Inc
+	2077  TP-240 dual span E1 VoIP PCI card
 14f9  AG COMMUNICATIONS
 14fa  WANDEL & GOCHERMANN
 14fb  TRANSAS MARINE (UK) Ltd
@@ -6665,6 +7601,8 @@
 	1008  PCI-1008
 151b  COMBOX Ltd
 151c  DIGITAL AUDIO LABS Inc
+	0003  Prodif T 2496
+	4000  Prodif 88
 151d  Fujitsu Computer Products Of America
 151e  MATRIX Corp
 151f  TOPIC SEMICONDUCTOR Corp
@@ -6687,12 +7625,16 @@
 1523  MUSIC Semiconductors
 1524  ENE Technology Inc
 	0510  CB710 Memory Card Reader Controller
+	0610  PCI Smart Card Reader Controller
 	1211  CB1211 Cardbus Controller
 	1225  CB1225 Cardbus Controller
 	1410  CB1410 Cardbus Controller
-	1411  CB710 Cardbus Controller
+		1025 005a  TravelMate 290
+	1411  CB-710/2/4 Cardbus Controller
+	1412  CB-712/4 Cardbus Controller
 	1420  CB1420 Cardbus Controller
-	1421  CB720 Cardbus Controller
+	1421  CB-720/2/4 Cardbus Controller
+	1422  CB-722/4 Cardbus Controller
 1525  IMPACT Technologies
 1526  ISS, Inc
 1527  SOLECTRON
@@ -6717,6 +7659,9 @@
 153a  ONO SOKKI
 153b  TERRATEC Electronic GmbH
 	1144  Aureon 5.1
+# Terratec seems to use several IDs for the same card.
+	1147  Aureon 5.1 Sky
+	1158  Philips Semiconductors SAA7134 (rev 01) [Terratec Cinergy 600 TV]
 153c  ANTAL Electronic
 153d  FILANET Corp
 153e  TECHWELL Inc
@@ -6798,6 +7743,7 @@
 1575  Voltaire Advanced Data Security Ltd
 1576  Viewcast COM
 1578  HITT
+	5615  VPMK3 [Video Processor Mk III]
 1579  Dual Technology Corp
 157a  Japan Elecronics Ind Inc
 157b  Star Multimedia Corp
@@ -6859,18 +7805,24 @@
 15aa  Moreton Bay
 15ab  Bluesteel Networks Inc
 15ac  North Atlantic Instruments
-15ad  VMWare Inc
-	0405  [VMWare SVGA II] PCI Display Adapter
+15ad  VMware Inc
+	0405  [VMware SVGA II] PCI Display Adapter
 	0710  Virtual SVGA
+	0720  VMware High-Speed Virtual NIC [vmxnet]
 15ae  Amersham Pharmacia Biotech
 15b0  Zoltrix International Ltd
 15b1  Source Technology Inc
 15b2  Mosaid Technologies Inc
-15b3  Mellanox Technology
+15b3  Mellanox Technologies
 	5274  MT21108 InfiniBridge
 	5a44  MT23108 InfiniHost
-	5a45  MT23108 InfiniHost (Tavor)
+	5a45  MT23108 [Infinihost HCA Flash Recovery]
 	5a46  MT23108 PCI Bridge
+	5e8c  MT24204 [InfiniHost III Lx HCA]
+	5e8d  MT24204 [InfiniHost III Lx HCA Flash Recovery]
+	6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)
+	6279  MT25208 [InfiniHost III Ex HCA Flash Recovery]
+	6282  MT25208 InfiniHost III Ex
 15b4  CCI/TRIAD
 15b5  Cimetrics Inc
 15b6  Texas Memory Systems Inc
@@ -6981,7 +7933,7 @@
 1637  Linksys
 	3874  Linksys 802.11b WMP11 PCI Wireless card
 1638  Standard Microsystems Corp [SMC]
-	1100  SMC2602W EZConnect/Addtron AWA-100/Eumitcom WL11000
+	1100  SMC2602W EZConnect / Addtron AWA-100 / Eumitcom PCI WL11000
 163c  Smart Link Ltd.
 	3052  SmartLink SmartPCI562 56K Modem
 	5449  SmartPCI561 Modem
@@ -6998,9 +7950,16 @@
 166d  Broadcom Corporation
 	0001  SiByte BCM1125/1125H/1250 System-on-a-Chip PCI
 	0002  SiByte BCM1125H/1250 System-on-a-Chip HyperTransport
+1677  Bernecker + Rainer
+	104e  5LS172.6 B&R Dual CAN Interface Card
+	12d7  5LS172.61 B&R Dual CAN Interface Card
+167b  ZyDAS Technology Corp.
+	2102  ZyDAS ZD1202
+		187e 3406  ZyAIR B-122 CardBus 11Mbs Wireless LAN Card
 1681  Hercules
 # More specs, more accurate desc.
 	0010  Hercules 3d Prophet II Ultra 64MB [ 350 MHz NV15BR core, 128-bit DDR @ 460 MHz, 1.5v AGP4x  ]
+1682  XFX Pine Group Inc.
 1688  CastleNet Technology Inc.
 	1170  WLAN 802.11b card
 168c  Atheros Communications, Inc.
@@ -7008,30 +7967,47 @@
 	0011  AR5210 802.11a NIC
 	0012  AR5211 802.11ab NIC
 	0013  AR5212 802.11abg NIC
+		1113 d301  Philips CPWNA100 Wireless CardBus adapter
 		1186 3202  D-link DWL-G650 B3 Wireless cardbus adapter
 		1186 3203  DWL-G520 Wireless PCI Adapter
+		1186 3a13  DWL-G520 Wireless PCI Adapter rev. B
 		1186 3a94  C54C Wireless 801.11g cardbus
+		1385 4d00  Netgear WG311T Wireless PCI Adapter
+		14b7 0a60  8482-WD ORiNOCO 11a/b/g Wireless PCI Adapter
 		168c 0013  WG511T Wireless CardBus Adapter
 		168c 1025  DWL-G650B2 Wireless CardBus Adapter
+		168c 1027  Netgate NL-3054CB ARIES b/g CardBus Adapter
+		168c 2026  Netgate 5354MP ARIES a(108Mb turbo)/b/g MiniPCI Adapter
+		168c 2041  Netgate 5354MP Plus ARIES2 b/g MiniPCI Adapter
+		168c 2042  Netgate 5354MP Plus ARIES2 a/b/g MiniPCI Adapter
 	1014  AR5212 802.11abg NIC
+169c  Netcell Corporation
+	0044  SyncRAID SR3000/5000 Series SATA RAID Controllers
 16a5  Tekram Technology Co.,Ltd.
 16ab  Global Sun Technology Inc
 	1100  GL24110P
 	1101  PLX9052 PCMCIA-to-PCI Wireless LAN
 	1102  PCMCIA-to-PCI Wireless Network Bridge
+	8501  WL-8305 Wireless LAN PCI Adapter
 16ae  Safenet Inc
 	1141  SafeXcel-1141
+16b4  Aspex Semiconductor Ltd
 16be  Creatix Polymedia GmbH
 16ca  CENATEK Inc
 	0001  Rocket Drive DL
 16cd  Densitron Technologies
+16ce  Roland Corp.
 # www.pikatechnologies.com
 16df  PIKA Technologies Inc.
 16e3  European Space Agency
 	1e0f  LEON2FT Processor
 16ec  U.S. Robotics
 	00ff  USR997900 10/100 Mbps PCI Network Card
+	0116  USR997902 10/100/1000 Mbps PCI Network Card
 	3685  Wireless Access PCI Adapter Model 022415
+16ed  Sycron N. V.
+	1001  UMIO communication card
+16f3  Jetway Information Co., Ltd.
 16f4  Vweb Corp
 	8000  VW2010
 16f6  VideoTele.com, Inc.
@@ -7045,8 +8021,10 @@
 1725  Vitesse Semiconductor
 	7174  VSC7174 PCI/PCI-X Serial ATA Host Bus Controller
 172a  Accelerated Encryption
+1734  Fujitsu Siemens Computer GmbH
 1737  Linksys
 	0013  WMP54G Wireless Pci Card
+	0015  WMP54GS Wireless Pci Card
 	1032  Gigabit Network Adapter
 		1737 0015  EG1032 v2 Instant Gigabit Network Adapter
 	1064  Gigabit Network Adapter
@@ -7081,6 +8059,9 @@
 	6020  Wireless PCMCIA Card - F5D6020
 	6060  Wireless PDA Card - F5D6060
 	7000  Wireless PCI Card - F5D7000
+17a0  Genesys Logic, Inc
+	8033  GL880S USB 1.1 controller
+	8034  GL880S USB 2.0 controller
 17af  Hightech Information System Ltd.
 17b3  Hawking Technologies
 	ab08  PN672TX 10/100 Ethernet
@@ -7090,11 +8071,25 @@
 17c2  Newisys, Inc.
 17cc  NetChip Technology, Inc
 	2280  USB 2.0
+17d3  Areca Technology Corp.
+	1110  ARC-1110 4-Port PCI-X to SATA RAID Controller
+	1120  ARC-1120 8-Port PCI-X to SATA RAID Controller
+	1130  ARC-1130 12-Port PCI-X to SATA RAID Controller
+	1160  ARC-1160 16-Port PCI-X to SATA RAID Controller
+	1210  ARC-1210 4-Port PCI-Express to SATA RAID Controller
+	1220  ARC-1220 8-Port PCI-Express to SATA RAID Controller
+	1230  ARC-1230 12-Port PCI-Express to SATA RAID Controller
+	1260  ARC-1260 16-Port PCI-Express to SATA RAID Controller
 # S2io ships 10Gb PCI-X Ethernet adapters www.s2io.com
 17d5  S2io Inc.
-# Supplying full name for a currently green entry
+	5831  Xframe 10 Gigabit Ethernet PCI-X
+		103c 12d5  HP PCI-X 133MHz 10GbE SR Fiber [AB287A]
+17de  KWorld Computer Co. Ltd.
+# http://www.connect3d.com
+17ee  Connect Components Ltd
 17fe  Linksys, A Division of Cisco Systems
-	2220  [AirConn] INPROCOMM IPN 2220 WLAN Adapter (rev 01)
+	2120  WMP11v4 802.11b PCI card
+	2220  [AirConn] INPROCOMM IPN 2220 Wireless LAN Adapter (rev 01)
 1813  Ambient Technologies Inc
 	4000  HaM controllerless modem
 		16be 0001  V9x HAM Data Fax Modem
@@ -7102,16 +8097,34 @@
 		16be 0002  V9x HAM 1394
 1814  RaLink
 	0101  Wireless PCI Adpator RT2400 / RT2460
+		3306 1113  Quidway WL100M
 	0201  Ralink RT2500 802.11 Cardbus Reference Card
+		1371 001e  CWC-854 Wireless-G CardBus Adapter
+		1371 001f  CWM-854 Wireless-G Mini PCI Adapter
+		1371 0020  CWP-854 Wireless-G PCI Adapter
+		1458 e381  GN-WMKG 802.11b/g Wireless CardBus Adapter
 1820  InfiniCon Systems Inc.
 1822  Twinhan Technology Co. Ltd
+182d  SiteCom Europe BV
+# HFC-based ISDN card
+	3069  ISDN PCI DC-105V2
+	9790  WL-121 Wireless Network Adapter 100g+ [Ver.3]
 1830  Credence Systems Corporation
+183b  MikroM GmbH
+	08a7  MVC100 DVI
+	08a8  MVC101 SDI
+	08a9  MVC102 DVI+Audio
+1849  ASRock Incorporation
 1851  Microtune, Inc.
 1852  Anritsu Corp.
+185f  Wistron NeWeb Corp.
 1867  Topspin Communications
 	5a44  MT23108 PCI-X HCA
 	5a45  MT23108 PCI-X HCA flash recovery
 	5a46  MT23108 PCI-X HCA bridge
+	6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)
+	6282  MT25208 InfiniHost III Ex
+187e  ZyXEL Communication Corporation
 1888  Varisys Ltd
 	0301  VMFX1 FPGA PMC module
 	0601  VSM2 dual PMC carrier
@@ -7119,14 +8132,33 @@
 	0720  VS24x series PowerPC PCI board
 # found e.g. on KNC DVB-S card
 1894  KNC One
+1896  B&B Electronics Manufacturing Company, Inc.
 18a1  Astute Networks Inc.
+18ac  DViCO Corporation
+	d810  FusionHDTV 3 Gold
+18b8  Ammasso
+	b001  AMSO 1100 iWARP/RDMA Gigabit Ethernet Coprocessor
 18bc  Info-Tek Corp.
+# assigned to Octigabay System, which has been acquired by Cray
+18c8  Cray Inc
 18c9  ARVOO Engineering BV
 18ca  XGI - Xabre Graphics Inc
 	0040  Volari V8
 18e6  MPL AG
 	0001  OSCI [Octal Serial Communication Interface]
+18f7  Commtech, Inc.
+	0001  Fastcom ESCC-PCI-335
+	0002  Fastcom 422/4-PCI-335
+	0004  Fastcom 422/2-PCI-335
+	0005  Fastcom IGESCC-PCI-ISO/1
+	000a  Fastcom 232/4-PCI-335
 18fb  Resilience Corporation
+1924  Level 5 Networks Inc.
+1966  Orad Hi-Tec Systems
+	1975  DVG64 family
+1993  Innominate Security Technologies AG
+# http://www.progeny.net
+19ae  Progeny Systems Corporation
 1a08  Sierra semiconductor
 	0000  SC15064
 1b13  Jaton Corp
@@ -7165,6 +8197,7 @@
 		4c53 10a0  CA3/CR3 mainboard
 		4c53 3010  PPCI mezzanine (32-bit PMC)
 		4c53 3011  PPCI mezzanine (64-bit PMC)
+	0022  HiNT HB4 PCI-PCI Bridge (PCI6150)
 	0026  HB2 PCI-PCI Bridge
 	101a  E.Band [AudioTrak Inca88]
 	101b  E.Band [AudioTrak Inca88]
@@ -7176,6 +8209,7 @@
 		3388 8013  VXPro II Chipset EIDE Controller
 3411  Quantum Designs (H.K.) Inc
 3513  ARCOM Control Systems Ltd
+3842  eVga.com. Corp.
 38ef  4Links
 3d3d  3DLabs
 	0001  GLINT 300SX
@@ -7211,6 +8245,7 @@
 	0024  VP9 visual processor
 	0100  Permedia II 2D+3D
 	07a1  Wildcat III 6210
+	07a2  Sun XVR-500 Graphics Accelerator
 	07a3  Wildcat IV 7210
 	1004  Permedia
 	3d04  Permedia
@@ -7235,15 +8270,19 @@
 	1360  RTL8139 Ethernet
 4143  Digital Equipment Corp
 4144  Alpha Data
+	0044  ADM-XRCIIPro
 416c  Aladdin Knowledge Systems
 	0100  AladdinCARD
 	0200  CPC
 4444  Internext Compression Inc
 	0016  iTVC16 (CX23416) MPEG-2 Encoder
 		0070 4009  WinTV PVR 250
+		0070 8003  WinTV PVR 150
 	0803  iTVC15 MPEG-2 Encoder
 		0070 4000  WinTV PVR-350
 		0070 4001  WinTV PVR-250
+# video capture card
+		1461 a3cf  M179
 4468  Bridgeport machines
 4594  Cogetec Informatique Inc
 45fb  Baldor Electric Company
@@ -7252,6 +8291,8 @@
 4916  RedCreek Communications Inc
 	1960  RedCreek PCI adapter
 4943  Growth Networks
+494f  ACCES I/O Products, Inc.
+	10e8  LPCI-COM-8SM
 4978  Axil Computer Inc
 4a14  NetVin
 	5000  NV5000SC
@@ -7366,6 +8407,7 @@
 	8a22  Savage 4
 		1033 8068  Savage 4
 		1033 8069  Savage 4
+		1033 8110  Savage4 LT
 		105d 0018  SR9 8Mb SDRAM
 		105d 002a  SR9 Pro 16Mb SDRAM
 		105d 003a  SR9 Pro 32Mb SDRAM
@@ -7404,6 +8446,7 @@
 	8c11  82C270-294 Savage/MX
 	8c12  86C270-294 Savage/IX-MV
 		1014 017f  ThinkPad T20
+		1179 0001  86C584 SuperSavage/IXC Toshiba
 	8c13  86C270-294 Savage/IX
 		1179 0001  Magnia Z310
 	8c22  SuperSavage MX/128
@@ -7458,7 +8501,7 @@
 	0011  PWDOG2 [PCI-Watchdog 2]
 # Wrong ID used in subsystem ID of AsusTek PCI-USB2 PCI card.
 807d  Asustek Computer, Inc.
-8086  Intel Corp.
+8086  Intel Corporation
 	0007  82379AB
 	0008  Extended Express System Support Controller
 		0008 1000  WorldMark 4300 INCA ASIC
@@ -7466,11 +8509,11 @@
 	0122  82437FX
 	0309  80303 I/O Processor PCI-to-PCI Bridge
 	030d  80312 I/O Companion Chip PCI-to-PCI Bridge
-	0326  PCI Bridge Hub I/OxAPIC Interrupt Controller A
-	0327  PCI Bridge Hub I/OxAPIC Interrupt Controller B
-	0329  PCI Bridge Hub A
-	032a  PCI Bridge Hub B
-	032c  PCI Bridge Hub
+	0326  6700/6702PXH I/OxAPIC Interrupt Controller A
+	0327  6700PXH I/OxAPIC Interrupt Controller B
+	0329  6700PXH PCI Express-to-PCI Bridge A
+	032a  6700PXH PCI Express-to-PCI Bridge B
+	032c  6702PXH PCI Express-to-PCI Bridge A
 # A-segment bridge
 	0330  80332 [Dobson] I/O processor
 # A-segment IOAPIC
@@ -7521,6 +8564,8 @@
 	0600  RAID Controller
 		8086 01c1  ICP Vortex GDT8546RZ
 		8086 01f7  SCRU32
+# uninitialized SRCU32 RAID Controller
+	061f  80303 I/O Processor
 	0960  80960RP [i960 RP Microprocessor/Bridge]
 	0962  80960RM [i960RM Bridge]
 	0964  80960RP [i960 RP Microprocessor/Bridge]
@@ -7533,6 +8578,7 @@
 	1001  82543GC Gigabit Ethernet Controller (Fiber)
 		0e11 004a  NC6136 Gigabit Server Adapter
 		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
+		8086 1002  PRO/1000 F Server 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
@@ -7567,6 +8613,8 @@
 		1014 0265  PRO/1000 MT Network Connection
 		1014 0267  PRO/1000 MT Network Connection
 		1014 026a  PRO/1000 MT Network Connection
+		1028 002e  Optiplex GX260
+		1028 0151  PRO/1000 MT Network Connection
 		107b 8920  PRO/1000 MT Desktop Adapter
 		8086 001e  PRO/1000 MT Desktop Adapter
 		8086 002e  PRO/1000 MT Desktop Adapter
@@ -7582,6 +8630,7 @@
 		4c53 10a0  CA3/CR3 mainboard
 		8086 1011  PRO/1000 MT Dual Port Server Adapter
 		8086 101a  PRO/1000 MT Dual Port Network Adapter
+		8086 3424  SE7501HG2 Mainboard
 	1011  82545EM Gigabit Ethernet Controller (Fiber)
 		1014 0268  iSeries Gigabit Ethernet Adapter
 		8086 1002  PRO/1000 MF Server Adapter
@@ -7590,6 +8639,7 @@
 		8086 1012  PRO/1000 MF Dual Port Server Adapter
 	1013  82541EI Gigabit Ethernet Controller (Copper)
 		8086 0013  PRO/1000 MT Network Connection
+		8086 1013  IBM ThinkCentre Network Card
 		8086 1113  PRO/1000 MT Desktop Adapter
 	1014  82541ER Gigabit Ethernet Controller
 	1015  82540EM Gigabit Ethernet Controller (LOM)
@@ -7604,7 +8654,9 @@
 		8086 1018  PRO/1000 MT Desktop Adapter
 	1019  82547EI Gigabit Ethernet Controller (LOM)
 		1458 1019  GA-8IPE1000 Pro2 motherboard (865PE)
+		1458 e000  Intel Gigabit Ethernet (Kenai II)
 		8086 1019  PRO/1000 CT Desktop Connection
+		8086 301f  D865PERL mainboard
 		8086 3427  S875WP1-E mainboard
 	101d  82546EB Gigabit Ethernet Controller
 		8086 1000  PRO/1000 MT Quad Port Server Adapter
@@ -7642,13 +8694,13 @@
 	1036  82801CAM (ICH3) 82562EH Ethernet Controller
 	1037  82801CAM (ICH3) Chipset Ethernet Controller
 	1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller
-	1039  82801BD PRO/100 VE (LOM) Ethernet Controller
+	1039  82801DB PRO/100 VE (LOM) Ethernet Controller
 		1014 0267  NetVista A30p
-	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
+	103a  82801DB PRO/100 VE (CNR) Ethernet Controller
+	103b  82801DB PRO/100 VM (LOM) Ethernet Controller
+	103c  82801DB PRO/100 VM (CNR) Ethernet Controller
+	103d  82801DB PRO/100 VE (MOB) Ethernet Controller
+	103e  82801DB PRO/100 VM (MOB) Ethernet Controller
 	1040  536EP Data Fax Modem
 		16be 1040  V.9X DSP Data Fax Modem
 	1043  PRO/Wireless LAN 2100 3B Mini PCI Adapter
@@ -7659,45 +8711,59 @@
 	1050  82562EZ 10/100 Ethernet Controller
 		1462 728c  865PE Neo2 (MS-6728)
 		1462 758c  MS-6758 (875P Neo)
+		8086 3020  D865PERL mainboard
 		8086 3427  S875WP1-E mainboard
 	1051  82801EB/ER (ICH5/ICH5R) integrated LAN Controller
 	1059  82551QM Ethernet Controller
-	1065  82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller
-# Updated controller name from 82547EI to 82547GI
+# ICH-6 Component
+	1064  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller
+# ICH-6 Component
+	1065  82562ET/EZ/GT/GZ - PRO/100 VE Ethernet Controller
+# ICH-6 Component
+	1066  82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller
+# ICH-6 Component
+	1067  82562 EM/EX/GX - PRO/100 VM Ethernet Controller
+# ICH-6 Component
+	1068  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller Mobile
+# ICH-6 Component
+	1069  82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller Mobile
+# ICH-6 Component
+	106a  82562G \t- PRO/100 VE (LOM) Ethernet Controller
+# ICH-6 Component
+	106b  82562G \t- PRO/100 VE Ethernet Controller Mobile
 	1075  82547GI Gigabit Ethernet Controller
+		1028 0165  PowerEdge 750
 		8086 0075  PRO/1000 CT Network Connection
 		8086 1075  PRO/1000 CT Network Connection
-# Added PI to part name.  Previous part name was 82541GI
 	1076  82541GI/PI Gigabit Ethernet Controller
+		1028 0165  PowerEdge 750
 		8086 0076  PRO/1000 MT Network Connection
 		8086 1076  PRO/1000 MT Network Connection
 		8086 1176  PRO/1000 MT Desktop Adapter
 		8086 1276  PRO/1000 MT Desktop Adapter
-# Update controller name from 82541EI to 82541GI
 	1077  82541GI Gigabit Ethernet Controller
 		1179 0001  PRO/1000 MT Mobile Connection
 		8086 0077  PRO/1000 MT Mobile Connection
 		8086 1077  PRO/1000 MT Mobile Connection
 	1078  82541EI Gigabit Ethernet Controller
 		8086 1078  PRO/1000 MT Network Connection
-# Update from mistaken ID of 82546EB
 	1079  82546GB Gigabit Ethernet Controller
 		103c 12a6  HP Dual Port 1000Base-T [A9900A]
 		103c 12cf  HP Core Dual Port 1000Base-T [AB352A]
 		4c53 1090  Cx9 / Vx9 mainboard
+		4c53 10b0  CL9 mainboard
 		8086 0079  PRO/1000 MT Dual Port Network Connection
 		8086 1079  PRO/1000 MT Dual Port Network Connection
 		8086 1179  PRO/1000 MT Dual Port Network Connection
 		8086 117a  PRO/1000 MT Dual Port Server Adapter
-# Update from mistaken ID of 82546EB
 	107a  82546GB Gigabit Ethernet Controller
 		103c 12a8  HP Dual Port 1000base-SX [A9899A]
 		8086 107a  PRO/1000 MF Dual Port Server Adapter
 		8086 127a  PRO/1000 MF Dual Port Server Adapter
-# Update from mistaken ID of 82546EB
 	107b  82546GB Gigabit Ethernet Controller
 		8086 007b  PRO/1000 MB Dual Port Server Connection
 		8086 107b  PRO/1000 MB Dual Port Server Connection
+	1107  PRO/1000 MF Server Adapter (LX)
 	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
 		1025 1016  Travelmate 612 TX
 		1043 8027  TUSL2-C Mainboard
@@ -7715,7 +8781,7 @@
 	1162  Xscale 80200 Big Endian Companion Chip
 	1200  Intel IXP1200 Network Processor
 		172a 0000  AEP SSL Accelerator
-	1209  82559ER
+	1209  8255xER/82551IT Fast Ethernet Controller
 		4c53 1050  CT7 mainboard
 		4c53 1051  CE7 mainboard
 		4c53 1070  PC6 mainboard
@@ -7766,7 +8832,7 @@
 		1014 605c  10/100 EtherJet Secure Management Adapter
 		1014 705c  10/100 Netfinity 10/100 Ethernet Security Adapter
 		1014 805c  10/100 Netfinity 10/100 Ethernet Security Adapter
-		1028 009b  PowerEdge 2550
+		1028 009b  PowerEdge 2500/2550
 		1028 00ce  PowerEdge 1400
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
@@ -7937,6 +9003,7 @@
 	1a23  82840 840 (Carmel) Chipset AGP Bridge
 	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
 	1a30  82845 845 (Brookdale) Chipset Host Bridge
+		1028 010e  Optiplex GX240
 	1a31  82845 845 (Brookdale) Chipset AGP Bridge
 	2410  82801AA ISA Bridge (LPC)
 	2411  82801AA IDE
@@ -7962,6 +9029,8 @@
 	2442  82801BA/BAM USB (Hub #1)
 		1014 01c6  Netvista A40/A40p
 		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
 		104d 80df  Vaio PCG-FX403
 		147b 0507  TH7II-RAID
 		8086 4532  D815EEA2 mainboard
@@ -7969,6 +9038,7 @@
 	2443  82801BA/BAM SMBus
 		1014 01c6  Netvista A40/A40p
 		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
 		1043 8027  TUSL2-C Mainboard
 		104d 80df  Vaio PCG-FX403
 		147b 0507  TH7II-RAID
@@ -7976,6 +9046,8 @@
 		8086 4557  D815EGEW Mainboard
 	2444  82801BA/BAM USB (Hub #2)
 		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
 		104d 80df  Vaio PCG-FX403
 		147b 0507  TH7II-RAID
 		8086 4532  D815EEA2 mainboard
@@ -7986,10 +9058,10 @@
 		1462 3370  STAC9721 AC
 		147b 0507  TH7II-RAID
 		8086 4557  D815EGEW Mainboard
-	2446  Intel 537 [82801BA/BAM AC'97 Modem]
+	2446  82801BA/BAM AC'97 Modem
 		1025 1016  Travelmate 612 TX
 		104d 80df  Vaio PCG-FX403
-	2448  82801 PCI Bridge
+	2448  82801 Mobile PCI Bridge
 	2449  82801BA/BAM/CA/CAM Ethernet Controller
 		0e11 0012  EtherExpress PRO/100 VM
 		0e11 0091  EtherExpress PRO/100 VE
@@ -8026,6 +9098,7 @@
 		104d 80df  Vaio PCG-FX403
 	244b  82801BA IDE U100
 		1014 01c6  Netvista A40/A40p
+		1028 010e  Optiplex GX240
 		1043 8027  TUSL2-C Mainboard
 		147b 0507  TH7II-RAID
 		8086 4532  D815EEA2 mainboard
@@ -8046,6 +9119,7 @@
 		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 		15d9 3480  P4DP6
 		8086 1958  vpr Matrix 170B4
+		8086 3424  SE7501HG2 Mainboard
 		8086 4541  Latitude C640
 	2483  82801CA/CAM SMBus Controller
 		1014 0220  ThinkPad A/T/X Series
@@ -8058,6 +9132,7 @@
 		15d9 3480  P4DP6
 		8086 1958  vpr Matrix 170B4
 	2485  82801CA/CAM AC'97 Audio Controller
+		1013 5959  Crystal WMD Audio Codec
 		1014 0222  ThinkPad T23 (2647-4MG) or A30/A30p (2652/2653)
 		1014 0508  ThinkPad T30
 		1014 051c  ThinkPad A/T/X Series
@@ -8086,103 +9161,163 @@
 	248b  82801CA Ultra ATA Storage Controller
 		15d9 3480  P4DP6
 	248c  82801CAM ISA Bridge (LPC)
-	24c0  82801DB/DBL (ICH4/ICH4-L) LPC Bridge
+	24c0  82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge
 		1014 0267  NetVista A30p
 		1462 5800  845PE Max (MS-6580)
 	24c1  82801DBL (ICH4-L) IDE Controller
 	24c2  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1462 5800  845PE Max (MS-6580)
+		1509 2990  Averatec 5110H laptop
+		4c53 1090  Cx9 / Vx9 mainboard
 	24c3  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1458 24c2  GA-8PE667 Ultra
 		1462 5800  845PE Max (MS-6580)
 		4c53 1090  Cx9 / Vx9 mainboard
 	24c4  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1462 5800  845PE Max (MS-6580)
+		1509 2990  Averatec 5110H
 		4c53 1090  Cx9 / Vx9 mainboard
 	24c5  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller
 		0e11 00b8  Analog Devices Inc. codec [SoundMAX]
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1458 a002  GA-8PE667 Ultra
 		1462 5800  845PE Max (MS-6580)
 	24c6  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 	24c7  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1462 5800  845PE Max (MS-6580)
-	24ca  82801DBM (ICH4) Ultra ATA Storage Controller
+		1509 2990  Averatec 5110H
+		4c53 1090  Cx9 / Vx9 mainboard
+	24ca  82801DBM (ICH4-M) IDE Controller
+		1025 005a  TravelMate 290
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
-	24cb  82801DB/DBL (ICH4/ICH4-L) UltraATA-100 IDE Controller
+	24cb  82801DB (ICH4) IDE Controller
 		1014 0267  NetVista A30p
+		1028 0126  Optiplex GX260
 		1458 24c2  GA-8PE667 Ultra
 		1462 5800  845PE Max (MS-6580)
 		4c53 1090  Cx9 / Vx9 mainboard
-	24cc  82801DBM LPC Interface Controller
-	24cd  82801DB/DBM (ICH4/ICH4-M) USB 2.0 EHCI Controller
+	24cc  82801DBM (ICH4-M) LPC Interface Bridge
+	24cd  82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller
 		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 		1071 8160  MIM2000
 		1462 3981  845PE Max (MS-6580)
+		1509 1968  Averatec 5110H
 		4c53 1090  Cx9 / Vx9 mainboard
-	24d0  82801EB/ER (ICH5/ICH5R) LPC Bridge
-	24d1  82801EB (ICH5) Serial ATA 150 Storage Controller
+	24d0  82801EB/ER (ICH5/ICH5R) LPC Interface Bridge
+	24d1  82801EB (ICH5) SATA Controller
 		103c 12bc  d530 CMT (DG746A)
 		1458 24d1  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
-	24d2  82801EB/ER (ICH5/ICH5R) USB UHCI #1
+		8086 524c  D865PERL mainboard
+	24d2  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #1
+		1028 0183  PowerEdge 1800
 		103c 12bc  d530 CMT (DG746A)
 		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000/8KNXP motherboard
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
 	24d3  82801EB/ER (ICH5/ICH5R) SMBus Controller
 		1043 80a6  P4P800 Mainboard
 		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
-	24d4  82801EB/ER (ICH5/ICH5R) USB UHCI #2
+		8086 524c  D865PERL mainboard
+	24d4  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #2
+		1028 0183  PowerEdge 1800
 		103c 12bc  d530 CMT (DG746A)
 		1043 80a6  P4P800 Mainboard
 		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
 	24d5  82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller
 		103c 12bc  Analog Devices codec [SoundMAX Integrated Digital Audio]
 		1043 80f3  P4P800 Mainboard
+# Again, I suppose they use the same in different subsystems
+		1458 a002  GA-8IPE1000/8KNXP motherboard
 		1462 7280  865PE Neo2 (MS-6728)
+		8086 a000  D865PERL mainboard
+		8086 e000  D865PERL mainboard
 	24d6  82801EB/ER (ICH5/ICH5R) AC'97 Modem Controller
 	24d7  82801EB/ER (ICH5/ICH5R) USB UHCI #3
+		1028 0183  PowerEdge 1800
 		103c 12bc  d530 CMT (DG746A)
 		1043 80a6  P4P800 Mainboard
 		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
-	24db  82801EB/ER (ICH5/ICH5R) Ultra ATA 100 Storage Controller
+		8086 524c  D865PERL mainboard
+	24db  82801EB/ER (ICH5/ICH5R) IDE Controller
 		103c 12bc  d530 CMT (DG746A)
 		1043 80a6  P4P800 Mainboard
 		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		1462 7580  MSI 875P
+		8086 24db  P4C800 Mainboard
 		8086 3427  S875WP1-E mainboard
-	24dc  82801EB LPC Interface Controller
+		8086 524c  D865PERL mainboard
+	24dc  82801EB (ICH5) LPC Interface Bridge
 	24dd  82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller
+		1028 0183  PowerEdge 1800
 		103c 12bc  d530 CMT (DG746A)
 		1043 80a6  P4P800 Mainboard
 		1458 5006  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
-	24de  82801EB/ER (ICH5/ICH5R) USB UHCI #4
+		8086 524c  D865PERL mainboard
+	24de  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #4
 		1043 80a6  P4P800 Mainboard
 		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
 		1462 7280  865PE Neo2 (MS-6728)
 		8086 3427  S875WP1-E mainboard
-	24df  82801EB (ICH5R) SATA (cc=RAID)
+		8086 524c  D865PERL mainboard
+	24df  82801ER (ICH5R) SATA Controller
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1028 0095  Precision Workstation 220 Chipset
 		1043 801c  P3C-2000 system chipset
@@ -8203,6 +9338,7 @@
 	2541  E7500/E7501 Host RASUM Controller
 		15d9 3480  P4DP6
 		4c53 1090  Cx9 / Vx9 mainboard
+		8086 3424  SE7501HG2 Mainboard
 	2543  E7500/E7501 Hub Interface B PCI-to-PCI Bridge
 	2544  E7500/E7501 Hub Interface B RASUM Controller
 		4c53 1090  Cx9 / Vx9 mainboard
@@ -8212,6 +9348,7 @@
 	2548  E7500/E7501 Hub Interface D RASUM Controller
 	254c  E7501 Memory Controller Hub
 		4c53 1090  Cx9 / Vx9 mainboard
+		8086 3424  SE7501HG2 Mainboard
 	2550  E7505 Memory Controller Hub
 	2551  E7505/E7205 Series RAS Controller
 	2552  E7505/E7205 PCI-to-AGP Bridge
@@ -8219,6 +9356,7 @@
 	2554  E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller
 	255d  E7205 Memory Controller Hub
 	2560  82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface
+		1028 0126  Optiplex GX260
 		1458 2560  GA-8PE667 Ultra
 		1462 5800  845PE Max (MS-6580)
 	2561  82845G/GL[Brookdale-G]/GE/PE Host-to-AGP Bridge
@@ -8228,100 +9366,153 @@
 		1043 80f2  P4P800 Mainboard
 		1458 2570  GA-8IPE1000 Pro2 motherboard (865PE)
 	2571  82865G/PE/P PCI to AGP Controller
-	2572  82865G Integrated Graphics Device
+	2572  82865G Integrated Graphics Controller
 	2573  82865G/PE/P PCI to CSA Bridge
 	2576  82865G/PE/P Processor to I/O Memory Interface
-	2578  82875P Memory Controller Hub
+	2578  82875P/E7210 Memory Controller Hub
+		1458 2578  GA-8KNXP motherboard (875P)
 		1462 7580  MS-6758 (875P Neo)
 # Motherboard P4SCE
 		15d9 4580  Super Micro Computer Inc. P4SCE
 	2579  82875P Processor to AGP Controller
-	257b  82875P Processor to PCI to CSA Bridge
-	257e  82875P Processor to I/O Memory Interface
-	2580  915G/P/GV Processor to I/O Controller
-	2581  915G/P/GV PCI Express Root Port
-	2582  82915G Express Chipset Family Graphics Controller
-	2584  925X Memory Controller Hub
-	2585  925X PCI Express Root Port
-	2588  Server Memory Controller Hub
-	2589  Server Memory Controller Hub PCI Express Port
-	258a  Graphics Controller
-	2590  Mobile Memory Controller Hub
-	2591  Mobile Memory Controller Hub PCI Express Port
-	2592  Mobile Graphics Controller
+	257b  82875P/E7210 Processor to PCI to CSA Bridge
+	257e  82875P/E7210 Processor to I/O Memory Interface
+	2580  915G/P/GV/GL/PL/910GL Processor to I/O Controller
+	2581  915G/P/GV/GL/PL/910GL PCI Express Root Port
+	2582  82915G/GV/910GL Express Chipset Family Graphics Controller
+		1028 1079  Optiplex GX280
+	2584  925X/XE Memory Controller Hub
+	2585  925X/XE PCI Express Root Port
+	2588  E7220/E7221 Memory Controller Hub
+	2589  E7220/E7221 PCI Express Root Port
+	258a  E7221 Integrated Graphics Controller
+	2590  Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller
+	2591  Mobile 915GM/PM Express PCI Express Root Port
+	2592  Mobile 915GM/GMS/910GML Express Graphics Controller
 	25a1  6300ESB LPC Interface Controller
 	25a2  6300ESB PATA Storage Controller
+		4c53 10b0  CL9 mainboard
 	25a3  6300ESB SATA Storage Controller
+		4c53 10b0  CL9 mainboard
 	25a4  6300ESB SMBus Controller
+		4c53 10b0  CL9 mainboard
 	25a6  6300ESB AC'97 Audio Controller
+		4c53 10b0  CL9 mainboard
 	25a7  6300ESB AC'97 Modem Controller
 	25a9  6300ESB USB Universal Host Controller
+		4c53 10b0  CL9 mainboard
 	25aa  6300ESB USB Universal Host Controller
+		4c53 10b0  CL9 mainboard
 	25ab  6300ESB Watchdog Timer
+		4c53 10b0  CL9 mainboard
 	25ac  6300ESB I/O Advanced Programmable Interrupt Controller
+		4c53 10b0  CL9 mainboard
 	25ad  6300ESB USB2 Enhanced Host Controller
 	25ae  6300ESB 64-bit PCI-X Bridge
 	25b0  6300ESB SATA RAID Controller
-	2600  Server Hub Interface
-	2601  Server Hub PCI Express x4 Port D
-	2602  Server Hub PCI Express x4 Port C0
-	2603  Server Hub PCI Express x4 Port C1
-	2604  Server Hub PCI Express x4 Port B0
-	2605  Server Hub PCI Express x4 Port B1
-	2606  Server Hub PCI Express x4 Port A0
-	2607  Server Hub PCI Express x4 Port A1
-	2608  Server Hub PCI Express x8 Port C
-	2609  Server Hub PCI Express x8 Port B
-	260a  Server Hub PCI Express x8 Port A
-	260c  Server Hub IMI Registers
-	2610  Server Hub System Bus, Boot, and Interrupt Registers
-	2611  Server Hub Address Mapping Registers
-	2612  Server Hub RAS Registers
-	2613  Server Hub Performance Monitoring Registers
-	2614  Server Hub Performance Monitoring Registers
-	2615  Server Hub Performance Monitoring Registers
-	2617  Server Hub Debug Registers
-	2618  Server Hub Debug Registers
-	2619  Server Hub Debug Registers
-	261a  Server Hub Debug Registers
-	261b  Server Hub Debug Registers
-	261c  Server Hub Debug Registers
-	261d  Server Hub Debug Registers
-	261e  Server Hub Debug Registers
-	2620  External Memory Bridge
-	2621  External Memory Bridge Control Registers
-	2622  External Memory Bridge Memory Interleaving Registers
-	2623  External Memory Bridge DDR Initialization and Calibration
-	2624  External Memory Bridge Reserved Registers
-	2625  External Memory Bridge Reserved Registers
-	2626  External Memory Bridge Reserved Registers
-	2627  External Memory Bridge Reserved Registers
+	2600  E8500 Hub Interface
+	2601  E8500 PCI Express x4 Port D
+	2602  E8500 PCI Express x4 Port C0
+	2603  E8500 PCI Express x4 Port C1
+	2604  E8500 PCI Express x4 Port B0
+	2605  E8500 PCI Express x4 Port B1
+	2606  E8500 PCI Express x4 Port A0
+	2607  E8500 PCI Express x4 Port A1
+	2608  E8500 PCI Express x8 Port C
+	2609  E8500 PCI Express x8 Port B
+	260a  E8500 PCI Express x8 Port A
+	260c  E8500 IMI Registers
+	2610  E8500 System Bus, Boot, and Interrupt Registers
+	2611  E8500 Address Mapping Registers
+	2612  E8500 RAS Registers
+	2613  E8500 Reserved Registers
+	2614  E8500 Reserved Registers
+	2615  E8500 Miscellaneous Registers
+	2617  E8500 Reserved Registers
+	2618  E8500 Reserved Registers
+	2619  E8500 Reserved Registers
+	261a  E8500 Reserved Registers
+	261b  E8500 Reserved Registers
+	261c  E8500 Reserved Registers
+	261d  E8500 Reserved Registers
+	261e  E8500 Reserved Registers
+	2620  E8500 eXternal Memory Bridge
+	2621  E8500 XMB Miscellaneous Registers
+	2622  E8500 XMB Memory Interleaving Registers
+	2623  E8500 XMB DDR Initialization and Calibration
+	2624  E8500 XMB Reserved Registers
+	2625  E8500 XMB Reserved Registers
+	2626  E8500 XMB Reserved Registers
+	2627  E8500 XMB Reserved Registers
 	2640  82801FB/FR (ICH6/ICH6R) LPC Interface Bridge
 	2641  82801FBM (ICH6M) LPC Interface Bridge
 	2642  82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge
 	2651  82801FB/FW (ICH6/ICH6W) SATA Controller
+		1028 0179  Optiplex GX280
 	2652  82801FR/FRW (ICH6R/ICH6RW) SATA Controller
 	2653  82801FBM (ICH6M) SATA Controller
 	2658  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1
+		1028 0179  Optiplex GX280
 	2659  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2
+		1028 0179  Optiplex GX280
 	265a  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3
+		1028 0179  Optiplex GX280
 	265b  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4
+		1028 0179  Optiplex GX280
 	265c  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller
+		1028 0179  Optiplex GX280
 	2660  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1
 	2662  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2
 	2664  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3
 	2666  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4
 	2668  82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller
 	266a  82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller
+		1028 0179  Optiplex GX280
 	266c  82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller
 	266d  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller
 	266e  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller
+		1028 0179  Optiplex GX280
 	266f  82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller
+	2770  Memory Controller Hub
+	2771  PCI Express Graphics Port
+	2772  Integrated Graphics Controller
+	2774  Workstation Memory Controller Hub
+	2775  PCI Express Graphics Port
+	2776  Integrated Graphics Controller
+	2778  Server Memory Controller Hub
+	2779  PCI Express Root Port
 	2782  82915G Express Chipset Family Graphics Controller
-	2792  Mobile Graphics Controller
+	2792  Mobile 915GM/GMS/910GML Express Graphics Controller
+	27b8  I/O Controller Hub LPC
+	27b9  Mobile I/O Controller Hub LPC
+	27c0  I/O Controller Hub SATA cc=IDE
+	27c1  I/O Controller Hub SATA cc=AHCI
+	27c3  I/O Controller Hub SATA cc=RAID
+	27c4  Mobile I/O Controller Hub SATA cc=IDE
+	27c5  Mobile I/O Controller Hub SATA cc=AHCI
+	27c8  I/O Controller Hub UHCI USB #1
+	27c9  I/O Controller Hub UHCI USB #2
+	27ca  I/O Controller Hub UHCI USB #3
+	27cb  I/O Controller Hub UHCI USB #4
+	27cc  I/O Controller Hub EHCI USB
+	27d0  I/O Controller Hub PCI Express Port 1
+	27d2  I/O Controller Hub PCI Express Port 2
+	27d4  I/O Controller Hub PCI Express Port 3
+	27d6  I/O Controller Hub PCI Express Port 4
+	27d8  I/O Controller Hub High Definition Audio
+	27da  I/O Controller Hub SMBus
+	27dc  I/O Controller Hub LAN
+	27dd  I/O Controller Hub AC'97 Modem
+	27de  I/O Controller Hub AC'97 Audio
+	27df  I/O Controller Hub PATA
+	27e0  I/O Controller Hub PCI Express Port 5
+	27e2  I/O Controller Hub PCI Express Port 6
 	3092  Integrated RAID
 	3200  GD31244 PCI-X SATA HBA
 	3340  82855PM Processor to I/O Controller
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
 	3341  82855PM Processor to AGP Controller
 	3575  82830 830 Chipset Host Bridge
 		1014 021d  ThinkPad A/T/X Series
@@ -8330,25 +9521,34 @@
 	3577  82830 CGC [Chipset Graphics Controller]
 		1014 0513  ThinkPad A/T/X Series
 	3578  82830 830 Chipset Host Bridge
-	3580  82852/855GM Host Bridge
-	3581  855GME GMCH Host-to-AGP Bridge (Virtual PCI-to-PCI)
+	3580  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3581  82852/82855 GM/GME/PM/GMV Processor to AGP Controller
 	3582  82852/855GM Integrated Graphics Device
-	3584  855GM/GME GMCH Memory I/O Control Registers
-	3585  855GM/GME GMCH Configuration Process Registers
-	3590  Server Memory Controller Hub
-	3591  Memory Controller Hub Error Reporting Register
-	3592  Server Memory Controller Hub
-	3593  Memory Controller Hub Error Reporting Register
-	3594  Memory Controller Hub DMA Controller
-	3595  Memory Controller Hub PCI Express Port A0
-	3596  Memory Controller Hub PCI Express Port A1
-	3597  Memory Controller Hub PCI Express Port B0
-	3598  Memory Controller Hub PCI Express Port B1
-	3599  Memory Controller Hub PCI Express Port C0
-	359a  Memory Controller Hub PCI Express Port C1
-	359b  Memory Controller Hub Extended Configuration Registers
-	359e  Workstation Memory Controller Hub
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3584  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3585  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3590  E7520 Memory Controller Hub
+	3591  E7525/E7520 Error Reporting Registers
+	3592  E7320 Memory Controller Hub
+	3593  E7320 Error Reporting Registers
+	3594  E7520 DMA Controller
+	3595  E7525/E7520/E7320 PCI Express Port A
+	3596  E7525/E7520/E7320 PCI Express Port A1
+	3597  E7525/E7520 PCI Express Port B
+	3598  E7520 PCI Express Port B1
+	3599  E7520 PCI Express Port C
+	359a  E7520 PCI Express Port C1
+	359b  E7525/E7520/E7320 Extended Configuration Registers
+	359e  E7525 Memory Controller Hub
 	4220  PRO/Wireless 2200BG
+	4223  PRO/Wireless 2915ABG MiniPCI Adapter
 	5200  EtherExpress PRO/100 Intelligent Server
 	5201  EtherExpress PRO/100 Intelligent Server
 		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
@@ -8360,9 +9560,13 @@
 	7050  Intel Intercast Video Capture Card
 	7100  430TX - 82439TX MTXC
 	7110  82371AB/EB/MB PIIX4 ISA
+		15ad 1976  virtualHW v3
 	7111  82371AB/EB/MB PIIX4 IDE
+		15ad 1976  virtualHW v3
 	7112  82371AB/EB/MB PIIX4 USB
+		15ad 1976  virtualHW v3
 	7113  82371AB/EB/MB PIIX4 ACPI
+		15ad 1976  virtualHW v3
 	7120  82810 GMCH [Graphics Memory Controller Hub]
 		4c53 1040  CL7 mainboard
 		4c53 1060  PC7 mainboard
@@ -8383,6 +9587,7 @@
 		0e11 0500  Armada 1750 Laptop System Chipset
 		0e11 b110  Armada M700/E500
 		1179 0001  Toshiba Tecra 8100 Laptop System Chipset
+		15ad 1976  virtualHW v3
 		4c53 1050  CT7 mainboard
 		4c53 1051  CE7 mainboard
 	7191  440BX/ZX/DX - 82443BX/ZX/DX AGP bridge
@@ -8393,6 +9598,7 @@
 		1033 0000  Versa Note Vxi
 		4c53 10a0  CA3/CR3 mainboard
 	7195  82440MX AC'97 Audio Controller
+		1033 80cc  Versa Note VXi
 		10cf 1099  QSound_SigmaTel Stac97 PCI Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
@@ -8430,7 +9636,9 @@
 	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)
-	8500  IXP4xx Family  Network Processor (IXP420, 421, 422, 425 and IXC1100)
+	8500  IXP4XX - Intel Network Processor family. IXP420, IXP421, IXP422, IXP425 and IXC1100
+		1993 0dee  mGuard-PCI AV#1
+		1993 0def  mGuard-PCI AV#0
 	9000  IXP2000 Family Network Processor
 	9001  IXP2400 Network Processor
 	9004  IXP2800 Network Processor
@@ -8438,11 +9646,15 @@
 	9622  Integrated RAID
 	9641  Integrated RAID
 	96a1  Integrated RAID
+# retail verson
+	a01f  PRO/10GbE LR Server Adapter
+# OEM version
+	a11f  PRO/10GbE LR Server Adapter
 	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
-		1331 0030  ENP-2611
+		12d9 000a  PCI VoIP Gateway
 		4c53 1050  CT7 mainboard
 		4c53 1051  CE7 mainboard
 		e4bf 1000  CC8-1-BLUES
@@ -8616,6 +9828,7 @@
 	00cf  AIC-7899P U160/m
 		1028 00ce  PowerEdge 1400
 		1028 00d1  PowerEdge 2550
+		1028 00d9  PowerEdge 2500
 		10f1 2462  Thunder K7 S2462
 		15d9 9005  Onboard SCSI Host Adapter
 		8086 3411  SDS2 Mainboard
@@ -8630,8 +9843,10 @@
 		9005 0284  Tomcat
 	0285  AAC-RAID
 		0e11 0295  SATA 6Ch (Bearcat)
+		1014 02f2  ServeRAID 8i
 		1028 0287  PowerEdge Expandable RAID Controller 320/DC
 		1028 0291  CERC SATA RAID 2 PCI SATA 6ch (DellCorsair)
+		103c 3227  AAR-2610SA
 		17aa 0286  Legend S220 (Legend Crusader)
 		17aa 0287  Legend S230 (Legend Vulcan)
 		9005 0285  2200S (Vulcan)
@@ -8647,6 +9862,8 @@
 		9005 0294  ESD SO-DIMM PCI-X SATA ZCR (Prowler)
 	0286  AAC-RAID (Rocket)
 		9005 028c  ASR-2230S + ASR-2230SLP PCI-X (Lancer)
+	0503  Scamp chipset SCSI controller
+		1014 02BF  Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571E)
 	8000  ASC-29320A U320
 	800f  AIC-7901 U320
 	8010  ASC-39320 U320
@@ -8685,13 +9902,26 @@
 9699  Omni Media Technology Inc
 	6565  6565
 9710  NetMos Technology
-	9815  PCI 9815 Multi-I/O Controller
+	7780  USB IRDA-port
+	9705  PCI 9705 Parallel Port
+	9715  PCI 9715 Dual Parallel Port
+	9735  PCI 9735 Multi-I/O Controller
+		1000 0002  0P2S (2 serial)
+		1000 0012  1P2S (1 parallel + 2 serial)
+	9745  PCI 9745 Multi-I/O Controller
+		1000 0002  0P2S (2 serial)
+		1000 0012  1P2S (1 parallel + 2 serial)
+	9755  PCI 9755 Parallel Port and ISA Bridge
+	9805  PCI 9805 Parallel Port
+	9815  PCI 9815 Dual Parallel Port
 		1000 0020  2P0S (2 port parallel adaptor)
 	9835  PCI 9835 Multi-I/O Controller
-		1000 0002  2S (16C550 UART)
+		1000 0002  0P2S (16C550 UART)
 		1000 0012  1P2S
 	9845  PCI 9845 Multi-I/O Controller
-		1000 0006  0P6S (6 port 16550a serial card)
+		1000 0004  0P4S (4 port 16550A serial card)
+		1000 0006  0P6S (6 port 16550A serial card)
+		1000 0014  1P4S (4 port 16550A serial card + parallel)
 	9855  PCI 9855 Multi-I/O Controller
 		1000 0014  1P4S
 9902  Stargen Inc.
@@ -8705,8 +9935,10 @@ a259  Hewlett Packard
 a25b  Hewlett Packard GmbH PL24-MKT
 a304  Sony
 a727  3Com Corporation
+	0013  3CRPAG175 Wireless PC Card
 aa42  Scitex Digital Video
 ac1e  Digital Receiver Technology Inc
+ac3d  Actuality Systems
 aecb  Adrienne Electronics Corporation
 b1b3  Shiva Europe Limited
 # Pinnacle should be 11bd, but they got it wrong several times --mj
@@ -8726,6 +9958,10 @@ d4d4  Dy4 Systems Inc
 d531  I+ME ACTIA GmbH
 d84d  Exsys
 dead  Indigita Corporation
+deaf  Middle Digital Inc.
+	9050  PC Weasel Virtual VGA
+	9051  PC Weasel Serial Port
+	9052  PC Weasel Watchdog Timer
 e000  Winbond
 	e000  W89C940
 # see also : http://www.schoenfeld.de/inside/Inside_CWMK3.txt maybe a misuse of TJN id or it use the TJN 3XX chip for other applic
@@ -8759,13 +9995,6 @@ eace  Endace Measurement Systems, Ltd
 ec80  Belkin Corporation
 	ec00  F5D6000
 ecc0  Echo Digital Audio Corporation
-	0050  Gina24_301
-	0051  Gina24_361
-	0060  Layla24
-	0070  Mona_301_80
-	0071  Mona_301_66
-	0072  Mona_361
-	0080  Mia
 edd8  ARK Logic Inc
 	a091  1000PV [Stingray]
 	a099  2000PV [Stingray]
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -3,14 +3,12 @@
 #
 config PCIEPORTBUS
 	bool "PCI Express support"
-	depends on PCI_GOMMCONFIG || PCI_GOANY
-	default n
-
-	---help---
-	This automatically enables PCI Express Port Bus support. Users can
-	choose Native Hot-Plug support, Advanced Error Reporting support,
-	Power Management Event support and Virtual Channel support to run
-	on PCI Express Ports (Root or Switch).
+	depends on PCI
+	help
+	  This automatically enables PCI Express Port Bus support. Users can
+	  choose Native Hot-Plug support, Advanced Error Reporting support,
+	  Power Management Event support and Virtual Channel support to run
+	  on PCI Express Ports (Root or Switch).
 
 #
 # Include service Kconfig here
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -31,7 +31,7 @@ extern struct bus_type pcie_port_bus_typ
 extern int pcie_port_device_probe(struct pci_dev *dev);
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
-extern int pcie_port_device_suspend(struct pci_dev *dev, u32 state);
+extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
 extern int pcie_port_device_resume(struct pci_dev *dev);
 #endif
 extern void pcie_port_device_remove(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -15,7 +15,7 @@
 #include <linux/pcieport_if.h>
 
 static int pcie_port_bus_match(struct device *dev, struct device_driver *drv);
-static int pcie_port_bus_suspend(struct device *dev, u32 state);
+static int pcie_port_bus_suspend(struct device *dev, pm_message_t state);
 static int pcie_port_bus_resume(struct device *dev);
 
 struct bus_type pcie_port_bus_type = {
@@ -39,14 +39,15 @@ static int pcie_port_bus_match(struct de
 		driver->id_table->vendor != pciedev->id.vendor) ||
 	       (driver->id_table->device != PCI_ANY_ID &&
 		driver->id_table->device != pciedev->id.device) ||	
-		driver->id_table->port_type != pciedev->id.port_type ||
+	       (driver->id_table->port_type != PCIE_ANY_PORT &&
+		driver->id_table->port_type != pciedev->id.port_type) ||
 		driver->id_table->service_type != pciedev->id.service_type )
 		return 0;
 
 	return 1;
 }
 
-static int pcie_port_bus_suspend(struct device *dev, u32 state)
+static int pcie_port_bus_suspend(struct device *dev, pm_message_t state)
 {
 	struct pcie_device *pciedev;
 	struct pcie_port_service_driver *driver;
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -61,7 +61,7 @@ static int pcie_port_remove_service(stru
 
 static void pcie_port_shutdown_service(struct device *dev) {}
 
-static int pcie_port_suspend_service(struct device *dev, u32 state, u32 level)
+static int pcie_port_suspend_service(struct device *dev, pm_message_t state, u32 level)
 {
 	struct pcie_device *pciedev;
 	struct pcie_port_service_driver *driver;
@@ -76,7 +76,7 @@ static int pcie_port_suspend_service(str
 	return 0;
 }
 
-static int pcie_port_resume_service(struct device *dev, u32 state)
+static int pcie_port_resume_service(struct device *dev, u32 level)
 {
 	struct pcie_device *pciedev;
 	struct pcie_port_service_driver *driver;
@@ -317,7 +317,7 @@ int pcie_port_device_register(struct pci
 }
 
 #ifdef CONFIG_PM
-int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	struct list_head 		*head, *tmp;
 	struct device 			*parent, *child;
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -67,7 +67,7 @@ static void pcie_portdrv_remove (struct 
 }
 
 #ifdef CONFIG_PM
-static int pcie_portdrv_suspend (struct pci_dev *dev, u32 state)
+static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
 {
 	return pcie_port_device_suspend(dev, state);
 }
@@ -106,7 +106,7 @@ static int __init pcie_portdrv_init(void
 	int retval = 0;
 
 	pcie_port_bus_register();
-	retval = pci_module_init(&pcie_portdrv);
+	retval = pci_register_driver(&pcie_portdrv);
 	if (retval)
 		pcie_port_bus_unregister();
 	return retval;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2,20 +2,14 @@
  * probe.c - PCI detection and setup code
  */
 
+#include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/cpumask.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
+#include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
@@ -64,9 +58,11 @@ static void pci_create_legacy_files(stru
 
 void pci_remove_legacy_files(struct pci_bus *b)
 {
-	class_device_remove_bin_file(&b->class_dev, b->legacy_io);
-	class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
-	kfree(b->legacy_io); /* both are allocated here */
+	if (b->legacy_io) {
+		class_device_remove_bin_file(&b->class_dev, b->legacy_io);
+		class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+		kfree(b->legacy_io); /* both are allocated here */
+	}
 }
 #else /* !HAVE_PCI_LEGACY */
 static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
@@ -78,7 +74,7 @@ void pci_remove_legacy_files(struct pci_
  */
 static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
 {
-	cpumask_t cpumask = pcibus_to_cpumask((to_pci_bus(class_dev))->number);
+	cpumask_t cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
 	int ret;
 
 	ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
@@ -129,7 +125,7 @@ static inline unsigned int pci_calc_reso
 /*
  * Find the extent of a PCI decode..
  */
-static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
+static u32 pci_size(u32 base, u32 maxbase, u32 mask)
 {
 	u32 size = mask & maxbase;	/* Find the significant bits */
 	if (!size)
@@ -420,8 +416,8 @@ int __devinit pci_scan_bridge(struct pci
 
 	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
 
-	DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n",
-	    pci_name(dev), buses & 0xffffff, pass);
+	pr_debug("PCI: Scanning behind PCI bridge %s, config %06x, pass %d\n",
+		 pci_name(dev), buses & 0xffffff, pass);
 
 	/* Disable MasterAbortMode during probing to avoid reporting
 	   of bus errors (in some architectures) */ 
@@ -549,7 +545,6 @@ static int pci_setup_device(struct pci_d
 {
 	u32 class;
 
-	dev->slot_name = dev->dev.bus_id;
 	sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
 		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
 
@@ -558,8 +553,8 @@ static int pci_setup_device(struct pci_d
 	dev->class = class;
 	class >>= 8;
 
-	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number,
-	    dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+	pr_debug("PCI: Found %s [%04x/%04x] %06x %02x\n", pci_name(dev),
+		 dev->vendor, dev->device, class, dev->hdr_type);
 
 	/* "Unknown power state" */
 	dev->current_state = 4;
@@ -814,7 +809,7 @@ unsigned int __devinit pci_scan_child_bu
 	unsigned int devfn, pass, max = bus->secondary;
 	struct pci_dev *dev;
 
-	DBG("Scanning bus %02x\n", bus->number);
+	pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
 
 	/* Go find them, Rover! */
 	for (devfn = 0; devfn < 0x100; devfn += 8)
@@ -824,7 +819,7 @@ unsigned int __devinit pci_scan_child_bu
 	 * After performing arch-dependent fixup of the bus, look behind
 	 * all PCI-to-PCI bridges on this bus.
 	 */
-	DBG("Fixups for bus %02x\n", bus->number);
+	pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
 	pcibios_fixup_bus(bus);
 	for (pass=0; pass < 2; pass++)
 		list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -840,7 +835,8 @@ unsigned int __devinit pci_scan_child_bu
 	 *
 	 * Return how far we've got finding sub-buses.
 	 */
-	DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n",
+		pci_domain_nr(bus), bus->number, max);
 	return max;
 }
 
@@ -879,7 +875,7 @@ struct pci_bus * __devinit pci_scan_bus_
 
 	if (pci_find_bus(pci_domain_nr(b), bus)) {
 		/* If we already got to this bus through a different bridge, ignore it */
-		DBG("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
+		pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
 		goto err_out;
 	}
 	list_add_tail(&b->node, &pci_root_buses);
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -15,6 +15,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
+#include "pci.h"
 
 static int proc_initialized;	/* = 0 */
 
@@ -313,13 +314,10 @@ static void *pci_seq_start(struct seq_fi
 	struct pci_dev *dev = NULL;
 	loff_t n = *pos;
 
-	dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-	while (n--) {
-		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-		if (dev == NULL)
-			goto exit;
+	for_each_pci_dev(dev) {
+		if (!n--)
+			break;
 	}
-exit:
 	return dev;
 }
 
@@ -384,26 +382,32 @@ static struct proc_dir_entry *proc_bus_p
 int pci_proc_attach_device(struct pci_dev *dev)
 {
 	struct pci_bus *bus = dev->bus;
-	struct proc_dir_entry *de, *e;
+	struct proc_dir_entry *e;
 	char name[16];
 
 	if (!proc_initialized)
 		return -EACCES;
 
-	if (!(de = bus->procdir)) {
-		if (pci_name_bus(name, bus))
-			return -EEXIST;
-		de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
-		if (!de)
+	if (!bus->procdir) {
+		if (pci_proc_domain(bus)) {
+			sprintf(name, "%04x:%02x", pci_domain_nr(bus),
+					bus->number);
+		} else {
+			sprintf(name, "%02x", bus->number);
+		}
+		bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
+		if (!bus->procdir)
 			return -ENOMEM;
 	}
+
 	sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
+	e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir);
 	if (!e)
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
 	e->size = dev->cfg_size;
+	dev->procent = e;
 
 	return 0;
 }
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -18,8 +18,8 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-
-#undef DEBUG
+#include <linux/acpi.h>
+#include "pci.h"
 
 /* Deal with broken BIOS'es that neglect to enable passive release,
    which can cause problems in combination with the 82441FX/PPro MTRRs */
@@ -330,6 +330,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,		quirk_ich4_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,	quirk_ich4_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,		quirk_ich4_lpc_acpi );
 
 /*
  * VIA ACPI: One IO region pointed to by longword at
@@ -429,6 +430,8 @@ static void __init quirk_ioapic_rmw(stru
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw );
 
+int pci_msi_quirk;
+
 #define AMD8131_revA0        0x01
 #define AMD8131_revB0        0x11
 #define AMD8131_MISC         0x40
@@ -437,6 +440,9 @@ static void __init quirk_amd_8131_ioapic
 { 
         unsigned char revid, tmp;
         
+	pci_msi_quirk = 1;
+	printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+
         if (nr_ioapics == 0) 
                 return;
 
@@ -450,24 +456,16 @@ static void __init quirk_amd_8131_ioapic
 } 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC,         quirk_amd_8131_ioapic ); 
 
+static void __init quirk_svw_msi(struct pci_dev *dev)
+{
+	pci_msi_quirk = 1;
+	printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi );
 #endif /* CONFIG_X86_IO_APIC */
 
 
 /*
- * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
- * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
- * when written, it makes an internal connection to the PIC.
- * For these devices, this register is defined to be 4 bits wide.
- * Normally this is fine.  However for IO-APIC motherboards, or
- * non-x86 architectures (yes Via exists on PPC among other places),
- * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
- * interrupts delivered properly.
- *
- * TODO: When we have device-specific interrupt routers,
- * quirk_via_irqpic will go away from quirks.
- */
-
-/*
  * FIXME: it is questionable that quirk_via_acpi
  * is needed.  It shows up as an ISA bridge, and does not
  * support the PCI_INTERRUPT_LINE register at all.  Therefore
@@ -490,6 +488,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_V
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi );
 
 /*
+ * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
+ * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
+ * when written, it makes an internal connection to the PIC.
+ * For these devices, this register is defined to be 4 bits wide.
+ * Normally this is fine.  However for IO-APIC motherboards, or
+ * non-x86 architectures (yes Via exists on PPC among other places),
+ * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
+ * interrupts delivered properly.
+ */
+static void quirk_via_irq(struct pci_dev *dev)
+{
+	u8 irq, new_irq;
+
+	new_irq = dev->irq & 0xf;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	if (new_irq != irq) {
+		printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
+			pci_name(dev), irq, new_irq);
+		udelay(15);	/* unknown if delay really needed */
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+	}
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+
+/*
  * PIIX3 USB: We have to disable USB interrupts that are
  * hardwired to PIRQD# and may be shared with an
  * external device.
@@ -536,7 +559,7 @@ static void __devinit quirk_cardbus_lega
 		return;
 	pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID,		PCI_ANY_ID,			quirk_cardbus_legacy );
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
 
 /*
  * Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -654,7 +677,7 @@ static void __devinit quirk_ide_bases(st
        printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n",
               first_bar, last_bar, pci_name(dev));
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,             PCI_ANY_ID,                     quirk_ide_bases );
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases);
 
 /*
  *	Ensure C0 rev restreaming is off. This is normally done by
@@ -678,24 +701,11 @@ static void __init quirk_disable_pxb(str
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb );
 
-/*
- *	VIA northbridges care about PCI_INTERRUPT_LINE
- */
-int via_interrupt_line_quirk;
-
-static void __devinit quirk_via_bridge(struct pci_dev *pdev)
-{
-	if(pdev->devfn == 0) {
-		printk(KERN_INFO "PCI: Via IRQ fixup\n");
-		via_interrupt_line_quirk = 1;
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_ANY_ID,                     quirk_via_bridge );
 
 /*
  *	Serverworks CSB5 IDE does not fully support native mode
  */
-static void __init quirk_svwks_csb5ide(struct pci_dev *pdev)
+static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev)
 {
 	u8 prog;
 	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
@@ -782,10 +792,12 @@ static void __init asus_hides_smbus_host
 		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
 			switch (dev->subsystem_device) {
 			case 0x1751: /* M2N notebook */
+			case 0x1821: /* M5N notebook */
 				asus_hides_smbus = 1;
 			}
 		if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
 			switch (dev->subsystem_device) {
+			case 0x184b: /* W1N notebook */
 			case 0x186a: /* M6Ne notebook */
 				asus_hides_smbus = 1;
 			}
@@ -801,6 +813,18 @@ static void __init asus_hides_smbus_host
 			case 0x12bc: /* HP D330L */
 				asus_hides_smbus = 1;
 			}
+	} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
+		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+			switch(dev->subsystem_device) {
+			case 0x0001: /* Toshiba Satellite A40 */
+				asus_hides_smbus = 1;
+			}
+       } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) {
+               if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
+                       switch(dev->subsystem_device) {
+                       case 0xC00C: /* Samsung P35 notebook */
+                               asus_hides_smbus = 1;
+                       }
 	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge );
@@ -1172,6 +1196,7 @@ static void __devinit quirk_intel_ide_co
 	case 0x2651:
 	case 0x2652:
 	case 0x2653:
+	case 0x2680:	/* ESB2 */
 		ich = 6;
 		break;
 	case 0x27c0:
@@ -1241,6 +1266,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7320_MCH,	quirk_pcie_mch );
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_pcie_mch );
 
+static void __devinit quirk_netmos(struct pci_dev *dev)
+{
+	unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
+	unsigned int num_serial = dev->subsystem_device & 0xf;
+
+	/*
+	 * These Netmos parts are multiport serial devices with optional
+	 * parallel ports.  Even when parallel ports are present, they
+	 * are identified as class SERIAL, which means the serial driver
+	 * will claim them.  To prevent this, mark them as class OTHER.
+	 * These combo devices should be claimed by parport_serial.
+	 *
+	 * The subdevice ID is of the form 0x00PS, where <P> is the number
+	 * of parallel ports and <S> is the number of serial ports.
+	 */
+	switch (dev->device) {
+	case PCI_DEVICE_ID_NETMOS_9735:
+	case PCI_DEVICE_ID_NETMOS_9745:
+	case PCI_DEVICE_ID_NETMOS_9835:
+	case PCI_DEVICE_ID_NETMOS_9845:
+	case PCI_DEVICE_ID_NETMOS_9855:
+		if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+		    num_parallel) {
+			printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+				"%u serial); changing class SERIAL to OTHER "
+				"(use parport_serial)\n",
+				dev->device, num_parallel, num_serial);
+			dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) |
+			    (dev->class & 0xff);
+		}
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
 {
 	while (f < end) {
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -2,14 +2,6 @@
 #include <linux/module.h>
 #include "pci.h"
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
 static void pci_free_resources(struct pci_dev *dev)
 {
 	int i;
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -14,7 +14,7 @@
 
 /**
  * pci_enable_rom - enable ROM decoding for a PCI device
- * @dev: PCI device to enable
+ * @pdev: PCI device to enable
  *
  * Enable ROM decoding on @dev.  This involves simply turning on the last
  * bit of the PCI ROM BAR.  Note that some cards may share address decoders
@@ -32,7 +32,7 @@ static void pci_enable_rom(struct pci_de
 
 /**
  * pci_disable_rom - disable ROM decoding for a PCI device
- * @dev: PCI device to disable
+ * @pdev: PCI device to disable
  *
  * Disable ROM decoding on a PCI device by turning off the last bit in the
  * ROM BAR.
@@ -47,7 +47,7 @@ static void pci_disable_rom(struct pci_d
 
 /**
  * pci_map_rom - map a PCI ROM to kernel space
- * @dev: pointer to pci device struct
+ * @pdev: pointer to pci device struct
  * @size: pointer to receive size of pci window over ROM
  * @return: kernel virtual pointer to image of ROM
  *
@@ -132,7 +132,7 @@ void __iomem *pci_map_rom(struct pci_dev
 
 /**
  * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
- * @dev: pointer to pci device struct
+ * @pdev: pointer to pci device struct
  * @size: pointer to receive size of pci window over ROM
  * @return: kernel virtual pointer to image of ROM
  *
@@ -166,7 +166,7 @@ void __iomem *pci_map_rom_copy(struct pc
 
 /**
  * pci_unmap_rom - unmap the ROM from kernel space
- * @dev: pointer to pci device struct
+ * @pdev: pointer to pci device struct
  * @rom: virtual address of the previous mapping
  *
  * Remove a mapping of a previously mapped ROM
@@ -187,7 +187,7 @@ void pci_unmap_rom(struct pci_dev *pdev,
 
 /**
  * pci_remove_rom - disable the ROM and remove its sysfs attribute
- * @dev: pointer to pci device struct
+ * @pdev: pointer to pci device struct
  *
  * Remove the rom file in sysfs and disable ROM decoding.
  */
@@ -206,7 +206,7 @@ void pci_remove_rom(struct pci_dev *pdev
 /**
  * pci_cleanup_rom - internal routine for freeing the ROM copy created
  * by pci_map_rom_copy called from remove.c
- * @dev: pointer to pci device struct
+ * @pdev: pointer to pci device struct
  *
  * Free the copied ROM if we allocated one.
  */
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -29,9 +29,9 @@
 
 #define DEBUG_CONFIG 1
 #if DEBUG_CONFIG
-# define DBGC(args)     printk args
+#define DBG(x...)     printk(x)
 #else
-# define DBGC(args)
+#define DBG(x...)
 #endif
 
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
@@ -151,8 +151,7 @@ pci_setup_bridge(struct pci_bus *bus)
 	struct pci_bus_region region;
 	u32 l, io_upper16;
 
-	DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
-			bus->number, pci_name(bridge)));
+	DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
 
 	/* Set up the top and bottom of the PCI I/O segment for this bus. */
 	pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
@@ -163,14 +162,14 @@ pci_setup_bridge(struct pci_bus *bus)
 		l |= region.end & 0xf000;
 		/* Set up upper 16 bits of I/O base/limit. */
 		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
-		DBGC((KERN_INFO "  IO window: %04lx-%04lx\n",
-				region.start, region.end));
+		DBG(KERN_INFO "  IO window: %04lx-%04lx\n",
+				region.start, region.end);
 	}
 	else {
 		/* Clear upper 16 bits of I/O base/limit. */
 		io_upper16 = 0;
 		l = 0x00f0;
-		DBGC((KERN_INFO "  IO window: disabled.\n"));
+		DBG(KERN_INFO "  IO window: disabled.\n");
 	}
 	/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
 	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
@@ -185,12 +184,12 @@ pci_setup_bridge(struct pci_bus *bus)
 	if (bus->resource[1]->flags & IORESOURCE_MEM) {
 		l = (region.start >> 16) & 0xfff0;
 		l |= region.end & 0xfff00000;
-		DBGC((KERN_INFO "  MEM window: %08lx-%08lx\n",
-				region.start, region.end));
+		DBG(KERN_INFO "  MEM window: %08lx-%08lx\n",
+				region.start, region.end);
 	}
 	else {
 		l = 0x0000fff0;
-		DBGC((KERN_INFO "  MEM window: disabled.\n"));
+		DBG(KERN_INFO "  MEM window: disabled.\n");
 	}
 	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 
@@ -204,12 +203,12 @@ pci_setup_bridge(struct pci_bus *bus)
 	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
 		l = (region.start >> 16) & 0xfff0;
 		l |= region.end & 0xfff00000;
-		DBGC((KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
-				region.start, region.end));
+		DBG(KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
+				region.start, region.end);
 	}
 	else {
 		l = 0x0000fff0;
-		DBGC((KERN_INFO "  PREFETCH window: disabled.\n"));
+		DBG(KERN_INFO "  PREFETCH window: disabled.\n");
 	}
 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -18,14 +18,6 @@
 #include <linux/cache.h>
 
 
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBGC(args)     printk args
-#else
-# define DBGC(args)
-#endif
-
-
 static void __init
 pdev_fixup_irq(struct pci_dev *dev,
 	       u8 (*swizzle)(struct pci_dev *, u8 *),
@@ -53,8 +45,8 @@ pdev_fixup_irq(struct pci_dev *dev,
 		irq = 0;
 	dev->irq = irq;
 
-	DBGC((KERN_ERR "PCI fixup irq: (%s) got %d\n", 
-		dev->dev.kobj.name, dev->irq));
+	pr_debug("PCI: fixup irq: (%s) got %d\n",
+		dev->dev.kobj.name, dev->irq);
 
 	/* Always tell the device, so the driver knows what is
 	   the real IRQ to use; the device does not use it. */
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -25,13 +25,6 @@
 #include <linux/slab.h>
 #include "pci.h"
 
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBGC(args)     printk args
-#else
-# define DBGC(args)
-#endif
-
 
 static void
 pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
@@ -42,10 +35,9 @@ pci_update_resource(struct pci_dev *dev,
 
 	pcibios_resource_to_bus(dev, &region, res);
 
-	DBGC((KERN_ERR "  got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
-	      "BAR %d of %s\n", res->start, res->end,
-	      region.start, region.end, res->flags,
-	      resno, pci_name(dev)));
+	pr_debug("  got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
+		 "BAR %d of %s\n", res->start, res->end,
+		 region.start, region.end, res->flags, resno, pci_name(dev));
 
 	new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
 	if (res->flags & IORESOURCE_IO)
@@ -60,7 +52,7 @@ pci_update_resource(struct pci_dev *dev,
 		reg = dev->rom_base_reg;
 	} else {
 		/* Hmm, non-standard resource. */
-		BUG();
+	
 		return;		/* kill uninitialised var warning */
 	}
 
@@ -85,12 +77,12 @@ pci_update_resource(struct pci_dev *dev,
 		}
 	}
 	res->flags &= ~IORESOURCE_UNSET;
-	DBGC((KERN_INFO "PCI: moved device %s resource %d (%lx) to %x\n",
-		dev->slot_name, resno, res->flags,
-		new & ~PCI_REGION_FLAG_MASK));
+	pr_debug("PCI: moved device %s resource %d (%lx) to %x\n",
+		pci_name(dev), resno, res->flags,
+		new & ~PCI_REGION_FLAG_MASK);
 }
 
-int __init
+int __devinit
 pci_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -20,9 +20,10 @@ config PCCARD
 	  To compile this driver as modules, choose M here: the
 	  module will be called pcmcia_core.
 
+if PCCARD
+
 config PCMCIA_DEBUG
 	bool "Enable PCCARD debugging"
-	depends on PCCARD != n
 	help
 	  Say Y here to enable PCMCIA subsystem debugging.  You
 	  will need to choose the debugging level either via the
@@ -41,7 +42,6 @@ config PCMCIA_DEBUG
 
 config PCMCIA
 	tristate "16-bit PCMCIA support"
-	depends on PCCARD
 	default y
 	---help---
 	   This option enables support for 16-bit PCMCIA cards. Most older
@@ -60,7 +60,7 @@ config PCMCIA
 
 config CARDBUS
 	bool "32-bit CardBus support"	
-	depends on PCCARD && PCI
+	depends on PCI
 	default y
 	---help---
 	  CardBus is a bus mastering architecture for PC-cards, which allows
@@ -77,7 +77,7 @@ comment "PC-card bridges"
 
 config YENTA
 	tristate "CardBus yenta-compatible bridge support"
-	depends on PCCARD && PCI
+	depends on PCI
 #fixme: remove dependendcy on CARDBUS
 	depends on CARDBUS
 	select PCCARD_NONSTATIC
@@ -197,6 +197,7 @@ config PCMCIA_VRC4173
 
 config PCCARD_NONSTATIC
 	tristate
-	depends on PCCARD
+
+endif	# PCCARD
 
 endmenu
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -156,15 +156,12 @@ static int au1x00_pcmcia_sock_init(struc
 static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock)
 {
 	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-	int ret;
 
 	debug("suspending socket %u\n", skt->nr);
 
-	ret = au1x00_pcmcia_config_skt(skt, &dead_socket);
-	if (ret == 0)
-		skt->ops->socket_suspend(skt);
+	skt->ops->socket_suspend(skt);
 
-	return ret;
+	return 0;
 }
 
 static DEFINE_SPINLOCK(status_lock);
@@ -521,7 +518,7 @@ static int au1x00_drv_pcmcia_probe(struc
 }
 
 
-static int au1x00_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level)
+static int au1x00_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -140,7 +140,7 @@ static u8 pcmcia_used_irq[NR_IRQS];
 static int socket_resume(struct pcmcia_socket *skt);
 static int socket_suspend(struct pcmcia_socket *skt);
 
-int pcmcia_socket_dev_suspend(struct device *dev, u32 state)
+int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
 {
 	struct pcmcia_socket *socket;
 
@@ -221,6 +221,8 @@ int pcmcia_register_socket(struct pcmcia
 
 	cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
 
+	spin_lock_init(&socket->lock);
+
 	if (socket->resource_ops->init) {
 		ret = socket->resource_ops->init(socket);
 		if (ret)
@@ -261,7 +263,6 @@ int pcmcia_register_socket(struct pcmcia
 	socket->cis_mem.speed = cis_speed;
 
 	INIT_LIST_HEAD(&socket->cis_cache);
-	spin_lock_init(&socket->lock);
 
 	init_completion(&socket->socket_released);
 	init_completion(&socket->thread_done);
@@ -564,7 +565,9 @@ static int socket_suspend(struct pcmcia_
 
 	send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
 	skt->socket = dead_socket;
-	skt->ops->suspend(skt);
+	skt->ops->set_socket(skt, &skt->socket);
+	if (skt->ops->suspend)
+		skt->ops->suspend(skt);
 	skt->state |= SOCKET_SUSPEND;
 
 	return CS_SUCCESS;
@@ -586,6 +589,11 @@ static int socket_resume(struct pcmcia_s
 	skt->ops->init(skt);
 	skt->ops->set_socket(skt, &skt->socket);
 
+	if (!(skt->state & SOCKET_PRESENT)) {
+		skt->state &= ~SOCKET_SUSPEND;
+		return socket_insert(skt);
+	}
+
 	ret = socket_setup(skt, resume_delay);
 	if (ret == CS_SUCCESS) {
 		/*
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -159,6 +159,7 @@ int pccard_access_configuration_register
 struct pcmcia_callback{
 	struct module	*owner;
 	int		(*event) (struct pcmcia_socket *s, event_t event, int priority);
+	int		(*resources_done) (struct pcmcia_socket *s);
 };
 
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -91,8 +91,7 @@ struct pcmcia_bus_socket {
 	struct pcmcia_callback	callback;
 	int			state;
 	user_info_t		*user;
-	int			req_pending, req_result;
-	wait_queue_head_t	queue, request;
+	wait_queue_head_t	queue;
 	struct pcmcia_socket	*parent;
 
 	/* the PCMCIA devices connected to this socket (normally one, more
@@ -285,13 +284,19 @@ static struct pcmcia_bus_socket *pcmcia_
  *
  * Registers a PCMCIA driver with the PCMCIA bus core.
  */
+static int pcmcia_device_probe(struct device *dev);
+static int pcmcia_device_remove(struct device * dev);
+
 int pcmcia_register_driver(struct pcmcia_driver *driver)
 {
 	if (!driver)
 		return -EINVAL;
 
+	/* initialize common fields */
 	driver->drv.bus = &pcmcia_bus_type;
 	driver->drv.owner = driver->owner;
+	driver->drv.probe = pcmcia_device_probe;
+	driver->drv.remove = pcmcia_device_remove;
 
 	return driver_register(&driver->drv);
 }
@@ -352,7 +357,8 @@ static struct pcmcia_device * pcmcia_get
 
 static void pcmcia_put_dev(struct pcmcia_device *p_dev)
 {
-	put_device(&p_dev->dev);
+	if (p_dev)
+		put_device(&p_dev->dev);
 }
 
 static void pcmcia_release_dev(struct device *dev)
@@ -364,6 +370,275 @@ static void pcmcia_release_dev(struct de
 }
 
 
+static int pcmcia_device_probe(struct device * dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_driver *p_drv;
+	int ret = 0;
+
+	dev = get_device(dev);
+	if (!dev)
+		return -ENODEV;
+
+	p_dev = to_pcmcia_dev(dev);
+	p_drv = to_pcmcia_drv(dev->driver);
+
+	if (!try_module_get(p_drv->owner)) {
+		ret = -EINVAL;
+		goto put_dev;
+	}
+
+	if (p_drv->attach) {
+		p_dev->instance = p_drv->attach();
+		if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
+			printk(KERN_NOTICE "ds: unable to create instance "
+			       "of '%s'!\n", p_drv->drv.name);
+			ret = -EINVAL;
+		}
+	}
+
+	if (ret)
+		module_put(p_drv->owner);
+ put_dev:
+	if ((ret) || !(p_drv->attach))
+		put_device(dev);
+	return (ret);
+}
+
+
+static int pcmcia_device_remove(struct device * dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_driver *p_drv;
+
+	/* detach the "instance" */
+	p_dev = to_pcmcia_dev(dev);
+	p_drv = to_pcmcia_drv(dev->driver);
+
+	if (p_drv) {
+		if ((p_drv->detach) && (p_dev->instance)) {
+			p_drv->detach(p_dev->instance);
+			/* from pcmcia_probe_device */
+			put_device(&p_dev->dev);
+		}
+		module_put(p_drv->owner);
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * pcmcia_device_query -- determine information about a pcmcia device
+ */
+static int pcmcia_device_query(struct pcmcia_device *p_dev)
+{
+	cistpl_manfid_t manf_id;
+	cistpl_funcid_t func_id;
+	cistpl_vers_1_t	vers1;
+	unsigned int i;
+
+	if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+			       CISTPL_MANFID, &manf_id)) {
+		p_dev->manf_id = manf_id.manf;
+		p_dev->card_id = manf_id.card;
+		p_dev->has_manf_id = 1;
+		p_dev->has_card_id = 1;
+	}
+
+	if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+			       CISTPL_FUNCID, &func_id)) {
+		p_dev->func_id = func_id.func;
+		p_dev->has_func_id = 1;
+	} else {
+		/* rule of thumb: cards with no FUNCID, but with
+		 * common memory device geometry information, are
+		 * probably memory cards (from pcmcia-cs) */
+		cistpl_device_geo_t devgeo;
+		if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+				      CISTPL_DEVICE_GEO, &devgeo)) {
+			ds_dbg(0, "mem device geometry probably means "
+			       "FUNCID_MEMORY\n");
+			p_dev->func_id = CISTPL_FUNCID_MEMORY;
+			p_dev->has_func_id = 1;
+		}
+	}
+
+	if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1,
+			       &vers1)) {
+		for (i=0; i < vers1.ns; i++) {
+			char *tmp;
+			unsigned int length;
+
+			tmp = vers1.str + vers1.ofs[i];
+
+			length = strlen(tmp) + 1;
+			if ((length < 3) || (length > 255))
+				continue;
+
+			p_dev->prod_id[i] = kmalloc(sizeof(char) * length,
+						    GFP_KERNEL);
+			if (!p_dev->prod_id[i])
+				continue;
+
+			p_dev->prod_id[i] = strncpy(p_dev->prod_id[i],
+						    tmp, length);
+		}
+	}
+
+	return 0;
+}
+
+
+/* device_add_lock is needed to avoid double registration by cardmgr and kernel.
+ * Serializes pcmcia_device_add; will most likely be removed in future.
+ *
+ * While it has the caveat that adding new PCMCIA devices inside(!) device_register()
+ * won't work, this doesn't matter much at the moment: the driver core doesn't
+ * support it either.
+ */
+static DECLARE_MUTEX(device_add_lock);
+
+static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function)
+{
+	struct pcmcia_device *p_dev;
+	unsigned long flags;
+
+	s = pcmcia_get_bus_socket(s);
+	if (!s)
+		return NULL;
+
+	down(&device_add_lock);
+
+	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+	if (!p_dev)
+		goto err_put;
+	memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+	p_dev->socket = s->parent;
+	p_dev->device_no = (s->device_count++);
+	p_dev->func   = function;
+
+	p_dev->dev.bus = &pcmcia_bus_type;
+	p_dev->dev.parent = s->parent->dev.dev;
+	p_dev->dev.release = pcmcia_release_dev;
+	sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
+
+	/* compat */
+	p_dev->client.client_magic = CLIENT_MAGIC;
+	p_dev->client.Socket = s->parent;
+	p_dev->client.Function = function;
+	p_dev->client.state = CLIENT_UNBOUND;
+
+	/* Add to the list in pcmcia_bus_socket */
+	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+	if (device_register(&p_dev->dev)) {
+		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+		list_del(&p_dev->socket_device_list);
+		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+		goto err_free;
+       }
+
+	up(&device_add_lock);
+
+	return p_dev;
+
+ err_free:
+	kfree(p_dev);
+	s->device_count--;
+ err_put:
+	up(&device_add_lock);
+	pcmcia_put_bus_socket(s);
+
+	return NULL;
+}
+
+
+static int pcmcia_card_add(struct pcmcia_socket *s)
+{
+	cisinfo_t cisinfo;
+	cistpl_longlink_mfc_t mfc;
+	unsigned int no_funcs, i;
+	int ret = 0;
+
+	if (!(s->resource_setup_done))
+		return -EAGAIN; /* try again, but later... */
+
+	pcmcia_validate_mem(s);
+	ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
+	if (ret || !cisinfo.Chains) {
+		ds_dbg(0, "invalid CIS or invalid resources\n");
+		return -ENODEV;
+	}
+
+	if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
+		no_funcs = mfc.nfn;
+	else
+		no_funcs = 1;
+
+	/* this doesn't handle multifunction devices on one pcmcia function
+	 * yet. */
+	for (i=0; i < no_funcs; i++)
+		pcmcia_device_add(s->pcmcia, i);
+
+	return (ret);
+}
+
+
+static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
+	struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+
+	/* matching by cardmgr */
+	if (p_dev->cardmgr == p_drv)
+		return 1;
+
+	return 0;
+}
+
+/************************ per-device sysfs output ***************************/
+
+#define pcmcia_device_attr(field, test, format)				\
+static ssize_t field##_show (struct device *dev, char *buf)		\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \
+}
+
+#define pcmcia_device_stringattr(name, field)					\
+static ssize_t name##_show (struct device *dev, char *buf)		\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \
+}
+
+pcmcia_device_attr(func, socket, "0x%02x\n");
+pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
+pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
+pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
+pcmcia_device_stringattr(prod_id1, prod_id[0]);
+pcmcia_device_stringattr(prod_id2, prod_id[1]);
+pcmcia_device_stringattr(prod_id3, prod_id[2]);
+pcmcia_device_stringattr(prod_id4, prod_id[3]);
+
+static struct device_attribute pcmcia_dev_attrs[] = {
+	__ATTR(function, 0444, func_show, NULL),
+	__ATTR_RO(func_id),
+	__ATTR_RO(manf_id),
+	__ATTR_RO(card_id),
+	__ATTR_RO(prod_id1),
+	__ATTR_RO(prod_id2),
+	__ATTR_RO(prod_id3),
+	__ATTR_RO(prod_id4),
+	__ATTR_NULL,
+};
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -397,19 +672,6 @@ static void handle_event(struct pcmcia_b
     wake_up_interruptible(&s->queue);
 }
 
-static int handle_request(struct pcmcia_bus_socket *s, event_t event)
-{
-    if (s->req_pending != 0)
-	return CS_IN_USE;
-    if (s->state & DS_SOCKET_BUSY)
-	s->req_pending = 1;
-    handle_event(s, event);
-    if (wait_event_interruptible(s->request, s->req_pending <= 0))
-        return CS_IN_USE;
-    if (s->state & DS_SOCKET_BUSY)
-        return s->req_result;
-    return CS_SUCCESS;
-}
 
 /*======================================================================
 
@@ -486,14 +748,11 @@ static int ds_event(struct pcmcia_socket
 	
 	case CS_EVENT_CARD_INSERTION:
 		s->state |= DS_SOCKET_PRESENT;
+		pcmcia_card_add(skt);
 		handle_event(s, event);
-		send_event(skt, event, priority);
 		break;
 
 	case CS_EVENT_EJECTION_REQUEST:
-		ret = handle_request(s, event);
-		if (ret)
-			break;
 		ret = send_event(skt, event, priority);
 		break;
 
@@ -533,9 +792,9 @@ static int ds_event(struct pcmcia_socket
 static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
 	struct pcmcia_driver *p_drv;
-	struct pcmcia_device *p_dev, *tmp_dev;
-	unsigned long flags;
+	struct pcmcia_device *p_dev;
 	int ret = 0;
+	unsigned long flags;
 
 	s = pcmcia_get_bus_socket(s);
 	if (!s)
@@ -555,74 +814,63 @@ static int bind_request(struct pcmcia_bu
 		goto err_put_driver;
 	}
 
-	/* Currently, the userspace pcmcia cardmgr detects pcmcia devices.
-	 * Here this information is translated into a kernel
-	 * struct pcmcia_device.
-	 */
-
-	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
-	if (!p_dev) {
-		ret = -ENOMEM;
-		goto err_put_module;
-	}
-	memset(p_dev, 0, sizeof(struct pcmcia_device));
-
-	p_dev->socket = s->parent;
-	p_dev->device_no = (s->device_count++);
-	p_dev->func   = bind_info->function;
-
-	p_dev->dev.bus = &pcmcia_bus_type;
-	p_dev->dev.parent = s->parent->dev.dev;
-	p_dev->dev.release = pcmcia_release_dev;
-	sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
-	p_dev->dev.driver = &p_drv->drv;
-
-	/* compat */
-	p_dev->client.client_magic = CLIENT_MAGIC;
-	p_dev->client.Socket = s->parent;
-	p_dev->client.Function = bind_info->function;
-	p_dev->client.state = CLIENT_UNBOUND;
-
-	ret = device_register(&p_dev->dev);
-	if (ret) {
-		kfree(p_dev);
-		goto err_put_module;
-	}
-
-	/* Add to the list in pcmcia_bus_socket, but only if no device
-	 * with the same func _and_ driver exists */
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-	list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) {
-		if ((tmp_dev->func == bind_info->function) &&
-		    (tmp_dev->dev.driver == p_dev->dev.driver)){
-			spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-			bind_info->instance = tmp_dev->instance;
-			ret = -EBUSY;
-			goto err_unregister;
+        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+		if (p_dev->func == bind_info->function) {
+			if ((p_dev->dev.driver == &p_drv->drv)) {
+				if (p_dev->cardmgr) {
+					/* if there's already a device
+					 * registered, and it was registered
+					 * by userspace before, we need to
+					 * return the "instance". */
+					spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+					bind_info->instance = p_dev->instance;
+					ret = -EBUSY;
+					goto err_put_module;
+				} else {
+					/* the correct driver managed to bind
+					 * itself magically to the correct
+					 * device. */
+					spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+					p_dev->cardmgr = p_drv;
+					ret = 0;
+					goto err_put_module;
+				}
+			} else if (!p_dev->dev.driver) {
+				/* there's already a device available where
+				 * no device has been bound to yet. So we don't
+				 * need to register a device! */
+				spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+				goto rescan;
+			}
 		}
 	}
-	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-	if (p_drv->attach) {
-		p_dev->instance = p_drv->attach();
-		if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
-			printk(KERN_NOTICE "ds: unable to create instance "
-			       "of '%s'!\n", (char *)bind_info->dev_info);
-			ret = -ENODEV;
-			goto err_unregister;
-		}
+	p_dev = pcmcia_device_add(s, bind_info->function);
+	if (!p_dev) {
+		ret = -EIO;
+		goto err_put_module;
 	}
 
-	put_driver(&p_drv->drv);
+rescan:
+	p_dev->cardmgr = p_drv;
 
-	return 0;
+	pcmcia_device_query(p_dev);
 
- err_unregister:
-	device_unregister(&p_dev->dev);
-	module_put(p_drv->owner);
-	put_driver(&p_drv->drv);
-	return (ret);
+	/*
+	 * Prevent this racing with a card insertion.
+	 */
+	down(&s->parent->skt_sem);
+	bus_rescan_devices(&pcmcia_bus_type);
+	up(&s->parent->skt_sem);
+
+	/* check whether the driver indeed matched. I don't care if this
+	 * is racy or not, because it can only happen on cardmgr access
+	 * paths...
+	 */
+	if (!(p_dev->dev.driver == &p_drv->drv))
+		p_dev->cardmgr = NULL;
 
  err_put_module:
 	module_put(p_drv->owner);
@@ -630,9 +878,11 @@ static int bind_request(struct pcmcia_bu
 	put_driver(&p_drv->drv);
  err_put:
 	pcmcia_put_bus_socket(s);
+
 	return (ret);
 } /* bind_request */
 
+
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 {
 	client_t *client = NULL;
@@ -683,10 +933,6 @@ int pcmcia_register_client(client_handle
 
 	pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */
 
-	/*
-	 * Prevent this racing with a card insertion.
-	 */
-	down(&s->skt_sem);
 	*handle = client;
 	client->state &= ~CLIENT_UNBOUND;
 	client->Socket = s;
@@ -723,11 +969,9 @@ int pcmcia_register_client(client_handle
 			EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
 	}
 
-	up(&s->skt_sem);
 	return CS_SUCCESS;
 
  out_no_resource:
-	up(&s->skt_sem);
 	pcmcia_put_dev(p_dev);
 	return CS_OUT_OF_RESOURCE;
 } /* register_client */
@@ -831,7 +1075,6 @@ static int get_device_info(struct pcmcia
 static int unbind_request(struct pcmcia_bus_socket *s)
 {
 	struct pcmcia_device	*p_dev;
-	struct pcmcia_driver	*p_drv;
 	unsigned long		flags;
 
 	ds_dbg(2, "unbind_request(%d)\n", s->parent->sock);
@@ -850,14 +1093,6 @@ static int unbind_request(struct pcmcia_
 		p_dev->client.state |= CLIENT_STALE;
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-		/* detach the "instance" */
-		p_drv = to_pcmcia_drv(p_dev->dev.driver);
-		if (p_drv) {
-			if ((p_drv->detach) && (p_dev->instance))
-				p_drv->detach(p_dev->instance);
-			module_put(p_drv->owner);
-		}
-
 		device_unregister(&p_dev->dev);
 	}
 
@@ -964,8 +1199,6 @@ static int ds_release(struct inode *inod
     /* Unlink user data structure */
     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 	s->state &= ~DS_SOCKET_BUSY;
-	s->req_pending = 0;
-	wake_up_interruptible(&s->request);
     }
     file->private_data = NULL;
     for (link = &s->user; *link; link = &(*link)->next)
@@ -1014,33 +1247,14 @@ static ssize_t ds_read(struct file *file
 static ssize_t ds_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-
     ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
-    
+
     if (count != 4)
 	return -EINVAL;
     if ((file->f_flags & O_ACCMODE) == O_RDONLY)
 	return -EBADF;
 
-    user = file->private_data;
-    if (CHECK_USER(user))
-	return -EIO;
-
-    s = user->socket;
-    if (s->state & DS_SOCKET_DEAD)
-        return -EIO;
-
-    if (s->req_pending) {
-	s->req_pending--;
-	get_user(s->req_result, (int __user *)buf);
-	if ((s->req_result != 0) || (s->req_pending == 0))
-	    wake_up_interruptible(&s->request);
-    } else
-	return -EIO;
-
-    return 4;
+    return -EIO;
 } /* ds_write */
 
 /*====================================================================*/
@@ -1099,17 +1313,15 @@ static int ds_ioctl(struct inode * inode
 	return -EPERM;
 	
     if (cmd & IOC_IN) {
-	err = verify_area(VERIFY_READ, uarg, size);
-	if (err) {
-	    ds_dbg(3, "ds_ioctl(): verify_read = %d\n", err);
-	    return err;
+	if (!access_ok(VERIFY_READ, uarg, size)) {
+	    ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
+	    return -EFAULT;
 	}
     }
     if (cmd & IOC_OUT) {
-	err = verify_area(VERIFY_WRITE, uarg, size);
-	if (err) {
-	    ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err);
-	    return err;
+	if (!access_ok(VERIFY_WRITE, uarg, size)) {
+	    ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
+	    return -EFAULT;
 	}
     }
     buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
@@ -1136,7 +1348,9 @@ static int ds_ioctl(struct inode * inode
 			buf->config.Function, &buf->config);
 	break;
     case DS_GET_FIRST_TUPLE:
+	down(&s->parent->skt_sem);
 	pcmcia_validate_mem(s->parent);
+	up(&s->parent->skt_sem);
 	ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
 	break;
     case DS_GET_NEXT_TUPLE:
@@ -1162,7 +1376,9 @@ static int ds_ioctl(struct inode * inode
 	ret = pccard_get_status(s->parent, buf->status.Function, &buf->status);
 	break;
     case DS_VALIDATE_CIS:
+	down(&s->parent->skt_sem);
 	pcmcia_validate_mem(s->parent);
+	up(&s->parent->skt_sem);
 	ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo);
 	break;
     case DS_SUSPEND_CARD:
@@ -1203,7 +1419,7 @@ static int ds_ioctl(struct inode * inode
 			printed++;
 		}
 	}
-	ret = -EINVAL;
+	err = -EINVAL;
 	goto free_out;
 	break;
     case DS_GET_FIRST_WINDOW:
@@ -1312,12 +1528,12 @@ static int __devinit pcmcia_bus_add_sock
 	msleep(250);
 
 	init_waitqueue_head(&s->queue);
-	init_waitqueue_head(&s->request);
 	INIT_LIST_HEAD(&s->devices_list);
 
 	/* Set up hotline to Card Services */
 	s->callback.owner = THIS_MODULE;
 	s->callback.event = &ds_event;
+	s->callback.resources_done = &pcmcia_card_add;
 	socket->pcmcia = s;
 
 	ret = pccard_register_pcmcia(socket, &s->callback);
@@ -1359,6 +1575,8 @@ static struct class_interface pcmcia_bus
 
 struct bus_type pcmcia_bus_type = {
 	.name = "pcmcia",
+	.match = pcmcia_bus_match,
+	.dev_attrs = pcmcia_dev_attrs,
 };
 EXPORT_SYMBOL(pcmcia_bus_type);
 
@@ -1374,9 +1592,9 @@ static int __init init_pcmcia_bus(void)
 
 	/* Set up character device for user mode clients */
 	i = register_chrdev(0, "pcmcia", &ds_fops);
-	if (i == -EBUSY)
+	if (i < 0)
 		printk(KERN_NOTICE "unable to find a free device # for "
-		       "Driver Services\n");
+		       "Driver Services (error=%d)\n", i);
 	else
 		major_dev = i;
 
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -353,20 +353,6 @@ static int hs_init(struct pcmcia_socket 
 
 /*============================================================*/
 
-static int hs_suspend(struct pcmcia_socket *s)
-{
-#ifdef HD64465_DEBUG
-    	hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
-    	DPRINTK("hs_suspend(%d)\n", sp->number);
-#endif
-
-    	/* TODO */
-	
-	return 0;
-}
-
-/*============================================================*/
-
 
 static int hs_get_status(struct pcmcia_socket *s, u_int *value)
 {
@@ -763,7 +749,6 @@ static irqreturn_t hs_interrupt(int irq,
 
 static struct pccard_operations hs_operations = {
 	.init			= hs_init,
-	.suspend		= hs_suspend,
 	.get_status		= hs_get_status,
 	.get_socket		= hs_get_socket,
 	.set_socket		= hs_set_socket,
@@ -860,7 +845,7 @@ static void hs_exit_socket(hs_socket_t *
 	local_irq_restore(flags);
 }
 
-static int hd64465_suspend(struct device *dev, u32 state, u32 level)
+static int hd64465_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -42,7 +42,7 @@ static struct pci_device_id i82092aa_pci
 };
 MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
 
-static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state)
+static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state)
 {
 	return pcmcia_socket_dev_suspend(&dev->dev, state);
 }
@@ -65,7 +65,6 @@ static struct pci_driver i82092aa_pci_dr
 /* the pccard structure and its functions */
 static struct pccard_operations i82092aa_operations = {
 	.init 		 	= i82092aa_init,
-	.suspend	   	= i82092aa_suspend,
 	.get_status		= i82092aa_get_status,
 	.get_socket		= i82092aa_get_socket,
 	.set_socket		= i82092aa_set_socket,
@@ -440,15 +439,6 @@ static int i82092aa_init(struct pcmcia_s
 	return 0;
 }
                                                                                                                                                                                                                                               
-static int i82092aa_suspend(struct pcmcia_socket *sock)
-{
-	int retval;
-	enter("i82092aa_suspend");
-        retval =  i82092aa_set_socket(sock, &dead_socket);
-        leave("i82092aa_suspend");
-        return retval;
-}
-       
 static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value)
 {
 	unsigned int sock = container_of(socket, struct socket_info, socket)->number;
diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h
--- a/drivers/pcmcia/i82092aa.h
+++ b/drivers/pcmcia/i82092aa.h
@@ -34,7 +34,6 @@ static int i82092aa_set_socket(struct pc
 static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io);
 static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem);
 static int i82092aa_init(struct pcmcia_socket *socket);
-static int i82092aa_suspend(struct pcmcia_socket *socket);
 
 #endif
 
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1322,14 +1322,8 @@ static int pcic_init(struct pcmcia_socke
 	return 0;
 }
 
-static int pcic_suspend(struct pcmcia_socket *sock)
-{
-	return pcic_set_socket(sock, &dead_socket);
-}
-
 static struct pccard_operations pcic_operations = {
 	.init			= pcic_init,
-	.suspend		= pcic_suspend,
 	.get_status		= pcic_get_status,
 	.get_socket		= pcic_get_socket,
 	.set_socket		= pcic_set_socket,
@@ -1339,7 +1333,7 @@ static struct pccard_operations pcic_ope
 
 /*====================================================================*/
 
-static int i82365_suspend(struct device *dev, u32 state, u32 level)
+static int i82365_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -732,15 +732,8 @@ static int pcc_init(struct pcmcia_socket
 	return 0;
 }
 
-static int pcc_suspend(struct pcmcia_socket *sock)
-{
-	debug(3, "m32r_cfc: pcc_suspend()\n");
-	return pcc_set_socket(sock, &dead_socket);
-}
-
 static struct pccard_operations pcc_operations = {
 	.init			= pcc_init,
-	.suspend		= pcc_suspend,
 	.get_status		= pcc_get_status,
 	.get_socket		= pcc_get_socket,
 	.set_socket		= pcc_set_socket,
@@ -750,7 +743,7 @@ static struct pccard_operations pcc_oper
 
 /*====================================================================*/
 
-static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level)
+static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -685,14 +685,8 @@ static int pcc_init(struct pcmcia_socket
 	return 0;
 }
 
-static int pcc_suspend(struct pcmcia_socket *sock)
-{
-	return pcc_set_socket(sock, &dead_socket);
-}
-
 static struct pccard_operations pcc_operations = {
 	.init			= pcc_init,
-	.suspend		= pcc_suspend,
 	.get_status		= pcc_get_status,
 	.get_socket		= pcc_get_socket,
 	.set_socket		= pcc_set_socket,
@@ -702,7 +696,7 @@ static struct pccard_operations pcc_oper
 
 /*====================================================================*/
 
-static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level)
+static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -615,11 +615,6 @@ static int pd6729_set_mem_map(struct pcm
 	return 0;
 }
 
-static int pd6729_suspend(struct pcmcia_socket *sock)
-{
-	return pd6729_set_socket(sock, &dead_socket);
-}
-
 static int pd6729_init(struct pcmcia_socket *sock)
 {
 	int i;
@@ -644,7 +639,6 @@ static int pd6729_init(struct pcmcia_soc
 /* the pccard structure and its functions */
 static struct pccard_operations pd6729_operations = {
 	.init 			= pd6729_init,
-	.suspend		= pd6729_suspend,
 	.get_status		= pd6729_get_status,
 	.get_socket		= pd6729_get_socket,
 	.set_socket		= pd6729_set_socket,
@@ -750,7 +744,7 @@ static int __devinit pd6729_pci_probe(st
 
 	for (i = 0; i < MAX_SOCKETS; i++) {
 		socket[i].io_base = pci_resource_start(dev, 0);
-		socket[i].socket.features |= SS_CAP_PCCARD;
+		socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
 		socket[i].socket.map_size = 0x1000;
 		socket[i].socket.irq_mask = mask;
 		socket[i].socket.pci_irq  = dev->irq;
@@ -833,7 +827,7 @@ static void __devexit pd6729_pci_remove(
 	kfree(socket);
 }
 
-static int pd6729_socket_suspend(struct pci_dev *dev, u32 state)
+static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	return pcmcia_socket_dev_suspend(&dev->dev, state);
 }
@@ -865,7 +859,7 @@ static struct pci_driver pd6729_pci_drv 
 
 static int pd6729_module_init(void)
 {
-	return pci_module_init(&pd6729_pci_drv);
+	return pci_register_driver(&pd6729_pci_drv);
 }
 
 static void pd6729_module_exit(void)
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -205,7 +205,7 @@ int pxa2xx_drv_pcmcia_probe(struct devic
 }
 EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe);
 
-static int pxa2xx_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level)
+static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -38,7 +38,7 @@ static struct pcmcia_irqs irqs[] = {
 
 static void sharpsl_pcmcia_init_reset(void)
 {
-	reset_scoop();
+	reset_scoop(&corgiscoop_device.dev);
 	keep_vs = NO_KEEP_VS;
 	keep_rd = 0;
 }
@@ -79,8 +79,8 @@ static int sharpsl_pcmcia_hw_init(struct
 	}
 
 	/* Enable interrupt */
-	write_scoop_reg(SCOOP_IMR, 0x00C0);
-	write_scoop_reg(SCOOP_MCR, 0x0101);
+	write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0);
+	write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101);
 	keep_vs = NO_KEEP_VS;
 
 	skt->irq = CORGI_IRQ_GPIO_CF_IRQ;
@@ -102,30 +102,30 @@ static void sharpsl_pcmcia_socket_state(
 {
 	unsigned short cpr, csr;
 
-	cpr = read_scoop_reg(SCOOP_CPR);
+	cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR);
 
-	write_scoop_reg(SCOOP_IRM, 0x00FF);
-	write_scoop_reg(SCOOP_ISR, 0x0000);
-	write_scoop_reg(SCOOP_IRM, 0x0000);
-	csr = read_scoop_reg(SCOOP_CSR);
+	write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF);
+	write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000);
+	write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000);
+	csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR);
 	if (csr & 0x0004) {
 		/* card eject */
-		write_scoop_reg(SCOOP_CDR, 0x0000);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
 		keep_vs = NO_KEEP_VS;
 	}
 	else if (!(keep_vs & NO_KEEP_VS)) {
 		/* keep vs1,vs2 */
-		write_scoop_reg(SCOOP_CDR, 0x0000);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
 		csr |= keep_vs;
 	}
 	else if (cpr & 0x0003) {
 		/* power on */
-		write_scoop_reg(SCOOP_CDR, 0x0000);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
 		keep_vs = (csr & 0x00C0);
 	}
 	else {
 		/* card detect */
-		write_scoop_reg(SCOOP_CDR, 0x0002);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002);
 	}
 
 	state->detect = (csr & 0x0004) ? 0 : 1;
@@ -166,10 +166,10 @@ static int sharpsl_pcmcia_configure_sock
 
 	local_irq_save(flags);
 
-	nmcr = (mcr = read_scoop_reg(SCOOP_MCR)) & ~0x0010;
-	ncpr = (cpr = read_scoop_reg(SCOOP_CPR)) & ~0x0083;
-	nccr = (ccr = read_scoop_reg(SCOOP_CCR)) & ~0x0080;
-	nimr = (imr = read_scoop_reg(SCOOP_IMR)) & ~0x003E;
+	nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010;
+	ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083;
+	nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080;
+	nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E;
 
 	ncpr |= (state->Vcc == 33) ? 0x0001 :
 				(state->Vcc == 50) ? 0x0002 : 0;
@@ -193,13 +193,13 @@ static int sharpsl_pcmcia_configure_sock
 	}
 
 	if (mcr != nmcr)
-		write_scoop_reg(SCOOP_MCR, nmcr);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr);
 	if (cpr != ncpr)
-		write_scoop_reg(SCOOP_CPR, ncpr);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr);
 	if (ccr != nccr)
-		write_scoop_reg(SCOOP_CCR, nccr);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr);
 	if (imr != nimr)
-		write_scoop_reg(SCOOP_IMR, nimr);
+		write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr);
 
 	local_irq_restore(flags);
 
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -59,6 +59,7 @@ int pcmcia_adjust_resource_info(adjust_t
 {
 	struct pcmcia_socket *s;
 	int ret = CS_UNSUPPORTED_FUNCTION;
+	unsigned long flags;
 
 	down_read(&pcmcia_socket_list_rwsem);
 	list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
@@ -66,8 +67,30 @@ int pcmcia_adjust_resource_info(adjust_t
 		if (adj->Resource == RES_IRQ)
 			ret = adjust_irq(s, adj);
 
-		else if (s->resource_ops->adjust_resource)
+		else if (s->resource_ops->adjust_resource) {
+
+			/* you can't use the old interface if the new
+			 * one was used before */
+			spin_lock_irqsave(&s->lock, flags);
+			if ((s->resource_setup_done) &&
+			    !(s->resource_setup_old)) {
+				spin_unlock_irqrestore(&s->lock, flags);
+				continue;
+			} else if (!(s->resource_setup_old))
+				s->resource_setup_old = 1;
+			spin_unlock_irqrestore(&s->lock, flags);
+
 			ret = s->resource_ops->adjust_resource(s, adj);
+			if (!ret) {
+				/* as there's no way we know this is the
+				 * last call to adjust_resource_info, we
+				 * always need to assume this is the latest
+				 * one... */
+				spin_lock_irqsave(&s->lock, flags);
+				s->resource_setup_done = 1;
+				spin_unlock_irqrestore(&s->lock, flags);
+			}
+		}
 	}
 	up_read(&pcmcia_socket_list_rwsem);
 
@@ -113,12 +136,28 @@ void release_resource_db(struct pcmcia_s
 }
 
 
+static int static_init(struct pcmcia_socket *s)
+{
+	unsigned long flags;
+
+	/* the good thing about SS_CAP_STATIC_MAP sockets is
+	 * that they don't need a resource database */
+
+	spin_lock_irqsave(&s->lock, flags);
+	s->resource_setup_done = 1;
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return 0;
+}
+
+
 struct pccard_resource_ops pccard_static_ops = {
 	.validate_mem = NULL,
 	.adjust_io_region = NULL,
 	.find_io = NULL,
 	.find_mem = NULL,
 	.adjust_resource = NULL,
+	.init = static_init,
 	.exit = NULL,
 };
 EXPORT_SYMBOL(pccard_static_ops);
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -24,6 +24,8 @@
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
+#include <linux/device.h>
+
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -472,8 +474,7 @@ static void validate_mem(struct pcmcia_s
 
 
 /*
- * Locking note: this is the only place where we take
- * both rsrc_sem and skt_sem.
+ * Locking note: Must be called with skt_sem held!
  */
 static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
 {
@@ -490,12 +491,8 @@ static void pcmcia_nonstatic_validate_me
 		if (probe_mask & ~s_data->rsrc_mem_probe) {
 			s_data->rsrc_mem_probe |= probe_mask;
 
-			down(&s->skt_sem);
-
 			if (s->state & SOCKET_PRESENT)
 				validate_mem(s, probe_mask);
-
-			up(&s->skt_sem);
 		}
 
 		up(&rsrc_sem);
@@ -779,6 +776,7 @@ static int nonstatic_init(struct pcmcia_
 	data = kmalloc(sizeof(struct socket_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
+	memset(data, 0, sizeof(struct socket_data));
 
 	data->mem_db.next = &data->mem_db;
 	data->io_db.next = &data->io_db;
@@ -816,3 +814,172 @@ struct pccard_resource_ops pccard_nonsta
 	.exit = nonstatic_release_resource_db,
 };
 EXPORT_SYMBOL(pccard_nonstatic_ops);
+
+
+/* sysfs interface to the resource database */
+
+static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct socket_data *data;
+	struct resource_map *p;
+	ssize_t ret = 0;
+
+	down(&rsrc_sem);
+	data = s->resource_data;
+
+	for (p = data->io_db.next; p != &data->io_db; p = p->next) {
+		if (ret > (PAGE_SIZE - 10))
+			continue;
+		ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1),
+				 "0x%08lx - 0x%08lx\n",
+				 ((unsigned long) p->base),
+				 ((unsigned long) p->base + p->num - 1));
+	}
+
+	up(&rsrc_sem);
+	return (ret);
+}
+
+static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	unsigned long start_addr, end_addr;
+	unsigned int add = 1;
+	adjust_t adj;
+	ssize_t ret = 0;
+
+	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+	if (ret != 2) {
+		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+		add = 0;
+		if (ret != 2) {
+			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
+			add = 1;
+			if (ret != 2)
+				return -EINVAL;
+		}
+	}
+	if (end_addr <= start_addr)
+		return -EINVAL;
+
+	adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
+	adj.Resource = RES_IO_RANGE;
+	adj.resource.io.BasePort = start_addr;
+	adj.resource.io.NumPorts = end_addr - start_addr + 1;
+
+	ret = adjust_io(s, &adj);
+
+	return ret ? ret : count;
+}
+static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+
+static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct socket_data *data;
+	struct resource_map *p;
+	ssize_t ret = 0;
+
+	down(&rsrc_sem);
+	data = s->resource_data;
+
+	for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
+		if (ret > (PAGE_SIZE - 10))
+			continue;
+		ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1),
+				 "0x%08lx - 0x%08lx\n",
+				 ((unsigned long) p->base),
+				 ((unsigned long) p->base + p->num - 1));
+	}
+
+	up(&rsrc_sem);
+	return (ret);
+}
+
+static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	unsigned long start_addr, end_addr;
+	unsigned int add = 1;
+	adjust_t adj;
+	ssize_t ret = 0;
+
+	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+	if (ret != 2) {
+		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+		add = 0;
+		if (ret != 2) {
+			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
+			add = 1;
+			if (ret != 2)
+				return -EINVAL;
+		}
+	}
+	if (end_addr <= start_addr)
+		return -EINVAL;
+
+	adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
+	adj.Resource = RES_MEMORY_RANGE;
+	adj.resource.memory.Base = start_addr;
+	adj.resource.memory.Size = end_addr - start_addr + 1;
+
+	ret = adjust_memory(s, &adj);
+
+	return ret ? ret : count;
+}
+static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+
+static struct class_device_attribute *pccard_rsrc_attributes[] = {
+	&class_device_attr_available_resources_io,
+	&class_device_attr_available_resources_mem,
+	NULL,
+};
+
+static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct class_device_attribute **attr;
+	int ret = 0;
+	if (s->resource_ops != &pccard_nonstatic_ops)
+		return 0;
+
+	for (attr = pccard_rsrc_attributes; *attr; attr++) {
+		ret = class_device_create_file(class_dev, *attr);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev)
+{
+	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct class_device_attribute **attr;
+
+	if (s->resource_ops != &pccard_nonstatic_ops)
+		return;
+
+	for (attr = pccard_rsrc_attributes; *attr; attr++)
+		class_device_remove_file(class_dev, *attr);
+}
+
+static struct class_interface pccard_rsrc_interface = {
+	.class = &pcmcia_socket_class,
+	.add = &pccard_sysfs_add_rsrc,
+	.remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+};
+
+static int __init nonstatic_sysfs_init(void)
+{
+	return class_interface_register(&pccard_rsrc_interface);
+}
+
+static void __exit nonstatic_sysfs_exit(void)
+{
+	class_interface_unregister(&pccard_rsrc_interface);
+}
+
+module_init(nonstatic_sysfs_init);
+module_exit(nonstatic_sysfs_exit);
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -75,7 +75,7 @@ static int sa11x0_drv_pcmcia_probe(struc
 	return ret;
 }
 
-static int sa11x0_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level)
+static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -158,7 +158,7 @@ static int __devexit pcmcia_remove(struc
 	return 0;
 }
 
-static int pcmcia_suspend(struct sa1111_dev *dev, u32 state)
+static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state)
 {
 	return pcmcia_socket_dev_suspend(&dev->dev, state);
 }
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -197,15 +197,12 @@ static int soc_common_pcmcia_sock_init(s
 static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
 {
 	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
-	int ret;
 
 	debug(skt, 2, "suspending socket\n");
 
-	ret = soc_common_pcmcia_config_skt(skt, &dead_socket);
-	if (ret == 0)
-		skt->ops->socket_suspend(skt);
+	skt->ops->socket_suspend(skt);
 
-	return ret;
+	return 0;
 }
 
 static DEFINE_SPINLOCK(status_lock);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -148,6 +148,45 @@ static ssize_t pccard_store_irq_mask(str
 static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
 
 
+static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
+}
+
+static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+{
+	unsigned long flags;
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (!s->resource_setup_done) {
+		s->resource_setup_done = 1;
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		down(&s->skt_sem);
+		if ((s->callback) &&
+		    (s->state & SOCKET_PRESENT) &&
+		    !(s->state & SOCKET_CARDBUS)) {
+			if (try_module_get(s->callback->owner)) {
+				s->callback->resources_done(s);
+				module_put(s->callback->owner);
+			}
+		}
+		up(&s->skt_sem);
+
+		return count;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return count;
+}
+static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+
 static struct class_device_attribute *pccard_socket_attributes[] = {
 	&class_device_attr_card_type,
 	&class_device_attr_card_voltage,
@@ -156,6 +195,7 @@ static struct class_device_attribute *pc
 	&class_device_attr_card_insert,
 	&class_device_attr_card_eject,
 	&class_device_attr_card_irq_mask,
+	&class_device_attr_available_resources_setup_done,
 	NULL,
 };
 
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -373,7 +373,7 @@ static int __init get_tcic_id(void)
 
 /*====================================================================*/
 
-static int tcic_drv_suspend(struct device *dev, u32 state, u32 level)
+static int tcic_drv_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int ret = 0;
 	if (level == SUSPEND_SAVE_STATE)
@@ -888,14 +888,8 @@ static int tcic_init(struct pcmcia_socke
 	return 0;
 }
 
-static int tcic_suspend(struct pcmcia_socket *sock)
-{
-	return tcic_set_socket(sock, &dead_socket);
-}
-
 static struct pccard_operations tcic_operations = {
 	.init		   = tcic_init,
-	.suspend	   = tcic_suspend,
 	.get_status	   = tcic_get_status,
 	.get_socket	   = tcic_get_socket,
 	.set_socket	   = tcic_set_socket,
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -262,6 +262,7 @@ static void ti_set_zv(struct yenta_socke
 			case PCI_DEVICE_ID_TI_1220:
 			case PCI_DEVICE_ID_TI_1221:
 			case PCI_DEVICE_ID_TI_1225:
+			case PCI_DEVICE_ID_TI_4510:
 				socket->socket.zoom_video = ti_zoom_video;
 				break;	
 			case PCI_DEVICE_ID_TI_1250:
@@ -441,6 +442,25 @@ out:
 }
 
 
+/* changes the irq of func1 to match that of func0 */
+static int ti12xx_align_irqs(struct yenta_socket *socket, int *old_irq)
+{
+	struct pci_dev *func0;
+
+	/* find func0 device */
+	func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07);
+	if (!func0)
+		return 0;
+
+	if (old_irq)
+		*old_irq = socket->cb_irq;
+	socket->cb_irq = socket->dev->irq = func0->irq;
+
+	pci_dev_put(func0);
+
+	return 1;
+}
+
 /*
  * ties INTA and INTB together. also changes the devices irq to that of
  * the function 0 device. call from func1 only.
@@ -448,26 +468,22 @@ out:
  */
 static int ti12xx_tie_interrupts(struct yenta_socket *socket, int *old_irq)
 {
-	struct pci_dev *func0;
 	u32 sysctl;
+	int ret;
 
 	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
 	if (sysctl & TI122X_SCR_INTRTIE)
 		return 0;
 
-	/* find func0 device */
-	func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07);
-	if (!func0)
+	/* align */
+	ret = ti12xx_align_irqs(socket, old_irq);
+	if (!ret)
 		return 0;
 
-	/* change the interrupt to match func0, tie 'em up */
-	*old_irq = socket->cb_irq;
-	socket->cb_irq = socket->dev->irq = func0->irq;
+	/* tie */
 	sysctl |= TI122X_SCR_INTRTIE;
 	config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl);
 
-	pci_dev_put(func0);
-
 	return 1;
 }
 
@@ -488,7 +504,7 @@ static void ti12xx_untie_interrupts(stru
  */
 static void ti12xx_irqroute_func1(struct yenta_socket *socket)
 {
-	u32 mfunc, mfunc_old, devctl;
+	u32 mfunc, mfunc_old, devctl, sysctl;
 	int pci_irq_status;
 
 	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
@@ -496,6 +512,11 @@ static void ti12xx_irqroute_func1(struct
 	printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
 	       pci_name(socket->dev), mfunc, devctl);
 
+	/* if IRQs are configured as tied, align irq of func1 with func0 */
+	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	if (sysctl & TI122X_SCR_INTRTIE)
+		ti12xx_align_irqs(socket, NULL);
+
 	/* make sure PCI interrupts are enabled before probing */
 	ti_init(socket);
 
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -1,7 +1,7 @@
 /*
  * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
  *
- * Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * Copyright (C) 2003-2005  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
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 
 #include <asm/io.h>
-#include <asm/vr41xx/vrc4171.h>
 
 #include <pcmcia/ss.h>
 
@@ -48,7 +47,6 @@ MODULE_LICENSE("GPL");
 
 #define CARD_CONTROLLER_INDEX	0x03e0
 #define CARD_CONTROLLER_DATA	0x03e1
-#define CARD_CONTROLLER_SIZE	2
  /* Power register */
   #define VPP_GET_VCC		0x01
   #define POWER_ENABLE		0x10
@@ -69,18 +67,40 @@ MODULE_LICENSE("GPL");
   #define IRQPM_EN		0x08
   #define CLRPMIRQ		0x10
 
+#define INTERRUPT_STATUS	0x05fa
+ #define IRQ_A			0x02
+ #define IRQ_B			0x04
+
+#define CONFIGURATION1		0x05fe
+ #define SLOTB_CONFIG		0xc000
+ #define SLOTB_NONE		0x0000
+ #define SLOTB_PCCARD		0x4000
+ #define SLOTB_CF		0x8000
+ #define SLOTB_FLASHROM		0xc000
+
+#define CARD_CONTROLLER_START	CARD_CONTROLLER_INDEX
+#define CARD_CONTROLLER_END	CARD_CONTROLLER_DATA
+
 #define IO_MAX_MAPS	2
 #define MEM_MAX_MAPS	5
 
-enum {
+typedef enum {
 	SLOT_PROBE = 0,
 	SLOT_NOPROBE_IO,
 	SLOT_NOPROBE_MEM,
-	SLOT_NOPROBE_ALL
-};
+	SLOT_NOPROBE_ALL,
+	SLOT_INITIALIZED,
+} vrc4171_slot_t;
+
+typedef enum {
+	SLOTB_IS_NONE,
+	SLOTB_IS_PCCARD,
+	SLOTB_IS_CF,
+	SLOTB_IS_FLASHROM,
+} vrc4171_slotb_t;
 
 typedef struct vrc4171_socket {
-	int noprobe;
+	vrc4171_slot_t slot;
 	struct pcmcia_socket pcmcia_socket;
 	char name[24];
 	int csc_irq;
@@ -88,10 +108,65 @@ typedef struct vrc4171_socket {
 } vrc4171_socket_t;
 
 static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS];
-static int vrc4171_slotb = SLOTB_IS_NONE;
+static vrc4171_slotb_t vrc4171_slotb = SLOTB_IS_NONE;
+static char vrc4171_card_name[] = "NEC VRC4171 Card Controller";
 static unsigned int vrc4171_irq;
 static uint16_t vrc4171_irq_mask = 0xdeb8;
 
+static struct resource vrc4171_card_resource[3] = {
+	{	.name		= vrc4171_card_name,
+		.start		= CARD_CONTROLLER_START,
+		.end		= CARD_CONTROLLER_END,
+		.flags		= IORESOURCE_IO,	},
+	{	.name		= vrc4171_card_name,
+		.start		= INTERRUPT_STATUS,
+		.end		= INTERRUPT_STATUS,
+		.flags		= IORESOURCE_IO,	},
+	{	.name		= vrc4171_card_name,
+		.start		= CONFIGURATION1,
+		.end		= CONFIGURATION1,
+		.flags		= IORESOURCE_IO,	},
+};
+
+static struct platform_device vrc4171_card_device = {
+	.name		= vrc4171_card_name,
+	.id		= 0,
+	.num_resources	= 3,
+	.resource	= vrc4171_card_resource,
+};
+
+static inline uint16_t vrc4171_get_irq_status(void)
+{
+	return inw(INTERRUPT_STATUS);
+}
+
+static inline void vrc4171_set_multifunction_pin(vrc4171_slotb_t config)
+{
+	uint16_t config1;
+
+	config1 = inw(CONFIGURATION1);
+	config1 &= ~SLOTB_CONFIG;
+
+	switch (config) {
+	case SLOTB_IS_NONE:
+		config1 |= SLOTB_NONE;
+		break;
+	case SLOTB_IS_PCCARD:
+		config1 |= SLOTB_PCCARD;
+		break;
+	case SLOTB_IS_CF:
+		config1 |= SLOTB_CF;
+		break;
+	case SLOTB_IS_FLASHROM:
+		config1 |= SLOTB_FLASHROM;
+		break;
+	default:
+		break;
+	}
+
+	outw(config1, CONFIGURATION1);
+}
+
 static inline uint8_t exca_read_byte(int slot, uint8_t index)
 {
 	if (slot == CARD_SLOTB)
@@ -174,11 +249,6 @@ static int pccard_init(struct pcmcia_soc
 	return 0;
 }
 
-static int pccard_suspend(struct pcmcia_socket *sock)
-{
-	return -EINVAL;
-}
-
 static int pccard_get_status(struct pcmcia_socket *sock, u_int *value)
 {
 	unsigned int slot;
@@ -425,9 +495,9 @@ static int pccard_set_mem_map(struct pcm
 
 	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||
 	    mem == NULL || mem->map >= MEM_MAX_MAPS ||
-	    mem->sys_start < CARD_MEM_START || mem->sys_start > CARD_MEM_END ||
-	    mem->sys_stop < CARD_MEM_START || mem->sys_stop > CARD_MEM_END ||
-	    mem->sys_start > mem->sys_stop ||
+	    mem->res->start < CARD_MEM_START || mem->res->start > CARD_MEM_END ||
+	    mem->res->end < CARD_MEM_START || mem->res->end > CARD_MEM_END ||
+	    mem->res->start > mem->res->end ||
 	    mem->card_start > CARD_MAX_MEM_OFFSET ||
 	    mem->speed > CARD_MAX_MEM_SPEED)
 		return -EINVAL;
@@ -441,12 +511,12 @@ static int pccard_set_mem_map(struct pcm
 		exca_write_byte(slot, I365_ADDRWIN, addrwin);
 	}
 
-	start = (mem->sys_start >> 12) & 0x3fff;
+	start = (mem->res->start >> 12) & 0x3fff;
 	if (mem->flags & MAP_16BIT)
 		start |= I365_MEM_16BIT;
 	exca_write_word(slot, I365_MEM(map)+I365_W_START, start);
 
-	stop = (mem->sys_stop >> 12) & 0x3fff;
+	stop = (mem->res->end >> 12) & 0x3fff;
 	switch (mem->speed) {
 	case 0:
 		break;
@@ -479,7 +549,6 @@ static int pccard_set_mem_map(struct pcm
 
 static struct pccard_operations vrc4171_pccard_operations = {
 	.init			= pccard_init,
-	.suspend		= pccard_suspend,
 	.get_status		= pccard_get_status,
 	.get_socket		= pccard_get_socket,
 	.set_socket		= pccard_set_socket,
@@ -524,7 +593,7 @@ static irqreturn_t pccard_interrupt(int 
 	status = vrc4171_get_irq_status();
 	if (status & IRQ_A) {
 		socket = &vrc4171_sockets[CARD_SLOTA];
-		if (socket->noprobe == SLOT_PROBE) {
+		if (socket->slot == SLOT_INITIALIZED) {
 			if (status & (1 << socket->csc_irq)) {
 				events = get_events(CARD_SLOTA);
 				if (events != 0) {
@@ -537,7 +606,7 @@ static irqreturn_t pccard_interrupt(int 
 
 	if (status & IRQ_B) {
 		socket = &vrc4171_sockets[CARD_SLOTB];
-		if (socket->noprobe == SLOT_PROBE) {
+		if (socket->slot == SLOT_INITIALIZED) {
 			if (status & (1 << socket->csc_irq)) {
 				events = get_events(CARD_SLOTB);
 				if (events != 0) {
@@ -564,63 +633,71 @@ static inline void reserve_using_irq(int
 	vrc4171_irq_mask &= ~(1 << irq);
 }
 
-static int __devinit vrc4171_add_socket(int slot)
+static int __devinit vrc4171_add_sockets(void)
 {
 	vrc4171_socket_t *socket;
-	int retval;
+	int slot, retval;
 
-	if (slot >= CARD_MAX_SLOTS)
-		return -EINVAL;
+	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
+		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
+			continue;
 
-	socket = &vrc4171_sockets[slot];
-	if (socket->noprobe != SLOT_PROBE) {
-		uint8_t addrwin;
+		socket = &vrc4171_sockets[slot];
+		if (socket->slot != SLOT_PROBE) {
+			uint8_t addrwin;
+
+			switch (socket->slot) {
+			case SLOT_NOPROBE_MEM:
+				addrwin = exca_read_byte(slot, I365_ADDRWIN);
+				addrwin &= 0x1f;
+				exca_write_byte(slot, I365_ADDRWIN, addrwin);
+				break;
+			case SLOT_NOPROBE_IO:
+				addrwin = exca_read_byte(slot, I365_ADDRWIN);
+				addrwin &= 0xc0;
+				exca_write_byte(slot, I365_ADDRWIN, addrwin);
+				break;
+			default:
+				break;
+			}
 
-		switch (socket->noprobe) {
-		case SLOT_NOPROBE_MEM:
-			addrwin = exca_read_byte(slot, I365_ADDRWIN);
-			addrwin &= 0x1f;
-			exca_write_byte(slot, I365_ADDRWIN, addrwin);
-			break;
-		case SLOT_NOPROBE_IO:
-			addrwin = exca_read_byte(slot, I365_ADDRWIN);
-			addrwin &= 0xc0;
-			exca_write_byte(slot, I365_ADDRWIN, addrwin);
-			break;
-		default:
-			break;
+			reserve_using_irq(slot);
+			continue;
 		}
 
-		reserve_using_irq(slot);
-
-		return 0;
-	}
-
-	sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
-
-	socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
+		sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
+		socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev;
+		socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
+		socket->pcmcia_socket.owner = THIS_MODULE;
 
-	retval = pcmcia_register_socket(&socket->pcmcia_socket);
-	if (retval != 0)
-		return retval;
+		retval = pcmcia_register_socket(&socket->pcmcia_socket);
+		if (retval < 0)
+			return retval;
 
-	exca_write_byte(slot, I365_ADDRWIN, 0);
+		exca_write_byte(slot, I365_ADDRWIN, 0);
+		exca_write_byte(slot, GLOBAL_CONTROL, 0);
 
-	exca_write_byte(slot, GLOBAL_CONTROL, 0);
+		socket->slot = SLOT_INITIALIZED;
+	}
 
 	return 0;
 }
 
-static void vrc4171_remove_socket(int slot)
+static void vrc4171_remove_sockets(void)
 {
 	vrc4171_socket_t *socket;
+	int slot;
 
-	if (slot >= CARD_MAX_SLOTS)
-		return;
+	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
+		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
+			continue;
 
-	socket = &vrc4171_sockets[slot];
+		socket = &vrc4171_sockets[slot];
+		if (socket->slot == SLOT_INITIALIZED)
+			pcmcia_unregister_socket(&socket->pcmcia_socket);
 
-	pcmcia_unregister_socket(&socket->pcmcia_socket);
+		socket->slot = SLOT_PROBE;
+	}
 }
 
 static int __devinit vrc4171_card_setup(char *options)
@@ -644,13 +721,13 @@ static int __devinit vrc4171_card_setup(
 		options += 6;
 		if (*options != '\0') {
 			if (strncmp(options, "memnoprobe", 10) == 0) {
-				vrc4171_sockets[CARD_SLOTA].noprobe = SLOT_NOPROBE_MEM;
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_MEM;
 				options += 10;
 			} else if (strncmp(options, "ionoprobe", 9) == 0) {
-				vrc4171_sockets[CARD_SLOTA].noprobe = SLOT_NOPROBE_IO;
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_IO;
 				options += 9;
 			} else if ( strncmp(options, "noprobe", 7) == 0) {
-				vrc4171_sockets[CARD_SLOTA].noprobe = SLOT_NOPROBE_ALL;
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_ALL;
 				options += 7;
 			}
 
@@ -684,11 +761,11 @@ static int __devinit vrc4171_card_setup(
 			options++;
 
 			if (strncmp(options, "memnoprobe", 10) == 0)
-				vrc4171_sockets[CARD_SLOTB].noprobe = SLOT_NOPROBE_MEM;
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_MEM;
 			if (strncmp(options, "ionoprobe", 9) == 0)
-				vrc4171_sockets[CARD_SLOTB].noprobe = SLOT_NOPROBE_IO;
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_IO;
 			if (strncmp(options, "noprobe", 7) == 0)
-				vrc4171_sockets[CARD_SLOTB].noprobe = SLOT_NOPROBE_ALL;
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_ALL;
 		}
 	}
 
@@ -697,47 +774,72 @@ static int __devinit vrc4171_card_setup(
 
 __setup("vrc4171_card=", vrc4171_card_setup);
 
-static int __devinit vrc4171_card_init(void)
+static int vrc4171_card_suspend(struct device *dev, pm_message_t state, u32 level)
 {
-	int retval, slot;
+	int retval = 0;
 
-	vrc4171_set_multifunction_pin(vrc4171_slotb);
+	if (level == SUSPEND_SAVE_STATE)
+		retval = pcmcia_socket_dev_suspend(dev, state);
 
-	if (request_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE,
-	                       "NEC VRC4171 Card Controller") == NULL)
-		return -EBUSY;
+	return retval;
+}
 
-	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
-		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
-			break;
+static int vrc4171_card_resume(struct device *dev, u32 level)
+{
+	int retval = 0;
 
-		retval = vrc4171_add_socket(slot);
-		if (retval != 0)
-			return retval;
-	}
+	if (level == RESUME_RESTORE_STATE)
+		retval = pcmcia_socket_dev_resume(dev);
 
-	retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
-	                     "NEC VRC4171 Card Controller", vrc4171_sockets);
+	return retval;
+}
+
+static struct device_driver vrc4171_card_driver = {
+	.name		= vrc4171_card_name,
+	.bus		= &platform_bus_type,
+	.suspend	= vrc4171_card_suspend,
+	.resume		= vrc4171_card_resume,
+};
+
+static int __devinit vrc4171_card_init(void)
+{
+	int retval;
+
+	retval = driver_register(&vrc4171_card_driver);
+	if (retval < 0)
+		return retval;
+
+	retval = platform_device_register(&vrc4171_card_device);
 	if (retval < 0) {
-		for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
-			vrc4171_remove_socket(slot);
+		driver_unregister(&vrc4171_card_driver);
+		return retval;
+	}
+
+	vrc4171_set_multifunction_pin(vrc4171_slotb);
+
+	retval = vrc4171_add_sockets();
+	if (retval == 0)
+		retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
+		                     vrc4171_card_name, vrc4171_sockets);
 
+	if (retval < 0) {
+		vrc4171_remove_sockets();
+		platform_device_unregister(&vrc4171_card_device);
+		driver_unregister(&vrc4171_card_driver);
 		return retval;
 	}
 
-	printk(KERN_INFO "NEC VRC4171 Card Controller, connected to IRQ %d\n", vrc4171_irq);
+	printk(KERN_INFO "%s, connected to IRQ %d\n", vrc4171_card_driver.name, vrc4171_irq);
 
 	return 0;
 }
 
 static void __devexit vrc4171_card_exit(void)
 {
-	int slot;
-
-	for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
-		vrc4171_remove_socket(slot);
-
-	release_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE);
+	free_irq(vrc4171_irq, vrc4171_sockets);
+	vrc4171_remove_sockets();
+	platform_device_unregister(&vrc4171_card_device);
+	driver_unregister(&vrc4171_card_driver);
 }
 
 module_init(vrc4171_card_init);
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -141,11 +141,6 @@ static int cardu_init(unsigned int slot)
 	return 0;
 }
 
-static int cardu_suspend(unsigned int slot)
-{
-	return -EINVAL;
-}
-
 static int cardu_register_callback(unsigned int sock,
                                            void (*handler)(void *, unsigned int),
                                            void * info)
@@ -433,7 +428,6 @@ static void cardu_proc_setup(unsigned in
 
 static struct pccard_operations cardu_operations = {
 	.init			= cardu_init,
-	.suspend		= cardu_suspend,
 	.register_callback	= cardu_register_callback,
 	.inquire_socket		= cardu_inquire_socket,
 	.get_status		= cardu_get_status,
@@ -620,3 +614,4 @@ static void __devexit vrc4173_cardu_exit
 
 module_init(vrc4173_cardu_init);
 module_exit(vrc4173_cardu_exit);
+MODULE_DEVICE_TABLE(pci, vrc4173_cardu_id_table);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -506,8 +506,6 @@ static int yenta_sock_suspend(struct pcm
 {
 	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
 
-	yenta_set_socket(sock, &dead_socket);
-
 	/* Disable CSC interrupts */
 	cb_writel(socket, CB_SOCKET_MASK, 0x0);
 
@@ -963,7 +961,7 @@ static int __devinit yenta_probe (struct
 	 * the irq stuff...
 	 */
 	printk(KERN_INFO "Yenta: CardBus bridge found at %s [%04x:%04x]\n",
-		dev->slot_name, dev->subsystem_vendor, dev->subsystem_device);
+		pci_name(dev), dev->subsystem_vendor, dev->subsystem_device);
 
 	yenta_config_init(socket);
 
@@ -1019,7 +1017,7 @@ static int __devinit yenta_probe (struct
 }
 
 
-static int yenta_dev_suspend (struct pci_dev *dev, u32 state)
+static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state)
 {
 	struct yenta_socket *socket = pci_get_drvdata(dev);
 	int ret;
@@ -1105,6 +1103,7 @@ static struct pci_device_id yenta_table 
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4510, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX),
 
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250),
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -18,7 +18,7 @@
 #include "base.h"
 
 
-LIST_HEAD(pnp_protocols);
+static LIST_HEAD(pnp_protocols);
 LIST_HEAD(pnp_global);
 DEFINE_SPINLOCK(pnp_lock);
 
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -29,7 +29,7 @@ struct pnp_info_buffer {
 
 typedef struct pnp_info_buffer pnp_info_buffer_t;
 
-int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
+static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
 {
 	va_list args;
 	int res;
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -52,9 +52,9 @@
 #endif
 
 int isapnp_disable;			/* Disable ISA PnP */
-int isapnp_rdp;				/* Read Data Port */
-int isapnp_reset = 1;			/* reset all PnP cards (deactivate) */
-int isapnp_verbose = 1;			/* verbose mode */
+static int isapnp_rdp;			/* Read Data Port */
+static int isapnp_reset = 1;		/* reset all PnP cards (deactivate) */
+static int isapnp_verbose = 1;		/* verbose mode */
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Generic ISA Plug & Play support");
@@ -121,7 +121,7 @@ unsigned char isapnp_read_byte(unsigned 
 	return read_data();
 }
 
-unsigned short isapnp_read_word(unsigned char idx)
+static unsigned short isapnp_read_word(unsigned char idx)
 {
 	unsigned short val;
 
@@ -130,38 +130,19 @@ unsigned short isapnp_read_word(unsigned
 	return val;
 }
 
-unsigned int isapnp_read_dword(unsigned char idx)
-{
-	unsigned int val;
-
-	val = isapnp_read_byte(idx);
-	val = (val << 8) + isapnp_read_byte(idx+1);
-	val = (val << 8) + isapnp_read_byte(idx+2);
-	val = (val << 8) + isapnp_read_byte(idx+3);
-	return val;
-}
-
 void isapnp_write_byte(unsigned char idx, unsigned char val)
 {
 	write_address(idx);
 	write_data(val);
 }
 
-void isapnp_write_word(unsigned char idx, unsigned short val)
+static void isapnp_write_word(unsigned char idx, unsigned short val)
 {
 	isapnp_write_byte(idx, val >> 8);
 	isapnp_write_byte(idx+1, val);
 }
 
-void isapnp_write_dword(unsigned char idx, unsigned int val)
-{
-	isapnp_write_byte(idx, val >> 24);
-	isapnp_write_byte(idx+1, val >> 16);
-	isapnp_write_byte(idx+2, val >> 8);
-	isapnp_write_byte(idx+3, val);
-}
-
-void *isapnp_alloc(long size)
+static void *isapnp_alloc(long size)
 {
 	void *result;
 
@@ -196,24 +177,24 @@ static void isapnp_wait(void)
 	isapnp_write_byte(0x02, 0x02);
 }
 
-void isapnp_wake(unsigned char csn)
+static void isapnp_wake(unsigned char csn)
 {
 	isapnp_write_byte(0x03, csn);
 }
 
-void isapnp_device(unsigned char logdev)
+static void isapnp_device(unsigned char logdev)
 {
 	isapnp_write_byte(0x07, logdev);
 }
 
-void isapnp_activate(unsigned char logdev)
+static void isapnp_activate(unsigned char logdev)
 {
 	isapnp_device(logdev);
 	isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 1);
 	udelay(250);
 }
 
-void isapnp_deactivate(unsigned char logdev)
+static void isapnp_deactivate(unsigned char logdev)
 {
 	isapnp_device(logdev);
 	isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);
@@ -972,13 +953,7 @@ EXPORT_SYMBOL(isapnp_present);
 EXPORT_SYMBOL(isapnp_cfg_begin);
 EXPORT_SYMBOL(isapnp_cfg_end);
 EXPORT_SYMBOL(isapnp_read_byte);
-EXPORT_SYMBOL(isapnp_read_word);
-EXPORT_SYMBOL(isapnp_read_dword);
 EXPORT_SYMBOL(isapnp_write_byte);
-EXPORT_SYMBOL(isapnp_write_word);
-EXPORT_SYMBOL(isapnp_write_dword);
-EXPORT_SYMBOL(isapnp_wake);
-EXPORT_SYMBOL(isapnp_device);
 
 static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res)
 {
@@ -1070,7 +1045,7 @@ struct pnp_protocol isapnp_protocol = {
 	.disable = isapnp_disable_resources,
 };
 
-int __init isapnp_init(void)
+static int __init isapnp_init(void)
 {
 	int cards;
 	struct pnp_card *card;
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -253,7 +253,7 @@ void pnp_init_resource_table(struct pnp_
 
 /**
  * pnp_clean_resources - clears resources that were not manually set
- * @res - the resources to clean
+ * @res: the resources to clean
  *
  */
 static void pnp_clean_resource_table(struct pnp_resource_table * res)
@@ -296,7 +296,7 @@ static void pnp_clean_resource_table(str
  *
  * Only set depnum to 0 if the device does not have dependent options.
  */
-int pnp_assign_resources(struct pnp_dev *dev, int depnum)
+static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
 {
 	struct pnp_port *port;
 	struct pnp_mem *mem;
@@ -558,7 +558,6 @@ void pnp_resource_change(struct resource
 }
 
 
-EXPORT_SYMBOL(pnp_assign_resources);
 EXPORT_SYMBOL(pnp_manual_config_dev);
 EXPORT_SYMBOL(pnp_auto_config_dev);
 EXPORT_SYMBOL(pnp_activate_dev);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -94,8 +94,8 @@ static void
 pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
 {
 	int i = 0;
-	while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) &&
-			i < PNP_MAX_DMA)
+	while (i < PNP_MAX_DMA &&
+			!(res->dma_resource[i].flags & IORESOURCE_UNSET))
 		i++;
 	if (i < PNP_MAX_DMA) {
 		res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
@@ -219,9 +219,10 @@ static acpi_status pnpacpi_allocated_res
 		res->data.address64.min_address_range, 
 		res->data.address64.address_length);
 		break;
+	case ACPI_RSTYPE_VENDOR:
+		break;
 	default:
-		pnp_warn("PnPACPI: Alloc type : %d not handle", 
-				res->id);
+		pnp_warn("PnPACPI: unknown resource type %d", res->id);
 		return AE_ERROR;
 	}
 			
@@ -508,7 +509,7 @@ static acpi_status pnpacpi_option_resour
 		case ACPI_RSTYPE_END_DPF:
 			return AE_CTRL_TERMINATE;
 		default:
-			pnp_warn("PnPACPI:Option type: %d not handle", res->id);
+			pnp_warn("PnPACPI: unknown resource type %d", res->id);
 			return AE_ERROR;
 	}
 			
@@ -810,7 +811,7 @@ int pnpacpi_encode_resources(struct pnp_
 			mem ++;
 			break;
 		default: /* other type */
-			pnp_warn("Invalid type");
+			pnp_warn("unknown resource type %d", resource->id);
 			return -EINVAL;
 		}
 		resource ++;
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -12,7 +12,7 @@
  * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
  * Further modifications (C) 2001, 2002 by:
  *   Alan Cox <alan@redhat.com>
- *   Thomas Hood <jdthood@mail.com>
+ *   Thomas Hood
  *   Brian Gerst <bgerst@didntduck.org>
  *
  * Ported to the PnP Layer and several additional improvements (C) 2002
@@ -180,8 +180,12 @@ static int pnp_dock_thread(void * unused
 		 * Poll every 2 seconds
 		 */
 		msleep_interruptible(2000);
-		if(signal_pending(current))
+
+		if(signal_pending(current)) {
+			if (try_to_freeze(PF_FREEZE))
+				continue;
 			break;
+		}
 
 		status = pnp_bios_dock_station_info(&now);
 
@@ -454,7 +458,7 @@ __setup("pnpbios=", pnpbios_setup);
 /* PnP BIOS signature: "$PnP" */
 #define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
 
-int __init pnpbios_probe_system(void)
+static int __init pnpbios_probe_system(void)
 {
 	union pnp_bios_install_struct *check;
 	u8 sum;
@@ -508,7 +512,7 @@ static int __init exploding_pnp_bios(str
 	return 0;
 }
 
-static struct dmi_system_id pnpbios_dmi_table[] = {
+static struct dmi_system_id pnpbios_dmi_table[] __initdata = {
 	{	/* PnPBIOS GPF on boot */
 		.callback = exploding_pnp_bios,
 		.ident = "Higraded P14H",
@@ -530,7 +534,7 @@ static struct dmi_system_id pnpbios_dmi_
 	{ }
 };
 
-int __init pnpbios_init(void)
+static int __init pnpbios_init(void)
 {
 	int ret;
 
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -2,7 +2,7 @@
  * /proc/bus/pnp interface for Plug and Play devices
  *
  * Written by David Hinds, dahinds@users.sourceforge.net
- * Modified by Thomas Hood, jdthood@mail.com
+ * Modified by Thomas Hood
  *
  * The .../devices and .../<node> and .../boot/<node> files are
  * utilized by the lspnp and setpnp utilities, supplied with the
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -72,7 +72,9 @@ static void
 pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
 {
 	int i = 0;
-	while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_DMA) i++;
+	while (i < PNP_MAX_DMA &&
+			!(res->dma_resource[i].flags & IORESOURCE_UNSET))
+		i++;
 	if (i < PNP_MAX_DMA) {
 		res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
 		if (dma == -1) {
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -21,11 +21,10 @@
 #include <linux/pnp.h>
 #include "base.h"
 
-int pnp_skip_pci_scan;				/* skip PCI resource scanning */
-int pnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
-int pnp_reserve_dma[8] = { [0 ... 7] = -1 };	/* reserve (don't use) some DMA */
-int pnp_reserve_io[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
-int pnp_reserve_mem[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some memory region */
+static int pnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
+static int pnp_reserve_dma[8] = { [0 ... 7] = -1 };	/* reserve (don't use) some DMA */
+static int pnp_reserve_io[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
+static int pnp_reserve_mem[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some memory region */
 
 
 /*
@@ -385,9 +384,9 @@ int pnp_check_irq(struct pnp_dev * dev, 
 
 #ifdef CONFIG_PCI
 	/* check if the resource is being used by a pci device */
-	if (!pnp_skip_pci_scan) {
-		struct pci_dev * pci = NULL;
-		while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
+	{
+		struct pci_dev *pci = NULL;
+		for_each_pci_dev(pci) {
 			if (pci->irq == *irq)
 				return 0;
 		}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.156 $
+ * $Revision: 1.164 $
  */
 
 #include <linux/config.h>
@@ -757,6 +757,17 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
 		DBF_DEV_EVENT(DBF_ERR, device, "%s",
 			      "start_IO: request timeout, retry later");
 		break;
+	case -EACCES:
+		/* -EACCES indicates that the request used only a
+		 * subset of the available pathes and all these
+		 * pathes are gone.
+		 * Do a retry with all available pathes.
+		 */
+		cqr->lpm = LPM_ANYPATH;
+		DBF_DEV_EVENT(DBF_ERR, device, "%s",
+			      "start_IO: selected pathes gone,"
+			      " retry on all pathes");
+		break;
 	case -ENODEV:
 	case -EIO:
 		DBF_DEV_EVENT(DBF_ERR, device, "%s",
@@ -1120,13 +1131,17 @@ __dasd_process_blk_queue(struct dasd_dev
 	request_queue_t *queue;
 	struct request *req;
 	struct dasd_ccw_req *cqr;
-	int nr_queued;
+	int nr_queued, feature_ro;
 
 	queue = device->request_queue;
 	/* No queue ? Then there is nothing to do. */
 	if (queue == NULL)
 		return;
 
+	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
+	if (feature_ro < 0) 	/* no devmap */
+		return;
+
 	/*
 	 * We requeue request from the block device queue to the ccw
 	 * queue only in two states. In state DASD_STATE_READY the
@@ -1146,8 +1161,8 @@ __dasd_process_blk_queue(struct dasd_dev
 	       elv_next_request(queue) &&
 		nr_queued < DASD_CHANQ_MAX_SIZE) {
 		req = elv_next_request(queue);
-		if (test_bit(DASD_FLAG_RO, &device->flags) &&
-		    rq_data_dir(req) == WRITE) {
+
+		if (feature_ro && rq_data_dir(req) == WRITE) {
 			DBF_DEV_EVENT(DBF_ERR, device,
 				      "Rejecting write request %p",
 				      req);
@@ -1222,7 +1237,9 @@ __dasd_start_head(struct dasd_device * d
 		rc = device->discipline->start_IO(cqr);
 		if (rc == 0)
 			dasd_set_timer(device, cqr->expires);
-		else
+		else if (rc == -EACCES) {
+			dasd_schedule_bh(device);
+		} else
 			/* Hmpf, try again in 1/2 sec */
 			dasd_set_timer(device, 50);
 	}
@@ -1618,6 +1635,7 @@ dasd_setup_queue(struct dasd_device * de
 	blk_queue_max_hw_segments(device->request_queue, -1L);
 	blk_queue_max_segment_size(device->request_queue, -1L);
 	blk_queue_segment_boundary(device->request_queue, -1L);
+	blk_queue_ordered(device->request_queue, 1);
 }
 
 /*
@@ -1748,10 +1766,10 @@ dasd_generic_probe (struct ccw_device *c
 		printk(KERN_WARNING
 		       "dasd_generic_probe: could not add sysfs entries "
 		       "for %s\n", cdev->dev.bus_id);
+	} else {
+		cdev->handler = &dasd_int_handler;
 	}
 
-	cdev->handler = &dasd_int_handler;
-
 	return ret;
 }
 
@@ -1762,6 +1780,8 @@ dasd_generic_remove (struct ccw_device *
 {
 	struct dasd_device *device;
 
+	cdev->handler = NULL;
+
 	dasd_remove_sysfs_files(cdev);
 	device = dasd_device_from_cdev(cdev);
 	if (IS_ERR(device))
@@ -1790,13 +1810,17 @@ dasd_generic_set_online (struct ccw_devi
 
 {
 	struct dasd_device *device;
-	int rc;
+	int feature_diag, rc;
 
 	device = dasd_create_device(cdev);
 	if (IS_ERR(device))
 		return PTR_ERR(device);
 
-	if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) {
+	feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
+	if (feature_diag < 0)
+		return feature_diag;
+
+	if (feature_diag) {
 	  	if (!dasd_diag_discipline_pointer) {
 		        printk (KERN_WARNING
 				"dasd_generic couldn't online device %s "
@@ -1813,8 +1837,8 @@ dasd_generic_set_online (struct ccw_devi
 	if (rc) {
 		printk (KERN_WARNING
 			"dasd_generic couldn't online device %s "
-			"with discipline %s\n", 
-			cdev->dev.bus_id, discipline->name);
+			"with discipline %s rc=%i\n",
+			cdev->dev.bus_id, discipline->name, rc);
 		dasd_delete_device(device);
 		return rc;
 	}
diff --git a/drivers/s390/block/dasd_cmb.c b/drivers/s390/block/dasd_cmb.c
--- a/drivers/s390/block/dasd_cmb.c
+++ b/drivers/s390/block/dasd_cmb.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.6 $)
+ * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.9 $)
  *
  * Linux on zSeries Channel Measurement Facility support
  *  (dasd device driver interface)
@@ -23,7 +23,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include <linux/init.h>
-#include <linux/ioctl32.h>
 #include <linux/module.h>
 #include <asm/ccwdev.h>
 #include <asm/cmb.h>
@@ -84,27 +83,13 @@ dasd_ioctl_readall_cmb(struct block_devi
 static inline int
 ioctl_reg(unsigned int no, dasd_ioctl_fn_t handler)
 {
-	int ret;
-	ret = dasd_ioctl_no_register(THIS_MODULE, no, handler);
-#ifdef CONFIG_COMPAT
-	if (ret)
-		return ret;
-
-	ret = register_ioctl32_conversion(no, NULL);
-	if (ret)
-		dasd_ioctl_no_unregister(THIS_MODULE, no, handler);
-#endif
-	return ret;
+	return dasd_ioctl_no_register(THIS_MODULE, no, handler);
 }
 
 static inline void
 ioctl_unreg(unsigned int no, dasd_ioctl_fn_t handler)
 {
 	dasd_ioctl_no_unregister(THIS_MODULE, no, handler);
-#ifdef CONFIG_COMPAT
-	unregister_ioctl32_conversion(no);
-#endif
-
 }
 
 static void
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -11,7 +11,7 @@
  * functions may not be called from interrupt context. In particular
  * dasd_get_device is a no-no from interrupt context.
  *
- * $Revision: 1.37 $
+ * $Revision: 1.40 $
  */
 
 #include <linux/config.h>
@@ -513,14 +513,6 @@ dasd_create_device(struct ccw_device *cd
 	if (!devmap->device) {
 		devmap->device = device;
 		device->devindex = devmap->devindex;
-		if (devmap->features & DASD_FEATURE_READONLY)
-			set_bit(DASD_FLAG_RO, &device->flags);
-		else
-			clear_bit(DASD_FLAG_RO, &device->flags);
-		if (devmap->features & DASD_FEATURE_USEDIAG)
-			set_bit(DASD_FLAG_USE_DIAG, &device->flags);
-		else
-			clear_bit(DASD_FLAG_USE_DIAG, &device->flags);
 		get_device(&cdev->dev);
 		device->cdev = cdev;
 		rc = 0;
@@ -651,14 +643,8 @@ dasd_ro_store(struct device *dev, const 
 		devmap->features |= DASD_FEATURE_READONLY;
 	else
 		devmap->features &= ~DASD_FEATURE_READONLY;
-	if (devmap->device) {
-		if (devmap->device->gdp)
-			set_disk_ro(devmap->device->gdp, ro_flag);
-		if (ro_flag)
-			set_bit(DASD_FLAG_RO, &devmap->device->flags);
-		else
-			clear_bit(DASD_FLAG_RO, &devmap->device->flags);
-	}
+	if (devmap->device && devmap->device->gdp)
+		set_disk_ro(devmap->device->gdp, ro_flag);
 	spin_unlock(&dasd_devmap_lock);
 	return count;
 }
@@ -739,6 +725,45 @@ static struct attribute_group dasd_attr_
 	.attrs = dasd_attrs,
 };
 
+/*
+ * Return value of the specified feature.
+ */
+int
+dasd_get_feature(struct ccw_device *cdev, int feature)
+{
+	struct dasd_devmap *devmap;
+
+	devmap = dasd_find_busid(cdev->dev.bus_id);
+	if (IS_ERR(devmap))
+		return (int) PTR_ERR(devmap);
+
+	return ((devmap->features & feature) != 0);
+}
+
+/*
+ * Set / reset given feature.
+ * Flag indicates wether to set (!=0) or the reset (=0) the feature.
+ */
+int
+dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
+{
+	struct dasd_devmap *devmap;
+
+	devmap = dasd_find_busid(cdev->dev.bus_id);
+	if (IS_ERR(devmap))
+		return (int) PTR_ERR(devmap);
+
+	spin_lock(&dasd_devmap_lock);
+	if (flag)
+		devmap->features |= feature;
+	else
+		devmap->features &= ~feature;
+
+	spin_unlock(&dasd_devmap_lock);
+	return 0;
+}
+
+
 int
 dasd_add_sysfs_files(struct ccw_device *cdev)
 {
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.68 $
+ * $Revision: 1.71 $
  */
 
 #include <linux/config.h>
@@ -56,6 +56,7 @@ static struct dasd_discipline dasd_eckd_
 struct dasd_eckd_private {
 	struct dasd_eckd_characteristics rdc_data;
 	struct dasd_eckd_confdata conf_data;
+	struct dasd_eckd_path path_data;
 	struct eckd_count count_area[5];
 	int init_cqr_status;
 	int uses_cdl;
@@ -447,12 +448,72 @@ dasd_eckd_cdl_reclen(int recid)
 }
 
 static int
+dasd_eckd_read_conf(struct dasd_device *device)
+{
+	void *conf_data;
+	int conf_len, conf_data_saved;
+	int rc;
+	__u8 lpm;
+	struct dasd_eckd_private *private;
+	struct dasd_eckd_path *path_data;
+
+	private = (struct dasd_eckd_private *) device->private;
+	path_data = (struct dasd_eckd_path *) &private->path_data;
+	path_data->opm = ccw_device_get_path_mask(device->cdev);
+	lpm = 0x80;
+	conf_data_saved = 0;
+
+	/* get configuration data per operational path */
+	for (lpm = 0x80; lpm; lpm>>= 1) {
+		if (lpm & path_data->opm){
+			rc = read_conf_data_lpm(device->cdev, &conf_data,
+						&conf_len, lpm);
+			if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
+				MESSAGE(KERN_WARNING,
+					"Read configuration data returned "
+					"error %d", rc);
+				return rc;
+			}
+			if (conf_data == NULL) {
+				MESSAGE(KERN_WARNING, "%s", "No configuration "
+					"data retrieved");
+				continue;	/* no errror */
+			}
+			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+				MESSAGE(KERN_WARNING,
+					"sizes of configuration data mismatch"
+					"%d (read) vs %ld (expected)",
+					conf_len,
+					sizeof (struct dasd_eckd_confdata));
+				kfree(conf_data);
+				continue;	/* no errror */
+			}
+			/* save first valid configuration data */
+			if (!conf_data_saved){
+				memcpy(&private->conf_data, conf_data,
+				       sizeof (struct dasd_eckd_confdata));
+				conf_data_saved++;
+			}
+			switch (((char *)conf_data)[242] & 0x07){
+			case 0x02:
+				path_data->npm |= lpm;
+				break;
+			case 0x03:
+				path_data->ppm |= lpm;
+				break;
+			}
+			kfree(conf_data);
+		}
+	}
+	return 0;
+}
+
+
+static int
 dasd_eckd_check_characteristics(struct dasd_device *device)
 {
 	struct dasd_eckd_private *private;
 	void *rdc_data;
-	void *conf_data;
-	int conf_len;
 	int rc;
 
 	private = (struct dasd_eckd_private *) device->private;
@@ -465,6 +526,7 @@ dasd_eckd_check_characteristics(struct d
 				    "data");
 			return -ENOMEM;
 		}
+		memset(private, 0, sizeof(struct dasd_eckd_private));
 		device->private = (void *) private;
 	}
 	/* Invalidate status of initial analysis. */
@@ -494,30 +556,9 @@ dasd_eckd_check_characteristics(struct d
 		    private->rdc_data.sec_per_trk);
 
 	/* Read Configuration Data */
-	rc = read_conf_data(device->cdev, &conf_data, &conf_len);
-	if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
-		DEV_MESSAGE(KERN_WARNING, device,
-			    "Read configuration data returned error %d", rc);
-		return rc;
-	}
-	if (conf_data == NULL) {
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
-			    "No configuration data retrieved");
-		return 0;	/* no errror */
-	}
-	if (conf_len != sizeof (struct dasd_eckd_confdata)) {
-		DEV_MESSAGE(KERN_WARNING, device,
-			    "sizes of configuration data mismatch"
-			    "%d (read) vs %ld (expected)",
-			    conf_len, sizeof (struct dasd_eckd_confdata));
+	rc = dasd_eckd_read_conf (device);
+	return rc;
 
-		kfree(conf_data); /* allocated by read_conf_data() */
-		return 0;	/* no errror */
-	}
-	memcpy(&private->conf_data, conf_data,
-	       sizeof (struct dasd_eckd_confdata));
-	kfree(conf_data); /* allocated by read_conf_data() */
-	return 0;
 }
 
 static struct dasd_ccw_req *
@@ -1060,7 +1101,8 @@ dasd_eckd_build_cp(struct dasd_device * 
 				if (dasd_eckd_cdl_special(blk_per_trk, recid)){
 					rcmd |= 0x8;
 					count = dasd_eckd_cdl_reclen(recid);
-					if (count < blksize)
+					if (count < blksize &&
+					    rq_data_dir(req) == READ)
 						memset(dst + count, 0xe5,
 						       blksize - count);
 				}
@@ -1096,7 +1138,7 @@ dasd_eckd_build_cp(struct dasd_device * 
 	}
 	cqr->device = device;
 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
-	cqr->lpm = LPM_ANYPATH;
+	cqr->lpm = private->path_data.ppm;
 	cqr->retries = 256;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -5,7 +5,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.9 $
+ * $Revision: 1.10 $
  */
 
 #ifndef DASD_ECKD_H
@@ -326,6 +326,12 @@ struct dasd_eckd_confdata {
 	} __attribute__ ((packed)) neq;
 } __attribute__ ((packed));
 
+struct dasd_eckd_path {
+	__u8 opm;
+	__u8 ppm;
+	__u8 npm;
+};
+
 /*
  * Perform Subsystem Function - Prepare for Read Subsystem Data	 
  */
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.13 $
+ * $Revision: 1.14 $
  */
 
 #include <linux/config.h>
@@ -95,6 +95,7 @@ dasd_default_erp_action(struct dasd_ccw_
                 DEV_MESSAGE (KERN_DEBUG, device, 
                              "default ERP called (%i retries left)",
                              cqr->retries);
+		cqr->lpm    = LPM_ANYPATH;
 		cqr->status = DASD_CQR_QUEUED;
         } else {
                 DEV_MESSAGE (KERN_WARNING, device, "%s",
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.48 $
+ * $Revision: 1.50 $
  */
 
 #include <linux/config.h>
@@ -31,12 +31,16 @@ int
 dasd_gendisk_alloc(struct dasd_device *device)
 {
 	struct gendisk *gdp;
-	int len;
+	int len, feature_ro;
 
 	/* Make sure the minor for this device exists. */
 	if (device->devindex >= DASD_PER_MAJOR)
 		return -EBUSY;
 
+	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
+	if (feature_ro < 0)
+		return feature_ro;
+
 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
 	if (!gdp)
 		return -ENOMEM;
@@ -71,7 +75,7 @@ dasd_gendisk_alloc(struct dasd_device *d
 
  	sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
 
-	if (test_bit(DASD_FLAG_RO, &device->flags))
+	if (feature_ro)
 		set_disk_ro(gdp, 1);
 	gdp->private_data = device;
 	gdp->queue = device->request_queue;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.63 $
+ * $Revision: 1.64 $
  */
 
 #ifndef DASD_INT_H
@@ -329,8 +329,6 @@ struct dasd_device {
 #define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
 
 /* per device flags */
-#define DASD_FLAG_RO		0	/* device is read-only */
-#define DASD_FLAG_USE_DIAG	1	/* use diag disciplnie */
 #define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
 #define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
 
@@ -501,6 +499,9 @@ void dasd_devmap_exit(void);
 struct dasd_device *dasd_create_device(struct ccw_device *);
 void dasd_delete_device(struct dasd_device *);
 
+int dasd_get_feature(struct ccw_device *, int);
+int dasd_set_feature(struct ccw_device *, int, int);
+
 int dasd_add_sysfs_files(struct ccw_device *);
 void dasd_remove_sysfs_files(struct ccw_device *);
 
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -7,6 +7,8 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
+ * $Revision: 1.45 $
+ *
  * i/o controls for the dasd driver.
  */
 #include <linux/config.h>
@@ -294,6 +296,7 @@ dasd_ioctl_format(struct block_device *b
 {
 	struct dasd_device *device;
 	struct format_data_t fdata;
+	int feature_ro;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -304,7 +307,11 @@ dasd_ioctl_format(struct block_device *b
 
 	if (device == NULL)
 		return -ENODEV;
-	if (test_bit(DASD_FLAG_RO, &device->flags))
+
+	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
+	if (feature_ro < 0)
+		return feature_ro;
+	if (feature_ro)
 		return -EROFS;
 	if (copy_from_user(&fdata, (void __user *) args,
 			   sizeof (struct format_data_t)))
@@ -377,7 +384,7 @@ dasd_ioctl_information(struct block_devi
 	struct dasd_device *device;
 	struct dasd_information2_t *dasd_info;
 	unsigned long flags;
-	int rc;
+	int rc, feature_ro;
 	struct ccw_device *cdev;
 
 	device = bdev->bd_disk->private_data;
@@ -387,6 +394,10 @@ dasd_ioctl_information(struct block_devi
 	if (!device->discipline->fill_info)
 		return -EINVAL;
 
+	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
+	if (feature_ro < 0)
+		return feature_ro;
+
 	dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
 	if (dasd_info == NULL)
 		return -ENOMEM;
@@ -415,9 +426,8 @@ dasd_ioctl_information(struct block_devi
 	if ((device->state < DASD_STATE_READY) ||
 	    (dasd_check_blocksize(device->bp_block)))
 		dasd_info->format = DASD_FORMAT_NONE;
-	
-	dasd_info->features |= test_bit(DASD_FLAG_RO, &device->flags) ?
-		DASD_FEATURE_READONLY : DASD_FEATURE_DEFAULT;
+
+	dasd_info->features |= feature_ro;
 
 	if (device->discipline)
 		memcpy(dasd_info->type, device->discipline->name, 4);
@@ -460,7 +470,7 @@ static int
 dasd_ioctl_set_ro(struct block_device *bdev, int no, long args)
 {
 	struct dasd_device *device;
-	int intval;
+	int intval, rc;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -472,12 +482,11 @@ dasd_ioctl_set_ro(struct block_device *b
 	device =  bdev->bd_disk->private_data;
 	if (device == NULL)
 		return -ENODEV;
+
 	set_disk_ro(bdev->bd_disk, intval);
-	if (intval)
-		set_bit(DASD_FLAG_RO, &device->flags);
-	else
-		clear_bit(DASD_FLAG_RO, &device->flags);
-	return 0;
+	rc = dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
+
+	return rc;
 }
 
 /*
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -9,7 +9,7 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.30 $
+ * $Revision: 1.31 $
  */
 
 #include <linux/config.h>
@@ -54,6 +54,7 @@ dasd_devices_show(struct seq_file *m, vo
 {
 	struct dasd_device *device;
 	char *substr;
+	int feature;
 
 	device = dasd_device_from_devindex((unsigned long) v - 1);
 	if (IS_ERR(device))
@@ -77,7 +78,10 @@ dasd_devices_show(struct seq_file *m, vo
 	else
 		seq_printf(m, " is ????????");
 	/* Print devices features. */
-	substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " ";
+	feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
+	if (feature < 0)
+		return 0;
+	substr = feature ? "(ro)" : " ";
 	seq_printf(m, "%4s: ", substr);
 	/* Print device status information. */
 	switch ((device != NULL) ? device->state : -1) {
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -32,11 +32,11 @@ static k_handler_fn K_HANDLERS;
 static k_handler_fn *k_handler[16] = { K_HANDLERS };
 
 /* maximum values each key_handler can handle */
-static const int max_vals[] = {
+static const int kbd_max_vals[] = {
 	255, ARRAY_SIZE(func_table) - 1, NR_FN_HANDLER - 1, 0,
 	NR_DEAD - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-static const int NR_TYPES = ARRAY_SIZE(max_vals);
+static const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals);
 
 static unsigned char ret_diacr[NR_DEAD] = {
 	'`', '\'', '^', '~', '"', ','
@@ -360,7 +360,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, stru
 		key_map = kbd->key_maps[tmp.kb_table];
 		if (key_map) {
 		    val = U(key_map[tmp.kb_index]);
-		    if (KTYP(val) >= NR_TYPES)
+		    if (KTYP(val) >= KBD_NR_TYPES)
 			val = K_HOLE;
 		} else
 		    val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP);
@@ -378,9 +378,9 @@ do_kdsk_ioctl(struct kbd_data *kbd, stru
 			break;
 		}
 
-		if (KTYP(tmp.kb_value) >= NR_TYPES)
+		if (KTYP(tmp.kb_value) >= KBD_NR_TYPES)
 			return -EINVAL;
-		if (KVAL(tmp.kb_value) > max_vals[KTYP(tmp.kb_value)])
+		if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)])
 			return -EINVAL;
 
 		if (!(key_map = kbd->key_maps[tmp.kb_table])) {
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -30,31 +30,16 @@ do_load_quiesce_psw(void * __unused)
 {
 	static atomic_t cpuid = ATOMIC_INIT(-1);
 	psw_t quiesce_psw;
-	__u32 status;
-	int i;
+	int cpu;
 
 	if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
 		signal_processor(smp_processor_id(), sigp_stop);
 	/* Wait for all other cpus to enter stopped state */
-	i = 1;
-	while (i < NR_CPUS) {
-		if (!cpu_online(i)) {
-			i++;
+	for_each_online_cpu(cpu) {
+		if (cpu == smp_processor_id())
 			continue;
-		}
-		switch (signal_processor_ps(&status, 0, i, sigp_sense)) {
-		case sigp_order_code_accepted:
-		case sigp_status_stored:
-			/* Check for stopped and check stop state */
-			if (status & 0x50)
-				i++;
-			break;
-		case sigp_busy:
-			break;
-		case sigp_not_operational:
-			i++;
-			break;
-		}
+		while(!smp_cpu_not_running(cpu))
+			cpu_relax();
 	}
 	/* Quiesce the last cpu with the special psw */
 	quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT;
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -45,7 +45,7 @@ s390_register_adapter_interrupt (adapter
 	else
 		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
 	if (!ret)
-		synchronize_kernel();
+		synchronize_sched();  /* Allow interrupts to complete. */
 
 	sprintf (dbf_txt, "ret:%d", ret);
 	CIO_TRACE_EVENT (4, dbf_txt);
@@ -65,7 +65,7 @@ s390_unregister_adapter_interrupt (adapt
 		ret = -EINVAL;
 	else {
 		adapter_handler = NULL;
-		synchronize_kernel();
+		synchronize_sched();  /* Allow interrupts to complete. */
 		ret = 0;
 	}
 	sprintf (dbf_txt, "ret:%d", ret);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.115 $
+ *   $Revision: 1.119 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -423,12 +423,12 @@ s390_process_res_acc (u8 chpid, __u16 fl
 			     sch->schib.pmcw.pam &
 			     sch->schib.pmcw.pom)
 			    | chp_mask) & sch->opm;
-		spin_unlock_irq(&sch->lock);
 		if (!old_lpm && sch->lpm)
 			device_trigger_reprobe(sch);
 		else if (sch->driver && sch->driver->verify)
 			sch->driver->verify(&sch->dev);
 
+		spin_unlock_irq(&sch->lock);
 		put_device(&sch->dev);
 		if (fla_mask != 0)
 			break;
@@ -703,6 +703,9 @@ __check_for_io_and_kill(struct subchanne
 {
 	int cc;
 
+	if (!device_is_online(sch))
+		/* cio could be doing I/O. */
+		return 0;
 	cc = stsch(sch->irq, &sch->schib);
 	if (cc)
 		return 0;
@@ -717,10 +720,12 @@ static inline void
 __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
 {
 	int chp, old_lpm;
+	unsigned long flags;
 
 	if (!sch->ssd_info.valid)
 		return;
 	
+	spin_lock_irqsave(&sch->lock, flags);
 	old_lpm = sch->lpm;
 	for (chp = 0; chp < 8; chp++) {
 		if (sch->ssd_info.chpid[chp] != chpid)
@@ -751,6 +756,7 @@ __s390_subchannel_vary_chpid(struct subc
 		}
 		break;
 	}
+	spin_unlock_irqrestore(&sch->lock, flags);
 }
 
 static int
@@ -881,6 +887,27 @@ chp_status_write(struct device *dev, con
 
 static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
 
+static ssize_t
+chp_type_show(struct device *dev, char *buf)
+{
+	struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+	if (!chp)
+		return 0;
+	return sprintf(buf, "%x\n", chp->desc.desc);
+}
+
+static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
+
+static struct attribute * chp_attrs[] = {
+	&dev_attr_status.attr,
+	&dev_attr_type.attr,
+	NULL,
+};
+
+static struct attribute_group chp_attr_group = {
+	.attrs = chp_attrs,
+};
 
 static void
 chp_release(struct device *dev)
@@ -891,6 +918,68 @@ chp_release(struct device *dev)
 	kfree(cp);
 }
 
+static int
+chsc_determine_channel_path_description(int chpid,
+					struct channel_path_desc *desc)
+{
+	int ccode, ret;
+
+	struct {
+		struct chsc_header request;
+		u32 : 24;
+		u32 first_chpid : 8;
+		u32 : 24;
+		u32 last_chpid : 8;
+		u32 zeroes1;
+		struct chsc_header response;
+		u32 zeroes2;
+		struct channel_path_desc desc;
+	} *scpd_area;
+
+	scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!scpd_area)
+		return -ENOMEM;
+
+	scpd_area->request = (struct chsc_header) {
+		.length = 0x0010,
+		.code   = 0x0002,
+	};
+
+	scpd_area->first_chpid = chpid;
+	scpd_area->last_chpid = chpid;
+
+	ccode = chsc(scpd_area);
+	if (ccode > 0) {
+		ret = (ccode == 3) ? -ENODEV : -EBUSY;
+		goto out;
+	}
+
+	switch (scpd_area->response.code) {
+	case 0x0001: /* Success. */
+		memcpy(desc, &scpd_area->desc,
+		       sizeof(struct channel_path_desc));
+		ret = 0;
+		break;
+	case 0x0003: /* Invalid block. */
+	case 0x0007: /* Invalid format. */
+	case 0x0008: /* Other invalid block. */
+		CIO_CRW_EVENT(2, "Error in chsc request block!\n");
+		ret = -EINVAL;
+		break;
+	case 0x0004: /* Command not provided in model. */
+		CIO_CRW_EVENT(2, "Model does not provide scpd\n");
+		ret = -EOPNOTSUPP;
+		break;
+	default:
+		CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+			      scpd_area->response.code);
+		ret = -EIO;
+	}
+out:
+	free_page((unsigned long)scpd_area);
+	return ret;
+}
+
 /*
  * Entries for chpids on the system bus.
  * This replaces /proc/chpids.
@@ -915,6 +1004,11 @@ new_channel_path(int chpid)
 	};
 	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
 
+	/* Obtain channel path description and fill it in. */
+	ret = chsc_determine_channel_path_description(chpid, &chp->desc);
+	if (ret)
+		goto out_free;
+
 	/* make it known to the system */
 	ret = device_register(&chp->dev);
 	if (ret) {
@@ -922,7 +1016,7 @@ new_channel_path(int chpid)
 		       __func__, chpid);
 		goto out_free;
 	}
-	ret = device_create_file(&chp->dev, &dev_attr_status);
+	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
 	if (ret) {
 		device_unregister(&chp->dev);
 		goto out_free;
@@ -934,6 +1028,23 @@ out_free:
 	return ret;
 }
 
+void *
+chsc_get_chp_desc(struct subchannel *sch, int chp_no)
+{
+	struct channel_path *chp;
+	struct channel_path_desc *desc;
+
+	chp = chps[sch->schib.pmcw.chpid[chp_no]];
+	if (!chp)
+		return NULL;
+	desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
+	if (!desc)
+		return NULL;
+	memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+	return desc;
+}
+
+
 static int __init
 chsc_alloc_sei_area(void)
 {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -12,14 +12,24 @@ struct chsc_header {
 	u16 code;
 };
 
+struct channel_path_desc {
+	u8 flags;
+	u8 lsn;
+	u8 desc;
+	u8 chpid;
+	u8 swla;
+	u8 zeroes;
+	u8 chla;
+	u8 chpp;
+};
+
 struct channel_path {
 	int id;
 	int state;
+	struct channel_path_desc desc;
 	struct device dev;
 };
 
-extern struct channel_path *chps[];
-
 extern void s390_process_css( void );
 extern void chsc_validate_chpids(struct subchannel *);
 extern void chpid_is_actually_online(int);
@@ -51,4 +61,6 @@ extern struct css_chsc_char css_chsc_cha
 
 extern int chsc_determine_css_characteristics(void);
 extern int css_characteristics_avail;
+
+extern void *chsc_get_chp_desc(struct subchannel*, int);
 #endif
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.130 $
+ *   $Revision: 1.133 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -228,7 +228,7 @@ cio_start_key (struct subchannel *sch,	/
 int
 cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm)
 {
-	return cio_start_key(sch, cpa, lpm, default_storage_key);
+	return cio_start_key(sch, cpa, lpm, PAGE_DEFAULT_KEY);
 }
 
 /*
@@ -608,6 +608,10 @@ do_IRQ (struct pt_regs *regs)
 	irq_enter ();
 	asm volatile ("mc 0,0");
 	if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+		/**
+		 * Make sure that the i/o interrupt did not "overtake"
+		 * the last HZ timer interrupt.
+		 */
 		account_ticks(regs);
 	/*
 	 * Get interrupt information from lowcore
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.84 $
+ *   $Revision: 1.85 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -180,6 +180,7 @@ css_evaluate_subchannel(int irq, int slo
 {
 	int event, ret, disc;
 	struct subchannel *sch;
+	unsigned long flags;
 
 	sch = get_subchannel_by_schid(irq);
 	disc = sch ? device_is_disconnected(sch) : 0;
@@ -221,7 +222,9 @@ css_evaluate_subchannel(int irq, int slo
 			 * coming operational again. It won't do harm in real
 			 * no path situations.
 			 */
+			spin_lock_irqsave(&sch->lock, flags);
 			device_trigger_reprobe(sch);
+			spin_unlock_irqrestore(&sch->lock, flags);
 			ret = 0;
 			break;
 		}
@@ -262,14 +265,19 @@ css_evaluate_subchannel(int irq, int slo
 			 * We can't immediately deregister the disconnected
 			 * device since it might block.
 			 */
+			spin_lock_irqsave(&sch->lock, flags);
 			device_trigger_reprobe(sch);
+			spin_unlock_irqrestore(&sch->lock, flags);
 			ret = 0;
 		}
 		break;
 	case CIO_OPER:
-		if (disc)
+		if (disc) {
+			spin_lock_irqsave(&sch->lock, flags);
 			/* Get device operational again. */
 			device_trigger_reprobe(sch);
+			spin_unlock_irqrestore(&sch->lock, flags);
+		}
 		ret = sch ? 0 : css_probe_device(irq);
 		break;
 	default:
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -84,6 +84,7 @@ struct ccw_device_private {
 		unsigned int doverify:1;    /* delayed path verification */
 		unsigned int donotify:1;    /* call notify function */
 		unsigned int recog_done:1;  /* dev. recog. complete */
+		unsigned int fake_irb:1;    /* deliver faked irb */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;
@@ -136,6 +137,7 @@ void device_set_disconnected(struct subc
 void device_trigger_reprobe(struct subchannel *);
 
 /* Helper functions for vary on/off. */
+int device_is_online(struct subchannel *);
 void device_set_waiting(struct subchannel *);
 
 /* Machine check helper function. */
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.129 $
+ *   $Revision: 1.131 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -293,6 +293,14 @@ ccw_device_set_offline(struct ccw_device
 	cdev->online = 0;
 	spin_lock_irq(cdev->ccwlock);
 	ret = ccw_device_offline(cdev);
+	if (ret == -ENODEV) {
+		if (cdev->private->state != DEV_STATE_NOT_OPER) {
+			cdev->private->state = DEV_STATE_OFFLINE;
+			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+		}
+		spin_unlock_irq(cdev->ccwlock);
+		return ret;
+	}
 	spin_unlock_irq(cdev->ccwlock);
 	if (ret == 0)
 		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -24,6 +24,17 @@
 #include "qdio.h"
 
 int
+device_is_online(struct subchannel *sch)
+{
+	struct ccw_device *cdev;
+
+	if (!sch->dev.driver_data)
+		return 0;
+	cdev = sch->dev.driver_data;
+	return (cdev->private->state == DEV_STATE_ONLINE);
+}
+
+int
 device_is_disconnected(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
@@ -44,6 +55,7 @@ device_set_disconnected(struct subchanne
 		return;
 	cdev = sch->dev.driver_data;
 	ccw_device_set_timeout(cdev, 0);
+	cdev->private->flags.fake_irb = 0;
 	cdev->private->state = DEV_STATE_DISCONNECTED;
 }
 
@@ -474,6 +486,7 @@ ccw_device_nopath_notify(void *data)
 	} else {
 		cio_disable_subchannel(sch);
 		ccw_device_set_timeout(cdev, 0);
+		cdev->private->flags.fake_irb = 0;
 		cdev->private->state = DEV_STATE_DISCONNECTED;
 		wake_up(&cdev->private->wait_q);
 	}
@@ -488,6 +501,21 @@ ccw_device_verify_done(struct ccw_device
 		cdev->private->options.pgroup = 0;
 	case 0:
 		ccw_device_done(cdev, DEV_STATE_ONLINE);
+		/* Deliver fake irb to device driver, if needed. */
+		if (cdev->private->flags.fake_irb) {
+			memset(&cdev->private->irb, 0, sizeof(struct irb));
+			cdev->private->irb.scsw = (struct scsw) {
+				.cc = 1,
+				.fctl = SCSW_FCTL_START_FUNC,
+				.actl = SCSW_ACTL_START_PEND,
+				.stctl = SCSW_STCTL_STATUS_PEND,
+			};
+			cdev->private->flags.fake_irb = 0;
+			if (cdev->handler)
+				cdev->handler(cdev, cdev->private->intparm,
+					      &cdev->private->irb);
+			memset(&cdev->private->irb, 0, sizeof(struct irb));
+		}
 		break;
 	case -ETIME:
 		ccw_device_done(cdev, DEV_STATE_BOXED);
@@ -560,6 +588,8 @@ ccw_device_offline(struct ccw_device *cd
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
+	if (stsch(sch->irq, &sch->schib) || !sch->schib.pmcw.dnv)
+		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE) {
 		if (sch->schib.scsw.actl != 0)
 			return -EBUSY;
@@ -619,9 +649,11 @@ ccw_device_offline_notoper(struct ccw_de
 
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	sch = to_subchannel(cdev->dev.parent);
-	device_unregister(&sch->dev);
-	sch->schib.pmcw.intparm = 0;
-	cio_modify(sch);
+	if (get_device(&cdev->dev)) {
+		PREPARE_WORK(&cdev->private->kick_work,
+			     ccw_device_call_sch_unregister, (void *)cdev);
+		queue_work(ccw_device_work, &cdev->private->kick_work);
+	}
 	wake_up(&cdev->private->wait_q);
 }
 
@@ -637,6 +669,7 @@ ccw_device_online_notoper(struct ccw_dev
 	if (sch->driver->notify &&
 	    sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {
 			ccw_device_set_timeout(cdev, 0);
+			cdev->private->flags.fake_irb = 0;
 			cdev->private->state = DEV_STATE_DISCONNECTED;
 			wake_up(&cdev->private->wait_q);
 			return;
@@ -647,9 +680,11 @@ ccw_device_online_notoper(struct ccw_dev
 		// FIXME: not-oper indication to device driver ?
 		ccw_device_call_handler(cdev);
 	}
-	device_unregister(&sch->dev);
-	sch->schib.pmcw.intparm = 0;
-	cio_modify(sch);
+	if (get_device(&cdev->dev)) {
+		PREPARE_WORK(&cdev->private->kick_work,
+			     ccw_device_call_sch_unregister, (void *)cdev);
+		queue_work(ccw_device_work, &cdev->private->kick_work);
+	}
 	wake_up(&cdev->private->wait_q);
 }
 
@@ -668,6 +703,12 @@ ccw_device_online_verify(struct ccw_devi
 		return;
 	}
 	sch = to_subchannel(cdev->dev.parent);
+	/*
+	 * Since we might not just be coming from an interrupt from the
+	 * subchannel we have to update the schib.
+	 */
+	stsch(sch->irq, &sch->schib);
+
 	if (sch->schib.scsw.actl != 0 ||
 	    (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
 		/*
@@ -982,21 +1023,17 @@ void
 device_trigger_reprobe(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
-	unsigned long flags;
 
 	if (!sch->dev.driver_data)
 		return;
 	cdev = sch->dev.driver_data;
-	spin_lock_irqsave(&sch->lock, flags);
-	if (cdev->private->state != DEV_STATE_DISCONNECTED) {
-		spin_unlock_irqrestore(&sch->lock, flags);
+	if (cdev->private->state != DEV_STATE_DISCONNECTED)
 		return;
-	}
+
 	/* Update some values. */
-	if (stsch(sch->irq, &sch->schib)) {
-		spin_unlock_irqrestore(&sch->lock, flags);
+	if (stsch(sch->irq, &sch->schib))
 		return;
-	}
+
 	/*
 	 * The pim, pam, pom values may not be accurate, but they are the best
 	 * we have before performing device selection :/
@@ -1014,7 +1051,6 @@ device_trigger_reprobe(struct subchannel
 	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
 	/* We should also udate ssd info, but this has to wait. */
 	ccw_device_start_id(cdev, 0);
-	spin_unlock_irqrestore(&sch->lock, flags);
 }
 
 static void
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -316,6 +316,7 @@ ccw_device_sense_id_irq(struct ccw_devic
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
 		return;
 	ret = ccw_device_check_sense_id(cdev);
+	memset(&cdev->private->irb, 0, sizeof(struct irb));
 	switch (ret) {
 	/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN or -EACCES */
 	case 0:			/* Sense id succeeded. */
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.53 $
+ *   $Revision: 1.56 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -24,6 +24,7 @@
 #include "cio.h"
 #include "cio_debug.h"
 #include "css.h"
+#include "chsc.h"
 #include "device.h"
 #include "qdio.h"
 
@@ -81,6 +82,16 @@ ccw_device_start_key(struct ccw_device *
 		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
+	if (cdev->private->state == DEV_STATE_VERIFY) {
+		/* Remember to fake irb when finished. */
+		if (!cdev->private->flags.fake_irb) {
+			cdev->private->flags.fake_irb = 1;
+			cdev->private->intparm = intparm;
+			return 0;
+		} else
+			/* There's already a fake I/O around. */
+			return -EBUSY;
+	}
 	if (cdev->private->state != DEV_STATE_ONLINE ||
 	    ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
 	     !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
@@ -117,7 +128,7 @@ ccw_device_start(struct ccw_device *cdev
 		 unsigned long intparm, __u8 lpm, unsigned long flags)
 {
 	return ccw_device_start_key(cdev, cpa, intparm, lpm,
-				    default_storage_key, flags);
+				    PAGE_DEFAULT_KEY, flags);
 }
 
 int
@@ -126,7 +137,7 @@ ccw_device_start_timeout(struct ccw_devi
 			 int expires)
 {
 	return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
-					    default_storage_key, flags,
+					    PAGE_DEFAULT_KEY, flags,
 					    expires);
 }
 
@@ -281,14 +292,14 @@ ccw_device_wake_up(struct ccw_device *cd
 }
 
 static inline int
-__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic)
+__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
 {
 	int ret;
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
 	do {
-		ret = cio_start (sch, ccw, 0);
+		ret = cio_start (sch, ccw, lpm);
 		if ((ret == -EBUSY) || (ret == -EACCES)) {
 			/* Try again later. */
 			spin_unlock_irq(&sch->lock);
@@ -378,7 +389,7 @@ read_dev_chars (struct ccw_device *cdev,
 		ret = -EBUSY;
 	else
 		/* 0x00D9C4C3 == ebcdic "RDC" */
-		ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3);
+		ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, 0);
 
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
@@ -391,10 +402,10 @@ read_dev_chars (struct ccw_device *cdev,
 }
 
 /*
- *  Read Configuration data
+ *  Read Configuration data using path mask
  */
 int
-read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
+read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lpm)
 {
 	void (*handler)(struct ccw_device *, unsigned long, struct irb *);
 	struct subchannel *sch;
@@ -447,7 +458,7 @@ read_conf_data (struct ccw_device *cdev,
 		ret = -EBUSY;
 	else
 		/* 0x00D9C3C4 == ebcdic "RCD" */
-		ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4);
+		ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, lpm);
 
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
@@ -470,6 +481,15 @@ read_conf_data (struct ccw_device *cdev,
 }
 
 /*
+ *  Read Configuration data
+ */
+int
+read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
+{
+	return read_conf_data_lpm (cdev, buffer, length, 0);
+}
+
+/*
  * Try to break the lock on a boxed device.
  */
 int
@@ -540,6 +560,15 @@ out_unlock:
 	return ret;
 }
 
+void *
+ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+{
+	struct subchannel *sch;
+
+	sch = to_subchannel(cdev->dev.parent);
+	return chsc_get_chp_desc(sch, chp_no);
+}
+
 // FIXME: these have to go:
 
 int
@@ -570,3 +599,5 @@ EXPORT_SYMBOL(read_conf_data);
 EXPORT_SYMBOL(read_dev_chars);
 EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
 EXPORT_SYMBOL(_ccw_device_get_device_number);
+EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
+EXPORT_SYMBOL_GPL(read_conf_data_lpm);
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -156,7 +156,9 @@ ccw_device_sense_pgid_irq(struct ccw_dev
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
 		return;
 	sch = to_subchannel(cdev->dev.parent);
-	switch (__ccw_device_check_sense_pgid(cdev)) {
+	ret = __ccw_device_check_sense_pgid(cdev);
+	memset(&cdev->private->irb, 0, sizeof(struct irb));
+	switch (ret) {
 	/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
 	case 0:			/* Sense Path Group ID successful. */
 		if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
@@ -307,6 +309,7 @@ ccw_device_verify_irq(struct ccw_device 
 {
 	struct subchannel *sch;
 	struct irb *irb;
+	int ret;
 
 	irb = (struct irb *) __LC_IRB;
 	/* Retry set pgid for cc=1. */
@@ -319,7 +322,9 @@ ccw_device_verify_irq(struct ccw_device 
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
 		return;
 	sch = to_subchannel(cdev->dev.parent);
-	switch (__ccw_device_check_pgid(cdev)) {
+	ret = __ccw_device_check_pgid(cdev);
+	memset(&cdev->private->irb, 0, sizeof(struct irb));
+	switch (ret) {
 	/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
 	case 0:
 		/* Establish or Resign Path Group done. Update vpm. */
@@ -405,6 +410,7 @@ ccw_device_disband_irq(struct ccw_device
 		return;
 	sch = to_subchannel(cdev->dev.parent);
 	ret = __ccw_device_check_pgid(cdev);
+	memset(&cdev->private->irb, 0, sizeof(struct irb));
 	switch (ret) {
 	/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
 	case 0:			/* disband successful. */
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -1,7 +1,9 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.26 $"
+#include <asm/page.h>
+
+#define VERSION_CIO_QDIO_H "$Revision: 1.32 $"
 
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_VERBOSE_LEVEL 9
@@ -42,7 +44,7 @@
 
 #define QDIO_Q_LAPS 5
 
-#define QDIO_STORAGE_KEY 0
+#define QDIO_STORAGE_KEY PAGE_DEFAULT_KEY
 
 #define L2_CACHELINE_SIZE 256
 #define INDICATORS_PER_CACHELINE (L2_CACHELINE_SIZE/sizeof(__u32))
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
--- a/drivers/s390/crypto/z90main.c
+++ b/drivers/s390/crypto/z90main.c
@@ -385,8 +385,8 @@ static int z90crypt_release(struct inode
 static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);
 static ssize_t z90crypt_write(struct file *, const char __user *,
 							size_t, loff_t *);
-static int z90crypt_ioctl(struct inode *, struct file *,
-			  unsigned int, unsigned long);
+static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
+static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 static void z90crypt_reader_task(unsigned long);
 static void z90crypt_schedule_reader_task(unsigned long);
@@ -433,12 +433,15 @@ static atomic_t total_open;
 static atomic_t z90crypt_step;
 
 static struct file_operations z90crypt_fops = {
-	.owner	 = THIS_MODULE,
-	.read	 = z90crypt_read,
-	.write	 = z90crypt_write,
-	.ioctl	 = z90crypt_ioctl,
-	.open	 = z90crypt_open,
-	.release = z90crypt_release
+	.owner		= THIS_MODULE,
+	.read		= z90crypt_read,
+	.write		= z90crypt_write,
+	.unlocked_ioctl	= z90crypt_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= z90crypt_compat_ioctl,
+#endif
+	.open		= z90crypt_open,
+	.release	= z90crypt_release
 };
 
 #ifndef Z90CRYPT_USE_HOTPLUG
@@ -474,14 +477,13 @@ struct ica_rsa_modexpo_32 { // For 32-bi
 	compat_uptr_t	n_modulus;
 };
 
-static int
-trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg,
-		struct file *file)
+static long
+trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg);
 	struct ica_rsa_modexpo_32  mex32k;
 	struct ica_rsa_modexpo __user *mex64;
-	int ret = 0;
+	long ret = 0;
 	unsigned int i;
 
 	if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
@@ -498,7 +500,7 @@ trans_modexpo32(unsigned int fd, unsigne
 	    __put_user(compat_ptr(mex32k.b_key), &mex64->b_key)           ||
 	    __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
 		return -EFAULT;
-	ret = sys_ioctl(fd, cmd, (unsigned long)mex64);
+	ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64);
 	if (!ret)
 		if (__get_user(i, &mex64->outputdatalength) ||
 		    __put_user(i, &mex32u->outputdatalength))
@@ -518,14 +520,13 @@ struct ica_rsa_modexpo_crt_32 { // For 3
 	compat_uptr_t	u_mult_inv;
 };
 
-static int
-trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg,
-		    struct file *file)
+static long
+trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg);
 	struct ica_rsa_modexpo_crt_32  crt32k;
 	struct ica_rsa_modexpo_crt __user *crt64;
-	int ret = 0;
+	long ret = 0;
 	unsigned int i;
 
 	if (!access_ok(VERIFY_WRITE, crt32u,
@@ -546,9 +547,8 @@ trans_modexpo_crt32(unsigned int fd, uns
 	    __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime)     ||
 	    __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime)     ||
 	    __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
-		ret = -EFAULT;
-	if (!ret)
-		ret = sys_ioctl(fd, cmd, (unsigned long)crt64);
+		return -EFAULT;
+	ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64);
 	if (!ret)
 		if (__get_user(i, &crt64->outputdatalength) ||
 		    __put_user(i, &crt32u->outputdatalength))
@@ -556,66 +556,34 @@ trans_modexpo_crt32(unsigned int fd, uns
 	return ret;
 }
 
-static int compatible_ioctls[] = {
-	ICAZ90STATUS, Z90QUIESCE, Z90STAT_TOTALCOUNT, Z90STAT_PCICACOUNT,
-	Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_PCIXCCMCL2COUNT,
-	Z90STAT_PCIXCCMCL3COUNT, Z90STAT_CEX2CCOUNT, Z90STAT_REQUESTQ_COUNT,
-	Z90STAT_PENDINGQ_COUNT, Z90STAT_TOTALOPEN_COUNT, Z90STAT_DOMAIN_INDEX,
-	Z90STAT_STATUS_MASK, Z90STAT_QDEPTH_MASK, Z90STAT_PERDEV_REQCNT,
-};
-
-static void z90_unregister_ioctl32s(void)
-{
-	int i;
-
-	unregister_ioctl32_conversion(ICARSAMODEXPO);
-	unregister_ioctl32_conversion(ICARSACRT);
-
-	for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++)
-		unregister_ioctl32_conversion(compatible_ioctls[i]);
-}
-
-static int z90_register_ioctl32s(void)
-{
-	int result, i;
-
-	result = register_ioctl32_conversion(ICARSAMODEXPO, trans_modexpo32);
-	if (result == -EBUSY) {
-		unregister_ioctl32_conversion(ICARSAMODEXPO);
-		result = register_ioctl32_conversion(ICARSAMODEXPO,
-						     trans_modexpo32);
-	}
-	if (result)
-		return result;
-	result = register_ioctl32_conversion(ICARSACRT, trans_modexpo_crt32);
-	if (result == -EBUSY) {
-		unregister_ioctl32_conversion(ICARSACRT);
-		result = register_ioctl32_conversion(ICARSACRT,
-						     trans_modexpo_crt32);
-	}
-	if (result)
-		return result;
-
-	for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) {
-		result = register_ioctl32_conversion(compatible_ioctls[i], 0);
-		if (result == -EBUSY) {
-			unregister_ioctl32_conversion(compatible_ioctls[i]);
-			result = register_ioctl32_conversion(
-						       compatible_ioctls[i], 0);
-		}
-		if (result)
-			return result;
-	}
-	return 0;
-}
-#else // !CONFIG_COMPAT
-static inline void z90_unregister_ioctl32s(void)
-{
-}
-
-static inline int z90_register_ioctl32s(void)
+static long
+z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-	return 0;
+	switch (cmd) {
+	case ICAZ90STATUS:
+	case Z90QUIESCE:
+	case Z90STAT_TOTALCOUNT:
+	case Z90STAT_PCICACOUNT:
+	case Z90STAT_PCICCCOUNT:
+	case Z90STAT_PCIXCCCOUNT:
+	case Z90STAT_PCIXCCMCL2COUNT:
+	case Z90STAT_PCIXCCMCL3COUNT:
+	case Z90STAT_CEX2CCOUNT:
+	case Z90STAT_REQUESTQ_COUNT:
+	case Z90STAT_PENDINGQ_COUNT:
+	case Z90STAT_TOTALOPEN_COUNT:
+	case Z90STAT_DOMAIN_INDEX:
+	case Z90STAT_STATUS_MASK:
+	case Z90STAT_QDEPTH_MASK:
+	case Z90STAT_PERDEV_REQCNT:
+		return z90crypt_unlocked_ioctl(filp, cmd, arg);
+	case ICARSAMODEXPO:
+		return trans_modexpo32(filp, cmd, arg);
+	case ICARSACRT:
+		return trans_modexpo_crt32(filp, cmd, arg);
+	default:
+		return -ENOIOCTLCMD;
+  	}
 }
 #endif
 
@@ -730,14 +698,9 @@ z90crypt_init_module(void)
 	reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
 	add_timer(&reader_timer);
 
-	if ((result = z90_register_ioctl32s()))
-		goto init_module_cleanup;
-
 	return 0; // success
 
 init_module_cleanup:
-	z90_unregister_ioctl32s();
-
 #ifndef Z90CRYPT_USE_HOTPLUG
 	if ((nresult = misc_deregister(&z90crypt_misc_device)))
 		PRINTK("misc_deregister failed with %d.\n", nresult);
@@ -763,8 +726,6 @@ z90crypt_cleanup_module(void)
 
 	PDEBUG("PID %d\n", PID());
 
-	z90_unregister_ioctl32s();
-
 	remove_proc_entry("driver/z90crypt", 0);
 
 #ifndef Z90CRYPT_USE_HOTPLUG
@@ -800,7 +761,7 @@ z90crypt_cleanup_module(void)
  *     z90crypt_release
  *     z90crypt_read
  *     z90crypt_write
- *     z90crypt_ioctl
+ *     z90crypt_unlocked_ioctl
  *     z90crypt_status
  *     z90crypt_status_write
  *	 disable_card
@@ -1804,9 +1765,8 @@ z90crypt_rsa(struct priv_data *private_d
  * This function is a little long, but it's really just one large switch
  * statement.
  */
-static int
-z90crypt_ioctl(struct inode *inode, struct file *filp,
-	       unsigned int cmd, unsigned long arg)
+static long
+z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct priv_data *private_data_p = filp->private_data;
 	unsigned char *status;
@@ -2657,8 +2617,8 @@ z90crypt_reader_task(unsigned long ptr)
 
 	/**
 	 * we use workavail = 2 to ensure 2 passes with nothing dequeued before
-	 * exiting the loop. If pendingq_count == 0 after the loop, there is no
-	 * work remaining on the queues.
+	 * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
+	 * loop, there is no work remaining on the queues.
 	 */
 	resp_addr = 0;
 	workavail = 2;
@@ -2697,7 +2657,7 @@ z90crypt_reader_task(unsigned long ptr)
 		spin_unlock_irq(&queuespinlock);
 	}
 
-	if (pendingq_count)
+	if (pendingq_count + requestq_count)
 		z90crypt_schedule_reader_timer();
 }
 
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -50,6 +50,15 @@ config SMSGIUCV
 	  Select this option if you want to be able to receive SMSG messages
 	  from other VM guest systems.
 
+config CLAW
+	tristate "CLAW device support"
+	depends on NETDEVICES
+	help
+	  This driver supports channel attached CLAW devices.
+	  CLAW is Common Link Access for Workstation.  Common devices
+          that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices.
+	  To compile as a module choose M here:  The module will be called
+	  claw.ko to compile into the kernel choose Y
 
 config QETH
 	tristate "Gigabit Ethernet device support"
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
 obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
 obj-$(CONFIG_LCS) += lcs.o cu3088.o
-qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o
+obj-$(CONFIG_CLAW) += claw.o cu3088.o
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o 
 qeth-$(CONFIG_PROC_FS) += qeth_proc.o
 obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/claw.c
@@ -0,0 +1,4447 @@
+/*
+ *  drivers/s390/net/claw.c
+ *    ESCON CLAW network driver
+ *
+ *    $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $
+ *
+ *  Linux fo zSeries version
+ *    Copyright (C) 2002,2005 IBM Corporation
+ *  Author(s) Original code written by:
+ *              Kazuo Iimura (iimura@jp.ibm.com)
+ *   	      Rewritten by
+ *              Andy Richter (richtera@us.ibm.com)
+ *              Marc Price (mwprice@us.ibm.com)
+ *
+ *    sysfs parms:
+ *   group x.x.rrrr,x.x.wwww
+ *   read_buffer nnnnnnn
+ *   write_buffer nnnnnn
+ *   host_name  aaaaaaaa
+ *   adapter_name aaaaaaaa
+ *   api_type    aaaaaaaa
+ *
+ *  eg.
+ *   group  0.0.0200 0.0.0201
+ *   read_buffer 25
+ *   write_buffer 20
+ *   host_name LINUX390
+ *   adapter_name RS6K
+ *   api_type     TCPIP
+ *
+ *  where
+ *
+ *   The device id is decided by the order entries
+ *   are added to the group the first is claw0 the second claw1
+ *   up to CLAW_MAX_DEV
+ *
+ *   rrrr     -	the first of 2 consecutive device addresses used for the
+ *		CLAW protocol.
+ *		The specified address is always used as the input (Read)
+ *		channel and the next address is used as the output channel.
+ *
+ *   wwww     -	the second of 2 consecutive device addresses used for
+ *		the CLAW protocol.
+ *              The specified address is always used as the output
+ *		channel and the previous address is used as the input channel.
+ *
+ *   read_buffer	-       specifies number of input buffers to allocate.
+ *   write_buffer       -       specifies number of output buffers to allocate.
+ *   host_name          -       host name
+ *   adaptor_name       -       adaptor name
+ *   api_type           -       API type TCPIP or API will be sent and expected
+ *				as ws_name
+ *
+ *   Note the following requirements:
+ *   1)  host_name must match the configured adapter_name on the remote side
+ *   2)  adaptor_name must match the configured host name on the remote side
+ *
+ *  Change History
+ *    1.00  Initial release shipped
+ *    1.10  Changes for Buffer allocation
+ *    1.15  Changed for 2.6 Kernel  No longer compiles on 2.4 or lower
+ *    1.25  Added Packing support
+ */
+#include <asm/bitops.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+#include <asm/debug.h>
+#include <asm/idals.h>
+#include <asm/io.h>
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tcp.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include "cu3088.h"
+#include "claw.h"
+
+MODULE_AUTHOR("Andy Richter <richtera@us.ibm.com>");
+MODULE_DESCRIPTION("Linux for zSeries CLAW Driver\n" \
+			"Copyright 2000,2005 IBM Corporation\n");
+MODULE_LICENSE("GPL");
+
+/* Debugging is based on DEBUGMSG, IOTRACE, or FUNCTRACE  options:
+   DEBUGMSG  - Enables output of various debug messages in the code
+   IOTRACE   - Enables output of CCW and other IO related traces
+   FUNCTRACE - Enables output of function entry/exit trace
+   Define any combination of above options to enable tracing
+
+   CLAW also uses the s390dbf file system  see claw_trace and claw_setup
+*/
+
+/* following enables tracing */
+//#define DEBUGMSG
+//#define IOTRACE
+//#define FUNCTRACE
+
+#ifdef DEBUGMSG
+#define DEBUG
+#endif
+
+#ifdef IOTRACE
+#define DEBUG
+#endif
+
+#ifdef FUNCTRACE
+#define DEBUG
+#endif
+
+ char debug_buffer[255];
+/**
+ * Debug Facility Stuff
+ */
+static debug_info_t *claw_dbf_setup;
+static debug_info_t *claw_dbf_trace;
+
+/**
+ *  CLAW Debug Facility functions
+ */
+static void
+claw_unregister_debug_facility(void)
+{
+	if (claw_dbf_setup)
+		debug_unregister(claw_dbf_setup);
+	if (claw_dbf_trace)
+		debug_unregister(claw_dbf_trace);
+}
+
+static int
+claw_register_debug_facility(void)
+{
+	claw_dbf_setup = debug_register("claw_setup", 1, 1, 8);
+	claw_dbf_trace = debug_register("claw_trace", 1, 2, 8);
+	if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) {
+		printk(KERN_WARNING "Not enough memory for debug facility.\n");
+		claw_unregister_debug_facility();
+		return -ENOMEM;
+	}
+	debug_register_view(claw_dbf_setup, &debug_hex_ascii_view);
+	debug_set_level(claw_dbf_setup, 2);
+	debug_register_view(claw_dbf_trace, &debug_hex_ascii_view);
+	debug_set_level(claw_dbf_trace, 2);
+	return 0;
+}
+
+static inline void
+claw_set_busy(struct net_device *dev)
+{
+ ((struct claw_privbk *) dev->priv)->tbusy=1;
+ eieio();
+}
+
+static inline void
+claw_clear_busy(struct net_device *dev)
+{
+	clear_bit(0, &(((struct claw_privbk *) dev->priv)->tbusy));
+	netif_wake_queue(dev);
+	eieio();
+}
+
+static inline int
+claw_check_busy(struct net_device *dev)
+{
+	eieio();
+	return ((struct claw_privbk *) dev->priv)->tbusy;
+}
+
+static inline void
+claw_setbit_busy(int nr,struct net_device *dev)
+{
+	netif_stop_queue(dev);
+ 	set_bit(nr, (void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+}
+
+static inline void
+claw_clearbit_busy(int nr,struct net_device *dev)
+{
+ 	clear_bit(nr,(void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+	netif_wake_queue(dev);
+}
+
+static inline int
+claw_test_and_setbit_busy(int nr,struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return test_and_set_bit(nr,
+ 		(void *)&(((struct claw_privbk *) dev->priv)->tbusy));
+}
+
+
+/* Functions for the DEV methods */
+
+static int claw_probe(struct ccwgroup_device *cgdev);
+static void claw_remove_device(struct ccwgroup_device *cgdev);
+static void claw_purge_skb_queue(struct sk_buff_head *q);
+static int claw_new_device(struct ccwgroup_device *cgdev);
+static int claw_shutdown_device(struct ccwgroup_device *cgdev);
+static int claw_tx(struct sk_buff *skb, struct net_device *dev);
+static int claw_change_mtu( struct net_device *dev, int new_mtu);
+static int claw_open(struct net_device *dev);
+static void claw_irq_handler(struct ccw_device *cdev,
+	unsigned long intparm, struct irb *irb);
+static void claw_irq_tasklet ( unsigned long data );
+static int claw_release(struct net_device *dev);
+static void claw_write_retry ( struct chbk * p_ch );
+static void claw_write_next ( struct chbk * p_ch );
+static void claw_timer ( struct chbk * p_ch );
+
+/* Functions */
+static int add_claw_reads(struct net_device *dev,
+	struct ccwbk* p_first, struct ccwbk* p_last);
+static void inline ccw_check_return_code (struct ccw_device *cdev,
+        int return_code);
+static void inline ccw_check_unit_check (struct chbk * p_ch,
+	unsigned char sense );
+static int find_link(struct net_device *dev, char *host_name, char *ws_name );
+static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
+static int init_ccw_bk(struct net_device *dev);
+static void probe_error( struct ccwgroup_device *cgdev);
+static struct net_device_stats *claw_stats(struct net_device *dev);
+static int inline pages_to_order_of_mag(int num_of_pages);
+static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
+#ifdef DEBUG
+static void dumpit (char *buf, int len);
+#endif
+/* sysfs Functions */
+static ssize_t claw_hname_show(struct device *dev, char *buf);
+static ssize_t claw_hname_write(struct device *dev,
+	const char *buf, size_t count);
+static ssize_t claw_adname_show(struct device *dev, char *buf);
+static ssize_t claw_adname_write(struct device *dev,
+	const char *buf, size_t count);
+static ssize_t claw_apname_show(struct device *dev, char *buf);
+static ssize_t claw_apname_write(struct device *dev,
+	const char *buf, size_t count);
+static ssize_t claw_wbuff_show(struct device *dev, char *buf);
+static ssize_t claw_wbuff_write(struct device *dev,
+	const char *buf, size_t count);
+static ssize_t claw_rbuff_show(struct device *dev, char *buf);
+static ssize_t claw_rbuff_write(struct device *dev,
+	const char *buf, size_t count);
+static int claw_add_files(struct device *dev);
+static void claw_remove_files(struct device *dev);
+
+/*   Functions for System Validate  */
+static int claw_process_control( struct net_device *dev, struct ccwbk * p_ccw);
+static int claw_send_control(struct net_device *dev, __u8 type, __u8 link,
+       __u8 correlator, __u8 rc , char *local_name, char *remote_name);
+static int claw_snd_conn_req(struct net_device *dev, __u8 link);
+static int claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl);
+static int claw_snd_sys_validate_rsp(struct net_device *dev,
+        struct clawctl * p_ctl, __u32 return_code);
+static int claw_strt_conn_req(struct net_device *dev );
+static void claw_strt_read ( struct net_device *dev, int lock );
+static void claw_strt_out_IO( struct net_device *dev );
+static void claw_free_wrt_buf( struct net_device *dev );
+
+/* Functions for unpack reads   */
+static void unpack_read (struct net_device *dev );
+
+/* ccwgroup table  */
+
+static struct ccwgroup_driver claw_group_driver = {
+        .owner       = THIS_MODULE,
+        .name        = "claw",
+        .max_slaves  = 2,
+        .driver_id   = 0xC3D3C1E6,
+        .probe       = claw_probe,
+        .remove      = claw_remove_device,
+        .set_online  = claw_new_device,
+        .set_offline = claw_shutdown_device,
+};
+
+/*
+*
+*       Key functions
+*/
+
+/*----------------------------------------------------------------*
+ *   claw_probe                                                   *
+ *      this function is called for each CLAW device.             *
+ *----------------------------------------------------------------*/
+static int
+claw_probe(struct ccwgroup_device *cgdev)
+{
+	int  		rc;
+	struct claw_privbk *privptr=NULL;
+
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s Enter\n",__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"probe");
+	if (!get_device(&cgdev->dev))
+		return -ENODEV;
+#ifdef DEBUGMSG
+        printk(KERN_INFO "claw: variable cgdev =\n");
+        dumpit((char *)cgdev, sizeof(struct ccwgroup_device));
+#endif
+	privptr = kmalloc(sizeof(struct claw_privbk), GFP_KERNEL);
+	if (privptr == NULL) {
+		probe_error(cgdev);
+		put_device(&cgdev->dev);
+		printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+			cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+		CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+		return -ENOMEM;
+	}
+	memset(privptr,0x00,sizeof(struct claw_privbk));
+	privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+	privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+        if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
+                probe_error(cgdev);
+		put_device(&cgdev->dev);
+		printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+			cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+		CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+                return -ENOMEM;
+        }
+	memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
+	memset(privptr->p_env, 0x00, sizeof(struct claw_env));
+	memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
+	memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
+	memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
+	privptr->p_env->packing = 0;
+	privptr->p_env->write_buffers = 5;
+	privptr->p_env->read_buffers = 5;
+	privptr->p_env->read_size = CLAW_FRAME_SIZE;
+	privptr->p_env->write_size = CLAW_FRAME_SIZE;
+	rc = claw_add_files(&cgdev->dev);
+	if (rc) {
+		probe_error(cgdev);
+		put_device(&cgdev->dev);
+		printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n",
+			cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+		CLAW_DBF_TEXT_(2,setup,"probex%d",rc);
+		return rc;
+	}
+	printk(KERN_INFO "claw: sysfs files added for %s\n",cgdev->cdev[0]->dev.bus_id);
+	privptr->p_env->p_priv = privptr;
+        cgdev->cdev[0]->handler = claw_irq_handler;
+	cgdev->cdev[1]->handler = claw_irq_handler;
+	cgdev->dev.driver_data = privptr;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "claw:%s exit on line %d, "
+		"rc = 0\n",__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"prbext 0");
+
+        return 0;
+}  /*  end of claw_probe       */
+
+/*-------------------------------------------------------------------*
+ *   claw_tx                                                         *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_tx(struct sk_buff *skb, struct net_device *dev)
+{
+        int             rc;
+        struct claw_privbk *privptr=dev->priv;
+	unsigned long saveflags;
+        struct chbk *p_ch;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"claw_tx");
+        p_ch=&privptr->channel[WRITE];
+        if (skb == NULL) {
+                printk(KERN_WARNING "%s: null pointer passed as sk_buffer\n",
+			dev->name);
+                privptr->stats.tx_dropped++;
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s: %s() exit on line %d, rc = EIO\n",
+			dev->name,__FUNCTION__, __LINE__);
+#endif
+		CLAW_DBF_TEXT_(2,trace,"clawtx%d",-EIO);
+                return -EIO;
+        }
+
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: variable sk_buff=\n",dev->name);
+        dumpit((char *) skb, sizeof(struct sk_buff));
+        printk(KERN_INFO "%s: variable dev=\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+#endif
+        spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
+        rc=claw_hw_tx( skb, dev, 1 );
+        spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s exit on line %d, rc = %d\n",
+		dev->name, __FUNCTION__, __LINE__, rc);
+#endif
+	CLAW_DBF_TEXT_(4,trace,"clawtx%d",rc);
+        return rc;
+}   /*  end of claw_tx */
+
+/*------------------------------------------------------------------*
+ *  pack the collect queue into an skb and return it                *
+ *   If not packing just return the top skb from the queue          *
+ *------------------------------------------------------------------*/
+
+static struct sk_buff *
+claw_pack_skb(struct claw_privbk *privptr)
+{
+	struct sk_buff *new_skb,*held_skb;
+	struct chbk *p_ch = &privptr->channel[WRITE];
+	struct claw_env  *p_env = privptr->p_env;
+	int	pkt_cnt,pk_ind,so_far;
+
+	new_skb = NULL;		/* assume no dice */
+	pkt_cnt = 0;
+	CLAW_DBF_TEXT(4,trace,"PackSKBe");
+	if (skb_queue_len(&p_ch->collect_queue) > 0) {
+	/* some data */
+		held_skb = skb_dequeue(&p_ch->collect_queue);
+		if (p_env->packing != DO_PACKED)
+			return held_skb;
+		if (held_skb)
+			atomic_dec(&held_skb->users);
+		else
+			return NULL;
+		/* get a new SKB we will pack at least one */
+		new_skb = dev_alloc_skb(p_env->write_size);
+		if (new_skb == NULL) {
+			atomic_inc(&held_skb->users);
+			skb_queue_head(&p_ch->collect_queue,held_skb);
+			return NULL;
+		}
+		/* we have packed packet and a place to put it  */
+		pk_ind = 1;
+		so_far = 0;
+		new_skb->cb[1] = 'P'; /* every skb on queue has pack header */
+		while ((pk_ind) && (held_skb != NULL)) {
+			if (held_skb->len+so_far <= p_env->write_size-8) {
+				memcpy(skb_put(new_skb,held_skb->len),
+					held_skb->data,held_skb->len);
+				privptr->stats.tx_packets++;
+				so_far += held_skb->len;
+				pkt_cnt++;
+				dev_kfree_skb_irq(held_skb);
+				held_skb = skb_dequeue(&p_ch->collect_queue);
+				if (held_skb)
+					atomic_dec(&held_skb->users);
+			} else {
+				pk_ind = 0;
+				atomic_inc(&held_skb->users);
+				skb_queue_head(&p_ch->collect_queue,held_skb);
+			}
+		}
+#ifdef IOTRACE
+		printk(KERN_INFO "%s: %s() Packed %d len %d\n",
+			p_env->ndev->name,
+			__FUNCTION__,pkt_cnt,new_skb->len);
+#endif
+	}
+	CLAW_DBF_TEXT(4,trace,"PackSKBx");
+	return new_skb;
+}
+
+/*-------------------------------------------------------------------*
+ *   claw_change_mtu                                                 *
+ *                                                                   *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct claw_privbk  *privptr=dev->priv;
+	int buff_size;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+        printk(KERN_INFO "variable dev =\n");
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "variable new_mtu = %d\n", new_mtu);
+#endif
+	CLAW_DBF_TEXT(4,trace,"setmtu");
+	buff_size = privptr->p_env->write_size;
+        if ((new_mtu < 60) || (new_mtu > buff_size)) {
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s:%s Exit on line %d, rc=EINVAL\n",
+		dev->name,
+		__FUNCTION__, __LINE__);
+#endif
+                return -EINVAL;
+        }
+        dev->mtu = new_mtu;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d\n",dev->name,
+	__FUNCTION__, __LINE__);
+#endif
+        return 0;
+}  /*   end of claw_change_mtu */
+
+
+/*-------------------------------------------------------------------*
+ *   claw_open                                                       *
+ *                                                                   *
+ *-------------------------------------------------------------------*/
+static int
+claw_open(struct net_device *dev)
+{
+
+        int     rc;
+        int     i;
+        unsigned long       saveflags=0;
+        unsigned long       parm;
+        struct claw_privbk  *privptr;
+	DECLARE_WAITQUEUE(wait, current);
+        struct timer_list  timer;
+        struct ccwbk *p_buf;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"open");
+	if (!dev | (dev->name[0] == 0x00)) {
+		CLAW_DBF_TEXT(2,trace,"BadDev");
+	 	printk(KERN_WARNING "claw: Bad device at open failing \n");
+		return -ENODEV;
+	}
+	privptr = (struct claw_privbk *)dev->priv;
+        /*   allocate and initialize CCW blocks */
+	if (privptr->buffs_alloc == 0) {
+	        rc=init_ccw_bk(dev);
+        	if (rc) {
+                	printk(KERN_INFO "%s:%s Exit on line %d, rc=ENOMEM\n",
+			dev->name,
+			__FUNCTION__, __LINE__);
+			CLAW_DBF_TEXT(2,trace,"openmem");
+                	return -ENOMEM;
+        	}
+	}
+        privptr->system_validate_comp=0;
+        privptr->release_pend=0;
+	if(strncmp(privptr->p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+		privptr->p_env->read_size=DEF_PACK_BUFSIZE;
+		privptr->p_env->write_size=DEF_PACK_BUFSIZE;
+		privptr->p_env->packing=PACKING_ASK;
+	} else {
+		privptr->p_env->packing=0;
+		privptr->p_env->read_size=CLAW_FRAME_SIZE;
+		privptr->p_env->write_size=CLAW_FRAME_SIZE;
+	}
+        claw_set_busy(dev);
+	tasklet_init(&privptr->channel[READ].tasklet, claw_irq_tasklet,
+        	(unsigned long) &privptr->channel[READ]);
+        for ( i = 0; i < 2;  i++) {
+		CLAW_DBF_TEXT_(2,trace,"opn_ch%d",i);
+                init_waitqueue_head(&privptr->channel[i].wait);
+		/* skb_queue_head_init(&p_ch->io_queue); */
+		if (i == WRITE)
+			skb_queue_head_init(
+				&privptr->channel[WRITE].collect_queue);
+                privptr->channel[i].flag_a = 0;
+                privptr->channel[i].IO_active = 0;
+                privptr->channel[i].flag  &= ~CLAW_TIMER;
+                init_timer(&timer);
+                timer.function = (void *)claw_timer;
+                timer.data = (unsigned long)(&privptr->channel[i]);
+                timer.expires = jiffies + 15*HZ;
+                add_timer(&timer);
+                spin_lock_irqsave(get_ccwdev_lock(
+			privptr->channel[i].cdev), saveflags);
+                parm = (unsigned long) &privptr->channel[i];
+                privptr->channel[i].claw_state = CLAW_START_HALT_IO;
+		rc = 0;
+		add_wait_queue(&privptr->channel[i].wait, &wait);
+                rc = ccw_device_halt(
+			(struct ccw_device *)privptr->channel[i].cdev,parm);
+                set_current_state(TASK_INTERRUPTIBLE);
+                spin_unlock_irqrestore(
+			get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+                schedule();
+		set_current_state(TASK_RUNNING);
+                remove_wait_queue(&privptr->channel[i].wait, &wait);
+                if(rc != 0)
+                        ccw_check_return_code(privptr->channel[i].cdev, rc);
+                if((privptr->channel[i].flag & CLAW_TIMER) == 0x00)
+                        del_timer(&timer);
+        }
+        if ((((privptr->channel[READ].last_dstat |
+		privptr->channel[WRITE].last_dstat) &
+           ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+           (((privptr->channel[READ].flag |
+	   	privptr->channel[WRITE].flag) & CLAW_TIMER) != 0x00)) {
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: channel problems during open - read:"
+			" %02x -  write: %02x\n",
+                        dev->name,
+			privptr->channel[READ].last_dstat,
+			privptr->channel[WRITE].last_dstat);
+#endif
+                printk(KERN_INFO "%s: remote side is not ready\n", dev->name);
+		CLAW_DBF_TEXT(2,trace,"notrdy");
+
+                for ( i = 0; i < 2;  i++) {
+                        spin_lock_irqsave(
+				get_ccwdev_lock(privptr->channel[i].cdev),
+				saveflags);
+                        parm = (unsigned long) &privptr->channel[i];
+                        privptr->channel[i].claw_state = CLAW_STOP;
+                        rc = ccw_device_halt(
+				(struct ccw_device *)&privptr->channel[i].cdev,
+				parm);
+                        spin_unlock_irqrestore(
+				get_ccwdev_lock(privptr->channel[i].cdev),
+				saveflags);
+                        if (rc != 0) {
+                                ccw_check_return_code(
+					privptr->channel[i].cdev, rc);
+                        }
+                }
+                free_pages((unsigned long)privptr->p_buff_ccw,
+			(int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+                if (privptr->p_env->read_size < PAGE_SIZE) {
+                        free_pages((unsigned long)privptr->p_buff_read,
+			       (int)pages_to_order_of_mag(
+			       		privptr->p_buff_read_num));
+                }
+                else {
+                        p_buf=privptr->p_read_active_first;
+                        while (p_buf!=NULL) {
+                                free_pages((unsigned long)p_buf->p_buffer,
+				      (int)pages_to_order_of_mag(
+				      	privptr->p_buff_pages_perread ));
+                                p_buf=p_buf->next;
+                        }
+                }
+                if (privptr->p_env->write_size < PAGE_SIZE ) {
+                        free_pages((unsigned long)privptr->p_buff_write,
+			     (int)pages_to_order_of_mag(
+			     	privptr->p_buff_write_num));
+                }
+                else {
+                        p_buf=privptr->p_write_active_first;
+                        while (p_buf!=NULL) {
+                                free_pages((unsigned long)p_buf->p_buffer,
+				     (int)pages_to_order_of_mag(
+				     	privptr->p_buff_pages_perwrite ));
+                                p_buf=p_buf->next;
+                        }
+                }
+		privptr->buffs_alloc = 0;
+		privptr->channel[READ].flag= 0x00;
+		privptr->channel[WRITE].flag = 0x00;
+                privptr->p_buff_ccw=NULL;
+                privptr->p_buff_read=NULL;
+                privptr->p_buff_write=NULL;
+                claw_clear_busy(dev);
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s:%s Exit on line %d, rc=EIO\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+		CLAW_DBF_TEXT(2,trace,"open EIO");
+                return -EIO;
+        }
+
+        /*   Send SystemValidate command */
+
+        claw_clear_busy(dev);
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d, rc=0\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"openok");
+        return 0;
+}    /*     end of claw_open    */
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*       claw_irq_handler                                             *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static void
+claw_irq_handler(struct ccw_device *cdev,
+	unsigned long intparm, struct irb *irb)
+{
+        struct chbk *p_ch = NULL;
+        struct claw_privbk *privptr = NULL;
+        struct net_device *dev = NULL;
+        struct claw_env  *p_env;
+        struct chbk *p_ch_r=NULL;
+
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s enter  \n",__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"clawirq");
+        /* Bypass all 'unsolicited interrupts' */
+	if (!cdev->dev.driver_data) {
+                printk(KERN_WARNING "claw: unsolicited interrupt for device:"
+		 	"%s received c-%02x d-%02x\n",
+                        cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat);
+#ifdef FUNCTRACE
+                printk(KERN_INFO "claw: %s() "
+			"exit on line %d\n",__FUNCTION__,__LINE__);
+#endif
+		CLAW_DBF_TEXT(2,trace,"badirq");
+                return;
+        }
+	privptr = (struct claw_privbk *)cdev->dev.driver_data;
+
+	/* Try to extract channel from driver data. */
+	if (privptr->channel[READ].cdev == cdev)
+		p_ch = &privptr->channel[READ];
+	else if (privptr->channel[WRITE].cdev == cdev)
+		p_ch = &privptr->channel[WRITE];
+	else {
+		printk(KERN_WARNING "claw: Can't determine channel for "
+			"interrupt, device %s\n", cdev->dev.bus_id);
+		CLAW_DBF_TEXT(2,trace,"badchan");
+		return;
+	}
+	CLAW_DBF_TEXT_(4,trace,"IRQCH=%d",p_ch->flag);
+
+	dev = (struct net_device *) (p_ch->ndev);
+        p_env=privptr->p_env;
+
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: interrupt for device: %04x "
+		"received c-%02x d-%02x state-%02x\n",
+                dev->name, p_ch->devno, irb->scsw.cstat,
+		irb->scsw.dstat, p_ch->claw_state);
+#endif
+
+	/* Copy interruption response block. */
+	memcpy(p_ch->irb, irb, sizeof(struct irb));
+
+        /* Check for good subchannel return code, otherwise error message */
+        if (irb->scsw.cstat  &&  !(irb->scsw.cstat & SCHN_STAT_PCI)) {
+                printk(KERN_INFO "%s: subchannel check for device: %04x -"
+			" Sch Stat %02x  Dev Stat %02x CPA - %04x\n",
+                        dev->name, p_ch->devno,
+			irb->scsw.cstat, irb->scsw.dstat,irb->scsw.cpa);
+#ifdef IOTRACE
+		dumpit((char *)irb,sizeof(struct irb));
+		dumpit((char *)(unsigned long)irb->scsw.cpa,
+			sizeof(struct ccw1));
+#endif
+#ifdef FUNCTRACE
+		printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+		CLAW_DBF_TEXT(2,trace,"chanchk");
+                /* return; */
+        }
+
+        /* Check the reason-code of a unit check */
+        if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+                ccw_check_unit_check(p_ch, irb->ecw[0]);
+        }
+
+        /* State machine to bring the connection up, down and to restart */
+        p_ch->last_dstat = irb->scsw.dstat;
+
+        switch (p_ch->claw_state) {
+                case CLAW_STOP:/* HALT_IO by claw_release (halt sequence) */
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: CLAW_STOP enter\n", dev->name);
+#endif
+                        if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+	    		(p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+	    		(p_ch->irb->scsw.stctl ==
+	     		(SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+                                printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+                                return;
+                        }
+                        wake_up(&p_ch->wait);   /* wake up claw_release */
+
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: CLAW_STOP exit\n", dev->name);
+#endif
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s:%s Exit on line %d\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+			CLAW_DBF_TEXT(4,trace,"stop");
+                        return;
+
+                case CLAW_START_HALT_IO: /* HALT_IO issued by claw_open  */
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO\n",
+				dev->name);
+#endif
+                        if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+	    		(p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+	    		(p_ch->irb->scsw.stctl ==
+	     		(SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+				CLAW_DBF_TEXT(4,trace,"haltio");
+                                return;
+                        }
+                        if (p_ch->flag == CLAW_READ) {
+                                p_ch->claw_state = CLAW_START_READ;
+                                wake_up(&p_ch->wait); /* wake claw_open (READ)*/
+                        }
+			else
+			   if (p_ch->flag == CLAW_WRITE) {
+                                p_ch->claw_state = CLAW_START_WRITE;
+                                /*      send SYSTEM_VALIDATE                    */
+                                claw_strt_read(dev, LOCK_NO);
+                               	claw_send_control(dev,
+					SYSTEM_VALIDATE_REQUEST,
+					0, 0, 0,
+					p_env->host_name,
+					p_env->adapter_name );
+                        } else {
+				printk(KERN_WARNING "claw: unsolicited "
+					"interrupt for device:"
+				 	"%s received c-%02x d-%02x\n",
+                		        cdev->dev.bus_id,
+					irb->scsw.cstat,
+					irb->scsw.dstat);
+				return;
+				}
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO exit\n",
+				dev->name);
+#endif
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s:%s Exit on line %d\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+			CLAW_DBF_TEXT(4,trace,"haltio");
+                        return;
+                case CLAW_START_READ:
+			CLAW_DBF_TEXT(4,trace,"ReadIRQ");
+                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+                                clear_bit(0, (void *)&p_ch->IO_active);
+                                if ((p_ch->irb->ecw[0] & 0x41) == 0x41 ||
+                                    (p_ch->irb->ecw[0] & 0x40) == 0x40 ||
+                                    (p_ch->irb->ecw[0])        == 0)
+                                {
+                                        privptr->stats.rx_errors++;
+                                        printk(KERN_INFO "%s: Restart is "
+						"required after remote "
+						"side recovers \n",
+						dev->name);
+                                }
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+					CLAW_DBF_TEXT(4,trace,"notrdy");
+                                        return;
+                        }
+                        if ((p_ch->irb->scsw.cstat & SCHN_STAT_PCI) &&
+			    (p_ch->irb->scsw.dstat==0)) {
+                                if (test_and_set_bit(CLAW_BH_ACTIVE,
+					(void *)&p_ch->flag_a) == 0) {
+					tasklet_schedule(&p_ch->tasklet);
+                                }
+				else {
+					CLAW_DBF_TEXT(4,trace,"PCINoBH");
+				}
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+				CLAW_DBF_TEXT(4,trace,"PCI_read");
+                                return;
+                        }
+                        if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+	    		 (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+	    		 (p_ch->irb->scsw.stctl ==
+	     		 (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+				CLAW_DBF_TEXT(4,trace,"SPend_rd");
+                                return;
+                        }
+                        clear_bit(0, (void *)&p_ch->IO_active);
+                        claw_clearbit_busy(TB_RETRY,dev);
+                        if (test_and_set_bit(CLAW_BH_ACTIVE,
+    				(void *)&p_ch->flag_a) == 0) {
+    				tasklet_schedule(&p_ch->tasklet);
+                         }
+    			else {
+    				CLAW_DBF_TEXT(4,trace,"RdBHAct");
+    			}
+
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: process CLAW_START_READ exit\n",
+				dev->name);
+#endif
+#ifdef FUNCTRACE
+			printk(KERN_INFO "%s:%s Exit on line %d\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+			CLAW_DBF_TEXT(4,trace,"RdIRQXit");
+                        return;
+                case CLAW_START_WRITE:
+                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+                                printk(KERN_INFO "%s: Unit Check Occured in "
+					"write channel\n",dev->name);
+                                clear_bit(0, (void *)&p_ch->IO_active);
+                                if (p_ch->irb->ecw[0] & 0x80 ) {
+                                        printk(KERN_INFO "%s: Resetting Event "
+						"occurred:\n",dev->name);
+                                        init_timer(&p_ch->timer);
+                                        p_ch->timer.function =
+						(void *)claw_write_retry;
+                                        p_ch->timer.data = (unsigned long)p_ch;
+                                        p_ch->timer.expires = jiffies + 10*HZ;
+                                        add_timer(&p_ch->timer);
+                                        printk(KERN_INFO "%s: write connection "
+						"restarting\n",dev->name);
+                                }
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+				CLAW_DBF_TEXT(4,trace,"rstrtwrt");
+                                return;
+                        }
+                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) {
+                                        clear_bit(0, (void *)&p_ch->IO_active);
+                                        printk(KERN_INFO "%s: Unit Exception "
+						"Occured in write channel\n",
+						dev->name);
+                        }
+                        if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+	    		(p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+	    		(p_ch->irb->scsw.stctl ==
+	     		(SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+				printk(KERN_INFO "%s:%s Exit on line %d\n",
+					dev->name,__FUNCTION__,__LINE__);
+#endif
+				CLAW_DBF_TEXT(4,trace,"writeUE");
+                                return;
+                        }
+                        clear_bit(0, (void *)&p_ch->IO_active);
+                        if (claw_test_and_setbit_busy(TB_TX,dev)==0) {
+                                claw_write_next(p_ch);
+                                claw_clearbit_busy(TB_TX,dev);
+                                claw_clear_busy(dev);
+                        }
+                        p_ch_r=(struct chbk *)&privptr->channel[READ];
+                        if (test_and_set_bit(CLAW_BH_ACTIVE,
+ 					(void *)&p_ch_r->flag_a) == 0) {
+			 	tasklet_schedule(&p_ch_r->tasklet);
+                        }
+
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: process CLAW_START_WRITE exit\n",
+				 dev->name);
+#endif
+#ifdef FUNCTRACE
+			printk(KERN_INFO "%s:%s Exit on line %d\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+			CLAW_DBF_TEXT(4,trace,"StWtExit");
+                        return;
+                default:
+                        printk(KERN_WARNING "%s: wrong selection code - irq "
+				"state=%d\n",dev->name,p_ch->claw_state);
+#ifdef FUNCTRACE
+			printk(KERN_INFO "%s:%s Exit on line %d\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+			CLAW_DBF_TEXT(2,trace,"badIRQ");
+                        return;
+        }
+
+}       /*   end of claw_irq_handler    */
+
+
+/*-------------------------------------------------------------------*
+*       claw_irq_tasklet                                             *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static void
+claw_irq_tasklet ( unsigned long data )
+{
+	struct chbk * p_ch;
+        struct net_device  *dev;
+        struct claw_privbk *       privptr;
+
+	p_ch = (struct chbk *) data;
+        dev = (struct net_device *)p_ch->ndev;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable p_ch =\n",dev->name);
+        dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+	CLAW_DBF_TEXT(4,trace,"IRQtask");
+
+        privptr = (struct claw_privbk *) dev->priv;
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: bh routine - state-%02x\n" ,
+		dev->name, p_ch->claw_state);
+#endif
+
+        unpack_read(dev);
+        clear_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a);
+	CLAW_DBF_TEXT(4,trace,"TskletXt");
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+        return;
+}       /*    end of claw_irq_bh    */
+
+/*-------------------------------------------------------------------*
+*       claw_release                                                 *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static int
+claw_release(struct net_device *dev)
+{
+        int                rc;
+        int                i;
+        unsigned long      saveflags;
+        unsigned long      parm;
+        struct claw_privbk *privptr;
+        DECLARE_WAITQUEUE(wait, current);
+        struct ccwbk*             p_this_ccw;
+        struct ccwbk*             p_buf;
+
+	if (!dev)
+                return 0;
+        privptr = (struct claw_privbk *) dev->priv;
+        if (!privptr)
+                return 0;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"release");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+	printk(KERN_INFO "Priv Buffalloc %d\n",privptr->buffs_alloc);
+	printk(KERN_INFO "Priv p_buff_ccw = %p\n",&privptr->p_buff_ccw);
+#endif
+        privptr->release_pend=1;
+        claw_setbit_busy(TB_STOP,dev);
+        for ( i = 1; i >=0 ;  i--) {
+                spin_lock_irqsave(
+			get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+             /*   del_timer(&privptr->channel[READ].timer);  */
+ 		privptr->channel[i].claw_state = CLAW_STOP;
+                privptr->channel[i].IO_active = 0;
+                parm = (unsigned long) &privptr->channel[i];
+		if (i == WRITE)
+			claw_purge_skb_queue(
+				&privptr->channel[WRITE].collect_queue);
+                rc = ccw_device_halt (privptr->channel[i].cdev, parm);
+	        if (privptr->system_validate_comp==0x00)  /* never opened? */
+                   init_waitqueue_head(&privptr->channel[i].wait);
+                add_wait_queue(&privptr->channel[i].wait, &wait);
+                set_current_state(TASK_INTERRUPTIBLE);
+	        spin_unlock_irqrestore(
+			get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+	        schedule();
+		set_current_state(TASK_RUNNING);
+	        remove_wait_queue(&privptr->channel[i].wait, &wait);
+	        if (rc != 0) {
+                        ccw_check_return_code(privptr->channel[i].cdev, rc);
+                }
+        }
+	if (privptr->pk_skb != NULL) {
+		dev_kfree_skb(privptr->pk_skb);
+		privptr->pk_skb = NULL;
+	}
+	if(privptr->buffs_alloc != 1) {
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+		CLAW_DBF_TEXT(4,trace,"none2fre");
+		return 0;
+	}
+	CLAW_DBF_TEXT(4,trace,"freebufs");
+	if (privptr->p_buff_ccw != NULL) {
+        	free_pages((unsigned long)privptr->p_buff_ccw,
+	        	(int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+	}
+	CLAW_DBF_TEXT(4,trace,"freeread");
+        if (privptr->p_env->read_size < PAGE_SIZE) {
+	    if (privptr->p_buff_read != NULL) {
+                free_pages((unsigned long)privptr->p_buff_read,
+		      (int)pages_to_order_of_mag(privptr->p_buff_read_num));
+		}
+        }
+        else {
+                p_buf=privptr->p_read_active_first;
+                while (p_buf!=NULL) {
+                        free_pages((unsigned long)p_buf->p_buffer,
+			     (int)pages_to_order_of_mag(
+			     	privptr->p_buff_pages_perread ));
+                        p_buf=p_buf->next;
+                }
+        }
+	 CLAW_DBF_TEXT(4,trace,"freewrit");
+        if (privptr->p_env->write_size < PAGE_SIZE ) {
+                free_pages((unsigned long)privptr->p_buff_write,
+		      (int)pages_to_order_of_mag(privptr->p_buff_write_num));
+        }
+        else {
+                p_buf=privptr->p_write_active_first;
+                while (p_buf!=NULL) {
+                        free_pages((unsigned long)p_buf->p_buffer,
+			      (int)pages_to_order_of_mag(
+			      privptr->p_buff_pages_perwrite ));
+                        p_buf=p_buf->next;
+                }
+        }
+	 CLAW_DBF_TEXT(4,trace,"clearptr");
+	privptr->buffs_alloc = 0;
+        privptr->p_buff_ccw=NULL;
+        privptr->p_buff_read=NULL;
+        privptr->p_buff_write=NULL;
+        privptr->system_validate_comp=0;
+        privptr->release_pend=0;
+        /*      Remove any writes that were pending and reset all reads   */
+        p_this_ccw=privptr->p_read_active_first;
+        while (p_this_ccw!=NULL) {
+                p_this_ccw->header.length=0xffff;
+                p_this_ccw->header.opcode=0xff;
+                p_this_ccw->header.flag=0x00;
+                p_this_ccw=p_this_ccw->next;
+        }
+
+        while (privptr->p_write_active_first!=NULL) {
+                p_this_ccw=privptr->p_write_active_first;
+                p_this_ccw->header.flag=CLAW_PENDING;
+                privptr->p_write_active_first=p_this_ccw->next;
+                p_this_ccw->next=privptr->p_write_free_chain;
+                privptr->p_write_free_chain=p_this_ccw;
+                ++privptr->write_free_count;
+        }
+        privptr->p_write_active_last=NULL;
+        privptr->mtc_logical_link = -1;
+        privptr->mtc_skipping = 1;
+        privptr->mtc_offset=0;
+
+        if (((privptr->channel[READ].last_dstat |
+		privptr->channel[WRITE].last_dstat) &
+		~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+                printk(KERN_WARNING "%s: channel problems during close - "
+			"read: %02x -  write: %02x\n",
+                dev->name,
+		privptr->channel[READ].last_dstat,
+		privptr->channel[WRITE].last_dstat);
+		 CLAW_DBF_TEXT(2,trace,"badclose");
+        }
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"rlsexit");
+        return 0;
+}      /* end of claw_release     */
+
+
+
+/*-------------------------------------------------------------------*
+*       claw_write_retry                                             *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static void
+claw_write_retry ( struct chbk *p_ch )
+{
+
+        struct net_device  *dev=p_ch->ndev;
+
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+        printk(KERN_INFO "claw: variable p_ch =\n");
+        dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+	CLAW_DBF_TEXT(4,trace,"w_retry");
+        if (p_ch->claw_state == CLAW_STOP) {
+#ifdef FUNCTRACE
+		printk(KERN_INFO "%s:%s Exit on line %d\n",
+			dev->name,__FUNCTION__,__LINE__);
+#endif
+        	return;
+        }
+#ifdef DEBUGMSG
+        printk( KERN_INFO "%s:%s  state-%02x\n" ,
+		dev->name,
+		__FUNCTION__,
+		p_ch->claw_state);
+#endif
+	claw_strt_out_IO( dev );
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"rtry_xit");
+        return;
+}      /* end of claw_write_retry      */
+
+
+/*-------------------------------------------------------------------*
+*       claw_write_next                                              *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static void
+claw_write_next ( struct chbk * p_ch )
+{
+
+        struct net_device  *dev;
+        struct claw_privbk *privptr=NULL;
+	struct sk_buff *pk_skb;
+	int	rc;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",p_ch->ndev->name,__FUNCTION__);
+        printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name);
+        dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+	CLAW_DBF_TEXT(4,trace,"claw_wrt");
+        if (p_ch->claw_state == CLAW_STOP)
+                return;
+        dev = (struct net_device *) p_ch->ndev;
+	privptr = (struct claw_privbk *) dev->priv;
+        claw_free_wrt_buf( dev );
+	if ((privptr->write_free_count > 0) &&
+	    (skb_queue_len(&p_ch->collect_queue) > 0)) {
+	  	pk_skb = claw_pack_skb(privptr);
+		while (pk_skb != NULL) {
+			rc = claw_hw_tx( pk_skb, dev,1);
+			if (privptr->write_free_count > 0) {
+	   			pk_skb = claw_pack_skb(privptr);
+			} else
+				pk_skb = NULL;
+		}
+	}
+        if (privptr->p_write_active_first!=NULL) {
+                claw_strt_out_IO(dev);
+        }
+
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+        return;
+}      /* end of claw_write_next      */
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*       claw_timer                                                   *
+*--------------------------------------------------------------------*/
+
+static void
+claw_timer ( struct chbk * p_ch )
+{
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Entry\n",p_ch->ndev->name,__FUNCTION__);
+        printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name);
+        dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+	CLAW_DBF_TEXT(4,trace,"timer");
+        p_ch->flag |= CLAW_TIMER;
+        wake_up(&p_ch->wait);
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		p_ch->ndev->name,__FUNCTION__,__LINE__);
+#endif
+        return;
+}      /* end of claw_timer  */
+
+
+/*
+*
+*       functions
+*/
+
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*     pages_to_order_of_mag                                          *
+*                                                                    *
+*    takes a number of pages from 1 to 512 and returns the           *
+*    log(num_pages)/log(2) get_free_pages() needs a base 2 order     *
+*    of magnitude get_free_pages() has an upper order of 9           *
+*--------------------------------------------------------------------*/
+
+static int inline
+pages_to_order_of_mag(int num_of_pages)
+{
+	int	order_of_mag=1;		/* assume 2 pages */
+	int	nump=2;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s Enter pages = %d \n",__FUNCTION__,num_of_pages);
+#endif
+	CLAW_DBF_TEXT_(5,trace,"pages%d",num_of_pages);
+	if (num_of_pages == 1)   {return 0; }  /* magnitude of 0 = 1 page */
+	/* 512 pages = 2Meg on 4k page systems */
+	if (num_of_pages >= 512) {return 9; }
+	/* we have two or more pages order is at least 1 */
+	for (nump=2 ;nump <= 512;nump*=2) {
+	  if (num_of_pages <= nump)
+		  break;
+	  order_of_mag +=1;
+	}
+	if (order_of_mag > 9) { order_of_mag = 9; }  /* I know it's paranoid */
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s Exit on line %d, order = %d\n",
+	__FUNCTION__,__LINE__, order_of_mag);
+#endif
+	CLAW_DBF_TEXT_(5,trace,"mag%d",order_of_mag);
+	return order_of_mag;
+}
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*     add_claw_reads                                                 *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static int
+add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
+	struct ccwbk* p_last)
+{
+        struct claw_privbk *privptr;
+        struct ccw1  temp_ccw;
+        struct endccw * p_end;
+#ifdef IOTRACE
+        struct ccwbk*  p_buf;
+#endif
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+        printk(KERN_INFO "dev\n");
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "p_first\n");
+        dumpit((char *) p_first, sizeof(struct ccwbk));
+        printk(KERN_INFO "p_last\n");
+        dumpit((char *) p_last, sizeof(struct ccwbk));
+#endif
+	CLAW_DBF_TEXT(4,trace,"addreads");
+        privptr = dev->priv;
+        p_end = privptr->p_end_ccw;
+
+        /* first CCW and last CCW contains a new set of read channel programs
+        *       to apend the running channel programs
+        */
+        if ( p_first==NULL) {
+#ifdef FUNCTRACE
+		printk(KERN_INFO "%s:%s Exit on line %d\n",
+			dev->name,__FUNCTION__,__LINE__);
+#endif
+		CLAW_DBF_TEXT(4,trace,"addexit");
+                return 0;
+        }
+
+        /* set up ending CCW sequence for this segment */
+        if (p_end->read1) {
+                p_end->read1=0x00;    /*  second ending CCW is now active */
+                /*      reset ending CCWs and setup TIC CCWs              */
+                p_end->read2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+                p_end->read2_nop2.flags  = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+                p_last->r_TIC_1.cda =(__u32)__pa(&p_end->read2_nop1);
+                p_last->r_TIC_2.cda =(__u32)__pa(&p_end->read2_nop1);
+                p_end->read2_nop2.cda=0;
+                p_end->read2_nop2.count=1;
+        }
+        else {
+                p_end->read1=0x01;  /* first ending CCW is now active */
+                /*      reset ending CCWs and setup TIC CCWs          */
+                p_end->read1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+                p_end->read1_nop2.flags  = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+                p_last->r_TIC_1.cda = (__u32)__pa(&p_end->read1_nop1);
+                p_last->r_TIC_2.cda = (__u32)__pa(&p_end->read1_nop1);
+                p_end->read1_nop2.cda=0;
+                p_end->read1_nop2.count=1;
+        }
+
+        if ( privptr-> p_read_active_first ==NULL ) {
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s:%s p_read_active_frist == NULL \n",
+			dev->name,__FUNCTION__);
+                printk(KERN_INFO "%s:%s Read active first/last changed \n",
+			dev->name,__FUNCTION__);
+#endif
+                privptr-> p_read_active_first= p_first;  /*    set new first */
+                privptr-> p_read_active_last = p_last;   /*    set new last  */
+        }
+        else {
+
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s:%s Read in progress \n",
+		dev->name,__FUNCTION__);
+#endif
+                /* set up TIC ccw  */
+                temp_ccw.cda= (__u32)__pa(&p_first->read);
+                temp_ccw.count=0;
+                temp_ccw.flags=0;
+                temp_ccw.cmd_code = CCW_CLAW_CMD_TIC;
+
+
+                if (p_end->read1) {
+
+               /* first set of CCW's is chained to the new read              */
+               /* chain, so the second set is chained to the active chain.   */
+               /* Therefore modify the second set to point to the new        */
+               /* read chain set up TIC CCWs                                 */
+               /* make sure we update the CCW so channel doesn't fetch it    */
+               /* when it's only half done                                   */
+                        memcpy( &p_end->read2_nop2, &temp_ccw ,
+				sizeof(struct ccw1));
+                        privptr->p_read_active_last->r_TIC_1.cda=
+				(__u32)__pa(&p_first->read);
+                        privptr->p_read_active_last->r_TIC_2.cda=
+				(__u32)__pa(&p_first->read);
+                }
+                else {
+                        /* make sure we update the CCW so channel doesn't   */
+			/* fetch it when it is only half done               */
+                        memcpy( &p_end->read1_nop2, &temp_ccw ,
+				sizeof(struct ccw1));
+                        privptr->p_read_active_last->r_TIC_1.cda=
+				(__u32)__pa(&p_first->read);
+                        privptr->p_read_active_last->r_TIC_2.cda=
+				(__u32)__pa(&p_first->read);
+                }
+                /*      chain in new set of blocks                              */
+                privptr->p_read_active_last->next = p_first;
+                privptr->p_read_active_last=p_last;
+        } /* end of if ( privptr-> p_read_active_first ==NULL)  */
+#ifdef IOTRACE
+        printk(KERN_INFO "%s:%s  dump p_last CCW BK \n",dev->name,__FUNCTION__);
+        dumpit((char *)p_last, sizeof(struct ccwbk));
+        printk(KERN_INFO "%s:%s  dump p_end CCW BK \n",dev->name,__FUNCTION__);
+        dumpit((char *)p_end, sizeof(struct endccw));
+
+        printk(KERN_INFO "%s:%s dump p_first CCW BK \n",dev->name,__FUNCTION__);
+        dumpit((char *)p_first, sizeof(struct ccwbk));
+        printk(KERN_INFO "%s:%s Dump Active CCW chain \n",
+		dev->name,__FUNCTION__);
+        p_buf=privptr->p_read_active_first;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+#endif
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"addexit");
+        return 0;
+}    /*     end of add_claw_reads   */
+
+/*-------------------------------------------------------------------*
+ *   ccw_check_return_code                                           *
+ *                                                                   *
+ *-------------------------------------------------------------------*/
+
+static void inline
+ccw_check_return_code(struct ccw_device *cdev, int return_code)
+{
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > enter  \n",
+		cdev->dev.bus_id,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"ccwret");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "variable cdev =\n");
+        dumpit((char *) cdev, sizeof(struct ccw_device));
+        printk(KERN_INFO "variable return_code = %d\n",return_code);
+#endif
+        if (return_code != 0) {
+                switch (return_code) {
+                        case -EBUSY:
+                                printk(KERN_INFO "%s: Busy !\n",
+					cdev->dev.bus_id);
+                                break;
+                        case -ENODEV:
+                                printk(KERN_EMERG "%s: Missing device called "
+					"for IO ENODEV\n", cdev->dev.bus_id);
+                                break;
+                        case -EIO:
+                                printk(KERN_EMERG "%s: Status pending... EIO \n",
+					cdev->dev.bus_id);
+                                break;
+			case -EINVAL:
+                                printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n",
+					cdev->dev.bus_id);
+                                break;
+                        default:
+                                printk(KERN_EMERG "%s: Unknown error in "
+				 "Do_IO %d\n",cdev->dev.bus_id, return_code);
+                }
+        }
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > exit on line %d\n",
+		cdev->dev.bus_id,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"ccwret");
+}    /*    end of ccw_check_return_code   */
+
+/*-------------------------------------------------------------------*
+*       ccw_check_unit_check                                         *
+*--------------------------------------------------------------------*/
+
+static void inline
+ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
+{
+	struct net_device *dev = p_ch->ndev;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *)dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable sense =\n",dev->name);
+        dumpit((char *)&sense, 2);
+#endif
+	CLAW_DBF_TEXT(4,trace,"unitchek");
+
+        printk(KERN_INFO "%s: Unit Check with sense byte:0x%04x\n",
+                dev->name, sense);
+
+        if (sense & 0x40) {
+                if (sense & 0x01) {
+                        printk(KERN_WARNING "%s: Interface disconnect or "
+				"Selective reset "
+			       	"occurred (remote side)\n", dev->name);
+                }
+                else {
+                        printk(KERN_WARNING "%s: System reset occured"
+				" (remote side)\n", dev->name);
+                }
+        }
+        else if (sense & 0x20) {
+                if (sense & 0x04) {
+                        printk(KERN_WARNING "%s: Data-streaming "
+				"timeout)\n", dev->name);
+                }
+                else  {
+                        printk(KERN_WARNING "%s: Data-transfer parity"
+				" error\n", dev->name);
+                }
+        }
+        else if (sense & 0x10) {
+                if (sense & 0x20) {
+                        printk(KERN_WARNING "%s: Hardware malfunction "
+				"(remote side)\n", dev->name);
+                }
+                else {
+                        printk(KERN_WARNING "%s: read-data parity error "
+				"(remote side)\n", dev->name);
+                }
+        }
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+}   /*    end of ccw_check_unit_check    */
+
+
+
+/*-------------------------------------------------------------------*
+* Dump buffer format                                                 *
+*                                                                    *
+*--------------------------------------------------------------------*/
+#ifdef DEBUG
+static void
+dumpit(char* buf, int len)
+{
+
+        __u32      ct, sw, rm, dup;
+        char       *ptr, *rptr;
+        char       tbuf[82], tdup[82];
+#if (CONFIG_ARCH_S390X)
+        char       addr[22];
+#else
+        char       addr[12];
+#endif
+        char       boff[12];
+        char       bhex[82], duphex[82];
+        char       basc[40];
+
+        sw  = 0;
+        rptr =ptr=buf;
+        rm  = 16;
+        duphex[0]  = 0x00;
+        dup = 0;
+        for ( ct=0; ct < len; ct++, ptr++, rptr++ )  {
+                if (sw == 0) {
+#if (CONFIG_ARCH_S390X)
+                        sprintf(addr, "%16.16lX",(unsigned long)rptr);
+#else
+                        sprintf(addr, "%8.8X",(__u32)rptr);
+#endif
+                        sprintf(boff, "%4.4X", (__u32)ct);
+                        bhex[0] = '\0';
+                        basc[0] = '\0';
+                }
+                if ((sw == 4) || (sw == 12)) {
+                        strcat(bhex, " ");
+                }
+                if (sw == 8) {
+                        strcat(bhex, "  ");
+                }
+#if (CONFIG_ARCH_S390X)
+                sprintf(tbuf,"%2.2lX", (unsigned long)*ptr);
+#else
+                sprintf(tbuf,"%2.2X", (__u32)*ptr);
+#endif
+                tbuf[2] = '\0';
+                strcat(bhex, tbuf);
+                if ((0!=isprint(*ptr)) && (*ptr >= 0x20)) {
+                        basc[sw] = *ptr;
+                }
+                else {
+                        basc[sw] = '.';
+                }
+                basc[sw+1] = '\0';
+                sw++;
+                rm--;
+                if (sw==16) {
+                        if ((strcmp(duphex, bhex)) !=0) {
+                                if (dup !=0) {
+					sprintf(tdup,"Duplicate as above to"
+						" %s", addr);
+                                        printk( KERN_INFO "                 "
+						"   --- %s ---\n",tdup);
+                                }
+                                printk( KERN_INFO "   %s (+%s) : %s  [%s]\n",
+					 addr, boff, bhex, basc);
+                                dup = 0;
+                                strcpy(duphex, bhex);
+                        }
+                        else {
+                                dup++;
+                        }
+                        sw = 0;
+                        rm = 16;
+                }
+        }  /* endfor */
+
+        if (sw != 0) {
+                for ( ; rm > 0; rm--, sw++ ) {
+                        if ((sw==4) || (sw==12)) strcat(bhex, " ");
+                        if (sw==8)               strcat(bhex, "  ");
+                        strcat(bhex, "  ");
+                        strcat(basc, " ");
+                }
+                if (dup !=0) {
+                        sprintf(tdup,"Duplicate as above to %s", addr);
+                        printk( KERN_INFO "                    --- %s ---\n",
+				tdup);
+                }
+                printk( KERN_INFO "   %s (+%s) : %s  [%s]\n",
+			addr, boff, bhex, basc);
+        }
+        else {
+                if (dup >=1) {
+                        sprintf(tdup,"Duplicate as above to %s", addr);
+                        printk( KERN_INFO "                    --- %s ---\n",
+				tdup);
+                }
+                if (dup !=0) {
+                        printk( KERN_INFO "   %s (+%s) : %s  [%s]\n",
+				addr, boff, bhex, basc);
+                }
+        }
+        return;
+
+}   /*   end of dumpit  */
+#endif
+
+/*-------------------------------------------------------------------*
+*               find_link                                            *
+*--------------------------------------------------------------------*/
+static int
+find_link(struct net_device *dev, char *host_name, char *ws_name )
+{
+	struct claw_privbk *privptr;
+	struct claw_env *p_env;
+	int    rc=0;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s > enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"findlink");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev = \n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable host_name = %s\n",dev->name, host_name);
+        printk(KERN_INFO "%s: variable ws_name = %s\n",dev->name, ws_name);
+#endif
+        privptr=dev->priv;
+        p_env=privptr->p_env;
+	switch (p_env->packing)
+	{
+		case  PACKING_ASK:
+			if ((memcmp(WS_APPL_NAME_PACKED, host_name, 8)!=0) ||
+			    (memcmp(WS_APPL_NAME_PACKED, ws_name, 8)!=0 ))
+        	             rc = EINVAL;
+			break;
+		case  DO_PACKED:
+		case  PACK_SEND:
+			if ((memcmp(WS_APPL_NAME_IP_NAME, host_name, 8)!=0) ||
+			    (memcmp(WS_APPL_NAME_IP_NAME, ws_name, 8)!=0 ))
+        	        	rc = EINVAL;
+			break;
+		default:
+	       		if ((memcmp(HOST_APPL_NAME, host_name, 8)!=0) ||
+		    	    (memcmp(p_env->api_type , ws_name, 8)!=0))
+        	        	rc = EINVAL;
+			break;
+	}
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+        return 0;
+}    /*    end of find_link    */
+
+/*-------------------------------------------------------------------*
+ *   claw_hw_tx                                                      *
+ *                                                                   *
+ *                                                                   *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
+{
+        int                             rc=0;
+        struct claw_privbk 		*privptr;
+        struct ccwbk           *p_this_ccw;
+        struct ccwbk           *p_first_ccw;
+        struct ccwbk           *p_last_ccw;
+        __u32                           numBuffers;
+        signed long                     len_of_data;
+        unsigned long                   bytesInThisBuffer;
+        unsigned char                   *pDataAddress;
+        struct endccw                   *pEnd;
+        struct ccw1                     tempCCW;
+        struct chbk                     *p_ch;
+	struct claw_env			*p_env;
+        int                             lock;
+	struct clawph			*pk_head;
+	struct chbk			*ch;
+#ifdef IOTRACE
+        struct ccwbk                   *p_buf;
+#endif
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"hw_tx");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev skb =\n",dev->name);
+        dumpit((char *) skb, sizeof(struct sk_buff));
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable linkid = %ld\n",dev->name,linkid);
+#endif
+        privptr = (struct claw_privbk *) (dev->priv);
+        p_ch=(struct chbk *)&privptr->channel[WRITE];
+	p_env =privptr->p_env;
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: %s() dump sk_buff  \n",dev->name,__FUNCTION__);
+        dumpit((char *)skb ,sizeof(struct sk_buff));
+#endif
+	claw_free_wrt_buf(dev);	/* Clean up free chain if posible */
+        /*  scan the write queue to free any completed write packets   */
+        p_first_ccw=NULL;
+        p_last_ccw=NULL;
+	if ((p_env->packing >= PACK_SEND) &&
+       	    (skb->cb[1] != 'P')) {
+		skb_push(skb,sizeof(struct clawph));
+		pk_head=(struct clawph *)skb->data;
+		pk_head->len=skb->len-sizeof(struct clawph);
+		if (pk_head->len%4)  {
+			pk_head->len+= 4-(pk_head->len%4);
+			skb_pad(skb,4-(pk_head->len%4));
+			skb_put(skb,4-(pk_head->len%4));
+		}
+		if (p_env->packing == DO_PACKED)
+			pk_head->link_num = linkid;
+		else
+			pk_head->link_num = 0;
+		pk_head->flag = 0x00;
+		skb_pad(skb,4);
+		skb->cb[1] = 'P';
+	}
+        if (linkid == 0) {
+        	if (claw_check_busy(dev)) {
+                	if (privptr->write_free_count!=0) {
+                                claw_clear_busy(dev);
+                        }
+                        else {
+                                claw_strt_out_IO(dev );
+                                claw_free_wrt_buf( dev );
+                                if (privptr->write_free_count==0) {
+#ifdef IOTRACE
+                                	printk(KERN_INFO "%s: "
+					   "(claw_check_busy) no free write "
+					   "buffers\n", dev->name);
+#endif
+					ch = &privptr->channel[WRITE];
+					atomic_inc(&skb->users);
+					skb_queue_tail(&ch->collect_queue, skb);
+                                	goto Done;
+                                }
+                                else {
+                                	claw_clear_busy(dev);
+                                }
+                        }
+                }
+                /*  tx lock  */
+                if (claw_test_and_setbit_busy(TB_TX,dev)) { /* set to busy */
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s:  busy  (claw_test_and_setbit_"
+				"busy)\n", dev->name);
+#endif
+			ch = &privptr->channel[WRITE];
+			atomic_inc(&skb->users);
+			skb_queue_tail(&ch->collect_queue, skb);
+                        claw_strt_out_IO(dev );
+                        rc=-EBUSY;
+                        goto Done2;
+                }
+        }
+        /*      See how many write buffers are required to hold this data */
+        numBuffers= ( skb->len + privptr->p_env->write_size - 1) /
+			( privptr->p_env->write_size);
+
+        /*      If that number of buffers isn't available, give up for now */
+        if (privptr->write_free_count < numBuffers ||
+            privptr->p_write_free_chain == NULL ) {
+
+                claw_setbit_busy(TB_NOBUFFER,dev);
+
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s:  busy  (claw_setbit_busy"
+			"(TB_NOBUFFER))\n", dev->name);
+                printk(KERN_INFO "       free_count: %d, numBuffers : %d\n",
+			(int)privptr->write_free_count,(int) numBuffers );
+#endif
+		ch = &privptr->channel[WRITE];
+		atomic_inc(&skb->users);
+		skb_queue_tail(&ch->collect_queue, skb);
+		CLAW_DBF_TEXT(2,trace,"clawbusy");
+                goto Done2;
+        }
+        pDataAddress=skb->data;
+        len_of_data=skb->len;
+
+        while (len_of_data > 0) {
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: %s() length-of-data is %ld \n",
+			dev->name ,__FUNCTION__,len_of_data);
+                dumpit((char *)pDataAddress ,64);
+#endif
+                p_this_ccw=privptr->p_write_free_chain;  /* get a block */
+		if (p_this_ccw == NULL) { /* lost the race */
+			ch = &privptr->channel[WRITE];
+			atomic_inc(&skb->users);
+			skb_queue_tail(&ch->collect_queue, skb);
+			goto Done2;
+		}
+                privptr->p_write_free_chain=p_this_ccw->next;
+                p_this_ccw->next=NULL;
+                --privptr->write_free_count; /* -1 */
+                bytesInThisBuffer=len_of_data;
+                memcpy( p_this_ccw->p_buffer,pDataAddress, bytesInThisBuffer);
+                len_of_data-=bytesInThisBuffer;
+                pDataAddress+=(unsigned long)bytesInThisBuffer;
+                /*      setup write CCW         */
+                p_this_ccw->write.cmd_code = (linkid * 8) +1;
+                if (len_of_data>0) {
+                        p_this_ccw->write.cmd_code+=MORE_to_COME_FLAG;
+                }
+                p_this_ccw->write.count=bytesInThisBuffer;
+                /*      now add to end of this chain    */
+                if (p_first_ccw==NULL)    {
+                        p_first_ccw=p_this_ccw;
+                }
+                if (p_last_ccw!=NULL) {
+                        p_last_ccw->next=p_this_ccw;
+                        /*      set up TIC ccws         */
+                        p_last_ccw->w_TIC_1.cda=
+				(__u32)__pa(&p_this_ccw->write);
+                }
+                p_last_ccw=p_this_ccw;      /* save new last block */
+#ifdef IOTRACE
+		printk(KERN_INFO "%s: %s() > CCW and Buffer %ld bytes long \n",
+			dev->name,__FUNCTION__,bytesInThisBuffer);
+                dumpit((char *)p_this_ccw, sizeof(struct ccwbk));
+                dumpit((char *)p_this_ccw->p_buffer, 64);
+#endif
+        }
+
+        /*      FirstCCW and LastCCW now contain a new set of write channel
+        *       programs to append to the running channel program
+        */
+
+        if (p_first_ccw!=NULL) {
+                /*      setup ending ccw sequence for this segment              */
+                pEnd=privptr->p_end_ccw;
+                if (pEnd->write1) {
+                        pEnd->write1=0x00;   /* second end ccw is now active */
+                        /*      set up Tic CCWs         */
+                        p_last_ccw->w_TIC_1.cda=
+				(__u32)__pa(&pEnd->write2_nop1);
+                        pEnd->write2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+                        pEnd->write2_nop2.flags    =
+				CCW_FLAG_SLI | CCW_FLAG_SKIP;
+                        pEnd->write2_nop2.cda=0;
+                        pEnd->write2_nop2.count=1;
+                }
+                else {  /*  end of if (pEnd->write1)*/
+                        pEnd->write1=0x01;   /* first end ccw is now active */
+                        /*      set up Tic CCWs         */
+                        p_last_ccw->w_TIC_1.cda=
+				(__u32)__pa(&pEnd->write1_nop1);
+                        pEnd->write1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+                        pEnd->write1_nop2.flags    =
+				CCW_FLAG_SLI | CCW_FLAG_SKIP;
+                        pEnd->write1_nop2.cda=0;
+                        pEnd->write1_nop2.count=1;
+                }  /* end if if (pEnd->write1) */
+
+
+                if (privptr->p_write_active_first==NULL ) {
+                        privptr->p_write_active_first=p_first_ccw;
+                        privptr->p_write_active_last=p_last_ccw;
+                }
+                else {
+
+                        /*      set up Tic CCWs         */
+
+                        tempCCW.cda=(__u32)__pa(&p_first_ccw->write);
+                        tempCCW.count=0;
+                        tempCCW.flags=0;
+                        tempCCW.cmd_code=CCW_CLAW_CMD_TIC;
+
+                        if (pEnd->write1) {
+
+                 /*
+                 * first set of ending CCW's is chained to the new write
+                 * chain, so the second set is chained to the active chain
+                 * Therefore modify the second set to point the new write chain.
+                 * make sure we update the CCW atomically
+                 * so channel does not fetch it when it's only half done
+                 */
+                                memcpy( &pEnd->write2_nop2, &tempCCW ,
+					sizeof(struct ccw1));
+                                privptr->p_write_active_last->w_TIC_1.cda=
+					(__u32)__pa(&p_first_ccw->write);
+                        }
+                        else {
+
+                        /*make sure we update the CCW atomically
+                         *so channel does not fetch it when it's only half done
+                         */
+                                memcpy(&pEnd->write1_nop2, &tempCCW ,
+					sizeof(struct ccw1));
+                                privptr->p_write_active_last->w_TIC_1.cda=
+				        (__u32)__pa(&p_first_ccw->write);
+
+                        } /* end if if (pEnd->write1) */
+
+                        privptr->p_write_active_last->next=p_first_ccw;
+                        privptr->p_write_active_last=p_last_ccw;
+                }
+
+        } /* endif (p_first_ccw!=NULL)  */
+
+
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: %s() >  Dump Active CCW chain \n",
+		dev->name,__FUNCTION__);
+        p_buf=privptr->p_write_active_first;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+        p_buf=(struct ccwbk*)privptr->p_end_ccw;
+        dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+        dev_kfree_skb(skb);
+	if (linkid==0) {
+        	lock=LOCK_NO;
+        }
+        else  {
+                lock=LOCK_YES;
+        }
+        claw_strt_out_IO(dev );
+        /*      if write free count is zero , set NOBUFFER       */
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() > free_count is %d\n",
+		dev->name,__FUNCTION__,
+		(int) privptr->write_free_count );
+#endif
+	if (privptr->write_free_count==0) {
+		claw_setbit_busy(TB_NOBUFFER,dev);
+        }
+Done2:
+	claw_clearbit_busy(TB_TX,dev);
+Done:
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > exit on line %d, rc = %d \n",
+		dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+	return(rc);
+}    /*    end of claw_hw_tx    */
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*     init_ccw_bk                                                    *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+init_ccw_bk(struct net_device *dev)
+{
+
+        __u32   ccw_blocks_required;
+        __u32   ccw_blocks_perpage;
+        __u32   ccw_pages_required;
+        __u32   claw_reads_perpage=1;
+        __u32   claw_read_pages;
+        __u32   claw_writes_perpage=1;
+        __u32   claw_write_pages;
+        void    *p_buff=NULL;
+        struct ccwbk*p_free_chain;
+	struct ccwbk*p_buf;
+	struct ccwbk*p_last_CCWB;
+	struct ccwbk*p_first_CCWB;
+        struct endccw *p_endccw=NULL;
+        addr_t  real_address;
+        struct claw_privbk *privptr=dev->priv;
+        struct clawh *pClawH=NULL;
+        addr_t   real_TIC_address;
+        int i,j;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"init_ccw");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+#endif
+
+        /*  initialize  statistics field */
+        privptr->active_link_ID=0;
+        /*  initialize  ccwbk pointers  */
+        privptr->p_write_free_chain=NULL;   /* pointer to free ccw chain*/
+        privptr->p_write_active_first=NULL; /* pointer to the first write ccw*/
+        privptr->p_write_active_last=NULL;  /* pointer to the last write ccw*/
+        privptr->p_read_active_first=NULL;  /* pointer to the first read ccw*/
+        privptr->p_read_active_last=NULL;   /* pointer to the last read ccw */
+        privptr->p_end_ccw=NULL;            /* pointer to ending ccw        */
+        privptr->p_claw_signal_blk=NULL;    /* pointer to signal block      */
+	privptr->buffs_alloc = 0;
+        memset(&privptr->end_ccw, 0x00, sizeof(struct endccw));
+        memset(&privptr->ctl_bk, 0x00, sizeof(struct clawctl));
+        /*  initialize  free write ccwbk counter  */
+        privptr->write_free_count=0;  /* number of free bufs on write chain */
+        p_last_CCWB = NULL;
+        p_first_CCWB= NULL;
+        /*
+        *  We need 1 CCW block for each read buffer, 1 for each
+        *  write buffer, plus 1 for ClawSignalBlock
+        */
+        ccw_blocks_required =
+		privptr->p_env->read_buffers+privptr->p_env->write_buffers+1;
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() "
+		"ccw_blocks_required=%d\n",
+		dev->name,__FUNCTION__,
+		ccw_blocks_required);
+        printk(KERN_INFO "%s: %s() "
+		"PAGE_SIZE=0x%x\n",
+		dev->name,__FUNCTION__,
+		(unsigned int)PAGE_SIZE);
+        printk(KERN_INFO "%s: %s() > "
+		"PAGE_MASK=0x%x\n",
+		dev->name,__FUNCTION__,
+		(unsigned int)PAGE_MASK);
+#endif
+        /*
+        * compute number of CCW blocks that will fit in a page
+        */
+        ccw_blocks_perpage= PAGE_SIZE /  CCWBK_SIZE;
+        ccw_pages_required=
+		(ccw_blocks_required+ccw_blocks_perpage -1) /
+			 ccw_blocks_perpage;
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() > ccw_blocks_perpage=%d\n",
+		dev->name,__FUNCTION__,
+		ccw_blocks_perpage);
+        printk(KERN_INFO "%s: %s() > ccw_pages_required=%d\n",
+		dev->name,__FUNCTION__,
+		ccw_pages_required);
+#endif
+        /*
+         *  read and write sizes are set by 2 constants in claw.h
+	 *  4k and 32k.  Unpacked values other than 4k are not going to
+	 * provide good performance. With packing buffers support 32k
+	 * buffers are used.
+         */
+        if (privptr->p_env->read_size < PAGE_SIZE) {
+            claw_reads_perpage= PAGE_SIZE / privptr->p_env->read_size;
+            claw_read_pages= (privptr->p_env->read_buffers +
+	    	claw_reads_perpage -1) / claw_reads_perpage;
+         }
+         else {       /* > or equal  */
+            privptr->p_buff_pages_perread=
+	    	(privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
+            claw_read_pages=
+	    	privptr->p_env->read_buffers * privptr->p_buff_pages_perread;
+         }
+        if (privptr->p_env->write_size < PAGE_SIZE) {
+            claw_writes_perpage=
+	    	PAGE_SIZE / privptr->p_env->write_size;
+            claw_write_pages=
+	    	(privptr->p_env->write_buffers + claw_writes_perpage -1) /
+			claw_writes_perpage;
+
+        }
+        else {      /* >  or equal  */
+            privptr->p_buff_pages_perwrite=
+	    	 (privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
+            claw_write_pages=
+	     	privptr->p_env->write_buffers * privptr->p_buff_pages_perwrite;
+        }
+#ifdef DEBUGMSG
+        if (privptr->p_env->read_size < PAGE_SIZE) {
+            printk(KERN_INFO "%s: %s() reads_perpage=%d\n",
+	    	dev->name,__FUNCTION__,
+		claw_reads_perpage);
+        }
+        else {
+            printk(KERN_INFO "%s: %s() pages_perread=%d\n",
+	    	dev->name,__FUNCTION__,
+		privptr->p_buff_pages_perread);
+        }
+        printk(KERN_INFO "%s: %s() read_pages=%d\n",
+		dev->name,__FUNCTION__,
+		claw_read_pages);
+        if (privptr->p_env->write_size < PAGE_SIZE) {
+            printk(KERN_INFO "%s: %s() writes_perpage=%d\n",
+	    	dev->name,__FUNCTION__,
+		claw_writes_perpage);
+        }
+        else {
+            printk(KERN_INFO "%s: %s() pages_perwrite=%d\n",
+	    	dev->name,__FUNCTION__,
+		privptr->p_buff_pages_perwrite);
+        }
+        printk(KERN_INFO "%s: %s() write_pages=%d\n",
+		dev->name,__FUNCTION__,
+		claw_write_pages);
+#endif
+
+
+        /*
+        *               allocate ccw_pages_required
+        */
+        if (privptr->p_buff_ccw==NULL) {
+                privptr->p_buff_ccw=
+			(void *)__get_free_pages(__GFP_DMA,
+		        (int)pages_to_order_of_mag(ccw_pages_required ));
+                if (privptr->p_buff_ccw==NULL) {
+                        printk(KERN_INFO "%s: %s()  "
+				"__get_free_pages for CCWs failed : "
+				"pages is %d\n",
+                                dev->name,__FUNCTION__,
+				ccw_pages_required );
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s: %s() > "
+				"exit on line %d, rc = ENOMEM\n",
+				dev->name,__FUNCTION__,
+				 __LINE__);
+#endif
+                        return -ENOMEM;
+                }
+                privptr->p_buff_ccw_num=ccw_pages_required;
+        }
+        memset(privptr->p_buff_ccw, 0x00,
+		privptr->p_buff_ccw_num * PAGE_SIZE);
+
+        /*
+        *               obtain ending ccw block address
+        *
+        */
+        privptr->p_end_ccw = (struct endccw *)&privptr->end_ccw;
+        real_address  = (__u32)__pa(privptr->p_end_ccw);
+        /*                              Initialize ending CCW block       */
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() begin initialize ending CCW blocks\n",
+		dev->name,__FUNCTION__);
+#endif
+
+        p_endccw=privptr->p_end_ccw;
+        p_endccw->real=real_address;
+        p_endccw->write1=0x00;
+        p_endccw->read1=0x00;
+
+        /*      write1_nop1                                     */
+        p_endccw->write1_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+        p_endccw->write1_nop1.flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
+        p_endccw->write1_nop1.count       = 1;
+        p_endccw->write1_nop1.cda         = 0;
+
+        /*      write1_nop2                                     */
+        p_endccw->write1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+        p_endccw->write1_nop2.flags        = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+        p_endccw->write1_nop2.count      = 1;
+        p_endccw->write1_nop2.cda        = 0;
+
+        /*      write2_nop1                                     */
+        p_endccw->write2_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+        p_endccw->write2_nop1.flags        = CCW_FLAG_SLI | CCW_FLAG_CC;
+        p_endccw->write2_nop1.count        = 1;
+        p_endccw->write2_nop1.cda          = 0;
+
+        /*      write2_nop2                                     */
+        p_endccw->write2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+        p_endccw->write2_nop2.flags        = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+        p_endccw->write2_nop2.count        = 1;
+        p_endccw->write2_nop2.cda          = 0;
+
+        /*      read1_nop1                                      */
+        p_endccw->read1_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+        p_endccw->read1_nop1.flags        = CCW_FLAG_SLI | CCW_FLAG_CC;
+        p_endccw->read1_nop1.count        = 1;
+        p_endccw->read1_nop1.cda          = 0;
+
+        /*      read1_nop2                                      */
+        p_endccw->read1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+        p_endccw->read1_nop2.flags        = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+        p_endccw->read1_nop2.count        = 1;
+        p_endccw->read1_nop2.cda          = 0;
+
+        /*      read2_nop1                                      */
+        p_endccw->read2_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+        p_endccw->read2_nop1.flags        = CCW_FLAG_SLI | CCW_FLAG_CC;
+        p_endccw->read2_nop1.count        = 1;
+        p_endccw->read2_nop1.cda          = 0;
+
+        /*      read2_nop2                                      */
+        p_endccw->read2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+        p_endccw->read2_nop2.flags        = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+        p_endccw->read2_nop2.count        = 1;
+        p_endccw->read2_nop2.cda          = 0;
+
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: %s() dump claw ending CCW BK \n",
+		dev->name,__FUNCTION__);
+        dumpit((char *)p_endccw, sizeof(struct endccw));
+#endif
+
+        /*
+        *                               Build a chain of CCWs
+        *
+        */
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s()  Begin build a chain of CCW buffer \n",
+		dev->name,__FUNCTION__);
+#endif
+        p_buff=privptr->p_buff_ccw;
+
+        p_free_chain=NULL;
+        for (i=0 ; i < ccw_pages_required; i++ ) {
+                real_address  = (__u32)__pa(p_buff);
+                p_buf=p_buff;
+                for (j=0 ; j < ccw_blocks_perpage ; j++) {
+                        p_buf->next  = p_free_chain;
+                        p_free_chain = p_buf;
+                        p_buf->real=(__u32)__pa(p_buf);
+                        ++p_buf;
+                }
+                p_buff+=PAGE_SIZE;
+        }
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() "
+		"End build a chain of CCW buffer \n",
+			dev->name,__FUNCTION__);
+        p_buf=p_free_chain;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+#endif
+
+        /*
+        *                               Initialize ClawSignalBlock
+        *
+        */
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() "
+		"Begin initialize ClawSignalBlock \n",
+		dev->name,__FUNCTION__);
+#endif
+        if (privptr->p_claw_signal_blk==NULL) {
+                privptr->p_claw_signal_blk=p_free_chain;
+                p_free_chain=p_free_chain->next;
+                pClawH=(struct clawh *)privptr->p_claw_signal_blk;
+                pClawH->length=0xffff;
+                pClawH->opcode=0xff;
+                pClawH->flag=CLAW_BUSY;
+        }
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() >  End initialize "
+	 	"ClawSignalBlock\n",
+		dev->name,__FUNCTION__);
+        dumpit((char *)privptr->p_claw_signal_blk, sizeof(struct ccwbk));
+#endif
+
+        /*
+        *               allocate write_pages_required and add to free chain
+        */
+        if (privptr->p_buff_write==NULL) {
+            if (privptr->p_env->write_size < PAGE_SIZE) {
+                privptr->p_buff_write=
+			(void *)__get_free_pages(__GFP_DMA,
+			(int)pages_to_order_of_mag(claw_write_pages ));
+                if (privptr->p_buff_write==NULL) {
+                        printk(KERN_INFO "%s: %s() __get_free_pages for write"
+				" bufs failed : get is for %d pages\n",
+                                dev->name,__FUNCTION__,claw_write_pages );
+                        free_pages((unsigned long)privptr->p_buff_ccw,
+			   (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+                        privptr->p_buff_ccw=NULL;
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s: %s() > exit on line %d,"
+			 	"rc = ENOMEM\n",
+				dev->name,__FUNCTION__,__LINE__);
+#endif
+                        return -ENOMEM;
+                }
+                /*
+                *                               Build CLAW write free chain
+                *
+                */
+
+                memset(privptr->p_buff_write, 0x00,
+			ccw_pages_required * PAGE_SIZE);
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: %s() Begin build claw write free "
+			"chain \n",dev->name,__FUNCTION__);
+#endif
+                privptr->p_write_free_chain=NULL;
+
+                p_buff=privptr->p_buff_write;
+
+                for (i=0 ; i< privptr->p_env->write_buffers ; i++) {
+                        p_buf        = p_free_chain;      /*  get a CCW */
+                        p_free_chain = p_buf->next;
+                        p_buf->next  =privptr->p_write_free_chain;
+                        privptr->p_write_free_chain = p_buf;
+                        p_buf-> p_buffer	= (struct clawbuf *)p_buff;
+                        p_buf-> write.cda       = (__u32)__pa(p_buff);
+                        p_buf-> write.flags     = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> w_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+                        p_buf-> w_read_FF.flags   = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> w_read_FF.count   = 1;
+                        p_buf-> w_read_FF.cda     =
+				(__u32)__pa(&p_buf-> header.flag);
+                        p_buf-> w_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+                        p_buf-> w_TIC_1.flags      = 0;
+                        p_buf-> w_TIC_1.count      = 0;
+
+                        if (((unsigned long)p_buff+privptr->p_env->write_size) >=
+			   ((unsigned long)(p_buff+2*
+				(privptr->p_env->write_size) -1) & PAGE_MASK)) {
+                        p_buff= p_buff+privptr->p_env->write_size;
+                        }
+                }
+           }
+           else      /*  Buffers are => PAGE_SIZE. 1 buff per get_free_pages */
+           {
+               privptr->p_write_free_chain=NULL;
+               for (i = 0; i< privptr->p_env->write_buffers ; i++) {
+                   p_buff=(void *)__get_free_pages(__GFP_DMA,
+		        (int)pages_to_order_of_mag(
+			privptr->p_buff_pages_perwrite) );
+#ifdef IOTRACE
+                   printk(KERN_INFO "%s:%s __get_free_pages "
+		    "for writes buf: get for %d pages\n",
+		    dev->name,__FUNCTION__,
+		    privptr->p_buff_pages_perwrite);
+#endif
+                   if (p_buff==NULL) {
+                        printk(KERN_INFO "%s:%s __get_free_pages"
+			 	"for writes buf failed : get is for %d pages\n",
+				dev->name,
+				__FUNCTION__,
+				privptr->p_buff_pages_perwrite );
+                        free_pages((unsigned long)privptr->p_buff_ccw,
+			      (int)pages_to_order_of_mag(
+			      		privptr->p_buff_ccw_num));
+                        privptr->p_buff_ccw=NULL;
+			p_buf=privptr->p_buff_write;
+                        while (p_buf!=NULL) {
+                                free_pages((unsigned long)
+					p_buf->p_buffer,
+					(int)pages_to_order_of_mag(
+					privptr->p_buff_pages_perwrite));
+                                p_buf=p_buf->next;
+                        }
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s: %s exit on line %d, rc = ENOMEM\n",
+			dev->name,
+			__FUNCTION__,
+			__LINE__);
+#endif
+                        return -ENOMEM;
+                   }  /* Error on get_pages   */
+                   memset(p_buff, 0x00, privptr->p_env->write_size );
+                   p_buf         = p_free_chain;
+                   p_free_chain  = p_buf->next;
+                   p_buf->next   = privptr->p_write_free_chain;
+                   privptr->p_write_free_chain = p_buf;
+                   privptr->p_buff_write = p_buf;
+                   p_buf->p_buffer=(struct clawbuf *)p_buff;
+                   p_buf-> write.cda     = (__u32)__pa(p_buff);
+                   p_buf-> write.flags   = CCW_FLAG_SLI | CCW_FLAG_CC;
+                   p_buf-> w_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+                   p_buf-> w_read_FF.flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
+                   p_buf-> w_read_FF.count    = 1;
+                   p_buf-> w_read_FF.cda      =
+			(__u32)__pa(&p_buf-> header.flag);
+                   p_buf-> w_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+                   p_buf-> w_TIC_1.flags   = 0;
+                   p_buf-> w_TIC_1.count   = 0;
+               }  /* for all write_buffers   */
+
+           }    /* else buffers are PAGE_SIZE or bigger */
+
+        }
+        privptr->p_buff_write_num=claw_write_pages;
+        privptr->write_free_count=privptr->p_env->write_buffers;
+
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s:%s  End build claw write free chain \n",
+	dev->name,__FUNCTION__);
+        p_buf=privptr->p_write_free_chain;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+#endif
+        /*
+        *               allocate read_pages_required and chain to free chain
+        */
+        if (privptr->p_buff_read==NULL) {
+            if (privptr->p_env->read_size < PAGE_SIZE)  {
+                privptr->p_buff_read=
+			(void *)__get_free_pages(__GFP_DMA,
+			(int)pages_to_order_of_mag(claw_read_pages) );
+                if (privptr->p_buff_read==NULL) {
+                        printk(KERN_INFO "%s: %s() "
+			 	"__get_free_pages for read buf failed : "
+			 	"get is for %d pages\n",
+                                dev->name,__FUNCTION__,claw_read_pages );
+                        free_pages((unsigned long)privptr->p_buff_ccw,
+				(int)pages_to_order_of_mag(
+					privptr->p_buff_ccw_num));
+			/* free the write pages size is < page size  */
+                        free_pages((unsigned long)privptr->p_buff_write,
+				(int)pages_to_order_of_mag(
+				privptr->p_buff_write_num));
+                        privptr->p_buff_ccw=NULL;
+                        privptr->p_buff_write=NULL;
+#ifdef FUNCTRACE
+                        printk(KERN_INFO "%s: %s() > exit on line %d, rc ="
+				" ENOMEM\n",dev->name,__FUNCTION__,__LINE__);
+#endif
+                        return -ENOMEM;
+                }
+                memset(privptr->p_buff_read, 0x00, claw_read_pages * PAGE_SIZE);
+                privptr->p_buff_read_num=claw_read_pages;
+                /*
+                *                               Build CLAW read free chain
+                *
+                */
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: %s() Begin build claw read free chain \n",
+			dev->name,__FUNCTION__);
+#endif
+                p_buff=privptr->p_buff_read;
+                for (i=0 ; i< privptr->p_env->read_buffers ; i++) {
+                        p_buf        = p_free_chain;
+                        p_free_chain = p_buf->next;
+
+                        if (p_last_CCWB==NULL) {
+                                p_buf->next=NULL;
+                                real_TIC_address=0;
+                                p_last_CCWB=p_buf;
+                        }
+                        else {
+                                p_buf->next=p_first_CCWB;
+                                real_TIC_address=
+				(__u32)__pa(&p_first_CCWB -> read );
+                        }
+
+                        p_first_CCWB=p_buf;
+
+                        p_buf->p_buffer=(struct clawbuf *)p_buff;
+                        /*  initialize read command */
+                        p_buf-> read.cmd_code = CCW_CLAW_CMD_READ;
+                        p_buf-> read.cda = (__u32)__pa(p_buff);
+                        p_buf-> read.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> read.count       = privptr->p_env->read_size;
+
+                        /*  initialize read_h command */
+                        p_buf-> read_h.cmd_code = CCW_CLAW_CMD_READHEADER;
+                        p_buf-> read_h.cda =
+				(__u32)__pa(&(p_buf->header));
+                        p_buf-> read_h.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> read_h.count      = sizeof(struct clawh);
+
+                        /*  initialize Signal command */
+                        p_buf-> signal.cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD;
+                        p_buf-> signal.cda =
+				(__u32)__pa(&(pClawH->flag));
+                        p_buf-> signal.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> signal.count     = 1;
+
+                        /*  initialize r_TIC_1 command */
+                        p_buf-> r_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+                        p_buf-> r_TIC_1.cda = (__u32)real_TIC_address;
+                        p_buf-> r_TIC_1.flags = 0;
+                        p_buf-> r_TIC_1.count      = 0;
+
+                        /*  initialize r_read_FF command */
+                        p_buf-> r_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+                        p_buf-> r_read_FF.cda =
+				(__u32)__pa(&(pClawH->flag));
+                        p_buf-> r_read_FF.flags =
+				CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI;
+                        p_buf-> r_read_FF.count    = 1;
+
+                        /*    initialize r_TIC_2          */
+                        memcpy(&p_buf->r_TIC_2,
+				&p_buf->r_TIC_1, sizeof(struct ccw1));
+
+                        /*     initialize Header     */
+                        p_buf->header.length=0xffff;
+                        p_buf->header.opcode=0xff;
+                        p_buf->header.flag=CLAW_PENDING;
+
+                        if (((unsigned long)p_buff+privptr->p_env->read_size) >=
+				((unsigned long)(p_buff+2*(privptr->p_env->read_size) -1)
+				 & PAGE_MASK) ) {
+                                p_buff= p_buff+privptr->p_env->read_size;
+                        }
+                        else {
+                                p_buff=
+				(void *)((unsigned long)
+					(p_buff+2*(privptr->p_env->read_size) -1)
+					 & PAGE_MASK) ;
+                        }
+                }   /* for read_buffers   */
+          }         /* read_size < PAGE_SIZE  */
+          else {  /* read Size >= PAGE_SIZE  */
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() Begin build claw read free chain \n",
+		dev->name,__FUNCTION__);
+#endif
+                for (i=0 ; i< privptr->p_env->read_buffers ; i++) {
+                        p_buff = (void *)__get_free_pages(__GFP_DMA,
+				(int)pages_to_order_of_mag(privptr->p_buff_pages_perread) );
+                        if (p_buff==NULL) {
+                                printk(KERN_INFO "%s: %s() __get_free_pages for read "
+					"buf failed : get is for %d pages\n",
+					dev->name,__FUNCTION__,
+                                        privptr->p_buff_pages_perread );
+                                free_pages((unsigned long)privptr->p_buff_ccw,
+					(int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+				/* free the write pages  */
+	                        p_buf=privptr->p_buff_write;
+                                while (p_buf!=NULL) {
+                                        free_pages((unsigned long)p_buf->p_buffer,
+						(int)pages_to_order_of_mag(
+						privptr->p_buff_pages_perwrite ));
+                                        p_buf=p_buf->next;
+                                }
+				/* free any read pages already alloc  */
+	                        p_buf=privptr->p_buff_read;
+                                while (p_buf!=NULL) {
+                                        free_pages((unsigned long)p_buf->p_buffer,
+						(int)pages_to_order_of_mag(
+						privptr->p_buff_pages_perread ));
+                                        p_buf=p_buf->next;
+                                }
+                                privptr->p_buff_ccw=NULL;
+                                privptr->p_buff_write=NULL;
+#ifdef FUNCTRACE
+                                printk(KERN_INFO "%s: %s() exit on line %d, rc = ENOMEM\n",
+					dev->name,__FUNCTION__,
+					__LINE__);
+#endif
+                                return -ENOMEM;
+                        }
+                        memset(p_buff, 0x00, privptr->p_env->read_size);
+                        p_buf        = p_free_chain;
+                        privptr->p_buff_read = p_buf;
+                        p_free_chain = p_buf->next;
+
+                        if (p_last_CCWB==NULL) {
+                                p_buf->next=NULL;
+                                real_TIC_address=0;
+                                p_last_CCWB=p_buf;
+                        }
+                        else {
+                                p_buf->next=p_first_CCWB;
+                                real_TIC_address=
+					(addr_t)__pa(
+						&p_first_CCWB -> read );
+                        }
+
+                        p_first_CCWB=p_buf;
+				/* save buff address */
+                        p_buf->p_buffer=(struct clawbuf *)p_buff;
+                        /*  initialize read command */
+                        p_buf-> read.cmd_code = CCW_CLAW_CMD_READ;
+                        p_buf-> read.cda = (__u32)__pa(p_buff);
+                        p_buf-> read.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> read.count       = privptr->p_env->read_size;
+
+                        /*  initialize read_h command */
+                        p_buf-> read_h.cmd_code = CCW_CLAW_CMD_READHEADER;
+                        p_buf-> read_h.cda =
+				(__u32)__pa(&(p_buf->header));
+                        p_buf-> read_h.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> read_h.count      = sizeof(struct clawh);
+
+                        /*  initialize Signal command */
+                        p_buf-> signal.cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD;
+                        p_buf-> signal.cda =
+				(__u32)__pa(&(pClawH->flag));
+                        p_buf-> signal.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        p_buf-> signal.count     = 1;
+
+                        /*  initialize r_TIC_1 command */
+                        p_buf-> r_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+                        p_buf-> r_TIC_1.cda = (__u32)real_TIC_address;
+                        p_buf-> r_TIC_1.flags = 0;
+                        p_buf-> r_TIC_1.count      = 0;
+
+                        /*  initialize r_read_FF command */
+                        p_buf-> r_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+                        p_buf-> r_read_FF.cda =
+				(__u32)__pa(&(pClawH->flag));
+                        p_buf-> r_read_FF.flags =
+				CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI;
+                        p_buf-> r_read_FF.count    = 1;
+
+                        /*    initialize r_TIC_2          */
+                        memcpy(&p_buf->r_TIC_2, &p_buf->r_TIC_1,
+				sizeof(struct ccw1));
+
+                        /*     initialize Header     */
+                        p_buf->header.length=0xffff;
+                        p_buf->header.opcode=0xff;
+                        p_buf->header.flag=CLAW_PENDING;
+
+                }    /* For read_buffers   */
+          }     /*  read_size >= PAGE_SIZE   */
+        }       /*  pBuffread = NULL */
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: %s() >  End build claw read free chain \n",
+		dev->name,__FUNCTION__);
+        p_buf=p_first_CCWB;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+
+#endif
+        add_claw_reads( dev  ,p_first_CCWB , p_last_CCWB);
+	privptr->buffs_alloc = 1;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+        return 0;
+}    /*    end of init_ccw_bk */
+
+/*-------------------------------------------------------------------*
+*                                                                    *
+*       probe_error                                                  *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static void
+probe_error( struct ccwgroup_device *cgdev)
+{
+  struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s enter  \n",__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"proberr");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s variable cgdev =\n",__FUNCTION__);
+        dumpit((char *) cgdev, sizeof(struct ccwgroup_device));
+#endif
+        privptr=(struct claw_privbk *)cgdev->dev.driver_data;
+	if (privptr!=NULL) {
+		if (privptr->p_env != NULL) {
+			kfree(privptr->p_env);
+			privptr->p_env=NULL;
+		}
+        	if (privptr->p_mtc_envelope!=NULL) {
+                	kfree(privptr->p_mtc_envelope);
+                	privptr->p_mtc_envelope=NULL;
+        	}
+                kfree(privptr);
+                privptr=NULL;
+        }
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s > exit on line %d\n",
+		 __FUNCTION__,__LINE__);
+#endif
+
+        return;
+}    /*    probe_error    */
+
+
+
+/*-------------------------------------------------------------------*
+*    claw_process_control                                            *
+*                                                                    *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+claw_process_control( struct net_device *dev, struct ccwbk * p_ccw)
+{
+
+        struct clawbuf *p_buf;
+        struct clawctl  ctlbk;
+        struct clawctl *p_ctlbk;
+        char    temp_host_name[8];
+        char    temp_ws_name[8];
+        struct claw_privbk *privptr;
+        struct claw_env *p_env;
+        struct sysval *p_sysval;
+        struct conncmd *p_connect=NULL;
+        int rc;
+        struct chbk *p_ch = NULL;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() > enter  \n",
+		dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"clw_cntl");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable p_ccw =\n",dev->name);
+        dumpit((char *) p_ccw, sizeof(struct ccwbk *));
+#endif
+        udelay(1000);  /* Wait a ms for the control packets to
+			*catch up to each other */
+        privptr=dev->priv;
+        p_env=privptr->p_env;
+	memcpy( &temp_host_name, p_env->host_name, 8);
+        memcpy( &temp_ws_name, p_env->adapter_name , 8);
+        printk(KERN_INFO "%s: CLAW device %.8s: "
+		"Received Control Packet\n",
+		dev->name, temp_ws_name);
+        if (privptr->release_pend==1) {
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s: %s() > "
+			"exit on line %d, rc=0\n",
+			dev->name,__FUNCTION__,__LINE__);
+#endif
+                return 0;
+        }
+        p_buf=p_ccw->p_buffer;
+        p_ctlbk=&ctlbk;
+	if (p_env->packing == DO_PACKED) { /* packing in progress?*/
+		memcpy(p_ctlbk, &p_buf->buffer[4], sizeof(struct clawctl));
+	} else {
+		memcpy(p_ctlbk, p_buf, sizeof(struct clawctl));
+	}
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: dump claw control data inbound\n",dev->name);
+        dumpit((char *)p_ctlbk, sizeof(struct clawctl));
+#endif
+        switch (p_ctlbk->command)
+        {
+                case SYSTEM_VALIDATE_REQUEST:
+                        if (p_ctlbk->version!=CLAW_VERSION_ID) {
+                                claw_snd_sys_validate_rsp(dev, p_ctlbk,
+					CLAW_RC_WRONG_VERSION );
+                                printk("%s: %d is wrong version id. "
+					"Expected %d\n",
+					dev->name, p_ctlbk->version,
+                                        CLAW_VERSION_ID);
+                        }
+                        p_sysval=(struct sysval *)&(p_ctlbk->data);
+			printk( "%s: Recv Sys Validate Request: "
+				"Vers=%d,link_id=%d,Corr=%d,WS name=%."
+				"8s,Host name=%.8s\n",
+                                dev->name, p_ctlbk->version,
+				p_ctlbk->linkid,
+				p_ctlbk->correlator,
+				p_sysval->WS_name,
+                                p_sysval->host_name);
+                        if (0!=memcmp(temp_host_name,p_sysval->host_name,8)) {
+                                claw_snd_sys_validate_rsp(dev, p_ctlbk,
+					CLAW_RC_NAME_MISMATCH );
+				CLAW_DBF_TEXT(2,setup,"HSTBAD");
+				CLAW_DBF_TEXT_(2,setup,"%s",p_sysval->host_name);
+				CLAW_DBF_TEXT_(2,setup,"%s",temp_host_name);
+                                printk(KERN_INFO "%s:  Host name mismatch\n",
+					dev->name);
+				printk(KERN_INFO "%s: Received :%s: "
+					"expected :%s: \n",
+					dev->name,
+					p_sysval->host_name,
+					temp_host_name);
+                        }
+                        if (0!=memcmp(temp_ws_name,p_sysval->WS_name,8)) {
+                                claw_snd_sys_validate_rsp(dev, p_ctlbk,
+					CLAW_RC_NAME_MISMATCH );
+				CLAW_DBF_TEXT(2,setup,"WSNBAD");
+                                CLAW_DBF_TEXT_(2,setup,"%s",p_sysval->WS_name);
+                                CLAW_DBF_TEXT_(2,setup,"%s",temp_ws_name);
+                                printk(KERN_INFO "%s: WS name mismatch\n",
+					dev->name);
+				 printk(KERN_INFO "%s: Received :%s: "
+                                        "expected :%s: \n",
+                                        dev->name,
+                                        p_sysval->WS_name,
+					temp_ws_name);
+                        }
+                        if (( p_sysval->write_frame_size < p_env->write_size) &&
+			   ( p_env->packing == 0)) {
+                                claw_snd_sys_validate_rsp(dev, p_ctlbk,
+					CLAW_RC_HOST_RCV_TOO_SMALL );
+                                printk(KERN_INFO "%s: host write size is too "
+					"small\n", dev->name);
+				CLAW_DBF_TEXT(2,setup,"wrtszbad");
+                        }
+                        if (( p_sysval->read_frame_size < p_env->read_size) &&
+			   ( p_env->packing == 0)) {
+                                claw_snd_sys_validate_rsp(dev, p_ctlbk,
+					CLAW_RC_HOST_RCV_TOO_SMALL );
+                                printk(KERN_INFO "%s: host read size is too "
+					"small\n", dev->name);
+				CLAW_DBF_TEXT(2,setup,"rdsizbad");
+                        }
+                        claw_snd_sys_validate_rsp(dev, p_ctlbk, 0 );
+                        printk("%s: CLAW device %.8s: System validate"
+				" completed.\n",dev->name, temp_ws_name);
+			printk("%s: sys Validate Rsize:%d Wsize:%d\n",dev->name,
+				p_sysval->read_frame_size,p_sysval->write_frame_size);
+                        privptr->system_validate_comp=1;
+                	if(strncmp(p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+				p_env->packing = PACKING_ASK;
+			}
+                        claw_strt_conn_req(dev);
+                        break;
+
+                case SYSTEM_VALIDATE_RESPONSE:
+			p_sysval=(struct sysval *)&(p_ctlbk->data);
+			printk("%s: Recv Sys Validate Resp: Vers=%d,Corr=%d,RC=%d,"
+				"WS name=%.8s,Host name=%.8s\n",
+                        	dev->name,
+                        	p_ctlbk->version,
+                        	p_ctlbk->correlator,
+                        	p_ctlbk->rc,
+                        	p_sysval->WS_name,
+                        	p_sysval->host_name);
+                        switch (p_ctlbk->rc)
+                        {
+                                case 0:
+                                        printk(KERN_INFO "%s: CLAW device "
+						"%.8s: System validate "
+						"completed.\n",
+                                                dev->name, temp_ws_name);
+					if (privptr->system_validate_comp == 0)
+	                                        claw_strt_conn_req(dev);
+					privptr->system_validate_comp=1;
+                                        break;
+                                case CLAW_RC_NAME_MISMATCH:
+                                        printk(KERN_INFO "%s: Sys Validate "
+						"Resp : Host, WS name is "
+						"mismatch\n",
+                                                dev->name);
+                                        break;
+                                case CLAW_RC_WRONG_VERSION:
+                                        printk(KERN_INFO "%s: Sys Validate "
+						"Resp : Wrong version\n",
+						dev->name);
+                                        break;
+                                case CLAW_RC_HOST_RCV_TOO_SMALL:
+                                        printk(KERN_INFO "%s: Sys Validate "
+						"Resp : bad frame size\n",
+						dev->name);
+                                        break;
+                                default:
+                                        printk(KERN_INFO "%s: Sys Validate "
+						"error code=%d \n",
+						 dev->name, p_ctlbk->rc );
+                                        break;
+                        }
+                        break;
+
+                case CONNECTION_REQUEST:
+                        p_connect=(struct conncmd *)&(p_ctlbk->data);
+                        printk(KERN_INFO "%s: Recv Conn Req: Vers=%d,link_id=%d,"
+				"Corr=%d,HOST appl=%.8s,WS appl=%.8s\n",
+                        	dev->name,
+	                        p_ctlbk->version,
+        	                p_ctlbk->linkid,
+                	        p_ctlbk->correlator,
+                        	p_connect->host_name,
+                      		p_connect->WS_name);
+                        if (privptr->active_link_ID!=0 ) {
+                                claw_snd_disc(dev, p_ctlbk);
+                                printk(KERN_INFO "%s: Conn Req error : "
+					"already logical link is active \n",
+					dev->name);
+                        }
+                        if (p_ctlbk->linkid!=1 ) {
+                                claw_snd_disc(dev, p_ctlbk);
+                                printk(KERN_INFO "%s: Conn Req error : "
+					"req logical link id is not 1\n",
+					dev->name);
+                        }
+                        rc=find_link(dev,
+				p_connect->host_name, p_connect->WS_name);
+                        if (rc!=0) {
+                                claw_snd_disc(dev, p_ctlbk);
+                                printk(KERN_INFO "%s: Conn Req error : "
+					"req appl name does not match\n",
+					 dev->name);
+                        }
+                        claw_send_control(dev,
+				CONNECTION_CONFIRM, p_ctlbk->linkid,
+				p_ctlbk->correlator,
+				0, p_connect->host_name,
+                                p_connect->WS_name);
+			if (p_env->packing == PACKING_ASK) {
+				printk("%s: Now Pack ask\n",dev->name);
+				p_env->packing = PACK_SEND;
+				claw_snd_conn_req(dev,0);
+			}
+                        printk(KERN_INFO "%s: CLAW device %.8s: Connection "
+				"completed link_id=%d.\n",
+				dev->name, temp_ws_name,
+                                p_ctlbk->linkid);
+                        privptr->active_link_ID=p_ctlbk->linkid;
+                        p_ch=&privptr->channel[WRITE];
+                        wake_up(&p_ch->wait);  /* wake up claw_open ( WRITE) */
+                        break;
+                case CONNECTION_RESPONSE:
+                        p_connect=(struct conncmd *)&(p_ctlbk->data);
+                        printk(KERN_INFO "%s: Revc Conn Resp: Vers=%d,link_id=%d,"
+				"Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s\n",
+                                dev->name,
+				p_ctlbk->version,
+				p_ctlbk->linkid,
+				p_ctlbk->correlator,
+				p_ctlbk->rc,
+				p_connect->host_name,
+                                p_connect->WS_name);
+
+                        if (p_ctlbk->rc !=0 ) {
+                                printk(KERN_INFO "%s: Conn Resp error: rc=%d \n",
+					dev->name, p_ctlbk->rc);
+                                return 1;
+                        }
+                        rc=find_link(dev,
+				p_connect->host_name, p_connect->WS_name);
+                        if (rc!=0) {
+                                claw_snd_disc(dev, p_ctlbk);
+                                printk(KERN_INFO "%s: Conn Resp error: "
+					"req appl name does not match\n",
+					 dev->name);
+                        }
+			/* should be until CONNECTION_CONFIRM */
+                        privptr->active_link_ID =  - (p_ctlbk->linkid);
+                        break;
+                case CONNECTION_CONFIRM:
+                        p_connect=(struct conncmd *)&(p_ctlbk->data);
+                        printk(KERN_INFO "%s: Recv Conn Confirm:Vers=%d,link_id=%d,"
+				"Corr=%d,Host appl=%.8s,WS appl=%.8s\n",
+                        dev->name,
+                        p_ctlbk->version,
+                        p_ctlbk->linkid,
+                        p_ctlbk->correlator,
+                        p_connect->host_name,
+                        p_connect->WS_name);
+                        if (p_ctlbk->linkid== -(privptr->active_link_ID)) {
+                                privptr->active_link_ID=p_ctlbk->linkid;
+				if (p_env->packing > PACKING_ASK) {
+					printk(KERN_INFO "%s: Confirmed Now packing\n",dev->name);
+					p_env->packing = DO_PACKED;
+					}
+				p_ch=&privptr->channel[WRITE];
+                                wake_up(&p_ch->wait);
+                        }
+                        else {
+                                printk(KERN_INFO "%s: Conn confirm: "
+					"unexpected linkid=%d \n",
+					dev->name, p_ctlbk->linkid);
+                                claw_snd_disc(dev, p_ctlbk);
+                        }
+                        break;
+                case DISCONNECT:
+                        printk(KERN_INFO "%s: Disconnect: "
+				"Vers=%d,link_id=%d,Corr=%d\n",
+				dev->name, p_ctlbk->version,
+                                p_ctlbk->linkid, p_ctlbk->correlator);
+			if ((p_ctlbk->linkid == 2) &&
+			    (p_env->packing == PACK_SEND)) {
+				privptr->active_link_ID = 1;
+				p_env->packing = DO_PACKED;
+			}
+			else
+	                        privptr->active_link_ID=0;
+                        break;
+                case CLAW_ERROR:
+                        printk(KERN_INFO "%s: CLAW ERROR detected\n",
+				dev->name);
+                        break;
+                default:
+                        printk(KERN_INFO "%s:  Unexpected command code=%d \n",
+				dev->name,  p_ctlbk->command);
+                        break;
+        }
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s() exit on line %d, rc = 0\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+
+        return 0;
+}   /*    end of claw_process_control    */
+
+
+/*-------------------------------------------------------------------*
+*               claw_send_control                                    *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+claw_send_control(struct net_device *dev, __u8 type, __u8 link,
+	 __u8 correlator, __u8 rc, char *local_name, char *remote_name)
+{
+        struct claw_privbk 		*privptr;
+        struct clawctl                  *p_ctl;
+        struct sysval                   *p_sysval;
+        struct conncmd                  *p_connect;
+        struct sk_buff 			*skb;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s > enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"sndcntl");
+#ifdef DEBUGMSG
+	printk(KERN_INFO "%s: Sending Control Packet \n",dev->name);
+        printk(KERN_INFO "%s: variable type = 0x%X, link = "
+		"%d, correlator = %d, rc = %d\n",
+                dev->name,type, link, correlator, rc);
+        printk(KERN_INFO "%s: variable local_name = %s, "
+		"remote_name = %s\n",dev->name, local_name, remote_name);
+#endif
+        privptr=dev->priv;
+        p_ctl=(struct clawctl *)&privptr->ctl_bk;
+
+        p_ctl->command=type;
+        p_ctl->version=CLAW_VERSION_ID;
+        p_ctl->linkid=link;
+        p_ctl->correlator=correlator;
+        p_ctl->rc=rc;
+
+        p_sysval=(struct sysval *)&p_ctl->data;
+        p_connect=(struct conncmd *)&p_ctl->data;
+
+        switch (p_ctl->command) {
+                case SYSTEM_VALIDATE_REQUEST:
+                case SYSTEM_VALIDATE_RESPONSE:
+                        memcpy(&p_sysval->host_name, local_name, 8);
+                        memcpy(&p_sysval->WS_name, remote_name, 8);
+			if (privptr->p_env->packing > 0) {
+                        	p_sysval->read_frame_size=DEF_PACK_BUFSIZE;
+	                        p_sysval->write_frame_size=DEF_PACK_BUFSIZE;
+			} else {
+				/* how big is the piggest group of packets */
+				p_sysval->read_frame_size=privptr->p_env->read_size;
+	                        p_sysval->write_frame_size=privptr->p_env->write_size;
+			}
+                        memset(&p_sysval->reserved, 0x00, 4);
+                        break;
+                case CONNECTION_REQUEST:
+                case CONNECTION_RESPONSE:
+                case CONNECTION_CONFIRM:
+                case DISCONNECT:
+                        memcpy(&p_sysval->host_name, local_name, 8);
+                        memcpy(&p_sysval->WS_name, remote_name, 8);
+			if (privptr->p_env->packing > 0) {
+			/* How big is the biggest packet */
+				p_connect->reserved1[0]=CLAW_FRAME_SIZE;
+                        	p_connect->reserved1[1]=CLAW_FRAME_SIZE;
+			} else {
+	                        memset(&p_connect->reserved1, 0x00, 4);
+        	                memset(&p_connect->reserved2, 0x00, 4);
+			}
+                        break;
+                default:
+                        break;
+        }
+
+        /*      write Control Record to the device                   */
+
+
+        skb = dev_alloc_skb(sizeof(struct clawctl));
+        if (!skb) {
+                printk(  "%s:%s low on mem, returning...\n",
+			dev->name,__FUNCTION__);
+#ifdef DEBUG
+                printk(KERN_INFO "%s:%s Exit, rc = ENOMEM\n",
+			dev->name,__FUNCTION__);
+#endif
+                return -ENOMEM;
+        }
+	memcpy(skb_put(skb, sizeof(struct clawctl)),
+		p_ctl, sizeof(struct clawctl));
+#ifdef IOTRACE
+	 printk(KERN_INFO "%s: outbnd claw cntl data \n",dev->name);
+        dumpit((char *)p_ctl,sizeof(struct clawctl));
+#endif
+	if (privptr->p_env->packing >= PACK_SEND)
+		claw_hw_tx(skb, dev, 1);
+	else
+        	claw_hw_tx(skb, dev, 0);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+
+        return 0;
+}  /*   end of claw_send_control  */
+
+/*-------------------------------------------------------------------*
+*               claw_snd_conn_req                                    *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static int
+claw_snd_conn_req(struct net_device *dev, __u8 link)
+{
+        int                rc;
+        struct claw_privbk *privptr=dev->priv;
+        struct clawctl 	   *p_ctl;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"snd_conn");
+#ifdef  DEBUGMSG
+        printk(KERN_INFO "%s: variable link = %X, dev =\n",dev->name, link);
+        dumpit((char *) dev, sizeof(struct net_device));
+#endif
+	rc = 1;
+        p_ctl=(struct clawctl *)&privptr->ctl_bk;
+	p_ctl->linkid = link;
+        if ( privptr->system_validate_comp==0x00 ) {
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s:%s Exit on line %d, rc = 1\n",
+			dev->name,__FUNCTION__,__LINE__);
+#endif
+                return rc;
+        }
+	if (privptr->p_env->packing == PACKING_ASK )
+		rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+        		WS_APPL_NAME_PACKED, WS_APPL_NAME_PACKED);
+	if (privptr->p_env->packing == PACK_SEND)  {
+		rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+        		WS_APPL_NAME_IP_NAME, WS_APPL_NAME_IP_NAME);
+	}
+	if (privptr->p_env->packing == 0)
+        	rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+       			HOST_APPL_NAME, privptr->p_env->api_type);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+		dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+        return rc;
+
+}  /*  end of claw_snd_conn_req */
+
+
+/*-------------------------------------------------------------------*
+*               claw_snd_disc                                        *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl)
+{
+        int rc;
+        struct conncmd *  p_connect;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"snd_dsc");
+#ifdef  DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable p_ctl",dev->name);
+        dumpit((char *) p_ctl, sizeof(struct clawctl));
+#endif
+        p_connect=(struct conncmd *)&p_ctl->data;
+
+        rc=claw_send_control(dev, DISCONNECT, p_ctl->linkid,
+		p_ctl->correlator, 0,
+                p_connect->host_name, p_connect->WS_name);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+		dev->name,__FUNCTION__, __LINE__, rc);
+#endif
+        return rc;
+}     /*   end of claw_snd_disc    */
+
+
+/*-------------------------------------------------------------------*
+*               claw_snd_sys_validate_rsp                            *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+claw_snd_sys_validate_rsp(struct net_device *dev,
+	struct clawctl *p_ctl, __u32 return_code)
+{
+        struct claw_env *  p_env;
+        struct claw_privbk *privptr;
+        int    rc;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",
+		dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"chkresp");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable return_code = %d, dev =\n",
+		dev->name, return_code);
+        dumpit((char *) dev, sizeof(struct net_device));
+        printk(KERN_INFO "%s: variable p_ctl =\n",dev->name);
+        dumpit((char *) p_ctl, sizeof(struct clawctl));
+#endif
+        privptr = dev->priv;
+        p_env=privptr->p_env;
+        rc=claw_send_control(dev, SYSTEM_VALIDATE_RESPONSE,
+		p_ctl->linkid,
+		p_ctl->correlator,
+                return_code,
+		p_env->host_name,
+		p_env->adapter_name  );
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+		dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+        return rc;
+}     /*    end of claw_snd_sys_validate_rsp    */
+
+/*-------------------------------------------------------------------*
+*               claw_strt_conn_req                                   *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static int
+claw_strt_conn_req(struct net_device *dev )
+{
+        int rc;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"conn_req");
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s: variable dev =\n",dev->name);
+        dumpit((char *) dev, sizeof(struct net_device));
+#endif
+        rc=claw_snd_conn_req(dev, 1);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+		dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+        return rc;
+}    /*   end of claw_strt_conn_req   */
+
+
+
+/*-------------------------------------------------------------------*
+ *   claw_stats                                                      *
+ *-------------------------------------------------------------------*/
+
+static struct
+net_device_stats *claw_stats(struct net_device *dev)
+{
+        struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"stats");
+        privptr = dev->priv;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+        return &privptr->stats;
+}     /*   end of claw_stats   */
+
+
+/*-------------------------------------------------------------------*
+*       unpack_read                                                  *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static void
+unpack_read(struct net_device *dev )
+{
+        struct sk_buff *skb;
+        struct claw_privbk *privptr;
+	struct claw_env    *p_env;
+        struct ccwbk 	*p_this_ccw;
+        struct ccwbk 	*p_first_ccw;
+        struct ccwbk 	*p_last_ccw;
+	struct clawph 	*p_packh;
+	void		*p_packd;
+	struct clawctl 	*p_ctlrec=NULL;
+
+        __u32	len_of_data;
+	__u32	pack_off;
+        __u8	link_num;
+        __u8 	mtc_this_frm=0;
+        __u32	bytes_to_mov;
+        struct chbk *p_ch = NULL;
+        int	i=0;
+	int     p=0;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s enter  \n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"unpkread");
+        p_first_ccw=NULL;
+        p_last_ccw=NULL;
+	p_packh=NULL;
+	p_packd=NULL;
+        privptr=dev->priv;
+	p_env = privptr->p_env;
+        p_this_ccw=privptr->p_read_active_first;
+        i=0;
+	while (p_this_ccw!=NULL && p_this_ccw->header.flag!=CLAW_PENDING) {
+#ifdef IOTRACE
+		printk(KERN_INFO "%s p_this_ccw \n",dev->name);
+                dumpit((char*)p_this_ccw, sizeof(struct ccwbk));
+                printk(KERN_INFO "%s Inbound p_this_ccw->p_buffer(64)"
+			" pk=%d \n",dev->name,p_env->packing);
+                dumpit((char *)p_this_ccw->p_buffer, 64 );
+#endif
+		pack_off = 0;
+		p = 0;
+		p_this_ccw->header.flag=CLAW_PENDING;
+		privptr->p_read_active_first=p_this_ccw->next;
+                p_this_ccw->next=NULL;
+		p_packh = (struct clawph *)p_this_ccw->p_buffer;
+		if ((p_env->packing == PACK_SEND) &&
+		    (p_packh->len == 32)           &&
+		    (p_packh->link_num == 0)) {   /* is it a packed ctl rec? */
+			p_packh++;  /* peek past pack header */
+			p_ctlrec = (struct clawctl *)p_packh;
+			p_packh--;  /* un peek */
+			if ((p_ctlrec->command == CONNECTION_RESPONSE) ||
+		            (p_ctlrec->command == CONNECTION_CONFIRM))
+				p_env->packing = DO_PACKED;
+		}
+		if (p_env->packing == DO_PACKED)
+			link_num=p_packh->link_num;
+		else
+	                link_num=p_this_ccw->header.opcode / 8;
+                if ((p_this_ccw->header.opcode & MORE_to_COME_FLAG)!=0) {
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: %s > More_to_come is ON\n",
+			dev->name,__FUNCTION__);
+#endif
+                        mtc_this_frm=1;
+                        if (p_this_ccw->header.length!=
+				privptr->p_env->read_size ) {
+                                printk(KERN_INFO " %s: Invalid frame detected "
+					"length is %02x\n" ,
+                                        dev->name, p_this_ccw->header.length);
+                        }
+                }
+
+                if (privptr->mtc_skipping) {
+                        /*
+                        *   We're in the mode of skipping past a
+			*   multi-frame message
+                        *   that we can't process for some reason or other.
+                        *   The first frame without the More-To-Come flag is
+			*   the last frame of the skipped message.
+                        */
+                        /*  in case of More-To-Come not set in this frame */
+                        if (mtc_this_frm==0) {
+                                privptr->mtc_skipping=0; /* Ok, the end */
+                                privptr->mtc_logical_link=-1;
+                        }
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s:%s goto next "
+				"frame from MoretoComeSkip \n",
+				dev->name,__FUNCTION__);
+#endif
+                        goto NextFrame;
+                }
+
+                if (link_num==0) {
+                        claw_process_control(dev, p_this_ccw);
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s:%s goto next "
+				"frame from claw_process_control \n",
+				dev->name,__FUNCTION__);
+#endif
+			CLAW_DBF_TEXT(4,trace,"UnpkCntl");
+                        goto NextFrame;
+                }
+unpack_next:
+		if (p_env->packing == DO_PACKED) {
+			if (pack_off > p_env->read_size)
+				goto NextFrame;
+			p_packd = p_this_ccw->p_buffer+pack_off;
+			p_packh = (struct clawph *) p_packd;
+			if ((p_packh->len == 0) || /* all done with this frame? */
+			    (p_packh->flag != 0))
+				goto NextFrame;
+			bytes_to_mov = p_packh->len;
+			pack_off += bytes_to_mov+sizeof(struct clawph);
+			p++;
+		} else {
+                	bytes_to_mov=p_this_ccw->header.length;
+		}
+                if (privptr->mtc_logical_link<0) {
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: %s mtc_logical_link < 0  \n",
+			dev->name,__FUNCTION__);
+#endif
+
+                /*
+                *  if More-To-Come is set in this frame then we don't know
+                *  length of entire message, and hence have to allocate
+		*  large buffer   */
+
+                /*      We are starting a new envelope  */
+                privptr->mtc_offset=0;
+                        privptr->mtc_logical_link=link_num;
+                }
+
+                if (bytes_to_mov > (MAX_ENVELOPE_SIZE- privptr->mtc_offset) ) {
+                        /*      error     */
+#ifdef DEBUGMSG
+                        printk(KERN_INFO "%s: %s > goto next "
+				"frame from MoretoComeSkip \n",
+				dev->name,
+				__FUNCTION__);
+                        printk(KERN_INFO "      bytes_to_mov %d > (MAX_ENVELOPE_"
+				"SIZE-privptr->mtc_offset %d)\n",
+				bytes_to_mov,(MAX_ENVELOPE_SIZE- privptr->mtc_offset));
+#endif
+                        privptr->stats.rx_frame_errors++;
+                        goto NextFrame;
+                }
+		if (p_env->packing == DO_PACKED) {
+			memcpy( privptr->p_mtc_envelope+ privptr->mtc_offset,
+				p_packd+sizeof(struct clawph), bytes_to_mov);
+
+		} else	{
+                	memcpy( privptr->p_mtc_envelope+ privptr->mtc_offset,
+                        	p_this_ccw->p_buffer, bytes_to_mov);
+		}
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: %s() received data \n",
+			dev->name,__FUNCTION__);
+		if (p_env->packing == DO_PACKED)
+			dumpit((char *)p_packd+sizeof(struct clawph),32);
+		else
+	                dumpit((char *)p_this_ccw->p_buffer, 32);
+		printk(KERN_INFO "%s: %s() bytelength %d \n",
+			dev->name,__FUNCTION__,bytes_to_mov);
+#endif
+                if (mtc_this_frm==0) {
+                        len_of_data=privptr->mtc_offset+bytes_to_mov;
+                        skb=dev_alloc_skb(len_of_data);
+                        if (skb) {
+                                memcpy(skb_put(skb,len_of_data),
+					privptr->p_mtc_envelope,
+					len_of_data);
+                                skb->mac.raw=skb->data;
+                                skb->dev=dev;
+                                skb->protocol=htons(ETH_P_IP);
+                                skb->ip_summed=CHECKSUM_UNNECESSARY;
+                                privptr->stats.rx_packets++;
+				privptr->stats.rx_bytes+=len_of_data;
+                                netif_rx(skb);
+#ifdef DEBUGMSG
+                                printk(KERN_INFO "%s: %s() netif_"
+					"rx(skb) completed \n",
+					dev->name,__FUNCTION__);
+#endif
+                        }
+                        else {
+                                privptr->stats.rx_dropped++;
+                                printk(KERN_WARNING "%s: %s() low on memory\n",
+				dev->name,__FUNCTION__);
+                        }
+                        privptr->mtc_offset=0;
+                        privptr->mtc_logical_link=-1;
+                }
+                else {
+                        privptr->mtc_offset+=bytes_to_mov;
+                }
+		if (p_env->packing == DO_PACKED)
+			goto unpack_next;
+NextFrame:
+                /*
+                *   Remove ThisCCWblock from active read queue, and add it
+                *   to queue of free blocks to be reused.
+                */
+                i++;
+                p_this_ccw->header.length=0xffff;
+                p_this_ccw->header.opcode=0xff;
+                /*
+                *       add this one to the free queue for later reuse
+                */
+                if (p_first_ccw==NULL) {
+                        p_first_ccw = p_this_ccw;
+                }
+                else {
+                        p_last_ccw->next = p_this_ccw;
+                }
+                p_last_ccw = p_this_ccw;
+                /*
+                *       chain to next block on active read queue
+                */
+                p_this_ccw = privptr->p_read_active_first;
+		CLAW_DBF_TEXT_(4,trace,"rxpkt %d",p);
+        } /* end of while */
+
+        /*      check validity                  */
+
+#ifdef IOTRACE
+        printk(KERN_INFO "%s:%s processed frame is %d \n",
+		dev->name,__FUNCTION__,i);
+        printk(KERN_INFO "%s:%s  F:%lx L:%lx\n",
+		dev->name,
+		__FUNCTION__,
+		(unsigned long)p_first_ccw,
+		(unsigned long)p_last_ccw);
+#endif
+	CLAW_DBF_TEXT_(4,trace,"rxfrm %d",i);
+        add_claw_reads(dev, p_first_ccw, p_last_ccw);
+        p_ch=&privptr->channel[READ];
+        claw_strt_read(dev, LOCK_YES);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s: %s exit on line %d\n",
+		dev->name, __FUNCTION__, __LINE__);
+#endif
+        return;
+}     /*  end of unpack_read   */
+
+/*-------------------------------------------------------------------*
+*       claw_strt_read                                               *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static void
+claw_strt_read (struct net_device *dev, int lock )
+{
+        int        rc = 0;
+        __u32      parm;
+        unsigned long  saveflags = 0;
+        struct claw_privbk *privptr=dev->priv;
+        struct ccwbk*p_ccwbk;
+        struct chbk *p_ch;
+        struct clawh *p_clawh;
+        p_ch=&privptr->channel[READ];
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter  \n",dev->name,__FUNCTION__);
+        printk(KERN_INFO "%s: variable lock = %d, dev =\n",dev->name, lock);
+        dumpit((char *) dev, sizeof(struct net_device));
+#endif
+	CLAW_DBF_TEXT(4,trace,"StRdNter");
+        p_clawh=(struct clawh *)privptr->p_claw_signal_blk;
+        p_clawh->flag=CLAW_IDLE;    /* 0x00 */
+
+        if ((privptr->p_write_active_first!=NULL &&
+             privptr->p_write_active_first->header.flag!=CLAW_PENDING) ||
+            (privptr->p_read_active_first!=NULL &&
+             privptr->p_read_active_first->header.flag!=CLAW_PENDING )) {
+                p_clawh->flag=CLAW_BUSY;    /* 0xff */
+        }
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s:%s state-%02x\n" ,
+		dev->name,__FUNCTION__, p_ch->claw_state);
+#endif
+        if (lock==LOCK_YES) {
+                spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
+        }
+        if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) {
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s: HOT READ started in %s\n" ,
+			dev->name,__FUNCTION__);
+                p_clawh=(struct clawh *)privptr->p_claw_signal_blk;
+                dumpit((char *)&p_clawh->flag , 1);
+#endif
+		CLAW_DBF_TEXT(4,trace,"HotRead");
+                p_ccwbk=privptr->p_read_active_first;
+                parm = (unsigned long) p_ch;
+                rc = ccw_device_start (p_ch->cdev, &p_ccwbk->read, parm,
+				       0xff, 0);
+                if (rc != 0) {
+                        ccw_check_return_code(p_ch->cdev, rc);
+                }
+        }
+	else {
+#ifdef DEBUGMSG
+		printk(KERN_INFO "%s: No READ started by %s() In progress\n" ,
+			dev->name,__FUNCTION__);
+#endif
+		CLAW_DBF_TEXT(2,trace,"ReadAct");
+	}
+
+        if (lock==LOCK_YES) {
+                spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
+        }
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+	CLAW_DBF_TEXT(4,trace,"StRdExit");
+        return;
+}       /*    end of claw_strt_read    */
+
+/*-------------------------------------------------------------------*
+*       claw_strt_out_IO                                             *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static void
+claw_strt_out_IO( struct net_device *dev )
+{
+        int             	rc = 0;
+        unsigned long   	parm;
+        struct claw_privbk 	*privptr;
+        struct chbk     	*p_ch;
+        struct ccwbk   	*p_first_ccw;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	if (!dev) {
+		return;
+	}
+        privptr=(struct claw_privbk *)dev->priv;
+        p_ch=&privptr->channel[WRITE];
+
+#ifdef DEBUGMSG
+        printk(KERN_INFO "%s:%s state-%02x\n" ,
+		dev->name,__FUNCTION__,p_ch->claw_state);
+#endif
+        CLAW_DBF_TEXT(4,trace,"strt_io");
+        p_first_ccw=privptr->p_write_active_first;
+
+        if (p_ch->claw_state == CLAW_STOP)
+                return;
+        if (p_first_ccw == NULL) {
+#ifdef FUNCTRACE
+                printk(KERN_INFO "%s:%s Exit on line %d\n",
+			dev->name,__FUNCTION__,__LINE__);
+#endif
+                return;
+        }
+        if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) {
+                parm = (unsigned long) p_ch;
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s:%s do_io \n" ,dev->name,__FUNCTION__);
+                dumpit((char *)p_first_ccw, sizeof(struct ccwbk));
+#endif
+		CLAW_DBF_TEXT(2,trace,"StWrtIO");
+                rc = ccw_device_start (p_ch->cdev,&p_first_ccw->write, parm,
+				       0xff, 0);
+                if (rc != 0) {
+                        ccw_check_return_code(p_ch->cdev, rc);
+                }
+        }
+        dev->trans_start = jiffies;
+#ifdef FUNCTRACE
+	printk(KERN_INFO "%s:%s Exit on line %d\n",
+		dev->name,__FUNCTION__,__LINE__);
+#endif
+
+        return;
+}       /*    end of claw_strt_out_IO    */
+
+/*-------------------------------------------------------------------*
+*       Free write buffers                                           *
+*                                                                    *
+*--------------------------------------------------------------------*/
+
+static void
+claw_free_wrt_buf( struct net_device *dev )
+{
+
+        struct claw_privbk *privptr=(struct claw_privbk *)dev->priv;
+        struct ccwbk*p_first_ccw;
+	struct ccwbk*p_last_ccw;
+	struct ccwbk*p_this_ccw;
+	struct ccwbk*p_next_ccw;
+#ifdef IOTRACE
+        struct ccwbk*p_buf;
+#endif
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+        printk(KERN_INFO "%s: free count = %d  variable dev =\n",
+		dev->name,privptr->write_free_count);
+#endif
+	CLAW_DBF_TEXT(4,trace,"freewrtb");
+        /*  scan the write queue to free any completed write packets   */
+        p_first_ccw=NULL;
+        p_last_ccw=NULL;
+#ifdef IOTRACE
+        printk(KERN_INFO "%s:  Dump current CCW chain \n",dev->name  );
+        p_buf=privptr->p_write_active_first;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+        if (p_buf==NULL) {
+                printk(KERN_INFO "%s: privptr->p_write_"
+			"active_first==NULL\n",dev->name  );
+        }
+        p_buf=(struct ccwbk*)privptr->p_end_ccw;
+        dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+        p_this_ccw=privptr->p_write_active_first;
+        while ( (p_this_ccw!=NULL) && (p_this_ccw->header.flag!=CLAW_PENDING))
+        {
+                p_next_ccw = p_this_ccw->next;
+                if (((p_next_ccw!=NULL) &&
+		     (p_next_ccw->header.flag!=CLAW_PENDING)) ||
+                    ((p_this_ccw == privptr->p_write_active_last) &&
+                     (p_this_ccw->header.flag!=CLAW_PENDING))) {
+                        /* The next CCW is OK or this is  */
+			/* the last CCW...free it   @A1A  */
+                        privptr->p_write_active_first=p_this_ccw->next;
+			p_this_ccw->header.flag=CLAW_PENDING;
+                        p_this_ccw->next=privptr->p_write_free_chain;
+			privptr->p_write_free_chain=p_this_ccw;
+                        ++privptr->write_free_count;
+			privptr->stats.tx_bytes+= p_this_ccw->write.count;
+			p_this_ccw=privptr->p_write_active_first;
+                        privptr->stats.tx_packets++;
+                }
+                else {
+			break;
+                }
+        }
+        if (privptr->write_free_count!=0) {
+                claw_clearbit_busy(TB_NOBUFFER,dev);
+        }
+        /*   whole chain removed?   */
+        if (privptr->p_write_active_first==NULL) {
+                privptr->p_write_active_last=NULL;
+#ifdef DEBUGMSG
+                printk(KERN_INFO "%s:%s p_write_"
+			"active_first==NULL\n",dev->name,__FUNCTION__);
+#endif
+        }
+#ifdef IOTRACE
+        printk(KERN_INFO "%s: Dump arranged CCW chain \n",dev->name  );
+        p_buf=privptr->p_write_active_first;
+        while (p_buf!=NULL) {
+                dumpit((char *)p_buf, sizeof(struct ccwbk));
+                p_buf=p_buf->next;
+        }
+        if (p_buf==NULL) {
+                printk(KERN_INFO "%s: privptr->p_write_active_"
+			"first==NULL\n",dev->name  );
+        }
+        p_buf=(struct ccwbk*)privptr->p_end_ccw;
+        dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+
+	CLAW_DBF_TEXT_(4,trace,"FWC=%d",privptr->write_free_count);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit on line %d free_count =%d\n",
+		dev->name,__FUNCTION__, __LINE__,privptr->write_free_count);
+#endif
+        return;
+}
+
+/*-------------------------------------------------------------------*
+*       claw free netdevice                                          *
+*                                                                    *
+*--------------------------------------------------------------------*/
+static void
+claw_free_netdevice(struct net_device * dev, int free_dev)
+{
+	struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"free_dev");
+
+	if (!dev)
+		return;
+	CLAW_DBF_TEXT_(2,setup,"%s",dev->name);
+	privptr = dev->priv;
+	if (dev->flags & IFF_RUNNING)
+		claw_release(dev);
+	if (privptr) {
+		privptr->channel[READ].ndev = NULL;  /* say it's free */
+	}
+	dev->priv=NULL;
+#ifdef MODULE
+	if (free_dev) {
+		free_netdev(dev);
+	}
+#endif
+	CLAW_DBF_TEXT(2,setup,"feee_ok");
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
+#endif
+}
+
+/**
+ * Claw init netdevice
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static void
+claw_init_netdevice(struct net_device * dev)
+{
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"init_dev");
+	CLAW_DBF_TEXT_(2,setup,"%s",dev->name);
+	if (!dev) {
+        printk(KERN_WARNING "claw:%s BAD Device exit line %d\n",
+		__FUNCTION__,__LINE__);
+		CLAW_DBF_TEXT(2,setup,"baddev");
+		return;
+	}
+	dev->mtu = CLAW_DEFAULT_MTU_SIZE;
+	dev->hard_start_xmit = claw_tx;
+	dev->open = claw_open;
+	dev->stop = claw_release;
+	dev->get_stats = claw_stats;
+	dev->change_mtu = claw_change_mtu;
+	dev->hard_header_len = 0;
+	dev->addr_len = 0;
+	dev->type = ARPHRD_SLIP;
+	dev->tx_queue_len = 1300;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	SET_MODULE_OWNER(dev);
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT(2,setup,"initok");
+	return;
+}
+
+/**
+ * Init a new channel in the privptr->channel[i].
+ *
+ * @param cdev  The ccw_device to be added.
+ *
+ * @return 0 on success, !0 on error.
+ */
+static int
+add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
+{
+	struct chbk *p_ch;
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "%s:%s Enter\n",cdev->dev.bus_id,__FUNCTION__);
+#endif
+	CLAW_DBF_TEXT_(2,setup,"%s",cdev->dev.bus_id);
+	privptr->channel[i].flag  = i+1;   /* Read is 1 Write is 2 */
+	p_ch = &privptr->channel[i];
+	p_ch->cdev = cdev;
+	snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
+	sscanf(cdev->dev.bus_id+4,"%x",&p_ch->devno);
+	if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING "%s Out of memory in %s for irb\n",
+			p_ch->id,__FUNCTION__);
+#ifdef FUNCTRACE
+        	printk(KERN_INFO "%s:%s Exit on line %d\n",
+			p_ch->id,__FUNCTION__,__LINE__);
+#endif
+		return -ENOMEM;
+	}
+	memset(p_ch->irb, 0, sizeof (struct irb));
+#ifdef FUNCTRACE
+        	printk(KERN_INFO "%s:%s Exit on line %d\n",
+			cdev->dev.bus_id,__FUNCTION__,__LINE__);
+#endif
+	return 0;
+}
+
+
+/**
+ *
+ * Setup an interface.
+ *
+ * @param cgdev  Device to be setup.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int
+claw_new_device(struct ccwgroup_device *cgdev)
+{
+	struct claw_privbk *privptr;
+	struct claw_env *p_env;
+	struct net_device *dev;
+	int ret;
+
+	pr_debug("%s() called\n", __FUNCTION__);
+	printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id);
+	CLAW_DBF_TEXT(2,setup,"new_dev");
+	privptr = cgdev->dev.driver_data;
+	cgdev->cdev[READ]->dev.driver_data = privptr;
+	cgdev->cdev[WRITE]->dev.driver_data = privptr;
+	if (!privptr)
+		return -ENODEV;
+	p_env = privptr->p_env;
+	sscanf(cgdev->cdev[READ]->dev.bus_id+4,"%x",
+		&p_env->devno[READ]);
+        sscanf(cgdev->cdev[WRITE]->dev.bus_id+4,"%x",
+		&p_env->devno[WRITE]);
+	ret = add_channel(cgdev->cdev[0],0,privptr);
+	if (ret == 0)
+		ret = add_channel(cgdev->cdev[1],1,privptr);
+	if (ret != 0) {
+			printk(KERN_WARNING
+		 	"add channel failed "
+				"with ret = %d\n", ret);
+			goto out;
+	}
+	ret = ccw_device_set_online(cgdev->cdev[READ]);
+	if (ret != 0) {
+		printk(KERN_WARNING
+		 "claw: ccw_device_set_online %s READ failed "
+			"with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret);
+		goto out;
+	}
+	ret = ccw_device_set_online(cgdev->cdev[WRITE]);
+	if (ret != 0) {
+		printk(KERN_WARNING
+		 "claw: ccw_device_set_online %s WRITE failed "
+			"with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret);
+		goto out;
+	}
+	dev = alloc_netdev(0,"claw%d",claw_init_netdevice);
+	if (!dev) {
+		printk(KERN_WARNING "%s:alloc_netdev failed\n",__FUNCTION__);
+		goto out;
+	}
+	dev->priv = privptr;
+	cgdev->dev.driver_data = privptr;
+        cgdev->cdev[READ]->dev.driver_data = privptr;
+        cgdev->cdev[WRITE]->dev.driver_data = privptr;
+	/* sysfs magic */
+        SET_NETDEV_DEV(dev, &cgdev->dev);
+	if (register_netdev(dev) != 0) {
+		claw_free_netdevice(dev, 1);
+		CLAW_DBF_TEXT(2,trace,"regfail");
+		goto out;
+	}
+	dev->flags &=~IFF_RUNNING;
+	if (privptr->buffs_alloc == 0) {
+	        ret=init_ccw_bk(dev);
+		if (ret !=0) {
+			printk(KERN_WARNING
+			 "claw: init_ccw_bk failed with ret=%d\n", ret);
+			unregister_netdev(dev);
+			claw_free_netdevice(dev,1);
+			CLAW_DBF_TEXT(2,trace,"ccwmem");
+			goto out;
+		}
+	}
+	privptr->channel[READ].ndev = dev;
+	privptr->channel[WRITE].ndev = dev;
+	privptr->p_env->ndev = dev;
+
+	printk(KERN_INFO "%s:readsize=%d  writesize=%d "
+		"readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x\n",
+                dev->name, p_env->read_size,
+		p_env->write_size, p_env->read_buffers,
+                p_env->write_buffers, p_env->devno[READ],
+		p_env->devno[WRITE]);
+        printk(KERN_INFO "%s:host_name:%.8s, adapter_name "
+		":%.8s api_type: %.8s\n",
+                dev->name, p_env->host_name,
+		p_env->adapter_name , p_env->api_type);
+	return 0;
+out:
+	ccw_device_set_offline(cgdev->cdev[1]);
+	ccw_device_set_offline(cgdev->cdev[0]);
+
+	return -ENODEV;
+}
+
+static void
+claw_purge_skb_queue(struct sk_buff_head *q)
+{
+        struct sk_buff *skb;
+
+        CLAW_DBF_TEXT(4,trace,"purgque");
+
+        while ((skb = skb_dequeue(q))) {
+                atomic_dec(&skb->users);
+                dev_kfree_skb_irq(skb);
+        }
+}
+
+/**
+ * Shutdown an interface.
+ *
+ * @param cgdev  Device to be shut down.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int
+claw_shutdown_device(struct ccwgroup_device *cgdev)
+{
+	struct claw_privbk *priv;
+	struct net_device *ndev;
+	int	ret;
+
+	pr_debug("%s() called\n", __FUNCTION__);
+	CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id);
+	priv = cgdev->dev.driver_data;
+	if (!priv)
+		return -ENODEV;
+	ndev = priv->channel[READ].ndev;
+	if (ndev) {
+		/* Close the device */
+		printk(KERN_INFO
+			"%s: shuting down \n",ndev->name);
+		if (ndev->flags & IFF_RUNNING)
+			ret = claw_release(ndev);
+		ndev->flags &=~IFF_RUNNING;
+		unregister_netdev(ndev);
+		ndev->priv = NULL;  /* cgdev data, not ndev's to free */
+		claw_free_netdevice(ndev, 1);
+		priv->channel[READ].ndev = NULL;
+		priv->channel[WRITE].ndev = NULL;
+		priv->p_env->ndev = NULL;
+	}
+	ccw_device_set_offline(cgdev->cdev[1]);
+	ccw_device_set_offline(cgdev->cdev[0]);
+	return 0;
+}
+
+static void
+claw_remove_device(struct ccwgroup_device *cgdev)
+{
+	struct claw_privbk *priv;
+
+	pr_debug("%s() called\n", __FUNCTION__);
+	CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id);
+	priv = cgdev->dev.driver_data;
+	if (!priv) {
+		printk(KERN_WARNING "claw: %s() no Priv exiting\n",__FUNCTION__);
+		return;
+	}
+	printk(KERN_INFO "claw: %s() called %s will be removed.\n",
+			__FUNCTION__,cgdev->cdev[0]->dev.bus_id);
+	if (cgdev->state == CCWGROUP_ONLINE)
+		claw_shutdown_device(cgdev);
+	claw_remove_files(&cgdev->dev);
+	if (priv->p_mtc_envelope!=NULL) {
+                kfree(priv->p_mtc_envelope);
+                priv->p_mtc_envelope=NULL;
+        }
+	if (priv->p_env != NULL) {
+		kfree(priv->p_env);
+		priv->p_env=NULL;
+	}
+	if (priv->channel[0].irb != NULL) {
+		kfree(priv->channel[0].irb);
+		priv->channel[0].irb=NULL;
+	}
+	if (priv->channel[1].irb != NULL) {
+		kfree(priv->channel[1].irb);
+		priv->channel[1].irb=NULL;
+	}
+	kfree(priv);
+	cgdev->dev.driver_data=NULL;
+	cgdev->cdev[READ]->dev.driver_data = NULL;
+	cgdev->cdev[WRITE]->dev.driver_data = NULL;
+	put_device(&cgdev->dev);
+}
+
+
+/*
+ * sysfs attributes
+ */
+static ssize_t
+claw_hname_show(struct device *dev, char *buf)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	return sprintf(buf, "%s\n",p_env->host_name);
+}
+
+static ssize_t
+claw_hname_write(struct device *dev, const char *buf, size_t count)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	if (count > MAX_NAME_LEN+1)
+		return -EINVAL;
+	memset(p_env->host_name, 0x20, MAX_NAME_LEN);
+	strncpy(p_env->host_name,buf, count);
+	p_env->host_name[count-1] = 0x20;  /* clear extra 0x0a */
+	p_env->host_name[MAX_NAME_LEN] = 0x00;
+	CLAW_DBF_TEXT(2,setup,"HstnSet");
+        CLAW_DBF_TEXT_(2,setup,"%s",p_env->host_name);
+
+	return count;
+}
+
+static DEVICE_ATTR(host_name, 0644, claw_hname_show, claw_hname_write);
+
+static ssize_t
+claw_adname_show(struct device *dev, char *buf)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	return sprintf(buf, "%s\n",p_env->adapter_name);
+}
+
+static ssize_t
+claw_adname_write(struct device *dev, const char *buf, size_t count)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	if (count > MAX_NAME_LEN+1)
+		return -EINVAL;
+	memset(p_env->adapter_name, 0x20, MAX_NAME_LEN);
+	strncpy(p_env->adapter_name,buf, count);
+	p_env->adapter_name[count-1] = 0x20; /* clear extra 0x0a */
+	p_env->adapter_name[MAX_NAME_LEN] = 0x00;
+	CLAW_DBF_TEXT(2,setup,"AdnSet");
+	CLAW_DBF_TEXT_(2,setup,"%s",p_env->adapter_name);
+
+	return count;
+}
+
+static DEVICE_ATTR(adapter_name, 0644, claw_adname_show, claw_adname_write);
+
+static ssize_t
+claw_apname_show(struct device *dev, char *buf)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	return sprintf(buf, "%s\n",
+		       p_env->api_type);
+}
+
+static ssize_t
+claw_apname_write(struct device *dev, const char *buf, size_t count)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	if (count > MAX_NAME_LEN+1)
+		return -EINVAL;
+	memset(p_env->api_type, 0x20, MAX_NAME_LEN);
+	strncpy(p_env->api_type,buf, count);
+	p_env->api_type[count-1] = 0x20;  /* we get a loose 0x0a */
+	p_env->api_type[MAX_NAME_LEN] = 0x00;
+	if(strncmp(p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+		p_env->read_size=DEF_PACK_BUFSIZE;
+		p_env->write_size=DEF_PACK_BUFSIZE;
+		p_env->packing=PACKING_ASK;
+		CLAW_DBF_TEXT(2,setup,"PACKING");
+	}
+	else {
+		p_env->packing=0;
+		p_env->read_size=CLAW_FRAME_SIZE;
+		p_env->write_size=CLAW_FRAME_SIZE;
+		CLAW_DBF_TEXT(2,setup,"ApiSet");
+	}
+	CLAW_DBF_TEXT_(2,setup,"%s",p_env->api_type);
+	return count;
+}
+
+static DEVICE_ATTR(api_type, 0644, claw_apname_show, claw_apname_write);
+
+static ssize_t
+claw_wbuff_show(struct device *dev, char *buf)
+{
+	struct claw_privbk *priv;
+	struct claw_env * p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	return sprintf(buf, "%d\n", p_env->write_buffers);
+}
+
+static ssize_t
+claw_wbuff_write(struct device *dev, const char *buf, size_t count)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+	int nnn,max;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	sscanf(buf, "%i", &nnn);
+	if (p_env->packing) {
+		max = 64;
+	}
+	else {
+		max = 512;
+	}
+	if ((nnn > max ) || (nnn < 2))
+		return -EINVAL;
+	p_env->write_buffers = nnn;
+	CLAW_DBF_TEXT(2,setup,"Wbufset");
+        CLAW_DBF_TEXT_(2,setup,"WB=%d",p_env->write_buffers);
+	return count;
+}
+
+static DEVICE_ATTR(write_buffer, 0644, claw_wbuff_show, claw_wbuff_write);
+
+static ssize_t
+claw_rbuff_show(struct device *dev, char *buf)
+{
+	struct claw_privbk *priv;
+	struct claw_env *  p_env;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	return sprintf(buf, "%d\n", p_env->read_buffers);
+}
+
+static ssize_t
+claw_rbuff_write(struct device *dev, const char *buf, size_t count)
+{
+	struct claw_privbk *priv;
+	struct claw_env *p_env;
+	int nnn,max;
+
+	priv = dev->driver_data;
+	if (!priv)
+		return -ENODEV;
+	p_env = priv->p_env;
+	sscanf(buf, "%i", &nnn);
+	if (p_env->packing) {
+		max = 64;
+	}
+	else {
+		max = 512;
+	}
+	if ((nnn > max ) || (nnn < 2))
+		return -EINVAL;
+	p_env->read_buffers = nnn;
+	CLAW_DBF_TEXT(2,setup,"Rbufset");
+	CLAW_DBF_TEXT_(2,setup,"RB=%d",p_env->read_buffers);
+	return count;
+}
+
+static DEVICE_ATTR(read_buffer, 0644, claw_rbuff_show, claw_rbuff_write);
+
+static struct attribute *claw_attr[] = {
+	&dev_attr_read_buffer.attr,
+	&dev_attr_write_buffer.attr,
+	&dev_attr_adapter_name.attr,
+	&dev_attr_api_type.attr,
+	&dev_attr_host_name.attr,
+	NULL,
+};
+
+static struct attribute_group claw_attr_group = {
+	.attrs = claw_attr,
+};
+
+static int
+claw_add_files(struct device *dev)
+{
+	pr_debug("%s() called\n", __FUNCTION__);
+	CLAW_DBF_TEXT(2,setup,"add_file");
+	return sysfs_create_group(&dev->kobj, &claw_attr_group);
+}
+
+static void
+claw_remove_files(struct device *dev)
+{
+	pr_debug("%s() called\n", __FUNCTION__);
+	CLAW_DBF_TEXT(2,setup,"rem_file");
+	sysfs_remove_group(&dev->kobj, &claw_attr_group);
+}
+
+/*--------------------------------------------------------------------*
+*    claw_init  and cleanup                                           *
+*---------------------------------------------------------------------*/
+
+static void __exit
+claw_cleanup(void)
+{
+	unregister_cu3088_discipline(&claw_group_driver);
+	claw_unregister_debug_facility();
+	printk(KERN_INFO "claw: Driver unloaded\n");
+
+}
+
+/**
+ * Initialize module.
+ * This is called just after the module is loaded.
+ *
+ * @return 0 on success, !0 on error.
+ */
+static int __init
+claw_init(void)
+{
+	int ret = 0;
+       printk(KERN_INFO "claw: starting driver "
+#ifdef MODULE
+                "module "
+#else
+                "compiled into kernel "
+#endif
+                " $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $ \n");
+
+
+#ifdef FUNCTRACE
+        printk(KERN_INFO "claw: %s() enter \n",__FUNCTION__);
+#endif
+	ret = claw_register_debug_facility();
+	if (ret) {
+		printk(KERN_WARNING "claw: %s() debug_register failed %d\n",
+			__FUNCTION__,ret);
+		return ret;
+	}
+	CLAW_DBF_TEXT(2,setup,"init_mod");
+	ret = register_cu3088_discipline(&claw_group_driver);
+	if (ret) {
+		claw_unregister_debug_facility();
+		printk(KERN_WARNING "claw; %s() cu3088 register failed %d\n",
+			__FUNCTION__,ret);
+	}
+#ifdef FUNCTRACE
+        printk(KERN_INFO "claw: %s() exit \n",__FUNCTION__);
+#endif
+	return ret;
+}
+
+module_init(claw_init);
+module_exit(claw_cleanup);
+
+
+
+/*--------------------------------------------------------------------*
+*    End of File                                                      *
+*---------------------------------------------------------------------*/
+
+
diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/claw.h
@@ -0,0 +1,335 @@
+/*******************************************************
+*  Define constants                                    *
+*                                                      *
+********************************************************/
+#define VERSION_CLAW_H "$Revision: 1.6 $"
+/*-----------------------------------------------------*
+*     CCW command codes for CLAW protocol              *
+*------------------------------------------------------*/
+
+#define CCW_CLAW_CMD_WRITE           0x01      /* write - not including link */
+#define CCW_CLAW_CMD_READ            0x02      /* read */
+#define CCW_CLAW_CMD_NOP             0x03      /* NOP */
+#define CCW_CLAW_CMD_SENSE           0x04      /* Sense */
+#define CCW_CLAW_CMD_SIGNAL_SMOD     0x05      /* Signal Status Modifier */
+#define CCW_CLAW_CMD_TIC             0x08      /* TIC */
+#define CCW_CLAW_CMD_READHEADER      0x12      /* read header data */
+#define CCW_CLAW_CMD_READFF          0x22      /* read an FF */
+#define CCW_CLAW_CMD_SENSEID         0xe4      /* Sense ID */
+
+
+/*-----------------------------------------------------*
+*    CLAW Unique constants                             *
+*------------------------------------------------------*/
+
+#define MORE_to_COME_FLAG       0x04   /* OR with write CCW in case of m-t-c */
+#define CLAW_IDLE               0x00   /* flag to indicate CLAW is idle */
+#define CLAW_BUSY               0xff   /* flag to indicate CLAW is busy */
+#define CLAW_PENDING            0x00   /* flag to indicate i/o is pending */
+#define CLAW_COMPLETE           0xff   /* flag to indicate i/o completed */
+
+/*-----------------------------------------------------*
+*     CLAW control comand code                         *
+*------------------------------------------------------*/
+
+#define SYSTEM_VALIDATE_REQUEST   0x01  /* System Validate request */
+#define SYSTEM_VALIDATE_RESPONSE  0x02  /* System Validate response */
+#define CONNECTION_REQUEST        0x21  /* Connection request */
+#define CONNECTION_RESPONSE       0x22  /* Connection response */
+#define CONNECTION_CONFIRM        0x23  /* Connection confirm */
+#define DISCONNECT                0x24  /* Disconnect */
+#define CLAW_ERROR                0x41  /* CLAW error message */
+#define CLAW_VERSION_ID           2     /* CLAW version ID */
+
+/*-----------------------------------------------------*
+*  CLAW adater sense bytes                             *
+*------------------------------------------------------*/
+
+#define CLAW_ADAPTER_SENSE_BYTE 0x41   /* Stop command issued to adapter */
+
+/*-----------------------------------------------------*
+*      CLAW control command return codes               *
+*------------------------------------------------------*/
+
+#define CLAW_RC_NAME_MISMATCH       166  /*  names do not match */
+#define CLAW_RC_WRONG_VERSION       167  /*  wrong CLAW version number */
+#define CLAW_RC_HOST_RCV_TOO_SMALL  180  /*  Host maximum receive is   */
+					 /*  less than Linux on zSeries*/
+                                         /*  transmit size             */
+
+/*-----------------------------------------------------*
+*      CLAW Constants application name                 *
+*------------------------------------------------------*/
+
+#define HOST_APPL_NAME          "TCPIP   "
+#define WS_APPL_NAME_IP_LINK    "TCPIP   "
+#define WS_APPL_NAME_IP_NAME	"IP      "
+#define WS_APPL_NAME_API_LINK   "API     "
+#define WS_APPL_NAME_PACKED     "PACKED  "
+#define WS_NAME_NOT_DEF         "NOT_DEF "
+#define PACKING_ASK		1
+#define PACK_SEND		2
+#define DO_PACKED		3
+
+#define MAX_ENVELOPE_SIZE       65536
+#define CLAW_DEFAULT_MTU_SIZE   4096
+#define DEF_PACK_BUFSIZE	32768
+#define READ                    0
+#define WRITE                   1
+
+#define TB_TX                   0          /* sk buffer handling in process  */
+#define TB_STOP                 1          /* network device stop in process */
+#define TB_RETRY                2          /* retry in process               */
+#define TB_NOBUFFER             3          /* no buffer on free queue        */
+#define CLAW_MAX_LINK_ID        1
+#define CLAW_MAX_DEV            256        /*      max claw devices          */
+#define MAX_NAME_LEN            8          /* host name, adapter name length */
+#define CLAW_FRAME_SIZE         4096
+#define CLAW_ID_SIZE            BUS_ID_SIZE+3
+
+/* state machine codes used in claw_irq_handler */
+
+#define CLAW_STOP                0
+#define CLAW_START_HALT_IO       1
+#define CLAW_START_SENSEID       2
+#define CLAW_START_READ          3
+#define CLAW_START_WRITE         4
+
+/*-----------------------------------------------------*
+*    Lock flag                                         *
+*------------------------------------------------------*/
+#define LOCK_YES             0
+#define LOCK_NO              1
+
+/*-----------------------------------------------------*
+*    DBF Debug macros                                  *
+*------------------------------------------------------*/
+#define CLAW_DBF_TEXT(level, name, text) \
+	do { \
+		debug_text_event(claw_dbf_##name, level, text); \
+	} while (0)
+
+#define CLAW_DBF_HEX(level,name,addr,len) \
+do { \
+	debug_event(claw_dbf_##name,level,(void*)(addr),len); \
+} while (0)
+
+#define CLAW_DBF_TEXT_(level,name,text...) \
+do {                                       \
+	sprintf(debug_buffer, text);  \
+		debug_text_event(claw_dbf_##name,level, debug_buffer);\
+} while (0)
+
+/*******************************************************
+*  Define Control Blocks                               *
+*                                                      *
+********************************************************/
+
+/*------------------------------------------------------*/
+/*     CLAW header                                      */
+/*------------------------------------------------------*/
+
+struct clawh {
+        __u16  length;     /* length of data read by preceding read CCW */
+        __u8   opcode;     /* equivalent read CCW */
+        __u8   flag;       /* flag of FF to indicate read was completed */
+};
+
+/*------------------------------------------------------*/
+/*     CLAW Packing header   4 bytes                    */
+/*------------------------------------------------------*/
+struct clawph {
+       __u16 len;  	/* Length of Packed Data Area   */
+       __u8  flag;  	/* Reserved not used            */
+       __u8  link_num;	/* Link ID                      */
+};
+
+/*------------------------------------------------------*/
+/*     CLAW Ending struct ccwbk                         */
+/*------------------------------------------------------*/
+struct endccw {
+	__u32     real;            /* real address of this block */
+       __u8      write1;          /* write 1 is active */
+        __u8      read1;           /* read 1 is active  */
+        __u16     reserved;        /* reserved for future use */
+        struct ccw1    write1_nop1;
+        struct ccw1    write1_nop2;
+        struct ccw1    write2_nop1;
+        struct ccw1    write2_nop2;
+        struct ccw1    read1_nop1;
+        struct ccw1    read1_nop2;
+        struct ccw1    read2_nop1;
+        struct ccw1    read2_nop2;
+};
+
+/*------------------------------------------------------*/
+/*     CLAW struct ccwbk                                       */
+/*------------------------------------------------------*/
+struct ccwbk {
+        void   *next;        /* pointer to next ccw block */
+        __u32     real;         /* real address of this ccw */
+        void      *p_buffer;    /* virtual address of data */
+        struct clawh     header;       /* claw header */
+        struct ccw1    write;   /* write CCW    */
+        struct ccw1    w_read_FF; /* read FF */
+        struct ccw1    w_TIC_1;        /* TIC */
+        struct ccw1    read;         /* read CCW  */
+        struct ccw1    read_h;        /* read header */
+        struct ccw1    signal;       /* signal SMOD  */
+        struct ccw1    r_TIC_1;        /* TIC1 */
+        struct ccw1    r_read_FF;      /* read FF  */
+        struct ccw1    r_TIC_2;        /* TIC2 */
+};
+
+/*------------------------------------------------------*/
+/*     CLAW control block                               */
+/*------------------------------------------------------*/
+struct clawctl {
+        __u8    command;      /* control command */
+        __u8    version;      /* CLAW protocol version */
+        __u8    linkid;       /* link ID   */
+        __u8    correlator;   /* correlator */
+        __u8    rc;           /* return code */
+        __u8    reserved1;    /* reserved */
+        __u8    reserved2;    /* reserved */
+        __u8    reserved3;    /* reserved */
+        __u8    data[24];     /* command specific fields */
+};
+
+/*------------------------------------------------------*/
+/*     Data for SYSTEMVALIDATE command                  */
+/*------------------------------------------------------*/
+struct sysval  {
+        char    WS_name[8];        /* Workstation System name  */
+        char    host_name[8];      /* Host system name     */
+        __u16   read_frame_size;   /* read frame size */
+        __u16   write_frame_size;  /* write frame size */
+        __u8    reserved[4];       /* reserved */
+};
+
+/*------------------------------------------------------*/
+/*     Data for Connect command                         */
+/*------------------------------------------------------*/
+struct conncmd  {
+        char     WS_name[8];       /* Workstation application name  */
+        char     host_name[8];     /* Host application name      */
+        __u16    reserved1[2];     /* read frame size */
+        __u8     reserved2[4];     /* reserved  */
+};
+
+/*------------------------------------------------------*/
+/*     Data for CLAW error                              */
+/*------------------------------------------------------*/
+struct clawwerror  {
+        char      reserved1[8];   /* reserved */
+        char      reserved2[8];   /* reserved  */
+        char      reserved3[8];   /* reserved  */
+};
+
+/*------------------------------------------------------*/
+/*     Data buffer for CLAW                             */
+/*------------------------------------------------------*/
+struct clawbuf  {
+       char      buffer[MAX_ENVELOPE_SIZE];   /* data buffer */
+};
+
+/*------------------------------------------------------*/
+/*     Channel control block for read and write channel */
+/*------------------------------------------------------*/
+
+struct chbk {
+        unsigned int        devno;
+        int                 irq;
+	char 		    id[CLAW_ID_SIZE];
+       __u32               IO_active;
+        __u8                claw_state;
+        struct irb          *irb;
+       	struct ccw_device   *cdev;  /* pointer to the channel device */
+	struct net_device   *ndev;
+        wait_queue_head_t   wait;
+        struct tasklet_struct    tasklet;
+        struct timer_list   timer;
+        unsigned long       flag_a;    /* atomic flags */
+#define CLAW_BH_ACTIVE      0
+        unsigned long       flag_b;    /* atomic flags */
+#define CLAW_WRITE_ACTIVE   0
+        __u8                last_dstat;
+        __u8                flag;
+	struct sk_buff_head collect_queue;
+	spinlock_t collect_lock;
+#define CLAW_WRITE      0x02      /* - Set if this is a write channel */
+#define CLAW_READ	0x01      /* - Set if this is a read channel  */
+#define CLAW_TIMER      0x80      /* - Set if timer made the wake_up  */
+};
+
+/*--------------------------------------------------------------*
+*           CLAW  environment block                             *
+*---------------------------------------------------------------*/
+
+struct claw_env {
+        unsigned int            devno[2];       /* device number */
+        char                    host_name[9];   /* Host name */
+        char                    adapter_name [9]; /* adapter name */
+        char                    api_type[9];    /* TCPIP, API or PACKED */
+        void                    *p_priv;        /* privptr */
+        __u16                   read_buffers;   /* read buffer number */
+        __u16                   write_buffers;  /* write buffer number */
+        __u16                   read_size;      /* read buffer size */
+        __u16                   write_size;     /* write buffer size */
+        __u16                   dev_id;         /* device ident */
+	__u8			packing;	/* are we packing? */
+	volatile __u8		queme_switch;   /* gate for imed packing  */
+	volatile unsigned long	pk_delay;	/* Delay for adaptive packing */
+        __u8                    in_use;         /* device active flag */
+        struct net_device       *ndev;    	/* backward ptr to the net dev*/
+};
+
+/*--------------------------------------------------------------*
+*           CLAW  main control block                            *
+*---------------------------------------------------------------*/
+
+struct claw_privbk {
+        void *p_buff_ccw;
+        __u32      p_buff_ccw_num;
+        void  *p_buff_read;
+        __u32      p_buff_read_num;
+        __u32      p_buff_pages_perread;
+        void  *p_buff_write;
+        __u32      p_buff_write_num;
+        __u32      p_buff_pages_perwrite;
+        long       active_link_ID;           /* Active logical link ID */
+        struct ccwbk *p_write_free_chain;     /* pointer to free ccw chain */
+        struct ccwbk *p_write_active_first;   /* ptr to the first write ccw */
+        struct ccwbk *p_write_active_last;    /* ptr to the last write ccw */
+        struct ccwbk *p_read_active_first;    /* ptr to the first read ccw */
+        struct ccwbk *p_read_active_last;     /* ptr to the last read ccw */
+        struct endccw *p_end_ccw;              /*ptr to ending ccw */
+        struct ccwbk *p_claw_signal_blk;      /* ptr to signal block */
+        __u32      write_free_count;       /* number of free bufs for write */
+	struct     net_device_stats  stats; /* 	 device status    */
+        struct chbk channel[2];            /* Channel control blocks */
+        __u8       mtc_skipping;
+        int        mtc_offset;
+        int        mtc_logical_link;
+        void       *p_mtc_envelope;
+	struct	   sk_buff	*pk_skb;	/* packing buffer    */
+	int	   pk_cnt;
+        struct clawctl ctl_bk;
+        struct claw_env *p_env;
+        __u8       system_validate_comp;
+        __u8       release_pend;
+        __u8      checksum_received_ip_pkts;
+	__u8      buffs_alloc;
+        struct endccw  end_ccw;
+        unsigned long  tbusy;
+
+};
+
+
+/************************************************************/
+/* define global constants                                  */
+/************************************************************/
+
+#define CCWBK_SIZE sizeof(struct ccwbk)
+
+
diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h
--- a/drivers/s390/net/ctcdbug.h
+++ b/drivers/s390/net/ctcdbug.h
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.4 $)
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
  *
  * CTC / ESCON network driver - s390 dbf exploit.
  *
@@ -9,7 +9,7 @@
  *    Author(s): Original Code written by
  *			  Peter Tiedemann (ptiedem@de.ibm.com)
  *
- *    $Revision: 1.4 $	 $Date: 2004/10/15 09:26:58 $
+ *    $Revision: 1.5 $	 $Date: 2005/02/27 19:46:44 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,9 +25,11 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
+#ifndef _CTCDBUG_H_
+#define _CTCDBUG_H_
 
 #include <asm/debug.h>
+#include "ctcmain.h"
 /**
  * Debug Facility stuff
  */
@@ -41,7 +43,7 @@
 #define CTC_DBF_DATA_LEN 128
 #define CTC_DBF_DATA_INDEX 3
 #define CTC_DBF_DATA_NR_AREAS 1
-#define CTC_DBF_DATA_LEVEL 2
+#define CTC_DBF_DATA_LEVEL 3
 
 #define CTC_DBF_TRACE_NAME "ctc_trace"
 #define CTC_DBF_TRACE_LEN 16
@@ -121,3 +123,5 @@ hex_dump(unsigned char *buf, size_t len)
 	printk("\n");
 }
 
+
+#endif
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.68 2004/12/27 09:25:27 heicarst Exp $
+ * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $
  *
  * CTC / ESCON network driver
  *
@@ -7,6 +7,7 @@
  * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+	      Peter Tiedemann (ptiedem@de.ibm.com)
  * Driver Model stuff by : Cornelia Huck <cohuck@de.ibm.com>
  *
  * Documentation used:
@@ -36,12 +37,11 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.68 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $
  *
  */
 
 #undef DEBUG
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -73,286 +73,13 @@
 #include "ctctty.h"
 #include "fsm.h"
 #include "cu3088.h"
+
 #include "ctcdbug.h"
+#include "ctcmain.h"
 
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
 MODULE_LICENSE("GPL");
-
-/**
- * CCW commands, used in this driver.
- */
-#define CCW_CMD_WRITE		0x01
-#define CCW_CMD_READ		0x02
-#define CCW_CMD_SET_EXTENDED	0xc3
-#define CCW_CMD_PREPARE		0xe3
-
-#define CTC_PROTO_S390          0
-#define CTC_PROTO_LINUX         1
-#define CTC_PROTO_LINUX_TTY     2
-#define CTC_PROTO_OS390         3
-#define CTC_PROTO_MAX           3
-
-#define CTC_BUFSIZE_LIMIT       65535
-#define CTC_BUFSIZE_DEFAULT     32768
-
-#define CTC_TIMEOUT_5SEC        5000
-
-#define CTC_INITIAL_BLOCKLEN    2
-
-#define READ			0
-#define WRITE			1
-
-#define CTC_ID_SIZE             BUS_ID_SIZE+3
-
-
-struct ctc_profile {
-	unsigned long maxmulti;
-	unsigned long maxcqueue;
-	unsigned long doios_single;
-	unsigned long doios_multi;
-	unsigned long txlen;
-	unsigned long tx_time;
-	struct timespec send_stamp;
-};
-
-/**
- * Definition of one channel
- */
-struct channel {
-
-	/**
-	 * Pointer to next channel in list.
-	 */
-	struct channel *next;
-	char id[CTC_ID_SIZE];
-	struct ccw_device *cdev;
-
-	/**
-	 * Type of this channel.
-	 * CTC/A or Escon for valid channels.
-	 */
-	enum channel_types type;
-
-	/**
-	 * Misc. flags. See CHANNEL_FLAGS_... below
-	 */
-	__u32 flags;
-
-	/**
-	 * The protocol of this channel
-	 */
-	__u16 protocol;
-
-	/**
-	 * I/O and irq related stuff
-	 */
-	struct ccw1 *ccw;
-	struct irb *irb;
-
-	/**
-	 * RX/TX buffer size
-	 */
-	int max_bufsize;
-
-	/**
-	 * Transmit/Receive buffer.
-	 */
-	struct sk_buff *trans_skb;
-
-	/**
-	 * Universal I/O queue.
-	 */
-	struct sk_buff_head io_queue;
-
-	/**
-	 * TX queue for collecting skb's during busy.
-	 */
-	struct sk_buff_head collect_queue;
-
-	/**
-	 * Amount of data in collect_queue.
-	 */
-	int collect_len;
-
-	/**
-	 * spinlock for collect_queue and collect_len
-	 */
-	spinlock_t collect_lock;
-
-	/**
-	 * Timer for detecting unresposive
-	 * I/O operations.
-	 */
-	fsm_timer timer;
-
-	/**
-	 * Retry counter for misc. operations.
-	 */
-	int retry;
-
-	/**
-	 * The finite state machine of this channel
-	 */
-	fsm_instance *fsm;
-
-	/**
-	 * The corresponding net_device this channel
-	 * belongs to.
-	 */
-	struct net_device *netdev;
-
-	struct ctc_profile prof;
-
-	unsigned char *trans_skb_data;
-
-	__u16 logflags;
-};
-
-#define CHANNEL_FLAGS_READ            0
-#define CHANNEL_FLAGS_WRITE           1
-#define CHANNEL_FLAGS_INUSE           2
-#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
-#define CHANNEL_FLAGS_FAILED          8
-#define CHANNEL_FLAGS_WAITIRQ        16
-#define CHANNEL_FLAGS_RWMASK 1
-#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
-
-#define LOG_FLAG_ILLEGALPKT  1
-#define LOG_FLAG_ILLEGALSIZE 2
-#define LOG_FLAG_OVERRUN     4
-#define LOG_FLAG_NOMEM       8
-
-#define CTC_LOGLEVEL_INFO     1
-#define CTC_LOGLEVEL_NOTICE   2
-#define CTC_LOGLEVEL_WARN     4
-#define CTC_LOGLEVEL_EMERG    8
-#define CTC_LOGLEVEL_ERR     16
-#define CTC_LOGLEVEL_DEBUG   32
-#define CTC_LOGLEVEL_CRIT    64
-
-#define CTC_LOGLEVEL_DEFAULT \
-(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
-
-#define CTC_LOGLEVEL_MAX     ((CTC_LOGLEVEL_CRIT<<1)-1)
-
-static int loglevel = CTC_LOGLEVEL_DEFAULT;
-
-#define ctc_pr_debug(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
-
-#define ctc_pr_info(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
-
-#define ctc_pr_notice(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
-
-#define ctc_pr_warn(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
-
-#define ctc_pr_emerg(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
-
-#define ctc_pr_err(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
-
-#define ctc_pr_crit(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
-
-/**
- * Linked list of all detected channels.
- */
-static struct channel *channels = NULL;
-
-struct ctc_priv {
-	struct net_device_stats stats;
-	unsigned long tbusy;
-	/**
-	 * The finite state machine of this interface.
-	 */
-	fsm_instance *fsm;
-	/**
-	 * The protocol of this device
-	 */
-	__u16 protocol;
- 	/**
- 	 * Timer for restarting after I/O Errors
- 	 */
- 	fsm_timer               restart_timer;
-
-	struct channel *channel[2];
-};
-
-/**
- * Definition of our link level header.
- */
-struct ll_header {
-	__u16 length;
-	__u16 type;
-	__u16 unused;
-};
-#define LL_HEADER_LENGTH (sizeof(struct ll_header))
-
-/**
- * Compatibility macros for busy handling
- * of network devices.
- */
-static __inline__ void
-ctc_clear_busy(struct net_device * dev)
-{
-	clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
-	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-		netif_wake_queue(dev);
-}
-
-static __inline__ int
-ctc_test_and_set_busy(struct net_device * dev)
-{
-	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-		netif_stop_queue(dev);
-	return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
-}
-
-/**
- * Print Banner.
- */
-static void
-print_banner(void)
-{
-	static int printed = 0;
-	char vbuf[] = "$Revision: 1.68 $";
-	char *version = vbuf;
-
-	if (printed)
-		return;
-	if ((version = strchr(version, ':'))) {
-		char *p = strchr(version + 1, '$');
-		if (p)
-			*p = '\0';
-	} else
-		version = " ??? ";
-	printk(KERN_INFO "CTC driver Version%s"
-#ifdef DEBUG
-		    " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
-#endif
-		    " initialized\n", version);
-	printed = 1;
-}
-
-/**
- * Return type of a detected device.
- */
-static enum channel_types
-get_channel_type(struct ccw_device_id *id)
-{
-	enum channel_types type = (enum channel_types) id->driver_info;
-
-	if (type == channel_type_ficon)
-		type = channel_type_escon;
-
-	return type;
-}
-
 /**
  * States of the interface statemachine.
  */
@@ -368,7 +95,7 @@ enum dev_states {
 	/**
 	 * MUST be always the last element!!
 	 */
-	NR_DEV_STATES
+	CTC_NR_DEV_STATES
 };
 
 static const char *dev_state_names[] = {
@@ -396,7 +123,7 @@ enum dev_events {
 	/**
 	 * MUST be always the last element!!
 	 */
-	NR_DEV_EVENTS
+	CTC_NR_DEV_EVENTS
 };
 
 static const char *dev_event_names[] = {
@@ -473,40 +200,6 @@ enum ch_events {
 	NR_CH_EVENTS,
 };
 
-static const char *ch_event_names[] = {
-	"ccw_device success",
-	"ccw_device busy",
-	"ccw_device enodev",
-	"ccw_device ioerr",
-	"ccw_device unknown",
-
-	"Status ATTN & BUSY",
-	"Status ATTN",
-	"Status BUSY",
-
-	"Unit check remote reset",
-	"Unit check remote system reset",
-	"Unit check TX timeout",
-	"Unit check TX parity",
-	"Unit check Hardware failure",
-	"Unit check RX parity",
-	"Unit check ZERO",
-	"Unit check Unknown",
-
-	"SubChannel check Unknown",
-
-	"Machine check failure",
-	"Machine check operational",
-
-	"IRQ normal",
-	"IRQ final",
-
-	"Timer",
-
-	"Start",
-	"Stop",
-};
-
 /**
  * States of the channel statemachine.
  */
@@ -542,6 +235,87 @@ enum ch_states {
 	NR_CH_STATES,
 };
 
+static int loglevel = CTC_LOGLEVEL_DEFAULT;
+
+/**
+ * Linked list of all detected channels.
+ */
+static struct channel *channels = NULL;
+
+/**
+ * Print Banner.
+ */
+static void
+print_banner(void)
+{
+	static int printed = 0;
+	char vbuf[] = "$Revision: 1.74 $";
+	char *version = vbuf;
+
+	if (printed)
+		return;
+	if ((version = strchr(version, ':'))) {
+		char *p = strchr(version + 1, '$');
+		if (p)
+			*p = '\0';
+	} else
+		version = " ??? ";
+	printk(KERN_INFO "CTC driver Version%s"
+#ifdef DEBUG
+		    " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
+#endif
+		    " initialized\n", version);
+	printed = 1;
+}
+
+/**
+ * Return type of a detected device.
+ */
+static enum channel_types
+get_channel_type(struct ccw_device_id *id)
+{
+	enum channel_types type = (enum channel_types) id->driver_info;
+
+	if (type == channel_type_ficon)
+		type = channel_type_escon;
+
+	return type;
+}
+
+static const char *ch_event_names[] = {
+	"ccw_device success",
+	"ccw_device busy",
+	"ccw_device enodev",
+	"ccw_device ioerr",
+	"ccw_device unknown",
+
+	"Status ATTN & BUSY",
+	"Status ATTN",
+	"Status BUSY",
+
+	"Unit check remote reset",
+	"Unit check remote system reset",
+	"Unit check TX timeout",
+	"Unit check TX parity",
+	"Unit check Hardware failure",
+	"Unit check RX parity",
+	"Unit check ZERO",
+	"Unit check Unknown",
+
+	"SubChannel check Unknown",
+
+	"Machine check failure",
+	"Machine check operational",
+
+	"IRQ normal",
+	"IRQ final",
+
+	"Timer",
+
+	"Start",
+	"Stop",
+};
+
 static const char *ch_state_names[] = {
 	"Idle",
 	"Stopped",
@@ -1894,13 +1668,15 @@ add_channel(struct ccw_device *cdev, enu
 		return -1;
 	}
 	memset(ch, 0, sizeof (struct channel));
-	if ((ch->ccw = (struct ccw1 *) kmalloc(sizeof (struct ccw1) * 8,
+	if ((ch->ccw = (struct ccw1 *) kmalloc(8*sizeof(struct ccw1),
 					       GFP_KERNEL | GFP_DMA)) == NULL) {
 		kfree(ch);
 		ctc_pr_warn("ctc: Out of memory in add_channel\n");
 		return -1;
 	}
 
+	memset(ch->ccw, 0, 8*sizeof(struct ccw1));	// assure all flags and counters are reset
+
 	/**
 	 * "static" ccws are used in the following way:
 	 *
@@ -1914,26 +1690,21 @@ add_channel(struct ccw_device *cdev, enu
 	 *           4: write (idal allocated on every write).
 	 *           5: nop
 	 * ccw[6..7] (Channel program for initial channel setup):
-	 *           3: set extended mode
-	 *           4: nop
+	 *           6: set extended mode
+	 *           7: nop
 	 *
 	 * ch->ccw[0..5] are initialized in ch_action_start because
 	 * the channel's direction is yet unknown here.
 	 */
 	ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED;
 	ch->ccw[6].flags = CCW_FLAG_SLI;
-	ch->ccw[6].count = 0;
-	ch->ccw[6].cda = 0;
 
 	ch->ccw[7].cmd_code = CCW_CMD_NOOP;
 	ch->ccw[7].flags = CCW_FLAG_SLI;
-	ch->ccw[7].count = 0;
-	ch->ccw[7].cda = 0;
 
 	ch->cdev = cdev;
 	snprintf(ch->id, CTC_ID_SIZE, "ch-%s", cdev->dev.bus_id);
 	ch->type = type;
-	loglevel = CTC_LOGLEVEL_DEFAULT;
 	ch->fsm = init_fsm(ch->id, ch_state_names,
 			   ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
 			   ch_fsm, CH_FSM_LEN, GFP_KERNEL);
@@ -1955,7 +1726,7 @@ add_channel(struct ccw_device *cdev, enu
 	memset(ch->irb, 0, sizeof (struct irb));
 	while (*c && less_than((*c)->id, ch->id))
 		c = &(*c)->next;
-	if (!strncmp((*c)->id, ch->id, CTC_ID_SIZE)) {
+	if (*c && (!strncmp((*c)->id, ch->id, CTC_ID_SIZE))) {
 		ctc_pr_debug(
 			"ctc: add_channel: device %s already in list, "
 			"using old entry\n", (*c)->id);
@@ -2011,6 +1782,8 @@ channel_remove(struct channel *ch)
 				dev_kfree_skb(ch->trans_skb);
 			}
 			kfree(ch->ccw);
+			kfree(ch->irb);
+			kfree(ch);
 			return;
 		}
 		c = &((*c)->next);
@@ -2694,6 +2467,7 @@ ctc_stats(struct net_device * dev)
 /*
  * sysfs attributes
  */
+
 static ssize_t
 buffer_show(struct device *dev, char *buf)
 {
@@ -2703,7 +2477,7 @@ buffer_show(struct device *dev, char *bu
 	if (!priv)
 		return -ENODEV;
 	return sprintf(buf, "%d\n",
-		       priv->channel[READ]->max_bufsize);
+			priv->buffer_size);
 }
 
 static ssize_t
@@ -2712,56 +2486,61 @@ buffer_write(struct device *dev, const c
 	struct ctc_priv *priv;
 	struct net_device *ndev;
 	int bs1;
+	char buffer[16];
 
 	DBF_TEXT(trace, 3, __FUNCTION__);
+	DBF_TEXT(trace, 3, buf);
 	priv = dev->driver_data;
-	if (!priv)
+	if (!priv) {
+		DBF_TEXT(trace, 3, "bfnopriv");
 		return -ENODEV;
+	}
+
+	sscanf(buf, "%u", &bs1);
+	if (bs1 > CTC_BUFSIZE_LIMIT)
+		goto einval;
+	if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+		goto einval;
+	priv->buffer_size = bs1;	// just to overwrite the default
+
 	ndev = priv->channel[READ]->netdev;
-	if (!ndev)
+	if (!ndev) {
+		DBF_TEXT(trace, 3, "bfnondev");
 		return -ENODEV;
-	sscanf(buf, "%u", &bs1);
+	}
 
-	if (bs1 > CTC_BUFSIZE_LIMIT)
-		return -EINVAL;
 	if ((ndev->flags & IFF_RUNNING) &&
 	    (bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))
-		return -EINVAL;
-	if (bs1 < (576 + LL_HEADER_LENGTH + 2))
-		return -EINVAL;
+		goto einval;
 
-	priv->channel[READ]->max_bufsize =
-	    priv->channel[WRITE]->max_bufsize = bs1;
+	priv->channel[READ]->max_bufsize = bs1;
+	priv->channel[WRITE]->max_bufsize = bs1;
 	if (!(ndev->flags & IFF_RUNNING))
 		ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;
 	priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
 	priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
 
+	sprintf(buffer, "%d",priv->buffer_size);
+	DBF_TEXT(trace, 3, buffer);
 	return count;
 
+einval:
+	DBF_TEXT(trace, 3, "buff_err");
+	return -EINVAL;
 }
 
 static ssize_t
 loglevel_show(struct device *dev, char *buf)
 {
-	struct ctc_priv *priv;
-
-	priv = dev->driver_data;
-	if (!priv)
-		return -ENODEV;
 	return sprintf(buf, "%d\n", loglevel);
 }
 
 static ssize_t
 loglevel_write(struct device *dev, const char *buf, size_t count)
 {
-	struct ctc_priv *priv;
 	int ll1;
 
 	DBF_TEXT(trace, 5, __FUNCTION__);
-	priv = dev->driver_data;
-	if (!priv)
-		return -ENODEV;
 	sscanf(buf, "%i", &ll1);
 
 	if ((ll1 > CTC_LOGLEVEL_MAX) || (ll1 < 0))
@@ -2831,27 +2610,6 @@ stats_write(struct device *dev, const ch
 	return count;
 }
 
-static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
-static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
-
-static int
-ctc_add_attributes(struct device *dev)
-{
-//	device_create_file(dev, &dev_attr_buffer);
-	device_create_file(dev, &dev_attr_loglevel);
-	device_create_file(dev, &dev_attr_stats);
-	return 0;
-}
-
-static void
-ctc_remove_attributes(struct device *dev)
-{
-	device_remove_file(dev, &dev_attr_stats);
-	device_remove_file(dev, &dev_attr_loglevel);
-//	device_remove_file(dev, &dev_attr_buffer);
-}
-
 
 static void
 ctc_netdev_unregister(struct net_device * dev)
@@ -2895,51 +2653,6 @@ ctc_free_netdevice(struct net_device * d
 #endif
 }
 
-/**
- * Initialize everything of the net device except the name and the
- * channel structs.
- */
-static struct net_device *
-ctc_init_netdevice(struct net_device * dev, int alloc_device, 
-		   struct ctc_priv *privptr)
-{
-	if (!privptr)
-		return NULL;
-
-	DBF_TEXT(setup, 3, __FUNCTION__);
-	if (alloc_device) {
-		dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
-		if (!dev)
-			return NULL;
-		memset(dev, 0, sizeof (struct net_device));
-	}
-
-	dev->priv = privptr;
-	privptr->fsm = init_fsm("ctcdev", dev_state_names,
-				dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
-				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
-	if (privptr->fsm == NULL) {
-		if (alloc_device)
-			kfree(dev);
-		return NULL;
-	}
-	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-	fsm_settimer(privptr->fsm, &privptr->restart_timer);
-	dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
-	dev->hard_start_xmit = ctc_tx;
-	dev->open = ctc_open;
-	dev->stop = ctc_close;
-	dev->get_stats = ctc_stats;
-	dev->change_mtu = ctc_change_mtu;
-	dev->hard_header_len = LL_HEADER_LENGTH + 2;
-	dev->addr_len = 0;
-	dev->type = ARPHRD_SLIP;
-	dev->tx_queue_len = 100;
-	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-	SET_MODULE_OWNER(dev);
-	return dev;
-}
-
 static ssize_t
 ctc_proto_show(struct device *dev, char *buf)
 {
@@ -2972,7 +2685,6 @@ ctc_proto_store(struct device *dev, cons
 	return count;
 }
 
-static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
 
 static ssize_t
 ctc_type_show(struct device *dev, char *buf)
@@ -2986,8 +2698,13 @@ ctc_type_show(struct device *dev, char *
 	return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);
 }
 
+static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
+static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
 static DEVICE_ATTR(type, 0444, ctc_type_show, NULL);
 
+static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
+static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
+
 static struct attribute *ctc_attr[] = {
 	&dev_attr_protocol.attr,
 	&dev_attr_type.attr,
@@ -3000,6 +2717,21 @@ static struct attribute_group ctc_attr_g
 };
 
 static int
+ctc_add_attributes(struct device *dev)
+{
+	device_create_file(dev, &dev_attr_loglevel);
+	device_create_file(dev, &dev_attr_stats);
+	return 0;
+}
+
+static void
+ctc_remove_attributes(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_stats);
+	device_remove_file(dev, &dev_attr_loglevel);
+}
+
+static int
 ctc_add_files(struct device *dev)
 {
 	pr_debug("%s() called\n", __FUNCTION__);
@@ -3023,15 +2755,15 @@ ctc_remove_files(struct device *dev)
  *
  * @returns 0 on success, !0 on failure.
  */
-
 static int
 ctc_probe_device(struct ccwgroup_device *cgdev)
 {
 	struct ctc_priv *priv;
 	int rc;
+	char buffer[16];
 
 	pr_debug("%s() called\n", __FUNCTION__);
-	DBF_TEXT(trace, 3, __FUNCTION__);
+	DBF_TEXT(setup, 3, __FUNCTION__);
 
 	if (!get_device(&cgdev->dev))
 		return -ENODEV;
@@ -3050,15 +2782,75 @@ ctc_probe_device(struct ccwgroup_device 
 		put_device(&cgdev->dev);
 		return rc;
 	}
-
+	priv->buffer_size = CTC_BUFSIZE_DEFAULT;
 	cgdev->cdev[0]->handler = ctc_irq_handler;
 	cgdev->cdev[1]->handler = ctc_irq_handler;
 	cgdev->dev.driver_data = priv;
 
+	sprintf(buffer, "%p", priv);
+	DBF_TEXT(data, 3, buffer);
+
+	sprintf(buffer, "%u", (unsigned int)sizeof(struct ctc_priv));
+	DBF_TEXT(data, 3, buffer);
+
+	sprintf(buffer, "%p", &channels);
+	DBF_TEXT(data, 3, buffer);
+
+	sprintf(buffer, "%u", (unsigned int)sizeof(struct channel));
+	DBF_TEXT(data, 3, buffer);
+
 	return 0;
 }
 
 /**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static struct net_device *
+ctc_init_netdevice(struct net_device * dev, int alloc_device,
+		   struct ctc_priv *privptr)
+{
+	if (!privptr)
+		return NULL;
+
+	DBF_TEXT(setup, 3, __FUNCTION__);
+
+	if (alloc_device) {
+		dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
+		if (!dev)
+			return NULL;
+		memset(dev, 0, sizeof (struct net_device));
+	}
+
+	dev->priv = privptr;
+	privptr->fsm = init_fsm("ctcdev", dev_state_names,
+				dev_event_names, CTC_NR_DEV_STATES, CTC_NR_DEV_EVENTS,
+				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+	if (privptr->fsm == NULL) {
+		if (alloc_device)
+			kfree(dev);
+		return NULL;
+	}
+	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+	fsm_settimer(privptr->fsm, &privptr->restart_timer);
+	if (dev->mtu == 0)
+		dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+	dev->hard_start_xmit = ctc_tx;
+	dev->open = ctc_open;
+	dev->stop = ctc_close;
+	dev->get_stats = ctc_stats;
+	dev->change_mtu = ctc_change_mtu;
+	dev->hard_header_len = LL_HEADER_LENGTH + 2;
+	dev->addr_len = 0;
+	dev->type = ARPHRD_SLIP;
+	dev->tx_queue_len = 100;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	SET_MODULE_OWNER(dev);
+	return dev;
+}
+
+
+/**
  *
  * Setup an interface.
  *
@@ -3076,6 +2868,7 @@ ctc_new_device(struct ccwgroup_device *c
 	struct ctc_priv *privptr;
 	struct net_device *dev;
 	int ret;
+	char buffer[16];
 
 	pr_debug("%s() called\n", __FUNCTION__);
 	DBF_TEXT(setup, 3, __FUNCTION__);
@@ -3084,6 +2877,9 @@ ctc_new_device(struct ccwgroup_device *c
 	if (!privptr)
 		return -ENODEV;
 
+	sprintf(buffer, "%d", privptr->buffer_size);
+	DBF_TEXT(setup, 3, buffer);
+
 	type = get_channel_type(&cgdev->cdev[0]->id);
 	
 	snprintf(read_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id);
@@ -3131,7 +2927,7 @@ ctc_new_device(struct ccwgroup_device *c
 		}
 		privptr->channel[direction]->netdev = dev;
 		privptr->channel[direction]->protocol = privptr->protocol;
-		privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
+		privptr->channel[direction]->max_bufsize = privptr->buffer_size;
 	}
 	/* sysfs magic */
 	SET_NETDEV_DEV(dev, &cgdev->dev);
@@ -3172,9 +2968,10 @@ ctc_shutdown_device(struct ccwgroup_devi
 	struct ctc_priv *priv;
 	struct net_device *ndev;
 		
-	DBF_TEXT(trace, 3, __FUNCTION__);
+	DBF_TEXT(setup, 3, __FUNCTION__);
 	pr_debug("%s() called\n", __FUNCTION__);
 
+
 	priv = cgdev->dev.driver_data;
 	ndev = NULL;
 	if (!priv)
@@ -3210,7 +3007,6 @@ ctc_shutdown_device(struct ccwgroup_devi
 		channel_remove(priv->channel[READ]);
 	if (priv->channel[WRITE])
 		channel_remove(priv->channel[WRITE]);
-	
 	priv->channel[READ] = priv->channel[WRITE] = NULL;
 
 	return 0;
@@ -3223,7 +3019,7 @@ ctc_remove_device(struct ccwgroup_device
 	struct ctc_priv *priv;
 
 	pr_debug("%s() called\n", __FUNCTION__);
-	DBF_TEXT(trace, 3, __FUNCTION__);
+	DBF_TEXT(setup, 3, __FUNCTION__);
 
 	priv = cgdev->dev.driver_data;
 	if (!priv)
@@ -3260,6 +3056,7 @@ static struct ccwgroup_driver ctc_group_
 static void __exit
 ctc_exit(void)
 {
+	DBF_TEXT(setup, 3, __FUNCTION__);
 	unregister_cu3088_discipline(&ctc_group_driver);
 	ctc_tty_cleanup();
 	ctc_unregister_dbf_views();
@@ -3277,6 +3074,10 @@ ctc_init(void)
 {
 	int ret = 0;
 
+	loglevel = CTC_LOGLEVEL_DEFAULT;
+
+	DBF_TEXT(setup, 3, __FUNCTION__);
+
 	print_banner();
 
 	ret = ctc_register_dbf_views();
diff --git a/drivers/s390/net/ctcmain.h b/drivers/s390/net/ctcmain.h
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/ctcmain.h
@@ -0,0 +1,276 @@
+/*
+ * $Id: ctcmain.h,v 1.4 2005/03/24 09:04:17 mschwide Exp $
+ *
+ * CTC / ESCON network driver
+ *
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+	      Peter Tiedemann (ptiedem@de.ibm.com)
+ *
+ *
+ * Documentation used:
+ *  - Principles of Operation (IBM doc#: SA22-7201-06)
+ *  - Common IO/-Device Commands and Self Description (IBM doc#: SA22-7204-02)
+ *  - Common IO/-Device Commands and Self Description (IBM doc#: SN22-5535)
+ *  - ESCON Channel-to-Channel Adapter (IBM doc#: SA22-7203-00)
+ *  - ESCON I/O Interface (IBM doc#: SA22-7202-029
+ *
+ * This program is free software; you can redistribute 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.
+ *
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.4 $
+ *
+ */
+
+#ifndef _CTCMAIN_H_
+#define _CTCMAIN_H_
+
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+
+#include "ctctty.h"
+#include "fsm.h"
+#include "cu3088.h"
+
+
+/**
+ * CCW commands, used in this driver.
+ */
+#define CCW_CMD_WRITE		0x01
+#define CCW_CMD_READ		0x02
+#define CCW_CMD_SET_EXTENDED	0xc3
+#define CCW_CMD_PREPARE		0xe3
+
+#define CTC_PROTO_S390          0
+#define CTC_PROTO_LINUX         1
+#define CTC_PROTO_LINUX_TTY     2
+#define CTC_PROTO_OS390         3
+#define CTC_PROTO_MAX           3
+
+#define CTC_BUFSIZE_LIMIT       65535
+#define CTC_BUFSIZE_DEFAULT     32768
+
+#define CTC_TIMEOUT_5SEC        5000
+
+#define CTC_INITIAL_BLOCKLEN    2
+
+#define READ			0
+#define WRITE			1
+
+#define CTC_ID_SIZE             BUS_ID_SIZE+3
+
+
+struct ctc_profile {
+	unsigned long maxmulti;
+	unsigned long maxcqueue;
+	unsigned long doios_single;
+	unsigned long doios_multi;
+	unsigned long txlen;
+	unsigned long tx_time;
+	struct timespec send_stamp;
+};
+
+/**
+ * Definition of one channel
+ */
+struct channel {
+
+	/**
+	 * Pointer to next channel in list.
+	 */
+	struct channel *next;
+	char id[CTC_ID_SIZE];
+	struct ccw_device *cdev;
+
+	/**
+	 * Type of this channel.
+	 * CTC/A or Escon for valid channels.
+	 */
+	enum channel_types type;
+
+	/**
+	 * Misc. flags. See CHANNEL_FLAGS_... below
+	 */
+	__u32 flags;
+
+	/**
+	 * The protocol of this channel
+	 */
+	__u16 protocol;
+
+	/**
+	 * I/O and irq related stuff
+	 */
+	struct ccw1 *ccw;
+	struct irb *irb;
+
+	/**
+	 * RX/TX buffer size
+	 */
+	int max_bufsize;
+
+	/**
+	 * Transmit/Receive buffer.
+	 */
+	struct sk_buff *trans_skb;
+
+	/**
+	 * Universal I/O queue.
+	 */
+	struct sk_buff_head io_queue;
+
+	/**
+	 * TX queue for collecting skb's during busy.
+	 */
+	struct sk_buff_head collect_queue;
+
+	/**
+	 * Amount of data in collect_queue.
+	 */
+	int collect_len;
+
+	/**
+	 * spinlock for collect_queue and collect_len
+	 */
+	spinlock_t collect_lock;
+
+	/**
+	 * Timer for detecting unresposive
+	 * I/O operations.
+	 */
+	fsm_timer timer;
+
+	/**
+	 * Retry counter for misc. operations.
+	 */
+	int retry;
+
+	/**
+	 * The finite state machine of this channel
+	 */
+	fsm_instance *fsm;
+
+	/**
+	 * The corresponding net_device this channel
+	 * belongs to.
+	 */
+	struct net_device *netdev;
+
+	struct ctc_profile prof;
+
+	unsigned char *trans_skb_data;
+
+	__u16 logflags;
+};
+
+#define CHANNEL_FLAGS_READ            0
+#define CHANNEL_FLAGS_WRITE           1
+#define CHANNEL_FLAGS_INUSE           2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
+#define CHANNEL_FLAGS_FAILED          8
+#define CHANNEL_FLAGS_WAITIRQ        16
+#define CHANNEL_FLAGS_RWMASK 1
+#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
+
+#define LOG_FLAG_ILLEGALPKT  1
+#define LOG_FLAG_ILLEGALSIZE 2
+#define LOG_FLAG_OVERRUN     4
+#define LOG_FLAG_NOMEM       8
+
+#define CTC_LOGLEVEL_INFO     1
+#define CTC_LOGLEVEL_NOTICE   2
+#define CTC_LOGLEVEL_WARN     4
+#define CTC_LOGLEVEL_EMERG    8
+#define CTC_LOGLEVEL_ERR     16
+#define CTC_LOGLEVEL_DEBUG   32
+#define CTC_LOGLEVEL_CRIT    64
+
+#define CTC_LOGLEVEL_DEFAULT \
+(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
+
+#define CTC_LOGLEVEL_MAX     ((CTC_LOGLEVEL_CRIT<<1)-1)
+
+#define ctc_pr_debug(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
+
+#define ctc_pr_info(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
+
+#define ctc_pr_notice(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
+
+#define ctc_pr_warn(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
+
+#define ctc_pr_emerg(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
+
+#define ctc_pr_err(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
+
+#define ctc_pr_crit(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
+
+struct ctc_priv {
+	struct net_device_stats stats;
+	unsigned long tbusy;
+	/**
+	 * The finite state machine of this interface.
+	 */
+	fsm_instance *fsm;
+	/**
+	 * The protocol of this device
+	 */
+	__u16 protocol;
+ 	/**
+ 	 * Timer for restarting after I/O Errors
+ 	 */
+ 	fsm_timer               restart_timer;
+
+	int buffer_size;
+
+	struct channel *channel[2];
+};
+
+/**
+ * Definition of our link level header.
+ */
+struct ll_header {
+	__u16 length;
+	__u16 type;
+	__u16 unused;
+};
+#define LL_HEADER_LENGTH (sizeof(struct ll_header))
+
+/**
+ * Compatibility macros for busy handling
+ * of network devices.
+ */
+static __inline__ void
+ctc_clear_busy(struct net_device * dev)
+{
+	clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
+	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+		netif_wake_queue(dev);
+}
+
+static __inline__ int
+ctc_test_and_set_busy(struct net_device * dev)
+{
+	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+		netif_stop_queue(dev);
+	return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
+}
+
+#endif
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
--- a/drivers/s390/net/ctctty.c
+++ b/drivers/s390/net/ctctty.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.26 2004/08/04 11:06:55 mschwide Exp $
+ * $Id: ctctty.c,v 1.29 2005/04/05 08:50:44 mschwide Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -778,11 +778,10 @@ ctc_tty_ioctl(struct tty_struct *tty, st
 			printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
 			       info->line);
 #endif
-			error = verify_area(VERIFY_WRITE, (void __user *) arg, sizeof(uint));
-			if (error)
-				return error;
-			else
+			if (access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(uint)))
 				return ctc_tty_get_lsr_info(info, (uint __user *) arg);
+			else
+				return -EFAULT;
 		default:
 #ifdef CTC_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd,
@@ -1057,8 +1056,7 @@ ctc_tty_close(struct tty_struct *tty, st
 	info->tty = 0;
 	tty->closing = 0;
 	if (info->blocked_open) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/2);
+		msleep_interruptible(500);
 		wake_up_interruptible(&info->open_wait);
 	}
 	info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cu3088.c,v 1.34 2004/06/15 13:16:27 pavlic Exp $
+ * $Id: cu3088.c,v 1.35 2005/03/30 19:28:52 richtera Exp $
  *
  * CTC / LCS ccw_device driver
  *
@@ -39,6 +39,7 @@ const char *cu3088_type[] = {
 	"FICON channel",
 	"P390 LCS card",
 	"OSA LCS card",
+	"CLAW channel device",
 	"unknown channel type",
 	"unsupported channel type",
 };
@@ -51,6 +52,7 @@ static struct ccw_device_id cu3088_ids[]
 	{ CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
 	{ CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
 	{ CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
+	{ CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw },
 	{ /* end of list */ }
 };
 
diff --git a/drivers/s390/net/cu3088.h b/drivers/s390/net/cu3088.h
--- a/drivers/s390/net/cu3088.h
+++ b/drivers/s390/net/cu3088.h
@@ -23,6 +23,9 @@ enum channel_types {
 	/* Device is a OSA2 card */
 	channel_type_osa2,
 
+	/* Device is a CLAW channel device */
+	channel_type_claw,
+
 	/* Device is a channel, but we don't know
 	 * anything about it */
 	channel_type_unknown,
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -1,5 +1,5 @@
 /* 
- * $Id: iucv.c,v 1.42 2005/01/07 10:49:54 braunu Exp $
+ * $Id: iucv.c,v 1.45 2005/04/26 22:59:06 braunu Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.42 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.45 $
  *
  */
 
@@ -355,7 +355,7 @@ do { \
 static void
 iucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.42 $";
+	char vbuf[] = "$Revision: 1.45 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
@@ -2525,7 +2525,7 @@ iucv_tasklet_handler(unsigned long ignor
 	return;
 }
 
-module_init(iucv_init);
+subsys_initcall(iucv_init);
 module_exit(iucv_exit);
 
 /**
@@ -2553,12 +2553,12 @@ EXPORT_SYMBOL (iucv_resume);
 #endif
 EXPORT_SYMBOL (iucv_reply_prmmsg);
 EXPORT_SYMBOL (iucv_send);
-#if 0
 EXPORT_SYMBOL (iucv_send2way);
 EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send_array);
 EXPORT_SYMBOL (iucv_send2way_prmmsg);
 EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
+#if 0
+EXPORT_SYMBOL (iucv_send_array);
 EXPORT_SYMBOL (iucv_send_prmmsg);
 EXPORT_SYMBOL (iucv_setmask);
 #endif
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -11,7 +11,7 @@
  *			  Frank Pavlic (pavlic@de.ibm.com) and
  *		 	  Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.96 $	 $Date: 2004/11/11 13:42:33 $
+ *    $Revision: 1.98 $	 $Date: 2005/04/18 13:41:29 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -59,7 +59,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.96 $"
+#define VERSION_LCS_C  "$Revision: 1.98 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 static char debug_buffer[255];
@@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_c
 		PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");
 		return -EOPNOTSUPP;
 	}
-	/* Print out supported assists: IPv6 */
-	PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
-		   (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
-		   "with" : "without");
-	/* Print out supported assist: Multicast */
-	PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
-		   (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
-		   "with" : "without");
 	if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)
 		return 0;
 	return -EOPNOTSUPP;
@@ -1160,7 +1152,7 @@ list_modified:
 		}
 	}
 	/* re-insert all entries from the failed_list into ipm_list */
-	list_for_each_entry(ipm, &failed_list, list) {
+	list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
 		list_del_init(&ipm->list);
 		list_add_tail(&ipm->list, &card->ipm_list);
 	}
@@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *c
 	if (!dev)
 		goto out;
 	card->dev = dev;
-netdev_out:
 	card->dev->priv = card;
 	card->dev->open = lcs_open_device;
 	card->dev->stop = lcs_stop_device;
 	card->dev->hard_start_xmit = lcs_start_xmit;
 	card->dev->get_stats = lcs_getstats;
 	SET_MODULE_OWNER(dev);
-	if (lcs_register_netdev(ccwgdev) != 0)
-		goto out;
 	memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
 #ifdef CONFIG_IP_MULTICAST
 	if (!lcs_check_multicast_support(card))
 		card->dev->set_multicast_list = lcs_set_multicast_list;
 #endif
-	netif_stop_queue(card->dev);
+netdev_out:
 	lcs_set_allowed_threads(card,0xffffffff);
 	if (recover_state == DEV_STATE_RECOVER) {
 		lcs_set_multicast_list(card->dev);
 		card->dev->flags |= IFF_UP;
 		netif_wake_queue(card->dev);
 		card->state = DEV_STATE_UP;
-	} else
+	} else {
 		lcs_stopcard(card);
+	}
 
+	if (lcs_register_netdev(ccwgdev) != 0)
+		goto out;
+
+	/* Print out supported assists: IPv6 */
+	PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
+		   (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
+		   "with" : "without");
+	/* Print out supported assist: Multicast */
+	PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
+		   (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
+		   "with" : "without");
 	return 0;
 out:
 
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -24,7 +24,7 @@
 
 #include "qeth_mpc.h"
 
-#define VERSION_QETH_H 		"$Revision: 1.132 $"
+#define VERSION_QETH_H 		"$Revision: 1.139 $"
 
 #ifdef CONFIG_QETH_IPV6
 #define QETH_VERSION_IPV6 	":IPv6"
@@ -68,7 +68,8 @@
 #define QETH_DBF_TRACE_LEN 8
 #define QETH_DBF_TRACE_INDEX 2
 #define QETH_DBF_TRACE_NR_AREAS 2
-#define QETH_DBF_TRACE_LEVEL 5
+#define QETH_DBF_TRACE_LEVEL 3
+extern debug_info_t *qeth_dbf_trace;
 
 #define QETH_DBF_SENSE_NAME "qeth_sense"
 #define QETH_DBF_SENSE_LEN 64
@@ -206,6 +207,11 @@ struct qeth_perf_stats {
 	__u64 outbound_do_qdio_start_time;
 	unsigned int outbound_do_qdio_cnt;
 	unsigned int outbound_do_qdio_time;
+	/* eddp data */
+	unsigned int large_send_bytes;
+	unsigned int large_send_cnt;
+	unsigned int sg_skbs_sent;
+	unsigned int sg_frags_sent;
 };
 #endif /* CONFIG_QETH_PERF_STATS */
 
@@ -282,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info
 #define QETH_TX_TIMEOUT		100 * HZ
 #define QETH_HEADER_SIZE	32
 #define MAX_PORTNO 		15
-#define QETH_FAKE_LL_LEN 	ETH_HLEN
+#define QETH_FAKE_LL_LEN_ETH	ETH_HLEN
+#define QETH_FAKE_LL_LEN_TR	(sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc))
 #define QETH_FAKE_LL_V6_ADDR_POS 24
 
 /*IPv6 address autoconfiguration stuff*/
@@ -334,8 +341,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info
 struct qeth_hdr_layer3 {
 	__u8  id;
 	__u8  flags;
-	__u16 inbound_checksum;
-	__u32 token;
+	__u16 inbound_checksum; /*TSO:__u16 seqno */
+	__u32 token;		/*TSO: __u32 reserved */
 	__u16 length;
 	__u8  vlan_prio;
 	__u8  ext_flags;
@@ -363,6 +370,25 @@ struct qeth_hdr {
 	} hdr;
 } __attribute__ ((packed));
 
+/*TCP Segmentation Offload header*/
+struct qeth_hdr_ext_tso {
+        __u16 hdr_tot_len;
+        __u8  imb_hdr_no;
+        __u8  reserved;
+        __u8  hdr_type;
+        __u8  hdr_version;
+        __u16 hdr_len;
+        __u32 payload_len;
+        __u16 mss;
+        __u16 dg_hdr_len;
+        __u8  padding[16];
+} __attribute__ ((packed));
+
+struct qeth_hdr_tso {
+        struct qeth_hdr hdr; 	/*hdr->hdr.l3.xxx*/
+	struct qeth_hdr_ext_tso ext;
+} __attribute__ ((packed));
+
 
 /* flags for qeth_hdr.flags */
 #define QETH_HDR_PASSTHRU 0x10
@@ -386,6 +412,7 @@ enum qeth_layer2_frame_flags {
 enum qeth_header_ids {
 	QETH_HEADER_TYPE_LAYER3 = 0x01,
 	QETH_HEADER_TYPE_LAYER2 = 0x02,
+	QETH_HEADER_TYPE_TSO	= 0x03,
 };
 /* flags for qeth_hdr.ext_flags */
 #define QETH_HDR_EXT_VLAN_FRAME       0x01
@@ -394,6 +421,7 @@ enum qeth_header_ids {
 #define QETH_HDR_EXT_SRC_MAC_ADDR     0x08
 #define QETH_HDR_EXT_CSUM_HDR_REQ     0x10
 #define QETH_HDR_EXT_CSUM_TRANSP_REQ  0x20
+#define QETH_HDR_EXT_UDP_TSO          0x40 /*bit off for TCP*/
 
 static inline int
 qeth_is_last_sbale(struct qdio_buffer_element *sbale)
@@ -448,11 +476,19 @@ struct qeth_qdio_q {
 	volatile int next_buf_to_init;
 } __attribute__ ((aligned(256)));
 
+/* possible types of qeth large_send support */
+enum qeth_large_send_types {
+	QETH_LARGE_SEND_NO,
+	QETH_LARGE_SEND_EDDP,
+	QETH_LARGE_SEND_TSO,
+};
+
 struct qeth_qdio_out_buffer {
 	struct qdio_buffer *buffer;
 	atomic_t state;
 	volatile int next_element_to_fill;
 	struct sk_buff_head skb_list;
+	struct list_head ctx_list;
 };
 
 struct qeth_card;
@@ -668,6 +704,14 @@ struct qeth_reply {
 #define QETH_BROADCAST_WITH_ECHO    1
 #define QETH_BROADCAST_WITHOUT_ECHO 2
 
+struct qeth_card_blkt {
+	int time_total;
+	int inter_packet;
+	int inter_packet_jumbo;
+};
+
+
+
 struct qeth_card_info {
 	unsigned short unit_addr2;
 	unsigned short cula;
@@ -686,6 +730,7 @@ struct qeth_card_info {
 	int max_mtu;
 	int broadcast_capable;
 	int unique_id;
+	struct qeth_card_blkt blkt;
 	__u32 csum_mask;
 };
 
@@ -704,6 +749,7 @@ struct qeth_card_options {
 	int add_hhlen;
 	int fake_ll;
 	int layer2;
+	enum qeth_large_send_types large_send;
 };
 
 /*
@@ -790,25 +836,77 @@ qeth_get_ipa_adp_type(enum qeth_link_typ
 }
 
 inline static int
+qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+	struct sk_buff *new_skb = NULL;
+
+	if (skb_headroom(*skb) < size){
+		new_skb = skb_realloc_headroom(*skb, size);
+		if (!new_skb) {
+                        PRINT_ERR("qeth_prepare_skb: could "
+                                  "not realloc headroom for qeth_hdr "
+                                  "on interface %s", QETH_CARD_IFNAME(card));
+                        return -ENOMEM;
+                }
+                *skb = new_skb;
+	}
+	return 0;
+}
+static inline struct sk_buff *
+qeth_pskb_unshare(struct sk_buff *skb, int pri)
+{
+        struct sk_buff *nskb;
+        if (!skb_cloned(skb))
+                return skb;
+        nskb = skb_copy(skb, pri);
+        kfree_skb(skb); /* free our shared copy */
+        return nskb;
+}
+
+
+inline static void *
+qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+        void *hdr;
+
+	hdr = (void *) skb_push(*skb, size);
+        /*
+         * sanity check, the Linux memory allocation scheme should
+         * never present us cases like this one (the qdio header size plus
+         * the first 40 bytes of the paket cross a 4k boundary)
+         */
+        if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
+            (((unsigned long) hdr + size +
+              QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
+                PRINT_ERR("qeth_prepare_skb: misaligned "
+                          "packet on interface %s. Discarded.",
+                          QETH_CARD_IFNAME(card));
+                return NULL;
+        }
+        return hdr;
+}
+
+
+inline static int
 qeth_get_hlen(__u8 link_type)
 {
 #ifdef CONFIG_QETH_IPV6
 	switch (link_type) {
 	case QETH_LINK_TYPE_HSTR:
 	case QETH_LINK_TYPE_LANE_TR:
-		return sizeof(struct qeth_hdr) + TR_HLEN;
+		return sizeof(struct qeth_hdr_tso) + TR_HLEN;
 	default:
 #ifdef CONFIG_QETH_VLAN
-		return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
+		return sizeof(struct qeth_hdr_tso) + VLAN_ETH_HLEN;
 #else
-		return sizeof(struct qeth_hdr) + ETH_HLEN;
+		return sizeof(struct qeth_hdr_tso) + ETH_HLEN;
 #endif
 	}
 #else  /* CONFIG_QETH_IPV6 */
 #ifdef CONFIG_QETH_VLAN
-	return sizeof(struct qeth_hdr) + VLAN_HLEN;
+	return sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
 #else
-	return sizeof(struct qeth_hdr);
+	return sizeof(struct qeth_hdr_tso);
 #endif
 #endif /* CONFIG_QETH_IPV6 */
 }
@@ -830,17 +928,6 @@ qeth_get_netdev_flags(struct qeth_card *
 #endif
 	}
 }
-static inline struct sk_buff *
-qeth_pskb_unshare(struct sk_buff *skb, int pri)
-{
-        struct sk_buff *nskb;
-        if (!skb_cloned(skb))
-                return skb;
-        nskb = skb_copy(skb, pri);
-        kfree_skb(skb); /* free our shared copy */
-        return nskb;
-}
-
 
 inline static int
 qeth_get_initial_mtu_for_card(struct qeth_card * card)
@@ -1084,4 +1171,13 @@ qeth_schedule_recovery(struct qeth_card 
 extern int
 qeth_realloc_buffer_pool(struct qeth_card *, int);
 
+extern int
+qeth_set_large_send(struct qeth_card *);
+
+extern void
+qeth_fill_header(struct qeth_card *, struct qeth_hdr *,
+		 struct sk_buff *, int, int);
+extern void
+qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int);
+
 #endif /* __QETH_H__ */
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/qeth_eddp.c
@@ -0,0 +1,632 @@
+/*
+ *
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.13 $)
+ *
+ * Enhanced Device Driver Packing (EDDP) support for the qeth driver.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ *    Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ *    $Revision: 1.13 $	 $Date: 2005/05/04 20:19:18 $
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/kernel.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <linux/skbuff.h>
+
+#include <net/ip.h>
+
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_eddp.h"
+
+int
+qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
+				    struct qeth_eddp_context *ctx)
+{
+	int index = queue->next_buf_to_fill;
+	int elements_needed = ctx->num_elements;
+	int elements_in_buffer;
+	int skbs_in_buffer;
+	int buffers_needed = 0;
+
+	QETH_DBF_TEXT(trace, 5, "eddpcbfc");
+	while(elements_needed > 0) {
+		buffers_needed++;
+		if (atomic_read(&queue->bufs[index].state) !=
+				QETH_QDIO_BUF_EMPTY)
+			return -EBUSY;
+
+		elements_in_buffer = QETH_MAX_BUFFER_ELEMENTS(queue->card) -
+				     queue->bufs[index].next_element_to_fill;
+		skbs_in_buffer = elements_in_buffer / ctx->elements_per_skb;
+		elements_needed -= skbs_in_buffer * ctx->elements_per_skb;
+		index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+	}
+	return buffers_needed;
+}
+
+static inline void
+qeth_eddp_free_context(struct qeth_eddp_context *ctx)
+{
+	int i;
+
+	QETH_DBF_TEXT(trace, 5, "eddpfctx");
+	for (i = 0; i < ctx->num_pages; ++i)
+		free_page((unsigned long)ctx->pages[i]);
+	kfree(ctx->pages);
+	if (ctx->elements != NULL)
+		kfree(ctx->elements);
+	kfree(ctx);
+}
+
+
+static inline void
+qeth_eddp_get_context(struct qeth_eddp_context *ctx)
+{
+	atomic_inc(&ctx->refcnt);
+}
+
+void
+qeth_eddp_put_context(struct qeth_eddp_context *ctx)
+{
+	if (atomic_dec_return(&ctx->refcnt) == 0)
+		qeth_eddp_free_context(ctx);
+}
+
+void
+qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
+{
+	struct qeth_eddp_context_reference *ref;
+	
+	QETH_DBF_TEXT(trace, 6, "eddprctx");
+	while (!list_empty(&buf->ctx_list)){
+		ref = list_entry(buf->ctx_list.next,
+				 struct qeth_eddp_context_reference, list);
+		qeth_eddp_put_context(ref->ctx);
+		list_del(&ref->list);
+		kfree(ref);
+	}
+}
+
+static inline int
+qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
+			  struct qeth_eddp_context *ctx)
+{
+	struct qeth_eddp_context_reference *ref;
+
+	QETH_DBF_TEXT(trace, 6, "eddprfcx");
+	ref = kmalloc(sizeof(struct qeth_eddp_context_reference), GFP_ATOMIC);
+	if (ref == NULL)
+		return -ENOMEM;
+	qeth_eddp_get_context(ctx);
+	ref->ctx = ctx;
+	list_add_tail(&ref->list, &buf->ctx_list);
+	return 0;
+}
+
+int
+qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
+		      struct qeth_eddp_context *ctx,
+		      int index)
+{
+	struct qeth_qdio_out_buffer *buf = NULL;
+	struct qdio_buffer *buffer;
+	int elements = ctx->num_elements;
+	int element = 0;
+	int flush_cnt = 0;
+	int must_refcnt = 1;
+	int i;
+
+	QETH_DBF_TEXT(trace, 5, "eddpfibu");
+	while (elements > 0) {
+		buf = &queue->bufs[index];
+		if (atomic_read(&buf->state) != QETH_QDIO_BUF_EMPTY){
+			/* normally this should not happen since we checked for
+			 * available elements in qeth_check_elements_for_context
+			 */
+			if (element == 0)
+				return -EBUSY;
+			else {
+				PRINT_WARN("could only partially fill eddp "
+					   "buffer!\n");
+				goto out;
+			}
+		}		
+		/* check if the whole next skb fits into current buffer */
+		if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
+					buf->next_element_to_fill)
+				< ctx->elements_per_skb){
+			/* no -> go to next buffer */
+			atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+			index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+			flush_cnt++;
+			/* new buffer, so we have to add ctx to buffer'ctx_list
+			 * and increment ctx's refcnt */
+			must_refcnt = 1;
+			continue;
+		}	
+		if (must_refcnt){
+			must_refcnt = 0;
+			if (qeth_eddp_buf_ref_context(buf, ctx)){
+				PRINT_WARN("no memory to create eddp context "
+					   "reference\n");
+				goto out_check;
+			}
+		}
+		buffer = buf->buffer;
+		/* fill one skb into buffer */
+		for (i = 0; i < ctx->elements_per_skb; ++i){
+			buffer->element[buf->next_element_to_fill].addr =
+				ctx->elements[element].addr;
+			buffer->element[buf->next_element_to_fill].length =
+				ctx->elements[element].length;
+			buffer->element[buf->next_element_to_fill].flags =
+				ctx->elements[element].flags;
+			buf->next_element_to_fill++;
+			element++;
+			elements--;
+		}
+	}
+out_check:
+	if (!queue->do_pack) {
+		QETH_DBF_TEXT(trace, 6, "fillbfnp");
+		/* set state to PRIMED -> will be flushed */
+		if (buf->next_element_to_fill > 0){
+			atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+			flush_cnt++;
+		}
+	} else {
+#ifdef CONFIG_QETH_PERF_STATS
+		queue->card->perf_stats.skbs_sent_pack++;
+#endif
+		QETH_DBF_TEXT(trace, 6, "fillbfpa");
+		if (buf->next_element_to_fill >=
+				QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
+			/*
+			 * packed buffer if full -> set state PRIMED
+			 * -> will be flushed
+			 */
+			atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+			flush_cnt++;
+		}
+	}
+out:
+	return flush_cnt;
+}
+
+static inline void
+qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
+			      struct qeth_eddp_data *eddp, int data_len)
+{
+	u8 *page;
+	int page_remainder;
+	int page_offset;
+	int pkt_len;
+	struct qeth_eddp_element *element;
+
+	QETH_DBF_TEXT(trace, 5, "eddpcrsh");
+	page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+	page_offset = ctx->offset % PAGE_SIZE;
+	element = &ctx->elements[ctx->num_elements];
+	pkt_len = eddp->nhl + eddp->thl + data_len;
+	/* FIXME: layer2 and VLAN !!! */
+	if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
+		pkt_len += ETH_HLEN;
+	if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
+		pkt_len += VLAN_HLEN;
+	/* does complete packet fit in current page ? */
+	page_remainder = PAGE_SIZE - page_offset;
+	if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
+		/* no -> go to start of next page */
+		ctx->offset += page_remainder;
+		page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+		page_offset = 0;
+	}
+	memcpy(page + page_offset, &eddp->qh, sizeof(struct qeth_hdr));
+	element->addr = page + page_offset;
+	element->length = sizeof(struct qeth_hdr);
+	ctx->offset += sizeof(struct qeth_hdr);
+	page_offset += sizeof(struct qeth_hdr);
+	/* add mac header (?) */
+	if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
+		memcpy(page + page_offset, &eddp->mac, ETH_HLEN);
+		element->length += ETH_HLEN;
+		ctx->offset += ETH_HLEN;
+		page_offset += ETH_HLEN;
+	}
+	/* add VLAN tag */
+	if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)){
+		memcpy(page + page_offset, &eddp->vlan, VLAN_HLEN);
+		element->length += VLAN_HLEN;
+		ctx->offset += VLAN_HLEN;
+		page_offset += VLAN_HLEN;
+	}
+	/* add network header */
+	memcpy(page + page_offset, (u8 *)&eddp->nh, eddp->nhl);
+	element->length += eddp->nhl;
+	eddp->nh_in_ctx = page + page_offset;
+	ctx->offset += eddp->nhl;
+	page_offset += eddp->nhl;
+	/* add transport header */
+	memcpy(page + page_offset, (u8 *)&eddp->th, eddp->thl);
+	element->length += eddp->thl;
+	eddp->th_in_ctx = page + page_offset;
+	ctx->offset += eddp->thl;
+}
+
+static inline void
+qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
+			u32 *hcsum)
+{
+	struct skb_frag_struct *frag;
+	int left_in_frag;
+	int copy_len;
+	u8 *src;
+	
+	QETH_DBF_TEXT(trace, 5, "eddpcdtc");
+	if (skb_shinfo(eddp->skb)->nr_frags == 0) {
+		memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
+		*hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len,
+				      *hcsum);
+		eddp->skb_offset += len;
+	} else {
+		while (len > 0) {
+			if (eddp->frag < 0) {
+				/* we're in skb->data */
+				left_in_frag = (eddp->skb->len - eddp->skb->data_len)
+						- eddp->skb_offset;
+				src = eddp->skb->data + eddp->skb_offset;
+			} else {
+				frag = &skb_shinfo(eddp->skb)->
+					frags[eddp->frag];
+				left_in_frag = frag->size - eddp->frag_offset;
+				src = (u8 *)(
+					(page_to_pfn(frag->page) << PAGE_SHIFT)+
+					frag->page_offset + eddp->frag_offset);
+			}
+			if (left_in_frag <= 0) {
+				eddp->frag++;
+				eddp->frag_offset = 0;
+				continue;
+			}
+			copy_len = min(left_in_frag, len);
+			memcpy(dst, src, copy_len);
+			*hcsum = csum_partial(src, copy_len, *hcsum);
+			dst += copy_len;
+			eddp->frag_offset += copy_len;
+			eddp->skb_offset += copy_len;
+			len -= copy_len;
+		}
+	}
+}
+
+static inline void
+qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
+				  struct qeth_eddp_data *eddp, int data_len,
+				  u32 hcsum)
+{
+	u8 *page;
+	int page_remainder;
+	int page_offset;
+	struct qeth_eddp_element *element;
+	int first_lap = 1;
+
+	QETH_DBF_TEXT(trace, 5, "eddpcsdt");
+	page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+	page_offset = ctx->offset % PAGE_SIZE;
+	element = &ctx->elements[ctx->num_elements];
+	while (data_len){
+		page_remainder = PAGE_SIZE - page_offset;
+		if (page_remainder < data_len){
+			qeth_eddp_copy_data_tcp(page + page_offset, eddp,
+						page_remainder, &hcsum);
+			element->length += page_remainder;
+			if (first_lap)
+				element->flags = SBAL_FLAGS_FIRST_FRAG;
+			else
+				element->flags = SBAL_FLAGS_MIDDLE_FRAG;
+			ctx->num_elements++;
+			element++;
+			data_len -= page_remainder;
+			ctx->offset += page_remainder;
+			page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+			page_offset = 0;
+			element->addr = page + page_offset;
+		} else {
+			qeth_eddp_copy_data_tcp(page + page_offset, eddp,
+						data_len, &hcsum);
+			element->length += data_len;
+			if (!first_lap)
+				element->flags = SBAL_FLAGS_LAST_FRAG;
+			ctx->num_elements++;
+			ctx->offset += data_len;
+			data_len = 0;
+		}
+		first_lap = 0;
+	}
+	((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
+}
+
+static inline u32
+qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
+{
+	u32 phcsum; /* pseudo header checksum */
+
+	QETH_DBF_TEXT(trace, 5, "eddpckt4");
+	eddp->th.tcp.h.check = 0;
+	/* compute pseudo header checksum */
+	phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr,
+				    eddp->thl + data_len, IPPROTO_TCP, 0);
+	/* compute checksum of tcp header */
+	return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
+}
+
+static inline u32
+qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
+{
+	u32 proto;
+	u32 phcsum; /* pseudo header checksum */
+
+	QETH_DBF_TEXT(trace, 5, "eddpckt6");
+	eddp->th.tcp.h.check = 0;
+	/* compute pseudo header checksum */
+	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr,
+			      sizeof(struct in6_addr), 0);
+	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr,
+			      sizeof(struct in6_addr), phcsum);
+	proto = htonl(IPPROTO_TCP);
+	phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum);
+	return phcsum;
+}
+
+static inline struct qeth_eddp_data *
+qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
+{
+	struct qeth_eddp_data *eddp;
+
+	QETH_DBF_TEXT(trace, 5, "eddpcrda");
+	eddp = kmalloc(sizeof(struct qeth_eddp_data), GFP_ATOMIC);
+	if (eddp){
+		memset(eddp, 0, sizeof(struct qeth_eddp_data));
+		eddp->nhl = nhl;
+		eddp->thl = thl;
+		memcpy(&eddp->qh, qh, sizeof(struct qeth_hdr));
+		memcpy(&eddp->nh, nh, nhl);
+		memcpy(&eddp->th, th, thl);
+		eddp->frag = -1; /* initially we're in skb->data */
+	}
+	return eddp;
+}
+
+static inline void
+__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
+			     struct qeth_eddp_data *eddp)
+{
+	struct tcphdr *tcph;
+	int data_len;
+	u32 hcsum;
+	
+	QETH_DBF_TEXT(trace, 5, "eddpftcp");
+	eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
+	tcph = eddp->skb->h.th;
+	while (eddp->skb_offset < eddp->skb->len) {
+		data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
+			       (int)(eddp->skb->len - eddp->skb_offset));
+		/* prepare qdio hdr */
+		if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
+			eddp->qh.hdr.l2.pkt_length = data_len + ETH_HLEN +
+						     eddp->nhl + eddp->thl -
+						     sizeof(struct qeth_hdr);
+#ifdef CONFIG_QETH_VLAN
+			if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
+				eddp->qh.hdr.l2.pkt_length += VLAN_HLEN;
+#endif /* CONFIG_QETH_VLAN */
+		} else
+			eddp->qh.hdr.l3.length = data_len + eddp->nhl +
+						 eddp->thl;
+		/* prepare ip hdr */
+		if (eddp->skb->protocol == ETH_P_IP){
+			eddp->nh.ip4.h.tot_len = data_len + eddp->nhl +
+						 eddp->thl;
+			eddp->nh.ip4.h.check = 0;
+			eddp->nh.ip4.h.check =
+				ip_fast_csum((u8 *)&eddp->nh.ip4.h,
+						eddp->nh.ip4.h.ihl);
+		} else
+			eddp->nh.ip6.h.payload_len = data_len + eddp->thl;
+		/* prepare tcp hdr */
+		if (data_len == (eddp->skb->len - eddp->skb_offset)){
+			/* last segment -> set FIN and PSH flags */
+			eddp->th.tcp.h.fin = tcph->fin;
+			eddp->th.tcp.h.psh = tcph->psh;
+		}
+		if (eddp->skb->protocol == ETH_P_IP)
+			hcsum = qeth_eddp_check_tcp4_hdr(eddp, data_len);
+		else
+			hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
+		/* fill the next segment into the context */
+		qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
+		qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
+		if (eddp->skb_offset >= eddp->skb->len)
+			break;
+		/* prepare headers for next round */
+		if (eddp->skb->protocol == ETH_P_IP)
+			eddp->nh.ip4.h.id++;
+		eddp->th.tcp.h.seq += data_len;
+	}
+}
+			   
+static inline int
+qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
+			   struct sk_buff *skb, struct qeth_hdr *qhdr)
+{
+	struct qeth_eddp_data *eddp = NULL;
+	
+	QETH_DBF_TEXT(trace, 5, "eddpficx");
+	/* create our segmentation headers and copy original headers */
+	if (skb->protocol == ETH_P_IP)
+		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph,
+				skb->nh.iph->ihl*4,
+				(u8 *)skb->h.th, skb->h.th->doff*4);
+	else
+		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h,
+				sizeof(struct ipv6hdr),
+				(u8 *)skb->h.th, skb->h.th->doff*4);
+
+	if (eddp == NULL) {
+		QETH_DBF_TEXT(trace, 2, "eddpfcnm");
+		return -ENOMEM;
+	}
+	if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
+		memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);
+#ifdef CONFIG_QETH_VLAN
+		if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
+			eddp->vlan[0] = __constant_htons(skb->protocol);
+			eddp->vlan[1] = htons(vlan_tx_tag_get(skb));
+		}
+#endif /* CONFIG_QETH_VLAN */
+	}
+	/* the next flags will only be set on the last segment */
+	eddp->th.tcp.h.fin = 0;
+	eddp->th.tcp.h.psh = 0;
+	eddp->skb = skb;
+	/* begin segmentation and fill context */
+	__qeth_eddp_fill_context_tcp(ctx, eddp);
+	kfree(eddp);
+	return 0;
+}
+
+static inline void
+qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
+			 int hdr_len)
+{
+	int skbs_per_page;
+	
+	QETH_DBF_TEXT(trace, 5, "eddpcanp");
+	/* can we put multiple skbs in one page? */
+	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
+	if (skbs_per_page > 1){
+		ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
+				 skbs_per_page + 1;
+		ctx->elements_per_skb = 1;
+	} else {
+		/* no -> how many elements per skb? */
+		ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
+				     PAGE_SIZE) >> PAGE_SHIFT;
+		ctx->num_pages = ctx->elements_per_skb *
+				 (skb_shinfo(skb)->tso_segs + 1);
+	}
+	ctx->num_elements = ctx->elements_per_skb *
+			    (skb_shinfo(skb)->tso_segs + 1);
+}
+
+static inline struct qeth_eddp_context *
+qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
+				 int hdr_len)
+{
+	struct qeth_eddp_context *ctx = NULL;
+	u8 *addr;
+	int i;
+
+	QETH_DBF_TEXT(trace, 5, "creddpcg");
+	/* create the context and allocate pages */
+	ctx = kmalloc(sizeof(struct qeth_eddp_context), GFP_ATOMIC);
+	if (ctx == NULL){
+		QETH_DBF_TEXT(trace, 2, "ceddpcn1");
+		return NULL;
+	}
+	memset(ctx, 0, sizeof(struct qeth_eddp_context));
+	ctx->type = QETH_LARGE_SEND_EDDP;
+	qeth_eddp_calc_num_pages(ctx, skb, hdr_len);
+	if (ctx->elements_per_skb > QETH_MAX_BUFFER_ELEMENTS(card)){
+		QETH_DBF_TEXT(trace, 2, "ceddpcis");
+		kfree(ctx);
+		return NULL;
+	}
+	ctx->pages = kmalloc(ctx->num_pages * sizeof(u8 *), GFP_ATOMIC);
+	if (ctx->pages == NULL){
+		QETH_DBF_TEXT(trace, 2, "ceddpcn2");
+		kfree(ctx);
+		return NULL;
+	}
+	memset(ctx->pages, 0, ctx->num_pages * sizeof(u8 *));
+	for (i = 0; i < ctx->num_pages; ++i){
+		addr = (u8 *)__get_free_page(GFP_ATOMIC);
+		if (addr == NULL){
+			QETH_DBF_TEXT(trace, 2, "ceddpcn3");
+			ctx->num_pages = i;
+			qeth_eddp_free_context(ctx);
+			return NULL;
+		}
+		memset(addr, 0, PAGE_SIZE);
+		ctx->pages[i] = addr;
+	}
+	ctx->elements = kmalloc(ctx->num_elements *
+				sizeof(struct qeth_eddp_element), GFP_ATOMIC);
+	if (ctx->elements == NULL){
+		QETH_DBF_TEXT(trace, 2, "ceddpcn4");
+		qeth_eddp_free_context(ctx);
+		return NULL;
+	}
+	memset(ctx->elements, 0,
+	       ctx->num_elements * sizeof(struct qeth_eddp_element));
+	/* reset num_elements; will be incremented again in fill_buffer to
+	 * reflect number of actually used elements */
+	ctx->num_elements = 0;
+	return ctx;
+}
+
+static inline struct qeth_eddp_context *
+qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
+			     struct qeth_hdr *qhdr)
+{
+	struct qeth_eddp_context *ctx = NULL;
+	
+	QETH_DBF_TEXT(trace, 5, "creddpct");
+	if (skb->protocol == ETH_P_IP)
+		ctx = qeth_eddp_create_context_generic(card, skb,
+			sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 +
+			skb->h.th->doff*4);
+	else if (skb->protocol == ETH_P_IPV6)
+		ctx = qeth_eddp_create_context_generic(card, skb,
+			sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) +
+			skb->h.th->doff*4);
+	else
+		QETH_DBF_TEXT(trace, 2, "cetcpinv");
+
+	if (ctx == NULL) {
+		QETH_DBF_TEXT(trace, 2, "creddpnl");
+		return NULL;
+	}
+	if (qeth_eddp_fill_context_tcp(ctx, skb, qhdr)){
+		QETH_DBF_TEXT(trace, 2, "ceddptfe");
+		qeth_eddp_free_context(ctx);
+		return NULL;
+	}
+	atomic_set(&ctx->refcnt, 1);
+	return ctx;
+}
+
+struct qeth_eddp_context *
+qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
+			 struct qeth_hdr *qhdr)
+{
+	QETH_DBF_TEXT(trace, 5, "creddpc");
+	switch (skb->sk->sk_protocol){
+	case IPPROTO_TCP:
+		return qeth_eddp_create_context_tcp(card, skb, qhdr);
+	default:
+		QETH_DBF_TEXT(trace, 2, "eddpinvp");
+	}
+	return NULL;
+}
+
+
diff --git a/drivers/s390/net/qeth_eddp.h b/drivers/s390/net/qeth_eddp.h
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/qeth_eddp.h
@@ -0,0 +1,85 @@
+/*
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.5 $)
+ *
+ * Header file for qeth enhanced device driver pakcing.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ *    Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ *    $Revision: 1.5 $	 $Date: 2005/03/24 09:04:18 $
+ *
+ */
+#ifndef __QETH_EDDP_H__
+#define __QETH_EDDP_H__
+
+struct qeth_eddp_element {
+	u32 flags;
+	u32 length;
+	void *addr;
+};
+
+struct qeth_eddp_context {
+	atomic_t refcnt;
+	enum qeth_large_send_types type;
+	int num_pages;			    /* # of allocated pages */
+	u8 **pages;			    /* pointers to pages */
+	int offset;			    /* offset in ctx during creation */
+	int num_elements;		    /* # of required 'SBALEs' */
+	struct qeth_eddp_element *elements; /* array of 'SBALEs' */
+	int elements_per_skb;		    /* # of 'SBALEs' per skb **/
+};
+
+struct qeth_eddp_context_reference {
+	struct list_head list;
+	struct qeth_eddp_context *ctx;
+};
+
+extern struct qeth_eddp_context *
+qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *);
+
+extern void
+qeth_eddp_put_context(struct qeth_eddp_context *);
+
+extern int
+qeth_eddp_fill_buffer(struct qeth_qdio_out_q *,struct qeth_eddp_context *,int);
+
+extern void
+qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *);
+
+extern int
+qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *,
+				    struct qeth_eddp_context *);
+/*
+ * Data used for fragmenting a IP packet.
+ */
+struct qeth_eddp_data {
+	struct qeth_hdr qh;
+	struct ethhdr mac;
+	u16 vlan[2];
+	union {
+		struct {
+			struct iphdr h;
+			u8 options[40];
+		} ip4;
+		struct {
+			struct ipv6hdr h;
+		} ip6;
+	} nh;
+	u8 nhl;
+	void *nh_in_ctx;	/* address of nh within the ctx */
+	union {
+		struct {
+			struct tcphdr h;
+			u8 options[40];
+		} tcp;
+	} th;
+	u8 thl;
+	void *th_in_ctx;	/* address of th within the ctx */
+	struct sk_buff *skb;
+	int skb_offset;
+	int frag;
+	int frag_offset;
+} __attribute__ ((packed));
+
+#endif /* __QETH_EDDP_H__ */
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.191 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -12,7 +12,7 @@
  *			  Frank Pavlic (pavlic@de.ibm.com) and
  *		 	  Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.191 $	 $Date: 2005/01/31 13:13:57 $
+ *    $Revision: 1.214 $	 $Date: 2005/05/04 20:19:18 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -61,6 +61,7 @@ qeth_eyecatcher(void)
 #include <linux/reboot.h>
 #include <linux/mii.h>
 #include <linux/rcupdate.h>
+#include <linux/ethtool.h>
 
 #include <net/arp.h>
 #include <net/ip.h>
@@ -76,8 +77,10 @@ qeth_eyecatcher(void)
 #include "qeth.h"
 #include "qeth_mpc.h"
 #include "qeth_fs.h"
+#include "qeth_eddp.h"
+#include "qeth_tso.h"
 
-#define VERSION_QETH_C "$Revision: 1.191 $"
+#define VERSION_QETH_C "$Revision: 1.214 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -87,7 +90,7 @@ static debug_info_t *qeth_dbf_setup = NU
 static debug_info_t *qeth_dbf_data = NULL;
 static debug_info_t *qeth_dbf_misc = NULL;
 static debug_info_t *qeth_dbf_control = NULL;
-static debug_info_t *qeth_dbf_trace = NULL;
+debug_info_t *qeth_dbf_trace = NULL;
 static debug_info_t *qeth_dbf_sense = NULL;
 static debug_info_t *qeth_dbf_qerr = NULL;
 
@@ -155,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
 static int
 qeth_set_online(struct ccwgroup_device *);
 
+static int
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode);
+
 static struct qeth_ipaddr *
 qeth_get_addr_buffer(enum qeth_prot_versions);
 
@@ -507,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
 	wake_up(&card->wait_q);
 }
 
-static int qeth_stop_card(struct qeth_card *);
+static int qeth_stop_card(struct qeth_card *, int);
 
 static int
-qeth_set_offline(struct ccwgroup_device *cgdev)
+__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
 {
 	struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
 	int rc = 0;
@@ -520,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device 
 	QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
 
 	recover_flag = card->state;
-	if (qeth_stop_card(card) == -ERESTARTSYS){
+	if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
 		PRINT_WARN("Stopping card %s interrupted by user!\n",
 			   CARD_BUS_ID(card));
 		return -ERESTARTSYS;
@@ -537,6 +543,12 @@ qeth_set_offline(struct ccwgroup_device 
 }
 
 static int
+qeth_set_offline(struct ccwgroup_device *cgdev)
+{
+	return  __qeth_set_offline(cgdev, 0);
+}
+
+static int
 qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
 
 
@@ -950,8 +962,8 @@ qeth_recover(void *ptr)
 	PRINT_WARN("Recovery of device %s started ...\n",
 		   CARD_BUS_ID(card));
 	card->use_hard_stop = 1;
-	qeth_set_offline(card->gdev);
-	rc = qeth_set_online(card->gdev);
+	__qeth_set_offline(card->gdev,1);
+	rc = __qeth_set_online(card->gdev,1);
 	if (!rc)
 		PRINT_INFO("Device %s successfully recovered!\n",
 			   CARD_BUS_ID(card));
@@ -1071,6 +1083,35 @@ qeth_setup_card(struct qeth_card *card)
 }
 
 static int
+is_1920_device (struct qeth_card *card)
+{
+	int single_queue = 0;
+	struct ccw_device *ccwdev;
+	struct channelPath_dsc {
+		u8 flags;
+		u8 lsn;
+		u8 desc;
+		u8 chpid;
+		u8 swla;
+		u8 zeroes;
+		u8 chla;
+		u8 chpp;
+	} *chp_dsc;
+
+	QETH_DBF_TEXT(setup, 2, "chk_1920");
+
+	ccwdev = card->data.ccwdev;
+	chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
+	if (chp_dsc != NULL) {
+		/* CHPP field bit 6 == 1 -> single queue */
+		single_queue = ((chp_dsc->chpp & 0x02) == 0x02);
+		kfree(chp_dsc);
+	}
+	QETH_DBF_TEXT_(setup, 2, "rc:%x", single_queue);
+	return single_queue;
+}
+
+static int
 qeth_determine_card_type(struct qeth_card *card)
 {
 	int i = 0;
@@ -1081,7 +1122,14 @@ qeth_determine_card_type(struct qeth_car
 		if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
 		    (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
 			card->info.type = known_devices[i][4];
-			card->qdio.no_out_queues = known_devices[i][8];
+			if (is_1920_device(card)) {
+				PRINT_INFO("Priority Queueing not able "
+					   "due to hardware limitations!\n");
+				card->qdio.no_out_queues = 1;
+				card->qdio.default_out_queue = 0;
+			} else {
+				card->qdio.no_out_queues = known_devices[i][8];
+			}
 			card->info.is_multicast_different = known_devices[i][9];
 			return 0;
 		}
@@ -1112,6 +1160,10 @@ qeth_probe_device(struct ccwgroup_device
 		QETH_DBF_TEXT_(setup, 2, "1err%d", -ENOMEM);
 		return -ENOMEM;
 	}
+	card->read.ccwdev  = gdev->cdev[0];
+	card->write.ccwdev = gdev->cdev[1];
+	card->data.ccwdev  = gdev->cdev[2];
+
 	if ((rc = qeth_setup_card(card))){
 		QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
 		put_device(dev);
@@ -1130,9 +1182,6 @@ qeth_probe_device(struct ccwgroup_device
 		qeth_free_card(card);
 		return rc;
 	}
-	card->read.ccwdev  = gdev->cdev[0];
-	card->write.ccwdev = gdev->cdev[1];
-	card->data.ccwdev  = gdev->cdev[2];
 	if ((rc = qeth_determine_card_type(card))){
 		PRINT_WARN("%s: not a valid card type\n", __func__);
 		QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
@@ -1631,10 +1680,7 @@ qeth_check_ipa_data(struct qeth_card *ca
 				QETH_DBF_TEXT(trace,3, "irla");
 				break;
 			case IPA_CMD_UNREGISTER_LOCAL_ADDR:
-				PRINT_WARN("probably problem on %s: "
-					   "received IPA command 0x%X\n",
-					   QETH_CARD_IFNAME(card),
-					   cmd->hdr.command);
+				QETH_DBF_TEXT(trace,3, "urla");
 				break;
 			default:
 				PRINT_WARN("Received data is IPA "
@@ -1714,7 +1760,7 @@ qeth_send_control_data_cb(struct qeth_ch
 							(unsigned long)iob);
 			}
 			if (cmd)
-				reply->rc = (s16) cmd->hdr.return_code;
+				reply->rc = (u16) cmd->hdr.return_code;
 			else if (iob->rc)
 				reply->rc = iob->rc;
 			if (keep_reply) {
@@ -2115,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card
 	if (!skb_len)
 		return NULL;
 	if (card->options.fake_ll){
-		if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN)))
-			goto no_mem;
-		skb_pull(skb, QETH_FAKE_LL_LEN);
+		if(card->dev->type == ARPHRD_IEEE802_TR){
+			if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR)))
+				goto no_mem;
+			skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
+		} else {
+			if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH)))
+				goto no_mem;
+			skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
+		}
 	} else if (!(skb = qeth_get_skb(skb_len)))
 		goto no_mem;
 	data_ptr = element->addr + offset;
@@ -2192,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, str
 }
 
 static inline void
-qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
+			 struct qeth_hdr *hdr)
+{
+	struct trh_hdr *fake_hdr;
+	struct trllc *fake_llc;
+	struct iphdr *ip_hdr;
+
+	QETH_DBF_TEXT(trace,5,"skbfktr");
+	skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
+	/* this is a fake ethernet header */
+	fake_hdr = (struct trh_hdr *) skb->mac.raw;
+
+	/* the destination MAC address */
+	switch (skb->pkt_type){
+	case PACKET_MULTICAST:
+		switch (skb->protocol){
+#ifdef CONFIG_QETH_IPV6
+		case __constant_htons(ETH_P_IPV6):
+			ndisc_mc_map((struct in6_addr *)
+				     skb->data + QETH_FAKE_LL_V6_ADDR_POS,
+				     fake_hdr->daddr, card->dev, 0);
+			break;
+#endif /* CONFIG_QETH_IPV6 */
+		case __constant_htons(ETH_P_IP):
+			ip_hdr = (struct iphdr *)skb->data;
+			ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr);
+			break;
+		default:
+			memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+		}
+		break;
+	case PACKET_BROADCAST:
+		memset(fake_hdr->daddr, 0xff, TR_ALEN);
+		break;
+	default:
+		memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+	}
+	/* the source MAC address */
+	if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+		memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN);
+	else
+		memset(fake_hdr->saddr, 0, TR_ALEN);
+	fake_hdr->rcf=0;
+	fake_llc = (struct trllc*)&(fake_hdr->rcf);
+	fake_llc->dsap = EXTENDED_SAP;
+	fake_llc->ssap = EXTENDED_SAP;
+	fake_llc->llc  = UI_CMD;
+	fake_llc->protid[0] = 0;
+	fake_llc->protid[1] = 0;
+	fake_llc->protid[2] = 0;
+	fake_llc->ethertype = ETH_P_IP;
+}
+
+static inline void
+qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
 			 struct qeth_hdr *hdr)
 {
 	struct ethhdr *fake_hdr;
 	struct iphdr *ip_hdr;
 
-	QETH_DBF_TEXT(trace,5,"skbfake");
-	skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
+	QETH_DBF_TEXT(trace,5,"skbfketh");
+	skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
 	/* this is a fake ethernet header */
 	fake_hdr = (struct ethhdr *) skb->mac.raw;
 
@@ -2216,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_car
 #endif /* CONFIG_QETH_IPV6 */
 		case __constant_htons(ETH_P_IP):
 			ip_hdr = (struct iphdr *)skb->data;
-			if (card->dev->type == ARPHRD_IEEE802_TR)
-				ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
-			else
-				ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
+			ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
 			break;
 		default:
 			memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
@@ -2241,6 +2344,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_car
 }
 
 static inline void
+qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+			struct qeth_hdr *hdr)
+{
+	if (card->dev->type == ARPHRD_IEEE802_TR)
+		qeth_rebuild_skb_fake_ll_tr(card, skb, hdr);
+	else
+		qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
+}
+
+static inline void
 qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
 		      struct qeth_hdr *hdr)
 {
@@ -2263,19 +2376,25 @@ qeth_layer2_rebuild_skb(struct qeth_card
 			struct qeth_hdr *hdr)
 {
 	unsigned short vlan_id = 0;
+#ifdef CONFIG_QETH_VLAN
+	struct vlan_hdr *vhdr;
+#endif
 
 	skb->pkt_type = PACKET_HOST;
+	skb->protocol = qeth_type_trans(skb, skb->dev);
 	if (card->options.checksum_type == NO_CHECKSUMMING)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	else
 		skb->ip_summed = CHECKSUM_NONE;
 #ifdef CONFIG_QETH_VLAN
 	if (hdr->hdr.l2.flags[2] & (QETH_LAYER2_FLAG_VLAN)) {
+		vhdr = (struct vlan_hdr *) skb->data;
+		skb->protocol =
+			__constant_htons(vhdr->h_vlan_encapsulated_proto);
 		vlan_id = hdr->hdr.l2.vlan_id;
 		skb_pull(skb, VLAN_HLEN);
 	}
 #endif
-	skb->protocol = qeth_type_trans(skb, skb->dev);
 	return vlan_id;
 }
 
@@ -2421,14 +2540,15 @@ qeth_clear_output_buffer(struct qeth_qdi
 	if (buf->buffer->element[0].flags & 0x40)
 		atomic_dec(&queue->set_pci_flags_count);
 
+	while ((skb = skb_dequeue(&buf->skb_list))){
+		atomic_dec(&skb->users);
+		dev_kfree_skb_any(skb);
+	}
+	qeth_eddp_buf_release_contexts(buf);
 	for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i){
 		buf->buffer->element[i].length = 0;
 		buf->buffer->element[i].addr = NULL;
 		buf->buffer->element[i].flags = 0;
-		while ((skb = skb_dequeue(&buf->skb_list))){
-			atomic_dec(&skb->users);
-			dev_kfree_skb_any(skb);
-		}
 	}
 	buf->next_element_to_fill = 0;
 	atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
@@ -2578,7 +2698,7 @@ qeth_handle_send_error(struct qeth_card 
 	return QETH_SEND_ERROR_LINK_FAILURE;
 }
 
-static inline void
+void
 qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
 		   int index, int count)
 {
@@ -2619,9 +2739,6 @@ qeth_flush_buffers(struct qeth_qdio_out_
 				atomic_inc(&queue->set_pci_flags_count);
 				buf->buffer->element[0].flags |= 0x40;
 			}
-#ifdef CONFIG_QETH_PERF_STATS
-			queue->card->perf_stats.bufs_sent_pack++;
-#endif
 		}
 	}
 
@@ -2743,6 +2860,7 @@ qeth_check_outbound_queue(struct qeth_qd
 {
 	int index;
 	int flush_cnt = 0;
+	int q_was_packing = 0;
 
 	/*
 	 * check if weed have to switch to non-packing mode or if
@@ -2757,20 +2875,22 @@ qeth_check_outbound_queue(struct qeth_qd
 			 * do_send_packet. So, we check if there is a
 			 * packing buffer to be flushed here.
 			 */
-			/* TODO: try if we get a performance improvement
-			 * by calling netif_stop_queue here */
-			/* save start index for flushing */
+			netif_stop_queue(queue->card->dev);
 			index = queue->next_buf_to_fill;
+			q_was_packing = queue->do_pack;
 			flush_cnt += qeth_switch_to_nonpacking_if_needed(queue);
 			if (!flush_cnt &&
 			    !atomic_read(&queue->set_pci_flags_count))
 				flush_cnt +=
 					qeth_flush_buffers_on_no_pci(queue);
-			/* were done with updating critical queue members */
-			atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-			/* flushing can be done outside the lock */
+#ifdef CONFIG_QETH_PERF_STATS
+			if (q_was_packing)
+				queue->card->perf_stats.bufs_sent_pack +=
+					flush_cnt;
+#endif
 			if (flush_cnt)
 				qeth_flush_buffers(queue, 1, index, flush_cnt);
+			atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
 		}
 	}
 }
@@ -2800,7 +2920,6 @@ qeth_qdio_output_handler(struct ccw_devi
 			return;
 		}
 	}
-
 #ifdef CONFIG_QETH_PERF_STATS
 	card->perf_stats.outbound_handler_cnt++;
 	card->perf_stats.outbound_handler_start_time = qeth_get_micros();
@@ -2821,24 +2940,16 @@ qeth_qdio_output_handler(struct ccw_devi
 	if (card->info.type != QETH_CARD_TYPE_IQD)
 		qeth_check_outbound_queue(queue);
 
-	netif_wake_queue(card->dev);
+	netif_wake_queue(queue->card->dev);
 #ifdef CONFIG_QETH_PERF_STATS
 	card->perf_stats.outbound_handler_time += qeth_get_micros() -
 		card->perf_stats.outbound_handler_start_time;
 #endif
 }
 
-static char*
-qeth_create_qib_param_field(struct qeth_card *card)
+static void
+qeth_create_qib_param_field(struct qeth_card *card, char *param_field)
 {
-	char *param_field;
-
-	param_field = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
-			      GFP_KERNEL);
- 	if (!param_field)
-		return NULL;
-
- 	memset(param_field, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
 
 	param_field[0] = _ascebc['P'];
 	param_field[1] = _ascebc['C'];
@@ -2847,8 +2958,18 @@ qeth_create_qib_param_field(struct qeth_
 	*((unsigned int *) (&param_field[4])) = QETH_PCI_THRESHOLD_A(card);
 	*((unsigned int *) (&param_field[8])) = QETH_PCI_THRESHOLD_B(card);
 	*((unsigned int *) (&param_field[12])) = QETH_PCI_TIMER_VALUE(card);
+}
 
-	return param_field;
+static void
+qeth_create_qib_param_field_blkt(struct qeth_card *card, char *param_field)
+{
+	param_field[16] = _ascebc['B'];
+        param_field[17] = _ascebc['L'];
+        param_field[18] = _ascebc['K'];
+        param_field[19] = _ascebc['T'];
+        *((unsigned int *) (&param_field[20])) = card->info.blkt.time_total;
+        *((unsigned int *) (&param_field[24])) = card->info.blkt.inter_packet;
+        *((unsigned int *) (&param_field[28])) = card->info.blkt.inter_packet_jumbo;
 }
 
 static void
@@ -2898,7 +3019,7 @@ qeth_alloc_buffer_pool(struct qeth_card 
 	void *ptr;
 	int i, j;
 
-	QETH_DBF_TEXT(trace,5,"clwkpool");
+	QETH_DBF_TEXT(trace,5,"alocpool");
 	for (i = 0; i < card->qdio.init_pool.buf_count; ++i){
 	 	pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
 		if (!pool_entry){
@@ -2986,12 +3107,13 @@ qeth_alloc_qdio_buffers(struct qeth_card
 		QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *));
 		memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q));
 		card->qdio.out_qs[i]->queue_no = i;
-		/* give inbound qeth_qdio_buffers their qdio_buffers */
+		/* give outbound qeth_qdio_buffers their qdio_buffers */
 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j){
 			card->qdio.out_qs[i]->bufs[j].buffer =
 				&card->qdio.out_qs[i]->qdio_bufs[j];
 			skb_queue_head_init(&card->qdio.out_qs[i]->bufs[j].
 					    skb_list);
+			INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list);
 		}
 	}
 	card->qdio.state = QETH_QDIO_ALLOCATED;
@@ -3108,10 +3230,17 @@ qeth_qdio_establish(struct qeth_card *ca
 	int rc;
 
 	QETH_DBF_TEXT(setup, 2, "qdioest");
-	qib_param_field = qeth_create_qib_param_field(card);
-	if (!qib_param_field)
+
+	qib_param_field = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
+			      GFP_KERNEL);
+ 	if (!qib_param_field)
 		return -ENOMEM;
 
+ 	memset(qib_param_field, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
+
+	qeth_create_qib_param_field(card, qib_param_field);
+	qeth_create_qib_param_field_blkt(card, qib_param_field);
+
 	in_sbal_ptrs = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(void *),
 			       GFP_KERNEL);
 	if (!in_sbal_ptrs) {
@@ -3387,18 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, st
 		     unsigned short type, void *daddr, void *saddr,
 		     unsigned len)
 {
-	struct ethhdr *hdr;
-	struct qeth_card *card;
+	if(dev->type == ARPHRD_IEEE802_TR){
+		struct trh_hdr *hdr;
+        	hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR);
+		memcpy(hdr->saddr, dev->dev_addr, TR_ALEN);
+        	memcpy(hdr->daddr, "FAKELL", TR_ALEN);
+		return QETH_FAKE_LL_LEN_TR;
 
-	card = (struct qeth_card *)dev->priv;
-        hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN);
-	memcpy(hdr->h_source, card->dev->dev_addr, ETH_ALEN);
-        memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
-        if (type != ETH_P_802_3)
-                hdr->h_proto = htons(type);
-        else
-                hdr->h_proto = htons(len);
-	return QETH_FAKE_LL_LEN;
+	} else {
+		struct ethhdr *hdr;
+        	hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH);
+		memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
+        	memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
+        	if (type != ETH_P_802_3)
+                	hdr->h_proto = htons(type);
+        	else
+                	hdr->h_proto = htons(len);
+		return QETH_FAKE_LL_LEN_ETH;
+
+	}
 }
 
 static inline int
@@ -3430,32 +3566,19 @@ qeth_hard_start_xmit(struct sk_buff *skb
 	card->perf_stats.outbound_cnt++;
 	card->perf_stats.outbound_start_time = qeth_get_micros();
 #endif
-	if (dev->hard_header == qeth_fake_header) {
-               if ((skb = qeth_pskb_unshare(skb, GFP_ATOMIC)) == NULL) {
-                        card->stats.tx_dropped++;
-                        dev_kfree_skb_irq(skb);
-                        return 0;
-                }
-                skb_pull(skb, QETH_FAKE_LL_LEN);
-	}
-	/*
-	 * We only call netif_stop_queue in case of errors. Since we've
-	 * got our own synchronization on queues we can keep the stack's
-	 * queue running.
-	 */
-	if ((rc = qeth_send_packet(card, skb))){
+	netif_stop_queue(dev);
+	if ((rc = qeth_send_packet(card, skb))) {
 		if (rc == -EBUSY) {
-			netif_stop_queue(dev);
-			rc = NETDEV_TX_BUSY;
+			return NETDEV_TX_BUSY;
 		} else {
 			card->stats.tx_errors++;
 			card->stats.tx_dropped++;
 			dev_kfree_skb_any(skb);
-			/* set to OK; otherwise ksoftirqd goes to 100% */
+			/*set to OK; otherwise ksoftirqd goes to 100% */
 			rc = NETDEV_TX_OK;
 		}
 	}
-
+	netif_wake_queue(dev);
 #ifdef CONFIG_QETH_PERF_STATS
 	card->perf_stats.outbound_time += qeth_get_micros() -
 		card->perf_stats.outbound_start_time;
@@ -3649,8 +3772,9 @@ qeth_get_priority_queue(struct qeth_card
 			/* TODO: IPv6!!! */
 		}
 		return card->qdio.default_out_queue;
+	case 1: /* fallthrough for single-out-queue 1920-device */
 	default:
-		return 0;
+		return card->qdio.default_out_queue;
 	}
 }
 
@@ -3671,22 +3795,12 @@ static inline int
 qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
 		 struct qeth_hdr **hdr, int ipv)
 {
-	struct sk_buff *new_skb;
 #ifdef CONFIG_QETH_VLAN
 	u16 *tag;
 #endif
 
 	QETH_DBF_TEXT(trace, 6, "prepskb");
-	if (skb_headroom(*skb) < sizeof(struct qeth_hdr)){
-		new_skb = skb_realloc_headroom(*skb, sizeof(struct qeth_hdr));
-		if (!new_skb) {
-			PRINT_ERR("qeth_prepare_skb: could "
-				  "not realloc headroom for qeth_hdr "
-				  "on interface %s", QETH_CARD_IFNAME(card));
-			return -ENOMEM;
-		}
-		*skb = new_skb;
-	}
+
 #ifdef CONFIG_QETH_VLAN
 	if (card->vlangrp && vlan_tx_tag_present(*skb) &&
 	    ((ipv == 6) || card->options.layer2) ) {
@@ -3708,20 +3822,10 @@ qeth_prepare_skb(struct qeth_card *card,
 		*(tag + 1) = htons(vlan_tx_tag_get(*skb));
 	}
 #endif
-	*hdr = (struct qeth_hdr *) skb_push(*skb, sizeof(struct qeth_hdr));
-	/*
-	 * sanity check, the Linux memory allocation scheme should
-	 * never present us cases like this one (the 32bytes header plus
-	 * the first 40 bytes of the paket cross a 4k boundary)
-	 */
-	if ((((unsigned long) *hdr) & (~(PAGE_SIZE - 1))) !=
-	    (((unsigned long) *hdr + sizeof(struct qeth_hdr) +
-	      QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
-		PRINT_ERR("qeth_prepare_skb: misaligned "
-			  "packet on interface %s. Discarded.",
-			  QETH_CARD_IFNAME(card));
+	*hdr = (struct qeth_hdr *)
+		qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
+	if (hdr == NULL)
 		return -EINVAL;
-	}
 	return 0;
 }
 
@@ -3813,12 +3917,13 @@ qeth_layer2_fill_header(struct qeth_card
 #endif
 }
 
-static inline void
+void
 qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
 		struct sk_buff *skb, int ipv, int cast_type)
 {
 	QETH_DBF_TEXT(trace, 6, "fillhdr");
 
+	memset(hdr, 0, sizeof(struct qeth_hdr));
 	if (card->options.layer2) {
 		qeth_layer2_fill_header(card, hdr, skb, cast_type);
 		return;
@@ -3858,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card,
 			memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
 		}
 	} else { /* passthrough */
-		if (!memcmp(skb->data + sizeof(struct qeth_hdr),
+                if((skb->dev->type == ARPHRD_IEEE802_TR) &&
+		    !memcmp(skb->data + sizeof(struct qeth_hdr) + 
+		    sizeof(__u16), skb->dev->broadcast, 6)) {
+			hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+						QETH_HDR_PASSTHRU;
+		} else if (!memcmp(skb->data + sizeof(struct qeth_hdr),
 			    skb->dev->broadcast, 6)) {   /* broadcast? */
-			hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU;
+			hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+						QETH_HDR_PASSTHRU;
 		} else {
  			hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
  				QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
@@ -3869,30 +3980,30 @@ qeth_fill_header(struct qeth_card *card,
 	}
 }
 
-static inline int
-qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf,
-		 char *data, struct sk_buff *skb)
+static inline void
+__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
+		   int is_tso, int *next_element_to_fill)
 {
-	struct qdio_buffer *buffer;
 	int length = skb->len;
 	int length_here;
 	int element;
-	int first_lap = 1;
+	char *data;
+	int first_lap ;
+
+	element = *next_element_to_fill;
+	data = skb->data;
+	first_lap = (is_tso == 0 ? 1 : 0);
 
-	QETH_DBF_TEXT(trace, 6, "qdfillbf");
-	buffer = buf->buffer;
-	atomic_inc(&skb->users);
-	skb_queue_tail(&buf->skb_list, skb);
-	element = buf->next_element_to_fill;
 	while (length > 0) {
 		/* length_here is the remaining amount of data in this page */
 		length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
 		if (length < length_here)
 			length_here = length;
+
 		buffer->element[element].addr = data;
 		buffer->element[element].length = length_here;
 		length -= length_here;
-		if (!length){
+		if (!length) {
 			if (first_lap)
 				buffer->element[element].flags = 0;
 			else
@@ -3910,11 +4021,51 @@ qeth_fill_buffer(struct qeth_qdio_out_q 
 		element++;
 		first_lap = 0;
 	}
-	buf->next_element_to_fill = element;
+	*next_element_to_fill = element;
+}
+
+static inline int
+qeth_fill_buffer(struct qeth_qdio_out_q *queue,
+		 struct qeth_qdio_out_buffer *buf,
+		 struct sk_buff *skb)
+{
+	struct qdio_buffer *buffer;
+	struct qeth_hdr_tso *hdr;
+	int flush_cnt = 0, hdr_len, large_send = 0;
+
+	QETH_DBF_TEXT(trace, 6, "qdfillbf");
+
+	buffer = buf->buffer;
+	atomic_inc(&skb->users);
+	skb_queue_tail(&buf->skb_list, skb);
+
+	hdr  = (struct qeth_hdr_tso *) skb->data;
+	/*check first on TSO ....*/
+	if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
+		int element = buf->next_element_to_fill;
+
+		hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
+		/*fill first buffer entry only with header information */
+		buffer->element[element].addr = skb->data;
+		buffer->element[element].length = hdr_len;
+		buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+		buf->next_element_to_fill++;
+		skb->data += hdr_len;
+		skb->len  -= hdr_len;
+		large_send = 1;
+	}
+	if (skb_shinfo(skb)->nr_frags == 0)
+		__qeth_fill_buffer(skb, buffer, large_send,
+				   (int *)&buf->next_element_to_fill);
+	else
+		__qeth_fill_buffer_frag(skb, buffer, large_send,
+					(int *)&buf->next_element_to_fill);
+
 	if (!queue->do_pack) {
 		QETH_DBF_TEXT(trace, 6, "fillbfnp");
 		/* set state to PRIMED -> will be flushed */
 		atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+		flush_cnt = 1;
 	} else {
 		QETH_DBF_TEXT(trace, 6, "fillbfpa");
 #ifdef CONFIG_QETH_PERF_STATS
@@ -3927,17 +4078,21 @@ qeth_fill_buffer(struct qeth_qdio_out_q 
 			 * -> will be flushed
 			 */
 			atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+			flush_cnt = 1;
 		}
 	}
-	return 0;
+	return flush_cnt;
 }
 
 static inline int
 qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 			 struct sk_buff *skb, struct qeth_hdr *hdr,
-			 int elements_needed)
+			 int elements_needed,
+			 struct qeth_eddp_context *ctx)
 {
 	struct qeth_qdio_out_buffer *buffer;
+	int buffers_needed = 0;
+	int flush_cnt = 0;
 	int index;
 
 	QETH_DBF_TEXT(trace, 6, "dosndpfa");
@@ -3958,22 +4113,42 @@ qeth_do_send_packet_fast(struct qeth_car
 		atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
 		return -EBUSY;
 	}
-	queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
-				  QDIO_MAX_BUFFERS_PER_Q;
+	if (ctx == NULL)
+		queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+					  QDIO_MAX_BUFFERS_PER_Q;
+	else {
+		buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx);
+		if (buffers_needed < 0) {
+			card->stats.tx_dropped++;
+			atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+			return -EBUSY;
+		}
+		queue->next_buf_to_fill =
+			(queue->next_buf_to_fill + buffers_needed) %
+			QDIO_MAX_BUFFERS_PER_Q;
+	}
 	atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-	qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
-	qeth_flush_buffers(queue, 0, index, 1);
+	if (ctx == NULL) {
+		qeth_fill_buffer(queue, buffer, skb);
+		qeth_flush_buffers(queue, 0, index, 1);
+	} else {
+		flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index);
+		WARN_ON(buffers_needed != flush_cnt);
+		qeth_flush_buffers(queue, 0, index, flush_cnt);
+	}
 	return 0;
 }
 
 static inline int
 qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 		    struct sk_buff *skb, struct qeth_hdr *hdr,
-		    int elements_needed)
+		    int elements_needed, struct qeth_eddp_context *ctx)
 {
 	struct qeth_qdio_out_buffer *buffer;
 	int start_index;
 	int flush_count = 0;
+	int do_pack = 0;
+	int tmp;
 	int rc = 0;
 
 	QETH_DBF_TEXT(trace, 6, "dosndpkt");
@@ -3996,34 +4171,56 @@ qeth_do_send_packet(struct qeth_card *ca
 	/* check if we need to switch packing state of this queue */
 	qeth_switch_to_packing_if_needed(queue);
 	if (queue->do_pack){
-		/* does packet fit in current buffer? */
-		if((QETH_MAX_BUFFER_ELEMENTS(card) -
-		    buffer->next_element_to_fill) < elements_needed){
-			/* ... no -> set state PRIMED */
-			atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
-			flush_count++;
-			queue->next_buf_to_fill =
-				(queue->next_buf_to_fill + 1) %
-				QDIO_MAX_BUFFERS_PER_Q;
-			buffer = &queue->bufs[queue->next_buf_to_fill];
-			/* we did a step forward, so check buffer state again */
-			if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
+		do_pack = 1;
+		if (ctx == NULL) {
+			/* does packet fit in current buffer? */
+			if((QETH_MAX_BUFFER_ELEMENTS(card) -
+			    buffer->next_element_to_fill) < elements_needed){
+				/* ... no -> set state PRIMED */
+				atomic_set(&buffer->state,QETH_QDIO_BUF_PRIMED);
+				flush_count++;
+				queue->next_buf_to_fill =
+					(queue->next_buf_to_fill + 1) %
+					QDIO_MAX_BUFFERS_PER_Q;
+				buffer = &queue->bufs[queue->next_buf_to_fill];
+				/* we did a step forward, so check buffer state
+				 * again */
+				if (atomic_read(&buffer->state) !=
+						QETH_QDIO_BUF_EMPTY){
+					card->stats.tx_dropped++;
+					qeth_flush_buffers(queue, 0, start_index, flush_count);
+					atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+					return -EBUSY;
+				}
+			}
+		} else {
+			/* check if we have enough elements (including following
+			 * free buffers) to handle eddp context */
+			if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
+				printk("eddp tx_dropped 1\n");
 				card->stats.tx_dropped++;
-				/* return EBUSY because we sent old packet, not
-				 * the current one */
 				rc = -EBUSY;
-				atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
 				goto out;
 			}
 		}
 	}
-	qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
-	if (atomic_read(&buffer->state) == QETH_QDIO_BUF_PRIMED){
-		/* next time fill the next buffer */
-		flush_count++;
-		queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
-			QDIO_MAX_BUFFERS_PER_Q;
+	if (ctx == NULL)
+		tmp = qeth_fill_buffer(queue, buffer, skb);
+	else {
+		tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill);
+		if (tmp < 0) {
+			printk("eddp tx_dropped 2\n");
+			card->stats.tx_dropped++;
+			rc = - EBUSY;
+			goto out;
+		}
 	}
+	queue->next_buf_to_fill = (queue->next_buf_to_fill + tmp) %
+				  QDIO_MAX_BUFFERS_PER_Q;
+	flush_count += tmp;
+out:
+	if (flush_count)
+		qeth_flush_buffers(queue, 0, start_index, flush_count);
 	/*
 	 * queue->state will go from LOCKED -> UNLOCKED or from
 	 * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
@@ -4031,6 +4228,8 @@ qeth_do_send_packet(struct qeth_card *ca
 	 * In that case we will enter this loop
 	 */
 	while (atomic_dec_return(&queue->state)){
+		flush_count = 0;
+		start_index = queue->next_buf_to_fill;
 		/* check if we can go back to non-packing state */
 		flush_count += qeth_switch_to_nonpacking_if_needed(queue);
 		/*
@@ -4039,56 +4238,140 @@ qeth_do_send_packet(struct qeth_card *ca
 		 */
 		if (!flush_count && !atomic_read(&queue->set_pci_flags_count))
 			flush_count += qeth_flush_buffers_on_no_pci(queue);
+		if (flush_count)
+			qeth_flush_buffers(queue, 0, start_index, flush_count);
 	}
 	/* at this point the queue is UNLOCKED again */
-out:
-	if (flush_count)
-		qeth_flush_buffers(queue, 0, start_index, flush_count);
+#ifdef CONFIG_QETH_PERF_STATS
+	if (do_pack)
+		queue->card->perf_stats.bufs_sent_pack += flush_count;
+#endif /* CONFIG_QETH_PERF_STATS */
 
 	return rc;
 }
 
 static inline int
+qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+{
+	int elements_needed = 0;
+
+        if (skb_shinfo(skb)->nr_frags > 0) {
+                elements_needed = (skb_shinfo(skb)->nr_frags + 1);
+	}
+        if (elements_needed == 0 )
+                elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+                                        + skb->len) >> PAGE_SHIFT);
+        if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
+                PRINT_ERR("qeth_do_send_packet: invalid size of "
+                          "IP packet. Discarded.");
+                return 0;
+        }
+        return elements_needed;
+}
+
+static inline int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
 {
 	int ipv = 0;
 	int cast_type;
 	struct qeth_qdio_out_q *queue;
 	struct qeth_hdr *hdr;
-	int elements_needed;
+	int elements_needed = 0;
+	enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
+	struct qeth_eddp_context *ctx = NULL;
 	int rc;
 
 	QETH_DBF_TEXT(trace, 6, "sendpkt");
 
-	if (!card->options.layer2)
+	if (!card->options.layer2) {
 		ipv = qeth_get_ip_version(skb);
+		if ((card->dev->hard_header == qeth_fake_header) && ipv) {
+               		if ((skb = qeth_pskb_unshare(skb,GFP_ATOMIC)) == NULL) {
+                        	card->stats.tx_dropped++;
+                        	dev_kfree_skb_irq(skb);
+                        	return 0;
+                	}
+			if(card->dev->type == ARPHRD_IEEE802_TR){
+				skb_pull(skb, QETH_FAKE_LL_LEN_TR);
+			} else {
+                		skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
+			}
+		}
+	}
 	cast_type = qeth_get_cast_type(card, skb);
+	if ((cast_type == RTN_BROADCAST) && (card->info.broadcast_capable == 0)){
+		card->stats.tx_dropped++;
+		card->stats.tx_errors++;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
 	queue = card->qdio.out_qs
 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
 
-	if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
-		QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
-		return rc;
+	if (skb_shinfo(skb)->tso_size)
+		large_send = card->options.large_send;
+
+	/*are we able to do TSO ? If so ,prepare and send it from here */
+	if ((large_send == QETH_LARGE_SEND_TSO) &&
+	    (cast_type == RTN_UNSPEC)) {
+		rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
+		if (rc) {
+			card->stats.tx_dropped++;
+			card->stats.tx_errors++;
+			dev_kfree_skb_any(skb);
+			return NETDEV_TX_OK;
+		} 
+		elements_needed++;
+	} else {
+		if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
+			QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
+			return rc;
+		}
+		qeth_fill_header(card, hdr, skb, ipv, cast_type);
 	}
-	qeth_fill_header(card, hdr, skb, ipv, cast_type);
-	elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len)
-				>> PAGE_SHIFT);
-	if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
-		PRINT_ERR("qeth_do_send_packet: invalid size of "
-				 "IP packet. Discarded.");
-		return -EINVAL;
+
+	if (large_send == QETH_LARGE_SEND_EDDP) {
+		ctx = qeth_eddp_create_context(card, skb, hdr);
+		if (ctx == NULL) {
+			PRINT_WARN("could not create eddp context\n");
+			return -EINVAL;
+		}
+	} else {
+		elements_needed += qeth_get_elements_no(card,(void*) hdr, skb);
+		if (!elements_needed)
+			return -EINVAL;
 	}
 
 	if (card->info.type != QETH_CARD_TYPE_IQD)
 		rc = qeth_do_send_packet(card, queue, skb, hdr,
-					 elements_needed);
+					 elements_needed, ctx);
 	else
 		rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
-					      elements_needed);
-
+					      elements_needed, ctx);
 	if (!rc){
 		card->stats.tx_packets++;
 		card->stats.tx_bytes += skb->len;
+#ifdef CONFIG_QETH_PERF_STATS
+		if (skb_shinfo(skb)->tso_size &&
+		   !(large_send == QETH_LARGE_SEND_NO)) {
+			card->perf_stats.large_send_bytes += skb->len;
+			card->perf_stats.large_send_cnt++;
+		}
+ 		if (skb_shinfo(skb)->nr_frags > 0){
+			card->perf_stats.sg_skbs_sent++;
+			/* nr_frags + skb->data */
+			card->perf_stats.sg_frags_sent +=
+				skb_shinfo(skb)->nr_frags + 1;
+		}
+#endif /* CONFIG_QETH_PERF_STATS */
+	}
+	if (ctx != NULL) {
+		/* drop creator's reference */
+		qeth_eddp_put_context(ctx);
+		/* free skb; it's not referenced by a buffer */
+		if (rc == 0)
+			dev_kfree_skb_any(skb);
+
 	}
 	return rc;
 }
@@ -4943,6 +5226,7 @@ out:
 static void
 qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
 {
+#ifdef CONFIG_QETH_IPV6
 	struct inet6_dev *in6_dev;
 	struct inet6_ifaddr *ifa;
 	struct qeth_ipaddr *addr;
@@ -4965,6 +5249,7 @@ qeth_free_vlan_addresses6(struct qeth_ca
 		}
 	}
 	in6_dev_put(in6_dev);
+#endif /* CONFIG_QETH_IPV6 */
 }
 
 static void
@@ -5242,7 +5527,8 @@ qeth_add_multicast_ipv6(struct qeth_card
 	struct inet6_dev *in6_dev;
 
 	QETH_DBF_TEXT(trace,4,"chkmcv6");
-	if (!qeth_is_supported(card, IPA_IPV6))
+	if ((card->options.layer2 == 0) &&
+	    (!qeth_is_supported(card, IPA_IPV6)) )
 		return ;
 
 	in6_dev = in6_dev_get(card->dev);
@@ -5563,7 +5849,7 @@ static int
 qeth_layer3_register_addr_entry(struct qeth_card *card,
 				struct qeth_ipaddr *addr)
 {
-	//char buf[50];
+	char buf[50];
 	int rc;
 	int cnt = 3;
 
@@ -5589,12 +5875,9 @@ qeth_layer3_register_addr_entry(struct q
 	} while ((--cnt > 0) && rc);
 	if (rc){
 		QETH_DBF_TEXT(trace, 2, "FAILED");
-		/* TODO: re-activate this warning as soon as we have a
-		 * clean mirco code
 		qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
-		PRINT_WARN("Could not register IP address %s (rc=%x)\n",
-			   buf, rc);
-		*/
+		PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n",
+			   buf, rc, rc);
 	}
 	return rc;
 }
@@ -5652,6 +5935,111 @@ qeth_deregister_addr_entry(struct qeth_c
 	return qeth_layer3_deregister_addr_entry(card, addr);
 }
 
+static u32
+qeth_ethtool_get_tx_csum(struct net_device *dev)
+{
+	/* We may need to say that we support tx csum offload if
+	 * we do EDDP or TSO. There are discussions going on to
+	 * enforce rules in the stack and in ethtool that make
+	 * SG and TSO depend on HW_CSUM. At the moment there are
+	 * no such rules....
+	 * If we say yes here, we have to checksum outbound packets
+	 * any time. */
+	return 0;
+}
+
+static int
+qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data)
+{
+	return -EINVAL;
+}
+
+static u32
+qeth_ethtool_get_rx_csum(struct net_device *dev)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	return (card->options.checksum_type == HW_CHECKSUMMING);
+}
+
+static int
+qeth_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	if ((card->state != CARD_STATE_DOWN) &&
+	    (card->state != CARD_STATE_RECOVER))
+		return -EPERM;
+	if (data)
+		card->options.checksum_type = HW_CHECKSUMMING;
+	else
+		card->options.checksum_type = SW_CHECKSUMMING;
+	return 0;
+}
+
+static u32
+qeth_ethtool_get_sg(struct net_device *dev)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	return ((card->options.large_send != QETH_LARGE_SEND_NO) &&
+		(dev->features & NETIF_F_SG));
+}
+
+static int
+qeth_ethtool_set_sg(struct net_device *dev, u32 data)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	if (data) {
+		if (card->options.large_send != QETH_LARGE_SEND_NO)
+			dev->features |= NETIF_F_SG;
+		else {
+			dev->features &= ~NETIF_F_SG;
+			return -EINVAL;
+		}
+	} else
+		dev->features &= ~NETIF_F_SG;
+	return 0;
+}
+
+static u32
+qeth_ethtool_get_tso(struct net_device *dev)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	return ((card->options.large_send != QETH_LARGE_SEND_NO) &&
+		(dev->features & NETIF_F_TSO));
+}
+
+static int
+qeth_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+	struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+	if (data) {
+		if (card->options.large_send != QETH_LARGE_SEND_NO)
+			dev->features |= NETIF_F_TSO;
+		else {
+			dev->features &= ~NETIF_F_TSO;
+			return -EINVAL;
+		}
+	} else
+		dev->features &= ~NETIF_F_TSO;
+	return 0;
+}
+
+static struct ethtool_ops qeth_ethtool_ops = {
+	.get_tx_csum = qeth_ethtool_get_tx_csum,
+	.set_tx_csum = qeth_ethtool_set_tx_csum,
+	.get_rx_csum = qeth_ethtool_get_rx_csum,
+	.set_rx_csum = qeth_ethtool_set_rx_csum,
+	.get_sg      = qeth_ethtool_get_sg,
+	.set_sg      = qeth_ethtool_set_sg,
+	.get_tso     = qeth_ethtool_get_tso,
+	.set_tso     = qeth_ethtool_set_tso,
+};
+
 static int
 qeth_netdev_init(struct net_device *dev)
 {
@@ -5701,6 +6089,8 @@ qeth_netdev_init(struct net_device *dev)
 	dev->addr_len = OSA_ADDR_LEN;
 	dev->mtu = card->info.initial_mtu;
 
+	SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops);
+
 	SET_MODULE_OWNER(dev);
 	return 0;
 }
@@ -6092,6 +6482,9 @@ qeth_query_ipassists_cb(struct qeth_card
 		card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
 #endif
 	}
+	QETH_DBF_TEXT(setup, 2, "suppenbl");
+	QETH_DBF_TEXT_(setup, 2, "%x",cmd->hdr.ipa_supported);
+	QETH_DBF_TEXT_(setup, 2, "%x",cmd->hdr.ipa_enabled);
 	return 0;
 }
 
@@ -6492,26 +6885,33 @@ qeth_start_ipa_checksum(struct qeth_card
 	return rc;
 }
 
-/*
-static inline void
-qeth_print_ipassist_status(struct qeth_card *card)
+static int
+qeth_start_ipa_tso(struct qeth_card *card)
 {
-	char buf[255];
-	int offset = 0;
+	int rc;
+
+	QETH_DBF_TEXT(trace,3,"sttso");
 
-	offset += sprintf(buf, "IPAssist options of %s: ", card->info.if_name);
-	if (qeth_is_enabled(card, IPA_ARP_PROCESSING))
-		offset += sprintf(buf+offset, "ARP ");
-	if (qeth_is_enabled(card, IPA_IP_FRAGMENTATION))
-		offset += sprintf(buf+offset, "IP_FRAG");
-	if (qeth_is_enabled(card, IPA_SOURCE_MAC))
-		offset += sprintf(buf+offset, "SRC_MAC");
-	if (qeth_is_enabled(card, IPA_FULL_VLAN))
-		offset += sprintf(buf+offset, "VLAN");
-	if (qeth_is_enabled(card, IPA_VLAN_PRIO))
-		offset += sprintf(buf+offset, "VLAN_PRIO");
+	if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+		PRINT_WARN("Outbound TSO not supported on %s\n",
+			   QETH_CARD_IFNAME(card));
+		rc = -EOPNOTSUPP;
+	} else {
+		rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
+						  IPA_CMD_ASS_START,0);
+		if (rc)
+			PRINT_WARN("Could not start outbound TSO "
+				   "assist on %s: rc=%i\n",
+				   QETH_CARD_IFNAME(card), rc);
+		else
+			PRINT_INFO("Outbound TSO enabled\n");
+	}
+	if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){
+		card->options.large_send = QETH_LARGE_SEND_NO;
+		card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG);
+	}
+	return rc;
 }
-*/
 
 static int
 qeth_start_ipassists(struct qeth_card *card)
@@ -6525,6 +6925,7 @@ qeth_start_ipassists(struct qeth_card *c
 	qeth_start_ipa_ipv6(card);		/* go on*/
 	qeth_start_ipa_broadcast(card);		/* go on*/
 	qeth_start_ipa_checksum(card);		/* go on*/
+	qeth_start_ipa_tso(card);		/* go on*/
 	return 0;
 }
 
@@ -6636,6 +7037,40 @@ qeth_setrouting_v6(struct qeth_card *car
 	return rc;
 }
 
+int
+qeth_set_large_send(struct qeth_card *card)
+{
+	int rc = 0;
+
+	if (card->dev == NULL)
+		return 0;
+
+	netif_stop_queue(card->dev);
+	switch (card->options.large_send) {
+	case QETH_LARGE_SEND_EDDP:
+		card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+		break;
+	case QETH_LARGE_SEND_TSO:
+		if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){
+			card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+		} else {
+			PRINT_WARN("TSO not supported on %s. "
+				   "large_send set to 'no'.\n",
+				   card->dev->name);
+			card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+			card->options.large_send = QETH_LARGE_SEND_NO;
+			rc = -EOPNOTSUPP;
+		}
+		break;
+	default: /* includes QETH_LARGE_SEND_NO */
+		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+		break;
+	}
+
+	netif_wake_queue(card->dev);
+	return rc;
+}
+
 /*
  * softsetup card: init IPA stuff
  */
@@ -6673,6 +7108,12 @@ qeth_softsetup_card(struct qeth_card *ca
 #endif
 		goto out;
 	}
+	if ((card->options.large_send == QETH_LARGE_SEND_EDDP) ||
+	    (card->options.large_send == QETH_LARGE_SEND_TSO))
+		card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+	else
+		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+
 	if ((rc = qeth_setadapter_parms(card)))
 		QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
 	if ((rc = qeth_start_ipassists(card)))
@@ -6809,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *
 }
 
 static int
-qeth_stop_card(struct qeth_card *card)
+qeth_stop_card(struct qeth_card *card, int recovery_mode)
 {
 	int rc = 0;
 
@@ -6822,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
 	if (card->read.state == CH_STATE_UP &&
 	    card->write.state == CH_STATE_UP &&
 	    (card->state == CARD_STATE_UP)) {
-		rtnl_lock();
-		dev_close(card->dev);
-		rtnl_unlock();
+		if(recovery_mode) {
+			qeth_stop(card->dev);
+		} else {
+			rtnl_lock();
+			dev_close(card->dev);
+			rtnl_unlock();
+		}
 		if (!card->use_hard_stop) {
 			__u8 *mac = &card->dev->dev_addr[0];
 			rc = qeth_layer2_send_delmac(card, mac);
@@ -6996,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *c
 }
 
 static void
-qeth_start_again(struct qeth_card *card)
+qeth_start_again(struct qeth_card *card, int recovery_mode)
 {
 	QETH_DBF_TEXT(setup ,2, "startag");
 
-	rtnl_lock();
-	dev_open(card->dev);
-	rtnl_unlock();
+	if(recovery_mode) {
+		qeth_open(card->dev);
+	} else {
+		rtnl_lock();
+		dev_open(card->dev);
+		rtnl_unlock();
+	}
 	/* this also sets saved unicast addresses */
 	qeth_set_multicast_list(card->dev);
 }
@@ -7059,7 +7508,7 @@ static void qeth_make_parameters_consist
 
 
 static int
-qeth_set_online(struct ccwgroup_device *gdev)
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
 {
 	struct qeth_card *card = gdev->dev.driver_data;
 	int rc = 0;
@@ -7117,17 +7566,14 @@ qeth_set_online(struct ccwgroup_device *
 	}
 /*maybe it was set offline without ifconfig down
  * we can also use this state for recovery purposes*/
-	if (card->options.layer2)
-		qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 0);
-	else
-		qeth_set_allowed_threads(card, 0xffffffff, 0);
+	qeth_set_allowed_threads(card, 0xffffffff, 0);
 	if (recover_flag == CARD_STATE_RECOVER)
-		qeth_start_again(card);
+		qeth_start_again(card, recovery_mode);
 	qeth_notify_processes();
 	return 0;
 out_remove:
 	card->use_hard_stop = 1;
-	qeth_stop_card(card);
+	qeth_stop_card(card, 0);
 	ccw_device_set_offline(CARD_DDEV(card));
 	ccw_device_set_offline(CARD_WDEV(card));
 	ccw_device_set_offline(CARD_RDEV(card));
@@ -7138,6 +7584,12 @@ out_remove:
 	return -ENODEV;
 }
 
+static int
+qeth_set_online(struct ccwgroup_device *gdev)
+{
+	return __qeth_set_online(gdev, 0);
+}
+
 static struct ccw_device_id qeth_ids[] = {
 	{CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
 	{CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -14,7 +14,7 @@
 
 #include <asm/qeth.h>
 
-#define VERSION_QETH_MPC_H "$Revision: 1.38 $"
+#define VERSION_QETH_MPC_H "$Revision: 1.43 $"
 
 extern const char *VERSION_QETH_MPC_C;
 
@@ -182,6 +182,9 @@ enum qeth_ipa_funcs {
 	IPA_FULL_VLAN           = 0x00004000L,
 	IPA_SOURCE_MAC          = 0x00010000L,
 	IPA_OSA_MC_ROUTER       = 0x00020000L,
+	IPA_QUERY_ARP_ASSIST	= 0x00040000L,
+	IPA_INBOUND_TSO         = 0x00080000L,
+	IPA_OUTBOUND_TSO        = 0x00100000L,
 };
 
 /* SETIP/DELIP IPA Command: ***************************************************/
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -236,6 +236,14 @@ qeth_perf_procfile_seq_show(struct seq_f
 		   card->perf_stats.skbs_sent_pack,
 		   card->perf_stats.bufs_sent_pack
 		  );
+	seq_printf(s, "  Skbs sent in SG mode                   : %i\n"
+		      "  Skb fragments sent in SG mode          : %i\n\n",
+		      card->perf_stats.sg_skbs_sent,
+		      card->perf_stats.sg_frags_sent);
+	seq_printf(s, "  large_send tx (in Kbytes)              : %i\n"
+		      "  large_send count                       : %i\n\n",
+		      card->perf_stats.large_send_bytes >> 10,
+		      card->perf_stats.large_send_cnt);
 	seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
 		      "  Watermarks L/H                         : %i/%i\n"
 		      "  Current buffer usage (outbound q's)    : "
@@ -262,7 +270,7 @@ qeth_perf_procfile_seq_show(struct seq_f
 		      "  Outbound time (in us, incl QDIO)       : %i\n"
 		      "  Outbound count                         : %i\n"
 		      "  Outbound do_QDIO time (in us)          : %i\n"
-		      "  Outbound do_QDIO count                 : %i\n",
+		      "  Outbound do_QDIO count                 : %i\n\n",
 		        card->perf_stats.inbound_time,
 			card->perf_stats.inbound_cnt,
 		        card->perf_stats.inbound_do_qdio_time,
@@ -274,7 +282,6 @@ qeth_perf_procfile_seq_show(struct seq_f
 		        card->perf_stats.outbound_do_qdio_time,
 			card->perf_stats.outbound_do_qdio_cnt
 		  );
-
 	return 0;
 }
 
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.49 $)
+ * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.51 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  * This file contains code related to sysfs.
@@ -20,7 +20,7 @@
 #include "qeth_mpc.h"
 #include "qeth_fs.h"
 
-const char *VERSION_QETH_SYS_C = "$Revision: 1.49 $";
+const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $";
 
 /*****************************************************************************/
 /*                                                                           */
@@ -249,6 +249,16 @@ qeth_dev_prioqing_store(struct device *d
 	    (card->state != CARD_STATE_RECOVER))
 		return -EPERM;
 
+	/* check if 1920 devices are supported ,
+	 * if though we have to permit priority queueing
+	 */
+	if (card->qdio.no_out_queues == 1) {
+		PRINT_WARN("Priority queueing disabled due "
+			   "to hardware limitations!\n");
+		card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
+		return -EPERM;
+	}
+
 	tmp = strsep((char **) &buf, "\n");
 	if (!strcmp(tmp, "prio_queueing_prec"))
 		card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
@@ -731,6 +741,174 @@ qeth_dev_layer2_store(struct device *dev
 static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show,
 		   qeth_dev_layer2_store);
 
+static ssize_t
+qeth_dev_large_send_show(struct device *dev, char *buf)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	if (!card)
+		return -EINVAL;
+
+	switch (card->options.large_send) {
+	case QETH_LARGE_SEND_NO:
+		return sprintf(buf, "%s\n", "no");
+	case QETH_LARGE_SEND_EDDP:
+		return sprintf(buf, "%s\n", "EDDP");
+	case QETH_LARGE_SEND_TSO:
+		return sprintf(buf, "%s\n", "TSO");
+	default:
+		return sprintf(buf, "%s\n", "N/A");
+	}
+}
+
+static ssize_t
+qeth_dev_large_send_store(struct device *dev, const char *buf, size_t count)
+{
+	struct qeth_card *card = dev->driver_data;
+	enum qeth_large_send_types type;
+	int rc = 0;
+	char *tmp;
+
+	if (!card)
+		return -EINVAL;
+
+	tmp = strsep((char **) &buf, "\n");
+
+	if (!strcmp(tmp, "no")){
+		type = QETH_LARGE_SEND_NO;
+	} else if (!strcmp(tmp, "EDDP")) {
+		type = QETH_LARGE_SEND_EDDP;
+	} else if (!strcmp(tmp, "TSO")) {
+		type = QETH_LARGE_SEND_TSO;
+	} else {
+		PRINT_WARN("large_send: invalid mode %s!\n", tmp);
+		return -EINVAL;
+	}
+	if (card->options.large_send == type)
+		return count;
+	card->options.large_send = type;
+	if ((rc = qeth_set_large_send(card)))
+		return rc;
+
+	return count;
+}
+
+static DEVICE_ATTR(large_send, 0644, qeth_dev_large_send_show,
+		   qeth_dev_large_send_store);
+
+static ssize_t
+qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value )
+{
+
+	if (!card)
+		return -EINVAL;
+
+	return sprintf(buf, "%i\n", value);
+}
+
+static ssize_t
+qeth_dev_blkt_store(struct qeth_card *card, const char *buf, size_t count,
+			  int *value, int max_value)
+{
+	char *tmp;
+	int i;
+
+	if (!card)
+		return -EINVAL;
+
+	if ((card->state != CARD_STATE_DOWN) &&
+	    (card->state != CARD_STATE_RECOVER))
+		return -EPERM;
+
+	i = simple_strtoul(buf, &tmp, 10);
+	if (i <= max_value) {
+		*value = i;
+	} else {
+		PRINT_WARN("blkt total time: write values between"
+			   " 0 and %d to this file!\n", max_value);
+		return -EINVAL;
+	}
+	return count;
+}
+
+static ssize_t
+qeth_dev_blkt_total_show(struct device *dev, char *buf)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_show(buf, card, card->info.blkt.time_total);
+}
+
+
+static ssize_t
+qeth_dev_blkt_total_store(struct device *dev, const char *buf, size_t count)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_store(card, buf, count,
+				   &card->info.blkt.time_total,1000);
+}
+
+
+
+static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show,
+		   qeth_dev_blkt_total_store);
+
+static ssize_t
+qeth_dev_blkt_inter_show(struct device *dev, char *buf)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_show(buf, card, card->info.blkt.inter_packet);
+}
+
+
+static ssize_t
+qeth_dev_blkt_inter_store(struct device *dev, const char *buf, size_t count)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_store(card, buf, count,
+				   &card->info.blkt.inter_packet,100);
+}
+
+static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show,
+		   qeth_dev_blkt_inter_store);
+
+static ssize_t
+qeth_dev_blkt_inter_jumbo_show(struct device *dev, char *buf)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_show(buf, card,
+				  card->info.blkt.inter_packet_jumbo);
+}
+
+
+static ssize_t
+qeth_dev_blkt_inter_jumbo_store(struct device *dev, const char *buf, size_t count)
+{
+	struct qeth_card *card = dev->driver_data;
+
+	return qeth_dev_blkt_store(card, buf, count,
+				   &card->info.blkt.inter_packet_jumbo,100);
+}
+
+static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show,
+		   qeth_dev_blkt_inter_jumbo_store);
+
+static struct device_attribute * qeth_blkt_device_attrs[] = {
+	&dev_attr_total,
+	&dev_attr_inter,
+	&dev_attr_inter_jumbo,
+	NULL,
+};
+
+static struct attribute_group qeth_device_blkt_group = {
+	.name = "blkt",
+	.attrs = (struct attribute **)qeth_blkt_device_attrs,
+};
+
 static struct device_attribute * qeth_device_attrs[] = {
 	&dev_attr_state,
 	&dev_attr_chpid,
@@ -752,6 +930,7 @@ static struct device_attribute * qeth_de
 	&dev_attr_broadcast_mode,
 	&dev_attr_canonical_macaddr,
 	&dev_attr_layer2,
+	&dev_attr_large_send,
 	NULL,
 };
 
@@ -1506,6 +1685,8 @@ qeth_create_device_attributes(struct dev
 		sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
 		sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
 	}
+	if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group)))
+		return ret;
 
 	return ret;
 }
@@ -1517,6 +1698,7 @@ qeth_remove_device_attributes(struct dev
 	sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
 	sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
 	sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
+	sysfs_remove_group(&dev->kobj, &qeth_device_blkt_group);
 }
 
 /**********************/
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
new file mode 100644
--- /dev/null
+++ b/drivers/s390/net/qeth_tso.h
@@ -0,0 +1,154 @@
+/*
+ * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $)
+ *
+ * Header file for qeth TCP Segmentation Offload support.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ *    Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ *
+ *    $Revision: 1.7 $	 $Date: 2005/05/04 20:19:18 $
+ *
+ */
+#ifndef __QETH_TSO_H__
+#define __QETH_TSO_H__
+
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "qeth.h"
+#include "qeth_mpc.h"
+
+
+static inline struct qeth_hdr_tso *
+qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
+{
+	QETH_DBF_TEXT(trace, 5, "tsoprsk");
+	return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * fill header for a TSO packet
+ */
+static inline void
+qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
+{
+	struct qeth_hdr_tso *hdr;
+	struct tcphdr *tcph;
+	struct iphdr *iph;
+
+	QETH_DBF_TEXT(trace, 5, "tsofhdr");
+
+	hdr  = (struct qeth_hdr_tso *) skb->data;
+	iph  = skb->nh.iph;
+	tcph = skb->h.th;
+	/*fix header to TSO values ...*/
+	hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
+	/*set values which are fix for the first approach ...*/
+	hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
+	hdr->ext.imb_hdr_no  = 1;
+	hdr->ext.hdr_type    = 1;
+	hdr->ext.hdr_version = 1;
+	hdr->ext.hdr_len     = 28;
+	/*insert non-fix values */
+	hdr->ext.mss = skb_shinfo(skb)->tso_size;
+	hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
+	hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
+				       sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * change some header values as requested by hardware
+ */
+static inline void
+qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	struct ipv6hdr *ip6h;
+	struct tcphdr *tcph;
+
+	iph  = skb->nh.iph;
+	ip6h = skb->nh.ipv6h;
+	tcph = skb->h.th;
+
+	tcph->check = 0;
+	if (skb->protocol == ETH_P_IPV6) {
+		ip6h->payload_len = 0;
+		tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+					       0, IPPROTO_TCP, 0);
+		return;
+	}
+	/*OSA want us to set these values ...*/
+	tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+					 0, IPPROTO_TCP, 0);
+	iph->tot_len = 0;
+	iph->check = 0;
+}
+
+static inline int
+qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
+			int ipv, int cast_type)
+{
+	struct qeth_hdr_tso *hdr;
+
+	QETH_DBF_TEXT(trace, 5, "tsoprep");
+
+	hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
+	if (hdr == NULL) {
+		QETH_DBF_TEXT(trace, 4, "tsoperr");
+		return -ENOMEM;
+	}
+	memset(hdr, 0, sizeof(struct qeth_hdr_tso));
+	/*fill first 32 bytes of  qdio header as used
+	 *FIXME: TSO has two struct members
+	 * with different names but same size
+	 * */
+	qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
+	qeth_tso_fill_header(card, skb);
+	qeth_tso_set_tcpip_header(card, skb);
+	return 0;
+}
+
+static inline void
+__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
+			int is_tso, int *next_element_to_fill)
+{
+	struct skb_frag_struct *frag;
+	int fragno;
+	unsigned long addr;
+	int element, cnt, dlen;
+	
+	fragno = skb_shinfo(skb)->nr_frags;
+	element = *next_element_to_fill;
+	dlen = 0;
+	
+	if (is_tso)
+		buffer->element[element].flags =
+			SBAL_FLAGS_MIDDLE_FRAG;
+	else
+		buffer->element[element].flags =
+			SBAL_FLAGS_FIRST_FRAG;
+	if ( (dlen = (skb->len - skb->data_len)) ) {
+		buffer->element[element].addr = skb->data;
+		buffer->element[element].length = dlen;
+		element++;
+	}
+	for (cnt = 0; cnt < fragno; cnt++) {
+		frag = &skb_shinfo(skb)->frags[cnt];
+		addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
+			frag->page_offset;
+		buffer->element[element].addr = (char *)addr;
+		buffer->element[element].length = frag->size;
+		if (cnt < (fragno - 1))
+			buffer->element[element].flags =
+				SBAL_FLAGS_MIDDLE_FRAG;
+		else
+			buffer->element[element].flags =
+				SBAL_FLAGS_LAST_FRAG;
+		element++;
+	}
+	*next_element_to_fill = element;
+}
+#endif /* __QETH_TSO_H__ */
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -32,7 +32,7 @@ struct smsg_callback {
 	struct list_head list;
 	char *prefix;
 	int len;
-	void (*callback)(char *str);
+	void (*callback)(char *from, char *str);
 };
 
 MODULE_AUTHOR
@@ -55,8 +55,9 @@ smsg_message_pending(iucv_MessagePending
 {
 	struct smsg_callback *cb;
 	unsigned char *msg;
+	unsigned char sender[9];
 	unsigned short len;
-	int rc;
+	int rc, i;
 
 	len = eib->ln1msg2.ipbfln1f;
 	msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
@@ -69,10 +70,18 @@ smsg_message_pending(iucv_MessagePending
 	if (rc == 0) {
 		msg[len] = 0;
 		EBCASC(msg, len);
+		memcpy(sender, msg, 8);
+		sender[8] = 0;
+		/* Remove trailing whitespace from the sender name. */
+		for (i = 7; i >= 0; i--) {
+			if (sender[i] != ' ' && sender[i] != '\t')
+				break;
+			sender[i] = 0;
+		}
 		spin_lock(&smsg_list_lock);
 		list_for_each_entry(cb, &smsg_list, list)
 			if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
-				cb->callback(msg + 8);
+				cb->callback(sender, msg + 8);
 				break;
 			}
 		spin_unlock(&smsg_list_lock);
@@ -91,7 +100,7 @@ static struct device_driver smsg_driver 
 };
 
 int
-smsg_register_callback(char *prefix, void (*callback)(char *str))
+smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
 {
 	struct smsg_callback *cb;
 
@@ -108,7 +117,7 @@ smsg_register_callback(char *prefix, voi
 }
 
 void
-smsg_unregister_callback(char *prefix, void (*callback)(char *str))
+smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
 {
 	struct smsg_callback *cb, *tmp;
 
diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h
--- a/drivers/s390/net/smsgiucv.h
+++ b/drivers/s390/net/smsgiucv.h
@@ -5,6 +5,6 @@
  * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
-int  smsg_register_callback(char *, void (*)(char *));
-void smsg_unregister_callback(char *, void (*)(char *));
+int  smsg_register_callback(char *, void (*)(char *, char *));
+void smsg_unregister_callback(char *, void (*)(char *, char *));
 
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -52,19 +52,18 @@ static inline int zfcp_sg_list_copy_from
 static inline int zfcp_sg_list_copy_to_user(void __user *,
 					    struct zfcp_sg_list *, size_t);
 
-static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *,
-	unsigned int, unsigned long);
+static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
 
 #define ZFCP_CFDC_IOC_MAGIC                     0xDD
 #define ZFCP_CFDC_IOC \
 	_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)
 
-#ifdef CONFIG_COMPAT
-static struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};
-#endif
 
 static struct file_operations zfcp_cfdc_fops = {
-	.ioctl = zfcp_cfdc_dev_ioctl
+	.unlocked_ioctl = zfcp_cfdc_dev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = zfcp_cfdc_dev_ioctl
+#endif
 };
 
 static struct miscdevice zfcp_cfdc_misc = {
@@ -89,10 +88,10 @@ MODULE_DESCRIPTION
     ("FCP (SCSI over Fibre Channel) HBA driver for IBM eServer zSeries");
 MODULE_LICENSE("GPL");
 
-module_param(device, charp, 0);
+module_param(device, charp, 0400);
 MODULE_PARM_DESC(device, "specify initial device");
 
-module_param(loglevel, uint, 0);
+module_param(loglevel, uint, 0400);
 MODULE_PARM_DESC(loglevel,
 		 "log levels, 8 nibbles: "
 		 "FC ERP QDIO CIO Config FSF SCSI Other, "
@@ -308,23 +307,16 @@ zfcp_module_init(void)
 	if (!zfcp_transport_template)
 		return -ENODEV;
 
-	retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,
-					     zfcp_ioctl_trans.handler);
-	if (retval != 0) {
-		ZFCP_LOG_INFO("registration of ioctl32 conversion failed\n");
-		goto out;
-	}
-
 	retval = misc_register(&zfcp_cfdc_misc);
 	if (retval != 0) {
 		ZFCP_LOG_INFO("registration of misc device "
 			      "zfcp_cfdc failed\n");
-		goto out_misc_register;
-	} else {
-		ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n",
-			       ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);
+		goto out;
 	}
 
+	ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n",
+		       ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);
+
 	/* Initialise proc semaphores */
 	sema_init(&zfcp_data.config_sema, 1);
 
@@ -348,8 +340,6 @@ zfcp_module_init(void)
 
  out_ccw_register:
 	misc_deregister(&zfcp_cfdc_misc);
- out_misc_register:
-	unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
  out:
 	return retval;
 }
@@ -370,9 +360,9 @@ zfcp_module_init(void)
  *              -EPERM      - Cannot create or queue FSF request or create SBALs
  *              -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS)
  */
-static int
-zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
-                    unsigned int command, unsigned long buffer)
+static long
+zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
+		    unsigned long buffer)
 {
 	struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user;
 	struct zfcp_adapter *adapter = NULL;
@@ -583,7 +573,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *
 		retval = -ENOMEM;
 		goto out;
 	}
-	memset(sg_list->sg, sg_list->count * sizeof(struct scatterlist), 0);
+	memset(sg_list->sg, 0, sg_list->count * sizeof(struct scatterlist));
 
 	for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
 		sg->length = min(size, PAGE_SIZE);
@@ -928,7 +918,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit
 }
 
 static void *
-zfcp_mempool_alloc(int gfp_mask, void *size)
+zfcp_mempool_alloc(unsigned int __nocast gfp_mask, void *size)
 {
 	return kmalloc((size_t) size, gfp_mask);
 }
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -61,7 +61,6 @@
 #include <linux/mempool.h>
 #include <linux/syscalls.h>
 #include <linux/ioctl.h>
-#include <linux/ioctl32.h>
 
 /************************ DEBUG FLAGS *****************************************/
 
@@ -70,7 +69,7 @@
 /********************* GENERAL DEFINES *********************************/
 
 /* zfcp version number, it consists of major, minor, and patch-level number */
-#define ZFCP_VERSION		"4.2.0"
+#define ZFCP_VERSION		"4.3.0"
 
 /**
  * zfcp_sg_to_address - determine kernel address from struct scatterlist
@@ -851,6 +850,9 @@ struct zfcp_adapter {
 	wwn_t			wwnn;	           /* WWNN */
 	wwn_t			wwpn;	           /* WWPN */
 	fc_id_t			s_id;	           /* N_Port ID */
+	wwn_t			peer_wwnn;	   /* P2P peer WWNN */
+	wwn_t			peer_wwpn;	   /* P2P peer WWPN */
+	fc_id_t			peer_d_id;	   /* P2P peer D_ID */
 	struct ccw_device       *ccw_device;	   /* S/390 ccw device */
 	u8			fc_service_class;
 	u32			fc_topology;	   /* FC topology */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -2568,6 +2568,23 @@ zfcp_erp_port_strategy_open_common(struc
 	case ZFCP_ERP_STEP_UNINITIALIZED:
 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
 	case ZFCP_ERP_STEP_PORT_CLOSING:
+		if (adapter->fc_topology == FSF_TOPO_P2P) {
+			if (port->wwpn != adapter->peer_wwpn) {
+				ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx "
+						"on adapter %s.\nPeer WWPN "
+						"0x%016Lx does not match\n",
+						port->wwpn,
+						zfcp_get_busid_by_adapter(adapter),
+						adapter->peer_wwpn);
+				zfcp_erp_port_failed(port);
+				retval = ZFCP_ERP_FAILED;
+				break;
+			}
+			port->d_id = adapter->peer_d_id;
+			atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
+			retval = zfcp_erp_port_strategy_open_port(erp_action);
+			break;
+		}
 		if (!(adapter->nameserver_port)) {
 			retval = zfcp_nameserver_enqueue(adapter);
 			if (retval != 0) {
@@ -3516,8 +3533,9 @@ zfcp_erp_adapter_access_changed(struct z
 	debug_text_event(adapter->erp_dbf, 3, "a_access_unblock");
 	debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
 
-	zfcp_erp_port_access_changed(adapter->nameserver_port);
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	if (adapter->nameserver_port)
+		zfcp_erp_port_access_changed(adapter->nameserver_port);
 	list_for_each_entry(port, &adapter->port_list_head, list)
 		if (port != adapter->nameserver_port)
 			zfcp_erp_port_access_changed(port);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -2107,6 +2107,9 @@ zfcp_fsf_exchange_config_evaluate(struct
 		       bottom->low_qtcb_version, bottom->high_qtcb_version);
 	adapter->fsf_lic_version = bottom->lic_version;
 	adapter->supported_features = bottom->supported_features;
+	adapter->peer_wwpn = 0;
+	adapter->peer_wwnn = 0;
+	adapter->peer_d_id = 0;
 
 	if (xchg_ok) {
 		adapter->wwnn = bottom->nport_serv_param.wwnn;
@@ -2124,13 +2127,19 @@ zfcp_fsf_exchange_config_evaluate(struct
 		adapter->hydra_version = 0;
 	}
 
+	if (adapter->fc_topology == FSF_TOPO_P2P) {
+		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
+		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
+		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
+	}
+
 	if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
 		adapter->hardware_version = bottom->hardware_version;
 		memcpy(adapter->serial_number, bottom->serial_number, 17);
 		EBCASC(adapter->serial_number, sizeof(adapter->serial_number));
 	}
 
-	ZFCP_LOG_INFO("The adapter %s reported the following characteristics:\n"
+	ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
 		      "WWNN 0x%016Lx, "
 		      "WWPN 0x%016Lx, "
 		      "S_ID 0x%08x,\n"
@@ -2194,14 +2203,18 @@ zfcp_fsf_exchange_config_data_handler(st
 		switch (adapter->fc_topology) {
 		case FSF_TOPO_P2P:
 			ZFCP_LOG_FLAGS(1, "FSF_TOPO_P2P\n");
-			ZFCP_LOG_NORMAL("error: Point-to-point fibrechannel "
-					"configuration detected at adapter %s "
-					"unsupported, shutting down adapter\n",
-					zfcp_get_busid_by_adapter(adapter));
+			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
+					"configuration detected at adapter %s\n"
+					"Peer WWNN 0x%016llx, "
+					"peer WWPN 0x%016llx, "
+					"peer d_id 0x%06x\n",
+					zfcp_get_busid_by_adapter(adapter),
+					adapter->peer_wwnn,
+					adapter->peer_wwpn,
+					adapter->peer_d_id);
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "top-p-to-p");
-			zfcp_erp_adapter_shutdown(adapter, 0);
-			return -EIO;
+			break;
 		case FSF_TOPO_AL:
 			ZFCP_LOG_FLAGS(1, "FSF_TOPO_AL\n");
 			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
@@ -2226,6 +2239,7 @@ zfcp_fsf_exchange_config_data_handler(st
 					"of a type known to the zfcp "
 					"driver, shutting down adapter\n",
 					zfcp_get_busid_by_adapter(adapter));
+			adapter->fc_topology = FSF_TOPO_ERROR;
 			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
 					     "unknown-topo");
 			zfcp_erp_adapter_shutdown(adapter, 0);
@@ -4281,6 +4295,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
 			zfcp_cmd_dbf_event_fsf("undeffcp", fsf_req, NULL, 0);
 			set_host_byte(&scpnt->result, DID_ERROR);
+			goto skip_fsfstatus;
 		}
 	}
 
@@ -4334,7 +4349,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 
 		scpnt->resid = fcp_rsp_iu->fcp_resid;
 		if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
-			scpnt->result |= DID_ERROR << 16;
+			set_host_byte(&scpnt->result, DID_ERROR);
 	}
 
  skip_fsfstatus:
@@ -4607,6 +4622,13 @@ zfcp_fsf_control_file_handler(struct zfc
 		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
 			switch (header->fsf_status_qual.word[0]) {
 
+			case FSF_SQ_CFDC_HARDENED_ON_SE:
+				ZFCP_LOG_NORMAL(
+					"CFDC on the adapter %s has being "
+					"hardened on primary and secondary SE\n",
+					zfcp_get_busid_by_adapter(adapter));
+				break;
+
 			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
 				ZFCP_LOG_NORMAL(
 					"CFDC of the adapter %s could not "
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -129,6 +129,7 @@
 #define FSF_SQ_NO_RETRY_POSSIBLE		0x07
 
 /* FSF status qualifier for CFDC commands */
+#define FSF_SQ_CFDC_HARDENED_ON_SE		0x00000000
 #define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE	0x00000001
 #define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2	0x00000002
 /* CFDC subtable codes */
@@ -357,7 +358,6 @@ struct fsf_nport_serv_param {
 	u8  class3_serv_param[16];
 	u8  class4_serv_param[16];
 	u8  vendor_version_level[16];
-	u8  res1[16];
 } __attribute__ ((packed));
 
 struct fsf_plogi {
@@ -415,11 +415,13 @@ struct fsf_qtcb_bottom_config {
 	u8 res2[12];
 	u32 s_id;
 	struct fsf_nport_serv_param nport_serv_param;
+	u8 reserved_nport_serv_param[16];
 	u8 res3[8];
 	u32 adapter_ports;
 	u32 hardware_version;
 	u8 serial_number[32];
-	u8 res4[272];
+	struct fsf_nport_serv_param plogi_payload;
+	u8 res4[160];
 } __attribute__ ((packed));
 
 struct fsf_qtcb_bottom_port {
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c
--- a/drivers/s390/scsi/zfcp_sysfs_adapter.c
+++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c
@@ -65,6 +65,9 @@ ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x
 ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn);
 ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn);
 ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id);
+ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn);
+ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn);
+ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
 ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
 ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed);
@@ -255,6 +258,9 @@ static struct attribute *zfcp_adapter_at
 	&dev_attr_wwnn.attr,
 	&dev_attr_wwpn.attr,
 	&dev_attr_s_id.attr,
+	&dev_attr_peer_wwnn.attr,
+	&dev_attr_peer_wwpn.attr,
+	&dev_attr_peer_d_id.attr,
 	&dev_attr_card_version.attr,
 	&dev_attr_lic_version.attr,
 	&dev_attr_fc_link_speed.attr,
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -81,10 +81,6 @@ unsigned char irqs[4] = {
 int irqhit=0;
 #endif
 
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
 static struct tty_driver *aurora_driver;
 static struct Aurora_board aurora_board[AURORA_NBOARD] = {
 	{0,},
@@ -594,7 +590,7 @@ static void aurora_transmit(struct Auror
 					    &bp->r[chip]->r[CD180_TDR]);
 				port->COR2 &= ~COR2_ETC;
 			}
-			count = MIN(port->break_length, 0xff);
+			count = min(port->break_length, 0xff);
 			sbus_writeb(CD180_C_ESC,
 				    &bp->r[chip]->r[CD180_TDR]);
 			sbus_writeb(CD180_C_DELAY,
@@ -1575,7 +1571,7 @@ static int aurora_write(struct tty_struc
 	save_flags(flags);
 	while (1) {
 		cli();
-		c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+		c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
 				   SERIAL_XMIT_SIZE - port->xmit_head));
 		if (c <= 0) {
 			restore_flags(flags);
@@ -1887,14 +1883,12 @@ extern int aurora_get_serial_info(struct
 {
 	struct serial_struct tmp;
 	struct Aurora_board *bp = port_Board(port);
-	int error;
 	
 #ifdef AURORA_DEBUG
 	printk("aurora_get_serial_info: start\n");
 #endif
-	error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
-	if (error)
-		return error;
+	if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
+		return -EFAULT;
 	
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = PORT_CIRRUS;
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -75,7 +75,7 @@ flash_mmap(struct file *file, struct vm_
 	pgprot_val(vma->vm_page_prot) |= _PAGE_E;
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 
-	if (remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
+	if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
 		return -EAGAIN;
 		
 	return 0;
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -427,16 +427,14 @@ static int openprom_bsd_ioctl(struct ino
 			len = op.op_buflen = 0;
 		}
 
-		error = verify_area(VERIFY_WRITE, argp, sizeof(op));
-		if (error) {
+		if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) {
 			kfree(str);
-			return error;
+			return -EFAULT;
 		}
 
-		error = verify_area(VERIFY_WRITE, op.op_buf, len);
-		if (error) {
+		if (!access_ok(VERIFY_WRITE, op.op_buf, len)) {
 			kfree(str);
-			return error;
+			return -EFAULT;
 		}
 
 		error = __copy_to_user(argp, &op, sizeof(op));
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -28,10 +28,46 @@
 
 static int rtc_busy = 0;
 
+/* This is the structure layout used by drivers/char/rtc.c, we
+ * support that driver's ioctls so that things are less messy in
+ * userspace.
+ */
+struct rtc_time_generic {
+	int tm_sec;
+	int tm_min;
+	int tm_hour;
+	int tm_mday;
+	int tm_mon;
+	int tm_year;
+	int tm_wday;
+	int tm_yday;
+	int tm_isdst;
+};
+#define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
+#define RTC_AIE_OFF	_IO('p', 0x02)	/* ... off			*/
+#define RTC_UIE_ON	_IO('p', 0x03)	/* Update int. enable on	*/
+#define RTC_UIE_OFF	_IO('p', 0x04)	/* ... off			*/
+#define RTC_PIE_ON	_IO('p', 0x05)	/* Periodic int. enable on	*/
+#define RTC_PIE_OFF	_IO('p', 0x06)	/* ... off			*/
+#define RTC_WIE_ON	_IO('p', 0x0f)  /* Watchdog int. enable on	*/
+#define RTC_WIE_OFF	_IO('p', 0x10)  /* ... off			*/
+#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time   */
+#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time    */
+#define RTC_ALM_SET	_IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
+#define RTC_ALM_READ	_IOR('p', 0x08, struct rtc_time) /* Read alarm time */
+#define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
+#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
+#define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
+#define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
+#define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
+#define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
+
 /* Retrieve the current date and time from the real time clock. */
 static void get_rtc_time(struct rtc_time *t)
 {
-	void * __iomem regs = mstk48t02_regs;
+	void __iomem *regs = mstk48t02_regs;
 	u8 tmp;
 
 	spin_lock_irq(&mostek_lock);
@@ -58,7 +94,7 @@ static void get_rtc_time(struct rtc_time
 /* Set the current date and time inthe real time clock. */
 void set_rtc_time(struct rtc_time *t)
 {
-	void * __iomem regs = mstk48t02_regs;
+	void __iomem *regs = mstk48t02_regs;
 	u8 tmp;
 
 	spin_lock_irq(&mostek_lock);
@@ -82,29 +118,87 @@ void set_rtc_time(struct rtc_time *t)
 	spin_unlock_irq(&mostek_lock);
 }
 
+static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm)
+{
+	struct rtc_time_generic __user *utm = argp;
+
+	if (__put_user(tm->sec, &utm->tm_sec) ||
+	    __put_user(tm->min, &utm->tm_min) ||
+	    __put_user(tm->hour, &utm->tm_hour) ||
+	    __put_user(tm->dom, &utm->tm_mday) ||
+	    __put_user(tm->month, &utm->tm_mon) ||
+	    __put_user(tm->year, &utm->tm_year) ||
+	    __put_user(tm->dow, &utm->tm_wday) ||
+	    __put_user(0, &utm->tm_yday) ||
+	    __put_user(0, &utm->tm_isdst))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp)
+{
+	struct rtc_time_generic __user *utm = argp;
+
+	if (__get_user(tm->sec, &utm->tm_sec) ||
+	    __get_user(tm->min, &utm->tm_min) ||
+	    __get_user(tm->hour, &utm->tm_hour) ||
+	    __get_user(tm->dom, &utm->tm_mday) ||
+	    __get_user(tm->month, &utm->tm_mon) ||
+	    __get_user(tm->year, &utm->tm_year) ||
+	    __get_user(tm->dow, &utm->tm_wday))
+		return -EFAULT;
+
+	return 0;
+}
+
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
 	struct rtc_time rtc_tm;
 	void __user *argp = (void __user *)arg;
 
-	switch (cmd)
-	{
+	switch (cmd) {
+	/* No interrupt support, return an error
+	 * compatible with drivers/char/rtc.c
+	 */
+	case RTC_AIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_PIE_OFF:
+	case RTC_PIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_UIE_ON:
+	case RTC_IRQP_READ:
+	case RTC_IRQP_SET:
+	case RTC_EPOCH_SET:
+	case RTC_EPOCH_READ:
+		return -EINVAL;
+
 	case RTCGET:
+	case RTC_RD_TIME:
 		memset(&rtc_tm, 0, sizeof(struct rtc_time));
 		get_rtc_time(&rtc_tm);
 
-		if (copy_to_user(argp, &rtc_tm, sizeof(struct rtc_time)))
+		if (cmd == RTCGET) {
+			if (copy_to_user(argp, &rtc_tm,
+					 sizeof(struct rtc_time)))
+				return -EFAULT;
+		} else if (put_rtc_time_generic(argp, &rtc_tm))
 			return -EFAULT;
 
 		return 0;
 
 
 	case RTCSET:
+	case RTC_SET_TIME:
 		if (!capable(CAP_SYS_TIME))
 			return -EPERM;
 
-		if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time)))
+		if (cmd == RTCSET) {
+			if (copy_from_user(&rtc_tm, argp,
+					   sizeof(struct rtc_time)))
+				return -EFAULT;
+		} else if (get_rtc_time_generic(&rtc_tm, argp))
 			return -EFAULT;
 
 		set_rtc_time(&rtc_tm);
@@ -156,7 +250,7 @@ static int __init rtc_sun_init(void)
 	/* It is possible we are being driven by some other RTC chip
 	 * and thus another RTC driver is handling things.
 	 */
-	if (mstk48t02_regs == 0)
+	if (!mstk48t02_regs)
 		return -ENODEV;
 
 	error = misc_register(&rtc_dev);
@@ -164,6 +258,7 @@ static int __init rtc_sun_init(void)
 		printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
 		return error;
 	}
+	printk("rtc_sun_init: Registered Mostek RTC driver.\n");
 
 	return 0;
 }
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -626,8 +626,10 @@ static int vfc_mmap(struct file *file, s
 	vma->vm_flags |=
 		(VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
 	map_offset = (unsigned int) (long)dev->phys_regs;
-	ret = io_remap_page_range(vma, vma->vm_start, map_offset, map_size, 
-				  vma->vm_page_prot, dev->which_io);
+	ret = io_remap_pfn_range(vma, vma->vm_start,
+				  MK_IOSPACE_PFN(dev->which_io,
+					map_offset >> PAGE_SHIFT),
+				  map_size, vma->vm_page_prot);
 
 	if(ret)
 		return -EAGAIN;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -3,7 +3,7 @@
 
    Written By: Adam Radford <linuxraid@amcc.com>
 
-   Copyright (C) 2004 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2005 Applied Micro Circuits 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
@@ -51,6 +51,14 @@
    -------
    2.26.02.000 - Driver cleanup for kernel submission.
    2.26.02.001 - Replace schedule_timeout() calls with msleep().
+   2.26.02.002 - Add support for PAE mode.
+                 Add lun support.
+                 Fix twa_remove() to free irq handler/unregister_chrdev()
+                 before shutting down card.
+                 Change to new 'change_queue_depth' api.
+                 Fix 'handled=1' ISR usage, remove bogus IRQ check.
+                 Remove un-needed eh_abort handler.
+                 Add support for embedded firmware error strings.
 */
 
 #include <linux/module.h>
@@ -73,7 +81,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-static const char *twa_driver_version="2.26.02.001";
+#define TW_DRIVER_VERSION "2.26.02.002"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -83,6 +91,7 @@ extern struct timezone sys_tz;
 MODULE_AUTHOR ("AMCC");
 MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
 
 /* Function prototypes */
 static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
@@ -108,9 +117,9 @@ static void twa_load_sgl(TW_Command_Full
 static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
 static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
 static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
 static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
 static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
 static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
 static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
@@ -126,7 +135,7 @@ static ssize_t twa_show_stats(struct cla
 	ssize_t len;
 
 	spin_lock_irqsave(tw_dev->host->host_lock, flags);
-	len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n"
+	len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
 		       "Current commands posted:   %4d\n"
 		       "Max commands posted:       %4d\n"
 		       "Current pending commands:  %4d\n"
@@ -136,9 +145,8 @@ static ssize_t twa_show_stats(struct cla
 		       "Last sector count:         %4d\n"
 		       "Max sector count:          %4d\n"
 		       "SCSI Host Resets:          %4d\n"
-		       "SCSI Aborts/Timeouts:      %4d\n"
 		       "AEN's:                     %4d\n", 
-		       twa_driver_version,
+		       TW_DRIVER_VERSION,
 		       tw_dev->posted_request_count,
 		       tw_dev->max_posted_request_count,
 		       tw_dev->pending_request_count,
@@ -148,40 +156,19 @@ static ssize_t twa_show_stats(struct cla
 		       tw_dev->sector_count,
 		       tw_dev->max_sector_count,
 		       tw_dev->num_resets,
-		       tw_dev->num_aborts,
 		       tw_dev->aen_count);
 	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 	return len;
 } /* End twa_show_stats() */
 
 /* This function will set a devices queue depth */
-static ssize_t twa_store_queue_depth(struct device *dev, const char *buf, size_t count)
+static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth)
 {
-	int queue_depth;
-	struct scsi_device *sdev = to_scsi_device(dev);
-
-	queue_depth = simple_strtoul(buf, NULL, 0);
 	if (queue_depth > TW_Q_LENGTH-2)
-		return -EINVAL;
+		queue_depth = TW_Q_LENGTH-2;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
-
-	return count;
-} /* End twa_store_queue_depth() */
-
-/* Create sysfs 'queue_depth' entry */
-static struct device_attribute twa_queue_depth_attr = {
-	.attr = {
-		.name =		"queue_depth",
-		.mode =		S_IRUSR | S_IWUSR,
-	},
-	.store = twa_store_queue_depth
-};
-
-/* Device attributes initializer */
-static struct device_attribute *twa_dev_attrs[] = {
-	&twa_queue_depth_attr,
-	NULL,
-};
+	return queue_depth;
+} /* End twa_change_queue_depth() */
 
 /* Create sysfs 'stats' entry */
 static struct class_device_attribute twa_host_stats_attr = {
@@ -265,7 +252,7 @@ static int twa_aen_drain_queue(TW_Device
 {
 	int request_id = 0;
 	char cdb[TW_MAX_CDB_LEN];
-	TW_SG_Apache sglist[1];
+	TW_SG_Entry sglist[1];
 	int finished = 0, count = 0;
 	TW_Command_Full *full_command_packet;
 	TW_Command_Apache_Header *header;
@@ -286,7 +273,7 @@ static int twa_aen_drain_queue(TW_Device
 	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
 
 	/* Initialize sglist */
-	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	memset(&sglist, 0, sizeof(TW_SG_Entry));
 	sglist[0].length = TW_SECTOR_SIZE;
 	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
 
@@ -359,6 +346,7 @@ static void twa_aen_queue_event(TW_Devic
 	TW_Event *event;
 	unsigned short aen;
 	char host[16];
+	char *error_str;
 
 	tw_dev->aen_count++;
 
@@ -385,6 +373,9 @@ static void twa_aen_queue_event(TW_Devic
 	event->sequence_id = tw_dev->error_sequence_id;
 	tw_dev->error_sequence_id++;
 
+	/* Check for embedded error string */
+	error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
+
 	header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
 	event->parameter_len = strlen(header->err_specific_desc);
 	memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
@@ -393,7 +384,7 @@ static void twa_aen_queue_event(TW_Devic
 		       host,
 		       twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
 		       TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
-		       twa_string_lookup(twa_aen_table, aen),
+		       error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
 		       header->err_specific_desc);
 	else
 		tw_dev->aen_count--;
@@ -407,7 +398,7 @@ static void twa_aen_queue_event(TW_Devic
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
 {
 	char cdb[TW_MAX_CDB_LEN];
-	TW_SG_Apache sglist[1];
+	TW_SG_Entry sglist[1];
 	TW_Command_Full *full_command_packet;
 	int retval = 1;
 
@@ -420,7 +411,7 @@ static int twa_aen_read_queue(TW_Device_
 	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
 
 	/* Initialize sglist */
-	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	memset(&sglist, 0, sizeof(TW_SG_Entry));
 	sglist[0].length = TW_SECTOR_SIZE;
 	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
 
@@ -558,18 +549,18 @@ static int twa_check_srl(TW_Device_Exten
 	u32 init_connect_result = 0;
 
 	if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
-			       TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL,
-			       TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH,
-			       TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl,
+			       TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
+			       TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
+			       TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
 			       &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
 			       &fw_on_ctlr_build, &init_connect_result)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
 		goto out;
 	}
 
-	tw_dev->working_srl = TW_CURRENT_FW_SRL;
-	tw_dev->working_branch = TW_CURRENT_FW_BRANCH;
-	tw_dev->working_build = TW_CURRENT_FW_BUILD;
+	tw_dev->working_srl = fw_on_ctlr_srl;
+	tw_dev->working_branch = fw_on_ctlr_branch;
+	tw_dev->working_build = fw_on_ctlr_build;
 
 	/* Try base mode compatibility */
 	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
@@ -584,7 +575,7 @@ static int twa_check_srl(TW_Device_Exten
 			goto out;
 		}
 		if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
-			if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {
+			if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
 				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
 			} else {
 				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
@@ -641,7 +632,7 @@ static int twa_chrdev_ioctl(struct inode
 	data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
 
 	/* Now allocate ioctl buf memory */
-	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);
+	cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
 	if (!cpu_addr) {
 		retval = TW_IOCTL_ERROR_OS_ENOMEM;
 		goto out2;
@@ -679,26 +670,28 @@ static int twa_chrdev_ioctl(struct inode
 		timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
 
 		/* Now wait for command to complete */
-		timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+		timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+		/* See if we reset while waiting for the ioctl to complete */
+		if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+			clear_bit(TW_IN_RESET, &tw_dev->flags);
+			retval = TW_IOCTL_ERROR_OS_ERESTARTSYS;
+			goto out3;
+		}
 
-		/* Check if we timed out, got a signal, or didn't get
-                   an interrupt */
-		if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+		/* We timed out, and didn't get an interrupt */
+		if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
 			/* Now we need to reset the board */
-			if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {
-				retval = timeout;
-			} else {
-				printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
-				       tw_dev->host->host_no, TW_DRIVER, 0xc,
-				       cmd);
-				retval = TW_IOCTL_ERROR_OS_EIO;
-			}
+			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+			       tw_dev->host->host_no, TW_DRIVER, 0xc,
+			       cmd);
+			retval = TW_IOCTL_ERROR_OS_EIO;
 			spin_lock_irqsave(tw_dev->host->host_lock, flags);
 			tw_dev->state[request_id] = TW_S_COMPLETED;
 			twa_free_request_id(tw_dev, request_id);
 			tw_dev->posted_request_count--;
-			twa_reset_device_extension(tw_dev);
 			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			twa_reset_device_extension(tw_dev, 1);
 			goto out3;
 		}
 
@@ -716,10 +709,16 @@ static int twa_chrdev_ioctl(struct inode
 		tw_ioctl->driver_command.status = 0;
 		/* Copy compatiblity struct into ioctl data buffer */
 		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
-		strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));
+		strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
 		tw_compat_info->working_srl = tw_dev->working_srl;
 		tw_compat_info->working_branch = tw_dev->working_branch;
 		tw_compat_info->working_build = tw_dev->working_build;
+		tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL;
+		tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+		tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD;
+		tw_compat_info->driver_srl_low = TW_BASE_FW_SRL;
+		tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH;
+		tw_compat_info->driver_build_low = TW_BASE_FW_BUILD;
 		break;
 	case TW_IOCTL_GET_LAST_EVENT:
 		if (tw_dev->event_queue_wrapped) {
@@ -849,7 +848,7 @@ static int twa_chrdev_ioctl(struct inode
 		retval = 0;
 out3:
 	/* Now free ioctl buf memory */
-	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
 out2:
 	up(&tw_dev->ioctl_sem);
 out:
@@ -936,8 +935,13 @@ static int twa_fill_sense(TW_Device_Exte
 	TW_Command_Full *full_command_packet;
 	unsigned short error;
 	int retval = 1;
+	char *error_str;
 
 	full_command_packet = tw_dev->command_packet_virt[request_id];
+
+	/* Check for embedded error string */
+	error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
+
 	/* Don't print error for Logical unit not supported during rollcall */
 	error = full_command_packet->header.status_block.error;
 	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
@@ -946,15 +950,17 @@ static int twa_fill_sense(TW_Device_Exte
 			       tw_dev->host->host_no,
 			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
 			       full_command_packet->header.status_block.error,
+			       error_str[0] == '\0' ?
 			       twa_string_lookup(twa_error_table,
-						 full_command_packet->header.status_block.error),
+						 full_command_packet->header.status_block.error) : error_str,
 			       full_command_packet->header.err_specific_desc);
 		else
 			printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
 			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
 			       full_command_packet->header.status_block.error,
+			       error_str[0] == '\0' ?
 			       twa_string_lookup(twa_error_table,
-						 full_command_packet->header.status_block.error),
+						 full_command_packet->header.status_block.error) : error_str,
 			       full_command_packet->header.err_specific_desc);
 	}
 
@@ -1075,10 +1081,9 @@ static int twa_initconnection(TW_Device_
 	tw_initconnect->request_id = request_id;
 	tw_initconnect->message_credits = message_credits;
 	tw_initconnect->features = set_features;
-#if BITS_PER_LONG > 32
-	/* Turn on 64-bit sgl support */
-	tw_initconnect->features |= 1;
-#endif
+
+	/* Turn on 64-bit sgl support if we need to */
+	tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
 
 	if (set_features & TW_EXTENDED_INIT_CONNECT) {
 		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
@@ -1173,139 +1178,142 @@ static irqreturn_t twa_interrupt(int irq
 	/* Get the per adapter lock */
 	spin_lock(tw_dev->host->host_lock);
 
-	/* See if the interrupt matches this instance */
-	if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
-
-		handled = 1;
-
-		/* Read the registers */
-		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	/* Read the registers */
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
 
-		/* Check if this is our interrupt, otherwise bail */
-		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+	/* Check if this is our interrupt, otherwise bail */
+	if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+		goto twa_interrupt_bail;
+
+	handled = 1;
+
+	/* Check controller for errors */
+	if (twa_check_bits(status_reg_value)) {
+		if (twa_decode_bits(tw_dev, status_reg_value)) {
+			TW_CLEAR_ALL_INTERRUPTS(tw_dev);
 			goto twa_interrupt_bail;
+		}
+	}
+
+	/* Handle host interrupt */
+	if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+		TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+	/* Handle attention interrupt */
+	if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+		TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+		if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+			twa_get_request_id(tw_dev, &request_id);
+
+			error = twa_aen_read_queue(tw_dev, request_id);
+			if (error) {
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				twa_free_request_id(tw_dev, request_id);
+				clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+			}
+		}
+	}
 
-		/* Check controller for errors */
-		if (twa_check_bits(status_reg_value)) {
-			if (twa_decode_bits(tw_dev, status_reg_value)) {
+	/* Handle command interrupt */
+	if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+		TW_MASK_COMMAND_INTERRUPT(tw_dev);
+		/* Drain as many pending commands as we can */
+		while (tw_dev->pending_request_count > 0) {
+			request_id = tw_dev->pending_queue[tw_dev->pending_head];
+			if (tw_dev->state[request_id] != TW_S_PENDING) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
 				TW_CLEAR_ALL_INTERRUPTS(tw_dev);
 				goto twa_interrupt_bail;
 			}
+			if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+				tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+				tw_dev->pending_request_count--;
+			} else {
+				/* If we get here, we will continue re-posting on the next command interrupt */
+				break;
+			}
 		}
+	}
+
+	/* Handle response interrupt */
+	if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
 
-		/* Handle host interrupt */
-		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
-			TW_CLEAR_HOST_INTERRUPT(tw_dev);
-
-		/* Handle attention interrupt */
-		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
-			TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
-			if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
-				twa_get_request_id(tw_dev, &request_id);
-
-				error = twa_aen_read_queue(tw_dev, request_id);
-				if (error) {
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					twa_free_request_id(tw_dev, request_id);
-					clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+		/* Drain the response queue from the board */
+		while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+			/* Complete the response */
+			response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+			request_id = TW_RESID_OUT(response_que.response_id);
+			full_command_packet = tw_dev->command_packet_virt[request_id];
+			error = 0;
+			command_packet = &full_command_packet->command.oldcommand;
+			/* Check for command packet errors */
+			if (full_command_packet->command.newcommand.status != 0) {
+				if (tw_dev->srb[request_id] != 0) {
+					error = twa_fill_sense(tw_dev, request_id, 1, 1);
+				} else {
+					/* Skip ioctl error prints */
+					if (request_id != tw_dev->chrdev_request_id) {
+						error = twa_fill_sense(tw_dev, request_id, 0, 1);
+					}
 				}
 			}
-		}
 
-		/* Handle command interrupt */
-		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
-			TW_MASK_COMMAND_INTERRUPT(tw_dev);
-			/* Drain as many pending commands as we can */
-			while (tw_dev->pending_request_count > 0) {
-				request_id = tw_dev->pending_queue[tw_dev->pending_head];
-				if (tw_dev->state[request_id] != TW_S_PENDING) {
-					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+			/* Check for correct state */
+			if (tw_dev->state[request_id] != TW_S_POSTED) {
+				if (tw_dev->srb[request_id] != 0) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
 					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
 					goto twa_interrupt_bail;
 				}
-				if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
-					tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
-					tw_dev->pending_request_count--;
-				} else {
-					/* If we get here, we will continue re-posting on the next command interrupt */
-					break;
-				}
 			}
-		}
 
-		/* Handle response interrupt */
-		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
-
-			/* Drain the response queue from the board */
-			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				/* Complete the response */
-				response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
-				request_id = TW_RESID_OUT(response_que.response_id);
-				full_command_packet = tw_dev->command_packet_virt[request_id];
-				error = 0;
-				command_packet = &full_command_packet->command.oldcommand;
-				/* Check for command packet errors */
-				if (full_command_packet->command.newcommand.status != 0) {
-					if (tw_dev->srb[request_id] != 0) {
-						error = twa_fill_sense(tw_dev, request_id, 1, 1);
-					} else {
-						/* Skip ioctl error prints */
-						if (request_id != tw_dev->chrdev_request_id) {
-							error = twa_fill_sense(tw_dev, request_id, 0, 1);
-						}
-					}
+			/* Check for internal command completion */
+			if (tw_dev->srb[request_id] == 0) {
+				if (request_id != tw_dev->chrdev_request_id) {
+					if (twa_aen_complete(tw_dev, request_id))
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+				} else {
+					tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+					wake_up(&tw_dev->ioctl_wqueue);
 				}
-
-				/* Check for correct state */
-				if (tw_dev->state[request_id] != TW_S_POSTED) {
-					if (tw_dev->srb[request_id] != 0) {
-						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
-					        TW_CLEAR_ALL_INTERRUPTS(tw_dev);
-						goto twa_interrupt_bail;
-					}
+			} else {
+				twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+				/* If no error command was a success */
+				if (error == 0) {
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
 				}
 
-				/* Check for internal command completion */
-				if (tw_dev->srb[request_id] == 0) {
-					if (request_id != tw_dev->chrdev_request_id) {
-						if (twa_aen_complete(tw_dev, request_id))
-							TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
-					} else {
-						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-						wake_up(&tw_dev->ioctl_wqueue);
-					}
-				} else {
-					twa_scsiop_execute_scsi_complete(tw_dev, request_id);
-					/* If no error command was a success */
-					if (error == 0) {
-						tw_dev->srb[request_id]->result = (DID_OK << 16);
-					}
-
-					/* If error, command failed */
-					if (error == 1) {
-						/* Ask for a host reset */
-						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-					}
+				/* If error, command failed */
+				if (error == 1) {
+					/* Ask for a host reset */
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
 
-					/* Now complete the io */
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					twa_free_request_id(tw_dev, request_id);
-					tw_dev->posted_request_count--;
-					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-					twa_unmap_scsi_data(tw_dev, request_id);
+				/* Report residual bytes for single sgl */
+				if ((tw_dev->srb[request_id]->use_sg <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+					if (full_command_packet->command.newcommand.sg_list[0].length < tw_dev->srb[request_id]->request_bufflen)
+						tw_dev->srb[request_id]->resid = tw_dev->srb[request_id]->request_bufflen - full_command_packet->command.newcommand.sg_list[0].length;
 				}
 
-				/* Check for valid status after each drain */
-				status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
-				if (twa_check_bits(status_reg_value)) {
-					if (twa_decode_bits(tw_dev, status_reg_value)) {
-						TW_CLEAR_ALL_INTERRUPTS(tw_dev);
-						goto twa_interrupt_bail;
-					}
+				/* Now complete the io */
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				twa_free_request_id(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+				twa_unmap_scsi_data(tw_dev, request_id);
+			}
+
+			/* Check for valid status after each drain */
+			status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+			if (twa_check_bits(status_reg_value)) {
+				if (twa_decode_bits(tw_dev, status_reg_value)) {
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto twa_interrupt_bail;
 				}
 			}
 		}
 	}
+
 twa_interrupt_bail:
 	spin_unlock(tw_dev->host->host_lock);
 	return IRQ_RETVAL(handled);
@@ -1320,9 +1328,12 @@ static void twa_load_sgl(TW_Command_Full
 
 	if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
 		newcommand = &full_command_packet->command.newcommand;
-		newcommand->request_id = request_id;
+		newcommand->request_id__lunl = 
+			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
 		newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
 		newcommand->sg_list[0].length = length;
+		newcommand->sgl_entries__lunh =
+			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1);
 	} else {
 		oldcommand = &full_command_packet->command.oldcommand;
 		oldcommand->request_id = request_id;
@@ -1332,6 +1343,9 @@ static void twa_load_sgl(TW_Command_Full
 			sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
 			sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
 			sgl->length = length;
+
+			if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+				oldcommand->size += 1;
 		}
 	}
 } /* End twa_load_sgl() */
@@ -1486,7 +1500,7 @@ out:
 static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
 {
 	u32 status_reg_value;
-	unsigned long command_que_value;
+	dma_addr_t command_que_value;
 	int retval = 1;
 
 	command_que_value = tw_dev->command_packet_phys[request_id];
@@ -1517,11 +1531,13 @@ static int twa_post_command_packet(TW_De
 		goto out;
 	} else {
 		/* We successfully posted the command packet */
-#if BITS_PER_LONG > 32
-		writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
-#else
-		writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
-#endif
+		if (sizeof(dma_addr_t) > 4) {
+			command_que_value += TW_COMMAND_OFFSET;
+			writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+			writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+		} else {
+			writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+		}
 		tw_dev->state[request_id] = TW_S_POSTED;
 		tw_dev->posted_request_count++;
 		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
@@ -1534,10 +1550,16 @@ out:
 } /* End twa_post_command_packet() */
 
 /* This function will reset a device extension */
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
 {
 	int i = 0;
 	int retval = 1;
+	unsigned long flags = 0;
+
+	set_bit(TW_IN_RESET, &tw_dev->flags);
+	TW_DISABLE_INTERRUPTS(tw_dev);
+	TW_MASK_COMMAND_INTERRUPT(tw_dev);
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
 
 	/* Abort all requests that are in progress */
 	for (i = 0; i < TW_Q_LENGTH; i++) {
@@ -1564,16 +1586,21 @@ static int twa_reset_device_extension(TW
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
 	tw_dev->reset_print = 0;
-	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-	tw_dev->flags = 0;
 
-	TW_DISABLE_INTERRUPTS(tw_dev);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 
 	if (twa_reset_sequence(tw_dev, 1))
 		goto out;
 
-        TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
 
+	/* Wake up any ioctl that was pending before the reset */
+	if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
+		clear_bit(TW_IN_RESET, &tw_dev->flags);
+	} else {
+		tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+		wake_up(&tw_dev->ioctl_wqueue);
+	}
 	retval = 0;
 out:
 	return retval;
@@ -1589,7 +1616,7 @@ static int twa_reset_sequence(TW_Device_
 			TW_SOFT_RESET(tw_dev);
 
 		/* Make sure controller is in a good state */
-		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
+		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
 			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
 			do_soft_reset = 1;
 			tries++;
@@ -1660,38 +1687,6 @@ static int twa_scsi_biosparam(struct scs
 	return 0;
 } /* End twa_scsi_biosparam() */
 
-/* This is the new scsi eh abort function */
-static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt)
-{
-	int i;
-	TW_Device_Extension *tw_dev = NULL;
-	int retval = FAILED;
-
-	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-
-	spin_unlock_irq(tw_dev->host->host_lock);
-
-	tw_dev->num_aborts++;
-
-	/* If we find any IO's in process, we have to reset the card */
-	for (i = 0; i < TW_Q_LENGTH; i++) {
-		if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) {
-			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n",
-			       tw_dev->host->host_no, TW_DRIVER, 0x2c,
-			       SCpnt->device->id, SCpnt->cmnd[0]);
-			if (twa_reset_device_extension(tw_dev)) {
-				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort");
-				goto out;
-			}
-			break;
-		}
-	}
-	retval = SUCCESS;
-out:
-	spin_lock_irq(tw_dev->host->host_lock);
-	return retval;
-} /* End twa_scsi_eh_abort() */
-
 /* This is the new scsi eh reset function */
 static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 {
@@ -1704,14 +1699,14 @@ static int twa_scsi_eh_reset(struct scsi
 
 	tw_dev->num_resets++;
 
-	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no);
+	printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
 
 	/* Now reset the card and some of the device extension data */
-	if (twa_reset_device_extension(tw_dev)) {
+	if (twa_reset_device_extension(tw_dev, 0)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
 		goto out;
 	}
-	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no);
+
 	retval = SUCCESS;
 out:
 	spin_lock_irq(tw_dev->host->host_lock);
@@ -1724,6 +1719,14 @@ static int twa_scsi_queue(struct scsi_cm
 	int request_id, retval;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
+	/* Check if this FW supports luns */
+	if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		done(SCpnt);
+		retval = 0;
+		goto out;
+	}
+
 	/* Save done function into scsi_cmnd struct */
 	SCpnt->scsi_done = done;
 		
@@ -1748,12 +1751,12 @@ static int twa_scsi_queue(struct scsi_cm
 		done(SCpnt);
 		retval = 0;
 	}
-
+out:
 	return retval;
 } /* End twa_scsi_queue() */
 
 /* This function hands scsi cdb's to the firmware */
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg)
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
 {
 	TW_Command_Full *full_command_packet;
 	TW_Command_Apache *command_packet;
@@ -1787,12 +1790,16 @@ static int twa_scsiop_execute_scsi(TW_De
 	else
 		memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
 
-	if (srb)
+	if (srb) {
 		command_packet->unit = srb->device->id;
-	else
+		command_packet->request_id__lunl =
+			TW_REQ_LUN_IN(srb->device->lun, request_id);
+	} else {
+		command_packet->request_id__lunl =
+			TW_REQ_LUN_IN(0, request_id);
 		command_packet->unit = 0;
+	}
 
-	command_packet->request_id = request_id;
 	command_packet->sgl_offset = 16;
 
 	if (!sglistarg) {
@@ -1809,7 +1816,7 @@ static int twa_scsiop_execute_scsi(TW_De
 				command_packet->sg_list[0].address = buffaddr;
 				command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
 			}
-			command_packet->sgl_entries = 1;
+			command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), 1);
 
 			if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
 				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
@@ -1818,19 +1825,24 @@ static int twa_scsiop_execute_scsi(TW_De
 		}
 
 		if (tw_dev->srb[request_id]->use_sg > 0) {
-			sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
-			if (sg_count == 0)
-				goto out;
-
-			for (i = 0; i < sg_count; i++) {
-				command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
-				command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
-				if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
-					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+			if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+				command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+			} else {
+				sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+				if (sg_count == 0)
 					goto out;
+
+				for (i = 0; i < sg_count; i++) {
+					command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+					command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+					if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+						goto out;
+					}
 				}
 			}
-			command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg;
+			command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg);
 		}
 	} else {
 		/* Internal cdb post */
@@ -1842,7 +1854,7 @@ static int twa_scsiop_execute_scsi(TW_De
 				goto out;
 			}
 		}
-		command_packet->sgl_entries = use_sg;
+		command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg);
 	}
 
 	if (srb) {
@@ -1903,7 +1915,7 @@ static void __twa_shutdown(TW_Device_Ext
 	}
 
 	/* Clear all interrupts just before exit */
-	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+	TW_CLEAR_ALL_INTERRUPTS(tw_dev);
 } /* End __twa_shutdown() */
 
 /* Wrapper for __twa_shutdown */
@@ -1946,9 +1958,9 @@ static struct scsi_host_template driver_
 	.module			= THIS_MODULE,
 	.name			= "3ware 9000 Storage Controller",
 	.queuecommand		= twa_scsi_queue,
-	.eh_abort_handler	= twa_scsi_eh_abort,
 	.eh_host_reset_handler	= twa_scsi_eh_reset,
 	.bios_param		= twa_scsi_biosparam,
+	.change_queue_depth	= twa_change_queue_depth,
 	.can_queue		= TW_Q_LENGTH-2,
 	.this_id		= -1,
 	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,
@@ -1956,7 +1968,6 @@ static struct scsi_host_template driver_
 	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= twa_host_attrs,
-	.sdev_attrs		= twa_dev_attrs,
 	.emulated		= 1
 };
 
@@ -1976,7 +1987,7 @@ static int __devinit twa_probe(struct pc
 
 	pci_set_master(pdev);
 
-	retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+	retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
 	if (retval) {
 		TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
 		goto out_disable_device;
@@ -2028,8 +2039,8 @@ static int __devinit twa_probe(struct pc
 	host->max_id = TW_MAX_UNITS;
 	host->max_cmd_len = TW_MAX_CDB_LEN;
 
-	/* Luns and channels aren't supported by adapter */
-	host->max_lun = 0;
+	/* Channels aren't supported by adapter */
+	host->max_lun = TW_MAX_LUNS(tw_dev->working_srl);
 	host->max_channel = 0;
 
 	/* Register the card with the kernel SCSI layer */
@@ -2095,23 +2106,24 @@ static void twa_remove(struct pci_dev *p
 
 	scsi_remove_host(tw_dev->host);
 
-	__twa_shutdown(tw_dev);
+	/* Unregister character device */
+	if (twa_major >= 0) {
+		unregister_chrdev(twa_major, "twa");
+		twa_major = -1;
+	}
 
 	/* Free up the IRQ */
 	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
 
+	/* Shutdown the card */
+	__twa_shutdown(tw_dev);
+
 	/* Free up the mem region */
 	pci_release_regions(pdev);
 
 	/* Free up device extension resources */
 	twa_free_device_extension(tw_dev);
 
-	/* Unregister character device */
-	if (twa_major >= 0) {
-		unregister_chrdev(twa_major, "twa");
-		twa_major = -1;
-	}
-
 	scsi_host_put(tw_dev->host);
 	pci_disable_device(pdev);
 	twa_device_extension_count--;
@@ -2139,7 +2151,7 @@ static struct pci_driver twa_driver = {
 /* This function is called on driver initialization */
 static int __init twa_init(void)
 {
-	printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version);
+	printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
 
 	return pci_module_init(&twa_driver);
 } /* End twa_init() */
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -3,7 +3,7 @@
 
    Written By: Adam Radford <linuxraid@amcc.com>
 
-   Copyright (C) 2004 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2005 Applied Micro Circuits 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
@@ -293,7 +293,6 @@ static twa_message_type twa_error_table[
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
 
 /* PCI related defines */
-#define TW_DEVICE_NAME			       "3w-9xxx"
 #define TW_NUMDEVICES 1
 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
 #define TW_PCI_CLEAR_PCI_ABORT     0x2000
@@ -325,9 +324,9 @@ static twa_message_type twa_error_table[
 
 /* Compatibility defines */
 #define TW_9000_ARCH_ID 0x5
-#define TW_CURRENT_FW_SRL 24
-#define TW_CURRENT_FW_BUILD 5
-#define TW_CURRENT_FW_BRANCH 1
+#define TW_CURRENT_DRIVER_SRL 28
+#define TW_CURRENT_DRIVER_BUILD 9
+#define TW_CURRENT_DRIVER_BRANCH 4
 
 /* Phase defines */
 #define TW_PHASE_INITIAL 0
@@ -346,19 +345,10 @@ static twa_message_type twa_error_table[
 #define TW_BUNDLED_FW_SAFE_TO_FLASH	      0x4
 #define TW_CTLR_FW_RECOMMENDS_FLASH	      0x8
 #define TW_CTLR_FW_COMPATIBLE		      0x2
-#define TW_BASE_FW_SRL			      0x17
+#define TW_BASE_FW_SRL			      24
 #define TW_BASE_FW_BRANCH		      0
 #define TW_BASE_FW_BUILD		      1
-#if BITS_PER_LONG > 32
-#define TW_APACHE_MAX_SGL_LENGTH 72
-#define TW_ESCALADE_MAX_SGL_LENGTH 41
-#define TW_APACHE_CMD_PKT_SIZE 5
-#else
-#define TW_APACHE_MAX_SGL_LENGTH 109
-#define TW_ESCALADE_MAX_SGL_LENGTH 62
-#define TW_APACHE_CMD_PKT_SIZE 4
-#endif
-#define TW_ATA_PASS_SGL_MAX                   60
+#define TW_FW_SRL_LUNS_SUPPORTED              28
 #define TW_Q_LENGTH			      256
 #define TW_Q_START			      0
 #define TW_MAX_SLOT			      32
@@ -366,7 +356,7 @@ static twa_message_type twa_error_table[
 #define TW_MAX_CMDS_PER_LUN		      254
 #define TW_MAX_RESPONSE_DRAIN		      256
 #define TW_MAX_AEN_DRAIN		      40
-#define TW_IN_IOCTL                           2
+#define TW_IN_RESET                           2
 #define TW_IN_CHRDEV_IOCTL                    3
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_MAX_SECTORS                        256
@@ -424,13 +414,6 @@ static twa_message_type twa_error_table[
 #define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER
 #define TW_MESSAGE_SOURCE_LINUX_OS            9
 #define TW_OS TW_MESSAGE_SOURCE_LINUX_OS
-#if BITS_PER_LONG > 32
-#define TW_COMMAND_SIZE			      5
-#define TW_DMA_MASK			      DMA_64BIT_MASK
-#else
-#define TW_COMMAND_SIZE			      4
-#define TW_DMA_MASK			      DMA_32BIT_MASK
-#endif
 #ifndef PCI_DEVICE_ID_3WARE_9000
 #define PCI_DEVICE_ID_3WARE_9000 0x1002
 #endif
@@ -451,14 +434,14 @@ static twa_message_type twa_error_table[
 /* reserved_1: 4, response_id: 8, reserved_2: 20 */
 #define TW_RESID_OUT(x) ((x >> 4) & 0xff)
 
+/* request_id: 12, lun: 4 */
+#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff))
+#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
+
 /* Macros */
 #define TW_CONTROL_REG_ADDR(x) (x->base_addr)
 #define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
-#if BITS_PER_LONG > 32
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x20)
-#else
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x8)
-#endif
+#define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
 #define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
 #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
 #define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
@@ -480,12 +463,17 @@ printk(KERN_WARNING "3w-9xxx: scsi%d: ER
 else \
 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
 }
+#define TW_MAX_LUNS(srl) (srl < TW_FW_SRL_LUNS_SUPPORTED ? 1 : 16)
+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 5 : 4)
+#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109)
+#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62)
+#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0)
 
 #pragma pack(1)
 
 /* Scatter Gather List Entry */
 typedef struct TAG_TW_SG_Entry {
-	unsigned long address;
+	dma_addr_t address;
 	u32 length;
 } TW_SG_Entry;
 
@@ -506,42 +494,27 @@ typedef struct TW_Command {
 		struct {
 			u32 lba;
 			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
-			u32 padding[2];	/* pad to 512 bytes */
-#else
-			u32 padding;
-#endif
+			dma_addr_t padding;
 		} io;
 		struct {
 			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
-			u32 padding[3];
-#else
-			u32 padding[2];
-#endif
+			u32 padding;
+			dma_addr_t padding2;
 		} param;
 	} byte8_offset;
 } TW_Command;
 
-/* Scatter gather element for 9000+ controllers */
-typedef struct TAG_TW_SG_Apache {
-	unsigned long address;
-	u32 length;
-} TW_SG_Apache;
-
 /* Command Packet for 9000+ controllers */
 typedef struct TAG_TW_Command_Apache {
 	unsigned char opcode__reserved;
 	unsigned char unit;
-	unsigned short request_id;
+	unsigned short request_id__lunl;
 	unsigned char status;
 	unsigned char sgl_offset;
-	unsigned short sgl_entries;
+	unsigned short sgl_entries__lunh;
 	unsigned char cdb[16];
-	TW_SG_Apache sg_list[TW_APACHE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
-	unsigned char padding[8];
-#endif
+	TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
+	unsigned char padding[TW_PADDING_LENGTH];
 } TW_Command_Apache;
 
 /* New command packet header */
@@ -652,14 +625,20 @@ typedef struct TAG_TW_Compatibility_Info
 	unsigned short working_srl;
 	unsigned short working_branch;
 	unsigned short working_build;
+	unsigned short driver_srl_high;
+	unsigned short driver_branch_high;
+	unsigned short driver_build_high;
+	unsigned short driver_srl_low;
+	unsigned short driver_branch_low;
+	unsigned short driver_build_low;
 } TW_Compatibility_Info;
 
 typedef struct TAG_TW_Device_Extension {
 	u32                     __iomem *base_addr;
 	unsigned long	       	*generic_buffer_virt[TW_Q_LENGTH];
-	unsigned long	       	generic_buffer_phys[TW_Q_LENGTH];
+	dma_addr_t	       	generic_buffer_phys[TW_Q_LENGTH];
 	TW_Command_Full	       	*command_packet_virt[TW_Q_LENGTH];
-	unsigned long		command_packet_phys[TW_Q_LENGTH];
+	dma_addr_t		command_packet_phys[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
 	struct scsi_cmnd	*srb[TW_Q_LENGTH];
 	unsigned char		free_queue[TW_Q_LENGTH];
@@ -675,7 +654,6 @@ typedef struct TAG_TW_Device_Extension {
 	unsigned int		max_pending_request_count;
 	unsigned int		max_sgl_entries;
 	unsigned int		sgl_entries;
-	unsigned int		num_aborts;
 	unsigned int		num_resets;
 	unsigned int		sector_count;
 	unsigned int		max_sector_count;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2004 3ware Inc.
+   Copyright (C) 1999-2005 3ware Inc.
 
    Kernel compatiblity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -185,6 +185,12 @@
                  Fix data_buffer_length usage in tw_chrdev_ioctl().
                  Update contact information.
    1.26.02.000 - Convert driver to pci_driver format.
+   1.26.02.001 - Increase max ioctl buffer size to 512 sectors.
+                 Make tw_scsi_queue() return 0 for 'Unknown scsi opcode'.
+                 Fix tw_remove() to free irq handler/unregister_chrdev()
+                 before shutting down card.
+                 Change to new 'change_queue_depth' api.
+                 Fix 'handled=1' ISR usage, remove bogus IRQ check.
 */
 
 #include <linux/module.h>
@@ -207,7 +213,7 @@
 #include "3w-xxxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "1.26.02.000"
+#define TW_DRIVER_VERSION "1.26.02.001"
 static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 static int tw_device_extension_count = 0;
 static int twe_major = -1;
@@ -509,33 +515,13 @@ static ssize_t tw_show_stats(struct clas
 } /* End tw_show_stats() */
 
 /* This function will set a devices queue depth */
-static ssize_t tw_store_queue_depth(struct device *dev, const char *buf, size_t count)
+static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
 {
-	int queue_depth;
-	struct scsi_device *sdev = to_scsi_device(dev);
-
-	queue_depth = simple_strtoul(buf, NULL, 0);
 	if (queue_depth > TW_Q_LENGTH-2)
-		return -EINVAL;
+		queue_depth = TW_Q_LENGTH-2;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
-
-	return count;
-} /* End tw_store_queue_depth() */
-
-/* Create sysfs 'queue_depth' entry */
-static struct device_attribute tw_queue_depth_attr = {
-	.attr = {
-		.name =		"queue_depth",
-		.mode =		S_IRUSR | S_IWUSR,
-	},
-	.store = tw_store_queue_depth
-};
-
-/* Device attributes initializer */
-static struct device_attribute *tw_dev_attrs[] = {
-	&tw_queue_depth_attr,
-	NULL,
-};
+	return queue_depth;
+} /* End tw_change_queue_depth() */
 
 /* Create sysfs 'stats' entry */
 static struct class_device_attribute tw_host_stats_attr = {
@@ -910,7 +896,7 @@ static int tw_chrdev_ioctl(struct inode 
 		goto out;
 
 	/* Check size */
-	if (data_buffer_length > TW_MAX_SECTORS * 512) {
+	if (data_buffer_length > TW_MAX_IOCTL_SECTORS * 512) {
 		retval = -EINVAL;
 		goto out;
 	}
@@ -995,7 +981,7 @@ static int tw_chrdev_ioctl(struct inode 
 			timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
 
 			/* Now wait for the command to complete */
-			timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+			timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
 
 			/* See if we reset while waiting for the ioctl to complete */
 			if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
@@ -1004,16 +990,11 @@ static int tw_chrdev_ioctl(struct inode 
 				goto out2;
 			}
 
-			/* Check if we timed out, got a signal, or didn't get
-			   an interrupt */
-			if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+			/* We timed out, and didn't get an interrupt */
+			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
 				/* Now we need to reset the board */
-				if (timeout == -ERESTARTSYS) {
-					retval = timeout;
-				} else {
-					printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
-					retval = -EIO;
-				}
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
+				retval = -EIO;
 				spin_lock_irqsave(tw_dev->host->host_lock, flags);
 				tw_dev->state[request_id] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, request_id);
@@ -2060,7 +2041,7 @@ static int tw_scsi_queue(struct scsi_cmn
 			tw_state_request_finish(tw_dev, request_id);
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			done(SCpnt);
-			goto out;
+			retval = 0;
 	}
 	if (retval) {
 		tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -2069,7 +2050,6 @@ static int tw_scsi_queue(struct scsi_cmn
 		done(SCpnt);
 		retval = 0;
 	}
-out:
 	return retval;
 } /* End tw_scsi_queue() */
 
@@ -2088,183 +2068,180 @@ static irqreturn_t tw_interrupt(int irq,
 	/* Get the host lock for io completions */
 	spin_lock(tw_dev->host->host_lock);
 
-	/* See if the interrupt matches this instance */
-	if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
+	/* Read the registers */
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
 
-		handled = 1;
+	/* Check if this is our interrupt, otherwise bail */
+	if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+		goto tw_interrupt_bail;
 
-		/* Read the registers */
-		status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+	handled = 1;
 
-		/* Check if this is our interrupt, otherwise bail */
-		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+	/* Check controller for errors */
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+		if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+			TW_CLEAR_ALL_INTERRUPTS(tw_dev);
 			goto tw_interrupt_bail;
-
-		/* Check controller for errors */
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-			if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-				TW_CLEAR_ALL_INTERRUPTS(tw_dev);
-				goto tw_interrupt_bail;
-			}
 		}
+	}
 
-		/* Handle host interrupt */
-		if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
-			TW_CLEAR_HOST_INTERRUPT(tw_dev);
+	/* Handle host interrupt */
+	if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
+		TW_CLEAR_HOST_INTERRUPT(tw_dev);
+	}
+
+	/* Handle attention interrupt */
+	if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+		TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+		tw_state_request_start(tw_dev, &request_id);
+		error = tw_aen_read_queue(tw_dev, request_id);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
 		}
+	}
 
-		/* Handle attention interrupt */
-		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
-			TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
-			tw_state_request_start(tw_dev, &request_id);
-			error = tw_aen_read_queue(tw_dev, request_id);
-			if (error) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
-				tw_dev->state[request_id] = TW_S_COMPLETED;
-				tw_state_request_finish(tw_dev, request_id);
+	/* Handle command interrupt */
+	if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+		/* Drain as many pending commands as we can */
+		while (tw_dev->pending_request_count > 0) {
+			request_id = tw_dev->pending_queue[tw_dev->pending_head];
+			if (tw_dev->state[request_id] != TW_S_PENDING) {
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
+				break;
+			}
+			if (tw_post_command_packet(tw_dev, request_id)==0) {
+				if (tw_dev->pending_head == TW_Q_LENGTH-1) {
+					tw_dev->pending_head = TW_Q_START;
+				} else {
+					tw_dev->pending_head = tw_dev->pending_head + 1;
+				}
+				tw_dev->pending_request_count--;
+			} else {
+				/* If we get here, we will continue re-posting on the next command interrupt */
+				break;
 			}
 		}
+		/* If there are no more pending requests, we mask command interrupt */
+		if (tw_dev->pending_request_count == 0) 
+			TW_MASK_COMMAND_INTERRUPT(tw_dev);
+	}
+
+	/* Handle response interrupt */
+	if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+		/* Drain the response queue from the board */
+		while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+			/* Read response queue register */
+			response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+			request_id = TW_RESID_OUT(response_que.response_id);
+			command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+			error = 0;
 
-		/* Handle command interrupt */
-		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
-			/* Drain as many pending commands as we can */
-			while (tw_dev->pending_request_count > 0) {
-				request_id = tw_dev->pending_queue[tw_dev->pending_head];
-				if (tw_dev->state[request_id] != TW_S_PENDING) {
-					printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
-					break;
-				}
-				if (tw_post_command_packet(tw_dev, request_id)==0) {
-					if (tw_dev->pending_head == TW_Q_LENGTH-1) {
-						tw_dev->pending_head = TW_Q_START;
-					} else {
-						tw_dev->pending_head = tw_dev->pending_head + 1;
-					}
-					tw_dev->pending_request_count--;
+			/* Check for bad response */
+			if (command_packet->status != 0) {
+				/* If internal command, don't error, don't fill sense */
+				if (tw_dev->srb[request_id] == NULL) {
+					tw_decode_sense(tw_dev, request_id, 0);
 				} else {
-					/* If we get here, we will continue re-posting on the next command interrupt */
-					break;
+					error = tw_decode_sense(tw_dev, request_id, 1);
 				}
 			}
-			/* If there are no more pending requests, we mask command interrupt */
-			if (tw_dev->pending_request_count == 0) 
-				TW_MASK_COMMAND_INTERRUPT(tw_dev);
-		}
-
-		/* Handle response interrupt */
-		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
-			/* Drain the response queue from the board */
-			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				/* Read response queue register */
-				response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
-				request_id = TW_RESID_OUT(response_que.response_id);
-				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-				error = 0;
-
-				/* Check for bad response */
-				if (command_packet->status != 0) {
-					/* If internal command, don't error, don't fill sense */
-					if (tw_dev->srb[request_id] == NULL) {
-						tw_decode_sense(tw_dev, request_id, 0);
-					} else {
-						error = tw_decode_sense(tw_dev, request_id, 1);
-					}
-				}
 
-				/* Check for correct state */
-				if (tw_dev->state[request_id] != TW_S_POSTED) {
-					if (tw_dev->srb[request_id] != NULL) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no);
-						error = 1;
-					}
+			/* Check for correct state */
+			if (tw_dev->state[request_id] != TW_S_POSTED) {
+				if (tw_dev->srb[request_id] != NULL) {
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no);
+					error = 1;
 				}
+			}
 
-				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
+			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 
-				/* Check for internal command completion */
-				if (tw_dev->srb[request_id] == NULL) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					/* Check for chrdev ioctl completion */
-					if (request_id != tw_dev->chrdev_request_id) {
-						retval = tw_aen_complete(tw_dev, request_id);
-						if (retval) {
-							printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
-						}
-					} else {
-						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-						wake_up(&tw_dev->ioctl_wqueue);
+			/* Check for internal command completion */
+			if (tw_dev->srb[request_id] == NULL) {
+				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
+				/* Check for chrdev ioctl completion */
+				if (request_id != tw_dev->chrdev_request_id) {
+					retval = tw_aen_complete(tw_dev, request_id);
+					if (retval) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
 					}
 				} else {
+					tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+					wake_up(&tw_dev->ioctl_wqueue);
+				}
+			} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
-					case READ_10:
-					case READ_6:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
-						break;
-					case WRITE_10:
-					case WRITE_6:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
-						break;
-					case TEST_UNIT_READY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
-						error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
-						break;
-					case INQUIRY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
-						error = tw_scsiop_inquiry_complete(tw_dev, request_id);
-						break;
-					case READ_CAPACITY:
-						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;
-					default:
-						printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
-						error = 1;
-					}
-
-					/* If no error command was a success */
-					if (error == 0) {
-						tw_dev->srb[request_id]->result = (DID_OK << 16);
-					}
+				case READ_10:
+				case READ_6:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
+					break;
+				case WRITE_10:
+				case WRITE_6:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
+					break;
+				case TEST_UNIT_READY:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+					error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+					break;
+				case INQUIRY:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
+					error = tw_scsiop_inquiry_complete(tw_dev, request_id);
+					break;
+				case READ_CAPACITY:
+					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;
+				default:
+					printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+					error = 1;
+				}
 
-					/* If error, command failed */
-					if (error == 1) {
-						/* Ask for a host reset */
-						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-					}
+				/* If no error command was a success */
+				if (error == 0) {
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
+				}
 
-					/* Now complete the io */
-					if ((error != TW_ISR_DONT_COMPLETE)) {
-						tw_dev->state[request_id] = TW_S_COMPLETED;
-						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]);
+				/* If error, command failed */
+				if (error == 1) {
+					/* Ask for a host reset */
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
 
-						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-					}
+				/* Now complete the io */
+				if ((error != TW_ISR_DONT_COMPLETE)) {
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					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]);
 				}
+			}
 				
-				/* Check for valid status after each drain */
-				status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
-				if (tw_check_bits(status_reg_value)) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-					if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-						TW_CLEAR_ALL_INTERRUPTS(tw_dev);
-						goto tw_interrupt_bail;
-					}
+			/* Check for valid status after each drain */
+			status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+			if (tw_check_bits(status_reg_value)) {
+				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+				if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto tw_interrupt_bail;
 				}
 			}
 		}
 	}
+
 tw_interrupt_bail:
 	spin_unlock(tw_dev->host->host_lock);
 	return IRQ_RETVAL(handled);
@@ -2304,6 +2281,7 @@ static struct scsi_host_template driver_
 	.queuecommand		= tw_scsi_queue,
 	.eh_host_reset_handler	= tw_scsi_eh_reset,
 	.bios_param		= tw_scsi_biosparam,
+	.change_queue_depth	= tw_change_queue_depth,
 	.can_queue		= TW_Q_LENGTH-2,
 	.this_id		= -1,
 	.sg_tablesize		= TW_MAX_SGL_LENGTH,
@@ -2311,7 +2289,6 @@ static struct scsi_host_template driver_
 	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,	
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= tw_host_attrs,
-	.sdev_attrs		= tw_dev_attrs,
 	.emulated		= 1
 };
 
@@ -2438,23 +2415,24 @@ static void tw_remove(struct pci_dev *pd
 
 	scsi_remove_host(tw_dev->host);
 
-	__tw_shutdown(tw_dev);
+	/* Unregister character device */
+	if (twe_major >= 0) {
+		unregister_chrdev(twe_major, "twe");
+		twe_major = -1;
+	}
 
 	/* Free up the IRQ */
 	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
 
+	/* Shutdown the card */
+	__tw_shutdown(tw_dev);
+
 	/* Free up the mem region */
 	pci_release_regions(pdev);
 
 	/* Free up device extension resources */
 	tw_free_device_extension(tw_dev);
 
-	/* Unregister character device */
-	if (twe_major >= 0) {
-		unregister_chrdev(twe_major, "twe");
-		twe_major = -1;
-	}
-
 	scsi_host_put(tw_dev->host);
 	pci_disable_device(pdev);
 	tw_device_extension_count--;
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2004 3ware Inc.
+   Copyright (C) 1999-2005 3ware Inc.
 
    Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -227,6 +227,7 @@ static unsigned char tw_sense_table[][4]
 #define TW_IN_RESET                           2
 #define TW_IN_CHRDEV_IOCTL                    3
 #define TW_MAX_SECTORS                        256
+#define TW_MAX_IOCTL_SECTORS		      512
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
 #define TW_ISR_DONT_COMPLETE                  2
@@ -397,7 +398,6 @@ typedef struct TAG_TW_Device_Extension {
 	unsigned long		*alignment_virtual_address[TW_Q_LENGTH];
 	unsigned long		alignment_physical_address[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
-	int			num_units;
 	unsigned long		*command_packet_virtual_address[TW_Q_LENGTH];
 	unsigned long		command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -296,8 +296,7 @@ NCR_700_get_SXFER(struct scsi_device *SD
 
 struct Scsi_Host *
 NCR_700_detect(struct scsi_host_template *tpnt,
-	       struct NCR_700_Host_Parameters *hostdata, struct device *dev,
-	       unsigned long irq, u8 scsi_id)
+	       struct NCR_700_Host_Parameters *hostdata, struct device *dev)
 {
 	dma_addr_t pScript, pSlots;
 	__u8 *memory;
@@ -390,11 +389,8 @@ NCR_700_detect(struct scsi_host_template
 	host->max_lun = NCR_700_MAX_LUNS;
 	BUG_ON(NCR_700_transport_template == NULL);
 	host->transportt = NCR_700_transport_template;
-	host->unique_id = hostdata->base;
-	host->base = hostdata->base;
+	host->unique_id = (unsigned long)hostdata->base;
 	hostdata->eh_complete = NULL;
-	host->irq = irq;
-	host->this_id = scsi_id;
 	host->hostdata[0] = (unsigned long)hostdata;
 	/* kick the chip */
 	NCR_700_writeb(0xff, host, CTEST9_REG);
@@ -415,28 +411,16 @@ NCR_700_detect(struct scsi_host_template
 	/* reset the chip */
 	NCR_700_chip_reset(host);
 
-	if (request_irq(irq, NCR_700_intr, SA_SHIRQ, dev->bus_id, host)) {
-		dev_printk(KERN_ERR, dev, "53c700: irq %lu request failed\n ",
-			   irq);
-		goto out_put_host;
-	}
-
 	if (scsi_add_host(host, dev)) {
 		dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n");
-		goto out_release_irq;
+		scsi_host_put(host);
+		return NULL;
 	}
 
 	spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
 		SPI_SIGNAL_SE;
 
 	return host;
-
- out_release_irq:
-	free_irq(irq, host);
- out_put_host:
-	scsi_host_put(host);
-
-	return NULL;
 }
 
 int
@@ -824,6 +808,7 @@ process_extended_message(struct Scsi_Hos
 	switch(hostdata->msgin[2]) {
 	case A_SDTR_MSG:
 		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+			struct scsi_target *starget = SCp->device->sdev_target;
 			__u8 period = hostdata->msgin[3];
 			__u8 offset = hostdata->msgin[4];
 
@@ -831,22 +816,15 @@ process_extended_message(struct Scsi_Hos
 				offset = 0;
 				period = 0;
 			}
+
+			spi_offset(starget) = offset;
+			spi_period(starget) = period;
 			
 			if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
-				if(spi_offset(SCp->device->sdev_target) != 0)
-					printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
-					       host->host_no, pun, lun,
-					       offset, period*4);
-				else
-					printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n",
-					       host->host_no, pun, lun);
+				spi_display_xfer_agreement(starget);
 				NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
 			}
-				
-			spi_offset(SCp->device->sdev_target) = offset;
-			spi_period(SCp->device->sdev_target) = period;
 			
-
 			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
 			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 			
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -14,10 +14,6 @@
 #include <scsi/scsi_device.h>
 
 
-#if defined(CONFIG_53C700_MEM_MAPPED) && defined(CONFIG_53C700_IO_MAPPED)
-#define CONFIG_53C700_BOTH_MAPPED
-#endif
-
 /* Turn on for general debugging---too verbose for normal use */
 #undef	NCR_700_DEBUG
 /* Debug the tag queues, checking hash queue allocation and deallocation
@@ -49,19 +45,11 @@
 /* magic byte identifying an internally generated REQUEST_SENSE command */
 #define NCR_700_INTERNAL_SENSE_MAGIC	0x42
 
-/* WARNING: Leave this in for now: the dependency preprocessor doesn't
- * pick up file specific flags, so must define here if they are not
- * set */
-#if !defined(CONFIG_53C700_IO_MAPPED) && !defined(CONFIG_53C700_MEM_MAPPED)
-#error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core."
-#endif
-
 struct NCR_700_Host_Parameters;
 
 /* These are the externally used routines */
 struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
-		struct NCR_700_Host_Parameters *, struct device *,
-		unsigned long, u8);
+		struct NCR_700_Host_Parameters *, struct device *);
 int NCR_700_release(struct Scsi_Host *host);
 irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
 
@@ -185,7 +173,7 @@ struct NCR_700_command_slot {
 struct NCR_700_Host_Parameters {
 	/* These must be filled in by the calling driver */
 	int	clock;			/* board clock speed in MHz */
-	unsigned long	base;		/* the base for the port (copied to host) */
+	void __iomem	*base;		/* the base for the port (copied to host) */
 	struct device	*dev;
 	__u32	dmode_extra;	/* adjustable bus settings */
 	__u32	differential:1;	/* if we are differential */
@@ -200,9 +188,6 @@ struct NCR_700_Host_Parameters {
 	/* NOTHING BELOW HERE NEEDS ALTERING */
 	__u32	fast:1;		/* if we can alter the SCSI bus clock
                                    speed (so can negiotiate sync) */
-#ifdef CONFIG_53C700_BOTH_MAPPED
-	__u32	mem_mapped;	/* set if memory mapped */
-#endif
 	int	sync_clock;	/* The speed of the SYNC core */
 
 	__u32	*script;		/* pointer to script location */
@@ -247,12 +232,18 @@ struct NCR_700_Host_Parameters {
 #ifdef CONFIG_53C700_LE_ON_BE
 #define bE	(hostdata->force_le_on_be ? 0 : 3)
 #define	bSWAP	(hostdata->force_le_on_be)
+/* This is terrible, but there's no raw version of ioread32.  That means
+ * that on a be board we swap twice (once in ioread32 and once again to 
+ * get the value correct) */
+#define bS_to_io(x)	((hostdata->force_le_on_be) ? (x) : cpu_to_le32(x))
 #elif defined(__BIG_ENDIAN)
 #define bE	3
 #define bSWAP	0
+#define bS_to_io(x)	(x)
 #elif defined(__LITTLE_ENDIAN)
 #define bE	0
 #define bSWAP	0
+#define bS_to_io(x)	(x)
 #else
 #error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?"
 #endif
@@ -456,91 +447,42 @@ struct NCR_700_Host_Parameters {
 
 
 static inline __u8
-NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg)
-{
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	return readb(host->base + (reg^bE));
-}
-
-static inline __u32
-NCR_700_mem_readl(struct Scsi_Host *host, __u32 reg)
-{
-	__u32 value = __raw_readl(host->base + reg);
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-#if 1
-	/* sanity check the register */
-	if((reg & 0x3) != 0)
-		BUG();
-#endif
-
-	return bS_to_cpu(value);
-}
-
-static inline void
-NCR_700_mem_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
-{
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	writeb(value, host->base + (reg^bE));
-}
-
-static inline void
-NCR_700_mem_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
-{
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-#if 1
-	/* sanity check the register */
-	if((reg & 0x3) != 0)
-		BUG();
-#endif
-
-	__raw_writel(bS_to_host(value), host->base + reg);
-}
-
-static inline __u8
-NCR_700_io_readb(struct Scsi_Host *host, __u32 reg)
+NCR_700_readb(struct Scsi_Host *host, __u32 reg)
 {
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+	const struct NCR_700_Host_Parameters *hostdata
 		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
 
-	return inb(host->base + (reg^bE));
+	return ioread8(hostdata->base + (reg^bE));
 }
 
 static inline __u32
-NCR_700_io_readl(struct Scsi_Host *host, __u32 reg)
+NCR_700_readl(struct Scsi_Host *host, __u32 reg)
 {
-	__u32 value = inl(host->base + reg);
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+	const struct NCR_700_Host_Parameters *hostdata
 		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
+	__u32 value = ioread32(hostdata->base + reg);
 #if 1
 	/* sanity check the register */
 	if((reg & 0x3) != 0)
 		BUG();
 #endif
 
-	return bS_to_cpu(value);
+	return bS_to_io(value);
 }
 
 static inline void
-NCR_700_io_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
 {
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+	const struct NCR_700_Host_Parameters *hostdata
 		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
 
-	outb(value, host->base + (reg^bE));
+	iowrite8(value, hostdata->base + (reg^bE));
 }
 
 static inline void
-NCR_700_io_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
 {
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+	const struct NCR_700_Host_Parameters *hostdata
 		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
 
 #if 1
@@ -549,102 +491,7 @@ NCR_700_io_writel(__u32 value, struct Sc
 		BUG();
 #endif
 
-	outl(bS_to_host(value), host->base + reg);
-}
-
-#ifdef CONFIG_53C700_BOTH_MAPPED
-
-static inline __u8
-NCR_700_readb(struct Scsi_Host *host, __u32 reg)
-{
-	__u8 val;
-
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	if(hostdata->mem_mapped)
-		val = NCR_700_mem_readb(host, reg);
-	else
-		val = NCR_700_io_readb(host, reg);
-
-	return val;
-}
-
-static inline __u32
-NCR_700_readl(struct Scsi_Host *host, __u32 reg)
-{
-	__u32 val;
-
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	if(hostdata->mem_mapped)
-		val = NCR_700_mem_readl(host, reg);
-	else
-		val = NCR_700_io_readl(host, reg);
-
-	return val;
-}
-
-static inline void
-NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
-{
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	if(hostdata->mem_mapped)
-		NCR_700_mem_writeb(value, host, reg);
-	else
-		NCR_700_io_writeb(value, host, reg);
-}
-
-static inline void
-NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
-{
-	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
-		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
-
-	if(hostdata->mem_mapped)
-		NCR_700_mem_writel(value, host, reg);
-	else
-		NCR_700_io_writel(value, host, reg);
-}
-
-static inline void
-NCR_700_set_mem_mapped(struct NCR_700_Host_Parameters *hostdata)
-{
-	hostdata->mem_mapped = 1;
-}
-
-static inline void
-NCR_700_set_io_mapped(struct NCR_700_Host_Parameters *hostdata)
-{
-	hostdata->mem_mapped = 0;
+	iowrite32(bS_to_io(value), hostdata->base + reg);
 }
 
-
-#elif defined(CONFIG_53C700_IO_MAPPED)
-
-#define NCR_700_readb NCR_700_io_readb
-#define NCR_700_readl NCR_700_io_readl
-#define NCR_700_writeb NCR_700_io_writeb
-#define NCR_700_writel NCR_700_io_writel
-
-#define NCR_700_set_io_mapped(x)
-#define NCR_700_set_mem_mapped(x)	error I/O mapped only
-
-#elif defined(CONFIG_53C700_MEM_MAPPED)
-
-#define NCR_700_readb NCR_700_mem_readb
-#define NCR_700_readl NCR_700_mem_readl
-#define NCR_700_writeb NCR_700_mem_writeb
-#define NCR_700_writel NCR_700_mem_writel
-
-#define NCR_700_set_io_mapped(x)	error MEM mapped only
-#define NCR_700_set_mem_mapped(x)
-
-#else
-#error neither CONFIG_53C700_MEM_MAPPED nor CONFIG_53C700_IO_MAPPED is set
-#endif
-
 #endif
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -280,6 +280,7 @@
 #endif
 
 #include "scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include "53c7xx.h"
 #include <linux/stat.h>
@@ -1721,9 +1722,9 @@ NCR53c7xx_run_tests (struct Scsi_Host *h
 		printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
 		    host->host_no, i, data + 8);
 		printk ("scsi%d : status ", host->host_no);
-		print_status (status);
+		scsi_print_status (status);
 		printk ("\nscsi%d : message ", host->host_no);
-		print_msg (&msg);
+		scsi_print_msg (&msg);
 		printk ("\n");
 	    } else if (hostdata->test_completed == 3) {
 		printk("scsi%d : test 2 no connection with target %d\n",
@@ -2312,7 +2313,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Ho
 	    printk ("scsi%d : received message", host->host_no);
 	    if (c) 
 	    	printk (" from target %d lun %d ", c->device->id, c->device->lun);
-	    print_msg ((unsigned char *) hostdata->msg_buf);
+	    scsi_print_msg ((unsigned char *) hostdata->msg_buf);
 	    printk("\n");
 	}
 	
@@ -3204,7 +3205,7 @@ create_cmd (Scsi_Cmnd *cmd) {
     case WRITE_10:
 #if 0
 	printk("scsi%d : command is ", host->host_no);
-	print_command(cmd->cmnd);
+	__scsi_print_command(cmd->cmnd);
 #endif
 #if 0
 	printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
@@ -3232,7 +3233,7 @@ create_cmd (Scsi_Cmnd *cmd) {
      */
     default:
 	printk("scsi%d : datain+dataout for command ", host->host_no);
-	print_command(cmd->cmnd);
+	__scsi_print_command(cmd->cmnd);
 	datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
     }
 
@@ -3938,7 +3939,7 @@ intr_scsi (struct Scsi_Host *host, struc
     	    if (cmd) {
     	    	printk("scsi%d : target %d, lun %d, command ",
 		    host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
-    	    	print_command (cmd->cmd->cmnd);
+    	    	__scsi_print_command (cmd->cmd->cmnd);
 		printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
 		    NCR53c7x0_read32(DSP_REG),
 		    bus_to_virt(NCR53c7x0_read32(DSP_REG)));
@@ -4208,7 +4209,7 @@ restart:
 	if (hostdata->options & OPTION_DEBUG_INTR) {
 	    printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", 
 		  host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
-	    print_command (tmp->cmnd);
+	    __scsi_print_command (tmp->cmnd);
 	}
 
 	tmp->scsi_done(tmp);
@@ -4297,7 +4298,7 @@ NCR53c7x0_intr (int irq, void *dev_id, s
 		printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", 
 		    host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
 		    (int) cmd->cmd->device->lun);
-		print_command (cmd->cmd->cmnd);
+		__scsi_print_command (cmd->cmd->cmnd);
 	    } else {
 		printk("scsi%d : no active command\n", host->host_no);
 	    }
@@ -5539,7 +5540,7 @@ print_dsa (struct Scsi_Host *host, u32 *
 	    i > 0 && !check_address ((unsigned long) ptr, 1);
 	    ptr += len, i -= len) {
 	    printk("               ");
-	    len = print_msg (ptr);
+	    len = scsi_print_msg (ptr);
 	    printk("\n");
 	    if (!len)
 		break;
@@ -5554,7 +5555,7 @@ print_dsa (struct Scsi_Host *host, u32 *
     if (cmd) {
 	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
 	    cmd->result, cmd->device->id, cmd->device->lun);
-	print_command(cmd->cmnd);
+	__scsi_print_command(cmd->cmnd);
     } else
 	printk("\n");
     printk("        + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
@@ -6028,7 +6029,7 @@ dump_events (struct Scsi_Host *host, int
 		    virt_to_bus(event.dsa), event.dsa);
 	    if (event.pid != -1) {
 		printk ("         event for pid %ld ", event.pid);
-		print_command (event.cmnd);
+		__scsi_print_command (event.cmnd);
 	    }
 	}
     }
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2958,13 +2958,6 @@ static int BusLogic_AbortCommand(struct 
 	struct BusLogic_CCB *CCB;
 	BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested);
 	/*
-	   If this Command has already completed, then no Abort is necessary.
-	 */
-	if (Command->serial_number != Command->serial_number_at_timeout) {
-		BusLogic_Warning("Unable to Abort Command to Target %d - " "Already Completed\n", HostAdapter, TargetID);
-		return SUCCESS;
-	}
-	/*
 	   Attempt to find an Active CCB for this Command.  If no Active CCB for this
 	   Command is found, then no Abort is necessary.
 	 */
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -260,7 +260,7 @@ config SCSI_3W_9XXX
 
 config SCSI_7000FASST
 	tristate "7000FASST SCSI support"
-	depends on ISA && SCSI
+	depends on ISA && SCSI && ISA_DMA_API
 	help
 	  This driver supports the Western Digital 7000 SCSI host adapter
 	  family.  Some information is in the source:
@@ -273,8 +273,8 @@ config SCSI_ACARD
 	tristate "ACARD SCSI support"
 	depends on PCI && SCSI
 	help
-	  This driver supports the ACARD 870U/W SCSI host adapter.
-
+	  This driver supports the ACARD SCSI host adapter.
+	  Support Chip <ATP870 ATP876 ATP880 ATP885>
 	  To compile this driver as a module, choose M here: the
 	  module will be called atp870u.
 
@@ -295,7 +295,7 @@ config SCSI_AHA152X
 
 config SCSI_AHA1542
 	tristate "Adaptec AHA1542 support"
-	depends on ISA && SCSI
+	depends on ISA && SCSI && ISA_DMA_API
 	---help---
 	  This is support for a SCSI host adapter.  It is explained in section
 	  3.4 of the SCSI-HOWTO, available from
@@ -515,7 +515,7 @@ config SCSI_SATA_VITESSE
 
 config SCSI_BUSLOGIC
 	tristate "BusLogic SCSI support"
-	depends on (PCI || ISA || MCA) && SCSI && (BROKEN || !SPARC64)
+	depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
 	---help---
 	  This is support for BusLogic MultiMaster and FlashPoint SCSI Host
 	  Adapters. Consult the SCSI-HOWTO, available from
@@ -571,7 +571,7 @@ config SCSI_DTC3280
 
 config SCSI_EATA
 	tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support"
-	depends on (ISA || EISA || PCI) && SCSI && (BROKEN || !SPARC64)
+	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
 	---help---
 	  This driver supports all EATA/DMA-compliant SCSI host adapters.  DPT
 	  ISA and all EISA I/O addresses are probed looking for the "EATA"
@@ -619,7 +619,7 @@ config SCSI_EATA_MAX_TAGS
 
 config SCSI_EATA_PIO
 	tristate "EATA-PIO (old DPT PM2001, PM2012A) support"
-	depends on (ISA || EISA || PCI) && SCSI
+	depends on (ISA || EISA || PCI) && SCSI && BROKEN
 	---help---
 	  This driver supports all EATA-PIO protocol compliant SCSI Host
 	  Adapters like the DPT PM2001 and the PM2012A.  EATA-DMA compliant
@@ -665,7 +665,7 @@ config SCSI_FD_MCS
 
 config SCSI_GDTH
 	tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
-	depends on (ISA || EISA || PCI) && SCSI && (BROKEN || !SPARC64)
+	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
 	---help---
 	  Formerly called GDT SCSI Disk Array Controller Support.
 
@@ -942,11 +942,6 @@ config SCSI_NCR_D700
 	  Unless you have an NCR manufactured machine, the chances are that
 	  you do not have this SCSI card, so say N.
 
-config 53C700_IO_MAPPED
-	bool
-	depends on SCSI_NCR_D700
-	default y
-
 config SCSI_LASI700
 	tristate "HP Lasi SCSI support for 53c700/710"
 	depends on GSC && SCSI
@@ -956,11 +951,6 @@ config SCSI_LASI700
 	  many PA-RISC workstations & servers.  If you do not know whether you
 	  have a Lasi chip, it is safe to say "Y" here.
 
-config 53C700_MEM_MAPPED
-	bool
-	depends on SCSI_LASI700
-	default y
-
 config 53C700_LE_ON_BE
 	bool
 	depends on SCSI_LASI700
@@ -1257,7 +1247,7 @@ config SCSI_QLOGIC_FAS
 
 config SCSI_QLOGIC_ISP
 	tristate "Qlogic ISP SCSI support (old driver)"
-	depends on PCI && SCSI
+	depends on PCI && SCSI && BROKEN
 	---help---
 	  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
 	  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
@@ -1324,6 +1314,14 @@ config SCSI_QLOGICPTI
 
 source "drivers/scsi/qla2xxx/Kconfig"
 
+config SCSI_LPFC
+	tristate "Emulex LightPulse Fibre Channel Support"
+	depends on PCI && SCSI
+	select SCSI_FC_ATTRS
+	help
+          This lpfc driver supports the Emulex LightPulse
+          Family of Fibre Channel PCI host adapters.
+
 config SCSI_SEAGATE
 	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
 	depends on X86 && ISA && SCSI && BROKEN
@@ -1418,7 +1416,7 @@ config SCSI_T128
 
 config SCSI_U14_34F
 	tristate "UltraStor 14F/34F support"
-	depends on ISA && SCSI
+	depends on ISA && SCSI && ISA_DMA_API
 	---help---
 	  This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
 	  The source at <file:drivers/scsi/u14-34f.c> contains some
@@ -1754,7 +1752,7 @@ config SCSI_NCR53C7xx_FAST
 
 config SUN3_SCSI
 	tristate "Sun3 NCR5380 SCSI"
-	depends on SUN3 && SCSI
+	depends on SUN3 && SCSI && BROKEN
 	help
 	  This option will enable support for the OBIO (onboard io) NCR5380
 	  SCSI controller found in the Sun 3/50 and 3/60, as well as for
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_SCSI_QLOGIC_ISP)	+= qlogici
 obj-$(CONFIG_SCSI_QLOGIC_FC)	+= qlogicfc.o 
 obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
 obj-$(CONFIG_SCSI_QLA2XXX)	+= qla2xxx/
+obj-$(CONFIG_SCSI_LPFC)		+= lpfc/
 obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
 obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
 obj-$(CONFIG_SCSI_FD_8xx)	+= seagate.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -86,6 +86,7 @@
  * 5.  Test linked command handling code after Eric is ready with 
  *      the high level code.
  */
+#include <scsi/scsi_dbg.h>
 
 #if (NDEBUG & NDEBUG_LISTS)
 #define LIST(x,y) {printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
@@ -533,7 +534,7 @@ static int should_disconnect(unsigned ch
 static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
 {
 	hostdata->time_expires = jiffies + timeout;
-	schedule_delayed_work(&hostdata->coroutine, hostdata->time_expires);
+	schedule_delayed_work(&hostdata->coroutine, timeout);
 }
 
 
@@ -671,16 +672,8 @@ static void __init NCR5380_print_options
 
 static void NCR5380_print_status(struct Scsi_Host *instance)
 {
-	static char pr_bfr[512];
-	char *start;
-	int len;
-
 	NCR5380_dprint(NDEBUG_ANY, instance);
 	NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
-	len = NCR5380_proc_info(instance, pr_bfr, &start, 0, sizeof(pr_bfr), 0);
-	pr_bfr[len] = 0;
-	printk("\n%s\n", pr_bfr);
 }
 
 /******************************************/
@@ -2379,7 +2372,7 @@ static void NCR5380_information_transfer
  * 3..length+1  arguments
  *
  * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since print_msg() wants the whole thing.  
+ * byte, since scsi_print_msg() wants the whole thing.  
  */
 					extended_msg[0] = EXTENDED_MESSAGE;
 					/* Accept first byte by clearing ACK */
@@ -2426,7 +2419,7 @@ static void NCR5380_information_transfer
 				default:
 					if (!tmp) {
 						printk("scsi%d: rejecting message ", instance->host_no);
-						print_msg(extended_msg);
+						scsi_print_msg(extended_msg);
 						printk("\n");
 					} else if (tmp != EXTENDED_MESSAGE)
 						printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->device->id, cmd->device->lun);
@@ -2560,7 +2553,7 @@ static void NCR5380_reselect(struct Scsi
 
 	if (!(msg[0] & 0x80)) {
 		printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
-		print_msg(msg);
+		scsi_print_msg(msg);
 		abort = 1;
 	} else {
 		/* Accept message by clearing ACK */
@@ -2685,12 +2678,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd
 	Scsi_Cmnd *tmp, **prev;
 	
 	printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
-	print_Scsi_Cmnd(cmd);
-
-	NCR5380_print_status(instance);
-
-	printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
-	print_Scsi_Cmnd(cmd);
+	scsi_print_command(cmd);
 
 	NCR5380_print_status(instance);
 
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -1824,7 +1824,10 @@ static int esp_do_data(struct NCR_ESP *e
 		/* loop */
 		while (hmuch) {
 			int j, fifo_stuck = 0, newphase;
-			unsigned long flags, timeout;
+			unsigned long timeout;
+#if 0
+			unsigned long flags;
+#endif
 #if 0
 			if ( i % 10 )
 				ESPDATA(("\r"));
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -97,6 +97,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mca.h>
+#include <linux/interrupt.h>
 #include <asm/io.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -106,7 +107,7 @@
 #include "53c700.h"
 #include "NCR_D700.h"
 
-char *NCR_D700;			/* command line from insmod */
+static char *NCR_D700;		/* command line from insmod */
 
 MODULE_AUTHOR("James Bottomley");
 MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
@@ -168,11 +169,13 @@ static struct scsi_host_template NCR_D70
 struct NCR_D700_private {
 	struct device		*dev;
 	struct Scsi_Host	*hosts[2];
+	char			name[30];
+	char			pad;
 };
 
 static int 
-NCR_D700_probe_one(struct NCR_D700_private *p, int siop,
-		int irq, int slot, u32 region, int differential)
+NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
+		   int slot, u32 region, int differential)
 {
 	struct NCR_700_Host_Parameters *hostdata;
 	struct Scsi_Host *host;
@@ -194,25 +197,24 @@ NCR_D700_probe_one(struct NCR_D700_priva
 	}
 		
 	/* Fill in the three required pieces of hostdata */
-	hostdata->base = region;
+	hostdata->base = ioport_map(region, 64);
 	hostdata->differential = (((1<<siop) & differential) != 0);
 	hostdata->clock = NCR_D700_CLOCK_MHZ;
 
-	NCR_700_set_io_mapped(hostdata);
-
 	/* and register the siop */
-	host = NCR_700_detect(&NCR_D700_driver_template, hostdata,
-			      p->dev, irq,
-			      /* FIXME: read this from SUS */
-			      id_array[slot * 2 + siop]);
+	host = NCR_700_detect(&NCR_D700_driver_template, hostdata, p->dev);
 	if (!host) {
 		ret = -ENOMEM;
 		goto detect_failed;
 	}
 
+	p->hosts[siop] = host;
+	/* FIXME: read this from SUS */
+	host->this_id = id_array[slot * 2 + siop];
+	host->irq = irq;
+	host->base = region;
 	scsi_scan_host(host);
 
-	p->hosts[siop] = host;
 	return 0;
 
  detect_failed:
@@ -223,6 +225,20 @@ NCR_D700_probe_one(struct NCR_D700_priva
 	return ret;
 }
 
+static int
+NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
+{
+	struct NCR_D700_private *p = (struct NCR_D700_private *)data;
+	int i, found = 0;
+
+	for (i = 0; i < 2; i++)
+		if (p->hosts[i] &&
+		    NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED)
+			found++;
+
+	return found ? IRQ_HANDLED : IRQ_NONE;
+}
+
 /* Detect a D700 card.  Note, because of the setup --- the chips are
  * essentially connectecd to the MCA bus independently, it is easier
  * to set them up as two separate host adapters, rather than one
@@ -301,13 +317,19 @@ NCR_D700_probe(struct device *dev)
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
+	memset(p, '\0', sizeof(*p));
 	p->dev = dev;
-
+	snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
+	if (request_irq(irq, NCR_D700_intr, SA_SHIRQ, p->name, p)) {
+		printk(KERN_ERR "D700: request_irq failed\n");
+		kfree(p);
+		return -EBUSY;
+	}
 	/* plumb in both 700 chips */
 	for (i = 0; i < 2; i++) {
 		int err;
 
-		if ((err = NCR_D700_probe_one(p, i, irq, slot,
+		if ((err = NCR_D700_probe_one(p, i, slot, irq,
 					      offset_addr + (0x80 * i),
 					      differential)) != 0)
 			printk("D700: SIOP%d: probe failed, error = %d\n",
@@ -352,7 +374,7 @@ NCR_D700_remove(struct device *dev)
 
 static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
 
-struct mca_driver NCR_D700_driver = {
+static struct mca_driver NCR_D700_driver = {
 	.id_table = NCR_D700_id_table,
 	.driver = {
 		.name		= "NCR_D700",
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -225,7 +225,7 @@ NCR_Q720_probe(struct device *dev)
 
 	/* The first 1k of the memory buffer is a memory map of the registers
 	 */
-	mem_base = (__u32)dma_mark_declared_memory_occupied(dev, base_addr,
+	mem_base = dma_mark_declared_memory_occupied(dev, base_addr,
 							    1024);
 	if (IS_ERR(mem_base)) {
 		printk("NCR_Q720 failed to reserve memory mapped region\n");
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -195,10 +195,12 @@ int aac_get_config_status(struct aac_dev
 		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
 		dprintk((KERN_WARNING
 		  "aac_get_config_status: response=%d status=%d action=%d\n",
-		  reply->response, reply->status, reply->data.action));
-		if ((reply->response != ST_OK)
-		 || (reply->status != CT_OK)
-		 || (reply->data.action > CFACT_PAUSE)) {
+		  le32_to_cpu(reply->response),
+		  le32_to_cpu(reply->status),
+		  le32_to_cpu(reply->data.action)));
+		if ((le32_to_cpu(reply->response) != ST_OK) ||
+		     (le32_to_cpu(reply->status) != CT_OK) ||
+		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
 			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
 			status = -EINVAL;
 		}
@@ -265,7 +267,7 @@ int aac_get_containers(struct aac_dev *d
 		    NULL, NULL);
 	if (status >= 0) {
 		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
-		maximum_num_containers = dresp->ContainerSwitchEntries;
+		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
 		fib_complete(fibptr);
 	}
 
@@ -624,25 +626,28 @@ int aac_get_adapter_info(struct aac_dev*
 
 	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", 
+	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+	printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d]\n", 
+			dev->name, 
+			dev->id,
+			tmp>>24,
+			(tmp>>16)&0xff,
+			tmp&0xff,
+			le32_to_cpu(dev->adapter_info.kernelbuild));
+	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+	printk(KERN_INFO "%s%d: monitor %d.%d-%d[%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", 
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.monitorbuild));
+	tmp = le32_to_cpu(dev->adapter_info.biosrev);
+	printk(KERN_INFO "%s%d: bios %d.%d-%d[%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", 
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.biosbuild));
+	if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+		printk(KERN_INFO "%s%d: serial %x\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]);
+			le32_to_cpu(dev->adapter_info.serial[0]));
 
 	dev->nondasd_support = 0;
 	dev->raid_scsi_mode = 0;
@@ -742,7 +747,8 @@ static void read_callback(void *context,
 	if (le32_to_cpu(readreply->status) == ST_OK)
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
 	else {
-		printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status);
+		printk(KERN_WARNING "read_callback: read failed, status = %d\n",
+				le32_to_cpu(readreply->status));
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
 				    HARDWARE_ERROR,
@@ -853,13 +859,15 @@ int aac_read(struct scsi_cmnd * scsicmd,
 		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); 
+		readcmd->pad   = 0;
+		readcmd->flags = 0; 
 
 		aac_build_sg64(scsicmd, &readcmd->sg);
-		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_read64) + ((readcmd->sg.count - 1) * sizeof (struct sgentry64));
+		fibsize = sizeof(struct aac_read64) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -882,9 +890,11 @@ int aac_read(struct scsi_cmnd * scsicmd,
 			BUG();
 
 		aac_build_sg(scsicmd, &readcmd->sg);
-		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
+		fibsize = sizeof(struct aac_read) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -903,10 +913,7 @@ int aac_read(struct scsi_cmnd * scsicmd,
 	 *	Check that the command queued to the controller
 	 */
 	if (status == -EINPROGRESS) 
-	{
-		dprintk("read queued.\n");
 		return 0;
-	}
 		
 	printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status);
 	/*
@@ -943,7 +950,8 @@ static int aac_write(struct scsi_cmnd * 
 		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_write[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n",
+	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	/*
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
@@ -961,13 +969,15 @@ static int aac_write(struct scsi_cmnd * 
 		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);
+		writecmd->pad	= 0;
+		writecmd->flags	= 0;
 
 		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));
+		fibsize = sizeof(struct aac_write64) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -993,9 +1003,11 @@ static int aac_write(struct scsi_cmnd * 
 		}
 
 		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));
+		fibsize = sizeof(struct aac_write) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -1051,7 +1063,7 @@ static void synchronize_callback(void *c
 		u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun);
 		printk(KERN_WARNING 
 		     "synchronize_callback: synchronize failed, status = %d\n",
-		     synchronizereply->status);
+		     le32_to_cpu(synchronizereply->status));
 		cmd->result = DID_OK << 16 | 
 			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
@@ -1538,7 +1550,8 @@ static void aac_srb_callback(void *conte
 	 *	Calculate resid for sg 
 	 */
 	 
-	scsicmd->resid = scsicmd->request_bufflen - srbreply->data_xfer_length;
+	scsicmd->resid = scsicmd->request_bufflen - 
+		le32_to_cpu(srbreply->data_xfer_length);
 
 	if(scsicmd->use_sg)
 		pci_unmap_sg(dev->pdev, 
@@ -1556,8 +1569,10 @@ static void aac_srb_callback(void *conte
 	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;
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) : 
+				le32_to_cpu(srbreply->sense_data_size);
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
 	}
@@ -1693,7 +1708,7 @@ static void aac_srb_callback(void *conte
 	default:
 #ifdef AAC_DETAILED_STATUS_INFO
 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
-			le32_to_cpu(srbreply->srb_status & 0x3F),
+			le32_to_cpu(srbreply->srb_status) & 0x3F,
 			aac_get_status_string(
 				le32_to_cpu(srbreply->srb_status) & 0x3F), 
 			scsicmd->cmnd[0], 
@@ -1705,8 +1720,10 @@ static void aac_srb_callback(void *conte
 	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
 		int len;
 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
-				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) :
+				le32_to_cpu(srbreply->sense_data_size);
 #ifdef AAC_DETAILED_STATUS_INFO
 		dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", 
 					le32_to_cpu(srbreply->status), len));
@@ -1786,7 +1803,7 @@ static int aac_send_srb_fib(struct scsi_
 		timeout = 1;
 	}
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
-	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->retry_limit = 0; /* Obsolete parameter */
 	srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
 	
 	if( dev->dac_support == 1 ) {
@@ -1798,13 +1815,19 @@ static int aac_send_srb_fib(struct scsi_
 		/*
 		 *	Build Scatter/Gather list
 		 */
-		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
+			((le32_to_cpu(srbcmd->sg.count) & 0xff) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 
 		/*
 		 *	Now send the Fib to the adapter
 		 */
-		status = fib_send(ScsiPortCommand64, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
-				  (fib_callback) aac_srb_callback, (void *) scsicmd);
+		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);
@@ -1814,7 +1837,11 @@ static int aac_send_srb_fib(struct scsi_
 		/*
 		 *	Build Scatter/Gather list
 		 */
-		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		fibsize = sizeof (struct aac_srb) + 
+			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
 
 		/*
 		 *	Now send the Fib to the adapter
@@ -1843,9 +1870,9 @@ static unsigned long aac_build_sg(struct
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	// Get rid of old data
-	psg->count = cpu_to_le32(0);
-	psg->sg[0].addr = cpu_to_le32(0);
-	psg->sg[0].count = cpu_to_le32(0);  
+	psg->count = 0;
+	psg->sg[0].addr = 0;
+	psg->sg[0].count = 0;  
 	if (scsicmd->use_sg) {
 		struct scatterlist *sg;
 		int i;
@@ -1899,10 +1926,10 @@ static unsigned long aac_build_sg64(stru
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	// Get rid of old data
-	psg->count = cpu_to_le32(0);
-	psg->sg[0].addr[0] = cpu_to_le32(0);
-	psg->sg[0].addr[1] = cpu_to_le32(0);
-	psg->sg[0].count = cpu_to_le32(0);  
+	psg->count = 0;
+	psg->sg[0].addr[0] = 0;
+	psg->sg[0].addr[1] = 0;
+	psg->sg[0].count = 0;
 	if (scsicmd->use_sg) {
 		struct scatterlist *sg;
 		int i;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -507,40 +507,32 @@ struct aac_queue_block
  */
  
 struct sa_drawbridge_CSR {
-						//	 Offset |	Name
-	u32	reserved[10];			//	00h-27h |   Reserved
-	u8	LUT_Offset;			//	28h	|	Looup Table Offset
-	u8	reserved1[3];			// 	29h-2bh	|	Reserved
-	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
-
-	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
-
-	//
-	//  TO DO
-	//	need to add DMA, I2O, UART, etc registers form 80h to 364h
-	//
-
+				/*	Offset 	|  Name */
+	__le32	reserved[10];	/*	00h-27h |  Reserved */
+	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
+	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
+	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
+	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
+	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
+	__le16	SECCLEARIRQ;	/*	9ah	|  Secondary Clear Irq */
+	__le16	PRISETIRQ;	/*	9ch	|  Primary Set Irq */
+	__le16	SECSETIRQ;	/*	9eh	|  Secondary Set Irq */
+	__le16	PRICLEARIRQMASK;/*	a0h	|  Primary Clear Irq Mask */
+	__le16	SECCLEARIRQMASK;/*	a2h	|  Secondary Clear Irq Mask */
+	__le16	PRISETIRQMASK;	/*	a4h	|  Primary Set Irq Mask */
+	__le16	SECSETIRQMASK;	/*	a6h	|  Secondary Set Irq Mask */
+	__le32	MAILBOX0;	/*	a8h	|  Scratchpad 0 */
+	__le32	MAILBOX1;	/*	ach	|  Scratchpad 1 */
+	__le32	MAILBOX2;	/*	b0h	|  Scratchpad 2 */
+	__le32	MAILBOX3;	/*	b4h	|  Scratchpad 3 */
+	__le32	MAILBOX4;	/*	b8h	|  Scratchpad 4 */
+	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
+	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
+	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
+	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
+	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
+	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
+	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
 };
 
 #define Mailbox0	SaDbCSR.MAILBOX0
@@ -556,13 +548,13 @@ struct sa_drawbridge_CSR {
 #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
 
 
-#define	DOORBELL_0	cpu_to_le16(0x0001)
-#define DOORBELL_1	cpu_to_le16(0x0002)
-#define DOORBELL_2	cpu_to_le16(0x0004)
-#define DOORBELL_3	cpu_to_le16(0x0008)
-#define DOORBELL_4	cpu_to_le16(0x0010)
-#define DOORBELL_5	cpu_to_le16(0x0020)
-#define DOORBELL_6	cpu_to_le16(0x0040)
+#define	DOORBELL_0	0x0001
+#define DOORBELL_1	0x0002
+#define DOORBELL_2	0x0004
+#define DOORBELL_3	0x0008
+#define DOORBELL_4	0x0010
+#define DOORBELL_5	0x0020
+#define DOORBELL_6	0x0040
 
 	
 #define PrintfReady	DOORBELL_5
@@ -585,25 +577,29 @@ struct sa_registers {
  */
 
 struct rx_mu_registers {
-						//	 Local	|   PCI*	|	Name
-						//			|		|
-	u32	ARSR;				//	1300h	|	00h	|	APIC Register Select Register
-	u32	reserved0;			//	1304h	|	04h	|	Reserved
-	u32	AWR;				//	1308h	|	08h	|	APIC Window Register
-	u32	reserved1;			//	130Ch	|	0Ch	|	Reserved
-	u32	IMRx[2];			//	1310h	|	10h	|	Inbound Message Registers
-	u32	OMRx[2];			//	1318h	|	18h	|	Outbound Message Registers
-	u32	IDR;				//	1320h	|	20h	|	Inbound Doorbell Register
-	u32	IISR;				//	1324h	|	24h	|	Inbound Interrupt Status Register
-	u32	IIMR;				//	1328h	|	28h	|	Inbound Interrupt Mask Register
-	u32	ODR;				//	132Ch	|	2Ch	|	Outbound Doorbell Register
-	u32	OISR;				//	1330h	|	30h	|	Outbound Interrupt Status Register
-	u32	OIMR;				//	1334h	|	34h	|	Outbound Interrupt Mask Register
-						// * Must access through ATU Inbound Translation Window
+			    /*	Local  | PCI*| Name */
+	__le32	ARSR;	    /*	1300h  | 00h | APIC Register Select Register */
+	__le32	reserved0;  /*	1304h  | 04h | Reserved */
+	__le32	AWR;	    /*	1308h  | 08h | APIC Window Register */
+	__le32	reserved1;  /*	130Ch  | 0Ch | Reserved */
+	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
+	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
+	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
+	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
+						Status Register */
+	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
+					 	Mask Register */
+	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
+	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
+						Status Register */
+	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
+						Mask Register */
+			    /* * Must access through ATU Inbound 
+			     	 Translation Window */
 };
 
 struct rx_inbound {
-	u32	Mailbox[8];
+	__le32	Mailbox[8];
 };
 
 #define	InboundMailbox0		IndexRegs.Mailbox[0]
@@ -613,28 +609,27 @@ struct rx_inbound {
 #define	InboundMailbox4		IndexRegs.Mailbox[4]
 #define	InboundMailbox5		IndexRegs.Mailbox[5]
 #define	InboundMailbox6		IndexRegs.Mailbox[6]
-#define	InboundMailbox7		IndexRegs.Mailbox[7]
 
-#define	INBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
-#define INBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
-#define INBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
-#define INBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
-#define INBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
-#define INBOUNDDOORBELL_5	cpu_to_le32(0x00000020)
-#define INBOUNDDOORBELL_6	cpu_to_le32(0x00000040)
-
-#define	OUTBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
-#define OUTBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
-#define OUTBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
-#define OUTBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
-#define OUTBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
+#define	INBOUNDDOORBELL_0	0x00000001
+#define INBOUNDDOORBELL_1	0x00000002
+#define INBOUNDDOORBELL_2	0x00000004
+#define INBOUNDDOORBELL_3	0x00000008
+#define INBOUNDDOORBELL_4	0x00000010
+#define INBOUNDDOORBELL_5	0x00000020
+#define INBOUNDDOORBELL_6	0x00000040
+
+#define	OUTBOUNDDOORBELL_0	0x00000001
+#define OUTBOUNDDOORBELL_1	0x00000002
+#define OUTBOUNDDOORBELL_2	0x00000004
+#define OUTBOUNDDOORBELL_3	0x00000008
+#define OUTBOUNDDOORBELL_4	0x00000010
 
 #define InboundDoorbellReg	MUnit.IDR
 #define OutboundDoorbellReg	MUnit.ODR
 
 struct rx_registers {
-	struct rx_mu_registers		MUnit;		// 1300h - 1334h
-	u32				reserved1[6];	// 1338h - 134ch
+	struct rx_mu_registers		MUnit;		/* 1300h - 1334h */
+	__le32				reserved1[6];	/* 1338h - 134ch */
 	struct rx_inbound		IndexRegs;
 };
 
@@ -652,7 +647,7 @@ struct rx_registers {
 
 struct rkt_registers {
 	struct rkt_mu_registers		MUnit;		 /* 1300h - 1334h */
-	u32				reserved1[1010]; /* 1338h - 22fch */
+	__le32				reserved1[1010]; /* 1338h - 22fch */
 	struct rkt_inbound		IndexRegs;	 /* 2300h - */
 };
 
@@ -824,6 +819,9 @@ struct aac_adapter_info
 #define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
 #define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
 #define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
+#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
+#define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
+#define AAC_OPT_NEW_COMM_64		cpu_to_le32(1<<18)
 
 struct aac_dev
 {
@@ -1482,15 +1480,19 @@ extern struct aac_common aac_config;
  *	Monitor/Kernel API
  */
 
-#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	COMMAND_POST_RESULTS		cpu_to_le32(0x00000014)
-#define GET_ADAPTER_PROPERTIES		cpu_to_le32(0x00000019)
-#define RE_INIT_ADAPTER			cpu_to_le32(0x000000ee)
+#define	BREAKPOINT_REQUEST		0x00000004
+#define	INIT_STRUCT_BASE_ADDRESS	0x00000005
+#define READ_PERMANENT_PARAMETERS	0x0000000a
+#define WRITE_PERMANENT_PARAMETERS	0x0000000b
+#define HOST_CRASHING			0x0000000d
+#define	SEND_SYNCHRONOUS_FIB		0x0000000c
+#define COMMAND_POST_RESULTS		0x00000014
+#define GET_ADAPTER_PROPERTIES		0x00000019
+#define GET_DRIVER_BUFFER_PROPERTIES	0x00000023
+#define RCV_TEMP_READINGS		0x00000025
+#define GET_COMM_PREFERRED_SETTINGS	0x00000026
+#define IOP_RESET			0x00001000
+#define RE_INIT_ADAPTER			0x000000ee
 
 /*
  *	Adapter Status Register
@@ -1513,22 +1515,22 @@ extern struct aac_common aac_config;
  *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
  */					
 
-#define	SELF_TEST_FAILED		(cpu_to_le32(0x00000004))
-#define MONITOR_PANIC			(cpu_to_le32(0x00000020))
-#define	KERNEL_UP_AND_RUNNING		(cpu_to_le32(0x00000080))
-#define	KERNEL_PANIC			(cpu_to_le32(0x00000100))
+#define	SELF_TEST_FAILED		0x00000004
+#define	MONITOR_PANIC			0x00000020
+#define	KERNEL_UP_AND_RUNNING		0x00000080
+#define	KERNEL_PANIC			0x00000100
 
 /*
  *	Doorbell bit defines
  */
 
-#define DoorBellSyncCmdAvailable	cpu_to_le32(1<<0)	// Host -> Adapter
-#define DoorBellPrintfDone		cpu_to_le32(1<<5)	// Host -> Adapter
-#define DoorBellAdapterNormCmdReady	cpu_to_le32(1<<1)	// Adapter -> Host
-#define DoorBellAdapterNormRespReady	cpu_to_le32(1<<2)	// Adapter -> Host
-#define DoorBellAdapterNormCmdNotFull	cpu_to_le32(1<<3)	// Adapter -> Host
-#define DoorBellAdapterNormRespNotFull	cpu_to_le32(1<<4)	// Adapter -> Host
-#define DoorBellPrintfReady		cpu_to_le32(1<<5)	// Adapter -> Host
+#define DoorBellSyncCmdAvailable	(1<<0)	/* Host -> Adapter */
+#define DoorBellPrintfDone		(1<<5)	/* Host -> Adapter */
+#define DoorBellAdapterNormCmdReady	(1<<1)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespReady	(1<<2)	/* Adapter -> Host */
+#define DoorBellAdapterNormCmdNotFull	(1<<3)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespNotFull	(1<<4)	/* Adapter -> Host */
+#define DoorBellPrintfReady		(1<<5)	/* Adapter -> Host */
 
 /*
  *	For FIB communication, we need all of the following things
@@ -1599,7 +1601,6 @@ void fib_dealloc(struct fib * context);
 void aac_printf(struct aac_dev *dev, u32 val);
 int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
-int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q);
 void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
 int fib_complete(struct fib * context);
 #define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -74,12 +74,14 @@ static int ioctl_send_fib(struct aac_dev
 	 *	will not overrun the buffer when we copy the memory. Return
 	 *	an error if we would.
 	 */
-	if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
+	if (le16_to_cpu(kfib->header.Size) > 
+			sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
 		fib_free(fibptr);
 		return -EINVAL;
 	}
 
-	if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) {
+	if (copy_from_user(kfib, arg, le16_to_cpu(kfib->header.Size) +
+				sizeof(struct aac_fibhdr))) {
 		fib_free(fibptr);
 		return -EFAULT;
 	}
@@ -93,7 +95,7 @@ static int ioctl_send_fib(struct aac_dev
 		kfib->header.XferState = 0;
 	} else {
 		int retval = fib_send(kfib->header.Command, fibptr,
-				le32_to_cpu(kfib->header.Size) , FsaNormal,
+				le16_to_cpu(kfib->header.Size) , FsaNormal,
 				1, 1, NULL, NULL);
 		if (retval) {
 			fib_free(fibptr);
@@ -538,7 +540,9 @@ int aac_send_raw_srb(struct aac_dev* dev
 		struct sgmap* psg = &srbcmd->sg;
 		byte_count = 0;
 
-		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		actual_fibsize = sizeof (struct aac_srb) + 
+			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+			 sizeof (struct sgentry));
 		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
 			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
 			rcode = -EINVAL;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -83,7 +83,7 @@ static int aac_alloc_comm(struct aac_dev
 	 */
 	dev->aif_base_va = (struct hw_fib *)base;
 	
-	init->AdapterFibsVirtualAddress = cpu_to_le32(0);
+	init->AdapterFibsVirtualAddress = 0;
 	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -102,7 +102,7 @@ int fib_setup(struct aac_dev * dev)
 		fibptr->next = fibptr+1;	/* Forward chain the fibs */
 		init_MUTEX_LOCKED(&fibptr->event_wait);
 		spin_lock_init(&fibptr->event_lock);
-		hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
+		hw_fib_va->header.XferState = 0xffffffff;
 		hw_fib_va->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
 		fibptr->hw_fib_pa = hw_fib_pa;
 		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + sizeof(struct hw_fib));
@@ -148,7 +148,7 @@ struct fib * fib_alloc(struct aac_dev *d
 	 *	Null out fields that depend on being zero at the start of
 	 *	each I/O
 	 */
-	fibptr->hw_fib->header.XferState = cpu_to_le32(0);
+	fibptr->hw_fib->header.XferState = 0;
 	fibptr->callback = NULL;
 	fibptr->callback_data = NULL;
 
@@ -175,7 +175,8 @@ void fib_free(struct fib * fibptr)
 	} else {
 		if (fibptr->hw_fib->header.XferState != 0) {
 			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
-				 (void*)fibptr, fibptr->hw_fib->header.XferState);
+				 (void*)fibptr, 
+				 le32_to_cpu(fibptr->hw_fib->header.XferState));
 		}
 		fibptr->next = fibptr->dev->free_fib;
 		fibptr->dev->free_fib = fibptr;
@@ -215,7 +216,7 @@ void fib_dealloc(struct fib * fibptr)
 	struct hw_fib *hw_fib = fibptr->hw_fib;
 	if(hw_fib->header.StructType != FIB_MAGIC) 
 		BUG();
-	hw_fib->header.XferState = cpu_to_le32(0);        
+	hw_fib->header.XferState = 0;        
 }
 
 /*
@@ -344,7 +345,7 @@ static int aac_queue_get(struct aac_dev 
 	 *	in the queue entry.
 	 */
 	if (map)
-		entry->addr = fibptr->hw_fib_pa;
+		entry->addr = cpu_to_le32(fibptr->hw_fib_pa);
 	return 0;
 }
 
@@ -418,13 +419,13 @@ int fib_send(u16 command, struct fib * f
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_queue * q;
 	unsigned long flags = 0;
-	if (!(le32_to_cpu(hw_fib->header.XferState) & HostOwned))
+	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
 		return -EBUSY;
 	/*
 	 *	There are 5 cases with the wait and reponse requested flags. 
 	 *	The only invalid cases are if the caller requests to wait and
 	 *	does not request a response and if the caller does not want a
-	 *	response and the Fibis not allocated from pool. If a response
+	 *	response and the Fib is not allocated from pool. If a response
 	 *	is not requesed the Fib will just be deallocaed by the DPC
 	 *	routine when the response comes back from the adapter. No
 	 *	further processing will be done besides deleting the Fib. We 
@@ -566,12 +567,6 @@ int aac_consumer_get(struct aac_dev * de
 	return(status);
 }
 
-int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q)
-{
-	return (le32_to_cpu(*q->headers.producer) != le32_to_cpu(*q->headers.consumer));
-}
-
-
 /**
  *	aac_consumer_free	-	free consumer entry
  *	@dev: Adapter
@@ -632,7 +627,7 @@ int fib_adapter_complete(struct fib * fi
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_dev * dev = fibptr->dev;
 	unsigned long nointr = 0;
-	if (le32_to_cpu(hw_fib->header.XferState) == 0)
+	if (hw_fib->header.XferState == 0)
         	return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
@@ -704,7 +699,7 @@ int fib_complete(struct fib * fibptr)
 	 *	Check for a fib which has already been completed
 	 */
 
-	if (hw_fib->header.XferState == cpu_to_le32(0))
+	if (hw_fib->header.XferState == 0)
         	return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -45,6 +45,7 @@
 #include <linux/syscalls.h>
 #include <linux/ioctl32.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include <asm/semaphore.h>
 
 #include <scsi/scsi.h>
@@ -191,28 +192,6 @@ static struct aac_driver_ident aac_drive
 	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec Rocket Catch All */
 };
 
-#ifdef CONFIG_COMPAT
-/* 
- * Promote 32 bit apps that call get_next_adapter_fib_ioctl to 64 bit version 
- */
-static int aac_get_next_adapter_fib_ioctl(unsigned int fd, unsigned int cmd, 
-		unsigned long arg, struct file *file)
-{
-	struct fib_ioctl __user *f;
-
-	f = compat_alloc_user_space(sizeof(*f));
-	if (!access_ok(VERIFY_WRITE, f, sizeof(*f)))
-		return -EFAULT;
-
-	clear_user(f, sizeof(*f));
-	if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
-		return -EFAULT;
-
-	return sys_ioctl(fd, cmd, (unsigned long)f);
-}
-#endif
-
-
 /**
  *	aac_queuecommand	-	queue a SCSI command
  *	@cmd:		SCSI command to queue
@@ -471,7 +450,7 @@ static int aac_cfg_open(struct inode *in
 		}
 	}
 
-	return 0;
+	return err;
 }
 
 /**
@@ -494,9 +473,65 @@ static int aac_cfg_ioctl(struct inode *i
 	return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
 }
 
+#ifdef CONFIG_COMPAT
+static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
+{
+	long ret;
+	lock_kernel();
+	switch (cmd) { 
+	case FSACTL_MINIPORT_REV_CHECK:
+	case FSACTL_SENDFIB:
+	case FSACTL_OPEN_GET_ADAPTER_FIB:
+	case FSACTL_CLOSE_GET_ADAPTER_FIB:
+	case FSACTL_SEND_RAW_SRB:
+	case FSACTL_GET_PCI_INFO:
+	case FSACTL_QUERY_DISK:
+	case FSACTL_DELETE_DISK:
+	case FSACTL_FORCE_DELETE_DISK:
+	case FSACTL_GET_CONTAINERS: 
+		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+
+	case FSACTL_GET_NEXT_ADAPTER_FIB: {
+		struct fib_ioctl __user *f;
+		
+		f = compat_alloc_user_space(sizeof(*f));
+		ret = 0;
+		if (clear_user(f, sizeof(*f) != sizeof(*f)))
+			ret = -EFAULT;
+		if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
+			ret = -EFAULT;
+		if (!ret)
+			ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+	}
+
+	default:
+		ret = -ENOIOCTLCMD; 
+		break;
+	} 
+	unlock_kernel();
+	return ret;
+}
+
+static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+	return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
+}
+
+static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
+}
+#endif
+
 static struct file_operations aac_cfg_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= aac_cfg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = aac_compat_cfg_ioctl,
+#endif
 	.open		= aac_cfg_open,
 };
 
@@ -506,6 +541,9 @@ static struct scsi_host_template aac_dri
 	.proc_name			= "aacraid",
 	.info           		= aac_info,
 	.ioctl          		= aac_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl			= aac_compat_ioctl,
+#endif
 	.queuecommand   		= aac_queuecommand,
 	.bios_param     		= aac_biosparm,	
 	.slave_configure		= aac_slave_configure,
@@ -535,10 +573,9 @@ static int __devinit aac_probe_one(struc
 	int unique_id = 0;
 
 	list_for_each_entry(aac, &aac_devices, entry) {
-		if (aac->id > unique_id) {
-			insert = &aac->entry;
+		if (aac->id > unique_id)
 			break;
-		}
+		insert = &aac->entry;
 		unique_id++;
 	}
 
@@ -699,39 +736,11 @@ static int __init aac_init(void)
 		printk(KERN_WARNING
 		       "aacraid: unable to register \"aac\" device.\n");
 	}
-#ifdef CONFIG_COMPAT
-	register_ioctl32_conversion(FSACTL_MINIPORT_REV_CHECK, NULL);
-	register_ioctl32_conversion(FSACTL_SENDFIB, NULL);
-	register_ioctl32_conversion(FSACTL_OPEN_GET_ADAPTER_FIB, NULL);
-	register_ioctl32_conversion(FSACTL_GET_NEXT_ADAPTER_FIB, 
-		aac_get_next_adapter_fib_ioctl);
-	register_ioctl32_conversion(FSACTL_CLOSE_GET_ADAPTER_FIB, NULL);
-	register_ioctl32_conversion(FSACTL_SEND_RAW_SRB, NULL);
-	register_ioctl32_conversion(FSACTL_GET_PCI_INFO, NULL);
-	register_ioctl32_conversion(FSACTL_QUERY_DISK, NULL);
-	register_ioctl32_conversion(FSACTL_DELETE_DISK, NULL);
-	register_ioctl32_conversion(FSACTL_FORCE_DELETE_DISK, NULL);
-	register_ioctl32_conversion(FSACTL_GET_CONTAINERS, NULL);
-#endif
-
 	return 0;
 }
 
 static void __exit aac_exit(void)
 {
-#ifdef CONFIG_COMPAT
-	unregister_ioctl32_conversion(FSACTL_MINIPORT_REV_CHECK);
-	unregister_ioctl32_conversion(FSACTL_SENDFIB);
-	unregister_ioctl32_conversion(FSACTL_OPEN_GET_ADAPTER_FIB);
-	unregister_ioctl32_conversion(FSACTL_GET_NEXT_ADAPTER_FIB);
-	unregister_ioctl32_conversion(FSACTL_CLOSE_GET_ADAPTER_FIB);
-	unregister_ioctl32_conversion(FSACTL_SEND_RAW_SRB);
-	unregister_ioctl32_conversion(FSACTL_GET_PCI_INFO);
-	unregister_ioctl32_conversion(FSACTL_QUERY_DISK);
-	unregister_ioctl32_conversion(FSACTL_DELETE_DISK);
-	unregister_ioctl32_conversion(FSACTL_FORCE_DELETE_DISK);
-	unregister_ioctl32_conversion(FSACTL_GET_CONTAINERS);
-#endif
 	unregister_chrdev(aac_cfg_major, "aac");
 	pci_unregister_driver(&aac_pci_driver);
 }
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -63,7 +63,7 @@ static irqreturn_t aac_rkt_intr(int irq,
 	{
 		bellbits = rkt_readl(dev, OutboundDoorbellReg);
 		if (bellbits & DoorBellPrintfReady) {
-			aac_printf(dev, le32_to_cpu(rkt_readl (dev, IndexRegs.Mailbox[5])));
+			aac_printf(dev, rkt_readl(dev, IndexRegs.Mailbox[5]));
 			rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
 			rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
 		}
@@ -94,7 +94,7 @@ static irqreturn_t aac_rkt_intr(int irq,
  *	@p1: first parameter
  *	@ret: adapter status
  *
- *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	This routine will send a synchronous command to the adapter and wait 
  *	for its	completion.
  */
 
@@ -105,11 +105,11 @@ static int rkt_sync_cmd(struct aac_dev *
 	/*
 	 *	Write the command into Mailbox 0
 	 */
-	rkt_writel(dev, InboundMailbox0, cpu_to_le32(command));
+	rkt_writel(dev, InboundMailbox0, command);
 	/*
 	 *	Write the parameters into Mailboxes 1 - 4
 	 */
-	rkt_writel(dev, InboundMailbox1, cpu_to_le32(p1));
+	rkt_writel(dev, InboundMailbox1, p1);
 	rkt_writel(dev, InboundMailbox2, 0);
 	rkt_writel(dev, InboundMailbox3, 0);
 	rkt_writel(dev, InboundMailbox4, 0);
@@ -168,7 +168,7 @@ static int rkt_sync_cmd(struct aac_dev *
 	 *	Pull the synch status from Mailbox 0.
 	 */
 	if (status)
-		*status = le32_to_cpu(rkt_readl(dev, IndexRegs.Mailbox[0]));
+		*status = rkt_readl(dev, IndexRegs.Mailbox[0]);
 	/*
 	 *	Clear the synch command doorbell.
 	 */
@@ -275,7 +275,7 @@ static void aac_rkt_start_adapter(struct
  */
 static int aac_rkt_check_health(struct aac_dev *dev)
 {
-	u32 status = le32_to_cpu(rkt_readl(dev, MUnit.OMRx[0]));
+	u32 status = rkt_readl(dev, MUnit.OMRx[0]);
 
 	/*
 	 *	Check to see if the board failed any self tests.
@@ -307,9 +307,9 @@ static int aac_rkt_check_health(struct a
 			return ret;
 		}
                 memset(buffer, 0, 512);
-                post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
+		post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
                 post->Post_Address = cpu_to_le32(baddr);
-                rkt_writel(dev, MUnit.IMRx[0], cpu_to_le32(paddr));
+                rkt_writel(dev, MUnit.IMRx[0], paddr);
                 rkt_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, &status);
 		pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
 		  post, paddr);
@@ -388,8 +388,9 @@ int aac_rkt_init(struct aac_dev *dev)
 	{
 		if(time_after(jiffies, start+180*HZ))
 		{
-			status = rkt_readl(dev, IndexRegs.Mailbox[7]) >> 16;
-			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status);
+			status = rkt_readl(dev, MUnit.OMRx[0]);
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					dev->name, instance, status);
 			goto error_iounmap;
 		}
 		set_current_state(TASK_UNINTERRUPTIBLE);
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -94,7 +94,7 @@ static irqreturn_t aac_rx_intr(int irq, 
  *	@p1: first parameter
  *	@ret: adapter status
  *
- *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	This routine will send a synchronous command to the adapter and wait 
  *	for its	completion.
  */
 
@@ -105,11 +105,11 @@ static int rx_sync_cmd(struct aac_dev *d
 	/*
 	 *	Write the command into Mailbox 0
 	 */
-	rx_writel(dev, InboundMailbox0, cpu_to_le32(command));
+	rx_writel(dev, InboundMailbox0, command);
 	/*
 	 *	Write the parameters into Mailboxes 1 - 4
 	 */
-	rx_writel(dev, InboundMailbox1, cpu_to_le32(p1));
+	rx_writel(dev, InboundMailbox1, p1);
 	rx_writel(dev, InboundMailbox2, 0);
 	rx_writel(dev, InboundMailbox3, 0);
 	rx_writel(dev, InboundMailbox4, 0);
@@ -167,7 +167,8 @@ static int rx_sync_cmd(struct aac_dev *d
 	/*
 	 *	Pull the synch status from Mailbox 0.
 	 */
-	*status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0]));
+	if (status)
+		*status = rx_readl(dev, IndexRegs.Mailbox[0]);
 	/*
 	 *	Clear the synch command doorbell.
 	 */
@@ -274,7 +275,7 @@ static void aac_rx_start_adapter(struct 
  */
 static int aac_rx_check_health(struct aac_dev *dev)
 {
-	u32 status = le32_to_cpu(rx_readl(dev, MUnit.OMRx[0]));
+	u32 status = rx_readl(dev, MUnit.OMRx[0]);
 
 	/*
 	 *	Check to see if the board failed any self tests.
@@ -308,7 +309,7 @@ static int aac_rx_check_health(struct aa
 		memset(buffer, 0, 512);
 		post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
 		post->Post_Address = cpu_to_le32(baddr);
-		rx_writel(dev, MUnit.IMRx[0], cpu_to_le32(paddr));
+		rx_writel(dev, MUnit.IMRx[0], paddr);
 		rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, &status);
 		pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
 		  post, paddr);
@@ -388,8 +389,9 @@ int aac_rx_init(struct aac_dev *dev)
 	{
 		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);
+			status = rx_readl(dev, IndexRegs.Mailbox[7]);
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					dev->name, instance, status);
 			goto error_iounmap;
 		}
 		set_current_state(TASK_UNINTERRUPTIBLE);
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -62,7 +62,7 @@ static irqreturn_t aac_sa_intr(int irq, 
 
 	if (intstat & mask) {
 		if (intstat & PrintfReady) {
-			aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5)));
+			aac_printf(dev, 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
@@ -128,7 +128,7 @@ void aac_sa_notify_adapter(struct aac_de
  *	@p1: first parameter
  *	@ret: adapter status
  *
- *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	This routine will send a synchronous command to the adapter and wait 
  *	for its	completion.
  */
 
@@ -139,11 +139,11 @@ static int sa_sync_cmd(struct aac_dev *d
 	/*
 	 *	Write the Command into Mailbox 0
 	 */
-	sa_writel(dev, Mailbox0, cpu_to_le32(command));
+	sa_writel(dev, Mailbox0, command);
 	/*
 	 *	Write the parameters into Mailboxes 1 - 4
 	 */
-	sa_writel(dev, Mailbox1, cpu_to_le32(p1));
+	sa_writel(dev, Mailbox1, p1);
 	sa_writel(dev, Mailbox2, 0);
 	sa_writel(dev, Mailbox3, 0);
 	sa_writel(dev, Mailbox4, 0);
@@ -186,7 +186,8 @@ static int sa_sync_cmd(struct aac_dev *d
 	/*
 	 *	Pull the synch status from Mailbox 0.
 	 */
-	*ret = le32_to_cpu(sa_readl(dev, Mailbox0));
+	if (ret)
+		*ret = sa_readl(dev, Mailbox0);
 	return 0;
 }
 
@@ -218,9 +219,8 @@ static void aac_sa_start_adapter(struct 
 	 * Fill in the remaining pieces of the init.
 	 */
 	init = dev->init;
-	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+	init->HostElapsedSeconds = cpu_to_le32(get_seconds());
 
-	dprintk(("INIT\n"));
 	/*
 	 * Tell the adapter we are back and up and running so it will scan its command
 	 * queues and enable our interrupts
@@ -230,10 +230,8 @@ static void aac_sa_start_adapter(struct 
 	 *	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);
 }
@@ -286,14 +284,12 @@ int aac_sa_init(struct aac_dev *dev)
 	int instance;
 	const char *name;
 
-	dprintk(("PREINST\n"));
 	instance = dev->id;
 	name     = dev->name;
 
 	/*
 	 *	Map in the registers from the adapter.
 	 */
-	dprintk(("PREMAP\n"));
 
 	if((dev->regs.sa = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
 	{	
@@ -320,15 +316,15 @@ int aac_sa_init(struct aac_dev *dev)
 	 */
 	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
 		if (time_after(jiffies, start+180*HZ)) {
-			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));
+			status = sa_readl(dev, Mailbox7);
+			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					name, instance, status);
 			goto error_iounmap;
 		}
 		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);
 		goto error_iounmap;
@@ -343,12 +339,10 @@ int aac_sa_init(struct aac_dev *dev)
 	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
 	dev->a_ops.adapter_check_health = aac_sa_check_health;
 
-	dprintk(("FUNCDONE\n"));
 
 	if(aac_init_adapter(dev) == NULL)
 		goto error_irq;
 
-	dprintk(("NEWADAPTDONE\n"));
 	/*
 	 *	Start any kernel threads needed
 	 */
@@ -362,9 +356,7 @@ int aac_sa_init(struct aac_dev *dev)
 	 *	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 --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -714,7 +714,7 @@
      Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
      patch and helped with PowerPC wide and narrow board support.
 
-     Philip Blundell <philip.blundell@pobox.com> provided an
+     Philip Blundell <philb@gnu.org> provided an
      advansys_interrupts_enabled patch.
 
      Dave Jones <dave@denial.force9.co.uk> reported the compiler
@@ -9198,16 +9198,13 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s)
         s->use_sg, s->sglist_len, s->abort_reason);
 
     printk(
-" serial_number 0x%x, serial_number_at_timeout 0x%x, retries %d, allowed %d\n",
-        (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
-         s->retries, s->allowed);
+" serial_number 0x%x, retries %d, allowed %d\n",
+        (unsigned) s->serial_number, s->retries, s->allowed);
 
     printk(
 " timeout_per_command %d, timeout_total %d, timeout %d\n",
         s->timeout_per_command, s->timeout_total, s->timeout);
 
-    printk(" internal_timeout %u\n", s->internal_timeout);
-
     printk(
 " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
         (ulong) s->scsi_done, (ulong) s->done,
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -257,6 +257,7 @@
 #include <scsi/scsicam.h>
 
 #include "scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include "aha152x.h"
 
@@ -986,7 +987,7 @@ static int aha152x_internal_queue(Scsi_C
 	if (HOSTDATA(shpnt)->debug & debug_queue) {
 		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
 		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
-		print_command(SCpnt->cmnd);
+		__scsi_print_command(SCpnt->cmnd);
 	}
 #endif
 
@@ -1560,7 +1561,7 @@ static void busfree_run(struct Scsi_Host
 #if 0
 			if(HOSTDATA(shpnt)->debug & debug_eh) {
 				printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
-				print_sense("bh", DONE_SC);
+				scsi_print_sense("bh", DONE_SC);
 			}
 #endif
 
@@ -1846,7 +1847,7 @@ static void msgi_run(struct Scsi_Host *s
 #if defined(AHA152X_DEBUG)
 		if (HOSTDATA(shpnt)->debug & debug_msgi) {
 			printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
-			print_msg(&MSGI(0));
+			scsi_print_msg(&MSGI(0));
 			printk("\n");
 		}
 #endif
@@ -1934,7 +1935,7 @@ static void msgi_run(struct Scsi_Host *s
 						break;
 
 					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
-					print_msg(&MSGI(0));
+					scsi_print_msg(&MSGI(0));
 					printk("\n");
 
 					ticks = (MSGI(3) * 4 + 49) / 50;
@@ -2032,7 +2033,7 @@ static void msgo_init(struct Scsi_Host *
 		int i;
 
 		printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
-		for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+		for (i=0; i<MSGOLEN; i+=scsi_print_msg(&MSGO(i)), printk(" "))
 			;
 		printk(")\n");
 	}
@@ -2104,7 +2105,7 @@ static void cmd_init(struct Scsi_Host *s
 #if defined(AHA152X_DEBUG)
 	if (HOSTDATA(shpnt)->debug & debug_cmd) {
 		printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
-		print_command(CURRENT_SC->cmnd);
+		__scsi_print_command(CURRENT_SC->cmnd);
 	}
 #endif
 
@@ -2158,7 +2159,7 @@ static void status_run(struct Scsi_Host 
 #if defined(AHA152X_DEBUG)
 	if (HOSTDATA(shpnt)->debug & debug_status) {
 		printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
-		print_status(CURRENT_SC->SCp.Status);
+		scsi_print_status(CURRENT_SC->SCp.Status);
 		printk("\n");
 	}
 #endif
@@ -2925,7 +2926,7 @@ static void show_command(Scsi_Cmnd *ptr)
 	printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
 	       (unsigned int) ptr, ptr->device->id, ptr->device->lun);
 
-	print_command(ptr->cmnd);
+	__scsi_print_command(ptr->cmnd);
 
 	printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
 	       ptr->request_bufflen, ptr->resid);
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/dma-mapping.h>
 #include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
@@ -177,6 +178,7 @@ static void ahci_eng_timeout(struct ata_
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
 static void ahci_host_stop(struct ata_host_set *host_set);
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
 static u8 ahci_check_err(struct ata_port *ap);
@@ -199,6 +201,7 @@ static Scsi_Host_Template ahci_sht = {
 	.dma_boundary		= AHCI_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations ahci_ops = {
@@ -209,6 +212,8 @@ static struct ata_port_operations ahci_o
 	.check_err		= ahci_check_err,
 	.dev_select		= ata_noop_dev_select,
 
+	.tf_read		= ahci_tf_read,
+
 	.phy_reset		= ahci_phy_reset,
 
 	.qc_prep		= ahci_qc_prep,
@@ -249,12 +254,16 @@ static struct pci_device_id ahci_pci_tbl
 	  board_ahci }, /* ICH7 */
 	{ PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_ahci }, /* ICH7M */
-	{ PCI_VENDOR_ID_INTEL, 0x27c2, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH7R */
 	{ PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_ahci }, /* ICH7R */
 	{ PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_ahci }, /* ULi M5288 */
+	{ PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ESB2 */
+	{ PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ESB2 */
+	{ PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ESB2 */
 	{ }	/* terminate list */
 };
 
@@ -281,6 +290,8 @@ static void ahci_host_stop(struct ata_ho
 {
 	struct ahci_host_priv *hpriv = host_set->private_data;
 	kfree(hpriv);
+
+	ata_host_stop(host_set);
 }
 
 static int ahci_port_start(struct ata_port *ap)
@@ -462,6 +473,14 @@ static u8 ahci_check_err(struct ata_port
 	return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
 }
 
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ahci_port_priv *pp = ap->private_data;
+	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+
+	ata_tf_from_fis(d2h_fis, tf);
+}
+
 static void ahci_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct ahci_port_priv *pp = qc->ap->private_data;
@@ -538,7 +557,7 @@ static void ahci_intr_error(struct ata_p
 
 	/* stop DMA */
 	tmp = readl(port_mmio + PORT_CMD);
-	tmp &= PORT_CMD_START | PORT_CMD_FIS_RX;
+	tmp &= ~PORT_CMD_START;
 	writel(tmp, port_mmio + PORT_CMD);
 
 	/* wait for engine to stop.  TODO: this could be
@@ -570,11 +589,11 @@ static void ahci_intr_error(struct ata_p
 
 	/* re-start DMA */
 	tmp = readl(port_mmio + PORT_CMD);
-	tmp |= PORT_CMD_START | PORT_CMD_FIS_RX;
+	tmp |= PORT_CMD_START;
 	writel(tmp, port_mmio + PORT_CMD);
 	readl(port_mmio + PORT_CMD); /* flush */
 
-	printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->port_no);
+	printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
 }
 
 static void ahci_eng_timeout(struct ata_port *ap)
@@ -766,10 +785,10 @@ static int ahci_host_init(struct ata_pro
 
 	using_dac = hpriv->cap & HOST_CAP_64;
 	if (using_dac &&
-	    !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
-		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (rc) {
-			rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 			if (rc) {
 				printk(KERN_ERR DRV_NAME "(%s): 64-bit DMA enable failed\n",
 					pci_name(pdev));
@@ -779,13 +798,13 @@ static int ahci_host_init(struct ata_pro
 
 		hpriv->flags |= HOST_CAP_64;
 	} else {
-		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n",
 				pci_name(pdev));
 			return rc;
 		}
-		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n",
 				pci_name(pdev));
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -5,6 +5,7 @@
 config SCSI_AIC7XXX
 	tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
 	depends on (PCI || EISA) && SCSI
+	select SCSI_SPI_ATTRS
 	---help---
 	This driver supports all of Adaptec's Fast through Ultra 160 PCI
 	based SCSI controllers as well as the aic7770 based EISA and VLB
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -41,7 +41,6 @@
 
 #include "aic7xxx_osm.h"
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 #include <linux/device.h>
 #include <linux/eisa.h>
 
@@ -62,13 +61,6 @@ static struct eisa_driver aic7770_driver
 };
 
 typedef  struct device *aic7770_dev_t;
-#else
-#define MINSLOT			1
-#define NUMSLOTS		16
-#define IDOFFSET		0x80
-
-typedef void *aic7770_dev_t;
-#endif
 
 static int aic7770_linux_config(struct aic7770_identity *entry,
 				aic7770_dev_t dev, u_int eisaBase);
@@ -76,7 +68,6 @@ static int aic7770_linux_config(struct a
 int
 ahc_linux_eisa_init(void)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	struct eisa_device_id *eid;
 	struct aic7770_identity *id;
 	int i;
@@ -110,44 +101,6 @@ ahc_linux_eisa_init(void)
 	eid->sig[0] = 0;
 
 	return eisa_driver_register(&aic7770_driver);
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */
-	struct aic7770_identity *entry;
-	u_int  slot;
-	u_int  eisaBase;
-	u_int  i;
-	int ret = -ENODEV;
-
-	if (aic7xxx_probe_eisa_vl == 0)
-		return ret;
-
-	eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
-	for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
-		uint32_t eisa_id;
-		size_t	 id_size;
-
-		if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0)
-			continue;
-
-		eisa_id = 0;
-		id_size = sizeof(eisa_id);
-		for (i = 0; i < 4; i++) {
-			/* VLcards require priming*/
-			outb(0x80 + i, eisaBase + IDOFFSET);
-			eisa_id |= inb(eisaBase + IDOFFSET + i)
-				   << ((id_size-i-1) * 8);
-		}
-		release_region(eisaBase, AHC_EISA_IOSIZE);
-		if (eisa_id & 0x80000000)
-			continue;  /* no EISA card in slot */
-
-		entry = aic7770_find_device(eisa_id);
-		if (entry != NULL) {
-			aic7770_linux_config(entry, NULL, eisaBase);
-			ret = 0;
-		}
-	}
-	return ret;
-#endif
 }
 
 void
@@ -187,11 +140,10 @@ aic7770_linux_config(struct aic7770_iden
 		ahc_free(ahc);
 		return (error);
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+
 	dev->driver_data = (void *)ahc;
 	if (aic7xxx_detect_complete)
 		error = ahc_linux_register_host(ahc, &aic7xxx_driver_template);
-#endif
 	return (error);
 }
 
@@ -225,7 +177,6 @@ aic7770_map_int(struct ahc_softc *ahc, u
 	return (-error);
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 static int
 aic7770_eisa_dev_probe(struct device *dev)
 {
@@ -261,4 +212,3 @@ aic7770_eisa_dev_remove(struct device *d
 
 	return (0);
 }
-#endif
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -687,7 +687,7 @@ ahd_linux_unmap_scb(struct ahd_softc *ah
 	int direction;
 
 	cmd = scb->io_ctx;
-	direction = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	direction = cmd->sc_data_direction;
 	ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);
 	if (cmd->use_sg != 0) {
 		struct scatterlist *sg;
@@ -2488,7 +2488,7 @@ ahd_linux_dv_thread(void *data)
 	sprintf(current->comm, "ahd_dv_%d", ahd->unit);
 #else
 	daemonize("ahd_dv_%d", ahd->unit);
-	current->flags |= PF_FREEZE;
+	current->flags |= PF_NOFREEZE;
 #endif
 	unlock_kernel();
 
@@ -3338,7 +3338,7 @@ ahd_linux_dv_inq(struct ahd_softc *ahd, 
 	}
 
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->sc_data_direction = DMA_FROM_DEVICE;
 	cmd->cmd_len = 6;
 	cmd->cmnd[0] = INQUIRY;
 	cmd->cmnd[4] = request_length;
@@ -3363,7 +3363,7 @@ ahd_linux_dv_tur(struct ahd_softc *ahd, 
 #endif
 	/* Do a TUR to clear out any non-fatal transitional state */
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->sc_data_direction = DMA_NONE;
 	cmd->cmd_len = 6;
 	cmd->cmnd[0] = TEST_UNIT_READY;
 }
@@ -3385,7 +3385,7 @@ ahd_linux_dv_rebd(struct ahd_softc *ahd,
 		free(targ->dv_buffer, M_DEVBUF);
 	targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK);
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->sc_data_direction = DMA_FROM_DEVICE;
 	cmd->cmd_len = 10;
 	cmd->cmnd[0] = READ_BUFFER;
 	cmd->cmnd[1] = 0x0b;
@@ -3407,7 +3407,7 @@ ahd_linux_dv_web(struct ahd_softc *ahd, 
 	}
 #endif
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_WRITE;
+	cmd->sc_data_direction = DMA_TO_DEVICE;
 	cmd->cmd_len = 10;
 	cmd->cmnd[0] = WRITE_BUFFER;
 	cmd->cmnd[1] = 0x0a;
@@ -3429,7 +3429,7 @@ ahd_linux_dv_reb(struct ahd_softc *ahd, 
 	}
 #endif
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->sc_data_direction = DMA_FROM_DEVICE;
 	cmd->cmd_len = 10;
 	cmd->cmnd[0] = READ_BUFFER;
 	cmd->cmnd[1] = 0x0a;
@@ -3455,7 +3455,7 @@ ahd_linux_dv_su(struct ahd_softc *ahd, s
 	}
 #endif
 	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->sc_data_direction = DMA_NONE;
 	cmd->cmd_len = 6;
 	cmd->cmnd[0] = START_STOP_UNIT;
 	cmd->cmnd[4] = le | SSS_START;
@@ -4018,7 +4018,7 @@ ahd_linux_run_device_queue(struct ahd_so
 			int	 dir;
 
 			cur_seg = (struct scatterlist *)cmd->request_buffer;
-			dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+			dir = cmd->sc_data_direction;
 			nseg = pci_map_sg(ahd->dev_softc, cur_seg,
 					  cmd->use_sg, dir);
 			scb->platform_data->xfer_len = 0;
@@ -4038,7 +4038,7 @@ ahd_linux_run_device_queue(struct ahd_so
 			int dir;
 
 			sg = scb->sg_list;
-			dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+			dir = cmd->sc_data_direction;
 			addr = pci_map_single(ahd->dev_softc,
 					      cmd->request_buffer,
 					      cmd->request_bufflen, dir);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -122,6 +122,10 @@
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
 #include <scsi/scsicam.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+static struct scsi_transport_template *ahc_linux_transport_template = NULL;
 
 /*
  * Include aiclib.c as part of our
@@ -130,11 +134,6 @@
 #include "aiclib.c"
 
 #include <linux/init.h>		/* __setup */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "sd.h"			/* For geometry detection */
-#endif
-
 #include <linux/mm.h>		/* For fetching system memory size */
 #include <linux/blkdev.h>		/* For block_size() */
 #include <linux/delay.h>	/* For ssleep/msleep */
@@ -144,11 +143,6 @@
  */
 spinlock_t ahc_list_spinlock;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/* For dynamic sglist size calculation. */
-u_int ahc_linux_nseg;
-#endif
-
 /*
  * Set this to the delay in seconds after SCSI bus reset.
  * Note, we honor this only for the initial bus reset.
@@ -271,39 +265,6 @@ static adapter_tag_info_t aic7xxx_tag_in
 };
 
 /*
- * DV option:
- *
- * positive value = DV Enabled
- * zero		  = DV Disabled
- * negative value = DV Default for adapter type/seeprom
- */
-#ifdef CONFIG_AIC7XXX_DV_SETTING
-#define AIC7XXX_CONFIGED_DV CONFIG_AIC7XXX_DV_SETTING
-#else
-#define AIC7XXX_CONFIGED_DV -1
-#endif
-
-static int8_t aic7xxx_dv_settings[] =
-{
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV,
-	AIC7XXX_CONFIGED_DV
-};
-
-/*
  * There should be a specific return value for this in scsi.h, but
  * it seems that most drivers ignore it.
  */
@@ -450,7 +411,6 @@ MODULE_PARM_DESC(aic7xxx,
 "	tag_info:<tag_str>	Set per-target tag depth\n"
 "	global_tag_depth:<int>	Global tag depth for every target\n"
 "				on every bus\n"
-"	dv:<dv_settings>	Set per-controller Domain Validation Setting.\n"
 "	seltime:<int>		Selection Timeout\n"
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "\n"
@@ -466,59 +426,14 @@ static void ahc_linux_handle_scsi_status
 					 struct ahc_linux_device *,
 					 struct scb *);
 static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
-					 Scsi_Cmnd *cmd);
-static void ahc_linux_filter_inquiry(struct ahc_softc*, struct ahc_devinfo*);
+					 struct scsi_cmnd *cmd);
 static void ahc_linux_sem_timeout(u_long arg);
 static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
 static void ahc_linux_release_simq(u_long arg);
-static void ahc_linux_dev_timed_unfreeze(u_long arg);
-static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
+static int  ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
-static void ahc_linux_size_nseg(void);
-static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc);
-static void ahc_linux_start_dv(struct ahc_softc *ahc);
-static void ahc_linux_dv_timeout(struct scsi_cmnd *cmd);
-static int  ahc_linux_dv_thread(void *data);
-static void ahc_linux_kill_dv_thread(struct ahc_softc *ahc);
-static void ahc_linux_dv_target(struct ahc_softc *ahc, u_int target);
-static void ahc_linux_dv_transition(struct ahc_softc *ahc,
-				    struct scsi_cmnd *cmd,
-				    struct ahc_devinfo *devinfo,
-				    struct ahc_linux_target *targ);
-static void ahc_linux_dv_fill_cmd(struct ahc_softc *ahc,
-				  struct scsi_cmnd *cmd,
-				  struct ahc_devinfo *devinfo);
-static void ahc_linux_dv_inq(struct ahc_softc *ahc,
-			     struct scsi_cmnd *cmd,
-			     struct ahc_devinfo *devinfo,
-			     struct ahc_linux_target *targ,
-			     u_int request_length);
-static void ahc_linux_dv_tur(struct ahc_softc *ahc,
-			     struct scsi_cmnd *cmd,
-			     struct ahc_devinfo *devinfo);
-static void ahc_linux_dv_rebd(struct ahc_softc *ahc,
-			      struct scsi_cmnd *cmd,
-			      struct ahc_devinfo *devinfo,
-			      struct ahc_linux_target *targ);
-static void ahc_linux_dv_web(struct ahc_softc *ahc,
-			     struct scsi_cmnd *cmd,
-			     struct ahc_devinfo *devinfo,
-			     struct ahc_linux_target *targ);
-static void ahc_linux_dv_reb(struct ahc_softc *ahc,
-			     struct scsi_cmnd *cmd,
-			     struct ahc_devinfo *devinfo,
-			     struct ahc_linux_target *targ);
-static void ahc_linux_dv_su(struct ahc_softc *ahc,
-			    struct scsi_cmnd *cmd,
-			    struct ahc_devinfo *devinfo,
-			    struct ahc_linux_target *targ);
-static int ahc_linux_fallback(struct ahc_softc *ahc,
-			      struct ahc_devinfo *devinfo);
-static void ahc_linux_dv_complete(Scsi_Cmnd *cmd);
-static void ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ);
 static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
 				     struct ahc_devinfo *devinfo);
-static u_int ahc_linux_user_dv_setting(struct ahc_softc *ahc);
 static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
 					 struct ahc_linux_device *dev);
 static struct ahc_linux_target*	ahc_linux_alloc_target(struct ahc_softc*,
@@ -530,55 +445,27 @@ static struct ahc_linux_device*	ahc_linu
 						       u_int);
 static void			ahc_linux_free_device(struct ahc_softc*,
 						      struct ahc_linux_device*);
-static void ahc_linux_run_device_queue(struct ahc_softc*,
-				       struct ahc_linux_device*);
+static int ahc_linux_run_command(struct ahc_softc*,
+				 struct ahc_linux_device *,
+				 struct scsi_cmnd *);
 static void ahc_linux_setup_tag_info_global(char *p);
 static aic_option_callback_t ahc_linux_setup_tag_info;
-static aic_option_callback_t ahc_linux_setup_dv;
 static int  aic7xxx_setup(char *s);
 static int  ahc_linux_next_unit(void);
-static void ahc_runq_tasklet(unsigned long data);
-static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc);
 
 /********************************* Inlines ************************************/
-static __inline void ahc_schedule_runq(struct ahc_softc *ahc);
 static __inline struct ahc_linux_device*
 		     ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
-					  u_int target, u_int lun, int alloc);
-static __inline void ahc_schedule_completeq(struct ahc_softc *ahc);
-static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc,
-						  struct ahc_linux_device *dev);
-static __inline struct ahc_linux_device *
-		     ahc_linux_next_device_to_run(struct ahc_softc *ahc);
-static __inline void ahc_linux_run_device_queues(struct ahc_softc *ahc);
+					  u_int target, u_int lun);
 static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
 
 static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
 		 		      struct ahc_dma_seg *sg,
 				      dma_addr_t addr, bus_size_t len);
 
-static __inline void
-ahc_schedule_completeq(struct ahc_softc *ahc)
-{
-	if ((ahc->platform_data->flags & AHC_RUN_CMPLT_Q_TIMER) == 0) {
-		ahc->platform_data->flags |= AHC_RUN_CMPLT_Q_TIMER;
-		ahc->platform_data->completeq_timer.expires = jiffies;
-		add_timer(&ahc->platform_data->completeq_timer);
-	}
-}
-
-/*
- * Must be called with our lock held.
- */
-static __inline void
-ahc_schedule_runq(struct ahc_softc *ahc)
-{
-	tasklet_schedule(&ahc->platform_data->runq_tasklet);
-}
-
 static __inline struct ahc_linux_device*
 ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
-		     u_int lun, int alloc)
+		     u_int lun)
 {
 	struct ahc_linux_target *targ;
 	struct ahc_linux_device *dev;
@@ -588,103 +475,15 @@ ahc_linux_get_device(struct ahc_softc *a
 	if (channel != 0)
 		target_offset += 8;
 	targ = ahc->platform_data->targets[target_offset];
-	if (targ == NULL) {
-		if (alloc != 0) {
-			targ = ahc_linux_alloc_target(ahc, channel, target);
-			if (targ == NULL)
-				return (NULL);
-		} else
-			return (NULL);
-	}
+	BUG_ON(targ == NULL);
 	dev = targ->devices[lun];
-	if (dev == NULL && alloc != 0)
-		dev = ahc_linux_alloc_device(ahc, targ, lun);
-	return (dev);
-}
-
-#define AHC_LINUX_MAX_RETURNED_ERRORS 4
-static struct ahc_cmd *
-ahc_linux_run_complete_queue(struct ahc_softc *ahc)
-{
-	struct	ahc_cmd *acmd;
-	u_long	done_flags;
-	int	with_errors;
-
-	with_errors = 0;
-	ahc_done_lock(ahc, &done_flags);
-	while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) {
-		Scsi_Cmnd *cmd;
-
-		if (with_errors > AHC_LINUX_MAX_RETURNED_ERRORS) {
-			/*
-			 * Linux uses stack recursion to requeue
-			 * commands that need to be retried.  Avoid
-			 * blowing out the stack by "spoon feeding"
-			 * commands that completed with error back
-			 * the operating system in case they are going
-			 * to be retried. "ick"
-			 */
-			ahc_schedule_completeq(ahc);
-			break;
-		}
-		TAILQ_REMOVE(&ahc->platform_data->completeq,
-			     acmd, acmd_links.tqe);
-		cmd = &acmd_scsi_cmd(acmd);
-		cmd->host_scribble = NULL;
-		if (ahc_cmd_get_transaction_status(cmd) != DID_OK
-		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
-			with_errors++;
-
-		cmd->scsi_done(cmd);
-	}
-	ahc_done_unlock(ahc, &done_flags);
-	return (acmd);
-}
-
-static __inline void
-ahc_linux_check_device_queue(struct ahc_softc *ahc,
-			     struct ahc_linux_device *dev)
-{
-	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0
-	 && dev->active == 0) {
-		dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY;
-		dev->qfrozen--;
-	}
-
-	if (TAILQ_FIRST(&dev->busyq) == NULL
-	 || dev->openings == 0 || dev->qfrozen != 0)
-		return;
-
-	ahc_linux_run_device_queue(ahc, dev);
-}
-
-static __inline struct ahc_linux_device *
-ahc_linux_next_device_to_run(struct ahc_softc *ahc)
-{
-	
-	if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0
-	 || (ahc->platform_data->qfrozen != 0
-	  && AHC_DV_SIMQ_FROZEN(ahc) == 0))
-		return (NULL);
-	return (TAILQ_FIRST(&ahc->platform_data->device_runq));
-}
-
-static __inline void
-ahc_linux_run_device_queues(struct ahc_softc *ahc)
-{
-	struct ahc_linux_device *dev;
-
-	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {
-		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
-		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
-		ahc_linux_check_device_queue(ahc, dev);
-	}
+	return dev;
 }
 
 static __inline void
 ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
 {
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 
 	cmd = scb->io_ctx;
 	ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE);
@@ -693,12 +492,12 @@ ahc_linux_unmap_scb(struct ahc_softc *ah
 
 		sg = (struct scatterlist *)cmd->request_buffer;
 		pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
-			     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			     cmd->sc_data_direction);
 	} else if (cmd->request_bufflen != 0) {
 		pci_unmap_single(ahc->dev_softc,
 				 scb->platform_data->buf_busaddr,
 				 cmd->request_bufflen,
-				 scsi_to_pci_dma_dir(cmd->sc_data_direction));
+				 cmd->sc_data_direction);
 	}
 }
 
@@ -724,109 +523,15 @@ ahc_linux_map_seg(struct ahc_softc *ahc,
 	return (consumed);
 }
 
-/************************  Host template entry points *************************/
-static int	   ahc_linux_detect(Scsi_Host_Template *);
-static int	   ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-static const char *ahc_linux_info(struct Scsi_Host *);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static int	   ahc_linux_slave_alloc(Scsi_Device *);
-static int	   ahc_linux_slave_configure(Scsi_Device *);
-static void	   ahc_linux_slave_destroy(Scsi_Device *);
-#if defined(__i386__)
-static int	   ahc_linux_biosparam(struct scsi_device*,
-				       struct block_device*,
-				       sector_t, int[]);
-#endif
-#else
-static int	   ahc_linux_release(struct Scsi_Host *);
-static void	   ahc_linux_select_queue_depth(struct Scsi_Host *host,
-						Scsi_Device *scsi_devs);
-#if defined(__i386__)
-static int	   ahc_linux_biosparam(Disk *, kdev_t, int[]);
-#endif
-#endif
-static int	   ahc_linux_bus_reset(Scsi_Cmnd *);
-static int	   ahc_linux_dev_reset(Scsi_Cmnd *);
-static int	   ahc_linux_abort(Scsi_Cmnd *);
-
-/*
- * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg).
- *
- * In pre-2.5.X...
- * The midlayer allocates an S/G array dynamically when a command is issued
- * using SCSI malloc.  This array, which is in an OS dependent format that
- * must later be copied to our private S/G list, is sized to house just the
- * number of segments needed for the current transfer.  Since the code that
- * sizes the SCSI malloc pool does not take into consideration fragmentation
- * of the pool, executing transactions numbering just a fraction of our
- * concurrent transaction limit with list lengths aproaching AHC_NSEG will
- * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
- * mid-layer does not properly handle this scsi malloc failures for the S/G
- * array and the result can be a lockup of the I/O subsystem.  We try to size
- * our S/G list so that it satisfies our drivers allocation requirements in
- * addition to avoiding fragmentation of the SCSI malloc pool.
- */
-static void
-ahc_linux_size_nseg(void)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	u_int cur_size;
-	u_int best_size;
-
-	/*
-	 * The SCSI allocator rounds to the nearest 512 bytes
-	 * an cannot allocate across a page boundary.  Our algorithm
-	 * is to start at 1K of scsi malloc space per-command and
-	 * loop through all factors of the PAGE_SIZE and pick the best.
-	 */
-	best_size = 0;
-	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
-		u_int nseg;
-
-		nseg = cur_size / sizeof(struct scatterlist);
-		if (nseg < AHC_LINUX_MIN_NSEG)
-			continue;
-
-		if (best_size == 0) {
-			best_size = cur_size;
-			ahc_linux_nseg = nseg;
-		} else {
-			u_int best_rem;
-			u_int cur_rem;
-
-			/*
-			 * Compare the traits of the current "best_size"
-			 * with the current size to determine if the
-			 * current size is a better size.
-			 */
-			best_rem = best_size % sizeof(struct scatterlist);
-			cur_rem = cur_size % sizeof(struct scatterlist);
-			if (cur_rem < best_rem) {
-				best_size = cur_size;
-				ahc_linux_nseg = nseg;
-			}
-		}
-	}
-#endif
-}
-
 /*
  * Try to detect an Adaptec 7XXX controller.
  */
 static int
-ahc_linux_detect(Scsi_Host_Template *template)
+ahc_linux_detect(struct scsi_host_template *template)
 {
 	struct	ahc_softc *ahc;
 	int     found = 0;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	/*
-	 * It is a bug that the upper layer takes
-	 * this lock just prior to calling us.
-	 */
-	spin_unlock_irq(&io_request_lock);
-#endif
-
 	/*
 	 * Sanity checking of Linux SCSI data structures so
 	 * that some of our hacks^H^H^H^H^Hassumptions aren't
@@ -838,7 +543,6 @@ ahc_linux_detect(Scsi_Host_Template *tem
 		printf("ahc_linux_detect: Unable to attach\n");
 		return (0);
 	}
-	ahc_linux_size_nseg();
 	/*
 	 * If we've been passed any parameters, process them now.
 	 */
@@ -867,48 +571,11 @@ ahc_linux_detect(Scsi_Host_Template *tem
 			found++;
 	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
 	aic7xxx_detect_complete++;
 
 	return (found);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/*
- * Free the passed in Scsi_Host memory structures prior to unloading the
- * module.
- */
-int
-ahc_linux_release(struct Scsi_Host * host)
-{
-	struct ahc_softc *ahc;
-	u_long l;
-
-	ahc_list_lock(&l);
-	if (host != NULL) {
-
-		/*
-		 * We should be able to just perform
-		 * the free directly, but check our
-		 * list for extra sanity.
-		 */
-		ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
-		if (ahc != NULL) {
-			u_long s;
-
-			ahc_lock(ahc, &s);
-			ahc_intr_enable(ahc, FALSE);
-			ahc_unlock(ahc, &s);
-			ahc_free(ahc);
-		}
-	}
-	ahc_list_unlock(&l);
-	return (0);
-}
-#endif
-
 /*
  * Return a string describing the driver.
  */
@@ -941,11 +608,10 @@ ahc_linux_info(struct Scsi_Host *host)
  * Queue an SCB to the controller.
  */
 static int
-ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
 {
 	struct	 ahc_softc *ahc;
 	struct	 ahc_linux_device *dev;
-	u_long	 flags;
 
 	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
 
@@ -954,201 +620,152 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*
 	 */
 	cmd->scsi_done = scsi_done;
 
-	ahc_midlayer_entrypoint_lock(ahc, &flags);
-
 	/*
 	 * Close the race of a command that was in the process of
 	 * being queued to us just as our simq was frozen.  Let
 	 * DV commands through so long as we are only frozen to
 	 * perform DV.
 	 */
-	if (ahc->platform_data->qfrozen != 0
-	 && AHC_DV_CMD(cmd) == 0) {
+	if (ahc->platform_data->qfrozen != 0)
+		return SCSI_MLQUEUE_HOST_BUSY;
 
-		ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
-		ahc_linux_queue_cmd_complete(ahc, cmd);
-		ahc_schedule_completeq(ahc);
-		ahc_midlayer_entrypoint_unlock(ahc, &flags);
-		return (0);
-	}
 	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
-				   cmd->device->lun, /*alloc*/TRUE);
-	if (dev == NULL) {
-		ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
-		ahc_linux_queue_cmd_complete(ahc, cmd);
-		ahc_schedule_completeq(ahc);
-		ahc_midlayer_entrypoint_unlock(ahc, &flags);
-		printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n",
-		       ahc_name(ahc));
-		return (0);
-	}
+				   cmd->device->lun);
+	BUG_ON(dev == NULL);
+
 	cmd->result = CAM_REQ_INPROG << 16;
-	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
-	if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
-		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
-		dev->flags |= AHC_DEV_ON_RUN_LIST;
-		ahc_linux_run_device_queues(ahc);
-	}
-	ahc_midlayer_entrypoint_unlock(ahc, &flags);
-	return (0);
+
+	return ahc_linux_run_command(ahc, dev, cmd);
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 static int
-ahc_linux_slave_alloc(Scsi_Device *device)
+ahc_linux_slave_alloc(struct scsi_device *device)
 {
 	struct	ahc_softc *ahc;
+	struct ahc_linux_target *targ;
+	struct scsi_target *starget = device->sdev_target;
+	struct ahc_linux_device *dev;
+	unsigned int target_offset;
+	unsigned long flags;
+	int retval = -ENOMEM;
+
+	target_offset = starget->id;
+	if (starget->channel != 0)
+		target_offset += 8;
 
 	ahc = *((struct ahc_softc **)device->host->hostdata);
 	if (bootverbose)
 		printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id);
-	return (0);
+	ahc_lock(ahc, &flags);
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL) {
+		struct seeprom_config *sc;
+
+		targ = ahc_linux_alloc_target(ahc, starget->channel,
+						starget->id);
+		sc = ahc->seep_config;
+		if (targ == NULL)
+			goto out;
+
+		if (sc) {
+			unsigned short scsirate;
+			struct ahc_devinfo devinfo;
+			struct ahc_initiator_tinfo *tinfo;
+			struct ahc_tmode_tstate *tstate;
+			char channel = starget->channel + 'A';
+			unsigned int our_id = ahc->our_id;
+
+			if (starget->channel)
+				our_id = ahc->our_id_b;
+
+			if ((ahc->features & AHC_ULTRA2) != 0) {
+				scsirate = sc->device_flags[target_offset] & CFXFER;
+			} else {
+				scsirate = (sc->device_flags[target_offset] & CFXFER) << 4;
+				if (sc->device_flags[target_offset] & CFSYNCH)
+					scsirate |= SOFS;
+			}
+			if (sc->device_flags[target_offset] & CFWIDEB) {
+				scsirate |= WIDEXFER;
+				spi_max_width(starget) = 1;
+			} else
+				spi_max_width(starget) = 0;
+			spi_min_period(starget) = 
+				ahc_find_period(ahc, scsirate, AHC_SYNCRATE_DT);
+			tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id,
+						    targ->target, &tstate);
+			ahc_compile_devinfo(&devinfo, our_id, targ->target,
+					    CAM_LUN_WILDCARD, channel,
+					    ROLE_INITIATOR);
+			ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0,
+					 AHC_TRANS_GOAL, /*paused*/FALSE);
+			ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHC_TRANS_GOAL, /*paused*/FALSE);
+		}
+			
+	}
+	dev = targ->devices[device->lun];
+	if (dev == NULL) {
+		dev = ahc_linux_alloc_device(ahc, targ, device->lun);
+		if (dev == NULL)
+			goto out;
+	}
+	retval = 0;
+
+ out:
+	ahc_unlock(ahc, &flags);
+	return retval;
 }
 
 static int
-ahc_linux_slave_configure(Scsi_Device *device)
+ahc_linux_slave_configure(struct scsi_device *device)
 {
 	struct	ahc_softc *ahc;
 	struct	ahc_linux_device *dev;
-	u_long	flags;
 
 	ahc = *((struct ahc_softc **)device->host->hostdata);
+
 	if (bootverbose)
 		printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id);
-	ahc_midlayer_entrypoint_lock(ahc, &flags);
-	/*
-	 * Since Linux has attached to the device, configure
-	 * it so we don't free and allocate the device
-	 * structure on every command.
-	 */
-	dev = ahc_linux_get_device(ahc, device->channel,
-				   device->id, device->lun,
-				   /*alloc*/TRUE);
-	if (dev != NULL) {
-		dev->flags &= ~AHC_DEV_UNCONFIGURED;
-		dev->scsi_device = device;
-		ahc_linux_device_queue_depth(ahc, dev);
-	}
-	ahc_midlayer_entrypoint_unlock(ahc, &flags);
-	return (0);
+
+	dev = ahc_linux_get_device(ahc, device->channel, device->id,
+				   device->lun);
+	dev->scsi_device = device;
+	ahc_linux_device_queue_depth(ahc, dev);
+
+	/* Initial Domain Validation */
+	if (!spi_initial_dv(device->sdev_target))
+		spi_dv_device(device);
+
+	return 0;
 }
 
 static void
-ahc_linux_slave_destroy(Scsi_Device *device)
+ahc_linux_slave_destroy(struct scsi_device *device)
 {
 	struct	ahc_softc *ahc;
 	struct	ahc_linux_device *dev;
-	u_long	flags;
 
 	ahc = *((struct ahc_softc **)device->host->hostdata);
 	if (bootverbose)
 		printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id);
-	ahc_midlayer_entrypoint_lock(ahc, &flags);
 	dev = ahc_linux_get_device(ahc, device->channel,
-				   device->id, device->lun,
-					   /*alloc*/FALSE);
-	/*
-	 * Filter out "silly" deletions of real devices by only
-	 * deleting devices that have had slave_configure()
-	 * called on them.  All other devices that have not
-	 * been configured will automatically be deleted by
-	 * the refcounting process.
-	 */
-	if (dev != NULL
-	 && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) {
-		dev->flags |= AHC_DEV_UNCONFIGURED;
-		if (TAILQ_EMPTY(&dev->busyq)
-		 && dev->active == 0
-	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
-			ahc_linux_free_device(ahc, dev);
-	}
-	ahc_midlayer_entrypoint_unlock(ahc, &flags);
-}
-#else
-/*
- * Sets the queue depth for each SCSI device hanging
- * off the input host adapter.
- */
-static void
-ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs)
-{
-	Scsi_Device *device;
-	Scsi_Device *ldev;
-	struct	ahc_softc *ahc;
-	u_long	flags;
-
-	ahc = *((struct ahc_softc **)host->hostdata);
-	ahc_lock(ahc, &flags);
-	for (device = scsi_devs; device != NULL; device = device->next) {
-
-		/*
-		 * Watch out for duplicate devices.  This works around
-		 * some quirks in how the SCSI scanning code does its
-		 * device management.
-		 */
-		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
-			if (ldev->host == device->host
-			 && ldev->channel == device->channel
-			 && ldev->id == device->id
-			 && ldev->lun == device->lun)
-				break;
-		}
-		/* Skip duplicate. */
-		if (ldev != device)
-			continue;
+				   device->id, device->lun);
 
-		if (device->host == host) {
-			struct	 ahc_linux_device *dev;
+	BUG_ON(dev->active);
 
-			/*
-			 * Since Linux has attached to the device, configure
-			 * it so we don't free and allocate the device
-			 * structure on every command.
-			 */
-			dev = ahc_linux_get_device(ahc, device->channel,
-						   device->id, device->lun,
-						   /*alloc*/TRUE);
-			if (dev != NULL) {
-				dev->flags &= ~AHC_DEV_UNCONFIGURED;
-				dev->scsi_device = device;
-				ahc_linux_device_queue_depth(ahc, dev);
-				device->queue_depth = dev->openings
-						    + dev->active;
-				if ((dev->flags & (AHC_DEV_Q_BASIC
-						| AHC_DEV_Q_TAGGED)) == 0) {
-					/*
-					 * We allow the OS to queue 2 untagged
-					 * transactions to us at any time even
-					 * though we can only execute them
-					 * serially on the controller/device.
-					 * This should remove some latency.
-					 */
-					device->queue_depth = 2;
-				}
-			}
-		}
-	}
-	ahc_unlock(ahc, &flags);
+	ahc_linux_free_device(ahc, dev);
 }
-#endif
 
 #if defined(__i386__)
 /*
  * Return the disk geometry for the given SCSI device.
  */
 static int
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 		    sector_t capacity, int geom[])
 {
 	uint8_t *bh;
-#else
-ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
-{
-	struct	scsi_device *sdev = disk->device;
-	u_long	capacity = disk->capacity;
-	struct	buffer_head *bh;
-#endif
 	int	 heads;
 	int	 sectors;
 	int	 cylinders;
@@ -1160,22 +777,11 @@ ahc_linux_biosparam(Disk *disk, kdev_t d
 	ahc = *((struct ahc_softc **)sdev->host->hostdata);
 	channel = sdev->channel;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	bh = scsi_bios_ptable(bdev);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
-#else
-	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
-#endif
-
 	if (bh) {
 		ret = scsi_partsize(bh, capacity,
 				    &geom[2], &geom[0], &geom[1]);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 		kfree(bh);
-#else
-		brelse(bh);
-#endif
 		if (ret != -1)
 			return (ret);
 	}
@@ -1205,7 +811,7 @@ ahc_linux_biosparam(Disk *disk, kdev_t d
  * Abort the current SCSI command(s).
  */
 static int
-ahc_linux_abort(Scsi_Cmnd *cmd)
+ahc_linux_abort(struct scsi_cmnd *cmd)
 {
 	int error;
 
@@ -1219,7 +825,7 @@ ahc_linux_abort(Scsi_Cmnd *cmd)
  * Attempt to send a target reset message to the device that timed out.
  */
 static int
-ahc_linux_dev_reset(Scsi_Cmnd *cmd)
+ahc_linux_dev_reset(struct scsi_cmnd *cmd)
 {
 	int error;
 
@@ -1233,18 +839,14 @@ ahc_linux_dev_reset(Scsi_Cmnd *cmd)
  * Reset the SCSI bus.
  */
 static int
-ahc_linux_bus_reset(Scsi_Cmnd *cmd)
+ahc_linux_bus_reset(struct scsi_cmnd *cmd)
 {
 	struct ahc_softc *ahc;
-	u_long s;
 	int    found;
 
 	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
-	ahc_midlayer_entrypoint_lock(ahc, &s);
 	found = ahc_reset_channel(ahc, cmd->device->channel + 'A',
 				  /*initiate reset*/TRUE);
-	ahc_linux_run_complete_queue(ahc);
-	ahc_midlayer_entrypoint_unlock(ahc, &s);
 
 	if (bootverbose)
 		printf("%s: SCSI bus reset delivered. "
@@ -1253,7 +855,7 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd)
 	return SUCCESS;
 }
 
-Scsi_Host_Template aic7xxx_driver_template = {
+struct scsi_host_template aic7xxx_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "aic7xxx",
 	.proc_info		= ahc_linux_proc_info,
@@ -1276,33 +878,6 @@ Scsi_Host_Template aic7xxx_driver_templa
 
 /**************************** Tasklet Handler *********************************/
 
-/*
- * In 2.4.X and above, this routine is called from a tasklet,
- * so we must re-acquire our lock prior to executing this code.
- * In all prior kernels, ahc_schedule_runq() calls this routine
- * directly and ahc_schedule_runq() is called with our lock held.
- */
-static void
-ahc_runq_tasklet(unsigned long data)
-{
-	struct ahc_softc* ahc;
-	struct ahc_linux_device *dev;
-	u_long flags;
-
-	ahc = (struct ahc_softc *)data;
-	ahc_lock(ahc, &flags);
-	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {
-	
-		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
-		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
-		ahc_linux_check_device_queue(ahc, dev);
-		/* Yeild to our interrupt handler */
-		ahc_unlock(ahc, &flags);
-		ahc_lock(ahc, &flags);
-	}
-	ahc_unlock(ahc, &flags);
-}
-
 /******************************** Macros **************************************/
 #define BUILD_SCSIID(ahc, cmd)						    \
 	((((cmd)->device->id << TID_SHIFT) & TID)			    \
@@ -1348,37 +923,11 @@ int
 ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr,
 		 int flags, bus_dmamap_t *mapp)
 {
-	bus_dmamap_t map;
-
-	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
-	if (map == NULL)
-		return (ENOMEM);
-	/*
-	 * Although we can dma data above 4GB, our
-	 * "consistent" memory is below 4GB for
-	 * space efficiency reasons (only need a 4byte
-	 * address).  For this reason, we have to reset
-	 * our dma mask when doing allocations.
-	 */
-	if (ahc->dev_softc != NULL)
-		if (pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF)) {
-			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
-			kfree(map);
-			return (ENODEV);
-		}
 	*vaddr = pci_alloc_consistent(ahc->dev_softc,
-				      dmat->maxsize, &map->bus_addr);
-	if (ahc->dev_softc != NULL)
-		if (pci_set_dma_mask(ahc->dev_softc,
-				     ahc->platform_data->hw_dma_mask)) {
-			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
-			kfree(map);
-			return (ENODEV);
-		}
+				      dmat->maxsize, mapp);
 	if (*vaddr == NULL)
-		return (ENOMEM);
-	*mapp = map;
-	return(0);
+		return ENOMEM;
+	return 0;
 }
 
 void
@@ -1386,7 +935,7 @@ ahc_dmamem_free(struct ahc_softc *ahc, b
 		void* vaddr, bus_dmamap_t map)
 {
 	pci_free_consistent(ahc->dev_softc, dmat->maxsize,
-			    vaddr, map->bus_addr);
+			    vaddr, map);
 }
 
 int
@@ -1400,7 +949,7 @@ ahc_dmamap_load(struct ahc_softc *ahc, b
 	 */
 	bus_dma_segment_t stack_sg;
 
-	stack_sg.ds_addr = map->bus_addr;
+	stack_sg.ds_addr = map;
 	stack_sg.ds_len = dmat->maxsize;
 	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
 	return (0);
@@ -1409,12 +958,6 @@ ahc_dmamap_load(struct ahc_softc *ahc, b
 void
 ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
 {
-	/*
-	 * The map may is NULL in our < 2.3.X implementation.
-	 * Now it's 2.6.5, but just in case...
-	 */
-	BUG_ON(map == NULL);
-	free(map, M_DEVBUF);
 }
 
 int
@@ -1545,18 +1088,6 @@ ahc_linux_setup_tag_info(u_long arg, int
 	}
 }
 
-static void
-ahc_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
-{
-
-	if ((instance >= 0)
-	 && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) {
-		aic7xxx_dv_settings[instance] = value;
-		if (bootverbose)
-			printf("dv[%d] = %d\n", instance, value);
-	}
-}
-
 /*
  * Handle Linux boot parameters. This routine allows for assigning a value
  * to a parameter with a ':' between the parameter and the value.
@@ -1616,9 +1147,6 @@ aic7xxx_setup(char *s)
 		} else if (strncmp(p, "tag_info", n) == 0) {
 			s = aic_parse_brace_option("tag_info", p + n, end,
 			    2, ahc_linux_setup_tag_info, 0);
-		} else if (strncmp(p, "dv", n) == 0) {
-			s = aic_parse_brace_option("dv", p + n, end, 1,
-			    ahc_linux_setup_dv, 0);
 		} else if (p[n] == ':') {
 			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
 		} else if (strncmp(p, "verbose", n) == 0) {
@@ -1635,13 +1163,12 @@ __setup("aic7xxx=", aic7xxx_setup);
 uint32_t aic7xxx_verbose;
 
 int
-ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
+ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *template)
 {
 	char	 buf[80];
 	struct	 Scsi_Host *host;
 	char	*new_name;
 	u_long	 s;
-	u_int	 targ_offset;
 
 	template->name = ahc->description;
 	host = scsi_host_alloc(template, sizeof(struct ahc_softc *));
@@ -1650,11 +1177,7 @@ ahc_linux_register_host(struct ahc_softc
 
 	*((struct ahc_softc **)host->hostdata) = ahc;
 	ahc_lock(ahc, &s);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	scsi_assign_lock(host, &ahc->platform_data->spin_lock);
-#elif AHC_SCSI_HAS_HOST_LOCK != 0
-	host->lock = &ahc->platform_data->spin_lock;
-#endif
 	ahc->platform_data->host = host;
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
@@ -1673,65 +1196,14 @@ ahc_linux_register_host(struct ahc_softc
 		ahc_set_name(ahc, new_name);
 	}
 	host->unique_id = ahc->unit;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	scsi_set_pci_device(host, ahc->dev_softc);
-#endif
 	ahc_linux_initialize_scsi_bus(ahc);
-	ahc_unlock(ahc, &s);
-	ahc->platform_data->dv_pid = kernel_thread(ahc_linux_dv_thread, ahc, 0);
-	ahc_lock(ahc, &s);
-	if (ahc->platform_data->dv_pid < 0) {
-		printf("%s: Failed to create DV thread, error= %d\n",
-		       ahc_name(ahc), ahc->platform_data->dv_pid);
-		return (-ahc->platform_data->dv_pid);
-	}
-	/*
-	 * Initially allocate *all* of our linux target objects
-	 * so that the DV thread will scan them all in parallel
-	 * just after driver initialization.  Any device that
-	 * does not exist will have its target object destroyed
-	 * by the selection timeout handler.  In the case of a
-	 * device that appears after the initial DV scan, async
-	 * negotiation will occur for the first command, and DV
-	 * will comence should that first command be successful.
-	 */
-	for (targ_offset = 0;
-	     targ_offset < host->max_id * (host->max_channel + 1);
-	     targ_offset++) {
-		u_int channel;
-		u_int target;
-
-		channel = 0;
-		target = targ_offset;
-		if (target > 7
-		 && (ahc->features & AHC_TWIN) != 0) {
-			channel = 1;
-			target &= 0x7;
-		}
-		/*
-		 * Skip our own ID.  Some Compaq/HP storage devices
-		 * have enclosure management devices that respond to
-		 * single bit selection (i.e. selecting ourselves).
-		 * It is expected that either an external application
-		 * or a modified kernel will be used to probe this
-		 * ID if it is appropriate.  To accommodate these
-		 * installations, ahc_linux_alloc_target() will allocate
-		 * for our ID if asked to do so.
-		 */
-		if ((channel == 0 && target == ahc->our_id)
-		 || (channel == 1 && target == ahc->our_id_b))
-			continue;
-
-		ahc_linux_alloc_target(ahc, channel, target);
-	}
 	ahc_intr_enable(ahc, TRUE);
-	ahc_linux_start_dv(ahc);
 	ahc_unlock(ahc, &s);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	host->transportt = ahc_linux_transport_template;
+
 	scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */
 	scsi_scan_host(host);
-#endif
 	return (0);
 }
 
@@ -1849,21 +1321,9 @@ ahc_platform_alloc(struct ahc_softc *ahc
 	if (ahc->platform_data == NULL)
 		return (ENOMEM);
 	memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
-	TAILQ_INIT(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->device_runq);
 	ahc->platform_data->irq = AHC_LINUX_NOIRQ;
-	ahc->platform_data->hw_dma_mask = 0xFFFFFFFF;
 	ahc_lockinit(ahc);
-	ahc_done_lockinit(ahc);
-	init_timer(&ahc->platform_data->completeq_timer);
-	ahc->platform_data->completeq_timer.data = (u_long)ahc;
-	ahc->platform_data->completeq_timer.function =
-	    (ahc_linux_callback_t *)ahc_linux_thread_run_complete_queue;
 	init_MUTEX_LOCKED(&ahc->platform_data->eh_sem);
-	init_MUTEX_LOCKED(&ahc->platform_data->dv_sem);
-	init_MUTEX_LOCKED(&ahc->platform_data->dv_cmd_sem);
-	tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet,
-		     (unsigned long)ahc);
 	ahc->seltime = (aic7xxx_seltime & 0x3) << 4;
 	ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4;
 	if (aic7xxx_pci_parity == 0)
@@ -1880,13 +1340,8 @@ ahc_platform_free(struct ahc_softc *ahc)
 	int i, j;
 
 	if (ahc->platform_data != NULL) {
-		del_timer_sync(&ahc->platform_data->completeq_timer);
-		ahc_linux_kill_dv_thread(ahc);
-		tasklet_kill(&ahc->platform_data->runq_tasklet);
 		if (ahc->platform_data->host != NULL) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 			scsi_remove_host(ahc->platform_data->host);
-#endif
 			scsi_host_put(ahc->platform_data->host);
 		}
 
@@ -1922,16 +1377,7 @@ ahc_platform_free(struct ahc_softc *ahc)
 			release_mem_region(ahc->platform_data->mem_busaddr,
 					   0x1000);
 		}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		/*
-		 * In 2.4 we detach from the scsi midlayer before the PCI
-		 * layer invokes our remove callback.  No per-instance
-		 * detach is provided, so we must reach inside the PCI
-		 * subsystem's internals and detach our driver manually.
-		 */
-		if (ahc->dev_softc != NULL)
-			ahc->dev_softc->driver = NULL;
-#endif
+
 		free(ahc->platform_data, M_DEVBUF);
 	}
 }
@@ -1955,7 +1401,7 @@ ahc_platform_set_tags(struct ahc_softc *
 
 	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
 				   devinfo->target,
-				   devinfo->lun, /*alloc*/FALSE);
+				   devinfo->lun);
 	if (dev == NULL)
 		return;
 	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
@@ -2008,7 +1454,6 @@ ahc_platform_set_tags(struct ahc_softc *
 		dev->maxtags = 0;
 		dev->openings =  1 - dev->active;
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	if (dev->scsi_device != NULL) {
 		switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
 		case AHC_DEV_Q_BASIC:
@@ -2034,1422 +1479,20 @@ ahc_platform_set_tags(struct ahc_softc *
 			break;
 		}
 	}
-#endif
 }
 
 int
 ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel,
 			int lun, u_int tag, role_t role, uint32_t status)
 {
-	int chan;
-	int maxchan;
-	int targ;
-	int maxtarg;
-	int clun;
-	int maxlun;
-	int count;
+	return 0;
+}
 
-	if (tag != SCB_LIST_NULL)
-		return (0);
-
-	chan = 0;
-	if (channel != ALL_CHANNELS) {
-		chan = channel - 'A';
-		maxchan = chan + 1;
-	} else {
-		maxchan = (ahc->features & AHC_TWIN) ? 2 : 1;
-	}
-	targ = 0;
-	if (target != CAM_TARGET_WILDCARD) {
-		targ = target;
-		maxtarg = targ + 1;
-	} else {
-		maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8;
-	}
-	clun = 0;
-	if (lun != CAM_LUN_WILDCARD) {
-		clun = lun;
-		maxlun = clun + 1;
-	} else {
-		maxlun = AHC_NUM_LUNS;
-	}
-
-	count = 0;
-	for (; chan < maxchan; chan++) {
-
-		for (; targ < maxtarg; targ++) {
-
-			for (; clun < maxlun; clun++) {
-				struct ahc_linux_device *dev;
-				struct ahc_busyq *busyq;
-				struct ahc_cmd *acmd;
-
-				dev = ahc_linux_get_device(ahc, chan,
-							   targ, clun,
-							   /*alloc*/FALSE);
-				if (dev == NULL)
-					continue;
-
-				busyq = &dev->busyq;
-				while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
-					Scsi_Cmnd *cmd;
-
-					cmd = &acmd_scsi_cmd(acmd);
-					TAILQ_REMOVE(busyq, acmd,
-						     acmd_links.tqe);
-					count++;
-					cmd->result = status << 16;
-					ahc_linux_queue_cmd_complete(ahc, cmd);
-				}
-			}
-		}
-	}
-
-	return (count);
-}
-
-static void
-ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc)
-{
-	u_long flags;
-
-	ahc_lock(ahc, &flags);
-	del_timer(&ahc->platform_data->completeq_timer);
-	ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER;
-	ahc_linux_run_complete_queue(ahc);
-	ahc_unlock(ahc, &flags);
-}
-
-static void
-ahc_linux_start_dv(struct ahc_softc *ahc)
-{
-
-	/*
-	 * Freeze the simq and signal ahc_linux_queue to not let any
-	 * more commands through.
-	 */
-	if ((ahc->platform_data->flags & AHC_DV_ACTIVE) == 0) {
-#ifdef AHC_DEBUG
-		if (ahc_debug & AHC_SHOW_DV)
-			printf("%s: Waking DV thread\n", ahc_name(ahc));
-#endif
-
-		ahc->platform_data->flags |= AHC_DV_ACTIVE;
-		ahc_linux_freeze_simq(ahc);
-
-		/* Wake up the DV kthread */
-		up(&ahc->platform_data->dv_sem);
-	}
-}
-
-static void
-ahc_linux_kill_dv_thread(struct ahc_softc *ahc)
-{
-	u_long s;
-
-	ahc_lock(ahc, &s);
-	if (ahc->platform_data->dv_pid != 0) {
-		ahc->platform_data->flags |= AHC_DV_SHUTDOWN;
-		ahc_unlock(ahc, &s);
-		up(&ahc->platform_data->dv_sem);
-
-		/*
-		 * Use the eh_sem as an indicator that the
-		 * dv thread is exiting.  Note that the dv
-		 * thread must still return after performing
-		 * the up on our semaphore before it has
-		 * completely exited this module.  Unfortunately,
-		 * there seems to be no easy way to wait for the
-		 * exit of a thread for which you are not the
-		 * parent (dv threads are parented by init).
-		 * Cross your fingers...
-		 */
-		down(&ahc->platform_data->eh_sem);
-
-		/*
-		 * Mark the dv thread as already dead.  This
-		 * avoids attempting to kill it a second time.
-		 * This is necessary because we must kill the
-		 * DV thread before calling ahc_free() in the
-		 * module shutdown case to avoid bogus locking
-		 * in the SCSI mid-layer, but we ahc_free() is
-		 * called without killing the DV thread in the
-		 * instance detach case, so ahc_platform_free()
-		 * calls us again to verify that the DV thread
-		 * is dead.
-		 */
-		ahc->platform_data->dv_pid = 0;
-	} else {
-		ahc_unlock(ahc, &s);
-	}
-}
-
-static int
-ahc_linux_dv_thread(void *data)
-{
-	struct	ahc_softc *ahc;
-	int	target;
-	u_long	s;
-
-	ahc = (struct ahc_softc *)data;
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV)
-		printf("Launching DV Thread\n");
-#endif
-
-	/*
-	 * Complete thread creation.
-	 */
-	lock_kernel();
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	/*
-	 * Don't care about any signals.
-	 */
-	siginitsetinv(&current->blocked, 0);
-
-	daemonize();
-	sprintf(current->comm, "ahc_dv_%d", ahc->unit);
-#else
-	daemonize("ahc_dv_%d", ahc->unit);
-	current->flags |= PF_FREEZE;
-#endif
-	unlock_kernel();
-
-	while (1) {
-		/*
-		 * Use down_interruptible() rather than down() to
-		 * avoid inclusion in the load average.
-		 */
-		down_interruptible(&ahc->platform_data->dv_sem);
-
-		/* Check to see if we've been signaled to exit */
-		ahc_lock(ahc, &s);
-		if ((ahc->platform_data->flags & AHC_DV_SHUTDOWN) != 0) {
-			ahc_unlock(ahc, &s);
-			break;
-		}
-		ahc_unlock(ahc, &s);
-
-#ifdef AHC_DEBUG
-		if (ahc_debug & AHC_SHOW_DV)
-			printf("%s: Beginning Domain Validation\n",
-			       ahc_name(ahc));
-#endif
-
-		/*
-		 * Wait for any pending commands to drain before proceeding.
-		 */
-		ahc_lock(ahc, &s);
-		while (LIST_FIRST(&ahc->pending_scbs) != NULL) {
-			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_EMPTY;
-			ahc_unlock(ahc, &s);
-			down_interruptible(&ahc->platform_data->dv_sem);
-			ahc_lock(ahc, &s);
-		}
-
-		/*
-		 * Wait for the SIMQ to be released so that DV is the
-		 * only reason the queue is frozen.
-		 */
-		while (AHC_DV_SIMQ_FROZEN(ahc) == 0) {
-			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE;
-			ahc_unlock(ahc, &s);
-			down_interruptible(&ahc->platform_data->dv_sem);
-			ahc_lock(ahc, &s);
-		}
-		ahc_unlock(ahc, &s);
-
-		for (target = 0; target < AHC_NUM_TARGETS; target++)
-			ahc_linux_dv_target(ahc, target);
-
-		ahc_lock(ahc, &s);
-		ahc->platform_data->flags &= ~AHC_DV_ACTIVE;
-		ahc_unlock(ahc, &s);
-
-		/*
-		 * Release the SIMQ so that normal commands are
-		 * allowed to continue on the bus.
-		 */
-		ahc_linux_release_simq((u_long)ahc);
-	}
-	up(&ahc->platform_data->eh_sem);
-	return (0);
-}
-
-#define AHC_LINUX_DV_INQ_SHORT_LEN	36
-#define AHC_LINUX_DV_INQ_LEN		256
-#define AHC_LINUX_DV_TIMEOUT		(HZ / 4)
-
-#define AHC_SET_DV_STATE(ahc, targ, newstate) \
-	ahc_set_dv_state(ahc, targ, newstate, __LINE__)
-
-static __inline void
-ahc_set_dv_state(struct ahc_softc *ahc, struct ahc_linux_target *targ,
-		 ahc_dv_state newstate, u_int line)
-{
-	ahc_dv_state oldstate;
-
-	oldstate = targ->dv_state;
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV)
-		printf("%s:%d: Going from state %d to state %d\n",
-		       ahc_name(ahc), line, oldstate, newstate);
-#endif
-
-	if (oldstate == newstate)
-		targ->dv_state_retry++;
-	else
-		targ->dv_state_retry = 0;
-	targ->dv_state = newstate;
-}
-
-static void
-ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
-{
-	struct	 ahc_devinfo devinfo;
-	struct	 ahc_linux_target *targ;
-	struct	 scsi_cmnd *cmd;
-	struct	 scsi_device *scsi_dev;
-	struct	 scsi_sense_data *sense;
-	uint8_t *buffer;
-	u_long	 s;
-	u_int	 timeout;
-	int	 echo_size;
-
-	sense = NULL;
-	buffer = NULL;
-	echo_size = 0;
-	ahc_lock(ahc, &s);
-	targ = ahc->platform_data->targets[target_offset];
-	if (targ == NULL || (targ->flags & AHC_DV_REQUIRED) == 0) {
-		ahc_unlock(ahc, &s);
-		return;
-	}
-	ahc_compile_devinfo(&devinfo,
-			    targ->channel == 0 ? ahc->our_id : ahc->our_id_b,
-			    targ->target, /*lun*/0, targ->channel + 'A',
-			    ROLE_INITIATOR);
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, &devinfo);
-		printf("Performing DV\n");
-	}
-#endif
-
-	ahc_unlock(ahc, &s);
-
-	cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
-	scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK);
-	scsi_dev->host = ahc->platform_data->host;
-	scsi_dev->id = devinfo.target;
-	scsi_dev->lun = devinfo.lun;
-	scsi_dev->channel = devinfo.channel - 'A';
-	ahc->platform_data->dv_scsi_dev = scsi_dev;
-
-	AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_SHORT_ASYNC);
-
-	while (targ->dv_state != AHC_DV_STATE_EXIT) {
-		timeout = AHC_LINUX_DV_TIMEOUT;
-		switch (targ->dv_state) {
-		case AHC_DV_STATE_INQ_SHORT_ASYNC:
-		case AHC_DV_STATE_INQ_ASYNC:
-		case AHC_DV_STATE_INQ_ASYNC_VERIFY:
-			/*
-			 * Set things to async narrow to reduce the
-			 * chance that the INQ will fail.
-			 */
-			ahc_lock(ahc, &s);
-			ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0,
-					 AHC_TRANS_GOAL, /*paused*/FALSE);
-			ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
-				      AHC_TRANS_GOAL, /*paused*/FALSE);
-			ahc_unlock(ahc, &s);
-			timeout = 10 * HZ;
-			targ->flags &= ~AHC_INQ_VALID;
-			/* FALLTHROUGH */
-		case AHC_DV_STATE_INQ_VERIFY:
-		{
-			u_int inq_len;
-
-			if (targ->dv_state == AHC_DV_STATE_INQ_SHORT_ASYNC)
-				inq_len = AHC_LINUX_DV_INQ_SHORT_LEN;
-			else
-				inq_len = targ->inq_data->additional_length + 5;
-			ahc_linux_dv_inq(ahc, cmd, &devinfo, targ, inq_len);
-			break;
-		}
-		case AHC_DV_STATE_TUR:
-		case AHC_DV_STATE_BUSY:
-			timeout = 5 * HZ;
-			ahc_linux_dv_tur(ahc, cmd, &devinfo);
-			break;
-		case AHC_DV_STATE_REBD:
-			ahc_linux_dv_rebd(ahc, cmd, &devinfo, targ);
-			break;
-		case AHC_DV_STATE_WEB:
-			ahc_linux_dv_web(ahc, cmd, &devinfo, targ);
-			break;
-
-		case AHC_DV_STATE_REB:
-			ahc_linux_dv_reb(ahc, cmd, &devinfo, targ);
-			break;
-
-		case AHC_DV_STATE_SU:
-			ahc_linux_dv_su(ahc, cmd, &devinfo, targ);
-			timeout = 50 * HZ;
-			break;
-
-		default:
-			ahc_print_devinfo(ahc, &devinfo);
-			printf("Unknown DV state %d\n", targ->dv_state);
-			goto out;
-		}
-
-		/* Queue the command and wait for it to complete */
-		/* Abuse eh_timeout in the scsi_cmnd struct for our purposes */
-		init_timer(&cmd->eh_timeout);
-#ifdef AHC_DEBUG
-		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
-			/*
-			 * All of the printfs during negotiation
-			 * really slow down the negotiation.
-			 * Add a bit of time just to be safe.
-			 */
-			timeout += HZ;
-#endif
-		scsi_add_timer(cmd, timeout, ahc_linux_dv_timeout);
-		/*
-		 * In 2.5.X, it is assumed that all calls from the
-		 * "midlayer" (which we are emulating) will have the
-		 * ahc host lock held.  For other kernels, the
-		 * io_request_lock must be held.
-		 */
-#if AHC_SCSI_HAS_HOST_LOCK != 0
-		ahc_lock(ahc, &s);
-#else
-		spin_lock_irqsave(&io_request_lock, s);
-#endif
-		ahc_linux_queue(cmd, ahc_linux_dv_complete);
-#if AHC_SCSI_HAS_HOST_LOCK != 0
-		ahc_unlock(ahc, &s);
-#else
-		spin_unlock_irqrestore(&io_request_lock, s);
-#endif
-		down_interruptible(&ahc->platform_data->dv_cmd_sem);
-		/*
-		 * Wait for the SIMQ to be released so that DV is the
-		 * only reason the queue is frozen.
-		 */
-		ahc_lock(ahc, &s);
-		while (AHC_DV_SIMQ_FROZEN(ahc) == 0) {
-			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE;
-			ahc_unlock(ahc, &s);
-			down_interruptible(&ahc->platform_data->dv_sem);
-			ahc_lock(ahc, &s);
-		}
-		ahc_unlock(ahc, &s);
-
-		ahc_linux_dv_transition(ahc, cmd, &devinfo, targ);
-	}
-
-out:
-	if ((targ->flags & AHC_INQ_VALID) != 0
-	 && ahc_linux_get_device(ahc, devinfo.channel - 'A',
-				 devinfo.target, devinfo.lun,
-				 /*alloc*/FALSE) == NULL) {
-		/*
-		 * The DV state machine failed to configure this device.  
-		 * This is normal if DV is disabled.  Since we have inquiry
-		 * data, filter it and use the "optimistic" negotiation
-		 * parameters found in the inquiry string.
-		 */
-		ahc_linux_filter_inquiry(ahc, &devinfo);
-		if ((targ->flags & (AHC_BASIC_DV|AHC_ENHANCED_DV)) != 0) {
-			ahc_print_devinfo(ahc, &devinfo);
-			printf("DV failed to configure device.  "
-			       "Please file a bug report against "
-			       "this driver.\n");
-		}
-	}
-
-	if (cmd != NULL)
-		free(cmd, M_DEVBUF);
-
-	if (ahc->platform_data->dv_scsi_dev != NULL) {
-		free(ahc->platform_data->dv_scsi_dev, M_DEVBUF);
-		ahc->platform_data->dv_scsi_dev = NULL;
-	}
-
-	ahc_lock(ahc, &s);
-	if (targ->dv_buffer != NULL) {
-		free(targ->dv_buffer, M_DEVBUF);
-		targ->dv_buffer = NULL;
-	}
-	if (targ->dv_buffer1 != NULL) {
-		free(targ->dv_buffer1, M_DEVBUF);
-		targ->dv_buffer1 = NULL;
-	}
-	targ->flags &= ~AHC_DV_REQUIRED;
-	if (targ->refcount == 0)
-		ahc_linux_free_target(ahc, targ);
-	ahc_unlock(ahc, &s);
-}
-
-static void
-ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-			struct ahc_devinfo *devinfo,
-			struct ahc_linux_target *targ)
-{
-	u_int32_t status;
-
-	status = aic_error_action(cmd, targ->inq_data,
-				  ahc_cmd_get_transaction_status(cmd),
-				  ahc_cmd_get_scsi_status(cmd));
-	
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Entering ahc_linux_dv_transition, state= %d, "
-		       "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state,
-		       status, cmd->result);
-	}
-#endif
-
-	switch (targ->dv_state) {
-	case AHC_DV_STATE_INQ_SHORT_ASYNC:
-	case AHC_DV_STATE_INQ_ASYNC:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		{
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1);
-			break;
-		}
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_TUR:
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ)
-				targ->dv_state_retry--;
-			if ((status & SS_ERRMASK) == EBUSY)
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
-			if (targ->dv_state_retry < 10)
-				break;
-			/* FALLTHROUGH */
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("Failed DV inquiry, skipping\n");
-			}
-#endif
-			break;
-		}
-		break;
-	case AHC_DV_STATE_INQ_ASYNC_VERIFY:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		{
-			u_int xportflags;
-			u_int spi3data;
-
-			if (memcmp(targ->inq_data, targ->dv_buffer,
-				   AHC_LINUX_DV_INQ_LEN) != 0) {
-				/*
-				 * Inquiry data must have changed.
-				 * Try from the top again.
-				 */
-				AHC_SET_DV_STATE(ahc, targ,
-						 AHC_DV_STATE_INQ_SHORT_ASYNC);
-				break;
-			}
-
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1);
-			targ->flags |= AHC_INQ_VALID;
-			if (ahc_linux_user_dv_setting(ahc) == 0)
-				break;
-
-			xportflags = targ->inq_data->flags;
-			if ((xportflags & (SID_Sync|SID_WBus16)) == 0)
-				break;
-
-			spi3data = targ->inq_data->spi3data;
-			switch (spi3data & SID_SPI_CLOCK_DT_ST) {
-			default:
-			case SID_SPI_CLOCK_ST:
-				/* Assume only basic DV is supported. */
-				targ->flags |= AHC_BASIC_DV;
-				break;
-			case SID_SPI_CLOCK_DT:
-			case SID_SPI_CLOCK_DT_ST:
-				targ->flags |= AHC_ENHANCED_DV;
-				break;
-			}
-			break;
-		}
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_TUR:
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ)
-				targ->dv_state_retry--;
-
-			if ((status & SS_ERRMASK) == EBUSY)
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
-			if (targ->dv_state_retry < 10)
-				break;
-			/* FALLTHROUGH */
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("Failed DV inquiry, skipping\n");
-			}
-#endif
-			break;
-		}
-		break;
-	case AHC_DV_STATE_INQ_VERIFY:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		{
-
-			if (memcmp(targ->inq_data, targ->dv_buffer,
-				   AHC_LINUX_DV_INQ_LEN) == 0) {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-				break;
-			}
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				int i;
-
-				ahc_print_devinfo(ahc, devinfo);
-				printf("Inquiry buffer mismatch:");
-				for (i = 0; i < AHC_LINUX_DV_INQ_LEN; i++) {
-					if ((i & 0xF) == 0)
-						printf("\n        ");
-					printf("0x%x:0x0%x ",
-					       ((uint8_t *)targ->inq_data)[i], 
-					       targ->dv_buffer[i]);
-				}
-				printf("\n");
-			}
-#endif
-
-			if (ahc_linux_fallback(ahc, devinfo) != 0) {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-				break;
-			}
-			/*
-			 * Do not count "falling back"
-			 * against our retries.
-			 */
-			targ->dv_state_retry = 0;
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			break;
-		}
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_TUR:
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ) {
-				targ->dv_state_retry--;
-			} else if ((status & SSQ_FALLBACK) != 0) {
-				if (ahc_linux_fallback(ahc, devinfo) != 0) {
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_EXIT);
-					break;
-				}
-				/*
-				 * Do not count "falling back"
-				 * against our retries.
-				 */
-				targ->dv_state_retry = 0;
-			} else if ((status & SS_ERRMASK) == EBUSY)
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
-			if (targ->dv_state_retry < 10)
-				break;
-			/* FALLTHROUGH */
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("Failed DV inquiry, skipping\n");
-			}
-#endif
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_TUR:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-			if ((targ->flags & AHC_BASIC_DV) != 0) {
-				ahc_linux_filter_inquiry(ahc, devinfo);
-				AHC_SET_DV_STATE(ahc, targ,
-						 AHC_DV_STATE_INQ_VERIFY);
-			} else if ((targ->flags & AHC_ENHANCED_DV) != 0) {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REBD);
-			} else {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			}
-			break;
-		case SS_RETRY:
-		case SS_TUR:
-			if ((status & SS_ERRMASK) == EBUSY) {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
-				break;
-			}
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ) {
-				targ->dv_state_retry--;
-			} else if ((status & SSQ_FALLBACK) != 0) {
-				if (ahc_linux_fallback(ahc, devinfo) != 0) {
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_EXIT);
-					break;
-				}
-				/*
-				 * Do not count "falling back"
-				 * against our retries.
-				 */
-				targ->dv_state_retry = 0;
-			}
-			if (targ->dv_state_retry >= 10) {
-#ifdef AHC_DEBUG
-				if (ahc_debug & AHC_SHOW_DV) {
-					ahc_print_devinfo(ahc, devinfo);
-					printf("DV TUR reties exhausted\n");
-				}
-#endif
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-				break;
-			}
-			if (status & SSQ_DELAY)
-				ssleep(1);
-
-			break;
-		case SS_START:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_SU);
-			break;
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_REBD:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		{
-			uint32_t echo_size;
-
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB);
-			echo_size = scsi_3btoul(&targ->dv_buffer[1]);
-			echo_size &= 0x1FFF;
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("Echo buffer size= %d\n", echo_size);
-			}
-#endif
-			if (echo_size == 0) {
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-				break;
-			}
-
-			/* Generate the buffer pattern */
-			targ->dv_echo_size = echo_size;
-			ahc_linux_generate_dv_pattern(targ);
-			/*
-			 * Setup initial negotiation values.
-			 */
-			ahc_linux_filter_inquiry(ahc, devinfo);
-			break;
-		}
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ)
-				targ->dv_state_retry--;
-			if (targ->dv_state_retry <= 10)
-				break;
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("DV REBD reties exhausted\n");
-			}
-#endif
-			/* FALLTHROUGH */
-		case SS_FATAL:
-		default:
-			/*
-			 * Setup initial negotiation values
-			 * and try level 1 DV.
-			 */
-			ahc_linux_filter_inquiry(ahc, devinfo);
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_VERIFY);
-			targ->dv_echo_size = 0;
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_WEB:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REB);
-			break;
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ) {
-				targ->dv_state_retry--;
-			} else if ((status & SSQ_FALLBACK) != 0) {
-				if (ahc_linux_fallback(ahc, devinfo) != 0) {
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_EXIT);
-					break;
-				}
-				/*
-				 * Do not count "falling back"
-				 * against our retries.
-				 */
-				targ->dv_state_retry = 0;
-			}
-			if (targ->dv_state_retry <= 10)
-				break;
-			/* FALLTHROUGH */
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("DV WEB reties exhausted\n");
-			}
-#endif
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_REB:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-			if (memcmp(targ->dv_buffer, targ->dv_buffer1,
-				   targ->dv_echo_size) != 0) {
-				if (ahc_linux_fallback(ahc, devinfo) != 0)
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_EXIT);
-				else
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_WEB);
-				break;
-			}
-			
-			if (targ->dv_buffer != NULL) {
-				free(targ->dv_buffer, M_DEVBUF);
-				targ->dv_buffer = NULL;
-			}
-			if (targ->dv_buffer1 != NULL) {
-				free(targ->dv_buffer1, M_DEVBUF);
-				targ->dv_buffer1 = NULL;
-			}
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ) {
-				targ->dv_state_retry--;
-			} else if ((status & SSQ_FALLBACK) != 0) {
-				if (ahc_linux_fallback(ahc, devinfo) != 0) {
-					AHC_SET_DV_STATE(ahc, targ,
-							 AHC_DV_STATE_EXIT);
-					break;
-				}
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB);
-			}
-			if (targ->dv_state_retry <= 10) {
-				if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0)
-					msleep(ahc->our_id*1000/10);
-				break;
-			}
-#ifdef AHC_DEBUG
-			if (ahc_debug & AHC_SHOW_DV) {
-				ahc_print_devinfo(ahc, devinfo);
-				printf("DV REB reties exhausted\n");
-			}
-#endif
-			/* FALLTHROUGH */
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_SU:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		}
-		break;
-
-	case AHC_DV_STATE_BUSY:
-		switch (status & SS_MASK) {
-		case SS_NOP:
-		case SS_INQ_REFRESH:
-			AHC_SET_DV_STATE(ahc, targ,
-					 AHC_DV_STATE_INQ_SHORT_ASYNC);
-			break;
-		case SS_TUR:
-		case SS_RETRY:
-			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
-			if (ahc_cmd_get_transaction_status(cmd)
-			 == CAM_REQUEUE_REQ) {
-				targ->dv_state_retry--;
-			} else if (targ->dv_state_retry < 60) {
-				if ((status & SSQ_DELAY) != 0)
-					ssleep(1);
-			} else {
-#ifdef AHC_DEBUG
-				if (ahc_debug & AHC_SHOW_DV) {
-					ahc_print_devinfo(ahc, devinfo);
-					printf("DV BUSY reties exhausted\n");
-				}
-#endif
-				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			}
-			break;
-		default:
-			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-			break;
-		}
-		break;
-
-	default:
-		printf("%s: Invalid DV completion state %d\n", ahc_name(ahc),
-		       targ->dv_state);
-		AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
-		break;
-	}
-}
-
-static void
-ahc_linux_dv_fill_cmd(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		      struct ahc_devinfo *devinfo)
-{
-	memset(cmd, 0, sizeof(struct scsi_cmnd));
-	cmd->device = ahc->platform_data->dv_scsi_dev;
-	cmd->scsi_done = ahc_linux_dv_complete;
-}
-
-/*
- * Synthesize an inquiry command.  On the return trip, it'll be
- * sniffed and the device transfer settings set for us.
- */
-static void
-ahc_linux_dv_inq(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ,
-		 u_int request_length)
-{
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending INQ\n");
-	}
-#endif
-	if (targ->inq_data == NULL)
-		targ->inq_data = malloc(AHC_LINUX_DV_INQ_LEN,
-					M_DEVBUF, M_WAITOK);
-	if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC) {
-		if (targ->dv_buffer != NULL)
-			free(targ->dv_buffer, M_DEVBUF);
-		targ->dv_buffer = malloc(AHC_LINUX_DV_INQ_LEN,
-					 M_DEVBUF, M_WAITOK);
-	}
-
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
-	cmd->cmd_len = 6;
-	cmd->cmnd[0] = INQUIRY;
-	cmd->cmnd[4] = request_length;
-	cmd->request_bufflen = request_length;
-	if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC)
-		cmd->request_buffer = targ->dv_buffer;
-	else
-		cmd->request_buffer = targ->inq_data;
-	memset(cmd->request_buffer, 0, AHC_LINUX_DV_INQ_LEN);
-}
-
-static void
-ahc_linux_dv_tur(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		 struct ahc_devinfo *devinfo)
-{
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending TUR\n");
-	}
-#endif
-	/* Do a TUR to clear out any non-fatal transitional state */
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_NONE;
-	cmd->cmd_len = 6;
-	cmd->cmnd[0] = TEST_UNIT_READY;
-}
-
-#define AHC_REBD_LEN 4
-
-static void
-ahc_linux_dv_rebd(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
-{
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending REBD\n");
-	}
-#endif
-	if (targ->dv_buffer != NULL)
-		free(targ->dv_buffer, M_DEVBUF);
-	targ->dv_buffer = malloc(AHC_REBD_LEN, M_DEVBUF, M_WAITOK);
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
-	cmd->cmd_len = 10;
-	cmd->cmnd[0] = READ_BUFFER;
-	cmd->cmnd[1] = 0x0b;
-	scsi_ulto3b(AHC_REBD_LEN, &cmd->cmnd[6]);
-	cmd->request_bufflen = AHC_REBD_LEN;
-	cmd->underflow = cmd->request_bufflen;
-	cmd->request_buffer = targ->dv_buffer;
-}
-
-static void
-ahc_linux_dv_web(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
-{
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending WEB\n");
-	}
-#endif
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_WRITE;
-	cmd->cmd_len = 10;
-	cmd->cmnd[0] = WRITE_BUFFER;
-	cmd->cmnd[1] = 0x0a;
-	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
-	cmd->request_bufflen = targ->dv_echo_size;
-	cmd->underflow = cmd->request_bufflen;
-	cmd->request_buffer = targ->dv_buffer;
-}
-
-static void
-ahc_linux_dv_reb(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
-{
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending REB\n");
-	}
-#endif
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_READ;
-	cmd->cmd_len = 10;
-	cmd->cmnd[0] = READ_BUFFER;
-	cmd->cmnd[1] = 0x0a;
-	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
-	cmd->request_bufflen = targ->dv_echo_size;
-	cmd->underflow = cmd->request_bufflen;
-	cmd->request_buffer = targ->dv_buffer1;
-}
-
-static void
-ahc_linux_dv_su(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
-		struct ahc_devinfo *devinfo,
-		struct ahc_linux_target *targ)
-{
-	u_int le;
-
-	le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0;
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Sending SU\n");
-	}
-#endif
-	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
-	cmd->sc_data_direction = SCSI_DATA_NONE;
-	cmd->cmd_len = 6;
-	cmd->cmnd[0] = START_STOP_UNIT;
-	cmd->cmnd[4] = le | SSS_START;
-}
-
-static int
-ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
-{
-	struct	ahc_linux_target *targ;
-	struct	ahc_initiator_tinfo *tinfo;
-	struct	ahc_transinfo *goal;
-	struct	ahc_tmode_tstate *tstate;
-	struct	ahc_syncrate *syncrate;
-	u_long	s;
-	u_int	width;
-	u_int	period;
-	u_int	offset;
-	u_int	ppr_options;
-	u_int	cur_speed;
-	u_int	wide_speed;
-	u_int	narrow_speed;
-	u_int	fallback_speed;
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		ahc_print_devinfo(ahc, devinfo);
-		printf("Trying to fallback\n");
-	}
-#endif
-	ahc_lock(ahc, &s);
-	targ = ahc->platform_data->targets[devinfo->target_offset];
-	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
-				    devinfo->our_scsiid,
-				    devinfo->target, &tstate);
-	goal = &tinfo->goal;
-	width = goal->width;
-	period = goal->period;
-	offset = goal->offset;
-	ppr_options = goal->ppr_options;
-	if (offset == 0)
-		period = AHC_ASYNC_XFER_PERIOD;
-	if (targ->dv_next_narrow_period == 0)
-		targ->dv_next_narrow_period = MAX(period, AHC_SYNCRATE_ULTRA2);
-	if (targ->dv_next_wide_period == 0)
-		targ->dv_next_wide_period = period;
-	if (targ->dv_max_width == 0)
-		targ->dv_max_width = width;
-	if (targ->dv_max_ppr_options == 0)
-		targ->dv_max_ppr_options = ppr_options;
-	if (targ->dv_last_ppr_options == 0)
-		targ->dv_last_ppr_options = ppr_options;
-
-	cur_speed = aic_calc_speed(width, period, offset, AHC_SYNCRATE_MIN);
-	wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT,
-					  targ->dv_next_wide_period,
-					  MAX_OFFSET,
-					  AHC_SYNCRATE_MIN);
-	narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT,
-					    targ->dv_next_narrow_period,
-					    MAX_OFFSET,
-					    AHC_SYNCRATE_MIN);
-	fallback_speed = aic_calc_speed(width, period+1, offset,
-					AHC_SYNCRATE_MIN);
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, "
-		       "fallback_speed= %d\n", cur_speed, wide_speed,
-		       narrow_speed, fallback_speed);
-	}
-#endif
-
-	if (cur_speed > 160000) {
-		/*
-		 * Paced/DT/IU_REQ only transfer speeds.  All we
-		 * can do is fallback in terms of syncrate.
-		 */
-		period++;
-	} else if (cur_speed > 80000) {
-		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
-			/*
-			 * Try without IU_REQ as it may be confusing
-			 * an expander.
-			 */
-			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
-		} else {
-			/*
-			 * Paced/DT only transfer speeds.  All we
-			 * can do is fallback in terms of syncrate.
-			 */
-			period++;
-			ppr_options = targ->dv_max_ppr_options;
-		}
-	} else if (cur_speed > 3300) {
-
-		/*
-		 * In this range we the following
-		 * options ordered from highest to
-		 * lowest desireability:
-		 *
-		 * o Wide/DT
-		 * o Wide/non-DT
-		 * o Narrow at a potentally higher sync rate.
-		 *
-		 * All modes are tested with and without IU_REQ
-		 * set since using IUs may confuse an expander.
-		 */
-		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
-
-			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
-		} else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
-			/*
-			 * Try going non-DT.
-			 */
-			ppr_options = targ->dv_max_ppr_options;
-			ppr_options &= ~MSG_EXT_PPR_DT_REQ;
-		} else if (targ->dv_last_ppr_options != 0) {
-			/*
-			 * Try without QAS or any other PPR options.
-			 * We may need a non-PPR message to work with
-			 * an expander.  We look at the "last PPR options"
-			 * so we will perform this fallback even if the
-			 * target responded to our PPR negotiation with
-			 * no option bits set.
-			 */
-			ppr_options = 0;
-		} else if (width == MSG_EXT_WDTR_BUS_16_BIT) {
-			/*
-			 * If the next narrow speed is greater than
-			 * the next wide speed, fallback to narrow.
-			 * Otherwise fallback to the next DT/Wide setting.
-			 * The narrow async speed will always be smaller
-			 * than the wide async speed, so handle this case
-			 * specifically.
-			 */
-			ppr_options = targ->dv_max_ppr_options;
-			if (narrow_speed > fallback_speed
-			 || period >= AHC_ASYNC_XFER_PERIOD) {
-				targ->dv_next_wide_period = period+1;
-				width = MSG_EXT_WDTR_BUS_8_BIT;
-				period = targ->dv_next_narrow_period;
-			} else {
-				period++;
-			}
-		} else if ((ahc->features & AHC_WIDE) != 0
-			&& targ->dv_max_width != 0
-			&& wide_speed >= fallback_speed
-			&& (targ->dv_next_wide_period <= AHC_ASYNC_XFER_PERIOD
-			 || period >= AHC_ASYNC_XFER_PERIOD)) {
-
-			/*
-			 * We are narrow.  Try falling back
-			 * to the next wide speed with 
-			 * all supported ppr options set.
-			 */
-			targ->dv_next_narrow_period = period+1;
-			width = MSG_EXT_WDTR_BUS_16_BIT;
-			period = targ->dv_next_wide_period;
-			ppr_options = targ->dv_max_ppr_options;
-		} else {
-			/* Only narrow fallback is allowed. */
-			period++;
-			ppr_options = targ->dv_max_ppr_options;
-		}
-	} else {
-		ahc_unlock(ahc, &s);
-		return (-1);
-	}
-	offset = MAX_OFFSET;
-	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
-				     AHC_SYNCRATE_DT);
-	ahc_set_width(ahc, devinfo, width, AHC_TRANS_GOAL, FALSE);
-	if (period == 0) {
-		period = 0;
-		offset = 0;
-		ppr_options = 0;
-		if (width == MSG_EXT_WDTR_BUS_8_BIT)
-			targ->dv_next_narrow_period = AHC_ASYNC_XFER_PERIOD;
-		else
-			targ->dv_next_wide_period = AHC_ASYNC_XFER_PERIOD;
-	}
-	ahc_set_syncrate(ahc, devinfo, syncrate, period, offset,
-			 ppr_options, AHC_TRANS_GOAL, FALSE);
-	targ->dv_last_ppr_options = ppr_options;
-	ahc_unlock(ahc, &s);
-	return (0);
-}
-
-static void
-ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
-{
-	struct	ahc_softc *ahc;
-	struct	scb *scb;
-	u_long	flags;
-
-	ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
-	ahc_lock(ahc, &flags);
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV) {
-		printf("%s: Timeout while doing DV command %x.\n",
-		       ahc_name(ahc), cmd->cmnd[0]);
-		ahc_dump_card_state(ahc);
-	}
-#endif
-	
-	/*
-	 * Guard against "done race".  No action is
-	 * required if we just completed.
-	 */
-	if ((scb = (struct scb *)cmd->host_scribble) == NULL) {
-		ahc_unlock(ahc, &flags);
-		return;
-	}
-
-	/*
-	 * Command has not completed.  Mark this
-	 * SCB as having failing status prior to
-	 * resetting the bus, so we get the correct
-	 * error code.
-	 */
-	if ((scb->flags & SCB_SENSE) != 0)
-		ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
-	else
-		ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
-	ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate*/TRUE);
-
-	/*
-	 * Add a minimal bus settle delay for devices that are slow to
-	 * respond after bus resets.
-	 */
-	ahc_linux_freeze_simq(ahc);
-	init_timer(&ahc->platform_data->reset_timer);
-	ahc->platform_data->reset_timer.data = (u_long)ahc;
-	ahc->platform_data->reset_timer.expires = jiffies + HZ / 2;
-	ahc->platform_data->reset_timer.function =
-	    (ahc_linux_callback_t *)ahc_linux_release_simq;
-	add_timer(&ahc->platform_data->reset_timer);
-	if (ahc_linux_next_device_to_run(ahc) != NULL)
-		ahc_schedule_runq(ahc);
-	ahc_linux_run_complete_queue(ahc);
-	ahc_unlock(ahc, &flags);
-}
-
-static void
-ahc_linux_dv_complete(struct scsi_cmnd *cmd)
-{
-	struct ahc_softc *ahc;
-
-	ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
-
-	/* Delete the DV timer before it goes off! */
-	scsi_delete_timer(cmd);
-
-#ifdef AHC_DEBUG
-	if (ahc_debug & AHC_SHOW_DV)
-		printf("%s:%d:%d: Command completed, status= 0x%x\n",
-		       ahc_name(ahc), cmd->device->channel,
-		       cmd->device->id, cmd->result);
-#endif
-
-	/* Wake up the state machine */
-	up(&ahc->platform_data->dv_cmd_sem);
-}
-
-static void
-ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ)
-{
-	uint16_t b;
-	u_int	 i;
-	u_int	 j;
-
-	if (targ->dv_buffer != NULL)
-		free(targ->dv_buffer, M_DEVBUF);
-	targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
-	if (targ->dv_buffer1 != NULL)
-		free(targ->dv_buffer1, M_DEVBUF);
-	targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
-
-	i = 0;
-	b = 0x0001;
-	for (j = 0 ; i < targ->dv_echo_size; j++) {
-		if (j < 32) {
-			/*
-			 * 32bytes of sequential numbers.
-			 */
-			targ->dv_buffer[i++] = j & 0xff;
-		} else if (j < 48) {
-			/*
-			 * 32bytes of repeating 0x0000, 0xffff.
-			 */
-			targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00;
-		} else if (j < 64) {
-			/*
-			 * 32bytes of repeating 0x5555, 0xaaaa.
-			 */
-			targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55;
-		} else {
-			/*
-			 * Remaining buffer is filled with a repeating
-			 * patter of:
-			 *
-			 *	 0xffff
-			 *	~0x0001 << shifted once in each loop.
-			 */
-			if (j & 0x02) {
-				if (j & 0x01) {
-					targ->dv_buffer[i++] = ~(b >> 8) & 0xff;
-					b <<= 1;
-					if (b == 0x0000)
-						b = 0x0001;
-				} else {
-					targ->dv_buffer[i++] = (~b & 0xff);
-				}
-			} else {
-				targ->dv_buffer[i++] = 0xff;
-			}
-		}
-	}
-}
-
-static u_int
-ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
-{
-	static int warned_user;
-	u_int tags;
+static u_int
+ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	static int warned_user;
+	u_int tags;
 
 	tags = 0;
 	if ((ahc->user_discenable & devinfo->target_mask) != 0) {
@@ -3476,48 +1519,6 @@ ahc_linux_user_tagdepth(struct ahc_softc
 	return (tags);
 }
 
-static u_int
-ahc_linux_user_dv_setting(struct ahc_softc *ahc)
-{
-	static int warned_user;
-	int dv;
-
-	if (ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) {
-		if (warned_user == 0) {
-
-			printf(KERN_WARNING
-"aic7xxx: WARNING: Insufficient dv settings instances\n"
-"aic7xxx: for installed controllers. Using defaults\n"
-"aic7xxx: Please update the aic7xxx_dv_settings array\n"
-"aic7xxx: in the aic7xxx_osm.c source file.\n");
-			warned_user++;
-		}
-		dv = -1;
-	} else {
-
-		dv = aic7xxx_dv_settings[ahc->unit];
-	}
-
-	if (dv < 0) {
-		u_long s;
-
-		/*
-		 * Apply the default.
-		 */
-		/*
-		 * XXX - Enable DV on non-U160 controllers once it
-		 *       has been tested there.
-		 */
-		ahc_lock(ahc, &s);
-		dv = (ahc->features & AHC_DT);
-		if (ahc->seep_config != 0
-		 && ahc->seep_config->signature >= CFSIGNATURE2)
-			dv = (ahc->seep_config->adapter_control & CFENABLEDV);
-		ahc_unlock(ahc, &s);
-	}
-	return (dv);
-}
-
 /*
  * Determines the queue depth for a given device.
  */
@@ -3547,217 +1548,200 @@ ahc_linux_device_queue_depth(struct ahc_
 	}
 }
 
-static void
-ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+static int
+ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
+		      struct scsi_cmnd *cmd)
 {
-	struct	 ahc_cmd *acmd;
-	struct	 scsi_cmnd *cmd;
 	struct	 scb *scb;
 	struct	 hardware_scb *hscb;
 	struct	 ahc_initiator_tinfo *tinfo;
 	struct	 ahc_tmode_tstate *tstate;
 	uint16_t mask;
+	struct scb_tailq *untagged_q = NULL;
 
-	if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0)
-		panic("running device on run list");
+	/*
+	 * Schedule us to run later.  The only reason we are not
+	 * running is because the whole controller Q is frozen.
+	 */
+	if (ahc->platform_data->qfrozen != 0)
+		return SCSI_MLQUEUE_HOST_BUSY;
 
-	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
-	    && dev->openings > 0 && dev->qfrozen == 0) {
+	/*
+	 * We only allow one untagged transaction
+	 * per target in the initiator role unless
+	 * we are storing a full busy target *lun*
+	 * table in SCB space.
+	 */
+	if (!blk_rq_tagged(cmd->request)
+	    && (ahc->features & AHC_SCB_BTT) == 0) {
+		int target_offset;
 
-		/*
-		 * Schedule us to run later.  The only reason we are not
-		 * running is because the whole controller Q is frozen.
-		 */
-		if (ahc->platform_data->qfrozen != 0
-	 	 && AHC_DV_SIMQ_FROZEN(ahc) == 0) {
-			TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq,
-					  dev, links);
-			dev->flags |= AHC_DEV_ON_RUN_LIST;
-			return;
-		}
-		/*
-		 * Get an scb to use.
-		 */
-		if ((scb = ahc_get_scb(ahc)) == NULL) {
-			TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq,
-					 dev, links);
-			dev->flags |= AHC_DEV_ON_RUN_LIST;
+		target_offset = cmd->device->id + cmd->device->channel * 8;
+		untagged_q = &(ahc->untagged_queues[target_offset]);
+		if (!TAILQ_EMPTY(untagged_q))
+			/* if we're already executing an untagged command
+			 * we're busy to another */
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+
+	/*
+	 * Get an scb to use.
+	 */
+	if ((scb = ahc_get_scb(ahc)) == NULL) {
 			ahc->flags |= AHC_RESOURCE_SHORTAGE;
-			return;
-		}
-		TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
-		cmd = &acmd_scsi_cmd(acmd);
-		scb->io_ctx = cmd;
-		scb->platform_data->dev = dev;
-		hscb = scb->hscb;
-		cmd->host_scribble = (char *)scb;
+			return SCSI_MLQUEUE_HOST_BUSY;
+	}
 
-		/*
-		 * Fill out basics of the HSCB.
-		 */
-		hscb->control = 0;
-		hscb->scsiid = BUILD_SCSIID(ahc, cmd);
-		hscb->lun = cmd->device->lun;
-		mask = SCB_GET_TARGET_MASK(ahc, scb);
-		tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb),
-					    SCB_GET_OUR_ID(scb),
-					    SCB_GET_TARGET(ahc, scb), &tstate);
-		hscb->scsirate = tinfo->scsirate;
-		hscb->scsioffset = tinfo->curr.offset;
-		if ((tstate->ultraenb & mask) != 0)
-			hscb->control |= ULTRAENB;
-
-		if ((ahc->user_discenable & mask) != 0)
-			hscb->control |= DISCENB;
-
-	 	if (AHC_DV_CMD(cmd) != 0)
-			scb->flags |= SCB_SILENT;
-
-		if ((tstate->auto_negotiate & mask) != 0) {
-			scb->flags |= SCB_AUTO_NEGOTIATE;
-			scb->hscb->control |= MK_MESSAGE;
-		}
+	scb->io_ctx = cmd;
+	scb->platform_data->dev = dev;
+	hscb = scb->hscb;
+	cmd->host_scribble = (char *)scb;
+
+	/*
+	 * Fill out basics of the HSCB.
+	 */
+	hscb->control = 0;
+	hscb->scsiid = BUILD_SCSIID(ahc, cmd);
+	hscb->lun = cmd->device->lun;
+	mask = SCB_GET_TARGET_MASK(ahc, scb);
+	tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb),
+				    SCB_GET_OUR_ID(scb),
+				    SCB_GET_TARGET(ahc, scb), &tstate);
+	hscb->scsirate = tinfo->scsirate;
+	hscb->scsioffset = tinfo->curr.offset;
+	if ((tstate->ultraenb & mask) != 0)
+		hscb->control |= ULTRAENB;
+	
+	if ((ahc->user_discenable & mask) != 0)
+		hscb->control |= DISCENB;
+	
+	if ((tstate->auto_negotiate & mask) != 0) {
+		scb->flags |= SCB_AUTO_NEGOTIATE;
+		scb->hscb->control |= MK_MESSAGE;
+	}
 
-		if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-			int	msg_bytes;
-			uint8_t tag_msgs[2];
-
-			msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
-			if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
-				hscb->control |= tag_msgs[0];
-				if (tag_msgs[0] == MSG_ORDERED_TASK)
-					dev->commands_since_idle_or_otag = 0;
-			} else
-#endif
-			if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
-			 && (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
-				hscb->control |= MSG_ORDERED_TASK;
+	if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
+		int	msg_bytes;
+		uint8_t tag_msgs[2];
+		
+		msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
+		if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
+			hscb->control |= tag_msgs[0];
+			if (tag_msgs[0] == MSG_ORDERED_TASK)
 				dev->commands_since_idle_or_otag = 0;
-			} else {
-				hscb->control |= MSG_SIMPLE_TASK;
-			}
-		}
-
-		hscb->cdb_len = cmd->cmd_len;
-		if (hscb->cdb_len <= 12) {
-			memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len);
+		} else if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
+				&& (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
+			hscb->control |= MSG_ORDERED_TASK;
+			dev->commands_since_idle_or_otag = 0;
 		} else {
-			memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len);
-			scb->flags |= SCB_CDB32_PTR;
+			hscb->control |= MSG_SIMPLE_TASK;
 		}
+	}
 
-		scb->platform_data->xfer_len = 0;
-		ahc_set_residual(scb, 0);
-		ahc_set_sense_residual(scb, 0);
-		scb->sg_count = 0;
-		if (cmd->use_sg != 0) {
-			struct	ahc_dma_seg *sg;
-			struct	scatterlist *cur_seg;
-			struct	scatterlist *end_seg;
-			int	nseg;
-
-			cur_seg = (struct scatterlist *)cmd->request_buffer;
-			nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
-			    scsi_to_pci_dma_dir(cmd->sc_data_direction));
-			end_seg = cur_seg + nseg;
-			/* Copy the segments into the SG list. */
-			sg = scb->sg_list;
-			/*
-			 * The sg_count may be larger than nseg if
-			 * a transfer crosses a 32bit page.
-			 */ 
-			while (cur_seg < end_seg) {
-				dma_addr_t addr;
-				bus_size_t len;
-				int consumed;
-
-				addr = sg_dma_address(cur_seg);
-				len = sg_dma_len(cur_seg);
-				consumed = ahc_linux_map_seg(ahc, scb,
-							     sg, addr, len);
-				sg += consumed;
-				scb->sg_count += consumed;
-				cur_seg++;
-			}
-			sg--;
-			sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
-
-			/*
-			 * Reset the sg list pointer.
-			 */
-			scb->hscb->sgptr =
-			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+	hscb->cdb_len = cmd->cmd_len;
+	if (hscb->cdb_len <= 12) {
+		memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len);
+	} else {
+		memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len);
+		scb->flags |= SCB_CDB32_PTR;
+	}
 
-			/*
-			 * Copy the first SG into the "current"
-			 * data pointer area.
-			 */
-			scb->hscb->dataptr = scb->sg_list->addr;
-			scb->hscb->datacnt = scb->sg_list->len;
-		} else if (cmd->request_bufflen != 0) {
-			struct	 ahc_dma_seg *sg;
+	scb->platform_data->xfer_len = 0;
+	ahc_set_residual(scb, 0);
+	ahc_set_sense_residual(scb, 0);
+	scb->sg_count = 0;
+	if (cmd->use_sg != 0) {
+		struct	ahc_dma_seg *sg;
+		struct	scatterlist *cur_seg;
+		struct	scatterlist *end_seg;
+		int	nseg;
+
+		cur_seg = (struct scatterlist *)cmd->request_buffer;
+		nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
+				  cmd->sc_data_direction);
+		end_seg = cur_seg + nseg;
+		/* Copy the segments into the SG list. */
+		sg = scb->sg_list;
+		/*
+		 * The sg_count may be larger than nseg if
+		 * a transfer crosses a 32bit page.
+		 */ 
+		while (cur_seg < end_seg) {
 			dma_addr_t addr;
+			bus_size_t len;
+			int consumed;
 
-			sg = scb->sg_list;
-			addr = pci_map_single(ahc->dev_softc,
-			       cmd->request_buffer,
-			       cmd->request_bufflen,
-			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
-			scb->platform_data->buf_busaddr = addr;
-			scb->sg_count = ahc_linux_map_seg(ahc, scb,
-							  sg, addr,
-							  cmd->request_bufflen);
-			sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
+			addr = sg_dma_address(cur_seg);
+			len = sg_dma_len(cur_seg);
+			consumed = ahc_linux_map_seg(ahc, scb,
+						     sg, addr, len);
+			sg += consumed;
+			scb->sg_count += consumed;
+			cur_seg++;
+		}
+		sg--;
+		sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
 
-			/*
-			 * Reset the sg list pointer.
-			 */
-			scb->hscb->sgptr =
-			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+		/*
+		 * Reset the sg list pointer.
+		 */
+		scb->hscb->sgptr =
+			ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+		
+		/*
+		 * Copy the first SG into the "current"
+		 * data pointer area.
+		 */
+		scb->hscb->dataptr = scb->sg_list->addr;
+		scb->hscb->datacnt = scb->sg_list->len;
+	} else if (cmd->request_bufflen != 0) {
+		struct	 ahc_dma_seg *sg;
+		dma_addr_t addr;
 
-			/*
-			 * Copy the first SG into the "current"
-			 * data pointer area.
-			 */
-			scb->hscb->dataptr = sg->addr;
-			scb->hscb->datacnt = sg->len;
-		} else {
-			scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
-			scb->hscb->dataptr = 0;
-			scb->hscb->datacnt = 0;
-			scb->sg_count = 0;
-		}
+		sg = scb->sg_list;
+		addr = pci_map_single(ahc->dev_softc,
+				      cmd->request_buffer,
+				      cmd->request_bufflen,
+				      cmd->sc_data_direction);
+		scb->platform_data->buf_busaddr = addr;
+		scb->sg_count = ahc_linux_map_seg(ahc, scb,
+						  sg, addr,
+						  cmd->request_bufflen);
+		sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
 
-		ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE);
-		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
-		dev->openings--;
-		dev->active++;
-		dev->commands_issued++;
-		if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0)
-			dev->commands_since_idle_or_otag++;
+		/*
+		 * Reset the sg list pointer.
+		 */
+		scb->hscb->sgptr =
+			ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
 
 		/*
-		 * We only allow one untagged transaction
-		 * per target in the initiator role unless
-		 * we are storing a full busy target *lun*
-		 * table in SCB space.
+		 * Copy the first SG into the "current"
+		 * data pointer area.
 		 */
-		if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
-		 && (ahc->features & AHC_SCB_BTT) == 0) {
-			struct scb_tailq *untagged_q;
-			int target_offset;
-
-			target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
-			untagged_q = &(ahc->untagged_queues[target_offset]);
-			TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
-			scb->flags |= SCB_UNTAGGEDQ;
-			if (TAILQ_FIRST(untagged_q) != scb)
-				continue;
-		}
-		scb->flags |= SCB_ACTIVE;
-		ahc_queue_scb(ahc, scb);
+		scb->hscb->dataptr = sg->addr;
+		scb->hscb->datacnt = sg->len;
+	} else {
+		scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
+		scb->hscb->dataptr = 0;
+		scb->hscb->datacnt = 0;
+		scb->sg_count = 0;
+	}
+
+	LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
+	dev->openings--;
+	dev->active++;
+	dev->commands_issued++;
+	if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0)
+		dev->commands_since_idle_or_otag++;
+	
+	scb->flags |= SCB_ACTIVE;
+	if (untagged_q) {
+		TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
+		scb->flags |= SCB_UNTAGGEDQ;
 	}
+	ahc_queue_scb(ahc, scb);
+	return 0;
 }
 
 /*
@@ -3773,9 +1757,6 @@ ahc_linux_isr(int irq, void *dev_id, str
 	ahc = (struct ahc_softc *) dev_id;
 	ahc_lock(ahc, &flags); 
 	ours = ahc_intr(ahc);
-	if (ahc_linux_next_device_to_run(ahc) != NULL)
-		ahc_schedule_runq(ahc);
-	ahc_linux_run_complete_queue(ahc);
 	ahc_unlock(ahc, &flags);
 	return IRQ_RETVAL(ours);
 }
@@ -3784,8 +1765,6 @@ void
 ahc_platform_flushwork(struct ahc_softc *ahc)
 {
 
-	while (ahc_linux_run_complete_queue(ahc) != NULL)
-		;
 }
 
 static struct ahc_linux_target*
@@ -3805,7 +1784,6 @@ ahc_linux_alloc_target(struct ahc_softc 
 	targ->channel = channel;
 	targ->target = target;
 	targ->ahc = ahc;
-	targ->flags = AHC_DV_REQUIRED;
 	ahc->platform_data->targets[target_offset] = targ;
 	return (targ);
 }
@@ -3842,12 +1820,6 @@ ahc_linux_free_target(struct ahc_softc *
 		      AHC_TRANS_GOAL, /*paused*/FALSE);
 	ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, AHC_NEG_ALWAYS);
 	ahc->platform_data->targets[target_offset] = NULL;
-	if (targ->inq_data != NULL)
-		free(targ->inq_data, M_DEVBUF);
-	if (targ->dv_buffer != NULL)
-		free(targ->dv_buffer, M_DEVBUF);
-	if (targ->dv_buffer1 != NULL)
-		free(targ->dv_buffer1, M_DEVBUF);
 	free(targ, M_DEVBUF);
 }
 
@@ -3861,9 +1833,6 @@ ahc_linux_alloc_device(struct ahc_softc 
 	if (dev == NULL)
 		return (NULL);
 	memset(dev, 0, sizeof(*dev));
-	init_timer(&dev->timer);
-	TAILQ_INIT(&dev->busyq);
-	dev->flags = AHC_DEV_UNCONFIGURED;
 	dev->lun = lun;
 	dev->target = targ;
 
@@ -3886,7 +1855,7 @@ ahc_linux_alloc_device(struct ahc_softc 
 }
 
 static void
-__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct ahc_linux_target *targ;
 
@@ -3894,18 +1863,10 @@ __ahc_linux_free_device(struct ahc_softc
 	targ->devices[dev->lun] = NULL;
 	free(dev, M_DEVBUF);
 	targ->refcount--;
-	if (targ->refcount == 0
-	 && (targ->flags & AHC_DV_REQUIRED) == 0)
+	if (targ->refcount == 0)
 		ahc_linux_free_target(ahc, targ);
 }
 
-static void
-ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
-{
-	del_timer_sync(&dev->timer);
-	__ahc_linux_free_device(ahc, dev);
-}
-
 void
 ahc_send_async(struct ahc_softc *ahc, char channel,
 	       u_int target, u_int lun, ac_code code, void *arg)
@@ -3977,28 +1938,9 @@ ahc_send_async(struct ahc_softc *ahc, ch
 	}
         case AC_SENT_BDR:
 	{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 		WARN_ON(lun != CAM_LUN_WILDCARD);
 		scsi_report_device_reset(ahc->platform_data->host,
 					 channel - 'A', target);
-#else
-		Scsi_Device *scsi_dev;
-
-		/*
-		 * Find the SCSI device associated with this
-		 * request and indicate that a UA is expected.
-		 */
-		for (scsi_dev = ahc->platform_data->host->host_queue;
-		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
-			if (channel - 'A' == scsi_dev->channel
-			 && target == scsi_dev->id
-			 && (lun == CAM_LUN_WILDCARD
-			  || lun == scsi_dev->lun)) {
-				scsi_dev->was_reset = 1;
-				scsi_dev->expecting_cc_ua = 1;
-			}
-		}
-#endif
 		break;
 	}
         case AC_BUS_RESET:
@@ -4018,7 +1960,7 @@ ahc_send_async(struct ahc_softc *ahc, ch
 void
 ahc_done(struct ahc_softc *ahc, struct scb *scb)
 {
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	struct	   ahc_linux_device *dev;
 
 	LIST_REMOVE(scb, pending_links);
@@ -4029,7 +1971,7 @@ ahc_done(struct ahc_softc *ahc, struct s
 		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
 		untagged_q = &(ahc->untagged_queues[target_offset]);
 		TAILQ_REMOVE(untagged_q, scb, links.tqe);
-		ahc_run_untagged_queue(ahc, untagged_q);
+		BUG_ON(!TAILQ_EMPTY(untagged_q));
 	}
 
 	if ((scb->flags & SCB_ACTIVE) == 0) {
@@ -4097,18 +2039,7 @@ ahc_done(struct ahc_softc *ahc, struct s
 		}
 	} else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
 		ahc_linux_handle_scsi_status(ahc, dev, scb);
-	} else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
-		dev->flags |= AHC_DEV_UNCONFIGURED;
-		if (AHC_DV_CMD(cmd) == FALSE)
-			dev->target->flags &= ~AHC_DV_REQUIRED;
 	}
-	/*
-	 * Start DV for devices that require it assuming the first command
-	 * sent does not result in a selection timeout.
-	 */
-	if (ahc_get_transaction_status(scb) != CAM_SEL_TIMEOUT
-	 && (dev->target->flags & AHC_DV_REQUIRED) != 0)
-		ahc_linux_start_dv(ahc);
 
 	if (dev->openings == 1
 	 && ahc_get_transaction_status(scb) == CAM_REQ_CMP
@@ -4129,16 +2060,6 @@ ahc_done(struct ahc_softc *ahc, struct s
 	if (dev->active == 0)
 		dev->commands_since_idle_or_otag = 0;
 
-	if (TAILQ_EMPTY(&dev->busyq)) {
-		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
-		 && dev->active == 0
-	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
-			ahc_linux_free_device(ahc, dev);
-	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
-		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
-		dev->flags |= AHC_DEV_ON_RUN_LIST;
-	}
-
 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
 		printf("Recovery SCB completes\n");
 		if (ahc_get_transaction_status(scb) == CAM_BDR_SENT
@@ -4152,13 +2073,6 @@ ahc_done(struct ahc_softc *ahc, struct s
 
 	ahc_free_scb(ahc, scb);
 	ahc_linux_queue_cmd_complete(ahc, cmd);
-
-	if ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_EMPTY) != 0
-	 && LIST_FIRST(&ahc->pending_scbs) == NULL) {
-		ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_EMPTY;
-		up(&ahc->platform_data->dv_sem);
-	}
-		
 }
 
 static void
@@ -4189,7 +2103,7 @@ ahc_linux_handle_scsi_status(struct ahc_
 	case SCSI_STATUS_CHECK_COND:
 	case SCSI_STATUS_CMD_TERMINATED:
 	{
-		Scsi_Cmnd *cmd;
+		struct scsi_cmnd *cmd;
 
 		/*
 		 * Copy sense information to the OS's cmd
@@ -4284,58 +2198,21 @@ ahc_linux_handle_scsi_status(struct ahc_
 		ahc_platform_set_tags(ahc, &devinfo,
 			     (dev->flags & AHC_DEV_Q_BASIC)
 			   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
-		/* FALLTHROUGH */
-	}
-	case SCSI_STATUS_BUSY:
-	{
-		/*
-		 * Set a short timer to defer sending commands for
-		 * a bit since Linux will not delay in this case.
-		 */
-		if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) {
-			printf("%s:%c:%d: Device Timer still active during "
-			       "busy processing\n", ahc_name(ahc),
-				dev->target->channel, dev->target->target);
-			break;
-		}
-		dev->flags |= AHC_DEV_TIMER_ACTIVE;
-		dev->qfrozen++;
-		init_timer(&dev->timer);
-		dev->timer.data = (u_long)dev;
-		dev->timer.expires = jiffies + (HZ/2);
-		dev->timer.function = ahc_linux_dev_timed_unfreeze;
-		add_timer(&dev->timer);
 		break;
 	}
 	}
 }
 
 static void
-ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd)
 {
 	/*
-	 * Typically, the complete queue has very few entries
-	 * queued to it before the queue is emptied by
-	 * ahc_linux_run_complete_queue, so sorting the entries
-	 * by generation number should be inexpensive.
-	 * We perform the sort so that commands that complete
-	 * with an error are retuned in the order origionally
-	 * queued to the controller so that any subsequent retries
-	 * are performed in order.  The underlying ahc routines do
-	 * not guarantee the order that aborted commands will be
-	 * returned to us.
-	 */
-	struct ahc_completeq *completeq;
-	struct ahc_cmd *list_cmd;
-	struct ahc_cmd *acmd;
-
-	/*
 	 * Map CAM error codes into Linux Error codes.  We
 	 * avoid the conversion so that the DV code has the
 	 * full error information available when making
 	 * state change decisions.
 	 */
-	if (AHC_DV_CMD(cmd) == FALSE) {
+	{
 		u_int new_status;
 
 		switch (ahc_cmd_get_transaction_status(cmd)) {
@@ -4382,26 +2259,7 @@ ahc_linux_queue_cmd_complete(struct ahc_
 			new_status = DID_ERROR;
 			break;
 		case CAM_REQUEUE_REQ:
-			/*
-			 * If we want the request requeued, make sure there
-			 * are sufficent retries.  In the old scsi error code,
-			 * we used to be able to specify a result code that
-			 * bypassed the retry count.  Now we must use this
-			 * hack.  We also "fake" a check condition with
-			 * a sense code of ABORTED COMMAND.  This seems to
-			 * evoke a retry even if this command is being sent
-			 * via the eh thread.  Ick!  Ick!  Ick!
-			 */
-			if (cmd->retries > 0)
-				cmd->retries--;
-			new_status = DID_OK;
-			ahc_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND);
-			cmd->result |= (DRIVER_SENSE << 24);
-			memset(cmd->sense_buffer, 0,
-			       sizeof(cmd->sense_buffer));
-			cmd->sense_buffer[0] = SSD_ERRCODE_VALID
-					     | SSD_CURRENT_ERROR;
-			cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND;
+			new_status = DID_REQUEUE;
 			break;
 		default:
 			/* We should never get here */
@@ -4412,126 +2270,7 @@ ahc_linux_queue_cmd_complete(struct ahc_
 		ahc_cmd_set_transaction_status(cmd, new_status);
 	}
 
-	completeq = &ahc->platform_data->completeq;
-	list_cmd = TAILQ_FIRST(completeq);
-	acmd = (struct ahc_cmd *)cmd;
-	while (list_cmd != NULL
-	    && acmd_scsi_cmd(list_cmd).serial_number
-	     < acmd_scsi_cmd(acmd).serial_number)
-		list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
-	if (list_cmd != NULL)
-		TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
-	else
-		TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
-}
-
-static void
-ahc_linux_filter_inquiry(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
-{
-	struct	scsi_inquiry_data *sid;
-	struct	ahc_initiator_tinfo *tinfo;
-	struct	ahc_transinfo *user;
-	struct	ahc_transinfo *goal;
-	struct	ahc_transinfo *curr;
-	struct	ahc_tmode_tstate *tstate;
-	struct	ahc_syncrate *syncrate;
-	struct	ahc_linux_device *dev;
-	u_int	maxsync;
-	u_int	width;
-	u_int	period;
-	u_int	offset;
-	u_int	ppr_options;
-	u_int	trans_version;
-	u_int	prot_version;
-
-	/*
-	 * Determine if this lun actually exists.  If so,
-	 * hold on to its corresponding device structure.
-	 * If not, make sure we release the device and
-	 * don't bother processing the rest of this inquiry
-	 * command.
-	 */
-	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
-				   devinfo->target, devinfo->lun,
-				   /*alloc*/TRUE);
-
-	sid = (struct scsi_inquiry_data *)dev->target->inq_data;
-	if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
-
-		dev->flags &= ~AHC_DEV_UNCONFIGURED;
-	} else {
-		dev->flags |= AHC_DEV_UNCONFIGURED;
-		return;
-	}
-
-	/*
-	 * Update our notion of this device's transfer
-	 * negotiation capabilities.
-	 */
-	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
-				    devinfo->our_scsiid,
-				    devinfo->target, &tstate);
-	user = &tinfo->user;
-	goal = &tinfo->goal;
-	curr = &tinfo->curr;
-	width = user->width;
-	period = user->period;
-	offset = user->offset;
-	ppr_options = user->ppr_options;
-	trans_version = user->transport_version;
-	prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
-
-	/*
-	 * Only attempt SPI3/4 once we've verified that
-	 * the device claims to support SPI3/4 features.
-	 */
-	if (prot_version < SCSI_REV_2)
-		trans_version = SID_ANSI_REV(sid);
-	else
-		trans_version = SCSI_REV_2;
-
-	if ((sid->flags & SID_WBus16) == 0)
-		width = MSG_EXT_WDTR_BUS_8_BIT;
-	if ((sid->flags & SID_Sync) == 0) {
-		period = 0;
-		offset = 0;
-		ppr_options = 0;
-	}
-	if ((sid->spi3data & SID_SPI_QAS) == 0)
-		ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
-	if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
-		ppr_options &= MSG_EXT_PPR_QAS_REQ;
-	if ((sid->spi3data & SID_SPI_IUS) == 0)
-		ppr_options &= (MSG_EXT_PPR_DT_REQ
-			      | MSG_EXT_PPR_QAS_REQ);
-
-	if (prot_version > SCSI_REV_2
-	 && ppr_options != 0)
-		trans_version = user->transport_version;
-
-	ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN);
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		maxsync = AHC_SYNCRATE_DT;
-	else if ((ahc->features & AHC_ULTRA) != 0)
-		maxsync = AHC_SYNCRATE_ULTRA;
-	else
-		maxsync = AHC_SYNCRATE_FAST;
-
-	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, maxsync);
-	ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate,
-			    &offset, width, ROLE_UNKNOWN);
-	if (offset == 0 || period == 0) {
-		period = 0;
-		offset = 0;
-		ppr_options = 0;
-	}
-	/* Apply our filtered user settings. */
-	curr->transport_version = trans_version;
-	curr->protocol_version = prot_version;
-	ahc_set_width(ahc, devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE);
-	ahc_set_syncrate(ahc, devinfo, syncrate, period,
-			 offset, ppr_options, AHC_TRANS_GOAL,
-			 /*paused*/FALSE);
+	cmd->scsi_done(cmd);
 }
 
 static void
@@ -4579,12 +2318,6 @@ ahc_linux_release_simq(u_long arg)
 		ahc->platform_data->qfrozen--;
 	if (ahc->platform_data->qfrozen == 0)
 		unblock_reqs = 1;
-	if (AHC_DV_SIMQ_FROZEN(ahc)
-	 && ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_RELEASE) != 0)) {
-		ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_RELEASE;
-		up(&ahc->platform_data->dv_sem);
-	}
-	ahc_schedule_runq(ahc);
 	ahc_unlock(ahc, &s);
 	/*
 	 * There is still a race here.  The mid-layer
@@ -4596,37 +2329,12 @@ ahc_linux_release_simq(u_long arg)
 		scsi_unblock_requests(ahc->platform_data->host);
 }
 
-static void
-ahc_linux_dev_timed_unfreeze(u_long arg)
-{
-	struct ahc_linux_device *dev;
-	struct ahc_softc *ahc;
-	u_long s;
-
-	dev = (struct ahc_linux_device *)arg;
-	ahc = dev->target->ahc;
-	ahc_lock(ahc, &s);
-	dev->flags &= ~AHC_DEV_TIMER_ACTIVE;
-	if (dev->qfrozen > 0)
-		dev->qfrozen--;
-	if (dev->qfrozen == 0
-	 && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0)
-		ahc_linux_run_device_queue(ahc, dev);
-	if (TAILQ_EMPTY(&dev->busyq)
-	 && dev->active == 0)
-		__ahc_linux_free_device(ahc, dev);
-	ahc_unlock(ahc, &s);
-}
-
 static int
-ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
+ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
 {
 	struct ahc_softc *ahc;
-	struct ahc_cmd *acmd;
-	struct ahc_cmd *list_acmd;
 	struct ahc_linux_device *dev;
 	struct scb *pending_scb;
-	u_long s;
 	u_int  saved_scbptr;
 	u_int  active_scb_index;
 	u_int  last_phase;
@@ -4642,7 +2350,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *
 	paused = FALSE;
 	wait = FALSE;
 	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
-	acmd = (struct ahc_cmd *)cmd;
 
 	printf("%s:%d:%d:%d: Attempting to queue a%s message\n",
 	       ahc_name(ahc), cmd->device->channel,
@@ -4655,22 +2362,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *
 	printf("\n");
 
 	/*
-	 * In all versions of Linux, we have to work around
-	 * a major flaw in how the mid-layer is locked down
-	 * if we are to sleep successfully in our error handler
-	 * while allowing our interrupt handler to run.  Since
-	 * the midlayer acquires either the io_request_lock or
-	 * our lock prior to calling us, we must use the
-	 * spin_unlock_irq() method for unlocking our lock.
-	 * This will force interrupts to be enabled on the
-	 * current CPU.  Since the EH thread should not have
-	 * been running with CPU interrupts disabled other than
-	 * by acquiring either the io_request_lock or our own
-	 * lock, this *should* be safe.
-	 */
-	ahc_midlayer_entrypoint_lock(ahc, &s);
-
-	/*
 	 * First determine if we currently own this command.
 	 * Start by searching the device queue.  If not found
 	 * there, check the pending_scb list.  If not found
@@ -4678,7 +2369,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *
 	 * command, return success.
 	 */
 	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
-				   cmd->device->lun, /*alloc*/FALSE);
+				   cmd->device->lun);
 
 	if (dev == NULL) {
 		/*
@@ -4692,24 +2383,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *
 		goto no_cmd;
 	}
 
-	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
-		if (list_acmd == acmd)
-			break;
-	}
-
-	if (list_acmd != NULL) {
-		printf("%s:%d:%d:%d: Command found on device queue\n",
-		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
-		       cmd->device->lun);
-		if (flag == SCB_ABORT) {
-			TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
-			cmd->result = DID_ABORT << 16;
-			ahc_linux_queue_cmd_complete(ahc, cmd);
-			retval = SUCCESS;
-			goto done;
-		}
-	}
-
 	if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
 	 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id,
 				       cmd->device->channel + 'A',
@@ -4943,100 +2616,299 @@ done:
 		}
 		spin_lock_irq(&ahc->platform_data->spin_lock);
 	}
-	ahc_schedule_runq(ahc);
-	ahc_linux_run_complete_queue(ahc);
-	ahc_midlayer_entrypoint_unlock(ahc, &s);
 	return (retval);
 }
 
 void
 ahc_platform_dump_card_state(struct ahc_softc *ahc)
 {
-	struct ahc_linux_device *dev;
-	int channel;
-	int maxchannel;
-	int target;
-	int maxtarget;
-	int lun;
-	int i;
+}
 
-	maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0;
-	maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7;
-	for (channel = 0; channel <= maxchannel; channel++) {
-
-		for (target = 0; target <=maxtarget; target++) {
-
-			for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
-				struct ahc_cmd *acmd;
-
-				dev = ahc_linux_get_device(ahc, channel, target,
-							   lun, /*alloc*/FALSE);
-				if (dev == NULL)
-					continue;
-
-				printf("DevQ(%d:%d:%d): ",
-				       channel, target, lun);
-				i = 0;
-				TAILQ_FOREACH(acmd, &dev->busyq,
-					      acmd_links.tqe) {
-					if (i++ > AHC_SCB_MAX)
-						break;
-				}
-				printf("%d waiting\n", i);
-			}
-		}
+static void ahc_linux_exit(void);
+
+static void ahc_linux_get_width(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_width(starget) = tinfo->curr.width;
+}
+
+static void ahc_linux_set_width(struct scsi_target *starget, int width)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_devinfo devinfo;
+	unsigned long flags;
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	ahc_lock(ahc, &flags);
+	ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
+}
+
+static void ahc_linux_get_period(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_period(starget) = tinfo->curr.period;
+}
+
+static void ahc_linux_set_period(struct scsi_target *starget, int period)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahc_devinfo devinfo;
+	unsigned int ppr_options = tinfo->curr.ppr_options;
+	unsigned long flags;
+	unsigned long offset = tinfo->curr.offset;
+	struct ahc_syncrate *syncrate;
+
+	if (offset == 0)
+		offset = MAX_OFFSET;
+
+	if (period < 9)
+		period = 9;	/* 12.5ns is our minimum */
+	if (period == 9)
+		ppr_options |= MSG_EXT_PPR_DT_REQ;
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+
+	/* all PPR requests apart from QAS require wide transfers */
+	if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) {
+		ahc_linux_get_width(starget);
+		if (spi_width(starget) == 0)
+			ppr_options &= MSG_EXT_PPR_QAS_REQ;
 	}
+
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
+	ahc_lock(ahc, &flags);
+	ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
 }
 
-static void ahc_linux_exit(void);
+static void ahc_linux_get_offset(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_offset(starget) = tinfo->curr.offset;
+}
+
+static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahc_devinfo devinfo;
+	unsigned int ppr_options = 0;
+	unsigned int period = 0;
+	unsigned long flags;
+	struct ahc_syncrate *syncrate = NULL;
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	if (offset != 0) {
+		syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
+		period = tinfo->curr.period;
+		ppr_options = tinfo->curr.ppr_options;
+	}
+	ahc_lock(ahc, &flags);
+	ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
+}
+
+static void ahc_linux_get_dt(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
+}
+
+static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahc_devinfo devinfo;
+	unsigned int ppr_options = tinfo->curr.ppr_options
+		& ~MSG_EXT_PPR_DT_REQ;
+	unsigned int period = tinfo->curr.period;
+	unsigned long flags;
+	struct ahc_syncrate *syncrate;
+
+	if (dt) {
+		period = 9;	/* 12.5ns is the only period valid for DT */
+		ppr_options |= MSG_EXT_PPR_DT_REQ;
+	} else if (period == 9)
+		period = 10;	/* if resetting DT, period must be >= 25ns */
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,AHC_SYNCRATE_DT);
+	ahc_lock(ahc, &flags);
+	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
+}
+
+static void ahc_linux_get_qas(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
+}
+
+static void ahc_linux_set_qas(struct scsi_target *starget, int qas)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahc_devinfo devinfo;
+	unsigned int ppr_options = tinfo->curr.ppr_options
+		& ~MSG_EXT_PPR_QAS_REQ;
+	unsigned int period = tinfo->curr.period;
+	unsigned long flags;
+	struct ahc_syncrate *syncrate;
+
+	if (qas)
+		ppr_options |= MSG_EXT_PPR_QAS_REQ;
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
+	ahc_lock(ahc, &flags);
+	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
+}
+
+static void ahc_linux_get_iu(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
+}
+
+static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
+	struct ahc_tmode_tstate *tstate;
+	struct ahc_initiator_tinfo *tinfo 
+		= ahc_fetch_transinfo(ahc,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahc_devinfo devinfo;
+	unsigned int ppr_options = tinfo->curr.ppr_options
+		& ~MSG_EXT_PPR_IU_REQ;
+	unsigned int period = tinfo->curr.period;
+	unsigned long flags;
+	struct ahc_syncrate *syncrate;
+
+	if (iu)
+		ppr_options |= MSG_EXT_PPR_IU_REQ;
+
+	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
+	ahc_lock(ahc, &flags);
+	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	ahc_unlock(ahc, &flags);
+}
+
+static struct spi_function_template ahc_linux_transport_functions = {
+	.get_offset	= ahc_linux_get_offset,
+	.set_offset	= ahc_linux_set_offset,
+	.show_offset	= 1,
+	.get_period	= ahc_linux_get_period,
+	.set_period	= ahc_linux_set_period,
+	.show_period	= 1,
+	.get_width	= ahc_linux_get_width,
+	.set_width	= ahc_linux_set_width,
+	.show_width	= 1,
+	.get_dt		= ahc_linux_get_dt,
+	.set_dt		= ahc_linux_set_dt,
+	.show_dt	= 1,
+	.get_iu		= ahc_linux_get_iu,
+	.set_iu		= ahc_linux_set_iu,
+	.show_iu	= 1,
+	.get_qas	= ahc_linux_get_qas,
+	.set_qas	= ahc_linux_set_qas,
+	.show_qas	= 1,
+};
+
+
 
 static int __init
 ahc_linux_init(void)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-	int rc = ahc_linux_detect(&aic7xxx_driver_template);
-	if (rc)
-		return rc;
+	ahc_linux_transport_template = spi_attach_transport(&ahc_linux_transport_functions);
+	if (!ahc_linux_transport_template)
+		return -ENODEV;
+	if (ahc_linux_detect(&aic7xxx_driver_template))
+		return 0;
+	spi_release_transport(ahc_linux_transport_template);
 	ahc_linux_exit();
 	return -ENODEV;
-#else
-	scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template);
-	if (aic7xxx_driver_template.present == 0) {
-		scsi_unregister_module(MODULE_SCSI_HA,
-				       &aic7xxx_driver_template);
-		return (-ENODEV);
-	}
-
-	return (0);
-#endif
 }
 
 static void
 ahc_linux_exit(void)
 {
-	struct ahc_softc *ahc;
-
-	/*
-	 * Shutdown DV threads before going into the SCSI mid-layer.
-	 * This avoids situations where the mid-layer locks the entire
-	 * kernel so that waiting for our DV threads to exit leads
-	 * to deadlock.
-	 */
-	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
-
-		ahc_linux_kill_dv_thread(ahc);
-	}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	/*
-	 * In 2.4 we have to unregister from the PCI core _after_
-	 * unregistering from the scsi midlayer to avoid dangling
-	 * references.
-	 */
-	scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template);
-#endif
 	ahc_linux_pci_exit();
 	ahc_linux_eisa_exit();
+	spi_release_transport(ahc_linux_transport_template);
 }
 
 module_init(ahc_linux_init);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -59,6 +59,7 @@
 #ifndef _AIC7XXX_LINUX_H_
 #define _AIC7XXX_LINUX_H_
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
@@ -66,18 +67,21 @@
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
 #include <linux/version.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
 
-#include <linux/interrupt.h> /* For tasklet support. */
-#include <linux/config.h>
-#include <linux/slab.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 
 /* Core SCSI definitions */
 #define AIC_LIB_PREFIX ahc
-#include "scsi.h"
-#include <scsi/scsi_host.h>
 
 /* Name space conflict with BSD queue macros */
 #ifdef LIST_HEAD
@@ -106,7 +110,7 @@
 /************************* Forward Declarations *******************************/
 struct ahc_softc;
 typedef struct pci_dev *ahc_dev_softc_t;
-typedef Scsi_Cmnd      *ahc_io_ctx_t;
+typedef struct scsi_cmnd      *ahc_io_ctx_t;
 
 /******************************* Byte Order ***********************************/
 #define ahc_htobe16(x)	cpu_to_be16(x)
@@ -144,7 +148,7 @@ typedef Scsi_Cmnd      *ahc_io_ctx_t;
 extern u_int aic7xxx_no_probe;
 extern u_int aic7xxx_allow_memio;
 extern int aic7xxx_detect_complete;
-extern Scsi_Host_Template aic7xxx_driver_template;
+extern struct scsi_host_template aic7xxx_driver_template;
 
 /***************************** Bus Space/DMA **********************************/
 
@@ -174,11 +178,7 @@ struct ahc_linux_dma_tag
 };
 typedef struct ahc_linux_dma_tag* bus_dma_tag_t;
 
-struct ahc_linux_dmamap
-{
-	dma_addr_t	bus_addr;
-};
-typedef struct ahc_linux_dmamap* bus_dmamap_t;
+typedef dma_addr_t bus_dmamap_t;
 
 typedef int bus_dma_filter_t(void*, dma_addr_t);
 typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
@@ -281,12 +281,6 @@ ahc_scb_timer_reset(struct scb *scb, u_i
 /***************************** SMP support ************************************/
 #include <linux/spinlock.h>
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
-#define AHC_SCSI_HAS_HOST_LOCK 1
-#else
-#define AHC_SCSI_HAS_HOST_LOCK 0
-#endif
-
 #define AIC7XXX_DRIVER_VERSION "6.2.36"
 
 /**************************** Front End Queues ********************************/
@@ -328,20 +322,15 @@ struct ahc_cmd {
  */
 TAILQ_HEAD(ahc_busyq, ahc_cmd);
 typedef enum {
-	AHC_DEV_UNCONFIGURED	 = 0x01,
 	AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
-	AHC_DEV_TIMER_ACTIVE	 = 0x04, /* Our timer is active */
-	AHC_DEV_ON_RUN_LIST	 = 0x08, /* Queued to be run later */
 	AHC_DEV_Q_BASIC		 = 0x10, /* Allow basic device queuing */
 	AHC_DEV_Q_TAGGED	 = 0x20, /* Allow full SCSI2 command queueing */
 	AHC_DEV_PERIODIC_OTAG	 = 0x40, /* Send OTAG to prevent starvation */
-	AHC_DEV_SLAVE_CONFIGURED = 0x80	 /* slave_configure() has been called */
 } ahc_linux_dev_flags;
 
 struct ahc_linux_target;
 struct ahc_linux_device {
 	TAILQ_ENTRY(ahc_linux_device) links;
-	struct		ahc_busyq busyq;
 
 	/*
 	 * The number of transactions currently
@@ -382,11 +371,6 @@ struct ahc_linux_device {
 	ahc_linux_dev_flags	flags;
 
 	/*
-	 * Per device timer.
-	 */
-	struct timer_list	timer;
-
-	/*
 	 * The high limit for the tags variable.
 	 */
 	u_int			maxtags;
@@ -419,32 +403,10 @@ struct ahc_linux_device {
 #define AHC_OTAG_THRESH	500
 
 	int			lun;
-	Scsi_Device	       *scsi_device;
+	struct scsi_device       *scsi_device;
 	struct			ahc_linux_target *target;
 };
 
-typedef enum {
-	AHC_DV_REQUIRED		 = 0x01,
-	AHC_INQ_VALID		 = 0x02,
-	AHC_BASIC_DV		 = 0x04,
-	AHC_ENHANCED_DV		 = 0x08
-} ahc_linux_targ_flags;
-
-/* DV States */
-typedef enum {
-	AHC_DV_STATE_EXIT = 0,
-	AHC_DV_STATE_INQ_SHORT_ASYNC,
-	AHC_DV_STATE_INQ_ASYNC,
-	AHC_DV_STATE_INQ_ASYNC_VERIFY,
-	AHC_DV_STATE_TUR,
-	AHC_DV_STATE_REBD,
-	AHC_DV_STATE_INQ_VERIFY,
-	AHC_DV_STATE_WEB,
-	AHC_DV_STATE_REB,
-	AHC_DV_STATE_SU,
-	AHC_DV_STATE_BUSY
-} ahc_dv_state;
-
 struct ahc_linux_target {
 	struct ahc_linux_device	 *devices[AHC_NUM_LUNS];
 	int			  channel;
@@ -452,21 +414,6 @@ struct ahc_linux_target {
 	int			  refcount;
 	struct ahc_transinfo	  last_tinfo;
 	struct ahc_softc	 *ahc;
-	ahc_linux_targ_flags	  flags;
-	struct scsi_inquiry_data *inq_data;
-	/*
-	 * The next "fallback" period to use for narrow/wide transfers.
-	 */
-	uint8_t			  dv_next_narrow_period;
-	uint8_t			  dv_next_wide_period;
-	uint8_t			  dv_max_width;
-	uint8_t			  dv_max_ppr_options;
-	uint8_t			  dv_last_ppr_options;
-	u_int			  dv_echo_size;
-	ahc_dv_state		  dv_state;
-	u_int			  dv_state_retry;
-	char			 *dv_buffer;
-	char			 *dv_buffer1;
 };
 
 /********************* Definitions Required by the Core ***********************/
@@ -476,32 +423,16 @@ struct ahc_linux_target {
  * manner and are allocated below 4GB, the number of S/G segments is
  * unrestricted.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/*
- * We dynamically adjust the number of segments in pre-2.5 kernels to
- * avoid fragmentation issues in the SCSI mid-layer's private memory
- * allocator.  See aic7xxx_osm.c ahc_linux_size_nseg() for details.
- */
-extern u_int ahc_linux_nseg;
-#define	AHC_NSEG ahc_linux_nseg
-#define	AHC_LINUX_MIN_NSEG 64
-#else
 #define	AHC_NSEG 128
-#endif
 
 /*
  * Per-SCB OSM storage.
  */
-typedef enum {
-	AHC_UP_EH_SEMAPHORE = 0x1
-} ahc_linux_scb_flags;
-
 struct scb_platform_data {
 	struct ahc_linux_device	*dev;
 	dma_addr_t		 buf_busaddr;
 	uint32_t		 xfer_len;
 	uint32_t		 sense_resid;	/* Auto-Sense residual */
-	ahc_linux_scb_flags	 flags;
 };
 
 /*
@@ -510,43 +441,24 @@ struct scb_platform_data {
  * alignment restrictions of the various platforms supported by
  * this driver.
  */
-typedef enum {
-	AHC_DV_WAIT_SIMQ_EMPTY	 = 0x01,
-	AHC_DV_WAIT_SIMQ_RELEASE = 0x02,
-	AHC_DV_ACTIVE		 = 0x04,
-	AHC_DV_SHUTDOWN		 = 0x08,
-	AHC_RUN_CMPLT_Q_TIMER	 = 0x10
-} ahc_linux_softc_flags;
-
-TAILQ_HEAD(ahc_completeq, ahc_cmd);
-
 struct ahc_platform_data {
 	/*
 	 * Fields accessed from interrupt context.
 	 */
 	struct ahc_linux_target *targets[AHC_NUM_TARGETS]; 
-	TAILQ_HEAD(, ahc_linux_device) device_runq;
-	struct ahc_completeq	 completeq;
 
 	spinlock_t		 spin_lock;
-	struct tasklet_struct	 runq_tasklet;
 	u_int			 qfrozen;
-	pid_t			 dv_pid;
-	struct timer_list	 completeq_timer;
 	struct timer_list	 reset_timer;
 	struct semaphore	 eh_sem;
-	struct semaphore	 dv_sem;
-	struct semaphore	 dv_cmd_sem;	/* XXX This needs to be in
-						 * the target struct
-						 */
-	struct scsi_device	*dv_scsi_dev;
 	struct Scsi_Host        *host;		/* pointer to scsi host */
 #define AHC_LINUX_NOIRQ	((uint32_t)~0)
 	uint32_t		 irq;		/* IRQ for this adapter */
 	uint32_t		 bios_address;
 	uint32_t		 mem_busaddr;	/* Mem Base Addr */
-	uint64_t		 hw_dma_mask;
-	ahc_linux_softc_flags	 flags;
+
+#define	AHC_UP_EH_SEMAPHORE	 0x1
+	uint32_t		 flags;
 };
 
 /************************** OS Utility Wrappers *******************************/
@@ -635,7 +547,7 @@ ahc_insb(struct ahc_softc * ahc, long po
 
 /**************************** Initialization **********************************/
 int		ahc_linux_register_host(struct ahc_softc *,
-					Scsi_Host_Template *);
+					struct scsi_host_template *);
 
 uint64_t	ahc_linux_get_memsize(void);
 
@@ -656,17 +568,6 @@ static __inline void ahc_lockinit(struct
 static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags);
 static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags);
 
-/* Lock acquisition and release of the above lock in midlayer entry points. */
-static __inline void ahc_midlayer_entrypoint_lock(struct ahc_softc *,
-						  unsigned long *flags);
-static __inline void ahc_midlayer_entrypoint_unlock(struct ahc_softc *,
-						    unsigned long *flags);
-
-/* Lock held during command compeletion to the upper layer */
-static __inline void ahc_done_lockinit(struct ahc_softc *);
-static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
-static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
-
 /* Lock held during ahc_list manipulation and ahc softc frees */
 extern spinlock_t ahc_list_spinlock;
 static __inline void ahc_list_lockinit(void);
@@ -692,57 +593,6 @@ ahc_unlock(struct ahc_softc *ahc, unsign
 }
 
 static __inline void
-ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags)
-{
-	/*
-	 * In 2.5.X and some 2.4.X versions, the midlayer takes our
-	 * lock just before calling us, so we avoid locking again.
-	 * For other kernel versions, the io_request_lock is taken
-	 * just before our entry point is called.  In this case, we
-	 * trade the io_request_lock for our per-softc lock.
-	 */
-#if AHC_SCSI_HAS_HOST_LOCK == 0
-	spin_unlock(&io_request_lock);
-	spin_lock(&ahc->platform_data->spin_lock);
-#endif
-}
-
-static __inline void
-ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags)
-{
-#if AHC_SCSI_HAS_HOST_LOCK == 0
-	spin_unlock(&ahc->platform_data->spin_lock);
-	spin_lock(&io_request_lock);
-#endif
-}
-
-static __inline void
-ahc_done_lockinit(struct ahc_softc *ahc)
-{
-	/*
-	 * In 2.5.X, our own lock is held during completions.
-	 * In previous versions, the io_request_lock is used.
-	 * In either case, we can't initialize this lock again.
-	 */
-}
-
-static __inline void
-ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
-{
-#if AHC_SCSI_HAS_HOST_LOCK == 0
-	spin_lock_irqsave(&io_request_lock, *flags);
-#endif
-}
-
-static __inline void
-ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
-{
-#if AHC_SCSI_HAS_HOST_LOCK == 0
-	spin_unlock_irqrestore(&io_request_lock, *flags);
-#endif
-}
-
-static __inline void
 ahc_list_lockinit(void)
 {
 	spin_lock_init(&ahc_list_spinlock);
@@ -808,12 +658,6 @@ typedef enum
 } ahc_power_state;
 
 /**************************** VL/EISA Routines ********************************/
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) \
-  && (defined(__i386__) || defined(__alpha__)) \
-  && (!defined(CONFIG_EISA)))
-#define CONFIG_EISA
-#endif
-
 #ifdef CONFIG_EISA
 extern uint32_t aic7xxx_probe_eisa_vl;
 int			 ahc_linux_eisa_init(void);
@@ -929,27 +773,18 @@ ahc_flush_device_writes(struct ahc_softc
 }
 
 /**************************** Proc FS Support *********************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-int	ahc_linux_proc_info(char *, char **, off_t, int, int, int);
-#else
 int	ahc_linux_proc_info(struct Scsi_Host *, char *, char **,
 			    off_t, int, int);
-#endif
 
 /*************************** Domain Validation ********************************/
-#define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete)
-#define AHC_DV_SIMQ_FROZEN(ahc)					\
-	((((ahc)->platform_data->flags & AHC_DV_ACTIVE) != 0)	\
-	 && (ahc)->platform_data->qfrozen == 1)
-
 /*********************** Transaction Access Wrappers *************************/
-static __inline void ahc_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t);
 static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
-static __inline void ahc_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t);
 static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
-static __inline uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd);
 static __inline uint32_t ahc_get_transaction_status(struct scb *);
-static __inline uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd);
 static __inline uint32_t ahc_get_scsi_status(struct scb *);
 static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
 static __inline u_long ahc_get_transfer_length(struct scb *);
@@ -968,7 +803,7 @@ static __inline void ahc_platform_scb_fr
 static __inline void ahc_freeze_scb(struct scb *scb);
 
 static __inline
-void ahc_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status)
+void ahc_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status)
 {
 	cmd->result &= ~(CAM_STATUS_MASK << 16);
 	cmd->result |= status << 16;
@@ -981,7 +816,7 @@ void ahc_set_transaction_status(struct s
 }
 
 static __inline
-void ahc_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status)
+void ahc_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status)
 {
 	cmd->result &= ~0xFFFF;
 	cmd->result |= status;
@@ -994,7 +829,7 @@ void ahc_set_scsi_status(struct scb *scb
 }
 
 static __inline
-uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd)
+uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd)
 {
 	return ((cmd->result >> 16) & CAM_STATUS_MASK);
 }
@@ -1006,7 +841,7 @@ uint32_t ahc_get_transaction_status(stru
 }
 
 static __inline
-uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd)
+uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd)
 {
 	return (cmd->result & 0xFFFF);
 }
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -221,13 +221,11 @@ ahc_linux_pci_dev_probe(struct pci_dev *
 	 && ahc_linux_get_memsize() > 0x80000000
 	 && pci_set_dma_mask(pdev, mask_39bit) == 0) {
 		ahc->flags |= AHC_39BIT_ADDRESSING;
-		ahc->platform_data->hw_dma_mask = mask_39bit;
 	} else {
 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
                 	return (-ENODEV);
 		}
-		ahc->platform_data->hw_dma_mask = DMA_32BIT_MASK;
 	}
 	ahc->dev_softc = pci;
 	error = ahc_pci_config(ahc, entry);
@@ -236,15 +234,8 @@ ahc_linux_pci_dev_probe(struct pci_dev *
 		return (-error);
 	}
 	pci_set_drvdata(pdev, ahc);
-	if (aic7xxx_detect_complete) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	if (aic7xxx_detect_complete)
 		ahc_linux_register_host(ahc, &aic7xxx_driver_template);
-#else
-		printf("aic7xxx: ignoring PCI device found after "
-		       "initialization\n");
-		return (-ENODEV);
-#endif
-	}
 	return (0);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -289,13 +289,8 @@ done:
  * Return information to handle /proc support for the driver.
  */
 int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-ahc_linux_proc_info(char *buffer, char **start, off_t offset,
-		    int length, int hostno, int inout)
-#else
 ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
 		    off_t offset, int length, int inout)
-#endif
 {
 	struct	ahc_softc *ahc;
 	struct	info_str info;
@@ -307,15 +302,7 @@ ahc_linux_proc_info(struct Scsi_Host *sh
 
 	retval = -EINVAL;
 	ahc_list_lock(&s);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
-		if (ahc->platform_data->host->host_no == hostno)
-			break;
-	}
-#else
 	ahc = ahc_find_softc(*(struct ahc_softc **)shost->hostdata);
-#endif
-
 	if (ahc == NULL)
 		goto done;
 
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
--- a/drivers/scsi/aic7xxx/aiclib.c
+++ b/drivers/scsi/aic7xxx/aiclib.c
@@ -35,7 +35,6 @@
 #include <linux/version.h>
 
 /* Core SCSI definitions */
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include "aiclib.h"
 #include "cam.h"
diff --git a/drivers/scsi/aic7xxx/cam.h b/drivers/scsi/aic7xxx/cam.h
--- a/drivers/scsi/aic7xxx/cam.h
+++ b/drivers/scsi/aic7xxx/cam.h
@@ -103,9 +103,9 @@ typedef enum {
 } ac_code;
 
 typedef enum {
-	CAM_DIR_IN		= SCSI_DATA_READ,
-	CAM_DIR_OUT		= SCSI_DATA_WRITE,
-	CAM_DIR_NONE		= SCSI_DATA_NONE
+	CAM_DIR_IN		= DMA_FROM_DEVICE,
+	CAM_DIR_OUT		= DMA_TO_DEVICE,
+	CAM_DIR_NONE		= DMA_NONE,
 } ccb_flags;
 
 #endif /* _AIC7XXX_CAM_H */
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -2700,12 +2700,12 @@ aic7xxx_done(struct aic7xxx_host *p, str
     struct scatterlist *sg;
 
     sg = (struct scatterlist *)cmd->request_buffer;
-    pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+    pci_unmap_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
   }
   else if (cmd->request_bufflen)
     pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
 		     cmd->request_bufflen,
-                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+                     cmd->sc_data_direction);
   if (scb->flags & SCB_SENSE)
   {
     pci_unmap_single(p->pdev,
@@ -10228,7 +10228,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
 
     sg = (struct scatterlist *)cmd->request_buffer;
     scb->sg_length = 0;
-    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
     /*
      * Copy the segments into the SG array.  NOTE!!! - We used to
      * have the first entry both in the data_pointer area and the first
@@ -10256,7 +10256,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
     {
       unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
 					    cmd->request_bufflen,
-                                            scsi_to_pci_dma_dir(cmd->sc_data_direction));
+                                            cmd->sc_data_direction);
       aic7xxx_mapping(cmd) = address;
       scb->sg_list[0].address = cpu_to_le32(address);
       scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -150,6 +150,7 @@
 #include <asm/ecard.h>
 
 #include "../scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include "acornscsi.h"
 #include "msgqueue.h"
@@ -866,7 +867,7 @@ void acornscsi_done(AS_Host *host, Scsi_
 		    default:
 			printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
 				host->host->host_no, SCpnt->result);
-			print_command(SCpnt->cmnd);
+			__scsi_print_command(SCpnt->cmnd);
 			acornscsi_dumpdma(host, "done");
 		 	acornscsi_dumplog(host, SCpnt->device->id);
 			SCpnt->result &= 0xffff;
@@ -1369,7 +1370,7 @@ void acornscsi_sendmessage(AS_Host *host
 
 	host->scsi.last_message = msg->msg[0];
 #if (DEBUG & DEBUG_MESSAGES)
-	print_msg(msg->msg);
+	scsi_print_msg(msg->msg);
 #endif
 	break;
 
@@ -1391,7 +1392,7 @@ void acornscsi_sendmessage(AS_Host *host
 	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
 	    unsigned int i;
 #if (DEBUG & DEBUG_MESSAGES)
-	    print_msg(msg);
+	    scsi_print_msg(msg);
 #endif
 	    i = 0;
 	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
@@ -1487,7 +1488,7 @@ void acornscsi_message(AS_Host *host)
 #if (DEBUG & DEBUG_MESSAGES)
     printk("scsi%d.%c: message in: ",
 	    host->host->host_no, acornscsi_target(host));
-    print_msg(message);
+    scsi_print_msg(message);
     printk("\n");
 #endif
 
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -43,6 +43,7 @@
 struct arxescsi_info {
 	FAS216_Info		info;
 	struct expansion_card	*ec;
+	void __iomem		*base;
 };
 
 #define DMADATA_OFFSET	(0x200)
@@ -73,7 +74,7 @@ arxescsi_dma_setup(struct Scsi_Host *hos
 	return fasdma_pseudo;
 }
 
-static void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned char *base)
+static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base)
 {
        __asm__ __volatile__(
        "               stmdb   sp!, {r0-r12}\n"
@@ -115,7 +116,7 @@ arxescsi_dma_pseudo(struct Scsi_Host *ho
 {
 	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
 	unsigned int length, error = 0;
-	unsigned char *base = info->info.scsi.io_base;
+	void __iomem *base = info->info.scsi.io_base;
 	unsigned char *addr;
 
 	length = SCp->this_residual;
@@ -283,7 +284,7 @@ arxescsi_probe(struct expansion_card *ec
 	struct Scsi_Host *host;
 	struct arxescsi_info *info;
 	unsigned long resbase, reslen;
-	unsigned char *base;
+	void __iomem *base;
 	int ret;
 
 	ret = ecard_request_resources(ec);
@@ -304,15 +305,13 @@ arxescsi_probe(struct expansion_card *ec
 		goto out_unmap;
 	}
 
-	host->base = (unsigned long)base;
-	host->irq = NO_IRQ;
-	host->dma_channel = NO_DMA;
-
 	info = (struct arxescsi_info *)host->hostdata;
 	info->ec = ec;
+	info->base = base;
 
 	info->info.scsi.io_base		= base + 0x2000;
-	info->info.scsi.irq		= host->irq;
+	info->info.scsi.irq		= NO_IRQ;
+	info->info.scsi.dma		= NO_DMA;
 	info->info.scsi.io_shift	= 5;
 	info->info.ifcfg.clockrate	= 24; /* MHz */
 	info->info.ifcfg.select_timeout = 255;
@@ -351,11 +350,12 @@ arxescsi_probe(struct expansion_card *ec
 static void __devexit arxescsi_remove(struct expansion_card *ec)
 {
 	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
 
 	ecard_set_drvdata(ec, NULL);
 	fas216_remove(host);
 
-	iounmap((void *)host->base);
+	iounmap(info->base);
 
 	fas216_release(host);
 	scsi_host_put(host);
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/acorn/scsi/cumana_2.c
  *
- *  Copyright (C) 1997-2002 Russell King
+ *  Copyright (C) 1997-2005 Russell King
  *
  * 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
@@ -78,11 +78,8 @@ static int term[MAX_ECARDS] = { 1, 1, 1,
 struct cumanascsi2_info {
 	FAS216_Info		info;
 	struct expansion_card	*ec;
-
-	void			*status;	/* card status register	*/
-	void			*alatch;	/* Control register	*/
+	void __iomem		*base;
 	unsigned int		terms;		/* Terminator state	*/
-	void			*dmaarea;	/* Pseudo DMA area	*/
 	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
 };
 
@@ -97,7 +94,8 @@ struct cumanascsi2_info {
 static void
 cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr)
 {
-	writeb(ALATCH_ENA_INT, ec->irq_data);
+	struct cumanascsi2_info *info = ec->irq_data;
+	writeb(ALATCH_ENA_INT, info->base + CUMANASCSI2_ALATCH);
 }
 
 /* Prototype: void cumanascsi_2_irqdisable(ec, irqnr)
@@ -108,7 +106,8 @@ cumanascsi_2_irqenable(struct expansion_
 static void
 cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr)
 {
-	writeb(ALATCH_DIS_INT, ec->irq_data);
+	struct cumanascsi2_info *info = ec->irq_data;
+	writeb(ALATCH_DIS_INT, info->base + CUMANASCSI2_ALATCH);
 }
 
 static const expansioncard_ops_t cumanascsi_2_ops = {
@@ -128,10 +127,10 @@ cumanascsi_2_terminator_ctl(struct Scsi_
 
 	if (on_off) {
 		info->terms = 1;
-		writeb(ALATCH_ENA_TERM, info->alatch);
+		writeb(ALATCH_ENA_TERM, info->base + CUMANASCSI2_ALATCH);
 	} else {
 		info->terms = 0;
-		writeb(ALATCH_DIS_TERM, info->alatch);
+		writeb(ALATCH_DIS_TERM, info->base + CUMANASCSI2_ALATCH);
 	}
 }
 
@@ -163,9 +162,9 @@ cumanascsi_2_dma_setup(struct Scsi_Host 
 {
 	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
 	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
+	int dmach = info->info.scsi.dma;
 
-	writeb(ALATCH_DIS_DMA, info->alatch);
+	writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH);
 
 	if (dmach != NO_DMA &&
 	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
@@ -186,11 +185,11 @@ cumanascsi_2_dma_setup(struct Scsi_Host 
 
 		disable_dma(dmach);
 		set_dma_sg(dmach, info->sg, bufs + 1);
-		writeb(alatch_dir, info->alatch);
+		writeb(alatch_dir, info->base + CUMANASCSI2_ALATCH);
 		set_dma_mode(dmach, dma_dir);
 		enable_dma(dmach);
-		writeb(ALATCH_ENA_DMA, info->alatch);
-		writeb(ALATCH_DIS_BIT32, info->alatch);
+		writeb(ALATCH_ENA_DMA, info->base + CUMANASCSI2_ALATCH);
+		writeb(ALATCH_DIS_BIT32, info->base + CUMANASCSI2_ALATCH);
 		return fasdma_real_all;
 	}
 
@@ -224,7 +223,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 #if 0
 		while (length > 1) {
 			unsigned long word;
-			unsigned int status = readb(info->status);
+			unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
 
 			if (status & STATUS_INT)
 				goto end;
@@ -233,7 +232,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 				continue;
 
 			word = *addr | *(addr + 1) << 8;
-			writew(word, info->dmaarea);
+			writew(word, info->base + CUMANASCSI2_PSEUDODMA);
 			addr += 2;
 			length -= 2;
 		}
@@ -243,7 +242,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 	else {
 		if (transfer && (transfer & 255)) {
 			while (length >= 256) {
-				unsigned int status = readb(info->status);
+				unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
 
 				if (status & STATUS_INT)
 					return;
@@ -251,7 +250,8 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 				if (!(status & STATUS_DRQ))
 					continue;
 
-				readsw(info->dmaarea, addr, 256 >> 1);
+				readsw(info->base + CUMANASCSI2_PSEUDODMA,
+				       addr, 256 >> 1);
 				addr += 256;
 				length -= 256;
 			}
@@ -259,7 +259,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 
 		while (length > 0) {
 			unsigned long word;
-			unsigned int status = readb(info->status);
+			unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
 
 			if (status & STATUS_INT)
 				return;
@@ -267,7 +267,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host
 			if (!(status & STATUS_DRQ))
 				continue;
 
-			word = readw(info->dmaarea);
+			word = readw(info->base + CUMANASCSI2_PSEUDODMA);
 			*addr++ = word;
 			if (--length > 0) {
 				*addr++ = word >> 8;
@@ -286,9 +286,9 @@ static void
 cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
 {
 	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	if (host->dma_channel != NO_DMA) {
-		writeb(ALATCH_DIS_DMA, info->alatch);
-		disable_dma(host->dma_channel);
+	if (info->info.scsi.dma != NO_DMA) {
+		writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH);
+		disable_dma(info->info.scsi.dma);
 	}
 }
 
@@ -405,7 +405,7 @@ cumanascsi2_probe(struct expansion_card 
 	struct Scsi_Host *host;
 	struct cumanascsi2_info *info;
 	unsigned long resbase, reslen;
-	unsigned char *base;
+	void __iomem *base;
 	int ret;
 
 	ret = ecard_request_resources(ec);
@@ -427,28 +427,18 @@ cumanascsi2_probe(struct expansion_card 
 		goto out_unmap;
 	}
 
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
 	ecard_set_drvdata(ec, host);
 
 	info = (struct cumanascsi2_info *)host->hostdata;
 	info->ec	= ec;
-	info->dmaarea	= base + CUMANASCSI2_PSEUDODMA;
-	info->status	= base + CUMANASCSI2_STATUS;
-	info->alatch	= base + CUMANASCSI2_ALATCH;
-
-	ec->irqaddr	= info->status;
-	ec->irqmask	= STATUS_INT;
-	ec->irq_data	= base + CUMANASCSI2_ALATCH;
-	ec->ops		= &cumanascsi_2_ops;
+	info->base	= base;
 
 	cumanascsi_2_terminator_ctl(host, term[ec->slot_no]);
 
 	info->info.scsi.io_base		= base + CUMANASCSI2_FAS216_OFFSET;
 	info->info.scsi.io_shift	= CUMANASCSI2_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
 	info->info.ifcfg.clockrate	= 40; /* MHz */
 	info->info.ifcfg.select_timeout	= 255;
 	info->info.ifcfg.asyncperiod	= 200; /* ns */
@@ -461,25 +451,30 @@ cumanascsi2_probe(struct expansion_card 
 	info->info.dma.pseudo		= cumanascsi_2_dma_pseudo;
 	info->info.dma.stop		= cumanascsi_2_dma_stop;
 
+	ec->irqaddr	= info->base + CUMANASCSI2_STATUS;
+	ec->irqmask	= STATUS_INT;
+	ec->irq_data	= info;
+	ec->ops		= &cumanascsi_2_ops;
+
 	ret = fas216_init(host);
 	if (ret)
 		goto out_free;
 
-	ret = request_irq(host->irq, cumanascsi_2_intr,
+	ret = request_irq(ec->irq, cumanascsi_2_intr,
 			  SA_INTERRUPT, "cumanascsi2", info);
 	if (ret) {
 		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
+		       host->host_no, ec->irq, ret);
 		goto out_release;
 	}
 
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "cumanascsi2")) {
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "cumanascsi2")) {
 			printk("scsi%d: DMA%d not free, using PIO\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
 		} else {
-			set_dma_speed(host->dma_channel, 180);
+			set_dma_speed(info->info.scsi.dma, 180);
 			info->info.ifcfg.capabilities |= FASCAP_DMA;
 		}
 	}
@@ -488,9 +483,9 @@ cumanascsi2_probe(struct expansion_card 
 	if (ret == 0)
 		goto out;
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
 
  out_release:
 	fas216_release(host);
@@ -516,11 +511,11 @@ static void __devexit cumanascsi2_remove
 	ecard_set_drvdata(ec, NULL);
 	fas216_remove(host);
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
 
-	iounmap((void *)host->base);
+	iounmap(info->base);
 
 	fas216_release(host);
 	scsi_host_put(host);
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/acorn/scsi/eesox.c
  *
- *  Copyright (C) 1997-2003 Russell King
+ *  Copyright (C) 1997-2005 Russell King
  *
  * 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
@@ -73,8 +73,8 @@ static int term[MAX_ECARDS] = { 1, 1, 1,
 struct eesoxscsi_info {
 	FAS216_Info		info;
 	struct expansion_card	*ec;
-
-	void			*ctl_port;
+	void __iomem		*base;
+	void __iomem		*ctl_port;
 	unsigned int		control;
 	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
 };
@@ -163,7 +163,7 @@ eesoxscsi_dma_setup(struct Scsi_Host *ho
 {
 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
+	int dmach = info->info.scsi.dma;
 
 	if (dmach != NO_DMA &&
 	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
@@ -194,11 +194,11 @@ eesoxscsi_dma_setup(struct Scsi_Host *ho
 	return fasdma_pseudo;
 }
 
-static void eesoxscsi_buffer_in(void *buf, int length, void *base)
+static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
 {
-	const void *reg_fas = base + EESOX_FAS216_OFFSET;
-	const void *reg_dmastat = base + EESOX_DMASTAT;
-	const void *reg_dmadata = base + EESOX_DMADATA;
+	const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
+	const void __iomem *reg_dmadata = base + EESOX_DMADATA;
 	const register unsigned long mask = 0xffff;
 
 	do {
@@ -272,11 +272,11 @@ static void eesoxscsi_buffer_in(void *bu
 	} while (length);
 }
 
-static void eesoxscsi_buffer_out(void *buf, int length, void *base)
+static void eesoxscsi_buffer_out(void *buf, int length, void __iomem *base)
 {
-	const void *reg_fas = base + EESOX_FAS216_OFFSET;
-	const void *reg_dmastat = base + EESOX_DMASTAT;
-	const void *reg_dmadata = base + EESOX_DMADATA;
+	const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
+	const void __iomem *reg_dmadata = base + EESOX_DMADATA;
 
 	do {
 		unsigned int status;
@@ -356,11 +356,11 @@ static void
 eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
 		     fasdmadir_t dir, int transfer_size)
 {
-	void *base = (void *)host->base;
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 	if (dir == DMA_IN) {
-		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base);
+		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, info->base);
 	} else {
-		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base);
+		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, info->base);
 	}
 }
 
@@ -372,8 +372,9 @@ eesoxscsi_dma_pseudo(struct Scsi_Host *h
 static void
 eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
 {
-	if (host->dma_channel != NO_DMA)
-		disable_dma(host->dma_channel);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	if (info->info.scsi.dma != NO_DMA)
+		disable_dma(info->info.scsi.dma);
 }
 
 /* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
@@ -522,7 +523,7 @@ eesoxscsi_probe(struct expansion_card *e
 	struct Scsi_Host *host;
 	struct eesoxscsi_info *info;
 	unsigned long resbase, reslen;
-	unsigned char *base;
+	void __iomem *base;
 	int ret;
 
 	ret = ecard_request_resources(ec);
@@ -544,26 +545,19 @@ eesoxscsi_probe(struct expansion_card *e
 		goto out_unmap;
 	}
 
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
 	ecard_set_drvdata(ec, host);
 
 	info = (struct eesoxscsi_info *)host->hostdata;
 	info->ec	= ec;
+	info->base	= base;
 	info->ctl_port	= base + EESOX_CONTROL;
 	info->control	= term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
 	writeb(info->control, info->ctl_port);
 
-	ec->irqaddr	= base + EESOX_DMASTAT;
-	ec->irqmask	= EESOX_STAT_INTR;
-	ec->irq_data	= info;
-	ec->ops		= &eesoxscsi_ops;
-
 	info->info.scsi.io_base		= base + EESOX_FAS216_OFFSET;
 	info->info.scsi.io_shift	= EESOX_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
 	info->info.ifcfg.clockrate	= 40; /* MHz */
 	info->info.ifcfg.select_timeout	= 255;
 	info->info.ifcfg.asyncperiod	= 200; /* ns */
@@ -576,26 +570,31 @@ eesoxscsi_probe(struct expansion_card *e
 	info->info.dma.pseudo		= eesoxscsi_dma_pseudo;
 	info->info.dma.stop		= eesoxscsi_dma_stop;
 
+	ec->irqaddr	= base + EESOX_DMASTAT;
+	ec->irqmask	= EESOX_STAT_INTR;
+	ec->irq_data	= info;
+	ec->ops		= &eesoxscsi_ops;
+
 	device_create_file(&ec->dev, &dev_attr_bus_term);
 
 	ret = fas216_init(host);
 	if (ret)
 		goto out_free;
 
-	ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
+	ret = request_irq(ec->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
 	if (ret) {
 		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
+		       host->host_no, ec->irq, ret);
 		goto out_remove;
 	}
 
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "eesox")) {
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "eesox")) {
 			printk("scsi%d: DMA%d not free, DMA disabled\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
 		} else {
-			set_dma_speed(host->dma_channel, 180);
+			set_dma_speed(info->info.scsi.dma, 180);
 			info->info.ifcfg.capabilities |= FASCAP_DMA;
 			info->info.ifcfg.cntl3 |= CNTL3_BS8;
 		}
@@ -605,9 +604,9 @@ eesoxscsi_probe(struct expansion_card *e
 	if (ret == 0)
 		goto out;
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
 
  out_remove:
 	fas216_remove(host);
@@ -634,13 +633,13 @@ static void __devexit eesoxscsi_remove(s
 	ecard_set_drvdata(ec, NULL);
 	fas216_remove(host);
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
 
 	device_remove_file(&ec->dev, &dev_attr_bus_term);
 
-	iounmap((void *)host->base);
+	iounmap(info->base);
 
 	fas216_release(host);
 	scsi_host_put(host);
@@ -679,4 +678,3 @@ MODULE_DESCRIPTION("EESOX 'Fast' SCSI dr
 MODULE_PARM(term, "1-8i");
 MODULE_PARM_DESC(term, "SCSI bus termination");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -52,6 +52,7 @@
 #include <asm/ecard.h>
 
 #include "../scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include "fas216.h"
 #include "scsi.h"
@@ -142,19 +143,13 @@ __setup("fas216_logging=", fas216_log_se
 static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
 {
 	unsigned int off = reg << info->scsi.io_shift;
-	if (info->scsi.io_base)
-		return readb(info->scsi.io_base + off);
-	else
-		return inb(info->scsi.io_port + off);
+	return readb(info->scsi.io_base + off);
 }
 
 static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val)
 {
 	unsigned int off = reg << info->scsi.io_shift;
-	if (info->scsi.io_base)
-		writeb(val, info->scsi.io_base + off);
-	else
-		outb(val, info->scsi.io_port + off);
+	writeb(val, info->scsi.io_base + off);
 }
 
 static void fas216_dumpstate(FAS216_Info *info)
@@ -197,8 +192,8 @@ static void fas216_dumpinfo(FAS216_Info 
 	printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",
 		info->magic_start, info->host, info->SCpnt,
 		info->origSCpnt);
-	printk("    scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
-		info->scsi.io_port, info->scsi.io_shift, info->scsi.irq,
+	printk("    scsi={ io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
+		info->scsi.io_shift, info->scsi.irq,
 		info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],
 		info->scsi.cfg[3]);
 	printk("           type=%p phase=%X\n",
@@ -315,7 +310,7 @@ fas216_log_command(FAS216_Info *info, in
 	va_end(args);
 
 	printk(" CDB: ");
-	print_command(SCpnt->cmnd);
+	__scsi_print_command(SCpnt->cmnd);
 }
 
 static void
@@ -2087,7 +2082,7 @@ fas216_std_done(FAS216_Info *info, Scsi_
 				info->host->host_no, '0' + SCpnt->device->id,
 				SCpnt->result, info->scsi.SCp.ptr,
 				info->scsi.SCp.this_residual);
-			print_command(SCpnt->cmnd);
+			__scsi_print_command(SCpnt->cmnd);
 			SCpnt->result &= ~(255 << 16);
 			SCpnt->result |= DID_BAD_TARGET << 16;
 			goto request_sense;
@@ -2122,7 +2117,7 @@ request_sense:
 	SCpnt->SCp.Message = 0;
 	SCpnt->SCp.Status = 0;
 	SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-	SCpnt->sc_data_direction = SCSI_DATA_READ;
+	SCpnt->sc_data_direction = DMA_FROM_DEVICE;
 	SCpnt->use_sg = 0;
 	SCpnt->tag = 0;
 	SCpnt->host_scribble = (void *)fas216_rq_sns_done;
@@ -2176,7 +2171,7 @@ static void fas216_done(FAS216_Info *inf
 		       info->host->host_no, '0' + SCpnt->device->id,
 		       info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
 		info->scsi.SCp.ptr = NULL;
-		print_command(SCpnt->cmnd);
+		__scsi_print_command(SCpnt->cmnd);
 	}
 
 	/*
@@ -2432,7 +2427,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
 	info->stats.aborts += 1;
 
 	printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
-	print_command(SCpnt->data_cmnd);
+	__scsi_print_command(SCpnt->data_cmnd);
 
 	print_debug_list();
 	fas216_dumpstate(info);
@@ -2967,11 +2962,11 @@ int fas216_print_host(FAS216_Info *info,
 	return sprintf(buffer,
 			"\n"
 			"Chip    : %s\n"
-			" Address: 0x%08lx\n"
+			" Address: 0x%p\n"
 			" IRQ    : %d\n"
 			" DMA    : %d\n",
-			info->scsi.type, info->host->io_port,
-			info->host->irq, info->host->dma_channel);
+			info->scsi.type, info->scsi.io_base,
+			info->scsi.irq, info->scsi.dma);
 }
 
 int fas216_print_stats(FAS216_Info *info, char *buffer)
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -236,12 +236,12 @@ typedef struct {
 	/* driver information */
 	struct {
 		phase_t		phase;			/* current phase			*/
-		void		*io_base;		/* iomem base of FAS216			*/
-		unsigned int	io_port;		/* base address of FAS216		*/
+		void __iomem	*io_base;		/* iomem base of FAS216			*/
 		unsigned int	io_shift;		/* shift to adjust reg offsets by	*/
 		unsigned char	cfg[4];			/* configuration registers		*/
 		const char	*type;			/* chip type				*/
 		unsigned int	irq;			/* interrupt				*/
+		int		dma;			/* dma channel				*/
 
 		Scsi_Pointer	SCp;			/* current commands data pointer	*/
 
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/acorn/scsi/powertec.c
  *
- *  Copyright (C) 1997-2003 Russell King
+ *  Copyright (C) 1997-2005 Russell King
  *
  * 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
@@ -61,7 +61,7 @@ static int term[MAX_ECARDS] = { 1, 1, 1,
 struct powertec_info {
 	FAS216_Info		info;
 	struct expansion_card	*ec;
-	void			*term_port;
+	void __iomem		*base;
 	unsigned int		term_ctl;
 	struct scatterlist	sg[NR_SG];
 };
@@ -74,7 +74,8 @@ struct powertec_info {
 static void
 powertecscsi_irqenable(struct expansion_card *ec, int irqnr)
 {
-	writeb(POWERTEC_INTR_ENABLE, ec->irq_data);
+	struct powertec_info *info = ec->irq_data;
+	writeb(POWERTEC_INTR_ENABLE, info->base + POWERTEC_INTR_CONTROL);
 }
 
 /* Prototype: void powertecscsi_irqdisable(ec, irqnr)
@@ -85,7 +86,8 @@ powertecscsi_irqenable(struct expansion_
 static void
 powertecscsi_irqdisable(struct expansion_card *ec, int irqnr)
 {
-	writeb(POWERTEC_INTR_DISABLE, ec->irq_data);
+	struct powertec_info *info = ec->irq_data;
+	writeb(POWERTEC_INTR_DISABLE, info->base + POWERTEC_INTR_CONTROL);
 }
 
 static const expansioncard_ops_t powertecscsi_ops = {
@@ -104,7 +106,7 @@ powertecscsi_terminator_ctl(struct Scsi_
 	struct powertec_info *info = (struct powertec_info *)host->hostdata;
 
 	info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0;
-	writeb(info->term_ctl, info->term_port);
+	writeb(info->term_ctl, info->base + POWERTEC_TERM_CONTROL);
 }
 
 /* Prototype: void powertecscsi_intr(irq, *dev_id, *regs)
@@ -135,7 +137,7 @@ powertecscsi_dma_setup(struct Scsi_Host 
 {
 	struct powertec_info *info = (struct powertec_info *)host->hostdata;
 	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
+	int dmach = info->info.scsi.dma;
 
 	if (info->info.ifcfg.capabilities & FASCAP_DMA &&
 	    min_type == fasdma_real_all) {
@@ -174,8 +176,9 @@ powertecscsi_dma_setup(struct Scsi_Host 
 static void
 powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
 {
-	if (host->dma_channel != NO_DMA)
-		disable_dma(host->dma_channel);
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	if (info->info.scsi.dma != NO_DMA)
+		disable_dma(info->info.scsi.dma);
 }
 
 /* Prototype: const char *powertecscsi_info(struct Scsi_Host * host)
@@ -315,7 +318,7 @@ powertecscsi_probe(struct expansion_card
 	struct Scsi_Host *host;
 	struct powertec_info *info;
 	unsigned long resbase, reslen;
-	unsigned char *base;
+	void __iomem *base;
 	int ret;
 
 	ret = ecard_request_resources(ec);
@@ -337,26 +340,16 @@ powertecscsi_probe(struct expansion_card
 		goto out_unmap;
 	}
 
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
-	ec->irqaddr	= base + POWERTEC_INTR_STATUS;
-	ec->irqmask	= POWERTEC_INTR_BIT;
-	ec->irq_data	= base + POWERTEC_INTR_CONTROL;
-	ec->ops		= &powertecscsi_ops;
-
 	ecard_set_drvdata(ec, host);
 
 	info = (struct powertec_info *)host->hostdata;
-	info->term_port = base + POWERTEC_TERM_CONTROL;
+	info->base = base;
 	powertecscsi_terminator_ctl(host, term[ec->slot_no]);
 
-	device_create_file(&ec->dev, &dev_attr_bus_term);
-
 	info->info.scsi.io_base		= base + POWERTEC_FAS216_OFFSET;
 	info->info.scsi.io_shift	= POWERTEC_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
 	info->info.ifcfg.clockrate	= 40; /* MHz */
 	info->info.ifcfg.select_timeout	= 255;
 	info->info.ifcfg.asyncperiod	= 200; /* ns */
@@ -369,25 +362,32 @@ powertecscsi_probe(struct expansion_card
 	info->info.dma.pseudo		= NULL;
 	info->info.dma.stop		= powertecscsi_dma_stop;
 
+	ec->irqaddr	= base + POWERTEC_INTR_STATUS;
+	ec->irqmask	= POWERTEC_INTR_BIT;
+	ec->irq_data	= info;
+	ec->ops		= &powertecscsi_ops;
+
+	device_create_file(&ec->dev, &dev_attr_bus_term);
+
 	ret = fas216_init(host);
 	if (ret)
 		goto out_free;
 
-	ret = request_irq(host->irq, powertecscsi_intr,
+	ret = request_irq(ec->irq, powertecscsi_intr,
 			  SA_INTERRUPT, "powertec", info);
 	if (ret) {
 		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
+		       host->host_no, ec->irq, ret);
 		goto out_release;
 	}
 
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "powertec")) {
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "powertec")) {
 			printk("scsi%d: DMA%d not free, using PIO\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
 		} else {
-			set_dma_speed(host->dma_channel, 180);
+			set_dma_speed(info->info.scsi.dma, 180);
 			info->info.ifcfg.capabilities |= FASCAP_DMA;
 		}
 	}
@@ -396,9 +396,9 @@ powertecscsi_probe(struct expansion_card
 	if (ret == 0)
 		goto out;
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
 
  out_release:
 	fas216_release(host);
@@ -420,18 +420,18 @@ powertecscsi_probe(struct expansion_card
 static void __devexit powertecscsi_remove(struct expansion_card *ec)
 {
 	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct powertecscsi_info *info = (struct powertecscsi_info *)host->hostdata;
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
 
 	ecard_set_drvdata(ec, NULL);
 	fas216_remove(host);
 
 	device_remove_file(&ec->dev, &dev_attr_bus_term);
 
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
 
-	iounmap((void *)host->base);
+	iounmap(info->base);
 
 	fas216_release(host);
 	scsi_host_put(host);
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -108,7 +108,7 @@ static inline void init_SCp(Scsi_Cmnd *S
 #if 0 //def BELT_AND_BRACES
 		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
 		       "command ", SCpnt->host->host_no, '0' + SCpnt->target);
-		print_command(SCpnt->cmnd);
+		__scsi_print_command(SCpnt->cmnd);
 #endif
 		SCpnt->SCp.ptr = NULL;
 	}
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -61,6 +61,7 @@ enum {
 	ich6_sata		= 3,
 	ich6_sata_rm		= 4,
 	ich7_sata		= 5,
+	esb2_sata		= 6,
 };
 
 static int piix_init_one (struct pci_dev *pdev,
@@ -93,6 +94,7 @@ static struct pci_device_id piix_pci_tbl
 	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
 	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
 	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+	{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb2_sata },
 
 	{ }	/* terminate list */
 };
@@ -121,6 +123,7 @@ static Scsi_Host_Template piix_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations piix_pata_ops = {
@@ -150,6 +153,7 @@ static struct ata_port_operations piix_p
 
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_operations piix_sata_ops = {
@@ -177,6 +181,7 @@ static struct ata_port_operations piix_s
 
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info piix_port_info[] = {
@@ -255,6 +260,18 @@ static struct ata_port_info piix_port_in
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
 	},
+
+	/* esb2_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -648,15 +665,6 @@ static int piix_init_one (struct pci_dev
 	return ata_pci_init_one(pdev, port_info, n_ports);
 }
 
-/**
- *	piix_init -
- *
- *	LOCKING:
- *
- *	RETURNS:
- *
- */
-
 static int __init piix_init(void)
 {
 	int rc;
@@ -672,13 +680,6 @@ static int __init piix_init(void)
 	return 0;
 }
 
-/**
- *	piix_exit -
- *
- *	LOCKING:
- *
- */
-
 static void __exit piix_exit(void)
 {
 	pci_unregister_driver(&piix_pci_driver);
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -73,6 +73,7 @@
  * 1.  Test linked command handling code after Eric is ready with 
  *     the high level code.
  */
+#include <scsi/scsi_dbg.h>
 
 #if (NDEBUG & NDEBUG_LISTS)
 #define LIST(x,y) \
@@ -2354,7 +2355,7 @@ static void NCR5380_information_transfer
  * 3..length+1	arguments
  *
  * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since print_msg() wants the whole thing.  
+ * byte, since scsi_print_msg() wants the whole thing.  
  */
 		    extended_msg[0] = EXTENDED_MESSAGE;
 		    /* Accept first byte by clearing ACK */
@@ -2407,7 +2408,7 @@ static void NCR5380_information_transfer
 		default:
 		    if (!tmp) {
 			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
-			print_msg (extended_msg);
+			scsi_print_msg (extended_msg);
 			printk("\n");
 		    } else if (tmp != EXTENDED_MESSAGE)
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
@@ -2540,7 +2541,7 @@ static void NCR5380_reselect (struct Scs
 
     if (!(msg[0] & 0x80)) {
 	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
-	print_msg(msg);
+	scsi_print_msg(msg);
 	do_abort(instance);
 	return;
     }
@@ -2646,7 +2647,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
     unsigned long flags;
 
     printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
-    print_Scsi_Cmnd (cmd);
+    scsi_print_command(cmd);
 
     NCR5380_print_status (instance);
 
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -1,4 +1,4 @@
-/*
+/* 
  *  Copyright (C) 1997	Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
  *  2.5.x update (C) 2002  Red Hat <alan@redhat.com>
@@ -13,8 +13,9 @@
  *		   fix disconnect bug  2000/12/21
  *		   support atp880 chip lvd u160 2001/05/15
  *		   fix prd table bug 2001/09/12 (7.1)
+ *
+ * atp885 support add by ACARD Hao Ping Lian 2005/01/05
  */
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -38,39 +39,54 @@
 #include "atp870u.h"
 
 static struct scsi_host_template atp870u_template;
-static void send_s870(struct Scsi_Host *host);
+static void send_s870(struct atp_unit *dev,unsigned char c);
+static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
+static void tscam_885(void);
 
-
-static irqreturn_t atp870u_intr_handle(int irq, void *dev_id,
-					struct pt_regs *regs)
+static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
 	unsigned short int tmpcip, id;
-	unsigned char i, j, target_id, lun;
+	unsigned char i, j, c, target_id, lun,cmdp;
 	unsigned char *prd;
-	struct scsi_cmnd *workrequ;
-	unsigned int workportu, tmport;
-	unsigned long adrcntu, k;
+	struct scsi_cmnd *workreq;
+	unsigned int workport, tmport, tmport1;
+	unsigned long adrcnt, k;
+#ifdef ED_DBGP
+	unsigned long l;
+#endif
 	int errstus;
 	struct Scsi_Host *host = dev_id;
 	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
 
-	dev->in_int = 1;
-	workportu = dev->ioport;
-	tmport = workportu;
-
-	if (dev->working != 0) {
-		tmport += 0x1f;
+	for (c = 0; c < 2; c++) {
+		tmport = dev->ioport[c] + 0x1f;
 		j = inb(tmport);
-		if ((j & 0x80) == 0) {
-			dev->in_int = 0;
-			return IRQ_NONE;
-		}
-
-		tmpcip = dev->pciport;
-		if ((inb(tmpcip) & 0x08) != 0) {
+		if ((j & 0x80) != 0)
+		{			
+	   		goto ch_sel;
+		}
+		dev->in_int[c] = 0;
+	}
+	return IRQ_NONE;
+ch_sel:
+#ifdef ED_DBGP	
+	printk("atp870u_intr_handle enter\n");
+#endif	
+	dev->in_int[c] = 1;
+	cmdp = inb(dev->ioport[c] + 0x10);
+	workport = dev->ioport[c];
+	if (dev->working[c] != 0) {
+		if (dev->dev_id == ATP885_DEVID) {
+			tmport1 = workport + 0x16;
+			if ((inb(tmport1) & 0x80) == 0)
+				outb((inb(tmport1) | 0x80), tmport1);
+		}		
+		tmpcip = dev->pciport[c];
+		if ((inb(tmpcip) & 0x08) != 0)
+		{
 			tmpcip += 0x2;
-			for (k = 0; k < 1000; k++) {
+			for (k=0; k < 1000; k++) {
 				if ((inb(tmpcip) & 0x08) == 0) {
 					goto stop_dma;
 				}
@@ -80,18 +96,24 @@ static irqreturn_t atp870u_intr_handle(i
 			}
 		}
 stop_dma:
-		tmpcip = dev->pciport;
+		tmpcip = dev->pciport[c];
 		outb(0x00, tmpcip);
 		tmport -= 0x08;
-
+		
 		i = inb(tmport);
+		
+		if (dev->dev_id == ATP885_DEVID) {
+			tmpcip += 2;
+			outb(0x06, tmpcip);
+			tmpcip -= 2;
+		}
 
 		tmport -= 0x02;
 		target_id = inb(tmport);
 		tmport += 0x02;
 
 		/*
-		 *      Remap wide devices onto id numbers
+		 *	Remap wide devices onto id numbers
 		 */
 
 		if ((target_id & 0x40) != 0) {
@@ -101,332 +123,460 @@ stop_dma:
 		}
 
 		if ((j & 0x40) != 0) {
-			if (dev->last_cmd == 0xff) {
-				dev->last_cmd = target_id;
-			}
-			dev->last_cmd |= 0x40;
-		}
-
+		     if (dev->last_cmd[c] == 0xff) {
+			dev->last_cmd[c] = target_id;
+		     }
+		     dev->last_cmd[c] |= 0x40;
+		}
+		if (dev->dev_id == ATP885_DEVID) 
+			dev->r1f[c][target_id] |= j;
+#ifdef ED_DBGP
+		printk("atp870u_intr_handle status = %x\n",i);
+#endif	
 		if (i == 0x85) {
-			if ((dev->last_cmd & 0xf0) != 0x40) {
-				dev->last_cmd = 0xff;
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
+			}
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport -= 0x05;
+				adrcnt = 0;
+				((unsigned char *) &adrcnt)[2] = inb(tmport++);
+				((unsigned char *) &adrcnt)[1] = inb(tmport++);
+				((unsigned char *) &adrcnt)[0] = inb(tmport);
+				if (dev->id[c][target_id].last_len != adrcnt)
+				{
+			   		k = dev->id[c][target_id].last_len;
+			   		k -= adrcnt;
+			   		dev->id[c][target_id].tran_len = k;			   
+			   	dev->id[c][target_id].last_len = adrcnt;			   
+				}
+#ifdef ED_DBGP
+				printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+#endif		
 			}
+
 			/*
 			 *      Flip wide
-			 */
-			if (dev->wide_idu != 0) {
-				tmport = workportu + 0x1b;
+			 */			
+			if (dev->wide_id[c] != 0) {
+				tmport = workport + 0x1b;
 				outb(0x01, tmport);
 				while ((inb(tmport) & 0x01) != 0x01) {
 					outb(0x01, tmport);
 				}
-			}
+			}		
 			/*
-			 *      Issue more commands
+			 *	Issue more commands
 			 */
-			spin_lock_irqsave(dev->host->host_lock, flags);
-			if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && (dev->in_snd == 0)) {
-				send_s870(host);
+			spin_lock_irqsave(dev->host->host_lock, flags);			 			 
+			if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) &&
+			    (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+				printk("Call sent_s870\n");
+#endif				
+				send_s870(dev,c);
 			}
 			spin_unlock_irqrestore(dev->host->host_lock, flags);
 			/*
-			 *      Done
+			 *	Done
 			 */
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("Status 0x85 return\n");
+#endif				
+			goto handled;
 		}
 
 		if (i == 0x40) {
-			dev->last_cmd |= 0x40;
-			dev->in_int = 0;
-			goto out;
+		     dev->last_cmd[c] |= 0x40;
+		     dev->in_int[c] = 0;
+		     goto handled;
 		}
 
 		if (i == 0x21) {
-			if ((dev->last_cmd & 0xf0) != 0x40) {
-				dev->last_cmd = 0xff;
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
 			}
 			tmport -= 0x05;
-			adrcntu = 0;
-			((unsigned char *) &adrcntu)[2] = inb(tmport++);
-			((unsigned char *) &adrcntu)[1] = inb(tmport++);
-			((unsigned char *) &adrcntu)[0] = inb(tmport);
-			k = dev->id[target_id].last_lenu;
-			k -= adrcntu;
-			dev->id[target_id].tran_lenu = k;
-			dev->id[target_id].last_lenu = adrcntu;
+			adrcnt = 0;
+			((unsigned char *) &adrcnt)[2] = inb(tmport++);
+			((unsigned char *) &adrcnt)[1] = inb(tmport++);
+			((unsigned char *) &adrcnt)[0] = inb(tmport);
+			k = dev->id[c][target_id].last_len;
+			k -= adrcnt;
+			dev->id[c][target_id].tran_len = k;
+			dev->id[c][target_id].last_len = adrcnt;
 			tmport -= 0x04;
 			outb(0x41, tmport);
 			tmport += 0x08;
 			outb(0x08, tmport);
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+			goto handled;
+		}
+
+		if (dev->dev_id == ATP885_DEVID) {
+			if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
+		   		if ((i == 0x4c) || (i == 0x8c)) 
+		      			i=0x48;
+		   		else 
+		      			i=0x49;
+		   	}	
+			
 		}
 		if ((i == 0x80) || (i == 0x8f)) {
+#ifdef ED_DBGP
+			printk(KERN_DEBUG "Device reselect\n");
+#endif			
 			lun = 0;
 			tmport -= 0x07;
-			j = inb(tmport);
-			if (j == 0x44 || i == 0x80) {
+			if (cmdp == 0x44 || i==0x80) {
 				tmport += 0x0d;
 				lun = inb(tmport) & 0x07;
 			} else {
-				if ((dev->last_cmd & 0xf0) != 0x40) {
-					dev->last_cmd = 0xff;
+				if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+				   dev->last_cmd[c] = 0xff;
 				}
-				if (j == 0x41) {
+				if (cmdp == 0x41) {
+#ifdef ED_DBGP
+					printk("cmdp = 0x41\n");
+#endif						
 					tmport += 0x02;
-					adrcntu = 0;
-					((unsigned char *) &adrcntu)[2] = inb(tmport++);
-					((unsigned char *) &adrcntu)[1] = inb(tmport++);
-					((unsigned char *) &adrcntu)[0] = inb(tmport);
-					k = dev->id[target_id].last_lenu;
-					k -= adrcntu;
-					dev->id[target_id].tran_lenu = k;
-					dev->id[target_id].last_lenu = adrcntu;
+					adrcnt = 0;
+					((unsigned char *) &adrcnt)[2] = inb(tmport++);
+					((unsigned char *) &adrcnt)[1] = inb(tmport++);
+					((unsigned char *) &adrcnt)[0] = inb(tmport);
+					k = dev->id[c][target_id].last_len;
+					k -= adrcnt;
+					dev->id[c][target_id].tran_len = k;
+					dev->id[c][target_id].last_len = adrcnt;
 					tmport += 0x04;
 					outb(0x08, tmport);
-					dev->in_int = 0;
-					goto out;
+					dev->in_int[c] = 0;
+					goto handled;
 				} else {
+#ifdef ED_DBGP
+					printk("cmdp != 0x41\n");
+#endif						
 					outb(0x46, tmport);
-					dev->id[target_id].dirctu = 0x00;
+					dev->id[c][target_id].dirct = 0x00;
 					tmport += 0x02;
 					outb(0x00, tmport++);
 					outb(0x00, tmport++);
 					outb(0x00, tmport++);
 					tmport += 0x03;
 					outb(0x08, tmport);
-					dev->in_int = 0;
-					goto out;
+					dev->in_int[c] = 0;
+					goto handled;
 				}
 			}
-			if (dev->last_cmd != 0xff) {
-				dev->last_cmd |= 0x40;
+			if (dev->last_cmd[c] != 0xff) {
+			   dev->last_cmd[c] |= 0x40;
 			}
-			tmport = workportu + 0x10;
-			outb(0x45, tmport);
-			tmport += 0x06;
+			if (dev->dev_id == ATP885_DEVID) {
+				j = inb(dev->baseport + 0x29) & 0xfe;
+				outb(j, dev->baseport + 0x29);
+				tmport = workport + 0x16;
+			} else {
+				tmport = workport + 0x10;
+				outb(0x45, tmport);
+				tmport += 0x06;				
+			}
+			
 			target_id = inb(tmport);
 			/*
-			 *      Remap wide identifiers
+			 *	Remap wide identifiers
 			 */
 			if ((target_id & 0x10) != 0) {
 				target_id = (target_id & 0x07) | 0x08;
 			} else {
 				target_id &= 0x07;
 			}
-			workrequ = dev->id[target_id].curr_req;
-			tmport = workportu + 0x0f;
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport = workport + 0x10;
+				outb(0x45, tmport);
+			}
+			workreq = dev->id[c][target_id].curr_req;
+#ifdef ED_DBGP			
+			printk(KERN_DEBUG "Channel = %d ID = %d LUN = %d CDB",c,workreq->device->id,workreq->device->lun);
+			for(l=0;l<workreq->cmd_len;l++)
+			{
+				printk(KERN_DEBUG " %x",workreq->cmnd[l]);
+			}
+#endif	
+			
+			tmport = workport + 0x0f;
 			outb(lun, tmport);
 			tmport += 0x02;
-			outb(dev->id[target_id].devspu, tmport++);
-			adrcntu = dev->id[target_id].tran_lenu;
-			k = dev->id[target_id].last_lenu;
+			outb(dev->id[c][target_id].devsp, tmport++);
+			adrcnt = dev->id[c][target_id].tran_len;
+			k = dev->id[c][target_id].last_len;
+
 			outb(((unsigned char *) &k)[2], tmport++);
 			outb(((unsigned char *) &k)[1], tmport++);
 			outb(((unsigned char *) &k)[0], tmport++);
+#ifdef ED_DBGP			
+			printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+#endif			
 			/* Remap wide */
 			j = target_id;
 			if (target_id > 7) {
 				j = (j & 0x07) | 0x40;
 			}
 			/* Add direction */
-			j |= dev->id[target_id].dirctu;
+			j |= dev->id[c][target_id].dirct;
 			outb(j, tmport++);
-			outb(0x80, tmport);
-
-			/* enable 32 bit fifo transfer */
-			if (dev->deviceid != 0x8081) {
-				tmport = workportu + 0x3a;
-				if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) {
-					outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
-				} else {
-					outb((unsigned char) (inb(tmport) & 0xf3), tmport);
+			outb(0x80,tmport);
+			
+			/* enable 32 bit fifo transfer */	
+			if (dev->dev_id == ATP885_DEVID) {
+				tmpcip = dev->pciport[c] + 1;
+				i=inb(tmpcip) & 0xf3;
+				//j=workreq->cmnd[0];	    		    	
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+				   i |= 0x0c;
 				}
-			} else {
-				tmport = workportu - 0x05;
-				if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) {
+				outb(i,tmpcip);		    		    		
+			} else if ((dev->dev_id == ATP880_DEVID1) ||
+	    		    	   (dev->dev_id == ATP880_DEVID2) ) {
+				tmport = workport - 0x05;
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
 					outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
 				} else {
 					outb((unsigned char) (inb(tmport) & 0x3f), tmport);
 				}
-			}
-
-			tmport = workportu + 0x1b;
+			} else {				
+				tmport = workport + 0x3a;
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+					outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
+				} else {
+					outb((unsigned char) (inb(tmport) & 0xf3), tmport);
+				}														
+			}	
+			tmport = workport + 0x1b;
 			j = 0;
 			id = 1;
 			id = id << target_id;
 			/*
-			 *      Is this a wide device
+			 *	Is this a wide device
 			 */
-			if ((id & dev->wide_idu) != 0) {
+			if ((id & dev->wide_id[c]) != 0) {
 				j |= 0x01;
 			}
 			outb(j, tmport);
 			while ((inb(tmport) & 0x01) != j) {
-				outb(j, tmport);
+				outb(j,tmport);
 			}
-
-			if (dev->id[target_id].last_lenu == 0) {
-				tmport = workportu + 0x18;
+			if (dev->id[c][target_id].last_len == 0) {
+				tmport = workport + 0x18;
 				outb(0x08, tmport);
-				dev->in_int = 0;
-				goto out;
-			}
-			prd = dev->id[target_id].prd_posu;
-			while (adrcntu != 0) {
-				id = ((unsigned short int *) (prd))[2];
+				dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("dev->id[c][target_id].last_len = 0\n");
+#endif					
+				goto handled;
+			}
+#ifdef ED_DBGP
+			printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
+#endif			
+			prd = dev->id[c][target_id].prd_pos;
+			while (adrcnt != 0) {
+				id = ((unsigned short int *)prd)[2];
 				if (id == 0) {
 					k = 0x10000;
 				} else {
 					k = id;
 				}
-				if (k > adrcntu) {
-					((unsigned short int *) (prd))[2] = (unsigned short int)
-					    (k - adrcntu);
-					((unsigned long *) (prd))[0] += adrcntu;
-					adrcntu = 0;
-					dev->id[target_id].prd_posu = prd;
+				if (k > adrcnt) {
+					((unsigned short int *)prd)[2] = (unsigned short int)
+					    (k - adrcnt);
+					((unsigned long *)prd)[0] += adrcnt;
+					adrcnt = 0;
+					dev->id[c][target_id].prd_pos = prd;
 				} else {
-					adrcntu -= k;
-					dev->id[target_id].prdaddru += 0x08;
+					adrcnt -= k;
+					dev->id[c][target_id].prdaddr += 0x08;
 					prd += 0x08;
-					if (adrcntu == 0) {
-						dev->id[target_id].prd_posu = prd;
+					if (adrcnt == 0) {
+						dev->id[c][target_id].prd_pos = prd;
 					}
-				}
+				}				
 			}
-			tmpcip = dev->pciport + 0x04;
-			outl(dev->id[target_id].prdaddru, tmpcip);
-			tmpcip -= 0x02;
-			outb(0x06, tmpcip);
-			outb(0x00, tmpcip);
-			tmpcip -= 0x02;
-			tmport = workportu + 0x18;
+			tmpcip = dev->pciport[c] + 0x04;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
+#ifdef ED_DBGP
+			printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
+#endif
+			if (dev->dev_id == ATP885_DEVID) {
+				tmpcip -= 0x04;
+			} else {
+				tmpcip -= 0x02;
+				outb(0x06, tmpcip);
+				outb(0x00, tmpcip);
+				tmpcip -= 0x02;
+			}
+			tmport = workport + 0x18;
 			/*
-			 *      Check transfer direction
+			 *	Check transfer direction
 			 */
-			if (dev->id[target_id].dirctu != 0) {
+			if (dev->id[c][target_id].dirct != 0) {
 				outb(0x08, tmport);
 				outb(0x01, tmpcip);
-				dev->in_int = 0;
-				goto out;
+				dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("status 0x80 return dirct != 0\n");
+#endif				
+				goto handled;
 			}
 			outb(0x08, tmport);
 			outb(0x09, tmpcip);
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+#ifdef ED_DBGP
+			printk("status 0x80 return dirct = 0\n");
+#endif			
+			goto handled;
 		}
 
 		/*
-		 *      Current scsi request on this target
+		 *	Current scsi request on this target
 		 */
 
-		workrequ = dev->id[target_id].curr_req;
+		workreq = dev->id[c][target_id].curr_req;
 
 		if (i == 0x42) {
-			if ((dev->last_cmd & 0xf0) != 0x40) {
-				dev->last_cmd = 0xff;
+			if ((dev->last_cmd[c] & 0xf0) != 0x40)
+			{
+			   dev->last_cmd[c] = 0xff;
 			}
 			errstus = 0x02;
-			workrequ->result = errstus;
+			workreq->result = errstus;
 			goto go_42;
 		}
 		if (i == 0x16) {
-			if ((dev->last_cmd & 0xf0) != 0x40) {
-				dev->last_cmd = 0xff;
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
 			}
 			errstus = 0;
 			tmport -= 0x08;
 			errstus = inb(tmport);
-			workrequ->result = errstus;
+			if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
+			   printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+			   errstus = 0x02;
+			}
+			workreq->result = errstus;
 go_42:
+			if (dev->dev_id == ATP885_DEVID) {		
+				j = inb(dev->baseport + 0x29) | 0x01;
+				outb(j, dev->baseport + 0x29);
+			}
 			/*
-			 *      Complete the command
+			 *	Complete the command
 			 */
-			 
-			if (workrequ->use_sg) {
+			if (workreq->use_sg) {
 				pci_unmap_sg(dev->pdev,
-					(struct scatterlist *)workrequ->buffer,
-					workrequ->use_sg,
-					workrequ->sc_data_direction);
-			} else if (workrequ->request_bufflen &&
-					workrequ->sc_data_direction != DMA_NONE) {
+					(struct scatterlist *)workreq->buffer,
+					workreq->use_sg,
+					workreq->sc_data_direction);
+			} else if (workreq->request_bufflen &&
+					workreq->sc_data_direction != DMA_NONE) {
 				pci_unmap_single(dev->pdev,
-					workrequ->SCp.dma_handle,
-					workrequ->request_bufflen,
-					workrequ->sc_data_direction);
-			}
+					workreq->SCp.dma_handle,
+					workreq->request_bufflen,
+					workreq->sc_data_direction);
+			}			
 			spin_lock_irqsave(dev->host->host_lock, flags);
-			(*workrequ->scsi_done) (workrequ);
-
+			(*workreq->scsi_done) (workreq);
+#ifdef ED_DBGP
+			   printk("workreq->scsi_done\n");
+#endif	
 			/*
-			 *      Clear it off the queue
+			 *	Clear it off the queue
 			 */
-			dev->id[target_id].curr_req = NULL;
-			dev->working--;
+			dev->id[c][target_id].curr_req = NULL;
+			dev->working[c]--;
 			spin_unlock_irqrestore(dev->host->host_lock, flags);
 			/*
 			 *      Take it back wide
 			 */
-			if (dev->wide_idu != 0) {
-				tmport = workportu + 0x1b;
+			if (dev->wide_id[c] != 0) {
+				tmport = workport + 0x1b;
 				outb(0x01, tmport);
 				while ((inb(tmport) & 0x01) != 0x01) {
 					outb(0x01, tmport);
-				}
-			}
+				}       
+			} 
 			/*
-			 *      If there is stuff to send and nothing going then send it
+			 *	If there is stuff to send and nothing going then send it
 			 */
 			spin_lock_irqsave(dev->host->host_lock, flags);
-			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) {
-				send_s870(host);
+			if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) &&
+			    (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+			   printk("Call sent_s870(scsi_done)\n");
+#endif				   
+			   send_s870(dev,c);
 			}
 			spin_unlock_irqrestore(dev->host->host_lock, flags);
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+			goto handled;
 		}
-		if ((dev->last_cmd & 0xf0) != 0x40) {
-			dev->last_cmd = 0xff;
+		if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+		   dev->last_cmd[c] = 0xff;
 		}
 		if (i == 0x4f) {
 			i = 0x89;
 		}
 		i &= 0x0f;
 		if (i == 0x09) {
-			tmpcip = tmpcip + 4;
-			outl(dev->id[target_id].prdaddru, tmpcip);
+			tmpcip += 4;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
 			tmpcip = tmpcip - 2;
 			outb(0x06, tmpcip);
 			outb(0x00, tmpcip);
 			tmpcip = tmpcip - 2;
-			tmport = workportu + 0x10;
+			tmport = workport + 0x10;
 			outb(0x41, tmport);
-			dev->id[target_id].dirctu = 0x00;
-			tmport += 0x08;
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport += 2;
+				k = dev->id[c][target_id].last_len;
+				outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+				dev->id[c][target_id].dirct = 0x00;
+				tmport += 0x04;
+			} else {
+				dev->id[c][target_id].dirct = 0x00;
+				tmport += 0x08;				
+			}
 			outb(0x08, tmport);
 			outb(0x09, tmpcip);
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+			goto handled;
 		}
 		if (i == 0x08) {
-			tmpcip = tmpcip + 4;
-			outl(dev->id[target_id].prdaddru, tmpcip);
+			tmpcip += 4;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
 			tmpcip = tmpcip - 2;
 			outb(0x06, tmpcip);
 			outb(0x00, tmpcip);
 			tmpcip = tmpcip - 2;
-			tmport = workportu + 0x10;
+			tmport = workport + 0x10;
 			outb(0x41, tmport);
-			tmport += 0x05;
+			if (dev->dev_id == ATP885_DEVID) {		
+				tmport += 2;
+				k = dev->id[c][target_id].last_len;
+				outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
+			} else {
+				tmport += 5;
+			}
 			outb((unsigned char) (inb(tmport) | 0x20), tmport);
-			dev->id[target_id].dirctu = 0x20;
+			dev->id[c][target_id].dirct = 0x20;
 			tmport += 0x03;
 			outb(0x08, tmport);
 			outb(0x01, tmpcip);
-			dev->in_int = 0;
-			goto out;
+			dev->in_int[c] = 0;
+			goto handled;
 		}
 		tmport -= 0x07;
 		if (i == 0x0a) {
@@ -434,25 +584,29 @@ go_42:
 		} else {
 			outb(0x46, tmport);
 		}
-		dev->id[target_id].dirctu = 0x00;
+		dev->id[c][target_id].dirct = 0x00;
 		tmport += 0x02;
 		outb(0x00, tmport++);
 		outb(0x00, tmport++);
 		outb(0x00, tmport++);
 		tmport += 0x03;
 		outb(0x08, tmport);
-		dev->in_int = 0;
-		goto out;
+		dev->in_int[c] = 0;
+		goto handled;
 	} else {
-//              tmport = workportu + 0x17;
-//              inb(tmport);
-//              dev->working = 0;
-		dev->in_int = 0;
+//		tmport = workport + 0x17;
+//		inb(tmport);
+//		dev->working[c] = 0;
+		dev->in_int[c] = 0;
+		goto handled;
 	}
-out:
+	
+handled:
+#ifdef ED_DBGP
+	printk("atp870u_intr_handle exit\n");
+#endif			
 	return IRQ_HANDLED;
 }
-
 /**
  *	atp870u_queuecommand	-	Queue SCSI command
  *	@req_p: request block
@@ -460,24 +614,31 @@ out:
  *
  *	Queue a command to the ATP queue. Called with the host lock held.
  */
- 
-static int atp870u_queuecommand(struct scsi_cmnd *req_p,
-		void (*done) (struct scsi_cmnd *))
+static int atp870u_queuecommand(struct scsi_cmnd * req_p, 
+			 void (*done) (struct scsi_cmnd *))
 {
-	unsigned short int m;
-	unsigned int tmport;
-	struct Scsi_Host *host;
+	unsigned char c;
+	unsigned int tmport,m;	
 	struct atp_unit *dev;
+	struct Scsi_Host *host;
 
-	if (req_p->device->channel != 0) {
+	c = req_p->device->channel;	
+	req_p->sense_buffer[0]=0;
+	req_p->resid = 0;
+	if (req_p->device->channel > 1) {
 		req_p->result = 0x00040000;
 		done(req_p);
+#ifdef ED_DBGP		
+		printk("atp870u_queuecommand : req_p->device->channel > 1\n");	
+#endif			
 		return 0;
-	};
+	}
 
 	host = req_p->device->host;
 	dev = (struct atp_unit *)&host->hostdata;
-	
+		
+
+		
 	m = 1;
 	m = m << req_p->device->id;
 
@@ -485,44 +646,60 @@ static int atp870u_queuecommand(struct s
 	 *      Fake a timeout for missing targets
 	 */
 
-	if ((m & dev->active_idu) == 0) {
+	if ((m & dev->active_id[c]) == 0) {
 		req_p->result = 0x00040000;
 		done(req_p);
 		return 0;
 	}
+
 	if (done) {
 		req_p->scsi_done = done;
 	} else {
-		printk(KERN_WARNING "atp870u_queuecommand: done can't be NULL\n");
+#ifdef ED_DBGP		
+		printk( "atp870u_queuecommand: done can't be NULL\n");
+#endif		
 		req_p->result = 0;
 		done(req_p);
 		return 0;
 	}
+	
 	/*
-	 *      Count new command
+	 *	Count new command
 	 */
-
-	dev->quendu++;
-	if (dev->quendu >= qcnt) {
-		dev->quendu = 0;
+	dev->quend[c]++;
+	if (dev->quend[c] >= qcnt) {
+		dev->quend[c] = 0;
 	}
+	
 	/*
-	 *      Check queue state
+	 *	Check queue state
 	 */
-	if (dev->quhdu == dev->quendu) {
-		if (dev->quendu == 0) {
-			dev->quendu = qcnt;
-		}
-		dev->quendu--;
+	if (dev->quhd[c] == dev->quend[c]) {
+		if (dev->quend[c] == 0) {
+			dev->quend[c] = qcnt;
+		}
+#ifdef ED_DBGP		
+		printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n");
+#endif		
+		dev->quend[c]--;
 		req_p->result = 0x00020000;
-		done(req_p);
+		done(req_p);	
 		return 0;
 	}
-	dev->querequ[dev->quendu] = req_p;
-	tmport = dev->ioport + 0x1c;
-	if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) {
-		send_s870(host);
-	}
+	dev->quereq[c][dev->quend[c]] = req_p;
+	tmport = dev->ioport[c] + 0x1c;
+#ifdef ED_DBGP	
+	printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+#endif
+	if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+		printk("Call sent_s870(atp870u_queuecommand)\n");
+#endif		
+		send_s870(dev,c);
+	}
+#ifdef ED_DBGP	
+	printk("atp870u_queuecommand : exit\n");
+#endif	
 	return 0;
 }
 
@@ -535,194 +712,242 @@ static int atp870u_queuecommand(struct s
  *
  *	Caller holds the host lock.
  */
- 
-static void send_s870(struct Scsi_Host *host)
+static void send_s870(struct atp_unit *dev,unsigned char c)
 {
 	unsigned int tmport;
-	struct scsi_cmnd *workrequ;
-	unsigned int i;
-	unsigned char j, target_id;
+	struct scsi_cmnd *workreq;
+	unsigned int i;//,k;
+	unsigned char  j, target_id;
 	unsigned char *prd;
 	unsigned short int tmpcip, w;
-	unsigned long l;
-	dma_addr_t bttl;
-	unsigned int workportu;
+	unsigned long l, bttl = 0;
+	unsigned int workport;
 	struct scatterlist *sgpnt;
-	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
-	int sg_count;
+	unsigned long  sg_count;
 
-	if (dev->in_snd != 0) {
-		return;
-	}
-	dev->in_snd = 1;
-	if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) {
-		dev->last_cmd &= 0x0f;
-		workrequ = dev->id[dev->last_cmd].curr_req;
-		if (workrequ != NULL) {	/* check NULL pointer */
-			goto cmd_subp;
-		}
-		dev->last_cmd = 0xff;
-		if (dev->quhdu == dev->quendu) {
-			dev->in_snd = 0;
-			return;
-		}
-	}
-	if ((dev->last_cmd != 0xff) && (dev->working != 0)) {
-		dev->in_snd = 0;
+	if (dev->in_snd[c] != 0) {
+#ifdef ED_DBGP		
+		printk("cmnd in_snd\n");
+#endif
 		return;
 	}
-	dev->working++;
-	j = dev->quhdu;
-	dev->quhdu++;
-	if (dev->quhdu >= qcnt) {
-		dev->quhdu = 0;
-	}
-	workrequ = dev->querequ[dev->quhdu];
-	if (dev->id[workrequ->device->id].curr_req == 0) {
-		dev->id[workrequ->device->id].curr_req = workrequ;
-		dev->last_cmd = workrequ->device->id;
+#ifdef ED_DBGP
+	printk("Sent_s870 enter\n");
+#endif
+	dev->in_snd[c] = 1;
+	if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
+		dev->last_cmd[c] &= 0x0f;
+		workreq = dev->id[c][dev->last_cmd[c]].curr_req;
+		if (workreq != NULL) {	/* check NULL pointer */
+		   goto cmd_subp;
+		}
+		dev->last_cmd[c] = 0xff;	
+		if (dev->quhd[c] == dev->quend[c]) {
+		   	dev->in_snd[c] = 0;
+		   	return ;
+		}
+	}
+	if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+	     	dev->in_snd[c] = 0;
+	     	return ;
+	}
+	dev->working[c]++;
+	j = dev->quhd[c];
+	dev->quhd[c]++;
+	if (dev->quhd[c] >= qcnt) {
+		dev->quhd[c] = 0;
+	}
+	workreq = dev->quereq[c][dev->quhd[c]];
+	if (dev->id[c][workreq->device->id].curr_req == 0) {	
+		dev->id[c][workreq->device->id].curr_req = workreq;
+		dev->last_cmd[c] = workreq->device->id;
 		goto cmd_subp;
-	}
-	dev->quhdu = j;
-	dev->working--;
-	dev->in_snd = 0;
+	}	
+	dev->quhd[c] = j;
+	dev->working[c]--;
+	dev->in_snd[c] = 0;
 	return;
 cmd_subp:
-	workportu = dev->ioport;
-	tmport = workportu + 0x1f;
+	workport = dev->ioport[c];
+	tmport = workport + 0x1f;
 	if ((inb(tmport) & 0xb0) != 0) {
 		goto abortsnd;
 	}
-	tmport = workportu + 0x1c;
+	tmport = workport + 0x1c;
 	if (inb(tmport) == 0) {
 		goto oktosend;
 	}
 abortsnd:
-	dev->last_cmd |= 0x40;
-	dev->in_snd = 0;
+#ifdef ED_DBGP
+	printk("Abort to Send\n");
+#endif
+	dev->last_cmd[c] |= 0x40;
+	dev->in_snd[c] = 0;
 	return;
 oktosend:
-	memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len);
-	if (dev->ata_cdbu[0] == READ_CAPACITY) {
-		if (workrequ->request_bufflen > 8) {
-			workrequ->request_bufflen = 0x08;
+#ifdef ED_DBGP
+	printk("OK to Send\n");
+	printk("CDB");
+	for(i=0;i<workreq->cmd_len;i++) {
+		printk(" %x",workreq->cmnd[i]);
+	}
+	printk("\nChannel = %d ID = %d LUN = %d\n",c,workreq->device->id,workreq->device->lun);
+#endif	
+	if (dev->dev_id == ATP885_DEVID) {
+		j = inb(dev->baseport + 0x29) & 0xfe;
+		outb(j, dev->baseport + 0x29);
+		dev->r1f[c][workreq->device->id] = 0;
+	}
+	
+	if (workreq->cmnd[0] == READ_CAPACITY) {
+		if (workreq->request_bufflen > 8) {
+			workreq->request_bufflen = 0x08;
 		}
 	}
-	if (dev->ata_cdbu[0] == 0x00) {
-		workrequ->request_bufflen = 0;
+	if (workreq->cmnd[0] == 0x00) {
+		workreq->request_bufflen = 0;
 	}
 
-	tmport = workportu + 0x1b;
+	tmport = workport + 0x1b;
 	j = 0;
-	target_id = workrequ->device->id;
+	target_id = workreq->device->id;
 
 	/*
-	 *      Wide ?
+	 *	Wide ?
 	 */
 	w = 1;
 	w = w << target_id;
-	if ((w & dev->wide_idu) != 0) {
+	if ((w & dev->wide_id[c]) != 0) {
 		j |= 0x01;
 	}
 	outb(j, tmport);
 	while ((inb(tmport) & 0x01) != j) {
-		outb(j, tmport);
+		outb(j,tmport);
+#ifdef ED_DBGP
+		printk("send_s870 while loop 1\n");
+#endif
 	}
-
 	/*
-	 *      Write the command
+	 *	Write the command
 	 */
 
-	tmport = workportu;
-	outb(workrequ->cmd_len, tmport++);
+	tmport = workport;
+	outb(workreq->cmd_len, tmport++);
 	outb(0x2c, tmport++);
-	outb(0xcf, tmport++);
-	for (i = 0; i < workrequ->cmd_len; i++) {
-		outb(dev->ata_cdbu[i], tmport++);
+	if (dev->dev_id == ATP885_DEVID) {
+		outb(0x7f, tmport++);
+	} else {
+		outb(0xcf, tmport++); 	
+	}	
+	for (i = 0; i < workreq->cmd_len; i++) {
+		outb(workreq->cmnd[i], tmport++);
 	}
-	tmport = workportu + 0x0f;
-	outb(workrequ->device->lun, tmport);
+	tmport = workport + 0x0f;
+	outb(workreq->device->lun, tmport);
 	tmport += 0x02;
 	/*
-	 *      Write the target
+	 *	Write the target
 	 */
-	outb(dev->id[target_id].devspu, tmport++);
-
+	outb(dev->id[c][target_id].devsp, tmport++);	 
+#ifdef ED_DBGP	
+	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
+#endif
 	/*
-	 *      Figure out the transfer size
+	 *	Figure out the transfer size
 	 */
-	if (workrequ->use_sg) {
+	if (workreq->use_sg) {
+#ifdef ED_DBGP
+		printk("Using SGL\n");
+#endif		
 		l = 0;
-		sgpnt = (struct scatterlist *) workrequ->request_buffer;
-		sg_count = pci_map_sg(dev->pdev, sgpnt, workrequ->use_sg,
-				workrequ->sc_data_direction);
-		for (i = 0; i < workrequ->use_sg; i++) {
-			if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) {
+		
+		sgpnt = (struct scatterlist *) workreq->request_buffer;
+		sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
+	   			workreq->sc_data_direction);		
+		
+		for (i = 0; i < workreq->use_sg; i++) {
+			if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
 				panic("Foooooooood fight!");
 			}
 			l += sgpnt[i].length;
 		}
-	} else if(workrequ->request_bufflen && workrequ->sc_data_direction != PCI_DMA_NONE) {
-		workrequ->SCp.dma_handle = pci_map_single(dev->pdev,
-				workrequ->request_buffer,
-				workrequ->request_bufflen,
-				workrequ->sc_data_direction);
-		l = workrequ->request_bufflen;
-	}
-	else l = 0;
+#ifdef ED_DBGP		
+		printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
+#endif
+	} else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
+#ifdef ED_DBGP
+		printk("Not using SGL\n");
+#endif					
+		workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
+				workreq->request_bufflen,
+				workreq->sc_data_direction);		
+		l = workreq->request_bufflen;
+#ifdef ED_DBGP		
+		printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
+#endif
+	} else l = 0;
 	/*
-	 *      Write transfer size
+	 *	Write transfer size
 	 */
 	outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
 	outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
 	outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
-	j = target_id;
-	dev->id[j].last_lenu = l;
-	dev->id[j].tran_lenu = 0;
+	j = target_id;	
+	dev->id[c][j].last_len = l;
+	dev->id[c][j].tran_len = 0;
+#ifdef ED_DBGP	
+	printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len);
+#endif	
 	/*
-	 *      Flip the wide bits
+	 *	Flip the wide bits
 	 */
 	if ((j & 0x08) != 0) {
 		j = (j & 0x07) | 0x40;
 	}
 	/*
-	 *      Check transfer direction
+	 *	Check transfer direction
 	 */
-	if (workrequ->sc_data_direction == DMA_TO_DEVICE) {
+	if (workreq->sc_data_direction == DMA_TO_DEVICE) {
 		outb((unsigned char) (j | 0x20), tmport++);
 	} else {
 		outb(j, tmport++);
 	}
 	outb((unsigned char) (inb(tmport) | 0x80), tmport);
 	outb(0x80, tmport);
-	tmport = workportu + 0x1c;
-	dev->id[target_id].dirctu = 0;
+	tmport = workport + 0x1c;
+	dev->id[c][target_id].dirct = 0;
 	if (l == 0) {
 		if (inb(tmport) == 0) {
-			tmport = workportu + 0x18;
+			tmport = workport + 0x18;
+#ifdef ED_DBGP
+			printk("change SCSI_CMD_REG 0x08\n");	
+#endif				
 			outb(0x08, tmport);
 		} else {
-			dev->last_cmd |= 0x40;
+			dev->last_cmd[c] |= 0x40;
 		}
-		dev->in_snd = 0;
+		dev->in_snd[c] = 0;
 		return;
 	}
-	tmpcip = dev->pciport;
-	prd = dev->id[target_id].prd_tableu;
-	dev->id[target_id].prd_posu = prd;
+	tmpcip = dev->pciport[c];
+	prd = dev->id[c][target_id].prd_table;
+	dev->id[c][target_id].prd_pos = prd;
 
 	/*
-	 *      Now write the request list. Either as scatter/gather or as
-	 *      a linear chain.
+	 *	Now write the request list. Either as scatter/gather or as
+	 *	a linear chain.
 	 */
 
-	if (workrequ->use_sg) {
-		sgpnt = (struct scatterlist *) workrequ->request_buffer;
+	if (workreq->use_sg) {
+		sgpnt = (struct scatterlist *) workreq->request_buffer;
 		i = 0;
-		for (j = 0; j < workrequ->use_sg; j++) {
+		for (j = 0; j < workreq->use_sg; j++) {
 			bttl = sg_dma_address(&sgpnt[j]);
-			l = sg_dma_len(&sgpnt[j]);
-			while (l > 0x10000) {
+			l=sg_dma_len(&sgpnt[j]);
+#ifdef ED_DBGP		
+		printk("1. bttl %x, l %x\n",bttl, l);
+#endif			
+		while (l > 0x10000) {
 				(((u16 *) (prd))[i + 3]) = 0x0000;
 				(((u16 *) (prd))[i + 2]) = 0x0000;
 				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
@@ -733,73 +958,105 @@ oktosend:
 			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
 			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
 			(((u16 *) (prd))[i + 3]) = 0;
-			i += 0x04;
+			i += 0x04;			
 		}
-		(((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000);
+		(((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000);	
+#ifdef ED_DBGP		
+		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+		printk("2. bttl %x, l %x\n",bttl, l);
+#endif			
 	} else {
 		/*
-		 *      For a linear request write a chain of blocks
-		 */
-		bttl = workrequ->SCp.dma_handle;
-		l = workrequ->request_bufflen;
+		 *	For a linear request write a chain of blocks
+		 */        
+		bttl = workreq->SCp.dma_handle;
+		l = workreq->request_bufflen;
 		i = 0;
+#ifdef ED_DBGP		
+		printk("3. bttl %x, l %x\n",bttl, l);
+#endif			
 		while (l > 0x10000) {
-			(((u16 *) (prd))[i + 3]) = 0x0000;
-			(((u16 *) (prd))[i + 2]) = 0x0000;
-			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
-			l -= 0x10000;
-			bttl += 0x10000;
-			i += 0x04;
-		}
-		(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
-		(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
-		(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
-	}
-	tmpcip = tmpcip + 4;
-	dev->id[target_id].prdaddru = dev->id[target_id].prd_phys;
-	outl(dev->id[target_id].prd_phys, tmpcip);
+				(((u16 *) (prd))[i + 3]) = 0x0000;
+				(((u16 *) (prd))[i + 2]) = 0x0000;
+				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+				l -= 0x10000;
+				bttl += 0x10000;
+				i += 0x04;
+			}
+			(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
+			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
+			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);		
+#ifdef ED_DBGP		
+		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+		printk("4. bttl %x, l %x\n",bttl, l);
+#endif			
+		
+	}
+	tmpcip += 4;
+#ifdef ED_DBGP		
+	printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+#endif	
+	outl(dev->id[c][target_id].prdaddr, tmpcip);
 	tmpcip = tmpcip - 2;
 	outb(0x06, tmpcip);
 	outb(0x00, tmpcip);
-	tmpcip = tmpcip - 2;
-
-	if (dev->deviceid != 0x8081) {
-		tmport = workportu + 0x3a;
-		if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) {
-			outb((inb(tmport) & 0xf3) | 0x08, tmport);
-		} else {
-			outb(inb(tmport) & 0xf3, tmport);
-		}
-	} else {
-		tmport = workportu - 0x05;
-		if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) {
+	if (dev->dev_id == ATP885_DEVID) {
+		tmpcip--;
+		j=inb(tmpcip) & 0xf3;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
+	    	(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+	   		j |= 0x0c;
+		}
+		outb(j,tmpcip);
+		tmpcip--;	    	
+	} else if ((dev->dev_id == ATP880_DEVID1) ||
+	    	   (dev->dev_id == ATP880_DEVID2)) {
+		tmpcip =tmpcip -2;	
+		tmport = workport - 0x05;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
 			outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
 		} else {
 			outb((unsigned char) (inb(tmport) & 0x3f), tmport);
-		}
-	}
-	tmport = workportu + 0x1c;
+		}		
+	} else {		
+		tmpcip =tmpcip -2;
+		tmport = workport + 0x3a;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+			outb((inb(tmport) & 0xf3) | 0x08, tmport);
+		} else {
+			outb(inb(tmport) & 0xf3, tmport);
+		}		
+	}	
+	tmport = workport + 0x1c;
 
-	if (workrequ->sc_data_direction == DMA_TO_DEVICE) {
-		dev->id[target_id].dirctu = 0x20;
+	if(workreq->sc_data_direction == DMA_TO_DEVICE) {
+		dev->id[c][target_id].dirct = 0x20;
 		if (inb(tmport) == 0) {
-			tmport = workportu + 0x18;
+			tmport = workport + 0x18;
 			outb(0x08, tmport);
 			outb(0x01, tmpcip);
+#ifdef ED_DBGP		
+		printk( "start DMA(to target)\n");
+#endif				
 		} else {
-			dev->last_cmd |= 0x40;
+			dev->last_cmd[c] |= 0x40;
 		}
-		dev->in_snd = 0;
+		dev->in_snd[c] = 0;
 		return;
 	}
-	if (inb(tmport) == 0) {
-		tmport = workportu + 0x18;
+	if (inb(tmport) == 0) {		
+		tmport = workport + 0x18;
 		outb(0x08, tmport);
 		outb(0x09, tmpcip);
+#ifdef ED_DBGP		
+		printk( "start DMA(to host)\n");
+#endif			
 	} else {
-		dev->last_cmd |= 0x40;
+		dev->last_cmd[c] |= 0x40;
 	}
-	dev->in_snd = 0;
+	dev->in_snd[c] = 0;
+	return;
+
 }
 
 static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
@@ -808,7 +1065,7 @@ static unsigned char fun_scam(struct atp
 	unsigned short int i, k;
 	unsigned char j;
 
-	tmport = dev->ioport + 0x1c;
+	tmport = dev->ioport[0] + 0x1c;
 	outw(*val, tmport);
 FUN_D7:
 	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
@@ -863,24 +1120,24 @@ static void tscam(struct Scsi_Host *host
 	}
  */
 
-	tmport = dev->ioport + 1;
+	tmport = dev->ioport[0] + 1;
 	outb(0x08, tmport++);
 	outb(0x7f, tmport);
-	tmport = dev->ioport + 0x11;
+	tmport = dev->ioport[0] + 0x11;
 	outb(0x20, tmport);
 
 	if ((dev->scam_on & 0x40) == 0) {
 		return;
 	}
 	m = 1;
-	m <<= dev->host_idu;
+	m <<= dev->host_id[0];
 	j = 16;
-	if (dev->chip_veru < 4) {
+	if (dev->chip_ver < 4) {
 		m |= 0xff00;
 		j = 8;
 	}
 	assignid_map = m;
-	tmport = dev->ioport + 0x02;
+	tmport = dev->ioport[0] + 0x02;
 	outb(0x02, tmport++);	/* 2*2=4ms,3EH 2/32*3E=3.9ms */
 	outb(0, tmport++);
 	outb(0, tmport++);
@@ -895,7 +1152,7 @@ static void tscam(struct Scsi_Host *host
 		if ((m & assignid_map) != 0) {
 			continue;
 		}
-		tmport = dev->ioport + 0x0f;
+		tmport = dev->ioport[0] + 0x0f;
 		outb(0, tmport++);
 		tmport += 0x02;
 		outb(0, tmport++);
@@ -907,40 +1164,41 @@ static void tscam(struct Scsi_Host *host
 			k = i;
 		}
 		outb(k, tmport++);
-		tmport = dev->ioport + 0x1b;
-		if (dev->chip_veru == 4) {
+		tmport = dev->ioport[0] + 0x1b;
+		if (dev->chip_ver == 4) {
 			outb(0x01, tmport);
 		} else {
 			outb(0x00, tmport);
 		}
 wait_rdyok:
-		tmport = dev->ioport + 0x18;
+		tmport = dev->ioport[0] + 0x18;
 		outb(0x09, tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
 		tmport -= 0x08;
 		k = inb(tmport);
 		if (k != 0x16) {
 			if ((k == 0x85) || (k == 0x42)) {
 				continue;
 			}
-			tmport = dev->ioport + 0x10;
+			tmport = dev->ioport[0] + 0x10;
 			outb(0x41, tmport);
 			goto wait_rdyok;
 		}
 		assignid_map |= m;
 
 	}
-	tmport = dev->ioport + 0x02;
+	tmport = dev->ioport[0] + 0x02;
 	outb(0x7f, tmport);
-	tmport = dev->ioport + 0x1b;
+	tmport = dev->ioport[0] + 0x1b;
 	outb(0x02, tmport);
 
 	outb(0, 0x80);
 
 	val = 0x0080;		/* bsy  */
-	tmport = dev->ioport + 0x1c;
+	tmport = dev->ioport[0] + 0x1c;
 	outw(val, tmport);
 	val |= 0x0040;		/* sel  */
 	outw(val, tmport);
@@ -984,12 +1242,13 @@ TCM_SYNC:
 	if ((inb(tmport) & 0x80) == 0x00) {	/* bsy ? */
 		outw(0, tmport--);
 		outb(0, tmport);
-		tmport = dev->ioport + 0x15;
+		tmport = dev->ioport[0] + 0x15;
 		outb(0, tmport);
 		tmport += 0x03;
 		outb(0x09, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0);
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
 		tmport -= 0x08;
 		inb(tmport);
 		return;
@@ -1085,7 +1344,7 @@ G2Q_QUIN:		/* k=binID#,       */
 
 }
 
-static void is870(struct Scsi_Host *host, unsigned int wkport)
+static void is870(struct atp_unit *dev, unsigned int wkport)
 {
 	unsigned int tmport;
 	unsigned char i, j, k, rmb, n;
@@ -1097,26 +1356,25 @@ static void is870(struct Scsi_Host *host
 	static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
 	static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
 	static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
-
+	
 	tmport = wkport + 0x3a;
 	outb((unsigned char) (inb(tmport) | 0x10), tmport);
 
 	for (i = 0; i < 16; i++) {
-		if ((dev->chip_veru != 4) && (i > 7)) {
+		if ((dev->chip_ver != 4) && (i > 7)) {
 			break;
 		}
 		m = 1;
 		m = m << i;
-		if ((m & dev->active_idu) != 0) {
+		if ((m & dev->active_id[0]) != 0) {
 			continue;
 		}
-		if (i == dev->host_idu) {
-			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_idu);
+		if (i == dev->host_id[0]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
 			continue;
 		}
 		tmport = wkport + 0x1b;
-		if (dev->chip_veru == 4) {
+		if (dev->chip_ver == 4) {
 			outb(0x01, tmport);
 		} else {
 			outb(0x00, tmport);
@@ -1133,7 +1391,7 @@ static void is870(struct Scsi_Host *host
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1146,13 +1404,17 @@ static void is870(struct Scsi_Host *host
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
-		dev->active_idu |= m;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
+		dev->active_id[0] |= m;
 
 		tmport = wkport + 0x10;
 		outb(0x30, tmport);
@@ -1163,7 +1425,8 @@ phase_cmd:
 		tmport = wkport + 0x18;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -1182,23 +1445,28 @@ sel_ok:
 		tmport += 0x07;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(inqd[6], tmport++);
 		outb(inqd[7], tmport++);
 		tmport += 0x03;
 		outb(inqd[8], tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
 		tmport = wkport + 0x1b;
-		if (dev->chip_veru == 4) {
+		if (dev->chip_ver == 4)
 			outb(0x00, tmport);
-		}
+
 		tmport = wkport + 0x18;
 		outb(0x08, tmport);
 		tmport += 0x07;
@@ -1228,7 +1496,10 @@ rd_inq_data:
 		tmport += 0x03;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
 		if (inb(tmport) != 0x16) {
 			goto sel_ok;
@@ -1236,16 +1507,16 @@ rd_inq_data:
 inq_ok:
 		mbuf[36] = 0;
 		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
-		dev->id[i].devtypeu = mbuf[0];
+		dev->id[0][i].devtype = mbuf[0];
 		rmb = mbuf[1];
 		n = mbuf[7];
-		if (dev->chip_veru != 4) {
+		if (dev->chip_ver != 4) {
 			goto not_wide;
 		}
 		if ((mbuf[7] & 0x60) == 0) {
 			goto not_wide;
 		}
-		if ((dev->global_map & 0x20) == 0) {
+		if ((dev->global_map[0] & 0x20) == 0) {
 			goto not_wide;
 		}
 		tmport = wkport + 0x1b;
@@ -1260,7 +1531,7 @@ inq_ok:
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1268,12 +1539,16 @@ inq_ok:
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
 try_wide:
 		j = 0;
 		tmport = wkport + 0x14;
@@ -1290,7 +1565,10 @@ try_wide:
 			}
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		j = inb(tmport) & 0x0f;
 		if (j == 0x0f) {
 			goto widep_in;
@@ -1363,7 +1641,10 @@ widep_cmd:
 		tmport += 0x04;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -1386,16 +1667,16 @@ widep_cmd:
 		}
 		m = 1;
 		m = m << i;
-		dev->wide_idu |= m;
+		dev->wide_id[0] |= m;
 not_wide:
-		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) {
+		if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
 			goto set_sync;
 		}
 		continue;
 set_sync:
 		tmport = wkport + 0x1b;
 		j = 0;
-		if ((m & dev->wide_idu) != 0) {
+		if ((m & dev->wide_id[0]) != 0) {
 			j |= 0x01;
 		}
 		outb(j, tmport);
@@ -1409,7 +1690,7 @@ set_sync:
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1417,12 +1698,16 @@ set_sync:
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
 try_sync:
 		j = 0;
 		tmport = wkport + 0x14;
@@ -1434,10 +1719,10 @@ try_sync:
 		while ((inb(tmport) & 0x80) == 0) {
 			if ((inb(tmport) & 0x01) != 0) {
 				tmport -= 0x06;
-				if ((m & dev->wide_idu) != 0) {
+				if ((m & dev->wide_id[0]) != 0) {
 					outb(synw[j++], tmport);
 				} else {
-					if ((m & dev->ultra_map) != 0) {
+					if ((m & dev->ultra_map[0]) != 0) {
 						outb(synu[j++], tmport);
 					} else {
 						outb(synn[j++], tmport);
@@ -1447,7 +1732,10 @@ try_sync:
 			}
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		j = inb(tmport) & 0x0f;
 		if (j == 0x0f) {
 			goto phase_ins;
@@ -1505,7 +1793,10 @@ phase_ins1:
 			goto phase_ins1;
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		j = inb(tmport);
 		if (j == 0x85) {
 			goto tar_dcons;
@@ -1530,7 +1821,10 @@ tar_dcons:
 		tmport += 0x04;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -1551,7 +1845,7 @@ tar_dcons:
 		if (mbuf[4] > 0x0c) {
 			mbuf[4] = 0x0c;
 		}
-		dev->id[i].devspu = mbuf[4];
+		dev->id[0][i].devsp = mbuf[4];
 		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
 			j = 0xa0;
 			goto set_syn_ok;
@@ -1570,13 +1864,13 @@ tar_dcons:
 		}
 		j = 0x60;
 set_syn_ok:
-		dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j;
+		dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
 	}
 	tmport = wkport + 0x3a;
 	outb((unsigned char) (inb(tmport) & 0xef), tmport);
 }
 
-static void is880(struct Scsi_Host *host, unsigned int wkport)
+static void is880(struct atp_unit *dev, unsigned int wkport)
 {
 	unsigned int tmport;
 	unsigned char i, j, k, rmb, n, lvdmode;
@@ -1590,18 +1884,17 @@ static void is880(struct Scsi_Host *host
 	unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
 	static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
 	static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
-	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
 
 	lvdmode = inb(wkport + 0x3f) & 0x40;
 
 	for (i = 0; i < 16; i++) {
 		m = 1;
 		m = m << i;
-		if ((m & dev->active_idu) != 0) {
+		if ((m & dev->active_id[0]) != 0) {
 			continue;
 		}
-		if (i == dev->host_idu) {
-			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_idu);
+		if (i == dev->host_id[0]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
 			continue;
 		}
 		tmport = wkport + 0x5b;
@@ -1618,7 +1911,7 @@ static void is880(struct Scsi_Host *host
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1631,13 +1924,17 @@ static void is880(struct Scsi_Host *host
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
-		dev->active_idu |= m;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+		dev->active_id[0] |= m;
 
 		tmport = wkport + 0x50;
 		outb(0x30, tmport);
@@ -1648,7 +1945,10 @@ phase_cmd:
 		tmport = wkport + 0x58;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -1667,19 +1967,24 @@ sel_ok:
 		tmport += 0x07;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(inqd[6], tmport++);
 		outb(inqd[7], tmport++);
 		tmport += 0x03;
 		outb(inqd[8], tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
 		tmport = wkport + 0x5b;
 		outb(0x00, tmport);
 		tmport = wkport + 0x58;
@@ -1711,27 +2016,29 @@ rd_inq_data:
 		tmport += 0x03;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if (inb(tmport) != 0x16) {
+		if (inb(tmport) != 0x16)
 			goto sel_ok;
-		}
+
 inq_ok:
 		mbuf[36] = 0;
 		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
-		dev->id[i].devtypeu = mbuf[0];
+		dev->id[0][i].devtype = mbuf[0];
 		rmb = mbuf[1];
 		n = mbuf[7];
 		if ((mbuf[7] & 0x60) == 0) {
 			goto not_wide;
 		}
-		if ((i < 8) && ((dev->global_map & 0x20) == 0)) {
+		if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
 			goto not_wide;
 		}
 		if (lvdmode == 0) {
 			goto chg_wide;
 		}
-		if (dev->sp[i] != 0x04)	// force u2
+		if (dev->sp[0][i] != 0x04)	// force u2
 		{
 			goto chg_wide;
 		}
@@ -1748,7 +2055,7 @@ inq_ok:
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1756,12 +2063,17 @@ inq_ok:
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
 try_u3:
 		j = 0;
 		tmport = wkport + 0x54;
@@ -1778,7 +2090,10 @@ try_u3:
 			}
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		j = inb(tmport) & 0x0f;
 		if (j == 0x0f) {
 			goto u3p_in;
@@ -1851,7 +2166,10 @@ u3p_cmd:
 		tmport += 0x04;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -1872,8 +2190,8 @@ u3p_cmd:
 		if (mbuf[3] == 0x09) {
 			m = 1;
 			m = m << i;
-			dev->wide_idu |= m;
-			dev->id[i].devspu = 0xce;
+			dev->wide_id[0] |= m;
+			dev->id[0][i].devsp = 0xce;
 			continue;
 		}
 chg_wide:
@@ -1889,7 +2207,7 @@ chg_wide:
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1897,12 +2215,16 @@ chg_wide:
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		tmport -= 0x08;
-		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
 			continue;
-		}
-		while (inb(tmport) != 0x8e);
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
 try_wide:
 		j = 0;
 		tmport = wkport + 0x54;
@@ -1919,7 +2241,9 @@ try_wide:
 			}
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
 		j = inb(tmport) & 0x0f;
 		if (j == 0x0f) {
 			goto widep_in;
@@ -1992,7 +2316,10 @@ widep_cmd:
 		tmport += 0x04;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -2015,29 +2342,29 @@ widep_cmd:
 		}
 		m = 1;
 		m = m << i;
-		dev->wide_idu |= m;
+		dev->wide_id[0] |= m;
 not_wide:
-		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) {
+		if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
 			m = 1;
 			m = m << i;
-			if ((dev->async & m) != 0) {
+			if ((dev->async[0] & m) != 0) {
 				goto set_sync;
 			}
 		}
 		continue;
 set_sync:
-		if (dev->sp[i] == 0x02) {
+		if (dev->sp[0][i] == 0x02) {
 			synu[4] = 0x0c;
 			synuw[4] = 0x0c;
 		} else {
-			if (dev->sp[i] >= 0x03) {
+			if (dev->sp[0][i] >= 0x03) {
 				synu[4] = 0x0a;
 				synuw[4] = 0x0a;
 			}
 		}
 		tmport = wkport + 0x5b;
 		j = 0;
-		if ((m & dev->wide_idu) != 0) {
+		if ((m & dev->wide_id[0]) != 0) {
 			j |= 0x01;
 		}
 		outb(j, tmport);
@@ -2051,7 +2378,7 @@ set_sync:
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(dev->id[i].devspu, tmport++);
+		outb(dev->id[0][i].devsp, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -2059,12 +2386,16 @@ set_sync:
 		outb(satn[8], tmport);
 		tmport += 0x07;
 
-		while ((inb(tmport) & 0x80) == 0x00);
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
 		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
 			continue;
 		}
-		while (inb(tmport) != 0x8e);
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
 try_sync:
 		j = 0;
 		tmport = wkport + 0x54;
@@ -2076,14 +2407,14 @@ try_sync:
 		while ((inb(tmport) & 0x80) == 0) {
 			if ((inb(tmport) & 0x01) != 0) {
 				tmport -= 0x06;
-				if ((m & dev->wide_idu) != 0) {
-					if ((m & dev->ultra_map) != 0) {
+				if ((m & dev->wide_id[0]) != 0) {
+					if ((m & dev->ultra_map[0]) != 0) {
 						outb(synuw[j++], tmport);
 					} else {
 						outb(synw[j++], tmport);
 					}
 				} else {
-					if ((m & dev->ultra_map) != 0) {
+					if ((m & dev->ultra_map[0]) != 0) {
 						outb(synu[j++], tmport);
 					} else {
 						outb(synn[j++], tmport);
@@ -2093,7 +2424,10 @@ try_sync:
 			}
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		j = inb(tmport) & 0x0f;
 		if (j == 0x0f) {
 			goto phase_ins;
@@ -2151,7 +2485,10 @@ phase_ins1:
 			goto phase_ins1;
 		}
 		tmport -= 0x08;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		j = inb(tmport);
 		if (j == 0x85) {
 			goto tar_dcons;
@@ -2176,7 +2513,10 @@ tar_dcons:
 		tmport += 0x04;
 		outb(0x08, tmport);
 		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0x00);
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
 		tmport -= 0x08;
 		j = inb(tmport);
 		if (j != 0x16) {
@@ -2197,7 +2537,7 @@ tar_dcons:
 		if (mbuf[4] > 0x0e) {
 			mbuf[4] = 0x0e;
 		}
-		dev->id[i].devspu = mbuf[4];
+		dev->id[0][i].devsp = mbuf[4];
 		if (mbuf[3] < 0x0c) {
 			j = 0xb0;
 			goto set_syn_ok;
@@ -2220,249 +2560,179 @@ tar_dcons:
 		}
 		j = 0x60;
 set_syn_ok:
-		dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j;
+		dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
 	}
 }
 
 static void atp870u_free_tables(struct Scsi_Host *host)
 {
 	struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
-	int k;
-
-	for (k = 0; k < 16; k++) {
-		if (!atp_dev->id[k].prd_tableu)
-			continue;
-		pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[k].prd_tableu,
-					atp_dev->id[k].prd_phys);
-		atp_dev->id[k].prd_tableu = NULL;
+	int j, k;
+	for (j=0; j < 2; j++) {
+		for (k = 0; k < 16; k++) {
+			if (!atp_dev->id[j][k].prd_table)
+				continue;
+			pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prdaddr);
+			atp_dev->id[j][k].prd_table = NULL;
+		}
 	}
 }
 
 static int atp870u_init_tables(struct Scsi_Host *host)
 {
-	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
-	int k, i;
-
-	for (i = k = 0; k < 16; k++) {
-		dev->id[k].prd_tableu = pci_alloc_consistent(dev->pdev, 1024, &dev->id[k].prd_phys);
-		if (!dev->id[k].prd_tableu) {
-			atp870u_free_tables(host);
-			return -ENOMEM;
-		}
-		dev->id[k].devspu = 0x20;
-		dev->id[k].devtypeu = 0;
-		dev->id[k].curr_req = NULL;
-	}
-	dev->active_idu = 0;
-	dev->wide_idu = 0;
-	dev->host_idu = 0x07;
-	dev->quhdu = 0;
-	dev->quendu = 0;
-	dev->chip_veru = 0;
-	dev->last_cmd = 0xff;
-	dev->in_snd = 0;
-	dev->in_int = 0;
-	for (k = 0; k < qcnt; k++) {
-		dev->querequ[k] = NULL;
-	}
-	for (k = 0; k < 16; k++) {
-		dev->id[k].curr_req = NULL;
-		dev->sp[k] = 0x04;
+	struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
+	int c,k;
+	for(c=0;c < 2;c++) {
+	   	for(k=0;k<16;k++) {
+	   			atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prdaddr));
+	   			if (!atp_dev->id[c][k].prd_table) {
+	   				printk("atp870u_init_tables fail\n");
+				atp870u_free_tables(host);
+				return -ENOMEM;
+			}
+			atp_dev->id[c][k].devsp=0x20;
+			atp_dev->id[c][k].devtype = 0x7f;
+			atp_dev->id[c][k].curr_req = NULL;			   
+	   	}
+	   			
+	   	atp_dev->active_id[c] = 0;
+	   	atp_dev->wide_id[c] = 0;
+	   	atp_dev->host_id[c] = 0x07;
+	   	atp_dev->quhd[c] = 0;
+	   	atp_dev->quend[c] = 0;
+	   	atp_dev->last_cmd[c] = 0xff;
+	   	atp_dev->in_snd[c] = 0;
+	   	atp_dev->in_int[c] = 0;
+	   	
+	   	for (k = 0; k < qcnt; k++) {
+	   		  atp_dev->quereq[c][k] = NULL;
+	   	}	   		   
+	   	for (k = 0; k < 16; k++) {
+			   atp_dev->id[c][k].curr_req = NULL;
+			   atp_dev->sp[c][k] = 0x04;
+	   	}		   
 	}
 	return 0;
 }
 
 /* return non-zero on detection */
-static int atp870u_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	unsigned char k, m;
+	unsigned char k, m, c;
 	unsigned long flags;
-	unsigned int base_io, error, tmport;
+	unsigned int base_io, tmport, error,n;
 	unsigned char host_id;
-	unsigned short n;
-	struct Scsi_Host *shpnt;
+	struct Scsi_Host *shpnt = NULL;
 	struct atp_unit atp_dev, *p;
-	static int count;
-
-	if (pci_enable_device(dev))
+	unsigned char setupdata[2][16];
+	int count = 0;
+	
+	if (pci_enable_device(pdev))
 		return -EIO;
 
-	if (pci_set_dma_mask(dev, 0xFFFFFFFFUL)) {
-		printk(KERN_ERR "atp870u: 32bit DMA mask required but not available.\n");
-		return -EIO;
-	}
-	
+        if (!pci_set_dma_mask(pdev, 0xFFFFFFFFUL)) {
+                printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
+        } else {
+                printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
+                return -EIO;
+        }
+
 	memset(&atp_dev, 0, sizeof atp_dev);
- 
 	/*
 	 * It's probably easier to weed out some revisions like
 	 * this than via the PCI device table
 	 */
 	if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
-		error = pci_read_config_byte(dev, PCI_CLASS_REVISION, &atp_dev.chip_veru);
-		if (atp_dev.chip_veru < 2)
+		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+		if (atp_dev.chip_ver < 2)
 			return -EIO;
 	}
 
 	switch (ent->device) {
-	case 0x8081:
 	case PCI_DEVICE_ID_ARTOP_AEC7612UW:
 	case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
-		atp_dev.chip_veru = 0x04;
+	case ATP880_DEVID1:	
+	case ATP880_DEVID2:	
+	case ATP885_DEVID:	
+		atp_dev.chip_ver = 0x04;
 	default:
 		break;
 	}
+	base_io = pci_resource_start(pdev, 0);
+	base_io &= 0xfffffff8;
+	
+	if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
+		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
+
+		host_id = inb(base_io + 0x39);
+		host_id >>= 0x04;
 
-	base_io = pci_resource_start(dev, 0);
+		printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
+			"    IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+		atp_dev.ioport[0] = base_io + 0x40;
+		atp_dev.pciport[0] = base_io + 0x28;
+		atp_dev.dev_id = ent->device;
+		atp_dev.host_id[0] = host_id;
 
-	if (ent->device != 0x8081) {
-		error = pci_read_config_byte(dev, 0x49, &host_id);
-		base_io &= 0xfffffff8;
-
-		printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d "
-			"IO:%x, IRQ:%d.\n", count, base_io, dev->irq);
-
-		atp_dev.unit = count;	
-		atp_dev.ioport = base_io;
-		atp_dev.pciport = base_io + 0x20;
-		atp_dev.deviceid = ent->device;
-		host_id &= 0x07;
-		atp_dev.host_idu = host_id;
 		tmport = base_io + 0x22;
 		atp_dev.scam_on = inb(tmport);
-		tmport += 0x0b;
-		atp_dev.global_map = inb(tmport++);
-		atp_dev.ultra_map = inw(tmport);
+		tmport += 0x13;
+		atp_dev.global_map[0] = inb(tmport);
+		tmport += 0x07;
+		atp_dev.ultra_map[0] = inw(tmport);
 
-		if (atp_dev.ultra_map == 0) {
-			atp_dev.scam_on = 0x00;
-			atp_dev.global_map = 0x20;
-			atp_dev.ultra_map = 0xffff;
-		}
+		n = 0x3f09;
+next_fblk_880:
+		if (n >= 0x4000)
+			goto flash_ok_880;
 
-		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
-		if (!shpnt)
-			return -ENOMEM;
+		m = 0;
+		outw(n, base_io + 0x34);
+		n += 0x0002;
+		if (inb(base_io + 0x30) == 0xff)
+			goto flash_ok_880;
 
-		p = (struct atp_unit *)&shpnt->hostdata;
-		
-		atp_dev.host = shpnt;
-		atp_dev.pdev = dev;
-		pci_set_drvdata(dev, p);
-		memcpy(p, &atp_dev, sizeof atp_dev);
-		if (atp870u_init_tables(shpnt) < 0)
-			goto unregister;
-
-		if (request_irq(dev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
-			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", dev->irq);
-			goto free_tables;
-		}
-
-		spin_lock_irqsave(shpnt->host_lock, flags);
-		if (atp_dev.chip_veru > 0x07) {	/* check if atp876 chip then enable terminator */
-			tmport = base_io + 0x3e;
-			outb(0x00, tmport);
-		}
- 
-		tmport = base_io + 0x3a;
-		k = (inb(tmport) & 0xf3) | 0x10;
-		outb(k, tmport);
-		outb((k & 0xdf), tmport);
-		mdelay(32);
-		outb(k, tmport);
-		mdelay(32);
-		tmport = base_io;
-		outb((host_id | 0x08), tmport);
-		tmport += 0x18;
-		outb(0, tmport);
-		tmport += 0x07;
-		while ((inb(tmport) & 0x80) == 0)
-			mdelay(1);
-
-		tmport -= 0x08;
-		inb(tmport);
-		tmport = base_io + 1;
-		outb(8, tmport++);
-		outb(0x7f, tmport);
-		tmport = base_io + 0x11;
-		outb(0x20, tmport);
-
-		tscam(shpnt);
-		is870(shpnt, base_io);
-		tmport = base_io + 0x3a;
-		outb((inb(tmport) & 0xef), tmport);
-		tmport++;
-		outb((inb(tmport) | 0x20), tmport);
-	} else {
-		base_io &= 0xfffffff8;
-		host_id = inb(base_io + 0x39);
-		host_id >>= 0x04;
-
-		printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
-			"    IO:%x, IRQ:%d.\n", count, base_io, dev->irq);
-		atp_dev.ioport = base_io + 0x40;
-		atp_dev.pciport = base_io + 0x28;
-		atp_dev.deviceid = ent->device;
-		atp_dev.host_idu = host_id;
-
-		tmport = base_io + 0x22;
-		atp_dev.scam_on = inb(tmport);
-		tmport += 0x13;
-		atp_dev.global_map = inb(tmport);
-		tmport += 0x07;
-		atp_dev.ultra_map = inw(tmport);
-
-		n = 0x3f09;
-next_fblk:
-		if (n >= 0x4000)
-			goto flash_ok;
-
-		m = 0;
-		outw(n, base_io + 0x34);
-		n += 0x0002;
-		if (inb(base_io + 0x30) == 0xff)
-			goto flash_ok;
-
-		atp_dev.sp[m++] = inb(base_io + 0x30);
-		atp_dev.sp[m++] = inb(base_io + 0x31);
-		atp_dev.sp[m++] = inb(base_io + 0x32);
-		atp_dev.sp[m++] = inb(base_io + 0x33);
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
 		outw(n, base_io + 0x34);
 		n += 0x0002;
-		atp_dev.sp[m++] = inb(base_io + 0x30);
-		atp_dev.sp[m++] = inb(base_io + 0x31);
-		atp_dev.sp[m++] = inb(base_io + 0x32);
-		atp_dev.sp[m++] = inb(base_io + 0x33);
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
 		outw(n, base_io + 0x34);
 		n += 0x0002;
-		atp_dev.sp[m++] = inb(base_io + 0x30);
-		atp_dev.sp[m++] = inb(base_io + 0x31);
-		atp_dev.sp[m++] = inb(base_io + 0x32);
-		atp_dev.sp[m++] = inb(base_io + 0x33);
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
 		outw(n, base_io + 0x34);
 		n += 0x0002;
-		atp_dev.sp[m++] = inb(base_io + 0x30);
-		atp_dev.sp[m++] = inb(base_io + 0x31);
-		atp_dev.sp[m++] = inb(base_io + 0x32);
-		atp_dev.sp[m++] = inb(base_io + 0x33);
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
 		n += 0x0018;
-		goto next_fblk;
-flash_ok:
+		goto next_fblk_880;
+flash_ok_880:
 		outw(0, base_io + 0x34);
-		atp_dev.ultra_map = 0;
-		atp_dev.async = 0;
+		atp_dev.ultra_map[0] = 0;
+		atp_dev.async[0] = 0;
 		for (k = 0; k < 16; k++) {
 			n = 1;
 			n = n << k;
-			if (atp_dev.sp[k] > 1) {
-				atp_dev.ultra_map |= n;
+			if (atp_dev.sp[0][k] > 1) {
+				atp_dev.ultra_map[0] |= n;
 			} else {
-				if (atp_dev.sp[k] == 0)
-					atp_dev.async |= n;
+				if (atp_dev.sp[0][k] == 0)
+					atp_dev.async[0] |= n;
  			}
 	 	}
-		atp_dev.async = ~(atp_dev.async);
-		outb(atp_dev.global_map, base_io + 0x35);
+		atp_dev.async[0] = ~(atp_dev.async[0]);
+		outb(atp_dev.global_map[0], base_io + 0x35);
  
 		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
 		if (!shpnt)
@@ -2471,16 +2741,16 @@ flash_ok:
 		p = (struct atp_unit *)&shpnt->hostdata;
 
 		atp_dev.host = shpnt;
-		atp_dev.pdev = dev;
-		pci_set_drvdata(dev, p);
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
 		memcpy(p, &atp_dev, sizeof atp_dev);
 		if (atp870u_init_tables(shpnt) < 0) {
 			printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
 			goto unregister;
 		}
 
-		if (request_irq(dev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
- 			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", dev->irq);
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp880i", shpnt)) {
+ 			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
 			goto free_tables;
 		}
 
@@ -2513,50 +2783,314 @@ flash_ok:
 		outb(0x20, tmport);
 
 		tscam(shpnt);
-		is880(shpnt, base_io);
+		is880(p, base_io);
 		tmport = base_io + 0x38;
 		outb(0xb0, tmport);
-	}
-
-	if (p->chip_veru == 4)
 		shpnt->max_id = 16;
-
-	shpnt->this_id = host_id;
-	shpnt->unique_id = base_io;
-	shpnt->io_port = base_io;
-	if (ent->device == 0x8081) {
+		shpnt->this_id = host_id;
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
 		shpnt->n_io_port = 0x60;	/* Number of bytes of I/O space used */
+		shpnt->irq = pdev->irq;			
+	} else if (ent->device == ATP885_DEVID) {	
+			printk(KERN_INFO "   ACARD AEC-67162 PCI Ultra3 LVD Host Adapter:  IO:%x, IRQ:%d.\n"
+			       , base_io, pdev->irq);
+        	
+		atp_dev.pdev = pdev;	
+		atp_dev.dev_id  = ent->device;
+		atp_dev.baseport = base_io;
+		atp_dev.ioport[0] = base_io + 0x80;
+		atp_dev.ioport[1] = base_io + 0xc0;
+		atp_dev.pciport[0] = base_io + 0x40;
+		atp_dev.pciport[1] = base_io + 0x50;
+				
+		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+		if (!shpnt)
+			return -ENOMEM;
+        	
+		p = (struct atp_unit *)&shpnt->hostdata;
+        	
+		atp_dev.host = shpnt;
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
+		memcpy(p, &atp_dev, sizeof(struct atp_unit));
+		if (atp870u_init_tables(shpnt) < 0)
+			goto unregister;
+			
+#ifdef ED_DBGP		
+	printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
+#endif	        
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
+				printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
+			goto free_tables;
+		}
+		
+		spin_lock_irqsave(shpnt->host_lock, flags);        					
+        			
+		c=inb(base_io + 0x29);
+		outb((c | 0x04),base_io + 0x29);
+        	
+		n=0x1f80;
+next_fblk_885:
+		if (n >= 0x2000) {
+		   goto flash_ok_885;
+		}
+		outw(n,base_io + 0x3c);
+		if (inl(base_io + 0x38) == 0xffffffff) {
+		   goto flash_ok_885;
+		}
+		for (m=0; m < 2; m++) {
+		    p->global_map[m]= 0;
+		    for (k=0; k < 4; k++) {
+			outw(n++,base_io + 0x3c);
+			((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
+		    }
+		    for (k=0; k < 4; k++) {
+			outw(n++,base_io + 0x3c);
+			((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
+		    }
+		    n += 8;
+		}
+		goto next_fblk_885;
+flash_ok_885:
+#ifdef ED_DBGP
+		printk( "Flash Read OK\n");
+#endif	
+		c=inb(base_io + 0x29);
+		outb((c & 0xfb),base_io + 0x29);
+		for (c=0;c < 2;c++) {
+		    p->ultra_map[c]=0;
+		    p->async[c] = 0;
+		    for (k=0; k < 16; k++) {
+			n=1;
+			n = n << k;
+			if (p->sp[c][k] > 1) {
+			   p->ultra_map[c] |= n;
+			} else {
+			   if (p->sp[c][k] == 0) {
+			      p->async[c] |= n;
+			   }
+			}
+		    }
+		    p->async[c] = ~(p->async[c]);
+
+		    if (p->global_map[c] == 0) {
+		       k=setupdata[c][1];
+		       if ((k & 0x40) != 0)
+			  p->global_map[c] |= 0x20;
+		       k &= 0x07;
+		       p->global_map[c] |= k;
+		       if ((setupdata[c][2] & 0x04) != 0)
+			  p->global_map[c] |= 0x08;
+		       p->host_id[c] = setupdata[c][0] & 0x07;
+		    }
+		}
+
+		k = inb(base_io + 0x28) & 0x8f;
+		k |= 0x10;
+		outb(k, base_io + 0x28);
+		outb(0x80, base_io + 0x41);
+		outb(0x80, base_io + 0x51);
+		mdelay(100);
+		outb(0, base_io + 0x41);
+		outb(0, base_io + 0x51);
+		mdelay(1000);
+		inb(base_io + 0x9b);
+		inb(base_io + 0x97);
+		inb(base_io + 0xdb);
+		inb(base_io + 0xd7);
+		tmport = base_io + 0x80;
+		k=p->host_id[0];
+		if (k > 7)
+		   k = (k & 0x07) | 0x40;
+		k |= 0x08;
+		outb(k, tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
+	
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 0x81;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x91;
+		outb(0x20, tmport);
+
+		tmport = base_io + 0xc0;
+		k=p->host_id[1];
+		if (k > 7)
+		   k = (k & 0x07) | 0x40;
+		k |= 0x08;
+		outb(k, tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
+
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 0xc1;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0xd1;
+		outb(0x20, tmport);
+
+		tscam_885();
+		printk(KERN_INFO "   Scanning Channel A SCSI Device ...\n");
+		is885(p, base_io + 0x80, 0);
+		printk(KERN_INFO "   Scanning Channel B SCSI Device ...\n");
+		is885(p, base_io + 0xc0, 1);
+
+		k = inb(base_io + 0x28) & 0xcf;
+		k |= 0xc0;
+		outb(k, base_io + 0x28);
+		k = inb(base_io + 0x1f) | 0x80;
+		outb(k, base_io + 0x1f);
+		k = inb(base_io + 0x29) | 0x01;
+		outb(k, base_io + 0x29);
+#ifdef ED_DBGP
+		//printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
+#endif		
+		shpnt->max_id = 16;
+		shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
+		shpnt->max_channel = 1;
+		shpnt->this_id = p->host_id[0];
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
+		shpnt->n_io_port = 0xff;	/* Number of bytes of I/O space used */
+		shpnt->irq = pdev->irq;
+				
 	} else {
+		error = pci_read_config_byte(pdev, 0x49, &host_id);
+
+		printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
+			"IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+
+		atp_dev.ioport[0] = base_io;
+		atp_dev.pciport[0] = base_io + 0x20;
+		atp_dev.dev_id = ent->device;
+		host_id &= 0x07;
+		atp_dev.host_id[0] = host_id;
+		tmport = base_io + 0x22;
+		atp_dev.scam_on = inb(tmport);
+		tmport += 0x0b;
+		atp_dev.global_map[0] = inb(tmport++);
+		atp_dev.ultra_map[0] = inw(tmport);
+
+		if (atp_dev.ultra_map[0] == 0) {
+			atp_dev.scam_on = 0x00;
+			atp_dev.global_map[0] = 0x20;
+			atp_dev.ultra_map[0] = 0xffff;
+		}
+
+		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+		if (!shpnt)
+			return -ENOMEM;
+
+		p = (struct atp_unit *)&shpnt->hostdata;
+		
+		atp_dev.host = shpnt;
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
+		memcpy(p, &atp_dev, sizeof atp_dev);
+		if (atp870u_init_tables(shpnt) < 0)
+			goto unregister;
+
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870i", shpnt)) {
+			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
+			goto free_tables;
+		}
+
+		spin_lock_irqsave(shpnt->host_lock, flags);
+		if (atp_dev.chip_ver > 0x07) {	/* check if atp876 chip then enable terminator */
+			tmport = base_io + 0x3e;
+			outb(0x00, tmport);
+		}
+ 
+		tmport = base_io + 0x3a;
+		k = (inb(tmport) & 0xf3) | 0x10;
+		outb(k, tmport);
+		outb((k & 0xdf), tmport);
+		mdelay(32);
+		outb(k, tmport);
+		mdelay(32);
+		tmport = base_io;
+		outb((host_id | 0x08), tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0)
+			mdelay(1);
+
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 1;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x11;
+		outb(0x20, tmport);
+
+		tscam(shpnt);
+		is870(p, base_io);
+		tmport = base_io + 0x3a;
+		outb((inb(tmport) & 0xef), tmport);
+		tmport++;
+		outb((inb(tmport) | 0x20), tmport);
+		if (atp_dev.chip_ver == 4)
+			shpnt->max_id = 16;
+		else		
+			shpnt->max_id = 7;
+		shpnt->this_id = host_id;
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
 		shpnt->n_io_port = 0x40;	/* Number of bytes of I/O space used */
-	}
-	shpnt->irq = dev->irq;
-	spin_unlock_irqrestore(shpnt->host_lock, flags);
-	if (ent->device == 0x8081) {
-		if (!request_region(base_io, 0x60, "atp870u"))
-			goto request_io_fail;
-	} else {
-		if (!request_region(base_io, 0x40, "atp870u"))
-			goto request_io_fail;
-	}
+		shpnt->irq = pdev->irq;		
+	} 
+		spin_unlock_irqrestore(shpnt->host_lock, flags);
+		if(ent->device==ATP885_DEVID) {
+			if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
+			if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		} else {
+			if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		}				
+		count++;
+		if (scsi_add_host(shpnt, &pdev->dev))
+			goto scsi_add_fail;
+		scsi_scan_host(shpnt);
+#ifdef ED_DBGP			
+		printk("atp870u_prob : exit\n");
+#endif		
+		return 0;
 
-	count++;
-	if (scsi_add_host(shpnt, &dev->dev))
-		goto scsi_add_fail;
-	scsi_scan_host(shpnt);
-	return 0;
-  
 scsi_add_fail:
-	if (ent->device == 0x8081)
+	printk("atp870u_prob:scsi_add_fail\n");
+	if(ent->device==ATP885_DEVID) {
+		release_region(base_io, 0xff);
+	} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
 		release_region(base_io, 0x60);
-	else
+	} else {
 		release_region(base_io, 0x40);
+	}
 request_io_fail:
-	free_irq(dev->irq, shpnt);
+	printk("atp870u_prob:request_io_fail\n");
+	free_irq(pdev->irq, shpnt);
 free_tables:
+	printk("atp870u_prob:free_table\n");
 	atp870u_free_tables(shpnt);
 unregister:
+	printk("atp870u_prob:unregister\n");
 	scsi_host_put(shpnt);
-	return -1;
+	return -1;		
 }
 
 /* The abort command does not leave the device in a clean state where
@@ -2565,40 +3099,40 @@ unregister:
 
 static int atp870u_abort(struct scsi_cmnd * SCpnt)
 {
-	unsigned char j, k;
+	unsigned char  j, k, c;
 	struct scsi_cmnd *workrequ;
 	unsigned int tmport;
-	struct atp_unit *dev = (struct atp_unit *)&SCpnt->device->host->hostdata;
+	struct atp_unit *dev;	
+	struct Scsi_Host *host;
+	host = SCpnt->device->host;
 
-	printk(KERN_DEBUG "working=%x last_cmd=%x ", dev->working, dev->last_cmd);
-	printk(" quhdu=%x quendu=%x ", dev->quhdu, dev->quendu);
-	tmport = dev->ioport;
-	for (j = 0; j < 0x17; j++) {
+	dev = (struct atp_unit *)&host->hostdata;
+	c=SCpnt->device->channel;
+	printk(" atp870u: abort Channel = %x \n", c);
+	printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
+	printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
+	tmport = dev->ioport[c];
+	for (j = 0; j < 0x18; j++) {
 		printk(" r%2x=%2x", j, inb(tmport++));
 	}
-	tmport += 0x05;
+	tmport += 0x04;
 	printk(" r1c=%2x", inb(tmport));
 	tmport += 0x03;
-	printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd);
-	tmport = dev->pciport;
-	printk(" r20=%2x", inb(tmport));
+	printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
+	tmport= dev->pciport[c];
+	printk(" d00=%2x", inb(tmport));
 	tmport += 0x02;
-	printk(" r22=%2x", inb(tmport));
-	tmport = dev->ioport + 0x3a;
-	printk(" r3a=%2x \n", inb(tmport));
-	tmport = dev->ioport + 0x3b;
-	printk(" r3b=%2x \n", inb(tmport));
-	for (j = 0; j < 16; j++) {
-		if (dev->id[j].curr_req != NULL) {
-			workrequ = dev->id[j].curr_req;
-			printk("\n que cdb= ");
-			for (k = 0; k < workrequ->cmd_len; k++) {
-				printk(" %2x ", workrequ->cmnd[k]);
-			}
-			printk(" last_lenu= %lx ", dev->id[j].last_lenu);
+	printk(" d02=%2x", inb(tmport));
+	for(j=0;j<16;j++) {
+	   if (dev->id[c][j].curr_req != NULL) {
+		workrequ = dev->id[c][j].curr_req;
+		printk("\n que cdb= ");
+		for (k=0; k < workrequ->cmd_len; k++) {
+		    printk(" %2x ",workrequ->cmnd[k]);
 		}
+		printk(" last_lenu= %x ",(unsigned int)dev->id[c][j].last_len);
+	   }
 	}
-	/* Sort of - the thing handles itself */
 	return SUCCESS;
 }
 
@@ -2612,20 +3146,19 @@ static const char *atp870u_info(struct S
 }
 
 #define BLS buffer + len + size
-static int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer,
-		char **start, off_t offset, int length, int inout)
+int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, 
+		      char **start, off_t offset, int length, int inout)
 {
 	static u8 buff[512];
 	int size = 0;
 	int len = 0;
 	off_t begin = 0;
 	off_t pos = 0;
-
-	if (inout)
-		return -ENOSYS;
-	if (offset == 0) {
+	
+	if (inout) 	
+		return -EINVAL;
+	if (offset == 0)
 		memset(buff, 0, sizeof(buff));
-	}
 	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.6+ac\n");
 	len += size;
 	pos = begin + len;
@@ -2637,7 +3170,7 @@ static int atp870u_proc_info(struct Scsi
 	size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
 	len += size;
 	pos = begin + len;
-
+	
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);	/* Start slop */
 	if (len > length) {
@@ -2646,15 +3179,15 @@ static int atp870u_proc_info(struct Scsi
 	return (len);
 }
 
-static int atp870u_biosparam(struct scsi_device *sdev,
-		struct block_device *dev, sector_t capacity, int *ip)
+
+static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev,
+			sector_t capacity, int *ip)
 {
 	int heads, sectors, cylinders;
 
 	heads = 64;
 	sectors = 32;
 	cylinders = (unsigned long)capacity / (heads * sectors);
-
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
@@ -2667,39 +3200,46 @@ static int atp870u_biosparam(struct scsi
 	return 0;
 }
 
-static void atp870u_remove(struct pci_dev *pdev)
-{
-	struct atp_unit *atp_dev = pci_get_drvdata(pdev);
-	struct Scsi_Host *pshost = atp_dev->host;
-
+static void atp870u_remove (struct pci_dev *pdev)
+{	
+	struct atp_unit *devext = pci_get_drvdata(pdev);
+	struct Scsi_Host *pshost = devext->host;
+	
+	
 	scsi_remove_host(pshost);
+	printk(KERN_INFO "free_irq : %d\n",pshost->irq);
 	free_irq(pshost->irq, pshost);
 	release_region(pshost->io_port, pshost->n_io_port);
+	printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
 	atp870u_free_tables(pshost);
+	printk(KERN_INFO "scsi_host_put : %p\n",pshost);
 	scsi_host_put(pshost);
-	pci_set_drvdata(pdev, NULL);
+	printk(KERN_INFO "pci_set_drvdata : %p\n",pdev);
+	pci_set_drvdata(pdev, NULL);	
 }
-
 MODULE_LICENSE("GPL");
 
 static struct scsi_host_template atp870u_template = {
-	.module			= THIS_MODULE,
-	.name			= "atp870u",
-	.proc_name		= "atp870u",
-	.proc_info		= atp870u_proc_info,
-	.info			= atp870u_info,
-	.queuecommand		= atp870u_queuecommand,
-	.eh_abort_handler	= atp870u_abort,
-	.bios_param		= atp870u_biosparam,
-	.can_queue		= qcnt,
-	.this_id		= 7,
-	.sg_tablesize		= ATP870U_SCATTER,
-	.cmd_per_lun		= ATP870U_CMDLUN,
-	.use_clustering		= ENABLE_CLUSTERING,
+     .module			= THIS_MODULE,
+     .name              	= "atp870u"		/* name */,
+     .proc_name			= "atp870u",
+     .proc_info			= atp870u_proc_info,
+     .info              	= atp870u_info		/* info */,
+     .queuecommand      	= atp870u_queuecommand	/* queuecommand */,
+     .eh_abort_handler  	= atp870u_abort		/* abort */,
+     .bios_param        	= atp870u_biosparam	/* biosparm */,
+     .can_queue         	= qcnt			/* can_queue */,
+     .this_id           	= 7			/* SCSI ID */,
+     .sg_tablesize      	= ATP870U_SCATTER	/*SG_ALL*/ /*SG_NONE*/,
+     .cmd_per_lun       	= ATP870U_CMDLUN		/* commands per lun */,
+     .use_clustering    	= ENABLE_CLUSTERING,
+     .max_sectors		= ATP870U_MAX_SECTORS,
 };
 
 static struct pci_device_id atp870u_id_table[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, 0x8081)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP885_DEVID)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID1)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID2)			  },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7610)    },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612UW)  },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612U)   },
@@ -2712,7 +3252,7 @@ static struct pci_device_id atp870u_id_t
 
 MODULE_DEVICE_TABLE(pci, atp870u_id_table);
 
-static struct pci_driver atp870u_driver = {	
+static struct pci_driver atp870u_driver = {
 	.id_table	= atp870u_id_table,
 	.name		= "atp870u",
 	.probe		= atp870u_probe,
@@ -2721,14 +3261,710 @@ static struct pci_driver atp870u_driver 
 
 static int __init atp870u_init(void)
 {
-	return pci_module_init(&atp870u_driver);
+#ifdef ED_DBGP	
+	printk("atp870u_init: Entry\n");
+#endif	
+	return pci_register_driver(&atp870u_driver);
 }
 
 static void __exit atp870u_exit(void)
 {
+#ifdef ED_DBGP	
+	printk("atp870u_exit: Entry\n");
+#endif
 	pci_unregister_driver(&atp870u_driver);
 }
 
+static void tscam_885(void)
+{
+	unsigned char i;
+
+	for (i = 0; i < 0x2; i++) {
+		mdelay(300);
+	}
+	return;
+}
+
+
+
+static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+{
+	unsigned int tmport;
+	unsigned char i, j, k, rmb, n, lvdmode;
+	unsigned short int m;
+	static unsigned char mbuf[512];
+	static unsigned char satn[9] =	{0, 0, 0, 0, 0, 0, 0, 6, 6};
+	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
+	static unsigned char synn[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synu[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synuw[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char wide[6] =	{0x80, 1, 2, 3, 1, 0};
+	static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
+
+	lvdmode=inb(wkport + 0x1b) >> 7;
+
+	for (i = 0; i < 16; i++) {
+		m = 1;
+		m = m << i;
+		if ((m & dev->active_id[c]) != 0) {
+			continue;
+		}
+		if (i == dev->host_id[c]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[c]);
+			continue;
+		}
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x01;
+		outb(0x08, tmport++);
+		outb(0x7f, tmport++);
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		j = i;
+		if ((j & 0x08) != 0) {
+			j = (j & 0x07) | 0x40;
+		}
+		outb(j, tmport);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+		dev->active_id[c] |= m;
+
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+
+phase_cmd:
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			tmport = wkport + 0x10;
+			outb(0x41, tmport);
+			goto phase_cmd;
+		}
+sel_ok:
+		tmport = wkport + 0x03;
+		outb(inqd[0], tmport++);
+		outb(inqd[1], tmport++);
+		outb(inqd[2], tmport++);
+		outb(inqd[3], tmport++);
+		outb(inqd[4], tmport++);
+		outb(inqd[5], tmport);
+		tmport += 0x07;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(inqd[6], tmport++);
+		outb(inqd[7], tmport++);
+		tmport += 0x03;
+		outb(inqd[8], tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+		tmport = wkport + 0x1b;
+		outb(0x00, tmport);
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		j = 0;
+rd_inq_data:
+		k = inb(tmport);
+		if ((k & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[j++] = inb(tmport);
+			tmport += 0x06;
+			goto rd_inq_data;
+		}
+		if ((k & 0x80) == 0) {
+			goto rd_inq_data;
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x16) {
+			goto inq_ok;
+		}
+		tmport = wkport + 0x10;
+		outb(0x46, tmport);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if (inb(tmport) != 0x16) {
+			goto sel_ok;
+		}
+inq_ok:
+		mbuf[36] = 0;
+		printk( KERN_INFO"         ID: %2d  %s\n", i, &mbuf[8]);
+		dev->id[c][i].devtype = mbuf[0];
+		rmb = mbuf[1];
+		n = mbuf[7];
+		if ((mbuf[7] & 0x60) == 0) {
+			goto not_wide;
+		}
+		if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
+			goto not_wide;
+		}
+		if (lvdmode == 0) {
+		   goto chg_wide;
+		}
+		if (dev->sp[c][i] != 0x04) {	// force u2
+		   goto chg_wide;
+		}
+
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_u3:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(u3[j++], tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_u3;
+		}
+		continue;
+u3p_out:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_in:
+		tmport = wkport + 0x14;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+u3p_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto u3p_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto u3p_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_cmd:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto u3p_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto chg_wide;
+		}
+		if (mbuf[1] != 0x06) {
+			goto chg_wide;
+		}
+		if (mbuf[2] != 0x04) {
+			goto chg_wide;
+		}
+		if (mbuf[3] == 0x09) {
+			m = 1;
+			m = m << i;
+			dev->wide_id[c] |= m;
+			dev->id[c][i].devsp = 0xce;
+#ifdef ED_DBGP		   
+			printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
+#endif
+			continue;
+		}
+chg_wide:
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_wide:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x05, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(wide[j++], tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_wide;
+		}
+		continue;
+widep_out:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_in:
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+widep_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto widep_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto widep_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_cmd:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto widep_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto not_wide;
+		}
+		if (mbuf[1] != 0x02) {
+			goto not_wide;
+		}
+		if (mbuf[2] != 0x03) {
+			goto not_wide;
+		}
+		if (mbuf[3] != 0x01) {
+			goto not_wide;
+		}
+		m = 1;
+		m = m << i;
+		dev->wide_id[c] |= m;
+not_wide:
+		if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
+		    ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+			m = 1;
+			m = m << i;
+			if ((dev->async[c] & m) != 0) {
+			   goto set_sync;
+			}
+		}
+		continue;
+set_sync:
+		if (dev->sp[c][i] == 0x02) {
+		   synu[4]=0x0c;
+		   synuw[4]=0x0c;
+		} else {
+		   if (dev->sp[c][i] >= 0x03) {
+		      synu[4]=0x0a;
+		      synuw[4]=0x0a;
+		   }
+		}
+		tmport = wkport + 0x1b;
+		j = 0;
+		if ((m & dev->wide_id[c]) != 0) {
+			j |= 0x01;
+		}
+		outb(j, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_sync:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				if ((m & dev->wide_id[c]) != 0) {
+					if ((m & dev->ultra_map[c]) != 0) {
+						outb(synuw[j++], tmport);
+					} else {
+						outb(synw[j++], tmport);
+					}
+				} else {
+					if ((m & dev->ultra_map[c]) != 0) {
+						outb(synu[j++], tmport);
+					} else {
+						outb(synn[j++], tmport);
+					}
+				}
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto try_sync;
+		}
+		continue;
+phase_outs:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00) {
+			if ((inb(tmport) & 0x01) != 0x00) {
+				tmport -= 0x06;
+				outb(0x00, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_ins:
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+phase_ins1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0x00) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto phase_ins1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto phase_ins1;
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00);
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_cmds:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+tar_dcons:
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			continue;
+		}
+		if (mbuf[1] != 0x03) {
+			continue;
+		}
+		if (mbuf[4] == 0x00) {
+			continue;
+		}
+		if (mbuf[3] > 0x64) {
+			continue;
+		}
+		if (mbuf[4] > 0x0e) {
+			mbuf[4] = 0x0e;
+		}
+		dev->id[c][i].devsp = mbuf[4];
+		if (mbuf[3] < 0x0c){
+			j = 0xb0;
+			goto set_syn_ok;
+		}
+		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+			j = 0xa0;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x1a) {
+			j = 0x20;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x33) {
+			j = 0x40;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x4c) {
+			j = 0x50;
+			goto set_syn_ok;
+		}
+		j = 0x60;
+	      set_syn_ok:
+		dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
+#ifdef ED_DBGP		
+		printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
+#endif
+	}
+	tmport = wkport + 0x16;
+	outb(0x80, tmport);
+}
+
 module_init(atp870u_init);
 module_exit(atp870u_exit);
 
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
--- a/drivers/scsi/atp870u.h
+++ b/drivers/scsi/atp870u.h
@@ -2,50 +2,64 @@
 #define _ATP870U_H
 
 #include <linux/types.h>
+#include <linux/kdev_t.h>
 
 /* I/O Port */
 
-#define MAX_CDB		12
-#define MAX_SENSE	14
-#define qcnt		32
-#define ATP870U_SCATTER 128
-#define ATP870U_CMDLUN 	1
-
-struct atp_unit {
-	unsigned long ioport;
-	unsigned long pciport;
-	unsigned char last_cmd;
-	unsigned char in_snd;
-	unsigned char in_int;
-	unsigned char quhdu;
-	unsigned char quendu;
+#define MAX_CDB 	12
+#define MAX_SENSE 	14
+#define qcnt	       	32
+#define ATP870U_SCATTER 	128
+#define ATP870U_CMDLUN  	1
+
+#define MAX_ADAPTER	8
+#define MAX_SCSI_ID	16
+#define ATP870U_MAX_SECTORS 128
+
+#define ATP885_DEVID 0x808A
+#define ATP880_DEVID1 0x8080
+#define ATP880_DEVID2 0x8081
+
+//#define ED_DBGP
+
+struct atp_unit
+{
+	unsigned long baseport;
+	unsigned long ioport[2];
+	unsigned long pciport[2];
+	unsigned long irq;
+	unsigned char last_cmd[2];
+	unsigned char in_snd[2];
+	unsigned char in_int[2];
+	unsigned char quhd[2];
+	unsigned char quend[2];
+	unsigned char global_map[2];
+	unsigned char chip_ver;
 	unsigned char scam_on;
-	unsigned char global_map;
-	unsigned char chip_veru;
-	unsigned char host_idu;
-	volatile int working;
-	unsigned short wide_idu;
-	unsigned short active_idu;
-	unsigned short ultra_map;
-	unsigned short async;
-	unsigned short deviceid;
-	unsigned char ata_cdbu[16];
-	unsigned char sp[16];
-	struct scsi_cmnd *querequ[qcnt];
-	struct atp_id {
-		unsigned char dirctu;
-		unsigned char devspu;
-		unsigned char devtypeu;
-		unsigned long prdaddru;
-		unsigned long tran_lenu;
-		unsigned long last_lenu;
-		unsigned char *prd_posu;
-		unsigned char *prd_tableu;
-		dma_addr_t prd_phys;
+	unsigned char host_id[2];
+	unsigned int working[2];
+	unsigned short wide_id[2];
+	unsigned short active_id[2];
+	unsigned short ultra_map[2];
+	unsigned short async[2];
+	unsigned short dev_id;
+	unsigned char sp[2][16];
+	unsigned char r1f[2][16];		
+	struct scsi_cmnd *quereq[2][qcnt];
+	struct atp_id
+	{
+		unsigned char dirct;
+		unsigned char devsp;
+		unsigned char devtype;
+		unsigned long tran_len;
+		unsigned long last_len;
+		unsigned char *prd_pos;
+		unsigned char *prd_table;
+		dma_addr_t prdaddr;
 		struct scsi_cmnd *curr_req;
-	} id[16];
-	struct Scsi_Host *host;
-	struct pci_dev *pdev;
+	} id[2][16];
+    	struct Scsi_Host *host;
+    	struct pci_dev *pdev;
 	unsigned int unit;
 };
 
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -372,7 +372,7 @@ static void scsi_print_cdb(unsigned char
 
 /**
  *
- *	print_status - print scsi status description
+ *	scsi_print_status - print scsi status description
  *	@scsi_status: scsi status value
  *
  *	If the status is recognized, the description is printed.
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -642,12 +642,12 @@ int cpqfcTS_ioctl( struct scsi_device *S
 				return( -EFAULT);
 			}
 		}
-		ScsiPassThruReq->sr_data_direction = SCSI_DATA_WRITE; 
+		ScsiPassThruReq->sr_data_direction = DMA_TO_DEVICE; 
 	} else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
-		ScsiPassThruReq->sr_data_direction = SCSI_DATA_READ; 
+		ScsiPassThruReq->sr_data_direction = DMA_FROM_DEVICE;
 	} else
 		// maybe this means a bug in the user app
-		ScsiPassThruReq->sr_data_direction = SCSI_DATA_NONE;
+		ScsiPassThruReq->sr_data_direction = DMA_BIDIRECTIONAL;
 	    
 	ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
 	ScsiPassThruReq->sr_sense_buffer[0] = 0;
@@ -752,7 +752,7 @@ int cpqfcTS_ioctl( struct scsi_device *S
 		result = -ENXIO;
 		break;
 	}
-	result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
+	result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;
 	if (result) break;
  
       put_user(pLoggedInPort->port_id,
diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c
--- a/drivers/scsi/cpqfcTSworker.c
+++ b/drivers/scsi/cpqfcTSworker.c
@@ -5129,7 +5129,7 @@ cpqfc_undo_SEST_mappings(struct pci_dev 
 	for (i=*sgPages_head; i != NULL ;i = next)
 	{
 		pci_unmap_single(pcidev, i->busaddr, i->maplen, 
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+			PCI_DMA_TODEVICE);
 		i->busaddr = (dma_addr_t) NULL; 
 		i->maplen = 0L; 
 		next = i->next;
@@ -5195,7 +5195,7 @@ static ULONG build_SEST_sgList( 
 			contigaddr = ulBuff = pci_map_single(pcidev, 
 				Cmnd->request_buffer, 
 				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				Cmnd->sc_data_direction);
 			// printk("ms %p ", ulBuff);
 		}
 		else {
@@ -5224,7 +5224,7 @@ static ULONG build_SEST_sgList( 
 		unsigned long btg;
 		contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
 				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				Cmnd->sc_data_direction);
 
 		// printk("contigaddr = %p, len = %d\n", 
 		//	(void *) contigaddr, bytes_to_go);
@@ -5247,7 +5247,7 @@ static ULONG build_SEST_sgList( 
  
 	sgl = (struct scatterlist*)Cmnd->request_buffer;  
 	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
-		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		Cmnd->sc_data_direction);
   	if( sg_count <= 3 ) {
 
 	// we need to be careful here that no individual mapping
@@ -5400,7 +5400,7 @@ static ULONG build_SEST_sgList( 
 
 	        cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
 			Cmnd->request_bufflen,
-			scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
+			Cmnd->sc_data_direction,
   			sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
 
 		// FIXME: testing shows that if we get here, 
@@ -5946,7 +5946,7 @@ cpqfc_pci_unmap_extended_sg(struct pci_d
 	// for each extended scatter gather region needing unmapping... 
 	for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
 		pci_unmap_single(pcidev, i->busaddr, i->maplen,
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+			PCI_DMA_TODEVICE);
 }
 
 // Called also from cpqfcTScontrol.o, so can't be static
@@ -5960,14 +5960,14 @@ cpqfc_pci_unmap(struct pci_dev *pcidev, 
 	if (cmd->use_sg) {	// Used scatter gather list for data buffer?
 		cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
 		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			cmd->sc_data_direction);
 		// printk("umsg %d\n", cmd->use_sg);
 	}
 	else if (cmd->request_bufflen) {
 		// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
 		pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
 			cmd->request_bufflen,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			cmd->sc_data_direction);
 	}	 
 }
 
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -56,6 +56,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -182,7 +183,7 @@
  * cross a page boundy.
  */
 #define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
-
+#define VIRTX_LEN	(sizeof(void *) * DC395x_MAX_SG_LISTENTRY)
 
 struct SGentry {
 	u32 address;		/* bus! address */
@@ -234,6 +235,7 @@ struct ScsiReqBlk {
 	u8 sg_count;			/* No of HW sg entries for this request */
 	u8 sg_index;			/* Index of HW sg entry for this request */
 	u32 total_xfer_length;		/* Total number of bytes remaining to be transfered */
+	void **virt_map;
 	unsigned char *virt_addr;	/* Virtual address of current transfer position */
 
 	/*
@@ -1020,14 +1022,14 @@ static void build_srb(struct scsi_cmnd *
 			reqlen, cmd->request_buffer, cmd->use_sg,
 			srb->sg_count);
 
-		srb->virt_addr = page_address(sl->page);
 		for (i = 0; i < srb->sg_count; i++) {
-			u32 busaddr = (u32)sg_dma_address(&sl[i]);
-			u32 seglen = (u32)sl[i].length;
-			sgp[i].address = busaddr;
+			u32 seglen = (u32)sg_dma_len(sl + i);
+			sgp[i].address = (u32)sg_dma_address(sl + i);
 			sgp[i].length = seglen;
 			srb->total_xfer_length += seglen;
+			srb->virt_map[i] = kmap(sl[i].page);
 		}
+		srb->virt_addr = srb->virt_map[0];
 		sgp += srb->sg_count - 1;
 
 		/*
@@ -1964,6 +1966,7 @@ static void sg_update_list(struct ScsiRe
 	int segment = cmd->use_sg;
 	u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
 	struct SGentry *psge = srb->segment_x + srb->sg_index;
+	void **virt = srb->virt_map;
 
 	dprintkdbg(DBG_0,
 		"sg_update_list: Transfered %i of %i bytes, %i remain\n",
@@ -2003,16 +2006,16 @@ static void sg_update_list(struct ScsiRe
 
 	/* We have to walk the scatterlist to find it */
 	sg = (struct scatterlist *)cmd->request_buffer;
+	idx = 0;
 	while (segment--) {
 		unsigned long mask =
 		    ~((unsigned long)sg->length - 1) & PAGE_MASK;
 		if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
-			srb->virt_addr = (page_address(sg->page)
-					   + psge->address -
-					   (psge->address & PAGE_MASK));
+			srb->virt_addr = virt[idx] + (psge->address & ~PAGE_MASK);
 			return;
 		}
 		++sg;
+		++idx;
 	}
 
 	dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n");
@@ -2138,7 +2141,7 @@ static void data_out_phase0(struct Adapt
 				DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
 		}
 		/*
-		 * calculate all the residue data that not yet tranfered
+		 * calculate all the residue data that not yet transfered
 		 * SCSI transfer counter + left in SCSI FIFO data
 		 *
 		 * .....TRM_S1040_SCSI_COUNTER (24bits)
@@ -3256,6 +3259,7 @@ static void pci_unmap_srb(struct Adapter
 	struct scsi_cmnd *cmd = srb->cmd;
 	enum dma_data_direction dir = cmd->sc_data_direction;
 	if (cmd->use_sg && dir != PCI_DMA_NONE) {
+		int i;
 		/* unmap DC395x SG list */
 		dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
 			srb->sg_bus_addr, SEGMENTX_LEN);
@@ -3265,6 +3269,8 @@ static void pci_unmap_srb(struct Adapter
 		dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
 			cmd->use_sg, cmd->request_buffer);
 		/* unmap the sg segments */
+		for (i = 0; i < srb->sg_count; i++)
+			kunmap(virt_to_page(srb->virt_map[i]));
 		pci_unmap_sg(acb->dev,
 			     (struct scatterlist *)cmd->request_buffer,
 			     cmd->use_sg, dir);
@@ -3311,7 +3317,7 @@ static void srb_done(struct AdapterCtlBl
 
 	if (cmd->use_sg) {
 		struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
-		ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset);
+		ptr = (struct ScsiInqData *)(srb->virt_map[0] + sg->offset);
 	} else {
 		ptr = (struct ScsiInqData *)(cmd->request_buffer);
 	}
@@ -4246,8 +4252,9 @@ static void adapter_sg_tables_free(struc
 	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
 
 	for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
-		if (acb->srb_array[i].segment_x)
-			kfree(acb->srb_array[i].segment_x);
+		kfree(acb->srb_array[i].segment_x);
+
+	vfree(acb->srb_array[0].virt_map);
 }
 
 
@@ -4263,9 +4270,12 @@ static int __devinit adapter_sg_tables_a
 	int srb_idx = 0;
 	unsigned i = 0;
 	struct SGentry *ptr;
+	void **virt_array;
 
-	for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
+	for (i = 0; i < DC395x_MAX_SRB_CNT; i++) {
 		acb->srb_array[i].segment_x = NULL;
+		acb->srb_array[i].virt_map = NULL;
+	}
 
 	dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
 	while (pages--) {
@@ -4286,6 +4296,19 @@ static int __devinit adapter_sg_tables_a
 		    ptr + (i * DC395x_MAX_SG_LISTENTRY);
 	else
 		dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n");
+
+	virt_array = vmalloc((DC395x_MAX_SRB_CNT + 1) * DC395x_MAX_SG_LISTENTRY * sizeof(void*));
+
+	if (!virt_array) {
+		adapter_sg_tables_free(acb);
+		return 1;
+	}
+
+	for (i = 0; i < DC395x_MAX_SRB_CNT + 1; i++) {
+		acb->srb_array[i].virt_map = virt_array;
+		virt_array += DC395x_MAX_SG_LISTENTRY;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -107,7 +107,7 @@ static dpt_sig_S DPTI_sig = {
  *============================================================================
  */
 
-DECLARE_MUTEX(adpt_configuration_lock);
+static DECLARE_MUTEX(adpt_configuration_lock);
 
 static struct i2o_sys_tbl *sys_tbl = NULL;
 static int sys_tbl_ind = 0;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -49,6 +49,8 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
+#define DRV_VERSION "1.101"
+
 #define DEBUG_ESP
 /* #define DEBUG_ESP_HME */
 /* #define DEBUG_ESP_DATA */
@@ -1145,7 +1147,7 @@ static int __init esp_detect(struct scsi
 	static struct sbus_dev esp_dev;
 	int esps_in_use = 0;
 
-	espchain = 0;
+	espchain = NULL;
 
 	if (sun4_esp_physaddr) {
 		memset (&esp_dev, 0, sizeof(esp_dev));
@@ -2511,7 +2513,7 @@ static inline void esp_reconnect(struct 
 		ESPLOG(("esp%d: Weird, being reselected but disconnected "
 			"command queue is empty.\n", esp->esp_id));
 	esp->snip = 0;
-	esp->current_SC = 0;
+	esp->current_SC = NULL;
 	sp->SCp.phase = not_issued;
 	append_SC(&esp->issue_SC, sp);
 }
@@ -4146,7 +4148,7 @@ static int esp_work_bus(struct esp *esp)
 }
 
 static espfunc_t isvc_vector[] = {
-	0,
+	NULL,
 	esp_do_phase_determine,
 	esp_do_resetbus,
 	esp_finish_reset,
@@ -4398,5 +4400,8 @@ static struct scsi_host_template driver_
 
 #include "scsi_module.c"
 
+MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4034,7 +4034,7 @@ static void gdth_log_event(gdth_evt_data
 }
 
 #ifdef GDTH_STATISTICS
-void gdth_timeout(ulong data)
+static void gdth_timeout(ulong data)
 {
     ulong32 i;
     Scsi_Cmnd *nscp;
@@ -4062,7 +4062,7 @@ void gdth_timeout(ulong data)
 }
 #endif
 
-void __init internal_setup(char *str,int *ints)
+static void __init internal_setup(char *str,int *ints)
 {
     int i, argc;
     char *cur_str, *argv;
@@ -4153,7 +4153,7 @@ int __init option_setup(char *str)
     return 1;
 }
 
-int __init gdth_detect(Scsi_Host_Template *shtp)
+static int __init gdth_detect(Scsi_Host_Template *shtp)
 {
     struct Scsi_Host *shp;
     gdth_pci_str pcistr[MAXHA];
@@ -4604,7 +4604,7 @@ int __init gdth_detect(Scsi_Host_Templat
 }
 
 
-int gdth_release(struct Scsi_Host *shp)
+static int gdth_release(struct Scsi_Host *shp)
 {
     int hanum;
     gdth_ha_str *ha;
@@ -4691,7 +4691,7 @@ static const char *gdth_ctr_name(int han
     return("");
 }
 
-const char *gdth_info(struct Scsi_Host *shp)
+static const char *gdth_info(struct Scsi_Host *shp)
 {
     int hanum;
     gdth_ha_str *ha;
@@ -4704,19 +4704,19 @@ const char *gdth_info(struct Scsi_Host *
 }
 
 /* new error handling */
-int gdth_eh_abort(Scsi_Cmnd *scp)
+static int gdth_eh_abort(Scsi_Cmnd *scp)
 {
     TRACE2(("gdth_eh_abort()\n"));
     return FAILED;
 }
 
-int gdth_eh_device_reset(Scsi_Cmnd *scp)
+static int gdth_eh_device_reset(Scsi_Cmnd *scp)
 {
     TRACE2(("gdth_eh_device_reset()\n"));
     return FAILED;
 }
 
-int gdth_eh_bus_reset(Scsi_Cmnd *scp)
+static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
 {
     int i, hanum;
     gdth_ha_str *ha;
@@ -4770,7 +4770,7 @@ int gdth_eh_bus_reset(Scsi_Cmnd *scp)
     return SUCCESS;
 }
 
-int gdth_eh_host_reset(Scsi_Cmnd *scp)
+static int gdth_eh_host_reset(Scsi_Cmnd *scp)
 {
     TRACE2(("gdth_eh_host_reset()\n"));
     return FAILED;
@@ -4778,9 +4778,9 @@ int gdth_eh_host_reset(Scsi_Cmnd *scp)
 
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
+static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
 #else
-int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 #endif
 {
     unchar b, t;
@@ -4818,7 +4818,7 @@ int gdth_bios_param(Disk *disk,kdev_t de
 }
 
 
-int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
 {
     int hanum;
     int priority;
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -1029,51 +1029,10 @@ typedef struct {
 
 /* function prototyping */
 
-int gdth_detect(Scsi_Host_Template *);
-int gdth_release(struct Scsi_Host *);
-int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
-const char *gdth_info(struct Scsi_Host *);
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *);
 int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-int gdth_bios_param(Disk *,kdev_t,int *);
-int gdth_proc_info(char *,char **,off_t,int,int,int);
 #else
-int gdth_bios_param(Disk *,kdev_t,int *);
-extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-int gdth_abort(Scsi_Cmnd *);
-int gdth_reset(Scsi_Cmnd *,unsigned int); 
-#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
-               proc_info:       gdth_proc_info,                  \
-               name:            "GDT SCSI Disk Array Controller",\
-               detect:          gdth_detect,                     \
-               release:         gdth_release,                    \
-               info:            gdth_info,                       \
-               command:         NULL,                            \
-               queuecommand:    gdth_queuecommand,               \
-               eh_abort_handler: gdth_eh_abort,                  \
-               eh_device_reset_handler: gdth_eh_device_reset,    \
-               eh_bus_reset_handler: gdth_eh_bus_reset,          \
-               eh_host_reset_handler: gdth_eh_host_reset,        \
-               abort:           gdth_abort,                      \
-               reset:           gdth_reset,                      \
-               bios_param:      gdth_bios_param,                 \
-               can_queue:       GDTH_MAXCMDS,                    \
-               this_id:         -1,                              \
-               sg_tablesize:    GDTH_MAXSG,                      \
-               cmd_per_lun:     GDTH_MAXC_P_L,                   \
-               present:         0,                               \
-               unchecked_isa_dma: 1,                             \
-               use_clustering:  ENABLE_CLUSTERING,               \
-               use_new_eh_code: 1       /* use new error code */ }    
 #endif
 
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
-
 #endif
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -129,6 +129,15 @@ int scsi_add_host(struct Scsi_Host *shos
 					 GFP_KERNEL)) == NULL)
 		goto out_del_classdev;
 
+	if (shost->transportt->create_work_queue) {
+		snprintf(shost->work_q_name, KOBJ_NAME_LEN, "scsi_wq_%d",
+			shost->host_no);
+		shost->work_q = create_singlethread_workqueue(
+					shost->work_q_name);
+		if (!shost->work_q)
+			goto out_free_shost_data;
+	}
+
 	error = scsi_sysfs_add_host(shost);
 	if (error)
 		goto out_destroy_host;
@@ -137,6 +146,10 @@ int scsi_add_host(struct Scsi_Host *shos
 	return error;
 
  out_destroy_host:
+	if (shost->work_q)
+		destroy_workqueue(shost->work_q);
+ out_free_shost_data:
+	kfree(shost->shost_data);
  out_del_classdev:
 	class_device_del(&shost->shost_classdev);
  out_del_gendev:
@@ -160,6 +173,9 @@ static void scsi_host_dev_release(struct
 		shost->eh_notify = NULL;
 	}
 
+	if (shost->work_q)
+		destroy_workqueue(shost->work_q);
+
 	scsi_proc_hostdir_rm(shost->hostt);
 	scsi_destroy_command_freelist(shost);
 	kfree(shost->shost_data);
@@ -216,6 +232,7 @@ struct Scsi_Host *scsi_host_alloc(struct
 	spin_lock_init(&shost->default_lock);
 	scsi_assign_lock(shost, &shost->default_lock);
 	INIT_LIST_HEAD(&shost->__devices);
+	INIT_LIST_HEAD(&shost->__targets);
 	INIT_LIST_HEAD(&shost->eh_cmd_q);
 	INIT_LIST_HEAD(&shost->starved_list);
 	init_waitqueue_head(&shost->host_wait);
@@ -247,6 +264,16 @@ struct Scsi_Host *scsi_host_alloc(struct
 	shost->cmd_per_lun = sht->cmd_per_lun;
 	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
 	shost->use_clustering = sht->use_clustering;
+	shost->ordered_flush = sht->ordered_flush;
+	shost->ordered_tag = sht->ordered_tag;
+
+	/*
+	 * hosts/devices that do queueing must support ordered tags
+	 */
+	if (shost->can_queue > 1 && shost->ordered_flush) {
+		printk(KERN_ERR "scsi: ordered flushes don't support queueing\n");
+		shost->ordered_flush = 0;
+	}
 
 	if (sht->max_host_blocked)
 		shost->max_host_blocked = sht->max_host_blocked;
@@ -392,3 +419,44 @@ int scsi_is_host_device(const struct dev
 	return dev->release == scsi_host_dev_release;
 }
 EXPORT_SYMBOL(scsi_is_host_device);
+
+/**
+ * scsi_queue_work - Queue work to the Scsi_Host workqueue.
+ * @shost:	Pointer to Scsi_Host.
+ * @work:	Work to queue for execution.
+ *
+ * Return value:
+ * 	0 on success / != 0 for error
+ **/
+int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+{
+	if (unlikely(!shost->work_q)) {
+		printk(KERN_ERR
+			"ERROR: Scsi host '%s' attempted to queue scsi-work, "
+			"when no workqueue created.\n", shost->hostt->name);
+		dump_stack();
+
+		return -EINVAL;
+	}
+
+	return queue_work(shost->work_q, work);
+}
+EXPORT_SYMBOL_GPL(scsi_queue_work);
+
+/**
+ * scsi_flush_work - Flush a Scsi_Host's workqueue.
+ * @shost:	Pointer to Scsi_Host.
+ **/
+void scsi_flush_work(struct Scsi_Host *shost)
+{
+	if (!shost->work_q) {
+		printk(KERN_ERR
+			"ERROR: Scsi host '%s' attempted to flush scsi-work, "
+			"when no workqueue created.\n", shost->hostt->name);
+		dump_stack();
+		return;
+	}
+
+	flush_workqueue(shost->work_q);
+}
+EXPORT_SYMBOL_GPL(scsi_flush_work);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -96,14 +96,42 @@ typedef struct idescsi_pc_s {
  */
 #define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
 
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_scsi_obj {
+	ide_drive_t		*drive;
+	ide_driver_t		*driver;
+	struct gendisk		*disk;
+	struct Scsi_Host	*host;
+
 	idescsi_pc_t *pc;			/* Current packet command */
 	unsigned long flags;			/* Status/Action flags */
 	unsigned long transform;		/* SCSI cmd translation layer */
 	unsigned long log;			/* log flags */
 } idescsi_scsi_t;
 
+static DECLARE_MUTEX(idescsi_ref_sem);
+
+#define ide_scsi_g(disk) \
+	container_of((disk)->private_data, struct ide_scsi_obj, driver)
+
+static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk)
+{
+	struct ide_scsi_obj *scsi = NULL;
+
+	down(&idescsi_ref_sem);
+	scsi = ide_scsi_g(disk);
+	if (scsi)
+		scsi_host_get(scsi->host);
+	up(&idescsi_ref_sem);
+	return scsi;
+}
+
+static void ide_scsi_put(struct ide_scsi_obj *scsi)
+{
+	down(&idescsi_ref_sem);
+	scsi_host_put(scsi->host);
+	up(&idescsi_ref_sem);
+}
+
 static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
 {
 	return (idescsi_scsi_t*) (&host[1]);
@@ -151,8 +179,18 @@ static void idescsi_input_buffers (ide_d
 			return;
 		}
 		count = min(pc->sg->length - pc->b_count, bcount);
-		buf = page_address(pc->sg->page) + pc->sg->offset;
-		drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count);
+		if (PageHighMem(pc->sg->page)) {
+			unsigned long flags;
+
+			local_irq_save(flags);
+			buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset;
+			drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count);
+			kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
+			local_irq_restore(flags);
+		} else {
+			buf = page_address(pc->sg->page) + pc->sg->offset;
+			drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count);
+		}
 		bcount -= count; pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
@@ -173,8 +211,18 @@ static void idescsi_output_buffers (ide_
 			return;
 		}
 		count = min(pc->sg->length - pc->b_count, bcount);
-		buf = page_address(pc->sg->page) + pc->sg->offset;
-		drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count);
+		if (PageHighMem(pc->sg->page)) {
+			unsigned long flags;
+
+			local_irq_save(flags);
+			buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset;
+			drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count);
+			kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
+			local_irq_restore(flags);
+		} else {
+			buf = page_address(pc->sg->page) + pc->sg->offset;
+			drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count);
+		}
 		bcount -= count; pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
@@ -298,9 +346,12 @@ static int idescsi_check_condition(ide_d
 		printk ("ide-scsi: %s: queue cmd = ", drive->name);
 		hexdump(pc->c, 6);
 	}
+	rq->rq_disk = scsi->disk;
 	return ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
+static int idescsi_end_request(ide_drive_t *, int, int);
+
 static ide_startstop_t
 idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
@@ -309,7 +360,9 @@ idescsi_atapi_error(ide_drive_t *drive, 
 		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
 
 	rq->errors++;
-	DRIVER(drive)->end_request(drive, 0, 0);
+
+	idescsi_end_request(drive, 0, 0);
+
 	return ide_stopped;
 }
 
@@ -321,7 +374,9 @@ idescsi_atapi_abort(ide_drive_t *drive, 
 			((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number);
 #endif
 	rq->errors |= ERROR_MAX;
-	DRIVER(drive)->end_request(drive, 0, 0);
+
+	idescsi_end_request(drive, 0, 0);
+
 	return ide_stopped;
 }
 
@@ -678,8 +733,6 @@ static void idescsi_add_settings(ide_dri
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
 {
-	DRIVER(drive)->busy++;
-	drive->ready_stat = 0;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
 		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
@@ -688,57 +741,84 @@ static void idescsi_setup (ide_drive_t *
 	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 	idescsi_add_settings(drive);
-	DRIVER(drive)->busy--;
 }
 
-static int idescsi_cleanup (ide_drive_t *drive)
+static int ide_scsi_remove(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	struct Scsi_Host *scsihost = drive->driver_data;
+	struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
+	struct gendisk *g = scsi->disk;
+
+	ide_unregister_subdriver(drive, scsi->driver);
+
+	ide_unregister_region(g);
 
-	if (ide_unregister_subdriver(drive))
-		return 1;
-	
-	/* FIXME?: Are these two statements necessary? */
 	drive->driver_data = NULL;
-	drive->disk->fops = ide_fops;
+	g->private_data = NULL;
+	put_disk(g);
 
 	scsi_remove_host(scsihost);
-	scsi_host_put(scsihost);
+	ide_scsi_put(scsi);
+
 	return 0;
 }
 
-static int idescsi_attach(ide_drive_t *drive);
+static int ide_scsi_probe(struct device *);
+
+#ifdef CONFIG_PROC_FS
+static ide_proc_entry_t idescsi_proc[] = {
+	{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#else
+# define idescsi_proc	NULL
+#endif
 
-/*
- *	IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idescsi_driver = {
 	.owner			= THIS_MODULE,
-	.name			= "ide-scsi",
+	.gen_driver = {
+		.name		= "ide-scsi",
+		.bus		= &ide_bus_type,
+		.probe		= ide_scsi_probe,
+		.remove		= ide_scsi_remove,
+	},
 	.version		= IDESCSI_VERSION,
 	.media			= ide_scsi,
-	.busy			= 0,
 	.supports_dsc_overlap	= 0,
-	.attach			= idescsi_attach,
-	.cleanup		= idescsi_cleanup,
+	.proc			= idescsi_proc,
 	.do_request		= idescsi_do_request,
 	.end_request		= idescsi_end_request,
 	.error                  = idescsi_atapi_error,
 	.abort                  = idescsi_atapi_abort,
-	.drives			= LIST_HEAD_INIT(idescsi_driver.drives),
 };
 
 static int idescsi_ide_open(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_scsi_obj *scsi;
+	ide_drive_t *drive;
+
+	if (!(scsi = ide_scsi_get(disk)))
+		return -ENXIO;
+
+	drive = scsi->drive;
+
 	drive->usage++;
+
 	return 0;
 }
 
 static int idescsi_ide_release(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_scsi_obj *scsi = ide_scsi_g(disk);
+	ide_drive_t *drive = scsi->drive;
+
 	drive->usage--;
+
+	ide_scsi_put(scsi);
+
 	return 0;
 }
 
@@ -746,7 +826,8 @@ static int idescsi_ide_ioctl(struct inod
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	return generic_ide_ioctl(file, bdev, cmd, arg);
+	struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk);
+	return generic_ide_ioctl(scsi->drive, file, bdev, cmd, arg);
 }
 
 static struct block_device_operations idescsi_ops = {
@@ -756,8 +837,6 @@ static struct block_device_operations id
 	.ioctl		= idescsi_ide_ioctl,
 };
 
-static int idescsi_attach(ide_drive_t *drive);
-
 static int idescsi_slave_configure(struct scsi_device * sdp)
 {
 	/* Configure detected device */
@@ -858,6 +937,7 @@ static int idescsi_queue (struct scsi_cm
 	rq->special = (char *) pc;
 	rq->flags = REQ_SPECIAL;
 	spin_unlock_irq(host->host_lock);
+	rq->rq_disk = scsi->disk;
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
 	spin_lock_irq(host->host_lock);
 	return 0;
@@ -1029,12 +1109,14 @@ static struct scsi_host_template idescsi
 	.proc_name		= "ide-scsi",
 };
 
-static int idescsi_attach(ide_drive_t *drive)
+static int ide_scsi_probe(struct device *dev)
 {
+	ide_drive_t *drive = to_ide_device(dev);
 	idescsi_scsi_t *idescsi;
 	struct Scsi_Host *host;
+	struct gendisk *g;
 	static int warned;
-	int err;
+	int err = -ENOMEM;
 
 	if (!warned && drive->media == ide_cdrom) {
 		printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
@@ -1045,7 +1127,13 @@ static int idescsi_attach(ide_drive_t *d
 	    !drive->present ||
 	    drive->media == ide_disk ||
 	    !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
-		return 1;
+		return -ENODEV;
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_host_put;
+
+	ide_init_disk(g, drive);
 
 	host->max_id = 1;
 
@@ -1061,31 +1149,38 @@ static int idescsi_attach(ide_drive_t *d
 	drive->driver_data = host;
 	idescsi = scsihost_to_idescsi(host);
 	idescsi->drive = drive;
-	err = ide_register_subdriver(drive, &idescsi_driver);
+	idescsi->driver = &idescsi_driver;
+	idescsi->host = host;
+	idescsi->disk = g;
+	g->private_data = &idescsi->driver;
+	ide_register_subdriver(drive, &idescsi_driver);
+	err = 0;
+	idescsi_setup(drive, idescsi);
+	g->fops = &idescsi_ops;
+	ide_register_region(g);
+	err = scsi_add_host(host, &drive->gendev);
 	if (!err) {
-		idescsi_setup (drive, idescsi);
-		drive->disk->fops = &idescsi_ops;
-		err = scsi_add_host(host, &drive->gendev);
-		if (!err) {
-			scsi_scan_host(host);
-			return 0;
-		}
-		/* fall through on error */
-		ide_unregister_subdriver(drive);
+		scsi_scan_host(host);
+		return 0;
 	}
+	/* fall through on error */
+	ide_unregister_region(g);
+	ide_unregister_subdriver(drive, &idescsi_driver);
 
+	put_disk(g);
+out_host_put:
 	scsi_host_put(host);
 	return err;
 }
 
 static int __init init_idescsi_module(void)
 {
-	return ide_register_driver(&idescsi_driver);
+	return driver_register(&idescsi_driver.gen_driver);
 }
 
 static void __exit exit_idescsi_module(void)
 {
-	ide_unregister_driver(&idescsi_driver);
+	driver_unregister(&idescsi_driver.gen_driver);
 }
 
 module_init(init_idescsi_module);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -89,6 +89,8 @@ static struct list_head ipr_ioa_head = L
 static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
 static unsigned int ipr_max_speed = 1;
 static int ipr_testmode = 0;
+static unsigned int ipr_fastfail = 0;
+static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
@@ -108,7 +110,7 @@ static const struct ipr_chip_cfg_t ipr_c
 			.clr_uproc_interrupt_reg = 0x00218
 		}
 	},
-	{ /* Snipe */
+	{ /* Snipe and Scamp */
 		.mailbox = 0x0052C,
 		.cache_line_size = 0x20,
 		{
@@ -125,6 +127,13 @@ static const struct ipr_chip_cfg_t ipr_c
 	},
 };
 
+static const struct ipr_chip_t ipr_chip[] = {
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
+};
+
 static int ipr_max_bus_speeds [] = {
 	IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE
 };
@@ -137,6 +146,10 @@ module_param_named(log_level, ipr_log_le
 MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver");
 module_param_named(testmode, ipr_testmode, int, 0);
 MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations");
+module_param_named(fastfail, ipr_fastfail, int, 0);
+MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
+module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
+MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -310,10 +323,12 @@ struct ipr_error_table_t ipr_error_table
 	"3150: SCSI bus configuration error"},
 	{0x06690200, 0, 1,
 	"9041: Array protection temporarily suspended"},
+	{0x06698200, 0, 1,
+	"9042: Corrupt array parity detected on specified device"},
 	{0x066B0200, 0, 1,
 	"9030: Array no longer protected due to missing or failed disk unit"},
 	{0x066B8200, 0, 1,
-	"9042: Corrupt array parity detected on specified device"},
+	"9032: Array exposed but still protected"},
 	{0x07270000, 0, 0,
 	"Failure due to other device"},
 	{0x07278000, 0, 1,
@@ -779,8 +794,6 @@ static void ipr_init_res_entry(struct ip
 	res->add_to_ml = 0;
 	res->del_from_ml = 0;
 	res->resetting_device = 0;
-	res->tcq_active = 0;
-	res->qdepth = IPR_MAX_CMD_PER_LUN;
 	res->sdev = NULL;
 }
 
@@ -1001,9 +1014,7 @@ static void ipr_log_array_error(struct i
 	int i;
 	struct ipr_hostrcb_type_04_error *error;
 	struct ipr_hostrcb_array_data_entry *array_entry;
-	u8 zero_sn[IPR_SERIAL_NUM_LEN];
-
-	memset(zero_sn, '0', IPR_SERIAL_NUM_LEN);
+	const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' };
 
 	error = &hostrcb->hcam.u.error.u.type_04_error;
 
@@ -1024,7 +1035,7 @@ static void ipr_log_array_error(struct i
 		if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN))
 			continue;
 
-		if (error->exposed_mode_adn == i) {
+		if (be32_to_cpu(error->exposed_mode_adn) == i) {
 			ipr_err("Exposed Array Member %d:\n", i);
 		} else {
 			ipr_err("Array Member %d:\n", i);
@@ -1250,6 +1261,41 @@ static void ipr_timeout(struct ipr_cmnd 
 }
 
 /**
+ * ipr_oper_timeout -  Adapter timed out transitioning to operational
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function blocks host requests and initiates an
+ * adapter reset.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd)
+{
+	unsigned long lock_flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	ioa_cfg->errors_logged++;
+	dev_err(&ioa_cfg->pdev->dev,
+		"Adapter timed out transitioning to operational.\n");
+
+	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+		ioa_cfg->sdt_state = GET_DUMP;
+
+	if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) {
+		if (ipr_fastfail)
+			ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES;
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	LEAVE;
+}
+
+/**
  * ipr_reset_reload - Reset/Reload the IOA
  * @ioa_cfg:		ioa config struct
  * @shutdown_type:	shutdown type
@@ -1390,7 +1436,7 @@ static int ipr_wait_iodbg_ack(struct ipr
  **/
 static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
 				      u32 start_addr,
-				      u32 *dest, u32 length_in_words)
+				      __be32 *dest, u32 length_in_words)
 {
 	volatile u32 temp_pcii_reg;
 	int i, delay = 0;
@@ -1482,7 +1528,7 @@ static int ipr_sdt_copy(struct ipr_ioa_c
 {
 	int bytes_copied = 0;
 	int cur_len, rc, rem_len, rem_page_len;
-	u32 *page;
+	__be32 *page;
 	unsigned long lock_flags = 0;
 	struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump;
 
@@ -1490,7 +1536,7 @@ static int ipr_sdt_copy(struct ipr_ioa_c
 	       (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) {
 		if (ioa_dump->page_offset >= PAGE_SIZE ||
 		    ioa_dump->page_offset == 0) {
-			page = (u32 *)__get_free_page(GFP_ATOMIC);
+			page = (__be32 *)__get_free_page(GFP_ATOMIC);
 
 			if (!page) {
 				ipr_trace;
@@ -1705,8 +1751,8 @@ static void ipr_get_ioa_dump(struct ipr_
 	 on entries in this table */
 	sdt = &ioa_dump->sdt;
 
-	rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (u32 *)sdt,
-					sizeof(struct ipr_sdt) / sizeof(u32));
+	rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt,
+					sizeof(struct ipr_sdt) / sizeof(__be32));
 
 	/* Smart Dump table is ready to use and the first entry is valid */
 	if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) {
@@ -1878,6 +1924,7 @@ restart:
 	}
 
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	kobject_uevent(&ioa_cfg->host->shost_classdev.kobj, KOBJ_CHANGE, NULL);
 	LEAVE;
 }
 
@@ -2619,100 +2666,48 @@ static int ipr_free_dump(struct ipr_ioa_
  **/
 static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
-	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
-	struct ipr_resource_entry *res;
-	int tagged = 0;
-	unsigned long lock_flags = 0;
-
-	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	res = (struct ipr_resource_entry *)sdev->hostdata;
-	if (res) {
-		res->qdepth = qdepth;
-
-		if (ipr_is_gscsi(res) && res->tcq_active)
-			tagged = MSG_ORDERED_TAG;
-	}
-
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-	scsi_adjust_queue_depth(sdev, tagged, qdepth);
-	return qdepth;
+	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+	return sdev->queue_depth;
 }
 
 /**
- * ipr_show_tcq_enable - Show if the device is enabled for tcqing
- * @dev:	device struct
- * @buf:	buffer
+ * ipr_change_queue_type - Change the device's queue type
+ * @dsev:		scsi device struct
+ * @tag_type:	type of tags to use
  *
  * Return value:
- * 	number of bytes printed to buffer
+ * 	actual queue type set
  **/
-static ssize_t ipr_show_tcq_enable(struct device *dev, char *buf)
+static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type)
 {
-	struct scsi_device *sdev = to_scsi_device(dev);
 	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
 	struct ipr_resource_entry *res;
 	unsigned long lock_flags = 0;
-	ssize_t len = -ENXIO;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 	res = (struct ipr_resource_entry *)sdev->hostdata;
-	if (res)
-		len = snprintf(buf, PAGE_SIZE, "%d\n", res->tcq_active);
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-	return len;
-}
-
-/**
- * ipr_store_tcq_enable - Change the device's TCQing state
- * @dev:	device struct
- * @buf:	buffer
- *
- * Return value:
- * 	number of bytes printed to buffer
- **/
-static ssize_t ipr_store_tcq_enable(struct device *dev,
-				    const char *buf, size_t count)
-{
-	struct scsi_device *sdev = to_scsi_device(dev);
-	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
-	struct ipr_resource_entry *res;
-	unsigned long lock_flags = 0;
-	int tcq_active = simple_strtoul(buf, NULL, 10);
-	ssize_t len = -ENXIO;
-
-	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-
-	res = (struct ipr_resource_entry *)sdev->hostdata;
 
 	if (res) {
 		if (ipr_is_gscsi(res) && sdev->tagged_supported) {
-			if (tcq_active) {
-				res->tcq_active = 1;
-				scsi_activate_tcq(sdev, res->qdepth);
-			} else {
-				res->tcq_active = 0;
-				scsi_deactivate_tcq(sdev, res->qdepth);
-			}
+			/*
+			 * We don't bother quiescing the device here since the
+			 * adapter firmware does it for us.
+			 */
+			scsi_set_tag_type(sdev, tag_type);
 
-			len = strlen(buf);
-		} else if (tcq_active) {
-			len = -EINVAL;
-		}
-	}
+			if (tag_type)
+				scsi_activate_tcq(sdev, sdev->queue_depth);
+			else
+				scsi_deactivate_tcq(sdev, sdev->queue_depth);
+		} else
+			tag_type = 0;
+	} else
+		tag_type = 0;
 
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-	return len;
+	return tag_type;
 }
 
-static struct device_attribute ipr_tcqing_attr = {
-	.attr = {
-		.name = 	"tcq_enable",
-		.mode =		S_IRUSR | S_IWUSR,
-	},
-	.store = ipr_store_tcq_enable,
-	.show = ipr_show_tcq_enable
-};
-
 /**
  * ipr_show_adapter_handle - Show the adapter's resource handle for this device
  * @dev:	device struct
@@ -2746,7 +2741,6 @@ static struct device_attribute ipr_adapt
 };
 
 static struct device_attribute *ipr_dev_attrs[] = {
-	&ipr_tcqing_attr,
 	&ipr_adapter_handle_attr,
 	NULL,
 };
@@ -2832,11 +2826,13 @@ static int ipr_slave_configure(struct sc
 			sdev->type = TYPE_RAID;
 		if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res))
 			sdev->scsi_level = 4;
-		if (ipr_is_vset_device(res))
+		if (ipr_is_vset_device(res)) {
 			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
+		}
 		if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))
 			sdev->allow_restart = 1;
-		scsi_adjust_queue_depth(sdev, 0, res->qdepth);
+		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
 	}
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	return 0;
@@ -3514,7 +3510,7 @@ static void ipr_erp_cancel_all(struct ip
 
 	ipr_reinit_ipr_cmnd_for_erp(ipr_cmd);
 
-	if (!res->tcq_active) {
+	if (!scsi_get_tag_type(scsi_cmd->device)) {
 		ipr_erp_request_sense(ipr_cmd);
 		return;
 	}
@@ -3546,7 +3542,7 @@ static void ipr_dump_ioasa(struct ipr_io
 	u16 data_len;
 	u32 ioasc;
 	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
-	u32 *ioasa_data = (u32 *)ioasa;
+	__be32 *ioasa_data = (__be32 *)ioasa;
 	int error_index;
 
 	ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
@@ -3947,11 +3943,12 @@ static struct scsi_host_template driver_
 	.slave_configure = ipr_slave_configure,
 	.slave_destroy = ipr_slave_destroy,
 	.change_queue_depth = ipr_change_queue_depth,
+	.change_queue_type = ipr_change_queue_type,
 	.bios_param = ipr_biosparam,
 	.can_queue = IPR_MAX_COMMANDS,
 	.this_id = -1,
 	.sg_tablesize = IPR_MAX_SGLIST,
-	.max_sectors = IPR_MAX_SECTORS,
+	.max_sectors = IPR_IOA_MAX_SECTORS,
 	.cmd_per_lun = IPR_MAX_CMD_PER_LUN,
 	.use_clustering = ENABLE_CLUSTERING,
 	.shost_attrs = ipr_ioa_attrs,
@@ -4058,10 +4055,10 @@ static int ipr_ioa_reset_done(struct ipr
 	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
 		if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) {
 			ipr_trace;
-			schedule_work(&ioa_cfg->work_q);
 			break;
 		}
 	}
+	schedule_work(&ioa_cfg->work_q);
 
 	list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) {
 		list_del(&hostrcb->queue);
@@ -4317,7 +4314,7 @@ static void ipr_modify_ioafp_mode_page_2
  * 	none
  **/
 static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd,
-				  u32 res_handle, u8 parm, u32 dma_addr,
+				  __be32 res_handle, u8 parm, u32 dma_addr,
 				  u8 xfer_len)
 {
 	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
@@ -4392,7 +4389,7 @@ static int ipr_ioafp_mode_select_page28(
  * 	none
  **/
 static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd,
-				 u32 res_handle,
+				 __be32 res_handle,
 				 u8 parm, u32 dma_addr, u8 xfer_len)
 {
 	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
@@ -4500,6 +4497,7 @@ static int ipr_init_res_table(struct ipr
 	list_for_each_entry_safe(res, temp, &old_res, queue) {
 		if (res->sdev) {
 			res->del_from_ml = 1;
+			res->sdev->hostdata = NULL;
 			list_move_tail(&res->queue, &ioa_cfg->used_res_q);
 		} else {
 			list_move_tail(&res->queue, &ioa_cfg->free_res_q);
@@ -4803,8 +4801,8 @@ static int ipr_reset_enable_ioa(struct i
 	dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
 
 	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
-	ipr_cmd->timer.expires = jiffies + IPR_OPERATIONAL_TIMEOUT;
-	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_timeout;
+	ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ);
+	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
 	ipr_cmd->done = ipr_reset_ioa_job;
 	add_timer(&ipr_cmd->timer);
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
@@ -4876,8 +4874,8 @@ static void ipr_get_unit_check_buffer(st
 	}
 
 	memset(&sdt, 0, sizeof(struct ipr_uc_sdt));
-	rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (u32 *) &sdt,
-					(sizeof(struct ipr_uc_sdt)) / sizeof(u32));
+	rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt,
+					(sizeof(struct ipr_uc_sdt)) / sizeof(__be32));
 
 	if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) ||
 	    !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) {
@@ -4896,8 +4894,8 @@ static void ipr_get_unit_check_buffer(st
 
 	rc = ipr_get_ldump_data_section(ioa_cfg,
 					be32_to_cpu(sdt.entry[0].bar_str_offset),
-					(u32 *)&hostrcb->hcam,
-					min(length, (int)sizeof(hostrcb->hcam)) / sizeof(u32));
+					(__be32 *)&hostrcb->hcam,
+					min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
 
 	if (!rc)
 		ipr_handle_log_data(ioa_cfg, hostrcb);
@@ -5279,7 +5277,7 @@ static void ipr_initiate_ioa_reset(struc
 	if (ioa_cfg->in_reset_reload && ioa_cfg->sdt_state == GET_DUMP)
 		ioa_cfg->sdt_state = ABORT_DUMP;
 
-	if (ioa_cfg->reset_retries++ > IPR_NUM_RESET_RELOAD_RETRIES) {
+	if (ioa_cfg->reset_retries++ >= IPR_NUM_RESET_RELOAD_RETRIES) {
 		dev_err(&ioa_cfg->pdev->dev,
 			"IOA taken offline - error recovery failed\n");
 
@@ -5664,6 +5662,28 @@ static void __devinit ipr_init_ioa_cfg(s
 }
 
 /**
+ * ipr_get_chip_cfg - Find adapter chip configuration
+ * @dev_id:		PCI device id struct
+ *
+ * Return value:
+ * 	ptr to chip config on success / NULL on failure
+ **/
+static const struct ipr_chip_cfg_t * __devinit
+ipr_get_chip_cfg(const struct pci_device_id *dev_id)
+{
+	int i;
+
+	if (dev_id->driver_data)
+		return (const struct ipr_chip_cfg_t *)dev_id->driver_data;
+
+	for (i = 0; i < ARRAY_SIZE(ipr_chip); i++)
+		if (ipr_chip[i].vendor == dev_id->vendor &&
+		    ipr_chip[i].device == dev_id->device)
+			return ipr_chip[i].cfg;
+	return NULL;
+}
+
+/**
  * ipr_probe_ioa - Allocates memory and does first stage of initialization
  * @pdev:		PCI device struct
  * @dev_id:		PCI device id struct
@@ -5700,7 +5720,13 @@ static int __devinit ipr_probe_ioa(struc
 	ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
 	memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
 
-	ioa_cfg->chip_cfg = (const struct ipr_chip_cfg_t *)dev_id->driver_data;
+	ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
+
+	if (!ioa_cfg->chip_cfg) {
+		dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n",
+			dev_id->vendor, dev_id->device);
+		goto out_scsi_host_put;
+	}
 
 	ipr_regs_pci = pci_resource_start(pdev, 0);
 
@@ -5989,22 +6015,28 @@ static struct pci_device_id ipr_pci_tabl
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702,
 		0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E,
-		0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
 		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_570F,
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E,
 		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
 	{ }
 };
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -36,8 +36,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.0.12"
-#define IPR_DRIVER_DATE "(December 14, 2004)"
+#define IPR_DRIVER_VERSION "2.0.13"
+#define IPR_DRIVER_DATE "(February 21, 2005)"
 
 /*
  * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing
@@ -70,10 +70,12 @@
 #define IPR_SUBS_DEV_ID_2780	0x0264
 #define IPR_SUBS_DEV_ID_5702	0x0266
 #define IPR_SUBS_DEV_ID_5703	0x0278
-#define IPR_SUBS_DEV_ID_572E  0x02D3
+#define IPR_SUBS_DEV_ID_572E  0x028D
+#define IPR_SUBS_DEV_ID_573E  0x02D3
 #define IPR_SUBS_DEV_ID_573D  0x02D4
-#define IPR_SUBS_DEV_ID_570F	0x02BD
+#define IPR_SUBS_DEV_ID_571A	0x02C0
 #define IPR_SUBS_DEV_ID_571B	0x02BE
+#define IPR_SUBS_DEV_ID_571E  0x02BF
 
 #define IPR_NAME				"ipr"
 
@@ -128,7 +130,8 @@
 #define IPR_MAX_PHYSICAL_DEVS				192
 
 #define IPR_MAX_SGLIST					64
-#define IPR_MAX_SECTORS					512
+#define IPR_IOA_MAX_SECTORS				32767
+#define IPR_VSET_MAX_SECTORS				512
 #define IPR_MAX_CDB_LEN					16
 
 #define IPR_DEFAULT_BUS_WIDTH				16
@@ -162,17 +165,17 @@
 /*
  * Timeouts
  */
-#define IPR_SHUTDOWN_TIMEOUT			(10 * 60 * HZ)
-#define IPR_VSET_RW_TIMEOUT			(2 * 60 * HZ)
+#define IPR_SHUTDOWN_TIMEOUT			(ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
+#define IPR_VSET_RW_TIMEOUT			(ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
 #define IPR_ABBREV_SHUTDOWN_TIMEOUT		(10 * HZ)
-#define IPR_DEVICE_RESET_TIMEOUT		(30 * HZ)
-#define IPR_CANCEL_ALL_TIMEOUT		(30 * HZ)
-#define IPR_ABORT_TASK_TIMEOUT		(30 * HZ)
-#define IPR_INTERNAL_TIMEOUT			(30 * HZ)
+#define IPR_DEVICE_RESET_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_CANCEL_ALL_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_ABORT_TASK_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_INTERNAL_TIMEOUT			(ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_WRITE_BUFFER_TIMEOUT		(10 * 60 * HZ)
 #define IPR_SET_SUP_DEVICE_TIMEOUT		(2 * 60 * HZ)
 #define IPR_REQUEST_SENSE_TIMEOUT		(10 * HZ)
-#define IPR_OPERATIONAL_TIMEOUT		(5 * 60 * HZ)
+#define IPR_OPERATIONAL_TIMEOUT		(5 * 60)
 #define IPR_WAIT_FOR_RESET_TIMEOUT		(2 * HZ)
 #define IPR_CHECK_FOR_RESET_TIMEOUT		(HZ / 10)
 #define IPR_WAIT_FOR_BIST_TIMEOUT		(2 * HZ)
@@ -302,8 +305,8 @@ struct ipr_config_table_entry {
 #define IPR_SUBTYPE_VOLUME_SET		2
 
 	struct ipr_res_addr res_addr;
-	u32 res_handle;
-	u32 reserved4[2];
+	__be32 res_handle;
+	__be32 reserved4[2];
 	struct ipr_std_inq_data std_inq_data;
 }__attribute__ ((packed, aligned (4)));
 
@@ -311,7 +314,7 @@ struct ipr_config_table_hdr {
 	u8 num_entries;
 	u8 flags;
 #define IPR_UCODE_DOWNLOAD_REQ	0x10
-	u16 reserved;
+	__be16 reserved;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_config_table {
@@ -325,7 +328,7 @@ struct ipr_hostrcb_cfg_ch_not {
 }__attribute__((packed, aligned (4)));
 
 struct ipr_supported_device {
-	u16 data_length;
+	__be16 data_length;
 	u8 reserved;
 	u8 num_records;
 	struct ipr_std_inq_vpids vpids;
@@ -334,7 +337,7 @@ struct ipr_supported_device {
 
 /* Command packet structure */
 struct ipr_cmd_pkt {
-	u16 reserved;		/* Reserved by IOA */
+	__be16 reserved;		/* Reserved by IOA */
 	u8 request_type;
 #define IPR_RQTYPE_SCSICDB		0x00
 #define IPR_RQTYPE_IOACMD		0x01
@@ -359,38 +362,38 @@ struct ipr_cmd_pkt {
 #define IPR_FLAGS_LO_ACA_TASK			0x08
 
 	u8 cdb[16];
-	u16 timeout;
+	__be16 timeout;
 }__attribute__ ((packed, aligned(4)));
 
 /* IOA Request Control Block    128 bytes  */
 struct ipr_ioarcb {
-	u32 ioarcb_host_pci_addr;
-	u32 reserved;
-	u32 res_handle;
-	u32 host_response_handle;
-	u32 reserved1;
-	u32 reserved2;
-	u32 reserved3;
-
-	u32 write_data_transfer_length;
-	u32 read_data_transfer_length;
-	u32 write_ioadl_addr;
-	u32 write_ioadl_len;
-	u32 read_ioadl_addr;
-	u32 read_ioadl_len;
-
-	u32 ioasa_host_pci_addr;
-	u16 ioasa_len;
-	u16 reserved4;
+	__be32 ioarcb_host_pci_addr;
+	__be32 reserved;
+	__be32 res_handle;
+	__be32 host_response_handle;
+	__be32 reserved1;
+	__be32 reserved2;
+	__be32 reserved3;
+
+	__be32 write_data_transfer_length;
+	__be32 read_data_transfer_length;
+	__be32 write_ioadl_addr;
+	__be32 write_ioadl_len;
+	__be32 read_ioadl_addr;
+	__be32 read_ioadl_len;
+
+	__be32 ioasa_host_pci_addr;
+	__be16 ioasa_len;
+	__be16 reserved4;
 
 	struct ipr_cmd_pkt cmd_pkt;
 
-	u32 add_cmd_parms_len;
-	u32 add_cmd_parms[10];
+	__be32 add_cmd_parms_len;
+	__be32 add_cmd_parms[10];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioadl_desc {
-	u32 flags_and_data_len;
+	__be32 flags_and_data_len;
 #define IPR_IOADL_FLAGS_MASK		0xff000000
 #define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
 #define IPR_IOADL_DATA_LEN_MASK		0x00ffffff
@@ -401,55 +404,55 @@ struct ipr_ioadl_desc {
 #define IPR_IOADL_FLAGS_WRITE_LAST	0x69000000
 #define IPR_IOADL_FLAGS_LAST		0x01000000
 
-	u32 address;
+	__be32 address;
 }__attribute__((packed, aligned (8)));
 
 struct ipr_ioasa_vset {
-	u32 failing_lba_hi;
-	u32 failing_lba_lo;
-	u32 ioa_data[22];
+	__be32 failing_lba_hi;
+	__be32 failing_lba_lo;
+	__be32 ioa_data[22];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_af_dasd {
-	u32 failing_lba;
+	__be32 failing_lba;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_gpdd {
 	u8 end_state;
 	u8 bus_phase;
-	u16 reserved;
-	u32 ioa_data[23];
+	__be16 reserved;
+	__be32 ioa_data[23];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_raw {
-	u32 ioa_data[24];
+	__be32 ioa_data[24];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa {
-	u32 ioasc;
+	__be32 ioasc;
 #define IPR_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24)
 #define IPR_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16)
 #define IPR_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8)
 #define IPR_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff)
 
-	u16 ret_stat_len;	/* Length of the returned IOASA */
+	__be16 ret_stat_len;	/* Length of the returned IOASA */
 
-	u16 avail_stat_len;	/* Total Length of status available. */
+	__be16 avail_stat_len;	/* Total Length of status available. */
 
-	u32 residual_data_len;	/* number of bytes in the host data */
+	__be32 residual_data_len;	/* number of bytes in the host data */
 	/* buffers that were not used by the IOARCB command. */
 
-	u32 ilid;
+	__be32 ilid;
 #define IPR_NO_ILID			0
 #define IPR_DRIVER_ILID		0xffffffff
 
-	u32 fd_ioasc;
+	__be32 fd_ioasc;
 
-	u32 fd_phys_locator;
+	__be32 fd_phys_locator;
 
-	u32 fd_res_handle;
+	__be32 fd_res_handle;
 
-	u32 ioasc_specific;	/* status code specific field */
+	__be32 ioasc_specific;	/* status code specific field */
 #define IPR_IOASC_SPECIFIC_MASK		0x00ffffff
 #define IPR_FIELD_POINTER_VALID		(0x80000000 >> 8)
 #define IPR_FIELD_POINTER_MASK		0x0000ffff
@@ -497,11 +500,11 @@ struct ipr_dev_bus_entry {
 	u8 extended_reset_delay;
 #define IPR_EXTENDED_RESET_DELAY	7
 
-	u32 max_xfer_rate;
+	__be32 max_xfer_rate;
 
 	u8 spinup_delay;
 	u8 reserved3;
-	u16 reserved4;
+	__be16 reserved4;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_mode_page28 {
@@ -543,7 +546,7 @@ struct ipr_hostrcb_device_data_entry {
 	u8 ioa_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
 	struct ipr_std_inq_vpids cfc_last_with_dev_vpids;
 	u8 cfc_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
-	u32 ioa_data[5];
+	__be32 ioa_data[5];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_array_data_entry {
@@ -554,14 +557,14 @@ struct ipr_hostrcb_array_data_entry {
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_ff_error {
-	u32 ioa_data[246];
+	__be32 ioa_data[246];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_01_error {
-	u32 seek_counter;
-	u32 read_counter;
+	__be32 seek_counter;
+	__be32 read_counter;
 	u8 sense_data[32];
-	u32 ioa_data[236];
+	__be32 ioa_data[236];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_02_error {
@@ -573,7 +576,7 @@ struct ipr_hostrcb_type_02_error {
 	u8 ioa_last_attached_to_cfc_sn[IPR_SERIAL_NUM_LEN];
 	struct ipr_std_inq_vpids cfc_last_attached_to_ioa_vpids;
 	u8 cfc_last_attached_to_ioa_sn[IPR_SERIAL_NUM_LEN];
-	u32 ioa_data[3];
+	__be32 ioa_data[3];
 	u8 reserved[844];
 }__attribute__((packed, aligned (4)));
 
@@ -582,8 +585,8 @@ struct ipr_hostrcb_type_03_error {
 	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
 	struct ipr_std_inq_vpids cfc_vpids;
 	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
-	u32 errors_detected;
-	u32 errors_logged;
+	__be32 errors_detected;
+	__be32 errors_logged;
 	u8 ioa_data[12];
 	struct ipr_hostrcb_device_data_entry dev_entry[3];
 	u8 reserved[444];
@@ -596,11 +599,11 @@ struct ipr_hostrcb_type_04_error {
 	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
 	u8 ioa_data[12];
 	struct ipr_hostrcb_array_data_entry array_member[10];
-	u32 exposed_mode_adn;
-	u32 array_id;
+	__be32 exposed_mode_adn;
+	__be32 array_id;
 	struct ipr_std_inq_vpids incomp_dev_vpids;
 	u8 incomp_dev_sn[IPR_SERIAL_NUM_LEN];
-	u32 ioa_data2;
+	__be32 ioa_data2;
 	struct ipr_hostrcb_array_data_entry array_member2[8];
 	struct ipr_res_addr last_func_vset_res_addr;
 	u8 vset_serial_num[IPR_SERIAL_NUM_LEN];
@@ -609,10 +612,10 @@ struct ipr_hostrcb_type_04_error {
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_error {
-	u32 failing_dev_ioasc;
+	__be32 failing_dev_ioasc;
 	struct ipr_res_addr failing_dev_res_addr;
-	u32 failing_dev_res_handle;
-	u32 prc;
+	__be32 failing_dev_res_handle;
+	__be32 prc;
 	union {
 		struct ipr_hostrcb_type_ff_error type_ff_error;
 		struct ipr_hostrcb_type_01_error type_01_error;
@@ -623,7 +626,7 @@ struct ipr_hostrcb_error {
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_raw {
-	u32 data[sizeof(struct ipr_hostrcb_error)/sizeof(u32)];
+	__be32 data[sizeof(struct ipr_hostrcb_error)/sizeof(__be32)];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hcam {
@@ -655,10 +658,10 @@ struct ipr_hcam {
 #define IPR_HOST_RCB_OVERLAY_ID_DEFAULT			0xFF
 
 	u8 reserved1[3];
-	u32 ilid;
-	u32 time_since_last_ioa_reset;
-	u32 reserved2;
-	u32 length;
+	__be32 ilid;
+	__be32 time_since_last_ioa_reset;
+	__be32 reserved2;
+	__be32 length;
 
 	union {
 		struct ipr_hostrcb_error error;
@@ -675,8 +678,8 @@ struct ipr_hostrcb {
 
 /* IPR smart dump table structures */
 struct ipr_sdt_entry {
-	u32 bar_str_offset;
-	u32 end_offset;
+	__be32 bar_str_offset;
+	__be32 end_offset;
 	u8 entry_byte;
 	u8 reserved[3];
 
@@ -685,14 +688,14 @@ struct ipr_sdt_entry {
 #define IPR_SDT_VALID_ENTRY	0x20
 
 	u8 resv;
-	u16 priority;
+	__be16 priority;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_sdt_header {
-	u32 state;
-	u32 num_entries;
-	u32 num_entries_used;
-	u32 dump_size;
+	__be32 state;
+	__be32 num_entries;
+	__be32 num_entries_used;
+	__be32 dump_size;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_sdt {
@@ -723,9 +726,7 @@ struct ipr_resource_entry {
 	u8 add_to_ml:1;
 	u8 del_from_ml:1;
 	u8 resetting_device:1;
-	u8 tcq_active:1;
 
-	int qdepth;
 	struct scsi_device *sdev;
 	struct list_head queue;
 };
@@ -779,6 +780,12 @@ struct ipr_chip_cfg_t {
 	struct ipr_interrupt_offsets regs;
 };
 
+struct ipr_chip_t {
+	u16 vendor;
+	u16 device;
+	const struct ipr_chip_cfg_t *cfg;
+};
+
 enum ipr_shutdown_type {
 	IPR_SHUTDOWN_NORMAL = 0x00,
 	IPR_SHUTDOWN_PREPARE_FOR_NORMAL = 0x40,
@@ -795,7 +802,7 @@ struct ipr_trace_entry {
 #define IPR_TRACE_FINISH		0xff
 	u16 cmd_index;
 
-	u32 res_handle;
+	__be32 res_handle;
 	union {
 		u32 ioasc;
 		u32 add_data;
@@ -880,15 +887,15 @@ struct ipr_ioa_cfg {
 	struct list_head hostrcb_free_q;
 	struct list_head hostrcb_pending_q;
 
-	u32 *host_rrq;
+	__be32 *host_rrq;
 	dma_addr_t host_rrq_dma;
 #define IPR_HRRQ_REQ_RESP_HANDLE_MASK	0xfffffffc
 #define IPR_HRRQ_RESP_BIT_SET			0x00000002
 #define IPR_HRRQ_TOGGLE_BIT				0x00000001
 #define IPR_HRRQ_REQ_RESP_HANDLE_SHIFT	2
-	volatile u32 *hrrq_start;
-	volatile u32 *hrrq_end;
-	volatile u32 *hrrq_curr;
+	volatile __be32 *hrrq_start;
+	volatile __be32 *hrrq_end;
+	volatile __be32 *hrrq_curr;
 	volatile u32 toggle_bit;
 
 	struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
@@ -1033,7 +1040,7 @@ struct ipr_driver_dump {
 struct ipr_ioa_dump {
 	struct ipr_dump_entry_header hdr;
 	struct ipr_sdt sdt;
-	u32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES];
+	__be32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES];
 	u32 reserved;
 	u32 next_page_index;
 	u32 page_offset;
@@ -1057,19 +1064,19 @@ struct ipr_error_table_t {
 };
 
 struct ipr_software_inq_lid_info {
-	u32 load_id;
-	u32 timestamp[3];
+	__be32 load_id;
+	__be32 timestamp[3];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ucode_image_header {
-	u32 header_length;
-	u32 lid_table_offset;
+	__be32 header_length;
+	__be32 lid_table_offset;
 	u8 major_release;
 	u8 card_type;
 	u8 minor_release[2];
 	u8 reserved[20];
 	char eyecatcher[16];
-	u32 num_lids;
+	__be32 num_lids;
 	struct ipr_software_inq_lid_info lid[1];
 }__attribute__((packed, aligned (4)));
 
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -231,9 +231,9 @@ module_param(ips, charp, 0);
 #endif
 
 #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
-                         SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \
+                         DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
                          PCI_DMA_BIDIRECTIONAL : \
-                         scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
+                         scb->scsi_cmd->sc_data_direction)
 
 #ifdef IPS_DEBUG
 #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
@@ -246,6 +246,117 @@ module_param(ips, charp, 0);
 #endif
 
 /*
+ * Function prototypes
+ */
+static int ips_detect(Scsi_Host_Template *);
+static int ips_release(struct Scsi_Host *);
+static int ips_eh_abort(Scsi_Cmnd *);
+static int ips_eh_reset(Scsi_Cmnd *);
+static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static const char *ips_info(struct Scsi_Host *);
+static irqreturn_t 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_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 *);
+static int ips_inquiry(ips_ha_t *, ips_scb_t *);
+static int ips_rdcap(ips_ha_t *, ips_scb_t *);
+static int ips_msense(ips_ha_t *, ips_scb_t *);
+static int ips_reqsen(ips_ha_t *, ips_scb_t *);
+static int ips_deallocatescbs(ips_ha_t *, int);
+static int ips_allocatescbs(ips_ha_t *);
+static int ips_reset_copperhead(ips_ha_t *);
+static int ips_reset_copperhead_memio(ips_ha_t *);
+static int ips_reset_morpheus(ips_ha_t *);
+static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
+static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
+static int ips_isintr_copperhead(ips_ha_t *);
+static int ips_isintr_copperhead_memio(ips_ha_t *);
+static int ips_isintr_morpheus(ips_ha_t *);
+static int ips_wait(ips_ha_t *, int, int);
+static int ips_write_driver_status(ips_ha_t *, int);
+static int ips_read_adapter_status(ips_ha_t *, int);
+static int ips_read_subsystem_parameters(ips_ha_t *, int);
+static int ips_read_config(ips_ha_t *, int);
+static int ips_clear_adapter(ips_ha_t *, int);
+static int ips_readwrite_page5(ips_ha_t *, int, int);
+static int ips_init_copperhead(ips_ha_t *);
+static int ips_init_copperhead_memio(ips_ha_t *);
+static int ips_init_morpheus(ips_ha_t *);
+static int ips_isinit_copperhead(ips_ha_t *);
+static int ips_isinit_copperhead_memio(ips_ha_t *);
+static int ips_isinit_morpheus(ips_ha_t *);
+static int ips_erase_bios(ips_ha_t *);
+static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
+static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
+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 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_get_bios_version(ips_ha_t *, int);
+static void ips_identify_controller(ips_ha_t *);
+static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
+static void ips_enable_int_copperhead(ips_ha_t *);
+static void ips_enable_int_copperhead_memio(ips_ha_t *);
+static void ips_enable_int_morpheus(ips_ha_t *);
+static int ips_intr_copperhead(ips_ha_t *);
+static int ips_intr_morpheus(ips_ha_t *);
+static void ips_next(ips_ha_t *, int);
+static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
+static void ipsintr_done(ips_ha_t *, struct ips_scb *);
+static void ips_done(ips_ha_t *, ips_scb_t *);
+static void ips_free(ips_ha_t *);
+static void ips_init_scb(ips_ha_t *, ips_scb_t *);
+static void ips_freescb(ips_ha_t *, ips_scb_t *);
+static void ips_setup_funclist(ips_ha_t *);
+static void ips_statinit(ips_ha_t *);
+static void ips_statinit_memio(ips_ha_t *);
+static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
+static void ips_ffdc_reset(ips_ha_t *, int);
+static void ips_ffdc_time(ips_ha_t *);
+static uint32_t ips_statupd_copperhead(ips_ha_t *);
+static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
+static uint32_t ips_statupd_morpheus(ips_ha_t *);
+static ips_scb_t *ips_getscb(ips_ha_t *);
+static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
+static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
+static void ips_putq_copp_tail(ips_copp_queue_t *,
+				      ips_copp_wait_item_t *);
+static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
+static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
+static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
+static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
+						     ips_copp_wait_item_t *);
+static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
+
+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 void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
+static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
+			       unsigned int count);
+static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
+
+static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+static int ips_host_info(ips_ha_t *, char *, off_t, int);
+static void copy_mem_info(IPS_INFOSTR *, char *, int);
+static int copy_info(IPS_INFOSTR *, char *, ...);
+static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
+static void ips_version_check(ips_ha_t * ha, int intr);
+static int ips_abort_init(ips_ha_t * ha, int index);
+static int ips_init_phase2(int index);
+
+static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
+static int ips_register_scsi(int index);
+
+/*
  * global variables
  */
 static const char ips_name[] = "ips";
@@ -293,7 +404,7 @@ static Scsi_Host_Template ips_driver_tem
 #endif
 };
 
-IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
+static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
 
 
 /* This table describes all ServeRAID Adapters */
@@ -311,7 +422,7 @@ static char ips_hot_plug_name[] = "ips";
 static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
 static void __devexit ips_remove_device(struct pci_dev *pci_dev);
    
-struct pci_driver ips_pci_driver = {
+static struct pci_driver ips_pci_driver = {
 	.name		= ips_hot_plug_name,
 	.id_table	= ips_pci_table,
 	.probe		= ips_insert_device,
@@ -408,119 +519,6 @@ static char ips_command_direction[] = {
 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
 };
 
-/*
- * Function prototypes
- */
-int ips_detect(Scsi_Host_Template *);
-int ips_release(struct Scsi_Host *);
-int ips_eh_abort(Scsi_Cmnd *);
-int ips_eh_reset(Scsi_Cmnd *);
-int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-const char *ips_info(struct Scsi_Host *);
-irqreturn_t 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_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 *);
-static int ips_inquiry(ips_ha_t *, ips_scb_t *);
-static int ips_rdcap(ips_ha_t *, ips_scb_t *);
-static int ips_msense(ips_ha_t *, ips_scb_t *);
-static int ips_reqsen(ips_ha_t *, ips_scb_t *);
-static int ips_deallocatescbs(ips_ha_t *, int);
-static int ips_allocatescbs(ips_ha_t *);
-static int ips_reset_copperhead(ips_ha_t *);
-static int ips_reset_copperhead_memio(ips_ha_t *);
-static int ips_reset_morpheus(ips_ha_t *);
-static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
-static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
-static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
-static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
-static int ips_isintr_copperhead(ips_ha_t *);
-static int ips_isintr_copperhead_memio(ips_ha_t *);
-static int ips_isintr_morpheus(ips_ha_t *);
-static int ips_wait(ips_ha_t *, int, int);
-static int ips_write_driver_status(ips_ha_t *, int);
-static int ips_read_adapter_status(ips_ha_t *, int);
-static int ips_read_subsystem_parameters(ips_ha_t *, int);
-static int ips_read_config(ips_ha_t *, int);
-static int ips_clear_adapter(ips_ha_t *, int);
-static int ips_readwrite_page5(ips_ha_t *, int, int);
-static int ips_init_copperhead(ips_ha_t *);
-static int ips_init_copperhead_memio(ips_ha_t *);
-static int ips_init_morpheus(ips_ha_t *);
-static int ips_isinit_copperhead(ips_ha_t *);
-static int ips_isinit_copperhead_memio(ips_ha_t *);
-static int ips_isinit_morpheus(ips_ha_t *);
-static int ips_erase_bios(ips_ha_t *);
-static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
-static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
-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 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_get_bios_version(ips_ha_t *, int);
-static void ips_identify_controller(ips_ha_t *);
-static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
-static void ips_enable_int_copperhead(ips_ha_t *);
-static void ips_enable_int_copperhead_memio(ips_ha_t *);
-static void ips_enable_int_morpheus(ips_ha_t *);
-static int ips_intr_copperhead(ips_ha_t *);
-static int ips_intr_morpheus(ips_ha_t *);
-static void ips_next(ips_ha_t *, int);
-static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
-static void ipsintr_done(ips_ha_t *, struct ips_scb *);
-static void ips_done(ips_ha_t *, ips_scb_t *);
-static void ips_free(ips_ha_t *);
-static void ips_init_scb(ips_ha_t *, ips_scb_t *);
-static void ips_freescb(ips_ha_t *, ips_scb_t *);
-static void ips_setup_funclist(ips_ha_t *);
-static void ips_statinit(ips_ha_t *);
-static void ips_statinit_memio(ips_ha_t *);
-static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
-static void ips_ffdc_reset(ips_ha_t *, int);
-static void ips_ffdc_time(ips_ha_t *);
-static uint32_t ips_statupd_copperhead(ips_ha_t *);
-static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
-static uint32_t ips_statupd_morpheus(ips_ha_t *);
-static ips_scb_t *ips_getscb(ips_ha_t *);
-static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
-static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
-static void ips_putq_copp_tail(ips_copp_queue_t *,
-				      ips_copp_wait_item_t *);
-static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
-static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
-static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
-static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
-static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
-						     ips_copp_wait_item_t *);
-static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
-
-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 void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
-static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
-			       unsigned int count);
-static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
-
-int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
-static int ips_host_info(ips_ha_t *, char *, off_t, int);
-static void copy_mem_info(IPS_INFOSTR *, char *, int);
-static int copy_info(IPS_INFOSTR *, char *, ...);
-static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
-static void ips_version_check(ips_ha_t * ha, int intr);
-static int ips_abort_init(ips_ha_t * ha, int index);
-static int ips_init_phase2(int index);
-
-static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
-static int ips_register_scsi(int index);
-/*--------------------------------------------------------------------------*/
-/* Exported Functions                                                       */
-/*--------------------------------------------------------------------------*/
 
 /****************************************************************************/
 /*                                                                          */
@@ -589,7 +587,7 @@ __setup("ips=", ips_setup);
 /* NOTE: this routine is called under the io_request_lock spinlock          */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_detect(Scsi_Host_Template * SHT)
 {
 	int i;
@@ -678,7 +676,7 @@ ips_setup_funclist(ips_ha_t * ha)
 /*   Remove a driver                                                        */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_release(struct Scsi_Host *sh)
 {
 	ips_scb_t *scb;
@@ -835,13 +833,6 @@ ips_eh_abort(Scsi_Cmnd * SC)
 	if (!ha->active)
 		return (FAILED);
 
-	if (SC->serial_number != SC->serial_number_at_timeout) {
-		/* HMM, looks like a bogus command */
-		DEBUG(1, "Abort called with bogus scsi command");
-
-		return (FAILED);
-	}
-
 	/* See if the command is on the copp queue */
 	item = ha->copp_waitlist.head;
 	while ((item) && (item->scsi_cmd != SC))
@@ -874,7 +865,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
 /* NOTE: this routine is called under the io_request_lock spinlock          */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_eh_reset(Scsi_Cmnd * SC)
 {
 	int ret;
@@ -1074,7 +1065,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
 /*    Linux obtains io_request_lock before calling this function            */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
 {
 	ips_ha_t *ha;
@@ -1297,7 +1288,7 @@ ips_select_queue_depth(struct Scsi_Host 
 /*   Set queue depths on devices once scan is complete                      */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_slave_configure(Scsi_Device * SDptr)
 {
 	ips_ha_t *ha;
@@ -1323,7 +1314,7 @@ ips_slave_configure(Scsi_Device * SDptr)
 /*   Wrapper for the interrupt handler                                      */
 /*                                                                          */
 /****************************************************************************/
-irqreturn_t
+static irqreturn_t
 do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	ips_ha_t *ha;
@@ -1502,7 +1493,7 @@ ips_intr_morpheus(ips_ha_t * ha)
 /*   Return info about the driver                                           */
 /*                                                                          */
 /****************************************************************************/
-const char *
+static const char *
 ips_info(struct Scsi_Host *SH)
 {
 	static char buffer[256];
@@ -1540,7 +1531,7 @@ ips_info(struct Scsi_Host *SH)
 /*   The passthru interface for the driver                                  */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
 	      int length, int func)
 {
@@ -2858,8 +2849,7 @@ ips_next(ips_ha_t * ha, int intr)
 
 			sg = SC->request_buffer;
 			scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
-						   scsi_to_pci_dma_dir(SC->
-								       sc_data_direction));
+						   SC->sc_data_direction);
 			scb->flags |= IPS_SCB_MAP_SG;
 			for (i = 0; i < scb->sg_count; i++) {
 				if (ips_fill_scb_sg_single
@@ -2874,8 +2864,7 @@ ips_next(ips_ha_t * ha, int intr)
 				    pci_map_single(ha->pcidev,
 						   SC->request_buffer,
 						   SC->request_bufflen,
-						   scsi_to_pci_dma_dir(SC->
-								       sc_data_direction));
+						   SC->sc_data_direction);
 				scb->flags |= IPS_SCB_MAP_SINGLE;
 				ips_fill_scb_sg_single(ha, scb->data_busaddr,
 						       scb, 0,
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -53,14 +53,6 @@
    #include <asm/uaccess.h>
    #include <asm/io.h>
 
-   /* Prototypes */
-   extern int ips_detect(Scsi_Host_Template *);
-   extern int ips_release(struct Scsi_Host *);
-   extern int ips_eh_abort(Scsi_Cmnd *);
-   extern int ips_eh_reset(Scsi_Cmnd *);
-   extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
-   extern const char * ips_info(struct Scsi_Host *);
-
    /*
     * Some handy macros
     */
@@ -457,10 +449,10 @@
    static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
    static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
 #else
-   int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+   static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
    static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 		sector_t capacity, int geom[]);
-   int ips_slave_configure(Scsi_Device *SDptr);
+   static int ips_slave_configure(Scsi_Device *SDptr);
 #endif
 
 /*
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -111,8 +111,8 @@ lasi700_probe(struct parisc_device *dev)
 	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
 	hostdata->dev = &dev->dev;
-	dma_set_mask(&dev->dev, 0xffffffffUL);
-	hostdata->base = base;
+	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
+	hostdata->base = ioremap(base, 0x100);
 	hostdata->differential = 0;
 
 	if (dev->id.sversion == LASI_700_SVERSION) {
@@ -127,17 +127,26 @@ lasi700_probe(struct parisc_device *dev)
 
 	NCR_700_set_mem_mapped(hostdata);
 
-	host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev,
-			      dev->irq, 7);
+	host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev);
 	if (!host)
 		goto out_kfree;
+	host->this_id = 7;
+	host->base = base;
+	host->irq = dev->irq;
+	if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) {
+		printk(KERN_ERR "lasi700: request_irq failed!\n");
+		goto out_put_host;
+	}
 
 	dev_set_drvdata(&dev->dev, host);
 	scsi_scan_host(host);
 
 	return 0;
 
+ out_put_host:
+	scsi_host_put(host);
  out_kfree:
+	iounmap(hostdata->base);
 	kfree(hostdata);
 	return -ENODEV;
 }
@@ -152,6 +161,7 @@ lasi700_driver_remove(struct parisc_devi
 	scsi_remove_host(host);
 	NCR_700_release(host);
 	free_irq(host->irq, host);
+	iounmap(hostdata->base);
 	kfree(hostdata);
 
 	return 0;
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -186,6 +186,28 @@ static void ata_tf_load_mmio(struct ata_
 	ata_wait_idle(ap);
 }
 
+
+/**
+ *	ata_tf_load - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using MMIO
+ *	or PIO as indicated by the ATA_FLAG_MMIO flag.
+ *	Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ *	Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ *	hob_lbal, hob_lbam, and hob_lbah.
+ *
+ *	This function waits for idle (!BUSY and !DRQ) after writing
+ *	registers.  If the control register has a new value, this
+ *	function also waits for idle after writing control and before
+ *	writing the remaining registers.
+ *
+ *	May be used as the tf_load() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
 void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
@@ -195,11 +217,11 @@ void ata_tf_load(struct ata_port *ap, st
 }
 
 /**
- *	ata_exec_command - issue ATA command to host controller
+ *	ata_exec_command_pio - issue ATA command to host controller
  *	@ap: port to which command is being issued
  *	@tf: ATA taskfile register set
  *
- *	Issues PIO/MMIO write to ATA command register, with proper
+ *	Issues PIO write to ATA command register, with proper
  *	synchronization with interrupt handler / other threads.
  *
  *	LOCKING:
@@ -235,6 +257,18 @@ static void ata_exec_command_mmio(struct
 	ata_pause(ap);
 }
 
+
+/**
+ *	ata_exec_command - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO/MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
 void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
@@ -305,7 +339,7 @@ void ata_tf_to_host_nolock(struct ata_po
 }
 
 /**
- *	ata_tf_read - input device's ATA taskfile shadow registers
+ *	ata_tf_read_pio - input device's ATA taskfile shadow registers
  *	@ap: Port from which input is read
  *	@tf: ATA taskfile register set for storing input
  *
@@ -368,6 +402,23 @@ static void ata_tf_read_mmio(struct ata_
 	}
 }
 
+
+/**
+ *	ata_tf_read - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf.
+ *
+ *	Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
+ *	is set, also reads the hob registers.
+ *
+ *	May be used as the tf_read() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
 void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
@@ -381,7 +432,7 @@ void ata_tf_read(struct ata_port *ap, st
  *	@ap: port where the device is
  *
  *	Reads ATA taskfile status register for currently-selected device
- *	and return it's value. This also clears pending interrupts
+ *	and return its value. This also clears pending interrupts
  *      from this device
  *
  *	LOCKING:
@@ -397,7 +448,7 @@ static u8 ata_check_status_pio(struct at
  *	@ap: port where the device is
  *
  *	Reads ATA taskfile status register for currently-selected device
- *	via MMIO and return it's value. This also clears pending interrupts
+ *	via MMIO and return its value. This also clears pending interrupts
  *      from this device
  *
  *	LOCKING:
@@ -408,6 +459,20 @@ static u8 ata_check_status_mmio(struct a
        	return readb((void __iomem *) ap->ioaddr.status_addr);
 }
 
+
+/**
+ *	ata_check_status - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *	May be used as the check_status() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
 u8 ata_check_status(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
@@ -415,6 +480,20 @@ u8 ata_check_status(struct ata_port *ap)
 	return ata_check_status_pio(ap);
 }
 
+
+/**
+ *	ata_altstatus - Read device alternate status reg
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile alternate status register for
+ *	currently-selected device and return its value.
+ *
+ *	Note: may NOT be used as the check_altstatus() entry in
+ *	ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
 u8 ata_altstatus(struct ata_port *ap)
 {
 	if (ap->ops->check_altstatus)
@@ -425,6 +504,20 @@ u8 ata_altstatus(struct ata_port *ap)
 	return inb(ap->ioaddr.altstatus_addr);
 }
 
+
+/**
+ *	ata_chk_err - Read device error reg
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile error register for
+ *	currently-selected device and return its value.
+ *
+ *	Note: may NOT be used as the check_err() entry in
+ *	ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
 u8 ata_chk_err(struct ata_port *ap)
 {
 	if (ap->ops->check_err)
@@ -873,10 +966,24 @@ void ata_dev_id_string(u16 *id, unsigned
 	}
 }
 
+
+/**
+ *	ata_noop_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *
+ *	This function performs no actual function.
+ *
+ *	May be used as the dev_select() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	caller.
+ */
 void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
 {
 }
 
+
 /**
  *	ata_std_dev_select - Select device 0/1 on ATA bus
  *	@ap: ATA channel to manipulate
@@ -884,7 +991,9 @@ void ata_noop_dev_select (struct ata_por
  *
  *	Use the method defined in the ATA specification to
  *	make either device 0, or device 1, active on the
- *	ATA channel.
+ *	ATA channel.  Works with both PIO and MMIO.
+ *
+ *	May be used as the dev_select() entry in ata_port_operations.
  *
  *	LOCKING:
  *	caller.
@@ -1190,7 +1299,12 @@ err_out:
  *	ata_bus_probe - Reset and probe ATA bus
  *	@ap: Bus to probe
  *
+ *	Master ATA bus probing function.  Initiates a hardware-dependent
+ *	bus reset, then attempts to identify any devices found on
+ *	the bus.
+ *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  *	RETURNS:
  *	Zero on success, non-zero on error.
@@ -1229,10 +1343,14 @@ err_out:
 }
 
 /**
- *	ata_port_probe -
- *	@ap:
+ *	ata_port_probe - Mark port as enabled
+ *	@ap: Port for which we indicate enablement
  *
- *	LOCKING:
+ *	Modify @ap data structure such that the system
+ *	thinks that the entire port is enabled.
+ *
+ *	LOCKING: host_set lock, or some other form of
+ *	serialization.
  */
 
 void ata_port_probe(struct ata_port *ap)
@@ -1241,10 +1359,15 @@ void ata_port_probe(struct ata_port *ap)
 }
 
 /**
- *	__sata_phy_reset -
- *	@ap:
+ *	__sata_phy_reset - Wake/reset a low-level SATA PHY
+ *	@ap: SATA port associated with target SATA PHY.
+ *
+ *	This function issues commands to standard SATA Sxxx
+ *	PHY registers, to wake up the phy (and device), and
+ *	clear any reset condition.
  *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  */
 void __sata_phy_reset(struct ata_port *ap)
@@ -1253,11 +1376,11 @@ void __sata_phy_reset(struct ata_port *a
 	unsigned long timeout = jiffies + (HZ * 5);
 
 	if (ap->flags & ATA_FLAG_SATA_RESET) {
-		scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */
-		scr_read(ap, SCR_STATUS);	/* dummy read; flush */
+		/* issue phy wake/reset */
+		scr_write_flush(ap, SCR_CONTROL, 0x301);
 		udelay(400);			/* FIXME: a guess */
 	}
-	scr_write(ap, SCR_CONTROL, 0x300);	/* issue phy wake/clear reset */
+	scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
 
 	/* wait for phy to become ready, if necessary */
 	do {
@@ -1289,10 +1412,14 @@ void __sata_phy_reset(struct ata_port *a
 }
 
 /**
- *	__sata_phy_reset -
- *	@ap:
+ *	sata_phy_reset - Reset SATA bus.
+ *	@ap: SATA port associated with target SATA PHY.
+ *
+ *	This function resets the SATA bus, and then probes
+ *	the bus for devices.
  *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  */
 void sata_phy_reset(struct ata_port *ap)
@@ -1304,10 +1431,16 @@ void sata_phy_reset(struct ata_port *ap)
 }
 
 /**
- *	ata_port_disable -
- *	@ap:
+ *	ata_port_disable - Disable port.
+ *	@ap: Port to be disabled.
  *
- *	LOCKING:
+ *	Modify @ap data structure such that the system
+ *	thinks that the entire port is disabled, and should
+ *	never attempt to probe or communicate with devices
+ *	on this port.
+ *
+ *	LOCKING: host_set lock, or some other form of
+ *	serialization.
  */
 
 void ata_port_disable(struct ata_port *ap)
@@ -1416,7 +1549,10 @@ static void ata_host_set_dma(struct ata_
  *	ata_set_mode - Program timings and issue SET FEATURES - XFER
  *	@ap: port on which timings will be programmed
  *
+ *	Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
+ *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  */
 static void ata_set_mode(struct ata_port *ap)
@@ -1467,7 +1603,10 @@ err_out:
  *	@tmout_pat: impatience timeout
  *	@tmout: overall timeout
  *
- *	LOCKING:
+ *	Sleep until ATA Status register bit BSY clears,
+ *	or a timeout occurs.
+ *
+ *	LOCKING: None.
  *
  */
 
@@ -1553,10 +1692,14 @@ static void ata_bus_post_reset(struct at
 }
 
 /**
- *	ata_bus_edd -
- *	@ap:
+ *	ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
+ *	@ap: Port to reset and probe
+ *
+ *	Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
+ *	probe the bus.  Not often used these days.
  *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  */
 
@@ -1633,8 +1776,8 @@ static unsigned int ata_bus_softreset(st
  *	the device is ATA or ATAPI.
  *
  *	LOCKING:
- *	Inherited from caller.  Some functions called by this function
- *	obtain the host_set lock.
+ *	PCI/etc. bus probe sem.
+ *	Obtains host_set lock.
  *
  *	SIDE EFFECTS:
  *	Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
@@ -1876,7 +2019,11 @@ static int fgb(u32 bitmap)
  *	@xfer_mode_out: (output) SET FEATURES - XFER MODE code
  *	@xfer_shift_out: (output) bit shift that selects this mode
  *
+ *	Based on host and device capabilities, determine the
+ *	maximum transfer mode that is amenable to all.
+ *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  *	RETURNS:
  *	Zero on success, negative on error.
@@ -1909,7 +2056,11 @@ static int ata_choose_xfer_mode(struct a
  *	@ap: Port associated with device @dev
  *	@dev: Device to which command will be sent
  *
+ *	Issue SET FEATURES - XFER MODE command to device @dev
+ *	on port @ap.
+ *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  */
 
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
@@ -1947,10 +2098,13 @@ static void ata_dev_set_xfermode(struct 
 }
 
 /**
- *	ata_sg_clean -
- *	@qc:
+ *	ata_sg_clean - Unmap DMA memory associated with command
+ *	@qc: Command containing DMA memory to be released
+ *
+ *	Unmap all mapped DMA memory associated with this command.
  *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
  */
 
 static void ata_sg_clean(struct ata_queued_cmd *qc)
@@ -1981,7 +2135,11 @@ static void ata_sg_clean(struct ata_queu
  *	ata_fill_sg - Fill PCI IDE PRD table
  *	@qc: Metadata associated with taskfile to be transferred
  *
+ *	Fill PCI IDE PRD (scatter-gather) table with segments
+ *	associated with the current disk command.
+ *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
  *
  */
 static void ata_fill_sg(struct ata_queued_cmd *qc)
@@ -2028,7 +2186,13 @@ static void ata_fill_sg(struct ata_queue
  *	ata_check_atapi_dma - Check whether ATAPI DMA can be supported
  *	@qc: Metadata associated with taskfile to check
  *
+ *	Allow low-level driver to filter ATA PACKET commands, returning
+ *	a status indicating whether or not it is OK to use DMA for the
+ *	supplied PACKET command.
+ *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
  *	RETURNS: 0 when ATAPI DMA can be used
  *               nonzero otherwise
  */
@@ -2046,6 +2210,8 @@ int ata_check_atapi_dma(struct ata_queue
  *	ata_qc_prep - Prepare taskfile for submission
  *	@qc: Metadata associated with taskfile to be prepared
  *
+ *	Prepare ATA taskfile for submission.
+ *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  */
@@ -2057,6 +2223,32 @@ void ata_qc_prep(struct ata_queued_cmd *
 	ata_fill_sg(qc);
 }
 
+/**
+ *	ata_sg_init_one - Associate command with memory buffer
+ *	@qc: Command to be associated
+ *	@buf: Memory buffer
+ *	@buflen: Length of memory buffer, in bytes.
+ *
+ *	Initialize the data-related elements of queued_cmd @qc
+ *	to point to a single memory buffer, @buf of byte length @buflen.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+
+
+/**
+ *	ata_sg_init_one - Prepare a one-entry scatter-gather list.
+ *	@qc:  Queued command
+ *	@buf:  transfer buffer
+ *	@buflen:  length of buf
+ *
+ *	Builds a single-entry scatter-gather list to initiate a
+ *	transfer utilizing the specified buffer.
+ *
+ *	LOCKING:
+ */
 void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
 {
 	struct scatterlist *sg;
@@ -2071,9 +2263,35 @@ void ata_sg_init_one(struct ata_queued_c
 	sg = qc->sg;
 	sg->page = virt_to_page(buf);
 	sg->offset = (unsigned long) buf & ~PAGE_MASK;
-	sg_dma_len(sg) = buflen;
+	sg->length = buflen;
 }
 
+/**
+ *	ata_sg_init - Associate command with scatter-gather table.
+ *	@qc: Command to be associated
+ *	@sg: Scatter-gather table.
+ *	@n_elem: Number of elements in s/g table.
+ *
+ *	Initialize the data-related elements of queued_cmd @qc
+ *	to point to a scatter-gather table @sg, containing @n_elem
+ *	elements.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+
+/**
+ *	ata_sg_init - Assign a scatter gather list to a queued command
+ *	@qc:  Queued command
+ *	@sg:  Scatter-gather list
+ *	@n_elem:  length of sg list
+ *
+ *	Attaches a scatter-gather list to a queued command.
+ *
+ *	LOCKING:
+ */
+
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
 		 unsigned int n_elem)
 {
@@ -2083,14 +2301,16 @@ void ata_sg_init(struct ata_queued_cmd *
 }
 
 /**
- *	ata_sg_setup_one -
- *	@qc:
+ *	ata_sg_setup_one - DMA-map the memory buffer associated with a command.
+ *	@qc: Command with memory buffer to be mapped.
+ *
+ *	DMA-map the memory buffer associated with queued_cmd @qc.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  *
  *	RETURNS:
- *
+ *	Zero on success, negative on error.
  */
 
 static int ata_sg_setup_one(struct ata_queued_cmd *qc)
@@ -2101,11 +2321,12 @@ static int ata_sg_setup_one(struct ata_q
 	dma_addr_t dma_address;
 
 	dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt,
-				     sg_dma_len(sg), dir);
+				     sg->length, dir);
 	if (dma_mapping_error(dma_address))
 		return -1;
 
 	sg_dma_address(sg) = dma_address;
+	sg_dma_len(sg) = sg->length;
 
 	DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
 		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
@@ -2114,13 +2335,16 @@ static int ata_sg_setup_one(struct ata_q
 }
 
 /**
- *	ata_sg_setup -
- *	@qc:
+ *	ata_sg_setup - DMA-map the scatter-gather table associated with a command.
+ *	@qc: Command with scatter-gather table to be mapped.
+ *
+ *	DMA-map the scatter-gather table associated with queued_cmd @qc.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  *
  *	RETURNS:
+ *	Zero on success, negative on error.
  *
  */
 
@@ -2150,6 +2374,7 @@ static int ata_sg_setup(struct ata_queue
  *	@ap:
  *
  *	LOCKING:
+ *	None.  (executing in kernel thread context)
  *
  *	RETURNS:
  *
@@ -2197,6 +2422,7 @@ static unsigned long ata_pio_poll(struct
  *	@ap:
  *
  *	LOCKING:
+ *	None.  (executing in kernel thread context)
  */
 
 static void ata_pio_complete (struct ata_port *ap)
@@ -2239,6 +2465,18 @@ static void ata_pio_complete (struct ata
 	ata_qc_complete(qc, drv_stat);
 }
 
+
+/**
+ *	swap_buf_le16 -
+ *	@buf:  Buffer to swap
+ *	@buf_words:  Number of 16-bit words in buffer.
+ *
+ *	Swap halves of 16-bit words if needed to convert from
+ *	little-endian byte order to native cpu byte order, or
+ *	vice-versa.
+ *
+ *	LOCKING:
+ */
 void swap_buf_le16(u16 *buf, unsigned int buf_words)
 {
 #ifdef __BIG_ENDIAN
@@ -2310,7 +2548,7 @@ static void ata_pio_sector(struct ata_qu
 	qc->cursect++;
 	qc->cursg_ofs++;
 
-	if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+	if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
 		qc->cursg++;
 		qc->cursg_ofs = 0;
 	}
@@ -2339,7 +2577,6 @@ static void __atapi_pio_bytes(struct ata
 next_sg:
 	sg = &qc->sg[qc->cursg];
 
-next_page:
 	page = sg->page;
 	offset = sg->offset + qc->cursg_ofs;
 
@@ -2347,7 +2584,8 @@ next_page:
 	page = nth_page(page, (offset >> PAGE_SHIFT));
 	offset %= PAGE_SIZE;
 
-	count = min(sg_dma_len(sg) - qc->cursg_ofs, bytes);
+	/* don't overrun current sg */
+	count = min(sg->length - qc->cursg_ofs, bytes);
 
 	/* don't cross page boundaries */
 	count = min(count, (unsigned int)PAGE_SIZE - offset);
@@ -2358,7 +2596,7 @@ next_page:
 	qc->curbytes += count;
 	qc->cursg_ofs += count;
 
-	if (qc->cursg_ofs == sg_dma_len(sg)) {
+	if (qc->cursg_ofs == sg->length) {
 		qc->cursg++;
 		qc->cursg_ofs = 0;
 	}
@@ -2371,8 +2609,6 @@ next_page:
 	kunmap(page);
 
 	if (bytes) {
-		if (qc->cursg_ofs < sg_dma_len(sg))
-			goto next_page;
 		goto next_sg;
 	}
 }
@@ -2414,6 +2650,7 @@ err_out:
  *	@ap:
  *
  *	LOCKING:
+ *	None.  (executing in kernel thread context)
  */
 
 static void ata_pio_block(struct ata_port *ap)
@@ -2539,7 +2776,7 @@ static void atapi_request_sense(struct a
 	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
 	qc->dma_dir = DMA_FROM_DEVICE;
 
-	memset(&qc->cdb, 0, sizeof(ap->cdb_len));
+	memset(&qc->cdb, 0, ap->cdb_len);
 	qc->cdb[0] = REQUEST_SENSE;
 	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
 
@@ -2582,6 +2819,7 @@ static void atapi_request_sense(struct a
  *	transaction completed successfully.
  *
  *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
  */
 
 static void ata_qc_timeout(struct ata_queued_cmd *qc)
@@ -2691,6 +2929,7 @@ out:
  *	@dev: Device from whom we request an available command structure
  *
  *	LOCKING:
+ *	None.
  */
 
 static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
@@ -2716,6 +2955,7 @@ static struct ata_queued_cmd *ata_qc_new
  *	@dev: Device from whom we request an available command structure
  *
  *	LOCKING:
+ *	None.
  */
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
@@ -2780,6 +3020,7 @@ static void __ata_qc_complete(struct ata
  *	in case something prevents using it.
  *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
  *
  */
 void ata_qc_free(struct ata_queued_cmd *qc)
@@ -2793,9 +3034,13 @@ void ata_qc_free(struct ata_queued_cmd *
 /**
  *	ata_qc_complete - Complete an active ATA command
  *	@qc: Command to complete
- *	@drv_stat: ATA status register contents
+ *	@drv_stat: ATA Status register contents
+ *
+ *	Indicate to the mid and upper layers that an ATA
+ *	command has completed, with either an ok or not-ok status.
  *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
  *
  */
 
@@ -2811,6 +3056,7 @@ void ata_qc_complete(struct ata_queued_c
 
 	/* call completion callback */
 	rc = qc->complete_fn(qc, drv_stat);
+	qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
 	/* if callback indicates not to complete command (non-zero),
 	 * return immediately
@@ -2890,6 +3136,7 @@ err_out:
 	return -1;
 }
 
+
 /**
  *	ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
  *	@qc: command to issue to device
@@ -2899,6 +3146,8 @@ err_out:
  *	classes called "protocols", and issuing each type of protocol
  *	is slightly different.
  *
+ *	May be used as the qc_issue() entry in ata_port_operations.
+ *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  *
@@ -2956,7 +3205,7 @@ int ata_qc_issue_prot(struct ata_queued_
 }
 
 /**
- *	ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *	ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
  *	@qc: Info associated with this ATA transaction.
  *
  *	LOCKING:
@@ -3063,6 +3312,18 @@ static void ata_bmdma_start_pio (struct 
 	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+
+/**
+ *	ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	Writes the ATA_DMA_START flag to the DMA command register.
+ *
+ *	May be used as the bmdma_start() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_start(struct ata_queued_cmd *qc)
 {
 	if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3071,6 +3332,20 @@ void ata_bmdma_start(struct ata_queued_c
 		ata_bmdma_start_pio(qc);
 }
 
+
+/**
+ *	ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	Writes address of PRD table to device's PRD Table Address
+ *	register, sets the DMA control register, and calls
+ *	ops->exec_command() to start the transfer.
+ *
+ *	May be used as the bmdma_setup() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_setup(struct ata_queued_cmd *qc)
 {
 	if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3079,6 +3354,19 @@ void ata_bmdma_setup(struct ata_queued_c
 		ata_bmdma_setup_pio(qc);
 }
 
+
+/**
+ *	ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ *	@ap: Port associated with this ATA transaction.
+ *
+ *	Clear interrupt and error flags in DMA status register.
+ *
+ *	May be used as the irq_clear() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_irq_clear(struct ata_port *ap)
 {
     if (ap->flags & ATA_FLAG_MMIO) {
@@ -3091,6 +3379,19 @@ void ata_bmdma_irq_clear(struct ata_port
 
 }
 
+
+/**
+ *	ata_bmdma_status - Read PCI IDE BMDMA status
+ *	@ap: Port associated with this ATA transaction.
+ *
+ *	Read and return BMDMA status register.
+ *
+ *	May be used as the bmdma_status() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
 u8 ata_bmdma_status(struct ata_port *ap)
 {
 	u8 host_stat;
@@ -3102,6 +3403,19 @@ u8 ata_bmdma_status(struct ata_port *ap)
 	return host_stat;
 }
 
+
+/**
+ *	ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+ *	@ap: Port associated with this ATA transaction.
+ *
+ *	Clears the ATA_DMA_START flag in the dma control register
+ *
+ *	May be used as the bmdma_stop() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_stop(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO) {
@@ -3201,13 +3515,18 @@ idle_irq:
 
 /**
  *	ata_interrupt - Default ATA host interrupt handler
- *	@irq: irq line
- *	@dev_instance: pointer to our host information structure
+ *	@irq: irq line (unused)
+ *	@dev_instance: pointer to our ata_host_set information structure
  *	@regs: unused
  *
+ *	Default interrupt handler for PCI IDE devices.  Calls
+ *	ata_host_intr() for each port that is not disabled.
+ *
  *	LOCKING:
+ *	Obtains host_set lock during operation.
  *
  *	RETURNS:
+ *	IRQ_NONE or IRQ_HANDLED.
  *
  */
 
@@ -3229,7 +3548,8 @@ irqreturn_t ata_interrupt (int irq, void
 			struct ata_queued_cmd *qc;
 
 			qc = ata_qc_from_tag(ap, ap->active_tag);
-			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+			    (qc->flags & ATA_QCFLAG_ACTIVE))
 				handled |= ata_host_intr(ap, qc);
 		}
 	}
@@ -3299,6 +3619,19 @@ err_out:
 	ata_qc_complete(qc, ATA_ERR);
 }
 
+
+/**
+ *	ata_port_start - Set port up for dma.
+ *	@ap: Port to initialize
+ *
+ *	Called just after data structures for each port are
+ *	initialized.  Allocates space for PRD table.
+ *
+ *	May be used as the port_start() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ */
+
 int ata_port_start (struct ata_port *ap)
 {
 	struct device *dev = ap->host_set->dev;
@@ -3312,6 +3645,18 @@ int ata_port_start (struct ata_port *ap)
 	return 0;
 }
 
+
+/**
+ *	ata_port_stop - Undo ata_port_start()
+ *	@ap: Port to shut down
+ *
+ *	Frees the PRD table.
+ *
+ *	May be used as the port_stop() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ */
+
 void ata_port_stop (struct ata_port *ap)
 {
 	struct device *dev = ap->host_set->dev;
@@ -3319,6 +3664,13 @@ void ata_port_stop (struct ata_port *ap)
 	dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
 }
 
+void ata_host_stop (struct ata_host_set *host_set)
+{
+	if (host_set->mmio_base)
+		iounmap(host_set->mmio_base);
+}
+
+
 /**
  *	ata_host_remove - Unregister SCSI host structure with upper layers
  *	@ap: Port to unregister
@@ -3347,7 +3699,11 @@ static void ata_host_remove(struct ata_p
  *	@ent: Probe information provided by low-level driver
  *	@port_no: Port number associated with this ata_port
  *
+ *	Initialize a new ata_port structure, and its associated
+ *	scsi_host.
+ *
  *	LOCKING:
+ *	Inherited from caller.
  *
  */
 
@@ -3402,9 +3758,13 @@ static void ata_host_init(struct ata_por
  *	@host_set: Collections of ports to which we add
  *	@port_no: Port number associated with this host
  *
+ *	Attach low-level ATA driver to system.
+ *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  *	RETURNS:
+ *	New ata_port on success, for NULL on error.
  *
  */
 
@@ -3437,12 +3797,22 @@ err_out:
 }
 
 /**
- *	ata_device_add -
- *	@ent:
+ *	ata_device_add - Register hardware device with ATA and SCSI layers
+ *	@ent: Probe information describing hardware device to be registered
+ *
+ *	This function processes the information provided in the probe
+ *	information struct @ent, allocates the necessary ATA and SCSI
+ *	host information structures, initializes them, and registers
+ *	everything with requisite kernel subsystems.
+ *
+ *	This function requests irqs, probes the ATA bus, and probes
+ *	the SCSI bus.
  *
  *	LOCKING:
+ *	PCI/etc. bus probe sem.
  *
  *	RETURNS:
+ *	Number of ports registered.  Zero on error (no ports registered).
  *
  */
 
@@ -3594,7 +3964,15 @@ int ata_scsi_release(struct Scsi_Host *h
 /**
  *	ata_std_ports - initialize ioaddr with standard port offsets.
  *	@ioaddr: IO address structure to be initialized
+ *
+ *	Utility function which initializes data_addr, error_addr,
+ *	feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
+ *	device_addr, status_addr, and command_addr to standard offsets
+ *	relative to cmd_addr.
+ *
+ *	Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
  */
+
 void ata_std_ports(struct ata_ioports *ioaddr)
 {
 	ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
@@ -3636,6 +4014,20 @@ ata_probe_ent_alloc(struct device *dev, 
 	return probe_ent;
 }
 
+
+
+/**
+ *	ata_pci_init_native_mode - Initialize native-mode driver
+ *	@pdev:  pci device to be initialized
+ *	@port:  array[2] of pointers to port info structures.
+ *
+ *	Utility function which allocates and initializes an
+ *	ata_probe_ent structure for a standard dual-port
+ *	PIO-based IDE controller.  The returned ata_probe_ent
+ *	structure can be passed to ata_device_add().  The returned
+ *	ata_probe_ent structure should then be freed with kfree().
+ */
+
 #ifdef CONFIG_PCI
 struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
@@ -3717,10 +4109,19 @@ ata_pci_init_legacy_mode(struct pci_dev 
  *	@port_info: Information from low-level host driver
  *	@n_ports: Number of ports attached to host controller
  *
+ *	This is a helper function which can be called from a driver's
+ *	xxx_init_one() probe function if the hardware uses traditional
+ *	IDE taskfile registers.
+ *
+ *	This function calls pci_enable_device(), reserves its register
+ *	regions, sets the dma mask, enables bus master mode, and calls
+ *	ata_device_add()
+ *
  *	LOCKING:
  *	Inherited from PCI layer (may sleep).
  *
  *	RETURNS:
+ *	Zero on success, negative on errno-based value on error.
  *
  */
 
@@ -3875,35 +4276,30 @@ void ata_pci_remove_one (struct pci_dev 
 	}
 
 	free_irq(host_set->irq, host_set);
-	if (host_set->ops->host_stop)
-		host_set->ops->host_stop(host_set);
-	if (host_set->mmio_base)
-		iounmap(host_set->mmio_base);
 
 	for (i = 0; i < host_set->n_ports; i++) {
 		ap = host_set->ports[i];
 
 		ata_scsi_release(ap->host);
-		scsi_host_put(ap->host);
-	}
-
-	pci_release_regions(pdev);
-
-	for (i = 0; i < host_set->n_ports; i++) {
-		struct ata_ioports *ioaddr;
-
-		ap = host_set->ports[i];
-		ioaddr = &ap->ioaddr;
 
 		if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+			struct ata_ioports *ioaddr = &ap->ioaddr;
+
 			if (ioaddr->cmd_addr == 0x1f0)
 				release_region(0x1f0, 8);
 			else if (ioaddr->cmd_addr == 0x170)
 				release_region(0x170, 8);
 		}
+
+		scsi_host_put(ap->host);
 	}
 
+	if (host_set->ops->host_stop)
+		host_set->ops->host_stop(host_set);
+
 	kfree(host_set);
+
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	dev_set_drvdata(dev, NULL);
 }
@@ -3944,15 +4340,6 @@ int pci_test_config_bits(struct pci_dev 
 #endif /* CONFIG_PCI */
 
 
-/**
- *	ata_init -
- *
- *	LOCKING:
- *
- *	RETURNS:
- *
- */
-
 static int __init ata_init(void)
 {
 	ata_wq = create_workqueue("ata");
@@ -3998,6 +4385,7 @@ EXPORT_SYMBOL_GPL(ata_chk_err);
 EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_host_stop);
 EXPORT_SYMBOL_GPL(ata_interrupt);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_bmdma_setup);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -305,7 +305,7 @@ void ata_to_sense_error(struct ata_queue
 	sb[0] = 0x70;
 	sb[2] = MEDIUM_ERROR;
 	sb[7] = 0x0A;
-	if (cmd->sc_data_direction == SCSI_DATA_READ) {
+	if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		sb[12] = 0x11; /* "unrecovered read error" */
 		sb[13] = 0x04;
 	} else {
@@ -347,7 +347,10 @@ int ata_scsi_slave_config(struct scsi_de
 		 */
 		if ((dev->flags & ATA_DFLAG_LBA48) &&
 		    ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) {
-			sdev->host->max_sectors = 2048;
+			/*
+			 * do not overwrite sdev->host->max_sectors, since
+			 * other drives on this host may not support LBA48
+			 */
 			blk_queue_max_sectors(sdev->request_queue, 2048);
 		}
 	}
@@ -671,8 +674,8 @@ static void ata_scsi_translate(struct at
 		return;
 
 	/* data is present; dma-map it */
-	if (cmd->sc_data_direction == SCSI_DATA_READ ||
-	    cmd->sc_data_direction == SCSI_DATA_WRITE) {
+	if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
+	    cmd->sc_data_direction == DMA_TO_DEVICE) {
 		if (unlikely(cmd->request_bufflen < 1)) {
 			printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
 			       ap->id, dev->devno);
@@ -944,7 +947,7 @@ unsigned int ata_scsiop_inq_83(struct at
 }
 
 /**
- *	ata_scsiop_noop -
+ *	ata_scsiop_noop - Command handler that simply returns success.
  *	@args: device IDENTIFY data / SCSI command of interest.
  *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
  *	@buflen: Response buffer length.
@@ -1038,7 +1041,12 @@ static unsigned int ata_msense_caching(u
 
 static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
 {
-	const u8 page[] = {0xa, 0xa, 2, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30};
+	const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30};
+
+	/* byte 2: set the descriptor format sense data bit (bit 2)
+	 * since we need to support returning this format for SAT
+	 * commands and any SCSI commands against a 48b LBA device.
+	 */
 
 	ata_msense_push(ptr_io, last, page, sizeof(page));
 	return sizeof(page);
@@ -1299,7 +1307,7 @@ static unsigned int atapi_xlat(struct at
 	struct scsi_cmnd *cmd = qc->scsicmd;
 	struct ata_device *dev = qc->dev;
 	int using_pio = (dev->flags & ATA_DFLAG_PIO);
-	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
+	int nodata = (cmd->sc_data_direction == DMA_NONE);
 
 	if (!using_pio)
 		/* Check whether ATAPI DMA is safe */
@@ -1311,7 +1319,7 @@ static unsigned int atapi_xlat(struct at
 	qc->complete_fn = atapi_qc_complete;
 
 	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		qc->tf.flags |= ATA_TFLAG_WRITE;
 		DPRINTK("direction: write\n");
 	}
@@ -1335,7 +1343,7 @@ static unsigned int atapi_xlat(struct at
 
 #ifdef ATAPI_ENABLE_DMADIR
 		/* some SATA bridges need us to indicate data xfer direction */
-		if (cmd->sc_data_direction != SCSI_DATA_WRITE)
+		if (cmd->sc_data_direction != DMA_TO_DEVICE)
 			qc->tf.feature |= ATAPI_DMADIR;
 #endif
 	}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -26,7 +26,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME	"libata"
-#define DRV_VERSION	"1.10"	/* must be exactly four chars */
+#define DRV_VERSION	"1.11"	/* must be exactly four chars */
 
 struct ata_scsi_args {
 	u16			*id;
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/Makefile
@@ -0,0 +1,32 @@
+#/*******************************************************************
+# * This file is part of the Emulex Linux Device Driver for         *
+# * Enterprise Fibre Channel Host Bus Adapters.                     *
+# * Refer to the README file included with this package for         *
+# * driver version and adapter support.                             *
+# * Copyright (C) 2004 Emulex Corporation.                          *
+# * www.emulex.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, a copy of which    *
+# * can be found in the file COPYING included with this package.    *
+# *******************************************************************/
+######################################################################
+
+#$Id: Makefile 1.58 2005/01/23 19:00:32EST sf_support Exp  $
+
+ifneq ($(GCOV),)
+  EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage
+  EXTRA_CFLAGS += -O0
+endif
+
+obj-$(CONFIG_SCSI_LPFC) := lpfc.o
+
+lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
+	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -0,0 +1,384 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc.h 1.167 2005/04/07 08:47:05EDT sf_support Exp  $
+ */
+
+struct lpfc_sli2_slim;
+
+#define LPFC_MAX_TARGET         256	/* max targets supported */
+#define LPFC_MAX_DISC_THREADS	64	/* max outstanding discovery els req */
+#define LPFC_MAX_NS_RETRY       3	/* max NameServer retries */
+
+#define LPFC_DFT_HBA_Q_DEPTH	2048	/* max cmds per hba */
+#define LPFC_LC_HBA_Q_DEPTH	1024	/* max cmds per low cost hba */
+#define LPFC_LP101_HBA_Q_DEPTH	128	/* max cmds per low cost hba */
+
+#define LPFC_CMD_PER_LUN	30	/* max outstanding cmds per lun */
+#define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
+#define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
+
+/* Define macros for 64 bit support */
+#define putPaddrLow(addr)    ((uint32_t) (0xffffffff & (u64)(addr)))
+#define putPaddrHigh(addr)   ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
+#define getPaddr(high, low)  ((dma_addr_t)( \
+			     (( (u64)(high)<<16 ) << 16)|( (u64)(low))))
+/* Provide maximum configuration definitions. */
+#define LPFC_DRVR_TIMEOUT	16	/* driver iocb timeout value in sec */
+#define MAX_FCP_TARGET		256	/* max num of FCP targets supported */
+#define FC_MAX_ADPTMSG		64
+
+#define MAX_HBAEVT	32
+
+/* Provide DMA memory definitions the driver uses per port instance. */
+struct lpfc_dmabuf {
+	struct list_head list;
+	void *virt;		/* virtual address ptr */
+	dma_addr_t phys;	/* mapped address */
+};
+
+struct lpfc_dma_pool {
+	struct lpfc_dmabuf   *elements;
+	uint32_t    max_count;
+	uint32_t    current_count;
+};
+
+/* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
+#define MEM_PRI		0x100
+
+
+/****************************************************************************/
+/*      Device VPD save area                                                */
+/****************************************************************************/
+typedef struct lpfc_vpd {
+	uint32_t status;	/* vpd status value */
+	uint32_t length;	/* number of bytes actually returned */
+	struct {
+		uint32_t rsvd1;	/* Revision numbers */
+		uint32_t biuRev;
+		uint32_t smRev;
+		uint32_t smFwRev;
+		uint32_t endecRev;
+		uint16_t rBit;
+		uint8_t fcphHigh;
+		uint8_t fcphLow;
+		uint8_t feaLevelHigh;
+		uint8_t feaLevelLow;
+		uint32_t postKernRev;
+		uint32_t opFwRev;
+		uint8_t opFwName[16];
+		uint32_t sli1FwRev;
+		uint8_t sli1FwName[16];
+		uint32_t sli2FwRev;
+		uint8_t sli2FwName[16];
+	} rev;
+} lpfc_vpd_t;
+
+struct lpfc_scsi_buf;
+
+
+/*
+ * lpfc stat counters
+ */
+struct lpfc_stats {
+	/* Statistics for ELS commands */
+	uint32_t elsLogiCol;
+	uint32_t elsRetryExceeded;
+	uint32_t elsXmitRetry;
+	uint32_t elsDelayRetry;
+	uint32_t elsRcvDrop;
+	uint32_t elsRcvFrame;
+	uint32_t elsRcvRSCN;
+	uint32_t elsRcvRNID;
+	uint32_t elsRcvFARP;
+	uint32_t elsRcvFARPR;
+	uint32_t elsRcvFLOGI;
+	uint32_t elsRcvPLOGI;
+	uint32_t elsRcvADISC;
+	uint32_t elsRcvPDISC;
+	uint32_t elsRcvFAN;
+	uint32_t elsRcvLOGO;
+	uint32_t elsRcvPRLO;
+	uint32_t elsRcvPRLI;
+	uint32_t elsRcvRRQ;
+	uint32_t elsXmitFLOGI;
+	uint32_t elsXmitPLOGI;
+	uint32_t elsXmitPRLI;
+	uint32_t elsXmitADISC;
+	uint32_t elsXmitLOGO;
+	uint32_t elsXmitSCR;
+	uint32_t elsXmitRNID;
+	uint32_t elsXmitFARP;
+	uint32_t elsXmitFARPR;
+	uint32_t elsXmitACC;
+	uint32_t elsXmitLSRJT;
+
+	uint32_t frameRcvBcast;
+	uint32_t frameRcvMulti;
+	uint32_t strayXmitCmpl;
+	uint32_t frameXmitDelay;
+	uint32_t xriCmdCmpl;
+	uint32_t xriStatErr;
+	uint32_t LinkUp;
+	uint32_t LinkDown;
+	uint32_t LinkMultiEvent;
+	uint32_t NoRcvBuf;
+	uint32_t fcpCmd;
+	uint32_t fcpCmpl;
+	uint32_t fcpRspErr;
+	uint32_t fcpRemoteStop;
+	uint32_t fcpPortRjt;
+	uint32_t fcpPortBusy;
+	uint32_t fcpError;
+	uint32_t fcpLocalErr;
+};
+
+enum sysfs_mbox_state {
+	SMBOX_IDLE,
+	SMBOX_WRITING,
+	SMBOX_READING
+};
+
+struct lpfc_sysfs_mbox {
+	enum sysfs_mbox_state state;
+	size_t                offset;
+	struct lpfcMboxq *    mbox;
+};
+
+struct lpfc_hba {
+	struct list_head hba_list;	/* List of hbas/ports */
+	struct lpfc_sli sli;
+	struct lpfc_sli2_slim *slim2p;
+	dma_addr_t slim2p_mapping;
+	uint16_t pci_cfg_value;
+
+	uint32_t hba_state;
+
+#define LPFC_INIT_START           1	/* Initial state after board reset */
+#define LPFC_INIT_MBX_CMDS        2	/* Initialize HBA with mbox commands */
+#define LPFC_LINK_DOWN            3	/* HBA initialized, link is down */
+#define LPFC_LINK_UP              4	/* Link is up  - issue READ_LA */
+#define LPFC_LOCAL_CFG_LINK       5	/* local NPORT Id configured */
+#define LPFC_FLOGI                6	/* FLOGI sent to Fabric */
+#define LPFC_FABRIC_CFG_LINK      7	/* Fabric assigned NPORT Id
+					   configured */
+#define LPFC_NS_REG               8	/* Register with NameServer */
+#define LPFC_NS_QRY               9	/* Query NameServer for NPort ID list */
+#define LPFC_BUILD_DISC_LIST      10	/* Build ADISC and PLOGI lists for
+					 * device authentication / discovery */
+#define LPFC_DISC_AUTH            11	/* Processing ADISC list */
+#define LPFC_CLEAR_LA             12	/* authentication cmplt - issue
+					   CLEAR_LA */
+#define LPFC_HBA_READY            32
+#define LPFC_HBA_ERROR            0xff
+
+	uint8_t fc_linkspeed;	/* Link speed after last READ_LA */
+
+	uint32_t fc_eventTag;	/* event tag for link attention */
+	uint32_t fc_prli_sent;	/* cntr for outstanding PRLIs */
+
+	uint32_t num_disc_nodes;	/*in addition to hba_state */
+
+	struct timer_list fc_estabtmo;	/* link establishment timer */
+	struct timer_list fc_disctmo;	/* Discovery rescue timer */
+	struct timer_list fc_fdmitmo;	/* fdmi timer */
+	/* These fields used to be binfo */
+	struct lpfc_name fc_nodename;	/* fc nodename */
+	struct lpfc_name fc_portname;	/* fc portname */
+	uint32_t fc_pref_DID;	/* preferred D_ID */
+	uint8_t fc_pref_ALPA;	/* preferred AL_PA */
+	uint32_t fc_edtov;	/* E_D_TOV timer value */
+	uint32_t fc_arbtov;	/* ARB_TOV timer value */
+	uint32_t fc_ratov;	/* R_A_TOV timer value */
+	uint32_t fc_rttov;	/* R_T_TOV timer value */
+	uint32_t fc_altov;	/* AL_TOV timer value */
+	uint32_t fc_crtov;	/* C_R_TOV timer value */
+	uint32_t fc_citov;	/* C_I_TOV timer value */
+	uint32_t fc_myDID;	/* fibre channel S_ID */
+	uint32_t fc_prevDID;	/* previous fibre channel S_ID */
+
+	struct serv_parm fc_sparam;	/* buffer for our service parameters */
+	struct serv_parm fc_fabparam;	/* fabric service parameters buffer */
+	uint8_t alpa_map[128];	/* AL_PA map from READ_LA */
+
+	uint8_t fc_ns_retry;	/* retries for fabric nameserver */
+	uint32_t fc_nlp_cnt;	/* outstanding NODELIST requests */
+	uint32_t fc_rscn_id_cnt;	/* count of RSCNs payloads in list */
+	struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
+	uint32_t lmt;
+	uint32_t fc_flag;	/* FC flags */
+#define FC_PT2PT                0x1	/* pt2pt with no fabric */
+#define FC_PT2PT_PLOGI          0x2	/* pt2pt initiate PLOGI */
+#define FC_DISC_TMO             0x4	/* Discovery timer running */
+#define FC_PUBLIC_LOOP          0x8	/* Public loop */
+#define FC_LBIT                 0x10	/* LOGIN bit in loopinit set */
+#define FC_RSCN_MODE            0x20	/* RSCN cmd rcv'ed */
+#define FC_NLP_MORE             0x40	/* More node to process in node tbl */
+#define FC_OFFLINE_MODE         0x80	/* Interface is offline for diag */
+#define FC_FABRIC               0x100	/* We are fabric attached */
+#define FC_ESTABLISH_LINK       0x200	/* Reestablish Link */
+#define FC_RSCN_DISCOVERY       0x400	/* Authenticate all devices after RSCN*/
+#define FC_LOADING		0x1000	/* HBA in process of loading drvr */
+#define FC_UNLOADING		0x2000	/* HBA in process of unloading drvr */
+#define FC_SCSI_SCAN_TMO        0x4000	/* scsi scan timer running */
+#define FC_ABORT_DISCOVERY      0x8000	/* we want to abort discovery */
+#define FC_NDISC_ACTIVE         0x10000	/* NPort discovery active */
+
+	uint32_t fc_topology;	/* link topology, from LINK INIT */
+
+	struct lpfc_stats fc_stat;
+
+	/* These are the head/tail pointers for the bind, plogi, adisc, unmap,
+	 *  and map lists.  Their counters are immediately following.
+	 */
+	struct list_head fc_plogi_list;
+	struct list_head fc_adisc_list;
+	struct list_head fc_reglogin_list;
+	struct list_head fc_prli_list;
+	struct list_head fc_nlpunmap_list;
+	struct list_head fc_nlpmap_list;
+	struct list_head fc_npr_list;
+	struct list_head fc_unused_list;
+
+	/* Keep counters for the number of entries in each list. */
+	uint16_t fc_plogi_cnt;
+	uint16_t fc_adisc_cnt;
+	uint16_t fc_reglogin_cnt;
+	uint16_t fc_prli_cnt;
+	uint16_t fc_unmap_cnt;
+	uint16_t fc_map_cnt;
+	uint16_t fc_npr_cnt;
+	uint16_t fc_unused_cnt;
+	struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */
+	uint32_t nport_event_cnt;	/* timestamp for nlplist entry */
+
+#define LPFC_RPI_HASH_SIZE     64
+#define LPFC_RPI_HASH_FUNC(x)  ((x) & (0x3f))
+	/* ptr to active D_ID / RPIs */
+	struct lpfc_nodelist *fc_nlplookup[LPFC_RPI_HASH_SIZE];
+	uint32_t wwnn[2];
+	uint32_t RandomData[7];
+
+	uint32_t cfg_log_verbose;
+	uint32_t cfg_lun_queue_depth;
+	uint32_t cfg_nodev_tmo;
+	uint32_t cfg_hba_queue_depth;
+	uint32_t cfg_fcp_class;
+	uint32_t cfg_use_adisc;
+	uint32_t cfg_ack0;
+	uint32_t cfg_topology;
+	uint32_t cfg_scan_down;
+	uint32_t cfg_link_speed;
+	uint32_t cfg_cr_delay;
+	uint32_t cfg_cr_count;
+	uint32_t cfg_fdmi_on;
+	uint32_t cfg_fcp_bind_method;
+	uint32_t cfg_discovery_threads;
+	uint32_t cfg_max_luns;
+	uint32_t cfg_sg_seg_cnt;
+	uint32_t cfg_sg_dma_buf_size;
+
+	lpfc_vpd_t vpd;		/* vital product data */
+
+	struct Scsi_Host *host;
+	struct pci_dev *pcidev;
+	struct list_head      work_list;
+	uint32_t              work_ha;      /* Host Attention Bits for WT */
+	uint32_t              work_ha_mask; /* HA Bits owned by WT        */
+	uint32_t              work_hs;      /* HS stored in case of ERRAT */
+	uint32_t              work_status[2]; /* Extra status from SLIM */
+	uint32_t              work_hba_events; /* Timeout to be handled  */
+#define WORKER_DISC_TMO                0x1	/* Discovery timeout */
+#define WORKER_ELS_TMO                 0x2	/* ELS timeout */
+#define WORKER_MBOX_TMO                0x4	/* MBOX timeout */
+#define WORKER_FDMI_TMO                0x8	/* FDMI timeout */
+
+	wait_queue_head_t    *work_wait;
+	struct task_struct   *worker_thread;
+
+	unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
+	unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
+	void __iomem *slim_memmap_p;	/* Kernel memory mapped address for
+					   PCI BAR0 */
+	void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for
+					    PCI BAR2 */
+
+	void __iomem *MBslimaddr;	/* virtual address for mbox cmds */
+	void __iomem *HAregaddr;	/* virtual address for host attn reg */
+	void __iomem *CAregaddr;	/* virtual address for chip attn reg */
+	void __iomem *HSregaddr;	/* virtual address for host status
+					   reg */
+	void __iomem *HCregaddr;	/* virtual address for host ctl reg */
+
+	int brd_no;			/* FC board number */
+
+	char SerialNumber[32];		/* adapter Serial Number */
+	char OptionROMVersion[32];	/* adapter BIOS / Fcode version */
+	char ModelDesc[256];		/* Model Description */
+	char ModelName[80];		/* Model Name */
+	char ProgramType[256];		/* Program Type */
+	char Port[20];			/* Port No */
+	uint8_t vpd_flag;               /* VPD data flag */
+
+#define VPD_MODEL_DESC      0x1         /* valid vpd model description */
+#define VPD_MODEL_NAME      0x2         /* valid vpd model name */
+#define VPD_PROGRAM_TYPE    0x4         /* valid vpd program type */
+#define VPD_PORT            0x8         /* valid vpd port data */
+#define VPD_MASK            0xf         /* mask for any vpd data */
+
+	struct timer_list els_tmofunc;
+
+	void *link_stats;
+
+	/*
+	 * stat  counters
+	 */
+	uint64_t fc4InputRequests;
+	uint64_t fc4OutputRequests;
+	uint64_t fc4ControlRequests;
+
+	struct lpfc_sysfs_mbox sysfs_mbox;
+
+	/* fastpath list. */
+	struct list_head lpfc_scsi_buf_list;
+	uint32_t total_scsi_bufs;
+	struct list_head lpfc_iocb_list;
+	uint32_t total_iocbq_bufs;
+
+	/* pci_mem_pools */
+	struct pci_pool *lpfc_scsi_dma_buf_pool;
+	struct pci_pool *lpfc_mbuf_pool;
+	struct lpfc_dma_pool lpfc_mbuf_safety_pool;
+
+	mempool_t *mbox_mem_pool;
+	mempool_t *nlp_mem_pool;
+	struct list_head freebufList;
+	struct list_head ctrspbuflist;
+	struct list_head rnidrspbuflist;
+};
+
+
+struct rnidrsp {
+	void *buf;
+	uint32_t uniqueid;
+	struct list_head list;
+	uint32_t data;
+};
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -0,0 +1,1291 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_attr.c 1.24 2005/04/13 11:58:55EDT sf_support Exp  $
+ */
+
+#include <linux/ctype.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_version.h"
+#include "lpfc_compat.h"
+#include "lpfc_crtn.h"
+
+
+static void
+lpfc_jedec_to_ascii(int incr, char hdw[])
+{
+	int i, j;
+	for (i = 0; i < 8; i++) {
+		j = (incr & 0xf);
+		if (j <= 9)
+			hdw[7 - i] = 0x30 +  j;
+		 else
+			hdw[7 - i] = 0x61 + j - 10;
+		incr = (incr >> 4);
+	}
+	hdw[8] = 0;
+	return;
+}
+
+static ssize_t
+lpfc_drvr_version_show(struct class_device *cdev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
+}
+
+static ssize_t
+management_version_show(struct class_device *cdev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n");
+}
+
+static ssize_t
+lpfc_info_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host));
+}
+
+static ssize_t
+lpfc_serialnum_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
+}
+
+static ssize_t
+lpfc_modeldesc_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);
+}
+
+static ssize_t
+lpfc_modelname_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);
+}
+
+static ssize_t
+lpfc_programtype_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);
+}
+
+static ssize_t
+lpfc_portnum_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);
+}
+
+static ssize_t
+lpfc_fwrev_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	char fwrev[32];
+	lpfc_decode_firmware_rev(phba, fwrev, 1);
+	return snprintf(buf, PAGE_SIZE, "%s\n",fwrev);
+}
+
+static ssize_t
+lpfc_hdw_show(struct class_device *cdev, char *buf)
+{
+	char hdw[9];
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	lpfc_vpd_t *vp = &phba->vpd;
+	lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
+	return snprintf(buf, PAGE_SIZE, "%s\n", hdw);
+}
+static ssize_t
+lpfc_option_rom_version_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
+}
+static ssize_t
+lpfc_state_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	int len = 0;
+	switch (phba->hba_state) {
+	case LPFC_INIT_START:
+	case LPFC_INIT_MBX_CMDS:
+	case LPFC_LINK_DOWN:
+		len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
+		break;
+	case LPFC_LINK_UP:
+	case LPFC_LOCAL_CFG_LINK:
+		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n");
+		break;
+	case LPFC_FLOGI:
+	case LPFC_FABRIC_CFG_LINK:
+	case LPFC_NS_REG:
+	case LPFC_NS_QRY:
+	case LPFC_BUILD_DISC_LIST:
+	case LPFC_DISC_AUTH:
+	case LPFC_CLEAR_LA:
+		len += snprintf(buf + len, PAGE_SIZE-len,
+				"Link Up - Discovery\n");
+		break;
+	case LPFC_HBA_READY:
+		len += snprintf(buf + len, PAGE_SIZE-len,
+				"Link Up - Ready:\n");
+		if (phba->fc_topology == TOPOLOGY_LOOP) {
+			if (phba->fc_flag & FC_PUBLIC_LOOP)
+				len += snprintf(buf + len, PAGE_SIZE-len,
+						"   Public Loop\n");
+			else
+				len += snprintf(buf + len, PAGE_SIZE-len,
+						"   Private Loop\n");
+		} else {
+			if (phba->fc_flag & FC_FABRIC)
+				len += snprintf(buf + len, PAGE_SIZE-len,
+						"   Fabric\n");
+			else
+				len += snprintf(buf + len, PAGE_SIZE-len,
+						"   Point-2-Point\n");
+		}
+	}
+	return len;
+}
+
+static ssize_t
+lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt +
+							phba->fc_unmap_cnt);
+}
+
+
+static ssize_t
+lpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0];
+	int val = 0;
+	LPFC_MBOXQ_t *pmboxq;
+	int mbxstatus = MBXERR_ERROR;
+
+	if ((sscanf(buf, "%d", &val) != 1) ||
+	    (val != 1))
+		return -EINVAL;
+
+	if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->hba_state != LPFC_HBA_READY))
+		return -EPERM;
+
+	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+
+	if (!pmboxq)
+		return -ENOMEM;
+
+	memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+	lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);
+	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+	if (mbxstatus == MBX_TIMEOUT)
+		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	else
+		mempool_free( pmboxq, phba->mbox_mem_pool);
+
+	if (mbxstatus == MBXERR_ERROR)
+		return -EIO;
+
+	return strlen(buf);
+}
+
+static ssize_t
+lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+}
+
+static ssize_t
+lpfc_board_online_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+
+	if (!phba) return 0;
+
+	if (phba->fc_flag & FC_OFFLINE_MODE)
+		return snprintf(buf, PAGE_SIZE, "0\n");
+	else
+		return snprintf(buf, PAGE_SIZE, "1\n");
+}
+
+static ssize_t
+lpfc_board_online_store(struct class_device *cdev, const char *buf,
+								size_t count)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	struct completion online_compl;
+	int val=0, status=0;
+
+	if (sscanf(buf, "%d", &val) != 1)
+		return 0;
+
+	init_completion(&online_compl);
+
+	if (val)
+		lpfc_workq_post_event(phba, &status, &online_compl,
+							LPFC_EVT_ONLINE);
+	else
+		lpfc_workq_post_event(phba, &status, &online_compl,
+							LPFC_EVT_OFFLINE);
+	wait_for_completion(&online_compl);
+	if (!status)
+		return strlen(buf);
+	else
+		return 0;
+}
+
+
+#define lpfc_param_show(attr)	\
+static ssize_t \
+lpfc_##attr##_show(struct class_device *cdev, char *buf) \
+{ \
+	struct Scsi_Host *host = class_to_shost(cdev);\
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\
+	int val = 0;\
+	if (phba){\
+		val = phba->cfg_##attr;\
+		return snprintf(buf, PAGE_SIZE, "%d\n",\
+				phba->cfg_##attr);\
+	}\
+	return 0;\
+}
+
+#define lpfc_param_store(attr, minval, maxval)	\
+static ssize_t \
+lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
+{ \
+	struct Scsi_Host *host = class_to_shost(cdev);\
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\
+	int val = 0;\
+	if (!isdigit(buf[0]))\
+		return -EINVAL;\
+	if (sscanf(buf, "0x%x", &val) != 1)\
+		if (sscanf(buf, "%d", &val) != 1)\
+			return -EINVAL;\
+	if (phba){\
+		if (val >= minval && val <= maxval) {\
+			phba->cfg_##attr = val;\
+			return strlen(buf);\
+		}\
+	}\
+	return 0;\
+}
+
+#define LPFC_ATTR_R_NOINIT(name, desc) \
+extern int lpfc_##name;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_show(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_show(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_show(name)\
+lpfc_param_store(name, minval, maxval)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+			 lpfc_##name##_show, lpfc_##name##_store)
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL);
+static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL);
+static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);
+static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL);
+static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
+static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL);
+static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
+static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
+static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);
+static CLASS_DEVICE_ATTR(option_rom_version, S_IRUGO,
+					lpfc_option_rom_version_show, NULL);
+static CLASS_DEVICE_ATTR(num_discovered_ports, S_IRUGO,
+					lpfc_num_discovered_ports_show, NULL);
+static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);
+static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
+			 NULL);
+static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
+			 NULL);
+static CLASS_DEVICE_ATTR(issue_lip, S_IWUSR, NULL, lpfc_issue_lip);
+static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
+			 lpfc_board_online_show, lpfc_board_online_store);
+
+
+/*
+# lpfc_log_verbose: Only turn this flag on if you are willing to risk being
+# deluged with LOTS of information.
+# You can set a bit mask to record specific types of verbose messages:
+#
+# LOG_ELS                       0x1        ELS events
+# LOG_DISCOVERY                 0x2        Link discovery events
+# LOG_MBOX                      0x4        Mailbox events
+# LOG_INIT                      0x8        Initialization events
+# LOG_LINK_EVENT                0x10       Link events
+# LOG_IP                        0x20       IP traffic history
+# LOG_FCP                       0x40       FCP traffic history
+# LOG_NODE                      0x80       Node table events
+# LOG_MISC                      0x400      Miscellaneous events
+# LOG_SLI                       0x800      SLI events
+# LOG_CHK_COND                  0x1000     FCP Check condition flag
+# LOG_LIBDFC                    0x2000     LIBDFC events
+# LOG_ALL_MSG                   0xffff     LOG all messages
+*/
+LPFC_ATTR_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask");
+
+/*
+# lun_queue_depth:  This parameter is used to limit the number of outstanding
+# commands per FCP LUN. Value range is [1,128]. Default value is 30.
+*/
+LPFC_ATTR_R(lun_queue_depth, 30, 1, 128,
+	    "Max number of FCP commands we can queue to a specific LUN");
+
+/*
+# Some disk devices have a "select ID" or "select Target" capability.
+# From a protocol standpoint "select ID" usually means select the
+# Fibre channel "ALPA".  In the FC-AL Profile there is an "informative
+# annex" which contains a table that maps a "select ID" (a number
+# between 0 and 7F) to an ALPA.  By default, for compatibility with
+# older drivers, the lpfc driver scans this table from low ALPA to high
+# ALPA.
+#
+# Turning on the scan-down variable (on  = 1, off = 0) will
+# cause the lpfc driver to use an inverted table, effectively
+# scanning ALPAs from high to low. Value range is [0,1]. Default value is 1.
+#
+# (Note: This "select ID" functionality is a LOOP ONLY characteristic
+# and will not work across a fabric. Also this parameter will take
+# effect only in the case when ALPA map is not available.)
+*/
+LPFC_ATTR_R(scan_down, 1, 0, 1,
+	     "Start scanning for devices from highest ALPA to lowest");
+
+/*
+# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+# until the timer expires. Value range is [0,255]. Default value is 20.
+# NOTE: this MUST be less then the SCSI Layer command timeout - 1.
+*/
+LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
+	     "Seconds driver will hold I/O waiting for a device to come back");
+
+/*
+# lpfc_topology:  link topology for init link
+#            0x0  = attempt loop mode then point-to-point
+#            0x02 = attempt point-to-point mode only
+#            0x04 = attempt loop mode only
+#            0x06 = attempt point-to-point mode then loop
+# Set point-to-point mode if you want to run as an N_Port.
+# Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
+# Default value is 0.
+*/
+LPFC_ATTR_R(topology, 0, 0, 6, "Select Fibre Channel topology");
+
+/*
+# lpfc_link_speed: Link speed selection for initializing the Fibre Channel
+# connection.
+#       0  = auto select (default)
+#       1  = 1 Gigabaud
+#       2  = 2 Gigabaud
+#       4  = 4 Gigabaud
+# Value range is [0,4]. Default value is 0.
+*/
+LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed");
+
+/*
+# lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
+# Value range is [2,3]. Default value is 3.
+*/
+LPFC_ATTR_R(fcp_class, 3, 2, 3,
+	     "Select Fibre Channel class of service for FCP sequences");
+
+/*
+# lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range
+# is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_RW(use_adisc, 0, 0, 1,
+	     "Use ADISC on rediscovery to authenticate FCP devices");
+
+/*
+# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
+# range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
+
+/*
+# lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing
+# cr_delay (msec) or cr_count outstanding commands. cr_delay can take
+# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay
+# is 0. Default value of cr_count is 1. The cr_count feature is disabled if
+# cr_delay is set to 0.
+*/
+static int lpfc_cr_delay = 0;
+module_param(lpfc_cr_delay, int , 0);
+MODULE_PARM_DESC(lpfc_cr_delay, "A count of milliseconds after which an "
+		"interrupt response is generated");
+
+static int lpfc_cr_count = 1;
+module_param(lpfc_cr_count, int, 0);
+MODULE_PARM_DESC(lpfc_cr_count, "A count of I/O completions after which an "
+		"interrupt response is generated");
+
+/*
+# lpfc_fdmi_on: controls FDMI support.
+#       0 = no FDMI support
+#       1 = support FDMI without attribute of hostname
+#       2 = support FDMI with attribute of hostname
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
+
+/*
+# Specifies the maximum number of ELS cmds we can have outstanding (for
+# discovery). Value range is [1,64]. Default value = 32.
+*/
+static int lpfc_discovery_threads = 32;
+module_param(lpfc_discovery_threads, int, 0);
+MODULE_PARM_DESC(lpfc_discovery_threads, "Maximum number of ELS commands "
+		 "during discovery");
+
+/*
+# lpfc_max_luns: maximum number of LUNs per target driver will support
+# Value range is [1,32768]. Default value is 256.
+# NOTE: The SCSI layer will scan each target for this many luns
+*/
+LPFC_ATTR_R(max_luns, 256, 1, 32768,
+	     "Maximum number of LUNs per target driver will support");
+
+struct class_device_attribute *lpfc_host_attrs[] = {
+	&class_device_attr_info,
+	&class_device_attr_serialnum,
+	&class_device_attr_modeldesc,
+	&class_device_attr_modelname,
+	&class_device_attr_programtype,
+	&class_device_attr_portnum,
+	&class_device_attr_fwrev,
+	&class_device_attr_hdw,
+	&class_device_attr_option_rom_version,
+	&class_device_attr_state,
+	&class_device_attr_num_discovered_ports,
+	&class_device_attr_lpfc_drvr_version,
+	&class_device_attr_lpfc_log_verbose,
+	&class_device_attr_lpfc_lun_queue_depth,
+	&class_device_attr_lpfc_nodev_tmo,
+	&class_device_attr_lpfc_fcp_class,
+	&class_device_attr_lpfc_use_adisc,
+	&class_device_attr_lpfc_ack0,
+	&class_device_attr_lpfc_topology,
+	&class_device_attr_lpfc_scan_down,
+	&class_device_attr_lpfc_link_speed,
+	&class_device_attr_lpfc_fdmi_on,
+	&class_device_attr_lpfc_max_luns,
+	&class_device_attr_nport_evt_cnt,
+	&class_device_attr_management_version,
+	&class_device_attr_issue_lip,
+	&class_device_attr_board_online,
+	NULL,
+};
+
+static ssize_t
+sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	size_t buf_off;
+	struct Scsi_Host *host = class_to_shost(container_of(kobj,
+					     struct class_device, kobj));
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+
+	if ((off + count) > FF_REG_AREA_SIZE)
+		return -ERANGE;
+
+	if (count == 0) return 0;
+
+	if (off % 4 || count % 4 || (unsigned long)buf % 4)
+		return -EINVAL;
+
+	spin_lock_irq(phba->host->host_lock);
+
+	if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return -EPERM;
+	}
+
+	for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t))
+		writel(*((uint32_t *)(buf + buf_off)),
+		       phba->ctrl_regs_memmap_p + off + buf_off);
+
+	spin_unlock_irq(phba->host->host_lock);
+
+	return count;
+}
+
+static ssize_t
+sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	size_t buf_off;
+	uint32_t * tmp_ptr;
+	struct Scsi_Host *host = class_to_shost(container_of(kobj,
+					     struct class_device, kobj));
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+
+	if (off > FF_REG_AREA_SIZE)
+		return -ERANGE;
+
+	if ((off + count) > FF_REG_AREA_SIZE)
+		count = FF_REG_AREA_SIZE - off;
+
+	if (count == 0) return 0;
+
+	if (off % 4 || count % 4 || (unsigned long)buf % 4)
+		return -EINVAL;
+
+	spin_lock_irq(phba->host->host_lock);
+
+	for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) {
+		tmp_ptr = (uint32_t *)(buf + buf_off);
+		*tmp_ptr = readl(phba->ctrl_regs_memmap_p + off + buf_off);
+	}
+
+	spin_unlock_irq(phba->host->host_lock);
+
+	return count;
+}
+
+static struct bin_attribute sysfs_ctlreg_attr = {
+	.attr = {
+		.name = "ctlreg",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 256,
+	.read = sysfs_ctlreg_read,
+	.write = sysfs_ctlreg_write,
+};
+
+
+static void
+sysfs_mbox_idle (struct lpfc_hba * phba)
+{
+	phba->sysfs_mbox.state = SMBOX_IDLE;
+	phba->sysfs_mbox.offset = 0;
+
+	if (phba->sysfs_mbox.mbox) {
+		mempool_free(phba->sysfs_mbox.mbox,
+			     phba->mbox_mem_pool);
+		phba->sysfs_mbox.mbox = NULL;
+	}
+}
+
+static ssize_t
+sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct Scsi_Host * host =
+		class_to_shost(container_of(kobj, struct class_device, kobj));
+	struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata[0];
+	struct lpfcMboxq * mbox = NULL;
+
+	if ((count + off) > MAILBOX_CMD_SIZE)
+		return -ERANGE;
+
+	if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
+		return -EINVAL;
+
+	if (count == 0)
+		return 0;
+
+	if (off == 0) {
+		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!mbox)
+			return -ENOMEM;
+
+	}
+
+	spin_lock_irq(host->host_lock);
+
+	if (off == 0) {
+		if (phba->sysfs_mbox.mbox)
+			mempool_free(mbox, phba->mbox_mem_pool);
+		else
+			phba->sysfs_mbox.mbox = mbox;
+		phba->sysfs_mbox.state = SMBOX_WRITING;
+	} else {
+		if (phba->sysfs_mbox.state  != SMBOX_WRITING ||
+		    phba->sysfs_mbox.offset != off           ||
+		    phba->sysfs_mbox.mbox   == NULL ) {
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(host->host_lock);
+			return -EINVAL;
+		}
+	}
+
+	memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off,
+	       buf, count);
+
+	phba->sysfs_mbox.offset = off + count;
+
+	spin_unlock_irq(host->host_lock);
+
+	return count;
+}
+
+static ssize_t
+sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct Scsi_Host *host =
+		class_to_shost(container_of(kobj, struct class_device,
+					    kobj));
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+	int rc;
+
+	if (off > sizeof(MAILBOX_t))
+		return -ERANGE;
+
+	if ((count + off) > sizeof(MAILBOX_t))
+		count = sizeof(MAILBOX_t) - off;
+
+	if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
+		return -EINVAL;
+
+	if (off && count == 0)
+		return 0;
+
+	spin_lock_irq(phba->host->host_lock);
+
+	if (off == 0 &&
+	    phba->sysfs_mbox.state  == SMBOX_WRITING &&
+	    phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
+
+		switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
+			/* Offline only */
+		case MBX_WRITE_NV:
+		case MBX_INIT_LINK:
+		case MBX_DOWN_LINK:
+		case MBX_CONFIG_LINK:
+		case MBX_CONFIG_RING:
+		case MBX_RESET_RING:
+		case MBX_UNREG_LOGIN:
+		case MBX_CLEAR_LA:
+		case MBX_DUMP_CONTEXT:
+		case MBX_RUN_DIAGS:
+		case MBX_RESTART:
+		case MBX_FLASH_WR_ULA:
+		case MBX_SET_MASK:
+		case MBX_SET_SLIM:
+		case MBX_SET_DEBUG:
+			if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
+				printk(KERN_WARNING "mbox_read:Command 0x%x "
+				       "is illegal in on-line state\n",
+				       phba->sysfs_mbox.mbox->mb.mbxCommand);
+				sysfs_mbox_idle(phba);
+				spin_unlock_irq(phba->host->host_lock);
+				return -EPERM;
+			}
+		case MBX_LOAD_SM:
+		case MBX_READ_NV:
+		case MBX_READ_CONFIG:
+		case MBX_READ_RCONFIG:
+		case MBX_READ_STATUS:
+		case MBX_READ_XRI:
+		case MBX_READ_REV:
+		case MBX_READ_LNK_STAT:
+		case MBX_DUMP_MEMORY:
+		case MBX_DOWN_LOAD:
+		case MBX_UPDATE_CFG:
+		case MBX_LOAD_AREA:
+		case MBX_LOAD_EXP_ROM:
+			break;
+		case MBX_READ_SPARM64:
+		case MBX_READ_LA:
+		case MBX_READ_LA64:
+		case MBX_REG_LOGIN:
+		case MBX_REG_LOGIN64:
+		case MBX_CONFIG_PORT:
+		case MBX_RUN_BIU_DIAG:
+			printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n",
+			       phba->sysfs_mbox.mbox->mb.mbxCommand);
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(phba->host->host_lock);
+			return -EPERM;
+		default:
+			printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n",
+			       phba->sysfs_mbox.mbox->mb.mbxCommand);
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(phba->host->host_lock);
+			return -EPERM;
+		}
+
+		if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+		    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
+
+			spin_unlock_irq(phba->host->host_lock);
+			rc = lpfc_sli_issue_mbox (phba,
+						  phba->sysfs_mbox.mbox,
+						  MBX_POLL);
+			spin_lock_irq(phba->host->host_lock);
+
+		} else {
+			spin_unlock_irq(phba->host->host_lock);
+			rc = lpfc_sli_issue_mbox_wait (phba,
+						       phba->sysfs_mbox.mbox,
+						       phba->fc_ratov * 2);
+			spin_lock_irq(phba->host->host_lock);
+		}
+
+		if (rc != MBX_SUCCESS) {
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(host->host_lock);
+			return -ENODEV;
+		}
+		phba->sysfs_mbox.state = SMBOX_READING;
+	}
+	else if (phba->sysfs_mbox.offset != off ||
+		 phba->sysfs_mbox.state  != SMBOX_READING) {
+		printk(KERN_WARNING  "mbox_read: Bad State\n");
+		sysfs_mbox_idle(phba);
+		spin_unlock_irq(host->host_lock);
+		return -EINVAL;
+	}
+
+	memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
+
+	phba->sysfs_mbox.offset = off + count;
+
+	if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t))
+		sysfs_mbox_idle(phba);
+
+	spin_unlock_irq(phba->host->host_lock);
+
+	return count;
+}
+
+static struct bin_attribute sysfs_mbox_attr = {
+	.attr = {
+		.name = "mbox",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = sizeof(MAILBOX_t),
+	.read = sysfs_mbox_read,
+	.write = sysfs_mbox_write,
+};
+
+int
+lpfc_alloc_sysfs_attr(struct lpfc_hba *phba)
+{
+	struct Scsi_Host *host = phba->host;
+	int error;
+
+	error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+							&sysfs_ctlreg_attr);
+	if (error)
+		goto out;
+
+	error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+							&sysfs_mbox_attr);
+	if (error)
+		goto out_remove_ctlreg_attr;
+
+	return 0;
+out_remove_ctlreg_attr:
+	sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+out:
+	return error;
+}
+
+void
+lpfc_free_sysfs_attr(struct lpfc_hba *phba)
+{
+	struct Scsi_Host *host = phba->host;
+
+	sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_mbox_attr);
+	sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+}
+
+
+/*
+ * Dynamic FC Host Attributes Support
+ */
+
+static void
+lpfc_get_host_port_id(struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+	/* note: fc_myDID already in cpu endianness */
+	fc_host_port_id(shost) = phba->fc_myDID;
+}
+
+static void
+lpfc_get_host_port_type(struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+
+	spin_lock_irq(shost->host_lock);
+
+	if (phba->hba_state == LPFC_HBA_READY) {
+		if (phba->fc_topology == TOPOLOGY_LOOP) {
+			if (phba->fc_flag & FC_PUBLIC_LOOP)
+				fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+			else
+				fc_host_port_type(shost) = FC_PORTTYPE_LPORT;
+		} else {
+			if (phba->fc_flag & FC_FABRIC)
+				fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+			else
+				fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+		}
+	} else
+		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
+
+	spin_unlock_irq(shost->host_lock);
+}
+
+static void
+lpfc_get_host_port_state(struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+
+	spin_lock_irq(shost->host_lock);
+
+	if (phba->fc_flag & FC_OFFLINE_MODE)
+		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+	else {
+		switch (phba->hba_state) {
+		case LPFC_INIT_START:
+		case LPFC_INIT_MBX_CMDS:
+		case LPFC_LINK_DOWN:
+			fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
+			break;
+		case LPFC_LINK_UP:
+		case LPFC_LOCAL_CFG_LINK:
+		case LPFC_FLOGI:
+		case LPFC_FABRIC_CFG_LINK:
+		case LPFC_NS_REG:
+		case LPFC_NS_QRY:
+		case LPFC_BUILD_DISC_LIST:
+		case LPFC_DISC_AUTH:
+		case LPFC_CLEAR_LA:
+		case LPFC_HBA_READY:
+			/* Links up, beyond this port_type reports state */
+			fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+			break;
+		case LPFC_HBA_ERROR:
+			fc_host_port_state(shost) = FC_PORTSTATE_ERROR;
+			break;
+		default:
+			fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+			break;
+		}
+	}
+
+	spin_unlock_irq(shost->host_lock);
+}
+
+static void
+lpfc_get_host_speed(struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+
+	spin_lock_irq(shost->host_lock);
+
+	if (phba->hba_state == LPFC_HBA_READY) {
+		switch(phba->fc_linkspeed) {
+			case LA_1GHZ_LINK:
+				fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+			break;
+			case LA_2GHZ_LINK:
+				fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
+			break;
+			case LA_4GHZ_LINK:
+				fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
+			break;
+			default:
+				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+			break;
+		}
+	}
+
+	spin_unlock_irq(shost->host_lock);
+}
+
+static void
+lpfc_get_host_fabric_name (struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+	u64 nodename;
+
+	spin_lock_irq(shost->host_lock);
+
+	if ((phba->fc_flag & FC_FABRIC) ||
+	    ((phba->fc_topology == TOPOLOGY_LOOP) &&
+	     (phba->fc_flag & FC_PUBLIC_LOOP)))
+		memcpy(&nodename, &phba->fc_fabparam.nodeName, sizeof(u64));
+	else
+		/* fabric is local port if there is no F/FL_Port */
+		memcpy(&nodename, &phba->fc_nodename, sizeof(u64));
+
+	spin_unlock_irq(shost->host_lock);
+
+	fc_host_fabric_name(shost) = be64_to_cpu(nodename);
+}
+
+
+static struct fc_host_statistics *
+lpfc_get_stats(struct Scsi_Host *shost)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
+	struct lpfc_sli *psli = &phba->sli;
+	struct fc_host_statistics *hs =
+			(struct fc_host_statistics *)phba->link_stats;
+	LPFC_MBOXQ_t *pmboxq;
+	MAILBOX_t *pmb;
+	int rc=0;
+
+	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmboxq)
+		return NULL;
+	memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+
+	pmb = &pmboxq->mb;
+	pmb->mbxCommand = MBX_READ_STATUS;
+	pmb->mbxOwner = OWN_HOST;
+	pmboxq->context1 = NULL;
+
+	if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE))){
+		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+	} else
+		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+	if (rc != MBX_SUCCESS) {
+		if (pmboxq) {
+			if (rc == MBX_TIMEOUT)
+				pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			else
+				mempool_free( pmboxq, phba->mbox_mem_pool);
+		}
+		return NULL;
+	}
+
+	hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt;
+	hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256);
+	hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt;
+	hs->rx_words = (pmb->un.varRdStatus.rcvByteCnt * 256);
+
+	memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+	pmb->mbxCommand = MBX_READ_LNK_STAT;
+	pmb->mbxOwner = OWN_HOST;
+	pmboxq->context1 = NULL;
+
+	if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) {
+		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+	} else
+		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+	if (rc != MBX_SUCCESS) {
+		if (pmboxq) {
+			if (rc == MBX_TIMEOUT)
+				pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			else
+				mempool_free( pmboxq, phba->mbox_mem_pool);
+		}
+		return NULL;
+	}
+
+	hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
+	hs->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt;
+	hs->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt;
+	hs->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt;
+	hs->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
+	hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
+	hs->error_frames = pmb->un.varRdLnk.crcCnt;
+
+	if (phba->fc_topology == TOPOLOGY_LOOP) {
+		hs->lip_count = (phba->fc_eventTag >> 1);
+		hs->nos_count = -1;
+	} else {
+		hs->lip_count = -1;
+		hs->nos_count = (phba->fc_eventTag >> 1);
+	}
+
+	hs->dumped_frames = -1;
+
+/* FIX ME */
+	/*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/
+
+	return hs;
+}
+
+
+/*
+ * The LPFC driver treats linkdown handling as target loss events so there
+ * are no sysfs handlers for link_down_tmo.
+ */
+static void
+lpfc_get_starget_port_id(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+	uint32_t did = -1;
+	struct lpfc_nodelist *ndlp = NULL;
+
+	spin_lock_irq(shost->host_lock);
+	/* Search the mapped list for this target ID */
+	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
+		if (starget->id == ndlp->nlp_sid) {
+			did = ndlp->nlp_DID;
+			break;
+		}
+	}
+	spin_unlock_irq(shost->host_lock);
+
+	fc_starget_port_id(starget) = did;
+}
+
+static void
+lpfc_get_starget_node_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+	uint64_t node_name = 0;
+	struct lpfc_nodelist *ndlp = NULL;
+
+	spin_lock_irq(shost->host_lock);
+	/* Search the mapped list for this target ID */
+	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
+		if (starget->id == ndlp->nlp_sid) {
+			memcpy(&node_name, &ndlp->nlp_nodename,
+						sizeof(struct lpfc_name));
+			break;
+		}
+	}
+	spin_unlock_irq(shost->host_lock);
+
+	fc_starget_node_name(starget) = be64_to_cpu(node_name);
+}
+
+static void
+lpfc_get_starget_port_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+	uint64_t port_name = 0;
+	struct lpfc_nodelist *ndlp = NULL;
+
+	spin_lock_irq(shost->host_lock);
+	/* Search the mapped list for this target ID */
+	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
+		if (starget->id == ndlp->nlp_sid) {
+			memcpy(&port_name, &ndlp->nlp_portname,
+						sizeof(struct lpfc_name));
+			break;
+		}
+	}
+	spin_unlock_irq(shost->host_lock);
+
+	fc_starget_port_name(starget) = be64_to_cpu(port_name);
+}
+
+static void
+lpfc_get_rport_loss_tmo(struct fc_rport *rport)
+{
+	/*
+	 * Return the driver's global value for device loss timeout plus
+	 * five seconds to allow the driver's nodev timer to run.
+	 */
+	rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+}
+
+static void
+lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	/*
+	 * The driver doesn't have a per-target timeout setting.  Set
+	 * this value globally. lpfc_nodev_tmo should be greater then 0.
+	 */
+	if (timeout)
+		lpfc_nodev_tmo = timeout;
+	else
+		lpfc_nodev_tmo = 1;
+	rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+}
+
+
+#define lpfc_rport_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+lpfc_show_rport_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	struct lpfc_rport_data *rdata = rport->hostdata;		\
+	return snprintf(buf, sz, format_string,				\
+		(rdata->target) ? cast rdata->target->field : 0);	\
+}
+
+#define lpfc_rport_rd_attr(field, format_string, sz)			\
+	lpfc_rport_show_function(field, format_string, sz, )		\
+static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL)
+
+
+struct fc_function_template lpfc_transport_functions = {
+	/* fixed attributes the driver supports */
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+	.show_host_supported_fc4s = 1,
+	.show_host_symbolic_name = 1,
+	.show_host_supported_speeds = 1,
+	.show_host_maxframe_size = 1,
+
+	/* dynamic attributes the driver supports */
+	.get_host_port_id = lpfc_get_host_port_id,
+	.show_host_port_id = 1,
+
+	.get_host_port_type = lpfc_get_host_port_type,
+	.show_host_port_type = 1,
+
+	.get_host_port_state = lpfc_get_host_port_state,
+	.show_host_port_state = 1,
+
+	/* active_fc4s is shown but doesn't change (thus no get function) */
+	.show_host_active_fc4s = 1,
+
+	.get_host_speed = lpfc_get_host_speed,
+	.show_host_speed = 1,
+
+	.get_host_fabric_name = lpfc_get_host_fabric_name,
+	.show_host_fabric_name = 1,
+
+	/*
+	 * The LPFC driver treats linkdown handling as target loss events
+	 * so there are no sysfs handlers for link_down_tmo.
+	 */
+
+	.get_fc_host_stats = lpfc_get_stats,
+
+	/* the LPFC driver doesn't support resetting stats yet */
+
+	.dd_fcrport_size = sizeof(struct lpfc_rport_data),
+	.show_rport_maxframe_size = 1,
+	.show_rport_supported_classes = 1,
+
+	.get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo,
+	.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+	.get_starget_port_id  = lpfc_get_starget_port_id,
+	.show_starget_port_id = 1,
+
+	.get_starget_node_name = lpfc_get_starget_node_name,
+	.show_starget_node_name = 1,
+
+	.get_starget_port_name = lpfc_get_starget_port_name,
+	.show_starget_port_name = 1,
+};
+
+void
+lpfc_get_cfgparam(struct lpfc_hba *phba)
+{
+	phba->cfg_log_verbose = lpfc_log_verbose;
+	phba->cfg_cr_delay = lpfc_cr_delay;
+	phba->cfg_cr_count = lpfc_cr_count;
+	phba->cfg_lun_queue_depth = lpfc_lun_queue_depth;
+	phba->cfg_fcp_class = lpfc_fcp_class;
+	phba->cfg_use_adisc = lpfc_use_adisc;
+	phba->cfg_ack0 = lpfc_ack0;
+	phba->cfg_topology = lpfc_topology;
+	phba->cfg_scan_down = lpfc_scan_down;
+	phba->cfg_nodev_tmo = lpfc_nodev_tmo;
+	phba->cfg_link_speed = lpfc_link_speed;
+	phba->cfg_fdmi_on = lpfc_fdmi_on;
+	phba->cfg_discovery_threads = lpfc_discovery_threads;
+	phba->cfg_max_luns = lpfc_max_luns;
+
+	/*
+	 * The total number of segments is the configuration value plus 2
+	 * since the IOCB need a command and response bde.
+	 */
+	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
+
+	/*
+	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+	 * used to create the sg_dma_buf_pool must be dynamically calculated
+	 */
+	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+			sizeof(struct fcp_rsp) +
+			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
+
+	switch (phba->pcidev->device) {
+	case PCI_DEVICE_ID_LP101:
+	case PCI_DEVICE_ID_BSMB:
+	case PCI_DEVICE_ID_ZSMB:
+		phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH;
+		break;
+	case PCI_DEVICE_ID_RFLY:
+	case PCI_DEVICE_ID_PFLY:
+	case PCI_DEVICE_ID_BMID:
+	case PCI_DEVICE_ID_ZMID:
+	case PCI_DEVICE_ID_TFLY:
+		phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH;
+		break;
+	default:
+		phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
+	}
+	return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_compat.h b/drivers/scsi/lpfc/lpfc_compat.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_compat.h
@@ -0,0 +1,97 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_compat.h 1.32 2005/01/25 17:51:45EST sf_support Exp  $
+ *
+ * This file provides macros to aid compilation in the Linux 2.4 kernel
+ * over various platform architectures.
+ */
+
+/*******************************************************************
+Note: HBA's SLI memory contains little-endian LW.
+Thus to access it from a little-endian host,
+memcpy_toio() and memcpy_fromio() can be used.
+However on a big-endian host, copy 4 bytes at a time,
+using writel() and readl().
+ *******************************************************************/
+
+#if __BIG_ENDIAN
+
+static inline void
+lpfc_memcpy_to_slim(void __iomem *dest, void *src, unsigned int bytes)
+{
+	uint32_t __iomem *dest32;
+	uint32_t *src32;
+	unsigned int four_bytes;
+
+
+	dest32  = (uint32_t __iomem *) dest;
+	src32  = (uint32_t *) src;
+
+	/* write input bytes, 4 bytes at a time */
+	for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) {
+		writel( *src32, dest32);
+		readl(dest32); /* flush */
+		dest32++;
+		src32++;
+	}
+
+	return;
+}
+
+static inline void
+lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes)
+{
+	uint32_t *dest32;
+	uint32_t __iomem *src32;
+	unsigned int four_bytes;
+
+
+	dest32  = (uint32_t *) dest;
+	src32  = (uint32_t __iomem *) src;
+
+	/* read input bytes, 4 bytes at a time */
+	for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) {
+		*dest32 = readl( src32);
+		dest32++;
+		src32++;
+	}
+
+	return;
+}
+
+#else
+
+static inline void
+lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes)
+{
+	/* actually returns 1 byte past dest */
+	memcpy_toio( dest, src, bytes);
+}
+
+static inline void
+lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes)
+{
+	/* actually returns 1 byte past dest */
+	memcpy_fromio( dest, src, bytes);
+}
+
+#endif	/* __BIG_ENDIAN */
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -0,0 +1,216 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_crtn.h 1.166 2005/04/07 08:46:47EDT sf_support Exp  $
+ */
+
+void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
+		 struct lpfc_dmabuf *mp);
+void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
+		   uint32_t);
+void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+
+
+int lpfc_linkdown(struct lpfc_hba *);
+void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+
+void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_nlp_plogi(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_nlp_adisc(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_nlp_unmapped(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_set_disctmo(struct lpfc_hba *);
+int lpfc_can_disctmo(struct lpfc_hba *);
+int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
+		    struct lpfc_iocbq *, struct lpfc_nodelist *);
+int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
+struct lpfc_nodelist *lpfc_setup_rscn_node(struct lpfc_hba *, uint32_t);
+void lpfc_disc_list_loopmap(struct lpfc_hba *);
+void lpfc_disc_start(struct lpfc_hba *);
+void lpfc_disc_flush_list(struct lpfc_hba *);
+void lpfc_disc_timeout(unsigned long);
+void lpfc_scan_timeout(unsigned long);
+
+struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
+struct lpfc_nodelist *lpfc_findnode_remove_rpi(struct lpfc_hba * phba,
+					       uint16_t rpi);
+void lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		      uint16_t rpi);
+
+int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
+int lpfc_do_work(void *);
+int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
+			    uint32_t);
+
+uint32_t lpfc_cmpl_prli_reglogin_issue(struct lpfc_hba *,
+				       struct lpfc_nodelist *, void *,
+				       uint32_t);
+uint32_t lpfc_cmpl_plogi_prli_issue(struct lpfc_hba *, struct lpfc_nodelist *,
+				    void *, uint32_t);
+
+int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
+		     struct serv_parm *, uint32_t);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
+			int);
+int lpfc_els_abort_flogi(struct lpfc_hba *);
+int lpfc_initial_flogi(struct lpfc_hba *);
+int lpfc_issue_els_plogi(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_scr(struct lpfc_hba *, uint32_t, uint8_t);
+int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+int lpfc_els_rsp_acc(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
+		     struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
+int lpfc_els_rsp_reject(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
+			struct lpfc_nodelist *);
+int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+			   struct lpfc_nodelist *);
+int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+			  struct lpfc_nodelist *);
+void lpfc_els_retry_delay(unsigned long);
+void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
+void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+			  struct lpfc_iocbq *);
+int lpfc_els_handle_rscn(struct lpfc_hba *);
+int lpfc_els_flush_rscn(struct lpfc_hba *);
+int lpfc_rscn_payload_check(struct lpfc_hba *, uint32_t);
+void lpfc_els_flush_cmd(struct lpfc_hba *);
+int lpfc_els_disc_adisc(struct lpfc_hba *);
+int lpfc_els_disc_plogi(struct lpfc_hba *);
+void lpfc_els_timeout(unsigned long);
+void lpfc_els_timeout_handler(struct lpfc_hba *);
+
+void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+			 struct lpfc_iocbq *);
+int lpfc_ns_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
+int lpfc_fdmi_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_fdmi_tmo(unsigned long);
+void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
+
+int lpfc_config_port_prep(struct lpfc_hba *);
+int lpfc_config_port_post(struct lpfc_hba *);
+int lpfc_hba_down_prep(struct lpfc_hba *);
+void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
+int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
+void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
+uint8_t *lpfc_get_lpfchba_info(struct lpfc_hba *, uint8_t *);
+int lpfc_fcp_abort(struct lpfc_hba *, int, int, int);
+int lpfc_online(struct lpfc_hba *);
+int lpfc_offline(struct lpfc_hba *);
+
+
+int lpfc_sli_setup(struct lpfc_hba *);
+int lpfc_sli_queue_setup(struct lpfc_hba *);
+void lpfc_slim_access(struct lpfc_hba *);
+
+void lpfc_handle_eratt(struct lpfc_hba *);
+void lpfc_handle_latt(struct lpfc_hba *);
+irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
+
+void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
+void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
+LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+
+int lpfc_mem_alloc(struct lpfc_hba *);
+void lpfc_mem_free(struct lpfc_hba *);
+
+int lpfc_sli_hba_setup(struct lpfc_hba *);
+int lpfc_sli_hba_down(struct lpfc_hba *);
+int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+int lpfc_sli_handle_mb_event(struct lpfc_hba *);
+int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
+				    struct lpfc_sli_ring *, uint32_t);
+void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
+			struct lpfc_iocbq *, uint32_t);
+void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
+int lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
+int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+			     struct lpfc_dmabuf *);
+struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
+					     struct lpfc_sli_ring *,
+					     dma_addr_t);
+int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
+				 struct lpfc_iocbq *);
+int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
+			  uint64_t, lpfc_ctx_cmd);
+int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
+			    uint64_t, uint32_t, lpfc_ctx_cmd);
+
+void lpfc_mbox_timeout(unsigned long);
+void lpfc_mbox_timeout_handler(struct lpfc_hba *);
+void lpfc_map_fcp_cmnd_to_bpl(struct lpfc_hba *, struct lpfc_scsi_buf *);
+void lpfc_free_scsi_cmd(struct lpfc_scsi_buf *);
+uint32_t lpfc_os_timeout_transform(struct lpfc_hba *, uint32_t);
+
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order,
+					uint32_t did);
+
+int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
+			 uint32_t timeout);
+
+int lpfc_sli_issue_iocb_wait_high_priority(struct lpfc_hba * phba,
+					   struct lpfc_sli_ring * pring,
+					   struct lpfc_iocbq * piocb,
+					   uint32_t flag,
+					   struct lpfc_iocbq * prspiocbq,
+					   uint32_t timeout);
+void lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba,
+				      struct lpfc_iocbq * queue1,
+				      struct lpfc_iocbq * queue2);
+
+void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
+
+/* Function prototypes. */
+const char* lpfc_info(struct Scsi_Host *);
+void lpfc_get_cfgparam(struct lpfc_hba *);
+int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
+void lpfc_free_sysfs_attr(struct lpfc_hba *);
+extern struct class_device_attribute *lpfc_host_attrs[];
+extern struct scsi_host_template lpfc_template;
+extern struct fc_function_template lpfc_transport_functions;
+
+void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
+
+#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
+#define HBA_EVENT_RSCN                   5
+#define HBA_EVENT_LINK_UP                2
+#define HBA_EVENT_LINK_DOWN              3
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -0,0 +1,1237 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_ct.c 1.161 2005/04/13 11:59:01EDT sf_support Exp  $
+ *
+ * Fibre Channel SCSI LAN Device Driver CT support
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_version.h"
+
+#define HBA_PORTSPEED_UNKNOWN               0	/* Unknown - transceiver
+						 * incapable of reporting */
+#define HBA_PORTSPEED_1GBIT                 1	/* 1 GBit/sec */
+#define HBA_PORTSPEED_2GBIT                 2	/* 2 GBit/sec */
+#define HBA_PORTSPEED_4GBIT                 8   /* 4 GBit/sec */
+#define HBA_PORTSPEED_8GBIT                16   /* 8 GBit/sec */
+#define HBA_PORTSPEED_10GBIT                4	/* 10 GBit/sec */
+#define HBA_PORTSPEED_NOT_NEGOTIATED        5	/* Speed not established */
+
+#define FOURBYTES	4
+
+
+static char *lpfc_release_version = LPFC_DRIVER_VERSION;
+
+/*
+ * lpfc_ct_unsol_event
+ */
+void
+lpfc_ct_unsol_event(struct lpfc_hba * phba,
+		    struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocbq)
+{
+
+	struct lpfc_iocbq *next_piocbq;
+	struct lpfc_dmabuf *pmbuf = NULL;
+	struct lpfc_dmabuf *matp, *next_matp;
+	uint32_t ctx = 0, size = 0, cnt = 0;
+	IOCB_t *icmd = &piocbq->iocb;
+	IOCB_t *save_icmd = icmd;
+	int i, go_exit = 0;
+	struct list_head head;
+
+	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+		/* Not enough posted buffers; Try posting more buffers */
+		phba->fc_stat.NoRcvBuf++;
+		lpfc_post_buffer(phba, pring, 0, 1);
+		return;
+	}
+
+	/* If there are no BDEs associated with this IOCB,
+	 * there is nothing to do.
+	 */
+	if (icmd->ulpBdeCount == 0)
+		return;
+
+	INIT_LIST_HEAD(&head);
+	list_add_tail(&head, &piocbq->list);
+
+	list_for_each_entry_safe(piocbq, next_piocbq, &head, list) {
+		icmd = &piocbq->iocb;
+		if (ctx == 0)
+			ctx = (uint32_t) (icmd->ulpContext);
+		if (icmd->ulpBdeCount == 0)
+			continue;
+
+		for (i = 0; i < icmd->ulpBdeCount; i++) {
+			matp = lpfc_sli_ringpostbuf_get(phba, pring,
+							getPaddr(icmd->un.
+								 cont64[i].
+								 addrHigh,
+								 icmd->un.
+								 cont64[i].
+								 addrLow));
+			if (!matp) {
+				/* Insert lpfc log message here */
+				lpfc_post_buffer(phba, pring, cnt, 1);
+				go_exit = 1;
+				goto ct_unsol_event_exit_piocbq;
+			}
+
+			/* Typically for Unsolicited CT requests */
+			if (!pmbuf) {
+				pmbuf = matp;
+				INIT_LIST_HEAD(&pmbuf->list);
+			} else
+				list_add_tail(&matp->list, &pmbuf->list);
+
+			size += icmd->un.cont64[i].tus.f.bdeSize;
+			cnt++;
+		}
+
+		icmd->ulpBdeCount = 0;
+	}
+
+	lpfc_post_buffer(phba, pring, cnt, 1);
+	if (save_icmd->ulpStatus) {
+		go_exit = 1;
+	}
+
+ct_unsol_event_exit_piocbq:
+	if (pmbuf) {
+		list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
+			lpfc_mbuf_free(phba, matp->virt, matp->phys);
+			list_del(&matp->list);
+			kfree(matp);
+		}
+		lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys);
+		kfree(pmbuf);
+	}
+	return;
+}
+
+static void
+lpfc_free_ct_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mlist)
+{
+	struct lpfc_dmabuf *mlast, *next_mlast;
+
+	list_for_each_entry_safe(mlast, next_mlast, &mlist->list, list) {
+		lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
+		list_del(&mlast->list);
+		kfree(mlast);
+	}
+	lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
+	kfree(mlist);
+	return;
+}
+
+static struct lpfc_dmabuf *
+lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
+		  uint32_t size, int *entries)
+{
+	struct lpfc_dmabuf *mlist = NULL;
+	struct lpfc_dmabuf *mp;
+	int cnt, i = 0;
+
+	/* We get chucks of FCELSSIZE */
+	cnt = size > FCELSSIZE ? FCELSSIZE: size;
+
+	while (size) {
+		/* Allocate buffer for rsp payload */
+		mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+		if (!mp) {
+			if (mlist)
+				lpfc_free_ct_rsp(phba, mlist);
+			return NULL;
+		}
+
+		INIT_LIST_HEAD(&mp->list);
+
+		if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT))
+			mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
+		else
+			mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
+
+		if (!mp->virt) {
+			kfree(mp);
+			lpfc_free_ct_rsp(phba, mlist);
+			return NULL;
+		}
+
+		/* Queue it to a linked list */
+		if (!mlist)
+			mlist = mp;
+		else
+			list_add_tail(&mp->list, &mlist->list);
+
+		bpl->tus.f.bdeFlags = BUFF_USE_RCV;
+		/* build buffer ptr list for IOCB */
+		bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+		bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+		bpl->tus.f.bdeSize = (uint16_t) cnt;
+		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+		bpl++;
+
+		i++;
+		size -= cnt;
+	}
+
+	*entries = i;
+	return mlist;
+}
+
+static int
+lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
+	     struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
+	     void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+		     struct lpfc_iocbq *),
+	     struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
+	     uint32_t tmo)
+{
+
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	IOCB_t *icmd;
+	struct lpfc_iocbq *geniocb = NULL;
+
+	/* Allocate buffer for  command iocb */
+	spin_lock_irq(phba->host->host_lock);
+	list_remove_head(lpfc_iocb_list, geniocb, struct lpfc_iocbq, list);
+	spin_unlock_irq(phba->host->host_lock);
+
+	if (geniocb == NULL)
+		return 1;
+	memset(geniocb, 0, sizeof (struct lpfc_iocbq));
+
+	icmd = &geniocb->iocb;
+	icmd->un.genreq64.bdl.ulpIoTag32 = 0;
+	icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
+	icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
+	icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
+	icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+
+	if (usr_flg)
+		geniocb->context3 = NULL;
+	else
+		geniocb->context3 = (uint8_t *) bmp;
+
+	/* Save for completion so we can release these resources */
+	geniocb->context1 = (uint8_t *) inp;
+	geniocb->context2 = (uint8_t *) outp;
+
+	/* Fill in payload, bp points to frame payload */
+	icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
+
+	/* Fill in rest of iocb */
+	icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
+	icmd->un.genreq64.w5.hcsw.Dfctl = 0;
+	icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
+	icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+
+	if (!tmo)
+		tmo = (2 * phba->fc_ratov) + 1;
+	icmd->ulpTimeout = tmo;
+	icmd->ulpBdeCount = 1;
+	icmd->ulpLe = 1;
+	icmd->ulpClass = CLASS3;
+	icmd->ulpContext = ndlp->nlp_rpi;
+
+	/* Issue GEN REQ IOCB for NPORT <did> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0119 Issue GEN REQ IOCB for NPORT x%x "
+			"Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5],
+			icmd->ulpIoTag, phba->hba_state);
+	geniocb->iocb_cmpl = cmpl;
+	geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
+	spin_lock_irq(phba->host->host_lock);
+	if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) {
+		list_add_tail(&geniocb->list, lpfc_iocb_list);
+		spin_unlock_irq(phba->host->host_lock);
+		return 1;
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	return 0;
+}
+
+static int
+lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp,
+	    struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
+	    void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+			  struct lpfc_iocbq *),
+	    uint32_t rsp_size)
+{
+	struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
+	struct lpfc_dmabuf *outmp;
+	int cnt = 0, status;
+	int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)->
+		CommandResponse.bits.CmdRsp;
+
+	bpl++;			/* Skip past ct request */
+
+	/* Put buffer(s) for ct rsp in bpl */
+	outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt);
+	if (!outmp)
+		return -ENOMEM;
+
+	status = lpfc_gen_req(phba, bmp, inmp, outmp, cmpl, ndlp, 0,
+			      cnt+1, 0);
+	if (status) {
+		lpfc_free_ct_rsp(phba, outmp);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int
+lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
+{
+	struct lpfc_sli_ct_request *Response =
+		(struct lpfc_sli_ct_request *) mp->virt;
+	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_dmabuf *mlast, *next_mp;
+	uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
+	uint32_t Did;
+	uint32_t CTentry;
+	int Cnt;
+	struct list_head head;
+
+	lpfc_set_disctmo(phba);
+
+	Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
+
+	list_add_tail(&head, &mp->list);
+	list_for_each_entry_safe(mp, next_mp, &head, list) {
+		mlast = mp;
+
+		Size -= Cnt;
+
+		if (!ctptr)
+			ctptr = (uint32_t *) mlast->virt;
+		else
+			Cnt -= 16;	/* subtract length of CT header */
+
+		/* Loop through entire NameServer list of DIDs */
+		while (Cnt) {
+
+			/* Get next DID from NameServer List */
+			CTentry = *ctptr++;
+			Did = ((be32_to_cpu(CTentry)) & Mask_DID);
+
+			ndlp = NULL;
+			if (Did != phba->fc_myDID) {
+				/* Check for rscn processing or not */
+				ndlp = lpfc_setup_disc_node(phba, Did);
+			}
+			/* Mark all node table entries that are in the
+			   Nameserver */
+			if (ndlp) {
+				/* NameServer Rsp */
+				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+						"%d:0238 Process x%x NameServer"
+						" Rsp Data: x%x x%x x%x\n",
+						phba->brd_no,
+						Did, ndlp->nlp_flag,
+						phba->fc_flag,
+						phba->fc_rscn_id_cnt);
+			} else {
+				/* NameServer Rsp */
+				lpfc_printf_log(phba,
+						KERN_INFO,
+						LOG_DISCOVERY,
+						"%d:0239 Skip x%x NameServer "
+						"Rsp Data: x%x x%x x%x\n",
+						phba->brd_no,
+						Did, Size, phba->fc_flag,
+						phba->fc_rscn_id_cnt);
+			}
+
+			if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY)))
+				goto nsout1;
+			Cnt -= sizeof (uint32_t);
+		}
+		ctptr = NULL;
+
+	}
+
+nsout1:
+	list_del(&head);
+
+	/* Here we are finished in the case RSCN */
+	if (phba->hba_state == LPFC_HBA_READY) {
+		lpfc_els_flush_rscn(phba);
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	return 0;
+}
+
+
+
+
+static void
+lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_sli *psli;
+	struct lpfc_dmabuf *bmp;
+	struct lpfc_dmabuf *inp;
+	struct lpfc_dmabuf *outp;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_sli_ct_request *CTrsp;
+
+	psli = &phba->sli;
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+	bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
+
+	irsp = &rspiocb->iocb;
+	if (irsp->ulpStatus) {
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
+			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) {
+			goto out;
+		}
+
+		/* Check for retry */
+		if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+			phba->fc_ns_retry++;
+			/* CT command is being retried */
+			ndlp =
+			    lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
+					      NameServer_DID);
+			if (ndlp) {
+				if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
+				    0) {
+					goto out;
+				}
+			}
+		}
+	} else {
+		/* Good status, continue checking */
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
+			lpfc_ns_rsp(phba, outp,
+				    (uint32_t) (irsp->un.genreq64.bdl.bdeSize));
+		} else if (CTrsp->CommandResponse.bits.CmdRsp ==
+			   be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
+			/* NameServer Rsp Error */
+			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+					"%d:0240 NameServer Rsp Error "
+					"Data: x%x x%x x%x x%x\n",
+					phba->brd_no,
+					CTrsp->CommandResponse.bits.CmdRsp,
+					(uint32_t) CTrsp->ReasonCode,
+					(uint32_t) CTrsp->Explanation,
+					phba->fc_flag);
+		} else {
+			/* NameServer Rsp Error */
+			lpfc_printf_log(phba,
+					KERN_INFO,
+					LOG_DISCOVERY,
+					"%d:0241 NameServer Rsp Error "
+					"Data: x%x x%x x%x x%x\n",
+					phba->brd_no,
+					CTrsp->CommandResponse.bits.CmdRsp,
+					(uint32_t) CTrsp->ReasonCode,
+					(uint32_t) CTrsp->Explanation,
+					phba->fc_flag);
+		}
+	}
+	/* Link up / RSCN discovery */
+	lpfc_disc_start(phba);
+out:
+	lpfc_free_ct_rsp(phba, outp);
+	lpfc_mbuf_free(phba, inp->virt, inp->phys);
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+	kfree(inp);
+	kfree(bmp);
+	spin_lock_irq(phba->host->host_lock);
+	list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			struct lpfc_iocbq * rspiocb)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_dmabuf *bmp;
+	struct lpfc_dmabuf *inp;
+	struct lpfc_dmabuf *outp;
+	IOCB_t *irsp;
+	struct lpfc_sli_ct_request *CTrsp;
+
+	psli = &phba->sli;
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+	bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
+	irsp = &rspiocb->iocb;
+
+	CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+
+	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0209 RFT request completes ulpStatus x%x "
+			"CmdRsp x%x\n", phba->brd_no, irsp->ulpStatus,
+			CTrsp->CommandResponse.bits.CmdRsp);
+
+	lpfc_free_ct_rsp(phba, outp);
+	lpfc_mbuf_free(phba, inp->virt, inp->phys);
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+	kfree(inp);
+	kfree(bmp);
+	spin_lock_irq(phba->host->host_lock);
+	list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			struct lpfc_iocbq * rspiocb)
+{
+	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+	return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			 struct lpfc_iocbq * rspiocb)
+{
+	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+	return;
+}
+
+void
+lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
+{
+	char fwrev[16];
+
+	lpfc_decode_firmware_rev(phba, fwrev, 0);
+
+	if (phba->Port[0]) {
+		sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName,
+			phba->Port, fwrev, lpfc_release_version);
+	} else {
+		sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
+			fwrev, lpfc_release_version);
+	}
+}
+
+/*
+ * lpfc_ns_cmd
+ * Description:
+ *    Issue Cmd to NameServer
+ *       SLI_CTNS_GID_FT
+ *       LI_CTNS_RFT_ID
+ */
+int
+lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+{
+	struct lpfc_dmabuf *mp, *bmp;
+	struct lpfc_sli_ct_request *CtReq;
+	struct ulp_bde64 *bpl;
+	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+		      struct lpfc_iocbq *) = NULL;
+	uint32_t rsp_size = 1024;
+
+	/* fill in BDEs for command */
+	/* Allocate buffer for command payload */
+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (!mp)
+		goto ns_cmd_exit;
+
+	INIT_LIST_HEAD(&mp->list);
+	mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
+	if (!mp->virt)
+		goto ns_cmd_free_mp;
+
+	/* Allocate buffer for Buffer ptr list */
+	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (!bmp)
+		goto ns_cmd_free_mpvirt;
+
+	INIT_LIST_HEAD(&bmp->list);
+	bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
+	if (!bmp->virt)
+		goto ns_cmd_free_bmp;
+
+	/* NameServer Req */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_DISCOVERY,
+			"%d:0236 NameServer Req Data: x%x x%x x%x\n",
+			phba->brd_no, cmdcode, phba->fc_flag,
+			phba->fc_rscn_id_cnt);
+
+	bpl = (struct ulp_bde64 *) bmp->virt;
+	memset(bpl, 0, sizeof(struct ulp_bde64));
+	bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+	bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+	bpl->tus.f.bdeFlags = 0;
+	if (cmdcode == SLI_CTNS_GID_FT)
+		bpl->tus.f.bdeSize = GID_REQUEST_SZ;
+	else if (cmdcode == SLI_CTNS_RFT_ID)
+		bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
+	else if (cmdcode == SLI_CTNS_RNN_ID)
+		bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
+	else if (cmdcode == SLI_CTNS_RSNN_NN)
+		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+	else
+		bpl->tus.f.bdeSize = 0;
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
+	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
+	memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+	CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
+	CtReq->RevisionId.bits.InId = 0;
+	CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
+	CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER;
+	CtReq->CommandResponse.bits.Size = 0;
+	switch (cmdcode) {
+	case SLI_CTNS_GID_FT:
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_GID_FT);
+		CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
+		if (phba->hba_state < LPFC_HBA_READY)
+			phba->hba_state = LPFC_NS_QRY;
+		lpfc_set_disctmo(phba);
+		cmpl = lpfc_cmpl_ct_cmd_gid_ft;
+		rsp_size = FC_MAX_NS_RSP;
+		break;
+
+	case SLI_CTNS_RFT_ID:
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_RFT_ID);
+		CtReq->un.rft.PortId = be32_to_cpu(phba->fc_myDID);
+		CtReq->un.rft.fcpReg = 1;
+		cmpl = lpfc_cmpl_ct_cmd_rft_id;
+		break;
+
+	case SLI_CTNS_RNN_ID:
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_RNN_ID);
+		CtReq->un.rnn.PortId = be32_to_cpu(phba->fc_myDID);
+		memcpy(CtReq->un.rnn.wwnn,  &phba->fc_nodename,
+		       sizeof (struct lpfc_name));
+		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
+		break;
+
+	case SLI_CTNS_RSNN_NN:
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_RSNN_NN);
+		memcpy(CtReq->un.rsnn.wwnn, &phba->fc_nodename,
+		       sizeof (struct lpfc_name));
+		lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname);
+		CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname);
+		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
+		break;
+	}
+
+	if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, rsp_size))
+		/* On success, The cmpl function will free the buffers */
+		return 0;
+
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ns_cmd_free_bmp:
+	kfree(bmp);
+ns_cmd_free_mpvirt:
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ns_cmd_free_mp:
+	kfree(mp);
+ns_cmd_exit:
+	return 1;
+}
+
+static void
+lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
+		      struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+{
+	struct lpfc_dmabuf *bmp = cmdiocb->context3;
+	struct lpfc_dmabuf *inp = cmdiocb->context1;
+	struct lpfc_dmabuf *outp = cmdiocb->context2;
+	struct lpfc_sli_ct_request *CTrsp = outp->virt;
+	struct lpfc_sli_ct_request *CTcmd = inp->virt;
+	struct lpfc_nodelist *ndlp;
+	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
+	uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
+
+	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
+		/* FDMI rsp failed */
+		lpfc_printf_log(phba,
+			        KERN_INFO,
+			        LOG_DISCOVERY,
+			        "%d:0220 FDMI rsp failed Data: x%x\n",
+			        phba->brd_no,
+			       be16_to_cpu(fdmi_cmd));
+	}
+
+	switch (be16_to_cpu(fdmi_cmd)) {
+	case SLI_MGMT_RHBA:
+		lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RPA);
+		break;
+
+	case SLI_MGMT_RPA:
+		break;
+
+	case SLI_MGMT_DHBA:
+		lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DPRT);
+		break;
+
+	case SLI_MGMT_DPRT:
+		lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RHBA);
+		break;
+	}
+
+	lpfc_free_ct_rsp(phba, outp);
+	lpfc_mbuf_free(phba, inp->virt, inp->phys);
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+	kfree(inp);
+	kfree(bmp);
+	spin_lock_irq(phba->host->host_lock);
+	list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+int
+lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+{
+	struct lpfc_dmabuf *mp, *bmp;
+	struct lpfc_sli_ct_request *CtReq;
+	struct ulp_bde64 *bpl;
+	uint32_t size;
+	REG_HBA *rh;
+	PORT_ENTRY *pe;
+	REG_PORT_ATTRIBUTE *pab;
+	ATTRIBUTE_BLOCK *ab;
+	ATTRIBUTE_ENTRY *ae;
+	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+		      struct lpfc_iocbq *);
+
+
+	/* fill in BDEs for command */
+	/* Allocate buffer for command payload */
+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (!mp)
+		goto fdmi_cmd_exit;
+
+	mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
+	if (!mp->virt)
+		goto fdmi_cmd_free_mp;
+
+	/* Allocate buffer for Buffer ptr list */
+	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (!bmp)
+		goto fdmi_cmd_free_mpvirt;
+
+	bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys));
+	if (!bmp->virt)
+		goto fdmi_cmd_free_bmp;
+
+	INIT_LIST_HEAD(&mp->list);
+	INIT_LIST_HEAD(&bmp->list);
+
+	/* FDMI request */
+	lpfc_printf_log(phba,
+		        KERN_INFO,
+		        LOG_DISCOVERY,
+		        "%d:0218 FDMI Request Data: x%x x%x x%x\n",
+		        phba->brd_no,
+		       phba->fc_flag, phba->hba_state, cmdcode);
+
+	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
+
+	memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
+	CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
+	CtReq->RevisionId.bits.InId = 0;
+
+	CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE;
+	CtReq->FsSubType = SLI_CT_FDMI_Subtypes;
+	size = 0;
+
+	switch (cmdcode) {
+	case SLI_MGMT_RHBA:
+		{
+			lpfc_vpd_t *vp = &phba->vpd;
+			uint32_t i, j, incr;
+			int len;
+
+			CtReq->CommandResponse.bits.CmdRsp =
+			    be16_to_cpu(SLI_MGMT_RHBA);
+			CtReq->CommandResponse.bits.Size = 0;
+			rh = (REG_HBA *) & CtReq->un.PortID;
+			memcpy(&rh->hi.PortName, &phba->fc_sparam.portName,
+			       sizeof (struct lpfc_name));
+			/* One entry (port) per adapter */
+			rh->rpl.EntryCnt = be32_to_cpu(1);
+			memcpy(&rh->rpl.pe, &phba->fc_sparam.portName,
+			       sizeof (struct lpfc_name));
+
+			/* point to the HBA attribute block */
+			size = 2 * sizeof (struct lpfc_name) + FOURBYTES;
+			ab = (ATTRIBUTE_BLOCK *) ((uint8_t *) rh + size);
+			ab->EntryCnt = 0;
+
+			/* Point to the beginning of the first HBA attribute
+			   entry */
+			/* #1 HBA attribute entry */
+			size += FOURBYTES;
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME);
+			ae->ad.bits.AttrLen =  be16_to_cpu(FOURBYTES
+						+ sizeof (struct lpfc_name));
+			memcpy(&ae->un.NodeName, &phba->fc_sparam.nodeName,
+			       sizeof (struct lpfc_name));
+			ab->EntryCnt++;
+			size += FOURBYTES + sizeof (struct lpfc_name);
+
+			/* #2 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(MANUFACTURER);
+			strcpy(ae->un.Manufacturer, "Emulex Corporation");
+			len = strlen(ae->un.Manufacturer);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #3 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(SERIAL_NUMBER);
+			strcpy(ae->un.SerialNumber, phba->SerialNumber);
+			len = strlen(ae->un.SerialNumber);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #4 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(MODEL);
+			strcpy(ae->un.Model, phba->ModelName);
+			len = strlen(ae->un.Model);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #5 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(MODEL_DESCRIPTION);
+			strcpy(ae->un.ModelDescription, phba->ModelDesc);
+			len = strlen(ae->un.ModelDescription);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #6 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(HARDWARE_VERSION);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 8);
+			/* Convert JEDEC ID to ascii for hardware version */
+			incr = vp->rev.biuRev;
+			for (i = 0; i < 8; i++) {
+				j = (incr & 0xf);
+				if (j <= 9)
+					ae->un.HardwareVersion[7 - i] =
+					    (char)((uint8_t) 0x30 +
+						   (uint8_t) j);
+				else
+					ae->un.HardwareVersion[7 - i] =
+					    (char)((uint8_t) 0x61 +
+						   (uint8_t) (j - 10));
+				incr = (incr >> 4);
+			}
+			ab->EntryCnt++;
+			size += FOURBYTES + 8;
+
+			/* #7 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(DRIVER_VERSION);
+			strcpy(ae->un.DriverVersion, lpfc_release_version);
+			len = strlen(ae->un.DriverVersion);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #8 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(OPTION_ROM_VERSION);
+			strcpy(ae->un.OptionROMVersion, phba->OptionROMVersion);
+			len = strlen(ae->un.OptionROMVersion);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #9 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(FIRMWARE_VERSION);
+			lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
+				1);
+			len = strlen(ae->un.FirmwareVersion);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #10 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
+			sprintf(ae->un.OsNameVersion, "%s %s %s",
+				system_utsname.sysname, system_utsname.release,
+				system_utsname.version);
+			len = strlen(ae->un.OsNameVersion);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			ab->EntryCnt++;
+			size += FOURBYTES + len;
+
+			/* #11 HBA attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+			ae->ad.bits.AttrType = be16_to_cpu(MAX_CT_PAYLOAD_LEN);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
+			ae->un.MaxCTPayloadLen = (65 * 4096);
+			ab->EntryCnt++;
+			size += FOURBYTES + 4;
+
+			ab->EntryCnt = be32_to_cpu(ab->EntryCnt);
+			/* Total size */
+			size = GID_REQUEST_SZ - 4 + size;
+		}
+		break;
+
+	case SLI_MGMT_RPA:
+		{
+			lpfc_vpd_t *vp;
+			struct serv_parm *hsp;
+			int len;
+
+			vp = &phba->vpd;
+
+			CtReq->CommandResponse.bits.CmdRsp =
+			    be16_to_cpu(SLI_MGMT_RPA);
+			CtReq->CommandResponse.bits.Size = 0;
+			pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID;
+			size = sizeof (struct lpfc_name) + FOURBYTES;
+			memcpy((uint8_t *) & pab->PortName,
+			       (uint8_t *) & phba->fc_sparam.portName,
+			       sizeof (struct lpfc_name));
+			pab->ab.EntryCnt = 0;
+
+			/* #1 Port attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
+			ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_FC4_TYPES);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 32);
+			ae->un.SupportFC4Types[2] = 1;
+			ae->un.SupportFC4Types[7] = 1;
+			pab->ab.EntryCnt++;
+			size += FOURBYTES + 32;
+
+			/* #2 Port attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
+			ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
+			if (FC_JEDEC_ID(vp->rev.biuRev) == VIPER_JEDEC_ID)
+				ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
+			else if (FC_JEDEC_ID(vp->rev.biuRev) == HELIOS_JEDEC_ID)
+				ae->un.SupportSpeed = HBA_PORTSPEED_4GBIT;
+			else if ((FC_JEDEC_ID(vp->rev.biuRev) ==
+				  CENTAUR_2G_JEDEC_ID)
+				 || (FC_JEDEC_ID(vp->rev.biuRev) ==
+				     PEGASUS_JEDEC_ID)
+				 || (FC_JEDEC_ID(vp->rev.biuRev) ==
+				     THOR_JEDEC_ID))
+				ae->un.SupportSpeed = HBA_PORTSPEED_2GBIT;
+			else
+				ae->un.SupportSpeed = HBA_PORTSPEED_1GBIT;
+			pab->ab.EntryCnt++;
+			size += FOURBYTES + 4;
+
+			/* #3 Port attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
+			ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
+			switch(phba->fc_linkspeed) {
+				case LA_1GHZ_LINK:
+					ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
+				break;
+				case LA_2GHZ_LINK:
+					ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
+				break;
+				case LA_4GHZ_LINK:
+					ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
+				break;
+				default:
+					ae->un.PortSpeed =
+						HBA_PORTSPEED_UNKNOWN;
+				break;
+			}
+			pab->ab.EntryCnt++;
+			size += FOURBYTES + 4;
+
+			/* #4 Port attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
+			ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE);
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
+			hsp = (struct serv_parm *) & phba->fc_sparam;
+			ae->un.MaxFrameSize =
+			    (((uint32_t) hsp->cmn.
+			      bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn.
+			    bbRcvSizeLsb;
+			pab->ab.EntryCnt++;
+			size += FOURBYTES + 4;
+
+			/* #5 Port attribute entry */
+			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
+			ae->ad.bits.AttrType = be16_to_cpu(OS_DEVICE_NAME);
+			strcpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME);
+			len = strlen((char *)ae->un.OsDeviceName);
+			len += (len & 3) ? (4 - (len & 3)) : 4;
+			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+			pab->ab.EntryCnt++;
+			size += FOURBYTES + len;
+
+			if (phba->cfg_fdmi_on == 2) {
+				/* #6 Port attribute entry */
+				ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab +
+							  size);
+				ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME);
+				sprintf(ae->un.HostName, "%s",
+					system_utsname.nodename);
+				len = strlen(ae->un.HostName);
+				len += (len & 3) ? (4 - (len & 3)) : 4;
+				ae->ad.bits.AttrLen =
+				    be16_to_cpu(FOURBYTES + len);
+				pab->ab.EntryCnt++;
+				size += FOURBYTES + len;
+			}
+
+			pab->ab.EntryCnt = be32_to_cpu(pab->ab.EntryCnt);
+			/* Total size */
+			size = GID_REQUEST_SZ - 4 + size;
+		}
+		break;
+
+	case SLI_MGMT_DHBA:
+		CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DHBA);
+		CtReq->CommandResponse.bits.Size = 0;
+		pe = (PORT_ENTRY *) & CtReq->un.PortID;
+		memcpy((uint8_t *) & pe->PortName,
+		       (uint8_t *) & phba->fc_sparam.portName,
+		       sizeof (struct lpfc_name));
+		size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
+		break;
+
+	case SLI_MGMT_DPRT:
+		CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DPRT);
+		CtReq->CommandResponse.bits.Size = 0;
+		pe = (PORT_ENTRY *) & CtReq->un.PortID;
+		memcpy((uint8_t *) & pe->PortName,
+		       (uint8_t *) & phba->fc_sparam.portName,
+		       sizeof (struct lpfc_name));
+		size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
+		break;
+	}
+
+	bpl = (struct ulp_bde64 *) bmp->virt;
+	bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+	bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+	bpl->tus.f.bdeFlags = 0;
+	bpl->tus.f.bdeSize = size;
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
+	cmpl = lpfc_cmpl_ct_cmd_fdmi;
+
+	if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP))
+		return 0;
+
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+fdmi_cmd_free_bmp:
+	kfree(bmp);
+fdmi_cmd_free_mpvirt:
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+fdmi_cmd_free_mp:
+	kfree(mp);
+fdmi_cmd_exit:
+	/* Issue FDMI request failed */
+	lpfc_printf_log(phba,
+		        KERN_INFO,
+		        LOG_DISCOVERY,
+		        "%d:0244 Issue FDMI request failed Data: x%x\n",
+		        phba->brd_no,
+			cmdcode);
+	return 1;
+}
+
+void
+lpfc_fdmi_tmo(unsigned long ptr)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+	unsigned long iflag;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	if (!(phba->work_hba_events & WORKER_FDMI_TMO)) {
+		phba->work_hba_events |= WORKER_FDMI_TMO;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+	}
+	spin_unlock_irqrestore(phba->host->host_lock,iflag);
+}
+
+void
+lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
+{
+	struct lpfc_nodelist *ndlp;
+
+	spin_lock_irq(phba->host->host_lock);
+	if (!(phba->work_hba_events & WORKER_FDMI_TMO)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return;
+	}
+	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+	if (ndlp) {
+		if (system_utsname.nodename[0] != '\0') {
+			lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
+		} else {
+			mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
+		}
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+
+
+void
+lpfc_decode_firmware_rev(struct lpfc_hba * phba, char *fwrevision, int flag)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	lpfc_vpd_t *vp = &phba->vpd;
+	uint32_t b1, b2, b3, b4, i, rev;
+	char c;
+	uint32_t *ptr, str[4];
+	uint8_t *fwname;
+
+	if (vp->rev.rBit) {
+		if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+			rev = vp->rev.sli2FwRev;
+		else
+			rev = vp->rev.sli1FwRev;
+
+		b1 = (rev & 0x0000f000) >> 12;
+		b2 = (rev & 0x00000f00) >> 8;
+		b3 = (rev & 0x000000c0) >> 6;
+		b4 = (rev & 0x00000030) >> 4;
+
+		switch (b4) {
+		case 0:
+			c = 'N';
+			break;
+		case 1:
+			c = 'A';
+			break;
+		case 2:
+			c = 'B';
+			break;
+		default:
+			c = 0;
+			break;
+		}
+		b4 = (rev & 0x0000000f);
+
+		if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+			fwname = vp->rev.sli2FwName;
+		else
+			fwname = vp->rev.sli1FwName;
+
+		for (i = 0; i < 16; i++)
+			if (fwname[i] == 0x20)
+				fwname[i] = 0;
+
+		ptr = (uint32_t*)fwname;
+
+		for (i = 0; i < 3; i++)
+			str[i] = be32_to_cpu(*ptr++);
+
+		if (c == 0) {
+			if (flag)
+				sprintf(fwrevision, "%d.%d%d (%s)",
+					b1, b2, b3, (char *)str);
+			else
+				sprintf(fwrevision, "%d.%d%d", b1,
+					b2, b3);
+		} else {
+			if (flag)
+				sprintf(fwrevision, "%d.%d%d%c%d (%s)",
+					b1, b2, b3, c,
+					b4, (char *)str);
+			else
+				sprintf(fwrevision, "%d.%d%d%c%d",
+					b1, b2, b3, c, b4);
+		}
+	} else {
+		rev = vp->rev.smFwRev;
+
+		b1 = (rev & 0xff000000) >> 24;
+		b2 = (rev & 0x00f00000) >> 20;
+		b3 = (rev & 0x000f0000) >> 16;
+		c  = (rev & 0x0000ff00) >> 8;
+		b4 = (rev & 0x000000ff);
+
+		if (flag)
+			sprintf(fwrevision, "%d.%d%d%c%d ", b1,
+				b2, b3, c, b4);
+		else
+			sprintf(fwrevision, "%d.%d%d%c%d ", b1,
+				b2, b3, c, b4);
+	}
+	return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -0,0 +1,206 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_disc.h 1.61 2005/04/07 08:46:52EDT sf_support Exp  $
+ */
+
+#define FC_MAX_HOLD_RSCN     32	      /* max number of deferred RSCNs */
+#define FC_MAX_NS_RSP        65536    /* max size NameServer rsp */
+#define FC_MAXLOOP           126      /* max devices supported on a fc loop */
+#define LPFC_DISC_FLOGI_TMO  10	      /* Discovery FLOGI ratov */
+
+
+/* This is the protocol dependent definition for a Node List Entry.
+ * This is used by Fibre Channel protocol to support FCP.
+ */
+
+/* structure used to queue event to the discovery tasklet */
+struct lpfc_work_evt {
+	struct list_head      evt_listp;
+	void                * evt_arg1;
+	void                * evt_arg2;
+	uint32_t              evt;
+};
+
+#define LPFC_EVT_NODEV_TMO	0x1
+#define LPFC_EVT_ONLINE		0x2
+#define LPFC_EVT_OFFLINE	0x3
+#define LPFC_EVT_ELS_RETRY	0x4
+
+struct lpfc_nodelist {
+	struct list_head nlp_listp;
+	struct lpfc_name nlp_portname;		/* port name */
+	struct lpfc_name nlp_nodename;		/* node name */
+	uint32_t         nlp_flag;		/* entry  flags */
+	uint32_t         nlp_DID;		/* FC D_ID of entry */
+	uint32_t         nlp_last_elscmd;	/* Last ELS cmd sent */
+	uint16_t         nlp_type;
+#define NLP_FC_NODE        0x1			/* entry is an FC node */
+#define NLP_FABRIC         0x4			/* entry rep a Fabric entity */
+#define NLP_FCP_TARGET     0x8			/* entry is an FCP target */
+#define NLP_FCP_INITIATOR  0x10			/* entry is an FCP Initiator */
+
+	uint16_t        nlp_rpi;
+	uint16_t        nlp_state;		/* state transition indicator */
+	uint16_t        nlp_xri;		/* output exchange id for RPI */
+	uint16_t        nlp_sid;		/* scsi id */
+#define NLP_NO_SID		0xffff
+	uint16_t	nlp_maxframe;		/* Max RCV frame size */
+	uint8_t		nlp_class_sup;		/* Supported Classes */
+	uint8_t         nlp_retry;		/* used for ELS retries */
+	uint8_t         nlp_disc_refcnt;	/* used for DSM */
+	uint8_t         nlp_fcp_info;	        /* class info, bits 0-3 */
+#define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */
+
+	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */
+	struct timer_list   nlp_tmofunc;	/* Used for nodev tmo */
+	struct fc_rport *rport;			/* Corresponding FC transport
+						   port structure */
+	struct lpfc_nodelist *nlp_rpi_hash_next;
+	struct lpfc_hba      *nlp_phba;
+	struct lpfc_work_evt nodev_timeout_evt;
+	struct lpfc_work_evt els_retry_evt;
+};
+
+/* Defines for nlp_flag (uint32) */
+#define NLP_NO_LIST        0x0		/* Indicates immediately free node */
+#define NLP_UNUSED_LIST    0x1		/* Flg to indicate node will be freed */
+#define NLP_PLOGI_LIST     0x2		/* Flg to indicate sent PLOGI */
+#define NLP_ADISC_LIST     0x3		/* Flg to indicate sent ADISC */
+#define NLP_REGLOGIN_LIST  0x4		/* Flg to indicate sent REG_LOGIN */
+#define NLP_PRLI_LIST      0x5		/* Flg to indicate sent PRLI */
+#define NLP_UNMAPPED_LIST  0x6		/* Node is now unmapped */
+#define NLP_MAPPED_LIST    0x7		/* Node is now mapped */
+#define NLP_NPR_LIST       0x8		/* Node is in NPort Recovery state */
+#define NLP_JUST_DQ        0x9		/* just deque ndlp in lpfc_nlp_list */
+#define NLP_LIST_MASK      0xf		/* mask to see what list node is on */
+#define NLP_PLOGI_SND      0x20		/* sent PLOGI request for this entry */
+#define NLP_PRLI_SND       0x40		/* sent PRLI request for this entry */
+#define NLP_ADISC_SND      0x80		/* sent ADISC request for this entry */
+#define NLP_LOGO_SND       0x100	/* sent LOGO request for this entry */
+#define NLP_RNID_SND       0x400	/* sent RNID request for this entry */
+#define NLP_ELS_SND_MASK   0x7e0	/* sent ELS request for this entry */
+#define NLP_NODEV_TMO      0x10000	/* nodev timeout is running for node */
+#define NLP_DELAY_TMO      0x20000	/* delay timeout is running for node */
+#define NLP_NPR_2B_DISC    0x40000	/* node is included in num_disc_nodes */
+#define NLP_RCV_PLOGI      0x80000	/* Rcv'ed PLOGI from remote system */
+#define NLP_LOGO_ACC       0x100000	/* Process LOGO after ACC completes */
+#define NLP_TGT_NO_SCSIID  0x200000	/* good PRLI but no binding for scsid */
+#define NLP_ACC_REGLOGIN   0x1000000	/* Issue Reg Login after successful
+					   ACC */
+#define NLP_NPR_ADISC      0x2000000	/* Issue ADISC when dq'ed from
+					   NPR list */
+#define NLP_DELAY_REMOVE   0x4000000	/* Defer removal till end of DSM */
+
+/* Defines for list searchs */
+#define NLP_SEARCH_MAPPED    0x1	/* search mapped */
+#define NLP_SEARCH_UNMAPPED  0x2	/* search unmapped */
+#define NLP_SEARCH_PLOGI     0x4	/* search plogi */
+#define NLP_SEARCH_ADISC     0x8	/* search adisc */
+#define NLP_SEARCH_REGLOGIN  0x10	/* search reglogin */
+#define NLP_SEARCH_PRLI      0x20	/* search prli */
+#define NLP_SEARCH_NPR       0x40	/* search npr */
+#define NLP_SEARCH_UNUSED    0x80	/* search mapped */
+#define NLP_SEARCH_ALL       0xff	/* search all lists */
+
+/* There are 4 different double linked lists nodelist entries can reside on.
+ * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
+ * when Link Up discovery or Registered State Change Notification (RSCN)
+ * processing is needed.  Each list holds the nodes that require a PLOGI or
+ * ADISC Extended Link Service (ELS) request.  These lists keep track of the
+ * nodes affected by an RSCN, or a Link Up (Typically, all nodes are effected
+ * by Link Up) event.  The unmapped_list contains all nodes that have
+ * successfully logged into at the Fibre Channel level.  The
+ * mapped_list will contain all nodes that are mapped FCP targets.
+ *
+ * The bind list is a list of undiscovered (potentially non-existent) nodes
+ * that we have saved binding information on. This information is used when
+ * nodes transition from the unmapped to the mapped list.
+ */
+
+/* Defines for nlp_state */
+#define NLP_STE_UNUSED_NODE       0x0	/* node is just allocated */
+#define NLP_STE_PLOGI_ISSUE       0x1	/* PLOGI was sent to NL_PORT */
+#define NLP_STE_ADISC_ISSUE       0x2	/* ADISC was sent to NL_PORT */
+#define NLP_STE_REG_LOGIN_ISSUE   0x3	/* REG_LOGIN was issued for NL_PORT */
+#define NLP_STE_PRLI_ISSUE        0x4	/* PRLI was sent to NL_PORT */
+#define NLP_STE_UNMAPPED_NODE     0x5	/* PRLI completed from NL_PORT */
+#define NLP_STE_MAPPED_NODE       0x6	/* Identified as a FCP Target */
+#define NLP_STE_NPR_NODE          0x7	/* NPort disappeared */
+#define NLP_STE_MAX_STATE         0x8
+#define NLP_STE_FREED_NODE        0xff	/* node entry was freed to MEM_NLP */
+
+/* For UNUSED_NODE state, the node has just been allocated.
+ * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on
+ * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list
+ * and put on the unmapped list. For ADISC processing, the node is taken off
+ * the ADISC list and placed on either the mapped or unmapped list (depending
+ * on its previous state). Once on the unmapped list, a PRLI is issued and the
+ * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is
+ * changed to PRLI_COMPL. If the completion indicates a mapped
+ * node, the node is taken off the unmapped list. The binding list is checked
+ * for a valid binding, or a binding is automatically assigned. If binding
+ * assignment is unsuccessful, the node is left on the unmapped list. If
+ * binding assignment is successful, the associated binding list entry (if
+ * any) is removed, and the node is placed on the mapped list.
+ */
+/*
+ * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * expire, all effected nodes will receive a DEVICE_RM event.
+ */
+/*
+ * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists
+ * to either the ADISC or PLOGI list.  After a Nameserver query or ALPA loopmap
+ * check, additional nodes may be added (DEVICE_ADD) or removed (DEVICE_RM) to /
+ * from the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated,
+ * we will first process the ADISC list.  32 entries are processed initially and
+ * ADISC is initited for each one.  Completions / Events for each node are
+ * funnelled thru the state machine.  As each node finishes ADISC processing, it
+ * starts ADISC for any nodes waiting for ADISC processing. If no nodes are
+ * waiting, and the ADISC list count is identically 0, then we are done. For
+ * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we
+ * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI
+ * list.  32 entries are processed initially and PLOGI is initited for each one.
+ * Completions / Events for each node are funnelled thru the state machine.  As
+ * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting
+ * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is
+ * identically 0, then we are done. We have now completed discovery / RSCN
+ * handling. Upon completion, ALL nodes should be on either the mapped or
+ * unmapped lists.
+ */
+
+/* Defines for Node List Entry Events that could happen */
+#define NLP_EVT_RCV_PLOGI         0x0	/* Rcv'd an ELS PLOGI command */
+#define NLP_EVT_RCV_PRLI          0x1	/* Rcv'd an ELS PRLI  command */
+#define NLP_EVT_RCV_LOGO          0x2	/* Rcv'd an ELS LOGO  command */
+#define NLP_EVT_RCV_ADISC         0x3	/* Rcv'd an ELS ADISC command */
+#define NLP_EVT_RCV_PDISC         0x4	/* Rcv'd an ELS PDISC command */
+#define NLP_EVT_RCV_PRLO          0x5	/* Rcv'd an ELS PRLO  command */
+#define NLP_EVT_CMPL_PLOGI        0x6	/* Sent an ELS PLOGI command */
+#define NLP_EVT_CMPL_PRLI         0x7	/* Sent an ELS PRLI  command */
+#define NLP_EVT_CMPL_LOGO         0x8	/* Sent an ELS LOGO  command */
+#define NLP_EVT_CMPL_ADISC        0x9	/* Sent an ELS ADISC command */
+#define NLP_EVT_CMPL_REG_LOGIN    0xa	/* REG_LOGIN mbox cmd completed */
+#define NLP_EVT_DEVICE_RM         0xb	/* Device not found in NS / ALPAmap */
+#define NLP_EVT_DEVICE_RECOVERY   0xc	/* Device existence unknown */
+#define NLP_EVT_MAX_EVENT         0xd
+
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -0,0 +1,3258 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_els.c 1.186 2005/04/13 14:26:55EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+
+static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
+			  struct lpfc_iocbq *);
+static int lpfc_max_els_tries = 3;
+
+static int
+lpfc_els_chk_latt(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli;
+	LPFC_MBOXQ_t *mbox;
+	uint32_t ha_copy;
+	int rc;
+
+	psli = &phba->sli;
+
+	if ((phba->hba_state >= LPFC_HBA_READY) ||
+	    (phba->hba_state == LPFC_LINK_DOWN))
+		return 0;
+
+	/* Read the HBA Host Attention Register */
+	spin_lock_irq(phba->host->host_lock);
+	ha_copy = readl(phba->HAregaddr);
+	spin_unlock_irq(phba->host->host_lock);
+
+	if (!(ha_copy & HA_LATT))
+		return 0;
+
+	/* Pending Link Event during Discovery */
+	lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
+			"%d:0237 Pending Link Event during "
+			"Discovery: State x%x\n",
+			phba->brd_no, phba->hba_state);
+
+	/* CLEAR_LA should re-enable link attention events and
+	 * we should then imediately take a LATT event. The
+	 * LATT processing should call lpfc_linkdown() which
+	 * will cleanup any left over in-progress discovery
+	 * events.
+	 */
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag |= FC_ABORT_DISCOVERY;
+	spin_unlock_irq(phba->host->host_lock);
+
+	if (phba->hba_state != LPFC_CLEAR_LA) {
+		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+			phba->hba_state = LPFC_CLEAR_LA;
+			lpfc_clear_la(phba, mbox);
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+			rc = lpfc_sli_issue_mbox (phba, mbox,
+						  (MBX_NOWAIT | MBX_STOP_IOCB));
+			if (rc == MBX_NOT_FINISHED) {
+				mempool_free(mbox, phba->mbox_mem_pool);
+				phba->hba_state = LPFC_HBA_ERROR;
+			}
+		}
+	}
+
+	return (1);
+
+}
+
+static struct lpfc_iocbq *
+lpfc_prep_els_iocb(struct lpfc_hba * phba,
+		   uint8_t expectRsp,
+		   uint16_t cmdSize,
+		   uint8_t retry, struct lpfc_nodelist * ndlp, uint32_t elscmd)
+{
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *elsiocb = NULL;
+	struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
+	struct ulp_bde64 *bpl;
+	IOCB_t *icmd;
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+
+	if (phba->hba_state < LPFC_LINK_UP)
+		return  NULL;
+
+
+	/* Allocate buffer for  command iocb */
+	spin_lock_irq(phba->host->host_lock);
+	list_remove_head(lpfc_iocb_list, elsiocb, struct lpfc_iocbq, list);
+	spin_unlock_irq(phba->host->host_lock);
+
+	if (elsiocb == NULL)
+		return NULL;
+	memset(elsiocb, 0, sizeof (struct lpfc_iocbq));
+	icmd = &elsiocb->iocb;
+
+	/* fill in BDEs for command */
+	/* Allocate buffer for command payload */
+	if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
+					   MEM_PRI, &(pcmd->phys))) == 0)) {
+		if (pcmd)
+			kfree(pcmd);
+
+		list_add_tail(&elsiocb->list, lpfc_iocb_list);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&pcmd->list);
+
+	/* Allocate buffer for response payload */
+	if (expectRsp) {
+		prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+		if (prsp)
+			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+						     &prsp->phys);
+		if (prsp == 0 || prsp->virt == 0) {
+			if (prsp)
+				kfree(prsp);
+			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+			kfree(pcmd);
+			list_add_tail(&elsiocb->list, lpfc_iocb_list);
+			return NULL;
+		}
+		INIT_LIST_HEAD(&prsp->list);
+	} else {
+		prsp = NULL;
+	}
+
+	/* Allocate buffer for Buffer ptr list */
+	pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (pbuflist)
+	    pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+					     &pbuflist->phys);
+	if (pbuflist == 0 || pbuflist->virt == 0) {
+		list_add_tail(&elsiocb->list, lpfc_iocb_list);
+		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
+		kfree(pcmd);
+		kfree(prsp);
+		if (pbuflist)
+			kfree(pbuflist);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&pbuflist->list);
+
+	icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
+	icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
+	icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
+	if (expectRsp) {
+		icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
+		icmd->un.elsreq64.remoteID = ndlp->nlp_DID;	/* DID */
+		icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
+	} else {
+		icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
+		icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
+	}
+
+	icmd->ulpBdeCount = 1;
+	icmd->ulpLe = 1;
+	icmd->ulpClass = CLASS3;
+
+	bpl = (struct ulp_bde64 *) pbuflist->virt;
+	bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
+	bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
+	bpl->tus.f.bdeSize = cmdSize;
+	bpl->tus.f.bdeFlags = 0;
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
+	if (expectRsp) {
+		bpl++;
+		bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
+		bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
+		bpl->tus.f.bdeSize = FCELSSIZE;
+		bpl->tus.f.bdeFlags = BUFF_USE_RCV;
+		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+	}
+
+	/* Save for completion so we can release these resources */
+	elsiocb->context1 = (uint8_t *) ndlp;
+	elsiocb->context2 = (uint8_t *) pcmd;
+	elsiocb->context3 = (uint8_t *) pbuflist;
+	elsiocb->retry = retry;
+	elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
+
+	if (prsp) {
+		list_add(&prsp->list, &pcmd->list);
+	}
+
+	if (expectRsp) {
+		/* Xmit ELS command <elsCmd> to remote NPORT <did> */
+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+				"%d:0116 Xmit ELS command x%x to remote "
+				"NPORT x%x Data: x%x x%x\n",
+				phba->brd_no, elscmd,
+				ndlp->nlp_DID, icmd->ulpIoTag, phba->hba_state);
+	} else {
+		/* Xmit ELS response <elsCmd> to remote NPORT <did> */
+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+				"%d:0117 Xmit ELS response x%x to remote "
+				"NPORT x%x Data: x%x x%x\n",
+				phba->brd_no, elscmd,
+				ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
+	}
+
+	return (elsiocb);
+}
+
+
+static int
+lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+		struct serv_parm *sp, IOCB_t *irsp)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag |= FC_FABRIC;
+	spin_unlock_irq(phba->host->host_lock);
+
+	phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
+	if (sp->cmn.edtovResolution)	/* E_D_TOV ticks are in nanoseconds */
+		phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
+
+	phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
+
+	if (phba->fc_topology == TOPOLOGY_LOOP) {
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag |= FC_PUBLIC_LOOP;
+		spin_unlock_irq(phba->host->host_lock);
+	} else {
+		/*
+		 * If we are a N-port connected to a Fabric, fixup sparam's so
+		 * logins to devices on remote loops work.
+		 */
+		phba->fc_sparam.cmn.altBbCredit = 1;
+	}
+
+	phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
+	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
+	ndlp->nlp_class_sup = 0;
+	if (sp->cls1.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS1;
+	if (sp->cls2.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS2;
+	if (sp->cls3.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS3;
+	if (sp->cls4.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS4;
+	ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
+				sp->cmn.bbRcvSizeLsb;
+	memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		goto fail;
+
+	phba->hba_state = LPFC_FABRIC_CFG_LINK;
+	lpfc_config_link(phba, mbox);
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+	if (rc == MBX_NOT_FINISHED)
+		goto fail_free_mbox;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		goto fail;
+
+	if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
+		goto fail_free_mbox;
+
+	/*
+	 * set_slim mailbox command needs to execute first,
+	 * queue this command to be processed later.
+	 */
+	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
+	mbox->context2 = ndlp;
+
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+	if (rc == MBX_NOT_FINISHED)
+		goto fail_free_mbox;
+
+	return 0;
+
+ fail_free_mbox:
+	mempool_free(mbox, phba->mbox_mem_pool);
+ fail:
+	return -ENXIO;
+}
+
+/*
+ * We FLOGIed into an NPort, initiate pt2pt protocol
+ */
+static int
+lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+		struct serv_parm *sp)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+	spin_unlock_irq(phba->host->host_lock);
+
+	phba->fc_edtov = FF_DEF_EDTOV;
+	phba->fc_ratov = FF_DEF_RATOV;
+	rc = memcmp(&phba->fc_portname, &sp->portName,
+			sizeof(struct lpfc_name));
+	if (rc >= 0) {
+		/* This side will initiate the PLOGI */
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag |= FC_PT2PT_PLOGI;
+		spin_unlock_irq(phba->host->host_lock);
+
+		/*
+		 * N_Port ID cannot be 0, set our to LocalID the other
+		 * side will be RemoteID.
+		 */
+
+		/* not equal */
+		if (rc)
+			phba->fc_myDID = PT2PT_LocalID;
+
+		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!mbox)
+			goto fail;
+
+		lpfc_config_link(phba, mbox);
+
+		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		rc = lpfc_sli_issue_mbox(phba, mbox,
+				MBX_NOWAIT | MBX_STOP_IOCB);
+		if (rc == MBX_NOT_FINISHED) {
+			mempool_free(mbox, phba->mbox_mem_pool);
+			goto fail;
+		}
+		mempool_free(ndlp, phba->nlp_mem_pool);
+
+		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+		if (!ndlp) {
+			/*
+			 * Cannot find existing Fabric ndlp, so allocate a
+			 * new one
+			 */
+			ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+			if (!ndlp)
+				goto fail;
+
+			lpfc_nlp_init(phba, ndlp, PT2PT_RemoteID);
+		}
+
+		memcpy(&ndlp->nlp_portname, &sp->portName,
+				sizeof(struct lpfc_name));
+		memcpy(&ndlp->nlp_nodename, &sp->nodeName,
+				sizeof(struct lpfc_name));
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+	} else {
+		/* This side will wait for the PLOGI */
+		mempool_free( ndlp, phba->nlp_mem_pool);
+	}
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag |= FC_PT2PT;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Start discovery - this should just do CLEAR_LA */
+	lpfc_disc_start(phba);
+	return 0;
+ fail:
+	return -ENXIO;
+}
+
+static void
+lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
+		    struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_nodelist *ndlp = cmdiocb->context1;
+	struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
+	struct serv_parm *sp;
+	int rc;
+
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba)) {
+		lpfc_nlp_remove(phba, ndlp);
+		goto out;
+	}
+
+	if (irsp->ulpStatus) {
+		/* Check for retry */
+		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+			/* ELS command is being retried */
+			goto out;
+		}
+		/* FLOGI failed, so there is no fabric */
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+		spin_unlock_irq(phba->host->host_lock);
+
+		/* If private loop, then allow max outstandting els to be
+		 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
+		 * alpa map would take too long otherwise.
+		 */
+		if (phba->alpa_map[0] == 0) {
+			phba->cfg_discovery_threads =
+			    LPFC_MAX_DISC_THREADS;
+		}
+
+		/* FLOGI failure */
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_ELS,
+				"%d:0100 FLOGI failure Data: x%x x%x\n",
+				phba->brd_no,
+				irsp->ulpStatus, irsp->un.ulpWord[4]);
+		goto flogifail;
+	}
+
+	/*
+	 * The FLogI succeeded.  Sync the data for the CPU before
+	 * accessing it.
+	 */
+	prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
+
+	sp = prsp->virt + sizeof(uint32_t);
+
+	/* FLOGI completes successfully */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0101 FLOGI completes sucessfully "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			irsp->un.ulpWord[4], sp->cmn.e_d_tov,
+			sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
+
+	if (phba->hba_state == LPFC_FLOGI) {
+		/*
+		 * If Common Service Parameters indicate Nport
+		 * we are point to point, if Fport we are Fabric.
+		 */
+		if (sp->cmn.fPort)
+			rc = lpfc_cmpl_els_flogi_fabric(phba, ndlp, sp, irsp);
+		else
+			rc = lpfc_cmpl_els_flogi_nport(phba, ndlp, sp);
+
+		if (!rc)
+			goto out;
+	}
+
+flogifail:
+	lpfc_nlp_remove(phba, ndlp);
+
+	if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
+	    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
+	     irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
+		/* FLOGI failed, so just use loop map to make discovery list */
+		lpfc_disc_list_loopmap(phba);
+
+		/* Start discovery */
+		lpfc_disc_start(phba);
+	}
+
+out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+}
+
+static int
+lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		     uint8_t retry)
+{
+	struct serv_parm *sp;
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	uint32_t tmo;
+	int rc;
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+
+	cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_FLOGI)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	/* For FLOGI request, remainder of payload is service parameters */
+	*((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
+	pcmd += sizeof (uint32_t);
+	memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+	sp = (struct serv_parm *) pcmd;
+
+	/* Setup CSPs accordingly for Fabric */
+	sp->cmn.e_d_tov = 0;
+	sp->cmn.w2.r_a_tov = 0;
+	sp->cls1.classValid = 0;
+	sp->cls2.seqDelivery = 1;
+	sp->cls3.seqDelivery = 1;
+	if (sp->cmn.fcphLow < FC_PH3)
+		sp->cmn.fcphLow = FC_PH3;
+	if (sp->cmn.fcphHigh < FC_PH3)
+		sp->cmn.fcphHigh = FC_PH3;
+
+	tmo = phba->fc_ratov;
+	phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
+	lpfc_set_disctmo(phba);
+	phba->fc_ratov = tmo;
+
+	phba->fc_stat.elsXmitFLOGI++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+int
+lpfc_els_abort_flogi(struct lpfc_hba * phba)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *iocb, *next_iocb;
+	struct lpfc_nodelist *ndlp;
+	IOCB_t *icmd;
+
+	/* Abort outstanding I/O on NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0201 Abort outstanding I/O on NPort x%x\n",
+			phba->brd_no, Fabric_DID);
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+
+	/*
+	 * Check the txcmplq for an iocb that matches the nport the driver is
+	 * searching for.
+	 */
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		icmd = &iocb->iocb;
+		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
+			ndlp = (struct lpfc_nodelist *)(iocb->context1);
+			if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
+				list_del(&iocb->list);
+				pring->txcmplq_cnt--;
+
+				if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
+					lpfc_sli_issue_abort_iotag32
+						(phba, pring, iocb);
+				}
+				if (iocb->iocb_cmpl) {
+					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+					icmd->un.ulpWord[4] =
+					    IOERR_SLI_ABORTED;
+					spin_unlock_irq(phba->host->host_lock);
+					(iocb->iocb_cmpl) (phba, iocb, iocb);
+					spin_lock_irq(phba->host->host_lock);
+				} else {
+					list_add_tail(&iocb->list,
+						      &phba->lpfc_iocb_list);
+				}
+			}
+		}
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	return 0;
+}
+
+int
+lpfc_initial_flogi(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist *ndlp;
+
+	/* First look for Fabric ndlp on the unmapped list */
+
+	if ((ndlp =
+	     lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
+			       Fabric_DID)) == 0) {
+		/* Cannot find existing Fabric ndlp, so allocate a new one */
+		if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL))
+		    == 0) {
+			return (0);
+		}
+		lpfc_nlp_init(phba, ndlp, Fabric_DID);
+	}
+	else {
+		phba->fc_unmap_cnt--;
+		list_del(&ndlp->nlp_listp);
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_LIST_MASK;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
+		mempool_free( ndlp, phba->nlp_mem_pool);
+	}
+	return (1);
+}
+
+static void
+lpfc_more_plogi(struct lpfc_hba * phba)
+{
+	int sentplogi;
+
+	if (phba->num_disc_nodes)
+		phba->num_disc_nodes--;
+
+	/* Continue discovery with <num_disc_nodes> PLOGIs to go */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0232 Continue discovery with %d PLOGIs to go "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, phba->num_disc_nodes, phba->fc_plogi_cnt,
+			phba->fc_flag, phba->hba_state);
+
+	/* Check to see if there are more PLOGIs to be sent */
+	if (phba->fc_flag & FC_NLP_MORE) {
+		/* go thru NPR list and issue any remaining ELS PLOGIs */
+		sentplogi = lpfc_els_disc_plogi(phba);
+	}
+	return;
+}
+
+static void
+lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		    struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+	int disc, rc, did, type;
+
+	psli = &phba->sli;
+
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	irsp = &rspiocb->iocb;
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_PLOGI_SND;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Since ndlp can be freed in the disc state machine, note if this node
+	 * is being used during discovery.
+	 */
+	disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
+	rc   = 0;
+
+	/* PLOGI completes to NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0102 PLOGI completes to NPort x%x "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
+			irsp->un.ulpWord[4], disc, phba->num_disc_nodes);
+
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba)) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+		spin_unlock_irq(phba->host->host_lock);
+		goto out;
+	}
+
+	/* ndlp could be freed in DSM, save these values now */
+	type = ndlp->nlp_type;
+	did = ndlp->nlp_DID;
+
+	if (irsp->ulpStatus) {
+		/* Check for retry */
+		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+			/* ELS command is being retried */
+			if (disc) {
+				spin_lock_irq(phba->host->host_lock);
+				ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+				spin_unlock_irq(phba->host->host_lock);
+			}
+			goto out;
+		}
+
+		/* PLOGI failed */
+		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+			disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
+		}
+		else {
+			rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_PLOGI);
+		}
+	} else {
+		/* Good status, call state machine */
+		rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_PLOGI);
+	}
+
+	if (type & NLP_FABRIC) {
+		/* If we cannot login to Nameserver, kick off discovery now */
+		if ((did == NameServer_DID) && (rc == NLP_STE_FREED_NODE)) {
+			lpfc_disc_start(phba);
+		}
+		goto out;
+	}
+
+	if (disc && phba->num_disc_nodes) {
+		/* Check to see if there are more PLOGIs to be sent */
+		lpfc_more_plogi(phba);
+	}
+
+	if (rc != NLP_STE_FREED_NODE) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+
+	if (phba->num_disc_nodes == 0) {
+		if(disc) {
+			spin_lock_irq(phba->host->host_lock);
+			phba->fc_flag &= ~FC_NDISC_ACTIVE;
+			spin_unlock_irq(phba->host->host_lock);
+		}
+		lpfc_can_disctmo(phba);
+		if (phba->fc_flag & FC_RSCN_MODE) {
+			/* Check to see if more RSCNs came in while we were
+			 * processing this one.
+			 */
+			if ((phba->fc_rscn_id_cnt == 0) &&
+			    (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+				spin_lock_irq(phba->host->host_lock);
+				phba->fc_flag &= ~FC_RSCN_MODE;
+				spin_unlock_irq(phba->host->host_lock);
+			} else {
+				lpfc_els_handle_rscn(phba);
+			}
+		}
+	}
+
+out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		     uint8_t retry)
+{
+	struct serv_parm *sp;
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_PLOGI)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	/* For PLOGI request, remainder of payload is service parameters */
+	*((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
+	pcmd += sizeof (uint32_t);
+	memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+	sp = (struct serv_parm *) pcmd;
+
+	if (sp->cmn.fcphLow < FC_PH_4_3)
+		sp->cmn.fcphLow = FC_PH_4_3;
+
+	if (sp->cmn.fcphHigh < FC_PH3)
+		sp->cmn.fcphHigh = FC_PH3;
+
+	phba->fc_stat.elsXmitPLOGI++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_PLOGI_SND;
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		ndlp->nlp_flag &= ~NLP_PLOGI_SND;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return (0);
+}
+
+static void
+lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		   struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	irsp = &(rspiocb->iocb);
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_PRLI_SND;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* PRLI completes to NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0103 PRLI completes to NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
+			irsp->un.ulpWord[4], phba->num_disc_nodes);
+
+	phba->fc_prli_sent--;
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba))
+		goto out;
+
+	if (irsp->ulpStatus) {
+		/* Check for retry */
+		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+			/* ELS command is being retried */
+			goto out;
+		}
+		/* PRLI failed */
+		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+			goto out;
+		}
+		else {
+			lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_PRLI);
+		}
+	} else {
+		/* Good status, call state machine */
+		lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI);
+	}
+
+out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		    uint8_t retry)
+{
+	PRLI *npr;
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_PRLI)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	/* For PRLI request, remainder of payload is service parameters */
+	memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t)));
+	*((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
+	pcmd += sizeof (uint32_t);
+
+	/* For PRLI, remainder of payload is PRLI parameter page */
+	npr = (PRLI *) pcmd;
+	/*
+	 * If our firmware version is 3.20 or later,
+	 * set the following bits for FC-TAPE support.
+	 */
+	if (phba->vpd.rev.feaLevelHigh >= 0x02) {
+		npr->ConfmComplAllowed = 1;
+		npr->Retry = 1;
+		npr->TaskRetryIdReq = 1;
+	}
+	npr->estabImagePair = 1;
+	npr->readXferRdyDis = 1;
+
+	/* For FCP support */
+	npr->prliType = PRLI_FCP_TYPE;
+	npr->initiatorFunc = 1;
+
+	phba->fc_stat.elsXmitPRLI++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_PRLI_SND;
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		ndlp->nlp_flag &= ~NLP_PRLI_SND;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	phba->fc_prli_sent++;
+	return (0);
+}
+
+static void
+lpfc_more_adisc(struct lpfc_hba * phba)
+{
+	int sentadisc;
+
+	if (phba->num_disc_nodes)
+		phba->num_disc_nodes--;
+
+	/* Continue discovery with <num_disc_nodes> ADISCs to go */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0210 Continue discovery with %d ADISCs to go "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, phba->num_disc_nodes, phba->fc_adisc_cnt,
+			phba->fc_flag, phba->hba_state);
+
+	/* Check to see if there are more ADISCs to be sent */
+	if (phba->fc_flag & FC_NLP_MORE) {
+		lpfc_set_disctmo(phba);
+
+		/* go thru NPR list and issue any remaining ELS ADISCs */
+		sentadisc = lpfc_els_disc_adisc(phba);
+	}
+	return;
+}
+
+static void
+lpfc_rscn_disc(struct lpfc_hba * phba)
+{
+	/* RSCN discovery */
+	/* go thru NPR list and issue ELS PLOGIs */
+	if (phba->fc_npr_cnt) {
+		if (lpfc_els_disc_plogi(phba))
+			return;
+	}
+	if (phba->fc_flag & FC_RSCN_MODE) {
+		/* Check to see if more RSCNs came in while we were
+		 * processing this one.
+		 */
+		if ((phba->fc_rscn_id_cnt == 0) &&
+		    (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+			spin_lock_irq(phba->host->host_lock);
+			phba->fc_flag &= ~FC_RSCN_MODE;
+			spin_unlock_irq(phba->host->host_lock);
+		} else {
+			lpfc_els_handle_rscn(phba);
+		}
+	}
+}
+
+static void
+lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		    struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+	LPFC_MBOXQ_t *mbox;
+	int disc, rc;
+
+	psli = &phba->sli;
+
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	irsp = &(rspiocb->iocb);
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_ADISC_SND;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Since ndlp can be freed in the disc state machine, note if this node
+	 * is being used during discovery.
+	 */
+	disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
+
+	/* ADISC completes to NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0104 ADISC completes to NPort x%x "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
+			irsp->un.ulpWord[4], disc, phba->num_disc_nodes);
+
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba)) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+		spin_unlock_irq(phba->host->host_lock);
+		goto out;
+	}
+
+	if (irsp->ulpStatus) {
+		/* Check for retry */
+		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+			/* ELS command is being retried */
+			if (disc) {
+				spin_lock_irq(phba->host->host_lock);
+				ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+				spin_unlock_irq(phba->host->host_lock);
+				lpfc_set_disctmo(phba);
+			}
+			goto out;
+		}
+		/* ADISC failed */
+		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+			disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
+		}
+		else {
+			lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_ADISC);
+		}
+	} else {
+		/* Good status, call state machine */
+		lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_ADISC);
+	}
+
+	if (disc && phba->num_disc_nodes) {
+		/* Check to see if there are more ADISCs to be sent */
+		lpfc_more_adisc(phba);
+
+		/* Check to see if we are done with ADISC authentication */
+		if (phba->num_disc_nodes == 0) {
+			lpfc_can_disctmo(phba);
+			/* If we get here, there is nothing left to wait for */
+			if ((phba->hba_state < LPFC_HBA_READY) &&
+			    (phba->hba_state != LPFC_CLEAR_LA)) {
+				/* Link up discovery */
+				if ((mbox = mempool_alloc(phba->mbox_mem_pool,
+							  GFP_KERNEL))) {
+					phba->hba_state = LPFC_CLEAR_LA;
+					lpfc_clear_la(phba, mbox);
+					mbox->mbox_cmpl =
+					    lpfc_mbx_cmpl_clear_la;
+					rc = lpfc_sli_issue_mbox
+						(phba, mbox,
+						 (MBX_NOWAIT | MBX_STOP_IOCB));
+					if (rc == MBX_NOT_FINISHED) {
+						mempool_free(mbox,
+						     phba->mbox_mem_pool);
+						lpfc_disc_flush_list(phba);
+						psli->ring[(psli->ip_ring)].
+						    flag &=
+						    ~LPFC_STOP_IOCB_EVENT;
+						psli->ring[(psli->fcp_ring)].
+						    flag &=
+						    ~LPFC_STOP_IOCB_EVENT;
+						psli->ring[(psli->next_ring)].
+						    flag &=
+						    ~LPFC_STOP_IOCB_EVENT;
+						phba->hba_state =
+						    LPFC_HBA_READY;
+					}
+				}
+			} else {
+				lpfc_rscn_disc(phba);
+			}
+		}
+	}
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		     uint8_t retry)
+{
+	ADISC *ap;
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_ADISC)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	/* For ADISC request, remainder of payload is service parameters */
+	*((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
+	pcmd += sizeof (uint32_t);
+
+	/* Fill in ADISC payload */
+	ap = (ADISC *) pcmd;
+	ap->hardAL_PA = phba->fc_pref_ALPA;
+	memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
+	memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+	ap->DID = be32_to_cpu(phba->fc_myDID);
+
+	phba->fc_stat.elsXmitADISC++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_ADISC_SND;
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		ndlp->nlp_flag &= ~NLP_ADISC_SND;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return (0);
+}
+
+static void
+lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		   struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	/* we pass cmdiocb to state machine which needs rspiocb as well */
+	cmdiocb->context_un.rsp_iocb = rspiocb;
+
+	irsp = &(rspiocb->iocb);
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_LOGO_SND;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* LOGO completes to NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0105 LOGO completes to NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
+			irsp->un.ulpWord[4], phba->num_disc_nodes);
+
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba))
+		goto out;
+
+	if (irsp->ulpStatus) {
+		/* Check for retry */
+		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+			/* ELS command is being retried */
+			goto out;
+		}
+		/* LOGO failed */
+		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+			goto out;
+		}
+		else {
+			lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+					NLP_EVT_CMPL_LOGO);
+		}
+	} else {
+		/* Good status, call state machine */
+		lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO);
+
+		if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+			lpfc_unreg_rpi(phba, ndlp);
+		}
+	}
+
+out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		    uint8_t retry)
+{
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];
+
+	cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name));
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_LOGO)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+	*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
+	pcmd += sizeof (uint32_t);
+
+	/* Fill in LOGO payload */
+	*((uint32_t *) (pcmd)) = be32_to_cpu(phba->fc_myDID);
+	pcmd += sizeof (uint32_t);
+	memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name));
+
+	phba->fc_stat.elsXmitLOGO++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_LOGO_SND;
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		ndlp->nlp_flag &= ~NLP_LOGO_SND;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return (0);
+}
+
+static void
+lpfc_cmpl_els_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		  struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+
+	irsp = &rspiocb->iocb;
+
+	/* ELS cmd tag <ulpIoTag> completes */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_ELS,
+			"%d:0106 ELS cmd tag x%x completes Data: x%x x%x\n",
+			phba->brd_no,
+			irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+	/* Check to see if link went down during discovery */
+	lpfc_els_chk_latt(phba);
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+{
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+	cmdsize = (sizeof (uint32_t) + sizeof (SCR));
+	if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) {
+		return (1);
+	}
+
+	lpfc_nlp_init(phba, ndlp, nportid);
+
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_SCR)) == 0) {
+		mempool_free( ndlp, phba->nlp_mem_pool);
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
+	pcmd += sizeof (uint32_t);
+
+	/* For SCR, remainder of payload is SCR parameter page */
+	memset(pcmd, 0, sizeof (SCR));
+	((SCR *) pcmd)->Function = SCR_FUNC_FULL;
+
+	phba->fc_stat.elsXmitSCR++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+	spin_lock_irq(phba->host->host_lock);
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		spin_unlock_irq(phba->host->host_lock);
+		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	mempool_free( ndlp, phba->nlp_mem_pool);
+	return (0);
+}
+
+static int
+lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+{
+	IOCB_t *icmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	FARP *fp;
+	uint8_t *pcmd;
+	uint32_t *lp;
+	uint16_t cmdsize;
+	struct lpfc_nodelist *ondlp;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+	cmdsize = (sizeof (uint32_t) + sizeof (FARP));
+	if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) {
+		return (1);
+	}
+	lpfc_nlp_init(phba, ndlp, nportid);
+
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
+					  ndlp, ELS_CMD_RNID)) == 0) {
+		mempool_free( ndlp, phba->nlp_mem_pool);
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
+	pcmd += sizeof (uint32_t);
+
+	/* Fill in FARPR payload */
+	fp = (FARP *) (pcmd);
+	memset(fp, 0, sizeof (FARP));
+	lp = (uint32_t *) pcmd;
+	*lp++ = be32_to_cpu(nportid);
+	*lp++ = be32_to_cpu(phba->fc_myDID);
+	fp->Rflags = 0;
+	fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
+
+	memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
+	memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+	if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) {
+		memcpy(&fp->OportName, &ondlp->nlp_portname,
+		       sizeof (struct lpfc_name));
+		memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
+		       sizeof (struct lpfc_name));
+	}
+
+	phba->fc_stat.elsXmitFARPR++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+	spin_lock_irq(phba->host->host_lock);
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		spin_unlock_irq(phba->host->host_lock);
+		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	mempool_free( ndlp, phba->nlp_mem_pool);
+	return (0);
+}
+
+void
+lpfc_els_retry_delay(unsigned long ptr)
+{
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_hba *phba;
+	unsigned long iflag;
+	struct lpfc_work_evt  *evtp;
+
+	ndlp = (struct lpfc_nodelist *)ptr;
+	phba = ndlp->nlp_phba;
+	evtp = &ndlp->els_retry_evt;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	if (!list_empty(&evtp->evt_listp)) {
+		spin_unlock_irqrestore(phba->host->host_lock, iflag);
+		return;
+	}
+
+	evtp->evt_arg1  = ndlp;
+	evtp->evt       = LPFC_EVT_ELS_RETRY;
+	list_add_tail(&evtp->evt_listp, &phba->work_list);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return;
+}
+
+void
+lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
+{
+	struct lpfc_hba *phba;
+	uint32_t cmd;
+	uint32_t did;
+	uint8_t retry;
+
+	phba = ndlp->nlp_phba;
+	spin_lock_irq(phba->host->host_lock);
+	did = (uint32_t) (ndlp->nlp_DID);
+	cmd = (uint32_t) (ndlp->nlp_last_elscmd);
+
+	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return;
+	}
+
+	ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+	spin_unlock_irq(phba->host->host_lock);
+	retry = ndlp->nlp_retry;
+
+	switch (cmd) {
+	case ELS_CMD_FLOGI:
+		lpfc_issue_els_flogi(phba, ndlp, retry);
+		break;
+	case ELS_CMD_PLOGI:
+		ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+		lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+		lpfc_issue_els_plogi(phba, ndlp, retry);
+		break;
+	case ELS_CMD_ADISC:
+		ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+		lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+		lpfc_issue_els_adisc(phba, ndlp, retry);
+		break;
+	case ELS_CMD_PRLI:
+		ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
+		lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+		lpfc_issue_els_prli(phba, ndlp, retry);
+		break;
+	case ELS_CMD_LOGO:
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_issue_els_logo(phba, ndlp, retry);
+		break;
+	}
+	return;
+}
+
+static int
+lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+	       struct lpfc_iocbq * rspiocb)
+{
+	IOCB_t *irsp;
+	struct lpfc_dmabuf *pcmd;
+	struct lpfc_nodelist *ndlp;
+	uint32_t *elscmd;
+	struct ls_rjt stat;
+	int retry, maxretry;
+	int delay;
+	uint32_t cmd;
+
+	retry = 0;
+	delay = 0;
+	maxretry = lpfc_max_els_tries;
+	irsp = &rspiocb->iocb;
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	cmd = 0;
+	/* Note: context2 may be 0 for internal driver abort
+	 * of delays ELS command.
+	 */
+
+	if (pcmd && pcmd->virt) {
+		elscmd = (uint32_t *) (pcmd->virt);
+		cmd = *elscmd++;
+	}
+
+	switch (irsp->ulpStatus) {
+	case IOSTAT_FCP_RSP_ERROR:
+	case IOSTAT_REMOTE_STOP:
+		break;
+
+	case IOSTAT_LOCAL_REJECT:
+		switch ((irsp->un.ulpWord[4] & 0xff)) {
+		case IOERR_LOOP_OPEN_FAILURE:
+			if (cmd == ELS_CMD_PLOGI) {
+				if (cmdiocb->retry == 0) {
+					delay = 1;
+				}
+			}
+			retry = 1;
+			break;
+
+		case IOERR_SEQUENCE_TIMEOUT:
+			retry = 1;
+			if ((cmd == ELS_CMD_FLOGI)
+			    && (phba->fc_topology != TOPOLOGY_LOOP)) {
+				delay = 1;
+				maxretry = 48;
+			}
+			break;
+
+		case IOERR_NO_RESOURCES:
+			if (cmd == ELS_CMD_PLOGI) {
+				delay = 1;
+			}
+			retry = 1;
+			break;
+
+		case IOERR_INVALID_RPI:
+			retry = 1;
+			break;
+		}
+		break;
+
+	case IOSTAT_NPORT_RJT:
+	case IOSTAT_FABRIC_RJT:
+		if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
+			retry = 1;
+			break;
+		}
+		break;
+
+	case IOSTAT_NPORT_BSY:
+	case IOSTAT_FABRIC_BSY:
+		retry = 1;
+		break;
+
+	case IOSTAT_LS_RJT:
+		stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
+		/* Added for Vendor specifc support
+		 * Just keep retrying for these Rsn / Exp codes
+		 */
+		switch (stat.un.b.lsRjtRsnCode) {
+		case LSRJT_UNABLE_TPC:
+			if (stat.un.b.lsRjtRsnCodeExp ==
+			    LSEXP_CMD_IN_PROGRESS) {
+				if (cmd == ELS_CMD_PLOGI) {
+					delay = 1;
+					maxretry = 48;
+				}
+				retry = 1;
+				break;
+			}
+			if (cmd == ELS_CMD_PLOGI) {
+				delay = 1;
+				maxretry = lpfc_max_els_tries + 1;
+				retry = 1;
+				break;
+			}
+			break;
+
+		case LSRJT_LOGICAL_BSY:
+			if (cmd == ELS_CMD_PLOGI) {
+				delay = 1;
+				maxretry = 48;
+			}
+			retry = 1;
+			break;
+		}
+		break;
+
+	case IOSTAT_INTERMED_RSP:
+	case IOSTAT_BA_RJT:
+		break;
+
+	default:
+		break;
+	}
+
+	if (ndlp->nlp_DID == FDMI_DID) {
+		retry = 1;
+	}
+
+	if ((++cmdiocb->retry) >= maxretry) {
+		phba->fc_stat.elsRetryExceeded++;
+		retry = 0;
+	}
+
+	if (retry) {
+
+		/* Retry ELS command <elsCmd> to remote NPORT <did> */
+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+				"%d:0107 Retry ELS command x%x to remote "
+				"NPORT x%x Data: x%x x%x\n",
+				phba->brd_no,
+				cmd, ndlp->nlp_DID, cmdiocb->retry, delay);
+
+		if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
+			/* If discovery / RSCN timer is running, reset it */
+			if (timer_pending(&phba->fc_disctmo) ||
+			      (phba->fc_flag & FC_RSCN_MODE)) {
+				lpfc_set_disctmo(phba);
+			}
+		}
+
+		phba->fc_stat.elsXmitRetry++;
+		if (delay) {
+			phba->fc_stat.elsDelayRetry++;
+			ndlp->nlp_retry = cmdiocb->retry;
+
+			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+			ndlp->nlp_flag |= NLP_DELAY_TMO;
+
+			ndlp->nlp_state = NLP_STE_NPR_NODE;
+			lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+			ndlp->nlp_last_elscmd = cmd;
+
+			return (1);
+		}
+		switch (cmd) {
+		case ELS_CMD_FLOGI:
+			lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry);
+			return (1);
+		case ELS_CMD_PLOGI:
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_issue_els_plogi(phba, ndlp, cmdiocb->retry);
+			return (1);
+		case ELS_CMD_ADISC:
+			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
+			return (1);
+		case ELS_CMD_PRLI:
+			ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+			lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
+			return (1);
+		case ELS_CMD_LOGO:
+			ndlp->nlp_state = NLP_STE_NPR_NODE;
+			lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+			lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
+			return (1);
+		}
+	}
+
+	/* No retry ELS command <elsCmd> to remote NPORT <did> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0108 No retry ELS command x%x to remote NPORT x%x "
+			"Data: x%x x%x\n",
+			phba->brd_no,
+			cmd, ndlp->nlp_DID, cmdiocb->retry, ndlp->nlp_flag);
+
+	return (0);
+}
+
+int
+lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
+{
+	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
+
+	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
+	if (elsiocb->context2) {
+		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+		/* Free the response before processing the command.  */
+		if (!list_empty(&buf_ptr1->list)) {
+			list_remove_head(&buf_ptr1->list, buf_ptr,
+					 struct lpfc_dmabuf,
+					 list);
+			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+			kfree(buf_ptr);
+		}
+		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+		kfree(buf_ptr1);
+	}
+
+	if (elsiocb->context3) {
+		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+	spin_lock_irq(phba->host->host_lock);
+	list_add_tail(&elsiocb->list, &phba->lpfc_iocb_list);
+	spin_unlock_irq(phba->host->host_lock);
+	return 0;
+}
+
+static void
+lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		       struct lpfc_iocbq * rspiocb)
+{
+	struct lpfc_nodelist *ndlp;
+
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+
+	/* ACC to LOGO completes to NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0109 ACC to LOGO completes to NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+			ndlp->nlp_state, ndlp->nlp_rpi);
+
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_LOGO_ACC;
+	spin_unlock_irq(phba->host->host_lock);
+
+	switch (ndlp->nlp_state) {
+	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
+		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		break;
+	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
+		lpfc_unreg_rpi(phba, ndlp);
+		break;
+	default:
+		break;
+	}
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+static void
+lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		  struct lpfc_iocbq * rspiocb)
+{
+	struct lpfc_nodelist *ndlp;
+	LPFC_MBOXQ_t *mbox = NULL;
+
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	if (cmdiocb->context_un.mbox)
+		mbox = cmdiocb->context_un.mbox;
+
+
+	/* Check to see if link went down during discovery */
+	if ((lpfc_els_chk_latt(phba)) || !ndlp) {
+		if (mbox) {
+			mempool_free( mbox, phba->mbox_mem_pool);
+		}
+		goto out;
+	}
+
+	/* ELS response tag <ulpIoTag> completes */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0110 ELS response tag x%x completes "
+			"Data: x%x x%x x%x x%x x%x x%x\n",
+			phba->brd_no,
+			cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
+			rspiocb->iocb.un.ulpWord[4], ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	if (mbox) {
+		if ((rspiocb->iocb.ulpStatus == 0)
+		    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
+			/* set_slim mailbox command needs to execute first,
+			 * queue this command to be processed later.
+			 */
+			lpfc_unreg_rpi(phba, ndlp);
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+			mbox->context2 = ndlp;
+			ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
+			if (lpfc_sli_issue_mbox(phba, mbox,
+						(MBX_NOWAIT | MBX_STOP_IOCB))
+			    != MBX_NOT_FINISHED) {
+				goto out;
+			}
+			/* NOTE: we should have messages for unsuccessful
+			   reglogin */
+			mempool_free( mbox, phba->mbox_mem_pool);
+		} else {
+			mempool_free( mbox, phba->mbox_mem_pool);
+			if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+				lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+			}
+		}
+	}
+out:
+	if (ndlp) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	lpfc_els_free_iocb(phba, cmdiocb);
+	return;
+}
+
+int
+lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
+		 struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp,
+		 LPFC_MBOXQ_t * mbox, uint8_t newnode)
+{
+	IOCB_t *icmd;
+	IOCB_t *oldcmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	int rc;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+	oldcmd = &oldiocb->iocb;
+
+	switch (flag) {
+	case ELS_CMD_ACC:
+		cmdsize = sizeof (uint32_t);
+		if ((elsiocb =
+		     lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					ndlp, ELS_CMD_ACC)) == 0) {
+			return (1);
+		}
+		icmd = &elsiocb->iocb;
+		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+		pcmd += sizeof (uint32_t);
+		break;
+	case ELS_CMD_PLOGI:
+		cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
+		if ((elsiocb =
+		     lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					ndlp, ELS_CMD_ACC)) == 0) {
+			return (1);
+		}
+		icmd = &elsiocb->iocb;
+		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+		if (mbox)
+			elsiocb->context_un.mbox = mbox;
+
+		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+		pcmd += sizeof (uint32_t);
+		memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+		break;
+	default:
+		return (1);
+	}
+
+	if (newnode)
+		elsiocb->context1 = NULL;
+
+	/* Xmit ELS ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0128 Xmit ELS ACC response tag x%x "
+			"Data: x%x x%x x%x x%x x%x\n",
+			phba->brd_no,
+			elsiocb->iocb.ulpIoTag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+		elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
+	} else {
+		elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	}
+
+	phba->fc_stat.elsXmitACC++;
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+int
+lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
+		    struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+{
+	IOCB_t *icmd;
+	IOCB_t *oldcmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	int rc;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = 2 * sizeof (uint32_t);
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					  ndlp, ELS_CMD_LS_RJT)) == 0) {
+		return (1);
+	}
+
+	icmd = &elsiocb->iocb;
+	oldcmd = &oldiocb->iocb;
+	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
+	pcmd += sizeof (uint32_t);
+	*((uint32_t *) (pcmd)) = rejectError;
+
+	/* Xmit ELS RJT <err> response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0129 Xmit ELS RJT x%x response tag x%x "
+			"Data: x%x x%x x%x x%x x%x\n",
+			phba->brd_no,
+			rejectError, elsiocb->iocb.ulpIoTag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	phba->fc_stat.elsXmitLSRJT++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+int
+lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
+		       struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+{
+	ADISC *ap;
+	IOCB_t *icmd;
+	IOCB_t *oldcmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	int rc;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = sizeof (uint32_t) + sizeof (ADISC);
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					  ndlp, ELS_CMD_ACC)) == 0) {
+		return (1);
+	}
+
+	/* Xmit ADISC ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0130 Xmit ADISC ACC response tag x%x "
+			"Data: x%x x%x x%x x%x x%x\n",
+			phba->brd_no,
+			elsiocb->iocb.ulpIoTag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	icmd = &elsiocb->iocb;
+	oldcmd = &oldiocb->iocb;
+	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+	pcmd += sizeof (uint32_t);
+
+	ap = (ADISC *) (pcmd);
+	ap->hardAL_PA = phba->fc_pref_ALPA;
+	memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
+	memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+	ap->DID = be32_to_cpu(phba->fc_myDID);
+
+	phba->fc_stat.elsXmitACC++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+int
+lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
+		      struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+{
+	PRLI *npr;
+	lpfc_vpd_t *vpd;
+	IOCB_t *icmd;
+	IOCB_t *oldcmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	int rc;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+
+	cmdsize = sizeof (uint32_t) + sizeof (PRLI);
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					  ndlp,
+					  (ELS_CMD_ACC |
+					   (ELS_CMD_PRLI & ~ELS_RSP_MASK)))) ==
+	    0) {
+		return (1);
+	}
+
+	/* Xmit PRLI ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0131 Xmit PRLI ACC response tag x%x "
+			"Data: x%x x%x x%x x%x x%x\n",
+			phba->brd_no,
+			elsiocb->iocb.ulpIoTag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	icmd = &elsiocb->iocb;
+	oldcmd = &oldiocb->iocb;
+	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
+	pcmd += sizeof (uint32_t);
+
+	/* For PRLI, remainder of payload is PRLI parameter page */
+	memset(pcmd, 0, sizeof (PRLI));
+
+	npr = (PRLI *) pcmd;
+	vpd = &phba->vpd;
+	/*
+	 * If our firmware version is 3.20 or later,
+	 * set the following bits for FC-TAPE support.
+	 */
+	if (vpd->rev.feaLevelHigh >= 0x02) {
+		npr->ConfmComplAllowed = 1;
+		npr->Retry = 1;
+		npr->TaskRetryIdReq = 1;
+	}
+
+	npr->acceptRspCode = PRLI_REQ_EXECUTED;
+	npr->estabImagePair = 1;
+	npr->readXferRdyDis = 1;
+	npr->ConfmComplAllowed = 1;
+
+	npr->prliType = PRLI_FCP_TYPE;
+	npr->initiatorFunc = 1;
+
+	phba->fc_stat.elsXmitACC++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+static int
+lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
+		      uint8_t format,
+		      struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+{
+	RNID *rn;
+	IOCB_t *icmd;
+	IOCB_t *oldcmd;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	uint8_t *pcmd;
+	uint16_t cmdsize;
+	int rc;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];
+
+	cmdsize = sizeof (uint32_t) + sizeof (uint32_t)
+		+ (2 * sizeof (struct lpfc_name));
+	if (format)
+		cmdsize += sizeof (RNID_TOP_DISC);
+
+	if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+					  ndlp, ELS_CMD_ACC)) == 0) {
+		return (1);
+	}
+
+	/* Xmit RNID ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0132 Xmit RNID ACC response tag x%x "
+			"Data: x%x\n",
+			phba->brd_no,
+			elsiocb->iocb.ulpIoTag,
+			elsiocb->iocb.ulpContext);
+
+	icmd = &elsiocb->iocb;
+	oldcmd = &oldiocb->iocb;
+	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+	pcmd += sizeof (uint32_t);
+
+	memset(pcmd, 0, sizeof (RNID));
+	rn = (RNID *) (pcmd);
+	rn->Format = format;
+	rn->CommonLen = (2 * sizeof (struct lpfc_name));
+	memcpy(&rn->portName, &phba->fc_portname, sizeof (struct lpfc_name));
+	memcpy(&rn->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+	switch (format) {
+	case 0:
+		rn->SpecificLen = 0;
+		break;
+	case RNID_TOPOLOGY_DISC:
+		rn->SpecificLen = sizeof (RNID_TOP_DISC);
+		memcpy(&rn->un.topologyDisc.portName,
+		       &phba->fc_portname, sizeof (struct lpfc_name));
+		rn->un.topologyDisc.unitType = RNID_HBA;
+		rn->un.topologyDisc.physPort = 0;
+		rn->un.topologyDisc.attachedNodes = 0;
+		break;
+	default:
+		rn->CommonLen = 0;
+		rn->SpecificLen = 0;
+		break;
+	}
+
+	phba->fc_stat.elsXmitACC++;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
+				    * it could be freed */
+
+	spin_lock_irq(phba->host->host_lock);
+	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	spin_unlock_irq(phba->host->host_lock);
+	if (rc == IOCB_ERROR) {
+		lpfc_els_free_iocb(phba, elsiocb);
+		return (1);
+	}
+	return (0);
+}
+
+int
+lpfc_els_disc_adisc(struct lpfc_hba * phba)
+{
+	int sentadisc;
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+
+	sentadisc = 0;
+	/* go thru NPR list and issue any remaining ELS ADISCs */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+			nlp_listp) {
+		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+			if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+				ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+				lpfc_nlp_list(phba, ndlp,
+					NLP_ADISC_LIST);
+				lpfc_issue_els_adisc(phba, ndlp, 0);
+				sentadisc++;
+				phba->num_disc_nodes++;
+				if (phba->num_disc_nodes >=
+				    phba->cfg_discovery_threads) {
+					spin_lock_irq(phba->host->host_lock);
+					phba->fc_flag |= FC_NLP_MORE;
+					spin_unlock_irq(phba->host->host_lock);
+					break;
+				}
+			}
+		}
+	}
+	if (sentadisc == 0) {
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~FC_NLP_MORE;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	return(sentadisc);
+}
+
+int
+lpfc_els_disc_plogi(struct lpfc_hba * phba)
+{
+	int sentplogi;
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+
+	sentplogi = 0;
+	/* go thru NPR list and issue any remaining ELS PLOGIs */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+				nlp_listp) {
+		if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+		   (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
+			if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+				ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+				lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+				lpfc_issue_els_plogi(phba, ndlp, 0);
+				sentplogi++;
+				phba->num_disc_nodes++;
+				if (phba->num_disc_nodes >=
+				    phba->cfg_discovery_threads) {
+					spin_lock_irq(phba->host->host_lock);
+					phba->fc_flag |= FC_NLP_MORE;
+					spin_unlock_irq(phba->host->host_lock);
+					break;
+				}
+			}
+		}
+	}
+	if (sentplogi == 0) {
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~FC_NLP_MORE;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	return(sentplogi);
+}
+
+int
+lpfc_els_flush_rscn(struct lpfc_hba * phba)
+{
+	struct lpfc_dmabuf *mp;
+	int i;
+
+	for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
+		mp = phba->fc_rscn_id_list[i];
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		phba->fc_rscn_id_list[i] = NULL;
+	}
+	phba->fc_rscn_id_cnt = 0;
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_can_disctmo(phba);
+	return (0);
+}
+
+int
+lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
+{
+	D_ID ns_did;
+	D_ID rscn_did;
+	struct lpfc_dmabuf *mp;
+	uint32_t *lp;
+	uint32_t payload_len, cmd, i, match;
+
+	ns_did.un.word = did;
+	match = 0;
+
+	/* Never match fabric nodes for RSCNs */
+	if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
+		return(0);
+
+	/* If we are doing a FULL RSCN rediscovery, match everything */
+	if (phba->fc_flag & FC_RSCN_DISCOVERY) {
+		return (did);
+	}
+
+	for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
+		mp = phba->fc_rscn_id_list[i];
+		lp = (uint32_t *) mp->virt;
+		cmd = *lp++;
+		payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
+		payload_len -= sizeof (uint32_t);	/* take off word 0 */
+		while (payload_len) {
+			rscn_did.un.word = *lp++;
+			rscn_did.un.word = be32_to_cpu(rscn_did.un.word);
+			payload_len -= sizeof (uint32_t);
+			switch (rscn_did.un.b.resv) {
+			case 0:	/* Single N_Port ID effected */
+				if (ns_did.un.word == rscn_did.un.word) {
+					match = did;
+				}
+				break;
+			case 1:	/* Whole N_Port Area effected */
+				if ((ns_did.un.b.domain == rscn_did.un.b.domain)
+				    && (ns_did.un.b.area == rscn_did.un.b.area))
+					{
+						match = did;
+					}
+				break;
+			case 2:	/* Whole N_Port Domain effected */
+				if (ns_did.un.b.domain == rscn_did.un.b.domain)
+					{
+						match = did;
+					}
+				break;
+			case 3:	/* Whole Fabric effected */
+				match = did;
+				break;
+			default:
+				/* Unknown Identifier in RSCN list */
+				lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+						"%d:0217 Unknown Identifier in "
+						"RSCN payload Data: x%x\n",
+						phba->brd_no, rscn_did.un.word);
+				break;
+			}
+			if (match) {
+				break;
+			}
+		}
+	}
+	return (match);
+}
+
+static int
+lpfc_rscn_recovery_check(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist *ndlp = NULL, *next_ndlp;
+	struct list_head *listp;
+	struct list_head *node_list[7];
+	int i;
+
+	/* Look at all nodes effected by pending RSCNs and move
+	 * them to NPR list.
+	 */
+	node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
+	node_list[1] = &phba->fc_nlpmap_list;
+	node_list[2] = &phba->fc_nlpunmap_list;
+	node_list[3] = &phba->fc_prli_list;
+	node_list[4] = &phba->fc_reglogin_list;
+	node_list[5] = &phba->fc_adisc_list;
+	node_list[6] = &phba->fc_plogi_list;
+	for (i = 0; i < 7; i++) {
+		listp = node_list[i];
+		if (list_empty(listp))
+			continue;
+
+		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
+			if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
+				continue;
+
+			lpfc_disc_state_machine(phba, ndlp, NULL,
+					NLP_EVT_DEVICE_RECOVERY);
+			if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+				ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+				del_timer_sync(&ndlp->nlp_delayfunc);
+				if (!list_empty(&ndlp->
+						els_retry_evt.evt_listp))
+					list_del_init(&ndlp->
+						els_retry_evt.evt_listp);
+			}
+		}
+	}
+	return (0);
+}
+
+static int
+lpfc_els_rcv_rscn(struct lpfc_hba * phba,
+		  struct lpfc_iocbq * cmdiocb,
+		  struct lpfc_nodelist * ndlp, uint8_t newnode)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	uint32_t payload_len, cmd;
+
+	icmd = &cmdiocb->iocb;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	payload_len = be32_to_cpu(cmd) & 0xffff;	/* payload length */
+	payload_len -= sizeof (uint32_t);	/* take off word 0 */
+	cmd &= ELS_CMD_MASK;
+
+	/* RSCN received */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_DISCOVERY,
+			"%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+
+	/* If we are about to begin discovery, just ACC the RSCN.
+	 * Discovery processing will satisfy it.
+	 */
+	if (phba->hba_state < LPFC_NS_QRY) {
+		lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+								newnode);
+		return (0);
+	}
+
+	/* If we are already processing an RSCN, save the received
+	 * RSCN payload buffer, cmdiocb->context2 to process later.
+	 */
+	if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
+		if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
+		    !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
+			spin_lock_irq(phba->host->host_lock);
+			phba->fc_flag |= FC_RSCN_MODE;
+			spin_unlock_irq(phba->host->host_lock);
+			phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+
+			/* If we zero, cmdiocb->context2, the calling
+			 * routine will not try to free it.
+			 */
+			cmdiocb->context2 = NULL;
+
+			/* Deferred RSCN */
+			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+					"%d:0235 Deferred RSCN "
+					"Data: x%x x%x x%x\n",
+					phba->brd_no, phba->fc_rscn_id_cnt,
+					phba->fc_flag, phba->hba_state);
+		} else {
+			spin_lock_irq(phba->host->host_lock);
+			phba->fc_flag |= FC_RSCN_DISCOVERY;
+			spin_unlock_irq(phba->host->host_lock);
+			/* ReDiscovery RSCN */
+			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+					"%d:0234 ReDiscovery RSCN "
+					"Data: x%x x%x x%x\n",
+					phba->brd_no, phba->fc_rscn_id_cnt,
+					phba->fc_flag, phba->hba_state);
+		}
+		/* Send back ACC */
+		lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+								newnode);
+
+		/* send RECOVERY event for ALL nodes that match RSCN payload */
+		lpfc_rscn_recovery_check(phba);
+		return (0);
+	}
+
+	phba->fc_flag |= FC_RSCN_MODE;
+	phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+	/*
+	 * If we zero, cmdiocb->context2, the calling routine will
+	 * not try to free it.
+	 */
+	cmdiocb->context2 = NULL;
+
+	lpfc_set_disctmo(phba);
+
+	/* Send back ACC */
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
+
+	/* send RECOVERY event for ALL nodes that match RSCN payload */
+	lpfc_rscn_recovery_check(phba);
+
+	return (lpfc_els_handle_rscn(phba));
+}
+
+int
+lpfc_els_handle_rscn(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist *ndlp;
+
+	/* Start timer for RSCN processing */
+	lpfc_set_disctmo(phba);
+
+	/* RSCN processed */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_DISCOVERY,
+			"%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			phba->fc_flag, 0, phba->fc_rscn_id_cnt,
+			phba->hba_state);
+
+	/* To process RSCN, first compare RSCN data with NameServer */
+	phba->fc_ns_retry = 0;
+	if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
+				      NameServer_DID))) {
+		/* Good ndlp, issue CT Request to NameServer */
+		if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
+			/* Wait for NameServer query cmpl before we can
+			   continue */
+			return (1);
+		}
+	} else {
+		/* If login to NameServer does not exist, issue one */
+		/* Good status, issue PLOGI to NameServer */
+		if ((ndlp =
+		     lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID))) {
+			/* Wait for NameServer login cmpl before we can
+			   continue */
+			return (1);
+		}
+		if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL))
+		    == 0) {
+			lpfc_els_flush_rscn(phba);
+			return (0);
+		} else {
+			lpfc_nlp_init(phba, ndlp, NameServer_DID);
+			ndlp->nlp_type |= NLP_FABRIC;
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_issue_els_plogi(phba, ndlp, 0);
+			/* Wait for NameServer login cmpl before we can
+			   continue */
+			return (1);
+		}
+	}
+
+	lpfc_els_flush_rscn(phba);
+	return (0);
+}
+
+static int
+lpfc_els_rcv_flogi(struct lpfc_hba * phba,
+		   struct lpfc_iocbq * cmdiocb,
+		   struct lpfc_nodelist * ndlp, uint8_t newnode)
+{
+	struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	uint32_t *lp = (uint32_t *) pcmd->virt;
+	IOCB_t *icmd = &cmdiocb->iocb;
+	struct serv_parm *sp;
+	LPFC_MBOXQ_t *mbox;
+	struct ls_rjt stat;
+	uint32_t cmd, did;
+	int rc;
+
+	cmd = *lp++;
+	sp = (struct serv_parm *) lp;
+
+	/* FLOGI received */
+
+	lpfc_set_disctmo(phba);
+
+	if (phba->fc_topology == TOPOLOGY_LOOP) {
+		/* We should never receive a FLOGI in loop mode, ignore it */
+		did = icmd->un.elsreq64.remoteID;
+
+		/* An FLOGI ELS command <elsCmd> was received from DID <did> in
+		   Loop Mode */
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+				"%d:0113 An FLOGI ELS command x%x was received "
+				"from DID x%x in Loop Mode\n",
+				phba->brd_no, cmd, did);
+		return (1);
+	}
+
+	did = Fabric_DID;
+
+	if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3))) {
+		/* For a FLOGI we accept, then if our portname is greater
+		 * then the remote portname we initiate Nport login.
+		 */
+
+		rc = memcmp(&phba->fc_portname, &sp->portName,
+			    sizeof (struct lpfc_name));
+
+		if (!rc) {
+			if ((mbox = mempool_alloc(phba->mbox_mem_pool,
+						  GFP_KERNEL)) == 0) {
+				return (1);
+			}
+			lpfc_linkdown(phba);
+			lpfc_init_link(phba, mbox,
+				       phba->cfg_topology,
+				       phba->cfg_link_speed);
+			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			rc = lpfc_sli_issue_mbox
+				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+			if (rc == MBX_NOT_FINISHED) {
+				mempool_free( mbox, phba->mbox_mem_pool);
+			}
+			return (1);
+		}
+		else if (rc > 0) {	/* greater than */
+			spin_lock_irq(phba->host->host_lock);
+			phba->fc_flag |= FC_PT2PT_PLOGI;
+			spin_unlock_irq(phba->host->host_lock);
+		}
+		phba->fc_flag |= FC_PT2PT;
+		phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+	} else {
+		/* Reject this request because invalid parameters */
+		stat.un.b.lsRjtRsvd0 = 0;
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
+		stat.un.b.vendorUnique = 0;
+		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+		return (1);
+	}
+
+	/* Send back ACC */
+	lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
+
+	return (0);
+}
+
+static int
+lpfc_els_rcv_rnid(struct lpfc_hba * phba,
+		  struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	RNID *rn;
+	struct ls_rjt stat;
+	uint32_t cmd, did;
+
+	icmd = &cmdiocb->iocb;
+	did = icmd->un.elsreq64.remoteID;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	rn = (RNID *) lp;
+
+	/* RNID received */
+
+	switch (rn->Format) {
+	case 0:
+	case RNID_TOPOLOGY_DISC:
+		/* Send back ACC */
+		lpfc_els_rsp_rnid_acc(phba, rn->Format, cmdiocb, ndlp);
+		break;
+	default:
+		/* Reject this request because format not supported */
+		stat.un.b.lsRjtRsvd0 = 0;
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+		stat.un.b.vendorUnique = 0;
+		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+	}
+	return (0);
+}
+
+static int
+lpfc_els_rcv_rrq(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		 struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	RRQ *rrq;
+	uint32_t cmd, did;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_FCP_RING];
+	icmd = &cmdiocb->iocb;
+	did = icmd->un.elsreq64.remoteID;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	rrq = (RRQ *) lp;
+
+	/* RRQ received */
+	/* Get oxid / rxid from payload and abort it */
+	spin_lock_irq(phba->host->host_lock);
+	if ((rrq->SID == be32_to_cpu(phba->fc_myDID))) {
+		lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Oxid,
+							LPFC_CTX_CTX);
+	} else {
+		lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Rxid,
+							LPFC_CTX_CTX);
+	}
+
+	spin_unlock_irq(phba->host->host_lock);
+	/* ACCEPT the rrq request */
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+
+	return 0;
+}
+
+static int
+lpfc_els_rcv_farp(struct lpfc_hba * phba,
+		  struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	FARP *fp;
+	uint32_t cmd, cnt, did;
+
+	icmd = &cmdiocb->iocb;
+	did = icmd->un.elsreq64.remoteID;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	fp = (FARP *) lp;
+
+	/* FARP-REQ received from DID <did> */
+	lpfc_printf_log(phba,
+			 KERN_INFO,
+			 LOG_IP,
+			 "%d:0601 FARP-REQ received from DID x%x\n",
+			 phba->brd_no, did);
+
+	/* We will only support match on WWPN or WWNN */
+	if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
+		return (0);
+	}
+
+	cnt = 0;
+	/* If this FARP command is searching for my portname */
+	if (fp->Mflags & FARP_MATCH_PORT) {
+		if (memcmp(&fp->RportName, &phba->fc_portname,
+			   sizeof (struct lpfc_name)) == 0)
+			cnt = 1;
+	}
+
+	/* If this FARP command is searching for my nodename */
+	if (fp->Mflags & FARP_MATCH_NODE) {
+		if (memcmp(&fp->RnodeName, &phba->fc_nodename,
+			   sizeof (struct lpfc_name)) == 0)
+			cnt = 1;
+	}
+
+	if (cnt) {
+		if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
+		   (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
+			/* Log back into the node before sending the FARP. */
+			if (fp->Rflags & FARP_REQUEST_PLOGI) {
+				ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+				lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+				lpfc_issue_els_plogi(phba, ndlp, 0);
+			}
+
+			/* Send a FARP response to that node */
+			if (fp->Rflags & FARP_REQUEST_FARPR) {
+				lpfc_issue_els_farpr(phba, did, 0);
+			}
+		}
+	}
+	return (0);
+}
+
+static int
+lpfc_els_rcv_farpr(struct lpfc_hba * phba,
+		   struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	uint32_t cmd, did;
+
+	icmd = &cmdiocb->iocb;
+	did = icmd->un.elsreq64.remoteID;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	/* FARP-RSP received from DID <did> */
+	lpfc_printf_log(phba,
+			 KERN_INFO,
+			 LOG_IP,
+			 "%d:0600 FARP-RSP received from DID x%x\n",
+			 phba->brd_no, did);
+
+	/* ACCEPT the Farp resp request */
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+
+	return 0;
+}
+
+static int
+lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+		 struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	FAN *fp;
+	uint32_t cmd, did;
+
+	icmd = &cmdiocb->iocb;
+	did = icmd->un.elsreq64.remoteID;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	fp = (FAN *) lp;
+
+	/* FAN received */
+
+	/* ACCEPT the FAN request */
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+
+	if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+		/* The discovery state machine needs to take a different
+		 * action if this node has switched fabrics
+		 */
+		if ((memcmp(&fp->FportName, &phba->fc_fabparam.portName,
+			    sizeof (struct lpfc_name)) != 0)
+		    ||
+		    (memcmp(&fp->FnodeName, &phba->fc_fabparam.nodeName,
+			    sizeof (struct lpfc_name)) != 0)) {
+			/* This node has switched fabrics.  An FLOGI is required
+			 * after the timeout
+			 */
+			return (0);
+		}
+
+		/* Start discovery */
+		lpfc_disc_start(phba);
+	}
+
+	return (0);
+}
+
+void
+lpfc_els_timeout(unsigned long ptr)
+{
+	struct lpfc_hba *phba;
+	unsigned long iflag;
+
+	phba = (struct lpfc_hba *)ptr;
+	if (phba == 0)
+		return;
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
+		phba->work_hba_events |= WORKER_ELS_TMO;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return;
+}
+
+void
+lpfc_els_timeout_handler(struct lpfc_hba *phba)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *tmp_iocb, *piocb;
+	IOCB_t *cmd = NULL;
+	struct lpfc_dmabuf *pcmd;
+	struct list_head *dlp;
+	uint32_t *elscmd;
+	uint32_t els_command;
+	uint32_t timeout;
+	uint32_t remote_ID;
+
+	if (phba == 0)
+		return;
+	spin_lock_irq(phba->host->host_lock);
+	/* If the timer is already canceled do nothing */
+	if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return;
+	}
+	timeout = (uint32_t)(phba->fc_ratov << 1);
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+	dlp = &pring->txcmplq;
+
+	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+		cmd = &piocb->iocb;
+
+		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+			continue;
+		}
+		pcmd = (struct lpfc_dmabuf *) piocb->context2;
+		elscmd = (uint32_t *) (pcmd->virt);
+		els_command = *elscmd;
+
+		if ((els_command == ELS_CMD_FARP)
+		    || (els_command == ELS_CMD_FARPR)) {
+			continue;
+		}
+
+		if (piocb->drvrTimeout > 0) {
+			if (piocb->drvrTimeout >= timeout) {
+				piocb->drvrTimeout -= timeout;
+			} else {
+				piocb->drvrTimeout = 0;
+			}
+			continue;
+		}
+
+		list_del(&piocb->list);
+		pring->txcmplq_cnt--;
+
+		if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
+			struct lpfc_nodelist *ndlp;
+
+			ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
+			remote_ID = ndlp->nlp_DID;
+			if (cmd->un.elsreq64.bdl.ulpIoTag32) {
+				lpfc_sli_issue_abort_iotag32(phba,
+					pring, piocb);
+			}
+		} else {
+			remote_ID = cmd->un.elsreq64.remoteID;
+		}
+
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_ELS,
+				"%d:0127 ELS timeout Data: x%x x%x x%x x%x\n",
+				phba->brd_no, els_command,
+				remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+
+		/*
+		 * The iocb has timed out; abort it.
+		 */
+		if (piocb->iocb_cmpl) {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			spin_unlock_irq(phba->host->host_lock);
+			(piocb->iocb_cmpl) (phba, piocb, piocb);
+			spin_lock_irq(phba->host->host_lock);
+		} else {
+			list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
+		}
+	}
+	if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
+		phba->els_tmofunc.expires = jiffies + HZ * timeout;
+		add_timer(&phba->els_tmofunc);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+}
+
+void
+lpfc_els_flush_cmd(struct lpfc_hba * phba)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *tmp_iocb, *piocb;
+	IOCB_t *cmd = NULL;
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *elscmd;
+	uint32_t els_command;
+	uint32_t remote_ID;
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
+		cmd = &piocb->iocb;
+
+		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+			continue;
+		}
+
+		/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
+		if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) ||
+		    (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) ||
+		    (cmd->ulpCommand == CMD_CLOSE_XRI_CN) ||
+		    (cmd->ulpCommand == CMD_ABORT_XRI_CN)) {
+			continue;
+		}
+
+		pcmd = (struct lpfc_dmabuf *) piocb->context2;
+		elscmd = (uint32_t *) (pcmd->virt);
+		els_command = *elscmd;
+
+		if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
+			struct lpfc_nodelist *ndlp;
+
+			ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
+			remote_ID = ndlp->nlp_DID;
+			if (phba->hba_state == LPFC_HBA_READY) {
+				continue;
+			}
+		} else {
+			remote_ID = cmd->un.elsreq64.remoteID;
+		}
+
+		list_del(&piocb->list);
+		pring->txcmplq_cnt--;
+
+		cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+		cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+
+		if (piocb->iocb_cmpl) {
+			spin_unlock_irq(phba->host->host_lock);
+			(piocb->iocb_cmpl) (phba, piocb, piocb);
+			spin_lock_irq(phba->host->host_lock);
+		}
+		else
+			list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
+	}
+
+	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+		cmd = &piocb->iocb;
+
+		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+			continue;
+		}
+		pcmd = (struct lpfc_dmabuf *) piocb->context2;
+		elscmd = (uint32_t *) (pcmd->virt);
+		els_command = *elscmd;
+
+		if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
+			struct lpfc_nodelist *ndlp;
+
+			ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
+			remote_ID = ndlp->nlp_DID;
+			if (phba->hba_state == LPFC_HBA_READY) {
+				continue;
+			}
+		} else {
+			remote_ID = cmd->un.elsreq64.remoteID;
+		}
+
+		list_del(&piocb->list);
+		pring->txcmplq_cnt--;
+
+		cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+		cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+
+		if (piocb->iocb_cmpl) {
+			spin_unlock_irq(phba->host->host_lock);
+			(piocb->iocb_cmpl) (phba, piocb, piocb);
+			spin_lock_irq(phba->host->host_lock);
+		}
+		else
+			list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+
+void
+lpfc_els_unsol_event(struct lpfc_hba * phba,
+		     struct lpfc_sli_ring * pring, struct lpfc_iocbq * elsiocb)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_dmabuf *mp;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	struct ls_rjt stat;
+	uint32_t cmd;
+	uint32_t did;
+	uint32_t newnode;
+	uint32_t drop_cmd = 0;	/* by default do NOT drop received cmd */
+	uint32_t rjt_err = 0;
+
+	psli = &phba->sli;
+	icmd = &elsiocb->iocb;
+
+	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+		/* Not enough posted buffers; Try posting more buffers */
+		phba->fc_stat.NoRcvBuf++;
+		lpfc_post_buffer(phba, pring, 0, 1);
+		return;
+	}
+
+	/* If there are no BDEs associated with this IOCB,
+	 * there is nothing to do.
+	 */
+	if (icmd->ulpBdeCount == 0)
+		return;
+
+	/* type of ELS cmd is first 32bit word in packet */
+	mp = lpfc_sli_ringpostbuf_get(phba, pring, getPaddr(icmd->un.
+							    cont64[0].
+							    addrHigh,
+							    icmd->un.
+							    cont64[0].addrLow));
+	if (mp == 0) {
+		drop_cmd = 1;
+		goto dropit;
+	}
+
+	newnode = 0;
+	lp = (uint32_t *) mp->virt;
+	cmd = *lp++;
+	lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1);
+
+	if (icmd->ulpStatus) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		drop_cmd = 1;
+		goto dropit;
+	}
+
+	/* Check to see if link went down during discovery */
+	if (lpfc_els_chk_latt(phba)) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		drop_cmd = 1;
+		goto dropit;
+	}
+
+	did = icmd->un.rcvels.remoteID;
+	if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did)) == 0) {
+		/* Cannot find existing Fabric ndlp, so allocate a new one */
+		if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL))
+		    == 0) {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+			drop_cmd = 1;
+			goto dropit;
+		}
+
+		lpfc_nlp_init(phba, ndlp, did);
+		newnode = 1;
+		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
+			ndlp->nlp_type |= NLP_FABRIC;
+		}
+	}
+
+	phba->fc_stat.elsRcvFrame++;
+	elsiocb->context1 = ndlp;
+	elsiocb->context2 = mp;
+
+	if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
+		cmd &= ELS_CMD_MASK;
+	}
+	/* ELS command <elsCmd> received from NPORT <did> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0112 ELS command x%x received from NPORT x%x "
+			"Data: x%x\n", phba->brd_no, cmd, did, phba->hba_state);
+
+	switch (cmd) {
+	case ELS_CMD_PLOGI:
+		phba->fc_stat.elsRcvPLOGI++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
+		break;
+	case ELS_CMD_FLOGI:
+		phba->fc_stat.elsRcvFLOGI++;
+		lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
+		if (newnode) {
+			mempool_free( ndlp, phba->nlp_mem_pool);
+		}
+		break;
+	case ELS_CMD_LOGO:
+		phba->fc_stat.elsRcvLOGO++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
+		break;
+	case ELS_CMD_PRLO:
+		phba->fc_stat.elsRcvPRLO++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
+		break;
+	case ELS_CMD_RSCN:
+		phba->fc_stat.elsRcvRSCN++;
+		lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
+		if (newnode) {
+			mempool_free( ndlp, phba->nlp_mem_pool);
+		}
+		break;
+	case ELS_CMD_ADISC:
+		phba->fc_stat.elsRcvADISC++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_ADISC);
+		break;
+	case ELS_CMD_PDISC:
+		phba->fc_stat.elsRcvPDISC++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PDISC);
+		break;
+	case ELS_CMD_FARPR:
+		phba->fc_stat.elsRcvFARPR++;
+		lpfc_els_rcv_farpr(phba, elsiocb, ndlp);
+		break;
+	case ELS_CMD_FARP:
+		phba->fc_stat.elsRcvFARP++;
+		lpfc_els_rcv_farp(phba, elsiocb, ndlp);
+		break;
+	case ELS_CMD_FAN:
+		phba->fc_stat.elsRcvFAN++;
+		lpfc_els_rcv_fan(phba, elsiocb, ndlp);
+		break;
+	case ELS_CMD_RRQ:
+		phba->fc_stat.elsRcvRRQ++;
+		lpfc_els_rcv_rrq(phba, elsiocb, ndlp);
+		break;
+	case ELS_CMD_PRLI:
+		phba->fc_stat.elsRcvPRLI++;
+		if (phba->hba_state < LPFC_DISC_AUTH) {
+			rjt_err = LSEXP_NOTHING_MORE;
+			break;
+		}
+		lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
+		break;
+	case ELS_CMD_RNID:
+		phba->fc_stat.elsRcvRNID++;
+		lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
+		break;
+	default:
+		/* Unsupported ELS command, reject */
+		rjt_err = LSEXP_NOTHING_MORE;
+
+		/* Unknown ELS command <elsCmd> received from NPORT <did> */
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+				"%d:0115 Unknown ELS command x%x received from "
+				"NPORT x%x\n", phba->brd_no, cmd, did);
+		if (newnode) {
+			mempool_free( ndlp, phba->nlp_mem_pool);
+		}
+		break;
+	}
+
+	/* check if need to LS_RJT received ELS cmd */
+	if (rjt_err) {
+		stat.un.b.lsRjtRsvd0 = 0;
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = rjt_err;
+		stat.un.b.vendorUnique = 0;
+		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
+	}
+
+	if (elsiocb->context2) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+	}
+dropit:
+	/* check if need to drop received ELS cmd */
+	if (drop_cmd == 1) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+				"%d:0111 Dropping received ELS cmd "
+				"Data: x%x x%x\n", phba->brd_no,
+				icmd->ulpStatus, icmd->un.ulpWord[4]);
+		phba->fc_stat.elsRcvDrop++;
+	}
+	return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -0,0 +1,2537 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_hbadisc.c 1.266 2005/04/13 11:59:06EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_disc.h"
+#include "lpfc_sli.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+
+/* AlpaArray for assignment of scsid for scan-down and bind_method */
+static uint8_t lpfcAlpaArray[] = {
+	0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6,
+	0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA,
+	0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5,
+	0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9,
+	0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97,
+	0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79,
+	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B,
+	0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56,
+	0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A,
+	0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35,
+	0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+	0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17,
+	0x10, 0x0F, 0x08, 0x04, 0x02, 0x01
+};
+
+static void lpfc_disc_timeout_handler(struct lpfc_hba *);
+
+static void
+lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+	if (!(ndlp->nlp_type & NLP_FABRIC)) {
+		/* Nodev timeout on NPort <nlp_DID> */
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+			"%d:0203 Nodev timeout on NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+			ndlp->nlp_state, ndlp->nlp_rpi);
+	}
+
+	spin_lock_irq(phba->host->host_lock);
+	if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return;
+	}
+
+	ndlp->nlp_flag &= ~NLP_NODEV_TMO;
+
+	if (ndlp->nlp_sid != NLP_NO_SID) {
+		/* flush the target */
+		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+			ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+	return;
+}
+
+static void
+lpfc_work_list_done(struct lpfc_hba * phba)
+{
+	struct lpfc_work_evt  *evtp = NULL;
+	struct lpfc_nodelist  *ndlp;
+	int free_evt;
+
+	spin_lock_irq(phba->host->host_lock);
+	while(!list_empty(&phba->work_list)) {
+		list_remove_head((&phba->work_list), evtp, typeof(*evtp),
+				 evt_listp);
+		spin_unlock_irq(phba->host->host_lock);
+		free_evt = 1;
+		switch(evtp->evt) {
+		case LPFC_EVT_NODEV_TMO:
+			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+			lpfc_process_nodev_timeout(phba, ndlp);
+			free_evt = 0;
+			break;
+		case LPFC_EVT_ELS_RETRY:
+			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+			lpfc_els_retry_delay_handler(ndlp);
+			free_evt = 0;
+			break;
+		case LPFC_EVT_ONLINE:
+			*(int *)(evtp->evt_arg1)  = lpfc_online(phba);
+			complete((struct completion *)(evtp->evt_arg2));
+			break;
+		case LPFC_EVT_OFFLINE:
+			*(int *)(evtp->evt_arg1)  = lpfc_offline(phba);
+			complete((struct completion *)(evtp->evt_arg2));
+			break;
+		}
+		if (free_evt)
+			kfree(evtp);
+		spin_lock_irq(phba->host->host_lock);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+}
+
+static void
+lpfc_work_done(struct lpfc_hba * phba)
+{
+	struct lpfc_sli_ring *pring;
+	int i;
+	uint32_t ha_copy;
+	uint32_t control;
+	uint32_t work_hba_events;
+
+	spin_lock_irq(phba->host->host_lock);
+	ha_copy = phba->work_ha;
+	phba->work_ha = 0;
+	work_hba_events=phba->work_hba_events;
+	spin_unlock_irq(phba->host->host_lock);
+
+	if(ha_copy & HA_ERATT)
+		lpfc_handle_eratt(phba);
+
+	if(ha_copy & HA_MBATT)
+		lpfc_sli_handle_mb_event(phba);
+
+	if(ha_copy & HA_LATT)
+		lpfc_handle_latt(phba);
+
+	if (work_hba_events & WORKER_DISC_TMO)
+		lpfc_disc_timeout_handler(phba);
+
+	if (work_hba_events & WORKER_ELS_TMO)
+		lpfc_els_timeout_handler(phba);
+
+	if (work_hba_events & WORKER_MBOX_TMO)
+		lpfc_mbox_timeout_handler(phba);
+
+	if (work_hba_events & WORKER_FDMI_TMO)
+		lpfc_fdmi_tmo_handler(phba);
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->work_hba_events &= ~work_hba_events;
+	spin_unlock_irq(phba->host->host_lock);
+
+	for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) {
+		pring = &phba->sli.ring[i];
+		if ((ha_copy & HA_RXATT)
+		    || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+			if (pring->flag & LPFC_STOP_IOCB_MASK) {
+				pring->flag |= LPFC_DEFERRED_RING_EVENT;
+			} else {
+				lpfc_sli_handle_slow_ring_event(phba, pring,
+								(ha_copy &
+								 HA_RXMASK));
+				pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+			}
+			/*
+			 * Turn on Ring interrupts
+			 */
+			spin_lock_irq(phba->host->host_lock);
+			control = readl(phba->HCregaddr);
+			control |= (HC_R0INT_ENA << i);
+			writel(control, phba->HCregaddr);
+			readl(phba->HCregaddr); /* flush */
+			spin_unlock_irq(phba->host->host_lock);
+		}
+	}
+
+	lpfc_work_list_done (phba);
+
+}
+
+static int
+check_work_wait_done(struct lpfc_hba *phba) {
+
+	spin_lock_irq(phba->host->host_lock);
+	if (phba->work_ha ||
+	    phba->work_hba_events ||
+	    (!list_empty(&phba->work_list)) ||
+	    kthread_should_stop()) {
+		spin_unlock_irq(phba->host->host_lock);
+		return 1;
+	} else {
+		spin_unlock_irq(phba->host->host_lock);
+		return 0;
+	}
+}
+
+int
+lpfc_do_work(void *p)
+{
+	struct lpfc_hba *phba = p;
+	int rc;
+	DECLARE_WAIT_QUEUE_HEAD(work_waitq);
+
+	set_user_nice(current, -20);
+	phba->work_wait = &work_waitq;
+
+	while (1) {
+
+		rc = wait_event_interruptible(work_waitq,
+						check_work_wait_done(phba));
+		BUG_ON(rc);
+
+		if (kthread_should_stop())
+			break;
+
+		lpfc_work_done(phba);
+
+	}
+	phba->work_wait = NULL;
+	return 0;
+}
+
+/*
+ * This is only called to handle FC worker events. Since this a rare
+ * occurance, we allocate a struct lpfc_work_evt structure here instead of
+ * embedding it in the IOCB.
+ */
+int
+lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
+		      uint32_t evt)
+{
+	struct lpfc_work_evt  *evtp;
+
+	/*
+	 * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will
+	 * be queued to worker thread for processing
+	 */
+	evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_KERNEL);
+	if (!evtp)
+		return 0;
+
+	evtp->evt_arg1  = arg1;
+	evtp->evt_arg2  = arg2;
+	evtp->evt       = evt;
+
+	list_add_tail(&evtp->evt_listp, &phba->work_list);
+	spin_lock_irq(phba->host->host_lock);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+	spin_unlock_irq(phba->host->host_lock);
+
+	return 1;
+}
+
+int
+lpfc_linkdown(struct lpfc_hba * phba)
+{
+	struct lpfc_sli       *psli;
+	struct lpfc_nodelist  *ndlp, *next_ndlp;
+	struct list_head *listp;
+	struct list_head *node_list[7];
+	LPFC_MBOXQ_t     *mb;
+	int               rc, i;
+
+	psli = &phba->sli;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->hba_state = LPFC_LINK_DOWN;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Clean up any firmware default rpi's */
+	if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+		lpfc_unreg_did(phba, 0xffffffff, mb);
+		mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+		    == MBX_NOT_FINISHED) {
+			mempool_free( mb, phba->mbox_mem_pool);
+		}
+	}
+
+	/* Cleanup any outstanding RSCN activity */
+	lpfc_els_flush_rscn(phba);
+
+	/* Cleanup any outstanding ELS commands */
+	lpfc_els_flush_cmd(phba);
+
+	/* Issue a LINK DOWN event to all nodes */
+	node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
+	node_list[1] = &phba->fc_nlpmap_list;
+	node_list[2] = &phba->fc_nlpunmap_list;
+	node_list[3] = &phba->fc_prli_list;
+	node_list[4] = &phba->fc_reglogin_list;
+	node_list[5] = &phba->fc_adisc_list;
+	node_list[6] = &phba->fc_plogi_list;
+	for (i = 0; i < 7; i++) {
+		listp = node_list[i];
+		if (list_empty(listp))
+			continue;
+
+		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
+			/* Fabric nodes are not handled thru state machine for
+			   link down */
+			if (ndlp->nlp_type & NLP_FABRIC) {
+				/* Remove ALL Fabric nodes except Fabric_DID */
+				if (ndlp->nlp_DID != Fabric_DID) {
+					/* Take it off current list and free */
+					lpfc_nlp_list(phba, ndlp,
+						NLP_NO_LIST);
+				}
+			}
+			else {
+
+				rc = lpfc_disc_state_machine(phba, ndlp, NULL,
+						     NLP_EVT_DEVICE_RECOVERY);
+
+				/* Check config parameter use-adisc or FCP-2 */
+				if ((rc != NLP_STE_FREED_NODE) &&
+					(phba->cfg_use_adisc == 0) &&
+					!(ndlp->nlp_fcp_info &
+						NLP_FCP_2_DEVICE)) {
+					/* We know we will have to relogin, so
+					 * unreglogin the rpi right now to fail
+					 * any outstanding I/Os quickly.
+					 */
+					lpfc_unreg_rpi(phba, ndlp);
+				}
+			}
+		}
+	}
+
+	/* free any ndlp's on unused list */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
+				nlp_listp) {
+		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	}
+
+	/* Setup myDID for link up if we are in pt2pt mode */
+	if (phba->fc_flag & FC_PT2PT) {
+		phba->fc_myDID = 0;
+		if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+			lpfc_config_link(phba, mb);
+			mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+			if (lpfc_sli_issue_mbox
+			    (phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+			    == MBX_NOT_FINISHED) {
+				mempool_free( mb, phba->mbox_mem_pool);
+			}
+		}
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~FC_LBIT;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Turn off discovery timer if its running */
+	lpfc_can_disctmo(phba);
+
+	/* Must process IOCBs on all rings to handle ABORTed I/Os */
+	return (0);
+}
+
+static int
+lpfc_linkup(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->hba_state = LPFC_LINK_UP;
+	phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
+			   FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
+	phba->fc_flag |= FC_NDISC_ACTIVE;
+	phba->fc_ns_retry = 0;
+	spin_unlock_irq(phba->host->host_lock);
+
+
+	/*
+	 * Clean up old Fabric NLP_FABRIC logins.
+	 */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
+				nlp_listp) {
+		if (ndlp->nlp_DID == Fabric_DID) {
+			/* Take it off current list and free */
+			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		}
+	}
+
+	/* free any ndlp's on unused list */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
+				nlp_listp) {
+		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	}
+
+	return 0;
+}
+
+/*
+ * This routine handles processing a CLEAR_LA mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+	uint32_t control;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+	/* Since we don't do discovery right now, turn these off here */
+	psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
+	psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
+	psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
+
+	/* Check for error */
+	if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
+		/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"%d:0320 CLEAR_LA mbxStatus error x%x hba "
+				"state x%x\n",
+				phba->brd_no, mb->mbxStatus, phba->hba_state);
+
+		phba->hba_state = LPFC_HBA_ERROR;
+		goto out;
+	}
+
+	if (phba->fc_flag & FC_ABORT_DISCOVERY)
+		goto out;
+
+	phba->num_disc_nodes = 0;
+	/* go thru NPR list and issue ELS PLOGIs */
+	if (phba->fc_npr_cnt) {
+		lpfc_els_disc_plogi(phba);
+	}
+
+	if(!phba->num_disc_nodes) {
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~FC_NDISC_ACTIVE;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+
+	phba->hba_state = LPFC_HBA_READY;
+
+out:
+	/* Device Discovery completes */
+	lpfc_printf_log(phba,
+			 KERN_INFO,
+			 LOG_DISCOVERY,
+			 "%d:0225 Device Discovery completes\n",
+			 phba->brd_no);
+
+	mempool_free( pmb, phba->mbox_mem_pool);
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~FC_ABORT_DISCOVERY;
+	if (phba->fc_flag & FC_ESTABLISH_LINK) {
+		phba->fc_flag &= ~FC_ESTABLISH_LINK;
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	del_timer_sync(&phba->fc_estabtmo);
+
+	lpfc_can_disctmo(phba);
+
+	/* turn on Link Attention interrupts */
+	spin_lock_irq(phba->host->host_lock);
+	psli->sli_flag |= LPFC_PROCESS_LA;
+	control = readl(phba->HCregaddr);
+	control |= HC_LAINT_ENA;
+	writel(control, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+	spin_unlock_irq(phba->host->host_lock);
+
+	return;
+}
+
+static void
+lpfc_mbx_cmpl_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+	/* Check for error */
+	if (mb->mbxStatus) {
+		/* CONFIG_LINK mbox error <mbxStatus> state <hba_state> */
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"%d:0306 CONFIG_LINK mbxStatus error x%x "
+				"HBA state x%x\n",
+				phba->brd_no, mb->mbxStatus, phba->hba_state);
+
+		lpfc_linkdown(phba);
+		phba->hba_state = LPFC_HBA_ERROR;
+		goto out;
+	}
+
+	if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+		if (phba->fc_topology == TOPOLOGY_LOOP) {
+			/* If we are public loop and L bit was set */
+			if ((phba->fc_flag & FC_PUBLIC_LOOP) &&
+			    !(phba->fc_flag & FC_LBIT)) {
+				/* Need to wait for FAN - use discovery timer
+				 * for timeout.  hba_state is identically
+				 * LPFC_LOCAL_CFG_LINK while waiting for FAN
+				 */
+				lpfc_set_disctmo(phba);
+				mempool_free( pmb, phba->mbox_mem_pool);
+				return;
+			}
+		}
+
+		/* Start discovery by sending a FLOGI hba_state is identically
+		 * LPFC_FLOGI while waiting for FLOGI cmpl
+		 */
+		phba->hba_state = LPFC_FLOGI;
+		lpfc_set_disctmo(phba);
+		lpfc_initial_flogi(phba);
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return;
+	}
+	if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return;
+	}
+
+out:
+	/* CONFIG_LINK bad hba state <hba_state> */
+	lpfc_printf_log(phba,
+			KERN_ERR,
+			LOG_DISCOVERY,
+			"%d:0200 CONFIG_LINK bad hba state x%x\n",
+			phba->brd_no, phba->hba_state);
+
+	if (phba->hba_state != LPFC_CLEAR_LA) {
+		lpfc_clear_la(phba, pmb);
+		pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+		if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB))
+		    == MBX_NOT_FINISHED) {
+			mempool_free( pmb, phba->mbox_mem_pool);
+			lpfc_disc_flush_list(phba);
+			psli->ring[(psli->ip_ring)].flag &=
+				~LPFC_STOP_IOCB_EVENT;
+			psli->ring[(psli->fcp_ring)].flag &=
+				~LPFC_STOP_IOCB_EVENT;
+			psli->ring[(psli->next_ring)].flag &=
+				~LPFC_STOP_IOCB_EVENT;
+			phba->hba_state = LPFC_HBA_READY;
+		}
+	} else {
+		mempool_free( pmb, phba->mbox_mem_pool);
+	}
+	return;
+}
+
+static void
+lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	MAILBOX_t *mb = &pmb->mb;
+	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
+
+
+	/* Check for error */
+	if (mb->mbxStatus) {
+		/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"%d:0319 READ_SPARAM mbxStatus error x%x "
+				"hba state x%x>\n",
+				phba->brd_no, mb->mbxStatus, phba->hba_state);
+
+		lpfc_linkdown(phba);
+		phba->hba_state = LPFC_HBA_ERROR;
+		goto out;
+	}
+
+	memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
+	       sizeof (struct serv_parm));
+	memcpy((uint8_t *) & phba->fc_nodename,
+	       (uint8_t *) & phba->fc_sparam.nodeName,
+	       sizeof (struct lpfc_name));
+	memcpy((uint8_t *) & phba->fc_portname,
+	       (uint8_t *) & phba->fc_sparam.portName,
+	       sizeof (struct lpfc_name));
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free( pmb, phba->mbox_mem_pool);
+	return;
+
+out:
+	pmb->context1 = NULL;
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	if (phba->hba_state != LPFC_CLEAR_LA) {
+		lpfc_clear_la(phba, pmb);
+		pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+		if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB))
+		    == MBX_NOT_FINISHED) {
+			mempool_free( pmb, phba->mbox_mem_pool);
+			lpfc_disc_flush_list(phba);
+			psli->ring[(psli->ip_ring)].flag &=
+			    ~LPFC_STOP_IOCB_EVENT;
+			psli->ring[(psli->fcp_ring)].flag &=
+			    ~LPFC_STOP_IOCB_EVENT;
+			psli->ring[(psli->next_ring)].flag &=
+			    ~LPFC_STOP_IOCB_EVENT;
+			phba->hba_state = LPFC_HBA_READY;
+		}
+	} else {
+		mempool_free( pmb, phba->mbox_mem_pool);
+	}
+	return;
+}
+
+static void
+lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
+{
+	int i;
+	LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+	sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+	spin_lock_irq(phba->host->host_lock);
+	switch(la->UlnkSpeed) {
+		case LA_1GHZ_LINK:
+			phba->fc_linkspeed = LA_1GHZ_LINK;
+			break;
+		case LA_2GHZ_LINK:
+			phba->fc_linkspeed = LA_2GHZ_LINK;
+			break;
+		case LA_4GHZ_LINK:
+			phba->fc_linkspeed = LA_4GHZ_LINK;
+			break;
+		default:
+			phba->fc_linkspeed = LA_UNKNW_LINK;
+			break;
+	}
+
+	phba->fc_topology = la->topology;
+
+	if (phba->fc_topology == TOPOLOGY_LOOP) {
+	/* Get Loop Map information */
+
+		if (la->il)
+			phba->fc_flag |= FC_LBIT;
+
+		phba->fc_myDID = la->granted_AL_PA;
+		i = la->un.lilpBde64.tus.f.bdeSize;
+
+		if (i == 0) {
+			phba->alpa_map[0] = 0;
+		} else {
+			if (phba->cfg_log_verbose & LOG_LINK_EVENT) {
+				int numalpa, j, k;
+				union {
+					uint8_t pamap[16];
+					struct {
+						uint32_t wd1;
+						uint32_t wd2;
+						uint32_t wd3;
+						uint32_t wd4;
+					} pa;
+				} un;
+				numalpa = phba->alpa_map[0];
+				j = 0;
+				while (j < numalpa) {
+					memset(un.pamap, 0, 16);
+					for (k = 1; j < numalpa; k++) {
+						un.pamap[k - 1] =
+							phba->alpa_map[j + 1];
+						j++;
+						if (k == 16)
+							break;
+					}
+					/* Link Up Event ALPA map */
+					lpfc_printf_log(phba,
+						KERN_WARNING,
+						LOG_LINK_EVENT,
+						"%d:1304 Link Up Event "
+						"ALPA map Data: x%x "
+						"x%x x%x x%x\n",
+						phba->brd_no,
+						un.pa.wd1, un.pa.wd2,
+						un.pa.wd3, un.pa.wd4);
+				}
+			}
+		}
+	} else {
+		phba->fc_myDID = phba->fc_pref_DID;
+		phba->fc_flag |= FC_LBIT;
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	lpfc_linkup(phba);
+	if (sparam_mbox) {
+		lpfc_read_sparam(phba, sparam_mbox);
+		sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
+		lpfc_sli_issue_mbox(phba, sparam_mbox,
+						(MBX_NOWAIT | MBX_STOP_IOCB));
+	}
+
+	if (cfglink_mbox) {
+		phba->hba_state = LPFC_LOCAL_CFG_LINK;
+		lpfc_config_link(phba, cfglink_mbox);
+		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_config_link;
+		lpfc_sli_issue_mbox(phba, cfglink_mbox,
+						(MBX_NOWAIT | MBX_STOP_IOCB));
+	}
+}
+
+static void
+lpfc_mbx_issue_link_down(struct lpfc_hba *phba) {
+	uint32_t control;
+	struct lpfc_sli *psli = &phba->sli;
+
+	lpfc_linkdown(phba);
+
+	/* turn on Link Attention interrupts - no CLEAR_LA needed */
+	spin_lock_irq(phba->host->host_lock);
+	psli->sli_flag |= LPFC_PROCESS_LA;
+	control = readl(phba->HCregaddr);
+	control |= HC_LAINT_ENA;
+	writel(control, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+	spin_unlock_irq(phba->host->host_lock);
+}
+
+/*
+ * This routine handles processing a READ_LA mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	READ_LA_VAR *la;
+	MAILBOX_t *mb = &pmb->mb;
+	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+
+	/* Check for error */
+	if (mb->mbxStatus) {
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_LINK_EVENT,
+				"%d:1307 READ_LA mbox error x%x state x%x\n",
+				phba->brd_no,
+				mb->mbxStatus, phba->hba_state);
+		lpfc_mbx_issue_link_down(phba);
+		phba->hba_state = LPFC_HBA_ERROR;
+		goto lpfc_mbx_cmpl_read_la_free_mbuf;
+	}
+
+	la = (READ_LA_VAR *) & pmb->mb.un.varReadLA;
+
+	memcpy(&phba->alpa_map[0], mp->virt, 128);
+
+	if (((phba->fc_eventTag + 1) < la->eventTag) ||
+	     (phba->fc_eventTag == la->eventTag)) {
+		phba->fc_stat.LinkMultiEvent++;
+		if (la->attType == AT_LINK_UP) {
+			if (phba->fc_eventTag != 0)
+				lpfc_linkdown(phba);
+		}
+	}
+
+	phba->fc_eventTag = la->eventTag;
+
+	if (la->attType == AT_LINK_UP) {
+		phba->fc_stat.LinkUp++;
+		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+				"%d:1303 Link Up Event x%x received "
+				"Data: x%x x%x x%x x%x\n",
+				phba->brd_no, la->eventTag, phba->fc_eventTag,
+				la->granted_AL_PA, la->UlnkSpeed,
+				phba->alpa_map[0]);
+		lpfc_mbx_process_link_up(phba, la);
+	} else {
+		phba->fc_stat.LinkDown++;
+		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+				"%d:1305 Link Down Event x%x received "
+				"Data: x%x x%x x%x\n",
+				phba->brd_no, la->eventTag, phba->fc_eventTag,
+				phba->hba_state, phba->fc_flag);
+		lpfc_mbx_issue_link_down(phba);
+	}
+
+lpfc_mbx_cmpl_read_la_free_mbuf:
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free(pmb, phba->mbox_mem_pool);
+	return;
+}
+
+/*
+ * This routine handles processing a REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+
+	ndlp = (struct lpfc_nodelist *) pmb->context2;
+	mp = (struct lpfc_dmabuf *) (pmb->context1);
+
+	pmb->context1 = NULL;
+
+	/* Good status, call state machine */
+	lpfc_disc_state_machine(phba, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free( pmb, phba->mbox_mem_pool);
+
+	return;
+}
+
+/*
+ * This routine handles processing a Fabric REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_nodelist *ndlp_fdmi;
+
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+
+	ndlp = (struct lpfc_nodelist *) pmb->context2;
+	mp = (struct lpfc_dmabuf *) (pmb->context1);
+
+	if (mb->mbxStatus) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		mempool_free( pmb, phba->mbox_mem_pool);
+		mempool_free( ndlp, phba->nlp_mem_pool);
+
+		/* FLOGI failed, so just use loop map to make discovery list */
+		lpfc_disc_list_loopmap(phba);
+
+		/* Start discovery */
+		lpfc_disc_start(phba);
+		return;
+	}
+
+	pmb->context1 = NULL;
+
+	if (ndlp->nlp_rpi != 0)
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+	ndlp->nlp_rpi = mb->un.varWords[0];
+	lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi);
+	ndlp->nlp_type |= NLP_FABRIC;
+	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+
+	if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
+		/* This NPort has been assigned an NPort_ID by the fabric as a
+		 * result of the completed fabric login.  Issue a State Change
+		 * Registration (SCR) ELS request to the fabric controller
+		 * (SCR_DID) so that this NPort gets RSCN events from the
+		 * fabric.
+		 */
+		lpfc_issue_els_scr(phba, SCR_DID, 0);
+
+		/* Allocate a new node instance.  If the pool is empty, just
+		 * start the discovery process and skip the Nameserver login
+		 * process.  This is attempted again later on.  Otherwise, issue
+		 * a Port Login (PLOGI) to the NameServer
+		 */
+		if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL))
+		    == 0) {
+			lpfc_disc_start(phba);
+		} else {
+			lpfc_nlp_init(phba, ndlp, NameServer_DID);
+			ndlp->nlp_type |= NLP_FABRIC;
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_issue_els_plogi(phba, ndlp, 0);
+			if (phba->cfg_fdmi_on) {
+				if ((ndlp_fdmi = mempool_alloc(
+						       phba->nlp_mem_pool,
+						       GFP_KERNEL))) {
+					lpfc_nlp_init(phba, ndlp_fdmi,
+						FDMI_DID);
+					ndlp_fdmi->nlp_type |= NLP_FABRIC;
+					ndlp_fdmi->nlp_state =
+					    NLP_STE_PLOGI_ISSUE;
+					lpfc_issue_els_plogi(phba, ndlp_fdmi,
+							     0);
+				}
+			}
+		}
+	}
+
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free( pmb, phba->mbox_mem_pool);
+
+	return;
+}
+
+/*
+ * This routine handles processing a NameServer REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+
+	ndlp = (struct lpfc_nodelist *) pmb->context2;
+	mp = (struct lpfc_dmabuf *) (pmb->context1);
+
+	if (mb->mbxStatus) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		mempool_free( pmb, phba->mbox_mem_pool);
+		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+
+		/* RegLogin failed, so just use loop map to make discovery
+		   list */
+		lpfc_disc_list_loopmap(phba);
+
+		/* Start discovery */
+		lpfc_disc_start(phba);
+		return;
+	}
+
+	pmb->context1 = NULL;
+
+	if (ndlp->nlp_rpi != 0)
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+	ndlp->nlp_rpi = mb->un.varWords[0];
+	lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi);
+	ndlp->nlp_type |= NLP_FABRIC;
+	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+
+	if (phba->hba_state < LPFC_HBA_READY) {
+		/* Link up discovery requires Fabrib registration. */
+		lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID);
+		lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN);
+		lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID);
+	}
+
+	phba->fc_ns_retry = 0;
+	/* Good status, issue CT Request to NameServer */
+	if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT)) {
+		/* Cannot issue NameServer Query, so finish up discovery */
+		lpfc_disc_start(phba);
+	}
+
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free( pmb, phba->mbox_mem_pool);
+
+	return;
+}
+
+static void
+lpfc_register_remote_port(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp)
+{
+	struct fc_rport *rport;
+	struct lpfc_rport_data *rdata;
+	struct fc_rport_identifiers rport_ids;
+	uint64_t wwn;
+
+	/* Remote port has reappeared. Re-register w/ FC transport */
+	memcpy(&wwn, &ndlp->nlp_nodename, sizeof(uint64_t));
+	rport_ids.node_name = be64_to_cpu(wwn);
+	memcpy(&wwn, &ndlp->nlp_portname, sizeof(uint64_t));
+	rport_ids.port_name = be64_to_cpu(wwn);
+	rport_ids.port_id = ndlp->nlp_DID;
+	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+	if (ndlp->nlp_type & NLP_FCP_TARGET)
+		rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+	if (ndlp->nlp_type & NLP_FCP_INITIATOR)
+		rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+	ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
+	if (!rport) {
+		dev_printk(KERN_WARNING, &phba->pcidev->dev,
+			   "Warning: fc_remote_port_add failed\n");
+		return;
+	}
+
+	/* initialize static port data */
+	rport->maxframe_size = ndlp->nlp_maxframe;
+	rport->supported_classes = ndlp->nlp_class_sup;
+	if ((rport->scsi_target_id != -1) &&
+		(rport->scsi_target_id < MAX_FCP_TARGET)) {
+		ndlp->nlp_sid = rport->scsi_target_id;
+	}
+	rdata = rport->dd_data;
+	rdata->pnode = ndlp;
+
+	return;
+}
+
+int
+lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
+{
+	enum { none, unmapped, mapped } rport_add = none, rport_del = none;
+	struct lpfc_sli      *psli;
+
+	psli = &phba->sli;
+	/* Sanity check to ensure we are not moving to / from the same list */
+	if ((nlp->nlp_flag & NLP_LIST_MASK) == list) {
+		if (list != NLP_NO_LIST)
+			return(0);
+	}
+
+	switch(nlp->nlp_flag & NLP_LIST_MASK) {
+	case NLP_NO_LIST: /* Not on any list */
+		break;
+	case NLP_UNUSED_LIST:
+		phba->fc_unused_cnt--;
+		list_del(&nlp->nlp_listp);
+		break;
+	case NLP_PLOGI_LIST:
+		phba->fc_plogi_cnt--;
+		list_del(&nlp->nlp_listp);
+		break;
+	case NLP_ADISC_LIST:
+		phba->fc_adisc_cnt--;
+		list_del(&nlp->nlp_listp);
+		break;
+	case NLP_REGLOGIN_LIST:
+		phba->fc_reglogin_cnt--;
+		list_del(&nlp->nlp_listp);
+		break;
+	case NLP_PRLI_LIST:
+		phba->fc_prli_cnt--;
+		list_del(&nlp->nlp_listp);
+		break;
+	case NLP_UNMAPPED_LIST:
+		phba->fc_unmap_cnt--;
+		list_del(&nlp->nlp_listp);
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
+		nlp->nlp_type &= ~NLP_FC_NODE;
+		spin_unlock_irq(phba->host->host_lock);
+		phba->nport_event_cnt++;
+		if (nlp->rport)
+			rport_del = unmapped;
+		break;
+	case NLP_MAPPED_LIST:
+		phba->fc_map_cnt--;
+		list_del(&nlp->nlp_listp);
+		phba->nport_event_cnt++;
+		if (nlp->rport)
+			rport_del = mapped;
+		break;
+	case NLP_NPR_LIST:
+		phba->fc_npr_cnt--;
+		list_del(&nlp->nlp_listp);
+		/* Stop delay tmo if taking node off NPR list */
+		if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
+		   (list != NLP_NPR_LIST)) {
+			spin_lock_irq(phba->host->host_lock);
+			nlp->nlp_flag &= ~NLP_DELAY_TMO;
+			spin_unlock_irq(phba->host->host_lock);
+			del_timer_sync(&nlp->nlp_delayfunc);
+			if (!list_empty(&nlp->els_retry_evt.evt_listp))
+				list_del_init(&nlp->els_retry_evt.evt_listp);
+		}
+		break;
+	}
+
+	spin_lock_irq(phba->host->host_lock);
+	nlp->nlp_flag &= ~NLP_LIST_MASK;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Add NPort <did> to <num> list */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_NODE,
+			"%d:0904 Add NPort x%x to %d list Data: x%x\n",
+			phba->brd_no,
+			nlp->nlp_DID, list, nlp->nlp_flag);
+
+	switch(list) {
+	case NLP_NO_LIST: /* No list, just remove it */
+		lpfc_nlp_remove(phba, nlp);
+		break;
+	case NLP_UNUSED_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the unused list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list);
+		phba->fc_unused_cnt++;
+		break;
+	case NLP_PLOGI_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the plogi list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list);
+		phba->fc_plogi_cnt++;
+		break;
+	case NLP_ADISC_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the adisc list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list);
+		phba->fc_adisc_cnt++;
+		break;
+	case NLP_REGLOGIN_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the reglogin list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list);
+		phba->fc_reglogin_cnt++;
+		break;
+	case NLP_PRLI_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the prli list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list);
+		phba->fc_prli_cnt++;
+		break;
+	case NLP_UNMAPPED_LIST:
+		rport_add = unmapped;
+		/* ensure all vestiges of "mapped" significance are gone */
+		nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the unmap list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
+		phba->fc_unmap_cnt++;
+		phba->nport_event_cnt++;
+		/* stop nodev tmo if running */
+		if (nlp->nlp_flag & NLP_NODEV_TMO) {
+			spin_lock_irq(phba->host->host_lock);
+			nlp->nlp_flag &= ~NLP_NODEV_TMO;
+			spin_unlock_irq(phba->host->host_lock);
+			del_timer_sync(&nlp->nlp_tmofunc);
+			if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
+				list_del_init(&nlp->nodev_timeout_evt.
+						evt_listp);
+
+		}
+		nlp->nlp_type |= NLP_FC_NODE;
+		break;
+	case NLP_MAPPED_LIST:
+		rport_add = mapped;
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the map list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
+		phba->fc_map_cnt++;
+		phba->nport_event_cnt++;
+		/* stop nodev tmo if running */
+		if (nlp->nlp_flag & NLP_NODEV_TMO) {
+			nlp->nlp_flag &= ~NLP_NODEV_TMO;
+			del_timer_sync(&nlp->nlp_tmofunc);
+			if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
+				list_del_init(&nlp->nodev_timeout_evt.
+						evt_listp);
+
+		}
+		break;
+	case NLP_NPR_LIST:
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= list;
+		spin_unlock_irq(phba->host->host_lock);
+		/* Put it at the end of the npr list */
+		list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
+		phba->fc_npr_cnt++;
+
+		/*
+		 * Sanity check for Fabric entity.
+		 * Set nodev_tmo for NPR state, for Fabric use 1 sec.
+		 */
+		if (nlp->nlp_type & NLP_FABRIC) {
+			mod_timer(&nlp->nlp_tmofunc, jiffies + HZ);
+		}
+		else {
+			mod_timer(&nlp->nlp_tmofunc,
+			    jiffies + HZ * phba->cfg_nodev_tmo);
+		}
+		spin_lock_irq(phba->host->host_lock);
+		nlp->nlp_flag |= NLP_NODEV_TMO;
+		nlp->nlp_flag &= ~NLP_RCV_PLOGI;
+		spin_unlock_irq(phba->host->host_lock);
+		break;
+	case NLP_JUST_DQ:
+		break;
+	}
+
+	/*
+	 * We make all the calls into the transport after we have
+	 * moved the node between lists. This so that we don't
+	 * release the lock while in-between lists.
+	 */
+
+	/* Don't upcall midlayer if we're unloading */
+	if (!(phba->fc_flag & FC_UNLOADING)) {
+		/*
+		 * We revalidate the rport pointer as the "add" function
+		 * may have removed the remote port.
+		 */
+		if ((rport_del != none) && nlp->rport)
+			fc_remote_port_block(nlp->rport);
+
+		if (rport_add != none) {
+			/*
+			 * Tell the fc transport about the port, if we haven't
+			 * already. If we have, and it's a scsi entity, be
+			 * sure to unblock any attached scsi devices
+			 */
+			if (!nlp->rport)
+				lpfc_register_remote_port(phba, nlp);
+			else
+				fc_remote_port_unblock(nlp->rport);
+
+			/*
+			 * if we added to Mapped list, but the remote port
+			 * registration failed or assigned a target id outside
+			 * our presentable range - move the node to the
+			 * Unmapped List
+			 */
+			if ((rport_add == mapped) &&
+			    ((!nlp->rport) ||
+			     (nlp->rport->scsi_target_id == -1) ||
+			     (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) {
+				nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+				spin_lock_irq(phba->host->host_lock);
+				nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
+				spin_unlock_irq(phba->host->host_lock);
+				lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST);
+			}
+		}
+	}
+	return (0);
+}
+
+/*
+ * Start / ReStart rescue timer for Discovery / RSCN handling
+ */
+void
+lpfc_set_disctmo(struct lpfc_hba * phba)
+{
+	uint32_t tmo;
+
+	tmo = ((phba->fc_ratov * 2) + 1);
+
+	mod_timer(&phba->fc_disctmo, jiffies + HZ * tmo);
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag |= FC_DISC_TMO;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Start Discovery Timer state <hba_state> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0247 Start Discovery Timer state x%x "
+			"Data: x%x x%lx x%x x%x\n",
+			phba->brd_no,
+			phba->hba_state, tmo, (unsigned long)&phba->fc_disctmo,
+			phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+
+	return;
+}
+
+/*
+ * Cancel rescue timer for Discovery / RSCN handling
+ */
+int
+lpfc_can_disctmo(struct lpfc_hba * phba)
+{
+	/* Turn off discovery timer if its running */
+	if (phba->fc_flag & FC_DISC_TMO) {
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~FC_DISC_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+		del_timer_sync(&phba->fc_disctmo);
+		phba->work_hba_events &= ~WORKER_DISC_TMO;
+	}
+
+	/* Cancel Discovery Timer state <hba_state> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0248 Cancel Discovery Timer state x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, phba->hba_state, phba->fc_flag,
+			phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+
+	return (0);
+}
+
+/*
+ * Check specified ring for outstanding IOCB on the SLI queue
+ * Return true if iocb matches the specified nport
+ */
+int
+lpfc_check_sli_ndlp(struct lpfc_hba * phba,
+		    struct lpfc_sli_ring * pring,
+		    struct lpfc_iocbq * iocb, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_sli *psli;
+	IOCB_t *icmd;
+
+	psli = &phba->sli;
+	icmd = &iocb->iocb;
+	if (pring->ringno == LPFC_ELS_RING) {
+		switch (icmd->ulpCommand) {
+		case CMD_GEN_REQUEST64_CR:
+			if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi)
+				return (1);
+		case CMD_ELS_REQUEST64_CR:
+		case CMD_XMIT_ELS_RSP64_CX:
+			if (iocb->context1 == (uint8_t *) ndlp)
+				return (1);
+		}
+	} else if (pring->ringno == psli->ip_ring) {
+
+	} else if (pring->ringno == psli->fcp_ring) {
+		/* Skip match check if waiting to relogin to FCP target */
+		if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
+		  (ndlp->nlp_flag & NLP_DELAY_TMO)) {
+			return (0);
+		}
+		if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) {
+			return (1);
+		}
+	} else if (pring->ringno == psli->next_ring) {
+
+	}
+	return (0);
+}
+
+/*
+ * Free resources / clean up outstanding I/Os
+ * associated with nlp_rpi in the LPFC_NODELIST entry.
+ */
+static int
+lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *iocb, *next_iocb;
+	IOCB_t *icmd;
+	uint32_t rpi, i;
+
+	/*
+	 * Everything that matches on txcmplq will be returned
+	 * by firmware with a no rpi error.
+	 */
+	psli = &phba->sli;
+	rpi = ndlp->nlp_rpi;
+	if (rpi) {
+		/* Now process each ring */
+		for (i = 0; i < psli->num_rings; i++) {
+			pring = &psli->ring[i];
+
+			spin_lock_irq(phba->host->host_lock);
+			list_for_each_entry_safe(iocb, next_iocb, &pring->txq,
+						list) {
+				/*
+				 * Check to see if iocb matches the nport we are
+				 * looking for
+				 */
+				if ((lpfc_check_sli_ndlp
+				     (phba, pring, iocb, ndlp))) {
+					/* It matches, so deque and call compl
+					   with an error */
+					list_del(&iocb->list);
+					pring->txq_cnt--;
+					if (iocb->iocb_cmpl) {
+						icmd = &iocb->iocb;
+						icmd->ulpStatus =
+						    IOSTAT_LOCAL_REJECT;
+						icmd->un.ulpWord[4] =
+						    IOERR_SLI_ABORTED;
+						spin_unlock_irq(phba->host->
+								host_lock);
+						(iocb->iocb_cmpl) (phba,
+								   iocb, iocb);
+						spin_lock_irq(phba->host->
+							      host_lock);
+					} else {
+						list_add_tail(&iocb->list,
+							&phba->lpfc_iocb_list);
+					}
+				}
+			}
+			spin_unlock_irq(phba->host->host_lock);
+
+		}
+	}
+	return (0);
+}
+
+/*
+ * Free rpi associated with LPFC_NODELIST entry.
+ * This routine is called from lpfc_freenode(), when we are removing
+ * a LPFC_NODELIST entry. It is also called if the driver initiates a
+ * LOGO that completes successfully, and we are waiting to PLOGI back
+ * to the remote NPort. In addition, it is called after we receive
+ * and unsolicated ELS cmd, send back a rsp, the rsp completes and
+ * we are waiting to PLOGI back to the remote NPort.
+ */
+int
+lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+
+	if (ndlp->nlp_rpi) {
+		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+			lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox);
+			mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+			rc = lpfc_sli_issue_mbox
+				    (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+			if (rc == MBX_NOT_FINISHED)
+				mempool_free( mbox, phba->mbox_mem_pool);
+		}
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+		lpfc_no_rpi(phba, ndlp);
+		ndlp->nlp_rpi = 0;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Free resources associated with LPFC_NODELIST entry
+ * so it can be freed.
+ */
+static int
+lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+{
+	LPFC_MBOXQ_t       *mb;
+	LPFC_MBOXQ_t       *nextmb;
+	struct lpfc_dmabuf *mp;
+	struct fc_rport *rport;
+
+	/* Cleanup node for NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+			"%d:0900 Cleanup node for NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+			ndlp->nlp_state, ndlp->nlp_rpi);
+
+	lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
+
+	/*
+	 * if unloading the driver - just leave the remote port in place.
+	 * The driver unload will force the attached devices to detach
+	 * and flush cache's w/o generating flush errors.
+	 */
+	if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
+		rport = ndlp->rport;
+		ndlp->rport = NULL;
+		fc_remote_port_unblock(rport);
+		fc_remote_port_delete(rport);
+		ndlp->nlp_sid = NLP_NO_SID;
+	}
+
+	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
+	if ((mb = phba->sli.mbox_active)) {
+		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+			mb->context2 = NULL;
+			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		}
+	}
+	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+			mp = (struct lpfc_dmabuf *) (mb->context1);
+			if (mp) {
+				lpfc_mbuf_free(phba, mp->virt, mp->phys);
+				kfree(mp);
+			}
+			list_del(&mb->list);
+			mempool_free(mb, phba->mbox_mem_pool);
+		}
+	}
+
+	lpfc_els_abort(phba,ndlp,0);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~(NLP_NODEV_TMO|NLP_DELAY_TMO);
+	spin_unlock_irq(phba->host->host_lock);
+	del_timer_sync(&ndlp->nlp_tmofunc);
+
+	del_timer_sync(&ndlp->nlp_delayfunc);
+
+	if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
+		list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
+	if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+		list_del_init(&ndlp->els_retry_evt.evt_listp);
+
+	lpfc_unreg_rpi(phba, ndlp);
+
+	return (0);
+}
+
+/*
+ * Check to see if we can free the nlp back to the freelist.
+ * If we are in the middle of using the nlp in the discovery state
+ * machine, defer the free till we reach the end of the state machine.
+ */
+int
+lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+{
+	if (ndlp->nlp_flag & NLP_NODEV_TMO) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_NODEV_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+		del_timer_sync(&ndlp->nlp_tmofunc);
+		if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
+			list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
+
+	}
+
+
+	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+		del_timer_sync(&ndlp->nlp_delayfunc);
+		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+			list_del_init(&ndlp->els_retry_evt.evt_listp);
+	}
+
+	if (ndlp->nlp_disc_refcnt) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_REMOVE;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	else {
+		lpfc_freenode(phba, ndlp);
+		mempool_free( ndlp, phba->nlp_mem_pool);
+	}
+	return(0);
+}
+
+static int
+lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
+{
+	D_ID mydid;
+	D_ID ndlpdid;
+	D_ID matchdid;
+
+	if (did == Bcast_DID)
+		return (0);
+
+	if (ndlp->nlp_DID == 0) {
+		return (0);
+	}
+
+	/* First check for Direct match */
+	if (ndlp->nlp_DID == did)
+		return (1);
+
+	/* Next check for area/domain identically equals 0 match */
+	mydid.un.word = phba->fc_myDID;
+	if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
+		return (0);
+	}
+
+	matchdid.un.word = did;
+	ndlpdid.un.word = ndlp->nlp_DID;
+	if (matchdid.un.b.id == ndlpdid.un.b.id) {
+		if ((mydid.un.b.domain == matchdid.un.b.domain) &&
+		    (mydid.un.b.area == matchdid.un.b.area)) {
+			if ((ndlpdid.un.b.domain == 0) &&
+			    (ndlpdid.un.b.area == 0)) {
+				if (ndlpdid.un.b.id)
+					return (1);
+			}
+			return (0);
+		}
+
+		matchdid.un.word = ndlp->nlp_DID;
+		if ((mydid.un.b.domain == ndlpdid.un.b.domain) &&
+		    (mydid.un.b.area == ndlpdid.un.b.area)) {
+			if ((matchdid.un.b.domain == 0) &&
+			    (matchdid.un.b.area == 0)) {
+				if (matchdid.un.b.id)
+					return (1);
+			}
+		}
+	}
+	return (0);
+}
+
+/* Search for a nodelist entry on a specific list */
+struct lpfc_nodelist *
+lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
+{
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+	uint32_t data1;
+
+	if (order & NLP_SEARCH_UNMAPPED) {
+		list_for_each_entry_safe(ndlp, next_ndlp,
+					 &phba->fc_nlpunmap_list, nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* FIND node DID unmapped */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0929 FIND node DID unmapped"
+						" Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_MAPPED) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* FIND node DID mapped */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0930 FIND node DID mapped "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_PLOGI) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to PLOGI */
+				/* FIND node DID plogi */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0908 FIND node DID plogi "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_ADISC) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to ADISC */
+				/* FIND node DID adisc */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0931 FIND node DID adisc "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_REGLOGIN) {
+		list_for_each_entry_safe(ndlp, next_ndlp,
+					 &phba->fc_reglogin_list, nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to REGLOGIN */
+				/* FIND node DID reglogin */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0931 FIND node DID reglogin"
+						" Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_PRLI) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to PRLI */
+				/* FIND node DID prli */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0931 FIND node DID prli "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_NPR) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to NPR */
+				/* FIND node DID npr */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0931 FIND node DID npr "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	if (order & NLP_SEARCH_UNUSED) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
+					nlp_listp) {
+			if (lpfc_matchdid(phba, ndlp, did)) {
+
+				data1 = (((uint32_t) ndlp->nlp_state << 24) |
+					 ((uint32_t) ndlp->nlp_xri << 16) |
+					 ((uint32_t) ndlp->nlp_type << 8) |
+					 ((uint32_t) ndlp->nlp_rpi & 0xff));
+				/* LOG change to UNUSED */
+				/* FIND node DID unused */
+				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+						"%d:0931 FIND node DID unused "
+						"Data: x%p x%x x%x x%x\n",
+						phba->brd_no,
+						ndlp, ndlp->nlp_DID,
+						ndlp->nlp_flag, data1);
+				return (ndlp);
+			}
+		}
+	}
+
+	/* FIND node did <did> NOT FOUND */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_NODE,
+			"%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
+			phba->brd_no, did, order);
+
+	/* no match found */
+	return NULL;
+}
+
+struct lpfc_nodelist *
+lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
+{
+	struct lpfc_nodelist *ndlp;
+	uint32_t flg;
+
+	if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did)) == 0) {
+		if ((phba->hba_state == LPFC_HBA_READY) &&
+		   ((lpfc_rscn_payload_check(phba, did) == 0)))
+			return NULL;
+		ndlp = (struct lpfc_nodelist *)
+		     mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+		if (!ndlp)
+			return NULL;
+		lpfc_nlp_init(phba, ndlp, did);
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+		return ndlp;
+	}
+	if ((phba->hba_state == LPFC_HBA_READY) &&
+	    (phba->fc_flag & FC_RSCN_MODE)) {
+		if (lpfc_rscn_payload_check(phba, did)) {
+			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+		}
+		else {
+			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+			ndlp = NULL;
+		}
+	}
+	else {
+		flg = ndlp->nlp_flag & NLP_LIST_MASK;
+		if ((flg == NLP_ADISC_LIST) ||
+		(flg == NLP_PLOGI_LIST)) {
+			return NULL;
+		}
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+	}
+	return ndlp;
+}
+
+/* Build a list of nodes to discover based on the loopmap */
+void
+lpfc_disc_list_loopmap(struct lpfc_hba * phba)
+{
+	int j;
+	uint32_t alpa, index;
+
+	if (phba->hba_state <= LPFC_LINK_DOWN) {
+		return;
+	}
+	if (phba->fc_topology != TOPOLOGY_LOOP) {
+		return;
+	}
+
+	/* Check for loop map present or not */
+	if (phba->alpa_map[0]) {
+		for (j = 1; j <= phba->alpa_map[0]; j++) {
+			alpa = phba->alpa_map[j];
+
+			if (((phba->fc_myDID & 0xff) == alpa) || (alpa == 0)) {
+				continue;
+			}
+			lpfc_setup_disc_node(phba, alpa);
+		}
+	} else {
+		/* No alpamap, so try all alpa's */
+		for (j = 0; j < FC_MAXLOOP; j++) {
+			/* If cfg_scan_down is set, start from highest
+			 * ALPA (0xef) to lowest (0x1).
+			 */
+			if (phba->cfg_scan_down)
+				index = j;
+			else
+				index = FC_MAXLOOP - j - 1;
+			alpa = lpfcAlpaArray[index];
+			if ((phba->fc_myDID & 0xff) == alpa) {
+				continue;
+			}
+
+			lpfc_setup_disc_node(phba, alpa);
+		}
+	}
+	return;
+}
+
+/* Start Link up / RSCN discovery on NPR list */
+void
+lpfc_disc_start(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli;
+	LPFC_MBOXQ_t *mbox;
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+	uint32_t did_changed, num_sent;
+	uint32_t clear_la_pending;
+	int rc;
+
+	psli = &phba->sli;
+
+	if (phba->hba_state <= LPFC_LINK_DOWN) {
+		return;
+	}
+	if (phba->hba_state == LPFC_CLEAR_LA)
+		clear_la_pending = 1;
+	else
+		clear_la_pending = 0;
+
+	if (phba->hba_state < LPFC_HBA_READY) {
+		phba->hba_state = LPFC_DISC_AUTH;
+	}
+	lpfc_set_disctmo(phba);
+
+	if (phba->fc_prevDID == phba->fc_myDID) {
+		did_changed = 0;
+	} else {
+		did_changed = 1;
+	}
+	phba->fc_prevDID = phba->fc_myDID;
+	phba->num_disc_nodes = 0;
+
+	/* Start Discovery state <hba_state> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0202 Start Discovery hba state x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, phba->hba_state, phba->fc_flag,
+			phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+
+	/* If our did changed, we MUST do PLOGI */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+				nlp_listp) {
+		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+			if (did_changed) {
+				spin_lock_irq(phba->host->host_lock);
+				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+				spin_unlock_irq(phba->host->host_lock);
+			}
+		}
+	}
+
+	/* First do ADISCs - if any */
+	num_sent = lpfc_els_disc_adisc(phba);
+
+	if (num_sent)
+		return;
+
+	if ((phba->hba_state < LPFC_HBA_READY) && (!clear_la_pending)) {
+		/* If we get here, there is nothing to ADISC */
+		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+			phba->hba_state = LPFC_CLEAR_LA;
+			lpfc_clear_la(phba, mbox);
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+			rc = lpfc_sli_issue_mbox(phba, mbox,
+						 (MBX_NOWAIT | MBX_STOP_IOCB));
+			if (rc == MBX_NOT_FINISHED) {
+				mempool_free( mbox, phba->mbox_mem_pool);
+				lpfc_disc_flush_list(phba);
+				psli->ring[(psli->ip_ring)].flag &=
+					~LPFC_STOP_IOCB_EVENT;
+				psli->ring[(psli->fcp_ring)].flag &=
+					~LPFC_STOP_IOCB_EVENT;
+				psli->ring[(psli->next_ring)].flag &=
+					~LPFC_STOP_IOCB_EVENT;
+				phba->hba_state = LPFC_HBA_READY;
+			}
+		}
+	} else {
+		/* Next do PLOGIs - if any */
+		num_sent = lpfc_els_disc_plogi(phba);
+
+		if (num_sent)
+			return;
+
+		if (phba->fc_flag & FC_RSCN_MODE) {
+			/* Check to see if more RSCNs came in while we
+			 * were processing this one.
+			 */
+			if ((phba->fc_rscn_id_cnt == 0) &&
+			    (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+				spin_lock_irq(phba->host->host_lock);
+				phba->fc_flag &= ~FC_RSCN_MODE;
+				spin_unlock_irq(phba->host->host_lock);
+			}
+			else
+				lpfc_els_handle_rscn(phba);
+		}
+	}
+	return;
+}
+
+/*
+ *  Ignore completion for all IOCBs on tx and txcmpl queue for ELS
+ *  ring the match the sppecified nodelist.
+ */
+static void
+lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+{
+	struct lpfc_sli *psli;
+	IOCB_t     *icmd;
+	struct lpfc_iocbq    *iocb, *next_iocb;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_dmabuf   *mp;
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];
+
+	/* Error matching iocb on txq or txcmplq
+	 * First check the txq.
+	 */
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+		if (iocb->context1 != ndlp) {
+			continue;
+		}
+		icmd = &iocb->iocb;
+		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
+		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+
+			list_del(&iocb->list);
+			pring->txq_cnt--;
+			lpfc_els_free_iocb(phba, iocb);
+		}
+	}
+
+	/* Next check the txcmplq */
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		if (iocb->context1 != ndlp) {
+			continue;
+		}
+		icmd = &iocb->iocb;
+		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
+		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+
+			iocb->iocb_cmpl = NULL;
+			/* context2 = cmd, context2->next = rsp, context3 =
+			   bpl */
+			if (iocb->context2) {
+				/* Free the response IOCB before handling the
+				   command. */
+
+				mp = (struct lpfc_dmabuf *) (iocb->context2);
+				mp = list_get_first(&mp->list,
+						    struct lpfc_dmabuf,
+						    list);
+				if (mp) {
+					/* Delay before releasing rsp buffer to
+					 * give UNREG mbox a chance to take
+					 * effect.
+					 */
+					list_add(&mp->list,
+						&phba->freebufList);
+				}
+				lpfc_mbuf_free(phba,
+					       ((struct lpfc_dmabuf *)
+						iocb->context2)->virt,
+					       ((struct lpfc_dmabuf *)
+						iocb->context2)->phys);
+				kfree(iocb->context2);
+			}
+
+			if (iocb->context3) {
+				lpfc_mbuf_free(phba,
+					       ((struct lpfc_dmabuf *)
+						iocb->context3)->virt,
+					       ((struct lpfc_dmabuf *)
+						iocb->context3)->phys);
+				kfree(iocb->context3);
+			}
+		}
+	}
+
+	return;
+}
+
+void
+lpfc_disc_flush_list(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+
+	if (phba->fc_plogi_cnt) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
+					nlp_listp) {
+			lpfc_free_tx(phba, ndlp);
+			lpfc_nlp_remove(phba, ndlp);
+		}
+	}
+	if (phba->fc_adisc_cnt) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
+					nlp_listp) {
+			lpfc_free_tx(phba, ndlp);
+			lpfc_nlp_remove(phba, ndlp);
+		}
+	}
+	return;
+}
+
+/*****************************************************************************/
+/*
+ * NAME:     lpfc_disc_timeout
+ *
+ * FUNCTION: Fibre Channel driver discovery timeout routine.
+ *
+ * EXECUTION ENVIRONMENT: interrupt only
+ *
+ * CALLED FROM:
+ *      Timer function
+ *
+ * RETURNS:
+ *      none
+ */
+/*****************************************************************************/
+void
+lpfc_disc_timeout(unsigned long ptr)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+	unsigned long flags = 0;
+
+	if (unlikely(!phba))
+		return;
+
+	spin_lock_irqsave(phba->host->host_lock, flags);
+	if (!(phba->work_hba_events & WORKER_DISC_TMO)) {
+		phba->work_hba_events |= WORKER_DISC_TMO;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+	return;
+}
+
+static void
+lpfc_disc_timeout_handler(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_nodelist *ndlp;
+	LPFC_MBOXQ_t *clearlambox, *initlinkmbox;
+	int rc, clrlaerr = 0;
+
+	if (unlikely(!phba))
+		return;
+
+	if (!(phba->fc_flag & FC_DISC_TMO))
+		return;
+
+	psli = &phba->sli;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~FC_DISC_TMO;
+	spin_unlock_irq(phba->host->host_lock);
+
+	switch (phba->hba_state) {
+
+	case LPFC_LOCAL_CFG_LINK:
+	/* hba_state is identically LPFC_LOCAL_CFG_LINK while waiting for FAN */
+		/* FAN timeout */
+		lpfc_printf_log(phba,
+				 KERN_WARNING,
+				 LOG_DISCOVERY,
+				 "%d:0221 FAN timeout\n",
+				 phba->brd_no);
+
+		/* Forget about FAN, Start discovery by sending a FLOGI
+		 * hba_state is identically LPFC_FLOGI while waiting for FLOGI
+		 * cmpl
+		 */
+		phba->hba_state = LPFC_FLOGI;
+		lpfc_set_disctmo(phba);
+		lpfc_initial_flogi(phba);
+		break;
+
+	case LPFC_FLOGI:
+	/* hba_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
+		/* Initial FLOGI timeout */
+		lpfc_printf_log(phba,
+				 KERN_ERR,
+				 LOG_DISCOVERY,
+				 "%d:0222 Initial FLOGI timeout\n",
+				 phba->brd_no);
+
+		/* Assume no Fabric and go on with discovery.
+		 * Check for outstanding ELS FLOGI to abort.
+		 */
+
+		/* FLOGI failed, so just use loop map to make discovery list */
+		lpfc_disc_list_loopmap(phba);
+
+		/* Start discovery */
+		lpfc_disc_start(phba);
+		break;
+
+	case LPFC_FABRIC_CFG_LINK:
+	/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
+	   NameServer login */
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+				"%d:0223 Timeout while waiting for NameServer "
+				"login\n", phba->brd_no);
+
+		/* Next look for NameServer ndlp */
+		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+		if (ndlp)
+			lpfc_nlp_remove(phba, ndlp);
+		/* Start discovery */
+		lpfc_disc_start(phba);
+		break;
+
+	case LPFC_NS_QRY:
+	/* Check for wait for NameServer Rsp timeout */
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+				"%d:0224 NameServer Query timeout "
+				"Data: x%x x%x\n",
+				phba->brd_no,
+				phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
+
+		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
+								NameServer_DID);
+		if (ndlp) {
+			if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+				/* Try it one more time */
+				rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
+				if (rc == 0)
+					break;
+			}
+			phba->fc_ns_retry = 0;
+		}
+
+		/* Nothing to authenticate, so CLEAR_LA right now */
+		clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!clearlambox) {
+			clrlaerr = 1;
+			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+					"%d:0226 Device Discovery "
+					"completion error\n",
+					phba->brd_no);
+			phba->hba_state = LPFC_HBA_ERROR;
+			break;
+		}
+
+		phba->hba_state = LPFC_CLEAR_LA;
+		lpfc_clear_la(phba, clearlambox);
+		clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+		rc = lpfc_sli_issue_mbox(phba, clearlambox,
+					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		if (rc == MBX_NOT_FINISHED) {
+			mempool_free(clearlambox, phba->mbox_mem_pool);
+			clrlaerr = 1;
+			break;
+		}
+
+		/* Setup and issue mailbox INITIALIZE LINK command */
+		initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!initlinkmbox) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+					"%d:0226 Device Discovery "
+					"completion error\n",
+					phba->brd_no);
+			phba->hba_state = LPFC_HBA_ERROR;
+			break;
+		}
+
+		lpfc_linkdown(phba);
+		lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
+			       phba->cfg_link_speed);
+		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
+					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		if (rc == MBX_NOT_FINISHED)
+			mempool_free(initlinkmbox, phba->mbox_mem_pool);
+
+		break;
+
+	case LPFC_DISC_AUTH:
+	/* Node Authentication timeout */
+		lpfc_printf_log(phba,
+				 KERN_ERR,
+				 LOG_DISCOVERY,
+				 "%d:0227 Node Authentication timeout\n",
+				 phba->brd_no);
+		lpfc_disc_flush_list(phba);
+		clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!clearlambox) {
+			clrlaerr = 1;
+			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+					"%d:0226 Device Discovery "
+					"completion error\n",
+					phba->brd_no);
+			phba->hba_state = LPFC_HBA_ERROR;
+			break;
+		}
+		phba->hba_state = LPFC_CLEAR_LA;
+		lpfc_clear_la(phba, clearlambox);
+		clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+		rc = lpfc_sli_issue_mbox(phba, clearlambox,
+					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		if (rc == MBX_NOT_FINISHED) {
+			mempool_free(clearlambox, phba->mbox_mem_pool);
+			clrlaerr = 1;
+		}
+		break;
+
+	case LPFC_CLEAR_LA:
+	/* CLEAR LA timeout */
+		lpfc_printf_log(phba,
+				 KERN_ERR,
+				 LOG_DISCOVERY,
+				 "%d:0228 CLEAR LA timeout\n",
+				 phba->brd_no);
+		clrlaerr = 1;
+		break;
+
+	case LPFC_HBA_READY:
+		if (phba->fc_flag & FC_RSCN_MODE) {
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_DISCOVERY,
+					"%d:0231 RSCN timeout Data: x%x x%x\n",
+					phba->brd_no,
+					phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
+
+			/* Cleanup any outstanding ELS commands */
+			lpfc_els_flush_cmd(phba);
+
+			lpfc_els_flush_rscn(phba);
+			lpfc_disc_flush_list(phba);
+		}
+		break;
+	}
+
+	if (clrlaerr) {
+		lpfc_disc_flush_list(phba);
+		psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+		psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+		psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+		phba->hba_state = LPFC_HBA_READY;
+	}
+
+	return;
+}
+
+static void
+lpfc_nodev_timeout(unsigned long ptr)
+{
+	struct lpfc_hba *phba;
+	struct lpfc_nodelist *ndlp;
+	unsigned long iflag;
+	struct lpfc_work_evt  *evtp;
+
+	ndlp = (struct lpfc_nodelist *)ptr;
+	phba = ndlp->nlp_phba;
+	evtp = &ndlp->nodev_timeout_evt;
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+
+	if (!list_empty(&evtp->evt_listp)) {
+		spin_unlock_irqrestore(phba->host->host_lock, iflag);
+		return;
+	}
+	evtp->evt_arg1  = ndlp;
+	evtp->evt       = LPFC_EVT_NODEV_TMO;
+	list_add_tail(&evtp->evt_listp, &phba->work_list);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return;
+}
+
+
+/*
+ * This routine handles processing a NameServer REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is
+ * handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ndlp;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+
+	ndlp = (struct lpfc_nodelist *) pmb->context2;
+	mp = (struct lpfc_dmabuf *) (pmb->context1);
+
+	pmb->context1 = NULL;
+
+	if (ndlp->nlp_rpi != 0)
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+	ndlp->nlp_rpi = mb->un.varWords[0];
+	lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi);
+	ndlp->nlp_type |= NLP_FABRIC;
+	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+
+	/* Start issuing Fabric-Device Management Interface (FDMI)
+	 * command to 0xfffffa (FDMI well known port)
+	 */
+	if (phba->cfg_fdmi_on == 1) {
+		lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
+	} else {
+		/*
+		 * Delay issuing FDMI command if fdmi-on=2
+		 * (supporting RPA/hostnmae)
+		 */
+		mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
+	}
+
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free( pmb, phba->mbox_mem_pool);
+
+	return;
+}
+
+/*
+ * This routine looks up the ndlp hash
+ * table for the given RPI. If rpi found
+ * it return the node list pointer
+ * else return 0.
+ */
+struct lpfc_nodelist *
+lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
+{
+	struct lpfc_nodelist *ret;
+
+	ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)];
+	while ((ret != 0) && (ret->nlp_rpi != rpi)) {
+		ret = ret->nlp_rpi_hash_next;
+	}
+	return ret;
+}
+
+/*
+ * This routine looks up the ndlp hash table for the
+ * given RPI. If rpi found it return the node list
+ * pointer else return 0 after deleting the entry
+ * from hash table.
+ */
+struct lpfc_nodelist *
+lpfc_findnode_remove_rpi(struct lpfc_hba * phba, uint16_t rpi)
+{
+	struct lpfc_nodelist *ret, *temp;;
+
+	ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)];
+	if (ret == 0)
+		return NULL;
+
+	if (ret->nlp_rpi == rpi) {
+		phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)] =
+		    ret->nlp_rpi_hash_next;
+		ret->nlp_rpi_hash_next = NULL;
+		return ret;
+	}
+
+	while ((ret->nlp_rpi_hash_next != 0) &&
+	       (ret->nlp_rpi_hash_next->nlp_rpi != rpi)) {
+		ret = ret->nlp_rpi_hash_next;
+	}
+
+	if (ret->nlp_rpi_hash_next != 0) {
+		temp = ret->nlp_rpi_hash_next;
+		ret->nlp_rpi_hash_next = temp->nlp_rpi_hash_next;
+		temp->nlp_rpi_hash_next = NULL;
+		return temp;
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * This routine adds the node list entry to the
+ * ndlp hash table.
+ */
+void
+lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		 uint16_t rpi)
+{
+
+	uint32_t index;
+
+	index = LPFC_RPI_HASH_FUNC(rpi);
+	ndlp->nlp_rpi_hash_next = phba->fc_nlplookup[index];
+	phba->fc_nlplookup[index] = ndlp;
+	return;
+}
+
+void
+lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		 uint32_t did)
+{
+	memset(ndlp, 0, sizeof (struct lpfc_nodelist));
+	INIT_LIST_HEAD(&ndlp->nodev_timeout_evt.evt_listp);
+	INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
+	init_timer(&ndlp->nlp_tmofunc);
+	ndlp->nlp_tmofunc.function = lpfc_nodev_timeout;
+	ndlp->nlp_tmofunc.data = (unsigned long)ndlp;
+	init_timer(&ndlp->nlp_delayfunc);
+	ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
+	ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
+	ndlp->nlp_DID = did;
+	ndlp->nlp_phba = phba;
+	ndlp->nlp_sid = NLP_NO_SID;
+	return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -0,0 +1,2687 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_hw.h 1.37 2005/03/29 19:51:45EST sf_support Exp  $
+ */
+
+#define FDMI_DID        0xfffffaU
+#define NameServer_DID  0xfffffcU
+#define SCR_DID         0xfffffdU
+#define Fabric_DID      0xfffffeU
+#define Bcast_DID       0xffffffU
+#define Mask_DID        0xffffffU
+#define CT_DID_MASK     0xffff00U
+#define Fabric_DID_MASK 0xfff000U
+#define WELL_KNOWN_DID_MASK 0xfffff0U
+
+#define PT2PT_LocalID	1
+#define PT2PT_RemoteID	2
+
+#define FF_DEF_EDTOV          2000	/* Default E_D_TOV (2000ms) */
+#define FF_DEF_ALTOV            15	/* Default AL_TIME (15ms) */
+#define FF_DEF_RATOV             2	/* Default RA_TOV (2s) */
+#define FF_DEF_ARBTOV         1900	/* Default ARB_TOV (1900ms) */
+
+#define LPFC_BUF_RING0        64	/* Number of buffers to post to RING
+					   0 */
+
+#define FCELSSIZE             1024	/* maximum ELS transfer size */
+
+#define LPFC_FCP_RING            0	/* ring 0 for FCP initiator commands */
+#define LPFC_IP_RING             1	/* ring 1 for IP commands */
+#define LPFC_ELS_RING            2	/* ring 2 for ELS commands */
+#define LPFC_FCP_NEXT_RING       3
+
+#define SLI2_IOCB_CMD_R0_ENTRIES    172	/* SLI-2 FCP command ring entries */
+#define SLI2_IOCB_RSP_R0_ENTRIES    134	/* SLI-2 FCP response ring entries */
+#define SLI2_IOCB_CMD_R1_ENTRIES      4	/* SLI-2 IP command ring entries */
+#define SLI2_IOCB_RSP_R1_ENTRIES      4	/* SLI-2 IP response ring entries */
+#define SLI2_IOCB_CMD_R1XTRA_ENTRIES 36	/* SLI-2 extra FCP cmd ring entries */
+#define SLI2_IOCB_RSP_R1XTRA_ENTRIES 52	/* SLI-2 extra FCP rsp ring entries */
+#define SLI2_IOCB_CMD_R2_ENTRIES     20	/* SLI-2 ELS command ring entries */
+#define SLI2_IOCB_RSP_R2_ENTRIES     20	/* SLI-2 ELS response ring entries */
+#define SLI2_IOCB_CMD_R3_ENTRIES      0
+#define SLI2_IOCB_RSP_R3_ENTRIES      0
+#define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24
+#define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32
+
+/* Common Transport structures and definitions */
+
+union CtRevisionId {
+	/* Structure is in Big Endian format */
+	struct {
+		uint32_t Revision:8;
+		uint32_t InId:24;
+	} bits;
+	uint32_t word;
+};
+
+union CtCommandResponse {
+	/* Structure is in Big Endian format */
+	struct {
+		uint32_t CmdRsp:16;
+		uint32_t Size:16;
+	} bits;
+	uint32_t word;
+};
+
+struct lpfc_sli_ct_request {
+	/* Structure is in Big Endian format */
+	union CtRevisionId RevisionId;
+	uint8_t FsType;
+	uint8_t FsSubType;
+	uint8_t Options;
+	uint8_t Rsrvd1;
+	union CtCommandResponse CommandResponse;
+	uint8_t Rsrvd2;
+	uint8_t ReasonCode;
+	uint8_t Explanation;
+	uint8_t VendorUnique;
+
+	union {
+		uint32_t PortID;
+		struct gid {
+			uint8_t PortType;	/* for GID_PT requests */
+			uint8_t DomainScope;
+			uint8_t AreaScope;
+			uint8_t Fc4Type;	/* for GID_FT requests */
+		} gid;
+		struct rft {
+			uint32_t PortId;	/* For RFT_ID requests */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint32_t rsvd0:16;
+			uint32_t rsvd1:7;
+			uint32_t fcpReg:1;	/* Type 8 */
+			uint32_t rsvd2:2;
+			uint32_t ipReg:1;	/* Type 5 */
+			uint32_t rsvd3:5;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint32_t rsvd0:16;
+			uint32_t fcpReg:1;	/* Type 8 */
+			uint32_t rsvd1:7;
+			uint32_t rsvd3:5;
+			uint32_t ipReg:1;	/* Type 5 */
+			uint32_t rsvd2:2;
+#endif
+
+			uint32_t rsvd[7];
+		} rft;
+		struct rnn {
+			uint32_t PortId;	/* For RNN_ID requests */
+			uint8_t wwnn[8];
+		} rnn;
+		struct rsnn {	/* For RSNN_ID requests */
+			uint8_t wwnn[8];
+			uint8_t len;
+			uint8_t symbname[255];
+		} rsnn;
+	} un;
+};
+
+#define  SLI_CT_REVISION        1
+#define  GID_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 260)
+#define  RFT_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 228)
+#define  RNN_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 252)
+#define  RSNN_REQUEST_SZ        (sizeof(struct lpfc_sli_ct_request))
+
+/*
+ * FsType Definitions
+ */
+
+#define  SLI_CT_MANAGEMENT_SERVICE        0xFA
+#define  SLI_CT_TIME_SERVICE              0xFB
+#define  SLI_CT_DIRECTORY_SERVICE         0xFC
+#define  SLI_CT_FABRIC_CONTROLLER_SERVICE 0xFD
+
+/*
+ * Directory Service Subtypes
+ */
+
+#define  SLI_CT_DIRECTORY_NAME_SERVER     0x02
+
+/*
+ * Response Codes
+ */
+
+#define  SLI_CT_RESPONSE_FS_RJT           0x8001
+#define  SLI_CT_RESPONSE_FS_ACC           0x8002
+
+/*
+ * Reason Codes
+ */
+
+#define  SLI_CT_NO_ADDITIONAL_EXPL	  0x0
+#define  SLI_CT_INVALID_COMMAND           0x01
+#define  SLI_CT_INVALID_VERSION           0x02
+#define  SLI_CT_LOGICAL_ERROR             0x03
+#define  SLI_CT_INVALID_IU_SIZE           0x04
+#define  SLI_CT_LOGICAL_BUSY              0x05
+#define  SLI_CT_PROTOCOL_ERROR            0x07
+#define  SLI_CT_UNABLE_TO_PERFORM_REQ     0x09
+#define  SLI_CT_REQ_NOT_SUPPORTED         0x0b
+#define  SLI_CT_HBA_INFO_NOT_REGISTERED	  0x10
+#define  SLI_CT_MULTIPLE_HBA_ATTR_OF_SAME_TYPE  0x11
+#define  SLI_CT_INVALID_HBA_ATTR_BLOCK_LEN      0x12
+#define  SLI_CT_HBA_ATTR_NOT_PRESENT	  0x13
+#define  SLI_CT_PORT_INFO_NOT_REGISTERED  0x20
+#define  SLI_CT_MULTIPLE_PORT_ATTR_OF_SAME_TYPE 0x21
+#define  SLI_CT_INVALID_PORT_ATTR_BLOCK_LEN     0x22
+#define  SLI_CT_VENDOR_UNIQUE             0xff
+
+/*
+ * Name Server SLI_CT_UNABLE_TO_PERFORM_REQ Explanations
+ */
+
+#define  SLI_CT_NO_PORT_ID                0x01
+#define  SLI_CT_NO_PORT_NAME              0x02
+#define  SLI_CT_NO_NODE_NAME              0x03
+#define  SLI_CT_NO_CLASS_OF_SERVICE       0x04
+#define  SLI_CT_NO_IP_ADDRESS             0x05
+#define  SLI_CT_NO_IPA                    0x06
+#define  SLI_CT_NO_FC4_TYPES              0x07
+#define  SLI_CT_NO_SYMBOLIC_PORT_NAME     0x08
+#define  SLI_CT_NO_SYMBOLIC_NODE_NAME     0x09
+#define  SLI_CT_NO_PORT_TYPE              0x0A
+#define  SLI_CT_ACCESS_DENIED             0x10
+#define  SLI_CT_INVALID_PORT_ID           0x11
+#define  SLI_CT_DATABASE_EMPTY            0x12
+
+/*
+ * Name Server Command Codes
+ */
+
+#define  SLI_CTNS_GA_NXT      0x0100
+#define  SLI_CTNS_GPN_ID      0x0112
+#define  SLI_CTNS_GNN_ID      0x0113
+#define  SLI_CTNS_GCS_ID      0x0114
+#define  SLI_CTNS_GFT_ID      0x0117
+#define  SLI_CTNS_GSPN_ID     0x0118
+#define  SLI_CTNS_GPT_ID      0x011A
+#define  SLI_CTNS_GID_PN      0x0121
+#define  SLI_CTNS_GID_NN      0x0131
+#define  SLI_CTNS_GIP_NN      0x0135
+#define  SLI_CTNS_GIPA_NN     0x0136
+#define  SLI_CTNS_GSNN_NN     0x0139
+#define  SLI_CTNS_GNN_IP      0x0153
+#define  SLI_CTNS_GIPA_IP     0x0156
+#define  SLI_CTNS_GID_FT      0x0171
+#define  SLI_CTNS_GID_PT      0x01A1
+#define  SLI_CTNS_RPN_ID      0x0212
+#define  SLI_CTNS_RNN_ID      0x0213
+#define  SLI_CTNS_RCS_ID      0x0214
+#define  SLI_CTNS_RFT_ID      0x0217
+#define  SLI_CTNS_RSPN_ID     0x0218
+#define  SLI_CTNS_RPT_ID      0x021A
+#define  SLI_CTNS_RIP_NN      0x0235
+#define  SLI_CTNS_RIPA_NN     0x0236
+#define  SLI_CTNS_RSNN_NN     0x0239
+#define  SLI_CTNS_DA_ID       0x0300
+
+/*
+ * Port Types
+ */
+
+#define  SLI_CTPT_N_PORT      0x01
+#define  SLI_CTPT_NL_PORT     0x02
+#define  SLI_CTPT_FNL_PORT    0x03
+#define  SLI_CTPT_IP          0x04
+#define  SLI_CTPT_FCP         0x08
+#define  SLI_CTPT_NX_PORT     0x7F
+#define  SLI_CTPT_F_PORT      0x81
+#define  SLI_CTPT_FL_PORT     0x82
+#define  SLI_CTPT_E_PORT      0x84
+
+#define SLI_CT_LAST_ENTRY     0x80000000
+
+/* Fibre Channel Service Parameter definitions */
+
+#define FC_PH_4_0   6		/* FC-PH version 4.0 */
+#define FC_PH_4_1   7		/* FC-PH version 4.1 */
+#define FC_PH_4_2   8		/* FC-PH version 4.2 */
+#define FC_PH_4_3   9		/* FC-PH version 4.3 */
+
+#define FC_PH_LOW   8		/* Lowest supported FC-PH version */
+#define FC_PH_HIGH  9		/* Highest supported FC-PH version */
+#define FC_PH3   0x20		/* FC-PH-3 version */
+
+#define FF_FRAME_SIZE     2048
+
+struct lpfc_name {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t nameType:4;	/* FC Word 0, bit 28:31 */
+	uint8_t IEEEextMsn:4;	/* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t IEEEextMsn:4;	/* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
+	uint8_t nameType:4;	/* FC Word 0, bit 28:31 */
+#endif
+
+#define NAME_IEEE           0x1	/* IEEE name - nameType */
+#define NAME_IEEE_EXT       0x2	/* IEEE extended name */
+#define NAME_FC_TYPE        0x3	/* FC native name type */
+#define NAME_IP_TYPE        0x4	/* IP address */
+#define NAME_CCITT_TYPE     0xC
+#define NAME_CCITT_GR_TYPE  0xE
+	uint8_t IEEEextLsb;	/* FC Word 0, bit 16:23, IEEE extended Lsb */
+	uint8_t IEEE[6];	/* FC IEEE address */
+};
+
+struct csp {
+	uint8_t fcphHigh;	/* FC Word 0, byte 0 */
+	uint8_t fcphLow;
+	uint8_t bbCreditMsb;
+	uint8_t bbCreditlsb;	/* FC Word 0, byte 3 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */
+	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */
+	uint16_t word1Reserved2:1;	/* FC Word 1, bit 29 */
+	uint16_t fPort:1;	/* FC Word 1, bit 28 */
+	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
+	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
+	uint16_t multicast:1;	/* FC Word 1, bit 25 */
+	uint16_t broadcast:1;	/* FC Word 1, bit 24 */
+
+	uint16_t huntgroup:1;	/* FC Word 1, bit 23 */
+	uint16_t simplex:1;	/* FC Word 1, bit 22 */
+	uint16_t word1Reserved1:3;	/* FC Word 1, bit 21:19 */
+	uint16_t dhd:1;		/* FC Word 1, bit 18 */
+	uint16_t contIncSeqCnt:1;	/* FC Word 1, bit 17 */
+	uint16_t payloadlength:1;	/* FC Word 1, bit 16 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t broadcast:1;	/* FC Word 1, bit 24 */
+	uint16_t multicast:1;	/* FC Word 1, bit 25 */
+	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
+	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
+	uint16_t fPort:1;	/* FC Word 1, bit 28 */
+	uint16_t word1Reserved2:1;	/* FC Word 1, bit 29 */
+	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */
+	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */
+
+	uint16_t payloadlength:1;	/* FC Word 1, bit 16 */
+	uint16_t contIncSeqCnt:1;	/* FC Word 1, bit 17 */
+	uint16_t dhd:1;		/* FC Word 1, bit 18 */
+	uint16_t word1Reserved1:3;	/* FC Word 1, bit 21:19 */
+	uint16_t simplex:1;	/* FC Word 1, bit 22 */
+	uint16_t huntgroup:1;	/* FC Word 1, bit 23 */
+#endif
+
+	uint8_t bbRcvSizeMsb;	/* Upper nibble is reserved */
+	uint8_t bbRcvSizeLsb;	/* FC Word 1, byte 3 */
+	union {
+		struct {
+			uint8_t word2Reserved1;	/* FC Word 2 byte 0 */
+
+			uint8_t totalConcurrSeq;	/* FC Word 2 byte 1 */
+			uint8_t roByCategoryMsb;	/* FC Word 2 byte 2 */
+
+			uint8_t roByCategoryLsb;	/* FC Word 2 byte 3 */
+		} nPort;
+		uint32_t r_a_tov;	/* R_A_TOV must be in B.E. format */
+	} w2;
+
+	uint32_t e_d_tov;	/* E_D_TOV must be in B.E. format */
+};
+
+struct class_parms {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t classValid:1;	/* FC Word 0, bit 31 */
+	uint8_t intermix:1;	/* FC Word 0, bit 30 */
+	uint8_t stackedXparent:1;	/* FC Word 0, bit 29 */
+	uint8_t stackedLockDown:1;	/* FC Word 0, bit 28 */
+	uint8_t seqDelivery:1;	/* FC Word 0, bit 27 */
+	uint8_t word0Reserved1:3;	/* FC Word 0, bit 24:26 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t word0Reserved1:3;	/* FC Word 0, bit 24:26 */
+	uint8_t seqDelivery:1;	/* FC Word 0, bit 27 */
+	uint8_t stackedLockDown:1;	/* FC Word 0, bit 28 */
+	uint8_t stackedXparent:1;	/* FC Word 0, bit 29 */
+	uint8_t intermix:1;	/* FC Word 0, bit 30 */
+	uint8_t classValid:1;	/* FC Word 0, bit 31 */
+
+#endif
+
+	uint8_t word0Reserved2;	/* FC Word 0, bit 16:23 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t iCtlXidReAssgn:2;	/* FC Word 0, Bit 14:15 */
+	uint8_t iCtlInitialPa:2;	/* FC Word 0, bit 12:13 */
+	uint8_t iCtlAck0capable:1;	/* FC Word 0, bit 11 */
+	uint8_t iCtlAckNcapable:1;	/* FC Word 0, bit 10 */
+	uint8_t word0Reserved3:2;	/* FC Word 0, bit  8: 9 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t word0Reserved3:2;	/* FC Word 0, bit  8: 9 */
+	uint8_t iCtlAckNcapable:1;	/* FC Word 0, bit 10 */
+	uint8_t iCtlAck0capable:1;	/* FC Word 0, bit 11 */
+	uint8_t iCtlInitialPa:2;	/* FC Word 0, bit 12:13 */
+	uint8_t iCtlXidReAssgn:2;	/* FC Word 0, Bit 14:15 */
+#endif
+
+	uint8_t word0Reserved4;	/* FC Word 0, bit  0: 7 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t rCtlAck0capable:1;	/* FC Word 1, bit 31 */
+	uint8_t rCtlAckNcapable:1;	/* FC Word 1, bit 30 */
+	uint8_t rCtlXidInterlck:1;	/* FC Word 1, bit 29 */
+	uint8_t rCtlErrorPolicy:2;	/* FC Word 1, bit 27:28 */
+	uint8_t word1Reserved1:1;	/* FC Word 1, bit 26 */
+	uint8_t rCtlCatPerSeq:2;	/* FC Word 1, bit 24:25 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t rCtlCatPerSeq:2;	/* FC Word 1, bit 24:25 */
+	uint8_t word1Reserved1:1;	/* FC Word 1, bit 26 */
+	uint8_t rCtlErrorPolicy:2;	/* FC Word 1, bit 27:28 */
+	uint8_t rCtlXidInterlck:1;	/* FC Word 1, bit 29 */
+	uint8_t rCtlAckNcapable:1;	/* FC Word 1, bit 30 */
+	uint8_t rCtlAck0capable:1;	/* FC Word 1, bit 31 */
+#endif
+
+	uint8_t word1Reserved2;	/* FC Word 1, bit 16:23 */
+	uint8_t rcvDataSizeMsb;	/* FC Word 1, bit  8:15 */
+	uint8_t rcvDataSizeLsb;	/* FC Word 1, bit  0: 7 */
+
+	uint8_t concurrentSeqMsb;	/* FC Word 2, bit 24:31 */
+	uint8_t concurrentSeqLsb;	/* FC Word 2, bit 16:23 */
+	uint8_t EeCreditSeqMsb;	/* FC Word 2, bit  8:15 */
+	uint8_t EeCreditSeqLsb;	/* FC Word 2, bit  0: 7 */
+
+	uint8_t openSeqPerXchgMsb;	/* FC Word 3, bit 24:31 */
+	uint8_t openSeqPerXchgLsb;	/* FC Word 3, bit 16:23 */
+	uint8_t word3Reserved1;	/* Fc Word 3, bit  8:15 */
+	uint8_t word3Reserved2;	/* Fc Word 3, bit  0: 7 */
+};
+
+struct serv_parm {	/* Structure is in Big Endian format */
+	struct csp cmn;
+	struct lpfc_name portName;
+	struct lpfc_name nodeName;
+	struct class_parms cls1;
+	struct class_parms cls2;
+	struct class_parms cls3;
+	struct class_parms cls4;
+	uint8_t vendorVersion[16];
+};
+
+/*
+ *  Extended Link Service LS_COMMAND codes (Payload Word 0)
+ */
+#ifdef __BIG_ENDIAN_BITFIELD
+#define ELS_CMD_MASK      0xffff0000
+#define ELS_RSP_MASK      0xff000000
+#define ELS_CMD_LS_RJT    0x01000000
+#define ELS_CMD_ACC       0x02000000
+#define ELS_CMD_PLOGI     0x03000000
+#define ELS_CMD_FLOGI     0x04000000
+#define ELS_CMD_LOGO      0x05000000
+#define ELS_CMD_ABTX      0x06000000
+#define ELS_CMD_RCS       0x07000000
+#define ELS_CMD_RES       0x08000000
+#define ELS_CMD_RSS       0x09000000
+#define ELS_CMD_RSI       0x0A000000
+#define ELS_CMD_ESTS      0x0B000000
+#define ELS_CMD_ESTC      0x0C000000
+#define ELS_CMD_ADVC      0x0D000000
+#define ELS_CMD_RTV       0x0E000000
+#define ELS_CMD_RLS       0x0F000000
+#define ELS_CMD_ECHO      0x10000000
+#define ELS_CMD_TEST      0x11000000
+#define ELS_CMD_RRQ       0x12000000
+#define ELS_CMD_PRLI      0x20100014
+#define ELS_CMD_PRLO      0x21100014
+#define ELS_CMD_PDISC     0x50000000
+#define ELS_CMD_FDISC     0x51000000
+#define ELS_CMD_ADISC     0x52000000
+#define ELS_CMD_FARP      0x54000000
+#define ELS_CMD_FARPR     0x55000000
+#define ELS_CMD_FAN       0x60000000
+#define ELS_CMD_RSCN      0x61040000
+#define ELS_CMD_SCR       0x62000000
+#define ELS_CMD_RNID      0x78000000
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+#define ELS_CMD_MASK      0xffff
+#define ELS_RSP_MASK      0xff
+#define ELS_CMD_LS_RJT    0x01
+#define ELS_CMD_ACC       0x02
+#define ELS_CMD_PLOGI     0x03
+#define ELS_CMD_FLOGI     0x04
+#define ELS_CMD_LOGO      0x05
+#define ELS_CMD_ABTX      0x06
+#define ELS_CMD_RCS       0x07
+#define ELS_CMD_RES       0x08
+#define ELS_CMD_RSS       0x09
+#define ELS_CMD_RSI       0x0A
+#define ELS_CMD_ESTS      0x0B
+#define ELS_CMD_ESTC      0x0C
+#define ELS_CMD_ADVC      0x0D
+#define ELS_CMD_RTV       0x0E
+#define ELS_CMD_RLS       0x0F
+#define ELS_CMD_ECHO      0x10
+#define ELS_CMD_TEST      0x11
+#define ELS_CMD_RRQ       0x12
+#define ELS_CMD_PRLI      0x14001020
+#define ELS_CMD_PRLO      0x14001021
+#define ELS_CMD_PDISC     0x50
+#define ELS_CMD_FDISC     0x51
+#define ELS_CMD_ADISC     0x52
+#define ELS_CMD_FARP      0x54
+#define ELS_CMD_FARPR     0x55
+#define ELS_CMD_FAN       0x60
+#define ELS_CMD_RSCN      0x0461
+#define ELS_CMD_SCR       0x62
+#define ELS_CMD_RNID      0x78
+#endif
+
+/*
+ *  LS_RJT Payload Definition
+ */
+
+struct ls_rjt {	/* Structure is in Big Endian format */
+	union {
+		uint32_t lsRjtError;
+		struct {
+			uint8_t lsRjtRsvd0;	/* FC Word 0, bit 24:31 */
+
+			uint8_t lsRjtRsnCode;	/* FC Word 0, bit 16:23 */
+			/* LS_RJT reason codes */
+#define LSRJT_INVALID_CMD     0x01
+#define LSRJT_LOGICAL_ERR     0x03
+#define LSRJT_LOGICAL_BSY     0x05
+#define LSRJT_PROTOCOL_ERR    0x07
+#define LSRJT_UNABLE_TPC      0x09	/* Unable to perform command */
+#define LSRJT_CMD_UNSUPPORTED 0x0B
+#define LSRJT_VENDOR_UNIQUE   0xFF	/* See Byte 3 */
+
+			uint8_t lsRjtRsnCodeExp; /* FC Word 0, bit 8:15 */
+			/* LS_RJT reason explanation */
+#define LSEXP_NOTHING_MORE      0x00
+#define LSEXP_SPARM_OPTIONS     0x01
+#define LSEXP_SPARM_ICTL        0x03
+#define LSEXP_SPARM_RCTL        0x05
+#define LSEXP_SPARM_RCV_SIZE    0x07
+#define LSEXP_SPARM_CONCUR_SEQ  0x09
+#define LSEXP_SPARM_CREDIT      0x0B
+#define LSEXP_INVALID_PNAME     0x0D
+#define LSEXP_INVALID_NNAME     0x0E
+#define LSEXP_INVALID_CSP       0x0F
+#define LSEXP_INVALID_ASSOC_HDR 0x11
+#define LSEXP_ASSOC_HDR_REQ     0x13
+#define LSEXP_INVALID_O_SID     0x15
+#define LSEXP_INVALID_OX_RX     0x17
+#define LSEXP_CMD_IN_PROGRESS   0x19
+#define LSEXP_INVALID_NPORT_ID  0x1F
+#define LSEXP_INVALID_SEQ_ID    0x21
+#define LSEXP_INVALID_XCHG      0x23
+#define LSEXP_INACTIVE_XCHG     0x25
+#define LSEXP_RQ_REQUIRED       0x27
+#define LSEXP_OUT_OF_RESOURCE   0x29
+#define LSEXP_CANT_GIVE_DATA    0x2A
+#define LSEXP_REQ_UNSUPPORTED   0x2C
+			uint8_t vendorUnique;	/* FC Word 0, bit  0: 7 */
+		} b;
+	} un;
+};
+
+/*
+ *  N_Port Login (FLOGO/PLOGO Request) Payload Definition
+ */
+
+typedef struct _LOGO {		/* Structure is in Big Endian format */
+	union {
+		uint32_t nPortId32;	/* Access nPortId as a word */
+		struct {
+			uint8_t word1Reserved1;	/* FC Word 1, bit 31:24 */
+			uint8_t nPortIdByte0;	/* N_port  ID bit 16:23 */
+			uint8_t nPortIdByte1;	/* N_port  ID bit  8:15 */
+			uint8_t nPortIdByte2;	/* N_port  ID bit  0: 7 */
+		} b;
+	} un;
+	struct lpfc_name portName;	/* N_port name field */
+} LOGO;
+
+/*
+ *  FCP Login (PRLI Request / ACC) Payload Definition
+ */
+
+#define PRLX_PAGE_LEN   0x10
+#define TPRLO_PAGE_LEN  0x14
+
+typedef struct _PRLI {		/* Structure is in Big Endian format */
+	uint8_t prliType;	/* FC Parm Word 0, bit 24:31 */
+
+#define PRLI_FCP_TYPE 0x08
+	uint8_t word0Reserved1;	/* FC Parm Word 0, bit 16:23 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t origProcAssocV:1;	/* FC Parm Word 0, bit 15 */
+	uint8_t respProcAssocV:1;	/* FC Parm Word 0, bit 14 */
+	uint8_t estabImagePair:1;	/* FC Parm Word 0, bit 13 */
+
+	/*    ACC = imagePairEstablished */
+	uint8_t word0Reserved2:1;	/* FC Parm Word 0, bit 12 */
+	uint8_t acceptRspCode:4;	/* FC Parm Word 0, bit 8:11, ACC ONLY */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t acceptRspCode:4;	/* FC Parm Word 0, bit 8:11, ACC ONLY */
+	uint8_t word0Reserved2:1;	/* FC Parm Word 0, bit 12 */
+	uint8_t estabImagePair:1;	/* FC Parm Word 0, bit 13 */
+	uint8_t respProcAssocV:1;	/* FC Parm Word 0, bit 14 */
+	uint8_t origProcAssocV:1;	/* FC Parm Word 0, bit 15 */
+	/*    ACC = imagePairEstablished */
+#endif
+
+#define PRLI_REQ_EXECUTED     0x1	/* acceptRspCode */
+#define PRLI_NO_RESOURCES     0x2
+#define PRLI_INIT_INCOMPLETE  0x3
+#define PRLI_NO_SUCH_PA       0x4
+#define PRLI_PREDEF_CONFIG    0x5
+#define PRLI_PARTIAL_SUCCESS  0x6
+#define PRLI_INVALID_PAGE_CNT 0x7
+	uint8_t word0Reserved3;	/* FC Parm Word 0, bit 0:7 */
+
+	uint32_t origProcAssoc;	/* FC Parm Word 1, bit 0:31 */
+
+	uint32_t respProcAssoc;	/* FC Parm Word 2, bit 0:31 */
+
+	uint8_t word3Reserved1;	/* FC Parm Word 3, bit 24:31 */
+	uint8_t word3Reserved2;	/* FC Parm Word 3, bit 16:23 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t Word3bit15Resved:1;	/* FC Parm Word 3, bit 15 */
+	uint16_t Word3bit14Resved:1;	/* FC Parm Word 3, bit 14 */
+	uint16_t Word3bit13Resved:1;	/* FC Parm Word 3, bit 13 */
+	uint16_t Word3bit12Resved:1;	/* FC Parm Word 3, bit 12 */
+	uint16_t Word3bit11Resved:1;	/* FC Parm Word 3, bit 11 */
+	uint16_t Word3bit10Resved:1;	/* FC Parm Word 3, bit 10 */
+	uint16_t TaskRetryIdReq:1;	/* FC Parm Word 3, bit  9 */
+	uint16_t Retry:1;	/* FC Parm Word 3, bit  8 */
+	uint16_t ConfmComplAllowed:1;	/* FC Parm Word 3, bit  7 */
+	uint16_t dataOverLay:1;	/* FC Parm Word 3, bit  6 */
+	uint16_t initiatorFunc:1;	/* FC Parm Word 3, bit  5 */
+	uint16_t targetFunc:1;	/* FC Parm Word 3, bit  4 */
+	uint16_t cmdDataMixEna:1;	/* FC Parm Word 3, bit  3 */
+	uint16_t dataRspMixEna:1;	/* FC Parm Word 3, bit  2 */
+	uint16_t readXferRdyDis:1;	/* FC Parm Word 3, bit  1 */
+	uint16_t writeXferRdyDis:1;	/* FC Parm Word 3, bit  0 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t Retry:1;	/* FC Parm Word 3, bit  8 */
+	uint16_t TaskRetryIdReq:1;	/* FC Parm Word 3, bit  9 */
+	uint16_t Word3bit10Resved:1;	/* FC Parm Word 3, bit 10 */
+	uint16_t Word3bit11Resved:1;	/* FC Parm Word 3, bit 11 */
+	uint16_t Word3bit12Resved:1;	/* FC Parm Word 3, bit 12 */
+	uint16_t Word3bit13Resved:1;	/* FC Parm Word 3, bit 13 */
+	uint16_t Word3bit14Resved:1;	/* FC Parm Word 3, bit 14 */
+	uint16_t Word3bit15Resved:1;	/* FC Parm Word 3, bit 15 */
+	uint16_t writeXferRdyDis:1;	/* FC Parm Word 3, bit  0 */
+	uint16_t readXferRdyDis:1;	/* FC Parm Word 3, bit  1 */
+	uint16_t dataRspMixEna:1;	/* FC Parm Word 3, bit  2 */
+	uint16_t cmdDataMixEna:1;	/* FC Parm Word 3, bit  3 */
+	uint16_t targetFunc:1;	/* FC Parm Word 3, bit  4 */
+	uint16_t initiatorFunc:1;	/* FC Parm Word 3, bit  5 */
+	uint16_t dataOverLay:1;	/* FC Parm Word 3, bit  6 */
+	uint16_t ConfmComplAllowed:1;	/* FC Parm Word 3, bit  7 */
+#endif
+} PRLI;
+
+/*
+ *  FCP Logout (PRLO Request / ACC) Payload Definition
+ */
+
+typedef struct _PRLO {		/* Structure is in Big Endian format */
+	uint8_t prloType;	/* FC Parm Word 0, bit 24:31 */
+
+#define PRLO_FCP_TYPE  0x08
+	uint8_t word0Reserved1;	/* FC Parm Word 0, bit 16:23 */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t origProcAssocV:1;	/* FC Parm Word 0, bit 15 */
+	uint8_t respProcAssocV:1;	/* FC Parm Word 0, bit 14 */
+	uint8_t word0Reserved2:2;	/* FC Parm Word 0, bit 12:13 */
+	uint8_t acceptRspCode:4;	/* FC Parm Word 0, bit 8:11, ACC ONLY */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t acceptRspCode:4;	/* FC Parm Word 0, bit 8:11, ACC ONLY */
+	uint8_t word0Reserved2:2;	/* FC Parm Word 0, bit 12:13 */
+	uint8_t respProcAssocV:1;	/* FC Parm Word 0, bit 14 */
+	uint8_t origProcAssocV:1;	/* FC Parm Word 0, bit 15 */
+#endif
+
+#define PRLO_REQ_EXECUTED     0x1	/* acceptRspCode */
+#define PRLO_NO_SUCH_IMAGE    0x4
+#define PRLO_INVALID_PAGE_CNT 0x7
+
+	uint8_t word0Reserved3;	/* FC Parm Word 0, bit 0:7 */
+
+	uint32_t origProcAssoc;	/* FC Parm Word 1, bit 0:31 */
+
+	uint32_t respProcAssoc;	/* FC Parm Word 2, bit 0:31 */
+
+	uint32_t word3Reserved1;	/* FC Parm Word 3, bit 0:31 */
+} PRLO;
+
+typedef struct _ADISC {		/* Structure is in Big Endian format */
+	uint32_t hardAL_PA;
+	struct lpfc_name portName;
+	struct lpfc_name nodeName;
+	uint32_t DID;
+} ADISC;
+
+typedef struct _FARP {		/* Structure is in Big Endian format */
+	uint32_t Mflags:8;
+	uint32_t Odid:24;
+#define FARP_NO_ACTION          0	/* FARP information enclosed, no
+					   action */
+#define FARP_MATCH_PORT         0x1	/* Match on Responder Port Name */
+#define FARP_MATCH_NODE         0x2	/* Match on Responder Node Name */
+#define FARP_MATCH_IP           0x4	/* Match on IP address, not supported */
+#define FARP_MATCH_IPV4         0x5	/* Match on IPV4 address, not
+					   supported */
+#define FARP_MATCH_IPV6         0x6	/* Match on IPV6 address, not
+					   supported */
+	uint32_t Rflags:8;
+	uint32_t Rdid:24;
+#define FARP_REQUEST_PLOGI      0x1	/* Request for PLOGI */
+#define FARP_REQUEST_FARPR      0x2	/* Request for FARP Response */
+	struct lpfc_name OportName;
+	struct lpfc_name OnodeName;
+	struct lpfc_name RportName;
+	struct lpfc_name RnodeName;
+	uint8_t Oipaddr[16];
+	uint8_t Ripaddr[16];
+} FARP;
+
+typedef struct _FAN {		/* Structure is in Big Endian format */
+	uint32_t Fdid;
+	struct lpfc_name FportName;
+	struct lpfc_name FnodeName;
+} FAN;
+
+typedef struct _SCR {		/* Structure is in Big Endian format */
+	uint8_t resvd1;
+	uint8_t resvd2;
+	uint8_t resvd3;
+	uint8_t Function;
+#define  SCR_FUNC_FABRIC     0x01
+#define  SCR_FUNC_NPORT      0x02
+#define  SCR_FUNC_FULL       0x03
+#define  SCR_CLEAR           0xff
+} SCR;
+
+typedef struct _RNID_TOP_DISC {
+	struct lpfc_name portName;
+	uint8_t resvd[8];
+	uint32_t unitType;
+#define RNID_HBA            0x7
+#define RNID_HOST           0xa
+#define RNID_DRIVER         0xd
+	uint32_t physPort;
+	uint32_t attachedNodes;
+	uint16_t ipVersion;
+#define RNID_IPV4           0x1
+#define RNID_IPV6           0x2
+	uint16_t UDPport;
+	uint8_t ipAddr[16];
+	uint16_t resvd1;
+	uint16_t flags;
+#define RNID_TD_SUPPORT     0x1
+#define RNID_LP_VALID       0x2
+} RNID_TOP_DISC;
+
+typedef struct _RNID {		/* Structure is in Big Endian format */
+	uint8_t Format;
+#define RNID_TOPOLOGY_DISC  0xdf
+	uint8_t CommonLen;
+	uint8_t resvd1;
+	uint8_t SpecificLen;
+	struct lpfc_name portName;
+	struct lpfc_name nodeName;
+	union {
+		RNID_TOP_DISC topologyDisc;	/* topology disc (0xdf) */
+	} un;
+} RNID;
+
+typedef struct _RRQ {		/* Structure is in Big Endian format */
+	uint32_t SID;
+	uint16_t Oxid;
+	uint16_t Rxid;
+	uint8_t resv[32];	/* optional association hdr */
+} RRQ;
+
+/* This is used for RSCN command */
+typedef struct _D_ID {		/* Structure is in Big Endian format */
+	union {
+		uint32_t word;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint8_t resv;
+			uint8_t domain;
+			uint8_t area;
+			uint8_t id;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint8_t id;
+			uint8_t area;
+			uint8_t domain;
+			uint8_t resv;
+#endif
+		} b;
+	} un;
+} D_ID;
+
+/*
+ *  Structure to define all ELS Payload types
+ */
+
+typedef struct _ELS_PKT {	/* Structure is in Big Endian format */
+	uint8_t elsCode;	/* FC Word 0, bit 24:31 */
+	uint8_t elsByte1;
+	uint8_t elsByte2;
+	uint8_t elsByte3;
+	union {
+		struct ls_rjt lsRjt;	/* Payload for LS_RJT ELS response */
+		struct serv_parm logi;	/* Payload for PLOGI/FLOGI/PDISC/ACC */
+		LOGO logo;	/* Payload for PLOGO/FLOGO/ACC */
+		PRLI prli;	/* Payload for PRLI/ACC */
+		PRLO prlo;	/* Payload for PRLO/ACC */
+		ADISC adisc;	/* Payload for ADISC/ACC */
+		FARP farp;	/* Payload for FARP/ACC */
+		FAN fan;	/* Payload for FAN */
+		SCR scr;	/* Payload for SCR/ACC */
+		RRQ rrq;	/* Payload for RRQ */
+		RNID rnid;	/* Payload for RNID */
+		uint8_t pad[128 - 4];	/* Pad out to payload of 128 bytes */
+	} un;
+} ELS_PKT;
+
+/*
+ * FDMI
+ * HBA MAnagement Operations Command Codes
+ */
+#define  SLI_MGMT_GRHL     0x100	/* Get registered HBA list */
+#define  SLI_MGMT_GHAT     0x101	/* Get HBA attributes */
+#define  SLI_MGMT_GRPL     0x102	/* Get registered Port list */
+#define  SLI_MGMT_GPAT     0x110	/* Get Port attributes */
+#define  SLI_MGMT_RHBA     0x200	/* Register HBA */
+#define  SLI_MGMT_RHAT     0x201	/* Register HBA atttributes */
+#define  SLI_MGMT_RPRT     0x210	/* Register Port */
+#define  SLI_MGMT_RPA      0x211	/* Register Port attributes */
+#define  SLI_MGMT_DHBA     0x300	/* De-register HBA */
+#define  SLI_MGMT_DPRT     0x310	/* De-register Port */
+
+/*
+ * Management Service Subtypes
+ */
+#define  SLI_CT_FDMI_Subtypes     0x10
+
+/*
+ * HBA Management Service Reject Code
+ */
+#define  REJECT_CODE             0x9	/* Unable to perform command request */
+
+/*
+ * HBA Management Service Reject Reason Code
+ * Please refer to the Reason Codes above
+ */
+
+/*
+ * HBA Attribute Types
+ */
+#define  NODE_NAME               0x1
+#define  MANUFACTURER            0x2
+#define  SERIAL_NUMBER           0x3
+#define  MODEL                   0x4
+#define  MODEL_DESCRIPTION       0x5
+#define  HARDWARE_VERSION        0x6
+#define  DRIVER_VERSION          0x7
+#define  OPTION_ROM_VERSION      0x8
+#define  FIRMWARE_VERSION        0x9
+#define  OS_NAME_VERSION	 0xa
+#define  MAX_CT_PAYLOAD_LEN	 0xb
+
+/*
+ * Port Attrubute Types
+ */
+#define  SUPPORTED_FC4_TYPES     0x1
+#define  SUPPORTED_SPEED         0x2
+#define  PORT_SPEED              0x3
+#define  MAX_FRAME_SIZE          0x4
+#define  OS_DEVICE_NAME          0x5
+#define  HOST_NAME               0x6
+
+union AttributesDef {
+	/* Structure is in Big Endian format */
+	struct {
+		uint32_t AttrType:16;
+		uint32_t AttrLen:16;
+	} bits;
+	uint32_t word;
+};
+
+
+/*
+ * HBA Attribute Entry (8 - 260 bytes)
+ */
+typedef struct {
+	union AttributesDef ad;
+	union {
+		uint32_t VendorSpecific;
+		uint8_t Manufacturer[64];
+		uint8_t SerialNumber[64];
+		uint8_t Model[256];
+		uint8_t ModelDescription[256];
+		uint8_t HardwareVersion[256];
+		uint8_t DriverVersion[256];
+		uint8_t OptionROMVersion[256];
+		uint8_t FirmwareVersion[256];
+		struct lpfc_name NodeName;
+		uint8_t SupportFC4Types[32];
+		uint32_t SupportSpeed;
+		uint32_t PortSpeed;
+		uint32_t MaxFrameSize;
+		uint8_t OsDeviceName[256];
+		uint8_t OsNameVersion[256];
+		uint32_t MaxCTPayloadLen;
+		uint8_t HostName[256];
+	} un;
+} ATTRIBUTE_ENTRY;
+
+/*
+ * HBA Attribute Block
+ */
+typedef struct {
+	uint32_t EntryCnt;	/* Number of HBA attribute entries */
+	ATTRIBUTE_ENTRY Entry;	/* Variable-length array */
+} ATTRIBUTE_BLOCK;
+
+/*
+ * Port Entry
+ */
+typedef struct {
+	struct lpfc_name PortName;
+} PORT_ENTRY;
+
+/*
+ * HBA Identifier
+ */
+typedef struct {
+	struct lpfc_name PortName;
+} HBA_IDENTIFIER;
+
+/*
+ * Registered Port List Format
+ */
+typedef struct {
+	uint32_t EntryCnt;
+	PORT_ENTRY pe;		/* Variable-length array */
+} REG_PORT_LIST;
+
+/*
+ * Register HBA(RHBA)
+ */
+typedef struct {
+	HBA_IDENTIFIER hi;
+	REG_PORT_LIST rpl;	/* variable-length array */
+/* ATTRIBUTE_BLOCK   ab; */
+} REG_HBA;
+
+/*
+ * Register HBA Attributes (RHAT)
+ */
+typedef struct {
+	struct lpfc_name HBA_PortName;
+	ATTRIBUTE_BLOCK ab;
+} REG_HBA_ATTRIBUTE;
+
+/*
+ * Register Port Attributes (RPA)
+ */
+typedef struct {
+	struct lpfc_name PortName;
+	ATTRIBUTE_BLOCK ab;
+} REG_PORT_ATTRIBUTE;
+
+/*
+ * Get Registered HBA List (GRHL) Accept Payload Format
+ */
+typedef struct {
+	uint32_t HBA__Entry_Cnt; /* Number of Registered HBA Identifiers */
+	struct lpfc_name HBA_PortName;	/* Variable-length array */
+} GRHL_ACC_PAYLOAD;
+
+/*
+ * Get Registered Port List (GRPL) Accept Payload Format
+ */
+typedef struct {
+	uint32_t RPL_Entry_Cnt;	/* Number of Registered Port Entries */
+	PORT_ENTRY Reg_Port_Entry[1];	/* Variable-length array */
+} GRPL_ACC_PAYLOAD;
+
+/*
+ * Get Port Attributes (GPAT) Accept Payload Format
+ */
+
+typedef struct {
+	ATTRIBUTE_BLOCK pab;
+} GPAT_ACC_PAYLOAD;
+
+
+/*
+ *  Begin HBA configuration parameters.
+ *  The PCI configuration register BAR assignments are:
+ *  BAR0, offset 0x10 - SLIM base memory address
+ *  BAR1, offset 0x14 - SLIM base memory high address
+ *  BAR2, offset 0x18 - REGISTER base memory address
+ *  BAR3, offset 0x1c - REGISTER base memory high address
+ *  BAR4, offset 0x20 - BIU I/O registers
+ *  BAR5, offset 0x24 - REGISTER base io high address
+ */
+
+/* Number of rings currently used and available. */
+#define MAX_CONFIGURED_RINGS     3
+#define MAX_RINGS                4
+
+/* IOCB / Mailbox is owned by FireFly */
+#define OWN_CHIP        1
+
+/* IOCB / Mailbox is owned by Host */
+#define OWN_HOST        0
+
+/* Number of 4-byte words in an IOCB. */
+#define IOCB_WORD_SZ    8
+
+/* defines for type field in fc header */
+#define FC_ELS_DATA     0x1
+#define FC_LLC_SNAP     0x5
+#define FC_FCP_DATA     0x8
+#define FC_COMMON_TRANSPORT_ULP 0x20
+
+/* defines for rctl field in fc header */
+#define FC_DEV_DATA     0x0
+#define FC_UNSOL_CTL    0x2
+#define FC_SOL_CTL      0x3
+#define FC_UNSOL_DATA   0x4
+#define FC_FCP_CMND     0x6
+#define FC_ELS_REQ      0x22
+#define FC_ELS_RSP      0x23
+
+/* network headers for Dfctl field */
+#define FC_NET_HDR      0x20
+
+/* Start FireFly Register definitions */
+#define PCI_VENDOR_ID_EMULEX        0x10df
+#define PCI_DEVICE_ID_FIREFLY       0x1ae5
+#define PCI_DEVICE_ID_SUPERFLY      0xf700
+#define PCI_DEVICE_ID_DRAGONFLY     0xf800
+#define PCI_DEVICE_ID_RFLY          0xf095
+#define PCI_DEVICE_ID_PFLY          0xf098
+#define PCI_DEVICE_ID_TFLY          0xf0a5
+#define PCI_DEVICE_ID_CENTAUR       0xf900
+#define PCI_DEVICE_ID_PEGASUS       0xf980
+#define PCI_DEVICE_ID_THOR          0xfa00
+#define PCI_DEVICE_ID_VIPER         0xfb00
+#define PCI_DEVICE_ID_HELIOS        0xfd00
+#define PCI_DEVICE_ID_BMID          0xf0d5
+#define PCI_DEVICE_ID_BSMB          0xf0d1
+#define PCI_DEVICE_ID_ZEPHYR        0xfe00
+#define PCI_DEVICE_ID_ZMID          0xf0e5
+#define PCI_DEVICE_ID_ZSMB          0xf0e1
+#define PCI_DEVICE_ID_LP101	    0xf0a1
+#define PCI_DEVICE_ID_LP10000S	    0xfc00
+
+#define JEDEC_ID_ADDRESS            0x0080001c
+#define FIREFLY_JEDEC_ID            0x1ACC
+#define SUPERFLY_JEDEC_ID           0x0020
+#define DRAGONFLY_JEDEC_ID          0x0021
+#define DRAGONFLY_V2_JEDEC_ID       0x0025
+#define CENTAUR_2G_JEDEC_ID         0x0026
+#define CENTAUR_1G_JEDEC_ID         0x0028
+#define PEGASUS_ORION_JEDEC_ID      0x0036
+#define PEGASUS_JEDEC_ID            0x0038
+#define THOR_JEDEC_ID               0x0012
+#define HELIOS_JEDEC_ID             0x0364
+#define ZEPHYR_JEDEC_ID             0x0577
+#define VIPER_JEDEC_ID              0x4838
+
+#define JEDEC_ID_MASK               0x0FFFF000
+#define JEDEC_ID_SHIFT              12
+#define FC_JEDEC_ID(id)             ((id & JEDEC_ID_MASK) >> JEDEC_ID_SHIFT)
+
+typedef struct {		/* FireFly BIU registers */
+	uint32_t hostAtt;	/* See definitions for Host Attention
+				   register */
+	uint32_t chipAtt;	/* See definitions for Chip Attention
+				   register */
+	uint32_t hostStatus;	/* See definitions for Host Status register */
+	uint32_t hostControl;	/* See definitions for Host Control register */
+	uint32_t buiConfig;	/* See definitions for BIU configuration
+				   register */
+} FF_REGS;
+
+/* IO Register size in bytes */
+#define FF_REG_AREA_SIZE       256
+
+/* Host Attention Register */
+
+#define HA_REG_OFFSET  0	/* Byte offset from register base address */
+
+#define HA_R0RE_REQ    0x00000001	/* Bit  0 */
+#define HA_R0CE_RSP    0x00000002	/* Bit  1 */
+#define HA_R0ATT       0x00000008	/* Bit  3 */
+#define HA_R1RE_REQ    0x00000010	/* Bit  4 */
+#define HA_R1CE_RSP    0x00000020	/* Bit  5 */
+#define HA_R1ATT       0x00000080	/* Bit  7 */
+#define HA_R2RE_REQ    0x00000100	/* Bit  8 */
+#define HA_R2CE_RSP    0x00000200	/* Bit  9 */
+#define HA_R2ATT       0x00000800	/* Bit 11 */
+#define HA_R3RE_REQ    0x00001000	/* Bit 12 */
+#define HA_R3CE_RSP    0x00002000	/* Bit 13 */
+#define HA_R3ATT       0x00008000	/* Bit 15 */
+#define HA_LATT        0x20000000	/* Bit 29 */
+#define HA_MBATT       0x40000000	/* Bit 30 */
+#define HA_ERATT       0x80000000	/* Bit 31 */
+
+#define HA_RXRE_REQ    0x00000001	/* Bit  0 */
+#define HA_RXCE_RSP    0x00000002	/* Bit  1 */
+#define HA_RXATT       0x00000008	/* Bit  3 */
+#define HA_RXMASK      0x0000000f
+
+/* Chip Attention Register */
+
+#define CA_REG_OFFSET  4	/* Byte offset from register base address */
+
+#define CA_R0CE_REQ    0x00000001	/* Bit  0 */
+#define CA_R0RE_RSP    0x00000002	/* Bit  1 */
+#define CA_R0ATT       0x00000008	/* Bit  3 */
+#define CA_R1CE_REQ    0x00000010	/* Bit  4 */
+#define CA_R1RE_RSP    0x00000020	/* Bit  5 */
+#define CA_R1ATT       0x00000080	/* Bit  7 */
+#define CA_R2CE_REQ    0x00000100	/* Bit  8 */
+#define CA_R2RE_RSP    0x00000200	/* Bit  9 */
+#define CA_R2ATT       0x00000800	/* Bit 11 */
+#define CA_R3CE_REQ    0x00001000	/* Bit 12 */
+#define CA_R3RE_RSP    0x00002000	/* Bit 13 */
+#define CA_R3ATT       0x00008000	/* Bit 15 */
+#define CA_MBATT       0x40000000	/* Bit 30 */
+
+/* Host Status Register */
+
+#define HS_REG_OFFSET  8	/* Byte offset from register base address */
+
+#define HS_MBRDY       0x00400000	/* Bit 22 */
+#define HS_FFRDY       0x00800000	/* Bit 23 */
+#define HS_FFER8       0x01000000	/* Bit 24 */
+#define HS_FFER7       0x02000000	/* Bit 25 */
+#define HS_FFER6       0x04000000	/* Bit 26 */
+#define HS_FFER5       0x08000000	/* Bit 27 */
+#define HS_FFER4       0x10000000	/* Bit 28 */
+#define HS_FFER3       0x20000000	/* Bit 29 */
+#define HS_FFER2       0x40000000	/* Bit 30 */
+#define HS_FFER1       0x80000000	/* Bit 31 */
+#define HS_FFERM       0xFF000000	/* Mask for error bits 31:24 */
+
+/* Host Control Register */
+
+#define HC_REG_OFFSET  12	/* Word offset from register base address */
+
+#define HC_MBINT_ENA   0x00000001	/* Bit  0 */
+#define HC_R0INT_ENA   0x00000002	/* Bit  1 */
+#define HC_R1INT_ENA   0x00000004	/* Bit  2 */
+#define HC_R2INT_ENA   0x00000008	/* Bit  3 */
+#define HC_R3INT_ENA   0x00000010	/* Bit  4 */
+#define HC_INITHBI     0x02000000	/* Bit 25 */
+#define HC_INITMB      0x04000000	/* Bit 26 */
+#define HC_INITFF      0x08000000	/* Bit 27 */
+#define HC_LAINT_ENA   0x20000000	/* Bit 29 */
+#define HC_ERINT_ENA   0x80000000	/* Bit 31 */
+
+/* Mailbox Commands */
+#define MBX_SHUTDOWN        0x00	/* terminate testing */
+#define MBX_LOAD_SM         0x01
+#define MBX_READ_NV         0x02
+#define MBX_WRITE_NV        0x03
+#define MBX_RUN_BIU_DIAG    0x04
+#define MBX_INIT_LINK       0x05
+#define MBX_DOWN_LINK       0x06
+#define MBX_CONFIG_LINK     0x07
+#define MBX_CONFIG_RING     0x09
+#define MBX_RESET_RING      0x0A
+#define MBX_READ_CONFIG     0x0B
+#define MBX_READ_RCONFIG    0x0C
+#define MBX_READ_SPARM      0x0D
+#define MBX_READ_STATUS     0x0E
+#define MBX_READ_RPI        0x0F
+#define MBX_READ_XRI        0x10
+#define MBX_READ_REV        0x11
+#define MBX_READ_LNK_STAT   0x12
+#define MBX_REG_LOGIN       0x13
+#define MBX_UNREG_LOGIN     0x14
+#define MBX_READ_LA         0x15
+#define MBX_CLEAR_LA        0x16
+#define MBX_DUMP_MEMORY     0x17
+#define MBX_DUMP_CONTEXT    0x18
+#define MBX_RUN_DIAGS       0x19
+#define MBX_RESTART         0x1A
+#define MBX_UPDATE_CFG      0x1B
+#define MBX_DOWN_LOAD       0x1C
+#define MBX_DEL_LD_ENTRY    0x1D
+#define MBX_RUN_PROGRAM     0x1E
+#define MBX_SET_MASK        0x20
+#define MBX_SET_SLIM        0x21
+#define MBX_UNREG_D_ID      0x23
+#define MBX_CONFIG_FARP     0x25
+
+#define MBX_LOAD_AREA       0x81
+#define MBX_RUN_BIU_DIAG64  0x84
+#define MBX_CONFIG_PORT     0x88
+#define MBX_READ_SPARM64    0x8D
+#define MBX_READ_RPI64      0x8F
+#define MBX_REG_LOGIN64     0x93
+#define MBX_READ_LA64       0x95
+
+#define MBX_FLASH_WR_ULA    0x98
+#define MBX_SET_DEBUG       0x99
+#define MBX_LOAD_EXP_ROM    0x9C
+
+#define MBX_MAX_CMDS        0x9D
+#define MBX_SLI2_CMD_MASK   0x80
+
+/* IOCB Commands */
+
+#define CMD_RCV_SEQUENCE_CX     0x01
+#define CMD_XMIT_SEQUENCE_CR    0x02
+#define CMD_XMIT_SEQUENCE_CX    0x03
+#define CMD_XMIT_BCAST_CN       0x04
+#define CMD_XMIT_BCAST_CX       0x05
+#define CMD_QUE_RING_BUF_CN     0x06
+#define CMD_QUE_XRI_BUF_CX      0x07
+#define CMD_IOCB_CONTINUE_CN    0x08
+#define CMD_RET_XRI_BUF_CX      0x09
+#define CMD_ELS_REQUEST_CR      0x0A
+#define CMD_ELS_REQUEST_CX      0x0B
+#define CMD_RCV_ELS_REQ_CX      0x0D
+#define CMD_ABORT_XRI_CN        0x0E
+#define CMD_ABORT_XRI_CX        0x0F
+#define CMD_CLOSE_XRI_CN        0x10
+#define CMD_CLOSE_XRI_CX        0x11
+#define CMD_CREATE_XRI_CR       0x12
+#define CMD_CREATE_XRI_CX       0x13
+#define CMD_GET_RPI_CN          0x14
+#define CMD_XMIT_ELS_RSP_CX     0x15
+#define CMD_GET_RPI_CR          0x16
+#define CMD_XRI_ABORTED_CX      0x17
+#define CMD_FCP_IWRITE_CR       0x18
+#define CMD_FCP_IWRITE_CX       0x19
+#define CMD_FCP_IREAD_CR        0x1A
+#define CMD_FCP_IREAD_CX        0x1B
+#define CMD_FCP_ICMND_CR        0x1C
+#define CMD_FCP_ICMND_CX        0x1D
+
+#define CMD_ADAPTER_MSG         0x20
+#define CMD_ADAPTER_DUMP        0x22
+
+/*  SLI_2 IOCB Command Set */
+
+#define CMD_RCV_SEQUENCE64_CX   0x81
+#define CMD_XMIT_SEQUENCE64_CR  0x82
+#define CMD_XMIT_SEQUENCE64_CX  0x83
+#define CMD_XMIT_BCAST64_CN     0x84
+#define CMD_XMIT_BCAST64_CX     0x85
+#define CMD_QUE_RING_BUF64_CN   0x86
+#define CMD_QUE_XRI_BUF64_CX    0x87
+#define CMD_IOCB_CONTINUE64_CN  0x88
+#define CMD_RET_XRI_BUF64_CX    0x89
+#define CMD_ELS_REQUEST64_CR    0x8A
+#define CMD_ELS_REQUEST64_CX    0x8B
+#define CMD_ABORT_MXRI64_CN     0x8C
+#define CMD_RCV_ELS_REQ64_CX    0x8D
+#define CMD_XMIT_ELS_RSP64_CX   0x95
+#define CMD_FCP_IWRITE64_CR     0x98
+#define CMD_FCP_IWRITE64_CX     0x99
+#define CMD_FCP_IREAD64_CR      0x9A
+#define CMD_FCP_IREAD64_CX      0x9B
+#define CMD_FCP_ICMND64_CR      0x9C
+#define CMD_FCP_ICMND64_CX      0x9D
+
+#define CMD_GEN_REQUEST64_CR    0xC2
+#define CMD_GEN_REQUEST64_CX    0xC3
+
+#define CMD_MAX_IOCB_CMD        0xE6
+#define CMD_IOCB_MASK           0xff
+
+#define MAX_MSG_DATA            28	/* max msg data in CMD_ADAPTER_MSG
+					   iocb */
+#define LPFC_MAX_ADPTMSG         32	/* max msg data */
+/*
+ *  Define Status
+ */
+#define MBX_SUCCESS                 0
+#define MBXERR_NUM_RINGS            1
+#define MBXERR_NUM_IOCBS            2
+#define MBXERR_IOCBS_EXCEEDED       3
+#define MBXERR_BAD_RING_NUMBER      4
+#define MBXERR_MASK_ENTRIES_RANGE   5
+#define MBXERR_MASKS_EXCEEDED       6
+#define MBXERR_BAD_PROFILE          7
+#define MBXERR_BAD_DEF_CLASS        8
+#define MBXERR_BAD_MAX_RESPONDER    9
+#define MBXERR_BAD_MAX_ORIGINATOR   10
+#define MBXERR_RPI_REGISTERED       11
+#define MBXERR_RPI_FULL             12
+#define MBXERR_NO_RESOURCES         13
+#define MBXERR_BAD_RCV_LENGTH       14
+#define MBXERR_DMA_ERROR            15
+#define MBXERR_ERROR                16
+#define MBX_NOT_FINISHED           255
+
+#define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
+#define MBX_TIMEOUT                0xfffffe /* time-out expired waiting for */
+
+/*
+ *    Begin Structure Definitions for Mailbox Commands
+ */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t tval;
+	uint8_t tmask;
+	uint8_t rval;
+	uint8_t rmask;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t rmask;
+	uint8_t rval;
+	uint8_t tmask;
+	uint8_t tval;
+#endif
+} RR_REG;
+
+struct ulp_bde {
+	uint32_t bdeAddress;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t bdeReserved:4;
+	uint32_t bdeAddrHigh:4;
+	uint32_t bdeSize:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t bdeSize:24;
+	uint32_t bdeAddrHigh:4;
+	uint32_t bdeReserved:4;
+#endif
+};
+
+struct ulp_bde64 {	/* SLI-2 */
+	union ULP_BDE_TUS {
+		uint32_t w;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
+						   VALUE !! */
+			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
+			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
+						   VALUE !! */
+#endif
+
+#define BUFF_USE_RSVD       0x01	/* bdeFlags */
+#define BUFF_USE_INTRPT     0x02	/* Not Implemented with LP6000 */
+#define BUFF_USE_CMND       0x04	/* Optional, 1=cmd/rsp 0=data buffer */
+#define BUFF_USE_RCV        0x08	/*  "" "", 1=rcv buffer, 0=xmit
+					    buffer */
+#define BUFF_TYPE_32BIT     0x10	/*  "" "", 1=32 bit addr 0=64 bit
+					    addr */
+#define BUFF_TYPE_SPECIAL   0x20	/* Not Implemented with LP6000  */
+#define BUFF_TYPE_BDL       0x40	/* Optional,  may be set in BDL */
+#define BUFF_TYPE_INVALID   0x80	/*  ""  "" */
+		} f;
+	} tus;
+	uint32_t addrLow;
+	uint32_t addrHigh;
+};
+#define BDE64_SIZE_WORD 0
+#define BPL64_SIZE_WORD 0x40
+
+typedef struct ULP_BDL {	/* SLI-2 */
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t bdeFlags:8;	/* BDL Flags */
+	uint32_t bdeSize:24;	/* Size of BDL array in host memory (bytes) */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t bdeSize:24;	/* Size of BDL array in host memory (bytes) */
+	uint32_t bdeFlags:8;	/* BDL Flags */
+#endif
+
+	uint32_t addrLow;	/* Address 0:31 */
+	uint32_t addrHigh;	/* Address 32:63 */
+	uint32_t ulpIoTag32;	/* Can be used for 32 bit I/O Tag */
+} ULP_BDL;
+
+/* Structure for MB Command LOAD_SM and DOWN_LOAD */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd2:25;
+	uint32_t acknowledgment:1;
+	uint32_t version:1;
+	uint32_t erase_or_prog:1;
+	uint32_t update_flash:1;
+	uint32_t update_ram:1;
+	uint32_t method:1;
+	uint32_t load_cmplt:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t load_cmplt:1;
+	uint32_t method:1;
+	uint32_t update_ram:1;
+	uint32_t update_flash:1;
+	uint32_t erase_or_prog:1;
+	uint32_t version:1;
+	uint32_t acknowledgment:1;
+	uint32_t rsvd2:25;
+#endif
+
+	uint32_t dl_to_adr_low;
+	uint32_t dl_to_adr_high;
+	uint32_t dl_len;
+	union {
+		uint32_t dl_from_mbx_offset;
+		struct ulp_bde dl_from_bde;
+		struct ulp_bde64 dl_from_bde64;
+	} un;
+
+} LOAD_SM_VAR;
+
+/* Structure for MB Command READ_NVPARM (02) */
+
+typedef struct {
+	uint32_t rsvd1[3];	/* Read as all one's */
+	uint32_t rsvd2;		/* Read as all zero's */
+	uint32_t portname[2];	/* N_PORT name */
+	uint32_t nodename[2];	/* NODE name */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t pref_DID:24;
+	uint32_t hardAL_PA:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t hardAL_PA:8;
+	uint32_t pref_DID:24;
+#endif
+
+	uint32_t rsvd3[21];	/* Read as all one's */
+} READ_NV_VAR;
+
+/* Structure for MB Command WRITE_NVPARMS (03) */
+
+typedef struct {
+	uint32_t rsvd1[3];	/* Must be all one's */
+	uint32_t rsvd2;		/* Must be all zero's */
+	uint32_t portname[2];	/* N_PORT name */
+	uint32_t nodename[2];	/* NODE name */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t pref_DID:24;
+	uint32_t hardAL_PA:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t hardAL_PA:8;
+	uint32_t pref_DID:24;
+#endif
+
+	uint32_t rsvd3[21];	/* Must be all one's */
+} WRITE_NV_VAR;
+
+/* Structure for MB Command RUN_BIU_DIAG (04) */
+/* Structure for MB Command RUN_BIU_DIAG64 (0x84) */
+
+typedef struct {
+	uint32_t rsvd1;
+	union {
+		struct {
+			struct ulp_bde xmit_bde;
+			struct ulp_bde rcv_bde;
+		} s1;
+		struct {
+			struct ulp_bde64 xmit_bde64;
+			struct ulp_bde64 rcv_bde64;
+		} s2;
+	} un;
+} BIU_DIAG_VAR;
+
+/* Structure for MB Command INIT_LINK (05) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd1:24;
+	uint32_t lipsr_AL_PA:8;	/* AL_PA to issue Lip Selective Reset to */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t lipsr_AL_PA:8;	/* AL_PA to issue Lip Selective Reset to */
+	uint32_t rsvd1:24;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t fabric_AL_PA;	/* If using a Fabric Assigned AL_PA */
+	uint8_t rsvd2;
+	uint16_t link_flags;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t link_flags;
+	uint8_t rsvd2;
+	uint8_t fabric_AL_PA;	/* If using a Fabric Assigned AL_PA */
+#endif
+
+#define FLAGS_LOCAL_LB               0x01 /* link_flags (=1) ENDEC loopback */
+#define FLAGS_TOPOLOGY_MODE_LOOP_PT  0x00 /* Attempt loop then pt-pt */
+#define FLAGS_TOPOLOGY_MODE_PT_PT    0x02 /* Attempt pt-pt only */
+#define FLAGS_TOPOLOGY_MODE_LOOP     0x04 /* Attempt loop only */
+#define FLAGS_TOPOLOGY_MODE_PT_LOOP  0x06 /* Attempt pt-pt then loop */
+#define FLAGS_LIRP_LILP              0x80 /* LIRP / LILP is disabled */
+
+#define FLAGS_TOPOLOGY_FAILOVER      0x0400	/* Bit 10 */
+#define FLAGS_LINK_SPEED             0x0800	/* Bit 11 */
+
+	uint32_t link_speed;
+#define LINK_SPEED_AUTO 0       /* Auto selection */
+#define LINK_SPEED_1G   1       /* 1 Gigabaud */
+#define LINK_SPEED_2G   2       /* 2 Gigabaud */
+#define LINK_SPEED_4G   4       /* 4 Gigabaud */
+#define LINK_SPEED_8G   8       /* 4 Gigabaud */
+#define LINK_SPEED_10G   16      /* 10 Gigabaud */
+
+} INIT_LINK_VAR;
+
+/* Structure for MB Command DOWN_LINK (06) */
+
+typedef struct {
+	uint32_t rsvd1;
+} DOWN_LINK_VAR;
+
+/* Structure for MB Command CONFIG_LINK (07) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t cr:1;
+	uint32_t ci:1;
+	uint32_t cr_delay:6;
+	uint32_t cr_count:8;
+	uint32_t rsvd1:8;
+	uint32_t MaxBBC:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t MaxBBC:8;
+	uint32_t rsvd1:8;
+	uint32_t cr_count:8;
+	uint32_t cr_delay:6;
+	uint32_t ci:1;
+	uint32_t cr:1;
+#endif
+
+	uint32_t myId;
+	uint32_t rsvd2;
+	uint32_t edtov;
+	uint32_t arbtov;
+	uint32_t ratov;
+	uint32_t rttov;
+	uint32_t altov;
+	uint32_t crtov;
+	uint32_t citov;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rrq_enable:1;
+	uint32_t rrq_immed:1;
+	uint32_t rsvd4:29;
+	uint32_t ack0_enable:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t ack0_enable:1;
+	uint32_t rsvd4:29;
+	uint32_t rrq_immed:1;
+	uint32_t rrq_enable:1;
+#endif
+} CONFIG_LINK;
+
+/* Structure for MB Command PART_SLIM (08)
+ * will be removed since SLI1 is no longer supported!
+ */
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t offCiocb;
+	uint16_t numCiocb;
+	uint16_t offRiocb;
+	uint16_t numRiocb;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t numCiocb;
+	uint16_t offCiocb;
+	uint16_t numRiocb;
+	uint16_t offRiocb;
+#endif
+} RING_DEF;
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t unused1:24;
+	uint32_t numRing:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t numRing:8;
+	uint32_t unused1:24;
+#endif
+
+	RING_DEF ringdef[4];
+	uint32_t hbainit;
+} PART_SLIM_VAR;
+
+/* Structure for MB Command CONFIG_RING (09) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t unused2:6;
+	uint32_t recvSeq:1;
+	uint32_t recvNotify:1;
+	uint32_t numMask:8;
+	uint32_t profile:8;
+	uint32_t unused1:4;
+	uint32_t ring:4;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t ring:4;
+	uint32_t unused1:4;
+	uint32_t profile:8;
+	uint32_t numMask:8;
+	uint32_t recvNotify:1;
+	uint32_t recvSeq:1;
+	uint32_t unused2:6;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t maxRespXchg;
+	uint16_t maxOrigXchg;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t maxOrigXchg;
+	uint16_t maxRespXchg;
+#endif
+
+	RR_REG rrRegs[6];
+} CONFIG_RING_VAR;
+
+/* Structure for MB Command RESET_RING (10) */
+
+typedef struct {
+	uint32_t ring_no;
+} RESET_RING_VAR;
+
+/* Structure for MB Command READ_CONFIG (11) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t cr:1;
+	uint32_t ci:1;
+	uint32_t cr_delay:6;
+	uint32_t cr_count:8;
+	uint32_t InitBBC:8;
+	uint32_t MaxBBC:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t MaxBBC:8;
+	uint32_t InitBBC:8;
+	uint32_t cr_count:8;
+	uint32_t cr_delay:6;
+	uint32_t ci:1;
+	uint32_t cr:1;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t topology:8;
+	uint32_t myDid:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t myDid:24;
+	uint32_t topology:8;
+#endif
+
+	/* Defines for topology (defined previously) */
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t AR:1;
+	uint32_t IR:1;
+	uint32_t rsvd1:29;
+	uint32_t ack0:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t ack0:1;
+	uint32_t rsvd1:29;
+	uint32_t IR:1;
+	uint32_t AR:1;
+#endif
+
+	uint32_t edtov;
+	uint32_t arbtov;
+	uint32_t ratov;
+	uint32_t rttov;
+	uint32_t altov;
+	uint32_t lmt;
+#define LMT_RESERVED    0x0    /* Not used */
+#define LMT_266_10bit   0x1    /* 265.625 Mbaud 10 bit iface  */
+#define LMT_532_10bit   0x2    /* 531.25  Mbaud 10 bit iface  */
+#define LMT_1063_20bit  0x3    /* 1062.5   Mbaud 20 bit iface */
+#define LMT_1063_10bit  0x4    /* 1062.5   Mbaud 10 bit iface */
+#define LMT_2125_10bit  0x8    /* 2125     Mbaud 10 bit iface */
+#define LMT_4250_10bit  0x40   /* 4250     Mbaud 10 bit iface */
+
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t max_xri;
+	uint32_t max_iocb;
+	uint32_t max_rpi;
+	uint32_t avail_xri;
+	uint32_t avail_iocb;
+	uint32_t avail_rpi;
+	uint32_t default_rpi;
+} READ_CONFIG_VAR;
+
+/* Structure for MB Command READ_RCONFIG (12) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd2:7;
+	uint32_t recvNotify:1;
+	uint32_t numMask:8;
+	uint32_t profile:8;
+	uint32_t rsvd1:4;
+	uint32_t ring:4;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t ring:4;
+	uint32_t rsvd1:4;
+	uint32_t profile:8;
+	uint32_t numMask:8;
+	uint32_t recvNotify:1;
+	uint32_t rsvd2:7;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t maxResp;
+	uint16_t maxOrig;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t maxOrig;
+	uint16_t maxResp;
+#endif
+
+	RR_REG rrRegs[6];
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t cmdRingOffset;
+	uint16_t cmdEntryCnt;
+	uint16_t rspRingOffset;
+	uint16_t rspEntryCnt;
+	uint16_t nextCmdOffset;
+	uint16_t rsvd3;
+	uint16_t nextRspOffset;
+	uint16_t rsvd4;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t cmdEntryCnt;
+	uint16_t cmdRingOffset;
+	uint16_t rspEntryCnt;
+	uint16_t rspRingOffset;
+	uint16_t rsvd3;
+	uint16_t nextCmdOffset;
+	uint16_t rsvd4;
+	uint16_t nextRspOffset;
+#endif
+} READ_RCONF_VAR;
+
+/* Structure for MB Command READ_SPARM (13) */
+/* Structure for MB Command READ_SPARM64 (0x8D) */
+
+typedef struct {
+	uint32_t rsvd1;
+	uint32_t rsvd2;
+	union {
+		struct ulp_bde sp; /* This BDE points to struct serv_parm
+				      structure */
+		struct ulp_bde64 sp64;
+	} un;
+} READ_SPARM_VAR;
+
+/* Structure for MB Command READ_STATUS (14) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd1:31;
+	uint32_t clrCounters:1;
+	uint16_t activeXriCnt;
+	uint16_t activeRpiCnt;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t clrCounters:1;
+	uint32_t rsvd1:31;
+	uint16_t activeRpiCnt;
+	uint16_t activeXriCnt;
+#endif
+
+	uint32_t xmitByteCnt;
+	uint32_t rcvByteCnt;
+	uint32_t xmitFrameCnt;
+	uint32_t rcvFrameCnt;
+	uint32_t xmitSeqCnt;
+	uint32_t rcvSeqCnt;
+	uint32_t totalOrigExchanges;
+	uint32_t totalRespExchanges;
+	uint32_t rcvPbsyCnt;
+	uint32_t rcvFbsyCnt;
+} READ_STATUS_VAR;
+
+/* Structure for MB Command READ_RPI (15) */
+/* Structure for MB Command READ_RPI64 (0x8F) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t nextRpi;
+	uint16_t reqRpi;
+	uint32_t rsvd2:8;
+	uint32_t DID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t reqRpi;
+	uint16_t nextRpi;
+	uint32_t DID:24;
+	uint32_t rsvd2:8;
+#endif
+
+	union {
+		struct ulp_bde sp;
+		struct ulp_bde64 sp64;
+	} un;
+
+} READ_RPI_VAR;
+
+/* Structure for MB Command READ_XRI (16) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t nextXri;
+	uint16_t reqXri;
+	uint16_t rsvd1;
+	uint16_t rpi;
+	uint32_t rsvd2:8;
+	uint32_t DID:24;
+	uint32_t rsvd3:8;
+	uint32_t SID:24;
+	uint32_t rsvd4;
+	uint8_t seqId;
+	uint8_t rsvd5;
+	uint16_t seqCount;
+	uint16_t oxId;
+	uint16_t rxId;
+	uint32_t rsvd6:30;
+	uint32_t si:1;
+	uint32_t exchOrig:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t reqXri;
+	uint16_t nextXri;
+	uint16_t rpi;
+	uint16_t rsvd1;
+	uint32_t DID:24;
+	uint32_t rsvd2:8;
+	uint32_t SID:24;
+	uint32_t rsvd3:8;
+	uint32_t rsvd4;
+	uint16_t seqCount;
+	uint8_t rsvd5;
+	uint8_t seqId;
+	uint16_t rxId;
+	uint16_t oxId;
+	uint32_t exchOrig:1;
+	uint32_t si:1;
+	uint32_t rsvd6:30;
+#endif
+} READ_XRI_VAR;
+
+/* Structure for MB Command READ_REV (17) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t cv:1;
+	uint32_t rr:1;
+	uint32_t rsvd1:29;
+	uint32_t rv:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t rv:1;
+	uint32_t rsvd1:29;
+	uint32_t rr:1;
+	uint32_t cv:1;
+#endif
+
+	uint32_t biuRev;
+	uint32_t smRev;
+	union {
+		uint32_t smFwRev;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint8_t ProgType;
+			uint8_t ProgId;
+			uint16_t ProgVer:4;
+			uint16_t ProgRev:4;
+			uint16_t ProgFixLvl:2;
+			uint16_t ProgDistType:2;
+			uint16_t DistCnt:4;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint16_t DistCnt:4;
+			uint16_t ProgDistType:2;
+			uint16_t ProgFixLvl:2;
+			uint16_t ProgRev:4;
+			uint16_t ProgVer:4;
+			uint8_t ProgId;
+			uint8_t ProgType;
+#endif
+
+		} b;
+	} un;
+	uint32_t endecRev;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t feaLevelHigh;
+	uint8_t feaLevelLow;
+	uint8_t fcphHigh;
+	uint8_t fcphLow;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t fcphLow;
+	uint8_t fcphHigh;
+	uint8_t feaLevelLow;
+	uint8_t feaLevelHigh;
+#endif
+
+	uint32_t postKernRev;
+	uint32_t opFwRev;
+	uint8_t opFwName[16];
+	uint32_t sli1FwRev;
+	uint8_t sli1FwName[16];
+	uint32_t sli2FwRev;
+	uint8_t sli2FwName[16];
+	uint32_t rsvd2;
+	uint32_t RandomData[7];
+} READ_REV_VAR;
+
+/* Structure for MB Command READ_LINK_STAT (18) */
+
+typedef struct {
+	uint32_t rsvd1;
+	uint32_t linkFailureCnt;
+	uint32_t lossSyncCnt;
+
+	uint32_t lossSignalCnt;
+	uint32_t primSeqErrCnt;
+	uint32_t invalidXmitWord;
+	uint32_t crcCnt;
+	uint32_t primSeqTimeout;
+	uint32_t elasticOverrun;
+	uint32_t arbTimeout;
+} READ_LNK_VAR;
+
+/* Structure for MB Command REG_LOGIN (19) */
+/* Structure for MB Command REG_LOGIN64 (0x93) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd1;
+	uint16_t rpi;
+	uint32_t rsvd2:8;
+	uint32_t did:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t rpi;
+	uint16_t rsvd1;
+	uint32_t did:24;
+	uint32_t rsvd2:8;
+#endif
+
+	union {
+		struct ulp_bde sp;
+		struct ulp_bde64 sp64;
+	} un;
+
+} REG_LOGIN_VAR;
+
+/* Word 30 contents for REG_LOGIN */
+typedef union {
+	struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+		uint16_t rsvd1:12;
+		uint16_t wd30_class:4;
+		uint16_t xri;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+		uint16_t xri;
+		uint16_t wd30_class:4;
+		uint16_t rsvd1:12;
+#endif
+	} f;
+	uint32_t word;
+} REG_WD30;
+
+/* Structure for MB Command UNREG_LOGIN (20) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd1;
+	uint16_t rpi;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t rpi;
+	uint16_t rsvd1;
+#endif
+} UNREG_LOGIN_VAR;
+
+/* Structure for MB Command UNREG_D_ID (0x23) */
+
+typedef struct {
+	uint32_t did;
+} UNREG_D_ID_VAR;
+
+/* Structure for MB Command READ_LA (21) */
+/* Structure for MB Command READ_LA64 (0x95) */
+
+typedef struct {
+	uint32_t eventTag;	/* Event tag */
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd1:22;
+	uint32_t pb:1;
+	uint32_t il:1;
+	uint32_t attType:8;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t attType:8;
+	uint32_t il:1;
+	uint32_t pb:1;
+	uint32_t rsvd1:22;
+#endif
+
+#define AT_RESERVED    0x00	/* Reserved - attType */
+#define AT_LINK_UP     0x01	/* Link is up */
+#define AT_LINK_DOWN   0x02	/* Link is down */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t granted_AL_PA;
+	uint8_t lipAlPs;
+	uint8_t lipType;
+	uint8_t topology;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t topology;
+	uint8_t lipType;
+	uint8_t lipAlPs;
+	uint8_t granted_AL_PA;
+#endif
+
+#define TOPOLOGY_PT_PT 0x01	/* Topology is pt-pt / pt-fabric */
+#define TOPOLOGY_LOOP  0x02	/* Topology is FC-AL */
+
+	union {
+		struct ulp_bde lilpBde; /* This BDE points to a 128 byte buffer
+					   to */
+		/* store the LILP AL_PA position map into */
+		struct ulp_bde64 lilpBde64;
+	} un;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t Dlu:1;
+	uint32_t Dtf:1;
+	uint32_t Drsvd2:14;
+	uint32_t DlnkSpeed:8;
+	uint32_t DnlPort:4;
+	uint32_t Dtx:2;
+	uint32_t Drx:2;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t Drx:2;
+	uint32_t Dtx:2;
+	uint32_t DnlPort:4;
+	uint32_t DlnkSpeed:8;
+	uint32_t Drsvd2:14;
+	uint32_t Dtf:1;
+	uint32_t Dlu:1;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t Ulu:1;
+	uint32_t Utf:1;
+	uint32_t Ursvd2:14;
+	uint32_t UlnkSpeed:8;
+	uint32_t UnlPort:4;
+	uint32_t Utx:2;
+	uint32_t Urx:2;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t Urx:2;
+	uint32_t Utx:2;
+	uint32_t UnlPort:4;
+	uint32_t UlnkSpeed:8;
+	uint32_t Ursvd2:14;
+	uint32_t Utf:1;
+	uint32_t Ulu:1;
+#endif
+
+#define LA_UNKNW_LINK  0x0    /* lnkSpeed */
+#define LA_1GHZ_LINK   0x04   /* lnkSpeed */
+#define LA_2GHZ_LINK   0x08   /* lnkSpeed */
+#define LA_4GHZ_LINK   0x10   /* lnkSpeed */
+#define LA_8GHZ_LINK   0x20   /* lnkSpeed */
+#define LA_10GHZ_LINK  0x40   /* lnkSpeed */
+
+} READ_LA_VAR;
+
+/* Structure for MB Command CLEAR_LA (22) */
+
+typedef struct {
+	uint32_t eventTag;	/* Event tag */
+	uint32_t rsvd1;
+} CLEAR_LA_VAR;
+
+/* Structure for MB Command DUMP */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd:25;
+	uint32_t ra:1;
+	uint32_t co:1;
+	uint32_t cv:1;
+	uint32_t type:4;
+	uint32_t entry_index:16;
+	uint32_t region_id:16;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t type:4;
+	uint32_t cv:1;
+	uint32_t co:1;
+	uint32_t ra:1;
+	uint32_t rsvd:25;
+	uint32_t region_id:16;
+	uint32_t entry_index:16;
+#endif
+
+	uint32_t rsvd1;
+	uint32_t word_cnt;
+	uint32_t resp_offset;
+} DUMP_VAR;
+
+#define  DMP_MEM_REG             0x1
+#define  DMP_NV_PARAMS           0x2
+
+#define  DMP_REGION_VPD          0xe
+#define  DMP_VPD_SIZE            0x400  /* maximum amount of VPD */
+#define  DMP_RSP_OFFSET          0x14   /* word 5 contains first word of rsp */
+#define  DMP_RSP_SIZE            0x6C   /* maximum of 27 words of rsp data */
+
+/* Structure for MB Command CONFIG_PORT (0x88) */
+
+typedef struct {
+	uint32_t pcbLen;
+	uint32_t pcbLow;       /* bit 31:0  of memory based port config block */
+	uint32_t pcbHigh;      /* bit 63:32 of memory based port config block */
+	uint32_t hbainit[5];
+} CONFIG_PORT_VAR;
+
+/* SLI-2 Port Control Block */
+
+/* SLIM POINTER */
+#define SLIMOFF 0x30		/* WORD */
+
+typedef struct _SLI2_RDSC {
+	uint32_t cmdEntries;
+	uint32_t cmdAddrLow;
+	uint32_t cmdAddrHigh;
+
+	uint32_t rspEntries;
+	uint32_t rspAddrLow;
+	uint32_t rspAddrHigh;
+} SLI2_RDSC;
+
+typedef struct _PCB {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t type:8;
+#define TYPE_NATIVE_SLI2       0x01;
+	uint32_t feature:8;
+#define FEATURE_INITIAL_SLI2   0x01;
+	uint32_t rsvd:12;
+	uint32_t maxRing:4;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t maxRing:4;
+	uint32_t rsvd:12;
+	uint32_t feature:8;
+#define FEATURE_INITIAL_SLI2   0x01;
+	uint32_t type:8;
+#define TYPE_NATIVE_SLI2       0x01;
+#endif
+
+	uint32_t mailBoxSize;
+	uint32_t mbAddrLow;
+	uint32_t mbAddrHigh;
+
+	uint32_t hgpAddrLow;
+	uint32_t hgpAddrHigh;
+
+	uint32_t pgpAddrLow;
+	uint32_t pgpAddrHigh;
+	SLI2_RDSC rdsc[MAX_RINGS];
+} PCB_t;
+
+/* NEW_FEATURE */
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd0:27;
+	uint32_t discardFarp:1;
+	uint32_t IPEnable:1;
+	uint32_t nodeName:1;
+	uint32_t portName:1;
+	uint32_t filterEnable:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t filterEnable:1;
+	uint32_t portName:1;
+	uint32_t nodeName:1;
+	uint32_t IPEnable:1;
+	uint32_t discardFarp:1;
+	uint32_t rsvd:27;
+#endif
+
+	uint8_t portname[8];	/* Used to be struct lpfc_name */
+	uint8_t nodename[8];
+	uint32_t rsvd1;
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t IPAddress;
+} CONFIG_FARP_VAR;
+
+/* Union of all Mailbox Command types */
+#define MAILBOX_CMD_WSIZE	32
+#define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
+
+typedef union {
+	uint32_t varWords[MAILBOX_CMD_WSIZE - 1];
+	LOAD_SM_VAR varLdSM;	/* cmd =  1 (LOAD_SM)        */
+	READ_NV_VAR varRDnvp;	/* cmd =  2 (READ_NVPARMS)   */
+	WRITE_NV_VAR varWTnvp;	/* cmd =  3 (WRITE_NVPARMS)  */
+	BIU_DIAG_VAR varBIUdiag;	/* cmd =  4 (RUN_BIU_DIAG)   */
+	INIT_LINK_VAR varInitLnk;	/* cmd =  5 (INIT_LINK)      */
+	DOWN_LINK_VAR varDwnLnk;	/* cmd =  6 (DOWN_LINK)      */
+	CONFIG_LINK varCfgLnk;	/* cmd =  7 (CONFIG_LINK)    */
+	PART_SLIM_VAR varSlim;	/* cmd =  8 (PART_SLIM)      */
+	CONFIG_RING_VAR varCfgRing;	/* cmd =  9 (CONFIG_RING)    */
+	RESET_RING_VAR varRstRing;	/* cmd = 10 (RESET_RING)     */
+	READ_CONFIG_VAR varRdConfig;	/* cmd = 11 (READ_CONFIG)    */
+	READ_RCONF_VAR varRdRConfig;	/* cmd = 12 (READ_RCONFIG)   */
+	READ_SPARM_VAR varRdSparm;	/* cmd = 13 (READ_SPARM(64)) */
+	READ_STATUS_VAR varRdStatus;	/* cmd = 14 (READ_STATUS)    */
+	READ_RPI_VAR varRdRPI;	/* cmd = 15 (READ_RPI(64))   */
+	READ_XRI_VAR varRdXRI;	/* cmd = 16 (READ_XRI)       */
+	READ_REV_VAR varRdRev;	/* cmd = 17 (READ_REV)       */
+	READ_LNK_VAR varRdLnk;	/* cmd = 18 (READ_LNK_STAT)  */
+	REG_LOGIN_VAR varRegLogin;	/* cmd = 19 (REG_LOGIN(64))  */
+	UNREG_LOGIN_VAR varUnregLogin;	/* cmd = 20 (UNREG_LOGIN)    */
+	READ_LA_VAR varReadLA;	/* cmd = 21 (READ_LA(64))    */
+	CLEAR_LA_VAR varClearLA;	/* cmd = 22 (CLEAR_LA)       */
+	DUMP_VAR varDmp;	/* Warm Start DUMP mbx cmd   */
+	UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID)   */
+	CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP)  NEW_FEATURE */
+	CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT)  */
+} MAILVARIANTS;
+
+/*
+ * SLI-2 specific structures
+ */
+
+typedef struct {
+	uint32_t cmdPutInx;
+	uint32_t rspGetInx;
+} HGP;
+
+typedef struct {
+	uint32_t cmdGetInx;
+	uint32_t rspPutInx;
+} PGP;
+
+typedef struct _SLI2_DESC {
+	HGP host[MAX_RINGS];
+	uint32_t unused1[16];
+	PGP port[MAX_RINGS];
+} SLI2_DESC;
+
+typedef union {
+	SLI2_DESC s2;
+} SLI_VAR;
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t mbxStatus;
+	uint8_t mbxCommand;
+	uint8_t mbxReserved:6;
+	uint8_t mbxHc:1;
+	uint8_t mbxOwner:1;	/* Low order bit first word */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t mbxOwner:1;	/* Low order bit first word */
+	uint8_t mbxHc:1;
+	uint8_t mbxReserved:6;
+	uint8_t mbxCommand;
+	uint16_t mbxStatus;
+#endif
+
+	MAILVARIANTS un;
+	SLI_VAR us;
+} MAILBOX_t;
+
+/*
+ *    Begin Structure Definitions for IOCB Commands
+ */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t statAction;
+	uint8_t statRsn;
+	uint8_t statBaExp;
+	uint8_t statLocalError;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint8_t statLocalError;
+	uint8_t statBaExp;
+	uint8_t statRsn;
+	uint8_t statAction;
+#endif
+	/* statRsn  P/F_RJT reason codes */
+#define RJT_BAD_D_ID       0x01	/* Invalid D_ID field */
+#define RJT_BAD_S_ID       0x02	/* Invalid S_ID field */
+#define RJT_UNAVAIL_TEMP   0x03	/* N_Port unavailable temp. */
+#define RJT_UNAVAIL_PERM   0x04	/* N_Port unavailable perm. */
+#define RJT_UNSUP_CLASS    0x05	/* Class not supported */
+#define RJT_DELIM_ERR      0x06	/* Delimiter usage error */
+#define RJT_UNSUP_TYPE     0x07	/* Type not supported */
+#define RJT_BAD_CONTROL    0x08	/* Invalid link conrtol */
+#define RJT_BAD_RCTL       0x09	/* R_CTL invalid */
+#define RJT_BAD_FCTL       0x0A	/* F_CTL invalid */
+#define RJT_BAD_OXID       0x0B	/* OX_ID invalid */
+#define RJT_BAD_RXID       0x0C	/* RX_ID invalid */
+#define RJT_BAD_SEQID      0x0D	/* SEQ_ID invalid */
+#define RJT_BAD_DFCTL      0x0E	/* DF_CTL invalid */
+#define RJT_BAD_SEQCNT     0x0F	/* SEQ_CNT invalid */
+#define RJT_BAD_PARM       0x10	/* Param. field invalid */
+#define RJT_XCHG_ERR       0x11	/* Exchange error */
+#define RJT_PROT_ERR       0x12	/* Protocol error */
+#define RJT_BAD_LENGTH     0x13	/* Invalid Length */
+#define RJT_UNEXPECTED_ACK 0x14	/* Unexpected ACK */
+#define RJT_LOGIN_REQUIRED 0x16	/* Login required */
+#define RJT_TOO_MANY_SEQ   0x17	/* Excessive sequences */
+#define RJT_XCHG_NOT_STRT  0x18	/* Exchange not started */
+#define RJT_UNSUP_SEC_HDR  0x19	/* Security hdr not supported */
+#define RJT_UNAVAIL_PATH   0x1A	/* Fabric Path not available */
+#define RJT_VENDOR_UNIQUE  0xFF	/* Vendor unique error */
+
+#define IOERR_SUCCESS                 0x00	/* statLocalError */
+#define IOERR_MISSING_CONTINUE        0x01
+#define IOERR_SEQUENCE_TIMEOUT        0x02
+#define IOERR_INTERNAL_ERROR          0x03
+#define IOERR_INVALID_RPI             0x04
+#define IOERR_NO_XRI                  0x05
+#define IOERR_ILLEGAL_COMMAND         0x06
+#define IOERR_XCHG_DROPPED            0x07
+#define IOERR_ILLEGAL_FIELD           0x08
+#define IOERR_BAD_CONTINUE            0x09
+#define IOERR_TOO_MANY_BUFFERS        0x0A
+#define IOERR_RCV_BUFFER_WAITING      0x0B
+#define IOERR_NO_CONNECTION           0x0C
+#define IOERR_TX_DMA_FAILED           0x0D
+#define IOERR_RX_DMA_FAILED           0x0E
+#define IOERR_ILLEGAL_FRAME           0x0F
+#define IOERR_EXTRA_DATA              0x10
+#define IOERR_NO_RESOURCES            0x11
+#define IOERR_RESERVED                0x12
+#define IOERR_ILLEGAL_LENGTH          0x13
+#define IOERR_UNSUPPORTED_FEATURE     0x14
+#define IOERR_ABORT_IN_PROGRESS       0x15
+#define IOERR_ABORT_REQUESTED         0x16
+#define IOERR_RECEIVE_BUFFER_TIMEOUT  0x17
+#define IOERR_LOOP_OPEN_FAILURE       0x18
+#define IOERR_RING_RESET              0x19
+#define IOERR_LINK_DOWN               0x1A
+#define IOERR_CORRUPTED_DATA          0x1B
+#define IOERR_CORRUPTED_RPI           0x1C
+#define IOERR_OUT_OF_ORDER_DATA       0x1D
+#define IOERR_OUT_OF_ORDER_ACK        0x1E
+#define IOERR_DUP_FRAME               0x1F
+#define IOERR_LINK_CONTROL_FRAME      0x20	/* ACK_N received */
+#define IOERR_BAD_HOST_ADDRESS        0x21
+#define IOERR_RCV_HDRBUF_WAITING      0x22
+#define IOERR_MISSING_HDR_BUFFER      0x23
+#define IOERR_MSEQ_CHAIN_CORRUPTED    0x24
+#define IOERR_ABORTMULT_REQUESTED     0x25
+#define IOERR_BUFFER_SHORTAGE         0x28
+#define IOERR_DEFAULT                 0x29
+#define IOERR_CNT                     0x2A
+
+#define IOERR_DRVR_MASK               0x100
+#define IOERR_SLI_DOWN                0x101  /* ulpStatus  - Driver defined */
+#define IOERR_SLI_BRESET              0x102
+#define IOERR_SLI_ABORTED             0x103
+} PARM_ERR;
+
+typedef union {
+	struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+		uint8_t Rctl;	/* R_CTL field */
+		uint8_t Type;	/* TYPE field */
+		uint8_t Dfctl;	/* DF_CTL field */
+		uint8_t Fctl;	/* Bits 0-7 of IOCB word 5 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+		uint8_t Fctl;	/* Bits 0-7 of IOCB word 5 */
+		uint8_t Dfctl;	/* DF_CTL field */
+		uint8_t Type;	/* TYPE field */
+		uint8_t Rctl;	/* R_CTL field */
+#endif
+
+#define BC      0x02		/* Broadcast Received  - Fctl */
+#define SI      0x04		/* Sequence Initiative */
+#define LA      0x08		/* Ignore Link Attention state */
+#define LS      0x80		/* Last Sequence */
+	} hcsw;
+	uint32_t reserved;
+} WORD5;
+
+/* IOCB Command template for a generic response */
+typedef struct {
+	uint32_t reserved[4];
+	PARM_ERR perr;
+} GENERIC_RSP;
+
+/* IOCB Command template for XMIT / XMIT_BCAST / RCV_SEQUENCE / XMIT_ELS */
+typedef struct {
+	struct ulp_bde xrsqbde[2];
+	uint32_t xrsqRo;	/* Starting Relative Offset */
+	WORD5 w5;		/* Header control/status word */
+} XR_SEQ_FIELDS;
+
+/* IOCB Command template for ELS_REQUEST */
+typedef struct {
+	struct ulp_bde elsReq;
+	struct ulp_bde elsRsp;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t word4Rsvd:7;
+	uint32_t fl:1;
+	uint32_t myID:24;
+	uint32_t word5Rsvd:8;
+	uint32_t remoteID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t myID:24;
+	uint32_t fl:1;
+	uint32_t word4Rsvd:7;
+	uint32_t remoteID:24;
+	uint32_t word5Rsvd:8;
+#endif
+} ELS_REQUEST;
+
+/* IOCB Command template for RCV_ELS_REQ */
+typedef struct {
+	struct ulp_bde elsReq[2];
+	uint32_t parmRo;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t word5Rsvd:8;
+	uint32_t remoteID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t remoteID:24;
+	uint32_t word5Rsvd:8;
+#endif
+} RCV_ELS_REQ;
+
+/* IOCB Command template for ABORT / CLOSE_XRI */
+typedef struct {
+	uint32_t rsvd[3];
+	uint32_t abortType;
+#define ABORT_TYPE_ABTX  0x00000000
+#define ABORT_TYPE_ABTS  0x00000001
+	uint32_t parm;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t abortContextTag; /* ulpContext from command to abort/close */
+	uint16_t abortIoTag;	/* ulpIoTag from command to abort/close */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t abortIoTag;	/* ulpIoTag from command to abort/close */
+	uint16_t abortContextTag; /* ulpContext from command to abort/close */
+#endif
+} AC_XRI;
+
+/* IOCB Command template for ABORT_MXRI64 */
+typedef struct {
+	uint32_t rsvd[3];
+	uint32_t abortType;
+	uint32_t parm;
+	uint32_t iotag32;
+} A_MXRI64;
+
+/* IOCB Command template for GET_RPI */
+typedef struct {
+	uint32_t rsvd[4];
+	uint32_t parmRo;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t word5Rsvd:8;
+	uint32_t remoteID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t remoteID:24;
+	uint32_t word5Rsvd:8;
+#endif
+} GET_RPI;
+
+/* IOCB Command template for all FCP Initiator commands */
+typedef struct {
+	struct ulp_bde fcpi_cmnd;	/* FCP_CMND payload descriptor */
+	struct ulp_bde fcpi_rsp;	/* Rcv buffer */
+	uint32_t fcpi_parm;
+	uint32_t fcpi_XRdy;	/* transfer ready for IWRITE */
+} FCPI_FIELDS;
+
+/* IOCB Command template for all FCP Target commands */
+typedef struct {
+	struct ulp_bde fcpt_Buffer[2];	/* FCP_CMND payload descriptor */
+	uint32_t fcpt_Offset;
+	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
+} FCPT_FIELDS;
+
+/* SLI-2 IOCB structure definitions */
+
+/* IOCB Command template for 64 bit XMIT / XMIT_BCAST / XMIT_ELS */
+typedef struct {
+	ULP_BDL bdl;
+	uint32_t xrsqRo;	/* Starting Relative Offset */
+	WORD5 w5;		/* Header control/status word */
+} XMT_SEQ_FIELDS64;
+
+/* IOCB Command template for 64 bit RCV_SEQUENCE64 */
+typedef struct {
+	struct ulp_bde64 rcvBde;
+	uint32_t rsvd1;
+	uint32_t xrsqRo;	/* Starting Relative Offset */
+	WORD5 w5;		/* Header control/status word */
+} RCV_SEQ_FIELDS64;
+
+/* IOCB Command template for ELS_REQUEST64 */
+typedef struct {
+	ULP_BDL bdl;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t word4Rsvd:7;
+	uint32_t fl:1;
+	uint32_t myID:24;
+	uint32_t word5Rsvd:8;
+	uint32_t remoteID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t myID:24;
+	uint32_t fl:1;
+	uint32_t word4Rsvd:7;
+	uint32_t remoteID:24;
+	uint32_t word5Rsvd:8;
+#endif
+} ELS_REQUEST64;
+
+/* IOCB Command template for GEN_REQUEST64 */
+typedef struct {
+	ULP_BDL bdl;
+	uint32_t xrsqRo;	/* Starting Relative Offset */
+	WORD5 w5;		/* Header control/status word */
+} GEN_REQUEST64;
+
+/* IOCB Command template for RCV_ELS_REQ64 */
+typedef struct {
+	struct ulp_bde64 elsReq;
+	uint32_t rcvd1;
+	uint32_t parmRo;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t word5Rsvd:8;
+	uint32_t remoteID:24;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t remoteID:24;
+	uint32_t word5Rsvd:8;
+#endif
+} RCV_ELS_REQ64;
+
+/* IOCB Command template for all 64 bit FCP Initiator commands */
+typedef struct {
+	ULP_BDL bdl;
+	uint32_t fcpi_parm;
+	uint32_t fcpi_XRdy;	/* transfer ready for IWRITE */
+} FCPI_FIELDS64;
+
+/* IOCB Command template for all 64 bit FCP Target commands */
+typedef struct {
+	ULP_BDL bdl;
+	uint32_t fcpt_Offset;
+	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
+} FCPT_FIELDS64;
+
+typedef struct _IOCB {	/* IOCB structure */
+	union {
+		GENERIC_RSP grsp;	/* Generic response */
+		XR_SEQ_FIELDS xrseq;	/* XMIT / BCAST / RCV_SEQUENCE cmd */
+		struct ulp_bde cont[3];	/* up to 3 continuation bdes */
+		RCV_ELS_REQ rcvels;	/* RCV_ELS_REQ template */
+		AC_XRI acxri;	/* ABORT / CLOSE_XRI template */
+		A_MXRI64 amxri;	/* abort multiple xri command overlay */
+		GET_RPI getrpi;	/* GET_RPI template */
+		FCPI_FIELDS fcpi;	/* FCP Initiator template */
+		FCPT_FIELDS fcpt;	/* FCP target template */
+
+		/* SLI-2 structures */
+
+		struct ulp_bde64 cont64[2];	/* up to 2 64 bit continuation
+					   bde_64s */
+		ELS_REQUEST64 elsreq64;	/* ELS_REQUEST template */
+		GEN_REQUEST64 genreq64;	/* GEN_REQUEST template */
+		RCV_ELS_REQ64 rcvels64;	/* RCV_ELS_REQ template */
+		XMT_SEQ_FIELDS64 xseq64;	/* XMIT / BCAST cmd */
+		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
+		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
+
+		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
+	} un;
+	union {
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint16_t ulpContext;	/* High order bits word 6 */
+			uint16_t ulpIoTag;	/* Low  order bits word 6 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint16_t ulpIoTag;	/* Low  order bits word 6 */
+			uint16_t ulpContext;	/* High order bits word 6 */
+#endif
+		} t1;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint16_t ulpContext;	/* High order bits word 6 */
+			uint16_t ulpIoTag1:2;	/* Low  order bits word 6 */
+			uint16_t ulpIoTag0:14;	/* Low  order bits word 6 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint16_t ulpIoTag0:14;	/* Low  order bits word 6 */
+			uint16_t ulpIoTag1:2;	/* Low  order bits word 6 */
+			uint16_t ulpContext;	/* High order bits word 6 */
+#endif
+		} t2;
+	} un1;
+#define ulpContext un1.t1.ulpContext
+#define ulpIoTag   un1.t1.ulpIoTag
+#define ulpIoTag0  un1.t2.ulpIoTag0
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t ulpTimeout:8;
+	uint32_t ulpXS:1;
+	uint32_t ulpFCP2Rcvy:1;
+	uint32_t ulpPU:2;
+	uint32_t ulpIr:1;
+	uint32_t ulpClass:3;
+	uint32_t ulpCommand:8;
+	uint32_t ulpStatus:4;
+	uint32_t ulpBdeCount:2;
+	uint32_t ulpLe:1;
+	uint32_t ulpOwner:1;	/* Low order bit word 7 */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t ulpOwner:1;	/* Low order bit word 7 */
+	uint32_t ulpLe:1;
+	uint32_t ulpBdeCount:2;
+	uint32_t ulpStatus:4;
+	uint32_t ulpCommand:8;
+	uint32_t ulpClass:3;
+	uint32_t ulpIr:1;
+	uint32_t ulpPU:2;
+	uint32_t ulpFCP2Rcvy:1;
+	uint32_t ulpXS:1;
+	uint32_t ulpTimeout:8;
+#endif
+
+#define PARM_UNUSED        0	/* PU field (Word 4) not used */
+#define PARM_REL_OFF       1	/* PU field (Word 4) = R. O. */
+#define PARM_READ_CHECK    2	/* PU field (Word 4) = Data Transfer Length */
+#define CLASS1             0	/* Class 1 */
+#define CLASS2             1	/* Class 2 */
+#define CLASS3             2	/* Class 3 */
+#define CLASS_FCP_INTERMIX 7	/* FCP Data->Cls 1, all else->Cls 2 */
+
+#define IOSTAT_SUCCESS         0x0	/* ulpStatus  - HBA defined */
+#define IOSTAT_FCP_RSP_ERROR   0x1
+#define IOSTAT_REMOTE_STOP     0x2
+#define IOSTAT_LOCAL_REJECT    0x3
+#define IOSTAT_NPORT_RJT       0x4
+#define IOSTAT_FABRIC_RJT      0x5
+#define IOSTAT_NPORT_BSY       0x6
+#define IOSTAT_FABRIC_BSY      0x7
+#define IOSTAT_INTERMED_RSP    0x8
+#define IOSTAT_LS_RJT          0x9
+#define IOSTAT_BA_RJT          0xA
+#define IOSTAT_RSVD1           0xB
+#define IOSTAT_RSVD2           0xC
+#define IOSTAT_RSVD3           0xD
+#define IOSTAT_RSVD4           0xE
+#define IOSTAT_RSVD5           0xF
+#define IOSTAT_DRIVER_REJECT   0x10   /* ulpStatus  - Driver defined */
+#define IOSTAT_DEFAULT         0xF    /* Same as rsvd5 for now */
+#define IOSTAT_CNT             0x11
+
+} IOCB_t;
+
+
+#define SLI1_SLIM_SIZE   (4 * 1024)
+
+/* Up to 498 IOCBs will fit into 16k
+ * 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384
+ */
+#define SLI2_SLIM_SIZE   (16 * 1024)
+
+/* Maximum IOCBs that will fit in SLI2 slim */
+#define MAX_SLI2_IOCB    498
+
+struct lpfc_sli2_slim {
+	MAILBOX_t mbx;
+	PCB_t pcb;
+	IOCB_t IOCBs[MAX_SLI2_IOCB];
+};
+
+/*******************************************************************
+This macro check PCI device to allow special handling for LC HBAs.
+
+Parameters:
+device : struct pci_dev 's device field
+
+return 1 => TRUE
+       0 => FALSE
+ *******************************************************************/
+static inline int
+lpfc_is_LC_HBA(unsigned short device)
+{
+	if ((device == PCI_DEVICE_ID_TFLY) ||
+	    (device == PCI_DEVICE_ID_PFLY) ||
+	    (device == PCI_DEVICE_ID_LP101) ||
+	    (device == PCI_DEVICE_ID_BMID) ||
+	    (device == PCI_DEVICE_ID_BSMB) ||
+	    (device == PCI_DEVICE_ID_ZMID) ||
+	    (device == PCI_DEVICE_ID_ZSMB) ||
+	    (device == PCI_DEVICE_ID_RFLY))
+		return 1;
+	else
+		return 0;
+}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -0,0 +1,1739 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_init.c 1.233 2005/04/13 11:59:09EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_version.h"
+
+static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *);
+static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
+static int lpfc_post_rcv_buf(struct lpfc_hba *);
+
+static struct scsi_transport_template *lpfc_transport_template = NULL;
+static DEFINE_IDR(lpfc_hba_index);
+
+/************************************************************************/
+/*                                                                      */
+/*    lpfc_config_port_prep                                             */
+/*    This routine will do LPFC initialization prior to the             */
+/*    CONFIG_PORT mailbox command. This will be initialized             */
+/*    as a SLI layer callback routine.                                  */
+/*    This routine returns 0 on success or -ERESTART if it wants        */
+/*    the SLI layer to reset the HBA and try again. Any                 */
+/*    other return value indicates an error.                            */
+/*                                                                      */
+/************************************************************************/
+int
+lpfc_config_port_prep(struct lpfc_hba * phba)
+{
+	lpfc_vpd_t *vp = &phba->vpd;
+	int i = 0, rc;
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+	char *lpfc_vpd_data = NULL;
+	uint16_t offset = 0;
+	static char licensed[56] =
+		    "key unlock for use with gnu public licensed code only\0";
+
+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		phba->hba_state = LPFC_HBA_ERROR;
+		return -ENOMEM;
+	}
+
+	mb = &pmb->mb;
+	phba->hba_state = LPFC_INIT_MBX_CMDS;
+
+	if (lpfc_is_LC_HBA(phba->pcidev->device)) {
+		uint32_t *ptext = (uint32_t *) licensed;
+
+		for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
+			*ptext = cpu_to_be32(*ptext);
+
+		lpfc_read_nv(phba, pmb);
+		memset((char*)mb->un.varRDnvp.rsvd3, 0,
+			sizeof (mb->un.varRDnvp.rsvd3));
+		memcpy((char*)mb->un.varRDnvp.rsvd3, licensed,
+			 sizeof (licensed));
+
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+
+		if (rc != MBX_SUCCESS) {
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_MBOX,
+					"%d:0324 Config Port initialization "
+					"error, mbxCmd x%x READ_NVPARM, "
+					"mbxStatus x%x\n",
+					phba->brd_no,
+					mb->mbxCommand, mb->mbxStatus);
+			mempool_free(pmb, phba->mbox_mem_pool);
+			return -ERESTART;
+		}
+		memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename,
+		       sizeof (mb->un.varRDnvp.nodename));
+	}
+
+	/* Setup and issue mailbox READ REV command */
+	lpfc_read_rev(phba, pmb);
+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0439 Adapter failed to init, mbxCmd x%x "
+				"READ_REV, mbxStatus x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, mb->mbxStatus);
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return -ERESTART;
+	}
+
+	/* The HBA's current state is provided by the ProgType and rr fields.
+	 * Read and check the value of these fields before continuing to config
+	 * this port.
+	 */
+	if (mb->un.varRdRev.rr == 0 || mb->un.varRdRev.un.b.ProgType != 2) {
+		/* Old firmware */
+		vp->rev.rBit = 0;
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0440 Adapter failed to init, mbxCmd x%x "
+				"READ_REV detected outdated firmware"
+				"Data: x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, 0);
+		mempool_free(pmb, phba->mbox_mem_pool);
+		return -ERESTART;
+	} else {
+		vp->rev.rBit = 1;
+		vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
+		memcpy(vp->rev.sli1FwName,
+			(char*)mb->un.varRdRev.sli1FwName, 16);
+		vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
+		memcpy(vp->rev.sli2FwName,
+					(char *)mb->un.varRdRev.sli2FwName, 16);
+	}
+
+	/* Save information as VPD data */
+	vp->rev.biuRev = mb->un.varRdRev.biuRev;
+	vp->rev.smRev = mb->un.varRdRev.smRev;
+	vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev;
+	vp->rev.endecRev = mb->un.varRdRev.endecRev;
+	vp->rev.fcphHigh = mb->un.varRdRev.fcphHigh;
+	vp->rev.fcphLow = mb->un.varRdRev.fcphLow;
+	vp->rev.feaLevelHigh = mb->un.varRdRev.feaLevelHigh;
+	vp->rev.feaLevelLow = mb->un.varRdRev.feaLevelLow;
+	vp->rev.postKernRev = mb->un.varRdRev.postKernRev;
+	vp->rev.opFwRev = mb->un.varRdRev.opFwRev;
+
+	if (lpfc_is_LC_HBA(phba->pcidev->device))
+		memcpy(phba->RandomData, (char *)&mb->un.varWords[24],
+						sizeof (phba->RandomData));
+
+	/* Get the default values for Model Name and Description */
+	lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
+
+	/* Get adapter VPD information */
+	pmb->context2 = kmalloc(DMP_RSP_SIZE, GFP_KERNEL);
+	if (!pmb->context2)
+		goto out_free_mbox;
+	lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL);
+	if (!lpfc_vpd_data)
+		goto out_free_context2;
+
+	do {
+		lpfc_dump_mem(phba, pmb, offset);
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+
+		if (rc != MBX_SUCCESS) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"%d:0441 VPD not present on adapter, "
+					"mbxCmd x%x DUMP VPD, mbxStatus x%x\n",
+					phba->brd_no,
+					mb->mbxCommand, mb->mbxStatus);
+			kfree(lpfc_vpd_data);
+			lpfc_vpd_data = NULL;
+			break;
+		}
+
+		lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset,
+							mb->un.varDmp.word_cnt);
+		offset += mb->un.varDmp.word_cnt;
+	} while (mb->un.varDmp.word_cnt);
+	lpfc_parse_vpd(phba, lpfc_vpd_data);
+
+	kfree(lpfc_vpd_data);
+out_free_context2:
+	kfree(pmb->context2);
+out_free_mbox:
+	mempool_free(pmb, phba->mbox_mem_pool);
+	return 0;
+}
+
+/************************************************************************/
+/*                                                                      */
+/*    lpfc_config_port_post                                             */
+/*    This routine will do LPFC initialization after the                */
+/*    CONFIG_PORT mailbox command. This will be initialized             */
+/*    as a SLI layer callback routine.                                  */
+/*    This routine returns 0 on success. Any other return value         */
+/*    indicates an error.                                               */
+/*                                                                      */
+/************************************************************************/
+int
+lpfc_config_port_post(struct lpfc_hba * phba)
+{
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	struct lpfc_sli *psli = &phba->sli;
+	uint32_t status, timeout;
+	int i, j, rc;
+
+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		phba->hba_state = LPFC_HBA_ERROR;
+		return -ENOMEM;
+	}
+	mb = &pmb->mb;
+
+	lpfc_config_link(phba, pmb);
+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0447 Adapter failed init, mbxCmd x%x "
+				"CONFIG_LINK mbxStatus x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, mb->mbxStatus);
+		phba->hba_state = LPFC_HBA_ERROR;
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return -EIO;
+	}
+
+	/* Get login parameters for NID.  */
+	lpfc_read_sparam(phba, pmb);
+	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0448 Adapter failed init, mbxCmd x%x "
+				"READ_SPARM mbxStatus x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, mb->mbxStatus);
+		phba->hba_state = LPFC_HBA_ERROR;
+		mp = (struct lpfc_dmabuf *) pmb->context1;
+		mempool_free( pmb, phba->mbox_mem_pool);
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		return -EIO;
+	}
+
+	mp = (struct lpfc_dmabuf *) pmb->context1;
+
+	memcpy(&phba->fc_sparam, mp->virt, sizeof (struct serv_parm));
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	pmb->context1 = NULL;
+
+	memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
+	       sizeof (struct lpfc_name));
+	memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
+	       sizeof (struct lpfc_name));
+	/* If no serial number in VPD data, use low 6 bytes of WWNN */
+	/* This should be consolidated into parse_vpd ? - mr */
+	if (phba->SerialNumber[0] == 0) {
+		uint8_t *outptr;
+
+		outptr = (uint8_t *) & phba->fc_nodename.IEEE[0];
+		for (i = 0; i < 12; i++) {
+			status = *outptr++;
+			j = ((status & 0xf0) >> 4);
+			if (j <= 9)
+				phba->SerialNumber[i] =
+				    (char)((uint8_t) 0x30 + (uint8_t) j);
+			else
+				phba->SerialNumber[i] =
+				    (char)((uint8_t) 0x61 + (uint8_t) (j - 10));
+			i++;
+			j = (status & 0xf);
+			if (j <= 9)
+				phba->SerialNumber[i] =
+				    (char)((uint8_t) 0x30 + (uint8_t) j);
+			else
+				phba->SerialNumber[i] =
+				    (char)((uint8_t) 0x61 + (uint8_t) (j - 10));
+		}
+	}
+
+	/* This should turn on DELAYED ABTS for ELS timeouts */
+	lpfc_set_slim(phba, pmb, 0x052198, 0x1);
+	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+		phba->hba_state = LPFC_HBA_ERROR;
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return -EIO;
+	}
+
+
+	lpfc_read_config(phba, pmb);
+	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0453 Adapter failed to init, mbxCmd x%x "
+				"READ_CONFIG, mbxStatus x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, mb->mbxStatus);
+		phba->hba_state = LPFC_HBA_ERROR;
+		mempool_free( pmb, phba->mbox_mem_pool);
+		return -EIO;
+	}
+
+	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */
+	if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))
+		phba->cfg_hba_queue_depth =
+			mb->un.varRdConfig.max_xri + 1;
+
+	phba->lmt = mb->un.varRdConfig.lmt;
+	/* HBA is not 4GB capable, or HBA is not 2GB capable,
+	don't let link speed ask for it */
+	if ((((phba->lmt & LMT_4250_10bit) != LMT_4250_10bit) &&
+		(phba->cfg_link_speed > LINK_SPEED_2G)) ||
+		(((phba->lmt & LMT_2125_10bit) != LMT_2125_10bit) &&
+		(phba->cfg_link_speed > LINK_SPEED_1G))) {
+		/* Reset link speed to auto. 1G/2GB HBA cfg'd for 4G */
+		lpfc_printf_log(phba,
+			KERN_WARNING,
+			LOG_LINK_EVENT,
+			"%d:1302 Invalid speed for this board: "
+			"Reset link speed to auto: x%x\n",
+			phba->brd_no,
+			phba->cfg_link_speed);
+			phba->cfg_link_speed = LINK_SPEED_AUTO;
+	}
+
+	phba->hba_state = LPFC_LINK_DOWN;
+
+	/* Only process IOCBs on ring 0 till hba_state is READY */
+	if (psli->ring[psli->ip_ring].cmdringaddr)
+		psli->ring[psli->ip_ring].flag |= LPFC_STOP_IOCB_EVENT;
+	if (psli->ring[psli->fcp_ring].cmdringaddr)
+		psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT;
+	if (psli->ring[psli->next_ring].cmdringaddr)
+		psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT;
+
+	/* Post receive buffers for desired rings */
+	lpfc_post_rcv_buf(phba);
+
+	/* Enable appropriate host interrupts */
+	spin_lock_irq(phba->host->host_lock);
+	status = readl(phba->HCregaddr);
+	status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;
+	if (psli->num_rings > 0)
+		status |= HC_R0INT_ENA;
+	if (psli->num_rings > 1)
+		status |= HC_R1INT_ENA;
+	if (psli->num_rings > 2)
+		status |= HC_R2INT_ENA;
+	if (psli->num_rings > 3)
+		status |= HC_R3INT_ENA;
+
+	writel(status, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+	spin_unlock_irq(phba->host->host_lock);
+
+	/*
+	 * Setup the ring 0 (els)  timeout handler
+	 */
+	timeout = phba->fc_ratov << 1;
+	phba->els_tmofunc.expires = jiffies + HZ * timeout;
+	add_timer(&phba->els_tmofunc);
+
+	lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
+	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0454 Adapter failed to init, mbxCmd x%x "
+				"INIT_LINK, mbxStatus x%x\n",
+				phba->brd_no,
+				mb->mbxCommand, mb->mbxStatus);
+
+		/* Clear all interrupt enable conditions */
+		writel(0, phba->HCregaddr);
+		readl(phba->HCregaddr); /* flush */
+		/* Clear all pending interrupts */
+		writel(0xffffffff, phba->HAregaddr);
+		readl(phba->HAregaddr); /* flush */
+
+		phba->hba_state = LPFC_HBA_ERROR;
+		mempool_free(pmb, phba->mbox_mem_pool);
+		return -EIO;
+	}
+	/* MBOX buffer will be freed in mbox compl */
+
+	i = 0;
+	while ((phba->hba_state != LPFC_HBA_READY) ||
+	       (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
+	       ((phba->fc_map_cnt == 0) && (i<2)) ||
+	       (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
+		/* Check every second for 30 retries. */
+		i++;
+		if (i > 30) {
+			break;
+		}
+		if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
+			/* The link is down.  Set linkdown timeout */
+			break;
+		}
+
+		/* Delay for 1 second to give discovery time to complete. */
+		msleep(1000);
+
+	}
+
+	/* Since num_disc_nodes keys off of PLOGI, delay a bit to let
+	 * any potential PRLIs to flush thru the SLI sub-system.
+	 */
+	msleep(50);
+
+	return (0);
+}
+
+/************************************************************************/
+/*                                                                      */
+/*    lpfc_hba_down_prep                                                */
+/*    This routine will do LPFC uninitialization before the             */
+/*    HBA is reset when bringing down the SLI Layer. This will be       */
+/*    initialized as a SLI layer callback routine.                      */
+/*    This routine returns 0 on success. Any other return value         */
+/*    indicates an error.                                               */
+/*                                                                      */
+/************************************************************************/
+int
+lpfc_hba_down_prep(struct lpfc_hba * phba)
+{
+	/* Disable interrupts */
+	writel(0, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+
+	/* Cleanup potential discovery resources */
+	lpfc_els_flush_rscn(phba);
+	lpfc_els_flush_cmd(phba);
+	lpfc_disc_flush_list(phba);
+
+	return (0);
+}
+
+/************************************************************************/
+/*                                                                      */
+/*    lpfc_handle_eratt                                                 */
+/*    This routine will handle processing a Host Attention              */
+/*    Error Status event. This will be initialized                      */
+/*    as a SLI layer callback routine.                                  */
+/*                                                                      */
+/************************************************************************/
+void
+lpfc_handle_eratt(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring  *pring;
+
+	/*
+	 * If a reset is sent to the HBA restore PCI configuration registers.
+	 */
+	if ( phba->hba_state == LPFC_INIT_START ) {
+		mdelay(1);
+		readl(phba->HCregaddr); /* flush */
+		writel(0, phba->HCregaddr);
+		readl(phba->HCregaddr); /* flush */
+
+		/* Restore PCI cmd register */
+		pci_write_config_word(phba->pcidev,
+				      PCI_COMMAND, phba->pci_cfg_value);
+	}
+
+	if (phba->work_hs & HS_FFER6) {
+		/* Re-establishing Link */
+		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
+				"%d:1301 Re-establishing Link "
+				"Data: x%x x%x x%x\n",
+				phba->brd_no, phba->work_hs,
+				phba->work_status[0], phba->work_status[1]);
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag |= FC_ESTABLISH_LINK;
+		spin_unlock_irq(phba->host->host_lock);
+
+		/*
+		* Firmware stops when it triggled erratt with HS_FFER6.
+		* That could cause the I/Os dropped by the firmware.
+		* Error iocb (I/O) on txcmplq and let the SCSI layer
+		* retry it after re-establishing link.
+		*/
+		pring = &psli->ring[psli->fcp_ring];
+		lpfc_sli_abort_iocb_ring(phba, pring);
+
+
+		/*
+		 * There was a firmware error.  Take the hba offline and then
+		 * attempt to restart it.
+		 */
+		lpfc_offline(phba);
+		if (lpfc_online(phba) == 0) {	/* Initialize the HBA */
+			mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+			return;
+		}
+	} else {
+		/* The if clause above forces this code path when the status
+		 * failure is a value other than FFER6.  Do not call the offline
+		 *  twice. This is the adapter hardware error path.
+		 */
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0457 Adapter Hardware Error "
+				"Data: x%x x%x x%x\n",
+				phba->brd_no, phba->work_hs,
+				phba->work_status[0], phba->work_status[1]);
+
+		lpfc_offline(phba);
+
+		/*
+		 * Restart all traffic to this host.  Since the fc_transport
+		 * block functions (future) were not called in lpfc_offline,
+		 * don't call them here.
+		 */
+		scsi_unblock_requests(phba->host);
+	}
+}
+
+/************************************************************************/
+/*                                                                      */
+/*    lpfc_handle_latt                                                  */
+/*    This routine will handle processing a Host Attention              */
+/*    Link Status event. This will be initialized                       */
+/*    as a SLI layer callback routine.                                  */
+/*                                                                      */
+/************************************************************************/
+void
+lpfc_handle_latt(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	LPFC_MBOXQ_t *pmb;
+	volatile uint32_t control;
+	struct lpfc_dmabuf *mp;
+	int rc = -ENOMEM;
+
+	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb)
+		goto lpfc_handle_latt_err_exit;
+
+	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!mp)
+		goto lpfc_handle_latt_free_pmb;
+
+	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+	if (!mp->virt)
+		goto lpfc_handle_latt_free_mp;
+
+	rc = -EIO;
+
+
+	psli->slistat.link_event++;
+	lpfc_read_la(phba, pmb, mp);
+	pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+	rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
+	if (rc == MBX_NOT_FINISHED)
+		goto lpfc_handle_latt_free_mp;
+
+	/* Clear Link Attention in HA REG */
+	spin_lock_irq(phba->host->host_lock);
+	writel(HA_LATT, phba->HAregaddr);
+	readl(phba->HAregaddr); /* flush */
+	spin_unlock_irq(phba->host->host_lock);
+
+	return;
+
+lpfc_handle_latt_free_mp:
+	kfree(mp);
+lpfc_handle_latt_free_pmb:
+	kfree(pmb);
+lpfc_handle_latt_err_exit:
+	/* Enable Link attention interrupts */
+	spin_lock_irq(phba->host->host_lock);
+	psli->sli_flag |= LPFC_PROCESS_LA;
+	control = readl(phba->HCregaddr);
+	control |= HC_LAINT_ENA;
+	writel(control, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+
+	/* Clear Link Attention in HA REG */
+	writel(HA_LATT, phba->HAregaddr);
+	readl(phba->HAregaddr); /* flush */
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_linkdown(phba);
+	phba->hba_state = LPFC_HBA_ERROR;
+
+	/* The other case is an error from issue_mbox */
+	if (rc == -ENOMEM)
+		lpfc_printf_log(phba,
+				KERN_WARNING,
+				LOG_MBOX,
+			        "%d:0300 READ_LA: no buffers\n",
+				phba->brd_no);
+
+	return;
+}
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_parse_vpd                                                     */
+/*   This routine will parse the VPD data                               */
+/*                                                                      */
+/************************************************************************/
+static int
+lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd)
+{
+	uint8_t lenlo, lenhi;
+	uint32_t Length;
+	int i, j;
+	int finished = 0;
+	int index = 0;
+
+	if (!vpd)
+		return 0;
+
+	/* Vital Product */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_INIT,
+			"%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
+			(uint32_t) vpd[3]);
+	do {
+		switch (vpd[index]) {
+		case 0x82:
+			index += 1;
+			lenlo = vpd[index];
+			index += 1;
+			lenhi = vpd[index];
+			index += 1;
+			i = ((((unsigned short)lenhi) << 8) + lenlo);
+			index += i;
+			break;
+		case 0x90:
+			index += 1;
+			lenlo = vpd[index];
+			index += 1;
+			lenhi = vpd[index];
+			index += 1;
+			Length = ((((unsigned short)lenhi) << 8) + lenlo);
+
+			while (Length > 0) {
+			/* Look for Serial Number */
+			if ((vpd[index] == 'S') && (vpd[index+1] == 'N')) {
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				j = 0;
+				Length -= (3+i);
+				while(i--) {
+					phba->SerialNumber[j++] = vpd[index++];
+					if (j == 31)
+						break;
+				}
+				phba->SerialNumber[j] = 0;
+				continue;
+			}
+			else if ((vpd[index] == 'V') && (vpd[index+1] == '1')) {
+				phba->vpd_flag |= VPD_MODEL_DESC;
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				j = 0;
+				Length -= (3+i);
+				while(i--) {
+					phba->ModelDesc[j++] = vpd[index++];
+					if (j == 255)
+						break;
+				}
+				phba->ModelDesc[j] = 0;
+				continue;
+			}
+			else if ((vpd[index] == 'V') && (vpd[index+1] == '2')) {
+				phba->vpd_flag |= VPD_MODEL_NAME;
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				j = 0;
+				Length -= (3+i);
+				while(i--) {
+					phba->ModelName[j++] = vpd[index++];
+					if (j == 79)
+						break;
+				}
+				phba->ModelName[j] = 0;
+				continue;
+			}
+			else if ((vpd[index] == 'V') && (vpd[index+1] == '3')) {
+				phba->vpd_flag |= VPD_PROGRAM_TYPE;
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				j = 0;
+				Length -= (3+i);
+				while(i--) {
+					phba->ProgramType[j++] = vpd[index++];
+					if (j == 255)
+						break;
+				}
+				phba->ProgramType[j] = 0;
+				continue;
+			}
+			else if ((vpd[index] == 'V') && (vpd[index+1] == '4')) {
+				phba->vpd_flag |= VPD_PORT;
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				j = 0;
+				Length -= (3+i);
+				while(i--) {
+				phba->Port[j++] = vpd[index++];
+				if (j == 19)
+					break;
+				}
+				phba->Port[j] = 0;
+				continue;
+			}
+			else {
+				index += 2;
+				i = vpd[index];
+				index += 1;
+				index += i;
+				Length -= (3 + i);
+			}
+		}
+		finished = 0;
+		break;
+		case 0x78:
+			finished = 1;
+			break;
+		default:
+			index ++;
+			break;
+		}
+	} while (!finished && (index < 108));
+
+	return(1);
+}
+
+static void
+lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
+{
+	lpfc_vpd_t *vp;
+	uint32_t id;
+	char str[16];
+
+	vp = &phba->vpd;
+	pci_read_config_dword(phba->pcidev, PCI_VENDOR_ID, &id);
+
+	switch ((id >> 16) & 0xffff) {
+	case PCI_DEVICE_ID_SUPERFLY:
+		if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3)
+			strcpy(str, "LP7000 1");
+		else
+			strcpy(str, "LP7000E 1");
+		break;
+	case PCI_DEVICE_ID_DRAGONFLY:
+		strcpy(str, "LP8000 1");
+		break;
+	case PCI_DEVICE_ID_CENTAUR:
+		if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID)
+			strcpy(str, "LP9002 2");
+		else
+			strcpy(str, "LP9000 1");
+		break;
+	case PCI_DEVICE_ID_RFLY:
+		strcpy(str, "LP952 2");
+		break;
+	case PCI_DEVICE_ID_PEGASUS:
+		strcpy(str, "LP9802 2");
+		break;
+	case PCI_DEVICE_ID_THOR:
+		strcpy(str, "LP10000 2");
+		break;
+	case PCI_DEVICE_ID_VIPER:
+		strcpy(str, "LPX1000 10");
+		break;
+	case PCI_DEVICE_ID_PFLY:
+		strcpy(str, "LP982 2");
+		break;
+	case PCI_DEVICE_ID_TFLY:
+		strcpy(str, "LP1050 2");
+		break;
+	case PCI_DEVICE_ID_HELIOS:
+		strcpy(str, "LP11000 4");
+		break;
+	case PCI_DEVICE_ID_BMID:
+		strcpy(str, "LP1150 4");
+		break;
+	case PCI_DEVICE_ID_BSMB:
+		strcpy(str, "LP111 4");
+		break;
+	case PCI_DEVICE_ID_ZEPHYR:
+		strcpy(str, "LP11000e 4");
+		break;
+	case PCI_DEVICE_ID_ZMID:
+		strcpy(str, "LP1150e 4");
+		break;
+	case PCI_DEVICE_ID_ZSMB:
+		strcpy(str, "LP111e 4");
+		break;
+	case PCI_DEVICE_ID_LP101:
+		strcpy(str, "LP101 2");
+		break;
+	case PCI_DEVICE_ID_LP10000S:
+		strcpy(str, "LP10000-S 2");
+		break;
+	}
+	if (mdp)
+		sscanf(str, "%s", mdp);
+	if (descp)
+		sprintf(descp, "Emulex LightPulse %s Gigabit PCI Fibre "
+			"Channel Adapter", str);
+}
+
+/**************************************************/
+/*   lpfc_post_buffer                             */
+/*                                                */
+/*   This routine will post count buffers to the  */
+/*   ring with the QUE_RING_BUF_CN command. This  */
+/*   allows 3 buffers / command to be posted.     */
+/*   Returns the number of buffers NOT posted.    */
+/**************************************************/
+int
+lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
+		 int type)
+{
+	IOCB_t *icmd;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	struct lpfc_iocbq *iocb = NULL;
+	struct lpfc_dmabuf *mp1, *mp2;
+
+	cnt += pring->missbufcnt;
+
+	/* While there are buffers to post */
+	while (cnt > 0) {
+		/* Allocate buffer for  command iocb */
+		spin_lock_irq(phba->host->host_lock);
+		list_remove_head(lpfc_iocb_list, iocb, struct lpfc_iocbq, list);
+		spin_unlock_irq(phba->host->host_lock);
+		if (iocb == NULL) {
+			pring->missbufcnt = cnt;
+			return cnt;
+		}
+		memset(iocb, 0, sizeof (struct lpfc_iocbq));
+		icmd = &iocb->iocb;
+
+		/* 2 buffers can be posted per command */
+		/* Allocate buffer to post */
+		mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+		if (mp1)
+		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+						&mp1->phys);
+		if (mp1 == 0 || mp1->virt == 0) {
+			if (mp1)
+				kfree(mp1);
+			spin_lock_irq(phba->host->host_lock);
+			list_add_tail(&iocb->list, lpfc_iocb_list);
+			spin_unlock_irq(phba->host->host_lock);
+			pring->missbufcnt = cnt;
+			return cnt;
+		}
+
+		INIT_LIST_HEAD(&mp1->list);
+		/* Allocate buffer to post */
+		if (cnt > 1) {
+			mp2 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+			if (mp2)
+				mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+							    &mp2->phys);
+			if (mp2 == 0 || mp2->virt == 0) {
+				if (mp2)
+					kfree(mp2);
+				lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
+				kfree(mp1);
+				spin_lock_irq(phba->host->host_lock);
+				list_add_tail(&iocb->list, lpfc_iocb_list);
+				spin_unlock_irq(phba->host->host_lock);
+				pring->missbufcnt = cnt;
+				return cnt;
+			}
+
+			INIT_LIST_HEAD(&mp2->list);
+		} else {
+			mp2 = NULL;
+		}
+
+		icmd->un.cont64[0].addrHigh = putPaddrHigh(mp1->phys);
+		icmd->un.cont64[0].addrLow = putPaddrLow(mp1->phys);
+		icmd->un.cont64[0].tus.f.bdeSize = FCELSSIZE;
+		icmd->ulpBdeCount = 1;
+		cnt--;
+		if (mp2) {
+			icmd->un.cont64[1].addrHigh = putPaddrHigh(mp2->phys);
+			icmd->un.cont64[1].addrLow = putPaddrLow(mp2->phys);
+			icmd->un.cont64[1].tus.f.bdeSize = FCELSSIZE;
+			cnt--;
+			icmd->ulpBdeCount = 2;
+		}
+
+		icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
+		icmd->ulpLe = 1;
+
+		spin_lock_irq(phba->host->host_lock);
+		if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) {
+			lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
+			kfree(mp1);
+			cnt++;
+			if (mp2) {
+				lpfc_mbuf_free(phba, mp2->virt, mp2->phys);
+				kfree(mp2);
+				cnt++;
+			}
+			list_add_tail(&iocb->list, lpfc_iocb_list);
+			pring->missbufcnt = cnt;
+			spin_unlock_irq(phba->host->host_lock);
+			return cnt;
+		}
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_sli_ringpostbuf_put(phba, pring, mp1);
+		if (mp2) {
+			lpfc_sli_ringpostbuf_put(phba, pring, mp2);
+		}
+	}
+	pring->missbufcnt = 0;
+	return 0;
+}
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_post_rcv_buf                                                  */
+/*   This routine post initial rcv buffers to the configured rings      */
+/*                                                                      */
+/************************************************************************/
+static int
+lpfc_post_rcv_buf(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+
+	/* Ring 0, ELS / CT buffers */
+	lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0, 1);
+	/* Ring 2 - FCP no buffers needed */
+
+	return 0;
+}
+
+#define S(N,V) (((V)<<(N))|((V)>>(32-(N))))
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_sha_init                                                      */
+/*                                                                      */
+/************************************************************************/
+static void
+lpfc_sha_init(uint32_t * HashResultPointer)
+{
+	HashResultPointer[0] = 0x67452301;
+	HashResultPointer[1] = 0xEFCDAB89;
+	HashResultPointer[2] = 0x98BADCFE;
+	HashResultPointer[3] = 0x10325476;
+	HashResultPointer[4] = 0xC3D2E1F0;
+}
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_sha_iterate                                                   */
+/*                                                                      */
+/************************************************************************/
+static void
+lpfc_sha_iterate(uint32_t * HashResultPointer, uint32_t * HashWorkingPointer)
+{
+	int t;
+	uint32_t TEMP;
+	uint32_t A, B, C, D, E;
+	t = 16;
+	do {
+		HashWorkingPointer[t] =
+		    S(1,
+		      HashWorkingPointer[t - 3] ^ HashWorkingPointer[t -
+								     8] ^
+		      HashWorkingPointer[t - 14] ^ HashWorkingPointer[t - 16]);
+	} while (++t <= 79);
+	t = 0;
+	A = HashResultPointer[0];
+	B = HashResultPointer[1];
+	C = HashResultPointer[2];
+	D = HashResultPointer[3];
+	E = HashResultPointer[4];
+
+	do {
+		if (t < 20) {
+			TEMP = ((B & C) | ((~B) & D)) + 0x5A827999;
+		} else if (t < 40) {
+			TEMP = (B ^ C ^ D) + 0x6ED9EBA1;
+		} else if (t < 60) {
+			TEMP = ((B & C) | (B & D) | (C & D)) + 0x8F1BBCDC;
+		} else {
+			TEMP = (B ^ C ^ D) + 0xCA62C1D6;
+		}
+		TEMP += S(5, A) + E + HashWorkingPointer[t];
+		E = D;
+		D = C;
+		C = S(30, B);
+		B = A;
+		A = TEMP;
+	} while (++t <= 79);
+
+	HashResultPointer[0] += A;
+	HashResultPointer[1] += B;
+	HashResultPointer[2] += C;
+	HashResultPointer[3] += D;
+	HashResultPointer[4] += E;
+
+}
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_challenge_key                                                 */
+/*                                                                      */
+/************************************************************************/
+static void
+lpfc_challenge_key(uint32_t * RandomChallenge, uint32_t * HashWorking)
+{
+	*HashWorking = (*RandomChallenge ^ *HashWorking);
+}
+
+/************************************************************************/
+/*                                                                      */
+/*   lpfc_hba_init                                                      */
+/*                                                                      */
+/************************************************************************/
+void
+lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
+{
+	int t;
+	uint32_t *HashWorking;
+	uint32_t *pwwnn = phba->wwnn;
+
+	HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
+	if (!HashWorking)
+		return;
+
+	memset(HashWorking, 0, (80 * sizeof(uint32_t)));
+	HashWorking[0] = HashWorking[78] = *pwwnn++;
+	HashWorking[1] = HashWorking[79] = *pwwnn;
+
+	for (t = 0; t < 7; t++)
+		lpfc_challenge_key(phba->RandomData + t, HashWorking + t);
+
+	lpfc_sha_init(hbainit);
+	lpfc_sha_iterate(hbainit, HashWorking);
+	kfree(HashWorking);
+}
+
+static void
+lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind)
+{
+	struct lpfc_nodelist *ndlp, *next_ndlp;
+
+	/* clean up phba - lpfc specific */
+	lpfc_can_disctmo(phba);
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
+				 nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
+				nlp_listp) {
+		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+				nlp_listp) {
+		lpfc_nlp_remove(phba, ndlp);
+	}
+
+	INIT_LIST_HEAD(&phba->fc_nlpmap_list);
+	INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
+	INIT_LIST_HEAD(&phba->fc_unused_list);
+	INIT_LIST_HEAD(&phba->fc_plogi_list);
+	INIT_LIST_HEAD(&phba->fc_adisc_list);
+	INIT_LIST_HEAD(&phba->fc_reglogin_list);
+	INIT_LIST_HEAD(&phba->fc_prli_list);
+	INIT_LIST_HEAD(&phba->fc_npr_list);
+
+	phba->fc_map_cnt   = 0;
+	phba->fc_unmap_cnt = 0;
+	phba->fc_plogi_cnt = 0;
+	phba->fc_adisc_cnt = 0;
+	phba->fc_reglogin_cnt = 0;
+	phba->fc_prli_cnt  = 0;
+	phba->fc_npr_cnt   = 0;
+	phba->fc_unused_cnt= 0;
+	return;
+}
+
+static void
+lpfc_establish_link_tmo(unsigned long ptr)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+	unsigned long iflag;
+
+
+	/* Re-establishing Link, timer expired */
+	lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+			"%d:1300 Re-establishing Link, timer expired "
+			"Data: x%x x%x\n",
+			phba->brd_no, phba->fc_flag, phba->hba_state);
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag &= ~FC_ESTABLISH_LINK;
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+static int
+lpfc_stop_timer(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+
+	/* Instead of a timer, this has been converted to a
+	 * deferred procedding list.
+	 */
+	while (!list_empty(&phba->freebufList)) {
+
+		struct lpfc_dmabuf *mp = NULL;
+
+		list_remove_head((&phba->freebufList), mp,
+				 struct lpfc_dmabuf, list);
+		if (mp) {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
+	}
+
+	del_timer_sync(&phba->fc_estabtmo);
+	del_timer_sync(&phba->fc_disctmo);
+	del_timer_sync(&phba->fc_fdmitmo);
+	del_timer_sync(&phba->els_tmofunc);
+	psli = &phba->sli;
+	del_timer_sync(&psli->mbox_tmo);
+	return(1);
+}
+
+int
+lpfc_online(struct lpfc_hba * phba)
+{
+	if (!phba)
+		return 0;
+
+	if (!(phba->fc_flag & FC_OFFLINE_MODE))
+		return 0;
+
+	lpfc_printf_log(phba,
+		       KERN_WARNING,
+		       LOG_INIT,
+		       "%d:0458 Bring Adapter online\n",
+		       phba->brd_no);
+
+	if (!lpfc_sli_queue_setup(phba))
+		return 1;
+
+	if (lpfc_sli_hba_setup(phba))	/* Initialize the HBA */
+		return 1;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~FC_OFFLINE_MODE;
+	spin_unlock_irq(phba->host->host_lock);
+
+	/*
+	 * Restart all traffic to this host.  Since the fc_transport block
+	 * functions (future) were not called in lpfc_offline, don't call them
+	 * here.
+	 */
+	scsi_unblock_requests(phba->host);
+	return 0;
+}
+
+int
+lpfc_offline(struct lpfc_hba * phba)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	unsigned long iflag;
+	int i = 0;
+
+	if (!phba)
+		return 0;
+
+	if (phba->fc_flag & FC_OFFLINE_MODE)
+		return 0;
+
+	/*
+	 * Don't call the fc_transport block api (future).  The device is
+	 * going offline and causing a timer to fire in the midlayer is
+	 * unproductive.  Just block all new requests until the driver
+	 * comes back online.
+	 */
+	scsi_block_requests(phba->host);
+	psli = &phba->sli;
+	pring = &psli->ring[psli->fcp_ring];
+
+	lpfc_linkdown(phba);
+
+	/* The linkdown event takes 30 seconds to timeout. */
+	while (pring->txcmplq_cnt) {
+		mdelay(10);
+		if (i++ > 3000)
+			break;
+	}
+
+	/* stop all timers associated with this hba */
+	lpfc_stop_timer(phba);
+	phba->work_hba_events = 0;
+
+	lpfc_printf_log(phba,
+		       KERN_WARNING,
+		       LOG_INIT,
+		       "%d:0460 Bring Adapter offline\n",
+		       phba->brd_no);
+
+	/* Bring down the SLI Layer and cleanup.  The HBA is offline
+	   now.  */
+	lpfc_sli_hba_down(phba);
+	lpfc_cleanup(phba, 1);
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag |= FC_OFFLINE_MODE;
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return 0;
+}
+
+/******************************************************************************
+* Function name: lpfc_scsi_free
+*
+* Description: Called from lpfc_pci_remove_one free internal driver resources
+*
+******************************************************************************/
+static int
+lpfc_scsi_free(struct lpfc_hba * phba)
+{
+	struct lpfc_scsi_buf *sb, *sb_next;
+	struct lpfc_iocbq *io, *io_next;
+
+	spin_lock_irq(phba->host->host_lock);
+	/* Release all the lpfc_scsi_bufs maintained by this host. */
+	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
+		list_del(&sb->list);
+		pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
+								sb->dma_handle);
+		kfree(sb);
+		phba->total_scsi_bufs--;
+	}
+
+	/* Release all the lpfc_iocbq entries maintained by this host. */
+	list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) {
+		list_del(&io->list);
+		kfree(io);
+		phba->total_iocbq_bufs--;
+	}
+
+	spin_unlock_irq(phba->host->host_lock);
+
+	return 0;
+}
+
+
+static int __devinit
+lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+	struct Scsi_Host *host;
+	struct lpfc_hba  *phba;
+	struct lpfc_sli  *psli;
+	struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
+	unsigned long bar0map_len, bar2map_len;
+	int error = -ENODEV, retval;
+	int i;
+	u64 wwname;
+
+	if (pci_enable_device(pdev))
+		goto out;
+	if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
+		goto out_disable_device;
+
+	host = scsi_host_alloc(&lpfc_template,
+			sizeof (struct lpfc_hba) + sizeof (unsigned long));
+	if (!host)
+		goto out_release_regions;
+
+	phba = (struct lpfc_hba*)host->hostdata;
+	memset(phba, 0, sizeof (struct lpfc_hba));
+	phba->link_stats = (void *)&phba[1];
+	phba->host = host;
+
+	phba->fc_flag |= FC_LOADING;
+	phba->pcidev = pdev;
+
+	/* Assign an unused board number */
+	if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
+		goto out_put_host;
+
+	error = idr_get_new(&lpfc_hba_index, NULL, &phba->brd_no);
+	if (error)
+		goto out_put_host;
+
+	host->unique_id = phba->brd_no;
+
+	INIT_LIST_HEAD(&phba->ctrspbuflist);
+	INIT_LIST_HEAD(&phba->rnidrspbuflist);
+	INIT_LIST_HEAD(&phba->freebufList);
+
+	/* Initialize timers used by driver */
+	init_timer(&phba->fc_estabtmo);
+	phba->fc_estabtmo.function = lpfc_establish_link_tmo;
+	phba->fc_estabtmo.data = (unsigned long)phba;
+	init_timer(&phba->fc_disctmo);
+	phba->fc_disctmo.function = lpfc_disc_timeout;
+	phba->fc_disctmo.data = (unsigned long)phba;
+
+	init_timer(&phba->fc_fdmitmo);
+	phba->fc_fdmitmo.function = lpfc_fdmi_tmo;
+	phba->fc_fdmitmo.data = (unsigned long)phba;
+	init_timer(&phba->els_tmofunc);
+	phba->els_tmofunc.function = lpfc_els_timeout;
+	phba->els_tmofunc.data = (unsigned long)phba;
+	psli = &phba->sli;
+	init_timer(&psli->mbox_tmo);
+	psli->mbox_tmo.function = lpfc_mbox_timeout;
+	psli->mbox_tmo.data = (unsigned long)phba;
+
+	/*
+	 * Get all the module params for configuring this host and then
+	 * establish the host parameters.
+	 */
+	lpfc_get_cfgparam(phba);
+
+	host->max_id = LPFC_MAX_TARGET;
+	host->max_lun = phba->cfg_max_luns;
+	host->this_id = -1;
+
+	/* Initialize all internally managed lists. */
+	INIT_LIST_HEAD(&phba->fc_nlpmap_list);
+	INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
+	INIT_LIST_HEAD(&phba->fc_unused_list);
+	INIT_LIST_HEAD(&phba->fc_plogi_list);
+	INIT_LIST_HEAD(&phba->fc_adisc_list);
+	INIT_LIST_HEAD(&phba->fc_reglogin_list);
+	INIT_LIST_HEAD(&phba->fc_prli_list);
+	INIT_LIST_HEAD(&phba->fc_npr_list);
+
+
+	pci_set_master(pdev);
+	retval = pci_set_mwi(pdev);
+	if (retval)
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "Warning: pci_set_mwi returned %d\n", retval);
+
+	if (pci_set_dma_mask(phba->pcidev, DMA_64BIT_MASK) != 0)
+		if (pci_set_dma_mask(phba->pcidev, DMA_32BIT_MASK) != 0)
+			goto out_idr_remove;
+
+	/*
+	 * Get the bus address of Bar0 and Bar2 and the number of bytes
+	 * required by each mapping.
+	 */
+	phba->pci_bar0_map = pci_resource_start(phba->pcidev, 0);
+	bar0map_len        = pci_resource_len(phba->pcidev, 0);
+
+	phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2);
+	bar2map_len        = pci_resource_len(phba->pcidev, 2);
+
+	/* Map HBA SLIM and Control Registers to a kernel virtual address. */
+	phba->slim_memmap_p      = ioremap(phba->pci_bar0_map, bar0map_len);
+	phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
+
+	/* Allocate memory for SLI-2 structures */
+	phba->slim2p = dma_alloc_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
+					  &phba->slim2p_mapping, GFP_KERNEL);
+	if (!phba->slim2p)
+		goto out_iounmap;
+
+
+	/* Initialize the SLI Layer to run with lpfc HBAs. */
+	lpfc_sli_setup(phba);
+	lpfc_sli_queue_setup(phba);
+
+	error = lpfc_mem_alloc(phba);
+	if (error)
+		goto out_free_slim;
+
+	/* Initialize and populate the iocb list per host.  */
+	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
+	for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
+		iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+		if (iocbq_entry == NULL) {
+			printk(KERN_ERR "%s: only allocated %d iocbs of "
+				"expected %d count. Unloading driver.\n",
+				__FUNCTION__, i, LPFC_IOCB_LIST_CNT);
+			error = -ENOMEM;
+			goto out_free_iocbq;
+		}
+
+		memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
+		spin_lock_irq(phba->host->host_lock);
+		list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
+		phba->total_iocbq_bufs++;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+
+	/* Initialize HBA structure */
+	phba->fc_edtov = FF_DEF_EDTOV;
+	phba->fc_ratov = FF_DEF_RATOV;
+	phba->fc_altov = FF_DEF_ALTOV;
+	phba->fc_arbtov = FF_DEF_ARBTOV;
+
+	INIT_LIST_HEAD(&phba->work_list);
+	phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT);
+	phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+
+	/* Startup the kernel thread for this host adapter. */
+	phba->worker_thread = kthread_run(lpfc_do_work, phba,
+				       "lpfc_worker_%d", phba->brd_no);
+	if (IS_ERR(phba->worker_thread)) {
+		error = PTR_ERR(phba->worker_thread);
+		goto out_free_iocbq;
+	}
+
+	/* We can rely on a queue depth attribute only after SLI HBA setup */
+	host->can_queue = phba->cfg_hba_queue_depth - 10;
+
+	/* Tell the midlayer we support 16 byte commands */
+	host->max_cmd_len = 16;
+
+	/* Initialize the list of scsi buffers used by driver for scsi IO. */
+	INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
+
+	host->transportt = lpfc_transport_template;
+	host->hostdata[0] = (unsigned long)phba;
+	pci_set_drvdata(pdev, host);
+	error = scsi_add_host(host, &pdev->dev);
+	if (error)
+		goto out_kthread_stop;
+
+	error = lpfc_alloc_sysfs_attr(phba);
+	if (error)
+		goto out_kthread_stop;
+
+	error =	request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ,
+							LPFC_DRIVER_NAME, phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"%d:0451 Enable interrupt handler failed\n",
+			phba->brd_no);
+		goto out_free_sysfs_attr;
+	}
+	phba->MBslimaddr = phba->slim_memmap_p;
+	phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+	phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+	error = lpfc_sli_hba_setup(phba);
+	if (error)
+		goto out_free_irq;
+
+	/*
+	 * set fixed host attributes
+	 * Must done after lpfc_sli_hba_setup()
+	 */
+
+	memcpy(&wwname, &phba->fc_nodename, sizeof(u64));
+	fc_host_node_name(host) = be64_to_cpu(wwname);
+	memcpy(&wwname, &phba->fc_portname, sizeof(u64));
+	fc_host_port_name(host) = be64_to_cpu(wwname);
+	fc_host_supported_classes(host) = FC_COS_CLASS3;
+
+	memset(fc_host_supported_fc4s(host), 0,
+		sizeof(fc_host_supported_fc4s(host)));
+	fc_host_supported_fc4s(host)[2] = 1;
+	fc_host_supported_fc4s(host)[7] = 1;
+
+	lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
+
+	fc_host_supported_speeds(host) = 0;
+	switch (FC_JEDEC_ID(phba->vpd.rev.biuRev)) {
+	case VIPER_JEDEC_ID:
+		fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
+		break;
+	case HELIOS_JEDEC_ID:
+		fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
+		/* Fall through */
+	case CENTAUR_2G_JEDEC_ID:
+	case PEGASUS_JEDEC_ID:
+	case THOR_JEDEC_ID:
+		fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
+		/* Fall through */
+	default:
+		fc_host_supported_speeds(host) = FC_PORTSPEED_1GBIT;
+	}
+
+	fc_host_maxframe_size(host) =
+		((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+		 (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+
+	/* This value is also unchanging */
+	memset(fc_host_active_fc4s(host), 0,
+		sizeof(fc_host_active_fc4s(host)));
+	fc_host_active_fc4s(host)[2] = 1;
+	fc_host_active_fc4s(host)[7] = 1;
+
+	spin_lock_irq(phba->host->host_lock);
+	phba->fc_flag &= ~FC_LOADING;
+	spin_unlock_irq(phba->host->host_lock);
+	return 0;
+
+out_free_irq:
+	lpfc_stop_timer(phba);
+	phba->work_hba_events = 0;
+	free_irq(phba->pcidev->irq, phba);
+out_free_sysfs_attr:
+	lpfc_free_sysfs_attr(phba);
+out_kthread_stop:
+	kthread_stop(phba->worker_thread);
+out_free_iocbq:
+	list_for_each_entry_safe(iocbq_entry, iocbq_next,
+						&phba->lpfc_iocb_list, list) {
+		spin_lock_irq(phba->host->host_lock);
+		kfree(iocbq_entry);
+		phba->total_iocbq_bufs--;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+	lpfc_mem_free(phba);
+out_free_slim:
+	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p,
+							phba->slim2p_mapping);
+out_iounmap:
+	iounmap(phba->ctrl_regs_memmap_p);
+	iounmap(phba->slim_memmap_p);
+out_idr_remove:
+	idr_remove(&lpfc_hba_index, phba->brd_no);
+out_put_host:
+	scsi_host_put(host);
+out_release_regions:
+	pci_release_regions(pdev);
+out_disable_device:
+	pci_disable_device(pdev);
+out:
+	return error;
+}
+
+static void __devexit
+lpfc_pci_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host   *host = pci_get_drvdata(pdev);
+	struct lpfc_hba    *phba = (struct lpfc_hba *)host->hostdata[0];
+	unsigned long iflag;
+
+	lpfc_free_sysfs_attr(phba);
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag |= FC_UNLOADING;
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+	fc_remove_host(phba->host);
+	scsi_remove_host(phba->host);
+
+	kthread_stop(phba->worker_thread);
+
+	/*
+	 * Bring down the SLI Layer. This step disable all interrupts,
+	 * clears the rings, discards all mailbox commands, and resets
+	 * the HBA.
+	 */
+	lpfc_sli_hba_down(phba);
+
+	/* Release the irq reservation */
+	free_irq(phba->pcidev->irq, phba);
+
+	lpfc_cleanup(phba, 0);
+	lpfc_stop_timer(phba);
+	phba->work_hba_events = 0;
+
+	/*
+	 * Call scsi_free before mem_free since scsi bufs are released to their
+	 * corresponding pools here.
+	 */
+	lpfc_scsi_free(phba);
+	lpfc_mem_free(phba);
+
+	/* Free resources associated with SLI2 interface */
+	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+			  phba->slim2p, phba->slim2p_mapping);
+
+	/* unmap adapter SLIM and Control Registers */
+	iounmap(phba->ctrl_regs_memmap_p);
+	iounmap(phba->slim_memmap_p);
+
+	pci_release_regions(phba->pcidev);
+	pci_disable_device(phba->pcidev);
+
+	idr_remove(&lpfc_hba_index, phba->brd_no);
+	scsi_host_put(phba->host);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_device_id lpfc_id_table[] = {
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, lpfc_id_table);
+
+static struct pci_driver lpfc_driver = {
+	.name		= LPFC_DRIVER_NAME,
+	.id_table	= lpfc_id_table,
+	.probe		= lpfc_pci_probe_one,
+	.remove		= __devexit_p(lpfc_pci_remove_one),
+};
+
+static int __init
+lpfc_init(void)
+{
+	int error = 0;
+
+	printk(LPFC_MODULE_DESC "\n");
+
+	lpfc_transport_template =
+				fc_attach_transport(&lpfc_transport_functions);
+	if (!lpfc_transport_template)
+		return -ENOMEM;
+	error = pci_register_driver(&lpfc_driver);
+	if (error)
+		fc_release_transport(lpfc_transport_template);
+
+	return error;
+}
+
+static void __exit
+lpfc_exit(void)
+{
+	pci_unregister_driver(&lpfc_driver);
+	fc_release_transport(lpfc_transport_template);
+}
+
+module_init(lpfc_init);
+module_exit(lpfc_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(LPFC_MODULE_DESC);
+MODULE_AUTHOR("Emulex Corporation - tech.support@emulex.com");
+MODULE_VERSION("0:" LPFC_DRIVER_VERSION);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -0,0 +1,41 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_logmsg.h 1.32 2005/01/25 17:52:01EST sf_support Exp  $
+ */
+
+#define LOG_ELS                       0x1	/* ELS events */
+#define LOG_DISCOVERY                 0x2	/* Link discovery events */
+#define LOG_MBOX                      0x4	/* Mailbox events */
+#define LOG_INIT                      0x8	/* Initialization events */
+#define LOG_LINK_EVENT                0x10	/* Link events */
+#define LOG_IP                        0x20	/* IP traffic history */
+#define LOG_FCP                       0x40	/* FCP traffic history */
+#define LOG_NODE                      0x80	/* Node table events */
+#define LOG_MISC                      0x400	/* Miscellaneous events */
+#define LOG_SLI                       0x800	/* SLI events */
+#define LOG_CHK_COND                  0x1000	/* FCP Check condition flag */
+#define LOG_LIBDFC                    0x2000	/* Libdfc events */
+#define LOG_ALL_MSG                   0xffff	/* LOG all messages */
+
+#define lpfc_printf_log(phba, level, mask, fmt, arg...) \
+	{ if (((mask) &(phba)->cfg_log_verbose) || (level[1] <= '3')) \
+		dev_printk(level, &((phba)->pcidev)->dev, fmt, ##arg); }
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -0,0 +1,646 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_mbox.c 1.85 2005/04/13 11:59:11EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_compat.h"
+
+/**********************************************/
+
+/*                mailbox command             */
+/**********************************************/
+void
+lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
+{
+	MAILBOX_t *mb;
+	void *ctx;
+
+	mb = &pmb->mb;
+	ctx = pmb->context2;
+
+	/* Setup to dump VPD region */
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_DUMP_MEMORY;
+	mb->un.varDmp.cv = 1;
+	mb->un.varDmp.type = DMP_NV_PARAMS;
+	mb->un.varDmp.entry_index = offset;
+	mb->un.varDmp.region_id = DMP_REGION_VPD;
+	mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t));
+	mb->un.varDmp.co = 0;
+	mb->un.varDmp.resp_offset = 0;
+	pmb->context2 = ctx;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
+/*  lpfc_read_nv  Issue a READ NVPARAM        */
+/*                mailbox command             */
+/**********************************************/
+void
+lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_READ_NV;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
+/*  lpfc_read_la  Issue a READ LA             */
+/*                mailbox command             */
+/**********************************************/
+int
+lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
+{
+	MAILBOX_t *mb;
+	struct lpfc_sli *psli;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	INIT_LIST_HEAD(&mp->list);
+	mb->mbxCommand = MBX_READ_LA64;
+	mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
+	mb->un.varReadLA.un.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
+	mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(mp->phys);
+
+	/* Save address for later completion and set the owner to host so that
+	 * the FW knows this mailbox is available for processing.
+	 */
+	pmb->context1 = (uint8_t *) mp;
+	mb->mbxOwner = OWN_HOST;
+	return (0);
+}
+
+/**********************************************/
+/*  lpfc_clear_la  Issue a CLEAR LA           */
+/*                 mailbox command            */
+/**********************************************/
+void
+lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varClearLA.eventTag = phba->fc_eventTag;
+	mb->mbxCommand = MBX_CLEAR_LA;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**************************************************/
+/*  lpfc_config_link  Issue a CONFIG LINK         */
+/*                    mailbox command             */
+/**************************************************/
+void
+lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	/* NEW_FEATURE
+	 * SLI-2, Coalescing Response Feature.
+	 */
+	if (phba->cfg_cr_delay) {
+		mb->un.varCfgLnk.cr = 1;
+		mb->un.varCfgLnk.ci = 1;
+		mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
+		mb->un.varCfgLnk.cr_count = phba->cfg_cr_count;
+	}
+
+	mb->un.varCfgLnk.myId = phba->fc_myDID;
+	mb->un.varCfgLnk.edtov = phba->fc_edtov;
+	mb->un.varCfgLnk.arbtov = phba->fc_arbtov;
+	mb->un.varCfgLnk.ratov = phba->fc_ratov;
+	mb->un.varCfgLnk.rttov = phba->fc_rttov;
+	mb->un.varCfgLnk.altov = phba->fc_altov;
+	mb->un.varCfgLnk.crtov = phba->fc_crtov;
+	mb->un.varCfgLnk.citov = phba->fc_citov;
+
+	if (phba->cfg_ack0)
+		mb->un.varCfgLnk.ack0_enable = 1;
+
+	mb->mbxCommand = MBX_CONFIG_LINK;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
+/*  lpfc_init_link  Issue an INIT LINK        */
+/*                  mailbox command           */
+/**********************************************/
+void
+lpfc_init_link(struct lpfc_hba * phba,
+	       LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed)
+{
+	lpfc_vpd_t *vpd;
+	struct lpfc_sli *psli;
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	psli = &phba->sli;
+	switch (topology) {
+	case FLAGS_TOPOLOGY_MODE_LOOP_PT:
+		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
+		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
+		break;
+	case FLAGS_TOPOLOGY_MODE_PT_PT:
+		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
+		break;
+	case FLAGS_TOPOLOGY_MODE_LOOP:
+		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
+		break;
+	case FLAGS_TOPOLOGY_MODE_PT_LOOP:
+		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
+		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
+		break;
+	}
+
+	/* NEW_FEATURE
+	 * Setting up the link speed
+	 */
+	vpd = &phba->vpd;
+	if (vpd->rev.feaLevelHigh >= 0x02){
+		switch(linkspeed){
+			case LINK_SPEED_1G:
+			case LINK_SPEED_2G:
+			case LINK_SPEED_4G:
+				mb->un.varInitLnk.link_flags |=
+							FLAGS_LINK_SPEED;
+				mb->un.varInitLnk.link_speed = linkspeed;
+			break;
+			case LINK_SPEED_AUTO:
+			default:
+				mb->un.varInitLnk.link_speed =
+							LINK_SPEED_AUTO;
+			break;
+		}
+
+	}
+	else
+		mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
+
+	mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
+	mb->mbxOwner = OWN_HOST;
+	mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
+	return;
+}
+
+/**********************************************/
+/*  lpfc_read_sparam  Issue a READ SPARAM     */
+/*                    mailbox command         */
+/**********************************************/
+int
+lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_dmabuf *mp;
+	MAILBOX_t *mb;
+	struct lpfc_sli *psli;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->mbxOwner = OWN_HOST;
+
+	/* Get a buffer to hold the HBAs Service Parameters */
+
+	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+		if (mp)
+			kfree(mp);
+		mb->mbxCommand = MBX_READ_SPARM64;
+		/* READ_SPARAM: no buffers */
+		lpfc_printf_log(phba,
+			        KERN_WARNING,
+			        LOG_MBOX,
+			        "%d:0301 READ_SPARAM: no buffers\n",
+			        phba->brd_no);
+		return (1);
+	}
+	INIT_LIST_HEAD(&mp->list);
+	mb->mbxCommand = MBX_READ_SPARM64;
+	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
+	mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
+	mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
+
+	/* save address for completion */
+	pmb->context1 = mp;
+
+	return (0);
+}
+
+/********************************************/
+/*  lpfc_unreg_did  Issue a UNREG_DID       */
+/*                  mailbox command         */
+/********************************************/
+void
+lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varUnregDID.did = did;
+
+	mb->mbxCommand = MBX_UNREG_D_ID;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/***********************************************/
+
+/*                  command to write slim      */
+/***********************************************/
+void
+lpfc_set_slim(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr,
+	      uint32_t value)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	/* addr = 0x090597 is AUTO ABTS disable for ELS commands */
+	/* addr = 0x052198 is DELAYED ABTS enable for ELS commands */
+
+	/*
+	 * Always turn on DELAYED ABTS for ELS timeouts
+	 */
+	if ((addr == 0x052198) && (value == 0))
+		value = 1;
+
+	mb->un.varWords[0] = addr;
+	mb->un.varWords[1] = value;
+
+	mb->mbxCommand = MBX_SET_SLIM;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
+/*  lpfc_read_nv  Issue a READ CONFIG         */
+/*                mailbox command             */
+/**********************************************/
+void
+lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->mbxCommand = MBX_READ_CONFIG;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/********************************************/
+/*  lpfc_reg_login  Issue a REG_LOGIN       */
+/*                  mailbox command         */
+/********************************************/
+int
+lpfc_reg_login(struct lpfc_hba * phba,
+	       uint32_t did, uint8_t * param, LPFC_MBOXQ_t * pmb, uint32_t flag)
+{
+	uint8_t *sparam;
+	struct lpfc_dmabuf *mp;
+	MAILBOX_t *mb;
+	struct lpfc_sli *psli;
+
+	psli = &phba->sli;
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varRegLogin.rpi = 0;
+	mb->un.varRegLogin.did = did;
+	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */
+
+	mb->mbxOwner = OWN_HOST;
+
+	/* Get a buffer to hold NPorts Service Parameters */
+	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
+	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+		if (mp)
+			kfree(mp);
+
+		mb->mbxCommand = MBX_REG_LOGIN64;
+		/* REG_LOGIN: no buffers */
+		lpfc_printf_log(phba,
+			       KERN_WARNING,
+			       LOG_MBOX,
+			       "%d:0302 REG_LOGIN: no buffers Data x%x x%x\n",
+			       phba->brd_no,
+			       (uint32_t) did, (uint32_t) flag);
+		return (1);
+	}
+	INIT_LIST_HEAD(&mp->list);
+	sparam = mp->virt;
+
+	/* Copy param's into a new buffer */
+	memcpy(sparam, param, sizeof (struct serv_parm));
+
+	/* save address for completion */
+	pmb->context1 = (uint8_t *) mp;
+
+	mb->mbxCommand = MBX_REG_LOGIN64;
+	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
+	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
+	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);
+
+	return (0);
+}
+
+/**********************************************/
+/*  lpfc_unreg_login  Issue a UNREG_LOGIN     */
+/*                    mailbox command         */
+/**********************************************/
+void
+lpfc_unreg_login(struct lpfc_hba * phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varUnregLogin.rpi = (uint16_t) rpi;
+	mb->un.varUnregLogin.rsvd1 = 0;
+
+	mb->mbxCommand = MBX_UNREG_LOGIN;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+static void
+lpfc_config_pcb_setup(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring *pring;
+	PCB_t *pcbp = &phba->slim2p->pcb;
+	dma_addr_t pdma_addr;
+	uint32_t offset;
+	uint32_t iocbCnt;
+	int i;
+
+	psli->MBhostaddr = (uint32_t *)&phba->slim2p->mbx;
+	pcbp->maxRing = (psli->num_rings - 1);
+
+	iocbCnt = 0;
+	for (i = 0; i < psli->num_rings; i++) {
+		pring = &psli->ring[i];
+		/* A ring MUST have both cmd and rsp entries defined to be
+		   valid */
+		if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
+			pcbp->rdsc[i].cmdEntries = 0;
+			pcbp->rdsc[i].rspEntries = 0;
+			pcbp->rdsc[i].cmdAddrHigh = 0;
+			pcbp->rdsc[i].rspAddrHigh = 0;
+			pcbp->rdsc[i].cmdAddrLow = 0;
+			pcbp->rdsc[i].rspAddrLow = 0;
+			pring->cmdringaddr = NULL;
+			pring->rspringaddr = NULL;
+			continue;
+		}
+		/* Command ring setup for ring */
+		pring->cmdringaddr =
+		    (void *)&phba->slim2p->IOCBs[iocbCnt];
+		pcbp->rdsc[i].cmdEntries = pring->numCiocb;
+
+		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
+			 (uint8_t *)phba->slim2p;
+		pdma_addr = phba->slim2p_mapping + offset;
+		pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr);
+		pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr);
+		iocbCnt += pring->numCiocb;
+
+		/* Response ring setup for ring */
+		pring->rspringaddr =
+		    (void *)&phba->slim2p->IOCBs[iocbCnt];
+
+		pcbp->rdsc[i].rspEntries = pring->numRiocb;
+		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
+			 (uint8_t *)phba->slim2p;
+		pdma_addr = phba->slim2p_mapping + offset;
+		pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr);
+		pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr);
+		iocbCnt += pring->numRiocb;
+	}
+}
+
+void
+lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	mb->un.varRdRev.cv = 1;
+	mb->mbxCommand = MBX_READ_REV;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+void
+lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
+{
+	int i;
+	MAILBOX_t *mb = &pmb->mb;
+	struct lpfc_sli *psli;
+	struct lpfc_sli_ring *pring;
+
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varCfgRing.ring = ring;
+	mb->un.varCfgRing.maxOrigXchg = 0;
+	mb->un.varCfgRing.maxRespXchg = 0;
+	mb->un.varCfgRing.recvNotify = 1;
+
+	psli = &phba->sli;
+	pring = &psli->ring[ring];
+	mb->un.varCfgRing.numMask = pring->num_mask;
+	mb->mbxCommand = MBX_CONFIG_RING;
+	mb->mbxOwner = OWN_HOST;
+
+	/* Is this ring configured for a specific profile */
+	if (pring->prt[0].profile) {
+		mb->un.varCfgRing.profile = pring->prt[0].profile;
+		return;
+	}
+
+	/* Otherwise we setup specific rctl / type masks for this ring */
+	for (i = 0; i < pring->num_mask; i++) {
+		mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl;
+		if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ)
+			mb->un.varCfgRing.rrRegs[i].rmask = 0xff;
+		else
+			mb->un.varCfgRing.rrRegs[i].rmask = 0xfe;
+		mb->un.varCfgRing.rrRegs[i].tval = pring->prt[i].type;
+		mb->un.varCfgRing.rrRegs[i].tmask = 0xff;
+	}
+
+	return;
+}
+
+void
+lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb = &pmb->mb;
+	dma_addr_t pdma_addr;
+	uint32_t bar_low, bar_high;
+	size_t offset;
+	HGP hgp;
+	void __iomem *to_slim;
+
+	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_CONFIG_PORT;
+	mb->mbxOwner = OWN_HOST;
+
+	mb->un.varCfgPort.pcbLen = sizeof(PCB_t);
+
+	offset = (uint8_t *)&phba->slim2p->pcb - (uint8_t *)phba->slim2p;
+	pdma_addr = phba->slim2p_mapping + offset;
+	mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
+	mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
+
+	/* Now setup pcb */
+	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
+	phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
+
+	/* Setup Mailbox pointers */
+	phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
+	offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
+	pdma_addr = phba->slim2p_mapping + offset;
+	phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
+	phba->slim2p->pcb.mbAddrLow = putPaddrLow(pdma_addr);
+
+	/*
+	 * Setup Host Group ring pointer.
+	 *
+	 * For efficiency reasons, the ring get/put pointers can be
+	 * placed in adapter memory (SLIM) rather than in host memory.
+	 * This allows firmware to avoid PCI reads/writes when updating
+	 * and checking pointers.
+	 *
+	 * The firmware recognizes the use of SLIM memory by comparing
+	 * the address of the get/put pointers structure with that of
+	 * the SLIM BAR (BAR0).
+	 *
+	 * Caution: be sure to use the PCI config space value of BAR0/BAR1
+	 * (the hardware's view of the base address), not the OS's
+	 * value of pci_resource_start() as the OS value may be a cookie
+	 * for ioremap/iomap.
+	 */
+
+
+	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
+	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
+
+
+	/* mask off BAR0's flag bits 0 - 3 */
+	phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
+					(SLIMOFF*sizeof(uint32_t));
+	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
+		phba->slim2p->pcb.hgpAddrHigh = bar_high;
+	else
+		phba->slim2p->pcb.hgpAddrHigh = 0;
+	/* write HGP data to SLIM at the required longword offset */
+	memset(&hgp, 0, sizeof(HGP));
+	to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
+	lpfc_memcpy_to_slim(to_slim, &hgp, sizeof (HGP));
+
+	/* Setup Port Group ring pointer */
+	offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
+		 (uint8_t *)phba->slim2p;
+	pdma_addr = phba->slim2p_mapping + offset;
+	phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
+	phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
+
+	/* Use callback routine to setp rings in the pcb */
+	lpfc_config_pcb_setup(phba);
+
+	/* special handling for LC HBAs */
+	if (lpfc_is_LC_HBA(phba->pcidev->device)) {
+		uint32_t hbainit[5];
+
+		lpfc_hba_init(phba, hbainit);
+
+		memcpy(&mb->un.varCfgPort.hbainit, hbainit, 20);
+	}
+
+	/* Swap PCB if needed */
+	lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
+								sizeof (PCB_t));
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+		        "%d:0405 Service Level Interface (SLI) 2 selected\n",
+		        phba->brd_no);
+}
+
+void
+lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+{
+	struct lpfc_sli *psli;
+
+	psli = &phba->sli;
+
+	list_add_tail(&mbq->list, &psli->mboxq);
+
+	psli->mboxq_cnt++;
+
+	return;
+}
+
+LPFC_MBOXQ_t *
+lpfc_mbox_get(struct lpfc_hba * phba)
+{
+	LPFC_MBOXQ_t *mbq = NULL;
+	struct lpfc_sli *psli = &phba->sli;
+
+	list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t,
+			 list);
+	if (mbq) {
+		psli->mboxq_cnt--;
+	}
+
+	return mbq;
+}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -0,0 +1,179 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_mem.c 1.79 2005/04/13 14:25:50EDT sf_support Exp  $
+ */
+
+#include <linux/mempool.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_crtn.h"
+
+#define LPFC_MBUF_POOL_SIZE     64      /* max elements in MBUF safety pool */
+#define LPFC_MEM_POOL_SIZE      64      /* max elem in non-DMA safety pool */
+
+static void *
+lpfc_pool_kmalloc(unsigned int gfp_flags, void *data)
+{
+	return kmalloc((unsigned long)data, gfp_flags);
+}
+
+static void
+lpfc_pool_kfree(void *obj, void *data)
+{
+	kfree(obj);
+}
+
+int
+lpfc_mem_alloc(struct lpfc_hba * phba)
+{
+	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+	int i;
+
+	phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
+				phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0);
+	if (!phba->lpfc_scsi_dma_buf_pool)
+		goto fail;
+
+	phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev,
+							LPFC_BPL_SIZE, 8,0);
+	if (!phba->lpfc_mbuf_pool)
+		goto fail_free_dma_buf_pool;
+
+	pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) *
+					 LPFC_MBUF_POOL_SIZE, GFP_KERNEL);
+	pool->max_count = 0;
+	pool->current_count = 0;
+	for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) {
+		pool->elements[i].virt = pci_pool_alloc(phba->lpfc_mbuf_pool,
+				       GFP_KERNEL, &pool->elements[i].phys);
+		if (!pool->elements[i].virt)
+			goto fail_free_mbuf_pool;
+		pool->max_count++;
+		pool->current_count++;
+	}
+
+	phba->mbox_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
+				lpfc_pool_kmalloc, lpfc_pool_kfree,
+				(void *)(unsigned long)sizeof(LPFC_MBOXQ_t));
+	if (!phba->mbox_mem_pool)
+		goto fail_free_mbuf_pool;
+
+	phba->nlp_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
+			lpfc_pool_kmalloc, lpfc_pool_kfree,
+			(void *)(unsigned long)sizeof(struct lpfc_nodelist));
+	if (!phba->nlp_mem_pool)
+		goto fail_free_mbox_pool;
+
+	return 0;
+
+ fail_free_mbox_pool:
+	mempool_destroy(phba->mbox_mem_pool);
+ fail_free_mbuf_pool:
+	while (--i)
+		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
+						 pool->elements[i].phys);
+	kfree(pool->elements);
+	pci_pool_destroy(phba->lpfc_mbuf_pool);
+ fail_free_dma_buf_pool:
+	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+ fail:
+	return -ENOMEM;
+}
+
+void
+lpfc_mem_free(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+	LPFC_MBOXQ_t *mbox, *next_mbox;
+	struct lpfc_dmabuf   *mp;
+	int i;
+
+	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
+		mp = (struct lpfc_dmabuf *) (mbox->context1);
+		if (mp) {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
+		list_del(&mbox->list);
+		mempool_free(mbox, phba->mbox_mem_pool);
+	}
+
+	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	if (psli->mbox_active) {
+		mbox = psli->mbox_active;
+		mp = (struct lpfc_dmabuf *) (mbox->context1);
+		if (mp) {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
+		mempool_free(mbox, phba->mbox_mem_pool);
+		psli->mbox_active = NULL;
+	}
+
+	for (i = 0; i < pool->current_count; i++)
+		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
+						 pool->elements[i].phys);
+	kfree(pool->elements);
+	mempool_destroy(phba->nlp_mem_pool);
+	mempool_destroy(phba->mbox_mem_pool);
+
+	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+	pci_pool_destroy(phba->lpfc_mbuf_pool);
+}
+
+void *
+lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+{
+	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+	void *ret;
+
+	ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
+
+	if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
+		pool->current_count--;
+		ret = pool->elements[pool->current_count].virt;
+		*handle = pool->elements[pool->current_count].phys;
+	}
+	return ret;
+}
+
+void
+lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+{
+	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+
+	if (pool->current_count < pool->max_count) {
+		pool->elements[pool->current_count].virt = virt;
+		pool->elements[pool->current_count].phys = dma;
+		pool->current_count++;
+	} else {
+		pci_pool_free(phba->lpfc_mbuf_pool, virt, dma);
+	}
+	return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -0,0 +1,1842 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_nportdisc.c 1.179 2005/04/13 11:59:13EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+
+
+/* Called to verify a rcv'ed ADISC was intended for us. */
+static int
+lpfc_check_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+		 struct lpfc_name * nn, struct lpfc_name * pn)
+{
+	/* Compare the ADISC rsp WWNN / WWPN matches our internal node
+	 * table entry for that node.
+	 */
+	if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)) != 0)
+		return (0);
+
+	if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)) != 0)
+		return (0);
+
+	/* we match, return success */
+	return (1);
+}
+
+
+int
+lpfc_check_sparm(struct lpfc_hba * phba,
+		 struct lpfc_nodelist * ndlp, struct serv_parm * sp,
+		 uint32_t class)
+{
+	volatile struct serv_parm *hsp = &phba->fc_sparam;
+	/* First check for supported version */
+
+	/* Next check for class validity */
+	if (sp->cls1.classValid) {
+
+		if (sp->cls1.rcvDataSizeMsb > hsp->cls1.rcvDataSizeMsb)
+			sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
+		if (sp->cls1.rcvDataSizeLsb > hsp->cls1.rcvDataSizeLsb)
+			sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
+	} else if (class == CLASS1) {
+		return (0);
+	}
+
+	if (sp->cls2.classValid) {
+
+		if (sp->cls2.rcvDataSizeMsb > hsp->cls2.rcvDataSizeMsb)
+			sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
+		if (sp->cls2.rcvDataSizeLsb > hsp->cls2.rcvDataSizeLsb)
+			sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
+	} else if (class == CLASS2) {
+		return (0);
+	}
+
+	if (sp->cls3.classValid) {
+
+		if (sp->cls3.rcvDataSizeMsb > hsp->cls3.rcvDataSizeMsb)
+			sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
+		if (sp->cls3.rcvDataSizeLsb > hsp->cls3.rcvDataSizeLsb)
+			sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
+	} else if (class == CLASS3) {
+		return (0);
+	}
+
+	if (sp->cmn.bbRcvSizeMsb > hsp->cmn.bbRcvSizeMsb)
+		sp->cmn.bbRcvSizeMsb = hsp->cmn.bbRcvSizeMsb;
+	if (sp->cmn.bbRcvSizeLsb > hsp->cmn.bbRcvSizeLsb)
+		sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb;
+
+	/* If check is good, copy wwpn wwnn into ndlp */
+	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
+	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
+	return (1);
+}
+
+static void *
+lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
+		      struct lpfc_iocbq *cmdiocb,
+		      struct lpfc_iocbq *rspiocb)
+{
+	struct lpfc_dmabuf *pcmd, *prsp;
+	uint32_t *lp;
+	void     *ptr = NULL;
+	IOCB_t   *irsp;
+
+	irsp = &rspiocb->iocb;
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+	/* For lpfc_els_abort, context2 could be zero'ed to delay
+	 * freeing associated memory till after ABTS completes.
+	 */
+	if (pcmd) {
+		prsp =  list_get_first(&pcmd->list, struct lpfc_dmabuf,
+				       list);
+		if (prsp) {
+			lp = (uint32_t *) prsp->virt;
+			ptr = (void *)((uint8_t *)lp + sizeof(uint32_t));
+		}
+	}
+	else {
+		/* Force ulpStatus error since we are returning NULL ptr */
+		if (!(irsp->ulpStatus)) {
+			irsp->ulpStatus = IOSTAT_LOCAL_REJECT;
+			irsp->un.ulpWord[4] = IOERR_SLI_ABORTED;
+		}
+		ptr = NULL;
+	}
+	return (ptr);
+}
+
+
+/*
+ * Free resources / clean up outstanding I/Os
+ * associated with a LPFC_NODELIST entry. This
+ * routine effectively results in a "software abort".
+ */
+int
+lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+	int send_abts)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *iocb, *next_iocb;
+	IOCB_t *icmd;
+	int    found = 0;
+
+	/* Abort outstanding I/O on NPort <nlp_DID> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			"%d:0201 Abort outstanding I/O on NPort x%x "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+			ndlp->nlp_state, ndlp->nlp_rpi);
+
+	psli = &phba->sli;
+	pring = &psli->ring[LPFC_ELS_RING];
+
+	/* First check the txq */
+	do {
+		found = 0;
+		spin_lock_irq(phba->host->host_lock);
+		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+			/* Check to see if iocb matches the nport we are looking
+			   for */
+			if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
+				found = 1;
+				/* It matches, so deque and call compl with an
+				   error */
+				list_del(&iocb->list);
+				pring->txq_cnt--;
+				if (iocb->iocb_cmpl) {
+					icmd = &iocb->iocb;
+					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+					icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+					spin_unlock_irq(phba->host->host_lock);
+					(iocb->iocb_cmpl) (phba, iocb, iocb);
+					spin_lock_irq(phba->host->host_lock);
+				} else {
+					list_add_tail(&iocb->list,
+							&phba->lpfc_iocb_list);
+				}
+				break;
+			}
+		}
+		spin_unlock_irq(phba->host->host_lock);
+	} while (found);
+
+	/* Everything on txcmplq will be returned by firmware
+	 * with a no rpi / linkdown / abort error.  For ring 0,
+	 * ELS discovery, we want to get rid of it right here.
+	 */
+	/* Next check the txcmplq */
+	do {
+		found = 0;
+		spin_lock_irq(phba->host->host_lock);
+		list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
+					 list) {
+			/* Check to see if iocb matches the nport we are looking
+			   for */
+			if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
+				found = 1;
+				/* It matches, so deque and call compl with an
+				   error */
+				list_del(&iocb->list);
+				pring->txcmplq_cnt--;
+
+				icmd = &iocb->iocb;
+				/* If the driver is completing an ELS
+				 * command early, flush it out of the firmware.
+				 */
+				if (send_abts &&
+				   (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) &&
+				   (icmd->un.elsreq64.bdl.ulpIoTag32)) {
+					lpfc_sli_issue_abort_iotag32(phba,
+							     pring, iocb);
+				}
+				if (iocb->iocb_cmpl) {
+					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+					icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+					spin_unlock_irq(phba->host->host_lock);
+					(iocb->iocb_cmpl) (phba, iocb, iocb);
+					spin_lock_irq(phba->host->host_lock);
+				} else {
+					list_add_tail(&iocb->list,
+							&phba->lpfc_iocb_list);
+				}
+				break;
+			}
+		}
+		spin_unlock_irq(phba->host->host_lock);
+	} while(found);
+
+	/* If we are delaying issuing an ELS command, cancel it */
+	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+		del_timer_sync(&ndlp->nlp_delayfunc);
+		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+			list_del_init(&ndlp->els_retry_evt.evt_listp);
+	}
+	return (0);
+}
+
+static int
+lpfc_rcv_plogi(struct lpfc_hba * phba,
+		      struct lpfc_nodelist * ndlp,
+		      struct lpfc_iocbq *cmdiocb)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	IOCB_t *icmd;
+	struct serv_parm *sp;
+	LPFC_MBOXQ_t *mbox;
+	struct ls_rjt stat;
+	int rc;
+
+	memset(&stat, 0, sizeof (struct ls_rjt));
+	if (phba->hba_state <= LPFC_FLOGI) {
+		/* Before responding to PLOGI, check for pt2pt mode.
+		 * If we are pt2pt, with an outstanding FLOGI, abort
+		 * the FLOGI and resend it first.
+		 */
+		if (phba->fc_flag & FC_PT2PT) {
+			lpfc_els_abort_flogi(phba);
+		        if (!(phba->fc_flag & FC_PT2PT_PLOGI)) {
+				/* If the other side is supposed to initiate
+				 * the PLOGI anyway, just ACC it now and
+				 * move on with discovery.
+				 */
+				phba->fc_edtov = FF_DEF_EDTOV;
+				phba->fc_ratov = FF_DEF_RATOV;
+				/* Start discovery - this should just do
+				   CLEAR_LA */
+				lpfc_disc_start(phba);
+			}
+			else {
+				lpfc_initial_flogi(phba);
+			}
+		}
+		else {
+			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
+			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+			lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb,
+					    ndlp);
+			return 0;
+		}
+	}
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+	if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3) == 0)) {
+		/* Reject this request because invalid parameters */
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
+		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+		return (0);
+	}
+	icmd = &cmdiocb->iocb;
+
+	/* PLOGI chkparm OK */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_ELS,
+			"%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
+			ndlp->nlp_rpi);
+
+	if ((phba->cfg_fcp_class == 2) &&
+	    (sp->cls2.classValid)) {
+		ndlp->nlp_fcp_info |= CLASS2;
+	} else {
+		ndlp->nlp_fcp_info |= CLASS3;
+	}
+	ndlp->nlp_class_sup = 0;
+	if (sp->cls1.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS1;
+	if (sp->cls2.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS2;
+	if (sp->cls3.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS3;
+	if (sp->cls4.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS4;
+	ndlp->nlp_maxframe =
+		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
+
+	/* no need to reg_login if we are already in one of these states */
+	switch(ndlp->nlp_state) {
+	case  NLP_STE_NPR_NODE:
+		if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
+			break;
+	case  NLP_STE_REG_LOGIN_ISSUE:
+	case  NLP_STE_PRLI_ISSUE:
+	case  NLP_STE_UNMAPPED_NODE:
+	case  NLP_STE_MAPPED_NODE:
+		lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
+		return (1);
+	}
+
+	if ((phba->fc_flag & FC_PT2PT)
+	    && !(phba->fc_flag & FC_PT2PT_PLOGI)) {
+		/* rcv'ed PLOGI decides what our NPortId will be */
+		phba->fc_myDID = icmd->un.rcvels.parmRo;
+		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (mbox == NULL)
+			goto out;
+		lpfc_config_link(phba, mbox);
+		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		rc = lpfc_sli_issue_mbox
+			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+		if (rc == MBX_NOT_FINISHED) {
+			mempool_free( mbox, phba->mbox_mem_pool);
+			goto out;
+		}
+
+		lpfc_can_disctmo(phba);
+	}
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (mbox == NULL)
+		goto out;
+
+	if (lpfc_reg_login(phba, icmd->un.rcvels.remoteID,
+			   (uint8_t *) sp, mbox, 0)) {
+		mempool_free( mbox, phba->mbox_mem_pool);
+		goto out;
+	}
+
+	/* ACC PLOGI rsp command needs to execute first,
+	 * queue this mbox command to be processed later.
+	 */
+	mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+	mbox->context2  = ndlp;
+	ndlp->nlp_flag |= NLP_ACC_REGLOGIN;
+
+	/* If there is an outstanding PLOGI issued, abort it before
+	 * sending ACC rsp to PLOGI recieved.
+	 */
+	if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+		/* software abort outstanding PLOGI */
+		lpfc_els_abort(phba, ndlp, 1);
+	}
+	ndlp->nlp_flag |= NLP_RCV_PLOGI;
+	lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
+	return (1);
+
+out:
+	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+	stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
+	lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+	return (0);
+}
+
+static int
+lpfc_rcv_padisc(struct lpfc_hba * phba,
+		struct lpfc_nodelist * ndlp,
+		struct lpfc_iocbq *cmdiocb)
+{
+	struct lpfc_dmabuf *pcmd;
+	struct serv_parm *sp;
+	struct lpfc_name *pnn, *ppn;
+	struct ls_rjt stat;
+	ADISC *ap;
+	IOCB_t *icmd;
+	uint32_t *lp;
+	uint32_t cmd;
+
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+
+	cmd = *lp++;
+	if (cmd == ELS_CMD_ADISC) {
+		ap = (ADISC *) lp;
+		pnn = (struct lpfc_name *) & ap->nodeName;
+		ppn = (struct lpfc_name *) & ap->portName;
+	} else {
+		sp = (struct serv_parm *) lp;
+		pnn = (struct lpfc_name *) & sp->nodeName;
+		ppn = (struct lpfc_name *) & sp->portName;
+	}
+
+	icmd = &cmdiocb->iocb;
+	if ((icmd->ulpStatus == 0) &&
+	    (lpfc_check_adisc(phba, ndlp, pnn, ppn))) {
+		if (cmd == ELS_CMD_ADISC) {
+			lpfc_els_rsp_adisc_acc(phba, cmdiocb, ndlp);
+		}
+		else {
+			lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp,
+				NULL, 0);
+		}
+		return (1);
+	}
+	/* Reject this request because invalid parameters */
+	stat.un.b.lsRjtRsvd0 = 0;
+	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+	stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
+	stat.un.b.vendorUnique = 0;
+	lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+
+	ndlp->nlp_last_elscmd = (unsigned long)ELS_CMD_PLOGI;
+	/* 1 sec timeout */
+	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_DELAY_TMO;
+	spin_unlock_irq(phba->host->host_lock);
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	return (0);
+}
+
+static int
+lpfc_rcv_logo(struct lpfc_hba * phba,
+		      struct lpfc_nodelist * ndlp,
+		      struct lpfc_iocbq *cmdiocb)
+{
+	/* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */
+	/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
+	 * PLOGIs during LOGO storms from a device.
+	 */
+	ndlp->nlp_flag |= NLP_LOGO_ACC;
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+
+	if (!(ndlp->nlp_type & NLP_FABRIC)) {
+		/* Only try to re-login if this is NOT a Fabric Node */
+		ndlp->nlp_last_elscmd = (unsigned long)ELS_CMD_PLOGI;
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+	}
+
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+
+	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+	/* The driver has to wait until the ACC completes before it continues
+	 * processing the LOGO.  The action will resume in
+	 * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an
+	 * unreg_login, the driver waits so the ACC does not get aborted.
+	 */
+	return (0);
+}
+
+static void
+lpfc_rcv_prli(struct lpfc_hba * phba,
+		      struct lpfc_nodelist * ndlp,
+		      struct lpfc_iocbq *cmdiocb)
+{
+	struct lpfc_dmabuf *pcmd;
+	uint32_t *lp;
+	PRLI *npr;
+	struct fc_rport *rport = ndlp->rport;
+	u32 roles;
+
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+	npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t));
+
+	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
+	    (npr->prliType == PRLI_FCP_TYPE)) {
+		if (npr->initiatorFunc)
+			ndlp->nlp_type |= NLP_FCP_INITIATOR;
+		if (npr->targetFunc)
+			ndlp->nlp_type |= NLP_FCP_TARGET;
+		if (npr->Retry)
+			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
+	}
+	if (rport) {
+		/* We need to update the rport role values */
+		roles = FC_RPORT_ROLE_UNKNOWN;
+		if (ndlp->nlp_type & NLP_FCP_INITIATOR)
+			roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+		if (ndlp->nlp_type & NLP_FCP_TARGET)
+			roles |= FC_RPORT_ROLE_FCP_TARGET;
+		fc_remote_port_rolechg(rport, roles);
+	}
+}
+
+static uint32_t
+lpfc_disc_set_adisc(struct lpfc_hba * phba,
+		      struct lpfc_nodelist * ndlp)
+{
+	/* Check config parameter use-adisc or FCP-2 */
+	if ((phba->cfg_use_adisc == 0) &&
+		!(phba->fc_flag & FC_RSCN_MODE)) {
+		if (!(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE))
+			return (0);
+	}
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_NPR_ADISC;
+	spin_unlock_irq(phba->host->host_lock);
+	return (1);
+}
+
+static uint32_t
+lpfc_disc_noop(struct lpfc_hba * phba,
+		struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	/* This routine does nothing, just return the current state */
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_disc_illegal(struct lpfc_hba * phba,
+		   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	lpfc_printf_log(phba,
+			KERN_ERR,
+			LOG_DISCOVERY,
+			"%d:0253 Illegal State Transition: node x%x event x%x, "
+			"state x%x Data: x%x x%x\n",
+			phba->brd_no,
+			ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+			ndlp->nlp_flag);
+	return (ndlp->nlp_state);
+}
+
+/* Start of Discovery State Machine routines */
+
+static uint32_t
+lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+		ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+		return (ndlp->nlp_state);
+	}
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	lpfc_issue_els_logo(phba, ndlp, 0);
+	lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_LOGO_ACC;
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_rm_unused_node(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_rcv_plogi_plogi_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+			   void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb = arg;
+	struct lpfc_dmabuf *pcmd;
+	struct serv_parm *sp;
+	uint32_t *lp;
+	struct ls_rjt stat;
+	int port_cmp;
+
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+	lp = (uint32_t *) pcmd->virt;
+	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+
+	memset(&stat, 0, sizeof (struct ls_rjt));
+
+	/* For a PLOGI, we only accept if our portname is less
+	 * than the remote portname.
+	 */
+	phba->fc_stat.elsLogiCol++;
+	port_cmp = memcmp(&phba->fc_portname, &sp->portName,
+			  sizeof (struct lpfc_name));
+
+	if (port_cmp >= 0) {
+		/* Reject this request because the remote node will accept
+		   ours */
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
+		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+	}
+	else {
+		lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+	} /* if our portname was less */
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* software abort outstanding PLOGI */
+	lpfc_els_abort(phba, ndlp, 1);
+	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag |= NLP_DELAY_TMO;
+	spin_unlock_irq(phba->host->host_lock);
+
+	if (evt == NLP_EVT_RCV_LOGO) {
+		lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	}
+	else {
+		lpfc_issue_els_logo(phba, ndlp, 0);
+	}
+
+	/* Put ndlp in npr list set plogi timer for 1 sec */
+	ndlp->nlp_last_elscmd = (unsigned long)ELS_CMD_PLOGI;
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb, *rspiocb;
+	struct lpfc_dmabuf *pcmd, *prsp;
+	uint32_t *lp;
+	IOCB_t *irsp;
+	struct serv_parm *sp;
+	LPFC_MBOXQ_t *mbox;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+	rspiocb = cmdiocb->context_un.rsp_iocb;
+
+	if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+		return (ndlp->nlp_state);
+	}
+
+	irsp = &rspiocb->iocb;
+
+	if (irsp->ulpStatus)
+		goto out;
+
+	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+	prsp = list_get_first(&pcmd->list,
+			      struct lpfc_dmabuf,
+			      list);
+	lp = (uint32_t *) prsp->virt;
+
+	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+	if (!lpfc_check_sparm(phba, ndlp, sp, CLASS3))
+		goto out;
+
+	/* PLOGI chkparm OK */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_ELS,
+			"%d:0121 PLOGI chkparm OK "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			ndlp->nlp_DID, ndlp->nlp_state,
+			ndlp->nlp_flag, ndlp->nlp_rpi);
+
+	if ((phba->cfg_fcp_class == 2) &&
+	    (sp->cls2.classValid)) {
+		ndlp->nlp_fcp_info |= CLASS2;
+	} else {
+		ndlp->nlp_fcp_info |= CLASS3;
+	}
+	ndlp->nlp_class_sup = 0;
+	if (sp->cls1.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS1;
+	if (sp->cls2.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS2;
+	if (sp->cls3.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS3;
+	if (sp->cls4.classValid)
+		ndlp->nlp_class_sup |= FC_COS_CLASS4;
+	ndlp->nlp_maxframe =
+		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
+		sp->cmn.bbRcvSizeLsb;
+
+	if (!(mbox = mempool_alloc(phba->mbox_mem_pool,
+				   GFP_KERNEL)))
+		goto out;
+
+	lpfc_unreg_rpi(phba, ndlp);
+	if (lpfc_reg_login
+	    (phba, irsp->un.elsreq64.remoteID,
+	     (uint8_t *) sp, mbox, 0) == 0) {
+		/* set_slim mailbox command needs to
+		 * execute first, queue this command to
+		 * be processed later.
+		 */
+		switch(ndlp->nlp_DID) {
+		case NameServer_DID:
+			mbox->mbox_cmpl =
+				lpfc_mbx_cmpl_ns_reg_login;
+			break;
+		case FDMI_DID:
+			mbox->mbox_cmpl =
+				lpfc_mbx_cmpl_fdmi_reg_login;
+			break;
+		default:
+			mbox->mbox_cmpl =
+				lpfc_mbx_cmpl_reg_login;
+		}
+		mbox->context2 = ndlp;
+		if (lpfc_sli_issue_mbox(phba, mbox,
+					(MBX_NOWAIT | MBX_STOP_IOCB))
+		    != MBX_NOT_FINISHED) {
+			ndlp->nlp_state =
+				NLP_STE_REG_LOGIN_ISSUE;
+			lpfc_nlp_list(phba, ndlp,
+				      NLP_REGLOGIN_LIST);
+			return (ndlp->nlp_state);
+		}
+		mempool_free(mbox, phba->mbox_mem_pool);
+	} else {
+		mempool_free(mbox, phba->mbox_mem_pool);
+	}
+
+
+ out:
+	/* Free this node since the driver cannot login or has the wrong
+	   sparm */
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	/* software abort outstanding PLOGI */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	/* software abort outstanding PLOGI */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	/* software abort outstanding ADISC */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+		return (ndlp->nlp_state);
+	}
+	ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+	lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+	lpfc_issue_els_plogi(phba, ndlp, 0);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* software abort outstanding ADISC */
+	lpfc_els_abort(phba, ndlp, 0);
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* Treat like rcv logo */
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb, *rspiocb;
+	IOCB_t *irsp;
+	ADISC *ap;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+	rspiocb = cmdiocb->context_un.rsp_iocb;
+
+	ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
+	irsp = &rspiocb->iocb;
+
+	if ((irsp->ulpStatus) ||
+		(!lpfc_check_adisc(phba, ndlp, &ap->nodeName, &ap->portName))) {
+		ndlp->nlp_last_elscmd = (unsigned long)ELS_CMD_PLOGI;
+		/* 1 sec timeout */
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+
+		memset(&ndlp->nlp_nodename, 0, sizeof (struct lpfc_name));
+		memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
+
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_unreg_rpi(phba, ndlp);
+		return (ndlp->nlp_state);
+	}
+	ndlp->nlp_state = NLP_STE_MAPPED_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	/* software abort outstanding ADISC */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	/* software abort outstanding ADISC */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+
+	lpfc_disc_set_adisc(phba, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_reglogin_issue(struct lpfc_hba * phba,
+			      struct lpfc_nodelist * ndlp, void *arg,
+			      uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_reglogin_issue(struct lpfc_hba * phba,
+			     struct lpfc_nodelist * ndlp, void *arg,
+			     uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
+			     struct lpfc_nodelist * ndlp, void *arg,
+			     uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_reglogin_issue(struct lpfc_hba * phba,
+			       struct lpfc_nodelist * ndlp, void *arg,
+			       uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba,
+			     struct lpfc_nodelist * ndlp, void *arg,
+			     uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
+				  struct lpfc_nodelist * ndlp,
+				  void *arg, uint32_t evt)
+{
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+	uint32_t did;
+
+	pmb = (LPFC_MBOXQ_t *) arg;
+	mb = &pmb->mb;
+	did = mb->un.varWords[1];
+	if (mb->mbxStatus) {
+		/* RegLogin failed */
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_DISCOVERY,
+				"%d:0246 RegLogin failed Data: x%x x%x x%x\n",
+				phba->brd_no,
+				did, mb->mbxStatus, phba->hba_state);
+
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(phba->host->host_lock);
+
+		lpfc_issue_els_logo(phba, ndlp, 0);
+		/* Put ndlp in npr list set plogi timer for 1 sec */
+		ndlp->nlp_last_elscmd = (unsigned long)ELS_CMD_PLOGI;
+		ndlp->nlp_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		return (ndlp->nlp_state);
+	}
+
+	if (ndlp->nlp_rpi != 0)
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+
+	ndlp->nlp_rpi = mb->un.varWords[0];
+	lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi);
+
+	/* Only if we are not a fabric nport do we issue PRLI */
+	if (!(ndlp->nlp_type & NLP_FABRIC)) {
+		ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
+		lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+		lpfc_issue_els_prli(phba, ndlp, 0);
+	} else {
+		ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+	}
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
+			      struct lpfc_nodelist * ndlp, void *arg,
+			      uint32_t evt)
+{
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
+			       struct lpfc_nodelist * ndlp, void *arg,
+			       uint32_t evt)
+{
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_prli_issue(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_prli_issue(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* Software abort outstanding PRLI before sending acc */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_prli_issue(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+/* This routine is envoked when we rcv a PRLO request from a nport
+ * we are logged into.  We should send back a PRLO rsp setting the
+ * appropriate bits.
+ * NEXT STATE = PRLI_ISSUE
+ */
+static uint32_t
+lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb, *rspiocb;
+	IOCB_t *irsp;
+	PRLI *npr;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+	rspiocb = cmdiocb->context_un.rsp_iocb;
+	npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
+
+	irsp = &rspiocb->iocb;
+	if (irsp->ulpStatus) {
+		ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+		lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+		return (ndlp->nlp_state);
+	}
+
+	/* Check out PRLI rsp */
+	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
+	    (npr->prliType == PRLI_FCP_TYPE)) {
+		if (npr->initiatorFunc)
+			ndlp->nlp_type |= NLP_FCP_INITIATOR;
+		if (npr->targetFunc)
+			ndlp->nlp_type |= NLP_FCP_TARGET;
+		if (npr->Retry)
+			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
+	}
+
+	ndlp->nlp_state = NLP_STE_MAPPED_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+	return (ndlp->nlp_state);
+}
+
+/*! lpfc_device_rm_prli_issue
+  *
+  * \pre
+  * \post
+  * \param   phba
+  * \param   ndlp
+  * \param   arg
+  * \param   evt
+  * \return  uint32_t
+  *
+  * \b Description:
+  *    This routine is envoked when we a request to remove a nport we are in the
+  *    process of PRLIing. We should software abort outstanding prli, unreg
+  *    login, send a logout. We will change node state to UNUSED_NODE, put it
+  *    on plogi list so it can be freed when LOGO completes.
+  *
+  */
+static uint32_t
+lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	/* software abort outstanding PRLI */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+
+/*! lpfc_device_recov_prli_issue
+  *
+  * \pre
+  * \post
+  * \param   phba
+  * \param   ndlp
+  * \param   arg
+  * \param   evt
+  * \return  uint32_t
+  *
+  * \b Description:
+  *    The routine is envoked when the state of a device is unknown, like
+  *    during a link down. We should remove the nodelist entry from the
+  *    unmapped list, issue a UNREG_LOGIN, do a software abort of the
+  *    outstanding PRLI command, then free the node entry.
+  */
+static uint32_t
+lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	/* software abort outstanding PRLI */
+	lpfc_els_abort(phba, ndlp, 1);
+
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_unmap_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_unmap_node(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_prli(phba, ndlp, cmdiocb);
+	lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_unmap_node(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba,
+			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* Treat like rcv logo */
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	lpfc_disc_set_adisc(phba, ndlp);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_mapped_node(struct lpfc_hba * phba,
+			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_mapped_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_mapped_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba,
+			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* flush the target */
+	spin_lock_irq(phba->host->host_lock);
+	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+			       ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+	spin_unlock_irq(phba->host->host_lock);
+
+	/* Treat like rcv logo */
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	ndlp->nlp_state = NLP_STE_NPR_NODE;
+	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_disc_set_adisc(phba, ndlp);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	/* Ignore PLOGI if we have an outstanding LOGO */
+	if (ndlp->nlp_flag & NLP_LOGO_SND) {
+		return (ndlp->nlp_state);
+	}
+
+	if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC);
+		spin_unlock_irq(phba->host->host_lock);
+		return (ndlp->nlp_state);
+	}
+
+	/* send PLOGI immediately, move to PLOGI issue state */
+	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_issue_els_plogi(phba, ndlp, 0);
+	}
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+	struct ls_rjt          stat;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	memset(&stat, 0, sizeof (struct ls_rjt));
+	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+	lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+
+	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_issue_els_adisc(phba, ndlp, 0);
+		} else {
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_issue_els_plogi(phba, ndlp, 0);
+		}
+	}
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_logo_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_logo(phba, ndlp, cmdiocb);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+
+	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_issue_els_adisc(phba, ndlp, 0);
+		} else {
+			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_issue_els_plogi(phba, ndlp, 0);
+		}
+	}
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_rcv_prlo_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	struct lpfc_iocbq     *cmdiocb;
+
+	cmdiocb = (struct lpfc_iocbq *) arg;
+
+	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+
+	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+		if (ndlp->nlp_last_elscmd == (unsigned long)ELS_CMD_PLOGI) {
+			return (ndlp->nlp_state);
+		} else {
+			spin_lock_irq(phba->host->host_lock);
+			ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+			spin_unlock_irq(phba->host->host_lock);
+			del_timer_sync(&ndlp->nlp_delayfunc);
+			if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+				list_del_init(&ndlp->els_retry_evt.evt_listp);
+		}
+	}
+
+	ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+	lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+	lpfc_issue_els_plogi(phba, ndlp, 0);
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_logo_npr_node(struct lpfc_hba * phba,
+		struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	lpfc_unreg_rpi(phba, ndlp);
+	/* This routine does nothing, just return the current state */
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+
+	pmb = (LPFC_MBOXQ_t *) arg;
+	mb = &pmb->mb;
+
+	/* save rpi */
+	if (ndlp->nlp_rpi != 0)
+		lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi);
+
+	ndlp->nlp_rpi = mb->un.varWords[0];
+	lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi);
+
+	return (ndlp->nlp_state);
+}
+
+static uint32_t
+lpfc_device_rm_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	return (NLP_STE_FREED_NODE);
+}
+
+static uint32_t
+lpfc_device_recov_npr_node(struct lpfc_hba * phba,
+			    struct lpfc_nodelist * ndlp, void *arg,
+			    uint32_t evt)
+{
+	spin_lock_irq(phba->host->host_lock);
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
+	return (ndlp->nlp_state);
+}
+
+
+/* This next section defines the NPort Discovery State Machine */
+
+/* There are 4 different double linked lists nodelist entries can reside on.
+ * The plogi list and adisc list are used when Link Up discovery or RSCN
+ * processing is needed. Each list holds the nodes that we will send PLOGI
+ * or ADISC on. These lists will keep track of what nodes will be effected
+ * by an RSCN, or a Link Up (Typically, all nodes are effected on Link Up).
+ * The unmapped_list will contain all nodes that we have successfully logged
+ * into at the Fibre Channel level. The mapped_list will contain all nodes
+ * that are mapped FCP targets.
+ */
+/*
+ * The bind list is a list of undiscovered (potentially non-existent) nodes
+ * that we have saved binding information on. This information is used when
+ * nodes transition from the unmapped to the mapped list.
+ */
+/* For UNUSED_NODE state, the node has just been allocated .
+ * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on
+ * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list
+ * and put on the unmapped list. For ADISC processing, the node is taken off
+ * the ADISC list and placed on either the mapped or unmapped list (depending
+ * on its previous state). Once on the unmapped list, a PRLI is issued and the
+ * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is
+ * changed to UNMAPPED_NODE. If the completion indicates a mapped
+ * node, the node is taken off the unmapped list. The binding list is checked
+ * for a valid binding, or a binding is automatically assigned. If binding
+ * assignment is unsuccessful, the node is left on the unmapped list. If
+ * binding assignment is successful, the associated binding list entry (if
+ * any) is removed, and the node is placed on the mapped list.
+ */
+/*
+ * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * expire, all effected nodes will receive a DEVICE_RM event.
+ */
+/*
+ * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists
+ * to either the ADISC or PLOGI list.  After a Nameserver query or ALPA loopmap
+ * check, additional nodes may be added or removed (via DEVICE_RM) to / from
+ * the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated,
+ * we will first process the ADISC list.  32 entries are processed initially and
+ * ADISC is initited for each one.  Completions / Events for each node are
+ * funnelled thru the state machine.  As each node finishes ADISC processing, it
+ * starts ADISC for any nodes waiting for ADISC processing. If no nodes are
+ * waiting, and the ADISC list count is identically 0, then we are done. For
+ * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we
+ * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI
+ * list.  32 entries are processed initially and PLOGI is initited for each one.
+ * Completions / Events for each node are funnelled thru the state machine.  As
+ * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting
+ * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is
+ * indentically 0, then we are done. We have now completed discovery / RSCN
+ * handling. Upon completion, ALL nodes should be on either the mapped or
+ * unmapped lists.
+ */
+
+static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
+     (struct lpfc_hba *, struct lpfc_nodelist *, void *, uint32_t) = {
+	/* Action routine                  Event       Current State  */
+	lpfc_rcv_plogi_unused_node,	/* RCV_PLOGI   UNUSED_NODE    */
+	lpfc_rcv_els_unused_node,	/* RCV_PRLI        */
+	lpfc_rcv_logo_unused_node,	/* RCV_LOGO        */
+	lpfc_rcv_els_unused_node,	/* RCV_ADISC       */
+	lpfc_rcv_els_unused_node,	/* RCV_PDISC       */
+	lpfc_rcv_els_unused_node,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_cmpl_logo_unused_node,	/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_device_rm_unused_node,	/* DEVICE_RM       */
+	lpfc_disc_illegal,		/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_plogi_issue,	/* RCV_PLOGI   PLOGI_ISSUE    */
+	lpfc_rcv_els_plogi_issue,	/* RCV_PRLI        */
+	lpfc_rcv_els_plogi_issue,	/* RCV_LOGO        */
+	lpfc_rcv_els_plogi_issue,	/* RCV_ADISC       */
+	lpfc_rcv_els_plogi_issue,	/* RCV_PDISC       */
+	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
+	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
+	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_adisc_issue,	/* RCV_PLOGI   ADISC_ISSUE    */
+	lpfc_rcv_prli_adisc_issue,	/* RCV_PRLI        */
+	lpfc_rcv_logo_adisc_issue,	/* RCV_LOGO        */
+	lpfc_rcv_padisc_adisc_issue,	/* RCV_ADISC       */
+	lpfc_rcv_padisc_adisc_issue,	/* RCV_PDISC       */
+	lpfc_rcv_prlo_adisc_issue,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_cmpl_adisc_adisc_issue,	/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_device_rm_adisc_issue,	/* DEVICE_RM       */
+	lpfc_device_recov_adisc_issue,	/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_reglogin_issue,	/* RCV_PLOGI  REG_LOGIN_ISSUE */
+	lpfc_rcv_prli_reglogin_issue,	/* RCV_PLOGI       */
+	lpfc_rcv_logo_reglogin_issue,	/* RCV_LOGO        */
+	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
+	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
+	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_cmpl_reglogin_reglogin_issue,/* CMPL_REG_LOGIN  */
+	lpfc_device_rm_reglogin_issue,	/* DEVICE_RM       */
+	lpfc_device_recov_reglogin_issue,/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_prli_issue,	/* RCV_PLOGI   PRLI_ISSUE     */
+	lpfc_rcv_prli_prli_issue,	/* RCV_PRLI        */
+	lpfc_rcv_logo_prli_issue,	/* RCV_LOGO        */
+	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
+	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
+	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_device_rm_prli_issue,	/* DEVICE_RM       */
+	lpfc_device_recov_prli_issue,	/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_unmap_node,	/* RCV_PLOGI   UNMAPPED_NODE  */
+	lpfc_rcv_prli_unmap_node,	/* RCV_PRLI        */
+	lpfc_rcv_logo_unmap_node,	/* RCV_LOGO        */
+	lpfc_rcv_padisc_unmap_node,	/* RCV_ADISC       */
+	lpfc_rcv_padisc_unmap_node,	/* RCV_PDISC       */
+	lpfc_rcv_prlo_unmap_node,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_disc_illegal,		/* DEVICE_RM       */
+	lpfc_device_recov_unmap_node,	/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_mapped_node,	/* RCV_PLOGI   MAPPED_NODE    */
+	lpfc_rcv_prli_mapped_node,	/* RCV_PRLI        */
+	lpfc_rcv_logo_mapped_node,	/* RCV_LOGO        */
+	lpfc_rcv_padisc_mapped_node,	/* RCV_ADISC       */
+	lpfc_rcv_padisc_mapped_node,	/* RCV_PDISC       */
+	lpfc_rcv_prlo_mapped_node,	/* RCV_PRLO        */
+	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_disc_illegal,		/* CMPL_PRLI       */
+	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_disc_illegal,		/* CMPL_ADISC      */
+	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_disc_illegal,		/* DEVICE_RM       */
+	lpfc_device_recov_mapped_node,	/* DEVICE_RECOVERY */
+
+	lpfc_rcv_plogi_npr_node,        /* RCV_PLOGI   NPR_NODE    */
+	lpfc_rcv_prli_npr_node,         /* RCV_PRLI        */
+	lpfc_rcv_logo_npr_node,         /* RCV_LOGO        */
+	lpfc_rcv_padisc_npr_node,       /* RCV_ADISC       */
+	lpfc_rcv_padisc_npr_node,       /* RCV_PDISC       */
+	lpfc_rcv_prlo_npr_node,         /* RCV_PRLO        */
+	lpfc_disc_noop,			/* CMPL_PLOGI      */
+	lpfc_disc_noop,			/* CMPL_PRLI       */
+	lpfc_cmpl_logo_npr_node,        /* CMPL_LOGO       */
+	lpfc_disc_noop,			/* CMPL_ADISC      */
+	lpfc_cmpl_reglogin_npr_node,    /* CMPL_REG_LOGIN  */
+	lpfc_device_rm_npr_node,        /* DEVICE_RM       */
+	lpfc_device_recov_npr_node,     /* DEVICE_RECOVERY */
+};
+
+int
+lpfc_disc_state_machine(struct lpfc_hba * phba,
+			struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+{
+	uint32_t cur_state, rc;
+	uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
+			 uint32_t);
+
+	ndlp->nlp_disc_refcnt++;
+	cur_state = ndlp->nlp_state;
+
+	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
+	lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_DISCOVERY,
+			"%d:0211 DSM in event x%x on NPort x%x in state %d "
+			"Data: x%x\n",
+			phba->brd_no,
+			evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
+
+	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
+	rc = (func) (phba, ndlp, arg, evt);
+
+	/* DSM out state <rc> on NPort <nlp_DID> */
+	lpfc_printf_log(phba,
+		       KERN_INFO,
+		       LOG_DISCOVERY,
+		       "%d:0212 DSM out state %d on NPort x%x Data: x%x\n",
+		       phba->brd_no,
+		       rc, ndlp->nlp_DID, ndlp->nlp_flag);
+
+	ndlp->nlp_disc_refcnt--;
+
+	/* Check to see if ndlp removal is deferred */
+	if ((ndlp->nlp_disc_refcnt == 0)
+	    && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag &= ~NLP_DELAY_REMOVE;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_nlp_remove(phba, ndlp);
+		return (NLP_STE_FREED_NODE);
+	}
+	if (rc == NLP_STE_FREED_NODE)
+		return (NLP_STE_FREED_NODE);
+	ndlp->nlp_state = rc;
+	return (rc);
+}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -0,0 +1,1246 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_scsi.c 1.37 2005/04/13 14:27:09EDT sf_support Exp  $
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_version.h"
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+
+#define LPFC_RESET_WAIT  2
+#define LPFC_ABORT_WAIT  2
+
+static inline void lpfc_put_lun(struct fcp_cmnd *fcmd, unsigned int lun)
+{
+	fcmd->fcpLunLsl = 0;
+	fcmd->fcpLunMsl = swab16((uint16_t)lun);
+}
+
+/*
+ * This routine allocates a scsi buffer, which contains all the necessary
+ * information needed to initiate a SCSI I/O.  The non-DMAable buffer region
+ * contains information to build the IOCB.  The DMAable region contains
+ * memory for the FCP CMND, FCP RSP, and the inital BPL.  In addition to
+ * allocating memeory, the FCP CMND and FCP RSP BDEs are setup in the BPL
+ * and the BPL BDE is setup in the IOCB.
+ */
+static struct lpfc_scsi_buf *
+lpfc_get_scsi_buf(struct lpfc_hba * phba)
+{
+	struct lpfc_scsi_buf *psb;
+	struct ulp_bde64 *bpl;
+	IOCB_t *iocb;
+	dma_addr_t pdma_phys;
+
+	psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+	if (!psb)
+		return NULL;
+	memset(psb, 0, sizeof (struct lpfc_scsi_buf));
+	psb->scsi_hba = phba;
+
+	/*
+	 * Get memory from the pci pool to map the virt space to pci bus space
+	 * for an I/O.  The DMA buffer includes space for the struct fcp_cmnd,
+	 * struct fcp_rsp and the number of bde's necessary to support the
+	 * sg_tablesize.
+	 */
+	psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL,
+							&psb->dma_handle);
+	if (!psb->data) {
+		kfree(psb);
+		return NULL;
+	}
+
+	/* Initialize virtual ptrs to dma_buf region. */
+	memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
+
+	psb->fcp_cmnd = psb->data;
+	psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
+	psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
+							sizeof(struct fcp_rsp);
+
+	/* Initialize local short-hand pointers. */
+	bpl = psb->fcp_bpl;
+	pdma_phys = psb->dma_handle;
+
+	/*
+	 * The first two bdes are the FCP_CMD and FCP_RSP.  The balance are sg
+	 * list bdes.  Initialize the first two and leave the rest for
+	 * queuecommand.
+	 */
+	bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys));
+	bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys));
+	bpl->tus.f.bdeSize = sizeof (struct fcp_cmnd);
+	bpl->tus.f.bdeFlags = BUFF_USE_CMND;
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+	bpl++;
+
+	/* Setup the physical region for the FCP RSP */
+	pdma_phys += sizeof (struct fcp_cmnd);
+	bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys));
+	bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys));
+	bpl->tus.f.bdeSize = sizeof (struct fcp_rsp);
+	bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV);
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
+	/*
+	 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
+	 * initialize it with all known data now.
+	 */
+	pdma_phys += (sizeof (struct fcp_rsp));
+	iocb = &psb->cur_iocbq.iocb;
+	iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
+	iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys);
+	iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys);
+	iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
+	iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL;
+	iocb->ulpBdeCount = 1;
+	iocb->ulpClass = CLASS3;
+
+	return psb;
+}
+
+static void
+lpfc_free_scsi_buf(struct lpfc_scsi_buf * psb)
+{
+	struct lpfc_hba *phba = psb->scsi_hba;
+
+	/*
+	 * There are only two special cases to consider.  (1) the scsi command
+	 * requested scatter-gather usage or (2) the scsi command allocated
+	 * a request buffer, but did not request use_sg.  There is a third
+	 * case, but it does not require resource deallocation.
+	 */
+	if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
+		dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
+				psb->seg_cnt, psb->pCmd->sc_data_direction);
+	} else {
+		 if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
+			dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
+						psb->pCmd->request_bufflen,
+						psb->pCmd->sc_data_direction);
+		 }
+	}
+
+	list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
+}
+
+static int
+lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
+{
+	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
+	struct scatterlist *sgel = NULL;
+	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
+	struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl;
+	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
+	dma_addr_t physaddr;
+	uint32_t i, num_bde = 0;
+	int datadir = scsi_cmnd->sc_data_direction;
+	int dma_error;
+
+	/*
+	 * There are three possibilities here - use scatter-gather segment, use
+	 * the single mapping, or neither.  Start the lpfc command prep by
+	 * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first
+	 * data bde entry.
+	 */
+	bpl += 2;
+	if (scsi_cmnd->use_sg) {
+		/*
+		 * The driver stores the segment count returned from pci_map_sg
+		 * because this a count of dma-mappings used to map the use_sg
+		 * pages.  They are not guaranteed to be the same for those
+		 * architectures that implement an IOMMU.
+		 */
+		sgel = (struct scatterlist *)scsi_cmnd->request_buffer;
+		lpfc_cmd->seg_cnt = dma_map_sg(&phba->pcidev->dev, sgel,
+						scsi_cmnd->use_sg, datadir);
+		if (lpfc_cmd->seg_cnt == 0)
+			return 1;
+
+		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
+			printk(KERN_ERR "%s: Too many sg segments from "
+			       "dma_map_sg.  Config %d, seg_cnt %d",
+			       __FUNCTION__, phba->cfg_sg_seg_cnt,
+			       lpfc_cmd->seg_cnt);
+			dma_unmap_sg(&phba->pcidev->dev, sgel,
+				     lpfc_cmd->seg_cnt, datadir);
+			return 1;
+		}
+
+		/*
+		 * The driver established a maximum scatter-gather segment count
+		 * during probe that limits the number of sg elements in any
+		 * single scsi command.  Just run through the seg_cnt and format
+		 * the bde's.
+		 */
+		for (i = 0; i < lpfc_cmd->seg_cnt; i++) {
+			physaddr = sg_dma_address(sgel);
+			bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
+			bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
+			bpl->tus.f.bdeSize = sg_dma_len(sgel);
+			if (datadir == DMA_TO_DEVICE)
+				bpl->tus.f.bdeFlags = 0;
+			else
+				bpl->tus.f.bdeFlags = BUFF_USE_RCV;
+			bpl->tus.w = le32_to_cpu(bpl->tus.w);
+			bpl++;
+			sgel++;
+			num_bde++;
+		}
+	} else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
+		physaddr = dma_map_single(&phba->pcidev->dev,
+					  scsi_cmnd->request_buffer,
+					  scsi_cmnd->request_bufflen,
+					  datadir);
+		dma_error = dma_mapping_error(physaddr);
+		if (dma_error) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+				"%d:0718 Unable to dma_map_single "
+				"request_buffer: x%x\n",
+				phba->brd_no, dma_error);
+			return 1;
+		}
+
+		lpfc_cmd->nonsg_phys = physaddr;
+		bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
+		bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
+		bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen;
+		if (datadir == DMA_TO_DEVICE)
+			bpl->tus.f.bdeFlags = 0;
+		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+		num_bde = 1;
+		bpl++;
+	}
+
+	/*
+	 * Finish initializing those IOCB fields that are dependent on the
+	 * scsi_cmnd request_buffer
+	 */
+	iocb_cmd->un.fcpi64.bdl.bdeSize +=
+		(num_bde * sizeof (struct ulp_bde64));
+	iocb_cmd->ulpBdeCount = 1;
+	iocb_cmd->ulpLe = 1;
+	fcp_cmnd->fcpDl = be32_to_cpu(scsi_cmnd->request_bufflen);
+	return 0;
+}
+
+static void
+lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
+{
+	struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
+	struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
+	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
+	struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
+	uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
+	uint32_t resp_info = fcprsp->rspStatus2;
+	uint32_t scsi_status = fcprsp->rspStatus3;
+	uint32_t host_status = DID_OK;
+	uint32_t rsplen = 0;
+
+	/*
+	 *  If this is a task management command, there is no
+	 *  scsi packet associated with this lpfc_cmd.  The driver
+	 *  consumes it.
+	 */
+	if (fcpcmd->fcpCntl2) {
+		scsi_status = 0;
+		goto out;
+	}
+
+	lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+			"%d:0730 FCP command failed: RSP "
+			"Data: x%x x%x x%x x%x x%x x%x\n",
+			phba->brd_no, resp_info, scsi_status,
+			be32_to_cpu(fcprsp->rspResId),
+			be32_to_cpu(fcprsp->rspSnsLen),
+			be32_to_cpu(fcprsp->rspRspLen),
+			fcprsp->rspInfo3);
+
+	if (resp_info & RSP_LEN_VALID) {
+		rsplen = be32_to_cpu(fcprsp->rspRspLen);
+		if ((rsplen != 0 && rsplen != 4 && rsplen != 8) ||
+		    (fcprsp->rspInfo3 != RSP_NO_FAILURE)) {
+			host_status = DID_ERROR;
+			goto out;
+		}
+	}
+
+	if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
+		uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
+		if (snslen > SCSI_SENSE_BUFFERSIZE)
+			snslen = SCSI_SENSE_BUFFERSIZE;
+
+		memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen);
+	}
+
+	cmnd->resid = 0;
+	if (resp_info & RESID_UNDER) {
+		cmnd->resid = be32_to_cpu(fcprsp->rspResId);
+
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+				"%d:0716 FCP Read Underrun, expected %d, "
+				"residual %d Data: x%x x%x x%x\n", phba->brd_no,
+				be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
+				fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
+
+		/*
+		 * The cmnd->underflow is the minimum number of bytes that must
+		 * be transfered for this command.  Provided a sense condition
+		 * is not present, make sure the actual amount transferred is at
+		 * least the underflow value or fail.
+		 */
+		if (!(resp_info & SNS_LEN_VALID) &&
+		    (scsi_status == SAM_STAT_GOOD) &&
+		    (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+					"%d:0717 FCP command x%x residual "
+					"underrun converted to error "
+					"Data: x%x x%x x%x\n", phba->brd_no,
+					cmnd->cmnd[0], cmnd->request_bufflen,
+					cmnd->resid, cmnd->underflow);
+
+			host_status = DID_ERROR;
+		}
+	} else if (resp_info & RESID_OVER) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+				"%d:0720 FCP command x%x residual "
+				"overrun error. Data: x%x x%x \n",
+				phba->brd_no, cmnd->cmnd[0],
+				cmnd->request_bufflen, cmnd->resid);
+		host_status = DID_ERROR;
+
+	/*
+	 * Check SLI validation that all the transfer was actually done
+	 * (fcpi_parm should be zero). Apply check only to reads.
+	 */
+	} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
+			(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+			"%d:0734 FCP Read Check Error Data: "
+			"x%x x%x x%x x%x\n", phba->brd_no,
+			be32_to_cpu(fcpcmd->fcpDl),
+			be32_to_cpu(fcprsp->rspResId),
+			fcpi_parm, cmnd->cmnd[0]);
+		host_status = DID_ERROR;
+		cmnd->resid = cmnd->request_bufflen;
+	}
+
+ out:
+	cmnd->result = ScsiResult(host_status, scsi_status);
+}
+
+static void
+lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+			struct lpfc_iocbq *pIocbOut)
+{
+	struct lpfc_scsi_buf *lpfc_cmd =
+		(struct lpfc_scsi_buf *) pIocbIn->context1;
+	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
+	struct lpfc_nodelist *pnode = rdata->pnode;
+	struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+	unsigned long iflag;
+
+	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
+	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
+
+	if (lpfc_cmd->status) {
+		if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
+		    (lpfc_cmd->result & IOERR_DRVR_MASK))
+			lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
+		else if (lpfc_cmd->status >= IOSTAT_CNT)
+			lpfc_cmd->status = IOSTAT_DEFAULT;
+
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+				"%d:0729 FCP cmd x%x failed <%d/%d> status: "
+				"x%x result: x%x Data: x%x x%x\n",
+				phba->brd_no, cmd->cmnd[0], cmd->device->id,
+				cmd->device->lun, lpfc_cmd->status,
+				lpfc_cmd->result, pIocbOut->iocb.ulpContext,
+				lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
+
+		switch (lpfc_cmd->status) {
+		case IOSTAT_FCP_RSP_ERROR:
+			/* Call FCP RSP handler to determine result */
+			lpfc_handle_fcp_err(lpfc_cmd);
+			break;
+		case IOSTAT_NPORT_BSY:
+		case IOSTAT_FABRIC_BSY:
+			cmd->result = ScsiResult(DID_BUS_BUSY, 0);
+			break;
+		default:
+			cmd->result = ScsiResult(DID_ERROR, 0);
+			break;
+		}
+
+		if (pnode) {
+			if (pnode->nlp_state != NLP_STE_MAPPED_NODE)
+				cmd->result = ScsiResult(DID_BUS_BUSY,
+					SAM_STAT_BUSY);
+		}
+		else {
+			cmd->result = ScsiResult(DID_NO_CONNECT, 0);
+		}
+	} else {
+		cmd->result = ScsiResult(DID_OK, 0);
+	}
+
+	if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) {
+		uint32_t *lp = (uint32_t *)cmd->sense_buffer;
+
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+				"%d:0710 Iodone <%d/%d> cmd %p, error x%x "
+				"SNS x%x x%x Data: x%x x%x\n",
+				phba->brd_no, cmd->device->id,
+				cmd->device->lun, cmd, cmd->result,
+				*lp, *(lp + 3), cmd->retries, cmd->resid);
+	}
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	lpfc_free_scsi_buf(lpfc_cmd);
+	cmd->host_scribble = NULL;
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+	cmd->scsi_done(cmd);
+}
+
+static void
+lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
+			struct lpfc_nodelist *pnode)
+{
+	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
+	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
+	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
+	struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq);
+	int datadir = scsi_cmnd->sc_data_direction;
+
+	lpfc_cmd->fcp_rsp->rspSnsLen = 0;
+
+	lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+
+	memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
+
+	if (scsi_cmnd->device->tagged_supported) {
+		switch (scsi_cmnd->tag) {
+		case HEAD_OF_QUEUE_TAG:
+			fcp_cmnd->fcpCntl1 = HEAD_OF_Q;
+			break;
+		case ORDERED_QUEUE_TAG:
+			fcp_cmnd->fcpCntl1 = ORDERED_Q;
+			break;
+		default:
+			fcp_cmnd->fcpCntl1 = SIMPLE_Q;
+			break;
+		}
+	} else
+		fcp_cmnd->fcpCntl1 = 0;
+
+	/*
+	 * There are three possibilities here - use scatter-gather segment, use
+	 * the single mapping, or neither.  Start the lpfc command prep by
+	 * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first
+	 * data bde entry.
+	 */
+	if (scsi_cmnd->use_sg) {
+		if (datadir == DMA_TO_DEVICE) {
+			iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
+			iocb_cmd->un.fcpi.fcpi_parm = 0;
+			iocb_cmd->ulpPU = 0;
+			fcp_cmnd->fcpCntl3 = WRITE_DATA;
+			phba->fc4OutputRequests++;
+		} else {
+			iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
+			iocb_cmd->ulpPU = PARM_READ_CHECK;
+			iocb_cmd->un.fcpi.fcpi_parm =
+				scsi_cmnd->request_bufflen;
+			fcp_cmnd->fcpCntl3 = READ_DATA;
+			phba->fc4InputRequests++;
+		}
+	} else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
+		if (datadir == DMA_TO_DEVICE) {
+			iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
+			iocb_cmd->un.fcpi.fcpi_parm = 0;
+			iocb_cmd->ulpPU = 0;
+			fcp_cmnd->fcpCntl3 = WRITE_DATA;
+			phba->fc4OutputRequests++;
+		} else {
+			iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
+			iocb_cmd->ulpPU = PARM_READ_CHECK;
+			iocb_cmd->un.fcpi.fcpi_parm =
+				scsi_cmnd->request_bufflen;
+			fcp_cmnd->fcpCntl3 = READ_DATA;
+			phba->fc4InputRequests++;
+		}
+	} else {
+		iocb_cmd->ulpCommand = CMD_FCP_ICMND64_CR;
+		iocb_cmd->un.fcpi.fcpi_parm = 0;
+		iocb_cmd->ulpPU = 0;
+		fcp_cmnd->fcpCntl3 = 0;
+		phba->fc4ControlRequests++;
+	}
+
+	/*
+	 * Finish initializing those IOCB fields that are independent
+	 * of the scsi_cmnd request_buffer
+	 */
+	piocbq->iocb.ulpContext = pnode->nlp_rpi;
+	if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
+		piocbq->iocb.ulpFCP2Rcvy = 1;
+
+	piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
+	piocbq->context1  = lpfc_cmd;
+	piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
+	piocbq->iocb.ulpTimeout = lpfc_cmd->timeout;
+}
+
+static int
+lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
+			     struct lpfc_scsi_buf *lpfc_cmd,
+			     uint8_t task_mgmt_cmd)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_iocbq *piocbq;
+	IOCB_t *piocb;
+	struct fcp_cmnd *fcp_cmnd;
+	struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device;
+	struct lpfc_rport_data *rdata = scsi_dev->hostdata;
+	struct lpfc_nodelist *ndlp = rdata->pnode;
+
+	if ((ndlp == 0) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
+		return 0;
+	}
+
+	psli = &phba->sli;
+	piocbq = &(lpfc_cmd->cur_iocbq);
+	piocb = &piocbq->iocb;
+
+	fcp_cmnd = lpfc_cmd->fcp_cmnd;
+	lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+	fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
+
+	piocb->ulpCommand = CMD_FCP_ICMND64_CR;
+
+	piocb->ulpContext = ndlp->nlp_rpi;
+	if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+		piocb->ulpFCP2Rcvy = 1;
+	}
+	piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f);
+
+	/* ulpTimeout is only one byte */
+	if (lpfc_cmd->timeout > 0xff) {
+		/*
+		 * Do not timeout the command at the firmware level.
+		 * The driver will provide the timeout mechanism.
+		 */
+		piocb->ulpTimeout = 0;
+	} else {
+		piocb->ulpTimeout = lpfc_cmd->timeout;
+	}
+
+	lpfc_cmd->rdata = rdata;
+
+	switch (task_mgmt_cmd) {
+	case FCP_LUN_RESET:
+		/* Issue LUN Reset to TGT <num> LUN <num> */
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_FCP,
+				"%d:0703 Issue LUN Reset to TGT %d LUN %d "
+				"Data: x%x x%x\n",
+				phba->brd_no,
+				scsi_dev->id, scsi_dev->lun,
+				ndlp->nlp_rpi, ndlp->nlp_flag);
+
+		break;
+	case FCP_ABORT_TASK_SET:
+		/* Issue Abort Task Set to TGT <num> LUN <num> */
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_FCP,
+				"%d:0701 Issue Abort Task Set to TGT %d LUN %d "
+				"Data: x%x x%x\n",
+				phba->brd_no,
+				scsi_dev->id, scsi_dev->lun,
+				ndlp->nlp_rpi, ndlp->nlp_flag);
+
+		break;
+	case FCP_TARGET_RESET:
+		/* Issue Target Reset to TGT <num> */
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_FCP,
+				"%d:0702 Issue Target Reset to TGT %d "
+				"Data: x%x x%x\n",
+				phba->brd_no,
+				scsi_dev->id, ndlp->nlp_rpi,
+				ndlp->nlp_flag);
+		break;
+	}
+
+	return (1);
+}
+
+static int
+lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
+{
+	struct lpfc_iocbq *iocbq;
+	struct lpfc_iocbq *iocbqrsp = NULL;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	int ret;
+
+	ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
+	if (!ret)
+		return FAILED;
+
+	lpfc_cmd->scsi_hba = phba;
+	iocbq = &lpfc_cmd->cur_iocbq;
+	list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list);
+	if (!iocbqrsp)
+		return FAILED;
+	memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq));
+
+	iocbq->iocb_flag |= LPFC_IO_POLL;
+	ret = lpfc_sli_issue_iocb_wait_high_priority(phba,
+		     &phba->sli.ring[phba->sli.fcp_ring],
+		     iocbq, SLI_IOCB_HIGH_PRIORITY,
+		     iocbqrsp,
+		     lpfc_cmd->timeout);
+	if (ret != IOCB_SUCCESS) {
+		lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
+		ret = FAILED;
+	} else {
+		ret = SUCCESS;
+		lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
+		lpfc_cmd->status = iocbqrsp->iocb.ulpStatus;
+		if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
+			(lpfc_cmd->result & IOERR_DRVR_MASK))
+				lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
+	}
+
+	/*
+	 * All outstanding txcmplq I/Os should have been aborted by the target.
+	 * Unfortunately, some targets do not abide by this forcing the driver
+	 * to double check.
+	 */
+	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+			    lpfc_cmd->pCmd->device->id,
+			    lpfc_cmd->pCmd->device->lun, 0, LPFC_CTX_TGT);
+
+	/* Return response IOCB to free list. */
+	list_add_tail(&iocbqrsp->list, lpfc_iocb_list);
+	return ret;
+}
+
+static void
+lpfc_scsi_cmd_iocb_cleanup (struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+			    struct lpfc_iocbq *pIocbOut)
+{
+	unsigned long iflag;
+	struct lpfc_scsi_buf *lpfc_cmd =
+		(struct lpfc_scsi_buf *) pIocbIn->context1;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	lpfc_free_scsi_buf(lpfc_cmd);
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+static void
+lpfc_scsi_cmd_iocb_cmpl_aborted(struct lpfc_hba *phba,
+				struct lpfc_iocbq *pIocbIn,
+				struct lpfc_iocbq *pIocbOut)
+{
+	struct scsi_cmnd *ml_cmd =
+		((struct lpfc_scsi_buf *) pIocbIn->context1)->pCmd;
+
+	lpfc_scsi_cmd_iocb_cleanup (phba, pIocbIn, pIocbOut);
+	ml_cmd->host_scribble = NULL;
+}
+
+const char *
+lpfc_info(struct Scsi_Host *host)
+{
+	struct lpfc_hba    *phba = (struct lpfc_hba *) host->hostdata[0];
+	int len;
+	static char  lpfcinfobuf[384];
+
+	memset(lpfcinfobuf,0,384);
+	if (phba && phba->pcidev){
+		strncpy(lpfcinfobuf, phba->ModelDesc, 256);
+		len = strlen(lpfcinfobuf);
+		snprintf(lpfcinfobuf + len,
+			384-len,
+			" on PCI bus %02x device %02x irq %d",
+			phba->pcidev->bus->number,
+			phba->pcidev->devfn,
+			phba->pcidev->irq);
+		len = strlen(lpfcinfobuf);
+		if (phba->Port[0]) {
+			snprintf(lpfcinfobuf + len,
+				 384-len,
+				 " port %s",
+				 phba->Port);
+		}
+	}
+	return lpfcinfobuf;
+}
+
+static int
+lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+{
+	struct lpfc_hba *phba =
+		(struct lpfc_hba *) cmnd->device->host->hostdata[0];
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+	struct lpfc_nodelist *ndlp = rdata->pnode;
+	struct lpfc_scsi_buf *lpfc_cmd = NULL;
+	struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+	int err = 0;
+
+	/*
+	 * The target pointer is guaranteed not to be NULL because the driver
+	 * only clears the device->hostdata field in lpfc_slave_destroy.  This
+	 * approach guarantees no further IO calls on this target.
+	 */
+	if (!ndlp) {
+		cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
+		goto out_fail_command;
+	}
+
+	/*
+	 * A Fibre Channel target is present and functioning only when the node
+	 * state is MAPPED.  Any other state is a failure.
+	 */
+	if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) {
+		if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
+		    (ndlp->nlp_state == NLP_STE_UNUSED_NODE)) {
+			cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
+			goto out_fail_command;
+		}
+		/*
+		 * The device is most likely recovered and the driver
+		 * needs a bit more time to finish.  Ask the midlayer
+		 * to retry.
+		 */
+		goto out_host_busy;
+	}
+
+	list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+	if (lpfc_cmd == NULL) {
+		printk(KERN_WARNING "%s: No buffer available - list empty, "
+		       "total count %d\n", __FUNCTION__, phba->total_scsi_bufs);
+		goto out_host_busy;
+	}
+
+	/*
+	 * Store the midlayer's command structure for the completion phase
+	 * and complete the command initialization.
+	 */
+	lpfc_cmd->pCmd  = cmnd;
+	lpfc_cmd->rdata = rdata;
+	lpfc_cmd->timeout = 0;
+	cmnd->host_scribble = (unsigned char *)lpfc_cmd;
+	cmnd->scsi_done = done;
+
+	err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
+	if (err)
+		goto out_host_busy_free_buf;
+
+	lpfc_scsi_prep_cmnd(phba, lpfc_cmd, ndlp);
+
+	err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
+				&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+	if (err)
+		goto out_host_busy_free_buf;
+	return 0;
+
+ out_host_busy_free_buf:
+	lpfc_free_scsi_buf(lpfc_cmd);
+	cmnd->host_scribble = NULL;
+ out_host_busy:
+	return SCSI_MLQUEUE_HOST_BUSY;
+
+ out_fail_command:
+	done(cmnd);
+	return 0;
+}
+
+static int
+lpfc_abort_handler(struct scsi_cmnd *cmnd)
+{
+	struct lpfc_hba *phba =
+			(struct lpfc_hba *)cmnd->device->host->hostdata[0];
+	struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
+	struct lpfc_iocbq *iocb, *next_iocb;
+	struct lpfc_iocbq *abtsiocb = NULL;
+	struct lpfc_scsi_buf *lpfc_cmd;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	IOCB_t *cmd, *icmd;
+	unsigned long snum;
+	unsigned int id, lun;
+	unsigned int loop_count = 0;
+	int ret = IOCB_SUCCESS;
+
+	/*
+	 * If the host_scribble data area is NULL, then the driver has already
+	 * completed this command, but the midlayer did not see the completion
+	 * before the eh fired.  Just return SUCCESS.
+	 */
+	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
+	if (!lpfc_cmd)
+		return SUCCESS;
+
+	/* save these now since lpfc_cmd can be freed */
+	id   = lpfc_cmd->pCmd->device->id;
+	lun  = lpfc_cmd->pCmd->device->lun;
+	snum = lpfc_cmd->pCmd->serial_number;
+
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+		cmd = &iocb->iocb;
+		if (iocb->context1 != lpfc_cmd)
+			continue;
+
+		list_del_init(&iocb->list);
+		pring->txq_cnt--;
+		if (!iocb->iocb_cmpl) {
+			list_add_tail(&iocb->list, lpfc_iocb_list);
+		}
+		else {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			lpfc_scsi_cmd_iocb_cmpl_aborted(phba, iocb, iocb);
+		}
+
+		goto out;
+	}
+
+	list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq, list);
+	if (abtsiocb == NULL)
+		return FAILED;
+
+	memset(abtsiocb, 0, sizeof (struct lpfc_iocbq));
+
+	/*
+	 * The scsi command was not in the txq.  Check the txcmplq and if it is
+	 * found, send an abort to the FW.
+	 */
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		if (iocb->context1 != lpfc_cmd)
+			continue;
+
+		iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl_aborted;
+		cmd = &iocb->iocb;
+		icmd = &abtsiocb->iocb;
+		icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
+		icmd->un.acxri.abortContextTag = cmd->ulpContext;
+		icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
+
+		icmd->ulpLe = 1;
+		icmd->ulpClass = cmd->ulpClass;
+		if (phba->hba_state >= LPFC_LINK_UP)
+			icmd->ulpCommand = CMD_ABORT_XRI_CN;
+		else
+			icmd->ulpCommand = CMD_CLOSE_XRI_CN;
+
+		if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) ==
+								IOCB_ERROR) {
+			list_add_tail(&abtsiocb->list, lpfc_iocb_list);
+			ret = IOCB_ERROR;
+			break;
+		}
+
+		/* Wait for abort to complete */
+		while (cmnd->host_scribble)
+		{
+			spin_unlock_irq(phba->host->host_lock);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(LPFC_ABORT_WAIT*HZ);
+			spin_lock_irq(phba->host->host_lock);
+			if (++loop_count
+			    > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
+				break;
+		}
+
+		if(cmnd->host_scribble) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+					"%d:0748 abort handler timed "
+					"out waiting for abort to "
+					"complete. Data: "
+					"x%x x%x x%x x%lx\n",
+					phba->brd_no, ret, id, lun, snum);
+			cmnd->host_scribble = NULL;
+			iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cleanup;
+			ret = IOCB_ERROR;
+		}
+
+		break;
+	}
+
+ out:
+	lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+			"%d:0749 SCSI layer issued abort device "
+			"Data: x%x x%x x%x x%lx\n",
+			phba->brd_no, ret, id, lun, snum);
+
+	return ret == IOCB_SUCCESS ? SUCCESS : FAILED;
+}
+
+static int
+lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
+{
+	struct Scsi_Host *shost = cmnd->device->host;
+	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_scsi_buf *lpfc_cmd = NULL;
+	struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	struct lpfc_iocbq *iocbq, *iocbqrsp = NULL;
+	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+	struct lpfc_nodelist *pnode = rdata->pnode;
+	int ret = FAILED;
+	int cnt, loopcnt;
+
+	/*
+	 * If target is not in a MAPPED state, delay the reset until
+	 * target is rediscovered or nodev timeout expires.
+	 */
+	while ( 1 ) {
+		if (!pnode)
+			break;
+
+		if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
+			spin_unlock_irq(phba->host->host_lock);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout( HZ/2);
+			spin_lock_irq(phba->host->host_lock);
+		}
+		if ((pnode) && (pnode->nlp_state == NLP_STE_MAPPED_NODE))
+			break;
+	}
+
+	list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+	if (lpfc_cmd == NULL)
+		goto out;
+
+	lpfc_cmd->pCmd = cmnd;
+	lpfc_cmd->timeout = 60;
+	lpfc_cmd->scsi_hba = phba;
+
+	ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
+	if (!ret)
+		goto out_free_scsi_buf;
+
+	iocbq = &lpfc_cmd->cur_iocbq;
+
+	/* get a buffer for this IOCB command response */
+	list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list);
+	if (iocbqrsp == NULL)
+		goto out_free_scsi_buf;
+
+	memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq));
+
+	iocbq->iocb_flag |= LPFC_IO_POLL;
+	iocbq->iocb_cmpl = lpfc_sli_wake_iocb_high_priority;
+
+	ret = lpfc_sli_issue_iocb_wait_high_priority(phba,
+		     &phba->sli.ring[psli->fcp_ring],
+		     iocbq, 0, iocbqrsp, 60);
+	if (ret == IOCB_SUCCESS)
+		ret = SUCCESS;
+
+	lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
+	lpfc_cmd->status = iocbqrsp->iocb.ulpStatus;
+	if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT)
+		if (lpfc_cmd->result & IOERR_DRVR_MASK)
+			lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
+
+	/*
+	 * All outstanding txcmplq I/Os should have been aborted by the target.
+	 * Unfortunately, some targets do not abide by this forcing the driver
+	 * to double check.
+	 */
+	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+			    cmnd->device->id, cmnd->device->lun, 0,
+			    LPFC_CTX_LUN);
+
+	loopcnt = 0;
+	while((cnt = lpfc_sli_sum_iocb(phba,
+				       &phba->sli.ring[phba->sli.fcp_ring],
+				       cmnd->device->id, cmnd->device->lun,
+				       LPFC_CTX_LUN))) {
+		spin_unlock_irq(phba->host->host_lock);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(LPFC_RESET_WAIT*HZ);
+		spin_lock_irq(phba->host->host_lock);
+
+		if (++loopcnt
+		    > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+			break;
+	}
+
+	if (cnt) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+			"%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
+			phba->brd_no, cnt);
+	}
+
+	list_add_tail(&iocbqrsp->list, lpfc_iocb_list);
+
+out_free_scsi_buf:
+	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+			"%d:0713 SCSI layer issued LUN reset (%d, %d) "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no, lpfc_cmd->pCmd->device->id,
+			lpfc_cmd->pCmd->device->lun, ret, lpfc_cmd->status,
+			lpfc_cmd->result);
+	lpfc_free_scsi_buf(lpfc_cmd);
+out:
+	return ret;
+}
+
+/*
+ * Note: midlayer calls this function with the host_lock held
+ */
+static int
+lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+{
+	struct Scsi_Host *shost = cmnd->device->host;
+	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
+	struct lpfc_nodelist *ndlp = NULL;
+	int match;
+	int ret = FAILED, i, err_count = 0;
+	int cnt, loopcnt;
+	unsigned int midlayer_id = 0;
+	struct lpfc_scsi_buf * lpfc_cmd = NULL;
+	struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+
+	list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+	if (lpfc_cmd == NULL)
+		goto out;
+
+	/* The lpfc_cmd storage is reused.  Set all loop invariants. */
+	lpfc_cmd->timeout = 60;
+	lpfc_cmd->pCmd = cmnd;
+	lpfc_cmd->scsi_hba = phba;
+
+	/*
+	 * Since the driver manages a single bus device, reset all
+	 * targets known to the driver.  Should any target reset
+	 * fail, this routine returns failure to the midlayer.
+	 */
+	midlayer_id = cmnd->device->id;
+	for (i = 0; i < MAX_FCP_TARGET; i++) {
+		/* Search the mapped list for this target ID */
+		match = 0;
+		list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
+			if ((i == ndlp->nlp_sid) && ndlp->rport) {
+				match = 1;
+				break;
+			}
+		}
+		if (!match)
+			continue;
+
+		lpfc_cmd->pCmd->device->id = i;
+		lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data;
+		ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba);
+		if (ret != SUCCESS) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+				"%d:0713 Bus Reset on target %d failed\n",
+				phba->brd_no, i);
+			err_count++;
+		}
+	}
+
+	cmnd->device->id = midlayer_id;
+	loopcnt = 0;
+	while((cnt = lpfc_sli_sum_iocb(phba,
+				&phba->sli.ring[phba->sli.fcp_ring],
+				0, 0, LPFC_CTX_HOST))) {
+		spin_unlock_irq(phba->host->host_lock);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(LPFC_RESET_WAIT*HZ);
+		spin_lock_irq(phba->host->host_lock);
+
+		if (++loopcnt
+		    > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+			break;
+	}
+
+	if (cnt) {
+		/* flush all outstanding commands on the host */
+		i = lpfc_sli_abort_iocb(phba,
+				&phba->sli.ring[phba->sli.fcp_ring], 0, 0, 0,
+				LPFC_CTX_HOST);
+
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+		   "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n",
+		   phba->brd_no, cnt, i);
+	}
+
+	if (!err_count)
+		ret = SUCCESS;
+
+	lpfc_free_scsi_buf(lpfc_cmd);
+	lpfc_printf_log(phba,
+			KERN_ERR,
+			LOG_FCP,
+			"%d:0714 SCSI layer issued Bus Reset Data: x%x\n",
+			phba->brd_no, ret);
+out:
+	return ret;
+}
+
+static int
+lpfc_slave_alloc(struct scsi_device *sdev)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0];
+	struct lpfc_nodelist *ndlp = NULL;
+	int match = 0;
+	struct lpfc_scsi_buf *scsi_buf = NULL;
+	uint32_t total = 0, i;
+	uint32_t num_to_alloc = 0;
+	unsigned long flags;
+	struct list_head *listp;
+	struct list_head *node_list[6];
+
+	/*
+	 * Store the target pointer in the scsi_device hostdata pointer provided
+	 * the driver has already discovered the target id.
+	 */
+
+	/* Search the nlp lists other than unmap_list for this target ID */
+	node_list[0] = &phba->fc_npr_list;
+	node_list[1] = &phba->fc_nlpmap_list;
+	node_list[2] = &phba->fc_prli_list;
+	node_list[3] = &phba->fc_reglogin_list;
+	node_list[4] = &phba->fc_adisc_list;
+	node_list[5] = &phba->fc_plogi_list;
+
+	for (i = 0; i < 6 && !match; i++) {
+		listp = node_list[i];
+		if (list_empty(listp))
+			continue;
+		list_for_each_entry(ndlp, listp, nlp_listp) {
+			if ((sdev->id == ndlp->nlp_sid) && ndlp->rport) {
+				match = 1;
+				break;
+			}
+		}
+	}
+
+	if (!match)
+		return -ENXIO;
+
+	sdev->hostdata = ndlp->rport->dd_data;
+
+	/*
+	 * Populate the cmds_per_lun count scsi_bufs into this host's globally
+	 * available list of scsi buffers.  Don't allocate more than the
+	 * HBA limit conveyed to the midlayer via the host structure.  Note
+	 * that this list of scsi bufs exists for the lifetime of the driver.
+	 */
+	total = phba->total_scsi_bufs;
+	num_to_alloc = LPFC_CMD_PER_LUN;
+	if (total >= phba->cfg_hba_queue_depth) {
+		printk(KERN_WARNING "%s, At config limitation of "
+		       "%d allocated scsi_bufs\n", __FUNCTION__, total);
+		return 0;
+	} else if (total + num_to_alloc > phba->cfg_hba_queue_depth) {
+		num_to_alloc = phba->cfg_hba_queue_depth - total;
+	}
+
+	for (i = 0; i < num_to_alloc; i++) {
+		scsi_buf = lpfc_get_scsi_buf(phba);
+		if (!scsi_buf) {
+			printk(KERN_ERR "%s, failed to allocate "
+			       "scsi_buf\n", __FUNCTION__);
+			break;
+		}
+
+		spin_lock_irqsave(phba->host->host_lock, flags);
+		phba->total_scsi_bufs++;
+		list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list);
+		spin_unlock_irqrestore(phba->host->host_lock, flags);
+	}
+	return 0;
+}
+
+static int
+lpfc_slave_configure(struct scsi_device *sdev)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata[0];
+	struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
+
+	if (sdev->tagged_supported)
+		scsi_activate_tcq(sdev, phba->cfg_lun_queue_depth);
+	else
+		scsi_deactivate_tcq(sdev, phba->cfg_lun_queue_depth);
+
+	/*
+	 * Initialize the fc transport attributes for the target
+	 * containing this scsi device.  Also note that the driver's
+	 * target pointer is stored in the starget_data for the
+	 * driver's sysfs entry point functions.
+	 */
+	rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5;
+
+	return 0;
+}
+
+static void
+lpfc_slave_destroy(struct scsi_device *sdev)
+{
+	sdev->hostdata = NULL;
+	return;
+}
+
+struct scsi_host_template lpfc_template = {
+	.module			= THIS_MODULE,
+	.name			= LPFC_DRIVER_NAME,
+	.info			= lpfc_info,
+	.queuecommand		= lpfc_queuecommand,
+	.eh_abort_handler	= lpfc_abort_handler,
+	.eh_device_reset_handler= lpfc_reset_lun_handler,
+	.eh_bus_reset_handler	= lpfc_reset_bus_handler,
+	.slave_alloc		= lpfc_slave_alloc,
+	.slave_configure	= lpfc_slave_configure,
+	.slave_destroy		= lpfc_slave_destroy,
+	.this_id		= -1,
+	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.cmd_per_lun		= LPFC_CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= lpfc_host_attrs,
+};
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -0,0 +1,157 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_scsi.h 1.83 2005/04/07 08:47:43EDT sf_support Exp  $
+ */
+
+struct lpfc_hba;
+
+#define list_remove_head(list, entry, type, member)		\
+	if (!list_empty(list)) {				\
+		entry = list_entry((list)->next, type, member);	\
+		list_del_init(&entry->member);			\
+	}
+
+#define list_get_first(list, type, member)			\
+	(list_empty(list)) ? NULL :				\
+	list_entry((list)->next, type, member)
+
+/* per-port data that is allocated in the FC transport for us */
+struct lpfc_rport_data {
+	struct lpfc_nodelist *pnode;	/* Pointer to the node structure. */
+};
+
+struct fcp_rsp {
+	uint32_t rspRsvd1;	/* FC Word 0, byte 0:3 */
+	uint32_t rspRsvd2;	/* FC Word 1, byte 0:3 */
+
+	uint8_t rspStatus0;	/* FCP_STATUS byte 0 (reserved) */
+	uint8_t rspStatus1;	/* FCP_STATUS byte 1 (reserved) */
+	uint8_t rspStatus2;	/* FCP_STATUS byte 2 field validity */
+#define RSP_LEN_VALID  0x01	/* bit 0 */
+#define SNS_LEN_VALID  0x02	/* bit 1 */
+#define RESID_OVER     0x04	/* bit 2 */
+#define RESID_UNDER    0x08	/* bit 3 */
+	uint8_t rspStatus3;	/* FCP_STATUS byte 3 SCSI status byte */
+
+	uint32_t rspResId;	/* Residual xfer if residual count field set in
+				   fcpStatus2 */
+	/* Received in Big Endian format */
+	uint32_t rspSnsLen;	/* Length of sense data in fcpSnsInfo */
+	/* Received in Big Endian format */
+	uint32_t rspRspLen;	/* Length of FCP response data in fcpRspInfo */
+	/* Received in Big Endian format */
+
+	uint8_t rspInfo0;	/* FCP_RSP_INFO byte 0 (reserved) */
+	uint8_t rspInfo1;	/* FCP_RSP_INFO byte 1 (reserved) */
+	uint8_t rspInfo2;	/* FCP_RSP_INFO byte 2 (reserved) */
+	uint8_t rspInfo3;	/* FCP_RSP_INFO RSP_CODE byte 3 */
+
+#define RSP_NO_FAILURE       0x00
+#define RSP_DATA_BURST_ERR   0x01
+#define RSP_CMD_FIELD_ERR    0x02
+#define RSP_RO_MISMATCH_ERR  0x03
+#define RSP_TM_NOT_SUPPORTED 0x04	/* Task mgmt function not supported */
+#define RSP_TM_NOT_COMPLETED 0x05	/* Task mgmt function not performed */
+
+	uint32_t rspInfoRsvd;	/* FCP_RSP_INFO bytes 4-7 (reserved) */
+
+	uint8_t rspSnsInfo[128];
+#define SNS_ILLEGAL_REQ 0x05	/* sense key is byte 3 ([2]) */
+#define SNSCOD_BADCMD 0x20	/* sense code is byte 13 ([12]) */
+};
+
+struct fcp_cmnd {
+	uint32_t fcpLunMsl;	/* most  significant lun word (32 bits) */
+	uint32_t fcpLunLsl;	/* least significant lun word (32 bits) */
+	/* # of bits to shift lun id to end up in right
+	 * payload word, little endian = 8, big = 16.
+	 */
+#if __BIG_ENDIAN
+#define FC_LUN_SHIFT         16
+#define FC_ADDR_MODE_SHIFT   24
+#else	/*  __LITTLE_ENDIAN */
+#define FC_LUN_SHIFT         8
+#define FC_ADDR_MODE_SHIFT   0
+#endif
+
+	uint8_t fcpCntl0;	/* FCP_CNTL byte 0 (reserved) */
+	uint8_t fcpCntl1;	/* FCP_CNTL byte 1 task codes */
+#define  SIMPLE_Q        0x00
+#define  HEAD_OF_Q       0x01
+#define  ORDERED_Q       0x02
+#define  ACA_Q           0x04
+#define  UNTAGGED        0x05
+	uint8_t fcpCntl2;	/* FCP_CTL byte 2 task management codes */
+#define  FCP_ABORT_TASK_SET  0x02	/* Bit 1 */
+#define  FCP_CLEAR_TASK_SET  0x04	/* bit 2 */
+#define  FCP_BUS_RESET       0x08	/* bit 3 */
+#define  FCP_LUN_RESET       0x10	/* bit 4 */
+#define  FCP_TARGET_RESET    0x20	/* bit 5 */
+#define  FCP_CLEAR_ACA       0x40	/* bit 6 */
+#define  FCP_TERMINATE_TASK  0x80	/* bit 7 */
+	uint8_t fcpCntl3;
+#define  WRITE_DATA      0x01	/* Bit 0 */
+#define  READ_DATA       0x02	/* Bit 1 */
+
+	uint8_t fcpCdb[16];	/* SRB cdb field is copied here */
+	uint32_t fcpDl;		/* Total transfer length */
+
+};
+
+struct lpfc_scsi_buf {
+	struct list_head list;
+	struct scsi_cmnd *pCmd;
+	struct lpfc_hba *scsi_hba;
+	struct lpfc_rport_data *rdata;
+
+	uint32_t timeout;
+
+	uint16_t status;	/* From IOCB Word 7- ulpStatus */
+	uint32_t result;	/* From IOCB Word 4. */
+
+	uint32_t   seg_cnt;	/* Number of scatter-gather segments returned by
+				 * dma_map_sg.  The driver needs this for calls
+				 * to dma_unmap_sg. */
+	dma_addr_t nonsg_phys;	/* Non scatter-gather physical address. */
+
+	/*
+	 * data and dma_handle are the kernel virutal and bus address of the
+	 * dma-able buffer containing the fcp_cmd, fcp_rsp and a scatter
+	 * gather bde list that supports the sg_tablesize value.
+	 */
+	void *data;
+	dma_addr_t dma_handle;
+
+	struct fcp_cmnd *fcp_cmnd;
+	struct fcp_rsp *fcp_rsp;
+	struct ulp_bde64 *fcp_bpl;
+
+	/* cur_iocbq has phys of the dma-able buffer.
+	 * Iotag is in here
+	 */
+	struct lpfc_iocbq cur_iocbq;
+};
+
+#define LPFC_SCSI_DMA_EXT_SIZE 264
+#define LPFC_BPL_SIZE          1024
+
+#define MDAC_DIRECT_CMD                  0x22
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -0,0 +1,2885 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_sli.c 1.232 2005/04/13 11:59:16EDT sf_support Exp  $
+ */
+
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_crtn.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_compat.h"
+
+/*
+ * Define macro to log: Mailbox command x%x cannot issue Data
+ * This allows multiple uses of lpfc_msgBlk0311
+ * w/o perturbing log msg utility.
+ */
+#define LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) \
+			lpfc_printf_log(phba, \
+				KERN_INFO, \
+				LOG_MBOX | LOG_SLI, \
+				"%d:0311 Mailbox command x%x cannot issue " \
+				"Data: x%x x%x x%x\n", \
+				phba->brd_no, \
+				mb->mbxCommand,		\
+				phba->hba_state,	\
+				psli->sli_flag,	\
+				flag);
+
+
+/* There are only four IOCB completion types. */
+typedef enum _lpfc_iocb_type {
+	LPFC_UNKNOWN_IOCB,
+	LPFC_UNSOL_IOCB,
+	LPFC_SOL_IOCB,
+	LPFC_ABORT_IOCB
+} lpfc_iocb_type;
+
+/*
+ * Translate the iocb command to an iocb command type used to decide the final
+ * disposition of each completed IOCB.
+ */
+static lpfc_iocb_type
+lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
+{
+	lpfc_iocb_type type = LPFC_UNKNOWN_IOCB;
+
+	if (iocb_cmnd > CMD_MAX_IOCB_CMD)
+		return 0;
+
+	switch (iocb_cmnd) {
+	case CMD_XMIT_SEQUENCE_CR:
+	case CMD_XMIT_SEQUENCE_CX:
+	case CMD_XMIT_BCAST_CN:
+	case CMD_XMIT_BCAST_CX:
+	case CMD_ELS_REQUEST_CR:
+	case CMD_ELS_REQUEST_CX:
+	case CMD_CREATE_XRI_CR:
+	case CMD_CREATE_XRI_CX:
+	case CMD_GET_RPI_CN:
+	case CMD_XMIT_ELS_RSP_CX:
+	case CMD_GET_RPI_CR:
+	case CMD_FCP_IWRITE_CR:
+	case CMD_FCP_IWRITE_CX:
+	case CMD_FCP_IREAD_CR:
+	case CMD_FCP_IREAD_CX:
+	case CMD_FCP_ICMND_CR:
+	case CMD_FCP_ICMND_CX:
+	case CMD_ADAPTER_MSG:
+	case CMD_ADAPTER_DUMP:
+	case CMD_XMIT_SEQUENCE64_CR:
+	case CMD_XMIT_SEQUENCE64_CX:
+	case CMD_XMIT_BCAST64_CN:
+	case CMD_XMIT_BCAST64_CX:
+	case CMD_ELS_REQUEST64_CR:
+	case CMD_ELS_REQUEST64_CX:
+	case CMD_FCP_IWRITE64_CR:
+	case CMD_FCP_IWRITE64_CX:
+	case CMD_FCP_IREAD64_CR:
+	case CMD_FCP_IREAD64_CX:
+	case CMD_FCP_ICMND64_CR:
+	case CMD_FCP_ICMND64_CX:
+	case CMD_GEN_REQUEST64_CR:
+	case CMD_GEN_REQUEST64_CX:
+	case CMD_XMIT_ELS_RSP64_CX:
+		type = LPFC_SOL_IOCB;
+		break;
+	case CMD_ABORT_XRI_CN:
+	case CMD_ABORT_XRI_CX:
+	case CMD_CLOSE_XRI_CN:
+	case CMD_CLOSE_XRI_CX:
+	case CMD_XRI_ABORTED_CX:
+	case CMD_ABORT_MXRI64_CN:
+		type = LPFC_ABORT_IOCB;
+		break;
+	case CMD_RCV_SEQUENCE_CX:
+	case CMD_RCV_ELS_REQ_CX:
+	case CMD_RCV_SEQUENCE64_CX:
+	case CMD_RCV_ELS_REQ64_CX:
+		type = LPFC_UNSOL_IOCB;
+		break;
+	default:
+		type = LPFC_UNKNOWN_IOCB;
+		break;
+	}
+
+	return type;
+}
+
+static int
+lpfc_sli_ring_map(struct lpfc_hba * phba, LPFC_MBOXQ_t *pmb)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	MAILBOX_t *pmbox = &pmb->mb;
+	int i, rc;
+
+	for (i = 0; i < psli->num_rings; i++) {
+		phba->hba_state = LPFC_INIT_MBX_CMDS;
+		lpfc_config_ring(phba, i, pmb);
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+		if (rc != MBX_SUCCESS) {
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_INIT,
+					"%d:0446 Adapter failed to init, "
+					"mbxCmd x%x CFG_RING, mbxStatus x%x, "
+					"ring %d\n",
+					phba->brd_no,
+					pmbox->mbxCommand,
+					pmbox->mbxStatus,
+					i);
+			phba->hba_state = LPFC_HBA_ERROR;
+			return -ENXIO;
+		}
+	}
+	return 0;
+}
+
+static int
+lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
+			struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
+{
+	uint16_t iotag;
+
+	list_add_tail(&piocb->list, &pring->txcmplq);
+	pring->txcmplq_cnt++;
+	if (unlikely(pring->ringno == LPFC_ELS_RING))
+		mod_timer(&phba->els_tmofunc,
+					jiffies + HZ * (phba->fc_ratov << 1));
+
+	if (pring->fast_lookup) {
+		/* Setup fast lookup based on iotag for completion */
+		iotag = piocb->iocb.ulpIoTag;
+		if (iotag && (iotag < pring->fast_iotag))
+			*(pring->fast_lookup + iotag) = piocb;
+		else {
+
+			/* Cmd ring <ringno> put: iotag <iotag> greater then
+			   configured max <fast_iotag> wd0 <icmd> */
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_SLI,
+					"%d:0316 Cmd ring %d put: iotag x%x "
+					"greater then configured max x%x "
+					"wd0 x%x\n",
+					phba->brd_no,
+					pring->ringno, iotag,
+					pring->fast_iotag,
+					*(((uint32_t *)(&piocb->iocb)) + 7));
+		}
+	}
+	return (0);
+}
+
+static struct lpfc_iocbq *
+lpfc_sli_ringtx_get(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+{
+	struct list_head *dlp;
+	struct lpfc_iocbq *cmd_iocb;
+
+	dlp = &pring->txq;
+	cmd_iocb = NULL;
+	list_remove_head((&pring->txq), cmd_iocb,
+			 struct lpfc_iocbq,
+			 list);
+	if (cmd_iocb) {
+		/* If the first ptr is not equal to the list header,
+		 * deque the IOCBQ_t and return it.
+		 */
+		pring->txq_cnt--;
+	}
+	return (cmd_iocb);
+}
+
+static IOCB_t *
+lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+	MAILBOX_t *mbox = (MAILBOX_t *)phba->sli.MBhostaddr;
+	PGP *pgp = (PGP *)&mbox->us.s2.port[pring->ringno];
+	uint32_t  max_cmd_idx = pring->numCiocb;
+	IOCB_t *iocb = NULL;
+
+	if ((pring->next_cmdidx == pring->cmdidx) &&
+	   (++pring->next_cmdidx >= max_cmd_idx))
+		pring->next_cmdidx = 0;
+
+	if (unlikely(pring->local_getidx == pring->next_cmdidx)) {
+
+		pring->local_getidx = le32_to_cpu(pgp->cmdGetInx);
+
+		if (unlikely(pring->local_getidx >= max_cmd_idx)) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"%d:0315 Ring %d issue: portCmdGet %d "
+					"is bigger then cmd ring %d\n",
+					phba->brd_no, pring->ringno,
+					pring->local_getidx, max_cmd_idx);
+
+			phba->hba_state = LPFC_HBA_ERROR;
+			/*
+			 * All error attention handlers are posted to
+			 * worker thread
+			 */
+			phba->work_ha |= HA_ERATT;
+			phba->work_hs = HS_FFER3;
+			if (phba->work_wait)
+				wake_up(phba->work_wait);
+
+			return NULL;
+		}
+
+		if (pring->local_getidx == pring->next_cmdidx)
+			return NULL;
+	}
+
+	iocb = IOCB_ENTRY(pring->cmdringaddr, pring->cmdidx);
+
+	return iocb;
+}
+
+static uint32_t
+lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+{
+	uint32_t search_start;
+
+	if (pring->fast_lookup == NULL) {
+		pring->iotag_ctr++;
+		if (pring->iotag_ctr >= pring->iotag_max)
+			pring->iotag_ctr = 1;
+		return pring->iotag_ctr;
+	}
+
+	search_start = pring->iotag_ctr;
+
+	do {
+		pring->iotag_ctr++;
+		if (pring->iotag_ctr >= pring->fast_iotag)
+			pring->iotag_ctr = 1;
+
+		if (*(pring->fast_lookup + pring->iotag_ctr) == NULL)
+			return pring->iotag_ctr;
+
+	} while (pring->iotag_ctr != search_start);
+
+	/*
+	 * Outstanding I/O count for ring <ringno> is at max <fast_iotag>
+	 */
+	lpfc_printf_log(phba,
+		KERN_ERR,
+		LOG_SLI,
+		"%d:0318 Outstanding I/O count for ring %d is at max x%x\n",
+		phba->brd_no,
+		pring->ringno,
+		pring->fast_iotag);
+	return (0);
+}
+
+static void
+lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
+{
+	/*
+	 * Allocate and set up an iotag
+	 */
+	nextiocb->iocb.ulpIoTag =
+		lpfc_sli_next_iotag(phba, &phba->sli.ring[phba->sli.fcp_ring]);
+
+	/*
+	 * Issue iocb command to adapter
+	 */
+	lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, sizeof (IOCB_t));
+	wmb();
+	pring->stats.iocb_cmd++;
+
+	/*
+	 * If there is no completion routine to call, we can release the
+	 * IOCB buffer back right now. For IOCBs, like QUE_RING_BUF,
+	 * that have no rsp ring completion, iocb_cmpl MUST be NULL.
+	 */
+	if (nextiocb->iocb_cmpl)
+		lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
+	else {
+		list_add_tail(&nextiocb->list, &phba->lpfc_iocb_list);
+	}
+
+	/*
+	 * Let the HBA know what IOCB slot will be the next one the
+	 * driver will put a command into.
+	 */
+	pring->cmdidx = pring->next_cmdidx;
+	writeb(pring->cmdidx, phba->MBslimaddr
+	       + (SLIMOFF + (pring->ringno * 2)) * 4);
+}
+
+static void
+lpfc_sli_update_full_ring(struct lpfc_hba * phba,
+			  struct lpfc_sli_ring *pring)
+{
+	int ringno = pring->ringno;
+
+	pring->flag |= LPFC_CALL_RING_AVAILABLE;
+
+	wmb();
+
+	/*
+	 * Set ring 'ringno' to SET R0CE_REQ in Chip Att register.
+	 * The HBA will tell us when an IOCB entry is available.
+	 */
+	writel((CA_R0ATT|CA_R0CE_REQ) << (ringno*4), phba->CAregaddr);
+	readl(phba->CAregaddr); /* flush */
+
+	pring->stats.iocb_cmd_full++;
+}
+
+static void
+lpfc_sli_update_ring(struct lpfc_hba * phba,
+		     struct lpfc_sli_ring *pring)
+{
+	int ringno = pring->ringno;
+
+	/*
+	 * Tell the HBA that there is work to do in this ring.
+	 */
+	wmb();
+	writel(CA_R0ATT << (ringno * 4), phba->CAregaddr);
+	readl(phba->CAregaddr); /* flush */
+}
+
+static void
+lpfc_sli_resume_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+{
+	IOCB_t *iocb;
+	struct lpfc_iocbq *nextiocb;
+
+	/*
+	 * Check to see if:
+	 *  (a) there is anything on the txq to send
+	 *  (b) link is up
+	 *  (c) link attention events can be processed (fcp ring only)
+	 *  (d) IOCB processing is not blocked by the outstanding mbox command.
+	 */
+	if (pring->txq_cnt &&
+	    (phba->hba_state > LPFC_LINK_DOWN) &&
+	    (pring->ringno != phba->sli.fcp_ring ||
+	     phba->sli.sli_flag & LPFC_PROCESS_LA) &&
+	    !(pring->flag & LPFC_STOP_IOCB_MBX)) {
+
+		while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
+		       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
+			lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
+
+		if (iocb)
+			lpfc_sli_update_ring(phba, pring);
+		else
+			lpfc_sli_update_full_ring(phba, pring);
+	}
+
+	return;
+}
+
+/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
+static void
+lpfc_sli_turn_on_ring(struct lpfc_hba * phba, int ringno)
+{
+	PGP *pgp =
+		((PGP *) &
+		 (((MAILBOX_t *)phba->sli.MBhostaddr)->us.s2.port[ringno]));
+
+	/* If the ring is active, flag it */
+	if (phba->sli.ring[ringno].cmdringaddr) {
+		if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
+			phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
+			/*
+			 * Force update of the local copy of cmdGetInx
+			 */
+			phba->sli.ring[ringno].local_getidx
+				= le32_to_cpu(pgp->cmdGetInx);
+			spin_lock_irq(phba->host->host_lock);
+			lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
+			spin_unlock_irq(phba->host->host_lock);
+		}
+	}
+}
+
+static int
+lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
+{
+	uint8_t ret;
+
+	switch (mbxCommand) {
+	case MBX_LOAD_SM:
+	case MBX_READ_NV:
+	case MBX_WRITE_NV:
+	case MBX_RUN_BIU_DIAG:
+	case MBX_INIT_LINK:
+	case MBX_DOWN_LINK:
+	case MBX_CONFIG_LINK:
+	case MBX_CONFIG_RING:
+	case MBX_RESET_RING:
+	case MBX_READ_CONFIG:
+	case MBX_READ_RCONFIG:
+	case MBX_READ_SPARM:
+	case MBX_READ_STATUS:
+	case MBX_READ_RPI:
+	case MBX_READ_XRI:
+	case MBX_READ_REV:
+	case MBX_READ_LNK_STAT:
+	case MBX_REG_LOGIN:
+	case MBX_UNREG_LOGIN:
+	case MBX_READ_LA:
+	case MBX_CLEAR_LA:
+	case MBX_DUMP_MEMORY:
+	case MBX_DUMP_CONTEXT:
+	case MBX_RUN_DIAGS:
+	case MBX_RESTART:
+	case MBX_UPDATE_CFG:
+	case MBX_DOWN_LOAD:
+	case MBX_DEL_LD_ENTRY:
+	case MBX_RUN_PROGRAM:
+	case MBX_SET_MASK:
+	case MBX_SET_SLIM:
+	case MBX_UNREG_D_ID:
+	case MBX_CONFIG_FARP:
+	case MBX_LOAD_AREA:
+	case MBX_RUN_BIU_DIAG64:
+	case MBX_CONFIG_PORT:
+	case MBX_READ_SPARM64:
+	case MBX_READ_RPI64:
+	case MBX_REG_LOGIN64:
+	case MBX_READ_LA64:
+	case MBX_FLASH_WR_ULA:
+	case MBX_SET_DEBUG:
+	case MBX_LOAD_EXP_ROM:
+		ret = mbxCommand;
+		break;
+	default:
+		ret = MBX_SHUTDOWN;
+		break;
+	}
+	return (ret);
+}
+static void
+lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+	wait_queue_head_t *pdone_q;
+
+	/*
+	 * If pdone_q is empty, the driver thread gave up waiting and
+	 * continued running.
+	 */
+	pdone_q = (wait_queue_head_t *) pmboxq->context1;
+	if (pdone_q)
+		wake_up_interruptible(pdone_q);
+	return;
+}
+
+void
+lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	struct lpfc_dmabuf *mp;
+	mp = (struct lpfc_dmabuf *) (pmb->context1);
+	if (mp) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+	}
+	mempool_free( pmb, phba->mbox_mem_pool);
+	return;
+}
+
+int
+lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
+{
+	MAILBOX_t *mbox;
+	MAILBOX_t *pmbox;
+	LPFC_MBOXQ_t *pmb;
+	struct lpfc_sli *psli;
+	int i, rc;
+	uint32_t process_next;
+
+	psli = &phba->sli;
+	/* We should only get here if we are in SLI2 mode */
+	if (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE)) {
+		return (1);
+	}
+
+	phba->sli.slistat.mbox_event++;
+
+	/* Get a Mailbox buffer to setup mailbox commands for callback */
+	if ((pmb = phba->sli.mbox_active)) {
+		pmbox = &pmb->mb;
+		mbox = (MAILBOX_t *) phba->sli.MBhostaddr;
+
+		/* First check out the status word */
+		lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof (uint32_t));
+
+		/* Sanity check to ensure the host owns the mailbox */
+		if (pmbox->mbxOwner != OWN_HOST) {
+			/* Lets try for a while */
+			for (i = 0; i < 10240; i++) {
+				/* First copy command data */
+				lpfc_sli_pcimem_bcopy(mbox, pmbox,
+							sizeof (uint32_t));
+				if (pmbox->mbxOwner == OWN_HOST)
+					goto mbout;
+			}
+			/* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
+			   <status> */
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_MBOX | LOG_SLI,
+					"%d:0304 Stray Mailbox Interrupt "
+					"mbxCommand x%x mbxStatus x%x\n",
+					phba->brd_no,
+					pmbox->mbxCommand,
+					pmbox->mbxStatus);
+
+			spin_lock_irq(phba->host->host_lock);
+			phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+			spin_unlock_irq(phba->host->host_lock);
+			return (1);
+		}
+
+	      mbout:
+		del_timer_sync(&phba->sli.mbox_tmo);
+		phba->work_hba_events &= ~WORKER_MBOX_TMO;
+
+		/*
+		 * It is a fatal error if unknown mbox command completion.
+		 */
+		if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) ==
+		    MBX_SHUTDOWN) {
+
+			/* Unknow mailbox command compl */
+			lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_MBOX | LOG_SLI,
+				"%d:0323 Unknown Mailbox command %x Cmpl\n",
+				phba->brd_no,
+				pmbox->mbxCommand);
+			phba->hba_state = LPFC_HBA_ERROR;
+			phba->work_hs = HS_FFER3;
+			lpfc_handle_eratt(phba);
+			return (0);
+		}
+
+		phba->sli.mbox_active = NULL;
+		if (pmbox->mbxStatus) {
+			phba->sli.slistat.mbox_stat_err++;
+			if (pmbox->mbxStatus == MBXERR_NO_RESOURCES) {
+				/* Mbox cmd cmpl error - RETRYing */
+				lpfc_printf_log(phba,
+					KERN_INFO,
+					LOG_MBOX | LOG_SLI,
+					"%d:0305 Mbox cmd cmpl error - "
+					"RETRYing Data: x%x x%x x%x x%x\n",
+					phba->brd_no,
+					pmbox->mbxCommand,
+					pmbox->mbxStatus,
+					pmbox->un.varWords[0],
+					phba->hba_state);
+				pmbox->mbxStatus = 0;
+				pmbox->mbxOwner = OWN_HOST;
+				spin_lock_irq(phba->host->host_lock);
+				phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+				spin_unlock_irq(phba->host->host_lock);
+				rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+				if (rc == MBX_SUCCESS)
+					return (0);
+			}
+		}
+
+		/* Mailbox cmd <cmd> Cmpl <cmpl> */
+		lpfc_printf_log(phba,
+				KERN_INFO,
+				LOG_MBOX | LOG_SLI,
+				"%d:0307 Mailbox cmd x%x Cmpl x%p "
+				"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
+				phba->brd_no,
+				pmbox->mbxCommand,
+				pmb->mbox_cmpl,
+				*((uint32_t *) pmbox),
+				pmbox->un.varWords[0],
+				pmbox->un.varWords[1],
+				pmbox->un.varWords[2],
+				pmbox->un.varWords[3],
+				pmbox->un.varWords[4],
+				pmbox->un.varWords[5],
+				pmbox->un.varWords[6],
+				pmbox->un.varWords[7]);
+
+		if (pmb->mbox_cmpl) {
+			lpfc_sli_pcimem_bcopy(mbox, pmbox, MAILBOX_CMD_SIZE);
+			pmb->mbox_cmpl(phba,pmb);
+		}
+	}
+
+
+	do {
+		process_next = 0;	/* by default don't loop */
+		spin_lock_irq(phba->host->host_lock);
+		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+
+		/* Process next mailbox command if there is one */
+		if ((pmb = lpfc_mbox_get(phba))) {
+			spin_unlock_irq(phba->host->host_lock);
+			rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+			if (rc == MBX_NOT_FINISHED) {
+				pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+				pmb->mbox_cmpl(phba,pmb);
+				process_next = 1;
+				continue;	/* loop back */
+			}
+		} else {
+			spin_unlock_irq(phba->host->host_lock);
+			/* Turn on IOCB processing */
+			for (i = 0; i < phba->sli.num_rings; i++) {
+				lpfc_sli_turn_on_ring(phba, i);
+			}
+
+			/* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */
+			while (!list_empty(&phba->freebufList)) {
+				struct lpfc_dmabuf *mp;
+
+				mp = NULL;
+				list_remove_head((&phba->freebufList),
+						 mp,
+						 struct lpfc_dmabuf,
+						 list);
+				if (mp) {
+					lpfc_mbuf_free(phba, mp->virt,
+						       mp->phys);
+					kfree(mp);
+				}
+			}
+		}
+
+	} while (process_next);
+
+	return (0);
+}
+static int
+lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			    struct lpfc_iocbq *saveq)
+{
+	IOCB_t           * irsp;
+	WORD5            * w5p;
+	uint32_t           Rctl, Type;
+	uint32_t           match, i;
+
+	match = 0;
+	irsp = &(saveq->iocb);
+	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
+	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)) {
+		Rctl = FC_ELS_REQ;
+		Type = FC_ELS_DATA;
+	} else {
+		w5p =
+		    (WORD5 *) & (saveq->iocb.un.
+				 ulpWord[5]);
+		Rctl = w5p->hcsw.Rctl;
+		Type = w5p->hcsw.Type;
+
+		/* Firmware Workaround */
+		if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
+			(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX)) {
+			Rctl = FC_ELS_REQ;
+			Type = FC_ELS_DATA;
+			w5p->hcsw.Rctl = Rctl;
+			w5p->hcsw.Type = Type;
+		}
+	}
+	/* unSolicited Responses */
+	if (pring->prt[0].profile) {
+		(pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring, saveq);
+		match = 1;
+	} else {
+		/* We must search, based on rctl / type
+		   for the right routine */
+		for (i = 0; i < pring->num_mask;
+		     i++) {
+			if ((pring->prt[i].rctl ==
+			     Rctl)
+			    && (pring->prt[i].
+				type == Type)) {
+				(pring->prt[i].lpfc_sli_rcv_unsol_event)
+					(phba, pring, saveq);
+				match = 1;
+				break;
+			}
+		}
+	}
+	if (match == 0) {
+		/* Unexpected Rctl / Type received */
+		/* Ring <ringno> handler: unexpected
+		   Rctl <Rctl> Type <Type> received */
+		lpfc_printf_log(phba,
+				KERN_WARNING,
+				LOG_SLI,
+				"%d:0313 Ring %d handler: unexpected Rctl x%x "
+				"Type x%x received \n",
+				phba->brd_no,
+				pring->ringno,
+				Rctl,
+				Type);
+	}
+	return(1);
+}
+
+static struct lpfc_iocbq *
+lpfc_sli_txcmpl_ring_search_slow(struct lpfc_sli_ring * pring,
+				 struct lpfc_iocbq * prspiocb)
+{
+	IOCB_t *icmd = NULL;
+	IOCB_t *irsp = NULL;
+	struct lpfc_iocbq *cmd_iocb;
+	struct lpfc_iocbq *iocb, *next_iocb;
+	uint16_t iotag;
+
+	irsp = &prspiocb->iocb;
+	iotag = irsp->ulpIoTag;
+	cmd_iocb = NULL;
+
+	/* Search through txcmpl from the begining */
+	list_for_each_entry_safe(iocb, next_iocb, &(pring->txcmplq), list) {
+		icmd = &iocb->iocb;
+		if (iotag == icmd->ulpIoTag) {
+			/* Found a match.  */
+			cmd_iocb = iocb;
+			list_del(&iocb->list);
+			pring->txcmplq_cnt--;
+			break;
+		}
+	}
+
+	return (cmd_iocb);
+}
+
+static struct lpfc_iocbq *
+lpfc_sli_txcmpl_ring_iotag_lookup(struct lpfc_hba * phba,
+			struct lpfc_sli_ring * pring,
+			struct lpfc_iocbq * prspiocb)
+{
+	IOCB_t *irsp = NULL;
+	struct lpfc_iocbq *cmd_iocb = NULL;
+	uint16_t iotag;
+
+	if (unlikely(pring->fast_lookup == NULL))
+		return NULL;
+
+	/* Use fast lookup based on iotag for completion */
+	irsp = &prspiocb->iocb;
+	iotag = irsp->ulpIoTag;
+	if (iotag < pring->fast_iotag) {
+		cmd_iocb = *(pring->fast_lookup + iotag);
+		*(pring->fast_lookup + iotag) = NULL;
+		if (cmd_iocb) {
+			list_del(&cmd_iocb->list);
+			pring->txcmplq_cnt--;
+			return cmd_iocb;
+		} else {
+			/*
+			 * This is clearly an error.  A ring that uses iotags
+			 * should never have a interrupt for a completion that
+			 * is not on the ring.  Return NULL and log a error.
+			 */
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"%d:0327 Rsp ring %d error -  command "
+				"completion for iotag x%x not found\n",
+				phba->brd_no, pring->ringno, iotag);
+			return NULL;
+		}
+	}
+
+	/*
+	 * Rsp ring <ringno> get: iotag <iotag> greater then
+	 * configured max <fast_iotag> wd0 <irsp>.  This is an
+	 * error.  Just return NULL.
+	 */
+	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"%d:0317 Rsp ring %d get: iotag x%x greater then "
+			"configured max x%x wd0 x%x\n",
+			phba->brd_no, pring->ringno, iotag, pring->fast_iotag,
+			*(((uint32_t *) irsp) + 7));
+	return NULL;
+}
+
+static int
+lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
+			  struct lpfc_iocbq *saveq)
+{
+	struct lpfc_iocbq * cmdiocbp;
+	int rc = 1;
+	unsigned long iflag;
+
+	/* Based on the iotag field, get the cmd IOCB from the txcmplq */
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	cmdiocbp = lpfc_sli_txcmpl_ring_search_slow(pring, saveq);
+	if (cmdiocbp) {
+		if (cmdiocbp->iocb_cmpl) {
+			/*
+			 * Post all ELS completions to the worker thread.
+			 * All other are passed to the completion callback.
+			 */
+			if (pring->ringno == LPFC_ELS_RING) {
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       iflag);
+				(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
+				spin_lock_irqsave(phba->host->host_lock, iflag);
+			}
+			else {
+				if (cmdiocbp->iocb_flag & LPFC_IO_POLL)
+					rc = 0;
+
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       iflag);
+				(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
+				spin_lock_irqsave(phba->host->host_lock, iflag);
+			}
+		} else {
+			list_add_tail(&cmdiocbp->list, &phba->lpfc_iocb_list);
+		}
+	} else {
+		/*
+		 * Unknown initiating command based on the response iotag.
+		 * This could be the case on the ELS ring because of
+		 * lpfc_els_abort().
+		 */
+		if (pring->ringno != LPFC_ELS_RING) {
+			/*
+			 * Ring <ringno> handler: unexpected completion IoTag
+			 * <IoTag>
+			 */
+			lpfc_printf_log(phba,
+				KERN_WARNING,
+				LOG_SLI,
+				"%d:0322 Ring %d handler: unexpected "
+				"completion IoTag x%x Data: x%x x%x x%x x%x\n",
+				phba->brd_no,
+				pring->ringno,
+				saveq->iocb.ulpIoTag,
+				saveq->iocb.ulpStatus,
+				saveq->iocb.un.ulpWord[4],
+				saveq->iocb.ulpCommand,
+				saveq->iocb.ulpContext);
+		}
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return rc;
+}
+
+/*
+ * This routine presumes LPFC_FCP_RING handling and doesn't bother
+ * to check it explicitly.
+ */
+static int
+lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
+				struct lpfc_sli_ring * pring, uint32_t mask)
+{
+	IOCB_t *irsp = NULL;
+	struct lpfc_iocbq *cmdiocbq = NULL;
+	struct lpfc_iocbq rspiocbq;
+	PGP *pgp;
+	uint32_t status;
+	uint32_t portRspPut, portRspMax;
+	int rc = 1;
+	lpfc_iocb_type type;
+	unsigned long iflag;
+	uint32_t rsp_cmpl = 0;
+	void __iomem  *to_slim;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	pring->stats.iocb_event++;
+
+	/* The driver assumes SLI-2 mode */
+	pgp = (PGP *) &((MAILBOX_t *) phba->sli.MBhostaddr)
+		->us.s2.port[pring->ringno];
+
+	/*
+	 * The next available response entry should never exceed the maximum
+	 * entries.  If it does, treat it as an adapter hardware error.
+	 */
+	portRspMax = pring->numRiocb;
+	portRspPut = le32_to_cpu(pgp->rspPutInx);
+	if (unlikely(portRspPut >= portRspMax)) {
+		/*
+		 * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
+		 * rsp ring <portRspMax>
+		 */
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"%d:0312 Ring %d handler: portRspPut %d "
+				"is bigger then rsp ring %d\n",
+				phba->brd_no, pring->ringno, portRspPut,
+				portRspMax);
+
+		phba->hba_state = LPFC_HBA_ERROR;
+
+		/* All error attention handlers are posted to worker thread */
+		phba->work_ha |= HA_ERATT;
+		phba->work_hs = HS_FFER3;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+
+		spin_unlock_irqrestore(phba->host->host_lock, iflag);
+		return 1;
+	}
+
+	rmb();
+	while (pring->rspidx != portRspPut) {
+		irsp = (IOCB_t *) IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+		type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
+		pring->stats.iocb_rsp++;
+		rsp_cmpl++;
+
+		if (unlikely(irsp->ulpStatus)) {
+			/* Rsp ring <ringno> error: IOCB */
+			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"%d:0326 Rsp Ring %d error: IOCB Data: "
+				"x%x x%x x%x x%x x%x x%x x%x x%x\n",
+				phba->brd_no, pring->ringno,
+				irsp->un.ulpWord[0], irsp->un.ulpWord[1],
+				irsp->un.ulpWord[2], irsp->un.ulpWord[3],
+				irsp->un.ulpWord[4], irsp->un.ulpWord[5],
+				*(((uint32_t *) irsp) + 6),
+				*(((uint32_t *) irsp) + 7));
+		}
+
+		switch (type) {
+		case LPFC_ABORT_IOCB:
+		case LPFC_SOL_IOCB:
+			/*
+			 * Idle exchange closed via ABTS from port.  No iocb
+			 * resources need to be recovered.
+			 */
+			if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
+				printk(KERN_INFO "%s: IOCB cmd 0x%x processed. "
+				       "Skipping completion\n", __FUNCTION__,
+				       irsp->ulpCommand);
+				break;
+			}
+
+			rspiocbq.iocb.un.ulpWord[4] = irsp->un.ulpWord[4];
+			rspiocbq.iocb.ulpStatus = irsp->ulpStatus;
+			rspiocbq.iocb.ulpContext = irsp->ulpContext;
+			rspiocbq.iocb.ulpIoTag = irsp->ulpIoTag;
+			cmdiocbq = lpfc_sli_txcmpl_ring_iotag_lookup(phba,
+								pring,
+								&rspiocbq);
+			if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
+				spin_unlock_irqrestore(
+				       phba->host->host_lock, iflag);
+				(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
+						      &rspiocbq);
+				spin_lock_irqsave(phba->host->host_lock,
+						  iflag);
+			}
+			break;
+		default:
+			if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
+				char adaptermsg[LPFC_MAX_ADPTMSG];
+				memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
+				memcpy(&adaptermsg[0], (uint8_t *) irsp,
+				       MAX_MSG_DATA);
+				dev_warn(&((phba->pcidev)->dev), "lpfc%d: %s",
+					 phba->brd_no, adaptermsg);
+			} else {
+				/* Unknown IOCB command */
+				lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"%d:0321 Unknown IOCB command "
+					"Data: x%x, x%x x%x x%x x%x\n",
+					phba->brd_no, type, irsp->ulpCommand,
+					irsp->ulpStatus, irsp->ulpIoTag,
+					irsp->ulpContext);
+			}
+			break;
+		}
+
+		/*
+		 * The response IOCB has been processed.  Update the ring
+		 * pointer in SLIM.  If the port response put pointer has not
+		 * been updated, sync the pgp->rspPutInx and fetch the new port
+		 * response put pointer.
+		 */
+		if (++pring->rspidx >= portRspMax)
+			pring->rspidx = 0;
+
+		to_slim = phba->MBslimaddr +
+			(SLIMOFF + (pring->ringno * 2) + 1) * 4;
+		writeb(pring->rspidx, to_slim);
+
+		if (pring->rspidx == portRspPut)
+			portRspPut = le32_to_cpu(pgp->rspPutInx);
+	}
+
+	if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) {
+		pring->stats.iocb_rsp_full++;
+		status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4));
+		writel(status, phba->CAregaddr);
+		readl(phba->CAregaddr);
+	}
+	if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) {
+		pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
+		pring->stats.iocb_cmd_empty++;
+
+		/* Force update of the local copy of cmdGetInx */
+		pring->local_getidx = le32_to_cpu(pgp->cmdGetInx);
+		lpfc_sli_resume_iocb(phba, pring);
+
+		if ((pring->lpfc_sli_cmd_available))
+			(pring->lpfc_sli_cmd_available) (phba, pring);
+
+	}
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return rc;
+}
+
+
+int
+lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
+			   struct lpfc_sli_ring * pring, uint32_t mask)
+{
+	IOCB_t *entry;
+	IOCB_t *irsp = NULL;
+	struct lpfc_iocbq *rspiocbp = NULL;
+	struct lpfc_iocbq *next_iocb;
+	struct lpfc_iocbq *cmdiocbp;
+	struct lpfc_iocbq *saveq;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	HGP *hgp;
+	PGP *pgp;
+	MAILBOX_t *mbox;
+	uint8_t iocb_cmd_type;
+	lpfc_iocb_type type;
+	uint32_t status, free_saveq;
+	uint32_t portRspPut, portRspMax;
+	int rc = 1;
+	unsigned long iflag;
+	void __iomem  *to_slim;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	pring->stats.iocb_event++;
+
+	/* The driver assumes SLI-2 mode */
+	mbox = (MAILBOX_t *) phba->sli.MBhostaddr;
+	pgp = (PGP *) & mbox->us.s2.port[pring->ringno];
+	hgp = (HGP *) & mbox->us.s2.host[pring->ringno];
+
+	/*
+	 * The next available response entry should never exceed the maximum
+	 * entries.  If it does, treat it as an adapter hardware error.
+	 */
+	portRspMax = pring->numRiocb;
+	portRspPut = le32_to_cpu(pgp->rspPutInx);
+	if (portRspPut >= portRspMax) {
+		/*
+		 * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
+		 * rsp ring <portRspMax>
+		 */
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_SLI,
+				"%d:0312 Ring %d handler: portRspPut %d "
+				"is bigger then rsp ring %d\n",
+				phba->brd_no,
+				pring->ringno, portRspPut, portRspMax);
+
+		phba->hba_state = LPFC_HBA_ERROR;
+		spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+		phba->work_hs = HS_FFER3;
+		lpfc_handle_eratt(phba);
+
+		return 1;
+	}
+
+	rmb();
+	lpfc_iocb_list = &phba->lpfc_iocb_list;
+	while (pring->rspidx != portRspPut) {
+		/*
+		 * Build a completion list and call the appropriate handler.
+		 * The process is to get the next available response iocb, get
+		 * a free iocb from the list, copy the response data into the
+		 * free iocb, insert to the continuation list, and update the
+		 * next response index to slim.  This process makes response
+		 * iocb's in the ring available to DMA as fast as possible but
+		 * pays a penalty for a copy operation.  Since the iocb is
+		 * only 32 bytes, this penalty is considered small relative to
+		 * the PCI reads for register values and a slim write.  When
+		 * the ulpLe field is set, the entire Command has been
+		 * received.
+		 */
+		entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+		list_remove_head(lpfc_iocb_list, rspiocbp, struct lpfc_iocbq,
+				 list);
+		if (rspiocbp == NULL) {
+			printk(KERN_ERR "%s: out of buffers! Failing "
+			       "completion.\n", __FUNCTION__);
+			break;
+		}
+
+		lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof (IOCB_t));
+		irsp = &rspiocbp->iocb;
+
+		if (++pring->rspidx >= portRspMax)
+			pring->rspidx = 0;
+
+		to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2)
+					      + 1) * 4;
+		writeb(pring->rspidx, to_slim);
+
+		if (list_empty(&(pring->iocb_continueq))) {
+			list_add(&rspiocbp->list, &(pring->iocb_continueq));
+		} else {
+			list_add_tail(&rspiocbp->list,
+				      &(pring->iocb_continueq));
+		}
+
+		pring->iocb_continueq_cnt++;
+		if (irsp->ulpLe) {
+			/*
+			 * By default, the driver expects to free all resources
+			 * associated with this iocb completion.
+			 */
+			free_saveq = 1;
+			saveq = list_get_first(&pring->iocb_continueq,
+					       struct lpfc_iocbq, list);
+			irsp = &(saveq->iocb);
+			list_del_init(&pring->iocb_continueq);
+			pring->iocb_continueq_cnt = 0;
+
+			pring->stats.iocb_rsp++;
+
+			if (irsp->ulpStatus) {
+				/* Rsp ring <ringno> error: IOCB */
+				lpfc_printf_log(phba,
+					KERN_WARNING,
+					LOG_SLI,
+					"%d:0328 Rsp Ring %d error: IOCB Data: "
+					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
+					phba->brd_no,
+					pring->ringno,
+					irsp->un.ulpWord[0],
+					irsp->un.ulpWord[1],
+					irsp->un.ulpWord[2],
+					irsp->un.ulpWord[3],
+					irsp->un.ulpWord[4],
+					irsp->un.ulpWord[5],
+					*(((uint32_t *) irsp) + 6),
+					*(((uint32_t *) irsp) + 7));
+			}
+
+			/*
+			 * Fetch the IOCB command type and call the correct
+			 * completion routine.  Solicited and Unsolicited
+			 * IOCBs on the ELS ring get freed back to the
+			 * lpfc_iocb_list by the discovery kernel thread.
+			 */
+			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
+			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
+			if (type == LPFC_SOL_IOCB) {
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       iflag);
+				rc = lpfc_sli_process_sol_iocb(phba, pring,
+					saveq);
+				spin_lock_irqsave(phba->host->host_lock, iflag);
+			} else if (type == LPFC_UNSOL_IOCB) {
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       iflag);
+				rc = lpfc_sli_process_unsol_iocb(phba, pring,
+					saveq);
+				spin_lock_irqsave(phba->host->host_lock, iflag);
+			} else if (type == LPFC_ABORT_IOCB) {
+				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
+				    ((cmdiocbp =
+				      lpfc_sli_txcmpl_ring_search_slow(pring,
+						saveq)))) {
+					/* Call the specified completion
+					   routine */
+					if (cmdiocbp->iocb_cmpl) {
+						spin_unlock_irqrestore(
+						       phba->host->host_lock,
+						       iflag);
+						(cmdiocbp->iocb_cmpl) (phba,
+							     cmdiocbp, saveq);
+						spin_lock_irqsave(
+							  phba->host->host_lock,
+							  iflag);
+					} else {
+						list_add_tail(&cmdiocbp->list,
+								lpfc_iocb_list);
+					}
+				}
+			} else if (type == LPFC_UNKNOWN_IOCB) {
+				if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
+
+					char adaptermsg[LPFC_MAX_ADPTMSG];
+
+					memset(adaptermsg, 0,
+					       LPFC_MAX_ADPTMSG);
+					memcpy(&adaptermsg[0], (uint8_t *) irsp,
+					       MAX_MSG_DATA);
+					dev_warn(&((phba->pcidev)->dev),
+						 "lpfc%d: %s",
+						 phba->brd_no, adaptermsg);
+				} else {
+					/* Unknown IOCB command */
+					lpfc_printf_log(phba,
+						KERN_ERR,
+						LOG_SLI,
+						"%d:0321 Unknown IOCB command "
+						"Data: x%x x%x x%x x%x\n",
+						phba->brd_no,
+						irsp->ulpCommand,
+						irsp->ulpStatus,
+						irsp->ulpIoTag,
+						irsp->ulpContext);
+				}
+			}
+
+			if (free_saveq) {
+				if (!list_empty(&saveq->list)) {
+					list_for_each_entry_safe(rspiocbp,
+								 next_iocb,
+								 &saveq->list,
+								 list) {
+						list_add_tail(&rspiocbp->list,
+							      lpfc_iocb_list);
+					}
+				}
+
+				list_add_tail(&saveq->list, lpfc_iocb_list);
+			}
+		}
+
+		/*
+		 * If the port response put pointer has not been updated, sync
+		 * the pgp->rspPutInx in the MAILBOX_tand fetch the new port
+		 * response put pointer.
+		 */
+		if (pring->rspidx == portRspPut) {
+			portRspPut = le32_to_cpu(pgp->rspPutInx);
+		}
+	} /* while (pring->rspidx != portRspPut) */
+
+	if ((rspiocbp != 0) && (mask & HA_R0RE_REQ)) {
+		/* At least one response entry has been freed */
+		pring->stats.iocb_rsp_full++;
+		/* SET RxRE_RSP in Chip Att register */
+		status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4));
+		writel(status, phba->CAregaddr);
+		readl(phba->CAregaddr); /* flush */
+	}
+	if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) {
+		pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
+		pring->stats.iocb_cmd_empty++;
+
+		/* Force update of the local copy of cmdGetInx */
+		pring->local_getidx = le32_to_cpu(pgp->cmdGetInx);
+		lpfc_sli_resume_iocb(phba, pring);
+
+		if ((pring->lpfc_sli_cmd_available))
+			(pring->lpfc_sli_cmd_available) (phba, pring);
+
+	}
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+	return rc;
+}
+
+int
+lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+	struct lpfc_iocbq *iocb, *next_iocb;
+	IOCB_t *icmd = NULL, *cmd = NULL;
+	int errcnt;
+	uint16_t iotag;
+
+	errcnt = 0;
+
+	/* Error everything on txq and txcmplq
+	 * First do the txq.
+	 */
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+		list_del_init(&iocb->list);
+		if (iocb->iocb_cmpl) {
+			icmd = &iocb->iocb;
+			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			spin_unlock_irq(phba->host->host_lock);
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+			spin_lock_irq(phba->host->host_lock);
+		} else {
+			list_add_tail(&iocb->list, &phba->lpfc_iocb_list);
+		}
+	}
+	pring->txq_cnt = 0;
+	INIT_LIST_HEAD(&(pring->txq));
+
+	/* Next issue ABTS for everything on the txcmplq */
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		cmd = &iocb->iocb;
+
+		/*
+		 * Imediate abort of IOCB, clear fast_lookup entry,
+		 * if any, deque and call compl
+		 */
+		iotag = cmd->ulpIoTag;
+		if (iotag && pring->fast_lookup &&
+		    (iotag < pring->fast_iotag))
+			pring->fast_lookup[iotag] = NULL;
+
+		list_del_init(&iocb->list);
+		pring->txcmplq_cnt--;
+
+		if (iocb->iocb_cmpl) {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			spin_unlock_irq(phba->host->host_lock);
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+			spin_lock_irq(phba->host->host_lock);
+		} else {
+			list_add_tail(&iocb->list, &phba->lpfc_iocb_list);
+		}
+	}
+
+	INIT_LIST_HEAD(&pring->txcmplq);
+	pring->txcmplq_cnt = 0;
+	spin_unlock_irq(phba->host->host_lock);
+
+	return errcnt;
+}
+
+/******************************************************************************
+* lpfc_sli_send_reset
+*
+* Note: After returning from this function, the HBA cannot be accessed for
+* 1 ms. Since we do not wish to delay in interrupt context, it is the
+* responsibility of the caller to perform the mdelay(1) and flush via readl().
+******************************************************************************/
+static int
+lpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post)
+{
+	MAILBOX_t *swpmb;
+	volatile uint32_t word0;
+	void __iomem *to_slim;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(phba->host->host_lock, flags);
+
+	/* A board reset must use REAL SLIM. */
+	phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+
+	word0 = 0;
+	swpmb = (MAILBOX_t *) & word0;
+	swpmb->mbxCommand = MBX_RESTART;
+	swpmb->mbxHc = 1;
+
+	to_slim = phba->MBslimaddr;
+	writel(*(uint32_t *) swpmb, to_slim);
+	readl(to_slim); /* flush */
+
+	/* Only skip post after fc_ffinit is completed */
+	if (skip_post) {
+		word0 = 1;	/* This is really setting up word1 */
+	} else {
+		word0 = 0;	/* This is really setting up word1 */
+	}
+	to_slim = phba->MBslimaddr + sizeof (uint32_t);
+	writel(*(uint32_t *) swpmb, to_slim);
+	readl(to_slim); /* flush */
+
+	/* Turn off parity checking and serr during the physical reset */
+	pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value);
+	pci_write_config_word(phba->pcidev, PCI_COMMAND,
+			      (phba->pci_cfg_value &
+			       ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
+	writel(HC_INITFF, phba->HCregaddr);
+
+	phba->hba_state = LPFC_INIT_START;
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+
+	return 0;
+}
+
+static int
+lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post)
+{
+	struct lpfc_sli_ring *pring;
+	int i;
+	struct lpfc_dmabuf *mp, *next_mp;
+	unsigned long flags = 0;
+
+	lpfc_sli_send_reset(phba, skip_post);
+	mdelay(1);
+
+	spin_lock_irqsave(phba->host->host_lock, flags);
+	/* Risk the write on flush case ie no delay after the readl */
+	readl(phba->HCregaddr); /* flush */
+	/* Now toggle INITFF bit set by lpfc_sli_send_reset */
+	writel(0, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+
+	/* Restore PCI cmd register */
+	pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value);
+
+	/* perform board reset */
+	phba->fc_eventTag = 0;
+	phba->fc_myDID = 0;
+	phba->fc_prevDID = Mask_DID;
+
+	/* Reset HBA */
+	lpfc_printf_log(phba,
+		KERN_INFO,
+		LOG_SLI,
+		"%d:0325 Reset HBA Data: x%x x%x x%x\n",
+		phba->brd_no,
+		phba->hba_state,
+		phba->sli.sli_flag,
+		skip_post);
+
+	/* Initialize relevant SLI info */
+	for (i = 0; i < phba->sli.num_rings; i++) {
+		pring = &phba->sli.ring[i];
+		pring->flag = 0;
+		pring->rspidx = 0;
+		pring->next_cmdidx  = 0;
+		pring->local_getidx = 0;
+		pring->cmdidx = 0;
+		pring->missbufcnt = 0;
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+
+	if (skip_post) {
+		mdelay(100);
+	} else {
+		mdelay(2000);
+	}
+
+	spin_lock_irqsave(phba->host->host_lock, flags);
+	/* Cleanup preposted buffers on the ELS ring */
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+		list_del(&mp->list);
+		pring->postbufq_cnt--;
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+
+	for (i = 0; i < phba->sli.num_rings; i++)
+		lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]);
+
+	return 0;
+}
+
+static int
+lpfc_sli_chipset_init(struct lpfc_hba *phba)
+{
+	uint32_t status, i = 0;
+
+	/* Read the HBA Host Status Register */
+	status = readl(phba->HSregaddr);
+
+	/* Check status register to see what current state is */
+	i = 0;
+	while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) {
+
+		/* Check every 100ms for 5 retries, then every 500ms for 5, then
+		 * every 2.5 sec for 5, then reset board and every 2.5 sec for
+		 * 4.
+		 */
+		if (i++ >= 20) {
+			/* Adapter failed to init, timeout, status reg
+			   <status> */
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_INIT,
+					"%d:0436 Adapter failed to init, "
+					"timeout, status reg x%x\n",
+					phba->brd_no,
+					status);
+			phba->hba_state = LPFC_HBA_ERROR;
+			return -ETIMEDOUT;
+		}
+
+		/* Check to see if any errors occurred during init */
+		if (status & HS_FFERM) {
+			/* ERROR: During chipset initialization */
+			/* Adapter failed to init, chipset, status reg
+			   <status> */
+			lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_INIT,
+					"%d:0437 Adapter failed to init, "
+					"chipset, status reg x%x\n",
+					phba->brd_no,
+					status);
+			phba->hba_state = LPFC_HBA_ERROR;
+			return -EIO;
+		}
+
+		if (i <= 5) {
+			msleep(10);
+		} else if (i <= 10) {
+			msleep(500);
+		} else {
+			msleep(2500);
+		}
+
+		if (i == 15) {
+			lpfc_sli_brdreset(phba, 0);
+		}
+		/* Read the HBA Host Status Register */
+		status = readl(phba->HSregaddr);
+	}
+
+	/* Check to see if any errors occurred during init */
+	if (status & HS_FFERM) {
+		/* ERROR: During chipset initialization */
+		/* Adapter failed to init, chipset, status reg <status> */
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"%d:0438 Adapter failed to init, chipset, "
+				"status reg x%x\n",
+				phba->brd_no,
+				status);
+		phba->hba_state = LPFC_HBA_ERROR;
+		return -EIO;
+	}
+
+	/* Clear all interrupt enable conditions */
+	writel(0, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+
+	/* setup host attn register */
+	writel(0xffffffff, phba->HAregaddr);
+	readl(phba->HAregaddr); /* flush */
+	return 0;
+}
+
+int
+lpfc_sli_hba_setup(struct lpfc_hba * phba)
+{
+	LPFC_MBOXQ_t *pmb;
+	uint32_t resetcount = 0, rc = 0, done = 0;
+
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		phba->hba_state = LPFC_HBA_ERROR;
+		return -ENOMEM;
+	}
+
+	while (resetcount < 2 && !done) {
+		phba->hba_state = 0;
+		lpfc_sli_brdreset(phba, 0);
+		msleep(2500);
+		rc = lpfc_sli_chipset_init(phba);
+		if (rc)
+			break;
+
+		resetcount++;
+
+	/* Call pre CONFIG_PORT mailbox command initialization.  A value of 0
+	 * means the call was successful.  Any other nonzero value is a failure,
+	 * but if ERESTART is returned, the driver may reset the HBA and try
+	 * again.
+	 */
+		rc = lpfc_config_port_prep(phba);
+		if (rc == -ERESTART) {
+			phba->hba_state = 0;
+			continue;
+		} else if (rc) {
+			break;
+		}
+
+		phba->hba_state = LPFC_INIT_MBX_CMDS;
+		lpfc_config_port(phba, pmb);
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+		if (rc == MBX_SUCCESS)
+			done = 1;
+		else {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0442 Adapter failed to init, mbxCmd x%x "
+				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
+				phba->brd_no, pmb->mb.mbxCommand,
+				pmb->mb.mbxStatus, 0);
+			phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+		}
+	}
+	if (!done)
+		goto lpfc_sli_hba_setup_error;
+
+	rc = lpfc_sli_ring_map(phba, pmb);
+
+	if (rc)
+		goto lpfc_sli_hba_setup_error;
+
+	phba->sli.sli_flag |= LPFC_PROCESS_LA;
+
+	rc = lpfc_config_port_post(phba);
+	if (rc)
+		goto lpfc_sli_hba_setup_error;
+
+	goto lpfc_sli_hba_setup_exit;
+lpfc_sli_hba_setup_error:
+	phba->hba_state = LPFC_HBA_ERROR;
+lpfc_sli_hba_setup_exit:
+	mempool_free(pmb, phba->mbox_mem_pool);
+	return rc;
+}
+
+static void
+lpfc_mbox_abort(struct lpfc_hba * phba)
+{
+	LPFC_MBOXQ_t *pmbox;
+	MAILBOX_t *mb;
+
+	if (phba->sli.mbox_active) {
+		del_timer_sync(&phba->sli.mbox_tmo);
+		phba->work_hba_events &= ~WORKER_MBOX_TMO;
+		pmbox = phba->sli.mbox_active;
+		mb = &pmbox->mb;
+		phba->sli.mbox_active = NULL;
+		if (pmbox->mbox_cmpl) {
+			mb->mbxStatus = MBX_NOT_FINISHED;
+			(pmbox->mbox_cmpl) (phba, pmbox);
+		}
+		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	}
+
+	/* Abort all the non active mailbox commands. */
+	spin_lock_irq(phba->host->host_lock);
+	pmbox = lpfc_mbox_get(phba);
+	while (pmbox) {
+		mb = &pmbox->mb;
+		if (pmbox->mbox_cmpl) {
+			mb->mbxStatus = MBX_NOT_FINISHED;
+			spin_unlock_irq(phba->host->host_lock);
+			(pmbox->mbox_cmpl) (phba, pmbox);
+			spin_lock_irq(phba->host->host_lock);
+		}
+		pmbox = lpfc_mbox_get(phba);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return;
+}
+
+/*! lpfc_mbox_timeout
+ *
+ * \pre
+ * \post
+ * \param hba Pointer to per struct lpfc_hba structure
+ * \param l1  Pointer to the driver's mailbox queue.
+ * \return
+ *   void
+ *
+ * \b Description:
+ *
+ * This routine handles mailbox timeout events at timer interrupt context.
+ */
+void
+lpfc_mbox_timeout(unsigned long ptr)
+{
+	struct lpfc_hba *phba;
+	unsigned long iflag;
+
+	phba = (struct lpfc_hba *)ptr;
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
+		phba->work_hba_events |= WORKER_MBOX_TMO;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+	}
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *pmbox;
+	MAILBOX_t *mb;
+
+	spin_lock_irq(phba->host->host_lock);
+	if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
+		spin_unlock_irq(phba->host->host_lock);
+		return;
+	}
+
+	pmbox = phba->sli.mbox_active;
+	mb = &pmbox->mb;
+
+	/* Mbox cmd <mbxCommand> timeout */
+	lpfc_printf_log(phba,
+		KERN_ERR,
+		LOG_MBOX | LOG_SLI,
+		"%d:0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
+		phba->brd_no,
+		mb->mbxCommand,
+		phba->hba_state,
+		phba->sli.sli_flag,
+		phba->sli.mbox_active);
+
+	if (phba->sli.mbox_active == pmbox) {
+		phba->sli.mbox_active = NULL;
+		if (pmbox->mbox_cmpl) {
+			mb->mbxStatus = MBX_NOT_FINISHED;
+			spin_unlock_irq(phba->host->host_lock);
+			(pmbox->mbox_cmpl) (phba, pmbox);
+			spin_lock_irq(phba->host->host_lock);
+		}
+		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	}
+
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_mbox_abort(phba);
+	return;
+}
+
+int
+lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
+{
+	MAILBOX_t *mbox;
+	MAILBOX_t *mb;
+	struct lpfc_sli *psli;
+	uint32_t status, evtctr;
+	uint32_t ha_copy;
+	int i;
+	unsigned long drvr_flag = 0;
+	volatile uint32_t word0, ldata;
+	void __iomem *to_slim;
+
+	psli = &phba->sli;
+
+	spin_lock_irqsave(phba->host->host_lock, drvr_flag);
+
+
+	mb = &pmbox->mb;
+	status = MBX_SUCCESS;
+
+	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+		/* Polling for a mbox command when another one is already active
+		 * is not allowed in SLI. Also, the driver must have established
+		 * SLI2 mode to queue and process multiple mbox commands.
+		 */
+
+		if (flag & MBX_POLL) {
+			spin_unlock_irqrestore(phba->host->host_lock,
+					       drvr_flag);
+
+			/* Mbox command <mbxCommand> cannot issue */
+			LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
+			return (MBX_NOT_FINISHED);
+		}
+
+		if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
+			spin_unlock_irqrestore(phba->host->host_lock,
+					       drvr_flag);
+			/* Mbox command <mbxCommand> cannot issue */
+			LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
+			return (MBX_NOT_FINISHED);
+		}
+
+		/* Handle STOP IOCB processing flag. This is only meaningful
+		 * if we are not polling for mbox completion.
+		 */
+		if (flag & MBX_STOP_IOCB) {
+			flag &= ~MBX_STOP_IOCB;
+			/* Now flag each ring */
+			for (i = 0; i < psli->num_rings; i++) {
+				/* If the ring is active, flag it */
+				if (psli->ring[i].cmdringaddr) {
+					psli->ring[i].flag |=
+					    LPFC_STOP_IOCB_MBX;
+				}
+			}
+		}
+
+		/* Another mailbox command is still being processed, queue this
+		 * command to be processed later.
+		 */
+		lpfc_mbox_put(phba, pmbox);
+
+		/* Mbox cmd issue - BUSY */
+		lpfc_printf_log(phba,
+			KERN_INFO,
+			LOG_MBOX | LOG_SLI,
+			"%d:0308 Mbox cmd issue - BUSY Data: x%x x%x x%x x%x\n",
+			phba->brd_no,
+			mb->mbxCommand,
+			phba->hba_state,
+			psli->sli_flag,
+			flag);
+
+		psli->slistat.mbox_busy++;
+		spin_unlock_irqrestore(phba->host->host_lock,
+				       drvr_flag);
+
+		return (MBX_BUSY);
+	}
+
+	/* Handle STOP IOCB processing flag. This is only meaningful
+	 * if we are not polling for mbox completion.
+	 */
+	if (flag & MBX_STOP_IOCB) {
+		flag &= ~MBX_STOP_IOCB;
+		if (flag == MBX_NOWAIT) {
+			/* Now flag each ring */
+			for (i = 0; i < psli->num_rings; i++) {
+				/* If the ring is active, flag it */
+				if (psli->ring[i].cmdringaddr) {
+					psli->ring[i].flag |=
+					    LPFC_STOP_IOCB_MBX;
+				}
+			}
+		}
+	}
+
+	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+
+	/* If we are not polling, we MUST be in SLI2 mode */
+	if (flag != MBX_POLL) {
+		if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
+			psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+			spin_unlock_irqrestore(phba->host->host_lock,
+					       drvr_flag);
+			/* Mbox command <mbxCommand> cannot issue */
+			LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag);
+			return (MBX_NOT_FINISHED);
+		}
+		/* timeout active mbox command */
+		mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO);
+	}
+
+	/* Mailbox cmd <cmd> issue */
+	lpfc_printf_log(phba,
+		KERN_INFO,
+		LOG_MBOX | LOG_SLI,
+		"%d:0309 Mailbox cmd x%x issue Data: x%x x%x x%x\n",
+		phba->brd_no,
+		mb->mbxCommand,
+		phba->hba_state,
+		psli->sli_flag,
+		flag);
+
+	psli->slistat.mbox_cmd++;
+	evtctr = psli->slistat.mbox_event;
+
+	/* next set own bit for the adapter and copy over command word */
+	mb->mbxOwner = OWN_CHIP;
+
+	if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+
+		/* First copy command data to host SLIM area */
+		mbox = (MAILBOX_t *) psli->MBhostaddr;
+		lpfc_sli_pcimem_bcopy(mb, mbox, MAILBOX_CMD_SIZE);
+	} else {
+		if (mb->mbxCommand == MBX_CONFIG_PORT) {
+			/* copy command data into host mbox for cmpl */
+			mbox = (MAILBOX_t *) psli->MBhostaddr;
+			lpfc_sli_pcimem_bcopy(mb, mbox, MAILBOX_CMD_SIZE);
+		}
+
+		/* First copy mbox command data to HBA SLIM, skip past first
+		   word */
+		to_slim = phba->MBslimaddr + sizeof (uint32_t);
+		lpfc_memcpy_to_slim(to_slim, &mb->un.varWords[0],
+			    MAILBOX_CMD_SIZE - sizeof (uint32_t));
+
+		/* Next copy over first word, with mbxOwner set */
+		ldata = *((volatile uint32_t *)mb);
+		to_slim = phba->MBslimaddr;
+		writel(ldata, to_slim);
+		readl(to_slim); /* flush */
+
+		if (mb->mbxCommand == MBX_CONFIG_PORT) {
+			/* switch over to host mailbox */
+			psli->sli_flag |= LPFC_SLI2_ACTIVE;
+		}
+	}
+
+	wmb();
+	/* interrupt board to doit right away */
+	writel(CA_MBATT, phba->CAregaddr);
+	readl(phba->CAregaddr); /* flush */
+
+	switch (flag) {
+	case MBX_NOWAIT:
+		/* Don't wait for it to finish, just return */
+		psli->mbox_active = pmbox;
+		break;
+
+	case MBX_POLL:
+		i = 0;
+		psli->mbox_active = NULL;
+		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+			/* First read mbox status word */
+			mbox = (MAILBOX_t *) psli->MBhostaddr;
+			word0 = *((volatile uint32_t *)mbox);
+			word0 = le32_to_cpu(word0);
+		} else {
+			/* First read mbox status word */
+			word0 = readl(phba->MBslimaddr);
+		}
+
+		/* Read the HBA Host Attention Register */
+		ha_copy = readl(phba->HAregaddr);
+
+		/* Wait for command to complete */
+		while (((word0 & OWN_CHIP) == OWN_CHIP)
+		       || !(ha_copy & HA_MBATT)) {
+			if (i++ >= 100) {
+				psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       drvr_flag);
+				return (MBX_NOT_FINISHED);
+			}
+
+			/* Check if we took a mbox interrupt while we were
+			   polling */
+			if (((word0 & OWN_CHIP) != OWN_CHIP)
+			    && (evtctr != psli->slistat.mbox_event))
+				break;
+
+			spin_unlock_irqrestore(phba->host->host_lock,
+					       drvr_flag);
+
+			/* Can be in interrupt context, do not sleep */
+			/* (or might be called with interrupts disabled) */
+			mdelay(i);
+
+			spin_lock_irqsave(phba->host->host_lock, drvr_flag);
+
+			if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+				/* First copy command data */
+				mbox = (MAILBOX_t *) psli->MBhostaddr;
+				word0 = *((volatile uint32_t *)mbox);
+				word0 = le32_to_cpu(word0);
+				if (mb->mbxCommand == MBX_CONFIG_PORT) {
+					MAILBOX_t *slimmb;
+					volatile uint32_t slimword0;
+					/* Check real SLIM for any errors */
+					slimword0 = readl(phba->MBslimaddr);
+					slimmb = (MAILBOX_t *) & slimword0;
+					if (((slimword0 & OWN_CHIP) != OWN_CHIP)
+					    && slimmb->mbxStatus) {
+						psli->sli_flag &=
+						    ~LPFC_SLI2_ACTIVE;
+						word0 = slimword0;
+					}
+				}
+			} else {
+				/* First copy command data */
+				word0 = readl(phba->MBslimaddr);
+			}
+			/* Read the HBA Host Attention Register */
+			ha_copy = readl(phba->HAregaddr);
+		}
+
+		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+			/* First copy command data */
+			mbox = (MAILBOX_t *) psli->MBhostaddr;
+			/* copy results back to user */
+			lpfc_sli_pcimem_bcopy(mbox, mb, MAILBOX_CMD_SIZE);
+		} else {
+			/* First copy command data */
+			lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
+							MAILBOX_CMD_SIZE);
+			if ((mb->mbxCommand == MBX_DUMP_MEMORY) &&
+				pmbox->context2) {
+				lpfc_memcpy_from_slim((void *)pmbox->context2,
+				      phba->MBslimaddr + DMP_RSP_OFFSET,
+						      mb->un.varDmp.word_cnt);
+			}
+		}
+
+		writel(HA_MBATT, phba->HAregaddr);
+		readl(phba->HAregaddr); /* flush */
+
+		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+		status = mb->mbxStatus;
+	}
+
+	spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
+	return (status);
+}
+
+static int
+lpfc_sli_ringtx_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
+		    struct lpfc_iocbq * piocb)
+{
+	/* Insert the caller's iocb in the txq tail for later processing. */
+	list_add_tail(&piocb->list, &pring->txq);
+	pring->txq_cnt++;
+	return (0);
+}
+
+static struct lpfc_iocbq *
+lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		   struct lpfc_iocbq ** piocb)
+{
+	struct lpfc_iocbq * nextiocb;
+
+	nextiocb = lpfc_sli_ringtx_get(phba, pring);
+	if (!nextiocb) {
+		nextiocb = *piocb;
+		*piocb = NULL;
+	}
+
+	return nextiocb;
+}
+
+int
+lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		    struct lpfc_iocbq *piocb, uint32_t flag)
+{
+	struct lpfc_iocbq *nextiocb;
+	IOCB_t *iocb;
+
+	/*
+	 * We should never get an IOCB if we are in a < LINK_DOWN state
+	 */
+	if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+		return IOCB_ERROR;
+
+	/*
+	 * Check to see if we are blocking IOCB processing because of a
+	 * outstanding mbox command.
+	 */
+	if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
+		goto iocb_busy;
+
+	if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
+		/*
+		 * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+		 * can be issued if the link is not up.
+		 */
+		switch (piocb->iocb.ulpCommand) {
+		case CMD_QUE_RING_BUF_CN:
+		case CMD_QUE_RING_BUF64_CN:
+		case CMD_CLOSE_XRI_CN:
+		case CMD_ABORT_XRI_CN:
+			/*
+			 * For IOCBs, like QUE_RING_BUF, that have no rsp ring
+			 * completion, iocb_cmpl MUST be 0.
+			 */
+			if (piocb->iocb_cmpl)
+				piocb->iocb_cmpl = NULL;
+			/*FALLTHROUGH*/
+		case CMD_CREATE_XRI_CR:
+			break;
+		default:
+			goto iocb_busy;
+		}
+
+	/*
+	 * For FCP commands, we must be in a state where we can process link
+	 * attention events.
+	 */
+	} else if (unlikely(pring->ringno == phba->sli.fcp_ring &&
+		   !(phba->sli.sli_flag & LPFC_PROCESS_LA)))
+		goto iocb_busy;
+
+	/*
+	 * Check to see if this is a high priority command.
+	 * If so bypass tx queue processing.
+	 */
+	if (unlikely((flag & SLI_IOCB_HIGH_PRIORITY) &&
+		     (iocb = lpfc_sli_next_iocb_slot(phba, pring)))) {
+		lpfc_sli_submit_iocb(phba, pring, iocb, piocb);
+		piocb = NULL;
+	}
+
+	while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
+	       (nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb)))
+		lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
+
+	if (iocb)
+		lpfc_sli_update_ring(phba, pring);
+	else
+		lpfc_sli_update_full_ring(phba, pring);
+
+	if (!piocb)
+		return IOCB_SUCCESS;
+
+	goto out_busy;
+
+ iocb_busy:
+	pring->stats.iocb_cmd_delay++;
+
+ out_busy:
+
+	if (!(flag & SLI_IOCB_RET_IOCB)) {
+		lpfc_sli_ringtx_put(phba, pring, piocb);
+		return IOCB_SUCCESS;
+	}
+
+	return IOCB_BUSY;
+}
+
+int
+lpfc_sli_setup(struct lpfc_hba *phba)
+{
+	int i, totiocb = 0;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring *pring;
+
+	psli->num_rings = MAX_CONFIGURED_RINGS;
+	psli->sli_flag = 0;
+	psli->fcp_ring = LPFC_FCP_RING;
+	psli->next_ring = LPFC_FCP_NEXT_RING;
+	psli->ip_ring = LPFC_IP_RING;
+
+	for (i = 0; i < psli->num_rings; i++) {
+		pring = &psli->ring[i];
+		switch (i) {
+		case LPFC_FCP_RING:	/* ring 0 - FCP */
+			/* numCiocb and numRiocb are used in config_port */
+			pring->numCiocb = SLI2_IOCB_CMD_R0_ENTRIES;
+			pring->numRiocb = SLI2_IOCB_RSP_R0_ENTRIES;
+			pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
+			pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
+			pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
+			pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+			pring->iotag_ctr = 0;
+			pring->iotag_max =
+			    (phba->cfg_hba_queue_depth * 2);
+			pring->fast_iotag = pring->iotag_max;
+			pring->num_mask = 0;
+			break;
+		case LPFC_IP_RING:	/* ring 1 - IP */
+			/* numCiocb and numRiocb are used in config_port */
+			pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
+			pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
+			pring->num_mask = 0;
+			break;
+		case LPFC_ELS_RING:	/* ring 2 - ELS / CT */
+			/* numCiocb and numRiocb are used in config_port */
+			pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES;
+			pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES;
+			pring->fast_iotag = 0;
+			pring->iotag_ctr = 0;
+			pring->iotag_max = 4096;
+			pring->num_mask = 4;
+			pring->prt[0].profile = 0;	/* Mask 0 */
+			pring->prt[0].rctl = FC_ELS_REQ;
+			pring->prt[0].type = FC_ELS_DATA;
+			pring->prt[0].lpfc_sli_rcv_unsol_event =
+			    lpfc_els_unsol_event;
+			pring->prt[1].profile = 0;	/* Mask 1 */
+			pring->prt[1].rctl = FC_ELS_RSP;
+			pring->prt[1].type = FC_ELS_DATA;
+			pring->prt[1].lpfc_sli_rcv_unsol_event =
+			    lpfc_els_unsol_event;
+			pring->prt[2].profile = 0;	/* Mask 2 */
+			/* NameServer Inquiry */
+			pring->prt[2].rctl = FC_UNSOL_CTL;
+			/* NameServer */
+			pring->prt[2].type = FC_COMMON_TRANSPORT_ULP;
+			pring->prt[2].lpfc_sli_rcv_unsol_event =
+			    lpfc_ct_unsol_event;
+			pring->prt[3].profile = 0;	/* Mask 3 */
+			/* NameServer response */
+			pring->prt[3].rctl = FC_SOL_CTL;
+			/* NameServer */
+			pring->prt[3].type = FC_COMMON_TRANSPORT_ULP;
+			pring->prt[3].lpfc_sli_rcv_unsol_event =
+			    lpfc_ct_unsol_event;
+			break;
+		}
+		totiocb += (pring->numCiocb + pring->numRiocb);
+	}
+	if (totiocb > MAX_SLI2_IOCB) {
+		/* Too many cmd / rsp ring entries in SLI2 SLIM */
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0462 Too many cmd / rsp ring entries in "
+				"SLI2 SLIM Data: x%x x%x\n",
+				phba->brd_no, totiocb, MAX_SLI2_IOCB);
+	}
+
+	return 0;
+}
+
+int
+lpfc_sli_queue_setup(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_sli_ring *pring;
+	int i, cnt;
+
+	psli = &phba->sli;
+	spin_lock_irq(phba->host->host_lock);
+	INIT_LIST_HEAD(&psli->mboxq);
+	/* Initialize list headers for txq and txcmplq as double linked lists */
+	for (i = 0; i < psli->num_rings; i++) {
+		pring = &psli->ring[i];
+		pring->ringno = i;
+		pring->next_cmdidx  = 0;
+		pring->local_getidx = 0;
+		pring->cmdidx = 0;
+		INIT_LIST_HEAD(&pring->txq);
+		INIT_LIST_HEAD(&pring->txcmplq);
+		INIT_LIST_HEAD(&pring->iocb_continueq);
+		INIT_LIST_HEAD(&pring->postbufq);
+		cnt = pring->fast_iotag;
+		spin_unlock_irq(phba->host->host_lock);
+		if (cnt) {
+			pring->fast_lookup =
+				kmalloc(cnt * sizeof (struct lpfc_iocbq *),
+					GFP_KERNEL);
+			if (pring->fast_lookup == 0) {
+				return (0);
+			}
+			memset((char *)pring->fast_lookup, 0,
+			       cnt * sizeof (struct lpfc_iocbq *));
+		}
+		spin_lock_irq(phba->host->host_lock);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+	return (1);
+}
+
+int
+lpfc_sli_hba_down(struct lpfc_hba * phba)
+{
+	struct lpfc_sli *psli;
+	struct lpfc_sli_ring *pring;
+	LPFC_MBOXQ_t *pmb;
+	struct lpfc_iocbq *iocb, *next_iocb;
+	IOCB_t *icmd = NULL;
+	int i;
+	unsigned long flags = 0;
+
+	psli = &phba->sli;
+	lpfc_hba_down_prep(phba);
+
+	spin_lock_irqsave(phba->host->host_lock, flags);
+
+	for (i = 0; i < psli->num_rings; i++) {
+		pring = &psli->ring[i];
+		pring->flag |= LPFC_DEFERRED_RING_EVENT;
+
+		/*
+		 * Error everything on the txq since these iocbs have not been
+		 * given to the FW yet.
+		 */
+		pring->txq_cnt = 0;
+
+		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+			list_del_init(&iocb->list);
+			if (iocb->iocb_cmpl) {
+				icmd = &iocb->iocb;
+				icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+				icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+				spin_unlock_irqrestore(phba->host->host_lock,
+						       flags);
+				(iocb->iocb_cmpl) (phba, iocb, iocb);
+				spin_lock_irqsave(phba->host->host_lock, flags);
+			} else {
+				list_add_tail(&iocb->list,
+					      &phba->lpfc_iocb_list);
+			}
+		}
+
+		INIT_LIST_HEAD(&(pring->txq));
+
+		if (pring->fast_lookup) {
+			kfree(pring->fast_lookup);
+			pring->fast_lookup = NULL;
+		}
+
+	}
+
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+
+	/* Return any active mbox cmds */
+	del_timer_sync(&psli->mbox_tmo);
+	spin_lock_irqsave(phba->host->host_lock, flags);
+	phba->work_hba_events &= ~WORKER_MBOX_TMO;
+	if (psli->mbox_active) {
+		pmb = psli->mbox_active;
+		pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+		if (pmb->mbox_cmpl) {
+			spin_unlock_irqrestore(phba->host->host_lock, flags);
+			pmb->mbox_cmpl(phba,pmb);
+			spin_lock_irqsave(phba->host->host_lock, flags);
+		}
+	}
+	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	psli->mbox_active = NULL;
+
+	/* Return any pending mbox cmds */
+	while ((pmb = lpfc_mbox_get(phba)) != NULL) {
+		pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+		if (pmb->mbox_cmpl) {
+			spin_unlock_irqrestore(phba->host->host_lock, flags);
+			pmb->mbox_cmpl(phba,pmb);
+			spin_lock_irqsave(phba->host->host_lock, flags);
+		}
+	}
+
+	INIT_LIST_HEAD(&psli->mboxq);
+
+	spin_unlock_irqrestore(phba->host->host_lock, flags);
+
+	/*
+	 * Provided the hba is not in an error state, reset it.  It is not
+	 * capable of IO anymore.
+	 */
+	if (phba->hba_state != LPFC_HBA_ERROR) {
+		phba->hba_state = LPFC_INIT_START;
+		lpfc_sli_brdreset(phba, 1);
+	}
+
+	return 1;
+}
+
+void
+lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
+{
+	uint32_t *src = srcp;
+	uint32_t *dest = destp;
+	uint32_t ldata;
+	int i;
+
+	for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) {
+		ldata = *src;
+		ldata = le32_to_cpu(ldata);
+		*dest = ldata;
+		src++;
+		dest++;
+	}
+}
+
+int
+lpfc_sli_ringpostbuf_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
+			 struct lpfc_dmabuf * mp)
+{
+	/* Stick struct lpfc_dmabuf at end of postbufq so driver can look it up
+	   later */
+	list_add_tail(&mp->list, &pring->postbufq);
+
+	pring->postbufq_cnt++;
+	return 0;
+}
+
+
+struct lpfc_dmabuf *
+lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			 dma_addr_t phys)
+{
+	struct lpfc_dmabuf *mp, *next_mp;
+	struct list_head *slp = &pring->postbufq;
+
+	/* Search postbufq, from the begining, looking for a match on phys */
+	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+		if (mp->phys == phys) {
+			list_del_init(&mp->list);
+			pring->postbufq_cnt--;
+			return mp;
+		}
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"%d:0410 Cannot find virtual addr for mapped buf on "
+			"ring %d Data x%llx x%p x%p x%x\n",
+			phba->brd_no, pring->ringno, (unsigned long long)phys,
+			slp->next, slp->prev, pring->postbufq_cnt);
+	return NULL;
+}
+
+static void
+lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			   struct lpfc_iocbq * rspiocb)
+{
+	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
+	/* Free the resources associated with the ELS_REQUEST64 IOCB the driver
+	 * just aborted.
+	 * In this case, context2  = cmd,  context2->next = rsp, context3 = bpl
+	 */
+	if (cmdiocb->context2) {
+		buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+		/* Free the response IOCB before completing the abort
+		   command.  */
+		buf_ptr = NULL;
+		list_remove_head((&buf_ptr1->list), buf_ptr,
+				 struct lpfc_dmabuf, list);
+		if (buf_ptr) {
+			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+			kfree(buf_ptr);
+		}
+		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+		kfree(buf_ptr1);
+	}
+
+	if (cmdiocb->context3) {
+		buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+
+	list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+	return;
+}
+
+int
+lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
+			     struct lpfc_sli_ring * pring,
+			     struct lpfc_iocbq * cmdiocb)
+{
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	struct lpfc_iocbq *abtsiocbp = NULL;
+	IOCB_t *icmd = NULL;
+	IOCB_t *iabt = NULL;
+
+	/* issue ABTS for this IOCB based on iotag */
+	list_remove_head(lpfc_iocb_list, abtsiocbp, struct lpfc_iocbq, list);
+	if (abtsiocbp == NULL)
+		return 0;
+	memset(abtsiocbp, 0, sizeof (struct lpfc_iocbq));
+
+	iabt = &abtsiocbp->iocb;
+	icmd = &cmdiocb->iocb;
+	switch (icmd->ulpCommand) {
+	case CMD_ELS_REQUEST64_CR:
+		/* Even though we abort the ELS command, the firmware may access
+		 * the BPL or other resources before it processes our
+		 * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
+		 * resources till the actual abort request completes.
+		 */
+		abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
+		abtsiocbp->context2 = cmdiocb->context2;
+		abtsiocbp->context3 = cmdiocb->context3;
+		cmdiocb->context2 = NULL;
+		cmdiocb->context3 = NULL;
+		abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
+		break;
+	default:
+		list_add_tail(&abtsiocbp->list, lpfc_iocb_list);
+		return 0;
+	}
+
+	iabt->un.amxri.abortType = ABORT_TYPE_ABTS;
+	iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32;
+
+	iabt->ulpLe = 1;
+	iabt->ulpClass = CLASS3;
+	iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
+
+	if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
+		list_add_tail(&abtsiocbp->list, lpfc_iocb_list);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+lpfc_sli_validate_iocb_cmd(struct lpfc_scsi_buf *lpfc_cmd, uint16_t tgt_id,
+			     uint64_t lun_id, struct lpfc_iocbq *iocb,
+			     uint32_t ctx, lpfc_ctx_cmd ctx_cmd)
+{
+	int rc = 1;
+
+	if (lpfc_cmd == NULL)
+		return rc;
+
+	switch (ctx_cmd) {
+	case LPFC_CTX_LUN:
+		if ((lpfc_cmd->pCmd->device->id == tgt_id) &&
+		    (lpfc_cmd->pCmd->device->lun == lun_id))
+			rc = 0;
+		break;
+	case LPFC_CTX_TGT:
+		if (lpfc_cmd->pCmd->device->id == tgt_id)
+			rc = 0;
+		break;
+	case LPFC_CTX_CTX:
+		if (iocb->iocb.ulpContext == ctx)
+			rc = 0;
+	case LPFC_CTX_HOST:
+		rc = 0;
+		break;
+	default:
+		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
+			__FUNCTION__, ctx_cmd);
+		break;
+	}
+
+	return rc;
+}
+
+int
+lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
+{
+	struct lpfc_iocbq *iocb, *next_iocb;
+	IOCB_t *cmd = NULL;
+	struct lpfc_scsi_buf *lpfc_cmd;
+	int sum = 0, ret_val = 0;
+
+	/* Next check the txcmplq */
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		cmd = &iocb->iocb;
+
+		/* Must be a FCP command */
+		if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
+		    (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
+		    (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
+			continue;
+		}
+
+		/* context1 MUST be a struct lpfc_scsi_buf */
+		lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
+		ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
+						     NULL, 0, ctx_cmd);
+		if (ret_val != 0)
+			continue;
+		sum++;
+	}
+	return sum;
+}
+
+int
+lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		    uint16_t tgt_id, uint64_t lun_id, uint32_t ctx,
+		    lpfc_ctx_cmd abort_cmd)
+{
+	struct lpfc_iocbq *iocb, *next_iocb;
+	struct lpfc_iocbq *abtsiocb = NULL;
+	struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+	IOCB_t *cmd = NULL;
+	struct lpfc_scsi_buf *lpfc_cmd;
+	int errcnt = 0, ret_val = 0;
+
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		cmd = &iocb->iocb;
+
+		/* Must be a FCP command */
+		if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
+		    (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
+		    (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
+			continue;
+		}
+
+		/* context1 MUST be a struct lpfc_scsi_buf */
+		lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
+		ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
+						     iocb, ctx, abort_cmd);
+		if (ret_val != 0)
+			continue;
+
+		/* issue ABTS for this IOCB based on iotag */
+		list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq,
+				 list);
+		if (abtsiocb == NULL) {
+			errcnt++;
+			continue;
+		}
+		memset(abtsiocb, 0, sizeof (struct lpfc_iocbq));
+
+		abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
+		abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
+		abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
+		abtsiocb->iocb.ulpLe = 1;
+		abtsiocb->iocb.ulpClass = cmd->ulpClass;
+
+		if (phba->hba_state >= LPFC_LINK_UP)
+			abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
+		else
+			abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN;
+
+		ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0);
+		if (ret_val == IOCB_ERROR) {
+			list_add_tail(&abtsiocb->list, lpfc_iocb_list);
+			errcnt++;
+			continue;
+		}
+	}
+
+	return errcnt;
+}
+
+void
+lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba,
+				 struct lpfc_iocbq * queue1,
+				 struct lpfc_iocbq * queue2)
+{
+	if (queue1->context2 && queue2)
+		memcpy(queue1->context2, queue2, sizeof (struct lpfc_iocbq));
+
+	/* The waiter is looking for LPFC_IO_HIPRI bit to be set
+	   as a signal to wake up */
+	queue1->iocb_flag |= LPFC_IO_HIPRI;
+	return;
+}
+
+int
+lpfc_sli_issue_iocb_wait_high_priority(struct lpfc_hba * phba,
+				       struct lpfc_sli_ring * pring,
+				       struct lpfc_iocbq * piocb,
+				       uint32_t flag,
+				       struct lpfc_iocbq * prspiocbq,
+				       uint32_t timeout)
+{
+	int j, delay_time,  retval = IOCB_ERROR;
+
+	/* The caller must left context1 empty.  */
+	if (piocb->context_un.hipri_wait_queue != 0) {
+		return IOCB_ERROR;
+	}
+
+	/*
+	 * If the caller has provided a response iocbq buffer, context2 must
+	 * be NULL or its an error.
+	 */
+	if (prspiocbq && piocb->context2) {
+		return IOCB_ERROR;
+	}
+
+	piocb->context2 = prspiocbq;
+
+	/* Setup callback routine and issue the command. */
+	piocb->iocb_cmpl = lpfc_sli_wake_iocb_high_priority;
+	retval = lpfc_sli_issue_iocb(phba, pring, piocb,
+					flag | SLI_IOCB_HIGH_PRIORITY);
+	if (retval != IOCB_SUCCESS) {
+		piocb->context2 = NULL;
+		return IOCB_ERROR;
+	}
+
+	/*
+	 * This high-priority iocb was sent out-of-band.  Poll for its
+	 * completion rather than wait for a signal.  Note that the host_lock
+	 * is held by the midlayer and must be released here to allow the
+	 * interrupt handlers to complete the IO and signal this routine via
+	 * the iocb_flag.
+	 * Also, the delay_time is computed to be one second longer than
+	 * the scsi command timeout to give the FW time to abort on
+	 * timeout rather than the driver just giving up.  Typically,
+	 * the midlayer does not specify a time for this command so the
+	 * driver is free to enforce its own timeout.
+	 */
+
+	delay_time = ((timeout + 1) * 1000) >> 6;
+	retval = IOCB_ERROR;
+	spin_unlock_irq(phba->host->host_lock);
+	for (j = 0; j < 64; j++) {
+		msleep(delay_time);
+		if (piocb->iocb_flag & LPFC_IO_HIPRI) {
+			piocb->iocb_flag &= ~LPFC_IO_HIPRI;
+			retval = IOCB_SUCCESS;
+			break;
+		}
+	}
+
+	spin_lock_irq(phba->host->host_lock);
+	piocb->context2 = NULL;
+	return retval;
+}
+int
+lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
+			 uint32_t timeout)
+{
+	DECLARE_WAIT_QUEUE_HEAD(done_q);
+	DECLARE_WAITQUEUE(wq_entry, current);
+	uint32_t timeleft = 0;
+	int retval;
+
+	/* The caller must leave context1 empty. */
+	if (pmboxq->context1 != 0) {
+		return (MBX_NOT_FINISHED);
+	}
+
+	/* setup wake call as IOCB callback */
+	pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
+	/* setup context field to pass wait_queue pointer to wake function  */
+	pmboxq->context1 = &done_q;
+
+	/* start to sleep before we wait, to avoid races */
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&done_q, &wq_entry);
+
+	/* now issue the command */
+	retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+	if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
+		timeleft = schedule_timeout(timeout * HZ);
+		pmboxq->context1 = NULL;
+		/* if schedule_timeout returns 0, we timed out and were not
+		   woken up */
+		if (timeleft == 0) {
+			retval = MBX_TIMEOUT;
+		} else {
+			retval = MBX_SUCCESS;
+		}
+	}
+
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&done_q, &wq_entry);
+	return retval;
+}
+
+irqreturn_t
+lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct lpfc_hba *phba;
+	uint32_t ha_copy;
+	uint32_t work_ha_copy;
+	unsigned long status;
+	int i;
+	uint32_t control;
+
+	/*
+	 * Get the driver's phba structure from the dev_id and
+	 * assume the HBA is not interrupting.
+	 */
+	phba = (struct lpfc_hba *) dev_id;
+
+	if (unlikely(!phba))
+		return IRQ_NONE;
+
+	phba->sli.slistat.sli_intr++;
+
+	/*
+	 * Call the HBA to see if it is interrupting.  If not, don't claim
+	 * the interrupt
+	 */
+
+	/* Ignore all interrupts during initialization. */
+	if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+		return IRQ_NONE;
+
+	/*
+	 * Read host attention register to determine interrupt source
+	 * Clear Attention Sources, except Error Attention (to
+	 * preserve status) and Link Attention
+	 */
+	spin_lock(phba->host->host_lock);
+	ha_copy = readl(phba->HAregaddr);
+	writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
+	readl(phba->HAregaddr); /* flush */
+	spin_unlock(phba->host->host_lock);
+
+	if (unlikely(!ha_copy))
+		return IRQ_NONE;
+
+	work_ha_copy = ha_copy & phba->work_ha_mask;
+
+	if (unlikely(work_ha_copy)) {
+		if (work_ha_copy & HA_LATT) {
+			if (phba->sli.sli_flag & LPFC_PROCESS_LA) {
+				/*
+				 * Turn off Link Attention interrupts
+				 * until CLEAR_LA done
+				 */
+				spin_lock(phba->host->host_lock);
+				phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
+				control = readl(phba->HCregaddr);
+				control &= ~HC_LAINT_ENA;
+				writel(control, phba->HCregaddr);
+				readl(phba->HCregaddr); /* flush */
+				spin_unlock(phba->host->host_lock);
+			}
+			else
+				work_ha_copy &= ~HA_LATT;
+		}
+
+		if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
+			for (i = 0; i < phba->sli.num_rings; i++) {
+				if (work_ha_copy & (HA_RXATT << (4*i))) {
+					/*
+					 * Turn off Slow Rings interrupts
+					 */
+					spin_lock(phba->host->host_lock);
+					control = readl(phba->HCregaddr);
+					control &= ~(HC_R0INT_ENA << i);
+					writel(control, phba->HCregaddr);
+					readl(phba->HCregaddr); /* flush */
+					spin_unlock(phba->host->host_lock);
+				}
+			}
+		}
+
+		if (work_ha_copy & HA_ERATT) {
+			phba->hba_state = LPFC_HBA_ERROR;
+			/*
+			 * There was a link/board error.  Read the
+			 * status register to retrieve the error event
+			 * and process it.
+			 */
+			phba->sli.slistat.err_attn_event++;
+			/* Save status info */
+			phba->work_hs = readl(phba->HSregaddr);
+			phba->work_status[0] = readl(phba->MBslimaddr + 0xa8);
+			phba->work_status[1] = readl(phba->MBslimaddr + 0xac);
+
+			/* Clear Chip error bit */
+			writel(HA_ERATT, phba->HAregaddr);
+			readl(phba->HAregaddr); /* flush */
+
+			/*
+			 * Reseting the HBA is the only reliable way
+			 * to shutdown interrupt when there is a
+			 * ERROR.
+			 */
+			lpfc_sli_send_reset(phba, phba->hba_state);
+		}
+
+		spin_lock(phba->host->host_lock);
+		phba->work_ha |= work_ha_copy;
+		if (phba->work_wait)
+			wake_up(phba->work_wait);
+		spin_unlock(phba->host->host_lock);
+	}
+
+	ha_copy &= ~(phba->work_ha_mask);
+
+	/*
+	 * Process all events on FCP ring.  Take the optimized path for
+	 * FCP IO.  Any other IO is slow path and is handled by
+	 * the worker thread.
+	 */
+	status = (ha_copy & (HA_RXMASK  << (4*LPFC_FCP_RING)));
+	status >>= (4*LPFC_FCP_RING);
+	if (status & HA_RXATT)
+		lpfc_sli_handle_fast_ring_event(phba,
+						&phba->sli.ring[LPFC_FCP_RING],
+						status);
+	return IRQ_HANDLED;
+
+} /* lpfc_intr_handler */
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -0,0 +1,216 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_sli.h 1.42 2005/03/21 02:01:28EST sf_support Exp  $
+ */
+
+/* forward declaration for LPFC_IOCB_t's use */
+struct lpfc_hba;
+
+/* Define the context types that SLI handles for abort and sums. */
+typedef enum _lpfc_ctx_cmd {
+	LPFC_CTX_LUN,
+	LPFC_CTX_TGT,
+	LPFC_CTX_CTX,
+	LPFC_CTX_HOST
+} lpfc_ctx_cmd;
+
+/* This structure is used to handle IOCB requests / responses */
+struct lpfc_iocbq {
+	/* lpfc_iocbqs are used in double linked lists */
+	struct list_head list;
+	IOCB_t iocb;		/* IOCB cmd */
+	uint8_t retry;		/* retry counter for IOCB cmd - if needed */
+	uint8_t iocb_flag;
+#define LPFC_IO_POLL	1	/* Polling mode iocb */
+#define LPFC_IO_LIBDFC	2	/* libdfc iocb */
+#define LPFC_IO_WAIT	4
+#define LPFC_IO_HIPRI	8	/* High Priority Queue signal flag */
+
+	uint8_t abort_count;
+	uint8_t rsvd2;
+	uint32_t drvrTimeout;	/* driver timeout in seconds */
+	void *context1;		/* caller context information */
+	void *context2;		/* caller context information */
+	void *context3;		/* caller context information */
+	union {
+		wait_queue_head_t *hipri_wait_queue; /* High Priority Queue wait
+							queue */
+		struct lpfc_iocbq  *rsp_iocb;
+		struct lpfcMboxq   *mbox;
+	} context_un;
+
+	void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+			   struct lpfc_iocbq *);
+
+};
+
+#define SLI_IOCB_RET_IOCB      1	/* Return IOCB if cmd ring full */
+#define SLI_IOCB_HIGH_PRIORITY 2	/* High priority command */
+
+#define IOCB_SUCCESS        0
+#define IOCB_BUSY           1
+#define IOCB_ERROR          2
+#define IOCB_TIMEDOUT       3
+
+typedef struct lpfcMboxq {
+	/* MBOXQs are used in single linked lists */
+	struct list_head list;	/* ptr to next mailbox command */
+	MAILBOX_t mb;		/* Mailbox cmd */
+	void *context1;		/* caller context information */
+	void *context2;		/* caller context information */
+
+	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
+
+} LPFC_MBOXQ_t;
+
+#define MBX_POLL        1	/* poll mailbox till command done, then
+				   return */
+#define MBX_NOWAIT      2	/* issue command then return immediately */
+#define MBX_STOP_IOCB   4	/* Stop iocb processing till mbox cmds
+				   complete */
+
+#define LPFC_MAX_RING_MASK  4	/* max num of rctl/type masks allowed per
+				   ring */
+#define LPFC_MAX_RING       4	/* max num of SLI rings used by driver */
+
+struct lpfc_sli_ring;
+
+struct lpfc_sli_ring_mask {
+	uint8_t profile;	/* profile associated with ring */
+	uint8_t rctl;	/* rctl / type pair configured for ring */
+	uint8_t type;	/* rctl / type pair configured for ring */
+	uint8_t rsvd;
+	/* rcv'd unsol event */
+	void (*lpfc_sli_rcv_unsol_event) (struct lpfc_hba *,
+					 struct lpfc_sli_ring *,
+					 struct lpfc_iocbq *);
+};
+
+
+/* Structure used to hold SLI statistical counters and info */
+struct lpfc_sli_ring_stat {
+	uint64_t iocb_event;	 /* IOCB event counters */
+	uint64_t iocb_cmd;	 /* IOCB cmd issued */
+	uint64_t iocb_rsp;	 /* IOCB rsp received */
+	uint64_t iocb_cmd_delay; /* IOCB cmd ring delay */
+	uint64_t iocb_cmd_full;	 /* IOCB cmd ring full */
+	uint64_t iocb_cmd_empty; /* IOCB cmd ring is now empty */
+	uint64_t iocb_rsp_full;	 /* IOCB rsp ring full */
+};
+
+/* Structure used to hold SLI ring information */
+struct lpfc_sli_ring {
+	uint16_t flag;		/* ring flags */
+#define LPFC_DEFERRED_RING_EVENT 0x001	/* Deferred processing a ring event */
+#define LPFC_CALL_RING_AVAILABLE 0x002	/* indicates cmd was full */
+#define LPFC_STOP_IOCB_MBX       0x010	/* Stop processing IOCB cmds mbox */
+#define LPFC_STOP_IOCB_EVENT     0x020	/* Stop processing IOCB cmds event */
+#define LPFC_STOP_IOCB_MASK      0x030	/* Stop processing IOCB cmds mask */
+	uint16_t abtsiotag;	/* tracks next iotag to use for ABTS */
+
+	uint32_t local_getidx;   /* last available cmd index (from cmdGetInx) */
+	uint32_t next_cmdidx;    /* next_cmd index */
+	uint8_t rsvd;
+	uint8_t ringno;		/* ring number */
+	uint8_t rspidx;		/* current index in response ring */
+	uint8_t cmdidx;		/* current index in command ring */
+	uint16_t numCiocb;	/* number of command iocb's per ring */
+	uint16_t numRiocb;	/* number of rsp iocb's per ring */
+
+	uint32_t fast_iotag;	/* max fastlookup based iotag           */
+	uint32_t iotag_ctr;	/* keeps track of the next iotag to use */
+	uint32_t iotag_max;	/* max iotag value to use               */
+	struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by
+					   iotag */
+	struct list_head txq;
+	uint16_t txq_cnt;	/* current length of queue */
+	uint16_t txq_max;	/* max length */
+	struct list_head txcmplq;
+	uint16_t txcmplq_cnt;	/* current length of queue */
+	uint16_t txcmplq_max;	/* max length */
+	uint32_t *cmdringaddr;	/* virtual address for cmd rings */
+	uint32_t *rspringaddr;	/* virtual address for rsp rings */
+	uint32_t missbufcnt;	/* keep track of buffers to post */
+	struct list_head postbufq;
+	uint16_t postbufq_cnt;	/* current length of queue */
+	uint16_t postbufq_max;	/* max length */
+	struct list_head iocb_continueq;
+	uint16_t iocb_continueq_cnt;	/* current length of queue */
+	uint16_t iocb_continueq_max;	/* max length */
+
+	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
+	uint32_t num_mask;	/* number of mask entries in prt array */
+
+	struct lpfc_sli_ring_stat stats;	/* SLI statistical info */
+
+	/* cmd ring available */
+	void (*lpfc_sli_cmd_available) (struct lpfc_hba *,
+					struct lpfc_sli_ring *);
+};
+
+/* Structure used to hold SLI statistical counters and info */
+struct lpfc_sli_stat {
+	uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
+	uint64_t mbox_cmd;       /* Mailbox commands issued */
+	uint64_t sli_intr;       /* Count of Host Attention interrupts */
+	uint32_t err_attn_event; /* Error Attn event counters */
+	uint32_t link_event;     /* Link event counters */
+	uint32_t mbox_event;     /* Mailbox event counters */
+	uint32_t mbox_busy;	 /* Mailbox cmd busy */
+};
+
+/* Structure used to hold SLI information */
+struct lpfc_sli {
+	uint32_t num_rings;
+	uint32_t sli_flag;
+
+	/* Additional sli_flags */
+#define LPFC_SLI_MBOX_ACTIVE      0x100	/* HBA mailbox is currently active */
+#define LPFC_SLI2_ACTIVE          0x200	/* SLI2 overlay in firmware is active */
+#define LPFC_PROCESS_LA           0x400	/* Able to process link attention */
+
+	struct lpfc_sli_ring ring[LPFC_MAX_RING];
+	int fcp_ring;		/* ring used for FCP initiator commands */
+	int next_ring;
+
+	int ip_ring;		/* ring used for IP network drv cmds */
+
+	struct lpfc_sli_stat slistat;	/* SLI statistical info */
+	struct list_head mboxq;
+	uint16_t mboxq_cnt;	/* current length of queue */
+	uint16_t mboxq_max;	/* max length */
+	LPFC_MBOXQ_t *mbox_active;	/* active mboxq information */
+
+	struct timer_list mbox_tmo;	/* Hold clk to timeout active mbox
+					   cmd */
+
+	uint32_t *MBhostaddr;	/* virtual address for mbox cmds */
+};
+
+/* Given a pointer to the start of the ring, and the slot number of
+ * the desired iocb entry, calc a pointer to that entry.
+ * (assume iocb entry size is 32 bytes, or 8 words)
+ */
+#define IOCB_ENTRY(ring,slot) ((IOCB_t *)(((char *)(ring)) + ((slot) * 32)))
+
+#define LPFC_MBOX_TMO           30	/* Sec tmo for outstanding mbox
+					   command */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -0,0 +1,32 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Enterprise Fibre Channel Host Bus Adapters.                     *
+ * Refer to the README file included with this package for         *
+ * driver version and adapter support.                             *
+ * Copyright (C) 2004 Emulex Corporation.                          *
+ * www.emulex.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, a copy of which    *
+ * can be found in the file COPYING included with this package.    *
+ *******************************************************************/
+
+/*
+ * $Id: lpfc_version.h 1.49 2005/04/13 15:07:19EDT sf_support Exp  $
+ */
+
+#define LPFC_DRIVER_VERSION "8.0.28"
+
+#define LPFC_DRIVER_NAME "lpfc"
+
+#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
+		LPFC_DRIVER_VERSION
+
+#define DFC_API_VERSION "0.0.0"
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -302,7 +302,7 @@ int macscsi_detect(Scsi_Host_Template * 
 
     if (instance->irq != SCSI_IRQ_NONE)
 	if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, 
-		"ncr5380", NCR5380_intr)) {
+		"ncr5380", instance)) {
 	    printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
 		   instance->host_no, instance->irq);
 	    instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -16,6 +16,7 @@
  */
 
 #include "megaraid_mm.h"
+#include <linux/smp_lock.h>
 
 
 // Entry points for char node driver
@@ -43,8 +44,7 @@ static void mraid_mm_free_adp_resources(
 static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);
 
 #ifdef CONFIG_COMPAT
-static int mraid_mm_compat_ioctl(unsigned int, unsigned int, unsigned long,
-		struct file *);
+static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long);
 #endif
 
 MODULE_AUTHOR("LSI Logic Corporation");
@@ -71,6 +71,9 @@ static wait_queue_head_t wait_q;
 static struct file_operations lsi_fops = {
 	.open	= mraid_mm_open,
 	.ioctl	= mraid_mm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = mraid_mm_compat_ioctl,
+#endif
 	.owner	= THIS_MODULE,
 };
 
@@ -1215,8 +1218,6 @@ mraid_mm_init(void)
 
 	INIT_LIST_HEAD(&adapters_list_g);
 
-	register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl);
-
 	return 0;
 }
 
@@ -1225,13 +1226,15 @@ mraid_mm_init(void)
  * mraid_mm_compat_ioctl	: 32bit to 64bit ioctl conversion routine
  */
 #ifdef CONFIG_COMPAT
-static int
-mraid_mm_compat_ioctl(unsigned int fd, unsigned int cmd,
-			unsigned long arg, struct file *filep)
-{
-	struct inode *inode = filep->f_dentry->d_inode;
-
-	return mraid_mm_ioctl(inode, filep, cmd, arg);
+static long
+mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
+		      unsigned long arg)
+{
+	int err;
+	lock_kernel();
+	err = mraid_mm_ioctl(NULL, filep, cmd, arg);
+	unlock_kernel();
+	return err;
 }
 #endif
 
@@ -1244,7 +1247,6 @@ mraid_mm_exit(void)
 	con_log(CL_DLEVEL1 , ("exiting common mod\n"));
 
 	unregister_chrdev(majorno, "megadev");
-	unregister_ioctl32_conversion(MEGAIOCCMD);
 }
 
 module_init(mraid_mm_init);
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1757,7 +1757,7 @@ static void set_mesh_power(struct mesh_s
 
 
 #ifdef CONFIG_PM
-static int mesh_suspend(struct macio_dev *mdev, u32 state)
+static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
 {
 	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
 	unsigned long flags;
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -86,7 +86,7 @@
 */
 
 /* Name and version of the driver */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3f"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3g"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -1219,7 +1219,7 @@ static	struct lcb *	ncr_alloc_lcb	(struc
 static	struct lcb *	ncr_setup_lcb	(struct ncb *np, struct scsi_device *sdev);
 static	void	ncr_getclock	(struct ncb *np, int mult);
 static	void	ncr_selectclock	(struct ncb *np, u_char scntl3);
-static	struct ccb *ncr_get_ccb	(struct ncb *np, u_char tn, u_char ln);
+static	struct ccb *ncr_get_ccb	(struct ncb *np, struct scsi_cmnd *cmd);
 static	void	ncr_chip_reset	(struct ncb *np, int delay);
 static	void	ncr_init	(struct ncb *np, int reset, char * msg, u_long code);
 static	int	ncr_int_sbmc	(struct ncb *np);
@@ -1238,8 +1238,6 @@ static	void	ncr_getsync	(struct ncb *np,
 static	void	ncr_setsync	(struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer);
 static	void	ncr_setup_tags	(struct ncb *np, struct scsi_device *sdev);
 static	void	ncr_setwide	(struct ncb *np, struct ccb *cp, u_char wide, u_char ack);
-static	int	ncr_show_msg	(u_char * msg);
-static  void    ncr_print_msg   (struct ccb *cp, char *label, u_char *msg);
 static	int	ncr_snooptest	(struct ncb *np);
 static	void	ncr_timeout	(struct ncb *np);
 static  void    ncr_wakeup      (struct ncb *np, u_long code);
@@ -2746,7 +2744,7 @@ void __init ncr_script_fill (struct scri
 	for (i=0; i<MAX_START; i++) {
 		*p++ =SCR_CALL;
 		*p++ =PADDR (idle);
-	};
+	}
 
 	BUG_ON((u_long)p != (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
 
@@ -2771,7 +2769,7 @@ void __init ncr_script_fill (struct scri
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
 		*p++ =offsetof (struct dsb, data[i]);
-	};
+	}
 
 	BUG_ON((u_long)p != (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
 
@@ -2781,7 +2779,7 @@ void __init ncr_script_fill (struct scri
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
 		*p++ =offsetof (struct dsb, data[i]);
-	};
+	}
 
 	BUG_ON((u_long)p != (u_long)&scr->data_in + sizeof (scr->data_in));
 
@@ -2791,7 +2789,7 @@ void __init ncr_script_fill (struct scri
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
 		*p++ =offsetof (struct dsb, data[i]);
-	};
+	}
 
 	BUG_ON((u_long)p != (u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
 
@@ -2801,7 +2799,7 @@ void __init ncr_script_fill (struct scri
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
 		*p++ =offsetof (struct dsb, data[i]);
-	};
+	}
 
 	BUG_ON((u_long) p != (u_long)&scr->data_out + sizeof (scr->data_out));
 }
@@ -2842,7 +2840,7 @@ ncr_script_copy_and_bind (struct ncb *np
 			printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n",
 				ncr_name(np), (int) (src-start-1));
 			mdelay(1000);
-		};
+		}
 
 		if (DEBUG_FLAGS & DEBUG_SCRIPT)
 			printk (KERN_DEBUG "%p:  <%x>\n",
@@ -2911,7 +2909,7 @@ ncr_script_copy_and_bind (struct ncb *np
 		default:
 			relocs = 0;
 			break;
-		};
+		}
 
 		if (relocs) {
 			while (relocs--) {
@@ -2958,7 +2956,7 @@ ncr_script_copy_and_bind (struct ncb *np
 		} else
 			*dst++ = cpu_to_scr(*src++);
 
-	};
+	}
 }
 
 /*
@@ -2969,25 +2967,25 @@ struct host_data {
      struct ncb *ncb;
 };
 
-/*
-**	Print something which allows to retrieve the controller type, unit,
-**	target, lun concerned by a kernel message.
-*/
+#define PRINT_ADDR(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
 
-static void PRINT_TARGET(struct ncb *np, int target)
+static void ncr_print_msg(struct ccb *cp, char *label, u_char *msg)
 {
-	printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target);
-}
+	int i;
+	PRINT_ADDR(cp->cmd, "%s: ", label);
 
-static void PRINT_LUN(struct ncb *np, int target, int lun)
-{
-	printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun);
-}
+	printk ("%x",*msg);
+	if (*msg == M_EXTENDED) {
+		for (i = 1; i < 8; i++) {
+			if (i - 1 > msg[1])
+				break;
+			printk ("-%x",msg[i]);
+		}
+	} else if ((*msg & 0xf0) == 0x20) {
+		printk ("-%x",msg[1]);
+	}
 
-static void PRINT_ADDR(struct scsi_cmnd *cmd)
-{
-	struct host_data *host_data = (struct host_data *) cmd->device->host->hostdata;
-	PRINT_LUN(host_data->ncb, cmd->device->id, cmd->device->lun);
+	printk(".\n");
 }
 
 /*==========================================================
@@ -3280,6 +3278,7 @@ static void __init ncr_prepare_setting(s
 		tp->usrsync = driver_setup.default_sync;
 		tp->usrwide = driver_setup.max_wide;
 		tp->usrtags = MAX_TAGS;
+		tp->period = 0xffff;
 		if (!driver_setup.disconnection)
 			np->target[i].usrflag = UF_NODISC;
 	}
@@ -3369,34 +3368,23 @@ static int ncr_prepare_nego(struct ncb *
 	int nego = 0;
 	struct scsi_target *starget = tp->starget;
 
-	if (likely(starget)) {
-
-		/*
-		**	negotiate wide transfers ?
-		*/
-
-		if (!tp->widedone) {
-			if (spi_support_wide(starget)) {
-				nego = NS_WIDE;
-			} else
-				tp->widedone=1;
-
-		};
-
-		/*
-		**	negotiate synchronous transfers?
-		*/
+	/* negotiate wide transfers ?  */
+	if (!tp->widedone) {
+		if (spi_support_wide(starget)) {
+			nego = NS_WIDE;
+		} else
+			tp->widedone=1;
+	}
 
-		if (!nego && !tp->period) {
-			if (spi_support_sync(starget)) {
-				nego = NS_SYNC;
-			} else {
-				tp->period  =0xffff;
-				PRINT_TARGET(np, cp->target);
-				printk ("target did not report SYNC.\n");
-			};
-		};
-	};
+	/* negotiate synchronous transfers?  */
+	if (!nego && !tp->period) {
+		if (spi_support_sync(starget)) {
+			nego = NS_SYNC;
+		} else {
+			tp->period  =0xffff;
+			dev_info(&starget->dev, "target did not report SYNC.\n");
+		}
+	}
 
 	switch (nego) {
 	case NS_SYNC:
@@ -3412,7 +3400,7 @@ static int ncr_prepare_nego(struct ncb *
 		msgptr[msglen++] = M_X_WIDE_REQ;
 		msgptr[msglen++] = tp->usrwide;
 		break;
-	};
+	}
 
 	cp->nego_status = nego;
 
@@ -3421,8 +3409,8 @@ static int ncr_prepare_nego(struct ncb *
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			ncr_print_msg(cp, nego == NS_WIDE ?
 					  "wide msgout":"sync_msgout", msgptr);
-		};
-	};
+		}
+	}
 
 	return msglen;
 }
@@ -3440,9 +3428,9 @@ static int ncr_prepare_nego(struct ncb *
 */
 static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
 {
-/*	struct scsi_device        *device    = cmd->device; */
-	struct tcb *tp                      = &np->target[cmd->device->id];
-	struct lcb *lp		      = tp->lp[cmd->device->lun];
+	struct scsi_device *sdev = cmd->device;
+	struct tcb *tp = &np->target[sdev->id];
+	struct lcb *lp = tp->lp[sdev->lun];
 	struct ccb *cp;
 
 	int	segments;
@@ -3457,9 +3445,9 @@ static int ncr_queue_command (struct ncb
 	**
 	**---------------------------------------------
 	*/
-	if ((cmd->device->id == np->myaddr	  ) ||
-		(cmd->device->id >= MAX_TARGET) ||
-		(cmd->device->lun    >= MAX_LUN   )) {
+	if ((sdev->id == np->myaddr	  ) ||
+		(sdev->id >= MAX_TARGET) ||
+		(sdev->lun    >= MAX_LUN   )) {
 		return(DID_BAD_TARGET);
 	}
 
@@ -3479,8 +3467,7 @@ static int ncr_queue_command (struct ncb
 	}
 
 	if (DEBUG_FLAGS & DEBUG_TINY) {
-		PRINT_ADDR(cmd);
-		printk ("CMD=%x ", cmd->cmnd[0]);
+		PRINT_ADDR(cmd, "CMD=%x ", cmd->cmnd[0]);
 	}
 
 	/*---------------------------------------------------
@@ -3499,7 +3486,7 @@ static int ncr_queue_command (struct ncb
 			np->settle_time = tlimit;
 	}
 
-	if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->device->id, cmd->device->lun))) {
+	if (np->settle_time || !(cp=ncr_get_ccb (np, cmd))) {
 		insert_into_waiting_list(np, cmd);
 		return(DID_OK);
 	}
@@ -3512,7 +3499,7 @@ static int ncr_queue_command (struct ncb
 	**----------------------------------------------------
 	*/
 
-	idmsg = M_IDENTIFY | cmd->device->lun;
+	idmsg = M_IDENTIFY | sdev->lun;
 
 	if (cp ->tag != NO_TAG ||
 		(cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC)))
@@ -3533,8 +3520,8 @@ static int ncr_queue_command (struct ncb
 			if (lp->tags_smap) {
 				order = M_ORDERED_TAG;
 				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
-					PRINT_ADDR(cmd);
-					printk("ordered tag forced.\n");
+					PRINT_ADDR(cmd,
+						"ordered tag forced.\n");
 				}
 			}
 			lp->tags_stime = ktime_get(3*HZ);
@@ -3682,7 +3669,7 @@ static int ncr_queue_command (struct ncb
 	/*
 	**	select
 	*/
-	cp->phys.select.sel_id		= cmd->device->id;
+	cp->phys.select.sel_id		= sdev->id;
 	cp->phys.select.sel_scntl3	= tp->wval;
 	cp->phys.select.sel_sxfer	= tp->sval;
 	/*
@@ -3719,9 +3706,7 @@ static int ncr_queue_command (struct ncb
 	**----------------------------------------------------
 	*/
 
-	/*
-	**	activate this job.
-	*/
+	/* activate this job.  */
 	cp->magic		= CCB_MAGIC;
 
 	/*
@@ -3734,11 +3719,9 @@ static int ncr_queue_command (struct ncb
 	else
 		ncr_put_start_queue(np, cp);
 
-	/*
-	**	Command is successfully queued.
-	*/
+	/* Command is successfully queued.  */
 
-	return(DID_OK);
+	return DID_OK;
 }
 
 
@@ -4203,8 +4186,7 @@ void ncr_complete (struct ncb *np, struc
 	*/
 
 	if (cp->parity_status > 1) {
-		PRINT_ADDR(cmd);
-		printk ("%d parity error(s).\n",cp->parity_status);
+		PRINT_ADDR(cmd, "%d parity error(s).\n",cp->parity_status);
 	}
 
 	/*
@@ -4212,16 +4194,16 @@ void ncr_complete (struct ncb *np, struc
 	*/
 
 	if (cp->xerr_status != XE_OK) {
-		PRINT_ADDR(cmd);
 		switch (cp->xerr_status) {
 		case XE_EXTRA_DATA:
-			printk ("extraneous data discarded.\n");
+			PRINT_ADDR(cmd, "extraneous data discarded.\n");
 			break;
 		case XE_BAD_PHASE:
-			printk ("invalid scsi phase (4/5).\n");
+			PRINT_ADDR(cmd, "invalid scsi phase (4/5).\n");
 			break;
 		default:
-			printk ("extended error %d.\n", cp->xerr_status);
+			PRINT_ADDR(cmd, "extended error %d.\n",
+					cp->xerr_status);
 			break;
 		}
 		if (cp->host_status==HS_COMPLETE)
@@ -4233,9 +4215,9 @@ void ncr_complete (struct ncb *np, struc
 	*/
 	if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
 		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
-			PRINT_ADDR(cmd);
-			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
-				cmd->cmnd[0], cp->host_status, cp->scsi_status);
+			PRINT_ADDR(cmd, "ERROR: cmd=%x host_status=%x "
+					"scsi_status=%x\n", cmd->cmnd[0],
+					cp->host_status, cp->scsi_status);
 		}
 	}
 
@@ -4296,8 +4278,7 @@ void ncr_complete (struct ncb *np, struc
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
 			u_char * p = (u_char*) & cmd->sense_buffer;
 			int i;
-			PRINT_ADDR(cmd);
-			printk ("sense data:");
+			PRINT_ADDR(cmd, "sense data:");
 			for (i=0; i<14; i++) printk (" %x", *p++);
 			printk (".\n");
 		}
@@ -4344,8 +4325,7 @@ void ncr_complete (struct ncb *np, struc
 		/*
 		**  Other protocol messes
 		*/
-		PRINT_ADDR(cmd);
-		printk ("COMMAND FAILED (%x %x) @%p.\n",
+		PRINT_ADDR(cmd, "COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
 
 		cmd->result = ScsiResult(DID_ERROR, cp->scsi_status);
@@ -4358,8 +4338,7 @@ void ncr_complete (struct ncb *np, struc
 	if (tp->usrflag & UF_TRACE) {
 		u_char * p;
 		int i;
-		PRINT_ADDR(cmd);
-		printk (" CMD:");
+		PRINT_ADDR(cmd, " CMD:");
 		p = (u_char*) &cmd->cmnd[0];
 		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
 
@@ -4667,12 +4646,11 @@ void ncr_init (struct ncb *np, int reset
 			}
 			else
 				tp->usrsync = 255;
-		};
+		}
 
 		if (tp->usrwide > np->maxwide)
 			tp->usrwide = np->maxwide;
 
-		ncr_negotiate (np, tp);
 	}
 
 	/*
@@ -4849,7 +4827,7 @@ static void ncr_set_sync_wide_status (st
 #endif
 		cp->phys.select.sel_scntl3 = tp->wval;
 		cp->phys.select.sel_sxfer  = tp->sval;
-	};
+	}
 }
 
 /*==========================================================
@@ -4885,40 +4863,19 @@ static void ncr_setsync (struct ncb *np,
 	else
 		tp->period = 0xffff;
 
-	/*
-	**	 Stop there if sync parameters are unchanged
-	*/
-	if (tp->sval == sxfer && tp->wval == scntl3) return;
+	/* Stop there if sync parameters are unchanged */
+	if (tp->sval == sxfer && tp->wval == scntl3)
+		return;
 	tp->sval = sxfer;
 	tp->wval = scntl3;
 
-	/*
-	**	Bells and whistles   ;-)
-	*/
-	PRINT_TARGET(np, target);
 	if (sxfer & 0x01f) {
-		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
-		unsigned mb10 = (f10 + tp->period/2) / tp->period;
-		char *scsi;
-
-		/*
-		**  Disable extended Sreq/Sack filtering
-		*/
-		if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT);
-
-		/*
-		**	Bells and whistles   ;-)
-		*/
-		if	(tp->period < 500)	scsi = "FAST-40";
-		else if	(tp->period < 1000)	scsi = "FAST-20";
-		else if	(tp->period < 2000)	scsi = "FAST-10";
-		else				scsi = "FAST-5";
-
-		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
-			tp->widedone > 1 ? "WIDE " : "",
-			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
-	} else
-		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
+		/* Disable extended Sreq/Sack filtering */
+		if (tp->period <= 2000)
+			OUTOFFB(nc_stest2, EXT);
+	}
+ 
+	spi_display_xfer_agreement(tp->starget);
 
 	/*
 	**	set actual value and sync_status
@@ -4964,11 +4921,8 @@ static void ncr_setwide (struct ncb *np,
 	**	Bells and whistles   ;-)
 	*/
 	if (bootverbose >= 2) {
-		PRINT_TARGET(np, target);
-		if (scntl3 & EWS)
-			printk ("WIDE SCSI (16 bit) enabled.\n");
-		else
-			printk ("WIDE SCSI disabled.\n");
+		dev_info(&cmd->device->sdev_target->dev, "WIDE SCSI %sabled.\n",
+				(scntl3 & EWS) ? "en" : "dis");
 	}
 
 	/*
@@ -5023,7 +4977,7 @@ static void ncr_setup_tags (struct ncb *
 		reqtags = lp->numtags;
 	} else {
 		reqtags = 1;
-	};
+	}
 
 	/*
 	**	Update max number of tags
@@ -5063,12 +5017,13 @@ static void ncr_setup_tags (struct ncb *
 	**	Announce change to user.
 	*/
 	if (bootverbose) {
-		PRINT_LUN(np, tn, ln);
 		if (lp->usetags) {
-			printk("tagged command queue depth set to %d\n", reqtags);
-		}
-		else {
-			printk("tagged command queueing disabled\n");
+			dev_info(&sdev->sdev_gendev,
+				"tagged command queue depth set to %d\n",
+				reqtags);
+		} else {
+			dev_info(&sdev->sdev_gendev,
+					"tagged command queueing disabled\n");
 		}
 	}
 }
@@ -5274,7 +5229,7 @@ void ncr_exception (struct ncb *np)
 		istat = INB (nc_istat);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		ncr_wakeup_done (np);
-	};
+	}
 
 	if (!(istat & (SIP|DIP)))
 		return;
@@ -5335,7 +5290,7 @@ void ncr_exception (struct ncb *np)
 		}
 		OUTONB_STD ();
 		return;
-	};
+	}
 
 	/*========================================================
 	**	Now, interrupts that need some fixing up.
@@ -5355,7 +5310,7 @@ void ncr_exception (struct ncb *np)
 	if (sist & RST) {
 		ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET);
 		return;
-	};
+	}
 
 	if ((sist & STO) &&
 		!(dstat & (MDPE|BF|ABRT))) {
@@ -5366,7 +5321,7 @@ void ncr_exception (struct ncb *np)
 
 		ncr_int_sto (np);
 		return;
-	};
+	}
 
 	/*=========================================================
 	**	Now, interrupts we are not able to recover cleanly.
@@ -5387,7 +5342,7 @@ void ncr_exception (struct ncb *np)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
 		np->regdump.nc_sist  = sist;
-	};
+	}
 
 	ncr_log_hard_error(np, sist, dstat);
 
@@ -5399,20 +5354,20 @@ void ncr_exception (struct ncb *np)
 		(dstat & (MDPE|BF|ABRT|IID))) {
 		ncr_start_reset(np);
 		return;
-	};
+	}
 
 	if (sist & HTH) {
 		printk ("%s: handshake timeout\n", ncr_name(np));
 		ncr_start_reset(np);
 		return;
-	};
+	}
 
 	if (sist & UDC) {
 		printk ("%s: unexpected disconnect\n", ncr_name(np));
 		OUTB (HS_PRT, HS_UNEXPECTED);
 		OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup));
 		return;
-	};
+	}
 
 	/*=========================================================
 	**	We just miss the cause of the interrupt. :(
@@ -5456,7 +5411,7 @@ void ncr_int_sto (struct ncb *np)
 	if (cp) {
 		cp-> host_status = HS_SEL_TIMEOUT;
 		ncr_complete (np, cp);
-	};
+	}
 
 	/*
 	**	repair start queue and jump to start point.
@@ -5647,7 +5602,7 @@ static void ncr_int_ma (struct ncb *np)
 			ss2 = INB (nc_sstat2);
 			if (ss2 & OLF1) rest++;
 			if (ss2 & ORF1) rest++;
-		};
+		}
 
 		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
 			printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
@@ -5716,7 +5671,7 @@ static void ncr_int_ma (struct ncb *np)
 			cp, np->header.cp,
 			(unsigned)dsp,
 			(unsigned)nxtdsp, vdsp, cmd);
-	};
+	}
 
 	/*
 	**	cp=0 means that the DSA does not point to a valid control 
@@ -5744,7 +5699,7 @@ static void ncr_int_ma (struct ncb *np)
 	} else {
 		tblp = (u32 *) 0;
 		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
-	};
+	}
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
@@ -5752,16 +5707,15 @@ static void ncr_int_ma (struct ncb *np)
 			tblp,
 			(unsigned) olen,
 			(unsigned) oadr);
-	};
+	}
 
 	/*
 	**	check cmd against assumed interrupted script command.
 	*/
 
 	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
-		PRINT_ADDR(cp->cmd);
-		printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
-			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
+		PRINT_ADDR(cp->cmd, "internal error: cmd=%02x != %02x=(vdsp[0] "
+				">> 24)\n", cmd, scr_to_cpu(vdsp[0]) >> 24);
 
 		goto reset_all;
 	}
@@ -5783,12 +5737,11 @@ static void ncr_int_ma (struct ncb *np)
 	*/
 
 	if (cmd & 0x06) {
-		PRINT_ADDR(cp->cmd);
-		printk ("phase change %x-%x %d@%08x resid=%d.\n",
+		PRINT_ADDR(cp->cmd, "phase change %x-%x %d@%08x resid=%d.\n",
 			cmd&7, sbcl&7, (unsigned)olen,
 			(unsigned)oadr, (unsigned)rest);
 		goto unexpected_phase;
-	};
+	}
 
 	/*
 	**	choose the correct patch area.
@@ -5812,8 +5765,7 @@ static void ncr_int_ma (struct ncb *np)
 	newcmd[3] = cpu_to_scr(nxtdsp);
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
-		PRINT_ADDR(cp->cmd);
-		printk ("newcmd[%d] %x %x %x %x.\n",
+		PRINT_ADDR(cp->cmd, "newcmd[%d] %x %x %x %x.\n",
 			(int) (newcmd - cp->patch),
 			(unsigned)scr_to_cpu(newcmd[0]),
 			(unsigned)scr_to_cpu(newcmd[1]),
@@ -5939,9 +5891,8 @@ static void ncr_sir_to_redo(struct ncb *
 		if (!lp)
 			goto out;
 		if (bootverbose >= 1) {
-			PRINT_ADDR(cmd);
-			printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n",
-				busy_cnt, disc_cnt);
+			PRINT_ADDR(cmd, "QUEUE FULL! %d busy, %d disconnected "
+					"CCBs\n", busy_cnt, disc_cnt);
 		}
 		if (disc_cnt < lp->numtags) {
 			lp->numtags	= disc_cnt > 2 ? disc_cnt : 2;
@@ -5978,7 +5929,7 @@ static void ncr_sir_to_redo(struct ncb *
 		**
 		**	identify message
 		*/
-		cp->scsi_smsg2[0]	= M_IDENTIFY | cmd->device->lun;
+		cp->scsi_smsg2[0]	= IDENTIFY(0, cmd->device->lun);
 		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
 		cp->phys.smsg.size	= cpu_to_scr(1);
 
@@ -6048,34 +5999,6 @@ out:
 **==========================================================
 */
 
-static int ncr_show_msg (u_char * msg)
-{
-	u_char i;
-	printk ("%x",*msg);
-	if (*msg==M_EXTENDED) {
-		for (i=1;i<8;i++) {
-			if (i-1>msg[1]) break;
-			printk ("-%x",msg[i]);
-		};
-		return (i+1);
-	} else if ((*msg & 0xf0) == 0x20) {
-		printk ("-%x",msg[1]);
-		return (2);
-	};
-	return (1);
-}
-
-static void ncr_print_msg ( struct ccb *cp, char *label, u_char *msg)
-{
-	if (cp)
-		PRINT_ADDR(cp->cmd);
-	if (label)
-		printk("%s: ", label);
-	
-	(void) ncr_show_msg (msg);
-	printk(".\n");
-}
-
 void ncr_int_sir (struct ncb *np)
 {
 	u_char scntl3;
@@ -6230,10 +6153,9 @@ void ncr_int_sir (struct ncb *np)
 		*/
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("negotiation failed sir=%x status=%x.\n",
-				num, cp->nego_status);
-		};
+			PRINT_ADDR(cp->cmd, "negotiation failed sir=%x "
+					"status=%x.\n", num, cp->nego_status);
+		}
 
 		/*
 		**	any error in negotiation:
@@ -6242,37 +6164,26 @@ void ncr_int_sir (struct ncb *np)
 		switch (cp->nego_status) {
 
 		case NS_SYNC:
-			ncr_setsync (np, cp, 0, 0xe0);
 			spi_period(starget) = 0;
 			spi_offset(starget) = 0;
+			ncr_setsync (np, cp, 0, 0xe0);
 			break;
 
 		case NS_WIDE:
-			ncr_setwide (np, cp, 0, 0);
 			spi_width(starget) = 0;
+			ncr_setwide (np, cp, 0, 0);
 			break;
 
-		};
+		}
 		np->msgin [0] = M_NOOP;
 		np->msgout[0] = M_NOOP;
 		cp->nego_status = 0;
 		break;
 
 	case SIR_NEGO_SYNC:
-		/*
-		**	Synchronous request message received.
-		*/
-
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
-
-		/*
-		**	get requested values.
-		*/
+			ncr_print_msg(cp, "sync msgin", np->msgin);
+		}
 
 		chg = 0;
 		per = np->msgin[3];
@@ -6284,8 +6195,8 @@ void ncr_int_sir (struct ncb *np)
 		**	      it CAN transfer synch.
 		*/
 
-		if (ofs && tp->starget)
-			spi_support_sync(tp->starget) = 1;
+		if (ofs && starget)
+			spi_support_sync(starget) = 1;
 
 		/*
 		**	check values against driver limits.
@@ -6318,9 +6229,8 @@ void ncr_int_sir (struct ncb *np)
 		}
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
-				per, scntl3, ofs, fak, chg);
+			PRINT_ADDR(cp->cmd, "sync: per=%d scntl3=0x%x ofs=%d "
+				"fak=%d chg=%d.\n", per, scntl3, ofs, fak, chg);
 		}
 
 		if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -6328,43 +6238,37 @@ void ncr_int_sir (struct ncb *np)
 			switch (cp->nego_status) {
 
 			case NS_SYNC:
-				/*
-				**      This was an answer message
-				*/
+				/* This was an answer message */
 				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setsync (np, cp, 0, 0xe0);
+					/* Answer wasn't acceptable.  */
 					spi_period(starget) = 0;
 					spi_offset(starget) = 0;
-					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
+					ncr_setsync(np, cp, 0, 0xe0);
+					OUTL_DSP(NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+					/* Answer is ok.  */
 					spi_period(starget) = per;
 					spi_offset(starget) = ofs;
-					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
-				};
+					ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
+					OUTL_DSP(NCB_SCRIPT_PHYS (np, clrack));
+				}
 				return;
 
 			case NS_WIDE:
-				ncr_setwide (np, cp, 0, 0);
 				spi_width(starget) = 0;
+				ncr_setwide(np, cp, 0, 0);
 				break;
-			};
-		};
+			}
+		}
 
 		/*
 		**	It was a request. Set value and
 		**      prepare an answer message
 		*/
 
-		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
 		spi_period(starget) = per;
 		spi_offset(starget) = ofs;
+		ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 3;
@@ -6375,10 +6279,7 @@ void ncr_int_sir (struct ncb *np)
 		cp->nego_status = NS_SYNC;
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			(void) ncr_show_msg (np->msgout);
-			printk (".\n");
+			ncr_print_msg(cp, "sync msgout", np->msgout);
 		}
 
 		if (!ofs) {
@@ -6394,11 +6295,8 @@ void ncr_int_sir (struct ncb *np)
 		**	Wide request message received.
 		*/
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+			ncr_print_msg(cp, "wide msgin", np->msgin);
+		}
 
 		/*
 		**	get requested values.
@@ -6412,8 +6310,8 @@ void ncr_int_sir (struct ncb *np)
 		**	      it CAN transfer wide.
 		*/
 
-		if (wide && tp->starget)
-			spi_support_wide(tp->starget) = 1;
+		if (wide && starget)
+			spi_support_wide(starget) = 1;
 
 		/*
 		**	check values against driver limits.
@@ -6423,8 +6321,8 @@ void ncr_int_sir (struct ncb *np)
 			{chg = 1; wide = tp->usrwide;}
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide: wide=%d chg=%d.\n", wide, chg);
+			PRINT_ADDR(cp->cmd, "wide: wide=%d chg=%d.\n", wide,
+					chg);
 		}
 
 		if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -6436,37 +6334,33 @@ void ncr_int_sir (struct ncb *np)
 				**      This was an answer message
 				*/
 				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setwide (np, cp, 0, 1);
+					/* Answer wasn't acceptable.  */
 					spi_width(starget) = 0;
+					ncr_setwide(np, cp, 0, 1);
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setwide (np, cp, wide, 1);
+					/* Answer is ok.  */
 					spi_width(starget) = wide;
+					ncr_setwide(np, cp, wide, 1);
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
-				};
+				}
 				return;
 
 			case NS_SYNC:
-				ncr_setsync (np, cp, 0, 0xe0);
 				spi_period(starget) = 0;
 				spi_offset(starget) = 0;
+				ncr_setsync(np, cp, 0, 0xe0);
 				break;
-			};
-		};
+			}
+		}
 
 		/*
 		**	It was a request, set value and
 		**      prepare an answer message
 		*/
 
-		ncr_setwide (np, cp, wide, 1);
 		spi_width(starget) = wide;
+		ncr_setwide(np, cp, wide, 1);
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 2;
@@ -6478,10 +6372,7 @@ void ncr_int_sir (struct ncb *np)
 		cp->nego_status = NS_WIDE;
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
+			ncr_print_msg(cp, "wide msgout", np->msgin);
 		}
 		break;
 
@@ -6500,8 +6391,7 @@ void ncr_int_sir (struct ncb *np)
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT received (%x:%x).\n",
+		PRINT_ADDR(cp->cmd, "M_REJECT received (%x:%x).\n",
 			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
 		break;
 
@@ -6513,10 +6403,7 @@ void ncr_int_sir (struct ncb *np)
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT sent for ");
-		(void) ncr_show_msg (np->msgin);
-		printk (".\n");
+		ncr_print_msg(cp, "M_REJECT sent for", np->msgin);
 		break;
 
 /*--------------------------------------------------------------------
@@ -6535,8 +6422,8 @@ void ncr_int_sir (struct ncb *np)
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
+		PRINT_ADDR(cp->cmd, "M_IGN_RESIDUE received, but not yet "
+				"implemented.\n");
 		break;
 #if 0
 	case SIR_MISSING_SAVE:
@@ -6548,15 +6435,14 @@ void ncr_int_sir (struct ncb *np)
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_DISCONNECT received, but datapointer not saved: "
-			"data=%x save=%x goal=%x.\n",
+		PRINT_ADDR(cp->cmd, "M_DISCONNECT received, but datapointer "
+				"not saved: data=%x save=%x goal=%x.\n",
 			(unsigned) INL (nc_temp),
 			(unsigned) scr_to_cpu(np->header.savep),
 			(unsigned) scr_to_cpu(np->header.goalp));
 		break;
 #endif
-	};
+	}
 
 out:
 	OUTONB_STD ();
@@ -6571,8 +6457,10 @@ out:
 **==========================================================
 */
 
-static	struct ccb *ncr_get_ccb (struct ncb *np, u_char tn, u_char ln)
+static struct ccb *ncr_get_ccb(struct ncb *np, struct scsi_cmnd *cmd)
 {
+	u_char tn = cmd->device->id;
+	u_char ln = cmd->device->lun;
 	struct tcb *tp = &np->target[tn];
 	struct lcb *lp = tp->lp[ln];
 	u_char tag = NO_TAG;
@@ -6602,8 +6490,8 @@ static	struct ccb *ncr_get_ccb (struct n
 		if (qp) {
 			cp = list_entry(qp, struct ccb, link_ccbq);
 			if (cp->magic) {
-				PRINT_LUN(np, tn, ln);
-				printk ("ccb free list corrupted (@%p)\n", cp);
+				PRINT_ADDR(cmd, "ccb free list corrupted "
+						"(@%p)\n", cp);
 				cp = NULL;
 			} else {
 				list_add_tail(qp, &lp->wait_ccbq);
@@ -6637,7 +6525,7 @@ static	struct ccb *ncr_get_ccb (struct n
 		if (flags & SCSI_NOSLEEP) break;
 		if (tsleep ((caddr_t)cp, PRIBIO|PCATCH, "ncr", 0))
 			break;
-	};
+	}
 #endif
 
 	if (cp->magic)
@@ -6665,8 +6553,7 @@ static	struct ccb *ncr_get_ccb (struct n
 	cp->lun    = ln;
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
-		PRINT_LUN(np, tn, ln);
-		printk ("ccb @%p using tag %d.\n", cp, tag);
+		PRINT_ADDR(cmd, "ccb @%p using tag %d.\n", cp, tag);
 	}
 
 	return cp;
@@ -6687,8 +6574,7 @@ static void ncr_free_ccb (struct ncb *np
 	struct lcb *lp = tp->lp[cp->lun];
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
-		PRINT_LUN(np, cp->target, cp->lun);
-		printk ("ccb @%p freeing tag %d.\n", cp, cp->tag);
+		PRINT_ADDR(cp->cmd, "ccb @%p freeing tag %d.\n", cp, cp->tag);
 	}
 
 	/*
@@ -7014,21 +6900,12 @@ static struct lcb *ncr_setup_lcb (struct
 	unsigned char tn = sdev->id, ln = sdev->lun;
 	struct tcb *tp = &np->target[tn];
 	struct lcb *lp = tp->lp[ln];
-	struct scsi_target *starget = tp->starget;
 
-	/*
-	**	If no lcb, try to allocate it.
-	*/
+	/* If no lcb, try to allocate it.  */
 	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
 		goto fail;
 
 	/*
-	**	Prepare negotiation
-	*/
-	if (spi_support_wide(starget) || spi_support_sync(starget))
-		ncr_negotiate(np, tp);
-
-	/*
 	**	If unit supports tagged commands, allocate the 
 	**	CCB JUMP table if not yet.
 	*/
@@ -7170,7 +7047,7 @@ static int __init ncr_regtest (struct nc
 		printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
 			(unsigned) data);
 		return (0x10);
-	};
+	}
 	return (0);
 }
 
@@ -7223,7 +7100,7 @@ static int __init ncr_snooptest (struct 
 	if (i>=NCR_SNOOP_TIMEOUT) {
 		printk ("CACHE TEST FAILED: timeout.\n");
 		return (0x20);
-	};
+	}
 	/*
 	**	Check termination position.
 	*/
@@ -7233,7 +7110,7 @@ static int __init ncr_snooptest (struct 
 			(u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc,
 			(u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
 		return (0x40);
-	};
+	}
 	/*
 	**	Show results.
 	*/
@@ -7241,17 +7118,17 @@ static int __init ncr_snooptest (struct 
 		printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
 			(int) host_wr, (int) ncr_rd);
 		err |= 1;
-	};
+	}
 	if (host_rd != ncr_wr) {
 		printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
 			(int) ncr_wr, (int) host_rd);
 		err |= 2;
-	};
+	}
 	if (ncr_bk != ncr_wr) {
 		printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
 			(int) ncr_wr, (int) ncr_bk);
 		err |= 4;
-	};
+	}
 	return (err);
 }
 
@@ -7424,6 +7301,16 @@ static void __init ncr_getclock (struct 
 
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
 
+static int ncr53c8xx_slave_alloc(struct scsi_device *device)
+{
+	struct Scsi_Host *host = device->host;
+	struct ncb *np = ((struct host_data *) host->hostdata)->ncb;
+	struct tcb *tp = &np->target[device->id];
+	tp->starget = device->sdev_target;
+
+	return 0;
+}
+
 static int ncr53c8xx_slave_configure(struct scsi_device *device)
 {
 	struct Scsi_Host *host = device->host;
@@ -7432,8 +7319,6 @@ static int ncr53c8xx_slave_configure(str
 	struct lcb *lp = tp->lp[device->lun];
 	int numtags, depth_to_use;
 
-	tp->starget = device->sdev_target;
-
 	ncr_setup_lcb(np, device);
 
 	/*
@@ -7601,24 +7486,14 @@ static int ncr53c8xx_abort(struct scsi_c
 	struct scsi_cmnd *done_list;
 
 #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-	printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n",
-		cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout);
+	printk("ncr53c8xx_abort: pid=%lu serial_number=%ld\n",
+		cmd->pid, cmd->serial_number);
 #else
 	printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
 #endif
 
 	NCR_LOCK_NCB(np, flags);
 
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-	/*
-	 * We have to just ignore abort requests in some situations.
-	 */
-	if (cmd->serial_number != cmd->serial_number_at_timeout) {
-		sts = SCSI_ABORT_NOT_RUNNING;
-		goto out;
-	}
-#endif
-
 	sts = ncr_abort_command(np, cmd);
 out:
 	done_list     = np->done_list;
@@ -7778,6 +7653,7 @@ struct Scsi_Host * __init ncr_attach(str
 
 	tpnt->queuecommand	= ncr53c8xx_queue_command;
 	tpnt->slave_configure	= ncr53c8xx_slave_configure;
+	tpnt->slave_alloc	= ncr53c8xx_slave_alloc;
 	tpnt->eh_bus_reset_handler = ncr53c8xx_bus_reset;
 	tpnt->can_queue		= SCSI_NCR_CAN_QUEUE;
 	tpnt->this_id		= 7;
@@ -7925,7 +7801,7 @@ struct Scsi_Host * __init ncr_attach(str
 	if (ncr_snooptest(np)) {
 		printk(KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n");
 		goto attach_error;
-	};
+	}
 
 	/* Install the interrupt handler.  */
 	np->irq = device->slot.irq;
@@ -8057,6 +7933,25 @@ static void ncr53c8xx_set_width(struct s
 	ncr_negotiate(np, tp);
 }
 
+static void ncr53c8xx_get_signalling(struct Scsi_Host *shost)
+{
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	enum spi_signal_type type;
+
+	switch (np->scsi_mode) {
+	case SMODE_SE:
+		type = SPI_SIGNAL_SE;
+		break;
+	case SMODE_HVD:
+		type = SPI_SIGNAL_HVD;
+		break;
+	default:
+		type = SPI_SIGNAL_UNKNOWN;
+		break;
+	}
+	spi_signalling(shost) = type;
+}
+
 static struct spi_function_template ncr53c8xx_transport_functions =  {
 	.set_period	= ncr53c8xx_set_period,
 	.show_period	= 1,
@@ -8064,6 +7959,7 @@ static struct spi_function_template ncr5
 	.show_offset	= 1,
 	.set_width	= ncr53c8xx_set_width,
 	.show_width	= 1,
+	.get_signalling	= ncr53c8xx_get_signalling,
 };
 
 int __init ncr53c8xx_init(void)
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -3435,7 +3435,7 @@ static int nsp32_prom_read_bit(nsp32_hw_
 #ifdef CONFIG_PM
 
 /* Device suspended */
-static int nsp32_suspend(struct pci_dev *pdev, u32 state)
+static int nsp32_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 
@@ -3443,7 +3443,7 @@ static int nsp32_suspend(struct pci_dev 
 
 	pci_save_state     (pdev);
 	pci_disable_device (pdev);
-	pci_set_power_state(pdev, state);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
 	return 0;
 }
@@ -3457,8 +3457,8 @@ static int nsp32_resume(struct pci_dev *
 
 	nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host);
 
-	pci_set_power_state(pdev, 0);
-	pci_enable_wake    (pdev, 0, 0);
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake    (pdev, PCI_D0, 0);
 	pci_restore_state  (pdev);
 
 	reg = nsp32_read2(data->BaseAddress, INDEX_REG);
@@ -3479,7 +3479,7 @@ static int nsp32_resume(struct pci_dev *
 }
 
 /* Enable wake event */
-static int nsp32_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+static int nsp32_enable_wake(struct pci_dev *pdev, pci_power_t state, int enable)
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -24,7 +24,7 @@
 */
 
 static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
-const char * osst_version = "0.99.3";
+static const char * osst_version = "0.99.3";
 
 /* The "failure to reconnect" firmware bug */
 #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
@@ -170,7 +170,7 @@ static int osst_copy_from_buffer(struct 
 static int osst_probe(struct device *);
 static int osst_remove(struct device *);
 
-struct scsi_driver osst_template = {
+static struct scsi_driver osst_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		=  "osst",
@@ -4318,7 +4318,13 @@ static int os_scsi_tape_open(struct inod
 	int		      dev  = TAPE_NR(inode);
 	int		      mode = TAPE_MODE(inode);
 
-	nonseekable_open(inode, filp);
+	/*
+	 * We really want to do nonseekable_open(inode, filp); here, but some
+	 * versions of tar incorrectly call lseek on tapes and bail out if that
+	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+	 */
+	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
 	write_lock(&os_scsi_tapes_lock);
 	if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
 	    (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
@@ -4764,9 +4770,6 @@ static int os_scsi_tape_close(struct ino
 {
 	int		      result = 0;
 	struct osst_tape    * STp    = filp->private_data;
-	struct scsi_request * SRpnt  = NULL;
-
-	if (SRpnt) scsi_release_request(SRpnt);
 
 	if (STp->door_locked == ST_LOCKED_AUTO)
 		do_door_lock(STp, 0);
@@ -5121,6 +5124,22 @@ out:
 	return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
+{
+	struct osst_tape *STp = file->private_data;
+	struct scsi_device *sdev = STp->device;
+	int ret = -ENOIOCTLCMD;
+	if (sdev->host->hostt->compat_ioctl) {
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
+
+	}
+	return ret;
+}
+#endif
+
+
 
 /* Memory handling routines */
 
@@ -5456,6 +5475,9 @@ static struct file_operations osst_fops 
 	.read =         osst_read,
 	.write =        osst_write,
 	.ioctl =        osst_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = osst_compat_ioctl,
+#endif
 	.open =         os_scsi_tape_open,
 	.flush =        os_scsi_tape_flush,
 	.release =      os_scsi_tape_close,
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -137,7 +137,7 @@ static unsigned short pas16_addr = 0;
 static int pas16_irq = 0;
  
 
-int scsi_irq_translate[] =
+static const int scsi_irq_translate[] =
 	{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
 
 /* The default_irqs array contains values used to set the irq into the
@@ -145,7 +145,7 @@ int scsi_irq_translate[] =
  * irq jumpers on the board).  The first value in the array will be
  * assigned to logical board 0, the next to board 1, etc.
  */
-int default_irqs[] __initdata = 
+static int default_irqs[] __initdata =
 	{  PAS16_DEFAULT_BOARD_1_IRQ,
 	   PAS16_DEFAULT_BOARD_2_IRQ,
 	   PAS16_DEFAULT_BOARD_3_IRQ,
@@ -177,7 +177,7 @@ static struct base {
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
-unsigned short  pas16_offset[ 8 ] =
+static const unsigned short  pas16_offset[ 8 ] =
     {
 	0x1c00,    /* OUTPUT_DATA_REG */
 	0x1c01,    /* INITIATOR_COMMAND_REG */
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -209,7 +209,7 @@ static int BuildSgList (Scsi_Cmnd *SCpnt
 	if ( SCpnt->use_sg )
 		{
 		sg = (struct scatterlist *)SCpnt->request_buffer;
-		zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+		zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, SCpnt->sc_data_direction);
 		for ( z = 0;  z < zc;  z++ )
 			{
 			pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg));
@@ -225,7 +225,9 @@ static int BuildSgList (Scsi_Cmnd *SCpnt
 		outl (0, padapter->mb3);
 		return TRUE;
 		}
-	SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+	SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev,
+			SCpnt->request_buffer, SCpnt->request_bufflen,
+			SCpnt->sc_data_direction);
 	outl (SCpnt->SCp.have_data_in, padapter->mb2);
 	outl (SCpnt->request_bufflen, padapter->mb3);
 	return TRUE;
@@ -340,11 +342,11 @@ unmapProceed:;
 			}
 		}
 	if ( SCpnt->SCp.have_data_in )
-		pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, SCpnt->sc_data_direction);
 	else 
 		{
 		if ( SCpnt->use_sg )
-			pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction);
 		}
 
 irqProceed:;
@@ -438,8 +440,8 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCp
 	if ( bus )
 		{
 		DEB (if(*cdb) printk ("\nCDB: %X-  %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));
-		DEB (if(*cdb) printk ("\ntimeout_per_command: %d, timeout_total: %d, timeout: %d, internal_timout: %d", SCpnt->timeout_per_command,
-							  SCpnt->timeout_total, SCpnt->timeout, SCpnt->internal_timeout));
+		DEB (if(*cdb) printk ("\ntimeout_per_command: %d, timeout_total: %d, timeout: %d", SCpnt->timeout_per_command,
+							  SCpnt->timeout_total, SCpnt->timeout));
 		outl (SCpnt->timeout_per_command, padapter->mb1);
 		outb_p (CMD_SCSI_TIMEOUT, padapter->cmd);
 		if ( WaitReady (padapter) )
@@ -495,7 +497,7 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCp
 						else
 							{
 							SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen,
-													  scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+													  SCpnt->sc_data_direction);
 							outl (SCpnt->SCp.have_data_in, padapter->mb2);
 							}
 						outl (cdb[5], padapter->mb0);
@@ -511,13 +513,13 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCp
 				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev,
 									  ((struct scatterlist *)SCpnt->request_buffer)->address,
 									  SCpnt->request_bufflen,
-									  scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+									  SCpnt->sc_data_direction);
 				}
 			else
 				{
 				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer,
 									  SCpnt->request_bufflen,
-									  scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+									  SCpnt->sc_data_direction);
 				}
 			outl (SCpnt->SCp.have_data_in, padapter->mb2);
 			outl (SCpnt->request_bufflen, padapter->mb3);
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -45,7 +45,7 @@ static struct ctrl_inquiry {
 	Scsi_Cmnd cmd;
 	char inquiry[256];
 	fc_channel *fc;
-} *fcs __initdata = { 0 };
+} *fcs __initdata;
 static int fcscount __initdata = 0;
 static atomic_t fcss __initdata = ATOMIC_INIT(0);
 DECLARE_MUTEX_LOCKED(fc_sem);
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -390,7 +390,7 @@ static irqreturn_t do_Irq_Handler (int i
  *	Returns:		Status code.
  *
  ****************************************************************/
-int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 	{
 	UCHAR		   *cdb = (UCHAR *)SCpnt->cmnd;					// Pointer to SCSI CDB
 	PADAPTER240I	padapter = HOSTDATA (SCpnt->device->host); 			// Pointer to adapter control structure
@@ -509,7 +509,7 @@ int Psi240i_QueueCommand (Scsi_Cmnd *SCp
  *	Returns:		Nothing.
  *
  **************************************************************************/
-void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
+static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
 	{
 	USHORT	z, zz;
 	UCHAR	*pd = (UCHAR *)pdata;
@@ -538,7 +538,7 @@ void ReadChipMemory (void *pdata, USHORT
  *	Returns:		Number of adapters found.
  *
  ****************************************************************/
-int Psi240i_Detect (Scsi_Host_Template *tpnt)
+static int Psi240i_Detect (Scsi_Host_Template *tpnt)
 	{
 	int					board;
 	int					count = 0;
@@ -654,7 +654,7 @@ static int Psi240i_Release(struct Scsi_H
  *	Returns:		zero.
  *
  ****************************************************************/
-int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
+static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
 		sector_t capacity, int geom[])
 	{
 	POUR_DEVICE	pdev;
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
--- a/drivers/scsi/psi240i.h
+++ b/drivers/scsi/psi240i.h
@@ -309,11 +309,7 @@ typedef struct _IDENTIFY_DATA2 {
 #endif	// PSI_EIDE_SCSIOP
 
 // function prototypes
-int Psi240i_Detect			(Scsi_Host_Template *tpnt);
 int Psi240i_Command			(Scsi_Cmnd *SCpnt);
-int Psi240i_QueueCommand	(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 int Psi240i_Abort			(Scsi_Cmnd *SCpnt);
 int Psi240i_Reset			(Scsi_Cmnd *SCpnt, unsigned int flags);
-int Psi240i_BiosParam		(struct scsi_device *sdev, struct block_device *bdev,
-					sector_t capacity, int geom[]);
 #endif
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -20,6 +20,9 @@
 #define QLA1280_VERSION      "3.25"
 /*****************************************************************************
     Revision History:
+    Rev  3.25.1, February 10, 2005 Christoph Hellwig
+	- use pci_map_single to map non-S/G requests
+	- remove qla1280_proc_info
     Rev  3.25, September 28, 2004, Christoph Hellwig
 	- add support for ISP1020/1040
 	- don't include "scsi.h" anymore for 2.6.x
@@ -670,8 +673,6 @@ static struct qla_boards ql1280_board_tb
 };
 
 static int qla1280_verbose = 1;
-static int qla1280_buffer_size;
-static char *qla1280_buffer;
 
 #if DEBUG_QLA1280
 static int ql_debug_level = 1;
@@ -694,97 +695,6 @@ static int ql_debug_level = 1;
 #define LEAVE_INTR(x)		dprintk(4, "qla1280 : Leaving %s()\n", x);
 
 
-/*************************************************************************
- * qla1280_proc_info
- *
- * Description:
- *   Return information to handle /proc support for the driver.
- *
- * buffer - ptrs to a page buffer
- *
- * Returns:
- *************************************************************************/
-#define	PROC_BUF	&qla1280_buffer[len]
-
-static int qla1280_proc_info(struct Scsi_Host *host, char *buffer,
-			     char **start, off_t offset, int length, int inout)
-{
-	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-	struct qla_boards *bdp = &ql1280_board_tbl[ha->devnum];
-	int size = 0;
-	int len = 0;
-
-	if (inout)
-		return -ENOSYS;
-
-	/*
-	 * if our old buffer is the right size use it otherwise
-	 * allocate a new one.
-	 */
-	if (qla1280_buffer_size != PAGE_SIZE) {
-		/* deallocate this buffer and get a new one */
-		if (qla1280_buffer != NULL) {
-			free_page((unsigned long)qla1280_buffer);
-			qla1280_buffer_size = 0;
-		}
-		qla1280_buffer = (char *)get_zeroed_page(GFP_KERNEL);
-	}
-	if (qla1280_buffer == NULL) {
-		size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n",
-			       __LINE__);
-		return size;
-	}
-	/* save the size of our buffer */
-	qla1280_buffer_size = PAGE_SIZE;
-
-	/* 3.20 clear the buffer we use for proc display */
-	memset(qla1280_buffer, 0, PAGE_SIZE);
-
-	/* start building the print buffer */
-	size = sprintf(PROC_BUF,
-		       "QLogic PCI to SCSI Adapter for ISP 1280/12160:\n"
-		       "        Firmware version: %2d.%02d.%02d, Driver version %s\n",
-		       bdp->fwver[0], bdp->fwver[1], bdp->fwver[2],
-		       QLA1280_VERSION);
-
-	len += size;
-
-	size = sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n",
-		       bdp->name);
-	len += size;
-	size = sprintf(PROC_BUF, "Request Queue count= 0x%x, Response "
-		       "Queue count= 0x%x\n",
-		       REQUEST_ENTRY_CNT, RESPONSE_ENTRY_CNT);
-	len += size;
-	size = sprintf(PROC_BUF, "Number of pending commands = 0x%lx\n",
-		       ha->actthreads);
-	len += size;
-	size = sprintf(PROC_BUF, "Number of free request entries = %d\n",
-		       ha->req_q_cnt);
-	len += size;
-	size = sprintf(PROC_BUF, "\n");	/* 1       */
-	len += size;
-
-	if (len >= qla1280_buffer_size) {
-		printk(KERN_WARNING
-		       "qla1280: Overflow buffer in qla1280_proc.c\n");
-	}
-
-	if (offset > len - 1) {
-		free_page((unsigned long) qla1280_buffer);
-		qla1280_buffer = NULL;
-		qla1280_buffer_size = length = 0;
-		*start = NULL;
-	} else {
-		*start = &qla1280_buffer[offset];	/* Start of wanted data */
-		if (len - offset < length) {
-			length = len - offset;
-		}
-	}
-	return length;
-}
-
-
 static int qla1280_read_nvram(struct scsi_qla_host *ha)
 {
 	uint16_t *wptr;
@@ -1334,22 +1244,6 @@ qla1280_biosparam_old(Disk * disk, kdev_
 {
 	return qla1280_biosparam(disk->device, NULL, disk->capacity, geom);
 }
-
-static int
-qla1280_proc_info_old(char *buffer, char **start, off_t offset, int length,
-		      int hostno, int inout)
-{
-	struct Scsi_Host *host;
-
-	for (host = scsi_hostlist; host; host = host->next) {
-		if (host->host_no == hostno) {
-			return qla1280_proc_info(host, buffer, start,
-						 offset, length, inout);
-		}
-	}
-
-	return -ESRCH;
-}
 #endif
 
 /**************************************************************************
@@ -1571,16 +1465,12 @@ qla1280_done(struct scsi_qla_host *ha)
 
 		/* Release memory used for this I/O */
 		if (cmd->use_sg) {
-			dprintk(3, "S/G unmap_sg cmd=%p\n", cmd);
-
 			pci_unmap_sg(ha->pdev, cmd->request_buffer,
-				     cmd->use_sg, cmd->sc_data_direction);
+					cmd->use_sg, cmd->sc_data_direction);
 		} else if (cmd->request_bufflen) {
-			/*dprintk(1, "No S/G unmap_single cmd=%x saved_dma_handle=%lx\n",
-			  cmd, sp->saved_dma_handle); */
-
-			pci_unmap_page(ha->pdev, sp->saved_dma_handle,
-				       cmd->request_bufflen, cmd->sc_data_direction);
+			pci_unmap_single(ha->pdev, sp->saved_dma_handle,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
 		}
 
 		/* Call the mid-level driver interrupt handler */
@@ -3354,14 +3244,11 @@ qla1280_64bit_start_scsi(struct scsi_qla
 						    REQUEST_ENTRY_SIZE);
 			}
 		} else {	/* No scatter gather data transfer */
-			struct page *page = virt_to_page(cmd->request_buffer);
-			unsigned long off = (unsigned long)cmd->request_buffer & ~PAGE_MASK;
-
-			dma_handle = pci_map_page(ha->pdev, page, off,
-						  cmd->request_bufflen,
-						  cmd->sc_data_direction);
+			dma_handle = pci_map_single(ha->pdev,
+					cmd->request_buffer,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
 
-			/* save dma_handle for pci_unmap_page */
 			sp->saved_dma_handle = dma_handle;
 #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
 			if (ha->flags.use_pci_vchannel)
@@ -3636,11 +3523,10 @@ qla1280_32bit_start_scsi(struct scsi_qla
 						    REQUEST_ENTRY_SIZE);
 			}
 		} else {	/* No S/G data transfer */
-			struct page *page = virt_to_page(cmd->request_buffer);
-			unsigned long off = (unsigned long)cmd->request_buffer & ~PAGE_MASK;
-			dma_handle = pci_map_page(ha->pdev, page, off,
-						  cmd->request_bufflen,
-						  cmd->sc_data_direction);
+			dma_handle = pci_map_single(ha->pdev,
+					cmd->request_buffer,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
 			sp->saved_dma_handle = dma_handle;
 
 			*dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle));
@@ -4668,7 +4554,6 @@ static struct scsi_host_template qla1280
 	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
 	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
 	.bios_param		= qla1280_biosparam,
-	.proc_info		= qla1280_proc_info,
 	.can_queue		= 0xfffff,
 	.this_id		= -1,
 	.sg_tablesize		= SG_ALL,
@@ -4688,7 +4573,6 @@ static Scsi_Host_Template qla1280_driver
 	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
 	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
 	.bios_param		= qla1280_biosparam_old,
-	.proc_info		= qla1280_proc_info_old,
 	.can_queue		= 0xfffff,
 	.this_id		= -1,
 	.sg_tablesize		= SG_ALL,
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,7 +1,7 @@
 EXTRA_CFLAGS += -DUNIQUE_FW_NAME
 
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
-		qla_dbg.o qla_sup.o qla_rscn.o
+		qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o
 
 qla2100-y := ql2100.o ql2100_fw.o
 qla2200-y := ql2200.o ql2200_fw.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
new file mode 100644
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -0,0 +1,332 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2005 QLogic Corporation
+ * (www.qlogic.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.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/vmalloc.h>
+#include <scsi/scsi_transport_fc.h>
+
+/* SYSFS attributes --------------------------------------------------------- */
+
+static ssize_t
+qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+
+	if (ha->fw_dump_reading == 0)
+		return 0;
+	if (off > ha->fw_dump_buffer_len)
+		return 0;
+	if (off + count > ha->fw_dump_buffer_len)
+		count = ha->fw_dump_buffer_len - off;
+
+	memcpy(buf, &ha->fw_dump_buffer[off], count);
+
+	return (count);
+}
+
+static ssize_t
+qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	int reading;
+	uint32_t dump_size;
+
+	if (off != 0)
+		return (0);
+
+	reading = simple_strtol(buf, NULL, 10);
+	switch (reading) {
+	case 0:
+		if (ha->fw_dump_reading == 1) {
+			qla_printk(KERN_INFO, ha,
+			    "Firmware dump cleared on (%ld).\n",
+			    ha->host_no);
+
+			vfree(ha->fw_dump_buffer);
+			free_pages((unsigned long)ha->fw_dump,
+			    ha->fw_dump_order);
+
+			ha->fw_dump_reading = 0;
+			ha->fw_dump_buffer = NULL;
+			ha->fw_dump = NULL;
+		}
+		break;
+	case 1:
+		if (ha->fw_dump != NULL && !ha->fw_dump_reading) {
+			ha->fw_dump_reading = 1;
+
+			dump_size = FW_DUMP_SIZE_1M;
+			if (ha->fw_memory_size < 0x20000) 
+				dump_size = FW_DUMP_SIZE_128K;
+			else if (ha->fw_memory_size < 0x80000) 
+				dump_size = FW_DUMP_SIZE_512K;
+			ha->fw_dump_buffer = (char *)vmalloc(dump_size);
+			if (ha->fw_dump_buffer == NULL) {
+				qla_printk(KERN_WARNING, ha,
+				    "Unable to allocate memory for firmware "
+				    "dump buffer (%d).\n", dump_size);
+
+				ha->fw_dump_reading = 0;
+				return (count);
+			}
+			qla_printk(KERN_INFO, ha,
+			    "Firmware dump ready for read on (%ld).\n",
+			    ha->host_no);
+			memset(ha->fw_dump_buffer, 0, dump_size);
+			if (IS_QLA2100(ha) || IS_QLA2200(ha))
+ 				qla2100_ascii_fw_dump(ha);
+ 			else
+ 				qla2300_ascii_fw_dump(ha);
+			ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
+		}
+		break;
+	}
+	return (count);
+}
+
+static struct bin_attribute sysfs_fw_dump_attr = {
+	.attr = {
+		.name = "fw_dump",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_fw_dump,
+	.write = qla2x00_sysfs_write_fw_dump,
+};
+
+static ssize_t
+qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint16_t	*witer;
+	unsigned long	flags;
+	uint16_t	cnt;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+		return 0;
+
+	/* Read NVRAM. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qla2x00_lock_nvram_access(ha);
+ 	witer = (uint16_t *)buf;
+ 	for (cnt = 0; cnt < count / 2; cnt++) {
+		*witer = cpu_to_le16(qla2x00_get_nvram_word(ha,
+		    cnt+ha->nvram_base));
+		witer++;
+ 	}
+	qla2x00_unlock_nvram_access(ha);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (count);
+}
+
+static ssize_t
+qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint8_t		*iter;
+	uint16_t	*witer;
+	unsigned long	flags;
+	uint16_t	cnt;
+	uint8_t		chksum;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+		return 0;
+
+	/* Checksum NVRAM. */
+	iter = (uint8_t *)buf;
+	chksum = 0;
+	for (cnt = 0; cnt < count - 1; cnt++)
+		chksum += *iter++;
+	chksum = ~chksum + 1;
+	*iter = chksum;
+
+	/* Write NVRAM. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qla2x00_lock_nvram_access(ha);
+	qla2x00_release_nvram_protection(ha);
+ 	witer = (uint16_t *)buf;
+	for (cnt = 0; cnt < count / 2; cnt++) {
+		qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,
+		    cpu_to_le16(*witer));
+		witer++;
+	}
+	qla2x00_unlock_nvram_access(ha);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (count);
+}
+
+static struct bin_attribute sysfs_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = sizeof(nvram_t),
+	.read = qla2x00_sysfs_read_nvram,
+	.write = qla2x00_sysfs_write_nvram,
+};
+
+void
+qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
+{
+	struct Scsi_Host *host = ha->host;
+
+	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
+}
+
+void
+qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
+{
+	struct Scsi_Host *host = ha->host;
+
+	sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+	sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
+}
+
+/* Host attributes. */
+
+static void
+qla2x00_get_host_port_id(struct Scsi_Host *shost)
+{
+	scsi_qla_host_t *ha = to_qla_host(shost);
+
+	fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
+	    ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
+}
+
+static void
+qla2x00_get_starget_node_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(host);
+	fc_port_t *fcport;
+	uint64_t node_name = 0;
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (starget->id == fcport->os_target_id) {
+			node_name = *(uint64_t *)fcport->node_name;
+			break;
+		}
+	}
+
+	fc_starget_node_name(starget) = be64_to_cpu(node_name);
+}
+
+static void
+qla2x00_get_starget_port_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(host);
+	fc_port_t *fcport;
+	uint64_t port_name = 0;
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (starget->id == fcport->os_target_id) {
+			port_name = *(uint64_t *)fcport->port_name;
+			break;
+		}
+	}
+
+	fc_starget_port_name(starget) = be64_to_cpu(port_name);
+}
+
+static void
+qla2x00_get_starget_port_id(struct scsi_target *starget)
+{
+	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(host);
+	fc_port_t *fcport;
+	uint32_t port_id = ~0U;
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (starget->id == fcport->os_target_id) {
+			port_id = fcport->d_id.b.domain << 16 |
+			    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
+			break;
+		}
+	}
+
+	fc_starget_port_id(starget) = port_id;
+}
+
+static void
+qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
+{
+	struct Scsi_Host *host = rport_to_shost(rport);
+	scsi_qla_host_t *ha = to_qla_host(host);
+
+	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+}
+
+static void
+qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	struct Scsi_Host *host = rport_to_shost(rport);
+	scsi_qla_host_t *ha = to_qla_host(host);
+
+	if (timeout)
+		ha->port_down_retry_count = timeout;
+	else
+		ha->port_down_retry_count = 1;
+
+	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+}
+
+struct fc_function_template qla2xxx_transport_functions = {
+
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.get_host_port_id = qla2x00_get_host_port_id,
+	.show_host_port_id = 1,
+
+	.dd_fcrport_size = sizeof(struct fc_port *),
+
+	.get_starget_node_name = qla2x00_get_starget_node_name,
+	.show_starget_node_name = 1,
+	.get_starget_port_name = qla2x00_get_starget_port_name,
+	.show_starget_port_name = 1,
+	.get_starget_port_id  = qla2x00_get_starget_port_id,
+	.show_starget_port_id = 1,
+
+	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
+	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+};
+
+void
+qla2x00_init_host_attr(scsi_qla_host_t *ha)
+{
+	fc_host_node_name(ha->host) =
+	    be64_to_cpu(*(uint64_t *)ha->init_cb->node_name);
+	fc_host_port_name(ha->host) =
+	    be64_to_cpu(*(uint64_t *)ha->init_cb->port_name);
+}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1050,10 +1050,8 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd 
 	for (i = 0; i < cmd->cmd_len; i++) {
 		printk("0x%02x ", cmd->cmnd[i]);
 	}
-	printk("\n  seg_cnt=%d, allowed=%d, retries=%d, "
-	    "serial_number_at_timeout=0x%lx\n",
-	    cmd->use_sg, cmd->allowed, cmd->retries,
-	    cmd->serial_number_at_timeout);
+	printk("\n  seg_cnt=%d, allowed=%d, retries=%d\n",
+	    cmd->use_sg, cmd->allowed, cmd->retries);
 	printk("  request buffer=0x%p, request buffer len=0x%x\n",
 	    cmd->request_buffer, cmd->request_bufflen);
 	printk("  tag=%d, transfersize=0x%x\n",
@@ -1067,11 +1065,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd 
 	printk("  sp flags=0x%x\n", sp->flags);
 	printk("  r_start=0x%lx, u_start=0x%lx, f_start=0x%lx, state=%d\n",
 	    sp->r_start, sp->u_start, sp->f_start, sp->state);
-
-	printk(" e_start= 0x%lx, ext_history=%d, fo retry=%d, loopid=%x, "
-	    "port path=%d\n", sp->e_start, sp->ext_history, sp->fo_retry_cnt,
-	    sp->lun_queue->fclun->fcport->loop_id,
-	    sp->lun_queue->fclun->fcport->cur_path);
 }
 
 #if defined(QL_DEBUG_ROUTINES)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -219,7 +219,7 @@
 /*
  * Timeout timer counts in seconds
  */
-#define PORT_RETRY_TIME			2
+#define PORT_RETRY_TIME			1
 #define LOOP_DOWN_TIMEOUT		60
 #define LOOP_DOWN_TIME			255	/* 240 */
 #define	LOOP_DOWN_RESET			(LOOP_DOWN_TIME - 30)
@@ -241,6 +241,7 @@ typedef struct srb {
 	struct list_head list;
 
 	struct scsi_qla_host *ha;	/* HA the SP is queued on */
+	struct fc_port *fcport;
 
 	struct scsi_cmnd *cmd;		/* Linux SCSI command pkt */
 
@@ -251,11 +252,6 @@ typedef struct srb {
 	/* Request state */
 	uint16_t state;
 
-	/* Target/LUN queue pointers. */
-	struct os_tgt *tgt_queue;	/* ptr to visible ha's target */
-	struct os_lun *lun_queue;	/* ptr to visible ha's lun */
-	struct fc_lun *fclun;		/* FC LUN context pointer. */
-
 	/* Timing counts. */
 	unsigned long e_start;		/* Start of extend timeout */
 	unsigned long r_start;		/* Start of request */
@@ -1603,73 +1599,6 @@ typedef struct {
 } rpt_lun_cmd_rsp_t;
 
 /*
- * SCSI Target Queue structure
- */
-typedef struct os_tgt {
-	struct os_lun *olun[MAX_LUNS]; /* LUN context pointer. */
-	struct fc_port *fcport;
-	unsigned long flags;
-	uint8_t port_down_retry_count;
-    	uint32_t down_timer;
-	struct scsi_qla_host *ha;
-
-	/* Persistent binding information */
-	port_id_t d_id;
-	uint8_t node_name[WWN_SIZE];
-	uint8_t port_name[WWN_SIZE];
-} os_tgt_t;
-
-/*
- * SCSI Target Queue flags
- */
-#define TQF_ONLINE		0		/* Device online to OS. */
-#define TQF_SUSPENDED		1
-#define TQF_RETRY_CMDS		2
-
-/*
- * SCSI LUN Queue structure
- */
-typedef struct os_lun {
-	struct fc_lun *fclun;		/* FC LUN context pointer. */
-    	spinlock_t q_lock;		/* Lun Lock */
-
-	unsigned long q_flag;
-#define LUN_MPIO_RESET_CNTS	1	/* Lun */
-#define LUN_MPIO_BUSY		2	/* Lun is changing paths  */
-#define LUN_EXEC_DELAYED	7	/* Lun execution is delayed */
-
-	u_long q_timeout;		/* total command timeouts */
-	atomic_t q_timer;		/* suspend timer */
-	uint32_t q_count;		/* current count */
-	uint32_t q_max;			/* maxmum count lun can be suspended */
-	uint8_t q_state;		/* lun State */
-#define LUN_STATE_READY		1	/* lun is ready for i/o */
-#define LUN_STATE_RUN		2	/* lun has a timer running */
-#define LUN_STATE_WAIT		3	/* lun is suspended */
-#define LUN_STATE_TIMEOUT	4	/* lun has timed out */
-
-	u_long io_cnt;			/* total xfer count since boot */
-	u_long out_cnt;			/* total outstanding IO count */
-	u_long w_cnt;			/* total writes */
-	u_long r_cnt;			/* total reads */
-	u_long avg_time;		/*  */
-} os_lun_t;
-
-
-/* LUN BitMask structure definition, array of 32bit words,
- * 1 bit per lun.  When bit == 1, the lun is masked.
- * Most significant bit of mask[0] is lun 0, bit 24 is lun 7.
- */
-typedef struct lun_bit_mask {
-	/* Must allocate at least enough bits to accomodate all LUNs */
-#if ((MAX_FIBRE_LUNS & 0x7) == 0)
-	uint8_t mask[MAX_FIBRE_LUNS >> 3];
-#else
-	uint8_t mask[(MAX_FIBRE_LUNS + 8) >> 3];
-#endif
-} lun_bit_mask_t;
-
-/*
  * Fibre channel port type.
  */
  typedef enum {
@@ -1686,8 +1615,6 @@ typedef struct lun_bit_mask {
  */
 typedef struct fc_port {
 	struct list_head list;
-	struct list_head fcluns;
-
 	struct scsi_qla_host *ha;
 	struct scsi_qla_host *vis_ha;	/* only used when suspending lun */
 
@@ -1702,8 +1629,7 @@ typedef struct fc_port {
 	atomic_t state;
 	uint32_t flags;
 
-	os_tgt_t *tgt_queue;
-	uint16_t os_target_id;
+	unsigned int os_target_id;
 
 	uint16_t iodesc_idx_sent;
 
@@ -1717,7 +1643,7 @@ typedef struct fc_port {
 	uint8_t mp_byte;		/* multi-path byte (not used) */
     	uint8_t cur_path;		/* current path id */
 
-	lun_bit_mask_t lun_mask;
+	struct fc_rport *rport;
 } fc_port_t;
 
 /*
@@ -1764,25 +1690,6 @@ typedef struct fc_port {
 #define FC_NO_LOOP_ID		0x1000
 
 /*
- * Fibre channel LUN structure.
- */
-typedef struct fc_lun {
-        struct list_head list;
-
-	fc_port_t *fcport;
-	fc_port_t *o_fcport;
-	uint16_t lun;
-	atomic_t state;
-	uint8_t device_type;
-
-	uint8_t max_path_retries;
-	uint32_t flags;
-} fc_lun_t;
-
-#define	FLF_VISIBLE_LUN		BIT_0
-#define	FLF_ACTIVE_LUN		BIT_1
-
-/*
  * FC-CT interface
  *
  * NOTE: All structures are big-endian in form.
@@ -2175,27 +2082,6 @@ typedef struct scsi_qla_host {
 	uint32_t	current_outstanding_cmd; 
 	srb_t		*status_srb;	/* Status continuation entry. */
 
-	/*
-	 * Need to hold the list_lock with irq's disabled in order to access
-	 * the following list.
-	 *
-	 * This list_lock is of lower priority than the host_lock.
-	 */
-	spinlock_t		list_lock ____cacheline_aligned;
-						/* lock to guard lists which
-						 * hold srb_t's */
-        struct list_head        retry_queue;    /* watchdog queue */
-        struct list_head        done_queue;     /* job on done queue */
-        struct list_head        failover_queue; /* failover list link. */
-	struct list_head        scsi_retry_queue;     /* SCSI retry queue */
-	struct list_head        pending_queue;	/* SCSI command pending queue */
-
-	unsigned long    done_q_cnt;
-	unsigned long    pending_in_q;
-        uint32_t	retry_q_cnt; 
-        uint32_t	scsi_retry_q_cnt; 
-        uint32_t	failover_cnt; 
-
 	unsigned long	last_irq_cpu;	/* cpu where we got our last irq */
 
 	uint16_t           revision;
@@ -2273,9 +2159,6 @@ typedef struct scsi_qla_host {
 	struct io_descriptor	io_descriptors[MAX_IO_DESCRIPTORS];
 	uint16_t		iodesc_signature;
 
-	/* OS target queue pointers. */
-	os_tgt_t		*otgt[MAX_FIBRE_DEVICES];
-
 	/* RSCN queue. */
 	uint32_t rscn_queue[MAX_RSCN_COUNT];
 	uint8_t rscn_in_ptr;
@@ -2420,8 +2303,6 @@ typedef struct scsi_qla_host {
 #define LOOP_RDY(ha)	(!LOOP_NOT_READY(ha))
 
 #define TGT_Q(ha, t) (ha->otgt[t])
-#define LUN_Q(ha, t, l)	(TGT_Q(ha, t)->olun[l])
-#define GET_LU_Q(ha, t, l) ((TGT_Q(ha,t) != NULL)? TGT_Q(ha, t)->olun[l] : NULL)
 
 #define to_qla_host(x)		((scsi_qla_host_t *) (x)->hostdata)
 
@@ -2479,7 +2360,6 @@ struct _qla2x00stats  {
 #include "qla_gbl.h"
 #include "qla_dbg.h"
 #include "qla_inline.h"
-#include "qla_listops.h"
 
 /*
 * String arrays
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,10 +44,10 @@ extern void qla2x00_restart_queues(scsi_
 
 extern void qla2x00_rescan_fcports(scsi_qla_host_t *);
 
-extern void qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t t);
-
 extern int qla2x00_abort_isp(scsi_qla_host_t *);
 
+extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
+
 /*
  * Global Data in qla_os.c source file.
  */
@@ -74,25 +74,15 @@ extern int ql2xsuspendcount;
 #if defined(MODULE)
 extern char *ql2xopts;
 #endif
+extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
 extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 
 extern void qla2x00_cmd_timeout(srb_t *);
 
-extern int __qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int, int);
-
-extern void qla2x00_done(scsi_qla_host_t *);
-extern void qla2x00_next(scsi_qla_host_t *);
-extern void qla2x00_flush_failover_q(scsi_qla_host_t *, os_lun_t *);
-extern void qla2x00_reset_lun_fo_counts(scsi_qla_host_t *, os_lun_t *);
-
-extern void qla2x00_extend_timeout(struct scsi_cmnd *, int);
-
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
 extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
 
-extern void qla2x00_abort_queues(scsi_qla_host_t *, uint8_t);
-
 extern void qla2x00_blink_led(scsi_qla_host_t *);
 
 extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
@@ -150,7 +140,7 @@ qla2x00_abort_target(fc_port_t *fcport);
 #endif
 
 extern int
-qla2x00_target_reset(scsi_qla_host_t *, uint16_t, uint16_t);
+qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *);
 
 extern int
 qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
@@ -254,4 +244,14 @@ extern void qla2x00_cancel_io_descriptor
 #define qla2x00_alloc_ioctl_mem(ha)		(0)
 #define qla2x00_free_ioctl_mem(ha)		do { } while (0)
 
+/*
+ * Global Function Prototypes in qla_attr.c source file.
+ */
+struct fc_function_template;
+extern struct fc_function_template qla2xxx_transport_functions;
+extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
+extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+extern void qla2x00_init_host_attr(scsi_qla_host_t *);
+extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
+extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -19,6 +19,7 @@
 #include "qla_def.h"
 
 #include <linux/delay.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include "qla_devtbl.h"
 
@@ -44,34 +45,17 @@ static int qla2x00_init_rings(scsi_qla_h
 static int qla2x00_fw_ready(scsi_qla_host_t *);
 static int qla2x00_configure_hba(scsi_qla_host_t *);
 static int qla2x00_nvram_config(scsi_qla_host_t *);
-static void qla2x00_init_tgt_map(scsi_qla_host_t *);
 static int qla2x00_configure_loop(scsi_qla_host_t *);
 static int qla2x00_configure_local_loop(scsi_qla_host_t *);
 static void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
-static void qla2x00_lun_discovery(scsi_qla_host_t *, fc_port_t *);
-static int qla2x00_rpt_lun_discovery(scsi_qla_host_t *, fc_port_t *,
-    inq_cmd_rsp_t *, dma_addr_t);
-static int qla2x00_report_lun(scsi_qla_host_t *, fc_port_t *);
-static fc_lun_t *qla2x00_cfg_lun(scsi_qla_host_t *, fc_port_t *, uint16_t,
-    inq_cmd_rsp_t *, dma_addr_t);
-static fc_lun_t * qla2x00_add_lun(fc_port_t *, uint16_t);
-static int qla2x00_inquiry(scsi_qla_host_t *, fc_port_t *, uint16_t,
-    inq_cmd_rsp_t *, dma_addr_t);
 static int qla2x00_configure_fabric(scsi_qla_host_t *);
 static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
 static int qla2x00_device_resync(scsi_qla_host_t *);
 static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
     uint16_t *);
-static void qla2x00_config_os(scsi_qla_host_t *ha);
-static uint16_t qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport);
-static os_lun_t * qla2x00_fclun_bind(scsi_qla_host_t *, fc_port_t *,
-    fc_lun_t *);
-static void qla2x00_lun_free(scsi_qla_host_t *, uint16_t, uint16_t);
 
 static int qla2x00_restart_isp(scsi_qla_host_t *);
 static void qla2x00_reset_adapter(scsi_qla_host_t *);
-static os_tgt_t *qla2x00_tgt_alloc(scsi_qla_host_t *, uint16_t);
-static os_lun_t *qla2x00_lun_alloc(scsi_qla_host_t *, uint16_t, uint16_t);
 
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
@@ -119,9 +103,6 @@ qla2x00_initialize_adapter(scsi_qla_host
 
 	qla2x00_reset_chip(ha);
 
-	/* Initialize target map database. */
-	qla2x00_init_tgt_map(ha);
-
 	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
 	qla2x00_nvram_config(ha);
 
@@ -1529,25 +1510,6 @@ qla2x00_nvram_config(scsi_qla_host_t *ha
 	return (rval);
 }
 
-/*
-* qla2x00_init_tgt_map
-*      Initializes target map.
-*
-* Input:
-*      ha = adapter block pointer.
-*
-* Output:
-*      TGT_Q initialized
-*/
-static void
-qla2x00_init_tgt_map(scsi_qla_host_t *ha)
-{
-	uint32_t t;
-
-	for (t = 0; t < MAX_TARGETS; t++)
-		TGT_Q(ha, t) = (os_tgt_t *)NULL;
-}
-
 /**
  * qla2x00_alloc_fcport() - Allocate a generic fcport.
  * @ha: HA context
@@ -1572,7 +1534,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha
 	fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	fcport->flags = FCF_RLC_SUPPORT;
-	INIT_LIST_HEAD(&fcport->fcluns);
 
 	return (fcport);
 }
@@ -1662,7 +1623,6 @@ qla2x00_configure_loop(scsi_qla_host_t *
 		    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 			rval = QLA_FUNCTION_FAILED;
 		} else {
-			qla2x00_config_os(ha);
 			atomic_set(&ha->loop_state, LOOP_READY);
 
 			DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no));
@@ -1907,8 +1867,11 @@ qla2x00_update_fcport(scsi_qla_host_t *h
 	if (fcport->flags & FCF_TAPE_PRESENT) {
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
+			fc_port_t *sfcp;
+
 			if ((sp = ha->outstanding_cmds[index]) != 0) {
-				if (sp->fclun->fcport == fcport) {
+				sfcp = sp->fcport;
+				if (sfcp == fcport) {
 					atomic_set(&fcport->state, FCS_ONLINE);
 					spin_unlock_irqrestore(
 					    &ha->hardware_lock, flags);
@@ -1919,423 +1882,48 @@ qla2x00_update_fcport(scsi_qla_host_t *h
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
 
-	/* Do LUN discovery. */
 	if (fcport->port_type == FCT_INITIATOR ||
-	    fcport->port_type == FCT_BROADCAST) {
+	    fcport->port_type == FCT_BROADCAST)
 		fcport->device_type = TYPE_PROCESSOR;
-	} else {
-		qla2x00_lun_discovery(ha, fcport);
-	}
-	atomic_set(&fcport->state, FCS_ONLINE);
-}
-
-/*
- * qla2x00_lun_discovery
- *	Issue SCSI inquiry command for LUN discovery.
- *
- * Input:
- *	ha:		adapter state pointer.
- *	fcport:		FC port structure pointer.
- *
- * Context:
- *	Kernel context.
- */
-static void
-qla2x00_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport)
-{
-	inq_cmd_rsp_t	*inq;
-	dma_addr_t	inq_dma;
-	uint16_t	lun;
 
-	inq = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &inq_dma);
-	if (inq == NULL) {
-		qla_printk(KERN_WARNING, ha,
-		    "Memory Allocation failed - INQ\n");
-		return;
-	}
-
-	/* Always add a fc_lun_t structure for lun 0 -- mid-layer requirement */
-	qla2x00_add_lun(fcport, 0);
-
-	/* If report LUN works, exit. */
-	if (qla2x00_rpt_lun_discovery(ha, fcport, inq, inq_dma) !=
-	    QLA_SUCCESS) {
-		for (lun = 0; lun < ha->max_probe_luns; lun++) {
-			/* Configure LUN. */
-			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);
-		}
-	}
-
-	dma_pool_free(ha->s_dma_pool, inq, inq_dma);
-}
-
-/*
- * qla2x00_rpt_lun_discovery
- *	Issue SCSI report LUN command for LUN discovery.
- *
- * Input:
- *	ha:		adapter state pointer.
- *	fcport:		FC port structure pointer.
- *
- * Returns:
- *	qla2x00 local function return status code.
- *
- * Context:
- *	Kernel context.
- */
-static int
-qla2x00_rpt_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport,
-    inq_cmd_rsp_t *inq, dma_addr_t inq_dma)
-{
-	int			rval;
-	uint32_t		len, cnt;
-	uint16_t		lun;
-
-	/* Assume a failed status */
-	rval = QLA_FUNCTION_FAILED;
-
-	/* No point in continuing if the device doesn't support RLC */
-	if ((fcport->flags & FCF_RLC_SUPPORT) == 0)
-		return (rval);
-
-	rval = qla2x00_report_lun(ha, fcport);
-	if (rval != QLA_SUCCESS)
-		return (rval);
-
-	/* Configure LUN list. */
-	len = be32_to_cpu(ha->rlc_rsp->list.hdr.len);
-	len /= 8;
-	for (cnt = 0; cnt < len; cnt++) {
-		lun = CHAR_TO_SHORT(ha->rlc_rsp->list.lst[cnt].lsb,
-		    ha->rlc_rsp->list.lst[cnt].msb.b);
-
-		DEBUG3(printk("scsi(%ld): RLC lun = (%d)\n", ha->host_no, lun));
-
-		/* We only support 0 through MAX_LUNS-1 range */
-		if (lun < MAX_LUNS) {
-			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);
-		}
-	}
 	atomic_set(&fcport->state, FCS_ONLINE);
 
-	return (rval);
+	if (ha->flags.init_done)
+		qla2x00_reg_remote_port(ha, fcport);
 }
 
-/*
- * qla2x00_report_lun
- *	Issue SCSI report LUN command.
- *
- * Input:
- *	ha:		adapter state pointer.
- *	fcport:		FC port structure pointer.
- *
- * Returns:
- *	qla2x00 local function return status code.
- *
- * Context:
- *	Kernel context.
- */
-static int
-qla2x00_report_lun(scsi_qla_host_t *ha, fc_port_t *fcport)
-{
-	int rval;
-	uint16_t retries;
-	uint16_t comp_status;
-	uint16_t scsi_status;
-	rpt_lun_cmd_rsp_t *rlc;
-	dma_addr_t rlc_dma;
-
-	rval = QLA_FUNCTION_FAILED;
-	rlc = ha->rlc_rsp;
-	rlc_dma = ha->rlc_rsp_dma;
-
-	for (retries = 3; retries; retries--) {
-		memset(rlc, 0, sizeof(rpt_lun_cmd_rsp_t));
-		rlc->p.cmd.entry_type = COMMAND_A64_TYPE;
-		rlc->p.cmd.entry_count = 1;
-		SET_TARGET_ID(ha, rlc->p.cmd.target, fcport->loop_id);
-		rlc->p.cmd.control_flags =
-		    __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG);
-		rlc->p.cmd.scsi_cdb[0] = REPORT_LUNS;
-		rlc->p.cmd.scsi_cdb[8] = MSB(sizeof(rpt_lun_lst_t));
-		rlc->p.cmd.scsi_cdb[9] = LSB(sizeof(rpt_lun_lst_t));
-		rlc->p.cmd.dseg_count = __constant_cpu_to_le16(1);
-		rlc->p.cmd.timeout = __constant_cpu_to_le16(10);
-		rlc->p.cmd.byte_count =
-		    __constant_cpu_to_le32(sizeof(rpt_lun_lst_t));
-		rlc->p.cmd.dseg_0_address[0] = cpu_to_le32(
-		    LSD(rlc_dma + sizeof(sts_entry_t)));
-		rlc->p.cmd.dseg_0_address[1] = cpu_to_le32(
-		    MSD(rlc_dma + sizeof(sts_entry_t)));
-		rlc->p.cmd.dseg_0_length =
-		    __constant_cpu_to_le32(sizeof(rpt_lun_lst_t));
-
-		rval = qla2x00_issue_iocb(ha, rlc, rlc_dma,
-		    sizeof(rpt_lun_cmd_rsp_t));
-
-		comp_status = le16_to_cpu(rlc->p.rsp.comp_status);
-		scsi_status = le16_to_cpu(rlc->p.rsp.scsi_status);
-
-		if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE ||
-		    scsi_status & SS_CHECK_CONDITION) {
-
-			/* Device underrun, treat as OK. */
-			if (rval == QLA_SUCCESS &&
-			    comp_status == CS_DATA_UNDERRUN &&
-			    scsi_status & SS_RESIDUAL_UNDER) {
-
-				rval = QLA_SUCCESS;
-				break;
-			}
-
-			DEBUG(printk("scsi(%ld): RLC failed to issue iocb! "
-			    "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n",
-			    ha->host_no, fcport->loop_id, fcport, rval,
-			    comp_status, scsi_status));
-
-			rval = QLA_FUNCTION_FAILED;
-			if (scsi_status & SS_CHECK_CONDITION) {
-				DEBUG2(printk("scsi(%ld): RLC "
-				    "SS_CHECK_CONDITION Sense Data "
-				    "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-				    ha->host_no,
-				    rlc->p.rsp.req_sense_data[0],
-				    rlc->p.rsp.req_sense_data[1],
-				    rlc->p.rsp.req_sense_data[2],
-				    rlc->p.rsp.req_sense_data[3],
-				    rlc->p.rsp.req_sense_data[4],
-				    rlc->p.rsp.req_sense_data[5],
-				    rlc->p.rsp.req_sense_data[6],
-				    rlc->p.rsp.req_sense_data[7]));
-				if (rlc->p.rsp.req_sense_data[2] ==
-				    ILLEGAL_REQUEST) {
-					fcport->flags &= ~(FCF_RLC_SUPPORT);
-					break;
-				}
-			}
-		} else {
-			break;
-		}
-	}
-
-	return (rval);
-}
-
-/*
- * qla2x00_cfg_lun
- *	Configures LUN into fcport LUN list.
- *
- * Input:
- *	fcport:		FC port structure pointer.
- *	lun:		LUN number.
- *
- * Context:
- *	Kernel context.
- */
-static fc_lun_t *
-qla2x00_cfg_lun(scsi_qla_host_t *ha, fc_port_t *fcport, uint16_t lun,
-    inq_cmd_rsp_t *inq, dma_addr_t inq_dma) 
-{
-	fc_lun_t *fclun;
-	uint8_t	  device_type;
-
-	/* Bypass LUNs that failed. */
-	if (qla2x00_inquiry(ha, fcport, lun, inq, inq_dma) != QLA_SUCCESS) {
-		DEBUG2(printk("scsi(%ld): Failed inquiry - loop id=0x%04x "
-		    "lun=%d\n", ha->host_no, fcport->loop_id, lun));
-
-		return (NULL);
-	}
-	device_type = (inq->inq[0] & 0x1f);
-	switch (device_type) {
-	case TYPE_DISK:
-	case TYPE_PROCESSOR:
-	case TYPE_WORM:
-	case TYPE_ROM:
-	case TYPE_SCANNER:
-	case TYPE_MOD:
-	case TYPE_MEDIUM_CHANGER:
-	case TYPE_ENCLOSURE:
-	case 0x20:
-	case 0x0C:
-		break;
-	case TYPE_TAPE:
-		fcport->flags |= FCF_TAPE_PRESENT;
-		break;
-	default:
-		DEBUG2(printk("scsi(%ld): Unsupported lun type -- "
-		    "loop id=0x%04x lun=%d type=%x\n",
-		    ha->host_no, fcport->loop_id, lun, device_type));
-		return (NULL);
-	}
-
-	fcport->device_type = device_type;
-	fclun = qla2x00_add_lun(fcport, lun);
-
-	if (fclun != NULL) {
-		atomic_set(&fcport->state, FCS_ONLINE);
-	}
-
-	return (fclun);
-}
-
-/*
- * qla2x00_add_lun
- *	Adds LUN to database
- *
- * Input:
- *	fcport:		FC port structure pointer.
- *	lun:		LUN number.
- *
- * Context:
- *	Kernel context.
- */
-static fc_lun_t *
-qla2x00_add_lun(fc_port_t *fcport, uint16_t lun)
+void
+qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
-	int		found;
-	fc_lun_t	*fclun;
+	struct fc_rport_identifiers rport_ids;
+	struct fc_rport *rport;
 
-	if (fcport == NULL) {
-		DEBUG(printk("scsi: Unable to add lun to NULL port\n"));
-		return (NULL);
-	}
-
-	/* Allocate LUN if not already allocated. */
-	found = 0;
-	list_for_each_entry(fclun, &fcport->fcluns, list) {
-		if (fclun->lun == lun) {
-			found++;
-			break;
-		}
+	if (fcport->rport) {
+		fc_remote_port_unblock(fcport->rport);
+		return;
 	}
-	if (found)
-		return (NULL);
 
-	fclun = kmalloc(sizeof(fc_lun_t), GFP_ATOMIC);
-	if (fclun == NULL) {
-		printk(KERN_WARNING
-		    "%s(): Memory Allocation failed - FCLUN\n",
-		    __func__);
-		return (NULL);
-	}
-
-	/* Setup LUN structure. */
-	memset(fclun, 0, sizeof(fc_lun_t));
-	fclun->lun = lun;
-	fclun->fcport = fcport;
-	fclun->o_fcport = fcport;
-	fclun->device_type = fcport->device_type;
-	atomic_set(&fcport->state, FCS_UNCONFIGURED);
-
-	list_add_tail(&fclun->list, &fcport->fcluns);
-
-	return (fclun);
-}
-
-/*
- * qla2x00_inquiry
- *	Issue SCSI inquiry command.
- *
- * Input:
- *	ha = adapter block pointer.
- *	fcport = FC port structure pointer.
- *
- * Return:
- *	0  - Success
- *  BIT_0 - error
- *
- * Context:
- *	Kernel context.
- */
-static int
-qla2x00_inquiry(scsi_qla_host_t *ha,
-    fc_port_t *fcport, uint16_t lun, inq_cmd_rsp_t *inq, dma_addr_t inq_dma)
-{
-	int rval;
-	uint16_t retries;
-	uint16_t comp_status;
-	uint16_t scsi_status;
+	rport_ids.node_name = be64_to_cpu(*(uint64_t *)fcport->node_name);
+	rport_ids.port_name = be64_to_cpu(*(uint64_t *)fcport->port_name);
+	rport_ids.port_id = fcport->d_id.b.domain << 16 |
+	    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
+	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+	if (fcport->port_type == FCT_INITIATOR)
+		rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+	if (fcport->port_type == FCT_TARGET)
+		rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
 
-	rval = QLA_FUNCTION_FAILED;
+	fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
+	if (!rport)
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocate fc remote port!\n");
 
-	for (retries = 3; retries; retries--) {
-		memset(inq, 0, sizeof(inq_cmd_rsp_t));
-		inq->p.cmd.entry_type = COMMAND_A64_TYPE;
-		inq->p.cmd.entry_count = 1;
-		inq->p.cmd.lun = cpu_to_le16(lun);
-		SET_TARGET_ID(ha, inq->p.cmd.target, fcport->loop_id);
-		inq->p.cmd.control_flags =
-		    __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG);
-		inq->p.cmd.scsi_cdb[0] = INQUIRY;
-		inq->p.cmd.scsi_cdb[4] = INQ_DATA_SIZE;
-		inq->p.cmd.dseg_count = __constant_cpu_to_le16(1);
-		inq->p.cmd.timeout = __constant_cpu_to_le16(10);
-		inq->p.cmd.byte_count =
-		    __constant_cpu_to_le32(INQ_DATA_SIZE);
-		inq->p.cmd.dseg_0_address[0] = cpu_to_le32(
-		    LSD(inq_dma + sizeof(sts_entry_t)));
-		inq->p.cmd.dseg_0_address[1] = cpu_to_le32(
-		    MSD(inq_dma + sizeof(sts_entry_t)));
-		inq->p.cmd.dseg_0_length =
-		    __constant_cpu_to_le32(INQ_DATA_SIZE);
-
-		DEBUG5(printk("scsi(%ld): Lun Inquiry - fcport=[%04x/%p],"
-		    " lun (%d)\n",
-		    ha->host_no, fcport->loop_id, fcport, lun));
-
-		rval = qla2x00_issue_iocb(ha, inq, inq_dma,
-		    sizeof(inq_cmd_rsp_t));
-
-		comp_status = le16_to_cpu(inq->p.rsp.comp_status);
-		scsi_status = le16_to_cpu(inq->p.rsp.scsi_status);
-
-		DEBUG5(printk("scsi(%ld): lun (%d) inquiry - "
-		    "inq[0]= 0x%x, comp status 0x%x, scsi status 0x%x, "
-		    "rval=%d\n",
-		    ha->host_no, lun, inq->inq[0], comp_status, scsi_status,
-		    rval));
-
-		if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE ||
-		    scsi_status & SS_CHECK_CONDITION) {
-
-			DEBUG(printk("scsi(%ld): INQ failed to issue iocb! "
-			    "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n",
-			    ha->host_no, fcport->loop_id, fcport, rval,
-			    comp_status, scsi_status));
-
-			if (rval == QLA_SUCCESS)
-				rval = QLA_FUNCTION_FAILED;
-
-			if (scsi_status & SS_CHECK_CONDITION) {
-				DEBUG2(printk("scsi(%ld): INQ "
-				    "SS_CHECK_CONDITION Sense Data "
-				    "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-				    ha->host_no,
-				    inq->p.rsp.req_sense_data[0],
-				    inq->p.rsp.req_sense_data[1],
-				    inq->p.rsp.req_sense_data[2],
-				    inq->p.rsp.req_sense_data[3],
-				    inq->p.rsp.req_sense_data[4],
-				    inq->p.rsp.req_sense_data[5],
-				    inq->p.rsp.req_sense_data[6],
-				    inq->p.rsp.req_sense_data[7]));
-			}
-
-			/* Device underrun drop LUN. */
-			if (comp_status == CS_DATA_UNDERRUN &&
-			    scsi_status & SS_RESIDUAL_UNDER) {
-				break;
-			}
-		} else {
-			break;
-		}
-	}
+	if (rport->scsi_target_id != -1 && rport->scsi_target_id < MAX_TARGETS)
+		fcport->os_target_id = rport->scsi_target_id;
 
-	return (rval);
+	rport->dd_data = fcport;
 }
 
-
 /*
  * qla2x00_configure_fabric
  *      Setup SNS devices with loop ID's.
@@ -2486,12 +2074,12 @@ qla2x00_configure_fabric(scsi_qla_host_t
 				break;
 			}
 
-			/* Login and update database */
-			qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
-
 			/* Remove device from the new list and add it to DB */
 			list_del(&fcport->list);
 			list_add_tail(&fcport->list, &ha->fcports);
+
+			/* Login and update database */
+			qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
 		}
 	} while (0);
 
@@ -2895,8 +2483,7 @@ qla2x00_device_resync(scsi_qla_host_t *h
 			if (atomic_read(&fcport->state) == FCS_ONLINE) {
 				if (format != 3 ||
 				    fcport->port_type != FCT_INITIATOR) {
-					atomic_set(&fcport->state,
-					    FCS_DEVICE_LOST);
+					qla2x00_mark_device_lost(ha, fcport, 0);
 				}
 			}
 			fcport->flags &= ~FCF_FARP_DONE;
@@ -3146,7 +2733,6 @@ qla2x00_loop_resync(scsi_qla_host_t *ha)
 				wait_time &&
 				(test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
 		}
-		qla2x00_restart_queues(ha, 1);
 	}
 
 	if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
@@ -3160,87 +2746,6 @@ qla2x00_loop_resync(scsi_qla_host_t *ha)
 	return (rval);
 }
 
-/*
- *  qla2x00_restart_queues
- *	Restart device queues.
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Context:
- *	Kernel/Interrupt context.
- */
-void
-qla2x00_restart_queues(scsi_qla_host_t *ha, uint8_t flush) 
-{
-	srb_t  		*sp;
-	int		retry_q_cnt = 0;
-	int		pending_q_cnt = 0;
-	struct list_head *list, *temp;
-	unsigned long flags = 0;
-
-	clear_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags);
-
-	/* start pending queue */
-	pending_q_cnt = ha->qthreads;
-	if (flush) {
-		spin_lock_irqsave(&ha->list_lock,flags);
-		list_for_each_safe(list, temp, &ha->pending_queue) {
-			sp = list_entry(list, srb_t, list);
-
-			if ((sp->flags & SRB_TAPE))
-				continue;
-			 
-			/* 
-			 * When time expire return request back to OS as BUSY 
-			 */
-			__del_from_pending_queue(ha, sp);
-			sp->cmd->result = DID_BUS_BUSY << 16;
-			sp->cmd->host_scribble = (unsigned char *)NULL;
-			__add_to_done_queue(ha, sp);
-		}
-		spin_unlock_irqrestore(&ha->list_lock, flags);
-	} else {
-		if (!list_empty(&ha->pending_queue))
-			qla2x00_next(ha);
-	}
-
-	/*
-	 * Clear out our retry queue
-	 */
-	if (flush) {
-		spin_lock_irqsave(&ha->list_lock, flags);
-		retry_q_cnt = ha->retry_q_cnt;
-		list_for_each_safe(list, temp, &ha->retry_queue) {
-			sp = list_entry(list, srb_t, list);
-			/* when time expire return request back to OS as BUSY */
-			__del_from_retry_queue(ha, sp);
-			sp->cmd->result = DID_BUS_BUSY << 16;
-			sp->cmd->host_scribble = (unsigned char *)NULL;
-			__add_to_done_queue(ha, sp);
-		}
-		spin_unlock_irqrestore(&ha->list_lock, flags);
-
-		DEBUG2(printk("%s(%ld): callback %d commands.\n",
-				__func__,
-				ha->host_no,
-				retry_q_cnt);)
-	}
-
-	DEBUG2(printk("%s(%ld): active=%ld, retry=%d, pending=%d, "
-			"done=%ld, scsi retry=%d commands.\n",
-			__func__,
-			ha->host_no,
-			ha->actthreads,
-			ha->retry_q_cnt,
-			pending_q_cnt,
-			ha->done_q_cnt,
-			ha->scsi_retry_q_cnt);)
-
-	if (!list_empty(&ha->done_queue))
-		qla2x00_done(ha);
-}
-
 void
 qla2x00_rescan_fcports(scsi_qla_host_t *ha)
 {
@@ -3258,396 +2763,6 @@ qla2x00_rescan_fcports(scsi_qla_host_t *
 		rescan_done = 1;
 	}
 	qla2x00_probe_for_all_luns(ha); 
-
-	/* Update OS target and lun structures if necessary. */
-	if (rescan_done) {
-		qla2x00_config_os(ha);
-	}
-}
-
-
-/*
- * qla2x00_config_os
- *	Setup OS target and LUN structures.
- *
- * Input:
- *	ha = adapter state pointer.
- *
- * Context:
- *	Kernel context.
- */
-static void
-qla2x00_config_os(scsi_qla_host_t *ha) 
-{
-	fc_port_t	*fcport;
-	fc_lun_t	*fclun;
-	os_tgt_t	*tq;
-	uint16_t	tgt;
-
-
-	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
-		if ((tq = TGT_Q(ha, tgt)) == NULL)
-			continue;
-
-		clear_bit(TQF_ONLINE, &tq->flags);
-	}
-
-	list_for_each_entry(fcport, &ha->fcports, list) {
-		if (atomic_read(&fcport->state) != FCS_ONLINE ||
-		    fcport->port_type == FCT_INITIATOR ||
-		    fcport->port_type == FCT_BROADCAST) {
-			fcport->os_target_id = MAX_TARGETS;
-			continue;
-		}
-
-		if (fcport->flags & FCF_FO_MASKED) {
-			continue;
-		}
-
-		/* Bind FC port to OS target number. */
-		if (qla2x00_fcport_bind(ha, fcport) == MAX_TARGETS) {
-			continue;
-		}
-
-		/* Bind FC LUN to OS LUN number. */
-		list_for_each_entry(fclun, &fcport->fcluns, list) {
-			qla2x00_fclun_bind(ha, fcport, fclun);
-		}
-	}
-}
-
-/*
- * qla2x00_fcport_bind
- *	Locates a target number for FC port.
- *
- * Input:
- *	ha = adapter state pointer.
- *	fcport = FC port structure pointer.
- *
- * Returns:
- *	target number
- *
- * Context:
- *	Kernel context.
- */
-static uint16_t
-qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport) 
-{
-	int		found;
-	uint16_t	tgt;
-	os_tgt_t	*tq;
-
-	/* Check for persistent binding. */
-	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
-		if ((tq = TGT_Q(ha, tgt)) == NULL)
-			continue;
-
-		found = 0;
-		switch (ha->binding_type) {
-		case BIND_BY_PORT_ID:
-			if (fcport->d_id.b24 == tq->d_id.b24) {
-				memcpy(tq->node_name, fcport->node_name,
-				    WWN_SIZE);
-				memcpy(tq->port_name, fcport->port_name,
-				    WWN_SIZE);
-				found++;
-			}
-			break;
-		case BIND_BY_PORT_NAME:    
-			if (memcmp(fcport->port_name, tq->port_name,
-			    WWN_SIZE) == 0) {
-				/*
-				 * In case of persistent binding, update the
-				 * WWNN.
-				 */
-				memcpy(tq->node_name, fcport->node_name,
-				    WWN_SIZE);
-				found++;
-			}
-			break;
-		}
-		if (found)
-		    break;	
-	}
-
-	/* TODO: honor the ConfigRequired flag */
-	if (tgt == MAX_TARGETS) {
-		/* Check if targetID 0 available. */
-		tgt = 0;
-
-		if (TGT_Q(ha, tgt) != NULL) {
-			/* Locate first free target for device. */
-			for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
-				if (TGT_Q(ha, tgt) == NULL) {
-					break;
-				}
-			}
-		}
-		if (tgt != MAX_TARGETS) {
-			if ((tq = qla2x00_tgt_alloc(ha, tgt)) != NULL) {
-				memcpy(tq->node_name, fcport->node_name,
-				    WWN_SIZE);
-				memcpy(tq->port_name, fcport->port_name,
-				    WWN_SIZE);
-				tq->d_id.b24 = fcport->d_id.b24;
-			}
-		}
-	}
-
-	/* Reset target numbers incase it changed. */
-	fcport->os_target_id = tgt;
-	if (tgt != MAX_TARGETS && tq != NULL) {
-		DEBUG2(printk("scsi(%ld): Assigning target ID=%02d @ %p to "
-		    "loop id=0x%04x, port state=0x%x, port down retry=%d\n",
-		    ha->host_no, tgt, tq, fcport->loop_id,
-		    atomic_read(&fcport->state),
-		    atomic_read(&fcport->port_down_timer)));
-
-		fcport->tgt_queue = tq;
-		fcport->flags |= FCF_PERSISTENT_BOUND;
-		tq->fcport = fcport;
-		set_bit(TQF_ONLINE, &tq->flags);
-		tq->port_down_retry_count = ha->port_down_retry_count;
-	}
-
-	if (tgt == MAX_TARGETS) {
-		qla_printk(KERN_WARNING, ha,
-		    "Unable to bind fcport, loop_id=%x\n", fcport->loop_id);
-	}
-
-	return (tgt);
-}
-
-/*
- * qla2x00_fclun_bind
- *	Binds all FC device LUNS to OS LUNS.
- *
- * Input:
- *	ha:		adapter state pointer.
- *	fcport:		FC port structure pointer.
- *
- * Returns:
- *	target number
- *
- * Context:
- *	Kernel context.
- */
-static os_lun_t *
-qla2x00_fclun_bind(scsi_qla_host_t *ha, fc_port_t *fcport, fc_lun_t *fclun)
-{
-	os_lun_t	*lq;
-	uint16_t	tgt;
-	uint16_t	lun;
-
-	tgt = fcport->os_target_id;
-	lun = fclun->lun;
-
-	/* Allocate LUNs */
-	if (lun >= MAX_LUNS) {
-		DEBUG2(printk("scsi(%ld): Unable to bind lun, invalid "
-		    "lun=(%x).\n", ha->host_no, lun));
-		return (NULL);
-	}
-
-	/* Always alloc LUN 0 so kernel will scan past LUN 0. */
-	if (lun != 0 && (EXT_IS_LUN_BIT_SET(&(fcport->lun_mask), lun))) {
-		return (NULL);
-	}
-
-	if ((lq = qla2x00_lun_alloc(ha, tgt, lun)) == NULL) {
-		qla_printk(KERN_WARNING, ha,
-		    "Unable to bind fclun, loop_id=%x lun=%x\n",
-		    fcport->loop_id, lun);
-		return (NULL);
-	}
-
-	lq->fclun = fclun;
-
-	return (lq);
-}
-
-/*
- * qla2x00_tgt_alloc
- *	Allocate and pre-initialize target queue.
- *
- * Input:
- *	ha = adapter block pointer.
- *	t = SCSI target number.
- *
- * Returns:
- *	NULL = failure
- *
- * Context:
- *	Kernel context.
- */
-static os_tgt_t *
-qla2x00_tgt_alloc(scsi_qla_host_t *ha, uint16_t tgt) 
-{
-	os_tgt_t	*tq;
-
-	/*
-	 * If SCSI addressing OK, allocate TGT queue and lock.
-	 */
-	if (tgt >= MAX_TARGETS) {
-		DEBUG2(printk("scsi(%ld): Unable to allocate target, invalid "
-		    "target number %d.\n", ha->host_no, tgt));
-		return (NULL);
-	}
-
-	tq = TGT_Q(ha, tgt);
-	if (tq == NULL) {
-		tq = kmalloc(sizeof(os_tgt_t), GFP_ATOMIC);
-		if (tq != NULL) {
-			DEBUG2(printk("scsi(%ld): Alloc Target %d @ %p\n",
-			    ha->host_no, tgt, tq));
-
-			memset(tq, 0, sizeof(os_tgt_t));
-			tq->ha = ha;
-
-			TGT_Q(ha, tgt) = tq;
-		}
-	}
-	if (tq != NULL) {
-		tq->port_down_retry_count = ha->port_down_retry_count;
-	} else {
-		qla_printk(KERN_WARNING, ha,
-		    "Unable to allocate target.\n");
-		ha->mem_err++;
-	}
-
-	return (tq);
-}
-
-/*
- * qla2x00_tgt_free
- *	Frees target and LUN queues.
- *
- * Input:
- *	ha = adapter block pointer.
- *	t = SCSI target number.
- *
- * Context:
- *	Kernel context.
- */
-void
-qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t tgt) 
-{
-	os_tgt_t	*tq;
-	uint16_t	lun;
-
-	/*
-	 * If SCSI addressing OK, allocate TGT queue and lock.
-	 */
-	if (tgt >= MAX_TARGETS) {
-		DEBUG2(printk("scsi(%ld): Unable to de-allocate target, "
-		    "invalid target number %d.\n", ha->host_no, tgt));
-
-		return;
-	}
-
-	tq = TGT_Q(ha, tgt);
-	if (tq != NULL) {
-		TGT_Q(ha, tgt) = NULL;
-
-		/* Free LUN structures. */
-		for (lun = 0; lun < MAX_LUNS; lun++)
-			qla2x00_lun_free(ha, tgt, lun);
-
-		kfree(tq);
-	}
-
-	return;
-}
-
-/*
- * qla2x00_lun_alloc
- *	Allocate and initialize LUN queue.
- *
- * Input:
- *	ha = adapter block pointer.
- *	t = SCSI target number.
- *	l = LUN number.
- *
- * Returns:
- *	NULL = failure
- *
- * Context:
- *	Kernel context.
- */
-static os_lun_t *
-qla2x00_lun_alloc(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) 
-{
-	os_lun_t	*lq;
-
-	/*
-	 * If SCSI addressing OK, allocate LUN queue.
-	 */
-	if (tgt >= MAX_TARGETS || lun >= MAX_LUNS || TGT_Q(ha, tgt) == NULL) {
-		DEBUG2(printk("scsi(%ld): Unable to allocate lun, invalid "
-		    "parameter.\n", ha->host_no));
-
-		return (NULL);
-	}
-
-	lq = LUN_Q(ha, tgt, lun);
-	if (lq == NULL) {
-		lq = kmalloc(sizeof(os_lun_t), GFP_ATOMIC);
-		if (lq != NULL) {
-			DEBUG2(printk("scsi(%ld): Alloc Lun %d @ tgt %d.\n",
-			    ha->host_no, lun, tgt));
-
-			memset(lq, 0, sizeof(os_lun_t));
-			LUN_Q(ha, tgt, lun) = lq;
-
-			/*
-			 * The following lun queue initialization code
-			 * must be duplicated in alloc_ioctl_mem function
-			 * for ioctl_lq.
-			 */
-			lq->q_state = LUN_STATE_READY;
-			spin_lock_init(&lq->q_lock);
-		}
-	}
-
-	if (lq == NULL) {
-		qla_printk(KERN_WARNING, ha, "Unable to allocate lun.\n");
-	}
-
-	return (lq);
-}
-
-/*
- * qla2x00_lun_free
- *	Frees LUN queue.
- *
- * Input:
- *	ha = adapter block pointer.
- *	t = SCSI target number.
- *
- * Context:
- *	Kernel context.
- */
-static void
-qla2x00_lun_free(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) 
-{
-	os_lun_t	*lq;
-
-	/*
-	 * If SCSI addressing OK, allocate TGT queue and lock.
-	 */
-	if (tgt >= MAX_TARGETS || lun >= MAX_LUNS) {
-		DEBUG2(printk("scsi(%ld): Unable to deallocate lun, invalid "
-		    "parameter.\n", ha->host_no));
-
-		return;
-	}
-
-	if (TGT_Q(ha, tgt) != NULL && (lq = LUN_Q(ha, tgt, lun)) != NULL) {
-		LUN_Q(ha, tgt, lun) = NULL;
-		kfree(lq);
-	}
-
-	return;
 }
 
 /*
@@ -3697,26 +2812,10 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 				ha->outstanding_cmds[cnt] = NULL;
 				if (ha->actthreads)
 					ha->actthreads--;
-				sp->lun_queue->out_cnt--;
-
-				/*
-				 * Set the cmd host_byte status depending on
-				 * whether the scsi_error_handler is
-				 * active or not.
- 				 */
-				if (sp->flags & SRB_TAPE) {
-					sp->cmd->result = DID_NO_CONNECT << 16;
-				} else {
-					if (ha->host->eh_active != EH_ACTIVE)
-						sp->cmd->result =
-						    DID_BUS_BUSY << 16;
-					else
-						sp->cmd->result =
-						    DID_RESET << 16;
-				}
 				sp->flags = 0;
+				sp->cmd->result = DID_RESET << 16;
 				sp->cmd->host_scribble = (unsigned char *)NULL;
-				add_to_done_queue(ha, sp);
+				qla2x00_sp_compl(ha, sp);
 			}
 		}
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3739,11 +2838,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 			/* Enable ISP interrupts. */
 			qla2x00_enable_intrs(ha);
 
-			/* v2.19.5b6 Return all commands */
-			qla2x00_abort_queues(ha, 1);
-
-			/* Restart queues that may have been stopped. */
-			qla2x00_restart_queues(ha, 1);
 			ha->isp_abort_cnt = 0; 
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 		} else {	/* failed the ISP abort */
@@ -3758,7 +2852,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 					 * completely.
 					 */
 					qla2x00_reset_adapter(ha);
-					qla2x00_abort_queues(ha, 0);
 					ha->flags.online = 0;
 					clear_bit(ISP_ABORT_RETRY,
 					    &ha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -187,23 +187,6 @@ qla2x00_is_wwn_zero(uint8_t *wwn)
 		return (0);
 }
 
-static __inline__ uint8_t
-qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int);
-static __inline__ uint8_t
-qla2x00_delay_lun(scsi_qla_host_t *, os_lun_t *, int);
-
-static __inline__ uint8_t
-qla2x00_suspend_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time, int count)
-{
-	return (__qla2x00_suspend_lun(ha, lq, time, count, 0));
-}
-
-static __inline__ uint8_t
-qla2x00_delay_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time)
-{
-	return (__qla2x00_suspend_lun(ha, lq, time, 1, 1));
-}
-
 static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
 /*
  * This routine will wait for fabric devices for
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -216,18 +216,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *
 			cur_seg++;
 		}
 	} else {
-		dma_addr_t	req_dma;
-		struct page	*page;
-		unsigned long	offset;
-
-		page = virt_to_page(cmd->request_buffer);
-		offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
-		req_dma = pci_map_page(ha->pdev, page, offset,
-		    cmd->request_bufflen, cmd->sc_data_direction);
-
-		sp->dma_handle = req_dma;
-
-		*cur_dsd++ = cpu_to_le32(req_dma);
+		*cur_dsd++ = cpu_to_le32(sp->dma_handle);
 		*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
 	}
 }
@@ -299,19 +288,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *
 			cur_seg++;
 		}
 	} else {
-		dma_addr_t	req_dma;
-		struct page	*page;
-		unsigned long	offset;
-
-		page = virt_to_page(cmd->request_buffer);
-		offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
-		req_dma = pci_map_page(ha->pdev, page, offset,
-		    cmd->request_bufflen, cmd->sc_data_direction);
-
-		sp->dma_handle = req_dma;
-
-		*cur_dsd++ = cpu_to_le32(LSD(req_dma));
-		*cur_dsd++ = cpu_to_le32(MSD(req_dma));
+		*cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
+		*cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
 		*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
 	}
 }
@@ -328,13 +306,11 @@ qla2x00_start_scsi(srb_t *sp)
 	int		ret;
 	unsigned long   flags;
 	scsi_qla_host_t	*ha;
-	fc_lun_t	*fclun;
 	struct scsi_cmnd *cmd;
 	uint32_t	*clr_ptr;
 	uint32_t        index;
 	uint32_t	handle;
 	cmd_entry_t	*cmd_pkt;
-	uint32_t        timeout;
 	struct scatterlist *sg;
 	uint16_t	cnt;
 	uint16_t	req_cnt;
@@ -344,10 +320,11 @@ qla2x00_start_scsi(srb_t *sp)
 
 	/* Setup device pointers. */
 	ret = 0;
-	fclun = sp->lun_queue->fclun;
-	ha = fclun->fcport->ha;
+	ha = sp->ha;
 	reg = ha->iobase;
 	cmd = sp->cmd;
+	/* So we know we haven't pci_map'ed anything yet */
+	tot_dsds = 0;
 
 	/* Send marker if required */
 	if (ha->marker_needed != 0) {
@@ -372,8 +349,27 @@ qla2x00_start_scsi(srb_t *sp)
 	if (index == MAX_OUTSTANDING_COMMANDS)
 		goto queuing_error;
 
+	/* Map the sg table so we have an accurate count of sg entries needed */
+	if (cmd->use_sg) {
+		sg = (struct scatterlist *) cmd->request_buffer;
+		tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+		    cmd->sc_data_direction);
+		if (tot_dsds == 0)
+			goto queuing_error;
+	} else if (cmd->request_bufflen) {
+		dma_addr_t	req_dma;
+
+		req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
+		    cmd->request_bufflen, cmd->sc_data_direction);
+		if (dma_mapping_error(req_dma))
+			goto queuing_error;
+
+		sp->dma_handle = req_dma;
+		tot_dsds = 1;
+	}
+
 	/* Calculate the number of request entries needed. */
-	req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments);
+	req_cnt = (ha->calc_request_entries)(tot_dsds);
 	if (ha->req_q_cnt < (req_cnt + 2)) {
 		cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
 		if (ha->req_ring_index < cnt)
@@ -385,19 +381,6 @@ qla2x00_start_scsi(srb_t *sp)
 	if (ha->req_q_cnt < (req_cnt + 2))
 		goto queuing_error;
 
-	/* Finally, we have enough space, now perform mappings. */
-	tot_dsds = 0;
-	if (cmd->use_sg) {
-		sg = (struct scatterlist *) cmd->request_buffer;
-		tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
-		    cmd->sc_data_direction);
-		if (tot_dsds == 0)
-			goto queuing_error;
-	} else if (cmd->request_bufflen) {
-	    tot_dsds++;
-	}
-	req_cnt = (ha->calc_request_entries)(tot_dsds);
-
 	/* Build command packet */
 	ha->current_outstanding_cmd = handle;
 	ha->outstanding_cmds[handle] = sp;
@@ -412,11 +395,9 @@ qla2x00_start_scsi(srb_t *sp)
 	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
 	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
 
-	/* Set target ID */
-	SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id);
-
-	/* Set LUN number*/
-	cmd_pkt->lun = cpu_to_le16(fclun->lun);
+	/* Set target ID and LUN number*/
+	SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
+	cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);
 
 	/* Update tagged queuing modifier */
 	cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
@@ -433,18 +414,6 @@ qla2x00_start_scsi(srb_t *sp)
 		}
 	}
 
-	/*
-	 * Allocate at least 5 (+ QLA_CMD_TIMER_DELTA) seconds for RISC timeout.
-	 */
-	timeout = (uint32_t)(cmd->timeout_per_command / HZ);
-	if (timeout > 65535)
-		cmd_pkt->timeout = __constant_cpu_to_le16(0);
-	else if (timeout > 25)
-		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout -
-		    (5 + QLA_CMD_TIMER_DELTA));
-	else
-		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout);
-
 	/* Load SCSI command packet. */
 	memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
 	cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
@@ -466,7 +435,6 @@ qla2x00_start_scsi(srb_t *sp)
 
 	ha->actthreads++;
 	ha->total_ios++;
-	sp->lun_queue->out_cnt++;
 	sp->flags |= SRB_DMA_VALID;
 	sp->state = SRB_ACTIVE_STATE;
 	sp->u_start = jiffies;
@@ -479,6 +447,14 @@ qla2x00_start_scsi(srb_t *sp)
 	return (QLA_SUCCESS);
 
 queuing_error:
+	if (cmd->use_sg && tot_dsds) {
+		sg = (struct scatterlist *) cmd->request_buffer;
+		pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
+		    cmd->sc_data_direction);
+	} else if (tot_dsds) {
+		pci_unmap_single(ha->pdev, sp->dma_handle,
+		    cmd->request_bufflen, cmd->sc_data_direction);
+	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	return (QLA_FUNCTION_FAILED);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -27,8 +27,6 @@ static void qla2x00_status_cont_entry(sc
 static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);
 static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *);
 
-static int qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *);
-
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
  * @irq:
@@ -93,7 +91,6 @@ qla2100_intr_handler(int irq, void *dev_
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-	qla2x00_next(ha);
 	ha->last_irq_cpu = _smp_processor_id();
 	ha->total_isr_cnt++;
 
@@ -107,9 +104,6 @@ qla2100_intr_handler(int irq, void *dev_
 		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
 	}
 
-	if (!list_empty(&ha->done_queue))
-		qla2x00_done(ha);
-
 	return (IRQ_HANDLED);
 }
 
@@ -206,7 +200,6 @@ qla2300_intr_handler(int irq, void *dev_
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-	qla2x00_next(ha);
 	ha->last_irq_cpu = _smp_processor_id();
 	ha->total_isr_cnt++;
 
@@ -220,9 +213,6 @@ qla2300_intr_handler(int irq, void *dev_
 		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
 	}
 
-	if (!list_empty(&ha->done_queue))
-		qla2x00_done(ha);
-
 	return (IRQ_HANDLED);
 }
 
@@ -707,14 +697,13 @@ qla2x00_process_completed_request(struct
 
 		if (ha->actthreads)
 			ha->actthreads--;
-		sp->lun_queue->out_cnt--;
 		CMD_COMPL_STATUS(sp->cmd) = 0L;
 		CMD_SCSI_STATUS(sp->cmd) = 0L;
 
 		/* Save ISP completion status */
 		sp->cmd->result = DID_OK << 16;
 		sp->fo_retry_cnt = 0;
-		add_to_done_queue(ha, sp);
+		qla2x00_sp_compl(ha, sp);
 	} else {
 		DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
 		    ha->host_no));
@@ -828,11 +817,8 @@ qla2x00_process_response_queue(struct sc
 static void
 qla2x00_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
 {
-	int		ret;
 	unsigned	b, t, l;
 	srb_t		*sp;
-	os_lun_t	*lq;
-	os_tgt_t	*tq;
 	fc_port_t	*fcport;
 	struct scsi_cmnd *cp;
 	uint16_t	comp_status;
@@ -882,21 +868,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 	if (ha->actthreads)
 		ha->actthreads--;
 
-	if (sp->lun_queue == NULL) {
-		DEBUG2(printk("scsi(%ld): Status Entry invalid lun pointer.\n",
-		    ha->host_no));
-		qla_printk(KERN_WARNING, ha,
-		    "Status Entry invalid lun pointer.\n");
-
-		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-		if (ha->dpc_wait && !ha->dpc_active) 
-			up(ha->dpc_wait);
-
-		return;
-	}
-
-	sp->lun_queue->out_cnt--;
-
 	comp_status = le16_to_cpu(pkt->comp_status);
 	/* Mask of reserved bits 12-15, before we examine the scsi status */
 	scsi_status = le16_to_cpu(pkt->scsi_status) & SS_MASK;
@@ -911,26 +882,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 	t = cp->device->id;
 	l = cp->device->lun,
 
-	tq = sp->tgt_queue;
-	lq = sp->lun_queue;
-
-	/*
-	 * If loop is in transient state Report DID_BUS_BUSY
-	 */
-	if ((comp_status != CS_COMPLETE || scsi_status != 0)) {
-		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
-		    (atomic_read(&ha->loop_down_timer) ||
-			atomic_read(&ha->loop_state) != LOOP_READY)) {
-
-			DEBUG2(printk("scsi(%ld:%d:%d:%d): Loop Not Ready - "
-			    "pid=%lx.\n",
-			    ha->host_no, b, t, l, cp->serial_number));
-
-			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
-			add_to_retry_queue(ha, sp);
-			return;
-		}
-	}
+	fcport = sp->fcport;
 
 	/* Check for any FCP transport errors. */
 	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
@@ -945,7 +897,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 			    pkt->rsp_info[6], pkt->rsp_info[7]));
 
 			cp->result = DID_BUS_BUSY << 16;
-			add_to_done_queue(ha, sp);
+			qla2x00_sp_compl(ha, sp);
 			return;
 		}
 	}
@@ -964,11 +916,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 			cp->resid = resid;
 			CMD_RESID_LEN(cp) = resid;
 		}
-		if (lscsi_status == SS_BUSY_CONDITION) {
-			cp->result = DID_BUS_BUSY << 16 | lscsi_status;
-			break;
-		}
-
 		cp->result = DID_OK << 16 | lscsi_status;
 
 		if (lscsi_status != SS_CHECK_CONDITION)
@@ -1002,14 +949,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 		if (sp->request_sense_length != 0)
 			ha->status_srb = sp;
 
-		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
-		    qla2x00_check_sense(cp, lq) == QLA_SUCCESS) {
-			/* Throw away status_cont if any */
-			ha->status_srb = NULL;
-			add_to_scsi_retry_queue(ha, sp);
-			return;
-		}
-
 		DEBUG5(printk("%s(): Check condition Sense data, "
 		    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
 		    __func__, ha->host_no, b, t, l, cp,
@@ -1035,12 +974,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 		 * Status.
 		 */
 		if (lscsi_status != 0) {
-			if (lscsi_status == SS_BUSY_CONDITION) {
-				cp->result = DID_BUS_BUSY << 16 |
-				    lscsi_status;
-				break;
-			}
-
 			cp->result = DID_OK << 16 | lscsi_status;
 
 			if (lscsi_status != SS_CHECK_CONDITION)
@@ -1072,12 +1005,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 			if (sp->request_sense_length != 0)
 				ha->status_srb = sp;
 
-			if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
-			    (qla2x00_check_sense(cp, lq) == QLA_SUCCESS)) {
-				ha->status_srb = NULL;
-				add_to_scsi_retry_queue(ha, sp);
-				return;
-			}
 			DEBUG5(printk("%s(): Check condition Sense data, "
 			    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
 			    __func__, ha->host_no, b, t, l, cp,
@@ -1149,30 +1076,15 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 		 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
 		 * retry_queue.
 		 */
-		fcport = sp->fclun->fcport;
 		DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
 		    "pid=%ld, compl status=0x%x, port state=0x%x\n",
 		    ha->host_no, t, l, cp->serial_number, comp_status,
 		    atomic_read(&fcport->state)));
 
-		if ((sp->flags & (SRB_IOCTL | SRB_TAPE)) ||
-		    atomic_read(&fcport->state) == FCS_DEVICE_DEAD) {
-			cp->result = DID_NO_CONNECT << 16;
-			if (atomic_read(&ha->loop_state) == LOOP_DOWN) 
-				sp->err_id = SRB_ERR_LOOP;
-			else
-				sp->err_id = SRB_ERR_PORT;
-			add_to_done_queue(ha, sp);
-		} else {
-			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
-			add_to_retry_queue(ha, sp);
-		}
-
+		cp->result = DID_BUS_BUSY << 16;
 		if (atomic_read(&fcport->state) == FCS_ONLINE) {
 			qla2x00_mark_device_lost(ha, fcport, 1);
 		}
-
-		return;
 		break;
 
 	case CS_RESET:
@@ -1180,13 +1092,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 		    "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
 		    ha->host_no, comp_status, scsi_status));
 
-		if (sp->flags & (SRB_IOCTL | SRB_TAPE)) {
-			cp->result = DID_RESET << 16;
-		} else {
-			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
-			add_to_retry_queue(ha, sp);
-			return;
-		}
+		cp->result = DID_RESET << 16;
 		break;
 
 	case CS_ABORTED:
@@ -1210,8 +1116,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 
 		cp->result = DID_BUS_BUSY << 16;
 
-		fcport = lq->fclun->fcport;
-
 		/* Check to see if logout occurred */
 		if ((le16_to_cpu(pkt->status_flags) & SF_LOGOUT_SENT)) {
 			qla2x00_mark_device_lost(ha, fcport, 1);
@@ -1227,16 +1131,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 
 		cp->result = DID_OK << 16 | lscsi_status; 
 
-		/* TODO: ??? */
-		/* Adjust queue depth */
-		ret = scsi_track_queue_full(cp->device,
-		    sp->lun_queue->out_cnt - 1);
-		if (ret) {
-			qla_printk(KERN_INFO, ha,
-			    "scsi(%ld:%d:%d:%d): Queue depth adjusted to %d.\n",
-			    ha->host_no, cp->device->channel, cp->device->id,
-			    cp->device->lun, ret);
-		}
 		break;
 
 	default:
@@ -1253,7 +1147,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha
 
 	/* Place command on done queue. */
 	if (ha->status_srb == NULL)
-		add_to_done_queue(ha, sp);
+		qla2x00_sp_compl(ha, sp);
 }
 
 /**
@@ -1298,8 +1192,8 @@ qla2x00_status_cont_entry(scsi_qla_host_
 
 		/* Place command on done queue. */
 		if (sp->request_sense_length == 0) {
-			add_to_done_queue(ha, sp);
 			ha->status_srb = NULL;
+			qla2x00_sp_compl(ha, sp);
 		}
 	}
 }
@@ -1341,8 +1235,6 @@ qla2x00_error_entry(scsi_qla_host_t *ha,
 		ha->outstanding_cmds[pkt->handle] = NULL;
 		if (ha->actthreads)
 			ha->actthreads--;
-		sp->lun_queue->out_cnt--;
-
 		/* Bad payload or header */
 		if (pkt->entry_status &
 		    (RF_INV_E_ORDER | RF_INV_E_COUNT |
@@ -1353,8 +1245,7 @@ qla2x00_error_entry(scsi_qla_host_t *ha,
 		} else {
 			sp->cmd->result = DID_ERROR << 16;
 		}
-		/* Place command on done queue. */
-		add_to_done_queue(ha, sp);
+		qla2x00_sp_compl(ha, sp);
 
 	} else if (pkt->entry_type == COMMAND_A64_TYPE ||
 	    pkt->entry_type == COMMAND_TYPE) {
@@ -1403,62 +1294,5 @@ qla2x00_ms_entry(scsi_qla_host_t *ha, ms
 	/* Free outstanding command slot. */
 	ha->outstanding_cmds[pkt->handle1] = NULL;
 
-	add_to_done_queue(ha, sp);
-}
-
-/**
- * qla2x00_check_sense() - Perform any sense data interrogation.
- * @cp: SCSI Command
- * @lq: Lun queue
- *
- * Returns QLA_SUCCESS if the lun queue is suspended, else
- * QLA_FUNCTION_FAILED  (lun queue not suspended).
- */
-static int 
-qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *lq)
-{
-	scsi_qla_host_t	*ha;
-	srb_t		*sp;
-	fc_port_t	*fcport;
-
-	ha = (scsi_qla_host_t *) cp->device->host->hostdata;
-	if ((cp->sense_buffer[0] & 0x70) != 0x70) {
-		return (QLA_FUNCTION_FAILED);
-	}
-
-	sp = (srb_t * )CMD_SP(cp);
-	sp->flags |= SRB_GOT_SENSE;
-
-	switch (cp->sense_buffer[2] & 0xf) {
-	case RECOVERED_ERROR:
-		cp->result = DID_OK << 16;
-		cp->sense_buffer[0] = 0;
-		break;
-
-	case NOT_READY:
-		fcport = lq->fclun->fcport;
-
-		/*
-		 * Suspend the lun only for hard disk device type.
-		 */
-		if ((fcport->flags & FCF_TAPE_PRESENT) == 0 &&
-		    lq->q_state != LUN_STATE_TIMEOUT) {
-			/*
-			 * If target is in process of being ready then suspend
-			 * lun for 6 secs and retry all the commands.
-			 */
-			if (cp->sense_buffer[12] == 0x4 &&
-			    cp->sense_buffer[13] == 0x1) {
-
-				/* Suspend the lun for 6 secs */
-				qla2x00_suspend_lun(ha, lq, 6,
-				    ql2xsuspendcount);
-
-				return (QLA_SUCCESS);
-			}
-		}
-		break;
-	}
-
-	return (QLA_FUNCTION_FAILED);
+	qla2x00_sp_compl(ha, sp);
 }
diff --git a/drivers/scsi/qla2xxx/qla_listops.h b/drivers/scsi/qla2xxx/qla_listops.h
deleted file mode 100644
--- a/drivers/scsi/qla2xxx/qla_listops.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/******************************************************************************
- *                  QLOGIC LINUX SOFTWARE
- *
- * QLogic ISP2x00 device driver for Linux 2.6.x
- * Copyright (C) 2003-2004 QLogic Corporation
- * (www.qlogic.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.
- *
- ******************************************************************************/
-
-/* Management functions for various lists */
-
-/* __add_to_done_queue()
- * 
- * Place SRB command on done queue.
- *
- * Input:
- *      ha           = host pointer
- *      sp           = srb pointer.
- * Locking:
- * 	this function assumes the ha->list_lock is already taken
- */
-static inline void 
-__add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-	/*
-        if (sp->state != SRB_NO_QUEUE_STATE && 
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-        /* Place block on done queue */
-        sp->cmd->host_scribble = (unsigned char *) NULL;
-        sp->state = SRB_DONE_STATE;
-        list_add_tail(&sp->list,&ha->done_queue);
-        ha->done_q_cnt++;
-	sp->ha = ha;
-}
-
-static inline void 
-__add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-	/*
-        if( sp->state != SRB_NO_QUEUE_STATE && 
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-        /* Place block on retry queue */
-        list_add_tail(&sp->list,&ha->retry_queue);
-        ha->retry_q_cnt++;
-        sp->flags |= SRB_WATCHDOG;
-        sp->state = SRB_RETRY_STATE;
-	sp->ha = ha;
-}
-
-static inline void 
-__add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-	/*
-        if( sp->state != SRB_NO_QUEUE_STATE && 
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-        /* Place block on retry queue */
-        list_add_tail(&sp->list,&ha->scsi_retry_queue);
-        ha->scsi_retry_q_cnt++;
-        sp->state = SRB_SCSI_RETRY_STATE;
-	sp->ha = ha;
-}
-
-static inline void 
-add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-        __add_to_done_queue(ha,sp);
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-static inline void 
-add_to_free_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-	mempool_free(sp, ha->srb_mempool);
-}
-
-static inline void 
-add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-        __add_to_retry_queue(ha,sp);
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-static inline void 
-add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-        __add_to_scsi_retry_queue(ha,sp);
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-/*
- * __del_from_retry_queue
- *      Function used to remove a command block from the
- *      watchdog timer queue.
- *
- *      Note: Must insure that command is on watchdog
- *            list before calling del_from_retry_queue
- *            if (sp->flags & SRB_WATCHDOG)
- *
- * Input: 
- *      ha = adapter block pointer.
- *      sp = srb pointer.
- * Locking:
- *	this function assumes the list_lock is already taken
- */
-static inline void 
-__del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        list_del_init(&sp->list);
-
-        sp->flags &= ~(SRB_WATCHDOG | SRB_BUSY);
-        sp->state = SRB_NO_QUEUE_STATE;
-        ha->retry_q_cnt--;
-}
-
-/*
- * __del_from_scsi_retry_queue
- *      Function used to remove a command block from the
- *      scsi retry queue.
- *
- * Input: 
- *      ha = adapter block pointer.
- *      sp = srb pointer.
- * Locking:
- *	this function assumes the list_lock is already taken
- */
-static inline void 
-__del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        list_del_init(&sp->list);
-
-        ha->scsi_retry_q_cnt--;
-        sp->state = SRB_NO_QUEUE_STATE;
-}
-
-/*
- * del_from_retry_queue
- *      Function used to remove a command block from the
- *      watchdog timer queue.
- *
- *      Note: Must insure that command is on watchdog
- *            list before calling del_from_retry_queue
- *            if (sp->flags & SRB_WATCHDOG)
- *
- * Input: 
- *      ha = adapter block pointer.
- *      sp = srb pointer.
- * Locking:
- *	this function takes and releases the list_lock
- */
-static inline void 
-del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        /*	if (unlikely(!(sp->flags & SRB_WATCHDOG)))
-        		BUG();*/
-        spin_lock_irqsave(&ha->list_lock, flags);
-
-        /*	if (unlikely(list_empty(&ha->retry_queue)))
-        		BUG();*/
-
-        __del_from_retry_queue(ha,sp);
-
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-/*
- * del_from_scsi_retry_queue
- *      Function used to remove a command block from the
- *      scsi retry queue.
- *
- * Input: 
- *      ha = adapter block pointer.
- *      sp = srb pointer.
- * Locking:
- *	this function takes and releases the list_lock
- */
-static inline void 
-del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-
-        /*	if (unlikely(list_empty(&ha->scsi_retry_queue)))
-        		BUG();*/
-
-        __del_from_scsi_retry_queue(ha,sp);
-
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-/*
- * __add_to_pending_queue
- *      Add the standard SCB job to the bottom of standard SCB commands.
- *
- * Input:
- * COMPLETE!!!
- *      q  = SCSI LU pointer.
- *      sp = srb pointer.
- *      SCSI_LU_Q lock must be already obtained.
- */
-static inline int 
-__add_to_pending_queue(struct scsi_qla_host *ha, srb_t * sp)
-{
-	int	empty;
-	/*
-        if( sp->state != SRB_NO_QUEUE_STATE &&
-        	sp->state != SRB_FREE_STATE &&
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-	empty = list_empty(&ha->pending_queue);
-	list_add_tail(&sp->list, &ha->pending_queue);
-	ha->qthreads++;
-	sp->state = SRB_PENDING_STATE;
-
-	return (empty);
-}
-
-static inline void 
-__add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t * sp)
-{
-	/*
-        if( sp->state != SRB_NO_QUEUE_STATE && 
-        	sp->state != SRB_FREE_STATE &&
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-	list_add(&sp->list, &ha->pending_queue);
-	ha->qthreads++;
-	sp->state = SRB_PENDING_STATE;
-}
-
-static inline int
-add_to_pending_queue(struct scsi_qla_host *ha, srb_t *sp)
-{
-	int	empty;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ha->list_lock, flags);
-	empty = __add_to_pending_queue(ha, sp);
-	spin_unlock_irqrestore(&ha->list_lock, flags);
-
-	return (empty);
-}
-static inline void
-add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t *sp)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ha->list_lock, flags);
-	__add_to_pending_queue_head(ha, sp);
-	spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-static inline void
-__del_from_pending_queue(struct scsi_qla_host *ha, srb_t *sp)
-{
-	list_del_init(&sp->list);
-	ha->qthreads--;
-	sp->state = SRB_NO_QUEUE_STATE;
-}
-
-/*
- * Failover Stuff.
- */
-static inline void
-__add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-	/*
-        if( sp->state != SRB_NO_QUEUE_STATE && 
-        	sp->state != SRB_ACTIVE_STATE)
-		BUG();
-	*/
-
-        list_add_tail(&sp->list,&ha->failover_queue);
-        ha->failover_cnt++;
-        sp->state = SRB_FAILOVER_STATE;
-	sp->ha = ha;
-}
-
-static inline void add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-
-        __add_to_failover_queue(ha,sp);
-
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-static inline void __del_from_failover_queue(struct scsi_qla_host * ha, srb_t *
-                sp)
-{
-        ha->failover_cnt--;
-        list_del_init(&sp->list);
-        sp->state = SRB_NO_QUEUE_STATE;
-}
-
-static inline void del_from_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-
-        __del_from_failover_queue(ha,sp);
-
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-static inline void 
-del_from_pending_queue(struct scsi_qla_host * ha, srb_t * sp)
-{
-        unsigned long flags;
-
-        spin_lock_irqsave(&ha->list_lock, flags);
-
-        __del_from_pending_queue(ha,sp);
-
-        spin_unlock_irqrestore(&ha->list_lock, flags);
-}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -858,8 +858,7 @@ qla2x00_abort_command(scsi_qla_host_t *h
 
 	DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);)
 
-	fcport = sp->fclun->fcport;
-
+	fcport = sp->fcport;
 	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
 	    atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
 		return 1;
@@ -884,7 +883,7 @@ qla2x00_abort_command(scsi_qla_host_t *h
 		mcp->mb[1] = fcport->loop_id << 8;
 	mcp->mb[2] = (uint16_t)handle;
 	mcp->mb[3] = (uint16_t)(handle >> 16);
-	mcp->mb[6] = (uint16_t)sp->fclun->lun;
+	mcp->mb[6] = (uint16_t)sp->cmd->device->lun;
 	mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
 	mcp->tov = 30;
@@ -980,30 +979,22 @@ qla2x00_abort_target(fc_port_t *fcport)
  *	Kernel context.
  */
 int
-qla2x00_target_reset(scsi_qla_host_t *ha, uint16_t b, uint16_t t)
+qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
-	os_tgt_t *tgt;
 
 	DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);)
 
-	tgt = TGT_Q(ha, t);
-	if (tgt->fcport == NULL) {
-		/* no target to abort */
-		return 0;
-	}
-	if (atomic_read(&tgt->fcport->state) != FCS_ONLINE) {
-		/* target not online */
+	if (atomic_read(&fcport->state) != FCS_ONLINE)
 		return 0;
-	}
 
 	mcp->mb[0] = MBC_TARGET_RESET;
 	if (HAS_EXTENDED_IDS(ha))
-		mcp->mb[1] = tgt->fcport->loop_id;
+		mcp->mb[1] = fcport->loop_id;
 	else
-		mcp->mb[1] = tgt->fcport->loop_id << 8;
+		mcp->mb[1] = fcport->loop_id << 8;
 	mcp->mb[2] = ha->loop_reset_delay;
 	mcp->out_mb = MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -63,7 +63,7 @@ module_param(ql2xlogintimeout, int, S_IR
 MODULE_PARM_DESC(ql2xlogintimeout,
 		"Login timeout value in seconds.");
 
-int qlport_down_retry;
+int qlport_down_retry = 30;
 module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(qlport_down_retry,
 		"Maximum number of command retries to a port that returns"
@@ -75,11 +75,6 @@ MODULE_PARM_DESC(ql2xretrycount,
 		"Maximum number of mid-layer retries allowed for a command.  "
 		"Default value is 20, ");
 
-int displayConfig;
-module_param(displayConfig, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(displayConfig,
-		"If 1 then display the configuration used in /etc/modprobe.conf.");
-
 int ql2xplogiabsentdevice;
 module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xplogiabsentdevice,
@@ -119,30 +114,11 @@ MODULE_PARM_DESC(ql2xsuspendcount,
 		"target returns a <NOT READY> status.  Default is 10 "
 		"iterations.");
 
-int ql2xdoinitscan = 1;
-module_param(ql2xdoinitscan, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(ql2xdoinitscan,
-		"Signal mid-layer to perform scan after driver load: 0 -- no "
-		"signal sent to mid-layer.");
-
 int ql2xloginretrycount = 0;
 module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xloginretrycount,
 		"Specify an alternate value for the NVRAM login retry count.");
 
-/*
- * Proc structures and functions
- */
-struct info_str {
-	char	*buffer;
-	int	length;
-	off_t	offset;
-	int	pos;
-};
-
-static void copy_mem_info(struct info_str *, char *, int);
-static int copy_info(struct info_str *, char *, ...);
-
 static void qla2x00_free_device(scsi_qla_host_t *);
 
 static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
@@ -151,6 +127,8 @@ static void qla2x00_config_dma_addressin
  * SCSI host template entry points 
  */
 static int qla2xxx_slave_configure(struct scsi_device * device);
+static int qla2xxx_slave_alloc(struct scsi_device *);
+static void qla2xxx_slave_destroy(struct scsi_device *);
 static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
 		void (*fn)(struct scsi_cmnd *));
 static int qla2xxx_eh_abort(struct scsi_cmnd *);
@@ -160,14 +138,9 @@ static int qla2xxx_eh_host_reset(struct 
 static int qla2x00_loop_reset(scsi_qla_host_t *ha);
 static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
 
-static int qla2x00_proc_info(struct Scsi_Host *, char *, char **,
-    off_t, int, int);
-
 static struct scsi_host_template qla2x00_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "qla2xxx",
-	.proc_name		= "qla2xxx",
-	.proc_info		= qla2x00_proc_info,
 	.queuecommand		= qla2x00_queuecommand,
 
 	.eh_abort_handler	= qla2xxx_eh_abort,
@@ -177,6 +150,8 @@ static struct scsi_host_template qla2x00
 
 	.slave_configure	= qla2xxx_slave_configure,
 
+	.slave_alloc		= qla2xxx_slave_alloc,
+	.slave_destroy		= qla2xxx_slave_destroy,
 	.this_id		= -1,
 	.cmd_per_lun		= 3,
 	.use_clustering		= ENABLE_CLUSTERING,
@@ -191,8 +166,6 @@ static struct scsi_host_template qla2x00
 
 static struct scsi_transport_template *qla2xxx_transport_template = NULL;
 
-static void qla2x00_display_fc_names(scsi_qla_host_t *);
-
 /* TODO Convert to inlines
  *
  * Timer routines
@@ -230,168 +203,6 @@ qla2x00_stop_timer(scsi_qla_host_t *ha)
 	ha->timer_active = 0;
 }
 
-void qla2x00_cmd_timeout(srb_t *);
-
-static __inline__ void qla2x00_callback(scsi_qla_host_t *, struct scsi_cmnd *);
-static __inline__ void sp_put(struct scsi_qla_host * ha, srb_t *sp);
-static __inline__ void sp_get(struct scsi_qla_host * ha, srb_t *sp);
-static __inline__ void
-qla2x00_delete_from_done_queue(scsi_qla_host_t *, srb_t *); 
-
-/*
-* qla2x00_callback
-*      Returns the completed SCSI command to LINUX.
-*
-* Input:
-*	ha -- Host adapter structure
-*	cmd -- SCSI mid-level command structure.
-* Returns:
-*      None
-* Note:From failover point of view we always get the sp
-*      from vis_ha pool in queuecommand.So when we put it 
-*      back to the pool it has to be the vis_ha.	 
-*      So rely on struct scsi_cmnd to get the vis_ha and not on sp. 		 	
-*/
-static inline void
-qla2x00_callback(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
-{
-	srb_t *sp = (srb_t *) CMD_SP(cmd);
-	scsi_qla_host_t *vis_ha;
-	os_lun_t *lq;
-	int got_sense;
-	unsigned long	cpu_flags = 0;
-
-	cmd->host_scribble = (unsigned char *) NULL;
-	vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
-
-	if (sp == NULL) {
-		qla_printk(KERN_INFO, ha,
-			"%s(): **** CMD derives a NULL SP\n",
-			__func__);
-                DEBUG2(BUG();)
-		return;
-	}
-
-	/*
-	 * If command status is not DID_BUS_BUSY then go ahead and freed sp.
-	 */
-	/*
-	 * Cancel command timeout
-	 */
-	qla2x00_delete_timer_from_cmd(sp);
-
-	/*
-	 * Put SP back in the free queue
-	 */
-	sp->cmd   = NULL;
-	CMD_SP(cmd) = NULL;
-	lq = sp->lun_queue;
-	got_sense = (sp->flags & SRB_GOT_SENSE)? 1: 0;
-	add_to_free_queue(vis_ha, sp);
-
-	if (host_byte(cmd->result) == DID_OK) {
-		/* device ok */
-		ha->total_bytes += cmd->bufflen;
-		if (!got_sense) {
-			/* If lun was suspended then clear retry count */
-			spin_lock_irqsave(&lq->q_lock, cpu_flags);
-			if (!test_bit(LUN_EXEC_DELAYED, &lq->q_flag))
-				lq->q_state = LUN_STATE_READY;
-			spin_unlock_irqrestore(&lq->q_lock, cpu_flags);
-		}
-	} else if (host_byte(cmd->result) == DID_ERROR) {
-		/* device error */
-		ha->total_dev_errs++;
-	}
-
-	/* Call the mid-level driver interrupt handler */
-	(*(cmd)->scsi_done)(cmd);
-}
-
-/**************************************************************************
-* sp_put
-*
-* Description:
-*   Decrement reference count and call the callback if we're the last
-*   owner of the specified sp. Will get the host_lock before calling
-*   the callback.
-*
-* Input:
-*   ha - pointer to the scsi_qla_host_t where the callback is to occur.
-*   sp - pointer to srb_t structure to use.
-*
-* Returns:
-*
-**************************************************************************/
-static inline void
-sp_put(struct scsi_qla_host * ha, srb_t *sp)
-{
-        if (atomic_read(&sp->ref_count) == 0) {
-		qla_printk(KERN_INFO, ha,
-			"%s(): **** SP->ref_count not zero\n",
-			__func__);
-                DEBUG2(BUG();)
-
-                return;
-	}
-
-        if (!atomic_dec_and_test(&sp->ref_count)) {
-                return;
-        }
-
-        qla2x00_callback(ha, sp->cmd);
-}
-
-/**************************************************************************
-* sp_get
-*
-* Description:
-*   Increment reference count of the specified sp.
-*
-* Input:
-*   sp - pointer to srb_t structure to use.
-*
-* Returns:
-*
-**************************************************************************/
-static inline void
-sp_get(struct scsi_qla_host * ha, srb_t *sp)
-{
-        atomic_inc(&sp->ref_count);
-
-        if (atomic_read(&sp->ref_count) > 2) {
-		qla_printk(KERN_INFO, ha,
-			"%s(): **** SP->ref_count greater than two\n",
-			__func__);
-                DEBUG2(BUG();)
-
-		return;
-	}
-}
-
-static inline void 
-qla2x00_delete_from_done_queue(scsi_qla_host_t *dest_ha, srb_t *sp) 
-{
-	/* remove command from done list */
-	list_del_init(&sp->list);
-	dest_ha->done_q_cnt--;
-	sp->state = SRB_NO_QUEUE_STATE;
-
-	if (sp->flags & SRB_DMA_VALID) {
-		sp->flags &= ~SRB_DMA_VALID;
-
-		/* Release memory used for this I/O */
-		if (sp->cmd->use_sg) {
-			pci_unmap_sg(dest_ha->pdev, sp->cmd->request_buffer,
-			    sp->cmd->use_sg, sp->cmd->sc_data_direction);
-		} else if (sp->cmd->request_bufflen) {
-			pci_unmap_page(dest_ha->pdev, sp->dma_handle,
-			    sp->cmd->request_bufflen,
-			    sp->cmd->sc_data_direction);
-		}
-	}
-}
-
 static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
@@ -400,186 +211,12 @@ static uint8_t qla2x00_mem_alloc(scsi_ql
 static void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
-static srb_t *qla2x00_get_new_sp(scsi_qla_host_t *ha);
-
-static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, char *, loff_t,
-    size_t);
-static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, char *, loff_t,
-    size_t);
-static struct bin_attribute sysfs_fw_dump_attr = {
-	.attr = {
-		.name = "fw_dump",
-		.mode = S_IRUSR | S_IWUSR,
-		.owner = THIS_MODULE,
-	},
-	.size = 0,
-	.read = qla2x00_sysfs_read_fw_dump,
-	.write = qla2x00_sysfs_write_fw_dump,
-};
-static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, char *, loff_t,
-    size_t);
-static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, char *, loff_t,
-    size_t);
-static struct bin_attribute sysfs_nvram_attr = {
-	.attr = {
-		.name = "nvram",
-		.mode = S_IRUSR | S_IWUSR,
-		.owner = THIS_MODULE,
-	},
-	.size = sizeof(nvram_t),
-	.read = qla2x00_sysfs_read_nvram,
-	.write = qla2x00_sysfs_write_nvram,
-};
+static srb_t *qla2x00_get_new_sp(scsi_qla_host_t *);
+static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
+void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
 
 /* -------------------------------------------------------------------------- */
 
-
-/* SysFS attributes. */
-static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf,
-    loff_t off, size_t count)
-{
-	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-
-	if (ha->fw_dump_reading == 0)
-		return 0;
-	if (off > ha->fw_dump_buffer_len)
-		return 0;
-	if (off + count > ha->fw_dump_buffer_len)
-		count = ha->fw_dump_buffer_len - off;
-
-	memcpy(buf, &ha->fw_dump_buffer[off], count);
-
-	return (count);
-}
-
-static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf,
-    loff_t off, size_t count)
-{
-	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	int reading;
-	uint32_t dump_size;
-
-	if (off != 0)
-		return (0);
-
-	reading = simple_strtol(buf, NULL, 10);
-	switch (reading) {
-	case 0:
-		if (ha->fw_dump_reading == 1) {
-			qla_printk(KERN_INFO, ha,
-			    "Firmware dump cleared on (%ld).\n",
-			    ha->host_no);
-
-			vfree(ha->fw_dump_buffer);
-			free_pages((unsigned long)ha->fw_dump,
-			    ha->fw_dump_order);
-
-			ha->fw_dump_reading = 0;
-			ha->fw_dump_buffer = NULL;
-			ha->fw_dump = NULL;
-		}
-		break;
-	case 1:
-		if (ha->fw_dump != NULL && !ha->fw_dump_reading) {
-			ha->fw_dump_reading = 1;
-
-			dump_size = FW_DUMP_SIZE_1M;
-			if (ha->fw_memory_size < 0x20000) 
-				dump_size = FW_DUMP_SIZE_128K;
-			else if (ha->fw_memory_size < 0x80000) 
-				dump_size = FW_DUMP_SIZE_512K;
-			ha->fw_dump_buffer = (char *)vmalloc(dump_size);
-			if (ha->fw_dump_buffer == NULL) {
-				qla_printk(KERN_WARNING, ha,
-				    "Unable to allocate memory for firmware "
-				    "dump buffer (%d).\n", dump_size);
-
-				ha->fw_dump_reading = 0;
-				return (count);
-			}
-			qla_printk(KERN_INFO, ha,
-			    "Firmware dump ready for read on (%ld).\n",
-			    ha->host_no);
-			memset(ha->fw_dump_buffer, 0, dump_size);
-			if (IS_QLA2100(ha) || IS_QLA2200(ha))
- 				qla2100_ascii_fw_dump(ha);
- 			else
- 				qla2300_ascii_fw_dump(ha);
-			ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
-		}
-		break;
-	}
-	return (count);
-}
-
-static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf,
-    loff_t off, size_t count)
-{
-	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	uint16_t	*witer;
-	unsigned long	flags;
-	uint16_t	cnt;
-
-	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
-		return 0;
-
-	/* Read NVRAM. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qla2x00_lock_nvram_access(ha);
- 	witer = (uint16_t *)buf;
- 	for (cnt = 0; cnt < count / 2; cnt++) {
-		*witer = cpu_to_le16(qla2x00_get_nvram_word(ha,
-		    cnt+ha->nvram_base));
-		witer++;
- 	}
-	qla2x00_unlock_nvram_access(ha);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-	return (count);
-}
-
-static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf,
-    loff_t off, size_t count)
-{
-	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	uint8_t		*iter;
-	uint16_t	*witer;
-	unsigned long	flags;
-	uint16_t	cnt;
-	uint8_t		chksum;
-
-	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
-		return 0;
-
-	/* Checksum NVRAM. */
-	iter = (uint8_t *)buf;
-	chksum = 0;
-	for (cnt = 0; cnt < count - 1; cnt++)
-		chksum += *iter++;
-	chksum = ~chksum + 1;
-	*iter = chksum;
-
-	/* Write NVRAM. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qla2x00_lock_nvram_access(ha);
-	qla2x00_release_nvram_protection(ha);
- 	witer = (uint16_t *)buf;
-	for (cnt = 0; cnt < count / 2; cnt++) {
-		qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,
-		    cpu_to_le16(*witer));
-		witer++;
-	}
-	qla2x00_unlock_nvram_access(ha);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-	return (count);
-}
-
-/* -------------------------------------------------------------------------- */
 static char *
 qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str)
 {
@@ -661,210 +298,76 @@ qla2x00_get_fw_version_str(struct scsi_q
 * handling).
 **************************************************************************/
 static int
-qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-	fc_port_t	*fcport;
-	os_lun_t	*lq;
-	os_tgt_t	*tq;
-	scsi_qla_host_t	*ha, *ha2;
-	srb_t		*sp;
-	struct Scsi_Host *host;
-	unsigned int	b, t, l;
-	unsigned long	handle;
-	int		was_empty;
-
+	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
+	srb_t *sp;
+	int rval;
 
-	host = cmd->device->host;
-	ha = (scsi_qla_host_t *) host->hostdata;
-	was_empty = 1;
+	if (!fcport) {
+		cmd->result = DID_NO_CONNECT << 16;
+		goto qc_fail_command;
+	}
 
-	cmd->scsi_done = fn;
+	if (atomic_read(&fcport->state) != FCS_ONLINE) {
+		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
+		    atomic_read(&ha->loop_state) == LOOP_DEAD) {
+			cmd->result = DID_NO_CONNECT << 16;
+			goto qc_fail_command;
+		}
+		goto qc_host_busy;
+	}
 
 	spin_unlock_irq(ha->host->host_lock);
 
-	/*
-	 * Allocate a command packet from the "sp" pool.  If we cant get back
-	 * one then let scsi layer come back later.
-	 */
+	/* Allocate a command packet from the "sp" pool. */
 	if ((sp = qla2x00_get_new_sp(ha)) == NULL) {
-		qla_printk(KERN_WARNING, ha,
-		    "Couldn't allocate memory for sp - retried.\n");
-
-		spin_lock_irq(ha->host->host_lock);
-
-		return (1);
+		goto qc_host_busy_lock;
 	}
 
+	sp->ha = ha;
+	sp->fcport = fcport;
 	sp->cmd = cmd;
-	CMD_SP(cmd) = (void *)sp;
-
 	sp->flags = 0;
-	if (CMD_RESID_LEN(cmd) & SRB_IOCTL) {
-		/* Need to set sp->flags */
-		sp->flags |= SRB_IOCTL;
-		CMD_RESID_LEN(cmd) = 0; /* Clear it since no more use. */
-	}
-
-	sp->fo_retry_cnt = 0;
 	sp->err_id = 0;
 
-	/* Generate LU queue on bus, target, LUN */
-	b = cmd->device->channel;
-	t = cmd->device->id;
-	l = cmd->device->lun;
-
-	/*
-	 * Start Command Timer. Typically it will be 2 seconds less than what
-	 * is requested by the Host such that we can return the IO before
-	 * aborts are called.
-	 */
-	if ((cmd->timeout_per_command / HZ) > QLA_CMD_TIMER_DELTA)
-		qla2x00_add_timer_to_cmd(sp,
-		    (cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA);
-	else
-		qla2x00_add_timer_to_cmd(sp, cmd->timeout_per_command / HZ);
-
-	if (l >= ha->max_luns) {
-		cmd->result = DID_NO_CONNECT << 16;
-		sp->err_id = SRB_ERR_PORT;
-
-		spin_lock_irq(ha->host->host_lock);
-
-		sp_put(ha, sp);
-
-		return (0);
-	}
-
-	if ((tq = (os_tgt_t *) TGT_Q(ha, t)) != NULL &&
-	    (lq = (os_lun_t *) LUN_Q(ha, t, l)) != NULL) {
-		fcport = lq->fclun->fcport;
-		ha2 = fcport->ha;
-	} else {
-		lq = NULL;
-		fcport = NULL;
-		ha2 = ha;
-	}
-
-	/* Set an invalid handle until we issue the command to ISP */
-	/* then we will set the real handle value.                 */
-	handle = INVALID_HANDLE;
-	cmd->host_scribble = (unsigned char *)handle;
-
-	/* Bookkeeping information */
-	sp->r_start = jiffies;		/* Time the request was recieved. */
-	sp->u_start = 0;
-
-	/* Setup device queue pointers. */
-	sp->tgt_queue = tq;
-	sp->lun_queue = lq;
-
-	/*
-	 * NOTE : q is NULL
-	 *
-	 * 1. When device is added from persistent binding but has not been
-	 *    discovered yet.The state of loopid == PORT_AVAIL.
-	 * 2. When device is never found on the bus.(loopid == UNUSED)
-	 *
-	 * IF Device Queue is not created, or device is not in a valid state
-	 * and link down error reporting is enabled, reject IO.
-	 */
-	if (fcport == NULL) {
-		DEBUG3(printk("scsi(%ld:%2d:%2d): port unavailable\n",
-		    ha->host_no,t,l));
-
-		cmd->result = DID_NO_CONNECT << 16;
-		sp->err_id = SRB_ERR_PORT;
-
-		spin_lock_irq(ha->host->host_lock);
-
-		sp_put(ha, sp);
-
-		return (0);
-	}
-
-	/* Only modify the allowed count if the target is a *non* tape device */
-	if ((fcport->flags & FCF_TAPE_PRESENT) == 0) {
-		sp->flags &= ~SRB_TAPE;
-		if (cmd->allowed < ql2xretrycount) {
-			cmd->allowed = ql2xretrycount;
-		}
-	} else
-		sp->flags |= SRB_TAPE;
-
-	DEBUG5(printk("scsi(%ld:%2d:%2d): (queuecmd) queue sp = %p, "
-	    "flags=0x%x fo retry=%d, pid=%ld\n",
-	    ha->host_no, t, l, sp, sp->flags, sp->fo_retry_cnt,
-	    cmd->serial_number));
-	DEBUG5(qla2x00_print_scsi_cmd(cmd));
-
-	sp->fclun = lq->fclun;
-	sp->ha = ha2;
-
-	if (cmd->sc_data_direction == DMA_BIDIRECTIONAL &&
-	    cmd->request_bufflen != 0) {
+	CMD_SP(cmd) = (void *)sp;
+	cmd->scsi_done = done;
 
-		DEBUG2(printk(KERN_WARNING
-		    "scsi(%ld): Incorrect data direction - transfer "
-		    "length=%d, direction=%d, pid=%ld, opcode=%x\n",
-		    ha->host_no, cmd->request_bufflen, cmd->sc_data_direction,
-		    cmd->serial_number, cmd->cmnd[0]));
+	rval = qla2x00_start_scsi(sp);
+	if (rval != QLA_SUCCESS)
+		goto qc_host_busy_free_sp;
+
+	/* Manage unprocessed RIO/ZIO commands in response queue. */
+	if (ha->flags.online && ha->flags.process_response_queue &&
+	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		qla2x00_process_response_queue(ha);
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
 
-	/* Final pre-check :
-	 *
-	 *	Either PORT_DOWN_TIMER OR LINK_DOWN_TIMER Expired.
-	 */
-	if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-	    atomic_read(&ha2->loop_state) == LOOP_DEAD) {
-		/*
-		 * Add the command to the done-queue for later failover
-		 * processing.
-		 */
-		cmd->result = DID_NO_CONNECT << 16;
-		if (atomic_read(&ha2->loop_state) == LOOP_DOWN) 
-			sp->err_id = SRB_ERR_LOOP;
-		else
-			sp->err_id = SRB_ERR_PORT;
-
-		add_to_done_queue(ha, sp);
-		qla2x00_done(ha);
+	spin_lock_irq(ha->host->host_lock);
 
-		spin_lock_irq(ha->host->host_lock);
-		return (0);
-	}
+	return 0;
 
-	if (tq && test_bit(TQF_SUSPENDED, &tq->flags) &&
-	    (sp->flags & SRB_TAPE) == 0) {
-		/* If target suspended put incoming I/O in retry_q. */
-		qla2x00_extend_timeout(sp->cmd, 10);
-		add_to_scsi_retry_queue(ha, sp);
-	} else
-		was_empty = add_to_pending_queue(ha, sp);
-
-	if ((IS_QLA2100(ha) || IS_QLA2200(ha)) && ha->flags.online) {
-		if (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
-			unsigned long flags;
+qc_host_busy_free_sp:
+	qla2x00_sp_free_dma(ha, sp);
+	CMD_SP(cmd) = NULL;
+	mempool_free(sp, ha->srb_mempool);
 
-			spin_lock_irqsave(&ha->hardware_lock, flags);	
-			qla2x00_process_response_queue(ha);
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		}
-	}
+qc_host_busy_lock:
+	spin_lock_irq(ha->host->host_lock);
 
-	/* We submit to the hardware if:
-	 *
-	 *	1) we're on the cpu the irq's arrive on or
-	 *	2) there are very few io's outstanding.
-	 *
-	 * In all other cases we'll let an irq pick up our IO and submit it
-	 * to the controller to improve affinity.
-	 */
-	if (_smp_processor_id() == ha->last_irq_cpu || was_empty)
-		qla2x00_next(ha);
+qc_host_busy:
+	return SCSI_MLQUEUE_HOST_BUSY;
 
-	spin_lock_irq(ha->host->host_lock);
+qc_fail_command:
+	done(cmd);
 
-	return (0);
+	return 0;
 }
 
 /*
@@ -886,54 +389,21 @@ static int
 qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
 {
 #define ABORT_POLLING_PERIOD	HZ
-#define ABORT_WAIT_TIME		((10 * HZ) / (ABORT_POLLING_PERIOD))
-
-	int		found = 0;
-	int		done = 0;
-	srb_t		*rp = NULL;
-	struct list_head *list, *temp;
-	u_long		max_wait_time = ABORT_WAIT_TIME;
-
-	do {
-		/* Check on done queue */
-		spin_lock(&ha->list_lock);
-		list_for_each_safe(list, temp, &ha->done_queue) {
-			rp = list_entry(list, srb_t, list);
-
-			/*
-			 * Found command. Just exit and wait for the cmd sent
-			 * to OS.
-			*/
-			if (cmd == rp->cmd) {
-				found++;
-				DEBUG3(printk("%s: found in done queue.\n",
-				    __func__);)
-				break;
-			}
-		}
-		spin_unlock(&ha->list_lock);
-
-		/* Complete the cmd right away. */
-		if (found) { 
-			qla2x00_delete_from_done_queue(ha, rp);
-			sp_put(ha, rp);
-			done++;
-			break;
-		}
-
-		spin_unlock_irq(ha->host->host_lock);
+#define ABORT_WAIT_ITER		((10 * HZ) / (ABORT_POLLING_PERIOD))
+	unsigned long wait_iter = ABORT_WAIT_ITER;
+	int ret = QLA_SUCCESS;
 
+	while (CMD_SP(cmd)) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(ABORT_POLLING_PERIOD);
 
-		spin_lock_irq(ha->host->host_lock);
-
-	} while ((max_wait_time--));
-
-	if (done)
-		DEBUG2(printk(KERN_INFO "%s: found cmd=%p.\n", __func__, cmd));
+		if (--wait_iter)
+			break;
+	}
+	if (CMD_SP(cmd))
+		ret = QLA_FUNCTION_FAILED;
 
-	return (done);
+	return ret;
 }
 
 /*
@@ -1032,246 +502,70 @@ qla2x00_wait_for_loop_ready(scsi_qla_hos
 int
 qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
-	int		i;
-	int		return_status = FAILED;
-	os_lun_t	*q;
-	scsi_qla_host_t *ha;
-	scsi_qla_host_t *vis_ha;
-	srb_t		*sp;
-	srb_t		*rp;
-	struct list_head *list, *temp;
-	struct Scsi_Host *host;
-	uint8_t		found = 0;
-	unsigned int	b, t, l;
-
-	/* Get the SCSI request ptr */
-	sp = (srb_t *) CMD_SP(cmd);
-
-	/*
-	 * If sp is NULL, command is already returned.
-	 * sp is NULLED just before we call back scsi_done
-	 *
-	 */
-	if ((sp == NULL)) {
-		/* no action - we don't have command */
-		qla_printk(KERN_INFO, to_qla_host(cmd->device->host),
-		    "qla2xxx_eh_abort: cmd already done sp=%p\n", sp);
-		DEBUG(printk("qla2xxx_eh_abort: cmd already done sp=%p\n", sp);)
-		return SUCCESS;
-	}
-	if (sp) {
-		DEBUG(printk("qla2xxx_eh_abort: refcount %i \n",
-		    atomic_read(&sp->ref_count));)
-	}
-
-	vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
-	ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-
-	host = ha->host;
-
-	/* Generate LU queue on bus, target, LUN */
-	b = cmd->device->channel;
-	t = cmd->device->id;
-	l = cmd->device->lun;
-	q = GET_LU_Q(vis_ha, t, l);
-
-	qla_printk(KERN_INFO, ha, 
-	    "%s scsi(%ld:%d:%d:%d): cmd_timeout_in_sec=0x%x.\n", __func__,
-	    ha->host_no, (int)b, (int)t, (int)l,
-	    cmd->timeout_per_command / HZ);
-
-	/*
-	 * if no LUN queue then something is very wrong!!!
-	 */
-	if (q == NULL) {
-		qla_printk(KERN_WARNING, ha,
-			"qla2x00: (%x:%x:%x) No LUN queue.\n", b, t, l);
+	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	srb_t *sp;
+	int ret, i;
+	unsigned int id, lun;
+	unsigned long serial;
+	unsigned long flags;
 
-		/* no action - we don't have command */
+	if (!CMD_SP(cmd))
 		return FAILED;
-	}
 
-	DEBUG2(printk("scsi(%ld): ABORTing cmd=%p sp=%p jiffies = 0x%lx, "
-	    "timeout=%x, dpc_flags=%lx, vis_ha->dpc_flags=%lx q->flag=%lx\n",
-	    ha->host_no, cmd, sp, jiffies, cmd->timeout_per_command / HZ,
-	    ha->dpc_flags, vis_ha->dpc_flags, q->q_flag));
-	DEBUG2(qla2x00_print_scsi_cmd(cmd));
+	ret = FAILED;
+
+	id = cmd->device->id;
+	lun = cmd->device->lun;
+	serial = cmd->serial_number;
 
+	/* Check active list for command command. */
 	spin_unlock_irq(ha->host->host_lock);
-	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
-		DEBUG2(printk("%s failed:board disabled\n", __func__);)
-		spin_lock_irq(ha->host->host_lock);
-		return FAILED;
-	}
-	spin_lock_irq(ha->host->host_lock);
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
+		sp = ha->outstanding_cmds[i];
 
-	/* Search done queue */
-	spin_lock(&ha->list_lock);
-	list_for_each_safe(list, temp, &ha->done_queue) {
-		rp = list_entry(list, srb_t, list);
+		if (sp == NULL)
+			continue;
 
-		if (cmd != rp->cmd)
+		if (sp->cmd != cmd)
 			continue;
 
-		/*
-		 * Found command.Remove it from done list.
-		 * And proceed to post completion to scsi mid layer.
-		 */
-		return_status = SUCCESS;
-		found++;
-		qla2x00_delete_from_done_queue(ha, sp);
+		DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld "
+		    "sp->state=%x\n", __func__, ha->host_no, sp, serial,
+		    sp->state));
+		DEBUG3(qla2x00_print_scsi_cmd(cmd);)
+
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		if (qla2x00_abort_command(ha, sp)) {
+			DEBUG2(printk("%s(%ld): abort_command "
+			    "mbx failed.\n", __func__, ha->host_no));
+		} else {
+			DEBUG3(printk("%s(%ld): abort_command "
+			    "mbx success.\n", __func__, ha->host_no));
+			ret = SUCCESS;
+		}
+		spin_lock_irqsave(&ha->hardware_lock, flags);
 
 		break;
-	} /* list_for_each_safe() */
-	spin_unlock(&ha->list_lock);
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-	/*
-	 * Return immediately if the aborted command was already in the done
-	 * queue
-	 */
-	if (found) {
-		qla_printk(KERN_INFO, ha,
-		    "qla2xxx_eh_abort: Returning completed command=%p sp=%p\n",
-		    cmd, sp);
-		sp_put(ha, sp);
-		return (return_status);
+	/* Wait for the command to be returned. */
+	if (ret == SUCCESS) {
+		if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
+			qla_printk(KERN_ERR, ha, 
+			    "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
+			    "%x.\n", ha->host_no, id, lun, serial, ret);
+		}
 	}
-	
+	spin_lock_irq(ha->host->host_lock);
 
-	/*
-	 * See if this command is in the retry queue
-	 */
-	DEBUG3(printk("qla2xxx_eh_abort: searching sp %p in retry "
-		    "queue.\n", sp);)
+	qla_printk(KERN_INFO, ha, 
+	    "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no,
+	    id, lun, serial, ret);
 
-	spin_lock(&ha->list_lock);
-	list_for_each_safe(list, temp, &ha->retry_queue) {
-		rp = list_entry(list, srb_t, list);
-
-		if (cmd != rp->cmd)
-			continue;
-
-
-		DEBUG2(printk("qla2xxx_eh_abort: found "
-		    "in retry queue. SP=%p\n", sp);)
-
-		__del_from_retry_queue(ha, rp);
-		cmd->result = DID_ABORT << 16;
-		__add_to_done_queue(ha, rp);
-
-		return_status = SUCCESS;
-		found++;
-
-		break;
-
-	} 
-	spin_unlock(&ha->list_lock);
-
-
-	/*
-	 * Our SP pointer points at the command we want to remove from the
-	 * pending queue providing we haven't already sent it to the adapter.
-	 */
-	if (!found) {
-		DEBUG3(printk("qla2xxx_eh_abort: searching sp %p "
-		    "in pending queue.\n", sp);)
-
-		spin_lock(&vis_ha->list_lock);
-		list_for_each_safe(list, temp, &vis_ha->pending_queue) {
-			rp = list_entry(list, srb_t, list);
-
-			if (rp->cmd != cmd)
-				continue;
-
-			/* Remove srb from LUN queue. */
-			rp->flags |=  SRB_ABORTED;
-
-			DEBUG2(printk("qla2xxx_eh_abort: Cmd in pending queue."
-			    " serial_number %ld.\n",
-			    sp->cmd->serial_number);)
-
-			__del_from_pending_queue(vis_ha, rp);
-			cmd->result = DID_ABORT << 16;
-
-			__add_to_done_queue(vis_ha, rp);
-
-			return_status = SUCCESS;
-
-			found++;
-			break;
-		} /* list_for_each_safe() */
-		spin_unlock(&vis_ha->list_lock);
-	} /*End of if !found */
-
-	if (!found) {  /* find the command in our active list */
-		DEBUG3(printk("qla2xxx_eh_abort: searching sp %p "
-		    "in outstanding queue.\n", sp);)
-
-		spin_lock(&ha->hardware_lock);
-		for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-			sp = ha->outstanding_cmds[i];
-
-			if (sp == NULL)
-				continue;
-
-			if (sp->cmd != cmd)
-				continue;
-
-			DEBUG2(printk("qla2xxx_eh_abort(%ld): aborting sp %p "
-			    "from RISC. pid=%ld sp->state=%x q->q_flag=%lx\n",
-			    ha->host_no, sp, sp->cmd->serial_number,
-			    sp->state, q->q_flag);)
-			DEBUG(qla2x00_print_scsi_cmd(cmd);)
-
-			/* Get a reference to the sp and drop the lock.*/
-			sp_get(ha, sp);
-
-			spin_unlock(&ha->hardware_lock);
-			spin_unlock_irq(ha->host->host_lock);
-
-			if (qla2x00_abort_command(ha, sp)) {
-				DEBUG2(printk("qla2xxx_eh_abort: abort_command "
-				    "mbx failed.\n");)
-				return_status = FAILED;
-			} else {
-				DEBUG3(printk("qla2xxx_eh_abort: abort_command "
-				    " mbx success.\n");)
-				return_status = SUCCESS;
-			}
-
-			sp_put(ha,sp);
-
-			spin_lock_irq(ha->host->host_lock);
-			spin_lock(&ha->hardware_lock);
-
-			/*
-			 * Regardless of mailbox command status, go check on
-			 * done queue just in case the sp is already done.
-			 */
-			break;
-
-		}/*End of for loop */
-		spin_unlock(&ha->hardware_lock);
-
-	} /*End of if !found */
-
-	/* Waiting for our command in done_queue to be returned to OS.*/
-	if (qla2x00_eh_wait_on_command(ha, cmd) != 0) {
-		DEBUG2(printk("qla2xxx_eh_abort: cmd returned back to OS.\n");)
-		return_status = SUCCESS;
-	}
-
-	if (return_status == FAILED) {
-		qla_printk(KERN_INFO, ha, 
-			"qla2xxx_eh_abort Exiting: status=Failed\n");
-		return FAILED;
-	}
-
-	DEBUG2(printk("qla2xxx_eh_abort: Exiting. return_status=0x%x.\n",
-	    return_status));
-
-	return return_status;
-}
+	return ret;
+}
 
 /**************************************************************************
 * qla2x00_eh_wait_for_pending_target_commands
@@ -1294,6 +588,7 @@ qla2x00_eh_wait_for_pending_target_comma
 	int	status;
 	srb_t		*sp;
 	struct scsi_cmnd *cmd;
+	unsigned long flags;
 
 	status = 0;
 
@@ -1302,20 +597,19 @@ qla2x00_eh_wait_for_pending_target_comma
 	 * array
 	 */
 	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-		spin_lock(&ha->hardware_lock);
+		spin_lock_irqsave(&ha->hardware_lock, flags);
 		sp = ha->outstanding_cmds[cnt];
 		if (sp) {
 			cmd = sp->cmd;
-			spin_unlock(&ha->hardware_lock);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 			if (cmd->device->id == t) {
 				if (!qla2x00_eh_wait_on_command(ha, cmd)) {
 					status = 1;
 					break;
 				}
 			}
-		}
-		else {
-			spin_unlock(&ha->hardware_lock);
+		} else {
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		}
 	}
 	return (status);
@@ -1344,96 +638,42 @@ qla2x00_eh_wait_for_pending_target_comma
 int
 qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
-	int		return_status;
-	unsigned int	b, t, l;
-	scsi_qla_host_t	*ha;
-	os_tgt_t	*tq;
-	os_lun_t	*lq;
-	fc_port_t	*fcport_to_reset;
-	srb_t		*rp;
-	struct list_head *list, *temp;
-
-	return_status = FAILED;
-	if (cmd == NULL) {
-		printk(KERN_INFO
-		    "%s(): **** SCSI mid-layer passing in NULL cmd\n",
-		    __func__);
-
-		return (return_status);
-	}
-
-	b = cmd->device->channel;
-	t = cmd->device->id;
-	l = cmd->device->lun;
-	ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-
-	tq = TGT_Q(ha, t);
-	if (tq == NULL) {
-		qla_printk(KERN_INFO, ha,
-		    "%s(): **** CMD derives a NULL TGT_Q\n", __func__);
+	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
+	srb_t *sp;
+	int ret;
+	unsigned int id, lun;
+	unsigned long serial;
 
-		return (return_status);
-	}
-	lq = (os_lun_t *)LUN_Q(ha, t, l);
-	if (lq == NULL) {
-		printk(KERN_INFO
-		    "%s(): **** CMD derives a NULL LUN_Q\n", __func__);
+	ret = FAILED;
 
-		return (return_status);
-	}
-	fcport_to_reset = lq->fclun->fcport;
+	id = cmd->device->id;
+	lun = cmd->device->lun;
+	serial = cmd->serial_number;
 
-	/* If we are coming in from the back-door, stall I/O until complete. */
-	if (!cmd->device->host->eh_active)
-		set_bit(TQF_SUSPENDED, &tq->flags);
+	sp = (srb_t *) CMD_SP(cmd);
+	if (!sp || !fcport)
+		return ret;
 
 	qla_printk(KERN_INFO, ha,
-	    "scsi(%ld:%d:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, b, t, l);
-
-	DEBUG2(printk(KERN_INFO
-	    "scsi(%ld): DEVICE_RESET cmd=%p jiffies = 0x%lx, timeout=%x, "
-	    "dpc_flags=%lx, status=%x allowed=%d cmd.state=%x\n",
-	    ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
-	    ha->dpc_flags, cmd->result, cmd->allowed, cmd->state));
-
- 	/* Clear commands from the retry queue. */
- 	spin_lock(&ha->list_lock);
- 	list_for_each_safe(list, temp, &ha->retry_queue) {
- 		rp = list_entry(list, srb_t, list);
- 
- 		if (t != rp->cmd->device->id) 
- 			continue;
- 
- 		DEBUG2(printk(KERN_INFO
-		    "qla2xxx_eh_reset: found in retry queue. SP=%p\n", rp));
- 
- 		__del_from_retry_queue(ha, rp);
- 		rp->cmd->result = DID_RESET << 16;
- 		__add_to_done_queue(ha, rp);
- 	}
- 	spin_unlock(&ha->list_lock);
+	    "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun);
 
 	spin_unlock_irq(ha->host->host_lock);
 
 	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
-		DEBUG2(printk(KERN_INFO
-		    "%s failed:board disabled\n",__func__));
-
 		spin_lock_irq(ha->host->host_lock);
 		goto eh_dev_reset_done;
 	}
 
 	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
-		if (qla2x00_device_reset(ha, fcport_to_reset) == 0) {
-			return_status = SUCCESS;
-		}
+		if (qla2x00_device_reset(ha, fcport) == 0)
+			ret = SUCCESS;
 
 #if defined(LOGOUT_AFTER_DEVICE_RESET)
-		if (return_status == SUCCESS) {
-			if (fcport_to_reset->flags & FC_FABRIC_DEVICE) {
-				qla2x00_fabric_logout(ha,
-				    fcport_to_reset->loop_id);
-				qla2x00_mark_device_lost(ha, fcport_to_reset);
+		if (ret == SUCCESS) {
+			if (fcport->flags & FC_FABRIC_DEVICE) {
+				qla2x00_fabric_logout(ha, fcport->loop_id);
+				qla2x00_mark_device_lost(ha, fcport);
 			}
 		}
 #endif
@@ -1442,9 +682,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd
 		    "%s failed: loop not ready\n",__func__);)
 	}
 
-	spin_lock_irq(ha->host->host_lock);
-
-	if (return_status == FAILED) {
+	if (ret == FAILED) {
 		DEBUG3(printk("%s(%ld): device reset failed\n",
 		    __func__, ha->host_no));
 		qla_printk(KERN_INFO, ha, "%s: device reset failed\n",
@@ -1458,10 +696,10 @@ qla2xxx_eh_device_reset(struct scsi_cmnd
 	 * complete for the device.
 	 */
 	if (cmd->device->host->eh_active) {
-		if (qla2x00_eh_wait_for_pending_target_commands(ha, t))
-			return_status = FAILED;
+		if (qla2x00_eh_wait_for_pending_target_commands(ha, id))
+			ret = FAILED;
 
-		if (return_status == FAILED) {
+		if (ret == FAILED) {
 			DEBUG3(printk("%s(%ld): failed while waiting for "
 			    "commands\n", __func__, ha->host_no));
 			qla_printk(KERN_INFO, ha,
@@ -1473,15 +711,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd
 	}
 
 	qla_printk(KERN_INFO, ha,
-	    "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
-	    ha->host_no, b, t, l);
+	    "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, id, lun);
 
 eh_dev_reset_done:
+	spin_lock_irq(ha->host->host_lock);
 
-	if (!cmd->device->host->eh_active)
-		clear_bit(TQF_SUSPENDED, &tq->flags);
-
-	return (return_status);
+	return ret;
 }
 
 /**************************************************************************
@@ -1506,6 +741,7 @@ qla2x00_eh_wait_for_pending_commands(scs
 	int	status;
 	srb_t		*sp;
 	struct scsi_cmnd *cmd;
+	unsigned long flags;
 
 	status = 1;
 
@@ -1514,17 +750,17 @@ qla2x00_eh_wait_for_pending_commands(scs
 	 * array
 	 */
 	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-		spin_lock(&ha->hardware_lock);
+		spin_lock_irqsave(&ha->hardware_lock, flags);
 		sp = ha->outstanding_cmds[cnt];
 		if (sp) {
 			cmd = sp->cmd;
-			spin_unlock(&ha->hardware_lock);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 			status = qla2x00_eh_wait_on_command(ha, cmd);
 			if (status == 0)
 				break;
 		}
 		else {
-			spin_unlock(&ha->hardware_lock);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		}
 	}
 	return (status);
@@ -1549,44 +785,52 @@ qla2x00_eh_wait_for_pending_commands(scs
 int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
-	scsi_qla_host_t *ha;
+	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
 	srb_t *sp;
-	int rval = FAILED;
+	int ret;
+	unsigned int id, lun;
+	unsigned long serial;
+
+	ret = FAILED;
+
+	id = cmd->device->id;
+	lun = cmd->device->lun;
+	serial = cmd->serial_number;
 
-	ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
 	sp = (srb_t *) CMD_SP(cmd);
+	if (!sp || !fcport)
+		return ret;
 
 	qla_printk(KERN_INFO, ha,
-	    "scsi(%ld:%d:%d:%d): LOOP RESET ISSUED.\n", ha->host_no,
-	    cmd->device->channel, cmd->device->id, cmd->device->lun);
+	    "scsi(%ld:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, id, lun);
 
 	spin_unlock_irq(ha->host->host_lock);
 
 	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
 		DEBUG2(printk("%s failed:board disabled\n",__func__));
-		spin_lock_irq(ha->host->host_lock);
-		return FAILED;
+		goto eh_bus_reset_done;
 	}
 
 	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
-		if (qla2x00_loop_reset(ha) == QLA_SUCCESS) 
-			rval = SUCCESS;
+		if (qla2x00_loop_reset(ha) == QLA_SUCCESS)
+			ret = SUCCESS;
 	}
-
-	spin_lock_irq(ha->host->host_lock);
-	if (rval == FAILED)
-		goto out;
+	if (ret == FAILED)
+		goto eh_bus_reset_done;
 
 	/* Waiting for our command in done_queue to be returned to OS.*/
 	if (cmd->device->host->eh_active)
 		if (!qla2x00_eh_wait_for_pending_commands(ha))
-			rval = FAILED;
+			ret = FAILED;
 
- out:
+eh_bus_reset_done:
 	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
-			(rval == FAILED) ? "failed" : "succeded");
+	    (ret == FAILED) ? "failed" : "succeded");
+
+	spin_lock_irq(ha->host->host_lock);
 
-	return rval;
+	return ret;
 }
 
 /**************************************************************************
@@ -1607,24 +851,30 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *c
 int
 qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
-	scsi_qla_host_t *ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-	int		rval = SUCCESS;
+	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
+	srb_t *sp;
+	int ret;
+	unsigned int id, lun;
+	unsigned long serial;
 
-	/* Display which one we're actually resetting for debug. */
-	DEBUG(printk("qla2xxx_eh_host_reset:Resetting scsi(%ld).\n",
-	    ha->host_no));
+	ret = FAILED;
+
+	id = cmd->device->id;
+	lun = cmd->device->lun;
+	serial = cmd->serial_number;
+
+	sp = (srb_t *) CMD_SP(cmd);
+	if (!sp || !fcport)
+		return ret;
 
-	/*
-	 *  Now issue reset.
-	 */
 	qla_printk(KERN_INFO, ha,
-	    "scsi(%ld:%d:%d:%d): ADAPTER RESET issued.\n", ha->host_no,
-	    cmd->device->channel, cmd->device->id, cmd->device->lun);
+	    "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, id, lun);
 
 	spin_unlock_irq(ha->host->host_lock);
 
 	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
-		goto board_disabled;
+		goto eh_host_reset_lock;
 
 	/*
 	 * Fixme-may be dpc thread is active and processing
@@ -1634,7 +884,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *
 	 * devices as lost kicking of the port_down_timer
 	 * while dpc is stuck for the mailbox to complete.
 	 */
-	/* Blocking call-Does context switching if loop is Not Ready */
 	qla2x00_wait_for_loop_ready(ha);
 	set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
 	if (qla2x00_abort_isp(ha)) {
@@ -1643,32 +892,22 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *
 		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 
 		if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
-			goto board_disabled;
+			goto eh_host_reset_lock;
 	} 
-
 	clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
 
-	spin_lock_irq(ha->host->host_lock);
-	if (rval == FAILED)
-		goto out;
-
 	/* Waiting for our command in done_queue to be returned to OS.*/
-	if (!qla2x00_eh_wait_for_pending_commands(ha))
-		rval = FAILED;
-
- out:
-	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
-			(rval == FAILED) ? "failed" : "succeded");
+	if (qla2x00_eh_wait_for_pending_commands(ha))
+		ret = SUCCESS;
 
-	return rval;
-
- board_disabled:
+eh_host_reset_lock:
 	spin_lock_irq(ha->host->host_lock);
 
-	qla_printk(KERN_INFO, ha, "%s: failed:board disabled\n", __func__);
-	return FAILED;
-}
+	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
+	    (ret == FAILED) ? "failed" : "succeded");
 
+	return ret;
+}
 
 /*
 * qla2x00_loop_reset
@@ -1684,25 +923,20 @@ static int
 qla2x00_loop_reset(scsi_qla_host_t *ha)
 {
 	int status = QLA_SUCCESS;
-	uint16_t t;
-	os_tgt_t        *tq;
+	struct fc_port *fcport;
 
 	if (ha->flags.enable_lip_reset) {
 		status = qla2x00_lip_reset(ha);
 	}
 
 	if (status == QLA_SUCCESS && ha->flags.enable_target_reset) {
-		for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
-			if ((tq = TGT_Q(ha, t)) == NULL)
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (fcport->port_type != FCT_TARGET)
 				continue;
 
-			if (tq->fcport == NULL)
-				continue;
-
-			status = qla2x00_target_reset(ha, 0, t);
-			if (status != QLA_SUCCESS) {
+			status = qla2x00_target_reset(ha, fcport);
+			if (status != QLA_SUCCESS)
 				break;
-			}
 		}
 	}
 
@@ -1752,41 +986,53 @@ qla2x00_device_reset(scsi_qla_host_t *ha
 	return qla2x00_abort_target(reset_fcport);
 }
 
-/**************************************************************************
-* qla2xxx_slave_configure
-*
-* Description:
-**************************************************************************/
-int
-qla2xxx_slave_configure(struct scsi_device *sdev)
+static int
+qla2xxx_slave_alloc(struct scsi_device *sdev)
 {
 	scsi_qla_host_t *ha = to_qla_host(sdev->host);
-	int queue_depth;
+	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+	fc_port_t *fcport;
+	int found;
 
-	if (IS_QLA2100(ha) || IS_QLA2200(ha))
-		queue_depth = 16;
-	else
-		queue_depth = 32;
+	if (!rport)
+		return -ENXIO;
 
-	if (sdev->tagged_supported) {
-		if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
-			queue_depth = ql2xmaxqdepth;
+	found = 0;
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (rport->port_name ==
+		    be64_to_cpu(*(uint64_t *)fcport->port_name)) {
+			found++;
+			break;
+		}
+	}
+	if (!found)
+		return -ENXIO;
 
-		ql2xmaxqdepth = queue_depth;
+	sdev->hostdata = fcport;
 
-		scsi_activate_tcq(sdev, queue_depth);
+	return 0;
+}
 
-		qla_printk(KERN_INFO, ha,
-		    "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue "
-		    "depth %d.\n",
-		    sdev->host->host_no, sdev->channel, sdev->id, sdev->lun,
-		    sdev->queue_depth);
-	} else {
-		 scsi_adjust_queue_depth(sdev, 0 /* TCQ off */,
-		     sdev->host->hostt->cmd_per_lun /* 3 */);
-	}
+static int
+qla2xxx_slave_configure(struct scsi_device *sdev)
+{
+	scsi_qla_host_t *ha = to_qla_host(sdev->host);
+	struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
 
-	return (0);
+	if (sdev->tagged_supported)
+		scsi_activate_tcq(sdev, 32);
+	else
+		scsi_deactivate_tcq(sdev, 32);
+
+	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+
+	return 0;
+}
+
+static void
+qla2xxx_slave_destroy(struct scsi_device *sdev)
+{
+	sdev->hostdata = NULL;
 }
 
 /**
@@ -1847,13 +1093,13 @@ qla2x00_iospace_config(scsi_qla_host_t *
 		if (pio_len < MIN_IOBASE_LEN) {
 			qla_printk(KERN_WARNING, ha,
 			    "Invalid PCI I/O region size (%s)...\n",
-			    ha->pdev->slot_name);
+				pci_name(ha->pdev));
 			pio = 0;
 		}
 	} else {
 		qla_printk(KERN_WARNING, ha,
 		    "region #0 not a PIO resource (%s)...\n",
-		    ha->pdev->slot_name);
+		    pci_name(ha->pdev));
 		pio = 0;
 	}
 
@@ -1865,20 +1111,20 @@ qla2x00_iospace_config(scsi_qla_host_t *
 	if (!(mmio_flags & IORESOURCE_MEM)) {
 		qla_printk(KERN_ERR, ha,
 		    "region #0 not an MMIO resource (%s), aborting\n",
-		    ha->pdev->slot_name);
+		    pci_name(ha->pdev));
 		goto iospace_error_exit;
 	}
 	if (mmio_len < MIN_IOBASE_LEN) {
 		qla_printk(KERN_ERR, ha,
 		    "Invalid PCI mem region size (%s), aborting\n",
-		    ha->pdev->slot_name);
+			pci_name(ha->pdev));
 		goto iospace_error_exit;
 	}
 
 	if (pci_request_regions(ha->pdev, ha->brd_info->drv_name)) {
 		qla_printk(KERN_WARNING, ha,
-		    "Failed to reserve PIO/MMIO regions (%s)\n", 
-		    ha->pdev->slot_name);
+		    "Failed to reserve PIO/MMIO regions (%s)\n",
+		    pci_name(ha->pdev));
 
 		goto iospace_error_exit;
 	}
@@ -1888,7 +1134,7 @@ qla2x00_iospace_config(scsi_qla_host_t *
 	ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
 	if (!ha->iobase) {
 		qla_printk(KERN_ERR, ha,
-		    "cannot remap MMIO (%s), aborting\n", ha->pdev->slot_name);
+		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
 
 		goto iospace_error_exit;
 	}
@@ -1912,6 +1158,7 @@ int qla2x00_probe_one(struct pci_dev *pd
 	unsigned long	wait_switch = 0;
 	char pci_info[20];
 	char fw_str[30];
+	fc_port_t *fcport;
 
 	if (pci_enable_device(pdev))
 		return -1;
@@ -1937,7 +1184,7 @@ int qla2x00_probe_one(struct pci_dev *pd
 	/* Configure PCI I/O space */
 	ret = qla2x00_iospace_config(ha);
 	if (ret != 0) {
-		goto probe_failed;
+		goto probe_alloc_failed;
 	}
 
 	/* Sanitize the information from PCI BIOS. */
@@ -1993,10 +1240,6 @@ int qla2x00_probe_one(struct pci_dev *pd
 	INIT_LIST_HEAD(&ha->list);
 	INIT_LIST_HEAD(&ha->fcports);
 	INIT_LIST_HEAD(&ha->rscn_fcports);
-	INIT_LIST_HEAD(&ha->done_queue);
-	INIT_LIST_HEAD(&ha->retry_queue);
-	INIT_LIST_HEAD(&ha->scsi_retry_queue);
-	INIT_LIST_HEAD(&ha->pending_queue);
 
 	/*
 	 * These locks are used to prevent more than one CPU
@@ -2005,7 +1248,6 @@ int qla2x00_probe_one(struct pci_dev *pd
 	 * contention for these locks.
 	 */
 	spin_lock_init(&ha->mbx_reg_lock);
-	spin_lock_init(&ha->list_lock);
 
 	ha->dpc_pid = -1;
 	init_completion(&ha->dpc_inited);
@@ -2016,9 +1258,23 @@ int qla2x00_probe_one(struct pci_dev *pd
 		qla_printk(KERN_WARNING, ha,
 		    "[ERROR] Failed to allocate memory for adapter\n");
 
-		goto probe_failed;
+		goto probe_alloc_failed;
 	}
 
+	pci_set_drvdata(pdev, ha);
+	host->this_id = 255;
+	host->cmd_per_lun = 3;
+	host->unique_id = ha->instance;
+	host->max_cmd_len = MAX_CMDSZ;
+	host->max_channel = ha->ports - 1;
+	host->max_id = ha->max_targets;
+	host->max_lun = ha->max_luns;
+	host->transportt = qla2xxx_transport_template;
+	if (scsi_add_host(host, &pdev->dev))
+		goto probe_alloc_failed;
+
+	qla2x00_alloc_sysfs_attr(ha);
+
 	if (qla2x00_initialize_adapter(ha) &&
 	    !(ha->device_flags & DFLG_NO_CABLE)) {
 
@@ -2032,6 +1288,8 @@ int qla2x00_probe_one(struct pci_dev *pd
 		goto probe_failed;
 	}
 
+	qla2x00_init_host_attr(ha);
+
 	/*
 	 * Startup the kernel thread for this host adapter
 	 */
@@ -2045,16 +1303,6 @@ int qla2x00_probe_one(struct pci_dev *pd
 	}
 	wait_for_completion(&ha->dpc_inited);
 
-	host->this_id = 255;
-	host->cmd_per_lun = 3;
-	host->max_cmd_len = MAX_CMDSZ;
-	host->max_channel = ha->ports - 1;
-	host->max_lun = ha->max_luns;
-	BUG_ON(qla2xxx_transport_template == NULL);
-	host->transportt = qla2xxx_transport_template;
-	host->unique_id = ha->instance;
-	host->max_id = ha->max_targets;
-
 	if (IS_QLA2100(ha) || IS_QLA2200(ha))
 		ret = request_irq(host->irq, qla2100_intr_handler,
 		    SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha);
@@ -2115,21 +1363,9 @@ int qla2x00_probe_one(struct pci_dev *pd
 		msleep(10);
 	}
 
-	pci_set_drvdata(pdev, ha);
 	ha->flags.init_done = 1;
 	num_hosts++;
 
-	/* List the target we have found */
-	if (displayConfig) {
-		qla2x00_display_fc_names(ha);
-	}
-
-	if (scsi_add_host(host, &pdev->dev))
-		goto probe_failed;
-
-	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
-	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
-
 	qla_printk(KERN_INFO, ha, "\n"
 	    " QLogic Fibre Channel HBA Driver: %s\n"
 	    "  QLogic %s - %s\n"
@@ -2139,12 +1375,18 @@ int qla2x00_probe_one(struct pci_dev *pd
 	    pci_name(ha->pdev), ha->flags.enable_64bit_addressing ? '+': '-',
 	    ha->host_no, qla2x00_get_fw_version_str(ha, fw_str));
 
-	if (ql2xdoinitscan)
-		scsi_scan_host(host);
+	/* Go with fc_rport registration. */
+	list_for_each_entry(fcport, &ha->fcports, list)
+		qla2x00_reg_remote_port(ha, fcport);
 
 	return 0;
 
 probe_failed:
+	fc_remove_host(ha->host);
+
+	scsi_remove_host(host);
+
+probe_alloc_failed:
 	qla2x00_free_device(ha);
 
 	scsi_host_put(host);
@@ -2162,9 +1404,9 @@ void qla2x00_remove_one(struct pci_dev *
 
 	ha = pci_get_drvdata(pdev);
 
-	sysfs_remove_bin_file(&ha->host->shost_gendev.kobj,
-	    &sysfs_fw_dump_attr);
-	sysfs_remove_bin_file(&ha->host->shost_gendev.kobj, &sysfs_nvram_attr);
+	qla2x00_free_sysfs_attr(ha);
+
+	fc_remove_host(ha->host);
 
 	scsi_remove_host(ha->host);
 
@@ -2225,590 +1467,99 @@ qla2x00_free_device(scsi_qla_host_t *ha)
 	pci_disable_device(ha->pdev);
 }
 
-
 /*
- * The following support functions are adopted to handle
- * the re-entrant qla2x00_proc_info correctly.
+ * qla2x00_mark_device_lost Updates fcport state when device goes offline.
+ *
+ * Input: ha = adapter block pointer.  fcport = port structure pointer.
+ *
+ * Return: None.
+ *
+ * Context:
  */
-static void
-copy_mem_info(struct info_str *info, char *data, int len)
+void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
+    int do_login)
 {
-	if (info->pos + len > info->offset + info->length)
-		len = info->offset + info->length - info->pos;
+	if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport)
+		fc_remote_port_block(fcport->rport);
+	/* 
+	 * We may need to retry the login, so don't change the state of the
+	 * port but do the retries.
+	 */
+	if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD)
+		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 
-	if (info->pos + len < info->offset) {
-		info->pos += len;
+	if (!do_login)
 		return;
-	}
- 
-	if (info->pos < info->offset) {
-		off_t partial;
- 
-		partial = info->offset - info->pos;
-		data += partial;
-		info->pos += partial;
-		len  -= partial;
-	}
- 
-	if (len > 0) {
-		memcpy(info->buffer, data, len);
-		info->pos += len;
-		info->buffer += len;
+
+	if (fcport->login_retry == 0) {
+		fcport->login_retry = ha->login_retry_count;
+		set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
+
+		DEBUG(printk("scsi(%ld): Port login retry: "
+		    "%02x%02x%02x%02x%02x%02x%02x%02x, "
+		    "id = 0x%04x retry cnt=%d\n",
+		    ha->host_no,
+		    fcport->port_name[0],
+		    fcport->port_name[1],
+		    fcport->port_name[2],
+		    fcport->port_name[3],
+		    fcport->port_name[4],
+		    fcport->port_name[5],
+		    fcport->port_name[6],
+		    fcport->port_name[7],
+		    fcport->loop_id,
+		    fcport->login_retry));
 	}
 }
 
-static int
-copy_info(struct info_str *info, char *fmt, ...)
+/*
+ * qla2x00_mark_all_devices_lost
+ *	Updates fcport state when device goes offline.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fcport = port structure pointer.
+ *
+ * Return:
+ *	None.
+ *
+ * Context:
+ */
+void
+qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) 
 {
-	va_list args;
-	char buf[256];
-	int len;
- 
-	va_start(args, fmt);
-	len = vsprintf(buf, fmt, args);
-	va_end(args);
- 
-	copy_mem_info(info, buf, len);
+	fc_port_t *fcport;
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (fcport->port_type != FCT_TARGET)
+			continue;
 
-	return (len);
+		/*
+		 * No point in marking the device as lost, if the device is
+		 * already DEAD.
+		 */
+		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
+			continue;
+		if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport)
+			fc_remote_port_block(fcport->rport);
+		atomic_set(&fcport->state, FCS_DEVICE_LOST);
+	}
 }
 
-/*************************************************************************
-* qla2x00_proc_info
-*
-* Description:
-*   Return information to handle /proc support for the driver.
+/*
+* qla2x00_mem_alloc
+*      Allocates adapter memory.
 *
-* inout : decides the direction of the dataflow and the meaning of the
-*         variables
-* buffer: If inout==0 data is being written to it else read from it
-*         (ptr to a page buffer)
-* *start: If inout==0 start of the valid data in the buffer
-* offset: If inout==0 starting offset from the beginning of all
-*         possible data to return.
-* length: If inout==0 max number of bytes to be written into the buffer
-*         else number of bytes in "buffer"
 * Returns:
-*         < 0:  error. errno value.
-*         >= 0: sizeof data returned.
-*************************************************************************/
-int
-qla2x00_proc_info(struct Scsi_Host *shost, char *buffer,
-    char **start, off_t offset, int length, int inout)
+*      0  = success.
+*      1  = failure.
+*/
+static uint8_t
+qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
-	struct info_str	info;
-	int             retval = -EINVAL;
-	os_lun_t	*up;
-	os_tgt_t	*tq;
-	unsigned int	t, l;
-	uint32_t        tmp_sn;
-	uint32_t	*flags;
-	uint8_t		*loop_state;
-	scsi_qla_host_t *ha;
-	char fw_info[30];
- 
-	DEBUG3(printk(KERN_INFO
-	    "Entering proc_info buff_in=%p, offset=0x%lx, length=0x%x\n",
-	    buffer, offset, length);)
-
-	ha = (scsi_qla_host_t *) shost->hostdata;
-
-	if (inout) {
-		/* Has data been written to the file? */
-		DEBUG3(printk(
-		    "%s: has data been written to the file. \n",
-		    __func__);)
-
-		return -ENOSYS;
-	}
-
-	if (start) {
-		*start = buffer;
-	}
-
-	info.buffer = buffer;
-	info.length = length;
-	info.offset = offset;
-	info.pos    = 0;
-
-	/* start building the print buffer */
-	copy_info(&info,
-	    "QLogic PCI to Fibre Channel Host Adapter for %s:\n"
-	    "        Firmware version %s, ",
-	    ha->model_number, qla2x00_get_fw_version_str(ha, fw_info));
-
-	copy_info(&info, "Driver version %s\n", qla2x00_version_str);
-
-	tmp_sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | 
-	    ha->serial1;
-	copy_info(&info, "ISP: %s, Serial# %c%05d\n",
-	    ha->brd_info->isp_name, ('A' + tmp_sn/100000), (tmp_sn%100000));
-
-	copy_info(&info,
-	    "Request Queue = 0x%llx, Response Queue = 0x%llx\n",
-		(unsigned long long)ha->request_dma,
-		(unsigned long long)ha->response_dma);
-
-	copy_info(&info,
-	    "Request Queue count = %d, Response Queue count = %d\n",
-	    ha->request_q_length, ha->response_q_length);
-
-	copy_info(&info,
-	    "Total number of active commands = %ld\n",
-	    ha->actthreads);
-
-	copy_info(&info,
-	    "Total number of interrupts = %ld\n",
-	    (long)ha->total_isr_cnt);
-
-	copy_info(&info,
-	    "    Device queue depth = 0x%x\n",
-	    (ql2xmaxqdepth == 0) ? 16 : ql2xmaxqdepth);
-
-	copy_info(&info,
-	    "Number of free request entries = %d\n", ha->req_q_cnt);
-
-	copy_info(&info,
-	    "Number of mailbox timeouts = %ld\n", ha->total_mbx_timeout);
-
-	copy_info(&info,
-	    "Number of ISP aborts = %ld\n", ha->total_isp_aborts);
-
-	copy_info(&info,
-	    "Number of loop resyncs = %ld\n", ha->total_loop_resync);
-
-	copy_info(&info,
-	    "Number of retries for empty slots = %ld\n",
-	    qla2x00_stats.outarray_full);
-
-	copy_info(&info,
-	    "Number of reqs in pending_q= %ld, retry_q= %d, "
-	    "done_q= %ld, scsi_retry_q= %d\n",
-	    ha->qthreads, ha->retry_q_cnt,
-	    ha->done_q_cnt, ha->scsi_retry_q_cnt);
-
-
-	flags = (uint32_t *) &ha->flags;
-
-	if (atomic_read(&ha->loop_state) == LOOP_DOWN) {
-		loop_state = "DOWN";
-	} else if (atomic_read(&ha->loop_state) == LOOP_UP) {
-		loop_state = "UP";
-	} else if (atomic_read(&ha->loop_state) == LOOP_READY) {
-		loop_state = "READY";
-	} else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT) {
-		loop_state = "TIMEOUT";
-	} else if (atomic_read(&ha->loop_state) == LOOP_UPDATE) {
-		loop_state = "UPDATE";
-	} else {
-		loop_state = "UNKNOWN";
-	}
-
-	copy_info(&info, 
-	    "Host adapter:loop state = <%s>, flags = 0x%lx\n",
-	    loop_state , *flags);
-
-	copy_info(&info, "Dpc flags = 0x%lx\n", ha->dpc_flags);
-
-	copy_info(&info, "MBX flags = 0x%x\n", ha->mbx_flags);
-
-	copy_info(&info, "Link down Timeout = %3.3d\n",
-	    ha->link_down_timeout);
-
-	copy_info(&info, "Port down retry = %3.3d\n",
-	    ha->port_down_retry_count);
-
-	copy_info(&info, "Login retry count = %3.3d\n",
-	    ha->login_retry_count);
-
-	copy_info(&info,
-	    "Commands retried with dropped frame(s) = %d\n",
-	    ha->dropped_frame_error_cnt);
-
-	copy_info(&info,
-	    "Product ID = %04x %04x %04x %04x\n", ha->product_id[0],
-	    ha->product_id[1], ha->product_id[2], ha->product_id[3]);
-
-	copy_info(&info, "\n");
-
-	/* 2.25 node/port display to proc */
-	/* Display the node name for adapter */
-	copy_info(&info, "\nSCSI Device Information:\n");
-	copy_info(&info,
-	    "scsi-qla%d-adapter-node="
-	    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
-	    (int)ha->instance,
-	    ha->init_cb->node_name[0],
-	    ha->init_cb->node_name[1],
-	    ha->init_cb->node_name[2],
-	    ha->init_cb->node_name[3],
-	    ha->init_cb->node_name[4],
-	    ha->init_cb->node_name[5],
-	    ha->init_cb->node_name[6],
-	    ha->init_cb->node_name[7]);
-
-	/* display the port name for adapter */
-	copy_info(&info,
-	    "scsi-qla%d-adapter-port="
-	    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
-	    (int)ha->instance,
-	    ha->init_cb->port_name[0],
-	    ha->init_cb->port_name[1],
-	    ha->init_cb->port_name[2],
-	    ha->init_cb->port_name[3],
-	    ha->init_cb->port_name[4],
-	    ha->init_cb->port_name[5],
-	    ha->init_cb->port_name[6],
-	    ha->init_cb->port_name[7]);
-
-	/* Print out device port names */
-	for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
-		if ((tq = TGT_Q(ha, t)) == NULL)
-			continue;
-
-		copy_info(&info,
-		    "scsi-qla%d-target-%d="
-		    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
-		    (int)ha->instance, t,
-		    tq->port_name[0], tq->port_name[1],
-		    tq->port_name[2], tq->port_name[3],
-		    tq->port_name[4], tq->port_name[5],
-		    tq->port_name[6], tq->port_name[7]);
-	}
-
-	copy_info(&info, "\nSCSI LUN Information:\n");
-	copy_info(&info,
-	    "(Id:Lun)  * - indicates lun is not registered with the OS.\n");
-
-	/* scan for all equipment stats */
-	for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
-		/* scan all luns */
-		for (l = 0; l < ha->max_luns; l++) {
-			up = (os_lun_t *) GET_LU_Q(ha, t, l);
-
-			if (up == NULL) {
-				continue;
-			}
-			if (up->fclun == NULL) {
-				continue;
-			}
-
-			copy_info(&info,
-			    "(%2d:%2d): Total reqs %ld,",
-			    t,l,up->io_cnt);
-
-			copy_info(&info,
-			    " Pending reqs %ld,",
-			    up->out_cnt);
-
-			if (up->io_cnt < 4) {
-				copy_info(&info,
-				    " flags 0x%x*,",
-				    (int)up->q_flag);
-			} else {
-				copy_info(&info,
-				    " flags 0x%x,",
-				    (int)up->q_flag);
-			}
-
-			copy_info(&info, 
-			    " %ld:%d:%02x %02x",
-			    up->fclun->fcport->ha->instance,
-			    up->fclun->fcport->cur_path,
-			    up->fclun->fcport->loop_id,
-			    up->fclun->device_type);
-
-			copy_info(&info, "\n");
-
-			if (info.pos >= info.offset + info.length) {
-				/* No need to continue */
-				goto profile_stop;
-			}
-		}
-
-		if (info.pos >= info.offset + info.length) {
-			/* No need to continue */
-			break;
-		}
-	}
-
-profile_stop:
-
-	retval = info.pos > info.offset ? info.pos - info.offset : 0;
-
-	DEBUG3(printk(KERN_INFO 
-	    "Exiting proc_info: info.pos=%d, offset=0x%lx, "
-	    "length=0x%x\n", info.pos, offset, length);)
-
-	return (retval);
-}
-
-/*
-* qla2x00_display_fc_names
-*      This routine will the node names of the different devices found
-*      after port inquiry.
-*
-* Input:
-*      cmd = SCSI command structure
-*
-* Returns:
-*      None.
-*/
-static void
-qla2x00_display_fc_names(scsi_qla_host_t *ha) 
-{
-	uint16_t	tgt;
-	os_tgt_t	*tq;
-
-	/* Display the node name for adapter */
-	qla_printk(KERN_INFO, ha,
-	    "scsi-qla%d-adapter-node=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
-	    (int)ha->instance,
-	    ha->init_cb->node_name[0],
-	    ha->init_cb->node_name[1],
-	    ha->init_cb->node_name[2],
-	    ha->init_cb->node_name[3],
-	    ha->init_cb->node_name[4],
-	    ha->init_cb->node_name[5],
-	    ha->init_cb->node_name[6],
-	    ha->init_cb->node_name[7]);
-
-	/* display the port name for adapter */
-	qla_printk(KERN_INFO, ha,
-	    "scsi-qla%d-adapter-port=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
-	    (int)ha->instance,
-	    ha->init_cb->port_name[0],
-	    ha->init_cb->port_name[1],
-	    ha->init_cb->port_name[2],
-	    ha->init_cb->port_name[3],
-	    ha->init_cb->port_name[4],
-	    ha->init_cb->port_name[5],
-	    ha->init_cb->port_name[6],
-	    ha->init_cb->port_name[7]);
-
-	/* Print out device port names */
-	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
-		if ((tq = ha->otgt[tgt]) == NULL)
-			continue;
-
-		if (tq->fcport == NULL)
-			continue;
-
-		switch (ha->binding_type) {
-			case BIND_BY_PORT_NAME:
-				qla_printk(KERN_INFO, ha,
-				    "scsi-qla%d-tgt-%d-di-0-port="
-				    "%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
-				    (int)ha->instance, 
-				    tgt,
-				    tq->port_name[0], 
-				    tq->port_name[1],
-				    tq->port_name[2], 
-				    tq->port_name[3],
-				    tq->port_name[4], 
-				    tq->port_name[5],
-				    tq->port_name[6], 
-				    tq->port_name[7]);
-
-				break;
-
-			case BIND_BY_PORT_ID:
-				qla_printk(KERN_INFO, ha,
-				    "scsi-qla%d-tgt-%d-di-0-pid="
-				    "%02x%02x%02x\\;\n",
-				    (int)ha->instance,
-				    tgt,
-				    tq->d_id.b.domain,
-				    tq->d_id.b.area,
-				    tq->d_id.b.al_pa);
-				break;
-		}
-
-#if VSA
-		qla_printk(KERN_INFO, ha,
-		    "scsi-qla%d-target-%d-vsa=01;\n", (int)ha->instance, tgt);
-#endif
-	}
-}
-
-/*
- *  qla2x00_suspend_lun
- *	Suspend lun and start port down timer
- *
- * Input:
- *	ha = visable adapter block pointer.
- *  lq = lun queue
- *  cp = Scsi command pointer 
- *  time = time in seconds
- *  count = number of times to let time expire
- *  delay_lun = non-zero, if lun should be delayed rather than suspended
- *
- * Return:
- *     QLA_SUCCESS  -- suspended lun 
- *     QLA_FUNCTION_FAILED  -- Didn't suspend lun
- *
- * Context:
- *	Interrupt context.
- */
-int
-__qla2x00_suspend_lun(scsi_qla_host_t *ha,
-		os_lun_t *lq, int time, int count, int delay_lun)
-{
-	int	rval;
-	srb_t *sp;
-	struct list_head *list, *temp;
-	unsigned long flags;
-
-	rval = QLA_SUCCESS;
-
-	/* if the lun_q is already suspended then don't do it again */
-	if (lq->q_state == LUN_STATE_READY ||lq->q_state == LUN_STATE_RUN) {
-
-		spin_lock_irqsave(&lq->q_lock, flags);
-		if (lq->q_state == LUN_STATE_READY) {
-			lq->q_max = count;
-			lq->q_count = 0;
-		}
-		/* Set the suspend time usually 6 secs */
-		atomic_set(&lq->q_timer, time);
-
-		/* now suspend the lun */
-		lq->q_state = LUN_STATE_WAIT;
-
-		if (delay_lun) {
-			set_bit(LUN_EXEC_DELAYED, &lq->q_flag);
-			DEBUG(printk(KERN_INFO
-			    "scsi(%ld): Delay lun execution for %d secs, "
-			    "count=%d, max count=%d, state=%d\n",
-			    ha->host_no,
-			    time,
-			    lq->q_count, lq->q_max, lq->q_state));
-		} else {
-			DEBUG(printk(KERN_INFO
-			    "scsi(%ld): Suspend lun for %d secs, count=%d, "
-			    "max count=%d, state=%d\n",
-			    ha->host_no,
-			    time,
-			    lq->q_count, lq->q_max, lq->q_state));
-		}
-		spin_unlock_irqrestore(&lq->q_lock, flags);
-
-		/*
-		 * Remove all pending commands from request queue and  put them
-		 * in the scsi_retry queue.
-		 */
-		spin_lock_irqsave(&ha->list_lock, flags);
-		list_for_each_safe(list, temp, &ha->pending_queue) {
-			sp = list_entry(list, srb_t, list);
-			if (sp->lun_queue != lq)
-				continue;
-
-			__del_from_pending_queue(ha, sp);
-
-			if (sp->cmd->allowed < count)
-				sp->cmd->allowed = count;
-			__add_to_scsi_retry_queue(ha, sp);
-
-		} /* list_for_each_safe */
-		spin_unlock_irqrestore(&ha->list_lock, flags);
-		rval = QLA_SUCCESS;
-	} else {
-		rval = QLA_FUNCTION_FAILED;
-	}
-
-	return (rval);
-}
-
-/*
- * qla2x00_mark_device_lost Updates fcport state when device goes offline.
- *
- * Input: ha = adapter block pointer.  fcport = port structure pointer.
- *
- * Return: None.
- *
- * Context:
- */
-void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
-    int do_login)
-{
-	/* 
-	 * We may need to retry the login, so don't change the state of the
-	 * port but do the retries.
-	 */
-	if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD)
-		atomic_set(&fcport->state, FCS_DEVICE_LOST);
-
-	if (!do_login)
-		return;
-
-	if (fcport->login_retry == 0) {
-		fcport->login_retry = ha->login_retry_count;
-		set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
-
-		DEBUG(printk("scsi(%ld): Port login retry: "
-		    "%02x%02x%02x%02x%02x%02x%02x%02x, "
-		    "id = 0x%04x retry cnt=%d\n",
-		    ha->host_no,
-		    fcport->port_name[0],
-		    fcport->port_name[1],
-		    fcport->port_name[2],
-		    fcport->port_name[3],
-		    fcport->port_name[4],
-		    fcport->port_name[5],
-		    fcport->port_name[6],
-		    fcport->port_name[7],
-		    fcport->loop_id,
-		    fcport->login_retry));
-	}
-}
-
-/*
- * qla2x00_mark_all_devices_lost
- *	Updates fcport state when device goes offline.
- *
- * Input:
- *	ha = adapter block pointer.
- *	fcport = port structure pointer.
- *
- * Return:
- *	None.
- *
- * Context:
- */
-void
-qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) 
-{
-	fc_port_t *fcport;
-
-	list_for_each_entry(fcport, &ha->fcports, list) {
-		if (fcport->port_type != FCT_TARGET)
-			continue;
-
-		/*
-		 * No point in marking the device as lost, if the device is
-		 * already DEAD.
-		 */
-		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
-			continue;
-
-		atomic_set(&fcport->state, FCS_DEVICE_LOST);
-	}
-}
-
-/*
-* qla2x00_mem_alloc
-*      Allocates adapter memory.
-*
-* Returns:
-*      0  = success.
-*      1  = failure.
-*/
-static uint8_t
-qla2x00_mem_alloc(scsi_qla_host_t *ha)
-{
-	char	name[16];
-	uint8_t   status = 1;
-	int	retry= 10;
+	char	name[16];
+	uint8_t   status = 1;
+	int	retry= 10;
 
 	do {
 		/*
@@ -3007,11 +1758,8 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 static void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
-	uint32_t	t;
 	struct list_head	*fcpl, *fcptemp;
 	fc_port_t	*fcport;
-	struct list_head	*fcll, *fcltemp;
-	fc_lun_t	*fclun;
 	unsigned long	wtime;/* max wait time if mbx cmd is busy. */
 
 	if (ha == NULL) {
@@ -3020,11 +1768,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 		return;
 	}
 
-	/* Free the target queues */
-	for (t = 0; t < MAX_TARGETS; t++) {
-		qla2x00_tgt_free(ha, t);
-	}
-
 	/* Make sure all other threads are stopped. */
 	wtime = 60 * HZ;
 	while (ha->dpc_wait && wtime) {
@@ -3103,14 +1846,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	list_for_each_safe(fcpl, fcptemp, &ha->fcports) {
 		fcport = list_entry(fcpl, fc_port_t, list);
 
-		/* fc luns */
-		list_for_each_safe(fcll, fcltemp, &fcport->fcluns) {
-			fclun = list_entry(fcll, fc_lun_t, list);
-
-			list_del_init(&fclun->list);
-			kfree(fclun);
-		}
-
 		/* fc ports */
 		list_del_init(&fcport->list);
 		kfree(fcport);
@@ -3188,16 +1923,8 @@ qla2x00_do_dpc(void *data)
 	DECLARE_MUTEX_LOCKED(sem);
 	scsi_qla_host_t *ha;
 	fc_port_t	*fcport;
-	os_lun_t        *q;
-	srb_t           *sp;
 	uint8_t		status;
-	unsigned long	flags = 0;
-	struct list_head *list, *templist;
-	int	dead_cnt, online_cnt;
-	int	retry_cmds = 0;
 	uint16_t	next_loopid;
-	int t;
-	os_tgt_t *tq;
 
 	ha = (scsi_qla_host_t *)data;
 
@@ -3233,139 +1960,7 @@ qla2x00_do_dpc(void *data)
 
 		ha->dpc_active = 1;
 
-		if (!list_empty(&ha->done_queue))
-			qla2x00_done(ha);
-
-		/* Process commands in retry queue */
-		if (test_and_clear_bit(PORT_RESTART_NEEDED, &ha->dpc_flags)) {
-			DEBUG(printk("scsi(%ld): DPC checking retry_q. "
-			    "total=%d\n",
-			    ha->host_no, ha->retry_q_cnt));
-
-			spin_lock_irqsave(&ha->list_lock, flags);
-			dead_cnt = online_cnt = 0;
-			list_for_each_safe(list, templist, &ha->retry_queue) {
-				sp = list_entry(list, srb_t, list);
-				q = sp->lun_queue;
-				DEBUG3(printk("scsi(%ld): pid=%ld sp=%p, "
-				    "spflags=0x%x, q_flag= 0x%lx\n",
-				    ha->host_no, sp->cmd->serial_number, sp,
-				    sp->flags, q->q_flag));
-
-				if (q == NULL)
-					continue;
-				fcport = q->fclun->fcport;
-
-				if (atomic_read(&fcport->state) ==
-				    FCS_DEVICE_DEAD ||
-				    atomic_read(&fcport->ha->loop_state) == LOOP_DEAD) {
-
-					__del_from_retry_queue(ha, sp);
-					sp->cmd->result = DID_NO_CONNECT << 16;
-					if (atomic_read(&fcport->ha->loop_state) ==
-					    LOOP_DOWN) 
-						sp->err_id = SRB_ERR_LOOP;
-					else
-						sp->err_id = SRB_ERR_PORT;
-					sp->cmd->host_scribble =
-					    (unsigned char *) NULL;
-					__add_to_done_queue(ha, sp);
-					dead_cnt++;
-				} else if (atomic_read(&fcport->state) !=
-				    FCS_DEVICE_LOST) {
-
-					__del_from_retry_queue(ha, sp);
-					sp->cmd->result = DID_BUS_BUSY << 16;
-					sp->cmd->host_scribble =
-					    (unsigned char *) NULL;
-					__add_to_done_queue(ha, sp);
-					online_cnt++;
-				}
-			} /* list_for_each_safe() */
-			spin_unlock_irqrestore(&ha->list_lock, flags);
-
-			DEBUG(printk("scsi(%ld): done processing retry queue "
-			    "- dead=%d, online=%d\n ",
-			    ha->host_no, dead_cnt, online_cnt));
-		}
-
-		/* Process commands in scsi retry queue */
-		if (test_and_clear_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags)) {
-			/*
-			 * Any requests we want to delay for some period is put
-			 * in the scsi retry queue with a delay added. The
-			 * timer will schedule a "scsi_restart_needed" every 
-			 * second as long as there are requests in the scsi
-			 * queue. 
-			 */
-			DEBUG(printk("scsi(%ld): DPC checking scsi "
-			    "retry_q.total=%d\n",
-			    ha->host_no, ha->scsi_retry_q_cnt));
-
-			online_cnt = 0;
-			spin_lock_irqsave(&ha->list_lock, flags);
-			list_for_each_safe(list, templist,
-			    &ha->scsi_retry_queue) {
-
-				sp = list_entry(list, srb_t, list);
-				q = sp->lun_queue;
-				tq = sp->tgt_queue;
-
-				DEBUG3(printk("scsi(%ld): scsi_retry_q: "
-				    "pid=%ld sp=%p, spflags=0x%x, "
-				    "q_flag= 0x%lx,q_state=%d\n",
-				    ha->host_no, sp->cmd->serial_number,
-				    sp, sp->flags, q->q_flag, q->q_state));
-
-				/* Was this lun suspended */
-				if (q->q_state != LUN_STATE_WAIT) {
-					online_cnt++;
-					__del_from_scsi_retry_queue(ha, sp);
-
-					if (test_bit(TQF_RETRY_CMDS,
-					    &tq->flags)) {
-						qla2x00_extend_timeout(sp->cmd,
-						    (sp->cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA);
-						__add_to_pending_queue(ha, sp);
-						retry_cmds++;
-					} else
-						__add_to_retry_queue(ha, sp);
-				}
-
-				/* Was this command suspended for N secs */
-				if (sp->delay != 0) {
-					sp->delay--;
-					if (sp->delay == 0) {
-						online_cnt++;
-						__del_from_scsi_retry_queue(
-						    ha, sp);
-						__add_to_retry_queue(ha,sp);
-					}
-				}
-			}
-			spin_unlock_irqrestore(&ha->list_lock, flags);
-
-			/* Clear all Target Unsuspended bits */
-			for (t = 0; t < ha->max_targets; t++) {
-				if ((tq = ha->otgt[t]) == NULL)
-					continue;
-
-				if (test_bit(TQF_RETRY_CMDS, &tq->flags))
-					clear_bit(TQF_RETRY_CMDS, &tq->flags);
-			}
-			if (retry_cmds)
-				qla2x00_next(ha);
-
-			DEBUG(if (online_cnt > 0))
-			DEBUG(printk("scsi(%ld): dpc() found scsi reqs to "
-			    "restart= %d\n",
-			    ha->host_no, online_cnt));
-		}
-
 		if (ha->flags.mbox_busy) {
-			if (!list_empty(&ha->done_queue))
-				qla2x00_done(ha);
-
 			ha->dpc_active = 0;
 			continue;
 		}
@@ -3493,28 +2088,6 @@ qla2x00_do_dpc(void *data)
 			    ha->host_no));
 		}
 
-
-		if (test_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags)) {
-			DEBUG(printk("scsi(%ld): qla2x00_restart_queues()\n",
-			    ha->host_no));
-
-			qla2x00_restart_queues(ha, 0);
-
-			DEBUG(printk("scsi(%ld): qla2x00_restart_queues - end\n",
-			    ha->host_no));
-		}
-
-		if (test_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags)) {
-
-			DEBUG(printk("scsi(%ld): qla2x00_abort_queues()\n",
-			    ha->host_no));
-				
-			qla2x00_abort_queues(ha, 0);
-
-			DEBUG(printk("scsi(%ld): qla2x00_abort_queues - end\n",
-			    ha->host_no));
-		}
-
 		if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) {
 
 			DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n",
@@ -3527,13 +2100,9 @@ qla2x00_do_dpc(void *data)
 			    ha->host_no));
 		}
 
-
 		if (!ha->interrupts_on)
 			qla2x00_enable_intrs(ha);
 
-		if (!list_empty(&ha->done_queue))
-			qla2x00_done(ha);
-
 		ha->dpc_active = 0;
 	} /* End of while(1) */
 
@@ -3549,45 +2118,6 @@ qla2x00_do_dpc(void *data)
 }
 
 /*
- *  qla2x00_abort_queues
- *	Abort all commands on queues on device
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Context:
- *	Interrupt context.
- */
-void
-qla2x00_abort_queues(scsi_qla_host_t *ha, uint8_t doneqflg) 
-{
-
-	srb_t       *sp;
-	struct list_head *list, *temp;
-	unsigned long flags;
-
-	clear_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
-
-	/* Return all commands device queues. */
-	spin_lock_irqsave(&ha->list_lock,flags);
-	list_for_each_safe(list, temp, &ha->pending_queue) {
-		sp = list_entry(list, srb_t, list);
-
-		if (sp->flags & SRB_ABORTED)
-			continue;
-
-		/* Remove srb from LUN queue. */
-		__del_from_pending_queue(ha, sp);
-
-		/* Set ending status. */
-		sp->cmd->result = DID_BUS_BUSY << 16;
-
-		__add_to_done_queue(ha, sp);
-	}
-	spin_unlock_irqrestore(&ha->list_lock, flags);
-}
-
-/*
 *  qla2x00_rst_aen
 *      Processes asynchronous reset.
 *
@@ -3632,6 +2162,36 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha)
 	return (sp);
 }
 
+static void
+qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp)
+{
+	struct scsi_cmnd *cmd = sp->cmd;
+
+	if (sp->flags & SRB_DMA_VALID) {
+		if (cmd->use_sg) {
+			dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
+			    cmd->use_sg, cmd->sc_data_direction);
+		} else if (cmd->request_bufflen) {
+			dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
+			    cmd->request_bufflen, cmd->sc_data_direction);
+		}
+		sp->flags &= ~SRB_DMA_VALID;
+	}
+}
+
+void
+qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
+{
+	struct scsi_cmnd *cmd = sp->cmd;
+
+	qla2x00_sp_free_dma(ha, sp);
+
+	CMD_SP(cmd) = NULL;
+	mempool_free(sp, ha->srb_mempool);
+
+	cmd->scsi_done(cmd);
+}
+
 /**************************************************************************
 *   qla2x00_timer
 *
@@ -3643,30 +2203,12 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha)
 static void
 qla2x00_timer(scsi_qla_host_t *ha)
 {
-	int		t,l;
 	unsigned long	cpu_flags = 0;
 	fc_port_t	*fcport;
-	os_lun_t *lq;
-	os_tgt_t *tq;
 	int		start_dpc = 0;
 	int		index;
 	srb_t		*sp;
-
-	/*
-	 * We try and restart any request in the retry queue every second.
-	 */
-	if (!list_empty(&ha->retry_queue)) {
-		set_bit(PORT_RESTART_NEEDED, &ha->dpc_flags);
-		start_dpc++;
-	}
-
-	/*
-	 * We try and restart any request in the scsi_retry queue every second.
-	 */
-	if (!list_empty(&ha->scsi_retry_queue)) {
-		set_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags);
-		start_dpc++;
-	}
+	int		t;
 
 	/*
 	 * Ports - Port down timer.
@@ -3696,59 +2238,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
 		t++;
 	} /* End of for fcport  */
 
-	/*
-	 * LUNS - lun suspend timer.
-	 *
-	 * Whenever, a lun is suspended the timer starts decrementing its
-	 * suspend timer every second until it reaches zero. Once  it reaches
-	 * zero the lun retry count is decremented. 
-	 */
-
-	/*
-	 * FIXME(dg) - Need to convert this linear search of luns into a search
-	 * of a list of suspended luns.
-	 */
-	for (t = 0; t < ha->max_targets; t++) {
-		if ((tq = ha->otgt[t]) == NULL)
-			continue;
-
-		for (l = 0; l < ha->max_luns; l++) {
-			if ((lq = (os_lun_t *) tq->olun[l]) == NULL)
-				continue;
-
-			spin_lock_irqsave(&lq->q_lock, cpu_flags);
-			if (lq->q_state == LUN_STATE_WAIT &&
-				atomic_read(&lq->q_timer) != 0) {
-
-				if (atomic_dec_and_test(&lq->q_timer) != 0) {
-					/*
-					 * A delay should immediately
-					 * transition to a READY state
-					 */
-					if (test_and_clear_bit(LUN_EXEC_DELAYED,
-					    &lq->q_flag)) {
-						lq->q_state = LUN_STATE_READY;
-					}
-					else {
-						lq->q_count++;
-						if (lq->q_count == lq->q_max)
-							lq->q_state =
-							    LUN_STATE_TIMEOUT;
-						else
-							lq->q_state =
-							    LUN_STATE_RUN;
-					}
-				}
-				DEBUG3(printk("scsi(%ld): lun%d - timer %d, "
-				    "count=%d, max=%d, state=%d\n",
-				    ha->host_no,
-				    l,
-				    atomic_read(&lq->q_timer),
-				    lq->q_count, lq->q_max, lq->q_state));
-			}
-			spin_unlock_irqrestore(&lq->q_lock, cpu_flags);
-		} /* End of for luns  */
-	} /* End of for targets  */
 
 	/* Loop down handler. */
 	if (atomic_read(&ha->loop_down_timer) > 0 &&
@@ -3768,11 +2257,13 @@ qla2x00_timer(scsi_qla_host_t *ha)
 			spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
 			for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
 			    index++) {
+				fc_port_t *sfcp;
+
 				sp = ha->outstanding_cmds[index];
 				if (!sp)
 					continue;
-				if (!(sp->fclun->fcport->flags &
-				    FCF_TAPE_PRESENT))
+				sfcp = sp->fcport;
+				if (!(sfcp->flags & FCF_TAPE_PRESENT))
 					continue;
 
 				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
@@ -3808,19 +2299,12 @@ qla2x00_timer(scsi_qla_host_t *ha)
 		    atomic_read(&ha->loop_down_timer)));
 	}
 
-	/*
-	 * Done Q Handler -- dgFIXME This handler will kick off doneq if we
-	 * haven't process it in 2 seconds.
-	 */
-	if (!list_empty(&ha->done_queue))
-		qla2x00_done(ha);
-
-
 	/* Schedule the DPC routine if needed */
 	if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
 	    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
 	    start_dpc ||
 	    test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
+	    test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
 	    test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
 	    ha->dpc_wait && !ha->dpc_active) {
 
@@ -3830,496 +2314,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
 	qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
 
-/*
- * qla2x00_extend_timeout
- *      This routine will extend the timeout to the specified value.
- *
- * Input:
- *      cmd = SCSI command structure
- *
- * Returns:
- *      None.
- */
-void 
-qla2x00_extend_timeout(struct scsi_cmnd *cmd, int timeout) 
-{
-	srb_t *sp = (srb_t *) CMD_SP(cmd);
-	u_long our_jiffies = (timeout * HZ) + jiffies;
-
-    	sp->ext_history= 0; 
-	sp->e_start = jiffies;
-	if (cmd->eh_timeout.function) {
-		mod_timer(&cmd->eh_timeout,our_jiffies);
-		sp->ext_history |= 1;
-	}
-	if (sp->timer.function != NULL) {
-		/* 
-		 * Our internal timer should timeout before the midlayer has a
-		 * chance begin the abort process
-		 */
-		mod_timer(&sp->timer,our_jiffies - (QLA_CMD_TIMER_DELTA * HZ));
-
-    	 	sp->ext_history |= 2;
-	}
-}
-
-/**************************************************************************
-*   qla2x00_cmd_timeout
-*
-* Description:
-*       Handles the command if it times out in any state.
-*
-* Input:
-*     sp - pointer to validate
-*
-* Returns:
-* None.
-* Note:Need to add the support for if( sp->state == SRB_FAILOVER_STATE).
-**************************************************************************/
-void
-qla2x00_cmd_timeout(srb_t *sp)
-{
-	int t, l;
-	int processed;
-	scsi_qla_host_t *vis_ha, *dest_ha;
-	struct scsi_cmnd *cmd;
-	unsigned long flags, cpu_flags;
-	fc_port_t *fcport;
-
-	cmd = sp->cmd;
-	vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-
-	DEBUG3(printk("cmd_timeout: Entering sp->state = %x\n", sp->state));
-
-	t = cmd->device->id;
-	l = cmd->device->lun;
-	fcport = sp->fclun->fcport;
-	dest_ha = sp->ha;
-
-	/*
-	 * If IO is found either in retry Queue 
-	 *    OR in Lun Queue
-	 * Return this IO back to host
-	 */
-	spin_lock_irqsave(&vis_ha->list_lock, flags);
-	processed = 0;
-	if (sp->state == SRB_PENDING_STATE) {
-		__del_from_pending_queue(vis_ha, sp);
-		DEBUG2(printk("scsi(%ld): Found in Pending queue pid %ld, "
-		    "State = %x., fcport state=%d sjiffs=%lx njiffs=%lx\n",
-		    vis_ha->host_no, cmd->serial_number, sp->state,
-		    atomic_read(&fcport->state), sp->r_start, jiffies));
-
-		/*
-		 * If FC_DEVICE is marked as dead return the cmd with
-		 * DID_NO_CONNECT status.  Otherwise set the host_byte to
-		 * DID_BUS_BUSY to let the OS  retry this cmd.
-		 */
-		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-		    atomic_read(&fcport->ha->loop_state) == LOOP_DEAD) {
-			cmd->result = DID_NO_CONNECT << 16;
-			if (atomic_read(&fcport->ha->loop_state) == LOOP_DOWN) 
-				sp->err_id = SRB_ERR_LOOP;
-			else
-				sp->err_id = SRB_ERR_PORT;
-		} else {
-			cmd->result = DID_BUS_BUSY << 16;
-		}
-		__add_to_done_queue(vis_ha, sp);
-		processed++;
-	} 
-	spin_unlock_irqrestore(&vis_ha->list_lock, flags);
-
-	if (processed) {
-		qla2x00_done(vis_ha);
-		return;
-	}
-
-	spin_lock_irqsave(&dest_ha->list_lock, flags);
-	if ((sp->state == SRB_RETRY_STATE) ||
-	    (sp->state == SRB_SCSI_RETRY_STATE)) {
-
-		DEBUG2(printk("scsi(%ld): Found in (Scsi) Retry queue or "
-		    "failover Q pid %ld, State = %x., fcport state=%d "
-		    "jiffies=%lx retried=%d\n",
-		    dest_ha->host_no, cmd->serial_number, sp->state,
-		    atomic_read(&fcport->state), jiffies, cmd->retries));
-
-		if ((sp->state == SRB_RETRY_STATE)) {
-			__del_from_retry_queue(dest_ha, sp);
-		} else if ((sp->state == SRB_SCSI_RETRY_STATE)) {
-			__del_from_scsi_retry_queue(dest_ha, sp);
-		} 
-
-		/*
-		 * If FC_DEVICE is marked as dead return the cmd with
-		 * DID_NO_CONNECT status.  Otherwise set the host_byte to
-		 * DID_BUS_BUSY to let the OS  retry this cmd.
-		 */
-		if ((atomic_read(&fcport->state) == FCS_DEVICE_DEAD) ||
-		    atomic_read(&dest_ha->loop_state) == LOOP_DEAD) {
-			qla2x00_extend_timeout(cmd, EXTEND_CMD_TIMEOUT);
-			cmd->result = DID_NO_CONNECT << 16;
-			if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN) 
-				sp->err_id = SRB_ERR_LOOP;
-			else
-				sp->err_id = SRB_ERR_PORT;
-		} else {
-			cmd->result = DID_BUS_BUSY << 16;
-		}
-
-		__add_to_done_queue(dest_ha, sp);
-		processed++;
-	} 
-	spin_unlock_irqrestore(&dest_ha->list_lock, flags);
-
-	if (processed) {
-		qla2x00_done(dest_ha);
-		return;
-	}
-
-	spin_lock_irqsave(&dest_ha->list_lock, cpu_flags);
-	if (sp->state == SRB_DONE_STATE) {
-		/* IO in done_q  -- leave it */
-		DEBUG(printk("scsi(%ld): Found in Done queue pid %ld sp=%p.\n",
-		    dest_ha->host_no, cmd->serial_number, sp));
-	} else if (sp->state == SRB_SUSPENDED_STATE) {
-		DEBUG(printk("scsi(%ld): Found SP %p in suspended state  "
-		    "- pid %ld:\n",
-		    dest_ha->host_no, sp, cmd->serial_number));
-		DEBUG(qla2x00_dump_buffer((uint8_t *)sp, sizeof(srb_t));)
-	} else if (sp->state == SRB_ACTIVE_STATE) {
-		/*
-		 * IO is with ISP find the command in our active list.
-		 */
-		spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags);
-		spin_lock_irqsave(&dest_ha->hardware_lock, flags);
-		if (sp == dest_ha->outstanding_cmds[
-		    (unsigned long)sp->cmd->host_scribble]) {
-
-			DEBUG(printk("cmd_timeout: Found in ISP \n"));
-
-			if (sp->flags & SRB_TAPE) {
-				/*
-				 * We cannot allow the midlayer error handler
-				 * to wakeup and begin the abort process.
-				 * Extend the timer so that the firmware can
-				 * properly return the IOCB.
-				 */
-				DEBUG(printk("cmd_timeout: Extending timeout "
-				    "of FCP2 tape command!\n"));
-				qla2x00_extend_timeout(sp->cmd,
-				    EXTEND_CMD_TIMEOUT);
-			}
-			sp->state = SRB_ACTIVE_TIMEOUT_STATE;
-			spin_unlock_irqrestore(&dest_ha->hardware_lock, flags);
-		} else {
-			spin_unlock_irqrestore(&dest_ha->hardware_lock, flags);
-			printk(KERN_INFO 
-				"qla_cmd_timeout: State indicates it is with "
-				"ISP, But not in active array\n");
-		}
-		spin_lock_irqsave(&dest_ha->list_lock, cpu_flags);
-	} else if (sp->state == SRB_ACTIVE_TIMEOUT_STATE) {
-		DEBUG(printk("qla2100%ld: Found in Active timeout state"
-				"pid %ld, State = %x., \n",
-				dest_ha->host_no,
-				sp->cmd->serial_number, sp->state);)
-	} else {
-		/* EMPTY */
-		DEBUG2(printk("cmd_timeout%ld: LOST command state = "
-				"0x%x, sp=%p\n",
-				vis_ha->host_no, sp->state,sp);)
-
-		qla_printk(KERN_INFO, vis_ha,
-			"cmd_timeout: LOST command state = 0x%x\n", sp->state);
-	}
-	spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags);
-
-	DEBUG3(printk("cmd_timeout: Leaving\n");)
-}
-
-/**************************************************************************
-* qla2x00_done
-*      Process completed commands.
-*
-* Input:
-*      old_ha           = adapter block pointer.
-*
-**************************************************************************/
-void
-qla2x00_done(scsi_qla_host_t *old_ha)
-{
-	os_lun_t	*lq;
-	struct scsi_cmnd *cmd;
-	unsigned long	flags = 0;
-	scsi_qla_host_t	*ha;
-	scsi_qla_host_t	*vis_ha;
-	int	send_marker_once = 0;
-	srb_t           *sp, *sptemp;
-	LIST_HEAD(local_sp_list);
-
-	/*
-	 * Get into local queue such that we do not wind up calling done queue
-	 * tasklet for the same IOs from DPC or any other place.
-	 */
-	spin_lock_irqsave(&old_ha->list_lock, flags);
-	list_splice_init(&old_ha->done_queue, &local_sp_list);
-	spin_unlock_irqrestore(&old_ha->list_lock, flags);
-
-	/*
-	 * All done commands are in the local queue, now do the call back.
-	 */
-	list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
-		old_ha->done_q_cnt--;
-        	sp->state = SRB_NO_QUEUE_STATE;
-
-		/* remove command from local list */
-		list_del_init(&sp->list);
-
-		cmd = sp->cmd;
-		if (cmd == NULL)
-		 	continue;
-
-		vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-		lq = sp->lun_queue;
-		ha = sp->ha;
-
-		if (sp->flags & SRB_DMA_VALID) {
-			sp->flags &= ~SRB_DMA_VALID;
-
-			/* Release memory used for this I/O */
-			if (cmd->use_sg) {
-				pci_unmap_sg(ha->pdev, cmd->request_buffer,
-				    cmd->use_sg, cmd->sc_data_direction);
-			} else if (cmd->request_bufflen) {
-				pci_unmap_page(ha->pdev, sp->dma_handle,
-				    cmd->request_bufflen,
-				    cmd->sc_data_direction);
-			}
-		}
-
-
-		switch (host_byte(cmd->result)) {
-			case DID_OK:
-			case DID_ERROR:
-				break;
-
-			case DID_RESET:
-				/*
-				 * Set marker needed, so we don't have to
-				 * send multiple markers
-				 */
-				if (!send_marker_once) {
-					ha->marker_needed = 1;
-					send_marker_once++;
-				}
-
-				/*
-				 * WORKAROUND
-				 *
-				 * A backdoor device-reset requires different
-				 * error handling.  This code differentiates
-				 * between normal error handling and the
-				 * backdoor method.
-				 *
-				 */
-				if (ha->host->eh_active != EH_ACTIVE)
-					cmd->result = DID_BUS_BUSY << 16;
-				break;
-
-
-			case DID_ABORT:
-				sp->flags &= ~SRB_ABORT_PENDING;
-				sp->flags |= SRB_ABORTED;
-
-				if (sp->flags & SRB_TIMEOUT)
-					cmd->result = DID_TIME_OUT << 16;
-
-				break;
-
-			default:
-				DEBUG2(printk("scsi(%ld:%d:%d) %s: did_error "
-				    "= %d, comp-scsi= 0x%x-0x%x pid=%ld.\n",
-				    vis_ha->host_no,
-				    cmd->device->id, cmd->device->lun,
-				    __func__,
-				    host_byte(cmd->result),
-				    CMD_COMPL_STATUS(cmd),
-				    CMD_SCSI_STATUS(cmd), cmd->serial_number));
-				break;
-		}
-
-		/*
-		 * Call the mid-level driver interrupt handler -- via sp_put()
-		 */
-		sp_put(ha, sp);
-	} /* end of while */
-}
-
-/*
- * qla2x00_process_response_queue_in_zio_mode
- *	Process response queue completion as fast as possible
- *	to achieve Zero Interrupt Opertions-ZIO
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Context:
- *	Kernel context.
- */
-static inline void
-qla2x00_process_response_queue_in_zio_mode(scsi_qla_host_t *ha)
-{
-	unsigned long flags;
-
-	/* Check for unprocessed commands in response queue. */
-	if (!ha->flags.process_response_queue)
-		return;
-	if (!ha->flags.online)
-		return;
-	if (ha->response_ring_ptr->signature == RESPONSE_PROCESSED)
-		return;
-	
-	spin_lock_irqsave(&ha->hardware_lock,flags);
-	qla2x00_process_response_queue(ha);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-/*
- * qla2x00_next
- *	Retrieve and process next job in the LUN queue.
- *
- * Input:
- *	tq = SCSI target queue pointer.
- *	lq = SCSI LUN queue pointer.
- *	TGT_LOCK must be already obtained.
- *
- * Output:
- *	Releases TGT_LOCK upon exit.
- *
- * Context:
- *	Kernel/Interrupt context.
- * 
- * Note: This routine will always try to start I/O from visible HBA.
- */
-void
-qla2x00_next(scsi_qla_host_t *vis_ha) 
-{
-	int		rval;
-	unsigned long   flags;
-	scsi_qla_host_t *dest_ha;
-	fc_port_t	*fcport;
-	srb_t           *sp, *sptemp;
-	LIST_HEAD(local_sp_list);
-
-	dest_ha = NULL;
-
-	spin_lock_irqsave(&vis_ha->list_lock, flags);
-	list_splice_init(&vis_ha->pending_queue, &local_sp_list);
-	vis_ha->qthreads = 0;
-	spin_unlock_irqrestore(&vis_ha->list_lock, flags);
-
-	list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
-		list_del_init(&sp->list);
-        	sp->state = SRB_NO_QUEUE_STATE;
-
-		fcport = sp->fclun->fcport;
-		dest_ha = fcport->ha;
-
-		/* If device is dead then send request back to OS */
-		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) {
-			sp->cmd->result = DID_NO_CONNECT << 16;
-			if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN) 
-				sp->err_id = SRB_ERR_LOOP;
-			else
-				sp->err_id = SRB_ERR_PORT;
-
-			DEBUG3(printk("scsi(%ld): loop/port is down - pid=%ld, "
-			    "sp=%p err_id=%d loopid=0x%x queued to dest HBA "
-			    "scsi%ld.\n", dest_ha->host_no,
-			    sp->cmd->serial_number, sp, sp->err_id,
-			    fcport->loop_id, dest_ha->host_no));
-			/* 
-			 * Initiate a failover - done routine will initiate.
-			 */
-			add_to_done_queue(vis_ha, sp);
-
-			continue;
-		}
-
-		/*
-		 * SCSI Kluge: Whenever, we need to wait for an event such as
-		 * loop down (i.e. loop_down_timer ) or port down (i.e.  LUN
-		 * request qeueue is suspended) then we will recycle new
-		 * commands back to the SCSI layer.  We do this because this is
-		 * normally a temporary condition and we don't want the
-		 * mid-level scsi.c driver to get upset and start aborting
-		 * commands.  The timeout value is extracted from the command
-		 * minus 1-second and put on a retry queue (watchdog). Once the
-		 * command timeout it is returned to the mid-level with a BUSY
-		 * status, so the mid-level will retry it. This process
-		 * continues until the LOOP DOWN time expires or the condition
-		 * goes away.
-		 */
-		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
-		    (atomic_read(&fcport->state) != FCS_ONLINE ||
-			test_bit(ABORT_ISP_ACTIVE, &dest_ha->dpc_flags) ||
-			atomic_read(&dest_ha->loop_state) != LOOP_READY)) {
-
-			DEBUG3(printk("scsi(%ld): pid=%ld port=0x%x state=%d "
-			    "loop state=%d, loop counter=0x%x "
-			    "dpc_flags=0x%lx\n", sp->cmd->serial_number,
-			    dest_ha->host_no, fcport->loop_id,
-			    atomic_read(&fcport->state),
-			    atomic_read(&dest_ha->loop_state),
-			    atomic_read(&dest_ha->loop_down_timer),
-			    dest_ha->dpc_flags));
-
-			qla2x00_extend_timeout(sp->cmd, EXTEND_CMD_TIMEOUT);
-			add_to_retry_queue(vis_ha, sp);
-
-			continue;
-		} 
-
-		/*
-		 * If this request's lun is suspended then put the request on
-		 * the  scsi_retry queue. 
-		 */
-	 	if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
-		    sp->lun_queue->q_state == LUN_STATE_WAIT) {
-			DEBUG3(printk("scsi(%ld): lun wait state - pid=%ld, "
-			    "opcode=%d, allowed=%d, retries=%d\n",
-			    dest_ha->host_no,
-			    sp->cmd->serial_number,
-			    sp->cmd->cmnd[0],
-			    sp->cmd->allowed,
-			    sp->cmd->retries));
-				
-			add_to_scsi_retry_queue(vis_ha, sp);
-
-			continue;
-		}
-
-		sp->lun_queue->io_cnt++;
-
-		rval = qla2x00_start_scsi(sp);
-		if (rval != QLA_SUCCESS) {
-			/* Place request back on top of device queue */
-			/* add to the top of queue */
-			add_to_pending_queue_head(vis_ha, sp);
-
-			sp->lun_queue->io_cnt--;
-		}
-	}
-
-	if (!IS_QLA2100(vis_ha) && !IS_QLA2200(vis_ha)) {
-		/* Process response_queue if ZIO support is enabled*/ 
-		qla2x00_process_response_queue_in_zio_mode(vis_ha);
-
-	}
-}
-
 /* XXX(hch): crude hack to emulate a down_timeout() */
 int
 qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
@@ -4337,67 +2331,6 @@ qla2x00_down_timeout(struct semaphore *s
 	return -ETIMEDOUT;
 }
 
-static void
-qla2xxx_get_port_id(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	scsi_qla_host_t *ha = to_qla_host(shost);
-	struct fc_port *fc;
-
-	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == starget->id) {
-			fc_starget_port_id(starget) = fc->d_id.b.domain << 16 |
-				fc->d_id.b.area << 8 | 
-				fc->d_id.b.al_pa;
-			return;
-		}
-	}
-	fc_starget_port_id(starget) = -1;
-}
-
-static void
-qla2xxx_get_port_name(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	scsi_qla_host_t *ha = to_qla_host(shost);
-	struct fc_port *fc;
-
-	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == starget->id) {
-			fc_starget_port_name(starget) =
-				__be64_to_cpu(*(uint64_t *)fc->port_name);
-			return;
-		}
-	}
-	fc_starget_port_name(starget) = -1;
-}
-
-static void
-qla2xxx_get_node_name(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	scsi_qla_host_t *ha = to_qla_host(shost);
-	struct fc_port *fc;
-
-	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == starget->id) {
-			fc_starget_node_name(starget) =
-				__be64_to_cpu(*(uint64_t *)fc->node_name);
-			return;
-		}
-	}
-	fc_starget_node_name(starget) = -1;
-}
-
-static struct fc_function_template qla2xxx_transport_functions = {
-	.get_starget_port_id = qla2xxx_get_port_id,
-	.show_starget_port_id = 1,
-	.get_starget_port_name = qla2xxx_get_port_name,
-	.show_starget_port_name = 1,
-	.get_starget_node_name = qla2xxx_get_node_name,
-	.show_starget_node_name = 1,
-};
-
 /**
  * qla2x00_module_init - Module initialization.
  **/
@@ -4419,8 +2352,8 @@ qla2x00_module_init(void)
 #if DEBUG_QLA2100
 	strcat(qla2x00_version_str, "-debug");
 #endif
-
-	qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions);
+	qla2xxx_transport_template =
+	    fc_attach_transport(&qla2xxx_transport_functions);
 	if (!qla2xxx_transport_template)
 		return -ENODEV;
 
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -85,7 +85,7 @@ qla2x00_unlock_nvram_access(scsi_qla_hos
 void
 qla2x00_release_nvram_protection(scsi_qla_host_t *ha)
 {
-	device_reg_t *reg;
+	device_reg_t __iomem *reg;
 	uint32_t word;
 
 	reg = ha->iobase;
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -19,9 +19,9 @@
 /*
  * Driver version 
  */
-#define QLA2XXX_VERSION      "8.00.02b4-k"
+#define QLA2XXX_VERSION      "8.00.02b5-k"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	0
 #define QLA_DRIVER_PATCH_VER	2
-#define QLA_DRIVER_BETA_VER	4
+#define QLA_DRIVER_BETA_VER	5
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -71,7 +71,25 @@
 #define pci64_dma_build(hi,lo) \
 	((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32)))
 
-#include "qlogicfc.h"
+/*
+ * With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 2 scatter/gather entries.  If we need more
+ * than 2 entries, continuation entries can be used that hold
+ * another 5 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+
+#define DATASEGS_PER_COMMAND 2
+#define DATASEGS_PER_CONT 5
+
+#define QLOGICFC_REQ_QUEUE_LEN 255     /* must be power of two - 1 */
+#define QLOGICFC_MAX_SG(ql)	(DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
+#define QLOGICFC_CMD_PER_LUN    8
 
 /* Configuration section **************************************************** */
 
@@ -693,7 +711,7 @@ static inline void isp2x00_disable_irqs(
 }
 
 
-int isp2x00_detect(Scsi_Host_Template * tmpt)
+static int isp2x00_detect(Scsi_Host_Template * tmpt)
 {
 	int hosts = 0;
 	unsigned long wait_time;
@@ -1083,7 +1101,7 @@ int isp2x00_init_fabric(struct Scsi_Host
 #endif				/* ISP2x00_FABRIC */
 
 
-int isp2x00_release(struct Scsi_Host *host)
+static int isp2x00_release(struct Scsi_Host *host)
 {
 	struct isp2x00_hostdata *hostdata;
 	dma_addr_t busaddr;
@@ -1107,7 +1125,7 @@ int isp2x00_release(struct Scsi_Host *ho
 }
 
 
-const char *isp2x00_info(struct Scsi_Host *host)
+static const char *isp2x00_info(struct Scsi_Host *host)
 {
 	static char buf[80];
 	struct isp2x00_hostdata *hostdata;
@@ -1132,7 +1150,7 @@ const char *isp2x00_info(struct Scsi_Hos
  * interrupt handler may call this routine as part of
  * request-completion handling).
  */
-int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
+static int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 {
 	int i, sg_count, n, num_free;
 	u_int in_ptr, out_ptr;
@@ -1243,7 +1261,7 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmn
 
 	if (Cmnd->use_sg) {
 		sg = (struct scatterlist *) Cmnd->request_buffer;
-		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
 		cmd->segment_cnt = cpu_to_le16(sg_count);
 		ds = cmd->dataseg;
 		/* fill in first two sg entries: */
@@ -1289,7 +1307,7 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmn
 		dma_addr_t busaddr = pci_map_page(hostdata->pci_dev,
 						  page, offset,
 						  Cmnd->request_bufflen,
-						  scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						  Cmnd->sc_data_direction);
 		Cmnd->SCp.dma_handle = busaddr;
 
 		cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr));
@@ -1302,7 +1320,7 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmn
 		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
 	}
 
-	if (Cmnd->sc_data_direction == SCSI_DATA_WRITE)
+	if (Cmnd->sc_data_direction == DMA_TO_DEVICE)
 		cmd->control_flags = cpu_to_le16(CFLAG_WRITE);
 	else 
 		cmd->control_flags = cpu_to_le16(CFLAG_READ);
@@ -1387,13 +1405,13 @@ static void redo_port_db(unsigned long a
 						 pci_unmap_sg(hostdata->pci_dev,
 							      (struct scatterlist *)Cmnd->buffer,
 							      Cmnd->use_sg,
-							      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+							      Cmnd->sc_data_direction);
 					 else if (Cmnd->request_bufflen &&
 						  Cmnd->sc_data_direction != PCI_DMA_NONE) {
 						 pci_unmap_page(hostdata->pci_dev,
 								Cmnd->SCp.dma_handle,
 								Cmnd->request_bufflen,
-								scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+								Cmnd->sc_data_direction);
 					 }
 
 					 hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16;
@@ -1497,13 +1515,13 @@ void isp2x00_intr_handler(int irq, void 
 					pci_unmap_sg(hostdata->pci_dev,
 						     (struct scatterlist *)Cmnd->buffer,
 						     Cmnd->use_sg,
-						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						     Cmnd->sc_data_direction);
 				else if (Cmnd->request_bufflen &&
 					 Cmnd->sc_data_direction != PCI_DMA_NONE)
 					pci_unmap_page(hostdata->pci_dev,
 						       Cmnd->SCp.dma_handle,
 						       Cmnd->request_bufflen,
-						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						       Cmnd->sc_data_direction);
 				Cmnd->result = 0x0;
 				(*Cmnd->scsi_done) (Cmnd);
 			} else
@@ -1551,12 +1569,12 @@ void isp2x00_intr_handler(int irq, void 
 				if (Cmnd->use_sg)
 					pci_unmap_sg(hostdata->pci_dev,
 						     (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg,
-						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						     Cmnd->sc_data_direction);
 				else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE)
 					pci_unmap_page(hostdata->pci_dev,
 						       Cmnd->SCp.dma_handle,
 						       Cmnd->request_bufflen,
-						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+						       Cmnd->sc_data_direction);
 
 				/* 
 				 * if any of the following are true we do not
@@ -1697,7 +1715,7 @@ static int isp2x00_return_status(Scsi_Cm
 }
 
 
-int isp2x00_abort(Scsi_Cmnd * Cmnd)
+static int isp2x00_abort(Scsi_Cmnd * Cmnd)
 {
 	u_short param[8];
 	int i;
@@ -1755,37 +1773,7 @@ int isp2x00_abort(Scsi_Cmnd * Cmnd)
 }
 
 
-int isp2x00_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
-{
-	u_short param[8];
-	struct Scsi_Host *host;
-	struct isp2x00_hostdata *hostdata;
-	int return_status = SCSI_RESET_SUCCESS;
-
-	ENTER("isp2x00_reset");
-
-	host = Cmnd->device->host;
-	hostdata = (struct isp2x00_hostdata *) host->hostdata;
-	param[0] = MBOX_BUS_RESET;
-	param[1] = 3;
-
-	isp2x00_disable_irqs(host);
-
-	isp2x00_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]);
-		return_status = SCSI_RESET_ERROR;
-	}
-	isp2x00_enable_irqs(host);
-
-	LEAVE("isp2x00_reset");
-
-	return return_status;
-}
-
-
-int isp2x00_biosparam(struct scsi_device *sdev, struct block_device *n,
+static int isp2x00_biosparam(struct scsi_device *sdev, struct block_device *n,
 		sector_t capacity, int ip[])
 {
 	int size = capacity;
diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h
deleted file mode 100644
--- a/drivers/scsi/qlogicfc.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * QLogic ISP2x00 SCSI-FCP
- * 
- * Written by Erik H. Moe, ehm@cris.com
- * Copyright 1995, Erik H. Moe
- *
- * This program is free software; you can redistribute 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.
- */
-
-/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
-
-/* This is a version of the isp1020 driver which was modified by
- * Chris Loveland <cwl@iol.unh.edu> to support the isp2x00
- */
-
-
-/*
- * $Date: 1995/09/22 02:32:56 $
- * $Revision: 0.5 $
- *
- * $Log: isp1020.h,v $
- * Revision 0.5  1995/09/22  02:32:56  root
- * do auto request sense
- *
- * Revision 0.4  1995/08/07  04:48:28  root
- * supply firmware with driver.
- * numerous bug fixes/general cleanup of code.
- *
- * Revision 0.3  1995/07/16  16:17:16  root
- * added reset/abort code.
- *
- * Revision 0.2  1995/06/29  03:19:43  root
- * fixed biosparam.
- * added queue protocol.
- *
- * Revision 0.1  1995/06/25  01:56:13  root
- * Initial release.
- *
- */
-
-#ifndef _QLOGICFC_H
-#define _QLOGICFC_H
-
-/*
- * With the qlogic interface, every queue slot can hold a SCSI
- * command with up to 2 scatter/gather entries.  If we need more
- * than 2 entries, continuation entries can be used that hold
- * another 5 entries each.  Unlike for other drivers, this means
- * that the maximum number of scatter/gather entries we can
- * support at any given time is a function of the number of queue
- * slots available.  That is, host->can_queue and host->sg_tablesize
- * are dynamic and _not_ independent.  This all works fine because
- * requests are queued serially and the scatter/gather limit is
- * determined for each queue request anew.
- */
-
-#define DATASEGS_PER_COMMAND 2
-#define DATASEGS_PER_CONT 5
-
-#define QLOGICFC_REQ_QUEUE_LEN 255     /* must be power of two - 1 */
-#define QLOGICFC_MAX_SG(ql)	(DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
-#define QLOGICFC_CMD_PER_LUN    8
-
-int isp2x00_detect(Scsi_Host_Template *);
-int isp2x00_release(struct Scsi_Host *);
-const char * isp2x00_info(struct Scsi_Host *);
-int isp2x00_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int isp2x00_abort(Scsi_Cmnd *);
-int isp2x00_reset(Scsi_Cmnd *, unsigned int);
-int isp2x00_biosparam(struct scsi_device *, struct block_device *,
-		sector_t, int[]);
-#endif /* _QLOGICFC_H */
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -37,7 +37,21 @@
 #include <asm/byteorder.h>
 #include "scsi.h"
 #include <scsi/scsi_host.h>
-#include "qlogicisp.h"
+
+/*
+ * With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 4 scatter/gather entries.  If we need more
+ * than 4 entries, continuation entries can be used that hold
+ * another 7 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+#define QLOGICISP_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
+#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
 
 /* Configuration section *****************************************************/
 
@@ -655,7 +669,7 @@ static inline void isp1020_disable_irqs(
 }
 
 
-int isp1020_detect(Scsi_Host_Template *tmpt)
+static int isp1020_detect(Scsi_Host_Template *tmpt)
 {
 	int hosts = 0;
 	struct Scsi_Host *host;
@@ -736,7 +750,7 @@ int isp1020_detect(Scsi_Host_Template *t
 }
 
 
-int isp1020_release(struct Scsi_Host *host)
+static int isp1020_release(struct Scsi_Host *host)
 {
 	struct isp1020_hostdata *hostdata;
 
@@ -757,7 +771,7 @@ int isp1020_release(struct Scsi_Host *ho
 }
 
 
-const char *isp1020_info(struct Scsi_Host *host)
+static const char *isp1020_info(struct Scsi_Host *host)
 {
 	static char buf[80];
 	struct isp1020_hostdata *hostdata;
@@ -783,7 +797,7 @@ const char *isp1020_info(struct Scsi_Hos
  * interrupt handler may call this routine as part of
  * request-completion handling).
  */
-int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
+static int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 {
 	int i, n, num_free;
 	u_int in_ptr, out_ptr;
@@ -863,7 +877,7 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd
 		ds = cmd->dataseg;
 
 		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg,
-				      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				      Cmnd->sc_data_direction);
 
 		cmd->segment_cnt = cpu_to_le16(sg_count);
 
@@ -920,7 +934,7 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd
 		dma_addr = pci_map_single(hostdata->pci_dev,
 				       Cmnd->request_buffer,
 				       Cmnd->request_bufflen,
-				       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				       Cmnd->sc_data_direction);
 		Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr;
 
 		cmd->dataseg[0].d_base =
@@ -1053,7 +1067,7 @@ void isp1020_intr_handler(int irq, void 
 			pci_unmap_sg(hostdata->pci_dev,
 				     (struct scatterlist *)Cmnd->buffer,
 				     Cmnd->use_sg,
-				     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				     Cmnd->sc_data_direction);
 		else if (Cmnd->request_bufflen)
 			pci_unmap_single(hostdata->pci_dev,
 #ifdef CONFIG_QL_ISP_A64
@@ -1062,7 +1076,7 @@ void isp1020_intr_handler(int irq, void 
 					 (u32)((long)Cmnd->SCp.ptr),
 #endif
 					 Cmnd->request_bufflen,
-					 scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					 Cmnd->sc_data_direction);
 
 		isp_outw(out_ptr, host, MBOX5);
 		(*Cmnd->scsi_done)(Cmnd);
@@ -1161,80 +1175,7 @@ static int isp1020_return_status(struct 
 }
 
 
-int isp1020_abort(Scsi_Cmnd *Cmnd)
-{
-	u_short param[6];
-	struct Scsi_Host *host;
-	struct isp1020_hostdata *hostdata;
-	int return_status = SCSI_ABORT_SUCCESS;
-	u_int cmd_cookie;
-	int i;
-
-	ENTER("isp1020_abort");
-
-	host = Cmnd->device->host;
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-
-	for (i = 0; i < QLOGICISP_REQ_QUEUE_LEN + 1; i++)
-		if (hostdata->cmd_slots[i] == Cmnd)
-			break;
-	cmd_cookie = i;
-
-	isp1020_disable_irqs(host);
-
-	param[0] = MBOX_ABORT;
-	param[1] = (((u_short) Cmnd->device->id) << 8) | Cmnd->device->lun;
-	param[2] = cmd_cookie >> 16;
-	param[3] = cmd_cookie & 0xffff;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : scsi abort failure: %x\n", param[0]);
-		return_status = SCSI_ABORT_ERROR;
-	}
-
-	isp1020_enable_irqs(host);
-
-	LEAVE("isp1020_abort");
-
-	return return_status;
-}
-
-
-int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
-{
-	u_short param[6];
-	struct Scsi_Host *host;
-	struct isp1020_hostdata *hostdata;
-	int return_status = SCSI_RESET_SUCCESS;
-
-	ENTER("isp1020_reset");
-
-	host = Cmnd->device->host;
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-
-	param[0] = MBOX_BUS_RESET;
-	param[1] = hostdata->host_param.bus_reset_delay;
-
-	isp1020_disable_irqs(host);
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : scsi bus reset failure: %x\n", param[0]);
-		return_status = SCSI_RESET_ERROR;
-	}
-
-	isp1020_enable_irqs(host);
-
-	LEAVE("isp1020_reset");
-
-	return return_status;
-}
-
-
-int isp1020_biosparam(struct scsi_device *sdev, struct block_device *n,
+static int isp1020_biosparam(struct scsi_device *sdev, struct block_device *n,
 		sector_t capacity, int ip[])
 {
 	int size = capacity;
diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h
deleted file mode 100644
--- a/drivers/scsi/qlogicisp.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
- * Written by Erik H. Moe, ehm@cris.com
- * Copyright 1995, Erik H. Moe
- *
- * This program is free software; you can redistribute 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.
- */
-
-/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
-
-/*
- * $Date: 1995/09/22 02:32:56 $
- * $Revision: 0.5 $
- *
- * $Log: isp1020.h,v $
- * Revision 0.5  1995/09/22  02:32:56  root
- * do auto request sense
- *
- * Revision 0.4  1995/08/07  04:48:28  root
- * supply firmware with driver.
- * numerous bug fixes/general cleanup of code.
- *
- * Revision 0.3  1995/07/16  16:17:16  root
- * added reset/abort code.
- *
- * Revision 0.2  1995/06/29  03:19:43  root
- * fixed biosparam.
- * added queue protocol.
- *
- * Revision 0.1  1995/06/25  01:56:13  root
- * Initial release.
- *
- */
-
-#ifndef _QLOGICISP_H
-#define _QLOGICISP_H
-
-/*
- * With the qlogic interface, every queue slot can hold a SCSI
- * command with up to 4 scatter/gather entries.  If we need more
- * than 4 entries, continuation entries can be used that hold
- * another 7 entries each.  Unlike for other drivers, this means
- * that the maximum number of scatter/gather entries we can
- * support at any given time is a function of the number of queue
- * slots available.  That is, host->can_queue and host->sg_tablesize
- * are dynamic and _not_ independent.  This all works fine because
- * requests are queued serially and the scatter/gather limit is
- * determined for each queue request anew.
- */
-#define QLOGICISP_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
-#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
-
-int isp1020_detect(Scsi_Host_Template *);
-int isp1020_release(struct Scsi_Host *);
-const char * isp1020_info(struct Scsi_Host *);
-int isp1020_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int isp1020_abort(Scsi_Cmnd *);
-int isp1020_reset(Scsi_Cmnd *, unsigned int);
-int isp1020_biosparam(struct scsi_device *, struct block_device *,
-		sector_t, int[]);
-#endif /* _QLOGICISP_H */
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -99,7 +99,8 @@
 #define NV_MCP_SATA_CFG_20_SATA_SPACE_EN	0x04
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t nv_interrupt (int irq, void *dev_instance,
+				 struct pt_regs *regs);
 static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void nv_host_stop (struct ata_host_set *host_set);
@@ -205,6 +206,7 @@ static Scsi_Host_Template nv_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations nv_ops = {
@@ -257,7 +259,8 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t nv_interrupt (int irq, void *dev_instance,
+				 struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
 	struct nv_host *host = host_set->private_data;
@@ -326,6 +329,8 @@ static void nv_host_stop (struct ata_hos
 		host->host_desc->disable_hotplug(host_set);
 
 	kfree(host);
+
+	ata_host_stop(host_set);
 }
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -102,6 +102,7 @@ static Scsi_Host_Template pdc_ata_sht = 
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations pdc_ata_ops = {
@@ -121,6 +122,7 @@ static struct ata_port_operations pdc_at
 	.scr_write		= pdc_sata_scr_write,
 	.port_start		= pdc_port_start,
 	.port_stop		= pdc_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info pdc_port_info[] = {
@@ -150,6 +152,8 @@ static struct ata_port_info pdc_port_inf
 static struct pci_device_id pdc_ata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -38,7 +38,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_qstor"
-#define DRV_VERSION	"0.03"
+#define DRV_VERSION	"0.04"
 
 enum {
 	QS_PORTS		= 4,
@@ -120,6 +120,7 @@ static int qs_check_atapi_dma(struct ata
 static void qs_bmdma_stop(struct ata_port *ap);
 static u8 qs_bmdma_status(struct ata_port *ap);
 static void qs_irq_clear(struct ata_port *ap);
+static void qs_eng_timeout(struct ata_port *ap);
 
 static Scsi_Host_Template qs_ata_sht = {
 	.module			= THIS_MODULE,
@@ -152,7 +153,7 @@ static struct ata_port_operations qs_ata
 	.phy_reset		= qs_phy_reset,
 	.qc_prep		= qs_qc_prep,
 	.qc_issue		= qs_qc_issue,
-	.eng_timeout		= ata_eng_timeout,
+	.eng_timeout		= qs_eng_timeout,
 	.irq_handler		= qs_intr,
 	.irq_clear		= qs_irq_clear,
 	.scr_read		= qs_scr_read,
@@ -212,7 +213,7 @@ static void qs_irq_clear(struct ata_port
 	/* nothing */
 }
 
-static void qs_enter_reg_mode(struct ata_port *ap)
+static inline void qs_enter_reg_mode(struct ata_port *ap)
 {
 	u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
 
@@ -220,17 +221,34 @@ static void qs_enter_reg_mode(struct ata
 	readb(chan + QS_CCT_CTR0);        /* flush */
 }
 
-static void qs_phy_reset(struct ata_port *ap)
+static inline void qs_reset_channel_logic(struct ata_port *ap)
 {
 	u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
-	struct qs_port_priv *pp = ap->private_data;
 
-	pp->state = qs_state_idle;
 	writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+	readb(chan + QS_CCT_CTR0);        /* flush */
 	qs_enter_reg_mode(ap);
+}
+
+static void qs_phy_reset(struct ata_port *ap)
+{
+	struct qs_port_priv *pp = ap->private_data;
+
+	pp->state = qs_state_idle;
+	qs_reset_channel_logic(ap);
 	sata_phy_reset(ap);
 }
 
+static void qs_eng_timeout(struct ata_port *ap)
+{
+	struct qs_port_priv *pp = ap->private_data;
+
+	if (pp->state != qs_state_idle) /* healthy paranoia */
+		pp->state = qs_state_mmio;
+	qs_reset_channel_logic(ap);
+	ata_eng_timeout(ap);
+}
+
 static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
 	if (sc_reg > SCR_CONTROL)
@@ -261,11 +279,11 @@ static void qs_fill_sg(struct ata_queued
 		u32 len;
 
 		addr = sg_dma_address(sg);
-		*(u64 *)prd = cpu_to_le64(addr);
+		*(__le64 *)prd = cpu_to_le64(addr);
 		prd += sizeof(u64);
 
 		len = sg_dma_len(sg);
-		*(u32 *)prd = cpu_to_le32(len);
+		*(__le32 *)prd = cpu_to_le32(len);
 		prd += sizeof(u64);
 
 		VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
@@ -298,10 +316,10 @@ static void qs_qc_prep(struct ata_queued
 	/* host control block (HCB) */
 	buf[ 0] = QS_HCB_HDR;
 	buf[ 1] = hflags;
-	*(u32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
-	*(u32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem);
+	*(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+	*(__le32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem);
 	addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
-	*(u64 *)(&buf[16]) = cpu_to_le64(addr);
+	*(__le64 *)(&buf[16]) = cpu_to_le64(addr);
 
 	/* device control block (DCB) */
 	buf[24] = QS_DCB_HDR;
@@ -518,6 +536,8 @@ static void qs_host_stop(struct ata_host
 
 	writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
 	writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+	ata_host_stop(host_set);
 }
 
 static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
@@ -566,10 +586,10 @@ static int qs_set_dma_masks(struct pci_d
 	int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
 
 	if (have_64bit_bus &&
-	    !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
-		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (rc) {
-			rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 			if (rc) {
 				printk(KERN_ERR DRV_NAME
 					"(%s): 64-bit DMA enable failed\n",
@@ -578,14 +598,14 @@ static int qs_set_dma_masks(struct pci_d
 			}
 		}
 	} else {
-		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME
 				"(%s): 32-bit DMA enable failed\n",
 				pci_name(pdev));
 			return rc;
 		}
-		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME
 				"(%s): 32-bit consistent DMA enable failed\n",
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -38,12 +38,21 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil"
-#define DRV_VERSION	"0.8"
+#define DRV_VERSION	"0.9"
 
 enum {
 	sil_3112		= 0,
 	sil_3114		= 1,
 
+	SIL_FIFO_R0		= 0x40,
+	SIL_FIFO_W0		= 0x41,
+	SIL_FIFO_R1		= 0x44,
+	SIL_FIFO_W1		= 0x45,
+	SIL_FIFO_R2		= 0x240,
+	SIL_FIFO_W2		= 0x241,
+	SIL_FIFO_R3		= 0x244,
+	SIL_FIFO_W3		= 0x245,
+
 	SIL_SYSCFG		= 0x48,
 	SIL_MASK_IDE0_INT	= (1 << 22),
 	SIL_MASK_IDE1_INT	= (1 << 23),
@@ -73,12 +82,13 @@ static struct pci_device_id sil_pci_tbl[
 	{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
 	{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
 	{ 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
 	{ }	/* terminate list */
 };
 
 
 /* TODO firmware versions should be added - eric */
-struct sil_drivelist {
+static const struct sil_drivelist {
 	const char * product;
 	unsigned int quirk;
 } sil_blacklist [] = {
@@ -125,6 +135,7 @@ static Scsi_Host_Template sil_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations sil_ops = {
@@ -150,6 +161,7 @@ static struct ata_port_operations sil_op
 	.scr_write		= sil_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info sil_port_info[] = {
@@ -198,6 +210,13 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
+static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
+{
+	u8 cache_line = 0;
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
+	return cache_line;
+}
+
 static void sil_post_set_mode (struct ata_port *ap)
 {
 	struct ata_host_set *host_set = ap->host_set;
@@ -340,6 +359,7 @@ static int sil_init_one (struct pci_dev 
 	unsigned int i;
 	int pci_dev_busy = 0;
 	u32 tmp, irq_mask;
+	u8 cls;
 
 	if (!printed_version++)
 		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
@@ -404,6 +424,25 @@ static int sil_init_one (struct pci_dev 
 		ata_std_ports(&probe_ent->port[i]);
 	}
 
+	/* Initialize FIFO PCI bus arbitration */
+	cls = sil_get_device_cache_line(pdev);
+	if (cls) {
+		cls >>= 3;
+		cls++;  /* cls = (line_size/8)+1 */
+		writeb(cls, mmio_base + SIL_FIFO_R0);
+		writeb(cls, mmio_base + SIL_FIFO_W0);
+		writeb(cls, mmio_base + SIL_FIFO_R1);
+		writeb(cls, mmio_base + SIL_FIFO_W1);
+		if (ent->driver_data == sil_3114) {
+			writeb(cls, mmio_base + SIL_FIFO_R2);
+			writeb(cls, mmio_base + SIL_FIFO_W2);
+			writeb(cls, mmio_base + SIL_FIFO_R3);
+			writeb(cls, mmio_base + SIL_FIFO_W3);
+		}
+	} else
+		printk(KERN_WARNING DRV_NAME "(%s): cache line size not set.  Driver may not function\n",
+			pci_name(pdev));
+
 	if (ent->driver_data == sil_3114) {
 		irq_mask = SIL_MASK_4PORT;
 
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -90,6 +90,7 @@ static Scsi_Host_Template sis_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations sis_ops = {
@@ -113,6 +114,7 @@ static struct ata_port_operations sis_op
 	.scr_write		= sis_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info sis_port_info = {
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -156,7 +156,7 @@ static void k2_sata_tf_read(struct ata_p
  *	spin_lock_irqsave(host_set lock)
  */
 
-void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
@@ -186,7 +186,7 @@ void k2_bmdma_setup_mmio (struct ata_que
  *	spin_lock_irqsave(host_set lock)
  */
 
-void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	void *mmio = (void *) ap->ioaddr.bmdma_addr;
@@ -288,6 +288,7 @@ static Scsi_Host_Template k2_sata_sht = 
 	.proc_info		= k2_sata_proc_info,
 #endif
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 
@@ -312,6 +313,7 @@ static struct ata_port_operations k2_sat
 	.scr_write		= k2_sata_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -394,7 +396,7 @@ static int k2_sata_init_one (struct pci_
 
 	/* Clear a magic bit in SCR1 according to Darwin, those help
 	 * some funky seagate drives (though so far, those were already
-	 * set by the firmware on the machines I had access to
+	 * set by the firmware on the machines I had access to)
 	 */
 	writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
 	       mmio_base + K2_SATA_SICR1_OFFSET);
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -188,6 +188,7 @@ static Scsi_Host_Template pdc_sata_sht =
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations pdc_20621_ops = {
@@ -244,6 +245,8 @@ static void pdc20621_host_stop(struct at
 
 	iounmap(dimm_mmio);
 	kfree(hpriv);
+
+	ata_host_stop(host_set);
 }
 
 static int pdc_port_start(struct ata_port *ap)
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -82,6 +82,7 @@ static Scsi_Host_Template uli_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations uli_ops = {
@@ -112,6 +113,7 @@ static struct ata_port_operations uli_op
 
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info uli_port_info = {
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -102,6 +102,7 @@ static Scsi_Host_Template svia_sht = {
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 static struct ata_port_operations svia_sata_ops = {
@@ -133,6 +134,7 @@ static struct ata_port_operations svia_s
 
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static struct ata_port_info svia_port_info = {
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -21,6 +21,7 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
@@ -155,7 +156,8 @@ static void vsc_sata_tf_read(struct ata_
  *
  * Read the interrupt register and process for the devices that have them pending.
  */
-irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
+				       struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
 	unsigned int i;
@@ -204,6 +206,7 @@ static Scsi_Host_Template vsc_sata_sht =
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
 };
 
 
@@ -228,6 +231,7 @@ static struct ata_port_operations vsc_sa
 	.scr_write		= vsc_sata_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
 };
 
 static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -285,10 +289,10 @@ static int __devinit vsc_sata_init_one (
 	/*
 	 * Use 32 bit DMA mask, because 64 bit address support is poor.
 	 */
-	rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
+	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (rc)
 		goto err_out_regions;
-	rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL);
+	rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 	if (rc)
 		goto err_out_regions;
 
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -88,12 +88,6 @@
 				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
 
 /*
- * Data declarations.
- */
-unsigned long scsi_pid;
-static unsigned long serial_number;
-
-/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -495,7 +489,7 @@ void scsi_log_completion(struct scsi_cmn
 			scsi_print_command(cmd);
 			if (status_byte(cmd->result) & CHECK_CONDITION) {
 				/*
-				 * XXX The print_sense formatting/prefix
+				 * XXX The scsi_print_sense formatting/prefix
 				 * doesn't match this function.
 				 */
 				scsi_print_sense("", cmd);
@@ -510,6 +504,21 @@ void scsi_log_completion(struct scsi_cmn
 }
 #endif
 
+/* 
+ * Assign a serial number and pid to the request for error recovery
+ * and debugging purposes.  Protected by the Host_Lock of host.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+	cmd->serial_number = host->cmd_serial_number++;
+	if (cmd->serial_number == 0) 
+		cmd->serial_number = host->cmd_serial_number++;
+	
+	cmd->pid = host->cmd_pid++;
+	if (cmd->pid == 0)
+		cmd->pid = host->cmd_pid++;
+}
+
 /*
  * Function:    scsi_dispatch_command
  *
@@ -532,7 +541,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		 * returns an immediate error upwards, and signals
 		 * that the device is no longer present */
 		cmd->result = DID_NO_CONNECT << 16;
-		scsi_done(cmd);
+		atomic_inc(&cmd->device->iorequest_cnt);
+		__scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -556,13 +566,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		goto out;
 	}
 
-	/* Assign a unique nonzero serial_number. */
-	/* XXX(hch): this is racy */
-	if (++serial_number == 0)
-		serial_number = 1;
-	cmd->serial_number = serial_number;
-	cmd->pid = scsi_pid++;
-
 	/* 
 	 * If SCSI-2 or lower, store the LUN value in cmnd.
 	 */
@@ -593,6 +596,10 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		host->resetting = 0;
 	}
 
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 */
 	scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
 
 	scsi_log_send(cmd);
@@ -605,6 +612,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	cmd->state = SCSI_STATE_QUEUED;
 	cmd->owner = SCSI_OWNER_LOWLEVEL;
 
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/*
 	 * Before we queue this command, check if the command
 	 * length exceeds what the host adapter can handle.
@@ -619,6 +628,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	scsi_cmd_get_serial(host, cmd); 
+
 	if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
 		cmd->result = (DID_NO_CONNECT << 16);
 		scsi_done(cmd);
@@ -627,6 +638,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 	spin_unlock_irqrestore(host->host_lock, flags);
 	if (rtn) {
+		atomic_inc(&cmd->device->iodone_cnt);
 		scsi_queue_insert(cmd,
 				(rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
 				 rtn : SCSI_MLQUEUE_HOST_BUSY);
@@ -674,7 +686,6 @@ void scsi_init_cmd_from_req(struct scsi_
 	cmd->request = sreq->sr_request;
 	memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd));
 	cmd->serial_number = 0;
-	cmd->serial_number_at_timeout = 0;
 	cmd->bufflen = sreq->sr_bufflen;
 	cmd->buffer = sreq->sr_buffer;
 	cmd->retries = 0;
@@ -704,7 +715,6 @@ void scsi_init_cmd_from_req(struct scsi_
 	/*
 	 * Start the timer ticking.
 	 */
-	cmd->internal_timeout = NORMAL_TIMEOUT;
 	cmd->abort_reason = 0;
 	cmd->result = 0;
 
@@ -754,10 +764,13 @@ void __scsi_done(struct scsi_cmnd *cmd)
 	 * Set the serial numbers back to zero
 	 */
 	cmd->serial_number = 0;
-	cmd->serial_number_at_timeout = 0;
 	cmd->state = SCSI_STATE_BHQUEUE;
 	cmd->owner = SCSI_OWNER_BH_HANDLER;
 
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
+
 	/*
 	 * Next, enqueue the command into the done queue.
 	 * It is a per-CPU queue, so we just disable local interrupts
@@ -920,12 +933,9 @@ EXPORT_SYMBOL(scsi_finish_command);
  * 		the right thing depending on whether or not the device is
  * 		currently active and whether or not it even has the
  * 		command blocks built yet.
- *
- * XXX(hch):	What exactly is device_request_lock trying to protect?
  */
 void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 {
-	static DEFINE_SPINLOCK(device_request_lock);
 	unsigned long flags;
 
 	/*
@@ -934,8 +944,7 @@ void scsi_adjust_queue_depth(struct scsi
 	if (tags <= 0)
 		return;
 
-	spin_lock_irqsave(&device_request_lock, flags);
-	spin_lock(sdev->request_queue->queue_lock);
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
 	/* Check to see if the queue is managed by the block layer
 	 * if it is, and we fail to adjust the depth, exit */
@@ -964,8 +973,7 @@ void scsi_adjust_queue_depth(struct scsi
 			break;
 	}
  out:
-	spin_unlock(sdev->request_queue->queue_lock);
-	spin_unlock_irqrestore(&device_request_lock, flags);
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 }
 EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
@@ -1105,6 +1113,60 @@ void starget_for_each_device(struct scsi
 EXPORT_SYMBOL(starget_for_each_device);
 
 /**
+ * __scsi_device_lookup_by_target - find a device given the target (UNLOCKED)
+ * @starget:	SCSI target pointer
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @lun for a give
+ * @starget. The returned scsi_device does not have an additional
+ * reference.  You must hold the host's host_lock over this call and
+ * any access to the returned scsi_device.
+ *
+ * Note:  The only reason why drivers would want to use this is because
+ * they're need to access the device list in irq context.  Otherwise you
+ * really want to use scsi_device_lookup_by_target instead.
+ **/
+struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
+						   uint lun)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &starget->devices, same_target_siblings) {
+		if (sdev->lun ==lun)
+			return sdev;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(__scsi_device_lookup_by_target);
+
+/**
+ * scsi_device_lookup_by_target - find a device given the target
+ * @starget:	SCSI target pointer
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @channel, @id, @lun for a
+ * give host.  The returned scsi_device has an additional reference that
+ * needs to be release with scsi_host_put once you're done with it.
+ **/
+struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
+						 uint lun)
+{
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	sdev = __scsi_device_lookup_by_target(starget, lun);
+	if (sdev && scsi_device_get(sdev))
+		sdev = NULL;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	return sdev;
+}
+EXPORT_SYMBOL(scsi_device_lookup_by_target);
+
+/**
  * scsi_device_lookup - find a device given the host (UNLOCKED)
  * @shost:	SCSI host pointer
  * @channel:	SCSI channel (zero if only one channel)
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -23,7 +23,6 @@
 #include <linux/config.h>	    /* for CONFIG_SCSI_LOGGING */
 
 #include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_request.h>
@@ -46,63 +45,6 @@ struct scsi_device;
 struct scsi_target;
 struct scatterlist;
 
-/*
- * Legacy dma direction interfaces.
- *
- * This assumes the pci/sbus dma mapping flags have the same numercial
- * values as the generic dma-mapping ones.  Currently they have but there's
- * no way to check.  Better don't use these interfaces!
- */
-#define SCSI_DATA_UNKNOWN	(DMA_BIDIRECTIONAL)
-#define SCSI_DATA_WRITE		(DMA_TO_DEVICE)
-#define SCSI_DATA_READ		(DMA_FROM_DEVICE)
-#define SCSI_DATA_NONE		(DMA_NONE)
-
-#define scsi_to_pci_dma_dir(scsi_dir)	((int)(scsi_dir))
-#define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
-
-/*
- * Old names for debug prettyprinting functions.
- */
-static inline void print_Scsi_Cmnd(struct scsi_cmnd *cmd)
-{
-	return scsi_print_command(cmd);
-}
-static inline void print_command(unsigned char *cdb)
-{
-	return __scsi_print_command(cdb);
-}
-static inline void print_sense(const char *devclass, struct scsi_cmnd *cmd)
-{
-	return scsi_print_sense(devclass, cmd);
-}
-static inline void print_req_sense(const char *devclass, struct scsi_request *req)
-{
-	return scsi_print_req_sense(devclass, req);
-}
-static inline void print_driverbyte(int scsiresult)
-{
-	return scsi_print_driverbyte(scsiresult);
-}
-static inline void print_hostbyte(int scsiresult)
-{
-	return scsi_print_hostbyte(scsiresult);
-}
-static inline void print_status(unsigned char status)
-{
-	return scsi_print_status(status);
-}
-static inline int print_msg(const unsigned char *msg)
-{
-	return scsi_print_msg(msg);
-}
-
-/*
- * 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.
- */
-#include "scsi_obsolete.h"
-
 /* obsolete typedef junk. */
 #include "scsi_typedefs.h"
 
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -63,6 +63,7 @@ static struct {
 	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* locks up */
 	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* locks up */
 	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* responds to all lun */
+	{"MICROTEK", "ScanMakerIII", "2.30", BLIST_NOLUN},	/* responds to all lun */
 	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
 	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* responds to all lun */
 	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* locks up */
@@ -159,6 +160,7 @@ static struct {
 	{"HP", "C3323-300", "4269", BLIST_NOTQ},
 	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
 	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
 	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
 	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
 	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
@@ -192,6 +194,7 @@ static struct {
 	{"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
 	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
 	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
+	{"ST650211", "CF", NULL, BLIST_RETRY_HWERROR},
 	{"SUN", "T300", "*", BLIST_SPARSELUN},
 	{"SUN", "T4", "*", BLIST_SPARSELUN},
 	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
@@ -201,6 +204,7 @@ static struct {
 	{"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN},
 	{"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN},
 	{"WangDAT", "Model 1300", "02.4", BLIST_SELECT_NO_ATN},
+	{"WDC WD25", "00JB-00FUA0", NULL, BLIST_NOREPORTLUN},
 	{"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -79,11 +79,6 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 	 */
 	scmd->owner = SCSI_OWNER_ERROR_HANDLER;
 	scmd->state = SCSI_STATE_FAILED;
-	/*
-	 * Set the serial_number_at_timeout to the current
-	 * serial_number
-	 */
-	scmd->serial_number_at_timeout = scmd->serial_number;
 	list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
 	set_bit(SHOST_RECOVERY, &shost->shost_state);
 	shost->host_failed++;
@@ -350,10 +345,15 @@ static int scsi_check_sense(struct scsi_
 	case MEDIUM_ERROR:
 		return NEEDS_RETRY;
 
+	case HARDWARE_ERROR:
+		if (scmd->device->retry_hwerror)
+			return NEEDS_RETRY;
+		else
+			return SUCCESS;
+
 	case ILLEGAL_REQUEST:
 	case BLANK_CHECK:
 	case DATA_PROTECT:
-	case HARDWARE_ERROR:
 	default:
 		return SUCCESS;
 	}
@@ -476,7 +476,8 @@ static void scsi_eh_done(struct scsi_cmn
  **/
 static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
 {
-	struct Scsi_Host *host = scmd->device->host;
+	struct scsi_device *sdev = scmd->device;
+	struct Scsi_Host *shost = sdev->host;
 	DECLARE_MUTEX_LOCKED(sem);
 	unsigned long flags;
 	int rtn = SUCCESS;
@@ -487,27 +488,27 @@ static int scsi_send_eh_cmnd(struct scsi
 	 */
 	scmd->owner = SCSI_OWNER_LOWLEVEL;
 
-	if (scmd->device->scsi_level <= SCSI_2)
+	if (sdev->scsi_level <= SCSI_2)
 		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
-			(scmd->device->lun << 5 & 0xe0);
+			(sdev->lun << 5 & 0xe0);
 
 	scsi_add_timer(scmd, timeout, scsi_eh_times_out);
 
 	/*
 	 * set up the semaphore so we wait for the command to complete.
 	 */
-	scmd->device->host->eh_action = &sem;
+	shost->eh_action = &sem;
 	scmd->request->rq_status = RQ_SCSI_BUSY;
 
-	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	spin_lock_irqsave(shost->host_lock, flags);
 	scsi_log_send(scmd);
-	host->hostt->queuecommand(scmd, scsi_eh_done);
-	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+	shost->hostt->queuecommand(scmd, scsi_eh_done);
+	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	down(&sem);
 	scsi_log_completion(scmd, SUCCESS);
 
-	scmd->device->host->eh_action = NULL;
+	shost->eh_action = NULL;
 
 	/*
 	 * see if timeout.  if so, tell the host to forget about it.
@@ -527,10 +528,10 @@ static int scsi_send_eh_cmnd(struct scsi
 		 * abort a timed out command or not.  not sure how
 		 * we should treat them differently anyways.
 		 */
-		spin_lock_irqsave(scmd->device->host->host_lock, flags);
-		if (scmd->device->host->hostt->eh_abort_handler)
-			scmd->device->host->hostt->eh_abort_handler(scmd);
-		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+		spin_lock_irqsave(shost->host_lock, flags);
+		if (shost->hostt->eh_abort_handler)
+			shost->hostt->eh_abort_handler(scmd);
+		spin_unlock_irqrestore(shost->host_lock, flags);
 			
 		scmd->request->rq_status = RQ_SCSI_DONE;
 		scmd->owner = SCSI_OWNER_ERROR_HANDLER;
@@ -583,7 +584,7 @@ static int scsi_request_sense(struct scs
 
 	memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
 
-	scsi_result = kmalloc(252, GFP_ATOMIC | (scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0);
+	scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0));
 
 
 	if (unlikely(!scsi_result)) {
@@ -1056,7 +1057,6 @@ static int scsi_try_bus_reset(struct scs
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
 					  __FUNCTION__));
 	scmd->owner = SCSI_OWNER_LOWLEVEL;
-	scmd->serial_number_at_timeout = scmd->serial_number;
 
 	if (!scmd->device->host->hostt->eh_bus_reset_handler)
 		return FAILED;
@@ -1088,7 +1088,6 @@ static int scsi_try_host_reset(struct sc
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
 					  __FUNCTION__));
 	scmd->owner = SCSI_OWNER_LOWLEVEL;
-	scmd->serial_number_at_timeout = scmd->serial_number;
 
 	if (!scmd->device->host->hostt->eh_host_reset_handler)
 		return FAILED;
@@ -1308,6 +1307,9 @@ int scsi_decide_disposition(struct scsi_
 	case DID_IMM_RETRY:
 		return NEEDS_RETRY;
 
+	case DID_REQUEUE:
+		return ADD_TO_MLQUEUE;
+
 	case DID_ERROR:
 		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
 		    status_byte(scmd->result) == RESERVATION_CONFLICT)
@@ -1364,6 +1366,7 @@ int scsi_decide_disposition(struct scsi_
 		return ADD_TO_MLQUEUE;
 	case GOOD:
 	case COMMAND_TERMINATED:
+	case TASK_ABORTED:
 		return SUCCESS;
 	case CHECK_CONDITION:
 		rtn = scsi_check_sense(scmd);
@@ -1377,6 +1380,7 @@ int scsi_decide_disposition(struct scsi_
 	case CONDITION_GOOD:
 	case INTERMEDIATE_GOOD:
 	case INTERMEDIATE_C_GOOD:
+	case ACA_ACTIVE:
 		/*
 		 * who knows?  FIXME(eric)
 		 */
@@ -1832,7 +1836,6 @@ scsi_reset_provider(struct scsi_device *
 	scmd->bufflen			= 0;
 	scmd->request_buffer		= NULL;
 	scmd->request_bufflen		= 0;
-	scmd->internal_timeout		= NORMAL_TIMEOUT;
 	scmd->abort_reason		= DID_ABORT;
 
 	scmd->cmd_len			= 0;
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -27,11 +27,6 @@
 
 #define NORMAL_RETRIES			5
 #define IOCTL_NORMAL_TIMEOUT			(10 * HZ)
-#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
-#define START_STOP_TIMEOUT		(60 * HZ)
-#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
-#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
-#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )  /* ZIP-250 on parallel port takes as long! */
 
 #define MAX_BUF PAGE_SIZE
 
@@ -230,7 +225,7 @@ int scsi_ioctl_send_command(struct scsi_
 	/*
 	 * Verify that we can read at least this much.
 	 */
-	if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
+	if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
 		return -EFAULT;
 
 	if(__get_user(inlen, &sic->inlen))
@@ -285,7 +280,7 @@ int scsi_ioctl_send_command(struct scsi_
 	
 	result = -EFAULT;
 
-	if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
+	if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen))
 		goto error;
 
 	if(__copy_from_user(cmd, cmd_in, cmdlen))
@@ -417,7 +412,7 @@ int scsi_ioctl(struct scsi_device *sdev,
 
 	switch (cmd) {
 	case SCSI_IOCTL_GET_IDLUN:
-		if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun)))
+		if (!access_ok(VERIFY_WRITE, arg, sizeof(struct scsi_idlun)))
 			return -EFAULT;
 
 		__put_user((sdev->id & 0xff)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -252,6 +252,16 @@ static void scsi_wait_done(struct scsi_c
 		complete(req->waiting);
 }
 
+/* This is the end routine we get to if a command was never attached
+ * to the request.  Simply complete the request without changing
+ * rq_status; this will cause a DRIVER_ERROR. */
+static void scsi_wait_req_end_io(struct request *req)
+{
+	BUG_ON(!req->waiting);
+
+	complete(req->waiting);
+}
+
 void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
 		   unsigned bufflen, int timeout, int retries)
 {
@@ -259,6 +269,7 @@ void scsi_wait_req(struct scsi_request *
 	
 	sreq->sr_request->waiting = &wait;
 	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
+	sreq->sr_request->end_io = scsi_wait_req_end_io;
 	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
 			timeout, retries);
 	wait_for_completion(&wait);
@@ -287,7 +298,6 @@ static int scsi_init_cmd_errh(struct scs
 {
 	cmd->owner = SCSI_OWNER_MIDLEVEL;
 	cmd->serial_number = 0;
-	cmd->serial_number_at_timeout = 0;
 	cmd->abort_reason = 0;
 
 	memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
@@ -309,7 +319,6 @@ static int scsi_init_cmd_errh(struct scs
 	memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
 	cmd->buffer = cmd->request_buffer;
 	cmd->bufflen = cmd->request_bufflen;
-	cmd->internal_timeout = NORMAL_TIMEOUT;
 	cmd->abort_reason = 0;
 
 	return 1;
@@ -349,9 +358,9 @@ void scsi_device_unbusy(struct scsi_devi
 		     shost->host_failed))
 		scsi_eh_wakeup(shost);
 	spin_unlock(shost->host_lock);
-	spin_lock(&sdev->sdev_lock);
+	spin_lock(sdev->request_queue->queue_lock);
 	sdev->device_busy--;
-	spin_unlock_irqrestore(&sdev->sdev_lock, flags);
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 }
 
 /*
@@ -365,10 +374,11 @@ static void scsi_single_lun_run(struct s
 {
 	struct Scsi_Host *shost = current_sdev->host;
 	struct scsi_device *sdev, *tmp;
+	struct scsi_target *starget = scsi_target(current_sdev);
 	unsigned long flags;
 
 	spin_lock_irqsave(shost->host_lock, flags);
-	scsi_target(current_sdev)->starget_sdev_user = NULL;
+	starget->starget_sdev_user = NULL;
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	/*
@@ -380,10 +390,12 @@ static void scsi_single_lun_run(struct s
 	blk_run_queue(current_sdev->request_queue);
 
 	spin_lock_irqsave(shost->host_lock, flags);
-	if (scsi_target(current_sdev)->starget_sdev_user)
+	if (starget->starget_sdev_user)
 		goto out;
-	list_for_each_entry_safe(sdev, tmp, &current_sdev->same_target_siblings,
+	list_for_each_entry_safe(sdev, tmp, &starget->devices,
 			same_target_siblings) {
+		if (sdev == current_sdev)
+			continue;
 		if (scsi_device_get(sdev))
 			continue;
 
@@ -697,6 +709,9 @@ void scsi_io_completion(struct scsi_cmnd
 	int sense_valid = 0;
 	int sense_deferred = 0;
 
+	if (blk_complete_barrier_rq(q, req, good_bytes >> 9))
+		return;
+
 	/*
 	 * Free up any indirection buffers we allocated for DMA purposes. 
 	 * For the case of a READ, we need to copy the data out of the
@@ -723,7 +738,7 @@ void scsi_io_completion(struct scsi_cmnd
 		req->errors = result;
 		if (result) {
 			clear_errors = 0;
-			if (sense_valid) {
+			if (sense_valid && req->sense) {
 				/*
 				 * SG_IO wants current and deferred errors
 				 */
@@ -962,6 +977,38 @@ static int scsi_init_io(struct scsi_cmnd
 	return BLKPREP_KILL;
 }
 
+static int scsi_prepare_flush_fn(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_driver *drv;
+
+	if (sdev->sdev_state == SDEV_RUNNING) {
+		drv = *(struct scsi_driver **) rq->rq_disk->private_data;
+
+		if (drv->prepare_flush)
+			return drv->prepare_flush(q, rq);
+	}
+
+	return 0;
+}
+
+static void scsi_end_flush_fn(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct request *flush_rq = rq->end_io_data;
+	struct scsi_driver *drv;
+
+	if (flush_rq->errors) {
+		printk("scsi: barrier error, disabling flush support\n");
+		blk_queue_ordered(q, QUEUE_ORDERED_NONE);
+	}
+
+	if (sdev->sdev_state == SDEV_RUNNING) {
+		drv = *(struct scsi_driver **) rq->rq_disk->private_data;
+		drv->end_flush(q, rq);
+	}
+}
+
 static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
 			       sector_t *error_sector)
 {
@@ -1195,6 +1242,22 @@ static inline int scsi_host_queue_ready(
 }
 
 /*
+ * Kill requests for a dead device
+ */
+static void scsi_kill_requests(request_queue_t *q)
+{
+	struct request *req;
+
+	while ((req = elv_next_request(q)) != NULL) {
+		blkdev_dequeue_request(req);
+		req->flags |= REQ_QUIET;
+		while (end_that_request_first(req, 0, req->nr_sectors))
+			;
+		end_that_request_last(req);
+	}
+}
+
+/*
  * Function:    scsi_request_fn()
  *
  * Purpose:     Main strategy routine for SCSI.
@@ -1208,10 +1271,16 @@ static inline int scsi_host_queue_ready(
 static void scsi_request_fn(struct request_queue *q)
 {
 	struct scsi_device *sdev = q->queuedata;
-	struct Scsi_Host *shost = sdev->host;
+	struct Scsi_Host *shost;
 	struct scsi_cmnd *cmd;
 	struct request *req;
 
+	if (!sdev) {
+		printk("scsi: killing requests for dead queue\n");
+		scsi_kill_requests(q);
+		return;
+	}
+
 	if(!get_device(&sdev->sdev_gendev))
 		/* We must be tearing the block queue down already */
 		return;
@@ -1220,6 +1289,7 @@ static void scsi_request_fn(struct reque
 	 * To start with, we keep looping until the queue is empty, or until
 	 * the host is no longer able to accept any more requests.
 	 */
+	shost = sdev->host;
 	while (!blk_queue_plugged(q)) {
 		int rtn;
 		/*
@@ -1353,7 +1423,7 @@ struct request_queue *scsi_alloc_queue(s
 	struct Scsi_Host *shost = sdev->host;
 	struct request_queue *q;
 
-	q = blk_init_queue(scsi_request_fn, &sdev->sdev_lock);
+	q = blk_init_queue(scsi_request_fn, NULL);
 	if (!q)
 		return NULL;
 
@@ -1366,6 +1436,17 @@ struct request_queue *scsi_alloc_queue(s
 	blk_queue_segment_boundary(q, shost->dma_boundary);
 	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
 
+	/*
+	 * ordered tags are superior to flush ordering
+	 */
+	if (shost->ordered_tag)
+		blk_queue_ordered(q, QUEUE_ORDERED_TAG);
+	else if (shost->ordered_flush) {
+		blk_queue_ordered(q, QUEUE_ORDERED_FLUSH);
+		q->prepare_flush_fn = scsi_prepare_flush_fn;
+		q->end_flush_fn = scsi_end_flush_fn;
+	}
+
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	return q;
@@ -1886,3 +1967,55 @@ scsi_internal_device_unblock(struct scsi
 	return 0;
 }
 EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
+
+static void
+device_block(struct scsi_device *sdev, void *data)
+{
+	scsi_internal_device_block(sdev);
+}
+
+static int
+target_block(struct device *dev, void *data)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_block);
+	return 0;
+}
+
+void
+scsi_target_block(struct device *dev)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_block);
+	else
+		device_for_each_child(dev, NULL, target_block);
+}
+EXPORT_SYMBOL_GPL(scsi_target_block);
+
+static void
+device_unblock(struct scsi_device *sdev, void *data)
+{
+	scsi_internal_device_unblock(sdev);
+}
+
+static int
+target_unblock(struct device *dev, void *data)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_unblock);
+	return 0;
+}
+
+void
+scsi_target_unblock(struct device *dev)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_unblock);
+	else
+		device_for_each_child(dev, NULL, target_unblock);
+}
+EXPORT_SYMBOL_GPL(scsi_target_unblock);
diff --git a/drivers/scsi/scsi_obsolete.h b/drivers/scsi/scsi_obsolete.h
deleted file mode 100644
--- a/drivers/scsi/scsi_obsolete.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *  scsi_obsolete.h Copyright (C) 1997 Eric Youngdale
- *
- */
-
-#ifndef _SCSI_OBSOLETE_H
-#define _SCSI_OBSOLETE_H
-
-/*
- * These are the return codes for the abort and reset functions.  The mid-level
- * code uses these to decide what to do next.  Each of the low level abort
- * and reset functions must correctly indicate what it has done.
- * The descriptions are written from the point of view of the mid-level code,
- * so that the return code is telling the mid-level drivers exactly what
- * the low level driver has already done, and what remains to be done.
- */
-
-/* We did not do anything.  
- * Wait some more for this command to complete, and if this does not work, 
- * try something more serious. */
-#define SCSI_ABORT_SNOOZE 0
-
-/* This means that we were able to abort the command.  We have already
- * called the mid-level done function, and do not expect an interrupt that 
- * will lead to another call to the mid-level done function for this command */
-#define SCSI_ABORT_SUCCESS 1
-
-/* We called for an abort of this command, and we should get an interrupt 
- * when this succeeds.  Thus we should not restore the timer for this
- * command in the mid-level abort function. */
-#define SCSI_ABORT_PENDING 2
-
-/* Unable to abort - command is currently on the bus.  Grin and bear it. */
-#define SCSI_ABORT_BUSY 3
-
-/* The command is not active in the low level code. Command probably
- * finished. */
-#define SCSI_ABORT_NOT_RUNNING 4
-
-/* Something went wrong.  The low level driver will indicate the correct
- * error condition when it calls scsi_done, so the mid-level abort function
- * can simply wait until this comes through */
-#define SCSI_ABORT_ERROR 5
-
-/* We do not know how to reset the bus, or we do not want to.  Bummer.
- * Anyway, just wait a little more for the command in question, and hope that
- * it eventually finishes.  If it never finishes, the SCSI device could
- * hang, so use this with caution. */
-#define SCSI_RESET_SNOOZE 0
-
-/* We do not know how to reset the bus, or we do not want to.  Bummer.
- * We have given up on this ever completing.  The mid-level code will
- * request sense information to decide how to proceed from here. */
-#define SCSI_RESET_PUNT 1
-
-/* This means that we were able to reset the bus.  We have restarted all of
- * the commands that should be restarted, and we should be able to continue
- * on normally from here.  We do not expect any interrupts that will return
- * DID_RESET to any of the other commands in the host_queue, and the mid-level
- * code does not need to do anything special to keep the commands alive. 
- * If a hard reset was performed then all outstanding commands on the
- * bus have been restarted. */
-#define SCSI_RESET_SUCCESS 2
-
-/* We called for a reset of this bus, and we should get an interrupt 
- * when this succeeds.  Each command should get its own status
- * passed up to scsi_done, but this has not happened yet. 
- * If a hard reset was performed, then we expect an interrupt
- * for *each* of the outstanding commands that will have the
- * effect of restarting the commands.
- */
-#define SCSI_RESET_PENDING 3
-
-/* We did a reset, but do not expect an interrupt to signal DID_RESET.
- * This tells the upper level code to request the sense info, and this
- * should keep the command alive. */
-#define SCSI_RESET_WAKEUP 4
-
-/* The command is not active in the low level code. Command probably
-   finished. */
-#define SCSI_RESET_NOT_RUNNING 5
-
-/* Something went wrong, and we do not know how to fix it. */
-#define SCSI_RESET_ERROR 6
-
-#define SCSI_RESET_SYNCHRONOUS		0x01
-#define SCSI_RESET_ASYNCHRONOUS		0x02
-#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
-#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a hard reset.
- */
-#define SCSI_RESET_BUS_RESET 0x100
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a host adapter reset.
- */
-#define SCSI_RESET_HOST_RESET 0x200
-/*
- * Used to mask off bits and to obtain the basic action that was
- * performed.  
- */
-#define SCSI_RESET_ACTION   0xff
-
-#endif				/* SCSI_OBSOLETE_H */
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -30,11 +30,6 @@ struct Scsi_Host;
 #define SCSI_REQ_MAGIC		0x75F6D354
 
 /*
- *  Flag bit for the internal_timeout array
- */
-#define NORMAL_TIMEOUT		0
-
-/*
  * Scsi Error Handler Flags
  */
 #define scsi_eh_eflags_chk(scp, flags) \
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -200,12 +200,12 @@ static void print_inquiry(unsigned char 
  * Return value:
  *     scsi_Device pointer, or NULL on failure.
  **/
-static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
-	       	uint channel, uint id, uint lun, void *hostdata)
+static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
+					   unsigned int lun, void *hostdata)
 {
 	struct scsi_device *sdev;
-	unsigned long flags;
 	int display_failure_msg = 1, ret;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
 	sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
 		       GFP_ATOMIC);
@@ -217,9 +217,9 @@ static struct scsi_device *scsi_alloc_sd
 	sdev->model = scsi_null_device_strs;
 	sdev->rev = scsi_null_device_strs;
 	sdev->host = shost;
-	sdev->id = id;
+	sdev->id = starget->id;
 	sdev->lun = lun;
-	sdev->channel = channel;
+	sdev->channel = starget->channel;
 	sdev->sdev_state = SDEV_CREATED;
 	INIT_LIST_HEAD(&sdev->siblings);
 	INIT_LIST_HEAD(&sdev->same_target_siblings);
@@ -227,6 +227,9 @@ static struct scsi_device *scsi_alloc_sd
 	INIT_LIST_HEAD(&sdev->starved_entry);
 	spin_lock_init(&sdev->list_lock);
 
+	sdev->sdev_gendev.parent = get_device(&starget->dev);
+	sdev->sdev_target = starget;
+
 	/* usually NULL and set by ->slave_alloc instead */
 	sdev->hostdata = hostdata;
 
@@ -246,10 +249,13 @@ static struct scsi_device *scsi_alloc_sd
 	 */
 	sdev->borken = 1;
 
-	spin_lock_init(&sdev->sdev_lock);
 	sdev->request_queue = scsi_alloc_queue(sdev);
-	if (!sdev->request_queue)
-		goto out_free_dev;
+	if (!sdev->request_queue) {
+		/* release fn is set up in scsi_sysfs_device_initialise, so
+		 * have to free and put manually here */
+		put_device(&starget->dev);
+		goto out;
+	}
 
 	sdev->request_queue->queuedata = sdev;
 	scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
@@ -262,6 +268,8 @@ static struct scsi_device *scsi_alloc_sd
 			/*
 			 * if LLDD reports slave not present, don't clutter
 			 * console with alloc failure messages
+
+
 			 */
 			if (ret == -ENXIO)
 				display_failure_msg = 0;
@@ -269,32 +277,128 @@ static struct scsi_device *scsi_alloc_sd
 		}
 	}
 
-	/* NOTE: this target initialisation code depends critically on
-	 * lun scanning being sequential. */
-	if (scsi_sysfs_target_initialize(sdev))
-		goto out_remove_siblings;
-
 	return sdev;
 
-out_remove_siblings:
-	spin_lock_irqsave(shost->host_lock, flags);
-	list_del(&sdev->siblings);
-	list_del(&sdev->same_target_siblings);
-	spin_unlock_irqrestore(shost->host_lock, flags);
-
-	if (shost->hostt->slave_destroy)
-		shost->hostt->slave_destroy(sdev);
 out_device_destroy:
 	transport_destroy_device(&sdev->sdev_gendev);
 	scsi_free_queue(sdev->request_queue);
-out_free_dev:
-	kfree(sdev);
+	put_device(&sdev->sdev_gendev);
 out:
 	if (display_failure_msg)
 		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
 	return NULL;
 }
 
+static void scsi_target_dev_release(struct device *dev)
+{
+	struct device *parent = dev->parent;
+	struct scsi_target *starget = to_scsi_target(dev);
+	kfree(starget);
+	put_device(parent);
+}
+
+int scsi_is_target_device(const struct device *dev)
+{
+	return dev->release == scsi_target_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_target_device);
+
+static struct scsi_target *__scsi_find_target(struct device *parent,
+					      int channel, uint id)
+{
+	struct scsi_target *starget, *found_starget = NULL;
+	struct Scsi_Host *shost = dev_to_shost(parent);
+	/*
+	 * Search for an existing target for this sdev.
+	 */
+	list_for_each_entry(starget, &shost->__targets, siblings) {
+		if (starget->id == id &&
+		    starget->channel == channel) {
+			found_starget = starget;
+			break;
+		}
+	}
+	if (found_starget)
+		get_device(&found_starget->dev);
+
+	return found_starget;
+}
+
+static struct scsi_target *scsi_alloc_target(struct device *parent,
+					     int channel, uint id)
+{
+	struct Scsi_Host *shost = dev_to_shost(parent);
+	struct device *dev = NULL;
+	unsigned long flags;
+	const int size = sizeof(struct scsi_target)
+		+ shost->transportt->target_size;
+	struct scsi_target *starget = kmalloc(size, GFP_ATOMIC);
+	struct scsi_target *found_target;
+
+	if (!starget) {
+		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		return NULL;
+	}
+	memset(starget, 0, size);
+	dev = &starget->dev;
+	device_initialize(dev);
+	starget->reap_ref = 1;
+	dev->parent = get_device(parent);
+	dev->release = scsi_target_dev_release;
+	sprintf(dev->bus_id, "target%d:%d:%d",
+		shost->host_no, channel, id);
+	starget->id = id;
+	starget->channel = channel;
+	INIT_LIST_HEAD(&starget->siblings);
+	INIT_LIST_HEAD(&starget->devices);
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	found_target = __scsi_find_target(parent, channel, id);
+	if (found_target)
+		goto found;
+
+	list_add_tail(&starget->siblings, &shost->__targets);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	/* allocate and add */
+	transport_setup_device(&starget->dev);
+	device_add(&starget->dev);
+	transport_add_device(&starget->dev);
+	return starget;
+
+ found:
+	found_target->reap_ref++;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(parent);
+	kfree(starget);
+	return found_target;
+}
+
+/**
+ * scsi_target_reap - check to see if target is in use and destroy if not
+ *
+ * @starget: target to be checked
+ *
+ * This is used after removing a LUN or doing a last put of the target
+ * it checks atomically that nothing is using the target and removes
+ * it if so.
+ */
+void scsi_target_reap(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
+		list_del_init(&starget->siblings);
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		device_del(&starget->dev);
+		transport_unregister_device(&starget->dev);
+		put_device(&starget->dev);
+		return;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
 /**
  * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
  * @sreq:	used to send the INQUIRY
@@ -620,6 +724,9 @@ static int scsi_add_lun(struct scsi_devi
 	if (*bflags & BLIST_NOT_LOCKABLE)
 		sdev->lockable = 0;
 
+	if (*bflags & BLIST_RETRY_HWERROR)
+		sdev->retry_hwerror = 1;
+
 	transport_configure_device(&sdev->sdev_gendev);
 
 	if (sdev->host->hostt->slave_configure)
@@ -637,6 +744,8 @@ static int scsi_add_lun(struct scsi_devi
 
 /**
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
+ * @starget:	pointer to target device structure
+ * @lun:	LUN of target device
  * @sdevscan:	probe the LUN corresponding to this Scsi_Device
  * @sdevnew:	store the value of any new Scsi_Device allocated
  * @bflagsp:	store bflags here if not NULL
@@ -651,45 +760,48 @@ static int scsi_add_lun(struct scsi_devi
  *         attached at the LUN
  *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
  **/
-static int scsi_probe_and_add_lun(struct Scsi_Host *host,
-		uint channel, uint id, uint lun, int *bflagsp,
-		struct scsi_device **sdevp, int rescan, void *hostdata)
+static int scsi_probe_and_add_lun(struct scsi_target *starget,
+				  uint lun, int *bflagsp,
+				  struct scsi_device **sdevp, int rescan,
+				  void *hostdata)
 {
 	struct scsi_device *sdev;
 	struct scsi_request *sreq;
 	unsigned char *result;
 	int bflags, res = SCSI_SCAN_NO_RESPONSE;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
 	/*
 	 * The rescan flag is used as an optimization, the first scan of a
 	 * host adapter calls into here with rescan == 0.
 	 */
 	if (rescan) {
-		sdev = scsi_device_lookup(host, channel, id, lun);
+		sdev = scsi_device_lookup_by_target(starget, lun);
 		if (sdev) {
 			SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
-				"scsi scan: device exists on <%d:%d:%d:%d>\n",
-				host->host_no, channel, id, lun));
+				"scsi scan: device exists on %s\n",
+				sdev->sdev_gendev.bus_id));
 			if (sdevp)
 				*sdevp = sdev;
+			else
+				scsi_device_put(sdev);
+
 			if (bflagsp)
 				*bflagsp = scsi_get_device_flags(sdev,
 								 sdev->vendor,
 								 sdev->model);
-			/* XXX: bandaid until callers do refcounting */
-			scsi_device_put(sdev);
 			return SCSI_SCAN_LUN_PRESENT;
 		}
 	}
 
-	sdev = scsi_alloc_sdev(host, channel, id, lun, hostdata);
+	sdev = scsi_alloc_sdev(starget, lun, hostdata);
 	if (!sdev)
 		goto out;
 	sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
 	if (!sreq)
 		goto out_free_sdev;
 	result = kmalloc(256, GFP_ATOMIC |
-			(host->unchecked_isa_dma) ? __GFP_DMA : 0);
+			((shost->unchecked_isa_dma) ? __GFP_DMA : 0));
 	if (!result)
 		goto out_free_sreq;
 
@@ -734,8 +846,10 @@ static int scsi_probe_and_add_lun(struct
 	scsi_release_request(sreq);
  out_free_sdev:
 	if (res == SCSI_SCAN_LUN_PRESENT) {
-		if (sdevp)
+		if (sdevp) {
+			scsi_device_get(sdev);
 			*sdevp = sdev;
+		}
 	} else {
 		if (sdev->host->hostt->slave_destroy)
 			sdev->host->hostt->slave_destroy(sdev);
@@ -748,7 +862,7 @@ static int scsi_probe_and_add_lun(struct
 
 /**
  * scsi_sequential_lun_scan - sequentially scan a SCSI target
- * @sdevscan:	scan the host, channel, and id of this Scsi_Device
+ * @starget:	pointer to target structure to scan
  * @bflags:	black/white list flag for LUN 0
  * @lun0_res:	result of scanning LUN 0
  *
@@ -759,14 +873,15 @@ static int scsi_probe_and_add_lun(struct
  *
  *     Modifies sdevscan->lun.
  **/
-static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
-		uint id, int bflags, int lun0_res, int scsi_level, int rescan)
+static void scsi_sequential_lun_scan(struct scsi_target *starget,
+				     int bflags, int lun0_res, int scsi_level,
+				     int rescan)
 {
 	unsigned int sparse_lun, lun, max_dev_lun;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
 	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of"
-			" host %d channel %d id %d\n", shost->host_no,
-			channel, id));
+				    "%s\n", starget->dev.bus_id));
 
 	max_dev_lun = min(max_scsi_luns, shost->max_lun);
 	/*
@@ -828,8 +943,8 @@ static void scsi_sequential_lun_scan(str
 	 * sparse_lun.
 	 */
 	for (lun = 1; lun < max_dev_lun; ++lun)
-		if ((scsi_probe_and_add_lun(shost, channel, id, lun,
-		      NULL, NULL, rescan, NULL) != SCSI_SCAN_LUN_PRESENT) &&
+		if ((scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan,
+					    NULL) != SCSI_SCAN_LUN_PRESENT) &&
 		    !sparse_lun)
 			return;
 }
@@ -893,6 +1008,7 @@ static int scsi_report_lun_scan(struct s
 	struct scsi_request *sreq;
 	u8 *data;
 	struct scsi_sense_hdr sshdr;
+	struct scsi_target *starget = scsi_target(sdev);
 
 	/*
 	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
@@ -1043,8 +1159,8 @@ static int scsi_report_lun_scan(struct s
 		} else {
 			int res;
 
-			res = scsi_probe_and_add_lun(sdev->host, sdev->channel,
-				sdev->id, lun, NULL, NULL, rescan, NULL);
+			res = scsi_probe_and_add_lun(starget,
+				lun, NULL, NULL, rescan, NULL);
 			if (res == SCSI_SCAN_NO_RESPONSE) {
 				/*
 				 * Got some results, but now none, abort.
@@ -1071,17 +1187,24 @@ static int scsi_report_lun_scan(struct s
 }
 
 struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
-		uint id, uint lun, void *hostdata)
+				      uint id, uint lun, void *hostdata)
 {
 	struct scsi_device *sdev;
+	struct device *parent = &shost->shost_gendev;
 	int res;
+	struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
 
+	if (!starget)
+		return ERR_PTR(-ENOMEM);
+
+	get_device(&starget->dev);
 	down(&shost->scan_mutex);
-	res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL,
-				     &sdev, 1, hostdata);
+	res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
 	if (res != SCSI_SCAN_LUN_PRESENT)
 		sdev = ERR_PTR(-ENODEV);
 	up(&shost->scan_mutex);
+	scsi_target_reap(starget);
+	put_device(&starget->dev);
 
 	return sdev;
 }
@@ -1122,12 +1245,14 @@ EXPORT_SYMBOL(scsi_rescan_device);
  *     First try a REPORT LUN scan, if that does not scan the target, do a
  *     sequential scan of LUNs on the target id.
  **/
-static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
-			     unsigned int id, unsigned int lun, int rescan)
+void scsi_scan_target(struct device *parent, unsigned int channel,
+		      unsigned int id, unsigned int lun, int rescan)
 {
+	struct Scsi_Host *shost = dev_to_shost(parent);
 	int bflags = 0;
 	int res;
-	struct scsi_device *sdev;
+	struct scsi_device *sdev = NULL;
+	struct scsi_target *starget;
 
 	if (shost->this_id == id)
 		/*
@@ -1135,28 +1260,33 @@ static void scsi_scan_target(struct Scsi
 		 */
 		return;
 
+
+	starget = scsi_alloc_target(parent, channel, id);
+
+	if (!starget)
+		return;
+
+	get_device(&starget->dev);
 	if (lun != SCAN_WILD_CARD) {
 		/*
 		 * Scan for a specific host/chan/id/lun.
 		 */
-		scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL,
-				       rescan, NULL);
-		return;
+		scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan, NULL);
+		goto out_reap;
 	}
 
 	/*
 	 * Scan LUN 0, if there is some response, scan further. Ideally, we
 	 * would not configure LUN 0 until all LUNs are scanned.
 	 */
-	res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev,
-				     rescan, NULL);
+	res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL);
 	if (res == SCSI_SCAN_LUN_PRESENT) {
 		if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
 			/*
 			 * The REPORT LUN did not scan the target,
 			 * do a sequential scan.
 			 */
-			scsi_sequential_lun_scan(shost, channel, id, bflags,
+			scsi_sequential_lun_scan(starget, bflags,
 				       	res, sdev->scsi_level, rescan);
 	} else if (res == SCSI_SCAN_TARGET_PRESENT) {
 		/*
@@ -1165,10 +1295,20 @@ static void scsi_scan_target(struct Scsi
 		 * sequential lun scan with a bflags of SPARSELUN and
 		 * a default scsi level of SCSI_2
 		 */
-		scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN,
+		scsi_sequential_lun_scan(starget, BLIST_SPARSELUN,
 				SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
 	}
+	if (sdev)
+		scsi_device_put(sdev);
+
+ out_reap:
+	/* now determine if the target has any children at all
+	 * and if not, nuke it */
+	scsi_target_reap(starget);
+
+	put_device(&starget->dev);
 }
+EXPORT_SYMBOL(scsi_scan_target);
 
 static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
 			      unsigned int id, unsigned int lun, int rescan)
@@ -1193,10 +1333,10 @@ static void scsi_scan_channel(struct Scs
 				order_id = shost->max_id - id - 1;
 			else
 				order_id = id;
-			scsi_scan_target(shost, channel, order_id, lun, rescan);
+			scsi_scan_target(&shost->shost_gendev, channel, order_id, lun, rescan);
 		}
 	else
-		scsi_scan_target(shost, channel, id, lun, rescan);
+		scsi_scan_target(&shost->shost_gendev, channel, id, lun, rescan);
 }
 
 int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
@@ -1247,7 +1387,7 @@ EXPORT_SYMBOL(scsi_scan_single_target);
 
 void scsi_forget_host(struct Scsi_Host *shost)
 {
-	struct scsi_device *sdev, *tmp;
+	struct scsi_target *starget, *tmp;
 	unsigned long flags;
 
 	/*
@@ -1260,9 +1400,9 @@ void scsi_forget_host(struct Scsi_Host *
 	 * after that we don't look at sdev anymore.
 	 */
 	spin_lock_irqsave(shost->host_lock, flags);
-	list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
+	list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
 		spin_unlock_irqrestore(shost->host_lock, flags);
-		scsi_remove_device(sdev);
+		scsi_remove_target(&starget->dev);
 		spin_lock_irqsave(shost->host_lock, flags);
 	}
 	spin_unlock_irqrestore(shost->host_lock, flags);
@@ -1291,11 +1431,18 @@ void scsi_forget_host(struct Scsi_Host *
 struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
 {
 	struct scsi_device *sdev;
+	struct scsi_target *starget;
+
+	starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
+	if (!starget)
+		return NULL;
 
-	sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0, NULL);
+	sdev = scsi_alloc_sdev(starget, 0, NULL);
 	if (sdev) {
+		sdev->sdev_gendev.parent = get_device(&starget->dev);
 		sdev->borken = 0;
 	}
+	put_device(&starget->dev);
 	return sdev;
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -154,32 +154,29 @@ void scsi_device_dev_release(struct devi
 {
 	struct scsi_device *sdev;
 	struct device *parent;
+	struct scsi_target *starget;
 	unsigned long flags;
-	int delete;
 
 	parent = dev->parent;
 	sdev = to_scsi_device(dev);
+	starget = to_scsi_target(parent);
 
 	spin_lock_irqsave(sdev->host->host_lock, flags);
-	/* If we're the last LUN on the target, destroy the target */
-	delete = list_empty(&sdev->same_target_siblings);
+	starget->reap_ref++;
 	list_del(&sdev->siblings);
 	list_del(&sdev->same_target_siblings);
 	list_del(&sdev->starved_entry);
 	spin_unlock_irqrestore(sdev->host->host_lock, flags);
 
-	if (delete) {
-		struct scsi_target *starget = to_scsi_target(parent);
-		if (!starget->create) {
-			transport_remove_device(&starget->dev);
-			device_del(parent);
-		}
-		transport_destroy_device(&starget->dev);
-
-		put_device(parent);
-	}
-	if (sdev->request_queue)
+	if (sdev->request_queue) {
+		sdev->request_queue->queuedata = NULL;
 		scsi_free_queue(sdev->request_queue);
+		/* temporary expedient, try to catch use of queue lock
+		 * after free of sdev */
+		sdev->request_queue = NULL;
+	}
+
+	scsi_target_reap(scsi_target(sdev));
 
 	kfree(sdev->inquiry);
 	kfree(sdev);
@@ -408,6 +405,28 @@ show_queue_type_field(struct device *dev
 
 static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
 
+static ssize_t
+show_iostat_counterbits(struct device *dev, char *buf)
+{
+	return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
+}
+
+static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL);
+
+#define show_sdev_iostat(field)						\
+static ssize_t								\
+show_iostat_##field(struct device *dev, char *buf)			\
+{									\
+	struct scsi_device *sdev = to_scsi_device(dev);			\
+	unsigned long long count = atomic_read(&sdev->field);		\
+	return snprintf(buf, 20, "0x%llx\n", count);			\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL)
+
+show_sdev_iostat(iorequest_cnt);
+show_sdev_iostat(iodone_cnt);
+show_sdev_iostat(ioerr_cnt);
+
 
 /* Default template for device attributes.  May NOT be modified */
 static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -423,6 +442,10 @@ static struct device_attribute *scsi_sys
 	&dev_attr_delete,
 	&dev_attr_state,
 	&dev_attr_timeout,
+	&dev_attr_iocounterbits,
+	&dev_attr_iorequest_cnt,
+	&dev_attr_iodone_cnt,
+	&dev_attr_ioerr_cnt,
 	NULL
 };
 
@@ -534,14 +557,6 @@ static int attr_add(struct device *dev, 
 	return device_create_file(dev, attr);
 }
 
-static void scsi_target_dev_release(struct device *dev)
-{
-	struct scsi_target *starget = to_scsi_target(dev);
-	struct device *parent = dev->parent;
-	kfree(starget);
-	put_device(parent);
-}
-
 /**
  * scsi_sysfs_add_sdev - add scsi device to sysfs
  * @sdev:	scsi_device to add
@@ -551,24 +566,7 @@ static void scsi_target_dev_release(stru
  **/
 int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
-	struct scsi_target *starget = sdev->sdev_target;
-	struct Scsi_Host *shost = sdev->host;
-	int error, i, create;
-	unsigned long flags;
-
-	spin_lock_irqsave(shost->host_lock, flags);
-	create = starget->create;
-	starget->create = 0;
-	spin_unlock_irqrestore(shost->host_lock, flags);
-
-	if (create) {
-		error = device_add(&starget->dev);
-		if (error) {
-			printk(KERN_ERR "Target device_add failed\n");
-			return error;
-		}
-		transport_add_device(&starget->dev);
-	}
+	int error, i;
 
 	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
 		return error;
@@ -617,7 +615,6 @@ int scsi_sysfs_add_sdev(struct scsi_devi
  out:
 	return error;
 
-	class_device_del(&sdev->sdev_classdev);
  clean_device:
 	scsi_device_set_state(sdev, SDEV_CANCEL);
 
@@ -647,12 +644,57 @@ void scsi_remove_device(struct scsi_devi
 		sdev->host->hostt->slave_destroy(sdev);
 	transport_unregister_device(&sdev->sdev_gendev);
 	put_device(&sdev->sdev_gendev);
-
 out:
 	up(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
+void __scsi_remove_target(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+	struct scsi_device *sdev, *tmp;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	starget->reap_ref++;
+	list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
+		if (sdev->channel != starget->channel ||
+		    sdev->id != starget->id)
+			continue;
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		scsi_remove_device(sdev);
+		spin_lock_irqsave(shost->host_lock, flags);
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	scsi_target_reap(starget);
+}
+
+/**
+ * scsi_remove_target - try to remove a target and all its devices
+ * @dev: generic starget or parent of generic stargets to be removed
+ *
+ * Note: This is slightly racy.  It is possible that if the user
+ * requests the addition of another device then the target won't be
+ * removed.
+ */
+void scsi_remove_target(struct device *dev)
+{
+	struct device *rdev, *idev, *next;
+
+	if (scsi_is_target_device(dev)) {
+		__scsi_remove_target(to_scsi_target(dev));
+		return;
+	}
+
+	rdev = get_device(dev);
+	list_for_each_entry_safe(idev, next, &dev->children, node) {
+		if (scsi_is_target_device(idev))
+			__scsi_remove_target(to_scsi_target(idev));
+	}
+	put_device(rdev);
+}
+EXPORT_SYMBOL(scsi_remove_target);
+
 int scsi_register_driver(struct device_driver *drv)
 {
 	drv->bus = &scsi_bus_type;
@@ -741,6 +783,10 @@ int scsi_sysfs_add_host(struct Scsi_Host
 
 void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 {
+	unsigned long flags;
+	struct Scsi_Host *shost = sdev->host;
+	struct scsi_target  *starget = sdev->sdev_target;
+
 	device_initialize(&sdev->sdev_gendev);
 	sdev->sdev_gendev.bus = &scsi_bus_type;
 	sdev->sdev_gendev.release = scsi_device_dev_release;
@@ -754,83 +800,20 @@ void scsi_sysfs_device_initialize(struct
 	snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
 		 "%d:%d:%d:%d", sdev->host->host_no,
 		 sdev->channel, sdev->id, sdev->lun);
-
+	sdev->scsi_level = SCSI_2;
 	transport_setup_device(&sdev->sdev_gendev);
-}
-
-int scsi_is_sdev_device(const struct device *dev)
-{
-	return dev->release == scsi_device_dev_release;
-}
-EXPORT_SYMBOL(scsi_is_sdev_device);
-
-int scsi_sysfs_target_initialize(struct scsi_device *sdev)
-{
-	struct scsi_target *starget = NULL;
-	struct Scsi_Host *shost = sdev->host;
-	struct scsi_device *device;
-	struct device *dev = NULL;
-	unsigned long flags;
-	int create = 0;
-
 	spin_lock_irqsave(shost->host_lock, flags);
-	/*
-	 * Search for an existing target for this sdev.
-	 */
-	list_for_each_entry(device, &shost->__devices, siblings) {
-		if (device->id == sdev->id &&
-		    device->channel == sdev->channel) {
-			list_add_tail(&sdev->same_target_siblings,
-				      &device->same_target_siblings);
-			sdev->scsi_level = device->scsi_level;
-			starget = device->sdev_target;
-			break;
-		}
-	}
-			
-	if (!starget) {
-		const int size = sizeof(*starget) +
-			shost->transportt->target_size;
-		starget = kmalloc(size, GFP_ATOMIC);
-		if (!starget) {
-			printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
-			spin_unlock_irqrestore(shost->host_lock,
-					       flags);
-			return -ENOMEM;
-		}
-		memset(starget, 0, size);
-		dev = &starget->dev;
-		device_initialize(dev);
-		dev->parent = get_device(&shost->shost_gendev);
-		dev->release = scsi_target_dev_release;
-		sprintf(dev->bus_id, "target%d:%d:%d",
-			shost->host_no, sdev->channel, sdev->id);
-		starget->id = sdev->id;
-		starget->channel = sdev->channel;
-		create = starget->create = 1;
-		/*
-		 * If there wasn't another lun already configured at
-		 * this target, then default this device to SCSI_2
-		 * until we know better
-		 */
-		sdev->scsi_level = SCSI_2;
-	}
-	get_device(&starget->dev);
-	sdev->sdev_gendev.parent = &starget->dev;
-	sdev->sdev_target = starget;
+	list_add_tail(&sdev->same_target_siblings, &starget->devices);
 	list_add_tail(&sdev->siblings, &shost->__devices);
 	spin_unlock_irqrestore(shost->host_lock, flags);
-	if (create)
-		transport_setup_device(&starget->dev);
-	return 0;
 }
 
-int scsi_is_target_device(const struct device *dev)
+int scsi_is_sdev_device(const struct device *dev)
 {
-	return dev->release == scsi_target_dev_release;
+	return dev->release == scsi_device_dev_release;
 }
-EXPORT_SYMBOL(scsi_is_target_device);
+EXPORT_SYMBOL(scsi_is_sdev_device);
 
 /* A blank transport template that is used in drivers that don't
  * yet implement Transport Attributes */
-struct scsi_transport_template blank_transport_template = { NULL, };
+struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, };
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -16,6 +16,13 @@
  *  You 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) 2004-2005   James Smart, Emulex Corporation
+ *    Rewrite for host, target, device, and remote port attributes,
+ *    statistics, and service functions...
+ *
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -90,8 +97,10 @@ static struct {
 	char			*name;
 } fc_port_state_names[] = {
 	{ FC_PORTSTATE_UNKNOWN,		"Unknown" },
+	{ FC_PORTSTATE_NOTPRESENT,	"Not Present" },
 	{ FC_PORTSTATE_ONLINE,		"Online" },
 	{ FC_PORTSTATE_OFFLINE,		"Offline" },
+	{ FC_PORTSTATE_BLOCKED,		"Blocked" },
 	{ FC_PORTSTATE_BYPASSED,	"Bypassed" },
 	{ FC_PORTSTATE_DIAGNOSTICS,	"Diagnostics" },
 	{ FC_PORTSTATE_LINKDOWN,	"Linkdown" },
@@ -108,9 +117,10 @@ static struct {
 	char				*name;
 	int				matchlen;
 } fc_tgtid_binding_type_names[] = {
+	{ FC_TGTID_BIND_NONE, "none", 4 },
 	{ FC_TGTID_BIND_BY_WWPN, "wwpn (World Wide Port Name)", 4 },
 	{ FC_TGTID_BIND_BY_WWNN, "wwnn (World Wide Node Name)", 4 },
-	{ FC_TGTID_BIND_BY_ID, "fcportid (FC Address)", 8 },
+	{ FC_TGTID_BIND_BY_ID, "port_id (FC Address)", 7 },
 };
 fc_enum_name_search(tgtid_bind_type, fc_tgtid_binding_type,
 		fc_tgtid_binding_type_names)
@@ -139,7 +149,7 @@ get_fc_##title##_names(u32 table_key, ch
 }
 
 
-/* Convert fc_cos bit values to ascii string name */
+/* Convert FC_COS bit values to ascii string name */
 static struct {
 	u32 			value;
 	char			*name;
@@ -153,7 +163,7 @@ static struct {
 fc_bitfield_name_search(cos, fc_cos_names)
 
 
-/* Convert fc_port_speed bit values to ascii string name */
+/* Convert FC_PORTSPEED bit values to ascii string name */
 static struct {
 	u32 			value;
 	char			*name;
@@ -179,67 +189,102 @@ show_fc_fc4s (char *buf, u8 *fc4_list)
 }
 
 
+/* Convert FC_RPORT_ROLE bit values to ascii string name */
+static struct {
+	u32 			value;
+	char			*name;
+} fc_remote_port_role_names[] = {
+	{ FC_RPORT_ROLE_FCP_TARGET,	"FCP Target" },
+	{ FC_RPORT_ROLE_FCP_INITIATOR,	"FCP Initiator" },
+	{ FC_RPORT_ROLE_IP_PORT,	"IP Port" },
+};
+fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
 
-static void fc_timeout_blocked_host(void *data);
-static void fc_timeout_blocked_tgt(void *data);
+/*
+ * Define roles that are specific to port_id. Values are relative to ROLE_MASK.
+ */
+#define FC_WELLKNOWN_PORTID_MASK	0xfffff0
+#define FC_WELLKNOWN_ROLE_MASK  	0x00000f
+#define FC_FPORT_PORTID			0x00000e
+#define FC_FABCTLR_PORTID		0x00000d
+#define FC_DIRSRVR_PORTID		0x00000c
+#define FC_TIMESRVR_PORTID		0x00000b
+#define FC_MGMTSRVR_PORTID		0x00000a
 
-#define FC_STARGET_NUM_ATTRS 	4	/* increase this if you add attributes */
-#define FC_STARGET_OTHER_ATTRS 	0	/* increase this if you add "always on"
-					 * attributes */
+
+static void fc_timeout_blocked_rport(void *data);
+static void fc_scsi_scan_rport(void *data);
+static void fc_rport_terminate(struct fc_rport  *rport);
+
+/*
+ * Attribute counts pre object type...
+ * Increase these values if you add attributes
+ */
+#define FC_STARGET_NUM_ATTRS 	3
+#define FC_RPORT_NUM_ATTRS	9
 #define FC_HOST_NUM_ATTRS	15
 
 struct fc_internal {
 	struct scsi_transport_template t;
 	struct fc_function_template *f;
-	/* The actual attributes */
+
+	/*
+	 * For attributes : each object has :
+	 *   An array of the actual attributes structures
+	 *   An array of null-terminated pointers to the attribute
+	 *     structures - used for mid-layer interaction.
+	 *
+	 * The attribute containers for the starget and host are are
+	 * part of the midlayer. As the remote port is specific to the
+	 * fc transport, we must provide the attribute container.
+	 */
 	struct class_device_attribute private_starget_attrs[
-						FC_STARGET_NUM_ATTRS];
-	/* The array of null terminated pointers to attributes
-	 * needed by scsi_sysfs.c */
-	struct class_device_attribute *starget_attrs[
-			FC_STARGET_NUM_ATTRS + FC_STARGET_OTHER_ATTRS + 1];
+							FC_STARGET_NUM_ATTRS];
+	struct class_device_attribute *starget_attrs[FC_STARGET_NUM_ATTRS + 1];
 
 	struct class_device_attribute private_host_attrs[FC_HOST_NUM_ATTRS];
 	struct class_device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1];
+
+	struct transport_container rport_attr_cont;
+	struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS];
+	struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1];
 };
 
 #define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t)
 
-static int fc_add_target(struct device *dev)
+static int fc_target_setup(struct device *dev)
 {
 	struct scsi_target *starget = to_scsi_target(dev);
-	/* 
-	 * Set default values easily detected by the midlayer as
-	 * failure cases.  The scsi lldd is responsible for initializing
-	 * all transport attributes to valid values per target.
+	struct fc_rport *rport = starget_to_rport(starget);
+
+	/*
+	 * if parent is remote port, use values from remote port.
+	 * Otherwise, this host uses the fc_transport, but not the
+	 * remote port interface. As such, initialize to known non-values.
 	 */
-	fc_starget_node_name(starget) = -1;
-	fc_starget_port_name(starget) = -1;
-	fc_starget_port_id(starget) = -1;
-	fc_starget_dev_loss_tmo(starget) = -1;
-	INIT_WORK(&fc_starget_dev_loss_work(starget),
-		  fc_timeout_blocked_tgt, starget);
-	return 0;
-}
+	if (rport) {
+		fc_starget_node_name(starget) = rport->node_name;
+		fc_starget_port_name(starget) = rport->port_name;
+		fc_starget_port_id(starget) = rport->port_id;
+	} else {
+		fc_starget_node_name(starget) = -1;
+		fc_starget_port_name(starget) = -1;
+		fc_starget_port_id(starget) = -1;
+	}
 
-static int fc_remove_target(struct device *dev)
-{
-	struct scsi_target *starget = to_scsi_target(dev);
-	/* Stop the target timer */
-	if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
-		flush_scheduled_work();
 	return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(fc_transport_class,
 			       "fc_transport",
-			       fc_add_target,
-			       fc_remove_target,
+			       fc_target_setup,
+			       NULL,
 			       NULL);
 
-static int fc_add_host(struct device *dev)
+static int fc_host_setup(struct device *dev)
 {
 	struct Scsi_Host *shost = dev_to_shost(dev);
+
 	/* 
 	 * Set default values easily detected by the midlayer as
 	 * failure cases.  The scsi lldd is responsible for initializing
@@ -254,16 +299,8 @@ static int fc_add_host(struct device *de
 		sizeof(fc_host_symbolic_name(shost)));
 	fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN;
 	fc_host_maxframe_size(shost) = -1;
-	memset(fc_host_hardware_version(shost), 0,
-		sizeof(fc_host_hardware_version(shost)));
-	memset(fc_host_firmware_version(shost), 0,
-		sizeof(fc_host_firmware_version(shost)));
 	memset(fc_host_serial_number(shost), 0,
 		sizeof(fc_host_serial_number(shost)));
-	memset(fc_host_opt_rom_version(shost), 0,
-		sizeof(fc_host_opt_rom_version(shost)));
-	memset(fc_host_driver_version(shost), 0,
-		sizeof(fc_host_driver_version(shost)));
 
 	fc_host_port_id(shost) = -1;
 	fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
@@ -272,93 +309,279 @@ static int fc_add_host(struct device *de
 		sizeof(fc_host_active_fc4s(shost)));
 	fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 	fc_host_fabric_name(shost) = -1;
- 	fc_host_link_down_tmo(shost) = -1;
 
 	fc_host_tgtid_bind_type(shost) = FC_TGTID_BIND_BY_WWPN;
 
-	INIT_WORK(&fc_host_link_down_work(shost),
-		  fc_timeout_blocked_host, shost);
-	return 0;
-}
+	INIT_LIST_HEAD(&fc_host_rports(shost));
+	INIT_LIST_HEAD(&fc_host_rport_bindings(shost));
+	fc_host_next_rport_number(shost) = 0;
+	fc_host_next_target_id(shost) = 0;
 
-static int fc_remove_host(struct device *dev)
-{
-	struct Scsi_Host *shost = dev_to_shost(dev);
-	/* Stop the host timer */
-	if (cancel_delayed_work(&fc_host_link_down_work(shost)))
-		flush_scheduled_work();
 	return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(fc_host_class,
 			       "fc_host",
-			       fc_add_host,
-			       fc_remove_host,
+			       fc_host_setup,
+			       NULL,
 			       NULL);
 
+/*
+ * Setup and Remove actions for remote ports are handled
+ * in the service functions below.
+ */
+static DECLARE_TRANSPORT_CLASS(fc_rport_class,
+			       "fc_remote_ports",
+			       NULL,
+			       NULL,
+			       NULL);
+
+/*
+ * Module Parameters
+ */
+
+/*
+ * dev_loss_tmo: the default number of seconds that the FC transport
+ *   should insulate the loss of a remote port.
+ *   The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
+ */
+static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT;
+
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(dev_loss_tmo,
+		 "Maximum number of seconds that the FC transport should"
+		 " insulate the loss of a remote port. Once this value is"
+		 " exceeded, the scsi target is removed. Value should be"
+		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+
+
 static __init int fc_transport_init(void)
 {
 	int error = transport_class_register(&fc_host_class);
 	if (error)
 		return error;
+	error = transport_class_register(&fc_rport_class);
+	if (error)
+		return error;
 	return transport_class_register(&fc_transport_class);
 }
 
 static void __exit fc_transport_exit(void)
 {
 	transport_class_unregister(&fc_transport_class);
+	transport_class_unregister(&fc_rport_class);
 	transport_class_unregister(&fc_host_class);
 }
 
 /*
- * Remote Port (Target) Attribute Management
+ * FC Remote Port Attribute Management
  */
 
-#define fc_starget_show_function(field, format_string, cast)		\
+#define fc_rport_show_function(field, format_string, sz, cast)		\
 static ssize_t								\
-show_fc_starget_##field (struct class_device *cdev, char *buf)		\
+show_fc_rport_##field (struct class_device *cdev, char *buf)		\
 {									\
-	struct scsi_target *starget = transport_class_to_starget(cdev);	\
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	struct Scsi_Host *shost = rport_to_shost(rport);		\
 	struct fc_internal *i = to_fc_internal(shost->transportt);	\
-	if (i->f->get_starget_##field)					\
-		i->f->get_starget_##field(starget);			\
-	return snprintf(buf, 20, format_string, 			\
-		cast fc_starget_##field(starget)); 			\
+	if (i->f->get_rport_##field)					\
+		i->f->get_rport_##field(rport);				\
+	return snprintf(buf, sz, format_string, cast rport->field); 	\
 }
 
-#define fc_starget_store_function(field, format_string)			\
+#define fc_rport_store_function(field)					\
 static ssize_t								\
-store_fc_starget_##field(struct class_device *cdev, const char *buf,	\
+store_fc_rport_##field(struct class_device *cdev, const char *buf,	\
 			   size_t count)				\
 {									\
 	int val;							\
-	struct scsi_target *starget = transport_class_to_starget(cdev);	\
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	struct Scsi_Host *shost = rport_to_shost(rport);		\
 	struct fc_internal *i = to_fc_internal(shost->transportt);	\
-									\
 	val = simple_strtoul(buf, NULL, 0);				\
-	i->f->set_starget_##field(starget, val);			\
+	i->f->set_rport_##field(rport, val);				\
 	return count;							\
 }
 
-#define fc_starget_rd_attr(field, format_string)			\
-	fc_starget_show_function(field, format_string, )		\
+#define fc_rport_rd_attr(field, format_string, sz)			\
+	fc_rport_show_function(field, format_string, sz, )		\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			 show_fc_rport_##field, NULL)
+
+#define fc_rport_rd_attr_cast(field, format_string, sz, cast)		\
+	fc_rport_show_function(field, format_string, sz, (cast))	\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			  show_fc_rport_##field, NULL)
+
+#define fc_rport_rw_attr(field, format_string, sz)			\
+	fc_rport_show_function(field, format_string, sz, )		\
+	fc_rport_store_function(field)					\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO | S_IWUSR,		\
+			show_fc_rport_##field,				\
+			store_fc_rport_##field)
+
+
+#define fc_private_rport_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+show_fc_rport_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	return snprintf(buf, sz, format_string, cast rport->field); 	\
+}
+
+#define fc_private_rport_rd_attr(field, format_string, sz)		\
+	fc_private_rport_show_function(field, format_string, sz, )	\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			 show_fc_rport_##field, NULL)
+
+#define fc_private_rport_rd_attr_cast(field, format_string, sz, cast)	\
+	fc_private_rport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			  show_fc_rport_##field, NULL)
+
+
+#define fc_private_rport_rd_enum_attr(title, maxlen)			\
+static ssize_t								\
+show_fc_rport_##title (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	const char *name;						\
+	name = get_fc_##title##_name(rport->title);			\
+	if (!name)							\
+		return -EINVAL;						\
+	return snprintf(buf, maxlen, "%s\n", name);			\
+}									\
+static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO,			\
+			show_fc_rport_##title, NULL)
+
+
+#define SETUP_RPORT_ATTRIBUTE_RD(field)					\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	i->private_rport_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_rport_attrs[count].store = NULL;			\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	if (i->f->show_rport_##field)					\
+		count++
+
+#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(field)				\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	i->private_rport_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_rport_attrs[count].store = NULL;			\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	count++
+
+#define SETUP_RPORT_ATTRIBUTE_RW(field)					\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	if (!i->f->set_rport_##field) {					\
+		i->private_rport_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_rport_attrs[count].store = NULL;		\
+	}								\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	if (i->f->show_rport_##field)					\
+		count++
+
+
+/* The FC Transport Remote Port Attributes: */
+
+/* Fixed Remote Port Attributes */
+
+fc_private_rport_rd_attr(maxframe_size, "%u bytes\n", 20);
+
+static ssize_t
+show_fc_rport_supported_classes (struct class_device *cdev, char *buf)
+{
+	struct fc_rport *rport = transport_class_to_rport(cdev);
+	if (rport->supported_classes == FC_COS_UNSPECIFIED)
+		return snprintf(buf, 20, "unspecified\n");
+	return get_fc_cos_names(rport->supported_classes, buf);
+}
+static FC_CLASS_DEVICE_ATTR(rport, supported_classes, S_IRUGO,
+		show_fc_rport_supported_classes, NULL);
+
+/* Dynamic Remote Port Attributes */
+
+fc_rport_rw_attr(dev_loss_tmo, "%d\n", 20);
+
+
+/* Private Remote Port Attributes */
+
+fc_private_rport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_private_rport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_private_rport_rd_attr(port_id, "0x%06x\n", 20);
+
+static ssize_t
+show_fc_rport_roles (struct class_device *cdev, char *buf)
+{
+	struct fc_rport *rport = transport_class_to_rport(cdev);
+
+	/* identify any roles that are port_id specific */
+	if ((rport->port_id != -1) &&
+	    (rport->port_id & FC_WELLKNOWN_PORTID_MASK) ==
+					FC_WELLKNOWN_PORTID_MASK) {
+		switch (rport->port_id & FC_WELLKNOWN_ROLE_MASK) {
+		case FC_FPORT_PORTID:
+			return snprintf(buf, 30, "Fabric Port\n");
+		case FC_FABCTLR_PORTID:
+			return snprintf(buf, 30, "Fabric Controller\n");
+		case FC_DIRSRVR_PORTID:
+			return snprintf(buf, 30, "Directory Server\n");
+		case FC_TIMESRVR_PORTID:
+			return snprintf(buf, 30, "Time Server\n");
+		case FC_MGMTSRVR_PORTID:
+			return snprintf(buf, 30, "Management Server\n");
+		default:
+			return snprintf(buf, 30, "Unknown Fabric Entity\n");
+		}
+	} else {
+		if (rport->roles == FC_RPORT_ROLE_UNKNOWN)
+			return snprintf(buf, 20, "unknown\n");
+		return get_fc_remote_port_roles_names(rport->roles, buf);
+	}
+}
+static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
+		show_fc_rport_roles, NULL);
+
+fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
+fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);
+
+
+
+/*
+ * FC SCSI Target Attribute Management
+ */
+
+/*
+ * Note: in the target show function we recognize when the remote
+ *  port is in the heirarchy and do not allow the driver to get
+ *  involved in sysfs functions. The driver only gets involved if
+ *  it's the "old" style that doesn't use rports.
+ */
+#define fc_starget_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+show_fc_starget_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	struct fc_rport *rport = starget_to_rport(starget);		\
+	if (rport)							\
+		fc_starget_##field(starget) = rport->field;		\
+	else if (i->f->get_starget_##field)				\
+		i->f->get_starget_##field(starget);			\
+	return snprintf(buf, sz, format_string, 			\
+		cast fc_starget_##field(starget)); 			\
+}
+
+#define fc_starget_rd_attr(field, format_string, sz)			\
+	fc_starget_show_function(field, format_string, sz, )		\
 static FC_CLASS_DEVICE_ATTR(starget, field, S_IRUGO,			\
 			 show_fc_starget_##field, NULL)
 
-#define fc_starget_rd_attr_cast(field, format_string, cast)		\
-	fc_starget_show_function(field, format_string, (cast))		\
+#define fc_starget_rd_attr_cast(field, format_string, sz, cast)		\
+	fc_starget_show_function(field, format_string, sz, (cast))	\
 static FC_CLASS_DEVICE_ATTR(starget, field, S_IRUGO,			\
 			  show_fc_starget_##field, NULL)
 
-#define fc_starget_rw_attr(field, format_string)			\
-	fc_starget_show_function(field, format_string, )		\
-	fc_starget_store_function(field, format_string)			\
-static FC_CLASS_DEVICE_ATTR(starget, field, S_IRUGO | S_IWUSR,		\
-			show_fc_starget_##field,			\
-			store_fc_starget_##field)
-
 #define SETUP_STARGET_ATTRIBUTE_RD(field)				\
 	i->private_starget_attrs[count] = class_device_attr_starget_##field; \
 	i->private_starget_attrs[count].attr.mode = S_IRUGO;		\
@@ -377,12 +600,10 @@ static FC_CLASS_DEVICE_ATTR(starget, fie
 	if (i->f->show_starget_##field)					\
 		count++
 
-/* The FC Tranport Remote Port (Target) Attributes: */
-fc_starget_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
-fc_starget_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
-fc_starget_rd_attr(port_id, "0x%06x\n");
-fc_starget_rw_attr(dev_loss_tmo, "%d\n");
-
+/* The FC Transport SCSI Target Attributes: */
+fc_starget_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_starget_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_starget_rd_attr(port_id, "0x%06x\n", 20);
 
 
 /*
@@ -400,7 +621,7 @@ show_fc_host_##field (struct class_devic
 	return snprintf(buf, sz, format_string, cast fc_host_##field(shost)); \
 }
 
-#define fc_host_store_function(field, format_string)			\
+#define fc_host_store_function(field)					\
 static ssize_t								\
 store_fc_host_##field(struct class_device *cdev, const char *buf,	\
 			   size_t count)				\
@@ -426,7 +647,7 @@ static FC_CLASS_DEVICE_ATTR(host, field,
 
 #define fc_host_rw_attr(field, format_string, sz)			\
 	fc_host_show_function(field, format_string, sz, )		\
-	fc_host_store_function(field, format_string)			\
+	fc_host_store_function(field)					\
 static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO | S_IWUSR,		\
 			show_fc_host_##field,				\
 			store_fc_host_##field)
@@ -539,11 +760,7 @@ fc_private_host_rd_attr_cast(node_name, 
 fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
 fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
 fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
-fc_private_host_rd_attr(hardware_version, "%s\n", (FC_VERSION_STRING_SIZE +1));
-fc_private_host_rd_attr(firmware_version, "%s\n", (FC_VERSION_STRING_SIZE +1));
 fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
-fc_private_host_rd_attr(opt_rom_version, "%s\n", (FC_VERSION_STRING_SIZE +1));
-fc_private_host_rd_attr(driver_version, "%s\n", (FC_VERSION_STRING_SIZE +1));
 
 
 /* Dynamic Host Attributes */
@@ -584,7 +801,6 @@ fc_host_rd_attr(port_id, "0x%06x\n", 20)
 fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN);
 fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
 fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
-fc_host_rw_attr(link_down_tmo, "%d\n", 20);
 
 
 /* Private Host Attributes */
@@ -606,10 +822,22 @@ store_fc_private_host_tgtid_bind_type(st
 	const char *buf, size_t count)
 {
 	struct Scsi_Host *shost = transport_class_to_shost(cdev);
-	enum fc_tgtid_binding_type val;
+	struct fc_rport *rport, *next_rport;
+ 	enum fc_tgtid_binding_type val;
+	unsigned long flags;
 
 	if (get_fc_tgtid_bind_type_match(buf, &val))
 		return -EINVAL;
+
+	/* if changing bind type, purge all unused consistent bindings */
+	if (val != fc_host_tgtid_bind_type(shost)) {
+		spin_lock_irqsave(shost->host_lock, flags);
+		list_for_each_entry_safe(rport, next_rport,
+				&fc_host_rport_bindings(shost), peers)
+			fc_rport_terminate(rport);
+		spin_unlock_irqrestore(shost->host_lock, flags);
+	}
+
 	fc_host_tgtid_bind_type(shost) = val;
 	return count;
 }
@@ -734,13 +962,13 @@ static int fc_host_match(struct attribut
 		return 0;
 
 	shost = dev_to_shost(dev);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &fc_host_class.class)
 		return 0;
 
 	i = to_fc_internal(shost->transportt);
-	
-	return &i->t.host_attrs == cont;
+
+	return &i->t.host_attrs.ac == cont;
 }
 
 static int fc_target_match(struct attribute_container *cont,
@@ -753,62 +981,99 @@ static int fc_target_match(struct attrib
 		return 0;
 
 	shost = dev_to_shost(dev->parent);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &fc_host_class.class)
 		return 0;
 
 	i = to_fc_internal(shost->transportt);
-	
-	return &i->t.target_attrs == cont;
+
+	return &i->t.target_attrs.ac == cont;
+}
+
+static void fc_rport_dev_release(struct device *dev)
+{
+	struct fc_rport *rport = dev_to_rport(dev);
+	put_device(dev->parent);
+	kfree(rport);
 }
 
+int scsi_is_fc_rport(const struct device *dev)
+{
+	return dev->release == fc_rport_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_fc_rport);
+
+static int fc_rport_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct fc_internal *i;
+
+	if (!scsi_is_fc_rport(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &fc_host_class.class)
+		return 0;
+
+	i = to_fc_internal(shost->transportt);
+
+	return &i->rport_attr_cont.ac == cont;
+}
 
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
 	struct fc_internal *i = kmalloc(sizeof(struct fc_internal),
 					GFP_KERNEL);
-	int count = 0;
+	int count;
 
 	if (unlikely(!i))
 		return NULL;
 
 	memset(i, 0, sizeof(struct fc_internal));
 
-	i->t.target_attrs.attrs = &i->starget_attrs[0];
-	i->t.target_attrs.class = &fc_transport_class.class;
-	i->t.target_attrs.match = fc_target_match;
-	attribute_container_register(&i->t.target_attrs);
+	i->t.target_attrs.ac.attrs = &i->starget_attrs[0];
+	i->t.target_attrs.ac.class = &fc_transport_class.class;
+	i->t.target_attrs.ac.match = fc_target_match;
 	i->t.target_size = sizeof(struct fc_starget_attrs);
+	transport_container_register(&i->t.target_attrs);
 
-	i->t.host_attrs.attrs = &i->host_attrs[0];
-	i->t.host_attrs.class = &fc_host_class.class;
-	i->t.host_attrs.match = fc_host_match;
-	attribute_container_register(&i->t.host_attrs);
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.class = &fc_host_class.class;
+	i->t.host_attrs.ac.match = fc_host_match;
 	i->t.host_size = sizeof(struct fc_host_attrs);
-
 	if (ft->get_fc_host_stats)
-		i->t.host_statistics = &fc_statistics_group;
+		i->t.host_attrs.statistics = &fc_statistics_group;
+	transport_container_register(&i->t.host_attrs);
+
+	i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+	i->rport_attr_cont.ac.class = &fc_rport_class.class;
+	i->rport_attr_cont.ac.match = fc_rport_match;
+	transport_container_register(&i->rport_attr_cont);
 
 	i->f = ft;
 
+	/* Transport uses the shost workq for scsi scanning */
+	i->t.create_work_queue = 1;
 	
 	/*
-	 * setup remote port (target) attributes
+	 * Setup SCSI Target Attributes.
 	 */
-	SETUP_STARGET_ATTRIBUTE_RD(port_id);
-	SETUP_STARGET_ATTRIBUTE_RD(port_name);
+	count = 0;
 	SETUP_STARGET_ATTRIBUTE_RD(node_name);
-	SETUP_STARGET_ATTRIBUTE_RW(dev_loss_tmo);
+	SETUP_STARGET_ATTRIBUTE_RD(port_name);
+	SETUP_STARGET_ATTRIBUTE_RD(port_id);
 
 	BUG_ON(count > FC_STARGET_NUM_ATTRS);
 
-	/* Setup the always-on attributes here */
-
 	i->starget_attrs[count] = NULL;
 
 
-	/* setup host attributes */
+	/*
+	 * Setup SCSI Host Attributes.
+	 */
 	count=0;
 	SETUP_HOST_ATTRIBUTE_RD(node_name);
 	SETUP_HOST_ATTRIBUTE_RD(port_name);
@@ -817,11 +1082,7 @@ fc_attach_transport(struct fc_function_t
 	SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
 	SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
 	SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
-	SETUP_HOST_ATTRIBUTE_RD(hardware_version);
-	SETUP_HOST_ATTRIBUTE_RD(firmware_version);
 	SETUP_HOST_ATTRIBUTE_RD(serial_number);
-	SETUP_HOST_ATTRIBUTE_RD(opt_rom_version);
-	SETUP_HOST_ATTRIBUTE_RD(driver_version);
 
 	SETUP_HOST_ATTRIBUTE_RD(port_id);
 	SETUP_HOST_ATTRIBUTE_RD(port_type);
@@ -829,7 +1090,6 @@ fc_attach_transport(struct fc_function_t
 	SETUP_HOST_ATTRIBUTE_RD(active_fc4s);
 	SETUP_HOST_ATTRIBUTE_RD(speed);
 	SETUP_HOST_ATTRIBUTE_RD(fabric_name);
-	SETUP_HOST_ATTRIBUTE_RW(link_down_tmo);
 
 	/* Transport-managed attributes */
 	SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
@@ -838,6 +1098,23 @@ fc_attach_transport(struct fc_function_t
 
 	i->host_attrs[count] = NULL;
 
+	/*
+	 * Setup Remote Port Attributes.
+	 */
+	count=0;
+	SETUP_RPORT_ATTRIBUTE_RD(maxframe_size);
+	SETUP_RPORT_ATTRIBUTE_RD(supported_classes);
+	SETUP_RPORT_ATTRIBUTE_RW(dev_loss_tmo);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(node_name);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_name);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_id);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
+
+	BUG_ON(count > FC_RPORT_NUM_ATTRS);
+
+	i->rport_attrs[count] = NULL;
 
 	return &i->t;
 }
@@ -847,205 +1124,538 @@ void fc_release_transport(struct scsi_tr
 {
 	struct fc_internal *i = to_fc_internal(t);
 
-	attribute_container_unregister(&i->t.target_attrs);
-	attribute_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->rport_attr_cont);
 
 	kfree(i);
 }
 EXPORT_SYMBOL(fc_release_transport);
 
 
-
 /**
- * fc_device_block - called by target functions to block a scsi device
- * @dev:	scsi device
- * @data:	unused
+ * fc_remove_host - called to terminate any fc_transport-related elements
+ *                  for a scsi host.
+ * @rport:	remote port to be unblocked.
+ *
+ * This routine is expected to be called immediately preceeding the
+ * a driver's call to scsi_remove_host().
+ *
+ * WARNING: A driver utilizing the fc_transport, which fails to call
+ *   this routine prior to scsi_remote_host(), will leave dangling
+ *   objects in /sys/class/fc_remote_ports. Access to any of these
+ *   objects can result in a system crash !!!
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
  **/
-static void fc_device_block(struct scsi_device *sdev, void *data)
+void
+fc_remove_host(struct Scsi_Host *shost)
 {
-	scsi_internal_device_block(sdev);
+	struct fc_rport *rport, *next_rport;
+
+	/* Remove any remote ports */
+	list_for_each_entry_safe(rport, next_rport,
+			&fc_host_rports(shost), peers)
+		fc_rport_terminate(rport);
+	list_for_each_entry_safe(rport, next_rport,
+			&fc_host_rport_bindings(shost), peers)
+		fc_rport_terminate(rport);
 }
+EXPORT_SYMBOL(fc_remove_host);
 
 /**
- * fc_device_unblock - called by target functions to unblock a scsi device
- * @dev:	scsi device
- * @data:	unused
+ * fc_rport_create - allocates and creates a remote FC port.
+ * @shost:	scsi host the remote port is connected to.
+ * @channel:	Channel on shost port connected to.
+ * @ids:	The world wide names, fc address, and FC4 port
+ *		roles for the remote port.
+ *
+ * Allocates and creates the remoter port structure, including the
+ * class and sysfs creation.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
  **/
-static void fc_device_unblock(struct scsi_device *sdev, void *data)
-{
-	scsi_internal_device_unblock(sdev);
+struct fc_rport *
+fc_rport_create(struct Scsi_Host *shost, int channel,
+	struct fc_rport_identifiers  *ids)
+{
+	struct fc_host_attrs *fc_host =
+			(struct fc_host_attrs *)shost->shost_data;
+	struct fc_internal *fci = to_fc_internal(shost->transportt);
+	struct fc_rport *rport;
+	struct device *dev;
+	unsigned long flags;
+	int error;
+	size_t size;
+
+	size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size);
+	rport = kmalloc(size, GFP_KERNEL);
+	if (unlikely(!rport)) {
+		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		return NULL;
+	}
+	memset(rport, 0, size);
+
+	rport->maxframe_size = -1;
+	rport->supported_classes = FC_COS_UNSPECIFIED;
+	rport->dev_loss_tmo = fc_dev_loss_tmo;
+	memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name));
+	memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name));
+	rport->port_id = ids->port_id;
+	rport->roles = ids->roles;
+	rport->port_state = FC_PORTSTATE_ONLINE;
+	if (fci->f->dd_fcrport_size)
+		rport->dd_data = &rport[1];
+	rport->channel = channel;
+
+	INIT_WORK(&rport->dev_loss_work, fc_timeout_blocked_rport, rport);
+	INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	rport->number = fc_host->next_rport_number++;
+	if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+		rport->scsi_target_id = fc_host->next_target_id++;
+	else
+		rport->scsi_target_id = -1;
+	list_add_tail(&rport->peers, &fc_host_rports(shost));
+	get_device(&shost->shost_gendev);
+
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	dev = &rport->dev;
+	device_initialize(dev);
+	dev->parent = get_device(&shost->shost_gendev);
+	dev->release = fc_rport_dev_release;
+	sprintf(dev->bus_id, "rport-%d:%d-%d",
+		shost->host_no, channel, rport->number);
+	transport_setup_device(dev);
+
+	error = device_add(dev);
+	if (error) {
+		printk(KERN_ERR "FC Remote Port device_add failed\n");
+		goto delete_rport;
+	}
+	transport_add_device(dev);
+	transport_configure_device(dev);
+
+	if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+		/* initiate a scan of the target */
+		scsi_queue_work(shost, &rport->scan_work);
+
+	return rport;
+
+delete_rport:
+	transport_destroy_device(dev);
+	put_device(dev->parent);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_del(&rport->peers);
+	put_device(&shost->shost_gendev);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(dev->parent);
+	kfree(rport);
+	return NULL;
 }
 
 /**
- * fc_timeout_blocked_tgt - Timeout handler for blocked scsi targets
- *			 that fail to recover in the alloted time.
- * @data:	scsi target that failed to reappear in the alloted time.
+ * fc_remote_port_add - notifies the fc transport of the existence
+ *		of a remote FC port.
+ * @shost:	scsi host the remote port is connected to.
+ * @channel:	Channel on shost port connected to.
+ * @ids:	The world wide names, fc address, and FC4 port
+ *		roles for the remote port.
+ *
+ * The LLDD calls this routine to notify the transport of the existence
+ * of a remote port. The LLDD provides the unique identifiers (wwpn,wwn)
+ * of the port, it's FC address (port_id), and the FC4 roles that are
+ * active for the port.
+ *
+ * For ports that are FCP targets (aka scsi targets), the FC transport
+ * maintains consistent target id bindings on behalf of the LLDD.
+ * A consistent target id binding is an assignment of a target id to
+ * a remote port identifier, which persists while the scsi host is
+ * attached. The remote port can disappear, then later reappear, and
+ * it's target id assignment remains the same. This allows for shifts
+ * in FC addressing (if binding by wwpn or wwnn) with no apparent
+ * changes to the scsi subsystem which is based on scsi host number and
+ * target id values.  Bindings are only valid during the attachment of
+ * the scsi host. If the host detaches, then later re-attaches, target
+ * id bindings may change.
+ *
+ * This routine is responsible for returning a remote port structure.
+ * The routine will search the list of remote ports it maintains
+ * internally on behalf of consistent target id mappings. If found, the
+ * remote port structure will be reused. Otherwise, a new remote port
+ * structure will be allocated.
+ *
+ * Whenever a remote port is allocated, a new fc_remote_port class
+ * device is created.
+ *
+ * Should not be called from interrupt context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
  **/
-static void fc_timeout_blocked_tgt(void  *data)
+struct fc_rport *
+fc_remote_port_add(struct Scsi_Host *shost, int channel,
+	struct fc_rport_identifiers  *ids)
+{
+	struct fc_rport *rport;
+	unsigned long flags;
+	int match = 0;
+
+	if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) &&
+		(fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) {
+
+		/* search for a matching consistent binding */
+
+		spin_lock_irqsave(shost->host_lock, flags);
+
+		list_for_each_entry(rport, &fc_host_rport_bindings(shost),
+					peers) {
+			if (rport->channel != channel)
+				continue;
+
+			switch (fc_host_tgtid_bind_type(shost)) {
+			case FC_TGTID_BIND_BY_WWPN:
+				if (rport->port_name == ids->port_name)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_BY_WWNN:
+				if (rport->node_name == ids->node_name)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_BY_ID:
+				if (rport->port_id == ids->port_id)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_NONE: /* to keep compiler happy */
+				break;
+			}
+
+			if (match) {
+				list_move_tail(&rport->peers,
+					&fc_host_rports(shost));
+				break;
+			}
+		}
+
+		spin_unlock_irqrestore(shost->host_lock, flags);
+
+		if (match) {
+			memcpy(&rport->node_name, &ids->node_name,
+				sizeof(rport->node_name));
+			memcpy(&rport->port_name, &ids->port_name,
+				sizeof(rport->port_name));
+			rport->port_id = ids->port_id;
+			rport->roles = ids->roles;
+			rport->port_state = FC_PORTSTATE_ONLINE;
+
+			if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+				/* initiate a scan of the target */
+				scsi_queue_work(shost, &rport->scan_work);
+
+			return rport;
+		}
+	}
+
+	/* No consistent binding found - create new remote port entry */
+	rport = fc_rport_create(shost, channel, ids);
+
+	return rport;
+}
+EXPORT_SYMBOL(fc_remote_port_add);
+
+/*
+ * fc_rport_tgt_remove - Removes the scsi target on the remote port
+ * @rport:	The remote port to be operated on
+ */
+static void
+fc_rport_tgt_remove(struct fc_rport *rport)
 {
-	struct scsi_target *starget = (struct scsi_target *)data;
+	struct Scsi_Host *shost = rport_to_shost(rport);
 
-	dev_printk(KERN_ERR, &starget->dev, 
-		"blocked target time out: target resuming\n");
+	scsi_target_unblock(&rport->dev);
 
-	/* 
-	 * set the device going again ... if the scsi lld didn't
-	 * unblock this device, then IO errors will probably
-	 * result if the host still isn't ready.
-	 */
-	starget_for_each_device(starget, NULL, fc_device_unblock);
+	/* Stop anything on the workq */
+	if (!cancel_delayed_work(&rport->dev_loss_work))
+		flush_scheduled_work();
+	scsi_flush_work(shost);
+
+	scsi_remove_target(&rport->dev);
+}
+
+/*
+ * fc_rport_terminate - this routine tears down and deallocates a remote port.
+ * @rport:	The remote port to be terminated
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ */
+static void
+fc_rport_terminate(struct fc_rport  *rport)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct device *dev = &rport->dev;
+	unsigned long flags;
+
+	fc_rport_tgt_remove(rport);
+
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_del(&rport->peers);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(&shost->shost_gendev);
 }
 
 /**
- * fc_target_block - block a target by temporarily putting all its scsi devices
- *		into the SDEV_BLOCK state.
- * @starget:	scsi target managed by this fc scsi lldd.
- *
- * scsi lldd's with a FC transport call this routine to temporarily stop all
- * scsi commands to all devices managed by this scsi target.  Called 
- * from interrupt or normal process context.
+ * fc_remote_port_delete - notifies the fc transport that a remote
+ *		port is no longer in existence.
+ * @rport:	The remote port that no longer exists
  *
- * Returns zero if successful or error if not
+ * The LLDD calls this routine to notify the transport that a remote
+ * port is no longer part of the topology. Note: Although a port
+ * may no longer be part of the topology, it may persist in the remote
+ * ports displayed by the fc_host. This is done so that target id
+ * mappings (managed via the remote port structures), are always visible
+ * as long as the mapping is valid, regardless of port state,
  *
- * Notes:       
- *	The timeout and timer types are extracted from the fc transport 
- *	attributes from the caller's target pointer.  This routine assumes no
- *	locks are held on entry.
+ * If the remote port is not an FCP Target, it will be fully torn down
+ * and deallocated, including the fc_remote_port class device.
+ *
+ * If the remote port is an FCP Target, the port structure will be
+ * marked as Not Present, but will remain as long as there is a valid
+ * SCSI target id mapping associated with the port structure. Validity
+ * is determined by the binding type. If binding by wwpn, then the port
+ * structure is always valid and will not be deallocated until the host
+ * is removed.  If binding by wwnn, then the port structure is valid
+ * until another port with the same node name is found in the topology.
+ * If binding by port id (fc address), then the port structure is valid
+ * valid until another port with the same address is identified.
+ *
+ * Called from interrupt or normal process context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
  **/
-int
-fc_target_block(struct scsi_target *starget)
+void
+fc_remote_port_delete(struct fc_rport  *rport)
 {
-	int timeout = fc_starget_dev_loss_tmo(starget);
-	struct work_struct *work = &fc_starget_dev_loss_work(starget);
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	unsigned long flags;
 
-	if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
-		return -EINVAL;
+	/* If no scsi target id mapping or consistent binding type, delete it */
+	if ((rport->scsi_target_id == -1) ||
+	    (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE)) {
+		fc_rport_terminate(rport);
+		return;
+	}
 
-	starget_for_each_device(starget, NULL, fc_device_block);
+	fc_rport_tgt_remove(rport);
 
-	/* The scsi lld blocks this target for the timeout period only. */
-	schedule_delayed_work(work, timeout * HZ);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_move_tail(&rport->peers, &fc_host_rport_bindings(shost));
+	spin_unlock_irqrestore(shost->host_lock, flags);
 
-	return 0;
+	/*
+	 * Note: We do not remove or clear the hostdata area. This allows
+	 *   host-specific target data to persist along with the
+	 *   scsi_target_id. It's up to the host to manage it's hostdata area.
+	 */
+
+	/*
+	 * Reinitialize port attributes that may change if the port comes back.
+	 */
+	rport->maxframe_size = -1;
+	rport->supported_classes = FC_COS_UNSPECIFIED;
+	rport->roles = FC_RPORT_ROLE_UNKNOWN;
+	rport->port_state = FC_PORTSTATE_NOTPRESENT;
+
+	/* remove the identifiers that aren't used in the consisting binding */
+	switch (fc_host_tgtid_bind_type(shost)) {
+	case FC_TGTID_BIND_BY_WWPN:
+		rport->node_name = -1;
+		rport->port_id = -1;
+		break;
+	case FC_TGTID_BIND_BY_WWNN:
+		rport->port_name = -1;
+		rport->port_id = -1;
+		break;
+	case FC_TGTID_BIND_BY_ID:
+		rport->node_name = -1;
+		rport->port_name = -1;
+		break;
+	case FC_TGTID_BIND_NONE:	/* to keep compiler happy */
+		break;
+	}
 }
-EXPORT_SYMBOL(fc_target_block);
+EXPORT_SYMBOL(fc_remote_port_delete);
 
 /**
- * fc_target_unblock - unblock a target following a fc_target_block request.
- * @starget:	scsi target managed by this fc scsi lldd.	
+ * fc_remote_port_rolechg - notifies the fc transport that the roles
+ *		on a remote may have changed.
+ * @rport:	The remote port that changed.
  *
- * scsi lld's with a FC transport call this routine to restart IO to all 
- * devices associated with the caller's scsi target following a fc_target_block
- * request.  Called from interrupt or normal process context.
+ * The LLDD calls this routine to notify the transport that the roles
+ * on a remote port may have changed. The largest effect of this is
+ * if a port now becomes a FCP Target, it must be allocated a
+ * scsi target id.  If the port is no longer a FCP target, any
+ * scsi target id value assigned to it will persist in case the
+ * role changes back to include FCP Target. No changes in the scsi
+ * midlayer will be invoked if the role changes (in the expectation
+ * that the role will be resumed. If it doesn't normal error processing
+ * will take place).
+ *
+ * Should not be called from interrupt context.
  *
- * Notes:       
+ * Notes:
  *	This routine assumes no locks are held on entry.
  **/
 void
-fc_target_unblock(struct scsi_target *starget)
+fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 {
-	/* 
-	 * Stop the target timer first. Take no action on the del_timer
-	 * failure as the state machine state change will validate the
-	 * transaction. 
-	 */
-	if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
-		flush_scheduled_work();
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct fc_host_attrs *fc_host =
+			(struct fc_host_attrs *)shost->shost_data;
+	unsigned long flags;
+	int create = 0;
+
+	rport->roles = roles;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	if ((rport->scsi_target_id == -1) &&
+	    (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+		rport->scsi_target_id = fc_host->next_target_id++;
+		create = 1;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
 
-	starget_for_each_device(starget, NULL, fc_device_unblock);
+	if (create)
+		/* initiate a scan of the target */
+		scsi_queue_work(shost, &rport->scan_work);
 }
-EXPORT_SYMBOL(fc_target_unblock);
+EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_blocked_host - Timeout handler for blocked scsi hosts
- *			 that fail to recover in the alloted time.
- * @data:	scsi host that failed to recover its devices in the alloted
- *		time.
+ * fc_timeout_blocked_rport - Timeout handler for blocked remote port
+ *                       that fails to return in the alloted time.
+ * @data:	scsi target that failed to reappear in the alloted time.
  **/
-static void fc_timeout_blocked_host(void  *data)
+static void
+fc_timeout_blocked_rport(void  *data)
 {
-	struct Scsi_Host *shost = (struct Scsi_Host *)data;
-	struct scsi_device *sdev;
+	struct fc_rport *rport = (struct fc_rport *)data;
 
-	dev_printk(KERN_ERR, &shost->shost_gendev, 
-		"blocked host time out: host resuming\n");
+	rport->port_state = FC_PORTSTATE_OFFLINE;
 
-	shost_for_each_device(sdev, shost) {
-		/* 
-		 * set the device going again ... if the scsi lld didn't
-		 * unblock this device, then IO errors will probably
-		 * result if the host still isn't ready.
-		 */
-		scsi_internal_device_unblock(sdev);
-	}
+	dev_printk(KERN_ERR, &rport->dev,
+		"blocked FC remote port time out: removing target\n");
+
+	/*
+	 * As this only occurs if the remote port (scsi target)
+	 * went away and didn't come back - we'll remove
+	 * all attached scsi devices.
+	 */
+	scsi_target_unblock(&rport->dev);
+	scsi_remove_target(&rport->dev);
 }
 
 /**
- * fc_host_block - block all scsi devices managed by the calling host temporarily 
- *		by putting each device in the SDEV_BLOCK state.
- * @shost:	scsi host pointer that contains all scsi device siblings.
- *
- * scsi lld's with a FC transport call this routine to temporarily stop all
- * scsi commands to all devices managed by this host.  Called 
- * from interrupt or normal process context.
+ * fc_remote_port_block - temporarily block any scsi traffic to a remote port.
+ * @rport:	remote port to be blocked.
+ *
+ * scsi lldd's with a FC transport call this routine to temporarily stop
+ * all scsi traffic to a remote port. If the port is not a SCSI target,
+ * no action is taken. If the port is a SCSI target, all attached devices
+ * are placed into a SDEV_BLOCK state and a timer is started. The timer is
+ * represents the maximum amount of time the port may be blocked. If the
+ * timer expires, the port is considered non-existent and the attached
+ * scsi devices will be removed.
+ *
+ * Called from interrupt or normal process context.
  *
  * Returns zero if successful or error if not
  *
  * Notes:
+ *      This routine assumes no locks are held on entry.
+ *
  *	The timeout and timer types are extracted from the fc transport 
- *	attributes from the caller's host pointer.  This routine assumes no
- *	locks are held on entry.
+ *	attributes from the caller's rport pointer.
  **/
 int
-fc_host_block(struct Scsi_Host *shost)
+fc_remote_port_block(struct fc_rport *rport)
 {
-	struct scsi_device *sdev;
-	int timeout = fc_host_link_down_tmo(shost);
-	struct work_struct *work = &fc_host_link_down_work(shost);
+	int timeout = rport->dev_loss_tmo;
+	struct work_struct *work = &rport->dev_loss_work;
 
 	if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
 		return -EINVAL;
 
-	shost_for_each_device(sdev, shost) {
-		scsi_internal_device_block(sdev);
-	}
+	scsi_target_block(&rport->dev);
 
+	/* cap the length the devices can be blocked */
 	schedule_delayed_work(work, timeout * HZ);
 
+	rport->port_state = FC_PORTSTATE_BLOCKED;
 	return 0;
 }
-EXPORT_SYMBOL(fc_host_block);
+EXPORT_SYMBOL(fc_remote_port_block);
 
 /**
- * fc_host_unblock - unblock all devices managed by this host following a 
- *		fc_host_block request.
- * @shost:	scsi host containing all scsi device siblings to unblock.
+ * fc_remote_port_unblock - restart any blocked scsi traffic to a remote port.
+ * @rport:	remote port to be unblocked.
  *
- * scsi lld's with a FC transport call this routine to restart IO to all scsi
- * devices managed by the specified scsi host following an fc_host_block 
+ * scsi lld's with a FC transport call this routine to restart IO to all
+ * devices associated with the caller's scsi target following a fc_target_block
  * request.  Called from interrupt or normal process context.
  *
- * Notes:       
+ * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-void
-fc_host_unblock(struct Scsi_Host *shost)
+ void
+fc_remote_port_unblock(struct fc_rport *rport)
 {
-	struct scsi_device *sdev;
+	struct work_struct *work = &rport->dev_loss_work;
+	struct Scsi_Host *shost = rport_to_shost(rport);
 
-	/* 
-	 * Stop the host timer first. Take no action on the del_timer
+	/*
+	 * Stop the target timer first. Take no action on the del_timer
 	 * failure as the state machine state change will validate the
 	 * transaction.
 	 */
-	if (cancel_delayed_work(&fc_host_link_down_work(shost)))
+	if (!cancel_delayed_work(work))
 		flush_scheduled_work();
 
-	shost_for_each_device(sdev, shost) {
-		scsi_internal_device_unblock(sdev);
-	}
+	if (rport->port_state == FC_PORTSTATE_OFFLINE)
+		/*
+		 * initiate a scan of the target as the target has
+		 * been torn down.
+		 */
+		scsi_queue_work(shost, &rport->scan_work);
+	else
+		scsi_target_unblock(&rport->dev);
+
+	rport->port_state = FC_PORTSTATE_ONLINE;
+}
+EXPORT_SYMBOL(fc_remote_port_unblock);
+
+/**
+ * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
+ * @data:	remote port to be scanned.
+ **/
+static void
+fc_scsi_scan_rport(void *data)
+{
+	struct fc_rport *rport = (struct fc_rport *)data;
+
+	scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id,
+			SCAN_WILD_CARD, 1);
 }
-EXPORT_SYMBOL(fc_host_unblock);
+
 
 MODULE_AUTHOR("Martin Hicks");
 MODULE_DESCRIPTION("FC Transport Attributes");
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -264,13 +264,13 @@ static int iscsi_host_match(struct attri
 		return 0;
 
 	shost = dev_to_shost(dev);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &iscsi_host_class.class)
 		return 0;
 
 	i = to_iscsi_internal(shost->transportt);
 	
-	return &i->t.host_attrs == cont;
+	return &i->t.host_attrs.ac == cont;
 }
 
 static int iscsi_target_match(struct attribute_container *cont,
@@ -283,13 +283,13 @@ static int iscsi_target_match(struct att
 		return 0;
 
 	shost = dev_to_shost(dev->parent);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &iscsi_host_class.class)
 		return 0;
 
 	i = to_iscsi_internal(shost->transportt);
 	
-	return &i->t.target_attrs == cont;
+	return &i->t.target_attrs.ac == cont;
 }
 
 struct scsi_transport_template *
@@ -305,10 +305,10 @@ iscsi_attach_transport(struct iscsi_func
 	memset(i, 0, sizeof(struct iscsi_internal));
 	i->fnt = fnt;
 
-	i->t.target_attrs.attrs = &i->session_attrs[0];
-	i->t.target_attrs.class = &iscsi_transport_class.class;
-	i->t.target_attrs.match = iscsi_target_match;
-	attribute_container_register(&i->t.target_attrs);
+	i->t.target_attrs.ac.attrs = &i->session_attrs[0];
+	i->t.target_attrs.ac.class = &iscsi_transport_class.class;
+	i->t.target_attrs.ac.match = iscsi_target_match;
+	transport_container_register(&i->t.target_attrs);
 	i->t.target_size = sizeof(struct iscsi_class_session);
 
 	SETUP_SESSION_RD_ATTR(tsih);
@@ -335,10 +335,10 @@ iscsi_attach_transport(struct iscsi_func
 	BUG_ON(count > ISCSI_SESSION_ATTRS);
 	i->session_attrs[count] = NULL;
 
-	i->t.host_attrs.attrs = &i->host_attrs[0];
-	i->t.host_attrs.class = &iscsi_host_class.class;
-	i->t.host_attrs.match = iscsi_host_match;
-	attribute_container_register(&i->t.host_attrs);
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.class = &iscsi_host_class.class;
+	i->t.host_attrs.ac.match = iscsi_host_match;
+	transport_container_register(&i->t.host_attrs);
 	i->t.host_size = 0;
 
 	count = 0;
@@ -357,9 +357,9 @@ void iscsi_release_transport(struct scsi
 {
 	struct iscsi_internal *i = to_iscsi_internal(t);
 
-	attribute_container_unregister(&i->t.target_attrs);
-	attribute_container_unregister(&i->t.host_attrs);
-
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
+  
 	kfree(i);
 }
 
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -18,15 +18,12 @@
  *  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/ctype.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/workqueue.h>
-#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 #include <scsi/scsi_device.h>
@@ -38,13 +35,18 @@
 
 #define SPI_PRINTK(x, l, f, a...)	dev_printk(l, &(x)->dev, f , ##a)
 
-#define SPI_NUM_ATTRS 10	/* increase this if you add attributes */
+#define SPI_NUM_ATTRS 13	/* increase this if you add attributes */
 #define SPI_OTHER_ATTRS 1	/* Increase this if you add "always
 				 * on" attributes */
 #define SPI_HOST_ATTRS	1
 
 #define SPI_MAX_ECHO_BUFFER_SIZE	4096
 
+#define DV_LOOPS	3
+#define DV_TIMEOUT	(10*HZ)
+#define DV_RETRIES	3	/* should only need at most 
+				 * two cc/ua clears */
+
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
 #define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
@@ -63,27 +65,70 @@ struct spi_internal {
 
 #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
 
-static const char *const ppr_to_ns[] = {
+static const int ppr_to_ps[] = {
 	/* The PPR values 0-6 are reserved, fill them in when
 	 * the committee defines them */
-	NULL,			/* 0x00 */
-	NULL,			/* 0x01 */
-	NULL,			/* 0x02 */
-	NULL,			/* 0x03 */
-	NULL,			/* 0x04 */
-	NULL,			/* 0x05 */
-	NULL,			/* 0x06 */
-	"3.125",		/* 0x07 */
-	"6.25",			/* 0x08 */
-	"12.5",			/* 0x09 */
-	"25",			/* 0x0a */
-	"30.3",			/* 0x0b */
-	"50",			/* 0x0c */
+	-1,			/* 0x00 */
+	-1,			/* 0x01 */
+	-1,			/* 0x02 */
+	-1,			/* 0x03 */
+	-1,			/* 0x04 */
+	-1,			/* 0x05 */
+	-1,			/* 0x06 */
+	 3125,			/* 0x07 */
+	 6250,			/* 0x08 */
+	12500,			/* 0x09 */
+	25000,			/* 0x0a */
+	30300,			/* 0x0b */
+	50000,			/* 0x0c */
 };
 /* The PPR values at which you calculate the period in ns by multiplying
  * by 4 */
 #define SPI_STATIC_PPR	0x0c
 
+static int sprint_frac(char *dest, int value, int denom)
+{
+	int frac = value % denom;
+	int result = sprintf(dest, "%d", value / denom);
+
+	if (frac == 0)
+		return result;
+	dest[result++] = '.';
+
+	do {
+		denom /= 10;
+		sprintf(dest + result, "%d", frac / denom);
+		result++;
+		frac %= denom;
+	} while (frac);
+
+	dest[result++] = '\0';
+	return result;
+}
+
+/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions
+ * resulting from (likely) bus and device resets */
+static void spi_wait_req(struct scsi_request *sreq, const void *cmd,
+			 void *buffer, unsigned bufflen)
+{
+	int i;
+
+	for(i = 0; i < DV_RETRIES; i++) {
+		sreq->sr_request->flags |= REQ_FAILFAST;
+
+		scsi_wait_req(sreq, cmd, buffer, bufflen,
+			      DV_TIMEOUT, /* retries */ 1);
+		if (sreq->sr_result & DRIVER_SENSE) {
+			struct scsi_sense_hdr sshdr;
+
+			if (scsi_request_normalize_sense(sreq, &sshdr)
+			    && sshdr.sense_key == UNIT_ATTENTION)
+				continue;
+		}
+		break;
+	}
+}
+
 static struct {
 	enum spi_signal_type	value;
 	char			*name;
@@ -142,13 +187,13 @@ static int spi_host_match(struct attribu
 		return 0;
 
 	shost = dev_to_shost(dev);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &spi_host_class.class)
 		return 0;
 
 	i = to_spi_internal(shost->transportt);
 	
-	return &i->t.host_attrs == cont;
+	return &i->t.host_attrs.ac == cont;
 }
 
 static int spi_device_configure(struct device *dev)
@@ -174,8 +219,11 @@ static int spi_setup_transport_attrs(str
 	struct scsi_target *starget = to_scsi_target(dev);
 
 	spi_period(starget) = -1;	/* illegal value */
+	spi_min_period(starget) = 0;
 	spi_offset(starget) = 0;	/* async */
+	spi_max_offset(starget) = 255;
 	spi_width(starget) = 0;	/* narrow */
+	spi_max_width(starget) = 1;
 	spi_iu(starget) = 0;	/* no IU */
 	spi_dt(starget) = 0;	/* ST */
 	spi_qas(starget) = 0;
@@ -190,6 +238,34 @@ static int spi_setup_transport_attrs(str
 	return 0;
 }
 
+#define spi_transport_show_simple(field, format_string)			\
+									\
+static ssize_t								\
+show_spi_transport_##field(struct class_device *cdev, char *buf)	\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct spi_transport_attrs *tp;					\
+									\
+	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
+	return snprintf(buf, 20, format_string, tp->field);		\
+}
+
+#define spi_transport_store_simple(field, format_string)		\
+									\
+static ssize_t								\
+store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+			    size_t count)				\
+{									\
+	int val;							\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct spi_transport_attrs *tp;					\
+									\
+	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
+	val = simple_strtoul(buf, NULL, 0);				\
+	tp->field = val;						\
+	return count;							\
+}
+
 #define spi_transport_show_function(field, format_string)		\
 									\
 static ssize_t								\
@@ -216,6 +292,25 @@ store_spi_transport_##field(struct class
 	struct spi_internal *i = to_spi_internal(shost->transportt);	\
 									\
 	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_##field(starget, val);			\
+	return count;							\
+}
+
+#define spi_transport_store_max(field, format_string)			\
+static ssize_t								\
+store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+			    size_t count)				\
+{									\
+	int val;							\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct spi_internal *i = to_spi_internal(shost->transportt);	\
+	struct spi_transport_attrs *tp					\
+		= (struct spi_transport_attrs *)&starget->starget_data;	\
+									\
+	val = simple_strtoul(buf, NULL, 0);				\
+	if (val > tp->max_##field)					\
+		val = tp->max_##field;					\
 	i->f->set_##field(starget, val);				\
 	return count;							\
 }
@@ -227,9 +322,24 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO 
 			 show_spi_transport_##field,			\
 			 store_spi_transport_##field);
 
+#define spi_transport_simple_attr(field, format_string)			\
+	spi_transport_show_simple(field, format_string)			\
+	spi_transport_store_simple(field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+			 show_spi_transport_##field,			\
+			 store_spi_transport_##field);
+
+#define spi_transport_max_attr(field, format_string)			\
+	spi_transport_show_function(field, format_string)		\
+	spi_transport_store_max(field, format_string)			\
+	spi_transport_simple_attr(max_##field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+			 show_spi_transport_##field,			\
+			 store_spi_transport_##field);
+
 /* The Parallel SCSI Tranport Attributes: */
-spi_transport_rd_attr(offset, "%d\n");
-spi_transport_rd_attr(width, "%d\n");
+spi_transport_max_attr(offset, "%d\n");
+spi_transport_max_attr(width, "%d\n");
 spi_transport_rd_attr(iu, "%d\n");
 spi_transport_rd_attr(dt, "%d\n");
 spi_transport_rd_attr(qas, "%d\n");
@@ -255,36 +365,81 @@ static CLASS_DEVICE_ATTR(revalidate, S_I
 
 /* Translate the period into ns according to the current spec
  * for SDTR/PPR messages */
-static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)
-
+static ssize_t
+show_spi_transport_period_helper(struct class_device *cdev, char *buf,
+				 int period)
 {
-	struct scsi_target *starget = transport_class_to_starget(cdev);
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct spi_transport_attrs *tp;
-	const char *str;
-	struct spi_internal *i = to_spi_internal(shost->transportt);
+	int len, picosec;
 
-	tp = (struct spi_transport_attrs *)&starget->starget_data;
+	if (period < 0 || period > 0xff) {
+		picosec = -1;
+	} else if (period <= SPI_STATIC_PPR) {
+		picosec = ppr_to_ps[period];
+	} else {
+		picosec = period * 4000;
+	}
 
-	if (i->f->get_period)
-		i->f->get_period(starget);
+	if (picosec == -1) {
+		len = sprintf(buf, "reserved");
+	} else {
+		len = sprint_frac(buf, picosec, 1000);
+	}
+
+	buf[len++] = '\n';
+	buf[len] = '\0';
+	return len;
+}
+
+static ssize_t
+store_spi_transport_period_helper(struct class_device *cdev, const char *buf,
+				  size_t count, int *periodp)
+{
+	int j, picosec, period = -1;
+	char *endp;
 
-	switch(tp->period) {
+	picosec = simple_strtoul(buf, &endp, 10) * 1000;
+	if (*endp == '.') {
+		int mult = 100;
+		do {
+			endp++;
+			if (!isdigit(*endp))
+				break;
+			picosec += (*endp - '0') * mult;
+			mult /= 10;
+		} while (mult > 0);
+	}
 
-	case 0x07 ... SPI_STATIC_PPR:
-		str = ppr_to_ns[tp->period];
-		if(!str)
-			str = "reserved";
+	for (j = 0; j <= SPI_STATIC_PPR; j++) {
+		if (ppr_to_ps[j] < picosec)
+			continue;
+		period = j;
 		break;
+	}
 
+	if (period == -1)
+		period = picosec / 4000;
 
-	case (SPI_STATIC_PPR+1) ... 0xff:
-		return sprintf(buf, "%d\n", tp->period * 4);
+	if (period > 0xff)
+		period = 0xff;
 
-	default:
-		str = "unknown";
-	}
-	return sprintf(buf, "%s\n", str);
+	*periodp = period;
+
+	return count;
+}
+
+static ssize_t
+show_spi_transport_period(struct class_device *cdev, char *buf)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+	struct spi_transport_attrs *tp =
+		(struct spi_transport_attrs *)&starget->starget_data;
+
+	if (i->f->get_period)
+		i->f->get_period(starget);
+
+	return show_spi_transport_period_helper(cdev, buf, tp->period);
 }
 
 static ssize_t
@@ -294,46 +449,51 @@ store_spi_transport_period(struct class_
 	struct scsi_target *starget = transport_class_to_starget(cdev);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct spi_internal *i = to_spi_internal(shost->transportt);
-	int j, period = -1;
+	struct spi_transport_attrs *tp =
+		(struct spi_transport_attrs *)&starget->starget_data;
+	int period, retval;
 
-	for (j = 0; j < SPI_STATIC_PPR; j++) {
-		int len;
+	retval = store_spi_transport_period_helper(cdev, buf, count, &period);
 
-		if(ppr_to_ns[j] == NULL)
-			continue;
+	if (period < tp->min_period)
+		period = tp->min_period;
 
-		len = strlen(ppr_to_ns[j]);
+	i->f->set_period(starget, period);
 
-		if(strncmp(ppr_to_ns[j], buf, len) != 0)
-			continue;
+	return retval;
+}
 
-		if(buf[len] != '\n')
-			continue;
-		
-		period = j;
-		break;
-	}
+static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
+			 show_spi_transport_period,
+			 store_spi_transport_period);
 
-	if (period == -1) {
-		int val = simple_strtoul(buf, NULL, 0);
+static ssize_t
+show_spi_transport_min_period(struct class_device *cdev, char *buf)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct spi_transport_attrs *tp =
+		(struct spi_transport_attrs *)&starget->starget_data;
 
+	return show_spi_transport_period_helper(cdev, buf, tp->min_period);
+}
 
-		/* Should probably check limits here, but this
-		 * gets reasonably close to OK for most things */
-		period = val/4;
-	}
+static ssize_t
+store_spi_transport_min_period(struct class_device *cdev, const char *buf,
+			    size_t count)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct spi_transport_attrs *tp =
+		(struct spi_transport_attrs *)&starget->starget_data;
 
-	if (period > 0xff)
-		period = 0xff;
+	return store_spi_transport_period_helper(cdev, buf, count,
+						 &tp->min_period);
+}
 
-	i->f->set_period(starget, period);
 
-	return count;
-}
-	
-static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
-			 show_spi_transport_period,
-			 store_spi_transport_period);
+static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 
+			 show_spi_transport_min_period,
+			 store_spi_transport_min_period);
+
 
 static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf)
 {
@@ -365,11 +525,6 @@ static CLASS_DEVICE_ATTR(signalling, S_I
 	if(i->f->set_##x)		\
 		i->f->set_##x(sdev->sdev_target, y)
 
-#define DV_LOOPS	3
-#define DV_TIMEOUT	(10*HZ)
-#define DV_RETRIES	3	/* should only need at most 
-				 * two cc/ua clears */
-
 enum spi_compare_returns {
 	SPI_COMPARE_SUCCESS,
 	SPI_COMPARE_FAILURE,
@@ -433,8 +588,7 @@ spi_dv_device_echo_buffer(struct scsi_re
 	for (r = 0; r < retries; r++) {
 		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
 		sreq->sr_data_direction = DMA_TO_DEVICE;
-		scsi_wait_req(sreq, spi_write_buffer, buffer, len,
-			      DV_TIMEOUT, DV_RETRIES);
+		spi_wait_req(sreq, spi_write_buffer, buffer, len);
 		if(sreq->sr_result || !scsi_device_online(sdev)) {
 			struct scsi_sense_hdr sshdr;
 
@@ -458,8 +612,7 @@ spi_dv_device_echo_buffer(struct scsi_re
 		memset(ptr, 0, len);
 		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
 		sreq->sr_data_direction = DMA_FROM_DEVICE;
-		scsi_wait_req(sreq, spi_read_buffer, ptr, len,
-			      DV_TIMEOUT, DV_RETRIES);
+		spi_wait_req(sreq, spi_read_buffer, ptr, len);
 		scsi_device_set_state(sdev, SDEV_QUIESCE);
 
 		if (memcmp(buffer, ptr, len) != 0)
@@ -487,8 +640,7 @@ spi_dv_device_compare_inquiry(struct scs
 
 		memset(ptr, 0, len);
 
-		scsi_wait_req(sreq, spi_inquiry, ptr, len,
-			      DV_TIMEOUT, DV_RETRIES);
+		spi_wait_req(sreq, spi_inquiry, ptr, len);
 		
 		if(sreq->sr_result || !scsi_device_online(sdev)) {
 			scsi_device_set_state(sdev, SDEV_QUIESCE);
@@ -580,8 +732,7 @@ spi_dv_device_get_echo_buffer(struct scs
 	 * (reservation conflict, device not ready, etc) just
 	 * skip the write tests */
 	for (l = 0; ; l++) {
-		scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0,
-			      DV_TIMEOUT, DV_RETRIES);
+		spi_wait_req(sreq, spi_test_unit_ready, NULL, 0);
 
 		if(sreq->sr_result) {
 			if(l >= 3)
@@ -595,8 +746,7 @@ spi_dv_device_get_echo_buffer(struct scs
 	sreq->sr_cmd_len = 0;
 	sreq->sr_data_direction = DMA_FROM_DEVICE;
 
-	scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4,
-		      DV_TIMEOUT, DV_RETRIES);
+	spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4);
 
 	if (sreq->sr_result)
 		/* Device has no echo buffer */
@@ -610,6 +760,7 @@ spi_dv_device_internal(struct scsi_reque
 {
 	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
 	struct scsi_device *sdev = sreq->sr_device;
+	struct scsi_target *starget = sdev->sdev_target;
 	int len = sdev->inquiry_len;
 	/* first set us up for narrow async */
 	DV_SET(offset, 0);
@@ -623,9 +774,11 @@ spi_dv_device_internal(struct scsi_reque
 	}
 
 	/* test width */
-	if (i->f->set_width && sdev->wdtr) {
+	if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) {
 		i->f->set_width(sdev->sdev_target, 1);
 
+		printk("WIDTH IS %d\n", spi_max_width(starget));
+
 		if (spi_dv_device_compare_inquiry(sreq, buffer,
 						   buffer + len,
 						   DV_LOOPS)
@@ -652,8 +805,8 @@ spi_dv_device_internal(struct scsi_reque
  retry:
 
 	/* now set up to the maximum */
-	DV_SET(offset, 255);
-	DV_SET(period, 1);
+	DV_SET(offset, spi_max_offset(starget));
+	DV_SET(period, spi_min_period(starget));
 
 	if (len == 0) {
 		SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n");
@@ -795,6 +948,61 @@ spi_schedule_dv_device(struct scsi_devic
 }
 EXPORT_SYMBOL(spi_schedule_dv_device);
 
+/**
+ * spi_display_xfer_agreement - Print the current target transfer agreement
+ * @starget: The target for which to display the agreement
+ *
+ * Each SPI port is required to maintain a transfer agreement for each
+ * other port on the bus.  This function prints a one-line summary of
+ * the current agreement; more detailed information is available in sysfs.
+ */
+void spi_display_xfer_agreement(struct scsi_target *starget)
+{
+	struct spi_transport_attrs *tp;
+	tp = (struct spi_transport_attrs *)&starget->starget_data;
+
+	if (tp->offset > 0 && tp->period > 0) {
+		unsigned int picosec, kb100;
+		char *scsi = "FAST-?";
+		char tmp[8];
+
+		if (tp->period <= SPI_STATIC_PPR) {
+			picosec = ppr_to_ps[tp->period];
+			switch (tp->period) {
+				case  7: scsi = "FAST-320"; break;
+				case  8: scsi = "FAST-160"; break;
+				case  9: scsi = "FAST-80"; break;
+				case 10:
+				case 11: scsi = "FAST-40"; break;
+				case 12: scsi = "FAST-20"; break;
+			}
+		} else {
+			picosec = tp->period * 4000;
+			if (tp->period < 25)
+				scsi = "FAST-20";
+			else if (tp->period < 50)
+				scsi = "FAST-10";
+			else
+				scsi = "FAST-5";
+		}
+
+		kb100 = (10000000 + picosec / 2) / picosec;
+		if (tp->width)
+			kb100 *= 2;
+		sprint_frac(tmp, picosec, 1000);
+
+		dev_info(&starget->dev,
+			"%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n",
+			scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
+			tp->dt ? "DT" : "ST", tp->iu ? " IU" : "",
+			tp->qas  ? " QAS" : "", tmp, tp->offset);
+	} else {
+		dev_info(&starget->dev, "%sasynchronous.\n",
+				tp->width ? "wide " : "");
+	}
+}
+EXPORT_SYMBOL(spi_display_xfer_agreement);
+
 #define SETUP_ATTRIBUTE(field)						\
 	i->private_attrs[count] = class_device_attr_##field;		\
 	if (!i->f->set_##field) {					\
@@ -805,6 +1013,16 @@ EXPORT_SYMBOL(spi_schedule_dv_device);
 	if (i->f->show_##field)						\
 		count++
 
+#define SETUP_RELATED_ATTRIBUTE(field, rel_field)			\
+	i->private_attrs[count] = class_device_attr_##field;		\
+	if (!i->f->set_##rel_field) {					\
+		i->private_attrs[count].attr.mode = S_IRUGO;		\
+		i->private_attrs[count].store = NULL;			\
+	}								\
+	i->attrs[count] = &i->private_attrs[count];			\
+	if (i->f->show_##rel_field)					\
+		count++
+
 #define SETUP_HOST_ATTRIBUTE(field)					\
 	i->private_host_attrs[count] = class_device_attr_##field;	\
 	if (!i->f->set_##field) {					\
@@ -825,7 +1043,7 @@ static int spi_device_match(struct attri
 
 	sdev = to_scsi_device(dev);
 	shost = sdev->host;
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &spi_host_class.class)
 		return 0;
 	/* Note: this class has no device attributes, so it has
@@ -844,13 +1062,13 @@ static int spi_target_match(struct attri
 		return 0;
 
 	shost = dev_to_shost(dev->parent);
-	if (!shost->transportt  || shost->transportt->host_attrs.class
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
 	    != &spi_host_class.class)
 		return 0;
 
 	i = to_spi_internal(shost->transportt);
 	
-	return &i->t.target_attrs == cont;
+	return &i->t.target_attrs.ac == cont;
 }
 
 static DECLARE_TRANSPORT_CLASS(spi_transport_class,
@@ -875,21 +1093,24 @@ spi_attach_transport(struct spi_function
 	memset(i, 0, sizeof(struct spi_internal));
 
 
-	i->t.target_attrs.class = &spi_transport_class.class;
-	i->t.target_attrs.attrs = &i->attrs[0];
-	i->t.target_attrs.match = spi_target_match;
-	attribute_container_register(&i->t.target_attrs);
+	i->t.target_attrs.ac.class = &spi_transport_class.class;
+	i->t.target_attrs.ac.attrs = &i->attrs[0];
+	i->t.target_attrs.ac.match = spi_target_match;
+	transport_container_register(&i->t.target_attrs);
 	i->t.target_size = sizeof(struct spi_transport_attrs);
-	i->t.host_attrs.class = &spi_host_class.class;
-	i->t.host_attrs.attrs = &i->host_attrs[0];
-	i->t.host_attrs.match = spi_host_match;
-	attribute_container_register(&i->t.host_attrs);
+	i->t.host_attrs.ac.class = &spi_host_class.class;
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.match = spi_host_match;
+	transport_container_register(&i->t.host_attrs);
 	i->t.host_size = sizeof(struct spi_host_attrs);
 	i->f = ft;
 
 	SETUP_ATTRIBUTE(period);
+	SETUP_RELATED_ATTRIBUTE(min_period, period);
 	SETUP_ATTRIBUTE(offset);
+	SETUP_RELATED_ATTRIBUTE(max_offset, offset);
 	SETUP_ATTRIBUTE(width);
+	SETUP_RELATED_ATTRIBUTE(max_width, width);
 	SETUP_ATTRIBUTE(iu);
 	SETUP_ATTRIBUTE(dt);
 	SETUP_ATTRIBUTE(qas);
@@ -921,8 +1142,8 @@ void spi_release_transport(struct scsi_t
 {
 	struct spi_internal *i = to_spi_internal(t);
 
-	attribute_container_unregister(&i->t.target_attrs);
-	attribute_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
 
 	kfree(i);
 }
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -122,6 +122,8 @@ static void sd_shutdown(struct device *d
 static void sd_rescan(struct device *);
 static int sd_init_command(struct scsi_cmnd *);
 static int sd_issue_flush(struct device *, sector_t *);
+static void sd_end_flush(request_queue_t *, struct request *);
+static int sd_prepare_flush(request_queue_t *, struct request *);
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
 		 struct scsi_request *SRpnt, unsigned char *buffer);
 
@@ -136,6 +138,8 @@ static struct scsi_driver sd_template = 
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
 	.issue_flush		= sd_issue_flush,
+	.prepare_flush		= sd_prepare_flush,
+	.end_flush		= sd_end_flush,
 };
 
 /*
@@ -735,17 +739,95 @@ static int sd_issue_flush(struct device 
 	return sd_sync_cache(sdp);
 }
 
+static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
+{
+	struct request *rq = flush_rq->end_io_data;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned int bytes = rq->hard_nr_sectors << 9;
+
+	if (!flush_rq->errors) {
+		spin_unlock(q->queue_lock);
+		scsi_io_completion(cmd, bytes, 0);
+		spin_lock(q->queue_lock);
+	} else if (blk_barrier_postflush(rq)) {
+		spin_unlock(q->queue_lock);
+		scsi_io_completion(cmd, 0, bytes);
+		spin_lock(q->queue_lock);
+	} else {
+		/*
+		 * force journal abort of barriers
+		 */
+		end_that_request_first(rq, -EOPNOTSUPP, rq->hard_nr_sectors);
+		end_that_request_last(rq);
+	}
+}
+
+static int sd_prepare_flush(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
+
+	if (sdkp->WCE) {
+		memset(rq->cmd, 0, sizeof(rq->cmd));
+		rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+		rq->timeout = SD_TIMEOUT;
+		rq->cmd[0] = SYNCHRONIZE_CACHE;
+		return 1;
+	}
+
+	return 0;
+}
+
 static void sd_rescan(struct device *dev)
 {
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
 	sd_revalidate_disk(sdkp->disk);
 }
 
+
+#ifdef CONFIG_COMPAT
+/* 
+ * This gets directly called from VFS. When the ioctl 
+ * is not recognized we go back to the other translation paths. 
+ */
+static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+	struct gendisk *disk = bdev->bd_disk;
+	struct scsi_device *sdev = scsi_disk(disk)->device;
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(sdev))
+		return -ENODEV;
+	       
+	if (sdev->host->hostt->compat_ioctl) {
+		int ret;
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+
+		return ret;
+	}
+
+	/* 
+	 * Let the static ioctl translation table take care of it.
+	 */
+	return -ENOIOCTLCMD; 
+}
+#endif
+
 static struct block_device_operations sd_fops = {
 	.owner			= THIS_MODULE,
 	.open			= sd_open,
 	.release		= sd_release,
 	.ioctl			= sd_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sd_compat_ioctl,
+#endif
 	.media_changed		= sd_media_changed,
 	.revalidate_disk	= sd_revalidate_disk,
 };
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -103,6 +103,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include "seagate.h"
 
@@ -746,7 +747,7 @@ static int internal_command (unsigned ch
 
 #if (DEBUG & PRINT_COMMAND)
 	printk("scsi%d : target = %d, command = ", hostno, target);
-	print_command((unsigned char *) cmnd);
+	__scsi_print_command((unsigned char *) cmnd);
 #endif
 
 #if (DEBUG & PHASE_RESELECT)
@@ -1553,7 +1554,7 @@ connect_loop:
 	printk("\n");
 #endif
 	printk("scsi%d : status = ", hostno);
-	print_status(status);
+	scsi_print_status(status);
 	printk(" message = %02x\n", message);
 #endif
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -18,8 +18,8 @@
  *
  */
 
-static int sg_version_num = 30532;	/* 2 digits for each component */
-#define SG_VERSION_STR "3.5.32"
+static int sg_version_num = 30533;	/* 2 digits for each component */
+#define SG_VERSION_STR "3.5.33"
 
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
@@ -51,6 +51,7 @@ static int sg_version_num = 30532;	/* 2 
 #include <linux/delay.h>
 
 #include "scsi.h"
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>
@@ -60,7 +61,7 @@ static int sg_version_num = 30532;	/* 2 
 
 #ifdef CONFIG_SCSI_PROC_FS
 #include <linux/proc_fs.h>
-static char *sg_version_date = "20050117";
+static char *sg_version_date = "20050328";
 
 static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
@@ -330,114 +331,153 @@ sg_release(struct inode *inode, struct f
 static ssize_t
 sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 {
-	int k, res;
 	Sg_device *sdp;
 	Sg_fd *sfp;
 	Sg_request *srp;
 	int req_pack_id = -1;
-	struct sg_header old_hdr;
-	sg_io_hdr_t new_hdr;
 	sg_io_hdr_t *hp;
+	struct sg_header *old_hdr = NULL;
+	int retval = 0;
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n",
 				   sdp->disk->disk_name, (int) count));
-	if ((k = verify_area(VERIFY_WRITE, buf, count)))
-		return k;
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
 	if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
-		if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
-			return -EFAULT;
-		if (old_hdr.reply_len < 0) {
+		old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
+		if (!old_hdr)
+			return -ENOMEM;
+		if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) {
+			retval = -EFAULT;
+			goto free_old_hdr;
+		}
+		if (old_hdr->reply_len < 0) {
 			if (count >= SZ_SG_IO_HDR) {
-				if (__copy_from_user
-				    (&new_hdr, buf, SZ_SG_IO_HDR))
-					return -EFAULT;
-				req_pack_id = new_hdr.pack_id;
+				sg_io_hdr_t *new_hdr;
+				new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL);
+				if (!new_hdr) {
+					retval = -ENOMEM;
+					goto free_old_hdr;
+				}
+				retval =__copy_from_user
+				    (new_hdr, buf, SZ_SG_IO_HDR);
+				req_pack_id = new_hdr->pack_id;
+				kfree(new_hdr);
+				if (retval) {
+					retval = -EFAULT;
+					goto free_old_hdr;
+				}
 			}
 		} else
-			req_pack_id = old_hdr.pack_id;
+			req_pack_id = old_hdr->pack_id;
 	}
 	srp = sg_get_rq_mark(sfp, req_pack_id);
 	if (!srp) {		/* now wait on packet to arrive */
-		if (sdp->detached)
-			return -ENODEV;
-		if (filp->f_flags & O_NONBLOCK)
-			return -EAGAIN;
+		if (sdp->detached) {
+			retval = -ENODEV;
+			goto free_old_hdr;
+		}
+		if (filp->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto free_old_hdr;
+		}
 		while (1) {
-			res = 0;	/* following is a macro that beats race condition */
+			retval = 0; /* following macro beats race condition */
 			__wait_event_interruptible(sfp->read_wait,
-				(sdp->detached || (srp = sg_get_rq_mark(sfp, req_pack_id))), 
-						   res);
-			if (sdp->detached)
-				return -ENODEV;
-			if (0 == res)
+				(sdp->detached ||
+				(srp = sg_get_rq_mark(sfp, req_pack_id))), 
+				retval);
+			if (sdp->detached) {
+				retval = -ENODEV;
+				goto free_old_hdr;
+			}
+			if (0 == retval)
 				break;
-			return res;	/* -ERESTARTSYS because signal hit process */
+
+			/* -ERESTARTSYS as signal hit process */
+			goto free_old_hdr;
 		}
 	}
-	if (srp->header.interface_id != '\0')
-		return sg_new_read(sfp, buf, count, srp);
+	if (srp->header.interface_id != '\0') {
+		retval = sg_new_read(sfp, buf, count, srp);
+		goto free_old_hdr;
+	}
 
 	hp = &srp->header;
-	memset(&old_hdr, 0, SZ_SG_HEADER);
-	old_hdr.reply_len = (int) hp->timeout;
-	old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */
-	old_hdr.pack_id = hp->pack_id;
-	old_hdr.twelve_byte =
+	if (old_hdr == NULL) {
+		old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
+		if (! old_hdr) {
+			retval = -ENOMEM;
+			goto free_old_hdr;
+		}
+	}
+	memset(old_hdr, 0, SZ_SG_HEADER);
+	old_hdr->reply_len = (int) hp->timeout;
+	old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */
+	old_hdr->pack_id = hp->pack_id;
+	old_hdr->twelve_byte =
 	    ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0;
-	old_hdr.target_status = hp->masked_status;
-	old_hdr.host_status = hp->host_status;
-	old_hdr.driver_status = hp->driver_status;
+	old_hdr->target_status = hp->masked_status;
+	old_hdr->host_status = hp->host_status;
+	old_hdr->driver_status = hp->driver_status;
 	if ((CHECK_CONDITION & hp->masked_status) ||
 	    (DRIVER_SENSE & hp->driver_status))
-		memcpy(old_hdr.sense_buffer, srp->sense_b,
-		       sizeof (old_hdr.sense_buffer));
+		memcpy(old_hdr->sense_buffer, srp->sense_b,
+		       sizeof (old_hdr->sense_buffer));
 	switch (hp->host_status) {
 	/* This setup of 'result' is for backward compatibility and is best
 	   ignored by the user who should use target, host + driver status */
 	case DID_OK:
 	case DID_PASSTHROUGH:
 	case DID_SOFT_ERROR:
-		old_hdr.result = 0;
+		old_hdr->result = 0;
 		break;
 	case DID_NO_CONNECT:
 	case DID_BUS_BUSY:
 	case DID_TIME_OUT:
-		old_hdr.result = EBUSY;
+		old_hdr->result = EBUSY;
 		break;
 	case DID_BAD_TARGET:
 	case DID_ABORT:
 	case DID_PARITY:
 	case DID_RESET:
 	case DID_BAD_INTR:
-		old_hdr.result = EIO;
+		old_hdr->result = EIO;
 		break;
 	case DID_ERROR:
-		old_hdr.result = (srp->sense_b[0] == 0 && 
+		old_hdr->result = (srp->sense_b[0] == 0 && 
 				  hp->masked_status == GOOD) ? 0 : EIO;
 		break;
 	default:
-		old_hdr.result = EIO;
+		old_hdr->result = EIO;
 		break;
 	}
 
 	/* Now copy the result back to the user buffer.  */
 	if (count >= SZ_SG_HEADER) {
-		if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER))
-			return -EFAULT;
+		if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) {
+			retval = -EFAULT;
+			goto free_old_hdr;
+		}
 		buf += SZ_SG_HEADER;
-		if (count > old_hdr.reply_len)
-			count = old_hdr.reply_len;
+		if (count > old_hdr->reply_len)
+			count = old_hdr->reply_len;
 		if (count > SZ_SG_HEADER) {
-			if ((res =
-			     sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)))
-				return -EFAULT;
+			if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) {
+				retval = -EFAULT;
+				goto free_old_hdr;
+			}
 		}
 	} else
-		count = (old_hdr.result == 0) ? 0 : -EIO;
+		count = (old_hdr->result == 0) ? 0 : -EIO;
 	sg_finish_rem_req(srp);
-	return count;
+	retval = count;
+free_old_hdr:
+	if (old_hdr)
+		kfree(old_hdr);
+	return retval;
 }
 
 static ssize_t
@@ -501,8 +541,8 @@ sg_write(struct file *filp, const char _
 	      scsi_block_when_processing_errors(sdp->device)))
 		return -ENXIO;
 
-	if ((k = verify_area(VERIFY_READ, buf, count)))
-		return k;	/* protects following copy_from_user()s + get_user()s */
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
 	if (count < SZ_SG_HEADER)
 		return -EIO;
 	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
@@ -594,8 +634,8 @@ sg_new_write(Sg_fd * sfp, const char __u
 
 	if (count < SZ_SG_IO_HDR)
 		return -EINVAL;
-	if ((k = verify_area(VERIFY_READ, buf, count)))
-		return k; /* protects following copy_from_user()s + get_user()s */
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT; /* protects following copy_from_user()s + get_user()s */
 
 	sfp->cmd_q = 1;	/* when sg_io_hdr seen, set command queuing on */
 	if (!(srp = sg_add_request(sfp))) {
@@ -631,9 +671,9 @@ sg_new_write(Sg_fd * sfp, const char __u
 		sg_remove_request(sfp, srp);
 		return -EMSGSIZE;
 	}
-	if ((k = verify_area(VERIFY_READ, hp->cmdp, hp->cmd_len))) {
+	if (!access_ok(VERIFY_READ, hp->cmdp, hp->cmd_len)) {
 		sg_remove_request(sfp, srp);
-		return k;	/* protects following copy_from_user()s + get_user()s */
+		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
 	}
 	if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
 		sg_remove_request(sfp, srp);
@@ -707,16 +747,16 @@ sg_common_write(Sg_fd * sfp, Sg_request 
 	switch (hp->dxfer_direction) {
 	case SG_DXFER_TO_FROM_DEV:
 	case SG_DXFER_FROM_DEV:
-		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		SRpnt->sr_data_direction = DMA_FROM_DEVICE;
 		break;
 	case SG_DXFER_TO_DEV:
-		SRpnt->sr_data_direction = SCSI_DATA_WRITE;
+		SRpnt->sr_data_direction = DMA_TO_DEVICE;
 		break;
 	case SG_DXFER_UNKNOWN:
-		SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+		SRpnt->sr_data_direction = DMA_BIDIRECTIONAL;
 		break;
 	default:
-		SRpnt->sr_data_direction = SCSI_DATA_NONE;
+		SRpnt->sr_data_direction = DMA_NONE;
 		break;
 	}
 	SRpnt->upper_private_data = srp;
@@ -724,7 +764,7 @@ sg_common_write(Sg_fd * sfp, Sg_request 
 	srp->data.sglist_len = 0;
 	srp->data.bufflen = 0;
 	srp->data.buffer = NULL;
-	hp->duration = jiffies;	/* unit jiffies now, millisecs after done */
+	hp->duration = jiffies_to_msecs(jiffies);
 /* Now send everything of to mid-level. The next time we hear about this
    packet is when sg_cmd_done() is called (i.e. a callback). */
 	scsi_do_req(SRpnt, (void *) cmnd,
@@ -773,9 +813,8 @@ sg_ioctl(struct inode *inode, struct fil
 				return -ENODEV;
 			if (!scsi_block_when_processing_errors(sdp->device))
 				return -ENXIO;
-			result = verify_area(VERIFY_WRITE, p, SZ_SG_IO_HDR);
-			if (result)
-				return result;
+			if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
+				return -EFAULT;
 			result =
 			    sg_new_write(sfp, p, SZ_SG_IO_HDR,
 					 blocking, read_only, &srp);
@@ -837,10 +876,8 @@ sg_ioctl(struct inode *inode, struct fil
 	case SG_GET_LOW_DMA:
 		return put_user((int) sfp->low_dma, ip);
 	case SG_GET_SCSI_ID:
-		result =
-		    verify_area(VERIFY_WRITE, p, sizeof (sg_scsi_id_t));
-		if (result)
-			return result;
+		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
+			return -EFAULT;
 		else {
 			sg_scsi_id_t __user *sg_idp = p;
 
@@ -868,9 +905,8 @@ sg_ioctl(struct inode *inode, struct fil
 		sfp->force_packid = val ? 1 : 0;
 		return 0;
 	case SG_GET_PACK_ID:
-		result = verify_area(VERIFY_WRITE, ip, sizeof (int));
-		if (result)
-			return result;
+		if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
+			return -EFAULT;
 		read_lock_irqsave(&sfp->rq_list_lock, iflags);
 		for (srp = sfp->headrp; srp; srp = srp->nextrp) {
 			if ((1 == srp->done) && (!srp->sg_io_owned)) {
@@ -938,13 +974,16 @@ sg_ioctl(struct inode *inode, struct fil
 		val = (sdp->device ? 1 : 0);
 		return put_user(val, ip);
 	case SG_GET_REQUEST_TABLE:
-		result = verify_area(VERIFY_WRITE, p,
-				     SZ_SG_REQ_INFO * SG_MAX_QUEUE);
-		if (result)
-			return result;
+		if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
+			return -EFAULT;
 		else {
-			sg_req_info_t rinfo[SG_MAX_QUEUE];
-			Sg_request *srp;
+			sg_req_info_t *rinfo;
+			unsigned int ms;
+
+			rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+								GFP_KERNEL);
+			if (!rinfo)
+				return -ENOMEM;
 			read_lock_irqsave(&sfp->rq_list_lock, iflags);
 			for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
 			     ++val, srp = srp ? srp->nextrp : srp) {
@@ -955,19 +994,30 @@ sg_ioctl(struct inode *inode, struct fil
 					    srp->header.masked_status & 
 					    srp->header.host_status & 
 					    srp->header.driver_status;
-					rinfo[val].duration =
-					    srp->done ? srp->header.duration :
-					    jiffies_to_msecs(
-						jiffies - srp->header.duration);
+					if (srp->done)
+						rinfo[val].duration =
+							srp->header.duration;
+					else {
+						ms = jiffies_to_msecs(jiffies);
+						rinfo[val].duration =
+						    (ms > srp->header.duration) ?
+						    (ms - srp->header.duration) : 0;
+					}
 					rinfo[val].orphan = srp->orphan;
-					rinfo[val].sg_io_owned = srp->sg_io_owned;
-					rinfo[val].pack_id = srp->header.pack_id;
-					rinfo[val].usr_ptr = srp->header.usr_ptr;
+					rinfo[val].sg_io_owned =
+							srp->sg_io_owned;
+					rinfo[val].pack_id =
+							srp->header.pack_id;
+					rinfo[val].usr_ptr =
+							srp->header.usr_ptr;
 				}
 			}
 			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-			return (__copy_to_user(p, rinfo,
-			        SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0);
+			result = __copy_to_user(p, rinfo, 
+						SZ_SG_REQ_INFO * SG_MAX_QUEUE);
+			result = result ? -EFAULT : 0;
+			kfree(rinfo);
+			return result;
 		}
 	case SG_EMULATED_HOST:
 		if (sdp->detached)
@@ -1037,6 +1087,29 @@ sg_ioctl(struct inode *inode, struct fil
 	}
 }
 
+#ifdef CONFIG_COMPAT
+static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+{
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	struct scsi_device *sdev;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+
+	sdev = sdp->device;
+	if (sdev->host->hostt->compat_ioctl) { 
+		int ret;
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
+
+		return ret;
+	}
+	
+	return -ENOIOCTLCMD;
+}
+#endif
+
 static unsigned int
 sg_poll(struct file *filp, poll_table * wait)
 {
@@ -1191,11 +1264,12 @@ static int
 sg_mmap(struct file *filp, struct vm_area_struct *vma)
 {
 	Sg_fd *sfp;
-	unsigned long req_sz = vma->vm_end - vma->vm_start;
+	unsigned long req_sz;
 	Sg_scatter_hold *rsv_schp;
 
 	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
 		return -ENXIO;
+	req_sz = vma->vm_end - vma->vm_start;
 	SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n",
 				   (void *) vma->vm_start, (int) req_sz));
 	if (vma->vm_pgoff)
@@ -1242,6 +1316,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt)
 	Sg_fd *sfp;
 	Sg_request *srp = NULL;
 	unsigned long iflags;
+	unsigned int ms;
 
 	if (SCpnt && (SRpnt = SCpnt->sc_request))
 		srp = (Sg_request *) SRpnt->upper_private_data;
@@ -1278,9 +1353,9 @@ sg_cmd_done(Scsi_Cmnd * SCpnt)
 	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
 		sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result));
 	srp->header.resid = SCpnt->resid;
-	/* N.B. unit of duration changes here from jiffies to millisecs */
-	srp->header.duration =
-	    jiffies_to_msecs(jiffies - srp->header.duration);
+	ms = jiffies_to_msecs(jiffies);
+	srp->header.duration = (ms > srp->header.duration) ?
+				(ms - srp->header.duration) : 0;
 	if (0 != SRpnt->sr_result) {
 		struct scsi_sense_hdr sshdr;
 
@@ -1294,7 +1369,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt)
 		if ((sdp->sgdebug > 0) &&
 		    ((CHECK_CONDITION == srp->header.masked_status) ||
 		     (COMMAND_TERMINATED == srp->header.masked_status)))
-			print_req_sense("sg_cmd_done", SRpnt);
+			scsi_print_req_sense("sg_cmd_done", SRpnt);
 
 		/* Following if statement is a patch supplied by Eric Youngdale */
 		if (driver_byte(SRpnt->sr_result) != 0
@@ -1346,6 +1421,9 @@ static struct file_operations sg_fops = 
 	.write = sg_write,
 	.poll = sg_poll,
 	.ioctl = sg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = sg_compat_ioctl,
+#endif
 	.open = sg_open,
 	.mmap = sg_mmap,
 	.release = sg_release,
@@ -1959,9 +2037,8 @@ sg_write_xfer(Sg_request * srp)
 			  num_xfer, iovec_count, schp->k_use_sg));
 	if (iovec_count) {
 		onum = iovec_count;
-		if ((k = verify_area(VERIFY_READ, hp->dxferp,
-				     SZ_SG_IOVEC * onum)))
-			return k;
+		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
+			return -EFAULT;
 	} else
 		onum = 1;
 
@@ -2031,7 +2108,7 @@ sg_u_iovec(sg_io_hdr_t * hp, int sg_num,
 {
 	int num_xfer = (int) hp->dxfer_len;
 	unsigned char __user *p = hp->dxferp;
-	int count, k;
+	int count;
 
 	if (0 == sg_num) {
 		if (wr_xf && ('\0' == hp->interface_id))
@@ -2045,8 +2122,8 @@ sg_u_iovec(sg_io_hdr_t * hp, int sg_num,
 		p = iovec.iov_base;
 		count = (int) iovec.iov_len;
 	}
-	if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count)))
-		return k;
+	if (!access_ok(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))
+		return -EFAULT;
 	if (up)
 		*up = p;
 	if (countp)
@@ -2113,9 +2190,8 @@ sg_read_xfer(Sg_request * srp)
 			  num_xfer, iovec_count, schp->k_use_sg));
 	if (iovec_count) {
 		onum = iovec_count;
-		if ((k = verify_area(VERIFY_READ, hp->dxferp,
-				     SZ_SG_IOVEC * onum)))
-			return k;
+		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
+			return -EFAULT;
 	} else
 		onum = 1;
 
@@ -2377,7 +2453,7 @@ sg_add_request(Sg_fd * sfp)
 	}
 	if (resp) {
 		resp->nextrp = NULL;
-		resp->header.duration = jiffies;
+		resp->header.duration = jiffies_to_msecs(jiffies);
 		resp->my_cmdp = NULL;
 	}
 	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
@@ -2972,6 +3048,7 @@ static void sg_proc_debug_helper(struct 
 	Sg_fd *fp;
 	const sg_io_hdr_t *hp;
 	const char * cp;
+	unsigned int ms;
 
 	for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
 		seq_printf(s, "   FD(%d): timeout=%dms bufflen=%d "
@@ -3010,10 +3087,13 @@ static void sg_proc_debug_helper(struct 
 				   srp->header.pack_id, blen);
 			if (srp->done)
 				seq_printf(s, " dur=%d", hp->duration);
-			else
+			else {
+				ms = jiffies_to_msecs(jiffies);
 				seq_printf(s, " t_o/elap=%d/%d",
-				  new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout),
-				  jiffies_to_msecs(hp->duration ? (jiffies - hp->duration) : 0));
+					(new_interface ? hp->timeout :
+						  jiffies_to_msecs(fp->timeout)),
+					(ms > hp->duration ? ms - hp->duration : 0));
+			}
 			seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
 				   (int) srp->data.cmd_opcode);
 		}
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -47,7 +47,7 @@
 #define MAX_SLOTS 8
 static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
 
-char *sim710;		/* command line passed by insmod */
+static char *sim710;		/* command line passed by insmod */
 
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("Simple NCR53C710 driver");
@@ -61,7 +61,7 @@ module_param(sim710, charp, 0);
 #define ARG_SEP ','
 #endif
 
-__init int
+static __init int
 param_setup(char *str)
 {
 	char *pos = str, *next;
@@ -120,23 +120,31 @@ sim710_probe_common(struct device *dev, 
 	}
 
 	/* Fill in the three required pieces of hostdata */
-	hostdata->base = base_addr;
+	hostdata->base = ioport_map(base_addr, 64);
 	hostdata->differential = differential;
 	hostdata->clock = clock;
 	hostdata->chip710 = 1;
-	NCR_700_set_io_mapped(hostdata);
 
 	/* and register the chip */
-	if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev, irq,
-				  scsi_id)) == NULL) {
+	if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
+	   == NULL) {
 		printk(KERN_ERR "sim710: No host detected; card configuration problem?\n");
 		goto out_release;
 	}
+	host->this_id = scsi_id;
+	host->base = base_addr;
+	host->irq = irq;
+	if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "sim710", host)) {
+		printk(KERN_ERR "sim710: request_irq failed\n");
+		goto out_put_host;
+	}
 
 	scsi_scan_host(host);
 
 	return 0;
 
+ out_put_host:
+	scsi_host_put(host);
  out_release:
 	release_region(host->base, 64);
  out_free:
@@ -156,6 +164,7 @@ sim710_device_remove(struct device *dev)
 	NCR_700_release(host);
 	kfree(hostdata);
 	free_irq(host->irq, host);
+	release_region(host->base, 64);
 	return 0;
 }
 
@@ -314,7 +323,7 @@ sim710_eisa_probe(struct device *dev)
 				   differential, scsi_id);
 }
 
-struct eisa_driver sim710_eisa_driver = {
+static struct eisa_driver sim710_eisa_driver = {
 	.id_table		= sim710_eisa_ids,
 	.driver = {
 		.name		= "sim710",
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -511,13 +511,17 @@ static int sr_block_media_changed(struct
 	return cdrom_media_changed(&cd->cdi);
 }
 
-struct block_device_operations sr_bdops =
+static struct block_device_operations sr_bdops =
 {
 	.owner		= THIS_MODULE,
 	.open		= sr_block_open,
 	.release	= sr_block_release,
 	.ioctl		= sr_block_ioctl,
 	.media_changed	= sr_block_media_changed,
+	/* 
+	 * No compat_ioctl for now because sr_block_ioctl never
+	 * seems to pass arbitary ioctls down to host drivers.
+	 */
 };
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -281,6 +281,9 @@ int sr_get_mcn(struct cdrom_device_info 
 	char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
 	int result;
 
+	if (!buffer)
+		return -ENOMEM;
+
 	memset(&cgc, 0, sizeof(struct packet_command));
 	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
 	cgc.cmd[2] = 0x40;	/* I do want the subchannel info */
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2004 Kai Makisara
+   Copyright 1992 - 2005 Kai Makisara
    email Kai.Makisara@kolumbus.fi
 
    Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20041025";
+static char *verstr = "20050312";
 
 #include <linux/module.h>
 
@@ -36,6 +36,8 @@ static char *verstr = "20041025";
 #include <linux/moduleparam.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/cdev.h>
+#include <linux/delay.h>
+
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -144,7 +146,7 @@ static char *st_formats[] = {
 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
 #endif
 
-DEB( static int debugging = DEBUG; )
+static int debugging = DEBUG;
 
 #define MAX_RETRIES 0
 #define MAX_WRITE_RETRIES 0
@@ -262,25 +264,57 @@ static inline char *tape_name(struct scs
 	return tape->disk->disk_name;
 }
 
+
+static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s)
+{
+	const u8 *ucp;
+	const u8 *sense = SRpnt->sr_sense_buffer;
+
+	s->have_sense = scsi_request_normalize_sense(SRpnt, &s->sense_hdr);
+	s->flags = 0;
+
+	if (s->have_sense) {
+		s->deferred = 0;
+		s->remainder_valid =
+			scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
+		switch (sense[0] & 0x7f) {
+		case 0x71:
+			s->deferred = 1;
+		case 0x70:
+			s->fixed_format = 1;
+			s->flags = sense[2] & 0xe0;
+			break;
+		case 0x73:
+			s->deferred = 1;
+		case 0x72:
+			s->fixed_format = 0;
+			ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
+			s->flags = ucp ? (ucp[3] & 0xe0) : 0;
+			break;
+		}
+	}
+}
+
+
 /* Convert the result to success code */
 static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
 {
 	int result = SRpnt->sr_result;
-	unsigned char *sense = SRpnt->sr_sense_buffer, scode;
+	u8 scode;
 	DEB(const char *stp;)
 	char *name = tape_name(STp);
+	struct st_cmdstatus *cmdstatp;
 
-	if (!result) {
-		sense[0] = 0;	/* We don't have sense data if this byte is zero */
+	if (!result)
 		return 0;
-	}
 
-	if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
-		scode = sense[2] & 0x0f;
-	else {
-		sense[0] = 0;
+	cmdstatp = &STp->buffer->cmdstat;
+	st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp);
+
+	if (cmdstatp->have_sense)
+		scode = STp->buffer->cmdstat.sense_hdr.sense_key;
+	else
 		scode = 0;
-	}
 
         DEB(
         if (debugging) {
@@ -289,29 +323,30 @@ static int st_chk_result(struct scsi_tap
 		       SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
 		       SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
 		       SRpnt->sr_bufflen);
-		if (driver_byte(result) & DRIVER_SENSE)
-			scsi_print_req_sense("st", SRpnt);
-	} else ) /* end DEB */
-		if (!(driver_byte(result) & DRIVER_SENSE) ||
-		    ((sense[0] & 0x70) == 0x70 &&
-		     scode != NO_SENSE &&
-		     scode != RECOVERED_ERROR &&
-                     /* scode != UNIT_ATTENTION && */
-		     scode != BLANK_CHECK &&
-		     scode != VOLUME_OVERFLOW &&
-		     SRpnt->sr_cmnd[0] != MODE_SENSE &&
-		     SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) {	/* Abnormal conditions for tape */
-		if (driver_byte(result) & DRIVER_SENSE) {
-			printk(KERN_WARNING "%s: Error with sense data: ", name);
+		if (cmdstatp->have_sense)
 			scsi_print_req_sense("st", SRpnt);
-		} else
+	} ) /* end DEB */
+	if (!debugging) { /* Abnormal conditions for tape */
+		if (!cmdstatp->have_sense)
 			printk(KERN_WARNING
 			       "%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 			       name, result, suggestion(result),
-                               driver_byte(result) & DRIVER_MASK, host_byte(result));
+			       driver_byte(result) & DRIVER_MASK, host_byte(result));
+		else if (cmdstatp->have_sense &&
+			 scode != NO_SENSE &&
+			 scode != RECOVERED_ERROR &&
+			 /* scode != UNIT_ATTENTION && */
+			 scode != BLANK_CHECK &&
+			 scode != VOLUME_OVERFLOW &&
+			 SRpnt->sr_cmnd[0] != MODE_SENSE &&
+			 SRpnt->sr_cmnd[0] != TEST_UNIT_READY) {
+				printk(KERN_WARNING "%s: Error with sense data: ", name);
+				scsi_print_req_sense("st", SRpnt);
+		}
 	}
 
-	if (STp->cln_mode >= EXTENDED_SENSE_START) {
+	if (cmdstatp->fixed_format &&
+	    STp->cln_mode >= EXTENDED_SENSE_START) {  /* Only fixed format sense */
 		if (STp->cln_sense_value)
 			STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
 					       STp->cln_sense_mask) == STp->cln_sense_value);
@@ -319,12 +354,13 @@ static int st_chk_result(struct scsi_tap
 			STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
 					       STp->cln_sense_mask) != 0);
 	}
-	if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
-		STp->cleaning_req = 1;
+	if (cmdstatp->have_sense &&
+	    cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17)
+		STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */
 
 	STp->pos_unknown |= STp->device->was_reset;
 
-	if ((sense[0] & 0x70) == 0x70 &&
+	if (cmdstatp->have_sense &&
 	    scode == RECOVERED_ERROR
 #if ST_RECOVERED_WRITE_FATAL
 	    && SRpnt->sr_cmnd[0] != WRITE_6
@@ -346,7 +382,7 @@ static int st_chk_result(struct scsi_tap
 			       STp->recover_count);
 		} ) /* end DEB */
 
-		if ((sense[2] & 0xe0) == 0)
+		if (cmdstatp->flags == 0)
 			return 0;
 	}
 	return (-EIO);
@@ -356,28 +392,10 @@ static int st_chk_result(struct scsi_tap
 /* Wakeup from interrupt */
 static void st_sleep_done(struct scsi_cmnd * SCpnt)
 {
-	int remainder;
 	struct scsi_tape *STp = container_of(SCpnt->request->rq_disk->private_data,
 					     struct scsi_tape, driver);
 
-	if ((STp->buffer)->writing &&
-	    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	    (SCpnt->sense_buffer[2] & 0x40)) {
-		/* EOM at write-behind, has all been written? */
-		if ((SCpnt->sense_buffer[0] & 0x80) != 0)
-			remainder = (SCpnt->sense_buffer[3] << 24) |
-				(SCpnt->sense_buffer[4] << 16) |
-				(SCpnt->sense_buffer[5] << 8) |
-				SCpnt->sense_buffer[6];
-		else
-			remainder = 0;
-		if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
-		    remainder > 0)
-			(STp->buffer)->midlevel_result = SCpnt->result; /* Error */
-		else
-			(STp->buffer)->midlevel_result = INT_MAX;	/* OK */
-	} else
-		(STp->buffer)->midlevel_result = SCpnt->result;
+	(STp->buffer)->cmdstat.midlevel_result = SCpnt->result;
 	SCpnt->request->rq_status = RQ_SCSI_DONE;
 	(STp->buffer)->last_SRpnt = SCpnt->sc_request;
 	DEB( STp->write_pending = 0; )
@@ -421,6 +439,7 @@ st_do_scsi(struct scsi_request * SRpnt, 
 	SRpnt->sr_request->waiting = &(STp->wait);
 	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
 	SRpnt->sr_request->rq_disk = STp->disk;
+	STp->buffer->cmdstat.have_sense = 0;
 
 	scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
 		    st_sleep_done, timeout, retries);
@@ -434,13 +453,20 @@ st_do_scsi(struct scsi_request * SRpnt, 
 }
 
 
-/* Handle the write-behind checking (downs the semaphore) */
-static void write_behind_check(struct scsi_tape * STp)
+/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
+   write has been correct but EOM early warning reached, -EIO if write ended in
+   error or zero if write successful. Asynchronous writes are used only in
+   variable block mode. */
+static int write_behind_check(struct scsi_tape * STp)
 {
+	int retval = 0;
 	struct st_buffer *STbuffer;
 	struct st_partstat *STps;
+	struct st_cmdstatus *cmdstatp;
 
 	STbuffer = STp->buffer;
+	if (!STbuffer->writing)
+		return 0;
 
         DEB(
 	if (STp->write_pending)
@@ -463,9 +489,29 @@ static void write_behind_check(struct sc
 		else
 			STps->drv_block += STbuffer->writing / STp->block_size;
 	}
+
+	cmdstatp = &STbuffer->cmdstat;
+	if (STbuffer->syscall_result) {
+		retval = -EIO;
+		if (cmdstatp->have_sense && !cmdstatp->deferred &&
+		    (cmdstatp->flags & SENSE_EOM) &&
+		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {
+			/* EOM at write-behind, has all data been written? */
+			if (!cmdstatp->remainder_valid ||
+			    cmdstatp->uremainder64 == 0)
+				retval = -ENOSPC;
+		}
+		if (retval == -EIO)
+			STps->drv_block = -1;
+	}
 	STbuffer->writing = 0;
 
-	return;
+	DEB(if (debugging && retval)
+	    printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n",
+		   tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
+
+	return retval;
 }
 
 
@@ -496,7 +542,7 @@ static int cross_eof(struct scsi_tape * 
 	scsi_release_request(SRpnt);
 	SRpnt = NULL;
 
-	if ((STp->buffer)->midlevel_result != 0)
+	if ((STp->buffer)->cmdstat.midlevel_result != 0)
 		printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
 		   tape_name(STp), forward ? "forward" : "backward");
 
@@ -513,19 +559,9 @@ static int flush_write_buffer(struct scs
 	struct scsi_request *SRpnt;
 	struct st_partstat *STps;
 
-	if ((STp->buffer)->writing) {
-		write_behind_check(STp);
-		if ((STp->buffer)->syscall_result) {
-                        DEBC(printk(ST_DEB_MSG
-                                       "%s: Async write error (flush) %x.\n",
-				       tape_name(STp), (STp->buffer)->midlevel_result))
-			if ((STp->buffer)->midlevel_result == INT_MAX)
-				return (-ENOSPC);
-			return (-EIO);
-		}
-	}
-	if (STp->block_size == 0)
-		return 0;
+	result = write_behind_check(STp);
+	if (result)
+		return result;
 
 	result = 0;
 	if (STp->dirty == 1) {
@@ -553,18 +589,25 @@ static int flush_write_buffer(struct scs
 
 		STps = &(STp->ps[STp->partition]);
 		if ((STp->buffer)->syscall_result != 0) {
-			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-			    (SRpnt->sr_sense_buffer[2] & 0x40) &&
-			    (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
+			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+			if (cmdstatp->have_sense && !cmdstatp->deferred &&
+			    (cmdstatp->flags & SENSE_EOM) &&
+			    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+			     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+			    (!cmdstatp->remainder_valid ||
+			     cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
 				STp->dirty = 0;
 				(STp->buffer)->buffer_bytes = 0;
+				if (STps->drv_block >= 0)
+					STps->drv_block += blks;
 				result = (-ENOSPC);
 			} else {
 				printk(KERN_ERR "%s: Error on flush.\n",
                                        tape_name(STp));
+				STps->drv_block = (-1);
 				result = (-EIO);
 			}
-			STps->drv_block = (-1);
 		} else {
 			if (STps->drv_block >= 0)
 				STps->drv_block += blks;
@@ -728,6 +771,7 @@ static int test_ready(struct scsi_tape *
 	int retval = CHKRES_READY, new_session = 0;
 	unsigned char cmd[MAX_COMMAND_SIZE];
 	struct scsi_request *SRpnt = NULL;
+	struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
 
 	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
 
@@ -742,9 +786,9 @@ static int test_ready(struct scsi_tape *
 			break;
 		}
 
-		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+		if (cmdstatp->have_sense) {
 
-			scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+			scode = cmdstatp->sense_hdr.sense_key;
 
 			if (scode == UNIT_ATTENTION) { /* New media? */
 				new_session = 1;
@@ -760,9 +804,7 @@ static int test_ready(struct scsi_tape *
 
 			if (scode == NOT_READY) {
 				if (waits < max_wait) {
-					set_current_state(TASK_INTERRUPTIBLE);
-					schedule_timeout(HZ);
-					if (signal_pending(current)) {
+					if (msleep_interruptible(1000)) {
 						retval = (-EINTR);
 						break;
 					}
@@ -771,7 +813,7 @@ static int test_ready(struct scsi_tape *
 				}
 				else {
 					if ((STp->device)->scsi_level >= SCSI_2 &&
-					    SRpnt->sr_sense_buffer[12] == 0x3a)	/* Check ASC */
+					    cmdstatp->sense_hdr.asc == 0x3a)	/* Check ASC */
 						retval = CHKRES_NO_TAPE;
 					else
 						retval = CHKRES_NOT_READY;
@@ -877,7 +919,7 @@ static int check_tape(struct scsi_tape *
 			goto err_out;
 		}
 
-		if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
+		if (!SRpnt->sr_result && !STp->buffer->cmdstat.have_sense) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
 			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
 			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
@@ -1004,7 +1046,13 @@ static int st_open(struct inode *inode, 
 	int dev = TAPE_NR(inode);
 	char *name;
 
-	nonseekable_open(inode, filp);
+	/*
+	 * We really want to do nonseekable_open(inode, filp); here, but some
+	 * versions of tar incorrectly call lseek on tapes and bail out if that
+	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+	 */
+	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
 	write_lock(&st_dev_arr_lock);
 	if (dev >= st_dev_max || scsi_tapes == NULL ||
 	    ((STp = scsi_tapes[dev]) == NULL)) {
@@ -1108,10 +1156,9 @@ static int st_flush(struct file *filp)
 		       name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
 
 	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
 
-                DEBC(printk(ST_DEB_MSG "%s: File length %lld bytes.\n",
-                            name, (long long)filp->f_pos);
-                     printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
+                DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
                             name, STp->nbr_waits, STp->nbr_finished);
 		)
 
@@ -1126,20 +1173,13 @@ static int st_flush(struct file *filp)
 			goto out;
 		}
 
-		if ((STp->buffer)->syscall_result != 0 &&
-		    ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
-		     (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
-		     ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
-		      (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
-		       SRpnt->sr_sense_buffer[5] |
-		       SRpnt->sr_sense_buffer[6]) != 0))) {
-			/* Filter out successful write at EOM */
-			scsi_release_request(SRpnt);
-			SRpnt = NULL;
-			printk(KERN_ERR "%s: Error on write filemark.\n", name);
-			if (result == 0)
-				result = (-EIO);
-		} else {
+		if (STp->buffer->syscall_result == 0 ||
+		    (cmdstatp->have_sense && !cmdstatp->deferred &&
+		     (cmdstatp->flags & SENSE_EOM) &&
+		     (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		      cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+		     (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
+			/* Write successful at EOM */
 			scsi_release_request(SRpnt);
 			SRpnt = NULL;
 			if (STps->drv_file >= 0)
@@ -1149,6 +1189,13 @@ static int st_flush(struct file *filp)
 				cross_eof(STp, 0);
 			STps->eof = ST_FM;
 		}
+		else { /* Write error */
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
+			printk(KERN_ERR "%s: Error on write filemark.\n", name);
+			if (result == 0)
+				result = (-EIO);
+		}
 
                 DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",
                             name, cmd[4]));
@@ -1410,16 +1457,12 @@ st_write(struct file *filp, const char _
 	}
 
 	STbp = STp->buffer;
-	if (STbp->writing) {
-		write_behind_check(STp);
-		if (STbp->syscall_result) {
-                        DEBC(printk(ST_DEB_MSG "%s: Async write error (write) %x.\n",
-                                    name, STbp->midlevel_result));
-			if (STbp->midlevel_result == INT_MAX)
-				STps->eof = ST_EOM_OK;
-			else
-				STps->eof = ST_EOM_ERROR;
-		}
+	i = write_behind_check(STp);
+	if (i) {
+		if (i == -ENOSPC)
+			STps->eof = ST_EOM_OK;
+		else
+			STps->eof = ST_EOM_ERROR;
 	}
 
 	if (STps->eof == ST_EOM_OK) {
@@ -1477,7 +1520,6 @@ st_write(struct file *filp, const char _
 			}
 		}
 		count -= do_count;
-		filp->f_pos += do_count;
 		b_point += do_count;
 
 		async_write = STp->block_size == 0 && !STbp->do_dio &&
@@ -1523,15 +1565,13 @@ st_write(struct file *filp, const char _
 		}
 
 		if (STbp->syscall_result != 0) {
+			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
                         DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));
-			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-			    (SRpnt->sr_sense_buffer[2] & 0x40)) {
-				scode = SRpnt->sr_sense_buffer[2] & 0x0f;
-				if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
-					undone = (SRpnt->sr_sense_buffer[3] << 24) |
-					    (SRpnt->sr_sense_buffer[4] << 16) |
-					    (SRpnt->sr_sense_buffer[5] << 8) |
-                                                SRpnt->sr_sense_buffer[6];
+			if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
+				scode = cmdstatp->sense_hdr.sense_key;
+				if (cmdstatp->remainder_valid)
+					undone = (int)cmdstatp->uremainder64;
 				else if (STp->block_size == 0 &&
 					 scode == VOLUME_OVERFLOW)
 					undone = transfer;
@@ -1539,7 +1579,6 @@ st_write(struct file *filp, const char _
 					undone = 0;
 				if (STp->block_size != 0)
 					undone *= STp->block_size;
-				filp->f_pos -= undone;
 				if (undone <= do_count) {
 					/* Only data from this write is not written */
 					count += undone;
@@ -1556,11 +1595,11 @@ st_write(struct file *filp, const char _
 						retval = (-ENOSPC); /* EOM within current request */
                                         DEBC(printk(ST_DEB_MSG
                                                        "%s: EOM with %d bytes unwritten.\n",
-						       name, count));
+						       name, (int)count));
 				} else {
 					/* EOT within data buffered earlier (possible only
 					   in fixed block mode without direct i/o) */
-					if (!retry_eot && (SRpnt->sr_sense_buffer[0] & 1) == 0 &&
+					if (!retry_eot && !cmdstatp->deferred &&
 					    (scode == NO_SENSE || scode == RECOVERED_ERROR)) {
 						move_buffer_data(STp->buffer, transfer - undone);
 						retry_eot = 1;
@@ -1588,7 +1627,6 @@ st_write(struct file *filp, const char _
 					}
 				}
 			} else {
-				filp->f_pos -= do_count;
 				count += do_count;
 				STps->drv_block = (-1);		/* Too cautious? */
 				retval = (-EIO);
@@ -1690,6 +1728,8 @@ static long read_tape(struct scsi_tape *
 
 	/* Something to check */
 	if (STbp->syscall_result) {
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
 		retval = 1;
 		DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
                             name,
@@ -1697,25 +1737,22 @@ static long read_tape(struct scsi_tape *
                             SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
                             SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
                             SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
-		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {	/* extended sense */
+		if (cmdstatp->have_sense) {
 
-			if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
-				SRpnt->sr_sense_buffer[2] &= 0xcf;	/* No need for EOM in this case */
+			if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
+				cmdstatp->flags &= 0xcf;	/* No need for EOM in this case */
 
-			if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
+			if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
 				/* Compute the residual count */
-				if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
-					transfer = (SRpnt->sr_sense_buffer[3] << 24) |
-					    (SRpnt->sr_sense_buffer[4] << 16) |
-					    (SRpnt->sr_sense_buffer[5] << 8) |
-					    SRpnt->sr_sense_buffer[6];
+				if (cmdstatp->remainder_valid)
+					transfer = (int)cmdstatp->uremainder64;
 				else
 					transfer = 0;
 				if (STp->block_size == 0 &&
-				    (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+				    cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)
 					transfer = bytes;
 
-				if (SRpnt->sr_sense_buffer[2] & 0x20) {	/* ILI */
+				if (cmdstatp->flags & SENSE_ILI) {	/* ILI */
 					if (STp->block_size == 0) {
 						if (transfer <= 0) {
 							if (transfer < 0)
@@ -1749,7 +1786,7 @@ static long read_tape(struct scsi_tape *
 						if (st_int_ioctl(STp, MTBSR, 1))
 							return (-EIO);
 					}
-				} else if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* FM overrides EOM */
+				} else if (cmdstatp->flags & SENSE_FMK) {	/* FM overrides EOM */
 					if (STps->eof != ST_FM_HIT)
 						STps->eof = ST_FM_HIT;
 					else
@@ -1762,7 +1799,7 @@ static long read_tape(struct scsi_tape *
                                         DEBC(printk(ST_DEB_MSG
                                                     "%s: EOF detected (%d bytes read).\n",
                                                     name, STbp->buffer_bytes));
-				} else if (SRpnt->sr_sense_buffer[2] & 0x40) {
+				} else if (cmdstatp->flags & SENSE_EOM) {
 					if (STps->eof == ST_FM)
 						STps->eof = ST_EOD_1;
 					else
@@ -1783,7 +1820,7 @@ static long read_tape(struct scsi_tape *
                                             "%s: Tape error while reading.\n", name));
 				STps->drv_block = (-1);
 				if (STps->eof == ST_FM &&
-				    (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+				    cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
                                         DEBC(printk(ST_DEB_MSG
                                                     "%s: Zero returned for first BLANK CHECK after EOF.\n",
                                                     name));
@@ -1907,7 +1944,7 @@ st_read(struct file *filp, char __user *
 				printk(ST_DEB_MSG
                                        "%s: EOF up (%d). Left %d, needed %d.\n", name,
 				       STps->eof, STbp->buffer_bytes,
-                                       count - total);
+                                       (int)(count - total));
                         ) /* end DEB */
 			transfer = STbp->buffer_bytes < count - total ?
 			    STbp->buffer_bytes : count - total;
@@ -1918,7 +1955,6 @@ st_read(struct file *filp, char __user *
 					goto out;
 				}
 			}
-			filp->f_pos += transfer;
 			buf += transfer;
 			total += transfer;
 		}
@@ -2373,6 +2409,22 @@ static int do_load_unload(struct scsi_ta
 	return retval;
 }
 
+#if DEBUG
+#define ST_DEB_FORWARD  0
+#define ST_DEB_BACKWARD 1
+static void deb_space_print(char *name, int direction, char *units, unsigned char *cmd)
+{
+	s32 sc;
+
+	sc = cmd[2] & 0x80 ? 0xff000000 : 0;
+	sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+	if (direction)
+		sc = -sc;
+	printk(ST_DEB_MSG "%s: Spacing tape %s over %d %s.\n", name,
+	       direction ? "backward" : "forward", sc, units);
+}
+#endif
+
 
 /* Internal ioctl function */
 static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
@@ -2411,8 +2463,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-                DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward over %d filemarks.\n",
-			    name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "filemarks", cmd);)
 		if (fileno >= 0)
 			fileno += arg;
 		blkno = 0;
@@ -2427,14 +2478,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-                DEBC(
-                     if (cmd[2] & 0x80)
-                     	ltmp = 0xff000000;
-                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-                     printk(ST_DEB_MSG
-                            "%s: Spacing tape backward over %ld filemarks.\n",
-                            name, (-ltmp));
-		)
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "filemarks", cmd);)
 		if (fileno >= 0)
 			fileno -= arg;
 		blkno = (-1);	/* We can't know the block number */
@@ -2446,8 +2490,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-                DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d blocks.\n", name,
-			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "blocks", cmd);)
 		if (blkno >= 0)
 			blkno += arg;
 		at_sm &= (arg == 0);
@@ -2459,13 +2502,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-                DEBC(
-                     if (cmd[2] & 0x80)
-                          ltmp = 0xff000000;
-                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-                     printk(ST_DEB_MSG
-                            "%s: Spacing tape backward %ld blocks.\n", name, (-ltmp));
-		)
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "blocks", cmd);)
 		if (blkno >= 0)
 			blkno -= arg;
 		at_sm &= (arg == 0);
@@ -2476,8 +2513,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-                DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d setmarks.\n", name,
-                            cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "setmarks", cmd);)
 		if (arg != 0) {
 			blkno = fileno = (-1);
 			at_sm = 1;
@@ -2490,13 +2526,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-                DEBC(
-                     if (cmd[2] & 0x80)
-				ltmp = 0xff000000;
-                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-                     printk(ST_DEB_MSG "%s: Spacing tape backward %ld setmarks.\n",
-                            name, (-ltmp));
-		)
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "setmarks", cmd);)
 		if (arg != 0) {
 			blkno = fileno = (-1);
 			at_sm = 1;
@@ -2566,7 +2596,7 @@ static int st_int_ioctl(struct scsi_tape
 		cmd[1] = 3;
                 DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n",
                             name));
-		blkno = 0;
+		blkno = -1;
 		at_sm = 0;
 		break;
 	case MTERASE:
@@ -2693,25 +2723,30 @@ static int st_int_ioctl(struct scsi_tape
 		else if (chg_eof)
 			STps->eof = ST_NOEOF;
 
+		if (cmd_in == MTWEOF)
+			STps->rw = ST_IDLE;
 	} else { /* SCSI command was not completely successful. Don't return
                     from this block without releasing the SCSI command block! */
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
 
-		if (SRpnt->sr_sense_buffer[2] & 0x40) {
+		if (cmdstatp->flags & SENSE_EOM) {
 			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
 			    cmd_in != MTBSR && cmd_in != MTBSS)
 				STps->eof = ST_EOM_OK;
 			STps->drv_block = 0;
 		}
 
-		undone = ((SRpnt->sr_sense_buffer[3] << 24) +
-			  (SRpnt->sr_sense_buffer[4] << 16) +
-			  (SRpnt->sr_sense_buffer[5] << 8) +
-			  SRpnt->sr_sense_buffer[6]);
+		if (cmdstatp->remainder_valid)
+			undone = (int)cmdstatp->uremainder64;
+		else
+			undone = 0;
 
 		if (cmd_in == MTWEOF &&
-		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-		    (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
-		 ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+		    cmdstatp->have_sense &&
+		    (cmdstatp->flags & SENSE_EOM) &&
+		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+		    undone == 0) {
 			ioctl_result = 0;	/* EOF written succesfully at EOM */
 			if (fileno >= 0)
 				fileno++;
@@ -2722,7 +2757,7 @@ static int st_int_ioctl(struct scsi_tape
 				STps->drv_file = fileno - undone;
 			else
 				STps->drv_file = fileno;
-			STps->drv_block = 0;
+			STps->drv_block = -1;
 			STps->eof = ST_NOEOF;
 		} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
 			if (arg > 0 && undone < 0)  /* Some drives get this wrong */
@@ -2732,7 +2767,7 @@ static int st_int_ioctl(struct scsi_tape
 			STps->drv_block = 0;
 			STps->eof = ST_NOEOF;
 		} else if (cmd_in == MTFSR) {
-			if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* Hit filemark */
+			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
 				if (STps->drv_file >= 0)
 					STps->drv_file++;
 				STps->drv_block = 0;
@@ -2745,7 +2780,7 @@ static int st_int_ioctl(struct scsi_tape
 				STps->eof = ST_NOEOF;
 			}
 		} else if (cmd_in == MTBSR) {
-			if (SRpnt->sr_sense_buffer[2] & 0x80) {	/* Hit filemark */
+			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
 				STps->drv_file--;
 				STps->drv_block = (-1);
 			} else {
@@ -2763,7 +2798,7 @@ static int st_int_ioctl(struct scsi_tape
 			   cmd_in == MTSETDENSITY ||
 			   cmd_in == MTSETDRVBUFFER ||
 			   cmd_in == SET_DENS_AND_BLK) {
-			if ((SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST &&
+			if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
 			    !(STp->use_pf & PF_TESTED)) {
 				/* Try the other possible state of Page Format if not
 				   already tried */
@@ -2775,7 +2810,7 @@ static int st_int_ioctl(struct scsi_tape
 		} else if (chg_eof)
 			STps->eof = ST_NOEOF;
 
-		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+		if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
 			STps->eof = ST_EOD;
 
 		scsi_release_request(SRpnt);
@@ -3198,6 +3233,20 @@ static int st_ioctl(struct inode *inode,
 				retval = i;
 				goto out;
 			}
+			if (STps->rw == ST_WRITING &&
+			    (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+			     mtc.mt_op == MTSEEK ||
+			     mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
+				i = st_int_ioctl(STp, MTWEOF, 1);
+				if (i < 0) {
+					retval = i;
+					goto out;
+				}
+				if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
+					mtc.mt_count++;
+				STps->rw = ST_IDLE;
+			     }
+
 		} else {
 			/*
 			 * If there was a bus reset, block further access
@@ -3414,17 +3463,39 @@ static int st_ioctl(struct inode *inode,
 		case SCSI_IOCTL_GET_BUS_NUMBER:
 			break;
 		default:
-			i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);
+			if (!capable(CAP_SYS_ADMIN))
+				i = -EPERM;
+			else
+				i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);
 			if (i != -ENOTTY)
 				return i;
 			break;
 	}
+	if (!capable(CAP_SYS_ADMIN) &&
+	    (cmd_in == SCSI_IOCTL_START_UNIT || cmd_in == SCSI_IOCTL_STOP_UNIT))
+		return -EPERM;
 	return scsi_ioctl(STp->device, cmd_in, p);
 
  out:
 	up(&STp->lock);
 	return retval;
 }
+
+#ifdef CONFIG_COMPAT
+static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct scsi_tape *STp = file->private_data;
+	struct scsi_device *sdev = STp->device;
+	int ret = -ENOIOCTLCMD;
+	if (sdev->host->hostt->compat_ioctl) { 
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+
+	}
+	return ret;
+}
+#endif
+
 
 
 /* Try to allocate a new tape buffer. Calling function must not hold
@@ -3716,6 +3787,9 @@ static struct file_operations st_fops =
 	.read =		st_read,
 	.write =	st_write,
 	.ioctl =	st_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = st_compat_ioctl,
+#endif
 	.open =		st_open,
 	.flush =	st_flush,
 	.release =	st_release,
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -5,6 +5,18 @@
 #include <linux/completion.h>
 
 
+/* Descriptor for analyzed sense data */
+struct st_cmdstatus {
+	int midlevel_result;
+	struct scsi_sense_hdr sense_hdr;
+	int have_sense;
+	u64 uremainder64;
+	u8 flags;
+	u8 remainder_valid;
+	u8 fixed_format;
+	u8 deferred;
+};
+
 /* The tape buffer descriptor. */
 struct st_buffer {
 	unsigned char in_use;
@@ -15,9 +27,9 @@ struct st_buffer {
 	int buffer_bytes;
 	int read_pointer;
 	int writing;
-	int midlevel_result;
 	int syscall_result;
 	struct scsi_request *last_SRpnt;
+	struct st_cmdstatus cmdstat;
 	unsigned char *b_data;
 	unsigned short use_sg;	/* zero or max number of s/g segments for this adapter */
 	unsigned short sg_segs;		/* number of segments in s/g list */
@@ -192,4 +204,9 @@ struct scsi_tape {
 
 #define EXTENDED_SENSE_START  18
 
+/* Masks for some conditions in the sense data */
+#define SENSE_FMK   0x80
+#define SENSE_EOM   0x40
+#define SENSE_ILI   0x20
+
 #endif
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -69,6 +69,7 @@
  *   finally replaced that by the *_PRINTK() macros.
  *
  */
+#include <scsi/scsi_dbg.h>
 
 /*
  * Further development / testing that should be done : 
@@ -2377,7 +2378,7 @@ static void NCR5380_information_transfer
  * 3..length+1	arguments
  *
  * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since print_msg() wants the whole thing.  
+ * byte, since scsi_print_msg() wants the whole thing.  
  */
 		    extended_msg[0] = EXTENDED_MESSAGE;
 		    /* Accept first byte by clearing ACK */
@@ -2430,7 +2431,7 @@ static void NCR5380_information_transfer
 		default:
 		    if (!tmp) {
 			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
-			print_msg (extended_msg);
+			scsi_print_msg (extended_msg);
 			printk("\n");
 		    } else if (tmp != EXTENDED_MESSAGE)
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
@@ -2565,7 +2566,7 @@ static void NCR5380_reselect (struct Scs
 
     if (!(msg[0] & 0x80)) {
 	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
-	print_msg(msg);
+	scsi_print_msg(msg);
 	do_abort(instance);
 	return;
     }
@@ -2691,7 +2692,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
     unsigned long flags;
 
     printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
-    print_Scsi_Cmnd (cmd);
+    scsi_print_command(cmd);
 
     NCR5380_print_status (instance);
 
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -616,7 +616,7 @@ static struct isapnp_device_id id_table[
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
 
-void sym53c416_probe(void)
+static void sym53c416_probe(void)
 {
 	int *base = probeaddrs;
 	int ints[2];
@@ -809,7 +809,7 @@ static int sym53c416_host_reset(Scsi_Cmn
 	/* printk("sym53c416_reset\n"); */
 	base = SCpnt->device->host->io_port;
 	/* search scsi_id - fixme, we shouldnt need to iterate for this! */
-	for(i = 0; i < host_index && scsi_id != -1; i++)
+	for(i = 0; i < host_index && scsi_id == -1; i++)
 		if(hosts[i].base == base)
 			scsi_id = hosts[i].scsi_id;
 	outb(RESET_CHIP, base + COMMAND_REG);
diff --git a/drivers/scsi/sym53c8xx_2/Makefile b/drivers/scsi/sym53c8xx_2/Makefile
--- a/drivers/scsi/sym53c8xx_2/Makefile
+++ b/drivers/scsi/sym53c8xx_2/Makefile
@@ -1,4 +1,4 @@
 # Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
 
-sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_misc.o sym_nvram.o
+sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o
 obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -42,10 +42,6 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_SCSI_SYM53C8XX_IOMAPPED
-#define	SYM_CONF_IOMAPPED
-#endif
-
 /*
  *  DMA addressing mode.
  *
@@ -144,10 +140,6 @@ struct sym_driver_setup {
 #define SYM_SETUP_HOST_ID		sym_driver_setup.host_id
 #define boot_verbose			sym_driver_setup.verbose
 
-/* Always enable parity. */
-#define SYM_SETUP_PCI_PARITY		1
-#define SYM_SETUP_SCSI_PARITY		1
-
 /*
  *  Initial setup.
  *
@@ -170,4 +162,56 @@ extern struct sym_driver_setup sym_drive
 extern unsigned int sym_debug_flags;
 #define DEBUG_FLAGS	sym_debug_flags
 
+/*
+ *  Max number of targets.
+ *  Maximum is 16 and you are advised not to change this value.
+ */
+#ifndef SYM_CONF_MAX_TARGET
+#define SYM_CONF_MAX_TARGET	(16)
+#endif
+
+/*
+ *  Max number of logical units.
+ *  SPI-2 allows up to 64 logical units, but in real life, target
+ *  that implements more that 7 logical units are pretty rare.
+ *  Anyway, the cost of accepting up to 64 logical unit is low in 
+ *  this driver, thus going with the maximum is acceptable.
+ */
+#ifndef SYM_CONF_MAX_LUN
+#define SYM_CONF_MAX_LUN	(64)
+#endif
+
+/*
+ *  Max number of IO control blocks queued to the controller.
+ *  Each entry needs 8 bytes and the queues are allocated contiguously.
+ *  Since we donnot want to allocate more than a page, the theorical 
+ *  maximum is PAGE_SIZE/8. For safety, we announce a bit less to the 
+ *  access method. :)
+ *  When not supplied, as it is suggested, the driver compute some 
+ *  good value for this parameter.
+ */
+/* #define SYM_CONF_MAX_START	(PAGE_SIZE/8 - 16) */
+
+/*
+ *  Support for Immediate Arbitration.
+ *  Not advised.
+ */
+/* #define SYM_CONF_IARB_SUPPORT */
+
+/*
+ *  Only relevant if IARB support configured.
+ *  - Max number of successive settings of IARB hints.
+ *  - Set IARB on arbitration lost.
+ */
+#define SYM_CONF_IARB_MAX 3
+#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
+
+/*
+ *  Returning wrong residuals may make problems.
+ *  When zero, this define tells the driver to 
+ *  always return 0 as transfer residual.
+ *  Btw, all my testings of residuals have succeeded.
+ */
+#define SYM_SETUP_RESIDUAL_SUPPORT 1
+
 #endif /* SYM53C8XX_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_conf.h b/drivers/scsi/sym53c8xx_2/sym_conf.h
deleted file mode 100644
--- a/drivers/scsi/sym53c8xx_2/sym_conf.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
- * of PCI-SCSI IO processors.
- *
- * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
- *
- * This driver is derived from the Linux sym53c8xx driver.
- * Copyright (C) 1998-2000  Gerard Roudier
- *
- * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
- * a port of the FreeBSD ncr driver to Linux-1.2.13.
- *
- * The original ncr driver has been written for 386bsd and FreeBSD by
- *         Wolfgang Stanglmeier        <wolf@cologne.de>
- *         Stefan Esser                <se@mi.Uni-Koeln.de>
- * Copyright (C) 1994  Wolfgang Stanglmeier
- *
- * Other major contributions:
- *
- * NVRAM detection and reading.
- * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
- *
- *-----------------------------------------------------------------------------
- *
- * This program is free software; you can redistribute it 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 SYM_CONF_H
-#define SYM_CONF_H
-
-#include "sym53c8xx.h"
-
-/*
- *  Max number of targets.
- *  Maximum is 16 and you are advised not to change this value.
- */
-#ifndef SYM_CONF_MAX_TARGET
-#define SYM_CONF_MAX_TARGET	(16)
-#endif
-
-/*
- *  Max number of logical units.
- *  SPI-2 allows up to 64 logical units, but in real life, target
- *  that implements more that 7 logical units are pretty rare.
- *  Anyway, the cost of accepting up to 64 logical unit is low in 
- *  this driver, thus going with the maximum is acceptable.
- */
-#ifndef SYM_CONF_MAX_LUN
-#define SYM_CONF_MAX_LUN	(64)
-#endif
-
-/*
- *  Max number of IO control blocks queued to the controller.
- *  Each entry needs 8 bytes and the queues are allocated contiguously.
- *  Since we donnot want to allocate more than a page, the theorical 
- *  maximum is PAGE_SIZE/8. For safety, we announce a bit less to the 
- *  access method. :)
- *  When not supplied, as it is suggested, the driver compute some 
- *  good value for this parameter.
- */
-/* #define SYM_CONF_MAX_START	(PAGE_SIZE/8 - 16) */
-
-/*
- *  Support for Immediate Arbitration.
- *  Not advised.
- */
-/* #define SYM_CONF_IARB_SUPPORT */
-
-/*
- *  Only relevant if IARB support configured.
- *  - Max number of successive settings of IARB hints.
- *  - Set IARB on arbitration lost.
- */
-#define SYM_CONF_IARB_MAX 3
-#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
-
-/*
- *  Returning wrong residuals may make problems.
- *  When zero, this define tells the driver to 
- *  always return 0 as transfer residual.
- *  Btw, all my testings of residuals have succeeded.
- */
-#define SYM_SETUP_RESIDUAL_SUPPORT 1
-
-/*
- *  Supported maximum number of LUNs to announce to 
- *  the access method.
- *  The driver supports up to 64 LUNs per target as 
- *  required by SPI-2/SPI-3. However some SCSI devices  
- *  designed prior to these specifications or not being  
- *  conformant may be highly confused when they are 
- *  asked about a LUN > 7.
- */
-#ifndef SYM_SETUP_MAX_LUN
-#define SYM_SETUP_MAX_LUN	(8)
-#endif
-
-#endif /* SYM_CONF_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h
--- a/drivers/scsi/sym53c8xx_2/sym_defs.h
+++ b/drivers/scsi/sym53c8xx_2/sym_defs.h
@@ -40,13 +40,13 @@
 #ifndef SYM_DEFS_H
 #define SYM_DEFS_H
 
-#define SYM_VERSION "2.1.18n"
+#define SYM_VERSION "2.2.0"
 #define SYM_DRIVER_NAME	"sym-" SYM_VERSION
 
 /*
  *	SYM53C8XX device features descriptor.
  */
-struct sym_pci_chip {
+struct sym_chip {
 	u_short	device_id;
 	u_short	revision_id;
 	char	*name;
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
--- a/drivers/scsi/sym53c8xx_2/sym_fw.c
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -361,7 +361,7 @@ static struct sym_fw sym_fw2 = SYM_FW_EN
  *  Find the most appropriate firmware for a chip.
  */
 struct sym_fw * 
-sym_find_firmware(struct sym_pci_chip *chip)
+sym_find_firmware(struct sym_chip *chip)
 {
 	if (chip->features & FE_LDSTR)
 		return &sym_fw2;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -3,7 +3,7 @@
  * of PCI-SCSI IO processors.
  *
  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
- * Copyright (c) 2003-2004  Matthew Wilcox <matthew@wil.cx>
+ * Copyright (c) 2003-2005  Matthew Wilcox <matthew@wil.cx>
  *
  * This driver is derived from the Linux sym53c8xx driver.
  * Copyright (C) 1998-2000  Gerard Roudier
@@ -47,7 +47,6 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_transport.h>
-#include <scsi/scsi_transport_spi.h>
 
 #include "sym_glue.h"
 #include "sym_nvram.h"
@@ -135,81 +134,47 @@ static void sym2_setup_params(void)
 	}
 }
 
+/*
+ * We used to try to deal with 64-bit BARs here, but don't any more.
+ * There are many parts of this driver which would need to be modified
+ * to handle a 64-bit base address, including scripts.  I'm uncomfortable
+ * with making those changes when I have no way of testing it, so I'm
+ * just going to disable it.
+ *
+ * Note that some machines (eg HP rx8620 and Superdome) have bus addresses
+ * below 4GB and physical addresses above 4GB.  These will continue to work.
+ */
 static int __devinit
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep)
 {
 	u32 tmp;
+	unsigned long base;
 #define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
 
-	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
-	*base = tmp;
-	++index;
+	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
+	base = tmp;
 	if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
-#if BITS_PER_LONG > 32
-		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
-		*base |= (((u_long)tmp) << 32);
-#endif
-		++index;
+		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
+		if (tmp > 0)
+			dev_err(&pdev->dev,
+				"BAR %d is 64-bit, disabling\n", index - 1);
+		base = 0;
 	}
+
+	if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+		base &= PCI_BASE_ADDRESS_IO_MASK;
+	} else {
+		base &= PCI_BASE_ADDRESS_MEM_MASK;
+	}
+
+	*basep = base;
 	return index;
 #undef PCI_BAR_OFFSET
 }
 
-/* This lock protects only the memory allocation/free.  */
-static DEFINE_SPINLOCK(sym53c8xx_lock);
-
 static struct scsi_transport_template *sym2_transport_template = NULL;
 
 /*
- *  Wrappers to the generic memory allocator.
- */
-void *sym_calloc(int size, char *name)
-{
-	unsigned long flags;
-	void *m;
-	spin_lock_irqsave(&sym53c8xx_lock, flags);
-	m = sym_calloc_unlocked(size, name);
-	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
-	return m;
-}
-
-void sym_mfree(void *m, int size, char *name)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&sym53c8xx_lock, flags);
-	sym_mfree_unlocked(m, size, name);
-	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
-}
-
-void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
-{
-	unsigned long flags;
-	void *m;
-	spin_lock_irqsave(&sym53c8xx_lock, flags);
-	m = __sym_calloc_dma_unlocked(dev_dmat, size, name);
-	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
-	return m;
-}
-
-void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&sym53c8xx_lock, flags);
-	__sym_mfree_dma_unlocked(dev_dmat, m, size, name);
-	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
-}
-
-m_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
-{
-	unsigned long flags;
-	m_addr_t b;
-	spin_lock_irqsave(&sym53c8xx_lock, flags);
-	b = __vtobus_unlocked(dev_dmat, m);
-	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
-	return b;
-}
-
-/*
  *  Used by the eh thread to wait for command completion.
  *  It is allocated on the eh thread stack.
  */
@@ -231,8 +196,7 @@ struct sym_ucmd {		/* Override the SCSI 
 };
 
 #define SYM_UCMD_PTR(cmd)  ((struct sym_ucmd *)(&(cmd)->SCp))
-#define SYM_SCMD_PTR(ucmd) sym_que_entry(ucmd, struct scsi_cmnd, SCp)
-#define SYM_SOFTC_PTR(cmd) (((struct host_data *)cmd->device->host->hostdata)->ncb)
+#define SYM_SOFTC_PTR(cmd) sym_get_hcb(cmd->device->host)
 
 static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
 {
@@ -288,31 +252,20 @@ static int __map_scsi_sg_data(struct pci
 /*
  *  Complete a pending CAM CCB.
  */
-void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb)
+void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd)
 {
-	unmap_scsi_data(np, ccb);
-	ccb->scsi_done(ccb);
+	unmap_scsi_data(np, cmd);
+	cmd->scsi_done(cmd);
 }
 
-static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *ccb, int cam_status)
+static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *cmd, int cam_status)
 {
-	sym_set_cam_status(ccb, cam_status);
-	sym_xpt_done(np, ccb);
+	sym_set_cam_status(cmd, cam_status);
+	sym_xpt_done(np, cmd);
 }
 
 
 /*
- *  Print something that identifies the IO.
- */
-void sym_print_addr(struct sym_ccb *cp)
-{
-	struct scsi_cmnd *cmd = cp->cam_ccb;
-	if (cmd)
-		printf("%s:%d:%d:", sym_name(SYM_SOFTC_PTR(cmd)),
-				cmd->device->id, cmd->device->lun);
-}
-
-/*
  *  Tell the SCSI layer about a BUS RESET.
  */
 void sym_xpt_async_bus_reset(struct sym_hcb *np)
@@ -334,16 +287,6 @@ void sym_xpt_async_sent_bdr(struct sym_h
 }
 
 /*
- *  Tell the SCSI layer about the new transfer parameters.
- */
-void sym_xpt_async_nego_wide(struct sym_hcb *np, int target)
-{
-	if (sym_verbose < 3)
-		return;
-	sym_announce_transfer_rate(np, target);
-}
-
-/*
  *  Choose the more appropriate CAM status if 
  *  the IO encountered an extended error.
  */
@@ -367,7 +310,7 @@ static int sym_xerr_cam_status(int cam_s
  */
 void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
 {
-	struct scsi_cmnd *csio = cp->cam_ccb;
+	struct scsi_cmnd *cmd = cp->cmd;
 	u_int cam_status, scsi_status, drv_status;
 
 	drv_status  = 0;
@@ -378,7 +321,7 @@ void sym_set_cam_result_error(struct sym
 		scsi_status = cp->sv_scsi_status;
 		resid = cp->sv_resid;
 		if (sym_verbose && cp->sv_xerr_status)
-			sym_print_xerr(cp, cp->sv_xerr_status);
+			sym_print_xerr(cmd, cp->sv_xerr_status);
 		if (cp->host_status == HS_COMPLETE &&
 		    cp->ssss_status == S_GOOD &&
 		    cp->xerr_status == 0) {
@@ -388,9 +331,9 @@ void sym_set_cam_result_error(struct sym
 			/*
 			 *  Bounce back the sense data to user.
 			 */
-			memset(&csio->sense_buffer, 0, sizeof(csio->sense_buffer));
-			memcpy(csio->sense_buffer, cp->sns_bbuf,
-			      min(sizeof(csio->sense_buffer),
+			memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+			memcpy(cmd->sense_buffer, cp->sns_bbuf,
+			      min(sizeof(cmd->sense_buffer),
 				  (size_t)SYM_SNS_BBUF_LEN));
 #if 0
 			/*
@@ -400,7 +343,7 @@ void sym_set_cam_result_error(struct sym
 			 */
 			if (1) {
 				u_char *p;
-				p  = (u_char *) csio->sense_data;
+				p  = (u_char *) cmd->sense_data;
 				if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29)
 					sym_clear_tasks(np, DID_ABORT,
 							cp->target,cp->lun, -1);
@@ -413,7 +356,7 @@ void sym_set_cam_result_error(struct sym
 			 * condition otherwise the device will always return
 			 * BUSY.  Use a big stick.
 			 */
-			sym_reset_scsi_target(np, csio->device->id);
+			sym_reset_scsi_target(np, cmd->device->id);
 			cam_status = DID_ERROR;
 		}
 	} else if (cp->host_status == HS_COMPLETE) 	/* Bad SCSI status */
@@ -424,8 +367,7 @@ void sym_set_cam_result_error(struct sym
 		cam_status = DID_ERROR;
 	else {						/* Extended error */
 		if (sym_verbose) {
-			PRINT_ADDR(cp);
-			printf ("COMMAND FAILED (%x %x %x).\n",
+			sym_print_addr(cmd, "COMMAND FAILED (%x %x %x).\n",
 				cp->host_status, cp->ssss_status,
 				cp->xerr_status);
 		}
@@ -434,8 +376,8 @@ void sym_set_cam_result_error(struct sym
 		 */
 		cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
 	}
-	csio->resid = resid;
-	csio->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
+	cmd->resid = resid;
+	cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
 }
 
 
@@ -502,9 +444,9 @@ static int sym_scatter(struct sym_hcb *n
 /*
  *  Queue a SCSI command.
  */
-static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *ccb)
+static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *cmd)
 {
-/*	struct scsi_device        *device    = ccb->device; */
+	struct scsi_device *sdev = cmd->device;
 	struct sym_tcb *tp;
 	struct sym_lcb *lp;
 	struct sym_ccb *cp;
@@ -514,17 +456,17 @@ static int sym_queue_command(struct sym_
 	 *  Minimal checkings, so that we will not 
 	 *  go outside our tables.
 	 */
-	if (ccb->device->id == np->myaddr ||
-	    ccb->device->id >= SYM_CONF_MAX_TARGET ||
-	    ccb->device->lun >= SYM_CONF_MAX_LUN) {
-		sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);
+	if (sdev->id == np->myaddr ||
+	    sdev->id >= SYM_CONF_MAX_TARGET ||
+	    sdev->lun >= SYM_CONF_MAX_LUN) {
+		sym_xpt_done2(np, cmd, CAM_DEV_NOT_THERE);
 		return 0;
 	}
 
 	/*
 	 *  Retrieve the target descriptor.
 	 */
-	tp = &np->target[ccb->device->id];
+	tp = &np->target[sdev->id];
 
 	/*
 	 *  Complete the 1st INQUIRY command with error 
@@ -538,12 +480,12 @@ static int sym_queue_command(struct sym_
 	 *  devices behave badly when asked for some non 
 	 *  zero LUN. Btw, this is an absolute hack.:-)
 	 */
-	if (ccb->cmnd[0] == 0x12 || ccb->cmnd[0] == 0x0) {
+	if (cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 0x0) {
 		if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||
 		    ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && 
-		     ccb->device->lun != 0)) {
+		     sdev->lun != 0)) {
 			tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
-			sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);
+			sym_xpt_done2(np, cmd, CAM_DEV_NOT_THERE);
 			return 0;
 		}
 	}
@@ -551,23 +493,23 @@ static int sym_queue_command(struct sym_
 	/*
 	 *  Select tagged/untagged.
 	 */
-	lp = sym_lp(np, tp, ccb->device->lun);
+	lp = sym_lp(tp, sdev->lun);
 	order = (lp && lp->s.reqtags) ? M_SIMPLE_TAG : 0;
 
 	/*
 	 *  Queue the SCSI IO.
 	 */
-	cp = sym_get_ccb(np, ccb->device->id, ccb->device->lun, order);
+	cp = sym_get_ccb(np, cmd, order);
 	if (!cp)
 		return 1;	/* Means resource shortage */
-	sym_queue_scsiio(np, ccb, cp);
+	sym_queue_scsiio(np, cmd, cp);
 	return 0;
 }
 
 /*
  *  Setup buffers and pointers that address the CDB.
  */
-static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp)
+static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
 {
 	u32	cmd_ba;
 	int	cmd_len;
@@ -575,14 +517,14 @@ static inline int sym_setup_cdb(struct s
 	/*
 	 *  CDB is 16 bytes max.
 	 */
-	if (ccb->cmd_len > sizeof(cp->cdb_buf)) {
-		sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID);
+	if (cmd->cmd_len > sizeof(cp->cdb_buf)) {
+		sym_set_cam_status(cp->cmd, CAM_REQ_INVALID);
 		return -1;
 	}
 
-	memcpy(cp->cdb_buf, ccb->cmnd, ccb->cmd_len);
+	memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len);
 	cmd_ba  = CCB_BA (cp, cdb_buf[0]);
-	cmd_len = ccb->cmd_len;
+	cmd_len = cmd->cmd_len;
 
 	cp->phys.cmd.addr	= cpu_to_scr(cmd_ba);
 	cp->phys.cmd.size	= cpu_to_scr(cmd_len);
@@ -593,29 +535,29 @@ static inline int sym_setup_cdb(struct s
 /*
  *  Setup pointers that address the data and start the I/O.
  */
-int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp)
+int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
 {
 	int dir;
 	struct sym_tcb *tp = &np->target[cp->target];
-	struct sym_lcb *lp = sym_lp(np, tp, cp->lun);
+	struct sym_lcb *lp = sym_lp(tp, cp->lun);
 
 	/*
 	 *  Build the CDB.
 	 */
-	if (sym_setup_cdb(np, csio, cp))
+	if (sym_setup_cdb(np, cmd, cp))
 		goto out_abort;
 
 	/*
 	 *  No direction means no data.
 	 */
-	dir = csio->sc_data_direction;
+	dir = cmd->sc_data_direction;
 	if (dir != DMA_NONE) {
-		cp->segments = sym_scatter(np, cp, csio);
+		cp->segments = sym_scatter(np, cp, cmd);
 		if (cp->segments < 0) {
 			if (cp->segments == -2)
-				sym_set_cam_status(csio, CAM_RESRC_UNAVAIL);
+				sym_set_cam_status(cmd, CAM_RESRC_UNAVAIL);
 			else
-				sym_set_cam_status(csio, CAM_REQ_TOO_BIG);
+				sym_set_cam_status(cmd, CAM_REQ_TOO_BIG);
 			goto out_abort;
 		}
 	} else {
@@ -655,7 +597,7 @@ int sym_setup_data_and_start(struct sym_
 
 out_abort:
 	sym_free_ccb(np, cp);
-	sym_xpt_done(np, csio);
+	sym_xpt_done(np, cmd);
 	return 0;
 }
 
@@ -737,7 +679,6 @@ static int sym53c8xx_queue_command(struc
 	int sts = 0;
 
 	cmd->scsi_done     = done;
-	cmd->host_scribble = NULL;
 	memset(ucp, 0, sizeof(*ucp));
 
 	/*
@@ -855,22 +796,13 @@ static int sym_eh_handler(int op, char *
 	int to_do = SYM_EH_DO_IGNORE;
 	int sts = -1;
 	struct sym_eh_wait eh, *ep = &eh;
-	char devname[20];
 
-	sprintf(devname, "%s:%d:%d", sym_name(np), cmd->device->id, cmd->device->lun);
-
-	printf_warning("%s: %s operation started.\n", devname, opname);
-
-#if 0
-	/* This one should be the result of some race, thus to ignore */
-	if (cmd->serial_number != cmd->serial_number_at_timeout)
-		goto prepare;
-#endif
+	dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
 
 	/* This one is queued in some place -> to wait for completion */
 	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
 		struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
-		if (cp->cam_ccb == cmd) {
+		if (cp->cmd == cmd) {
 			to_do = SYM_EH_DO_WAIT;
 			goto prepare;
 		}
@@ -939,9 +871,9 @@ prepare:
 		if (ep->timed_out)
 			sts = -2;
 	}
-	printf_warning("%s: %s operation %s.\n", devname, opname,
-			sts==0?"complete":sts==-2?"timed-out":"failed");
-	return sts? SCSI_FAILED : SCSI_SUCCESS;
+	dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
+			sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
+	return sts ? SCSI_FAILED : SCSI_SUCCESS;
 }
 
 
@@ -971,10 +903,9 @@ static int sym53c8xx_eh_host_reset_handl
 /*
  *  Tune device queuing depth, according to various limits.
  */
-static void sym_tune_dev_queuing(struct sym_hcb *np, int target, int lun, u_short reqtags)
+static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags)
 {
-	struct sym_tcb *tp = &np->target[target];
-	struct sym_lcb *lp = sym_lp(np, tp, lun);
+	struct sym_lcb *lp = sym_lp(tp, lun);
 	u_short	oldtags;
 
 	if (!lp)
@@ -990,9 +921,8 @@ static void sym_tune_dev_queuing(struct 
 	lp->s.reqtags     = reqtags;
 
 	if (reqtags != oldtags) {
-		printf_info("%s:%d:%d: "
+		dev_info(&tp->sdev->sdev_target->dev,
 		         "tagged command queuing %s, command queue depth %d.\n",
-		          sym_name(np), target, lun,
 		          lp->s.reqtags ? "enabled" : "disabled",
  		          lp->started_limit);
 	}
@@ -1051,21 +981,34 @@ static int device_queue_depth(struct sym
 	return DEF_DEPTH;
 }
 
+static int sym53c8xx_slave_alloc(struct scsi_device *device)
+{
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
+	if (!tp->sdev)
+		tp->sdev = device;
+
+	return 0;
+}
+
+static void sym53c8xx_slave_destroy(struct scsi_device *device)
+{
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
+	if (tp->sdev == device)
+		tp->sdev = NULL;
+}
+
 /*
  * Linux entry point for device queue sizing.
  */
 static int sym53c8xx_slave_configure(struct scsi_device *device)
 {
-	struct Scsi_Host *host = device->host;
-	struct sym_hcb *np;
-	struct sym_tcb *tp;
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
 	struct sym_lcb *lp;
 	int reqtags, depth_to_use;
 
-	np = ((struct host_data *) host->hostdata)->ncb;
-	tp = &np->target[device->id];
-	tp->sdev = device;
-
 	/*
 	 *  Allocate the LCB if not yet.
 	 *  If it fail, we may well be in the sh*t. :)
@@ -1102,7 +1045,7 @@ static int sym53c8xx_slave_configure(str
 				 MSG_SIMPLE_TAG : 0),
 				depth_to_use);
 	lp->s.scdev_depth = depth_to_use;
-	sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
+	sym_tune_dev_queuing(tp, device->lun, reqtags);
 
 	if (!spi_initial_dv(device->sdev_target))
 		spi_dv_device(device);
@@ -1115,7 +1058,7 @@ static int sym53c8xx_slave_configure(str
  */
 static const char *sym53c8xx_info (struct Scsi_Host *host)
 {
-	return sym_driver_name();
+	return SYM_DRIVER_NAME;
 }
 
 
@@ -1178,44 +1121,47 @@ static void sym_exec_user_command (struc
 
 			case UC_SETSYNC:
 				if (!uc->data || uc->data >= 255) {
-					tp->tinfo.goal.options = 0;
-					tp->tinfo.goal.offset  = 0;
-					break;
-				}
-				if (uc->data <= 9 && np->minsync_dt) {
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 0;
+					tp->tgoal.offset = 0;
+				} else if (uc->data <= 9 && np->minsync_dt) {
 					if (uc->data < np->minsync_dt)
 						uc->data = np->minsync_dt;
-					tp->tinfo.goal.options = PPR_OPT_MASK;
-					tp->tinfo.goal.width   = 1;
-					tp->tinfo.goal.period = uc->data;
-					tp->tinfo.goal.offset = np->maxoffs_dt;
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 1;
+					tp->tgoal.width = 1;
+					tp->tgoal.period = uc->data;
+					tp->tgoal.offset = np->maxoffs_dt;
 				} else {
 					if (uc->data < np->minsync)
 						uc->data = np->minsync;
-					tp->tinfo.goal.options = 0;
-					tp->tinfo.goal.period = uc->data;
-					tp->tinfo.goal.offset = np->maxoffs;
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 0;
+					tp->tgoal.period = uc->data;
+					tp->tgoal.offset = np->maxoffs;
 				}
+				tp->tgoal.check_nego = 1;
 				break;
 			case UC_SETWIDE:
-				tp->tinfo.goal.width = uc->data ? 1 : 0;
+				tp->tgoal.width = uc->data ? 1 : 0;
+				tp->tgoal.check_nego = 1;
 				break;
 			case UC_SETTAGS:
 				for (l = 0; l < SYM_CONF_MAX_LUN; l++)
-					sym_tune_dev_queuing(np, t,l, uc->data);
+					sym_tune_dev_queuing(tp, l, uc->data);
 				break;
 			case UC_RESETDEV:
 				tp->to_reset = 1;
 				np->istat_sem = SEM;
-				OUTB (nc_istat, SIGP|SEM);
+				OUTB(np, nc_istat, SIGP|SEM);
 				break;
 			case UC_CLEARDEV:
 				for (l = 0; l < SYM_CONF_MAX_LUN; l++) {
-					struct sym_lcb *lp = sym_lp(np, tp, l);
+					struct sym_lcb *lp = sym_lp(tp, l);
 					if (lp) lp->to_clear = 1;
 				}
 				np->istat_sem = SEM;
-				OUTB (nc_istat, SIGP|SEM);
+				OUTB(np, nc_istat, SIGP|SEM);
 				break;
 			case UC_SETFLAG:
 				tp->usrflags = uc->data;
@@ -1226,8 +1172,6 @@ static void sym_exec_user_command (struc
 	}
 }
 
-#define digit_to_bin(c)	((c) - '0')
-
 static int skip_spaces(char *ptr, int len)
 {
 	int cnt, c;
@@ -1239,17 +1183,10 @@ static int skip_spaces(char *ptr, int le
 
 static int get_int_arg(char *ptr, int len, u_long *pv)
 {
-	int	cnt, c;
-	u_long	v;
-
-	for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && isdigit(c); cnt--) {
-		v = (v * 10) + digit_to_bin(c);
-	}
-
-	if (pv)
-		*pv = v;
+	char *end;
 
-	return (len - cnt);
+	*pv = simple_strtoul(ptr, &end, 10);
+	return (end - ptr);
 }
 
 static int is_keyword(char *ptr, int len, char *verb)
@@ -1260,15 +1197,14 @@ static int is_keyword(char *ptr, int len
 		return verb_len;
 	else
 		return 0;
-
 }
 
-#define SKIP_SPACES(min_spaces)						\
-	if ((arg_len = skip_spaces(ptr, len)) < (min_spaces))		\
+#define SKIP_SPACES(ptr, len)						\
+	if ((arg_len = skip_spaces(ptr, len)) < 1)			\
 		return -EINVAL;						\
 	ptr += arg_len; len -= arg_len;
 
-#define GET_INT_ARG(v)							\
+#define GET_INT_ARG(ptr, len, v)					\
 	if (!(arg_len = get_int_arg(ptr, len, &(v))))			\
 		return -EINVAL;						\
 	ptr += arg_len; len -= arg_len;
@@ -1327,12 +1263,12 @@ printk("sym_user_command: arg_len=%d, cm
 	case UC_SETFLAG:
 	case UC_RESETDEV:
 	case UC_CLEARDEV:
-		SKIP_SPACES(1);
+		SKIP_SPACES(ptr, len);
 		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
 			ptr += arg_len; len -= arg_len;
 			uc->target = ~0;
 		} else {
-			GET_INT_ARG(target);
+			GET_INT_ARG(ptr, len, target);
 			uc->target = (1<<target);
 #ifdef DEBUG_PROC_INFO
 printk("sym_user_command: target=%ld\n", target);
@@ -1346,8 +1282,8 @@ printk("sym_user_command: target=%ld\n",
 	case UC_SETSYNC:
 	case UC_SETTAGS:
 	case UC_SETWIDE:
-		SKIP_SPACES(1);
-		GET_INT_ARG(uc->data);
+		SKIP_SPACES(ptr, len);
+		GET_INT_ARG(ptr, len, uc->data);
 #ifdef DEBUG_PROC_INFO
 printk("sym_user_command: data=%ld\n", uc->data);
 #endif
@@ -1355,7 +1291,7 @@ printk("sym_user_command: data=%ld\n", u
 #ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
 	case UC_SETDEBUG:
 		while (len > 0) {
-			SKIP_SPACES(1);
+			SKIP_SPACES(ptr, len);
 			if	((arg_len = is_keyword(ptr, len, "alloc")))
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
@@ -1389,7 +1325,7 @@ printk("sym_user_command: data=%ld\n", u
 #endif /* SYM_LINUX_DEBUG_CONTROL_SUPPORT */
 	case UC_SETFLAG:
 		while (len > 0) {
-			SKIP_SPACES(1);
+			SKIP_SPACES(ptr, len);
 			if	((arg_len = is_keyword(ptr, len, "no_disc")))
 				uc->data &= ~SYM_DISC_ENABLED;
 			else
@@ -1499,15 +1435,9 @@ static int sym_host_info(struct sym_hcb 
 static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer,
 			char **start, off_t offset, int length, int func)
 {
-	struct host_data *host_data;
-	struct sym_hcb *np = NULL;
+	struct sym_hcb *np = sym_get_hcb(host);
 	int retv;
 
-	host_data = (struct host_data *) host->hostdata;
-	np = host_data->ncb;
-	if (!np)
-		return -EINVAL;
-
 	if (func) {
 #ifdef	SYM_LINUX_USER_COMMAND_SUPPORT
 		retv = sym_user_command(np, buffer, length);
@@ -1531,19 +1461,17 @@ static int sym53c8xx_proc_info(struct Sc
 /*
  *	Free controller resources.
  */
-static void sym_free_resources(struct sym_hcb *np)
+static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
 {
 	/*
 	 *  Free O/S specific resources.
 	 */
 	if (np->s.irq)
 		free_irq(np->s.irq, np);
-#ifndef SYM_CONF_IOMAPPED
-	if (np->s.mmio_va)
-		iounmap(np->s.mmio_va);
-#endif
-	if (np->s.ram_va)
-		iounmap(np->s.ram_va);
+	if (np->s.ioaddr)
+		pci_iounmap(pdev, np->s.ioaddr);
+	if (np->s.ramaddr)
+		pci_iounmap(pdev, np->s.ramaddr);
 	/*
 	 *  Free O/S independent resources.
 	 */
@@ -1592,13 +1520,14 @@ static struct Scsi_Host * __devinit sym_
 	struct host_data *host_data;
 	struct sym_hcb *np = NULL;
 	struct Scsi_Host *instance = NULL;
+	struct pci_dev *pdev = dev->pdev;
 	unsigned long flags;
 	struct sym_fw *fw;
 
 	printk(KERN_INFO
 		"sym%d: <%s> rev 0x%x at pci %s irq " IRQ_FMT "\n",
 		unit, dev->chip.name, dev->chip.revision_id,
-		pci_name(dev->pdev), IRQ_PRM(dev->s.irq));
+		pci_name(pdev), IRQ_PRM(pdev->irq));
 
 	/*
 	 *  Get the firmware for this chip.
@@ -1621,22 +1550,22 @@ static struct Scsi_Host * __devinit sym_
 	 *  We keep track in the HCB of all the resources that 
 	 *  are to be released on error.
 	 */
-	np = __sym_calloc_dma(dev->pdev, sizeof(*np), "HCB");
+	np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB");
 	if (!np)
 		goto attach_failed;
-	np->s.device = dev->pdev;
-	np->bus_dmat = dev->pdev; /* Result in 1 DMA pool per HBA */
+	np->s.device = pdev;
+	np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */
 	host_data->ncb = np;
 	np->s.host = instance;
 
-	pci_set_drvdata(dev->pdev, np);
+	pci_set_drvdata(pdev, np);
 
 	/*
 	 *  Copy some useful infos to the HCB.
 	 */
 	np->hcb_ba	= vtobus(np);
 	np->verbose	= sym_driver_setup.verbose;
-	np->s.device	= dev->pdev;
+	np->s.device	= pdev;
 	np->s.unit	= unit;
 	np->device_id	= dev->chip.device_id;
 	np->revision_id	= dev->chip.revision_id;
@@ -1659,58 +1588,35 @@ static struct Scsi_Host * __devinit sym_
 	 *  Try to map the controller chip to
 	 *  virtual and physical memory.
 	 */
-	np->mmio_ba	= (u32)dev->s.base;
-	np->s.io_ws	= (np->features & FE_IO256)? 256 : 128;
-
-#ifndef SYM_CONF_IOMAPPED
-	np->s.mmio_va = ioremap(dev->s.base_c, np->s.io_ws);
-	if (!np->s.mmio_va) {
-		printf_err("%s: can't map PCI MMIO region\n", sym_name(np));
-		goto attach_failed;
-	} else if (sym_verbose > 1)
-		printf_info("%s: using memory mapped IO\n", sym_name(np));
-#endif /* !defined SYM_CONF_IOMAPPED */
-
-	np->s.io_port = dev->s.io_port;
+	np->mmio_ba = (u32)dev->mmio_base;
+	np->s.ioaddr	= dev->s.ioaddr;
+	np->s.ramaddr	= dev->s.ramaddr;
+	np->s.io_ws = (np->features & FE_IO256) ? 256 : 128;
 
 	/*
 	 *  Map on-chip RAM if present and supported.
 	 */
 	if (!(np->features & FE_RAM))
-		dev->s.base_2 = 0;
-	if (dev->s.base_2) {
-		np->ram_ba = (u32)dev->s.base_2;
-		if (np->features & FE_RAM8K)
-			np->ram_ws = 8192;
-		else
-			np->ram_ws = 4096;
-		np->s.ram_va = ioremap(dev->s.base_2_c, np->ram_ws);
-		if (!np->s.ram_va) {
-			printf_err("%s: can't map PCI MEMORY region\n",
-				sym_name(np));
-			goto attach_failed;
-		}
+		dev->ram_base = 0;
+	if (dev->ram_base) {
+		np->ram_ba = (u32)dev->ram_base;
+		np->ram_ws = (np->features & FE_RAM8K) ? 8192 : 4096;
 	}
 
-	/*
-	 *  Perform O/S independent stuff.
-	 */
-	if (sym_hcb_attach(np, fw, dev->nvram))
+	if (sym_hcb_attach(instance, fw, dev->nvram))
 		goto attach_failed;
 
-
 	/*
 	 *  Install the interrupt handler.
 	 *  If we synchonize the C code with SCRIPTS on interrupt, 
-	 *  we donnot want to share the INTR line at all.
+	 *  we do not want to share the INTR line at all.
 	 */
-	if (request_irq(dev->s.irq, sym53c8xx_intr, SA_SHIRQ,
-			NAME53C8XX, np)) {
+	if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) {
 		printf_err("%s: request irq %d failure\n",
-			sym_name(np), dev->s.irq);
+			sym_name(np), pdev->irq);
 		goto attach_failed;
 	}
-	np->s.irq = dev->s.irq;
+	np->s.irq = pdev->irq;
 
 	/*
 	 *  After SCSI devices have been opened, we cannot
@@ -1742,14 +1648,7 @@ static struct Scsi_Host * __devinit sym_
 	instance->this_id	= np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= SYM_CONF_MAX_LUN;
-#ifndef SYM_CONF_IOMAPPED
-	instance->base		= (unsigned long) np->s.mmio_va;
-#endif
-	instance->irq		= np->s.irq;
-	instance->unique_id	= np->s.io_port;
-	instance->io_port	= np->s.io_port;
-	instance->n_io_port	= np->s.io_ws;
-	instance->dma_channel	= 0;
+	instance->unique_id	= pci_resource_start(pdev, 0);
 	instance->cmd_per_lun	= SYM_CONF_MAX_TAG;
 	instance->can_queue	= (SYM_CONF_MAX_START-2);
 	instance->sg_tablesize	= SYM_CONF_MAX_SG;
@@ -1770,7 +1669,7 @@ static struct Scsi_Host * __devinit sym_
 		return NULL;
 	printf_info("%s: giving up ...\n", sym_name(np));
 	if (np)
-		sym_free_resources(np);
+		sym_free_resources(np, pdev);
 	scsi_host_put(instance);
 
 	return NULL;
@@ -1787,23 +1686,7 @@ static void __devinit sym_get_nvram(stru
 	devp->device_id = devp->chip.device_id;
 	nvp->type = 0;
 
-	/*
-	 *  Get access to chip IO registers
-	 */
-#ifndef SYM_CONF_IOMAPPED
-	devp->s.mmio_va = ioremap(devp->s.base_c, 128);
-	if (!devp->s.mmio_va)
-		return;
-#endif
-
 	sym_read_nvram(devp, nvp);
-
-	/*
-	 *  Release access to chip IO registers
-	 */
-#ifndef SYM_CONF_IOMAPPED
-	iounmap(devp->s.mmio_va);
-#endif
 }
 #else
 static inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
@@ -1813,15 +1696,15 @@ static inline void sym_get_nvram(struct 
 
 static int __devinit sym_check_supported(struct sym_device *device)
 {
-	struct sym_pci_chip *chip;
+	struct sym_chip *chip;
 	struct pci_dev *pdev = device->pdev;
 	u_char revision;
-	unsigned long io_port = device->s.io_port;
-	unsigned long base = device->s.base;
+	unsigned long io_port = pci_resource_start(pdev, 0);
 	int i;
 
 	/*
 	 *  If user excluded this chip, do not initialize it.
+	 *  I hate this code so much.  Must kill it.
 	 */
 	if (io_port) {
 		for (i = 0 ; i < 8 ; i++) {
@@ -1831,32 +1714,14 @@ static int __devinit sym_check_supported
 	}
 
 	/*
-	 *  Check if the chip has been assigned resources we need.
-	 *  XXX: can this still happen with Linux 2.6's PCI layer?
-	 */
-#ifdef SYM_CONF_IOMAPPED
-	if (!io_port) {
-		printf_info("%s: IO base address disabled.\n",
-			    sym_name(device));
-		return -ENODEV;
-	}
-#else
-	if (!base) {
-		printf_info("%s: MMIO base address disabled.\n",
-			    sym_name(device));
-		return -ENODEV;
-	}
-#endif
-
-	/*
 	 * Check if the chip is supported.  Then copy the chip description
 	 * to our device structure so we can make it match the actual device
 	 * and options.
 	 */
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
-	chip = sym_lookup_pci_chip_table(pdev->device, revision);
+	chip = sym_lookup_chip_table(pdev->device, revision);
 	if (!chip) {
-		printf_info("%s: device not supported\n", sym_name(device));
+		dev_info(&pdev->dev, "device not supported\n");
 		return -ENODEV;
 	}
 	memcpy(&device->chip, chip, sizeof(device->chip));
@@ -1871,11 +1736,9 @@ static int __devinit sym_check_supported
  */
 static int __devinit sym_check_raid(struct sym_device *device)
 {
-	unsigned long base_2_c = device->s.base_2_c;
 	unsigned int ram_size, ram_val;
-	void __iomem *ram_ptr;
 
-	if (!base_2_c)
+	if (!device->s.ramaddr)
 		return 0;
 
 	if (device->chip.features & FE_RAM8K)
@@ -1883,23 +1746,18 @@ static int __devinit sym_check_raid(stru
 	else
 		ram_size = 4096;
 
-	ram_ptr = ioremap(base_2_c, ram_size);
-	if (!ram_ptr)
-		return 0;
-
-	ram_val = readl(ram_ptr + ram_size - 16);
-	iounmap(ram_ptr);
+	ram_val = readl(device->s.ramaddr + ram_size - 16);
 	if (ram_val != 0x52414944)
 		return 0;
 
-	printf_info("%s: not initializing, driven by RAID controller.\n",
-		    sym_name(device));
+	dev_info(&device->pdev->dev,
+			"not initializing, driven by RAID controller.\n");
 	return -ENODEV;
 }
 
 static int __devinit sym_set_workarounds(struct sym_device *device)
 {
-	struct sym_pci_chip *chip = &device->chip;
+	struct sym_chip *chip = &device->chip;
 	struct pci_dev *pdev = device->pdev;
 	u_short status_reg;
 
@@ -1952,26 +1810,25 @@ static int __devinit sym_set_workarounds
 static void __devinit
 sym_init_device(struct pci_dev *pdev, struct sym_device *device)
 {
-	unsigned long base, base_2; 
 	int i;
 
 	device->host_id = SYM_SETUP_HOST_ID;
 	device->pdev = pdev;
-	device->s.irq = pdev->irq;
-
-	/* Choose some short name for this device */
-	sprintf(device->s.inst_name, "sym.%d.%d.%d", pdev->bus->number,
-			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
-	device->s.io_port = pdev->resource[0].start;
+	i = pci_get_base_address(pdev, 1, &device->mmio_base);
+	pci_get_base_address(pdev, i, &device->ram_base);
 
-	device->s.base_c = pdev->resource[1].start;
-	i = pci_get_base_address(pdev, 1, &base);
-	device->s.base = base & PCI_BASE_ADDRESS_MEM_MASK;
-
-	device->s.base_2_c = pdev->resource[i].start;
-	pci_get_base_address(pdev, i, &base_2);
-	device->s.base_2 = base_2 & PCI_BASE_ADDRESS_MEM_MASK;
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
+	if (device->mmio_base)
+		device->s.ioaddr = pci_iomap(pdev, 1,
+						pci_resource_len(pdev, 1));
+#endif
+	if (!device->s.ioaddr)
+		device->s.ioaddr = pci_iomap(pdev, 0,
+						pci_resource_len(pdev, 0));
+	if (device->ram_base)
+		device->s.ramaddr = pci_iomap(pdev, i,
+						pci_resource_len(pdev, i));
 }
 
 /*
@@ -2027,7 +1884,7 @@ static void sym_config_pqs(struct pci_de
  *  Detach the host.
  *  We have to free resources and halt the NCR chip.
  */
-static int sym_detach(struct sym_hcb *np)
+static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev)
 {
 	printk("%s: detaching ...\n", sym_name(np));
 
@@ -2039,11 +1896,11 @@ static int sym_detach(struct sym_hcb *np
 	 * so, since we may not be safe if interrupts occur.
 	 */
 	printk("%s: resetting chip\n", sym_name(np));
-	OUTB (nc_istat, SRST);
-	UDELAY (10);
-	OUTB (nc_istat, 0);
+	OUTB(np, nc_istat, SRST);
+	udelay(10);
+	OUTB(np, nc_istat, 0);
 
-	sym_free_resources(np);
+	sym_free_resources(np, pdev);
 
 	return 1;
 }
@@ -2056,7 +1913,9 @@ static struct scsi_host_template sym2_te
 	.name			= "sym53c8xx",
 	.info			= sym53c8xx_info, 
 	.queuecommand		= sym53c8xx_queue_command,
+	.slave_alloc		= sym53c8xx_slave_alloc,
 	.slave_configure	= sym53c8xx_slave_configure,
+	.slave_destroy		= sym53c8xx_slave_destroy,
 	.eh_abort_handler	= sym53c8xx_eh_abort_handler,
 	.eh_device_reset_handler = sym53c8xx_eh_device_reset_handler,
 	.eh_bus_reset_handler	= sym53c8xx_eh_bus_reset_handler,
@@ -2116,7 +1975,7 @@ static int __devinit sym2_probe(struct p
 	return 0;
 
  detach:
-	sym_detach(pci_get_drvdata(pdev));
+	sym_detach(pci_get_drvdata(pdev), pdev);
  free:
 	pci_release_regions(pdev);
  disable:
@@ -2133,7 +1992,7 @@ static void __devexit sym2_remove(struct
 	scsi_remove_host(host);
 	scsi_host_put(host);
 
-	sym_detach(np);
+	sym_detach(np, pdev);
 
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
@@ -2143,12 +2002,12 @@ static void __devexit sym2_remove(struct
 
 static void sym2_get_signalling(struct Scsi_Host *shost)
 {
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	enum spi_signal_type type;
 
 	switch (np->scsi_mode) {
 	case SMODE_SE:
-		type =  SPI_SIGNAL_SE;
+		type = SPI_SIGNAL_SE;
 		break;
 	case SMODE_LVD:
 		type = SPI_SIGNAL_LVD;
@@ -2163,152 +2022,98 @@ static void sym2_get_signalling(struct S
 	spi_signalling(shost) = type;
 }
 
-static void sym2_get_offset(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
-
-	spi_offset(starget) = tp->tinfo.curr.offset;
-}
-
 static void sym2_set_offset(struct scsi_target *starget, int offset)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
-	tp->tinfo.goal.offset = offset;
-}
-
-
-static void sym2_get_period(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
-
-	spi_period(starget) = tp->tinfo.curr.period;
+	tp->tgoal.offset = offset;
+	tp->tgoal.check_nego = 1;
 }
 
 static void sym2_set_period(struct scsi_target *starget, int period)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
-	/* have to have DT for these transfers */
-	if (period <= np->minsync)
-		tp->tinfo.goal.options |= PPR_OPT_DT;
-
-	tp->tinfo.goal.period = period;
-}
-
-static void sym2_get_width(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
+	/* have to have DT for these transfers, but DT will also
+	 * set width, so check that this is allowed */
+	if (period <= np->minsync && spi_width(starget))
+		tp->tgoal.dt = 1;
 
-	spi_width(starget) = tp->tinfo.curr.width ? 1 : 0;
+	tp->tgoal.period = period;
+	tp->tgoal.check_nego = 1;
 }
 
 static void sym2_set_width(struct scsi_target *starget, int width)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
 	/* It is illegal to have DT set on narrow transfers.  If DT is
 	 * clear, we must also clear IU and QAS.  */
 	if (width == 0)
-		tp->tinfo.goal.options &= ~PPR_OPT_MASK;
-
-	tp->tinfo.goal.width = width;
-}
-
-static void sym2_get_dt(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
 
-	spi_dt(starget) = (tp->tinfo.curr.options & PPR_OPT_DT) ? 1 : 0;
+	tp->tgoal.width = width;
+	tp->tgoal.check_nego = 1;
 }
 
 static void sym2_set_dt(struct scsi_target *starget, int dt)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
 	/* We must clear QAS and IU if DT is clear */
 	if (dt)
-		tp->tinfo.goal.options |= PPR_OPT_DT;
+		tp->tgoal.dt = 1;
 	else
-		tp->tinfo.goal.options &= ~PPR_OPT_MASK;
-}
-
-static void sym2_get_iu(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
-
-	spi_iu(starget) = (tp->tinfo.curr.options & PPR_OPT_IU) ? 1 : 0;
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+	tp->tgoal.check_nego = 1;
 }
 
 static void sym2_set_iu(struct scsi_target *starget, int iu)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
 	if (iu)
-		tp->tinfo.goal.options |= PPR_OPT_IU | PPR_OPT_DT;
+		tp->tgoal.iu = tp->tgoal.dt = 1;
 	else
-		tp->tinfo.goal.options &= ~PPR_OPT_IU;
-}
-
-static void sym2_get_qas(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[starget->id];
-
-	spi_qas(starget) = (tp->tinfo.curr.options & PPR_OPT_QAS) ? 1 : 0;
+		tp->tgoal.iu = 0;
+	tp->tgoal.check_nego = 1;
 }
 
 static void sym2_set_qas(struct scsi_target *starget, int qas)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_hcb *np = sym_get_hcb(shost);
 	struct sym_tcb *tp = &np->target[starget->id];
 
 	if (qas)
-		tp->tinfo.goal.options |= PPR_OPT_QAS | PPR_OPT_DT;
+		tp->tgoal.dt = tp->tgoal.qas = 1;
 	else
-		tp->tinfo.goal.options &= ~PPR_OPT_QAS;
+		tp->tgoal.qas = 0;
+	tp->tgoal.check_nego = 1;
 }
 
 
 static struct spi_function_template sym2_transport_functions = {
 	.set_offset	= sym2_set_offset,
-	.get_offset	= sym2_get_offset,
 	.show_offset	= 1,
 	.set_period	= sym2_set_period,
-	.get_period	= sym2_get_period,
 	.show_period	= 1,
 	.set_width	= sym2_set_width,
-	.get_width	= sym2_get_width,
 	.show_width	= 1,
-	.get_dt		= sym2_get_dt,
 	.set_dt		= sym2_set_dt,
 	.show_dt	= 1,
-	.get_iu		= sym2_get_iu,
 	.set_iu		= sym2_set_iu,
 	.show_iu	= 1,
-	.get_qas	= sym2_get_qas,
 	.set_qas	= sym2_set_qas,
 	.show_qas	= 1,
 	.get_signalling	= sym2_get_signalling,
@@ -2370,7 +2175,7 @@ static int __init sym2_init(void)
 	if (!sym2_transport_template)
 		return -ENODEV;
 
-	error = pci_module_init(&sym2_driver);
+	error = pci_register_driver(&sym2_driver);
 	if (error)
 		spi_release_transport(sym2_transport_template);
 	return error;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -56,9 +56,10 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_spi.h>
 #include <scsi/scsi_host.h>
 
-#include "sym_conf.h"
+#include "sym53c8xx.h"
 #include "sym_defs.h"
 #include "sym_misc.h"
 
@@ -70,7 +71,6 @@
 #define SYM_OPT_HANDLE_DIR_UNKNOWN
 #define SYM_OPT_HANDLE_DEVICE_QUEUEING
 #define SYM_OPT_LIMIT_COMMAND_REORDERING
-#define	SYM_OPT_ANNOUNCE_TRANSFER_RATE
 
 /*
  *  Print a message with severity.
@@ -86,11 +86,6 @@
 #define	printf(args...)		printk(args)
 
 /*
- *  Insert a delay in micro-seconds
- */
-#define sym_udelay(us)	udelay(us)
-
-/*
  *  A 'read barrier' flushes any data that have been prefetched 
  *  by the processor due to out of order execution. Such a barrier 
  *  must notably be inserted prior to looking at data that have 
@@ -111,23 +106,12 @@
 #define MEMORY_WRITE_BARRIER()	wmb()
 
 /*
- *  Let the compiler know about driver data structure names.
- */
-typedef struct sym_tcb *tcb_p;
-typedef struct sym_lcb *lcb_p;
-typedef struct sym_ccb *ccb_p;
-
-/*
  *  IO functions definition for big/little endian CPU support.
  *  For now, PCI chips are only supported in little endian addressing mode, 
  */
 
 #ifdef	__BIG_ENDIAN
 
-#define	inw_l2b		inw
-#define	inl_l2b		inl
-#define	outw_b2l	outw
-#define	outl_b2l	outl
 #define	readw_l2b	readw
 #define	readl_l2b	readl
 #define	writew_b2l	writew
@@ -135,11 +119,6 @@ typedef struct sym_ccb *ccb_p;
 
 #else	/* little endian */
 
-#define	inw_raw		inw
-#define	inl_raw		inl
-#define	outw_raw	outw
-#define	outl_raw	outl
-
 #define	readw_raw	readw
 #define	readl_raw	readl
 #define	writew_raw	writew
@@ -151,27 +130,6 @@ typedef struct sym_ccb *ccb_p;
 #error	"Chips in BIG ENDIAN addressing mode are not (yet) supported"
 #endif
 
-
-/*
- *  If the chip uses big endian addressing mode over the 
- *  PCI, actual io register addresses for byte and word 
- *  accesses must be changed according to lane routing.
- *  Btw, sym_offb() and sym_offw() macros only apply to 
- *  constants and so donnot generate bloated code.
- */
-
-#if	defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define sym_offb(o)	(((o)&~3)+((~((o)&3))&3))
-#define sym_offw(o)	(((o)&~3)+((~((o)&3))&2))
-
-#else
-
-#define sym_offb(o)	(o)
-#define sym_offw(o)	(o)
-
-#endif
-
 /*
  *  If the CPU and the chip use same endian-ness addressing,
  *  no byte reordering is needed for script patching.
@@ -180,117 +138,9 @@ typedef struct sym_ccb *ccb_p;
  *  from the script.
  */
 
-#if	defined(__BIG_ENDIAN) && !defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
 #define cpu_to_scr(dw)	cpu_to_le32(dw)
 #define scr_to_cpu(dw)	le32_to_cpu(dw)
 
-#elif	defined(__LITTLE_ENDIAN) && defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_be32(dw)
-#define scr_to_cpu(dw)	be32_to_cpu(dw)
-
-#else
-
-#define cpu_to_scr(dw)	(dw)
-#define scr_to_cpu(dw)	(dw)
-
-#endif
-
-/*
- *  Access to the controller chip.
- *
- *  If SYM_CONF_IOMAPPED is defined, the driver will use 
- *  normal IOs instead of the MEMORY MAPPED IO method  
- *  recommended by PCI specifications.
- *  If all PCI bridges, host brigdes and architectures 
- *  would have been correctly designed for PCI, this 
- *  option would be useless.
- *
- *  If the CPU and the chip use same endian-ness addressing,
- *  no byte reordering is needed for accessing chip io 
- *  registers. Functions suffixed by '_raw' are assumed 
- *  to access the chip over the PCI without doing byte 
- *  reordering. Functions suffixed by '_l2b' are 
- *  assumed to perform little-endian to big-endian byte 
- *  reordering, those suffixed by '_b2l' blah, blah,
- *  blah, ...
- */
-
-#if defined(SYM_CONF_IOMAPPED)
-
-/*
- *  IO mapped only input / ouput
- */
-
-#define	INB_OFF(o)        inb (np->s.io_port + sym_offb(o))
-#define	OUTB_OFF(o, val)  outb ((val), np->s.io_port + sym_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define	INW_OFF(o)        inw_l2b (np->s.io_port + sym_offw(o))
-#define	INL_OFF(o)        inl_l2b (np->s.io_port + (o))
-
-#define	OUTW_OFF(o, val)  outw_b2l ((val), np->s.io_port + sym_offw(o))
-#define	OUTL_OFF(o, val)  outl_b2l ((val), np->s.io_port + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define	INW_OFF(o)        inw_b2l (np->s.io_port + sym_offw(o))
-#define	INL_OFF(o)        inl_b2l (np->s.io_port + (o))
-
-#define	OUTW_OFF(o, val)  outw_l2b ((val), np->s.io_port + sym_offw(o))
-#define	OUTL_OFF(o, val)  outl_l2b ((val), np->s.io_port + (o))
-
-#else
-
-#define	INW_OFF(o)        inw_raw (np->s.io_port + sym_offw(o))
-#define	INL_OFF(o)        inl_raw (np->s.io_port + (o))
-
-#define	OUTW_OFF(o, val)  outw_raw ((val), np->s.io_port + sym_offw(o))
-#define	OUTL_OFF(o, val)  outl_raw ((val), np->s.io_port + (o))
-
-#endif	/* ENDIANs */
-
-#else	/* defined SYM_CONF_IOMAPPED */
-
-/*
- *  MEMORY mapped IO input / output
- */
-
-#define INB_OFF(o)        readb(np->s.mmio_va + sym_offb(o))
-#define OUTB_OFF(o, val)  writeb((val), np->s.mmio_va + sym_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define INW_OFF(o)        readw_l2b(np->s.mmio_va + sym_offw(o))
-#define INL_OFF(o)        readl_l2b(np->s.mmio_va + (o))
-
-#define OUTW_OFF(o, val)  writew_b2l((val), np->s.mmio_va + sym_offw(o))
-#define OUTL_OFF(o, val)  writel_b2l((val), np->s.mmio_va + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SYM_CONF_CHIP_BIG_ENDIAN)
-
-#define INW_OFF(o)        readw_b2l(np->s.mmio_va + sym_offw(o))
-#define INL_OFF(o)        readl_b2l(np->s.mmio_va + (o))
-
-#define OUTW_OFF(o, val)  writew_l2b((val), np->s.mmio_va + sym_offw(o))
-#define OUTL_OFF(o, val)  writel_l2b((val), np->s.mmio_va + (o))
-
-#else
-
-#define INW_OFF(o)        readw_raw(np->s.mmio_va + sym_offw(o))
-#define INL_OFF(o)        readl_raw(np->s.mmio_va + (o))
-
-#define OUTW_OFF(o, val)  writew_raw((val), np->s.mmio_va + sym_offw(o))
-#define OUTL_OFF(o, val)  writel_raw((val), np->s.mmio_va + (o))
-
-#endif
-
-#endif	/* defined SYM_CONF_IOMAPPED */
-
-#define OUTRAM_OFF(o, a, l) memcpy_toio(np->s.ram_va + (o), (a), (l))
-
 /*
  *  Remap some status field values.
  */
@@ -360,9 +210,8 @@ struct sym_shcb {
 
 	struct Scsi_Host *host;
 
-	void __iomem *	mmio_va;	/* MMIO kernel virtual address	*/
-	void __iomem *	ram_va;		/* RAM  kernel virtual address	*/
-	u_long		io_port;	/* IO port address cookie	*/
+	void __iomem *	ioaddr;		/* MMIO kernel io address	*/
+	void __iomem *	ramaddr;	/* RAM  kernel io address	*/
 	u_short		io_ws;		/* IO window size		*/
 	int		irq;		/* IRQ number			*/
 
@@ -377,29 +226,20 @@ struct sym_shcb {
  */
 #define sym_name(np) (np)->s.inst_name
 
-/*
- *  Data structure used as input for the NVRAM reading.
- *  Must resolve the IO macros and sym_name(), when  
- *  used as sub-field 's' of another structure.
- */
-struct sym_slot {
-	u_long	base;
-	u_long	base_2;
-	u_long	base_c;
-	u_long	base_2_c;
-	int	irq;
-/* port and address fields to fit INB, OUTB macros */
-	u_long	io_port;
-	void __iomem *	mmio_va;
-	char	inst_name[16];
-};
-
 struct sym_nvram;
 
+/*
+ * The IO macros require a struct called 's' and are abused in sym_nvram.c
+ */
 struct sym_device {
 	struct pci_dev *pdev;
-	struct sym_slot  s;
-	struct sym_pci_chip chip;
+	unsigned long mmio_base;
+	unsigned long ram_base;
+	struct {
+		void __iomem *ioaddr;
+		void __iomem *ramaddr;
+	} s;
+	struct sym_chip chip;
 	struct sym_nvram *nvram;
 	u_short device_id;
 	u_char host_id;
@@ -412,133 +252,48 @@ struct host_data {
 	struct sym_hcb *ncb;
 };
 
-/*
- *  The driver definitions (sym_hipd.h) must know about a 
- *  couple of things related to the memory allocator.
- */
-typedef u_long m_addr_t;	/* Enough bits to represent any address */
-#define SYM_MEM_PAGE_ORDER 0	/* 1 PAGE  maximum */
-#define SYM_MEM_CLUSTER_SHIFT	(PAGE_SHIFT+SYM_MEM_PAGE_ORDER)
-#ifdef	MODULE
-#define SYM_MEM_FREE_UNUSED	/* Free unused pages immediately */
-#endif
-typedef struct pci_dev *m_pool_ident_t;
-
-/*
- *  Include driver soft definitions.
- */
-#include "sym_fw.h"
-#include "sym_hipd.h"
-
-/*
- *  Memory allocator related stuff.
- */
-
-#define SYM_MEM_GFP_FLAGS	GFP_ATOMIC
-#define SYM_MEM_WARN	1	/* Warn on failed operations */
-
-#define sym_get_mem_cluster()	\
-	__get_free_pages(SYM_MEM_GFP_FLAGS, SYM_MEM_PAGE_ORDER)
-#define sym_free_mem_cluster(p)	\
-	free_pages(p, SYM_MEM_PAGE_ORDER)
-
-void *sym_calloc(int size, char *name);
-void sym_mfree(void *m, int size, char *name);
-
-/*
- *  We have to provide the driver memory allocator with methods for 
- *  it to maintain virtual to bus physical address translations.
- */
-
-#define sym_m_pool_match(mp_id1, mp_id2)	(mp_id1 == mp_id2)
-
-static __inline m_addr_t sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
 {
-	void *vaddr = NULL;
-	dma_addr_t baddr = 0;
-
-	vaddr = pci_alloc_consistent(mp->dev_dmat,SYM_MEM_CLUSTER_SIZE, &baddr);
-	if (vaddr) {
-		vbp->vaddr = (m_addr_t) vaddr;
-		vbp->baddr = (m_addr_t) baddr;
-	}
-	return (m_addr_t) vaddr;
+	return ((struct host_data *)host->hostdata)->ncb;
 }
 
-static __inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
-{
-	pci_free_consistent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE,
-	                    (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
-}
-
-#define sym_m_create_dma_mem_tag(mp)	(0)
-#define sym_m_delete_dma_mem_tag(mp)	do { ; } while (0)
-
-void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name);
-void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name);
-m_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m);
+#include "sym_fw.h"
+#include "sym_hipd.h"
 
 /*
  *  Set the status field of a CAM CCB.
  */
 static __inline void 
-sym_set_cam_status(struct scsi_cmnd *ccb, int status)
+sym_set_cam_status(struct scsi_cmnd *cmd, int status)
 {
-	ccb->result &= ~(0xff  << 16);
-	ccb->result |= (status << 16);
+	cmd->result &= ~(0xff  << 16);
+	cmd->result |= (status << 16);
 }
 
 /*
  *  Get the status field of a CAM CCB.
  */
 static __inline int 
-sym_get_cam_status(struct scsi_cmnd *ccb)
+sym_get_cam_status(struct scsi_cmnd *cmd)
 {
-	return ((ccb->result >> 16) & 0xff);
+	return host_byte(cmd->result);
 }
 
 /*
- *  The dma mapping is mostly handled by the 
- *  SCSI layer and the driver glue under Linux.
- */
-#define sym_data_dmamap_create(np, cp)		(0)
-#define sym_data_dmamap_destroy(np, cp)		do { ; } while (0)
-#define sym_data_dmamap_unload(np, cp)		do { ; } while (0)
-#define sym_data_dmamap_presync(np, cp)		do { ; } while (0)
-#define sym_data_dmamap_postsync(np, cp)	do { ; } while (0)
-
-/*
- *  Async handler for negotiations.
- */
-void sym_xpt_async_nego_wide(struct sym_hcb *np, int target);
-#define sym_xpt_async_nego_sync(np, target)	\
-	sym_announce_transfer_rate(np, target)
-#define sym_xpt_async_nego_ppr(np, target)	\
-	sym_announce_transfer_rate(np, target)
-
-/*
  *  Build CAM result for a successful IO and for a failed IO.
  */
-static __inline void sym_set_cam_result_ok(struct sym_hcb *np, ccb_p cp, int resid)
+static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
 {
-	struct scsi_cmnd *cmd = cp->cam_ccb;
-
 	cmd->resid = resid;
 	cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
 }
-void sym_set_cam_result_error(struct sym_hcb *np, ccb_p cp, int resid);
+void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
 
-/*
- *  Other O/S specific methods.
- */
-#define sym_cam_target_id(ccb)	(ccb)->target
-#define sym_cam_target_lun(ccb)	(ccb)->lun
-#define	sym_freeze_cam_ccb(ccb)	do { ; } while (0)
 void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb);
-void sym_print_addr (ccb_p cp);
+#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
 void sym_xpt_async_bus_reset(struct sym_hcb *np);
 void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target);
-int  sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, ccb_p cp);
+int  sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
 void sym_log_bus_error(struct sym_hcb *np);
 void sym_sniff_inquiry(struct sym_hcb *np, struct scsi_cmnd *cmd, int resid);
 
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -3,7 +3,7 @@
  * of PCI-SCSI IO processors.
  *
  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
- * Copyright (c) 2003-2004  Matthew Wilcox <matthew@wil.cx>
+ * Copyright (c) 2003-2005  Matthew Wilcox <matthew@wil.cx>
  *
  * This driver is derived from the Linux sym53c8xx driver.
  * Copyright (C) 1998-2000  Gerard Roudier
@@ -49,54 +49,24 @@
  */
 static void sym_int_ma (struct sym_hcb *np);
 static void sym_int_sir (struct sym_hcb *np);
-static ccb_p sym_alloc_ccb(struct sym_hcb *np);
-static ccb_p sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);
+static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np);
+static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);
 static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln);
-static void sym_complete_error (struct sym_hcb *np, ccb_p cp);
-static void sym_complete_ok (struct sym_hcb *np, ccb_p cp);
-static int sym_compute_residual(struct sym_hcb *np, ccb_p cp);
+static void sym_complete_error (struct sym_hcb *np, struct sym_ccb *cp);
+static void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp);
+static int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp);
 
 /*
- *  Returns the name of this driver.
+ *  Print a buffer in hexadecimal format with a ".\n" at end.
  */
-char *sym_driver_name(void)
-{
-	return SYM_DRIVER_NAME;
-}
-/*
- *  Print a buffer in hexadecimal format.
- */
-static void sym_printb_hex (u_char *p, int n)
+static void sym_printl_hex(u_char *p, int n)
 {
 	while (n-- > 0)
 		printf (" %x", *p++);
-}
-
-/*
- *  Same with a label at beginning and .\n at end.
- */
-static void sym_printl_hex (char *label, u_char *p, int n)
-{
-	printf ("%s", label);
-	sym_printb_hex (p, n);
 	printf (".\n");
 }
 
 /*
- *  Print something which allows to retrieve the controler type, 
- *  unit, target, lun concerned by a kernel message.
- */
-static void sym_print_target (struct sym_hcb *np, int target)
-{
-	printf ("%s:%d:", sym_name(np), target);
-}
-
-static void sym_print_lun(struct sym_hcb *np, int target, int lun)
-{
-	printf ("%s:%d:%d:", sym_name(np), target, lun);
-}
-
-/*
  *  Print out the content of a SCSI message.
  */
 static int sym_show_msg (u_char * msg)
@@ -107,59 +77,51 @@ static int sym_show_msg (u_char * msg)
 		for (i=1;i<8;i++) {
 			if (i-1>msg[1]) break;
 			printf ("-%x",msg[i]);
-		};
+		}
 		return (i+1);
 	} else if ((*msg & 0xf0) == 0x20) {
 		printf ("-%x",msg[1]);
 		return (2);
-	};
+	}
 	return (1);
 }
 
-static void sym_print_msg (ccb_p cp, char *label, u_char *msg)
+static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg)
 {
-	PRINT_ADDR(cp);
-	if (label)
-		printf ("%s: ", label);
+	sym_print_addr(cp->cmd, "%s: ", label);
 
-	(void) sym_show_msg (msg);
-	printf (".\n");
+	sym_show_msg(msg);
+	printf(".\n");
 }
 
-static void sym_print_nego_msg (struct sym_hcb *np, int target, char *label, u_char *msg)
+static void sym_print_nego_msg(struct sym_hcb *np, int target, char *label, u_char *msg)
 {
-	PRINT_TARGET(np, target);
-	if (label)
-		printf ("%s: ", label);
+	struct sym_tcb *tp = &np->target[target];
+	dev_info(&tp->sdev->sdev_target->dev, "%s: ", label);
 
-	(void) sym_show_msg (msg);
-	printf (".\n");
+	sym_show_msg(msg);
+	printf(".\n");
 }
 
 /*
  *  Print something that tells about extended errors.
  */
-void sym_print_xerr(ccb_p cp, int x_status)
+void sym_print_xerr(struct scsi_cmnd *cmd, int x_status)
 {
 	if (x_status & XE_PARITY_ERR) {
-		PRINT_ADDR(cp);
-		printf ("unrecovered SCSI parity error.\n");
+		sym_print_addr(cmd, "unrecovered SCSI parity error.\n");
 	}
 	if (x_status & XE_EXTRA_DATA) {
-		PRINT_ADDR(cp);
-		printf ("extraneous data discarded.\n");
+		sym_print_addr(cmd, "extraneous data discarded.\n");
 	}
 	if (x_status & XE_BAD_PHASE) {
-		PRINT_ADDR(cp);
-		printf ("illegal scsi phase (4/5).\n");
+		sym_print_addr(cmd, "illegal scsi phase (4/5).\n");
 	}
 	if (x_status & XE_SODL_UNRUN) {
-		PRINT_ADDR(cp);
-		printf ("ODD transfer in DATA OUT phase.\n");
+		sym_print_addr(cmd, "ODD transfer in DATA OUT phase.\n");
 	}
 	if (x_status & XE_SWIDE_OVRUN) {
-		PRINT_ADDR(cp);
-		printf ("ODD transfer in DATA IN phase.\n");
+		sym_print_addr(cmd, "ODD transfer in DATA IN phase.\n");
 	}
 }
 
@@ -186,10 +148,10 @@ static char *sym_scsi_bus_mode(int mode)
  */
 static void sym_chip_reset (struct sym_hcb *np)
 {
-	OUTB (nc_istat, SRST);
-	UDELAY (10);
-	OUTB (nc_istat, 0);
-	UDELAY(2000);	/* For BUS MODE to settle */
+	OUTB(np, nc_istat, SRST);
+	udelay(10);
+	OUTB(np, nc_istat, 0);
+	udelay(2000);	/* For BUS MODE to settle */
 }
 
 /*
@@ -206,27 +168,27 @@ static void sym_soft_reset (struct sym_h
 	u_char istat = 0;
 	int i;
 
-	if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SCRUN))
+	if (!(np->features & FE_ISTAT1) || !(INB(np, nc_istat1) & SCRUN))
 		goto do_chip_reset;
 
-	OUTB (nc_istat, CABRT);
+	OUTB(np, nc_istat, CABRT);
 	for (i = 100000 ; i ; --i) {
-		istat = INB (nc_istat);
+		istat = INB(np, nc_istat);
 		if (istat & SIP) {
-			INW (nc_sist);
+			INW(np, nc_sist);
 		}
 		else if (istat & DIP) {
-			if (INB (nc_dstat) & ABRT)
+			if (INB(np, nc_dstat) & ABRT)
 				break;
 		}
-		UDELAY(5);
+		udelay(5);
 	}
-	OUTB (nc_istat, 0);
+	OUTB(np, nc_istat, 0);
 	if (!i)
 		printf("%s: unable to abort current chip operation, "
 		       "ISTAT=0x%02x.\n", sym_name(np), istat);
 do_chip_reset:
-	sym_chip_reset (np);
+	sym_chip_reset(np);
 }
 
 /*
@@ -236,7 +198,7 @@ do_chip_reset:
  */
 static void sym_start_reset(struct sym_hcb *np)
 {
-	(void) sym_reset_scsi_bus(np, 1);
+	sym_reset_scsi_bus(np, 1);
 }
  
 int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int)
@@ -246,15 +208,15 @@ int sym_reset_scsi_bus(struct sym_hcb *n
 
 	sym_soft_reset(np);	/* Soft reset the chip */
 	if (enab_int)
-		OUTW (nc_sien, RST);
+		OUTW(np, nc_sien, RST);
 	/*
 	 *  Enable Tolerant, reset IRQD if present and 
 	 *  properly set IRQ mode, prior to resetting the bus.
 	 */
-	OUTB (nc_stest3, TE);
-	OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
-	OUTB (nc_scntl1, CRST);
-	UDELAY (200);
+	OUTB(np, nc_stest3, TE);
+	OUTB(np, nc_dcntl, (np->rv_dcntl & IRQM));
+	OUTB(np, nc_scntl1, CRST);
+	udelay(200);
 
 	if (!SYM_SETUP_SCSI_BUS_CHECK)
 		goto out;
@@ -264,12 +226,12 @@ int sym_reset_scsi_bus(struct sym_hcb *n
 	 *  We are expecting RESET to be TRUE and other signals to be 
 	 *  FALSE.
 	 */
-	term =	INB(nc_sstat0);
+	term =	INB(np, nc_sstat0);
 	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
-	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
-		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
-		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
-		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
+	term |= ((INB(np, nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(np, nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(np, nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(np, nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
 	if (!np->maxwide)
 		term &= 0x3ffff;
@@ -286,7 +248,7 @@ int sym_reset_scsi_bus(struct sym_hcb *n
 			retv = 1;
 	}
 out:
-	OUTB (nc_scntl1, 0);
+	OUTB(np, nc_scntl1, 0);
 	return retv;
 }
 
@@ -299,31 +261,31 @@ static void sym_selectclock(struct sym_h
 	 *  If multiplier not present or not selected, leave here.
 	 */
 	if (np->multiplier <= 1) {
-		OUTB(nc_scntl3,	scntl3);
+		OUTB(np, nc_scntl3, scntl3);
 		return;
 	}
 
 	if (sym_verbose >= 2)
 		printf ("%s: enabling clock multiplier\n", sym_name(np));
 
-	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
+	OUTB(np, nc_stest1, DBLEN);	   /* Enable clock multiplier */
 	/*
 	 *  Wait for the LCKFRQ bit to be set if supported by the chip.
 	 *  Otherwise wait 50 micro-seconds (at least).
 	 */
 	if (np->features & FE_LCKFRQ) {
 		int i = 20;
-		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
-			UDELAY (20);
+		while (!(INB(np, nc_stest4) & LCKFRQ) && --i > 0)
+			udelay(20);
 		if (!i)
 			printf("%s: the chip cannot lock the frequency\n",
 				sym_name(np));
 	} else
-		UDELAY ((50+10));
-	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
-	OUTB(nc_scntl3,	scntl3);
-	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
-	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
+		udelay((50+10));
+	OUTB(np, nc_stest3, HSC);		/* Halt the scsi clock	*/
+	OUTB(np, nc_scntl3, scntl3);
+	OUTB(np, nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
+	OUTB(np, nc_stest3, 0x00);		/* Restart scsi clock 	*/
 }
 
 
@@ -368,38 +330,38 @@ static unsigned getfreq (struct sym_hcb 
 	 * performed trust the higher delay 
 	 * (lower frequency returned).
 	 */
-	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
-	(void) INW (nc_sist);	/* clear pending scsi interrupt */
-	OUTB (nc_dien , 0);	/* mask all dma interrupts */
-	(void) INW (nc_sist);	/* another one, just to be sure :) */
+	OUTW(np, nc_sien, 0);	/* mask all scsi interrupts */
+	INW(np, nc_sist);	/* clear pending scsi interrupt */
+	OUTB(np, nc_dien, 0);	/* mask all dma interrupts */
+	INW(np, nc_sist);	/* another one, just to be sure :) */
 	/*
 	 * The C1010-33 core does not report GEN in SIST,
 	 * if this interrupt is masked in SIEN.
 	 * I don't know yet if the C1010-66 behaves the same way.
 	 */
 	if (np->features & FE_C10) {
-		OUTW (nc_sien, GEN);
-		OUTB (nc_istat1, SIRQD);
+		OUTW(np, nc_sien, GEN);
+		OUTB(np, nc_istat1, SIRQD);
 	}
-	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
-	OUTB (nc_stime1, 0);	/* disable general purpose timer */
-	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
-	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
-		UDELAY (1000/4);/* count in 1/4 of ms */
-	OUTB (nc_stime1, 0);	/* disable general purpose timer */
+	OUTB(np, nc_scntl3, 4);	   /* set pre-scaler to divide by 3 */
+	OUTB(np, nc_stime1, 0);	   /* disable general purpose timer */
+	OUTB(np, nc_stime1, gen);  /* set to nominal delay of 1<<gen * 125us */
+	while (!(INW(np, nc_sist) & GEN) && ms++ < 100000)
+		udelay(1000/4);    /* count in 1/4 of ms */
+	OUTB(np, nc_stime1, 0);    /* disable general purpose timer */
 	/*
 	 * Undo C1010-33 specific settings.
 	 */
 	if (np->features & FE_C10) {
-		OUTW (nc_sien, 0);
-		OUTB (nc_istat1, 0);
+		OUTW(np, nc_sien, 0);
+		OUTB(np, nc_istat1, 0);
 	}
  	/*
  	 * set prescaler to divide by whatever 0 means
  	 * 0 ought to choose divide by 2, but appears
  	 * to set divide by 3.5 mode in my 53c810 ...
  	 */
- 	OUTB (nc_scntl3, 0);
+ 	OUTB(np, nc_scntl3, 0);
 
   	/*
  	 * adjust for prescaler, and convert into KHz 
@@ -425,7 +387,7 @@ static unsigned sym_getfreq (struct sym_
 	u_int f1, f2;
 	int gen = 8;
 
-	(void) getfreq (np, gen);	/* throw away first result */
+	getfreq (np, gen);	/* throw away first result */
 	f1 = getfreq (np, gen);
 	f2 = getfreq (np, gen);
 	if (f1 > f2) f1 = f2;		/* trust lower result	*/
@@ -458,7 +420,7 @@ static void sym_getclock (struct sym_hcb
 	 *  Otherwise trust scntl3 BIOS setting.
 	 */
 	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
-		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
+		OUTB(np, nc_stest1, 0);		/* make sure doubler is OFF */
 		f1 = sym_getfreq (np);
 
 		if (sym_verbose)
@@ -505,9 +467,9 @@ static int sym_getpciclock (struct sym_h
 #else
 	if (1) {
 #endif
-		OUTB (nc_stest1, SCLK);	/* Use the PCI clock as SCSI clock */
-		f = (int) sym_getfreq (np);
-		OUTB (nc_stest1, 0);
+		OUTB(np, nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */
+		f = sym_getfreq(np);
+		OUTB(np, nc_stest1, 0);
 	}
 	np->pciclk_khz = f;
 
@@ -698,29 +660,29 @@ static void sym_print_targets_flag(struc
  */
 static void sym_save_initial_setting (struct sym_hcb *np)
 {
-	np->sv_scntl0	= INB(nc_scntl0) & 0x0a;
-	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
-	np->sv_dmode	= INB(nc_dmode)  & 0xce;
-	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
-	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
-	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
-	np->sv_gpcntl	= INB(nc_gpcntl);
-	np->sv_stest1	= INB(nc_stest1);
-	np->sv_stest2	= INB(nc_stest2) & 0x20;
-	np->sv_stest4	= INB(nc_stest4);
+	np->sv_scntl0	= INB(np, nc_scntl0) & 0x0a;
+	np->sv_scntl3	= INB(np, nc_scntl3) & 0x07;
+	np->sv_dmode	= INB(np, nc_dmode)  & 0xce;
+	np->sv_dcntl	= INB(np, nc_dcntl)  & 0xa8;
+	np->sv_ctest3	= INB(np, nc_ctest3) & 0x01;
+	np->sv_ctest4	= INB(np, nc_ctest4) & 0x80;
+	np->sv_gpcntl	= INB(np, nc_gpcntl);
+	np->sv_stest1	= INB(np, nc_stest1);
+	np->sv_stest2	= INB(np, nc_stest2) & 0x20;
+	np->sv_stest4	= INB(np, nc_stest4);
 	if (np->features & FE_C10) {	/* Always large DMA fifo + ultra3 */
-		np->sv_scntl4	= INB(nc_scntl4);
-		np->sv_ctest5	= INB(nc_ctest5) & 0x04;
+		np->sv_scntl4	= INB(np, nc_scntl4);
+		np->sv_ctest5	= INB(np, nc_ctest5) & 0x04;
 	}
 	else
-		np->sv_ctest5	= INB(nc_ctest5) & 0x24;
+		np->sv_ctest5	= INB(np, nc_ctest5) & 0x24;
 }
 
 /*
  *  Prepare io register values used by sym_start_up() 
  *  according to selected and supported features.
  */
-static int sym_prepare_setting(struct sym_hcb *np, struct sym_nvram *nvram)
+static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
 {
 	u_char	burst_max;
 	u32	period;
@@ -903,22 +865,20 @@ static int sym_prepare_setting(struct sy
 	/*
 	 *  Select some other
 	 */
-	if (SYM_SETUP_PCI_PARITY)
-		np->rv_ctest4	|= MPEE; /* Master parity checking */
-	if (SYM_SETUP_SCSI_PARITY)
-		np->rv_scntl0	|= 0x0a; /*  full arb., ena parity, par->ATN  */
+	np->rv_ctest4	|= MPEE; /* Master parity checking */
+	np->rv_scntl0	|= 0x0a; /*  full arb., ena parity, par->ATN  */
 
 	/*
 	 *  Get parity checking, host ID and verbose mode from NVRAM
 	 */
 	np->myaddr = 255;
-	sym_nvram_setup_host (np, nvram);
+	sym_nvram_setup_host(shost, np, nvram);
 
 	/*
 	 *  Get SCSI addr of host adapter (set by bios?).
 	 */
 	if (np->myaddr == 255) {
-		np->myaddr = INB(nc_scid) & 0x07;
+		np->myaddr = INB(np, nc_scid) & 0x07;
 		if (!np->myaddr)
 			np->myaddr = SYM_SETUP_HOST_ID;
 	}
@@ -946,7 +906,7 @@ static int sym_prepare_setting(struct sy
 					np->scsi_mode = SMODE_HVD;
 			}
 			else if (nvram->type == SYM_SYMBIOS_NVRAM) {
-				if (!(INB(nc_gpreg) & 0x08))
+				if (!(INB(np, nc_gpreg) & 0x08))
 					np->scsi_mode = SMODE_HVD;
 			}
 		}
@@ -988,12 +948,12 @@ static int sym_prepare_setting(struct sy
 	 *  If NVRAM present get targets setup from NVRAM.
 	 */
 	for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
-		tcb_p tp = &np->target[i];
+		struct sym_tcb *tp = &np->target[i];
 
 		tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED);
 		tp->usrtags = SYM_SETUP_MAX_TAG;
 
-		sym_nvram_setup_target (np, i, nvram);
+		sym_nvram_setup_target(np, i, nvram);
 
 		if (!tp->usrtags)
 			tp->usrflags &= ~SYM_TAGS_ENABLED;
@@ -1002,11 +962,8 @@ static int sym_prepare_setting(struct sy
 	/*
 	 *  Let user know about the settings.
 	 */
-	i = nvram->type;
-	printf("%s: %s NVRAM, ID %d, Fast-%d, %s, %s\n", sym_name(np),
-		i  == SYM_SYMBIOS_NVRAM ? "Symbios" :
-		(i == SYM_TEKRAM_NVRAM  ? "Tekram" : "No"),
-		np->myaddr,
+	printf("%s: %s, ID %d, Fast-%d, %s, %s\n", sym_name(np),
+		sym_nvram_type(nvram), np->myaddr,
 		(np->features & FE_ULTRA3) ? 80 : 
 		(np->features & FE_ULTRA2) ? 40 : 
 		(np->features & FE_ULTRA)  ? 20 : 10,
@@ -1055,7 +1012,7 @@ static int sym_prepare_setting(struct sy
  *
  *  Has to be called with interrupts disabled.
  */
-#ifndef SYM_CONF_IOMAPPED
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
 static int sym_regtest (struct sym_hcb *np)
 {
 	register volatile u32 data;
@@ -1065,8 +1022,8 @@ static int sym_regtest (struct sym_hcb *
 	 *  and try to read it back.
 	 */
 	data = 0xffffffff;
-	OUTL_OFF(offsetof(struct sym_reg, nc_dstat), data);
-	data = INL_OFF(offsetof(struct sym_reg, nc_dstat));
+	OUTL(np, nc_dstat, data);
+	data = INL(np, nc_dstat);
 #if 1
 	if (data == 0xffffffff) {
 #else
@@ -1075,7 +1032,7 @@ static int sym_regtest (struct sym_hcb *
 		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
 			(unsigned) data);
 		return (0x10);
-	};
+	}
 	return (0);
 }
 #endif
@@ -1084,7 +1041,7 @@ static int sym_snooptest (struct sym_hcb
 {
 	u32	sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat;
 	int	i, err=0;
-#ifndef SYM_CONF_IOMAPPED
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
 	err |= sym_regtest (np);
 	if (err) return (err);
 #endif
@@ -1093,37 +1050,37 @@ restart_test:
 	 *  Enable Master Parity Checking as we intend 
 	 *  to enable it for normal operations.
 	 */
-	OUTB (nc_ctest4, (np->rv_ctest4 & MPEE));
+	OUTB(np, nc_ctest4, (np->rv_ctest4 & MPEE));
 	/*
 	 *  init
 	 */
-	pc  = SCRIPTZ_BA (np, snooptest);
+	pc  = SCRIPTZ_BA(np, snooptest);
 	host_wr = 1;
 	sym_wr  = 2;
 	/*
 	 *  Set memory and register.
 	 */
 	np->scratch = cpu_to_scr(host_wr);
-	OUTL (nc_temp, sym_wr);
+	OUTL(np, nc_temp, sym_wr);
 	/*
 	 *  Start script (exchange values)
 	 */
-	OUTL (nc_dsa, np->hcb_ba);
-	OUTL_DSP (pc);
+	OUTL(np, nc_dsa, np->hcb_ba);
+	OUTL_DSP(np, pc);
 	/*
 	 *  Wait 'til done (with timeout)
 	 */
 	for (i=0; i<SYM_SNOOP_TIMEOUT; i++)
-		if (INB(nc_istat) & (INTF|SIP|DIP))
+		if (INB(np, nc_istat) & (INTF|SIP|DIP))
 			break;
 	if (i>=SYM_SNOOP_TIMEOUT) {
 		printf ("CACHE TEST FAILED: timeout.\n");
 		return (0x20);
-	};
+	}
 	/*
 	 *  Check for fatal DMA errors.
 	 */
-	dstat = INB (nc_dstat);
+	dstat = INB(np, nc_dstat);
 #if 1	/* Band aiding for broken hardwares that fail PCI parity */
 	if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) {
 		printf ("%s: PCI DATA PARITY ERROR DETECTED - "
@@ -1140,23 +1097,23 @@ restart_test:
 	/*
 	 *  Save termination position.
 	 */
-	pc = INL (nc_dsp);
+	pc = INL(np, nc_dsp);
 	/*
 	 *  Read memory and register.
 	 */
 	host_rd = scr_to_cpu(np->scratch);
-	sym_rd  = INL (nc_scratcha);
-	sym_bk  = INL (nc_temp);
+	sym_rd  = INL(np, nc_scratcha);
+	sym_bk  = INL(np, nc_temp);
 	/*
 	 *  Check termination position.
 	 */
-	if (pc != SCRIPTZ_BA (np, snoopend)+8) {
+	if (pc != SCRIPTZ_BA(np, snoopend)+8) {
 		printf ("CACHE TEST FAILED: script execution failed.\n");
 		printf ("start=%08lx, pc=%08lx, end=%08lx\n", 
-			(u_long) SCRIPTZ_BA (np, snooptest), (u_long) pc,
-			(u_long) SCRIPTZ_BA (np, snoopend) +8);
+			(u_long) SCRIPTZ_BA(np, snooptest), (u_long) pc,
+			(u_long) SCRIPTZ_BA(np, snoopend) +8);
 		return (0x40);
-	};
+	}
 	/*
 	 *  Show results.
 	 */
@@ -1164,17 +1121,17 @@ restart_test:
 		printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n",
 			(int) host_wr, (int) sym_rd);
 		err |= 1;
-	};
+	}
 	if (host_rd != sym_wr) {
 		printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n",
 			(int) sym_wr, (int) host_rd);
 		err |= 2;
-	};
+	}
 	if (sym_bk != sym_wr) {
 		printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n",
 			(int) sym_wr, (int) sym_bk);
 		err |= 4;
-	};
+	}
 
 	return (err);
 }
@@ -1215,7 +1172,7 @@ static void sym_log_hard_error(struct sy
 	u_char	*script_base;
 	int	i;
 
-	dsp	= INL (nc_dsp);
+	dsp	= INL(np, nc_dsp);
 
 	if	(dsp > np->scripta_ba &&
 		 dsp <= np->scripta_ba + np->scripta_sz) {
@@ -1238,12 +1195,12 @@ static void sym_log_hard_error(struct sy
 	}
 
 	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x/%x) @ (%s %x:%08x).\n",
-		sym_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
-		(unsigned)INB (nc_socl),   (unsigned)INB (nc_sbcl),
-		(unsigned)INB (nc_sbdl),   (unsigned)INB (nc_sxfer),
-		(unsigned)INB (nc_scntl3),
-		(np->features & FE_C10) ?  (unsigned)INB (nc_scntl4) : 0,
-		script_name, script_ofs,   (unsigned)INL (nc_dbc));
+		sym_name(np), (unsigned)INB(np, nc_sdid)&0x0f, dstat, sist,
+		(unsigned)INB(np, nc_socl), (unsigned)INB(np, nc_sbcl),
+		(unsigned)INB(np, nc_sbdl), (unsigned)INB(np, nc_sxfer),
+		(unsigned)INB(np, nc_scntl3),
+		(np->features & FE_C10) ?  (unsigned)INB(np, nc_scntl4) : 0,
+		script_name, script_ofs,   (unsigned)INL(np, nc_dbc));
 
 	if (((script_ofs & 3) == 0) &&
 	    (unsigned)script_ofs < script_size) {
@@ -1253,7 +1210,7 @@ static void sym_log_hard_error(struct sy
 
         printf ("%s: regdump:", sym_name(np));
         for (i=0; i<24;i++)
-            printf (" %02x", (unsigned)INB_OFF(i));
+            printf (" %02x", (unsigned)INB_OFF(np, i));
         printf (".\n");
 
 	/*
@@ -1263,7 +1220,7 @@ static void sym_log_hard_error(struct sy
 		sym_log_bus_error(np);
 }
 
-static struct sym_pci_chip sym_pci_dev_table[] = {
+static struct sym_chip sym_dev_table[] = {
  {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, 64,
  FE_ERL}
  ,
@@ -1347,8 +1304,8 @@ static struct sym_pci_chip sym_pci_dev_t
  FE_RAM|FE_IO256|FE_LEDC}
 };
 
-#define sym_pci_num_devs \
-	(sizeof(sym_pci_dev_table) / sizeof(sym_pci_dev_table[0]))
+#define sym_num_devs \
+	(sizeof(sym_dev_table) / sizeof(sym_dev_table[0]))
 
 /*
  *  Look up the chip table.
@@ -1356,14 +1313,14 @@ static struct sym_pci_chip sym_pci_dev_t
  *  Return a pointer to the chip entry if found, 
  *  zero otherwise.
  */
-struct sym_pci_chip *
-sym_lookup_pci_chip_table (u_short device_id, u_char revision)
+struct sym_chip *
+sym_lookup_chip_table (u_short device_id, u_char revision)
 {
-	struct	sym_pci_chip *chip;
+	struct	sym_chip *chip;
 	int	i;
 
-	for (i = 0; i < sym_pci_num_devs; i++) {
-		chip = &sym_pci_dev_table[i];
+	for (i = 0; i < sym_num_devs; i++) {
+		chip = &sym_dev_table[i];
 		if (device_id != chip->device_id)
 			continue;
 		if (revision > chip->revision_id)
@@ -1421,7 +1378,7 @@ static void sym_update_dmap_regs(struct 
 		return;
 	o = offsetof(struct sym_reg, nc_scrx[0]);
 	for (i = 0; i < SYM_DMAP_SIZE; i++) {
-		OUTL_OFF(o, np->dmap_bah[i]);
+		OUTL_OFF(np, o, np->dmap_bah[i]);
 		o += 4;
 	}
 	np->dmap_dirty = 0;
@@ -1429,52 +1386,52 @@ static void sym_update_dmap_regs(struct 
 #endif
 
 /* Enforce all the fiddly SPI rules and the chip limitations */
-static void sym_check_goals(struct scsi_device *sdev)
+static void sym_check_goals(struct sym_hcb *np, struct scsi_target *starget,
+		struct sym_trans *goal)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_trans *st = &np->target[sdev->id].tinfo.goal;
-
-	if (!scsi_device_wide(sdev))
-		st->width = 0;
+	if (!spi_support_wide(starget))
+		goal->width = 0;
 
-	if (!scsi_device_sync(sdev)) {
-		st->options = 0;
-		st->period = 0;
-		st->offset = 0;
+	if (!spi_support_sync(starget)) {
+		goal->iu = 0;
+		goal->dt = 0;
+		goal->qas = 0;
+		goal->period = 0;
+		goal->offset = 0;
 		return;
 	}
 
-	if (scsi_device_dt(sdev)) {
-		if (scsi_device_dt_only(sdev))
-			st->options |= PPR_OPT_DT;
+	if (spi_support_dt(starget)) {
+		if (spi_support_dt_only(starget))
+			goal->dt = 1;
 
-		if (st->offset == 0)
-			st->options &= ~PPR_OPT_DT;
+		if (goal->offset == 0)
+			goal->dt = 0;
 	} else {
-		st->options &= ~PPR_OPT_DT;
+		goal->dt = 0;
 	}
 
 	/* Some targets fail to properly negotiate DT in SE mode */
 	if ((np->scsi_mode != SMODE_LVD) || !(np->features & FE_U3EN))
-		st->options &= ~PPR_OPT_DT;
+		goal->dt = 0;
 
-	if (st->options & PPR_OPT_DT) {
+	if (goal->dt) {
 		/* all DT transfers must be wide */
-		st->width = 1;
-		if (st->offset > np->maxoffs_dt)
-			st->offset = np->maxoffs_dt;
-		if (st->period < np->minsync_dt)
-			st->period = np->minsync_dt;
-		if (st->period > np->maxsync_dt)
-			st->period = np->maxsync_dt;
+		goal->width = 1;
+		if (goal->offset > np->maxoffs_dt)
+			goal->offset = np->maxoffs_dt;
+		if (goal->period < np->minsync_dt)
+			goal->period = np->minsync_dt;
+		if (goal->period > np->maxsync_dt)
+			goal->period = np->maxsync_dt;
 	} else {
-		st->options &= ~PPR_OPT_MASK;
-		if (st->offset > np->maxoffs)
-			st->offset = np->maxoffs;
-		if (st->period < np->minsync)
-			st->period = np->minsync;
-		if (st->period > np->maxsync)
-			st->period = np->maxsync;
+		goal->iu = goal->qas = 0;
+		if (goal->offset > np->maxoffs)
+			goal->offset = np->maxoffs;
+		if (goal->period < np->minsync)
+			goal->period = np->minsync;
+		if (goal->period > np->maxsync)
+			goal->period = np->maxsync;
 	}
 }
 
@@ -1485,30 +1442,29 @@ static void sym_check_goals(struct scsi_
  *  negotiation and the nego_status field of the CCB.
  *  Returns the size of the message in bytes.
  */
-static int sym_prepare_nego(struct sym_hcb *np, ccb_p cp, u_char *msgptr)
+static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgptr)
 {
-	tcb_p tp = &np->target[cp->target];
-	struct scsi_device *sdev = tp->sdev;
-	struct sym_trans *goal = &tp->tinfo.goal;
-	struct sym_trans *curr = &tp->tinfo.curr;
+	struct sym_tcb *tp = &np->target[cp->target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+	struct sym_trans *goal = &tp->tgoal;
 	int msglen = 0;
 	int nego;
 
-	if (likely(sdev))
-		sym_check_goals(sdev);
+	sym_check_goals(np, starget, goal);
 
 	/*
 	 * Many devices implement PPR in a buggy way, so only use it if we
 	 * really want to.
 	 */
-	if ((goal->options & PPR_OPT_MASK) || (goal->period < 0xa)) {
+	if (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)) {
 		nego = NS_PPR;
-	} else if (curr->width != goal->width) {
+	} else if (spi_width(starget) != goal->width) {
 		nego = NS_WIDE;
-	} else if (curr->period != goal->period ||
-		   curr->offset != goal->offset) {
+	} else if (spi_period(starget) != goal->period ||
+		   spi_offset(starget) != goal->offset) {
 		nego = NS_SYNC;
 	} else {
+		goal->check_nego = 0;
 		nego = 0;
 	}
 
@@ -1534,9 +1490,11 @@ static int sym_prepare_nego(struct sym_h
 		msgptr[msglen++] = 0;
 		msgptr[msglen++] = goal->offset;
 		msgptr[msglen++] = goal->width;
-		msgptr[msglen++] = goal->options & PPR_OPT_MASK;
+		msgptr[msglen++] = (goal->iu ? PPR_OPT_IU : 0) |
+					(goal->dt ? PPR_OPT_DT : 0) |
+					(goal->qas ? PPR_OPT_QAS : 0);
 		break;
-	};
+	}
 
 	cp->nego_status = nego;
 
@@ -1547,8 +1505,8 @@ static int sym_prepare_nego(struct sym_h
 					  nego == NS_SYNC ? "sync msgout" :
 					  nego == NS_WIDE ? "wide msgout" :
 					  "ppr msgout", msgptr);
-		};
-	};
+		}
+	}
 
 	return msglen;
 }
@@ -1556,7 +1514,7 @@ static int sym_prepare_nego(struct sym_h
 /*
  *  Insert a job into the start queue.
  */
-void sym_put_start_queue(struct sym_hcb *np, ccb_p cp)
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
 {
 	u_short	qidx;
 
@@ -1608,17 +1566,17 @@ void sym_put_start_queue(struct sym_hcb 
 	 *  Wake it up.
 	 */
 	MEMORY_WRITE_BARRIER();
-	OUTB (nc_istat, SIGP|np->istat_sem);
+	OUTB(np, nc_istat, SIGP|np->istat_sem);
 }
 
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
 /*
  *  Start next ready-to-start CCBs.
  */
-void sym_start_next_ccbs(struct sym_hcb *np, lcb_p lp, int maxn)
+void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn)
 {
 	SYM_QUEHEAD *qp;
-	ccb_p cp;
+	struct sym_ccb *cp;
 
 	/* 
 	 *  Paranoia, as usual. :-)
@@ -1643,7 +1601,7 @@ void sym_start_next_ccbs(struct sym_hcb 
 			}
 			lp->itlq_tbl[cp->tag] = cpu_to_scr(cp->ccb_ba);
 			lp->head.resel_sa =
-				cpu_to_scr(SCRIPTA_BA (np, resel_tag));
+				cpu_to_scr(SCRIPTA_BA(np, resel_tag));
 			++lp->started_tags;
 		} else {
 			if (lp->started_no_tag || lp->started_tags) {
@@ -1652,7 +1610,7 @@ void sym_start_next_ccbs(struct sym_hcb 
 			}
 			lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba);
 			lp->head.resel_sa =
-			      cpu_to_scr(SCRIPTA_BA (np, resel_no_tag));
+			      cpu_to_scr(SCRIPTA_BA(np, resel_no_tag));
 			++lp->started_no_tag;
 		}
 		cp->started = 1;
@@ -1671,7 +1629,7 @@ void sym_start_next_ccbs(struct sym_hcb 
  */
 static int sym_wakeup_done (struct sym_hcb *np)
 {
-	ccb_p cp;
+	struct sym_ccb *cp;
 	int i, n;
 	u32 dsa;
 
@@ -1719,22 +1677,22 @@ static int sym_wakeup_done (struct sym_h
 static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status)
 {
 	SYM_QUEHEAD *qp;
-	ccb_p cp;
+	struct sym_ccb *cp;
 
 	while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) {
-		struct scsi_cmnd *ccb;
+		struct scsi_cmnd *cmd;
 		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
 		sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
 		/* Leave quiet CCBs waiting for resources */
 		if (cp->host_status == HS_WAIT)
 			continue;
-		ccb = cp->cam_ccb;
+		cmd = cp->cmd;
 		if (cam_status)
-			sym_set_cam_status(ccb, cam_status);
+			sym_set_cam_status(cmd, cam_status);
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
-		if (sym_get_cam_status(ccb) == CAM_REQUEUE_REQ) {
-			tcb_p tp = &np->target[cp->target];
-			lcb_p lp = sym_lp(np, tp, cp->lun);
+		if (sym_get_cam_status(cmd) == CAM_REQUEUE_REQ) {
+			struct sym_tcb *tp = &np->target[cp->target];
+			struct sym_lcb *lp = sym_lp(tp, cp->lun);
 			if (lp) {
 				sym_remque(&cp->link2_ccbq);
 				sym_insque_tail(&cp->link2_ccbq,
@@ -1751,8 +1709,7 @@ static void sym_flush_comp_queue(struct 
 		}
 #endif
 		sym_free_ccb(np, cp);
-		sym_freeze_cam_ccb(ccb);
-		sym_xpt_done(np, ccb);
+		sym_xpt_done(np, cmd);
 	}
 }
 
@@ -1790,8 +1747,8 @@ void sym_start_up (struct sym_hcb *np, i
 	if (reason == 1)
 		sym_soft_reset(np);
 	else {
-		OUTB (nc_stest3, TE|CSF);
-		OUTONB (nc_ctest3, CLF);
+		OUTB(np, nc_stest3, TE|CSF);
+		OUTONB(np, nc_ctest3, CLF);
 	}
  
 	/*
@@ -1839,39 +1796,39 @@ void sym_start_up (struct sym_hcb *np, i
 	/*
 	 *  Init chip.
 	 */
-	OUTB (nc_istat,  0x00   );	/*  Remove Reset, abort */
-	UDELAY (2000);	/* The 895 needs time for the bus mode to settle */
+	OUTB(np, nc_istat,  0x00);			/*  Remove Reset, abort */
+	udelay(2000); /* The 895 needs time for the bus mode to settle */
 
-	OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
+	OUTB(np, nc_scntl0, np->rv_scntl0 | 0xc0);
 					/*  full arb., ena parity, par->ATN  */
-	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
+	OUTB(np, nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
 
 	sym_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
 
-	OUTB (nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
-	OUTW (nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
-	OUTB (nc_istat , SIGP	);		/*  Signal Process */
-	OUTB (nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
-	OUTB (nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
-
-	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
-	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
-	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
+	OUTB(np, nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
+	OUTW(np, nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
+	OUTB(np, nc_istat , SIGP	);		/*  Signal Process */
+	OUTB(np, nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
+	OUTB(np, nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
+
+	OUTB(np, nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
+	OUTB(np, nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
+	OUTB(np, nc_ctest4, np->rv_ctest4);	/* Master parity checking */
 
 	/* Extended Sreq/Sack filtering not supported on the C10 */
 	if (np->features & FE_C10)
-		OUTB (nc_stest2, np->rv_stest2);
+		OUTB(np, nc_stest2, np->rv_stest2);
 	else
-		OUTB (nc_stest2, EXT|np->rv_stest2);
+		OUTB(np, nc_stest2, EXT|np->rv_stest2);
 
-	OUTB (nc_stest3, TE);			/* TolerANT enable */
-	OUTB (nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
+	OUTB(np, nc_stest3, TE);			/* TolerANT enable */
+	OUTB(np, nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
 
 	/*
 	 *  For now, disable AIP generation on C1010-66.
 	 */
 	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
-		OUTB (nc_aipcntl1, DISAIP);
+		OUTB(np, nc_aipcntl1, DISAIP);
 
 	/*
 	 *  C10101 rev. 0 errata.
@@ -1882,7 +1839,7 @@ void sym_start_up (struct sym_hcb *np, i
 	 */
 	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
 	    np->revision_id < 1)
-		OUTB (nc_stest1, INB(nc_stest1) | 0x30);
+		OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30);
 
 	/*
 	 *  DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
@@ -1890,7 +1847,7 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  regardless revision id (kind of post-chip-design feature. ;-))
 	 */
 	if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
-		OUTB (nc_ctest0, (1<<5));
+		OUTB(np, nc_ctest0, (1<<5));
 	else if (np->device_id == PCI_DEVICE_ID_NCR_53C896)
 		np->rv_ccntl0 |= DPR;
 
@@ -1900,8 +1857,8 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  seem to support those IO registers.
 	 */
 	if (np->features & (FE_DAC|FE_NOPM)) {
-		OUTB (nc_ccntl0, np->rv_ccntl0);
-		OUTB (nc_ccntl1, np->rv_ccntl1);
+		OUTB(np, nc_ccntl0, np->rv_ccntl0);
+		OUTB(np, nc_ccntl1, np->rv_ccntl1);
 	}
 
 #if	SYM_CONF_DMA_ADDRESSING_MODE == 2
@@ -1911,8 +1868,8 @@ void sym_start_up (struct sym_hcb *np, i
 	 */
 	if (np->use_dac) {
 		np->dmap_bah[0] = 0;	/* ??? */
-		OUTL (nc_scrx[0], np->dmap_bah[0]);
-		OUTL (nc_drs, np->dmap_bah[0]);
+		OUTL(np, nc_scrx[0], np->dmap_bah[0]);
+		OUTL(np, nc_drs, np->dmap_bah[0]);
 	}
 #endif
 
@@ -1921,8 +1878,8 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  set PM jump addresses.
 	 */
 	if (np->features & FE_NOPM) {
-		OUTL (nc_pmjad1, SCRIPTB_BA (np, pm_handle));
-		OUTL (nc_pmjad2, SCRIPTB_BA (np, pm_handle));
+		OUTL(np, nc_pmjad1, SCRIPTB_BA(np, pm_handle));
+		OUTL(np, nc_pmjad2, SCRIPTB_BA(np, pm_handle));
 	}
 
 	/*
@@ -1930,15 +1887,15 @@ void sym_start_up (struct sym_hcb *np, i
 	 *    Also set GPIO5 and clear GPIO6 if hardware LED control.
 	 */
 	if (np->features & FE_LED0)
-		OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01);
+		OUTB(np, nc_gpcntl, INB(np, nc_gpcntl) & ~0x01);
 	else if (np->features & FE_LEDC)
-		OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20);
+		OUTB(np, nc_gpcntl, (INB(np, nc_gpcntl) & ~0x41) | 0x20);
 
 	/*
 	 *      enable ints
 	 */
-	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
-	OUTB (nc_dien , MDPE|BF|SSI|SIR|IID);
+	OUTW(np, nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
+	OUTB(np, nc_dien , MDPE|BF|SSI|SIR|IID);
 
 	/*
 	 *  For 895/6 enable SBMC interrupt and save current SCSI bus mode.
@@ -1946,12 +1903,12 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  we reset the chip but not the SCSI BUS (at initialization).
 	 */
 	if (np->features & (FE_ULTRA2|FE_ULTRA3)) {
-		OUTONW (nc_sien, SBMC);
+		OUTONW(np, nc_sien, SBMC);
 		if (reason == 0) {
 			mdelay(100);
-			INW (nc_sist);
+			INW(np, nc_sist);
 		}
-		np->scsi_mode = INB (nc_stest4) & SMODE;
+		np->scsi_mode = INB(np, nc_stest4) & SMODE;
 	}
 
 	/*
@@ -1961,17 +1918,12 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  Prepare sync negotiation according to actual SCSI bus mode.
 	 */
 	for (i=0;i<SYM_CONF_MAX_TARGET;i++) {
-		tcb_p tp = &np->target[i];
+		struct sym_tcb *tp = &np->target[i];
 
 		tp->to_reset  = 0;
 		tp->head.sval = 0;
 		tp->head.wval = np->rv_scntl3;
 		tp->head.uval = 0;
-
-		tp->tinfo.curr.period = 0;
-		tp->tinfo.curr.offset = 0;
-		tp->tinfo.curr.width  = BUS_8_BIT;
-		tp->tinfo.curr.options = 0;
 	}
 
 	/*
@@ -1981,29 +1933,25 @@ void sym_start_up (struct sym_hcb *np, i
 	 *  For platforms that may not support PCI memory mapping,
 	 *  we use simple SCRIPTS that performs MEMORY MOVEs.
 	 */
+	phys = SCRIPTA_BA(np, init);
 	if (np->ram_ba) {
 		if (sym_verbose >= 2)
-			printf ("%s: Downloading SCSI SCRIPTS.\n",
-				sym_name(np));
+			printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np));
+		memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz);
 		if (np->ram_ws == 8192) {
-			OUTRAM_OFF(4096, np->scriptb0, np->scriptb_sz);
-			phys =  scr_to_cpu(np->scr_ram_seg);
-			OUTL (nc_mmws, phys);
-			OUTL (nc_mmrs, phys);
-			OUTL (nc_sfs,  phys);
-			phys = SCRIPTB_BA (np, start64);
+			memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz);
+			phys = scr_to_cpu(np->scr_ram_seg);
+			OUTL(np, nc_mmws, phys);
+			OUTL(np, nc_mmrs, phys);
+			OUTL(np, nc_sfs,  phys);
+			phys = SCRIPTB_BA(np, start64);
 		}
-		else
-			phys = SCRIPTA_BA (np, init);
-		OUTRAM_OFF(0, np->scripta0, np->scripta_sz);
 	}
-	else
-		phys = SCRIPTA_BA (np, init);
 
 	np->istat_sem = 0;
 
-	OUTL (nc_dsa, np->hcb_ba);
-	OUTL_DSP (phys);
+	OUTL(np, nc_dsa, np->hcb_ba);
+	OUTL_DSP(np, phys);
 
 	/*
 	 *  Notify the XPT about the RESET condition.
@@ -2013,16 +1961,16 @@ void sym_start_up (struct sym_hcb *np, i
 }
 
 /*
- *  Switch trans mode for current job and it's target.
+ *  Switch trans mode for current job and its target.
  */
 static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs,
 			 u_char per, u_char wide, u_char div, u_char fak)
 {
 	SYM_QUEHEAD *qp;
 	u_char sval, wval, uval;
-	tcb_p tp = &np->target[target];
+	struct sym_tcb *tp = &np->target[target];
 
-	assert(target == (INB (nc_sdid) & 0x0f));
+	assert(target == (INB(np, nc_sdid) & 0x0f));
 
 	sval = tp->head.sval;
 	wval = tp->head.wval;
@@ -2070,8 +2018,7 @@ static void sym_settrans(struct sym_hcb 
 			assert(np->features & FE_U3EN);
 			uval |= U3EN;
 		}
-	}
-	else {
+	} else {
 		wval = wval & ~ULTRA;
 		if (per <= 12)	wval |= ULTRA;
 	}
@@ -2092,23 +2039,23 @@ static void sym_settrans(struct sym_hcb 
 	 *  Not supported on the C1010.
 	 */
 	if (per < 50 && !(np->features & FE_C10))
-		OUTOFFB (nc_stest2, EXT);
+		OUTOFFB(np, nc_stest2, EXT);
 
 	/*
 	 *  set actual value and sync_status
 	 */
-	OUTB (nc_sxfer,  tp->head.sval);
-	OUTB (nc_scntl3, tp->head.wval);
+	OUTB(np, nc_sxfer,  tp->head.sval);
+	OUTB(np, nc_scntl3, tp->head.wval);
 
 	if (np->features & FE_C10) {
-		OUTB (nc_scntl4, tp->head.uval);
+		OUTB(np, nc_scntl4, tp->head.uval);
 	}
 
 	/*
 	 *  patch ALL busy ccbs of this target.
 	 */
 	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
-		ccb_p cp;
+		struct sym_ccb *cp;
 		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
 		if (cp->target != target)
 			continue;
@@ -2126,16 +2073,24 @@ static void sym_settrans(struct sym_hcb 
  */
 static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
 {
-	tcb_p tp = &np->target[target];
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+
+	if (spi_width(starget) == wide)
+		return;
 
 	sym_settrans(np, target, 0, 0, 0, wide, 0, 0);
 
-	tp->tinfo.goal.width = tp->tinfo.curr.width = wide;
-	tp->tinfo.curr.offset = 0;
-	tp->tinfo.curr.period = 0;
-	tp->tinfo.curr.options = 0;
+	tp->tgoal.width = wide;
+	spi_offset(starget) = 0;
+	spi_period(starget) = 0;
+	spi_width(starget) = wide;
+	spi_iu(starget) = 0;
+	spi_dt(starget) = 0;
+	spi_qas(starget) = 0;
 
-	sym_xpt_async_nego_wide(np, target);
+	if (sym_verbose >= 3)
+		spi_display_xfer_agreement(starget);
 }
 
 /*
@@ -2146,22 +2101,23 @@ static void
 sym_setsync(struct sym_hcb *np, int target,
             u_char ofs, u_char per, u_char div, u_char fak)
 {
-	tcb_p tp = &np->target[target];
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
 	u_char wide = (tp->head.wval & EWS) ? BUS_16_BIT : BUS_8_BIT;
 
 	sym_settrans(np, target, 0, ofs, per, wide, div, fak);
 
-	tp->tinfo.curr.period  = per;
-	tp->tinfo.curr.offset  = ofs;
-	tp->tinfo.curr.options = 0;
+	spi_period(starget) = per;
+	spi_offset(starget) = ofs;
+	spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;
 
-	if (!(tp->tinfo.goal.options & PPR_OPT_MASK)) {
-		tp->tinfo.goal.period	= per;
-		tp->tinfo.goal.offset	= ofs;
-		tp->tinfo.goal.options	= 0;
+	if (!tp->tgoal.dt && !tp->tgoal.iu && !tp->tgoal.qas) {
+		tp->tgoal.period = per;
+		tp->tgoal.offset = ofs;
+		tp->tgoal.check_nego = 0;
 	}
 
-	sym_xpt_async_nego_sync(np, target);
+	spi_display_xfer_agreement(starget);
 }
 
 /*
@@ -2172,16 +2128,20 @@ static void 
 sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
              u_char per, u_char wide, u_char div, u_char fak)
 {
-	tcb_p tp = &np->target[target];
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
 
 	sym_settrans(np, target, opts, ofs, per, wide, div, fak);
 
-	tp->tinfo.goal.width	= tp->tinfo.curr.width  = wide;
-	tp->tinfo.goal.period	= tp->tinfo.curr.period = per;
-	tp->tinfo.goal.offset	= tp->tinfo.curr.offset = ofs;
-	tp->tinfo.goal.options	= tp->tinfo.curr.options = opts;
+	spi_width(starget) = tp->tgoal.width = wide;
+	spi_period(starget) = tp->tgoal.period = per;
+	spi_offset(starget) = tp->tgoal.offset = ofs;
+	spi_iu(starget) = tp->tgoal.iu = !!(opts & PPR_OPT_IU);
+	spi_dt(starget) = tp->tgoal.dt = !!(opts & PPR_OPT_DT);
+	spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS);
+	tp->tgoal.check_nego = 0;
 
-	sym_xpt_async_nego_ppr(np, target);
+	spi_display_xfer_agreement(starget);
 }
 
 /*
@@ -2212,25 +2172,25 @@ sym_setpprot(struct sym_hcb *np, int tar
  */
 static void sym_recover_scsi_int (struct sym_hcb *np, u_char hsts)
 {
-	u32	dsp	= INL (nc_dsp);
-	u32	dsa	= INL (nc_dsa);
-	ccb_p cp	= sym_ccb_from_dsa(np, dsa);
+	u32	dsp	= INL(np, nc_dsp);
+	u32	dsa	= INL(np, nc_dsa);
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
 
 	/*
 	 *  If we haven't been interrupted inside the SCRIPTS 
 	 *  critical pathes, we can safely restart the SCRIPTS 
 	 *  and trust the DSA value if it matches a CCB.
 	 */
-	if ((!(dsp > SCRIPTA_BA (np, getjob_begin) &&
-	       dsp < SCRIPTA_BA (np, getjob_end) + 1)) &&
-	    (!(dsp > SCRIPTA_BA (np, ungetjob) &&
-	       dsp < SCRIPTA_BA (np, reselect) + 1)) &&
-	    (!(dsp > SCRIPTB_BA (np, sel_for_abort) &&
-	       dsp < SCRIPTB_BA (np, sel_for_abort_1) + 1)) &&
-	    (!(dsp > SCRIPTA_BA (np, done) &&
-	       dsp < SCRIPTA_BA (np, done_end) + 1))) {
-		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
-		OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
+	if ((!(dsp > SCRIPTA_BA(np, getjob_begin) &&
+	       dsp < SCRIPTA_BA(np, getjob_end) + 1)) &&
+	    (!(dsp > SCRIPTA_BA(np, ungetjob) &&
+	       dsp < SCRIPTA_BA(np, reselect) + 1)) &&
+	    (!(dsp > SCRIPTB_BA(np, sel_for_abort) &&
+	       dsp < SCRIPTB_BA(np, sel_for_abort_1) + 1)) &&
+	    (!(dsp > SCRIPTA_BA(np, done) &&
+	       dsp < SCRIPTA_BA(np, done_end) + 1))) {
+		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo  */
+		OUTB(np, nc_stest3, TE|CSF);		/* clear scsi fifo */
 		/*
 		 *  If we have a CCB, let the SCRIPTS call us back for 
 		 *  the handling of the error with SCRATCHA filled with 
@@ -2239,14 +2199,14 @@ static void sym_recover_scsi_int (struct
 		 */
 		if (cp) {
 			cp->host_status = hsts;
-			OUTL_DSP (SCRIPTA_BA (np, complete_error));
+			OUTL_DSP(np, SCRIPTA_BA(np, complete_error));
 		}
 		/*
 		 *  Otherwise just restart the SCRIPTS.
 		 */
 		else {
-			OUTL (nc_dsa, 0xffffff);
-			OUTL_DSP (SCRIPTA_BA (np, start));
+			OUTL(np, nc_dsa, 0xffffff);
+			OUTL_DSP(np, SCRIPTA_BA(np, start));
 		}
 	}
 	else
@@ -2263,11 +2223,11 @@ reset_all:
  */
 static void sym_int_sto (struct sym_hcb *np)
 {
-	u32 dsp	= INL (nc_dsp);
+	u32 dsp	= INL(np, nc_dsp);
 
 	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
 
-	if (dsp == SCRIPTA_BA (np, wf_sel_done) + 8)
+	if (dsp == SCRIPTA_BA(np, wf_sel_done) + 8)
 		sym_recover_scsi_int(np, HS_SEL_TIMEOUT);
 	else
 		sym_start_reset(np);
@@ -2294,7 +2254,7 @@ static void sym_int_udc (struct sym_hcb 
  */
 static void sym_int_sbmc (struct sym_hcb *np)
 {
-	u_char scsi_mode = INB (nc_stest4) & SMODE;
+	u_char scsi_mode = INB(np, nc_stest4) & SMODE;
 
 	/*
 	 *  Notify user.
@@ -2335,14 +2295,14 @@ static void sym_int_sbmc (struct sym_hcb
  */
 static void sym_int_par (struct sym_hcb *np, u_short sist)
 {
-	u_char	hsts	= INB (HS_PRT);
-	u32	dsp	= INL (nc_dsp);
-	u32	dbc	= INL (nc_dbc);
-	u32	dsa	= INL (nc_dsa);
-	u_char	sbcl	= INB (nc_sbcl);
+	u_char	hsts	= INB(np, HS_PRT);
+	u32	dsp	= INL(np, nc_dsp);
+	u32	dbc	= INL(np, nc_dbc);
+	u32	dsa	= INL(np, nc_dsa);
+	u_char	sbcl	= INB(np, nc_sbcl);
 	u_char	cmd	= dbc >> 24;
 	int phase	= cmd & 7;
-	ccb_p	cp	= sym_ccb_from_dsa(np, dsa);
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
 
 	printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
 		sym_name(np), hsts, dbc, sbcl);
@@ -2350,7 +2310,7 @@ static void sym_int_par (struct sym_hcb 
 	/*
 	 *  Check that the chip is connected to the SCSI BUS.
 	 */
-	if (!(INB (nc_scntl1) & ISCON)) {
+	if (!(INB(np, nc_scntl1) & ISCON)) {
 		sym_recover_scsi_int(np, HS_UNEXPECTED);
 		return;
 	}
@@ -2372,7 +2332,7 @@ static void sym_int_par (struct sym_hcb 
 	/*
 	 *  Keep track of the parity error.
 	 */
-	OUTONB (HF_PRT, HF_EXT_ERR);
+	OUTONB(np, HF_PRT, HF_EXT_ERR);
 	cp->xerr_status |= XE_PARITY_ERR;
 
 	/*
@@ -2389,25 +2349,25 @@ static void sym_int_par (struct sym_hcb 
 	 */
 	if (phase == 1 || phase == 5) {
 		/* Phase mismatch handled by SCRIPTS */
-		if (dsp == SCRIPTB_BA (np, pm_handle))
-			OUTL_DSP (dsp);
+		if (dsp == SCRIPTB_BA(np, pm_handle))
+			OUTL_DSP(np, dsp);
 		/* Phase mismatch handled by the C code */
 		else if (sist & MA)
 			sym_int_ma (np);
 		/* No phase mismatch occurred */
 		else {
 			sym_set_script_dp (np, cp, dsp);
-			OUTL_DSP (SCRIPTA_BA (np, dispatch));
+			OUTL_DSP(np, SCRIPTA_BA(np, dispatch));
 		}
 	}
 	else if (phase == 7)	/* We definitely cannot handle parity errors */
 #if 1				/* in message-in phase due to the relection  */
 		goto reset_all; /* path and various message anticipations.   */
 #else
-		OUTL_DSP (SCRIPTA_BA (np, clrack));
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 #endif
 	else
-		OUTL_DSP (SCRIPTA_BA (np, dispatch));
+		OUTL_DSP(np, SCRIPTA_BA(np, dispatch));
 	return;
 
 reset_all:
@@ -2436,11 +2396,11 @@ static void sym_int_ma (struct sym_hcb *
 	u_char	cmd;
 	u_char	hflags, hflags0;
 	struct	sym_pmc *pm;
-	ccb_p	cp;
+	struct sym_ccb *cp;
 
-	dsp	= INL (nc_dsp);
-	dbc	= INL (nc_dbc);
-	dsa	= INL (nc_dsa);
+	dsp	= INL(np, nc_dsp);
+	dbc	= INL(np, nc_dbc);
+	dsa	= INL(np, nc_dsa);
 
 	cmd	= dbc >> 24;
 	rest	= dbc & 0xffffff;
@@ -2461,14 +2421,14 @@ static void sym_int_ma (struct sym_hcb *
 		u_char ss0, ss2;
 
 		if (np->features & FE_DFBC)
-			delta = INW (nc_dfbc);
+			delta = INW(np, nc_dfbc);
 		else {
 			u32 dfifo;
 
 			/*
 			 * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
 			 */
-			dfifo = INL(nc_dfifo);
+			dfifo = INL(np, nc_dfifo);
 
 			/*
 			 *  Calculate remaining bytes in DMA fifo.
@@ -2488,29 +2448,29 @@ static void sym_int_ma (struct sym_hcb *
 		 *  Check the sstat2 register in case of wide transfer.
 		 */
 		rest += delta;
-		ss0  = INB (nc_sstat0);
+		ss0  = INB(np, nc_sstat0);
 		if (ss0 & OLF) rest++;
 		if (!(np->features & FE_C10))
 			if (ss0 & ORF) rest++;
 		if (cp && (cp->phys.select.sel_scntl3 & EWS)) {
-			ss2 = INB (nc_sstat2);
+			ss2 = INB(np, nc_sstat2);
 			if (ss2 & OLF1) rest++;
 			if (!(np->features & FE_C10))
 				if (ss2 & ORF1) rest++;
-		};
+		}
 
 		/*
 		 *  Clear fifos.
 		 */
-		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
-		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
+		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
+		OUTB(np, nc_stest3, TE|CSF);		/* scsi fifo */
 	}
 
 	/*
 	 *  log the information
 	 */
 	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
-		printf ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7,
+		printf ("P%x%x RL=%d D=%d ", cmd&7, INB(np, nc_sbcl)&7,
 			(unsigned) rest, (unsigned) delta);
 
 	/*
@@ -2536,7 +2496,7 @@ static void sym_int_ma (struct sym_hcb *
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
 			cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd);
-	};
+	}
 
 	if (!vdsp) {
 		printf ("%s: interrupted SCRIPT address not found.\n", 
@@ -2562,7 +2522,7 @@ static void sym_int_ma (struct sym_hcb *
 	} else {
 		tblp = (u32 *) 0;
 		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
-	};
+	}
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
@@ -2570,7 +2530,7 @@ static void sym_int_ma (struct sym_hcb *
 			tblp,
 			(unsigned) olen,
 			(unsigned) oadr);
-	};
+	}
 
 	/*
 	 *  check cmd against assumed interrupted script command.
@@ -2578,23 +2538,23 @@ static void sym_int_ma (struct sym_hcb *
 	 *  the phase.
 	 */
 	if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) {
-		PRINT_ADDR(cp);
-		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
-			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
+		sym_print_addr(cp->cmd,
+			"internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+			cmd, scr_to_cpu(vdsp[0]) >> 24);
 
 		goto reset_all;
-	};
+	}
 
 	/*
 	 *  if old phase not dataphase, leave here.
 	 */
 	if (cmd & 2) {
-		PRINT_ADDR(cp);
-		printf ("phase change %x-%x %d@%08x resid=%d.\n",
-			cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
+		sym_print_addr(cp->cmd,
+			"phase change %x-%x %d@%08x resid=%d.\n",
+			cmd&7, INB(np, nc_sbcl)&7, (unsigned)olen,
 			(unsigned)oadr, (unsigned)rest);
 		goto unexpected_phase;
-	};
+	}
 
 	/*
 	 *  Choose the correct PM save area.
@@ -2604,7 +2564,7 @@ static void sym_int_ma (struct sym_hcb *
 	 *  SCRIPTS for the 895A, 896 and 1010 that are able to 
 	 *  handle PM from the SCRIPTS processor.
 	 */
-	hflags0 = INB (HF_PRT);
+	hflags0 = INB(np, HF_PRT);
 	hflags = hflags0;
 
 	if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) {
@@ -2619,16 +2579,16 @@ static void sym_int_ma (struct sym_hcb *
 
 	if (!(hflags & HF_ACT_PM)) {
 		pm = &cp->phys.pm0;
-		newcmd = SCRIPTA_BA (np, pm0_data);
+		newcmd = SCRIPTA_BA(np, pm0_data);
 	}
 	else {
 		pm = &cp->phys.pm1;
-		newcmd = SCRIPTA_BA (np, pm1_data);
+		newcmd = SCRIPTA_BA(np, pm1_data);
 	}
 
 	hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED);
 	if (hflags != hflags0)
-		OUTB (HF_PRT, hflags);
+		OUTB(np, HF_PRT, hflags);
 
 	/*
 	 *  fillin the phase mismatch context
@@ -2643,9 +2603,9 @@ static void sym_int_ma (struct sym_hcb *
 	 *  - compute the SCRIPTS address to restart from,
 	 *  - move current data pointer context by one byte.
 	 */
-	nxtdsp = SCRIPTA_BA (np, dispatch);
+	nxtdsp = SCRIPTA_BA(np, dispatch);
 	if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
-	    (INB (nc_scntl2) & WSR)) {
+	    (INB(np, nc_scntl2) & WSR)) {
 		u32 tmp;
 
 		/*
@@ -2671,12 +2631,11 @@ static void sym_int_ma (struct sym_hcb *
 		 *  Prepare the address of SCRIPTS that will 
 		 *  move the residual byte to memory.
 		 */
-		nxtdsp = SCRIPTB_BA (np, wsr_ma_helper);
+		nxtdsp = SCRIPTB_BA(np, wsr_ma_helper);
 	}
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
-		PRINT_ADDR(cp);
-		printf ("PM %x %x %x / %x %x %x.\n",
+		sym_print_addr(cp->cmd, "PM %x %x %x / %x %x %x.\n",
 			hflags0, hflags, newcmd,
 			(unsigned)scr_to_cpu(pm->sg.addr),
 			(unsigned)scr_to_cpu(pm->sg.size),
@@ -2687,7 +2646,7 @@ static void sym_int_ma (struct sym_hcb *
 	 *  Restart the SCRIPTS processor.
 	 */
 	sym_set_script_dp (np, cp, newcmd);
-	OUTL_DSP (nxtdsp);
+	OUTL_DSP(np, nxtdsp);
 	return;
 
 	/*
@@ -2723,11 +2682,11 @@ unexpected_phase:
 
 	switch (cmd & 7) {
 	case 2:	/* COMMAND phase */
-		nxtdsp = SCRIPTA_BA (np, dispatch);
+		nxtdsp = SCRIPTA_BA(np, dispatch);
 		break;
 #if 0
 	case 3:	/* STATUS  phase */
-		nxtdsp = SCRIPTA_BA (np, dispatch);
+		nxtdsp = SCRIPTA_BA(np, dispatch);
 		break;
 #endif
 	case 6:	/* MSG OUT phase */
@@ -2737,30 +2696,34 @@ unexpected_phase:
 		 *  since we will not be able to handle reselect.
 		 *  Otherwise, we just don't care.
 		 */
-		if	(dsp == SCRIPTA_BA (np, send_ident)) {
+		if	(dsp == SCRIPTA_BA(np, send_ident)) {
 			if (cp->tag != NO_TAG && olen - rest <= 3) {
 				cp->host_status = HS_BUSY;
 				np->msgout[0] = IDENTIFY(0, cp->lun);
-				nxtdsp = SCRIPTB_BA (np, ident_break_atn);
+				nxtdsp = SCRIPTB_BA(np, ident_break_atn);
 			}
 			else
-				nxtdsp = SCRIPTB_BA (np, ident_break);
+				nxtdsp = SCRIPTB_BA(np, ident_break);
 		}
-		else if	(dsp == SCRIPTB_BA (np, send_wdtr) ||
-			 dsp == SCRIPTB_BA (np, send_sdtr) ||
-			 dsp == SCRIPTB_BA (np, send_ppr)) {
-			nxtdsp = SCRIPTB_BA (np, nego_bad_phase);
+		else if	(dsp == SCRIPTB_BA(np, send_wdtr) ||
+			 dsp == SCRIPTB_BA(np, send_sdtr) ||
+			 dsp == SCRIPTB_BA(np, send_ppr)) {
+			nxtdsp = SCRIPTB_BA(np, nego_bad_phase);
+			if (dsp == SCRIPTB_BA(np, send_ppr)) {
+				struct scsi_device *dev = cp->cmd->device;
+				dev->ppr = 0;
+			}
 		}
 		break;
 #if 0
 	case 7:	/* MSG IN  phase */
-		nxtdsp = SCRIPTA_BA (np, clrack);
+		nxtdsp = SCRIPTA_BA(np, clrack);
 		break;
 #endif
 	}
 
 	if (nxtdsp) {
-		OUTL_DSP (nxtdsp);
+		OUTL_DSP(np, nxtdsp);
 		return;
 	}
 
@@ -2848,20 +2811,20 @@ void sym_interrupt (struct sym_hcb *np)
 	 *  Note that SCRIPTS also (dummy) read to memory 
 	 *  prior to deliver the INTF interrupt condition.
 	 */
-	istat = INB (nc_istat);
+	istat = INB(np, nc_istat);
 	if (istat & INTF) {
-		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
-		istat = INB (nc_istat);		/* DUMMY READ */
+		OUTB(np, nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+		istat = INB(np, nc_istat);		/* DUMMY READ */
 		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
-		(void)sym_wakeup_done (np);
-	};
+		sym_wakeup_done(np);
+	}
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
 #if 0	/* We should never get this one */
 	if (istat & CABRT)
-		OUTB (nc_istat, CABRT);
+		OUTB(np, nc_istat, CABRT);
 #endif
 
 	/*
@@ -2879,19 +2842,19 @@ void sym_interrupt (struct sym_hcb *np)
 	istatc	= istat;
 	do {
 		if (istatc & SIP)
-			sist  |= INW (nc_sist);
+			sist  |= INW(np, nc_sist);
 		if (istatc & DIP)
-			dstat |= INB (nc_dstat);
-		istatc = INB (nc_istat);
+			dstat |= INB(np, nc_dstat);
+		istatc = INB(np, nc_istat);
 		istat |= istatc;
 	} while (istatc & (SIP|DIP));
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printf ("<%d|%x:%x|%x:%x>",
-			(int)INB(nc_scr0),
+			(int)INB(np, nc_scr0),
 			dstat,sist,
-			(unsigned)INL(nc_dsp),
-			(unsigned)INL(nc_dbc));
+			(unsigned)INL(np, nc_dsp),
+			(unsigned)INL(np, nc_dbc));
 	/*
 	 *  On paper, a memory read barrier may be needed here to 
 	 *  prevent out of order LOADs by the CPU from having 
@@ -2918,10 +2881,10 @@ void sym_interrupt (struct sym_hcb *np)
 		if	(sist & PAR)	sym_int_par (np, sist);
 		else if (sist & MA)	sym_int_ma (np);
 		else if (dstat & SIR)	sym_int_sir (np);
-		else if (dstat & SSI)	OUTONB_STD ();
+		else if (dstat & SSI)	OUTONB_STD();
 		else			goto unknown_int;
 		return;
-	};
+	}
 
 	/*
 	 *  Now, interrupts that donnot happen in normal 
@@ -2938,10 +2901,10 @@ void sym_interrupt (struct sym_hcb *np)
 		printf("%s: SCSI BUS reset detected.\n", sym_name(np));
 		sym_start_up (np, 1);
 		return;
-	};
+	}
 
-	OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
-	OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
+	OUTB(np, nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
+	OUTB(np, nc_stest3, TE|CSF);		/* clear scsi fifo */
 
 	if (!(sist  & (GEN|HTH|SGE)) &&
 	    !(dstat & (MDPE|BF|ABRT|IID))) {
@@ -2950,7 +2913,7 @@ void sym_interrupt (struct sym_hcb *np)
 		else if (sist & UDC)	sym_int_udc (np);
 		else			goto unknown_int;
 		return;
-	};
+	}
 
 	/*
 	 *  Now, interrupts we are not able to recover cleanly.
@@ -2965,7 +2928,7 @@ void sym_interrupt (struct sym_hcb *np)
 		(dstat & (MDPE|BF|ABRT|IID))) {
 		sym_start_reset(np);
 		return;
-	};
+	}
 
 unknown_int:
 	/*
@@ -2989,7 +2952,7 @@ static int 
 sym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task)
 {
 	int j;
-	ccb_p cp;
+	struct sym_ccb *cp;
 
 	/*
 	 *  Make sure the starting index is within range.
@@ -3011,7 +2974,7 @@ sym_dequeue_from_squeue(struct sym_hcb *
 		if ((target == -1 || cp->target == target) &&
 		    (lun    == -1 || cp->lun    == lun)    &&
 		    (task   == -1 || cp->tag    == task)) {
-			sym_set_cam_status(cp->cam_ccb, CAM_REQUEUE_REQ);
+			sym_set_cam_status(cp->cmd, CAM_REQUEUE_REQ);
 			sym_remque(&cp->link_ccbq);
 			sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
 		}
@@ -3047,9 +3010,8 @@ sym_dequeue_from_squeue(struct sym_hcb *
  *  SCRATCHA is assumed to have been loaded with STARTPOS 
  *  before the SCRIPTS called the C code.
  */
-static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, ccb_p cp)
+static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb *cp)
 {
-	tcb_p tp	= &np->target[cp->target];
 	u32		startp;
 	u_char		s_status = cp->ssss_status;
 	u_char		h_flags  = cp->host_flags;
@@ -3059,7 +3021,7 @@ static void sym_sir_bad_scsi_status(stru
 	/*
 	 *  Compute the index of the next job to start from SCRIPTS.
 	 */
-	i = (INL (nc_scratcha) - np->squeue_ba) / 4;
+	i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
 
 	/*
 	 *  The last CCB queued used for IARB hint may be 
@@ -3077,8 +3039,7 @@ static void sym_sir_bad_scsi_status(stru
 	case S_BUSY:
 	case S_QUEUE_FULL:
 		if (sym_verbose >= 2) {
-			PRINT_ADDR(cp);
-			printf ("%s\n",
+			sym_print_addr(cp->cmd, "%s\n",
 			        s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n");
 		}
 	default:	/* S_INT, S_INT_COND_MET, S_CONFLICT */
@@ -3098,8 +3059,8 @@ static void sym_sir_bad_scsi_status(stru
 		 *  Dequeue all queued CCBs for that device not yet started,
 		 *  and restart the SCRIPTS processor immediately.
 		 */
-		(void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
-		OUTL_DSP (SCRIPTA_BA (np, start));
+		sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
+		OUTL_DSP(np, SCRIPTA_BA(np, start));
 
  		/*
 		 *  Save some info of the actual IO.
@@ -3132,13 +3093,13 @@ static void sym_sir_bad_scsi_status(stru
 		/*
 		 *  Message table indirect structure.
 		 */
-		cp->phys.smsg.addr	= cpu_to_scr(CCB_BA (cp, scsi_smsg2));
+		cp->phys.smsg.addr	= cpu_to_scr(CCB_BA(cp, scsi_smsg2));
 		cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 		/*
 		 *  sense command
 		 */
-		cp->phys.cmd.addr	= cpu_to_scr(CCB_BA (cp, sensecmd));
+		cp->phys.cmd.addr	= cpu_to_scr(CCB_BA(cp, sensecmd));
 		cp->phys.cmd.size	= cpu_to_scr(6);
 
 		/*
@@ -3146,7 +3107,7 @@ static void sym_sir_bad_scsi_status(stru
 		 */
 		cp->sensecmd[0]		= REQUEST_SENSE;
 		cp->sensecmd[1]		= 0;
-		if (tp->tinfo.curr.scsi_version <= 2 && cp->lun <= 7)
+		if (cp->cmd->device->scsi_level <= SCSI_2 && cp->lun <= 7)
 			cp->sensecmd[1]	= cp->lun << 5;
 		cp->sensecmd[4]		= SYM_SNS_BBUF_LEN;
 		cp->data_len		= SYM_SNS_BBUF_LEN;
@@ -3155,13 +3116,13 @@ static void sym_sir_bad_scsi_status(stru
 		 *  sense data
 		 */
 		memset(cp->sns_bbuf, 0, SYM_SNS_BBUF_LEN);
-		cp->phys.sense.addr	= cpu_to_scr(vtobus(cp->sns_bbuf));
+		cp->phys.sense.addr	= cpu_to_scr(CCB_BA(cp, sns_bbuf));
 		cp->phys.sense.size	= cpu_to_scr(SYM_SNS_BBUF_LEN);
 
 		/*
 		 *  requeue the command.
 		 */
-		startp = SCRIPTB_BA (np, sdata_in);
+		startp = SCRIPTB_BA(np, sdata_in);
 
 		cp->phys.head.savep	= cpu_to_scr(startp);
 		cp->phys.head.lastp	= cpu_to_scr(startp);
@@ -3175,7 +3136,7 @@ static void sym_sir_bad_scsi_status(stru
 		cp->xerr_status = 0;
 		cp->extra_bytes = 0;
 
-		cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select));
+		cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select));
 
 		/*
 		 *  Requeue the command.
@@ -3208,7 +3169,7 @@ int sym_clear_tasks(struct sym_hcb *np, 
 {
 	SYM_QUEHEAD qtmp, *qp;
 	int i = 0;
-	ccb_p cp;
+	struct sym_ccb *cp;
 
 	/*
 	 *  Move the entire BUSY queue to our temporary queue.
@@ -3223,9 +3184,9 @@ int sym_clear_tasks(struct sym_hcb *np, 
 	 *  the BUSY queue.
 	 */
 	while ((qp = sym_remque_head(&qtmp)) != 0) {
-		struct scsi_cmnd *ccb;
+		struct scsi_cmnd *cmd;
 		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
-		ccb = cp->cam_ccb;
+		cmd = cp->cmd;
 		if (cp->host_status != HS_DISCONNECT ||
 		    cp->target != target	     ||
 		    (lun  != -1 && cp->lun != lun)   ||
@@ -3237,8 +3198,8 @@ int sym_clear_tasks(struct sym_hcb *np, 
 		sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
 
 		/* Preserve the software timeout condition */
-		if (sym_get_cam_status(ccb) != CAM_CMD_TIMEOUT)
-			sym_set_cam_status(ccb, cam_status);
+		if (sym_get_cam_status(cmd) != CAM_CMD_TIMEOUT)
+			sym_set_cam_status(cmd, cam_status);
 		++i;
 #if 0
 printf("XXXX TASK @%p CLEARED\n", cp);
@@ -3290,8 +3251,9 @@ printf("XXXX TASK @%p CLEARED\n", cp);
 static void sym_sir_task_recovery(struct sym_hcb *np, int num)
 {
 	SYM_QUEHEAD *qp;
-	ccb_p cp;
-	tcb_p tp;
+	struct sym_ccb *cp;
+	struct sym_tcb *tp = NULL; /* gcc isn't quite smart enough yet */
+	struct scsi_target *starget;
 	int target=-1, lun=-1, task;
 	int i, k;
 
@@ -3349,8 +3311,8 @@ static void sym_sir_task_recovery(struct
 			np->abrt_sel.sel_id	= target;
 			np->abrt_sel.sel_scntl3 = tp->head.wval;
 			np->abrt_sel.sel_sxfer  = tp->head.sval;
-			OUTL(nc_dsa, np->hcb_ba);
-			OUTL_DSP (SCRIPTB_BA (np, sel_for_abort));
+			OUTL(np, nc_dsa, np->hcb_ba);
+			OUTL_DSP(np, SCRIPTB_BA(np, sel_for_abort));
 			return;
 		}
 
@@ -3389,7 +3351,7 @@ static void sym_sir_task_recovery(struct
 			 *  Remove the SEM flag from the ISTAT.
 			 */
 			np->istat_sem = 0;
-			OUTB (nc_istat, SIGP);
+			OUTB(np, nc_istat, SIGP);
 			break;
 		}
 		/*
@@ -3397,14 +3359,14 @@ static void sym_sir_task_recovery(struct
 		 *  queue the SCRIPTS intends to start and dequeue 
 		 *  all CCBs for that device that haven't been started.
 		 */
-		i = (INL (nc_scratcha) - np->squeue_ba) / 4;
+		i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
 		i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
 
 		/*
 		 *  Make sure at least our IO to abort has been dequeued.
 		 */
 #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
-		assert(i && sym_get_cam_status(cp->cam_ccb) == CAM_REQUEUE_REQ);
+		assert(i && sym_get_cam_status(cp->cmd) == CAM_REQUEUE_REQ);
 #else
 		sym_remque(&cp->link_ccbq);
 		sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
@@ -3413,9 +3375,9 @@ static void sym_sir_task_recovery(struct
 		 *  Keep track in cam status of the reason of the abort.
 		 */
 		if (cp->to_abort == 2)
-			sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT);
+			sym_set_cam_status(cp->cmd, CAM_CMD_TIMEOUT);
 		else
-			sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED);
+			sym_set_cam_status(cp->cmd, CAM_REQ_ABORTED);
 
 		/*
 		 *  Complete with error everything that we have dequeued.
@@ -3427,7 +3389,7 @@ static void sym_sir_task_recovery(struct
 	 *  we may have some manual recovery to perform for.
 	 */
 	case SIR_TARGET_SELECTED:
-		target = (INB (nc_sdid) & 0xf);
+		target = INB(np, nc_sdid) & 0xf;
 		tp = &np->target[target];
 
 		np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg));
@@ -3463,7 +3425,7 @@ static void sym_sir_task_recovery(struct
 		 *  an IDENTIFY(lun) + ABORT MESSAGE.
 		 */
 		if (lun != -1) {
-			lcb_p lp = sym_lp(np, tp, lun);
+			struct sym_lcb *lp = sym_lp(tp, lun);
 			lp->to_clear = 0; /* We don't expect to fail here */
 			np->abrt_msg[0] = IDENTIFY(0, lun);
 			np->abrt_msg[1] = M_ABORT;
@@ -3529,7 +3491,7 @@ static void sym_sir_task_recovery(struct
 		 *  conditions not due to timeout.
 		 */
 		if (cp->to_abort == 2)
-			sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT);
+			sym_set_cam_status(cp->cmd, CAM_CMD_TIMEOUT);
 		cp->to_abort = 0; /* We donnot expect to fail here */
 		break;
 
@@ -3538,8 +3500,9 @@ static void sym_sir_task_recovery(struct
 	 *  to BUS FREE phase as we expected.
 	 */
 	case SIR_ABORT_SENT:
-		target = (INB (nc_sdid) & 0xf);
+		target = INB(np, nc_sdid) & 0xf;
 		tp = &np->target[target];
+		starget = tp->sdev->sdev_target;
 		
 		/*
 		**  If we didn't abort anything, leave here.
@@ -3561,10 +3524,13 @@ static void sym_sir_task_recovery(struct
 			tp->head.sval = 0;
 			tp->head.wval = np->rv_scntl3;
 			tp->head.uval = 0;
-			tp->tinfo.curr.period = 0;
-			tp->tinfo.curr.offset = 0;
-			tp->tinfo.curr.width  = BUS_8_BIT;
-			tp->tinfo.curr.options = 0;
+			spi_period(starget) = 0;
+			spi_offset(starget) = 0;
+			spi_width(starget) = 0;
+			spi_iu(starget) = 0;
+			spi_dt(starget) = 0;
+			spi_qas(starget) = 0;
+			tp->tgoal.check_nego = 1;
 		}
 
 		/*
@@ -3583,9 +3549,9 @@ static void sym_sir_task_recovery(struct
 		 *  Complete all the CCBs the device should have 
 		 *  aborted due to our 'kiss of death' message.
 		 */
-		i = (INL (nc_scratcha) - np->squeue_ba) / 4;
-		(void) sym_dequeue_from_squeue(np, i, target, lun, -1);
-		(void) sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task);
+		i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+		sym_dequeue_from_squeue(np, i, target, lun, -1);
+		sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task);
 		sym_flush_comp_queue(np, 0);
 
  		/*
@@ -3600,16 +3566,15 @@ static void sym_sir_task_recovery(struct
 	 *  Print to the log the message we intend to send.
 	 */
 	if (num == SIR_TARGET_SELECTED) {
-		PRINT_TARGET(np, target);
-		sym_printl_hex("control msgout:", np->abrt_msg,
-			      np->abrt_tbl.size);
+		dev_info(&tp->sdev->sdev_target->dev, "control msgout:");
+		sym_printl_hex(np->abrt_msg, np->abrt_tbl.size);
 		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
 	}
 
 	/*
 	 *  Let the SCRIPTS processor continue.
 	 */
-	OUTONB_STD ();
+	OUTONB_STD();
 }
 
 /*
@@ -3617,7 +3582,7 @@ static void sym_sir_task_recovery(struct
  *  pointer for both MDP and the residual calculation.
  *
  *  I didn't want to bloat the code by more than 200 
- *  lignes for the handling of both MDP and the residual.
+ *  lines for the handling of both MDP and the residual.
  *  This has been achieved by using a data pointer 
  *  representation consisting in an index in the data 
  *  array (dp_sg) and a negative offset (dp_ofs) that 
@@ -3639,7 +3604,7 @@ static void sym_sir_task_recovery(struct
  *  the corresponding values of dp_sg and dp_ofs.
  */
 
-static int sym_evaluate_dp(struct sym_hcb *np, ccb_p cp, u32 scr, int *ofs)
+static int sym_evaluate_dp(struct sym_hcb *np, struct sym_ccb *cp, u32 scr, int *ofs)
 {
 	u32	dp_scr;
 	int	dp_ofs, dp_sg, dp_sgmin;
@@ -3652,9 +3617,9 @@ static int sym_evaluate_dp(struct sym_hc
 	 */
 	dp_scr = scr;
 	dp_ofs = *ofs;
-	if	(dp_scr == SCRIPTA_BA (np, pm0_data))
+	if	(dp_scr == SCRIPTA_BA(np, pm0_data))
 		pm = &cp->phys.pm0;
-	else if (dp_scr == SCRIPTA_BA (np, pm1_data))
+	else if (dp_scr == SCRIPTA_BA(np, pm1_data))
 		pm = &cp->phys.pm1;
 	else
 		pm = NULL;
@@ -3757,7 +3722,7 @@ out_err:
  *  is equivalent to a MODIFY DATA POINTER (offset=-1).
  */
 
-static void sym_modify_dp(struct sym_hcb *np, tcb_p tp, ccb_p cp, int ofs)
+static void sym_modify_dp(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp, int ofs)
 {
 	int dp_ofs	= ofs;
 	u32	dp_scr	= sym_get_script_dp (np, cp);
@@ -3800,23 +3765,23 @@ static void sym_modify_dp(struct sym_hcb
 	/*
 	 *  Get a context for the new current data pointer.
 	 */
-	hflags = INB (HF_PRT);
+	hflags = INB(np, HF_PRT);
 
 	if (hflags & HF_DP_SAVED)
 		hflags ^= HF_ACT_PM;
 
 	if (!(hflags & HF_ACT_PM)) {
 		pm  = &cp->phys.pm0;
-		dp_scr = SCRIPTA_BA (np, pm0_data);
+		dp_scr = SCRIPTA_BA(np, pm0_data);
 	}
 	else {
 		pm = &cp->phys.pm1;
-		dp_scr = SCRIPTA_BA (np, pm1_data);
+		dp_scr = SCRIPTA_BA(np, pm1_data);
 	}
 
 	hflags &= ~(HF_DP_SAVED);
 
-	OUTB (HF_PRT, hflags);
+	OUTB(np, HF_PRT, hflags);
 
 	/*
 	 *  Set up the new current data pointer.
@@ -3833,11 +3798,11 @@ static void sym_modify_dp(struct sym_hcb
 
 out_ok:
 	sym_set_script_dp (np, cp, dp_scr);
-	OUTL_DSP (SCRIPTA_BA (np, clrack));
+	OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 	return;
 
 out_reject:
-	OUTL_DSP (SCRIPTB_BA (np, msg_bad));
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
 }
 
 
@@ -3856,7 +3821,7 @@ out_reject:
  *  a relevant information. :)
  */
 
-int sym_compute_residual(struct sym_hcb *np, ccb_p cp)
+int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp)
 {
 	int dp_sg, dp_sgmin, resid = 0;
 	int dp_ofs = 0;
@@ -3956,13 +3921,14 @@ int sym_compute_residual(struct sym_hcb 
  *  chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message.
  */
 static int  
-sym_sync_nego_check(struct sym_hcb *np, int req, int target)
+sym_sync_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp)
 {
+	int target = cp->target;
 	u_char	chg, ofs, per, fak, div;
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
 		sym_print_nego_msg(np, target, "sync msgin", np->msgin);
-	};
+	}
 
 	/*
 	 *  Get requested values.
@@ -3992,9 +3958,9 @@ sym_sync_nego_check(struct sym_hcb *np, 
 		goto reject_it;
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
-		PRINT_TARGET(np, target);
-		printf ("sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n",
-			ofs, per, div, fak, chg);
+		sym_print_addr(cp->cmd,
+				"sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n",
+				ofs, per, div, fak, chg);
 	}
 
 	/*
@@ -4037,7 +4003,7 @@ reject_it:
 	return -1;
 }
 
-static void sym_sync_nego(struct sym_hcb *np, tcb_p tp, ccb_p cp)
+static void sym_sync_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
 {
 	int req = 1;
 	int result;
@@ -4045,8 +4011,8 @@ static void sym_sync_nego(struct sym_hcb
 	/*
 	 *  Request or answer ?
 	 */
-	if (INB (HS_PRT) == HS_NEGOTIATE) {
-		OUTB (HS_PRT, HS_BUSY);
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
 		if (cp->nego_status && cp->nego_status != NS_SYNC)
 			goto reject_it;
 		req = 0;
@@ -4055,19 +4021,19 @@ static void sym_sync_nego(struct sym_hcb
 	/*
 	 *  Check and apply new values.
 	 */
-	result = sym_sync_nego_check(np, req, cp->target);
+	result = sym_sync_nego_check(np, req, cp);
 	if (result)	/* Not acceptable, reject it */
 		goto reject_it;
 	if (req) {	/* Was a request, send response. */
 		cp->nego_status = NS_SYNC;
-		OUTL_DSP (SCRIPTB_BA (np, sdtr_resp));
+		OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp));
 	}
 	else		/* Was a response, we are done. */
-		OUTL_DSP (SCRIPTA_BA (np, clrack));
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 	return;
 
 reject_it:
-	OUTL_DSP (SCRIPTB_BA (np, msg_bad));
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
 }
 
 /*
@@ -4076,7 +4042,7 @@ reject_it:
 static int 
 sym_ppr_nego_check(struct sym_hcb *np, int req, int target)
 {
-	tcb_p tp = &np->target[target];
+	struct sym_tcb *tp = &np->target[target];
 	unsigned char fak, div;
 	int dt, chg = 0;
 
@@ -4096,10 +4062,7 @@ sym_ppr_nego_check(struct sym_hcb *np, i
 		chg = 1;
 		wide = np->maxwide;
 	}
-	if (!wide || !(np->features & FE_ULTRA3))
-		opts = 0;
-
-	if (!(np->features & FE_U3EN))	/* Broken U3EN bit not supported */
+	if (!wide || !(np->features & FE_U3EN))
 		opts = 0;
 
 	if (opts != (np->msgin[7] & PPR_OPT_MASK))
@@ -4175,15 +4138,16 @@ reject_it:
 	 *  ST, we may want to try a legacy negotiation later.
 	 */
 	if (!req && !opts) {
-		tp->tinfo.goal.options = 0;
-		tp->tinfo.goal.width   = wide;
-		tp->tinfo.goal.period  = per;
-		tp->tinfo.goal.offset  = ofs;
+		tp->tgoal.period = per;
+		tp->tgoal.offset = ofs;
+		tp->tgoal.width = wide;
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+		tp->tgoal.check_nego = 1;
 	}
 	return -1;
 }
 
-static void sym_ppr_nego(struct sym_hcb *np, tcb_p tp, ccb_p cp)
+static void sym_ppr_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
 {
 	int req = 1;
 	int result;
@@ -4191,8 +4155,8 @@ static void sym_ppr_nego(struct sym_hcb 
 	/*
 	 *  Request or answer ?
 	 */
-	if (INB (HS_PRT) == HS_NEGOTIATE) {
-		OUTB (HS_PRT, HS_BUSY);
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
 		if (cp->nego_status && cp->nego_status != NS_PPR)
 			goto reject_it;
 		req = 0;
@@ -4206,27 +4170,28 @@ static void sym_ppr_nego(struct sym_hcb 
 		goto reject_it;
 	if (req) {	/* Was a request, send response. */
 		cp->nego_status = NS_PPR;
-		OUTL_DSP (SCRIPTB_BA (np, ppr_resp));
+		OUTL_DSP(np, SCRIPTB_BA(np, ppr_resp));
 	}
 	else		/* Was a response, we are done. */
-		OUTL_DSP (SCRIPTA_BA (np, clrack));
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 	return;
 
 reject_it:
-	OUTL_DSP (SCRIPTB_BA (np, msg_bad));
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
 }
 
 /*
  *  chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message.
  */
 static int  
-sym_wide_nego_check(struct sym_hcb *np, int req, int target)
+sym_wide_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp)
 {
+	int target = cp->target;
 	u_char	chg, wide;
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
 		sym_print_nego_msg(np, target, "wide msgin", np->msgin);
-	};
+	}
 
 	/*
 	 *  Get requested values.
@@ -4243,8 +4208,8 @@ sym_wide_nego_check(struct sym_hcb *np, 
 	}
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
-		PRINT_TARGET(np, target);
-		printf ("wdtr: wide=%d chg=%d.\n", wide, chg);
+		sym_print_addr(cp->cmd, "wdtr: wide=%d chg=%d.\n",
+				wide, chg);
 	}
 
 	/*
@@ -4285,7 +4250,7 @@ reject_it:
 	return -1;
 }
 
-static void sym_wide_nego(struct sym_hcb *np, tcb_p tp, ccb_p cp)
+static void sym_wide_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
 {
 	int req = 1;
 	int result;
@@ -4293,8 +4258,8 @@ static void sym_wide_nego(struct sym_hcb
 	/*
 	 *  Request or answer ?
 	 */
-	if (INB (HS_PRT) == HS_NEGOTIATE) {
-		OUTB (HS_PRT, HS_BUSY);
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
 		if (cp->nego_status && cp->nego_status != NS_WIDE)
 			goto reject_it;
 		req = 0;
@@ -4303,25 +4268,24 @@ static void sym_wide_nego(struct sym_hcb
 	/*
 	 *  Check and apply new values.
 	 */
-	result = sym_wide_nego_check(np, req, cp->target);
+	result = sym_wide_nego_check(np, req, cp);
 	if (result)	/* Not acceptable, reject it */
 		goto reject_it;
 	if (req) {	/* Was a request, send response. */
 		cp->nego_status = NS_WIDE;
-		OUTL_DSP (SCRIPTB_BA (np, wdtr_resp));
-	}
-	else {		/* Was a response. */
+		OUTL_DSP(np, SCRIPTB_BA(np, wdtr_resp));
+	} else {		/* Was a response. */
 		/*
 		 * Negotiate for SYNC immediately after WIDE response.
 		 * This allows to negotiate for both WIDE and SYNC on 
 		 * a single SCSI command (Suggested by Justin Gibbs).
 		 */
-		if (tp->tinfo.goal.offset) {
+		if (tp->tgoal.offset) {
 			np->msgout[0] = M_EXTENDED;
 			np->msgout[1] = 3;
 			np->msgout[2] = M_X_SYNC_REQ;
-			np->msgout[3] = tp->tinfo.goal.period;
-			np->msgout[4] = tp->tinfo.goal.offset;
+			np->msgout[3] = tp->tgoal.period;
+			np->msgout[4] = tp->tgoal.offset;
 
 			if (DEBUG_FLAGS & DEBUG_NEGO) {
 				sym_print_nego_msg(np, cp->target,
@@ -4329,18 +4293,17 @@ static void sym_wide_nego(struct sym_hcb
 			}
 
 			cp->nego_status = NS_SYNC;
-			OUTB (HS_PRT, HS_NEGOTIATE);
-			OUTL_DSP (SCRIPTB_BA (np, sdtr_resp));
+			OUTB(np, HS_PRT, HS_NEGOTIATE);
+			OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp));
 			return;
-		}
-		else
-			OUTL_DSP (SCRIPTA_BA (np, clrack));
-	};
+		} else
+			OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	}
 
 	return;
 
 reject_it:
-	OUTL_DSP (SCRIPTB_BA (np, msg_bad));
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
 }
 
 /*
@@ -4354,18 +4317,19 @@ reject_it:
  *  So, if a PPR makes problems, we may just want to 
  *  try a legacy negotiation later.
  */
-static void sym_nego_default(struct sym_hcb *np, tcb_p tp, ccb_p cp)
+static void sym_nego_default(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
 {
 	switch (cp->nego_status) {
 	case NS_PPR:
 #if 0
 		sym_setpprot (np, cp->target, 0, 0, 0, 0, 0, 0);
 #else
-		tp->tinfo.goal.options = 0;
-		if (tp->tinfo.goal.period < np->minsync)
-			tp->tinfo.goal.period = np->minsync;
-		if (tp->tinfo.goal.offset > np->maxoffs)
-			tp->tinfo.goal.offset = np->maxoffs;
+		if (tp->tgoal.period < np->minsync)
+			tp->tgoal.period = np->minsync;
+		if (tp->tgoal.offset > np->maxoffs)
+			tp->tgoal.offset = np->maxoffs;
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+		tp->tgoal.check_nego = 1;
 #endif
 		break;
 	case NS_SYNC:
@@ -4374,7 +4338,7 @@ static void sym_nego_default(struct sym_
 	case NS_WIDE:
 		sym_setwide (np, cp->target, 0);
 		break;
-	};
+	}
 	np->msgin [0] = M_NOOP;
 	np->msgout[0] = M_NOOP;
 	cp->nego_status = 0;
@@ -4384,10 +4348,10 @@ static void sym_nego_default(struct sym_
  *  chip handler for MESSAGE REJECT received in response to 
  *  PPR, WIDE or SYNCHRONOUS negotiation.
  */
-static void sym_nego_rejected(struct sym_hcb *np, tcb_p tp, ccb_p cp)
+static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
 {
 	sym_nego_default(np, tp, cp);
-	OUTB (HS_PRT, HS_BUSY);
+	OUTB(np, HS_PRT, HS_BUSY);
 }
 
 /*
@@ -4395,11 +4359,11 @@ static void sym_nego_rejected(struct sym
  */
 static void sym_int_sir (struct sym_hcb *np)
 {
-	u_char	num	= INB (nc_dsps);
-	u32	dsa	= INL (nc_dsa);
-	ccb_p	cp	= sym_ccb_from_dsa(np, dsa);
-	u_char	target	= INB (nc_sdid) & 0x0f;
-	tcb_p	tp	= &np->target[target];
+	u_char	num	= INB(np, nc_dsps);
+	u32	dsa	= INL(np, nc_dsa);
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
+	u_char	target	= INB(np, nc_sdid) & 0x0f;
+	struct sym_tcb *tp	= &np->target[target];
 	int	tmp;
 
 	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
@@ -4497,7 +4461,7 @@ static void sym_int_sir (struct sym_hcb 
 			if (cp) {
 				cp->xerr_status &= ~XE_PARITY_ERR;
 				if (!cp->xerr_status)
-					OUTOFFB (HF_PRT, HF_EXT_ERR);
+					OUTOFFB(np, HF_PRT, HF_EXT_ERR);
 			}
 		}
 		goto out;
@@ -4527,7 +4491,7 @@ static void sym_int_sir (struct sym_hcb 
 	 */
 	case SIR_SWIDE_OVERRUN:
 		if (cp) {
-			OUTONB (HF_PRT, HF_EXT_ERR);
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
 			cp->xerr_status |= XE_SWIDE_OVRUN;
 		}
 		goto out;
@@ -4538,7 +4502,7 @@ static void sym_int_sir (struct sym_hcb 
 	 */
 	case SIR_SODL_UNDERRUN:
 		if (cp) {
-			OUTONB (HF_PRT, HF_EXT_ERR);
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
 			cp->xerr_status |= XE_SODL_UNRUN;
 		}
 		goto out;
@@ -4550,9 +4514,9 @@ static void sym_int_sir (struct sym_hcb 
 	 */
 	case SIR_DATA_OVERRUN:
 		if (cp) {
-			OUTONB (HF_PRT, HF_EXT_ERR);
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
 			cp->xerr_status |= XE_EXTRA_DATA;
-			cp->extra_bytes += INL (nc_scratcha);
+			cp->extra_bytes += INL(np, nc_scratcha);
 		}
 		goto out;
 	/*
@@ -4560,7 +4524,7 @@ static void sym_int_sir (struct sym_hcb 
 	 */
 	case SIR_BAD_PHASE:
 		if (cp) {
-			OUTONB (HF_PRT, HF_EXT_ERR);
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
 			cp->xerr_status |= XE_BAD_PHASE;
 		}
 		goto out;
@@ -4609,16 +4573,16 @@ static void sym_int_sir (struct sym_hcb 
 			if (DEBUG_FLAGS & DEBUG_POINTER)
 				sym_print_msg(cp,"ign wide residue", np->msgin);
 			if (cp->host_flags & HF_SENSE)
-				OUTL_DSP (SCRIPTA_BA (np, clrack));
+				OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 			else
 				sym_modify_dp(np, tp, cp, -1);
 			return;
 		case M_REJECT:
-			if (INB (HS_PRT) == HS_NEGOTIATE)
+			if (INB(np, HS_PRT) == HS_NEGOTIATE)
 				sym_nego_rejected(np, tp, cp);
 			else {
-				PRINT_ADDR(cp);
-				printf ("M_REJECT received (%x:%x).\n",
+				sym_print_addr(cp->cmd,
+					"M_REJECT received (%x:%x).\n",
 					scr_to_cpu(np->lastmsg), np->msgout[0]);
 			}
 			goto out_clrack;
@@ -4633,7 +4597,7 @@ static void sym_int_sir (struct sym_hcb 
 	 */
 	case SIR_MSG_WEIRD:
 		sym_print_msg(cp, "WEIRD message received", np->msgin);
-		OUTL_DSP (SCRIPTB_BA (np, msg_weird));
+		OUTL_DSP(np, SCRIPTB_BA(np, msg_weird));
 		return;
 	/*
 	 *  Negotiation failed.
@@ -4641,7 +4605,7 @@ static void sym_int_sir (struct sym_hcb 
 	 *  Remove the HS_NEGOTIATE status.
 	 */
 	case SIR_NEGO_FAILED:
-		OUTB (HS_PRT, HS_BUSY);
+		OUTB(np, HS_PRT, HS_BUSY);
 	/*
 	 *  Negotiation failed.
 	 *  Target does not want answer message.
@@ -4649,16 +4613,16 @@ static void sym_int_sir (struct sym_hcb 
 	case SIR_NEGO_PROTO:
 		sym_nego_default(np, tp, cp);
 		goto out;
-	};
+	}
 
 out:
-	OUTONB_STD ();
+	OUTONB_STD();
 	return;
 out_reject:
-	OUTL_DSP (SCRIPTB_BA (np, msg_bad));
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
 	return;
 out_clrack:
-	OUTL_DSP (SCRIPTA_BA (np, clrack));
+	OUTL_DSP(np, SCRIPTA_BA(np, clrack));
 	return;
 out_stuck:
 	return;
@@ -4667,19 +4631,21 @@ out_stuck:
 /*
  *  Acquire a control block
  */
-ccb_p sym_get_ccb (struct sym_hcb *np, u_char tn, u_char ln, u_char tag_order)
+struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order)
 {
-	tcb_p tp = &np->target[tn];
-	lcb_p lp = sym_lp(np, tp, ln);
+	u_char tn = cmd->device->id;
+	u_char ln = cmd->device->lun;
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
 	u_short tag = NO_TAG;
 	SYM_QUEHEAD *qp;
-	ccb_p cp = (ccb_p) 0;
+	struct sym_ccb *cp = NULL;
 
 	/*
 	 *  Look for a free CCB
 	 */
 	if (sym_que_empty(&np->free_ccbq))
-		(void) sym_alloc_ccb(np);
+		sym_alloc_ccb(np);
 	qp = sym_remque_head(&np->free_ccbq);
 	if (!qp)
 		goto out;
@@ -4741,7 +4707,7 @@ ccb_p sym_get_ccb (struct sym_hcb *np, u
 #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
 				lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba);
 				lp->head.resel_sa =
-					cpu_to_scr(SCRIPTA_BA (np, resel_tag));
+					cpu_to_scr(SCRIPTA_BA(np, resel_tag));
 #endif
 #ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
 				cp->tags_si = lp->tags_si;
@@ -4774,7 +4740,7 @@ ccb_p sym_get_ccb (struct sym_hcb *np, u
 			if (lp->busy_itl == 1) {
 				lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba);
 				lp->head.resel_sa =
-				      cpu_to_scr(SCRIPTA_BA (np, resel_no_tag));
+				      cpu_to_scr(SCRIPTA_BA(np, resel_no_tag));
 			}
 			else
 				goto out_free;
@@ -4802,28 +4768,27 @@ ccb_p sym_get_ccb (struct sym_hcb *np, u
 	cp->lun    = ln;
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
-		PRINT_LUN(np, tn, ln);
-		printf ("ccb @%p using tag %d.\n", cp, tag);
+		sym_print_addr(cmd, "ccb @%p using tag %d.\n", cp, tag);
 	}
 
 out:
 	return cp;
 out_free:
 	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
-	return (ccb_p) 0;
+	return NULL;
 }
 
 /*
  *  Release one control block
  */
-void sym_free_ccb (struct sym_hcb *np, ccb_p cp)
+void sym_free_ccb (struct sym_hcb *np, struct sym_ccb *cp)
 {
-	tcb_p tp = &np->target[cp->target];
-	lcb_p lp = sym_lp(np, tp, cp->lun);
+	struct sym_tcb *tp = &np->target[cp->target];
+	struct sym_lcb *lp = sym_lp(tp, cp->lun);
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
-		PRINT_LUN(np, cp->target, cp->lun);
-		printf ("ccb @%p freeing tag %d.\n", cp, cp->tag);
+		sym_print_addr(cp->cmd, "ccb @%p freeing tag %d.\n",
+				cp, cp->tag);
 	}
 
 	/*
@@ -4862,7 +4827,7 @@ void sym_free_ccb (struct sym_hcb *np, c
 		 */
 		if (lp->busy_itlq == 0 && lp->busy_itl == 0)
 			lp->head.resel_sa =
-				cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
+				cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
 	}
 	/*
 	 *  Otherwise, we only accept 1 IO per LUN.
@@ -4889,14 +4854,9 @@ void sym_free_ccb (struct sym_hcb *np, c
 #endif
 
 	/*
-	 *  Unmap user data from DMA map if needed.
-	 */
-	sym_data_dmamap_unload(np, cp);
-
-	/*
 	 *  Make this CCB available.
 	 */
-	cp->cam_ccb = NULL;
+	cp->cmd = NULL;
 	cp->host_status = HS_IDLE;
 	sym_remque(&cp->link_ccbq);
 	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
@@ -4919,9 +4879,9 @@ void sym_free_ccb (struct sym_hcb *np, c
 /*
  *  Allocate a CCB from memory and initialize its fixed part.
  */
-static ccb_p sym_alloc_ccb(struct sym_hcb *np)
+static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np)
 {
-	ccb_p cp = NULL;
+	struct sym_ccb *cp = NULL;
 	int hcode;
 
 	/*
@@ -4939,19 +4899,6 @@ static ccb_p sym_alloc_ccb(struct sym_hc
 		goto out_free;
 
 	/*
-	 *  Allocate a bounce buffer for sense data.
-	 */
-	cp->sns_bbuf = sym_calloc_dma(SYM_SNS_BBUF_LEN, "SNS_BBUF");
-	if (!cp->sns_bbuf)
-		goto out_free;
-
-	/*
-	 *  Allocate a map for the DMA of user data.
-	 */
-	if (sym_data_dmamap_create(np, cp))
-		goto out_free;
-
-	/*
 	 *  Count it.
 	 */
 	np->actccbs++;
@@ -4971,8 +4918,8 @@ static ccb_p sym_alloc_ccb(struct sym_hc
 	/*
 	 *  Initialyze the start and restart actions.
 	 */
-	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA (np, idle));
-	cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
+	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA(np, idle));
+	cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
 
  	/*
 	 *  Initilialyze some other fields.
@@ -4992,21 +4939,18 @@ static ccb_p sym_alloc_ccb(struct sym_hc
 #endif
 	return cp;
 out_free:
-	if (cp) {
-		if (cp->sns_bbuf)
-			sym_mfree_dma(cp->sns_bbuf,SYM_SNS_BBUF_LEN,"SNS_BBUF");
+	if (cp)
 		sym_mfree_dma(cp, sizeof(*cp), "CCB");
-	}
 	return NULL;
 }
 
 /*
  *  Look up a CCB from a DSA value.
  */
-static ccb_p sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa)
+static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa)
 {
 	int hcode;
-	ccb_p cp;
+	struct sym_ccb *cp;
 
 	hcode = CCB_HASH_CODE(dsa);
 	cp = np->ccbh[hcode];
@@ -5039,10 +4983,10 @@ static void sym_init_tcb (struct sym_hcb
 /*
  *  Lun control block allocation and initialization.
  */
-lcb_p sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
+struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
 {
-	tcb_p tp = &np->target[tn];
-	lcb_p lp = sym_lp(np, tp, ln);
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
 
 	/*
 	 *  Already done, just return.
@@ -5081,8 +5025,8 @@ lcb_p sym_alloc_lcb (struct sym_hcb *np,
 	 *  Allocate the table of pointers for LUN(s) > 0, if needed.
 	 */
 	if (ln && !tp->lunmp) {
-		tp->lunmp = sym_calloc(SYM_CONF_MAX_LUN * sizeof(lcb_p),
-				   "LUNMP");
+		tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *),
+				GFP_KERNEL);
 		if (!tp->lunmp)
 			goto fail;
 	}
@@ -5111,7 +5055,7 @@ lcb_p sym_alloc_lcb (struct sym_hcb *np,
 	/*
 	 *  Set the reselect pattern to our default. :)
 	 */
-	lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
+	lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
 
 	/*
 	 *  Set user capabilities.
@@ -5143,8 +5087,8 @@ fail:
  */
 static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln)
 {
-	tcb_p tp = &np->target[tn];
-	lcb_p lp = sym_lp(np, tp, ln);
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
 	int i;
 
 	/*
@@ -5160,7 +5104,7 @@ static void sym_alloc_lcb_tags (struct s
 	lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
 	if (!lp->itlq_tbl)
 		goto fail;
-	lp->cb_tags = sym_calloc(SYM_CONF_MAX_TASK, "CB_TAGS");
+	lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_KERNEL);
 	if (!lp->cb_tags) {
 		sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
 		lp->itlq_tbl = NULL;
@@ -5193,10 +5137,11 @@ fail:
 /*
  *  Queue a SCSI IO to the controller.
  */
-int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, ccb_p cp)
+int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
 {
-	tcb_p	tp;
-	lcb_p	lp;
+	struct scsi_device *sdev = cmd->device;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
 	u_char	*msgptr;
 	u_int   msglen;
 	int can_disconnect;
@@ -5204,7 +5149,7 @@ int sym_queue_scsiio(struct sym_hcb *np,
 	/*
 	 *  Keep track of the IO in our CCB.
 	 */
-	cp->cam_ccb = csio;
+	cp->cmd = cmd;
 
 	/*
 	 *  Retrieve the target descriptor.
@@ -5214,14 +5159,14 @@ int sym_queue_scsiio(struct sym_hcb *np,
 	/*
 	 *  Retrieve the lun descriptor.
 	 */
-	lp = sym_lp(np, tp, cp->lun);
+	lp = sym_lp(tp, sdev->lun);
 
 	can_disconnect = (cp->tag != NO_TAG) ||
 		(lp && (lp->curr_flags & SYM_DISC_ENABLED));
 
 	msgptr = cp->scsi_smsg;
 	msglen = 0;
-	msgptr[msglen++] = IDENTIFY(can_disconnect, cp->lun);
+	msgptr[msglen++] = IDENTIFY(can_disconnect, sdev->lun);
 
 	/*
 	 *  Build the tag message if present.
@@ -5249,8 +5194,8 @@ int sym_queue_scsiio(struct sym_hcb *np,
 			if (lp->tags_sum[lp->tags_si]) {
 				order = M_ORDERED_TAG;
 				if ((DEBUG_FLAGS & DEBUG_TAGS)||sym_verbose>1) {
-					PRINT_ADDR(cp);
-					printf("ordered tag forced.\n");
+					sym_print_addr(cmd,
+						"ordered tag forced.\n");
 				}
 			}
 			lp->tags_since = 0;
@@ -5277,19 +5222,15 @@ int sym_queue_scsiio(struct sym_hcb *np,
 	 *  (nego_status is filled by sym_prepare_nego())
 	 */
 	cp->nego_status = 0;
-	if (tp->tinfo.curr.width   != tp->tinfo.goal.width  ||
-	    tp->tinfo.curr.period  != tp->tinfo.goal.period ||
-	    tp->tinfo.curr.offset  != tp->tinfo.goal.offset ||
-	    tp->tinfo.curr.options != tp->tinfo.goal.options) {
-		if (!tp->nego_cp && lp)
-			msglen += sym_prepare_nego(np, cp, msgptr + msglen);
+	if (tp->tgoal.check_nego && !tp->nego_cp && lp) {
+		msglen += sym_prepare_nego(np, cp, msgptr + msglen);
 	}
 
 	/*
 	 *  Startqueue
 	 */
-	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA (np, select));
-	cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA (np, resel_dsa));
+	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA(np, select));
+	cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA(np, resel_dsa));
 
 	/*
 	 *  select
@@ -5302,7 +5243,7 @@ int sym_queue_scsiio(struct sym_hcb *np,
 	/*
 	 *  message
 	 */
-	cp->phys.smsg.addr	= cpu_to_scr(CCB_BA (cp, scsi_smsg));
+	cp->phys.smsg.addr	= cpu_to_scr(CCB_BA(cp, scsi_smsg));
 	cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 	/*
@@ -5326,7 +5267,7 @@ int sym_queue_scsiio(struct sym_hcb *np,
 	 *  Build the CDB and DATA descriptor block 
 	 *  and start the IO.
 	 */
-	return sym_setup_data_and_start(np, csio, cp);
+	return sym_setup_data_and_start(np, cmd, cp);
 }
 
 /*
@@ -5334,7 +5275,7 @@ int sym_queue_scsiio(struct sym_hcb *np,
  */
 int sym_reset_scsi_target(struct sym_hcb *np, int target)
 {
-	tcb_p tp;
+	struct sym_tcb *tp;
 
 	if (target == np->myaddr || (u_int)target >= SYM_CONF_MAX_TARGET)
 		return -1;
@@ -5343,7 +5284,7 @@ int sym_reset_scsi_target(struct sym_hcb
 	tp->to_reset = 1;
 
 	np->istat_sem = SEM;
-	OUTB (nc_istat, SIGP|SEM);
+	OUTB(np, nc_istat, SIGP|SEM);
 
 	return 0;
 }
@@ -5351,7 +5292,7 @@ int sym_reset_scsi_target(struct sym_hcb
 /*
  *  Abort a SCSI IO.
  */
-int sym_abort_ccb(struct sym_hcb *np, ccb_p cp, int timed_out)
+static int sym_abort_ccb(struct sym_hcb *np, struct sym_ccb *cp, int timed_out)
 {
 	/*
 	 *  Check that the IO is active.
@@ -5377,13 +5318,13 @@ int sym_abort_ccb(struct sym_hcb *np, cc
 	 *  Tell the SCRIPTS processor to stop and synchronize with us.
 	 */
 	np->istat_sem = SEM;
-	OUTB (nc_istat, SIGP|SEM);
+	OUTB(np, nc_istat, SIGP|SEM);
 	return 0;
 }
 
-int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out)
+int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, int timed_out)
 {
-	ccb_p cp;
+	struct sym_ccb *cp;
 	SYM_QUEHEAD *qp;
 
 	/*
@@ -5391,8 +5332,8 @@ int sym_abort_scsiio(struct sym_hcb *np,
 	 */
 	cp = NULL;
 	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
-		ccb_p cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq);
-		if (cp2->cam_ccb == ccb) {
+		struct sym_ccb *cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		if (cp2->cmd == cmd) {
 			cp = cp2;
 			break;
 		}
@@ -5411,37 +5352,40 @@ int sym_abort_scsiio(struct sym_hcb *np,
  *  SCRATCHA is assumed to have been loaded with STARTPOS 
  *  before the SCRIPTS called the C code.
  */
-void sym_complete_error (struct sym_hcb *np, ccb_p cp)
+void sym_complete_error(struct sym_hcb *np, struct sym_ccb *cp)
 {
-	tcb_p tp;
-	lcb_p lp;
+	struct scsi_device *sdev;
+	struct scsi_cmnd *cmd;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
 	int resid;
 	int i;
 
 	/*
 	 *  Paranoid check. :)
 	 */
-	if (!cp || !cp->cam_ccb)
+	if (!cp || !cp->cmd)
 		return;
 
+	cmd = cp->cmd;
+	sdev = cmd->device;
 	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) {
-		printf ("CCB=%lx STAT=%x/%x/%x DEV=%d/%d\n", (unsigned long)cp,
-			cp->host_status, cp->ssss_status, cp->host_flags,
-			cp->target, cp->lun);
+		dev_info(&sdev->sdev_gendev, "CCB=%p STAT=%x/%x/%x\n", cp,
+			cp->host_status, cp->ssss_status, cp->host_flags);
 	}
 
 	/*
 	 *  Get target and lun pointers.
 	 */
 	tp = &np->target[cp->target];
-	lp = sym_lp(np, tp, cp->lun);
+	lp = sym_lp(tp, sdev->lun);
 
 	/*
 	 *  Check for extended errors.
 	 */
 	if (cp->xerr_status) {
 		if (sym_verbose)
-			sym_print_xerr(cp, cp->xerr_status);
+			sym_print_xerr(cmd, cp->xerr_status);
 		if (cp->host_status == HS_COMPLETE)
 			cp->host_status = HS_COMP_ERR;
 	}
@@ -5464,13 +5408,13 @@ if (resid)
 	 *  Dequeue all queued CCBs for that device 
 	 *  not yet started by SCRIPTS.
 	 */
-	i = (INL (nc_scratcha) - np->squeue_ba) / 4;
-	i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
+	i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+	i = sym_dequeue_from_squeue(np, i, cp->target, sdev->lun, -1);
 
 	/*
 	 *  Restart the SCRIPTS processor.
 	 */
-	OUTL_DSP (SCRIPTA_BA (np, start));
+	OUTL_DSP(np, SCRIPTA_BA(np, start));
 
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
 	if (cp->host_status == HS_COMPLETE &&
@@ -5484,8 +5428,8 @@ if (resid)
 		lp->num_sgood = 0;
 
 		if (sym_verbose >= 2) {
-			PRINT_LUN(np, cp->target, cp->lun);
-			printf(" queue depth is now %d\n", lp->started_max);
+			sym_print_addr(cmd, " queue depth is now %d\n",
+					lp->started_max);
 		}
 
 		/*
@@ -5497,17 +5441,12 @@ if (resid)
 		/*
 		 *  Let's requeue it to device.
 		 */
-		sym_set_cam_status(cp->cam_ccb, CAM_REQUEUE_REQ);
+		sym_set_cam_status(cmd, CAM_REQUEUE_REQ);
 		goto finish;
 	}
 weirdness:
 #endif
 	/*
-	 *  Synchronize DMA map if needed.
-	 */
-	sym_data_dmamap_postsync(np, cp);
-
-	/*
 	 *  Build result in CAM ccb.
 	 */
 	sym_set_cam_result_error(np, cp, resid);
@@ -5545,30 +5484,30 @@ finish:
  *  The SCRIPTS processor is running while we are 
  *  completing successful commands.
  */
-void sym_complete_ok (struct sym_hcb *np, ccb_p cp)
+void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp)
 {
-	tcb_p tp;
-	lcb_p lp;
-	struct scsi_cmnd *ccb;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	struct scsi_cmnd *cmd;
 	int resid;
 
 	/*
 	 *  Paranoid check. :)
 	 */
-	if (!cp || !cp->cam_ccb)
+	if (!cp || !cp->cmd)
 		return;
 	assert (cp->host_status == HS_COMPLETE);
 
 	/*
 	 *  Get user command.
 	 */
-	ccb = cp->cam_ccb;
+	cmd = cp->cmd;
 
 	/*
 	 *  Get target and lun pointers.
 	 */
 	tp = &np->target[cp->target];
-	lp = sym_lp(np, tp, cp->lun);
+	lp = sym_lp(tp, cp->lun);
 
 	/*
 	 *  Assume device discovered on first success.
@@ -5586,8 +5525,8 @@ void sym_complete_ok (struct sym_hcb *np
 
 	/*
 	 *  Wrong transfer residuals may be worse than just always 
-	 *  returning zero. User can disable this feature from 
-	 *  sym_conf.h. Residual support is enabled by default.
+	 *  returning zero. User can disable this feature in 
+	 *  sym53c8xx.h. Residual support is enabled by default.
 	 */
 	if (!SYM_SETUP_RESIDUAL_SUPPORT)
 		resid  = 0;
@@ -5597,14 +5536,9 @@ if (resid)
 #endif
 
 	/*
-	 *  Synchronize DMA map if needed.
-	 */
-	sym_data_dmamap_postsync(np, cp);
-
-	/*
 	 *  Build result in CAM ccb.
 	 */
-	sym_set_cam_result_ok(np, cp, resid);
+	sym_set_cam_result_ok(cp, cmd, resid);
 
 #ifdef	SYM_OPT_SNIFF_INQUIRY
 	/*
@@ -5612,7 +5546,7 @@ if (resid)
 	 *  not set), sniff out device capabilities.
 	 */
 	if (cp->cdb_buf[0] == INQUIRY && !(cp->cdb_buf[1] & 0x3))
-		sym_sniff_inquiry(np, cp->cam_ccb, resid);
+		sym_sniff_inquiry(np, cmd, resid);
 #endif
 
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
@@ -5626,8 +5560,7 @@ if (resid)
 			lp->num_sgood = 0;
 			++lp->started_max;
 			if (sym_verbose >= 2) {
-				PRINT_LUN(np, cp->target, cp->lun);
-				printf(" queue depth is now %d\n",
+				sym_print_addr(cmd, " queue depth is now %d\n",
 				       lp->started_max);
 			}
 		}
@@ -5649,14 +5582,15 @@ if (resid)
 	/*
 	 *  Complete the command.
 	 */
-	sym_xpt_done(np, ccb);
+	sym_xpt_done(np, cmd);
 }
 
 /*
  *  Soft-attach the controller.
  */
-int sym_hcb_attach(struct sym_hcb *np, struct sym_fw *fw, struct sym_nvram *nvram)
+int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram)
 {
+	struct sym_hcb *np = sym_get_hcb(shost);
 	int i;
 
 	/*
@@ -5680,13 +5614,13 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	 *  that SCSI clock calibration may not work properly 
 	 *  if the chip is currently active.
 	 */
-	sym_chip_reset (np);
+	sym_chip_reset(np);
 
 	/*
 	 *  Prepare controller and devices settings, according 
 	 *  to chip features, user set-up and driver set-up.
 	 */
-	(void) sym_prepare_setting(np, nvram);
+	sym_prepare_setting(shost, np, nvram);
 
 	/*
 	 *  Check the PCI clock frequency.
@@ -5701,7 +5635,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	/*
 	 *  Allocate the start queue.
 	 */
-	np->squeue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE");
+	np->squeue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE");
 	if (!np->squeue)
 		goto attach_failed;
 	np->squeue_ba = vtobus(np->squeue);
@@ -5709,7 +5643,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	/*
 	 *  Allocate the done queue.
 	 */
-	np->dqueue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE");
+	np->dqueue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE");
 	if (!np->dqueue)
 		goto attach_failed;
 	np->dqueue_ba = vtobus(np->dqueue);
@@ -5717,7 +5651,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	/*
 	 *  Allocate the target bus address array.
 	 */
-	np->targtbl = (u32 *) sym_calloc_dma(256, "TARGTBL");
+	np->targtbl = sym_calloc_dma(256, "TARGTBL");
 	if (!np->targtbl)
 		goto attach_failed;
 	np->targtbl_ba = vtobus(np->targtbl);
@@ -5734,7 +5668,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	/*
 	 *  Allocate the array of lists of CCBs hashed by DSA.
 	 */
-	np->ccbh = sym_calloc(sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH");
+	np->ccbh = kcalloc(sizeof(struct sym_ccb **), CCB_HASH_SIZE, GFP_KERNEL);
 	if (!np->ccbh)
 		goto attach_failed;
 
@@ -5817,20 +5751,20 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	/*
 	 *  Prepare the idle and invalid task actions.
 	 */
-	np->idletask.start	= cpu_to_scr(SCRIPTA_BA (np, idle));
-	np->idletask.restart	= cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
+	np->idletask.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->idletask.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
 	np->idletask_ba		= vtobus(&np->idletask);
 
-	np->notask.start	= cpu_to_scr(SCRIPTA_BA (np, idle));
-	np->notask.restart	= cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
+	np->notask.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->notask.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
 	np->notask_ba		= vtobus(&np->notask);
 
-	np->bad_itl.start	= cpu_to_scr(SCRIPTA_BA (np, idle));
-	np->bad_itl.restart	= cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
+	np->bad_itl.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->bad_itl.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
 	np->bad_itl_ba		= vtobus(&np->bad_itl);
 
-	np->bad_itlq.start	= cpu_to_scr(SCRIPTA_BA (np, idle));
-	np->bad_itlq.restart	= cpu_to_scr(SCRIPTB_BA (np,bad_i_t_l_q));
+	np->bad_itlq.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->bad_itlq.restart	= cpu_to_scr(SCRIPTB_BA(np,bad_i_t_l_q));
 	np->bad_itlq_ba		= vtobus(&np->bad_itlq);
 
 	/*
@@ -5843,7 +5777,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	if (!np->badluntbl)
 		goto attach_failed;
 
-	np->badlun_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
+	np->badlun_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
 	for (i = 0 ; i < 64 ; i++)	/* 64 luns/target, no less */
 		np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
 
@@ -5866,7 +5800,7 @@ int sym_hcb_attach(struct sym_hcb *np, s
 	if (sym_snooptest (np)) {
 		printf("%s: CACHE INCORRECTLY CONFIGURED.\n", sym_name(np));
 		goto attach_failed;
-	};
+	}
 
 	/*
 	 *  Sigh! we are done.
@@ -5883,9 +5817,9 @@ attach_failed:
 void sym_hcb_free(struct sym_hcb *np)
 {
 	SYM_QUEHEAD *qp;
-	ccb_p cp;
-	tcb_p tp;
-	lcb_p lp;
+	struct sym_ccb *cp;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
 	int target, lun;
 
 	if (np->scriptz0)
@@ -5902,14 +5836,10 @@ void sym_hcb_free(struct sym_hcb *np)
 	if (np->actccbs) {
 		while ((qp = sym_remque_head(&np->free_ccbq)) != 0) {
 			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
-			sym_data_dmamap_destroy(np, cp);
-			sym_mfree_dma(cp->sns_bbuf, SYM_SNS_BBUF_LEN,
-				      "SNS_BBUF");
 			sym_mfree_dma(cp, sizeof(*cp), "CCB");
 		}
 	}
-	if (np->ccbh)
-		sym_mfree(np->ccbh, sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH");
+	kfree(np->ccbh);
 
 	if (np->badluntbl)
 		sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL");
@@ -5917,21 +5847,17 @@ void sym_hcb_free(struct sym_hcb *np)
 	for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
 		tp = &np->target[target];
 		for (lun = 0 ; lun < SYM_CONF_MAX_LUN ; lun++) {
-			lp = sym_lp(np, tp, lun);
+			lp = sym_lp(tp, lun);
 			if (!lp)
 				continue;
 			if (lp->itlq_tbl)
 				sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4,
 				       "ITLQ_TBL");
-			if (lp->cb_tags)
-				sym_mfree(lp->cb_tags, SYM_CONF_MAX_TASK,
-				       "CB_TAGS");
+			kfree(lp->cb_tags);
 			sym_mfree_dma(lp, sizeof(*lp), "LCB");
 		}
 #if SYM_CONF_MAX_LUN > 1
-		if (tp->lunmp)
-			sym_mfree(tp->lunmp, SYM_CONF_MAX_LUN*sizeof(lcb_p),
-			       "LUNMP");
+		kfree(tp->lunmp);
 #endif 
 	}
 	if (np->targtbl)
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -188,36 +188,45 @@
 /*
  *  Common definitions for both bus space based and legacy IO methods.
  */
-#define INB(r)		INB_OFF(offsetof(struct sym_reg,r))
-#define INW(r)		INW_OFF(offsetof(struct sym_reg,r))
-#define INL(r)		INL_OFF(offsetof(struct sym_reg,r))
-
-#define OUTB(r, v)	OUTB_OFF(offsetof(struct sym_reg,r), (v))
-#define OUTW(r, v)	OUTW_OFF(offsetof(struct sym_reg,r), (v))
-#define OUTL(r, v)	OUTL_OFF(offsetof(struct sym_reg,r), (v))
-
-#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+
+#define INB_OFF(np, o)		ioread8(np->s.ioaddr + (o))
+#define INW_OFF(np, o)		ioread16(np->s.ioaddr + (o))
+#define INL_OFF(np, o)		ioread32(np->s.ioaddr + (o))
+
+#define OUTB_OFF(np, o, val)	iowrite8((val), np->s.ioaddr + (o))
+#define OUTW_OFF(np, o, val)	iowrite16((val), np->s.ioaddr + (o))
+#define OUTL_OFF(np, o, val)	iowrite32((val), np->s.ioaddr + (o))
+
+#define INB(np, r)		INB_OFF(np, offsetof(struct sym_reg, r))
+#define INW(np, r)		INW_OFF(np, offsetof(struct sym_reg, r))
+#define INL(np, r)		INL_OFF(np, offsetof(struct sym_reg, r))
+
+#define OUTB(np, r, v)		OUTB_OFF(np, offsetof(struct sym_reg, r), (v))
+#define OUTW(np, r, v)		OUTW_OFF(np, offsetof(struct sym_reg, r), (v))
+#define OUTL(np, r, v)		OUTL_OFF(np, offsetof(struct sym_reg, r), (v))
+
+#define OUTONB(np, r, m)	OUTB(np, r, INB(np, r) | (m))
+#define OUTOFFB(np, r, m)	OUTB(np, r, INB(np, r) & ~(m))
+#define OUTONW(np, r, m)	OUTW(np, r, INW(np, r) | (m))
+#define OUTOFFW(np, r, m)	OUTW(np, r, INW(np, r) & ~(m))
+#define OUTONL(np, r, m)	OUTL(np, r, INL(np, r) | (m))
+#define OUTOFFL(np, r, m)	OUTL(np, r, INL(np, r) & ~(m))
 
 /*
  *  We normally want the chip to have a consistent view
  *  of driver internal data structures when we restart it.
  *  Thus these macros.
  */
-#define OUTL_DSP(v)				\
+#define OUTL_DSP(np, v)				\
 	do {					\
 		MEMORY_WRITE_BARRIER();		\
-		OUTL (nc_dsp, (v));		\
+		OUTL(np, nc_dsp, (v));		\
 	} while (0)
 
 #define OUTONB_STD()				\
 	do {					\
 		MEMORY_WRITE_BARRIER();		\
-		OUTONB (nc_dcntl, (STD|NOCOM));	\
+		OUTONB(np, nc_dcntl, (STD|NOCOM));	\
 	} while (0)
 
 /*
@@ -321,7 +330,6 @@
  *  Host adapter miscellaneous flags.
  */
 #define SYM_AVOID_BUS_RESET	(1)
-#define SYM_SCAN_TARGETS_HILO	(1<<1)
 
 /*
  *  Misc.
@@ -334,20 +342,13 @@
  *  Gather negotiable parameters value
  */
 struct sym_trans {
-	u8 scsi_version;
-	u8 spi_version;
 	u8 period;
 	u8 offset;
-	u8 width;
-	u8 options;	/* PPR options */
-};
-
-struct sym_tinfo {
-	struct sym_trans curr;
-	struct sym_trans goal;
-#ifdef	SYM_OPT_ANNOUNCE_TRANSFER_RATE
-	struct sym_trans prev;
-#endif
+	unsigned int width:1;
+	unsigned int iu:1;
+	unsigned int dt:1;
+	unsigned int qas:1;
+	unsigned int check_nego:1;
 };
 
 /*
@@ -398,9 +399,9 @@ struct sym_tcb {
 	/*
 	 *  LUN table used by the C code.
 	 */
-	lcb_p	lun0p;		/* LCB of LUN #0 (usual case)	*/
+	struct sym_lcb *lun0p;		/* LCB of LUN #0 (usual case)	*/
 #if SYM_CONF_MAX_LUN > 1
-	lcb_p	*lunmp;		/* Other LCBs [1..MAX_LUN]	*/
+	struct sym_lcb **lunmp;		/* Other LCBs [1..MAX_LUN]	*/
 #endif
 
 	/*
@@ -423,16 +424,14 @@ struct sym_tcb {
 	struct sym_stcb s;
 #endif
 
-	/*
-	 *  Transfer capabilities (SIP)
-	 */
-	struct sym_tinfo tinfo;
+	/* Transfer goal */
+	struct sym_trans tgoal;
 
 	/*
 	 * Keep track of the CCB used for the negotiation in order
 	 * to ensure that only 1 negotiation is queued at a time.
 	 */
-	ccb_p   nego_cp;	/* CCB used for the nego		*/
+	struct sym_ccb *  nego_cp;	/* CCB used for the nego		*/
 
 	/*
 	 *  Set when we want to reset the device.
@@ -520,10 +519,8 @@ struct sym_lcb {
 	 *  Optionnaly the driver can handle device queueing, 
 	 *  and requeues internally command to redo.
 	 */
-	SYM_QUEHEAD
-		waiting_ccbq;
-	SYM_QUEHEAD
-		started_ccbq;
+	SYM_QUEHEAD waiting_ccbq;
+	SYM_QUEHEAD started_ccbq;
 	int	num_sgood;
 	u_short	started_tags;
 	u_short	started_no_tag;
@@ -533,8 +530,8 @@ struct sym_lcb {
 
 #ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
 	/*
-	 *  Optionnaly the driver can try to prevent SCSI 
-	 *  IOs from being too much reordering.
+	 *  Optionally the driver can try to prevent SCSI 
+	 *  IOs from being reordered too much.
 	 */
 	u_char		tags_si;	/* Current index to tags sum	*/
 	u_short		tags_sum[2];	/* Tags sum counters		*/
@@ -582,9 +579,9 @@ struct sym_pmc {
  *  LUN(s) > 0.
  */
 #if SYM_CONF_MAX_LUN <= 1
-#define sym_lp(np, tp, lun) (!lun) ? (tp)->lun0p : NULL
+#define sym_lp(tp, lun) (!lun) ? (tp)->lun0p : NULL
 #else
-#define sym_lp(np, tp, lun) \
+#define sym_lp(tp, lun) \
 	(!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : NULL
 #endif
 
@@ -749,12 +746,10 @@ struct sym_ccb {
 	/*
 	 *  Pointer to CAM ccb and related stuff.
 	 */
-	struct scsi_cmnd *cam_ccb;	/* CAM scsiio ccb		*/
+	struct scsi_cmnd *cmd;	/* CAM scsiio ccb		*/
 	u8	cdb_buf[16];	/* Copy of CDB			*/
-	u8	*sns_bbuf;	/* Bounce buffer for sense data	*/
-#ifndef	SYM_SNS_BBUF_LEN
-#define	SYM_SNS_BBUF_LEN (32)
-#endif	
+#define	SYM_SNS_BBUF_LEN 32
+	u8	sns_bbuf[SYM_SNS_BBUF_LEN]; /* Bounce buffer for sense data */
 	int	data_len;	/* Total data length		*/
 	int	segments;	/* Number of SG segments	*/
 
@@ -788,12 +783,6 @@ struct sym_ccb {
 	int	sv_resid;	/* Saved residual		*/
 
 	/*
-	 *  O/S specific data structure.
-	 */
-#ifdef	SYM_HAVE_SCCB
-	struct sym_sccb s;
-#endif
-	/*
 	 *  Other fields.
 	 */
 	u32	ccb_ba;		/* BUS address of this CCB	*/
@@ -801,9 +790,8 @@ struct sym_ccb {
 				/*  NO_TAG means no tag		*/
 	u_char	target;
 	u_char	lun;
-	ccb_p	link_ccbh;	/* Host adapter CCB hash chain	*/
-	SYM_QUEHEAD
-		link_ccbq;	/* Link to free/busy CCB queue	*/
+	struct sym_ccb *link_ccbh;	/* Host adapter CCB hash chain	*/
+	SYM_QUEHEAD link_ccbq;	/* Link to free/busy CCB queue	*/
 	u32	startp;		/* Initial data pointer		*/
 	u32	goalp;		/* Expected last data pointer	*/
 #ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
@@ -812,8 +800,7 @@ struct sym_ccb {
 	int	ext_sg;		/* Extreme data pointer, used	*/
 	int	ext_ofs;	/*  to calculate the residual.	*/
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
-	SYM_QUEHEAD
-		link2_ccbq;	/* Link for device queueing	*/
+	SYM_QUEHEAD link2_ccbq;	/* Link for device queueing	*/
 	u_char	started;	/* CCB queued to the squeue	*/
 #endif
 	u_char	to_abort;	/* Want this IO to be aborted	*/
@@ -830,6 +817,8 @@ struct sym_ccb {
 #define	sym_goalp(cp) (cp->goalp)
 #endif
 
+typedef struct device *m_pool_ident_t;
+
 /*
  *  Host Control Block
  */
@@ -1005,7 +994,7 @@ struct sym_hcb {
 	/*
 	 *  CCB lists and queue.
 	 */
-	ccb_p *ccbh;			/* CCBs hashed by DSA value	*/
+	struct sym_ccb **ccbh;			/* CCBs hashed by DSA value	*/
 					/* CCB_HASH_SIZE lists of CCBs	*/
 	SYM_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
 	SYM_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
@@ -1037,7 +1026,7 @@ struct sym_hcb {
 #ifdef SYM_CONF_IARB_SUPPORT
 	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
 	u_short		iarb_count;	/* Actual # of these hints	*/
-	ccb_p		last_cp;
+	struct sym_ccb *	last_cp;
 #endif
 
 	/*
@@ -1068,41 +1057,31 @@ struct sym_hcb {
 /*
  *  FIRMWARES (sym_fw.c)
  */
-struct sym_fw * sym_find_firmware(struct sym_pci_chip *chip);
-void sym_fw_bind_script (struct sym_hcb *np, u32 *start, int len);
+struct sym_fw * sym_find_firmware(struct sym_chip *chip);
+void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len);
 
 /*
  *  Driver methods called from O/S specific code.
  */
 char *sym_driver_name(void);
-void sym_print_xerr(ccb_p cp, int x_status);
+void sym_print_xerr(struct scsi_cmnd *cmd, int x_status);
 int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int);
-struct sym_pci_chip *
-sym_lookup_pci_chip_table (u_short device_id, u_char revision);
-void sym_put_start_queue(struct sym_hcb *np, ccb_p cp);
+struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision);
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
-void sym_start_next_ccbs(struct sym_hcb *np, lcb_p lp, int maxn);
+void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
 #endif
-void sym_start_up (struct sym_hcb *np, int reason);
-void sym_interrupt (struct sym_hcb *np);
+void sym_start_up(struct sym_hcb *np, int reason);
+void sym_interrupt(struct sym_hcb *np);
 int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task);
-ccb_p sym_get_ccb (struct sym_hcb *np, u_char tn, u_char ln, u_char tag_order);
-void sym_free_ccb (struct sym_hcb *np, ccb_p cp);
-lcb_p sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln);
-int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, ccb_p cp);
+struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
+void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
+struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln);
+int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
 int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out);
-int sym_abort_ccb(struct sym_hcb *np, ccb_p cp, int timed_out);
 int sym_reset_scsi_target(struct sym_hcb *np, int target);
 void sym_hcb_free(struct sym_hcb *np);
-int sym_hcb_attach(struct sym_hcb *np, struct sym_fw *fw, struct sym_nvram *nvram);
-
-/*
- *  Optionnaly, the driver may provide a function
- *  to announce transfer rate changes.
- */
-#ifdef	SYM_OPT_ANNOUNCE_TRANSFER_RATE
-void sym_announce_transfer_rate(struct sym_hcb *np, int target);
-#endif
+int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram);
 
 /*
  *  Build a scatter/gather entry.
@@ -1169,7 +1148,7 @@ static inline void sym_setup_data_pointe
 	case CAM_DIR_UNKNOWN:
 #endif
 	case CAM_DIR_OUT:
-		goalp = SCRIPTA_BA (np, data_out2) + 8;
+		goalp = SCRIPTA_BA(np, data_out2) + 8;
 		lastp = goalp - 8 - (cp->segments * (2*4));
 #ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
 		cp->wgoalp = cpu_to_scr(goalp);
@@ -1182,7 +1161,7 @@ static inline void sym_setup_data_pointe
 #endif
 	case CAM_DIR_IN:
 		cp->host_flags |= HF_DATA_IN;
-		goalp = SCRIPTA_BA (np, data_in2) + 8;
+		goalp = SCRIPTA_BA(np, data_in2) + 8;
 		lastp = goalp - 8 - (cp->segments * (2*4));
 		break;
 	case CAM_DIR_NONE:
@@ -1190,7 +1169,7 @@ static inline void sym_setup_data_pointe
 #ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
 		cp->host_flags |= HF_DATA_IN;
 #endif
-		lastp = goalp = SCRIPTB_BA (np, no_data);
+		lastp = goalp = SCRIPTB_BA(np, no_data);
 		break;
 	}
 
@@ -1207,7 +1186,7 @@ static inline void sym_setup_data_pointe
 	 *  If direction is unknown, start at data_io.
 	 */
 	if (dir == CAM_DIR_UNKNOWN)
-		cp->phys.head.savep = cpu_to_scr(SCRIPTB_BA (np, data_io));
+		cp->phys.head.savep = cpu_to_scr(SCRIPTB_BA(np, data_io));
 #endif
 }
 
@@ -1215,6 +1194,17 @@ static inline void sym_setup_data_pointe
  *  MEMORY ALLOCATOR.
  */
 
+#define SYM_MEM_PAGE_ORDER 0	/* 1 PAGE  maximum */
+#define SYM_MEM_CLUSTER_SHIFT	(PAGE_SHIFT+SYM_MEM_PAGE_ORDER)
+#define SYM_MEM_FREE_UNUSED	/* Free unused pages immediately */
+
+#define SYM_MEM_WARN	1	/* Warn on failed operations */
+
+#define sym_get_mem_cluster()	\
+	(void *) __get_free_pages(GFP_ATOMIC, SYM_MEM_PAGE_ORDER)
+#define sym_free_mem_cluster(p)	\
+	free_pages((unsigned long)p, SYM_MEM_PAGE_ORDER)
+
 /*
  *  Link between free memory chunks of a given size.
  */
@@ -1228,11 +1218,8 @@ typedef struct sym_m_link {
  */
 typedef struct sym_m_vtob {	/* Virtual to Bus address translation */
 	struct sym_m_vtob *next;
-#ifdef	SYM_HAVE_M_SVTOB
-	struct sym_m_svtob s;	/* OS specific data structure */
-#endif
-	m_addr_t	vaddr;	/* Virtual address */
-	m_addr_t	baddr;	/* Bus physical address */
+	void *vaddr;		/* Virtual address */
+	dma_addr_t baddr;	/* Bus physical address */
 } *m_vtob_p;
 
 /* Hash this stuff a bit to speed up translations */
@@ -1240,7 +1227,7 @@ typedef struct sym_m_vtob {	/* Virtual t
 #define VTOB_HASH_SIZE		(1UL << VTOB_HASH_SHIFT)
 #define VTOB_HASH_MASK		(VTOB_HASH_SIZE-1)
 #define VTOB_HASH_CODE(m)	\
-	((((m_addr_t) (m)) >> SYM_MEM_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+	((((unsigned long)(m)) >> SYM_MEM_CLUSTER_SHIFT) & VTOB_HASH_MASK)
 
 /*
  *  Memory pool of a given kind.
@@ -1253,15 +1240,12 @@ typedef struct sym_m_vtob {	/* Virtual t
  */
 typedef struct sym_m_pool {
 	m_pool_ident_t	dev_dmat;	/* Identifies the pool (see above) */
-	m_addr_t (*get_mem_cluster)(struct sym_m_pool *);
+	void * (*get_mem_cluster)(struct sym_m_pool *);
 #ifdef	SYM_MEM_FREE_UNUSED
-	void (*free_mem_cluster)(struct sym_m_pool *, m_addr_t);
+	void (*free_mem_cluster)(struct sym_m_pool *, void *);
 #endif
 #define M_GET_MEM_CLUSTER()		mp->get_mem_cluster(mp)
 #define M_FREE_MEM_CLUSTER(p)		mp->free_mem_cluster(mp, p)
-#ifdef	SYM_HAVE_M_SPOOL
-	struct sym_m_spool	s;	/* OS specific data structure */
-#endif
 	int nump;
 	m_vtob_p vtob[VTOB_HASH_SIZE];
 	struct sym_m_pool *next;
@@ -1269,19 +1253,12 @@ typedef struct sym_m_pool {
 } *m_pool_p;
 
 /*
- *  Alloc and free non DMAable memory.
- */
-void sym_mfree_unlocked(void *ptr, int size, char *name);
-void *sym_calloc_unlocked(int size, char *name);
-
-/*
  *  Alloc, free and translate addresses to bus physical 
  *  for DMAable memory.
  */
-void *__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat, int size, char *name);
-void 
-__sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat, void *m,int size, char *name);
-u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m);
+void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name);
+void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name);
+dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m);
 
 /*
  * Verbs used by the driver code for DMAable memory handling.
@@ -1295,15 +1272,33 @@ u32 __vtobus_unlocked(m_pool_ident_t dev
 			__sym_mfree_dma(np->bus_dmat, _uvptv_(p), l, n)
 #define sym_calloc_dma(l, n)		_sym_calloc_dma(np, l, n)
 #define sym_mfree_dma(p, l, n)		_sym_mfree_dma(np, p, l, n)
-#define _vtobus(np, p)			__vtobus(np->bus_dmat, _uvptv_(p))
-#define vtobus(p)			_vtobus(np, p)
+#define vtobus(p)			__vtobus(np->bus_dmat, _uvptv_(p))
 
 /*
- *  Override some function names.
+ *  We have to provide the driver memory allocator with methods for 
+ *  it to maintain virtual to bus physical address translations.
  */
-#define PRINT_ADDR	sym_print_addr
-#define PRINT_TARGET	sym_print_target
-#define PRINT_LUN	sym_print_lun
-#define UDELAY		sym_udelay
+
+#define sym_m_pool_match(mp_id1, mp_id2)	(mp_id1 == mp_id2)
+
+static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+{
+	void *vaddr = NULL;
+	dma_addr_t baddr = 0;
+
+	vaddr = dma_alloc_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, &baddr,
+			GFP_ATOMIC);
+	if (vaddr) {
+		vbp->vaddr = vaddr;
+		vbp->baddr = baddr;
+	}
+	return vaddr;
+}
+
+static __inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+{
+	dma_free_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, vbp->vaddr,
+			vbp->baddr);
+}
 
 #endif /* SYM_HIPD_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c
--- a/drivers/scsi/sym53c8xx_2/sym_malloc.c
+++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c
@@ -66,7 +66,7 @@ static void *___sym_malloc(m_pool_p mp, 
 	int i = 0;
 	int s = (1 << SYM_MEM_SHIFT);
 	int j;
-	m_addr_t a;
+	void *a;
 	m_link_p h = mp->h;
 
 	if (size > SYM_MEM_CLUSTER_SIZE)
@@ -88,7 +88,7 @@ static void *___sym_malloc(m_pool_p mp, 
 		++j;
 		s <<= 1;
 	}
-	a = (m_addr_t) h[j].next;
+	a = h[j].next;
 	if (a) {
 		h[j].next = h[j].next->next;
 		while (j > i) {
@@ -101,7 +101,7 @@ static void *___sym_malloc(m_pool_p mp, 
 #ifdef DEBUG
 	printf("___sym_malloc(%d) = %p\n", size, (void *) a);
 #endif
-	return (void *) a;
+	return a;
 }
 
 /*
@@ -112,7 +112,7 @@ static void ___sym_mfree(m_pool_p mp, vo
 	int i = 0;
 	int s = (1 << SYM_MEM_SHIFT);
 	m_link_p q;
-	m_addr_t a, b;
+	unsigned long a, b;
 	m_link_p h = mp->h;
 
 #ifdef DEBUG
@@ -127,12 +127,12 @@ static void ___sym_mfree(m_pool_p mp, vo
 		++i;
 	}
 
-	a = (m_addr_t) ptr;
+	a = (unsigned long)ptr;
 
 	while (1) {
 		if (s == SYM_MEM_CLUSTER_SIZE) {
 #ifdef SYM_MEM_FREE_UNUSED
-			M_FREE_MEM_CLUSTER(a);
+			M_FREE_MEM_CLUSTER((void *)a);
 #else
 			((m_link_p) a)->next = h[i].next;
 			h[i].next = (m_link_p) a;
@@ -194,58 +194,40 @@ static void __sym_mfree(m_pool_p mp, voi
  *  With DMA abstraction, we use functions (methods), to 
  *  distinguish between non DMAable memory and DMAable memory.
  */
-static m_addr_t ___mp0_get_mem_cluster(m_pool_p mp)
+static void *___mp0_get_mem_cluster(m_pool_p mp)
 {
-	m_addr_t m = (m_addr_t) sym_get_mem_cluster();
+	void *m = sym_get_mem_cluster();
 	if (m)
 		++mp->nump;
 	return m;
 }
 
 #ifdef	SYM_MEM_FREE_UNUSED
-static void ___mp0_free_mem_cluster(m_pool_p mp, m_addr_t m)
+static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)
 {
 	sym_free_mem_cluster(m);
 	--mp->nump;
 }
-#endif
-
-#ifdef	SYM_MEM_FREE_UNUSED
-static struct sym_m_pool mp0 =
-	{NULL, ___mp0_get_mem_cluster, ___mp0_free_mem_cluster};
 #else
-static struct sym_m_pool mp0 =
-	{NULL, ___mp0_get_mem_cluster};
+#define ___mp0_free_mem_cluster NULL
 #endif
 
-/*
- * Actual memory allocation routine for non-DMAed memory.
- */
-void *sym_calloc_unlocked(int size, char *name)
-{
-	void *m;
-	m = __sym_calloc(&mp0, size, name);
-	return m;
-}
-
-/*
- *  Its counter-part.
- */
-void sym_mfree_unlocked(void *ptr, int size, char *name)
-{
-	__sym_mfree(&mp0, ptr, size, name);
-}
+static struct sym_m_pool mp0 = {
+	NULL,
+	___mp0_get_mem_cluster,
+	___mp0_free_mem_cluster
+};
 
 /*
  *  Methods that maintains DMAable pools according to user allocations.
  *  New pools are created on the fly when a new pool id is provided.
  *  They are deleted on the fly when they get emptied.
  */
-/* Get a memory cluster that matches the DMA contraints of a given pool */
-static m_addr_t ___get_dma_mem_cluster(m_pool_p mp)
+/* Get a memory cluster that matches the DMA constraints of a given pool */
+static void * ___get_dma_mem_cluster(m_pool_p mp)
 {
 	m_vtob_p vbp;
-	m_addr_t vaddr;
+	void *vaddr;
 
 	vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
 	if (!vbp)
@@ -257,16 +239,15 @@ static m_addr_t ___get_dma_mem_cluster(m
 		vbp->next = mp->vtob[hc];
 		mp->vtob[hc] = vbp;
 		++mp->nump;
-		return (m_addr_t) vaddr;
 	}
 	return vaddr;
 out_err:
-	return 0;
+	return NULL;
 }
 
 #ifdef	SYM_MEM_FREE_UNUSED
 /* Free a memory cluster and associated resources for DMA */
-static void ___free_dma_mem_cluster(m_pool_p mp, m_addr_t m)
+static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
 {
 	m_vtob_p *vbpp, vbp;
 	int hc = VTOB_HASH_CODE(m);
@@ -297,23 +278,17 @@ static __inline m_pool_p ___get_dma_pool
 /* Create a new memory DMAable pool (when fetch failed) */
 static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
 {
-	m_pool_p mp = NULL;
-
-	mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
+	m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
 	if (mp) {
 		mp->dev_dmat = dev_dmat;
-		if (!sym_m_create_dma_mem_tag(mp)) {
-			mp->get_mem_cluster = ___get_dma_mem_cluster;
+		mp->get_mem_cluster = ___get_dma_mem_cluster;
 #ifdef	SYM_MEM_FREE_UNUSED
-			mp->free_mem_cluster = ___free_dma_mem_cluster;
+		mp->free_mem_cluster = ___free_dma_mem_cluster;
 #endif
-			mp->next = mp0.next;
-			mp0.next = mp;
-			return mp;
-		}
+		mp->next = mp0.next;
+		mp0.next = mp;
+		return mp;
 	}
-	if (mp)
-		__sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL");
 	return NULL;
 }
 
@@ -327,68 +302,81 @@ static void ___del_dma_pool(m_pool_p p)
 		pp = &(*pp)->next;
 	if (*pp) {
 		*pp = (*pp)->next;
-		sym_m_delete_dma_mem_tag(p);
 		__sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
 	}
 }
 #endif
 
+/* This lock protects only the memory allocation/free.  */
+static DEFINE_SPINLOCK(sym53c8xx_lock);
+
 /*
  *  Actual allocator for DMAable memory.
  */
-void *__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat, int size, char *name)
+void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
 {
+	unsigned long flags;
 	m_pool_p mp;
 	void *m = NULL;
 
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
 	mp = ___get_dma_pool(dev_dmat);
 	if (!mp)
 		mp = ___cre_dma_pool(dev_dmat);
-	if (mp)
-		m = __sym_calloc(mp, size, name);
+	if (!mp)
+		goto out;
+	m = __sym_calloc(mp, size, name);
 #ifdef	SYM_MEM_FREE_UNUSED
-	if (mp && !mp->nump)
+	if (!mp->nump)
 		___del_dma_pool(mp);
 #endif
 
+ out:
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
 	return m;
 }
 
-/*
- *  Its counter-part.
- */
-void 
-__sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat, void *m, int size, char *name)
+void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
 {
+	unsigned long flags;
 	m_pool_p mp;
 
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
 	mp = ___get_dma_pool(dev_dmat);
-	if (mp)
-		__sym_mfree(mp, m, size, name);
+	if (!mp)
+		goto out;
+	__sym_mfree(mp, m, size, name);
 #ifdef	SYM_MEM_FREE_UNUSED
-	if (mp && !mp->nump)
+	if (!mp->nump)
 		___del_dma_pool(mp);
 #endif
+ out:
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
 }
 
 /*
  *  Actual virtual to bus physical address translator 
  *  for 32 bit addressable DMAable memory.
  */
-u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m)
+dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
 {
+	unsigned long flags;
 	m_pool_p mp;
 	int hc = VTOB_HASH_CODE(m);
 	m_vtob_p vp = NULL;
-	m_addr_t a = ((m_addr_t) m) & ~SYM_MEM_CLUSTER_MASK;
+	void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);
+	dma_addr_t b;
 
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
 	mp = ___get_dma_pool(dev_dmat);
 	if (mp) {
 		vp = mp->vtob[hc];
-		while (vp && (m_addr_t) vp->vaddr != a)
+		while (vp && vp->vaddr != a)
 			vp = vp->next;
 	}
 	if (!vp)
 		panic("sym: VTOBUS FAILED!\n");
-	return (u32)(vp ? vp->baddr + (((m_addr_t) m) - a) : 0);
+	b = vp->baddr + (m - a);
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
+	return b;
 }
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.c b/drivers/scsi/sym53c8xx_2/sym_misc.c
deleted file mode 100644
--- a/drivers/scsi/sym53c8xx_2/sym_misc.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
- * of PCI-SCSI IO processors.
- *
- * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
- *
- * This driver is derived from the Linux sym53c8xx driver.
- * Copyright (C) 1998-2000  Gerard Roudier
- *
- * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
- * a port of the FreeBSD ncr driver to Linux-1.2.13.
- *
- * The original ncr driver has been written for 386bsd and FreeBSD by
- *         Wolfgang Stanglmeier        <wolf@cologne.de>
- *         Stefan Esser                <se@mi.Uni-Koeln.de>
- * Copyright (C) 1994  Wolfgang Stanglmeier
- *
- * Other major contributions:
- *
- * NVRAM detection and reading.
- * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
- *
- *-----------------------------------------------------------------------------
- *
- * This program is free software; you can redistribute it 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 "sym_glue.h"
-
-#ifdef	SYM_OPT_ANNOUNCE_TRANSFER_RATE
-/*
- *  Announce transfer rate if anything changed since last announcement.
- */
-void sym_announce_transfer_rate(struct sym_hcb *np, int target)
-{
-	tcb_p tp = &np->target[target];
-
-#define __tprev	tp->tinfo.prev
-#define __tcurr	tp->tinfo.curr
-
-	if (__tprev.options  == __tcurr.options &&
-	    __tprev.width    == __tcurr.width   &&
-	    __tprev.offset   == __tcurr.offset  &&
-	    !(__tprev.offset && __tprev.period != __tcurr.period))
-		return;
-
-	__tprev.options  = __tcurr.options;
-	__tprev.width    = __tcurr.width;
-	__tprev.offset   = __tcurr.offset;
-	__tprev.period   = __tcurr.period;
-
-	if (__tcurr.offset && __tcurr.period) {
-		u_int period, f10, mb10;
-		char *scsi;
-
-		period = f10 = mb10 = 0;
-		scsi = "FAST-5";
-
-		if (__tcurr.period <= 9) {
-			scsi = "FAST-80";
-			period = 125;
-			mb10 = 1600;
-		}
-		else {
-			if	(__tcurr.period <= 11) {
-				scsi = "FAST-40";
-				period = 250;
-				if (__tcurr.period == 11)
-					period = 303;
-			}
-			else if	(__tcurr.period < 25) {
-				scsi = "FAST-20";
-				if (__tcurr.period == 12)
-					period = 500;
-			}
-			else if	(__tcurr.period <= 50) {
-				scsi = "FAST-10";
-			}
-			if (!period)
-				period = 40 * __tcurr.period;
-			f10 = 100000 << (__tcurr.width ? 1 : 0);
-			mb10 = (f10 + period/2) / period;
-		}
-		printf_info (
-		    "%s:%d: %s %sSCSI %d.%d MB/s %s%s%s (%d.%d ns, offset %d)\n",
-		    sym_name(np), target, scsi, __tcurr.width? "WIDE " : "",
-		    mb10/10, mb10%10,
-		    (__tcurr.options & PPR_OPT_DT) ? "DT" : "ST",
-		    (__tcurr.options & PPR_OPT_IU) ? " IU" : "",
-		    (__tcurr.options & PPR_OPT_QAS) ? " QAS" : "",
-		    period/10, period%10, __tcurr.offset);
-	}
-	else
-		printf_info ("%s:%d: %sasynchronous.\n", 
-		             sym_name(np), target, __tcurr.width? "wide " : "");
-}
-#undef __tprev
-#undef __tcurr
-#endif	/* SYM_OPT_ANNOUNCE_TRANSFER_RATE */
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.c
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c
@@ -47,7 +47,7 @@ static u_char Tekram_boot_delay[7] = {3,
 /*
  *  Get host setup from NVRAM.
  */
-void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram)
+void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
 {
 	/*
 	 *  Get parity checking, host ID, verbose mode 
@@ -61,7 +61,7 @@ void sym_nvram_setup_host(struct sym_hcb
 		if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
 			np->verbose += 1;
 		if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
-			np->usrflags |= SYM_SCAN_TARGETS_HILO;
+			shost->reverse_ordering = 1;
 		if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
 			np->usrflags |= SYM_AVOID_BUS_RESET;
 		break;
@@ -253,7 +253,7 @@ static void sym_display_Tekram_nvram(str
 static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 
 			  int bit_mode)
 {
-	UDELAY (5);
+	udelay(5);
 	switch (bit_mode) {
 	case SET_BIT:
 		*gpreg |= write_bit;
@@ -269,8 +269,8 @@ static void S24C16_set_bit(struct sym_de
 		break;
 
 	}
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (5);
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(5);
 }
 
 /*
@@ -303,7 +303,7 @@ static void S24C16_do_bit(struct sym_dev
 	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
 	S24C16_set_bit(np, 0, gpreg, SET_CLK);
 	if (read_bit)
-		*read_bit = INB (nc_gpreg);
+		*read_bit = INB(np, nc_gpreg);
 	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
 	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
 }
@@ -315,9 +315,9 @@ static void S24C16_do_bit(struct sym_dev
 static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 
 			    u_char *gpcntl)
 {
-	OUTB (nc_gpcntl, *gpcntl & 0xfe);
+	OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
 	S24C16_do_bit(np, NULL, write_bit, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
+	OUTB(np, nc_gpcntl, *gpcntl);
 }
 
 /*
@@ -327,9 +327,9 @@ static void S24C16_write_ack(struct sym_
 static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 
 			   u_char *gpcntl)
 {
-	OUTB (nc_gpcntl, *gpcntl | 0x01);
+	OUTB(np, nc_gpcntl, *gpcntl | 0x01);
 	S24C16_do_bit(np, read_bit, 1, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
+	OUTB(np, nc_gpcntl, *gpcntl);
 }
 
 /*
@@ -379,13 +379,13 @@ static int sym_write_S24C16_nvram(struct
 	int	x;
 
 	/* save current state of GPCNTL and GPREG */
-	old_gpreg	= INB (nc_gpreg);
-	old_gpcntl	= INB (nc_gpcntl);
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
 	gpcntl		= old_gpcntl & 0x1c;
 
 	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
-	OUTB (nc_gpreg,  old_gpreg);
-	OUTB (nc_gpcntl, gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, gpcntl);
 
 	/* this is to set NVRAM into a known state with GPIO0/1 both low */
 	gpreg = old_gpreg;
@@ -414,8 +414,8 @@ static int sym_write_S24C16_nvram(struct
 	}
 
 	/* return GPIO0/1 to original states after having accessed NVRAM */
-	OUTB (nc_gpcntl, old_gpcntl);
-	OUTB (nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
 
 	return 0;
 }
@@ -433,13 +433,13 @@ static int sym_read_S24C16_nvram(struct 
 	int	x;
 
 	/* save current state of GPCNTL and GPREG */
-	old_gpreg	= INB (nc_gpreg);
-	old_gpcntl	= INB (nc_gpcntl);
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
 	gpcntl		= old_gpcntl & 0x1c;
 
 	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
-	OUTB (nc_gpreg,  old_gpreg);
-	OUTB (nc_gpcntl, gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, gpcntl);
 
 	/* this is to set NVRAM into a known state with GPIO0/1 both low */
 	gpreg = old_gpreg;
@@ -475,7 +475,7 @@ static int sym_read_S24C16_nvram(struct 
 
 	/* now set up GPIO0 for inputting data */
 	gpcntl |= 0x01;
-	OUTB (nc_gpcntl, gpcntl);
+	OUTB(np, nc_gpcntl, gpcntl);
 		
 	/* input all requested data - only part of total NVRAM */
 	for (x = 0; x < len; x++) 
@@ -483,13 +483,13 @@ static int sym_read_S24C16_nvram(struct 
 
 	/* finally put NVRAM back in inactive mode */
 	gpcntl &= 0xfe;
-	OUTB (nc_gpcntl, gpcntl);
+	OUTB(np, nc_gpcntl, gpcntl);
 	S24C16_stop(np, &gpreg);
 	retv = 0;
 out:
 	/* return GPIO0/1 to original states after having accessed NVRAM */
-	OUTB (nc_gpcntl, old_gpcntl);
-	OUTB (nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
 
 	return retv;
 }
@@ -546,9 +546,9 @@ static int sym_read_Symbios_nvram(struct
  */
 static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
 {
-	OUTB (nc_gpreg, *gpreg | 0x04);
-	UDELAY (2);
-	OUTB (nc_gpreg, *gpreg);
+	OUTB(np, nc_gpreg, *gpreg | 0x04);
+	udelay(2);
+	OUTB(np, nc_gpreg, *gpreg);
 }
 
 /* 
@@ -556,9 +556,9 @@ static void T93C46_Clk(struct sym_device
  */
 static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
 {
-	UDELAY (2);
+	udelay(2);
 	T93C46_Clk(np, gpreg);
-	*read_bit = INB (nc_gpreg);
+	*read_bit = INB(np, nc_gpreg);
 }
 
 /*
@@ -573,8 +573,8 @@ static void T93C46_Write_Bit(struct sym_
 		
 	*gpreg |= 0x10;
 		
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(2);
 
 	T93C46_Clk(np, gpreg);
 }
@@ -585,8 +585,8 @@ static void T93C46_Write_Bit(struct sym_
 static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
 {
 	*gpreg &= 0xef;
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(2);
 
 	T93C46_Clk(np, gpreg);
 }
@@ -603,7 +603,7 @@ static void T93C46_Send_Command(struct s
 	for (x = 0; x < 9; x++)
 		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
 
-	*read_bit = INB (nc_gpreg);
+	*read_bit = INB(np, nc_gpreg);
 }
 
 /*
@@ -657,23 +657,23 @@ static int sym_read_T93C46_nvram(struct 
 	int retv = 1;
 
 	/* save current state of GPCNTL and GPREG */
-	old_gpreg	= INB (nc_gpreg);
-	old_gpcntl	= INB (nc_gpcntl);
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
 
 	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
 	   1/2/4 out */
 	gpreg = old_gpreg & 0xe9;
-	OUTB (nc_gpreg, gpreg);
+	OUTB(np, nc_gpreg, gpreg);
 	gpcntl = (old_gpcntl & 0xe9) | 0x09;
-	OUTB (nc_gpcntl, gpcntl);
+	OUTB(np, nc_gpcntl, gpcntl);
 
 	/* input all of NVRAM, 64 words */
 	retv = T93C46_Read_Data(np, (u_short *) nvram,
 				sizeof(*nvram) / sizeof(short), &gpreg);
 	
 	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
-	OUTB (nc_gpcntl, old_gpcntl);
-	OUTB (nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
 
 	return retv;
 }
@@ -755,3 +755,17 @@ int sym_read_nvram(struct sym_device *np
 	}
 	return nvp->type;
 }
+
+char *sym_nvram_type(struct sym_nvram *nvp)
+{
+	switch (nvp->type) {
+	case SYM_SYMBIOS_NVRAM:
+		return "Symbios NVRAM";
+	case SYM_TEKRAM_NVRAM:
+		return "Tekram NVRAM";
+	case SYM_PARISC_PDC:
+		return "PA-RISC Firmware";
+	default:
+		return "No NVRAM";
+	}
+}
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.h
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h
@@ -40,7 +40,7 @@
 #ifndef SYM_NVRAM_H
 #define SYM_NVRAM_H
 
-#include "sym_conf.h"
+#include "sym53c8xx.h"
 
 /*
  *	Symbios NVRAM data format
@@ -193,17 +193,22 @@ struct sym_nvram {
 };
 
 #if SYM_CONF_NVRAM_SUPPORT
-void sym_nvram_setup_host (struct sym_hcb *np, struct sym_nvram *nvram);
+void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram);
 void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp);
 int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp);
+char *sym_nvram_type(struct sym_nvram *nvp);
 #else
-static inline void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) { }
+static inline void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) { }
 static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { }
 static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
 {
 	nvp->type = 0;
 	return 0;
 }
+static inline char *sym_nvram_type(struct sym_nvram *nvp)
+{
+	return "No NVRAM";
+}
 #endif
 
 #endif /* SYM_NVRAM_H */
diff --git a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h
--- a/drivers/scsi/sym53c8xx_defs.h
+++ b/drivers/scsi/sym53c8xx_defs.h
@@ -314,9 +314,9 @@
 #define	writew_b2l	__raw_writew
 #define	writel_b2l	__raw_writel
 #define	readw_raw	__raw_readw
-#define	readl_raw(a)	__raw_readl((unsigned long)(a))
+#define	readl_raw	__raw_readl
 #define	writew_raw	__raw_writew
-#define	writel_raw(v,a)	__raw_writel(v,(unsigned long)(a))
+#define	writel_raw	__raw_writel
 #else	/* Other big-endian */
 #define	readw_l2b	readw
 #define	readl_l2b	readl
@@ -1281,34 +1281,34 @@ struct scr_tblsel {
 **	Messages
 */
 
-#define	M_COMPLETE	(0x00)
-#define	M_EXTENDED	(0x01)
-#define	M_SAVE_DP	(0x02)
-#define	M_RESTORE_DP	(0x03)
-#define	M_DISCONNECT	(0x04)
-#define	M_ID_ERROR	(0x05)
-#define	M_ABORT		(0x06)
-#define	M_REJECT	(0x07)
-#define	M_NOOP		(0x08)
-#define	M_PARITY	(0x09)
-#define	M_LCOMPLETE	(0x0a)
-#define	M_FCOMPLETE	(0x0b)
-#define	M_RESET		(0x0c)
-#define	M_ABORT_TAG	(0x0d)
-#define	M_CLEAR_QUEUE	(0x0e)
-#define	M_INIT_REC	(0x0f)
-#define	M_REL_REC	(0x10)
+#define	M_COMPLETE	COMMAND_COMPLETE
+#define	M_EXTENDED	EXTENDED_MESSAGE
+#define	M_SAVE_DP	SAVE_POINTERS
+#define	M_RESTORE_DP	RESTORE_POINTERS
+#define	M_DISCONNECT	DISCONNECT
+#define	M_ID_ERROR	INITIATOR_ERROR
+#define	M_ABORT		ABORT_TASK_SET
+#define	M_REJECT	MESSAGE_REJECT
+#define	M_NOOP		NOP
+#define	M_PARITY	MSG_PARITY_ERROR
+#define	M_LCOMPLETE	LINKED_CMD_COMPLETE
+#define	M_FCOMPLETE	LINKED_FLG_CMD_COMPLETE
+#define	M_RESET		TARGET_RESET
+#define	M_ABORT_TAG	ABORT_TASK
+#define	M_CLEAR_QUEUE	CLEAR_TASK_SET
+#define	M_INIT_REC	INITIATE_RECOVERY
+#define	M_REL_REC	RELEASE_RECOVERY
 #define	M_TERMINATE	(0x11)
-#define	M_SIMPLE_TAG	(0x20)
-#define	M_HEAD_TAG	(0x21)
-#define	M_ORDERED_TAG	(0x22)
-#define	M_IGN_RESIDUE	(0x23)
+#define	M_SIMPLE_TAG	SIMPLE_QUEUE_TAG
+#define	M_HEAD_TAG	HEAD_OF_QUEUE_TAG
+#define	M_ORDERED_TAG	ORDERED_QUEUE_TAG
+#define	M_IGN_RESIDUE	IGNORE_WIDE_RESIDUE
 #define	M_IDENTIFY   	(0x80)
 
-#define	M_X_MODIFY_DP	(0x00)
-#define	M_X_SYNC_REQ	(0x01)
-#define	M_X_WIDE_REQ	(0x03)
-#define	M_X_PPR_REQ	(0x04)
+#define	M_X_MODIFY_DP	EXTENDED_MODIFY_DATA_POINTER
+#define	M_X_SYNC_REQ	EXTENDED_SDTR
+#define	M_X_WIDE_REQ	EXTENDED_WDTR
+#define	M_X_PPR_REQ	EXTENDED_PPR
 
 /*
 **	Status
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -259,7 +259,7 @@ static struct ultrastor_config
 } config = {0};
 
 /* Set this to 1 to reset the SCSI bus on error.  */
-int ultrastor_bus_reset;
+static int ultrastor_bus_reset;
 
 
 /* Allowed BIOS base addresses (NULL indicates reserved) */
@@ -945,7 +945,7 @@ static int ultrastor_abort(Scsi_Cmnd *SC
 	       config.mscp[mscp_index].SCint, SCpnt);
 #endif
     if (config.mscp[mscp_index].SCint == 0)
-	return SCSI_ABORT_NOT_RUNNING;
+	return FAILED;
 
     if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
     config.mscp[mscp_index].SCint = NULL;
@@ -1020,7 +1020,7 @@ static int ultrastor_host_reset(Scsi_Cmn
 #endif
 
     spin_unlock_irqrestore(host->host_lock, flags);
-    return SCSI_RESET_SUCCESS;
+    return SUCCESS;
 
 }
 
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -88,31 +88,30 @@ zalon_probe(struct parisc_device *dev)
 	struct gsc_irq gsc_irq;
 	u32 zalon_vers;
 	int error = -ENODEV;
-	unsigned long zalon = dev->hpa;
-	unsigned long io_port = zalon + GSC_SCSI_ZALON_OFFSET;
+	void __iomem *zalon = ioremap(dev->hpa, 4096);
+	void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET;
 	static int unit = 0;
 	struct Scsi_Host *host;
 	struct ncr_device device;
 
 	__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND);
 	while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY))
-		;
+		cpu_relax();
 	__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;
+	zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07;
 
 	/* Setup the interrupts first.
 	** Later on request_irq() will register the handler.
 	*/
 	dev->irq = gsc_alloc_irq(&gsc_irq);
 
-	printk("%s: Zalon vers field is 0x%x, IRQ %d\n", __FUNCTION__,
+	printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __FUNCTION__,
 		zalon_vers, dev->irq);
 
-	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, dev->hpa + IO_MODULE_EIM);
+	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM);
 
 	if (zalon_vers == 0)
 		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__);
@@ -120,16 +119,16 @@ zalon_probe(struct parisc_device *dev)
 	memset(&device, 0, sizeof(struct ncr_device));
 
 	/* The following three are needed before any other access. */
-	writeb(0x20, io_port + 0x38); /* DCNTL_REG,  EA  */
-	writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */
-	writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */
+	__raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG,  EA  */
+	__raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */
+	__raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */
 
 	/* Initialise ncr_device structure with items required by ncr_attach. */
 	device.chip		= zalon720_chip;
 	device.host_id		= 7;
 	device.dev		= &dev->dev;
-	device.slot.base	= (u_long)io_port;
-	device.slot.base_c	= (u_long)io_port;
+	device.slot.base	= dev->hpa + GSC_SCSI_ZALON_OFFSET;
+	device.slot.base_v	= io_port;
 	device.slot.irq		= dev->irq;
 	device.differential	= 2;
 
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -110,7 +110,7 @@ static irqreturn_t serial21285_rx_chars(
 		port->icount.rx++;
 
 		rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
-		if (rxs & RXSTAT_ANYERR) {
+		if (unlikely(rxs & RXSTAT_ANYERR)) {
 			if (rxs & RXSTAT_PARITY)
 				port->icount.parity++;
 			else if (rxs & RXSTAT_FRAME)
@@ -126,23 +126,12 @@ static irqreturn_t serial21285_rx_chars(
 				flag = TTY_FRAME;
 		}
 
-		if ((rxs & port->ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((rxs & RXSTAT_OVERRUN) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+		uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
+
 		status = *CSR_UARTFLG;
 	}
 	tty_flip_buffer_push(tty);
 
- out:
 	return IRQ_HANDLED;
 }
 
@@ -383,11 +372,9 @@ static struct uart_ops serial21285_ops =
 };
 
 static struct uart_port serial21285_port = {
-	.membase	= 0,
 	.mapbase	= 0x42000160,
 	.iotype		= SERIAL_IO_MEM,
 	.irq		= NO_IRQ,
-	.uartclk	= 0,
 	.fifosize	= 16,
 	.ops		= &serial21285_ops,
 	.flags		= ASYNC_BOOT_AUTOCONF,
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -1055,28 +1055,23 @@ static int rs_ioctl(struct tty_struct *t
 				 (arg ? CLOCAL : 0));
 			return 0;
 		case TIOCGSERIAL:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct));
-			if (error)
-				return error;
-			return get_serial_info(info,
+			if (access_ok(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct)))
+				return get_serial_info(info,
 					       (struct serial_struct *) arg);
+			return -EFAULT;
 		case TIOCSSERIAL:
 			return set_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return get_lsr_info(info, (unsigned int *) arg);
-
+			if (access_ok(VERIFY_WRITE, (void *) arg,
+						sizeof(unsigned int));
+				return get_lsr_info(info, (unsigned int *) arg);
+			return -EFAULT;
 		case TIOCSERGSTRUCT:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct m68k_serial));
-			if (error)
-				return error;
+			if (!access_ok(VERIFY_WRITE, (void *) arg,
+						sizeof(struct m68k_serial)))
+				return -EFAULT;
 			copy_to_user((struct m68k_serial *) arg,
 				    info, sizeof(struct m68k_serial));
 			return 0;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -51,7 +51,7 @@
  *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
  *                is unsafe when used on edge-triggered interrupts.
  */
-unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 /*
  * Debugging.
@@ -261,7 +261,7 @@ static const struct serial8250_config ua
 		.fifo_size	= 32,
 		.tx_loadsz	= 32,
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-		.flags		= UART_CAP_FIFO,
+		.flags		= UART_CAP_FIFO | UART_CAP_UUE,
 	},
 };
 
@@ -642,6 +642,7 @@ static int broken_efr(struct uart_8250_p
 static void autoconfig_16550a(struct uart_8250_port *up)
 {
 	unsigned char status1, status2;
+	unsigned int iersave;
 
 	up->port.type = PORT_16550A;
 	up->capabilities |= UART_CAP_FIFO;
@@ -681,8 +682,6 @@ static void autoconfig_16550a(struct uar
 	 * from EXCR1. Switch back to bank 0, change it in MCR. Then
 	 * switch back to bank 2, read it from EXCR1 again and check
 	 * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
-	 * On PowerPC we don't want to change baud_base, as we have
-	 * a number of different divisors.  -- Tom Rini
 	 */
 	serial_outp(up, UART_LCR, 0);
 	status1 = serial_in(up, UART_MCR);
@@ -698,16 +697,25 @@ static void autoconfig_16550a(struct uar
 		serial_outp(up, UART_MCR, status1);
 
 		if ((status2 ^ status1) & UART_MCR_LOOP) {
-#ifndef CONFIG_PPC
+			unsigned short quot;
+
 			serial_outp(up, UART_LCR, 0xE0);
+
+			quot = serial_inp(up, UART_DLM) << 8;
+			quot += serial_inp(up, UART_DLL);
+			quot <<= 3;
+
 			status1 = serial_in(up, 0x04); /* EXCR1 */
 			status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
 			status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
 			serial_outp(up, 0x04, status1);
+			
+			serial_outp(up, UART_DLL, quot & 0xff);
+			serial_outp(up, UART_DLM, quot >> 8);
+
 			serial_outp(up, UART_LCR, 0);
-			up->port.uartclk = 921600*16;
-#endif
 
+			up->port.uartclk = 921600*16;
 			up->port.type = PORT_NS16550A;
 			up->capabilities |= UART_NATSEMI;
 			return;
@@ -728,6 +736,7 @@ static void autoconfig_16550a(struct uar
 	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 	status2 = serial_in(up, UART_IIR) >> 5;
 	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_outp(up, UART_LCR, 0);
 
 	DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
 
@@ -736,6 +745,41 @@ static void autoconfig_16550a(struct uar
 		up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
 		return;
 	}
+
+	/*
+	 * Try writing and reading the UART_IER_UUE bit (b6).
+	 * If it works, this is probably one of the Xscale platform's
+	 * internal UARTs.
+	 * We're going to explicitly set the UUE bit to 0 before
+	 * trying to write and read a 1 just to make sure it's not
+	 * already a 1 and maybe locked there before we even start start.
+	 */
+	iersave = serial_in(up, UART_IER);
+	serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
+	if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
+		/*
+		 * OK it's in a known zero state, try writing and reading
+		 * without disturbing the current state of the other bits.
+		 */
+		serial_outp(up, UART_IER, iersave | UART_IER_UUE);
+		if (serial_in(up, UART_IER) & UART_IER_UUE) {
+			/*
+			 * It's an Xscale.
+			 * We'll leave the UART_IER_UUE bit set to 1 (enabled).
+			 */
+			DEBUG_AUTOCONF("Xscale ");
+			up->port.type = PORT_XSCALE;
+			up->capabilities |= UART_CAP_UUE;
+			return;
+		}
+	} else {
+		/*
+		 * If we got here we couldn't force the IER_UUE bit to 0.
+		 * Log it and continue.
+		 */
+		DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
+	}
+	serial_outp(up, UART_IER, iersave);
 }
 
 /*
@@ -1028,8 +1072,10 @@ receive_chars(struct uart_8250_port *up,
 				tty_flip_buffer_push(tty);
 				spin_lock(&up->port.lock);
 			}
-			/* If this failed then we will throw away the
-			   bytes but must do so to clear interrupts */
+			/*
+			 * If this failed then we will throw away the
+			 * bytes but must do so to clear interrupts
+			 */
 		}
 		ch = serial_inp(up, UART_RX);
 		flag = TTY_NORMAL;
@@ -1069,7 +1115,7 @@ receive_chars(struct uart_8250_port *up,
 				up->port.icount.overrun++;
 
 			/*
-			 * Mask off conditions which should be ingored.
+			 * Mask off conditions which should be ignored.
 			 */
 			lsr &= up->port.read_status_mask;
 
@@ -1083,18 +1129,9 @@ receive_chars(struct uart_8250_port *up,
 		}
 		if (uart_handle_sysrq_char(&up->port, ch, regs))
 			goto ignore_char;
-		if ((lsr & up->port.ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((lsr & UART_LSR_OE) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+
+		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+
 	ignore_char:
 		lsr = serial_inp(up, UART_LSR);
 	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
@@ -1714,7 +1751,7 @@ serial8250_set_termios(struct uart_port 
 	up->ier &= ~UART_IER_MSI;
 	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
 		up->ier |= UART_IER_MSI;
-	if (up->port.type == PORT_XSCALE)
+	if (up->capabilities & UART_CAP_UUE)
 		up->ier |= UART_IER_UUE | UART_IER_RTOIE;
 
 	serial_out(up, UART_IER, up->ier);
@@ -2083,7 +2120,7 @@ serial8250_console_write(struct console 
 	 */
 	ier = serial_in(up, UART_IER);
 
-	if (up->port.type == PORT_XSCALE)
+	if (up->capabilities & UART_CAP_UUE)
 		serial_out(up, UART_IER, UART_IER_UUE);
 	else
 		serial_out(up, UART_IER, 0);
@@ -2157,14 +2194,6 @@ static int __init serial8250_console_ini
 }
 console_initcall(serial8250_console_init);
 
-static int __init serial8250_late_console_init(void)
-{
-	if (!(serial8250_console.flags & CON_ENABLED))
-		register_console(&serial8250_console);
-	return 0;
-}
-late_initcall(serial8250_late_console_init);
-
 static int __init find_port(struct uart_port *p)
 {
 	int line;
@@ -2296,7 +2325,7 @@ static int __devexit serial8250_remove(s
 	return 0;
 }
 
-static int serial8250_suspend(struct device *dev, u32 state, u32 level)
+static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	int i;
 
@@ -2352,26 +2381,6 @@ static struct platform_device *serial825
  */
 static DECLARE_MUTEX(serial_sem);
 
-/*
- *	Are the two ports equivalent?
- */
-static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
-{
-	if (port1->iotype != port2->iotype)
-		return 0;
-
-	switch (port1->iotype) {
-	case UPIO_PORT:
-		return (port1->iobase == port2->iobase);
-	case UPIO_HUB6:
-		return (port1->iobase == port2->iobase) &&
-		       (port1->hub6   == port2->hub6);
-	case UPIO_MEM:
-		return (port1->membase == port2->membase);
-	}
-	return 0;
-}
-
 static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
 {
 	int i;
@@ -2561,6 +2570,9 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
  *	If this fails an error is returned.
  *
  *	On success the port is ready to use and the line number is returned.
+ *
+ *	Note: this function is deprecated - use serial8250_register_port
+ *	instead.
  */
 int register_serial(struct serial_struct *req)
 {
@@ -2615,6 +2627,9 @@ EXPORT_SYMBOL(register_serial);
  *
  *	Remove one serial port.  This may not be called from interrupt
  *	context.  We hand the port back to our local PM control.
+ *
+ *	Note: this function is deprecated - use serial8250_unregister_port
+ *	instead.
  */
 void unregister_serial(int line)
 {
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -49,14 +49,9 @@ struct serial8250_config {
 #define UART_CAP_EFR	(1 << 9)	/* UART has EFR */
 #define UART_CAP_SLEEP	(1 << 10)	/* UART has IER sleep */
 #define UART_CAP_AFE	(1 << 11)	/* MCR-based hw flow control */
-
-#undef SERIAL_DEBUG_PCI
+#define UART_CAP_UUE	(1 << 12)	/* UART needs IER bit 6 set (Xscale) */
 
 #if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
-#define SERIAL_INLINE
-#endif
-  
-#ifdef SERIAL_INLINE
 #define _INLINE_ inline
 #else
 #define _INLINE_
@@ -80,6 +75,13 @@ struct serial8250_config {
  * is cleared, the machine locks up with endless interrupts.
  */
 #define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#elif defined(CONFIG_SBC8560)
+/*
+ * WindRiver did something similarly broken on their SBC8560 board. The
+ * UART tristates its IRQ output while OUT2 is clear, but they pulled
+ * the interrupt line _up_ instead of down, so if we register the IRQ
+ * while the UART is in that state, we die in an IRQ storm. */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
 #else
 #define ALPHA_KLUDGE_MCR 0
 #endif
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
--- a/drivers/serial/8250_hp300.c
+++ b/drivers/serial/8250_hp300.c
@@ -9,15 +9,15 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/tty.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/serial_core.h>
 #include <linux/delay.h>
 #include <linux/dio.h>
 #include <linux/console.h>
 #include <asm/io.h>
 
+#include "8250.h"
+
 #if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
 #warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
 #endif
@@ -163,7 +163,7 @@ int __init hp300_setup_serial_console(vo
 static int __devinit hpdca_init_one(struct dio_dev *d,
                                 const struct dio_device_id *ent)
 {
-	struct serial_struct serial_req;
+	struct uart_port port;
 	int line;
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
@@ -172,21 +172,22 @@ static int __devinit hpdca_init_one(stru
 		return 0;
 	}
 #endif
-	memset(&serial_req, 0, sizeof(struct serial_struct));
+	memset(&port, 0, sizeof(struct uart_port));
 
 	/* Memory mapped I/O */
-	serial_req.io_type = SERIAL_IO_MEM;
-	serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-	serial_req.irq = d->ipl;
-	serial_req.baud_base = HPDCA_BAUD_BASE;
-	serial_req.iomap_base = (d->resource.start + UART_OFFSET);
-	serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
-	serial_req.iomem_reg_shift = 1;
-	line = register_serial(&serial_req);
+	port.iotype = UPIO_MEM;
+	port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+	port.irq = d->ipl;
+	port.uartclk = HPDCA_BAUD_BASE * 16;
+	port.mapbase = (d->resource.start + UART_OFFSET);
+	port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+	port.regshift = 1;
+	port.dev = &d->dev;
+	line = serial8250_register_port(&port);
 
 	if (line < 0) {
 		printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
-		       " irq %d failed\n", d->scode, serial_req.irq);
+		       " irq %d failed\n", d->scode, port.irq);
 		return -ENOMEM;
 	}
 
@@ -209,7 +210,7 @@ static int __init hp300_8250_init(void)
 #ifdef CONFIG_HPAPCI
 	int line;
 	unsigned long base;
-	struct serial_struct serial_req;
+	struct uart_port uport;
 	struct hp300_port *port;
 	int i;
 #endif
@@ -251,25 +252,25 @@ static int __init hp300_8250_init(void)
 		if (!port)
 			return -ENOMEM;
 
-		memset(&serial_req, 0, sizeof(struct serial_struct));
+		memset(&uport, 0, sizeof(struct uart_port));
 
 		base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
 
 		/* Memory mapped I/O */
-		serial_req.io_type = SERIAL_IO_MEM;
-		serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+		uport.iotype = UPIO_MEM;
+		uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
 		/* XXX - no interrupt support yet */
-		serial_req.irq = 0;
-		serial_req.baud_base = HPAPCI_BAUD_BASE;
-		serial_req.iomap_base = base;
-		serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
-		serial_req.iomem_reg_shift = 2;
+		uport.irq = 0;
+		uport.uartclk = HPAPCI_BAUD_BASE * 16;
+		uport.mapbase = base;
+		uport.membase = (char *)(base + DIO_VIRADDRBASE);
+		uport.regshift = 2;
 
-		line = register_serial(&serial_req);
+		line = serial8250_register_port(&uport);
 
 		if (line < 0) {
 			printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
-			       " irq %d failed\n", i, serial_req.irq);
+			       " irq %d failed\n", i, uport.irq);
 			kfree(port);
 			continue;
 		}
@@ -299,7 +300,7 @@ static void __devexit hpdca_remove_one(s
 		/* Disable board-interrupts */
 		out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
 	}
-	unregister_serial(line);
+	serial8250_unregister_port(line);
 }
 #endif
 
@@ -309,7 +310,7 @@ static void __exit hp300_8250_exit(void)
 	struct hp300_port *port, *to_free;
 
 	for (port = hp300_ports; port; ) {
-		unregister_serial(port->line);
+		serial8250_unregister_port(port->line);
 		to_free = port;
 		port = port->next;
 		kfree(to_free);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -31,6 +31,8 @@
 
 #include "8250.h"
 
+#undef SERIAL_DEBUG_PCI
+
 /*
  * Definitions for PCI support.
  */
@@ -577,6 +579,16 @@ static int __devinit pci_xircom_init(str
 	return 0;
 }
 
+static int __devinit pci_netmos_init(struct pci_dev *dev)
+{
+	/* subdevice 0x00PS means <P> parallel, <S> serial */
+	unsigned int num_serial = dev->subsystem_device & 0xf;
+
+	if (num_serial == 0)
+		return -ENODEV;
+	return num_serial;
+}
+
 static int
 pci_default_setup(struct pci_dev *dev, struct pci_board *board,
 		  struct uart_port *port, int idx)
@@ -934,6 +946,17 @@ static struct pci_serial_quirk pci_seria
 		.setup		= pci_default_setup,
 	},
 	/*
+	 * Netmos cards
+	 */
+	{
+		.vendor		= PCI_VENDOR_ID_NETMOS,
+		.device		= PCI_ANY_ID,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.init		= pci_netmos_init,
+		.setup		= pci_default_setup,
+	},
+	/*
 	 * Default "match everything" terminator entry
 	 */
 	{
@@ -986,6 +1009,8 @@ get_pci_irq(struct pci_dev *dev, struct 
  *  n    = number of serial ports
  *  baud = baud rate
  *
+ * This table is sorted by (in order): baud, bt, bn, n.
+ *
  * Please note: in theory if n = 1, _bt infix should make no difference.
  * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
  */
@@ -1759,7 +1784,7 @@ static void __devexit pciserial_remove_o
 	}
 }
 
-static int pciserial_suspend_one(struct pci_dev *dev, u32 state)
+static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
 {
 	struct serial_private *priv = pci_get_drvdata(dev);
 
@@ -1769,6 +1794,8 @@ static int pciserial_suspend_one(struct 
 		for (i = 0; i < priv->nr; i++)
 			serial8250_suspend_port(priv->line[i]);
 	}
+	pci_save_state(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
 	return 0;
 }
 
@@ -1776,10 +1803,18 @@ static int pciserial_resume_one(struct p
 {
 	struct serial_private *priv = pci_get_drvdata(dev);
 
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+
 	if (priv) {
 		int i;
 
 		/*
+		 * The device may have been disabled.  Re-enable it.
+		 */
+		pci_enable_device(dev);
+
+		/*
 		 * Ensure that the board is correctly configured.
 		 */
 		if (priv->quirk->init)
@@ -1867,6 +1902,9 @@ static struct pci_device_id serial_pci_t
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
 		pbn_b2_8_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_8_115200 },
 
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
@@ -2175,6 +2213,9 @@ static struct pci_device_id serial_pci_t
 	 * HP Diva card
 	 */
 	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+		PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
+		pbn_b1_1_115200 },
+	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_5_115200 },
 	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -615,7 +615,7 @@ config SERIAL_68360
 
 config SERIAL_PMACZILOG
 	tristate "PowerMac z85c30 ESCC support"
-	depends on PPC_OF
+	depends on PPC_OF && PPC_PMAC
 	select SERIAL_CORE
 	help
 	  This driver supports the Zilog z85C30 serial ports found on
@@ -810,4 +810,37 @@ config SERIAL_TXX9_STDSERIAL
 	bool "TX39XX/49XX SIO act as standard serial"
 	depends on !SERIAL_8250 && SERIAL_TXX9
 
+config SERIAL_VR41XX
+	tristate "NEC VR4100 series Serial Interface Unit support"
+	depends on CPU_VR41XX
+	select SERIAL_CORE
+	help
+	  If you have a NEC VR4100 series processor and you want to use
+	  Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
+	  (not include VR4111/VR4121 DSIU), say Y.  Otherwise, say N.
+
+config SERIAL_VR41XX_CONSOLE
+	bool "Enable NEC VR4100 series Serial Interface Unit console"
+	depends on SERIAL_VR41XX
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you have a NEC VR4100 series processor and you want to use
+	  a console on a serial port, say Y.  Otherwise, say N.
+
+config SERIAL_JSM
+        tristate "Digi International NEO PCI Support"
+	depends on PCI
+        select SERIAL_CORE
+        help
+          This is a driver for Digi International's Neo series
+          of cards which provide multiple serial ports. You would need
+          something like this to connect more than two modems to your Linux
+          box, for instance in order to become a dial-in server. This driver
+          supports PCI boards only.
+          If you have a card like this, say Y here and read the file
+          <file:Documentation/jsm.txt>.
+
+          To compile this driver as a module, choose M here: the
+          module will be called jsm.
+
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -48,4 +48,7 @@ obj-$(CONFIG_SERIAL_ICOM) += icom.o
 obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
 obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
+obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
+obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4_serial.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -172,7 +172,7 @@ pl010_rx_chars(struct uart_port *port)
 		 * out of the main execution path
 		 */
 		rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
-		if (rsr & UART01x_RSR_ANY) {
+		if (unlikely(rsr & UART01x_RSR_ANY)) {
 			if (rsr & UART01x_RSR_BE) {
 				rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
 				port->icount.brk++;
@@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port)
 		if (uart_handle_sysrq_char(port, ch, regs))
 			goto ignore_char;
 
-		if ((rsr & port->ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((rsr & UART01x_RSR_OE) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+		uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
+
 	ignore_char:
 		status = UART_GET_FR(port);
 	}
@@ -772,7 +762,7 @@ static int pl010_remove(struct amba_devi
 	return 0;
 }
 
-static int pl010_suspend(struct amba_device *dev, u32 state)
+static int pl010_suspend(struct amba_device *dev, pm_message_t state)
 {
 	struct uart_amba_port *uap = amba_get_drvdata(dev);
 
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -137,7 +137,7 @@ pl011_rx_chars(struct uart_amba_port *ua
 		 * out of the main execution path
 		 */
 		rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
-		if (rsr & UART01x_RSR_ANY) {
+		if (unlikely(rsr & UART01x_RSR_ANY)) {
 			if (rsr & UART01x_RSR_BE) {
 				rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
 				uap->port.icount.brk++;
@@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *ua
 		if (uart_handle_sysrq_char(&uap->port, ch, regs))
 			goto ignore_char;
 
-		if ((rsr & uap->port.ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((rsr & UART01x_RSR_OE) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+		uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
+
 	ignore_char:
 		status = readw(uap->port.membase + UART01x_FR);
 	}
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c
--- a/drivers/serial/au1x00_uart.c
+++ b/drivers/serial/au1x00_uart.c
@@ -320,7 +320,9 @@ receive_chars(struct uart_8250_port *up,
 	ignore_char:
 		*status = serial_inp(up, UART_LSR);
 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(tty);
+	spin_lock(&up->port.lock);
 }
 
 static _INLINE_ void transmit_chars(struct uart_8250_port *up)
@@ -1242,57 +1244,6 @@ static struct uart_driver serial8250_reg
 	.cons			= SERIAL8250_CONSOLE,
 };
 
-/*
- * register_serial and unregister_serial allows for 16x50 serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-
-static int __register_serial(struct serial_struct *req, int line)
-{
-	struct uart_port port;
-
-	port.iobase   = req->port;
-	port.membase  = req->iomem_base;
-	port.irq      = req->irq;
-	port.uartclk  = req->baud_base * 16;
-	port.fifosize = req->xmit_fifo_size;
-	port.regshift = req->iomem_reg_shift;
-	port.iotype   = req->io_type;
-	port.flags    = req->flags | UPF_BOOT_AUTOCONF;
-	port.mapbase  = req->iomap_base;
-	port.line     = line;
-
-	if (HIGH_BITS_OFFSET)
-		port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
-	/*
-	 * If a clock rate wasn't specified by the low level
-	 * driver, then default to the standard clock rate.
-	 */
-	if (port.uartclk == 0)
-		port.uartclk = BASE_BAUD * 16;
-
-	return uart_register_port(&serial8250_reg, &port);
-}
-
-/**
- *	register_serial - configure a 16x50 serial port at runtime
- *	@req: request structure
- *
- *	Configure the serial port specified by the request. If the
- *	port exists and is in use an error is returned. If the port
- *	is not currently in the table it is added.
- *
- *	The port is then probed and if necessary the IRQ is autodetected
- *	If this fails an error is returned.
- *
- *	On success the port is ready to use and the line number is returned.
- */
-int register_serial(struct serial_struct *req)
-{
-	return __register_serial(req, -1);
-}
-
 int __init early_serial_setup(struct uart_port *port)
 {
 	serial8250_isa_init_ports();
@@ -1302,18 +1253,6 @@ int __init early_serial_setup(struct uar
 }
 
 /**
- *	unregister_serial - remove a 16x50 serial port at runtime
- *	@line: serial line number
- *
- *	Remove one serial port.  This may be called from interrupt
- *	context.
- */
-void unregister_serial(int line)
-{
-	uart_unregister_port(&serial8250_reg, line);
-}
-
-/**
  *	serial8250_suspend_port - suspend one serial port
  *	@line:  serial line number
  *      @level: the level of port suspension, as per uart_suspend_port
@@ -1366,8 +1305,6 @@ static void __exit serial8250_exit(void)
 module_init(serial8250_init);
 module_exit(serial8250_exit);
 
-EXPORT_SYMBOL(register_serial);
-EXPORT_SYMBOL(unregister_serial);
 EXPORT_SYMBOL(serial8250_suspend_port);
 EXPORT_SYMBOL(serial8250_resume_port);
 
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -116,54 +116,40 @@ static irqreturn_t clps711xuart_int_rx(i
 		 * Note that the error handling code is
 		 * out of the main execution path
 		 */
-		if (ch & UART_ANY_ERR)
-			goto handle_error;
+		if (unlikely(ch & UART_ANY_ERR)) {
+			if (ch & UARTDR_PARERR)
+				port->icount.parity++;
+			else if (ch & UARTDR_FRMERR)
+				port->icount.frame++;
+			if (ch & UARTDR_OVERR)
+				port->icount.overrun++;
+
+			ch &= port->read_status_mask;
+
+			if (ch & UARTDR_PARERR)
+				flg = TTY_PARITY;
+			else if (ch & UARTDR_FRMERR)
+				flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+			port->sysrq = 0;
+#endif
+		}
 
 		if (uart_handle_sysrq_char(port, ch, regs))
 			goto ignore_char;
 
-	error_return:
-		tty_insert_flip_char(tty, ch, flg);
-	ignore_char:
-		status = clps_readl(SYSFLG(port));
-	}
- out:
-	tty_flip_buffer_push(tty);
-	return IRQ_HANDLED;
-
- handle_error:
-	if (ch & UARTDR_PARERR)
-		port->icount.parity++;
-	else if (ch & UARTDR_FRMERR)
-		port->icount.frame++;
-	if (ch & UARTDR_OVERR)
-		port->icount.overrun++;
-
-	if (ch & port->ignore_status_mask) {
-		if (++ignored > 100)
-			goto out;
-		goto ignore_char;
-	}
-	ch &= port->read_status_mask;
-
-	if (ch & UARTDR_PARERR)
-		flg = TTY_PARITY;
-	else if (ch & UARTDR_FRMERR)
-		flg = TTY_FRAME;
-
-	if (ch & UARTDR_OVERR) {
 		/*
 		 * CHECK: does overrun affect the current character?
 		 * ASSUMPTION: it does not.
 		 */
-		tty_insert_flip_char(tty, ch, flg);
-		ch = 0;
-		flg = TTY_OVERRUN;
+		uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+
+	ignore_char:
+		status = clps_readl(SYSFLG(port));
 	}
-#ifdef SUPPORT_SYSRQ
-	port->sysrq = 0;
-#endif
-	goto error_return;
+	tty_flip_buffer_push(tty);
+	return IRQ_HANDLED;
 }
 
 static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -864,6 +864,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SMC1_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.flags = FLAG_SMC,
 		.tx_nrfifos = TX_NUM_FIFO,
@@ -877,6 +878,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SMC2_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.flags = FLAG_SMC,
 		.tx_nrfifos = TX_NUM_FIFO,
@@ -893,6 +895,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SCC1_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -905,6 +908,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SCC2_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -917,6 +921,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SCC3_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -929,6 +934,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SCC4_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= SERIAL_IO_MEM,
+			.lock		= SPIN_LOCK_UNLOCKED,
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -3757,10 +3757,8 @@ rs_write(struct tty_struct * tty, int fr
 		e100_enable_rx_irq(info);
 #endif
 
-		if (info->rs485.delay_rts_before_send > 0) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
-		}
+		if (info->rs485.delay_rts_before_send > 0)
+			msleep(info->rs485.delay_rts_before_send);
 	}
 #endif /* CONFIG_ETRAX_RS485 */
 
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -22,6 +22,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
+ * [29-Mar-2005] Mike Lee
+ * Added hardware handshake
  */
 #include <linux/config.h>
 
@@ -319,18 +321,39 @@ static void imx_break_ctl(struct uart_po
 #define TXTL 2 /* reset default */
 #define RXTL 1 /* reset default */
 
+static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+{
+	unsigned int val;
+	unsigned int ufcr_rfdiv;
+
+	/* set receiver / transmitter trigger level.
+	 * RFDIV is set such way to satisfy requested uartclk value
+	 */
+	val = TXTL<<10 | RXTL;
+	ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
+
+	if(!ufcr_rfdiv)
+		ufcr_rfdiv = 1;
+
+	if(ufcr_rfdiv >= 7)
+		ufcr_rfdiv = 6;
+	else
+		ufcr_rfdiv = 6 - ufcr_rfdiv;
+
+	val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
+
+	UFCR((u32)sport->port.membase) = val;
+
+	return 0;
+}
+
 static int imx_startup(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
 	int retval;
-	unsigned int val;
 	unsigned long flags;
 
-	/* set receiver / transmitter trigger level. We assume
-	 * that RFDIV has been set by the arch setup or by the bootloader.
-	 */
-	val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV)  | TXTL<<10 | RXTL;
-	UFCR((u32)sport->port.membase) = val;
+	imx_setup_ufcr(sport, 0);
 
 	/* disable the DREN bit (Data Ready interrupt enable) before
 	 * requesting IRQs
@@ -428,6 +451,11 @@ imx_set_termios(struct uart_port *port, 
 	else
 		ucr2 = UCR2_SRST | UCR2_IRTS;
 
+	if (termios->c_cflag & CRTSCTS) {
+		ucr2 &= ~UCR2_IRTS;
+		ucr2 |= UCR2_CTSC;
+	}
+
 	if (termios->c_cflag & CSTOPB)
 		ucr2 |= UCR2_STPB;
 	if (termios->c_cflag & PARENB) {
@@ -730,9 +758,12 @@ static void __init
 imx_console_get_options(struct imx_port *sport, int *baud,
 			   int *parity, int *bits)
 {
+
 	if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
 		/* ok, the port was enabled */
 		unsigned int ucr2, ubir,ubmr, uartclk;
+		unsigned int baud_raw;
+		unsigned int ucfr_rfdiv;
 
 		ucr2 = UCR2((u32)sport->port.membase);
 
@@ -751,9 +782,35 @@ imx_console_get_options(struct imx_port 
 
 		ubir = UBIR((u32)sport->port.membase) & 0xffff;
 		ubmr = UBMR((u32)sport->port.membase) & 0xffff;
-		uartclk = sport->port.uartclk;
 
-		*baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1);
+
+		ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7;
+		if (ucfr_rfdiv == 6)
+			ucfr_rfdiv = 7;
+		else
+			ucfr_rfdiv = 6 - ucfr_rfdiv;
+
+		uartclk = imx_get_perclk1();
+		uartclk /= ucfr_rfdiv;
+
+		{	/*
+			 * The next code provides exact computation of
+			 *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
+			 * without need of float support or long long division,
+			 * which would be required to prevent 32bit arithmetic overflow
+			 */
+			unsigned int mul = ubir + 1;
+			unsigned int div = 16 * (ubmr + 1);
+			unsigned int rem = uartclk % div;
+
+			baud_raw = (uartclk / div) * mul;
+			baud_raw += (rem * mul + div / 2) / div;
+			*baud = (baud_raw + 50) / 100 * 100;
+		}
+
+		if(*baud != baud_raw)
+			printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
+				baud_raw, *baud);
 	}
 }
 
@@ -780,6 +837,8 @@ imx_console_setup(struct console *co, ch
 	else
 		imx_console_get_options(sport, &baud, &parity, &bits);
 
+	imx_setup_ufcr(sport, 0);
+
 	return uart_set_options(&sport->port, co, baud, parity, bits, flow);
 }
 
@@ -818,7 +877,7 @@ static struct uart_driver imx_reg = {
 	.cons           = IMX_CONSOLE,
 };
 
-static int serial_imx_suspend(struct device *_dev, u32 state, u32 level)
+static int serial_imx_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
         struct imx_port *sport = dev_get_drvdata(_dev);
 
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
new file mode 100644
--- /dev/null
+++ b/drivers/serial/ioc4_serial.c
@@ -0,0 +1,2897 @@
+/*
+ * 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) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * This file contains a module version of the ioc4 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioc4_common.h>
+#include <linux/serial_core.h>
+
+/*
+ * interesting things about the ioc4
+ */
+
+#define IOC4_NUM_SERIAL_PORTS	4	/* max ports per card */
+#define IOC4_NUM_CARDS		8	/* max cards per partition */
+
+#define	GET_SIO_IR(_n)	(_n == 0) ? (IOC4_SIO_IR_S0) : \
+				(_n == 1) ? (IOC4_SIO_IR_S1) : \
+				(_n == 2) ? (IOC4_SIO_IR_S2) : \
+				(IOC4_SIO_IR_S3)
+
+#define	GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
+				(_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
+				(_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
+				(IOC4_OTHER_IR_S3_MEMERR)
+
+
+/*
+ * All IOC4 registers are 32 bits wide.
+ */
+
+/*
+ * PCI Memory Space Map
+ */
+#define IOC4_PCI_ERR_ADDR_L     0x000	/* Low Error Address */
+#define IOC4_PCI_ERR_ADDR_VLD	        (0x1 << 0)
+#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
+#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
+#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
+#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
+#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
+
+/* Interrupt types */
+#define	IOC4_SIO_INTR_TYPE	0
+#define	IOC4_OTHER_INTR_TYPE	1
+#define	IOC4_NUM_INTR_TYPES	2
+
+/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
+#define IOC4_SIO_IR_S0_TX_MT	   0x00000001	/* Serial port 0 TX empty */
+#define IOC4_SIO_IR_S0_RX_FULL	   0x00000002	/* Port 0 RX buf full */
+#define IOC4_SIO_IR_S0_RX_HIGH	   0x00000004	/* Port 0 RX hiwat */
+#define IOC4_SIO_IR_S0_RX_TIMER	   0x00000008	/* Port 0 RX timeout */
+#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010	/* Port 0 delta DCD */
+#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020	/* Port 0 delta CTS */
+#define IOC4_SIO_IR_S0_INT	   0x00000040	/* Port 0 pass-thru intr */
+#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080	/* Port 0 explicit TX thru */
+#define IOC4_SIO_IR_S1_TX_MT	   0x00000100	/* Serial port 1 */
+#define IOC4_SIO_IR_S1_RX_FULL	   0x00000200	/* */
+#define IOC4_SIO_IR_S1_RX_HIGH	   0x00000400	/* */
+#define IOC4_SIO_IR_S1_RX_TIMER	   0x00000800	/* */
+#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000	/* */
+#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000	/* */
+#define IOC4_SIO_IR_S1_INT	   0x00004000	/* */
+#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000	/* */
+#define IOC4_SIO_IR_S2_TX_MT	   0x00010000	/* Serial port 2 */
+#define IOC4_SIO_IR_S2_RX_FULL	   0x00020000	/* */
+#define IOC4_SIO_IR_S2_RX_HIGH	   0x00040000	/* */
+#define IOC4_SIO_IR_S2_RX_TIMER	   0x00080000	/* */
+#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000	/* */
+#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000	/* */
+#define IOC4_SIO_IR_S2_INT	   0x00400000	/* */
+#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000	/* */
+#define IOC4_SIO_IR_S3_TX_MT	   0x01000000	/* Serial port 3 */
+#define IOC4_SIO_IR_S3_RX_FULL	   0x02000000	/* */
+#define IOC4_SIO_IR_S3_RX_HIGH	   0x04000000	/* */
+#define IOC4_SIO_IR_S3_RX_TIMER	   0x08000000	/* */
+#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000	/* */
+#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000	/* */
+#define IOC4_SIO_IR_S3_INT	   0x40000000	/* */
+#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000	/* */
+
+/* Per device interrupt masks */
+#define IOC4_SIO_IR_S0		(IOC4_SIO_IR_S0_TX_MT | \
+				 IOC4_SIO_IR_S0_RX_FULL | \
+				 IOC4_SIO_IR_S0_RX_HIGH | \
+				 IOC4_SIO_IR_S0_RX_TIMER | \
+				 IOC4_SIO_IR_S0_DELTA_DCD | \
+				 IOC4_SIO_IR_S0_DELTA_CTS | \
+				 IOC4_SIO_IR_S0_INT | \
+				 IOC4_SIO_IR_S0_TX_EXPLICIT)
+#define IOC4_SIO_IR_S1		(IOC4_SIO_IR_S1_TX_MT | \
+				 IOC4_SIO_IR_S1_RX_FULL | \
+				 IOC4_SIO_IR_S1_RX_HIGH | \
+				 IOC4_SIO_IR_S1_RX_TIMER | \
+				 IOC4_SIO_IR_S1_DELTA_DCD | \
+				 IOC4_SIO_IR_S1_DELTA_CTS | \
+				 IOC4_SIO_IR_S1_INT | \
+				 IOC4_SIO_IR_S1_TX_EXPLICIT)
+#define IOC4_SIO_IR_S2		(IOC4_SIO_IR_S2_TX_MT | \
+				 IOC4_SIO_IR_S2_RX_FULL | \
+				 IOC4_SIO_IR_S2_RX_HIGH | \
+				 IOC4_SIO_IR_S2_RX_TIMER | \
+				 IOC4_SIO_IR_S2_DELTA_DCD | \
+				 IOC4_SIO_IR_S2_DELTA_CTS | \
+				 IOC4_SIO_IR_S2_INT | \
+				 IOC4_SIO_IR_S2_TX_EXPLICIT)
+#define IOC4_SIO_IR_S3		(IOC4_SIO_IR_S3_TX_MT | \
+				 IOC4_SIO_IR_S3_RX_FULL | \
+				 IOC4_SIO_IR_S3_RX_HIGH | \
+				 IOC4_SIO_IR_S3_RX_TIMER | \
+				 IOC4_SIO_IR_S3_DELTA_DCD | \
+				 IOC4_SIO_IR_S3_DELTA_CTS | \
+				 IOC4_SIO_IR_S3_INT | \
+				 IOC4_SIO_IR_S3_TX_EXPLICIT)
+
+/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
+#define IOC4_OTHER_IR_ATA_INT           0x00000001  /* ATAPI intr pass-thru */
+#define IOC4_OTHER_IR_ATA_MEMERR        0x00000002  /* ATAPI DMA PCI error */
+#define IOC4_OTHER_IR_S0_MEMERR         0x00000004  /* Port 0 PCI error */
+#define IOC4_OTHER_IR_S1_MEMERR         0x00000008  /* Port 1 PCI error */
+#define IOC4_OTHER_IR_S2_MEMERR         0x00000010  /* Port 2 PCI error */
+#define IOC4_OTHER_IR_S3_MEMERR         0x00000020  /* Port 3 PCI error */
+
+/* Bitmasks for IOC4_SIO_CR */
+#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
+#define IOC4_SIO_CR_ARB_DIAG_TX0	0x00000000
+#define IOC4_SIO_CR_ARB_DIAG_RX0	0x00000010
+#define IOC4_SIO_CR_ARB_DIAG_TX1	0x00000020
+#define IOC4_SIO_CR_ARB_DIAG_RX1	0x00000030
+#define IOC4_SIO_CR_ARB_DIAG_TX2	0x00000040
+#define IOC4_SIO_CR_ARB_DIAG_RX2	0x00000050
+#define IOC4_SIO_CR_ARB_DIAG_TX3	0x00000060
+#define IOC4_SIO_CR_ARB_DIAG_RX3	0x00000070
+#define IOC4_SIO_CR_SIO_DIAG_IDLE	0x00000080  /* 0 -> active request among
+							   serial ports (ro) */
+/* Defs for some of the generic I/O pins */
+#define IOC4_GPCR_UART0_MODESEL	   0x10	/* Pin is output to port 0
+						   mode sel */
+#define IOC4_GPCR_UART1_MODESEL	   0x20	/* Pin is output to port 1
+						   mode sel */
+#define IOC4_GPCR_UART2_MODESEL	   0x40	/* Pin is output to port 2
+						   mode sel */
+#define IOC4_GPCR_UART3_MODESEL	   0x80	/* Pin is output to port 3
+						   mode sel */
+
+#define IOC4_GPPR_UART0_MODESEL_PIN   4	/* GIO pin controlling
+					   uart 0 mode select */
+#define IOC4_GPPR_UART1_MODESEL_PIN   5	/* GIO pin controlling
+					   uart 1 mode select */
+#define IOC4_GPPR_UART2_MODESEL_PIN   6	/* GIO pin controlling
+					   uart 2 mode select */
+#define IOC4_GPPR_UART3_MODESEL_PIN   7	/* GIO pin controlling
+					   uart 3 mode select */
+
+/* Bitmasks for serial RX status byte */
+#define IOC4_RXSB_OVERRUN       0x01	/* Char(s) lost */
+#define IOC4_RXSB_PAR_ERR	0x02	/* Parity error */
+#define IOC4_RXSB_FRAME_ERR	0x04	/* Framing error */
+#define IOC4_RXSB_BREAK	        0x08	/* Break character */
+#define IOC4_RXSB_CTS	        0x10	/* State of CTS */
+#define IOC4_RXSB_DCD	        0x20	/* State of DCD */
+#define IOC4_RXSB_MODEM_VALID   0x40	/* DCD, CTS, and OVERRUN are valid */
+#define IOC4_RXSB_DATA_VALID    0x80	/* Data byte, FRAME_ERR PAR_ERR
+					 * & BREAK valid */
+
+/* Bitmasks for serial TX control byte */
+#define IOC4_TXCB_INT_WHEN_DONE 0x20	/* Interrupt after this byte is sent */
+#define IOC4_TXCB_INVALID	0x00	/* Byte is invalid */
+#define IOC4_TXCB_VALID	        0x40	/* Byte is valid */
+#define IOC4_TXCB_MCR	        0x80	/* Data<7:0> to modem control reg */
+#define IOC4_TXCB_DELAY	        0xc0	/* Delay data<7:0> mSec */
+
+/* Bitmasks for IOC4_SBBR_L */
+#define IOC4_SBBR_L_SIZE	0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
+
+/* Bitmasks for IOC4_SSCR_<3:0> */
+#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
+#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
+#define IOC4_SSCR_HFC_EN	0x00020000  /* Hardware flow control enabled */
+#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
+#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
+#define IOC4_SSCR_DIAG	        0x00200000  /* Bypass clock divider for sim */
+#define IOC4_SSCR_RX_DRAIN	0x08000000  /* Drain RX buffer to memory */
+#define IOC4_SSCR_DMA_EN	0x10000000  /* Enable ring buffer DMA */
+#define IOC4_SSCR_DMA_PAUSE	0x20000000  /* Pause DMA */
+#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
+#define IOC4_SSCR_RESET	        0x80000000  /* Reset DMA channels */
+
+/* All producer/comsumer pointers are the same bitfield */
+#define IOC4_PROD_CONS_PTR_4K   0x00000ff8	/* For 4K buffers */
+#define IOC4_PROD_CONS_PTR_1K   0x000003f8	/* For 1K buffers */
+#define IOC4_PROD_CONS_PTR_OFF           3
+
+/* Bitmasks for IOC4_SRCIR_<3:0> */
+#define IOC4_SRCIR_ARM	        0x80000000	/* Arm RX timer */
+
+/* Bitmasks for IOC4_SHADOW_<3:0> */
+#define IOC4_SHADOW_DR	 0x00000001	/* Data ready */
+#define IOC4_SHADOW_OE	 0x00000002	/* Overrun error */
+#define IOC4_SHADOW_PE	 0x00000004	/* Parity error */
+#define IOC4_SHADOW_FE	 0x00000008	/* Framing error */
+#define IOC4_SHADOW_BI	 0x00000010	/* Break interrupt */
+#define IOC4_SHADOW_THRE 0x00000020	/* Xmit holding register empty */
+#define IOC4_SHADOW_TEMT 0x00000040	/* Xmit shift register empty */
+#define IOC4_SHADOW_RFCE 0x00000080	/* Char in RX fifo has an error */
+#define IOC4_SHADOW_DCTS 0x00010000	/* Delta clear to send */
+#define IOC4_SHADOW_DDCD 0x00080000	/* Delta data carrier detect */
+#define IOC4_SHADOW_CTS	 0x00100000	/* Clear to send */
+#define IOC4_SHADOW_DCD	 0x00800000	/* Data carrier detect */
+#define IOC4_SHADOW_DTR	 0x01000000	/* Data terminal ready */
+#define IOC4_SHADOW_RTS	 0x02000000	/* Request to send */
+#define IOC4_SHADOW_OUT1 0x04000000	/* 16550 OUT1 bit */
+#define IOC4_SHADOW_OUT2 0x08000000	/* 16550 OUT2 bit */
+#define IOC4_SHADOW_LOOP 0x10000000	/* Loopback enabled */
+
+/* Bitmasks for IOC4_SRTR_<3:0> */
+#define IOC4_SRTR_CNT	        0x00000fff	/* Reload value for RX timer */
+#define IOC4_SRTR_CNT_VAL	0x0fff0000	/* Current value of RX timer */
+#define IOC4_SRTR_CNT_VAL_SHIFT         16
+#define IOC4_SRTR_HZ                 16000	/* SRTR clock frequency */
+
+/* Serial port register map used for DMA and PIO serial I/O */
+struct ioc4_serialregs {
+	uint32_t sscr;
+	uint32_t stpir;
+	uint32_t stcir;
+	uint32_t srpir;
+	uint32_t srcir;
+	uint32_t srtr;
+	uint32_t shadow;
+};
+
+/* IOC4 UART register map */
+struct ioc4_uartregs {
+	char i4u_lcr;
+	union {
+		char iir;	/* read only */
+		char fcr;	/* write only */
+	} u3;
+	union {
+		char ier;	/* DLAB == 0 */
+		char dlm;	/* DLAB == 1 */
+	} u2;
+	union {
+		char rbr;	/* read only, DLAB == 0 */
+		char thr;	/* write only, DLAB == 0 */
+		char dll;	/* DLAB == 1 */
+	} u1;
+	char i4u_scr;
+	char i4u_msr;
+	char i4u_lsr;
+	char i4u_mcr;
+};
+
+/* short names */
+#define i4u_dll u1.dll
+#define i4u_ier u2.ier
+#define i4u_dlm u2.dlm
+#define i4u_fcr u3.fcr
+
+/* PCI memory space register map addressed using pci_bar0 */
+struct ioc4_memregs {
+	struct ioc4_mem {
+		/* Miscellaneous IOC4  registers */
+		uint32_t pci_err_addr_l;
+		uint32_t pci_err_addr_h;
+		uint32_t sio_ir;
+		uint32_t other_ir;
+
+		/* These registers are read-only for general kernel code.  */
+		uint32_t sio_ies_ro;
+		uint32_t other_ies_ro;
+		uint32_t sio_iec_ro;
+		uint32_t other_iec_ro;
+		uint32_t sio_cr;
+		uint32_t misc_fill1;
+		uint32_t int_out;
+		uint32_t misc_fill2;
+		uint32_t gpcr_s;
+		uint32_t gpcr_c;
+		uint32_t gpdr;
+		uint32_t misc_fill3;
+		uint32_t gppr_0;
+		uint32_t gppr_1;
+		uint32_t gppr_2;
+		uint32_t gppr_3;
+		uint32_t gppr_4;
+		uint32_t gppr_5;
+		uint32_t gppr_6;
+		uint32_t gppr_7;
+	} ioc4_mem;
+
+	char misc_fill4[0x100 - 0x5C - 4];
+
+	/* ATA/ATAP registers */
+	uint32_t ata_notused[9];
+	char ata_fill1[0x140 - 0x120 - 4];
+	uint32_t ata_notused1[8];
+	char ata_fill2[0x200 - 0x15C - 4];
+
+	/* Keyboard and mouse registers */
+	uint32_t km_notused[5];;
+	char km_fill1[0x300 - 0x210 - 4];
+
+	/* Serial port registers used for DMA serial I/O */
+	struct ioc4_serial {
+		uint32_t sbbr01_l;
+		uint32_t sbbr01_h;
+		uint32_t sbbr23_l;
+		uint32_t sbbr23_h;
+
+		struct ioc4_serialregs port_0;
+		struct ioc4_serialregs port_1;
+		struct ioc4_serialregs port_2;
+		struct ioc4_serialregs port_3;
+		struct ioc4_uartregs uart_0;
+		struct ioc4_uartregs uart_1;
+		struct ioc4_uartregs uart_2;
+		struct ioc4_uartregs uart_3;
+	} ioc4_serial;
+};
+
+/* UART clock speed */
+#define IOC4_SER_XIN_CLK        IOC4_SER_XIN_CLK_66
+#define IOC4_SER_XIN_CLK_66     66666667
+#define IOC4_SER_XIN_CLK_33     33333333
+
+#define IOC4_W_IES		0
+#define IOC4_W_IEC		1
+
+typedef void ioc4_intr_func_f(void *, uint32_t);
+typedef ioc4_intr_func_f *ioc4_intr_func_t;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)	;
+//#define DPRINT_CONFIG(_x...)	printk _x
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS	256
+
+/* number of characters we want to transmit to the lower level at a time */
+#define IOC4_MAX_CHARS	128
+
+/* Device name we're using */
+#define DEVICE_NAME	"ttyIOC"
+#define DEVICE_MAJOR 204
+#define DEVICE_MINOR 50
+
+/* register offsets */
+#define IOC4_SERIAL_OFFSET	0x300
+
+/* flags for next_char_state */
+#define NCS_BREAK	0x1
+#define NCS_PARITY	0x2
+#define NCS_FRAMING	0x4
+#define NCS_OVERRUN	0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED	1200
+#define MAX_BAUD_SUPPORTED	115200
+
+/* protocol types supported */
+enum sio_proto {
+	PROTO_RS232,
+	PROTO_RS422
+};
+
+/* Notification types */
+#define N_DATA_READY	0x01
+#define N_OUTPUT_LOWAT	0x02
+#define N_BREAK		0x04
+#define N_PARITY_ERROR	0x08
+#define N_FRAMING_ERROR	0x10
+#define N_OVERRUN_ERROR	0x20
+#define N_DDCD		0x40
+#define N_DCTS		0x80
+
+#define N_ALL_INPUT	(N_DATA_READY | N_BREAK |			\
+			 N_PARITY_ERROR | N_FRAMING_ERROR |		\
+			 N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT	N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS	(N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
+
+#define N_ALL		(N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |	\
+			 N_PARITY_ERROR | N_FRAMING_ERROR |		\
+			 N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_DIVISOR(_x, clk)		(((clk) + (_x) * 8) / ((_x) * 16))
+#define DIVISOR_TO_BAUD(div, clk)	((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR	(UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+					| UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS	(UART_LCR_STOP)
+
+#define PENDING(_p)	(readl(&(_p)->ip_mem->sio_ir) & _p->ip_ienb)
+#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir)
+
+/* Default to 4k buffers */
+#ifdef IOC4_1K_BUFFERS
+#define RING_BUF_SIZE 1024
+#define IOC4_BUF_SIZE_BIT 0
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
+#else
+#define RING_BUF_SIZE 4096
+#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
+#endif
+
+#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
+
+/*
+ * This is the entry saved by the driver - one per card
+ */
+struct ioc4_control {
+	int ic_irq;
+	struct {
+		/* uart ports are allocated here */
+		struct uart_port icp_uart_port;
+		/* Handy reference material */
+		struct ioc4_port *icp_port;
+	} ic_port[IOC4_NUM_SERIAL_PORTS];
+	struct ioc4_soft *ic_soft;
+};
+
+/*
+ * per-IOC4 data structure
+ */
+#define MAX_IOC4_INTR_ENTS	(8 * sizeof(uint32_t))
+struct ioc4_soft {
+	struct ioc4_mem __iomem *is_ioc4_mem_addr;
+	struct ioc4_serial __iomem *is_ioc4_serial_addr;
+
+	/* Each interrupt type has an entry in the array */
+	struct ioc4_intr_type {
+
+		/*
+		 * Each in-use entry in this array contains at least
+		 * one nonzero bit in sd_bits; no two entries in this
+		 * array have overlapping sd_bits values.
+		 */
+		struct ioc4_intr_info {
+			uint32_t sd_bits;
+			ioc4_intr_func_f *sd_intr;
+			void *sd_info;
+		} is_intr_info[MAX_IOC4_INTR_ENTS];
+
+		/* Number of entries active in the above array */
+		atomic_t is_num_intrs;
+	} is_intr_type[IOC4_NUM_INTR_TYPES];
+
+	/* is_ir_lock must be held while
+	 * modifying sio_ie values, so
+	 * we can be sure that sio_ie is
+	 * not changing when we read it
+	 * along with sio_ir.
+	 */
+	spinlock_t is_ir_lock;	/* SIO_IE[SC] mod lock */
+};
+
+/* Local port info for each IOC4 serial ports */
+struct ioc4_port {
+	struct uart_port *ip_port;
+	/* Back ptrs for this port */
+	struct ioc4_control *ip_control;
+	struct pci_dev *ip_pdev;
+	struct ioc4_soft *ip_ioc4_soft;
+
+	/* pci mem addresses */
+	struct ioc4_mem __iomem *ip_mem;
+	struct ioc4_serial __iomem *ip_serial;
+	struct ioc4_serialregs __iomem *ip_serial_regs;
+	struct ioc4_uartregs __iomem *ip_uart_regs;
+
+	/* Ring buffer page for this port */
+	dma_addr_t ip_dma_ringbuf;
+	/* vaddr of ring buffer */
+	struct ring_buffer *ip_cpu_ringbuf;
+
+	/* Rings for this port */
+	struct ring *ip_inring;
+	struct ring *ip_outring;
+
+	/* Hook to port specific values */
+	struct hooks *ip_hooks;
+
+	spinlock_t ip_lock;
+
+	/* Various rx/tx parameters */
+	int ip_baud;
+	int ip_tx_lowat;
+	int ip_rx_timeout;
+
+	/* Copy of notification bits */
+	int ip_notify;
+
+	/* Shadow copies of various registers so we don't need to PIO
+	 * read them constantly
+	 */
+	uint32_t ip_ienb;	/* Enabled interrupts */
+	uint32_t ip_sscr;
+	uint32_t ip_tx_prod;
+	uint32_t ip_rx_cons;
+	int ip_pci_bus_speed;
+	unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH	0x01
+#define DCD_ON		0x02
+#define LOWAT_WRITTEN	0x04
+#define READ_ABORTED	0x08
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct hooks {
+	uint32_t intr_delta_dcd;
+	uint32_t intr_delta_cts;
+	uint32_t intr_tx_mt;
+	uint32_t intr_rx_timer;
+	uint32_t intr_rx_high;
+	uint32_t intr_tx_explicit;
+	uint32_t intr_dma_error;
+	uint32_t intr_clear;
+	uint32_t intr_all;
+	char rs422_select_pin;
+};
+
+static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
+	/* Values for port 0 */
+	{
+	 IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
+	 IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
+	 IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
+	 IOC4_OTHER_IR_S0_MEMERR,
+	 (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
+	  IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
+	  IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
+	  IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
+	 IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
+	 },
+
+	/* Values for port 1 */
+	{
+	 IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
+	 IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
+	 IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
+	 IOC4_OTHER_IR_S1_MEMERR,
+	 (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
+	  IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
+	  IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
+	  IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
+	 IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
+	 },
+
+	/* Values for port 2 */
+	{
+	 IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
+	 IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
+	 IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
+	 IOC4_OTHER_IR_S2_MEMERR,
+	 (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
+	  IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
+	  IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
+	  IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
+	 IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
+	 },
+
+	/* Values for port 3 */
+	{
+	 IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
+	 IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
+	 IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
+	 IOC4_OTHER_IR_S3_MEMERR,
+	 (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
+	  IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
+	  IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
+	  IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
+	 IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
+	 }
+};
+
+/* A ring buffer entry */
+struct ring_entry {
+	union {
+		struct {
+			uint32_t alldata;
+			uint32_t allsc;
+		} all;
+		struct {
+			char data[4];	/* data bytes */
+			char sc[4];	/* status/control */
+		} s;
+	} u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+	((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc     u.s.sc
+#define ring_data   u.s.data
+#define ring_allsc  u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+	struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+	struct ring TX_0_OR_2;
+	struct ring RX_0_OR_2;
+	struct ring TX_1_OR_3;
+	struct ring RX_1_OR_3;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)	&(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* Infinite loop detection.
+ */
+#define MAXITER 10000000
+
+/* Prototypes */
+static void receive_chars(struct uart_port *);
+static void handle_intr(void *arg, uint32_t sio_ir);
+
+/**
+ * write_ireg - write the interrupt regs
+ * @ioc4_soft: ptr to soft struct for this port
+ * @val: value to write
+ * @which: which register
+ * @type: which ireg set
+ */
+static inline void
+write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
+{
+	struct ioc4_mem __iomem *mem = ioc4_soft->is_ioc4_mem_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
+
+	switch (type) {
+	case IOC4_SIO_INTR_TYPE:
+		switch (which) {
+		case IOC4_W_IES:
+			writel(val, &mem->sio_ies_ro);
+			break;
+
+		case IOC4_W_IEC:
+			writel(val, &mem->sio_iec_ro);
+			break;
+		}
+		break;
+
+	case IOC4_OTHER_INTR_TYPE:
+		switch (which) {
+		case IOC4_W_IES:
+			writel(val, &mem->other_ies_ro);
+			break;
+
+		case IOC4_W_IEC:
+			writel(val, &mem->other_iec_ro);
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
+}
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc4_port *port, int baud)
+{
+	int actual_baud;
+	int diff;
+	int lcr;
+	unsigned short divisor;
+	struct ioc4_uartregs __iomem *uart;
+
+	divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
+	if (!divisor)
+		return 1;
+	actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
+
+	diff = actual_baud - baud;
+	if (diff < 0)
+		diff = -diff;
+
+	/* If we're within 1%, we've found a match */
+	if (diff * 100 > actual_baud)
+		return 1;
+
+	uart = port->ip_uart_regs;
+	lcr = readb(&uart->i4u_lcr);
+	writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
+	writeb((unsigned char)divisor, &uart->i4u_dll);
+	writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
+	writeb(lcr, &uart->i4u_lcr);
+	return 0;
+}
+
+
+/**
+ * get_ioc4_port - given a uart port, return the control structure
+ * @port: uart port
+ */
+static struct ioc4_port *get_ioc4_port(struct uart_port *the_port)
+{
+	struct ioc4_control *control = dev_get_drvdata(the_port->dev);
+	int ii;
+
+	if (control) {
+		for ( ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++ ) {
+			if (!control->ic_port[ii].icp_port)
+				continue;
+			if (the_port == control->ic_port[ii].icp_port->ip_port)
+				return control->ic_port[ii].icp_port;
+		}
+	}
+	return NULL;
+}
+
+/* The IOC4 hardware provides no atomic way to determine if interrupts
+ * are pending since two reads are required to do so.  The handler must
+ * read the SIO_IR and the SIO_IES, and take the logical and of the
+ * two.  When this value is zero, all interrupts have been serviced and
+ * the handler may return.
+ *
+ * This has the unfortunate "hole" that, if some other CPU or
+ * some other thread or some higher level interrupt manages to
+ * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
+ * think we have observed SIO_IR&SIO_IE==0 when in fact this
+ * condition never really occurred.
+ *
+ * To solve this, we use a simple spinlock that must be held
+ * whenever modifying SIO_IE; holding this lock while observing
+ * both SIO_IR and SIO_IE guarantees that we do not falsely
+ * conclude that no enabled interrupts are pending.
+ */
+
+static inline uint32_t
+pending_intrs(struct ioc4_soft *soft, int type)
+{
+	struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr;
+	unsigned long flag;
+	uint32_t intrs = 0;
+
+	BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+	       || (type == IOC4_OTHER_INTR_TYPE)));
+
+	spin_lock_irqsave(&soft->is_ir_lock, flag);
+
+	switch (type) {
+	case IOC4_SIO_INTR_TYPE:
+		intrs = readl(&mem->sio_ir) & readl(&mem->sio_ies_ro);
+		break;
+
+	case IOC4_OTHER_INTR_TYPE:
+		intrs = readl(&mem->other_ir) & readl(&mem->other_ies_ro);
+
+		/* Don't process any ATA interrupte */
+		intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+		break;
+
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+	return intrs;
+}
+
+/**
+ * port_init - Initialize the sio and ioc4 hardware for a given port
+ *			called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc4_port *port)
+{
+	uint32_t sio_cr;
+	struct hooks *hooks = port->ip_hooks;
+	struct ioc4_uartregs __iomem *uart;
+
+	/* Idle the IOC4 serial interface */
+	writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
+
+	/* Wait until any pending bus activity for this port has ceased */
+	do
+		sio_cr = readl(&port->ip_mem->sio_cr);
+	while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
+
+	/* Finish reset sequence */
+	writel(0, &port->ip_serial_regs->sscr);
+
+	/* Once RESET is done, reload cached tx_prod and rx_cons values
+	 * and set rings to empty by making prod == cons
+	 */
+	port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+	writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+	port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+	writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+	/* Disable interrupts for this 16550 */
+	uart = port->ip_uart_regs;
+	writeb(0, &uart->i4u_lcr);
+	writeb(0, &uart->i4u_ier);
+
+	/* Set the default baud */
+	set_baud(port, port->ip_baud);
+
+	/* Set line control to 8 bits no parity */
+	writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
+					/* UART_LCR_STOP == 1 stop */
+
+	/* Enable the FIFOs */
+	writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
+	/* then reset 16550 FIFOs */
+	writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+			&uart->i4u_fcr);
+
+	/* Clear modem control register */
+	writeb(0, &uart->i4u_mcr);
+
+	/* Clear deltas in modem status register */
+	readb(&uart->i4u_msr);
+
+	/* Only do this once per port pair */
+	if (port->ip_hooks == &hooks_array[0]
+			    || port->ip_hooks == &hooks_array[2]) {
+		unsigned long ring_pci_addr;
+		uint32_t __iomem *sbbr_l;
+		uint32_t __iomem *sbbr_h;
+
+		if (port->ip_hooks == &hooks_array[0]) {
+			sbbr_l = &port->ip_serial->sbbr01_l;
+			sbbr_h = &port->ip_serial->sbbr01_h;
+		} else {
+			sbbr_l = &port->ip_serial->sbbr23_l;
+			sbbr_h = &port->ip_serial->sbbr23_h;
+		}
+
+		ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+		DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
+					__FUNCTION__, ring_pci_addr));
+
+		writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
+		writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
+	}
+
+	/* Set the receive timeout value to 10 msec */
+	writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+	/* Set rx threshold, enable DMA */
+	/* Set high water mark at 3/4 of full ring */
+	port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Disable and clear all serial related interrupt bits */
+	write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
+		       IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+	port->ip_ienb &= ~hooks->intr_clear;
+	writel(hooks->intr_clear, &port->ip_mem->sio_ir);
+	return 0;
+}
+
+/**
+ * handle_dma_error_intr - service any pending DMA error interrupts for the
+ *			given port - 2nd level called via sd_intr
+ * @arg: handler arg
+ * @other_ir: ioc4regs
+ */
+static void handle_dma_error_intr(void *arg, uint32_t other_ir)
+{
+	struct ioc4_port *port = (struct ioc4_port *)arg;
+	struct hooks *hooks = port->ip_hooks;
+	unsigned int flags;
+
+	spin_lock_irqsave(&port->ip_lock, flags);
+
+	/* ACK the interrupt */
+	writel(hooks->intr_dma_error, &port->ip_mem->other_ir);
+
+	if (readl(&port->ip_mem->pci_err_addr_l) & IOC4_PCI_ERR_ADDR_VLD) {
+		printk(KERN_ERR
+			"PCI error address is 0x%lx, "
+				"master is serial port %c %s\n",
+		     (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
+							 << 32)
+				| readl(&port->ip_mem->pci_err_addr_l))
+					& IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
+		     ((char)(readl(&port->ip_mem-> pci_err_addr_l) &
+			     IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
+		     (readl(&port->ip_mem->pci_err_addr_l)
+				& IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
+				? "RX" : "TX");
+
+		if (readl(&port->ip_mem->pci_err_addr_l)
+						& IOC4_PCI_ERR_ADDR_MUL_ERR) {
+			printk(KERN_ERR
+				"Multiple errors occurred\n");
+		}
+	}
+	spin_unlock_irqrestore(&port->ip_lock, flags);
+
+	/* Re-enable DMA error interrupts */
+	write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
+						IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * intr_connect - interrupt connect function
+ * @soft: soft struct for this card
+ * @type: interrupt type
+ * @intrbits: bit pattern to set
+ * @intr: handler function
+ * @info: handler arg
+ */
+static void
+intr_connect(struct ioc4_soft *soft, int type,
+		  uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
+{
+	int i;
+	struct ioc4_intr_info *intr_ptr;
+
+	BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+	       || (type == IOC4_OTHER_INTR_TYPE)));
+
+	i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
+	BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
+
+	/* Save off the lower level interrupt handler */
+	intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
+	intr_ptr->sd_bits = intrbits;
+	intr_ptr->sd_intr = intr;
+	intr_ptr->sd_info = info;
+}
+
+/**
+ * ioc4_intr - Top level IOC4 interrupt handler.
+ * @irq: irq value
+ * @arg: handler arg
+ * @regs: registers
+ */
+static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
+{
+	struct ioc4_soft *soft;
+	uint32_t this_ir, this_mir;
+	int xx, num_intrs = 0;
+	int intr_type;
+	int handled = 0;
+	struct ioc4_intr_info *ii;
+
+	soft = arg;
+	for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
+		num_intrs = (int)atomic_read(
+				&soft->is_intr_type[intr_type].is_num_intrs);
+
+		this_mir = this_ir = pending_intrs(soft, intr_type);
+
+		/* Farm out the interrupt to the various drivers depending on
+		 * which interrupt bits are set.
+		 */
+		for (xx = 0; xx < num_intrs; xx++) {
+			ii = &soft->is_intr_type[intr_type].is_intr_info[xx];
+			if ((this_mir = this_ir & ii->sd_bits)) {
+				/* Disable owned interrupts, call handler */
+				handled++;
+				write_ireg(soft, ii->sd_bits, IOC4_W_IEC,
+								intr_type);
+				ii->sd_intr(ii->sd_info, this_mir);
+				this_ir &= ~this_mir;
+			}
+		}
+		if (this_ir) {
+			printk(KERN_ERR
+			       "unknown IOC4 %s interrupt 0x%x, sio_ir = 0x%x,"
+				" sio_ies = 0x%x, other_ir = 0x%x :"
+				"other_ies = 0x%x\n",
+			       (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" :
+			       "other", this_ir,
+			       readl(&soft->is_ioc4_mem_addr->sio_ir),
+			       readl(&soft->is_ioc4_mem_addr->sio_ies_ro),
+			       readl(&soft->is_ioc4_mem_addr->other_ir),
+			       readl(&soft->is_ioc4_mem_addr->other_ies_ro));
+		}
+	}
+#ifdef DEBUG_INTERRUPTS
+	{
+		struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr;
+		spinlock_t *lp = &soft->is_ir_lock;
+		unsigned long flag;
+
+		spin_lock_irqsave(&soft->is_ir_lock, flag);
+		printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies_ro 0x%x "
+				"other_ir 0x%x other_ies_ro 0x%x mask 0x%x\n",
+		     __FUNCTION__, __LINE__,
+		     (void *)mem, readl(&mem->sio_ir),
+		     readl(&mem->sio_ies_ro),
+		     readl(&mem->other_ir),
+		     readl(&mem->other_ies_ro),
+		     IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+		spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+	}
+#endif
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * ioc4_attach_local - Device initialization.
+ *			Called at *_attach() time for each
+ *			IOC4 with serial ports in the system.
+ * @control: ioc4_control ptr
+ * @pdev: PCI handle for this device
+ * @soft: soft struct for this device
+ * @ioc4: ioc4 mem space
+ */
+static int inline ioc4_attach_local(struct pci_dev *pdev,
+			struct ioc4_control *control,
+			struct ioc4_soft *soft, void __iomem *ioc4_mem,
+			void __iomem *ioc4_serial)
+{
+	struct ioc4_port *port;
+	struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
+	int port_number;
+	uint16_t ioc4_revid_min = 62;
+	uint16_t ioc4_revid;
+
+	/* IOC4 firmware must be at least rev 62 */
+	pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
+
+	printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
+	if (ioc4_revid < ioc4_revid_min) {
+		printk(KERN_WARNING
+		    "IOC4 serial not supported on firmware rev %d, "
+				"please upgrade to rev %d or higher\n",
+				ioc4_revid, ioc4_revid_min);
+		return -EPERM;
+	}
+	BUG_ON(ioc4_mem == NULL);
+	BUG_ON(ioc4_serial == NULL);
+
+	/* Create port structures for each port */
+	for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
+							port_number++) {
+		port = kmalloc(sizeof(struct ioc4_port), GFP_KERNEL);
+		if (!port) {
+			printk(KERN_WARNING
+				"IOC4 serial memory not available for port\n");
+			return -ENOMEM;
+		}
+		memset(port, 0, sizeof(struct ioc4_port));
+
+		/* we need to remember the previous ones, to point back to
+		 * them farther down - setting up the ring buffers.
+		 */
+		ports[port_number] = port;
+
+		/* Allocate buffers and jumpstart the hardware.  */
+		control->ic_port[port_number].icp_port = port;
+		port->ip_ioc4_soft = soft;
+		port->ip_pdev = pdev;
+		port->ip_ienb = 0;
+		port->ip_pci_bus_speed = IOC4_SER_XIN_CLK;
+		port->ip_baud = 9600;
+		port->ip_control = control;
+		port->ip_mem = ioc4_mem;
+		port->ip_serial = ioc4_serial;
+
+		/* point to the right hook */
+		port->ip_hooks = &hooks_array[port_number];
+
+		/* Get direct hooks to the serial regs and uart regs
+		 * for this port
+		 */
+		switch (port_number) {
+		case 0:
+			port->ip_serial_regs = &(port->ip_serial->port_0);
+			port->ip_uart_regs = &(port->ip_serial->uart_0);
+			break;
+		case 1:
+			port->ip_serial_regs = &(port->ip_serial->port_1);
+			port->ip_uart_regs = &(port->ip_serial->uart_1);
+			break;
+		case 2:
+			port->ip_serial_regs = &(port->ip_serial->port_2);
+			port->ip_uart_regs = &(port->ip_serial->uart_2);
+			break;
+		default:
+		case 3:
+			port->ip_serial_regs = &(port->ip_serial->port_3);
+			port->ip_uart_regs = &(port->ip_serial->uart_3);
+			break;
+		}
+
+		/* ring buffers are 1 to a pair of ports */
+		if (port_number && (port_number & 1)) {
+			/* odd use the evens buffer */
+			port->ip_dma_ringbuf =
+					ports[port_number - 1]->ip_dma_ringbuf;
+			port->ip_cpu_ringbuf =
+					ports[port_number - 1]->ip_cpu_ringbuf;
+			port->ip_inring = RING(port, RX_1_OR_3);
+			port->ip_outring = RING(port, TX_1_OR_3);
+
+		} else {
+			if (port->ip_dma_ringbuf == 0) {
+				port->ip_cpu_ringbuf = pci_alloc_consistent
+					(pdev, TOTAL_RING_BUF_SIZE,
+					&port->ip_dma_ringbuf);
+
+			}
+			BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
+				(TOTAL_RING_BUF_SIZE - 1)) == 0));
+			DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
+						"ip_dma_ringbuf 0x%p\n",
+					__FUNCTION__,
+					(void *)port->ip_cpu_ringbuf,
+					(void *)port->ip_dma_ringbuf));
+			port->ip_inring = RING(port, RX_0_OR_2);
+			port->ip_outring = RING(port, TX_0_OR_2);
+		}
+		DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
+				__FUNCTION__,
+				port_number, (void *)port, (void *)control));
+		DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+				(void *)port->ip_serial_regs,
+				(void *)port->ip_uart_regs));
+
+		/* Initialize the hardware for IOC4 */
+		port_init(port);
+
+		DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
+						"outring 0x%p\n",
+				__FUNCTION__,
+				port_number, (void *)port,
+				(void *)port->ip_inring,
+				(void *)port->ip_outring));
+
+		/* Attach interrupt handlers */
+		intr_connect(soft, IOC4_SIO_INTR_TYPE,
+				GET_SIO_IR(port_number),
+				handle_intr, port);
+
+		intr_connect(soft, IOC4_OTHER_INTR_TYPE,
+				GET_OTHER_IR(port_number),
+				handle_dma_error_intr, port);
+	}
+	return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+	struct hooks *hooks = port->ip_hooks;
+
+	if ((port->ip_ienb & mask) != mask) {
+		write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
+						IOC4_SIO_INTR_TYPE);
+		port->ip_ienb |= mask;
+	}
+
+	if (port->ip_ienb)
+		write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+				IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc4_port *port)
+{
+	int spiniter = 0;
+
+	port->ip_flags = 0;
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+		writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+			&port->ip_serial_regs->sscr);
+		while((readl(&port->ip_serial_regs-> sscr)
+				& IOC4_SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER) {
+				return -1;
+			}
+		}
+	}
+
+	/* Reset the input fifo.  If the uart received chars while the port
+	 * was closed and DMA is not enabled, the uart may have a bunch of
+	 * chars hanging around in its rx fifo which will not be discarded
+	 * by rclr in the upper layer. We must get rid of them here.
+	 */
+	writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+				&port->ip_uart_regs->i4u_fcr);
+
+	writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
+					/* UART_LCR_STOP == 1 stop */
+
+	/* Re-enable DMA, set default threshold to intr whenever there is
+	 * data available.
+	 */
+	port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+	port->ip_sscr |= 1;	/* default threshold */
+
+	/* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+	 * flag if it was set above
+	 */
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	port->ip_tx_lowat = 1;
+	return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
+{
+	int threshold;
+
+	port->ip_rx_timeout = timeout;
+
+	/* Timeout is in ticks.  Let's figure out how many chars we
+	 * can receive at the current baud rate in that interval
+	 * and set the rx threshold to that amount.  There are 4 chars
+	 * per ring entry, so we'll divide the number of chars that will
+	 * arrive in timeout by 4.
+	 * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+	 */
+	threshold = timeout * port->ip_baud / 4000;
+	if (threshold == 0)
+		threshold = 1;	/* otherwise we'll intr all the time! */
+
+	if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
+		return 1;
+
+	port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+	port->ip_sscr |= threshold;
+
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Now set the rx timeout to the given value
+	 * again timeout * IOC4_SRTR_HZ / HZ
+	 */
+	timeout = timeout * IOC4_SRTR_HZ / 100;
+	if (timeout > IOC4_SRTR_CNT)
+		timeout = IOC4_SRTR_CNT;
+
+	writel(timeout, &port->ip_serial_regs->srtr);
+	return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc4_port *port,
+	    int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+	char lcr, sizebits;
+	int spiniter = 0;
+
+	DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
+		__FUNCTION__, baud, byte_size, stop_bits, parenb, parodd));
+
+	if (set_baud(port, baud))
+		return 1;
+
+	switch (byte_size) {
+	case 5:
+		sizebits = UART_LCR_WLEN5;
+		break;
+	case 6:
+		sizebits = UART_LCR_WLEN6;
+		break;
+	case 7:
+		sizebits = UART_LCR_WLEN7;
+		break;
+	case 8:
+		sizebits = UART_LCR_WLEN8;
+		break;
+	default:
+		return 1;
+	}
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+		writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+			&port->ip_serial_regs->sscr);
+		while((readl(&port->ip_serial_regs->sscr)
+						& IOC4_SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER)
+				return -1;
+		}
+	}
+
+	/* Clear relevant fields in lcr */
+	lcr = readb(&port->ip_uart_regs->i4u_lcr);
+	lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+		 UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+	/* Set byte size in lcr */
+	lcr |= sizebits;
+
+	/* Set parity */
+	if (parenb) {
+		lcr |= UART_LCR_PARITY;
+		if (!parodd)
+			lcr |= UART_LCR_EPAR;
+	}
+
+	/* Set stop bits */
+	if (stop_bits)
+		lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+	writeb(lcr, &port->ip_uart_regs->i4u_lcr);
+
+	/* Re-enable the DMA interface if necessary */
+	if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+	port->ip_baud = baud;
+
+	/* When we get within this number of ring entries of filling the
+	 * entire ring on tx, place an EXPLICIT intr to generate a lowat
+	 * notification when output has drained.
+	 */
+	port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+	if (port->ip_tx_lowat == 0)
+		port->ip_tx_lowat = 1;
+
+	set_rx_timeout(port, 2);
+
+	return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *			actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc4_port *port, char *buf, int len)
+{
+	int prod_ptr, cons_ptr, total = 0;
+	struct ring *outring;
+	struct ring_entry *entry;
+	struct hooks *hooks = port->ip_hooks;
+
+	BUG_ON(!(len >= 0));
+
+	prod_ptr = port->ip_tx_prod;
+	cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+	outring = port->ip_outring;
+
+	/* Maintain a 1-entry red-zone.  The ring buffer is full when
+	 * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+	 * in the body of the loop, I'll do it now.
+	 */
+	cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+	/* Stuff the bytes into the output */
+	while ((prod_ptr != cons_ptr) && (len > 0)) {
+		int xx;
+
+		/* Get 4 bytes (one ring entry) at a time */
+		entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+		/* Invalidate all entries */
+		entry->ring_allsc = 0;
+
+		/* Copy in some bytes */
+		for (xx = 0; (xx < 4) && (len > 0); xx++) {
+			entry->ring_data[xx] = *buf++;
+			entry->ring_sc[xx] = IOC4_TXCB_VALID;
+			len--;
+			total++;
+		}
+
+		/* If we are within some small threshold of filling up the
+		 * entire ring buffer, we must place an EXPLICIT intr here
+		 * to generate a lowat interrupt in case we subsequently
+		 * really do fill up the ring and the caller goes to sleep.
+		 * No need to place more than one though.
+		 */
+		if (!(port->ip_flags & LOWAT_WRITTEN) &&
+			((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+				<= port->ip_tx_lowat
+					* (int)sizeof(struct ring_entry)) {
+			port->ip_flags |= LOWAT_WRITTEN;
+			entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
+		}
+
+		/* Go on to next entry */
+		prod_ptr += sizeof(struct ring_entry);
+		prod_ptr &= PROD_CONS_MASK;
+	}
+
+	/* If we sent something, start DMA if necessary */
+	if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+		port->ip_sscr |= IOC4_SSCR_DMA_EN;
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+
+	/* Store the new producer pointer.  If tx is disabled, we stuff the
+	 * data into the ring buffer, but we don't actually start tx.
+	 */
+	if (!uart_tx_stopped(port->ip_port)) {
+		writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+		/* If we are now transmitting, enable tx_mt interrupt so we
+		 * can disable DMA if necessary when the tx finishes.
+		 */
+		if (total > 0)
+			enable_intrs(port, hooks->intr_tx_mt);
+	}
+	port->ip_tx_prod = prod_ptr;
+	return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void disable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+	struct hooks *hooks = port->ip_hooks;
+
+	if (port->ip_ienb & mask) {
+		write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
+					IOC4_SIO_INTR_TYPE);
+		port->ip_ienb &= ~mask;
+	}
+
+	if (!port->ip_ienb)
+		write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+				IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc4_port *port, int mask, int set_on)
+{
+	struct hooks *hooks = port->ip_hooks;
+	uint32_t intrbits, sscrbits;
+
+	BUG_ON(!mask);
+
+	intrbits = sscrbits = 0;
+
+	if (mask & N_DATA_READY)
+		intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+	if (mask & N_OUTPUT_LOWAT)
+		intrbits |= hooks->intr_tx_explicit;
+	if (mask & N_DDCD) {
+		intrbits |= hooks->intr_delta_dcd;
+		sscrbits |= IOC4_SSCR_RX_RING_DCD;
+	}
+	if (mask & N_DCTS)
+		intrbits |= hooks->intr_delta_cts;
+
+	if (set_on) {
+		enable_intrs(port, intrbits);
+		port->ip_notify |= mask;
+		port->ip_sscr |= sscrbits;
+	} else {
+		disable_intrs(port, intrbits);
+		port->ip_notify &= ~mask;
+		port->ip_sscr &= ~sscrbits;
+	}
+
+	/* We require DMA if either DATA_READY or DDCD notification is
+	 * currently requested. If neither of these is requested and
+	 * there is currently no tx in progress, DMA may be disabled.
+	 */
+	if (port->ip_notify & (N_DATA_READY | N_DDCD))
+		port->ip_sscr |= IOC4_SSCR_DMA_EN;
+	else if (!(port->ip_ienb & hooks->intr_tx_mt))
+		port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @set: set ?
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port, int set,
+		int mask1, int mask2)
+{
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	uint32_t shadow;
+	int spiniter = 0;
+	char mcr;
+
+	if (!port)
+		return -1;
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+		writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+			&port->ip_serial_regs->sscr);
+		while ((readl(&port->ip_serial_regs->sscr)
+					& IOC4_SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER)
+				return -1;
+		}
+	}
+	shadow = readl(&port->ip_serial_regs->shadow);
+	mcr = (shadow & 0xff000000) >> 24;
+
+	/* Set new value */
+	if (set) {
+		mcr |= mask1;
+		shadow |= mask2;
+	} else {
+		mcr &= ~mask1;
+		shadow &= ~mask2;
+	}
+	writeb(mcr, &port->ip_uart_regs->i4u_mcr);
+	writel(shadow, &port->ip_serial_regs->shadow);
+
+	/* Re-enable the DMA interface if necessary */
+	if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+	return 0;
+}
+
+/**
+ * ioc4_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto)
+{
+	struct hooks *hooks = port->ip_hooks;
+
+	switch (proto) {
+	case PROTO_RS232:
+		/* Clear the appropriate GIO pin */
+		writel(0, (&port->ip_mem->gppr_0 +
+				  hooks->rs422_select_pin));
+		break;
+
+	case PROTO_RS422:
+		/* Set the appropriate GIO pin */
+		writel(1, (&port->ip_mem->gppr_0 +
+				  hooks->rs422_select_pin));
+		break;
+
+	default:
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with ip_lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+	int xmit_count, tail, head;
+	int result;
+	char *start;
+	struct tty_struct *tty;
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	struct uart_info *info;
+
+	if (!the_port)
+		return;
+	if (!port)
+		return;
+
+	info = the_port->info;
+	tty = info->tty;
+
+	if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
+		/* Nothing to do or hw stopped */
+		set_notification(port, N_ALL_OUTPUT, 0);
+		return;
+	}
+
+	head = info->xmit.head;
+	tail = info->xmit.tail;
+	start = (char *)&info->xmit.buf[tail];
+
+	/* write out all the data or until the end of the buffer */
+	xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+	if (xmit_count > 0) {
+		result = do_write(port, start, xmit_count);
+		if (result > 0) {
+			/* booking */
+			xmit_count -= result;
+			the_port->icount.tx += result;
+			/* advance the pointers */
+			tail += result;
+			tail &= UART_XMIT_SIZE - 1;
+			info->xmit.tail = tail;
+			start = (char *)&info->xmit.buf[tail];
+		}
+	}
+	if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(the_port);
+
+	if (uart_circ_empty(&info->xmit)) {
+		set_notification(port, N_OUTPUT_LOWAT, 0);
+	} else {
+		set_notification(port, N_OUTPUT_LOWAT, 1);
+	}
+}
+
+/**
+ * ioc4_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc4_change_speed(struct uart_port *the_port,
+		  struct termios *new_termios, struct termios *old_termios)
+{
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	int baud, bits;
+	unsigned cflag;
+	int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+	struct uart_info *info = the_port->info;
+
+	cflag = new_termios->c_cflag;
+
+	switch (cflag & CSIZE) {
+	case CS5:
+		new_data = 5;
+		bits = 7;
+		break;
+	case CS6:
+		new_data = 6;
+		bits = 8;
+		break;
+	case CS7:
+		new_data = 7;
+		bits = 9;
+		break;
+	case CS8:
+		new_data = 8;
+		bits = 10;
+		break;
+	default:
+		/* cuz we always need a default ... */
+		new_data = 5;
+		bits = 7;
+		break;
+	}
+	if (cflag & CSTOPB) {
+		bits++;
+		new_stop = 1;
+	}
+	if (cflag & PARENB) {
+		bits++;
+		new_parity_enable = 1;
+		if (cflag & PARODD)
+			new_parity = 1;
+	}
+	baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+				MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+	DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud));
+
+	/* default is 9600 */
+	if (!baud)
+		baud = 9600;
+
+	if (!the_port->fifosize)
+		the_port->fifosize = IOC4_MAX_CHARS;
+	the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
+	the_port->timeout += HZ / 50;	/* Add .02 seconds of slop */
+
+	the_port->ignore_status_mask = N_ALL_INPUT;
+
+	if (I_IGNPAR(info->tty))
+		the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+						| N_FRAMING_ERROR);
+	if (I_IGNBRK(info->tty)) {
+		the_port->ignore_status_mask &= ~N_BREAK;
+		if (I_IGNPAR(info->tty))
+			the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+	}
+	if (!(cflag & CREAD)) {
+		/* ignore everything */
+		the_port->ignore_status_mask &= ~N_DATA_READY;
+	}
+
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		port->ip_sscr |= IOC4_SSCR_HFC_EN;
+	}
+	else {
+		info->flags &= ~ASYNC_CTS_FLOW;
+		port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
+	}
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Set the configuration and proper notification call */
+	DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
+		"config_port(baud %d data %d stop %d p enable %d parity %d),"
+		" notification 0x%x\n",
+	     __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop,
+	     new_parity_enable, new_parity, the_port->ignore_status_mask));
+
+	if ((config_port(port, baud,		/* baud */
+			 new_data,		/* byte size */
+			 new_stop,		/* stop bits */
+			 new_parity_enable,	/* set parity */
+			 new_parity)) >= 0) {	/* parity 1==odd */
+		set_notification(port, the_port->ignore_status_mask, 1);
+	}
+}
+
+/**
+ * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic4_startup_local(struct uart_port *the_port)
+{
+	int retval = 0;
+	struct ioc4_port *port;
+	struct uart_info *info;
+
+	if (!the_port)
+		return -1;
+
+	port = get_ioc4_port(the_port);
+	if (!port)
+		return -1;
+
+	info = the_port->info;
+	if (info->flags & UIF_INITIALIZED) {
+		return retval;
+	}
+
+	if (info->tty) {
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
+	local_open(port);
+
+	/* set the speed of the serial port */
+	ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0);
+
+	info->flags |= UIF_INITIALIZED;
+	return 0;
+}
+
+/*
+ * ioc4_cb_output_lowat - called when the output low water mark is hit
+ * @port: port to output
+ */
+static void ioc4_cb_output_lowat(struct ioc4_port *port)
+{
+	/* ip_lock is set on the call here */
+	if (port->ip_port) {
+		transmit_chars(port->ip_port);
+	}
+}
+
+/**
+ * handle_intr - service any interrupts for the given port - 2nd level
+ *			called via sd_intr
+ * @arg: handler arg
+ * @sio_ir: ioc4regs
+ */
+static void handle_intr(void *arg, uint32_t sio_ir)
+{
+	struct ioc4_port *port = (struct ioc4_port *)arg;
+	struct hooks *hooks = port->ip_hooks;
+	unsigned int rx_high_rd_aborted = 0;
+	unsigned int flags;
+	struct uart_port *the_port;
+	int loop_counter;
+
+	/* Possible race condition here: The tx_mt interrupt bit may be
+	 * cleared without the intervention of the interrupt handler,
+	 * e.g. by a write.  If the top level interrupt handler reads a
+	 * tx_mt, then some other processor does a write, starting up
+	 * output, then we come in here, see the tx_mt and stop DMA, the
+	 * output started by the other processor will hang.  Thus we can
+	 * only rely on tx_mt being legitimate if it is read while the
+	 * port lock is held.  Therefore this bit must be ignored in the
+	 * passed in interrupt mask which was read by the top level
+	 * interrupt handler since the port lock was not held at the time
+	 * it was read.  We can only rely on this bit being accurate if it
+	 * is read while the port lock is held.  So we'll clear it for now,
+	 * and reload it later once we have the port lock.
+	 */
+	sio_ir &= ~(hooks->intr_tx_mt);
+
+	spin_lock_irqsave(&port->ip_lock, flags);
+
+	loop_counter = MAXITER;	/* to avoid hangs */
+
+	do {
+		uint32_t shadow;
+
+		if ( loop_counter-- <= 0 ) {
+			printk(KERN_WARNING "IOC4 serial: "
+					"possible hang condition/"
+					"port stuck on interrupt.\n");
+			break;
+		}
+
+		/* Handle a DCD change */
+		if (sio_ir & hooks->intr_delta_dcd) {
+			/* ACK the interrupt */
+			writel(hooks->intr_delta_dcd,
+				&port->ip_mem->sio_ir);
+
+			shadow = readl(&port->ip_serial_regs->shadow);
+
+			if ((port->ip_notify & N_DDCD)
+					&& (shadow & IOC4_SHADOW_DCD)
+					&& (port->ip_port)) {
+				the_port = port->ip_port;
+				the_port->icount.dcd = 1;
+				wake_up_interruptible
+					    (&the_port-> info->delta_msr_wait);
+			} else if ((port->ip_notify & N_DDCD)
+					&& !(shadow & IOC4_SHADOW_DCD)) {
+				/* Flag delta DCD/no DCD */
+				port->ip_flags |= DCD_ON;
+			}
+		}
+
+		/* Handle a CTS change */
+		if (sio_ir & hooks->intr_delta_cts) {
+			/* ACK the interrupt */
+			writel(hooks->intr_delta_cts,
+					&port->ip_mem->sio_ir);
+
+			shadow = readl(&port->ip_serial_regs->shadow);
+
+			if ((port->ip_notify & N_DCTS)
+					&& (port->ip_port)) {
+				the_port = port->ip_port;
+				the_port->icount.cts =
+					(shadow & IOC4_SHADOW_CTS) ? 1 : 0;
+				wake_up_interruptible
+					(&the_port->info->delta_msr_wait);
+			}
+		}
+
+		/* rx timeout interrupt.  Must be some data available.  Put this
+		 * before the check for rx_high since servicing this condition
+		 * may cause that condition to clear.
+		 */
+		if (sio_ir & hooks->intr_rx_timer) {
+			/* ACK the interrupt */
+			writel(hooks->intr_rx_timer,
+				&port->ip_mem->sio_ir);
+
+			if ((port->ip_notify & N_DATA_READY)
+					&& (port->ip_port)) {
+				/* ip_lock is set on call here */
+				receive_chars(port->ip_port);
+			}
+		}
+
+		/* rx high interrupt. Must be after rx_timer.  */
+		else if (sio_ir & hooks->intr_rx_high) {
+			/* Data available, notify upper layer */
+			if ((port->ip_notify & N_DATA_READY)
+						&& port->ip_port) {
+				/* ip_lock is set on call here */
+				receive_chars(port->ip_port);
+			}
+
+			/* We can't ACK this interrupt.  If receive_chars didn't
+			 * cause the condition to clear, we'll have to disable
+			 * the interrupt until the data is drained.
+			 * If the read was aborted, don't disable the interrupt
+			 * as this may cause us to hang indefinitely.  An
+			 * aborted read generally means that this interrupt
+			 * hasn't been delivered to the cpu yet anyway, even
+			 * though we see it as asserted when we read the sio_ir.
+			 */
+			if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
+				if ((port->ip_flags & READ_ABORTED) == 0) {
+					port->ip_ienb &= ~hooks->intr_rx_high;
+					port->ip_flags |= INPUT_HIGH;
+				} else {
+					rx_high_rd_aborted++;
+				}
+			}
+		}
+
+		/* We got a low water interrupt: notify upper layer to
+		 * send more data.  Must come before tx_mt since servicing
+		 * this condition may cause that condition to clear.
+		 */
+		if (sio_ir & hooks->intr_tx_explicit) {
+			port->ip_flags &= ~LOWAT_WRITTEN;
+
+			/* ACK the interrupt */
+			writel(hooks->intr_tx_explicit,
+					&port->ip_mem->sio_ir);
+
+			if (port->ip_notify & N_OUTPUT_LOWAT)
+				ioc4_cb_output_lowat(port);
+		}
+
+		/* Handle tx_mt.  Must come after tx_explicit.  */
+		else if (sio_ir & hooks->intr_tx_mt) {
+			/* If we are expecting a lowat notification
+			 * and we get to this point it probably means that for
+			 * some reason the tx_explicit didn't work as expected
+			 * (that can legitimately happen if the output buffer is
+			 * filled up in just the right way).
+			 * So send the notification now.
+			 */
+			if (port->ip_notify & N_OUTPUT_LOWAT) {
+				ioc4_cb_output_lowat(port);
+
+				/* We need to reload the sio_ir since the lowat
+				 * call may have caused another write to occur,
+				 * clearing the tx_mt condition.
+				 */
+				sio_ir = PENDING(port);
+			}
+
+			/* If the tx_mt condition still persists even after the
+			 * lowat call, we've got some work to do.
+			 */
+			if (sio_ir & hooks->intr_tx_mt) {
+
+				/* If we are not currently expecting DMA input,
+				 * and the transmitter has just gone idle,
+				 * there is no longer any reason for DMA, so
+				 * disable it.
+				 */
+				if (!(port->ip_notify
+						& (N_DATA_READY | N_DDCD))) {
+					BUG_ON(!(port->ip_sscr
+							& IOC4_SSCR_DMA_EN));
+					port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+					writel(port->ip_sscr,
+					   &port->ip_serial_regs->sscr);
+				}
+
+				/* Prevent infinite tx_mt interrupt */
+				port->ip_ienb &= ~hooks->intr_tx_mt;
+			}
+		}
+		sio_ir = PENDING(port);
+
+		/* if the read was aborted and only hooks->intr_rx_high,
+		 * clear hooks->intr_rx_high, so we do not loop forever.
+		 */
+
+		if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+			sio_ir &= ~hooks->intr_rx_high;
+		}
+	} while (sio_ir & hooks->intr_all);
+
+	spin_unlock_irqrestore(&port->ip_lock, flags);
+
+	/* Re-enable interrupts before returning from interrupt handler.
+	 * Getting interrupted here is okay.  It'll just v() our semaphore, and
+	 * we'll come through the loop again.
+	 */
+
+	write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
+							IOC4_SIO_INTR_TYPE);
+}
+
+/*
+ * ioc4_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+	struct uart_icount *icount;
+
+	icount = &the_port->icount;
+
+	if (ncs & NCS_BREAK)
+		icount->brk++;
+	if (ncs & NCS_FRAMING)
+		icount->frame++;
+	if (ncs & NCS_OVERRUN)
+		icount->overrun++;
+	if (ncs & NCS_PARITY)
+		icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *			actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, unsigned char *buf,
+				int len)
+{
+	int prod_ptr, cons_ptr, total;
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	struct ring *inring;
+	struct ring_entry *entry;
+	struct hooks *hooks = port->ip_hooks;
+	int byte_num;
+	char *sc;
+	int loop_counter;
+
+	BUG_ON(!(len >= 0));
+	BUG_ON(!port);
+
+	/* There is a nasty timing issue in the IOC4. When the rx_timer
+	 * expires or the rx_high condition arises, we take an interrupt.
+	 * At some point while servicing the interrupt, we read bytes from
+	 * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+	 * not started until the first byte is received *after* it is armed,
+	 * and any bytes pending in the rx construction buffers are not drained
+	 * to memory until either there are 4 bytes available or the rx_timer
+	 * expires.  This leads to a potential situation where data is left
+	 * in the construction buffers forever - 1 to 3 bytes were received
+	 * after the interrupt was generated but before the rx_timer was
+	 * re-armed. At that point as long as no subsequent bytes are received
+	 * the timer will never be started and the bytes will remain in the
+	 * construction buffer forever.  The solution is to execute a DRAIN
+	 * command after rearming the timer.  This way any bytes received before
+	 * the DRAIN will be drained to memory, and any bytes received after
+	 * the DRAIN will start the TIMER and be drained when it expires.
+	 * Luckily, this only needs to be done when the DMA buffer is empty
+	 * since there is no requirement that this function return all
+	 * available data as long as it returns some.
+	 */
+	/* Re-arm the timer */
+	writel(port->ip_rx_cons | IOC4_SRCIR_ARM,
+			&port->ip_serial_regs->srcir);
+
+	prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+	cons_ptr = port->ip_rx_cons;
+
+	if (prod_ptr == cons_ptr) {
+		int reset_dma = 0;
+
+		/* Input buffer appears empty, do a flush. */
+
+		/* DMA must be enabled for this to work. */
+		if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+			port->ip_sscr |= IOC4_SSCR_DMA_EN;
+			reset_dma = 1;
+		}
+
+		/* Potential race condition: we must reload the srpir after
+		 * issuing the drain command, otherwise we could think the rx
+		 * buffer is empty, then take a very long interrupt, and when
+		 * we come back it's full and we wait forever for the drain to
+		 * complete.
+		 */
+		writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
+				&port->ip_serial_regs->sscr);
+		prod_ptr = readl(&port->ip_serial_regs->srpir)
+				& PROD_CONS_MASK;
+
+		/* We must not wait for the DRAIN to complete unless there are
+		 * at least 8 bytes (2 ring entries) available to receive the
+		 * data otherwise the DRAIN will never complete and we'll
+		 * deadlock here.
+		 * In fact, to make things easier, I'll just ignore the flush if
+		 * there is any data at all now available.
+		 */
+		if (prod_ptr == cons_ptr) {
+			loop_counter = 0;
+			while (readl(&port->ip_serial_regs->sscr) &
+						IOC4_SSCR_RX_DRAIN) {
+				loop_counter++;
+				if (loop_counter > MAXITER)
+					return -1;
+			}
+
+			/* SIGH. We have to reload the prod_ptr *again* since
+			 * the drain may have caused it to change
+			 */
+			prod_ptr = readl(&port->ip_serial_regs->srpir)
+							& PROD_CONS_MASK;
+		}
+		if (reset_dma) {
+			port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+			writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+		}
+	}
+	inring = port->ip_inring;
+	port->ip_flags &= ~READ_ABORTED;
+
+	total = 0;
+	loop_counter = 0xfffff;	/* to avoid hangs */
+
+	/* Grab bytes from the hardware */
+	while ((prod_ptr != cons_ptr) && (len > 0)) {
+		entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
+
+		if ( loop_counter-- <= 0 ) {
+			printk(KERN_WARNING "IOC4 serial: "
+					"possible hang condition/"
+					"port stuck on read.\n");
+			break;
+		}
+
+		/* According to the producer pointer, this ring entry
+		 * must contain some data.  But if the PIO happened faster
+		 * than the DMA, the data may not be available yet, so let's
+		 * wait until it arrives.
+		 */
+		if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+			/* Indicate the read is aborted so we don't disable
+			 * the interrupt thinking that the consumer is
+			 * congested.
+			 */
+			port->ip_flags |= READ_ABORTED;
+			len = 0;
+			break;
+		}
+
+		/* Load the bytes/status out of the ring entry */
+		for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+			sc = &(entry->ring_sc[byte_num]);
+
+			/* Check for change in modem state or overrun */
+			if ((*sc & IOC4_RXSB_MODEM_VALID)
+						&& (port->ip_notify & N_DDCD)) {
+				/* Notify upper layer if DCD dropped */
+
+				if ((port->ip_flags & DCD_ON)
+						&& !(*sc & IOC4_RXSB_DCD)) {
+
+					/* If we have already copied some data,
+					 * return it.  We'll pick up the carrier
+					 * drop on the next pass.  That way we
+					 * don't throw away the data that has
+					 * already been copied back to
+					 * the caller's buffer.
+					 */
+					if (total > 0) {
+						len = 0;
+						break;
+					}
+					port->ip_flags &= ~DCD_ON;
+
+					/* Turn off this notification so the
+					 * carrier drop protocol won't see it
+					 * again when it does a read.
+					 */
+					*sc &= ~IOC4_RXSB_MODEM_VALID;
+
+					/* To keep things consistent, we need
+					 * to update the consumer pointer so
+					 * the next reader won't come in and
+					 * try to read the same ring entries
+					 * again. This must be done here before
+					 * the dcd change.
+					 */
+
+					if ((entry->ring_allsc & RING_ANY_VALID)
+									== 0) {
+						cons_ptr += (int)sizeof
+							(struct ring_entry);
+						cons_ptr &= PROD_CONS_MASK;
+					}
+					writel(cons_ptr,
+						&port->ip_serial_regs->srcir);
+					port->ip_rx_cons = cons_ptr;
+
+					/* Notify upper layer of carrier drop */
+					if ((port->ip_notify & N_DDCD)
+						   && port->ip_port) {
+						the_port->icount.dcd = 0;
+						wake_up_interruptible
+						    (&the_port->info->
+							delta_msr_wait);
+					}
+
+					/* If we had any data to return, we
+					 * would have returned it above.
+					 */
+					return 0;
+				}
+			}
+			if (*sc & IOC4_RXSB_MODEM_VALID) {
+				/* Notify that an input overrun occurred */
+				if ((*sc & IOC4_RXSB_OVERRUN)
+				    && (port->ip_notify & N_OVERRUN_ERROR)) {
+					ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
+				}
+				/* Don't look at this byte again */
+				*sc &= ~IOC4_RXSB_MODEM_VALID;
+			}
+
+			/* Check for valid data or RX errors */
+			if ((*sc & IOC4_RXSB_DATA_VALID) &&
+					((*sc & (IOC4_RXSB_PAR_ERR
+							| IOC4_RXSB_FRAME_ERR
+							| IOC4_RXSB_BREAK))
+					&& (port->ip_notify & (N_PARITY_ERROR
+							| N_FRAMING_ERROR
+							| N_BREAK)))) {
+				/* There is an error condition on the next byte.
+				 * If we have already transferred some bytes,
+				 * we'll stop here. Otherwise if this is the
+				 * first byte to be read, we'll just transfer
+				 * it alone after notifying the
+				 * upper layer of its status.
+				 */
+				if (total > 0) {
+					len = 0;
+					break;
+				} else {
+					if ((*sc & IOC4_RXSB_PAR_ERR) &&
+					   (port->ip_notify & N_PARITY_ERROR)) {
+						ioc4_cb_post_ncs(the_port,
+								NCS_PARITY);
+					}
+					if ((*sc & IOC4_RXSB_FRAME_ERR) &&
+					   (port->ip_notify & N_FRAMING_ERROR)){
+						ioc4_cb_post_ncs(the_port,
+								NCS_FRAMING);
+					}
+					if ((*sc & IOC4_RXSB_BREAK)
+					    && (port->ip_notify & N_BREAK)) {
+							ioc4_cb_post_ncs
+								    (the_port,
+								     NCS_BREAK);
+					}
+					len = 1;
+				}
+			}
+			if (*sc & IOC4_RXSB_DATA_VALID) {
+				*sc &= ~IOC4_RXSB_DATA_VALID;
+				*buf = entry->ring_data[byte_num];
+				buf++;
+				len--;
+				total++;
+			}
+		}
+
+		/* If we used up this entry entirely, go on to the next one,
+		 * otherwise we must have run out of buffer space, so
+		 * leave the consumer pointer here for the next read in case
+		 * there are still unread bytes in this entry.
+		 */
+		if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+			cons_ptr += (int)sizeof(struct ring_entry);
+			cons_ptr &= PROD_CONS_MASK;
+		}
+	}
+
+	/* Update consumer pointer and re-arm rx timer interrupt */
+	writel(cons_ptr, &port->ip_serial_regs->srcir);
+	port->ip_rx_cons = cons_ptr;
+
+	/* If we have now dipped below the rx high water mark and we have
+	 * rx_high interrupt turned off, we can now turn it back on again.
+	 */
+	if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+			& PROD_CONS_MASK) < ((port->ip_sscr &
+				IOC4_SSCR_RX_THRESHOLD)
+					<< IOC4_PROD_CONS_PTR_OFF))) {
+		port->ip_flags &= ~INPUT_HIGH;
+		enable_intrs(port, hooks->intr_rx_high);
+	}
+	return total;
+}
+/**
+ * receive_chars - upper level read. Called with ip_lock.
+ * @the_port: port to read from
+ */
+static void receive_chars(struct uart_port *the_port)
+{
+	struct tty_struct *tty;
+	unsigned char ch[IOC4_MAX_CHARS];
+	int read_count, request_count;
+	struct uart_icount *icount;
+	struct uart_info *info = the_port->info;
+
+	/* Make sure all the pointers are "good" ones */
+	if (!info)
+		return;
+	if (!info->tty)
+		return;
+
+	tty = info->tty;
+
+	request_count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
+
+	if (request_count > 0) {
+		if (request_count > IOC4_MAX_CHARS - 2)
+			request_count = IOC4_MAX_CHARS - 2;
+		icount = &the_port->icount;
+		read_count = do_read(the_port, ch, request_count);
+		if (read_count > 0) {
+			memcpy(tty->flip.char_buf_ptr, ch, read_count);
+			memset(tty->flip.flag_buf_ptr, TTY_NORMAL, read_count);
+			tty->flip.char_buf_ptr += read_count;
+			tty->flip.flag_buf_ptr += read_count;
+			tty->flip.count += read_count;
+			icount->rx += read_count;
+		}
+	}
+	tty_flip_buffer_push(tty);
+}
+
+/**
+ * ic4_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic4_type(struct uart_port *the_port)
+{
+	return "SGI IOC4 Serial";
+}
+
+/**
+ * ic4_tx_empty - Is the transmitter empty?  We pretend we're always empty
+ * @port: Port to operate on (we ignore since we always return 1)
+ *
+ */
+static unsigned int ic4_tx_empty(struct uart_port *the_port)
+{
+	return 1;
+}
+
+/**
+ * ic4_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ * @tty_stop: Set to 1 if called via uart_stop
+ *
+ */
+static void ic4_stop_tx(struct uart_port *the_port, unsigned int tty_stop)
+{
+}
+
+/**
+ * null_void_function -
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic4_shutdown - shut down the port - free irq and disable
+ * @port: Port to shut down
+ *
+ */
+static void ic4_shutdown(struct uart_port *the_port)
+{
+	unsigned long port_flags;
+	struct ioc4_port *port;
+	struct uart_info *info;
+
+	port = get_ioc4_port(the_port);
+	if (!port)
+		return;
+
+	info = the_port->info;
+
+	if (!(info->flags & UIF_INITIALIZED))
+		return;
+
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	spin_lock_irqsave(&port->ip_lock, port_flags);
+	set_notification(port, N_ALL, 0);
+	info->flags &= ~UIF_INITIALIZED;
+	spin_unlock_irqrestore(&port->ip_lock, port_flags);
+}
+
+/**
+ * ic4_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+	unsigned char mcr = 0;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	set_mcr(the_port, 1, mcr, IOC4_SHADOW_DTR);
+}
+
+/**
+ * ic4_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic4_get_mctrl(struct uart_port *the_port)
+{
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	uint32_t shadow;
+	unsigned int ret = 0;
+
+	if (!port)
+		return 0;
+
+	shadow = readl(&port->ip_serial_regs->shadow);
+	if (shadow & IOC4_SHADOW_DCD)
+		ret |= TIOCM_CAR;
+	if (shadow & IOC4_SHADOW_DR)
+		ret |= TIOCM_DSR;
+	if (shadow & IOC4_SHADOW_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+/**
+ * ic4_start_tx - Start transmitter, flush any output
+ * @port: Port to operate on
+ * @tty_stop: Set to 1 if called via uart_start
+ *
+ */
+static void ic4_start_tx(struct uart_port *the_port, unsigned int tty_stop)
+{
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	unsigned long flags;
+
+	if (port) {
+		spin_lock_irqsave(&port->ip_lock, flags);
+		transmit_chars(the_port);
+		spin_unlock_irqrestore(&port->ip_lock, flags);
+	}
+}
+
+/**
+ * ic4_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic4_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic4_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int ic4_startup(struct uart_port *the_port)
+{
+	int retval;
+	struct ioc4_port *port;
+	struct ioc4_control *control;
+	struct uart_info *info;
+	unsigned long port_flags;
+
+	if (!the_port) {
+		return -ENODEV;
+	}
+	port = get_ioc4_port(the_port);
+	if (!port) {
+		return -ENODEV;
+	}
+	info = the_port->info;
+
+	control = port->ip_control;
+	if (!control) {
+		return -ENODEV;
+	}
+
+	/* Start up the serial port */
+	spin_lock_irqsave(&port->ip_lock, port_flags);
+	retval = ic4_startup_local(the_port);
+	spin_unlock_irqrestore(&port->ip_lock, port_flags);
+	return retval;
+}
+
+/**
+ * ic4_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic4_set_termios(struct uart_port *the_port,
+		struct termios *termios, struct termios *old_termios)
+{
+	struct ioc4_port *port = get_ioc4_port(the_port);
+	unsigned long port_flags;
+
+	spin_lock_irqsave(&port->ip_lock, port_flags);
+	ioc4_change_speed(the_port, termios, old_termios);
+	spin_unlock_irqrestore(&port->ip_lock, port_flags);
+}
+
+/**
+ * ic4_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic4_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops ioc4_ops = {
+	.tx_empty	= ic4_tx_empty,
+	.set_mctrl	= ic4_set_mctrl,
+	.get_mctrl	= ic4_get_mctrl,
+	.stop_tx	= ic4_stop_tx,
+	.start_tx	= ic4_start_tx,
+	.stop_rx	= null_void_function,
+	.enable_ms	= null_void_function,
+	.break_ctl	= ic4_break_ctl,
+	.startup	= ic4_startup,
+	.shutdown	= ic4_shutdown,
+	.set_termios	= ic4_set_termios,
+	.type		= ic4_type,
+	.release_port	= null_void_function,
+	.request_port	= ic4_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc4_uart = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "ioc4_serial",
+	.dev_name	= DEVICE_NAME,
+	.major		= DEVICE_MAJOR,
+	.minor		= DEVICE_MINOR,
+	.nr		= IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+/**
+ * ioc4_serial_core_attach - register with serial core
+ *		This is done during pci probing
+ * @pdev: handle for this card
+ */
+static inline int
+ioc4_serial_core_attach(struct pci_dev *pdev)
+{
+	struct ioc4_port *port;
+	struct uart_port *the_port;
+	struct ioc4_control *control = pci_get_drvdata(pdev);
+	int ii;
+
+	DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
+			__FUNCTION__, pdev, (void *)control));
+
+	if (!control)
+		return -ENODEV;
+
+	/* once around for each port on this card */
+	for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
+		the_port = &control->ic_port[ii].icp_uart_port;
+		port = control->ic_port[ii].icp_port;
+		port->ip_port = the_port;
+
+		DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p\n",
+				__FUNCTION__, (void *)the_port,
+				(void *)port));
+
+		spin_lock_init(&the_port->lock);
+		/* membase, iobase and mapbase just need to be non-0 */
+		the_port->membase = (unsigned char __iomem *)1;
+		the_port->line = the_port->iobase = ii;
+		the_port->mapbase = 1;
+		the_port->type = PORT_16550A;
+		the_port->fifosize = IOC4_MAX_CHARS;
+		the_port->ops = &ioc4_ops;
+		the_port->irq = control->ic_irq;
+		the_port->dev = &pdev->dev;
+		if (uart_add_one_port(&ioc4_uart, the_port) < 0) {
+			printk(KERN_WARNING
+				       "%s: unable to add port %d\n",
+				       __FUNCTION__, the_port->line);
+		} else {
+			DPRINT_CONFIG(
+				    ("IOC4 serial driver port %d irq = %d\n",
+				       the_port->line, the_port->irq));
+		}
+		/* all ports are rs232 for now */
+		ioc4_set_proto(port, PROTO_RS232);
+	}
+	return 0;
+}
+
+/**
+ * ioc4_serial_attach_one - register attach function
+ *		called per card found from ioc4_serial_detect as part
+ *		of module_init().
+ * @pdev: handle for this card
+ * @pci_id: pci id for this card
+ */
+int
+ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+	struct ioc4_mem __iomem *mem;
+	unsigned long tmp_addr, tmp_addr1;
+	struct ioc4_serial __iomem *serial;
+	struct ioc4_soft *soft;
+	struct ioc4_control *control;
+	int tmp, ret = 0;
+
+
+	DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, pdev, pci_id));
+
+	/* Map in the ioc4 memory */
+	tmp_addr = pci_resource_start(pdev, 0);
+	if (!tmp_addr) {
+		printk(KERN_WARNING
+			 "ioc4 (%p) : unable to get PIO mapping for "
+				"MEM space\n", (void *)pdev);
+		return -ENODEV;
+	}
+	if (!request_region(tmp_addr, sizeof(struct ioc4_mem), "sioc4_mem")) {
+		printk(KERN_ALERT
+			"ioc4 (%p): unable to get request region for "
+			"MEM space\n", (void *)pdev);
+		return -ENODEV;
+	}
+	mem = ioremap(tmp_addr, sizeof(struct ioc4_mem));
+	if (!mem) {
+		printk(KERN_WARNING
+			 "ioc4 (%p) : unable to remap ioc4 memory\n",
+				(void *)pdev);
+		ret = -ENODEV;
+		goto out1;
+	}
+
+	/* request serial registers */
+	tmp_addr1 = pci_resource_start(pdev, 0) + IOC4_SERIAL_OFFSET;
+
+	if (!request_region(tmp_addr1, sizeof(struct ioc4_serial),
+					"sioc4_uart")) {
+		printk(KERN_WARNING
+			"ioc4 (%p): unable to get request region for "
+				"uart space\n", (void *)pdev);
+		ret = -ENODEV;
+		goto out1;
+	}
+	serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
+	if (!serial) {
+		printk(KERN_WARNING
+			 "ioc4 (%p) : unable to remap ioc4 serial register\n",
+				(void *)pdev);
+		ret = -ENODEV;
+		goto out2;
+	}
+	DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
+				__FUNCTION__, (void *)mem, (void *)serial));
+
+	/* Get memory for the new card */
+	control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS,
+						GFP_KERNEL);
+
+	if (!control) {
+		printk(KERN_WARNING "ioc4_attach_one"
+		       ": unable to get memory for the IOC4\n");
+		ret = -ENOMEM;
+		goto out2;
+	}
+	memset(control, 0, sizeof(struct ioc4_control));
+	pci_set_drvdata(pdev, control);
+
+	/* Allocate the soft structure */
+	soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
+	if (!soft) {
+		printk(KERN_WARNING
+		       "ioc4 (%p): unable to get memory for the soft struct\n",
+		       (void *)pdev);
+		ret = -ENOMEM;
+		goto out3;
+	}
+	memset(soft, 0, sizeof(struct ioc4_soft));
+
+	spin_lock_init(&soft->is_ir_lock);
+	soft->is_ioc4_mem_addr = mem;
+	soft->is_ioc4_serial_addr = serial;
+
+	/* Init the IOC4 */
+	pci_read_config_dword(pdev, PCI_COMMAND, &tmp);
+	pci_write_config_dword(pdev, PCI_COMMAND,
+			       tmp | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+	writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, &mem->sio_cr);
+
+	/* Enable serial port mode select generic PIO pins as outputs */
+	writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
+		| IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
+		&mem->gpcr_s);
+
+	/* Clear and disable all interrupts */
+	write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+	writel(~0, &mem->sio_ir);
+	write_ireg(soft, ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR),
+			IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
+	writel(~(IOC4_OTHER_IR_ATA_MEMERR | IOC4_OTHER_IR_ATA_MEMERR),
+					&mem->other_ir);
+	control->ic_soft = soft;
+	if (!request_irq(pdev->irq, ioc4_intr, SA_SHIRQ,
+				"sgi-ioc4serial", (void *)soft)) {
+		control->ic_irq = pdev->irq;
+	} else {
+		printk(KERN_WARNING
+		    "%s : request_irq fails for IRQ 0x%x\n ",
+			__FUNCTION__, pdev->irq);
+	}
+	if ((ret = ioc4_attach_local(pdev, control, soft,
+				soft->is_ioc4_mem_addr,
+				soft->is_ioc4_serial_addr)))
+		goto out4;
+
+	/* register port with the serial core */
+
+	if ((ret = ioc4_serial_core_attach(pdev)))
+		goto out4;
+
+	return ret;
+
+	/* error exits that give back resources */
+out4:
+	kfree(soft);
+out3:
+	kfree(control);
+out2:
+	release_region(tmp_addr1, sizeof(struct ioc4_serial));
+out1:
+	release_region(tmp_addr, sizeof(struct ioc4_mem));
+
+	return ret;
+}
+
+
+/**
+ * ioc4_serial_remove_one - detach function
+ *
+ * @pdev: handle for this card
+ */
+
+#if 0
+void ioc4_serial_remove_one(struct pci_dev *pdev)
+{
+	int ii;
+	struct ioc4_control *control;
+	struct uart_port *the_port;
+	struct ioc4_port *port;
+	struct ioc4_soft *soft;
+
+	control = pci_get_drvdata(pdev);
+
+	for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
+		the_port = &control->ic_port[ii].icp_uart_port;
+		if (the_port) {
+			uart_remove_one_port(&ioc4_uart, the_port);
+		}
+		port = control->ic_port[ii].icp_port;
+		if (!(ii & 1) && port) {
+			pci_free_consistent(port->ip_pdev,
+					TOTAL_RING_BUF_SIZE,
+					(void *)port->ip_cpu_ringbuf,
+					port->ip_dma_ringbuf);
+			kfree(port);
+		}
+	}
+	soft = control->ic_soft;
+	if (soft) {
+		free_irq(control->ic_irq, (void *)soft);
+		if (soft->is_ioc4_serial_addr) {
+			release_region((unsigned long)
+			     soft->is_ioc4_serial_addr,
+				sizeof(struct ioc4_serial));
+		}
+		kfree(soft);
+	}
+	kfree(control);
+	pci_set_drvdata(pdev, NULL);
+	uart_unregister_driver(&ioc4_uart);
+}
+#endif
+
+/**
+ * ioc4_serial_init - module init
+ */
+int ioc4_serial_init(void)
+{
+	int ret;
+
+	/* register with serial core */
+	if ((ret = uart_register_driver(&ioc4_uart)) < 0) {
+		printk(KERN_WARNING
+			"%s: Couldn't register IOC4 serial driver\n",
+			__FUNCTION__);
+		return ret;
+	}
+	return 0;
+}
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc4_serial_init);
+EXPORT_SYMBOL(ioc4_serial_attach_one);
diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/serial/jsm/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Jasmine adapter
+#
+
+obj-$(CONFIG_SERIAL_JSM) += jsm.o
+
+jsm-objs :=    jsm_driver.o jsm_neo.o jsm_tty.o
+
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
new file mode 100644
--- /dev/null
+++ b/drivers/serial/jsm/jsm.h
@@ -0,0 +1,398 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+
+#ifndef __JSM_DRIVER_H
+#define __JSM_DRIVER_H
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>	/* To pick up the varions Linux types */
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+enum {
+	DBG_INIT	= 0x01,
+	DBG_BASIC	= 0x02,
+	DBG_CORE	= 0x04,
+	DBG_OPEN	= 0x08,
+	DBG_CLOSE	= 0x10,
+	DBG_READ	= 0x20,
+	DBG_WRITE	= 0x40,
+	DBG_IOCTL	= 0x80,
+	DBG_PROC	= 0x100,
+	DBG_PARAM	= 0x200,
+	DBG_PSCAN	= 0x400,
+	DBG_EVENT	= 0x800,
+	DBG_DRAIN	= 0x1000,
+	DBG_MSIGS	= 0x2000,
+	DBG_MGMT	= 0x4000,
+	DBG_INTR	= 0x8000,
+	DBG_CARR	= 0x10000,
+};
+
+#define jsm_printk(nlevel, klevel, pdev, fmt, args...)	\
+	if ((DBG_##nlevel & jsm_debug))			\
+	dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
+
+#define MAXPORTS	8
+#define MAX_STOPS_SENT	5
+
+/* Board type definitions */
+
+#define T_NEO		0000
+#define T_CLASSIC	0001
+#define T_PCIBUS	0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING	0x0
+#define BD_REASON	0x7f
+#define BD_NOTFOUND	0x1
+#define BD_NOIOPORT	0x2
+#define BD_NOMEM	0x3
+#define BD_NOBIOS	0x4
+#define BD_NOFEP	0x5
+#define BD_FAILED	0x6
+#define BD_ALLOCATED	0x7
+#define BD_TRIBOOT	0x8
+#define BD_BADKME	0x80
+
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN	((4096) + 4)
+#define MYFLIPLEN	N_TTY_BUF_SIZE
+
+#define JSM_VERSION	"jsm: 1.1-1-INKERNEL"
+#define JSM_PARTNUM	"40002438_A-INKERNEL"
+
+struct jsm_board;
+struct jsm_channel;
+
+/************************************************************************
+ * Per board operations structure					*
+ ************************************************************************/
+struct board_ops {
+	irqreturn_t (*intr) (int irq, void *voidbrd, struct pt_regs *regs);
+	void (*uart_init) (struct jsm_channel *ch);
+	void (*uart_off) (struct jsm_channel *ch);
+	void (*param) (struct jsm_channel *ch);
+	void (*assert_modem_signals) (struct jsm_channel *ch);
+	void (*flush_uart_write) (struct jsm_channel *ch);
+	void (*flush_uart_read) (struct jsm_channel *ch);
+	void (*disable_receiver) (struct jsm_channel *ch);
+	void (*enable_receiver) (struct jsm_channel *ch);
+	void (*send_break) (struct jsm_channel *ch);
+	void (*clear_break) (struct jsm_channel *ch, int);
+	void (*send_start_character) (struct jsm_channel *ch);
+	void (*send_stop_character) (struct jsm_channel *ch);
+	void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
+	u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
+	void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
+};
+
+
+/*
+ *	Per-board information
+ */
+struct jsm_board
+{
+	int		boardnum;	/* Board number: 0-32 */
+
+	int		type;		/* Type of board */
+	u8		rev;		/* PCI revision ID */
+	struct pci_dev	*pci_dev;
+	u32		maxports;	/* MAX ports this board can handle */
+
+	spinlock_t	bd_lock;	/* Used to protect board */
+
+	spinlock_t	bd_intr_lock;	/* Used to protect the poller tasklet and
+					 * the interrupt routine from each other.
+					 */
+
+	u32		nasync;		/* Number of ports on card */
+
+	u32		irq;		/* Interrupt request number */
+	u64		intr_count;	/* Count of interrupts */
+
+	u64		membase;	/* Start of base memory of the card */
+	u64		membase_end;	/* End of base memory of the card */
+
+	u8	__iomem *re_map_membase;/* Remapped memory of the card */
+
+	u64		iobase;		/* Start of io base of the card */
+	u64		iobase_end;	/* End of io base of the card */
+
+	u32		bd_uart_offset;	/* Space between each UART */
+
+	struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
+	char		*flipbuf;	/* Our flip buffer, alloced if board is found */
+
+	u32		bd_dividend;	/* Board/UARTs specific dividend */
+
+	struct board_ops *bd_ops;
+
+	struct list_head jsm_board_entry;
+};
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON		0x0001		/* Printer on string		*/
+#define CH_STOP		0x0002		/* Output is stopped		*/
+#define CH_STOPI	0x0004		/* Input is stopped		*/
+#define CH_CD		0x0008		/* Carrier is present		*/
+#define CH_FCAR		0x0010		/* Carrier forced on		*/
+#define CH_HANGUP	0x0020		/* Hangup received		*/
+
+#define CH_RECEIVER_OFF	0x0040		/* Receiver is off		*/
+#define CH_OPENING	0x0080		/* Port in fragile open state	*/
+#define CH_CLOSING	0x0100		/* Port in fragile close state	*/
+#define CH_FIFO_ENABLED 0x0200		/* Port has FIFOs enabled	*/
+#define CH_TX_FIFO_EMPTY 0x0400		/* TX Fifo is completely empty	*/
+#define CH_TX_FIFO_LWM	0x0800		/* TX Fifo is below Low Water	*/
+#define CH_BREAK_SENDING 0x1000		/* Break is being sent		*/
+#define CH_LOOPBACK 0x2000		/* Channel is in lookback mode	*/
+#define CH_FLIPBUF_IN_USE 0x4000	/* Channel's flipbuf is in use	*/
+#define CH_BAUD0	0x08000		/* Used for checking B0 transitions */
+
+/* Our Read/Error/Write queue sizes */
+#define RQUEUEMASK	0x1FFF		/* 8 K - 1 */
+#define EQUEUEMASK	0x1FFF		/* 8 K - 1 */
+#define WQUEUEMASK	0x0FFF		/* 4 K - 1 */
+#define RQUEUESIZE	(RQUEUEMASK + 1)
+#define EQUEUESIZE	RQUEUESIZE
+#define WQUEUESIZE	(WQUEUEMASK + 1)
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct jsm_channel {
+	struct uart_port uart_port;
+	struct jsm_board	*ch_bd;		/* Board structure pointer	*/
+
+	spinlock_t	ch_lock;	/* provide for serialization */
+	wait_queue_head_t ch_flags_wait;
+
+	u32		ch_portnum;	/* Port number, 0 offset.	*/
+	u32		ch_open_count;	/* open count			*/
+	u32		ch_flags;	/* Channel flags		*/
+
+	u64		ch_close_delay;	/* How long we should drop RTS/DTR for */
+
+	u64		ch_cpstime;	/* Time for CPS calculations	*/
+
+	tcflag_t	ch_c_iflag;	/* channel iflags		*/
+	tcflag_t	ch_c_cflag;	/* channel cflags		*/
+	tcflag_t	ch_c_oflag;	/* channel oflags		*/
+	tcflag_t	ch_c_lflag;	/* channel lflags		*/
+	u8		ch_stopc;	/* Stop character		*/
+	u8		ch_startc;	/* Start character		*/
+
+	u32		ch_old_baud;	/* Cache of the current baud */
+	u32		ch_custom_speed;/* Custom baud, if set */
+
+	u32		ch_wopen;	/* Waiting for open process cnt */
+
+	u8		ch_mostat;	/* FEP output modem status	*/
+	u8		ch_mistat;	/* FEP input modem status	*/
+
+	struct neo_uart_struct __iomem *ch_neo_uart;	/* Pointer to the "mapped" UART struct */
+	u8		ch_cached_lsr;	/* Cached value of the LSR register */
+
+	u8		*ch_rqueue;	/* Our read queue buffer - malloc'ed */
+	u16		ch_r_head;	/* Head location of the read queue */
+	u16		ch_r_tail;	/* Tail location of the read queue */
+
+	u8		*ch_equeue;	/* Our error queue buffer - malloc'ed */
+	u16		ch_e_head;	/* Head location of the error queue */
+	u16		ch_e_tail;	/* Tail location of the error queue */
+
+	u8		*ch_wqueue;	/* Our write queue buffer - malloc'ed */
+	u16		ch_w_head;	/* Head location of the write queue */
+	u16		ch_w_tail;	/* Tail location of the write queue */
+
+	u64		ch_rxcount;	/* total of data received so far */
+	u64		ch_txcount;	/* total of data transmitted so far */
+
+	u8		ch_r_tlevel;	/* Receive Trigger level */
+	u8		ch_t_tlevel;	/* Transmit Trigger level */
+
+	u8		ch_r_watermark;	/* Receive Watermark */
+
+
+	u32		ch_stops_sent;	/* How many times I have sent a stop character
+					 * to try to stop the other guy sending.
+					 */
+	u64		ch_err_parity;	/* Count of parity errors on channel */
+	u64		ch_err_frame;	/* Count of framing errors on channel */
+	u64		ch_err_break;	/* Count of breaks on channel */
+	u64		ch_err_overrun; /* Count of overruns on channel */
+
+	u64		ch_xon_sends;	/* Count of xons transmitted */
+	u64		ch_xoff_sends;	/* Count of xoffs transmitted */
+};
+
+
+/************************************************************************
+ * Per channel/port NEO UART structure					*
+ ************************************************************************
+ *		Base Structure Entries Usage Meanings to Host		*
+ *									*
+ *	W = read write		R = read only				*
+ *			U = Unused.					*
+ ************************************************************************/
+
+struct neo_uart_struct {
+	 u8 txrx;		/* WR	RHR/THR - Holding Reg */
+	 u8 ier;		/* WR	IER - Interrupt Enable Reg */
+	 u8 isr_fcr;		/* WR	ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+	 u8 lcr;		/* WR	LCR - Line Control Reg */
+	 u8 mcr;		/* WR	MCR - Modem Control Reg */
+	 u8 lsr;		/* WR	LSR - Line Status Reg */
+	 u8 msr;		/* WR	MSR - Modem Status Reg */
+	 u8 spr;		/* WR	SPR - Scratch Pad Reg */
+	 u8 fctr;		/* WR	FCTR - Feature Control Reg */
+	 u8 efr;		/* WR	EFR - Enhanced Function Reg */
+	 u8 tfifo;		/* WR	TXCNT/TXTRG - Transmit FIFO Reg */
+	 u8 rfifo;		/* WR	RXCNT/RXTRG - Recieve FIFO Reg */
+	 u8 xoffchar1;	/* WR	XOFF 1 - XOff Character 1 Reg */
+	 u8 xoffchar2;	/* WR	XOFF 2 - XOff Character 2 Reg */
+	 u8 xonchar1;	/* WR	XON 1 - Xon Character 1 Reg */
+	 u8 xonchar2;	/* WR	XON 2 - XOn Character 2 Reg */
+
+	 u8 reserved1[0x2ff - 0x200]; /* U	Reserved by Exar */
+	 u8 txrxburst[64];	/* RW	64 bytes of RX/TX FIFO Data */
+	 u8 reserved2[0x37f - 0x340]; /* U	Reserved by Exar */
+	 u8 rxburst_with_errors[64];	/* R	64 bytes of RX FIFO Data + LSR */
+};
+
+/* Where to read the extended interrupt register (32bits instead of 8bits) */
+#define	UART_17158_POLL_ADDR_OFFSET	0x80
+
+/*
+ * These are the redefinitions for the FCTR on the XR17C158, since
+ * Exar made them different than their earlier design. (XR16C854)
+ */
+
+/* These are only applicable when table D is selected */
+#define UART_17158_FCTR_RTS_NODELAY	0x00
+#define UART_17158_FCTR_RTS_4DELAY	0x01
+#define UART_17158_FCTR_RTS_6DELAY	0x02
+#define UART_17158_FCTR_RTS_8DELAY	0x03
+#define UART_17158_FCTR_RTS_12DELAY	0x12
+#define UART_17158_FCTR_RTS_16DELAY	0x05
+#define UART_17158_FCTR_RTS_20DELAY	0x13
+#define UART_17158_FCTR_RTS_24DELAY	0x06
+#define UART_17158_FCTR_RTS_28DELAY	0x14
+#define UART_17158_FCTR_RTS_32DELAY	0x07
+#define UART_17158_FCTR_RTS_36DELAY	0x16
+#define UART_17158_FCTR_RTS_40DELAY	0x08
+#define UART_17158_FCTR_RTS_44DELAY	0x09
+#define UART_17158_FCTR_RTS_48DELAY	0x10
+#define UART_17158_FCTR_RTS_52DELAY	0x11
+
+#define UART_17158_FCTR_RTS_IRDA	0x10
+#define UART_17158_FCTR_RS485		0x20
+#define UART_17158_FCTR_TRGA		0x00
+#define UART_17158_FCTR_TRGB		0x40
+#define UART_17158_FCTR_TRGC		0x80
+#define UART_17158_FCTR_TRGD		0xC0
+
+/* 17158 trigger table selects.. */
+#define UART_17158_FCTR_BIT6		0x40
+#define UART_17158_FCTR_BIT7		0x80
+
+/* 17158 TX/RX memmapped buffer offsets */
+#define UART_17158_RX_FIFOSIZE		64
+#define UART_17158_TX_FIFOSIZE		64
+
+/* 17158 Extended IIR's */
+#define UART_17158_IIR_RDI_TIMEOUT	0x0C	/* Receiver data TIMEOUT */
+#define UART_17158_IIR_XONXOFF		0x10	/* Received an XON/XOFF char */
+#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20	/* CTS/DSR or RTS/DTR state change */
+#define UART_17158_IIR_FIFO_ENABLED	0xC0	/* 16550 FIFOs are Enabled */
+
+/*
+ * These are the extended interrupts that get sent
+ * back to us from the UART's 32bit interrupt register
+ */
+#define UART_17158_RX_LINE_STATUS	0x1	/* RX Ready */
+#define UART_17158_RXRDY_TIMEOUT	0x2	/* RX Ready Timeout */
+#define UART_17158_TXRDY		0x3	/* TX Ready */
+#define UART_17158_MSR			0x4	/* Modem State Change */
+#define UART_17158_TX_AND_FIFO_CLR	0x40	/* Transmitter Holding Reg Empty */
+#define UART_17158_RX_FIFO_DATA_ERROR	0x80	/* UART detected an RX FIFO Data error */
+
+/*
+ * These are the EXTENDED definitions for the 17C158's Interrupt
+ * Enable Register.
+ */
+#define UART_17158_EFR_ECB	0x10	/* Enhanced control bit */
+#define UART_17158_EFR_IXON	0x2	/* Receiver compares Xon1/Xoff1 */
+#define UART_17158_EFR_IXOFF	0x8	/* Transmit Xon1/Xoff1 */
+#define UART_17158_EFR_RTSDTR	0x40	/* Auto RTS/DTR Flow Control Enable */
+#define UART_17158_EFR_CTSDSR	0x80	/* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_17158_XOFF_DETECT	0x1	/* Indicates whether chip saw an incoming XOFF char */
+#define UART_17158_XON_DETECT	0x2	/* Indicates whether chip saw an incoming XON char */
+
+#define UART_17158_IER_RSVD1	0x10	/* Reserved by Exar */
+#define UART_17158_IER_XOFF	0x20	/* Xoff Interrupt Enable */
+#define UART_17158_IER_RTSDTR	0x40	/* Output Interrupt Enable */
+#define UART_17158_IER_CTSDSR	0x80	/* Input Interrupt Enable */
+
+#define PCI_DEVICE_NEO_2DB9_PCI_NAME		"Neo 2 - DB9 Universal PCI"
+#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME		"Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_2RJ45_PCI_NAME		"Neo 2 - RJ45 Universal PCI"
+#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME	"Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+
+/*
+ * Our Global Variables.
+ */
+extern struct	uart_driver jsm_uart_driver;
+extern struct	board_ops jsm_neo_ops;
+extern int	jsm_debug;
+extern int	jsm_rawreadok;
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+int jsm_tty_write(struct uart_port *port);
+int jsm_tty_init(struct jsm_board *);
+int jsm_uart_port_init(struct jsm_board *);
+int jsm_remove_uart_port(struct jsm_board *);
+void jsm_input(struct jsm_channel *ch);
+void jsm_check_queue_flow_control(struct jsm_channel *ch);
+
+#endif
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
new file mode 100644
--- /dev/null
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -0,0 +1,246 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+
+#include "jsm.h"
+
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International "
+		   "Neo PCI based product line");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("jsm");
+
+#define JSM_DRIVER_NAME "jsm"
+#define NR_PORTS	32
+#define JSM_MINOR_START	0
+
+struct uart_driver jsm_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= JSM_DRIVER_NAME,
+	.dev_name	= "ttyn",
+	.major		= 253,
+	.minor		= JSM_MINOR_START,
+	.nr		= NR_PORTS,
+};
+
+int jsm_debug;
+int jsm_rawreadok;
+module_param(jsm_debug, int, 0);
+module_param(jsm_rawreadok, int, 0);
+MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
+MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input");
+
+static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc = 0;
+	struct jsm_board *brd;
+	static int adapter_count = 0;
+	int retval;
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_err(&pdev->dev, "Device enable FAILED\n");
+		goto out;
+	}
+
+	rc = pci_request_regions(pdev, "jsm");
+	if (rc) {
+		dev_err(&pdev->dev, "pci_request_region FAILED\n");
+		goto out_disable_device;
+	}
+
+	brd = kmalloc(sizeof(struct jsm_board), GFP_KERNEL);
+	if (!brd) {
+		dev_err(&pdev->dev,
+			"memory allocation for board structure failed\n");
+		rc = -ENOMEM;
+		goto out_release_regions;
+	}
+	memset(brd, 0, sizeof(struct jsm_board));
+
+	/* store the info for the board we've found */
+	brd->boardnum = adapter_count++;
+	brd->pci_dev = pdev;
+	brd->maxports = 2;
+
+	spin_lock_init(&brd->bd_lock);
+	spin_lock_init(&brd->bd_intr_lock);
+
+	/* store which revision we have */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+	brd->irq = pdev->irq;
+
+	jsm_printk(INIT, INFO, &brd->pci_dev,
+		"jsm_found_board - NEO adapter\n");
+
+	/* get the PCI Base Address Registers */
+	brd->membase	= pci_resource_start(pdev, 0);
+	brd->membase_end = pci_resource_end(pdev, 0);
+
+	if (brd->membase & 1)
+		brd->membase &= ~3;
+	else
+		brd->membase &= ~15;
+
+	/* Assign the board_ops struct */
+	brd->bd_ops = &jsm_neo_ops;
+
+	brd->bd_uart_offset = 0x200;
+	brd->bd_dividend = 921600;
+
+	brd->re_map_membase = ioremap(brd->membase, 0x1000);
+	if (!brd->re_map_membase) {
+		dev_err(&pdev->dev,
+			"card has no PCI Memory resources, "
+			"failing board.\n");
+		rc = -ENOMEM;
+		goto out_kfree_brd;
+	}
+
+	rc = request_irq(brd->irq, brd->bd_ops->intr,
+			SA_INTERRUPT|SA_SHIRQ, "JSM", brd);
+	if (rc) {
+		printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
+		goto out_iounmap;
+	}
+
+	rc = jsm_tty_init(brd);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
+		retval = -ENXIO;
+		goto out_free_irq;
+	}
+
+	rc = jsm_uart_port_init(brd);
+	if (rc < 0) {
+		/* XXX: leaking all resources from jsm_tty_init here! */
+		dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
+		retval = -ENXIO;
+		goto out_free_irq;
+	}
+
+	/* Log the information about the board */
+	dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
+			adapter_count, brd->rev, brd->irq);
+
+	/*
+	 * allocate flip buffer for board.
+	 *
+	 * Okay to malloc with GFP_KERNEL, we are not at interrupt
+	 * context, and there are no locks held.
+	 */
+	brd->flipbuf = kmalloc(MYFLIPLEN, GFP_KERNEL);
+	if (!brd->flipbuf) {
+		/* XXX: leaking all resources from jsm_tty_init and
+		 	jsm_uart_port_init here! */
+		dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
+		retval = -ENOMEM;
+		goto out_free_irq;
+	}
+	memset(brd->flipbuf, 0, MYFLIPLEN);
+
+	pci_set_drvdata(pdev, brd);
+
+	return 0;
+ out_free_irq:
+	free_irq(brd->irq, brd);
+ out_iounmap:
+	iounmap(brd->re_map_membase);
+ out_kfree_brd:
+	kfree(brd);
+ out_release_regions:
+	pci_release_regions(pdev);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return rc;
+}
+
+static void jsm_remove_one(struct pci_dev *pdev)
+{
+	struct jsm_board *brd = pci_get_drvdata(pdev);
+	int i = 0;
+
+	jsm_remove_uart_port(brd);
+
+	free_irq(brd->irq, brd);
+	iounmap(brd->re_map_membase);
+
+	/* Free all allocated channels structs */
+	for (i = 0; i < brd->maxports; i++) {
+		if (brd->channels[i]) {
+			kfree(brd->channels[i]->ch_rqueue);
+			kfree(brd->channels[i]->ch_equeue);
+			kfree(brd->channels[i]->ch_wqueue);
+			kfree(brd->channels[i]);
+		}
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	kfree(brd->flipbuf);
+	kfree(brd);
+}
+
+static struct pci_device_id jsm_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
+
+static struct pci_driver jsm_driver = {
+	.name		= "jsm",
+	.id_table	= jsm_pci_tbl,
+	.probe		= jsm_probe_one,
+	.remove		= __devexit_p(jsm_remove_one),
+};
+
+static int __init jsm_init_module(void)
+{
+	int rc;
+
+	rc = uart_register_driver(&jsm_uart_driver);
+	if (!rc) {
+		rc = pci_register_driver(&jsm_driver);
+		if (rc)
+			uart_unregister_driver(&jsm_uart_driver);
+	}
+	return rc;
+}
+
+static void __exit jsm_exit_module(void)
+{
+	pci_unregister_driver(&jsm_driver);
+	uart_unregister_driver(&jsm_uart_driver);
+}
+
+module_init(jsm_init_module);
+module_exit(jsm_exit_module);
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
new file mode 100644
--- /dev/null
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -0,0 +1,1427 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/delay.h>	/* For udelay */
+#include <linux/serial_reg.h>	/* For the various UART offsets */
+#include <linux/tty.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "jsm.h"		/* Driver main header file */
+
+static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+/*
+ * This function allows calls to ensure that all outstanding
+ * PCI writes have been completed, by doing a PCI read against
+ * a non-destructive, read-only location on the Neo card.
+ *
+ * In this case, we are reading the DVID (Read-only Device Identification)
+ * value of the Neo card.
+ */
+static inline void neo_pci_posting_flush(struct jsm_board *bd)
+{
+      readb(bd->re_map_membase + 0x8D);
+}
+
+static void neo_set_cts_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
+
+	/* Turn on auto CTS flow control */
+	ier |= (UART_17158_IER_CTSDSR);
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
+
+	/* Turn off auto Xon flow control */
+	efr &= ~(UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+
+	/* Feed the UART our trigger levels */
+	writeb(8, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 8;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_rts_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
+
+	/* Turn on auto RTS flow control */
+	ier |= (UART_17158_IER_RTSDTR);
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
+
+	/* Turn off auto Xoff flow control */
+	ier &= ~(UART_17158_IER_XOFF);
+	efr &= ~(UART_17158_EFR_IXOFF);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+	ch->ch_r_watermark = 4;
+
+	writeb(56, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 56;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	/*
+	 * From the Neo UART spec sheet:
+	 * The auto RTS/DTR function must be started by asserting
+	 * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
+	 * it is enabled.
+	 */
+	ch->ch_mostat |= (UART_MCR_RTS);
+}
+
+
+static void neo_set_ixon_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
+
+	/* Turn off auto CTS flow control */
+	ier &= ~(UART_17158_IER_CTSDSR);
+	efr &= ~(UART_17158_EFR_CTSDSR);
+
+	/* Turn on auto Xon flow control */
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+	ch->ch_r_watermark = 4;
+
+	writeb(32, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 32;
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
+
+	/* Turn off auto RTS flow control */
+	ier &= ~(UART_17158_IER_RTSDTR);
+	efr &= ~(UART_17158_EFR_RTSDTR);
+
+	/* Turn on auto Xoff flow control */
+	ier |= (UART_17158_IER_XOFF);
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	writeb(8, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 8;
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_input_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
+
+	/* Turn off auto RTS flow control */
+	ier &= ~(UART_17158_IER_RTSDTR);
+	efr &= ~(UART_17158_EFR_RTSDTR);
+
+	/* Turn off auto Xoff flow control */
+	ier &= ~(UART_17158_IER_XOFF);
+	if (ch->ch_c_iflag & IXON)
+		efr &= ~(UART_17158_EFR_IXOFF);
+	else
+		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	ch->ch_r_watermark = 0;
+
+	writeb(16, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 16;
+
+	writeb(16, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 16;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_output_flow_control(struct jsm_channel *ch)
+{
+	u8 ier = readb(&ch->ch_neo_uart->ier);
+	u8 efr = readb(&ch->ch_neo_uart->efr);
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
+
+	/* Turn off auto CTS flow control */
+	ier &= ~(UART_17158_IER_CTSDSR);
+	efr &= ~(UART_17158_EFR_CTSDSR);
+
+	/* Turn off auto Xon flow control */
+	if (ch->ch_c_iflag & IXOFF)
+		efr &= ~(UART_17158_EFR_IXON);
+	else
+		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	ch->ch_r_watermark = 0;
+
+	writeb(16, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 16;
+
+	writeb(16, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 16;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
+{
+
+	/* if hardware flow control is set, then skip this whole thing */
+	if (ch->ch_c_cflag & CRTSCTS)
+		return;
+
+	jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+}
+
+static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
+{
+	int qleft = 0;
+	u8 linestatus = 0;
+	u8 error_mask = 0;
+	int n = 0;
+	int total = 0;
+	u16 head;
+	u16 tail;
+
+	if (!ch)
+		return;
+
+	/* cache head and tail of queue */
+	head = ch->ch_r_head & RQUEUEMASK;
+	tail = ch->ch_r_tail & RQUEUEMASK;
+
+	/* Get our cached LSR */
+	linestatus = ch->ch_cached_lsr;
+	ch->ch_cached_lsr = 0;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = tail - head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * If the UART is not in FIFO mode, force the FIFO copy to
+	 * NOT be run, by setting total to 0.
+	 *
+	 * On the other hand, if the UART IS in FIFO mode, then ask
+	 * the UART to give us an approximation of data it has RX'ed.
+	 */
+	if (!(ch->ch_flags & CH_FIFO_ENABLED))
+		total = 0;
+	else {
+		total = readb(&ch->ch_neo_uart->rfifo);
+
+		/*
+		 * EXAR chip bug - RX FIFO COUNT - Fudge factor.
+		 *
+		 * This resolves a problem/bug with the Exar chip that sometimes
+		 * returns a bogus value in the rfifo register.
+		 * The count can be any where from 0-3 bytes "off".
+		 * Bizarre, but true.
+		 */
+		total -= 3;
+	}
+
+	/*
+	 * Finally, bound the copy to make sure we don't overflow
+	 * our own queue...
+	 * The byte by byte copy loop below this loop this will
+	 * deal with the queue overflow possibility.
+	 */
+	total = min(total, qleft);
+
+	while (total > 0) {
+		/*
+		 * Grab the linestatus register, we need to check
+		 * to see if there are any errors in the FIFO.
+		 */
+		linestatus = readb(&ch->ch_neo_uart->lsr);
+
+		/*
+		 * Break out if there is a FIFO error somewhere.
+		 * This will allow us to go byte by byte down below,
+		 * finding the exact location of the error.
+		 */
+		if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+			break;
+
+		/* Make sure we don't go over the end of our queue */
+		n = min(((u32) total), (RQUEUESIZE - (u32) head));
+
+		/*
+		 * Cut down n even further if needed, this is to fix
+		 * a problem with memcpy_fromio() with the Neo on the
+		 * IBM pSeries platform.
+		 * 15 bytes max appears to be the magic number.
+		 */
+		n = min((u32) n, (u32) 12);
+
+		/*
+		 * Since we are grabbing the linestatus register, which
+		 * will reset some bits after our read, we need to ensure
+		 * we don't miss our TX FIFO emptys.
+		 */
+		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+		linestatus = 0;
+
+		/* Copy data from uart to the queue */
+		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
+		/*
+		 * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
+		 * that all the data currently in the FIFO is free of
+		 * breaks and parity/frame/orun errors.
+		 */
+		memset(ch->ch_equeue + head, 0, n);
+
+		/* Add to and flip head if needed */
+		head = (head + n) & RQUEUEMASK;
+		total -= n;
+		qleft -= n;
+		ch->ch_rxcount += n;
+	}
+
+	/*
+	 * Create a mask to determine whether we should
+	 * insert the character (if any) into our queue.
+	 */
+	if (ch->ch_c_iflag & IGNBRK)
+		error_mask |= UART_LSR_BI;
+
+	/*
+	 * Now cleanup any leftover bytes still in the UART.
+	 * Also deal with any possible queue overflow here as well.
+	 */
+	while (1) {
+
+		/*
+		 * Its possible we have a linestatus from the loop above
+		 * this, so we "OR" on any extra bits.
+		 */
+		linestatus |= readb(&ch->ch_neo_uart->lsr);
+
+		/*
+		 * If the chip tells us there is no more data pending to
+		 * be read, we can then leave.
+		 * But before we do, cache the linestatus, just in case.
+		 */
+		if (!(linestatus & UART_LSR_DR)) {
+			ch->ch_cached_lsr = linestatus;
+			break;
+		}
+
+		/* No need to store this bit */
+		linestatus &= ~UART_LSR_DR;
+
+		/*
+		 * Since we are grabbing the linestatus register, which
+		 * will reset some bits after our read, we need to ensure
+		 * we don't miss our TX FIFO emptys.
+		 */
+		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+			linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		}
+
+		/*
+		 * Discard character if we are ignoring the error mask.
+		 */
+		if (linestatus & error_mask) {
+			u8 discard;
+			linestatus = 0;
+			memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
+			continue;
+		}
+
+		/*
+		 * If our queue is full, we have no choice but to drop some data.
+		 * The assumption is that HWFLOW or SWFLOW should have stopped
+		 * things way way before we got to this point.
+		 *
+		 * I decided that I wanted to ditch the oldest data first,
+		 * I hope thats okay with everyone? Yes? Good.
+		 */
+		while (qleft < 1) {
+			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+				"Queue full, dropping DATA:%x LSR:%x\n",
+				ch->ch_rqueue[tail], ch->ch_equeue[tail]);
+
+			ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+			ch->ch_err_overrun++;
+			qleft++;
+		}
+
+		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
+		ch->ch_equeue[head] = (u8) linestatus;
+
+		jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+				"DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
+
+		/* Ditch any remaining linestatus value. */
+		linestatus = 0;
+
+		/* Add to and flip head if needed */
+		head = (head + 1) & RQUEUEMASK;
+
+		qleft--;
+		ch->ch_rxcount++;
+	}
+
+	/*
+	 * Write new final heads to channel structure.
+	 */
+	ch->ch_r_head = head & RQUEUEMASK;
+	ch->ch_e_head = head & EQUEUEMASK;
+	jsm_input(ch);
+}
+
+static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
+{
+	u16 head;
+	u16 tail;
+	int n;
+	int s;
+	int qlen;
+	u32 len_written = 0;
+
+	if (!ch)
+		return;
+
+	/* No data to write to the UART */
+	if (ch->ch_w_tail == ch->ch_w_head)
+		return;
+
+	/* If port is "stopped", don't send any data to the UART */
+	if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
+		return;
+	/*
+	 * If FIFOs are disabled. Send data directly to txrx register
+	 */
+	if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
+		u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
+
+		ch->ch_cached_lsr |= lsrbits;
+		if (ch->ch_cached_lsr & UART_LSR_THRE) {
+			ch->ch_cached_lsr &= ~(UART_LSR_THRE);
+
+			writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+			jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
+					"Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
+			ch->ch_w_tail++;
+			ch->ch_w_tail &= WQUEUEMASK;
+			ch->ch_txcount++;
+		}
+		return;
+	}
+
+	/*
+	 * We have to do it this way, because of the EXAR TXFIFO count bug.
+	 */
+	if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
+		return;
+
+	len_written = 0;
+	n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
+
+	/* cache head and tail of queue */
+	head = ch->ch_w_head & WQUEUEMASK;
+	tail = ch->ch_w_tail & WQUEUEMASK;
+	qlen = (head - tail) & WQUEUEMASK;
+
+	/* Find minimum of the FIFO space, versus queue length */
+	n = min(n, qlen);
+
+	while (n > 0) {
+
+		s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+		/* Add and flip queue if needed */
+		tail = (tail + s) & WQUEUEMASK;
+		n -= s;
+		ch->ch_txcount += s;
+		len_written += s;
+	}
+
+	/* Update the final tail */
+	ch->ch_w_tail = tail & WQUEUEMASK;
+
+	if (len_written >= ch->ch_t_tlevel)
+		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+	if (!jsm_tty_write(&ch->uart_port))
+		uart_write_wakeup(&ch->uart_port);
+}
+
+static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
+{
+	u8 msignals = signals;
+
+	jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+			"neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
+
+	if (!ch)
+		return;
+
+	/* Scrub off lower bits. They signify delta's, which I don't care about */
+	msignals &= 0xf0;
+
+	if (msignals & UART_MSR_DCD)
+		ch->ch_mistat |= UART_MSR_DCD;
+	else
+		ch->ch_mistat &= ~UART_MSR_DCD;
+
+	if (msignals & UART_MSR_DSR)
+		ch->ch_mistat |= UART_MSR_DSR;
+	else
+		ch->ch_mistat &= ~UART_MSR_DSR;
+
+	if (msignals & UART_MSR_RI)
+		ch->ch_mistat |= UART_MSR_RI;
+	else
+		ch->ch_mistat &= ~UART_MSR_RI;
+
+	if (msignals & UART_MSR_CTS)
+		ch->ch_mistat |= UART_MSR_CTS;
+	else
+		ch->ch_mistat &= ~UART_MSR_CTS;
+
+	jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+			"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+		ch->ch_portnum,
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
+}
+
+/* Make the UART raise any of the output signals we want up */
+static void neo_assert_modem_signals(struct jsm_channel *ch)
+{
+	u8 out;
+
+	if (!ch)
+		return;
+
+	out = ch->ch_mostat;
+
+	writeb(out, &ch->ch_neo_uart->mcr);
+
+	/* flush write operation */
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+/*
+ * Flush the WRITE FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_write(struct jsm_channel *ch)
+{
+	u8 tmp = 0;
+	int i = 0;
+
+	if (!ch)
+		return;
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+
+	for (i = 0; i < 10; i++) {
+
+		/* Check to see if the UART feels it completely flushed the FIFO. */
+		tmp = readb(&ch->ch_neo_uart->isr_fcr);
+		if (tmp & 4) {
+			jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+					"Still flushing TX UART... i: %d\n", i);
+			udelay(10);
+		}
+		else
+			break;
+	}
+
+	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/*
+ * Flush the READ FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_read(struct jsm_channel *ch)
+{
+	u8 tmp = 0;
+	int i = 0;
+
+	if (!ch)
+		return;
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
+
+	for (i = 0; i < 10; i++) {
+
+		/* Check to see if the UART feels it completely flushed the FIFO. */
+		tmp = readb(&ch->ch_neo_uart->isr_fcr);
+		if (tmp & 2) {
+			jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+					"Still flushing RX UART... i: %d\n", i);
+			udelay(10);
+		}
+		else
+			break;
+	}
+}
+
+/*
+ * No locks are assumed to be held when calling this function.
+ */
+static void neo_clear_break(struct jsm_channel *ch, int force)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+	/* Turn break off, and unset some variables */
+	if (ch->ch_flags & CH_BREAK_SENDING) {
+		u8 temp = readb(&ch->ch_neo_uart->lcr);
+		writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+
+		ch->ch_flags &= ~(CH_BREAK_SENDING);
+		jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+				"clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
+
+		/* flush write operation */
+		neo_pci_posting_flush(ch->ch_bd);
+	}
+	spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+}
+
+/*
+ * Parse the ISR register.
+ */
+static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
+{
+	struct jsm_channel *ch;
+	u8 isr;
+	u8 cause;
+	unsigned long lock_flags;
+
+	if (!brd)
+		return;
+
+	if (port > brd->maxports)
+		return;
+
+	ch = brd->channels[port];
+	if (!ch)
+		return;
+
+	/* Here we try to figure out what caused the interrupt to happen */
+	while (1) {
+
+		isr = readb(&ch->ch_neo_uart->isr_fcr);
+
+		/* Bail if no pending interrupt */
+		if (isr & UART_IIR_NO_INT)
+			break;
+
+		/*
+		 * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
+		 */
+		isr &= ~(UART_17158_IIR_FIFO_ENABLED);
+
+		jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+				"%s:%d isr: %x\n", __FILE__, __LINE__, isr);
+
+		if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
+			/* Read data from uart -> queue */
+			neo_copy_data_from_uart_to_queue(ch);
+
+			/* Call our tty layer to enforce queue flow control if needed. */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			jsm_check_queue_flow_control(ch);
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		}
+
+		if (isr & UART_IIR_THRI) {
+			/* Transfer data (if any) from Write Queue -> UART. */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+			neo_copy_data_from_queue_to_uart(ch);
+		}
+
+		if (isr & UART_17158_IIR_XONXOFF) {
+			cause = readb(&ch->ch_neo_uart->xoffchar1);
+
+			jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+					"Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
+
+			/*
+			 * Since the UART detected either an XON or
+			 * XOFF match, we need to figure out which
+			 * one it was, so we can suspend or resume data flow.
+			 */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			if (cause == UART_17158_XON_DETECT) {
+				/* Is output stopped right now, if so, resume it */
+				if (brd->channels[port]->ch_flags & CH_STOP) {
+					ch->ch_flags &= ~(CH_STOP);
+				}
+				jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+						"Port %d. XON detected in incoming data\n", port);
+			}
+			else if (cause == UART_17158_XOFF_DETECT) {
+				if (!(brd->channels[port]->ch_flags & CH_STOP)) {
+					ch->ch_flags |= CH_STOP;
+					jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+							"Setting CH_STOP\n");
+				}
+				jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+						"Port: %d. XOFF detected in incoming data\n", port);
+			}
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		}
+
+		if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
+			/*
+			 * If we get here, this means the hardware is doing auto flow control.
+			 * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
+			 */
+			cause = readb(&ch->ch_neo_uart->mcr);
+
+			/* Which pin is doing auto flow? RTS or DTR? */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			if ((cause & 0x4) == 0) {
+				if (cause & UART_MCR_RTS)
+					ch->ch_mostat |= UART_MCR_RTS;
+				else
+					ch->ch_mostat &= ~(UART_MCR_RTS);
+			} else {
+				if (cause & UART_MCR_DTR)
+					ch->ch_mostat |= UART_MCR_DTR;
+				else
+					ch->ch_mostat &= ~(UART_MCR_DTR);
+			}
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		}
+
+		/* Parse any modem signal changes */
+		jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+				"MOD_STAT: sending to parse_modem_sigs\n");
+		neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+	}
+}
+
+static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
+{
+	struct jsm_channel *ch;
+	int linestatus;
+	unsigned long lock_flags;
+
+	if (!brd)
+		return;
+
+	if (port > brd->maxports)
+		return;
+
+	ch = brd->channels[port];
+	if (!ch)
+		return;
+
+	linestatus = readb(&ch->ch_neo_uart->lsr);
+
+	jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+			"%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
+
+	ch->ch_cached_lsr |= linestatus;
+
+	if (ch->ch_cached_lsr & UART_LSR_DR) {
+		/* Read data from uart -> queue */
+		neo_copy_data_from_uart_to_queue(ch);
+		spin_lock_irqsave(&ch->ch_lock, lock_flags);
+		jsm_check_queue_flow_control(ch);
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+	}
+
+	/*
+	 * This is a special flag. It indicates that at least 1
+	 * RX error (parity, framing, or break) has happened.
+	 * Mark this in our struct, which will tell me that I have
+	 *to do the special RX+LSR read for this FIFO load.
+	 */
+	if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+		jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+			"%s:%d Port: %d Got an RX error, need to parse LSR\n",
+			__FILE__, __LINE__, port);
+
+	/*
+	 * The next 3 tests should *NOT* happen, as the above test
+	 * should encapsulate all 3... At least, thats what Exar says.
+	 */
+
+	if (linestatus & UART_LSR_PE) {
+		ch->ch_err_parity++;
+		jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+			"%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
+	}
+
+	if (linestatus & UART_LSR_FE) {
+		ch->ch_err_frame++;
+		jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+			"%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
+	}
+
+	if (linestatus & UART_LSR_BI) {
+		ch->ch_err_break++;
+		jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+			"%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
+	}
+
+	if (linestatus & UART_LSR_OE) {
+		/*
+		 * Rx Oruns. Exar says that an orun will NOT corrupt
+		 * the FIFO. It will just replace the holding register
+		 * with this new data byte. So basically just ignore this.
+		 * Probably we should eventually have an orun stat in our driver...
+		 */
+		ch->ch_err_overrun++;
+		jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+			"%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
+	}
+
+	if (linestatus & UART_LSR_THRE) {
+		spin_lock_irqsave(&ch->ch_lock, lock_flags);
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		/* Transfer data (if any) from Write Queue -> UART. */
+		neo_copy_data_from_queue_to_uart(ch);
+	}
+	else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
+		spin_lock_irqsave(&ch->ch_lock, lock_flags);
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		/* Transfer data (if any) from Write Queue -> UART. */
+		neo_copy_data_from_queue_to_uart(ch);
+	}
+}
+
+/*
+ * neo_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void neo_param(struct jsm_channel *ch)
+{
+	u8 lcr = 0;
+	u8 uart_lcr = 0;
+	u8 ier = 0;
+	u32 baud = 9600;
+	int quot = 0;
+	struct jsm_board *bd;
+
+	bd = ch->ch_bd;
+	if (!bd)
+		return;
+
+	/*
+	 * If baud rate is zero, flush queues, and set mval to drop DTR.
+	 */
+	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+		ch->ch_r_head = ch->ch_r_tail = 0;
+		ch->ch_e_head = ch->ch_e_tail = 0;
+		ch->ch_w_head = ch->ch_w_tail = 0;
+
+		neo_flush_uart_write(ch);
+		neo_flush_uart_read(ch);
+
+		ch->ch_flags |= (CH_BAUD0);
+		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+		neo_assert_modem_signals(ch);
+		ch->ch_old_baud = 0;
+		return;
+
+	} else if (ch->ch_custom_speed) {
+			baud = ch->ch_custom_speed;
+			if (ch->ch_flags & CH_BAUD0)
+				ch->ch_flags &= ~(CH_BAUD0);
+		} else {
+			int iindex = 0;
+			int jindex = 0;
+
+			const u64 bauds[4][16] = {
+				{
+					0,	50,	75,	110,
+					134,	150,	200,	300,
+					600,	1200,	1800,	2400,
+					4800,	9600,	19200,	38400 },
+				{
+					0,	57600,	115200, 230400,
+					460800, 150,	200,	921600,
+					600,	1200,	1800,	2400,
+					4800,	9600,	19200,	38400 },
+				{
+					0,	57600,	76800, 115200,
+					131657, 153600, 230400, 460800,
+					921600, 1200,	1800,	2400,
+					4800,	9600,	19200,	38400 },
+				{
+					0,	57600,	115200, 230400,
+					460800, 150,	200,	921600,
+					600,	1200,	1800,	2400,
+					4800,	9600,	19200,	38400 }
+			};
+
+			baud = C_BAUD(ch->uart_port.info->tty) & 0xff;
+
+			if (ch->ch_c_cflag & CBAUDEX)
+				iindex = 1;
+
+			jindex = baud;
+
+			if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16))
+				baud = bauds[iindex][jindex];
+			else {
+				jsm_printk(IOCTL, DEBUG, &ch->ch_bd->pci_dev,
+					"baud indices were out of range (%d)(%d)",
+				iindex, jindex);
+				baud = 0;
+			}
+
+			if (baud == 0)
+				baud = 9600;
+
+			if (ch->ch_flags & CH_BAUD0)
+				ch->ch_flags &= ~(CH_BAUD0);
+		}
+
+	if (ch->ch_c_cflag & PARENB)
+		lcr |= UART_LCR_PARITY;
+
+	if (!(ch->ch_c_cflag & PARODD))
+		lcr |= UART_LCR_EPAR;
+
+	/*
+	 * Not all platforms support mark/space parity,
+	 * so this will hide behind an ifdef.
+	 */
+#ifdef CMSPAR
+	if (ch->ch_c_cflag & CMSPAR)
+		lcr |= UART_LCR_SPAR;
+#endif
+
+	if (ch->ch_c_cflag & CSTOPB)
+		lcr |= UART_LCR_STOP;
+
+	switch (ch->ch_c_cflag & CSIZE) {
+		case CS5:
+			lcr |= UART_LCR_WLEN5;
+			break;
+		case CS6:
+			lcr |= UART_LCR_WLEN6;
+			break;
+		case CS7:
+			lcr |= UART_LCR_WLEN7;
+			break;
+		case CS8:
+		default:
+			lcr |= UART_LCR_WLEN8;
+		break;
+	}
+
+	ier = readb(&ch->ch_neo_uart->ier);
+	uart_lcr = readb(&ch->ch_neo_uart->lcr);
+
+	if (baud == 0)
+		baud = 9600;
+
+	quot = ch->ch_bd->bd_dividend / baud;
+
+	if (quot != 0) {
+		ch->ch_old_baud = baud;
+		writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
+		writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
+		writeb((quot >> 8), &ch->ch_neo_uart->ier);
+		writeb(lcr, &ch->ch_neo_uart->lcr);
+	}
+
+	if (uart_lcr != lcr)
+		writeb(lcr, &ch->ch_neo_uart->lcr);
+
+	if (ch->ch_c_cflag & CREAD)
+		ier |= (UART_IER_RDI | UART_IER_RLSI);
+
+	ier |= (UART_IER_THRI | UART_IER_MSI);
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	/* Set new start/stop chars */
+	neo_set_new_start_stop_chars(ch);
+
+	if (ch->ch_c_cflag & CRTSCTS)
+		neo_set_cts_flow_control(ch);
+	else if (ch->ch_c_iflag & IXON) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+			neo_set_no_output_flow_control(ch);
+		else
+			neo_set_ixon_flow_control(ch);
+	}
+	else
+		neo_set_no_output_flow_control(ch);
+
+	if (ch->ch_c_cflag & CRTSCTS)
+		neo_set_rts_flow_control(ch);
+	else if (ch->ch_c_iflag & IXOFF) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+			neo_set_no_input_flow_control(ch);
+		else
+			neo_set_ixoff_flow_control(ch);
+	}
+	else
+		neo_set_no_input_flow_control(ch);
+	/*
+	 * Adjust the RX FIFO Trigger level if baud is less than 9600.
+	 * Not exactly elegant, but this is needed because of the Exar chip's
+	 * delay on firing off the RX FIFO interrupt on slower baud rates.
+	 */
+	if (baud < 9600) {
+		writeb(1, &ch->ch_neo_uart->rfifo);
+		ch->ch_r_tlevel = 1;
+	}
+
+	neo_assert_modem_signals(ch);
+
+	/* Get current status of the modem signals now */
+	neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+	return;
+}
+
+/*
+ * jsm_neo_intr()
+ *
+ * Neo specific interrupt handler.
+ */
+static irqreturn_t neo_intr(int irq, void *voidbrd, struct pt_regs *regs)
+{
+	struct jsm_board *brd = (struct jsm_board *) voidbrd;
+	struct jsm_channel *ch;
+	int port = 0;
+	int type = 0;
+	int current_port;
+	u32 tmp;
+	u32 uart_poll;
+	unsigned long lock_flags;
+	unsigned long lock_flags2;
+	int outofloop_count = 0;
+
+	brd->intr_count++;
+
+	/* Lock out the slow poller from running on this board. */
+	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
+
+	/*
+	 * Read in "extended" IRQ information from the 32bit Neo register.
+	 * Bits 0-7: What port triggered the interrupt.
+	 * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
+	 */
+	uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
+
+	jsm_printk(INTR, INFO, &brd->pci_dev,
+		"%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
+
+	if (!uart_poll) {
+		jsm_printk(INTR, INFO, &brd->pci_dev,
+			"Kernel interrupted to me, but no pending interrupts...\n");
+		spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+		return IRQ_NONE;
+	}
+
+	/* At this point, we have at least SOMETHING to service, dig further... */
+
+	current_port = 0;
+
+	/* Loop on each port */
+	while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
+
+		tmp = uart_poll;
+		outofloop_count++;
+
+		/* Check current port to see if it has interrupt pending */
+		if ((tmp & jsm_offset_table[current_port]) != 0) {
+			port = current_port;
+			type = tmp >> (8 + (port * 3));
+			type &= 0x7;
+		} else {
+			current_port++;
+			continue;
+		}
+
+		jsm_printk(INTR, INFO, &brd->pci_dev,
+		"%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
+
+		/* Remove this port + type from uart_poll */
+		uart_poll &= ~(jsm_offset_table[port]);
+
+		if (!type) {
+			/* If no type, just ignore it, and move onto next port */
+			jsm_printk(INTR, ERR, &brd->pci_dev,
+				"Interrupt with no type! port: %d\n", port);
+			continue;
+		}
+
+		/* Switch on type of interrupt we have */
+		switch (type) {
+
+		case UART_17158_RXRDY_TIMEOUT:
+			/*
+			 * RXRDY Time-out is cleared by reading data in the
+			* RX FIFO until it falls below the trigger level.
+			 */
+
+			/* Verify the port is in range. */
+			if (port > brd->nasync)
+				continue;
+
+			ch = brd->channels[port];
+			neo_copy_data_from_uart_to_queue(ch);
+
+			/* Call our tty layer to enforce queue flow control if needed. */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+			jsm_check_queue_flow_control(ch);
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+
+			continue;
+
+		case UART_17158_RX_LINE_STATUS:
+			/*
+			 * RXRDY and RX LINE Status (logic OR of LSR[4:1])
+			 */
+			neo_parse_lsr(brd, port);
+			continue;
+
+		case UART_17158_TXRDY:
+			/*
+			 * TXRDY interrupt clears after reading ISR register for the UART channel.
+			 */
+
+			/*
+			 * Yes, this is odd...
+			 * Why would I check EVERY possibility of type of
+			 * interrupt, when we know its TXRDY???
+			 * Becuz for some reason, even tho we got triggered for TXRDY,
+			 * it seems to be occassionally wrong. Instead of TX, which
+			 * it should be, I was getting things like RXDY too. Weird.
+			 */
+			neo_parse_isr(brd, port);
+			continue;
+
+		case UART_17158_MSR:
+			/*
+			 * MSR or flow control was seen.
+			 */
+			neo_parse_isr(brd, port);
+			continue;
+
+		default:
+			/*
+			 * The UART triggered us with a bogus interrupt type.
+			 * It appears the Exar chip, when REALLY bogged down, will throw
+			 * these once and awhile.
+			 * Its harmless, just ignore it and move on.
+			 */
+			jsm_printk(INTR, ERR, &brd->pci_dev,
+				"%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
+			continue;
+		}
+	}
+
+	spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+
+	jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
+	return IRQ_HANDLED;
+}
+
+/*
+ * Neo specific way of turning off the receiver.
+ * Used as a way to enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_disable_receiver(struct jsm_channel *ch)
+{
+	u8 tmp = readb(&ch->ch_neo_uart->ier);
+	tmp &= ~(UART_IER_RDI);
+	writeb(tmp, &ch->ch_neo_uart->ier);
+
+	/* flush write operation */
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Neo specific way of turning on the receiver.
+ * Used as a way to un-enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_enable_receiver(struct jsm_channel *ch)
+{
+	u8 tmp = readb(&ch->ch_neo_uart->ier);
+	tmp |= (UART_IER_RDI);
+	writeb(tmp, &ch->ch_neo_uart->ier);
+
+	/* flush write operation */
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+static void neo_send_start_character(struct jsm_channel *ch)
+{
+	if (!ch)
+		return;
+
+	if (ch->ch_startc != __DISABLED_CHAR) {
+		ch->ch_xon_sends++;
+		writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
+
+		/* flush write operation */
+		neo_pci_posting_flush(ch->ch_bd);
+	}
+}
+
+static void neo_send_stop_character(struct jsm_channel *ch)
+{
+	if (!ch)
+		return;
+
+	if (ch->ch_stopc != __DISABLED_CHAR) {
+		ch->ch_xoff_sends++;
+		writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
+
+		/* flush write operation */
+		neo_pci_posting_flush(ch->ch_bd);
+	}
+}
+
+/*
+ * neo_uart_init
+ */
+static void neo_uart_init(struct jsm_channel *ch)
+{
+	writeb(0, &ch->ch_neo_uart->ier);
+	writeb(0, &ch->ch_neo_uart->efr);
+	writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
+
+	/* Clear out UART and FIFO */
+	readb(&ch->ch_neo_uart->txrx);
+	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+	readb(&ch->ch_neo_uart->lsr);
+	readb(&ch->ch_neo_uart->msr);
+
+	ch->ch_flags |= CH_FIFO_ENABLED;
+
+	/* Assert any signals we want up */
+	writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+}
+
+/*
+ * Make the UART completely turn off.
+ */
+static void neo_uart_off(struct jsm_channel *ch)
+{
+	/* Turn off UART enhanced bits */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Stop all interrupts from occurring. */
+	writeb(0, &ch->ch_neo_uart->ier);
+}
+
+static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
+{
+	u8 left = 0;
+	u8 lsr = readb(&ch->ch_neo_uart->lsr);
+
+	/* We must cache the LSR as some of the bits get reset once read... */
+	ch->ch_cached_lsr |= lsr;
+
+	/* Determine whether the Transmitter is empty or not */
+	if (!(lsr & UART_LSR_TEMT))
+		left = 1;
+	else {
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		left = 0;
+	}
+
+	return left;
+}
+
+/* Channel lock MUST be held by the calling function! */
+static void neo_send_break(struct jsm_channel *ch)
+{
+	/*
+	 * Set the time we should stop sending the break.
+	 * If we are already sending a break, toss away the existing
+	 * time to stop, and use this new value instead.
+	 */
+
+	/* Tell the UART to start sending the break */
+	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+		u8 temp = readb(&ch->ch_neo_uart->lcr);
+		writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+		ch->ch_flags |= (CH_BREAK_SENDING);
+
+		/* flush write operation */
+		neo_pci_posting_flush(ch->ch_bd);
+	}
+}
+
+/*
+ * neo_send_immediate_char.
+ *
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
+{
+	if (!ch)
+		return;
+
+	writeb(c, &ch->ch_neo_uart->txrx);
+
+	/* flush write operation */
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+struct board_ops jsm_neo_ops = {
+	.intr				= neo_intr,
+	.uart_init			= neo_uart_init,
+	.uart_off			= neo_uart_off,
+	.param				= neo_param,
+	.assert_modem_signals		= neo_assert_modem_signals,
+	.flush_uart_write		= neo_flush_uart_write,
+	.flush_uart_read		= neo_flush_uart_read,
+	.disable_receiver		= neo_disable_receiver,
+	.enable_receiver		= neo_enable_receiver,
+	.send_break			= neo_send_break,
+	.clear_break			= neo_clear_break,
+	.send_start_character		= neo_send_start_character,
+	.send_stop_character		= neo_send_stop_character,
+	.copy_data_from_queue_to_uart	= neo_copy_data_from_queue_to_uart,
+	.get_uart_bytes_left		= neo_get_uart_bytes_left,
+	.send_immediate_char		= neo_send_immediate_char
+};
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
new file mode 100644
--- /dev/null
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -0,0 +1,1016 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>	/* For udelay */
+#include <linux/pci.h>
+
+#include "jsm.h"
+
+static void jsm_carrier(struct jsm_channel *ch);
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+	unsigned char mstat;
+	unsigned result;
+
+	jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+	mstat = (ch->ch_mostat | ch->ch_mistat);
+
+	result = 0;
+
+	if (mstat & UART_MCR_DTR)
+		result |= TIOCM_DTR;
+	if (mstat & UART_MCR_RTS)
+		result |= TIOCM_RTS;
+	if (mstat & UART_MSR_CTS)
+		result |= TIOCM_CTS;
+	if (mstat & UART_MSR_DSR)
+		result |= TIOCM_DSR;
+	if (mstat & UART_MSR_RI)
+		result |= TIOCM_RI;
+	if (mstat & UART_MSR_DCD)
+		result |= TIOCM_CD;
+
+	jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+	return result;
+}
+
+static unsigned int jsm_tty_tx_empty(struct uart_port *port)
+{
+	return TIOCSER_TEMT;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
+{
+	int result;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+	result = jsm_get_mstat(channel);
+
+	if (result < 0)
+		return -ENXIO;
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+
+	return result;
+}
+
+/*
+ * jsm_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+	if (mctrl & TIOCM_RTS)
+		channel->ch_mostat |= UART_MCR_RTS;
+	else
+		channel->ch_mostat &= ~UART_MCR_RTS;
+
+	if (mctrl & TIOCM_DTR)
+		channel->ch_mostat |= UART_MCR_DTR;
+	else
+		channel->ch_mostat &= ~UART_MCR_DTR;
+
+	channel->ch_bd->bd_ops->assert_modem_signals(channel);
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+	udelay(10);
+}
+
+static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+	channel->ch_flags &= ~(CH_STOP);
+	jsm_tty_write(port);
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+	channel->ch_flags |= (CH_STOP);
+
+	jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (ch == port->info->tty->termios->c_cc[VSTART])
+		channel->ch_bd->bd_ops->send_start_character(channel);
+
+	if (ch == port->info->tty->termios->c_cc[VSTOP])
+		channel->ch_bd->bd_ops->send_stop_character(channel);
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static void jsm_tty_stop_rx(struct uart_port *port)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	channel->ch_bd->bd_ops->disable_receiver(channel);
+}
+
+static void jsm_tty_break(struct uart_port *port, int break_state)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (break_state == -1)
+		channel->ch_bd->bd_ops->send_break(channel);
+	else
+		channel->ch_bd->bd_ops->clear_break(channel, 0);
+
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+	struct jsm_board *brd;
+	int rc = 0;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	/* Get board pointer from our array of majors we have allocated */
+	brd = channel->ch_bd;
+
+	/*
+	 * Allocate channel buffers for read/write/error.
+	 * Set flag, so we don't get trounced on.
+	 */
+	channel->ch_flags |= (CH_OPENING);
+
+	/* Drop locks, as malloc with GFP_KERNEL can sleep */
+
+	if (!channel->ch_rqueue) {
+		channel->ch_rqueue = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_rqueue) {
+			jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+				"unable to allocate read queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_rqueue, 0, RQUEUESIZE);
+	}
+	if (!channel->ch_equeue) {
+		channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_equeue) {
+			jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+				"unable to allocate error queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_equeue, 0, EQUEUESIZE);
+	}
+	if (!channel->ch_wqueue) {
+		channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_wqueue) {
+			jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+				"unable to allocate write queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_wqueue, 0, WQUEUESIZE);
+	}
+
+	channel->ch_flags &= ~(CH_OPENING);
+	/*
+	 * Initialize if neither terminal is open.
+	 */
+	jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
+		"jsm_open: initializing channel in open...\n");
+
+	/*
+	 * Flush input queues.
+	 */
+	channel->ch_r_head = channel->ch_r_tail = 0;
+	channel->ch_e_head = channel->ch_e_tail = 0;
+	channel->ch_w_head = channel->ch_w_tail = 0;
+
+	brd->bd_ops->flush_uart_write(channel);
+	brd->bd_ops->flush_uart_read(channel);
+
+	channel->ch_flags = 0;
+	channel->ch_cached_lsr = 0;
+	channel->ch_stops_sent = 0;
+
+	channel->ch_c_cflag	= port->info->tty->termios->c_cflag;
+	channel->ch_c_iflag	= port->info->tty->termios->c_iflag;
+	channel->ch_c_oflag	= port->info->tty->termios->c_oflag;
+	channel->ch_c_lflag	= port->info->tty->termios->c_lflag;
+	channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
+	channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP];
+
+	/* Tell UART to init itself */
+	brd->bd_ops->uart_init(channel);
+
+	/*
+	 * Run param in case we changed anything
+	 */
+	brd->bd_ops->param(channel);
+
+	jsm_carrier(channel);
+
+	channel->ch_open_count++;
+
+	jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
+	return rc;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+	struct jsm_board *bd;
+	struct termios *ts;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+	bd = channel->ch_bd;
+	ts = channel->uart_port.info->tty->termios;
+
+	channel->ch_flags &= ~(CH_STOPI);
+
+	channel->ch_open_count--;
+
+	/*
+	 * If we have HUPCL set, lower DTR and RTS
+	 */
+	if (channel->ch_c_cflag & HUPCL) {
+		jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
+			"Close. HUPCL set, dropping DTR/RTS\n");
+
+		/* Drop RTS/DTR */
+		channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+		bd->bd_ops->assert_modem_signals(channel);
+	}
+
+	channel->ch_old_baud = 0;
+
+	/* Turn off UART interrupts for this port */
+	channel->ch_bd->bd_ops->uart_off(channel);
+
+	jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+				 struct termios *termios,
+				 struct termios *old_termios)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	channel->ch_c_cflag	= termios->c_cflag;
+	channel->ch_c_iflag	= termios->c_iflag;
+	channel->ch_c_oflag	= termios->c_oflag;
+	channel->ch_c_lflag	= termios->c_lflag;
+	channel->ch_startc	= termios->c_cc[VSTART];
+	channel->ch_stopc	= termios->c_cc[VSTOP];
+
+	channel->ch_bd->bd_ops->param(channel);
+	jsm_carrier(channel);
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static const char *jsm_tty_type(struct uart_port *port)
+{
+	return "jsm";
+}
+
+static void jsm_tty_release_port(struct uart_port *port)
+{
+}
+
+static int jsm_tty_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void jsm_config_port(struct uart_port *port, int flags)
+{
+	port->type = PORT_JSM;
+}
+
+static struct uart_ops jsm_ops = {
+	.tx_empty	= jsm_tty_tx_empty,
+	.set_mctrl	= jsm_tty_set_mctrl,
+	.get_mctrl	= jsm_tty_get_mctrl,
+	.stop_tx	= jsm_tty_stop_tx,
+	.start_tx	= jsm_tty_start_tx,
+	.send_xchar	= jsm_tty_send_xchar,
+	.stop_rx	= jsm_tty_stop_rx,
+	.break_ctl	= jsm_tty_break,
+	.startup	= jsm_tty_open,
+	.shutdown	= jsm_tty_close,
+	.set_termios	= jsm_tty_set_termios,
+	.type		= jsm_tty_type,
+	.release_port	= jsm_tty_release_port,
+	.request_port	= jsm_tty_request_port,
+	.config_port	= jsm_config_port,
+};
+
+/*
+ * jsm_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int jsm_tty_init(struct jsm_board *brd)
+{
+	int i;
+	void __iomem *vaddr;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/*
+	 * Allocate channel memory that might not have been allocated
+	 * when the driver was first loaded.
+	 */
+	for (i = 0; i < brd->nasync; i++) {
+		if (!brd->channels[i]) {
+
+			/*
+			 * Okay to malloc with GFP_KERNEL, we are not at
+			 * interrupt context, and there are no locks held.
+			 */
+			brd->channels[i] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+			if (!brd->channels[i]) {
+				jsm_printk(CORE, ERR, &brd->pci_dev,
+					"%s:%d Unable to allocate memory for channel struct\n",
+							 __FILE__, __LINE__);
+			}
+			memset(brd->channels[i], 0, sizeof(struct jsm_channel));
+		}
+	}
+
+	ch = brd->channels[0];
+	vaddr = brd->re_map_membase;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		spin_lock_init(&ch->ch_lock);
+
+		if (brd->bd_uart_offset == 0x200)
+			ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
+
+		ch->ch_bd = brd;
+		ch->ch_portnum = i;
+
+		/* .25 second delay */
+		ch->ch_close_delay = 250;
+
+		init_waitqueue_head(&ch->ch_flags_wait);
+	}
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+int jsm_uart_port_init(struct jsm_board *brd)
+{
+	int i;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		brd->channels[i]->uart_port.irq = brd->irq;
+		brd->channels[i]->uart_port.type = PORT_JSM;
+		brd->channels[i]->uart_port.iotype = UPIO_MEM;
+		brd->channels[i]->uart_port.membase = brd->re_map_membase;
+		brd->channels[i]->uart_port.fifosize = 16;
+		brd->channels[i]->uart_port.ops = &jsm_ops;
+		brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
+		if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
+			printk(KERN_INFO "Added device failed\n");
+		else
+			printk(KERN_INFO "Added device \n");
+	}
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+int jsm_remove_uart_port(struct jsm_board *brd)
+{
+	int i;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++) {
+
+		if (!brd->channels[i])
+			continue;
+
+		ch = brd->channels[i];
+
+		uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
+	}
+
+	jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+void jsm_input(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+	struct tty_struct *tp;
+	u32 rmask;
+	u16 head;
+	u16 tail;
+	int data_len;
+	unsigned long lock_flags;
+	int flip_len;
+	int len = 0;
+	int n = 0;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	int s = 0;
+	int i = 0;
+
+	jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+	if (!ch)
+		return;
+
+	tp = ch->uart_port.info->tty;
+
+	bd = ch->ch_bd;
+	if(!bd)
+		return;
+
+	spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+	/*
+	 *Figure the number of characters in the buffer.
+	 *Exit immediately if none.
+	 */
+
+	rmask = RQUEUEMASK;
+
+	head = ch->ch_r_head & rmask;
+	tail = ch->ch_r_tail & rmask;
+
+	data_len = (head - tail) & rmask;
+	if (data_len == 0) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		return;
+	}
+
+	jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+	/*
+	 *If the device is not open, or CREAD is off, flush
+	 *input data and return immediately.
+	 */
+	if (!tp ||
+		!(tp->termios->c_cflag & CREAD) ) {
+
+		jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+			"input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
+		ch->ch_r_head = tail;
+
+		/* Force queue flow control to be released, if needed */
+		jsm_check_queue_flow_control(ch);
+
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * If we are throttled, simply don't read any data.
+	 */
+	if (ch->ch_flags & CH_STOPI) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+			"Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail);
+		return;
+	}
+
+	jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
+
+	/*
+	 * If the rxbuf is empty and we are not throttled, put as much
+	 * as we can directly into the linux TTY flip buffer.
+	 * The jsm_rawreadok case takes advantage of carnal knowledge that
+	 * the char_buf and the flag_buf are next to each other and
+	 * are each of (2 * TTY_FLIPBUF_SIZE) size.
+	 *
+	 * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
+	 *actually still uses the flag buffer, so you can't
+	 *use it for input data
+	 */
+	if (jsm_rawreadok) {
+		if (tp->real_raw)
+			flip_len = MYFLIPLEN;
+		else
+			flip_len = 2 * TTY_FLIPBUF_SIZE;
+	} else
+		flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+
+	len = min(data_len, flip_len);
+	len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+
+	if (len <= 0) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+		return;
+	}
+
+	/*
+	 * If we're bypassing flip buffers on rx, we can blast it
+	 * right into the beginning of the buffer.
+	 */
+	if (jsm_rawreadok) {
+		if (tp->real_raw) {
+			if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
+				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+					"JSM - FLIPBUF in use. delaying input\n");
+				spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+				return;
+			}
+			ch->ch_flags |= CH_FLIPBUF_IN_USE;
+			buf = ch->ch_bd->flipbuf;
+			buf2 = NULL;
+		} else {
+			buf = tp->flip.char_buf;
+			buf2 = tp->flip.flag_buf;
+		}
+	} else {
+		buf = tp->flip.char_buf_ptr;
+		buf2 = tp->flip.flag_buf_ptr;
+	}
+
+	n = len;
+
+	/*
+	 * n now contains the most amount of data we can copy,
+	 * bounded either by the flip buffer size or the amount
+	 * of data the card actually has pending...
+	 */
+	while (n) {
+		s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		memcpy(buf, ch->ch_rqueue + tail, s);
+
+		/* buf2 is only set when port isn't raw */
+		if (buf2)
+			memcpy(buf2, ch->ch_equeue + tail, s);
+
+		tail += s;
+		buf += s;
+		if (buf2)
+			buf2 += s;
+		n -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	/*
+	 * In high performance mode, we don't have to update
+	 * flag_buf or any of the counts or pointers into flip buf.
+	 */
+	if (!jsm_rawreadok) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else {
+			memset(tp->flip.flag_buf_ptr, 0, len);
+		}
+
+		tp->flip.char_buf_ptr += len;
+		tp->flip.flag_buf_ptr += len;
+		tp->flip.count += len;
+	}
+	else if (!tp->real_raw) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else
+			memset(tp->flip.flag_buf, 0, len);
+	}
+
+	/*
+	 * If we're doing raw reads, jam it right into the
+	 * line disc bypassing the flip buffers.
+	 */
+	if (jsm_rawreadok) {
+		if (tp->real_raw) {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+				"jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
+				__LINE__, len, ch->ch_bd->boardnum);
+			tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
+
+			/* Allow use of channel flip buffer again */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		} else {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+				"jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n",
+				__LINE__, len, ch->ch_bd->boardnum);
+
+			tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
+		}
+	} else {
+		ch->ch_r_tail = tail & rmask;
+		ch->ch_e_tail = tail & rmask;
+
+		jsm_check_queue_flow_control(ch);
+
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+			"jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__);
+		tty_schedule_flip(tp);
+	}
+
+	jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_carrier(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+
+	jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
+	if (!ch)
+		return;
+
+	bd = ch->ch_bd;
+
+	if (!bd)
+		return;
+
+	if (ch->ch_mistat & UART_MSR_DCD) {
+		jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+			"mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
+		phys_carrier = 1;
+	}
+
+	if (ch->ch_c_cflag & CLOCAL)
+		virt_carrier = 1;
+
+	jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+		"DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
+
+	/*
+	 * Test for a VIRTUAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+			"carrier: virt DCD rose\n");
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 * Test for a PHYSICAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+			"carrier: physical DCD rose\n");
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Test for a PHYSICAL transition to low, so long as we aren't
+	 *  currently ignoring physical transitions (which is what "virtual
+	 *  carrier" indicates).
+	 *
+	 *  The transition of the virtual carrier to low really doesn't
+	 *  matter... it really only means "ignore carrier state", not
+	 *  "make pretend that carrier is there".
+	 */
+	if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
+			&& (phys_carrier == 0)) {
+		/*
+		 *	When carrier drops:
+		 *
+		 *	Drop carrier on all open units.
+		 *
+		 *	Flush queues, waking up any task waiting in the
+		 *	line discipline.
+		 *
+		 *	Send a hangup to the control terminal.
+		 *
+		 *	Enable all select calls.
+		 */
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Make sure that our cached values reflect the current reality.
+	 */
+	if (virt_carrier == 1)
+		ch->ch_flags |= CH_FCAR;
+	else
+		ch->ch_flags &= ~CH_FCAR;
+
+	if (phys_carrier == 1)
+		ch->ch_flags |= CH_CD;
+	else
+		ch->ch_flags &= ~CH_CD;
+}
+
+
+void jsm_check_queue_flow_control(struct jsm_channel *ch)
+{
+	int qleft = 0;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * Check to see if we should enforce flow control on our queue because
+	 * the ld (or user) isn't reading data out of our queue fast enuf.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to back up, and force
+	 *	the RTS signal to be dropped.
+	 * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+	 *	the other side, in hopes it will stop sending data to us.
+	 * 3) NONE - Nothing we can do.  We will simply drop any extra data
+	 *	that gets sent into us when the queue fills up.
+	 */
+	if (qleft < 256) {
+		/* HWFLOW */
+		if (ch->ch_c_cflag & CRTSCTS) {
+			if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
+				ch->ch_bd->bd_ops->disable_receiver(ch);
+				ch->ch_flags |= (CH_RECEIVER_OFF);
+				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+					"Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+					qleft);
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF) {
+			if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+				ch->ch_bd->bd_ops->send_stop_character(ch);
+				ch->ch_stops_sent++;
+				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+					"Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
+			}
+		}
+	}
+
+	/*
+	 * Check to see if we should unenforce flow control because
+	 * ld (or user) finally read enuf data out of our queue.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to raise RTS back up,
+	 *	which will allow the other side to start sending data again.
+	 * 2) SWFLOW (IXOFF) - Send a start character to
+	 *	the other side, so it will start sending data to us again.
+	 * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+	 *	other side, we don't need to do anything now.
+	 */
+	if (qleft > (RQUEUESIZE / 2)) {
+		/* HWFLOW */
+		if (ch->ch_c_cflag & CRTSCTS) {
+			if (ch->ch_flags & CH_RECEIVER_OFF) {
+				ch->ch_bd->bd_ops->enable_receiver(ch);
+				ch->ch_flags &= ~(CH_RECEIVER_OFF);
+				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+					"Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+					qleft);
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+			ch->ch_stops_sent = 0;
+			ch->ch_bd->bd_ops->send_start_character(ch);
+			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
+		}
+	}
+}
+
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+int jsm_tty_write(struct uart_port *port)
+{
+	int bufcount = 0, n = 0;
+	int data_count = 0,data_count1 =0;
+	u16 head;
+	u16 tail;
+	u16 tmask;
+	u32 remain;
+	int temp_tail = port->info->xmit.tail;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	tmask = WQUEUEMASK;
+	head = (channel->ch_w_head) & tmask;
+	tail = (channel->ch_w_tail) & tmask;
+
+	if ((bufcount = tail - head - 1) < 0)
+		bufcount += WQUEUESIZE;
+
+	n = bufcount;
+
+	n = min(n, 56);
+	remain = WQUEUESIZE - head;
+
+	data_count = 0;
+	if (n >= remain) {
+		n -= remain;
+		while ((port->info->xmit.head != temp_tail) &&
+		(data_count < remain)) {
+			channel->ch_wqueue[head++] =
+			port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count++;
+		}
+		if (data_count == remain) head = 0;
+	}
+
+	data_count1 = 0;
+	if (n > 0) {
+		remain = n;
+		while ((port->info->xmit.head != temp_tail) &&
+			(data_count1 < remain)) {
+			channel->ch_wqueue[head++] =
+				port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count1++;
+
+		}
+	}
+
+	port->info->xmit.tail = temp_tail;
+
+	data_count += data_count1;
+	if (data_count) {
+		head &= tmask;
+		channel->ch_w_head = head;
+	}
+
+	if (data_count) {
+		channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+	}
+
+	return data_count;
+}
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -26,6 +26,11 @@
  *  serial.c driver, and is currently the preferred form.
  */
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/ioport.h>
@@ -40,12 +45,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#define PORT_SIO	1
-#define PORT_MAX_SIO	1
+#define PORT_M32R_BASE	PORT_M32R_SIO
+#define PORT_INDEX(x)	(x - PORT_M32R_BASE + 1)
 #define BAUD_RATE	115200
 
 #include <linux/serial_core.h>
@@ -53,13 +54,6 @@
 #include "m32r_sio_reg.h"
 
 /*
- * Configuration:
- *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
- *                is unsafe when used on edge-triggered interrupts.
- */
-unsigned int share_irqs_sio = M32R_SIO_SHARE_IRQS;
-
-/*
  * Debugging.
  */
 #if 0
@@ -83,44 +77,41 @@ unsigned int share_irqs_sio = M32R_SIO_S
  */
 #define is_real_interrupt(irq)	((irq) != 0)
 
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects.  You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
+#include <asm/serial.h>
 
-#ifdef CONFIG_SERIAL_M32R_SIO_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_M32R_SIO_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
-#ifdef CONFIG_SERIAL_M32R_SIO_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
+/* Standard COM flags */
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
 /*
- * HUB6 is always on.  This will be removed once the header
- * files have been cleaned.
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism.   Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
  */
-#define CONFIG_HUB6 1
-
-#include <asm/serial.h>
+#undef SERIAL_PORT_DFNS
+#if defined(CONFIG_PLAT_USRV)
 
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-static struct old_serial_port old_serial_port[] = {
-	{ 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, STD_COM_FLAGS },
-};
+#define SERIAL_PORT_DFNS						\
+       /* UART  CLK     PORT   IRQ            FLAGS */			\
+	{ 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
+	{ 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
+
+#else /* !CONFIG_PLAT_USRV */
+
+#if defined(CONFIG_SERIAL_M32R_PLDSIO)
+#define SERIAL_PORT_DFNS						\
+	{ 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV,	\
+	  STD_COM_FLAGS }, /* ttyS0 */
 #else
+#define SERIAL_PORT_DFNS						\
+	{ 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R,		\
+	  STD_COM_FLAGS }, /* ttyS0 */
+#endif
+
+#endif /* !CONFIG_PLAT_USRV */
+
 static struct old_serial_port old_serial_port[] = {
-	{ 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, STD_COM_FLAGS },
+	SERIAL_PORT_DFNS	/* defined in asm/serial.h */
 };
-#endif
 
 #define UART_NR	ARRAY_SIZE(old_serial_port)
 
@@ -153,9 +144,17 @@ static struct irq_info irq_lists[NR_IRQS
 /*
  * Here we define the default xmit fifo size used for each type of UART.
  */
-static const struct serial_uart_config uart_config[PORT_MAX_SIO+1] = {
-	{ "unknown",	1,	0 },
-	{ "M32RSIO",	1,	0 }
+static const struct serial_uart_config uart_config[] = {
+	[PORT_UNKNOWN] = {
+		.name			= "unknown",
+		.dfl_xmit_fifo_size	= 1,
+		.flags			= 0,
+	},
+	[PORT_INDEX(PORT_M32R_SIO)] = {
+		.name			= "M32RSIO",
+		.dfl_xmit_fifo_size	= 1,
+		.flags			= 0,
+	},
 };
 
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
@@ -460,7 +459,6 @@ static inline void m32r_sio_handle_port(
 
 	if (status & 0x04)
 		receive_chars(up, &status, regs);
-	// check_modem_status(up);
 	if (status & 0x01)
 		transmit_chars(up);
 }
@@ -597,10 +595,7 @@ static void serial_unlink_irq_chain(stru
 }
 
 /*
- * This function is used to handle ports that do not have an
- * interrupt.  This doesn't work very well for 16450's, but gives
- * barely passable results for a 16550A.  (Although at the expense
- * of much CPU overhead).
+ * This function is used to handle ports that do not have an interrupt.
  */
 static void m32r_sio_timeout(unsigned long data)
 {
@@ -842,13 +837,12 @@ m32r_sio_request_std_resource(struct uar
 	int ret = 0;
 
 	switch (up->port.iotype) {
-	case SERIAL_IO_MEM:
+	case UPIO_MEM:
 		if (up->port.mapbase) {
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
 			*res = request_mem_region(up->port.mapbase, size, "serial");
 #else
 			start = up->port.mapbase;
-			start += UART_RSA_BASE << up->port.regshift;
 			*res = request_mem_region(start, size, "serial");
 #endif
 			if (!*res)
@@ -856,8 +850,7 @@ m32r_sio_request_std_resource(struct uar
 		}
 		break;
 
-	case SERIAL_IO_HUB6:
-	case SERIAL_IO_PORT:
+	case UPIO_PORT:
 		*res = request_region(up->port.iobase, size, "serial");
 		if (!*res)
 			ret = -EBUSY;
@@ -866,55 +859,15 @@ m32r_sio_request_std_resource(struct uar
 	return ret;
 }
 
-static int
-m32r_sio_request_rsa_resource(struct uart_sio_port *up, struct resource **res)
-{
-	unsigned int size = 8 << up->port.regshift;
-	unsigned long start;
-	int ret = 0;
-
-	switch (up->port.iotype) {
-	case SERIAL_IO_MEM:
-		if (up->port.mapbase) {
-			start = up->port.mapbase;
-			start += UART_RSA_BASE << up->port.regshift;
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-			*res = request_mem_region(start, size, "serial-rsa");
-#else
-			*res = request_mem_region(up->port.mapbase, size, "serial-rsa");
-#endif
-			if (!*res)
-				ret = -EBUSY;
-		}
-		break;
-
-	case SERIAL_IO_HUB6:
-	case SERIAL_IO_PORT:
-		start = up->port.iobase;
-		start += UART_RSA_BASE << up->port.regshift;
-		*res = request_region(up->port.iobase, size, "serial-rsa");
-		if (!*res)
-			ret = -EBUSY;
-		break;
-	}
-
-	return ret;
-}
-
 static void m32r_sio_release_port(struct uart_port *port)
 {
 	struct uart_sio_port *up = (struct uart_sio_port *)port;
 	unsigned long start, offset = 0, size = 0;
 
-	if (up->port.type == PORT_RSA) {
-		offset = UART_RSA_BASE << up->port.regshift;
-		size = 8;
-	}
-
 	size <<= up->port.regshift;
 
 	switch (up->port.iotype) {
-	case SERIAL_IO_MEM:
+	case UPIO_MEM:
 		if (up->port.mapbase) {
 			/*
 			 * Unmap the area.
@@ -930,8 +883,7 @@ static void m32r_sio_release_port(struct
 		}
 		break;
 
-	case SERIAL_IO_HUB6:
-	case SERIAL_IO_PORT:
+	case UPIO_PORT:
 		start = up->port.iobase;
 
 		if (size)
@@ -947,14 +899,9 @@ static void m32r_sio_release_port(struct
 static int m32r_sio_request_port(struct uart_port *port)
 {
 	struct uart_sio_port *up = (struct uart_sio_port *)port;
-	struct resource *res = NULL, *res_rsa = NULL;
+	struct resource *res = NULL;
 	int ret = 0;
 
-	if (up->port.type == PORT_RSA){
-		ret = m32r_sio_request_rsa_resource(up, &res_rsa);
-		if (ret < 0)
-			return ret;
-	}
 	ret = m32r_sio_request_std_resource(up, &res);
 
 	/*
@@ -969,11 +916,10 @@ static int m32r_sio_request_port(struct 
 	}
 
 	if (ret < 0) {
-		if (res_rsa)
-			release_resource(res_rsa);
 		if (res)
 			release_resource(res);
 	}
+
 	return ret;
 }
 
@@ -983,7 +929,7 @@ static void m32r_sio_config_port(struct 
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
-	up->port.type = PORT_SIO;
+	up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
 	up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
@@ -994,8 +940,7 @@ m32r_sio_verify_port(struct uart_port *p
 {
 	if (ser->irq >= NR_IRQS || ser->irq < 0 ||
 	    ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-	    ser->type > PORT_MAX_SIO || ser->type == PORT_CIRRUS ||
-	    ser->type == PORT_STARTECH)
+	    ser->type >= ARRAY_SIZE(uart_config))
 		return -EINVAL;
 	return 0;
 }
@@ -1032,7 +977,7 @@ static struct uart_ops m32r_sio_pops = {
 
 static struct uart_sio_port m32r_sio_ports[UART_NR];
 
-static void __init m32r_sio_isa_init_ports(void)
+static void __init m32r_sio_init_ports(void)
 {
 	struct uart_sio_port *up;
 	static int first = 1;
@@ -1048,13 +993,10 @@ static void __init m32r_sio_isa_init_por
 		up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
 		up->port.uartclk  = old_serial_port[i].baud_base * 16;
 		up->port.flags    = old_serial_port[i].flags;
-		up->port.hub6     = old_serial_port[i].hub6;
 		up->port.membase  = old_serial_port[i].iomem_base;
 		up->port.iotype   = old_serial_port[i].io_type;
 		up->port.regshift = old_serial_port[i].iomem_reg_shift;
 		up->port.ops      = &m32r_sio_pops;
-		if (share_irqs_sio)
-			up->port.flags |= UPF_SHARE_IRQ;
 	}
 }
 
@@ -1062,7 +1004,7 @@ static void __init m32r_sio_register_por
 {
 	int i;
 
-	m32r_sio_isa_init_ports();
+	m32r_sio_init_ports();
 
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_sio_port *up = &m32r_sio_ports[i];
@@ -1196,7 +1138,7 @@ static int __init m32r_sio_console_init(
 {
 	sio_reset();
 	sio_init();
-	m32r_sio_isa_init_ports();
+	m32r_sio_init_ports();
 	register_console(&m32r_sio_console);
 	return 0;
 }
@@ -1218,95 +1160,6 @@ static struct uart_driver m32r_sio_reg =
 	.cons			= M32R_SIO_CONSOLE,
 };
 
-/*
- * register_serial and unregister_serial allows for 16x50 serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-
-static int __register_m32r_sio(struct serial_struct *req, int line)
-{
-	struct uart_port port;
-
-	port.iobase   = req->port;
-	port.membase  = req->iomem_base;
-	port.irq      = req->irq;
-	port.uartclk  = req->baud_base * 16;
-	port.fifosize = req->xmit_fifo_size;
-	port.regshift = req->iomem_reg_shift;
-	port.iotype   = req->io_type;
-	port.flags    = req->flags | UPF_BOOT_AUTOCONF;
-	port.mapbase  = req->iomap_base;
-	port.line     = line;
-
-	if (share_irqs_sio)
-		port.flags |= UPF_SHARE_IRQ;
-
-	if (HIGH_BITS_OFFSET)
-		port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
-	/*
-	 * If a clock rate wasn't specified by the low level
-	 * driver, then default to the standard clock rate.
-	 */
-	if (port.uartclk == 0)
-		port.uartclk = BASE_BAUD * 16;
-
-	return uart_register_port(&m32r_sio_reg, &port);
-}
-
-/**
- *	register_serial - configure a 16x50 serial port at runtime
- *	@req: request structure
- *
- *	Configure the serial port specified by the request. If the
- *	port exists and is in use an error is returned. If the port
- *	is not currently in the table it is added.
- *
- *	The port is then probed and if necessary the IRQ is autodetected
- *	If this fails an error is returned.
- *
- *	On success the port is ready to use and the line number is returned.
- */
-int register_m32r_sio(struct serial_struct *req)
-{
-	return __register_m32r_sio(req, -1);
-}
-
-int __init early_m32r_sio_setup(struct uart_port *port)
-{
-	m32r_sio_isa_init_ports();
- 	m32r_sio_ports[port->line].port = *port;
-	m32r_sio_ports[port->line].port.ops = &m32r_sio_pops;
-
-	return 0;
-}
-
-/**
- *	unregister_serial - remove a 16x50 serial port at runtime
- *	@line: serial line number
- *
- *	Remove one serial port.  This may be called from interrupt
- *	context.
- */
-void unregister_m32r_sio(int line)
-{
-	uart_unregister_port(&m32r_sio_reg, line);
-}
-
-/*
- * This is for ISAPNP only.
- */
-void m32r_sio_get_irq_map(unsigned int *map)
-{
-	int i;
-
-	for (i = 0; i < UART_NR; i++) {
-		if (m32r_sio_ports[i].port.type != PORT_UNKNOWN &&
-		    m32r_sio_ports[i].port.irq < 16)
-			*map |= 1 << m32r_sio_ports[i].port.irq;
-	}
-}
-
 /**
  *	m32r_sio_suspend_port - suspend one serial port
  *	@line: serial line number
@@ -1333,8 +1186,7 @@ static int __init m32r_sio_init(void)
 {
 	int ret, i;
 
-	printk(KERN_INFO "Serial: M32R SIO driver $Revision: 1.9 $ "
-		"IRQ sharing %sabled\n", share_irqs_sio ? "en" : "dis");
+	printk(KERN_INFO "Serial: M32R SIO driver $Revision: 1.11 $ ");
 
 	for (i = 0; i < NR_IRQS; i++)
 		spin_lock_init(&irq_lists[i].lock);
@@ -1359,15 +1211,8 @@ static void __exit m32r_sio_exit(void)
 module_init(m32r_sio_init);
 module_exit(m32r_sio_exit);
 
-EXPORT_SYMBOL(register_m32r_sio);
-EXPORT_SYMBOL(unregister_m32r_sio);
-EXPORT_SYMBOL(m32r_sio_get_irq_map);
 EXPORT_SYMBOL(m32r_sio_suspend_port);
 EXPORT_SYMBOL(m32r_sio_resume_port);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic M32R SIO serial driver $Revision: 1.9 $");
-
-module_param(share_irqs_sio, bool, 0400);
-MODULE_PARM_DESC(share_irqs_sio, "Share IRQs with other non-M32R SIO devices"
-	" (unsafe)");
+MODULE_DESCRIPTION("Generic M32R SIO serial driver $Revision: 1.11 $");
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
--- a/drivers/serial/m32r_sio.h
+++ b/drivers/serial/m32r_sio.h
@@ -36,7 +36,6 @@ struct old_serial_port {
 	unsigned int port;
 	unsigned int irq;
 	unsigned int flags;
-	unsigned char hub6;
 	unsigned char io_type;
 	unsigned char *iomem_base;
 	unsigned short iomem_reg_shift;
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
--- a/drivers/serial/m32r_sio_reg.h
+++ b/drivers/serial/m32r_sio_reg.h
@@ -104,31 +104,6 @@
 #define UART_EMPTY	(UART_LSR_TEMT | UART_LSR_THRE)
 
 /*
- * These are the definitions for the FIFO Control Register
- * (16650 only)
- */
-#define UART_FCR_ENABLE_FIFO	0x01 /* Enable the FIFO */
-#define UART_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
-#define UART_FCR_CLEAR_XMIT	0x04 /* Clear the XMIT FIFO */
-#define UART_FCR_DMA_SELECT	0x08 /* For DMA applications */
-#define UART_FCR_TRIGGER_MASK	0xC0 /* Mask for the FIFO trigger range */
-#define UART_FCR_TRIGGER_1	0x00 /* Mask for trigger set at 1 */
-#define UART_FCR_TRIGGER_4	0x40 /* Mask for trigger set at 4 */
-#define UART_FCR_TRIGGER_8	0x80 /* Mask for trigger set at 8 */
-#define UART_FCR_TRIGGER_14	0xC0 /* Mask for trigger set at 14 */
-/* 16650 redefinitions */
-#define UART_FCR6_R_TRIGGER_8	0x00 /* Mask for receive trigger set at 1 */
-#define UART_FCR6_R_TRIGGER_16	0x40 /* Mask for receive trigger set at 4 */
-#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
-#define UART_FCR6_R_TRIGGER_28	0xC0 /* Mask for receive trigger set at 14 */
-#define UART_FCR6_T_TRIGGER_16	0x00 /* Mask for transmit trigger set at 16 */
-#define UART_FCR6_T_TRIGGER_8	0x10 /* Mask for transmit trigger set at 8 */
-#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
-#define UART_FCR6_T_TRIGGER_30	0x30 /* Mask for transmit trigger set at 30 */
-/* TI 16750 definitions */
-#define UART_FCR7_64BYTE	0x20 /* Go into 64 byte mode */
-
-/*
  * These are the definitions for the Line Control Register
  *
  * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
@@ -174,170 +149,5 @@
 #define UART_IER_RLSI	0x08	/* Enable receiver line status interrupt */
 #define UART_IER_THRI	0x03	/* Enable Transmitter holding register int. */
 #define UART_IER_RDI	0x04	/* Enable receiver data interrupt */
-/*
- * Sleep mode for ST16650 and TI16750.
- * Note that for 16650, EFR-bit 4 must be selected as well.
- */
-#define UART_IERX_SLEEP  0x10	/* Enable sleep mode */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP	0x10	/* Enable loopback test mode */
-#define UART_MCR_OUT2	0x08	/* Out2 complement */
-#define UART_MCR_OUT1	0x04	/* Out1 complement */
-#define UART_MCR_RTS	0x02	/* RTS complement */
-#define UART_MCR_DTR	0x01	/* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD	0x80	/* Data Carrier Detect */
-#define UART_MSR_RI	0x40	/* Ring Indicator */
-#define UART_MSR_DSR	0x20	/* Data Set Ready */
-#define UART_MSR_CTS	0x10	/* Clear to Send */
-#define UART_MSR_DDCD	0x08	/* Delta DCD */
-#define UART_MSR_TERI	0x04	/* Trailing edge ring indicator */
-#define UART_MSR_DDSR	0x02	/* Delta DSR */
-#define UART_MSR_DCTS	0x01	/* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F	/* Any of the delta bits! */
-
-/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
-#define UART_EFR_CTS	0x80	/* CTS flow control */
-#define UART_EFR_RTS	0x40	/* RTS flow control */
-#define UART_EFR_SCD	0x20	/* Special character detect */
-#define UART_EFR_ECB	0x10	/* Enhanced control bit */
-/*
- * the low four bits control software flow control
- */
-
-/*
- * These register definitions are for the 16C950
- */
-#define UART_ASR	0x01	/* Additional Status Register */
-#define UART_RFL	0x03	/* Receiver FIFO level */
-#define UART_TFL 	0x04	/* Transmitter FIFO level */
-#define UART_ICR	0x05	/* Index Control Register */
-
-/* The 16950 ICR registers */
-#define UART_ACR	0x00	/* Additional Control Register */
-#define UART_CPR	0x01	/* Clock Prescalar Register */
-#define UART_TCR	0x02	/* Times Clock Register */
-#define UART_CKS	0x03	/* Clock Select Register */
-#define UART_TTL	0x04	/* Transmitter Interrupt Trigger Level */
-#define UART_RTL	0x05	/* Receiver Interrupt Trigger Level */
-#define UART_FCL	0x06	/* Flow Control Level Lower */
-#define UART_FCH	0x07	/* Flow Control Level Higher */
-#define UART_ID1	0x08	/* ID #1 */
-#define UART_ID2	0x09	/* ID #2 */
-#define UART_ID3	0x0A	/* ID #3 */
-#define UART_REV	0x0B	/* Revision */
-#define UART_CSR	0x0C	/* Channel Software Reset */
-#define UART_NMR	0x0D	/* Nine-bit Mode Register */
-#define UART_CTR	0xFF
-
-/*
- * The 16C950 Additional Control Reigster
- */
-#define UART_ACR_RXDIS	0x01	/* Receiver disable */
-#define UART_ACR_TXDIS	0x02	/* Receiver disable */
-#define UART_ACR_DSRFC	0x04	/* DSR Flow Control */
-#define UART_ACR_TLENB	0x20	/* 950 trigger levels enable */
-#define UART_ACR_ICRRD	0x40	/* ICR Read enable */
-#define UART_ACR_ASREN	0x80	/* Additional status enable */
-
-/*
- * These are the definitions for the Feature Control Register
- * (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
- * Register, UART register #1)
- */
-#define UART_FCTR_RTS_NODELAY	0x00  /* RTS flow control delay */
-#define UART_FCTR_RTS_4DELAY	0x01
-#define UART_FCTR_RTS_6DELAY	0x02
-#define UART_FCTR_RTS_8DELAY	0x03
-#define UART_FCTR_IRDA	0x04  /* IrDa data encode select */
-#define UART_FCTR_TX_INT	0x08  /* Tx interrupt type select */
-#define UART_FCTR_TRGA	0x00  /* Tx/Rx 550 trigger table select */
-#define UART_FCTR_TRGB	0x10  /* Tx/Rx 650 trigger table select */
-#define UART_FCTR_TRGC	0x20  /* Tx/Rx 654 trigger table select */
-#define UART_FCTR_TRGD	0x30  /* Tx/Rx 850 programmable trigger select */
-#define UART_FCTR_SCR_SWAP	0x40  /* Scratch pad register swap */
-#define UART_FCTR_RX	0x00  /* Programmable trigger mode select */
-#define UART_FCTR_TX	0x80  /* Programmable trigger mode select */
-
-/*
- * These are the definitions for the Enhanced Mode Select Register
- * (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
- * Scratch register, UART register #7)
- */
-#define UART_EMSR_FIFO_COUNT	0x01  /* Rx/Tx select */
-#define UART_EMSR_ALT_COUNT	0x02  /* Alternating count select */
-
-/*
- * These are the definitions for the Programmable Trigger
- * Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
- * register, UART register #0)
- */
-#define UART_TRG_1	0x01
-#define UART_TRG_4	0x04
-#define UART_TRG_8	0x08
-#define UART_TRG_16	0x10
-#define UART_TRG_32	0x20
-#define UART_TRG_64	0x40
-#define UART_TRG_96	0x60
-#define UART_TRG_120	0x78
-#define UART_TRG_128	0x80
-
-/*
- * These definitions are for the RSA-DV II/S card, from
- *
- * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
- */
-
-#define UART_RSA_BASE (-8)
-
-#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
-
-#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
-#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
-#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
-#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
-
-#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
-
-#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
-#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
-#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
-#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
-#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
-
-#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
-
-#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
-#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
-#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
-#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
-#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
-#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
-#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
-#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
-
-#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
-
-#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
-
-#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
-
-#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
-
-/*
- * The RSA DSV/II board has two fixed clock frequencies.  One is the
- * standard rate, and the other is 8 times faster.
- */
-#define SERIAL_RSA_BAUD_BASE (921600)
-#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
 
 #endif /* _M32R_SIO_REG_H */
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -138,18 +138,6 @@ extern int	magic_sysrq_key(int ch);
 
 
 /*
- * 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 mcfrs_tmp_buf[4096]; /* This is cheating */
-static DECLARE_MUTEX(mcfrs_tmp_buf_sem);
-
-/*
  *	Forware declarations...
  */
 static void	mcfrs_change_speed(struct mcf_serial *info);
@@ -1092,23 +1080,19 @@ static int mcfrs_ioctl(struct tty_struct
 				 (arg ? CLOCAL : 0));
 			return 0;
 		case TIOCGSERIAL:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct));
-			if (error)
-				return error;
-			return get_serial_info(info,
+			if (access_ok(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct)))
+				return get_serial_info(info,
 					       (struct serial_struct *) arg);
+			return -EFAULT;
 		case TIOCSSERIAL:
 			return set_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return get_lsr_info(info, (unsigned int *) arg);
-
+			if (access_ok(VERIFY_WRITE, (void *) arg,
+						sizeof(unsigned int)))
+				return get_lsr_info(info, (unsigned int *) arg);
+			return -EFAULT;
 		case TIOCSERGSTRUCT:
 			error = copy_to_user((struct mcf_serial *) arg,
 				    info, sizeof(struct mcf_serial));
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -18,7 +18,7 @@
  * Some of the code has been inspired/copied from the 2.4 code written
  * by Dale Farnsworth <dfarnsworth@mvista.com>.
  * 
- * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
  * Copyright (C) 2003 MontaVista, Software, Inc.
  * 
  * This file is licensed under the terms of the GNU General Public License
@@ -26,33 +26,26 @@
  * kind, whether express or implied.
  */
  
-/* OCP Usage :
+/* Platform device Usage :
  *
- * This drivers uses the OCP model. To load the serial driver for one of the
- * PSCs, just add this to the core_ocp table :
+ * Since PSCs can have multiple function, the correct driver for each one
+ * is selected by calling mpc52xx_match_psc_function(...). The function
+ * handled by this driver is "uart".
  *
- * {
- * 	.vendor         = OCP_VENDOR_FREESCALE,
- * 	.function       = OCP_FUNC_PSC_UART,
- * 	.index          = 0,
- * 	.paddr          = MPC52xx_PSC1,
- * 	.irq            = MPC52xx_PSC1_IRQ,
- * 	.pm             = OCP_CPM_NA,
- * },
- *
- * This is for PSC1, replace the paddr and irq according to the PSC you want to
- * use. The driver all necessary registers to place the PSC in uart mode without
+ * The driver init all necessary registers to place the PSC in uart mode without
  * DCD. However, the pin multiplexing aren't changed and should be set either
  * by the bootloader or in the platform init code.
- * The index field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2,
+ *
+ * The idx field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2,
  * and so on). So the PSC1 is mapped to /dev/ttyS0, PSC2 to /dev/ttyS1 and so
  * on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly for
  * the console code : without this 1:1 mapping, at early boot time, when we are
  * parsing the kernel args console=ttyS?, we wouldn't know wich PSC it will be
- * mapped to because OCP stuff is not yet initialized.
+ * mapped to.
  */
 
 #include <linux/config.h>
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/serial.h>
@@ -61,7 +54,6 @@
 
 #include <asm/delay.h>
 #include <asm/io.h>
-#include <asm/ocp.h>
 
 #include <asm/mpc52xx.h>
 #include <asm/mpc52xx_psc.h>
@@ -86,7 +78,7 @@ static struct uart_port mpc52xx_uart_por
 	 *        the console_init
 	 */
 
-#define PSC(port) ((struct mpc52xx_psc *)((port)->membase))
+#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
 
 
 /* Forward declaration of the interruption handling routine */
@@ -190,7 +182,14 @@ mpc52xx_uart_break_ctl(struct uart_port 
 static int
 mpc52xx_uart_startup(struct uart_port *port)
 {
-	struct mpc52xx_psc *psc = PSC(port);
+	struct mpc52xx_psc __iomem *psc = PSC(port);
+	int ret;
+
+	/* Request IRQ */
+	ret = request_irq(port->irq, mpc52xx_uart_int,
+		SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
+	if (ret)
+		return ret;
 
 	/* Reset/activate the port, clear and enable interrupts */
 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
@@ -217,7 +216,7 @@ mpc52xx_uart_startup(struct uart_port *p
 static void
 mpc52xx_uart_shutdown(struct uart_port *port)
 {
-	struct mpc52xx_psc *psc = PSC(port);
+	struct mpc52xx_psc __iomem *psc = PSC(port);
 	
 	/* Shut down the port, interrupt and all */
 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
@@ -225,13 +224,16 @@ mpc52xx_uart_shutdown(struct uart_port *
 	
 	port->read_status_mask = 0; 
 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+
+	/* Release interrupt */
+	free_irq(port->irq, port);
 }
 
 static void 
 mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
                          struct termios *old)
 {
-	struct mpc52xx_psc *psc = PSC(port);
+	struct mpc52xx_psc __iomem *psc = PSC(port);
 	unsigned long flags;
 	unsigned char mr1, mr2;
 	unsigned short ctr;
@@ -326,15 +328,21 @@ mpc52xx_uart_release_port(struct uart_po
 		iounmap(port->membase);
 		port->membase = NULL;
 	}
+
+	release_mem_region(port->mapbase, MPC52xx_PSC_SIZE);
 }
 
 static int
 mpc52xx_uart_request_port(struct uart_port *port)
 {
 	if (port->flags & UPF_IOREMAP) /* Need to remap ? */
-		port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
-	
-	return port->membase != NULL ? 0 : -EBUSY;
+		port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
+
+	if (!port->membase)
+		return -EINVAL;
+
+	return request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
+			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
 }
 
 static void
@@ -354,7 +362,7 @@ mpc52xx_uart_verify_port(struct uart_por
 	if ( (ser->irq != port->irq) ||
 	     (ser->io_type != SERIAL_IO_MEM) ||
 	     (ser->baud_base != port->uartclk)  || 
-	     // FIXME Should check addresses/irq as well ?
+	     (ser->iomem_base != (void*)port->mapbase) ||
 	     (ser->hub6 != 0 ) )
 		return -EINVAL;
 
@@ -562,7 +570,7 @@ static void __init
 mpc52xx_console_get_options(struct uart_port *port,
                             int *baud, int *parity, int *bits, int *flow)
 {
-	struct mpc52xx_psc *psc = PSC(port);
+	struct mpc52xx_psc __iomem *psc = PSC(port);
 	unsigned char mr1;
 
 	/* Read the mode registers */
@@ -592,7 +600,7 @@ static void  
 mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
-	struct mpc52xx_psc *psc = PSC(port);
+	struct mpc52xx_psc __iomem *psc = PSC(port);
 	unsigned int i, j;
 	
 	/* Disable interrupts */
@@ -630,7 +638,7 @@ mpc52xx_console_setup(struct console *co
 {
 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
 
-	int baud = 9600;
+	int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
@@ -643,14 +651,12 @@ mpc52xx_console_setup(struct console *co
 	spin_lock_init(&port->lock);
 	port->uartclk	= __res.bi_ipbfreq / 2; /* Look at CTLR doc */
 	port->ops	= &mpc52xx_uart_ops;
-	port->mapbase	= MPC52xx_PSCx(co->index);
+	port->mapbase	= MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1));
 
-		/* We ioremap ourself */
-	port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
-	if (port->membase == NULL) {
-		release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
-		return -EBUSY;
-	}
+	/* We ioremap ourself */
+	port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
+	if (port->membase == NULL)
+		return -EINVAL;
 
 	/* Setup the port parameters accoding to options */
 	if (options)
@@ -707,26 +713,32 @@ static struct uart_driver mpc52xx_uart_d
 
 
 /* ======================================================================== */
-/* OCP Driver                                                               */
+/* Platform Driver                                                          */
 /* ======================================================================== */
 
 static int __devinit
-mpc52xx_uart_probe(struct ocp_device *ocp)
+mpc52xx_uart_probe(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res = pdev->resource;
+
 	struct uart_port *port = NULL;
-	int idx, ret;
+	int i, idx, ret;
 
-	/* Get the corresponding port struct */
-	idx = ocp->def->index;
+	/* Check validity & presence */
+	idx = pdev->id;
 	if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
 		return -EINVAL;
-	
-	port = &mpc52xx_uart_ports[idx];
+
+	if (!mpc52xx_match_psc_function(idx,"uart"))
+		return -ENODEV;
 
 	/* Init the port structure */
+	port = &mpc52xx_uart_ports[idx];
+
+	memset(port, 0x00, sizeof(struct uart_port));
+
 	spin_lock_init(&port->lock);
-	port->mapbase	= ocp->def->paddr;
-	port->irq	= ocp->def->irq;
 	port->uartclk	= __res.bi_ipbfreq / 2; /* Look at CTLR doc */
 	port->fifosize	= 255; /* Should be 512 ! But it can't be */
 	                       /* stored in a unsigned char       */
@@ -735,95 +747,65 @@ mpc52xx_uart_probe(struct ocp_device *oc
 			  ( uart_console(port) ? 0 : UPF_IOREMAP );
 	port->line	= idx;
 	port->ops	= &mpc52xx_uart_ops;
-	port->read_status_mask = 0;
-	
-	/* Requests the mem & irqs */
-	/* Unlike other serial drivers, we reserve the resources here, so we
-	 * can detect early if multiple drivers uses the same PSC. Special
-	 * care must be taken with the console PSC
-	 */
-	ret = request_irq(
-		port->irq, mpc52xx_uart_int,
-		SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
-	if (ret)
-		goto error;
 
-	ret = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
-	                         "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
-	if (ret)
-		goto free_irq;
+	/* Search for IRQ and mapbase */
+	for (i=0 ; i<pdev->num_resources ; i++, res++) {
+		if (res->flags & IORESOURCE_MEM)
+			port->mapbase = res->start;
+		else if (res->flags & IORESOURCE_IRQ)
+			port->irq = res->start;
+	}
+	if (!port->irq || !port->mapbase)
+		return -EINVAL;
 
 	/* Add the port to the uart sub-system */
 	ret = uart_add_one_port(&mpc52xx_uart_driver, port);
-	if (ret)
-		goto release_mem;
-
-	ocp_set_drvdata(ocp, (void*)port);
-
-	return 0;
-
-
-free_irq:
-	free_irq(port->irq, mpc52xx_uart_int);
-
-release_mem:
-	release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
-
-error:
-	if (uart_console(port))
-		printk(	"mpc52xx_uart.c: Error during resource alloction for "
-			"the console port !!! Check that the console PSC is "
-			"not used by another OCP driver !!!\n" );
+	if (!ret)
+		dev_set_drvdata(dev, (void*)port);
 
 	return ret;
 }
 
-static void
-mpc52xx_uart_remove(struct ocp_device *ocp)
+static int
+mpc52xx_uart_remove(struct device *dev)
 {
-	struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
 
-	ocp_set_drvdata(ocp, NULL);
+	dev_set_drvdata(dev, NULL);
 
-	if (port) {
+	if (port)
 		uart_remove_one_port(&mpc52xx_uart_driver, port);
-		release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
-		free_irq(port->irq, mpc52xx_uart_int);
-	}
+
+	return 0;
 }
 
 #ifdef CONFIG_PM
 static int
-mpc52xx_uart_suspend(struct ocp_device *ocp, u32 state)
+mpc52xx_uart_suspend(struct device *dev, u32 state, u32 level)
 {
-	struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
 
-	uart_suspend_port(&mpc52xx_uart_driver, port);
+	if (sport && level == SUSPEND_DISABLE)
+		uart_suspend_port(&mpc52xx_uart_driver, port);
 
 	return 0;
 }
 
 static int
-mpc52xx_uart_resume(struct ocp_device *ocp)
+mpc52xx_uart_resume(struct device *dev, u32 level)
 {
-	struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
 
-	uart_resume_port(&mpc52xx_uart_driver, port);
+	if (port && level == RESUME_ENABLE)
+		uart_resume_port(&mpc52xx_uart_driver, port);
 
 	return 0;
 }
 #endif
 
-static struct ocp_device_id mpc52xx_uart_ids[] __devinitdata = {
-	{ .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_PSC_UART },
-	{ .vendor = OCP_VENDOR_INVALID /* Terminating entry */ }
-};
-
-MODULE_DEVICE_TABLE(ocp, mpc52xx_uart_ids);
-
-static struct ocp_driver mpc52xx_uart_ocp_driver = {
-	.name		= "mpc52xx_psc_uart",
-	.id_table	= mpc52xx_uart_ids,
+static struct device_driver mpc52xx_uart_platform_driver = {
+	.name		= "mpc52xx-psc",
+	.bus		= &platform_bus_type,
 	.probe		= mpc52xx_uart_probe,
 	.remove		= mpc52xx_uart_remove,
 #ifdef CONFIG_PM
@@ -845,10 +827,11 @@ mpc52xx_uart_init(void)
 	printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
 
 	ret = uart_register_driver(&mpc52xx_uart_driver);
-	if (ret)
-		return ret;
-
-	ret = ocp_register_driver(&mpc52xx_uart_ocp_driver);
+	if (ret == 0) {
+		ret = driver_register(&mpc52xx_uart_platform_driver);
+		if (ret)
+			uart_unregister_driver(&mpc52xx_uart_driver);
+	}
 
 	return ret;
 }
@@ -856,7 +839,7 @@ mpc52xx_uart_init(void)
 static void __exit
 mpc52xx_uart_exit(void)
 {
-	ocp_unregister_driver(&mpc52xx_uart_ocp_driver);
+	driver_unregister(&mpc52xx_uart_platform_driver);
 	uart_unregister_driver(&mpc52xx_uart_driver);
 }
 
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -329,8 +329,8 @@ mpsc_sdma_stop(struct mpsc_port_info *pi
 	mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
 
 	/* Clear the SDMA current and first TX and RX pointers */
-	mpsc_sdma_set_tx_ring(pi, 0);
-	mpsc_sdma_set_rx_ring(pi, 0);
+	mpsc_sdma_set_tx_ring(pi, NULL);
+	mpsc_sdma_set_rx_ring(pi, NULL);
 
 	/* Disable interrupts */
 	mpsc_sdma_intr_mask(pi, 0xf);
@@ -1540,8 +1540,8 @@ mpsc_shared_unmap_regs(void)
 			MPSC_SDMA_INTR_REG_BLOCK_SIZE);
 	}
 
-	mpsc_shared_regs.mpsc_routing_base = 0;
-	mpsc_shared_regs.sdma_intr_base = 0;
+	mpsc_shared_regs.mpsc_routing_base = NULL;
+	mpsc_shared_regs.sdma_intr_base = NULL;
 
 	mpsc_shared_regs.mpsc_routing_base_p = 0;
 	mpsc_shared_regs.sdma_intr_base_p = 0;
@@ -1678,9 +1678,9 @@ mpsc_drv_unmap_regs(struct mpsc_port_inf
 		release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
 	}
 
-	pi->mpsc_base = 0;
-	pi->sdma_base = 0;
-	pi->brg_base = 0;
+	pi->mpsc_base = NULL;
+	pi->sdma_base = NULL;
+	pi->brg_base = NULL;
 
 	pi->mpsc_base_p = 0;
 	pi->sdma_base_p = 0;
diff --git a/drivers/serial/mpsc.h b/drivers/serial/mpsc.h
--- a/drivers/serial/mpsc.h
+++ b/drivers/serial/mpsc.h
@@ -83,8 +83,8 @@ struct mpsc_shared_regs {
 	phys_addr_t mpsc_routing_base_p;
 	phys_addr_t sdma_intr_base_p;
 
-	void *mpsc_routing_base;
-	void *sdma_intr_base;
+	void __iomem *mpsc_routing_base;
+	void __iomem *sdma_intr_base;
 
 	u32 MPSC_MRR_m;
 	u32 MPSC_RCRR_m;
@@ -120,9 +120,9 @@ struct mpsc_port_info {
 	phys_addr_t brg_base_p;
 
 	/* Virtual addresses of various blocks of registers (from platform) */
-	void *mpsc_base;
-	void *sdma_base;
-	void *brg_base;
+	void __iomem *mpsc_base;
+	void __iomem *sdma_base;
+	void __iomem *brg_base;
 
 	/* Descriptor ring and buffer allocations */
 	void *dma_region;
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -404,7 +404,7 @@ static struct console mux_console = {
 	.write =	mux_console_write,
 	.device =	mux_console_device,
 	.setup =	mux_console_setup,
-	.flags =	CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
+	.flags =	CON_ENABLED | CON_PRINTBUFFER,
 	.index =	0,
 };
 
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1590,7 +1590,7 @@ static int pmz_detach(struct macio_dev *
 }
 
 
-static int pmz_suspend(struct macio_dev *mdev, u32 pm_state)
+static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
 {
 	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
 	struct uart_state *state;
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, 
 			else if (*status & UART_LSR_FE)
 				flag = TTY_FRAME;
 		}
+
 		if (uart_handle_sysrq_char(&up->port, ch, regs))
 			goto ignore_char;
-		if ((*status & up->port.ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((*status & UART_LSR_OE) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+
+		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+
 	ignore_char:
 		*status = serial_in(up, UART_LSR);
 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
@@ -797,7 +789,7 @@ static struct uart_driver serial_pxa_reg
 	.cons		= PXA_CONSOLE,
 };
 
-static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level)
+static int serial_pxa_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
         struct uart_pxa_port *sport = dev_get_drvdata(_dev);
 
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -5,7 +5,8 @@
  *
  * Based on drivers/char/serial.c and drivers/char/21285.c
  *
- * Ben Dooks, (c) 2003 Simtec Electronics
+ * Ben Dooks, (c) 2003-2005 Simtec Electronics
+ *	http://www.simtec.co.uk/products/SWLINUX/
  *
  * Changelog:
  *
@@ -24,6 +25,19 @@
  *		     - spin-lock initialisation (Dimitry Andric)
  *		     - added clock control
  *		     - updated init code to use platform_device info
+ *
+ * 06-Mar-2005  BJD  Add s3c2440 fclk clock source
+ *
+ * 09-Mar-2005  BJD  Add s3c2400 support
+ *
+ * 10-Mar-2005  LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
+*/
+
+/* Note on 2440 fclk clock source handling
+ *
+ * Whilst it is possible to use the fclk as clock source, the method
+ * of properly switching too/from this is currently un-implemented, so
+ * whichever way is configured at startup is the one that will be used.
 */
 
 /* Hote on 2410 error handling
@@ -87,6 +101,9 @@ struct s3c24xx_uart_info {
 
 	int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
 	int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+
+	/* uart controls */
+	int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
 };
 
 struct s3c24xx_uart_port {
@@ -347,7 +364,7 @@ s3c24xx_serial_rx_chars(int irq, void *d
 		flag = TTY_NORMAL;
 		port->icount.rx++;
 
-		if (uerstat & S3C2410_UERSTAT_ANY) {
+		if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
 			dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
 			    ch, uerstat);
 
@@ -377,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *d
 		if (uart_handle_sysrq_char(port, ch, regs))
 			goto ignore_char;
 
-		if ((uerstat & port->ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-
-		if ((uerstat & S3C2410_UERSTAT_OVERRUN) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+		uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
 
 	ignore_char:
 		continue;
@@ -606,11 +610,6 @@ static void s3c24xx_serial_pm(struct uar
  * baud clocks (and the resultant actual baud rates) and then tries to
  * pick the closest one and select that.
  *
- * NOTES:
- *	1) there is no current code to properly select/deselect FCLK on
- *	   the s3c2440, so only specify FCLK or non-FCLK in the clock
- *	   sources for the UART
- *
 */
 
 
@@ -658,6 +657,7 @@ static int s3c24xx_serial_calcbaud(struc
 		return 0;
 
 	rate = clk_get_rate(calc->src);
+	rate /= clksrc->divisor;
 
 	calc->clksrc = clksrc;
 	calc->quot = (rate + (8 * baud)) / (16 * baud);
@@ -685,6 +685,27 @@ static unsigned int s3c24xx_serial_getcl
 		if (cfg->clocks_size == 0)
 			clkp = &tmp_clksrc;
 
+		/* check to see if we're sourcing fclk, and if so we're
+		 * going to have to update the clock source
+		 */
+
+		if (strcmp(clkp->name, "fclk") == 0) {
+			struct s3c24xx_uart_clksrc src;
+
+			s3c24xx_serial_getsource(port, &src);
+
+			/* check that the port already using fclk, and if
+			 * not, then re-select fclk
+			 */
+
+			if (strcmp(src.name, clkp->name) == 0) {
+				s3c24xx_serial_setsource(port, clkp);
+				s3c24xx_serial_getsource(port, &src);
+			}
+
+			clkp->divisor = src.divisor;
+		}
+
 		s3c24xx_serial_calcbaud(res, port, clkp, baud);
 		best = res;
 		resptr = best + 1;
@@ -955,8 +976,6 @@ static struct s3c24xx_uart_port s3c24xx_
 	[0] = {
 		.port = {
 			.lock		= SPIN_LOCK_UNLOCKED,
-			.membase	= 0,
-			.mapbase	= 0,
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX0,
 			.uartclk	= 0,
@@ -969,8 +988,6 @@ static struct s3c24xx_uart_port s3c24xx_
 	[1] = {
 		.port = {
 			.lock		= SPIN_LOCK_UNLOCKED,
-			.membase	= 0,
-			.mapbase	= 0,
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX1,
 			.uartclk	= 0,
@@ -985,8 +1002,6 @@ static struct s3c24xx_uart_port s3c24xx_
 	[2] = {
 		.port = {
 			.lock		= SPIN_LOCK_UNLOCKED,
-			.membase	= 0,
-			.mapbase	= 0,
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX2,
 			.uartclk	= 0,
@@ -999,24 +1014,18 @@ static struct s3c24xx_uart_port s3c24xx_
 #endif
 };
 
+/* s3c24xx_serial_resetport
+ *
+ * wrapper to call the specific reset for this port (reset the fifos
+ * and the settings)
+*/
 
-static int s3c24xx_serial_resetport(struct uart_port *port,
-				    struct s3c2410_uartcfg *cfg)
+static inline int s3c24xx_serial_resetport(struct uart_port * port,
+					   struct s3c2410_uartcfg *cfg)
 {
-	/* ensure registers are setup */
-
-	dbg("s3c24xx_serial_resetport: port=%p (%08lx), cfg=%p\n",
-	    port, port->mapbase, cfg);
-
-	wr_regl(port, S3C2410_UCON,  cfg->ucon);
-	wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-	/* reset both fifos */
-
-	wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-	wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+	struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
 
-	return 0;
+	return (info->reset_port)(port, cfg);
 }
 
 /* s3c24xx_serial_init_port
@@ -1072,8 +1081,7 @@ static int s3c24xx_serial_init_port(stru
 	dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
 
 	port->mapbase	= res->start;
-	port->membase	= (void __iomem *)(res->start - S3C2410_PA_UART);
-	port->membase  += S3C2410_VA_UART;
+	port->membase	= S3C24XX_VA_UART + (res->start - S3C2410_PA_UART);
 	port->irq	= platform_get_irq(platdev, 0);
 
 	ourport->clk	= clk_get(&platdev->dev, "uart");
@@ -1135,7 +1143,7 @@ int s3c24xx_serial_remove(struct device 
 
 #ifdef CONFIG_PM
 
-int s3c24xx_serial_suspend(struct device *dev, u32 state, u32 level)
+int s3c24xx_serial_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct uart_port *port = s3c24xx_dev_to_port(dev);
 
@@ -1180,6 +1188,97 @@ int s3c24xx_serial_init(struct device_dr
 
 /* cpu specific variations on the serial port support */
 
+#ifdef CONFIG_CPU_S3C2400
+
+static int s3c2400_serial_getsource(struct uart_port *port,
+				    struct s3c24xx_uart_clksrc *clk)
+{
+	clk->divisor = 1;
+	clk->name = "pclk";
+
+	return 0;
+}
+
+static int s3c2400_serial_setsource(struct uart_port *port,
+				    struct s3c24xx_uart_clksrc *clk)
+{
+	return 0;
+}
+
+static int s3c2400_serial_resetport(struct uart_port *port,
+				    struct s3c2410_uartcfg *cfg)
+{
+	dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+	    port, port->mapbase, cfg);
+
+	wr_regl(port, S3C2410_UCON,  cfg->ucon);
+	wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+	/* reset both fifos */
+
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+	return 0;
+}
+
+static struct s3c24xx_uart_info s3c2400_uart_inf = {
+	.name		= "Samsung S3C2400 UART",
+	.type		= PORT_S3C2400,
+	.fifosize	= 16,
+	.rx_fifomask	= S3C2410_UFSTAT_RXMASK,
+	.rx_fifoshift	= S3C2410_UFSTAT_RXSHIFT,
+	.rx_fifofull	= S3C2410_UFSTAT_RXFULL,
+	.tx_fifofull	= S3C2410_UFSTAT_TXFULL,
+	.tx_fifomask	= S3C2410_UFSTAT_TXMASK,
+	.tx_fifoshift	= S3C2410_UFSTAT_TXSHIFT,
+	.get_clksrc	= s3c2400_serial_getsource,
+	.set_clksrc	= s3c2400_serial_setsource,
+	.reset_port	= s3c2400_serial_resetport,
+};
+
+static int s3c2400_serial_probe(struct device *dev)
+{
+	return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
+}
+
+static struct device_driver s3c2400_serial_drv = {
+	.name		= "s3c2400-uart",
+	.bus		= &platform_bus_type,
+	.probe		= s3c2400_serial_probe,
+	.remove		= s3c24xx_serial_remove,
+	.suspend	= s3c24xx_serial_suspend,
+	.resume		= s3c24xx_serial_resume,
+};
+
+static inline int s3c2400_serial_init(void)
+{
+	return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
+}
+
+static inline void s3c2400_serial_exit(void)
+{
+	driver_unregister(&s3c2400_serial_drv);
+}
+
+#define s3c2400_uart_inf_at &s3c2400_uart_inf
+#else
+
+static inline int s3c2400_serial_init(void)
+{
+	return 0;
+}
+
+static inline void s3c2400_serial_exit(void)
+{
+}
+
+#define s3c2400_uart_inf_at NULL
+
+#endif /* CONFIG_CPU_S3C2400 */
+
+/* S3C2410 support */
+
 #ifdef CONFIG_CPU_S3C2410
 
 static int s3c2410_serial_setsource(struct uart_port *port,
@@ -1207,6 +1306,23 @@ static int s3c2410_serial_getsource(stru
 	return 0;
 }
 
+static int s3c2410_serial_resetport(struct uart_port *port,
+				    struct s3c2410_uartcfg *cfg)
+{
+	dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
+	    port, port->mapbase, cfg);
+
+	wr_regl(port, S3C2410_UCON,  cfg->ucon);
+	wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+	/* reset both fifos */
+
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+	return 0;
+}
+
 static struct s3c24xx_uart_info s3c2410_uart_inf = {
 	.name		= "Samsung S3C2410 UART",
 	.type		= PORT_S3C2410,
@@ -1219,6 +1335,7 @@ static struct s3c24xx_uart_info s3c2410_
 	.tx_fifoshift	= S3C2410_UFSTAT_TXSHIFT,
 	.get_clksrc	= s3c2410_serial_getsource,
 	.set_clksrc	= s3c2410_serial_setsource,
+	.reset_port	= s3c2410_serial_resetport,
 };
 
 /* device management */
@@ -1294,6 +1411,7 @@ static int s3c2440_serial_getsource(stru
 				    struct s3c24xx_uart_clksrc *clk)
 {
 	unsigned long ucon = rd_regl(port, S3C2410_UCON);
+	unsigned long ucon0, ucon1, ucon2;
 
 	switch (ucon & S3C2440_UCON_CLKMASK) {
 	case S3C2440_UCON_UCLK:
@@ -1308,7 +1426,33 @@ static int s3c2440_serial_getsource(stru
 		break;
 
 	case S3C2440_UCON_FCLK:
-		clk->divisor = 7; /* todo - work out divisor */
+		/* the fun of calculating the uart divisors on
+		 * the s3c2440 */
+
+		ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
+		ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
+		ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
+
+		printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
+
+		ucon0 &= S3C2440_UCON0_DIVMASK;
+		ucon1 &= S3C2440_UCON1_DIVMASK;
+		ucon2 &= S3C2440_UCON2_DIVMASK;
+
+		if (ucon0 != 0) {
+			clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
+			clk->divisor += 6;
+		} else if (ucon1 != 0) {
+			clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
+			clk->divisor += 21;
+		} else if (ucon2 != 0) {
+			clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
+			clk->divisor += 36;
+		} else {
+			/* manual calims 44, seems to be 9 */
+			clk->divisor = 9;
+		}
+
 		clk->name = "fclk";
 		break;
 	}
@@ -1316,6 +1460,28 @@ static int s3c2440_serial_getsource(stru
 	return 0;
 }
 
+static int s3c2440_serial_resetport(struct uart_port *port,
+				    struct s3c2410_uartcfg *cfg)
+{
+	unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+	dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
+	    port, port->mapbase, cfg);
+
+	/* ensure we don't change the clock settings... */
+
+	ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
+
+	wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+	wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+	/* reset both fifos */
+
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+	wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+	return 0;
+}
 
 static struct s3c24xx_uart_info s3c2440_uart_inf = {
 	.name		= "Samsung S3C2440 UART",
@@ -1328,7 +1494,8 @@ static struct s3c24xx_uart_info s3c2440_
 	.tx_fifomask	= S3C2440_UFSTAT_TXMASK,
 	.tx_fifoshift	= S3C2440_UFSTAT_TXSHIFT,
 	.get_clksrc	= s3c2440_serial_getsource,
-	.set_clksrc	= s3c2440_serial_setsource
+	.set_clksrc	= s3c2440_serial_setsource,
+	.reset_port	= s3c2440_serial_resetport,
 };
 
 /* device management */
@@ -1386,6 +1553,7 @@ static int __init s3c24xx_serial_modinit
 		return -1;
 	}
 
+	s3c2400_serial_init();
 	s3c2410_serial_init();
 	s3c2440_serial_init();
 
@@ -1394,6 +1562,7 @@ static int __init s3c24xx_serial_modinit
 
 static void __exit s3c24xx_serial_modexit(void)
 {
+	s3c2400_serial_exit();
 	s3c2410_serial_exit();
 	s3c2440_serial_exit();
 
@@ -1509,7 +1678,7 @@ s3c24xx_serial_get_options(struct uart_p
 
 		clk = clk_get(port->dev, clksrc.name);
 		if (!IS_ERR(clk) && clk != NULL)
-			rate = clk_get_rate(clk);
+			rate = clk_get_rate(clk) / clksrc.divisor;
 		else
 			rate = 1;
 
@@ -1603,7 +1772,6 @@ static struct console s3c24xx_serial_con
 	.setup		= s3c24xx_serial_console_setup
 };
 
-
 static int s3c24xx_serial_initconsole(void)
 {
 	struct s3c24xx_uart_info *info;
@@ -1618,7 +1786,9 @@ static int s3c24xx_serial_initconsole(vo
 		return 0;
 	}
 
-	if (strcmp(dev->name, "s3c2410-uart") == 0) {
+	if (strcmp(dev->name, "s3c2400-uart") == 0) {
+		info = s3c2400_uart_inf_at;
+	} else if (strcmp(dev->name, "s3c2410-uart") == 0) {
 		info = s3c2410_uart_inf_at;
 	} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
 		info = s3c2440_uart_inf_at;
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -197,7 +197,7 @@ static void
 sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
 {
 	struct tty_struct *tty = sport->port.info->tty;
-	unsigned int status, ch, flg, ignored = 0;
+	unsigned int status, ch, flg;
 
 	status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
 		 UTSR0_TO_SM(UART_GET_UTSR0(sport));
@@ -214,56 +214,36 @@ sa1100_rx_chars(struct sa1100_port *spor
 		 * note that the error handling code is
 		 * out of the main execution path
 		 */
-		if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR))
-			goto handle_error;
+		if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) {
+			if (status & UTSR1_TO_SM(UTSR1_PRE))
+				sport->port.icount.parity++;
+			else if (status & UTSR1_TO_SM(UTSR1_FRE))
+				sport->port.icount.frame++;
+			if (status & UTSR1_TO_SM(UTSR1_ROR))
+				sport->port.icount.overrun++;
+
+			status &= sport->port.read_status_mask;
+
+			if (status & UTSR1_TO_SM(UTSR1_PRE))
+				flg = TTY_PARITY;
+			else if (status & UTSR1_TO_SM(UTSR1_FRE))
+				flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+			sport->port.sysrq = 0;
+#endif
+		}
 
 		if (uart_handle_sysrq_char(&sport->port, ch, regs))
 			goto ignore_char;
 
-	error_return:
-		tty_insert_flip_char(tty, ch, flg);
+		uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
+
 	ignore_char:
 		status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
 			 UTSR0_TO_SM(UART_GET_UTSR0(sport));
 	}
- out:
 	tty_flip_buffer_push(tty);
-	return;
-
- handle_error:
-	if (status & UTSR1_TO_SM(UTSR1_PRE))
-		sport->port.icount.parity++;
-	else if (status & UTSR1_TO_SM(UTSR1_FRE))
-		sport->port.icount.frame++;
-	if (status & UTSR1_TO_SM(UTSR1_ROR))
-		sport->port.icount.overrun++;
-
-	if (status & sport->port.ignore_status_mask) {
-		if (++ignored > 100)
-			goto out;
-		goto ignore_char;
-	}
-
-	status &= sport->port.read_status_mask;
-
-	if (status & UTSR1_TO_SM(UTSR1_PRE))
-		flg = TTY_PARITY;
-	else if (status & UTSR1_TO_SM(UTSR1_FRE))
-		flg = TTY_FRAME;
-
-	if (status & UTSR1_TO_SM(UTSR1_ROR)) {
-		/*
-		 * overrun does *not* affect the character
-		 * we read from the FIFO
-		 */
-		tty_insert_flip_char(tty, ch, flg);
-		ch = 0;
-		flg = TTY_OVERRUN;
-	}
-#ifdef SUPPORT_SYSRQ
-	sport->port.sysrq = 0;
-#endif
-	goto error_return;
 }
 
 static void sa1100_tx_chars(struct sa1100_port *sport)
@@ -687,21 +667,21 @@ void __init sa1100_register_uart(int idx
 
 	switch (port) {
 	case 1:
-		sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0;
+		sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
 		sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
 		sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
 		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
 		break;
 
 	case 2:
-		sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0;
+		sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
 		sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
 		sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
 		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
 		break;
 
 	case 3:
-		sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0;
+		sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
 		sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
 		sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
 		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
@@ -854,7 +834,7 @@ static struct uart_driver sa1100_reg = {
 	.cons			= SA1100_CONSOLE,
 };
 
-static int sa1100_serial_suspend(struct device *_dev, u32 state, u32 level)
+static int sa1100_serial_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
 	struct sa1100_port *sport = dev_get_drvdata(_dev);
 
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2233,7 +2233,7 @@ int uart_remove_one_port(struct uart_dri
 /*
  *	Are the two ports equivalent?
  */
-static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
 {
 	if (port1->iotype != port2->iotype)
 		return 0;
@@ -2249,6 +2249,7 @@ static int uart_match_port(struct uart_p
 	}
 	return 0;
 }
+EXPORT_SYMBOL(uart_match_port);
 
 /*
  *	Try to find an unused uart_state slot for a port.
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -107,6 +107,13 @@ struct serial_info {
 	int			line[4];
 };
 
+struct serial_cfg_mem {
+	tuple_t tuple;
+	cisparse_t parse;
+	u_char buf[256];
+};
+
+
 static void serial_config(dev_link_t * link);
 static int serial_event(event_t event, int priority,
 			event_callback_args_t * args);
@@ -289,7 +296,8 @@ static void serial_detach(dev_link_t * l
 
 /*====================================================================*/
 
-static int setup_serial(struct serial_info * info, kio_addr_t iobase, int irq)
+static int setup_serial(client_handle_t handle, struct serial_info * info,
+			kio_addr_t iobase, int irq)
 {
 	struct uart_port port;
 	int line;
@@ -299,6 +307,7 @@ static int setup_serial(struct serial_in
 	port.irq = irq;
 	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
 	port.uartclk = 1843200;
+	port.dev = &handle_to_dev(handle);
 	if (buggy_uart)
 		port.flags |= UPF_BUGGY_UART;
 	line = serial8250_register_port(&port);
@@ -355,14 +364,24 @@ static int simple_config(dev_link_t *lin
 	static int size_table[2] = { 8, 16 };
 	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
-	tuple_t tuple;
-	u_char buf[256];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	struct serial_cfg_mem *cfg_mem;
+	tuple_t *tuple;
+	u_char *buf;
+	cisparse_t *parse;
+	cistpl_cftable_entry_t *cf;
 	config_info_t config;
 	int i, j, try;
 	int s;
 
+	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
+	if (!cfg_mem)
+		return -1;
+
+	tuple = &cfg_mem->tuple;
+	parse = &cfg_mem->parse;
+	cf = &parse->cftable_entry;
+	buf = cfg_mem->buf;
+
 	/* If the card is already configured, look up the port and irq */
 	i = pcmcia_get_configuration_info(handle, &config);
 	if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
@@ -375,21 +394,23 @@ static int simple_config(dev_link_t *lin
 			port = config.BasePort1 + 0x28;
 			info->slave = 1;
 		}
-		if (info->slave)
-			return setup_serial(info, port, config.AssignedIRQ);
+		if (info->slave) {
+			kfree(cfg_mem);
+			return setup_serial(handle, info, port, config.AssignedIRQ);
+		}
 	}
 	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;
+	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 (s = 0; s < 2; s++) {
 		for (try = 0; try < 2; try++) {
-			i = first_tuple(handle, &tuple, &parse);
+			i = first_tuple(handle, tuple, parse);
 			while (i != CS_NO_MORE_ITEMS) {
 				if (i != CS_SUCCESS)
 					goto next_entry;
@@ -407,14 +428,14 @@ static int simple_config(dev_link_t *lin
 						goto found_port;
 				}
 next_entry:
-				i = next_tuple(handle, &tuple, &parse);
+				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);
+	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)) {
@@ -427,7 +448,7 @@ next_entry:
 					goto found_port;
 			}
 		}
-		i = next_tuple(handle, &tuple, &parse);
+		i = next_tuple(handle, tuple, parse);
 	}
 
       found_port:
@@ -435,6 +456,7 @@ next_entry:
 		printk(KERN_NOTICE
 		       "serial_cs: no usable port range found, giving up\n");
 		cs_error(link->handle, RequestIO, i);
+		kfree(cfg_mem);
 		return -1;
 	}
 
@@ -448,39 +470,50 @@ next_entry:
 	i = pcmcia_request_configuration(link->handle, &link->conf);
 	if (i != CS_SUCCESS) {
 		cs_error(link->handle, RequestConfiguration, i);
+		kfree(cfg_mem);
 		return -1;
 	}
-
-	return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	kfree(cfg_mem);
+	return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
 }
 
 static int multi_config(dev_link_t * link)
 {
 	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
-	tuple_t tuple;
-	u_char buf[256];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	struct serial_cfg_mem *cfg_mem;
+	tuple_t *tuple;
+	u_char *buf;
+	cisparse_t *parse;
+	cistpl_cftable_entry_t *cf;
 	config_info_t config;
-	int i, base2 = 0;
+	int i, rc, base2 = 0;
+
+	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
+	if (!cfg_mem)
+		return -1;
+	tuple = &cfg_mem->tuple;
+	parse = &cfg_mem->parse;
+	cf = &parse->cftable_entry;
+	buf = cfg_mem->buf;
 
 	i = pcmcia_get_configuration_info(handle, &config);
 	if (i != CS_SUCCESS) {
 		cs_error(handle, GetConfigurationInfo, i);
-		return -1;
+		rc = -1;
+		goto free_cfg_mem;
 	}
 	link->conf.Vcc = config.Vcc;
 
-	tuple.TupleData = (cisdata_t *) buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	tuple->TupleData = (cisdata_t *) buf;
+	tuple->TupleOffset = 0;
+	tuple->TupleDataMax = 255;
+	tuple->Attributes = 0;
+	tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
 
 	/* First, look for a generic full-sized window */
 	link->io.NumPorts1 = info->multi * 8;
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(handle, tuple, parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		/* The quad port cards have bad CIS's, so just look for a
 		   window larger than 8 ports and assume it will be right */
@@ -495,14 +528,14 @@ static int multi_config(dev_link_t * lin
 			if (i == CS_SUCCESS)
 				break;
 		}
-		i = next_tuple(handle, &tuple, &parse);
+		i = next_tuple(handle, tuple, parse);
 	}
 
 	/* If that didn't work, look for two windows */
 	if (i != CS_SUCCESS) {
 		link->io.NumPorts1 = link->io.NumPorts2 = 8;
 		info->multi = 2;
-		i = first_tuple(handle, &tuple, &parse);
+		i = first_tuple(handle, tuple, parse);
 		while (i != CS_NO_MORE_ITEMS) {
 			if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
 				link->conf.ConfigIndex = cf->index;
@@ -515,13 +548,14 @@ static int multi_config(dev_link_t * lin
 				if (i == CS_SUCCESS)
 					break;
 			}
-			i = next_tuple(handle, &tuple, &parse);
+			i = next_tuple(handle, tuple, parse);
 		}
 	}
 
 	if (i != CS_SUCCESS) {
 		cs_error(link->handle, RequestIO, i);
-		return -1;
+		rc = -1;
+		goto free_cfg_mem;
 	}
 
 	i = pcmcia_request_irq(link->handle, &link->irq);
@@ -539,30 +573,37 @@ static int multi_config(dev_link_t * lin
 	i = pcmcia_request_configuration(link->handle, &link->conf);
 	if (i != CS_SUCCESS) {
 		cs_error(link->handle, RequestConfiguration, i);
-		return -1;
+		rc = -1;
+		goto free_cfg_mem;
 	}
 
 	/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
 	   8 registers are for the UART, the others are extra registers */
 	if (info->manfid == MANFID_OXSEMI) {
 		if (cf->index == 1 || cf->index == 3) {
-			setup_serial(info, base2, link->irq.AssignedIRQ);
+			setup_serial(handle, info, base2, link->irq.AssignedIRQ);
 			outb(12, link->io.BasePort1 + 1);
 		} else {
-			setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+			setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
 			outb(12, base2 + 1);
 		}
-		return 0;
+		rc = 0;
+		goto free_cfg_mem;
 	}
 
-	setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
 	/* The Nokia cards are not really multiport cards */
-	if (info->manfid == MANFID_NOKIA)
-		return 0;
+	if (info->manfid == MANFID_NOKIA) {
+		rc = 0;
+		goto free_cfg_mem;
+	}
 	for (i = 0; i < info->multi - 1; i++)
-		setup_serial(info, base2 + (8 * i), link->irq.AssignedIRQ);
-
-	return 0;
+		setup_serial(handle, info, base2 + (8 * i),
+				link->irq.AssignedIRQ);
+	rc = 0;
+free_cfg_mem:
+	kfree(cfg_mem);
+	return rc;
 }
 
 /*======================================================================
@@ -577,43 +618,53 @@ void serial_config(dev_link_t * link)
 {
 	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
-	tuple_t tuple;
-	u_short buf[128];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	struct serial_cfg_mem *cfg_mem;
+	tuple_t *tuple;
+	u_char *buf;
+	cisparse_t *parse;
+	cistpl_cftable_entry_t *cf;
 	int i, last_ret, last_fn;
 
 	DEBUG(0, "serial_config(0x%p)\n", link);
 
-	tuple.TupleData = (cisdata_t *) buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
+	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
+	if (!cfg_mem)
+		goto failed;
+
+	tuple = &cfg_mem->tuple;
+	parse = &cfg_mem->parse;
+	cf = &parse->cftable_entry;
+	buf = cfg_mem->buf;
+
+	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);
+	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];
+	link->conf.ConfigBase = parse->config.base;
+	link->conf.Present = parse->config.rmask[0];
 
 	/* Configure card */
 	link->state |= DEV_CONFIG;
 
 	/* Is this a compliant multifunction card? */
-	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
-	tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
-	info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+	tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+	info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
 
 	/* Is this a multiport card? */
-	tuple.DesiredTuple = CISTPL_MANFID;
-	if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
-		info->manfid = le16_to_cpu(buf[0]);
+	tuple->DesiredTuple = CISTPL_MANFID;
+	if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+		info->manfid = parse->manfid.manf;
 		for (i = 0; i < MULTI_COUNT; i++)
 			if ((info->manfid == multi_id[i].manfid) &&
-			    (le16_to_cpu(buf[1]) == multi_id[i].prodid))
+			    (parse->manfid.card == multi_id[i].prodid))
 				break;
 		if (i < MULTI_COUNT)
 			info->multi = multi_id[i].multi;
@@ -621,13 +672,13 @@ void serial_config(dev_link_t * link)
 
 	/* Another check for dual-serial cards: look for either serial or
 	   multifunction cards that ask for appropriate IO port ranges */
-	tuple.DesiredTuple = CISTPL_FUNCID;
+	tuple->DesiredTuple = CISTPL_FUNCID;
 	if ((info->multi == 0) &&
-	    ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
-	     (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
-	     (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
-		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-		if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+	    ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
+	     (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
+	     (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
+		tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+		if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
 			if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
 				info->multi = cf->io.win[0].len >> 3;
 			if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
@@ -662,6 +713,7 @@ void serial_config(dev_link_t * link)
 
 	link->dev = &info->node[0];
 	link->state &= ~DEV_CONFIG_PENDING;
+	kfree(cfg_mem);
 	return;
 
  cs_failed:
@@ -669,6 +721,7 @@ void serial_config(dev_link_t * link)
  failed:
 	serial_remove(link);
 	link->state &= ~DEV_CONFIG_PENDING;
+	kfree(cfg_mem);
 }
 
 /*======================================================================
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -162,7 +162,7 @@ lh7a40xuart_rx_chars (struct uart_port* 
 		flag = TTY_NORMAL;
 		++port->icount.rx;
 
-		if (data & RxError) {	/* Quick check, short-circuit */
+		if (unlikely(data & RxError)) {	/* Quick check, short-circuit */
 			if (data & RxBreak) {
 				data &= ~(RxFramingError | RxParityError);
 				++port->icount.brk;
@@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* 
 		if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
 			continue;
 
-		if ((data & port->ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, data, flag);
-		}
-		if ((data & RxOverrunError)
-		    && tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+		uart_insert_char(port, data, RxOverrunError, data, flag);
 	}
 	tty_flip_buffer_push (tty);
 	return;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up,
 		}
 		if (uart_handle_sysrq_char(&up->port, ch, regs))
 			goto ignore_char;
-		if ((disr & up->port.ignore_status_mask) == 0) {
-			tty_insert_flip_char(tty, ch, flag);
-		}
-		if ((disr & TXX9_SIDISR_UOER) &&
-		    tty->flip.count < TTY_FLIPBUF_SIZE) {
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
+
+		uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
+
 	ignore_char:
 		disr = sio_in(up, TXX9_SIDISR);
 	} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
@@ -1095,7 +1086,7 @@ static void __devexit pciserial_txx9_rem
 	}
 }
 
-static int pciserial_txx9_suspend_one(struct pci_dev *dev, u32 state)
+static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
 {
 	int line = (int)(long)pci_get_drvdata(dev);
 
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -6,7 +6,7 @@
  * driver for that.
  *
  *
- * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -104,6 +104,7 @@ struct sn_cons_port {
 };
 
 static struct sn_cons_port sal_console_port;
+static int sn_process_input;
 
 /* Only used if USE_DYNAMIC_MINOR is set to 1 */
 static struct miscdevice misc;	/* used with misc_register for dynamic */
@@ -681,7 +682,8 @@ static void sn_sal_timer_poll(unsigned l
 
 	if (!port->sc_port.irq) {
 		spin_lock_irqsave(&port->sc_port.lock, flags);
-		sn_receive_chars(port, NULL, flags);
+		if (sn_process_input)
+			sn_receive_chars(port, NULL, flags);
 		sn_transmit_chars(port, TRANSMIT_RAW);
 		spin_unlock_irqrestore(&port->sc_port.lock, flags);
 		mod_timer(&port->sc_timer,
@@ -785,7 +787,7 @@ static void __init sn_sal_switch_to_inte
 
 static void sn_sal_console_write(struct console *, const char *, unsigned);
 static int __init sn_sal_console_setup(struct console *, char *);
-extern struct uart_driver sal_console_uart;
+static struct uart_driver sal_console_uart;
 extern struct tty_driver *uart_console_device(struct console *, int *);
 
 static struct console sal_console = {
@@ -878,6 +880,7 @@ static int __init sn_sal_module_init(voi
 	if (!IS_RUNNING_ON_SIMULATOR()) {
 		sn_sal_switch_to_interrupts(&sal_console_port);
 	}
+	sn_process_input = 1;
 	return 0;
 }
 
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -61,6 +61,16 @@ struct uart_sunsab_port {
 	unsigned char			pvr_dtr_bit;	/* Which PVR bit is DTR */
 	unsigned char			pvr_dsr_bit;	/* Which PVR bit is DSR */
 	int				type;		/* SAB82532 version	*/
+
+	/* Setting configuration bits while the transmitter is active
+	 * can cause garbage characters to get emitted by the chip.
+	 * Therefore, we cache such writes here and do the real register
+	 * write the next time the transmitter becomes idle.
+	 */
+	unsigned int			cached_ebrg;
+	unsigned char			cached_mode;
+	unsigned char			cached_pvr;
+	unsigned char			cached_dafo;
 };
 
 /*
@@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *u
 }
 
 static void sunsab_stop_tx(struct uart_port *, unsigned int);
+static void sunsab_tx_idle(struct uart_sunsab_port *);
 
 static void transmit_chars(struct uart_sunsab_port *up,
 			   union sab82532_irq_status *stat)
@@ -258,6 +269,7 @@ static void transmit_chars(struct uart_s
 		return;
 
 	set_bit(SAB82532_XPR, &up->irqflags);
+	sunsab_tx_idle(up);
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
 		up->interrupt_mask1 |= SAB82532_IMR1_XPR;
@@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart
 	struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 
 	if (mctrl & TIOCM_RTS) {
-		writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS,
-		       &up->regs->rw.mode);
-		writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS,
-		       &up->regs->rw.mode);
+		up->cached_mode &= ~SAB82532_MODE_FRTS;
+		up->cached_mode |= SAB82532_MODE_RTS;
 	} else {
-		writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS,
-		       &up->regs->rw.mode);
-		writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS,
-		       &up->regs->rw.mode);
+		up->cached_mode |= (SAB82532_MODE_FRTS |
+				    SAB82532_MODE_RTS);
 	}
 	if (mctrl & TIOCM_DTR) {
-		writeb(readb(&up->regs->rw.pvr) & ~(up->pvr_dtr_bit), &up->regs->rw.pvr);
+		up->cached_pvr &= ~(up->pvr_dtr_bit);
 	} else {
-		writeb(readb(&up->regs->rw.pvr) | up->pvr_dtr_bit, &up->regs->rw.pvr);
+		up->cached_pvr |= up->pvr_dtr_bit;
 	}
+
+	set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+	if (test_bit(SAB82532_XPR, &up->irqflags))
+		sunsab_tx_idle(up);
 }
 
 /* port->lock is not held.  */
@@ -450,6 +462,25 @@ static void sunsab_stop_tx(struct uart_p
 }
 
 /* port->lock held by caller.  */
+static void sunsab_tx_idle(struct uart_sunsab_port *up)
+{
+	if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
+		u8 tmp;
+
+		clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
+		writeb(up->cached_mode, &up->regs->rw.mode);
+		writeb(up->cached_pvr, &up->regs->rw.pvr);
+		writeb(up->cached_dafo, &up->regs->w.dafo);
+
+		writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
+		tmp = readb(&up->regs->rw.ccr2);
+		tmp &= ~0xc0;
+		tmp |= (up->cached_ebrg >> 2) & 0xc0;
+		writeb(tmp, &up->regs->rw.ccr2);
+	}
+}
+
+/* port->lock held by caller.  */
 static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start)
 {
 	struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
@@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
-	val = readb(&up->regs->rw.dafo);
+	val = up->cached_dafo;
 	if (break_state)
 		val |= SAB82532_DAFO_XBRK;
 	else
 		val &= ~SAB82532_DAFO_XBRK;
-	writeb(val, &up->regs->rw.dafo);
+	up->cached_dafo = val;
+
+	set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+	if (test_bit(SAB82532_XPR, &up->irqflags))
+		sunsab_tx_idle(up);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
@@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_po
 	       SAB82532_CCR2_TOE, &up->regs->w.ccr2);
 	writeb(0, &up->regs->w.ccr3);
 	writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
-	writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
-	       SAB82532_MODE_RAC, &up->regs->w.mode);
+	up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
+			   SAB82532_MODE_RAC);
+	writeb(up->cached_mode, &up->regs->w.mode);
 	writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
 	
 	tmp = readb(&up->regs->rw.ccr0);
@@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_
 {
 	struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 	unsigned long flags;
-	unsigned char tmp;
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
@@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_
 	writeb(up->interrupt_mask1, &up->regs->w.imr1);
 
 	/* Disable break condition */
-	tmp = readb(&up->regs->rw.dafo);
-	tmp &= ~SAB82532_DAFO_XBRK;
-	writeb(tmp, &up->regs->rw.dafo);
+	up->cached_dafo = readb(&up->regs->rw.dafo);
+	up->cached_dafo &= ~SAB82532_DAFO_XBRK;
+	writeb(up->cached_dafo, &up->regs->rw.dafo);
 
 	/* Disable Receiver */	
-	tmp = readb(&up->regs->rw.mode);
-	tmp &= ~SAB82532_MODE_RAC;
-	writeb(tmp, &up->regs->rw.mode);
+	up->cached_mode &= ~SAB82532_MODE_RAC;
+	writeb(up->cached_mode, &up->regs->rw.mode);
 
 	/*
 	 * XXX FIXME
@@ -682,9 +716,9 @@ static void calc_ebrg(int baud, int *n_r
 
 /* Internal routine, port->lock is held and local interrupts are disabled.  */
 static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag,
-				  unsigned int iflag, int baud)
+				  unsigned int iflag, unsigned int baud,
+				  unsigned int quot)
 {
-	unsigned int ebrg;
 	unsigned char dafo;
 	int bits, n, m;
 
@@ -713,10 +747,11 @@ static void sunsab_convert_to_sab(struct
 	} else {
 		dafo |= SAB82532_DAFO_PAR_EVEN;
 	}
+	up->cached_dafo = dafo;
 
 	calc_ebrg(baud, &n, &m);
 
-	ebrg = n | (m << 6);
+	up->cached_ebrg = n | (m << 6);
 
 	up->tec_timeout = (10 * 1000000) / baud;
 	up->cec_timeout = up->tec_timeout >> 2;
@@ -766,16 +801,16 @@ static void sunsab_convert_to_sab(struct
 		up->port.ignore_status_mask |= (SAB82532_ISR0_RPF |
 						SAB82532_ISR0_TCD);
 
-	/* Now bang the new settings into the chip.  */
-	sunsab_cec_wait(up);
-	sunsab_tec_wait(up);
-	writeb(dafo, &up->regs->w.dafo);
-	writeb(ebrg & 0xff, &up->regs->w.bgr);
-	writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0),
-	       &up->regs->rw.ccr2);
-
-	writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode);
+	uart_update_timeout(&up->port, cflag,
+			    (up->port.uartclk / (16 * quot)));
 
+	/* Now schedule a register update when the chip's
+	 * transmitter is idle.
+	 */
+	up->cached_mode |= SAB82532_MODE_RAC;
+	set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+	if (test_bit(SAB82532_XPR, &up->irqflags))
+		sunsab_tx_idle(up);
 }
 
 /* port->lock is not held.  */
@@ -784,10 +819,11 @@ static void sunsab_set_termios(struct ua
 {
 	struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 	unsigned long flags;
-	int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+	unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+	unsigned int quot = uart_get_divisor(port, baud);
 
 	spin_lock_irqsave(&up->port.lock, flags);
-	sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud);
+	sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
@@ -880,7 +916,7 @@ static int sunsab_console_setup(struct c
 {
 	struct uart_sunsab_port *up = &sunsab_ports[con->index];
 	unsigned long flags;
-	int baud;
+	unsigned int baud, quot;
 
 	printk("Console: ttyS%d (SAB82532)\n",
 	       (sunsab_reg.minor - 64) + con->index);
@@ -926,7 +962,8 @@ static int sunsab_console_setup(struct c
 				SAB82532_IMR1_XPR;
 	writeb(up->interrupt_mask1, &up->regs->w.imr1);
 
-	sunsab_convert_to_sab(up, con->cflag, 0, baud);
+	quot = uart_get_divisor(&up->port, baud);
+	sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
 	sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
@@ -1078,11 +1115,13 @@ static void __init sunsab_init_hw(void)
 			up->pvr_dsr_bit = (1 << 3);
 			up->pvr_dtr_bit = (1 << 2);
 		}
-		writeb((1 << 1) | (1 << 2) | (1 << 4), &up->regs->w.pvr);
-		writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS,
-		       &up->regs->rw.mode);
-		writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS,
-		       &up->regs->rw.mode);
+		up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
+		writeb(up->cached_pvr, &up->regs->w.pvr);
+		up->cached_mode = readb(&up->regs->rw.mode);
+		up->cached_mode |= SAB82532_MODE_FRTS;
+		writeb(up->cached_mode, &up->regs->rw.mode);
+		up->cached_mode |= SAB82532_MODE_RTS;
+		writeb(up->cached_mode, &up->regs->rw.mode);
 
 		up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
 		up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h
--- a/drivers/serial/sunsab.h
+++ b/drivers/serial/sunsab.h
@@ -126,6 +126,7 @@ union sab82532_irq_status {
 /* irqflags bits */
 #define SAB82532_ALLS			0x00000001
 #define SAB82532_XPR			0x00000002
+#define SAB82532_REGS_PENDING		0x00000004
 
 /* RFIFO Status Byte */
 #define SAB82532_RSTAT_PE		0x80
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1285,6 +1285,7 @@ static struct uart_driver sunsu_reg = {
 
 static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
 {
+	int quot, baud;
 #ifdef CONFIG_SERIO
 	struct serio *serio;
 #endif
@@ -1293,10 +1294,14 @@ static int __init sunsu_kbd_ms_init(stru
 	up->port.type = PORT_UNKNOWN;
 	up->port.uartclk = (SU_BASE_BAUD * 16);
 
-	if (up->su_type == SU_PORT_KBD)
+	if (up->su_type == SU_PORT_KBD) {
 		up->cflag = B1200 | CS8 | CLOCAL | CREAD;
-	else
+		baud = 1200;
+	} else {
 		up->cflag = B4800 | CS8 | CLOCAL | CREAD;
+		baud = 4800;
+	}
+	quot = up->port.uartclk / (16 * baud);
 
 	sunsu_autoconfig(up);
 	if (up->port.type == PORT_UNKNOWN)
@@ -1314,12 +1319,13 @@ static int __init sunsu_kbd_ms_init(stru
 
 		serio->port_data = up;
 
-		serio->type = SERIO_RS232;
+		serio->id.type = SERIO_RS232;
 		if (up->su_type == SU_PORT_KBD) {
-			serio->type |= SERIO_SUNKBD;
+			serio->id.proto = SERIO_SUNKBD;
 			strlcpy(serio->name, "sukbd", sizeof(serio->name));
 		} else {
-			serio->type |= (SERIO_SUN | (1 << 16));
+			serio->id.proto = SERIO_SUN;
+			serio->id.extra = 1;
 			strlcpy(serio->name, "sums", sizeof(serio->name));
 		}
 		strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"),
@@ -1336,6 +1342,8 @@ static int __init sunsu_kbd_ms_init(stru
 	}
 #endif
 
+	sunsu_change_speed(&up->port, up->cflag, 0, quot);
+
 	sunsu_startup(&up->port);
 	return 0;
 }
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1562,12 +1562,13 @@ static void __init sunzilog_register_ser
 
 		serio->port_data = up;
 
-		serio->type = SERIO_RS232;
+		serio->id.type = SERIO_RS232;
 		if (channel == KEYBOARD_LINE) {
-			serio->type |= SERIO_SUNKBD;
+			serio->id.proto = SERIO_SUNKBD;
 			strlcpy(serio->name, "zskbd", sizeof(serio->name));
 		} else {
-			serio->type |= (SERIO_SUN | (1 << 16));
+			serio->id.proto = SERIO_SUN;
+			serio->id.extra = 1;
 			strlcpy(serio->name, "zsms", sizeof(serio->name));
 		}
 		strlcpy(serio->phys,
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
new file mode 100644
--- /dev/null
+++ b/drivers/serial/vr41xx_siu.c
@@ -0,0 +1,1050 @@
+/*
+ *  Driver for NEC VR4100 series Serial Interface Unit.
+ *
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ *  Based on drivers/serial/8250.c, by Russell King.
+ *
+ *  This program is free software; you can redistribute it 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>
+
+#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <asm/io.h>
+#include <asm/vr41xx/siu.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define SIU_PORTS_MAX	2
+#define SIU_BAUD_BASE	1152000
+#define SIU_MAJOR	204
+#define SIU_MINOR_BASE	82
+
+#define RX_MAX_COUNT	256
+#define TX_MAX_COUNT	15
+
+#define SIUIRSEL	0x08
+ #define TMICMODE	0x20
+ #define TMICTX		0x10
+ #define IRMSEL		0x0c
+ #define IRMSEL_HP	0x08
+ #define IRMSEL_TEMIC	0x04
+ #define IRMSEL_SHARP	0x00
+ #define IRUSESEL	0x02
+ #define SIRSEL		0x01
+
+struct siu_port {
+	unsigned int type;
+	unsigned int irq;
+	unsigned long start;
+};
+
+static const struct siu_port siu_type1_ports[] = {
+	{	.type		= PORT_VR41XX_SIU,
+		.irq		= SIU_IRQ,
+		.start		= 0x0c000000UL,		},
+};
+
+#define SIU_TYPE1_NR_PORTS	(sizeof(siu_type1_ports) / sizeof(struct siu_port))
+
+static const struct siu_port siu_type2_ports[] = {
+	{	.type		= PORT_VR41XX_SIU,
+		.irq		= SIU_IRQ,
+		.start		= 0x0f000800UL,		},
+	{	.type		= PORT_VR41XX_DSIU,
+		.irq		= DSIU_IRQ,
+		.start		= 0x0f000820UL,		},
+};
+
+#define SIU_TYPE2_NR_PORTS	(sizeof(siu_type2_ports) / sizeof(struct siu_port))
+
+static struct uart_port siu_uart_ports[SIU_PORTS_MAX];
+static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+
+#define siu_read(port, offset)		readb((port)->membase + (offset))
+#define siu_write(port, offset, value)	writeb((value), (port)->membase + (offset))
+
+void vr41xx_select_siu_interface(siu_interface_t interface)
+{
+	struct uart_port *port;
+	unsigned long flags;
+	uint8_t irsel;
+
+	port = &siu_uart_ports[0];
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	irsel = siu_read(port, SIUIRSEL);
+	if (interface == SIU_INTERFACE_IRDA)
+		irsel |= SIRSEL;
+	else
+		irsel &= ~SIRSEL;
+	siu_write(port, SIUIRSEL, irsel);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
+
+void vr41xx_use_irda(irda_use_t use)
+{
+	struct uart_port *port;
+	unsigned long flags;
+	uint8_t irsel;
+
+	port = &siu_uart_ports[0];
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	irsel = siu_read(port, SIUIRSEL);
+	if (use == FIR_USE_IRDA)
+		irsel |= IRUSESEL;
+	else
+		irsel &= ~IRUSESEL;
+	siu_write(port, SIUIRSEL, irsel);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_use_irda);
+
+void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
+{
+	struct uart_port *port;
+	unsigned long flags;
+	uint8_t irsel;
+
+	port = &siu_uart_ports[0];
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	irsel = siu_read(port, SIUIRSEL);
+	irsel &= ~(IRMSEL | TMICTX | TMICMODE);
+	switch (module) {
+	case SHARP_IRDA:
+		irsel |= IRMSEL_SHARP;
+		break;
+	case TEMIC_IRDA:
+		irsel |= IRMSEL_TEMIC | TMICMODE;
+		if (speed == IRDA_TX_4MBPS)
+			irsel |= TMICTX;
+		break;
+	case HP_IRDA:
+		irsel |= IRMSEL_HP;
+		break;
+	default:
+		break;
+	}
+	siu_write(port, SIUIRSEL, irsel);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
+
+static inline void siu_clear_fifo(struct uart_port *port)
+{
+	siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+	siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+	                          UART_FCR_CLEAR_XMIT);
+	siu_write(port, UART_FCR, 0);
+}
+
+static inline int siu_probe_ports(void)
+{
+	switch (current_cpu_data.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		return SIU_TYPE1_NR_PORTS;
+	case CPU_VR4122:
+	case CPU_VR4131:
+	case CPU_VR4133:
+		return SIU_TYPE2_NR_PORTS;
+	}
+
+	return 0;
+}
+
+static inline unsigned long siu_port_size(struct uart_port *port)
+{
+	switch (port->type) {
+	case PORT_VR41XX_SIU:
+		return 11UL;
+	case PORT_VR41XX_DSIU:
+		return 8UL;
+	}
+
+	return 0;
+}
+
+static inline unsigned int siu_check_type(struct uart_port *port)
+{
+	switch (current_cpu_data.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		if (port->line == 0)
+			return PORT_VR41XX_SIU;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+	case CPU_VR4133:
+		if (port->line == 0)
+			return PORT_VR41XX_SIU;
+		else if (port->line == 1)
+			return PORT_VR41XX_DSIU;
+		break;
+	}
+
+	return PORT_UNKNOWN;
+}
+
+static inline const char *siu_type_name(struct uart_port *port)
+{
+	switch (port->type) {
+	case PORT_VR41XX_SIU:
+		return "SIU";
+	case PORT_VR41XX_DSIU:
+		return "DSIU";
+	}
+
+	return NULL;
+}
+
+static unsigned int siu_tx_empty(struct uart_port *port)
+{
+	uint8_t lsr;
+
+	lsr = siu_read(port, UART_LSR);
+	if (lsr & UART_LSR_TEMT)
+		return TIOCSER_TEMT;
+
+	return 0;
+}
+
+static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	uint8_t mcr = 0;
+
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	siu_write(port, UART_MCR, mcr);
+}
+
+static unsigned int siu_get_mctrl(struct uart_port *port)
+{
+	uint8_t msr;
+	unsigned int mctrl = 0;
+
+	msr = siu_read(port, UART_MSR);
+	if (msr & UART_MSR_DCD)
+		mctrl |= TIOCM_CAR;
+	if (msr & UART_MSR_RI)
+		mctrl |= TIOCM_RNG;
+	if (msr & UART_MSR_DSR)
+		mctrl |= TIOCM_DSR;
+	if (msr & UART_MSR_CTS)
+		mctrl |= TIOCM_CTS;
+
+	return mctrl;
+}
+
+static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned long flags;
+	uint8_t ier;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ier = siu_read(port, UART_IER);
+	ier &= ~UART_IER_THRI;
+	siu_write(port, UART_IER, ier);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned long flags;
+	uint8_t ier;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ier = siu_read(port, UART_IER);
+	ier |= UART_IER_THRI;
+	siu_write(port, UART_IER, ier);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_stop_rx(struct uart_port *port)
+{
+	unsigned long flags;
+	uint8_t ier;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ier = siu_read(port, UART_IER);
+	ier &= ~UART_IER_RLSI;
+	siu_write(port, UART_IER, ier);
+
+	port->read_status_mask &= ~UART_LSR_DR;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_enable_ms(struct uart_port *port)
+{
+	unsigned long flags;
+	uint8_t ier;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ier = siu_read(port, UART_IER);
+	ier |= UART_IER_MSI;
+	siu_write(port, UART_IER, ier);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_break_ctl(struct uart_port *port, int ctl)
+{
+	unsigned long flags;
+	uint8_t lcr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	lcr = siu_read(port, UART_LCR);
+	if (ctl == -1)
+		lcr |= UART_LCR_SBC;
+	else
+		lcr &= ~UART_LCR_SBC;
+	siu_write(port, UART_LCR, lcr);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static inline void receive_chars(struct uart_port *port, uint8_t *status,
+                                 struct pt_regs *regs)
+{
+	struct tty_struct *tty;
+	uint8_t lsr, ch;
+	char flag;
+	int max_count = RX_MAX_COUNT;
+
+	tty = port->info->tty;
+	lsr = *status;
+
+	do {
+		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+			if (tty->low_latency)
+				tty_flip_buffer_push(tty);
+		}
+
+		ch = siu_read(port, UART_RX);
+		port->icount.rx++;
+		flag = TTY_NORMAL;
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+		lsr |= lsr_break_flag[port->line];
+		lsr_break_flag[port->line] = 0;
+#endif
+		if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
+		                    UART_LSR_PE | UART_LSR_OE))) {
+			if (lsr & UART_LSR_BI) {
+				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+				port->icount.brk++;
+
+				if (uart_handle_break(port))
+					goto ignore_char;
+			}
+
+			if (lsr & UART_LSR_FE)
+				port->icount.frame++;
+			if (lsr & UART_LSR_PE)
+				port->icount.parity++;
+			if (lsr & UART_LSR_OE)
+				port->icount.overrun++;
+
+			lsr &= port->read_status_mask;
+			if (lsr & UART_LSR_BI)
+				flag = TTY_BREAK;
+			if (lsr & UART_LSR_FE)
+				flag = TTY_FRAME;
+			if (lsr & UART_LSR_PE)
+				flag = TTY_PARITY;
+		}
+
+		if (uart_handle_sysrq_char(port, ch, regs))
+			goto ignore_char;
+
+		uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+
+	ignore_char:
+		lsr = siu_read(port, UART_LSR);
+	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+
+	tty_flip_buffer_push(tty);
+
+	*status = lsr;
+}
+
+static inline void check_modem_status(struct uart_port *port)
+{
+	uint8_t msr;
+
+	msr = siu_read(port, UART_MSR);
+	if ((msr & UART_MSR_ANY_DELTA) == 0)
+		return;
+	if (msr & UART_MSR_DDCD)
+		uart_handle_dcd_change(port, msr & UART_MSR_DCD);
+	if (msr & UART_MSR_TERI)
+		port->icount.rng++;
+	if (msr & UART_MSR_DDSR)
+		port->icount.dsr++;
+	if (msr & UART_MSR_DCTS)
+		uart_handle_cts_change(port, msr & UART_MSR_CTS);
+
+	wake_up_interruptible(&port->info->delta_msr_wait);
+}
+
+static inline void transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit;
+	int max_count = TX_MAX_COUNT;
+
+	xmit = &port->info->xmit;
+
+	if (port->x_char) {
+		siu_write(port, UART_TX, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		siu_stop_tx(port, 0);
+		return;
+	}
+
+	do {
+		siu_write(port, UART_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (max_count-- > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		siu_stop_tx(port, 0);
+}
+
+static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port;
+	uint8_t iir, lsr;
+
+	port = (struct uart_port *)dev_id;
+
+	iir = siu_read(port, UART_IIR);
+	if (iir & UART_IIR_NO_INT)
+		return IRQ_NONE;
+
+	lsr = siu_read(port, UART_LSR);
+	if (lsr & UART_LSR_DR)
+		receive_chars(port, &lsr, regs);
+
+	check_modem_status(port);
+
+	if (lsr & UART_LSR_THRE)
+		transmit_chars(port);
+
+	return IRQ_HANDLED;
+}
+
+static int siu_startup(struct uart_port *port)
+{
+	int retval;
+
+	if (port->membase == NULL)
+		return -ENODEV;
+
+	siu_clear_fifo(port);
+
+	(void)siu_read(port, UART_LSR);
+	(void)siu_read(port, UART_RX);
+	(void)siu_read(port, UART_IIR);
+	(void)siu_read(port, UART_MSR);
+
+	if (siu_read(port, UART_LSR) == 0xff)
+		return -ENODEV;
+
+	retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
+	if (retval)
+		return retval;
+
+	if (port->type == PORT_VR41XX_DSIU)
+		vr41xx_enable_dsiuint(DSIUINT_ALL);
+
+	siu_write(port, UART_LCR, UART_LCR_WLEN8);
+
+	spin_lock_irq(&port->lock);
+	siu_set_mctrl(port, port->mctrl);
+	spin_unlock_irq(&port->lock);
+
+	siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
+
+	(void)siu_read(port, UART_LSR);
+	(void)siu_read(port, UART_RX);
+	(void)siu_read(port, UART_IIR);
+	(void)siu_read(port, UART_MSR);
+
+	return 0;
+}
+
+static void siu_shutdown(struct uart_port *port)
+{
+	unsigned long flags;
+	uint8_t lcr;
+
+	siu_write(port, UART_IER, 0);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->mctrl &= ~TIOCM_OUT2;
+	siu_set_mctrl(port, port->mctrl);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	lcr = siu_read(port, UART_LCR);
+	lcr &= ~UART_LCR_SBC;
+	siu_write(port, UART_LCR, lcr);
+
+	siu_clear_fifo(port);
+
+	(void)siu_read(port, UART_RX);
+
+	if (port->type == PORT_VR41XX_DSIU)
+		vr41xx_disable_dsiuint(DSIUINT_ALL);
+
+	free_irq(port->irq, port);
+}
+
+static void siu_set_termios(struct uart_port *port, struct termios *new,
+                            struct termios *old)
+{
+	tcflag_t c_cflag, c_iflag;
+	uint8_t lcr, fcr, ier;
+	unsigned int baud, quot;
+	unsigned long flags;
+
+	c_cflag = new->c_cflag;
+	switch (c_cflag & CSIZE) {
+	case CS5:
+		lcr = UART_LCR_WLEN5;
+		break;
+	case CS6:
+		lcr = UART_LCR_WLEN6;
+		break;
+	case CS7:
+		lcr = UART_LCR_WLEN7;
+		break;
+	default:
+		lcr = UART_LCR_WLEN8;
+		break;
+	}
+
+	if (c_cflag & CSTOPB)
+		lcr |= UART_LCR_STOP;
+	if (c_cflag & PARENB)
+		lcr |= UART_LCR_PARITY;
+	if ((c_cflag & PARODD) != PARODD)
+		lcr |= UART_LCR_EPAR;
+	if (c_cflag & CMSPAR)
+		lcr |= UART_LCR_SPAR;
+
+	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+	quot = uart_get_divisor(port, baud);
+
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	uart_update_timeout(port, c_cflag, baud);
+
+	c_iflag = new->c_iflag;
+
+	port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
+	if (c_iflag & INPCK)
+		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= UART_LSR_BI;
+
+	port->ignore_status_mask = 0;
+	if (c_iflag & IGNPAR)
+		port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (c_iflag & IGNBRK) {
+		port->ignore_status_mask |= UART_LSR_BI;
+		if (c_iflag & IGNPAR)
+			port->ignore_status_mask |= UART_LSR_OE;
+	}
+
+	if ((c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= UART_LSR_DR;
+
+	ier = siu_read(port, UART_IER);
+	ier &= ~UART_IER_MSI;
+	if (UART_ENABLE_MS(port, c_cflag))
+		ier |= UART_IER_MSI;
+	siu_write(port, UART_IER, ier);
+
+	siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
+
+	siu_write(port, UART_DLL, (uint8_t)quot);
+	siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
+
+	siu_write(port, UART_LCR, lcr);
+
+	siu_write(port, UART_FCR, fcr);
+
+	siu_set_mctrl(port, port->mctrl);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+	switch (state) {
+	case 0:
+		switch (port->type) {
+		case PORT_VR41XX_SIU:
+			vr41xx_supply_clock(SIU_CLOCK);
+			break;
+		case PORT_VR41XX_DSIU:
+			vr41xx_supply_clock(DSIU_CLOCK);
+			break;
+		}
+		break;
+	case 3:
+		switch (port->type) {
+		case PORT_VR41XX_SIU:
+			vr41xx_mask_clock(SIU_CLOCK);
+			break;
+		case PORT_VR41XX_DSIU:
+			vr41xx_mask_clock(DSIU_CLOCK);
+			break;
+		}
+		break;
+	}
+}
+
+static const char *siu_type(struct uart_port *port)
+{
+	return siu_type_name(port);
+}
+
+static void siu_release_port(struct uart_port *port)
+{
+	unsigned long size;
+
+	if (port->flags	& UPF_IOREMAP) {
+		iounmap(port->membase);
+		port->membase = NULL;
+	}
+
+	size = siu_port_size(port);
+	release_mem_region(port->mapbase, size);
+}
+
+static int siu_request_port(struct uart_port *port)
+{
+	unsigned long size;
+	struct resource *res;
+
+	size = siu_port_size(port);
+	res = request_mem_region(port->mapbase, size, siu_type_name(port));
+	if (res == NULL)
+		return -EBUSY;
+
+	if (port->flags & UPF_IOREMAP) {
+		port->membase = ioremap(port->mapbase, size);
+		if (port->membase == NULL) {
+			release_resource(res);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static void siu_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = siu_check_type(port);
+		(void)siu_request_port(port);
+	}
+}
+
+static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
+{
+	if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
+		return -EINVAL;
+	if (port->irq != serial->irq)
+		return -EINVAL;
+	if (port->iotype != serial->io_type)
+		return -EINVAL;
+	if (port->mapbase != (unsigned long)serial->iomem_base)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct uart_ops siu_uart_ops = {
+	.tx_empty	= siu_tx_empty,
+	.set_mctrl	= siu_set_mctrl,
+	.get_mctrl	= siu_get_mctrl,
+	.stop_tx	= siu_stop_tx,
+	.start_tx	= siu_start_tx,
+	.stop_rx	= siu_stop_rx,
+	.enable_ms	= siu_enable_ms,
+	.break_ctl	= siu_break_ctl,
+	.startup	= siu_startup,
+	.shutdown	= siu_shutdown,
+	.set_termios	= siu_set_termios,
+	.pm		= siu_pm,
+	.type		= siu_type,
+	.release_port	= siu_release_port,
+	.request_port	= siu_request_port,
+	.config_port	= siu_config_port,
+	.verify_port	= siu_verify_port,
+};
+
+static int siu_init_ports(void)
+{
+	const struct siu_port *siu;
+	struct uart_port *port;
+	int i, num;
+
+	switch (current_cpu_data.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		siu = siu_type1_ports;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+	case CPU_VR4133:
+		siu = siu_type2_ports;
+		break;
+	default:
+		return 0;
+	}
+
+	port = siu_uart_ports;
+	num = siu_probe_ports();
+	for (i = 0; i < num; i++) {
+		spin_lock_init(&port->lock);
+		port->irq = siu->irq;
+		port->uartclk = SIU_BAUD_BASE * 16;
+		port->fifosize = 16;
+		port->regshift = 0;
+		port->iotype = UPIO_MEM;
+		port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+		port->type = siu->type;
+		port->line = i;
+		port->mapbase = siu->start;
+		siu++;
+		port++;
+	}
+
+	return num;
+}
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+
+#define BOTH_EMPTY	(UART_LSR_TEMT | UART_LSR_THRE)
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+	int timeout = 10000;
+	uint8_t lsr, msr;
+
+	do {
+		lsr = siu_read(port, UART_LSR);
+		if (lsr & UART_LSR_BI)
+			lsr_break_flag[port->line] = UART_LSR_BI;
+
+		if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
+			break;
+	} while (timeout-- > 0);
+
+	if (port->flags & UPF_CONS_FLOW) {
+		timeout = 1000000;
+
+		do {
+			msr = siu_read(port, UART_MSR);
+			if ((msr & UART_MSR_CTS) != 0)
+				break;
+		} while (timeout-- > 0);
+	}
+}
+
+static void siu_console_write(struct console *con, const char *s, unsigned count)
+{
+	struct uart_port *port;
+	uint8_t ier;
+	unsigned i;
+
+	port = &siu_uart_ports[con->index];
+
+	ier = siu_read(port, UART_IER);
+	siu_write(port, UART_IER, 0);
+
+	for (i = 0; i < count && *s != '\0'; i++, s++) {
+		wait_for_xmitr(port);
+		siu_write(port, UART_TX, *s);
+		if (*s == '\n') {
+			wait_for_xmitr(port);
+			siu_write(port, UART_TX, '\r');
+		}
+	}
+
+	wait_for_xmitr(port);
+	siu_write(port, UART_IER, ier);
+}
+
+static int siu_console_setup(struct console *con, char *options)
+{
+	struct uart_port *port;
+	int baud = 9600;
+	int parity = 'n';
+	int bits = 8;
+	int flow = 'n';
+
+	if (con->index >= SIU_PORTS_MAX)
+		con->index = 0;
+
+	port = &siu_uart_ports[con->index];
+	if (port->membase == NULL) {
+		if (port->mapbase == 0)
+			return -ENODEV;
+		port->membase = ioremap(port->mapbase, siu_port_size(port));
+	}
+
+	vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+
+	if (options != NULL)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver siu_uart_driver;
+
+static struct console siu_console = {
+	.name	= "ttyVR",
+	.write	= siu_console_write,
+	.device	= uart_console_device,
+	.setup	= siu_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+	.data	= &siu_uart_driver,
+};
+
+static int __devinit siu_console_init(void)
+{
+	struct uart_port *port;
+	int num, i;
+
+	num = siu_init_ports();
+	if (num <= 0)
+		return -ENODEV;
+
+	for (i = 0; i < num; i++) {
+		port = &siu_uart_ports[i];
+		port->ops = &siu_uart_ops;
+	}
+
+	register_console(&siu_console);
+
+	return 0;
+}
+
+console_initcall(siu_console_init);
+
+#define SERIAL_VR41XX_CONSOLE	&siu_console
+#else
+#define SERIAL_VR41XX_CONSOLE	NULL
+#endif
+
+static struct uart_driver siu_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "SIU",
+	.dev_name	= "ttyVR",
+	.devfs_name	= "ttvr/",
+	.major		= SIU_MAJOR,
+	.minor		= SIU_MINOR_BASE,
+	.cons		= SERIAL_VR41XX_CONSOLE,
+};
+
+static int siu_probe(struct device *dev)
+{
+	struct uart_port *port;
+	int num, i, retval;
+
+	num = siu_init_ports();
+	if (num <= 0)
+		return -ENODEV;
+
+	siu_uart_driver.nr = num;
+	retval = uart_register_driver(&siu_uart_driver);
+	if (retval)
+		return retval;
+
+	for (i = 0; i < num; i++) {
+		port = &siu_uart_ports[i];
+		port->ops = &siu_uart_ops;
+		port->dev = dev;
+
+		retval = uart_add_one_port(&siu_uart_driver, port);
+		if (retval < 0) {
+			port->dev = NULL;
+			break;
+		}
+	}
+
+	if (i == 0 && retval < 0) {
+		uart_unregister_driver(&siu_uart_driver);
+		return retval;
+	}
+
+	return 0;
+}
+
+static int siu_remove(struct device *dev)
+{
+	struct uart_port *port;
+	int i;
+
+	for (i = 0; i < siu_uart_driver.nr; i++) {
+		port = &siu_uart_ports[i];
+		if (port->dev == dev) {
+			uart_remove_one_port(&siu_uart_driver, port);
+			port->dev = NULL;
+		}
+	}
+
+	uart_unregister_driver(&siu_uart_driver);
+
+	return 0;
+}
+
+static int siu_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+	struct uart_port *port;
+	int i;
+
+	if (level != SUSPEND_DISABLE)
+		return 0;
+
+	for (i = 0; i < siu_uart_driver.nr; i++) {
+		port = &siu_uart_ports[i];
+		if ((port->type == PORT_VR41XX_SIU ||
+		     port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+			uart_suspend_port(&siu_uart_driver, port);
+
+	}
+
+	return 0;
+}
+
+static int siu_resume(struct device *dev, u32 level)
+{
+	struct uart_port *port;
+	int i;
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	for (i = 0; i < siu_uart_driver.nr; i++) {
+		port = &siu_uart_ports[i];
+		if ((port->type == PORT_VR41XX_SIU ||
+		     port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+			uart_resume_port(&siu_uart_driver, port);
+	}
+
+	return 0;
+}
+
+static struct platform_device *siu_platform_device;
+
+static struct device_driver siu_device_driver = {
+	.name		= "SIU",
+	.bus		= &platform_bus_type,
+	.probe		= siu_probe,
+	.remove		= siu_remove,
+	.suspend	= siu_suspend,
+	.resume		= siu_resume,
+};
+
+static int __devinit vr41xx_siu_init(void)
+{
+	int retval;
+
+	siu_platform_device = platform_device_register_simple("SIU", -1, NULL, 0);
+	if (IS_ERR(siu_platform_device))
+		return PTR_ERR(siu_platform_device);
+
+	retval = driver_register(&siu_device_driver);
+	if (retval < 0)
+		platform_device_unregister(siu_platform_device);
+
+	return retval;
+}
+
+static void __devexit vr41xx_siu_exit(void)
+{
+	driver_unregister(&siu_device_driver);
+
+	platform_device_unregister(siu_platform_device);
+}
+
+module_init(vr41xx_siu_init);
+module_exit(vr41xx_siu_exit);
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/sh/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SuperH specific drivers.
+#
+
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
+
diff --git a/drivers/sh/superhyway/Makefile b/drivers/sh/superhyway/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/sh/superhyway/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the SuperHyway bus drivers.
+#
+
+obj-$(CONFIG_SUPERHYWAY)	+= superhyway.o
+obj-$(CONFIG_SYSFS)		+= superhyway-sysfs.o
+
diff --git a/drivers/sh/superhyway/superhyway-sysfs.c b/drivers/sh/superhyway/superhyway-sysfs.c
new file mode 100644
--- /dev/null
+++ b/drivers/sh/superhyway/superhyway-sysfs.c
@@ -0,0 +1,45 @@
+/*
+ * drivers/sh/superhyway/superhyway-sysfs.c
+ *
+ * SuperHyway Bus sysfs interface
+ *
+ * Copyright (C) 2004, 2005  Paul Mundt <lethal@linux-sh.org>
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/superhyway.h>
+
+#define superhyway_ro_attr(name, fmt, field)				\
+static ssize_t name##_show(struct device *dev, char *buf)		\
+{									\
+	struct superhyway_device *s = to_superhyway_device(dev);	\
+	return sprintf(buf, fmt, s->field);				\
+}
+
+/* VCR flags */
+superhyway_ro_attr(perr_flags, "0x%02x\n", vcr.perr_flags);
+superhyway_ro_attr(merr_flags, "0x%02x\n", vcr.merr_flags);
+superhyway_ro_attr(mod_vers, "0x%04x\n", vcr.mod_vers);
+superhyway_ro_attr(mod_id, "0x%04x\n", vcr.mod_id);
+superhyway_ro_attr(bot_mb, "0x%02x\n", vcr.bot_mb);
+superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb);
+
+/* Misc */
+superhyway_ro_attr(resource, "0x%08lx\n", resource.start);
+
+struct device_attribute superhyway_dev_attrs[] = {
+	__ATTR_RO(perr_flags),
+	__ATTR_RO(merr_flags),
+	__ATTR_RO(mod_vers),
+	__ATTR_RO(mod_id),
+	__ATTR_RO(bot_mb),
+	__ATTR_RO(top_mb),
+	__ATTR_RO(resource),
+	__ATTR_NULL,
+};
+
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
new file mode 100644
--- /dev/null
+++ b/drivers/sh/superhyway/superhyway.c
@@ -0,0 +1,201 @@
+/*
+ * drivers/sh/superhyway/superhyway.c
+ *
+ * SuperHyway Bus Driver
+ *
+ * Copyright (C) 2004, 2005  Paul Mundt <lethal@linux-sh.org>
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/superhyway.h>
+
+static int superhyway_devices;
+
+static struct device superhyway_bus_device = {
+	.bus_id = "superhyway",
+};
+
+static void superhyway_device_release(struct device *dev)
+{
+	kfree(to_superhyway_device(dev));
+}
+
+/**
+ * superhyway_add_device - Add a SuperHyway module
+ * @mod_id: Module ID (taken from MODULE.VCR.MOD_ID).
+ * @base: Physical address where module is mapped.
+ * @vcr: VCR value.
+ *
+ * This is responsible for adding a new SuperHyway module. This sets up a new
+ * struct superhyway_device for the module being added. Each one of @mod_id,
+ * @base, and @vcr are registered with the new device for further use
+ * elsewhere.
+ *
+ * Devices are initially added in the order that they are scanned (from the
+ * top-down of the memory map), and are assigned an ID based on the order that
+ * they are added. Any manual addition of a module will thus get the ID after
+ * the devices already discovered regardless of where it resides in memory.
+ *
+ * Further work can and should be done in superhyway_scan_bus(), to be sure
+ * that any new modules are properly discovered and subsequently registered.
+ */
+int superhyway_add_device(unsigned int mod_id, unsigned long base,
+			  unsigned long long vcr)
+{
+	struct superhyway_device *dev;
+
+	dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(struct superhyway_device));
+
+	dev->id.id = mod_id;
+	sprintf(dev->name, "SuperHyway device %04x", dev->id.id);
+
+	dev->vcr		= *((struct vcr_info *)(&vcr));
+	dev->resource.name	= dev->name;
+	dev->resource.start	= base;
+	dev->resource.end	= dev->resource.start + 0x01000000;
+	dev->dev.parent		= &superhyway_bus_device;
+	dev->dev.bus		= &superhyway_bus_type;
+	dev->dev.release	= superhyway_device_release;
+
+	sprintf(dev->dev.bus_id, "%02x", superhyway_devices);
+
+	superhyway_devices++;
+
+	return device_register(&dev->dev);
+}
+
+static int __init superhyway_init(void)
+{
+	device_register(&superhyway_bus_device);
+	return superhyway_scan_bus();
+}
+
+postcore_initcall(superhyway_init);
+
+static const struct superhyway_device_id *
+superhyway_match_id(const struct superhyway_device_id *ids,
+		    struct superhyway_device *dev)
+{
+	while (ids->id) {
+		if (ids->id == dev->id.id)
+			return ids;
+
+		ids++;
+	}
+
+	return NULL;
+}
+
+static int superhyway_device_probe(struct device *dev)
+{
+	struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+	struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
+
+	if (shyway_drv && shyway_drv->probe) {
+		const struct superhyway_device_id *id;
+
+		id = superhyway_match_id(shyway_drv->id_table, shyway_dev);
+		if (id)
+			return shyway_drv->probe(shyway_dev, id);
+	}
+
+	return -ENODEV;
+}
+
+static int superhyway_device_remove(struct device *dev)
+{
+	struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+	struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
+
+	if (shyway_drv && shyway_drv->remove) {
+		shyway_drv->remove(shyway_dev);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * superhyway_register_driver - Register a new SuperHyway driver
+ * @drv: SuperHyway driver to register.
+ *
+ * This registers the passed in @drv. Any devices matching the id table will
+ * automatically be populated and handed off to the driver's specified probe
+ * routine.
+ */
+int superhyway_register_driver(struct superhyway_driver *drv)
+{
+	drv->drv.name	= drv->name;
+	drv->drv.bus	= &superhyway_bus_type;
+	drv->drv.probe	= superhyway_device_probe;
+	drv->drv.remove	= superhyway_device_remove;
+
+	return driver_register(&drv->drv);
+}
+
+/**
+ * superhyway_unregister_driver - Unregister a SuperHyway driver
+ * @drv: SuperHyway driver to unregister.
+ *
+ * This cleans up after superhyway_register_driver(), and should be invoked in
+ * the exit path of any module drivers.
+ */
+void superhyway_unregister_driver(struct superhyway_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+
+static int superhyway_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+	struct superhyway_driver *shyway_drv = to_superhyway_driver(drv);
+	const struct superhyway_device_id *ids = shyway_drv->id_table;
+
+	if (!ids)
+		return -EINVAL;
+	if (superhyway_match_id(ids, shyway_dev))
+		return 1;
+
+	return -ENODEV;
+}
+
+struct bus_type superhyway_bus_type = {
+	.name		= "superhyway",
+	.match		= superhyway_bus_match,
+#ifdef CONFIG_SYSFS
+	.dev_attrs	= superhyway_dev_attrs,
+#endif
+};
+
+static int __init superhyway_bus_init(void)
+{
+	return bus_register(&superhyway_bus_type);
+}
+
+static void __exit superhyway_bus_exit(void)
+{
+	device_unregister(&superhyway_bus_device);
+	bus_unregister(&superhyway_bus_type);
+}
+
+core_initcall(superhyway_bus_init);
+module_exit(superhyway_bus_exit);
+
+EXPORT_SYMBOL(superhyway_bus_type);
+EXPORT_SYMBOL(superhyway_add_device);
+EXPORT_SYMBOL(superhyway_register_driver);
+EXPORT_SYMBOL(superhyway_unregister_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/sn/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Altix device drivers.
+#
+#
+
+obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4.o
diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c
new file mode 100644
--- /dev/null
+++ b/drivers/sn/ioc4.c
@@ -0,0 +1,65 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * This file contains a shim driver for the IOC4 IDE and serial drivers.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioc4_common.h>
+#include <linux/ide.h>
+
+
+static int __devinit
+ioc4_probe_one(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+	int ret;
+
+	if ((ret = pci_enable_device(pdev))) {
+		printk(KERN_WARNING
+			 "%s: Failed to enable device with "
+				"pci_dev 0x%p... returning\n",
+				__FUNCTION__, (void *)pdev);
+		return ret;
+	}
+	pci_set_master(pdev);
+
+	/* attach each sub-device */
+	ret = ioc4_ide_attach_one(pdev, pci_id);
+	if (ret)
+		return ret;
+	return ioc4_serial_attach_one(pdev, pci_id);
+}
+
+/* pci device struct */
+static struct pci_device_id ioc4_s_id_table[] = {
+	{PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
+	 PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ioc4_s_id_table);
+
+static struct pci_driver __devinitdata ioc4_s_driver = {
+	.name	= "IOC4",
+	.id_table = ioc4_s_id_table,
+	.probe	= ioc4_probe_one,
+};
+
+static int __devinit ioc4_detect(void)
+{
+	ioc4_serial_init();
+
+	return pci_register_driver(&ioc4_s_driver);
+}
+module_init(ioc4_detect);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1240,28 +1240,24 @@ static int rs_ioctl(struct tty_struct *t
 
 	switch (cmd) {
 	case TIOCGSERIAL:
-		error = verify_area(VERIFY_WRITE, (void *)arg,
-				    sizeof(struct serial_struct));
-		if (error)
-			return error;
+		if (!access_ok(VERIFY_WRITE, (void *)arg,
+			       sizeof(struct serial_struct)))
+			return -EFAULT;
 		return get_serial_info(info, (struct serial_struct *)arg);
 
 	case TIOCSSERIAL:
 		return set_serial_info(info, (struct serial_struct *)arg);
 
 	case TIOCSERGETLSR:			/* Get line status register */
-		error = verify_area(VERIFY_WRITE, (void *)arg,
-				    sizeof(unsigned int));
-		if (error)
-			return error;
-		else
-			return get_lsr_info(info, (unsigned int *)arg);
+		if (!access_ok(VERIFY_WRITE, (void *)arg,
+			       sizeof(unsigned int)))
+			return -EFAULT;
+		return get_lsr_info(info, (unsigned int *)arg);
 
 	case TIOCSERGSTRUCT:
-		error = verify_area(VERIFY_WRITE, (void *)arg,
-				    sizeof(struct dec_serial));
-		if (error)
-			return error;
+		if (!access_ok(VERIFY_WRITE, (void *)arg,
+			       sizeof(struct dec_serial)))
+			return -EFAULT;
 		copy_from_user((struct dec_serial *)arg, info,
 			       sizeof(struct dec_serial));
 		return 0;
@@ -1368,8 +1364,7 @@ static void rs_close(struct tty_struct *
 	info->tty = 0;
 	if (info->blocked_open) {
 		if (info->close_delay) {
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(info->close_delay);
+			msleep_interruptible(jiffies_to_msecs(info->close_delay));
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -1403,8 +1398,7 @@ static void rs_wait_until_sent(struct tt
 	if (timeout)
 		char_time = min(char_time, timeout);
 	while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(char_time);
+		msleep_interruptible(jiffies_to_msecs(char_time));
 		if (signal_pending(current))
 			break;
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -41,9 +41,6 @@
  *
  ***************************************************************************/
 
-static char ixj_c_rcsid[] = "$Id: ixj.c,v 4.7 2001/08/13 06:19:33 craigs Exp $";
-static char ixj_c_revision[] = "$Revision: 4.7 $";
-
 /*
  * $Log: ixj.c,v $
  *
@@ -5949,10 +5946,10 @@ static int ixj_build_filter_cadence(IXJ 
 	j->cadence_f[lcp->filter].off3 = lcp->off3;
 	j->cadence_f[lcp->filter].off3min = 0;
 	j->cadence_f[lcp->filter].off3max = 0;
-	kfree(lcp);
 	if(ixjdebug & 0x0002) {
 		printk(KERN_INFO "Cadence %d loaded\n", lcp->filter);
 	}
+	kfree(lcp);
 	return 0;
 }
 
@@ -6172,8 +6169,14 @@ static int ixj_ioctl(struct inode *inode
 		retval = j->serial;
 		break;
 	case IXJCTL_VERSION:
-		if (copy_to_user(argp, ixj_c_revision, strlen(ixj_c_revision))) 
-			retval = -EFAULT;
+		{
+			char arg_str[100];
+			snprintf(arg_str, sizeof(arg_str),
+				"\nDriver version %i.%i.%i", IXJ_VER_MAJOR,
+				IXJ_VER_MINOR, IXJ_BLD_VER);
+			if (copy_to_user(argp, arg_str, strlen(arg_str)))
+				retval = -EFAULT;
+		}
 		break;
 	case PHONE_RING_CADENCE:
 		j->ring_cadence = arg;
@@ -7168,9 +7171,6 @@ static int ixj_get_status_proc(char *buf
 	int cnt;
 	IXJ *j;
 	len = 0;
-	len += sprintf(buf + len, "%s", ixj_c_rcsid);
-	len += sprintf(buf + len, "\n%s", ixj_h_rcsid);
-	len += sprintf(buf + len, "\n%s", ixjuser_h_rcsid);
 	len += sprintf(buf + len, "\nDriver version %i.%i.%i", IXJ_VER_MAJOR, IXJ_VER_MINOR, IXJ_BLD_VER);
 	len += sprintf(buf + len, "\nsizeof IXJ struct %Zd bytes", sizeof(IXJ));
 	len += sprintf(buf + len, "\nsizeof DAA struct %Zd bytes", sizeof(DAA_REGS));
@@ -7790,7 +7790,7 @@ static int __init ixj_init(void)
 	if ((probe = ixj_probe_pci(&cnt)) < 0) {
 		return probe;
 	}
-	printk("%s\n", ixj_c_rcsid);
+	printk(KERN_INFO "ixj driver initialized.\n");
 	create_proc_read_entry ("ixj", 0, NULL, ixj_read_proc, NULL);
 	return probe;
 }
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -38,8 +38,6 @@
  * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  *****************************************************************************/
-static char ixj_h_rcsid[] = "$Id: ixj.h,v 4.1 2001/08/04 14:49:27 craigs Exp $";
-
 #define IXJ_VERSION 3031
 
 #include <linux/version.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -4,6 +4,31 @@
 
 menu "USB support"
 
+# Host-side USB depends on having a host controller
+# NOTE:  dummy_hcd is always an option, but it's ignored here ...
+# NOTE:  SL-811 option should be board-specific ...
+config USB_ARCH_HAS_HCD
+	boolean
+	default y if USB_ARCH_HAS_OHCI
+	default y if ARM				# SL-811
+	default PCI
+
+# many non-PCI SOC chips embed OHCI
+config USB_ARCH_HAS_OHCI
+	boolean
+	# ARM:
+	default y if SA1111
+	default y if ARCH_OMAP
+	default y if ARCH_LH7A404
+	default y if PXA27x
+	# PPC:
+	default y if STB03xxx
+	default y if PPC_MPC52xx
+	# MIPS:
+	default y if SOC_AU1X00
+	# more:
+	default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
 	tristate "Support for Host-side USB"
@@ -56,12 +81,15 @@ source "drivers/usb/media/Kconfig"
 
 source "drivers/usb/net/Kconfig"
 
+source "drivers/usb/mon/Kconfig"
+
 comment "USB port drivers"
 	depends on USB
 
 config USB_USS720
 	tristate "USS720 parport driver"
 	depends on USB && PARPORT
+	select PARPORT_NOT_PC
 	---help---
 	  This driver is for USB parallel port adapters that use the Lucent
 	  Technologies USS-720 chip. These cables are plugged into your USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)		+= core/
 
+obj-$(CONFIG_USB_MON)		+= mon/
+
 obj-$(CONFIG_USB_EHCI_HCD)	+= host/
 obj-$(CONFIG_USB_OHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
@@ -48,8 +50,8 @@ obj-$(CONFIG_USB_KAWETH)	+= net/
 obj-$(CONFIG_USB_PEGASUS)	+= net/
 obj-$(CONFIG_USB_RTL8150)	+= net/
 obj-$(CONFIG_USB_USBNET)	+= net/
+obj-$(CONFIG_USB_ZD1201)	+= net/
 
-obj-$(CONFIG_USB_HPUSBSCSI)	+= image/
 obj-$(CONFIG_USB_MDC800)	+= image/
 obj-$(CONFIG_USB_MICROTEK)	+= image/
 
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -58,8 +58,8 @@ static const char speedtch_driver_name[]
 #define SPEEDTOUCH_PRODUCTID		0x4061
 
 /* Timeout in jiffies */
-#define CTRL_TIMEOUT (2*HZ)
-#define DATA_TIMEOUT (2*HZ)
+#define CTRL_TIMEOUT 2000
+#define DATA_TIMEOUT 2000
 
 #define OFFSET_7  0		/* size 1 */
 #define OFFSET_b  1		/* size 8 */
@@ -386,6 +386,8 @@ static void speedtch_poll_status(struct 
 		if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
 			instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
 			printk(KERN_NOTICE "ADSL line is down\n");
+			/* It'll never resync again unless we ask it to... */
+			speedtch_start_synchro(instance);
 		}
 		break;
 
@@ -474,7 +476,7 @@ static void speedtch_upload_firmware(str
 	/* URB 7 */
 	if (dl_512_first) {	/* some modems need a read before writing the firmware */
 		ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
-				   buffer, 0x200, &actual_length, 2 * HZ);
+				   buffer, 0x200, &actual_length, 2000);
 
 		if (ret < 0 && ret != -ETIMEDOUT)
 			dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);
@@ -766,7 +768,7 @@ static int speedtch_usb_probe(struct usb
 
 	/* First check whether the modem already seems to be alive */
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, HZ / 2);
+			      0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500);
 
 	if (ret == SIZE_7) {
 		dbg("firmware appears to be already loaded");
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
--- a/drivers/usb/class/audio.c
+++ b/drivers/usb/class/audio.c
@@ -649,14 +649,10 @@ static void usbin_stop(struct usb_audiod
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb->transfer_buffer)
-		kfree(u->durb[0].urb->transfer_buffer);
-	if (u->durb[1].urb->transfer_buffer)
-		kfree(u->durb[1].urb->transfer_buffer);
-	if (u->surb[0].urb->transfer_buffer)
-		kfree(u->surb[0].urb->transfer_buffer);
-	if (u->surb[1].urb->transfer_buffer)
-		kfree(u->surb[1].urb->transfer_buffer);
+	kfree(u->durb[0].urb->transfer_buffer);
+	kfree(u->durb[1].urb->transfer_buffer);
+	kfree(u->surb[0].urb->transfer_buffer);
+	kfree(u->surb[1].urb->transfer_buffer);
 	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
 		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
@@ -1009,21 +1005,17 @@ static int usbin_start(struct usb_audiod
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb->transfer_buffer)
-			kfree(u->durb[0].urb->transfer_buffer);
+		kfree(u->durb[0].urb->transfer_buffer);
 		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
 		u->durb[0].urb->transfer_buffer_length = bufsz;
-		if (u->durb[1].urb->transfer_buffer)
-			kfree(u->durb[1].urb->transfer_buffer);
+		kfree(u->durb[1].urb->transfer_buffer);
 		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
 		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb->transfer_buffer)
-				kfree(u->surb[0].urb->transfer_buffer);
+			kfree(u->surb[0].urb->transfer_buffer);
 			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
 			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb->transfer_buffer)
-				kfree(u->surb[1].urb->transfer_buffer);
+			kfree(u->surb[1].urb->transfer_buffer);
 			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
 			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
@@ -1128,14 +1120,10 @@ static void usbout_stop(struct usb_audio
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb->transfer_buffer)
-		kfree(u->durb[0].urb->transfer_buffer);
-	if (u->durb[1].urb->transfer_buffer)
-		kfree(u->durb[1].urb->transfer_buffer);
-	if (u->surb[0].urb->transfer_buffer)
-		kfree(u->surb[0].urb->transfer_buffer);
-	if (u->surb[1].urb->transfer_buffer)
-		kfree(u->surb[1].urb->transfer_buffer);
+	kfree(u->durb[0].urb->transfer_buffer);
+	kfree(u->durb[1].urb->transfer_buffer);
+	kfree(u->surb[0].urb->transfer_buffer);
+	kfree(u->surb[1].urb->transfer_buffer);
 	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
 		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
@@ -1376,21 +1364,17 @@ static int usbout_start(struct usb_audio
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb->transfer_buffer)
-			kfree(u->durb[0].urb->transfer_buffer);
+		kfree(u->durb[0].urb->transfer_buffer);
 		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
 		u->durb[0].urb->transfer_buffer_length = bufsz;
-		if (u->durb[1].urb->transfer_buffer)
-			kfree(u->durb[1].urb->transfer_buffer);
+		kfree(u->durb[1].urb->transfer_buffer);
 		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
 		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb->transfer_buffer)
-				kfree(u->surb[0].urb->transfer_buffer);
+			kfree(u->surb[0].urb->transfer_buffer);
 			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
 			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb->transfer_buffer)
-				kfree(u->surb[1].urb->transfer_buffer);
+			kfree(u->surb[1].urb->transfer_buffer);
 			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
 			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
@@ -1561,7 +1545,7 @@ static int set_format_in(struct usb_audi
 	if (fmt->attributes & 0x02) {
 		data[0] = 1;
 		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
 			       ret, dev->devnum, u->interface, ep, d->srate);
 			return -1;
@@ -1573,13 +1557,13 @@ static int set_format_in(struct usb_audi
 		data[1] = d->srate >> 8;
 		data[2] = d->srate >> 16;
 		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
 			       ret, dev->devnum, u->interface, ep, d->srate);
 			return -1;
 		}
 		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
 			       ret, dev->devnum, u->interface, ep);
 			return -1;
@@ -1657,7 +1641,7 @@ static int set_format_out(struct usb_aud
 	if (fmt->attributes & 0x02) {
 		data[0] = 1;
 		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
 			       ret, dev->devnum, u->interface, ep, d->srate);
 			return -1;
@@ -1669,13 +1653,13 @@ static int set_format_out(struct usb_aud
 		data[1] = d->srate >> 8;
 		data[2] = d->srate >> 16;
 		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
 			       ret, dev->devnum, u->interface, ep, d->srate);
 			return -1;
 		}
 		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
 			       ret, dev->devnum, u->interface, ep);
 			return -1;
@@ -1754,7 +1738,7 @@ static int wrmixer(struct usb_mixerdev *
 		data[0] = v1;
 		data[1] = v1 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+				    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
 			goto err;
 		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 			return 0;
@@ -1762,7 +1746,7 @@ static int wrmixer(struct usb_mixerdev *
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+				    ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
 			goto err;
 		return 0;
 
@@ -1771,14 +1755,14 @@ static int wrmixer(struct usb_mixerdev *
 		data[0] = v1;
 		data[1] = v1 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
 			goto err;
 		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 			return 0;
 		data[0] = v2;
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
 			goto err;
 		return 0;
                 
@@ -1787,13 +1771,13 @@ static int wrmixer(struct usb_mixerdev *
 	case TREBLE_CONTROL:
 		data[0] = v1 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
 			goto err;
 		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 			return 0;
 		data[0] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
 			goto err;
 		return 0;
 
@@ -1820,7 +1804,7 @@ static int get_rec_src(struct usb_mixerd
 		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
 			continue;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
 			err = -EIO;
 			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
 			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
@@ -1851,7 +1835,7 @@ static int set_rec_src(struct usb_mixerd
 		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
 			continue;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
 			err = -EIO;
 			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
 			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
@@ -1880,7 +1864,7 @@ static int set_rec_src(struct usb_mixerd
 				continue;
 			buf = ms->ch[j].slctunitid >> 8;
 			if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
+				    0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) {
 				err = -EIO;
 				printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", 
 				       dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
@@ -3136,18 +3120,18 @@ static void prepmixch(struct consmixstat
 	switch (ch->selector) {
 	case 0:  /* mixer unit request */
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
 		if (!v2)
 			v2 = 1;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v3 = v1 - ch->minval;
@@ -3158,7 +3142,7 @@ static void prepmixch(struct consmixstat
 		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+					    state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -3172,15 +3156,15 @@ static void prepmixch(struct consmixstat
 		/* various feature unit controls */
 	case VOLUME_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
@@ -3193,7 +3177,7 @@ static void prepmixch(struct consmixstat
 		ch->value = v3;
 		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
 				goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -3208,15 +3192,15 @@ static void prepmixch(struct consmixstat
 	case MID_CONTROL:
 	case TREBLE_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
 			goto err;
 		ch->minval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
 			goto err;
 		ch->maxval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
 			goto err;
 		v1 = buf[0] << 8;
 		v2 = ch->maxval - ch->minval;
@@ -3229,7 +3213,7 @@ static void prepmixch(struct consmixstat
 		ch->value = v3;
 		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
 				goto err;
 			v1 = buf[0] << 8;
 			v3 = v1 - ch->minval;
@@ -3522,7 +3506,7 @@ static void usb_audio_featureunit(struct
 		printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
 		data[0] = 0;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, HZ) < 0)
+				    (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0)
 			printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
  	}
 #endif
diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c
+++ b/drivers/usb/class/bluetty.c
@@ -309,7 +309,7 @@ static int bluetooth_ctrl_msg (struct us
 		}
 	}
 	if (urb->transfer_buffer_length < len) {
-		kfree (urb->transfer_buffer);
+		kfree(urb->transfer_buffer);
 		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
 		if (urb->transfer_buffer == NULL) {
 			err ("%s - out of memory", __FUNCTION__);
@@ -535,7 +535,7 @@ static int bluetooth_write (struct tty_s
 	}
 
 exit:
-	kfree (temp_buffer);
+	kfree(temp_buffer);
 
 	return retval;
 } 
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -60,6 +60,7 @@
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
+#include <linux/usb_cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
@@ -89,7 +90,7 @@ static int acm_ctrl_msg(struct acm *acm,
 	int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
 		request, USB_RT_ACM, value,
 		acm->control->altsetting[0].desc.bInterfaceNumber,
-		buf, len, HZ * 5);
+		buf, len, 5000);
 	dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
 	return retval < 0 ? retval : 0;
 }
@@ -97,9 +98,12 @@ static int acm_ctrl_msg(struct acm *acm,
 /* devices aren't required to support these requests.
  * the cdc acm descriptor tells whether they do...
  */
-#define acm_set_control(acm, control)	acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
-#define acm_set_line(acm, line)		acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
-#define acm_send_break(acm, ms)		acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
+#define acm_set_control(acm, control) \
+	acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
+#define acm_set_line(acm, line) \
+	acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
+#define acm_send_break(acm, ms) \
+	acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
 
 /*
  * Interrupt handlers for various ACM device responses
@@ -109,7 +113,7 @@ static int acm_ctrl_msg(struct acm *acm,
 static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
 {
 	struct acm *acm = urb->context;
-	struct usb_ctrlrequest *dr = urb->transfer_buffer;
+	struct usb_cdc_notification *dr = urb->transfer_buffer;
 	unsigned char *data;
 	int newctrl;
 	int status;
@@ -133,14 +137,14 @@ static void acm_ctrl_irq(struct urb *urb
 		goto exit;
 
 	data = (unsigned char *)(dr + 1);
-	switch (dr->bRequest) {
+	switch (dr->bNotificationType) {
 
-		case ACM_IRQ_NETWORK:
+		case USB_CDC_NOTIFY_NETWORK_CONNECTION:
 
 			dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
 			break;
 
-		case ACM_IRQ_LINE_STATE:
+		case USB_CDC_NOTIFY_SERIAL_STATE:
 
 			newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
 
@@ -160,8 +164,9 @@ static void acm_ctrl_irq(struct urb *urb
 			break;
 
 		default:
-			dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
-				dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
+			dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
+				dr->bNotificationType, dr->wIndex,
+				dr->wLength, data[0], data[1]);
 			break;
 	}
 exit:
@@ -485,32 +490,34 @@ static void acm_tty_set_termios(struct t
 {
 	struct acm *acm = tty->driver_data;
 	struct termios *termios = tty->termios;
-	struct acm_line newline;
+	struct usb_cdc_line_coding newline;
 	int newctrl = acm->ctrlout;
 
 	if (!ACM_READY(acm))
 		return;
 
-	newline.speed = cpu_to_le32p(acm_tty_speed +
+	newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
 		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
-	newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
-	newline.parity = termios->c_cflag & PARENB ?
+	newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
+	newline.bParityType = termios->c_cflag & PARENB ?
 		(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
-	newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
+	newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
 
 	acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
 
-	if (!newline.speed) {
-		newline.speed = acm->line.speed;
+	if (!newline.dwDTERate) {
+		newline.dwDTERate = acm->line.dwDTERate;
 		newctrl &= ~ACM_CTRL_DTR;
 	} else  newctrl |=  ACM_CTRL_DTR;
 
 	if (newctrl != acm->ctrlout)
 		acm_set_control(acm, acm->ctrlout = newctrl);
 
-	if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {
-		memcpy(&acm->line, &newline, sizeof(struct acm_line));
-		dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
+	if (memcmp(&acm->line, &newline, sizeof newline)) {
+		memcpy(&acm->line, &newline, sizeof newline);
+		dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
+			newline.bCharFormat, newline.bParityType,
+			newline.bDataBits);
 		acm_set_line(acm, &acm->line);
 	}
 }
@@ -522,7 +529,7 @@ static void acm_tty_set_termios(struct t
 static int acm_probe (struct usb_interface *intf,
 		      const struct usb_device_id *id)
 {
-	struct union_desc *union_header = NULL;
+	struct usb_cdc_union_desc *union_header = NULL;
 	char *buffer = intf->altsetting->extra;
 	int buflen = intf->altsetting->extralen;
 	struct usb_interface *control_interface;
@@ -573,21 +580,22 @@ static int acm_probe (struct usb_interfa
 		}
 
 		switch (buffer [2]) {
-			case CDC_UNION_TYPE: /* we've found it */
+			case USB_CDC_UNION_TYPE: /* we've found it */
 				if (union_header) {
 					err("More than one union descriptor, skipping ...");
 					goto next_desc;
 				}
-				union_header = (struct union_desc *)buffer;
+				union_header = (struct usb_cdc_union_desc *)
+							buffer;
 				break;
-			case CDC_COUNTRY_TYPE: /* maybe somehow export */
+			case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
 				break; /* for now we ignore it */
-			case CDC_HEADER_TYPE: /* maybe check version */ 
+			case USB_CDC_HEADER_TYPE: /* maybe check version */ 
 				break; /* for now we ignore it */ 
-			case CDC_AC_MANAGEMENT_TYPE:
+			case USB_CDC_ACM_TYPE:
 				ac_management_function = buffer[3];
 				break;
-			case CDC_CALL_MANAGEMENT_TYPE:
+			case USB_CDC_CALL_MANAGEMENT_TYPE:
 				call_management_function = buffer[3];
 				call_interface_num = buffer[4];
 				if ((call_management_function & 3) != 3)
@@ -750,8 +758,8 @@ skip_normal_probe:
 
 	acm_set_control(acm, acm->ctrlout);
 
-	acm->line.speed = cpu_to_le32(9600);
-	acm->line.databits = 8;
+	acm->line.dwDTERate = cpu_to_le32(9600);
+	acm->line.bDataBits = 8;
 	acm_set_line(acm, &acm->line);
 
 	usb_driver_claim_interface(&acm_driver, data_interface, acm);
@@ -831,14 +839,20 @@ static struct usb_device_id acm_ids[] = 
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
 	/* control interfaces with various AT-command sets */
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 1) },
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 2) },
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 3) },
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 4) },
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 5) },
-	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 6) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_V25TER) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_PCCA101) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_GSM) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_3G	) },
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+		USB_CDC_ACM_PROTO_AT_CDMA) },
 
-	/* NOTE:  COMM/2/0xff is likely MSFT RNDIS ... NOT a modem!! */
+	/* NOTE:  COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
 	{ }
 };
 
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -27,24 +27,6 @@
 
 #define USB_RT_ACM		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
 
-#define ACM_REQ_COMMAND		0x00
-#define ACM_REQ_RESPONSE	0x01
-#define ACM_REQ_SET_FEATURE	0x02
-#define ACM_REQ_GET_FEATURE	0x03
-#define ACM_REQ_CLEAR_FEATURE	0x04
-
-#define ACM_REQ_SET_LINE	0x20
-#define ACM_REQ_GET_LINE	0x21
-#define ACM_REQ_SET_CONTROL	0x22
-#define ACM_REQ_SEND_BREAK	0x23
-
-/*
- * IRQs.
- */
-
-#define ACM_IRQ_NETWORK		0x00
-#define ACM_IRQ_LINE_STATE	0x20
-
 /*
  * Output control lines.
  */
@@ -66,17 +48,6 @@
 #define ACM_CTRL_OVERRUN	0x40
 
 /*
- * Line speed and caracter encoding.
- */
-
-struct acm_line {
-	__le32 speed;
-	__u8 stopbits;
-	__u8 parity;
-	__u8 databits;
-} __attribute__ ((packed));
-
-/*
  * Internal driver structures.
  */
 
@@ -88,7 +59,7 @@ struct acm {
 	struct urb *ctrlurb, *readurb, *writeurb;	/* urbs */
 	u8 *ctrl_buffer, *read_buffer, *write_buffer;	/* buffers of urbs */
 	dma_addr_t ctrl_dma, read_dma, write_dma;	/* dma handles of buffers */
-	struct acm_line line;				/* line coding (bits, stop, parity) */
+	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
 	struct tasklet_struct bh;			/* rx processing */
 	spinlock_t throttle_lock;			/* synchronize throtteling and read callback */
@@ -105,24 +76,6 @@ struct acm {
 	unsigned int ctrl_caps;				/* control capabilities from the class specific header */
 };
 
-/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
-struct union_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u8	bMasterInterface0;
-	u8	bSlaveInterface0;
-	/* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* class specific descriptor types */
-#define CDC_HEADER_TYPE			0x00
-#define CDC_CALL_MANAGEMENT_TYPE	0x01
-#define CDC_AC_MANAGEMENT_TYPE		0x02
-#define CDC_UNION_TYPE			0x06
-#define CDC_COUNTRY_TYPE		0x07
-
 #define CDC_DATA_INTERFACE_TYPE	0x0a
 
 /* constants describing various quirks and errors */
diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
--- a/drivers/usb/class/usb-midi.c
+++ b/drivers/usb/class/usb-midi.c
@@ -992,7 +992,7 @@ static struct midi_in_endpoint *alloc_mi
 	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) );
+	bufSize = usb_maxpacket( d, pipe, 0 );
 	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
 
 	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
@@ -1063,7 +1063,7 @@ static struct midi_out_endpoint *alloc_m
 
 	endPoint &= 0x0f;
 	pipe =  usb_sndbulkpipe( d, endPoint );
-	bufSize = usb_maxpacket( d, pipe, usb_pipeout(pipe) );
+	bufSize = usb_maxpacket( d, pipe, 1 );
 
 	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
 	if ( !ep ) {
@@ -1451,8 +1451,6 @@ static struct usb_midi_device *parse_des
 			} 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 )
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -114,7 +114,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD
 #define USBLP_MINORS		16
 #define USBLP_MINOR_BASE	0
 
-#define USBLP_WRITE_TIMEOUT	(5*HZ)			/* 5 seconds */
+#define USBLP_WRITE_TIMEOUT	(5000)			/* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL	1
 #define USBLP_LAST_PROTOCOL	3
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -76,7 +76,6 @@ int hcd_buffer_create (struct usb_hcd *h
 	}
 	return 0;
 }
-EXPORT_SYMBOL (hcd_buffer_create);
 
 
 /**
@@ -98,7 +97,6 @@ void hcd_buffer_destroy (struct usb_hcd 
 		}
 	}
 }
-EXPORT_SYMBOL (hcd_buffer_destroy);
 
 
 /* sometimes alloc/free could use kmalloc with SLAB_DMA, for
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -10,7 +10,8 @@
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <asm/byteorder.h>
-
+#include "usb.h"
+#include "hcd.h"
 
 #define USB_MAXALTSETTING		128	/* Hard limit */
 #define USB_MAXENDPOINTS		30	/* Hard limit */
@@ -221,7 +222,7 @@ skip_to_next_interface_descriptor:
 	return buffer - buffer0 + i;
 }
 
-int usb_parse_configuration(struct device *ddev, int cfgidx,
+static int usb_parse_configuration(struct device *ddev, int cfgidx,
     struct usb_host_config *config, unsigned char *buffer, int size)
 {
 	unsigned char *buffer0 = buffer;
@@ -420,6 +421,9 @@ void usb_destroy_configuration(struct us
 	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
 		struct usb_host_config *cf = &dev->config[c];
 
+		kfree(cf->string);
+		cf->string = NULL;
+
 		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
 			if (cf->intf_cache[i])
 				kref_put(&cf->intf_cache[i]->ref, 
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -59,6 +59,7 @@
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 
+#include "usb.h"
 #include "hcd.h"
 
 #define MAX_TOPO_LEVEL		6
@@ -362,33 +363,21 @@ static char *usb_dump_device_descriptor(
  */
 static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
 {
-	char *buf;
-
 	if (start > end)
 		return start;
-	buf = kmalloc(128, GFP_KERNEL);
-	if (!buf)
-		return start;
-	if (dev->descriptor.iManufacturer) {
-		if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0)
-			start += sprintf(start, format_string_manufacturer, buf);
-	}				
+	if (dev->manufacturer)
+		start += sprintf(start, format_string_manufacturer, dev->manufacturer);
 	if (start > end)
 		goto out;
-	if (dev->descriptor.iProduct) {
-		if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0)
-			start += sprintf(start, format_string_product, buf);
-	}
+	if (dev->product)
+		start += sprintf(start, format_string_product, dev->product);
 	if (start > end)
 		goto out;
 #ifdef ALLOW_SERIAL_NUMBER
-	if (dev->descriptor.iSerialNumber) {
-		if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0)
-			start += sprintf(start, format_string_serialnumber, buf);
-	}
+	if (dev->serial)
+		start += sprintf(start, format_string_serialnumber, dev->serial);
 #endif
  out:
-	kfree(buf);
 	return start;
 }
 
@@ -472,7 +461,7 @@ static ssize_t usb_device_dump(char __us
 		return 0;
 	
 	if (level > MAX_TOPO_LEVEL)
-		return total_written;
+		return 0;
 	/* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
         if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
                 return -ENOMEM;
@@ -539,10 +528,7 @@ static ssize_t usb_device_dump(char __us
 			length = *nbytes;
 		if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
 			free_pages((unsigned long)pages_start, 1);
-			
-			if (total_written == 0)
-				return -EFAULT;
-			return total_written;
+			return -EFAULT;
 		}
 		*nbytes -= length;
 		*file_offset += length;
@@ -620,6 +606,7 @@ static unsigned int usb_device_poll(stru
 		/* we may have dropped BKL - need to check for having lost the race */
 		if (file->private_data) {
 			kfree(st);
+			st = file->private_data;
 			goto lost_race;
 		}
 
@@ -650,11 +637,8 @@ static int usb_device_open(struct inode 
 
 static int usb_device_release(struct inode *inode, struct file *file)
 {
-	if (file->private_data) {
-		kfree(file->private_data);
-		file->private_data = NULL;
-	}
-
+	kfree(file->private_data);
+	file->private_data = NULL;
         return 0;
 }
 
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -213,12 +213,10 @@ static struct async *alloc_async(unsigne
 
 static void free_async(struct async *as)
 {
-        if (as->urb->transfer_buffer)
-                kfree(as->urb->transfer_buffer);
-        if (as->urb->setup_packet)
-                kfree(as->urb->setup_packet);
+	kfree(as->urb->transfer_buffer);
+	kfree(as->urb->setup_packet);
 	usb_free_urb(as->urb);
-        kfree(as);
+	kfree(as);
 }
 
 static inline void async_newpending(struct async *as)
@@ -565,7 +563,7 @@ static int proc_control(struct dev_state
 		return -EINVAL;
 	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
-	tmo = (ctrl.timeout * HZ + 999) / 1000;
+	tmo = ctrl.timeout;
 	if (ctrl.bRequestType & 0x80) {
 		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
 			free_page((unsigned long)tbuf);
@@ -646,7 +644,7 @@ static int proc_bulk(struct dev_state *p
 		return -EINVAL;
 	if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
 		return -ENOMEM;
-	tmo = (bulk.timeout * HZ + 999) / 1000;
+	tmo = bulk.timeout;
 	if (bulk.ep & 0x80) {
 		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
 			kfree(tbuf);
@@ -673,11 +671,8 @@ static int proc_bulk(struct dev_state *p
 		usb_lock_device(dev);
 	}
 	kfree(tbuf);
-	if (i < 0) {
-		dev_warn(&dev->dev, "usbfs: USBDEVFS_BULK failed "
-			 "ep 0x%x len %u ret %d\n", bulk.ep, bulk.len, i);
+	if (i < 0)
 		return i;
-	}
 	return len2;
 }
 
@@ -816,9 +811,11 @@ static int proc_setconfig(struct dev_sta
 	return status;
 }
 
-static int proc_submiturb(struct dev_state *ps, void __user *arg)
+
+static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+			     struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+			     void __user *arg)
 {
-	struct usbdevfs_urb uurb;
 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
 	struct usb_host_endpoint *ep;
 	struct async *as;
@@ -826,42 +823,40 @@ static int proc_submiturb(struct dev_sta
 	unsigned int u, totlen, isofrmlen;
 	int ret, interval = 0, ifnum = -1;
 
-	if (copy_from_user(&uurb, arg, sizeof(uurb)))
-		return -EFAULT;
-	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
+	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
 		return -EINVAL;
-	if (!uurb.buffer)
+	if (!uurb->buffer)
 		return -EINVAL;
-	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
+	if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX))
 		return -EINVAL;
-	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-		if ((ifnum = findintfep(ps->dev, uurb.endpoint)) < 0)
+	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+		if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0)
 			return ifnum;
 		if ((ret = checkintf(ps, ifnum)))
 			return ret;
 	}
-	if ((uurb.endpoint & USB_ENDPOINT_DIR_MASK) != 0)
-		ep = ps->dev->ep_in [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK];
+	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
+		ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
 	else
-		ep = ps->dev->ep_out [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK];
+		ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
 	if (!ep)
 		return -ENOENT;
-	switch(uurb.type) {
+	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
 		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 				!= USB_ENDPOINT_XFER_CONTROL)
 			return -EINVAL;
 		/* min 8 byte setup packet, max arbitrary */
-		if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
+		if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE)
 			return -EINVAL;
 		if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
 			return -ENOMEM;
-		if (copy_from_user(dr, uurb.buffer, 8)) {
+		if (copy_from_user(dr, uurb->buffer, 8)) {
 			kfree(dr);
 			return -EFAULT;
 		}
-		if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
+		if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
 			kfree(dr);
 			return -EINVAL;
 		}
@@ -869,11 +864,11 @@ static int proc_submiturb(struct dev_sta
 			kfree(dr);
 			return ret;
 		}
-		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->wLength);
-		uurb.buffer += 8;
-		if (!access_ok((uurb.endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
+		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->wLength);
+		uurb->buffer += 8;
+		if (!access_ok((uurb->endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
 			kfree(dr);
 			return -EFAULT;
 		}
@@ -886,29 +881,29 @@ static int proc_submiturb(struct dev_sta
 			return -EINVAL;
 		/* allow single-shot interrupt transfers, at bogus rates */
 		}
-		uurb.number_of_packets = 0;
-		if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE)
+		uurb->number_of_packets = 0;
+		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		break;
 
 	case USBDEVFS_URB_TYPE_ISO:
 		/* arbitrary limit */
-		if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
+		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
 			return -EINVAL;
 		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 				!= USB_ENDPOINT_XFER_ISOC)
 			return -EINVAL;
 		interval = 1 << min (15, ep->desc.bInterval - 1);
-		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
+		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
 			return -ENOMEM;
-		if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) {
+		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
 			kfree(isopkt);
 			return -EFAULT;
 		}
-		for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+		for (totlen = u = 0; u < uurb->number_of_packets; u++) {
 			if (isopkt[u].length > 1023) {
 				kfree(isopkt);
 				return -EINVAL;
@@ -919,11 +914,11 @@ static int proc_submiturb(struct dev_sta
 			kfree(isopkt);
 			return -EINVAL;
 		}
-		uurb.buffer_length = totlen;
+		uurb->buffer_length = totlen;
 		break;
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
-		uurb.number_of_packets = 0;
+		uurb->number_of_packets = 0;
 		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 				!= USB_ENDPOINT_XFER_INT)
 			return -EINVAL;
@@ -931,58 +926,53 @@ static int proc_submiturb(struct dev_sta
 			interval = 1 << min (15, ep->desc.bInterval - 1);
 		else
 			interval = ep->desc.bInterval;
-		if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE)
+		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		break;
 
 	default:
 		return -EINVAL;
 	}
-	if (!(as = alloc_async(uurb.number_of_packets))) {
-		if (isopkt)
-			kfree(isopkt);
-		if (dr)
-			kfree(dr);
+	if (!(as = alloc_async(uurb->number_of_packets))) {
+		kfree(isopkt);
+		kfree(dr);
 		return -ENOMEM;
 	}
-	if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
-		if (isopkt)
-			kfree(isopkt);
-		if (dr)
-			kfree(dr);
+	if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
+		kfree(isopkt);
+		kfree(dr);
 		free_async(as);
 		return -ENOMEM;
 	}
         as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb.flags;
-	as->urb->transfer_buffer_length = uurb.buffer_length;
+        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags;
+	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char*)dr;
-	as->urb->start_frame = uurb.start_frame;
-	as->urb->number_of_packets = uurb.number_of_packets;
+	as->urb->start_frame = uurb->start_frame;
+	as->urb->number_of_packets = uurb->number_of_packets;
 	as->urb->interval = interval;
         as->urb->context = as;
         as->urb->complete = async_completed;
-	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+	for (totlen = u = 0; u < uurb->number_of_packets; u++) {
 		as->urb->iso_frame_desc[u].offset = totlen;
 		as->urb->iso_frame_desc[u].length = isopkt[u].length;
 		totlen += isopkt[u].length;
 	}
-	if (isopkt)
-		kfree(isopkt);
+	kfree(isopkt);
 	as->ps = ps;
         as->userurb = arg;
-	if (uurb.endpoint & USB_DIR_IN)
-		as->userbuffer = uurb.buffer;
+	if (uurb->endpoint & USB_DIR_IN)
+		as->userbuffer = uurb->buffer;
 	else
 		as->userbuffer = NULL;
-	as->signr = uurb.signr;
+	as->signr = uurb->signr;
 	as->ifnum = ifnum;
 	as->task = current;
-	if (!(uurb.endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
+	if (!(uurb->endpoint & USB_DIR_IN)) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
@@ -997,6 +987,16 @@ static int proc_submiturb(struct dev_sta
         return 0;
 }
 
+static int proc_submiturb(struct dev_state *ps, void __user *arg)
+{
+	struct usbdevfs_urb uurb;
+
+	if (copy_from_user(&uurb, arg, sizeof(uurb)))
+		return -EFAULT;
+
+	return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
+}
+
 static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
 {
 	struct async *as;
@@ -1008,10 +1008,11 @@ static int proc_unlinkurb(struct dev_sta
 	return 0;
 }
 
-static int processcompl(struct async *as)
+static int processcompl(struct async *as, void __user * __user *arg)
 {
 	struct urb *urb = as->urb;
 	struct usbdevfs_urb __user *userurb = as->userurb;
+	void __user *addr = as->userurb;
 	unsigned int i;
 
 	if (as->userbuffer)
@@ -1024,26 +1025,29 @@ static int processcompl(struct async *as
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 
-	if (!(usb_pipeisoc(urb->pipe)))
-		return 0;
-	for (i = 0; i < urb->number_of_packets; i++) {
-		if (put_user(urb->iso_frame_desc[i].actual_length,
-			     &userurb->iso_frame_desc[i].actual_length))
-			return -EFAULT;
-		if (put_user(urb->iso_frame_desc[i].status,
-			     &userurb->iso_frame_desc[i].status))
-			return -EFAULT;
+	if (usb_pipeisoc(urb->pipe)) {
+		for (i = 0; i < urb->number_of_packets; i++) {
+			if (put_user(urb->iso_frame_desc[i].actual_length,
+				     &userurb->iso_frame_desc[i].actual_length))
+				return -EFAULT;
+			if (put_user(urb->iso_frame_desc[i].status,
+				     &userurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
 	}
+
+	free_async(as);
+
+	if (put_user(addr, (void __user * __user *)arg))
+		return -EFAULT;
 	return 0;
 }
 
-static int proc_reapurb(struct dev_state *ps, void __user *arg)
+static struct async* reap_as(struct dev_state *ps)
 {
         DECLARE_WAITQUEUE(wait, current);
 	struct async *as = NULL;
-	void __user *addr;
 	struct usb_device *dev = ps->dev;
-	int ret;
 
 	add_wait_queue(&ps->wait, &wait);
 	for (;;) {
@@ -1058,16 +1062,14 @@ static int proc_reapurb(struct dev_state
 	}
 	remove_wait_queue(&ps->wait, &wait);
 	set_current_state(TASK_RUNNING);
-	if (as) {
-		ret = processcompl(as);
-		addr = as->userurb;
-		free_async(as);
-		if (ret)
-			return ret;
-		if (put_user(addr, (void __user * __user *)arg))
-			return -EFAULT;
-		return 0;
-	}
+	return as;
+}
+
+static int proc_reapurb(struct dev_state *ps, void __user *arg)
+{
+	struct async *as = reap_as(ps);
+	if (as)
+		return processcompl(as, (void __user * __user *)arg);
 	if (signal_pending(current))
 		return -EINTR;
 	return -EIO;
@@ -1076,21 +1078,105 @@ static int proc_reapurb(struct dev_state
 static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
 {
 	struct async *as;
-	void __user *addr;
-	int ret;
 
 	if (!(as = async_getcompleted(ps)))
 		return -EAGAIN;
-	ret = processcompl(as);
-	addr = as->userurb;
+	return processcompl(as, (void __user * __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 __user *uurb)
+{
+	__u32  uptr;
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
+		return -EFAULT;
+
+	if (__get_user(uptr, &uurb->buffer))
+		return -EFAULT;
+	kurb->buffer = compat_ptr(uptr);
+	if (__get_user(uptr, &uurb->buffer))
+		return -EFAULT;
+	kurb->usercontext = compat_ptr(uptr);
+
+	return 0;
+}
+
+static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
+{
+	struct usbdevfs_urb uurb;
+
+	if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
+		return -EFAULT;
+
+	return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
+}
+
+static int processcompl_compat(struct async *as, void __user * __user *arg)
+{
+	struct urb *urb = as->urb;
+	struct usbdevfs_urb32 __user *userurb = as->userurb;
+	void __user *addr = as->userurb;
+	unsigned int i;
+
+	if (as->userbuffer)
+		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+			return -EFAULT;
+	if (put_user(urb->status, &userurb->status))
+		return -EFAULT;
+	if (put_user(urb->actual_length, &userurb->actual_length))
+		return -EFAULT;
+	if (put_user(urb->error_count, &userurb->error_count))
+		return -EFAULT;
+
+	if (usb_pipeisoc(urb->pipe)) {
+		for (i = 0; i < urb->number_of_packets; i++) {
+			if (put_user(urb->iso_frame_desc[i].actual_length,
+				     &userurb->iso_frame_desc[i].actual_length))
+				return -EFAULT;
+			if (put_user(urb->iso_frame_desc[i].status,
+				     &userurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
+	}
+
 	free_async(as);
-	if (ret)
-		return ret;
-	if (put_user(addr, (void __user * __user *)arg))
+	if (put_user((u32)(u64)addr, (u32 __user *)arg))
 		return -EFAULT;
 	return 0;
 }
 
+static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
+{
+	struct async *as = reap_as(ps);
+	if (as)
+		return processcompl_compat(as, (void __user * __user *)arg);
+	if (signal_pending(current))
+		return -EINTR;
+	return -EIO;
+}
+
+static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
+{
+	struct async *as;
+
+	if (!(as = async_getcompleted(ps)))
+		return -EAGAIN;
+	return processcompl_compat(as, (void __user * __user *)arg);
+}
+
+#endif
+
 static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
 {
 	struct usbdevfs_disconnectsignal ds;
@@ -1144,7 +1230,7 @@ static int proc_ioctl (struct dev_state 
 			return -ENOMEM;
 		if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) {
 			if (copy_from_user (buf, ctrl.data, size)) {
-				kfree (buf);
+				kfree(buf);
 				return -EFAULT;
 			}
 		} else {
@@ -1153,8 +1239,7 @@ static int proc_ioctl (struct dev_state 
 	}
 
 	if (!connected(ps->dev)) {
-		if (buf)
-			kfree(buf);
+		kfree(buf);
 		return -ENODEV;
 	}
 
@@ -1216,8 +1301,8 @@ static int proc_ioctl (struct dev_state 
 			&& size > 0
 			&& copy_to_user (ctrl.data, buf, size) != 0)
 		retval = -EFAULT;
-	if (buf != NULL)
-		kfree (buf);
+
+	kfree(buf);
 	return retval;
 }
 
@@ -1302,6 +1387,27 @@ static int usbdev_ioctl(struct inode *in
 			inode->i_mtime = CURRENT_TIME;
 		break;
 
+#ifdef CONFIG_COMPAT
+
+	case USBDEVFS_SUBMITURB32:
+		snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__);
+		ret = proc_submiturb_compat(ps, p);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_REAPURB32:
+		snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__);
+		ret = proc_reapurb_compat(ps, p);
+		break;
+
+	case USBDEVFS_REAPURBNDELAY32:
+		snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__);
+		ret = proc_reapurbnonblock_compat(ps, p);
+		break;
+
+#endif
+
 	case USBDEVFS_DISCARDURB:
 		snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__);
 		ret = proc_unlinkurb(ps, p);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -28,6 +28,8 @@
 #endif
 #include <linux/usb.h>
 
+#include "usb.h"
+
 #define MAX_USB_MINORS	256
 static struct file_operations *usb_minors[MAX_USB_MINORS];
 static DEFINE_SPINLOCK(minor_lock);
@@ -66,16 +68,7 @@ static struct file_operations usb_fops =
 	.open =		usb_open,
 };
 
-static void release_usb_class_dev(struct class_device *class_dev)
-{
-	dbg("%s - %s", __FUNCTION__, class_dev->class_id);
-	kfree(class_dev);
-}
-
-static struct class usb_class = {
-	.name		= "usb",
-	.release	= &release_usb_class_dev,
-};
+static struct class_simple *usb_class;
 
 int usb_major_init(void)
 {
@@ -87,9 +80,9 @@ int usb_major_init(void)
 		goto out;
 	}
 
-	error = class_register(&usb_class);
-	if (error) {
-		err("class_register failed for usb devices");
+	usb_class = class_simple_create(THIS_MODULE, "usb");
+	if (IS_ERR(usb_class)) {
+		err("class_simple_create failed for usb devices");
 		unregister_chrdev(USB_MAJOR, "usb");
 		goto out;
 	}
@@ -102,18 +95,11 @@ out:
 
 void usb_major_cleanup(void)
 {
-	class_unregister(&usb_class);
+	class_simple_destroy(usb_class);
 	devfs_remove("usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 }
 
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
-	int minor = (int)(long)class_get_devdata(class_dev);
-	return print_dev_t(buf, MKDEV(USB_MAJOR, minor));
-}
-static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-
 /**
  * usb_register_dev - register a USB device, and ask for a minor number
  * @intf: pointer to the usb_interface that is being registered
@@ -141,7 +127,6 @@ int usb_register_dev(struct usb_interfac
 	int minor_base = class_driver->minor_base;
 	int minor = 0;
 	char name[BUS_ID_SIZE];
-	struct class_device *class_dev;
 	char *temp;
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -181,22 +166,18 @@ int usb_register_dev(struct usb_interfac
 	devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name);
 
 	/* create a usb class device for this usb interface */
-	class_dev = kmalloc(sizeof(*class_dev), GFP_KERNEL);
-	if (class_dev) {
-		memset(class_dev, 0x00, sizeof(struct class_device));
-		class_dev->class = &usb_class;
-		class_dev->dev = &intf->dev;
-
-		temp = strrchr(name, '/');
-		if (temp && (temp[1] != 0x00))
-			++temp;
-		else
-			temp = name;
-		snprintf(class_dev->class_id, BUS_ID_SIZE, "%s", temp);
-		class_set_devdata(class_dev, (void *)(long)intf->minor);
-		class_device_register(class_dev);
-		class_device_create_file(class_dev, &class_device_attr_dev);
-		intf->class_dev = class_dev;
+	temp = strrchr(name, '/');
+	if (temp && (temp[1] != 0x00))
+		++temp;
+	else
+		temp = name;
+	intf->class_dev = class_simple_device_add(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp);
+	if (IS_ERR(intf->class_dev)) {
+		spin_lock (&minor_lock);
+		usb_minors[intf->minor] = NULL;
+		spin_unlock (&minor_lock);
+		devfs_remove (name);
+		retval = PTR_ERR(intf->class_dev);
 	}
 exit:
 	return retval;
@@ -239,11 +220,8 @@ void usb_deregister_dev(struct usb_inter
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
 	devfs_remove (name);
-
-	if (intf->class_dev) {
-		class_device_unregister(intf->class_dev);
-		intf->class_dev = NULL;
-	}
+	class_simple_device_remove(MKDEV(USB_MAJOR, intf->minor));
+	intf->class_dev = NULL;
 	intf->minor = -1;
 }
 EXPORT_SYMBOL(usb_deregister_dev);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -33,7 +33,7 @@
 #include "hcd.h"
 
 
-/* PCI-based HCs are normal, but custom bus glue should be ok */
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
 
 
 /*-------------------------------------------------------------------------*/
@@ -56,11 +56,8 @@
 int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
 {
 	struct hc_driver	*driver;
-	unsigned long		resource, len;
-	void __iomem		*base;
 	struct usb_hcd		*hcd;
-	int			retval, region;
-	char			buf [8], *bufp = buf;
+	int			retval;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -70,130 +67,83 @@ int usb_hcd_pci_probe (struct pci_dev *d
 
 	if (pci_enable_device (dev) < 0)
 		return -ENODEV;
-	dev->current_state = 0;
-	dev->dev.power.power_state = 0;
+	dev->current_state = PCI_D0;
+	dev->dev.power.power_state = PMSG_ON;
 	
         if (!dev->irq) {
         	dev_err (&dev->dev,
 			"Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",
 			pci_name(dev));
    	        retval = -ENODEV;
-		goto done;
+		goto err1;
         }
-	
+
+	hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err1;
+	}
+
 	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
-		region = 0;
-		resource = pci_resource_start (dev, 0);
-		len = pci_resource_len (dev, 0);
-		if (!request_mem_region (resource, len, driver->description)) {
+		hcd->rsrc_start = pci_resource_start (dev, 0);
+		hcd->rsrc_len = pci_resource_len (dev, 0);
+		if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
 			dev_dbg (&dev->dev, "controller already in use\n");
 			retval = -EBUSY;
-			goto done;
+			goto err2;
 		}
-		base = ioremap_nocache (resource, len);
-		if (base == NULL) {
+		hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
+		if (hcd->regs == NULL) {
 			dev_dbg (&dev->dev, "error mapping memory\n");
 			retval = -EFAULT;
-clean_1:
-			release_mem_region (resource, len);
-			dev_err (&dev->dev, "init %s fail, %d\n",
-				pci_name(dev), retval);
-			goto done;
+			goto err3;
 		}
 
 	} else { 				// UHCI
-		resource = len = 0;
+		int	region;
+
 		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+			if (!(pci_resource_flags (dev, region) &
+					IORESOURCE_IO))
 				continue;
 
-			resource = pci_resource_start (dev, region);
-			len = pci_resource_len (dev, region);
-			if (request_region (resource, len,
+			hcd->rsrc_start = pci_resource_start (dev, region);
+			hcd->rsrc_len = pci_resource_len (dev, region);
+			if (request_region (hcd->rsrc_start, hcd->rsrc_len,
 					driver->description))
 				break;
 		}
 		if (region == PCI_ROM_RESOURCE) {
 			dev_dbg (&dev->dev, "no i/o regions available\n");
 			retval = -EBUSY;
-			goto done;
-		}
-		base = (void __iomem *) resource;
-	}
-
-	// driver->reset(), later on, will transfer device from
-	// control by SMM/BIOS to control by Linux (if needed)
-
-	hcd = usb_create_hcd (driver);
-	if (hcd == NULL){
-		dev_dbg (&dev->dev, "hcd alloc fail\n");
-		retval = -ENOMEM;
-clean_2:
-		if (driver->flags & HCD_MEMORY) {
-			iounmap (base);
-			goto clean_1;
-		} else {
-			release_region (resource, len);
-			dev_err (&dev->dev, "init %s fail, %d\n",
-				pci_name(dev), retval);
-			goto done;
+			goto err1;
 		}
 	}
-	// hcd zeroed everything
-	hcd->regs = base;
-	hcd->region = region;
 
-	pci_set_drvdata (dev, hcd);
-	hcd->self.bus_name = pci_name(dev);
 #ifdef CONFIG_PCI_NAMES
 	hcd->product_desc = dev->pretty_name;
 #endif
-	hcd->self.controller = &dev->dev;
-
-	if ((retval = hcd_buffer_create (hcd)) != 0) {
-clean_3:
-		pci_set_drvdata (dev, NULL);
-		usb_put_hcd (hcd);
-		goto clean_2;
-	}
-
-	dev_info (hcd->self.controller, "%s\n", hcd->product_desc);
-
-	/* till now HC has been in an indeterminate state ... */
-	if (driver->reset && (retval = driver->reset (hcd)) < 0) {
-		dev_err (hcd->self.controller, "can't reset\n");
-		goto clean_3;
-	}
 
 	pci_set_master (dev);
-#ifndef __sparc__
-	sprintf (buf, "%d", dev->irq);
-#else
-	bufp = __irq_itoa(dev->irq);
-#endif
-	retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
-				hcd->driver->description, hcd);
-	if (retval != 0) {
-		dev_err (hcd->self.controller,
-				"request interrupt %s failed\n", bufp);
-		goto clean_3;
-	}
-	hcd->irq = dev->irq;
-
-	dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
-		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
-		resource);
 
-	usb_register_bus (&hcd->self);
-
-	if ((retval = driver->start (hcd)) < 0) {
-		dev_err (hcd->self.controller, "init error %d\n", retval);
-		usb_hcd_pci_remove (dev);
-	}
-
-done:
+	retval = usb_add_hcd (hcd, dev->irq, SA_SHIRQ);
 	if (retval != 0)
-		pci_disable_device (dev);
+		goto err4;
+	return retval;
+
+ err4:
+	if (driver->flags & HCD_MEMORY) {
+		iounmap (hcd->regs);
+ err3:
+		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+	} else
+		release_region (hcd->rsrc_start, hcd->rsrc_len);
+ err2:
+	usb_put_hcd (hcd);
+ err1:
+	pci_disable_device (dev);
+	dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
 	return retval;
 } 
 EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -220,34 +170,15 @@ void usb_hcd_pci_remove (struct pci_dev 
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	dev_info (hcd->self.controller, "remove, state %x\n", hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	if (HCD_IS_RUNNING (hcd->state))
-		hcd->state = USB_STATE_QUIESCING;
-
-	dev_dbg (hcd->self.controller, "roothub graceful disconnect\n");
-	usb_disconnect (&hcd->self.root_hub);
 
-	hcd->driver->stop (hcd);
-	hcd_buffer_destroy (hcd);
-	hcd->state = USB_STATE_HALT;
-	pci_set_drvdata(dev, NULL);
-
-	free_irq (hcd->irq, hcd);
+	usb_remove_hcd (hcd);
 	if (hcd->driver->flags & HCD_MEMORY) {
 		iounmap (hcd->regs);
-		release_mem_region (pci_resource_start (dev, 0),
-			pci_resource_len (dev, 0));
+		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
 	} else {
-		release_region (pci_resource_start (dev, hcd->region),
-			pci_resource_len (dev, hcd->region));
+		release_region (hcd->rsrc_start, hcd->rsrc_len);
 	}
-
-	usb_deregister_bus (&hcd->self);
-
+	usb_put_hcd (hcd);
 	pci_disable_device(dev);
 }
 EXPORT_SYMBOL (usb_hcd_pci_remove);
@@ -255,26 +186,14 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
 
 #ifdef	CONFIG_PM
 
-static char __attribute_used__ *pci_state(u32 state)
-{
-	switch (state) {
-	case 0:		return "D0";
-	case 1:		return "D1";
-	case 2:		return "D2";
-	case 3:		return "D3hot";
-	case 4:		return "D3cold";
-	}
-	return NULL;
-}
-
 /**
  * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
  * @dev: USB Host Controller being suspended
- * @state: state that the controller is going into
+ * @message: semantics in flux
  *
  * Store this function in the HCD's struct pci_driver as suspend().
  */
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 {
 	struct usb_hcd		*hcd;
 	int			retval = 0;
@@ -282,29 +201,39 @@ int usb_hcd_pci_suspend (struct pci_dev 
 
 	hcd = pci_get_drvdata(dev);
 
+	/* FIXME until the generic PM interfaces change a lot more, this
+	 * can't use PCI D1 and D2 states.  For example, the confusion
+	 * between messages and states will need to vanish, and messages
+	 * will need to provide a target system state again.
+	 *
+	 * It'll be important to learn characteristics of the target state,
+	 * especially on embedded hardware where the HCD will often be in
+	 * charge of an external VBUS power supply and one or more clocks.
+	 * Some target system states will leave them active; others won't.
+	 * (With PCI, that's often handled by platform BIOS code.)
+	 */
+
 	/* even when the PCI layer rejects some of the PCI calls
 	 * below, HCs can try global suspend and reduce DMA traffic.
 	 * PM-sensitive HCDs may already have done this.
 	 */
 	has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-	if (state > 4)
-		state = 4;
 
 	switch (hcd->state) {
 
 	/* entry if root hub wasn't yet suspended ... from sysfs,
 	 * without autosuspend, or if USB_SUSPEND isn't configured.
 	 */
-	case USB_STATE_RUNNING:
-		hcd->state = USB_STATE_QUIESCING;
-		retval = hcd->driver->suspend (hcd, state);
+	case HC_STATE_RUNNING:
+		hcd->state = HC_STATE_QUIESCING;
+		retval = hcd->driver->suspend (hcd, message);
 		if (retval) {
 			dev_dbg (hcd->self.controller, 
 					"suspend fail, retval %d\n",
 					retval);
 			break;
 		}
-		hcd->state = HCD_STATE_SUSPENDED;
+		hcd->state = HC_STATE_SUSPENDED;
 		/* FALLTHROUGH */
 
 	/* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
@@ -314,15 +243,12 @@ int usb_hcd_pci_suspend (struct pci_dev 
 	 * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
 	 * have been called, otherwise root hub timers still run ...
 	 */
-	case HCD_STATE_SUSPENDED:
-		if (state <= dev->current_state)
-			break;
-
-		/* no DMA or IRQs except in D0 */
-		if (!dev->current_state) {
+	case HC_STATE_SUSPENDED:
+		/* no DMA or IRQs except when HC is active */
+		if (dev->current_state == PCI_D0) {
+			free_irq (hcd->irq, hcd);
 			pci_save_state (dev);
 			pci_disable_device (dev);
-			free_irq (hcd->irq, hcd);
 		}
 
 		if (!has_pci_pm) {
@@ -330,25 +256,19 @@ int usb_hcd_pci_suspend (struct pci_dev 
 			break;
 		}
 
-		/* POLICY: ignore D1/D2/D3hot differences;
-		 * we know D3hot will always work.
+		/* NOTE:  dev->current_state becomes nonzero only here, and
+		 * only for devices that support PCI PM.  Also, exiting
+		 * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
+		 * some device state (e.g. as part of clock reinit).
 		 */
-		retval = pci_set_power_state (dev, state);
-		if (retval < 0 && state < 3) {
-			retval = pci_set_power_state (dev, 3);
-			if (retval == 0)
-				state = 3;
-		}
+		retval = pci_set_power_state (dev, PCI_D3hot);
 		if (retval == 0) {
-			dev_dbg (hcd->self.controller, "--> PCI %s\n",
-					pci_state(dev->current_state));
-#ifdef	CONFIG_USB_SUSPEND
-			pci_enable_wake (dev, state, hcd->remote_wakeup);
-			pci_enable_wake (dev, 4, hcd->remote_wakeup);
-#endif
+			dev_dbg (hcd->self.controller, "--> PCI D3\n");
+			pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
+			pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
 		} else if (retval < 0) {
-			dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
-					pci_state(state), retval);
+			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
+					retval);
 			(void) usb_hcd_pci_resume (dev);
 			break;
 		}
@@ -356,13 +276,14 @@ int usb_hcd_pci_suspend (struct pci_dev 
 	default:
 		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
 			hcd->state);
+		WARN_ON(1);
 		retval = -EINVAL;
 		break;
 	}
 
 	/* update power_state **ONLY** to make sysfs happier */
 	if (retval == 0)
-		dev->dev.power.power_state = state;
+		dev->dev.power.power_state = message;
 	return retval;
 }
 EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -377,42 +298,83 @@ int usb_hcd_pci_resume (struct pci_dev *
 {
 	struct usb_hcd		*hcd;
 	int			retval;
-	int			has_pci_pm;
 
 	hcd = pci_get_drvdata(dev);
-	if (hcd->state != HCD_STATE_SUSPENDED) {
+	if (hcd->state != HC_STATE_SUSPENDED) {
 		dev_dbg (hcd->self.controller, 
 				"can't resume, not suspended!\n");
 		return 0;
 	}
-	has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
 
-	/* D3cold resume isn't usually reported this way... */
-	dev_dbg(hcd->self.controller, "resume from PCI %s%s\n",
-			pci_state(dev->current_state),
-			has_pci_pm ? "" : " (legacy)");
-
-	hcd->state = USB_STATE_RESUMING;
-
-	if (has_pci_pm)
-		pci_set_power_state (dev, 0);
-	dev->dev.power.power_state = 0;
+	/* NOTE:  chip docs cover clean "real suspend" cases (what Linux
+	 * calls "standby", "suspend to RAM", and so on).  There are also
+	 * dirty cases when swsusp fakes a suspend in "shutdown" mode.
+	 */
+	if (dev->current_state != PCI_D0) {
+#ifdef	DEBUG
+		int	pci_pm;
+		u16	pmcr;
+
+		pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+		pci_read_config_word(dev, pci_pm + PCI_PM_CTRL, &pmcr);
+		pmcr &= PCI_PM_CTRL_STATE_MASK;
+		if (pmcr) {
+			/* Clean case:  power to USB and to HC registers was
+			 * maintained; remote wakeup is easy.
+			 */
+			dev_dbg(hcd->self.controller, "resume from PCI D%d\n",
+					pmcr);
+		} else {
+			/* Clean:  HC lost Vcc power, D0 uninitialized
+			 *   + Vaux may have preserved port and transceiver
+			 *     state ... for remote wakeup from D3cold
+			 *   + or not; HCD must reinit + re-enumerate
+			 *
+			 * Dirty: D0 semi-initialized cases with swsusp
+			 *   + after BIOS init
+			 *   + after Linux init (HCD statically linked)
+			 */
+			dev_dbg(hcd->self.controller,
+				"PCI D0, from previous PCI D%d\n",
+				dev->current_state);
+		}
+#endif
+		pci_enable_wake (dev, dev->current_state, 0);
+		pci_enable_wake (dev, PCI_D3cold, 0);
+	} else {
+		/* Same basic cases: clean (powered/not), dirty */
+		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
+	}
+
+	/* NOTE:  the PCI API itself is asymmetric here.  We don't need to
+	 * pci_set_power_state(PCI_D0) since that's part of re-enabling;
+	 * but that won't re-enable bus mastering.  Yet pci_disable_device()
+	 * explicitly disables bus mastering...
+	 */
+	retval = pci_enable_device (dev);
+	if (retval < 0) {
+		dev_err (hcd->self.controller,
+			"can't re-enable after resume, %d!\n", retval);
+		return retval;
+	}
+	pci_set_master (dev);
+	pci_restore_state (dev);
+
+	dev->dev.power.power_state = PMSG_ON;
+
+	hcd->state = HC_STATE_RESUMING;
+	hcd->saw_irq = 0;
 	retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
-				hcd->driver->description, hcd);
+				hcd->irq_descr, hcd);
 	if (retval < 0) {
 		dev_err (hcd->self.controller,
 			"can't restore IRQ after resume!\n");
+		usb_hc_died (hcd);
 		return retval;
 	}
-	hcd->saw_irq = 0;
-	pci_restore_state (dev);
-#ifdef	CONFIG_USB_SUSPEND
-	pci_enable_wake (dev, dev->current_state, 0);
-	pci_enable_wake (dev, 4, 0);
-#endif
 
 	retval = hcd->driver->resume (hcd);
-	if (!HCD_IS_RUNNING (hcd->state)) {
+	if (!HC_IS_RUNNING (hcd->state)) {
 		dev_dbg (hcd->self.controller, 
 				"resume fail, retval %d\n", retval);
 		usb_hc_died (hcd);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -46,6 +46,7 @@
 
 #include "usb.h"
 #include "hcd.h"
+#include "hub.h"
 
 
 // #define USB_BANDWIDTH_MESSAGES
@@ -87,6 +88,7 @@
 
 /* host controllers we manage */
 LIST_HEAD (usb_bus_list);
+EXPORT_SYMBOL_GPL (usb_bus_list);
 
 /* used when allocating bus numbers */
 #define USB_MAXBUS		64
@@ -97,6 +99,10 @@ static struct usb_busmap busmap;
 
 /* used when updating list of hcds */
 DECLARE_MUTEX (usb_bus_list_lock);	/* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_list_lock);
+
+/* used for controlling access to virtual root hubs */
+static DEFINE_SPINLOCK(hcd_root_hub_lock);
 
 /* used when updating hcd data */
 static DEFINE_SPINLOCK(hcd_data_lock);
@@ -272,6 +278,10 @@ static int ascii2utf (char *s, u8 *utf, 
 		*utf++ = *s++;
 		*utf++ = 0;
 	}
+	if (utfmax > 0) {
+		*utf = *s;
+		++retval;
+	}
 	return retval;
 }
 
@@ -296,30 +306,40 @@ static int rh_string (
 
 	// language ids
 	if (id == 0) {
-		*data++ = 4; *data++ = 3;	/* 4 bytes string data */
-		*data++ = 0x09; *data++ = 0x04;	/* MSFT-speak for "en-us" */
-		return 4;
+		buf[0] = 4;    buf[1] = 3;	/* 4 bytes string data */
+		buf[2] = 0x09; buf[3] = 0x04;	/* MSFT-speak for "en-us" */
+		len = min (len, 4);
+		memcpy (data, buf, len);
+		return len;
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, hcd->self.bus_name);
+		strlcpy (buf, hcd->self.bus_name, sizeof buf);
 
 	// product description
 	} else if (id == 2) {
-                strcpy (buf, hcd->product_desc);
+		strlcpy (buf, hcd->product_desc, sizeof buf);
 
  	// id 3 == vendor description
 	} else if (id == 3) {
-                sprintf (buf, "%s %s %s",  system_utsname.sysname,
+		snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname,
 			system_utsname.release, hcd->driver->description);
 
 	// unsupported IDs --> "protocol stall"
 	} else
-	    return 0;
+		return -EPIPE;
 
-	data [0] = 2 * (strlen (buf) + 1);
-	data [1] = 3;	/* type == string */
-	return 2 + ascii2utf (buf, data + 2, len - 2);
+	switch (len) {		/* All cases fall through */
+	default:
+		len = 2 + ascii2utf (buf, data + 2, len - 2);
+	case 2:
+		data [1] = 3;	/* type == string */
+	case 1:
+		data [0] = 2 * (strlen (buf) + 1);
+	case 0:
+		;		/* Compiler wants a statement here */
+	}
+	return len;
 }
 
 
@@ -328,11 +348,14 @@ static int rh_call_control (struct usb_h
 {
 	struct usb_ctrlrequest *cmd;
  	u16		typeReq, wValue, wIndex, wLength;
-	const u8	*bufp = NULL;
 	u8		*ubuf = urb->transfer_buffer;
+	u8		tbuf [sizeof (struct usb_hub_descriptor)];
+	const u8	*bufp = tbuf;
 	int		len = 0;
 	int		patch_wakeup = 0;
 	unsigned long	flags;
+	int		status = 0;
+	int		n;
 
 	cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
@@ -343,17 +366,16 @@ static int rh_call_control (struct usb_h
 	if (wLength > urb->transfer_buffer_length)
 		goto error;
 
-	/* set up for success */
-	urb->status = 0;
-	urb->actual_length = wLength;
+	urb->actual_length = 0;
 	switch (typeReq) {
 
 	/* DEVICE REQUESTS */
 
 	case DeviceRequest | USB_REQ_GET_STATUS:
-		ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+		tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
 				| (1 << USB_DEVICE_SELF_POWERED);
-		ubuf [1] = 0;
+		tbuf [1] = 0;
+		len = 2;
 		break;
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 		if (wValue == USB_DEVICE_REMOTE_WAKEUP)
@@ -368,7 +390,8 @@ static int rh_call_control (struct usb_h
 			goto error;
 		break;
 	case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-		ubuf [0] = 1;
+		tbuf [0] = 1;
+		len = 1;
 			/* FALLTHROUGH */
 	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
 		break;
@@ -395,16 +418,18 @@ static int rh_call_control (struct usb_h
 				patch_wakeup = 1;
 			break;
 		case USB_DT_STRING << 8:
-			urb->actual_length = rh_string (
-				wValue & 0xff, hcd,
-				ubuf, wLength);
+			n = rh_string (wValue & 0xff, hcd, ubuf, wLength);
+			if (n < 0)
+				goto error;
+			urb->actual_length = n;
 			break;
 		default:
 			goto error;
 		}
 		break;
 	case DeviceRequest | USB_REQ_GET_INTERFACE:
-		ubuf [0] = 0;
+		tbuf [0] = 0;
+		len = 1;
 			/* FALLTHROUGH */
 	case DeviceOutRequest | USB_REQ_SET_INTERFACE:
 		break;
@@ -420,8 +445,9 @@ static int rh_call_control (struct usb_h
 
 	case EndpointRequest | USB_REQ_GET_STATUS:
 		// ENDPOINT_HALT flag
-		ubuf [0] = 0;
-		ubuf [1] = 0;
+		tbuf [0] = 0;
+		tbuf [1] = 0;
+		len = 2;
 			/* FALLTHROUGH */
 	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
 	case EndpointOutRequest | USB_REQ_SET_FEATURE:
@@ -432,20 +458,31 @@ static int rh_call_control (struct usb_h
 
 	default:
 		/* non-generic request */
-		if (HCD_IS_SUSPENDED (hcd->state))
-			urb->status = -EAGAIN;
-		else
-			urb->status = hcd->driver->hub_control (hcd,
+		if (HC_IS_SUSPENDED (hcd->state))
+			status = -EAGAIN;
+		else {
+			switch (typeReq) {
+			case GetHubStatus:
+			case GetPortStatus:
+				len = 4;
+				break;
+			case GetHubDescriptor:
+				len = sizeof (struct usb_hub_descriptor);
+				break;
+			}
+			status = hcd->driver->hub_control (hcd,
 				typeReq, wValue, wIndex,
-				ubuf, wLength);
+				tbuf, wLength);
+		}
 		break;
 error:
 		/* "protocol stall" on error */
-		urb->status = -EPIPE;
+		status = -EPIPE;
 	}
-	if (urb->status) {
-		urb->actual_length = 0;
-		if (urb->status != -EPIPE) {
+
+	if (status) {
+		len = 0;
+		if (status != -EPIPE) {
 			dev_dbg (hcd->self.controller,
 				"CTRL: TypeReq=0x%x val=0x%x "
 				"idx=0x%x len=%d ==> %d\n",
@@ -453,7 +490,7 @@ error:
 				wLength, urb->status);
 		}
 	}
-	if (bufp) {
+	if (len) {
 		if (urb->transfer_buffer_length < len)
 			len = urb->transfer_buffer_length;
 		urb->actual_length = len;
@@ -461,13 +498,19 @@ error:
 		memcpy (ubuf, bufp, len);
 
 		/* report whether RH hardware supports remote wakeup */
-		if (patch_wakeup)
+		if (patch_wakeup &&
+				len > offsetof (struct usb_config_descriptor,
+						bmAttributes))
 			((struct usb_config_descriptor *)ubuf)->bmAttributes
 				|= USB_CONFIG_ATT_WAKEUP;
 	}
 
 	/* any errors get returned through the urb completion */
 	local_irq_save (flags);
+	spin_lock (&urb->lock);
+	if (urb->status == -EINPROGRESS)
+		urb->status = status;
+	spin_unlock (&urb->lock);
 	usb_hcd_giveback_urb (hcd, urb, NULL);
 	local_irq_restore (flags);
 	return 0;
@@ -661,7 +704,7 @@ void usb_host_cleanup(void)
  * This code is used to initialize a usb_bus structure, memory for which is
  * separately managed.
  */
-void usb_bus_init (struct usb_bus *bus)
+static void usb_bus_init (struct usb_bus *bus)
 {
 	memset (&bus->devmap, 0, sizeof(struct usb_devmap));
 
@@ -679,7 +722,6 @@ void usb_bus_init (struct usb_bus *bus)
 	class_device_initialize(&bus->class_dev);
 	bus->class_dev.class = &usb_host_class;
 }
-EXPORT_SYMBOL (usb_bus_init);
 
 /**
  * usb_alloc_bus - creates a new USB host controller structure
@@ -705,7 +747,6 @@ struct usb_bus *usb_alloc_bus (struct us
 	bus->op = op;
 	return bus;
 }
-EXPORT_SYMBOL (usb_alloc_bus);
 
 /*-------------------------------------------------------------------------*/
 
@@ -717,7 +758,7 @@ EXPORT_SYMBOL (usb_alloc_bus);
  * Assigns a bus number, and links the controller into usbcore data
  * structures so that it can be seen by scanning the bus list.
  */
-int usb_register_bus(struct usb_bus *bus)
+static int usb_register_bus(struct usb_bus *bus)
 {
 	int busnum;
 	int retval;
@@ -747,11 +788,11 @@ int usb_register_bus(struct usb_bus *bus
 	up (&usb_bus_list_lock);
 
 	usbfs_add_bus (bus);
+	usbmon_notify_bus_add (bus);
 
 	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
 	return 0;
 }
-EXPORT_SYMBOL (usb_register_bus);
 
 /**
  * usb_deregister_bus - deregisters the USB host controller
@@ -761,7 +802,7 @@ EXPORT_SYMBOL (usb_register_bus);
  * Recycles the bus number, and unlinks the controller from usbcore data
  * structures so that it won't be seen by scanning the bus list.
  */
-void usb_deregister_bus (struct usb_bus *bus)
+static void usb_deregister_bus (struct usb_bus *bus)
 {
 	dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);
 
@@ -774,18 +815,18 @@ void usb_deregister_bus (struct usb_bus 
 	list_del (&bus->bus_list);
 	up (&usb_bus_list_lock);
 
+	usbmon_notify_bus_remove (bus);
 	usbfs_remove_bus (bus);
 
 	clear_bit (bus->busnum, busmap.busmap);
 
-	class_device_unregister(&bus->class_dev);
+	class_device_del(&bus->class_dev);
 }
-EXPORT_SYMBOL (usb_deregister_bus);
 
 /**
- * usb_register_root_hub - called by HCD to register its root hub 
+ * usb_hcd_register_root_hub - called by HCD to register its root hub 
  * @usb_dev: the usb root hub device to be registered.
- * @parent_dev: the parent device of this root hub.
+ * @hcd: host controller for this root hub
  *
  * The USB host controller calls this function to register the root hub
  * properly with the USB subsystem.  It sets up the device properly in
@@ -793,11 +834,20 @@ EXPORT_SYMBOL (usb_deregister_bus);
  * then calls usb_new_device() to register the usb device.  It also
  * assigns the root hub's USB address (always 1).
  */
-int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
+int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
 {
+	struct device *parent_dev = hcd->self.controller;
 	const int devnum = 1;
 	int retval;
 
+	/* hcd->driver->start() reported can_wakeup, probably with
+	 * assistance from board's boot firmware.
+	 * NOTE:  normal devices won't enable wakeup by default.
+	 */
+	if (hcd->can_wakeup)
+		dev_dbg (parent_dev, "supports USB remote wakeup\n");
+	hcd->remote_wakeup = hcd->can_wakeup;
+
 	usb_dev->devnum = devnum;
 	usb_dev->bus->devnum_next = devnum + 1;
 	memset (&usb_dev->bus->devmap.devicemap, 0,
@@ -827,9 +877,20 @@ int usb_register_root_hub (struct usb_de
 				usb_dev->dev.bus_id, retval);
 	}
 	up (&usb_bus_list_lock);
+
+	if (retval == 0) {
+		spin_lock_irq (&hcd_root_hub_lock);
+		hcd->rh_registered = 1;
+		spin_unlock_irq (&hcd_root_hub_lock);
+
+		/* Did the HC die before the root hub was registered? */
+		if (hcd->state == HC_STATE_HALT)
+			usb_hc_died (hcd);	/* This time clean up */
+	}
+
 	return retval;
 }
-EXPORT_SYMBOL (usb_register_root_hub);
+EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
 
 
 /*-------------------------------------------------------------------------*/
@@ -1049,19 +1110,10 @@ static int hcd_submit_urb (struct urb *u
 	struct usb_host_endpoint *ep;
 	unsigned long		flags;
 
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (!hcd || !ep)
+	if (!hcd)
 		return -ENODEV;
 
-	/*
-	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
-	 * as simple as possible.
-	 */
-
-	// NOTE:  a generic device/urb monitoring hook would go here.
-	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
-	// It would catch submission paths for all urbs.
+	usbmon_urb_submit(&hcd->self, urb);
 
 	/*
 	 * Atomically queue the urb,  first to our records, then to the HCD.
@@ -1072,11 +1124,15 @@ static int hcd_submit_urb (struct urb *u
 	// FIXME:  verify that quiescing hc works right (RH cleans up)
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
-	if (unlikely (urb->reject))
+	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
+			[usb_pipeendpoint(urb->pipe)];
+	if (unlikely (!ep))
+		status = -ENOENT;
+	else if (unlikely (urb->reject))
 		status = -EPERM;
 	else switch (hcd->state) {
-	case USB_STATE_RUNNING:
-	case USB_STATE_RESUMING:
+	case HC_STATE_RUNNING:
+	case HC_STATE_RESUMING:
 		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
@@ -1088,6 +1144,7 @@ static int hcd_submit_urb (struct urb *u
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
 	if (status) {
 		INIT_LIST_HEAD (&urb->urb_list);
+		usbmon_urb_submit_error(&hcd->self, urb, status);
 		return status;
 	}
 
@@ -1104,8 +1161,6 @@ static int hcd_submit_urb (struct urb *u
 		 * valid and usb_buffer_{sync,unmap}() not be needed, since
 		 * they could clobber root hub response data.
 		 */
-		urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
-					| URB_NO_SETUP_DMA_MAP);
 		status = rh_urb_enqueue (hcd, urb);
 		goto done;
 	}
@@ -1140,6 +1195,7 @@ done:
 		if (urb->reject)
 			wake_up (&usb_kill_urb_queue);
 		usb_put_urb (urb);
+		usbmon_urb_submit_error(&hcd->self, urb, status);
 	}
 	return status;
 }
@@ -1150,7 +1206,7 @@ done:
 static int hcd_get_frame_number (struct usb_device *udev)
 {
 	struct usb_hcd	*hcd = (struct usb_hcd *)udev->bus->hcpriv;
-	if (!HCD_IS_RUNNING (hcd->state))
+	if (!HC_IS_RUNNING (hcd->state))
 		return -ESHUTDOWN;
 	return hcd->driver->get_frame_number (hcd);
 }
@@ -1232,7 +1288,7 @@ static int hcd_unlink_urb (struct urb *u
 	 * halted ~= no unlink handshake is needed
 	 * suspended, resuming == should never happen
 	 */
-	WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
+	WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
 
 	/* insist the urb is still queued */
 	list_for_each(tmp, &ep->urb_list) {
@@ -1299,7 +1355,7 @@ hcd_endpoint_disable (struct usb_device 
 
 	hcd = udev->bus->hcpriv;
 
-	WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
+	WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
 
 	local_irq_disable ();
 
@@ -1386,7 +1442,31 @@ static int hcd_hub_resume (struct usb_bu
 	return 0;
 }
 
+/**
+ * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
+ * @hcd: host controller for this root hub
+ *
+ * The USB host controller calls this function when its root hub is
+ * suspended (with the remote wakeup feature enabled) and a remote
+ * wakeup request is received.  It queues a request for khubd to
+ * resume the root hub.
+ */
+void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave (&hcd_root_hub_lock, flags);
+	if (hcd->rh_registered)
+		usb_resume_root_hub (hcd->self.root_hub);
+	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+}
+
+#else
+void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
+{
+}
 #endif
+EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1395,7 +1475,7 @@ static int hcd_hub_resume (struct usb_bu
 /**
  * usb_bus_start_enum - start immediate enumeration (for OTG)
  * @bus: the bus (must use hcd framework)
- * @port: 1-based number of port; usually bus->otg_port
+ * @port_num: 1-based number of port; usually bus->otg_port
  * Context: in_interrupt()
  *
  * Starts enumeration, with an immediate reset followed later by
@@ -1462,14 +1542,13 @@ static struct usb_operations usb_hcd_ope
  */
 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
 {
-	urb_unlink (urb);
+	int at_root_hub;
 
-	// NOTE:  a generic device/urb monitoring hook would go here.
-	// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
-	// It would catch exit/unlink paths for all urbs.
+	at_root_hub = (urb->dev == hcd->self.root_hub);
+	urb_unlink (urb);
 
 	/* lower level hcd code should use *_dma exclusively */
-	if (hcd->self.controller->dma_mask) {
+	if (hcd->self.controller->dma_mask && !at_root_hub) {
 		if (usb_pipecontrol (urb->pipe)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -1485,6 +1564,7 @@ void usb_hcd_giveback_urb (struct usb_hc
 					    : DMA_TO_DEVICE);
 	}
 
+	usbmon_urb_complete (&hcd->self, urb);
 	/* pass ownership to the completion handler */
 	urb->complete (urb, regs);
 	atomic_dec (&urb->use_count);
@@ -1499,29 +1579,27 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
 /**
  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
  * @irq: the IRQ being raised
- * @__hcd: pointer to the HCD whose IRQ is beinng signaled
+ * @__hcd: pointer to the HCD whose IRQ is being signaled
  * @r: saved hardware registers
  *
- * When registering a USB bus through the HCD framework code, use this
- * to handle interrupts.  The PCI glue layer does so automatically; only
- * bus glue for non-PCI system busses will need to use this.
+ * If the controller isn't HALTed, calls the driver's irq handler.
+ * Checks whether the controller is now dead.
  */
 irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
 {
 	struct usb_hcd		*hcd = __hcd;
 	int			start = hcd->state;
 
-	if (start == USB_STATE_HALT)
+	if (start == HC_STATE_HALT)
 		return IRQ_NONE;
 	if (hcd->driver->irq (hcd, r) == IRQ_NONE)
 		return IRQ_NONE;
 
 	hcd->saw_irq = 1;
-	if (hcd->state != start && hcd->state == USB_STATE_HALT)
+	if (hcd->state != start && hcd->state == HC_STATE_HALT)
 		usb_hc_died (hcd);
 	return IRQ_HANDLED;
 }
-EXPORT_SYMBOL (usb_hcd_irq);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1535,12 +1613,21 @@ EXPORT_SYMBOL (usb_hcd_irq);
  */
 void usb_hc_died (struct usb_hcd *hcd)
 {
+	unsigned long flags;
+
 	dev_err (hcd->self.controller, "HC died; cleaning up\n");
 
-	/* make khubd clean up old urbs and devices */
-	usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED);
-	mod_timer(&hcd->rh_timer, jiffies);
+	spin_lock_irqsave (&hcd_root_hub_lock, flags);
+	if (hcd->rh_registered) {
+
+		/* make khubd clean up old urbs and devices */
+		usb_set_device_state (hcd->self.root_hub,
+				USB_STATE_NOTATTACHED);
+		usb_kick_khubd (hcd->self.root_hub);
+	}
+	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
+EXPORT_SYMBOL_GPL (usb_hc_died);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1555,6 +1642,8 @@ static void hcd_release (struct usb_bus 
 /**
  * usb_create_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
  * Context: !in_interrupt()
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
@@ -1563,25 +1652,30 @@ static void hcd_release (struct usb_bus 
  *
  * If memory is unavailable, returns NULL.
  */
-struct usb_hcd *usb_create_hcd (const struct hc_driver *driver)
+struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+		struct device *dev, char *bus_name)
 {
 	struct usb_hcd *hcd;
 
 	hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
-	if (!hcd)
+	if (!hcd) {
+		dev_dbg (dev, "hcd alloc failed\n");
 		return NULL;
+	}
+	dev_set_drvdata(dev, hcd);
 
 	usb_bus_init(&hcd->self);
 	hcd->self.op = &usb_hcd_operations;
 	hcd->self.hcpriv = hcd;
 	hcd->self.release = &hcd_release;
+	hcd->self.controller = dev;
+	hcd->self.bus_name = bus_name;
 
 	init_timer(&hcd->rh_timer);
 
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 			"USB Host Controller";
-	hcd->state = USB_STATE_HALT;
 
 	return hcd;
 }
@@ -1589,6 +1683,158 @@ EXPORT_SYMBOL (usb_create_hcd);
 
 void usb_put_hcd (struct usb_hcd *hcd)
 {
+	dev_set_drvdata(hcd->self.controller, NULL);
 	usb_bus_put(&hcd->self);
 }
 EXPORT_SYMBOL (usb_put_hcd);
+
+/**
+ * usb_add_hcd - finish generic HCD structure initialization and register
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ *
+ * Finish the remaining parts of generic HCD initialization: allocate the
+ * buffers of consistent memory, register the bus, request the IRQ line,
+ * and call the driver's reset() and start() routines.
+ */
+int usb_add_hcd(struct usb_hcd *hcd,
+		unsigned int irqnum, unsigned long irqflags)
+{
+	int	retval;
+
+	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+
+	/* till now HC has been in an indeterminate state ... */
+	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+		dev_err(hcd->self.controller, "can't reset\n");
+		return retval;
+	}
+
+	if ((retval = hcd_buffer_create(hcd)) != 0) {
+		dev_dbg(hcd->self.controller, "pool alloc failed\n");
+		return retval;
+	}
+
+	if ((retval = usb_register_bus(&hcd->self)) < 0)
+		goto err1;
+
+	if (hcd->driver->irq) {
+		char	buf[8], *bufp = buf;
+
+#ifdef __sparc__
+		bufp = __irq_itoa(irqnum);
+#else
+		sprintf(buf, "%d", irqnum);
+#endif
+
+		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+				hcd->driver->description, hcd->self.busnum);
+		if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
+				hcd->irq_descr, hcd)) != 0) {
+			dev_err(hcd->self.controller,
+					"request interrupt %s failed\n", bufp);
+			goto err2;
+		}
+		hcd->irq = irqnum;
+		dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
+				(hcd->driver->flags & HCD_MEMORY) ?
+					"io mem" : "io base",
+					(unsigned long long)hcd->rsrc_start);
+	} else {
+		hcd->irq = -1;
+		if (hcd->rsrc_start)
+			dev_info(hcd->self.controller, "%s 0x%08llx\n",
+					(hcd->driver->flags & HCD_MEMORY) ?
+					"io mem" : "io base",
+					(unsigned long long)hcd->rsrc_start);
+	}
+
+	if ((retval = hcd->driver->start(hcd)) < 0) {
+		dev_err(hcd->self.controller, "startup error %d\n", retval);
+		goto err3;
+	}
+
+	return retval;
+
+ err3:
+	if (hcd->irq >= 0)
+		free_irq(irqnum, hcd);
+ err2:
+	usb_deregister_bus(&hcd->self);
+ err1:
+	hcd_buffer_destroy(hcd);
+	return retval;
+} 
+EXPORT_SYMBOL (usb_add_hcd);
+
+/**
+ * usb_remove_hcd - shutdown processing for generic HCDs
+ * @hcd: the usb_hcd structure to remove
+ * Context: !in_interrupt()
+ *
+ * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() method.
+ */
+void usb_remove_hcd(struct usb_hcd *hcd)
+{
+	dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
+
+	if (HC_IS_RUNNING (hcd->state))
+		hcd->state = HC_STATE_QUIESCING;
+
+	dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
+	spin_lock_irq (&hcd_root_hub_lock);
+	hcd->rh_registered = 0;
+	spin_unlock_irq (&hcd_root_hub_lock);
+	usb_disconnect(&hcd->self.root_hub);
+
+	hcd->driver->stop(hcd);
+	hcd->state = HC_STATE_HALT;
+
+	if (hcd->irq >= 0)
+		free_irq(hcd->irq, hcd);
+	usb_deregister_bus(&hcd->self);
+	hcd_buffer_destroy(hcd);
+}
+EXPORT_SYMBOL (usb_remove_hcd);
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+
+struct usb_mon_operations *mon_ops;
+
+/*
+ * The registration is unlocked.
+ * We do it this way because we do not want to lock in hot paths.
+ *
+ * Notice that the code is minimally error-proof. Because usbmon needs
+ * symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
+ */
+ 
+int usb_mon_register (struct usb_mon_operations *ops)
+{
+
+	if (mon_ops)
+		return -EBUSY;
+
+	mon_ops = ops;
+	mb();
+	return 0;
+}
+EXPORT_SYMBOL_GPL (usb_mon_register);
+
+void usb_mon_deregister (void)
+{
+
+	if (mon_ops == NULL) {
+		printk(KERN_ERR "USB: monitor was not registered\n");
+		return;
+	}
+	mon_ops = NULL;
+	mb();
+}
+EXPORT_SYMBOL_GPL (usb_mon_deregister);
+
+#endif /* CONFIG_USB_MON */
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -63,6 +63,7 @@ struct usb_hcd {	/* usb_bus.hcpriv point
 	struct usb_bus		self;		/* hcd is-a bus */
 
 	const char		*product_desc;	/* product/vendor string */
+	char			irq_descr[24];	/* driver + bus # */
 
 	struct timer_list	rh_timer;	/* drives root hub */
 
@@ -73,12 +74,12 @@ struct usb_hcd {	/* usb_bus.hcpriv point
 	unsigned		saw_irq : 1;
 	unsigned		can_wakeup:1;	/* hw supports wakeup? */
 	unsigned		remote_wakeup:1;/* sw should use wakeup? */
+	unsigned		rh_registered:1;/* is root hub registered? */
+
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
-
-#ifdef	CONFIG_PCI
-	int			region;		/* pci region for regs */
-#endif
+	u64			rsrc_start;	/* memory/io resource start */
+	u64			rsrc_len;	/* memory/io resource length */
 
 #define HCD_BUFFER_POOLS	4
 	struct dma_pool		*pool [HCD_BUFFER_POOLS];
@@ -88,14 +89,14 @@ struct usb_hcd {	/* usb_bus.hcpriv point
 #	define	__SUSPEND		0x04
 #	define	__TRANSIENT		0x80
 
-#	define	USB_STATE_HALT		0
-#	define	USB_STATE_RUNNING	(__ACTIVE)
-#	define	USB_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
-#	define	USB_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
-#	define	HCD_STATE_SUSPENDED	(__SUSPEND)
+#	define	HC_STATE_HALT		0
+#	define	HC_STATE_RUNNING	(__ACTIVE)
+#	define	HC_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
+#	define	HC_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
+#	define	HC_STATE_SUSPENDED	(__SUSPEND)
 
-#define	HCD_IS_RUNNING(state) ((state) & __ACTIVE)
-#define	HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+#define	HC_IS_RUNNING(state) ((state) & __ACTIVE)
+#define	HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
 
 	/* more shared queuing code would be good; it should support
 	 * smarter scheduling, handle transaction translators, etc;
@@ -176,7 +177,7 @@ struct hc_driver {
 	 * a whole, not just the root hub; they're for bus glue.
 	 */
 	/* called after all devices were suspended */
-	int	(*suspend) (struct usb_hcd *hcd, u32 state);
+	int	(*suspend) (struct usb_hcd *hcd, pm_message_t message);
 
 	/* called before any devices get resumed */
 	int	(*resume) (struct usb_hcd *hcd);
@@ -209,11 +210,13 @@ struct hc_driver {
 };
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
-extern void usb_bus_init (struct usb_bus *bus);
 
-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver);
+extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+		struct device *dev, char *bus_name);
 extern void usb_put_hcd (struct usb_hcd *hcd);
-
+extern int usb_add_hcd(struct usb_hcd *hcd,
+		unsigned int irqnum, unsigned long irqflags);
+extern void usb_remove_hcd(struct usb_hcd *hcd);
 
 #ifdef CONFIG_PCI
 struct pci_dev;
@@ -223,7 +226,7 @@ extern int usb_hcd_pci_probe (struct pci
 extern void usb_hcd_pci_remove (struct pci_dev *dev);
 
 #ifdef CONFIG_PM
-extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
 extern int usb_hcd_pci_resume (struct pci_dev *dev);
 #endif /* CONFIG_PM */
 
@@ -338,25 +341,10 @@ extern long usb_calc_bus_time (int speed
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 
-extern int usb_register_bus (struct usb_bus *);
-extern void usb_deregister_bus (struct usb_bus *);
-
-extern int usb_register_root_hub (struct usb_device *usb_dev,
-		struct device *parent_dev);
+extern int usb_hcd_register_root_hub (struct usb_device *usb_dev,
+		struct usb_hcd *hcd);
 
-static inline int hcd_register_root (struct usb_device *usb_dev,
-		struct usb_hcd *hcd)
-{
-	/* hcd->driver->start() reported can_wakeup, probably with
-	 * assistance from board's boot firmware.
-	 * NOTE:  normal devices won't enable wakeup by default.
-	 */
-	if (hcd->can_wakeup)
-		dev_dbg (hcd->self.controller, "supports USB remote wakeup\n");
-	hcd->remote_wakeup = hcd->can_wakeup;
-
-	return usb_register_root_hub (usb_dev, hcd->self.controller);
-}
+extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
 
 extern void usb_set_device_state(struct usb_device *udev,
 		enum usb_device_state new_state);
@@ -411,6 +399,66 @@ static inline void usbfs_cleanup(void) {
 
 /*-------------------------------------------------------------------------*/
 
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+
+struct usb_mon_operations {
+	void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
+	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
+	void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
+	void (*bus_add)(struct usb_bus *bus);
+	void (*bus_remove)(struct usb_bus *bus);
+};
+
+extern struct usb_mon_operations *mon_ops;
+
+static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
+{
+	if (bus->monitored)
+		(*mon_ops->urb_submit)(bus, urb);
+}
+
+static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
+    int error)
+{
+	if (bus->monitored)
+		(*mon_ops->urb_submit_error)(bus, urb, error);
+}
+
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+{
+	if (bus->monitored)
+		(*mon_ops->urb_complete)(bus, urb);
+}
+ 
+static inline void usbmon_notify_bus_add(struct usb_bus *bus)
+{
+	if (mon_ops)
+		(*mon_ops->bus_add)(bus);
+}
+
+static inline void usbmon_notify_bus_remove(struct usb_bus *bus)
+{
+	if (mon_ops)
+		(*mon_ops->bus_remove)(bus);
+}
+
+int usb_mon_register(struct usb_mon_operations *ops);
+void usb_mon_deregister(void);
+
+#else
+
+static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
+    int error) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_notify_bus_add(struct usb_bus *bus) {}
+static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {}
+
+#endif /* CONFIG_USB_MON */
+
+/*-------------------------------------------------------------------------*/
+
 /* 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
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -74,7 +74,7 @@ module_param(old_scheme_first, bool, S_I
 MODULE_PARM_DESC(old_scheme_first,
 		 "start with the old device initialization scheme");
 
-static int use_both_schemes = 0;
+static int use_both_schemes = 1;
 module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(use_both_schemes,
 		"try the other device initialization scheme if the "
@@ -108,7 +108,7 @@ static int get_hub_descriptor(struct usb
 		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
 			USB_DT_HUB << 8, 0, data, size,
-			HZ * USB_CTRL_GET_TIMEOUT);
+			USB_CTRL_GET_TIMEOUT);
 		if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
 			return ret;
 	}
@@ -121,7 +121,7 @@ static int get_hub_descriptor(struct usb
 static int clear_hub_feature(struct usb_device *hdev, int feature)
 {
 	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
+		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000);
 }
 
 /*
@@ -131,7 +131,7 @@ static int clear_port_feature(struct usb
 {
 	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
-		NULL, 0, HZ);
+		NULL, 0, 1000);
 }
 
 /*
@@ -141,7 +141,7 @@ static int set_port_feature(struct usb_d
 {
 	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
-		NULL, 0, HZ);
+		NULL, 0, 1000);
 }
 
 /*
@@ -242,7 +242,7 @@ static void led_work (void *__hub)
 }
 
 /* use a short timeout for hub/port status fetches */
-#define	USB_STS_TIMEOUT		1
+#define	USB_STS_TIMEOUT		1000
 #define	USB_STS_RETRIES		5
 
 /*
@@ -256,7 +256,7 @@ static int get_hub_status(struct usb_dev
 	for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
 		status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
-			data, sizeof(*data), HZ * USB_STS_TIMEOUT);
+			data, sizeof(*data), USB_STS_TIMEOUT);
 	}
 	return status;
 }
@@ -272,7 +272,7 @@ static int get_port_status(struct usb_de
 	for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
 		status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
-			data, sizeof(*data), HZ * USB_STS_TIMEOUT);
+			data, sizeof(*data), USB_STS_TIMEOUT);
 	}
 	return status;
 }
@@ -289,6 +289,11 @@ static void kick_khubd(struct usb_hub *h
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
+void usb_kick_khubd(struct usb_device *hdev)
+{
+	kick_khubd(hdev_to_hub(hdev));
+}
+
 
 /* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb, struct pt_regs *regs)
@@ -342,7 +347,7 @@ hub_clear_tt_buffer (struct usb_device *
 {
 	return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 			       HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
-			       tt, NULL, 0, HZ);
+			       tt, NULL, 0, 1000);
 }
 
 /*
@@ -376,14 +381,14 @@ static void hub_tt_kevent (void *arg)
 			dev_err (&hdev->dev,
 				"clear tt %d (%04x) error %d\n",
 				clear->tt, clear->devinfo, status);
-		kfree (clear);
+		kfree(clear);
 	}
 	spin_unlock_irqrestore (&hub->tt.lock, flags);
 }
 
 /**
  * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
- * @dev: the device whose split transaction failed
+ * @udev: the device whose split transaction failed
  * @pipe: identifies the endpoint of the failed transaction
  *
  * High speed HCDs use this to tell the hub driver that some split control or
@@ -459,6 +464,7 @@ static void hub_activate(struct usb_hub 
 	int	status;
 
 	hub->quiescing = 0;
+	hub->activating = 1;
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	if (status < 0)
 		dev_err(hub->intfdev, "activate --> %d\n", status);
@@ -466,7 +472,6 @@ static void hub_activate(struct usb_hub 
 		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
 
 	/* scan all ports ASAP */
-	hub->event_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 1;
 	kick_khubd(hub);
 }
 
@@ -689,7 +694,6 @@ static int hub_configure(struct usb_hub 
 		hub->indicator [0] = INDICATOR_CYCLE;
 
 	hub_power_on(hub);
-	hub->change_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 2;
 	hub_activate(hub);
 	return 0;
 
@@ -724,15 +728,11 @@ static void hub_disconnect(struct usb_in
 	list_del_init(&hub->event_list);
 	spin_unlock_irq(&hub_event_lock);
 
-	if (hub->descriptor) {
-		kfree(hub->descriptor);
-		hub->descriptor = NULL;
-	}
+	kfree(hub->descriptor);
+	hub->descriptor = NULL;
 
-	if (hub->status) {
-		kfree(hub->status);
-		hub->status = NULL;
-	}
+	kfree(hub->status);
+	hub->status = NULL;
 
 	if (hub->buffer) {
 		usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,
@@ -1103,23 +1103,33 @@ static int choose_configuration(struct u
 }
 
 #ifdef DEBUG
-static void show_string(struct usb_device *udev, char *id, int index)
+static void show_string(struct usb_device *udev, char *id, char *string)
+{
+	if (!string)
+		return;
+	dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
+}
+
+#else
+static inline void show_string(struct usb_device *udev, char *id, char *string)
+{}
+#endif
+
+static void get_string(struct usb_device *udev, char **string, int index)
 {
 	char *buf;
 
 	if (!index)
 		return;
-	if (!(buf = kmalloc(256, GFP_KERNEL)))
+	buf = kmalloc(256, GFP_KERNEL);
+	if (!buf)
 		return;
 	if (usb_string(udev, index, buf, 256) > 0)
-		dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, buf);
-	kfree(buf);
+		*string = buf;
+	else
+		kfree(buf);
 }
 
-#else
-static inline void show_string(struct usb_device *udev, char *id, int index)
-{}
-#endif
 
 #ifdef	CONFIG_USB_OTG
 #include "otg_whitelist.h"
@@ -1157,22 +1167,20 @@ int usb_new_device(struct usb_device *ud
 		goto fail;
 	}
 
+	/* read the standard strings and cache them if present */
+	get_string(udev, &udev->product, udev->descriptor.iProduct);
+	get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer);
+	get_string(udev, &udev->serial, udev->descriptor.iSerialNumber);
+
 	/* Tell the world! */
 	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
 			"SerialNumber=%d\n",
 			udev->descriptor.iManufacturer,
 			udev->descriptor.iProduct,
 			udev->descriptor.iSerialNumber);
-
-	if (udev->descriptor.iProduct)
-		show_string(udev, "Product",
-				udev->descriptor.iProduct);
-	if (udev->descriptor.iManufacturer)
-		show_string(udev, "Manufacturer",
-				udev->descriptor.iManufacturer);
-	if (udev->descriptor.iSerialNumber)
-		show_string(udev, "SerialNumber",
-				udev->descriptor.iSerialNumber);
+	show_string(udev, "Product", udev->product);
+	show_string(udev, "Manufacturer", udev->manufacturer);
+	show_string(udev, "SerialNumber", udev->serial);
 
 #ifdef	CONFIG_USB_OTG
 	/*
@@ -1214,7 +1222,7 @@ int usb_new_device(struct usb_device *ud
 					bus->b_hnp_enable
 						? USB_DEVICE_B_HNP_ENABLE
 						: USB_DEVICE_A_ALT_HNP_SUPPORT,
-					0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+					0, NULL, 0, USB_CTRL_SET_TIMEOUT);
 				if (err < 0) {
 					/* OTG MESSAGE: report errors here,
 					 * customize to match your product.
@@ -1235,10 +1243,10 @@ int usb_new_device(struct usb_device *ud
 		 */
 		if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
 			static int __usb_suspend_device (struct usb_device *,
-						int port1, u32 state);
+						int port1, pm_message_t state);
 			err = __usb_suspend_device(udev,
 					udev->bus->otg_port,
-					PM_SUSPEND_MEM);
+					PMSG_SUSPEND);
 			if (err < 0)
 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
 		}
@@ -1376,8 +1384,13 @@ static int hub_port_reset(struct usb_hub
 			dev_err(hub->intfdev,
 					"cannot reset port %d (err = %d)\n",
 					port1, status);
-		else
+		else {
 			status = hub_port_wait_reset(hub, port1, udev, delay);
+			if (status)
+				dev_dbg(hub->intfdev,
+						"port_wait_reset: err = %d\n",
+						status);
+		}
 
 		/* return on disconnect or reset */
 		switch (status) {
@@ -1439,7 +1452,7 @@ static void hub_port_logical_disconnect(
 	/* FIXME let caller ask to power down the port:
 	 *  - some devices won't enumerate without a VBUS power cycle
 	 *  - SRP saves power that way
-	 *  - usb_suspend_device(dev,PM_SUSPEND_DISK)
+	 *  - usb_suspend_device(dev, PMSG_SUSPEND)
 	 * That's easy if this hub can switch power per-port, and
 	 * khubd reactivates the port later (timer, SRP, etc).
 	 * Powerdown must be optional, because of reset/DFU.
@@ -1514,7 +1527,7 @@ static int hub_port_suspend(struct usb_h
 
 /*
  * Devices on USB hub ports have only one "suspend" state, corresponding
- * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context".
+ * to ACPI D2, "may cause the device to lose some context".
  * State transitions include:
  *
  *   - suspend, resume ... when the VBUS power link stays live
@@ -1526,7 +1539,8 @@ static int hub_port_suspend(struct usb_h
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * timer, no SRP, no requests through sysfs.
  */
-int __usb_suspend_device (struct usb_device *udev, int port1, u32 state)
+static int __usb_suspend_device (struct usb_device *udev, int port1,
+				 pm_message_t state)
 {
 	int	status;
 
@@ -1607,9 +1621,11 @@ int __usb_suspend_device (struct usb_dev
 		struct usb_bus	*bus = udev->bus;
 		if (bus && bus->op->hub_suspend) {
 			status = bus->op->hub_suspend (bus);
-			if (status == 0)
+			if (status == 0) {
+				dev_dbg(&udev->dev, "usb suspend\n");
 				usb_set_device_state(udev,
 						USB_STATE_SUSPENDED);
+			}
 		} else
 			status = -EOPNOTSUPP;
 	} else
@@ -1624,7 +1640,7 @@ int __usb_suspend_device (struct usb_dev
 /**
  * usb_suspend_device - suspend a usb device
  * @udev: device that's no longer in active use
- * @state: PM_SUSPEND_MEM to suspend
+ * @state: PMSG_SUSPEND to suspend
  * Context: must be able to sleep; device not locked
  *
  * Suspends a USB device that isn't in active use, conserving power.
@@ -1639,7 +1655,7 @@ int __usb_suspend_device (struct usb_dev
  *
  * Returns 0 on success, else negative errno.
  */
-int usb_suspend_device(struct usb_device *udev, u32 state)
+int usb_suspend_device(struct usb_device *udev, pm_message_t state)
 {
 	int	port1, status;
 
@@ -1673,7 +1689,7 @@ static int finish_port_resume(struct usb
 	usb_set_device_state(udev, udev->actconfig
 			? USB_STATE_CONFIGURED
 			: USB_STATE_ADDRESS);
-	udev->dev.power.power_state = PM_SUSPEND_ON;
+	udev->dev.power.power_state = PMSG_ON;
 
  	/* 10.5.4.5 says be sure devices in the tree are still there.
  	 * For now let's assume the device didn't go crazy on resume,
@@ -1711,7 +1727,7 @@ static int finish_port_resume(struct usb
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (intf->dev.power.power_state == PM_SUSPEND_ON)
+			if (intf->dev.power.power_state == PMSG_SUSPEND)
 				continue;
 			if (!intf->dev.driver) {
 				/* FIXME maybe force to alt 0 */
@@ -1725,7 +1741,7 @@ static int finish_port_resume(struct usb
 
 			/* can we do better than just logging errors? */
 			status = driver->resume(intf);
-			if (intf->dev.power.power_state != PM_SUSPEND_ON
+			if (intf->dev.power.power_state != PMSG_ON
 					|| status)
 				dev_dbg(&intf->dev,
 					"resume fail, state %d code %d\n",
@@ -1827,9 +1843,11 @@ int usb_resume_device(struct usb_device 
 		} else
 			status = -EOPNOTSUPP;
 		if (status == 0) {
+			dev_dbg(&udev->dev, "usb resume\n");
 			/* TRSMRCY = 10 msec */
 			msleep(10);
 			usb_set_device_state (udev, USB_STATE_CONFIGURED);
+			udev->dev.power.power_state = PMSG_ON;
 			status = hub_resume (udev
 					->actconfig->interface[0]);
 		}
@@ -1874,7 +1892,7 @@ static int remote_wakeup(struct usb_devi
 	return status;
 }
 
-static int hub_suspend(struct usb_interface *intf, u32 state)
+static int hub_suspend(struct usb_interface *intf, pm_message_t state)
 {
 	struct usb_hub		*hub = usb_get_intfdata (intf);
 	struct usb_device	*hdev = hub->hdev;
@@ -1946,15 +1964,24 @@ static int hub_resume(struct usb_interfa
 		}
 		up(&udev->serialize);
 	}
-	intf->dev.power.power_state = PM_SUSPEND_ON;
+	intf->dev.power.power_state = PMSG_ON;
 
+	hub->resume_root_hub = 0;
 	hub_activate(hub);
 	return 0;
 }
 
+void usb_resume_root_hub(struct usb_device *hdev)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	hub->resume_root_hub = 1;
+	kick_khubd(hub);
+}
+
 #else	/* !CONFIG_USB_SUSPEND */
 
-int usb_suspend_device(struct usb_device *udev, u32 state)
+int usb_suspend_device(struct usb_device *udev, pm_message_t state)
 {
 	return 0;
 }
@@ -2058,7 +2085,7 @@ static int hub_set_address(struct usb_de
 		return -EINVAL;
 	retval = usb_control_msg(udev, usb_sndaddr0pipe(),
 		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
-		NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+		NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval == 0) {
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		ep0_reinit(udev);
@@ -2181,24 +2208,35 @@ hub_port_init (struct usb_hub *hub, stru
 				retval = -ENOMEM;
 				continue;
 			}
-			buf->bMaxPacketSize0 = 0;
 
 			/* Use a short timeout the first time through,
 			 * so that recalcitrant full-speed devices with
 			 * 8- or 16-byte ep0-maxpackets won't slow things
 			 * down tremendously by NAKing the unexpectedly
-			 * early status stage.  Also, retry on length 0
-			 * or stall; some devices are flakey.
+			 * early status stage.  Also, retry on all errors;
+			 * some devices are flakey.
 			 */
 			for (j = 0; j < 3; ++j) {
+				buf->bMaxPacketSize0 = 0;
 				r = usb_control_msg(udev, usb_rcvaddr0pipe(),
 					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 					USB_DT_DEVICE << 8, 0,
 					buf, GET_DESCRIPTOR_BUFSIZE,
-					(i ? HZ * USB_CTRL_GET_TIMEOUT : HZ));
-				if (r == 0 || r == -EPIPE)
-					continue;
-				if (r < 0)
+					(i ? USB_CTRL_GET_TIMEOUT : 1000));
+				switch (buf->bMaxPacketSize0) {
+				case 8: case 16: case 32: case 64:
+					if (buf->bDescriptorType ==
+							USB_DT_DEVICE) {
+						r = 0;
+						break;
+					}
+					/* FALL THROUGH */
+				default:
+					if (r == 0)
+						r = -EPROTO;
+					break;
+				}
+				if (r == 0)
 					break;
 			}
 			udev->descriptor.bMaxPacketSize0 =
@@ -2214,10 +2252,7 @@ hub_port_init (struct usb_hub *hub, stru
 				retval = -ENODEV;
 				goto fail;
 			}
-			switch (udev->descriptor.bMaxPacketSize0) {
-			case 64: case 32: case 16: case 8:
-				break;
-			default:
+			if (r) {
 				dev_err(&udev->dev, "device descriptor "
 						"read/%s, error %d\n",
 						"64", r);
@@ -2315,7 +2350,7 @@ check_highspeed (struct usb_hub *hub, st
 			schedule_work (&hub->leds);
 		}
 	}
-	kfree (qual);
+	kfree(qual);
 }
 
 static unsigned
@@ -2600,15 +2635,30 @@ static void hub_events(void)
 				(u16) hub->event_bits[0]);
 
 		usb_get_intf(intf);
+		i = hub->resume_root_hub;
 		spin_unlock_irq(&hub_event_lock);
 
+		/* Is this is a root hub wanting to be resumed? */
+		if (i)
+			usb_resume_device(hdev);
+
 		/* Lock the device, then check to see if we were
 		 * disconnected while waiting for the lock to succeed. */
 		if (locktree(hdev) < 0) {
 			usb_put_intf(intf);
 			continue;
 		}
-		if (hub != usb_get_intfdata(intf) || hub->quiescing)
+		if (hub != usb_get_intfdata(intf))
+			goto loop;
+
+		/* If the hub has died, clean up after it */
+		if (hdev->state == USB_STATE_NOTATTACHED) {
+			hub_pre_reset(hub);
+			goto loop;
+		}
+
+		/* If this is an inactive or suspended hub, do nothing */
+		if (hub->quiescing)
 			goto loop;
 
 		if (hub->error) {
@@ -2628,9 +2678,11 @@ static void hub_events(void)
 
 		/* deal with port status changes */
 		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+			if (test_bit(i, hub->busy_bits))
+				continue;
 			connect_change = test_bit(i, hub->change_bits);
 			if (!test_and_clear_bit(i, hub->event_bits) &&
-					!connect_change)
+					!connect_change && !hub->activating)
 				continue;
 
 			ret = hub_port_status(hub, i,
@@ -2638,6 +2690,11 @@ static void hub_events(void)
 			if (ret < 0)
 				continue;
 
+			if (hub->activating && !hdev->children[i-1] &&
+					(portstatus &
+						USB_PORT_STAT_CONNECTION))
+				connect_change = 1;
+
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
 				clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_CONNECTION);
@@ -2728,6 +2785,8 @@ static void hub_events(void)
 			}
 		}
 
+		hub->activating = 0;
+
 loop:
 		usb_unlock_device(hdev);
 		usb_put_intf(intf);
@@ -2926,6 +2985,7 @@ int usb_reset_device(struct usb_device *
 		hub_pre_reset(hub);
 	}
 
+	set_bit(port1, parent_hub->busy_bits);
 	for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
 		/* ep0 maxpacket size may change; let the HCD know about it.
@@ -2935,6 +2995,7 @@ int usb_reset_device(struct usb_device *
 		if (ret >= 0)
 			break;
 	}
+	clear_bit(port1, parent_hub->busy_bits);
 	if (ret < 0)
 		goto re_enumerate;
  
@@ -2952,7 +3013,7 @@ int usb_reset_device(struct usb_device *
 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			USB_REQ_SET_CONFIGURATION, 0,
 			udev->actconfig->desc.bConfigurationValue, 0,
-			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (ret < 0) {
 		dev_err(&udev->dev,
 			"can't restore configuration #%d (error=%d)\n",
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -205,6 +205,7 @@ struct usb_hub {
 	unsigned long		event_bits[1];	/* status change bitmask */
 	unsigned long		change_bits[1];	/* ports with logical connect
 							status change */
+	unsigned long		busy_bits[1];	/* ports being reset */
 #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
 #error event_bits[] is too short!
 #endif
@@ -215,6 +216,8 @@ struct usb_hub {
 	u8			power_budget;	/* in 2mA units; or zero */
 
 	unsigned		quiescing:1;
+	unsigned		activating:1;
+	unsigned		resume_root_hub:1;
 
 	unsigned		has_indicators:1;
 	enum hub_led_mode	indicator[USB_MAXCHILDREN];
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -41,6 +41,7 @@
 #include <linux/parser.h>
 #include <asm/byteorder.h>
 #include "usb.h"
+#include "hcd.h"
 
 static struct super_operations usbfs_ops;
 static struct file_operations default_file_operations;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -55,7 +55,7 @@ static int usb_start_wait_urb(struct urb
 	if (status == 0) {
 		if (timeout > 0) {
 			init_timer(&timer);
-			timer.expires = jiffies + timeout;
+			timer.expires = jiffies + msecs_to_jiffies(timeout);
 			timer.data = (unsigned long)urb;
 			timer.function = timeout_kill;
 			/* grr.  timeout _should_ include submit delays. */
@@ -65,12 +65,18 @@ static int usb_start_wait_urb(struct urb
 		status = urb->status;
 		/* note:  HCDs return ETIMEDOUT for other reasons too */
 		if (status == -ECONNRESET) {
-			dev_warn(&urb->dev->dev,
-				"%s timed out on ep%d%s\n",
+			dev_dbg(&urb->dev->dev,
+				"%s timed out on ep%d%s len=%d/%d\n",
 				current->comm,
 				usb_pipeendpoint(urb->pipe),
-				usb_pipein(urb->pipe) ? "in" : "out");
-			status = -ETIMEDOUT;
+				usb_pipein(urb->pipe) ? "in" : "out",
+				urb->actual_length,
+				urb->transfer_buffer_length
+				);
+			if (urb->actual_length > 0)
+				status = 0;
+			else
+				status = -ETIMEDOUT;
 		}
 		if (timeout > 0)
 			del_timer_sync(&timer);
@@ -84,8 +90,10 @@ static int usb_start_wait_urb(struct urb
 
 /*-------------------------------------------------------------------*/
 // returns status (negative) or length (positive)
-int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
-			    struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
+static int usb_internal_control_msg(struct usb_device *usb_dev,
+				    unsigned int pipe, 
+				    struct usb_ctrlrequest *cmd,
+				    void *data, int len, int timeout)
 {
 	struct urb *urb;
 	int retv;
@@ -115,7 +123,7 @@ int usb_internal_control_msg(struct usb_
  *	@index: USB message index value
  *	@data: pointer to the data to send
  *	@size: length in bytes of the data to send
- *	@timeout: time in jiffies to wait for the message to complete before
+ *	@timeout: time in msecs to wait for the message to complete before
  *		timing out (if 0 the wait is forever)
  *	Context: !in_interrupt ()
  *
@@ -163,7 +171,7 @@ int usb_control_msg(struct usb_device *d
  *	@data: pointer to the data to send
  *	@len: length in bytes of the data to send
  *	@actual_length: pointer to a location to put the actual length transferred in bytes
- *	@timeout: time in jiffies to wait for the message to complete before
+ *	@timeout: time in msecs to wait for the message to complete before
  *		timing out (if 0 the wait is forever)
  *	Context: !in_interrupt ()
  *
@@ -196,7 +204,7 @@ int usb_bulk_msg(struct usb_device *usb_
 	usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
 			  usb_api_blocking_completion, NULL);
 
-	return usb_start_wait_urb(urb,timeout,actual_length);
+	return usb_start_wait_urb(urb, timeout, actual_length);
 }
 
 /*-------------------------------------------------------------------*/
@@ -423,7 +431,7 @@ nomem:
  * (2) error, where io->status is a negative errno value.  The number
  *     of io->bytes transferred before the error is usually less
  *     than requested, and can be nonzero.
- * (3) cancelation, a type of error with status -ECONNRESET that
+ * (3) cancellation, a type of error with status -ECONNRESET that
  *     is initiated by usb_sg_cancel().
  *
  * When this function returns, all memory allocated through usb_sg_init() or
@@ -579,7 +587,7 @@ int usb_get_descriptor(struct usb_device
 		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 				(type << 8) + index, 0, buf, size,
-				HZ * USB_CTRL_GET_TIMEOUT);
+				USB_CTRL_GET_TIMEOUT);
 		if (result == 0 || result == -EPIPE)
 			continue;
 		if (result > 1 && ((u8 *)buf)[1] != type) {
@@ -624,7 +632,7 @@ int usb_get_string(struct usb_device *de
 		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 			(USB_DT_STRING << 8) + index, langid, buf, size,
-			HZ * USB_CTRL_GET_TIMEOUT);
+			USB_CTRL_GET_TIMEOUT);
 		if (!(result == 0 || result == -EPIPE))
 			break;
 	}
@@ -834,7 +842,7 @@ int usb_get_status(struct usb_device *de
 
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
-		sizeof(*status), HZ * USB_CTRL_GET_TIMEOUT);
+		sizeof(*status), USB_CTRL_GET_TIMEOUT);
 
 	*(u16 *)data = *status;
 	kfree(status);
@@ -879,7 +887,7 @@ int usb_clear_halt(struct usb_device *de
 	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
 		USB_ENDPOINT_HALT, endp, NULL, 0,
-		HZ * USB_CTRL_SET_TIMEOUT);
+		USB_CTRL_SET_TIMEOUT);
 
 	/* don't un-halt or force to DATA0 except on success */
 	if (result < 0)
@@ -982,6 +990,8 @@ void usb_disable_device(struct usb_devic
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
 			usb_remove_sysfs_intf_files(interface);
+			kfree(interface->cur_altsetting->string);
+			interface->cur_altsetting->string = NULL;
 			device_del (&interface->dev);
 		}
 
@@ -1033,8 +1043,8 @@ usb_enable_endpoint(struct usb_device *d
  *
  * Enables all the endpoints for the interface's current altsetting.
  */
-void usb_enable_interface(struct usb_device *dev,
-		struct usb_interface *intf)
+static void usb_enable_interface(struct usb_device *dev,
+				 struct usb_interface *intf)
 {
 	struct usb_host_interface *alt = intf->cur_altsetting;
 	int i;
@@ -1101,7 +1111,7 @@ int usb_set_interface(struct usb_device 
 
 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 				   USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
-				   alternate, interface, NULL, 0, HZ * 5);
+				   alternate, interface, NULL, 0, 5000);
 
 	/* 9.4.10 says devices don't need this and are free to STALL the
 	 * request if the interface only has one alternate setting.
@@ -1173,7 +1183,9 @@ int usb_set_interface(struct usb_device 
  *
  * Because this affects multiple interfaces, avoid using this with composite
  * (multi-interface) devices.  Instead, the driver for each interface may
- * use usb_set_interface() on the interfaces it claims.  Resetting the whole
+ * use usb_set_interface() on the interfaces it claims.  Be careful though;
+ * some devices don't support the SET_INTERFACE request, and others won't
+ * reset all the interface state (notably data toggles).  Resetting the whole
  * configuration would affect other drivers' interfaces.
  *
  * The caller must own the device lock.
@@ -1202,7 +1214,7 @@ int usb_reset_configuration(struct usb_d
 	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0,
 			config->desc.bConfigurationValue, 0,
-			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval < 0) {
 		usb_set_device_state(dev, USB_STATE_ADDRESS);
 		return retval;
@@ -1270,7 +1282,7 @@ static void release_interface(struct dev
  * bus rwsem; usb device driver probe() methods cannot use this routine.
  *
  * Returns zero on success, or else the status code returned by the
- * underlying call that failed.  On succesful completion, each interface
+ * underlying call that failed.  On successful completion, each interface
  * in the original device configuration has been destroyed, and each one
  * in the new configuration has been probed by all relevant usb device
  * drivers currently known to the kernel.
@@ -1337,7 +1349,7 @@ free_interfaces:
 
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
-			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
+			NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
 		goto free_interfaces;
 
 	dev->actconfig = cp;
@@ -1386,6 +1398,13 @@ free_interfaces:
 		}
 		kfree(new_interfaces);
 
+		if ((cp->desc.iConfiguration) &&
+		    (cp->string == NULL)) {
+			cp->string = kmalloc(256, GFP_KERNEL);
+			if (cp->string)
+				usb_string(dev, cp->desc.iConfiguration, cp->string, 256);
+		}
+
 		/* Now that all the interfaces are set up, register them
 		 * to trigger binding of drivers to interfaces.  probe()
 		 * routines may install different altsettings and may
@@ -1409,6 +1428,13 @@ free_interfaces:
 					ret);
 				continue;
 			}
+			if ((intf->cur_altsetting->desc.iInterface) &&
+			    (intf->cur_altsetting->string == NULL)) {
+				intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL);
+				if (intf->cur_altsetting->string)
+					usb_string(dev, intf->cur_altsetting->desc.iInterface,
+						   intf->cur_altsetting->string, 256);
+			}
 			usb_create_sysfs_intf_files (intf);
 		}
 	}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -46,27 +46,24 @@ usb_actconfig_attr (bNumInterfaces, 1, "
 usb_actconfig_attr (bmAttributes, 1, "%2x\n")
 usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
 
-#define usb_actconfig_str(name, field)					\
-static ssize_t  show_##name(struct device *dev, char *buf)		\
-{									\
-	struct usb_device *udev;					\
-	struct usb_host_config *actconfig;				\
-	int len;							\
-									\
-	udev = to_usb_device (dev);					\
-	actconfig = udev->actconfig;					\
-	if (!actconfig)							\
-		return 0;						\
-	len = usb_string(udev, actconfig->desc.field, buf, PAGE_SIZE);	\
-	if (len < 0)							\
-		return 0;						\
-	buf[len] = '\n';						\
-	buf[len+1] = 0;							\
-	return len+1;							\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static ssize_t show_configuration_string(struct device *dev, char *buf)
+{
+	struct usb_device *udev;
+	struct usb_host_config *actconfig;
+	int len;
 
-usb_actconfig_str (configuration, iConfiguration)
+	udev = to_usb_device (dev);
+	actconfig = udev->actconfig;
+	if ((!actconfig) || (!actconfig->string))
+		return 0;
+	len = sprintf(buf, actconfig->string, PAGE_SIZE);
+	if (len < 0)
+		return 0;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+	return len+1;
+}
+static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 
 /* configuration value is always present, and r/w */
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
@@ -89,14 +86,14 @@ static DEVICE_ATTR(bConfigurationValue, 
 		show_bConfigurationValue, set_bConfigurationValue);
 
 /* String fields */
-#define usb_string_attr(name, field)		\
+#define usb_string_attr(name)						\
 static ssize_t  show_##name(struct device *dev, char *buf)		\
 {									\
 	struct usb_device *udev;					\
 	int len;							\
 									\
 	udev = to_usb_device (dev);					\
-	len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE);	\
+	len = snprintf(buf, 256, "%s", udev->name);			\
 	if (len < 0)							\
 		return 0;						\
 	buf[len] = '\n';						\
@@ -105,9 +102,9 @@ static ssize_t  show_##name(struct devic
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 
-usb_string_attr(product, iProduct);
-usb_string_attr(manufacturer, iManufacturer);
-usb_string_attr(serial, iSerialNumber);
+usb_string_attr(product);
+usb_string_attr(manufacturer);
+usb_string_attr(serial);
 
 static ssize_t
 show_speed (struct device *dev, char *buf)
@@ -230,11 +227,11 @@ void usb_create_sysfs_dev_files (struct 
 
 	sysfs_create_group(&dev->kobj, &dev_attr_grp);
 
-	if (udev->descriptor.iManufacturer)
+	if (udev->manufacturer)
 		device_create_file (dev, &dev_attr_manufacturer);
-	if (udev->descriptor.iProduct)
+	if (udev->product)
 		device_create_file (dev, &dev_attr_product);
-	if (udev->descriptor.iSerialNumber)
+	if (udev->serial)
 		device_create_file (dev, &dev_attr_serial);
 	device_create_file (dev, &dev_attr_configuration);
 }
@@ -272,25 +269,53 @@ usb_intf_attr (bInterfaceClass, "%02x\n"
 usb_intf_attr (bInterfaceSubClass, "%02x\n")
 usb_intf_attr (bInterfaceProtocol, "%02x\n")
 
-#define usb_intf_str(name, field)					\
-static ssize_t  show_##name(struct device *dev, char *buf)		\
-{									\
-	struct usb_interface *intf;					\
-	struct usb_device *udev;					\
-	int len;							\
-									\
-	intf = to_usb_interface (dev);					\
-	udev = interface_to_usbdev (intf);				\
-	len = usb_string(udev, intf->cur_altsetting->desc.field, buf, PAGE_SIZE);\
-	if (len < 0)							\
-		return 0;						\
-	buf[len] = '\n';						\
-	buf[len+1] = 0;							\
-	return len+1;							\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static ssize_t show_interface_string(struct device *dev, char *buf)
+{
+	struct usb_interface *intf;
+	struct usb_device *udev;
+	int len;
+
+	intf = to_usb_interface (dev);
+	udev = interface_to_usbdev (intf);
+	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
+	if (len < 0)
+		return 0;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+	return len+1;
+}
+static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
+
+static ssize_t show_modalias(struct device *dev, char *buf)
+{
+	struct usb_interface *intf;
+	struct usb_device *udev;
+	int len;
+
+	intf = to_usb_interface(dev);
+	udev = interface_to_usbdev(intf);
 
-usb_intf_str (interface, iInterface);
+	len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic",
+			       le16_to_cpu(udev->descriptor.idVendor),
+			       le16_to_cpu(udev->descriptor.idProduct),
+			       le16_to_cpu(udev->descriptor.bcdDevice),
+			       udev->descriptor.bDeviceClass,
+			       udev->descriptor.bDeviceSubClass,
+			       udev->descriptor.bDeviceProtocol);
+	buf += len;
+
+	if (udev->descriptor.bDeviceClass == 0) {
+		struct usb_host_interface *alt = intf->cur_altsetting;
+
+		return len + sprintf(buf, "%02Xisc%02Xip%02X\n",
+			       alt->desc.bInterfaceClass,
+			       alt->desc.bInterfaceSubClass,
+			       alt->desc.bInterfaceProtocol);
+ 	} else {
+		return len + sprintf(buf, "*isc*ip*\n");
+	}
+}
+static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
 static struct attribute *intf_attrs[] = {
 	&dev_attr_bInterfaceNumber.attr,
@@ -299,6 +324,7 @@ static struct attribute *intf_attrs[] = 
 	&dev_attr_bInterfaceClass.attr,
 	&dev_attr_bInterfaceSubClass.attr,
 	&dev_attr_bInterfaceProtocol.attr,
+	&dev_attr_modalias.attr,
 	NULL,
 };
 static struct attribute_group intf_attr_grp = {
@@ -309,7 +335,7 @@ void usb_create_sysfs_intf_files (struct
 {
 	sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
 
-	if (intf->cur_altsetting->desc.iInterface)
+	if (intf->cur_altsetting->string)
 		device_create_file(&intf->dev, &dev_attr_interface);
 		
 }
@@ -318,7 +344,7 @@ void usb_remove_sysfs_intf_files (struct
 {
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
 
-	if (intf->cur_altsetting->desc.iInterface)
+	if (intf->cur_altsetting->string)
 		device_remove_file(&intf->dev, &dev_attr_interface);
 
 }
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -121,7 +121,7 @@ struct urb * usb_get_urb(struct urb *urb
  * describing that request to the USB subsystem.  Request completion will
  * be indicated later, asynchronously, by calling the completion handler.
  * The three types of completion are success, error, and unlink
- * (a software-induced fault, also called "request cancelation").  
+ * (a software-induced fault, also called "request cancellation").  
  *
  * URBs may be submitted in interrupt context.
  *
@@ -170,7 +170,7 @@ struct urb * usb_get_urb(struct urb *urb
  * As of Linux 2.6, all USB endpoint transfer queues support depths greater
  * than one.  This was previously a HCD-specific behavior, except for ISO
  * transfers.  Non-isochronous endpoint queues are inactive during cleanup
- * after faults (transfer errors or cancelation).
+ * after faults (transfer errors or cancellation).
  *
  * Reserved Bandwidth Transfers:
  *
@@ -395,7 +395,7 @@ int usb_submit_urb(struct urb *urb, int 
  *
  * This routine cancels an in-progress request.  URBs complete only
  * once per submission, and may be canceled only once per submission.
- * Successful cancelation means the requests's completion handler will
+ * Successful cancellation means the requests's completion handler will
  * be called with a status code indicating that the request has been
  * canceled (rather than any other code) and will quickly be removed
  * from host controller data structures.
@@ -420,12 +420,16 @@ int usb_submit_urb(struct urb *urb, int 
  *
  * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
- * hardware processes each request.  But when an URB terminates with any
- * fault (such as an error, or being unlinked) its queue stops, at least
- * until that URB's completion routine returns.  It is guaranteed that
- * the queue will not restart until all its unlinked URBs have been fully
- * retired, with their completion routines run, even if that's not until
- * some time after the original completion handler returns.
+ * hardware processes each request.  But when an URB terminates with an
+ * error its queue stops, at least until that URB's completion routine
+ * returns.  It is guaranteed that the queue will not restart until all
+ * its unlinked URBs have been fully retired, with their completion
+ * routines run, even if that's not until some time after the original
+ * completion handler returns.  Normally the same behavior and guarantees
+ * apply when an URB terminates because it was unlinked; however if an
+ * URB is unlinked before the hardware has started to execute it, then
+ * its queue is not guaranteed to stop until all the preceding URBs have
+ * completed.
  *
  * This means that USB device drivers can safely build deep queues for
  * large or complex transfers, and clean them up reliably after any sort
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -50,17 +50,10 @@
 #include "hcd.h"
 #include "usb.h"
 
-extern int  usb_hub_init(void);
-extern void usb_hub_cleanup(void);
-extern int usb_major_init(void);
-extern void usb_major_cleanup(void);
-extern int usb_host_init(void);
-extern void usb_host_cleanup(void);
-
 
 const char *usbcore_name = "usbcore";
 
-int nousb;		/* Disable USB when built into kernel image */
+static int nousb;	/* Disable USB when built into kernel image */
 			/* Not honored on modular build */
 
 static DECLARE_RWSEM(usb_all_devices_rwsem);
@@ -86,7 +79,7 @@ static struct device_driver usb_generic_
 static int usb_generic_driver_data;
 
 /* called from driver core with usb_bus_type.subsys writelock */
-int usb_probe_interface(struct device *dev)
+static int usb_probe_interface(struct device *dev)
 {
 	struct usb_interface * intf = to_usb_interface(dev);
 	struct usb_driver * driver = to_usb_driver(dev->driver);
@@ -114,7 +107,7 @@ int usb_probe_interface(struct device *d
 }
 
 /* called from driver core with usb_bus_type.subsys writelock */
-int usb_unbind_interface(struct device *dev)
+static int usb_unbind_interface(struct device *dev)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_driver *driver = to_usb_driver(intf->dev.driver);
@@ -615,6 +608,31 @@ static int usb_hotplug (struct device *d
 					alt->desc.bInterfaceSubClass,
 					alt->desc.bInterfaceProtocol))
 			return -ENOMEM;
+
+		if (add_hotplug_env_var(envp, num_envp, &i,
+					buffer, buffer_size, &length,
+					"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+					le16_to_cpu(usb_dev->descriptor.idVendor),
+					le16_to_cpu(usb_dev->descriptor.idProduct),
+					le16_to_cpu(usb_dev->descriptor.bcdDevice),
+					usb_dev->descriptor.bDeviceClass,
+					usb_dev->descriptor.bDeviceSubClass,
+					usb_dev->descriptor.bDeviceProtocol,
+					alt->desc.bInterfaceClass,
+					alt->desc.bInterfaceSubClass,
+					alt->desc.bInterfaceProtocol))
+			return -ENOMEM;
+ 	} else {
+		if (add_hotplug_env_var(envp, num_envp, &i,
+					buffer, buffer_size, &length,
+					"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*",
+					le16_to_cpu(usb_dev->descriptor.idVendor),
+					le16_to_cpu(usb_dev->descriptor.idProduct),
+					le16_to_cpu(usb_dev->descriptor.bcdDevice),
+					usb_dev->descriptor.bDeviceClass,
+					usb_dev->descriptor.bDeviceSubClass,
+					usb_dev->descriptor.bDeviceProtocol))
+			return -ENOMEM;
 	}
 
 	envp[i] = NULL;
@@ -647,7 +665,10 @@ static void usb_release_dev(struct devic
 
 	usb_destroy_configuration(udev);
 	usb_bus_put(udev->bus);
-	kfree (udev);
+	kfree(udev->product);
+	kfree(udev->manufacturer);
+	kfree(udev->serial);
+	kfree(udev);
 }
 
 /**
@@ -1145,6 +1166,7 @@ void usb_buffer_free (
  *
  * Reverse the effect of this call with usb_buffer_unmap().
  */
+#if 0
 struct urb *usb_buffer_map (struct urb *urb)
 {
 	struct usb_bus		*bus;
@@ -1174,6 +1196,7 @@ struct urb *usb_buffer_map (struct urb *
 				| URB_NO_SETUP_DMA_MAP);
 	return urb;
 }
+#endif  /*  0  */
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
  * XXX please determine whether the sync is to transfer ownership of
@@ -1218,6 +1241,7 @@ void usb_buffer_dmasync (struct urb *urb
  *
  * Reverses the effect of usb_buffer_map().
  */
+#if 0
 void usb_buffer_unmap (struct urb *urb)
 {
 	struct usb_bus		*bus;
@@ -1244,6 +1268,7 @@ void usb_buffer_unmap (struct urb *urb)
 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
 				| URB_NO_SETUP_DMA_MAP);
 }
+#endif  /*  0  */
 
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
@@ -1348,13 +1373,13 @@ void usb_buffer_unmap_sg (struct usb_dev
 			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
-static int usb_generic_suspend(struct device *dev, u32 state)
+static int usb_generic_suspend(struct device *dev, pm_message_t message)
 {
 	struct usb_interface *intf;
 	struct usb_driver *driver;
 
 	if (dev->driver == &usb_generic_driver)
-		return usb_suspend_device (to_usb_device(dev), state);
+		return usb_suspend_device (to_usb_device(dev), message);
 
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1368,7 +1393,7 @@ static int usb_generic_suspend(struct de
 		return 0;
 
 	if (driver->suspend)
-		return driver->suspend(intf, state);
+		return driver->suspend(intf, message);
 	return 0;
 }
 
@@ -1524,11 +1549,11 @@ EXPORT_SYMBOL(usb_get_current_frame_numb
 EXPORT_SYMBOL (usb_buffer_alloc);
 EXPORT_SYMBOL (usb_buffer_free);
 
-EXPORT_SYMBOL (usb_buffer_map);
 #if 0
+EXPORT_SYMBOL (usb_buffer_map);
 EXPORT_SYMBOL (usb_buffer_dmasync);
-#endif
 EXPORT_SYMBOL (usb_buffer_unmap);
+#endif
 
 EXPORT_SYMBOL (usb_buffer_map_sg);
 #if 0
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -4,8 +4,6 @@ extern void usb_create_sysfs_dev_files (
 extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
 extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
 extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
-extern int usb_probe_interface (struct device *dev);
-extern int usb_unbind_interface (struct device *dev);
 
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
@@ -13,9 +11,6 @@ extern void usb_disable_interface (struc
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
 
-extern void usb_enable_interface (struct usb_device *dev,
-		struct usb_interface *intf);
-
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
@@ -23,6 +18,16 @@ extern int usb_set_configuration(struct 
 extern void usb_lock_all_devices(void);
 extern void usb_unlock_all_devices(void);
 
+extern void usb_kick_khubd(struct usb_device *dev);
+extern void usb_resume_root_hub(struct usb_device *dev);
+
+extern int  usb_hub_init(void);
+extern void usb_hub_cleanup(void);
+extern int usb_major_init(void);
+extern void usb_major_cleanup(void);
+extern int usb_host_init(void);
+extern void usb_host_cleanup(void);
+
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 
@@ -32,6 +37,7 @@ extern struct file_operations usbfs_devi
 extern struct file_operations usbfs_device_file_operations;
 extern void usbfs_conn_disc_event(void);
 
+
 struct dev_state {
 	struct list_head list;      /* state list */
 	struct usb_device *dev;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -87,10 +87,10 @@ config USB_NET2280
 	default USB_GADGET
 
 config USB_GADGET_PXA2XX
-	boolean "PXA 2xx or IXP 4xx"
-	depends on ARCH_PXA || ARCH_IXP4XX
+	boolean "PXA 25x or IXP 4xx"
+	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
 	help
-	   Intel's PXA 2xx series XScale ARM-5TE processors include
+	   Intel's PXA 25x series XScale ARM-5TE processors include
 	   an integrated full speed USB 1.1 device controller.  The
 	   controller in the IXP 4xx series is register-compatible.
 
@@ -135,21 +135,6 @@ config USB_GOKU
 	depends on USB_GADGET_GOKU
 	default USB_GADGET
 
-# this could be built elsewhere (doesn't yet exist)
-config USB_GADGET_SA1100
-	boolean "SA 1100"
-	depends on ARCH_SA1100
-	help
-	   Intel's SA-1100 is an ARM-4 processor with an integrated
-	   full speed USB 1.1 device controller.
-
-	   It has two fixed-function endpoints, as well as endpoint
-	   zero (for control transfers).
-
-config USB_SA1100
-	tristate
-	depends on USB_GADGET_SA1100
-	default USB_GADGET
 
 config USB_GADGET_LH7A40X
 	boolean "LH7A40X"
@@ -163,38 +148,10 @@ config USB_LH7A40X
 	default USB_GADGET
 
 
-config USB_GADGET_DUMMY_HCD
-	boolean "Dummy HCD (DEVELOPMENT)"
-	depends on USB && EXPERIMENTAL
-	select USB_GADGET_DUALSPEED
-	help
-	  This host controller driver emulates USB, looping all data transfer
-	  requests back to a USB "gadget driver" in the same host.  The host
-	  side is the master; the gadget side is the slave.  Gadget drivers
-	  can be high, full, or low speed; and they have access to endpoints
-	  like those from NET2280, PXA2xx, or SA1100 hardware.
-	  
-	  This may help in some stages of creating a driver to embed in a
-	  Linux device, since it lets you debug several parts of the gadget
-	  driver without its hardware or drivers being involved.
-	  
-	  Since such a gadget side driver needs to interoperate with a host
-	  side Linux-USB device driver, this may help to debug both sides
-	  of a USB protocol stack.
-
-	  Say "y" to link the driver statically, or "m" to build a
-	  dynamically linked module called "dummy_hcd" and force all
-	  gadget drivers to also be dynamically linked.
-
-config USB_DUMMY_HCD
-	tristate
-	depends on USB_GADGET_DUMMY_HCD
-	default USB_GADGET
-
 config USB_GADGET_OMAP
 	boolean "OMAP USB Device Controller"
 	depends on ARCH_OMAP
-	select ISP1301_OMAP if MACH_OMAP_H2
+	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
 	help
 	   Many Texas Instruments OMAP processors have flexible full
 	   speed USB device controllers, with support for up to 30
@@ -222,6 +179,38 @@ config USB_OTG
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 
+
+config USB_GADGET_DUMMY_HCD
+	boolean "Dummy HCD (DEVELOPMENT)"
+	depends on USB && EXPERIMENTAL
+	select USB_GADGET_DUALSPEED
+	help
+	  This host controller driver emulates USB, looping all data transfer
+	  requests back to a USB "gadget driver" in the same host.  The host
+	  side is the master; the gadget side is the slave.  Gadget drivers
+	  can be high, full, or low speed; and they have access to endpoints
+	  like those from NET2280, PXA2xx, or SA1100 hardware.
+	  
+	  This may help in some stages of creating a driver to embed in a
+	  Linux device, since it lets you debug several parts of the gadget
+	  driver without its hardware or drivers being involved.
+	  
+	  Since such a gadget side driver needs to interoperate with a host
+	  side Linux-USB device driver, this may help to debug both sides
+	  of a USB protocol stack.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "dummy_hcd" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_DUMMY_HCD
+	tristate
+	depends on USB_GADGET_DUMMY_HCD
+	default USB_GADGET
+
+# NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
+# first and will be selected by default.
+
 endchoice
 
 config USB_GADGET_DUALSPEED
@@ -355,8 +344,6 @@ config USB_GADGETFS
 
 config USB_FILE_STORAGE
 	tristate "File-backed Storage Gadget"
-	# we don't support the SA1100 because of its limitations
-	depends on USB_GADGET_SA1100 = n
 	help
 	  The File-backed Storage Gadget acts as a USB Mass Storage
 	  disk drive.  As its storage repository it can use a regular
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,6 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
 
 
 /**
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -4,7 +4,7 @@
  * Maintainer: Alan Stern <stern@rowland.harvard.edu>
  *
  * Copyright (C) 2003 David Brownell
- * Copyright (C) 2003, 2004 Alan Stern
+ * Copyright (C) 2003-2005 Alan Stern
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -167,7 +167,6 @@ struct dummy {
 	 */
 	struct timer_list		timer;
 	u32				port_status;
-	unsigned			started:1;
 	unsigned			resuming:1;
 	unsigned long			re_timeout;
 
@@ -1637,7 +1636,6 @@ static int dummy_start (struct usb_hcd *
 	 * just like more familiar pci-based HCDs.
 	 */
 	spin_lock_init (&dum->lock);
-
 	init_timer (&dum->timer);
 	dum->timer.function = dummy_timer;
 	dum->timer.data = (unsigned long) dum;
@@ -1649,30 +1647,30 @@ static int dummy_start (struct usb_hcd *
 		return -ENOMEM;
 
 	/* root hub enters addressed state... */
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 	root->speed = USB_SPEED_HIGH;
 
 	/* ...then configured, so khubd sees us. */
-	if ((retval = hcd_register_root (root, hcd)) != 0) {
-		usb_put_dev (root);
-clean:
-		hcd->state = USB_STATE_QUIESCING;
-		return retval;
+	if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) {
+		goto err1;
 	}
 
 	/* only show a low-power port: just 8mA */
 	hub_set_power_budget (root, 8);
 
-	if ((retval = dummy_register_udc (dum)) != 0) {
-		usb_disconnect (&hcd->self.root_hub);
-		goto clean;
-	}
+	if ((retval = dummy_register_udc (dum)) != 0)
+		goto err2;
 
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
 	device_create_file (dummy_dev(dum), &dev_attr_urbs);
-
-	dum->started = 1;
 	return 0;
+
+ err2:
+	usb_disconnect (&hcd->self.root_hub);
+ err1:
+	usb_put_dev (root);
+	hcd->state = HC_STATE_QUIESCING;
+	return retval;
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
@@ -1680,9 +1678,6 @@ static void dummy_stop (struct usb_hcd *
 	struct dummy		*dum;
 
 	dum = hcd_to_dummy (hcd);
-	if (!dum->started)
-		return;
-	dum->started = 0;
 
 	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
 
@@ -1718,71 +1713,33 @@ static const struct hc_driver dummy_hcd 
 	.hub_control = 		dummy_hub_control,
 };
 
-static void dummy_remove (struct device *dev);
-
 static int dummy_probe (struct device *dev)
 {
 	struct usb_hcd		*hcd;
-	struct dummy		*dum;
 	int			retval;
 
 	dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-	hcd = usb_create_hcd (&dummy_hcd);
-	if (hcd == NULL) {
-		dev_dbg (dev, "hcd_alloc failed\n");
+	hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id);
+	if (!hcd)
 		return -ENOMEM;
-	}
+	the_controller = hcd_to_dummy (hcd);
 
-	dev_set_drvdata (dev, hcd);
-	dum = hcd_to_dummy (hcd);
-	the_controller = dum;
-
-	hcd->self.controller = dev;
-
-	/* FIXME don't require the pci-based buffer/alloc impls;
-	 * the "generic dma" implementation still requires them,
-	 * it's not very generic yet.
-	 */
-	retval = hcd_buffer_create (hcd);
+	retval = usb_add_hcd(hcd, 0, 0);
 	if (retval != 0) {
-		dev_dbg (dev, "pool alloc failed\n");
-		goto err1;
+		usb_put_hcd (hcd);
+		the_controller = NULL;
 	}
-
-	hcd->self.bus_name = dev->bus_id;
-	usb_register_bus (&hcd->self);
-
-	if ((retval = dummy_start (hcd)) < 0) 
-		dummy_remove (dev);
-	return retval;
-
-err1:
-	usb_put_hcd (hcd);
-	dev_set_drvdata (dev, NULL);
 	return retval;
 }
 
 static void dummy_remove (struct device *dev)
 {
 	struct usb_hcd		*hcd;
-	struct dummy		*dum;
 
 	hcd = dev_get_drvdata (dev);
-	dum = hcd_to_dummy (hcd);
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	dev_dbg (dev, "roothub graceful disconnect\n");
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	hcd_buffer_destroy (hcd);
-
-	dev_set_drvdata (dev, NULL);
-	usb_deregister_bus (&hcd->self);
+	usb_remove_hcd (hcd);
+	usb_put_hcd (hcd);
 	the_controller = NULL;
 }
 
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1,7 +1,7 @@
 /*
  * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2005 David Brownell
  * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
  *
  * This program is free software; you can redistribute it and/or modify
@@ -49,6 +49,7 @@
 #include <asm/unaligned.h>
 
 #include <linux/usb_ch9.h>
+#include <linux/usb_cdc.h>
 #include <linux/usb_gadget.h>
 
 #include <linux/random.h>
@@ -97,12 +98,20 @@ static const char driver_desc [] = DRIVE
 #define rndis_exit() do{}while(0)
 #endif
 
+/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
+#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
+ 			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+ 			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
+ 			|USB_CDC_PACKET_TYPE_DIRECTED)
+
+
 /*-------------------------------------------------------------------------*/
 
 struct eth_dev {
 	spinlock_t		lock;
 	struct usb_gadget	*gadget;
 	struct usb_request	*req;		/* for control responses */
+	struct usb_request	*stat_req;	/* for cdc & rndis status */
 
 	u8			config;
 	struct usb_ep		*in_ep, *out_ep, *status_ep;
@@ -198,7 +207,7 @@ MODULE_PARM_DESC(iProduct, "USB Product 
 /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
 static char *__initdata dev_addr;
 module_param(dev_addr, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "Device Ethernet Address");
+MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
 
 /* this address is invisible to ifconfig */
 static char *__initdata host_addr;
@@ -242,6 +251,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethern
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_AT91
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -259,11 +272,45 @@ MODULE_PARM_DESC(host_addr, "Host Ethern
 #define	DEV_CONFIG_SUBSET
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
 
 /*-------------------------------------------------------------------------*/
 
+/* "main" config is either CDC, or its simple subset */
+static inline int is_cdc(struct eth_dev *dev)
+{
+#if	!defined(DEV_CONFIG_SUBSET)
+	return 1;		/* only cdc possible */
+#elif	!defined (DEV_CONFIG_CDC)
+	return 0;		/* only subset possible */
+#else
+	return dev->cdc;	/* depends on what hardware we found */
+#endif
+}
+
+/* "secondary" RNDIS config may sometimes be activated */
+static inline int rndis_active(struct eth_dev *dev)
+{
+#ifdef	CONFIG_USB_ETH_RNDIS
+	return dev->rndis;
+#else
+	return 0;
+#endif
+}
+
+#define	subset_active(dev)	(!is_cdc(dev) && !rndis_active(dev))
+#define	cdc_active(dev)		( is_cdc(dev) && !rndis_active(dev))
+
+
+
 #define DEFAULT_QLEN	2	/* double buffering by default */
 
+/* peak bulk transfer bits-per-second */
+#define	HS_BPS 		(13 * 512 * 8 * 1000 * 8)
+#define	FS_BPS		(19 *  64 * 1 * 1000 * 8)
+
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 
 static unsigned qmult = 5;
@@ -277,12 +324,18 @@ module_param (qmult, uint, S_IRUGO|S_IWU
 /* also defer IRQs on highspeed TX */
 #define TX_DELAY	qmult
 
-#define	BITRATE(g) ((g->speed == USB_SPEED_HIGH) ? 4800000 : 120000)
+static inline int BITRATE(struct usb_gadget *g)
+{
+	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
+}
 
 #else	/* full speed (low speed doesn't do bulk) */
 #define qlen(gadget) DEFAULT_QLEN
 
-#define	BITRATE(g)	(12000)
+static inline int BITRATE(struct usb_gadget *g)
+{
+	return FS_BPS;
+}
 #endif
 
 
@@ -432,8 +485,8 @@ control_intf = {
 	/* status endpoint is optional; this may be patched later */
 	.bNumEndpoints =	1,
 	.bInterfaceClass =	USB_CLASS_COMM,
-	.bInterfaceSubClass =	6,	/* ethernet control model */
-	.bInterfaceProtocol =	0,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ETHERNET,
+	.bInterfaceProtocol =	USB_CDC_PROTO_NONE,
 	.iInterface =		STRING_CONTROL,
 };
 #endif
@@ -447,46 +500,26 @@ rndis_control_intf = {
 	.bInterfaceNumber =     0,
 	.bNumEndpoints =        1,
 	.bInterfaceClass =      USB_CLASS_COMM,
-	.bInterfaceSubClass =   2,	/* abstract control model */
-	.bInterfaceProtocol =   0xff,	/* vendor specific */
+	.bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+	.bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
 	.iInterface =           STRING_RNDIS_CONTROL,
 };
 #endif
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
-/* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
-struct header_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u16	bcdCDC;
-} __attribute__ ((packed));
-
-static const struct header_desc header_desc = {
+static const struct usb_cdc_header_desc header_desc = {
 	.bLength =		sizeof header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	0,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
 
 	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
 };
 
-/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
-struct union_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u8	bMasterInterface0;
-	u8	bSlaveInterface0;
-	/* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-static const struct union_desc union_desc = {
+static const struct usb_cdc_union_desc union_desc = {
 	.bLength =		sizeof union_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	6,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
 
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of DATA interface */
@@ -496,64 +529,31 @@ static const struct union_desc union_des
 
 #ifdef	CONFIG_USB_ETH_RNDIS
 
-/* "Call Management Descriptor" from CDC spec  5.2.3.3 */
-struct call_mgmt_descriptor {
-	u8  bLength;
-	u8  bDescriptorType;
-	u8  bDescriptorSubType;
-
-	u8  bmCapabilities;
-	u8  bDataInterface;
-} __attribute__ ((packed));
-
-static const struct call_mgmt_descriptor call_mgmt_descriptor = {
+static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
 	.bLength =  		sizeof call_mgmt_descriptor,
 	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	0x01,
+	.bDescriptorSubType = 	USB_CDC_CALL_MANAGEMENT_TYPE,
 
 	.bmCapabilities = 	0x00,
 	.bDataInterface = 	0x01,
 };
 
-
-/* "Abstract Control Management Descriptor" from CDC spec  5.2.3.4 */
-struct acm_descriptor {
-	u8  bLength;
-	u8  bDescriptorType;
-	u8  bDescriptorSubType;
-
-	u8  bmCapabilities;
-} __attribute__ ((packed));
-
-static struct acm_descriptor acm_descriptor = {
+static struct usb_cdc_acm_descriptor acm_descriptor = {
 	.bLength =  		sizeof acm_descriptor,
 	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	0x02,
+	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
 
-	.bmCapabilities = 	0X00,
+	.bmCapabilities = 	0x00,
 };
 
 #endif
 
 #ifdef	DEV_CONFIG_CDC
 
-/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
-struct ether_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u8	iMACAddress;
-	u32	bmEthernetStatistics;
-	u16	wMaxSegmentSize;
-	u16	wNumberMCFilters;
-	u8	bNumberPowerFilters;
-} __attribute__ ((packed));
-
-static const struct ether_desc ether_desc = {
+static const struct usb_cdc_ether_desc ether_desc = {
 	.bLength =		sizeof ether_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	0x0f,
+	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,
 
 	/* this descriptor actually adds value, surprise! */
 	.iMACAddress =		STRING_ETHADDR,
@@ -568,9 +568,8 @@ static const struct ether_desc ether_des
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
 /* include the status endpoint if we can, even where it's optional.
- * use small wMaxPacketSize, since many "interrupt" endpoints have
- * very small fifos and it's no big deal if CDC_NOTIFY_SPEED_CHANGE
- * takes two packets.  also default to a big transfer interval, to
+ * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
  * waste less bandwidth.
  *
  * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
@@ -583,7 +582,7 @@ static const struct ether_desc ether_des
  */
  
 #define LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
-#define STATUS_BYTECOUNT		8	/* 8 byte header + data */
+#define STATUS_BYTECOUNT		16	/* 8 byte header + data */
 
 static struct usb_endpoint_descriptor
 fs_status_desc = {
@@ -965,14 +964,12 @@ static inline int ether_alt_ep_setup (st
 	if (strcmp (ep->name, EP_IN_NAME) == 0) {
 		d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
 		ep->driver_data = dev;
-		dev->in_ep = ep;
 		dev->in = d;
 
 	/* one endpoint just reads OUT packets */
 	} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
 		d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
 		ep->driver_data = dev;
-		dev->out_ep = ep;
 		dev->out = d;
 
 	/* optional status/notification endpoint */
@@ -986,7 +983,6 @@ static inline int ether_alt_ep_setup (st
 			return result;
 
 		ep->driver_data = dev;
-		dev->status_ep = ep;
 		dev->status = d;
 	}
 	return 0;
@@ -1013,7 +1009,6 @@ static inline int ether_ep_setup (struct
 			return result;
 
 		ep->driver_data = dev;
-		dev->in_ep = ep;
 		dev->in = d;
 
 	/* one endpoint just reads OUT packets */
@@ -1024,7 +1019,6 @@ static inline int ether_ep_setup (struct
 			return result;
 
 		ep->driver_data = dev;
-		dev->out_ep = ep;
 		dev->out = d;
 	}
 
@@ -1055,7 +1049,6 @@ set_ether_config (struct eth_dev *dev, i
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				dev->status_ep = ep;
 				dev->status = d;
 				continue;
 			}
@@ -1083,22 +1076,19 @@ set_ether_config (struct eth_dev *dev, i
 	/* on error, disable any endpoints  */
 	if (result < 0) {
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-		if (dev->status_ep)
+		if (dev->status)
 			(void) usb_ep_disable (dev->status_ep);
 #endif
-		dev->status_ep = NULL;
 		dev->status = NULL;
 #if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
 		if (dev->rndis || !dev->cdc) {
-			if (dev->in_ep)
+			if (dev->in)
 				(void) usb_ep_disable (dev->in_ep);
-			if (dev->out_ep)
+			if (dev->out)
 				(void) usb_ep_disable (dev->out_ep);
 		}
 #endif
-		dev->in_ep = NULL;
 		dev->in = NULL;
-		dev->out_ep = NULL;
 		dev->out = NULL;
 	} else
 
@@ -1138,7 +1128,7 @@ static void eth_reset_config (struct eth
 	/* disable endpoints, forcing (synchronous) completion of
 	 * pending i/o.  then free the requests.
 	 */
-	if (dev->in_ep) {
+	if (dev->in) {
 		usb_ep_disable (dev->in_ep);
 		while (likely (!list_empty (&dev->tx_reqs))) {
 			req = container_of (dev->tx_reqs.next,
@@ -1146,9 +1136,8 @@ static void eth_reset_config (struct eth
 			list_del (&req->list);
 			usb_ep_free_request (dev->in_ep, req);
 		}
-		dev->in_ep = NULL;
 	}
-	if (dev->out_ep) {
+	if (dev->out) {
 		usb_ep_disable (dev->out_ep);
 		while (likely (!list_empty (&dev->rx_reqs))) {
 			req = container_of (dev->rx_reqs.next,
@@ -1156,12 +1145,10 @@ static void eth_reset_config (struct eth
 			list_del (&req->list);
 			usb_ep_free_request (dev->out_ep, req);
 		}
-		dev->out_ep = NULL;
 	}
 
-	if (dev->status_ep) {
+	if (dev->status) {
 		usb_ep_disable (dev->status_ep);
-		dev->status_ep = NULL;
 	}
 	dev->config = 0;
 }
@@ -1188,7 +1175,7 @@ eth_set_config (struct eth_dev *dev, uns
 	eth_reset_config (dev);
 
 	/* default:  pass all packets, no multicast filtering */
-	dev->cdc_filter = 0x000f;
+	dev->cdc_filter = DEFAULT_FILTER;
 
 	switch (number) {
 	case DEV_CONFIG_VALUE:
@@ -1242,67 +1229,44 @@ eth_set_config (struct eth_dev *dev, uns
 
 /*-------------------------------------------------------------------------*/
 
-/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
- * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
- * and RNDIS also defines its own bit-incompatible notifications
- */
-#define CDC_NOTIFY_NETWORK_CONNECTION	0x00	/* required; 6.3.1 */
-#define CDC_NOTIFY_RESPONSE_AVAILABLE	0x01	/* optional; 6.3.2 */
-#define CDC_NOTIFY_SPEED_CHANGE		0x2a	/* required; 6.3.8 */
-
 #ifdef	DEV_CONFIG_CDC
 
-struct cdc_notification {
-	u8	bmRequestType;
-	u8	bNotificationType;
-	u16	wValue;
-	u16	wIndex;
-	u16	wLength;
-
-	/* SPEED_CHANGE data looks like this */
-	u32	data [2];
-};
-
 static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
 {
-	struct cdc_notification	*event = req->buf;
-	int			value = req->status;
-	struct eth_dev		*dev = ep->driver_data;
+	struct usb_cdc_notification	*event = req->buf;
+	int				value = req->status;
+	struct eth_dev			*dev = ep->driver_data;
 
 	/* issue the second notification if host reads the first */
-	if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION
+	if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION
 			&& value == 0) {
+		__le32	*data = req->buf + sizeof *event;
+
 		event->bmRequestType = 0xA1;
-		event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE;
+		event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
 		event->wValue = __constant_cpu_to_le16 (0);
 		event->wIndex = __constant_cpu_to_le16 (1);
 		event->wLength = __constant_cpu_to_le16 (8);
 
 		/* SPEED_CHANGE data is up/down speeds in bits/sec */
-		event->data [0] = event->data [1] =
-			(dev->gadget->speed == USB_SPEED_HIGH)
-				? (13 * 512 * 8 * 1000 * 8)
-				: (19 *  64 * 1 * 1000 * 8);
+		data [0] = data [1] = cpu_to_le32 (BITRATE (dev->gadget));
 
-		req->length = 16;
+		req->length = STATUS_BYTECOUNT;
 		value = usb_ep_queue (ep, req, GFP_ATOMIC);
 		DEBUG (dev, "send SPEED_CHANGE --> %d\n", value);
 		if (value == 0)
 			return;
-	} else
+	} else if (value != -ECONNRESET)
 		DEBUG (dev, "event %02x --> %d\n",
 			event->bNotificationType, value);
-
-	/* free when done */
-	usb_ep_free_buffer (ep, req->buf, req->dma, 16);
-	usb_ep_free_request (ep, req);
+	event->bmRequestType = 0xff;
 }
 
 static void issue_start_status (struct eth_dev *dev)
 {
-	struct usb_request	*req;
-	struct cdc_notification	*event;
-	int			value;
+	struct usb_request		*req = dev->stat_req;
+	struct usb_cdc_notification	*event;
+	int				value;
  
 	DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
 
@@ -1316,40 +1280,21 @@ static void issue_start_status (struct e
 	usb_ep_disable (dev->status_ep);
 	usb_ep_enable (dev->status_ep, dev->status);
 
-	/* FIXME make these allocations static like dev->req */
-	req = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
-	if (req == 0) {
-		DEBUG (dev, "status ENOMEM\n");
-		return;
-	}
-	req->buf = usb_ep_alloc_buffer (dev->status_ep, 16,
-				&dev->req->dma, GFP_ATOMIC);
-	if (req->buf == 0) {
-		DEBUG (dev, "status buf ENOMEM\n");
-free_req:
-		usb_ep_free_request (dev->status_ep, req);
-		return;
-	}
-
 	/* 3.8.1 says to issue first NETWORK_CONNECTION, then
 	 * a SPEED_CHANGE.  could be useful in some configs.
 	 */
 	event = req->buf;
 	event->bmRequestType = 0xA1;
-	event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION;
+	event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
 	event->wValue = __constant_cpu_to_le16 (1);	/* connected */
 	event->wIndex = __constant_cpu_to_le16 (1);
 	event->wLength = 0;
 
-	req->length = 8;
+	req->length = sizeof *event;
 	req->complete = eth_status_complete;
 	value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
-	if (value < 0) {
+	if (value < 0)
 		DEBUG (dev, "status buf queue --> %d\n", value);
-		usb_ep_free_buffer (dev->status_ep,
-				req->buf, dev->req->dma, 16);
-		goto free_req;
-	}
 }
 
 #endif
@@ -1364,26 +1309,6 @@ static void eth_setup_complete (struct u
 				req->status, req->actual, req->length);
 }
 
-/* see section 3.8.2 table 10 of the CDC spec for more ethernet
- * requests, mostly for filters (multicast, pm) and statistics
- * section 3.6.2.1 table 4 has ACM requests; RNDIS requires the
- * encapsulated command mechanism.
- */
-#define CDC_SEND_ENCAPSULATED_COMMAND		0x00	/* optional */
-#define CDC_GET_ENCAPSULATED_RESPONSE		0x01	/* optional */
-#define CDC_SET_ETHERNET_MULTICAST_FILTERS	0x40	/* optional */
-#define CDC_SET_ETHERNET_PM_PATTERN_FILTER	0x41	/* optional */
-#define CDC_GET_ETHERNET_PM_PATTERN_FILTER	0x42	/* optional */
-#define CDC_SET_ETHERNET_PACKET_FILTER		0x43	/* required */
-#define CDC_GET_ETHERNET_STATISTIC		0x44	/* optional */
-
-/* table 62; bits in cdc_filter */
-#define	CDC_PACKET_TYPE_PROMISCUOUS		(1 << 0)
-#define	CDC_PACKET_TYPE_ALL_MULTICAST		(1 << 1) /* no filter */
-#define	CDC_PACKET_TYPE_DIRECTED		(1 << 2)
-#define	CDC_PACKET_TYPE_BROADCAST		(1 << 3)
-#define	CDC_PACKET_TYPE_MULTICAST		(1 << 4) /* filtered */
-
 #ifdef CONFIG_USB_ETH_RNDIS
 
 static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
@@ -1393,7 +1318,7 @@ static void rndis_response_complete (str
 			"rndis response complete --> %d, %d/%d\n",
 			req->status, req->actual, req->length);
 
-	/* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
+	/* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */
 }
 
 static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
@@ -1401,7 +1326,7 @@ static void rndis_command_complete (stru
 	struct eth_dev          *dev = ep->driver_data;
 	int			status;
 	
-	/* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */
+	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 	spin_lock(&dev->lock);
 	status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
 	if (status < 0)
@@ -1426,6 +1351,9 @@ eth_setup (struct usb_gadget *gadget, co
 	struct eth_dev		*dev = get_gadget_data (gadget);
 	struct usb_request	*req = dev->req;
 	int			value = -EOPNOTSUPP;
+	u16			wIndex = (__force u16) ctrl->wIndex;
+	u16			wValue = (__force u16) ctrl->wValue;
+	u16			wLength = (__force u16) ctrl->wLength;
 
 	/* descriptors just go into the pre-allocated ep0 buffer,
 	 * while config change events may enable network traffic.
@@ -1436,17 +1364,17 @@ eth_setup (struct usb_gadget *gadget, co
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			break;
-		switch (ctrl->wValue >> 8) {
+		switch (wValue >> 8) {
 
 		case USB_DT_DEVICE:
-			value = min (ctrl->wLength, (u16) sizeof device_desc);
+			value = min (wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			if (!gadget->is_dualspeed)
 				break;
-			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+			value = min (wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
@@ -1457,18 +1385,18 @@ eth_setup (struct usb_gadget *gadget, co
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget->speed, req->buf,
-					ctrl->wValue >> 8,
-					ctrl->wValue & 0xff,
+					wValue >> 8,
+					wValue & 0xff,
 					gadget->is_otg);
 			if (value >= 0)
-				value = min (ctrl->wLength, (u16) value);
+				value = min (wLength, (u16) value);
 			break;
 
 		case USB_DT_STRING:
 			value = usb_gadget_get_string (&stringtab,
-					ctrl->wValue & 0xff, req->buf);
+					wValue & 0xff, req->buf);
 			if (value >= 0)
-				value = min (ctrl->wLength, (u16) value);
+				value = min (wLength, (u16) value);
 			break;
 		}
 		break;
@@ -1481,22 +1409,22 @@ eth_setup (struct usb_gadget *gadget, co
 		else if (gadget->a_alt_hnp_support)
 			DEBUG (dev, "HNP needs a different root port\n");
 		spin_lock (&dev->lock);
-		value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+		value = eth_set_config (dev, wValue, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			break;
 		*(u8 *)req->buf = dev->config;
-		value = min (ctrl->wLength, (u16) 1);
+		value = min (wLength, (u16) 1);
 		break;
 
 	case USB_REQ_SET_INTERFACE:
 		if (ctrl->bRequestType != USB_RECIP_INTERFACE
 				|| !dev->config
-				|| ctrl->wIndex > 1)
+				|| wIndex > 1)
 			break;
-		if (!dev->cdc && ctrl->wIndex != 0)
+		if (!dev->cdc && wIndex != 0)
 			break;
 		spin_lock (&dev->lock);
 
@@ -1510,18 +1438,18 @@ eth_setup (struct usb_gadget *gadget, co
 		}
 
 #ifdef DEV_CONFIG_CDC
-		switch (ctrl->wIndex) {
+		switch (wIndex) {
 		case 0:		/* control/master intf */
-			if (ctrl->wValue != 0)
+			if (wValue != 0)
 				break;
-			if (dev->status_ep) {
+			if (dev->status) {
 				usb_ep_disable (dev->status_ep);
 				usb_ep_enable (dev->status_ep, dev->status);
 			}
 			value = 0;
 			break;
 		case 1:		/* data intf */
-			if (ctrl->wValue > 1)
+			if (wValue > 1)
 				break;
 			usb_ep_disable (dev->in_ep);
 			usb_ep_disable (dev->out_ep);
@@ -1530,11 +1458,12 @@ eth_setup (struct usb_gadget *gadget, co
 			 * the default interface setting ... also, setting
 			 * the non-default interface clears filters etc.
 			 */
-			if (ctrl->wValue == 1) {
+			if (wValue == 1) {
 				usb_ep_enable (dev->in_ep, dev->in);
 				usb_ep_enable (dev->out_ep, dev->out);
+				dev->cdc_filter = DEFAULT_FILTER;
 				netif_carrier_on (dev->net);
-				if (dev->status_ep)
+				if (dev->status)
 					issue_start_status (dev);
 				if (netif_running (dev->net)) {
 					spin_unlock (&dev->lock);
@@ -1561,66 +1490,70 @@ done_set_intf:
 	case USB_REQ_GET_INTERFACE:
 		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
 				|| !dev->config
-				|| ctrl->wIndex > 1)
+				|| wIndex > 1)
 			break;
-		if (!(dev->cdc || dev->rndis) && ctrl->wIndex != 0)
+		if (!(dev->cdc || dev->rndis) && wIndex != 0)
 			break;
 
 		/* for CDC, iff carrier is on, data interface is active. */
-		if (dev->rndis || ctrl->wIndex != 1)
+		if (dev->rndis || wIndex != 1)
 			*(u8 *)req->buf = 0;
 		else
 			*(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
-		value = min (ctrl->wLength, (u16) 1);
+		value = min (wLength, (u16) 1);
 		break;
 
 #ifdef DEV_CONFIG_CDC
-	case CDC_SET_ETHERNET_PACKET_FILTER:
+	case USB_CDC_SET_ETHERNET_PACKET_FILTER:
 		/* see 6.2.30: no data, wIndex = interface,
 		 * wValue = packet filter bitmap
 		 */
 		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
 				|| !dev->cdc
 				|| dev->rndis
-				|| ctrl->wLength != 0
-				|| ctrl->wIndex > 1)
+				|| wLength != 0
+				|| wIndex > 1)
 			break;
-		DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue);
-		/* NOTE: table 62 has 5 filter bits to reduce traffic,
-		 * and we "must" support multicast and promiscuous.
-		 * this NOP implements a bad filter (always promisc)
-		 */
-		dev->cdc_filter = ctrl->wValue;
+		DEBUG (dev, "packet filter %02x\n", wValue);
+		dev->cdc_filter = wValue;
 		value = 0;
 		break;
+
+	/* and potentially:
+	 * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+	 * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+	 * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+	 * case USB_CDC_GET_ETHERNET_STATISTIC:
+	 */
+
 #endif /* DEV_CONFIG_CDC */
 
 #ifdef CONFIG_USB_ETH_RNDIS		
 	/* RNDIS uses the CDC command encapsulation mechanism to implement
 	 * an RPC scheme, with much getting/setting of attributes by OID.
 	 */
-	case CDC_SEND_ENCAPSULATED_COMMAND:
+	case USB_CDC_SEND_ENCAPSULATED_COMMAND:
 		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
 				|| !dev->rndis
-				|| ctrl->wLength > USB_BUFSIZ
-				|| ctrl->wValue
+				|| wLength > USB_BUFSIZ
+				|| wValue
 				|| rndis_control_intf.bInterfaceNumber
-					!= ctrl->wIndex)
+					!= wIndex)
 			break;
 		/* read the request, then process it */
-		value = ctrl->wLength;
+		value = wLength;
 		req->complete = rndis_command_complete;
 		/* later, rndis_control_ack () sends a notification */
 		break;
 		
-	case CDC_GET_ENCAPSULATED_RESPONSE:
+	case USB_CDC_GET_ENCAPSULATED_RESPONSE:
 		if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
 					== ctrl->bRequestType
 				&& dev->rndis
-				// && ctrl->wLength >= 0x0400
-				&& !ctrl->wValue
+				// && wLength >= 0x0400
+				&& !wValue
 				&& rndis_control_intf.bInterfaceNumber
-					== ctrl->wIndex) {
+					== wIndex) {
 			u8 *buf;
 
 			/* return the result */
@@ -1640,13 +1573,13 @@ done_set_intf:
 		VDEBUG (dev,
 			"unknown control req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+			wValue, wIndex, wLength);
 	}
 
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
-		req->zero = value < ctrl->wLength
+		req->zero = value < wLength
 				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
@@ -1761,10 +1694,16 @@ rx_submit (struct eth_dev *dev, struct u
 #endif	
 	size -= size % dev->out_ep->maxpacket;
 
-	if ((skb = alloc_skb (size, gfp_flags)) == 0) {
+	if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
 		DEBUG (dev, "no rx skb\n");
 		goto enomem;
 	}
+	
+	/* Some platforms perform better when IP packets are aligned,
+	 * but on at least one, checksumming fails otherwise.  Note:
+	 * RNDIS headers involve variable numbers of LE32 values.
+	 */
+	skb_reserve(skb, NET_IP_ALIGN);
 
 	req->buf = skb->data;
 	req->length = size;
@@ -1799,9 +1738,11 @@ static void rx_complete (struct usb_ep *
 #ifdef CONFIG_USB_ETH_RNDIS
 		/* we know MaxPacketsPerTransfer == 1 here */
 		if (dev->rndis)
-			rndis_rm_hdr (req->buf, &(skb->len));
+			status = rndis_rm_hdr (skb);
 #endif
-		if (ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) {
+		if (status < 0
+				|| ETH_HLEN > skb->len
+				|| skb->len > ETH_FRAME_LEN) {
 			dev->stats.rx_errors++;
 			dev->stats.rx_length_errors++;
 			DEBUG (dev, "rx length %d\n", skb->len);
@@ -1981,6 +1922,14 @@ static void tx_complete (struct usb_ep *
 		netif_wake_queue (dev->net);
 }
 
+static inline int eth_is_promisc (struct eth_dev *dev)
+{
+	/* no filters for the CDC subset; always promisc */
+	if (subset_active (dev))
+		return 1;
+	return dev->cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+}
+
 static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
 	struct eth_dev		*dev = netdev_priv(net);
@@ -1989,10 +1938,27 @@ static int eth_start_xmit (struct sk_buf
 	struct usb_request	*req = NULL;
 	unsigned long		flags;
 
-	/* FIXME check dev->cdc_filter to decide whether to send this,
-	 * instead of acting as if CDC_PACKET_TYPE_PROMISCUOUS were
-	 * always set.  RNDIS has the same kind of outgoing filter.
-	 */
+	/* apply outgoing CDC or RNDIS filters */
+	if (!eth_is_promisc (dev)) {
+		u8		*dest = skb->data;
+
+		if (dest [0] & 0x01) {
+			u16	type;
+
+			/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+			 * SET_ETHERNET_MULTICAST_FILTERS requests
+			 */
+			if (memcmp (dest, net->broadcast, ETH_ALEN) == 0)
+				type = USB_CDC_PACKET_TYPE_BROADCAST;
+			else
+				type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+			if (!(dev->cdc_filter & type)) {
+				dev_kfree_skb_any (skb);
+				return 0;
+			}
+		}
+		/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+	}
 
 	spin_lock_irqsave (&dev->lock, flags);
 	req = container_of (dev->tx_reqs.next, struct usb_request, list);
@@ -2091,46 +2057,28 @@ rndis_control_ack_complete (struct usb_e
 		DEBUG ((struct eth_dev *) ep->driver_data,
 			"rndis control ack complete --> %d, %d/%d\n",
 			req->status, req->actual, req->length);
-
-	usb_ep_free_buffer(ep, req->buf, req->dma, 8);
-	usb_ep_free_request(ep, req);
 }
 
 static int rndis_control_ack (struct net_device *net)
 {
 	struct eth_dev          *dev = netdev_priv(net);
 	u32                     length;
-	struct usb_request      *resp;
+	struct usb_request      *resp = dev->stat_req;
 	
 	/* in case RNDIS calls this after disconnect */
-	if (!dev->status_ep) {
+	if (!dev->status) {
 		DEBUG (dev, "status ENODEV\n");
 		return -ENODEV;
 	}
 
-	/* Allocate memory for notification ie. ACK */
-	resp = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
-	if (!resp) {
-		DEBUG (dev, "status ENOMEM\n");
-		return -ENOMEM;
-	}
-	
-	resp->buf = usb_ep_alloc_buffer (dev->status_ep, 8,
-					 &resp->dma, GFP_ATOMIC);
-	if (!resp->buf) {
-		DEBUG (dev, "status buf ENOMEM\n");
-		usb_ep_free_request (dev->status_ep, resp);
-		return -ENOMEM;
-	}
-	
 	/* Send RNDIS RESPONSE_AVAILABLE notification;
-	 * CDC_NOTIFY_RESPONSE_AVAILABLE should work too
+	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
 	 */
 	resp->length = 8;
 	resp->complete = rndis_control_ack_complete;
 	
-	*((u32 *) resp->buf) = __constant_cpu_to_le32 (1);
-	*((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
+	*((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
+	*((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
 	
 	length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);
 	if (length < 0) {
@@ -2157,7 +2105,7 @@ static void eth_start (struct eth_dev *d
 	if (dev->rndis) {
 		rndis_set_param_medium (dev->rndis_config,
 					NDIS_MEDIUM_802_3,
-					BITRATE(dev->gadget));
+					BITRATE(dev->gadget)/100);
 		rndis_send_media_state (dev, 1);
 	}
 #endif	
@@ -2214,6 +2162,30 @@ static int eth_stop (struct net_device *
 
 /*-------------------------------------------------------------------------*/
 
+static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size)
+{
+	struct usb_request	*req;
+
+	req = usb_ep_alloc_request (ep, GFP_KERNEL);
+	if (!req)
+		return NULL;
+
+	req->buf = kmalloc (size, GFP_KERNEL);
+	if (!req->buf) {
+		usb_ep_free_request (ep, req);
+		req = NULL;
+	}
+	return req;
+}
+
+static void
+eth_req_free (struct usb_ep *ep, struct usb_request *req)
+{
+	kfree (req->buf);
+	usb_ep_free_request (ep, req);
+}
+
+
 static void
 eth_unbind (struct usb_gadget *gadget)
 {
@@ -2227,12 +2199,13 @@ eth_unbind (struct usb_gadget *gadget)
 
 	/* we've already been disconnected ... no i/o is active */
 	if (dev->req) {
-		usb_ep_free_buffer (gadget->ep0,
-				dev->req->buf, dev->req->dma,
-				USB_BUFSIZ);
-		usb_ep_free_request (gadget->ep0, dev->req);
+		eth_req_free (gadget->ep0, dev->req);
 		dev->req = NULL;
 	}
+	if (dev->stat_req) {
+		eth_req_free (dev->status_ep, dev->stat_req);
+		dev->stat_req = NULL;
+	}
 
 	unregister_netdev (dev->net);
 	free_netdev(dev->net);
@@ -2278,7 +2251,7 @@ eth_bind (struct usb_gadget *gadget)
 	struct eth_dev		*dev;
 	struct net_device	*net;
 	u8			cdc = 1, zlp = 1, rndis = 1;
-	struct usb_ep		*ep;
+	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
 	int			status = -ENOMEM;
 
 	/* these flags are only ever cleared; compiler take note */
@@ -2326,6 +2299,10 @@ eth_bind (struct usb_gadget *gadget)
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
 	} else if (gadget_is_pxa27x(gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+	} else if (gadget_is_s3c2410(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
+	} else if (gadget_is_at91(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
 	} else {
 		/* can't assume CDC works.  don't want to default to
 		 * anything less functional on CDC-capable hardware,
@@ -2383,40 +2360,43 @@ eth_bind (struct usb_gadget *gadget)
 
 	/* all we really need is bulk IN/OUT */
 	usb_ep_autoconfig_reset (gadget);
-	ep = usb_ep_autoconfig (gadget, &fs_source_desc);
-	if (!ep) {
+	in_ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+	if (!in_ep) {
 autoconf_fail:
 		dev_err (&gadget->dev,
 			"can't autoconfigure on %s\n",
 			gadget->name);
 		return -ENODEV;
 	}
-	EP_IN_NAME = ep->name;
-	ep->driver_data = ep;	/* claim */
+	EP_IN_NAME = in_ep->name;
+	in_ep->driver_data = in_ep;	/* claim */
 	
-	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
-	if (!ep)
+	out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+	if (!out_ep)
 		goto autoconf_fail;
-	EP_OUT_NAME = ep->name;
-	ep->driver_data = ep;	/* claim */
+	EP_OUT_NAME = out_ep->name;
+	out_ep->driver_data = out_ep;	/* claim */
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 	/* CDC Ethernet control interface doesn't require a status endpoint.
 	 * Since some hosts expect one, try to allocate one anyway.
 	 */
 	if (cdc || rndis) {
-		ep = usb_ep_autoconfig (gadget, &fs_status_desc);
-		if (ep) {
-			EP_STATUS_NAME = ep->name;
-			ep->driver_data = ep;	/* claim */
+		status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
+		if (status_ep) {
+			EP_STATUS_NAME = status_ep->name;
+			status_ep->driver_data = status_ep;	/* claim */
 		} else if (rndis) {
 			dev_err (&gadget->dev,
 				"can't run RNDIS on %s\n",
 				gadget->name);
 			return -ENODEV;
+#ifdef DEV_CONFIG_CDC
+		/* pxa25x only does CDC subset; often used with RNDIS */
 		} else if (cdc) {
 			control_intf.bNumEndpoints = 0;
 			/* FIXME remove endpoint from descriptor list */
+#endif
 		}
 	}
 #endif
@@ -2481,6 +2461,10 @@ autoconf_fail:
 	dev->cdc = cdc;
 	dev->zlp = zlp;
 
+	dev->in_ep = in_ep;
+	dev->out_ep = out_ep;
+	dev->status_ep = status_ep;
+
 	/* Module params for these addresses should come from ID proms.
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * ends up in a persistent config database.
@@ -2514,16 +2498,20 @@ autoconf_fail:
 	// set_multicast_list
 	SET_ETHTOOL_OPS(net, &ops);
 
-	/* preallocate control response and buffer */
-	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+	/* preallocate control message data and buffer */
+	dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ);
 	if (!dev->req)
 		goto fail;
 	dev->req->complete = eth_setup_complete;
-	dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
-				&dev->req->dma, GFP_KERNEL);
-	if (!dev->req->buf) {
-		usb_ep_free_request (gadget->ep0, dev->req);
-		goto fail;
+
+	/* ... and maybe likewise for status transfer */
+	if (dev->status_ep) {
+		dev->stat_req = eth_req_alloc (dev->status_ep,
+					STATUS_BYTECOUNT);
+		if (!dev->stat_req) {
+			eth_req_free (gadget->ep0, dev->req);
+			goto fail;
+		}
 	}
 
 	/* finish hookup to lower layer ... */
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
 /*
  * file_storage.c -- File-backed USB Storage Gadget, for USB development
  *
- * Copyright (C) 2003, 2004 Alan Stern
+ * Copyright (C) 2003-2005 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -832,6 +832,8 @@ static void inline put_be32(u8 *buf, u32
 #define STRING_MANUFACTURER	1
 #define STRING_PRODUCT		2
 #define STRING_SERIAL		3
+#define STRING_CONFIG		4
+#define STRING_INTERFACE	5
 
 /* There is only one configuration. */
 #define	CONFIG_VALUE		1
@@ -863,6 +865,7 @@ config_desc = {
 	/* wTotalLength computed by usb_gadget_config_buf() */
 	.bNumInterfaces =	1,
 	.bConfigurationValue =	CONFIG_VALUE,
+	.iConfiguration =	STRING_CONFIG,
 	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 	.bMaxPower =		1,	// self-powered
 };
@@ -886,6 +889,7 @@ intf_desc = {
 	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
 	.bInterfaceSubClass =	USB_SC_SCSI,	// Adjusted during fsg_bind()
 	.bInterfaceProtocol =	USB_PR_BULK,	// Adjusted during fsg_bind()
+	.iInterface =		STRING_INTERFACE,
 };
 
 /* Three full-speed endpoint descriptors: bulk-in, bulk-out,
@@ -1009,7 +1013,7 @@ static const struct usb_descriptor_heade
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
  * characters. */
-static char				manufacturer[50];
+static char				manufacturer[64];
 static char				serial[13];
 
 /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
@@ -1017,6 +1021,8 @@ static struct usb_string		strings[] = {
 	{STRING_MANUFACTURER,	manufacturer},
 	{STRING_PRODUCT,	longname},
 	{STRING_SERIAL,		serial},
+	{STRING_CONFIG,		"Self-powered"},
+	{STRING_INTERFACE,	"Mass Storage"},
 	{}
 };
 
@@ -1270,6 +1276,8 @@ static int class_setup_req(struct fsg_de
 {
 	struct usb_request	*req = fsg->ep0req;
 	int			value = -EOPNOTSUPP;
+	u16			w_index = ctrl->wIndex;
+	u16			w_length = ctrl->wLength;
 
 	if (!fsg->config)
 		return value;
@@ -1282,7 +1290,7 @@ static int class_setup_req(struct fsg_de
 			if (ctrl->bRequestType != (USB_DIR_OUT |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (ctrl->wIndex != 0) {
+			if (w_index != 0) {
 				value = -EDOM;
 				break;
 			}
@@ -1298,13 +1306,13 @@ static int class_setup_req(struct fsg_de
 			if (ctrl->bRequestType != (USB_DIR_IN |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (ctrl->wIndex != 0) {
+			if (w_index != 0) {
 				value = -EDOM;
 				break;
 			}
 			VDBG(fsg, "get max LUN\n");
 			*(u8 *) req->buf = fsg->nluns - 1;
-			value = min(ctrl->wLength, (u16) 1);
+			value = min(w_length, (u16) 1);
 			break;
 		}
 	}
@@ -1317,15 +1325,15 @@ static int class_setup_req(struct fsg_de
 			if (ctrl->bRequestType != (USB_DIR_OUT |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (ctrl->wIndex != 0) {
+			if (w_index != 0) {
 				value = -EDOM;
 				break;
 			}
-			if (ctrl->wLength > MAX_COMMAND_SIZE) {
+			if (w_length > MAX_COMMAND_SIZE) {
 				value = -EOVERFLOW;
 				break;
 			}
-			value = ctrl->wLength;
+			value = w_length;
 			fsg->ep0req->context = received_cbi_adsc;
 			break;
 		}
@@ -1336,7 +1344,7 @@ static int class_setup_req(struct fsg_de
 			"unknown class-specific control req "
 			"%02x.%02x v%04x i%04x l%u\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+			ctrl->wValue, w_index, w_length);
 	return value;
 }
 
@@ -1350,6 +1358,9 @@ static int standard_setup_req(struct fsg
 {
 	struct usb_request	*req = fsg->ep0req;
 	int			value = -EOPNOTSUPP;
+	u16			w_index = ctrl->wIndex;
+	u16			w_value = ctrl->wValue;
+	u16			w_length = ctrl->wLength;
 
 	/* Usually this just stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will also reconfigure hardware. */
@@ -1359,11 +1370,11 @@ static int standard_setup_req(struct fsg
 		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
 				USB_RECIP_DEVICE))
 			break;
-		switch (ctrl->wValue >> 8) {
+		switch (w_value >> 8) {
 
 		case USB_DT_DEVICE:
 			VDBG(fsg, "get device descriptor\n");
-			value = min(ctrl->wLength, (u16) sizeof device_desc);
+			value = min(w_length, (u16) sizeof device_desc);
 			memcpy(req->buf, &device_desc, value);
 			break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -1371,7 +1382,7 @@ static int standard_setup_req(struct fsg
 			VDBG(fsg, "get device qualifier\n");
 			if (!fsg->gadget->is_dualspeed)
 				break;
-			value = min(ctrl->wLength, (u16) sizeof dev_qualifier);
+			value = min(w_length, (u16) sizeof dev_qualifier);
 			memcpy(req->buf, &dev_qualifier, value);
 			break;
 
@@ -1388,10 +1399,10 @@ static int standard_setup_req(struct fsg
 #endif
 			value = populate_config_buf(fsg->gadget,
 					req->buf,
-					ctrl->wValue >> 8,
-					ctrl->wValue & 0xff);
+					w_value >> 8,
+					w_value & 0xff);
 			if (value >= 0)
-				value = min(ctrl->wLength, (u16) value);
+				value = min(w_length, (u16) value);
 			break;
 
 		case USB_DT_STRING:
@@ -1399,9 +1410,9 @@ static int standard_setup_req(struct fsg
 
 			/* wIndex == language code */
 			value = usb_gadget_get_string(&stringtab,
-					ctrl->wValue & 0xff, req->buf);
+					w_value & 0xff, req->buf);
 			if (value >= 0)
-				value = min(ctrl->wLength, (u16) value);
+				value = min(w_length, (u16) value);
 			break;
 		}
 		break;
@@ -1412,8 +1423,8 @@ static int standard_setup_req(struct fsg
 				USB_RECIP_DEVICE))
 			break;
 		VDBG(fsg, "set configuration\n");
-		if (ctrl->wValue == CONFIG_VALUE || ctrl->wValue == 0) {
-			fsg->new_config = ctrl->wValue;
+		if (w_value == CONFIG_VALUE || w_value == 0) {
+			fsg->new_config = w_value;
 
 			/* Raise an exception to wipe out previous transaction
 			 * state (queued bufs, etc) and set the new config. */
@@ -1427,14 +1438,14 @@ static int standard_setup_req(struct fsg
 			break;
 		VDBG(fsg, "get configuration\n");
 		*(u8 *) req->buf = fsg->config;
-		value = min(ctrl->wLength, (u16) 1);
+		value = min(w_length, (u16) 1);
 		break;
 
 	case USB_REQ_SET_INTERFACE:
 		if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
 				USB_RECIP_INTERFACE))
 			break;
-		if (fsg->config && ctrl->wIndex == 0) {
+		if (fsg->config && w_index == 0) {
 
 			/* Raise an exception to wipe out previous transaction
 			 * state (queued bufs, etc) and install the new
@@ -1449,20 +1460,20 @@ static int standard_setup_req(struct fsg
 			break;
 		if (!fsg->config)
 			break;
-		if (ctrl->wIndex != 0) {
+		if (w_index != 0) {
 			value = -EDOM;
 			break;
 		}
 		VDBG(fsg, "get interface\n");
 		*(u8 *) req->buf = 0;
-		value = min(ctrl->wLength, (u16) 1);
+		value = min(w_length, (u16) 1);
 		break;
 
 	default:
 		VDBG(fsg,
 			"unknown control req %02x.%02x v%04x i%04x l%u\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+			w_value, w_index, w_length);
 	}
 
 	return value;
@@ -3740,6 +3751,10 @@ static int __init check_parameters(struc
 			mod_data.release = 0x0310;
 		else if (gadget_is_pxa27x(fsg->gadget))
 			mod_data.release = 0x0311;
+		else if (gadget_is_s3c2410(gadget))
+			mod_data.release = 0x0312;
+		else if (gadget_is_at91(fsg->gadget))
+			mod_data.release = 0x0313;
 		else {
 			WARN(fsg, "controller '%s' not recognized\n",
 				fsg->gadget->name);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -74,7 +74,18 @@
 #define	gadget_is_pxa27x(g)	0
 #endif
 
-// CONFIG_USB_GADGET_AT91RM9200
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
+#else
+#define gadget_is_s3c2410(g)    0
+#endif
+
+#ifdef CONFIG_USB_GADGET_AT91
+#define gadget_is_at91(g)	!strcmp("at91_udc", (g)->name)
+#else
+#define gadget_is_at91(g)	0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // ...
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -275,7 +275,7 @@ static const char *CHIP;
  *
  * After opening, configure non-control endpoints.  Then use normal
  * stream read() and write() requests; and maybe ioctl() to get more
- * precise FIFO status when recovering from cancelation.
+ * precise FIFO status when recovering from cancellation.
  */
 
 static void epio_complete (struct usb_ep *ep, struct usb_request *req)
@@ -1318,6 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadge
 	struct usb_request		*req = dev->req;
 	int				value = -EOPNOTSUPP;
 	struct usb_gadgetfs_event	*event;
+	u16				w_value = ctrl->wValue;
+	u16				w_length = ctrl->wLength;
 
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
@@ -1378,17 +1380,17 @@ gadgetfs_setup (struct usb_gadget *gadge
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			goto unrecognized;
-		switch (ctrl->wValue >> 8) {
+		switch (w_value >> 8) {
 
 		case USB_DT_DEVICE:
-			value = min (ctrl->wLength, (u16) sizeof *dev->dev);
+			value = min (w_length, (u16) sizeof *dev->dev);
 			req->buf = dev->dev;
 			break;
 #ifdef	HIGHSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			if (!dev->hs_config)
 				break;
-			value = min (ctrl->wLength, (u16)
+			value = min (w_length, (u16)
 				sizeof (struct usb_qualifier_descriptor));
 			make_qualifier (dev);
 			break;
@@ -1397,10 +1399,10 @@ gadgetfs_setup (struct usb_gadget *gadge
 #endif
 		case USB_DT_CONFIG:
 			value = config_buf (dev,
-					ctrl->wValue >> 8,
-					ctrl->wValue & 0xff);
+					w_value >> 8,
+					w_value & 0xff);
 			if (value >= 0)
-				value = min (ctrl->wLength, (u16) value);
+				value = min (w_length, (u16) value);
 			break;
 		case USB_DT_STRING:
 			goto unrecognized;
@@ -1414,7 +1416,7 @@ gadgetfs_setup (struct usb_gadget *gadge
 	case USB_REQ_SET_CONFIGURATION:
 		if (ctrl->bRequestType != 0)
 			break;
-		if (0 == (u8) ctrl->wValue) {
+		if (0 == (u8) w_value) {
 			value = 0;
 			dev->current_config = 0;
 			usb_gadget_vbus_draw(gadget, 8 /* mA */ );
@@ -1432,7 +1434,7 @@ gadgetfs_setup (struct usb_gadget *gadge
 				power = dev->config->bMaxPower;
 			}
 
-			if (config == (u8) ctrl->wValue) {
+			if (config == (u8) w_value) {
 				value = 0;
 				dev->current_config = config;
 				usb_gadget_vbus_draw(gadget, 2 * power);
@@ -1463,7 +1465,7 @@ gadgetfs_setup (struct usb_gadget *gadge
 		if (ctrl->bRequestType != 0x80)
 			break;
 		*(u8 *)req->buf = dev->current_config;
-		value = min (ctrl->wLength, (u16) 1);
+		value = min (w_length, (u16) 1);
 		break;
 #endif
 
@@ -1472,7 +1474,7 @@ unrecognized:
 		VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n",
 			dev->usermode_setup ? "delegate" : "fail",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+			w_value, le16_to_cpu(ctrl->wIndex), w_length);
 
 		/* if there's an ep0 reader, don't stall */
 		if (dev->usermode_setup) {
@@ -1485,9 +1487,9 @@ delegate:
 			value = 0;
 
 			/* read DATA stage for OUT right away */
-			if (unlikely (!dev->setup_in && ctrl->wLength)) {
+			if (unlikely (!dev->setup_in && w_length)) {
 				value = setup_req (gadget->ep0, dev->req,
-							ctrl->wLength);
+							w_length);
 				if (value < 0)
 					break;
 				value = usb_ep_queue (gadget->ep0, dev->req,
@@ -1513,8 +1515,7 @@ delegate:
 	/* proceed with data transfer and status phases? */
 	if (value >= 0 && dev->state != STATE_SETUP) {
 		req->length = value;
-		req->zero = value < ctrl->wLength
-				&& (value % gadget->ep0->maxpacket) == 0;
+		req->zero = value < w_length;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -705,7 +705,7 @@ void nuke(struct lh7a40x_ep *ep, int sta
 		done(ep, req, status);
 	}
 
-	/* Disable IRQ if EP is enabled (has decriptor) */
+	/* Disable IRQ if EP is enabled (has descriptor) */
 	if (ep->desc)
 		pio_irq_disable(ep_index(ep));
 }
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1,8 +1,9 @@
 /*
- * Driver for the NetChip 2280 USB device controller.
- * Specs and errata are available from <http://www.netchip.com>.
+ * Driver for the PLX NET2280 USB device controller.
+ * Specs and errata are available from <http://www.plxtech.com>.
  *
- * NetChip Technology Inc. supported the development of this driver.
+ * PLX Technology Inc. (formerly NetChip Technology) supported the 
+ * development of this driver.
  *
  *
  * CODE STATUS HIGHLIGHTS
@@ -23,7 +24,7 @@
 
 /*
  * Copyright (C) 2003 David Brownell
- * Copyright (C) 2003 NetChip Technologies
+ * Copyright (C) 2003-2005 PLX Technology, 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
@@ -69,8 +70,8 @@
 #include <asm/unaligned.h>
 
 
-#define	DRIVER_DESC		"NetChip 2280 USB Peripheral Controller"
-#define	DRIVER_VERSION		"2004 Jan 14"
+#define	DRIVER_DESC		"PLX NET2280 USB Peripheral Controller"
+#define	DRIVER_VERSION		"2005 Feb 03"
 
 #define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
 #define	EP_DONTUSE		13	/* nonzero */
@@ -113,6 +114,16 @@ static ushort fifo_mode = 0;
 /* "modprobe net2280 fifo_mode=1" etc */
 module_param (fifo_mode, ushort, 0644);
 
+/* enable_suspend -- When enabled, the driver will respond to
+ * USB suspend requests by powering down the NET2280.  Otherwise,
+ * USB suspend requests will be ignored.  This is acceptible for
+ * self-powered devices, and helps avoid some quirks.
+ */
+static int enable_suspend = 0;
+
+/* "modprobe net2280 enable_suspend=1" etc */
+module_param (enable_suspend, bool, S_IRUGO);
+
 
 #define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 
@@ -1259,7 +1270,7 @@ static int net2280_dequeue (struct usb_e
 	}
 
 	spin_unlock_irqrestore (&ep->dev->lock, flags);
-	return req ? 0 : -EOPNOTSUPP;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -2561,6 +2572,8 @@ static void handle_stat1_irqs (struct ne
 		if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
 			if (dev->driver->suspend)
 				dev->driver->suspend (&dev->gadget);
+			if (!enable_suspend)
+				stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
 		} else {
 			if (dev->driver->resume)
 				dev->driver->resume (&dev->gadget);
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2,7 +2,7 @@
  * omap_udc.c -- for OMAP full speed udc; most chips support OTG.
  *
  * Copyright (C) 2004 Texas Instruments, Inc.
- * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2004-2005 David Brownell
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -2046,7 +2046,10 @@ int usb_gadget_register_driver (struct u
 			pullup_disable (udc);
 	}
 
-	if (machine_is_omap_innovator())
+	/* boards that don't have VBUS sensing can't autogate 48MHz;
+	 * can't enter deep sleep while a gadget driver is active.
+	 */
+	if (machine_is_omap_innovator() || machine_is_omap_osk())
 		omap_vbus_session(&udc->gadget, 1);
 
 done:
@@ -2064,7 +2067,7 @@ int usb_gadget_unregister_driver (struct
 	if (!driver || driver != udc->driver)
 		return -EINVAL;
 
-	if (machine_is_omap_innovator())
+	if (machine_is_omap_innovator() || machine_is_omap_osk())
 		omap_vbus_session(&udc->gadget, 0);
 
 	if (udc->transceiver)
@@ -2157,13 +2160,13 @@ static void proc_ep_show(struct seq_file
 		}
 }
 
-static char *trx_mode(unsigned m)
+static char *trx_mode(unsigned m, int enabled)
 {
 	switch (m) {
-	case 3:
-	case 0:		return "6wire";
+	case 0:		return enabled ? "*6wire" : "unused";
 	case 1:		return "4wire";
 	case 2:		return "3wire";
+	case 3: 	return "6wire";
 	default:	return "unknown";
 	}
 }
@@ -2171,17 +2174,20 @@ static char *trx_mode(unsigned m)
 static int proc_otg_show(struct seq_file *s)
 {
 	u32		tmp;
+	u32		trans;
 
 	tmp = OTG_REV_REG;
-	seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n",
-		tmp >> 4, tmp & 0xf,
-		USB_TRANSCEIVER_CTRL_REG);
+	trans = USB_TRANSCEIVER_CTRL_REG;
+	seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
+		tmp >> 4, tmp & 0xf, trans);
 	tmp = OTG_SYSCON_1_REG;
 	seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
 			FOURBITS "\n", tmp,
-		trx_mode(USB2_TRX_MODE(tmp)),
-		trx_mode(USB1_TRX_MODE(tmp)),
-		trx_mode(USB0_TRX_MODE(tmp)),
+		trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
+		trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
+		(USB0_TRX_MODE(tmp) == 0)
+			? "internal"
+			: trx_mode(USB0_TRX_MODE(tmp), 1),
 		(tmp & OTG_IDLE_EN) ? " !otg" : "",
 		(tmp & HST_IDLE_EN) ? " !host" : "",
 		(tmp & DEV_IDLE_EN) ? " !dev" : "",
@@ -2803,17 +2809,15 @@ static int __exit omap_udc_remove(struct
 	return 0;
 }
 
-/* suspend/resume/wakeup from sysfs (echo > power/state) */
-
-static int omap_udc_suspend(struct device *dev, u32 state, u32 level)
+static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level != 0)
 		return 0;
 
 	DBG("suspend, state %d\n", state);
 	omap_pullup(&udc->gadget, 0);
-	udc->gadget.dev.power.power_state = 3;
-	udc->gadget.dev.parent->power.power_state = 3;
+	udc->gadget.dev.power.power_state = PMSG_SUSPEND;
+	udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
 	return 0;
 }
 
@@ -2823,8 +2827,8 @@ static int omap_udc_resume(struct device
 		return 0;
 
 	DBG("resume + wakeup/SRP\n");
-	udc->gadget.dev.parent->power.power_state = 0;
-	udc->gadget.dev.power.power_state = 0;
+	udc->gadget.dev.parent->power.power_state = PMSG_ON;
+	udc->gadget.dev.power.power_state = PMSG_ON;
 	omap_pullup(&udc->gadget, 1);
 
 	/* maybe the host would enumerate us if we nudged it */
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -310,7 +310,7 @@ static int pxa2xx_ep_disable (struct usb
 	/* flush fifo (mostly for IN buffers) */
 	pxa2xx_ep_fifo_flush (_ep);
 
-	ep->desc = 0;
+	ep->desc = NULL;
 	ep->stopped = 1;
 
 	DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
@@ -334,7 +334,7 @@ pxa2xx_ep_alloc_request (struct usb_ep *
 
 	req = kmalloc (sizeof *req, gfp_flags);
 	if (!req)
-		return 0;
+		return NULL;
 
 	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
@@ -369,7 +369,11 @@ pxa2xx_ep_alloc_buffer(struct usb_ep *_e
 
 	retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
 	if (retval)
+#ifdef	USE_DMA
 		*dma = virt_to_bus (retval);
+#else
+		*dma = (dma_addr_t)~0;
+#endif
 	return retval;
 }
 
@@ -411,7 +415,6 @@ static void done(struct pxa2xx_ep *ep, s
 static inline void ep0_idle (struct pxa2xx_udc *dev)
 {
 	dev->ep0state = EP0_IDLE;
-	LED_EP0_OFF;
 }
 
 static int
@@ -930,7 +933,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, stru
 			case EP0_IN_DATA_PHASE:
 				dev->stats.write.ops++;
 				if (write_ep0_fifo(ep, req))
-					req = 0;
+					req = NULL;
 				break;
 
 			case EP0_OUT_DATA_PHASE:
@@ -940,9 +943,11 @@ pxa2xx_ep_queue(struct usb_ep *_ep, stru
 					DBG(DBG_VERBOSE, "ep0 config ack%s\n",
 						dev->has_cfr ?  "" : " raced");
 					if (dev->has_cfr)
-						UDCCFR = UDCCFR_AREN|UDCCFR_ACM;
+						UDCCFR = UDCCFR_AREN|UDCCFR_ACM
+							|UDCCFR_MB1;
 					done(ep, req, 0);
 					dev->ep0state = EP0_END_XFER;
+					local_irq_restore (flags);
 					return 0;
 				}
 				if (dev->req_pending)
@@ -951,7 +956,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, stru
 						&& read_ep0_fifo(ep, req))) {
 					ep0_idle(dev);
 					done(ep, req, 0);
-					req = 0;
+					req = NULL;
 				}
 				break;
 
@@ -969,10 +974,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, stru
 		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
 				&& (*ep->reg_udccs & UDCCS_BI_TFS) != 0
 				&& write_fifo(ep, req)) {
-			req = 0;
+			req = NULL;
 		} else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
 				&& read_fifo(ep, req)) {
-			req = 0;
+			req = NULL;
 		}
 
 		if (likely (req && ep->desc) && ep->dma < 0)
@@ -1093,7 +1098,6 @@ static int pxa2xx_ep_set_halt(struct usb
 		start_watchdog(ep->dev);
 		ep->dev->req_pending = 0;
 		ep->dev->ep0state = EP0_STALL;
-		LED_EP0_OFF;
 
  	/* and bulk/intr endpoints like dropping stalls too */
  	} else {
@@ -1193,13 +1197,71 @@ static int pxa2xx_udc_wakeup(struct usb_
 	return 0;
 }
 
+static void stop_activity(struct pxa2xx_udc *, struct usb_gadget_driver *);
+static void udc_enable (struct pxa2xx_udc *);
+static void udc_disable(struct pxa2xx_udc *);
+
+/* We disable the UDC -- and its 48 MHz clock -- whenever it's not
+ * in active use.  
+ */
+static int pullup(struct pxa2xx_udc *udc, int is_active)
+{
+	is_active = is_active && udc->vbus && udc->pullup;
+	DMSG("%s\n", is_active ? "active" : "inactive");
+	if (is_active)
+		udc_enable(udc);
+	else {
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+			DMSG("disconnect %s\n", udc->driver
+				? udc->driver->driver.name
+				: "(no driver)");
+			stop_activity(udc, udc->driver);
+		}
+		udc_disable(udc);
+	}
+	return 0;
+}
+
+/* VBUS reporting logically comes from a transceiver */
+static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct pxa2xx_udc	*udc;
+
+	udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+	udc->vbus = is_active = (is_active != 0);
+	DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
+	pullup(udc, is_active);
+	return 0;
+}
+
+/* drivers may have software control over D+ pullup */
+static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct pxa2xx_udc	*udc;
+
+	udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+
+	/* not all boards support pullup control */
+	if (!udc->mach->udc_command)
+		return -EOPNOTSUPP;
+
+	is_active = (is_active != 0);
+	udc->pullup = is_active;
+	pullup(udc, is_active);
+	return 0;
+}
+
 static const struct usb_gadget_ops pxa2xx_udc_ops = {
-	.get_frame	 = pxa2xx_udc_get_frame,
-	.wakeup		 = pxa2xx_udc_wakeup,
-	// current versions must always be self-powered
+	.get_frame	= pxa2xx_udc_get_frame,
+	.wakeup		= pxa2xx_udc_wakeup,
+	.vbus_session	= pxa2xx_udc_vbus_session,
+	.pullup		= pxa2xx_udc_pullup,
+
+	// .vbus_draw ... boards may consume current from VBUS, up to
+	// 100-500mA based on config.  the 500uA suspend ceiling means
+	// that exclusively vbus-powered PXA designs violate USB specs.
 };
 
-
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -1426,7 +1488,7 @@ static void udc_reinit(struct pxa2xx_udc
 		if (i != 0)
 			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
 
-		ep->desc = 0;
+		ep->desc = NULL;
 		ep->stopped = 0;
 		INIT_LIST_HEAD (&ep->queue);
 		ep->pio_irqs = ep->dma_irqs = 0;
@@ -1445,6 +1507,7 @@ static void udc_enable (struct pxa2xx_ud
 #ifdef	CONFIG_ARCH_PXA
         /* Enable clock for USB device */
 	pxa_set_cken(CKEN11_USB, 1);
+	udelay(5);
 #endif
 
 	/* try to clear these bits before we enable the udc */
@@ -1468,7 +1531,7 @@ static void udc_enable (struct pxa2xx_ud
 		/* pxa255 (a0+) can avoid a set_config race that could
 		 * prevent gadget drivers from configuring correctly
 		 */
-		UDCCFR = UDCCFR_ACM;
+		UDCCFR = UDCCFR_ACM | UDCCFR_MB1;
 	} else {
 		/* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)
 		 * which could result in missing packets and interrupts.
@@ -1497,18 +1560,13 @@ static void udc_enable (struct pxa2xx_ud
 	}
 #endif
 
-	/* caller must be able to sleep in order to cope
-	 * with startup transients.
-	 */
-	msleep(100);
-
 	/* enable suspend/resume and reset irqs */
 	udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
 
 	/* enable ep0 irqs */
 	UICR0 &= ~UICR0_IM0;
 
-	/* if hardware supports it, connect to usb and wait for host */
+	/* if hardware supports it, pullup D+ and wait for reset */
 	let_usb_appear();
 }
 
@@ -1539,6 +1597,7 @@ int usb_gadget_register_driver(struct us
 	/* first hook up the driver ... */
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
+	dev->pullup = 1;
 
 	device_add (&dev->gadget.dev);
 	retval = driver->bind(&dev->gadget);
@@ -1547,18 +1606,17 @@ int usb_gadget_register_driver(struct us
 				driver->driver.name, retval);
 		device_del (&dev->gadget.dev);
 
-		dev->driver = 0;
-		dev->gadget.dev.driver = 0;
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
 		return retval;
 	}
 	device_create_file(dev->dev, &dev_attr_function);
 
 	/* ... then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
-	 * NOTE:  this shouldn't power up until later.
 	 */
 	DMSG("registered gadget driver '%s'\n", driver->driver.name);
-	udc_enable(dev);
+	pullup(dev, 1);
 	dump_state(dev);
 	return 0;
 }
@@ -1571,7 +1629,7 @@ stop_activity(struct pxa2xx_udc *dev, st
 
 	/* don't disconnect drivers more than once */
 	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
-		driver = 0;
+		driver = NULL;
 	dev->gadget.speed = USB_SPEED_UNKNOWN;
 
 	/* prevent new request submissions, kill any outstanding requests  */
@@ -1602,12 +1660,12 @@ int usb_gadget_unregister_driver(struct 
 		return -EINVAL;
 
 	local_irq_disable();
-	udc_disable(dev);
+	pullup(dev, 0);
 	stop_activity(dev, driver);
 	local_irq_enable();
 
 	driver->unbind(&dev->gadget);
-	dev->driver = 0;
+	dev->driver = NULL;
 
 	device_del (&dev->gadget.dev);
 	device_remove_file(dev->dev, &dev_attr_function);
@@ -1623,61 +1681,41 @@ EXPORT_SYMBOL(usb_gadget_unregister_driv
 
 #ifdef CONFIG_ARCH_LUBBOCK
 
-/* Lubbock can report connect or disconnect irqs.  Likely more hardware
- * could support it as a timer callback.
- *
- * FIXME for better power management, keep the hardware powered down
- * until a host is powering the link.  means scheduling work later
- * in some task that can udc_enable().
+/* Lubbock has separate connect and disconnect irqs.  More typical designs
+ * use one GPIO as the VBUS IRQ, and another to control the D+ pullup.
  */
 
-#define	enable_disconnect_irq() \
-	if (machine_is_lubbock()) { enable_irq(LUBBOCK_USB_DISC_IRQ); }
-#define	disable_disconnect_irq() \
-	if (machine_is_lubbock()) { disable_irq(LUBBOCK_USB_DISC_IRQ); }
-
 static irqreturn_t
-usb_connection_irq(int irq, void *_dev, struct pt_regs *r)
+lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
 {
 	struct pxa2xx_udc	*dev = _dev;
+	int			vbus;
 
 	dev->stats.irqs++;
 	HEX_DISPLAY(dev->stats.irqs);
-
-	if (!is_usb_connected()) {
-		LED_CONNECTED_OFF;
-		disable_disconnect_irq();
-		/* report disconnect just once */
-		if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
-			DMSG("disconnect %s\n",
-				dev->driver ? dev->driver->driver.name : 0);
-			stop_activity(dev, dev->driver);
-
-			// udc_disable (dev);
-			// no more udc irqs
-			// maybe "ACTION=disconnect /sbin/hotplug gadget".
-		}
-	} else if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
+	switch (irq) {
+	case LUBBOCK_USB_IRQ:
 		LED_CONNECTED_ON;
-
-		DMSG("?? connect irq ??\n");
-
-		// if there's no driver bound, ignore; else
-		// udc_enable (dev);
-		// UDC irqs drive the rest.
-		// maybe "ACTION=connect /sbin/hotplug gadget".
+		vbus = 1;
+		disable_irq(LUBBOCK_USB_IRQ);
+		enable_irq(LUBBOCK_USB_DISC_IRQ);
+		break;
+	case LUBBOCK_USB_DISC_IRQ:
+		LED_CONNECTED_OFF;
+		vbus = 0;
+		disable_irq(LUBBOCK_USB_DISC_IRQ);
+		enable_irq(LUBBOCK_USB_IRQ);
+		break;
+	default:
+		return IRQ_NONE;
 	}
+
+	pxa2xx_udc_vbus_session(&dev->gadget, vbus);
 	return IRQ_HANDLED;
 }
 
 #endif
 
-#ifndef	enable_disconnect_irq
-#warning USB disconnect() is not yet reported.
-#define	enable_disconnect_irq()		do {} while (0)
-#define	disable_disconnect_irq()	do {} while (0)
-#endif
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1719,7 +1757,7 @@ static void handle_ep0 (struct pxa2xx_ud
 	} u;
 
 	if (list_empty(&ep->queue))
-		req = 0;
+		req = NULL;
 	else
 		req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
 
@@ -1763,14 +1801,11 @@ bad_setup:
 				goto bad_setup;
 
 got_setup:
-			le16_to_cpus (&u.r.wValue);
-			le16_to_cpus (&u.r.wIndex);
-			le16_to_cpus (&u.r.wLength);
-
-			LED_EP0_ON;
 			DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n",
 				u.r.bRequestType, u.r.bRequest,
-				u.r.wValue, u.r.wIndex, u.r.wLength);
+				le16_to_cpu(u.r.wValue),
+				le16_to_cpu(u.r.wIndex),
+				le16_to_cpu(u.r.wLength));
 
 			/* cope with automagic for some standard requests. */
 			dev->req_std = (u.r.bRequestType & USB_TYPE_MASK)
@@ -1802,7 +1837,8 @@ config_change:
 					 *  - ep reset doesn't include halt(?).
 					 */
 					DMSG("broken set_interface (%d/%d)\n",
-						u.r.wIndex, u.r.wValue);
+						le16_to_cpu(u.r.wIndex),
+						le16_to_cpu(u.r.wValue));
 					goto config_change;
 				}
 				break;
@@ -1846,7 +1882,6 @@ stall:
 				ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");
 				start_watchdog(dev);
 				dev->ep0state = EP0_STALL;
-				LED_EP0_OFF;
 
 			/* deferred i/o == no response yet */
 			} else if (dev->req_pending) {
@@ -1947,7 +1982,7 @@ static void handle_ep(struct pxa2xx_ep *
 			req = list_entry(ep->queue.next,
 					struct pxa2xx_request, queue);
 		else
-			req = 0;
+			req = NULL;
 
 		// TODO check FST handling
 
@@ -2049,8 +2084,6 @@ pxa2xx_udc_irq(int irq, void *_dev, stru
 
 			if ((UDCCR & UDCCR_UDA) == 0) {
 				DBG(DBG_VERBOSE, "USB reset start\n");
-				if (dev->gadget.speed != USB_SPEED_UNKNOWN)
-					disable_disconnect_irq();
 
 				/* reset driver and endpoints,
 				 * in case that's not yet done
@@ -2058,12 +2091,11 @@ pxa2xx_udc_irq(int irq, void *_dev, stru
 				stop_activity (dev, dev->driver);
 
 			} else {
-				INFO("USB reset\n");
+				DBG(DBG_VERBOSE, "USB reset end\n");
 				dev->gadget.speed = USB_SPEED_FULL;
 				LED_CONNECTED_ON;
 				memset(&dev->stats, 0, sizeof dev->stats);
 				/* driver and endpoints are still reset */
-				enable_disconnect_irq();
 			}
 
 		} else {
@@ -2477,6 +2509,8 @@ static int __init pxa2xx_udc_probe(struc
 	udc_disable(dev);
 	udc_reinit(dev);
 
+	dev->vbus = is_usb_connected();
+
 	/* irq setup after old hardware state is cleaned up */
 	retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
 			SA_INTERRUPT, driver_name, dev);
@@ -2489,18 +2523,32 @@ static int __init pxa2xx_udc_probe(struc
 
 #ifdef CONFIG_ARCH_LUBBOCK
 	if (machine_is_lubbock()) {
-		disable_irq(LUBBOCK_USB_DISC_IRQ);
 		retval = request_irq(LUBBOCK_USB_DISC_IRQ,
-				usb_connection_irq,
-				SA_INTERRUPT /* OOPSING | SA_SAMPLE_RANDOM */,
+				lubbock_vbus_irq,
+				SA_INTERRUPT | SA_SAMPLE_RANDOM,
 				driver_name, dev);
 		if (retval != 0) {
-			enable_irq(LUBBOCK_USB_DISC_IRQ);
 			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
 				driver_name, LUBBOCK_USB_DISC_IRQ, retval);
+lubbock_fail0:
+			free_irq(IRQ_USB, dev);
 			return -EBUSY;
 		}
-		dev->got_disc = 1;
+		retval = request_irq(LUBBOCK_USB_IRQ,
+				lubbock_vbus_irq,
+				SA_INTERRUPT | SA_SAMPLE_RANDOM,
+				driver_name, dev);
+		if (retval != 0) {
+			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+				driver_name, LUBBOCK_USB_IRQ, retval);
+			free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+			goto lubbock_fail0;
+		}
+#ifdef DEBUG
+		/* with U-Boot (but not BLOB), hex is off by default */
+		HEX_DISPLAY(dev->stats.irqs);
+		LUB_DISC_BLNK_LED &= 0xff;
+#endif
 	}
 #endif
 	create_proc_files();
@@ -2509,7 +2557,7 @@ static int __init pxa2xx_udc_probe(struc
 }
 static int __exit pxa2xx_udc_remove(struct device *_dev)
 {
-	struct pxa2xx_udc *dev = _dev->driver_data;
+	struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
 
 	udc_disable(dev);
 	remove_proc_files();
@@ -2519,26 +2567,66 @@ static int __exit pxa2xx_udc_remove(stru
 		free_irq(IRQ_USB, dev);
 		dev->got_irq = 0;
 	}
-	if (machine_is_lubbock() && dev->got_disc) {
+	if (machine_is_lubbock()) {
 		free_irq(LUBBOCK_USB_DISC_IRQ, dev);
-		dev->got_disc = 0;
+		free_irq(LUBBOCK_USB_IRQ, dev);
 	}
-	dev_set_drvdata(_dev, 0);
-	the_controller = 0;
+	dev_set_drvdata(_dev, NULL);
+	the_controller = NULL;
 	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef	CONFIG_PM
+
+/* USB suspend (controlled by the host) and system suspend (controlled
+ * by the PXA) don't necessarily work well together.  If USB is active,
+ * the 48 MHz clock is required; so the system can't enter 33 MHz idle
+ * mode, or any deeper PM saving state.
+ *
+ * For now, we punt and forcibly disconnect from the USB host when PXA
+ * enters any suspend state.  While we're disconnected, we always disable
+ * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. 
+ * Boards without software pullup control shouldn't use those states.
+ * VBUS IRQs should probably be ignored so that the PXA device just acts
+ * "dead" to USB hosts until system resume.
+ */
+static int pxa2xx_udc_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct pxa2xx_udc	*udc = dev_get_drvdata(dev);
+
+	if (level == SUSPEND_POWER_DOWN) {
+		if (!udc->mach->udc_command)
+			WARN("USB host won't detect disconnect!\n");
+		pullup(udc, 0);
+	}
+	return 0;
+}
+
+static int pxa2xx_udc_resume(struct device *dev, u32 level)
+{
+	struct pxa2xx_udc	*udc = dev_get_drvdata(dev);
+
+	if (level == RESUME_POWER_ON)
+		pullup(udc, 1);
+	return 0;
+}
+
+#else
+#define	pxa2xx_udc_suspend	NULL
+#define	pxa2xx_udc_resume	NULL
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 static struct device_driver udc_driver = {
 	.name		= "pxa2xx-udc",
 	.bus		= &platform_bus_type,
 	.probe		= pxa2xx_udc_probe,
 	.remove		= __exit_p(pxa2xx_udc_remove),
-
-	// FIXME power management support
-	// .suspend = ... disable UDC
-	// .resume = ... re-enable UDC
+	.suspend	= pxa2xx_udc_suspend,
+	.resume		= pxa2xx_udc_resume,
 };
 
 static int __init udc_init(void)
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -40,6 +40,9 @@
 #define UDCCFR_AREN	(1 << 7)	/* ACK response enable (now) */
 #define UDCCFR_ACM	(1 << 2)	/* ACK control mode (wait for AREN) */
 
+/* latest pxa255 errata define new "must be one" bits in UDCCFR */
+#define	UDCCFR_MB1	(0xff & ~(UDCCFR_AREN|UDCCFR_ACM))
+
 /*-------------------------------------------------------------------------*/
 
 struct pxa2xx_udc;
@@ -120,7 +123,8 @@ struct pxa2xx_udc {
 	enum ep0_state				ep0state;
 	struct udc_stats			stats;
 	unsigned				got_irq : 1,
-						got_disc : 1,
+						vbus : 1,
+						pullup : 1,
 						has_cfr : 1,
 						req_pending : 1,
 						req_std : 1,
@@ -143,14 +147,7 @@ struct pxa2xx_udc {
 
 #ifdef DEBUG
 #define HEX_DISPLAY(n)	if (machine_is_lubbock()) { LUB_HEXLED = (n); }
-
-#define LED_CONNECTED_ON	if (machine_is_lubbock()) { \
-	DISCRETE_LED_ON(D26); }
-#define LED_CONNECTED_OFF	if(machine_is_lubbock()) { \
-	DISCRETE_LED_OFF(D26); LUB_HEXLED = 0; }
-#define LED_EP0_ON	if (machine_is_lubbock()) { DISCRETE_LED_ON(D25); }
-#define LED_EP0_OFF	if (machine_is_lubbock()) { DISCRETE_LED_OFF(D25); }
-#endif /* DEBUG */
+#endif
 
 #endif
 
@@ -161,14 +158,20 @@ struct pxa2xx_udc {
 #define HEX_DISPLAY(n)		do {} while(0)
 #endif
 
+#ifdef DEBUG
+#include <asm/leds.h>
+
+#define LED_CONNECTED_ON	leds_event(led_green_on)
+#define LED_CONNECTED_OFF	do { \
+					leds_event(led_green_off); \
+					HEX_DISPLAY(0); \
+				} while(0)
+#endif
+
 #ifndef LED_CONNECTED_ON
 #define LED_CONNECTED_ON	do {} while(0)
 #define LED_CONNECTED_OFF	do {} while(0)
 #endif
-#ifndef LED_EP0_ON
-#define LED_EP0_ON		do {} while (0)
-#define LED_EP0_OFF		do {} while (0)
-#endif
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 
 #undef	RNDIS_PM
@@ -74,7 +75,7 @@ MODULE_PARM_DESC (rndis_debug, "enable d
 static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
 
 /* Driver Version */
-static const u32 rndis_driver_version = __constant_cpu_to_le32 (1);
+static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
 
 /* Function Prototypes */
 static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
@@ -92,7 +93,7 @@ static int gen_ndis_query_resp (int conf
 {
 	int 			retval = -ENOTSUPP;
 	u32 			length = 0;
-	u32			*tmp;
+	__le32			*tmp;
 	int			i, count;
 	rndis_query_cmplt_type	*resp;
 
@@ -110,7 +111,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
 		length = sizeof (oid_supported_list);
 		count  = length / sizeof (u32);
-		tmp = (u32 *) ((u8 *)resp + 24);
+		tmp = (__le32 *) ((u8 *)resp + 24);
 		for (i = 0; i < count; i++)
 			tmp[i] = cpu_to_le32 (oid_supported_list[i]);
 		retval = 0;
@@ -126,7 +127,7 @@ static int gen_ndis_query_resp (int conf
 		 * reddite ergo quae sunt Caesaris Caesari
 		 * et quae sunt Dei Deo!
 		 */
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -134,7 +135,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MEDIA_SUPPORTED:
 		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = cpu_to_le32 (
+		*((__le32 *) resp + 6) = cpu_to_le32 (
 					rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
@@ -144,7 +145,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
 		length = 4;
 		/* one medium, one transport... (maybe you do it better) */
-		*((u32 *) resp + 6) = cpu_to_le32 (
+		*((__le32 *) resp + 6) = cpu_to_le32 (
 					rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
@@ -154,24 +155,24 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_LINK_SPEED:
-		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+//		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
 		length = 4;
 		if (rndis_per_dev_params [configNr].media_state
 			== NDIS_MEDIA_STATE_DISCONNECTED)
-		    *((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		    *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		else
-		    *((u32 *) resp + 6) = cpu_to_le32 (
+		    *((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr].speed);
 		retval = 0;
 		break;
@@ -181,7 +182,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -192,7 +193,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -202,7 +203,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_VENDOR_ID:
 		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = cpu_to_le32 (
+		*((__le32 *) resp + 6) = cpu_to_le32 (
 			rndis_per_dev_params [configNr].vendorID);
 		retval = 0;
 		break;
@@ -220,7 +221,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
 		length = 4;
 		/* Created as LE */
-		*((u32 *) resp + 6) = rndis_driver_version;
+		*((__le32 *) resp + 6) = rndis_driver_version;
 		retval = 0;
 		break;
 
@@ -228,7 +229,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_CURRENT_PACKET_FILTER:
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = cpu_to_le32 (
+		*((__le32 *) resp + 6) = cpu_to_le32 (
 					rndis_per_dev_params[configNr].filter);
 		retval = 0;
 		break;
@@ -237,7 +238,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = __constant_cpu_to_le32(
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
 					RNDIS_MAX_TOTAL_SIZE);
 		retval = 0;
 		break;
@@ -246,7 +247,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MEDIA_CONNECT_STATUS:
 		DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = cpu_to_le32 (
+		*((__le32 *) resp + 6) = cpu_to_le32 (
 					rndis_per_dev_params [configNr]
 						.media_state);
 		retval = 0;
@@ -255,7 +256,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_PHYSICAL_MEDIUM:
 		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 
@@ -266,7 +267,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
 		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = __constant_cpu_to_le32(
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
 			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
 			| NDIS_MAC_OPTION_FULL_DUPLEX);
 		retval = 0;
@@ -279,13 +280,13 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->tx_packets - 
 			    rndis_per_dev_params [configNr].stats->tx_errors -
 			    rndis_per_dev_params [configNr].stats->tx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -295,13 +296,13 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->rx_packets - 
 			    rndis_per_dev_params [configNr].stats->rx_errors -
 			    rndis_per_dev_params [configNr].stats->rx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -311,12 +312,12 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->tx_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -325,12 +326,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_RCV_ERROR:
 		DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -339,12 +340,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_RCV_NO_BUFFER:
 		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -359,7 +360,7 @@ static int gen_ndis_query_resp (int conf
 		 */
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -369,7 +370,7 @@ static int gen_ndis_query_resp (int conf
 				* 123);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -379,7 +380,7 @@ static int gen_ndis_query_resp (int conf
 		/* dito */
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -389,7 +390,7 @@ static int gen_ndis_query_resp (int conf
 				/ 123);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -397,12 +398,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MULTICAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->multicast*1234);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -410,12 +411,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -423,12 +424,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_BROADCAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->tx_packets/42*255);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -436,37 +437,37 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->tx_packets/42);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_DIRECTED_BYTES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_DIRECTED_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->multicast * 1111);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -474,12 +475,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_MULTICAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -487,12 +488,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_BROADCAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_packets/42*255);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -500,12 +501,12 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_BROADCAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_packets/42);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -513,19 +514,19 @@ static int gen_ndis_query_resp (int conf
 	case OID_GEN_RCV_CRC_ERROR:
 		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_crc_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
 		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 #endif	/* RNDIS_OPTIONAL_STATS */
@@ -542,7 +543,7 @@ static int gen_ndis_query_resp (int conf
 				length);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -564,7 +565,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
 		length = 4;
 		/* Multicast base address only */
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
 		retval = 0;
 		break;
 		
@@ -573,7 +574,7 @@ static int gen_ndis_query_resp (int conf
 		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
 		 length = 4;
 		/* Multicast base address only */
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (1);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
 		retval = 0;
 		break;
 		
@@ -589,7 +590,7 @@ static int gen_ndis_query_resp (int conf
 		if (rndis_per_dev_params [configNr].stats)
 		{
 			length = 4;
-			*((u32 *) resp + 6) = cpu_to_le32 (
+			*((__le32 *) resp + 6) = cpu_to_le32 (
 				rndis_per_dev_params [configNr]
 					.stats->rx_frame_errors);
 			retval = 0;
@@ -600,7 +601,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_802_3_XMIT_ONE_COLLISION:
 		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -608,7 +609,7 @@ static int gen_ndis_query_resp (int conf
 	case OID_802_3_XMIT_MORE_COLLISIONS:
 		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -729,12 +730,12 @@ static int gen_ndis_set_resp (u8 configN
 		retval = 0;
 
 		/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-		 * filter packets in hard_start_xmit()
-		 * NDIS_PACKET_TYPE_x == CDC_PACKET_TYPE_x for x in:
+		 * set the cdc_filter; it's not RNDIS-specific
+		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
 		 *	PROMISCUOUS, DIRECTED,
 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
 		 */
-		params->filter = cpu_to_le32p((u32 *)buf);
+		params->filter = le32_to_cpup((__le32 *)buf);
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
 			__FUNCTION__, params->filter);
 
@@ -866,7 +867,7 @@ static int rndis_query_response (int con
 	resp->MessageLength = __constant_cpu_to_le32 (24);
 	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
 	
-	if (gen_ndis_query_resp (configNr, cpu_to_le32 (buf->OID), r)) {
+	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
 		/* OID not supported */
 		resp->Status = __constant_cpu_to_le32 (
 				RNDIS_STATUS_NOT_SUPPORTED);
@@ -893,8 +894,8 @@ static int rndis_set_response (int confi
 	resp = (rndis_set_cmplt_type *) r->buf;
 	if (!resp) return -ENOMEM;
 
-	BufLength = cpu_to_le32 (buf->InformationBufferLength);
-	BufOffset = cpu_to_le32 (buf->InformationBufferOffset);
+	BufLength = le32_to_cpu (buf->InformationBufferLength);
+	BufOffset = le32_to_cpu (buf->InformationBufferOffset);
 
 #ifdef	VERBOSE
 	DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
@@ -911,7 +912,7 @@ static int rndis_set_response (int confi
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
 	resp->MessageLength = __constant_cpu_to_le32 (16);
 	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-	if (gen_ndis_set_resp (configNr, cpu_to_le32 (buf->OID), 
+	if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID), 
 			       ((u8 *) buf) + 8 + BufOffset, BufLength, r))
 	    resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
 	else resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
@@ -1030,15 +1031,16 @@ void rndis_set_host_mac (int configNr, c
  */
 int rndis_msg_parser (u8 configNr, u8 *buf)
 {
-	u32 MsgType, MsgLength, *tmp;
+	u32 MsgType, MsgLength;
+	__le32 *tmp;
 	struct rndis_params		*params;
 	
 	if (!buf)
 		return -ENOMEM;
 	
-	tmp = (u32 *) buf; 
-	MsgType   = cpu_to_le32p(tmp++);
-	MsgLength = cpu_to_le32p(tmp++);
+	tmp = (__le32 *) buf; 
+	MsgType   = le32_to_cpup(tmp++);
+	MsgLength = le32_to_cpup(tmp++);
 	
 	if (configNr >= RNDIS_MAX_CONFIGS)
 		return -ENOTSUPP;
@@ -1187,15 +1189,16 @@ int rndis_set_param_medium (u8 configNr,
 
 void rndis_add_hdr (struct sk_buff *skb)
 {
-	if (!skb) return;
-	skb_push (skb, sizeof (struct rndis_packet_msg_type));
-	memset (skb->data, 0, sizeof (struct rndis_packet_msg_type));
-	*((u32 *) skb->data) = __constant_cpu_to_le32 (1);
-	*((u32 *) skb->data + 1) = cpu_to_le32(skb->len);
-	*((u32 *) skb->data + 2) = __constant_cpu_to_le32 (36);
-	*((u32 *) skb->data + 3) = cpu_to_le32(skb->len - 44);
-	
-	return;
+	struct rndis_packet_msg_type	*header;
+
+	if (!skb)
+		return;
+	header = (void *) skb_push (skb, sizeof *header);
+	memset (header, 0, sizeof *header);
+	header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
+	header->MessageLength = cpu_to_le32(skb->len);
+	header->DataOffset = __constant_cpu_to_le32 (36);
+	header->DataLength = cpu_to_le32(skb->len - sizeof *header);
 }
 
 void rndis_free_response (int configNr, u8 *buf)
@@ -1251,25 +1254,23 @@ static rndis_resp_t *rndis_add_response 
 	return r;
 }
 
-int rndis_rm_hdr (u8 *buf, u32 *length)
+int rndis_rm_hdr(struct sk_buff *skb)
 {
-	u32 i, messageLen, dataOffset, *tmp;
-	
-	tmp = (u32 *) buf; 
+	/* tmp points to a struct rndis_packet_msg_type */
+	__le32		*tmp = (void *) skb->data;
 
-	if (!buf || !length) return -1;
-	if (cpu_to_le32p(tmp++) != 1) return -1;
-	
-	messageLen = cpu_to_le32p(tmp++);
-	dataOffset = cpu_to_le32p(tmp++) + 8;
+	/* MessageType, MessageLength */
+	if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
+			!= get_unaligned(tmp++))
+		return -EINVAL;
+	tmp++;
+
+	/* DataOffset, DataLength */
+	if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
+			+ 8 /* offset of DataOffset */))
+		return -EOVERFLOW;
+	skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
 
-	if (messageLen < dataOffset || messageLen > *length) return -1;
-	
-	for (i = dataOffset; i < messageLen; i++)
-		buf [i - dataOffset] = buf [i];
-		
-	*length = messageLen - dataOffset;
-	
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -38,6 +38,7 @@
  */
 
 /* Message Set for Connectionless (802.3) Devices */
+#define REMOTE_NDIS_PACKET_MSG		0x00000001U
 #define REMOTE_NDIS_INITIALIZE_MSG	0x00000002U	/* Initialize device */
 #define REMOTE_NDIS_HALT_MSG		0x00000003U
 #define REMOTE_NDIS_QUERY_MSG		0x00000004U
@@ -154,139 +155,139 @@ static const u32 oid_supported_list [] =
 
 typedef struct rndis_init_msg_type 
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	MajorVersion;
-	u32	MinorVersion;
-	u32	MaxTransferSize;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	MaxTransferSize;
 } rndis_init_msg_type;
 
 typedef struct rndis_init_cmplt_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	Status;
-	u32	MajorVersion;
-	u32	MinorVersion;
-	u32	DeviceFlags;
-	u32	Medium;
-	u32	MaxPacketsPerTransfer;
-	u32	MaxTransferSize;
-	u32	PacketAlignmentFactor;
-	u32	AFListOffset;
-	u32	AFListSize;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	DeviceFlags;
+	__le32	Medium;
+	__le32	MaxPacketsPerTransfer;
+	__le32	MaxTransferSize;
+	__le32	PacketAlignmentFactor;
+	__le32	AFListOffset;
+	__le32	AFListSize;
 } rndis_init_cmplt_type;
 
 typedef struct rndis_halt_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
 } rndis_halt_msg_type;
 
 typedef struct rndis_query_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	OID;
-	u32	InformationBufferLength;
-	u32	InformationBufferOffset;
-	u32	DeviceVcHandle;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
 } rndis_query_msg_type;
 
 typedef struct rndis_query_cmplt_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	Status;
-	u32	InformationBufferLength;
-	u32	InformationBufferOffset;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
 } rndis_query_cmplt_type;
 
 typedef struct rndis_set_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	OID;
-	u32	InformationBufferLength;
-	u32	InformationBufferOffset;
-	u32	DeviceVcHandle;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
 } rndis_set_msg_type;
 
 typedef struct rndis_set_cmplt_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	Status;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
 } rndis_set_cmplt_type;
 
 typedef struct rndis_reset_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	Reserved;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Reserved;
 } rndis_reset_msg_type;
 
 typedef struct rndis_reset_cmplt_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	Status;
-	u32	AddressingReset;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	AddressingReset;
 } rndis_reset_cmplt_type;
 
 typedef struct rndis_indicate_status_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	Status;
-	u32	StatusBufferLength;
-	u32	StatusBufferOffset;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	StatusBufferLength;
+	__le32	StatusBufferOffset;
 } rndis_indicate_status_msg_type;
 
 typedef struct rndis_keepalive_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
 } rndis_keepalive_msg_type;
 
 typedef struct rndis_keepalive_cmplt_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	RequestID;
-	u32	Status;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
 } rndis_keepalive_cmplt_type;
 
 struct rndis_packet_msg_type
 {
-	u32	MessageType;
-	u32	MessageLength;
-	u32	DataOffset;
-	u32	DataLength;
-	u32	OOBDataOffset;
-	u32	OOBDataLength;
-	u32	NumOOBDataElements;
-	u32	PerPacketInfoOffset;
-	u32	PerPacketInfoLength;
-	u32	VcHandle;
-	u32	Reserved;
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	DataOffset;
+	__le32	DataLength;
+	__le32	OOBDataOffset;
+	__le32	OOBDataLength;
+	__le32	NumOOBDataElements;
+	__le32	PerPacketInfoOffset;
+	__le32	PerPacketInfoLength;
+	__le32	VcHandle;
+	__le32	Reserved;
 };
 
 struct rndis_config_parameter
 {
-	u32	ParameterNameOffset;
-	u32	ParameterNameLength;
-	u32	ParameterType;
-	u32	ParameterValueOffset;
-	u32	ParameterValueLength;
+	__le32	ParameterNameOffset;
+	__le32	ParameterNameLength;
+	__le32	ParameterType;
+	__le32	ParameterValueOffset;
+	__le32	ParameterValueLength;
 };
 
 /* implementation specific */
@@ -333,7 +334,7 @@ int  rndis_set_param_vendor (u8 configNr
 			    const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
 void rndis_add_hdr (struct sk_buff *skb);
-int  rndis_rm_hdr (u8 *buf, u32 *length);
+int rndis_rm_hdr (struct sk_buff *skb);
 u8   *rndis_get_next_response (int configNr, u32 *length);
 void rndis_free_response (int configNr, u8 *buf);
 
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -45,6 +45,7 @@
 #include <asm/uaccess.h>
 
 #include <linux/usb_ch9.h>
+#include <linux/usb_cdc.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
@@ -122,80 +123,6 @@ do {									\
 })
 
 
-/* CDC-ACM Defines and Structures */
-
-#define USB_CDC_SUBCLASS_ACM			2
-
-#define USB_CDC_CTRL_PROTO_NONE			0
-#define USB_CDC_CTRL_PROTO_AT			1
-#define USB_CDC_CTRL_PROTO_VENDOR		0xff
-
-#define USB_CDC_SUBTYPE_HEADER			0
-#define USB_CDC_SUBTYPE_CALL_MGMT		1
-#define USB_CDC_SUBTYPE_ACM			2
-#define USB_CDC_SUBTYPE_UNION			6
-
-#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT		0x01
-#define USB_CDC_CALL_MGMT_CAP_DATA_INTF		0x02
-
-#define USB_CDC_REQ_SET_LINE_CODING		0x20
-#define USB_CDC_REQ_GET_LINE_CODING		0x21
-#define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
-
-#define USB_CDC_1_STOP_BITS			0
-#define USB_CDC_1_5_STOP_BITS			1
-#define USB_CDC_2_STOP_BITS			2
-
-#define USB_CDC_NO_PARITY			0
-#define USB_CDC_ODD_PARITY			1
-#define USB_CDC_EVEN_PARITY			2
-#define USB_CDC_MARK_PARITY			3
-#define USB_CDC_SPACE_PARITY			4
-
-/* Header Functional Descriptor from CDC spec 5.2.3.1 */
-struct usb_cdc_header_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-	u16	bcdCDC;
-} __attribute__ ((packed));
-
-/* Call Management Descriptor from CDC spec 5.2.3.3 */
-struct usb_cdc_call_mgmt_desc {
-	u8  bLength;
-	u8  bDescriptorType;
-	u8  bDescriptorSubType;
-	u8  bmCapabilities;
-	u8  bDataInterface;
-} __attribute__ ((packed));
-
-/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */
-struct usb_cdc_acm_desc {
-	u8  bLength;
-	u8  bDescriptorType;
-	u8  bDescriptorSubType;
-	u8  bmCapabilities;
-} __attribute__ ((packed));
-
-/* Union Functional Descriptor from CDC spec 5.2.3.8 */
-struct usb_cdc_union_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-	u8	bMasterInterface0;
-	u8	bSlaveInterface0;
-	/* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* Line Coding Structure from CDC spec 6.2.13 */
-struct usb_cdc_line_coding {
-	u32 dwDTERate;
-	u8 bCharFormat;
-	u8 bParityType;
-	u8 bDataBits;
-} __attribute__ ((packed));
-
-
 /* Defines */
 
 #define GS_VERSION_STR			"v2.0"
@@ -313,7 +240,7 @@ struct gs_dev {
 	struct usb_ep		*dev_notify_ep;	/* address of notify endpoint */
 	struct usb_ep		*dev_in_ep;	/* address of in endpoint */
 	struct usb_ep		*dev_out_ep;	/* address of out endpoint */
-	struct usb_endpoint_descriptor		/* desciptor of notify ep */
+	struct usb_endpoint_descriptor		/* descriptor of notify ep */
 				*dev_notify_ep_desc;
 	struct usb_endpoint_descriptor		/* descriptor of in endpoint */
 				*dev_in_ep_desc;
@@ -542,7 +469,7 @@ static const struct usb_interface_descri
 	.bNumEndpoints =	1,
 	.bInterfaceClass =	USB_CLASS_COMM,
 	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ACM,
-	.bInterfaceProtocol =	USB_CDC_CTRL_PROTO_AT,
+	.bInterfaceProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
 	.iInterface =		GS_CONTROL_STR_ID,
 };
 
@@ -560,29 +487,29 @@ static const struct usb_interface_descri
 static const struct usb_cdc_header_desc gs_header_desc = {
 	.bLength =		sizeof(gs_header_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_SUBTYPE_HEADER,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
 	.bcdCDC =		__constant_cpu_to_le16(0x0110),
 };
 
-static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = {
+static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
 	.bLength =  		sizeof(gs_call_mgmt_descriptor),
 	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_SUBTYPE_CALL_MGMT,
+	.bDescriptorSubType = 	USB_CDC_CALL_MANAGEMENT_TYPE,
 	.bmCapabilities = 	0,
 	.bDataInterface = 	1,	/* index of data interface */
 };
 
-static struct usb_cdc_acm_desc gs_acm_descriptor = {
+static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
 	.bLength =  		sizeof(gs_acm_descriptor),
 	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_SUBTYPE_ACM,
+	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
 	.bmCapabilities = 	0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
 	.bLength =		sizeof(gs_union_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_SUBTYPE_UNION,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 };
@@ -1531,6 +1458,12 @@ static int gs_bind(struct usb_gadget *ga
 	} else if (gadget_is_pxa27x(gadget)) {
 		gs_device_desc.bcdDevice =
 			__constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
+	} else if (gadget_is_s3c2410(gadget)) {
+		gs_device_desc.bcdDevice =
+			__constant_cpu_to_le16(GS_VERSION_NUM|0x0012);
+	} else if (gadget_is_at91(gadget)) {
+		gs_device_desc.bcdDevice =
+			__constant_cpu_to_le16(GS_VERSION_NUM|0x0013);
 	} else {
 		printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
 			gadget->name);
@@ -1674,6 +1607,9 @@ static int gs_setup(struct usb_gadget *g
 	int ret = -EOPNOTSUPP;
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct usb_request *req = dev->dev_ctrl_req;
+	u16 wIndex = ctrl->wIndex;
+	u16 wValue = ctrl->wValue;
+	u16 wLength = ctrl->wLength;
 
 	switch (ctrl->bRequestType & USB_TYPE_MASK) {
 	case USB_TYPE_STANDARD:
@@ -1686,15 +1622,15 @@ static int gs_setup(struct usb_gadget *g
 
 	default:
 		printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
-			ctrl->wIndex, ctrl->wLength);
+			ctrl->bRequestType, ctrl->bRequest,
+			wValue, wIndex, wLength);
 		break;
 	}
 
 	/* respond with data transfer before status phase? */
 	if (ret >= 0) {
 		req->length = ret;
-		req->zero = ret < ctrl->wLength
+		req->zero = ret < wLength
 				&& (ret % gadget->ep0->maxpacket) == 0;
 		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
 		if (ret < 0) {
@@ -1715,15 +1651,18 @@ static int gs_setup_standard(struct usb_
 	int ret = -EOPNOTSUPP;
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct usb_request *req = dev->dev_ctrl_req;
+	u16 wIndex = ctrl->wIndex;
+	u16 wValue = ctrl->wValue;
+	u16 wLength = ctrl->wLength;
 
 	switch (ctrl->bRequest) {
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			break;
 
-		switch (ctrl->wValue >> 8) {
+		switch (wValue >> 8) {
 		case USB_DT_DEVICE:
-			ret = min(ctrl->wLength,
+			ret = min(wLength,
 				(u16)sizeof(struct usb_device_descriptor));
 			memcpy(req->buf, &gs_device_desc, ret);
 			break;
@@ -1732,7 +1671,7 @@ static int gs_setup_standard(struct usb_
 		case USB_DT_DEVICE_QUALIFIER:
 			if (!gadget->is_dualspeed)
 				break;
-			ret = min(ctrl->wLength,
+			ret = min(wLength,
 				(u16)sizeof(struct usb_qualifier_descriptor));
 			memcpy(req->buf, &gs_qualifier_desc, ret);
 			break;
@@ -1744,18 +1683,18 @@ static int gs_setup_standard(struct usb_
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			ret = gs_build_config_buf(req->buf, gadget->speed,
-				ctrl->wValue >> 8, ctrl->wValue & 0xff,
+				wValue >> 8, wValue & 0xff,
 				gadget->is_otg);
 			if (ret >= 0)
-				ret = min(ctrl->wLength, (u16)ret);
+				ret = min(wLength, (u16)ret);
 			break;
 
 		case USB_DT_STRING:
 			/* wIndex == language code. */
 			ret = usb_gadget_get_string(&gs_string_table,
-				ctrl->wValue & 0xff, req->buf);
+				wValue & 0xff, req->buf);
 			if (ret >= 0)
-				ret = min(ctrl->wLength, (u16)ret);
+				ret = min(wLength, (u16)ret);
 			break;
 		}
 		break;
@@ -1764,7 +1703,7 @@ static int gs_setup_standard(struct usb_
 		if (ctrl->bRequestType != 0)
 			break;
 		spin_lock(&dev->dev_lock);
-		ret = gs_set_config(dev, ctrl->wValue);
+		ret = gs_set_config(dev, wValue);
 		spin_unlock(&dev->dev_lock);
 		break;
 
@@ -1772,18 +1711,19 @@ static int gs_setup_standard(struct usb_
 		if (ctrl->bRequestType != USB_DIR_IN)
 			break;
 		*(u8 *)req->buf = dev->dev_config;
-		ret = min(ctrl->wLength, (u16)1);
+		ret = min(wLength, (u16)1);
 		break;
 
 	case USB_REQ_SET_INTERFACE:
 		if (ctrl->bRequestType != USB_RECIP_INTERFACE
-		|| !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES)
+				|| !dev->dev_config
+				|| wIndex >= GS_MAX_NUM_INTERFACES)
 			break;
 		if (dev->dev_config == GS_BULK_CONFIG_ID
-		&& ctrl->wIndex != GS_BULK_INTERFACE_ID)
+				&& wIndex != GS_BULK_INTERFACE_ID)
 			break;
 		/* no alternate interface settings */
-		if (ctrl->wValue != 0)
+		if (wValue != 0)
 			break;
 		spin_lock(&dev->dev_lock);
 		/* PXA hardware partially handles SET_INTERFACE;
@@ -1794,7 +1734,7 @@ static int gs_setup_standard(struct usb_
 			goto set_interface_done;
 		}
 		if (dev->dev_config != GS_BULK_CONFIG_ID
-		&& ctrl->wIndex == GS_CONTROL_INTERFACE_ID) {
+				&& wIndex == GS_CONTROL_INTERFACE_ID) {
 			if (dev->dev_notify_ep) {
 				usb_ep_disable(dev->dev_notify_ep);
 				usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc);
@@ -1814,21 +1754,21 @@ set_interface_done:
 		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
 		|| dev->dev_config == GS_NO_CONFIG_ID)
 			break;
-		if (ctrl->wIndex >= GS_MAX_NUM_INTERFACES
-		|| (dev->dev_config == GS_BULK_CONFIG_ID
-		&& ctrl->wIndex != GS_BULK_INTERFACE_ID)) {
+		if (wIndex >= GS_MAX_NUM_INTERFACES
+				|| (dev->dev_config == GS_BULK_CONFIG_ID
+				&& wIndex != GS_BULK_INTERFACE_ID)) {
 			ret = -EDOM;
 			break;
 		}
 		/* no alternate interface settings */
 		*(u8 *)req->buf = 0;
-		ret = min(ctrl->wLength, (u16)1);
+		ret = min(wLength, (u16)1);
 		break;
 
 	default:
 		printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
-			ctrl->wIndex, ctrl->wLength);
+			ctrl->bRequestType, ctrl->bRequest,
+			wValue, wIndex, wLength);
 		break;
 	}
 
@@ -1842,10 +1782,13 @@ static int gs_setup_class(struct usb_gad
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct gs_port *port = dev->dev_port[0];	/* ACM only has one port */
 	struct usb_request *req = dev->dev_ctrl_req;
+	u16 wIndex = ctrl->wIndex;
+	u16 wValue = ctrl->wValue;
+	u16 wLength = ctrl->wLength;
 
 	switch (ctrl->bRequest) {
 	case USB_CDC_REQ_SET_LINE_CODING:
-		ret = min(ctrl->wLength,
+		ret = min(wLength,
 			(u16)sizeof(struct usb_cdc_line_coding));
 		if (port) {
 			spin_lock(&port->port_lock);
@@ -1856,7 +1799,7 @@ static int gs_setup_class(struct usb_gad
 
 	case USB_CDC_REQ_GET_LINE_CODING:
 		port = dev->dev_port[0];	/* ACM only has one port */
-		ret = min(ctrl->wLength,
+		ret = min(wLength,
 			(u16)sizeof(struct usb_cdc_line_coding));
 		if (port) {
 			spin_lock(&port->port_lock);
@@ -1871,8 +1814,8 @@ static int gs_setup_class(struct usb_gad
 
 	default:
 		printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
-			ctrl->wIndex, ctrl->wLength);
+			ctrl->bRequestType, ctrl->bRequest,
+			wValue, wIndex, wLength);
 		break;
 	}
 
@@ -2272,7 +2215,7 @@ static int gs_alloc_ports(struct gs_dev 
 		memset(port, 0, sizeof(struct gs_port));
 		port->port_dev = dev;
 		port->port_num = i;
-		port->port_line_coding.dwDTERate = GS_DEFAULT_DTE_RATE;
+		port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
 		port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
 		port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
 		port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
@@ -2324,6 +2267,7 @@ static void gs_free_ports(struct gs_dev 
 				}
 				spin_unlock_irqrestore(&port->port_lock, flags);
 			} else {
+				spin_unlock_irqrestore(&port->port_lock, flags);
 				kfree(port);
 			}
 
@@ -2368,9 +2312,8 @@ static struct gs_buf *gs_buf_alloc(unsig
  */
 void gs_buf_free(struct gs_buf *gb)
 {
-	if (gb != NULL) {
-		if (gb->buf_buf != NULL)
-			kfree(gb->buf_buf);
+	if (gb) {
+		kfree(gb->buf_buf);
 		kfree(gb);
 	}
 }
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -20,7 +20,7 @@
 #include <asm/unaligned.h>
 
 
-static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
+static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
 {
 	int	count = 0;
 	u8	c;
@@ -126,7 +126,7 @@ usb_gadget_get_string (struct usb_gadget
 	/* string descriptors have length, tag, then UTF16-LE text */
 	len = min ((size_t) 126, strlen (s->s));
 	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
-	len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
+	len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
 	if (len < 0)
 		return -EINVAL;
 	buf [0] = (len + 1) * 2;
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -919,6 +919,9 @@ zero_setup (struct usb_gadget *gadget, c
 	struct zero_dev		*dev = get_gadget_data (gadget);
 	struct usb_request	*req = dev->req;
 	int			value = -EOPNOTSUPP;
+	u16			w_index = ctrl->wIndex;
+	u16			w_value = ctrl->wValue;
+	u16			w_length = ctrl->wLength;
 
 	/* usually this stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will reconfigure hardware.
@@ -929,17 +932,17 @@ zero_setup (struct usb_gadget *gadget, c
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			goto unknown;
-		switch (ctrl->wValue >> 8) {
+		switch (w_value >> 8) {
 
 		case USB_DT_DEVICE:
-			value = min (ctrl->wLength, (u16) sizeof device_desc);
+			value = min (w_length, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			if (!gadget->is_dualspeed)
 				break;
-			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+			value = min (w_length, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
@@ -950,10 +953,10 @@ zero_setup (struct usb_gadget *gadget, c
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget, req->buf,
-					ctrl->wValue >> 8,
-					ctrl->wValue & 0xff);
+					w_value >> 8,
+					w_value & 0xff);
 			if (value >= 0)
-				value = min (ctrl->wLength, (u16) value);
+				value = min (w_length, (u16) value);
 			break;
 
 		case USB_DT_STRING:
@@ -963,9 +966,9 @@ zero_setup (struct usb_gadget *gadget, c
 			 * any UTF-8 characters
 			 */
 			value = usb_gadget_get_string (&stringtab,
-					ctrl->wValue & 0xff, req->buf);
+					w_value & 0xff, req->buf);
 			if (value >= 0)
-				value = min (ctrl->wLength, (u16) value);
+				value = min (w_length, (u16) value);
 			break;
 		}
 		break;
@@ -981,14 +984,14 @@ zero_setup (struct usb_gadget *gadget, c
 		else
 			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
-		value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+		value = zero_set_config (dev, w_value, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
 		if (ctrl->bRequestType != USB_DIR_IN)
 			goto unknown;
 		*(u8 *)req->buf = dev->config;
-		value = min (ctrl->wLength, (u16) 1);
+		value = min (w_length, (u16) 1);
 		break;
 
 	/* until we add altsetting support, or other interfaces,
@@ -999,7 +1002,7 @@ zero_setup (struct usb_gadget *gadget, c
 		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
 			goto unknown;
 		spin_lock (&dev->lock);
-		if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) {
+		if (dev->config && w_index == 0 && w_value == 0) {
 			u8		config = dev->config;
 
 			/* resets interface configuration, forgets about
@@ -1020,12 +1023,12 @@ zero_setup (struct usb_gadget *gadget, c
 			goto unknown;
 		if (!dev->config)
 			break;
-		if (ctrl->wIndex != 0) {
+		if (w_index != 0) {
 			value = -EDOM;
 			break;
 		}
 		*(u8 *)req->buf = 0;
-		value = min (ctrl->wLength, (u16) 1);
+		value = min (w_length, (u16) 1);
 		break;
 
 	/*
@@ -1036,23 +1039,23 @@ zero_setup (struct usb_gadget *gadget, c
 	case 0x5b:	/* control WRITE test -- fill the buffer */
 		if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
 			goto unknown;
-		if (ctrl->wValue || ctrl->wIndex)
+		if (w_value || w_index)
 			break;
 		/* just read that many bytes into the buffer */
-		if (ctrl->wLength > USB_BUFSIZ)
+		if (w_length > USB_BUFSIZ)
 			break;
-		value = ctrl->wLength;
+		value = w_length;
 		break;
 	case 0x5c:	/* control READ test -- return the buffer */
 		if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
 			goto unknown;
-		if (ctrl->wValue || ctrl->wIndex)
+		if (w_value || w_index)
 			break;
 		/* expect those bytes are still in the buffer; send back */
-		if (ctrl->wLength > USB_BUFSIZ
-				|| ctrl->wLength != req->length)
+		if (w_length > USB_BUFSIZ
+				|| w_length != req->length)
 			break;
-		value = ctrl->wLength;
+		value = w_length;
 		break;
 
 	default:
@@ -1060,14 +1063,13 @@ unknown:
 		VDBG (dev,
 			"unknown control req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+			w_value, w_index, w_length);
 	}
 
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
-		req->zero = value < ctrl->wLength
-				&& (value % gadget->ep0->maxpacket) == 0;
+		req->zero = value < w_length;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
@@ -1191,6 +1193,10 @@ autoconf_fail:
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
 	} else if (gadget_is_pxa27x(gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+	} else if (gadget_is_s3c2410(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
+	} else if (gadget_is_at91(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
 	} else {
 		/* gadget zero is so simple (for now, no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -1,21 +1,3 @@
-# Host-side USB depends on having a host controller
-# NOTE:  dummy_hcd is always an option, but it's ignored here ...
-# NOTE:  SL-811 option should be board-specific ...
-config USB_ARCH_HAS_HCD
-	boolean
-	default y if USB_ARCH_HAS_OHCI
-	default y if ARM				# SL-811
-	default PCI
-
-# many non-PCI hcds implement OHCI
-config USB_ARCH_HAS_OHCI
-	boolean
-	default y if SA1111
-	default y if ARCH_OMAP
-	default y if ARCH_LH7A404
-	default y if PXA27x
-	default PCI
-
 #
 # USB Host Controller Drivers
 #
@@ -65,7 +47,7 @@ config USB_EHCI_ROOT_HUB_TT
 	  controller is needed.  It's safe to say "y" even if your
 	  controller doesn't support this feature.
 
-	  This supports the EHCI implementation from ARC International.
+	  This supports the EHCI implementation from TransDimension Inc.
 
 config USB_OHCI_HCD
 	tristate "OHCI HCD support"
@@ -84,6 +66,35 @@ config USB_OHCI_HCD
 	  To compile this driver as a module, choose M here: the
 	  module will be called ohci-hcd.
 
+config USB_OHCI_HCD_PPC_SOC
+	bool "OHCI support for on-chip PPC USB controller"
+	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_BIG_ENDIAN
+	---help---
+	  Enables support for the USB controller on the MPC52xx or
+	  STB03xxx processor chip.  If unsure, say Y.
+
+config USB_OHCI_HCD_PCI
+	bool "OHCI support for PCI-bus USB controllers"
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_LITTLE_ENDIAN
+	---help---
+	  Enables support for PCI-bus plug-in USB controller cards.
+	  If unsure, say Y.
+
+config USB_OHCI_BIG_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_LITTLE_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n if STB03xxx || PPC_MPC52xx
+	default y
+
 config USB_UHCI_HCD
 	tristate "UHCI HCD (most Intel and VIA) support"
 	depends on USB && PCI
@@ -113,3 +124,14 @@ config USB_SL811_HCD
 	  To compile this driver as a module, choose M here: the
 	  module will be called sl811-hcd.
 
+config USB_SL811_CS
+	tristate "CF/PCMCIA support for SL811HS HCD"
+	depends on USB_SL811_HCD && PCMCIA
+	default N
+	help
+	  Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC
+	  REX-CFU1U CF card (often used with PDAs).  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called "sl811_cs".
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
 obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
+obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 obj-$(CONFIG_ETRAX_ARCH_V10)	+= hc_crisv10.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -394,7 +394,7 @@ static void qh_lines (
 		mark = ' ';
 		if (hw_curr == td->qtd_dma)
 			mark = '*';
-		else if (qh->hw_qtd_next == td->qtd_dma)
+		else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma))
 			mark = '+';
 		else if (QTD_LENGTH (scratch)) {
 			if (td->hw_alt_next == ehci->async->hw_alt_next)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -191,17 +191,38 @@ static int ehci_halt (struct ehci_hcd *e
 	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
 }
 
+/* put TDI/ARC silicon into EHCI mode */
+static void tdi_reset (struct ehci_hcd *ehci)
+{
+	u32 __iomem	*reg_ptr;
+	u32		tmp;
+
+	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
+	tmp = readl (reg_ptr);
+	tmp |= 0x3;
+	writel (tmp, reg_ptr);
+}
+
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
+	int	retval;
 	u32	command = readl (&ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	writel (command, &ehci->regs->command);
-	ehci_to_hcd(ehci)->state = USB_STATE_HALT;
+	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 	ehci->next_statechange = jiffies;
-	return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+
+	if (retval)
+		return retval;
+
+	if (ehci_is_TDI(ehci))
+		tdi_reset (ehci);
+
+	return retval;
 }
 
 /* idle the controller (from running) */
@@ -210,7 +231,7 @@ static void ehci_quiesce (struct ehci_hc
 	u32	temp;
 
 #ifdef DEBUG
-	if (!HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))
+	if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 		BUG ();
 #endif
 
@@ -219,7 +240,7 @@ static void ehci_quiesce (struct ehci_hc
 	temp &= STS_ASS | STS_PSS;
 	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
 				temp, 16 * 125) != 0) {
-		ehci_to_hcd(ehci)->state = USB_STATE_HALT;
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 	}
 
@@ -231,7 +252,7 @@ static void ehci_quiesce (struct ehci_hc
 	/* hardware can take 16 microframes to turn off ... */
 	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
 				0, 16 * 125) != 0) {
-		ehci_to_hcd(ehci)->state = USB_STATE_HALT;
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 	}
 }
@@ -325,6 +346,22 @@ ehci_reboot (struct notifier_block *self
 	return 0;
 }
 
+static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+{
+	unsigned port;
+
+	if (!HCS_PPC (ehci->hcs_params))
+		return;
+
+	ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
+	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+		(void) ehci_hub_control(ehci_to_hcd(ehci),
+				is_on ? SetPortFeature : ClearPortFeature,
+				USB_PORT_FEAT_POWER,
+				port--, NULL, 0);
+	msleep(20);
+}
+
 
 /* called by khubd or root hub init threads */
 
@@ -341,21 +378,53 @@ static int ehci_hc_reset (struct usb_hcd
 	dbg_hcs_params (ehci, "reset");
 	dbg_hcc_params (ehci, "reset");
 
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
 #ifdef	CONFIG_PCI
-	/* EHCI 0.96 and later may have "extended capabilities" */
 	if (hcd->self.controller->bus == &pci_bus_type) {
 		struct pci_dev	*pdev = to_pci_dev(hcd->self.controller);
 
-		/* AMD8111 EHCI doesn't work, according to AMD errata */
-		if ((pdev->vendor == PCI_VENDOR_ID_AMD)
-				&& (pdev->device == 0x7463)) {
-			ehci_info (ehci, "ignoring AMD8111 (errata)\n");
-			return -EIO;
+		switch (pdev->vendor) {
+		case PCI_VENDOR_ID_TDI:
+			if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+				ehci->is_tdi_rh_tt = 1;
+				tdi_reset (ehci);
+			}
+			break;
+		case PCI_VENDOR_ID_AMD:
+			/* AMD8111 EHCI doesn't work, according to AMD errata */
+			if (pdev->device == 0x7463) {
+				ehci_info (ehci, "ignoring AMD8111 (errata)\n");
+				return -EIO;
+			}
+			break;
+		}
+
+		/* optional debug port, normally in the first BAR */
+		temp = pci_find_capability (pdev, 0x0a);
+		if (temp) {
+			pci_read_config_dword(pdev, temp, &temp);
+			temp >>= 16;
+			if ((temp & (3 << 13)) == (1 << 13)) {
+				temp &= 0x1fff;
+				ehci->debug = hcd->regs + temp;
+				temp = readl (&ehci->debug->control);
+				ehci_info (ehci, "debug port %d%s\n",
+					HCS_DEBUG_PORT(ehci->hcs_params),
+					(temp & DBGP_ENABLED)
+						? " IN USE"
+						: "");
+				if (!(temp & DBGP_ENABLED))
+					ehci->debug = NULL;
+			}
 		}
 
 		temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
 	} else
 		temp = 0;
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
 	while (temp && count--) {
 		u32		cap;
 
@@ -380,10 +449,11 @@ static int ehci_hc_reset (struct usb_hcd
 		ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
 		return -EIO;
 	}
+	if (ehci_is_TDI(ehci))
+		ehci_reset (ehci);
 #endif
 
-	/* cache this readonly data; minimize PCI reads */
-	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+	ehci_port_power (ehci, 0);
 
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
@@ -481,15 +551,6 @@ static int ehci_start (struct usb_hcd *h
 
 		/* help hc dma work well with cachelines */
 		pci_set_mwi (pdev);
-
-		/* chip-specific init */
-		switch (pdev->vendor) {
-		case PCI_VENDOR_ID_ARC:
-			if (pdev->device == PCI_DEVICE_ID_ARC_EHCI)
-				ehci->is_arc_rh_tt = 1;
-			break;
-		}
-
 	}
 #endif
 
@@ -592,7 +653,7 @@ done2:
 		register_reboot_notifier (&ehci->reboot_notifier);
 	}
 
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 	writel (FLAG_CF, &ehci->regs->configured_flag);
 	readl (&ehci->regs->command);	/* unblock posted write */
 
@@ -612,8 +673,8 @@ done2:
 	 * Before this point the HC was idle/ready.  After, khubd
 	 * and device drivers may start it running.
 	 */
-	if (first && hcd_register_root (udev, hcd) != 0) {
-		if (hcd->state == USB_STATE_RUNNING)
+	if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
+		if (hcd->state == HC_STATE_RUNNING)
 			ehci_quiesce (ehci);
 		ehci_reset (ehci);
 		usb_put_dev (udev); 
@@ -634,22 +695,17 @@ done2:
 static void ehci_stop (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u8			rh_ports, port;
 
 	ehci_dbg (ehci, "stop\n");
 
 	/* Turn off port power on all root hub ports. */
-	rh_ports = HCS_N_PORTS (ehci->hcs_params);
-	for (port = 1; port <= rh_ports; port++)
-		(void) ehci_hub_control(hcd,
-			ClearPortFeature, USB_PORT_FEAT_POWER,
-			port, NULL, 0);
+	ehci_port_power (ehci, 0);
 
 	/* no more interrupts ... */
 	del_timer_sync (&ehci->watchdog);
 
 	spin_lock_irq(&ehci->lock);
-	if (HCD_IS_RUNNING (hcd->state))
+	if (HC_IS_RUNNING (hcd->state))
 		ehci_quiesce (ehci);
 
 	ehci_reset (ehci);
@@ -698,7 +754,7 @@ static int ehci_get_frame (struct usb_hc
  * the right sort of wakeup.  
  */
 
-static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 
@@ -706,7 +762,7 @@ static int ehci_suspend (struct usb_hcd 
 		msleep (100);
 
 #ifdef	CONFIG_USB_SUSPEND
-	(void) usb_suspend_device (hcd->self.root_hub, state);
+	(void) usb_suspend_device (hcd->self.root_hub, message);
 #else
 	usb_lock_device (hcd->self.root_hub);
 	(void) ehci_hub_suspend (hcd);
@@ -725,7 +781,6 @@ static int ehci_resume (struct usb_hcd *
 	unsigned		port;
 	struct usb_device	*root = hcd->self.root_hub;
 	int			retval = -EINVAL;
-	int			powerup = 0;
 
 	// maybe restore (PCI) FLADJ
 
@@ -743,8 +798,6 @@ static int ehci_resume (struct usb_hcd *
 			up (&hcd->self.root_hub->serialize);
 			break;
 		}
-		if ((status & PORT_POWER) == 0)
-			powerup = 1;
 		if (!root->children [port])
 			continue;
 		dbg_port (ehci, __FUNCTION__, port + 1, status);
@@ -771,16 +824,9 @@ static int ehci_resume (struct usb_hcd *
 		retval = ehci_start (hcd);
 
 		/* here we "know" root ports should always stay powered;
-		 * but some controllers may lost all power.
+		 * but some controllers may lose all power.
 		 */
-		if (powerup) {
-			ehci_dbg (ehci, "...powerup ports...\n");
-			for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
-				(void) ehci_hub_control(hcd,
-					SetPortFeature, USB_PORT_FEAT_POWER,
-						port--, NULL, 0);
-			msleep(20);
-		}
+		ehci_port_power (ehci, 1);
 	}
 
 	return retval;
@@ -816,7 +862,7 @@ static void ehci_work (struct ehci_hcd *
 	 * misplace IRQs, and should let us run completely without IRQs.
 	 * such lossage has been observed on both VT6202 and VT8235. 
 	 */
-	if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
 			(ehci->async->qh_next.ptr != NULL ||
 			 ehci->periodic_sched != 0))
 		timer_action (ehci, TIMER_IO_WATCHDOG);
@@ -977,7 +1023,7 @@ static void unlink_async (struct ehci_hc
 	/* if we need to use IAA and it's busy, defer */
 	if (qh->qh_state == QH_STATE_LINKED
 			&& ehci->reclaim
-			&& HCD_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
 		struct ehci_qh		*last;
 
 		for (last = ehci->reclaim;
@@ -988,7 +1034,7 @@ static void unlink_async (struct ehci_hc
 		last->reclaim = qh;
 
 	/* bypass IAA if the hc can't care */
-	} else if (!HCD_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
+	} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
 		end_unlink_async (ehci, NULL);
 
 	/* something else might have unlinked the qh by now */
@@ -1036,7 +1082,7 @@ static int ehci_urb_dequeue (struct usb_
 
 		/* reschedule QH iff another request is queued */
 		if (!list_empty (&qh->qtd_list)
-				&& HCD_IS_RUNNING (hcd->state)) {
+				&& HC_IS_RUNNING (hcd->state)) {
 			int status;
 
 			status = qh_schedule (ehci, qh);
@@ -1092,7 +1138,7 @@ rescan:
 		goto idle_timeout;
 	}
 
-	if (!HCD_IS_RUNNING (hcd->state))
+	if (!HC_IS_RUNNING (hcd->state))
 		qh->qh_state = QH_STATE_IDLE;
 	switch (qh->qh_state) {
 	case QH_STATE_LINKED:
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -42,9 +42,9 @@ static int ehci_hub_suspend (struct usb_
 	spin_lock_irq (&ehci->lock);
 
 	/* stop schedules, clean any completed work */
-	if (HCD_IS_RUNNING(hcd->state)) {
+	if (HC_IS_RUNNING(hcd->state)) {
 		ehci_quiesce (ehci);
-		hcd->state = USB_STATE_QUIESCING;
+		hcd->state = HC_STATE_QUIESCING;
 	}
 	ehci->command = readl (&ehci->regs->command);
 	if (ehci->reclaim)
@@ -72,8 +72,9 @@ static int ehci_hub_suspend (struct usb_
 	}
 
 	/* turn off now-idle HC */
+	del_timer_sync (&ehci->watchdog);
 	ehci_halt (ehci);
-	hcd->state = HCD_STATE_SUSPENDED;
+	hcd->state = HC_STATE_SUSPENDED;
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	spin_unlock_irq (&ehci->lock);
@@ -145,7 +146,7 @@ static int ehci_hub_resume (struct usb_h
 	}
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 	/* Now we can safely re-enable irqs */
 	if (intr_enable)
@@ -178,7 +179,7 @@ static int check_reset_complete (
 	if (!(port_status & PORT_PE)) {
 
 		/* with integrated TT, there's nobody to hand it to! */
-		if (ehci_is_ARC(ehci)) {
+		if (ehci_is_TDI(ehci)) {
 			ehci_dbg (ehci,
 				"Failed to enable port %d on root hub TT\n",
 				index+1);
@@ -212,7 +213,7 @@ ehci_hub_status_data (struct usb_hcd *hc
 	unsigned long	flags;
 
 	/* if !USB_SUSPEND, root hub timers won't get shut down ... */
-	if (!HCD_IS_RUNNING(hcd->state))
+	if (!HC_IS_RUNNING(hcd->state))
 		return 0;
 
 	/* init status to no-changes */
@@ -281,6 +282,8 @@ ehci_hub_descriptor (
 	temp = 0x0008;			/* per-port overcurrent reporting */
 	if (HCS_PPC (ehci->hcs_params))
 		temp |= 0x0001;		/* per-port power control */
+	else
+		temp |= 0x0002;		/* no power switching */
 #if 0
 // re-enable when we support USB_PORT_FEAT_INDICATOR below.
 	if (HCS_INDICATOR (ehci->hcs_params))
@@ -436,9 +439,12 @@ static int ehci_hub_control (
 			/* force reset to complete */
 			writel (temp & ~PORT_RESET,
 					&ehci->regs->port_status [wIndex]);
+			/* REVISIT:  some hardware needs 550+ usec to clear
+			 * this bit; seems too long to spin routinely...
+			 */
 			retval = handshake (
 					&ehci->regs->port_status [wIndex],
-					PORT_RESET, 0, 500);
+					PORT_RESET, 0, 750);
 			if (retval != 0) {
 				ehci_err (ehci, "port %d reset error %d\n",
 					wIndex + 1, retval);
@@ -517,7 +523,7 @@ static int ehci_hub_control (
 			 * transaction translator built in.
 			 */
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
-					&& !ehci_is_ARC(ehci)
+					&& !ehci_is_TDI(ehci)
 					&& PORT_USB11 (temp)) {
 				ehci_dbg (ehci,
 					"port %d low speed --> companion\n",
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -156,8 +156,7 @@ static void ehci_mem_cleanup (struct ehc
 	ehci->periodic = NULL;
 
 	/* shadow periodic table */
-	if (ehci->pshadow)
-		kfree (ehci->pshadow);
+	kfree(ehci->pshadow);
 	ehci->pshadow = NULL;
 }
 
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -198,7 +198,7 @@ static void qtd_copy_status (
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
-				&& (!ehci_is_ARC(ehci)
+				&& (!ehci_is_TDI(ehci)
                 	                || urb->dev->tt->hub !=
 					   ehci_to_hcd(ehci)->self.root_hub)) {
 #ifdef DEBUG
@@ -338,23 +338,24 @@ qh_completions (struct ehci_hcd *ehci, s
 			if ((token & QTD_STS_HALT) != 0) {
 				stopped = 1;
 
-			/* magic dummy for some short reads; qh won't advance */
+			/* magic dummy for some short reads; qh won't advance.
+			 * that silicon quirk can kick in with this dummy too.
+			 */
 			} else if (IS_SHORT_READ (token)
-					&& (qh->hw_alt_next & QTD_MASK)
-						== ehci->async->hw_alt_next) {
+					&& !(qtd->hw_alt_next & EHCI_LIST_END)) {
 				stopped = 1;
 				goto halt;
 			}
 
 		/* stop scanning when we reach qtds the hc is using */
 		} else if (likely (!stopped
-				&& HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
+				&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
 			break;
 
 		} else {
 			stopped = 1;
 
-			if (unlikely (!HCD_IS_RUNNING (ehci_to_hcd(ehci)->state)))
+			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
 				urb->status = -ESHUTDOWN;
 
 			/* ignore active urbs unless some previous qtd
@@ -522,7 +523,7 @@ qh_urb_transaction (
 	else
 		buf = 0;
 
-	// FIXME this 'buf' check break some zlps...
+	/* for zero length DATA stages, STATUS is always IN */
 	if (!buf || is_input)
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
@@ -714,10 +715,10 @@ qh_make (
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
 
-		/* set the address of the TT; for ARC's integrated
+		/* set the address of the TT; for TDI's integrated
 		 * root hub tt, leave it zeroed.
 		 */
-		if (!ehci_is_ARC(ehci)
+		if (!ehci_is_TDI(ehci)
 				|| urb->dev->tt->hub !=
 					ehci_to_hcd(ehci)->self.root_hub)
 			info2 |= urb->dev->tt->hub->devnum << 16;
@@ -780,7 +781,7 @@ static void qh_link_async (struct ehci_h
 			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
 			cmd |= CMD_ASE | CMD_RUN;
 			writel (cmd, &ehci->regs->command);
-			ehci_to_hcd(ehci)->state = USB_STATE_RUNNING;
+			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			/* posted write need not be known to HC yet ... */
 		}
 	}
@@ -959,7 +960,7 @@ static void end_unlink_async (struct ehc
 	qh_completions (ehci, qh, regs);
 
 	if (!list_empty (&qh->qtd_list)
-			&& HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))
+			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 		qh_link_async (ehci, qh);
 	else {
 		qh_put (qh);		// refcount from async list
@@ -967,7 +968,7 @@ static void end_unlink_async (struct ehc
 		/* it's not free to turn the async schedule on/off; leave it
 		 * active but idle for a while once it empties.
 		 */
-		if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state)
+		if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
 				&& ehci->async->qh_next.qh == NULL)
 			timer_action (ehci, TIMER_ASYNC_OFF);
 	}
@@ -998,7 +999,7 @@ static void start_unlink_async (struct e
 	/* stop async schedule right now? */
 	if (unlikely (qh == ehci->async)) {
 		/* can't get here without STS_ASS set */
-		if (ehci_to_hcd(ehci)->state != USB_STATE_HALT) {
+		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
 			writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			wmb ();
 			// handshake later, if we need to
@@ -1018,7 +1019,7 @@ static void start_unlink_async (struct e
 	prev->qh_next = qh->qh_next;
 	wmb ();
 
-	if (unlikely (ehci_to_hcd(ehci)->state == USB_STATE_HALT)) {
+	if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
 		/* if (unlikely (qh->reclaim != 0))
 		 * 	this will recurse, probably not much
 		 */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -208,7 +208,7 @@ static int tt_no_collision (
 				here = here.qh->qh_next;
 				continue;
 			case Q_TYPE_SITD:
-				if (same_tt (dev, here.itd->urb->dev)) {
+				if (same_tt (dev, here.sitd->urb->dev)) {
 					u16		mask;
 
 					mask = le32_to_cpu (here.sitd
@@ -218,7 +218,7 @@ static int tt_no_collision (
 					if (mask & uf_mask)
 						break;
 				}
-				type = Q_NEXT_TYPE (here.qh->hw_next);
+				type = Q_NEXT_TYPE (here.sitd->hw_next);
 				here = here.sitd->sitd_next;
 				continue;
 			// case Q_TYPE_FSTN:
@@ -249,14 +249,14 @@ static int enable_periodic (struct ehci_
 	 */
 	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
 	if (status != 0) {
-		ehci_to_hcd(ehci)->state = USB_STATE_HALT;
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
 	cmd = readl (&ehci->regs->command) | CMD_PSE;
 	writel (cmd, &ehci->regs->command);
 	/* posted write ... PSS happens later */
-	ehci_to_hcd(ehci)->state = USB_STATE_RUNNING;
+	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 	/* make sure ehci_work scans these */
 	ehci->next_uframe = readl (&ehci->regs->frame_index)
@@ -274,7 +274,7 @@ static int disable_periodic (struct ehci
 	 */
 	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
 	if (status != 0) {
-		ehci_to_hcd(ehci)->state = USB_STATE_HALT;
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
@@ -310,9 +310,9 @@ static int qh_link_periodic (struct ehci
 
 	for (i = qh->start; i < ehci->periodic_size; i += period) {
 		union ehci_shadow	*prev = &ehci->pshadow [i];
-		u32			*hw_p = &ehci->periodic [i];
+		__le32			*hw_p = &ehci->periodic [i];
 		union ehci_shadow	here = *prev;
-		u32			type = 0;
+		__le32			type = 0;
 
 		/* skip the iso nodes at list head */
 		while (here.ptr) {
@@ -650,6 +650,7 @@ iso_stream_alloc (int mem_flags)
 
 static void
 iso_stream_init (
+	struct ehci_hcd		*ehci,
 	struct ehci_iso_stream	*stream,
 	struct usb_device	*dev,
 	int			pipe,
@@ -701,7 +702,10 @@ iso_stream_init (
 		u32		addr;
 
 		addr = dev->ttport << 24;
-		addr |= dev->tt->hub->devnum << 16;
+		if (!ehci_is_TDI(ehci)
+				|| (dev->tt->hub !=
+					ehci_to_hcd(ehci)->self.root_hub))
+			addr |= dev->tt->hub->devnum << 16;
 		addr |= epnum << 8;
 		addr |= dev->devnum;
 		stream->usecs = HS_USECS_ISO (maxp);
@@ -819,7 +823,7 @@ iso_stream_find (struct ehci_hcd *ehci, 
 			/* dev->ep owns the initial refcount */
 			ep->hcpriv = stream;
 			stream->ep = ep;
-			iso_stream_init(stream, urb->dev, urb->pipe,
+			iso_stream_init(ehci, stream, urb->dev, urb->pipe,
 					urb->interval);
 		}
 
@@ -1176,7 +1180,10 @@ fail:
 	return status;
 
 ready:
+	/* report high speed start in uframes; full speed, in frames */
 	urb->start_frame = stream->next_uframe;
+	if (!stream->highspeed)
+		urb->start_frame >>= 3;
 	return 0;
 }
 
@@ -1500,18 +1507,17 @@ sitd_sched_init (
 
 		/* might need to cross a buffer page within a td */
 		packet->bufp = buf;
-		buf += length;
-		packet->buf1 = buf & ~0x0fff;
+		packet->buf1 = (buf + length) & ~0x0fff;
 		if (packet->buf1 != (buf & ~(u64)0x0fff))
 			packet->cross = 1;
 
 		/* OUT uses multiple start-splits */ 
 		if (stream->bEndpointAddress & USB_DIR_IN)
 			continue;
-		length = 1 + (length / 188);
-		packet->buf1 |= length;
+		length = (length + 187) / 188;
 		if (length > 1) /* BEGIN vs ALL */
-			packet->buf1 |= 1 << 3;
+			length |= 1 << 3;
+		packet->buf1 |= length;
 	}
 }
 
@@ -1606,10 +1612,9 @@ sitd_patch (
 	sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
 
 	sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
-	if (uf->cross) {
+	if (uf->cross)
 		bufp += 4096;
-		sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
-	}
+	sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
 	sitd->index = index;
 }
 
@@ -1646,7 +1651,7 @@ sitd_link_urb (
 		ehci_to_hcd(ehci)->self.bandwidth_allocated
 				+= stream->bandwidth;
 		ehci_vdbg (ehci,
-			"sched dev%s ep%d%s-iso [%d] %dms/%04x\n",
+			"sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
 			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 			(next_uframe >> 3) % ehci->periodic_size,
@@ -1693,7 +1698,7 @@ sitd_link_urb (
 /*-------------------------------------------------------------------------*/
 
 #define	SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
-			| SITD_STS_XACT | SITD_STS_MMF | SITD_STS_STS)
+	       			| SITD_STS_XACT | SITD_STS_MMF)
 
 static unsigned
 sitd_complete (
@@ -1776,12 +1781,6 @@ static int sitd_submit (struct ehci_hcd 
 	unsigned long		flags;
 	struct ehci_iso_stream	*stream;
 
-	// FIXME remove when csplits behave
-	if (usb_pipein(urb->pipe)) {
-		ehci_dbg (ehci, "no iso-IN split transactions yet\n");
-		return -ENOMEM;
-	}
-
 	/* Get iso_stream head */
 	stream = iso_stream_find (ehci, urb);
 	if (stream == NULL) {
@@ -1860,7 +1859,7 @@ scan_periodic (struct ehci_hcd *ehci, st
 	 * Touches as few pages as possible:  cache-friendly.
 	 */
 	now_uframe = ehci->next_uframe;
-	if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))
+	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 		clock = readl (&ehci->regs->frame_index);
 	else
 		clock = now_uframe + mod - 1;
@@ -1894,7 +1893,7 @@ restart:
 			union ehci_shadow	temp;
 			int			live;
 
-			live = HCD_IS_RUNNING (ehci_to_hcd(ehci)->state);
+			live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
 			switch (type) {
 			case Q_TYPE_QH:
 				/* handle any completions */
@@ -1983,7 +1982,7 @@ restart:
 		if (now_uframe == clock) {
 			unsigned	now;
 
-			if (!HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))
+			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 				break;
 			ehci->next_uframe = now_uframe;
 			now = readl (&ehci->regs->frame_index) % mod;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -47,6 +47,12 @@ struct ehci_stats {
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 
 struct ehci_hcd {			/* one per controller */
+	/* glue to PCI and HCD framework */
+	struct ehci_caps __iomem *caps;
+	struct ehci_regs __iomem *regs;
+	struct ehci_dbg_port __iomem *debug;
+
+	__u32			hcs_params;	/* cached register copy */
 	spinlock_t		lock;
 
 	/* async schedule support */
@@ -82,12 +88,7 @@ struct ehci_hcd {			/* one per controlle
 	unsigned long		next_statechange;
 	u32			command;
 
-	unsigned		is_arc_rh_tt:1;	/* ARC roothub with TT */
-
-	/* glue to PCI and HCD framework */
-	struct ehci_caps __iomem *caps;
-	struct ehci_regs __iomem *regs;
-	__u32			hcs_params;	/* cached register copy */
+	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 
 	/* irq statistics */
 #ifdef EHCI_STATS
@@ -165,7 +166,7 @@ struct ehci_caps {
 	/* these fields are specified as 8 and 16 bit registers,
 	 * but some hosts can't perform 8 or 16 bit PCI accesses.
 	 */
-	u32	hc_capbase;
+	u32		hc_capbase;
 #define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
 #define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
 	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
@@ -273,7 +274,7 @@ struct ehci_dbg_port {
 #define DBGP_ENABLED	(1<<28)
 #define DBGP_DONE	(1<<16)
 #define DBGP_INUSE	(1<<10)
-#define DBGP_ERRCODE(x)	(((x)>>7)&0x0f)
+#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
 #	define DBGP_ERR_BAD	1
 #	define DBGP_ERR_SIGNAL	2
 #define DBGP_ERROR	(1<<6)
@@ -282,11 +283,11 @@ struct ehci_dbg_port {
 #define DBGP_LEN(x)	(((x)>>0)&0x0f)
 	u32	pids;
 #define DBGP_PID_GET(x)		(((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok)	(((data)<<8)|(tok));
+#define DBGP_PID_SET(data,tok)	(((data)<<8)|(tok))
 	u32	data03;
 	u32	data47;
 	u32	address;
-#define DBGP_EPADDR(dev,ep)	(((dev)<<8)|(ep));
+#define DBGP_EPADDR(dev,ep)	(((dev)<<8)|(ep))
 } __attribute__ ((packed));
 
 /*-------------------------------------------------------------------------*/
@@ -364,7 +365,7 @@ union ehci_shadow {
 	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
 	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
 	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
-	u32			*hw_next;	/* (all types) */
+	__le32			*hw_next;	/* (all types) */
 	void			*ptr;
 };
 
@@ -430,7 +431,7 @@ struct ehci_iso_packet {
 	__le32			transaction;	/* itd->hw_transaction[i] |= */
 	u8			cross;		/* buf crosses pages */
 	/* for full speed OUT splits */
-	u16			buf1;
+	u32			buf1;
 };
 
 /* temporary schedule data for packets from iso urbs (both speeds)
@@ -599,13 +600,13 @@ struct ehci_fstn {
  * needed (mostly in root hub code).
  */
 
-#define	ehci_is_ARC(e)			((e)->is_arc_rh_tt)
+#define	ehci_is_TDI(e)			((e)->is_tdi_rh_tt)
 
 /* Returns the speed of a device attached to a port on the root hub. */
 static inline unsigned int
 ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 {
-	if (ehci_is_ARC(ehci)) {
+	if (ehci_is_TDI(ehci)) {
 		switch ((portsc>>26)&3) {
 		case 0:
 			return 0;
@@ -621,7 +622,7 @@ ehci_port_speed(struct ehci_hcd *ehci, u
 
 #else
 
-#define	ehci_is_ARC(e)			(0)
+#define	ehci_is_TDI(e)			(0)
 
 #define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
 #endif
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -4329,7 +4329,7 @@ static int __init etrax_usb_hc_init(void
 	bus->bus_name="ETRAX 100LX";
 	bus->hcpriv = hc;
 
-	/* Initalize RH to the default address.
+	/* Initialize RH to the default address.
 	   And make sure that we have no status change indication */
 	hc->rh.numports = 2;  /* The RH has two ports */
 	hc->rh.devnum = 1;
@@ -4396,6 +4396,7 @@ static int __init etrax_usb_hc_init(void
         device_initialize(&fake_device);
         kobject_set_name(&fake_device.kobj, "etrax_usb");
         kobject_add(&fake_device.kobj);
+        kobject_hotplug(&fake_device.kobj, KOBJ_ADD);
         hc->bus->controller = &fake_device;
 	usb_register_bus(hc->bus);
 
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -70,19 +70,6 @@ static void au1xxx_stop_hc(struct platfo
 
 /*-------------------------------------------------------------------------*/
 
-
-static irqreturn_t usb_hcd_au1xxx_hcim_irq (int irq, void *__hcd,
-					     struct pt_regs * r)
-{
-	struct usb_hcd *hcd = __hcd;
-
-	return usb_hcd_irq(irq, hcd, r);
-}
-
-/*-------------------------------------------------------------------------*/
-
-void usb_hcd_au1xxx_remove (struct usb_hcd *, struct platform_device *);
-
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
@@ -97,90 +84,48 @@ void usb_hcd_au1xxx_remove (struct usb_h
  *
  */
 int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
-			  struct usb_hcd **hcd_out,
 			  struct platform_device *dev)
 {
 	int retval;
-	struct usb_hcd *hcd = 0;
-
-	unsigned int *addr = NULL;
-
-	if (!request_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-				- dev->resource[0].start + 1, hcd_name)) {
-		pr_debug("request_mem_region failed");
-		return -EBUSY;
-	}
-
-	au1xxx_start_hc(dev);
-
-	addr = ioremap(dev->resource[0].start,
-		       dev->resource[0].end
-		       - dev->resource[0].start + 1);
-	if (!addr) {
-		pr_debug("ioremap failed");
-		retval = -ENOMEM;
-		goto err1;
-	}
+	struct usb_hcd *hcd;
 
 	if(dev->resource[1].flags != IORESOURCE_IRQ) {
 		pr_debug ("resource[1] is not IORESOURCE_IRQ");
-		retval = -ENOMEM;
-		goto err1;
+		return -ENOMEM;
 	}
 
-	hcd = usb_create_hcd(driver);
-	if (hcd == NULL) {
-		pr_debug ("usb_create_hcd failed");
-		retval = -ENOMEM;
+	hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
 		goto err1;
 	}
-	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	hcd->irq = dev->resource[1].start;
-	hcd->regs = addr;
-	hcd->self.controller = &dev->dev;
-
-	retval = hcd_buffer_create (hcd);
-	if (retval != 0) {
-		pr_debug ("pool alloc fail");
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
 		goto err2;
 	}
 
-	retval = request_irq (hcd->irq, usb_hcd_au1xxx_hcim_irq, SA_INTERRUPT,
-			      hcd->driver->description, hcd);
-	if (retval != 0) {
-		pr_debug("request_irq failed");
-		retval = -EBUSY;
-		goto err3;
-	}
-
-	pr_debug ("%s (Au1xxx) at 0x%p, irq %d",
-	     hcd->driver->description, hcd->regs, hcd->irq);
-
-	hcd->self.bus_name = "au1xxx";
-
-	usb_register_bus (&hcd->self);
+	au1xxx_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	if ((retval = driver->start (hcd)) < 0)
-	{
-		usb_hcd_au1xxx_remove(hcd, dev);
-		printk("bad driver->start\n");
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
 		return retval;
-	}
 
-	*hcd_out = hcd;
-	return 0;
-
- err3:
-	hcd_buffer_destroy (hcd);
+	au1xxx_stop_hc(dev);
+	iounmap(hcd->regs);
  err2:
-	usb_put_hcd(hcd);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
-	au1xxx_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-			   - dev->resource[0].start + 1);
+	usb_put_hcd(hcd);
 	return retval;
 }
 
@@ -200,28 +145,11 @@ int usb_hcd_au1xxx_probe (const struct h
  */
 void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
 {
-	pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	free_irq (hcd->irq, hcd);
-	hcd_buffer_destroy (hcd);
-
-	usb_deregister_bus (&hcd->self);
-
+	usb_remove_hcd(hcd);
 	au1xxx_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-			   dev->resource[0].end
-			   - dev->resource[0].start + 1);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -257,7 +185,7 @@ static const struct hc_driver ohci_au1xx
 	 * generic hardware linkage
 	 */
 	.irq =			ohci_irq,
-	.flags =		HCD_USB11,
+	.flags =		HCD_USB11 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
@@ -293,7 +221,6 @@ static const struct hc_driver ohci_au1xx
 static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = NULL;
 	int ret;
 
 	pr_debug ("In ohci_hcd_au1xxx_drv_probe");
@@ -301,11 +228,7 @@ static int ohci_hcd_au1xxx_drv_probe(str
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, &hcd, pdev);
-
-	if (ret == 0)
-		dev_set_drvdata(dev, hcd);
-
+	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
 	return ret;
 }
 
@@ -315,7 +238,6 @@ static int ohci_hcd_au1xxx_drv_remove(st
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 	usb_hcd_au1xxx_remove(hcd, pdev);
-	dev_set_drvdata(dev, NULL);
 	return 0;
 }
 	/*TBD*/
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -138,7 +138,7 @@ ohci_dump_status (struct ohci_hcd *contr
 	ohci_dbg_sw (controller, next, size,
 		"OHCI %d.%d, %s legacy support registers\n",
 		0x03 & (temp >> 4), (temp & 0x0f),
-		(temp & 0x10) ? "with" : "NO");
+		(temp & 0x0100) ? "with" : "NO");
 
 	temp = ohci_readl (controller, &regs->control);
 	ohci_dbg_sw (controller, next, size,
@@ -193,6 +193,10 @@ ohci_dump_status (struct ohci_hcd *contr
 
 	maybe_print_eds (controller, "donehead",
 			ohci_readl (controller, &regs->donehead), next, size);
+
+	/* broken fminterval means traffic won't flow! */ 
+	ohci_dbg (controller, "fminterval %08x\n", 
+			ohci_readl (controller, &regs->fminterval));
 }
 
 #define dbg_port_sw(hc,num,value,next,size) \
@@ -328,7 +332,7 @@ static void ohci_dump_td (const struct o
 			hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
 			hc32_to_cpup (ohci, &td->hwBE));
 		for (i = 0; i < MAXPSW; i++) {
-			u16	psw = hc16_to_cpup (ohci, &td->hwPSW [i]);
+			u16	psw = ohci_hwPSW (ohci, td, i);
 			int	cc = (psw >> 12) & 0x0f;
 			ohci_dbg (ohci, "    psw [%d] = %2x, CC=%x %s=%d\n", i,
 				psw, cc,
@@ -620,9 +624,11 @@ show_registers (struct class_device *cla
 
 	ohci_dbg_sw (ohci, &next, &size,
 		"bus %s, device %s\n"
+		"%s\n"
 		"%s version " DRIVER_VERSION "\n",
 		hcd->self.controller->bus->name,
 		hcd->self.controller->bus_id,
+		hcd->product_desc,
 		hcd_name);
 
 	if (bus->controller->power.power_state) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -148,10 +148,22 @@ static void ohci_stop (struct usb_hcd *h
 #include "ohci-q.c"
 
 
-/* Some boards don't support per-port power switching */
-static int power_switching = 0;
-module_param (power_switching, bool, 0);
-MODULE_PARM_DESC (power_switching, "true (not default) to switch port power");
+/*
+ * On architectures with edge-triggered interrupts we must never return
+ * IRQ_NONE.
+ */
+#if defined(CONFIG_SA1111)  /* ... or other edge-triggered systems */
+#define IRQ_NOTMINE	IRQ_HANDLED
+#else
+#define IRQ_NOTMINE	IRQ_NONE
+#endif
+
+
+/* Some boards misreport power switching/overcurrent */
+static int distrust_firmware = 1;
+module_param (distrust_firmware, bool, 0);
+MODULE_PARM_DESC (distrust_firmware,
+	"true to distrust firmware power/overcurrent setup");
 
 /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */
 static int no_handshake = 0;
@@ -240,7 +252,7 @@ static int ohci_urb_enqueue (
 	spin_lock_irqsave (&ohci->lock, flags);
 
 	/* don't submit to a dead HC */
-	if (!HCD_IS_RUNNING(hcd->state)) {
+	if (!HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		goto fail;
 	}
@@ -308,7 +320,7 @@ static int ohci_urb_dequeue (struct usb_
 #endif		  
 
 	spin_lock_irqsave (&ohci->lock, flags);
- 	if (HCD_IS_RUNNING(hcd->state)) {
+ 	if (HC_IS_RUNNING(hcd->state)) {
 		urb_priv_t  *urb_priv;
 
 		/* Unless an IRQ completed the unlink while it was being
@@ -355,7 +367,7 @@ ohci_endpoint_disable (struct usb_hcd *h
 rescan:
 	spin_lock_irqsave (&ohci->lock, flags);
 
-	if (!HCD_IS_RUNNING (hcd->state)) {
+	if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
 		ed->state = ED_IDLE;
 		finish_unlinks (ohci, 0, NULL);
@@ -532,8 +544,9 @@ static int ohci_run (struct ohci_hcd *oh
 	// flush the writes
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	msleep(temp);
-	if (power_switching) {
-		unsigned ports = roothub_a (ohci) & RH_A_NDP; 
+	temp = roothub_a (ohci);
+	if (!(temp & RH_A_NPS)) {
+		unsigned ports = temp & RH_A_NDP; 
 
 		/* power down each port */
 		for (temp = 0; temp < ports; temp++)
@@ -574,7 +587,6 @@ retry:
 		// flush those writes
 		(void) ohci_readl (ohci, &ohci->regs->control);
 	}
-	ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
 
 	/* Tell the controller where the control and bulk lists are
 	 * The lists are empty now. */
@@ -607,7 +619,7 @@ retry:
 	ohci->hc_control &= OHCI_CTRL_RWC;
  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-	ohci_to_hcd(ohci)->state = USB_STATE_RUNNING;
+	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
 
 	/* wake on ConnectStatusChange, matching external hubs */
 	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -624,21 +636,16 @@ retry:
 		/* NSC 87560 and maybe others */
 		temp |= RH_A_NOCP;
 		temp &= ~(RH_A_POTPGT | RH_A_NPS);
-	} else if (power_switching) {
-		/* act like most external hubs:  use per-port power
-		 * switching and overcurrent reporting.
-		 */
-		temp &= ~(RH_A_NPS | RH_A_NOCP);
-		temp |= RH_A_PSM | RH_A_OCPM;
-	} else {
+		ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+	} else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
 		/* hub power always on; required for AMD-756 and some
 		 * Mac platforms.  ganged overcurrent reporting, if any.
 		 */
 		temp |= RH_A_NPS;
+		ohci_writel (ohci, temp, &ohci->regs->roothub.a);
 	}
-	ohci_writel (ohci, temp, &ohci->regs->roothub.a);
 	ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
-	ohci_writel (ohci, power_switching ? RH_B_PPCM : 0,
+	ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
 						&ohci->regs->roothub.b);
 	// flush those writes
 	(void) ohci_readl (ohci, &ohci->regs->control);
@@ -646,9 +653,9 @@ retry:
 	spin_unlock_irq (&ohci->lock);
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
-	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+	mdelay ((temp >> 23) & 0x1fe);
 	bus = &ohci_to_hcd(ohci)->self;
-	ohci_to_hcd(ohci)->state = USB_STATE_RUNNING;
+	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
 
 	ohci_dump (ohci, 1);
 
@@ -667,7 +674,7 @@ retry:
 	}
 
 	udev->speed = USB_SPEED_FULL;
-	if (hcd_register_root (udev, ohci_to_hcd(ohci)) != 0) {
+	if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
 		usb_put_dev (udev);
 		disable (ohci);
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
@@ -706,7 +713,7 @@ static irqreturn_t ohci_irq (struct usb_
 
 	/* interrupt for some other device? */
 	} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
-		return IRQ_NONE;
+		return IRQ_NOTMINE;
 	} 
 
 	if (ints & OHCI_INTR_UE) {
@@ -720,16 +727,17 @@ static irqreturn_t ohci_irq (struct usb_
 
 	if (ints & OHCI_INTR_RD) {
 		ohci_vdbg (ohci, "resume detect\n");
-		schedule_work(&ohci->rh_resume);
+		if (hcd->state != HC_STATE_QUIESCING)
+			schedule_work(&ohci->rh_resume);
 	}
 
 	if (ints & OHCI_INTR_WDH) {
-		if (HCD_IS_RUNNING(hcd->state))
+		if (HC_IS_RUNNING(hcd->state))
 			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);	
 		spin_lock (&ohci->lock);
 		dl_done_list (ohci, ptregs);
 		spin_unlock (&ohci->lock);
-		if (HCD_IS_RUNNING(hcd->state))
+		if (HC_IS_RUNNING(hcd->state))
 			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable); 
 	}
   
@@ -742,11 +750,11 @@ static irqreturn_t ohci_irq (struct usb_
 	if (ohci->ed_rm_list)
 		finish_unlinks (ohci, ohci_frame_no(ohci), ptregs);
 	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
-			&& HCD_IS_RUNNING(hcd->state))
+			&& HC_IS_RUNNING(hcd->state))
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);	
 	spin_unlock (&ohci->lock);
 
-	if (HCD_IS_RUNNING(hcd->state)) {
+	if (HC_IS_RUNNING(hcd->state)) {
 		ohci_writel (ohci, ints, &regs->intrstatus);
 		ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);	
 		// flush those writes
@@ -901,12 +909,17 @@ MODULE_LICENSE ("GPL");
 #include "ohci-au1xxx.c"
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+#include "ohci-ppc-soc.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_OMAP) \
       || defined (CONFIG_ARCH_LH7A404) \
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_SOC_AU1X00) \
+      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
 	)
 #error "missing bus glue for ohci-hcd"
 #endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -73,7 +73,7 @@ static int ohci_hub_suspend (struct usb_
 	ohci_dbg (ohci, "suspend root hub\n");
 
 	/* First stop any processing */
-	hcd->state = USB_STATE_QUIESCING;
+	hcd->state = HC_STATE_QUIESCING;
 	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
 		int		limit;
 
@@ -119,7 +119,7 @@ static int ohci_hub_suspend (struct usb_
 
 done:
 	if (status == 0)
-		hcd->state = HCD_STATE_SUSPENDED;
+		hcd->state = HC_STATE_SUSPENDED;
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return status;
 }
@@ -147,7 +147,7 @@ static int ohci_hub_resume (struct usb_h
 
 	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
 		/* this can happen after suspend-to-disk */
-		if (hcd->state == USB_STATE_RESUMING) {
+		if (hcd->state == HC_STATE_RESUMING) {
 			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
 					ohci->hc_control);
 			status = -EBUSY;
@@ -169,7 +169,7 @@ static int ohci_hub_resume (struct usb_h
 		ohci_info (ohci, "wakeup\n");
 		break;
 	case OHCI_USB_OPER:
-		ohci_dbg (ohci, "odd resume\n");
+		ohci_dbg (ohci, "already resumed\n");
 		status = 0;
 		break;
 	default:		/* RESET, we lost power */
@@ -197,8 +197,8 @@ static int ohci_hub_resume (struct usb_h
 				&ohci->regs->roothub.portstatus [temp]);
 	}
 
-	/* Some controllers (lucent) need extra-long delays */
-	hcd->state = USB_STATE_RESUMING;
+	/* Some controllers (lucent erratum) need extra-long delays */
+	hcd->state = HC_STATE_RESUMING;
 	mdelay (20 /* usb 11.5.1.10 */ + 15);
 
 	temp = ohci_readl (ohci, &ohci->regs->control);
@@ -216,6 +216,7 @@ static int ohci_hub_resume (struct usb_h
 	ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent);
 	ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca);
 
+	/* Sometimes PCI D3 suspend trashes frame timings ... */
 	periodic_reinit (ohci);
 
 	/* interrupts might have been disabled */
@@ -272,7 +273,7 @@ static int ohci_hub_resume (struct usb_h
 		(void) ohci_readl (ohci, &ohci->regs->control);
 	}
 
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 	return 0;
 }
 
@@ -313,7 +314,7 @@ ohci_hub_status_data (struct usb_hcd *hc
 	 * letting khubd or root hub timer see state changes.
 	 */
 	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
-			|| !HCD_IS_RUNNING(hcd->state)) {
+			|| !HC_IS_RUNNING(hcd->state)) {
 		can_suspend = 0;
 		goto done;
 	}
@@ -378,7 +379,7 @@ done:
 			) {
 		ohci_vdbg (ohci, "autosuspend\n");
 		(void) ohci_hub_suspend (hcd);
-		hcd->state = USB_STATE_RUNNING;
+		hcd->state = HC_STATE_RUNNING;
 		usb_unlock_device (hcd->self.root_hub);
 	}
 #endif
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -53,19 +53,6 @@ static void lh7a404_stop_hc(struct platf
 
 /*-------------------------------------------------------------------------*/
 
-
-static irqreturn_t usb_hcd_lh7a404_hcim_irq (int irq, void *__hcd,
-					     struct pt_regs * r)
-{
-	struct usb_hcd *hcd = __hcd;
-
-	return usb_hcd_irq(irq, hcd, r);
-}
-
-/*-------------------------------------------------------------------------*/
-
-void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *);
-
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
@@ -80,90 +67,48 @@ void usb_hcd_lh7a404_remove (struct usb_
  *
  */
 int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
-			  struct usb_hcd **hcd_out,
 			  struct platform_device *dev)
 {
 	int retval;
-	struct usb_hcd *hcd = 0;
-
-	unsigned int *addr = NULL;
+	struct usb_hcd *hcd;
 
-	if (!request_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-				- dev->resource[0].start + 1, hcd_name)) {
-		pr_debug("request_mem_region failed");
-		return -EBUSY;
-	}
-	
-	
-	lh7a404_start_hc(dev);
-	
-	addr = ioremap(dev->resource[0].start,
-		       dev->resource[0].end
-		       - dev->resource[0].start + 1);
-	if (!addr) {
-		pr_debug("ioremap failed");
-		retval = -ENOMEM;
-		goto err1;
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
 	}
 
-	if(dev->resource[1].flags != IORESOURCE_IRQ){
-		pr_debug ("resource[1] is not IORESOURCE_IRQ");
-		retval = -ENOMEM;
+	hcd = usb_create_hcd(driver, &dev->dev, "lh7a404");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
 		goto err1;
 	}
 	
-
-	hcd = usb_create_hcd (driver);
-	if (hcd == NULL){
-		pr_debug ("hcd_alloc failed");
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
 		retval = -ENOMEM;
-		goto err1;
-	}
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	hcd->irq = dev->resource[1].start;
-	hcd->regs = addr;
-	hcd->self.controller = &dev->dev;
-
-	retval = hcd_buffer_create (hcd);
-	if (retval != 0) {
-		pr_debug ("pool alloc fail");
 		goto err2;
 	}
 
-	retval = request_irq (hcd->irq, usb_hcd_lh7a404_hcim_irq, SA_INTERRUPT,
-			      hcd->driver->description, hcd);
-	if (retval != 0) {
-		pr_debug("request_irq failed");
-		retval = -EBUSY;
-		goto err3;
-	}
-
-	pr_debug ("%s (LH7A404) at 0x%p, irq %d",
-		hcd->driver->description, hcd->regs, hcd->irq);
-
-	hcd->self.bus_name = "lh7a404";
-	usb_register_bus (&hcd->self);
+	lh7a404_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	if ((retval = driver->start (hcd)) < 0)
-	{
-		usb_hcd_lh7a404_remove(hcd, dev);
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
 		return retval;
-	}
-
-	*hcd_out = hcd;
-	return 0;
 
- err3:
-	hcd_buffer_destroy (hcd);
+	lh7a404_stop_hc(dev);
+	iounmap(hcd->regs);
  err2:
-	usb_put_hcd(hcd);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
-	lh7a404_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-			   - dev->resource[0].start + 1);
+	usb_put_hcd(hcd);
 	return retval;
 }
 
@@ -183,28 +128,11 @@ int usb_hcd_lh7a404_probe (const struct 
  */
 void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
 {
-	pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	free_irq (hcd->irq, hcd);
-	hcd_buffer_destroy (hcd);
-
-	usb_deregister_bus (&hcd->self);
-
+	usb_remove_hcd(hcd);
 	lh7a404_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-			   dev->resource[0].end
-			   - dev->resource[0].start + 1);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -238,7 +166,7 @@ static const struct hc_driver ohci_lh7a4
 	 * generic hardware linkage
 	 */
 	.irq =			ohci_irq,
-	.flags =		HCD_USB11,
+	.flags =		HCD_USB11 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
@@ -274,7 +202,6 @@ static const struct hc_driver ohci_lh7a4
 static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = NULL;
 	int ret;
 
 	pr_debug ("In ohci_hcd_lh7a404_drv_probe");
@@ -282,11 +209,7 @@ static int ohci_hcd_lh7a404_drv_probe(st
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, &hcd, pdev);
-
-	if (ret == 0)
-		dev_set_drvdata(dev, hcd);
-
+	ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, pdev);
 	return ret;
 }
 
@@ -296,7 +219,6 @@ static int ohci_hcd_lh7a404_drv_remove(s
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 	usb_hcd_lh7a404_remove(hcd, pdev);
-	dev_set_drvdata(dev, NULL);
 	return 0;
 }
 	/*TBD*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -2,16 +2,14 @@
  * OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2005 David Brownell
  * (C) Copyright 2002 Hewlett-Packard Company
  * 
  * OMAP Bus Glue
  *
- * Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Russell King et al.
- *
- * Modified for OMAP from ohci-sa1111.c by Tony Lindgren <tony@atomide.com>
+ * Modified for OMAP by Tony Lindgren <tony@atomide.com>
  * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc.
+ * and on ohci-sa1111.c by Christopher Hoover <ch@hpl.hp.com>
  *
  * This file is licenced under the GPL.
  */
@@ -26,59 +24,60 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/usb.h>
+#include <asm/hardware/clock.h>
+
+
+/* OMAP-1510 OHCI has its own MMU for DMA */
+#define OMAP1510_LB_MEMSIZE	32	/* Should be same as SDRAM size */
+#define OMAP1510_LB_CLOCK_DIV	0xfffec10c
+#define OMAP1510_LB_MMU_CTL	0xfffec208
+#define OMAP1510_LB_MMU_LCK	0xfffec224
+#define OMAP1510_LB_MMU_LD_TLB	0xfffec228
+#define OMAP1510_LB_MMU_CAM_H	0xfffec22c
+#define OMAP1510_LB_MMU_CAM_L	0xfffec230
+#define OMAP1510_LB_MMU_RAM_H	0xfffec234
+#define OMAP1510_LB_MMU_RAM_L	0xfffec238
 
-#include "ohci-omap.h"
 
 #ifndef CONFIG_ARCH_OMAP
 #error "This file is OMAP bus glue.  CONFIG_OMAP must be defined."
 #endif
 
-extern int usb_disabled(void);
-extern int ocpi_enable(void);
+#ifdef CONFIG_TPS65010
+#include <asm/arch/tps65010.h>
+#else
 
-/*
- * OHCI clock initialization for OMAP-1510 and 1610
- */
-static int omap_ohci_clock_power(int on)
-{
-	if (on) {
-		/* for 1510, 48MHz DPLL is set up in usb init */
+#define LOW	0
+#define HIGH	1
 
-		if (cpu_is_omap16xx()) {
-			/* Enable OHCI */
-			omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_OTG_REQ,
-				ULPD_SOFT_REQ);
-
-			/* USB host clock request if not using OTG */
-			omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_REQ,
-				ULPD_SOFT_REQ);
+#define GPIO1	1
 
-			omap_writel(omap_readl(ULPD_STATUS_REQ) | USB_HOST_DPLL_REQ,
-			     ULPD_STATUS_REQ);
-		}
+static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
+{
+	return 0;
+}
 
-		/* Enable 48MHz clock to USB */
-		omap_writel(omap_readl(ULPD_CLOCK_CTRL) | USB_MCLK_EN,
-		       ULPD_CLOCK_CTRL);
+#endif
 
-		omap_writel(omap_readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK),
-		       ARM_IDLECT2);
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
 
-		omap_writel(omap_readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN,
-		       MOD_CONF_CTRL_0);
-	} else {
-		/* Disable 48MHz clock to USB */
-		omap_writel(omap_readl(ULPD_CLOCK_CTRL) & ~USB_MCLK_EN,
-		       ULPD_CLOCK_CTRL);
+static struct clk *usb_host_ck;
 
-		/* FIXME: The DPLL stays on for now */
+static void omap_ohci_clock_power(int on)
+{
+	if (on) {
+		clk_enable(usb_host_ck);
+		/* guesstimate for T5 == 1x 32K clock + APLL lock time */
+		udelay(100);
+	} else {
+		clk_disable(usb_host_ck);
 	}
-
-	return 0;
 }
 
 /*
- * Hardware specific transceiver power on/off
+ * Board specific gang-switched transceiver power on/off.
+ * NOTE:  OSK supplies power from DC, not battery.
  */
 static int omap_ohci_transceiver_power(int on)
 {
@@ -87,17 +86,15 @@ static int omap_ohci_transceiver_power(i
 			fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
 				| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), 
 			       INNOVATOR_FPGA_CAM_USB_CONTROL);
-		else if (machine_is_omap_osk()) {
-			/* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */
-		}
+		else if (machine_is_omap_osk())
+			tps65010_set_gpio_out_value(GPIO1, LOW);
 	} else {
 		if (machine_is_omap_innovator() && cpu_is_omap1510())
 			fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
 				& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), 
 			       INNOVATOR_FPGA_CAM_USB_CONTROL);
-		else if (machine_is_omap_osk()) {
-			/* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */
-		}
+		else if (machine_is_omap_osk())
+			tps65010_set_gpio_out_value(GPIO1, HIGH);
 	}
 
 	return 0;
@@ -177,6 +174,7 @@ static int omap_start_hc(struct ohci_hcd
 {
 	struct omap_usb_config	*config = pdev->dev.platform_data;
 	int			need_transceiver = (config->otg != 0);
+	int			ret;
 
 	dev_dbg(&pdev->dev, "starting USB Controller\n");
 
@@ -188,7 +186,7 @@ static int omap_start_hc(struct ohci_hcd
 
 	/* boards can use OTG transceivers in non-OTG modes */
 	need_transceiver = need_transceiver
-			|| machine_is_omap_h2();
+			|| machine_is_omap_h2() || machine_is_omap_h3();
 
 	if (cpu_is_omap16xx())
 		ocpi_enable();
@@ -213,21 +211,44 @@ static int omap_start_hc(struct ohci_hcd
 	}
 #endif
 
-	if (machine_is_omap_osk()) {
-		omap_request_gpio(9);
-		omap_set_gpio_direction(9, 1);
-		omap_set_gpio_dataout(9, 1);
-	}
-
 	omap_ohci_clock_power(1);
 
-	omap_ohci_transceiver_power(1);
-
 	if (cpu_is_omap1510()) {
 		omap_1510_local_bus_power(1);
 		omap_1510_local_bus_init();
 	}
 
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	/* board-specific power switching and overcurrent support */
+	if (machine_is_omap_osk() || machine_is_omap_innovator()) {
+		u32	rh = roothub_a (ohci);
+
+		/* power switching (ganged by default) */
+		rh &= ~RH_A_NPS;
+
+		/* TPS2045 switch for internal transceiver (port 1) */
+		if (machine_is_omap_osk()) {
+			ohci->power_budget = 250;
+
+			rh &= ~RH_A_NOCP;
+
+			/* gpio9 for overcurrent detction */
+			omap_cfg_reg(W8_1610_GPIO9);
+			omap_request_gpio(9);
+			omap_set_gpio_direction(9, 1 /* IN */);
+
+			/* for paranoia's sake:  disable USB.PUEN */
+			omap_cfg_reg(W4_USB_HIGHZ);
+		}
+		ohci_writel(ohci, rh, &ohci->regs->roothub.a);
+		distrust_firmware = 0;
+	}
+
+	/* FIXME khubd hub requests should manage power switching */
+	omap_ohci_transceiver_power(1);
+
 	/* board init will have already handled HMC and mux setup.
 	 * any external transceiver should already be initialized
 	 * too, so all configured ports use the right signaling now.
@@ -239,16 +260,7 @@ static int omap_start_hc(struct ohci_hcd
 static void omap_stop_hc(struct platform_device *pdev)
 {
 	dev_dbg(&pdev->dev, "stopping USB Controller\n");
-
-	/*
-	 * FIXME: Put the USB host controller into reset.
-	 */
-
-	/*
-	 * FIXME: Stop the USB clock.
-	 */
-	//omap_disable_device(dev);
-
+	omap_ohci_clock_power(0);
 }
 
 
@@ -282,78 +294,53 @@ int usb_hcd_omap_probe (const struct hc_
 	}
 
 	if (pdev->resource[0].flags != IORESOURCE_MEM 
-	    || pdev->resource[1].flags != IORESOURCE_IRQ) {
+			|| pdev->resource[1].flags != IORESOURCE_IRQ) {
 		printk(KERN_ERR "hcd probe: invalid resource type\n");
 		return -ENODEV;
 	}
 
-	if (!request_mem_region(pdev->resource[0].start, 
-				pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) {
-		dev_dbg(&pdev->dev, "request_mem_region failed\n");
-		return -EBUSY;
-	}
+	usb_host_ck = clk_get(0, "usb_hhc_ck");
+	if (IS_ERR(usb_host_ck))
+		return PTR_ERR(usb_host_ck);
 
-	hcd = usb_create_hcd (driver);
-	if (hcd == NULL){
-		dev_dbg(&pdev->dev, "hcd_alloc failed\n");
+	hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
 		retval = -ENOMEM;
+		goto err0;
+	}
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		retval = -EBUSY;
 		goto err1;
 	}
-	dev_set_drvdata(&pdev->dev, hcd);
+
+	hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start);
+
 	ohci = hcd_to_ohci(hcd);
 	ohci_hcd_init(ohci);
 
-	hcd->irq = pdev->resource[1].start;
-	hcd->regs = (void *)pdev->resource[0].start;
-	hcd->self.controller = &pdev->dev;
-
 	retval = omap_start_hc(ohci, pdev);
 	if (retval < 0)
 		goto err2;
 
-	retval = hcd_buffer_create (hcd);
-	if (retval != 0) {
-		dev_dbg(&pdev->dev, "pool alloc fail\n");
-		goto err2;
-	}
-
-	retval = request_irq (hcd->irq, usb_hcd_irq, 
-			      SA_INTERRUPT, hcd->driver->description, hcd);
-	if (retval != 0) {
-		dev_dbg(&pdev->dev, "request_irq failed\n");
-		retval = -EBUSY;
-		goto err3;
-	}
-
-	dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
-
-	hcd->self.bus_name = pdev->dev.bus_id;
-	usb_register_bus (&hcd->self);
-
-	if ((retval = driver->start (hcd)) < 0) 
-	{
-		usb_hcd_omap_remove(hcd, pdev);
+	retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+	if (retval == 0)
 		return retval;
-	}
-
-	return 0;
 
- err3:
-	hcd_buffer_destroy (hcd);
- err2:
-	dev_set_drvdata(&pdev->dev, NULL);
-	usb_put_hcd(hcd);
- err1:
 	omap_stop_hc(pdev);
-
-	release_mem_region(pdev->resource[0].start, 
-			   pdev->resource[0].end - pdev->resource[0].start + 1);
-
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+err0:
+	clk_put(usb_host_ck);
 	return retval;
 }
 
 
-/* may be called without controller electrically present */
 /* may be called with controller, bus, and devices active */
 
 /**
@@ -368,31 +355,13 @@ int usb_hcd_omap_probe (const struct hc_
  */
 void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 {
-	dev_info(&pdev->dev, "remove: state %x\n", hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	dev_dbg(&pdev->dev, "roothub graceful disconnect\n");
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd_buffer_destroy (hcd);
-	hcd->state = USB_STATE_HALT;
-
+	usb_remove_hcd(hcd);
 	if (machine_is_omap_osk())
 		omap_free_gpio(9);
-
-	free_irq (hcd->irq, hcd);
-
-	usb_deregister_bus (&hcd->self);
-
 	omap_stop_hc(pdev);
-
-	release_mem_region(pdev->resource[0].start, 
-			   pdev->resource[0].end - pdev->resource[0].start + 1);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	clk_put(usb_host_ck);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -404,15 +373,12 @@ ohci_omap_start (struct usb_hcd *hcd)
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	if ((ret = ohci_init(ohci)) < 0)
-		return ret;
-
 	config = hcd->self.controller->platform_data;
 	if (config->otg || config->rwc)
 		writel(OHCI_CTRL_RWC, &ohci->regs->control);
 
 	if ((ret = ohci_run (ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
+		dev_err(hcd->self.controller, "can't start\n");
 		ohci_stop (hcd);
 		return ret;
 	}
@@ -430,7 +396,7 @@ static const struct hc_driver ohci_omap_
 	 * generic hardware linkage
 	 */
 	.irq =			ohci_irq,
-	.flags =		HCD_USB11,
+	.flags =		HCD_USB11 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
@@ -488,17 +454,21 @@ static int ohci_hcd_omap_drv_remove(stru
 
 /*-------------------------------------------------------------------------*/
 
-#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+#ifdef	CONFIG_PM
 
 /* states match PCI usage, always suspending the root hub except that
  * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset).
+ *
+ * FIXME: above comment is not right, and code is wrong, too :-(.
  */
 
-static int ohci_omap_suspend(struct device *dev, u32 state, u32 level)
+static int ohci_omap_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
 	int		status = -EINVAL;
 
+	if (level != SUSPEND_POWER_DOWN)
+		return 0;
 	if (state <= dev->power.power_state)
 		return 0;
 
@@ -507,13 +477,12 @@ static int ohci_omap_suspend(struct devi
 	status = ohci_hub_suspend(ohci_to_hcd(ohci));
 	if (status == 0) {
 		if (state >= 4) {
-			/* power off + reset */
-			OTG_SYSCON_2_REG &= ~UHOST_EN;
+			omap_ohci_clock_power(0);
 			ohci_to_hcd(ohci)->self.root_hub->state =
 					USB_STATE_SUSPENDED;
 			state = 4;
 		}
-		ohci_to_hcd(ohci)->state = HCD_STATE_SUSPENDED;
+		ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
 		dev->power.power_state = state;
 	}
 	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
@@ -525,6 +494,9 @@ static int ohci_omap_resume(struct devic
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
 	int		status = 0;
 
+	if (level != RESUME_POWER_ON)
+		return 0;
+
 	switch (dev->power.power_state) {
 	case 0:
 		break;
@@ -532,7 +504,7 @@ static int ohci_omap_resume(struct devic
 		if (time_before(jiffies, ohci->next_statechange))
 			msleep(5);
 		ohci->next_statechange = jiffies;
-		OTG_SYSCON_2_REG |= UHOST_EN;
+		omap_ohci_clock_power(1);
 		/* FALLTHROUGH */
 	default:
 		dev_dbg(dev, "resume from %d\n", dev->power.power_state);
@@ -563,7 +535,7 @@ static struct device_driver ohci_hcd_oma
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_omap_drv_probe,
 	.remove		= ohci_hcd_omap_drv_remove,
-#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+#ifdef	CONFIG_PM
 	.suspend	= ohci_omap_suspend,
 	.resume		= ohci_omap_resume,
 #endif
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -54,7 +54,7 @@ ohci_pci_start (struct usb_hcd *hcd)
 		if (pdev->vendor == PCI_VENDOR_ID_AMD
 				&& pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
-			ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
 			// also somewhat erratum 10 (suspend/resume issues)
 		}
 
@@ -68,7 +68,7 @@ ohci_pci_start (struct usb_hcd *hcd)
 		 */
 		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
 				&& pdev->device == 0xc861) {
-			ohci_info (ohci,
+			ohci_dbg (ohci,
 				"WARNING: OPTi workarounds unavailable\n");
 		}
 
@@ -84,9 +84,20 @@ ohci_pci_start (struct usb_hcd *hcd)
 			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
 					&& b->vendor == PCI_VENDOR_ID_NS) {
 				ohci->flags |= OHCI_QUIRK_SUPERIO;
-				ohci_info (ohci, "Using NSC SuperIO setup\n");
+				ohci_dbg (ohci, "Using NSC SuperIO setup\n");
 			}
 		}
+
+		/* Check for Compaq's ZFMicro chipset, which needs short 
+		 * delays before control or bulk queues get re-activated
+		 * in finish_unlinks()
+		 */
+		else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
+				&& pdev->device  == 0xa0f8) {
+			ohci->flags |= OHCI_QUIRK_ZFMICRO;
+			ohci_dbg (ohci,
+				"enabled Compaq ZFMicro chipset quirk\n");
+		}
 	}
 
 	/* NOTE: there may have already been a first reset, to
@@ -102,7 +113,7 @@ ohci_pci_start (struct usb_hcd *hcd)
 
 #ifdef	CONFIG_PM
 
-static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
@@ -111,7 +122,7 @@ static int ohci_pci_suspend (struct usb_
 		msleep (100);
 
 #ifdef	CONFIG_USB_SUSPEND
-	(void) usb_suspend_device (hcd->self.root_hub, state);
+	(void) usb_suspend_device (hcd->self.root_hub, message);
 #else
 	usb_lock_device (hcd->self.root_hub);
 	(void) ohci_hub_suspend (hcd);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -0,0 +1,234 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2003-2005 MontaVista Software Inc.
+ * 
+ * Bus Glue for PPC On-Chip OHCI driver
+ * Tested on Freescale MPC5200 and IBM STB04xxx
+ *
+ * Modified by Dale Farnsworth <dale@farnsworth.org> from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/usb.h>
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
+			  struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ohci_hcd	*ohci;
+	struct resource *res;
+	int irq;
+	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+	pr_debug("initializing PPC-SOC USB Controller\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		pr_debug(__FILE__ ": no irq\n");
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_debug(__FILE__ ": no reg addr\n");
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = res->end - res->start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug(__FILE__ ": request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug(__FILE__ ": ioremap failed\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	if (pd->start && (retval = pd->start(pdev)))
+		goto err3;
+
+	ohci = hcd_to_ohci(hcd);
+	ohci->flags |= OHCI_BIG_ENDIAN;
+	ohci_hcd_init(ohci);
+
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	pr_debug("Removing PPC-SOC USB Controller\n");
+	if (pd && pd->stop)
+		pd->stop(pdev);
+ err3:
+	iounmap(hcd->regs);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ 	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs
+ * @pdev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
+		struct platform_device *pdev)
+{
+	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+	usb_remove_hcd(hcd);
+
+	pr_debug("stopping PPC-SOC USB Controller\n");
+	if (pd && pd->stop)
+		pd->stop(pdev);
+
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_hcd_put(hcd);
+}
+
+static int __devinit
+ohci_ppc_soc_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_ppc_soc_hc_driver = {
+	.description =		hcd_name,
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_ppc_soc_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+static int ohci_hcd_ppc_soc_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev);
+	return ret;
+}
+
+static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_ppc_soc_remove(hcd, pdev);
+	return 0;
+}
+
+static struct device_driver ohci_hcd_ppc_soc_driver = {
+	.name		= "ppc-soc-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_ppc_soc_drv_probe,
+	.remove		= ohci_hcd_ppc_soc_drv_remove,
+#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
+	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+};
+
+static int __init ohci_hcd_ppc_soc_init(void)
+{
+	pr_debug(DRIVER_INFO " (PPC SOC)\n");
+	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
+							sizeof(struct td));
+
+	return driver_register(&ohci_hcd_ppc_soc_driver);
+}
+
+static void __exit ohci_hcd_ppc_soc_cleanup(void)
+{
+	driver_unregister(&ohci_hcd_ppc_soc_driver);
+}
+
+module_init(ohci_hcd_ppc_soc_init);
+module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -152,8 +152,6 @@ static void pxa27x_stop_hc(struct platfo
 
 /*-------------------------------------------------------------------------*/
 
-void usb_hcd_pxa27x_remove (struct usb_hcd *, struct platform_device *);
-
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
@@ -168,19 +166,33 @@ void usb_hcd_pxa27x_remove (struct usb_h
  *
  */
 int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
-			  struct usb_hcd **hcd_out,
 			  struct platform_device *dev)
 {
 	int retval;
-	struct usb_hcd *hcd = 0;
+	struct usb_hcd *hcd;
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
+	}
 
-	unsigned int *addr = NULL;
+	hcd = usb_create_hcd (driver, &dev->dev, "pxa27x");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
 
-	if (!request_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-				- dev->resource[0].start + 1, hcd_name)) {
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 		pr_debug("request_mem_region failed");
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
 	}
 
 	pxa27x_start_hc(dev);
@@ -198,69 +210,18 @@ int usb_hcd_pxa27x_probe (const struct h
 	if (pxa27x_ohci_clear_port_power(3) < 0)
 		printk(KERN_ERR "Setting port 3 power failed.\n");
 
-	addr = ioremap(dev->resource[0].start,
-		       dev->resource[0].end - dev->resource[0].start + 1);
-	if (!addr) {
-		pr_debug("ioremap failed");
-		retval = -ENOMEM;
-		goto err1;
-	}
-
-	if(dev->resource[1].flags != IORESOURCE_IRQ){
-		pr_debug ("resource[1] is not IORESOURCE_IRQ");
-		retval = -ENOMEM;
-		goto err1;
-	}
-
-	hcd = usb_create_hcd (driver);
-	if (hcd == NULL){
-		pr_debug ("hcd_alloc failed");
-		retval = -ENOMEM;
-		goto err1;
-	}
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	hcd->irq = dev->resource[1].start;
-	hcd->regs = addr;
-	hcd->self.controller = &dev->dev;
-
-	retval = hcd_buffer_create (hcd);
-	if (retval != 0) {
-		pr_debug ("pool alloc fail");
-		goto err2;
-	}
-
-	retval = request_irq (hcd->irq, usb_hcd_irq, SA_INTERRUPT,
-			      hcd->driver->description, hcd);
-	if (retval != 0) {
-		pr_debug("request_irq(%d) failed with retval %d\n",hcd->irq,retval);
-		retval = -EBUSY;
-		goto err3;
-	}
-
-	pr_debug ("%s (pxa27x) at 0x%p, irq %d",
-		hcd->driver->description, hcd->regs, hcd->irq);
-
-	hcd->self.bus_name = "pxa27x";
-	usb_register_bus (&hcd->self);
-
-	if ((retval = driver->start (hcd)) < 0) {
-		usb_hcd_pxa27x_remove(hcd, dev);
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
 		return retval;
-	}
-
-	*hcd_out = hcd;
-	return 0;
 
- err3:
-	hcd_buffer_destroy (hcd);
+	pxa27x_stop_hc(dev);
+	iounmap(hcd->regs);
  err2:
-	usb_put_hcd(hcd);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
-	pxa27x_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-				dev->resource[0].end
-			   - dev->resource[0].start + 1);
+	usb_put_hcd(hcd);
 	return retval;
 }
 
@@ -280,27 +241,11 @@ int usb_hcd_pxa27x_probe (const struct h
  */
 void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev)
 {
-	pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	free_irq (hcd->irq, hcd);
-	hcd_buffer_destroy (hcd);
-
-	usb_deregister_bus (&hcd->self);
-
+	usb_remove_hcd(hcd);
 	pxa27x_stop_hc(dev);
-	release_mem_region(dev->resource[0].start,
-			   dev->resource[0].end - dev->resource[0].start + 1);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -336,7 +281,7 @@ static const struct hc_driver ohci_pxa27
 	 * generic hardware linkage
 	 */
 	.irq =			ohci_irq,
-	.flags =		HCD_USB11,
+	.flags =		HCD_USB11 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
@@ -372,7 +317,6 @@ static const struct hc_driver ohci_pxa27
 static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = NULL;
 	int ret;
 
 	pr_debug ("In ohci_hcd_pxa27x_drv_probe");
@@ -380,11 +324,7 @@ static int ohci_hcd_pxa27x_drv_probe(str
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, &hcd, pdev);
-
-	if (ret == 0)
-		dev_set_drvdata(dev, hcd);
-
+	ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
 	return ret;
 }
 
@@ -394,11 +334,10 @@ static int ohci_hcd_pxa27x_drv_remove(st
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 	usb_hcd_pxa27x_remove(hcd, pdev);
-	dev_set_drvdata(dev, NULL);
 	return 0;
 }
 
-static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, u32 state, u32 level)
+static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 //	struct platform_device *pdev = to_platform_device(dev);
 //	struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -407,7 +346,7 @@ static int ohci_hcd_pxa27x_drv_suspend(s
 	return 0;
 }
 
-static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 state)
+static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 level)
 {
 //	struct platform_device *pdev = to_platform_device(dev);
 //	struct usb_hcd *hcd = dev_get_drvdata(dev);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -172,7 +172,7 @@ static int ed_schedule (struct ohci_hcd 
 {	 
 	int	branch;
 
-	if (ohci_to_hcd(ohci)->state == USB_STATE_QUIESCING)
+	if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
 		return -EAGAIN;
 
 	ed->state = ED_OPER;
@@ -547,7 +547,8 @@ td_fill (struct ohci_hcd *ohci, u32 info
 	td->hwINFO = cpu_to_hc32 (ohci, info);
 	if (is_iso) {
 		td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
-		td->hwPSW [0] = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000);
+		*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
+						(data & 0x0FFF) | 0xE000);
 		td->ed->last_iso = info & 0xffff;
 	} else {
 		td->hwCBP = cpu_to_hc32 (ohci, data); 
@@ -662,7 +663,7 @@ static void td_submit_urb (
 			/* NOTE:  mishandles transfers >8K, some >4K */
 			td_fill (ohci, info, data, data_len, urb, cnt++);
 		}
-		info = is_out
+		info = (is_out || data_len == 0)
 			? TD_CC | TD_DP_IN | TD_T_DATA1
 			: TD_CC | TD_DP_OUT | TD_T_DATA1;
 		td_fill (ohci, info, data, 0, urb, cnt++);
@@ -719,10 +720,12 @@ static void td_done (struct ohci_hcd *oh
 
 	/* ISO ... drivers see per-TD length/status */
   	if (tdINFO & TD_ISO) {
- 		u16	tdPSW = hc16_to_cpu (ohci, td->hwPSW [0]);
+ 		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
 		int	dlen = 0;
 
-		/* NOTE:  assumes FC in tdINFO == 0 (and MAXPSW == 1) */
+		/* NOTE:  assumes FC in tdINFO == 0, and that
+		 * only the first of 0..MAXPSW psws is used.
+		 */
 
  		cc = (tdPSW >> 12) & 0xF;
   		if (tdINFO & TD_CC)	/* hc didn't touch? */
@@ -920,7 +923,7 @@ rescan_all:
 		/* only take off EDs that the HC isn't using, accounting for
 		 * frame counter wraps and EDs with partially retired TDs
 		 */
-		if (likely (regs && HCD_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+		if (likely (regs && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
 			if (tick_before (tick, ed->tick)) {
 skip_ed:
 				last = &ed->ed_next;
@@ -1002,7 +1005,7 @@ rescan_this:
 
 		/* but if there's work queued, reschedule */
 		if (!list_empty (&ed->td_list)) {
-			if (HCD_IS_RUNNING(ohci_to_hcd(ohci)->state))
+			if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))
 				ed_schedule (ohci, ed);
 		}
 
@@ -1011,13 +1014,15 @@ rescan_this:
    	}
 
 	/* maybe reenable control and bulk lists */ 
-	if (HCD_IS_RUNNING(ohci_to_hcd(ohci)->state)
-			&& ohci_to_hcd(ohci)->state != USB_STATE_QUIESCING
+	if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
+			&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
 			&& !ohci->ed_rm_list) {
 		u32	command = 0, control = 0;
 
 		if (ohci->ed_controltail) {
 			command |= OHCI_CLF;
+			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 				control |= OHCI_CTRL_CLE;
 				ohci_writel (ohci, 0,
@@ -1026,6 +1031,8 @@ rescan_this:
 		}
 		if (ohci->ed_bulktail) {
 			command |= OHCI_BLF;
+			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 				control |= OHCI_CTRL_BLE;
 				ohci_writel (ohci, 0,
@@ -1036,12 +1043,17 @@ rescan_this:
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		if (control) {
 			ohci->hc_control |= control;
+			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+				mdelay(1);
  			ohci_writel (ohci, ohci->hc_control,
 					&ohci->regs->control);   
  		}
-		if (command)
+		if (command) {
+			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+				mdelay(1);
 			ohci_writel (ohci, command, &ohci->regs->cmdstatus);   
- 	}
+	 	}
+	}
 }
 
 
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -105,34 +105,8 @@ static void dump_hci_status(struct usb_h
 }
 #endif
 
-static irqreturn_t usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
-{
-	struct usb_hcd *hcd = __hcd;
-//	unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
-
-	//dump_hci_status(hcd, "irq");
-
-#if 0
-	/* may work better this way -- need to investigate further */
-	if (status & USB_STATUS_NIRQHCIM) {
-		//dbg ("not normal HC interrupt; ignoring");
-		return;
-	}
-#endif
-
-	usb_hcd_irq(irq, hcd, r);
-
-	/*
-	 * SA1111 seems to re-assert its interrupt immediately
-	 * after processing an interrupt.  Always return IRQ_HANDLED.
-	 */
-	return IRQ_HANDLED;
-}
-
 /*-------------------------------------------------------------------------*/
 
-void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
-
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
@@ -148,68 +122,35 @@ void usb_hcd_sa1111_remove (struct usb_h
  * Store this function in the HCD's struct pci_driver as probe().
  */
 int usb_hcd_sa1111_probe (const struct hc_driver *driver,
-			  struct usb_hcd **hcd_out,
 			  struct sa1111_dev *dev)
 {
+	struct usb_hcd *hcd;
 	int retval;
-	struct usb_hcd *hcd = 0;
 
-	if (!request_mem_region(dev->res.start, 
-				dev->res.end - dev->res.start + 1, hcd_name)) {
-		dbg("request_mem_region failed");
-		return -EBUSY;
-	}
-
-	sa1111_start_hc(dev);
+	hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->res.start;
+	hcd->rsrc_len = dev->res.end - dev->res.start + 1;
 
-	hcd = usb_create_hcd (driver);
-	if (hcd == NULL){
-		dbg ("hcd_alloc failed");
-		retval = -ENOMEM;
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dbg("request_mem_region failed");
+		retval = -EBUSY;
 		goto err1;
 	}
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	hcd->irq = dev->irq[1];
 	hcd->regs = dev->mapbase;
-	hcd->self.controller = &dev->dev;
-
-	retval = hcd_buffer_create (hcd);
-	if (retval != 0) {
-		dbg ("pool alloc fail");
-		goto err2;
-	}
-
-	retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
-			      hcd->driver->description, hcd);
-	if (retval != 0) {
-		dbg("request_irq failed");
-		retval = -EBUSY;
-		goto err3;
-	}
 
-	info ("%s (SA-1111) at 0x%p, irq %d\n",
-		hcd->driver->description, hcd->regs, hcd->irq);
-
-	hcd->self.bus_name = "sa1111";
-	usb_register_bus (&hcd->self);
+	sa1111_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	if ((retval = driver->start (hcd)) < 0) 
-	{
-		usb_hcd_sa1111_remove(hcd, dev);
+	retval = usb_add_hcd(hcd, dev->irq[1], SA_INTERRUPT);
+	if (retval == 0)
 		return retval;
-	}
 
-	*hcd_out = hcd;
-	return 0;
-
- err3:
-	hcd_buffer_destroy (hcd);
- err2:
-	usb_put_hcd(hcd);
- err1:
 	sa1111_stop_hc(dev);
-	release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
 	return retval;
 }
 
@@ -229,26 +170,10 @@ int usb_hcd_sa1111_probe (const struct h
  */
 void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
 {
-	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-	if (in_interrupt ())
-		BUG ();
-
-	hcd->state = USB_STATE_QUIESCING;
-
-	dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
-	usb_disconnect (&hcd->self.root_hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	free_irq (hcd->irq, hcd);
-	hcd_buffer_destroy (hcd);
-
-	usb_deregister_bus (&hcd->self);
-
+	usb_remove_hcd(hcd);
 	sa1111_stop_hc(dev);
-	release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -281,7 +206,7 @@ static const struct hc_driver ohci_sa111
 	 * generic hardware linkage
 	 */
 	.irq =			ohci_irq,
-	.flags =		HCD_USB11,
+	.flags =		HCD_USB11 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
@@ -294,11 +219,6 @@ static const struct hc_driver ohci_sa111
 	.stop =			ohci_stop,
 
 	/*
-	 * memory lifecycle (except per-request)
-	 */
-	.hcd_alloc =		ohci_hcd_alloc,
-
-	/*
 	 * managing i/o requests and associated device resources
 	 */
 	.urb_enqueue =		ohci_urb_enqueue,
@@ -325,17 +245,12 @@ static const struct hc_driver ohci_sa111
 
 static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
 {
-	struct usb_hcd *hcd = NULL;
 	int ret;
 
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
-
-	if (ret == 0)
-		sa1111_set_drvdata(dev, hcd);
-
+	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
 	return ret;
 }
 
@@ -344,9 +259,6 @@ static int ohci_hcd_sa1111_drv_remove(st
 	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 
 	usb_hcd_sa1111_remove(hcd, dev);
-
-	sa1111_set_drvdata(dev, NULL);
-
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -111,8 +111,10 @@ struct td {
   	__hc32		hwNextTD;	/* Next TD Pointer */
   	__hc32		hwBE;		/* Memory Buffer End Pointer */
 
-	/* PSW is only for ISO */
-#define MAXPSW 1		/* hardware allows 8 */
+	/* PSW is only for ISO.  Only 1 PSW entry is used, but on
+	 * big-endian PPC hardware that's the second entry.
+	 */
+#define MAXPSW	2
   	__hc16		hwPSW [MAXPSW];
 
 	/* rest are purely for the driver's use */
@@ -183,7 +185,7 @@ struct ohci_hcca {
 	/* 
 	 * OHCI defines u16 frame_no, followed by u16 zero pad.
 	 * Since some processors can't do 16 bit bus accesses,
-	 * portable access must be a 32 bit byteswapped access.
+	 * portable access must be a 32 bits wide.
 	 */
 	__hc32	frame_no;		/* current frame number */
 	__hc32	done_head;		/* info returned for an interrupt */
@@ -191,8 +193,6 @@ struct ohci_hcca {
 	u8	what [4];		/* spec only identifies 252 bytes :) */
 } __attribute__ ((aligned(256)));
 
-#define ohci_frame_no(ohci) ((u16)hc32_to_cpup(ohci,&(ohci)->hcca->frame_no))
-  
 /*
  * This is the structure of the OHCI controller's memory mapped I/O region.
  * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
@@ -396,6 +396,7 @@ struct ohci_hcd {
 #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
 #define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
+#define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
 	// there are also chip quirks/bugs in init logic
 
 };
@@ -554,19 +555,61 @@ static inline u32 hc32_to_cpup (const st
 
 /*-------------------------------------------------------------------------*/
 
+/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads.  That creates a different confusion on
+ * some big-endian SOC implementations.  Same thing happens with PSW access.
+ */
+
+#ifdef CONFIG_STB03xxx
+#define OHCI_BE_FRAME_NO_SHIFT	16
+#else
+#define OHCI_BE_FRAME_NO_SHIFT	0
+#endif
+
+static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+{
+	u32 tmp;
+	if (big_endian(ohci)) {
+		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+	} else
+		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
+
+	return (u16)tmp;
+}
+
+static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+                                 const struct td *td, int index)
+{
+	return (__hc16 *)(big_endian(ohci) ?
+			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+}
+
+static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
+                               const struct td *td, int index)
+{
+	return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index));
+}
+
+/*-------------------------------------------------------------------------*/
+
 static inline void disable (struct ohci_hcd *ohci)
 {
-	ohci_to_hcd(ohci)->state = USB_STATE_HALT;
+	ohci_to_hcd(ohci)->state = HC_STATE_HALT;
 }
 
 #define	FI			0x2edf		/* 12000 bits per frame (-1) */
 #define	FSMP(fi) 		(0x7fff & ((6 * ((fi) - 210)) / 7))
+#define	FIT			(1 << 31)
 #define LSTHRESH		0x628		/* lowspeed bit threshold */
 
-static inline void periodic_reinit (struct ohci_hcd *ohci)
+static void periodic_reinit (struct ohci_hcd *ohci)
 {
-	u32	fi = ohci->fminterval & 0x0ffff;
+	u32	fi = ohci->fminterval & 0x03fff;
+	u32	fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
 
+	ohci_writel (ohci, (fit ^ FIT) | ohci->fminterval,
+						&ohci->regs->fminterval);
 	ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff,
 						&ohci->regs->periodicstart);
 }
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -2,8 +2,8 @@
  * SL811HS HCD (Host Controller Driver) for USB.
  *
  * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
- * Copyright (C) 2004 David Brownell
- * 
+ * Copyright (C) 2004-2005 David Brownell
+ *
  * Periodic scheduling is based on Roman's OHCI code
  * 	Copyright (C) 1999 Roman Weissgaerber
  *
@@ -15,7 +15,7 @@
  * For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
  * document (providing significant pieces missing from that spec); plus
  * the SL811S spec if you want peripheral side info.
- */ 
+ */
 
 /*
  * Status:  Passed basic stress testing, works with hubs, mice, keyboards,
@@ -67,7 +67,7 @@
 MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION	"15 Dec 2004"
+#define DRIVER_VERSION	"19 May 2005"
 
 
 #ifndef DEBUG
@@ -90,8 +90,6 @@ static const char hcd_name[] = "sl811-hc
 
 /*-------------------------------------------------------------------------*/
 
-static irqreturn_t sl811h_irq(int irq, void *_hcd, struct pt_regs *regs);
-
 static void port_power(struct sl811 *sl811, int is_on)
 {
 	struct usb_hcd	*hcd = sl811_to_hcd(sl811);
@@ -103,12 +101,12 @@ static void port_power(struct sl811 *sl8
 
 		sl811->port1 = (1 << USB_PORT_FEAT_POWER);
 		sl811->irq_enable = SL11H_INTMASK_INSRMV;
-		hcd->self.controller->power.power_state = PM_SUSPEND_ON;
+		hcd->self.controller->power.power_state = PMSG_ON;
 	} else {
 		sl811->port1 = 0;
 		sl811->irq_enable = 0;
-		hcd->state = USB_STATE_HALT;
-		hcd->self.controller->power.power_state = PM_SUSPEND_DISK;
+		hcd->state = HC_STATE_HALT;
+		hcd->self.controller->power.power_state = PMSG_SUSPEND;
 	}
 	sl811->ctrl1 = 0;
 	sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
@@ -123,6 +121,10 @@ static void port_power(struct sl811 *sl8
 	/* reset as thoroughly as we can */
 	if (sl811->board && sl811->board->reset)
 		sl811->board->reset(hcd->self.controller);
+	else {
+		sl811_write(sl811, SL11H_CTLREG1, SL11H_CTL1MASK_SE0);
+		mdelay(20);
+	}
 
 	sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
 	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
@@ -136,7 +138,7 @@ static void port_power(struct sl811 *sl8
 
 /* This is a PIO-only HCD.  Queueing appends URBs to the endpoint's queue,
  * and may start I/O.  Endpoint queues are scanned during completion irq
- * handlers (one per packet: ACK, NAK, faults, etc) and urb cancelation.
+ * handlers (one per packet: ACK, NAK, faults, etc) and urb cancellation.
  *
  * Using an external DMA engine to copy a packet at a time could work,
  * though setup/teardown costs may be too big to make it worthwhile.
@@ -445,6 +447,7 @@ static void finish_request(
 	spin_lock(&urb->lock);
 	if (urb->status == -EINPROGRESS)
 		urb->status = status;
+	urb->hcpriv = NULL;
 	spin_unlock(&urb->lock);
 
 	spin_unlock(&sl811->lock);
@@ -474,7 +477,7 @@ static void finish_request(
 		if (*prev)
 			*prev = ep->next;
 		sl811->load[i] -= ep->load;
-	}	
+	}
 	ep->branch = PERIODIC_SIZE;
 	sl811->periodic_count--;
 	sl811_to_hcd(sl811)->self.bandwidth_allocated
@@ -645,9 +648,8 @@ static inline u8 checkdone(struct sl811 
 	return irqstat;
 }
 
-static irqreturn_t sl811h_irq(int irq, void *_hcd, struct pt_regs *regs)
+static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
-	struct usb_hcd	*hcd = _hcd;
 	struct sl811	*sl811 = hcd_to_sl811(hcd);
 	u8		irqstat;
 	irqreturn_t	ret = IRQ_NONE;
@@ -664,9 +666,9 @@ retry:
 
 #ifdef	QUIRK2
 	/* this may no longer be necessary ... */
-	if (irqstat == 0 && ret == IRQ_NONE) {
+	if (irqstat == 0) {
 		irqstat = checkdone(sl811);
-		if (irqstat && irq != ~0)
+		if (irqstat)
 			sl811->stat_lost++;
 	}
 #endif
@@ -725,7 +727,8 @@ retry:
 		if (sl811->active_a) {
 			sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
 			finish_request(sl811, sl811->active_a,
-				container_of(sl811->active_a->hep->urb_list.next,
+				container_of(sl811->active_a
+						->hep->urb_list.next,
 					struct urb, urb_list),
 				NULL, -ESHUTDOWN);
 			sl811->active_a = NULL;
@@ -734,14 +737,15 @@ retry:
 		if (sl811->active_b) {
 			sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
 			finish_request(sl811, sl811->active_b,
-				container_of(sl811->active_b->hep->urb_list.next,
+				container_of(sl811->active_b
+						->hep->urb_list.next,
 					struct urb, urb_list),
 				NULL, -ESHUTDOWN);
 			sl811->active_b = NULL;
 		}
 #endif
 
-		/* port status seems wierd until after reset, so
+		/* port status seems weird until after reset, so
 		 * force the reset and make khubd clean up later.
 		 */
 		sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
@@ -760,12 +764,11 @@ retry:
 		if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
 			start_transfer(sl811);
 		ret = IRQ_HANDLED;
-		hcd->saw_irq = 1;
 		if (retries--)
 			goto retry;
 	}
 
-	if (sl811->periodic_count == 0 && list_empty(&sl811->async)) 
+	if (sl811->periodic_count == 0 && list_empty(&sl811->async))
 		sofirq_off(sl811);
 	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 
@@ -800,7 +803,7 @@ static int balance(struct sl811 *sl811, 
 			}
 			if (j < PERIODIC_SIZE)
 				continue;
-			branch = i; 
+			branch = i;
 		}
 	}
 	return branch;
@@ -838,7 +841,7 @@ static int sl811h_urb_enqueue(
 
 	/* don't submit to a dead or disabled port */
 	if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
-			|| !HCD_IS_RUNNING(hcd->state)) {
+			|| !HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		goto fail;
 	}
@@ -894,6 +897,7 @@ static int sl811h_urb_enqueue(
 			break;
 		}
 
+		ep->hep = hep;
 		hep->hcpriv = ep;
 	}
 
@@ -965,15 +969,16 @@ fail:
 static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 {
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
-	struct usb_host_endpoint *hep = urb->hcpriv;
+	struct usb_host_endpoint *hep;
 	unsigned long		flags;
 	struct sl811h_ep	*ep;
 	int			retval = 0;
 
+	spin_lock_irqsave(&sl811->lock, flags);
+	hep = urb->hcpriv;
 	if (!hep)
-		return -EINVAL;
+		goto fail;
 
-	spin_lock_irqsave(&sl811->lock, flags);
 	ep = hep->hcpriv;
 	if (ep) {
 		/* finish right away if this urb can't be active ...
@@ -1021,6 +1026,7 @@ static int sl811h_urb_dequeue(struct usb
 			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
 				(sl811->active_a == ep) ? "A" : "B");
 	} else
+fail:
 		retval = -EINVAL;
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
@@ -1073,7 +1079,7 @@ sl811h_hub_status_data(struct usb_hcd *h
 	 */
 	local_irq_save(flags);
 	if (!timer_pending(&sl811->timer)) {
-		if (sl811h_irq(~0, sl811, NULL) != IRQ_NONE)
+		if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
 			sl811->stat_lost++;
 	}
 	local_irq_restore(flags);
@@ -1566,12 +1572,12 @@ sl811h_start(struct usb_hcd *hcd)
 		return -ENOMEM;
 
 	udev->speed = USB_SPEED_FULL;
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 	if (sl811->board)
 		hcd->can_wakeup = sl811->board->can_wakeup;
 
-	if (hcd_register_root(udev, hcd) != 0) {
+	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
 		usb_put_dev(udev);
 		sl811h_stop(hcd);
 		return -ENODEV;
@@ -1580,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd)
 	if (sl811->board && sl811->board->power)
 		hub_set_power_budget(udev, sl811->board->power * 2);
 
+	/* enable power and interupts */
+	port_power(sl811, 1);
+
 	return 0;
 }
 
@@ -1592,7 +1601,12 @@ static struct hc_driver sl811h_hc_driver
 	/*
 	 * generic hardware linkage
 	 */
-	.flags =		HCD_USB11,
+	.irq =			sl811h_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/* Basic lifecycle operations */
+	.start =		sl811h_start,
+	.stop =			sl811h_stop,
 
 	/*
 	 * managing i/o requests and associated device resources
@@ -1617,42 +1631,33 @@ static struct hc_driver sl811h_hc_driver
 
 /*-------------------------------------------------------------------------*/
 
-static int __init_or_module
+static int __devexit
 sl811h_remove(struct device *dev)
 {
-	struct sl811		*sl811 = dev_get_drvdata(dev);
-	struct usb_hcd		*hcd = sl811_to_hcd(sl811);
+	struct usb_hcd		*hcd = dev_get_drvdata(dev);
+	struct sl811		*sl811 = hcd_to_sl811(hcd);
 	struct platform_device	*pdev;
 	struct resource		*res;
 
 	pdev = container_of(dev, struct platform_device, dev);
 
-	if (HCD_IS_RUNNING(hcd->state))
-		hcd->state = USB_STATE_QUIESCING;
-
-	usb_disconnect(&hcd->self.root_hub);
 	remove_debug_file(sl811);
-	sl811h_stop(hcd);
+	usb_remove_hcd(hcd);
 
-	usb_deregister_bus(&hcd->self);
-
-	free_irq(hcd->irq, hcd);
-
-	iounmap(sl811->data_reg);
+	/* some platforms may use IORESOURCE_IO */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	release_mem_region(res->start, 1);
+	if (res)
+		iounmap(sl811->data_reg);
 
-	iounmap(sl811->addr_reg);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, 1);
+	if (res)
+		iounmap(sl811->addr_reg);
 
 	usb_put_hcd(hcd);
 	return 0;
 }
 
-#define resource_len(r) (((r)->end - (r)->start) + 1)
-
-static int __init
+static int __devinit
 sl811h_probe(struct device *dev)
 {
 	struct usb_hcd		*hcd;
@@ -1663,7 +1668,7 @@ sl811h_probe(struct device *dev)
 	void __iomem		*addr_reg;
 	void __iomem		*data_reg;
 	int			retval;
-	u8			tmp;
+	u8			tmp, ioaddr = 0;
 
 	/* basic sanity checks first.  board-specific init logic should
 	 * have initialized these three resources and probably board
@@ -1671,13 +1676,8 @@ sl811h_probe(struct device *dev)
 	 * minimal sanity checking.
 	 */
 	pdev = container_of(dev, struct platform_device, dev);
-	if (pdev->num_resources < 3)
-		return -ENODEV;
-
-	addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	irq = platform_get_irq(pdev, 0);
-	if (!addr || !data || irq < 0)
+	if (pdev->num_resources < 3 || irq < 0)
 		return -ENODEV;
 
 	/* refuse to confuse usbcore */
@@ -1686,39 +1686,41 @@ sl811h_probe(struct device *dev)
 		return -EINVAL;
 	}
 
-	if (!request_mem_region(addr->start, 1, hcd_name)) {
-		retval = -EBUSY;
-		goto err1;
-	}
-	addr_reg = ioremap(addr->start, resource_len(addr));
-	if (addr_reg == NULL) {
-		retval = -ENOMEM;
-		goto err2;
-	}
+	/* the chip may be wired for either kind of addressing */
+	addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	retval = -EBUSY;
+	if (!addr || !data) {
+		addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
+		data = platform_get_resource(pdev, IORESOURCE_IO, 1);
+		if (!addr || !data)
+			return -ENODEV;
+		ioaddr = 1;
 
-	if (!request_mem_region(data->start, 1, hcd_name)) {
-		retval = -EBUSY;
-		goto err3;
-	}
-	data_reg = ioremap(data->start, resource_len(addr));
-	if (data_reg == NULL) {
-		retval = -ENOMEM;
-		goto err4;
+		addr_reg = (void __iomem *) addr->start;
+		data_reg = (void __iomem *) data->start;
+	} else {
+		addr_reg = ioremap(addr->start, 1);
+		if (addr_reg == NULL) {
+			retval = -ENOMEM;
+			goto err2;
+		}
+
+		data_reg = ioremap(data->start, 1);
+		if (data_reg == NULL) {
+			retval = -ENOMEM;
+			goto err4;
+		}
 	}
 
 	/* allocate and initialize hcd */
-	hcd = usb_create_hcd(&sl811h_hc_driver);
+	hcd = usb_create_hcd(&sl811h_hc_driver, dev, dev->bus_id);
 	if (!hcd) {
-		retval = 0;
+		retval = -ENOMEM;
 		goto err5;
 	}
+	hcd->rsrc_start = addr->start;
 	sl811 = hcd_to_sl811(hcd);
-	dev_set_drvdata(dev, sl811);
-
-	hcd->self.controller = dev;
-	hcd->self.bus_name = dev->bus_id;
-	hcd->irq = irq;
-	hcd->regs = addr_reg;
 
 	spin_lock_init(&sl811->lock);
 	INIT_LIST_HEAD(&sl811->async);
@@ -1749,44 +1751,29 @@ sl811h_probe(struct device *dev)
 		goto err6;
 	}
 
-	/* sl811s would need a different handler for this irq */
-#ifdef	CONFIG_ARM
-	/* Cypress docs say the IRQ is IRQT_HIGH ... */
-	set_irq_type(irq, IRQT_RISING);
-#endif
-	retval = request_irq(irq, sl811h_irq, SA_INTERRUPT,
-			hcd->driver->description, hcd);
+	/* The chip's IRQ is level triggered, active high.  A requirement
+	 * for platform device setup is to cope with things like signal
+	 * inverters (e.g. CF is active low) or working only with edge
+	 * triggers (e.g. most ARM CPUs).  Initial driver stress testing
+	 * was on a system with single edge triggering, so most sorts of
+	 * triggering arrangement should work.
+	 */
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
 	if (retval != 0)
 		goto err6;
 
-	INFO("%s, irq %d\n", hcd->product_desc, irq);
-
-	retval = usb_register_bus(&hcd->self);
-	if (retval < 0)
-		goto err7;
-
-	retval = sl811h_start(hcd);
-	if (retval < 0)
-		goto err8;
-
 	create_debug_file(sl811);
-	return 0;
+	return retval;
 
- err8:
-	usb_deregister_bus(&hcd->self);
- err7:
-	free_irq(hcd->irq, hcd);
  err6:
 	usb_put_hcd(hcd);
  err5:
-	iounmap(data_reg);
+	if (!ioaddr)
+		iounmap(data_reg);
  err4:
-	release_mem_region(data->start, 1);
- err3:
-	iounmap(addr_reg);
+	if (!ioaddr)
+		iounmap(addr_reg);
  err2:
-	release_mem_region(addr->start, 1);
- err1:
 	DBG("init error, %d\n", retval);
 	return retval;
 }
@@ -1794,21 +1781,22 @@ sl811h_probe(struct device *dev)
 #ifdef	CONFIG_PM
 
 /* for this device there's no useful distinction between the controller
- * and its root hub, except that the root hub only gets direct PM calls 
+ * and its root hub, except that the root hub only gets direct PM calls
  * when CONFIG_USB_SUSPEND is enabled.
  */
 
 static int
-sl811h_suspend(struct device *dev, u32 state, u32 phase)
+sl811h_suspend(struct device *dev, pm_message_t state, u32 phase)
 {
-	struct sl811	*sl811 = dev_get_drvdata(dev);
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
 	int		retval = 0;
 
 	if (phase != SUSPEND_POWER_DOWN)
 		return retval;
 
 	if (state <= PM_SUSPEND_MEM)
-		retval = sl811h_hub_suspend(sl811_to_hcd(sl811));
+		retval = sl811h_hub_suspend(hcd);
 	else
 		port_power(sl811, 0);
 	if (retval == 0)
@@ -1819,7 +1807,8 @@ sl811h_suspend(struct device *dev, u32 s
 static int
 sl811h_resume(struct device *dev, u32 phase)
 {
-	struct sl811	*sl811 = dev_get_drvdata(dev);
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
 
 	if (phase != RESUME_POWER_ON)
 		return 0;
@@ -1828,14 +1817,14 @@ sl811h_resume(struct device *dev, u32 ph
 	 * let's assume it'd only be powered to enable remote wakeup.
 	 */
 	if (dev->power.power_state > PM_SUSPEND_MEM
-			|| !sl811_to_hcd(sl811)->can_wakeup) {
+			|| !hcd->can_wakeup) {
 		sl811->port1 = 0;
 		port_power(sl811, 1);
 		return 0;
 	}
 
-	dev->power.power_state = PM_SUSPEND_ON;
-	return sl811h_hub_resume(sl811_to_hcd(sl811));
+	dev->power.power_state = PMSG_ON;
+	return sl811h_hub_resume(hcd);
 }
 
 #else
@@ -1846,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 ph
 #endif
 
 
-static struct device_driver sl811h_driver = {
+/* this driver is exported so sl811_cs can depend on it */
+struct device_driver sl811h_driver = {
 	.name =		(char *) hcd_name,
 	.bus =		&platform_bus_type,
 
 	.probe =	sl811h_probe,
-	.remove =	sl811h_remove,
+	.remove =	__devexit_p(sl811h_remove),
 
 	.suspend =	sl811h_suspend,
 	.resume =	sl811h_resume,
 };
+EXPORT_SYMBOL(sl811h_driver);
 
 /*-------------------------------------------------------------------------*/
- 
-static int __init sl811h_init(void) 
+
+static int __init sl811h_init(void)
 {
 	if (usb_disabled())
 		return -ENODEV;
@@ -1869,8 +1860,8 @@ static int __init sl811h_init(void) 
 }
 module_init(sl811h_init);
 
-static void __exit sl811h_cleanup(void) 
-{	
+static void __exit sl811h_cleanup(void)
+{
 	driver_unregister(&sl811h_driver);
 }
 module_exit(sl811h_cleanup);
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/host/sl811_cs.c
@@ -0,0 +1,442 @@
+/*
+ * PCMCIA driver for SL811HS (as found in REX-CFU1U)
+ * Filename: sl811_cs.c
+ * Author:   Yukio Yamamoto
+ *
+ *  Port to sl811-hcd and 2.6.x by
+ *    Botond Botyanszki <boti@rocketmail.com>
+ *    Simon Pickering
+ *
+ *  Last update: 2005-05-12
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.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 <linux/usb_sl811.h>
+
+MODULE_AUTHOR("Botond Botyanszki");
+MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6");
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+/* MACROS                                                             */
+/*====================================================================*/
+
+#if defined(DEBUG) || defined(CONFIG_USB_DEBUG) || defined(PCMCIA_DEBUG)
+
+static int pc_debug = 0;
+module_param(pc_debug, int, 0644);
+
+#define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args)
+
+#else
+#define DBG(n, args...) do{}while(0)
+#endif	/* no debugging */
+
+#define INFO(args...) printk(KERN_INFO "sl811_cs: " args)
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
+
+#define CS_CHECK(fn, ret) \
+	do { \
+		last_fn = (fn); \
+		if ((last_ret = (ret)) != 0) \
+			goto cs_failed; \
+	} while (0)
+
+/*====================================================================*/
+/* VARIABLES                                                          */
+/*====================================================================*/
+
+static const char driver_name[DEV_NAME_LEN]  = "sl811_cs";
+
+static dev_link_t *dev_list = NULL;
+
+static int irq_list[4] = { -1 };
+static int irq_list_count;
+
+module_param_array(irq_list, int, &irq_list_count, 0444);
+
+INT_MODULE_PARM(irq_mask, 0xdeb8);
+
+typedef struct local_info_t {
+	dev_link_t		link;
+	dev_node_t		node;
+} local_info_t;
+
+/*====================================================================*/
+
+static void release_platform_dev(struct device * dev)
+{
+	DBG(0, "sl811_cs platform_dev release\n");
+	dev->parent = NULL;
+}
+
+static struct sl811_platform_data platform_data = {
+	.potpg		= 100,
+	.power		= 50,		/* == 100mA */
+	// .reset	= ... FIXME:  invoke CF reset on the card
+};
+
+static struct resource resources[] = {
+	[0] = {
+		.flags	= IORESOURCE_IRQ,
+	},
+	[1] = {
+		// .name   = "address",
+		.flags	= IORESOURCE_IO,
+	},
+	[2] = {
+		// .name   = "data",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+extern struct device_driver sl811h_driver;
+
+static struct platform_device platform_dev = {
+	.id			= -1,
+	.dev = {
+		.platform_data = &platform_data,
+		.release       = release_platform_dev,
+	},
+	.resource		= resources,
+	.num_resources		= ARRAY_SIZE(resources),
+};
+
+static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq)
+{
+	if (platform_dev.dev.parent)
+		return -EBUSY;
+	platform_dev.dev.parent = parent;
+
+	/* finish seting up the platform device */
+	resources[0].start = irq;
+
+	resources[1].start = base_addr;
+	resources[1].end = base_addr;
+
+	resources[2].start = base_addr + 1;
+	resources[2].end   = base_addr + 1;
+
+	/* The driver core will probe for us.  We know sl811-hcd has been
+	 * initialized already because of the link order dependency.
+	 */
+	platform_dev.name = sl811h_driver.name;
+	return platform_device_register(&platform_dev);
+}
+
+/*====================================================================*/
+
+static void sl811_cs_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+
+	DBG(0, "sl811_cs_detach(0x%p)\n", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
+		if (*linkp == link)
+			break;
+	}
+	if (*linkp == NULL)
+		return;
+
+	/* Break the link with Card Services */
+	if (link->handle)
+		pcmcia_deregister_client(link->handle);
+
+	/* Unlink device structure, and free it */
+	*linkp = link->next;
+	/* This points to the parent local_info_t struct */
+	kfree(link->priv);
+}
+
+static void sl811_cs_release(dev_link_t * link)
+{
+
+	DBG(0, "sl811_cs_release(0x%p)\n", link);
+
+	if (link->open) {
+		DBG(1, "sl811_cs: release postponed, '%s' still open\n",
+		    link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	/* Unlink the device chain */
+	link->dev = NULL;
+
+	platform_device_unregister(&platform_dev);
+	pcmcia_release_configuration(link->handle);
+	if (link->io.NumPorts1)
+		pcmcia_release_io(link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		pcmcia_release_irq(link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+
+	if (link->state & DEV_STALE_LINK)
+		sl811_cs_detach(link);
+}
+
+static void sl811_cs_config(dev_link_t *link)
+{
+	client_handle_t		handle = link->handle;
+	struct device		*parent = &handle_to_dev(handle);
+	local_info_t		*dev = 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 };
+
+	DBG(0, "sl811_cs_config(0x%p)\n", link);
+
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(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,
+			pcmcia_get_configuration_info(handle, &conf));
+	link->conf.Vcc = conf.Vcc;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	while (1) {
+		cistpl_cftable_entry_t	*cfg = &(parse.cftable_entry);
+
+		if (pcmcia_get_tuple_data(handle, &tuple) != 0
+				|| pcmcia_parse_tuple(handle, &tuple, &parse)
+						!= 0)
+			goto next_entry;
+
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) {
+			dflt = *cfg;
+		}
+
+		if (cfg->index == 0)
+			goto next_entry;
+
+		link->conf.ConfigIndex = cfg->index;
+
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+			if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000
+					!= conf.Vcc)
+				goto next_entry;
+		} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+			if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000
+					!= conf.Vcc)
+				goto next_entry;
+		}
+
+		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+		/* we need an interrupt */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 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_8;
+			link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+
+			if (pcmcia_request_io(link->handle, &link->io) != 0)
+				goto next_entry;
+		}
+		break;
+
+next_entry:
+		if (link->io.NumPorts1)
+			pcmcia_release_io(link->handle, &link->io);
+		last_ret = pcmcia_get_next_tuple(handle, &tuple);
+	}
+
+	/* require an IRQ and two registers */
+	if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
+		goto cs_failed;
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		CS_CHECK(RequestIRQ,
+			pcmcia_request_irq(link->handle, &link->irq));
+	else
+		goto cs_failed;
+
+	CS_CHECK(RequestConfiguration,
+		pcmcia_request_configuration(link->handle, &link->conf));
+
+	sprintf(dev->node.dev_name, driver_name);
+	dev->node.major = dev->node.minor = 0;
+	link->dev = &dev->node;
+
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	       dev->node.dev_name, link->conf.ConfigIndex,
+	       link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	printk(", irq %d", link->irq.AssignedIRQ);
+	printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+	       link->io.BasePort1+link->io.NumPorts1-1);
+	printk("\n");
+
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ)
+			< 0) {
+cs_failed:
+		printk("sl811_cs_config failed\n");
+		cs_error(link->handle, last_fn, last_ret);
+		sl811_cs_release(link);
+		link->state &= ~DEV_CONFIG_PENDING;
+	}
+}
+
+static int
+sl811_cs_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+
+	DBG(1, "sl811_cs_event(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG)
+			sl811_cs_release(link);
+		break;
+
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		sl811_cs_config(link);
+		break;
+
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			pcmcia_release_configuration(link->handle);
+		break;
+
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG)
+			pcmcia_request_configuration(link->handle, &link->conf);
+		DBG(0, "reset sl811-hcd here?\n");
+		break;
+	}
+	return 0;
+}
+
+static dev_link_t *sl811_cs_attach(void)
+{
+	local_info_t *local;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int ret, i;
+
+	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	if (!local)
+		return NULL;
+	memset(local, 0, sizeof(local_info_t));
+	link = &local->link;
+	link->priv = local;
+
+	/* Initialize */
+	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 < irq_list_count; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = NULL;
+
+	link->conf.Attributes = 0;
+	link->conf.Vcc = 33;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = (dev_info_t *) &driver_name;
+	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 = &sl811_cs_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		sl811_cs_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+static struct pcmcia_driver sl811_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= (char *)driver_name,
+	},
+	.attach		= sl811_cs_attach,
+	.detach		= sl811_cs_detach,
+};
+
+/*====================================================================*/
+
+static int __init init_sl811_cs(void)
+{
+	return pcmcia_register_driver(&sl811_cs_driver);
+}
+module_init(init_sl811_cs);
+
+static void __exit exit_sl811_cs(void)
+{
+	pcmcia_unregister_driver(&sl811_cs_driver);
+}
+module_exit(exit_sl811_cs);
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -17,6 +17,8 @@
 
 #include "uhci-hcd.h"
 
+static struct dentry *uhci_debugfs_root = NULL;
+
 /* Handle REALLY large printk's so we don't overflow buffers */
 static inline void lprintk(char *buf)
 {
@@ -404,7 +406,7 @@ static int uhci_sprint_schedule(struct u
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 
-	spin_lock_irqsave(&uhci->schedule_lock, flags);
+	spin_lock_irqsave(&uhci->lock, flags);
 
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
@@ -490,15 +492,13 @@ static int uhci_sprint_schedule(struct u
 	if (debug > 2)
 		out += uhci_show_lists(uhci, out, len - (out - buf));
 
-	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
+	spin_unlock_irqrestore(&uhci->lock, flags);
 
 	return out - buf;
 }
 
 #define MAX_OUTPUT	(64 * 1024)
 
-static struct dentry *uhci_debugfs_root = NULL;
-
 struct uhci_debug {
 	int size;
 	char *data;
@@ -579,4 +579,9 @@ static struct file_operations uhci_debug
 	.read =		uhci_debug_read,
 	.release =	uhci_debug_release,
 };
+
+#else	/* CONFIG_DEBUG_FS */
+
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+
 #endif
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -87,19 +87,9 @@ MODULE_PARM_DESC(debug, "Debug level");
 static char *errbuf;
 #define ERRBUF_LEN    (32 * 1024)
 
-#include "uhci-hub.c"
-#include "uhci-debug.c"
-
 static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
 
-static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci);
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
-static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
-static void uhci_free_pending_tds(struct uhci_hcd *uhci);
-
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
@@ -111,1424 +101,9 @@ static void hc_state_transitions(struct 
 /* to make sure it doesn't hog all of the bandwidth */
 #define DEPTH_INTERVAL 5
 
-/*
- * 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 spurious 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_hcd *uhci)
-{
-	uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
-}
-
-static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
-{
-	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
-}
-
-static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
-					struct urb_priv *urbp)
-{
-	list_move_tail(&urbp->urb_list, &uhci->complete_list);
-}
-
-static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_td *td;
-
-	td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
-	if (!td)
-		return NULL;
-
-	td->dma_handle = dma_handle;
-
-	td->link = UHCI_PTR_TERM;
-	td->buffer = 0;
-
-	td->frame = -1;
-	td->dev = dev;
-
-	INIT_LIST_HEAD(&td->list);
-	INIT_LIST_HEAD(&td->remove_list);
-	INIT_LIST_HEAD(&td->fl_list);
-
-	usb_get_dev(dev);
-
-	return td;
-}
-
-static inline void uhci_fill_td(struct uhci_td *td, u32 status,
-		u32 token, u32 buffer)
-{
-	td->status = cpu_to_le32(status);
-	td->token = cpu_to_le32(token);
-	td->buffer = cpu_to_le32(buffer);
-}
-
-/*
- * We insert Isochronous URB's directly into the frame list at the beginning
- */
-static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
-{
-	framenum &= (UHCI_NUMFRAMES - 1);
-
-	td->frame = framenum;
-
-	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
-		struct uhci_td *ftd, *ltd;
-
-		ftd = uhci->fl->frame_cpu[framenum];
-		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
-
-		list_add_tail(&td->fl_list, &ftd->fl_list);
-
-		td->link = ltd->link;
-		wmb();
-		ltd->link = cpu_to_le32(td->dma_handle);
-	} else {
-		td->link = uhci->fl->frame[framenum];
-		wmb();
-		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
-		uhci->fl->frame_cpu[framenum] = td;
-	}
-}
-
-static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
-	/* If it's not inserted, don't remove it */
-	if (td->frame == -1 && list_empty(&td->fl_list))
-		return;
-
-	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
-		if (list_empty(&td->fl_list)) {
-			uhci->fl->frame[td->frame] = td->link;
-			uhci->fl->frame_cpu[td->frame] = NULL;
-		} else {
-			struct uhci_td *ntd;
-
-			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-			uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
-			uhci->fl->frame_cpu[td->frame] = ntd;
-		}
-	} else {
-		struct uhci_td *ptd;
-
-		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
-		ptd->link = td->link;
-	}
-
-	wmb();
-	td->link = UHCI_PTR_TERM;
-
-	list_del_init(&td->fl_list);
-	td->frame = -1;
-}
-
-/*
- * Inserts a td list into qh.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	__le32 *plink;
-
-	/* Ordering isn't important here yet since the QH hasn't been */
-	/* inserted into the schedule yet */
-	plink = &qh->element;
-	list_for_each_entry(td, &urbp->td_list, list) {
-		*plink = cpu_to_le32(td->dma_handle) | breadth;
-		plink = &td->link;
-	}
-	*plink = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
-	if (!list_empty(&td->list))
-		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
-	if (!list_empty(&td->remove_list))
-		dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
-	if (!list_empty(&td->fl_list))
-		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
-
-	if (td->dev)
-		usb_put_dev(td->dev);
-
-	dma_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_qh *qh;
-
-	qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
-	if (!qh)
-		return NULL;
-
-	qh->dma_handle = dma_handle;
-
-	qh->element = UHCI_PTR_TERM;
-	qh->link = UHCI_PTR_TERM;
-
-	qh->dev = dev;
-	qh->urbp = NULL;
-
-	INIT_LIST_HEAD(&qh->list);
-	INIT_LIST_HEAD(&qh->remove_list);
-
-	usb_get_dev(dev);
-
-	return qh;
-}
-
-static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
-{
-	if (!list_empty(&qh->list))
-		dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
-	if (!list_empty(&qh->remove_list))
-		dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
-
-	if (qh->dev)
-		usb_put_dev(qh->dev);
-
-	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
-}
-
-/*
- * Append this urb's qh after the last qh in skelqh->list
- *
- * Note that urb_priv.queue_list doesn't have a separate queue head;
- * it's a ring with every element "live".
- */
-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct urb_priv *turbp;
-	struct uhci_qh *lqh;
-
-	/* Grab the last QH */
-	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
-
-	/* Point to the next skelqh */
-	urbp->qh->link = lqh->link;
-	wmb();				/* Ordering is important */
-
-	/*
-	 * Patch QHs for previous endpoint's queued URBs?  HC goes
-	 * here next, not to the next skelqh it now points to.
-	 *
-	 *    lqh --> td ... --> qh ... --> td --> qh ... --> td
-	 *     |                 |                 |
-	 *     v                 v                 v
-	 *     +<----------------+-----------------+
-	 *     v
-	 *    newqh --> td ... --> td
-	 *     |
-	 *     v
-	 *    ...
-	 *
-	 * The HC could see (and use!) any of these as we write them.
-	 */
-	lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-	if (lqh->urbp) {
-		list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
-			turbp->qh->link = lqh->link;
-	}
-
-	list_add_tail(&urbp->qh->list, &skelqh->list);
-}
-
-/*
- * Start removal of QH from schedule; it finishes next frame.
- * TDs should be unlinked before this is called.
- */
-static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
-{
-	struct uhci_qh *pqh;
-	__le32 newlink;
-	unsigned int age;
-
-	if (!qh)
-		return;
-
-	/*
-	 * Only go through the hoops if it's actually linked in
-	 */
-	if (!list_empty(&qh->list)) {
-
-		/* If our queue is nonempty, make the next URB the head */
-		if (!list_empty(&qh->urbp->queue_list)) {
-			struct urb_priv *nurbp;
-
-			nurbp = list_entry(qh->urbp->queue_list.next,
-					struct urb_priv, queue_list);
-			nurbp->queued = 0;
-			list_add(&nurbp->qh->list, &qh->list);
-			newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-		} else
-			newlink = qh->link;
-
-		/* Fix up the previous QH's queue to link to either
-		 * the new head of this queue or the start of the
-		 * next endpoint's queue. */
-		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-		pqh->link = newlink;
-		if (pqh->urbp) {
-			struct urb_priv *turbp;
-
-			list_for_each_entry(turbp, &pqh->urbp->queue_list,
-					queue_list)
-				turbp->qh->link = newlink;
-		}
-		wmb();
-
-		/* Leave qh->link in case the HC is on the QH now, it will */
-		/* continue the rest of the schedule */
-		qh->element = UHCI_PTR_TERM;
-
-		list_del_init(&qh->list);
-	}
-
-	list_del_init(&qh->urbp->queue_list);
-	qh->urbp = NULL;
-
-	age = uhci_get_current_frame_number(uhci);
-	if (age != uhci->qh_remove_age) {
-		uhci_free_pending_qhs(uhci);
-		uhci->qh_remove_age = age;
-	}
-
-	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the QH */
-	if (list_empty(&uhci->qh_remove_list))
-		uhci_set_next_interrupt(uhci);
-
-	list_add(&qh->remove_list, &uhci->qh_remove_list);
-}
-
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-
-	list_for_each_entry(td, &urbp->td_list, list) {
-		if (toggle)
-			td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
-		else
-			td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
-
-		toggle ^= 1;
-	}
-
-	return toggle;
-}
-
-/* This function will append one URB's QH to another URB's QH. This is for */
-/* queuing interrupt, control or bulk transfers */
-static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-	struct uhci_td *lltd;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	/* Find the first URB in the queue */
-	furbp = eurbp;
-	if (eurbp->queued) {
-		list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
-			if (!furbp->queued)
-				break;
-	}
-
-	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-	/* Control transfers always start with toggle 0 */
-	if (!usb_pipecontrol(urb->pipe))
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-				usb_pipeout(urb->pipe),
-				uhci_fixup_toggle(urb,
-					uhci_toggle(td_token(lltd)) ^ 1));
-
-	/* All qh's in the queue need to link to the next queue */
-	urbp->qh->link = eurbp->qh->link;
-
-	wmb();			/* Make sure we flush everything */
-
-	lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-	urbp->queued = 1;
-}
-
-static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp, *nurbp, *purbp, *turbp;
-	struct uhci_td *pltd;
-	unsigned int toggle;
-
-	urbp = urb->hcpriv;
-
-	if (list_empty(&urbp->queue_list))
-		return;
-
-	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
-	/*
-	 * Fix up the toggle for the following URBs in the queue.
-	 * Only needed for bulk and interrupt: control and isochronous
-	 * endpoints don't propagate toggles between messages.
-	 */
-	if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
-		if (!urbp->queued)
-			/* We just set the toggle in uhci_unlink_generic */
-			toggle = usb_gettoggle(urb->dev,
-					usb_pipeendpoint(urb->pipe),
-					usb_pipeout(urb->pipe));
-		else {
-			/* If we're in the middle of the queue, grab the */
-			/* toggle from the TD previous to us */
-			purbp = list_entry(urbp->queue_list.prev,
-					struct urb_priv, queue_list);
-			pltd = list_entry(purbp->td_list.prev,
-					struct uhci_td, list);
-			toggle = uhci_toggle(td_token(pltd)) ^ 1;
-		}
-
-		list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
-			if (!turbp->queued)
-				break;
-			toggle = uhci_fixup_toggle(turbp->urb, toggle);
-		}
-
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-				usb_pipeout(urb->pipe), toggle);
-	}
-
-	if (urbp->queued) {
-		/* We're somewhere in the middle (or end).  The case where
-		 * we're at the head is handled in uhci_remove_qh(). */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued)
-			pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-		else
-			/* The next URB happens to be the beginning, so */
-			/*  we're the last, end the chain */
-			pltd->link = UHCI_PTR_TERM;
-	}
-
-	/* urbp->queue_list is handled in uhci_remove_qh() */
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp;
-
-	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
-	if (!urbp)
-		return NULL;
-
-	memset((void *)urbp, 0, sizeof(*urbp));
-
-	urbp->inserttime = jiffies;
-	urbp->fsbrtime = jiffies;
-	urbp->urb = urb;
-	
-	INIT_LIST_HEAD(&urbp->td_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->urb_list);
-
-	list_add_tail(&urbp->urb_list, &uhci->urb_list);
-
-	urb->hcpriv = urbp;
-
-	return urbp;
-}
-
-static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	td->urb = urb;
-
-	list_add_tail(&td->list, &urbp->td_list);
-}
-
-static void uhci_remove_td_from_urb(struct uhci_td *td)
-{
-	if (list_empty(&td->list))
-		return;
-
-	list_del_init(&td->list);
-
-	td->urb = NULL;
-}
-
-static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct uhci_td *td, *tmp;
-	struct urb_priv *urbp;
-	unsigned int age;
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp)
-		return;
-
-	if (!list_empty(&urbp->urb_list))
-		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
-				"or uhci->remove_list!\n", urb);
-
-	age = uhci_get_current_frame_number(uhci);
-	if (age != uhci->td_remove_age) {
-		uhci_free_pending_tds(uhci);
-		uhci->td_remove_age = age;
-	}
-
-	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the TD's*/
-	if (list_empty(&uhci->td_remove_list))
-		uhci_set_next_interrupt(uhci);
-
-	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		list_add(&td->remove_list, &uhci->td_remove_list);
-	}
-
-	urb->hcpriv = NULL;
-	kmem_cache_free(uhci_up_cachep, urbp);
-}
-
-static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
-		urbp->fsbr = 1;
-		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-			uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-	}
-}
-
-static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
-		urbp->fsbr = 0;
-		if (!--uhci->fsbr)
-			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-	}
-}
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td_status(td) & 0xF60000), a.k.a.
- * uhci_status_bits(td_status(td)).
- * Note: <status> does not include the TD_CTRL_NAK bit.
- * <dir_out> is True for output TDs and False for input TDs.
- */
-static int uhci_map_status(int status, int dir_out)
-{
-	if (!status)
-		return 0;
-	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
-		return -EPROTO;
-	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
-		if (dir_out)
-			return -EPROTO;
-		else
-			return -EILSEQ;
-	}
-	if (status & TD_CTRL_BABBLE)			/* Babble */
-		return -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)			/* Stalled */
-		return -EPIPE;
-	WARN_ON(status & TD_CTRL_ACTIVE);		/* Active */
-	return 0;
-}
-
-/*
- * Control transfers
- */
-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	struct uhci_qh *qh, *skelqh;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	dma_addr_t data = urb->transfer_dma;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | uhci_maxerr(3);
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/*
-	 * Build the TD for the control request setup packet
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination | uhci_explen(7),
-		urb->setup_dma);
-
-	/*
-	 * If direction is "send", change the packet ID from SETUP (0x2D)
-	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
-	 * set Short Packet Detect (SPD) for all data packets.
-	 */
-	if (usb_pipeout(urb->pipe))
-		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
-	else {
-		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
-		status |= TD_CTRL_SPD;
-	}
-
-	/*
-	 * Build the DATA TD's
-	 */
-	while (len > 0) {
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		/* Alternate Data0/1 (start with Data1) */
-		destination ^= TD_TOKEN_TOGGLE;
-	
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
-			data);
-
-		data += pktsze;
-		len -= pktsze;
-	}
-
-	/*
-	 * Build the final TD for control status 
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	/*
-	 * It's IN if the pipe is an output pipe or we're not expecting
-	 * data back.
-	 */
-	destination &= ~TD_TOKEN_PID_MASK;
-	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
-
-	status &= ~TD_CTRL_SPD;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status | TD_CTRL_IOC,
-		destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
-
-	/* Low-speed transfers get a different queue, and won't hog the bus.
-	 * Also, some devices enumerate better without FSBR; the easiest way
-	 * to do that is to put URBs on the low-speed queue while the device
-	 * is in the DEFAULT state. */
-	if (urb->dev->speed == USB_SPEED_LOW ||
-			urb->dev->state == USB_STATE_DEFAULT)
-		skelqh = uhci->skel_ls_control_qh;
-	else {
-		skelqh = uhci->skel_fs_control_qh;
-		uhci_inc_fsbr(uhci, urb);
-	}
-
-	if (eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, skelqh, urb);
-
-	return -EINPROGRESS;
-}
-
-/*
- * If control-IN transfer was short, the status packet wasn't sent.
- * This routine changes the element pointer in the QH to point at the
- * status TD.  It's safe to do this even while the QH is live, because
- * the hardware only updates the element pointer following a successful
- * transfer.  The inactive TD for the short packet won't cause an update,
- * so the pointer won't get overwritten.  The next time the controller
- * sees this QH, it will send the status packet.
- */
-static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-
-	urbp->short_control_packet = 1;
-
-	td = list_entry(urbp->td_list.prev, struct uhci_td, list);
-	urbp->qh->element = cpu_to_le32(td->dma_handle);
-
-	return -EINPROGRESS;
-}
-
-
-static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	if (list_empty(&urbp->td_list))
-		return -EINVAL;
-
-	head = &urbp->td_list;
-
-	if (urbp->short_control_packet) {
-		tmp = head->prev;
-		goto status_stage;
-	}
-
-	tmp = head->next;
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* The first TD is the SETUP stage, check the status, but skip */
-	/*  the count */
-	status = uhci_status_bits(td_status(td));
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	urb->actual_length = 0;
-
-	/* The rest of the TD's (but the last) are data */
-	tmp = tmp->next;
-	while (tmp != head && tmp->next != head) {
-		unsigned int ctrlstat;
-
-		td = list_entry(tmp, struct uhci_td, list);
-		tmp = tmp->next;
-
-		ctrlstat = td_status(td);
-		status = uhci_status_bits(ctrlstat);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(ctrlstat);
-
-		if (status)
-			goto td_error;
-
-		/* Check to see if we received a short packet */
-		if (uhci_actual_length(ctrlstat) <
-				uhci_expected_length(td_token(td))) {
-			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-				ret = -EREMOTEIO;
-				goto err;
-			}
-
-			if (uhci_packetid(td_token(td)) == USB_PID_IN)
-				return usb_control_retrigger_status(uhci, urb);
-			else
-				return 0;
-		}
-	}
-
-status_stage:
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Control status stage */
-	status = td_status(td);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
-	/* APC BackUPS Pro kludge */
-	/* It tries to send all of the descriptor instead of the amount */
-	/*  we requested */
-	if (status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
-	    status & TD_CTRL_ACTIVE &&
-	    status & TD_CTRL_NAK)
-		return 0;
-#endif
-
-	status = uhci_status_bits(status);
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
-				__FUNCTION__, status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-/*
- * Common submit for bulk and interrupt
- */
-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
-{
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	dma_addr_t data = urb->transfer_dma;
-
-	if (len < 0)
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-	if (usb_pipein(urb->pipe))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	do {	/* Allow zero length packets */
-		int pktsze = maxsze;
-
-		if (pktsze >= len) {
-			pktsze = len;
-			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-				status &= ~TD_CTRL_SPD;
-		}
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		data += pktsze;
-		len -= maxsze;
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	} while (len > 0);
-
-	/*
-	 * URB_ZERO_PACKET means adding a 0-length packet, if direction
-	 * is OUT and the transfer_length was an exact multiple of maxsze,
-	 * hence (len = transfer_length - N * maxsze) == 0
-	 * however, if transfer_length == 0, the zero packet was already
-	 * prepared above.
-	 */
-	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
-	    !len && urb->transfer_buffer_length) {
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	}
-
-	/* Set the interrupt-on-completion flag on the last packet.
-	 * A more-or-less typical 4 KB URB (= size of one memory page)
-	 * will require about 3 ms to transfer; that's a little on the
-	 * fast side but not enough to justify delaying an interrupt
-	 * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
-	 * flag setting. */
-	td->status |= cpu_to_le32(TD_CTRL_IOC);
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Always breadth first */
-	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
-
-	if (eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, skelqh, urb);
-
-	return -EINPROGRESS;
-}
-
-/*
- * Common result for bulk and interrupt
- */
-static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status = 0;
-	int ret = 0;
-
-	urb->actual_length = 0;
-
-	list_for_each_entry(td, &urbp->td_list, list) {
-		unsigned int ctrlstat = td_status(td);
-
-		status = uhci_status_bits(ctrlstat);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(ctrlstat);
-
-		if (status)
-			goto td_error;
-
-		if (uhci_actual_length(ctrlstat) <
-				uhci_expected_length(td_token(td))) {
-			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-				ret = -EREMOTEIO;
-				goto err;
-			} else
-				return 0;
-		}
-	}
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
-	/* 
-	 * Enable this chunk of code if you want to see some more debugging.
-	 * But be careful, it has the tendancy to starve out khubd and prevent
-	 * disconnects from happening successfully if you have a slow debug
-	 * log interface (like a serial console.
-	 */
-#if 0
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
-				__FUNCTION__, status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-#endif
-	return ret;
-}
-
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
-	int ret;
-
-	/* Can't have low-speed bulk transfers */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		return -EINVAL;
-
-	ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
-	if (ret == -EINPROGRESS)
-		uhci_inc_fsbr(uhci, urb);
-
-	return ret;
-}
-
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
-	/* USB 1.1 interrupt transfers only involve one packet per interval;
-	 * that's the uhci_submit_common() "breadth first" policy.  Drivers
-	 * can submit urbs of any length, but longer ones might need many
-	 * intervals to complete.
-	 */
-	return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
-}
-
-/*
- * Isochronous transfers
- */
-static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *last_urb = NULL;
-	struct urb_priv *up;
-	int ret = 0;
-
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		/* look for pending URB's with identical pipe handle */
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
-		    (u->status == -EINPROGRESS) && (u != urb)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets *
-				last_urb->interval) & (UHCI_NUMFRAMES-1);
-		ret = 0;
-	} else
-		ret = -1;	/* no previous urb found */
-
-	return ret;
-}
-
-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
-{
-	int limits;
-	unsigned int start = 0, end = 0;
-
-	if (urb->number_of_packets > 900)	/* 900? Why? */
-		return -EFBIG;
-
-	limits = isochronous_find_limits(uhci, urb, &start, &end);
-
-	if (urb->transfer_flags & URB_ISO_ASAP) {
-		if (limits)
-			urb->start_frame =
-					(uhci_get_current_frame_number(uhci) +
-						10) & (UHCI_NUMFRAMES - 1);
-		else
-			urb->start_frame = end;
-	} else {
-		urb->start_frame &= (UHCI_NUMFRAMES - 1);
-		/* FIXME: Sanity check */
-	}
-
-	return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct uhci_td *td;
-	int i, ret, frame;
-	int status, destination;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	ret = isochronous_find_start(uhci, urb);
-	if (ret)
-		return ret;
-
-	frame = urb->start_frame;
-	for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
-		if (!urb->iso_frame_desc[i].length)
-			continue;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
-			urb->transfer_dma + urb->iso_frame_desc[i].offset);
-
-		if (i + 1 >= urb->number_of_packets)
-			td->status |= cpu_to_le32(TD_CTRL_IOC);
-
-		uhci_insert_td_frame_list(uhci, td, frame);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct uhci_td *td;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int status;
-	int i, ret = 0;
-
-	urb->actual_length = 0;
-
-	i = 0;
-	list_for_each_entry(td, &urbp->td_list, list) {
-		int actlength;
-		unsigned int ctrlstat = td_status(td);
-
-		if (ctrlstat & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		actlength = uhci_actual_length(ctrlstat);
-		urb->iso_frame_desc[i].actual_length = actlength;
-		urb->actual_length += actlength;
-
-		status = uhci_map_status(uhci_status_bits(ctrlstat),
-				usb_pipeout(urb->pipe));
-		urb->iso_frame_desc[i].status = status;
-		if (status) {
-			urb->error_count++;
-			ret = status;
-		}
-
-		i++;
-	}
-
-	return ret;
-}
-
-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *up;
-
-	/* We don't match Isoc transfers since they are special */
-	if (usb_pipeisoc(urb->pipe))
-		return NULL;
-
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		if (u->dev == urb->dev && u->status == -EINPROGRESS) {
-			/* For control, ignore the direction */
-			if (usb_pipecontrol(urb->pipe) &&
-			    (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
-				return u;
-			else if (u->pipe == urb->pipe)
-				return u;
-		}
-	}
-
-	return NULL;
-}
-
-static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *ep,
-		struct urb *urb, int mem_flags)
-{
-	int ret;
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	unsigned long flags;
-	struct urb *eurb;
-	int bustime;
-
-	spin_lock_irqsave(&uhci->schedule_lock, flags);
-
-	ret = urb->status;
-	if (ret != -EINPROGRESS)		/* URB already unlinked! */
-		goto out;
-
-	eurb = uhci_find_urb_ep(uhci, urb);
-
-	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_submit_control(uhci, urb, eurb);
-		break;
-	case PIPE_INTERRUPT:
-		if (!eurb) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(uhci, urb, eurb);
-				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {	/* inherit from parent */
-			urb->bandwidth = eurb->bandwidth;
-			ret = uhci_submit_interrupt(uhci, urb, eurb);
-		}
-		break;
-	case PIPE_BULK:
-		ret = uhci_submit_bulk(uhci, urb, eurb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		bustime = usb_check_bandwidth(urb->dev, urb);
-		if (bustime < 0) {
-			ret = bustime;
-			break;
-		}
-
-		ret = uhci_submit_isochronous(uhci, urb);
-		if (ret == -EINPROGRESS)
-			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-		break;
-	}
-
-	if (ret != -EINPROGRESS) {
-		/* Submit failed, so delete it from the urb_list */
-		struct urb_priv *urbp = urb->hcpriv;
-
-		list_del_init(&urbp->urb_list);
-		uhci_destroy_urb_priv(uhci, urb);
-	} else
-		ret = 0;
-
-out:
-	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
-	return ret;
-}
-
-/*
- * Return the result of a transfer
- */
-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
-{
-	int ret = -EINPROGRESS;
-	struct urb_priv *urbp;
-
-	spin_lock(&urb->lock);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->status != -EINPROGRESS)	/* URB already dequeued */
-		goto out;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_result_control(uhci, urb);
-		break;
-	case PIPE_BULK:
-	case PIPE_INTERRUPT:
-		ret = uhci_result_common(uhci, urb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = uhci_result_isochronous(uhci, urb);
-		break;
-	}
-
-	if (ret == -EINPROGRESS)
-		goto out;
-	urb->status = ret;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-	case PIPE_ISOCHRONOUS:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	case PIPE_INTERRUPT:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Make sure we don't release if we have a queued URB */
-		if (list_empty(&urbp->queue_list) && urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		else
-			/* bandwidth was passed on to queued URB, */
-			/* so don't let usb_unlink_urb() release it */
-			urb->bandwidth = 0;
-		uhci_unlink_generic(uhci, urb);
-		break;
-	default:
-		dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
-				"for urb %p\n",
-				__FUNCTION__, usb_pipetype(urb->pipe), urb);
-	}
-
-	/* Move it from uhci->urb_list to uhci->complete_list */
-	uhci_moveto_complete(uhci, urbp);
-
-out:
-	spin_unlock(&urb->lock);
-}
-
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct list_head *head;
-	struct uhci_td *td;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int prevactive = 0;
-
-	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
-
-	/*
-	 * Now we need to find out what the last successful toggle was
-	 * so we can update the local data toggle for the next transfer
-	 *
-	 * There are 2 ways the last successful completed TD is found:
-	 *
-	 * 1) The TD is NOT active and the actual length < expected length
-	 * 2) The TD is NOT active and it's the last TD in the chain
-	 *
-	 * and a third way the first uncompleted TD is found:
-	 *
-	 * 3) The TD is active and the previous TD is NOT active
-	 *
-	 * Control and Isochronous ignore the toggle, so this is safe
-	 * for all types
-	 *
-	 * FIXME: The toggle fixups won't be 100% reliable until we
-	 * change over to using a single queue for each endpoint and
-	 * stop the queue before unlinking.
-	 */
-	head = &urbp->td_list;
-	list_for_each_entry(td, head, list) {
-		unsigned int ctrlstat = td_status(td);
-
-		if (!(ctrlstat & TD_CTRL_ACTIVE) &&
-				(uhci_actual_length(ctrlstat) <
-				 uhci_expected_length(td_token(td)) ||
-				td->list.next == head))
-			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-				uhci_packetout(td_token(td)),
-				uhci_toggle(td_token(td)) ^ 1);
-		else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
-			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-				uhci_packetout(td_token(td)),
-				uhci_toggle(td_token(td)));
-
-		prevactive = ctrlstat & TD_CTRL_ACTIVE;
-	}
-
-	uhci_delete_queued_urb(uhci, urb);
-
-	/* The interrupt loop will reclaim the QH's */
-	uhci_remove_qh(uhci, urbp->qh);
-	urbp->qh = NULL;
-}
-
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	unsigned long flags;
-	struct urb_priv *urbp;
-	unsigned int age;
-
-	spin_lock_irqsave(&uhci->schedule_lock, flags);
-	urbp = urb->hcpriv;
-	if (!urbp)			/* URB was never linked! */
-		goto done;
-	list_del_init(&urbp->urb_list);
-
-	uhci_unlink_generic(uhci, urb);
-
-	age = uhci_get_current_frame_number(uhci);
-	if (age != uhci->urb_remove_age) {
-		uhci_remove_pending_urbps(uhci);
-		uhci->urb_remove_age = age;
-	}
-
-	/* If we're the first, set the next interrupt bit */
-	if (list_empty(&uhci->urb_remove_list))
-		uhci_set_next_interrupt(uhci);
-	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
-
-done:
-	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
-	return 0;
-}
-
-static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head;
-	struct uhci_td *td;
-	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;
-	list_for_each_entry(td, head, list) {
-		/*
-		 * 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 (td->list.next != head && (count % DEPTH_INTERVAL) ==
-				(DEPTH_INTERVAL - 1))
-			td->link |= UHCI_PTR_DEPTH;
-
-		count++;
-	}
-
-	return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci)
-{
-	return inw(uhci->io_addr + USBFRNUM);
-}
+#include "uhci-hub.c"
+#include "uhci-debug.c"
+#include "uhci-q.c"
 
 static int init_stall_timer(struct usb_hcd *hcd);
 
@@ -1538,15 +113,9 @@ static void stall_callback(unsigned long
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct urb_priv *up;
 	unsigned long flags;
-	int called_uhci_finish_completion = 0;
 
-	spin_lock_irqsave(&uhci->schedule_lock, flags);
-	if (!list_empty(&uhci->urb_remove_list) &&
-	    uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
-		uhci_remove_pending_urbps(uhci);
-		uhci_finish_completion(hcd, NULL);
-		called_uhci_finish_completion = 1;
-	}
+	spin_lock_irqsave(&uhci->lock, flags);
+	uhci_scan_schedule(uhci, NULL);
 
 	list_for_each_entry(up, &uhci->urb_list, urb_list) {
 		struct urb *u = up->urb;
@@ -1559,11 +128,6 @@ static void stall_callback(unsigned long
 
 		spin_unlock(&u->lock);
 	}
-	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
-
-	/* Wake up anyone waiting for an URB to complete */
-	if (called_uhci_finish_completion)
-		wake_up_all(&uhci->waitqh);
 
 	/* Really disable FSBR */
 	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
@@ -1574,9 +138,10 @@ static void stall_callback(unsigned long
 	/* Poll for and perform state transitions */
 	hc_state_transitions(uhci);
 	if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
-		uhci_check_resume(uhci);
+		uhci_check_ports(uhci);
 
 	init_stall_timer(hcd);
+	spin_unlock_irqrestore(&uhci->lock, flags);
 }
 
 static int init_stall_timer(struct usb_hcd *hcd)
@@ -1592,69 +157,11 @@ static int init_stall_timer(struct usb_h
 	return 0;
 }
 
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
-{
-	struct uhci_qh *qh, *tmp;
-
-	list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
-		list_del_init(&qh->remove_list);
-
-		uhci_free_qh(uhci, qh);
-	}
-}
-
-static void uhci_free_pending_tds(struct uhci_hcd *uhci)
-{
-	struct uhci_td *td, *tmp;
-
-	list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
-		list_del_init(&td->remove_list);
-
-		uhci_free_td(uhci, td);
-	}
-}
-
-static void
-uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
-__releases(uhci->schedule_lock)
-__acquires(uhci->schedule_lock)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
-	uhci_destroy_urb_priv(uhci, urb);
-
-	spin_unlock(&uhci->schedule_lock);
-	usb_hcd_giveback_urb(hcd, urb, regs);
-	spin_lock(&uhci->schedule_lock);
-}
-
-static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	struct urb_priv *urbp, *tmp;
-
-	list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
-		struct urb *urb = urbp->urb;
-
-		list_del_init(&urbp->urb_list);
-		uhci_finish_urb(hcd, urb, regs);
-	}
-}
-
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
-{
-
-	/* Splice the urb_remove_list onto the end of the complete_list */
-	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
-}
-
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long io_addr = uhci->io_addr;
 	unsigned short status;
-	struct urb_priv *urbp, *tmp;
-	unsigned int age;
 
 	/*
 	 * Read the interrupt status, and write it back to clear the
@@ -1683,37 +190,9 @@ static irqreturn_t uhci_irq(struct usb_h
 	if (status & USBSTS_RD)
 		uhci->resume_detect = 1;
 
-	spin_lock(&uhci->schedule_lock);
-
-	age = uhci_get_current_frame_number(uhci);
-	if (age != uhci->qh_remove_age)
-		uhci_free_pending_qhs(uhci);
-	if (age != uhci->td_remove_age)
-		uhci_free_pending_tds(uhci);
-	if (age != uhci->urb_remove_age)
-		uhci_remove_pending_urbps(uhci);
-
-	if (list_empty(&uhci->urb_remove_list) &&
-	    list_empty(&uhci->td_remove_list) &&
-	    list_empty(&uhci->qh_remove_list))
-		uhci_clear_next_interrupt(uhci);
-	else
-		uhci_set_next_interrupt(uhci);
-
-	/* Walk the list of pending URBs to see which ones completed
-	 * (must be _safe because uhci_transfer_result() dequeues URBs) */
-	list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
-		struct urb *urb = urbp->urb;
-
-		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(uhci, urb);
-	}
-	uhci_finish_completion(hcd, regs);
-
-	spin_unlock(&uhci->schedule_lock);
-
-	/* Wake up anyone waiting for an URB to complete */
-	wake_up_all(&uhci->waitqh);
+	spin_lock(&uhci->lock);
+	uhci_scan_schedule(uhci, regs);
+	spin_unlock(&uhci->lock);
 
 	return IRQ_HANDLED;
 }
@@ -1737,6 +216,7 @@ static void reset_hc(struct uhci_hcd *uh
 	/* Another 10ms delay */
 	msleep(10);
 	uhci->resume_detect = 0;
+	uhci->is_stopped = UHCI_IS_STOPPED;
 }
 
 static void suspend_hc(struct uhci_hcd *uhci)
@@ -1747,6 +227,12 @@ static void suspend_hc(struct uhci_hcd *
 	uhci->state = UHCI_SUSPENDED;
 	uhci->resume_detect = 0;
 	outw(USBCMD_EGSM, io_addr + USBCMD);
+
+	/* FIXME: Wait for the controller to actually stop */
+	uhci_get_current_frame_number(uhci);
+	uhci->is_stopped = UHCI_IS_STOPPED;
+
+	uhci_scan_schedule(uhci, NULL);
 }
 
 static void wakeup_hc(struct uhci_hcd *uhci)
@@ -1761,6 +247,7 @@ static void wakeup_hc(struct uhci_hcd *u
 			outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
 			uhci->state = UHCI_RESUMING_1;
 			uhci->state_end = jiffies + msecs_to_jiffies(20);
+			uhci->is_stopped = 0;
 			break;
 
 		case UHCI_RESUMING_1:		/* End global resume */
@@ -1866,6 +353,16 @@ static void hc_state_transitions(struct 
 	}
 }
 
+/*
+ * Store the current frame number in uhci->frame_number if the controller
+ * is runnning
+ */
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+{
+	if (!uhci->is_stopped)
+		uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
+}
+
 static int start_hc(struct uhci_hcd *uhci)
 {
 	unsigned long io_addr = uhci->io_addr;
@@ -1886,6 +383,9 @@ static int start_hc(struct uhci_hcd *uhc
 		msleep(1);
 	}
 
+	/* Mark controller as running before we enable interrupts */
+	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+
 	/* Turn on PIRQ and all interrupts */
 	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
 			USBLEGSUP_DEFAULT);
@@ -1900,13 +400,13 @@ static int start_hc(struct uhci_hcd *uhc
 	uhci->state = UHCI_RUNNING_GRACE;
 	uhci->state_end = jiffies + HZ;
 	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+	uhci->is_stopped = 0;
 
-        uhci_to_hcd(uhci)->state = USB_STATE_RUNNING;
 	return 0;
 }
 
 /*
- * De-allocate all resources..
+ * De-allocate all resources
  */
 static void release_uhci(struct uhci_hcd *uhci)
 {
@@ -1949,7 +449,7 @@ static int uhci_reset(struct usb_hcd *hc
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	uhci->io_addr = (unsigned long) hcd->regs;
+	uhci->io_addr = (unsigned long) hcd->rsrc_start;
 
 	/* Kick BIOS off this hardware and reset, so we won't get
 	 * interrupts from any previous setup.
@@ -1984,7 +484,7 @@ static int uhci_start(struct usb_hcd *hc
 	struct usb_device *udev;
 	struct dentry *dentry;
 
-	io_size = pci_resource_len(to_pci_dev(uhci_dev(uhci)), hcd->region);
+	io_size = (unsigned) hcd->rsrc_len;
 
 	dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
 	if (!dentry) {
@@ -1997,7 +497,7 @@ static int uhci_start(struct usb_hcd *hc
 	uhci->fsbr = 0;
 	uhci->fsbrtimeout = 0;
 
-	spin_lock_init(&uhci->schedule_lock);
+	spin_lock_init(&uhci->lock);
 	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
 	INIT_LIST_HEAD(&uhci->td_remove_list);
@@ -2151,7 +651,7 @@ static int uhci_start(struct usb_hcd *hc
 
 	udev->speed = USB_SPEED_FULL;
 
-	if (hcd_register_root(udev, hcd) != 0) {
+	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
 		dev_err(uhci_dev(uhci), "unable to start root hub\n");
 		retval = -ENOMEM;
 		goto err_start_root_hub;
@@ -2206,42 +706,33 @@ static void uhci_stop(struct usb_hcd *hc
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
 	del_timer_sync(&uhci->stall_timer);
-
-	/*
-	 * At this point, we're guaranteed that no new connects can be made
-	 * to this bus since there are no more parents
-	 */
-
 	reset_hc(uhci);
 
-	spin_lock_irq(&uhci->schedule_lock);
-	uhci_free_pending_qhs(uhci);
-	uhci_free_pending_tds(uhci);
-	uhci_remove_pending_urbps(uhci);
-	uhci_finish_completion(hcd, NULL);
-
-	uhci_free_pending_qhs(uhci);
-	uhci_free_pending_tds(uhci);
-	spin_unlock_irq(&uhci->schedule_lock);
-
-	/* Wake up anyone waiting for an URB to complete */
-	wake_up_all(&uhci->waitqh);
+	spin_lock_irq(&uhci->lock);
+	uhci_scan_schedule(uhci, NULL);
+	spin_unlock_irq(&uhci->lock);
 	
 	release_uhci(uhci);
 }
 
 #ifdef CONFIG_PM
-static int uhci_suspend(struct usb_hcd *hcd, u32 state)
+static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
+	spin_lock_irq(&uhci->lock);
+
 	/* Don't try to suspend broken motherboards, reset instead */
-	if (suspend_allowed(uhci)) {
+	if (suspend_allowed(uhci))
 		suspend_hc(uhci);
-		uhci->saved_framenumber =
-				inw(uhci->io_addr + USBFRNUM) & 0x3ff;
-	} else
+	else {
+		spin_unlock_irq(&uhci->lock);
 		reset_hc(uhci);
+		spin_lock_irq(&uhci->lock);
+		uhci_scan_schedule(uhci, NULL);
+	}
+
+	spin_unlock_irq(&uhci->lock);
 	return 0;
 }
 
@@ -2252,6 +743,8 @@ static int uhci_resume(struct usb_hcd *h
 
 	pci_set_master(to_pci_dev(uhci_dev(uhci)));
 
+	spin_lock_irq(&uhci->lock);
+
 	if (uhci->state == UHCI_SUSPENDED) {
 
 		/*
@@ -2262,7 +755,7 @@ static int uhci_resume(struct usb_hcd *h
 		 */
 		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
 				0);
-		outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
+		outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
 		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
 		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
 				USBINTR_SP, uhci->io_addr + USBINTR);
@@ -2270,11 +763,15 @@ static int uhci_resume(struct usb_hcd *h
 		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
 				USBLEGSUP_DEFAULT);
 	} else {
+		spin_unlock_irq(&uhci->lock);
 		reset_hc(uhci);
 		if ((rc = start_hc(uhci)) != 0)
 			return rc;
+		spin_lock_irq(&uhci->lock);
 	}
-	hcd->state = USB_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
+
+	spin_unlock_irq(&uhci->lock);
 	return 0;
 }
 #endif
@@ -2290,7 +787,17 @@ static void uhci_hcd_endpoint_disable(st
 
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 {
-	return uhci_get_current_frame_number(hcd_to_uhci(hcd));
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int frame_number;
+	unsigned long flags;
+
+	/* Minimize latency by avoiding the spinlock */
+	local_irq_save(flags);
+	rmb();
+	frame_number = (uhci->is_stopped ? uhci->frame_number :
+			inw(uhci->io_addr + USBFRNUM));
+	local_irq_restore(flags);
+	return frame_number;
 }
 
 static const char hcd_name[] = "uhci_hcd";
@@ -2383,8 +890,7 @@ up_failed:
 	debugfs_remove(uhci_debugfs_root);
 
 debug_failed:
-	if (errbuf)
-		kfree(errbuf);
+	kfree(errbuf);
 
 errbuf_failed:
 
@@ -2399,9 +905,7 @@ static void __exit uhci_hcd_cleanup(void
 		warn("not all urb_priv's were freed!");
 
 	debugfs_remove(uhci_debugfs_root);
-
-	if (errbuf)
-		kfree(errbuf);
+	kfree(errbuf);
 }
 
 module_init(uhci_hcd_init);
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -358,39 +358,44 @@ struct uhci_hcd {
 	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
-	spinlock_t schedule_lock;
-	struct uhci_frame_list *fl;		/* P: uhci->schedule_lock */
+	spinlock_t lock;
+	struct uhci_frame_list *fl;		/* P: uhci->lock */
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
 	enum uhci_state state;			/* FIXME: needs a spinlock */
 	unsigned long state_end;		/* Time of next transition */
-	int resume_detect;			/* Need a Global Resume */
-	unsigned int saved_framenumber;		/* Save during PM suspend */
+	unsigned int frame_number;		/* As of last check */
+	unsigned int is_stopped;
+#define UHCI_IS_STOPPED		9999		/* Larger than a frame # */
+
+	unsigned int scan_in_progress:1;	/* Schedule scan is running */
+	unsigned int need_rescan:1;		/* Redo the schedule scan */
+	unsigned int resume_detect:1;		/* Need a Global Resume */
 
-	/* Support for port suspend/resume */
+	/* Support for port suspend/resume/reset */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
 	unsigned long suspended_ports;
 	unsigned long resuming_ports;
-	unsigned long resume_timeout;		/* Time to stop signalling */
+	unsigned long ports_timeout;		/* Time to stop signalling */
 
 	/* Main list of URB's currently controlled by this HC */
-	struct list_head urb_list;		/* P: uhci->schedule_lock */
+	struct list_head urb_list;		/* P: uhci->lock */
 
 	/* List of QH's that are done, but waiting to be unlinked (race) */
-	struct list_head qh_remove_list;	/* P: uhci->schedule_lock */
+	struct list_head qh_remove_list;	/* P: uhci->lock */
 	unsigned int qh_remove_age;		/* Age in frames */
 
 	/* List of TD's that are done, but waiting to be freed (race) */
-	struct list_head td_remove_list;	/* P: uhci->schedule_lock */
+	struct list_head td_remove_list;	/* P: uhci->lock */
 	unsigned int td_remove_age;		/* Age in frames */
 
 	/* List of asynchronously unlinked URB's */
-	struct list_head urb_remove_list;	/* P: uhci->schedule_lock */
+	struct list_head urb_remove_list;	/* P: uhci->lock */
 	unsigned int urb_remove_age;		/* Age in frames */
 
 	/* List of URB's awaiting completion callback */
-	struct list_head complete_list;		/* P: uhci->schedule_lock */
+	struct list_head complete_list;		/* P: uhci->lock */
 
 	int rh_numports;
 
@@ -436,13 +441,13 @@ struct urb_priv {
  * Locking in uhci.c
  *
  * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->schedule_lock.  urb->status is protected
- * by urb->lock; that's the one exception.
+ * of URBs is protected by uhci->lock.  urb->status is protected by
+ * urb->lock; that's the one exception.
  *
- * To prevent deadlocks, never lock uhci->schedule_lock while holding
- * urb->lock.  The safe order of locking is:
+ * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
+ * The safe order of locking is:
  *
- * #1 uhci->schedule_lock
+ * #1 uhci->lock
  * #2 urb->lock
  */
 
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -66,7 +66,6 @@ static int uhci_hub_status_data(struct u
 
 /* UHCI controllers don't automatically stop resume signalling after 20 msec,
  * so we have to poll and check timeouts in order to take care of it.
- * FIXME:  Synchronize access to these fields by a spinlock.
  */
 static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
 		unsigned long port_addr)
@@ -87,22 +86,37 @@ static void uhci_finish_suspend(struct u
 	}
 }
 
-static void uhci_check_resume(struct uhci_hcd *uhci)
+static void uhci_check_ports(struct uhci_hcd *uhci)
 {
 	unsigned int port;
 	unsigned long port_addr;
+	int status;
 
 	for (port = 0; port < uhci->rh_numports; ++port) {
 		port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
-		if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
+		status = inw(port_addr);
+		if (unlikely(status & USBPORTSC_PR)) {
+			if (time_after_eq(jiffies, uhci->ports_timeout)) {
+				CLR_RH_PORTSTAT(USBPORTSC_PR);
+				udelay(10);
+
+				/* If the port was enabled before, turning
+				 * reset on caused a port enable change.
+				 * Turning reset off causes a port connect
+				 * status change.  Clear these changes. */
+				CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
+				SET_RH_PORTSTAT(USBPORTSC_PE);
+			}
+		}
+		if (unlikely(status & USBPORTSC_RD)) {
 			if (!test_bit(port, &uhci->resuming_ports)) {
 
 				/* Port received a wakeup request */
 				set_bit(port, &uhci->resuming_ports);
-				uhci->resume_timeout = jiffies +
+				uhci->ports_timeout = jiffies +
 						msecs_to_jiffies(20);
 			} else if (time_after_eq(jiffies,
-						uhci->resume_timeout)) {
+						uhci->ports_timeout)) {
 				uhci_finish_suspend(uhci, port, port_addr);
 			}
 		}
@@ -118,7 +132,9 @@ static int uhci_hub_control(struct usb_h
 	unsigned int port = wIndex - 1;
 	unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
 	u16 wPortChange, wPortStatus;
+	unsigned long flags;
 
+	spin_lock_irqsave(&uhci->lock, flags);
 	switch (typeReq) {
 
 	case GetHubStatus:
@@ -128,9 +144,7 @@ static int uhci_hub_control(struct usb_h
 		if (port >= uhci->rh_numports)
 			goto err;
 
-		if (uhci->resuming_ports)
-			uhci_check_resume(uhci);
-
+		uhci_check_ports(uhci);
 		status = inw(port_addr);
 
 		/* Intel controllers report the OverCurrent bit active on.
@@ -203,15 +217,12 @@ static int uhci_hub_control(struct usb_h
 			OK(0);
 		case USB_PORT_FEAT_RESET:
 			SET_RH_PORTSTAT(USBPORTSC_PR);
-			mdelay(50);	/* USB v1.1 7.1.7.3 */
-			CLR_RH_PORTSTAT(USBPORTSC_PR);
-			udelay(10);
 
 			/* Reset terminates Resume signalling */
 			uhci_finish_suspend(uhci, port, port_addr);
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			mdelay(10);
-			CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
+
+			/* USB v2.0 7.1.7.5 */
+			uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
 			OK(0);
 		case USB_PORT_FEAT_POWER:
 			/* UHCI has no power switching */
@@ -238,8 +249,6 @@ static int uhci_hub_control(struct usb_h
 			if (test_bit(port, &uhci->suspended_ports) &&
 					!test_and_set_bit(port,
 						&uhci->resuming_ports)) {
-				uhci->resume_timeout = jiffies +
-						msecs_to_jiffies(20);
 				SET_RH_PORTSTAT(USBPORTSC_RD);
 
 				/* The controller won't allow RD to be set
@@ -249,6 +258,10 @@ static int uhci_hub_control(struct usb_h
 				if (!(inw(port_addr) & USBPORTSC_RD))
 					uhci_finish_suspend(uhci, port,
 							port_addr);
+				else
+					/* USB v2.0 7.1.7.7 */
+					uhci->ports_timeout = jiffies +
+						msecs_to_jiffies(20);
 			}
 			OK(0);
 		case USB_PORT_FEAT_C_SUSPEND:
@@ -280,6 +293,7 @@ static int uhci_hub_control(struct usb_h
 err:
 		retval = -EPIPE;
 	}
+	spin_unlock_irqrestore(&uhci->lock, flags);
 
 	return retval;
 }
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/host/uhci-q.c
@@ -0,0 +1,1539 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ */
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+static void uhci_free_pending_tds(struct uhci_hcd *uhci);
+
+/*
+ * 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 spurious 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_hcd *uhci)
+{
+	uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
+}
+
+static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
+{
+	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
+}
+
+static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
+					struct urb_priv *urbp)
+{
+	list_move_tail(&urbp->urb_list, &uhci->complete_list);
+}
+
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_td *td;
+
+	td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
+	if (!td)
+		return NULL;
+
+	td->dma_handle = dma_handle;
+
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
+
+	td->frame = -1;
+	td->dev = dev;
+
+	INIT_LIST_HEAD(&td->list);
+	INIT_LIST_HEAD(&td->remove_list);
+	INIT_LIST_HEAD(&td->fl_list);
+
+	usb_get_dev(dev);
+
+	return td;
+}
+
+static inline void uhci_fill_td(struct uhci_td *td, u32 status,
+		u32 token, u32 buffer)
+{
+	td->status = cpu_to_le32(status);
+	td->token = cpu_to_le32(token);
+	td->buffer = cpu_to_le32(buffer);
+}
+
+/*
+ * We insert Isochronous URB's directly into the frame list at the beginning
+ */
+static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+{
+	framenum &= (UHCI_NUMFRAMES - 1);
+
+	td->frame = framenum;
+
+	/* Is there a TD already mapped there? */
+	if (uhci->fl->frame_cpu[framenum]) {
+		struct uhci_td *ftd, *ltd;
+
+		ftd = uhci->fl->frame_cpu[framenum];
+		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+
+		list_add_tail(&td->fl_list, &ftd->fl_list);
+
+		td->link = ltd->link;
+		wmb();
+		ltd->link = cpu_to_le32(td->dma_handle);
+	} else {
+		td->link = uhci->fl->frame[framenum];
+		wmb();
+		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
+		uhci->fl->frame_cpu[framenum] = td;
+	}
+}
+
+static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+	/* If it's not inserted, don't remove it */
+	if (td->frame == -1 && list_empty(&td->fl_list))
+		return;
+
+	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+		if (list_empty(&td->fl_list)) {
+			uhci->fl->frame[td->frame] = td->link;
+			uhci->fl->frame_cpu[td->frame] = NULL;
+		} else {
+			struct uhci_td *ntd;
+
+			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+			uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+			uhci->fl->frame_cpu[td->frame] = ntd;
+		}
+	} else {
+		struct uhci_td *ptd;
+
+		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
+		ptd->link = td->link;
+	}
+
+	wmb();
+	td->link = UHCI_PTR_TERM;
+
+	list_del_init(&td->fl_list);
+	td->frame = -1;
+}
+
+/*
+ * Inserts a td list into qh.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	__le32 *plink;
+
+	/* Ordering isn't important here yet since the QH hasn't been */
+	/* inserted into the schedule yet */
+	plink = &qh->element;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		*plink = cpu_to_le32(td->dma_handle) | breadth;
+		plink = &td->link;
+	}
+	*plink = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+	if (!list_empty(&td->list))
+		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+	if (!list_empty(&td->remove_list))
+		dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+	if (!list_empty(&td->fl_list))
+		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+
+	if (td->dev)
+		usb_put_dev(td->dev);
+
+	dma_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_qh *qh;
+
+	qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
+	if (!qh)
+		return NULL;
+
+	qh->dma_handle = dma_handle;
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
+
+	qh->dev = dev;
+	qh->urbp = NULL;
+
+	INIT_LIST_HEAD(&qh->list);
+	INIT_LIST_HEAD(&qh->remove_list);
+
+	usb_get_dev(dev);
+
+	return qh;
+}
+
+static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	if (!list_empty(&qh->list))
+		dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
+	if (!list_empty(&qh->remove_list))
+		dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
+
+	if (qh->dev)
+		usb_put_dev(qh->dev);
+
+	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+}
+
+/*
+ * Append this urb's qh after the last qh in skelqh->list
+ *
+ * Note that urb_priv.queue_list doesn't have a separate queue head;
+ * it's a ring with every element "live".
+ */
+static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct urb_priv *turbp;
+	struct uhci_qh *lqh;
+
+	/* Grab the last QH */
+	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+
+	/* Point to the next skelqh */
+	urbp->qh->link = lqh->link;
+	wmb();				/* Ordering is important */
+
+	/*
+	 * Patch QHs for previous endpoint's queued URBs?  HC goes
+	 * here next, not to the next skelqh it now points to.
+	 *
+	 *    lqh --> td ... --> qh ... --> td --> qh ... --> td
+	 *     |                 |                 |
+	 *     v                 v                 v
+	 *     +<----------------+-----------------+
+	 *     v
+	 *    newqh --> td ... --> td
+	 *     |
+	 *     v
+	 *    ...
+	 *
+	 * The HC could see (and use!) any of these as we write them.
+	 */
+	lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+	if (lqh->urbp) {
+		list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
+			turbp->qh->link = lqh->link;
+	}
+
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+/*
+ * Start removal of QH from schedule; it finishes next frame.
+ * TDs should be unlinked before this is called.
+ */
+static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	struct uhci_qh *pqh;
+	__le32 newlink;
+
+	if (!qh)
+		return;
+
+	/*
+	 * Only go through the hoops if it's actually linked in
+	 */
+	if (!list_empty(&qh->list)) {
+
+		/* If our queue is nonempty, make the next URB the head */
+		if (!list_empty(&qh->urbp->queue_list)) {
+			struct urb_priv *nurbp;
+
+			nurbp = list_entry(qh->urbp->queue_list.next,
+					struct urb_priv, queue_list);
+			nurbp->queued = 0;
+			list_add(&nurbp->qh->list, &qh->list);
+			newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+		} else
+			newlink = qh->link;
+
+		/* Fix up the previous QH's queue to link to either
+		 * the new head of this queue or the start of the
+		 * next endpoint's queue. */
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+		pqh->link = newlink;
+		if (pqh->urbp) {
+			struct urb_priv *turbp;
+
+			list_for_each_entry(turbp, &pqh->urbp->queue_list,
+					queue_list)
+				turbp->qh->link = newlink;
+		}
+		wmb();
+
+		/* Leave qh->link in case the HC is on the QH now, it will */
+		/* continue the rest of the schedule */
+		qh->element = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+	}
+
+	list_del_init(&qh->urbp->queue_list);
+	qh->urbp = NULL;
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
+		uhci_free_pending_qhs(uhci);
+		uhci->qh_remove_age = uhci->frame_number;
+	}
+
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the QH */
+	if (list_empty(&uhci->qh_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_add(&qh->remove_list, &uhci->qh_remove_list);
+}
+
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	list_for_each_entry(td, &urbp->td_list, list) {
+		if (toggle)
+			td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
+		else
+			td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
+
+		toggle ^= 1;
+	}
+
+	return toggle;
+}
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* queuing interrupt, control or bulk transfers */
+static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct uhci_td *lltd;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	/* Find the first URB in the queue */
+	furbp = eurbp;
+	if (eurbp->queued) {
+		list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
+			if (!furbp->queued)
+				break;
+	}
+
+	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+
+	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+
+	/* Control transfers always start with toggle 0 */
+	if (!usb_pipecontrol(urb->pipe))
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe),
+				uhci_fixup_toggle(urb,
+					uhci_toggle(td_token(lltd)) ^ 1));
+
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
+	wmb();			/* Make sure we flush everything */
+
+	lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->queue_list, &furbp->queue_list);
+
+	urbp->queued = 1;
+}
+
+static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp, *nurbp, *purbp, *turbp;
+	struct uhci_td *pltd;
+	unsigned int toggle;
+
+	urbp = urb->hcpriv;
+
+	if (list_empty(&urbp->queue_list))
+		return;
+
+	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+	/*
+	 * Fix up the toggle for the following URBs in the queue.
+	 * Only needed for bulk and interrupt: control and isochronous
+	 * endpoints don't propagate toggles between messages.
+	 */
+	if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
+		if (!urbp->queued)
+			/* We just set the toggle in uhci_unlink_generic */
+			toggle = usb_gettoggle(urb->dev,
+					usb_pipeendpoint(urb->pipe),
+					usb_pipeout(urb->pipe));
+		else {
+			/* If we're in the middle of the queue, grab the */
+			/* toggle from the TD previous to us */
+			purbp = list_entry(urbp->queue_list.prev,
+					struct urb_priv, queue_list);
+			pltd = list_entry(purbp->td_list.prev,
+					struct uhci_td, list);
+			toggle = uhci_toggle(td_token(pltd)) ^ 1;
+		}
+
+		list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
+			if (!turbp->queued)
+				break;
+			toggle = uhci_fixup_toggle(turbp->urb, toggle);
+		}
+
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe), toggle);
+	}
+
+	if (urbp->queued) {
+		/* We're somewhere in the middle (or end).  The case where
+		 * we're at the head is handled in uhci_remove_qh(). */
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+		if (nurbp->queued)
+			pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+		else
+			/* The next URB happens to be the beginning, so */
+			/*  we're the last, end the chain */
+			pltd->link = UHCI_PTR_TERM;
+	}
+
+	/* urbp->queue_list is handled in uhci_remove_qh() */
+}
+
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp;
+
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
+	if (!urbp)
+		return NULL;
+
+	memset((void *)urbp, 0, sizeof(*urbp));
+
+	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
+	urbp->urb = urb;
+	
+	INIT_LIST_HEAD(&urbp->td_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->urb_list);
+
+	list_add_tail(&urbp->urb_list, &uhci->urb_list);
+
+	urb->hcpriv = urbp;
+
+	return urbp;
+}
+
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	td->urb = urb;
+
+	list_add_tail(&td->list, &urbp->td_list);
+}
+
+static void uhci_remove_td_from_urb(struct uhci_td *td)
+{
+	if (list_empty(&td->list))
+		return;
+
+	list_del_init(&td->list);
+
+	td->urb = NULL;
+}
+
+static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td, *tmp;
+	struct urb_priv *urbp;
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp)
+		return;
+
+	if (!list_empty(&urbp->urb_list))
+		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
+				"or uhci->remove_list!\n", urb);
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
+		uhci_free_pending_tds(uhci);
+		uhci->td_remove_age = uhci->frame_number;
+	}
+
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the TD's*/
+	if (list_empty(&uhci->td_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		list_add(&td->remove_list, &uhci->td_remove_list);
+	}
+
+	urb->hcpriv = NULL;
+	kmem_cache_free(uhci_up_cachep, urbp);
+}
+
+static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
+		urbp->fsbr = 1;
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
+			uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+	}
+}
+
+static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
+		urbp->fsbr = 0;
+		if (!--uhci->fsbr)
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
+	}
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td_status(td) & 0xF60000), a.k.a.
+ * uhci_status_bits(td_status(td)).
+ * Note: <status> does not include the TD_CTRL_NAK bit.
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
+		if (dir_out)
+			return -EPROTO;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_BABBLE)			/* Babble */
+		return -EOVERFLOW;
+	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)			/* Stalled */
+		return -EPIPE;
+	WARN_ON(status & TD_CTRL_ACTIVE);		/* Active */
+	return 0;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	struct uhci_qh *qh, *skelqh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	dma_addr_t data = urb->transfer_dma;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
+
+	/*
+	 * Build the TD for the control request setup packet
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | uhci_explen(7),
+		urb->setup_dma);
+
+	/*
+	 * If direction is "send", change the packet ID from SETUP (0x2D)
+	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
+	 * set Short Packet Detect (SPD) for all data packets.
+	 */
+	if (usb_pipeout(urb->pipe))
+		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
+	else {
+		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
+		status |= TD_CTRL_SPD;
+	}
+
+	/*
+	 * Build the DATA TD's
+	 */
+	while (len > 0) {
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		/* Alternate Data0/1 (start with Data1) */
+		destination ^= TD_TOKEN_TOGGLE;
+	
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
+			data);
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/*
+	 * Build the final TD for control status 
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	/*
+	 * It's IN if the pipe is an output pipe or we're not expecting
+	 * data back.
+	 */
+	destination &= ~TD_TOKEN_PID_MASK;
+	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
+
+	status &= ~TD_CTRL_SPD;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status | TD_CTRL_IOC,
+		destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+	/* Low-speed transfers get a different queue, and won't hog the bus.
+	 * Also, some devices enumerate better without FSBR; the easiest way
+	 * to do that is to put URBs on the low-speed queue while the device
+	 * is in the DEFAULT state. */
+	if (urb->dev->speed == USB_SPEED_LOW ||
+			urb->dev->state == USB_STATE_DEFAULT)
+		skelqh = uhci->skel_ls_control_qh;
+	else {
+		skelqh = uhci->skel_fs_control_qh;
+		uhci_inc_fsbr(uhci, urb);
+	}
+
+	if (eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, skelqh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * If control-IN transfer was short, the status packet wasn't sent.
+ * This routine changes the element pointer in the QH to point at the
+ * status TD.  It's safe to do this even while the QH is live, because
+ * the hardware only updates the element pointer following a successful
+ * transfer.  The inactive TD for the short packet won't cause an update,
+ * so the pointer won't get overwritten.  The next time the controller
+ * sees this QH, it will send the status packet.
+ */
+static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	urbp->short_control_packet = 1;
+
+	td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+	urbp->qh->element = cpu_to_le32(td->dma_handle);
+
+	return -EINPROGRESS;
+}
+
+
+static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	if (list_empty(&urbp->td_list))
+		return -EINVAL;
+
+	head = &urbp->td_list;
+
+	if (urbp->short_control_packet) {
+		tmp = head->prev;
+		goto status_stage;
+	}
+
+	tmp = head->next;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* The first TD is the SETUP stage, check the status, but skip */
+	/*  the count */
+	status = uhci_status_bits(td_status(td));
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	tmp = tmp->next;
+	while (tmp != head && tmp->next != head) {
+		unsigned int ctrlstat;
+
+		td = list_entry(tmp, struct uhci_td, list);
+		tmp = tmp->next;
+
+		ctrlstat = td_status(td);
+		status = uhci_status_bits(ctrlstat);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(ctrlstat);
+
+		if (status)
+			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(ctrlstat) <
+				uhci_expected_length(td_token(td))) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td_token(td)) == USB_PID_IN)
+				return usb_control_retrigger_status(uhci, urb);
+			else
+				return 0;
+		}
+	}
+
+status_stage:
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Control status stage */
+	status = td_status(td);
+
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
+	/* APC BackUPS Pro kludge */
+	/* It tries to send all of the descriptor instead of the amount */
+	/*  we requested */
+	if (status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		return 0;
+#endif
+
+	status = uhci_status_bits(status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+				__FUNCTION__, status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Common submit for bulk and interrupt
+ */
+static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	dma_addr_t data = urb->transfer_dma;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
+	if (usb_pipein(urb->pipe))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	do {	/* Allow zero length packets */
+		int pktsze = maxsze;
+
+		if (pktsze >= len) {
+			pktsze = len;
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+				status &= ~TD_CTRL_SPD;
+		}
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		data += pktsze;
+		len -= maxsze;
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	} while (len > 0);
+
+	/*
+	 * URB_ZERO_PACKET means adding a 0-length packet, if direction
+	 * is OUT and the transfer_length was an exact multiple of maxsze,
+	 * hence (len = transfer_length - N * maxsze) == 0
+	 * however, if transfer_length == 0, the zero packet was already
+	 * prepared above.
+	 */
+	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
+	    !len && urb->transfer_buffer_length) {
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	}
+
+	/* Set the interrupt-on-completion flag on the last packet.
+	 * A more-or-less typical 4 KB URB (= size of one memory page)
+	 * will require about 3 ms to transfer; that's a little on the
+	 * fast side but not enough to justify delaying an interrupt
+	 * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
+	 * flag setting. */
+	td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Always breadth first */
+	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+	if (eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, skelqh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * Common result for bulk and interrupt
+ */
+static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status = 0;
+	int ret = 0;
+
+	urb->actual_length = 0;
+
+	list_for_each_entry(td, &urbp->td_list, list) {
+		unsigned int ctrlstat = td_status(td);
+
+		status = uhci_status_bits(ctrlstat);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(ctrlstat);
+
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(ctrlstat) <
+				uhci_expected_length(td_token(td))) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
+		}
+	}
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+	/* 
+	 * Enable this chunk of code if you want to see some more debugging.
+	 * But be careful, it has the tendancy to starve out khubd and prevent
+	 * disconnects from happening successfully if you have a slow debug
+	 * log interface (like a serial console.
+	 */
+#if 0
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+				__FUNCTION__, status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+#endif
+	return ret;
+}
+
+static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	int ret;
+
+	/* Can't have low-speed bulk transfers */
+	if (urb->dev->speed == USB_SPEED_LOW)
+		return -EINVAL;
+
+	ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
+	if (ret == -EINPROGRESS)
+		uhci_inc_fsbr(uhci, urb);
+
+	return ret;
+}
+
+static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	/* USB 1.1 interrupt transfers only involve one packet per interval;
+	 * that's the uhci_submit_common() "breadth first" policy.  Drivers
+	 * can submit urbs of any length, but longer ones might need many
+	 * intervals to complete.
+	 */
+	return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
+}
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *last_urb = NULL;
+	struct urb_priv *up;
+	int ret = 0;
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		/* look for pending URB's with identical pipe handle */
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+		    (u->status == -EINPROGRESS) && (u != urb)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets *
+				last_urb->interval) & (UHCI_NUMFRAMES-1);
+		ret = 0;
+	} else
+		ret = -1;	/* no previous urb found */
+
+	return ret;
+}
+
+static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
+{
+	int limits;
+	unsigned int start = 0, end = 0;
+
+	if (urb->number_of_packets > 900)	/* 900? Why? */
+		return -EFBIG;
+
+	limits = isochronous_find_limits(uhci, urb, &start, &end);
+
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		if (limits) {
+			uhci_get_current_frame_number(uhci);
+			urb->start_frame = (uhci->frame_number + 10)
+					& (UHCI_NUMFRAMES - 1);
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame &= (UHCI_NUMFRAMES - 1);
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+/*
+ * Isochronous transfers
+ */
+static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td;
+	int i, ret, frame;
+	int status, destination;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(uhci, urb);
+	if (ret)
+		return ret;
+
+	frame = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
+		if (!urb->iso_frame_desc[i].length)
+			continue;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
+			urb->transfer_dma + urb->iso_frame_desc[i].offset);
+
+		if (i + 1 >= urb->number_of_packets)
+			td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+		uhci_insert_td_frame_list(uhci, td, frame);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int status;
+	int i, ret = 0;
+
+	urb->actual_length = 0;
+
+	i = 0;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		int actlength;
+		unsigned int ctrlstat = td_status(td);
+
+		if (ctrlstat & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		actlength = uhci_actual_length(ctrlstat);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(ctrlstat),
+				usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status) {
+			urb->error_count++;
+			ret = status;
+		}
+
+		i++;
+	}
+
+	return ret;
+}
+
+static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *up;
+
+	/* We don't match Isoc transfers since they are special */
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		if (u->dev == urb->dev && u->status == -EINPROGRESS) {
+			/* For control, ignore the direction */
+			if (usb_pipecontrol(urb->pipe) &&
+			    (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
+				return u;
+			else if (u->pipe == urb->pipe)
+				return u;
+		}
+	}
+
+	return NULL;
+}
+
+static int uhci_urb_enqueue(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep,
+		struct urb *urb, int mem_flags)
+{
+	int ret;
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
+	struct urb *eurb;
+	int bustime;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+
+	ret = urb->status;
+	if (ret != -EINPROGRESS)		/* URB already unlinked! */
+		goto out;
+
+	eurb = uhci_find_urb_ep(uhci, urb);
+
+	if (!uhci_alloc_urb_priv(uhci, urb)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(uhci, urb, eurb);
+		break;
+	case PIPE_INTERRUPT:
+		if (!eurb) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0)
+				ret = bustime;
+			else {
+				ret = uhci_submit_interrupt(uhci, urb, eurb);
+				if (ret == -EINPROGRESS)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {	/* inherit from parent */
+			urb->bandwidth = eurb->bandwidth;
+			ret = uhci_submit_interrupt(uhci, urb, eurb);
+		}
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(uhci, urb, eurb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		bustime = usb_check_bandwidth(urb->dev, urb);
+		if (bustime < 0) {
+			ret = bustime;
+			break;
+		}
+
+		ret = uhci_submit_isochronous(uhci, urb);
+		if (ret == -EINPROGRESS)
+			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+		break;
+	}
+
+	if (ret != -EINPROGRESS) {
+		/* Submit failed, so delete it from the urb_list */
+		struct urb_priv *urbp = urb->hcpriv;
+
+		list_del_init(&urbp->urb_list);
+		uhci_destroy_urb_priv(uhci, urb);
+	} else
+		ret = 0;
+
+out:
+	spin_unlock_irqrestore(&uhci->lock, flags);
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ */
+static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
+{
+	int ret = -EINPROGRESS;
+	struct urb_priv *urbp;
+
+	spin_lock(&urb->lock);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->status != -EINPROGRESS)	/* URB already dequeued */
+		goto out;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(uhci, urb);
+		break;
+	case PIPE_BULK:
+	case PIPE_INTERRUPT:
+		ret = uhci_result_common(uhci, urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(uhci, urb);
+		break;
+	}
+
+	if (ret == -EINPROGRESS)
+		goto out;
+	urb->status = ret;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+	case PIPE_ISOCHRONOUS:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 1);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Make sure we don't release if we have a queued URB */
+		if (list_empty(&urbp->queue_list) && urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 0);
+		else
+			/* bandwidth was passed on to queued URB, */
+			/* so don't let usb_unlink_urb() release it */
+			urb->bandwidth = 0;
+		uhci_unlink_generic(uhci, urb);
+		break;
+	default:
+		dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
+				"for urb %p\n",
+				__FUNCTION__, usb_pipetype(urb->pipe), urb);
+	}
+
+	/* Move it from uhci->urb_list to uhci->complete_list */
+	uhci_moveto_complete(uhci, urbp);
+
+out:
+	spin_unlock(&urb->lock);
+}
+
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct list_head *head;
+	struct uhci_td *td;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int prevactive = 0;
+
+	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
+
+	/*
+	 * Now we need to find out what the last successful toggle was
+	 * so we can update the local data toggle for the next transfer
+	 *
+	 * There are 2 ways the last successful completed TD is found:
+	 *
+	 * 1) The TD is NOT active and the actual length < expected length
+	 * 2) The TD is NOT active and it's the last TD in the chain
+	 *
+	 * and a third way the first uncompleted TD is found:
+	 *
+	 * 3) The TD is active and the previous TD is NOT active
+	 *
+	 * Control and Isochronous ignore the toggle, so this is safe
+	 * for all types
+	 *
+	 * FIXME: The toggle fixups won't be 100% reliable until we
+	 * change over to using a single queue for each endpoint and
+	 * stop the queue before unlinking.
+	 */
+	head = &urbp->td_list;
+	list_for_each_entry(td, head, list) {
+		unsigned int ctrlstat = td_status(td);
+
+		if (!(ctrlstat & TD_CTRL_ACTIVE) &&
+				(uhci_actual_length(ctrlstat) <
+				 uhci_expected_length(td_token(td)) ||
+				td->list.next == head))
+			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+				uhci_packetout(td_token(td)),
+				uhci_toggle(td_token(td)) ^ 1);
+		else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
+			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+				uhci_packetout(td_token(td)),
+				uhci_toggle(td_token(td)));
+
+		prevactive = ctrlstat & TD_CTRL_ACTIVE;
+	}
+
+	uhci_delete_queued_urb(uhci, urb);
+
+	/* The interrupt loop will reclaim the QH's */
+	uhci_remove_qh(uhci, urbp->qh);
+	urbp->qh = NULL;
+}
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
+	struct urb_priv *urbp;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+	urbp = urb->hcpriv;
+	if (!urbp)			/* URB was never linked! */
+		goto done;
+	list_del_init(&urbp->urb_list);
+
+	uhci_unlink_generic(uhci, urb);
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
+		uhci_remove_pending_urbps(uhci);
+		uhci->urb_remove_age = uhci->frame_number;
+	}
+
+	/* If we're the first, set the next interrupt bit */
+	if (list_empty(&uhci->urb_remove_list))
+		uhci_set_next_interrupt(uhci);
+	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
+
+done:
+	spin_unlock_irqrestore(&uhci->lock, flags);
+	return 0;
+}
+
+static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head;
+	struct uhci_td *td;
+	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;
+	list_for_each_entry(td, head, list) {
+		/*
+		 * 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 (td->list.next != head && (count % DEPTH_INTERVAL) ==
+				(DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
+	}
+
+	return 0;
+}
+
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
+{
+	struct uhci_qh *qh, *tmp;
+
+	list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
+		list_del_init(&qh->remove_list);
+
+		uhci_free_qh(uhci, qh);
+	}
+}
+
+static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+{
+	struct uhci_td *td, *tmp;
+
+	list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
+		list_del_init(&td->remove_list);
+
+		uhci_free_td(uhci, td);
+	}
+}
+
+static void
+uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+__releases(uhci->lock)
+__acquires(uhci->lock)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	uhci_destroy_urb_priv(uhci, urb);
+
+	spin_unlock(&uhci->lock);
+	usb_hcd_giveback_urb(hcd, urb, regs);
+	spin_lock(&uhci->lock);
+}
+
+static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs)
+{
+	struct urb_priv *urbp, *tmp;
+
+	list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
+		struct urb *urb = urbp->urb;
+
+		list_del_init(&urbp->urb_list);
+		uhci_finish_urb(uhci_to_hcd(uhci), urb, regs);
+	}
+}
+
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
+{
+
+	/* Splice the urb_remove_list onto the end of the complete_list */
+	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
+}
+
+/* Process events in the schedule, but only in one thread at a time */
+static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+{
+	struct urb_priv *urbp, *tmp;
+
+	/* Don't allow re-entrant calls */
+	if (uhci->scan_in_progress) {
+		uhci->need_rescan = 1;
+		return;
+	}
+	uhci->scan_in_progress = 1;
+ rescan:
+	uhci->need_rescan = 0;
+
+	uhci_get_current_frame_number(uhci);
+
+	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
+		uhci_free_pending_qhs(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
+		uhci_free_pending_tds(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
+		uhci_remove_pending_urbps(uhci);
+
+	/* Walk the list of pending URBs to see which ones completed
+	 * (must be _safe because uhci_transfer_result() dequeues URBs) */
+	list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
+		struct urb *urb = urbp->urb;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(uhci, urb);
+	}
+	uhci_finish_completion(uhci, regs);
+
+	/* If the controller is stopped, we can finish these off right now */
+	if (uhci->is_stopped) {
+		uhci_free_pending_qhs(uhci);
+		uhci_free_pending_tds(uhci);
+		uhci_remove_pending_urbps(uhci);
+	}
+
+	if (uhci->need_rescan)
+		goto rescan;
+	uhci->scan_in_progress = 0;
+
+	if (list_empty(&uhci->urb_remove_list) &&
+	    list_empty(&uhci->td_remove_list) &&
+	    list_empty(&uhci->qh_remove_list))
+		uhci_clear_next_interrupt(uhci);
+	else
+		uhci_set_next_interrupt(uhci);
+
+	/* Wake up anyone waiting for an URB to complete */
+	wake_up_all(&uhci->waitqh);
+}
diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig
--- a/drivers/usb/image/Kconfig
+++ b/drivers/usb/image/Kconfig
@@ -28,14 +28,3 @@ config USB_MICROTEK
 	  The scanner will appear as a scsi generic device to the rest
 	  of the system. Scsi support is required.
 	  This driver can be compiled as a module, called microtek.
-
-config USB_HPUSBSCSI
-	tristate "HP53xx USB scanner support"
-	depends on USB && SCSI && BROKEN
-	help
-	  Say Y here if you want support for the HP 53xx series of scanners
-	  and the Minolta Scan Dual.
-	  The scanner will be accessible as a SCSI device.
-	  Please note that recent versions of SANE use usbfs, not this driver.
-	  This can be compiled as a module, called hpusbscsi.
-
diff --git a/drivers/usb/image/Makefile b/drivers/usb/image/Makefile
--- a/drivers/usb/image/Makefile
+++ b/drivers/usb/image/Makefile
@@ -3,5 +3,4 @@
 #
 
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
-obj-$(CONFIG_USB_HPUSBSCSI)	+= hpusbscsi.o
 obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
deleted file mode 100644
--- a/drivers/usb/image/hpusbscsi.c
+++ /dev/null
@@ -1,523 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <asm/atomic.h>
-#include <linux/blkdev.h>
-#include "../../scsi/scsi.h"
-#include <scsi/scsi_host.h>
-
-#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__)
-
-static Scsi_Host_Template hpusbscsi_scsi_host_template = {
-	.module			= THIS_MODULE,
-	.name			= "hpusbscsi",
-	.proc_name		= "hpusbscsi",
-	.queuecommand		= hpusbscsi_scsi_queuecommand,
-	.eh_abort_handler	= hpusbscsi_scsi_abort,
-	.eh_host_reset_handler	= hpusbscsi_scsi_host_reset,
-	.sg_tablesize		= SG_ALL,
-	.can_queue		= 1,
-	.this_id		= -1,
-	.cmd_per_lun		= 1,
-	.use_clustering		= 1,
-	.emulated		= 1,
-};
-
-static int
-hpusbscsi_usb_probe(struct usb_interface *intf,
-		    const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_host_interface *altsetting =	intf->cur_altsetting;
-	struct hpusbscsi *new;
-	int error = -ENOMEM;
-	int i;
-
-	if (altsetting->desc.bNumEndpoints != 3) {
-		printk (KERN_ERR "Wrong number of endpoints\n");
-		return -ENODEV;
-	}
-
-	new = kmalloc(sizeof(struct hpusbscsi), GFP_KERNEL);
-	if (!new)
-		return -ENOMEM;
-	memset(new, 0, sizeof(struct hpusbscsi));
-	new->dataurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!new->dataurb)
-		goto out_kfree;
-	new->controlurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!new->controlurb)
-		goto out_free_dataurb;
-
-	new->dev = dev;
-	init_waitqueue_head(&new->pending);
-	init_waitqueue_head(&new->deathrow);
-
-	error = -ENODEV;
-	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
-		if ((altsetting->endpoint[i].desc.
-		     bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-				USB_ENDPOINT_XFER_BULK) {
-			if (altsetting->endpoint[i].desc.
-			    bEndpointAddress & USB_DIR_IN) {
-				new->ep_in =
-					altsetting->endpoint[i].desc.
-					bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
-			} else {
-				new->ep_out =
-					altsetting->endpoint[i].desc.
-					bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
-			}
-		} else {
-			new->ep_int =
-				altsetting->endpoint[i].desc.
-				bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-			new->interrupt_interval= altsetting->endpoint[i].desc.
-				bInterval;
-		}
-	}
-
-	/* build and submit an interrupt URB for status byte handling */
- 	usb_fill_int_urb(new->controlurb, new->dev,
-			usb_rcvintpipe(new->dev, new->ep_int),
-			&new->scsi_state_byte, 1,
-			control_interrupt_callback,new,
-			new->interrupt_interval);
-
-	if (usb_submit_urb(new->controlurb, GFP_KERNEL) < 0)
-		goto out_free_controlurb;
-
-	/* In host->hostdata we store a pointer to desc */
-	new->host = scsi_host_alloc(&hpusbscsi_scsi_host_template, sizeof(new));
-	if (!new->host)
-		goto out_kill_controlurb;
-
-	new->host->hostdata[0] = (unsigned long)new;
-	scsi_add_host(new->host, &intf->dev); /* XXX handle failure */
-	scsi_scan_host(new->host);
-
-	new->sense_command[0] = REQUEST_SENSE;
-	new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
-
-	usb_set_intfdata(intf, new);
-	return 0;
-
- out_kill_controlurb:
-	usb_kill_urb(new->controlurb);
- out_free_controlurb:
-	usb_free_urb(new->controlurb);
- out_free_dataurb:
-	usb_free_urb(new->dataurb);
- out_kfree:
-	kfree(new);
-	return error;
-}
-
-static void
-hpusbscsi_usb_disconnect(struct usb_interface *intf)
-{
-	struct hpusbscsi *desc = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-
-	scsi_remove_host(desc->host);
-	usb_kill_urb(desc->controlurb);
-	scsi_host_put(desc->host);
-
-	usb_free_urb(desc->controlurb);
-	usb_free_urb(desc->dataurb);
-	kfree(desc);
-}
-
-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 */
-};
-
-MODULE_DEVICE_TABLE (usb, hpusbscsi_usb_ids);
-MODULE_LICENSE("GPL");
-
-
-static struct usb_driver hpusbscsi_usb_driver = {
-	.owner = THIS_MODULE,
-	.name ="hpusbscsi",
-	.probe =hpusbscsi_usb_probe,
-	.disconnect =hpusbscsi_usb_disconnect,
-	.id_table =hpusbscsi_usb_ids,
-};
-
-/* module initialisation */
-
-static int __init
-hpusbscsi_init (void)
-{
-	return usb_register(&hpusbscsi_usb_driver);
-}
-
-static void __exit
-hpusbscsi_exit (void)
-{
-	usb_deregister(&hpusbscsi_usb_driver);
-}
-
-module_init (hpusbscsi_init);
-module_exit (hpusbscsi_exit);
-
-static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
-{
-	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]);
-	usb_complete_t usb_callback;
-	int res;
-
-	/* 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;
-	}
-
-	/* Now we need to decide which callback to give to the urb we send the command with */
-
-	if (!srb->bufflen) {
-		if (srb->cmnd[0] == REQUEST_SENSE){
-			hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
-			usb_callback = request_sense_callback;
-		} else {
-			usb_callback = simple_command_callback;
-		}
-	} else {
-        	if (likely(srb->use_sg)) {
-			usb_callback = scatter_gather_callback;
-			hpusbscsi->fragment = 0;
-		} else {
-                	usb_callback = simple_payload_callback;
-		}
-		/* Now we find out which direction data is to be transferred in */
-		hpusbscsi->current_data_pipe = DIRECTION_IS_IN(srb->cmnd[0]) ?
-			usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in)
-		:
-			usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out)
-		;
-	}
-
-
-	TRACE_STATE;
-
-        /* We zero the sense buffer to avoid confusing user space */
-        memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
-	hpusbscsi->state = HP_STATE_BEGINNING;
-	TRACE_STATE;
-
-	/* We prepare the urb for writing out the scsi command */
-	usb_fill_bulk_urb(
-		hpusbscsi->dataurb,
-		hpusbscsi->dev,
-		usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
-		srb->cmnd,
-		srb->cmd_len,
-		usb_callback,
-		hpusbscsi
-	);
-	hpusbscsi->scallback = callback;
-	hpusbscsi->srb = srb;
-
-	res = usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC);
-	if (unlikely(res)) {
-		hpusbscsi->state = HP_STATE_FREE;
-		TRACE_STATE;
-		if (likely(callback != NULL)) {
-			srb->result = DID_ERROR;
-			callback(srb);
-		}
-	}
-
-out:
-	return 0;
-}
-
-static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb)
-{
-	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]);
-
-	printk(KERN_DEBUG"SCSI reset requested.\n");
-	//usb_reset_device(hpusbscsi->dev);
-	//printk(KERN_DEBUG"SCSI reset completed.\n");
-	hpusbscsi->state = HP_STATE_FREE;
-
-	return 0;
-}
-
-static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
-{
-	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]);
-	printk(KERN_DEBUG"Requested is canceled.\n");
-
-	usb_kill_urb(hpusbscsi->dataurb);
-	usb_kill_urb(hpusbscsi->controlurb);
-	hpusbscsi->state = HP_STATE_FREE;
-
-	return SCSI_ABORT_PENDING;
-}
-
-/* usb interrupt handlers - they are all running IN INTERRUPT ! */
-
-static void handle_usb_error (struct hpusbscsi *hpusbscsi)
-{
-	if (likely(hpusbscsi->scallback != NULL)) {
-		hpusbscsi->srb->result = DID_ERROR;
-		hpusbscsi->scallback(hpusbscsi->srb);
-	}
-	hpusbscsi->state = HP_STATE_FREE;
-}
-
-static void  control_interrupt_callback (struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	u8 scsi_state;
-
-DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-	if(unlikely(u->status < 0)) {
-                if (likely(hpusbscsi->state != HP_STATE_FREE))
-                        handle_usb_error(hpusbscsi);
-		if (u->status == -ECONNRESET || u->status == -ENOENT || u->status == -ESHUTDOWN)
-			return;
-		else
-			goto resub;
-	}
-
-	scsi_state = hpusbscsi->scsi_state_byte;
-	if (hpusbscsi->state != HP_STATE_ERROR) {
-		hpusbscsi->srb->result &= SCSI_ERR_MASK;
-		hpusbscsi->srb->result |= scsi_state;
-	}
-
-	if (scsi_state == CHECK_CONDITION << 1) {
-		if (hpusbscsi->state == HP_STATE_WAIT) {
-			issue_request_sense(hpusbscsi);
-		} else {
-			/* we request sense after an eventual data transfer */
-			hpusbscsi->state = HP_STATE_ERROR;
-		}
-	}
-
-	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
-		/* we do a callback to the scsi layer if and only if all data has been transferred */
-		hpusbscsi->scallback(hpusbscsi->srb);
-
-	TRACE_STATE;
-	switch (hpusbscsi->state) {
-	case HP_STATE_WAIT:
-		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
-		break;
-	case HP_STATE_WORKING:
-	case HP_STATE_BEGINNING:
-		hpusbscsi->state = HP_STATE_PREMATURE;
-	TRACE_STATE;
-		break;
-	case HP_STATE_ERROR:
-		break;
-	default:
-		printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
-	TRACE_STATE;
-		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
-		break;
-	}
-resub:
-	usb_submit_urb(u, GFP_ATOMIC);
-}
-
-static void simple_command_callback(struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	if (unlikely(u->status<0)) {
-		handle_usb_error(hpusbscsi);
-		return;
-        }
-	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-	        TRACE_STATE;
-		hpusbscsi->state = HP_STATE_WAIT;
-	} else {
-		if (likely(hpusbscsi->scallback != NULL))
-			hpusbscsi->scallback(hpusbscsi->srb);
-		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
-	}
-}
-
-static void scatter_gather_callback(struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-        struct scatterlist *sg = hpusbscsi->srb->buffer;
-        usb_complete_t callback;
-        int res;
-
-        DEBUG("Going through scatter/gather\n");
-        if (unlikely(u->status < 0)) {
-                handle_usb_error(hpusbscsi);
-                return;
-        }
-
-        if (hpusbscsi->fragment + 1 != hpusbscsi->srb->use_sg)
-                callback = scatter_gather_callback;
-        else
-                callback = simple_done;
-
-	TRACE_STATE;
-        if (hpusbscsi->state != HP_STATE_PREMATURE)
-		hpusbscsi->state = HP_STATE_WORKING;
-	TRACE_STATE;
-
-        usb_fill_bulk_urb(
-                u,
-                hpusbscsi->dev,
-                hpusbscsi->current_data_pipe,
-                page_address(sg[hpusbscsi->fragment].page) +
-		sg[hpusbscsi->fragment].offset,
-                sg[hpusbscsi->fragment++].length,
-                callback,
-                hpusbscsi
-        );
-
-        res = usb_submit_urb(u, GFP_ATOMIC);
-        if (unlikely(res))
-                handle_usb_error(hpusbscsi);
-	TRACE_STATE;
-}
-
-static void simple_done (struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
-        if (unlikely(u->status < 0)) {
-                handle_usb_error(hpusbscsi);
-                return;
-        }
-        DEBUG("Data transfer done\n");
-	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (unlikely(u->status < 0)) {
-			handle_usb_error(hpusbscsi);
-		} else {
-			if (hpusbscsi->state != HP_STATE_ERROR) {
-				hpusbscsi->state = HP_STATE_WAIT;
-			} else {
-				issue_request_sense(hpusbscsi);
-			}
-		}
-	} else {
-		if (likely(hpusbscsi->scallback != NULL))
-			hpusbscsi->scallback(hpusbscsi->srb);
-		hpusbscsi->state = HP_STATE_FREE;
-	}
-}
-
-static void simple_payload_callback (struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	int res;
-
-	if (unlikely(u->status<0)) {
-                handle_usb_error(hpusbscsi);
-		return;
-        }
-
-	usb_fill_bulk_urb(
-		u,
-		hpusbscsi->dev,
-		hpusbscsi->current_data_pipe,
-		hpusbscsi->srb->buffer,
-		hpusbscsi->srb->bufflen,
-		simple_done,
-		hpusbscsi
-	);
-
-	res = usb_submit_urb(u, GFP_ATOMIC);
-	if (unlikely(res)) {
-                handle_usb_error(hpusbscsi);
-		return;
-        }
-	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		hpusbscsi->state = HP_STATE_WORKING;
-	TRACE_STATE;
-	} 
-}
-
-static void request_sense_callback (struct urb *u, struct pt_regs *regs)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
-	if (u->status<0) {
-                handle_usb_error(hpusbscsi);
-		return;
-        }
-
-	usb_fill_bulk_urb(
-		u,
-		hpusbscsi->dev,
-		hpusbscsi->current_data_pipe,
-		hpusbscsi->srb->sense_buffer,
-		SCSI_SENSE_BUFFERSIZE,
-		simple_done,
-		hpusbscsi
-	);
-
-	if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
-		handle_usb_error(hpusbscsi);
-		return;
-	}
-	if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
-		hpusbscsi->state = HP_STATE_WORKING;
-}
-
-static void issue_request_sense (struct hpusbscsi *hpusbscsi)
-{
-	usb_fill_bulk_urb(
-		hpusbscsi->dataurb,
-		hpusbscsi->dev,
-		usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
-		&hpusbscsi->sense_command,
-		SENSE_COMMAND_SIZE,
-		request_sense_callback,
-		hpusbscsi
-	);
-
-	hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
-
-	if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
-		handle_usb_error(hpusbscsi);
-	}
-}
-
-
diff --git a/drivers/usb/image/hpusbscsi.h b/drivers/usb/image/hpusbscsi.h
deleted file mode 100644
--- a/drivers/usb/image/hpusbscsi.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Header file for the hpusbscsi driver */
-/* (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 file is licensed under the GPL */
-
-/* A big thanks to Jose for untiring testing */
-
-typedef void (*scsi_callback)(Scsi_Cmnd *);
-
-#define SENSE_COMMAND_SIZE 6
-#define HPUSBSCSI_SENSE_LENGTH 0x16
-
-struct hpusbscsi
-{
-        struct usb_device *dev; /* NULL indicates unplugged device */
-        int ep_out;
-        int ep_in;
-        int ep_int;
-        int interrupt_interval;
-	int number;
-	int fragment;
-        struct Scsi_Host *host;
-
-	scsi_callback scallback;
-	Scsi_Cmnd *srb;
-
-
-        wait_queue_head_t pending;
-        wait_queue_head_t deathrow;
-
-        struct urb *dataurb;
-        struct urb *controlurb;
-
-
-        int state;
-        int current_data_pipe;
-	u8 sense_command[SENSE_COMMAND_SIZE];
-        u8 scsi_state_byte;
-};
-
-#define SCSI_ERR_MASK ~0x3fu
-
-static const unsigned char scsi_command_direction[256/8] = {
-	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
-	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1)
-
-static void simple_command_callback(struct urb *u, struct pt_regs *regs);
-static void scatter_gather_callback(struct urb *u, struct pt_regs *regs);
-static void simple_payload_callback (struct urb *u, struct pt_regs *regs);
-static void request_sense_callback (struct urb *u, struct pt_regs *regs);
-static void control_interrupt_callback (struct urb *u, struct pt_regs *regs);
-static void simple_done (struct urb *u, struct pt_regs *regs);
-static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
-static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
-static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
-static void issue_request_sense (struct hpusbscsi *hpusbscsi);
-
-/* defines for internal driver state */
-#define HP_STATE_FREE                 0  /*ready for next request */
-#define HP_STATE_BEGINNING      1  /*command being transferred */
-#define HP_STATE_WORKING         2  /* data transfer stage */
-#define HP_STATE_ERROR             3  /* error has been reported */
-#define HP_STATE_WAIT                 4  /* waiting for status transfer */
-#define HP_STATE_PREMATURE              5 /* status prematurely reported */
-
-
-
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -23,7 +23,7 @@
  *
  *
  * The driver brings the USB functions of the MDC800 to Linux.
- * To use the Camera you must support the USB Protocoll of the camera
+ * To use the Camera you must support the USB Protocol of the camera
  * to the Kernel Node.
  * The Driver uses a misc device Node. Create it with :
  * mknod /dev/mustek c 180 32
@@ -95,6 +95,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
+#include <linux/wait.h>
 
 #include <linux/usb.h>
 #include <linux/fs.h>
@@ -330,7 +331,7 @@ static void mdc800_usb_irq (struct urb *
 	{
 		mdc800->camera_request_ready=0;
 		mdc800->irq_woken=1;
-		wake_up_interruptible (&mdc800->irq_wait);
+		wake_up (&mdc800->irq_wait);
 	}
 }
 
@@ -346,19 +347,9 @@ static void mdc800_usb_irq (struct urb *
  */
 static int mdc800_usb_waitForIRQ (int mode, int msec)
 {
-        DECLARE_WAITQUEUE(wait, current);
-	long timeout;
-
 	mdc800->camera_request_ready=1+mode;
 
-	add_wait_queue(&mdc800->irq_wait, &wait);
-	timeout = msec*HZ/1000;
-	while (!mdc800->irq_woken && timeout)
-	{
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		timeout = schedule_timeout (timeout);
-	}
-        remove_wait_queue(&mdc800->irq_wait, &wait);
+	wait_event_timeout(mdc800->irq_wait, mdc800->irq_woken, msec*HZ/1000);
 	mdc800->irq_woken = 0;
 
 	if (mdc800->camera_request_ready>0)
@@ -395,7 +386,7 @@ static void mdc800_usb_write_notify (str
 		mdc800->state=READY;
 	}
 	mdc800->written = 1;
-	wake_up_interruptible (&mdc800->write_wait);
+	wake_up (&mdc800->write_wait);
 }
 
 
@@ -423,7 +414,7 @@ static void mdc800_usb_download_notify (
 		err ("request bytes fails (status:%i)", urb->status);
 	}
 	mdc800->downloaded = 1;
-	wake_up_interruptible (&mdc800->download_wait);
+	wake_up (&mdc800->download_wait);
 }
 
 
@@ -704,8 +695,6 @@ static ssize_t mdc800_device_read (struc
 {
 	size_t left=len, sts=len; /* single transfer size */
 	char __user *ptr = buf;
-	long timeout;
-	DECLARE_WAITQUEUE(wait, current);
 
 	down (&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
@@ -751,14 +740,8 @@ static ssize_t mdc800_device_read (struc
 					up (&mdc800->io_lock);
 					return len-left;
 				}
-				add_wait_queue(&mdc800->download_wait, &wait);
-				timeout = TO_DOWNLOAD_GET_READY*HZ/1000;
-				while (!mdc800->downloaded && timeout)
-				{
-					set_current_state(TASK_UNINTERRUPTIBLE);
-					timeout = schedule_timeout (timeout);
-				}
-				remove_wait_queue(&mdc800->download_wait, &wait);
+				wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
+										TO_DOWNLOAD_GET_READY*HZ/1000);
 				mdc800->downloaded = 0;
 				if (mdc800->download_urb->status != 0)
 				{
@@ -802,7 +785,6 @@ static ssize_t mdc800_device_read (struc
 static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
 {
 	size_t i=0;
-	DECLARE_WAITQUEUE(wait, current);
 
 	down (&mdc800->io_lock);
 	if (mdc800->state != READY)
@@ -856,7 +838,6 @@ static ssize_t mdc800_device_write (stru
 		if (mdc800->in_count == 8)
 		{
 			int answersize;
-			long timeout;
 
 			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
 			{
@@ -876,14 +857,7 @@ static ssize_t mdc800_device_write (stru
 				up (&mdc800->io_lock);
 				return -EIO;
 			}
-			add_wait_queue(&mdc800->write_wait, &wait);
-			timeout = TO_WRITE_GET_READY*HZ/1000;
-			while (!mdc800->written && timeout)
-			{
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				timeout = schedule_timeout (timeout);
-			}
-			remove_wait_queue(&mdc800->write_wait, &wait);
+			wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
 			mdc800->written = 0;
 			if (mdc800->state == WORKING)
 			{
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -335,7 +335,7 @@ static int mts_scsi_abort (Scsi_Cmnd *sr
 
 	mts_urb_abort(desc);
 
-	return SCSI_ABORT_PENDING;
+	return FAILED;
 }
 
 static int mts_scsi_host_reset (Scsi_Cmnd *srb)
@@ -703,6 +703,7 @@ static int mts_usb_probe(struct usb_inte
 	int ep_in_set[3]; /* this will break if we have more than three endpoints
 			   which is why we check */
 	int *ep_in_current = ep_in_set;
+	int err_retval = -ENOMEM;
 
 	struct mts_desc * new_desc;
 	struct vendor_product const* p;
@@ -809,7 +810,10 @@ static int mts_usb_probe(struct usb_inte
 		goto out_free_urb;
 
 	new_desc->host->hostdata[0] = (unsigned long)new_desc;
-	scsi_add_host(new_desc->host, NULL); /* XXX handle failure */
+	if (scsi_add_host(new_desc->host, NULL)) {
+		err_retval = -EIO;
+		goto out_free_urb;
+	}
 	scsi_scan_host(new_desc->host);
 
 	usb_set_intfdata(intf, new_desc);
@@ -820,7 +824,7 @@ static int mts_usb_probe(struct usb_inte
  out_kfree:
 	kfree(new_desc);
  out:
-	return -ENOMEM;
+	return err_retval;
 }
 
 static void mts_usb_disconnect (struct usb_interface *intf)
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -297,8 +297,6 @@ struct aiptek_features {
 	int firmwareCode;	/* prom/eeprom version            */
 	char usbPath[64 + 1];	/* device's physical usb path     */
 	char inputPath[64 + 1];	/* input device path              */
-	char manuName[64 + 1];	/* manufacturer name              */
-	char prodName[64 + 1];	/* product name                   */
 };
 
 struct aiptek_settings {
@@ -388,7 +386,7 @@ static int aiptek_convert_from_2s_comple
  * convention above.) I therefore have taken over REL_MISC and ABS_MISC
  * (for relative and absolute reports, respectively) for communicating
  * Proximity. Why two events? I thought it interesting to know if the
- * Proximity event occured while the tablet was in absolute or relative
+ * Proximity event occurred while the tablet was in absolute or relative
  * mode.
  *
  * Other tablets use the notion of a certain minimum stylus pressure
@@ -796,7 +794,7 @@ exit:
  * manufacturing revisions. In any event, we consider these 
  * IDs to not be model-specific nor unique.
  */
-struct usb_device_id aiptek_ids[] = {
+static const struct usb_device_id aiptek_ids[] = {
 	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)},
 	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)},
 	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)},
@@ -855,7 +853,7 @@ aiptek_set_report(struct aiptek *aiptek,
 			       USB_REQ_SET_REPORT,
 			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
 			       USB_DIR_OUT, (report_type << 8) + report_id,
-			       aiptek->ifnum, buffer, size, 5 * HZ);
+			       aiptek->ifnum, buffer, size, 5000);
 }
 
 static int
@@ -868,7 +866,7 @@ aiptek_get_report(struct aiptek *aiptek,
 			       USB_REQ_GET_REPORT,
 			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
 			       USB_DIR_IN, (report_type << 8) + report_id,
-			       aiptek->ifnum, buffer, size, 5 * HZ);
+			       aiptek->ifnum, buffer, size, 5000);
 }
 
 /***********************************************************************
@@ -1089,7 +1087,7 @@ static ssize_t show_tabletManufacturer(s
 	if (aiptek == NULL)
 		return 0;
 
-	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->features.manuName);
+	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
 	return retval;
 }
 
@@ -1106,7 +1104,7 @@ static ssize_t show_tabletProduct(struct
 	if (aiptek == NULL)
 		return 0;
 
-	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->features.prodName);
+	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
 	return retval;
 }
 
@@ -2140,6 +2138,7 @@ aiptek_probe(struct usb_interface *intf,
 	aiptek->inputdev.id.vendor = le16_to_cpu(usbdev->descriptor.idVendor);
 	aiptek->inputdev.id.product = le16_to_cpu(usbdev->descriptor.idProduct);
 	aiptek->inputdev.id.version = le16_to_cpu(usbdev->descriptor.bcdDevice);
+	aiptek->inputdev.dev = &intf->dev;
 
 	aiptek->usbdev = usbdev;
 	aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
@@ -2166,19 +2165,6 @@ aiptek_probe(struct usb_interface *intf,
 	 */
 	input_register_device(&aiptek->inputdev);
 
-	/* Go and decode the USB representation of the tablet's manufacturer
-	 * name and product name. They only change once every hotplug event,
-	 * which is why we put it here instead of in the sysfs interface.
-	 */
-	usb_string(usbdev,
-		   usbdev->descriptor.iManufacturer,
-		   aiptek->features.manuName,
-		   sizeof(aiptek->features.manuName));
-	usb_string(usbdev,
-		   usbdev->descriptor.iProduct,
-		   aiptek->features.prodName,
-		   sizeof(aiptek->features.prodName));
-
 	/* We now will look for the evdev device which is mapped to
 	 * the tablet. The partial name is kept in the link list of
 	 * input_handles associated with this input device.
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -94,6 +94,7 @@
 #include <linux/moduleparam.h>
 #include <linux/input.h>
 #include <linux/usb.h>
+#include <linux/wait.h>
 
 /*
  * Module and Version Information, Module Parameters
@@ -174,7 +175,6 @@ struct ati_remote {
 	dma_addr_t outbuf_dma;
 
 	int open;                   /* open counter */
-	int present;                /* device plugged in? */
 	
 	unsigned char old_data[2];  /* Detect duplicate events */
 	unsigned long old_jiffies;
@@ -252,8 +252,8 @@ static struct
 	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
 	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
 	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1},      /* TV */
-	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1},      /* DVD */
+	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
 	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
 	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
 	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
@@ -263,14 +263,14 @@ static struct
 	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
 	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
 	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1},      /* "OK" */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
 	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
 	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
 	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
 	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1},     /* ( >) */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
 	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
 	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
 	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */ 
@@ -356,19 +356,8 @@ static void ati_remote_close(struct inpu
 {
 	struct ati_remote *ati_remote = inputdev->private;
 	
-	if (ati_remote == NULL) {
-		err("ati_remote: %s: object is NULL!\n", __FUNCTION__);
-		return;
-	}
-	
-	if (ati_remote->open <= 0)
-		dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__);
-	else
-		--ati_remote->open;
-	
-	/* If still present, disconnect will call delete. */
-	if (!ati_remote->present && !ati_remote->open)
-		ati_remote_delete(ati_remote);
+	if (!--ati_remote->open)
+		usb_kill_urb(ati_remote->irq_urb);
 }
 
 /*
@@ -396,8 +385,6 @@ static void ati_remote_irq_out(struct ur
  */
 static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	int timeout = HZ;	/* 1 second */
 	int retval = 0;
 	
 	/* Set up out_urb */
@@ -415,18 +402,10 @@ static int ati_remote_sendpacket(struct 
 		return retval;
 	}
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&ati_remote->wait, &wait);
-
-	while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) 
-	       && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		timeout = schedule_timeout(timeout);
-		rmb();
-	}
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&ati_remote->wait, &wait);
+	wait_event_timeout(ati_remote->wait,
+		((ati_remote->out_urb->status != -EINPROGRESS) ||
+		 	(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+		HZ);
 	usb_kill_urb(ati_remote->out_urb);
 	
 	return retval;
@@ -640,7 +619,7 @@ static void ati_remote_delete(struct ati
 		
 	if (ati_remote->outbuf)
 		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
-				ati_remote->inbuf, ati_remote->outbuf_dma);
+				ati_remote->outbuf, ati_remote->outbuf_dma);
 	
 	if (ati_remote->irq_urb)
 		usb_free_urb(ati_remote->irq_urb);
@@ -727,7 +706,6 @@ static int ati_remote_probe(struct usb_i
 	struct usb_host_interface *iface_host;
 	int retval = -ENOMEM;
 	char path[64];
-	char *buf = NULL;
 
 	/* Allocate and clear an ati_remote struct */
 	if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL)))
@@ -761,8 +739,6 @@ static int ati_remote_probe(struct usb_i
 		retval = -ENODEV;
 		goto error;
 	}
-	if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL)))
-		goto error;
 
 	/* Allocate URB buffers, URBs */
 	ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
@@ -785,14 +761,11 @@ static int ati_remote_probe(struct usb_i
 
 	usb_make_path(udev, path, NAME_BUFSIZE);
 	sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM);
-	if (udev->descriptor.iManufacturer && 
-	    (usb_string(udev, udev->descriptor.iManufacturer, buf, 
-			NAME_BUFSIZE) > 0))
-		strcat(ati_remote->name, buf);
-
-	if (udev->descriptor.iProduct && 
-	    (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0))
-		sprintf(ati_remote->name, "%s %s", ati_remote->name, buf);
+	if (udev->manufacturer)
+		strcat(ati_remote->name, udev->manufacturer);
+
+	if (udev->product)
+		sprintf(ati_remote->name, "%s %s", ati_remote->name, udev->product);
 
 	if (!strlen(ati_remote->name))
 		sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
@@ -812,12 +785,8 @@ static int ati_remote_probe(struct usb_i
 		 ati_remote->name, path);
 
 	usb_set_intfdata(interface, ati_remote);
-	ati_remote->present = 1;	
 	
 error:
-	if (buf)
-		kfree(buf);
-
 	if (retval)
 		ati_remote_delete(ati_remote);
 
@@ -840,12 +809,7 @@ static void ati_remote_disconnect(struct
 		return;
 	}
 	
-	/* Mark device as unplugged */
-	ati_remote->present = 0;
-
-	/* If device is still open, ati_remote_close will call delete. */
-	if (!ati_remote->open)
-		ati_remote_delete(ati_remote);
+	ati_remote_delete(ati_remote);
 
 	up(&disconnect_sem);
 }
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -24,6 +24,7 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 #include <linux/input.h>
+#include <linux/wait.h>
 
 #undef DEBUG
 #undef DEBUG_DATA
@@ -37,13 +38,20 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v2.0"
+#define DRIVER_VERSION "v2.01"
 #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
 #define DRIVER_DESC "USB HID core driver"
 #define DRIVER_LICENSE "GPL"
 
 static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
 				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
 /*
  * Register a new report for a device.
@@ -121,18 +129,17 @@ static int open_collection(struct hid_pa
 
 	if (parser->device->maxcollection == parser->device->collection_size) {
 		collection = kmalloc(sizeof(struct hid_collection) *
-				     parser->device->collection_size * 2,
-				     GFP_KERNEL);
+				parser->device->collection_size * 2, GFP_KERNEL);
 		if (collection == NULL) {
 			dbg("failed to reallocate collection array");
 			return -1;
 		}
 		memcpy(collection, parser->device->collection,
-		       sizeof(struct hid_collection) *
-		       parser->device->collection_size);
+			sizeof(struct hid_collection) *
+			parser->device->collection_size);
 		memset(collection + parser->device->collection_size, 0,
-		       sizeof(struct hid_collection) *
-		       parser->device->collection_size);
+			sizeof(struct hid_collection) *
+			parser->device->collection_size);
 		kfree(parser->device->collection);
 		parser->device->collection = collection;
 		parser->device->collection_size *= 2;
@@ -141,12 +148,12 @@ static int open_collection(struct hid_pa
 	parser->collection_stack[parser->collection_stack_ptr++] =
 		parser->device->maxcollection;
 
-	collection = parser->device->collection + 
+	collection = parser->device->collection +
 		parser->device->maxcollection++;
 	collection->type = type;
 	collection->usage = usage;
 	collection->level = parser->collection_stack_ptr - 1;
-	
+
 	if (type == HID_COLLECTION_APPLICATION)
 		parser->device->maxapplication++;
 
@@ -193,7 +200,7 @@ static int hid_add_usage(struct hid_pars
 	}
 	parser->local.usage[parser->local.usage_index] = usage;
 	parser->local.collection_index[parser->local.usage_index] =
-		parser->collection_stack_ptr ? 
+		parser->collection_stack_ptr ?
 		parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
 	parser->local.usage_index++;
 	return 0;
@@ -220,13 +227,15 @@ static int hid_add_field(struct hid_pars
 		dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
 		return -1;
 	}
-	
-	if (!(usages = max_t(int, parser->local.usage_index, parser->global.report_count)))
-		return 0; /* Ignore padding fields */
 
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	if (!parser->local.usage_index) /* Ignore padding fields */
+		return 0; 
+
+	usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+
 	if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
 		return 0;
 
@@ -549,8 +558,7 @@ static void hid_free_device(struct hid_d
 		}
 	}
 
-	if (device->rdesc)
-		kfree(device->rdesc);
+	kfree(device->rdesc);
 	kfree(device);
 }
 
@@ -581,13 +589,13 @@ static u8 *fetch_item(__u8 *start, __u8 
 		item->size = *start++;
 		item->tag  = *start++;
 
-		if ((end - start) < item->size) 
+		if ((end - start) < item->size)
 			return NULL;
 
 		item->data.longdata = start;
 		start += item->size;
 		return start;
-	} 
+	}
 
 	item->format = HID_ITEM_FORMAT_SHORT;
 	item->size = b & 3;
@@ -604,7 +612,7 @@ static u8 *fetch_item(__u8 *start, __u8 
 			return start;
 
 		case 2:
-			if ((end - start) < 2) 
+			if ((end - start) < 2)
 				return NULL;
 			item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
 			start = (__u8 *)((__le16 *)start + 1);
@@ -646,13 +654,13 @@ static struct hid_device *hid_parse_repo
 		return NULL;
 	memset(device, 0, sizeof(struct hid_device));
 
-	if (!(device->collection =kmalloc(sizeof(struct hid_collection) *
+	if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
 				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
 		kfree(device);
 		return NULL;
 	}
 	memset(device->collection, 0, sizeof(struct hid_collection) *
-	       HID_DEFAULT_NUM_COLLECTIONS);
+		HID_DEFAULT_NUM_COLLECTIONS);
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 	for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -806,8 +814,7 @@ static void hid_input_field(struct hid_d
 	__s32 max = field->logical_maximum;
 	__s32 *value;
 
-	value = kmalloc(sizeof(__s32)*count, GFP_ATOMIC);
-	if (!value)
+	if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
 		return;
 
 	for (n = 0; n < count; n++) {
@@ -824,14 +831,6 @@ static void hid_input_field(struct hid_d
 	for (n = 0; n < count; n++) {
 
 		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				if (!value[n])
-					continue;
-			} else {
-				if (value[n] == field->value[n])
-					continue;
-			}	
 			hid_process_event(hid, field, &field->usage[n], value[n], regs);
 			continue;
 		}
@@ -893,10 +892,8 @@ static int hid_input_report(int type, st
 
 	size = ((report->size - 1) >> 3) + 1;
 
-	if (len < size) {
+	if (len < size)
 		dbg("report %d is too short, (%d < %d)", report->id, len, size);
-		return -1;
-	}
 
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
 		hiddev_report_event(hid, report);
@@ -934,7 +931,7 @@ static void hid_irq_in(struct urb *urb, 
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
 	}
-	
+
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
 	if (status)
 		err("can't resubmit intr, %s-%s/input%d, status %d",
@@ -956,7 +953,7 @@ static void hid_output_field(struct hid_
 	for (n = 0; n < count; n++) {
 		if (field->logical_minimum < 0)	/* signed values */
 			implement(data, offset + n * size, size, s32ton(field->value[n], size));
-		 else				/* unsigned values */
+		else				/* unsigned values */
 			implement(data, offset + n * size, size, field->value[n]);
 	}
 }
@@ -1003,64 +1000,22 @@ int hid_set_field(struct hid_field *fiel
 	return 0;
 }
 
-int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
-{
-	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
-	struct list_head *list = report_enum->report_list.next;
-	int i, j;
-
-	while (list != &report_enum->report_list) {
-		struct hid_report *report = (struct hid_report *) list;
-		list = list->next;
-		for (i = 0; i < report->maxfield; i++) {
-			*field = report->field[i];
-			for (j = 0; j < (*field)->maxusage; j++)
-				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
-					return j;
-		}
-	}
-	return -1;
-}
-
 /*
- * Find a report with a specified HID usage.
+ * Find a report field with a specified HID usage.
  */
 
-int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type)
+struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
 {
-	struct hid_report_enum *report_enum = hid->report_enum + type;
-	struct list_head *list = report_enum->report_list.next;
-	int i, j;
+	struct hid_report *report;
+	int i;
 
-	while (list != &report_enum->report_list) {
-		*report = (struct hid_report *) list;
-		list = list->next;
-		for (i = 0; i < (*report)->maxfield; i++) {
-			struct hid_field *field = (*report)->field[i];
-			for (j = 0; j < field->maxusage; j++)
-				if (field->logical == wanted_usage)
-					return j;
-		}
-	}
-	return -1;
+	list_for_each_entry(report, &hid->report_enum[type].report_list, list)
+		for (i = 0; i < report->maxfield; i++)
+			if (report->field[i]->logical == wanted_usage)
+				return report->field[i];
+	return NULL;
 }
 
-#if 0
-static int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field)
-{
-	int i, j;
-
-	for (i = 0; i < report->maxfield; i++) {
-		*field = report->field[i];
-		for (j = 0; j < (*field)->maxusage; j++)
-			if ((*field)->usage[j].hid == wanted_usage)
-				return j;
-	}
-
-	return -1;
-}
-#endif
-
 static int hid_submit_out(struct hid_device *hid)
 {
 	struct hid_report *report;
@@ -1118,8 +1073,8 @@ static int hid_submit_ctrl(struct hid_de
 	hid->cr->wLength = cpu_to_le16(len);
 
 	dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
-	    hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
-	    hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
+		hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+		hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
 
 	if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
 		err("usb_submit_urb(ctrl) failed");
@@ -1186,7 +1141,7 @@ static void hid_ctrl(struct urb *urb, st
 
 	switch (urb->status) {
 		case 0:			/* success */
-			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) 
+			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs);
 		case -ESHUTDOWN:	/* unplug */
 		case -EILSEQ:		/* unplug timectrl on uhci */
@@ -1268,22 +1223,9 @@ void hid_submit_report(struct hid_device
 
 int hid_wait_io(struct hid_device *hid)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	int timeout = 10*HZ;
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&hid->wait, &wait);
-
-	while (timeout && (test_bit(HID_CTRL_RUNNING, &hid->iofl) ||
-			   test_bit(HID_OUT_RUNNING, &hid->iofl))) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		timeout = schedule_timeout(timeout);
-	}
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&hid->wait, &wait);
-
-	if (!timeout) {
+	if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
+					!test_bit(HID_OUT_RUNNING, &hid->iofl)),
+					10*HZ)) {
 		dbg("timeout waiting for ctrl or out queue to clear");
 		return -1;
 	}
@@ -1301,7 +1243,7 @@ static int hid_get_class_descriptor(stru
 	do {
 		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
-				(type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
+				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
 		retries--;
 	} while (result < size && retries);
 	return result;
@@ -1332,47 +1274,19 @@ void hid_close(struct hid_device *hid)
 
 void hid_init_reports(struct hid_device *hid)
 {
-	struct hid_report_enum *report_enum;
 	struct hid_report *report;
-	struct list_head *list;
-	int err, ret, size;
-
-	/*
-	 * The Set_Idle request is supposed to affect only the
-	 * "Interrupt In" pipe. Unfortunately, buggy devices such as
-	 * the BTC keyboard (ID 046e:5303) the request also affects
-	 * Get_Report requests on the control pipe.  In the worst
-	 * case, if the device was put on idle for an indefinite
-	 * amount of time (as we do below) and there are no input
-	 * events to report, the Get_Report requests will just hang
-	 * until we get a USB timeout.  To avoid this, we temporarily
-	 * establish a minimal idle time of 1ms.  This shouldn't hurt
-	 * bugfree devices and will cause a worst-case extra delay of
-	 * 1ms for buggy ones.
-	 */
-	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8),
-			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+	int err, ret;
 
-	report_enum = hid->report_enum + HID_INPUT_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
-		size = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) {
+		int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
 		if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
 		if (size > hid->urbin->transfer_buffer_length)
 			hid->urbin->transfer_buffer_length = size;
 		hid_submit_report(hid, report, USB_DIR_IN);
-		list = list->next;
 	}
 
-	report_enum = hid->report_enum + HID_FEATURE_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
+	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
 		hid_submit_report(hid, report, USB_DIR_IN);
-		list = list->next;
-	}
 
 	err = 0;
 	ret = hid_wait_io(hid);
@@ -1388,15 +1302,9 @@ void hid_init_reports(struct hid_device 
 	if (err)
 		warn("timeout initializing reports\n");
 
-	report_enum = hid->report_enum + HID_INPUT_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
-		usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
-			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-		list = list->next;
-	}
+	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
+		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+		hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
 #define USB_VENDOR_ID_WACOM		0x056a
@@ -1405,11 +1313,13 @@ void hid_init_reports(struct hid_device 
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
 #define USB_DEVICE_ID_WACOM_PL		0x0030
 #define USB_DEVICE_ID_WACOM_INTUOS2	0x0040
-#define USB_DEVICE_ID_WACOM_VOLITO      0x0060
-#define USB_DEVICE_ID_WACOM_PTU         0x0003
+#define USB_DEVICE_ID_WACOM_VOLITO	0x0060
+#define USB_DEVICE_ID_WACOM_PTU		0x0003
+#define USB_DEVICE_ID_WACOM_INTUOS3	0x00B0
+#define USB_DEVICE_ID_WACOM_CINTIQ	0x003F
 
-#define USB_VENDOR_ID_KBGEAR            0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO  0x1001
+#define USB_VENDOR_ID_KBGEAR		0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
 
 #define USB_VENDOR_ID_AIPTEK		0x08ca
 #define USB_DEVICE_ID_AIPTEK_01		0x0001
@@ -1424,35 +1334,35 @@ void hid_init_reports(struct hid_device 
 #define USB_DEVICE_ID_POWERMATE		0x0410
 #define USB_DEVICE_ID_SOUNDKNOB		0x04AA
 
-#define USB_VENDOR_ID_ATEN             0x0557  
-#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
-#define USB_DEVICE_ID_ATEN_CS124U      0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
-
-#define USB_VENDOR_ID_TOPMAX           0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
-
-#define USB_VENDOR_ID_HAPP             0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
-#define USB_DEVICE_ID_UGCI_FLYING      0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
-
-#define USB_VENDOR_ID_MGE              0x0463
-#define USB_DEVICE_ID_MGE_UPS          0xffff
-#define USB_DEVICE_ID_MGE_UPS1         0x0001
+#define USB_VENDOR_ID_ATEN		0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
+#define USB_DEVICE_ID_ATEN_CS124U	0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
+
+#define USB_VENDOR_ID_TOPMAX		0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
+
+#define USB_VENDOR_ID_HAPP		0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
+#define USB_DEVICE_ID_UGCI_FLYING	0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
+
+#define USB_VENDOR_ID_MGE		0x0463
+#define USB_DEVICE_ID_MGE_UPS		0xffff
+#define USB_DEVICE_ID_MGE_UPS1		0x0001
 
 #define USB_VENDOR_ID_ONTRAK		0x0a07
 #define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
 
-#define USB_VENDOR_ID_TANGTOP          0x0d3d
-#define USB_DEVICE_ID_TANGTOP_USBPS2   0x0001
+#define USB_VENDOR_ID_TANGTOP		0x0d3d
+#define USB_DEVICE_ID_TANGTOP_USBPS2	0x0001
 
 #define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5	0x0100
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
-#define USB_VENDOR_ID_A4TECH		0x09DA
+#define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 
 #define USB_VENDOR_ID_CYPRESS		0x04b4
@@ -1493,6 +1403,28 @@ void hid_init_reports(struct hid_device 
 
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
+
+#define USB_VENDOR_ID_MCC		0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
+
+#define USB_VENDOR_ID_CHICONY		0x04f2
+#define USB_DEVICE_ID_CHICONY_USBHUB_KB	0x0100
+
+#define USB_VENDOR_ID_BTC		0x046e
+#define USB_DEVICE_ID_BTC_KEYBOARD	0x5303
+
+#define USB_VENDOR_ID_VERNIER		0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP	0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP	0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
+
+
+/*
+ * Alphabetically sorted blacklist by quirk type.
+ */
 
 static struct hid_blacklist {
 	__u16 idVendor;
@@ -1512,9 +1444,10 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
-	
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
@@ -1522,6 +1455,9 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
@@ -1530,6 +1466,10 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
@@ -1555,20 +1495,24 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-	
 
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
+	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 
 	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
 
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
@@ -1579,13 +1523,6 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
 
-	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-
 	{ 0, 0 }
 };
 
@@ -1695,6 +1632,10 @@ static struct hid_device *usb_hid_config
 		if (dev->speed == USB_SPEED_HIGH)
 			interval = 1 << (interval - 1);
 
+		/* Change the polling interval of mice. */
+		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+			interval = hid_mousepoll_interval;
+		
 		if (endpoint->bEndpointAddress & USB_DIR_IN) {
 			if (hid->urbin)
 				continue;
@@ -1724,7 +1665,7 @@ static struct hid_device *usb_hid_config
 	}
 
 	init_waitqueue_head(&hid->wait);
-	
+
 	spin_lock_init(&hid->outlock);
 	spin_lock_init(&hid->ctrllock);
 
@@ -1739,16 +1680,16 @@ static struct hid_device *usb_hid_config
 	if (!(buf = kmalloc(64, GFP_KERNEL)))
 		goto fail;
 
-	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
-		strcat(hid->name, buf);
-		if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
-			snprintf(hid->name, 64, "%s %s", hid->name, buf);
-	} else if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) {
-			snprintf(hid->name, 128, "%s", buf);
+	if (dev->manufacturer) {
+		strcat(hid->name, dev->manufacturer);
+		if (dev->product)
+			snprintf(hid->name, 64, "%s %s", hid->name, dev->product);
+	} else if (dev->product) {
+			snprintf(hid->name, 128, "%s", dev->product);
 	} else
-		snprintf(hid->name, 128, "%04x:%04x", 
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
+		snprintf(hid->name, 128, "%04x:%04x",
+			le16_to_cpu(dev->descriptor.idVendor),
+			le16_to_cpu(dev->descriptor.idProduct));
 
 	usb_make_path(dev, buf, 64);
 	snprintf(hid->phys, 64, "%s/input%d", buf,
@@ -1810,7 +1751,7 @@ static void hid_disconnect(struct usb_in
 	hid_free_device(hid);
 }
 
-static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id)
+static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct hid_device *hid;
 	char path[64];
@@ -1866,12 +1807,12 @@ static int hid_probe (struct usb_interfa
 	return 0;
 }
 
-static int hid_suspend(struct usb_interface *intf, u32 state)
+static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct hid_device *hid = usb_get_intfdata (intf);
 
 	usb_kill_urb(hid->urbin);
-	intf->dev.power.power_state = state;
+	intf->dev.power.power_state = PMSG_SUSPEND;
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 }
@@ -1881,7 +1822,7 @@ static int hid_resume(struct usb_interfa
 	struct hid_device *hid = usb_get_intfdata (intf);
 	int status;
 
-	intf->dev.power.power_state = PM_SUSPEND_ON;
+	intf->dev.power.power_state = PMSG_ON;
 	if (hid->open)
 		status = usb_submit_urb(hid->urbin, GFP_NOIO);
 	else
@@ -1892,7 +1833,7 @@ static int hid_resume(struct usb_interfa
 
 static struct usb_device_id hid_usb_ids [] = {
 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
-	    .bInterfaceClass = USB_INTERFACE_CLASS_HID },
+		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
 	{ }						/* Terminating entry */
 };
 
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -473,7 +473,6 @@ static void __attribute__((unused)) hid_
 
 
 static char *events[EV_MAX + 1] = {
-	[0 ... EV_MAX] = NULL,
 	[EV_SYN] = "Sync",			[EV_KEY] = "Key",
 	[EV_REL] = "Relative",			[EV_ABS] = "Absolute",
 	[EV_MSC] = "Misc",			[EV_LED] = "LED",
@@ -483,11 +482,9 @@ static char *events[EV_MAX + 1] = {
 };
 
 static char *syncs[2] = {
-	[0 ... 1] = NULL,
 	[SYN_REPORT] = "Report",		[SYN_CONFIG] = "Config",
 };
 static char *keys[KEY_MAX + 1] = {
-	[0 ... KEY_MAX] = NULL,
 	[KEY_RESERVED] = "Reserved",		[KEY_ESC] = "Esc",
 	[KEY_1] = "1",				[KEY_2] = "2",
 	[KEY_3] = "3",				[KEY_4] = "4",
@@ -665,7 +662,6 @@ static char *keys[KEY_MAX + 1] = {
 };
 
 static char *relatives[REL_MAX + 1] = {
-	[0 ... REL_MAX] = NULL,
 	[REL_X] = "X",			[REL_Y] = "Y",
 	[REL_Z] = "Z",			[REL_HWHEEL] = "HWheel",
 	[REL_DIAL] = "Dial",		[REL_WHEEL] = "Wheel", 
@@ -673,7 +669,6 @@ static char *relatives[REL_MAX + 1] = {
 };
 
 static char *absolutes[ABS_MAX + 1] = {
-	[0 ... ABS_MAX] = NULL,
 	[ABS_X] = "X",			[ABS_Y] = "Y",
 	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
 	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
@@ -690,13 +685,11 @@ static char *absolutes[ABS_MAX + 1] = {
 };
 
 static char *misc[MSC_MAX + 1] = {
-	[ 0 ... MSC_MAX] = NULL,
 	[MSC_SERIAL] = "Serial",	[MSC_PULSELED] = "Pulseled",
 	[MSC_GESTURE] = "Gesture",	[MSC_RAW] = "RawData"
 };
 
 static char *leds[LED_MAX + 1] = {
-	[0 ... LED_MAX] = NULL,
 	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock", 
 	[LED_SCROLLL] = "ScrollLock",	[LED_COMPOSE] = "Compose",
 	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep", 
@@ -705,25 +698,22 @@ static char *leds[LED_MAX + 1] = {
 };
 
 static char *repeats[REP_MAX + 1] = {
-	[0 ... REP_MAX] = NULL,
 	[REP_DELAY] = "Delay",		[REP_PERIOD] = "Period"
 };
 
 static char *sounds[SND_MAX + 1] = {
-	[0 ... SND_MAX] = NULL,
 	[SND_CLICK] = "Click",		[SND_BELL] = "Bell",
 	[SND_TONE] = "Tone"
 };
 
 static char **names[EV_MAX + 1] = {
-	[0 ... EV_MAX] = NULL,
 	[EV_SYN] = syncs,			[EV_KEY] = keys,
 	[EV_REL] = relatives,			[EV_ABS] = absolutes,
 	[EV_MSC] = misc,			[EV_LED] = leds,
 	[EV_SND] = sounds,			[EV_REP] = repeats,
 };
 
-static void resolv_event(__u8 type, __u16 code) {
+static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
 
 	printk("%s.%s", events[type] ? events[type] : "?",
 		names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -55,6 +55,7 @@ static struct hid_ff_initializer inits[]
 	{0x46d, 0xc211, hid_lgff_init}, // Logitech Cordless rumble pad
 	{0x46d, 0xc283, hid_lgff_init}, // Logitech Wingman Force 3d
 	{0x46d, 0xc295, hid_lgff_init},	// Logitech MOMO force wheel
+	{0x46d, 0xc219, hid_lgff_init}, // Logitech Cordless rumble pad 2
 #endif
 #ifdef CONFIG_HID_PID
 	{0x45e, 0x001b, hid_pid_init},
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -404,7 +404,6 @@ void hidinput_hid_event(struct hid_devic
 		return;
 
 	input_regs(input, regs);
-	input_event(input, EV_MSC, MSC_SCAN, usage->hid);
 
 	if (!usage->type)
 		return;
@@ -483,10 +482,26 @@ void hidinput_report_event(struct hid_de
 	}
 }
 
+static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+	struct hid_report *report;
+	int i, j;
+
+	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			*field = report->field[i];
+			for (j = 0; j < (*field)->maxusage; j++)
+				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+					return j;
+		}
+	}
+	return -1;
+}
+
 static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct hid_device *hid = dev->private;
-	struct hid_field *field = NULL;
+	struct hid_field *field;
 	int offset;
 
 	if (type == EV_FF)
@@ -495,7 +510,7 @@ static int hidinput_input_event(struct i
 	if (type != EV_LED)
 		return -1;
 
-	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
+	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
 		warn("event field not found");
 		return -1;
 	}
@@ -527,9 +542,7 @@ static void hidinput_close(struct input_
 int hidinput_connect(struct hid_device *hid)
 {
 	struct usb_device *dev = hid->dev;
-	struct hid_report_enum *report_enum;
 	struct hid_report *report;
-	struct list_head *list;
 	struct hid_input *hidinput = NULL;
 	int i, j, k;
 
@@ -544,16 +557,11 @@ int hidinput_connect(struct hid_device *
 	if (i == hid->maxcollection)
 		return -1;
 
-	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
-		report_enum = hid->report_enum + k;
-		list = report_enum->report_list.next;
-		while (list != &report_enum->report_list) {
-			report = (struct hid_report *) list;
+	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
 
-			if (!report->maxfield) {
-				list = list->next;
+			if (!report->maxfield)
 				continue;
-			}
 
 			if (!hidinput) {
 				hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL);
@@ -578,9 +586,6 @@ int hidinput_connect(struct hid_device *
 				hidinput->input.id.product = le16_to_cpu(dev->descriptor.idProduct);
 				hidinput->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
 				hidinput->input.dev = &hid->intf->dev;
-
-				set_bit(EV_MSC, hidinput->input.evbit);
-				set_bit(MSC_SCAN, hidinput->input.mscbit);
 			}
 
 			for (i = 0; i < report->maxfield; i++)
@@ -598,10 +603,7 @@ int hidinput_connect(struct hid_device *
 				input_register_device(&hidinput->input);
 				hidinput = NULL;
 			}
-
-			list = list->next;
 		}
-	}
 
 	/* This only gets called when we are a single-input (most of the
 	 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
@@ -619,7 +621,7 @@ void hidinput_disconnect(struct hid_devi
 	struct list_head *lh, *next;
 	struct hid_input *hidinput;
 
-	list_for_each_safe (lh, next, &hid->inputs) {
+	list_for_each_safe(lh, next, &hid->inputs) {
 		hidinput = list_entry(lh, struct hid_input, list);
 		input_unregister_device(&hidinput->input);
 		list_del(&hidinput->list);
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -126,6 +126,7 @@ static signed short ff_joystick[] = {
 
 static struct device_type devices[] = {
 	{0x046d, 0xc211, ff_rumble},
+	{0x046d, 0xc219, ff_rumble},
 	{0x046d, 0xc283, ff_joystick},
 	{0x0000, 0x0000, ff_joystick}
 };
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -484,11 +484,10 @@ static inline void hidinput_disconnect(s
 
 int hid_open(struct hid_device *);
 void hid_close(struct hid_device *);
-int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **);
 int hid_set_field(struct hid_field *, unsigned, __s32);
 void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
 void hid_init_reports(struct hid_device *hid);
-int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type);
+struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type);
 int hid_wait_io(struct hid_device* hid);
 
 
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -124,7 +124,6 @@ hiddev_lookup_usage(struct hid_device *h
 	int i, j;
 	struct hid_report *report;
 	struct hid_report_enum *report_enum;
-	struct list_head *list;
 	struct hid_field *field;
 
 	if (uref->report_type < HID_REPORT_TYPE_MIN ||
@@ -132,9 +131,8 @@ hiddev_lookup_usage(struct hid_device *h
 
 	report_enum = hid->report_enum +
 		(uref->report_type - HID_REPORT_TYPE_MIN);
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
+
+	list_for_each_entry(report, &report_enum->report_list, list)
 		for (i = 0; i < report->maxfield; i++) {
 			field = report->field[i];
 			for (j = 0; j < field->maxusage; j++) {
@@ -146,8 +144,6 @@ hiddev_lookup_usage(struct hid_device *h
 				}
 			}
 		}
-		list = list->next;
-	}
 
 	return NULL;
 }
@@ -634,9 +630,8 @@ static int hiddev_ioctl(struct inode *in
 				goto inval;
 
 			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-				 (uref_multi->num_values >= HID_MAX_MULTI_USAGES ||
-				  uref->usage_index + uref_multi->num_values >= field->report_count ||
-				  uref->usage_index + uref_multi->num_values < uref->usage_index))
+				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+				  uref->usage_index + uref_multi->num_values >= field->report_count))
 				goto inval;
 			}
 
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -32,7 +32,10 @@
  *    Changed reset from standard USB dev reset to vendor reset
  *    Changed data sent to host from compensated to raw coordinates
  *    Eliminated vendor/product module params
- *    Performed multiple successfull tests with an EXII-5010UC
+ *    Performed multiple successful tests with an EXII-5010UC
+ *
+ *  1.5 02/27/2005 ddstreet@ieee.org
+ *    Added module parameter to select raw or hw-calibrated coordinate reporting
  *
  *****************************************************************************/
 
@@ -52,11 +55,13 @@
 #include <linux/usb.h>
 
 #define MTOUCHUSB_MIN_XC                0x0
-#define MTOUCHUSB_MAX_XC                0x4000
+#define MTOUCHUSB_MAX_RAW_XC            0x4000
+#define MTOUCHUSB_MAX_CALIB_XC          0xffff
 #define MTOUCHUSB_XC_FUZZ               0x0
 #define MTOUCHUSB_XC_FLAT               0x0
 #define MTOUCHUSB_MIN_YC                0x0
-#define MTOUCHUSB_MAX_YC                0x4000
+#define MTOUCHUSB_MAX_RAW_YC            0x4000
+#define MTOUCHUSB_MAX_CALIB_YC          0xffff
 #define MTOUCHUSB_YC_FUZZ               0x0
 #define MTOUCHUSB_YC_FLAT               0x0
 
@@ -65,15 +70,28 @@
 #define MTOUCHUSB_REPORT_DATA_SIZE      11
 #define MTOUCHUSB_REQ_CTRLLR_ID         10
 
-#define MTOUCHUSB_GET_XC(data)          (data[8]<<8 | data[7])
-#define MTOUCHUSB_GET_YC(data)          (data[10]<<8 | data[9])
+#define MTOUCHUSB_GET_RAW_XC(data)      (data[8]<<8 | data[7])
+#define MTOUCHUSB_GET_CALIB_XC(data)    (data[4]<<8 | data[3])
+#define MTOUCHUSB_GET_RAW_YC(data)      (data[10]<<8 | data[9])
+#define MTOUCHUSB_GET_CALIB_YC(data)    (data[6]<<8 | data[5])
+#define MTOUCHUSB_GET_XC(data)          (raw_coordinates ? \
+                                         MTOUCHUSB_GET_RAW_XC(data) : \
+                                         MTOUCHUSB_GET_CALIB_XC(data))
+#define MTOUCHUSB_GET_YC(data)          (raw_coordinates ? \
+                                         MTOUCHUSB_GET_RAW_YC(data) : \
+                                         MTOUCHUSB_GET_CALIB_YC(data))
 #define MTOUCHUSB_GET_TOUCHED(data)     ((data[2] & 0x40) ? 1:0)
 
-#define DRIVER_VERSION "v1.4"
+#define DRIVER_VERSION "v1.5"
 #define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
 #define DRIVER_DESC "3M USB Touchscreen Driver"
 #define DRIVER_LICENSE "GPL"
 
+static int raw_coordinates = 1;
+
+module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
+
 struct mtouch_usb {
         unsigned char *data;
         dma_addr_t data_dma;
@@ -123,7 +141,8 @@ static void mtouchusb_irq(struct urb *ur
         input_report_abs(&mtouch->input, ABS_X,
                          MTOUCHUSB_GET_XC(mtouch->data));
         input_report_abs(&mtouch->input, ABS_Y,
-                         MTOUCHUSB_GET_YC(mtouch->data));
+			 (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
+                         - MTOUCHUSB_GET_YC(mtouch->data));
         input_sync(&mtouch->input);
 
 exit:
@@ -187,7 +206,6 @@ static int mtouchusb_probe(struct usb_in
         struct usb_endpoint_descriptor *endpoint;
         struct usb_device *udev = interface_to_usbdev (intf);
         char path[64];
-        char *buf;
         int nRet;
 
         dbg("%s - called", __FUNCTION__);
@@ -234,32 +252,25 @@ static int mtouchusb_probe(struct usb_in
 
         /* Used to Scale Compensated Data and Flip Y */
         mtouch->input.absmin[ABS_X] =  MTOUCHUSB_MIN_XC;
-        mtouch->input.absmax[ABS_X] =  MTOUCHUSB_MAX_XC;
+        mtouch->input.absmax[ABS_X] =  raw_coordinates ? \
+                                       MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
         mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
         mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
         mtouch->input.absmin[ABS_Y] =  MTOUCHUSB_MIN_YC;
-        mtouch->input.absmax[ABS_Y] =  MTOUCHUSB_MAX_YC;
+        mtouch->input.absmax[ABS_Y] =  raw_coordinates ? \
+                                       MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
         mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
         mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
 
-        if (!(buf = kmalloc(63, GFP_KERNEL))) {
-                kfree(mtouch);
-                return -ENOMEM;
-        }
-
-        if (udev->descriptor.iManufacturer &&
-            usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
-                        strcat(mtouch->name, buf);
-        if (udev->descriptor.iProduct &&
-            usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
-                        sprintf(mtouch->name, "%s %s", mtouch->name, buf);
+	if (udev->manufacturer)
+		strcat(mtouch->name, udev->manufacturer);
+	if (udev->product)
+		sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
 
         if (!strlen(mtouch->name))
                 sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
                         mtouch->input.id.vendor, mtouch->input.id.product);
 
-        kfree(buf);
-
         nRet = usb_control_msg(mtouch->udev,
                                usb_rcvctrlpipe(udev, 0),
                                MTOUCHUSB_RESET,
@@ -268,7 +279,7 @@ static int mtouchusb_probe(struct usb_in
                                0,
                                NULL,
                                0,
-                               HZ * USB_CTRL_SET_TIMEOUT);
+                               USB_CTRL_SET_TIMEOUT);
         dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
             __FUNCTION__, nRet);
 
@@ -302,7 +313,7 @@ static int mtouchusb_probe(struct usb_in
                                1,
                                NULL,
                                0,
-                               HZ * USB_CTRL_SET_TIMEOUT);
+                               USB_CTRL_SET_TIMEOUT);
         dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
             __FUNCTION__, nRet);
 
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- a/drivers/usb/input/pid.c
+++ b/drivers/usb/input/pid.c
@@ -48,106 +48,96 @@
 /* Called when a transfer is completed */
 static void hid_pid_ctrl_out(struct urb *u, struct pt_regs *regs)
 {
-    dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
+	dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
 }
 
-static void hid_pid_exit(struct hid_device* hid)
+static void hid_pid_exit(struct hid_device *hid)
 {
-    struct hid_ff_pid *private = hid->ff_private;
-    
-    if (private->urbffout) {
-	usb_kill_urb(private->urbffout);
-	usb_free_urb(private->urbffout);
-    }
+	struct hid_ff_pid *private = hid->ff_private;
+
+	if (private->urbffout) {
+		usb_kill_urb(private->urbffout);
+		usb_free_urb(private->urbffout);
+	}
 }
 
-static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
-    return 0;
+static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
+	return 0;
 }
 
-static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
-    return 0;
+static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
+	return 0;
 }
 
-static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
-    return 0;
+static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
+	return 0;
 }
 
-static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
-    return 0;
+static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
+	return 0;
 }
 
 static int hid_pid_event(struct hid_device *hid, struct input_dev *input,
-			  unsigned int type, unsigned int code, int value)
+			 unsigned int type, unsigned int code, int value)
 {
-    dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
+	dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
 
-    if (type != EV_FF)
-	return -1;
+	if (type != EV_FF)
+		return -1;
 
-    
-
-    return 0;
+	return 0;
 }
 
 /* Lock must be held by caller */
-static void hid_pid_ctrl_playback(struct hid_device *hid,
-				   struct hid_pid_effect *effect, int play)
+static void hid_pid_ctrl_playback(struct hid_device *hid, struct hid_pid_effect *effect, int play)
 {
-	if (play) {
+	if (play)
 		set_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
-
-	} else {
+	else
 		clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
-	}
 }
 
-
 static int hid_pid_erase(struct input_dev *dev, int id)
 {
 	struct hid_device *hid = dev->private;
-	struct hid_field* field;
-	struct hid_report* report;
 	struct hid_ff_pid *pid = hid->ff_private;
+	struct hid_field *field;
 	unsigned long flags;
-	unsigned wanted_report = HID_UP_PID | FF_PID_USAGE_BLOCK_FREE;  /*  PID Block Free Report */
 	int ret;
 
 	if (!CHECK_OWNERSHIP(id, pid))
 		return -EACCES;
 
 	/* Find report */
-	ret =  hid_find_report_by_usage(hid, wanted_report, &report, HID_OUTPUT_REPORT);
-	if(!ret) {
+	field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE,
+					HID_OUTPUT_REPORT);
+	if (!field) {
 		dev_err(&hid->dev->dev, "couldn't find report\n");
-		return ret;
-	}
-
-	/* Find field */
-	field = (struct hid_field *) kmalloc(sizeof(struct hid_field), GFP_KERNEL);
-	if(!field) {
-		dev_err(&hid->dev->dev, "couldn't allocate field\n");
-		return -ENOMEM;
+		return -EIO;
 	}
 
-	ret = hid_set_field(field, ret, pid->effects[id].device_id);
-	if(!ret) {
+	ret = hid_set_field(field, 0, pid->effects[id].device_id);
+	if (ret) {
 		dev_err(&hid->dev->dev, "couldn't set field\n");
 		return ret;
 	}
 
-	hid_submit_report(hid, report, USB_DIR_OUT);
+	hid_submit_report(hid, field->report, USB_DIR_OUT);
 
 	spin_lock_irqsave(&pid->lock, flags);
 	hid_pid_ctrl_playback(hid, pid->effects + id, 0);
 	pid->effects[id].flags = 0;
 	spin_unlock_irqrestore(&pid->lock, flags);
 
-	return ret;
+	return 0;
 }
 
 /* Erase all effects this process owns */
@@ -158,31 +148,32 @@ static int hid_pid_flush(struct input_de
 	int i;
 
 	/*NOTE: no need to lock here. The only times EFFECT_USED is
-	  modified is when effects are uploaded or when an effect is
-	  erased. But a process cannot close its dev/input/eventX fd
-	  and perform ioctls on the same fd all at the same time */
-	for (i=0; i<dev->ff_effects_max; ++i)
-		if ( current->pid == pid->effects[i].owner
-		     && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
+	   modified is when effects are uploaded or when an effect is
+	   erased. But a process cannot close its dev/input/eventX fd
+	   and perform ioctls on the same fd all at the same time */
+	/*FIXME: multiple threads, anyone? */
+	for (i = 0; i < dev->ff_effects_max; ++i)
+		if (current->pid == pid->effects[i].owner
+		    && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
 			if (hid_pid_erase(dev, i))
 				dev_warn(&hid->dev->dev, "erase effect %d failed", i);
 
 	return 0;
 }
 
-
 static int hid_pid_upload_effect(struct input_dev *dev,
-				  struct ff_effect *effect)
+				 struct ff_effect *effect)
 {
-	struct hid_ff_pid* pid_private  = (struct hid_ff_pid*)(dev->private);
+	struct hid_ff_pid *pid_private = (struct hid_ff_pid *)(dev->private);
 	int ret;
 	int is_update;
-	unsigned long flags = 0;
+	unsigned long flags;
 
-        dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n",effect->type);
+	dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n", effect->type);
 	/* Check this effect type is supported by this device */
 	if (!test_bit(effect->type, dev->ffbit)) {
-		dev_dbg(&pid_private->hid->dev->dev, "invalid kind of effect requested.\n");
+		dev_dbg(&pid_private->hid->dev->dev,
+			"invalid kind of effect requested.\n");
 		return -EINVAL;
 	}
 
@@ -190,31 +181,30 @@ static int hid_pid_upload_effect(struct 
 	 * If we want to create a new effect, get a free id
 	 */
 	if (effect->id == -1) {
-		int id=0;
+		int id = 0;
 
 		// Spinlock so we don`t get a race condition when choosing IDs
 		spin_lock_irqsave(&pid_private->lock, flags);
 
-		while(id < FF_EFFECTS_MAX)
-			if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags)) 
-			    break;
+		while (id < FF_EFFECTS_MAX)
+			if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags))
+				break;
 
-		if ( id == FF_EFFECTS_MAX) {
-			spin_unlock_irqrestore(&pid_private->lock,flags);
+		if (id == FF_EFFECTS_MAX) {
+			spin_unlock_irqrestore(&pid_private->lock, flags);
 // TEMP - We need to get ff_effects_max correctly first:  || id >= dev->ff_effects_max) {
 			dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
 			return -ENOMEM;
 		}
 
 		effect->id = id;
-		dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d\n.",id);
+		dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d\n.", id);
 		pid_private->effects[id].owner = current->pid;
-		pid_private->effects[id].flags = (1<<FF_PID_FLAGS_USED);
-		spin_unlock_irqrestore(&pid_private->lock,flags);
+		pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED);
+		spin_unlock_irqrestore(&pid_private->lock, flags);
 
 		is_update = FF_PID_FALSE;
-	}
-	else {
+	} else {
 		/* We want to update an effect */
 		if (!CHECK_OWNERSHIP(effect->id, pid_private))
 			return -EACCES;
@@ -224,9 +214,8 @@ static int hid_pid_upload_effect(struct 
 			return -EINVAL;
 
 		/* Check the effect is not already being updated */
-		if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags)) {
+		if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags))
 			return -EAGAIN;
-		}
 
 		is_update = FF_PID_TRUE;
 	}
@@ -235,28 +224,30 @@ static int hid_pid_upload_effect(struct 
 	 * Upload the effect
 	 */
 	switch (effect->type) {
-		case FF_PERIODIC:
-			ret = pid_upload_periodic(pid_private, effect, is_update);
-			break;
-
-		case FF_CONSTANT:
-			ret = pid_upload_constant(pid_private, effect, is_update);
-			break;
-
-		case FF_SPRING:
-		case FF_FRICTION:
-		case FF_DAMPER:
-		case FF_INERTIA:
-			ret = pid_upload_condition(pid_private, effect, is_update);
-			break;
-
-		case FF_RAMP:
-			ret = pid_upload_ramp(pid_private, effect, is_update);
-			break;
-
-		default:
-			dev_dbg(&pid_private->hid->dev->dev, "invalid type of effect requested - %x.\n", effect->type);
-			return -EINVAL;
+	case FF_PERIODIC:
+		ret = pid_upload_periodic(pid_private, effect, is_update);
+		break;
+
+	case FF_CONSTANT:
+		ret = pid_upload_constant(pid_private, effect, is_update);
+		break;
+
+	case FF_SPRING:
+	case FF_FRICTION:
+	case FF_DAMPER:
+	case FF_INERTIA:
+		ret = pid_upload_condition(pid_private, effect, is_update);
+		break;
+
+	case FF_RAMP:
+		ret = pid_upload_ramp(pid_private, effect, is_update);
+		break;
+
+	default:
+		dev_dbg(&pid_private->hid->dev->dev,
+			"invalid type of effect requested - %x.\n",
+			effect->type);
+		return -EINVAL;
 	}
 	/* If a packet was sent, forbid new updates until we are notified
 	 * that the packet was updated
@@ -269,37 +260,36 @@ static int hid_pid_upload_effect(struct 
 
 int hid_pid_init(struct hid_device *hid)
 {
-    struct hid_ff_pid *private;
-    struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+	struct hid_ff_pid *private;
+	struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
 
-    private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
-    if (!private) return -1;
-    
-    memset(private,0,sizeof(struct hid_ff_pid));
-
-    hid->ff_private = private; /* 'cause memset can move the block away */
-
-    private->hid = hid;
-    
-    hid->ff_exit = hid_pid_exit;
-    hid->ff_event = hid_pid_event;
-    
-    /* Open output URB */
-    if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
-	kfree(private);
-	return -1;
-    }
-
-    usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid);
-    hidinput->input.upload_effect = hid_pid_upload_effect;
-    hidinput->input.flush = hid_pid_flush;
-    hidinput->input.ff_effects_max = 8;  // A random default
-    set_bit(EV_FF, hidinput->input.evbit);
-    set_bit(EV_FF_STATUS, hidinput->input.evbit);
-
-    spin_lock_init(&private->lock);
-
-    printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
-    
-    return 0;    
+	private = hid->ff_private = kcalloc(1, sizeof(struct hid_ff_pid), GFP_KERNEL);
+	if (!private)
+		return -ENOMEM;
+
+	private->hid = hid;
+
+	hid->ff_exit = hid_pid_exit;
+	hid->ff_event = hid_pid_event;
+
+	/* Open output URB */
+	if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+		kfree(private);
+		return -1;
+	}
+
+	usb_fill_control_urb(private->urbffout, hid->dev, 0,
+			     (void *)&private->ffcr, private->ctrl_buffer, 8,
+			     hid_pid_ctrl_out, hid);
+	hidinput->input.upload_effect = hid_pid_upload_effect;
+	hidinput->input.flush = hid_pid_flush;
+	hidinput->input.ff_effects_max = 8;	// A random default
+	set_bit(EV_FF, hidinput->input.evbit);
+	set_bit(EV_FF_STATUS, hidinput->input.evbit);
+
+	spin_lock_init(&private->lock);
+
+	printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
+
+	return 0;
 }
diff --git a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h
--- a/drivers/usb/input/pid.h
+++ b/drivers/usb/input/pid.h
@@ -25,31 +25,31 @@
 
 #define FF_EFFECTS_MAX 64
 
-#define FF_PID_FLAGS_USED	1  /* If the effect exists */
-#define FF_PID_FLAGS_UPDATING	2  /* If the effect is being updated */
-#define FF_PID_FLAGS_PLAYING	3  /* If the effect is currently being played */
+#define FF_PID_FLAGS_USED	1	/* If the effect exists */
+#define FF_PID_FLAGS_UPDATING	2	/* If the effect is being updated */
+#define FF_PID_FLAGS_PLAYING	3	/* If the effect is currently being played */
 
 #define FF_PID_FALSE	0
 #define FF_PID_TRUE	1
 
 struct hid_pid_effect {
-    unsigned long flags;
-    pid_t owner;
-    unsigned int device_id;  // The device-assigned ID
-    struct ff_effect effect;
+	unsigned long flags;
+	pid_t owner;
+	unsigned int device_id;	/* The device-assigned ID */
+	struct ff_effect effect;
 };
 
 struct hid_ff_pid {
-    struct hid_device *hid;
-    unsigned long int gain;
+	struct hid_device *hid;
+	unsigned long gain;
 
-    struct urb *urbffout;
-    struct usb_ctrlrequest ffcr;
-    spinlock_t lock;
+	struct urb *urbffout;
+	struct usb_ctrlrequest ffcr;
+	spinlock_t lock;
 
-    char ctrl_buffer[8];
+	unsigned char ctrl_buffer[8];
 
-    struct hid_pid_effect effects[FF_EFFECTS_MAX];
+	struct hid_pid_effect effects[FF_EFFECTS_MAX];
 };
 
 /*
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -320,7 +320,7 @@ static int powermate_probe(struct usb_in
 	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 		0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0, interface->desc.bInterfaceNumber, NULL, 0,
-		HZ * USB_CTRL_SET_TIMEOUT);
+		USB_CTRL_SET_TIMEOUT);
 
 	if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
 		return -ENOMEM;
@@ -395,6 +395,7 @@ static int powermate_probe(struct usb_in
 	pm->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
 	pm->input.event = powermate_input_event;
 	pm->input.dev = &intf->dev;
+	pm->input.phys = pm->phys;
 
 	input_register_device(&pm->input);
 
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -184,7 +184,6 @@ static int touchkit_probe(struct usb_int
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_device *udev = interface_to_usbdev(intf);
 	char path[64];
-	char *buf;
 
 	interface = intf->cur_altsetting;
 	endpoint = &interface->endpoint[0].desc;
@@ -230,25 +229,15 @@ static int touchkit_probe(struct usb_int
 	touchkit->input.absfuzz[ABS_Y] = TOUCHKIT_YC_FUZZ;
 	touchkit->input.absflat[ABS_Y] = TOUCHKIT_YC_FLAT;
 
-	buf = kmalloc(63, GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto out_free_buffers;
-	}
-
-	if (udev->descriptor.iManufacturer &&
-	    usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
-		strcat(touchkit->name, buf);
-	if (udev->descriptor.iProduct &&
-	    usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
-		sprintf(touchkit->name, "%s %s", touchkit->name, buf);
+	if (udev->manufacturer)
+		strcat(touchkit->name, udev->manufacturer);
+	if (udev->product)
+		sprintf(touchkit->name, "%s %s", touchkit->name, udev->product);
 
 	if (!strlen(touchkit->name))
 		sprintf(touchkit->name, "USB Touchscreen %04x:%04x",
 		        touchkit->input.id.vendor, touchkit->input.id.product);
 
-	kfree(buf);
-
 	touchkit->irq = usb_alloc_urb(0, GFP_KERNEL);
 	if (!touchkit->irq) {
 		dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__);
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -133,7 +133,8 @@ resubmit:
 				kbd->usbdev->devpath, i);
 }
 
-int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int usb_kbd_event(struct input_dev *dev, unsigned int type,
+			 unsigned int code, int value)
 {
 	struct usb_kbd *kbd = dev->private;
 
@@ -238,7 +239,6 @@ static int usb_kbd_probe(struct usb_inte
 	struct usb_kbd *kbd;
 	int i, pipe, maxp;
 	char path[64];
-	char *buf;
 
 	interface = iface->cur_altsetting;
 
@@ -301,26 +301,15 @@ static int usb_kbd_probe(struct usb_inte
 	kbd->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
 	kbd->dev.dev = &iface->dev;
 
-	if (!(buf = kmalloc(63, GFP_KERNEL))) {
-		usb_free_urb(kbd->irq);
-		usb_kbd_free_mem(dev, kbd);
-		kfree(kbd);
-		return -ENOMEM;
-	}
-
-	if (dev->descriptor.iManufacturer &&
-		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
-			strcat(kbd->name, buf);
-	if (dev->descriptor.iProduct &&
-		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
-			sprintf(kbd->name, "%s %s", kbd->name, buf);
+	if (dev->manufacturer)
+		strcat(kbd->name, dev->manufacturer);
+	if (dev->product)
+		sprintf(kbd->name, "%s %s", kbd->name, dev->product);
 
 	if (!strlen(kbd->name))
 		sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x",
 			kbd->dev.id.vendor, kbd->dev.id.product);
 
-	kfree(buf);
-
 	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
 			     (void *) kbd->cr, kbd->leds, 1,
 			     usb_kbd_led, kbd);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -129,7 +129,6 @@ static int usb_mouse_probe(struct usb_in
 	struct usb_mouse *mouse;
 	int pipe, maxp;
 	char path[64];
-	char *buf;
 
 	interface = intf->cur_altsetting;
 
@@ -185,25 +184,15 @@ static int usb_mouse_probe(struct usb_in
 	mouse->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
 	mouse->dev.dev = &intf->dev;
 
-	if (!(buf = kmalloc(63, GFP_KERNEL))) {
-		usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
-		kfree(mouse);
-		return -ENOMEM;
-	}
-
-	if (dev->descriptor.iManufacturer &&
-		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
-			strcat(mouse->name, buf);
-	if (dev->descriptor.iProduct &&
-		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
-			sprintf(mouse->name, "%s %s", mouse->name, buf);
+	if (dev->manufacturer)
+		strcat(mouse->name, dev->manufacturer);
+	if (dev->product)
+		sprintf(mouse->name, "%s %s", mouse->name, dev->product);
 
 	if (!strlen(mouse->name))
 		sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x",
 			mouse->dev.id.vendor, mouse->dev.id.product);
 
-	kfree(buf);
-
 	usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
 			 (maxp > 8 ? 8 : maxp),
 			 usb_mouse_irq, mouse, endpoint->bInterval);
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -72,7 +72,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.30"
+#define DRIVER_VERSION "v1.40"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -115,7 +115,7 @@ static int usb_set_report(struct usb_int
 		usb_sndctrlpipe(interface_to_usbdev(intf), 0),
                 USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                 (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
-		buf, size, HZ);
+		buf, size, 1000);
 }
 
 static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
@@ -141,8 +141,10 @@ static void wacom_pl_irq(struct urb *urb
 		goto exit;
 	}
 
-	if (data[0] != 2)
+	if (data[0] != 2) {
 		dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
 
 	prox = data[1] & 0x40;
 
@@ -233,6 +235,7 @@ static void wacom_ptu_irq(struct urb *ur
 	if (data[0] != 2)
 	{
 		printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+		goto exit;
 	}
 
 	input_regs(dev, regs);
@@ -246,9 +249,9 @@ static void wacom_ptu_irq(struct urb *ur
 		input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
 		input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
 	}
-	input_report_abs(dev, ABS_X, data[3] << 8 | data[2]);
-	input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]);
-	input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8));
+	input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
+	input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
+	input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
 	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
 	input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
 
@@ -283,10 +286,15 @@ static void wacom_penpartner_irq(struct 
 		goto exit;
 	}
 
+	if (data[0] != 2) {
+		printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+		goto exit;
+	}
+
 	input_regs(dev, regs);
 	input_report_key(dev, BTN_TOOL_PEN, 1);
-	input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((__le16 *) &data[1])));
-	input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((__le16 *) &data[3])));
+	input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
+	input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
 	input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
 	input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
 	input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
@@ -322,12 +330,10 @@ static void wacom_graphire_irq(struct ur
 		goto exit;
 	}
 
-	/* check if we can handle the data */
-	if (data[0] == 99)
-		goto exit;
-
-	if (data[0] != 2)
+	if (data[0] != 2) {
 		dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
 
 	x = le16_to_cpu(*(__le16 *) &data[2]);
 	y = le16_to_cpu(*(__le16 *) &data[4]);
@@ -381,107 +387,171 @@ exit:
 		     __FUNCTION__, retval);
 }
 
-static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+static int wacom_intuos_inout(struct urb *urb)
 {
 	struct wacom *wacom = urb->context;
 	unsigned char *data = wacom->data;
 	struct input_dev *dev = &wacom->dev;
-	unsigned int t;
 	int idx;
-	int retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	if (data[0] != 2)
-		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
-
-	input_regs(dev, regs);
 
 	/* tool number */
 	idx = data[1] & 0x01;
 
-	if ((data[1] & 0xfc) == 0xc0) {						/* Enter report */
-
-		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +		/* serial number of the tool */
+	/* Enter report */
+	if ((data[1] & 0xfc) == 0xc0)
+	{
+		/* serial number of the tool */
+		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
 			((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
 			((__u32)data[6] << 4) + (data[7] >> 4);
 
 		switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
-			case 0x812:
-			case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;		break;	/* Inking pen */
-			case 0x822:
+			case 0x812: /* Inking pen */
+			case 0x801: /* Intuos3 Inking pen */
+			case 0x012:
+				wacom->tool[idx] = BTN_TOOL_PENCIL;
+				break;
+			case 0x822: /* Pen */
 			case 0x842:
 			case 0x852:
-			case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Pen */
-			case 0x832:
-			case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;		break;	/* Stroke pen */
-			case 0x007:
+			case 0x823: /* Intuos3 Grip Pen */
+			case 0x813: /* Intuos3 Classic Pen */
+			case 0x885: /* Intuos3 Marker Pen */
+			case 0x022:
+				wacom->tool[idx] = BTN_TOOL_PEN;
+				break;
+			case 0x832: /* Stroke pen */
+			case 0x032:
+				wacom->tool[idx] = BTN_TOOL_BRUSH;
+				break;
+			case 0x007: /* Mouse 4D and 2D */
 		        case 0x09c:
-			case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;		break;	/* Mouse 4D and 2D */
-			case 0x096: wacom->tool[idx] = BTN_TOOL_LENS;		break;	/* Lens cursor */
-			case 0x82a:
+			case 0x094:
+			case 0x017: /* Intuos3 2D Mouse */
+				wacom->tool[idx] = BTN_TOOL_MOUSE;
+				break;
+			case 0x096: /* Lens cursor */
+			case 0x097: /* Intuos3 Lens cursor */
+				wacom->tool[idx] = BTN_TOOL_LENS;
+				break;
+			case 0x82a: /* Eraser */
 			case 0x85a:
 		        case 0x91a:
 			case 0xd1a:
-			case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;		break;	/* Eraser */
+			case 0x0fa:
+			case 0x82b: /* Intuos3 Grip Pen Eraser */
+			case 0x81b: /* Intuos3 Classic Pen Eraser */
+			case 0x91b: /* Intuos3 Airbrush Eraser */
+				wacom->tool[idx] = BTN_TOOL_RUBBER;
+				break;
 			case 0xd12:
 			case 0x912:
-			case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
-			default:    wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Unknown tool */
+			case 0x112:
+			case 0x913: /* Intuos3 Airbrush */
+				wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+				break;	/* Airbrush */
+			default: /* Unknown tool */
+				wacom->tool[idx] = BTN_TOOL_PEN;
 		}
-
 		input_report_key(dev, wacom->tool[idx], 1);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 		input_sync(dev);
-		goto exit;
+		return 1;
 	}
 
-	if ((data[1] & 0xfe) == 0x80) {						/* Exit report */
+	/* Exit report */
+	if ((data[1] & 0xfe) == 0x80) {
 		input_report_key(dev, wacom->tool[idx], 0);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 		input_sync(dev);
-		goto exit;
+		return 1;
 	}
 
-	input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
-	input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
-	input_report_abs(dev, ABS_DISTANCE, data[9]);
+	return 0;
+}
 
-	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
-		input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-		input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+static void wacom_intuos_general(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+
+	/* general pen packet */
+	if ((data[1] & 0xb8) == 0xa0)
+	{
+		t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+		input_report_abs(dev, ABS_PRESSURE, t);
+		input_report_abs(dev, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
 		input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
 		input_report_key(dev, BTN_STYLUS, data[1] & 2);
 		input_report_key(dev, BTN_STYLUS2, data[1] & 4);
 		input_report_key(dev, BTN_TOUCH, t > 10);
 	}
 
-	if ((data[1] & 0xbc) == 0xb4) {						/* airbrush second packet */
-		input_report_abs(dev, ABS_WHEEL, ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-		input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+	/* airbrush second packet */
+	if ((data[1] & 0xbc) == 0xb4)
+	{
+		input_report_abs(dev, ABS_WHEEL,
+				((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+		input_report_abs(dev, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
 		input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
 	}
+	return;
+}
+
+static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+	int idx;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
+
+	input_regs(dev, regs);
+
+	/* tool number */
+	idx = data[1] & 0x01;
+
+	/* process in/out prox events */
+	if (wacom_intuos_inout(urb)) goto exit;
+
+	input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
+	input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
+	input_report_abs(dev, ABS_DISTANCE, data[9]);
+
+	/* process general packets */
+	wacom_intuos_general(urb);
 	
 	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {		/* 4D mouse or Lens cursor packets */
 
 		if (data[1] & 0x02) {						/* Rotation packet */
 
-			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
-					 ((__u32)data[6] << 3) | ((data[7] >> 5) & 7):
-					 (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1);
+			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
 
 		} else {
 
@@ -493,9 +563,8 @@ static void wacom_intuos_irq(struct urb 
 
 				input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
 				input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-				input_report_abs(dev, ABS_THROTTLE,  -((data[8] & 0x08) ?
-						 ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
-						 -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)));
+				t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+				input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
 
 			} else {
 				if (wacom->tool[idx] == BTN_TOOL_MOUSE) {	/* 2D mouse packets */	
@@ -527,6 +596,111 @@ exit:
 		     __FUNCTION__, retval);
 }
 
+static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+	int idx, retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	/* check for valid report */
+	if (data[0] != 2 && data[0] != 5 && data[0] != 12)
+	{
+		printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
+		goto exit;
+	}
+
+	input_regs(dev, regs);
+
+	/* tool index is always 0 here since there is no dual input tool */
+	idx = data[1] & 0x01;
+
+	/* pad packets. Works as a second tool and is always in prox */
+	if (data[0] == 12)
+	{
+		/* initiate the pad as a device */
+		if (wacom->tool[1] != BTN_TOOL_FINGER)
+		{
+			wacom->tool[1] = BTN_TOOL_FINGER;
+			input_report_key(dev, wacom->tool[1], 1);
+		}
+		input_report_key(dev, BTN_0, (data[5] & 0x01));
+		input_report_key(dev, BTN_1, (data[5] & 0x02));
+		input_report_key(dev, BTN_2, (data[5] & 0x04));
+		input_report_key(dev, BTN_3, (data[5] & 0x08));
+		input_report_key(dev, BTN_4, (data[6] & 0x01));
+		input_report_key(dev, BTN_5, (data[6] & 0x02));
+		input_report_key(dev, BTN_6, (data[6] & 0x04));
+		input_report_key(dev, BTN_7, (data[6] & 0x08));
+		input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+		input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+		input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+		input_sync(dev);
+		goto exit;
+	}
+
+	/* process in/out prox events */
+	if (wacom_intuos_inout(urb)) goto exit;
+
+	input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
+	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
+	input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+
+	/* process general packets */
+	wacom_intuos_general(urb);
+
+	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
+	{
+		/* Marker pen rotation packet. Reported as wheel due to valuator limitation */
+		if (data[1] & 0x02)
+		{
+			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+			t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+				((t-1) / 2 + 450)) : (450 - t / 2) ;
+			input_report_abs(dev, ABS_WHEEL, t);
+		}
+
+		/* 2D mouse packets */
+		if (wacom->tool[idx] == BTN_TOOL_MOUSE)
+		{
+			input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
+			input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
+			input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
+			input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
+			input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
+			/* mouse wheel is positive when rolled backwards */
+			input_report_rel(dev, REL_WHEEL,  ((__u32)((data[8] & 0x02) >> 1)
+					 - (__u32)(data[8] & 0x01)));
+		}
+	}
+
+	input_report_key(dev, wacom->tool[idx], 1);
+	input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+	input_sync(dev);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		    __FUNCTION__, retval);
+}
+
 static struct wacom_features wacom_features[] = {
 	{ "Wacom Penpartner",    7,   5040,  3780,  255, 32, 0, wacom_penpartner_irq },
         { "Wacom Graphire",      8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
@@ -552,6 +726,9 @@ static struct wacom_features wacom_featu
 	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
 	{ "Wacom Volito",        8,   5104,  3712,  511, 32, 1, wacom_graphire_irq },
 	{ "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, 3, wacom_ptu_irq },
+	{ "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
+	{ "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
+	{ "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
 	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
  	{ }
 };
@@ -581,6 +758,9 @@ static struct usb_device_id wacom_ids[] 
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
 	{ }
 };
@@ -651,6 +831,12 @@ static int wacom_probe(struct usb_interf
  			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
 			break;
 
+		case 4: /* new functions for Intuos3 */
+			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+			wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
+			/* fall through */
+
 		case 2:
 			wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
 			wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
@@ -662,7 +848,7 @@ static int wacom_probe(struct usb_interf
 			break;
 
 		case 3:
- 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2);
+ 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
 			break;
 	}
 
@@ -674,6 +860,8 @@ static int wacom_probe(struct usb_interf
 	wacom->dev.absmax[ABS_TILT_Y] = 127;
 	wacom->dev.absmax[ABS_WHEEL] = 1023;
 
+	wacom->dev.absmax[ABS_RX] = 4097;
+	wacom->dev.absmax[ABS_RY] = 4097;
 	wacom->dev.absmin[ABS_RZ] = -900;
 	wacom->dev.absmax[ABS_RZ] = 899;
 	wacom->dev.absmin[ABS_THROTTLE] = -1023;
@@ -712,9 +900,10 @@ static int wacom_probe(struct usb_interf
 
 	input_register_device(&wacom->dev);
 
+	/* ask the tablet to report tablet data */
+	usb_set_report(intf, 3, 2, rep_data, 2);
+	/* repeat once (not sure why the first call often fails) */
 	usb_set_report(intf, 3, 2, rep_data, 2);
-	usb_set_report(intf, 3, 5, rep_data, 0);
-	usb_set_report(intf, 3, 6, rep_data, 0);
 
 	printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);
 
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
--- a/drivers/usb/media/Kconfig
+++ b/drivers/usb/media/Kconfig
@@ -175,3 +175,39 @@ config USB_W9968CF
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called w9968cf.
+
+config USB_PWC
+	tristate "USB Philips Cameras"
+	depends on USB && VIDEO_DEV
+	---help---
+	  Say Y or M here if you want to use one of these Philips & OEM
+          webcams:
+           * Philips PCA645, PCA646
+           * Philips PCVC675, PCVC680, PCVC690
+           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+	   * Askey VC010
+	   * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' 
+             and 'Orbit'/'Sphere'
+           * Samsung MPC-C10, MPC-C30
+	   * Creative Webcam 5, Pro Ex
+	   * SOTEC Afina Eye
+	   * Visionite VCS-UC300, VCS-UM100
+	   
+	  The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
+	  and never will be, but the 665 and 720/20 are supported by other 
+	  drivers.
+
+	  See <file:Documentation/usb/philips.txt> for more information and
+	  installation instructions.
+
+	  The built-in microphone is enabled by selecting USB Audio support.
+
+	  This driver uses the Video For Linux API. You must say Y or M to
+	  "Video For Linux" (under Character Devices) to use this driver.
+	  Information on this API and pointers to "v4l" programs may be found
+	  at <file:Documentation/video4linux/API.html>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pwc.
+
+
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
--- a/drivers/usb/media/Makefile
+++ b/drivers/usb/media/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_USB_SN9C102)	+= sn9c102.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
+obj-$(CONFIG_USB_PWC)           += pwc/
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -138,8 +138,7 @@ static int dabusb_free_queue (struct lis
 #ifdef DEBUG 
 		dump_urb(b->purb);
 #endif
-		if (b->purb->transfer_buffer)
-			kfree (b->purb->transfer_buffer);
+		kfree(b->purb->transfer_buffer);
 		usb_free_urb(b->purb);
 		tmp = p->next;
 		list_del (p);
diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
--- a/drivers/usb/media/ibmcam.c
+++ b/drivers/usb/media/ibmcam.c
@@ -1036,7 +1036,8 @@ static enum ParseState ibmcam_model4_128
  * History:
  * 1/21/00  Created.
  */
-void ibmcam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
+static void ibmcam_ProcessIsocData(struct uvd *uvd,
+				   struct usbvideo_frame *frame)
 {
 	enum ParseState newstate;
 	long copylen = 0;
@@ -1137,7 +1138,7 @@ static int ibmcam_veio(
 			index,
 			cp,
 			sizeof(cp),
-			HZ);
+			1000);
 #if 0
 		info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
 		       "(req=$%02x val=$%04x ind=$%04x)",
@@ -1154,7 +1155,7 @@ static int ibmcam_veio(
 			index,
 			NULL,
 			0,
-			HZ);
+			1000);
 	}
 	if (i < 0) {
 		err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
--- a/drivers/usb/media/konicawc.c
+++ b/drivers/usb/media/konicawc.c
@@ -133,7 +133,7 @@ static int konicawc_ctrl_msg(struct uvd 
 {
         int retval = usb_control_msg(uvd->dev,
 		dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
-		    request, 0x40 | dir, value, index, buf, len, HZ);
+		    request, 0x40 | dir, value, index, buf, len, 1000);
         return retval < 0 ? retval : 0;
 }
 
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -383,7 +383,7 @@ reg_w(struct usb_ov511 *ov, unsigned cha
 			     usb_sndctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
+			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
@@ -404,7 +404,7 @@ reg_r(struct usb_ov511 *ov, unsigned cha
 			     usb_rcvctrlpipe(ov->dev, 0),
 			     (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);
+			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
 
 	if (rc < 0) {
 		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
@@ -464,7 +464,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsi
 			     usb_sndctrlpipe(ov->dev, 0),
 			     1 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			     0, (__u16)reg, ov->cbuf, n, HZ);
+			     0, (__u16)reg, ov->cbuf, n, 1000);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
@@ -3915,10 +3915,8 @@ ov51x_do_dealloc(struct usb_ov511 *ov)
 	ov->tempfbuf = NULL;
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
-		if (ov->sbuf[i].data) {
-			kfree(ov->sbuf[i].data);
-			ov->sbuf[i].data = NULL;
-		}
+		kfree(ov->sbuf[i].data);
+		ov->sbuf[i].data = NULL;
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
@@ -5043,7 +5041,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
 		{ 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, 0x33, 0xa0 }, /* Color Processing Parameter */
 		{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
 		{ OV511_I2C_BUS, 0x38, 0x8b },
 		{ OV511_I2C_BUS, 0x39, 0x40 },
@@ -5954,10 +5952,8 @@ error:
 		up(&ov->cbuf_lock);
 	}
 
-	if (ov) {
-		kfree(ov);
-		ov = NULL;
-	}
+	kfree(ov);
+	ov = NULL;
 
 error_out:
 	err("Camera initialization failed");
diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/Makefile
@@ -0,0 +1,20 @@
+ifneq ($(KERNELRELEASE),)
+
+pwc-objs	:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+
+obj-$(CONFIG_USB_PWC) += pwc.o
+
+else
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+endif
+
+clean:
+	rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c 
+	rm -rf .tmp_versions
+
diff --git a/drivers/usb/media/pwc/philips.txt b/drivers/usb/media/pwc/philips.txt
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/philips.txt
@@ -0,0 +1,236 @@
+This file contains some additional information for the Philips and OEM webcams.
+E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19
+Site: http://www.smcc.demon.nl/webcam/
+
+As of this moment, the following cameras are supported:
+ * Philips PCA645
+ * Philips PCA646
+ * Philips PCVC675
+ * Philips PCVC680
+ * Philips PCVC690
+ * Philips PCVC720/40
+ * Philips PCVC730
+ * Philips PCVC740
+ * Philips PCVC750
+ * Askey VC010
+ * Creative Labs Webcam 5
+ * Creative Labs Webcam Pro Ex
+ * Logitech QuickCam 3000 Pro
+ * Logitech QuickCam 4000 Pro
+ * Logitech QuickCam Notebook Pro
+ * Logitech QuickCam Zoom
+ * Logitech QuickCam Orbit
+ * Logitech QuickCam Sphere
+ * Samsung MPC-C10
+ * Samsung MPC-C30
+ * Sotec Afina Eye
+ * AME CU-001
+ * Visionite VCS-UM100
+ * Visionite VCS-UC300
+
+The main webpage for the Philips driver is at the address above. It contains
+a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
+contains decompression routines that allow you to use higher image sizes and
+framerates; in addition the webcam uses less bandwidth on the USB bus (handy
+if you want to run more than 1 camera simultaneously). These routines fall
+under a NDA, and may therefor not be distributed as source; however, its use
+is completely optional.
+
+You can build this code either into your kernel, or as a module. I recommend
+the latter, since it makes troubleshooting a lot easier. The built-in
+microphone is supported through the USB Audio class.
+
+When you load the module you can set some default settings for the
+camera; some programs depend on a particular image-size or -format and
+don't know how to set it properly in the driver. The options are:
+
+size
+   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
+   'vga', for an image size of resp. 128x96, 160x120, 176x144,
+   320x240, 352x288 and 640x480 (of course, only for those cameras that 
+   support these resolutions).
+
+fps
+   Specifies the desired framerate. Is an integer in the range of 4-30.
+
+fbufs
+   This paramter specifies the number of internal buffers to use for storing 
+   frames from the cam. This will help if the process that reads images from 
+   the cam is a bit slow or momentarely busy. However, on slow machines it 
+   only introduces lag, so choose carefully. The default is 3, which is 
+   reasonable. You can set it between 2 and 5.
+
+mbufs
+   This is an integer between 1 and 10. It will tell the module the number of
+   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
+   The default is 2, which is adequate for most applications (double
+   buffering).
+      
+   Should you experience a lot of 'Dumping frame...' messages during
+   grabbing with a tool that uses mmap(), you might want to increase if. 
+   However, it doesn't really buffer images, it just gives you a bit more
+   slack when your program is behind. But you need a multi-threaded or
+   forked program to really take advantage of these buffers.
+
+   The absolute maximum is 10, but don't set it too high!  Every buffer takes
+   up 460 KB of RAM, so unless you have a lot of memory setting this to
+   something more than 4 is an absolute waste.  This memory is only
+   allocated during open(), so nothing is wasted when the camera is not in
+   use.
+
+power_save
+   When power_save is enabled (set to 1), the module will try to shut down
+   the cam on close() and re-activate on open(). This will save power and
+   turn off the LED. Not all cameras support this though (the 645 and 646
+   don't have power saving at all), and some models don't work either (they
+   will shut down, but never wake up). Consider this experimental. By
+   default this option is disabled.
+
+compression (only useful with the plugin)
+   With this option you can control the compression factor that the camera
+   uses to squeeze the image through the USB bus. You can set the 
+   parameter between 0 and 3:
+     0 = prefer uncompressed images; if the requested mode is not available
+         in an uncompressed format, the driver will silently switch to low
+         compression.
+     1 = low compression.
+     2 = medium compression.
+     3 = high compression.
+      
+   High compression takes less bandwidth of course, but it could also
+   introduce some unwanted artefacts. The default is 2, medium compression.
+   See the FAQ on the website for an overview of which modes require
+   compression.
+
+   The compression parameter does not apply to the 645 and 646 cameras
+   and OEM models derived from those (only a few). Most cams honour this
+   parameter.
+
+leds
+   This settings takes 2 integers, that define the on/off time for the LED
+   (in milliseconds). One of the interesting things that you can do with
+   this is let the LED blink while the camera is in use. This:
+
+     leds=500,500
+      
+   will blink the LED once every second. But with:
+
+     leds=0,0
+
+   the LED never goes on, making it suitable for silent surveillance.
+
+   By default the camera's LED is on solid while in use, and turned off
+   when the camera is not used anymore.
+
+   This parameter works only with the ToUCam range of cameras (720, 730, 740,
+   750) and OEMs. For other cameras this command is silently ignored, and 
+   the LED cannot be controlled.
+
+   Finally: this parameters does not take effect UNTIL the first time you
+   open the camera device. Until then, the LED remains on.
+
+dev_hint
+   A long standing problem with USB devices is their dynamic nature: you
+   never know what device a camera gets assigned; it depends on module load
+   order, the hub configuration, the order in which devices are plugged in,
+   and the phase of the moon (i.e. it can be random). With this option you
+   can give the driver a hint as to what video device node (/dev/videoX) it
+   should use with a specific camera. This is also handy if you have two
+   cameras of the same model.
+
+   A camera is specified by its type (the number from the camera model,
+   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
+   in /proc/bus/usb/devices). A hint consists of a string with the following
+   format:
+
+      [type[.serialnumber]:]node
+      
+   The square brackets mean that both the type and the serialnumber are
+   optional, but a serialnumber cannot be specified without a type (which
+   would be rather pointless). The serialnumber is separated from the type
+   by a '.'; the node number by a ':'.
+   
+   This somewhat cryptic syntax is best explained by a few examples:
+
+     dev_hint=3,5              The first detected cam gets assigned
+                               /dev/video3, the second /dev/video5. Any
+                               other cameras will get the first free 
+                               available slot (see below).
+
+     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1,
+                               and a PCVC680 /dev/video2.
+                               
+     dev_hint=645.0123:3,645.4567:0	The PCA645 camera with serialnumber 
+                                        0123 goes to /dev/video3, the same
+                                        camera model with the 4567 serial
+                                        gets /dev/video0.
+
+     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
+                                next 3 Philips cams will use /dev/video4 
+                                through /dev/video6.
+
+   Some points worth knowing:
+   - Serialnumbers are case sensitive and must be written full, including 
+     leading zeroes (it's treated as a string).
+   - If a device node is already occupied, registration will fail and 
+     the webcam is not available.
+   - You can have up to 64 video devices; be sure to make enough device
+     nodes in /dev if you want to spread the numbers (this does not apply
+     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+   - If a camera does not match any dev_hint, it will simply get assigned
+     the first available device node, just as it used to be.
+
+trace
+   In order to better detect problems, it is now possible to turn on a
+   'trace' of some of the calls the module makes; it logs all items in your
+   kernel log at debug level.
+
+   The trace variable is a bitmask; each bit represents a certain feature.
+   If you want to trace something, look up the bit value(s) in the table 
+   below, add the values together and supply that to the trace variable.
+
+   Value  Value   Description					   Default
+   (dec)  (hex)
+       1    0x1   Module initialization; this will log messages       On
+                  while loading and unloading the module
+
+       2    0x2   probe() and disconnect() traces                     On
+
+       4    0x4   Trace open() and close() calls                      Off
+
+       8    0x8   read(), mmap() and associated ioctl() calls         Off
+
+      16   0x10   Memory allocation of buffers, etc.                  Off
+
+      32   0x20   Showing underflow, overflow and Dumping frame       On
+                  messages
+
+      64   0x40   Show viewport and image sizes                       Off
+
+     128   0x80   PWCX debugging                                      Off
+
+   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+   so you would supply trace=12 during insmod or modprobe. If
+   you want to turn the initialization and probing tracing off, set trace=0.
+   The default value for trace is 35 (0x23).
+
+
+
+Example:
+     
+     # modprobe pwc size=cif fps=15 power_save=1
+
+The fbufs, mbufs and trace parameters are global and apply to all connected
+cameras. Each camera has its own set of buffers.
+
+size and fps only specify defaults when you open() the device; this is to
+accommodate some tools that don't set the size. You can change these
+settings after open() with the Video4Linux ioctl() calls. The default of
+defaults is QCIF size at 10 fps.
+
+The compression parameter is semiglobal; it sets the initial compression
+preference for all camera's, but this parameter can be set per camera with
+the VIDIOCPWCSCQUAL ioctl() call.
+
+All parameters are optional.
+
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-ctrl.c
@@ -0,0 +1,1628 @@
+/* Driver for Philips webcam
+   Functions that send various control messages to the webcam, including
+   video modes.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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
+*/
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added methods for changing white balance and 
+                          red/green gains
+ */
+
+/* Control functions for the cam; brightness, contrast, video mode, etc. */
+
+#ifdef __KERNEL__
+#include <asm/uaccess.h> 
+#endif
+#include <asm/errno.h>
+#include <linux/version.h>
+ 
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-uncompress.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+
+/* Request types: video */
+#define SET_LUM_CTL			0x01
+#define GET_LUM_CTL			0x02
+#define SET_CHROM_CTL			0x03
+#define GET_CHROM_CTL			0x04
+#define SET_STATUS_CTL			0x05
+#define GET_STATUS_CTL			0x06
+#define SET_EP_STREAM_CTL		0x07
+#define GET_EP_STREAM_CTL		0x08
+#define SET_MPT_CTL			0x0D
+#define GET_MPT_CTL			0x0E
+
+/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
+#define AGC_MODE_FORMATTER			0x2000
+#define PRESET_AGC_FORMATTER			0x2100
+#define SHUTTER_MODE_FORMATTER			0x2200
+#define PRESET_SHUTTER_FORMATTER		0x2300
+#define PRESET_CONTOUR_FORMATTER		0x2400
+#define AUTO_CONTOUR_FORMATTER			0x2500
+#define BACK_LIGHT_COMPENSATION_FORMATTER	0x2600
+#define CONTRAST_FORMATTER			0x2700
+#define DYNAMIC_NOISE_CONTROL_FORMATTER		0x2800
+#define FLICKERLESS_MODE_FORMATTER		0x2900
+#define AE_CONTROL_SPEED			0x2A00
+#define BRIGHTNESS_FORMATTER			0x2B00
+#define GAMMA_FORMATTER				0x2C00
+
+/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
+#define WB_MODE_FORMATTER			0x1000
+#define AWB_CONTROL_SPEED_FORMATTER		0x1100
+#define AWB_CONTROL_DELAY_FORMATTER		0x1200
+#define PRESET_MANUAL_RED_GAIN_FORMATTER	0x1300
+#define PRESET_MANUAL_BLUE_GAIN_FORMATTER	0x1400
+#define COLOUR_MODE_FORMATTER			0x1500
+#define SATURATION_MODE_FORMATTER1		0x1600
+#define SATURATION_MODE_FORMATTER2		0x1700
+
+/* Selectors for the Status controls [GS]ET_STATUS_CTL */
+#define SAVE_USER_DEFAULTS_FORMATTER		0x0200
+#define RESTORE_USER_DEFAULTS_FORMATTER		0x0300
+#define RESTORE_FACTORY_DEFAULTS_FORMATTER	0x0400
+#define READ_AGC_FORMATTER			0x0500
+#define READ_SHUTTER_FORMATTER			0x0600
+#define READ_RED_GAIN_FORMATTER			0x0700
+#define READ_BLUE_GAIN_FORMATTER		0x0800
+#define SENSOR_TYPE_FORMATTER1			0x0C00
+#define READ_RAW_Y_MEAN_FORMATTER		0x3100
+#define SET_POWER_SAVE_MODE_FORMATTER		0x3200
+#define MIRROR_IMAGE_FORMATTER			0x3300
+#define LED_FORMATTER				0x3400
+#define SENSOR_TYPE_FORMATTER2			0x3700
+
+/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
+#define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100
+
+/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
+#define PT_RELATIVE_CONTROL_FORMATTER		0x01
+#define PT_RESET_CONTROL_FORMATTER		0x02
+#define PT_STATUS_FORMATTER			0x03
+
+static char *size2name[PSZ_MAX] =
+{
+	"subQCIF",
+	"QSIF",
+	"QCIF",
+	"SIF",
+	"CIF",
+	"VGA",
+};  
+
+/********/
+
+/* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
+   preferences, so you either get compressed or non-compressed streams.
+   
+   An alternate value of 0 means this mode is not available at all.
+ */
+
+struct Nala_table_entry {
+	char alternate;			/* USB alternate setting */
+	int compressed;			/* Compressed yes/no */
+
+	unsigned char mode[3];		/* precomputed mode table */
+};
+
+static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
+{
+#include "pwc-nala.h"
+};
+
+
+/****************************************************************************/
+
+
+#define SendControlMsg(request, value, buflen) \
+	usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
+		request, \
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+		value, \
+		pdev->vcinterface, \
+		&buf, buflen, 500)
+
+#define RecvControlMsg(request, value, buflen) \
+	usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
+		request, \
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+		value, \
+		pdev->vcinterface, \
+		&buf, buflen, 500)
+
+
+#if PWC_DEBUG
+void pwc_hexdump(void *p, int len)
+{
+	int i;
+	unsigned char *s;
+	char buf[100], *d;
+
+	s = (unsigned char *)p;
+	d = buf;
+	*d = '\0';
+	Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
+	for (i = 0; i < len; i++) {
+		d += sprintf(d, "%02X ", *s++);
+		if ((i & 0xF) == 0xF) {
+			Debug("%s\n", buf);
+			d = buf;
+			*d = '\0';
+		}
+	}
+	if ((i & 0xF) != 0)
+		Debug("%s\n", buf);
+}
+#endif
+
+static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+{
+	return usb_control_msg(udev,
+		usb_sndctrlpipe(udev, 0),
+		SET_EP_STREAM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		VIDEO_OUTPUT_CONTROL_FORMATTER,
+		index,
+		buf, buflen, 1000);
+}
+
+
+
+static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+{
+	unsigned char buf[3];
+	int ret, fps;
+	struct Nala_table_entry *pEntry;
+	int frames2frames[31] =
+	{ /* closest match of framerate */
+	   0,  0,  0,  0,  4,  /*  0-4  */
+	   5,  5,  7,  7, 10,  /*  5-9  */
+          10, 10, 12, 12, 15,  /* 10-14 */
+          15, 15, 15, 20, 20,  /* 15-19 */
+          20, 20, 20, 24, 24,  /* 20-24 */
+          24, 24, 24, 24, 24,  /* 25-29 */
+          24                   /* 30    */
+	};
+	int frames2table[31] = 
+	{ 0, 0, 0, 0, 0, /*  0-4  */
+	  1, 1, 1, 2, 2, /*  5-9  */
+	  3, 3, 4, 4, 4, /* 10-14 */
+	  5, 5, 5, 5, 5, /* 15-19 */
+	  6, 6, 6, 6, 7, /* 20-24 */
+	  7, 7, 7, 7, 7, /* 25-29 */
+	  7              /* 30    */
+	};
+	
+	if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
+		return -EINVAL;
+	frames = frames2frames[frames];
+	fps = frames2table[frames];
+	pEntry = &Nala_table[size][fps];
+	if (pEntry->alternate == 0)
+		return -EINVAL;
+
+	if (pEntry->compressed)
+		return -ENOENT; /* Not supported. */
+
+	memcpy(buf, pEntry->mode, 3);	
+	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
+	if (ret < 0) {
+		Debug("Failed to send video command... %d\n", ret);
+		return ret;
+	}
+	if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
+	 {
+	   switch(pdev->type) {
+	     case 645:
+	     case 646:
+/*	       pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+	       break;
+
+	     case 675:
+	     case 680:
+	     case 690:
+	     case 720:
+	     case 730:
+	     case 740:
+	     case 750:
+/*	       pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+	       break;
+	   }
+	}
+ 
+	pdev->cmd_len = 3;
+	memcpy(pdev->cmd_buf, buf, 3);
+
+	/* Set various parameters */
+	pdev->vframes = frames;
+	pdev->vsize = size;
+	pdev->valternate = pEntry->alternate;
+	pdev->image = pwc_image_sizes[size];
+	pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
+	if (pEntry->compressed) {
+		if (pdev->release < 5) { /* 4 fold compression */
+			pdev->vbandlength = 528;
+			pdev->frame_size /= 4;
+		}
+		else {
+			pdev->vbandlength = 704;
+			pdev->frame_size /= 3;
+		}
+	}
+	else
+		pdev->vbandlength = 0;
+	return 0;
+}
+
+
+static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+	unsigned char buf[13];
+	const struct Timon_table_entry *pChoose;
+	int ret, fps;
+
+	if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+		return -EINVAL;
+	if (size == PSZ_VGA && frames > 15)
+		return -EINVAL;
+	fps = (frames / 5) - 1;
+
+	/* Find a supported framerate with progressively higher compression ratios
+	   if the preferred ratio is not available.
+	*/
+	pChoose = NULL;
+	while (compression <= 3) {
+	   pChoose = &Timon_table[size][fps][compression];
+	   if (pChoose->alternate != 0)
+	     break;
+	   compression++;
+	}
+	if (pChoose == NULL || pChoose->alternate == 0)
+		return -ENOENT; /* Not supported. */
+
+	memcpy(buf, pChoose->mode, 13);
+	if (snapshot)
+		buf[0] |= 0x80;
+	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
+	if (ret < 0)
+		return ret;
+
+/* 	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+	   pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+	pdev->cmd_len = 13;
+	memcpy(pdev->cmd_buf, buf, 13);
+
+	/* Set various parameters */
+	pdev->vframes = frames;
+	pdev->vsize = size;
+	pdev->vsnapshot = snapshot;
+	pdev->valternate = pChoose->alternate;
+	pdev->image = pwc_image_sizes[size];
+	pdev->vbandlength = pChoose->bandlength;
+	if (pChoose->bandlength > 0)
+		pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
+	else
+		pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+	return 0;
+}
+
+
+static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+	const struct Kiara_table_entry *pChoose = NULL;
+	int fps, ret;
+	unsigned char buf[12];
+	struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
+
+	if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+		return -EINVAL;
+	if (size == PSZ_VGA && frames > 15)
+		return -EINVAL;
+	fps = (frames / 5) - 1;
+
+	/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
+	if (size == PSZ_VGA && frames == 5 && snapshot)
+	{
+		/* Only available in case the raw palette is selected or 
+		   we have the decompressor available. This mode is 
+		   only available in compressed form 
+		*/
+		if (pdev->vpalette == VIDEO_PALETTE_RAW)
+		{
+	                Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
+			pChoose = &RawEntry;
+		}
+		else
+		{
+			Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
+		}
+	}
+	else
+	{
+        	/* Find a supported framerate with progressively higher compression ratios
+		   if the preferred ratio is not available.
+                   Skip this step when using RAW modes.
+		*/
+		while (compression <= 3) {
+			pChoose = &Kiara_table[size][fps][compression];
+			if (pChoose->alternate != 0)
+				break;
+			compression++;
+		}
+	}
+	if (pChoose == NULL || pChoose->alternate == 0)
+		return -ENOENT; /* Not supported. */
+
+	Debug("Using alternate setting %d.\n", pChoose->alternate);
+	
+	/* usb_control_msg won't take staticly allocated arrays as argument?? */
+	memcpy(buf, pChoose->mode, 12);
+	if (snapshot)
+		buf[0] |= 0x80;
+
+	/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
+	ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
+	if (ret < 0)
+		return ret;
+
+/*	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+	  pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+	pdev->cmd_len = 12;
+	memcpy(pdev->cmd_buf, buf, 12);
+	/* All set and go */
+	pdev->vframes = frames;
+	pdev->vsize = size;
+	pdev->vsnapshot = snapshot;
+	pdev->valternate = pChoose->alternate;
+	pdev->image = pwc_image_sizes[size];
+	pdev->vbandlength = pChoose->bandlength;
+	if (pdev->vbandlength > 0)
+		pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
+	else
+		pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+	return 0;
+}
+
+
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+	int i, factor = 0, filler = 0;
+
+	/* for PALETTE_YUV420P */
+	switch(pdev->vpalette)
+	{
+	case VIDEO_PALETTE_YUV420P:
+		factor = 6;
+		filler = 128;
+		break;
+	case VIDEO_PALETTE_RAW:
+		factor = 6; /* can be uncompressed YUV420P */
+		filler = 0;
+		break;
+	}
+
+	/* Set sizes in bytes */
+	pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+	pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
+
+	/* Align offset, or you'll get some very weird results in
+	   YUV420 mode... x must be multiple of 4 (to get the Y's in
+	   place), and y even (or you'll mixup U & V). This is less of a
+	   problem for YUV420P.
+	 */
+	pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+	pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+	/* Fill buffers with gray or black */
+	for (i = 0; i < MAX_IMAGES; i++) {
+		if (pdev->image_ptr[i] != NULL)
+			memset(pdev->image_ptr[i], filler, pdev->view.size);
+	}
+}
+
+
+
+/**
+   @pdev: device structure
+   @width: viewport width
+   @height: viewport height
+   @frame: framerate, in fps
+   @compression: preferred compression ratio
+   @snapshot: snapshot mode or streaming
+ */
+int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
+{
+        int ret, size;
+
+        Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+	size = pwc_decode_size(pdev, width, height);
+	if (size < 0) {
+		Debug("Could not find suitable size.\n");
+		return -ERANGE;
+	}
+	Debug("decode_size = %d.\n", size);
+
+        ret = -EINVAL;
+	switch(pdev->type) {
+	case 645:
+	case 646:
+		ret = set_video_mode_Nala(pdev, size, frames);
+		break;
+
+	case 675:
+	case 680:
+	case 690:
+		ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
+		break;
+	
+	case 720:
+	case 730:
+	case 740:
+	case 750:
+		ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
+		break;
+	}
+	if (ret < 0) {
+		if (ret == -ENOENT)
+			Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
+		else {
+			Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
+		}
+		return ret;
+	}
+	pdev->view.x = width;
+	pdev->view.y = height;
+	pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
+	pwc_set_image_buffer_size(pdev);
+	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+	return 0;
+}
+
+
+/* BRIGHTNESS */
+
+int pwc_get_brightness(struct pwc_device *pdev)
+{
+	char buf;
+	int ret;
+
+	ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);	
+	if (ret < 0)
+		return ret;
+	return buf << 9;
+}
+
+int pwc_set_brightness(struct pwc_device *pdev, int value)
+{
+	char buf;
+
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	buf = (value >> 9) & 0x7f;
+	return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
+}
+
+/* CONTRAST */
+
+int pwc_get_contrast(struct pwc_device *pdev)
+{
+	char buf;
+	int ret;
+
+	ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	return buf << 10;
+}
+
+int pwc_set_contrast(struct pwc_device *pdev, int value)
+{
+	char buf;
+
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	buf = (value >> 10) & 0x3f;
+	return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);
+}
+
+/* GAMMA */
+
+int pwc_get_gamma(struct pwc_device *pdev)
+{
+	char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	return buf << 11;
+}
+
+int pwc_set_gamma(struct pwc_device *pdev, int value)
+{
+	char buf;
+
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	buf = (value >> 11) & 0x1f;
+	return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);
+}
+
+
+/* SATURATION */
+
+int pwc_get_saturation(struct pwc_device *pdev)
+{
+	char buf;
+	int ret;
+
+	if (pdev->type < 675)
+		return -1;
+	ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+	if (ret < 0)
+		return ret;
+	return 32768 + buf * 327;
+}
+
+int pwc_set_saturation(struct pwc_device *pdev, int value)
+{
+	char buf;
+
+	if (pdev->type < 675)
+		return -EINVAL;
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	/* saturation ranges from -100 to +100 */
+	buf = (value - 32768) / 327;
+	return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+}
+
+/* AGC */
+
+static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+{
+	char buf;
+	int ret;
+	
+	if (mode)
+		buf = 0x0; /* auto */
+	else
+		buf = 0xff; /* fixed */
+
+	ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+	
+	if (!mode && ret >= 0) {
+		if (value < 0)
+			value = 0;
+		if (value > 0xffff)
+			value = 0xffff;
+		buf = (value >> 10) & 0x3F;
+		ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+	}
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+
+	if (buf != 0) { /* fixed */
+		ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+		if (ret < 0)
+			return ret;
+		if (buf > 0x3F)
+			buf = 0x3F;
+		*value = (buf << 10);		
+	}
+	else { /* auto */
+		ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1);
+		if (ret < 0)
+			return ret;
+		/* Gah... this value ranges from 0x00 ... 0x9F */
+		if (buf > 0x9F)
+			buf = 0x9F;
+		*value = -(48 + buf * 409);
+	}
+
+	return 0;
+}
+
+static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+{
+	char buf[2];
+	int speed, ret;
+
+
+	if (mode)
+		buf[0] = 0x0;	/* auto */
+	else
+		buf[0] = 0xff; /* fixed */
+	
+	ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1);
+
+	if (!mode && ret >= 0) {
+		if (value < 0)
+			value = 0;
+		if (value > 0xffff)
+			value = 0xffff;
+		switch(pdev->type) {
+		case 675:
+		case 680:
+		case 690:
+			/* speed ranges from 0x0 to 0x290 (656) */
+			speed = (value / 100);
+			buf[1] = speed >> 8;
+			buf[0] = speed & 0xff;
+			break;
+		case 720:
+		case 730:
+		case 740:
+		case 750:
+			/* speed seems to range from 0x0 to 0xff */
+			buf[1] = 0;
+			buf[0] = value >> 8;
+			break;
+		}
+
+		ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
+	}
+	return ret;
+}	
+
+
+/* POWER */
+
+int pwc_camera_power(struct pwc_device *pdev, int power)
+{
+	char buf;
+
+	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
+		return 0;	/* Not supported by Nala or Timon < release 6 */
+
+	if (power)
+		buf = 0x00; /* active */
+	else
+		buf = 0xFF; /* power save */
+	return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1);
+}
+
+
+
+/* private calls */
+
+static inline int pwc_restore_user(struct pwc_device *pdev)
+{
+	char buf; /* dummy */
+	return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_save_user(struct pwc_device *pdev)
+{
+	char buf; /* dummy */
+	return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_restore_factory(struct pwc_device *pdev)
+{
+	char buf; /* dummy */
+	return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
+}
+
+ /* ************************************************* */
+ /* Patch by Alvarado: (not in the original version   */
+
+ /*
+  * the camera recognizes modes from 0 to 4:
+  *
+  * 00: indoor (incandescant lighting)
+  * 01: outdoor (sunlight)
+  * 02: fluorescent lighting
+  * 03: manual
+  * 04: auto
+  */ 
+static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+{
+	char buf;
+	int ret;
+	
+	if (mode < 0)
+	    mode = 0;
+	
+	if (mode > 4)
+	    mode = 4;
+	
+	buf = mode & 0x07; /* just the lowest three bits */
+	
+	ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+	
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static inline int pwc_get_awb(struct pwc_device *pdev)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+
+	if (ret < 0) 
+		return ret;
+	return buf;
+}
+
+static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+{
+        unsigned char buf;
+
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	/* only the msb is considered */
+	buf = value >> 8;
+	return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+	if (ret < 0)
+	    return ret;
+	*value = buf << 8;
+	return 0;
+}
+
+
+static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+{
+	unsigned char buf;
+
+	if (value < 0)
+		value = 0;
+	if (value > 0xffff)
+		value = 0xffff;
+	/* only the msb is considered */
+	buf = value >> 8;
+	return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+	if (ret < 0)
+	    return ret;
+	*value = buf << 8;
+	return 0;
+}
+
+
+/* The following two functions are different, since they only read the
+   internal red/blue gains, which may be different from the manual 
+   gains set or read above.
+ */   
+static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*value = buf << 8;
+	return 0;
+}
+
+static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*value = buf << 8;
+	return 0;
+}
+
+
+static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+{
+	unsigned char buf;
+	
+	/* useful range is 0x01..0x20 */
+	buf = speed / 0x7f0;
+	return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*value = buf * 0x7f0;
+	return 0;
+}
+
+
+static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+{
+	unsigned char buf;
+	
+	/* useful range is 0x01..0x3F */
+	buf = (delay >> 10);
+	return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*value = buf << 10;
+	return 0;
+}
+
+
+int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
+{
+	unsigned char buf[2];
+
+	if (pdev->type < 730)
+		return 0;
+	on_value /= 100;
+	off_value /= 100;
+	if (on_value < 0)
+		on_value = 0;
+	if (on_value > 0xff)
+		on_value = 0xff;
+	if (off_value < 0)
+		off_value = 0;
+	if (off_value > 0xff)
+		off_value = 0xff;
+
+	buf[0] = on_value;
+	buf[1] = off_value;
+
+	return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
+}
+
+static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
+{
+	unsigned char buf[2];
+	int ret;
+	
+	if (pdev->type < 730) {
+		*on_value = -1;
+		*off_value = -1;
+		return 0;
+	}
+
+	ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
+	if (ret < 0)
+		return ret;
+	*on_value = buf[0] * 100;
+	*off_value = buf[1] * 100;
+	return 0;
+}
+
+static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+{
+	unsigned char buf;
+	int ret;
+	
+	if (contour < 0)
+		buf = 0xff; /* auto contour on */
+	else
+		buf = 0x0; /* auto contour off */
+	ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	
+	if (contour < 0)
+		return 0;
+	if (contour > 0xffff)
+		contour = 0xffff;
+	
+	buf = (contour >> 10); /* contour preset is [0..3f] */
+	ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+	if (ret < 0)	
+		return ret;	
+	return 0;
+}
+
+static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+
+	if (buf == 0) {
+		/* auto mode off, query current preset value */
+		ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+		if (ret < 0)	
+			return ret;
+		*contour = buf << 10;
+	}
+	else
+		*contour = -1;
+	return 0;
+}
+
+
+static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+{
+	unsigned char buf;
+	
+	if (backlight)
+		buf = 0xff;
+	else
+		buf = 0x0;
+	return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+}
+
+static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*backlight = buf;
+	return 0;
+}
+
+
+static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+{
+	unsigned char buf;
+	
+	if (flicker)
+		buf = 0xff;
+	else
+		buf = 0x0;
+	return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+}
+
+static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*flicker = buf;
+	return 0;
+}
+
+
+static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+{
+	unsigned char buf;
+
+	if (noise < 0)
+		noise = 0;
+	if (noise > 3)
+		noise = 3;
+	buf = noise;
+	return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*noise = buf;
+	return 0;
+}
+
+static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+	unsigned char buf;
+	
+	buf = flags & 0x03; // only lower two bits are currently used
+	return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+	unsigned char buf[4];
+	
+	/* set new relative angle; angles are expressed in degrees * 100,
+	   but cam as .5 degree resolution, hence divide by 200. Also
+	   the angle must be multiplied by 64 before it's send to
+	   the cam (??)
+	 */
+	pan  =  64 * pan  / 100;
+	tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
+	buf[0] = pan & 0xFF;
+	buf[1] = (pan >> 8) & 0xFF;
+	buf[2] = tilt & 0xFF;
+	buf[3] = (tilt >> 8) & 0xFF;
+	return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
+}
+
+static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+{
+	int ret;
+	unsigned char buf[5];
+	
+	ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
+	if (ret < 0)
+		return ret;
+	status->status = buf[0] & 0x7; // 3 bits are used for reporting
+	status->time_pan = (buf[1] << 8) + buf[2];
+	status->time_tilt = (buf[3] << 8) + buf[4];
+	return 0;
+}
+
+
+int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
+{
+	unsigned char buf;
+	int ret = -1, request;
+	
+	if (pdev->type < 675)
+		request = SENSOR_TYPE_FORMATTER1;
+	else if (pdev->type < 730)
+		return -1; /* The Vesta series doesn't have this call */
+	else
+		request = SENSOR_TYPE_FORMATTER2;
+	
+	ret = RecvControlMsg(GET_STATUS_CTL, request, 1);
+	if (ret < 0)
+		return ret;
+	if (pdev->type < 675)
+		*sensor = buf | 0x100;
+	else
+		*sensor = buf;
+	return 0;
+}
+
+
+ /* End of Add-Ons                                    */
+ /* ************************************************* */
+
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+   and copy_to_user() calls. With these macros we circumvent this,
+   and let me maintain only one source file. The functionality is
+   exactly the same otherwise.
+ */   
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+	ARG_type *ARG_name = arg;
+/* copy arg to local variable */	
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
+#else
+
+#define ARG_DEF(ARG_type, ARG_name)\
+	ARG_type ARG_name;
+#define ARG_IN(ARG_name)\
+	if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\
+		ret = -EFAULT;\
+		break;\
+	}
+#define ARGR(ARG_name) ARG_name
+#define ARGA(ARG_name) &ARG_name
+#define ARG_OUT(ARG_name)\
+	if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\
+		ret = -EFAULT;\
+		break;\
+	}
+
+#endif
+
+int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
+{
+	int ret = 0;
+
+	switch(cmd) {
+	case VIDIOCPWCRUSER:
+	{
+		if (pwc_restore_user(pdev))
+			ret = -EINVAL;
+		break;
+	}
+	
+	case VIDIOCPWCSUSER:
+	{
+		if (pwc_save_user(pdev))
+			ret = -EINVAL;
+		break;
+	}
+		
+	case VIDIOCPWCFACTORY:
+	{
+		if (pwc_restore_factory(pdev))
+			ret = -EINVAL;
+		break;
+	}
+	
+	case VIDIOCPWCSCQUAL:
+	{	
+		ARG_DEF(int, qual)
+
+		ARG_IN(qual)
+		if (ARGR(qual) < 0 || ARGR(qual) > 3)
+			ret = -EINVAL;
+		else
+			ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
+		if (ret >= 0)
+			pdev->vcompression = ARGR(qual);
+		break;
+	}
+	
+	case VIDIOCPWCGCQUAL:
+	{
+		ARG_DEF(int, qual)
+		
+		ARGR(qual) = pdev->vcompression;
+		ARG_OUT(qual)
+		break;
+	}
+	
+	case VIDIOCPWCPROBE:
+	{
+		ARG_DEF(struct pwc_probe, probe)
+		
+		strcpy(ARGR(probe).name, pdev->vdev->name);
+		ARGR(probe).type = pdev->type;
+		ARG_OUT(probe)
+		break;
+	}
+
+	case VIDIOCPWCGSERIAL:
+	{
+		ARG_DEF(struct pwc_serial, serial)
+		
+		strcpy(ARGR(serial).serial, pdev->serial);
+		ARG_OUT(serial)
+		break;
+	}
+
+	case VIDIOCPWCSAGC:
+	{
+		ARG_DEF(int, agc)
+
+		ARG_IN(agc)
+		if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
+			ret = -EINVAL;
+		break;
+	}
+	
+	case VIDIOCPWCGAGC:
+	{
+		ARG_DEF(int, agc)
+		
+		if (pwc_get_agc(pdev, ARGA(agc)))
+			ret = -EINVAL;
+		ARG_OUT(agc)
+		break;
+	}
+	
+	case VIDIOCPWCSSHUTTER:
+	{
+		ARG_DEF(int, shutter_speed)
+
+		ARG_IN(shutter_speed)
+		ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
+		break;
+	}
+	
+        case VIDIOCPWCSAWB:
+	{
+		ARG_DEF(struct pwc_whitebalance, wb)
+		
+		ARG_IN(wb)
+		ret = pwc_set_awb(pdev, ARGR(wb).mode);
+		if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+			pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+			pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
+		}
+		break;
+	}
+
+	case VIDIOCPWCGAWB:
+	{
+		ARG_DEF(struct pwc_whitebalance, wb)
+
+		memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+		ARGR(wb).mode = pwc_get_awb(pdev);
+		if (ARGR(wb).mode < 0)
+			ret = -EINVAL;
+		else {
+			if (ARGR(wb).mode == PWC_WB_MANUAL) {
+				ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
+				if (ret < 0)
+					break;
+				ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
+				if (ret < 0)
+					break;
+			}
+			if (ARGR(wb).mode == PWC_WB_AUTO) {
+				ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
+				if (ret < 0)
+					break;
+ 				ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
+ 				if (ret < 0)
+ 					break;
+			}
+		}
+		ARG_OUT(wb)
+		break;
+	}
+	
+	case VIDIOCPWCSAWBSPEED:
+	{
+		ARG_DEF(struct pwc_wb_speed, wbs)
+		
+		if (ARGR(wbs).control_speed > 0) {
+			ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
+		}
+		if (ARGR(wbs).control_delay > 0) {
+			ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
+		}
+		break;
+	}
+	
+	case VIDIOCPWCGAWBSPEED:
+	{
+		ARG_DEF(struct pwc_wb_speed, wbs)
+		
+		ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
+		if (ret < 0)
+			break;
+		ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
+		if (ret < 0)
+			break;
+		ARG_OUT(wbs)
+		break;
+	}
+
+        case VIDIOCPWCSLED:
+	{
+		ARG_DEF(struct pwc_leds, leds)
+
+		ARG_IN(leds)
+		ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+	    	break;
+	}
+
+
+	case VIDIOCPWCGLED:
+	{
+		ARG_DEF(struct pwc_leds, leds)
+		
+		ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+		ARG_OUT(leds)
+		break;
+	}
+
+	case VIDIOCPWCSCONTOUR:
+	{
+		ARG_DEF(int, contour)
+
+		ARG_IN(contour)
+		ret = pwc_set_contour(pdev, ARGR(contour));
+		break;
+	}
+			
+	case VIDIOCPWCGCONTOUR:
+	{
+		ARG_DEF(int, contour)
+		
+		ret = pwc_get_contour(pdev, ARGA(contour));
+		ARG_OUT(contour)
+		break;
+	}
+	
+	case VIDIOCPWCSBACKLIGHT:
+	{
+		ARG_DEF(int, backlight)
+		
+		ARG_IN(backlight)
+		ret = pwc_set_backlight(pdev, ARGR(backlight));
+		break;
+	}
+
+	case VIDIOCPWCGBACKLIGHT:
+	{
+		ARG_DEF(int, backlight)
+		
+		ret = pwc_get_backlight(pdev, ARGA(backlight));
+		ARG_OUT(backlight)
+		break;
+	}
+	
+	case VIDIOCPWCSFLICKER:
+	{
+		ARG_DEF(int, flicker)
+		
+		ARG_IN(flicker)
+		ret = pwc_set_flicker(pdev, ARGR(flicker));
+		break;
+	}
+
+	case VIDIOCPWCGFLICKER:
+	{
+		ARG_DEF(int, flicker)
+		
+		ret = pwc_get_flicker(pdev, ARGA(flicker));
+		ARG_OUT(flicker)
+		break;
+	}
+	
+	case VIDIOCPWCSDYNNOISE:
+	{
+		ARG_DEF(int, dynnoise)
+		
+		ARG_IN(dynnoise)
+		ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
+		break;
+	}
+	
+	case VIDIOCPWCGDYNNOISE:
+	{
+		ARG_DEF(int, dynnoise)
+
+		ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+		ARG_OUT(dynnoise);
+		break;
+	}
+
+	case VIDIOCPWCGREALSIZE:
+	{
+		ARG_DEF(struct pwc_imagesize, size)
+		
+		ARGR(size).width = pdev->image.x;
+		ARGR(size).height = pdev->image.y;
+		ARG_OUT(size)
+		break;
+ 	}
+ 	
+ 	case VIDIOCPWCMPTRESET:
+ 	{
+ 		if (pdev->features & FEATURE_MOTOR_PANTILT)
+ 		{
+	 		ARG_DEF(int, flags)
+
+ 			ARG_IN(flags)
+			ret = pwc_mpt_reset(pdev, ARGR(flags));
+ 			if (ret >= 0)
+ 			{
+ 				pdev->pan_angle = 0;
+ 				pdev->tilt_angle = 0;
+ 			}
+ 		}
+ 		else
+ 		{
+ 			ret = -ENXIO;
+ 		}
+ 		break;		
+ 	}
+ 	
+ 	case VIDIOCPWCMPTGRANGE:
+ 	{
+ 		if (pdev->features & FEATURE_MOTOR_PANTILT)
+ 		{
+ 			ARG_DEF(struct pwc_mpt_range, range)
+ 			
+ 			ARGR(range) = pdev->angle_range;
+ 			ARG_OUT(range)
+ 		}
+ 		else
+ 		{	
+ 			ret = -ENXIO;
+ 		}
+ 		break;
+ 	}
+ 	
+ 	case VIDIOCPWCMPTSANGLE:
+ 	{
+ 		int new_pan, new_tilt;
+ 		
+ 		if (pdev->features & FEATURE_MOTOR_PANTILT)
+ 		{
+	 		ARG_DEF(struct pwc_mpt_angles, angles)
+
+	 		ARG_IN(angles)
+			/* The camera can only set relative angles, so
+			   do some calculations when getting an absolute angle .
+			 */
+			if (ARGR(angles).absolute)
+			{
+ 				new_pan  = ARGR(angles).pan; 
+ 				new_tilt = ARGR(angles).tilt;
+ 			}
+ 			else
+ 			{
+ 				new_pan  = pdev->pan_angle  + ARGR(angles).pan;
+ 				new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
+			}
+			/* check absolute ranges */
+			if (new_pan  < pdev->angle_range.pan_min  ||
+			    new_pan  > pdev->angle_range.pan_max  ||
+			    new_tilt < pdev->angle_range.tilt_min ||
+			    new_tilt > pdev->angle_range.tilt_max)
+			{
+				ret = -ERANGE;
+			}
+			else
+			{
+				/* go to relative range, check again */
+				new_pan  -= pdev->pan_angle;
+				new_tilt -= pdev->tilt_angle;
+				/* angles are specified in degrees * 100, thus the limit = 36000 */
+				if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
+					ret = -ERANGE;
+			}
+			if (ret == 0) /* no errors so far */
+			{
+				ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
+				if (ret >= 0)
+				{
+					pdev->pan_angle  += new_pan;
+					pdev->tilt_angle += new_tilt;
+				}
+				if (ret == -EPIPE) /* stall -> out of range */
+					ret = -ERANGE;				
+			}
+ 		}
+ 		else
+ 		{
+ 			ret = -ENXIO;
+ 		}
+ 		break;
+ 	}
+
+ 	case VIDIOCPWCMPTGANGLE:
+ 	{
+ 		
+ 		if (pdev->features & FEATURE_MOTOR_PANTILT)
+ 		{
+	 		ARG_DEF(struct pwc_mpt_angles, angles)
+
+ 			ARGR(angles).absolute = 1;
+ 			ARGR(angles).pan  = pdev->pan_angle;
+ 			ARGR(angles).tilt = pdev->tilt_angle;
+ 			ARG_OUT(angles)
+ 		}
+ 		else
+ 		{
+ 			ret = -ENXIO;
+ 		}
+ 		break;
+ 	}
+ 
+ 	case VIDIOCPWCMPTSTATUS:
+ 	{
+ 		if (pdev->features & FEATURE_MOTOR_PANTILT)
+ 		{
+ 			ARG_DEF(struct pwc_mpt_status, status)
+ 			
+ 			ret = pwc_mpt_get_status(pdev, ARGA(status));
+ 			ARG_OUT(status)
+ 		}
+ 		else
+ 		{
+ 			ret = -ENXIO;
+ 		}
+ 		break;
+	}
+
+	case VIDIOCPWCGVIDCMD:
+	{
+		ARG_DEF(struct pwc_video_command, cmd);
+		
+                ARGR(cmd).type = pdev->type;
+		ARGR(cmd).release = pdev->release;
+		ARGR(cmd).command_len = pdev->cmd_len;
+		memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+		ARGR(cmd).bandlength = pdev->vbandlength;
+		ARGR(cmd).frame_size = pdev->frame_size;
+		ARG_OUT(cmd)
+		break;
+	}
+       /*
+	case VIDIOCPWCGVIDTABLE:
+	{
+		ARG_DEF(struct pwc_table_init_buffer, table);
+		ARGR(table).len = pdev->cmd_len;
+		memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+		ARG_OUT(table)
+		break;
+	}
+	*/
+
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	
+	if (ret > 0)
+		return 0;
+	return ret;
+}
+
+
+
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -0,0 +1,2209 @@
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 code forms the interface between the USB layers and the Philips
+   specific stuff. Some adanved stuff of the driver falls under an
+   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
+   is thus not distributed in source form. The binary pwcx.o module 
+   contains the code that falls under the NDA.
+   
+   In case you're wondering: 'pwc' stands for "Philips WebCam", but 
+   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
+   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
+   without explanation).
+   
+   Oh yes, convention: to disctinguish between all the various pointers to
+   device-structures, I use these names for the pointer variables:
+   udev: struct usb_device *
+   vdev: struct video_device *
+   pdev: struct pwc_devive *
+*/
+
+/* Contributors:
+   - Alvarado: adding whitebalance code
+   - Alistar Moire: QuickCam 3000 Pro device/product ID
+   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
+   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+#include "pwc-uncompress.h"
+
+/* Function prototypes and driver templates */
+
+/* hotplug device table support */
+static struct usb_device_id pwc_device_table [] = {
+	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
+	{ USB_DEVICE(0x0471, 0x0303) },
+	{ USB_DEVICE(0x0471, 0x0304) },
+	{ USB_DEVICE(0x0471, 0x0307) },
+	{ USB_DEVICE(0x0471, 0x0308) },
+	{ USB_DEVICE(0x0471, 0x030C) },
+	{ USB_DEVICE(0x0471, 0x0310) },
+	{ USB_DEVICE(0x0471, 0x0311) },
+	{ USB_DEVICE(0x0471, 0x0312) },
+	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
+	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
+	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
+	{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
+	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
+	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
+	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
+	{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
+	{ USB_DEVICE(0x055D, 0x9001) },
+	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
+	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
+	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+	{ USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
+	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+	{ USB_DEVICE(0x0d81, 0x1900) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, pwc_device_table);
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void usb_pwc_disconnect(struct usb_interface *intf);
+
+static struct usb_driver pwc_driver = {
+	.owner =		THIS_MODULE,
+	.name =			"Philips webcam",	/* name */
+	.id_table =		pwc_device_table,
+	.probe =		usb_pwc_probe,		/* probe() */
+	.disconnect =		usb_pwc_disconnect,	/* disconnect() */
+};
+
+#define MAX_DEV_HINTS	20
+#define MAX_ISOC_ERRORS	20
+
+static int default_size = PSZ_QCIF;
+static int default_fps = 10;
+static int default_fbufs = 3;   /* Default number of frame buffers */
+static int default_mbufs = 2;	/* Default number of mmap() buffers */
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+static int power_save = 0;
+static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
+static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static struct {
+	int type;
+	char serial_number[30];
+	int device_node;
+	struct pwc_device *pdev;
+} device_hint[MAX_DEV_HINTS];
+
+/***/
+
+static int pwc_video_open(struct inode *inode, struct file *file);
+static int pwc_video_close(struct inode *inode, struct file *file);
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+			  size_t count, loff_t *ppos);
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
+static int  pwc_video_ioctl(struct inode *inode, struct file *file,
+			    unsigned int ioctlnr, unsigned long arg);
+static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations pwc_fops = {
+	.owner =	THIS_MODULE,
+	.open =		pwc_video_open,
+	.release =     	pwc_video_close,
+	.read =		pwc_video_read,
+	.poll =		pwc_video_poll,
+	.mmap =		pwc_video_mmap,
+	.ioctl =        pwc_video_ioctl,
+	.llseek =       no_llseek,
+};
+static struct video_device pwc_template = {
+	.owner =	THIS_MODULE,
+	.name =		"Philips Webcam",	/* Filled in later */
+	.type =		VID_TYPE_CAPTURE,
+	.hardware =	VID_HARDWARE_PWC,
+	.release =	video_device_release,
+	.fops =         &pwc_fops,
+	.minor =        -1,
+};
+
+/***************************************************************************/
+
+/* Okay, this is some magic that I worked out and the reasoning behind it...
+
+   The biggest problem with any USB device is of course: "what to do 
+   when the user unplugs the device while it is in use by an application?"
+   We have several options:
+   1) Curse them with the 7 plagues when they do (requires divine intervention)
+   2) Tell them not to (won't work: they'll do it anyway)
+   3) Oops the kernel (this will have a negative effect on a user's uptime)
+   4) Do something sensible.
+   
+   Of course, we go for option 4.
+
+   It happens that this device will be linked to two times, once from
+   usb_device and once from the video_device in their respective 'private'
+   pointers. This is done when the device is probed() and all initialization
+   succeeded. The pwc_device struct links back to both structures.
+
+   When a device is unplugged while in use it will be removed from the 
+   list of known USB devices; I also de-register it as a V4L device, but 
+   unfortunately I can't free the memory since the struct is still in use
+   by the file descriptor. This free-ing is then deferend until the first
+   opportunity. Crude, but it works.
+   
+   A small 'advantage' is that if a user unplugs the cam and plugs it back
+   in, it should get assigned the same video device minor, but unfortunately
+   it's non-trivial to re-link the cam back to the video device... (that 
+   would surely be magic! :))
+*/
+
+/***************************************************************************/
+/* Private functions */
+
+/* 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 kva, ret;
+
+	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;
+
+	size=PAGE_ALIGN(size);
+        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) 
+                {
+			SetPageReserved(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 ((long) size > 0) 
+                {
+			ClearPageReserved(vmalloc_to_page((void *)adr));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+
+
+
+static int pwc_allocate_buffers(struct pwc_device *pdev)
+{
+	int i;
+	void *kbuf;
+
+	Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+
+	if (pdev == NULL)
+		return -ENXIO;
+		
+#ifdef PWC_MAGIC
+	if (pdev->magic != PWC_MAGIC) {
+		Err("allocate_buffers(): magic failed.\n");
+		return -ENXIO;
+	}
+#endif	
+	/* Allocate Isochronous pipe buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		if (pdev->sbuf[i].data == NULL) {
+			kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+			if (kbuf == NULL) {
+				Err("Failed to allocate iso buffer %d.\n", i);
+				return -ENOMEM;
+			}
+			Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+			pdev->sbuf[i].data = kbuf;
+			memset(kbuf, 0, ISO_BUFFER_SIZE);
+		}
+	}
+
+	/* Allocate frame buffer structure */
+	if (pdev->fbuf == NULL) {
+		kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+		if (kbuf == NULL) {
+			Err("Failed to allocate frame buffer structure.\n");
+			return -ENOMEM;
+		}
+		Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+		pdev->fbuf = kbuf;
+		memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
+	}
+	/* create frame buffers, and make circular ring */
+	for (i = 0; i < default_fbufs; i++) {
+		if (pdev->fbuf[i].data == NULL) {
+			kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+			if (kbuf == NULL) {
+				Err("Failed to allocate frame buffer %d.\n", i);
+				return -ENOMEM;
+			}
+			Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+			pdev->fbuf[i].data = kbuf;
+			memset(kbuf, 128, PWC_FRAME_SIZE);
+		}
+	}
+	
+	/* Allocate decompressor table space */
+	kbuf = NULL;
+	switch (pdev->type)
+	 {
+	  case 675:
+	  case 680:
+	  case 690:
+	  case 720:
+	  case 730:
+	  case 740:
+	  case 750:
+#if 0	  
+	    Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
+	    kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);	/* Timon & Kiara */
+	    break;
+	  case 645:
+	  case 646:
+	    /* TODO & FIXME */
+	    kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+	    break;
+#endif	 
+	;
+	 }
+	pdev->decompress_data = kbuf;
+	
+	/* Allocate image buffer; double buffer for mmap() */
+	kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+	if (kbuf == NULL) {
+		Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+		return -ENOMEM;
+	}
+	Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+	pdev->image_data = kbuf;
+	for (i = 0; i < default_mbufs; i++)
+		pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
+	for (; i < MAX_IMAGES; i++)
+		pdev->image_ptr[i] = NULL;
+
+	kbuf = NULL;
+	  
+	Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+	return 0;
+}
+
+static void pwc_free_buffers(struct pwc_device *pdev)
+{
+	int i;
+
+	Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+
+	if (pdev == NULL)
+		return;
+#ifdef PWC_MAGIC
+	if (pdev->magic != PWC_MAGIC) {
+		Err("free_buffers(): magic failed.\n");
+		return;
+	}
+#endif	
+
+	/* Release Iso-pipe buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++)
+		if (pdev->sbuf[i].data != NULL) {
+			Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+			kfree(pdev->sbuf[i].data);
+			pdev->sbuf[i].data = NULL;
+		}
+
+	/* The same for frame buffers */
+	if (pdev->fbuf != NULL) {
+		for (i = 0; i < default_fbufs; i++) {
+			if (pdev->fbuf[i].data != NULL) {
+				Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+				vfree(pdev->fbuf[i].data);
+				pdev->fbuf[i].data = NULL;
+			}
+		}
+		kfree(pdev->fbuf);
+		pdev->fbuf = NULL;
+	}
+
+	/* Intermediate decompression buffer & tables */
+	if (pdev->decompress_data != NULL) {
+		Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+		kfree(pdev->decompress_data);
+		pdev->decompress_data = NULL;
+	}
+	pdev->decompressor = NULL;
+
+	/* Release image buffers */
+	if (pdev->image_data != NULL) {
+		Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
+		rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+	}
+	pdev->image_data = NULL;
+	
+	Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+}
+
+/* The frame & image buffer mess. 
+
+   Yes, this is a mess. Well, it used to be simple, but alas...  In this
+   module, 3 buffers schemes are used to get the data from the USB bus to
+   the user program. The first scheme involves the ISO buffers (called thus
+   since they transport ISO data from the USB controller), and not really
+   interesting. Suffices to say the data from this buffer is quickly 
+   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
+   frame buffer.
+
+   The frame buffer is the second scheme, and is the central element here.
+   It collects the data from a single frame from the camera (hence, the
+   name). Frames are delimited by the USB camera with a short USB packet,
+   so that's easy to detect. The frame buffers form a list that is filled
+   by the camera+USB controller and drained by the user process through
+   either read() or mmap().
+
+   The image buffer is the third scheme, in which frames are decompressed
+   and converted into planar format. For mmap() there is more than
+   one image buffer available.
+
+   The frame buffers provide the image buffering. In case the user process
+   is a bit slow, this introduces lag and some undesired side-effects.
+   The problem arises when the frame buffer is full. I used to drop the last
+   frame, which makes the data in the queue stale very quickly. But dropping
+   the frame at the head of the queue proved to be a litte bit more difficult.
+   I tried a circular linked scheme, but this introduced more problems than
+   it solved.
+
+   Because filling and draining are completely asynchronous processes, this
+   requires some fiddling with pointers and mutexes.
+
+   Eventually, I came up with a system with 2 lists: an 'empty' frame list
+   and a 'full' frame list:
+     * Initially, all frame buffers but one are on the 'empty' list; the one
+       remaining buffer is our initial fill frame.
+     * If a frame is needed for filling, we try to take it from the 'empty' 
+       list, unless that list is empty, in which case we take the buffer at 
+       the head of the 'full' list.
+     * When our fill buffer has been filled, it is appended to the 'full'
+       list.
+     * If a frame is needed by read() or mmap(), it is taken from the head of
+       the 'full' list, handled, and then appended to the 'empty' list. If no
+       buffer is present on the 'full' list, we wait.
+   The advantage is that the buffer that is currently being decompressed/
+   converted, is on neither list, and thus not in our way (any other scheme
+   I tried had the problem of old data lingering in the queue).
+
+   Whatever strategy you choose, it always remains a tradeoff: with more
+   frame buffers the chances of a missed frame are reduced. On the other
+   hand, on slower machines it introduces lag because the queue will
+   always be full.
+ */
+
+/**
+  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
+ */
+static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+{
+	int ret;
+	unsigned long flags;
+
+	ret = 0;
+	spin_lock_irqsave(&pdev->ptrlock, flags);
+	if (pdev->fill_frame != NULL) {
+		/* append to 'full' list */
+		if (pdev->full_frames == NULL) {
+			pdev->full_frames = pdev->fill_frame;
+			pdev->full_frames_tail = pdev->full_frames;
+		}
+		else {
+			pdev->full_frames_tail->next = pdev->fill_frame;
+			pdev->full_frames_tail = pdev->fill_frame;
+		}
+	}
+	if (pdev->empty_frames != NULL) {
+		/* We have empty frames available. That's easy */
+		pdev->fill_frame = pdev->empty_frames;
+		pdev->empty_frames = pdev->empty_frames->next;
+	}
+	else {
+		/* Hmm. Take it from the full list */
+#if PWC_DEBUG
+		/* sanity check */
+		if (pdev->full_frames == NULL) {
+			Err("Neither empty or full frames available!\n");
+			spin_unlock_irqrestore(&pdev->ptrlock, flags);
+			return -EINVAL;
+		}
+#endif
+		pdev->fill_frame = pdev->full_frames;
+		pdev->full_frames = pdev->full_frames->next;
+		ret = 1;
+	}
+	pdev->fill_frame->next = NULL;
+#if PWC_DEBUG
+	Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
+	pdev->fill_frame->sequence = pdev->sequence++;
+#endif
+	spin_unlock_irqrestore(&pdev->ptrlock, flags);
+	return ret;
+}
+
+
+/**
+  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
+
+  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
+ */
+static void pwc_reset_buffers(struct pwc_device *pdev)
+{
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdev->ptrlock, flags);
+	pdev->full_frames = NULL;
+	pdev->full_frames_tail = NULL;
+	for (i = 0; i < default_fbufs; i++) {
+		pdev->fbuf[i].filled = 0;
+		if (i > 0)
+			pdev->fbuf[i].next = &pdev->fbuf[i - 1];
+		else
+			pdev->fbuf->next = NULL;
+	}
+	pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
+	pdev->empty_frames_tail = pdev->fbuf;
+	pdev->read_frame = NULL;
+	pdev->fill_frame = pdev->empty_frames;
+	pdev->empty_frames = pdev->empty_frames->next;
+
+	pdev->image_read_pos = 0;
+	pdev->fill_image = 0;
+	spin_unlock_irqrestore(&pdev->ptrlock, flags);
+}
+
+
+/**
+  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
+ */
+static int pwc_handle_frame(struct pwc_device *pdev)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdev->ptrlock, flags);
+	/* First grab our read_frame; this is removed from all lists, so
+	   we can release the lock after this without problems */
+	if (pdev->read_frame != NULL) {
+		/* This can't theoretically happen */
+		Err("Huh? Read frame still in use?\n");
+	}
+	else {
+		if (pdev->full_frames == NULL) {
+			Err("Woops. No frames ready.\n");
+		}
+		else {
+			pdev->read_frame = pdev->full_frames;
+			pdev->full_frames = pdev->full_frames->next;
+			pdev->read_frame->next = NULL;
+		}
+
+		if (pdev->read_frame != NULL) {
+#if PWC_DEBUG
+			Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
+#endif
+			/* Decompression is a lenghty process, so it's outside of the lock.
+			   This gives the isoc_handler the opportunity to fill more frames
+			   in the mean time.
+			*/
+			spin_unlock_irqrestore(&pdev->ptrlock, flags);
+			ret = pwc_decompress(pdev);
+			spin_lock_irqsave(&pdev->ptrlock, flags);
+
+			/* We're done with read_buffer, tack it to the end of the empty buffer list */
+			if (pdev->empty_frames == NULL) {
+				pdev->empty_frames = pdev->read_frame;
+				pdev->empty_frames_tail = pdev->empty_frames;
+			}
+			else {
+				pdev->empty_frames_tail->next = pdev->read_frame;
+				pdev->empty_frames_tail = pdev->read_frame;
+			}
+			pdev->read_frame = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&pdev->ptrlock, flags);
+	return ret;
+}
+
+/**
+  \brief Advance pointers of image buffer (after each user request)
+*/
+static inline void pwc_next_image(struct pwc_device *pdev)
+{
+	pdev->image_used[pdev->fill_image] = 0;
+	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+}
+
+
+/* This gets called for the Isochronous pipe (video). This is done in
+ * interrupt time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
+{
+	struct pwc_device *pdev;
+	int i, fst, flen;
+	int awake;
+	struct pwc_frame_buf *fbuf;
+	unsigned char *fillptr = NULL, *iso_buf = NULL;
+
+	awake = 0;
+	pdev = (struct pwc_device *)urb->context;
+	if (pdev == NULL) {
+		Err("isoc_handler() called with NULL device?!\n");
+		return;
+	}
+#ifdef PWC_MAGIC
+	if (pdev->magic != PWC_MAGIC) {
+		Err("isoc_handler() called with bad magic!\n");
+		return;
+	}
+#endif
+	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+		return;
+	}
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		const char *errmsg;
+
+		errmsg = "Unknown";
+		switch(urb->status) {
+			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
+			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
+			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
+			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
+			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;
+			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
+		}
+		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+		/* Give up after a number of contiguous errors on the USB bus. 
+		   Appearantly something is wrong so we simulate an unplug event.
+		 */
+		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
+		{
+			Info("Too many ISOC errors, bailing out.\n");
+			pdev->error_status = EIO;
+			awake = 1;
+			wake_up_interruptible(&pdev->frameq);
+		}
+		goto handler_end; // ugly, but practical
+	}
+
+	fbuf = pdev->fill_frame;
+	if (fbuf == NULL) {
+		Err("pwc_isoc_handler without valid fill frame.\n");
+		awake = 1;
+		goto handler_end;
+	}
+	else {
+		fillptr = fbuf->data + fbuf->filled;
+	}
+
+	/* Reset ISOC error counter. We did get here, after all. */
+	pdev->visoc_errors = 0;
+
+	/* vsync: 0 = don't copy data
+	          1 = sync-hunt
+	          2 = synched
+	 */
+	/* Compact data */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		fst  = urb->iso_frame_desc[i].status;
+		flen = urb->iso_frame_desc[i].actual_length;
+		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		if (fst == 0) {
+			if (flen > 0) { /* if valid data... */
+				if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
+					pdev->vsync = 2;
+
+					/* ...copy data to frame buffer, if possible */
+					if (flen + fbuf->filled > pdev->frame_total_size) {
+						Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+						pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
+						pdev->vframes_error++;
+					}
+					else {
+						memmove(fillptr, iso_buf, flen);
+						fillptr += flen;
+					}
+				}
+				fbuf->filled += flen;
+			} /* ..flen > 0 */
+
+			if (flen < pdev->vlast_packet_size) {
+				/* Shorter packet... We probably have the end of an image-frame; 
+				   wake up read() process and let select()/poll() do something.
+				   Decompression is done in user time over there.
+				 */
+				if (pdev->vsync == 2) {
+					/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 
+					   frames on the USB wire after an exposure change. This conditition is 
+					   however detected  in the cam and a bit is set in the header.
+					 */
+					if (pdev->type == 730) {
+						unsigned char *ptr = (unsigned char *)fbuf->data;
+						
+						if (ptr[1] == 1 && ptr[0] & 0x10) {
+#if PWC_DEBUG
+							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
+#endif
+							pdev->drop_frames += 2;
+							pdev->vframes_error++;
+						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+							if (ptr[0] & 0x01)
+								Info("Snapshot button pressed.\n");
+							else
+								Info("Snapshot button released.\n");
+						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+							if (ptr[0] & 0x02)
+								Info("Image is mirrored.\n");
+							else
+								Info("Image is normal.\n");
+						}
+						pdev->vmirror = ptr[0] & 0x03;
+						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
+						   after a short frame; this condition is filtered out specifically. A 4 byte
+						   frame doesn't make sense anyway.
+						   So we get either this sequence: 
+						   	drop_bit set -> 4 byte frame -> short frame -> good frame
+						   Or this one:
+						   	drop_bit set -> short frame -> good frame
+						   So we drop either 3 or 2 frames in all!
+						 */
+						if (fbuf->filled == 4)
+							pdev->drop_frames++;
+					}
+
+					/* In case we were instructed to drop the frame, do so silently.
+					   The buffer pointers are not updated either (but the counters are reset below).
+					 */
+					if (pdev->drop_frames > 0)
+						pdev->drop_frames--;
+					else {
+						/* Check for underflow first */
+						if (fbuf->filled < pdev->frame_total_size) {
+							Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
+							pdev->vframes_error++;
+						}
+						else {
+							/* Send only once per EOF */
+							awake = 1; /* delay wake_ups */
+
+							/* Find our next frame to fill. This will always succeed, since we
+							 * nick a frame from either empty or full list, but if we had to
+							 * take it from the full list, it means a frame got dropped.
+							 */
+							if (pwc_next_fill_frame(pdev)) {
+								pdev->vframes_dumped++;
+								if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
+									if (pdev->vframes_dumped < 20)
+										Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
+									if (pdev->vframes_dumped == 20)
+										Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
+								}
+							}
+							fbuf = pdev->fill_frame;
+						}
+					} /* !drop_frames */
+					pdev->vframe_count++;
+				}
+				fbuf->filled = 0;
+				fillptr = fbuf->data;
+				pdev->vsync = 1;
+			} /* .. flen < last_packet_size */
+			pdev->vlast_packet_size = flen;
+		} /* ..status == 0 */
+#if PWC_DEBUG
+		/* This is normally not interesting to the user, unless you are really debugging something */
+		else {
+			static int iso_error = 0;
+			iso_error++;
+			if (iso_error < 20)
+				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		}
+#endif
+	}
+
+handler_end:
+	if (awake)
+		wake_up_interruptible(&pdev->frameq);
+
+	urb->dev = pdev->udev;
+	i = usb_submit_urb(urb, GFP_ATOMIC);
+	if (i != 0)
+		Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+}
+
+
+static int pwc_isoc_init(struct pwc_device *pdev)
+{
+	struct usb_device *udev;
+	struct urb *urb;
+	int i, j, ret;
+
+	struct usb_interface *intf;
+	struct usb_host_interface *idesc = NULL;
+
+	if (pdev == NULL)
+		return -EFAULT;
+	if (pdev->iso_init)
+		return 0;
+	pdev->vsync = 0;
+	udev = pdev->udev;
+
+	/* Get the current alternate interface, adjust packet size */
+	if (!udev->actconfig)
+		return -EFAULT;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
+	idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
+#else
+	intf = usb_ifnum_to_if(udev, 0);
+	if (intf)
+		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
+#endif
+		
+	if (!idesc)
+		return -EFAULT;
+
+	/* Search video endpoint */
+	pdev->vmax_packet_size = -1;
+	for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+		if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
+			pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
+			break;
+		}
+	
+	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
+		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+		return -ENFILE; /* Odd error, that should be noticeable */
+	}
+
+	/* Set alternate interface */
+	ret = 0;
+	Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+		if (urb == NULL) {
+			Err("Failed to allocate urb %d\n", i);
+			ret = -ENOMEM;
+			break;
+		}
+		pdev->sbuf[i].urb = urb;
+		Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+	}
+	if (ret) {
+		/* De-allocate in reverse order */
+		while (i >= 0) {
+			if (pdev->sbuf[i].urb != NULL)
+				usb_free_urb(pdev->sbuf[i].urb);
+			pdev->sbuf[i].urb = NULL;
+			i--;
+		}
+		return ret;
+	}
+
+	/* init URB structure */	
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		urb = pdev->sbuf[i].urb;
+
+		urb->interval = 1; // devik
+		urb->dev = udev;
+	        urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
+		urb->transfer_flags = URB_ISO_ASAP;
+	        urb->transfer_buffer = pdev->sbuf[i].data;
+	        urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+	        urb->complete = pwc_isoc_handler;
+	        urb->context = pdev;
+		urb->start_frame = 0;
+		urb->number_of_packets = ISO_FRAMES_PER_DESC;
+		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
+		}
+	}
+
+	/* link */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
+		if (ret)
+			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+		else
+			Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+	}
+
+	/* All is done... */
+	pdev->iso_init = 1;
+	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+	return 0;
+}
+
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+	int i;
+
+	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+	if (pdev == NULL)
+		return;
+
+	/* Unlinking ISOC buffers one by one */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = pdev->sbuf[i].urb;
+		if (urb != 0) {
+			if (pdev->iso_init) {
+				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+				usb_kill_urb(urb);
+			}
+			Trace(TRACE_MEMORY, "Freeing URB\n");
+			usb_free_urb(urb);
+			pdev->sbuf[i].urb = NULL;
+		}
+	}
+
+	/* Stop camera, but only if we are sure the camera is still there (unplug
+	   is signalled by EPIPE) 
+	 */
+	if (pdev->error_status && pdev->error_status != EPIPE) {
+		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+		usb_set_interface(pdev->udev, 0, 0);
+	}
+
+	pdev->iso_init = 0;
+	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+}
+
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
+{
+	int ret, start;
+
+	/* Stop isoc stuff */
+	pwc_isoc_cleanup(pdev);
+	/* Reset parameters */
+	pwc_reset_buffers(pdev);
+	/* Try to set video mode... */
+	start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
+	if (ret) { 
+	        Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+		/* That failed... restore old mode (we know that worked) */
+		start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+		if (start) {
+		        Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+		}
+	}
+	if (start == 0)
+	{
+		if (pwc_isoc_init(pdev) < 0)
+		{
+			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+			ret = -EAGAIN; /* let's try again, who knows if it works a second time */
+		}
+	}
+	pdev->drop_frames++; /* try to avoid garbage during switch */
+	return ret; /* Return original error code */
+}
+
+
+/***************************************************************************/
+/* Video4Linux functions */
+
+static int pwc_video_open(struct inode *inode, struct file *file)
+{
+	int i;
+	struct video_device *vdev = video_devdata(file);
+	struct pwc_device *pdev;
+
+	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+	
+	pdev = (struct pwc_device *)vdev->priv;
+	if (pdev == NULL)
+		BUG();
+	if (pdev->vopen)
+		return -EBUSY;
+	
+	down(&pdev->modlock);
+	if (!pdev->usb_init) {
+		Trace(TRACE_OPEN, "Doing first time initialization.\n");
+		pdev->usb_init = 1;
+		
+		if (pwc_trace & TRACE_OPEN)
+		{
+			/* Query sensor type */
+			const char *sensor_type = NULL;
+			int ret;
+
+			ret = pwc_get_cmos_sensor(pdev, &i);
+			if (ret >= 0)
+			{
+				switch(i) {
+				case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
+				case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
+				case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+				case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
+				case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
+				case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+				case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+				case 0x40:  sensor_type = "UPA 1021 sensor"; break;
+				case 0x100: sensor_type = "VGA sensor"; break;
+				case 0x101: sensor_type = "PAL MR sensor"; break;
+				default:    sensor_type = "unknown type of sensor"; break;
+				}
+			}
+			if (sensor_type != NULL)
+				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+		}
+	}
+
+	/* Turn on camera */
+	if (power_save) {
+		i = pwc_camera_power(pdev, 1);
+		if (i < 0)
+			Info("Failed to restore power to the camera! (%d)\n", i);
+	}
+	/* Set LED on/off time */
+	if (pwc_set_leds(pdev, led_on, led_off) < 0)
+		Info("Failed to set LED on/off time.\n");
+	
+	pwc_construct(pdev); /* set min/max sizes correct */
+
+	/* So far, so good. Allocate memory. */
+	i = pwc_allocate_buffers(pdev);
+	if (i < 0) {
+		Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+		up(&pdev->modlock);
+		return i;
+	}
+	
+	/* Reset buffers & parameters */
+	pwc_reset_buffers(pdev);
+	for (i = 0; i < default_mbufs; i++)
+		pdev->image_used[i] = 0;
+	pdev->vframe_count = 0;
+	pdev->vframes_dumped = 0;
+	pdev->vframes_error = 0;
+	pdev->visoc_errors = 0;
+	pdev->error_status = 0;
+#if PWC_DEBUG
+	pdev->sequence = 0;
+#endif
+	pwc_construct(pdev); /* set min/max sizes correct */
+
+	/* Set some defaults */
+	pdev->vsnapshot = 0;
+
+	/* Start iso pipe for video; first try the last used video size
+	   (or the default one); if that fails try QCIF/10 or QSIF/10;
+	   it that fails too, give up.
+	 */
+	i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
+	if (i)	{
+		Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
+		if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
+			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+		else
+			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+	}
+	if (i) {
+		Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+		up(&pdev->modlock);
+		return i;
+	}
+	
+	i = pwc_isoc_init(pdev);
+	if (i) {
+		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+		up(&pdev->modlock);
+		return i;
+	}
+
+	pdev->vopen++;
+	file->private_data = vdev;
+	up(&pdev->modlock);
+	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+	return 0;
+}
+
+/* Note that all cleanup is done in the reverse order as in _open */
+static int pwc_video_close(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+	int i;
+
+	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+
+	pdev = (struct pwc_device *)vdev->priv;
+	if (pdev->vopen == 0)
+		Info("video_close() called on closed device?\n");
+
+	/* Dump statistics, but only if a reasonable amount of frames were
+	   processed (to prevent endless log-entries in case of snap-shot
+	   programs)
+	 */
+	if (pdev->vframe_count > 20)
+		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+
+	switch (pdev->type)
+	 {
+	  case 675:
+	  case 680:
+	  case 690:
+	  case 720:
+	  case 730:
+	  case 740:
+	  case 750:
+/*	    pwc_dec23_exit();	*//* Timon & Kiara */
+	    break;
+	  case 645:
+	  case 646:
+/*	    pwc_dec1_exit(); */
+	    break;
+	 }
+
+	pwc_isoc_cleanup(pdev);
+	pwc_free_buffers(pdev);
+
+	/* Turn off LEDS and power down camera, but only when not unplugged */
+	if (pdev->error_status != EPIPE) {
+		/* Turn LEDs off */
+		if (pwc_set_leds(pdev, 0, 0) < 0)
+			Info("Failed to set LED on/off time.\n");
+		if (power_save) {
+			i = pwc_camera_power(pdev, 0);
+			if (i < 0)
+				Err("Failed to power down camera (%d)\n", i);
+		}
+	}
+	pdev->vopen = 0;
+	Trace(TRACE_OPEN, "<< video_close()\n");
+	return 0;
+}
+
+/*
+ *	FIXME: what about two parallel reads ????
+ *      ANSWER: Not supported. You can't open the device more than once,
+                despite what the V4L1 interface says. First, I don't see
+                the need, second there's no mechanism of alerting the
+                2nd/3rd/... process of events like changing image size.
+                And I don't see the point of blocking that for the
+                2nd/3rd/... process.
+                In multi-threaded environments reading parallel from any
+                device is tricky anyhow.
+ */
+
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+			  size_t count, loff_t *ppos)
+{
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+	int noblock = file->f_flags & O_NONBLOCK;
+	DECLARE_WAITQUEUE(wait, current);
+        int bytes_to_read;
+
+	Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+	if (vdev == NULL)
+		return -EFAULT;
+	pdev = vdev->priv;
+	if (pdev == NULL)
+		return -EFAULT;
+	if (pdev->error_status)
+		return -pdev->error_status; /* Something happened, report what. */
+
+	/* In case we're doing partial reads, we don't have to wait for a frame */
+	if (pdev->image_read_pos == 0) {
+		/* Do wait queueing according to the (doc)book */
+		add_wait_queue(&pdev->frameq, &wait);
+		while (pdev->full_frames == NULL) {
+			/* Check for unplugged/etc. here */
+			if (pdev->error_status) {
+				remove_wait_queue(&pdev->frameq, &wait);
+				set_current_state(TASK_RUNNING);
+				return -pdev->error_status ;
+			}
+	                if (noblock) {
+	                	remove_wait_queue(&pdev->frameq, &wait);
+	                	set_current_state(TASK_RUNNING);
+	                	return -EWOULDBLOCK;
+	                }
+	                if (signal_pending(current)) {
+	                	remove_wait_queue(&pdev->frameq, &wait);
+	                	set_current_state(TASK_RUNNING);
+	                	return -ERESTARTSYS;
+	                }
+	                schedule();
+	               	set_current_state(TASK_INTERRUPTIBLE);
+		}
+		remove_wait_queue(&pdev->frameq, &wait);
+		set_current_state(TASK_RUNNING);
+                                                                                                                                                                                
+		/* Decompress and release frame */
+		if (pwc_handle_frame(pdev))
+			return -EFAULT;
+	}
+
+	Trace(TRACE_READ, "Copying data to user space.\n");
+	if (pdev->vpalette == VIDEO_PALETTE_RAW)
+		bytes_to_read = pdev->frame_size;
+	else
+ 		bytes_to_read = pdev->view.size;
+
+	/* copy bytes to user space; we allow for partial reads */
+	if (count + pdev->image_read_pos > bytes_to_read)
+		count = bytes_to_read - pdev->image_read_pos;
+	if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+		return -EFAULT;
+	pdev->image_read_pos += count;
+	if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
+		pdev->image_read_pos = 0;
+		pwc_next_image(pdev);
+	}
+	return count;
+}
+
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
+{
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+
+	if (vdev == NULL)
+		return -EFAULT;
+	pdev = vdev->priv;
+	if (pdev == NULL)
+		return -EFAULT;
+
+	poll_wait(file, &pdev->frameq, wait);
+	if (pdev->error_status)
+		return POLLERR;
+	if (pdev->full_frames != NULL) /* we have frames waiting */
+		return (POLLIN | POLLRDNORM);
+
+	return 0;
+}
+
+static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+			      unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (vdev == NULL)
+		return -EFAULT;
+	pdev = vdev->priv;
+	if (pdev == NULL)
+		return -EFAULT;
+
+	switch (cmd) {
+		/* Query cabapilities */
+		case VIDIOCGCAP:
+		{
+			struct video_capability *caps = arg;
+
+			strcpy(caps->name, vdev->name);
+			caps->type = VID_TYPE_CAPTURE;
+			caps->channels = 1;
+			caps->audios = 1;
+			caps->minwidth  = pdev->view_min.x;
+			caps->minheight = pdev->view_min.y;
+			caps->maxwidth  = pdev->view_max.x;
+			caps->maxheight = pdev->view_max.y;
+			break;
+		}
+
+		/* Channel functions (simulate 1 channel) */
+		case VIDIOCGCHAN:
+		{
+			struct video_channel *v = arg;
+
+			if (v->channel != 0)
+				return -EINVAL;
+			v->flags = 0;
+			v->tuners = 0;
+			v->type = VIDEO_TYPE_CAMERA;
+			strcpy(v->name, "Webcam");
+			return 0;
+		}
+
+		case VIDIOCSCHAN:
+		{
+			/* The spec says the argument is an integer, but
+			   the bttv driver uses a video_channel arg, which
+			   makes sense becasue it also has the norm flag.
+			 */
+			struct video_channel *v = arg;
+			if (v->channel != 0)
+				return -EINVAL;
+			return 0;
+		}
+
+
+		/* Picture functions; contrast etc. */
+		case VIDIOCGPICT:
+		{
+			struct video_picture *p = arg;
+			int val;
+
+			val = pwc_get_brightness(pdev);
+			if (val >= 0)
+				p->brightness = val;
+			else
+				p->brightness = 0xffff;
+			val = pwc_get_contrast(pdev);
+			if (val >= 0)
+				p->contrast = val;
+			else
+				p->contrast = 0xffff;
+			/* Gamma, Whiteness, what's the difference? :) */
+			val = pwc_get_gamma(pdev);
+			if (val >= 0)
+				p->whiteness = val;
+			else
+				p->whiteness = 0xffff;
+			val = pwc_get_saturation(pdev);
+			if (val >= 0)
+				p->colour = val;
+			else
+				p->colour = 0xffff;
+			p->depth = 24;
+			p->palette = pdev->vpalette;
+			p->hue = 0xFFFF; /* N/A */
+			break;
+		}
+
+		case VIDIOCSPICT:
+		{
+			struct video_picture *p = arg;
+			/*
+			 *	FIXME:	Suppose we are mid read
+			        ANSWER: No problem: the firmware of the camera
+			                can handle brightness/contrast/etc
+			                changes at _any_ time, and the palette
+			                is used exactly once in the uncompress
+			                routine.
+			 */
+			pwc_set_brightness(pdev, p->brightness);
+			pwc_set_contrast(pdev, p->contrast);
+			pwc_set_gamma(pdev, p->whiteness);
+			pwc_set_saturation(pdev, p->colour);
+			if (p->palette && p->palette != pdev->vpalette) {
+				switch (p->palette) {
+					case VIDEO_PALETTE_YUV420P:
+					case VIDEO_PALETTE_RAW:
+						pdev->vpalette = p->palette;
+						return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+						break;
+					default:
+						return -EINVAL;
+						break;
+				}
+			}
+			break;
+		}
+
+		/* Window/size parameters */		
+		case VIDIOCGWIN:
+		{
+			struct video_window *vw = arg;
+			
+			vw->x = 0;
+			vw->y = 0;
+			vw->width = pdev->view.x;
+			vw->height = pdev->view.y;
+			vw->chromakey = 0;
+			vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | 
+			           (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+			break;
+		}
+		
+		case VIDIOCSWIN:
+		{
+			struct video_window *vw = arg;
+			int fps, snapshot, ret;
+
+			fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+			snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+			if (fps == 0)
+				fps = pdev->vframes;
+			if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+				return 0;
+			ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+			if (ret)
+				return ret;
+			break;		
+		}
+		
+		/* We don't have overlay support (yet) */
+		case VIDIOCGFBUF:
+		{
+			struct video_buffer *vb = arg;
+
+			memset(vb,0,sizeof(*vb));
+			break;
+		}
+
+		/* mmap() functions */
+		case VIDIOCGMBUF:
+		{
+			/* Tell the user program how much memory is needed for a mmap() */
+			struct video_mbuf *vm = arg;
+			int i;
+
+			memset(vm, 0, sizeof(*vm));
+			vm->size = default_mbufs * pdev->len_per_image;
+			vm->frames = default_mbufs; /* double buffering should be enough for most applications */
+			for (i = 0; i < default_mbufs; i++)
+				vm->offsets[i] = i * pdev->len_per_image;
+			break;
+		}
+
+		case VIDIOCMCAPTURE:
+		{
+			/* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+			struct video_mmap *vm = arg;
+
+			Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+			if (vm->frame < 0 || vm->frame >= default_mbufs)
+				return -EINVAL;
+
+			/* xawtv is nasty. It probes the available palettes
+			   by setting a very small image size and trying
+			   various palettes... The driver doesn't support
+			   such small images, so I'm working around it.
+			 */
+			if (vm->format)
+			{
+				switch (vm->format)
+				{
+					case VIDEO_PALETTE_YUV420P:
+					case VIDEO_PALETTE_RAW:
+						break;
+					default:
+						return -EINVAL;
+						break;
+				}
+			}
+
+			if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+			    (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+				int ret;
+
+				Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+				ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+				if (ret)
+					return ret;
+			} /* ... size mismatch */
+
+			/* FIXME: should we lock here? */
+			if (pdev->image_used[vm->frame])
+				return -EBUSY;	/* buffer wasn't available. Bummer */
+			pdev->image_used[vm->frame] = 1;
+
+			/* Okay, we're done here. In the SYNC call we wait until a 
+			   frame comes available, then expand image into the given 
+			   buffer.
+			   In contrast to the CPiA cam the Philips cams deliver a
+			   constant stream, almost like a grabber card. Also,
+			   we have separate buffers for the rawdata and the image,
+			   meaning we can nearly always expand into the requested buffer.
+			 */
+			Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
+			break;
+		}
+
+		case VIDIOCSYNC:
+		{
+			/* The doc says: "Whenever a buffer is used it should
+			   call VIDIOCSYNC to free this frame up and continue."
+			   
+			   The only odd thing about this whole procedure is 
+			   that MCAPTURE flags the buffer as "in use", and
+			   SYNC immediately unmarks it, while it isn't 
+			   after SYNC that you know that the buffer actually
+			   got filled! So you better not start a CAPTURE in
+			   the same frame immediately (use double buffering). 
+			   This is not a problem for this cam, since it has 
+			   extra intermediate buffers, but a hardware 
+			   grabber card will then overwrite the buffer 
+			   you're working on.
+			 */
+			int *mbuf = arg;
+			int ret;
+
+			Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
+
+			/* bounds check */
+			if (*mbuf < 0 || *mbuf >= default_mbufs)
+				return -EINVAL;
+			/* check if this buffer was requested anyway */
+			if (pdev->image_used[*mbuf] == 0)
+				return -EINVAL;
+
+			/* Add ourselves to the frame wait-queue.
+			   
+			   FIXME: needs auditing for safety.
+			   QUESTION: In what respect? I think that using the
+			             frameq is safe now.
+			 */
+			add_wait_queue(&pdev->frameq, &wait);
+			while (pdev->full_frames == NULL) {
+				if (pdev->error_status) {
+					remove_wait_queue(&pdev->frameq, &wait);
+					set_current_state(TASK_RUNNING);
+					return -pdev->error_status;
+				}
+			
+	                	if (signal_pending(current)) {
+	                		remove_wait_queue(&pdev->frameq, &wait);
+		                	set_current_state(TASK_RUNNING);
+		                	return -ERESTARTSYS;
+	        	        }
+	                	schedule();
+		                set_current_state(TASK_INTERRUPTIBLE);
+			}
+			remove_wait_queue(&pdev->frameq, &wait);
+			set_current_state(TASK_RUNNING);
+				
+			/* The frame is ready. Expand in the image buffer 
+			   requested by the user. I don't care if you 
+			   mmap() 5 buffers and request data in this order: 
+			   buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+			   Grabber hardware may not be so forgiving.
+			 */
+			Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
+			pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+			/* Decompress, etc */
+			ret = pwc_handle_frame(pdev);
+			pdev->image_used[*mbuf] = 0;
+			if (ret)
+				return -EFAULT;
+			break;
+		}
+		
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio *v = arg;
+			
+			strcpy(v->name, "Microphone");
+			v->audio = -1; /* unknown audio minor */
+			v->flags = 0;
+			v->mode = VIDEO_SOUND_MONO;
+			v->volume = 0;
+			v->bass = 0;
+			v->treble = 0;
+			v->balance = 0x8000;
+			v->step = 1;
+			break;	
+		}
+		
+		case VIDIOCSAUDIO:
+		{
+			/* Dummy: nothing can be set */
+			break;
+		}
+		
+		case VIDIOCGUNIT:
+		{
+			struct video_unit *vu = arg;
+			
+			vu->video = pdev->vdev->minor & 0x3F;
+			vu->audio = -1; /* not known yet */
+			vu->vbi = -1;
+			vu->radio = -1;
+			vu->teletext = -1;
+			break;
+		}
+		default:
+			return pwc_ioctl(pdev, cmd, arg);
+	} /* ..switch */
+	return 0;
+}	
+
+static int pwc_video_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+}
+
+
+static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end-vma->vm_start;
+	unsigned long page, pos;
+	
+	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+	pdev = vdev->priv;
+	
+	vma->vm_flags |= VM_IO;
+
+	pos = (unsigned long)pdev->image_data;
+	while (size > 0) {
+		page = vmalloc_to_pfn((void *)pos);
+		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return 0;
+}
+
+/***************************************************************************/
+/* USB functions */
+
+/* This function gets called when a new device is plugged in or the usb core
+ * is loaded.
+ */
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct pwc_device *pdev = NULL;
+	int vendor_id, product_id, type_id;
+	int i, hint;
+	int features = 0;
+	int video_nr = -1; /* default: use next available device */
+	char serial_number[30], *name;
+
+	/* Check if we can handle this device */
+	Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", 
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct),
+		intf->altsetting->desc.bInterfaceNumber);
+
+	/* the interfaces are probed one by one. We are only interested in the
+	   video interface (0) now.
+	   Interface 1 is the Audio Control, and interface 2 Audio itself.
+	 */
+	if (intf->altsetting->desc.bInterfaceNumber > 0)
+		return -ENODEV;
+
+	vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+	product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+	if (vendor_id == 0x0471) {
+		switch (product_id) {
+		case 0x0302:
+			Info("Philips PCA645VC USB webcam detected.\n");
+			name = "Philips 645 webcam";
+			type_id = 645;
+			break;
+		case 0x0303:
+			Info("Philips PCA646VC USB webcam detected.\n");
+			name = "Philips 646 webcam";
+			type_id = 646;
+			break;
+		case 0x0304:
+			Info("Askey VC010 type 2 USB webcam detected.\n");
+			name = "Askey VC010 webcam";
+			type_id = 646;
+			break;
+		case 0x0307:
+			Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+			name = "Philips 675 webcam";
+			type_id = 675;
+			break;
+		case 0x0308:
+			Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+			name = "Philips 680 webcam";
+			type_id = 680;
+			break;
+		case 0x030C:
+			Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+			name = "Philips 690 webcam";
+			type_id = 690;
+			break;
+		case 0x0310:
+			Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+			name = "Philips 730 webcam";
+			type_id = 730;
+			break;
+		case 0x0311:
+			Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+			name = "Philips 740 webcam";
+			type_id = 740;
+			break;
+		case 0x0312:
+			Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+			name = "Philips 750 webcam";
+			type_id = 750;
+			break;
+		case 0x0313:
+			Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+			name = "Philips 720K/40 webcam";
+			type_id = 720;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else if (vendor_id == 0x069A) {
+		switch(product_id) {
+		case 0x0001:
+			Info("Askey VC010 type 1 USB webcam detected.\n");
+			name = "Askey VC010 webcam";
+			type_id = 645;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else if (vendor_id == 0x046d) {
+		switch(product_id) {
+		case 0x08b0:
+			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 3000";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b1:
+			Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Notebook Pro";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b2:
+			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 4000";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b3:
+			Info("Logitech QuickCam Zoom USB webcam detected.\n");
+			name = "Logitech QuickCam Zoom";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08B4:
+			Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+			name = "Logitech QuickCam Zoom";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b5:
+			Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+			name = "Logitech QuickCam Orbit";
+			type_id = 740; /* CCD sensor */
+			features |= FEATURE_MOTOR_PANTILT;
+			break;
+		case 0x08b6:
+		case 0x08b7:
+		case 0x08b8:
+			Info("Logitech QuickCam detected (reserved ID).\n");
+			name = "Logitech QuickCam (res.)";
+			type_id = 730; /* Assuming CMOS */
+			break;
+        	default:
+			return -ENODEV;
+        		break;
+        	}
+        }
+	else if (vendor_id == 0x055d) {
+		/* I don't know the difference between the C10 and the C30;
+		   I suppose the difference is the sensor, but both cameras
+		   work equally well with a type_id of 675
+		 */
+		switch(product_id) {
+		case 0x9000:
+			Info("Samsung MPC-C10 USB webcam detected.\n");
+			name = "Samsung MPC-C10";
+			type_id = 675;
+			break;
+		case 0x9001:
+			Info("Samsung MPC-C30 USB webcam detected.\n");
+			name = "Samsung MPC-C30";
+			type_id = 675;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else if (vendor_id == 0x041e) {
+		switch(product_id) {
+		case 0x400c:
+			Info("Creative Labs Webcam 5 detected.\n");
+			name = "Creative Labs Webcam 5";
+			type_id = 730;
+			break;
+		case 0x4011:
+			Info("Creative Labs Webcam Pro Ex detected.\n");
+			name = "Creative Labs Webcam Pro Ex";
+			type_id = 740;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else if (vendor_id == 0x04cc) {
+		switch(product_id) {
+		case 0x8116:
+			Info("Sotec Afina Eye USB webcam detected.\n");
+			name = "Sotec Afina Eye";
+			type_id = 730;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else if (vendor_id == 0x06be) {
+		switch(product_id) {
+		case 0x8116:
+			/* This is essentially the same cam as the Sotec Afina Eye */
+			Info("AME Co. Afina Eye USB webcam detected.\n");
+			name = "AME Co. Afina Eye";
+			type_id = 750;
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	
+	}
+	else if (vendor_id == 0x0d81) {
+		switch(product_id) {
+		case 0x1900:
+			Info("Visionite VCS-UC300 USB webcam detected.\n");
+			name = "Visionite VCS-UC300";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x1910:
+			Info("Visionite VCS-UM100 USB webcam detected.\n");
+			name = "Visionite VCS-UM100";
+			type_id = 730; /* CMOS sensor */
+			break;
+		default:
+			return -ENODEV;
+			break;
+		}
+	}
+	else 
+		return -ENODEV; /* Not any of the know types; but the list keeps growing. */
+
+	memset(serial_number, 0, 30);
+	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
+	Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+
+	if (udev->descriptor.bNumConfigurations > 1)
+		Info("Warning: more than 1 configuration available.\n");
+
+	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
+	pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL);
+	if (pdev == NULL) {
+		Err("Oops, could not allocate memory for pwc_device.\n");
+		return -ENOMEM;
+	}
+	memset(pdev, 0, sizeof(struct pwc_device));
+	pdev->type = type_id;
+	pdev->vsize = default_size;
+	pdev->vframes = default_fps;
+	strcpy(pdev->serial, serial_number);
+	pdev->features = features;
+	if (vendor_id == 0x046D && product_id == 0x08B5)
+	{
+		/* Logitech QuickCam Orbit
+	           The ranges have been determined experimentally; they may differ from cam to cam.
+	           Also, the exact ranges left-right and up-down are different for my cam
+	          */
+		pdev->angle_range.pan_min  = -7000;
+		pdev->angle_range.pan_max  =  7000;
+		pdev->angle_range.tilt_min = -3000;
+		pdev->angle_range.tilt_max =  2500;
+	}
+
+	init_MUTEX(&pdev->modlock);
+	spin_lock_init(&pdev->ptrlock);
+
+	pdev->udev = udev;
+	init_waitqueue_head(&pdev->frameq);
+	pdev->vcompression = pwc_preferred_compression;
+
+	/* Allocate video_device structure */
+	pdev->vdev = video_device_alloc();
+	if (pdev->vdev == 0)
+	{
+		Err("Err, cannot allocate video_device struture. Failing probe.");
+		kfree(pdev);
+		return -ENOMEM;
+	}
+	memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+	strcpy(pdev->vdev->name, name);
+	pdev->vdev->owner = THIS_MODULE;
+	video_set_drvdata(pdev->vdev, pdev);
+
+	pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
+	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+
+	/* Now search device_hint[] table for a match, so we can hint a node number. */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
+		if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
+		     (device_hint[hint].pdev == NULL)) {
+			/* so far, so good... try serial number */
+			if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
+			    	/* match! */
+			    	video_nr = device_hint[hint].device_node;
+			    	Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+			    	break;
+			}
+		}
+	}
+
+	pdev->vdev->release = video_device_release;
+	i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+	if (i < 0) {
+		Err("Failed to register as video device (%d).\n", i);
+		video_device_release(pdev->vdev); /* Drip... drip... drip... */
+		kfree(pdev); /* Oops, no memory leaks please */
+		return -EIO;
+	}
+	else {
+		Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+	}
+
+	/* occupy slot */
+	if (hint < MAX_DEV_HINTS) 
+		device_hint[hint].pdev = pdev;
+
+	Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+	usb_set_intfdata (intf, pdev);
+	return 0;
+}
+
+/* The user janked out the cable... */
+static void usb_pwc_disconnect(struct usb_interface *intf)
+{
+	struct pwc_device *pdev;
+	int hint;
+
+	lock_kernel();
+	pdev = usb_get_intfdata (intf);
+	usb_set_intfdata (intf, NULL);
+	if (pdev == NULL) {
+		Err("pwc_disconnect() Called without private pointer.\n");
+		goto disconnect_out;
+	}
+	if (pdev->udev == NULL) {
+		Err("pwc_disconnect() already called for %p\n", pdev);
+		goto disconnect_out;
+	}
+	if (pdev->udev != interface_to_usbdev(intf)) {
+		Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+		goto disconnect_out;
+	}
+#ifdef PWC_MAGIC	
+	if (pdev->magic != PWC_MAGIC) {
+		Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+		goto disconnect_out;
+	}
+#endif
+	
+	/* We got unplugged; this is signalled by an EPIPE error code */
+	if (pdev->vopen) {
+		Info("Disconnected while webcam is in use!\n");
+		pdev->error_status = EPIPE;
+	}
+
+	/* Alert waiting processes */
+	wake_up_interruptible(&pdev->frameq);
+	/* Wait until device is closed */
+	while (pdev->vopen)
+		schedule();
+	/* Device is now closed, so we can safely unregister it */
+	Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+	video_unregister_device(pdev->vdev);
+
+	/* Free memory (don't set pdev to 0 just yet) */
+	kfree(pdev);
+
+disconnect_out:
+	/* search device_hint[] table if we occupy a slot, by any chance */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+		if (device_hint[hint].pdev == pdev)
+			device_hint[hint].pdev = NULL;
+
+	unlock_kernel();
+}
+
+
+/* *grunt* We have to do atoi ourselves :-( */
+static int pwc_atoi(const char *s)
+{
+	int k = 0;
+
+	k = 0;
+	while (*s != '\0' && *s >= '0' && *s <= '9') {
+		k = 10 * k + (*s - '0');
+		s++;
+	}
+	return k;
+}
+
+
+/* 
+ * Initialization code & module stuff 
+ */
+
+static char size[10];
+static int fps = 0;
+static int fbufs = 0;
+static int mbufs = 0;
+static int trace = -1;
+static int compression = -1;
+static int leds[2] = { -1, -1 };
+static char *dev_hint[MAX_DEV_HINTS] = { };
+
+module_param_string(size, size, sizeof(size), 0);
+MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
+module_param(fps, int, 0000);
+MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
+module_param(fbufs, int, 0000);
+MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
+module_param(mbufs, int, 0000);
+MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
+module_param(trace, int, 0000);
+MODULE_PARM_DESC(trace, "For debugging purposes");
+module_param(power_save, bool, 0000);
+MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+module_param(compression, int, 0000);
+MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
+module_param_array(leds, int, NULL, 0000);
+MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+module_param_array(dev_hint, charp, NULL, 0000);
+MODULE_PARM_DESC(dev_hint, "Device node hints");
+
+MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
+MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
+MODULE_LICENSE("GPL");
+
+static int __init usb_pwc_init(void)
+{
+	int i, sz;
+	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
+
+	Info("Philips webcam module version " PWC_VERSION " loaded.\n");
+	Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+	Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+	Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+
+	if (fps) {
+		if (fps < 4 || fps > 30) {
+			Err("Framerate out of bounds (4-30).\n");
+			return -EINVAL;
+		}
+		default_fps = fps;
+		Info("Default framerate set to %d.\n", default_fps);
+	}
+
+	if (size[0]) {
+		/* string; try matching with array */
+		for (sz = 0; sz < PSZ_MAX; sz++) {
+			if (!strcmp(sizenames[sz], size)) { /* Found! */
+				default_size = sz;
+				break;
+			}
+		}
+		if (sz == PSZ_MAX) {
+			Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+			return -EINVAL;
+		}
+		Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+	}
+	if (mbufs) {
+		if (mbufs < 1 || mbufs > MAX_IMAGES) {
+			Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+			return -EINVAL;
+		}
+		default_mbufs = mbufs;
+		Info("Number of image buffers set to %d.\n", default_mbufs);
+	}
+	if (fbufs) {
+		if (fbufs < 2 || fbufs > MAX_FRAMES) {
+			Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+			return -EINVAL;
+		}
+		default_fbufs = fbufs;
+		Info("Number of frame buffers set to %d.\n", default_fbufs);
+	}
+	if (trace >= 0) {
+		Info("Trace options: 0x%04x\n", trace);
+		pwc_trace = trace;
+	}
+	if (compression >= 0) {
+		if (compression > 3) {
+			Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+			return -EINVAL;
+		}
+		pwc_preferred_compression = compression;
+		Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+	}
+	if (power_save)
+		Info("Enabling power save on open/close.\n");
+	if (leds[0] >= 0)
+		led_on = leds[0];
+	if (leds[1] >= 0)
+		led_off = leds[1];
+
+	/* Big device node whoopla. Basically, it allows you to assign a
+	   device node (/dev/videoX) to a camera, based on its type
+	   & serial number. The format is [type[.serialnumber]:]node.
+
+	   Any camera that isn't matched by these rules gets the next
+	   available free device node.
+	 */
+	for (i = 0; i < MAX_DEV_HINTS; i++) {
+		char *s, *colon, *dot;
+
+		/* This loop also initializes the array */
+		device_hint[i].pdev = NULL;
+		s = dev_hint[i];
+		if (s != NULL && *s != '\0') {
+			device_hint[i].type = -1; /* wildcard */
+			strcpy(device_hint[i].serial_number, "*");
+
+			/* parse string: chop at ':' & '/' */
+			colon = dot = s;
+			while (*colon != '\0' && *colon != ':')
+				colon++;
+			while (*dot != '\0' && *dot != '.')
+				dot++;
+			/* Few sanity checks */
+			if (*dot != '\0' && dot > colon) {
+				Err("Malformed camera hint: the colon must be after the dot.\n");
+				return -EINVAL;
+			}
+
+			if (*colon == '\0') {
+				/* No colon */
+				if (*dot != '\0') {
+					Err("Malformed camera hint: no colon + device node given.\n");
+					return -EINVAL;
+				}
+				else {
+					/* No type or serial number specified, just a number. */
+					device_hint[i].device_node = pwc_atoi(s);
+				}
+			}
+			else {
+				/* There's a colon, so we have at least a type and a device node */
+				device_hint[i].type = pwc_atoi(s);
+				device_hint[i].device_node = pwc_atoi(colon + 1);
+				if (*dot != '\0') {
+					/* There's a serial number as well */
+					int k;
+					
+					dot++;
+					k = 0;
+					while (*dot != ':' && k < 29) {
+						device_hint[i].serial_number[k++] = *dot;
+						dot++;
+					}
+					device_hint[i].serial_number[k] = '\0';
+				}
+			}
+#if PWC_DEBUG		
+			Debug("device_hint[%d]:\n", i);
+			Debug("  type    : %d\n", device_hint[i].type);
+			Debug("  serial# : %s\n", device_hint[i].serial_number);
+			Debug("  node    : %d\n", device_hint[i].device_node);
+#endif			
+		}
+		else
+			device_hint[i].type = 0; /* not filled */
+	} /* ..for MAX_DEV_HINTS */
+
+ 	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+	return usb_register(&pwc_driver);
+}
+
+static void __exit usb_pwc_exit(void)
+{
+	Trace(TRACE_MODULE, "Deregistering driver.\n");
+	usb_deregister(&pwc_driver);
+	Info("Philips webcam module removed.\n");
+}
+
+module_init(usb_pwc_init);
+module_exit(usb_pwc_exit);
+
diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-ioctl.h
@@ -0,0 +1,292 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 is pwc-ioctl.h belonging to PWC 8.12.1
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+                          changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+               PWCX easier
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC		VIDeo IOCtl prefix
+         PWC		Philps WebCam
+            G           optional: Get
+            S           optional: Set
+             ... 	the function
+ */
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF	0x00
+#define PSZ_QSIF	0x01
+#define PSZ_QCIF	0x02
+#define PSZ_SIF		0x03
+#define PSZ_CIF		0x04
+#define PSZ_VGA		0x05
+#define PSZ_MAX		6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT		16
+#define PWC_FPS_MASK		0x00FF0000
+#define PWC_FPS_FRMASK		0x003F0000
+#define PWC_FPS_SNAPSHOT	0x00400000
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+	int x, y;		/* guess what */
+	int size;		/* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+	char name[32];
+	int type;
+};
+
+struct pwc_serial
+{
+	char serial[30];	/* String with serial number. Contains terminating 0 */
+};
+	
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR		0
+#define PWC_WB_OUTDOOR		1
+#define PWC_WB_FL		2
+#define PWC_WB_MANUAL		3
+#define PWC_WB_AUTO		4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). 
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside 
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/   
+struct pwc_whitebalance
+{
+	int mode;
+	int manual_red, manual_blue;	/* R/W */
+	int read_red, read_blue;	/* R/O */
+};
+
+/* 
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and 
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+	int control_speed;
+	int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+	int led_on;			/* Led on-time; range = 0..25000 */
+	int led_off;			/* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN		0x01
+#define PWC_MPT_TILT		0x02
+#define PWC_MPT_TIMEOUT		0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the 
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */   
+struct pwc_mpt_angles
+{
+	int absolute;		/* write-only */
+	int pan;		/* degrees * 100 */
+	int tilt;		/* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+	int pan_min, pan_max;		/* degrees * 100 */
+	int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+	int status;
+	int time_pan;
+	int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */   
+struct pwc_video_command
+{
+	int type;		/* camera type (645, 675, 730, etc.) */
+	int release;		/* release number */
+
+        int size;		/* one of PSZ_* */
+        int alternate;
+	int command_len;	/* length of USB video command */
+	unsigned char command_buf[13];	/* Actual USB video command */
+	int bandlength;		/* >0 = compressed */
+	int frame_size;		/* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR	0x0001
+#define PWCX_FLAG_BAYER		0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER		_IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER		_IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY	_IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL		_IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL		_IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL	_IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE		_IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC		_IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC		_IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER	_IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED	_IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED	_IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR	_IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR	_IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT	_IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT	_IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER	_IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER	_IOR('v', 208, int)  
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */ 
+#define VIDIOCPWCMPTRESET	_IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE	_IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE	_IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE	_IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS	_IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD	_IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE	_IOR('v', 216, struct pwc_table_init_buffer)
+
+#endif
diff --git a/drivers/usb/media/pwc/pwc-kiara.c b/drivers/usb/media/pwc/pwc-kiara.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-kiara.c
@@ -0,0 +1,318 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 tables contains entries for the 730/740/750 (Kiara) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+
+#include "pwc-kiara.h"
+#include "pwc-uncompress.h"
+
+const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}},
+         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+         {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}},
+         {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}},
+         {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}},
+         {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 25 fps */
+      {
+         {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}},
+         {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}},
+         {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+         {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}},
+      },
+      /* 30 fps */
+      {
+         {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}},
+         {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}},
+         {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}},
+         {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+         {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}},
+         {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}},
+         {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}},
+         {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}},
+         {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}},
+         {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}},
+         {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}},
+         {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}},
+         {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}},
+         {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}},
+         {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}},
+         {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}},
+         {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}},
+         {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}},
+         {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}},
+         {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}},
+         {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}},
+         {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+         {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+};
+
diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-kiara.h
@@ -0,0 +1,45 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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
+*/
+
+/* Entries for the Kiara (730/740/750) camera */
+
+#ifndef PWC_KIARA_H
+#define PWC_KIARA_H
+
+#include "pwc-ioctl.h"
+
+struct Kiara_table_entry
+{
+	char alternate;			/* USB alternate interface */
+	unsigned short packetsize;	/* Normal packet size */
+	unsigned short bandlength;	/* Bandlength when decompressing */
+	unsigned char mode[12];		/* precomputed mode settings for cam */
+};
+
+const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+const extern unsigned int KiaraRomTable[8][2][16][8];
+
+#endif
+
+
diff --git a/drivers/usb/media/pwc/pwc-misc.c b/drivers/usb/media/pwc/pwc-misc.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-misc.c
@@ -0,0 +1,140 @@
+/* Linux driver for Philips webcam 
+   Various miscellaneous functions and tables.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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/slab.h>
+
+#include "pwc.h"
+
+struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+{
+	{ 128,  96, 0 },
+	{ 160, 120, 0 },
+	{ 176, 144, 0 },
+	{ 320, 240, 0 },
+	{ 352, 288, 0 },
+	{ 640, 480, 0 },
+};
+
+/* x,y -> PSZ_ */
+int pwc_decode_size(struct pwc_device *pdev, int width, int height)
+{
+	int i, find;
+
+	/* Make sure we don't go beyond our max size.
+           NB: we have different limits for RAW and normal modes. In case
+           you don't have the decompressor loaded or use RAW mode, 
+           the maximum viewable size is smaller.
+        */
+	if (pdev->vpalette == VIDEO_PALETTE_RAW)
+	{
+		if (width > pdev->abs_max.x || height > pdev->abs_max.y)
+		{
+			Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+                	return -1;
+                }
+	}
+	else
+	{
+		if (width > pdev->view_max.x || height > pdev->view_max.y)
+		{
+			Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+			return -1;
+		}
+	}
+
+	/* Find the largest size supported by the camera that fits into the
+	   requested size.
+	 */
+	find = -1;
+	for (i = 0; i < PSZ_MAX; i++) {
+		if (pdev->image_mask & (1 << i)) {
+			if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
+				find = i;
+		}
+	}
+	return find;
+}
+
+/* initialize variables depending on type and decompressor*/
+void pwc_construct(struct pwc_device *pdev)
+{
+	switch(pdev->type) {
+	case 645:
+	case 646:
+		pdev->view_min.x = 128;
+		pdev->view_min.y =  96;
+		pdev->view_max.x = 352;
+		pdev->view_max.y = 288;
+                pdev->abs_max.x  = 352;
+                pdev->abs_max.y  = 288;
+		pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
+		pdev->vcinterface = 2;
+		pdev->vendpoint = 4;
+		pdev->frame_header_size = 0;
+		pdev->frame_trailer_size = 0;
+		break;
+	case 675:
+	case 680:
+	case 690:
+		pdev->view_min.x = 128;
+		pdev->view_min.y =  96;
+		/* Anthill bug #38: PWC always reports max size, even without PWCX */
+		pdev->view_max.x = 640;
+		pdev->view_max.y = 480;
+		pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
+                pdev->abs_max.x = 640;
+                pdev->abs_max.y = 480;
+		pdev->vcinterface = 3;
+		pdev->vendpoint = 4;
+		pdev->frame_header_size = 0;
+		pdev->frame_trailer_size = 0;
+		break;
+	case 720:
+	case 730:
+	case 740:
+	case 750:
+		pdev->view_min.x = 160;
+		pdev->view_min.y = 120;
+		pdev->view_max.x = 640;
+		pdev->view_max.y = 480;
+		pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+                pdev->abs_max.x = 640;
+                pdev->abs_max.y = 480;
+		pdev->vcinterface = 3;
+		pdev->vendpoint = 5;
+		pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+		pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+		break;
+	}
+	Debug("type = %d\n",pdev->type);
+	pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
+	pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
+	pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
+	/* length of image, in YUV format; always allocate enough memory. */
+	pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+}
+
+
diff --git a/drivers/usb/media/pwc/pwc-nala.h b/drivers/usb/media/pwc/pwc-nala.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-nala.h
@@ -0,0 +1,66 @@
+   /* SQCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x03}},
+      {8, 0, {0x05, 0x01, 0x03}},
+      {7, 0, {0x08, 0x01, 0x03}},
+      {7, 0, {0x0A, 0x01, 0x03}},
+      {6, 0, {0x0C, 0x01, 0x03}},
+      {5, 0, {0x0F, 0x01, 0x03}},
+      {4, 0, {0x14, 0x01, 0x03}},
+      {3, 0, {0x18, 0x01, 0x03}},
+   },
+   /* QSIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* QCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x02}},
+      {8, 0, {0x05, 0x01, 0x02}},
+      {7, 0, {0x08, 0x01, 0x02}},
+      {6, 0, {0x0A, 0x01, 0x02}},
+      {5, 0, {0x0C, 0x01, 0x02}},
+      {4, 0, {0x0F, 0x01, 0x02}},
+      {1, 0, {0x14, 0x01, 0x02}},
+      {1, 0, {0x18, 0x01, 0x02}},
+   },
+   /* SIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* CIF */
+   {
+      {4, 0, {0x04, 0x01, 0x01}},
+      {7, 1, {0x05, 0x03, 0x01}},
+      {6, 1, {0x08, 0x03, 0x01}},
+      {4, 1, {0x0A, 0x03, 0x01}},
+      {3, 1, {0x0C, 0x03, 0x01}},
+      {2, 1, {0x0F, 0x03, 0x01}},
+      {0},
+      {0},
+   },
+   /* VGA */
+   {  
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
diff --git a/drivers/usb/media/pwc/pwc-timon.c b/drivers/usb/media/pwc/pwc-timon.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-timon.c
@@ -0,0 +1,316 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#include "pwc-timon.h"
+
+const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}},
+         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}},
+         {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}},
+         {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}},
+         {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}},
+         {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}},
+         {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}},
+         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}},
+         {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}},
+         {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}},
+         {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}},
+         {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}},
+         {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}},
+         {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}},
+         {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}},
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+         {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}},
+         {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}},
+         {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}},
+         {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}},
+         {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}},
+         {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}},
+         {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}},
+         {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}},
+         {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}},
+         {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}},
+         {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}},
+         {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}},
+         {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}},
+         {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+         {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}},
+         {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}},
+         {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}},
+         {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}},
+         {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}},
+         {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}},
+         {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}},
+         {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}},
+         {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}},
+         {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}},
+         {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}},
+         {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}},
+         {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}},
+         {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}},
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}},
+         {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}},
+         {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}},
+         {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}},
+         {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+         {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+};
+
diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-timon.h
@@ -0,0 +1,61 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#ifndef PWC_TIMON_H
+#define PWC_TIMON_H
+
+#include "pwc-ioctl.h"
+
+struct Timon_table_entry
+{
+	char alternate;			/* USB alternate interface */
+	unsigned short packetsize;	/* Normal packet size */
+	unsigned short bandlength;	/* Bandlength when decompressing */
+	unsigned char mode[13];		/* precomputed mode settings for cam */
+};
+
+const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+const extern unsigned int TimonRomTable [16][2][16][8];
+
+
+#endif
+
+
diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-uncompress.c
@@ -0,0 +1,147 @@
+/* Linux driver for Philips webcam
+   Decompression frontend.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 <asm/current.h>
+#include <asm/types.h>
+
+#include "pwc.h"
+#include "pwc-uncompress.h"
+
+int pwc_decompress(struct pwc_device *pdev)
+{
+	struct pwc_frame_buf *fbuf;
+	int n, line, col, stride;
+	void *yuv, *image;
+	u16 *src;
+	u16 *dsty, *dstu, *dstv;
+
+	if (pdev == NULL)
+		return -EFAULT;
+#if defined(__KERNEL__) && defined(PWC_MAGIC)
+	if (pdev->magic != PWC_MAGIC) {
+		Err("pwc_decompress(): magic failed.\n");
+		return -EFAULT;
+	}
+#endif
+
+	fbuf = pdev->read_frame;
+	if (fbuf == NULL)
+		return -EFAULT;
+	image = pdev->image_ptr[pdev->fill_image];
+	if (!image)
+		return -EFAULT;
+
+	yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
+
+	/* Raw format; that's easy... */
+	if (pdev->vpalette == VIDEO_PALETTE_RAW)
+	{
+		memcpy(image, yuv, pdev->frame_size);
+		return 0;
+	}
+
+	if (pdev->vbandlength == 0) {
+		/* Uncompressed mode. We copy the data into the output buffer,
+		   using the viewport size (which may be larger than the image
+		   size). Unfortunately we have to do a bit of byte stuffing
+		   to get the desired output format/size.
+		 */
+			/*
+			 * We do some byte shuffling here to go from the
+			 * native format to YUV420P.
+			 */
+			src = (u16 *)yuv;
+			n = pdev->view.x * pdev->view.y;
+
+			/* offset in Y plane */
+			stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+			dsty = (u16 *)(image + stride);
+
+			/* offsets in U/V planes */
+			stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+			dstu = (u16 *)(image + n +         stride);
+			dstv = (u16 *)(image + n + n / 4 + stride);
+
+			/* increment after each line */
+			stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+			for (line = 0; line < pdev->image.y; line++) {
+				for (col = 0; col < pdev->image.x; col += 4) {
+					*dsty++ = *src++;
+					*dsty++ = *src++;
+					if (line & 1)
+						*dstv++ = *src++;
+					else
+						*dstu++ = *src++;
+				}
+				dsty += stride;
+				if (line & 1)
+					dstv += (stride >> 1);
+				else
+					dstu += (stride >> 1);
+			}
+	}
+	else {
+		/* Compressed; the decompressor routines will write the data
+		   in planar format immediately.
+		 */
+		int flags;
+                
+                flags = PWCX_FLAG_PLANAR;
+                if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
+		 {
+		   printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
+		   flags |= PWCX_FLAG_BAYER;
+		   return -ENXIO; /* No such device or address: missing decompressor */
+		 }
+
+		switch (pdev->type)
+		 {
+#if 0		 
+		  case 675:
+		  case 680:
+		  case 690:
+		  case 720:
+		  case 730:
+		  case 740:
+		  case 750:
+		    pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset,
+				yuv, image,
+				flags,
+				pdev->decompress_data, pdev->vbandlength);
+		    break;
+		  case 645:
+		  case 646:
+		    /* TODO & FIXME */
+#endif		    
+		    return -ENXIO; /* No such device or address: missing decompressor */
+		    break;
+		 }
+	}
+	return 0;
+}
+
+
diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc-uncompress.h
@@ -0,0 +1,41 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This file is the bridge between the kernel module and the plugin; it
+   describes the structures and datatypes used in both modules. Any
+   significant change should be reflected by increasing the 
+   pwc_decompressor_version major number.
+ */
+#ifndef PWC_UNCOMPRESS_H
+#define PWC_UNCOMPRESS_H
+
+#include <linux/config.h>
+
+#include "pwc-ioctl.h"
+
+/* from pwc-dec.h */
+#define PWCX_FLAG_PLANAR        0x0001
+/* */
+
+#endif
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/media/pwc/pwc.h
@@ -0,0 +1,274 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it 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 PWC_H
+#define PWC_H
+
+#include <linux/version.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <linux/videodev.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+#include "pwc-uncompress.h"
+#include "pwc-ioctl.h"
+
+/* Defines and structures for the Philips webcam */
+/* Used for checking memory corruption/pointer validation */
+#define PWC_MAGIC 0x89DC10ABUL
+#undef PWC_MAGIC
+
+/* Turn some debugging options on/off */
+#define PWC_DEBUG 0
+
+/* Trace certain actions in the driver */
+#define TRACE_MODULE	0x0001
+#define TRACE_PROBE	0x0002
+#define TRACE_OPEN	0x0004
+#define TRACE_READ	0x0008
+#define TRACE_MEMORY	0x0010
+#define TRACE_FLOW	0x0020
+#define TRACE_SIZE	0x0040
+#define TRACE_PWCX	0x0080
+#define TRACE_SEQUENCE	0x1000
+
+#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
+#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
+#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
+#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
+
+
+/* Defines for ToUCam cameras */
+#define TOUCAM_HEADER_SIZE		8
+#define TOUCAM_TRAILER_SIZE		4
+
+#define FEATURE_MOTOR_PANTILT		0x0001
+
+/* Version block */
+#define PWC_MAJOR	9
+#define PWC_MINOR	0
+#define PWC_VERSION 	"9.0.2-unofficial"
+#define PWC_NAME 	"pwc"
+
+/* Turn certain features on/off */
+#define PWC_INT_PIPE 0
+
+/* Ignore errors in the first N frames, to allow for startup delays */
+#define FRAME_LOWMARK 5
+
+/* Size and number of buffers for the ISO pipe. */
+#define MAX_ISO_BUFS		2
+#define ISO_FRAMES_PER_DESC	10
+#define ISO_MAX_FRAME_SIZE	960
+#define ISO_BUFFER_SIZE 	(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+/* Frame buffers: contains compressed or uncompressed video data. */
+#define MAX_FRAMES		5
+/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
+#define PWC_FRAME_SIZE 		(460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
+
+/* Absolute maximum number of buffers available for mmap() */
+#define MAX_IMAGES 		10
+
+/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
+struct pwc_iso_buf
+{
+	void *data;
+	int  length;
+	int  read;
+	struct urb *urb;
+};
+
+/* intermediate buffers with raw data from the USB cam */
+struct pwc_frame_buf
+{
+   void *data;
+   volatile int filled;		/* number of bytes filled */
+   struct pwc_frame_buf *next;	/* list */
+#if PWC_DEBUG
+   int sequence;		/* Sequence number */
+#endif
+};
+
+struct pwc_device
+{
+   struct video_device *vdev;
+#ifdef PWC_MAGIC
+   int magic;
+#endif
+   /* Pointer to our usb_device */
+   struct usb_device *udev;
+   
+   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
+   int release;			/* release number */
+   int features;		/* feature bits */
+   char serial[30];		/* serial number (string) */
+   int error_status;		/* set when something goes wrong with the cam (unplugged, USB errors) */
+   int usb_init;		/* set when the cam has been initialized over USB */
+
+   /*** Video data ***/
+   int vopen;			/* flag */
+   int vendpoint;		/* video isoc endpoint */
+   int vcinterface;		/* video control interface */
+   int valternate;		/* alternate interface needed */
+   int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
+   int vpalette;		/* palette: 420P, RAW or RGBBAYER */
+   int vframe_count;		/* received frames */
+   int vframes_dumped; 		/* counter for dumped frames */
+   int vframes_error;		/* frames received in error */
+   int vmax_packet_size;	/* USB maxpacket size */
+   int vlast_packet_size;	/* for frame synchronisation */
+   int visoc_errors;		/* number of contiguous ISOC errors */
+   int vcompression;		/* desired compression factor */
+   int vbandlength;		/* compressed band length; 0 is uncompressed */
+   char vsnapshot;		/* snapshot mode */
+   char vsync;			/* used by isoc handler */
+   char vmirror;		/* for ToUCaM series */
+   
+   int cmd_len;
+   unsigned char cmd_buf[13];
+
+   /* The image acquisition requires 3 to 4 steps:
+      1. data is gathered in short packets from the USB controller
+      2. data is synchronized and packed into a frame buffer
+      3a. in case data is compressed, decompress it directly into image buffer
+      3b. in case data is uncompressed, copy into image buffer with viewport
+      4. data is transferred to the user process
+
+      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
+      We have in effect a back-to-back-double-buffer system.
+    */
+   /* 1: isoc */
+   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
+   char iso_init;
+
+   /* 2: frame */
+   struct pwc_frame_buf *fbuf;	/* all frames */
+   struct pwc_frame_buf *empty_frames, *empty_frames_tail;	/* all empty frames */
+   struct pwc_frame_buf *full_frames, *full_frames_tail;	/* all filled frames */
+   struct pwc_frame_buf *fill_frame;	/* frame currently being filled */
+   struct pwc_frame_buf *read_frame;	/* frame currently read by user process */
+   int frame_header_size, frame_trailer_size;
+   int frame_size;
+   int frame_total_size; /* including header & trailer */
+   int drop_frames;
+#if PWC_DEBUG
+   int sequence;			/* Debugging aid */
+#endif
+
+   /* 3: decompression */
+   struct pwc_decompressor *decompressor;	/* function block with decompression routines */
+   void *decompress_data;		/* private data for decompression engine */
+
+   /* 4: image */
+   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
+      as delivered by the camera, and 'view' is the size requested by the
+      program. The camera image is centered in this viewport, laced with
+      a gray or black border. view_min <= image <= view <= view_max;
+    */
+   int image_mask;			/* bitmask of supported sizes */
+   struct pwc_coord view_min, view_max;	/* minimum and maximum viewable sizes */
+   struct pwc_coord abs_max;            /* maximum supported size with compression */
+   struct pwc_coord image, view;	/* image and viewport size */
+   struct pwc_coord offset;		/* offset within the viewport */
+
+   void *image_data;			/* total buffer, which is subdivided into ... */
+   void *image_ptr[MAX_IMAGES];		/* ...several images... */
+   int fill_image;			/* ...which are rotated. */
+   int len_per_image;			/* length per image */
+   int image_read_pos;			/* In case we read data in pieces, keep track of were we are in the imagebuffer */
+   int image_used[MAX_IMAGES];		/* For MCAPTURE and SYNC */
+
+   struct semaphore modlock;		/* to prevent races in video_open(), etc */
+   spinlock_t ptrlock;			/* for manipulating the buffer pointers */
+
+   /*** motorized pan/tilt feature */
+   struct pwc_mpt_range angle_range;
+   int pan_angle;			/* in degrees * 100 */
+   int tilt_angle;			/* absolute angle; 0,0 is home position */
+
+   /*** Misc. data ***/
+   wait_queue_head_t frameq;		/* When waiting for a frame to finish... */
+#if PWC_INT_PIPE
+   void *usb_int_handler;		/* for the interrupt endpoint */
+#endif
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global variable */
+extern int pwc_trace;
+
+/** functions in pwc-if.c */
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+
+/** Functions in pwc-misc.c */
+/* sizes in pixels */
+extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+
+int pwc_decode_size(struct pwc_device *pdev, int width, int height);
+void pwc_construct(struct pwc_device *pdev);
+
+/** Functions in pwc-ctrl.c */
+/* Request a certain video mode. Returns < 0 if not possible */
+extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+
+/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
+extern int pwc_get_brightness(struct pwc_device *pdev);
+extern int pwc_set_brightness(struct pwc_device *pdev, int value);
+extern int pwc_get_contrast(struct pwc_device *pdev);
+extern int pwc_set_contrast(struct pwc_device *pdev, int value);
+extern int pwc_get_gamma(struct pwc_device *pdev);
+extern int pwc_set_gamma(struct pwc_device *pdev, int value);
+extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_set_saturation(struct pwc_device *pdev, int value);
+extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
+extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+
+/* Power down or up the camera; not supported by all models */
+extern int pwc_camera_power(struct pwc_device *pdev, int power);
+
+/* Private ioctl()s; see pwc-ioctl.h */
+extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+
+
+/** pwc-uncompress.c */
+/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
+extern int pwc_decompress(struct pwc_device *pdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -122,7 +122,7 @@ static int se401_sndctrl(int set, struct
                 0,
                 cp,
                 size,
-                HZ
+                1000
         );
 }
 
@@ -142,7 +142,7 @@ static int se401_set_feature(struct usb_
 		selector,
                 NULL,
                 0,
-                HZ
+                1000
         );
 }
 
@@ -162,7 +162,7 @@ static unsigned short se401_get_feature(
                 selector,
                 cp,
                 2,
-                HZ
+                1000
         );
 	return cp[0]+cp[1]*256;
 }
@@ -868,13 +868,14 @@ static void usb_se401_remove_disconnecte
 
         se401->dev = NULL;
 
-	for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-		usb_kill_urb(se401->urb[i]);
-		usb_free_urb(se401->urb[i]);
-		se401->urb[i] = NULL;
-		kfree(se401->sbuf[i].data);
-	}
-	for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
+	for (i=0; i<SE401_NUMSBUF; i++)
+		if (se401->urb[i]) {
+			usb_kill_urb(se401->urb[i]);
+			usb_free_urb(se401->urb[i]);
+			se401->urb[i] = NULL;
+			kfree(se401->sbuf[i].data);
+		}
+	for (i=0; i<SE401_NUMSCRATCH; i++) {
 		kfree(se401->scratch[i].data);
 	}
 	if (se401->inturb) {
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -48,16 +48,16 @@
 #define SN9C102_ISO_PACKETS       7
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT      msecs_to_jiffies(300)
+#define SN9C102_CTRL_TIMEOUT      300
 
 /*****************************************************************************/
 
 #define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004 Luca Risolia"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2005 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.22"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 22)
+#define SN9C102_MODULE_VERSION  "1:1.24"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 24)
 
 enum sn9c102_bridge {
 	BRIDGE_SN9C101 = 0x01,
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -164,8 +164,8 @@ sn9c102_request_buffers(struct sn9c102_d
 	struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
 	const size_t imagesize = cam->module_param.force_munmap ||
 	                         io == IO_READ ?
-	                         (p->width * p->height * p->priv)/8 :
-	                         (r->width * r->height * p->priv)/8;
+	                         (p->width * p->height * p->priv) / 8 :
+	                         (r->width * r->height * p->priv) / 8;
 	void* buff = NULL;
 	u32 i;
 
@@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_devi
 }
 
 
-int 
+static int 
 sn9c102_i2c_try_write(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor, u8 address, u8 value)
 {
@@ -499,6 +499,7 @@ static void sn9c102_urb_complete(struct 
 {
 	struct sn9c102_device* cam = urb->context;
 	struct sn9c102_frame_t** f;
+	size_t imagesize;
 	unsigned long lock_flags;
 	u8 i;
 	int err = 0;
@@ -516,9 +517,14 @@ static void sn9c102_urb_complete(struct 
 		wake_up_interruptible(&cam->wait_stream);
 	}
 
-	if ((cam->state & DEV_DISCONNECTED)||(cam->state & DEV_MISCONFIGURED))
+	if (cam->state & DEV_DISCONNECTED)
 		return;
 
+	if (cam->state & DEV_MISCONFIGURED) {
+		wake_up_interruptible(&cam->wait_frame);
+		return;
+	}
+
 	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
 		goto resubmit_urb;
 
@@ -526,6 +532,10 @@ static void sn9c102_urb_complete(struct 
 		(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
 		                  frame);
 
+	imagesize = (cam->sensor->pix_format.width *
+	             cam->sensor->pix_format.height *
+	             cam->sensor->pix_format.priv) / 8;
+
 	for (i = 0; i < urb->number_of_packets; i++) {
 		unsigned int img, len, status;
 		void *pos, *sof, *eof;
@@ -560,11 +570,10 @@ end_of_frame:
 				if (eof)
 					img = (eof > pos) ? eof - pos - 1 : 0;
 
-				if ((*f)->buf.bytesused+img>(*f)->buf.length) {
+				if ((*f)->buf.bytesused+img > imagesize) {
 					u32 b = (*f)->buf.bytesused + img -
-					        (*f)->buf.length;
-					img = (*f)->buf.length - 
-					      (*f)->buf.bytesused;
+					        imagesize;
+					img = imagesize - (*f)->buf.bytesused;
 					DBG(3, "Expected EOF not found: "
 					       "video frame cut")
 					if (eof)
@@ -580,7 +589,7 @@ end_of_frame:
 
 				(*f)->buf.bytesused += img;
 
-				if ((*f)->buf.bytesused == (*f)->buf.length ||
+				if ((*f)->buf.bytesused == imagesize ||
 				    (cam->sensor->pix_format.pixelformat ==
 				                V4L2_PIX_FMT_SN9C10X && eof)) {
 					u32 b = (*f)->buf.bytesused;
@@ -776,7 +785,7 @@ static int sn9c102_stop_transfer(struct 
 }
 
 
-int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 {
 	int err = 0;
 
@@ -1558,7 +1567,8 @@ sn9c102_read(struct file* filp, char __u
 		err = wait_event_interruptible
 		      ( cam->wait_frame, 
 		        (!list_empty(&cam->outqueue)) ||
-		        (cam->state & DEV_DISCONNECTED) );
+		        (cam->state & DEV_DISCONNECTED) ||
+			(cam->state & DEV_MISCONFIGURED) );
 		if (err) {
 			up(&cam->fileop_sem);
 			return err;
@@ -1567,6 +1577,10 @@ sn9c102_read(struct file* filp, char __u
 			up(&cam->fileop_sem);
 			return -ENODEV;
 		}
+		if (cam->state & DEV_MISCONFIGURED) {
+			up(&cam->fileop_sem);
+			return -EIO;
+		}
 	}
 
 	f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
@@ -1615,7 +1629,8 @@ static unsigned int sn9c102_poll(struct 
 	}
 
 	if (cam->io == IO_NONE) {
-		if (!sn9c102_request_buffers(cam, 2, IO_READ)) {
+		if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
+		                             IO_READ)) {
 			DBG(1, "poll() failed, not enough memory")
 			goto error;
 		}
@@ -1729,7 +1744,7 @@ static int sn9c102_mmap(struct file* fil
 }
 
 
-static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
                               unsigned int cmd, void __user * arg)
 {
 	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
@@ -1970,7 +1985,7 @@ static int sn9c102_v4l2_ioctl(struct ino
 			return -EFAULT;
 		}
 
-		if (cam->module_param.force_munmap)
+		if (cam->module_param.force_munmap || cam->io == IO_READ)
 			sn9c102_release_buffers(cam);
 
 		err = sn9c102_set_crop(cam, rect);
@@ -1990,7 +2005,7 @@ static int sn9c102_v4l2_ioctl(struct ino
 		s->pix_format.height = rect->height/scale;
 		memcpy(&(s->_rect), rect, sizeof(*rect));
 
-		if (cam->module_param.force_munmap &&
+		if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
 		    nbuffers != sn9c102_request_buffers(cam, nbuffers,
 		                                        cam->io)) {
 			cam->state |= DEV_MISCONFIGURED;
@@ -2146,7 +2161,7 @@ static int sn9c102_v4l2_ioctl(struct ino
 			return -EFAULT;
 		}
 
-		if (cam->module_param.force_munmap)
+		if (cam->module_param.force_munmap  || cam->io == IO_READ)
 			sn9c102_release_buffers(cam);
 
 		err += sn9c102_set_pix_format(cam, pix);
@@ -2168,7 +2183,7 @@ static int sn9c102_v4l2_ioctl(struct ino
 		memcpy(pfmt, pix, sizeof(*pix));
 		memcpy(&(s->_rect), &rect, sizeof(rect));
 
-		if (cam->module_param.force_munmap &&
+		if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
 		    nbuffers != sn9c102_request_buffers(cam, nbuffers,
 		                                        cam->io)) {
 			cam->state |= DEV_MISCONFIGURED;
@@ -2346,11 +2361,14 @@ static int sn9c102_v4l2_ioctl(struct ino
 			err = wait_event_interruptible
 			      ( cam->wait_frame, 
 			        (!list_empty(&cam->outqueue)) ||
-			        (cam->state & DEV_DISCONNECTED) );
+			        (cam->state & DEV_DISCONNECTED) ||
+			        (cam->state & DEV_MISCONFIGURED) );
 			if (err)
 				return err;
 			if (cam->state & DEV_DISCONNECTED)
 				return -ENODEV;
+			if (cam->state & DEV_MISCONFIGURED)
+				return -EIO;
 		}
 
 		spin_lock_irqsave(&cam->queue_lock, lock_flags);
@@ -2495,7 +2513,7 @@ static int sn9c102_ioctl(struct inode* i
 		return -EIO;
 	}
 
-	err = sn9c102_v4l2_ioctl(inode, filp, cmd, (void __user *)arg);
+	err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
 	up(&cam->fileop_sem);
 
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -145,8 +145,6 @@ static const struct usb_device_id sn9c10
 */
 
 /* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
-                                 u8 address, u8 value);
 extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
                                 u8 address);
 
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
--- a/drivers/usb/media/ultracam.c
+++ b/drivers/usb/media/ultracam.c
@@ -155,7 +155,7 @@ static int ultracam_veio(
 			index,
 			cp,
 			sizeof(cp),
-			HZ);
+			1000);
 #if 1
 		info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
 		       "(req=$%02x val=$%04x ind=$%04x)",
@@ -172,7 +172,7 @@ static int ultracam_veio(
 			index,
 			NULL,
 			0,
-			HZ);
+			1000);
 	}
 	if (i < 0) {
 		err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -1169,10 +1169,8 @@ static int usbvideo_v4l_open(struct inod
 			}
 			RingQueue_Free(&uvd->dp);
 			for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-				if (uvd->sbuf[i].data != NULL) {
-					kfree (uvd->sbuf[i].data);
-					uvd->sbuf[i].data = NULL;
-				}
+				kfree(uvd->sbuf[i].data);
+				uvd->sbuf[i].data = NULL;
 			}
 		}
 	}
@@ -1814,12 +1812,12 @@ static void usbvideo_StopDataPump(struct
 {
 	int i, j;
 
-	if (uvd->debug > 1)
-		info("%s($%p)", __FUNCTION__, uvd);
-
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
 
+	if (uvd->debug > 1)
+		info("%s($%p)", __FUNCTION__, uvd);
+
 	/* Unschedule all of the iso td's */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		usb_kill_urb(uvd->sbuf[i].urb);
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -441,7 +441,7 @@ static int __send_control_msg(struct vic
 				 request,
 				 USB_DIR_OUT | USB_TYPE_VENDOR |
 				 USB_RECIP_DEVICE, value, index,
-				 cp, size, HZ);
+				 cp, size, 1000);
 
 	status = min(status, 0);
 
@@ -977,7 +977,7 @@ read_frame(struct vicam_camera *cam, int
 	n = usb_bulk_msg(cam->udev,
 			 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
 			 cam->raw_image,
-			 512 * 242 + 128, &actual_length, HZ*10);
+			 512 * 242 + 128, &actual_length, 10000);
 
 	if (n < 0) {
 		printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -3624,10 +3624,8 @@ w9968cf_usb_probe(struct usb_interface* 
 	return 0;
 
 fail: /* Free unused memory */
-	if (cam->control_buffer)
-		kfree(cam->control_buffer);
-	if (cam->data_buffer)
-		kfree(cam->data_buffer);
+	kfree(cam->control_buffer);
+	kfree(cam->data_buffer);
 	if (cam->v4ldev)
 		video_device_release(cam->v4ldev);
 	up(&cam->dev_sem);
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h
--- a/drivers/usb/media/w9968cf.h
+++ b/drivers/usb/media/w9968cf.h
@@ -65,7 +65,7 @@ static const u16 wMaxPacketSize[] = {102
 #define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
 #define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
 #define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT HZ /* timeout for usb control commands */
+#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
 #define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
 
 #define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -137,6 +137,8 @@ config USB_IDMOUSE
 
 	  See also <http://www.fs.tum.de/~echtler/idmouse/>.
 
+source "drivers/usb/misc/sisusbvga/Kconfig"
+
 config USB_TEST
 	tristate "USB testing driver (DEVELOPMENT)"
 	depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_USB_PHIDGETSERVO)	+= phidge
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
 obj-$(CONFIG_USB_TEST)		+= usbtest.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
+
+obj-$(CONFIG_USB_SISUSBVGA)	+= sisusbvga/
\ No newline at end of file
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/wait.h>
 #undef DEBUG   		/* include debug macros until it's done	*/
 #include <linux/usb.h>
 
@@ -605,7 +606,6 @@ static void auerchain_blocking_completio
 /* Starts chained urb and waits for completion or timeout */
 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;
 	int status;
 
@@ -613,26 +613,13 @@ static int auerchain_start_wait_urb (pau
 	init_waitqueue_head (&chs.wqh);
 	chs.done = 0;
 
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	add_wait_queue (&chs.wqh, &wait);
 	urb->context = &chs;
 	status = auerchain_submit_urb (acp, urb);
-	if (status) {
+	if (status)
 		/* something went wrong */
-		set_current_state (TASK_RUNNING);
-		remove_wait_queue (&chs.wqh, &wait);
 		return status;
-	}
-
-	while (timeout && !chs.done)
-	{
-		timeout = schedule_timeout (timeout);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		rmb();
-	}
 
-	set_current_state (TASK_RUNNING);
-	remove_wait_queue (&chs.wqh, &wait);
+	timeout = wait_event_timeout(chs.wqh, chs.done, timeout);
 
 	if (!timeout && !chs.done) {
 		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
@@ -718,16 +705,12 @@ static int auerchain_control_msg (pauerc
 /* free a single auerbuf */
 static void auerbuf_free (pauerbuf_t bp)
 {
-	if (bp->bufp) {
-		kfree (bp->bufp);
-	}
-	if (bp->dr) {
-		kfree (bp->dr);
-	}
+	kfree(bp->bufp);
+	kfree(bp->dr);
 	if (bp->urbp) {
-		usb_free_urb (bp->urbp);
+		usb_free_urb(bp->urbp);
 	}
-	kfree (bp);
+	kfree(bp);
 }
 
 /* free the buffers from an auerbuf list */
@@ -1106,14 +1089,12 @@ exit:
 */
 static void auerswald_int_free (pauerswald_t cp)
 {
-        if (cp->inturbp) {
-                usb_free_urb (cp->inturbp);
-                cp->inturbp = NULL;
-        }
-        if (cp->intbufp) {
-                kfree (cp->intbufp);
-                cp->intbufp = NULL;
-        }
+	if (cp->inturbp) {
+		usb_free_urb(cp->inturbp);
+		cp->inturbp = NULL;
+	}
+	kfree(cp->intbufp);
+	cp->intbufp = NULL;
 }
 
 /* This function is called to activate the interrupt
@@ -2009,7 +1990,7 @@ static int auerswald_probe (struct usb_i
                 AUDI_MBCTRANS,                      /* USB message index value */
                 pbuf,                               /* pointer to the receive buffer */
                 2,                                  /* length of the buffer */
-                HZ * 2);                            /* time to wait for the message to complete before timing out */
+                2000);                            /* time to wait for the message to complete before timing out */
         if (ret == 2) {
 	        cp->maxControlLength = le16_to_cpup(pbuf);
                 kfree(pbuf);
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -77,7 +77,7 @@ static int vendor_command(struct usb_dev
 			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
 			       value, 
 			       index, buf, size,
-			       HZ * USB_CTRL_GET_TIMEOUT);
+			       USB_CTRL_GET_TIMEOUT);
 }
 
 
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -30,6 +30,7 @@ typedef struct _INTEL_HEX_RECORD
 
 #define EMI26_VENDOR_ID 		0x086a  /* Emagic Soft-und Hardware GmBH */
 #define EMI26_PRODUCT_ID		0x0100	/* EMI 2|6 without firmware */
+#define EMI26B_PRODUCT_ID		0x0102	/* EMI 2|6 without firmware */
 
 #define ANCHOR_LOAD_INTERNAL	0xA0	/* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */
 #define ANCHOR_LOAD_EXTERNAL	0xA3	/* This command is not implemented in the core. Requires firmware */
@@ -203,6 +204,7 @@ wraperr:
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) },
+	{ USB_DEVICE(EMI26_VENDOR_ID, EMI26B_PRODUCT_ID) },
 	{ }                                             /* Terminating entry */
 };
 
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -124,28 +124,28 @@ static int idmouse_create_image(struct u
 	   means init..
 	*/
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+				0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+				0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+				0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+				0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+				0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+				0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 
@@ -154,7 +154,7 @@ static int idmouse_create_image(struct u
 		result = usb_bulk_msg (dev->udev,
 				usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
 				dev->bulk_in_buffer + bytes_read,
-				dev->bulk_in_size, &bulk_read, HZ * 5);
+				dev->bulk_in_size, &bulk_read, 5000);
 		if (result < 0)
 			return result;
 		if (signal_pending(current))
@@ -164,7 +164,7 @@ static int idmouse_create_image(struct u
 
 	/* reset the device */
 	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+				0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
 	if (result < 0)
 		return result;
 
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -391,7 +391,7 @@ static int tower_open (struct inode *ino
 				  0,
 				  &reset_reply,
 				  sizeof(reset_reply),
-				  HZ);
+				  1000);
 	if (result < 0) {
 		err("LEGO USB Tower reset control request failed");
 		retval = result;
@@ -859,7 +859,7 @@ static int tower_probe (struct usb_inter
 		info ("udev is NULL.");
 	}
 
-	/* allocate memory for our device state and intialize it */
+	/* allocate memory for our device state and initialize it */
 
 	dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
 
@@ -972,7 +972,7 @@ static int tower_probe (struct usb_inter
 				  0,
 				  &get_version_reply,
 				  sizeof(get_version_reply),
-				  HZ);
+				  1000);
 	if (result < 0) {
 		err("LEGO USB Tower get version control request failed");
 		retval = result;
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -103,14 +103,15 @@ static int change_outputs(struct phidget
 		}
 	}
 
-	dev_dbg(&kit->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
+	dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]);
 
 	retval = usb_control_msg(kit->udev,
 			 usb_sndctrlpipe(kit->udev, 0),
-			 0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2 * HZ);
+			 0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2000);
 
 	if (retval != 4)
-		dev_err(&kit->udev->dev, "retval = %d\n", retval);
+		dev_err(&kit->udev->dev, "usb_control_msg returned %d\n", 
+				retval);
 	kfree(buffer);
 
 	return retval < 0 ? retval : 0;
@@ -158,7 +159,7 @@ static int change_string(struct phidget_
 
 		retval = usb_control_msg(kit->udev,
 				 usb_sndctrlpipe(kit->udev, 0),
-				 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+				 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
 		if (retval < 0)
 			goto exit;
 	}
@@ -210,7 +211,7 @@ static ssize_t set_backlight(struct devi
 	
 	retval = usb_control_msg(kit->udev,
 			 usb_sndctrlpipe(kit->udev, 0),
-			 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+			 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
 	if (retval < 0)
 		goto exit;
 
@@ -328,7 +329,7 @@ static ssize_t show_output##value(struct
 	struct usb_interface *intf = to_usb_interface(dev);		\
 	struct phidget_interfacekit *kit = usb_get_intfdata(intf);	\
 									\
-	return sprintf(buf, "%d\n", kit->outputs[value - 1 ]);		\
+	return sprintf(buf, "%d\n", kit->outputs[value - 1]);		\
 }									\
 static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO,			\
 		show_output##value, set_output##value);
@@ -440,11 +441,13 @@ static int interfacekit_probe(struct usb
 		return -EIO;
 	}
 
-	if (ifkit->outputs == 8) {
+	if (ifkit->outputs >= 4) {
 		device_create_file(&intf->dev, &dev_attr_output1);
 		device_create_file(&intf->dev, &dev_attr_output2);
 		device_create_file(&intf->dev, &dev_attr_output3);
 		device_create_file(&intf->dev, &dev_attr_output4);
+	}
+	if (ifkit->outputs == 8) {
 		device_create_file(&intf->dev, &dev_attr_output5);
 		device_create_file(&intf->dev, &dev_attr_output6);
 		device_create_file(&intf->dev, &dev_attr_output7);
@@ -483,7 +486,7 @@ static int interfacekit_probe(struct usb
 		device_create_file(&intf->dev, &dev_attr_lcd);
 
 	dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
-			ifkit->inputs, ifkit->outputs, ifkit->sensors);
+			ifkit->sensors, ifkit->inputs, ifkit->outputs);
 
 	return 0;
 }
@@ -497,15 +500,17 @@ static void interfacekit_disconnect(stru
 	if (!kit)
 		return;
 
-	if (kit->ifkit->outputs == MAX_INTERFACES) {
+	if (kit->ifkit->outputs >= 4) {
 		device_remove_file(&interface->dev, &dev_attr_output1);
 		device_remove_file(&interface->dev, &dev_attr_output2);
 		device_remove_file(&interface->dev, &dev_attr_output3);
 		device_remove_file(&interface->dev, &dev_attr_output4);
+	}
+	if (kit->ifkit->outputs == 8) {
 		device_remove_file(&interface->dev, &dev_attr_output5);
 		device_remove_file(&interface->dev, &dev_attr_output6);
 		device_remove_file(&interface->dev, &dev_attr_output7);
-		device_remove_file(&interface->dev, &dev_attr_output7);
+		device_remove_file(&interface->dev, &dev_attr_output8);
 	}
 
 	if (kit->ifkit->inputs >= 4) {
@@ -536,10 +541,10 @@ static void interfacekit_disconnect(stru
 		device_remove_file(&interface->dev, &dev_attr_sensor8);
 	}
 	if (kit->ifkit->has_lcd)
-		device_create_file(&interface->dev, &dev_attr_lcd);
+		device_remove_file(&interface->dev, &dev_attr_lcd);
 
 	dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
-		kit->ifkit->inputs, kit->ifkit->outputs, kit->ifkit->sensors);
+		kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
 
 	usb_kill_urb(kit->irq);
 	usb_free_urb(kit->irq);
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -148,7 +148,7 @@ change_position_v30(struct phidget_servo
 
 	retval = usb_control_msg(servo->udev,
 				 usb_sndctrlpipe(servo->udev, 0),
-				 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2 * HZ);
+				 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2000);
 
 	kfree(buffer);
 
@@ -199,7 +199,7 @@ change_position_v20(struct phidget_servo
 
 	retval = usb_control_msg(servo->udev,
 				 usb_sndctrlpipe(servo->udev, 0),
-				 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2 * HZ);
+				 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2000);
 
 	kfree(buffer);
 
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -40,6 +40,7 @@
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/wait.h>
 
 #include "rio500_usb.h"
 
@@ -166,7 +167,7 @@ ioctl_rio(struct inode *inode, struct fi
 						 rio_cmd.value,
 						 rio_cmd.index, buffer,
 						 rio_cmd.length,
-						 rio_cmd.timeout);
+						 jiffies_to_msecs(rio_cmd.timeout));
 			if (result == -ETIMEDOUT)
 				retries--;
 			else if (result < 0) {
@@ -233,7 +234,7 @@ ioctl_rio(struct inode *inode, struct fi
 						 rio_cmd.value,
 						 rio_cmd.index, buffer,
 						 rio_cmd.length,
-						 rio_cmd.timeout);
+						 jiffies_to_msecs(rio_cmd.timeout));
 			if (result == -ETIMEDOUT)
 				retries--;
 			else if (result < 0) {
@@ -264,6 +265,7 @@ static ssize_t
 write_rio(struct file *file, const char __user *buffer,
 	  size_t count, loff_t * ppos)
 {
+	DEFINE_WAIT(wait);
 	struct rio_usb_data *rio = &rio_instance;
 
 	unsigned long copy_size;
@@ -309,7 +311,7 @@ write_rio(struct file *file, const char 
 
 			result = usb_bulk_msg(rio->rio_dev,
 					 usb_sndbulkpipe(rio->rio_dev, 2),
-					 obuf, thistime, &partial, 5 * HZ);
+					 obuf, thistime, &partial, 5000);
 
 			dbg("write stats: result:%d thistime:%lu partial:%u",
 			     result, thistime, partial);
@@ -319,7 +321,9 @@ write_rio(struct file *file, const char 
 					errn = -ETIME;
 					goto error;
 				}
-				interruptible_sleep_on_timeout(&rio-> wait_q, NAK_TIMEOUT);
+				prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
+				schedule_timeout(NAK_TIMEOUT);
+				finish_wait(&rio->wait_q, &wait);
 				continue;
 			} else if (!result && partial) {
 				obuf += partial;
@@ -349,6 +353,7 @@ error:
 static ssize_t
 read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 {
+	DEFINE_WAIT(wait);
 	struct rio_usb_data *rio = &rio_instance;
 	ssize_t read_count;
 	unsigned int partial;
@@ -386,7 +391,7 @@ read_rio(struct file *file, char __user 
 		result = usb_bulk_msg(rio->rio_dev,
 				      usb_rcvbulkpipe(rio->rio_dev, 1),
 				      ibuf, this_read, &partial,
-				      (int) (HZ * 8));
+				      8000);
 
 		dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
 		       result, this_read, partial);
@@ -399,8 +404,9 @@ read_rio(struct file *file, char __user 
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 			}
-			interruptible_sleep_on_timeout(&rio->wait_q,
-						       NAK_TIMEOUT);
+			prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
+			schedule_timeout(NAK_TIMEOUT);
+			finish_wait(&rio->wait_q, &wait);
 			continue;
 		} else if (result != -EREMOTEIO) {
 			up(&(rio->lock));
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -0,0 +1,14 @@
+
+config USB_SISUSBVGA
+	tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
+	depends on USB && USB_EHCI_HCD
+        ---help---
+	  Say Y here if you intend to attach a USB2VGA dongle based on a
+	  Net2280 and a SiS315 chip. 
+	  
+	  Note that this device requires a USB 2.0 host controller. It will not 
+	  work with USB 1.x controllers.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called sisusb.  If unsure, say N.
+
diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the sisusb driver (if driver is inside kernel tree).
+#
+
+obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -0,0 +1,3147 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * 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.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific psisusbr written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+#include "sisusb.h"
+
+#define SISUSB_DONTSYNC
+
+/* Forward declarations / clean-up routines */
+
+static struct usb_driver sisusb_driver;
+
+static DECLARE_MUTEX(disconnect_sem);
+
+static void
+sisusb_free_buffers(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < NUMOBUFS; i++) {
+		if (sisusb->obuf[i]) {
+			usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
+				sisusb->obuf[i], sisusb->transfer_dma_out[i]);
+			sisusb->obuf[i] = NULL;
+		}
+	}
+	if (sisusb->ibuf) {
+		usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
+			sisusb->ibuf, sisusb->transfer_dma_in);
+		sisusb->ibuf = NULL;
+	}
+}
+
+static void
+sisusb_free_urbs(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < NUMOBUFS; i++) {
+		usb_free_urb(sisusb->sisurbout[i]);
+		sisusb->sisurbout[i] = NULL;
+	}
+	usb_free_urb(sisusb->sisurbin);
+	sisusb->sisurbin = NULL;
+}
+
+/* Level 0: USB transport layer */
+
+/* 1. out-bulks */
+
+/* out-urb management */
+
+/* Return 1 if all free, 0 otherwise */
+static int
+sisusb_all_free(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if (sisusb->urbstatus[i] & SU_URB_BUSY)
+			return 0;
+
+	}
+
+	return 1;
+}
+
+/* Kill all busy URBs */
+static void
+sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	if (sisusb_all_free(sisusb))
+		return;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if (sisusb->urbstatus[i] & SU_URB_BUSY)
+			usb_kill_urb(sisusb->sisurbout[i]);
+
+	}
+}
+
+/* Return 1 if ok, 0 if error (not all complete within timeout) */
+static int
+sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
+{
+	int timeout = 5 * HZ, i = 1;
+
+	wait_event_timeout(sisusb->wait_q,
+				(i = sisusb_all_free(sisusb)),
+				 timeout);
+
+	return i;
+}
+
+static int
+sisusb_outurb_available(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
+			return i;
+
+	}
+
+	return -1;
+}
+
+static int
+sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
+{
+	int i, timeout = 5 * HZ;
+
+	wait_event_timeout(sisusb->wait_q,
+				((i = sisusb_outurb_available(sisusb)) >= 0),
+				timeout);
+
+	return i;
+}
+
+static int
+sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	i = sisusb_outurb_available(sisusb);
+
+	if (i >= 0)
+		sisusb->urbstatus[i] |= SU_URB_ALLOC;
+
+	return i;
+}
+
+static void
+sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
+{
+	if ((index >= 0) && (index < sisusb->numobufs))
+		sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
+}
+
+/* completion callback */
+
+static void
+sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
+{
+	struct sisusb_urb_context *context = urb->context;
+	struct sisusb_usb_data *sisusb;
+
+	if (!context)
+		return;
+
+	sisusb = context->sisusb;
+
+	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+		return;
+
+#ifndef SISUSB_DONTSYNC
+	if (context->actual_length)
+		*(context->actual_length) += urb->actual_length;
+#endif
+
+	sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
+	wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
+		int len, int *actual_length, int timeout, unsigned int tflags,
+		dma_addr_t transfer_dma)
+{
+	struct urb *urb = sisusb->sisurbout[index];
+	int retval, byteswritten = 0;
+
+	/* Set up URB */
+	urb->transfer_flags = 0;
+
+	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+		sisusb_bulk_completeout, &sisusb->urbout_context[index]);
+
+	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->actual_length = 0;
+
+	if ((urb->transfer_dma = transfer_dma))
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* Set up context */
+	sisusb->urbout_context[index].actual_length = (timeout) ?
+						NULL : actual_length;
+
+	/* Declare this urb/buffer in use */
+	sisusb->urbstatus[index] |= SU_URB_BUSY;
+
+	/* Submit URB */
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+	/* If OK, and if timeout > 0, wait for completion */
+	if ((retval == 0) && timeout) {
+		wait_event_timeout(sisusb->wait_q,
+				   (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
+				   timeout);
+		if (sisusb->urbstatus[index] & SU_URB_BUSY) {
+			/* URB timed out... kill it and report error */
+			usb_kill_urb(urb);
+			retval = -ETIMEDOUT;
+		} else {
+			/* Otherwise, report urb status */
+			retval = urb->status;
+			byteswritten = urb->actual_length;
+		}
+	}
+
+	if (actual_length)
+		*actual_length = byteswritten;
+
+	return retval;
+}
+
+/* 2. in-bulks */
+
+/* completion callback */
+
+static void
+sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
+{
+	struct sisusb_usb_data *sisusb = urb->context;
+
+	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+		return;
+
+	sisusb->completein = 1;
+	wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
+		int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
+{
+	struct urb *urb = sisusb->sisurbin;
+	int retval, readbytes = 0;
+
+	urb->transfer_flags = 0;
+
+	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+			sisusb_bulk_completein, sisusb);
+
+	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->actual_length = 0;
+
+	if ((urb->transfer_dma = transfer_dma))
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	sisusb->completein = 0;
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval == 0) {
+		wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
+		if (!sisusb->completein) {
+			/* URB timed out... kill it and report error */
+			usb_kill_urb(urb);
+			retval = -ETIMEDOUT;
+		} else {
+			/* URB completed within timout */
+			retval = urb->status;
+			readbytes = urb->actual_length;
+		}
+	}
+
+	if (actual_length)
+		*actual_length = readbytes;
+
+	return retval;
+}
+
+
+/* Level 1:  */
+
+/* Send a bulk message of variable size
+ *
+ * To copy the data from userspace, give pointer to "userbuffer",
+ * to copy from (non-DMA) kernel memory, give "kernbuffer". If
+ * both of these are NULL, it is assumed, that the transfer
+ * buffer "sisusb->obuf[index]" is set up with the data to send.
+ * Index is ignored if either kernbuffer or userbuffer is set.
+ * If async is nonzero, URBs will be sent without waiting for
+ * completion of the previous URB.
+ *
+ * (return 0 on success)
+ */
+
+static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+		char *kernbuffer, const char __user *userbuffer, int index,
+		ssize_t *bytes_written, unsigned int tflags, int async)
+{
+	int result = 0, retry, count = len;
+	int passsize, thispass, transferred_len = 0;
+	int fromuser = (userbuffer != NULL) ? 1 : 0;
+	int fromkern = (kernbuffer != NULL) ? 1 : 0;
+	unsigned int pipe;
+	char *buffer;
+
+	(*bytes_written) = 0;
+
+	/* Sanity check */
+	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+		return -ENODEV;
+
+	/* If we copy data from kernel or userspace, force the
+	 * allocation of a buffer/urb. If we have the data in
+	 * the transfer buffer[index] already, reuse the buffer/URB
+	 * if the length is > buffer size. (So, transmitting
+	 * large data amounts directly from the transfer buffer
+	 * treats the buffer as a ring buffer. However, we need
+	 * to sync in this case.)
+	 */
+	if (fromuser || fromkern)
+		index = -1;
+	else if (len > sisusb->obufsize)
+		async = 0;
+
+	pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
+
+	do {
+		passsize = thispass = (sisusb->obufsize < count) ?
+						sisusb->obufsize : count;
+
+		if (index < 0)
+			index = sisusb_get_free_outbuf(sisusb);
+
+		if (index < 0)
+			return -EIO;
+
+		buffer = sisusb->obuf[index];
+
+		if (fromuser) {
+
+			if (copy_from_user(buffer, userbuffer, passsize))
+				return -EFAULT;
+
+			userbuffer += passsize;
+
+		} else if (fromkern) {
+
+			memcpy(buffer, kernbuffer, passsize);
+			kernbuffer += passsize;
+
+		}
+
+		retry = 5;
+		while (thispass) {
+
+			if (!sisusb->sisusb_dev)
+				return -ENODEV;
+
+			result = sisusb_bulkout_msg(sisusb,
+						index,
+						pipe,
+						buffer,
+						thispass,
+						&transferred_len,
+						async ? 0 : 5 * HZ,
+						tflags,
+						sisusb->transfer_dma_out[index]);
+
+			if (result == -ETIMEDOUT) {
+
+				/* Will not happen if async */
+				if (!retry--)
+					return -ETIME;
+
+				continue;
+
+			} else if ((result == 0) && !async && transferred_len) {
+
+				thispass -= transferred_len;
+				if (thispass) {
+					if (sisusb->transfer_dma_out) {
+						/* If DMA, copy remaining
+						 * to beginning of buffer
+						 */
+						memcpy(buffer,
+						       buffer + transferred_len,
+						       thispass);
+					} else {
+						/* If not DMA, simply increase
+						 * the pointer
+						 */
+						buffer += transferred_len;
+					}
+				}
+
+			} else
+				break;
+		};
+
+		if (result)
+			return result;
+
+		(*bytes_written) += passsize;
+		count            -= passsize;
+
+		/* Force new allocation in next iteration */
+		if (fromuser || fromkern)
+			index = -1;
+
+	} while (count > 0);
+
+	if (async) {
+#ifdef SISUSB_DONTSYNC
+		(*bytes_written) = len;
+		/* Some URBs/buffers might be busy */
+#else
+		sisusb_wait_all_out_complete(sisusb);
+		(*bytes_written) = transferred_len;
+		/* All URBs and all buffers are available */
+#endif
+	}
+
+	return ((*bytes_written) == len) ? 0 : -EIO;
+}
+
+/* Receive a bulk message of variable size
+ *
+ * To copy the data to userspace, give pointer to "userbuffer",
+ * to copy to kernel memory, give "kernbuffer". One of them
+ * MUST be set. (There is no technique for letting the caller
+ * read directly from the ibuf.)
+ *
+ */
+
+static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+		void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
+		unsigned int tflags)
+{
+	int result = 0, retry, count = len;
+	int bufsize, thispass, transferred_len;
+	unsigned int pipe;
+	char *buffer;
+
+	(*bytes_read) = 0;
+
+	/* Sanity check */
+	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+		return -ENODEV;
+
+	pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
+	buffer = sisusb->ibuf;
+	bufsize = sisusb->ibufsize;
+
+	retry = 5;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return -EIO;
+#endif
+
+	while (count > 0) {
+
+		if (!sisusb->sisusb_dev)
+			return -ENODEV;
+
+		thispass = (bufsize < count) ? bufsize : count;
+
+		result = sisusb_bulkin_msg(sisusb,
+					   pipe,
+					   buffer,
+					   thispass,
+					   &transferred_len,
+					   5 * HZ,
+					   tflags,
+					   sisusb->transfer_dma_in);
+
+		if (transferred_len)
+			thispass = transferred_len;
+
+		else if (result == -ETIMEDOUT) {
+
+			if (!retry--)
+				return -ETIME;
+
+			continue;
+
+		} else
+			return -EIO;
+
+
+		if (thispass) {
+
+			(*bytes_read) += thispass;
+			count         -= thispass;
+
+			if (userbuffer) {
+
+				if (copy_to_user(userbuffer, buffer, thispass))
+					return -EFAULT;
+
+				userbuffer += thispass;
+
+			} else {
+
+				memcpy(kernbuffer, buffer, thispass);
+				kernbuffer += thispass;
+
+			}
+
+		}
+
+	}
+
+	return ((*bytes_read) == len) ? 0 : -EIO;
+}
+
+static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
+						struct sisusb_packet *packet)
+{
+	int ret;
+	ssize_t bytes_transferred = 0;
+	__le32 tmp;
+
+	if (len == 6)
+		packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return 1;
+#endif
+
+	/* Eventually correct endianness */
+	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+	/* 1. send the packet */
+	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
+			(char *)packet, NULL, 0, &bytes_transferred, 0, 0);
+
+	if ((ret == 0) && (len == 6)) {
+
+		/* 2. if packet len == 6, it means we read, so wait for 32bit
+		 *    return value and write it to packet->data
+		 */
+		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
+				(char *)&tmp, NULL, &bytes_transferred, 0);
+
+		packet->data = le32_to_cpu(tmp);
+	}
+
+	return ret;
+}
+
+static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
+					struct sisusb_packet *packet,
+					unsigned int tflags)
+{
+	int ret;
+	ssize_t bytes_transferred = 0;
+	__le32 tmp;
+
+	if (len == 6)
+		packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return 1;
+#endif
+
+	/* Eventually correct endianness */
+	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+	/* 1. send the packet */
+	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
+			(char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
+
+	if ((ret == 0) && (len == 6)) {
+
+		/* 2. if packet len == 6, it means we read, so wait for 32bit
+		 *    return value and write it to packet->data
+		 */
+		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
+				(char *)&tmp, NULL, &bytes_transferred, 0);
+
+		packet->data = le32_to_cpu(tmp);
+	}
+
+	return ret;
+}
+
+/* access video memory and mmio (return 0 on success) */
+
+/* Low level */
+
+/* The following routines assume being used to transfer byte, word,
+ * long etc.
+ * This means that they assume "data" in machine endianness format.
+ */
+
+static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u8 data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header  = (1 << (addr & 3)) | (type << 6);
+	packet.address = addr & ~3;
+	packet.data    = data << ((addr & 3) << 3);
+	ret = sisusb_send_packet(sisusb, 10, &packet);
+	return ret;
+}
+
+static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u16 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header = (type << 6) | 0x0003;
+			packet.data   = (u32)data;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header = (type << 6) | 0x0006;
+			packet.data   = (u32)data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header = (type << 6) | 0x000c;
+			packet.data   = (u32)data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header = (type << 6) | 0x0008;
+			packet.data   = (u32)data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data   = (u32)data >> 8;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x0007;
+			packet.data    = data & 0x00ffffff;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			packet.data    = data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			packet.data    = data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = (data >> 16) & 0x00ff;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			packet.data    = data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = (data >> 8) & 0xffff;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x000f;
+			packet.data    = data;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			packet.data    = data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 24;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			packet.data    = data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 16;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			packet.data    = data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0007;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 8;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+/* The xxx_bulk routines copy a buffer of variable size. They treat the
+ * buffer as chars, therefore lsb/msb has to be corrected if using the
+ * byte/word/long/etc routines for speed-up
+ *
+ * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
+ * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
+ * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
+ * that the data already is in the transfer buffer "sisusb->obuf[index]".
+ */
+
+static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+				char *kernbuffer, int length,
+				const char __user *userbuffer, int index,
+				ssize_t *bytes_written)
+{
+	struct sisusb_packet packet;
+	int  ret = 0;
+	static int msgcount = 0;
+	u8   swap8, fromkern = kernbuffer ? 1 : 0;
+	u16  swap16;
+	u32  swap32, flag = (length >> 28) & 1;
+	char buf[4];
+
+	/* if neither kernbuffer not userbuffer are given, assume
+	 * data in obuf
+	 */
+	if (!fromkern && !userbuffer)
+		kernbuffer = sisusb->obuf[index];
+
+	(*bytes_written = 0);
+
+	length &= 0x00ffffff;
+
+	while (length) {
+
+	    switch (length) {
+
+		case 0:
+			return ret;
+
+		case 1:
+			if (userbuffer) {
+				if (get_user(swap8, (u8 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap8 = kernbuffer[0];
+
+			ret = sisusb_write_memio_byte(sisusb,
+							SISUSB_TYPE_MEM,
+							addr, swap8);
+
+			if (!ret)
+				(*bytes_written)++;
+
+			return ret;
+
+		case 2:
+			if (userbuffer) {
+				if (get_user(swap16, (u16 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
+
+			ret = sisusb_write_memio_word(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap16);
+
+			if (!ret)
+				(*bytes_written) += 2;
+
+			return ret;
+
+		case 3:
+			if (userbuffer) {
+				if (copy_from_user(&buf, userbuffer, 3))
+					return -EFAULT;
+
+				swap32 = (buf[0] << 16) |
+					 (buf[1] <<  8) |
+					 buf[2];
+			} else
+				swap32 = (kernbuffer[0] << 16) |
+					 (kernbuffer[1] <<  8) |
+					 kernbuffer[2];
+
+			ret = sisusb_write_memio_24bit(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap32);
+
+			if (!ret)
+				(*bytes_written) += 3;
+
+			return ret;
+
+		case 4:
+			if (userbuffer) {
+				if (get_user(swap32, (u32 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap32 = (kernbuffer[0] << 24) |
+					 (kernbuffer[1] << 16) |
+					 (kernbuffer[2] <<  8) |
+					 kernbuffer[3];
+
+			ret = sisusb_write_memio_long(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap32);
+			if (!ret)
+				(*bytes_written) += 4;
+
+			return ret;
+
+		default:
+			if ((length & ~3) > 0x10000) {
+
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001d4;
+			   packet.data    = addr;
+			   ret = sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001d0;
+			   packet.data    = (length & ~3);
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001c0;
+			   packet.data    = flag | 0x16;
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   if (userbuffer) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							NULL, userbuffer, 0,
+							bytes_written, 0, 1);
+				userbuffer += (*bytes_written);
+			   } else if (fromkern) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							kernbuffer, NULL, 0,
+							bytes_written, 0, 1);
+				kernbuffer += (*bytes_written);
+			   } else {
+			ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							NULL, NULL, index,
+							bytes_written, 0, 1);
+				kernbuffer += ((*bytes_written) &
+						(sisusb->obufsize-1));
+			   }
+
+			} else {
+
+			   packet.header  = 0x001f;
+			   packet.address = 0x00000194;
+			   packet.data    = addr;
+			   ret = sisusb_send_bridge_packet(sisusb, 10,
+			   					&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x00000190;
+			   packet.data    = (length & ~3);
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+			   					&packet, 0);
+			   if (sisusb->flagb0 != 0x16) {
+				packet.header  = 0x001f;
+				packet.address = 0x00000180;
+				packet.data    = flag | 0x16;
+				ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+				sisusb->flagb0 = 0x16;
+			   }
+			   if (userbuffer) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							NULL, userbuffer, 0,
+							bytes_written, 0, 1);
+				userbuffer += (*bytes_written);
+			   } else if (fromkern) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							kernbuffer, NULL, 0,
+							bytes_written, 0, 1);
+				kernbuffer += (*bytes_written);
+			   } else {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							NULL, NULL, index,
+							bytes_written, 0, 1);
+				kernbuffer += ((*bytes_written) &
+						(sisusb->obufsize-1));
+			   }
+			}
+			if (ret) {
+				msgcount++;
+				if (msgcount < 500)
+					printk(KERN_ERR
+						"sisusbvga[%d]: Wrote %zd of "
+						"%d bytes, error %d\n",
+						sisusb->minor, *bytes_written,
+						length, ret);
+				else if (msgcount == 500)
+					printk(KERN_ERR
+						"sisusbvga[%d]: Too many errors"
+						", logging stopped\n",
+						sisusb->minor);
+			}
+			addr += (*bytes_written);
+			length -= (*bytes_written);
+	    }
+
+	    if (ret)
+	    	break;
+
+	}
+
+	return ret ? -EIO : 0;
+}
+
+static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u8 *data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	CLEARPACKET(&packet);
+	packet.header  = (1 << (addr & 3)) | (type << 6);
+	packet.address = addr & ~3;
+	ret = sisusb_send_packet(sisusb, 6, &packet);
+	*data = (u8)(packet.data >> ((addr & 3) << 3));
+	return ret;
+}
+
+static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u16 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	CLEARPACKET(&packet);
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header = (type << 6) | 0x0003;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data);
+			break;
+		case 1:
+			packet.header = (type << 6) | 0x0006;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 8);
+			break;
+		case 2:
+			packet.header = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 16);
+			break;
+		case 3:
+			packet.header = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 24);
+			packet.header = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (u16)(packet.data << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x0007;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data & 0x00ffffff;
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 8;
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 16;
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= ((packet.data & 0xff) << 16);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 24;
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= ((packet.data & 0xffff) << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x000f;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data;
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 8;
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 24);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 16;
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 16);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 24;
+			packet.header  = (type << 6) | 0x0007;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+				char *kernbuffer, int length,
+				char __user *userbuffer, ssize_t *bytes_read)
+{
+	int ret = 0;
+	char buf[4];
+	u16 swap16;
+	u32 swap32;
+
+	(*bytes_read = 0);
+
+	length &= 0x00ffffff;
+
+	while (length) {
+
+	    switch (length) {
+
+		case 0:
+			return ret;
+
+		case 1:
+
+			ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
+								addr, &buf[0]);
+			if (!ret) {
+				(*bytes_read)++;
+				if (userbuffer) {
+					if (put_user(buf[0],
+						(u8 __user *)userbuffer)) {
+						return -EFAULT;
+					}
+				} else {
+					kernbuffer[0] = buf[0];
+				}
+			}
+			return ret;
+
+		case 2:
+			ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap16);
+			if (!ret) {
+				(*bytes_read) += 2;
+				if (userbuffer) {
+					if (put_user(swap16,
+						(u16 __user *)userbuffer))
+						return -EFAULT;
+				} else {
+					kernbuffer[0] = swap16 >> 8;
+					kernbuffer[1] = swap16 & 0xff;
+				}
+			}
+			return ret;
+
+		case 3:
+			ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap32);
+			if (!ret) {
+				(*bytes_read) += 3;
+				buf[0] = (swap32 >> 16) & 0xff;
+				buf[1] = (swap32 >> 8) & 0xff;
+				buf[2] = swap32 & 0xff;
+				if (userbuffer) {
+					if (copy_to_user(userbuffer, &buf[0], 3))
+						return -EFAULT;
+				} else {
+					kernbuffer[0] = buf[0];
+					kernbuffer[1] = buf[1];
+					kernbuffer[2] = buf[2];
+				}
+			}
+			return ret;
+
+		default:
+			ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap32);
+			if (!ret) {
+				(*bytes_read) += 4;
+				if (userbuffer) {
+					if (put_user(swap32,
+						(u32 __user *)userbuffer))
+						return -EFAULT;
+
+					userbuffer += 4;
+				} else {
+					kernbuffer[0] = (swap32 >> 24) & 0xff;
+					kernbuffer[1] = (swap32 >> 16) & 0xff;
+					kernbuffer[2] = (swap32 >> 8) & 0xff;
+					kernbuffer[3] = swap32 & 0xff;
+					kernbuffer += 4;
+				}
+				addr += 4;
+				length -= 4;
+			}
+#if 0		/* That does not work, as EP 2 is an OUT EP! */
+		default:
+			CLEARPACKET(&packet);
+			packet.header  = 0x001f;
+			packet.address = 0x000001a0;
+			packet.data    = 0x00000006;
+			ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			packet.header  = 0x001f;
+			packet.address = 0x000001b0;
+			packet.data    = (length & ~3) | 0x40000000;
+			ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			packet.header  = 0x001f;
+			packet.address = 0x000001b4;
+			packet.data    = addr;
+			ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			packet.header  = 0x001f;
+			packet.address = 0x000001a4;
+			packet.data    = 0x00000001;
+			ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			if (userbuffer) {
+				ret |= sisusb_recv_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_IN,
+							(length & ~3),
+							NULL, userbuffer,
+							bytes_read, 0);
+				if (!ret) userbuffer += (*bytes_read);
+			} else {
+				ret |= sisusb_recv_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_IN,
+							(length & ~3),
+							kernbuffer, NULL,
+							bytes_read, 0);
+				if (!ret) kernbuffer += (*bytes_read);
+			}
+			addr += (*bytes_read);
+			length -= (*bytes_read);
+#endif
+	    }
+
+	    if (ret)
+	    	break;
+	}
+
+	return ret;
+}
+
+/* High level: Gfx (indexed) register access */
+
+static int
+sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
+{
+	int ret;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+	return ret;
+}
+
+static int
+sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
+{
+	int ret;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+	return ret;
+}
+
+static int
+sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
+							u8 myand, u8 myor)
+{
+	int ret;
+	u8 tmp;
+
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+	tmp &= myand;
+	tmp |= myor;
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+	return ret;
+}
+
+static int
+sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
+							u8 data, u8 mask)
+{
+	int ret;
+	u8 tmp;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+	tmp &= ~(mask);
+	tmp |= (data & mask);
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+	return ret;
+}
+
+static int
+sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
+{
+	return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
+}
+
+static int
+sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
+{
+	return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
+}
+
+/* access pci config registers (reg numbers 0, 4, 8, etc) */
+
+static int
+sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header = 0x008f;
+	packet.address = regnum | 0x10000;
+	packet.data = data;
+	ret = sisusb_send_packet(sisusb, 10, &packet);
+	return ret;
+}
+
+static int
+sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header = 0x008f;
+	packet.address = (u32)regnum | 0x10000;
+	ret = sisusb_send_packet(sisusb, 6, &packet);
+	*data = packet.data;
+	return ret;
+}
+
+/* Clear video RAM */
+
+static int
+sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
+{
+	int ret, i;
+	ssize_t j;
+
+	if (address < sisusb->vrambase)
+		return 1;
+
+	if (address >= sisusb->vrambase + sisusb->vramsize)
+		return 1;
+
+	if (address + length > sisusb->vrambase + sisusb->vramsize)
+		length = sisusb->vrambase + sisusb->vramsize - address;
+
+	if (length <= 0)
+		return 0;
+
+	/* allocate free buffer/urb and clear the buffer */
+	if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
+		return -EBUSY;
+
+	memset(sisusb->obuf[i], 0, sisusb->obufsize);
+
+	/* We can write a length > buffer size here. The buffer
+	 * data will simply be re-used (like a ring-buffer).
+	 */
+	ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
+
+	/* Free the buffer/urb */
+	sisusb_free_outbuf(sisusb, i);
+
+	return ret;
+}
+
+/* Initialize the graphics core (return 0 on success)
+ * This resets the graphics hardware and puts it into
+ * a defined mode (640x480@60Hz)
+ */
+
+#define GETREG(r,d)     sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETREG(r,d)	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETIREG(r,i,d)	sisusb_setidxreg(sisusb, r, i, d)
+#define GETIREG(r,i,d)  sisusb_getidxreg(sisusb, r, i, d)
+#define SETIREGOR(r,i,o)	sisusb_setidxregor(sisusb, r, i, o)
+#define SETIREGAND(r,i,a)	sisusb_setidxregand(sisusb, r, i, a)
+#define SETIREGANDOR(r,i,a,o)	sisusb_setidxregandor(sisusb, r, i, a, o)
+#define READL(a,d)	sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d) 	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define READB(a,d)	sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d) 	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+
+static int
+sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
+{
+	int ret;
+	u8 tmp8;
+
+	ret = GETIREG(SISSR, 0x16, &tmp8);
+	if (ramtype <= 1) {
+		tmp8 &= 0x3f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0x80;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+	} else {
+		tmp8 |= 0xc0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0x80;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0xd0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0xa0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+	}
+	return ret;
+}
+
+static int
+sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
+{
+	int ret;
+	u8  ramtype, done = 0;
+	u32 t0, t1, t2, t3;
+	u32 ramptr = SISUSB_PCI_MEMBASE;
+
+	ret = GETIREG(SISSR, 0x3a, &ramtype);
+	ramtype &= 3;
+
+	ret |= SETIREG(SISSR, 0x13, 0x00);
+
+	if (ramtype <= 1) {
+		ret |= SETIREG(SISSR, 0x14, 0x12);
+		ret |= SETIREGAND(SISSR, 0x15, 0xef);
+	} else {
+		ret |= SETIREG(SISSR, 0x14, 0x02);
+	}
+
+	ret |= sisusb_triggersr16(sisusb, ramtype);
+	ret |= WRITEL(ramptr +  0, 0x01234567);
+	ret |= WRITEL(ramptr +  4, 0x456789ab);
+	ret |= WRITEL(ramptr +  8, 0x89abcdef);
+	ret |= WRITEL(ramptr + 12, 0xcdef0123);
+	ret |= WRITEL(ramptr + 16, 0x55555555);
+	ret |= WRITEL(ramptr + 20, 0x55555555);
+	ret |= WRITEL(ramptr + 24, 0xffffffff);
+	ret |= WRITEL(ramptr + 28, 0xffffffff);
+	ret |= READL(ramptr +  0, &t0);
+	ret |= READL(ramptr +  4, &t1);
+	ret |= READL(ramptr +  8, &t2);
+	ret |= READL(ramptr + 12, &t3);
+
+	if (ramtype <= 1) {
+
+		*chab = 0; *bw = 64;
+
+		if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
+			if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
+				*chab = 0; *bw = 64;
+				ret |= SETIREGAND(SISSR, 0x14, 0xfd);
+			}
+		}
+		if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
+			*chab = 1; *bw = 64;
+			ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
+
+			ret |= sisusb_triggersr16(sisusb, ramtype);
+			ret |= WRITEL(ramptr +  0, 0x89abcdef);
+			ret |= WRITEL(ramptr +  4, 0xcdef0123);
+			ret |= WRITEL(ramptr +  8, 0x55555555);
+			ret |= WRITEL(ramptr + 12, 0x55555555);
+			ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
+			ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
+			ret |= READL(ramptr +  4, &t1);
+
+			if (t1 != 0xcdef0123) {
+				*bw = 32;
+				ret |= SETIREGOR(SISSR, 0x15, 0x10);
+			}
+		}
+
+	} else {
+
+		*chab = 0; *bw = 64;	/* default: cha, bw = 64 */
+
+		done = 0;
+
+		if (t1 == 0x456789ab) {
+			if (t0 == 0x01234567) {
+				*chab = 0; *bw = 64;
+				done = 1;
+			}
+		} else {
+			if (t0 == 0x01234567) {
+				*chab = 0; *bw = 32;
+				ret |= SETIREG(SISSR, 0x14, 0x00);
+				done = 1;
+			}
+		}
+
+		if (!done) {
+			ret |= SETIREG(SISSR, 0x14, 0x03);
+			ret |= sisusb_triggersr16(sisusb, ramtype);
+
+			ret |= WRITEL(ramptr +  0, 0x01234567);
+			ret |= WRITEL(ramptr +  4, 0x456789ab);
+			ret |= WRITEL(ramptr +  8, 0x89abcdef);
+			ret |= WRITEL(ramptr + 12, 0xcdef0123);
+			ret |= WRITEL(ramptr + 16, 0x55555555);
+			ret |= WRITEL(ramptr + 20, 0x55555555);
+			ret |= WRITEL(ramptr + 24, 0xffffffff);
+			ret |= WRITEL(ramptr + 28, 0xffffffff);
+			ret |= READL(ramptr +  0, &t0);
+			ret |= READL(ramptr +  4, &t1);
+
+			if (t1 == 0x456789ab) {
+				if (t0 == 0x01234567) {
+					*chab = 1; *bw = 64;
+					return ret;
+				} /* else error */
+			} else {
+				if (t0 == 0x01234567) {
+					*chab = 1; *bw = 32;
+					ret |= SETIREG(SISSR, 0x14, 0x01);
+				} /* else error */
+			}
+		}
+	}
+	return ret;
+}
+
+static int
+sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
+{
+	int ret = 0;
+	u32 ramptr = SISUSB_PCI_MEMBASE;
+	u8 tmp1, tmp2, i, j;
+
+	ret |= WRITEB(ramptr, 0xaa);
+	ret |= WRITEB(ramptr + 16, 0x55);
+	ret |= READB(ramptr, &tmp1);
+	ret |= READB(ramptr + 16, &tmp2);
+	if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
+		for (i = 0, j = 16; i < 2; i++, j += 16) {
+			ret |= GETIREG(SISSR, 0x21, &tmp1);
+			ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
+			ret |= SETIREGOR(SISSR, 0x3c, 0x01);  /* not on 330 */
+			ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
+			ret |= SETIREG(SISSR, 0x21, tmp1);
+			ret |= WRITEB(ramptr + 16 + j, j);
+			ret |= READB(ramptr + 16 + j, &tmp1);
+			if (tmp1 == j) {
+				ret |= WRITEB(ramptr + j, j);
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+static int
+sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
+			u8 rankno, u8 chab, const u8 dramtype[][5],
+			int bw)
+{
+	int ret = 0, ranksize;
+	u8 tmp;
+
+	*iret = 0;
+
+	if ((rankno == 2) && (dramtype[index][0] == 2))
+		return ret;
+
+	ranksize = dramtype[index][3] / 2 * bw / 32;
+
+	if ((ranksize * rankno) > 128)
+		return ret;
+
+	tmp = 0;
+	while ((ranksize >>= 1) > 0) tmp += 0x10;
+	tmp |= ((rankno - 1) << 2);
+	tmp |= ((bw / 64) & 0x02);
+	tmp |= (chab & 0x01);
+
+	ret = SETIREG(SISSR, 0x14, tmp);
+	ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
+
+	*iret = 1;
+
+	return ret;
+}
+
+static int
+sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
+{
+	int ret = 0, i;
+	u32 j, tmp;
+
+	*iret = 0;
+
+	for (i = 0, j = 0; i < testn; i++) {
+		ret |= WRITEL(sisusb->vrambase + j, j);
+		j += inc;
+	}
+
+	for (i = 0, j = 0; i < testn; i++) {
+		ret |= READL(sisusb->vrambase + j, &tmp);
+		if (tmp != j) return ret;
+		j += inc;
+	}
+
+	*iret = 1;
+	return ret;
+}
+
+static int
+sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
+					int idx, int bw, const u8 rtype[][5])
+{
+	int ret = 0, i, i2ret;
+	u32 inc;
+
+	*iret = 0;
+
+	for (i = rankno; i >= 1; i--) {
+		inc = 1 << (rtype[idx][2] +
+			    rtype[idx][1] +
+			    rtype[idx][0] +
+			    bw / 64 + i);
+		ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+		if (!i2ret)
+			return ret;
+	}
+
+	inc = 1 << (rtype[idx][2] + bw / 64 + 2);
+	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
+	if (!i2ret)
+		return ret;
+
+	inc = 1 << (10 + bw / 64);
+	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+	if (!i2ret)
+		return ret;
+
+	*iret = 1;
+	return ret;
+}
+
+static int
+sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
+								int chab)
+{
+	int ret = 0, i2ret = 0, i, j;
+	static const u8 sdramtype[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 }
+	};
+
+	*iret = 1; /* error */
+
+	for (i = 0; i < 13; i++) {
+		ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
+		for (j = 2; j > 0; j--) {
+			ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
+						chab, sdramtype, bw);
+			if (!i2ret)
+				continue;
+
+			ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
+						bw, sdramtype);
+			if (i2ret) {
+				*iret = 0;	/* ram size found */
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
+{
+	int ret = 0;
+	u32 address;
+	int i, length, modex, modey, bpp;
+
+	modex = 640; modey = 480; bpp = 2;
+
+	address = sisusb->vrambase;	/* Clear video ram */
+
+	if (clrall)
+		length = sisusb->vramsize;
+	else
+		length = modex * bpp * modey;
+
+	ret = sisusb_clear_vram(sisusb, address, length);
+
+	if (!ret && drwfr) {
+		for (i = 0; i < modex; i++) {
+			address = sisusb->vrambase + (i * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+			address += (modex * (modey-1) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+		}
+		for (i = 0; i < modey; i++) {
+			address = sisusb->vrambase + ((i * modex) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+			address += ((modex - 1) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+		}
+	}
+
+	return ret;
+}
+
+static int
+sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
+{
+	int ret = 0, i, j, modex, modey, bpp, du;
+	u8 sr31, cr63, tmp8;
+	static const char attrdata[] = {
+		0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+		0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+		0x01,0x00,0x00,0x00
+	};
+	static const char crtcrdata[] = {
+		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
+	};
+	static const char grcdata[] = {
+		0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+		0xff
+	};
+	static const char crtcdata[] = {
+		0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
+		0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+		0x00
+	};
+
+	modex = 640; modey = 480; bpp = 2;
+
+	GETIREG(SISSR, 0x31, &sr31);
+	GETIREG(SISCR, 0x63, &cr63);
+	SETIREGOR(SISSR, 0x01, 0x20);
+	SETIREG(SISCR, 0x63, cr63 & 0xbf);
+	SETIREGOR(SISCR, 0x17, 0x80);
+	SETIREGOR(SISSR, 0x1f, 0x04);
+	SETIREGAND(SISSR, 0x07, 0xfb);
+	SETIREG(SISSR, 0x00, 0x03);	/* seq */
+	SETIREG(SISSR, 0x01, 0x21);
+	SETIREG(SISSR, 0x02, 0x0f);
+	SETIREG(SISSR, 0x03, 0x00);
+	SETIREG(SISSR, 0x04, 0x0e);
+	SETREG(SISMISCW, 0x23);		/* misc */
+	for (i = 0; i <= 0x18; i++) {	/* crtc */
+		SETIREG(SISCR, i, crtcrdata[i]);
+	}
+	for (i = 0; i <= 0x13; i++) {	/* att */
+		GETREG(SISINPSTAT, &tmp8);
+		SETREG(SISAR, i);
+		SETREG(SISAR, attrdata[i]);
+	}
+	GETREG(SISINPSTAT, &tmp8);
+	SETREG(SISAR, 0x14);
+	SETREG(SISAR, 0x00);
+	GETREG(SISINPSTAT, &tmp8);
+	SETREG(SISAR, 0x20);
+	GETREG(SISINPSTAT, &tmp8);
+	for (i = 0; i <= 0x08; i++) {	/* grc */
+		SETIREG(SISGR, i, grcdata[i]);
+	}
+	SETIREGAND(SISGR, 0x05, 0xbf);
+	for (i = 0x0A; i <= 0x0E; i++) {	/* clr ext */
+		SETIREG(SISSR, i, 0x00);
+	}
+	SETIREGAND(SISSR, 0x37, 0xfe);
+	SETREG(SISMISCW, 0xef);		/* sync */
+	SETIREG(SISCR, 0x11, 0x00);	/* crtc */
+	for (j = 0x00, i = 0; i <= 7; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x10; i <= 10; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x15; i <= 12; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x0A; i <= 15; i++, j++) {
+		SETIREG(SISSR, j, crtcdata[i]);
+	}
+	SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
+	SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
+	SETIREG(SISCR, 0x14, 0x4f);
+	du = (modex / 16) * (bpp * 2);	/* offset/pitch */
+	if (modex % 16) du += bpp;
+	SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
+	SETIREG(SISCR, 0x13, (du & 0xff));
+	du <<= 5;
+	tmp8 = du >> 8;
+	if (du & 0xff) tmp8++;
+	SETIREG(SISSR, 0x10, tmp8);
+	SETIREG(SISSR, 0x31, 0x00);	/* VCLK */
+	SETIREG(SISSR, 0x2b, 0x1b);
+	SETIREG(SISSR, 0x2c, 0xe1);
+	SETIREG(SISSR, 0x2d, 0x01);
+	SETIREGAND(SISSR, 0x3d, 0xfe);	/* FIFO */
+	SETIREG(SISSR, 0x08, 0xae);
+	SETIREGAND(SISSR, 0x09, 0xf0);
+	SETIREG(SISSR, 0x08, 0x34);
+	SETIREGOR(SISSR, 0x3d, 0x01);
+	SETIREGAND(SISSR, 0x1f, 0x3f);	/* mode regs */
+	SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
+	SETIREG(SISCR, 0x19, 0x00);
+	SETIREGAND(SISCR, 0x1a, 0xfc);
+	SETIREGAND(SISSR, 0x0f, 0xb7);
+	SETIREGAND(SISSR, 0x31, 0xfb);
+	SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
+	SETIREGAND(SISSR, 0x32, 0xf3);
+	SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
+	SETIREG(SISCR, 0x52, 0x6c);
+
+	SETIREG(SISCR, 0x0d, 0x00);	/* adjust frame */
+	SETIREG(SISCR, 0x0c, 0x00);
+	SETIREG(SISSR, 0x0d, 0x00);
+	SETIREGAND(SISSR, 0x37, 0xfe);
+
+	SETIREG(SISCR, 0x32, 0x20);
+	SETIREGAND(SISSR, 0x01, 0xdf);	/* enable display */
+	SETIREG(SISCR, 0x63, (cr63 & 0xbf));
+	SETIREG(SISSR, 0x31, (sr31 & 0xfb));
+
+	if (touchengines) {
+		SETIREG(SISSR, 0x20, 0xa1);	/* enable engines */
+		SETIREGOR(SISSR, 0x1e, 0x5a);
+
+		SETIREG(SISSR, 0x26, 0x01);	/* disable cmdqueue */
+		SETIREG(SISSR, 0x27, 0x1f);
+		SETIREG(SISSR, 0x26, 0x00);
+	}
+
+	SETIREG(SISCR, 0x34, 0x44);  	/* we just set std mode #44 */
+
+	return ret;
+}
+
+static int
+sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
+{
+	int ret = 0, i, j, bw, chab, iret, retry = 3;
+	u8 tmp8, ramtype;
+	u32 tmp32;
+	static const char mclktable[] = {
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143
+	};
+	static const char eclktable[] = {
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143
+	};
+	static const char ramtypetable1[] = {
+		0x00, 0x04, 0x60, 0x60,
+		0x0f, 0x0f, 0x1f, 0x1f,
+		0xba, 0xba, 0xba, 0xba,
+		0xa9, 0xa9, 0xac, 0xac,
+		0xa0, 0xa0, 0xa0, 0xa8,
+		0x00, 0x00, 0x02, 0x02,
+		0x30, 0x30, 0x40, 0x40
+	};
+	static const char ramtypetable2[] = {
+		0x77, 0x77, 0x44, 0x44,
+		0x77, 0x77, 0x44, 0x44,
+		0x00, 0x00, 0x00, 0x00,
+		0x5b, 0x5b, 0xab, 0xab,
+		0x00, 0x00, 0xf0, 0xf8
+	};
+
+	while (retry--) {
+
+		/* Enable VGA */
+		ret = GETREG(SISVGAEN, &tmp8);
+		ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
+
+		/* Enable GPU access to VRAM */
+		ret |= GETREG(SISMISCR, &tmp8);
+		ret |= SETREG(SISMISCW, (tmp8 | 0x01));
+
+		if (ret) continue;
+
+		/* Reset registers */
+		ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
+		ret |= SETIREG(SISSR, 0x05, 0x86);
+		ret |= SETIREGOR(SISSR, 0x20, 0x01);
+
+		ret |= SETREG(SISMISCW, 0x67);
+
+		for (i = 0x06; i <= 0x1f; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x21; i <= 0x27; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x31; i <= 0x3d; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x12; i <= 0x1b; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x79; i <= 0x7c; i++) {
+			ret |= SETIREG(SISCR, i, 0x00);
+		}
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISCR, 0x63, 0x80);
+
+		ret |= GETIREG(SISSR, 0x3a, &ramtype);
+		ramtype &= 0x03;
+
+		ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
+		ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
+		ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
+
+		ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
+		ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
+		ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
+
+		ret |= SETIREG(SISSR, 0x07, 0x18);
+		ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+		if (ret) continue;
+
+		for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
+			ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
+		}
+		for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
+			ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
+		}
+
+		ret |= SETIREG(SISCR, 0x49, 0xaa);
+
+		ret |= SETIREG(SISSR, 0x1f, 0x00);
+		ret |= SETIREG(SISSR, 0x20, 0xa0);
+		ret |= SETIREG(SISSR, 0x23, 0xf6);
+		ret |= SETIREG(SISSR, 0x24, 0x0d);
+		ret |= SETIREG(SISSR, 0x25, 0x33);
+
+		ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+		ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
+
+		ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISPART1, 0x00, 0x00);
+
+		ret |= GETIREG(SISSR, 0x13, &tmp8);
+		tmp8 >>= 4;
+
+		ret |= SETIREG(SISPART1, 0x02, 0x00);
+		ret |= SETIREG(SISPART1, 0x2e, 0x08);
+
+		ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
+		tmp32 &= 0x00f00000;
+		tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
+		ret |= SETIREG(SISSR, 0x25, tmp8);
+		tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
+		ret |= SETIREG(SISCR, 0x49, tmp8);
+
+		ret |= SETIREG(SISSR, 0x27, 0x1f);
+		ret |= SETIREG(SISSR, 0x31, 0x00);
+		ret |= SETIREG(SISSR, 0x32, 0x11);
+		ret |= SETIREG(SISSR, 0x33, 0x00);
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISCR, 0x83, 0x00);
+
+		ret |= sisusb_set_default_mode(sisusb, 0);
+
+		ret |= SETIREGAND(SISSR, 0x21, 0xdf);
+		ret |= SETIREGOR(SISSR, 0x01, 0x20);
+		ret |= SETIREGOR(SISSR, 0x16, 0x0f);
+
+		ret |= sisusb_triggersr16(sisusb, ramtype);
+
+		/* Disable refresh */
+		ret |= SETIREGAND(SISSR, 0x17, 0xf8);
+		ret |= SETIREGOR(SISSR, 0x19, 0x03);
+
+		ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
+		ret |= sisusb_verify_mclk(sisusb);
+
+		if (ramtype <= 1) {
+			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
+			if (iret) {
+				printk(KERN_ERR "sisusbvga[%d]: RAM size "
+					"detection failed, "
+					"assuming 8MB video RAM\n",
+					sisusb->minor);
+				ret |= SETIREG(SISSR,0x14,0x31);
+				/* TODO */
+			}
+		} else {
+			printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
+					"assuming 8MB video RAM\n",
+					sisusb->minor);
+			ret |= SETIREG(SISSR,0x14,0x31);
+			/* *** TODO *** */
+		}
+
+		/* Enable refresh */
+		ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
+		ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
+		ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
+
+		ret |= SETIREGOR(SISSR, 0x21, 0x20);
+
+		ret |= SETIREG(SISSR, 0x22, 0xfb);
+		ret |= SETIREG(SISSR, 0x21, 0xa5);
+
+		if (ret == 0)
+			break;
+	}
+
+	return ret;
+}
+
+#undef SETREG
+#undef GETREG
+#undef SETIREG
+#undef GETIREG
+#undef SETIREGOR
+#undef SETIREGAND
+#undef SETIREGANDOR
+#undef READL
+#undef WRITEL
+
+static void
+sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
+{
+	u8 tmp8, tmp82, ramtype;
+	int bw = 0;
+	char *ramtypetext1 = NULL;
+	const char *ramtypetext2[] = {	"SDR SDRAM", "SDR SGRAM",
+					"DDR SDRAM", "DDR SGRAM" };
+	static const int busSDR[4]  = {64, 64, 128, 128};
+	static const int busDDR[4]  = {32, 32,  64,  64};
+	static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
+
+	sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
+	sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
+	sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
+	sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
+	ramtype &= 0x03;
+	switch ((tmp8 >> 2) & 0x03) {
+	case 0: ramtypetext1 = "1 ch/1 r";
+		if (tmp82 & 0x10) {
+			bw = 32;
+		} else {
+			bw = busSDR[(tmp8 & 0x03)];
+		}
+		break;
+	case 1: ramtypetext1 = "1 ch/2 r";
+		sisusb->vramsize <<= 1;
+		bw = busSDR[(tmp8 & 0x03)];
+		break;
+	case 2: ramtypetext1 = "asymmeric";
+		sisusb->vramsize += sisusb->vramsize/2;
+		bw = busDDRA[(tmp8 & 0x03)];
+		break;
+	case 3: ramtypetext1 = "2 channel";
+		sisusb->vramsize <<= 1;
+		bw = busDDR[(tmp8 & 0x03)];
+		break;
+	}
+
+	printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
+			sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+			ramtypetext2[ramtype], bw);
+}
+
+static int
+sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
+{
+	struct sisusb_packet packet;
+	int ret;
+	u32 tmp32;
+
+	/* Do some magic */
+	packet.header  = 0x001f;
+	packet.address = 0x00000324;
+	packet.data    = 0x00000004;
+	ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000364;
+	packet.data    = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000384;
+	packet.data    = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000100;
+	packet.data    = 0x00000700;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x000f;
+	packet.address = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
+	packet.data |= 0x17;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	/* Init BAR 0 (VRAM) */
+	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_MEMBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
+
+	/* Init BAR 1 (MMIO) */
+	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_MMIOBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
+
+	/* Init BAR 2 (i/o ports) */
+	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_IOPORTBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
+
+	/* Enable memory and i/o access */
+	ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
+	tmp32 |= 0x3;
+	ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
+
+	if (ret == 0) {
+		/* Some further magic */
+		packet.header  = 0x001f;
+		packet.address = 0x00000050;
+		packet.data    = 0x000000ff;
+		ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+	}
+
+	return ret;
+}
+
+/* Initialize the graphics device (return 0 on success)
+ * This initializes the net2280 as well as the PCI registers
+ * of the graphics board.
+ */
+
+static int
+sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
+{
+	int ret = 0, test = 0;
+	u32 tmp32;
+
+	if (sisusb->devinit == 1) {
+		/* Read PCI BARs and see if they have been set up */
+		ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
+
+		ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
+
+		ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
+	}
+
+	/* No? So reset the device */
+	if ((sisusb->devinit == 0) || (test != 3)) {
+
+		ret |= sisusb_do_init_gfxdevice(sisusb);
+
+		if (ret == 0)
+			sisusb->devinit = 1;
+
+	}
+
+	if (sisusb->devinit) {
+		/* Initialize the graphics core */
+		if (sisusb_init_gfxcore(sisusb) == 0) {
+			sisusb->gfxinit = 1;
+			sisusb_get_ramconfig(sisusb);
+			ret |= sisusb_set_default_mode(sisusb, 1);
+			ret |= sisusb_setup_screen(sisusb, 1, initscreen);
+		}
+	}
+
+	return ret;
+}
+
+/* fops */
+
+static int
+sisusb_open(struct inode *inode, struct file *file)
+{
+	struct sisusb_usb_data *sisusb;
+	struct usb_interface *interface;
+	int subminor = iminor(inode);
+
+	down(&disconnect_sem);
+
+	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
+		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
+				subminor);
+		up(&disconnect_sem);
+		return -ENODEV;
+	}
+
+	if (!(sisusb = usb_get_intfdata(interface))) {
+		up(&disconnect_sem);
+		return -ENODEV;
+	}
+
+	down(&sisusb->lock);
+
+	if (!sisusb->present || !sisusb->ready) {
+		up(&sisusb->lock);
+		up(&disconnect_sem);
+		return -ENODEV;
+	}
+
+	if (sisusb->isopen) {
+		up(&sisusb->lock);
+		up(&disconnect_sem);
+		return -EBUSY;
+	}
+
+	if (!sisusb->devinit) {
+		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
+			if (sisusb_init_gfxdevice(sisusb, 0)) {
+				up(&sisusb->lock);
+				up(&disconnect_sem);
+				printk(KERN_ERR
+					"sisusbvga[%d]: Failed to initialize "
+					"device\n",
+					sisusb->minor);
+				return -EIO;
+			}
+		} else {
+			up(&sisusb->lock);
+			up(&disconnect_sem);
+			printk(KERN_ERR
+				"sisusbvga[%d]: Device not attached to "
+				"USB 2.0 hub\n",
+				sisusb->minor);
+			return -EIO;
+		}
+	}
+
+	/* increment usage count for the device */
+	kref_get(&sisusb->kref);
+
+	sisusb->isopen = 1;
+
+	file->private_data = sisusb;
+
+	up(&sisusb->lock);
+
+	up(&disconnect_sem);
+
+	printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
+
+	return 0;
+}
+
+static void
+sisusb_delete(struct kref *kref)
+{
+	struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
+
+	if (!sisusb)
+		return;
+
+	if (sisusb->sisusb_dev)
+		usb_put_dev(sisusb->sisusb_dev);
+
+	sisusb->sisusb_dev = NULL;
+	sisusb_free_buffers(sisusb);
+	sisusb_free_urbs(sisusb);
+	kfree(sisusb);
+}
+
+static int
+sisusb_release(struct inode *inode, struct file *file)
+{
+	struct sisusb_usb_data *sisusb;
+	int myminor;
+
+	down(&disconnect_sem);
+
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
+		up(&disconnect_sem);
+		return -ENODEV;
+	}
+
+	down(&sisusb->lock);
+
+	if (sisusb->present) {
+		/* Wait for all URBs to finish if device still present */
+		if (!sisusb_wait_all_out_complete(sisusb))
+			sisusb_kill_all_busy(sisusb);
+	}
+
+	myminor = sisusb->minor;
+
+	sisusb->isopen = 0;
+	file->private_data = NULL;
+
+	up(&sisusb->lock);
+
+	/* decrement the usage count on our device */
+	kref_put(&sisusb->kref, sisusb_delete);
+
+	up(&disconnect_sem);
+
+	printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
+
+	return 0;
+}
+
+static ssize_t
+sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t bytes_read = 0;
+	int errno = 0;
+	u8 buf8;
+	u16 buf16;
+	u32 buf32, address;
+
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+		return -ENODEV;
+
+	down(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		up(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+	    (*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_IOPORTBASE +
+			SISUSB_PCI_IOPORTBASE;
+
+		/* Read i/o ports
+		 * Byte, word and long(32) can be read. As this
+		 * emulates inX instructions, the data returned is
+		 * in machine-endianness.
+		 */
+		switch (count) {
+
+			case 1:
+				if (sisusb_read_memio_byte(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf8))
+					errno = -EIO;
+				else if (put_user(buf8, (u8 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 1;
+
+				break;
+
+			case 2:
+				if (sisusb_read_memio_word(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf16))
+					errno = -EIO;
+				else if (put_user(buf16, (u16 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 2;
+
+				break;
+
+			case 4:
+				if (sisusb_read_memio_long(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf32))
+					errno = -EIO;
+				else if (put_user(buf32, (u32 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 4;
+
+				break;
+
+			default:
+				errno = -EIO;
+
+		}
+
+	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+		   (*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MEMBASE +
+			SISUSB_PCI_MEMBASE;
+
+		/* Read video ram
+		 * Remember: Data delivered is never endian-corrected
+		 */
+		errno = sisusb_read_mem_bulk(sisusb, address,
+					NULL, count, buffer, &bytes_read);
+
+		if (bytes_read)
+			errno = bytes_read;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+		    (*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MMIOBASE +
+			SISUSB_PCI_MMIOBASE;
+
+		/* Read MMIO
+		 * Remember: Data delivered is never endian-corrected
+		 */
+		errno = sisusb_read_mem_bulk(sisusb, address,
+					NULL, count, buffer, &bytes_read);
+
+		if (bytes_read)
+			errno = bytes_read;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
+
+		if (count != 4) {
+			up(&sisusb->lock);
+			return -EINVAL;
+		}
+
+		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+		/* Read PCI config register
+		 * Return value delivered in machine endianness.
+		 */
+		if (sisusb_read_pci_config(sisusb, address, &buf32))
+			errno = -EIO;
+		else if (put_user(buf32, (u32 __user *)buffer))
+			errno = -EFAULT;
+		else
+			bytes_read = 4;
+
+	} else {
+
+		errno = -EBADFD;
+
+	}
+
+	(*ppos) += bytes_read;
+
+	up(&sisusb->lock);
+
+	return errno ? errno : bytes_read;
+}
+
+static ssize_t
+sisusb_write(struct file *file, const char __user *buffer, size_t count,
+								loff_t *ppos)
+{
+	struct sisusb_usb_data *sisusb;
+	int errno = 0;
+	ssize_t bytes_written = 0;
+	u8 buf8;
+	u16 buf16;
+	u32 buf32, address;
+
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+		return -ENODEV;
+
+	down(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		up(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+	    (*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_IOPORTBASE +
+			SISUSB_PCI_IOPORTBASE;
+
+		/* Write i/o ports
+		 * Byte, word and long(32) can be written. As this
+		 * emulates outX instructions, the data is expected
+		 * in machine-endianness.
+		 */
+		switch (count) {
+
+			case 1:
+				if (get_user(buf8, (u8 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_byte(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf8))
+					errno = -EIO;
+				else
+					bytes_written = 1;
+
+				break;
+
+			case 2:
+				if (get_user(buf16, (u16 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_word(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf16))
+					errno = -EIO;
+				else
+					bytes_written = 2;
+
+				break;
+
+			case 4:
+				if (get_user(buf32, (u32 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_long(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf32))
+					errno = -EIO;
+				else
+					bytes_written = 4;
+
+				break;
+
+			default:
+				errno = -EIO;
+		}
+
+	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+		   (*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MEMBASE +
+			SISUSB_PCI_MEMBASE;
+
+		/* Write video ram.
+		 * Buffer is copied 1:1, therefore, on big-endian
+		 * machines, the data must be swapped by userland
+		 * in advance (if applicable; no swapping in 8bpp
+		 * mode or if YUV data is being transferred).
+		 */
+		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+					count, buffer, 0, &bytes_written);
+
+		if (bytes_written)
+			errno = bytes_written;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+		    (*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MMIOBASE +
+			SISUSB_PCI_MMIOBASE;
+
+		/* Write MMIO.
+		 * Buffer is copied 1:1, therefore, on big-endian
+		 * machines, the data must be swapped by userland
+		 * in advance.
+		 */
+		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+					count, buffer, 0, &bytes_written);
+
+		if (bytes_written)
+			errno = bytes_written;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
+
+		if (count != 4) {
+			up(&sisusb->lock);
+			return -EINVAL;
+		}
+
+		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+		/* Write PCI config register.
+		 * Given value expected in machine endianness.
+		 */
+		if (get_user(buf32, (u32 __user *)buffer))
+			errno = -EFAULT;
+		else if (sisusb_write_pci_config(sisusb, address, buf32))
+			errno = -EIO;
+		else
+			bytes_written = 4;
+
+
+	} else {
+
+		/* Error */
+		errno = -EBADFD;
+
+	}
+
+	(*ppos) += bytes_written;
+
+	up(&sisusb->lock);
+
+	return errno ? errno : bytes_written;
+}
+
+static loff_t
+sisusb_lseek(struct file *file, loff_t offset, int orig)
+{
+	struct sisusb_usb_data *sisusb;
+	loff_t ret;
+
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+		return -ENODEV;
+
+	down(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		up(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	switch (orig) {
+		case 0:
+			file->f_pos = offset;
+			ret = file->f_pos;
+			/* never negative, no force_successful_syscall needed */
+			break;
+		case 1:
+			file->f_pos += offset;
+			ret = file->f_pos;
+			/* never negative, no force_successful_syscall needed */
+			break;
+		default:
+			/* seeking relative to "end of file" is not supported */
+			ret = -EINVAL;
+	}
+
+	up(&sisusb->lock);
+	return ret;
+}
+
+static int
+sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
+							unsigned long arg)
+{
+	int 	retval, port, length;
+	u32	address;
+
+	port = y->data3 -
+		SISUSB_PCI_PSEUDO_IOPORTBASE +
+		SISUSB_PCI_IOPORTBASE;
+
+	switch (y->operation) {
+		case SUCMD_GET:
+			retval = sisusb_getidxreg(sisusb, port,
+							 y->data0, &y->data1);
+			if (!retval) {
+				if (copy_to_user((void __user *)arg, y,
+							sizeof(*y)))
+					retval = -EFAULT;
+			}
+			break;
+
+		case SUCMD_SET:
+			retval = sisusb_setidxreg(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETOR:
+			retval = sisusb_setidxregor(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETAND:
+			retval = sisusb_setidxregand(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETANDOR:
+			retval = sisusb_setidxregandor(sisusb, port,
+						y->data0, y->data1, y->data2);
+			break;
+
+		case SUCMD_SETMASK:
+			retval = sisusb_setidxregmask(sisusb, port,
+						y->data0, y->data1, y->data2);
+			break;
+
+		case SUCMD_CLRSCR:
+			length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
+			address = y->data3 -
+				SISUSB_PCI_PSEUDO_MEMBASE +
+				SISUSB_PCI_MEMBASE;
+			retval = sisusb_clear_vram(sisusb, address, length);
+			break;
+
+		default:
+			retval = -EINVAL;
+	}
+
+	if(retval > 0)
+		retval = -EIO;
+
+	return retval;
+}
+
+static int
+sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	     						unsigned long arg)
+{
+	struct sisusb_usb_data *sisusb;
+	struct sisusb_info x;
+	struct sisusb_command y;
+	int 	retval = 0;
+	u32 __user *argp = (u32 __user *)arg;
+
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+		return -ENODEV;
+
+	down(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	switch (cmd) {
+
+		case SISUSB_GET_CONFIG_SIZE:
+
+			if (put_user(sizeof(x), argp))
+				retval = -EFAULT;
+
+			break;
+
+		case SISUSB_GET_CONFIG:
+
+			x.sisusb_id   	    = SISUSB_ID;
+			x.sisusb_version    = SISUSB_VERSION;
+			x.sisusb_revision   = SISUSB_REVISION;
+			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
+			x.sisusb_gfxinit    = sisusb->gfxinit;
+			x.sisusb_vrambase   = SISUSB_PCI_PSEUDO_MEMBASE;
+			x.sisusb_mmiobase   = SISUSB_PCI_PSEUDO_MMIOBASE;
+			x.sisusb_iobase     = SISUSB_PCI_PSEUDO_IOPORTBASE;
+			x.sisusb_pcibase    = SISUSB_PCI_PSEUDO_PCIBASE;
+			x.sisusb_vramsize   = sisusb->vramsize;
+			x.sisusb_minor	    = sisusb->minor;
+			x.sisusb_fbdevactive= 0;
+
+			if (copy_to_user((void __user *)arg, &x, sizeof(x)))
+				retval = -EFAULT;
+
+			break;
+
+		case SISUSB_COMMAND:
+
+			if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
+				retval = -EFAULT;
+			else
+				retval = sisusb_handle_command(sisusb, &y, arg);
+
+			break;
+
+		default:
+			retval = -EINVAL;
+			break;
+	}
+
+err_out:
+	up(&sisusb->lock);
+	return retval;
+}
+
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+static long
+sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	long retval;
+
+	switch (cmd) {
+		case SISUSB_GET_CONFIG_SIZE:
+		case SISUSB_GET_CONFIG:
+		case SISUSB_COMMAND:
+			lock_kernel();
+			retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+			unlock_kernel();
+			return retval;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+#endif
+
+static struct file_operations usb_sisusb_fops = {
+	.owner =	THIS_MODULE,
+	.open =		sisusb_open,
+	.release =	sisusb_release,
+	.read =		sisusb_read,
+	.write =	sisusb_write,
+	.llseek = 	sisusb_lseek,
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+	.compat_ioctl = sisusb_compat_ioctl,
+#endif
+	.ioctl =	sisusb_ioctl
+};
+
+static struct usb_class_driver usb_sisusb_class = {
+	.name =		"usb/sisusbvga%d",
+	.fops =		&usb_sisusb_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	SISUSB_MINOR
+};
+
+static int sisusb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct sisusb_usb_data *sisusb;
+	int retval = 0, i;
+	const char *memfail =
+		KERN_ERR
+		"sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
+
+	printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+		dev->devnum);
+
+	/* Allocate memory for our private */
+	if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
+		printk(KERN_ERR
+			"sisusb: Failed to allocate memory for private data\n");
+		return -ENOMEM;
+	}
+	memset(sisusb, 0, sizeof(*sisusb));
+	kref_init(&sisusb->kref);
+
+	init_MUTEX(&(sisusb->lock));
+
+	/* Register device */
+	if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
+		printk(KERN_ERR
+			"sisusb: Failed to get a minor for device %d\n",
+			dev->devnum);
+		retval = -ENODEV;
+		goto error_1;
+	}
+
+	sisusb->sisusb_dev = dev;
+	sisusb->minor      = intf->minor;
+	sisusb->vrambase   = SISUSB_PCI_MEMBASE;
+	sisusb->mmiobase   = SISUSB_PCI_MMIOBASE;
+	sisusb->mmiosize   = SISUSB_PCI_MMIOSIZE;
+	sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
+	/* Everything else is zero */
+
+	/* Allocate buffers */
+	sisusb->ibufsize = SISUSB_IBUF_SIZE;
+	if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
+					GFP_KERNEL, &sisusb->transfer_dma_in))) {
+		printk(memfail, "input", sisusb->minor);
+		retval = -ENOMEM;
+		goto error_2;
+	}
+
+	sisusb->numobufs = 0;
+	sisusb->obufsize = SISUSB_OBUF_SIZE;
+	for (i = 0; i < NUMOBUFS; i++) {
+		if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
+					GFP_KERNEL,
+					&sisusb->transfer_dma_out[i]))) {
+			if (i == 0) {
+				printk(memfail, "output", sisusb->minor);
+				retval = -ENOMEM;
+				goto error_3;
+			}
+			break;
+		} else
+			sisusb->numobufs++;
+
+	}
+
+	/* Allocate URBs */
+	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
+		printk(KERN_ERR
+			"sisusbvga[%d]: Failed to allocate URBs\n",
+			sisusb->minor);
+		retval = -ENOMEM;
+		goto error_3;
+	}
+	sisusb->completein = 1;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+		if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
+			printk(KERN_ERR
+				"sisusbvga[%d]: Failed to allocate URBs\n",
+				sisusb->minor);
+			retval = -ENOMEM;
+			goto error_4;
+		}
+		sisusb->urbout_context[i].sisusb = (void *)sisusb;
+		sisusb->urbout_context[i].urbindex = i;
+		sisusb->urbstatus[i] = 0;
+	}
+
+	printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
+					sisusb->minor, sisusb->numobufs);
+
+	/* Do remaining init stuff */
+
+	init_waitqueue_head(&sisusb->wait_q);
+
+	usb_set_intfdata(intf, sisusb);
+
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+	{
+	int ret;
+	/* Our ioctls are all "32/64bit compatible" */
+	ret =  register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
+	ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
+	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
+	if (ret)
+		printk(KERN_ERR
+			"sisusbvga[%d]: Error registering ioctl32 "
+			"translations\n",
+			sisusb->minor);
+	else
+		sisusb->ioctl32registered = 1;
+
+	}
+#endif
+
+	sisusb->present = 1;
+
+	if (dev->speed == USB_SPEED_HIGH) {
+		if (sisusb_init_gfxdevice(sisusb, 1))
+			printk(KERN_ERR
+				"sisusbvga[%d]: Failed to early "
+				"initialize device\n",
+				sisusb->minor);
+
+	} else
+		printk(KERN_INFO
+			"sisusbvga[%d]: Not attached to USB 2.0 hub, "
+			"deferring init\n",
+			sisusb->minor);
+
+	sisusb->ready = 1;
+
+	return 0;
+
+error_4:
+	sisusb_free_urbs(sisusb);
+error_3:
+	sisusb_free_buffers(sisusb);
+error_2:
+	usb_deregister_dev(intf, &usb_sisusb_class);
+error_1:
+	kfree(sisusb);
+	return retval;
+}
+
+static void sisusb_disconnect(struct usb_interface *intf)
+{
+	struct sisusb_usb_data *sisusb;
+	int minor;
+
+	down(&disconnect_sem);
+
+	/* This should *not* happen */
+	if (!(sisusb = usb_get_intfdata(intf))) {
+		up(&disconnect_sem);
+		return;
+	}
+
+	down(&sisusb->lock);
+
+	/* Wait for all URBs to complete and kill them in case (MUST do) */
+	if (!sisusb_wait_all_out_complete(sisusb))
+		sisusb_kill_all_busy(sisusb);
+
+	minor = sisusb->minor;
+
+	usb_set_intfdata(intf, NULL);
+
+	usb_deregister_dev(intf, &usb_sisusb_class);
+
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+	if (sisusb->ioctl32registered) {
+		int ret;
+		sisusb->ioctl32registered = 0;
+		ret =  unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
+		ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
+		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
+		if (ret) {
+			printk(KERN_ERR
+				"sisusbvga[%d]: Error unregistering "
+				"ioctl32 translations\n",
+				minor);
+		}
+	}
+#endif
+
+	sisusb->present = 0;
+	sisusb->ready = 0;
+
+	up(&sisusb->lock);
+
+	/* decrement our usage count */
+	kref_put(&sisusb->kref, sisusb_delete);
+
+	up(&disconnect_sem);
+
+	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+}
+
+static struct usb_device_id sisusb_table [] = {
+	{ USB_DEVICE(0x0711, 0x0900) },
+	{ USB_DEVICE(0x182d, 0x021c) },
+	{ USB_DEVICE(0x182d, 0x0269) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, sisusb_table);
+
+static struct usb_driver sisusb_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"sisusb",
+	.probe =	sisusb_probe,
+	.disconnect =	sisusb_disconnect,
+	.id_table =	sisusb_table,
+};
+
+static int __init usb_sisusb_init(void)
+{
+	int retval;
+
+	if (!(retval = usb_register(&sisusb_driver))) {
+		printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
+			SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
+		printk(KERN_INFO
+			"sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
+	}
+
+	return retval;
+}
+
+static void __exit usb_sisusb_exit(void)
+{
+	usb_deregister(&sisusb_driver);
+}
+
+module_init(usb_sisusb_init);
+module_exit(usb_sisusb_exit);
+
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -0,0 +1,278 @@
+/*
+ * sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * 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.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_H_
+#define _SISUSB_H_
+
+#ifdef CONFIG_COMPAT
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
+#include <linux/ioctl32.h>
+#define SISUSB_OLD_CONFIG_COMPAT
+#else
+#define SISUSB_NEW_CONFIG_COMPAT
+#endif
+#endif
+
+/* Version Information */
+
+#define SISUSB_VERSION		0
+#define SISUSB_REVISION 	0
+#define SISUSB_PATCHLEVEL	7
+
+/* USB related */
+
+#define SISUSB_MINOR	133		/* FIXME */
+
+/* Size of the sisusb input/output buffers */
+#define SISUSB_IBUF_SIZE  0x01000
+#define SISUSB_OBUF_SIZE  0x10000	/* fixed */
+
+#define NUMOBUFS 8			/* max number of output buffers/output URBs */
+
+/* About endianness:
+ *
+ * 1) I/O ports, PCI config registers. The read/write()
+ *    calls emulate inX/outX. Hence, the data is
+ *    expected/delivered in machine endiannes by this
+ *    driver.
+ * 2) Video memory. The data is copied 1:1. There is
+ *    no swapping. Ever. This means for userland that
+ *    the data has to be prepared properly. (Hint:
+ *    think graphics data format, command queue,
+ *    hardware cursor.)
+ * 3) MMIO. Data is copied 1:1. MMIO must be swapped
+ *    properly by userland.
+ *
+ */
+
+#ifdef __BIG_ENDIAN
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) 		\
+	do {						\
+		p->header  = cpu_to_le16(p->header);	\
+		p->address = cpu_to_le32(p->address);	\
+		p->data    = cpu_to_le32(p->data);	\
+	} while(0)
+#else
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)
+#endif
+
+struct sisusb_usb_data;
+
+struct sisusb_urb_context {		/* urb->context for outbound bulk URBs */
+	struct sisusb_usb_data *sisusb;
+	int urbindex;
+	int *actual_length;
+};
+
+struct sisusb_usb_data {
+	struct usb_device *sisusb_dev;
+	struct usb_interface *interface;
+	struct kref kref;
+	wait_queue_head_t wait_q;	/* for syncind and timeouts */
+	struct semaphore lock;		/* general race avoidance */
+	unsigned int ifnum;		/* interface number of the USB device */
+	int minor;			/* minor (for logging clarity) */
+	int isopen;			/* !=0 if open */
+	int present;			/* !=0 if device is present on the bus */
+	int ready;			/* !=0 if device is ready for userland */
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+	int ioctl32registered;
+#endif
+	int numobufs;			/* number of obufs = number of out urbs */
+	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
+	int obufsize, ibufsize;
+	dma_addr_t transfer_dma_out[NUMOBUFS];
+	dma_addr_t transfer_dma_in;
+	struct urb *sisurbout[NUMOBUFS];
+	struct urb *sisurbin;
+	unsigned char urbstatus[NUMOBUFS];
+	unsigned char completein;
+	struct sisusb_urb_context urbout_context[NUMOBUFS];
+	unsigned long flagb0;
+	unsigned long vrambase;		/* framebuffer base */
+	unsigned int vramsize;		/* framebuffer size (bytes) */
+	unsigned long mmiobase;
+	unsigned int mmiosize;
+	unsigned long ioportbase;
+	unsigned char devinit;		/* device initialized? */
+	unsigned char gfxinit;		/* graphics core initialized? */
+	unsigned short chipid, chipvendor;
+	unsigned short chiprevision;
+};
+
+#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
+
+/* USB transport related */
+
+/* urbstatus */
+#define SU_URB_BUSY   1
+#define SU_URB_ALLOC  2
+
+/* Endpoints */
+
+#define SISUSB_EP_GFX_IN	0x0e	/* gfx std packet out(0e)/in(8e) */
+#define SISUSB_EP_GFX_OUT	0x0e
+
+#define SISUSB_EP_GFX_BULK_OUT	0x01	/* gfx mem bulk out/in */
+#define SISUSB_EP_GFX_BULK_IN	0x02	/* ? 2 is "OUT" ? */
+
+#define SISUSB_EP_GFX_LBULK_OUT	0x03	/* gfx large mem bulk out */
+
+#define SISUSB_EP_UNKNOWN_04	0x04	/* ? 4 is "OUT" ? - unused */
+
+#define SISUSB_EP_BRIDGE_IN	0x0d	/* Net2280 out(0d)/in(8d) */
+#define SISUSB_EP_BRIDGE_OUT	0x0d
+
+#define SISUSB_TYPE_MEM		0
+#define SISUSB_TYPE_IO		1
+
+struct sisusb_packet {
+	unsigned short header;
+	u32 address;
+	u32 data;
+} __attribute__((__packed__));
+
+#define CLEARPACKET(packet) memset(packet, 0, 10)
+
+/* PCI bridge related */
+
+#define SISUSB_PCI_MEMBASE	0xd0000000
+#define SISUSB_PCI_MMIOBASE	0xe4000000
+#define SISUSB_PCI_IOPORTBASE	0x0000d000
+
+#define SISUSB_PCI_PSEUDO_MEMBASE	0x10000000
+#define SISUSB_PCI_PSEUDO_MMIOBASE	0x20000000
+#define SISUSB_PCI_PSEUDO_IOPORTBASE	0x0000d000
+#define SISUSB_PCI_PSEUDO_PCIBASE	0x00010000
+
+#define SISUSB_PCI_MMIOSIZE	(128*1024)
+#define SISUSB_PCI_PCONFSIZE	0x5c
+
+/* graphics core related */
+
+#define AROFFSET	0x40
+#define ARROFFSET	0x41
+#define GROFFSET	0x4e
+#define SROFFSET	0x44
+#define CROFFSET	0x54
+#define MISCROFFSET	0x4c
+#define MISCWOFFSET	0x42
+#define INPUTSTATOFFSET 0x5A
+#define PART1OFFSET	0x04
+#define PART2OFFSET	0x10
+#define PART3OFFSET	0x12
+#define PART4OFFSET	0x14
+#define PART5OFFSET	0x16
+#define CAPTUREOFFSET	0x00
+#define VIDEOOFFSET	0x02
+#define COLREGOFFSET	0x48
+#define PELMASKOFFSET	0x46
+#define VGAENABLE	0x43
+
+#define SISAR		SISUSB_PCI_IOPORTBASE + AROFFSET
+#define SISARR		SISUSB_PCI_IOPORTBASE + ARROFFSET
+#define SISGR		SISUSB_PCI_IOPORTBASE + GROFFSET
+#define SISSR		SISUSB_PCI_IOPORTBASE + SROFFSET
+#define SISCR		SISUSB_PCI_IOPORTBASE + CROFFSET
+#define SISMISCR	SISUSB_PCI_IOPORTBASE + MISCROFFSET
+#define SISMISCW	SISUSB_PCI_IOPORTBASE + MISCWOFFSET
+#define SISINPSTAT	SISUSB_PCI_IOPORTBASE + INPUTSTATOFFSET
+#define SISPART1	SISUSB_PCI_IOPORTBASE + PART1OFFSET
+#define SISPART2	SISUSB_PCI_IOPORTBASE + PART2OFFSET
+#define SISPART3	SISUSB_PCI_IOPORTBASE + PART3OFFSET
+#define SISPART4	SISUSB_PCI_IOPORTBASE + PART4OFFSET
+#define SISPART5	SISUSB_PCI_IOPORTBASE + PART5OFFSET
+#define SISCAP		SISUSB_PCI_IOPORTBASE + CAPTUREOFFSET
+#define SISVID		SISUSB_PCI_IOPORTBASE + VIDEOOFFSET
+#define SISCOLIDXR	SISUSB_PCI_IOPORTBASE + COLREGOFFSET - 1
+#define SISCOLIDX	SISUSB_PCI_IOPORTBASE + COLREGOFFSET
+#define SISCOLDATA	SISUSB_PCI_IOPORTBASE + COLREGOFFSET + 1
+#define SISCOL2IDX	SISPART5
+#define SISCOL2DATA	SISPART5 + 1
+#define SISPEL		SISUSB_PCI_IOPORTBASE + PELMASKOFFSET
+#define SISVGAEN	SISUSB_PCI_IOPORTBASE + VGAENABLE
+#define SISDACA		SISCOLIDX
+#define SISDACD		SISCOLDATA
+
+/* ioctl related */
+
+/* Structure argument for SISUSB_GET_INFO ioctl  */
+struct sisusb_info {
+	__u32	sisusb_id;		/* for identifying sisusb */
+#define SISUSB_ID  0x53495355		/* Identify myself with 'SISU' */
+	__u8	sisusb_version;
+	__u8	sisusb_revision;
+	__u8	sisusb_patchlevel;
+	__u8	sisusb_gfxinit;		/* graphics core initialized? */
+
+	__u32	sisusb_vrambase;
+	__u32	sisusb_mmiobase;
+	__u32	sisusb_iobase;
+	__u32	sisusb_pcibase;
+
+	__u32	sisusb_vramsize;	/* framebuffer size in bytes */
+
+	__u32	sisusb_minor;
+
+	__u32   sisusb_fbdevactive;	/* != 0 if framebuffer device active */
+
+	__u8	sisusb_reserved[32];	/* for future use */
+};
+
+struct sisusb_command {
+	__u8   operation;	/* see below */
+	__u8   data0;		/* operation dependent */
+	__u8   data1;		/* operation dependent */
+	__u8   data2;		/* operation dependent */
+	__u32  data3;		/* operation dependent */
+	__u32  data4;		/* for future use */
+};
+
+#define SUCMD_GET      0x01	/* for all: data0 = index, data3 = port */
+#define SUCMD_SET      0x02	/* data1 = value */
+#define SUCMD_SETOR    0x03	/* data1 = or */
+#define SUCMD_SETAND   0x04	/* data1 = and */
+#define SUCMD_SETANDOR 0x05	/* data1 = and, data2 = or */
+#define SUCMD_SETMASK  0x06	/* data1 = data, data2 = mask */
+
+#define SUCMD_CLRSCR   0x07	/* data0:1:2 = length, data3 = address */
+
+#define SISUSB_COMMAND		_IOWR(0xF3,0x3D,struct sisusb_command)
+#define SISUSB_GET_CONFIG_SIZE 	_IOR(0xF3,0x3E,__u32)
+#define SISUSB_GET_CONFIG  	_IOR(0xF3,0x3F,struct sisusb_info)
+
+#endif /* SISUSB_H */
+
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -1,14 +1,16 @@
 /*****************************************************************************
  *                          USBLCD Kernel Driver                             *
- *        See http://www.usblcd.de for Hardware and Documentation.           *
- *                            Version 1.03                                   *
- *             (C) 2002 Adams IT Services <info@usblcd.de>                   *
+ *                            Version 1.05                                   *
+ *             (C) 2005 Georges Toth <g.toth@e-biz.lu>                       *
  *                                                                           *
  *     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)                        *
+ * Based on usb-skeleton.c 2.0 by Greg Kroah-Hartman (greg@kroah.com)        *
  *                                                                           *
- * 23.7.02 RA changed minor device number to the official assigned one       *
+ *                                                                           *
+ * 28.02.05 Complete rewrite of the original usblcd.c driver,                *
+ *          based on usb_skeleton.c.                                         *
+ *          This new driver allows more than one USB-LCD to be connected     *
+ *          and controlled, at once                                          *
  *****************************************************************************/
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -18,74 +20,130 @@
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
-#define DRIVER_VERSION "USBLCD Driver Version 1.04"
+#define DRIVER_VERSION "USBLCD Driver Version 1.05"
 
 #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
+static struct usb_device_id id_table [] = {
+	{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
+	{ },
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
 
-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 */
+struct usb_lcd {
+	struct usb_device *	udev;			/* init: probe_lcd */
+	struct usb_interface *  interface;		/* the interface for this device */
+	unsigned char *         bulk_in_buffer;		/* the buffer to receive data */
+	size_t			bulk_in_size;		/* the size of the receive buffer */
+	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
+	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
+	struct kref             kref;
 };
+#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
+
+static struct usb_driver lcd_driver;
+
+
+static void lcd_delete(struct kref *kref)
+{
+	struct usb_lcd *dev = to_lcd_dev(kref);
+
+	usb_put_dev(dev->udev);
+	kfree (dev->bulk_in_buffer);
+	kfree (dev);
+}
 
-static struct lcd_usb_data lcd_instance;
 
-static int open_lcd(struct inode *inode, struct file *file)
+static int lcd_open(struct inode *inode, struct file *file)
 {
-	struct lcd_usb_data *lcd = &lcd_instance;
+	struct usb_lcd *dev;
+	struct usb_interface *interface;
+	int subminor;
+	int retval = 0;
+
+	subminor = iminor(inode);
+
+	interface = usb_find_interface(&lcd_driver, subminor);
+	if (!interface) {
+		err ("USBLCD: %s - error, can't find device for minor %d",
+		     __FUNCTION__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
 
-	if (lcd->isopen || !lcd->present) {
-		return -EBUSY;
+	dev = usb_get_intfdata(interface);
+	if (!dev) {
+		retval = -ENODEV;
+		goto exit;
 	}
-	lcd->isopen = 1;
 
-	init_waitqueue_head(&lcd->wait_q);
+	/* increment our usage count for the device */
+	kref_get(&dev->kref);
 
-	info("USBLCD opened.");
+	/* save our object in the file's private structure */
+	file->private_data = dev;
 
-	return 0;
+exit:
+	return retval;
 }
 
-static int close_lcd(struct inode *inode, struct file *file)
+static int lcd_release(struct inode *inode, struct file *file)
 {
-	struct lcd_usb_data *lcd = &lcd_instance;
+	struct usb_lcd *dev;
 
-	lcd->isopen = 0;
+	dev = (struct usb_lcd *)file->private_data;
+	if (dev == NULL)
+		return -ENODEV;
 
-	info("USBLCD closed.");
+	/* decrement the count on our device */
+	kref_put(&dev->kref, lcd_delete);
 	return 0;
 }
 
-static int
-ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd,
-	  unsigned long arg)
+static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos)
 {
-	struct lcd_usb_data *lcd = &lcd_instance;
+	struct usb_lcd *dev;
+	int retval = 0;
+	int bytes_read;
+
+	dev = (struct usb_lcd *)file->private_data;
+
+	/* do a blocking bulk read to get data from the device */
+	retval = usb_bulk_msg(dev->udev, 
+			      usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+			      dev->bulk_in_buffer,
+			      min(dev->bulk_in_size, count),
+			      &bytes_read, 10000);
+
+	/* if the read was successful, copy the data to userspace */
+	if (!retval) {
+		if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
+			retval = -EFAULT;
+		else
+			retval = bytes_read;
+	}
+
+	return retval;
+}
+
+static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_lcd *dev;
 	u16 bcdDevice;
 	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;
-
+	dev = (struct usb_lcd *)file->private_data;
+	if (dev == NULL)
+		return -ENODEV;
+	
 	switch (cmd) {
 	case IOCTL_GET_HARD_VERSION:
-		bcdDevice = le16_to_cpu((lcd->lcd_dev)->descriptor.bcdDevice);
+		bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
 		sprintf(buf,"%1d%1d.%1d%1d",
 			(bcdDevice & 0xF000)>>12,
 			(bcdDevice & 0xF00)>>8,
@@ -107,269 +165,240 @@ ioctl_lcd(struct inode *inode, struct fi
 	return 0;
 }
 
-static ssize_t
-write_lcd(struct file *file, const char __user *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;
-			}
+static void lcd_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_lcd *dev;
 
-			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 == -ETIMEDOUT) {	/* 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);
+	dev = (struct usb_lcd *)urb->context;
+
+	/* sync/async unlink faults aren't errors */
+	if (urb->status &&
+	    !(urb->status == -ENOENT ||
+	      urb->status == -ECONNRESET ||
+              urb->status == -ESHUTDOWN)) {
+		dbg("USBLCD: %s - nonzero write bulk status received: %d",
+		    __FUNCTION__, urb->status);
+	}
 
-	return bytes_written ? bytes_written : -EIO;
+	/* free up our allocated buffer */
+	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+			urb->transfer_buffer, urb->transfer_dma);
 }
 
-static ssize_t
-read_lcd(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
+static ssize_t lcd_write(struct file *file, const char __user * user_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 == -ETIMEDOUT || 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 != -EREMOTEIO) {
-			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;
-		}
+	struct usb_lcd *dev;
+        int retval = 0;
+	struct urb *urb = NULL;
+	char *buf = NULL;
+	
+	dev = (struct usb_lcd *)file->private_data;
+	
+	/* verify that we actually have some data to write */
+	if (count == 0)
+		goto exit;
+
+	/* create a urb, and a buffer for it, and copy the data to the urb */
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	
+	buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
+	if (!buf) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	
+	if (copy_from_user(buf, user_buffer, count)) {
+		retval = -EFAULT;
+		goto error;
 	}
-	return read_count;
+	
+	/* initialize the urb properly */
+	usb_fill_bulk_urb(urb, dev->udev,
+			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+			  buf, count, lcd_write_bulk_callback, dev);
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	
+	/* send the data out the bulk port */
+	retval = usb_submit_urb(urb, GFP_KERNEL);
+	if (retval) {
+		err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
+		goto error;
+	}
+	
+	/* release our reference to this urb, the USB core will eventually free it entirely */
+	usb_free_urb(urb);
+
+exit:
+	return count;
+
+error:
+	usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
+	usb_free_urb(urb);
+	return retval;
 }
 
-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 file_operations lcd_fops = {
+        .owner =        THIS_MODULE,
+        .read =         lcd_read,
+        .write =        lcd_write,
+        .open =         lcd_open,
+	.ioctl =        lcd_ioctl,
+        .release =      lcd_release,
 };
 
-static struct usb_class_driver usb_lcd_class = {
-	.name =		"usb/lcd%d",
-	.fops =		&usb_lcd_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-	.minor_base =	USBLCD_MINOR,
+/*
+ *  * usb class driver info in order to get a minor number from the usb core,
+ *   * and to have the device registered with devfs and the driver core
+ *    */
+static struct usb_class_driver lcd_class = {
+        .name =         "usb/lcd%d",
+        .fops =         &lcd_fops,
+        .mode =         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
+        .minor_base =   USBLCD_MINOR,
 };
 
-static int probe_lcd(struct usb_interface *intf, const struct usb_device_id *id)
+static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id)
 {
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct lcd_usb_data *lcd = &lcd_instance;
+	struct usb_lcd *dev = NULL;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	size_t buffer_size;
 	int i;
-	int retval;
+	int retval = -ENOMEM;
 
-	if (le16_to_cpu(dev->descriptor.idProduct) != 0x0001) {
-		warn(KERN_INFO "USBLCD model not supported.");
-		return -ENODEV;
+	/* allocate memory for our device state and initialize it */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		err("Out of memory");
+		goto error;
 	}
+	memset(dev, 0x00, sizeof(*dev));
+	kref_init(&dev->kref);
+
+	dev->udev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
 
-	if (lcd->present == 1) {
-		warn(KERN_INFO "Multiple USBLCDs are not supported!");
+	if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
+		warn(KERN_INFO "USBLCD model not supported.");
 		return -ENODEV;
 	}
+	
+	/* set up the endpoint information */
+	/* use only the first bulk-in and bulk-out endpoints */
+	iface_desc = interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!dev->bulk_in_endpointAddr &&
+		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+					== USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk in endpoint */
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			dev->bulk_in_size = buffer_size;
+			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+			dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+			if (!dev->bulk_in_buffer) {
+				err("Could not allocate bulk_in_buffer");
+				goto error;
+			}
+		}
 
-	i = le16_to_cpu(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 -ENOMEM;
+		if (!dev->bulk_out_endpointAddr &&
+		    !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+					== USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk out endpoint */
+			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+		}
 	}
-	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 -ENOMEM;
+	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+		err("Could not find both bulk-in and bulk-out endpoints");
+		goto error;
 	}
-	dbg("probe_lcd: ibuf address:%p", lcd->ibuf);
 
-	retval = usb_register_dev(intf, &usb_lcd_class);
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	/* we can register the device now, as it is ready */
+	retval = usb_register_dev(interface, &lcd_class);
 	if (retval) {
+		/* something prevented us from registering this driver */
 		err("Not able to get a minor for this device.");
-		kfree(lcd->obuf);
-		kfree(lcd->ibuf);
-		return -ENOMEM;
+		usb_set_intfdata(interface, NULL);
+		goto error;
 	}
 
-	usb_set_intfdata (intf, lcd);
+	i = le16_to_cpu(dev->udev->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->udev->devnum);
+
+	/* let the user know what node this device is now attached to */
+	info("USB LCD device now attached to USBLCD-%d", interface->minor);
 	return 0;
+
+error:
+	if (dev)
+		kref_put(&dev->kref, lcd_delete);
+	return retval;
 }
 
-static void disconnect_lcd(struct usb_interface *intf)
+static void lcd_disconnect(struct usb_interface *interface)
 {
-	struct lcd_usb_data *lcd = usb_get_intfdata (intf);
+	struct usb_lcd *dev;
+        int minor = interface->minor;
 
-	usb_set_intfdata (intf, NULL);
-	if (lcd) {
-		usb_deregister_dev(intf, &usb_lcd_class);
-
-		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);
+        /* prevent skel_open() from racing skel_disconnect() */
+        lock_kernel();
 
-		info("USBLCD disconnected.");
+        dev = usb_get_intfdata(interface);
+        usb_set_intfdata(interface, NULL);
 
-		lcd->present = 0;
-	}
-}
+        /* give back our minor */
+        usb_deregister_dev(interface, &lcd_class);
+ 
+	unlock_kernel();
 
-static struct usb_device_id id_table [] = {
-	{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
-	{},
-};
+	/* decrement our usage count */
+	kref_put(&dev->kref, lcd_delete);
 
-MODULE_DEVICE_TABLE (usb, id_table);
+	info("USB LCD #%d now disconnected", minor);
+}
 
 static struct usb_driver lcd_driver = {
 	.owner =	THIS_MODULE,
 	.name =		"usblcd",
-	.probe =	(void *)probe_lcd,
-	.disconnect =	disconnect_lcd,
+	.probe =	lcd_probe,
+	.disconnect =	lcd_disconnect,
 	.id_table =	id_table,
 };
 
 static int __init usb_lcd_init(void)
 {
-	int retval;
-	retval = usb_register(&lcd_driver);
-	if (retval)
-		goto out;
-
-	info("%s (C) Adams IT Services http://www.usblcd.de", DRIVER_VERSION);
-	info("USBLCD support registered.");
-out:
-	return retval;
+	int result;
+	
+	result = usb_register(&lcd_driver);
+	if (result)
+		err("usb_register failed. Error number %d", result);
+
+	return result;
 }
 
 
-static void __exit usb_lcd_cleanup(void)
+static void __exit usb_lcd_exit(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_exit(usb_lcd_exit);
 
-MODULE_AUTHOR("Adams IT Services <info@usblcd.de>");
+MODULE_AUTHOR("Georges Toth <g.toth@e-biz.lu>");
 MODULE_DESCRIPTION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -74,7 +74,7 @@ static void change_color(struct usb_led 
 				(0x00 * 0x100) + color,
 				buffer,	
 				8,
-				2 * HZ);
+				2000);
 	if (retval)
 		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
 	kfree(buffer);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -472,7 +472,7 @@ static int get_altsetting (struct usbtes
 	retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
 			USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE,
 			0, iface->altsetting [0].desc.bInterfaceNumber,
-			dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+			dev->buf, 1, USB_CTRL_GET_TIMEOUT);
 	switch (retval) {
 	case 1:
 		return dev->buf [0];
@@ -602,7 +602,7 @@ static int ch9_postconfig (struct usbtes
 		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
 				USB_REQ_GET_CONFIGURATION,
 				USB_DIR_IN | USB_RECIP_DEVICE,
-				0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+				0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
 		if (retval != 1 || dev->buf [0] != expected) {
 			dev_dbg (&iface->dev,
 				"get config --> %d (%d)\n", retval,
@@ -851,7 +851,7 @@ test_ctrl_queue (struct usbtest_dev *dev
 	 */
 	urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL);
 	if (!urb)
-		goto cleanup;
+		return -ENOMEM;
 	memset (urb, 0, param->sglen * sizeof (struct urb *));
 	for (i = 0; i < param->sglen; i++) {
 		int			pipe = usb_rcvctrlpipe (udev, 0);
@@ -1173,7 +1173,7 @@ static int test_halt (int ep, struct urb
 	retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0),
 			USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
 			USB_ENDPOINT_HALT, ep,
-			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval < 0) {
 		dbg ("ep %02x couldn't set halt, %d", ep, retval);
 		return retval;
@@ -1263,7 +1263,7 @@ static int ctrl_out (struct usbtest_dev 
 			buf [j] = i + j;
 		retval = usb_control_msg (udev, usb_sndctrlpipe (udev,0),
 				0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
-				0, 0, buf, len, HZ * USB_CTRL_SET_TIMEOUT);
+				0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
 		if (retval != len) {
 			what = "write";
 			break;
@@ -1272,7 +1272,7 @@ static int ctrl_out (struct usbtest_dev 
 		/* read it back -- assuming nothing intervened!!  */
 		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev,0),
 				0x5c, USB_DIR_IN|USB_TYPE_VENDOR,
-				0, 0, buf, len, HZ * USB_CTRL_GET_TIMEOUT);
+				0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
 		if (retval != len) {
 			what = "read";
 			break;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -75,7 +75,7 @@ static int get_1284_register(struct parp
 
 	if (!usbdev)
 		return -1;
-	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, HZ);
+	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000);
 	if (ret != 7) {
 		printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n",
 		       (unsigned int)reg, ret);
@@ -105,7 +105,7 @@ static int set_1284_register(struct parp
 
 	if (!usbdev)
 		return -1;
-	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, HZ);
+	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000);
 	if (ret) {
 		printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
 		       (unsigned int)reg, (unsigned int)val, ret);
@@ -374,7 +374,7 @@ static size_t parport_uss720_epp_write_d
 		return 0;
 	if (change_mode(pp, ECR_EPP))
 		return 0;
-	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, HZ*20);
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buf, length, rlen);
 	change_mode(pp, ECR_PS2);
@@ -435,7 +435,7 @@ static size_t parport_uss720_ecp_write_d
 		return 0;
 	if (change_mode(pp, ECR_ECP))
 		return 0;
-	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
@@ -453,7 +453,7 @@ static size_t parport_uss720_ecp_read_da
 		return 0;
 	if (change_mode(pp, ECR_ECP))
 		return 0;
-	i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20);
+	i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000);
 	if (i)
 		printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
@@ -486,7 +486,7 @@ static size_t parport_uss720_write_compa
 		return 0;
 	if (change_mode(pp, ECR_PPF))
 		return 0;
-	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/Kconfig
@@ -0,0 +1,22 @@
+#
+# USB Monitor configuration
+#
+
+# In normal life, it makes little sense to have usbmon as a module, and in fact
+# it is harmful, because there is no way to autoload the module.
+# The 'm' option is allowed for hackers who debug the usbmon itself,
+# and for those who have usbcore as a module.
+config USB_MON
+	tristate "USB Monitor"
+	depends on USB
+	default y
+	help
+	  If you say Y here, a component which captures the USB traffic
+	  between peripheral-specific drivers and HC drivers will be built.
+	  The USB_MON is similar in spirit and may be compatible with Dave
+	  Harding's USBMon.
+
+	  This is somewhat experimental at this time, but it should be safe,
+	  as long as you aren't building this as a module and then removing it.
+
+	  If unsure, say Y. Do not say M.
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for USB Core files and filesystem
+#
+
+usbmon-objs	:= mon_main.o mon_stat.o mon_text.o
+
+obj-$(CONFIG_USB_MON)	+= usbmon.o
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/mon_main.c
@@ -0,0 +1,377 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * mon_main.c: Main file, module initiation and exit, registrations, etc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/smp_lock.h>
+
+#include "usb_mon.h"
+#include "../core/hcd.h"
+
+static void mon_submit(struct usb_bus *ubus, struct urb *urb);
+static void mon_complete(struct usb_bus *ubus, struct urb *urb);
+static void mon_stop(struct mon_bus *mbus);
+static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
+static void mon_bus_drop(struct kref *r);
+static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+
+DECLARE_MUTEX(mon_lock);
+
+static struct dentry *mon_dir;		/* /dbg/usbmon */
+static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
+
+/*
+ * Link a reader into the bus.
+ *
+ * This must be called with mon_lock taken because of mbus->ref.
+ */
+void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
+{
+	unsigned long flags;
+	struct usb_bus *ubus;
+
+	spin_lock_irqsave(&mbus->lock, flags);
+	if (mbus->nreaders == 0) {
+		ubus = mbus->u_bus;
+		if (ubus->monitored) {
+			/*
+			 * Something is really broken, refuse to go on and
+			 * possibly corrupt ops pointers or worse.
+			 */
+			printk(KERN_ERR TAG ": bus %d is already monitored\n",
+			    ubus->busnum);
+			spin_unlock_irqrestore(&mbus->lock, flags);
+			return;
+		}
+		ubus->monitored = 1;
+	}
+	mbus->nreaders++;
+	list_add_tail(&r->r_link, &mbus->r_list);
+	spin_unlock_irqrestore(&mbus->lock, flags);
+
+	kref_get(&mbus->ref);
+}
+
+/*
+ * Unlink reader from the bus.
+ *
+ * This is called with mon_lock taken, so we can decrement mbus->ref.
+ */
+void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mbus->lock, flags);
+	list_del(&r->r_link);
+	--mbus->nreaders;
+	if (mbus->nreaders == 0)
+		mon_stop(mbus);
+	spin_unlock_irqrestore(&mbus->lock, flags);
+
+	kref_put(&mbus->ref, mon_bus_drop);
+}
+
+/*
+ */
+static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+{
+	struct mon_bus *mbus;
+	unsigned long flags;
+	struct list_head *pos;
+	struct mon_reader *r;
+
+	mbus = ubus->mon_bus;
+	if (mbus == NULL)
+		goto out_unlocked;
+
+	spin_lock_irqsave(&mbus->lock, flags);
+	if (mbus->nreaders == 0)
+		goto out_locked;
+
+	list_for_each (pos, &mbus->r_list) {
+		r = list_entry(pos, struct mon_reader, r_link);
+		r->rnf_submit(r->r_data, urb);
+	}
+
+	spin_unlock_irqrestore(&mbus->lock, flags);
+	return;
+
+out_locked:
+	spin_unlock_irqrestore(&mbus->lock, flags);
+out_unlocked:
+	return;
+}
+
+/*
+ */
+static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err)
+{
+	struct mon_bus *mbus;
+
+	mbus = ubus->mon_bus;
+	if (mbus == NULL)
+		goto out_unlocked;
+
+	/*
+	 * XXX Capture the error code and the 'E' event.
+	 */
+
+	return;
+
+out_unlocked:
+	return;
+}
+
+/*
+ */
+static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+{
+	struct mon_bus *mbus;
+	unsigned long flags;
+	struct list_head *pos;
+	struct mon_reader *r;
+
+	mbus = ubus->mon_bus;
+	if (mbus == NULL) {
+		/*
+		 * This should not happen.
+		 * At this point we do not even know the bus number...
+		 */
+		printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
+		    urb->pipe);
+		return;
+	}
+
+	spin_lock_irqsave(&mbus->lock, flags);
+	list_for_each (pos, &mbus->r_list) {
+		r = list_entry(pos, struct mon_reader, r_link);
+		r->rnf_complete(r->r_data, urb);
+	}
+	spin_unlock_irqrestore(&mbus->lock, flags);
+}
+
+/* int (*unlink_urb) (struct urb *urb, int status); */
+
+/*
+ * Stop monitoring.
+ * Obviously this must be well locked, so no need to play with mb's.
+ */
+static void mon_stop(struct mon_bus *mbus)
+{
+	struct usb_bus *ubus = mbus->u_bus;
+
+	/*
+	 * A stop can be called for a dissolved mon_bus in case of
+	 * a reader staying across an rmmod foo_hcd.
+	 */
+	if (ubus != NULL) {
+		ubus->monitored = 0;
+		mb();
+	}
+}
+
+/*
+ * Add a USB bus (usually by a modprobe foo-hcd)
+ *
+ * This does not return an error code because the core cannot care less
+ * if monitoring is not established.
+ */
+static void mon_bus_add(struct usb_bus *ubus)
+{
+	mon_bus_init(mon_dir, ubus);
+}
+
+/*
+ * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
+ */
+static void mon_bus_remove(struct usb_bus *ubus)
+{
+	struct mon_bus *mbus = ubus->mon_bus;
+
+	down(&mon_lock);
+	list_del(&mbus->bus_link);
+	debugfs_remove(mbus->dent_t);
+	debugfs_remove(mbus->dent_s);
+
+	mon_dissolve(mbus, ubus);
+	kref_put(&mbus->ref, mon_bus_drop);
+	up(&mon_lock);
+}
+
+/*
+ * Ops
+ */
+static struct usb_mon_operations mon_ops_0 = {
+	.urb_submit =	mon_submit,
+	.urb_submit_error = mon_submit_error,
+	.urb_complete =	mon_complete,
+	.bus_add =	mon_bus_add,
+	.bus_remove =	mon_bus_remove,
+};
+
+/*
+ * Tear usb_bus and mon_bus apart.
+ */
+static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
+{
+
+	/*
+	 * Never happens, but...
+	 */
+	if (ubus->monitored) {
+		printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
+		    ubus->busnum);
+		ubus->monitored = 0;
+		mb();
+	}
+
+	ubus->mon_bus = NULL;
+	mbus->u_bus = NULL;
+	mb();
+	// usb_bus_put(ubus);
+}
+
+/*
+ */
+static void mon_bus_drop(struct kref *r)
+{
+	struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
+	kfree(mbus);
+}
+
+/*
+ * Initialize a bus for us:
+ *  - allocate mon_bus
+ *  - refcount USB bus struct
+ *  - link
+ */
+static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+{
+	struct dentry *d;
+	struct mon_bus *mbus;
+	enum { NAMESZ = 10 };
+	char name[NAMESZ];
+	int rc;
+
+	if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+		goto err_alloc;
+	memset(mbus, 0, sizeof(struct mon_bus));
+	kref_init(&mbus->ref);
+	spin_lock_init(&mbus->lock);
+	INIT_LIST_HEAD(&mbus->r_list);
+
+	/*
+	 * This usb_bus_get here is superfluous, because we receive
+	 * a notification if usb_bus is about to be removed.
+	 */
+	// usb_bus_get(ubus);
+	mbus->u_bus = ubus;
+	ubus->mon_bus = mbus;
+
+	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_t;
+	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
+	if (d == NULL)
+		goto err_create_t;
+	mbus->dent_t = d;
+
+	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_s;
+	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
+	if (d == NULL)
+		goto err_create_s;
+	mbus->dent_s = d;
+
+	down(&mon_lock);
+	list_add_tail(&mbus->bus_link, &mon_buses);
+	up(&mon_lock);
+	return;
+
+err_create_s:
+err_print_s:
+	debugfs_remove(mbus->dent_t);
+err_create_t:
+err_print_t:
+	kfree(mbus);
+err_alloc:
+	return;
+}
+
+static int __init mon_init(void)
+{
+	struct usb_bus *ubus;
+	struct dentry *mondir;
+
+	mondir = debugfs_create_dir("usbmon", NULL);
+	if (IS_ERR(mondir)) {
+		printk(KERN_NOTICE TAG ": debugs is not available\n");
+		return -ENODEV;
+	}
+	if (mondir == NULL) {
+		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+		return -ENODEV;
+	}
+	mon_dir = mondir;
+
+	if (usb_mon_register(&mon_ops_0) != 0) {
+		printk(KERN_NOTICE TAG ": unable to register with the core\n");
+		debugfs_remove(mondir);
+		return -ENODEV;
+	}
+	// MOD_INC_USE_COUNT(which_module?);
+
+	down(&usb_bus_list_lock);
+	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
+		mon_bus_init(mondir, ubus);
+	}
+	up(&usb_bus_list_lock);
+	return 0;
+}
+
+static void __exit mon_exit(void)
+{
+	struct mon_bus *mbus;
+	struct list_head *p;
+
+	usb_mon_deregister();
+
+	down(&mon_lock);
+	while (!list_empty(&mon_buses)) {
+		p = mon_buses.next;
+		mbus = list_entry(p, struct mon_bus, bus_link);
+		list_del(p);
+
+		debugfs_remove(mbus->dent_t);
+		debugfs_remove(mbus->dent_s);
+
+		/*
+		 * This never happens, because the open/close paths in
+		 * file level maintain module use counters and so rmmod fails
+		 * before reaching here. However, better be safe...
+		 */
+		if (mbus->nreaders) {
+			printk(KERN_ERR TAG
+			    ": Outstanding opens (%d) on usb%d, leaking...\n",
+			    mbus->nreaders, mbus->u_bus->busnum);
+			atomic_set(&mbus->ref.refcount, 2);	/* Force leak */
+		}
+
+		mon_dissolve(mbus, mbus->u_bus);
+		kref_put(&mbus->ref, mon_bus_drop);
+	}
+	up(&mon_lock);
+
+	debugfs_remove(mon_dir);
+}
+
+module_init(mon_init);
+module_exit(mon_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/mon_stat.c
@@ -0,0 +1,74 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is the 's' or 'stat' reader which debugs usbmon itself.
+ * Note that this code blows through locks, so make sure that
+ * /dbg/usbmon/0s is well protected from non-root users.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+#define STAT_BUF_SIZE  80
+
+struct snap {
+	int slen;
+	char str[STAT_BUF_SIZE];
+};
+
+static int mon_stat_open(struct inode *inode, struct file *file)
+{
+	struct mon_bus *mbus;
+	struct snap *sp;
+
+	if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	mbus = inode->u.generic_ip;
+
+	sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
+	    "nreaders %d text_lost %u\n",
+	    mbus->nreaders, mbus->cnt_text_lost);
+
+	file->private_data = sp;
+	return 0;
+}
+
+static ssize_t mon_stat_read(struct file *file, char __user *buf,
+				size_t nbytes, loff_t *ppos)
+{
+	struct snap *sp = file->private_data;
+	loff_t pos = *ppos;
+	int cnt;
+
+	if (pos < 0 || pos >= sp->slen)
+		return 0;
+	if (nbytes == 0)
+		return 0;
+	if ((cnt = sp->slen - pos) > nbytes)
+		cnt = nbytes;
+	if (copy_to_user(buf, sp->str + pos, cnt))
+		return -EFAULT;
+	*ppos = pos + cnt;
+	return cnt;
+}
+
+static int mon_stat_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+struct file_operations mon_fops_stat = {
+	.owner =	THIS_MODULE,
+	.open =		mon_stat_open,
+	.llseek =	no_llseek,
+	.read =		mon_stat_read,
+	/* .write =	mon_stat_write, */
+	/* .poll =		mon_stat_poll, */
+	/* .ioctl =	mon_stat_ioctl, */
+	.release =	mon_stat_release,
+};
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/mon_text.c
@@ -0,0 +1,405 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a text format reader.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * No, we do not want arbitrarily long data strings.
+ * Use the binary interface if you want to capture bulk data!
+ */
+#define DATA_MAX  32
+
+/*
+ * This limit exists to prevent OOMs when the user process stops reading.
+ */
+#define EVENT_MAX  25
+
+#define PRINTF_DFL  120
+
+struct mon_event_text {
+	struct list_head e_link;
+	int type;		/* submit, complete, etc. */
+	unsigned int pipe;	/* Pipe */
+	unsigned long id;	/* From pointer, most of the time */
+	unsigned int tstamp;
+	int length;		/* Depends on type: xfer length or act length */
+	int status;
+	char data_flag;
+	unsigned char data[DATA_MAX];
+};
+
+#define SLAB_NAME_SZ  30
+struct mon_reader_text {
+	kmem_cache_t *e_slab;
+	int nevents;
+	struct list_head e_list;
+	struct mon_reader r;	/* In C, parent class can be placed anywhere */
+
+	wait_queue_head_t wait;
+	int printf_size;
+	char *printf_buf;
+	struct semaphore printf_lock;
+
+	char slab_name[SLAB_NAME_SZ];
+};
+
+static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
+static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
+
+/*
+ * mon_text_submit
+ * mon_text_complete
+ *
+ * May be called from an interrupt.
+ *
+ * This is called with the whole mon_bus locked, so no additional lock.
+ */
+
+static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
+    int len, char ev_type)
+{
+	int pipe = urb->pipe;
+	unsigned char *data;
+
+	/*
+	 * The check to see if it's safe to poke at data has an enormous
+	 * number of corner cases, but it seems that the following is
+	 * more or less safe.
+	 *
+	 * We do not even try to look transfer_buffer, because it can
+	 * contain non-NULL garbage in case the upper level promised to
+	 * set DMA for the HCD.
+	 */
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+		return 'D';
+
+	if (len <= 0)
+		return 'L';
+
+	if ((data = urb->transfer_buffer) == NULL)
+		return 'Z';	/* '0' would be not as pretty. */
+
+	/*
+	 * Bulk is easy to shortcut reliably. 
+	 * XXX Control needs setup packet taken.
+	 * XXX Other pipe types need consideration. Currently, we overdo it
+	 * and collect garbage for them: better more than less.
+	 */
+	if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) {
+		if (usb_pipein(pipe)) {
+			if (ev_type == 'S')
+				return '<';
+		} else {
+			if (ev_type == 'C')
+				return '>';
+		}
+	}
+
+	if (len >= DATA_MAX)
+		len = DATA_MAX;
+	memcpy(ep->data, urb->transfer_buffer, len);
+	return 0;
+}
+
+static inline unsigned int mon_get_timestamp(void)
+{
+	struct timeval tval;
+	unsigned int stamp;
+
+	do_gettimeofday(&tval);
+	stamp = tval.tv_sec & 0xFFFF;	/* 2^32 = 4294967296. Limit to 4096s. */
+	stamp = stamp * 1000000 + tval.tv_usec;
+	return stamp;
+}
+
+static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
+    char ev_type)
+{
+	struct mon_event_text *ep;
+	unsigned int stamp;
+
+	stamp = mon_get_timestamp();
+
+	if (rp->nevents >= EVENT_MAX ||
+	    (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) {
+		rp->r.m_bus->cnt_text_lost++;
+		return;
+	}
+
+	ep->type = ev_type;
+	ep->pipe = urb->pipe;
+	ep->id = (unsigned long) urb;
+	ep->tstamp = stamp;
+	ep->length = (ev_type == 'S') ?
+	    urb->transfer_buffer_length : urb->actual_length;
+	/* Collecting status makes debugging sense for submits, too */
+	ep->status = urb->status;
+
+	ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
+
+	rp->nevents++;
+	list_add_tail(&ep->e_link, &rp->e_list);
+	wake_up(&rp->wait);
+}
+
+static void mon_text_submit(void *data, struct urb *urb)
+{
+	struct mon_reader_text *rp = data;
+	mon_text_event(rp, urb, 'S');
+}
+
+static void mon_text_complete(void *data, struct urb *urb)
+{
+	struct mon_reader_text *rp = data;
+	mon_text_event(rp, urb, 'C');
+}
+
+/*
+ * Fetch next event from the circular buffer.
+ */
+static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp,
+    struct mon_bus *mbus)
+{
+	struct list_head *p;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mbus->lock, flags);
+	if (list_empty(&rp->e_list)) {
+		spin_unlock_irqrestore(&mbus->lock, flags);
+		return NULL;
+	}
+	p = rp->e_list.next;
+	list_del(p);
+	--rp->nevents;
+	spin_unlock_irqrestore(&mbus->lock, flags);
+	return list_entry(p, struct mon_event_text, e_link);
+}
+
+/*
+ */
+static int mon_text_open(struct inode *inode, struct file *file)
+{
+	struct mon_bus *mbus;
+	struct usb_bus *ubus;
+	struct mon_reader_text *rp;
+	int rc;
+
+	down(&mon_lock);
+	mbus = inode->u.generic_ip;
+	ubus = mbus->u_bus;
+
+	rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+	if (rp == NULL) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	memset(rp, 0, sizeof(struct mon_reader_text));
+	INIT_LIST_HEAD(&rp->e_list);
+	init_waitqueue_head(&rp->wait);
+	init_MUTEX(&rp->printf_lock);
+
+	rp->printf_size = PRINTF_DFL;
+	rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
+	if (rp->printf_buf == NULL) {
+		rc = -ENOMEM;
+		goto err_alloc_pr;
+	}
+
+	rp->r.m_bus = mbus;
+	rp->r.r_data = rp;
+	rp->r.rnf_submit = mon_text_submit;
+	rp->r.rnf_complete = mon_text_complete;
+
+	snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
+	    (long)rp);
+	rp->e_slab = kmem_cache_create(rp->slab_name,
+	    sizeof(struct mon_event_text), sizeof(long), 0,
+	    mon_text_ctor, mon_text_dtor);
+	if (rp->e_slab == NULL) {
+		rc = -ENOMEM;
+		goto err_slab;
+	}
+
+	mon_reader_add(mbus, &rp->r);
+
+	file->private_data = rp;
+	up(&mon_lock);
+	return 0;
+
+// err_busy:
+//	kmem_cache_destroy(rp->e_slab);
+err_slab:
+	kfree(rp->printf_buf);
+err_alloc_pr:
+	kfree(rp);
+err_alloc:
+	up(&mon_lock);
+	return rc;
+}
+
+/*
+ * For simplicity, we read one record in one system call and throw out
+ * what does not fit. This means that the following does not work:
+ *   dd if=/dbg/usbmon/0t bs=10
+ * Also, we do not allow seeks and do not bother advancing the offset.
+ */
+static ssize_t mon_text_read(struct file *file, char __user *buf,
+				size_t nbytes, loff_t *ppos)
+{
+	struct mon_reader_text *rp = file->private_data;
+	struct mon_bus *mbus = rp->r.m_bus;
+	DECLARE_WAITQUEUE(waita, current);
+	struct mon_event_text *ep;
+	int cnt, limit;
+	char *pbuf;
+	char udir, utype;
+	int data_len, i;
+
+	add_wait_queue(&rp->wait, &waita);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while ((ep = mon_text_fetch(rp, mbus)) == NULL) {
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&rp->wait, &waita);
+			return -EWOULDBLOCK;	/* Same as EAGAIN in Linux */
+		}
+		/*
+		 * We do not count nwaiters, because ->release is supposed
+		 * to be called when all openers are gone only.
+		 */
+		schedule();
+		if (signal_pending(current)) {
+			remove_wait_queue(&rp->wait, &waita);
+			return -EINTR;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rp->wait, &waita);
+
+	down(&rp->printf_lock);
+	cnt = 0;
+	pbuf = rp->printf_buf;
+	limit = rp->printf_size;
+
+	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
+	switch (usb_pipetype(ep->pipe)) {
+	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
+	case PIPE_INTERRUPT:	utype = 'I'; break;
+	case PIPE_CONTROL:	utype = 'C'; break;
+	default: /* PIPE_BULK */  utype = 'B';
+	}
+	cnt += snprintf(pbuf + cnt, limit - cnt,
+	    "%lx %u %c %c%c:%03u:%02u %d %d",
+	    ep->id, ep->tstamp, ep->type,
+	    utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe),
+	    ep->status, ep->length);
+
+	if ((data_len = ep->length) > 0) {
+		if (ep->data_flag == 0) {
+			cnt += snprintf(pbuf + cnt, limit - cnt, " =");
+			if (data_len >= DATA_MAX)
+				data_len = DATA_MAX;
+			for (i = 0; i < data_len; i++) {
+				if (i % 4 == 0) {
+					cnt += snprintf(pbuf + cnt, limit - cnt,
+					    " ");
+				}
+				cnt += snprintf(pbuf + cnt, limit - cnt,
+				    "%02x", ep->data[i]);
+			}
+			cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+		} else {
+			cnt += snprintf(pbuf + cnt, limit - cnt,
+			    " %c\n", ep->data_flag);
+		}
+	} else {
+		cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+	}
+
+	if (copy_to_user(buf, rp->printf_buf, cnt))
+		cnt = -EFAULT;
+	up(&rp->printf_lock);
+	kmem_cache_free(rp->e_slab, ep);
+	return cnt;
+}
+
+static int mon_text_release(struct inode *inode, struct file *file)
+{
+	struct mon_reader_text *rp = file->private_data;
+	struct mon_bus *mbus;
+	/* unsigned long flags; */
+	struct list_head *p;
+	struct mon_event_text *ep;
+
+	down(&mon_lock);
+	mbus = inode->u.generic_ip;
+
+	if (mbus->nreaders <= 0) {
+		printk(KERN_ERR TAG ": consistency error on close\n");
+		up(&mon_lock);
+		return 0;
+	}
+	mon_reader_del(mbus, &rp->r);
+
+	/*
+	 * In theory, e_list is protected by mbus->lock. However,
+	 * after mon_reader_del has finished, the following is the case:
+	 *  - we are not on reader list anymore, so new events won't be added;
+	 *  - whole mbus may be dropped if it was orphaned.
+	 * So, we better not touch mbus.
+	 */
+	/* spin_lock_irqsave(&mbus->lock, flags); */
+	while (!list_empty(&rp->e_list)) {
+		p = rp->e_list.next;
+		ep = list_entry(p, struct mon_event_text, e_link);
+		list_del(p);
+		--rp->nevents;
+		kmem_cache_free(rp->e_slab, ep);
+	}
+	/* spin_unlock_irqrestore(&mbus->lock, flags); */
+
+	kmem_cache_destroy(rp->e_slab);
+	kfree(rp->printf_buf);
+	kfree(rp);
+
+	up(&mon_lock);
+	return 0;
+}
+
+struct file_operations mon_fops_text = {
+	.owner =	THIS_MODULE,
+	.open =		mon_text_open,
+	.llseek =	no_llseek,
+	.read =		mon_text_read,
+	/* .write =	mon_text_write, */
+	/* .poll =		mon_text_poll, */
+	/* .ioctl =	mon_text_ioctl, */
+	.release =	mon_text_release,
+};
+
+/*
+ * Slab interface: constructor.
+ */
+static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags)
+{
+	/*
+	 * Nothing to initialize. No, really!
+	 * So, we fill it with garbage to emulate a reused object.
+	 */
+	memset(mem, 0xe5, sizeof(struct mon_event_text));
+}
+
+static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags)
+{
+	;
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/mon/usb_mon.h
@@ -0,0 +1,51 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ */
+
+#ifndef __USB_MON_H
+#define __USB_MON_H
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+/* #include <linux/usb.h> */	/* We use struct pointers only in this header */
+
+#define TAG "usbmon"
+
+struct mon_bus {
+	struct list_head bus_link;
+	spinlock_t lock;
+	struct dentry *dent_s;		/* Debugging file */
+	struct dentry *dent_t;		/* Text interface file */
+	struct usb_bus *u_bus;
+
+	/* Ref */
+	int nreaders;			/* Under mon_lock AND mbus->lock */
+	struct list_head r_list;	/* Chain of readers (usually one) */
+	struct kref ref;		/* Under mon_lock */
+
+	/* Stats */
+	unsigned int cnt_text_lost;
+};
+
+/*
+ * An instance of a process which opened a file (but can fork later)
+ */
+struct mon_reader {
+	struct list_head r_link;
+	struct mon_bus *m_bus;
+	void *r_data;		/* Use container_of instead? */
+
+	void (*rnf_submit)(void *data, struct urb *urb);
+	void (*rnf_complete)(void *data, struct urb *urb);
+};
+
+void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
+void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+
+extern struct semaphore mon_lock;
+
+extern struct file_operations mon_fops_text;
+extern struct file_operations mon_fops_stat;
+
+#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -219,17 +219,21 @@ config USB_EPSON2888
 	  by some sample firmware from Epson.
 
 config USB_ZAURUS
-	boolean "Sharp Zaurus (stock ROMs)"
+	boolean "Sharp Zaurus (stock ROMs) and compatible"
 	depends on USB_USBNET
 	select CRC32
 	default y
 	help
 	  Choose this option to support the usb networking links used by
 	  Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500.
+	  This also supports some related device firmware, as used in some
+	  PDAs from Olympus and some cell phones from Motorola.
 
-	  If you install an alternate ROM image, you may no longer need
-	  to support this protocol.  Only the "eth-fd" driver really needs
-	  this non-conformant variant of CDC Ethernet protocol.
+	  If you install an alternate ROM image, such as the Linux 2.6 based
+	  versions of OpenZaurus, you should no longer need to support this
+	  protocol.  Only the "eth-fd" or "net_fd" drivers in these devices
+	  really need this non-conformant variant of CDC Ethernet (or in
+	  some cases CDC MDLM) protocol, not "g_ether".
 
 config USB_CDCETHER
 	boolean "CDC Ethernet support (smart devices such as cable modems)"
@@ -260,13 +264,13 @@ comment "USB Network Adapters"
 	depends on USB_USBNET
 
 config USB_AX8817X
-	boolean "ASIX AX88172 Based USB 2.0 Ethernet Devices"
+	boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices"
 	depends on USB_USBNET && NET_ETHERNET
 	select CRC32
 	select MII
 	default y
 	help
-	  This option adds support for ASIX AX88172 based USB 2.0
+	  This option adds support for ASIX AX88xxx based USB 2.0
 	  10/100 Ethernet devices.
 
  	  This driver should work with at least the following devices:
@@ -287,4 +291,21 @@ config USB_AX8817X
 	  This driver creates an interface named "ethX", where X depends on
 	  what other networking devices you have in use.  
 
+config USB_ZD1201
+	tristate "USB ZD1201 based Wireless device support"
+	depends on NET_RADIO
+	select FW_LOADER
+	---help---
+	  Say Y if you want to use wireless LAN adapters based on the ZyDAS
+	  ZD1201 chip.
+
+	  This driver makes the adapter appear as a normal Ethernet interface,
+	  typically on wlan0.
+	  
+	  The zd1201 device requires external firmware to be loaded.
+	  This can be found at http://linux-lc100020.sourceforge.net/
+	  
+	  To compile this driver as a module, choose M here: the
+	  module will be called zd1201.
+
 endmenu
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_USB_KAWETH)	+= kaweth.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
+obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
+
+CFLAGS_zd1201.o = -Idrivers/net/wireless/
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -457,7 +457,7 @@ static int catc_ctrl_msg(struct catc *ca
 {
         int retval = usb_control_msg(catc->usbdev,
 		dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0),
-		 request, 0x40 | dir, value, index, buf, len, HZ);
+		 request, 0x40 | dir, value, index, buf, len, 1000);
         return retval < 0 ? retval : 0;
 }
 
@@ -664,7 +664,8 @@ static void catc_set_multicast_list(stru
 	}
 }
 
-void catc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static void catc_get_drvinfo(struct net_device *dev,
+			     struct ethtool_drvinfo *info)
 {
 	struct catc *catc = netdev_priv(dev);
 	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -58,6 +58,7 @@
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
@@ -519,7 +520,7 @@ static void int_callback(struct urb *u, 
 
 	/* we check the link state to report changes */
 	if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) {
-		if (!act_state)
+		if (act_state)
 			netif_carrier_on(kaweth->net);
 		else
 			netif_carrier_off(kaweth->net);
@@ -593,7 +594,7 @@ static void kaweth_usb_receive(struct ur
 
 	struct sk_buff *skb;
 
-	if(unlikely(urb->status == -ECONNRESET || urb->status == -ECONNABORTED || urb->status == -ESHUTDOWN))
+	if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN))
 	/* we are killed - set a flag and wake the disconnect handler */
 	{
 		kaweth->end = 1;
@@ -1180,31 +1181,21 @@ static void usb_api_blocking_completion(
 // Starts urb and waits for completion or timeout
 static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 {
-        DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
         int status;
 
         init_waitqueue_head(&awd.wqh);
         awd.done = 0;
 
-        add_wait_queue(&awd.wqh, &wait);
         urb->context = &awd;
         status = usb_submit_urb(urb, GFP_NOIO);
         if (status) {
                 // something went wrong
                 usb_free_urb(urb);
-                remove_wait_queue(&awd.wqh, &wait);
                 return status;
         }
 
-	while (timeout && !awd.done) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		timeout = schedule_timeout(timeout);
-	}
-
-        remove_wait_queue(&awd.wqh, &wait);
-
-        if (!timeout) {
+	if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
                 // timeout
                 kaweth_warn("usb_control/bulk_msg: timeout");
                 usb_kill_urb(urb);  // remove urb safely
diff --git a/drivers/usb/net/kawethfw.h b/drivers/usb/net/kawethfw.h
--- a/drivers/usb/net/kawethfw.h
+++ b/drivers/usb/net/kawethfw.h
@@ -551,7 +551,7 @@ static __u8 kaweth_new_code_fix[] = 
 };
 
 
-const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
-const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
-const int len_kaweth_new_code = sizeof(kaweth_new_code);
-const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);
+static const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
+static const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
+static const int len_kaweth_new_code = sizeof(kaweth_new_code);
+static const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999-2003 Petko Manolov (petkan@users.sourceforge.net)
+ *  Copyright (c) 1999-2005 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
@@ -47,7 +47,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.12 (2005/01/13)"
+#define DRIVER_VERSION "v0.6.12 (2005/01/13)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -85,6 +85,11 @@ module_param(mii_mode, bool, 0);
 MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
 MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
 
+/* use ethtool to change the level for any given device */
+static int msg_level = -1;
+module_param (msg_level, int, 0);
+MODULE_PARM_DESC (msg_level, "Override default message level");
+
 MODULE_DEVICE_TABLE(usb, pegasus_ids);
 
 static int update_eth_regs_async(pegasus_t *);
@@ -110,7 +115,9 @@ static void ctrl_callback(struct urb *ur
 	case -ENOENT:
 		break;
 	default:
-		warn("%s: status %d", __FUNCTION__, urb->status);
+		if (netif_msg_drv(pegasus))
+			dev_err(&pegasus->intf->dev, "%s, status %d\n",
+				__FUNCTION__, urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
 	wake_up(&pegasus->ctrl_wait);
@@ -125,7 +132,9 @@ static int get_registers(pegasus_t * peg
 
 	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
-		warn("%s: looks like we're out of memory", __FUNCTION__);
+		if (netif_msg_drv(pegasus))
+			dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
+					__FUNCTION__);
 		return -ENOMEM;
 	}
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
@@ -152,7 +161,9 @@ static int get_registers(pegasus_t * peg
 
 	/* using ATOMIC, we'd never wake up if we slept */
 	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
-		err("%s: BAD CTRLs %d", __FUNCTION__, ret);
+		if (netif_msg_drv(pegasus))
+			dev_err(&pegasus->intf->dev, "%s, status %d\n",
+					__FUNCTION__, ret);
 		goto out;
 	}
 
@@ -174,7 +185,9 @@ static int set_registers(pegasus_t * peg
 
 	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
-		warn("%s: looks like we're out of memory", __FUNCTION__);
+		if (netif_msg_drv(pegasus))
+			dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
+					__FUNCTION__);
 		return -ENOMEM;
 	}
 	memcpy(buffer, data, size);
@@ -202,7 +215,9 @@ static int set_registers(pegasus_t * peg
 	set_current_state(TASK_UNINTERRUPTIBLE);
 
 	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
-		err("%s: BAD CTRL %d", __FUNCTION__, ret);
+		if (netif_msg_drv(pegasus))
+			dev_err(&pegasus->intf->dev, "%s, status %d\n",
+					__FUNCTION__, ret);
 		goto out;
 	}
 
@@ -222,7 +237,9 @@ static int set_register(pegasus_t * pega
 
 	tmp = kmalloc(1, GFP_KERNEL);
 	if (!tmp) {
-		warn("%s: looks like we're out of memory", __FUNCTION__);
+		if (netif_msg_drv(pegasus))
+			dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
+					__FUNCTION__);
 		return -ENOMEM;
 	}
 	memcpy(tmp, &data, 1);
@@ -249,7 +266,9 @@ static int set_register(pegasus_t * pega
 	set_current_state(TASK_UNINTERRUPTIBLE);
 
 	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
-		err("%s: BAD CTRL %d", __FUNCTION__, ret);
+		if (netif_msg_drv(pegasus))
+			dev_err(&pegasus->intf->dev, "%s, status %d\n",
+					__FUNCTION__, ret);
 		goto out;
 	}
 
@@ -278,8 +297,9 @@ static int update_eth_regs_async(pegasus
 			     pegasus->eth_regs, 3, ctrl_callback, pegasus);
 
 	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC)))
-		err("%s: BAD CTRL %d, flgs %x", __FUNCTION__, ret,
-		    pegasus->flags);
+		if (netif_msg_drv(pegasus))
+			dev_err(&pegasus->intf->dev, "%s, status %d\n",
+					__FUNCTION__, ret);
 
 	return ret;
 }
@@ -289,52 +309,57 @@ static int read_mii_word(pegasus_t * peg
 	int i;
 	__u8 data[4] = { phy, 0, 0, indx };
 	__le16 regdi;
+	int ret;
 
-	set_register(pegasus, PhyCtrl, 0);
-	set_registers(pegasus, PhyAddr, sizeof (data), data);
-	set_register(pegasus, PhyCtrl, (indx | PHY_READ));
+	ret = set_register(pegasus, PhyCtrl, 0);
+	ret = set_registers(pegasus, PhyAddr, sizeof (data), data);
+	ret = set_register(pegasus, PhyCtrl, (indx | PHY_READ));
 	for (i = 0; i < REG_TIMEOUT; i++) {
-		get_registers(pegasus, PhyCtrl, 1, data);
+		ret = get_registers(pegasus, PhyCtrl, 1, data);
 		if (data[0] & PHY_DONE)
 			break;
 	}
 	if (i < REG_TIMEOUT) {
-		get_registers(pegasus, PhyData, 2, &regdi);
+		ret = get_registers(pegasus, PhyData, 2, &regdi);
 		*regd = le16_to_cpu(regdi);
-		return 0;
+		return 1;
 	}
-	warn("%s: failed", __FUNCTION__);
+	if (netif_msg_drv(pegasus))
+		dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
 
-	return 1;
+	return 0;
 }
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
 	pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
-	int res;
+	u16 res;
 
-	read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
-	return res & 0xffff;
+	read_mii_word(pegasus, phy_id, loc, &res);
+	return (int)res;
 }
 
 static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
 {
 	int i;
 	__u8 data[4] = { phy, 0, 0, indx };
+	int ret;
 
-	*(data + 1) = cpu_to_le16p(&regd);
-	set_register(pegasus, PhyCtrl, 0);
-	set_registers(pegasus, PhyAddr, sizeof(data), data);
-	set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
+	data[1] = (u8) regd;
+	data[2] = (u8) (regd >> 8);
+	ret = set_register(pegasus, PhyCtrl, 0);
+	ret = set_registers(pegasus, PhyAddr, sizeof(data), data);
+	ret = set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
 	for (i = 0; i < REG_TIMEOUT; i++) {
-		get_registers(pegasus, PhyCtrl, 1, data);
+		ret = get_registers(pegasus, PhyCtrl, 1, data);
 		if (data[0] & PHY_DONE)
 			break;
 	}
 	if (i < REG_TIMEOUT)
 		return 0;
-	warn("%s: failed", __FUNCTION__);
 
+	if (netif_msg_drv(pegasus))
+		dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
 	return 1;
 }
 
@@ -350,23 +375,25 @@ static int read_eprom_word(pegasus_t * p
 	int i;
 	__u8 tmp;
 	__le16 retdatai;
+	int ret;
 
-	set_register(pegasus, EpromCtrl, 0);
-	set_register(pegasus, EpromOffset, index);
-	set_register(pegasus, EpromCtrl, EPROM_READ);
+	ret = set_register(pegasus, EpromCtrl, 0);
+	ret = set_register(pegasus, EpromOffset, index);
+	ret = set_register(pegasus, EpromCtrl, EPROM_READ);
 
 	for (i = 0; i < REG_TIMEOUT; i++) {
-		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
 		if (tmp & EPROM_DONE)
 			break;
 	}
 	if (i < REG_TIMEOUT) {
-		get_registers(pegasus, EpromData, 2, &retdatai);
+		ret = get_registers(pegasus, EpromData, 2, &retdatai);
 		*retdata = le16_to_cpu(retdatai);
 		return 0;
 	}
-	warn("%s: failed", __FUNCTION__);
 
+	if (netif_msg_drv(pegasus))
+		dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
 	return -1;
 }
 
@@ -374,40 +401,44 @@ static int read_eprom_word(pegasus_t * p
 static inline void enable_eprom_write(pegasus_t * pegasus)
 {
 	__u8 tmp;
+	int ret;
 
-	get_registers(pegasus, EthCtrl2, 1, &tmp);
-	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
+	ret = get_registers(pegasus, EthCtrl2, 1, &tmp);
+	ret = set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
 }
 
 static inline void disable_eprom_write(pegasus_t * pegasus)
 {
 	__u8 tmp;
+	int ret;
 
-	get_registers(pegasus, EthCtrl2, 1, &tmp);
-	set_register(pegasus, EpromCtrl, 0);
-	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
+	ret = get_registers(pegasus, EthCtrl2, 1, &tmp);
+	ret = set_register(pegasus, EpromCtrl, 0);
+	ret = set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
 static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
 {
 	int i;
 	__u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE };
+	int ret;
 
-	set_registers(pegasus, EpromOffset, 4, d);
+	ret = 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);
+	ret = set_register(pegasus, EpromOffset, index);
+	ret = set_registers(pegasus, EpromData, 2, &data);
+	ret = set_register(pegasus, EpromCtrl, EPROM_WRITE);
 
 	for (i = 0; i < REG_TIMEOUT; i++) {
-		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
 		if (tmp & EPROM_DONE)
 			break;
 	}
 	disable_eprom_write(pegasus);
 	if (i < REG_TIMEOUT)
 		return 0;
-	warn("%s: failed", __FUNCTION__);
+	if (netif_msg_drv(pegasus))
+		dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
 	return -1;
 }
 #endif				/* PEGASUS_WRITE_EEPROM */
@@ -426,9 +457,10 @@ static inline void get_node_id(pegasus_t
 static void set_ethernet_addr(pegasus_t * pegasus)
 {
 	__u8 node_id[6];
+	int ret;
 
 	get_node_id(pegasus, node_id);
-	set_registers(pegasus, EthID, sizeof (node_id), node_id);
+	ret = set_registers(pegasus, EthID, sizeof (node_id), node_id);
 	memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
 }
 
@@ -436,19 +468,20 @@ static inline int reset_mac(pegasus_t * 
 {
 	__u8 data = 0x8;
 	int i;
+	int ret;
 
-	set_register(pegasus, EthCtrl1, data);
+	ret = set_register(pegasus, EthCtrl1, data);
 	for (i = 0; i < REG_TIMEOUT; i++) {
-		get_registers(pegasus, EthCtrl1, 1, &data);
+		ret = get_registers(pegasus, EthCtrl1, 1, &data);
 		if (~data & 0x08) {
 			if (loopback & 1)
 				break;
 			if (mii_mode && (pegasus->features & HAS_HOME_PNA))
-				set_register(pegasus, Gpio1, 0x34);
+				ret = set_register(pegasus, Gpio1, 0x34);
 			else
-				set_register(pegasus, Gpio1, 0x26);
-			set_register(pegasus, Gpio0, pegasus->features);
-			set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
+				ret = set_register(pegasus, Gpio1, 0x26);
+			ret = set_register(pegasus, Gpio0, pegasus->features);
+			ret = set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
 			break;
 		}
 	}
@@ -457,8 +490,8 @@ static inline int reset_mac(pegasus_t * 
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-		set_register(pegasus, Gpio0, 0x24);
-		set_register(pegasus, Gpio0, 0x26);
+		ret = set_register(pegasus, Gpio0, 0x24);
+		ret = set_register(pegasus, Gpio0, 0x26);
 	}
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
 		__u16 auxmode;
@@ -474,6 +507,7 @@ static int enable_net_traffic(struct net
 	__u16 linkpart;
 	__u8 data[4];
 	pegasus_t *pegasus = netdev_priv(dev);
+	int ret;
 
 	read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart);
 	data[0] = 0xc9;
@@ -487,7 +521,7 @@ static int enable_net_traffic(struct net
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
 
 	memcpy(pegasus->eth_regs, data, sizeof (data));
-	set_registers(pegasus, EthCtrl0, 3, data);
+	ret = set_registers(pegasus, EthCtrl0, 3, data);
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
@@ -550,48 +584,56 @@ static void read_bulk_callback(struct ur
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
 	int rx_status, count = urb->actual_length;
+	u8 *buf = urb->transfer_buffer;
 	__u16 pkt_len;
 
-	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
+	if (!pegasus)
 		return;
 
 	net = pegasus->net;
-	if (!netif_device_present(net))
+	if (!netif_device_present(net) || !netif_running(net))
 		return;
 
 	switch (urb->status) {
 	case 0:
 		break;
 	case -ETIMEDOUT:
-		dbg("%s: reset MAC", net->name);
+		if (netif_msg_rx_err(pegasus))
+			pr_debug("%s: reset MAC\n", net->name);
 		pegasus->flags &= ~PEGASUS_RX_BUSY;
 		break;
 	case -EPIPE:		/* stall, or disconnect from TT */
 		/* FIXME schedule work to clear the halt */
-		warn("%s: no rx stall recovery", net->name);
+		if (netif_msg_rx_err(pegasus))
+			printk(KERN_WARNING "%s: no rx stall recovery\n",
+					net->name);
 		return;
 	case -ENOENT:
 	case -ECONNRESET:
 	case -ESHUTDOWN:
-		dbg("%s: rx unlink, %d", net->name, urb->status);
+		if (netif_msg_ifdown(pegasus))
+			pr_debug("%s: rx unlink, %d\n", net->name, urb->status);
 		return;
 	default:
-		dbg("%s: RX status %d", net->name, urb->status);
+		if (netif_msg_rx_err(pegasus))
+			pr_debug("%s: RX status %d\n", net->name, urb->status);
 		goto goon;
 	}
 
-	if (!count)
+	if (!count || count < 4)
 		goto goon;
 
-	rx_status = le32_to_cpu(*(__le32 *) (urb->transfer_buffer + count - 4));
-	if (rx_status & 0x000e0000) {
-		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
+	rx_status = buf[count - 2];
+	if (rx_status & 0x1e) {
+		if (netif_msg_rx_err(pegasus))
+			pr_debug("%s: RX packet error %x\n",
+					net->name, rx_status);
 		pegasus->stats.rx_errors++;
-		if (rx_status & 0x060000)
+		if (rx_status & 0x06)	// long or runt
 			pegasus->stats.rx_length_errors++;
-		if (rx_status & 0x080000)
+		if (rx_status & 0x08)
 			pegasus->stats.rx_crc_errors++;
-		if (rx_status & 0x100000)
+		if (rx_status & 0x10)	// extra bits
 			pegasus->stats.rx_frame_errors++;
 		goto goon;
 	}
@@ -600,7 +642,10 @@ static void read_bulk_callback(struct ur
 		pkt_len &= 0x0fff;
 		pegasus->rx_skb->data += 2;
 	} else {
-		pkt_len = (rx_status & 0xfff) - 8;
+		pkt_len = buf[count - 3] << 8;
+		pkt_len += buf[count - 4];
+		pkt_len &= 0xfff;
+		pkt_len -= 8;
 	}
 
 	/*
@@ -636,7 +681,7 @@ goon:
 
 	return;
 
-      tl_sched:
+tl_sched:
 	tasklet_schedule(&pegasus->rx_tl);
 }
 
@@ -658,7 +703,9 @@ static void rx_fixup(unsigned long data)
 		pegasus->rx_skb = pull_skb(pegasus);
 	}
 	if (pegasus->rx_skb == NULL) {
-		warn("wow, low on memory");
+		if (netif_msg_rx_err(pegasus))
+			printk(KERN_WARNING "%s: low on memory\n",
+					pegasus->net->name);
 		tasklet_schedule(&pegasus->rx_tl);
 		goto done;
 	}
@@ -682,25 +729,29 @@ static void write_bulk_callback(struct u
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net = pegasus->net;
 
-	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
+	if (!pegasus)
 		return;
 
-	if (!netif_device_present(net))
+	if (!netif_device_present(net) || !netif_running(net))
 		return;
 
 	switch (urb->status) {
 	case -EPIPE:
 		/* FIXME schedule_work() to clear the tx halt */
 		netif_stop_queue(net);
-		warn("%s: no tx stall recovery", net->name);
+		if (netif_msg_tx_err(pegasus))
+			printk(KERN_WARNING "%s: no tx stall recovery\n",
+					net->name);
 		return;
 	case -ENOENT:
 	case -ECONNRESET:
 	case -ESHUTDOWN:
-		dbg("%s: tx unlink, %d", net->name, urb->status);
+		if (netif_msg_ifdown(pegasus))
+			pr_debug("%s: tx unlink, %d\n", net->name, urb->status);
 		return;
 	default:
-		info("%s: TX status %d", net->name, urb->status);
+		if (netif_msg_tx_err(pegasus))
+			pr_info("%s: TX status %d\n", net->name, urb->status);
 		/* FALL THROUGH */
 	case 0:
 		break;
@@ -731,7 +782,9 @@ static void intr_callback(struct urb *ur
 		/* some Pegasus-I products report LOTS of data
 		 * toggle errors... avoid log spamming
 		 */
-		pr_debug("%s: intr status %d\n", net->name, urb->status);
+		if (netif_msg_timer(pegasus))
+			pr_debug("%s: intr status %d\n", net->name,
+					urb->status);
 	}
 
 	if (urb->actual_length >= 6) {
@@ -763,7 +816,7 @@ static void intr_callback(struct urb *ur
 	}
 
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
-	if (status)
+	if (status && netif_msg_timer(pegasus))
 		printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",
 				net->name, status);
 }
@@ -771,7 +824,8 @@ static void intr_callback(struct urb *ur
 static void pegasus_tx_timeout(struct net_device *net)
 {
 	pegasus_t *pegasus = netdev_priv(net);
-	printk(KERN_WARNING "%s: tx timeout\n", net->name);
+	if (netif_msg_timer(pegasus))
+		printk(KERN_WARNING "%s: tx timeout\n", net->name);
 	pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(pegasus->tx_urb);
 	pegasus->stats.tx_errors++;
@@ -793,7 +847,9 @@ static int pegasus_start_xmit(struct sk_
 			  pegasus->tx_buff, count,
 			  write_bulk_callback, pegasus);
 	if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
-		warn("failed tx_urb %d", res);
+		if (netif_msg_tx_err(pegasus))
+			printk(KERN_WARNING "%s: fail tx, %d\n",
+					net->name, res);
 		switch (res) {
 		case -EPIPE:		/* stall, or disconnect from TT */
 			/* cleanup should already have been scheduled */
@@ -822,8 +878,9 @@ static struct net_device_stats *pegasus_
 static inline void disable_net_traffic(pegasus_t * pegasus)
 {
 	int tmp = 0;
+	int ret;
 
-	set_registers(pegasus, EthCtrl0, 2, &tmp);
+	ret = set_registers(pegasus, EthCtrl0, 2, &tmp);
 }
 
 static inline void get_interrupt_interval(pegasus_t * pegasus)
@@ -832,8 +889,10 @@ static inline void get_interrupt_interva
 
 	read_eprom_word(pegasus, 4, (__u16 *) data);
 	if (data[1] < 0x80) {
-		info("intr interval will be changed from %ums to %ums",
-		     data[1], 0x80);
+		if (netif_msg_timer(pegasus))
+			dev_info(&pegasus->intf->dev,
+				"intr interval changed from %ums to %ums\n",
+				data[1], 0x80);
 		data[1] = 0x80;
 #ifdef	PEGASUS_WRITE_EEPROM
 		write_eprom_word(pegasus, 4, *(__u16 *) data);
@@ -845,14 +904,14 @@ static inline void get_interrupt_interva
 static void set_carrier(struct net_device *net)
 {
 	pegasus_t *pegasus = netdev_priv(net);
-	short tmp;
+	u16 tmp;
 
-	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+	if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
+		return;
 	if (tmp & BMSR_LSTATUS)
 		netif_carrier_on(net);
 	else
 		netif_carrier_off(net);
-
 }
 
 static void free_all_urbs(pegasus_t * pegasus)
@@ -912,24 +971,32 @@ static int pegasus_open(struct net_devic
 	if (!pegasus->rx_skb)
 		return -ENOMEM;
 
-	set_registers(pegasus, EthID, 6, net->dev_addr);
+	res = set_registers(pegasus, EthID, 6, net->dev_addr);
 	
 	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
 			  usb_rcvbulkpipe(pegasus->usb, 1),
 			  pegasus->rx_skb->data, PEGASUS_MTU + 8,
 			  read_bulk_callback, pegasus);
-	if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)))
-		warn("%s: failed rx_urb %d", __FUNCTION__, res);
+	if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
+		if (netif_msg_ifup(pegasus))
+			pr_debug("%s: failed rx_urb, %d", net->name, res);
+		goto exit;
+	}
+
 	usb_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, GFP_KERNEL)))
-		warn("%s: failed intr_urb %d", __FUNCTION__, res);
-	netif_start_queue(net);
-	pegasus->flags |= PEGASUS_RUNNING;
+	if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
+		if (netif_msg_ifup(pegasus))
+			pr_debug("%s: failed intr_urb, %d\n", net->name, res);
+		usb_kill_urb(pegasus->rx_urb);
+		goto exit;
+	}
 	if ((res = enable_net_traffic(net, pegasus->usb))) {
-		err("can't enable_net_traffic() - %d", res);
+		if (netif_msg_ifup(pegasus))
+			pr_debug("%s: can't enable_net_traffic() - %d\n",
+					net->name, res);
 		res = -EIO;
 		usb_kill_urb(pegasus->rx_urb);
 		usb_kill_urb(pegasus->intr_urb);
@@ -937,6 +1004,9 @@ static int pegasus_open(struct net_devic
 		goto exit;
 	}
 	set_carrier(net);
+	netif_start_queue(net);
+	if (netif_msg_ifup(pegasus))
+		pr_debug("%s: open\n", net->name);
 	res = 0;
 exit:
 	return res;
@@ -946,7 +1016,6 @@ static int pegasus_close(struct net_devi
 {
 	pegasus_t *pegasus = netdev_priv(net);
 
-	pegasus->flags &= ~PEGASUS_RUNNING;
 	netif_stop_queue(net);
 	if (!(pegasus->flags & PEGASUS_UNPLUG))
 		disable_net_traffic(pegasus);
@@ -956,7 +1025,8 @@ static int pegasus_close(struct net_devi
 	return 0;
 }
 
-void pegasus_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static void pegasus_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
 {
 	pegasus_t *pegasus = netdev_priv(dev);
 	strncpy(info->driver, driver_name, sizeof (info->driver) - 1);
@@ -989,6 +1059,7 @@ pegasus_set_wol(struct net_device *dev, 
 		reg78 |= 0x80;
 	if (wol->wolopts & WAKE_PHY)
 		reg78 |= 0x40;
+	/* FIXME this 0x10 bit still needs to get set in the chip... */
 	if (wol->wolopts)
 		pegasus->eth_regs[0] |= 0x10;
 	else
@@ -997,8 +1068,7 @@ pegasus_set_wol(struct net_device *dev, 
 	return set_register(pegasus, WakeupControl, reg78);
 }
 
-static inline void
-pegasus_reset_wol(struct net_device *dev)
+static inline void pegasus_reset_wol(struct net_device *dev)
 {
 	struct ethtool_wolinfo wol;
 	
@@ -1009,10 +1079,17 @@ pegasus_reset_wol(struct net_device *dev
 static int
 pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	pegasus_t *pegasus = netdev_priv(dev);
+	pegasus_t *pegasus;
+
+	if (in_atomic())
+		return 0;
+
+	pegasus = netdev_priv(dev);
 	mii_ethtool_gset(&pegasus->mii, ecmd);
+
 	return 0;
 }
+
 static int
 pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
@@ -1035,13 +1112,13 @@ static u32 pegasus_get_link(struct net_d
 static u32 pegasus_get_msglevel(struct net_device *dev)
 {
 	pegasus_t *pegasus = netdev_priv(dev);
-	return pegasus->msg_level;
+	return pegasus->msg_enable;
 }
 
 static void pegasus_set_msglevel(struct net_device *dev, u32 v)
 {
 	pegasus_t *pegasus = netdev_priv(dev);
-	pegasus->msg_level = v;
+	pegasus->msg_enable = v;
 }
 
 static struct ethtool_ops ops = {
@@ -1087,12 +1164,14 @@ static void pegasus_set_multicast(struct
 
 	if (net->flags & IFF_PROMISC) {
 		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
-		pr_info("%s: Promiscuous mode enabled.\n", net->name);
+		if (netif_msg_link(pegasus))
+			pr_info("%s: Promiscuous mode enabled.\n", net->name);
 	} else if ((net->mc_count > multicast_filter_limit) ||
 		   (net->flags & IFF_ALLMULTI)) {
 		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
-		pr_info("%s: set allmulti\n", net->name);
+		if (netif_msg_link(pegasus))
+			pr_info("%s: set allmulti\n", net->name);
 	} else {
 		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
@@ -1121,17 +1200,18 @@ static __u8 mii_phy_probe(pegasus_t * pe
 static inline void setup_pegasus_II(pegasus_t * pegasus)
 {
 	__u8 data = 0xa5;
+	int ret;
 	
-	set_register(pegasus, Reg1d, 0);
-	set_register(pegasus, Reg7b, 1);
+	ret = set_register(pegasus, Reg1d, 0);
+	ret = set_register(pegasus, Reg7b, 1);
 	mdelay(100);
 	if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
-		set_register(pegasus, Reg7b, 0);
+		ret = set_register(pegasus, Reg7b, 0);
 	else
-		set_register(pegasus, Reg7b, 2);
+		ret = set_register(pegasus, Reg7b, 2);
 
-	set_register(pegasus, 0x83, data);
-	get_registers(pegasus, 0x83, 1, &data);
+	ret = set_register(pegasus, 0x83, data);
+	ret = get_registers(pegasus, 0x83, 1, &data);
 
 	if (data == 0xa5) {
 		pegasus->chip = 0x8513;
@@ -1139,14 +1219,28 @@ static inline void setup_pegasus_II(pega
 		pegasus->chip = 0;
 	}
 
-	set_register(pegasus, 0x80, 0xc0);
-	set_register(pegasus, 0x83, 0xff);
-	set_register(pegasus, 0x84, 0x01);
+	ret = set_register(pegasus, 0x80, 0xc0);
+	ret = set_register(pegasus, 0x83, 0xff);
+	ret = set_register(pegasus, 0x84, 0x01);
 	
 	if (pegasus->features & HAS_HOME_PNA && mii_mode)
-		set_register(pegasus, Reg81, 6);
+		ret = set_register(pegasus, Reg81, 6);
 	else
-		set_register(pegasus, Reg81, 2);
+		ret = set_register(pegasus, Reg81, 2);
+}
+
+
+static struct workqueue_struct *pegasus_workqueue = NULL;
+#define CARRIER_CHECK_DELAY (2 * HZ)
+
+static void check_carrier(void *data)
+{
+	pegasus_t *pegasus = data;
+	set_carrier(pegasus->net);
+	if (!(pegasus->flags & PEGASUS_UNPLUG)) {
+		queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+			CARRIER_CHECK_DELAY);
+	}
 }
 
 static int pegasus_probe(struct usb_interface *intf,
@@ -1161,7 +1255,7 @@ static int pegasus_probe(struct usb_inte
 	usb_get_dev(dev);
 	net = alloc_etherdev(sizeof(struct pegasus));
 	if (!net) {
-		err("out of memory allocating device structure");
+		dev_err(&intf->dev, "can't allocate %s\n", "device");
 		goto out;
 	}
 
@@ -1170,11 +1264,16 @@ static int pegasus_probe(struct usb_inte
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head(&pegasus->ctrl_wait);
 
-	if (!alloc_urbs(pegasus))
+	if (!alloc_urbs(pegasus)) {
+		dev_err(&intf->dev, "can't allocate %s\n", "urbs");
 		goto out1;
+	}
 
 	tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
 
+	INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus);
+
+	pegasus->intf = intf;
 	pegasus->usb = dev;
 	pegasus->net = net;
 	SET_MODULE_OWNER(net);
@@ -1193,6 +1292,8 @@ static int pegasus_probe(struct usb_inte
 	pegasus->mii.phy_id_mask = 0x1f;
 	pegasus->mii.reg_num_mask = 0x1f;
 	spin_lock_init(&pegasus->rx_pool_lock);
+	pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
+				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 
 	pegasus->features = usb_dev_id[dev_index].private;
 	get_interrupt_interval(pegasus);
@@ -1212,13 +1313,22 @@ static int pegasus_probe(struct usb_inte
 		dev_warn(&intf->dev, "can't locate MII phy, using default\n");
 		pegasus->phy = 1;
 	}
+	pegasus->mii.phy_id = pegasus->phy;
 	usb_set_intfdata(intf, pegasus);
 	SET_NETDEV_DEV(net, &intf->dev);
 	pegasus_reset_wol(net);
 	res = register_netdev(net);
 	if (res)
 		goto out3;
-	pr_info("%s: %s\n", net->name, usb_dev_id[dev_index].name);
+	queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+				CARRIER_CHECK_DELAY);
+
+	dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n",
+		net->name,
+		usb_dev_id[dev_index].name,
+		net->dev_addr [0], net->dev_addr [1],
+		net->dev_addr [2], net->dev_addr [3],
+		net->dev_addr [4], net->dev_addr [5]);
 	return 0;
 
 out3:
@@ -1239,11 +1349,12 @@ static void pegasus_disconnect(struct us
 
 	usb_set_intfdata(intf, NULL);
 	if (!pegasus) {
-		warn("unregistering non-existant device");
+		dev_dbg(&intf->dev, "unregistering non-bound device?\n");
 		return;
 	}
 
 	pegasus->flags |= PEGASUS_UNPLUG;
+	cancel_delayed_work(&pegasus->carrier_check);
 	unregister_netdev(pegasus->net);
 	usb_put_dev(interface_to_usbdev(intf));
 	free_all_urbs(pegasus);
@@ -1253,11 +1364,18 @@ static void pegasus_disconnect(struct us
 	free_netdev(pegasus->net);
 }
 
-static int pegasus_suspend (struct usb_interface *intf, u32 state)
+static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 	
 	netif_device_detach (pegasus->net);
+	if (netif_running(pegasus->net)) {
+		cancel_delayed_work(&pegasus->carrier_check);
+
+		usb_kill_urb(pegasus->rx_urb);
+		usb_kill_urb(pegasus->intr_urb);
+	}
+	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 }
 
@@ -1265,7 +1383,20 @@ static int pegasus_resume (struct usb_in
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 
+	intf->dev.power.power_state = PMSG_ON;
 	netif_device_attach (pegasus->net);
+	if (netif_running(pegasus->net)) {
+		pegasus->rx_urb->status = 0;
+		pegasus->rx_urb->actual_length = 0;
+		read_bulk_callback(pegasus->rx_urb, NULL);
+
+		pegasus->intr_urb->status = 0;
+		pegasus->intr_urb->actual_length = 0;
+		intr_callback(pegasus->intr_urb, NULL);
+
+		queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+					CARRIER_CHECK_DELAY);
+	}
 	return 0;
 }
 
@@ -1281,11 +1412,15 @@ static struct usb_driver pegasus_driver 
 static int __init pegasus_init(void)
 {
 	pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
+	pegasus_workqueue = create_singlethread_workqueue("pegasus");
+	if (!pegasus_workqueue)
+		return -ENOMEM;
 	return usb_register(&pegasus_driver);
 }
 
 static void __exit pegasus_exit(void)
 {
+	destroy_workqueue(pegasus_workqueue);
 	usb_deregister(&pegasus_driver);
 }
 
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -29,7 +29,6 @@
 #define	DEFAULT_GPIO_SET	0x26
 
 #define	PEGASUS_PRESENT		0x00000001
-#define	PEGASUS_RUNNING		0x00000002
 #define	PEGASUS_TX_BUSY		0x00000004
 #define	PEGASUS_RX_BUSY		0x00000008
 #define	CTRL_URB_RUNNING	0x00000010
@@ -86,16 +85,18 @@ enum pegasus_registers {
 
 typedef struct pegasus {
 	struct usb_device	*usb;
+	struct usb_interface	*intf;
 	struct net_device	*net;
 	struct net_device_stats	stats;
 	struct mii_if_info	mii;
 	unsigned		flags;
 	unsigned		features;
-	u32			msg_level;
+	u32			msg_enable;
 	u32			wolopts;
 	int			dev_index;
 	int			intr_interval;
 	struct tasklet_struct	rx_tl;
+	struct work_struct	carrier_check;
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	struct sk_buff		*rx_pool[RX_SKBS];
 	struct sk_buff		*rx_skb;
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -195,14 +195,14 @@ static int get_registers(rtl8150_t * dev
 {
 	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
 			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-			       indx, 0, data, size, HZ / 2);
+			       indx, 0, data, size, 500);
 }
 
 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);
+			       indx, 0, data, size, 500);
 }
 
 static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -1,8 +1,9 @@
 /*
  * USB Networking Links
- * Copyright (C) 2000-2003 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
  * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
- * Copyright (C) 2003 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
  * Copyright (c) 2002-2003 TiVo Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -109,6 +110,7 @@
  *		(Neil Bortnak)
  * 03-nov-2004	Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell)
  *
+ * 01-feb-2005	AX88772 support (Phil Chang & Dave Hollis)
  *-------------------------------------------------------------------------*/
 
 // #define	DEBUG			// error path messages, extra info
@@ -164,8 +166,7 @@
 #define THROTTLE_JIFFIES	(HZ/8)
 
 // for vendor-specific control operations
-#define	CONTROL_TIMEOUT_MS	(500)			/* msec */
-#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
+#define	CONTROL_TIMEOUT_MS	500
 
 // between wakeups
 #define UNLINK_TIMEOUT_MS	3
@@ -184,13 +185,14 @@ struct usbnet {
 
 	// i/o info: pipes etc
 	unsigned		in, out;
+	struct usb_host_endpoint *status;
 	unsigned		maxpacket;
 	struct timer_list	delay;
 
 	// protocol/interface state
 	struct net_device	*net;
 	struct net_device_stats	stats;
-	int			msg_level;
+	int			msg_enable;
 	unsigned long		data [5];
 
 	struct mii_if_info	mii;
@@ -199,6 +201,7 @@ struct usbnet {
 	struct sk_buff_head	rxq;
 	struct sk_buff_head	txq;
 	struct sk_buff_head	done;
+	struct urb		*interrupt;
 	struct tasklet_struct	bh;
 
 	struct work_struct	kevent;
@@ -206,6 +209,8 @@ struct usbnet {
 #		define EVENT_TX_HALT	0
 #		define EVENT_RX_HALT	1
 #		define EVENT_RX_MEMORY	2
+#		define EVENT_STS_SPLIT	3
+#		define EVENT_LINK_RESET	4
 };
 
 // device-specific info used by the driver
@@ -222,6 +227,8 @@ struct driver_info {
 #define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 #define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
 
+#define FLAG_FRAMING_AX 0x0040          /* AX88772/178 packets */
+
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);
 
@@ -234,6 +241,12 @@ struct driver_info {
 	/* see if peer is connected ... can sleep */
 	int	(*check_connect)(struct usbnet *);
 
+	/* for status polling */
+	void	(*status)(struct usbnet *, struct urb *);
+
+	/* link reset handling, called from defer_kevent */
+	int	(*link_reset)(struct usbnet *);
+
 	/* fixup rx packet (strip framing) */
 	int	(*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
 
@@ -269,14 +282,11 @@ struct skb_data {	// skb->cb is one of t
 static const char driver_name [] = "usbnet";
 
 /* use ethtool to change the level for any given device */
-static int msg_level = 1;
+static int msg_level = -1;
 module_param (msg_level, int, 0);
-MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
+MODULE_PARM_DESC (msg_level, "Override default message level");
 
 
-#define	RUN_CONTEXT (in_irq () ? "in_irq" \
-			: (in_interrupt () ? "in_interrupt" : "can sleep"))
-
 #ifdef DEBUG
 #define devdbg(usbnet, fmt, arg...) \
 	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
@@ -290,9 +300,7 @@ MODULE_PARM_DESC (msg_level, "Initial me
 	printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
 
 #define devinfo(usbnet, fmt, arg...) \
-	do { if ((usbnet)->msg_level >= 1) \
 	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
-	} while (0)
 
 /*-------------------------------------------------------------------------*/
 
@@ -300,6 +308,7 @@ static void usbnet_get_drvinfo (struct n
 static u32 usbnet_get_link (struct net_device *);
 static u32 usbnet_get_msglevel (struct net_device *);
 static void usbnet_set_msglevel (struct net_device *, u32);
+static void defer_kevent (struct usbnet *, int);
 
 /* mostly for PDA style devices, which are always connected if present */
 static int always_connected (struct usbnet *dev)
@@ -312,38 +321,52 @@ static int
 get_endpoints (struct usbnet *dev, struct usb_interface *intf)
 {
 	int				tmp;
-	struct usb_host_interface	*alt;
-	struct usb_host_endpoint	*in, *out;
+	struct usb_host_interface	*alt = NULL;
+	struct usb_host_endpoint	*in = NULL, *out = NULL;
+	struct usb_host_endpoint	*status = NULL;
 
 	for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
 		unsigned	ep;
 
-		in = out = NULL;
+		in = out = status = NULL;
 		alt = intf->altsetting + tmp;
 
 		/* take the first altsetting with in-bulk + out-bulk;
+		 * remember any status endpoint, just in case;
 		 * ignore other endpoints and altsetttings.
 		 */
 		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
 			struct usb_host_endpoint	*e;
+			int				intr = 0;
 
 			e = alt->endpoint + ep;
-			if (e->desc.bmAttributes != USB_ENDPOINT_XFER_BULK)
+			switch (e->desc.bmAttributes) {
+			case USB_ENDPOINT_XFER_INT:
+				if (!(e->desc.bEndpointAddress & USB_DIR_IN))
+					continue;
+				intr = 1;
+				/* FALLTHROUGH */
+			case USB_ENDPOINT_XFER_BULK:
+				break;
+			default:
 				continue;
+			}
 			if (e->desc.bEndpointAddress & USB_DIR_IN) {
-				if (!in)
+				if (!intr && !in)
 					in = e;
+				else if (intr && !status)
+					status = e;
 			} else {
 				if (!out)
 					out = e;
 			}
-			if (in && out)
-				goto found;
 		}
+		if (in && out)
+			break;
 	}
-	return -EINVAL;
+	if (!alt || !in || !out)
+		return -EINVAL;
 
-found:
 	if (alt->desc.bAlternateSetting != 0
 			|| !(dev->driver_info->flags & FLAG_NO_SETINT)) {
 		tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
@@ -356,9 +379,48 @@ found:
 			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
 	dev->out = usb_sndbulkpipe (dev->udev,
 			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	dev->status = status;
 	return 0;
 }
 
+static void intr_complete (struct urb *urb, struct pt_regs *regs);
+
+static int init_status (struct usbnet *dev, struct usb_interface *intf)
+{
+	char		*buf = NULL;
+	unsigned	pipe = 0;
+	unsigned	maxp;
+	unsigned	period;
+
+	if (!dev->driver_info->status)
+		return 0;
+
+	pipe = usb_rcvintpipe (dev->udev,
+			dev->status->desc.bEndpointAddress
+				& USB_ENDPOINT_NUMBER_MASK);
+	maxp = usb_maxpacket (dev->udev, pipe, 0);
+
+	/* avoid 1 msec chatter:  min 8 msec poll rate */
+	period = max ((int) dev->status->desc.bInterval,
+		(dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
+
+	buf = kmalloc (maxp, SLAB_KERNEL);
+	if (buf) {
+		dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL);
+		if (!dev->interrupt) {
+			kfree (buf);
+			return -ENOMEM;
+		} else {
+			usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
+				buf, maxp, intr_complete, dev, period);
+			dev_dbg(&intf->dev,
+				"status ep%din, %d bytes period %d\n",
+				usb_pipeendpoint(pipe), maxp, period);
+		}
+	}
+	return  0;
+}
+
 static void skb_return (struct usbnet *dev, struct sk_buff *skb)
 {
 	int	status;
@@ -368,13 +430,12 @@ static void skb_return (struct usbnet *d
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += skb->len;
 
-#ifdef	VERBOSE
-	devdbg (dev, "< rx, len %d, type 0x%x",
-		skb->len + sizeof (struct ethhdr), skb->protocol);
-#endif
+	if (netif_msg_rx_status (dev))
+		devdbg (dev, "< rx, len %zu, type 0x%x",
+			skb->len + sizeof (struct ethhdr), skb->protocol);
 	memset (skb->cb, 0, sizeof (struct skb_data));
 	status = netif_rx (skb);
-	if (status != NET_RX_SUCCESS)
+	if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
 		devdbg (dev, "netif_rx status %d", status);
 }
 
@@ -435,6 +496,8 @@ static const struct driver_info	an2720_i
 #define AX_CMD_SET_HW_MII		0x0a
 #define AX_CMD_READ_EEPROM		0x0b
 #define AX_CMD_WRITE_EEPROM		0x0c
+#define AX_CMD_WRITE_ENABLE		0x0d
+#define AX_CMD_WRITE_DISABLE		0x0e
 #define AX_CMD_WRITE_RX_CTL		0x10
 #define AX_CMD_READ_IPG012		0x11
 #define AX_CMD_WRITE_IPG0		0x12
@@ -443,28 +506,71 @@ static const struct driver_info	an2720_i
 #define AX_CMD_WRITE_MULTI_FILTER	0x16
 #define AX_CMD_READ_NODE_ID		0x17
 #define AX_CMD_READ_PHY_ID		0x19
+#define AX_CMD_READ_MEDIUM_STATUS	0x1a
 #define AX_CMD_WRITE_MEDIUM_MODE	0x1b
 #define AX_CMD_READ_MONITOR_MODE	0x1c
 #define AX_CMD_WRITE_MONITOR_MODE	0x1d
 #define AX_CMD_WRITE_GPIOS		0x1f
+#define AX_CMD_SW_RESET			0x20
+#define AX_CMD_SW_PHY_STATUS		0x21
+#define AX_CMD_SW_PHY_SELECT		0x22
+#define AX88772_CMD_READ_NODE_ID	0x13
 
 #define AX_MONITOR_MODE			0x01
 #define AX_MONITOR_LINK			0x02
 #define AX_MONITOR_MAGIC		0x04
 #define AX_MONITOR_HSFS			0x10
 
+/* AX88172 Medium Status Register values */
+#define AX_MEDIUM_FULL_DUPLEX		0x02
+#define AX_MEDIUM_TX_ABORT_ALLOW	0x04
+#define AX_MEDIUM_FLOW_CONTROL_EN	0x10
+
 #define AX_MCAST_FILTER_SIZE		8
 #define AX_MAX_MCAST			64
 
-#define AX_INTERRUPT_BUFSIZE		8
+#define AX_EEPROM_LEN			0x40
+
+#define AX_SWRESET_CLEAR		0x00
+#define AX_SWRESET_RR			0x01
+#define AX_SWRESET_RT			0x02
+#define AX_SWRESET_PRTE			0x04
+#define AX_SWRESET_PRL			0x08
+#define AX_SWRESET_BZ			0x10
+#define AX_SWRESET_IPRL			0x20
+#define AX_SWRESET_IPPD			0x40
+
+#define AX88772_IPG0_DEFAULT		0x15
+#define AX88772_IPG1_DEFAULT		0x0c
+#define AX88772_IPG2_DEFAULT		0x12
+
+#define AX88772_MEDIUM_FULL_DUPLEX	0x0002
+#define AX88772_MEDIUM_RESERVED		0x0004
+#define AX88772_MEDIUM_RX_FC_ENABLE	0x0010
+#define AX88772_MEDIUM_TX_FC_ENABLE	0x0020
+#define AX88772_MEDIUM_PAUSE_FORMAT	0x0080
+#define AX88772_MEDIUM_RX_ENABLE	0x0100
+#define AX88772_MEDIUM_100MB		0x0200
+#define AX88772_MEDIUM_DEFAULT	\
+	(AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
+	 AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
+	 AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
+
+#define AX_EEPROM_MAGIC			0xdeadbeef
 
 /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
 struct ax8817x_data {
 	u8 multi_filter[AX_MCAST_FILTER_SIZE];
-	struct urb *int_urb;
-	u8 *int_buf;
 };
 
+struct ax88172_int_data {
+	u16 res1;
+	u8 link;
+	u16 res2;
+	u8 status;
+	u16 res3;
+} __attribute__ ((packed));
+
 static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 			    u16 size, void *data)
 {
@@ -477,7 +583,7 @@ static int ax8817x_read_cmd(struct usbne
 		index,
 		data,
 		size,
-		CONTROL_TIMEOUT_JIFFIES);
+		CONTROL_TIMEOUT_MS);
 }
 
 static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
@@ -492,7 +598,7 @@ static int ax8817x_write_cmd(struct usbn
 		index,
 		data,
 		size,
-		CONTROL_TIMEOUT_JIFFIES);
+		CONTROL_TIMEOUT_MS);
 }
 
 static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
@@ -507,27 +613,23 @@ static void ax8817x_async_cmd_callback(s
 	usb_free_urb(urb);
 }
 
-static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs)
+static void ax8817x_status(struct usbnet *dev, struct urb *urb)
 {
-	struct usbnet *dev = (struct usbnet *)urb->context;
-	struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+	struct ax88172_int_data *event;
 	int link;
 
-	if (urb->status < 0) {
-		printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d",
-			urb->status);
-	} else {
-		if (data->int_buf[5] == 0x90) {
-			link = data->int_buf[2] & 0x01;
-			if (netif_carrier_ok(dev->net) != link) {
-				if (link)
-					netif_carrier_on(dev->net);
-				else
-					netif_carrier_off(dev->net);
-				devdbg(dev, "ax8817x - Link Status is: %d", link);
-			}
-		}
-		usb_submit_urb(data->int_urb, GFP_ATOMIC);
+	if (urb->actual_length < 8)
+		return;
+
+	event = urb->transfer_buffer;
+	link = event->link & 0x01;
+	if (netif_carrier_ok(dev->net) != link) {
+		if (link) {
+			netif_carrier_on(dev->net);
+			defer_kevent (dev, EVENT_LINK_RESET );
+		} else
+			netif_carrier_off(dev->net);
+		devdbg(dev, "ax8817x - Link Status is: %d", link);
 	}
 }
 
@@ -634,6 +736,20 @@ static void ax8817x_mdio_write(struct ne
 	ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
 }
 
+static int ax88172_link_reset(struct usbnet *dev)
+{
+	u16 lpa;
+	u8 mode;
+
+	mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
+	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
+	if (lpa & LPA_DUPLEX)
+		mode |= AX_MEDIUM_FULL_DUPLEX;
+	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+
+	return 0;
+}
+
 static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
 {
 	struct usbnet *dev = netdev_priv(net);
@@ -674,6 +790,11 @@ static int ax8817x_set_wol(struct net_de
 	return 0;
 }
 
+static int ax8817x_get_eeprom_len(struct net_device *net)
+{
+	return AX_EEPROM_LEN;
+}
+
 static int ax8817x_get_eeprom(struct net_device *net,
 			      struct ethtool_eeprom *eeprom, u8 *data)
 {
@@ -687,13 +808,15 @@ static int ax8817x_get_eeprom(struct net
 	if (eeprom->len % 2)
 		return -EINVAL;
 
+	eeprom->magic = AX_EEPROM_MAGIC;
+
 	/* ax8817x returns 2 bytes from eeprom on read */
 	for (i=0; i < eeprom->len / 2; i++) {
 		if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 
 			eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
 			return -EINVAL;
 	}
-	return i * 2;
+	return 0;
 }
 
 static void ax8817x_get_drvinfo (struct net_device *net,
@@ -728,6 +851,7 @@ static struct ethtool_ops ax8817x_ethtoo
 	.set_msglevel		= usbnet_set_msglevel,
 	.get_wol		= ax8817x_get_wol,
 	.set_wol		= ax8817x_set_wol,
+	.get_eeprom_len		= ax8817x_get_eeprom_len,
 	.get_eeprom		= ax8817x_get_eeprom,
 	.get_settings		= ax8817x_get_settings,
 	.set_settings		= ax8817x_set_settings,
@@ -735,66 +859,50 @@ static struct ethtool_ops ax8817x_ethtoo
 
 static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-	int ret;
-	u8 buf[6];
+	int ret = 0;
+	void *buf;
 	int i;
 	unsigned long gpio_bits = dev->driver_info->data;
-	struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
 
-	dev->in = usb_rcvbulkpipe(dev->udev, 3);
-	dev->out = usb_sndbulkpipe(dev->udev, 2);
+	get_endpoints(dev,intf);
 
-	// allocate irq urb
-	if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) {
-		dbg ("%s: cannot allocate interrupt URB",
-			dev->net->name);
-		return -ENOMEM;
-	}
-	
-	if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) {
-		dbg ("%s: cannot allocate memory for interrupt buffer",
-			dev->net->name);
-		usb_free_urb(data->int_urb);
-		return -ENOMEM;
+	buf = kmalloc(ETH_ALEN, GFP_KERNEL);
+	if(!buf) {
+		ret = -ENOMEM;
+		goto out1;
 	}
-	memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
-
-	usb_fill_int_urb (data->int_urb, dev->udev,
-		usb_rcvintpipe (dev->udev, 1),
-		data->int_buf, AX_INTERRUPT_BUFSIZE,
-		ax8817x_interrupt_complete, dev,
-		dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
 
 	/* Toggle the GPIOs in a manufacturer/model specific way */
 	for (i = 2; i >= 0; i--) {
 		if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
 					(gpio_bits >> (i * 8)) & 0xff, 0, 0,
 					buf)) < 0)
-			return ret;
+			goto out2;
 		msleep(5);
 	}
 
 	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) {
 		dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret);
-		return ret;
+		goto out2;
 	}
 
 	/* Get the MAC address */
 	memset(buf, 0, ETH_ALEN);
 	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) {
 		dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
-		return ret;
+		goto out2;
 	}
 	memcpy(dev->net->dev_addr, buf, ETH_ALEN);
 
 	/* Get the PHY id */
 	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) {
 		dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret);
-		return ret;
+		goto out2;
 	} else if (ret < 2) {
 		/* this should always return 2 bytes */
 		dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret);
-		return -EIO;
+		ret = -EIO;
+		goto out2;
 	}
 
 	/* Initialize MII structure */
@@ -803,39 +911,300 @@ static int ax8817x_bind(struct usbnet *d
 	dev->mii.mdio_write = ax8817x_mdio_write;
 	dev->mii.phy_id_mask = 0x3f;
 	dev->mii.reg_num_mask = 0x1f;
-	dev->mii.phy_id = buf[1];
+	dev->mii.phy_id = *((u8 *)buf + 1);
 
 	dev->net->set_multicast_list = ax8817x_set_multicast;
 	dev->net->ethtool_ops = &ax8817x_ethtool_ops;
 
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
-			cpu_to_le16(BMCR_RESET));
+	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
 	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-			cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400));
+		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
 	mii_nway_restart(&dev->mii);
 
-	if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
-		dbg("Failed to submit interrupt URB: %02x", ret);
-		usb_free_urb(data->int_urb);
-		return ret;
+	return 0;
+out2:
+	kfree(buf);
+out1:
+	return ret;
+}
+
+static struct ethtool_ops ax88772_ethtool_ops = {
+	.get_drvinfo		= ax8817x_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= usbnet_get_msglevel,
+	.set_msglevel		= usbnet_set_msglevel,
+	.get_wol		= ax8817x_get_wol,
+	.set_wol		= ax8817x_set_wol,
+	.get_eeprom_len		= ax8817x_get_eeprom_len,
+	.get_eeprom		= ax8817x_get_eeprom,
+	.get_settings		= ax8817x_get_settings,
+	.set_settings		= ax8817x_set_settings,
+};
+
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+	void *buf;
+
+	get_endpoints(dev,intf);
+
+	buf = kmalloc(6, GFP_KERNEL);
+	if(!buf) {
+		dbg ("Cannot allocate memory for buffer");
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+				     0x00B0, 0, 0, buf)) < 0)
+		goto out2;
+
+	msleep(5);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) {
+		dbg("Select PHY #1 failed: %d", ret);
+		goto out2;
+	}
+
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) {
+		dbg("Failed to power down internal PHY: %d", ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) {
+		dbg("Failed to perform software reset: %d", ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+		dbg("Failed to set Internal/External PHY reset control: %d", ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0,
+			       buf)) < 0) {
+		dbg("Failed to reset RX_CTL: %d", ret);
+		goto out2;
 	}
 
+	/* Get the MAC address */
+	memset(buf, 0, ETH_ALEN);
+	if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) {
+		dbg("Failed to read MAC address: %d", ret);
+		goto out2;
+	}
+	memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) {
+		dbg("Enabling software MII failed: %d", ret);
+		goto out2;
+	}
+
+	if (((ret =
+	      ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0)
+	    || (*((u16 *)buf) != 0x003b)) {
+		dbg("Read PHY register 2 must be 0x3b00: %d", ret);
+		goto out2;
+	}
+
+	/* Initialize MII structure */
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = ax8817x_mdio_read;
+	dev->mii.mdio_write = ax8817x_mdio_write;
+	dev->mii.phy_id_mask = 0xff;
+	dev->mii.reg_num_mask = 0xff;
+
+	/* Get the PHY id */
+	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) {
+		dbg("Error reading PHY ID: %02x", ret);
+		goto out2;
+	} else if (ret < 2) {
+		/* this should always return 2 bytes */
+		dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
+		    ret);
+		ret = -EIO;
+		goto out2;
+	}
+	dev->mii.phy_id = *((u8 *)buf + 1);
+
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+		dbg("Set external PHY reset pin level: %d", ret);
+		goto out2;
+	}
+	msleep(150);
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+		dbg("Set Internal/External PHY reset control: %d", ret);
+		goto out2;
+	}
+	msleep(150);
+
+
+	dev->net->set_multicast_list = ax8817x_set_multicast;
+	dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_CSMA);
+	mii_nway_restart(&dev->mii);
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
+		dbg("Write medium mode register: %d", ret);
+		goto out2;
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) {
+		dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
+		goto out2;
+	}
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
+		dbg("Failed to set hardware MII: %02x", ret);
+		goto out2;
+	}
+
+	/* Set RX_CTL to default values with 2k buffer, and enable cactus */
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
+			       buf)) < 0) {
+		dbg("Reset RX_CTL failed: %d", ret);
+		goto out2;
+	}
+
+	kfree(buf);
+
 	return 0;
+
+out2:
+	kfree(buf);
+out1:
+	return ret;
 }
 
-static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf)
+static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
-	struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
+	u32 *header;
+	char *packet;
+	struct sk_buff *ax_skb;
+	u16 size;
+
+	header = (u32 *) skb->data;
+	le32_to_cpus(header);
+	packet = (char *)(header + 1);
+
+	skb_pull(skb, 4);
+
+	while (skb->len > 0) {
+		if ((short)(*header & 0x0000ffff) !=
+		    ~((short)((*header & 0xffff0000) >> 16))) {
+			devdbg(dev,"header length data is error");
+		}
+		/* get the packet length */
+		size = (u16) (*header & 0x0000ffff);
+
+		if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+			return 2;
+		if (size > ETH_FRAME_LEN) {
+			devdbg(dev,"invalid rx length %d", size);
+			return 0;
+		}
+		ax_skb = skb_clone(skb, GFP_ATOMIC);
+		if (ax_skb) {
+			ax_skb->len = size;
+			ax_skb->data = packet;
+			ax_skb->tail = packet + size;
+			skb_return(dev, ax_skb);
+		} else {
+			return 0;
+		}
 
-	usb_kill_urb(data->int_urb);
-	usb_free_urb(data->int_urb);
-	kfree(data->int_buf);
+		skb_pull(skb, (size + 1) & 0xfffe);
+
+		if (skb->len == 0)
+			break;
+
+		header = (u32 *) skb->data;
+		le32_to_cpus(header);
+		packet = (char *)(header + 1);
+		skb_pull(skb, 4);
+	}
+
+	if (skb->len < 0) {
+		devdbg(dev,"invalid rx length %d", skb->len);
+		return 0;
+	}
+	return 1;
+}
+
+static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+					int flags)
+{
+	int padlen;
+	int headroom = skb_headroom(skb);
+	int tailroom = skb_tailroom(skb);
+	u32 *packet_len;
+	u32 *padbytes_ptr;
+
+	padlen = ((skb->len + 4) % 512) ? 0 : 4;
+
+	if ((!skb_cloned(skb))
+	    && ((headroom + tailroom) >= (4 + padlen))) {
+		if ((headroom < 4) || (tailroom < padlen)) {
+			skb->data = memmove(skb->head + 4, skb->data, skb->len);
+			skb->tail = skb->data + skb->len;
+		}
+	} else {
+		struct sk_buff *skb2;
+		skb2 = skb_copy_expand(skb, 4, padlen, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	packet_len = (u32 *) skb_push(skb, 4);
+
+	packet_len = (u32 *) skb->data;
+	*packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+
+	if ((skb->len % 512) == 0) {
+		padbytes_ptr = (u32 *) skb->tail;
+		*padbytes_ptr = 0xffff0000;
+		skb_put(skb, padlen);
+	}
+	return skb;
+}
+
+static int ax88772_link_reset(struct usbnet *dev)
+{
+	u16 lpa;
+	u16 mode;
+
+	mode = AX88772_MEDIUM_DEFAULT;
+	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
+
+	if ((lpa & LPA_DUPLEX) == 0)
+		mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+	if ((lpa & LPA_100) == 0)
+		mode &= ~AX88772_MEDIUM_100MB;
+	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+
+	return 0;
 }
 
 static const struct driver_info ax8817x_info = {
 	.description = "ASIX AX8817x USB 2.0 Ethernet",
 	.bind = ax8817x_bind,
-	.unbind = ax8817x_unbind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
 	.flags =  FLAG_ETHER,
 	.data = 0x00130103,
 };
@@ -843,7 +1212,9 @@ static const struct driver_info ax8817x_
 static const struct driver_info dlink_dub_e100_info = {
 	.description = "DLink DUB-E100 USB Ethernet",
 	.bind = ax8817x_bind,
-	.unbind = ax8817x_unbind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
 	.flags =  FLAG_ETHER,
 	.data = 0x009f9d9f,
 };
@@ -851,7 +1222,9 @@ static const struct driver_info dlink_du
 static const struct driver_info netgear_fa120_info = {
 	.description = "Netgear FA-120 USB Ethernet",
 	.bind = ax8817x_bind,
-	.unbind = ax8817x_unbind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
 	.flags =  FLAG_ETHER,
 	.data = 0x00130103,
 };
@@ -859,11 +1232,25 @@ static const struct driver_info netgear_
 static const struct driver_info hawking_uf200_info = {
 	.description = "Hawking UF200 USB Ethernet",
 	.bind = ax8817x_bind,
-	.unbind = ax8817x_unbind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
 	.flags =  FLAG_ETHER,
 	.data = 0x001f1d1f,
 };
 
+static const struct driver_info ax88772_info = {
+	.description = "ASIX AX88772 USB 2.0 Ethernet",
+	.bind = ax88772_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88772_link_reset,
+	.reset = ax88772_link_reset,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.rx_fixup = ax88772_rx_fixup,
+	.tx_fixup = ax88772_tx_fixup,
+	.data = 0x00130103,
+};
+
 #endif /* CONFIG_USB_AX8817X */
 
 
@@ -911,45 +1298,14 @@ static const struct driver_info	belkin_i
 
 #ifdef	NEED_GENERIC_CDC
 
-/* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
-struct header_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u16	bcdCDC;
-} __attribute__ ((packed));
-
-/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
-struct union_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u8	bMasterInterface0;
-	u8	bSlaveInterface0;
-	/* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
-struct ether_desc {
-	u8	bLength;
-	u8	bDescriptorType;
-	u8	bDescriptorSubType;
-
-	u8	iMACAddress;
-	u32	bmEthernetStatistics;
-	__le16	wMaxSegmentSize;
-	__le16	wNumberMCFilters;
-	u8	bNumberPowerFilters;
-} __attribute__ ((packed));
+#include <linux/usb_cdc.h>
 
 struct cdc_state {
-	struct header_desc	*header;
-	struct union_desc	*u;
-	struct ether_desc	*ether;
-	struct usb_interface	*control;
-	struct usb_interface	*data;
+	struct usb_cdc_header_desc	*header;
+	struct usb_cdc_union_desc	*u;
+	struct usb_cdc_ether_desc	*ether;
+	struct usb_interface		*control;
+	struct usb_interface		*data;
 };
 
 static struct usb_driver usbnet_driver;
@@ -1004,7 +1360,7 @@ static int generic_cdc_bind (struct usbn
 		 * CDC Ethernet achieves with a simple descriptor.
 		 */
 		switch (buf [2]) {
-		case 0x00:		/* Header, mostly useless */
+		case USB_CDC_HEADER_TYPE:
 			if (info->header) {
 				dev_dbg (&intf->dev, "extra CDC header\n");
 				goto bad_desc;
@@ -1016,7 +1372,7 @@ static int generic_cdc_bind (struct usbn
 				goto bad_desc;
 			}
 			break;
-		case 0x06:		/* Union (groups interfaces) */
+		case USB_CDC_UNION_TYPE:
 			if (info->u) {
 				dev_dbg (&intf->dev, "extra CDC union\n");
 				goto bad_desc;
@@ -1065,7 +1421,7 @@ static int generic_cdc_bind (struct usbn
 				goto bad_desc;
 			}
 			break;
-		case 0x0F:		/* Ethernet Networking */
+		case USB_CDC_ETHERNET_TYPE:
 			if (info->ether) {
 				dev_dbg (&intf->dev, "extra CDC ether\n");
 				goto bad_desc;
@@ -1110,6 +1466,29 @@ next_desc:
 		usb_driver_release_interface (&usbnet_driver, info->data);
 		return status;
 	}
+
+	/* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
+	dev->status = NULL;
+	if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
+		struct usb_endpoint_descriptor	*desc;
+
+		dev->status = &info->control->cur_altsetting->endpoint [0];
+		desc = &dev->status->desc;
+		if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
+				|| !(desc->bEndpointAddress & USB_DIR_IN)
+				|| (le16_to_cpu(desc->wMaxPacketSize)
+					< sizeof (struct usb_cdc_notification))
+				|| !desc->bInterval) {
+			dev_dbg (&intf->dev, "bad notification endpoint\n");
+			dev->status = NULL;
+		}
+	}
+	if (rndis && !dev->status) {
+		dev_dbg (&intf->dev, "missing RNDIS status endpoint\n");
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface (&usbnet_driver, info->data);
+		return -ENODEV;
+	}
 	return 0;
 
 bad_desc:
@@ -1147,7 +1526,7 @@ static void cdc_unbind (struct usbnet *d
 /*-------------------------------------------------------------------------
  *
  * Communications Device Class, Ethernet Control model
- * 
+ *
  * Takes two interfaces.  The DATA interface is inactive till an altsetting
  * is selected.  Configuration data includes class descriptors.
  *
@@ -1158,6 +1537,56 @@ static void cdc_unbind (struct usbnet *d
 
 #include <linux/ctype.h>
 
+
+static void dumpspeed (struct usbnet *dev, __le32 *speeds)
+{
+	if (netif_msg_timer (dev))
+		devinfo (dev, "link speeds: %u kbps up, %u kbps down",
+			__le32_to_cpu(speeds[0]) / 1000,
+		__le32_to_cpu(speeds[1]) / 1000);
+}
+
+static void cdc_status (struct usbnet *dev, struct urb *urb)
+{
+	struct usb_cdc_notification	*event;
+
+	if (urb->actual_length < sizeof *event)
+		return;
+	
+	/* SPEED_CHANGE can get split into two 8-byte packets */
+	if (test_and_clear_bit (EVENT_STS_SPLIT, &dev->flags)) {
+		dumpspeed (dev, (__le32 *) urb->transfer_buffer);
+		return;
+	}
+
+	event = urb->transfer_buffer;
+	switch (event->bNotificationType) {
+	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+		if (netif_msg_timer (dev))
+			devdbg (dev, "CDC: carrier %s",
+					event->wValue ? "on" : "off");
+		if (event->wValue)
+			netif_carrier_on(dev->net);
+		else
+			netif_carrier_off(dev->net);
+		break;
+	case USB_CDC_NOTIFY_SPEED_CHANGE:	/* tx/rx rates */
+		if (netif_msg_timer (dev))
+			devdbg (dev, "CDC: speed change (len %d)",
+					urb->actual_length);
+		if (urb->actual_length != (sizeof *event + 8))
+			set_bit (EVENT_STS_SPLIT, &dev->flags);
+		else
+			dumpspeed (dev, (__le32 *) &event[1]);
+		break;
+	// case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:	/* RNDIS; or unsolicited */
+	default:
+		deverr (dev, "CDC: unexpected notification %02x!",
+				 event->bNotificationType);
+		break;
+	}
+}
+
 static u8 nibble (unsigned char c)
 {
 	if (likely (isdigit (c)))
@@ -1169,7 +1598,7 @@ static u8 nibble (unsigned char c)
 }
 
 static inline int
-get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
+get_ethernet_addr (struct usbnet *dev, struct usb_cdc_ether_desc *e)
 {
 	int 		tmp, i;
 	unsigned char	buf [13];
@@ -1216,6 +1645,7 @@ static const struct driver_info	cdc_info
 	// .check_connect = cdc_check_connect,
 	.bind =		cdc_bind,
 	.unbind =	cdc_unbind,
+	.status =	cdc_status,
 };
 
 #endif	/* CONFIG_USB_CDCETHER */
@@ -1321,7 +1751,7 @@ static inline int gl_control_write (stru
 		      0,			// index
 		      0,			// data buffer
 		      0,			// size
-		      CONTROL_TIMEOUT_JIFFIES);
+		      CONTROL_TIMEOUT_MS);
 	return retval;
 }
 
@@ -1602,9 +2032,9 @@ static const struct driver_info	genelink
  */
 
 struct nc_header {		// packed:
-	u16	hdr_len;		// sizeof nc_header (LE, all)
-	u16	packet_len;		// payload size (including ethhdr)
-	u16	packet_id;		// detects dropped packets
+	__le16	hdr_len;		// sizeof nc_header (LE, all)
+	__le16	packet_len;		// payload size (including ethhdr)
+	__le16	packet_id;		// detects dropped packets
 #define MIN_HEADER	6
 
 	// all else is optional, and must start with:
@@ -1615,7 +2045,7 @@ struct nc_header {		// packed:
 #define	PAD_BYTE	((unsigned char)0xAC)
 
 struct nc_trailer {
-	u16	packet_id;
+	__le16	packet_id;
 } __attribute__((__packed__));
 
 // packets may use FLAG_FRAMING_NC and optional pad
@@ -1658,7 +2088,7 @@ nc_vendor_read (struct usbnet *dev, u8 r
 		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		0, regnum,
 		retval_ptr, sizeof *retval_ptr,
-		CONTROL_TIMEOUT_JIFFIES);
+		CONTROL_TIMEOUT_MS);
 	if (status > 0)
 		status = 0;
 	if (!status)
@@ -1682,7 +2112,7 @@ nc_vendor_write (struct usbnet *dev, u8 
 		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		value, regnum,
 		NULL, 0,			// data is in setup packet
-		CONTROL_TIMEOUT_JIFFIES);
+		CONTROL_TIMEOUT_MS);
 }
 
 static inline void
@@ -1747,7 +2177,8 @@ static void nc_dump_registers (struct us
 
 static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl)
 {
-#ifdef DEBUG
+	if (!netif_msg_link (dev))
+		return;
 	devdbg (dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
 			" this%s%s;"
 			" other%s%s; r/o 0x%x",
@@ -1765,7 +2196,6 @@ static inline void nc_dump_usbctl (struc
 		(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
 		usbctl & ~USBCTL_WRITABLE_MASK
 		);
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1792,7 +2222,8 @@ static inline void nc_dump_usbctl (struc
 
 static inline void nc_dump_status (struct usbnet *dev, u16 status)
 {
-#ifdef DEBUG
+	if (!netif_msg_link (dev))
+		return;
 	devdbg (dev, "net1080 %s-%s status 0x%x:"
 			" this (%c) PKT=%d%s%s%s;"
 			" other PKT=%d%s%s%s; unspec 0x%x",
@@ -1815,7 +2246,6 @@ static inline void nc_dump_status (struc
 
 		status & STATUS_UNSPEC_MASK
 		);
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1830,15 +2260,10 @@ static inline void nc_dump_status (struc
 
 static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl)
 {
-#ifdef DEBUG
-	devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
-		dev->udev->bus->bus_name, dev->udev->devpath,
-		ttl,
-
-		TTL_THIS (ttl),
-		TTL_OTHER (ttl)
-		);
-#endif
+	if (netif_msg_link (dev))
+		devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
+			dev->udev->bus->bus_name, dev->udev->devpath,
+			ttl, TTL_THIS (ttl), TTL_OTHER (ttl));
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1860,14 +2285,14 @@ static int net1080_reset (struct usbnet 
 		goto done;
 	}
 	status = *vp;
-	// nc_dump_status (dev, status);
+	nc_dump_status (dev, status);
 
 	if ((retval = nc_register_read (dev, REG_USBCTL, vp)) < 0) {
 		dbg ("can't read USBCTL, %d", retval);
 		goto done;
 	}
 	usbctl = *vp;
-	// nc_dump_usbctl (dev, usbctl);
+	nc_dump_usbctl (dev, usbctl);
 
 	nc_register_write (dev, REG_USBCTL,
 			USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
@@ -1883,7 +2308,7 @@ static int net1080_reset (struct usbnet 
 			MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) );
 	dbg ("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS);
 
-	if (dev->msg_level >= 2)
+	if (netif_msg_link (dev))
 		devinfo (dev, "port %c, peer %sconnected",
 			(status & STATUS_PORT_A) ? 'A' : 'B',
 			(status & STATUS_CONN_OTHER) ? "" : "dis"
@@ -1964,7 +2389,8 @@ static void nc_ensure_sync (struct usbne
 			return;
 		}
 
-		devdbg (dev, "flush net1080; too many framing errors");
+		if (netif_msg_rx_err (dev))
+			devdbg (dev, "flush net1080; too many framing errors");
 		dev->frame_errors = 0;
 	}
 }
@@ -1973,6 +2399,7 @@ static int net1080_rx_fixup (struct usbn
 {
 	struct nc_header	*header;
 	struct nc_trailer	*trailer;
+	u16			hdr_len, packet_len;
 
 	if (!(skb->len & 0x01)
 			|| MIN_FRAMED > skb->len
@@ -1986,50 +2413,50 @@ static int net1080_rx_fixup (struct usbn
 	}
 
 	header = (struct nc_header *) skb->data;
-	le16_to_cpus (&header->hdr_len);
-	le16_to_cpus (&header->packet_len);
-	if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
+	hdr_len = le16_to_cpup (&header->hdr_len);
+	packet_len = le16_to_cpup (&header->packet_len);
+	if (FRAMED_SIZE (packet_len) > MAX_PACKET) {
 		dev->stats.rx_frame_errors++;
-		dbg ("packet too big, %d", header->packet_len);
+		dbg ("packet too big, %d", packet_len);
 		nc_ensure_sync (dev);
 		return 0;
-	} else if (header->hdr_len < MIN_HEADER) {
+	} else if (hdr_len < MIN_HEADER) {
 		dev->stats.rx_frame_errors++;
-		dbg ("header too short, %d", header->hdr_len);
+		dbg ("header too short, %d", hdr_len);
 		nc_ensure_sync (dev);
 		return 0;
-	} else if (header->hdr_len > MIN_HEADER) {
+	} else if (hdr_len > MIN_HEADER) {
 		// out of band data for us?
-		dbg ("header OOB, %d bytes",
-			header->hdr_len - MIN_HEADER);
+		dbg ("header OOB, %d bytes", hdr_len - MIN_HEADER);
 		nc_ensure_sync (dev);
 		// switch (vendor/product ids) { ... }
 	}
-	skb_pull (skb, header->hdr_len);
+	skb_pull (skb, hdr_len);
 
 	trailer = (struct nc_trailer *)
 		(skb->data + skb->len - sizeof *trailer);
 	skb_trim (skb, skb->len - sizeof *trailer);
 
-	if ((header->packet_len & 0x01) == 0) {
-		if (skb->data [header->packet_len] != PAD_BYTE) {
+	if ((packet_len & 0x01) == 0) {
+		if (skb->data [packet_len] != PAD_BYTE) {
 			dev->stats.rx_frame_errors++;
 			dbg ("bad pad");
 			return 0;
 		}
 		skb_trim (skb, skb->len - 1);
 	}
-	if (skb->len != header->packet_len) {
+	if (skb->len != packet_len) {
 		dev->stats.rx_frame_errors++;
 		dbg ("bad packet len %d (expected %d)",
-			skb->len, header->packet_len);
+			skb->len, packet_len);
 		nc_ensure_sync (dev);
 		return 0;
 	}
 	if (header->packet_id != get_unaligned (&trailer->packet_id)) {
 		dev->stats.rx_fifo_errors++;
 		dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
-			header->packet_id, trailer->packet_id);
+			le16_to_cpu (header->packet_id),
+			le16_to_cpu (trailer->packet_id));
 		return 0;
 	}
 #if 0
@@ -2125,7 +2552,7 @@ pl_vendor_req (struct usbnet *dev, u8 re
 		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		val, index,
 		NULL, 0,
-		CONTROL_TIMEOUT_JIFFIES);
+		CONTROL_TIMEOUT_MS);
 }
 
 static inline int
@@ -2221,11 +2648,17 @@ static const struct driver_info	blob_inf
  * For the current version of that driver, the main way that framing is
  * nonstandard (also from perspective of the CDC ethernet model!) is a
  * crc32, added to help detect when some sa1100 usb-to-memory DMA errata
- * haven't been fully worked around.
+ * haven't been fully worked around.  Also, all Zaurii use the same
+ * default Ethernet address.
  *
  * PXA based models use the same framing, and also can't implement
  * set_interface properly.
  *
+ * All known Zaurii lie about their standards conformance.  Most lie by
+ * saying they support CDC Ethernet.  Some lie and say they support CDC
+ * MDLM (as if for access to cell phone modems).  Someone, please beat 
+ * on Sharp (and other such vendors) for a while with a cluestick.
+ *
  *-------------------------------------------------------------------------*/
 
 static struct sk_buff *
@@ -2287,6 +2720,135 @@ static const struct driver_info	olympus_
 };
 #define	OLYMPUS_MXL_INFO	((unsigned long)&olympus_mxl_info)
 
+
+/* Some more recent products using Lineo/Belcarra code will wrongly claim
+ * CDC MDLM conformance.  They aren't conformant:  data endpoints live
+ * in the control interface, there's no data interface, and it's not used
+ * to talk to a cell phone radio.  But at least we can detect these two
+ * pseudo-classes, rather than growing this product list with entries for
+ * each new nonconformant product (sigh).
+ */
+static const u8 safe_guid[16] = {
+	0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+	0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+};
+static const u8 blan_guid[16] = {
+	0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
+	0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
+};
+
+static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf)
+{
+	u8				*buf = intf->cur_altsetting->extra;
+	int				len = intf->cur_altsetting->extralen;
+	struct usb_cdc_mdlm_desc	*desc = NULL;
+	struct usb_cdc_mdlm_detail_desc	*detail = NULL;
+
+	while (len > 3) {
+		if (buf [1] != USB_DT_CS_INTERFACE)
+			goto next_desc;
+
+		/* use bDescriptorSubType, and just verify that we get a
+		 * "BLAN" (or "SAFE") descriptor.
+		 */
+		switch (buf [2]) {
+		case USB_CDC_MDLM_TYPE:
+			if (desc) {
+				dev_dbg (&intf->dev, "extra MDLM\n");
+				goto bad_desc;
+			}
+			desc = (void *) buf;
+			if (desc->bLength != sizeof *desc) {
+				dev_dbg (&intf->dev, "MDLM len %u\n",
+					desc->bLength);
+				goto bad_desc;
+			}
+			/* expect bcdVersion 1.0, ignore */
+			if (memcmp(&desc->bGUID, blan_guid, 16)
+				    && memcmp(&desc->bGUID, safe_guid, 16) ) {
+				/* hey, this one might _really_ be MDLM! */
+				dev_dbg (&intf->dev, "MDLM guid\n");
+				goto bad_desc;
+			}
+			break;
+		case USB_CDC_MDLM_DETAIL_TYPE:
+			if (detail) {
+				dev_dbg (&intf->dev, "extra MDLM detail\n");
+				goto bad_desc;
+			}
+			detail = (void *) buf;
+			switch (detail->bGuidDescriptorType) {
+			case 0:			/* "SAFE" */
+				if (detail->bLength != (sizeof *detail + 2))
+					goto bad_detail;
+				break;
+			case 1:			/* "BLAN" */
+				if (detail->bLength != (sizeof *detail + 3))
+					goto bad_detail;
+				break;
+			default:
+				goto bad_detail;
+			}
+
+			/* assuming we either noticed BLAN already, or will
+			 * find it soon, there are some data bytes here:
+			 *  - bmNetworkCapabilities (unused)
+			 *  - bmDataCapabilities (bits, see below)
+			 *  - bPad (ignored, for PADAFTER -- BLAN-only)
+			 * bits are:
+			 *  - 0x01 -- Zaurus framing (add CRC)
+			 *  - 0x02 -- PADBEFORE (CRC includes some padding)
+			 *  - 0x04 -- PADAFTER (some padding after CRC)
+			 *  - 0x08 -- "fermat" packet mangling (for hw bugs)
+			 * the PADBEFORE appears not to matter; we interop
+			 * with devices that use it and those that don't.
+			 */
+			if ((detail->bDetailData[1] & ~02) != 0x01) {
+				/* bmDataCapabilites == 0 would be fine too,
+				 * but framing is minidriver-coupled for now.
+				 */
+bad_detail:
+				dev_dbg (&intf->dev,
+						"bad MDLM detail, %d %d %d\n",
+						detail->bLength,
+						detail->bDetailData[0],
+						detail->bDetailData[2]);
+				goto bad_desc;
+			}
+			break;
+		}
+next_desc:
+		len -= buf [0];	/* bLength */
+		buf += buf [0];
+	}
+
+	if (!desc || !detail) {
+		dev_dbg (&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
+			desc ? "" : "func ",
+			detail ? "" : "detail ");
+		goto bad_desc;
+	}
+
+	/* There's probably a CDC Ethernet descriptor there, but we can't
+	 * rely on the Ethernet address it provides since not all vendors
+	 * bother to make it unique.  Likewise there's no point in tracking
+	 * of the CDC event notifications.
+	 */
+	return get_endpoints (dev, intf);
+
+bad_desc:
+	dev_info (&dev->udev->dev, "unsupported MDLM descriptors\n");
+	return -ENODEV;
+}
+
+static const struct driver_info	bogus_mdlm_info = {
+	.description =	"pseudo-MDLM (BLAN) device",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+	.bind =		blan_mdlm_bind,
+};
+
 #else
 
 /* blacklist all those devices */
@@ -2402,14 +2964,21 @@ static void rx_submit (struct usbnet *de
 		size = RNDIS_MAX_TRANSFER;
 	else
 #endif
+#ifdef CONFIG_USB_AX8817X
+	if (dev->driver_info->flags & FLAG_FRAMING_AX)
+		size = 2048;
+	else
+#endif
 		size = (sizeof (struct ethhdr) + dev->net->mtu);
 
-	if ((skb = alloc_skb (size, flags)) == NULL) {
-		devdbg (dev, "no rx skb");
+	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+		if (netif_msg_rx_err (dev))
+			devdbg (dev, "no rx skb");
 		defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		return;
 	}
+	skb_reserve (skb, NET_IP_ALIGN);
 
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
@@ -2434,18 +3003,21 @@ static void rx_submit (struct usbnet *de
 			defer_kevent (dev, EVENT_RX_MEMORY);
 			break;
 		case -ENODEV:
-			devdbg (dev, "device gone");
+			if (netif_msg_ifdown (dev))
+				devdbg (dev, "device gone");
 			netif_device_detach (dev->net);
 			break;
 		default:
-			devdbg (dev, "rx submit, %d", retval);
+			if (netif_msg_rx_err (dev))
+				devdbg (dev, "rx submit, %d", retval);
 			tasklet_schedule (&dev->bh);
 			break;
 		case 0:
 			__skb_queue_tail (&dev->rxq, skb);
 		}
 	} else {
-		devdbg (dev, "rx: stopped");
+		if (netif_msg_ifdown (dev))
+			devdbg (dev, "rx: stopped");
 		retval = -ENOLINK;
 	}
 	spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
@@ -2468,7 +3040,8 @@ static inline void rx_process (struct us
 	if (skb->len)
 		skb_return (dev, skb);
 	else {
-		devdbg (dev, "drop");
+		if (netif_msg_rx_err (dev))
+			devdbg (dev, "drop");
 error:
 		dev->stats.rx_errors++;
 		skb_queue_tail (&dev->done, skb);
@@ -2495,7 +3068,8 @@ static void rx_complete (struct urb *urb
 			entry->state = rx_cleanup;
 			dev->stats.rx_errors++;
 			dev->stats.rx_length_errors++;
-			devdbg (dev, "rx length %d", skb->len);
+			if (netif_msg_rx_err (dev))
+				devdbg (dev, "rx length %d", skb->len);
 		}
 		break;
 
@@ -2511,9 +3085,8 @@ static void rx_complete (struct urb *urb
 	    // software-driven interface shutdown
 	    case -ECONNRESET:		// async unlink
 	    case -ESHUTDOWN:		// hardware gone
-#ifdef	VERBOSE
-		devdbg (dev, "rx shutdown, code %d", urb_status);
-#endif
+		if (netif_msg_ifdown (dev))
+			devdbg (dev, "rx shutdown, code %d", urb_status);
 		goto block;
 
 	    // we get controller i/o faults during khubd disconnect() delays.
@@ -2525,7 +3098,8 @@ static void rx_complete (struct urb *urb
 		dev->stats.rx_errors++;
 		if (!timer_pending (&dev->delay)) {
 			mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
-			devdbg (dev, "rx throttle %d", urb_status);
+			if (netif_msg_link (dev))
+				devdbg (dev, "rx throttle %d", urb_status);
 		}
 block:
 		entry->state = rx_cleanup;
@@ -2541,7 +3115,8 @@ block:
 	    default:
 		entry->state = rx_cleanup;
 		dev->stats.rx_errors++;
-		devdbg (dev, "rx status %d", urb_status);
+		if (netif_msg_rx_err (dev))
+			devdbg (dev, "rx status %d", urb_status);
 		break;
 	}
 
@@ -2555,9 +3130,43 @@ block:
 		}
 		usb_free_urb (urb);
 	}
-#ifdef	VERBOSE
-	devdbg (dev, "no read resubmitted");
-#endif /* VERBOSE */
+	if (netif_msg_rx_err (dev))
+		devdbg (dev, "no read resubmitted");
+}
+
+static void intr_complete (struct urb *urb, struct pt_regs *regs)
+{
+	struct usbnet	*dev = urb->context;
+	int		status = urb->status;
+
+	switch (status) {
+	    /* success */
+	    case 0:
+		dev->driver_info->status(dev, urb);
+		break;
+
+	    /* software-driven interface shutdown */
+	    case -ENOENT:		// urb killed
+	    case -ESHUTDOWN:		// hardware gone
+		if (netif_msg_ifdown (dev))
+			devdbg (dev, "intr shutdown, code %d", status);
+		return;
+
+	    /* NOTE:  not throttling like RX/TX, since this endpoint
+	     * already polls infrequently
+	     */
+	    default:
+		devdbg (dev, "intr status %d", status);
+		break;
+	}
+
+	if (!netif_running (dev->net))
+		return;
+
+	memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+	status = usb_submit_urb (urb, GFP_ATOMIC);
+	if (status != 0 && netif_msg_timer (dev))
+		deverr(dev, "intr resubmit --> %d", status);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -2606,7 +3215,7 @@ static int usbnet_stop (struct net_devic
 
 	netif_stop_queue (net);
 
-	if (dev->msg_level >= 2)
+	if (netif_msg_ifdown (dev))
 		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
@@ -2622,11 +3231,14 @@ static int usbnet_stop (struct net_devic
 			&& skb_queue_len (&dev->txq)
 			&& skb_queue_len (&dev->done)) {
 		msleep(UNLINK_TIMEOUT_MS);
-		devdbg (dev, "waited for %d urb completions", temp);
+		if (netif_msg_ifdown (dev))
+			devdbg (dev, "waited for %d urb completions", temp);
 	}
 	dev->wait = NULL;
 	remove_wait_queue (&unlink_wakeup, &wait); 
 
+	usb_kill_urb(dev->interrupt);
+
 	/* deferred work (task, timer, softirq) must also stop.
 	 * can't flush_scheduled_work() until we drop rtnl (later),
 	 * else workers could deadlock; so make workers a NOP.
@@ -2652,21 +3264,34 @@ static int usbnet_open (struct net_devic
 
 	// put into "known safe" state
 	if (info->reset && (retval = info->reset (dev)) < 0) {
-		devinfo (dev, "open reset fail (%d) usbnet usb-%s-%s, %s",
-			retval,
-			dev->udev->bus->bus_name, dev->udev->devpath,
+		if (netif_msg_ifup (dev))
+			devinfo (dev,
+				"open reset fail (%d) usbnet usb-%s-%s, %s",
+				retval,
+				dev->udev->bus->bus_name, dev->udev->devpath,
 			info->description);
 		goto done;
 	}
 
 	// insist peer be connected
 	if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
-		devdbg (dev, "can't open; %d", retval);
+		if (netif_msg_ifup (dev))
+			devdbg (dev, "can't open; %d", retval);
 		goto done;
 	}
 
+	/* start any status interrupt transfer */
+	if (dev->interrupt) {
+		retval = usb_submit_urb (dev->interrupt, GFP_KERNEL);
+		if (retval < 0) {
+			if (netif_msg_ifup (dev))
+				deverr (dev, "intr submit %d", retval);
+			goto done;
+		}
+	}
+
 	netif_start_queue (net);
-	if (dev->msg_level >= 2) {
+	if (netif_msg_ifup (dev)) {
 		char	*framing;
 
 		if (dev->driver_info->flags & FLAG_FRAMING_NC)
@@ -2677,6 +3302,8 @@ static int usbnet_open (struct net_devic
 			framing = "Zaurus";
 		else if (dev->driver_info->flags & FLAG_FRAMING_RN)
 			framing = "RNDIS";
+		else if (dev->driver_info->flags & FLAG_FRAMING_AX)
+			framing = "ASIX";
 		else
 			framing = "simple";
 
@@ -2721,14 +3348,14 @@ static u32 usbnet_get_msglevel (struct n
 {
 	struct usbnet *dev = netdev_priv(net);
 
-	return dev->msg_level;
+	return dev->msg_enable;
 }
 
 static void usbnet_set_msglevel (struct net_device *net, u32 level)
 {
 	struct usbnet *dev = netdev_priv(net);
 
-	dev->msg_level = level;
+	dev->msg_enable = level;
 }
 
 static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
@@ -2761,10 +3388,11 @@ kevent (void *data)
 	if (test_bit (EVENT_TX_HALT, &dev->flags)) {
 		unlink_urbs (dev, &dev->txq);
 		status = usb_clear_halt (dev->udev, dev->out);
-		if (status < 0 && status != -EPIPE)
-			deverr (dev, "can't clear tx halt, status %d",
-				status);
-		else {
+		if (status < 0 && status != -EPIPE) {
+			if (netif_msg_tx_err (dev))
+				deverr (dev, "can't clear tx halt, status %d",
+					status);
+		} else {
 			clear_bit (EVENT_TX_HALT, &dev->flags);
 			netif_wake_queue (dev->net);
 		}
@@ -2772,10 +3400,11 @@ kevent (void *data)
 	if (test_bit (EVENT_RX_HALT, &dev->flags)) {
 		unlink_urbs (dev, &dev->rxq);
 		status = usb_clear_halt (dev->udev, dev->in);
-		if (status < 0 && status != -EPIPE)
-			deverr (dev, "can't clear rx halt, status %d",
-				status);
-		else {
+		if (status < 0 && status != -EPIPE) {
+			if (netif_msg_rx_err (dev))
+				deverr (dev, "can't clear rx halt, status %d",
+					status);
+		} else {
 			clear_bit (EVENT_RX_HALT, &dev->flags);
 			tasklet_schedule (&dev->bh);
 		}
@@ -2796,6 +3425,19 @@ kevent (void *data)
 		}
 	}
 
+	if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
+		struct driver_info 	*info = dev->driver_info;
+		int			retval = 0;
+
+		clear_bit (EVENT_LINK_RESET, &dev->flags);
+		if(info->link_reset && (retval = info->link_reset(dev)) < 0) {
+			devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s",
+				retval,
+				dev->udev->bus->bus_name, dev->udev->devpath,
+				info->description);
+		}
+	}
+
 	if (dev->flags)
 		devdbg (dev, "kevent done, flags = 0x%lx",
 			dev->flags);
@@ -2820,6 +3462,11 @@ static void tx_complete (struct urb *urb
 			defer_kevent (dev, EVENT_TX_HALT);
 			break;
 
+		/* software-driven interface shutdown */
+		case -ECONNRESET:		// async unlink
+		case -ESHUTDOWN:		// hardware gone
+			break;
+
 		// like rx, tx gets controller i/o faults during khubd delays
 		// and so it uses the same throttling mechanism.
 		case -EPROTO:		// ehci
@@ -2828,12 +3475,15 @@ static void tx_complete (struct urb *urb
 			if (!timer_pending (&dev->delay)) {
 				mod_timer (&dev->delay,
 					jiffies + THROTTLE_JIFFIES);
-				devdbg (dev, "tx throttle %d", urb->status);
+				if (netif_msg_link (dev))
+					devdbg (dev, "tx throttle %d",
+							urb->status);
 			}
 			netif_stop_queue (dev->net);
 			break;
 		default:
-			devdbg (dev, "tx err %d", entry->urb->status);
+			if (netif_msg_tx_err (dev))
+				devdbg (dev, "tx err %d", entry->urb->status);
 			break;
 		}
 	}
@@ -2876,14 +3526,16 @@ static int usbnet_start_xmit (struct sk_
 	if (info->tx_fixup) {
 		skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
 		if (!skb) {
-			devdbg (dev, "can't tx_fixup skb");
+			if (netif_msg_tx_err (dev))
+				devdbg (dev, "can't tx_fixup skb");
 			goto drop;
 		}
 	}
 	length = skb->len;
 
 	if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
-		devdbg (dev, "no urb");
+		if (netif_msg_tx_err (dev))
+			devdbg (dev, "no urb");
 		goto drop;
 	}
 
@@ -2941,7 +3593,8 @@ static int usbnet_start_xmit (struct sk_
 		defer_kevent (dev, EVENT_TX_HALT);
 		break;
 	default:
-		devdbg (dev, "tx: submit urb err %d", retval);
+		if (netif_msg_tx_err (dev))
+			devdbg (dev, "tx: submit urb err %d", retval);
 		break;
 	case 0:
 		net->trans_start = jiffies;
@@ -2952,18 +3605,17 @@ static int usbnet_start_xmit (struct sk_
 	spin_unlock_irqrestore (&dev->txq.lock, flags);
 
 	if (retval) {
-		devdbg (dev, "drop, code %d", retval);
+		if (netif_msg_tx_err (dev))
+			devdbg (dev, "drop, code %d", retval);
 drop:
 		retval = NET_XMIT_SUCCESS;
 		dev->stats.tx_dropped++;
 		if (skb)
 			dev_kfree_skb_any (skb);
 		usb_free_urb (urb);
-#ifdef	VERBOSE
-	} else {
+	} else if (netif_msg_tx_queued (dev)) {
 		devdbg (dev, "> tx, len %d, type 0x%x",
 			length, skb->protocol);
-#endif
 	}
 	return retval;
 }
@@ -3020,7 +3672,7 @@ static void usbnet_bh (unsigned long par
 				if (urb != NULL)
 					rx_submit (dev, urb, GFP_ATOMIC);
 			}
-			if (temp != dev->rxq.qlen)
+			if (temp != dev->rxq.qlen && netif_msg_link (dev))
 				devdbg (dev, "rxqlen %d --> %d",
 						temp, dev->rxq.qlen);
 			if (dev->rxq.qlen < qlen)
@@ -3054,9 +3706,10 @@ static void usbnet_disconnect (struct us
 
 	xdev = interface_to_usbdev (intf);
 
-	devinfo (dev, "unregister usbnet usb-%s-%s, %s",
-		xdev->bus->bus_name, xdev->devpath,
-		dev->driver_info->description);
+	if (netif_msg_probe (dev))
+		devinfo (dev, "unregister usbnet usb-%s-%s, %s",
+			xdev->bus->bus_name, xdev->devpath,
+			dev->driver_info->description);
 	
 	net = dev->net;
 	unregister_netdev (net);
@@ -3110,7 +3763,8 @@ usbnet_probe (struct usb_interface *udev
 	dev = netdev_priv(net);
 	dev->udev = xdev;
 	dev->driver_info = info;
-	dev->msg_level = msg_level;
+	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
+				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 	skb_queue_head_init (&dev->rxq);
 	skb_queue_head_init (&dev->txq);
 	skb_queue_head_init (&dev->done);
@@ -3129,7 +3783,7 @@ usbnet_probe (struct usb_interface *udev
 #if 0
 // dma_supported() is deeply broken on almost all architectures
 	// possible with some EHCI controllers
-	if (dma_supported (&udev->dev, 0xffffffffffffffffULL))
+	if (dma_supported (&udev->dev, DMA_64BIT_MASK))
 		net->features |= NETIF_F_HIGHDMA;
 #endif
 
@@ -3166,6 +3820,9 @@ usbnet_probe (struct usb_interface *udev
 			status = 0;
 
 	}
+
+	if (status == 0 && dev->status)
+		status = init_status (dev, udev);
 	if (status < 0)
 		goto out1;
 
@@ -3175,9 +3832,14 @@ usbnet_probe (struct usb_interface *udev
 	status = register_netdev (net);
 	if (status)
 		goto out3;
-	devinfo (dev, "register usbnet at usb-%s-%s, %s",
-		xdev->bus->bus_name, xdev->devpath,
-		dev->driver_info->description);
+	if (netif_msg_probe (dev))
+		devinfo (dev, "register usbnet at usb-%s-%s, %s, "
+				"%02x:%02x:%02x:%02x:%02x:%02x",
+			xdev->bus->bus_name, xdev->devpath,
+			dev->driver_info->description,
+			net->dev_addr [0], net->dev_addr [1],
+			net->dev_addr [2], net->dev_addr [3],
+			net->dev_addr [4], net->dev_addr [5]);
 
 	// ok, it's ready to go.
 	usb_set_intfdata (udev, dev);
@@ -3197,6 +3859,40 @@ out:
 	return status;
 }
 
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+static int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
+{
+	struct usbnet		*dev = usb_get_intfdata(intf);
+	
+	/* accelerate emptying of the rx and queues, to avoid
+	 * having everything error out.
+	 */
+	netif_device_detach (dev->net);
+	(void) unlink_urbs (dev, &dev->rxq);
+	(void) unlink_urbs (dev, &dev->txq);
+	intf->dev.power.power_state = PMSG_SUSPEND;
+	return 0;
+}
+
+static int usbnet_resume (struct usb_interface *intf)
+{
+	struct usbnet		*dev = usb_get_intfdata(intf);
+
+	intf->dev.power.power_state = PMSG_ON;
+	netif_device_attach (dev->net);
+	tasklet_schedule (&dev->bh);
+	return 0;
+}
+
+#else	/* !CONFIG_PM */
+
+#define	usbnet_suspend	NULL
+#define	usbnet_resume	NULL
+
+#endif	/* CONFIG_PM */
 
 /*-------------------------------------------------------------------------*/
 
@@ -3290,6 +3986,10 @@ static const struct usb_device_id	produc
 	// goodway corp usb gwusb2e
 	USB_DEVICE (0x1631, 0x6200),
 	.driver_info = (unsigned long) &ax8817x_info,
+}, {
+	// ASIX AX88772 10/100
+        USB_DEVICE (0x0b95, 0x7720),
+        .driver_info = (unsigned long) &ax88772_info,
 },
 #endif
 
@@ -3374,6 +4074,7 @@ static const struct usb_device_id	produc
 	.driver_info =	(unsigned long) &blob_info,
 }, {
 	// Linux Ethernet/RNDIS gadget on pxa210/25x/26x
+	// e.g. Gumstix, current OpenZaurus, ...
 	USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
 	.driver_info =	(unsigned long) &linuxdev_info,
 }, 
@@ -3385,76 +4086,82 @@ static const struct usb_device_id	produc
  * Same idea as above, but different framing.
  *
  * PXA-2xx based models are also lying-about-cdc.
+ * Some models don't even tell the same lies ...
+ *
+ * NOTE:  OpenZaurus versions with 2.6 kernels won't use these entries,
+ * unlike the older ones with 2.4 "embedix" kernels.
  *
  * NOTE:  These entries do double-duty, serving as blacklist entries
  * whenever Zaurus support isn't enabled, but CDC Ethernet is.
  */
+#define	ZAURUS_MASTER_INTERFACE \
+	.bInterfaceClass	= USB_CLASS_COMM, \
+	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
+	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
 {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
 	.idProduct		= 0x8004,
-	/* match the master interface */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol	= 0,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_STRONGARM_INFO,
 }, {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
 	.idProduct		= 0x8005,	/* A-300 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol	= 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
 	.idProduct		= 0x8006,	/* B-500/SL-5600 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol	= 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 	          | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor		= 0x04DD,
 	.idProduct		= 0x8007,	/* C-700 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol = 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	.idProduct              = 0x9031,	/* C-750 C-760 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol     = 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	.idProduct              = 0x9032,	/* SL-6000 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol     = 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
+	/* reported with some C860 units */
 	.idProduct              = 0x9050,	/* C-860 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol     = 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 },
 
+#ifdef	CONFIG_USB_ZAURUS
+	/* At least some (reports vary) PXA units have very different lies
+	 * about their standards support:  they claim to be cell phones with
+	 * direct access to their radios.  (They don't conform to CDC MDLM.)
+	 */
+{
+	USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
+			USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long) &bogus_mdlm_info,
+},
+#endif
+
 /* Olympus has some models with a Zaurus-compatible option.
  * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
  */
@@ -3463,9 +4170,7 @@ static const struct usb_device_id	produc
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x07B4,
 	.idProduct              = 0x0F02,	/* R-1000 */
-	.bInterfaceClass	= USB_CLASS_COMM,
-	.bInterfaceSubClass	= 6 /* Ethernet model */,
-	.bInterfaceProtocol     = 0x00,
+	ZAURUS_MASTER_INTERFACE,
 	.driver_info = OLYMPUS_MXL_INFO,
 },
 #endif
@@ -3480,7 +4185,8 @@ static const struct usb_device_id	produc
 	 * NOTE:  this match must come AFTER entries working around
 	 * bugs/quirks in a given product (like Zaurus, above).
 	 */
-	USB_INTERFACE_INFO (USB_CLASS_COMM, 6 /* Ethernet model */, 0),
+	USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
+			USB_CDC_PROTO_NONE),
 	.driver_info = (unsigned long) &cdc_info,
 },
 #endif
@@ -3495,6 +4201,8 @@ static struct usb_driver usbnet_driver =
 	.id_table =	products,
 	.probe =	usbnet_probe,
 	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
 };
 
 /* Default ethtool_ops assigned.  Devices can override in their bind() routine */
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/net/zd1201.c
@@ -0,0 +1,1906 @@
+/*
+ *	Driver for ZyDAS zd1201 based wireless USB devices.
+ *
+ *	Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.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.
+ *
+ *	Parts of this driver have been derived from a wlan-ng version
+ *	modified by ZyDAS. They also made documentation available, thanks!
+ *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/string.h>
+#include <linux/if_arp.h>
+#include <linux/firmware.h>
+#include <ieee802_11.h>
+#include "zd1201.h"
+
+static struct usb_device_id zd1201_table[] = {
+	{USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */
+	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
+	{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb  adapter */
+	{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb  adapter */
+	{}
+};
+
+static int ap = 0;	/* Are we an AP or a normal station? */
+
+#define ZD1201_VERSION	"0.15"
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters");
+MODULE_VERSION(ZD1201_VERSION);
+MODULE_LICENSE("GPL");
+module_param(ap, int, 0);
+MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded");
+MODULE_DEVICE_TABLE(usb, zd1201_table);
+
+
+static int zd1201_fw_upload(struct usb_device *dev, int apfw)
+{
+	const struct firmware *fw_entry;
+	char* data;
+	unsigned long len;
+	int err;
+	unsigned char ret;
+	char *buf;
+	char *fwfile;
+
+	if (apfw)
+		fwfile = "zd1201-ap.fw";
+	else
+		fwfile = "zd1201.fw";
+
+	err = request_firmware(&fw_entry, fwfile, &dev->dev);
+	if (err) {
+		dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile);
+		dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n");
+		dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info\n");
+		return err;
+	}
+
+	data = fw_entry->data;
+        len = fw_entry->size;
+
+	buf = kmalloc(1024, GFP_ATOMIC);
+	if (!buf)
+		goto exit;
+	
+	while (len > 0) {
+		int translen = (len > 1024) ? 1024 : len;
+		memcpy(buf, data, translen);
+
+		err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0,
+		    USB_DIR_OUT | 0x40, 0, 0, buf, translen,
+		    ZD1201_FW_TIMEOUT);
+		if (err < 0)
+			goto exit;
+
+		len -= translen;
+		data += translen;
+	}
+                                        
+	err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2,
+	    USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT);
+	if (err < 0)
+		goto exit;
+                                                                                                                                                                
+	err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
+	    USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
+	if (err < 0)
+		goto exit;
+                                                                                                                                                                                                                                                                                        
+	if (ret & 0x80) {
+		err = -EIO;
+		goto exit;
+	}
+
+	err = 0;
+exit:
+	kfree(buf);
+	release_firmware(fw_entry);
+	return err;
+}
+
+static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
+{
+	struct zd1201 *zd = urb->context;
+
+	switch(urb->status) {
+		case -EILSEQ:
+		case -ENODEV:
+		case -ETIMEDOUT:
+		case -ENOENT:
+		case -EPIPE:
+		case -EOVERFLOW:
+		case -ESHUTDOWN:
+			dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", 
+			    zd->dev->name, urb->status);
+	}
+
+	kfree(urb->transfer_buffer);
+	usb_free_urb(urb);
+	return;
+}
+
+/* cmdreq message: 
+	u32 type
+	u16 cmd
+	u16 parm0
+	u16 parm1
+	u16 parm2
+	u8  pad[4]
+
+	total: 4 + 2 + 2 + 2 + 2 + 4 = 16
+*/
+static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
+			int parm1, int parm2)
+{
+	unsigned char *command;
+	int ret;
+	struct urb *urb;
+
+	command = kmalloc(16, GFP_ATOMIC);
+	if (!command)
+		return -ENOMEM;
+
+	*((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ);
+	*((__le16*)&command[4]) = cpu_to_le16(cmd);
+	*((__le16*)&command[6]) = cpu_to_le16(parm0);
+	*((__le16*)&command[8]) = cpu_to_le16(parm1);
+	*((__le16*)&command[10])= cpu_to_le16(parm2);
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree(command);
+		return -ENOMEM;
+	}
+	usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
+	     command, 16, zd1201_usbfree, zd);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		kfree(command);
+		usb_free_urb(urb);
+	}
+	
+	return ret;
+}
+
+/* Callback after sending out a packet */
+static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
+{
+	struct zd1201 *zd = urb->context;
+	netif_wake_queue(zd->dev);
+	return;
+}
+
+/* Incoming data */
+static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
+{
+	struct zd1201 *zd = urb->context;
+	int free = 0;
+	unsigned char *data = urb->transfer_buffer;
+	struct sk_buff *skb;
+	unsigned char type;
+
+	if (!zd) {
+		free = 1;
+		goto exit;
+	}
+
+	switch(urb->status) {
+		case -EILSEQ:
+		case -ENODEV:
+		case -ETIMEDOUT:
+		case -ENOENT:
+		case -EPIPE:
+		case -EOVERFLOW:
+		case -ESHUTDOWN:
+			dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n",
+			    zd->dev->name, urb->status);
+			free = 1;
+			goto exit;
+	}
+	
+	if (urb->status != 0 || urb->actual_length == 0)
+		goto resubmit;
+
+	type = data[0];
+	if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) {
+		memcpy(zd->rxdata, data, urb->actual_length);
+		zd->rxlen = urb->actual_length;
+		zd->rxdatas = 1;
+		wake_up(&zd->rxdataq);
+	}
+	/* Info frame */
+	if (type == ZD1201_PACKET_INQUIRE) {
+		int i = 0;
+		unsigned short infotype, framelen, copylen;
+		framelen = le16_to_cpu(*(__le16*)&data[4]);
+		infotype = le16_to_cpu(*(__le16*)&data[6]);
+
+		if (infotype == ZD1201_INF_LINKSTATUS) {
+			short linkstatus;
+
+			linkstatus = le16_to_cpu(*(__le16*)&data[8]);
+			switch(linkstatus) {
+				case 1:
+					netif_carrier_on(zd->dev);
+					break;
+				case 2:
+					netif_carrier_off(zd->dev);
+					break;
+				case 3:
+					netif_carrier_off(zd->dev);
+					break;
+				case 4:
+					netif_carrier_on(zd->dev);
+					break;
+				default:
+					netif_carrier_off(zd->dev);
+			}
+			goto resubmit;
+		}
+		if (infotype == ZD1201_INF_ASSOCSTATUS) {
+			short status = le16_to_cpu(*(__le16*)(data+8));
+			int event;
+			union iwreq_data wrqu;
+
+			switch (status) {
+				case ZD1201_ASSOCSTATUS_STAASSOC:
+				case ZD1201_ASSOCSTATUS_REASSOC:
+					event = IWEVREGISTERED;
+					break;
+				case ZD1201_ASSOCSTATUS_DISASSOC:
+				case ZD1201_ASSOCSTATUS_ASSOCFAIL:
+				case ZD1201_ASSOCSTATUS_AUTHFAIL:
+				default:
+					event = IWEVEXPIRED;
+			}
+			memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN);
+			wrqu.addr.sa_family = ARPHRD_ETHER;
+
+			/* Send event to user space */
+			wireless_send_event(zd->dev, event, &wrqu, NULL);
+
+			goto resubmit;
+		}
+		if (infotype == ZD1201_INF_AUTHREQ) {
+			union iwreq_data wrqu;
+
+			memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN);
+			wrqu.addr.sa_family = ARPHRD_ETHER;
+			/* There isn't a event that trully fits this request.
+			   We assume that userspace will be smart enough to
+			   see a new station being expired and sends back a
+			   authstation ioctl to authorize it. */
+			wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL);
+			goto resubmit;
+		}
+		/* Other infotypes are handled outside this handler */
+		zd->rxlen = 0;
+		while (i < urb->actual_length) {
+			copylen = le16_to_cpu(*(__le16*)&data[i+2]);
+			/* Sanity check, sometimes we get junk */
+			if (copylen+zd->rxlen > sizeof(zd->rxdata))
+				break;
+			memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen);
+			zd->rxlen += copylen;
+			i += 64;
+		}
+		if (i >= urb->actual_length) {
+			zd->rxdatas = 1;
+			wake_up(&zd->rxdataq);
+		}
+		goto  resubmit;
+	}
+	/* Actual data */
+	if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) {
+		int datalen = urb->actual_length-1;
+		unsigned short len, fc, seq;
+		struct hlist_node *node;
+
+		len = ntohs(*(__be16 *)&data[datalen-2]);
+		if (len>datalen)
+			len=datalen;
+		fc = le16_to_cpu(*(__le16 *)&data[datalen-16]);
+		seq = le16_to_cpu(*(__le16 *)&data[datalen-24]);
+
+		if(zd->monitor) {
+			if (datalen < 24)
+				goto resubmit;
+			if (!(skb = dev_alloc_skb(datalen+24)))
+				goto resubmit;
+			
+			memcpy(skb_put(skb, 2), &data[datalen-16], 2);
+			memcpy(skb_put(skb, 2), &data[datalen-2], 2);
+			memcpy(skb_put(skb, 6), &data[datalen-14], 6);
+			memcpy(skb_put(skb, 6), &data[datalen-22], 6);
+			memcpy(skb_put(skb, 6), &data[datalen-8], 6);
+			memcpy(skb_put(skb, 2), &data[datalen-24], 2);
+			memcpy(skb_put(skb, len), data, len);
+			skb->dev = zd->dev;
+			skb->dev->last_rx = jiffies;
+			skb->protocol = eth_type_trans(skb, zd->dev);
+			zd->stats.rx_packets++;
+			zd->stats.rx_bytes += skb->len;
+			netif_rx(skb);
+			goto resubmit;
+		}
+			
+		if ((seq & IEEE802_11_SCTL_FRAG) ||
+		    (fc & IEEE802_11_FCTL_MOREFRAGS)) {
+			struct zd1201_frag *frag = NULL;
+			char *ptr;
+
+			if (datalen<14)
+				goto resubmit;
+			if ((seq & IEEE802_11_SCTL_FRAG) == 0) {
+				frag = kmalloc(sizeof(struct zd1201_frag*),
+				    GFP_ATOMIC);
+				if (!frag)
+					goto resubmit;
+				skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2);
+				if (!skb) {
+					kfree(frag);
+					goto resubmit;
+				}
+				frag->skb = skb;
+				frag->seq = seq & IEEE802_11_SCTL_SEQ;
+				skb_reserve(skb, 2);
+				memcpy(skb_put(skb, 12), &data[datalen-14], 12);
+				memcpy(skb_put(skb, 2), &data[6], 2);
+				memcpy(skb_put(skb, len), data+8, len);
+				hlist_add_head(&frag->fnode, &zd->fraglist);
+				goto resubmit;
+			}
+			hlist_for_each_entry(frag, node, &zd->fraglist, fnode)
+				if(frag->seq == (seq&IEEE802_11_SCTL_SEQ))
+					break;
+			if (!frag)
+				goto resubmit;
+			skb = frag->skb;
+			ptr = skb_put(skb, len);
+			if (ptr)
+				memcpy(ptr, data+8, len);
+			if (fc & IEEE802_11_FCTL_MOREFRAGS)
+				goto resubmit;
+			hlist_del_init(&frag->fnode);
+			kfree(frag);
+			/* Fallthrough */
+		} else {
+			if (datalen<14)
+				goto resubmit;
+			skb = dev_alloc_skb(len + 14 + 2);
+			if (!skb)
+				goto resubmit;
+			skb_reserve(skb, 2);
+			memcpy(skb_put(skb, 12), &data[datalen-14], 12);
+			memcpy(skb_put(skb, 2), &data[6], 2);
+			memcpy(skb_put(skb, len), data+8, len);
+		}
+		skb->dev = zd->dev;
+		skb->dev->last_rx = jiffies;
+		skb->protocol = eth_type_trans(skb, zd->dev);
+		zd->stats.rx_packets++;
+		zd->stats.rx_bytes += skb->len;
+		netif_rx(skb);
+	}
+resubmit:
+	memset(data, 0, ZD1201_RXSIZE);
+
+	urb->status = 0;
+	urb->dev = zd->usb;
+	if(usb_submit_urb(urb, GFP_ATOMIC))
+		free = 1;
+
+exit:
+	if (free) {
+		zd->rxlen = 0;
+		zd->rxdatas = 1;
+		wake_up(&zd->rxdataq);
+		kfree(urb->transfer_buffer);
+	}
+	return;
+}
+
+static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
+	unsigned int riddatalen)
+{
+	int err;
+	int i = 0;
+	int code;
+	int rid_fid;
+	int length;
+	unsigned char *pdata;
+	
+	zd->rxdatas = 0;
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0);
+	if (err)
+		return err;
+
+	wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+	if (!zd->rxlen)
+		return -EIO;
+
+	code = le16_to_cpu(*(__le16*)(&zd->rxdata[4]));
+	rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6]));
+	length = le16_to_cpu(*(__le16*)(&zd->rxdata[8]));
+	if (length > zd->rxlen)
+		length = zd->rxlen-6;
+
+	/* If access bit is not on, then error */
+	if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid )
+		return -EINVAL;
+
+	/* Not enough buffer for allocating data */
+	if (riddatalen != (length - 4)) {
+		dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n",
+		    riddatalen, zd->rxlen, length, rid, rid_fid);
+		return -ENODATA;
+	}
+
+	zd->rxdatas = 0;
+	/* Issue SetRxRid commnd */			
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length);
+	if (err)
+		return err;
+
+	/* Receive RID record from resource packets */
+	wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+	if (!zd->rxlen)
+		return -EIO;
+
+	if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) {
+		dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n",
+		    zd->rxdata[zd->rxlen-1]);
+		return -EINVAL;
+	}
+
+	/* Set the data pointer and received data length */
+	pdata = zd->rxdata;
+	length = zd->rxlen;
+
+	do {
+		int  actual_length;
+
+		actual_length = (length > 64) ? 64 : length;
+
+		if(pdata[0] != 0x3) {
+			dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n",
+			    pdata[0]);
+			return -EINVAL;
+		}
+
+		if (actual_length != 64) {
+			/* Trim the last packet type byte */
+			actual_length--;
+		}
+
+		/* Skip the 4 bytes header (RID length and RID) */
+		if(i == 0) {
+			pdata += 8;
+			actual_length -= 8;
+		}
+		else {
+			pdata += 4;
+			actual_length -= 4;
+		}
+		
+		memcpy(riddata, pdata, actual_length);
+		riddata += actual_length;
+		pdata += actual_length;
+		length -= 64;
+		i++;
+	} while (length > 0);
+
+	return 0;
+}
+
+/*
+ *	resreq:
+ *		byte	type
+ *		byte	sequence
+ *		u16	reserved
+ *		byte	data[12]
+ *	total: 16
+ */
+static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int wait)
+{
+	int err;
+	unsigned char *request;
+	int reqlen;
+	char seq=0;
+	struct urb *urb;
+	unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC;
+
+	len += 4;			/* first 4 are for header */
+
+	zd->rxdatas = 0;
+	zd->rxlen = 0;
+	for (seq=0; len > 0; seq++) {
+		request = kmalloc(16, gfp_mask);
+		if (!request)
+			return -ENOMEM;
+		urb = usb_alloc_urb(0, gfp_mask);
+		if (!urb) {
+			kfree(request);
+			return -ENOMEM;
+		}
+		memset(request, 0, 16);
+		reqlen = len>12 ? 12 : len;
+		request[0] = ZD1201_USB_RESREQ;
+		request[1] = seq;
+		request[2] = 0;
+		request[3] = 0;
+		if (request[1] == 0) {
+			/* add header */
+			*(__le16*)&request[4] = cpu_to_le16((len-2+1)/2);
+			*(__le16*)&request[6] = cpu_to_le16(rid);
+			memcpy(request+8, buf, reqlen-4);
+			buf += reqlen-4;
+		} else {
+			memcpy(request+4, buf, reqlen);
+			buf += reqlen;
+		}
+
+		len -= reqlen;
+
+		usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb,
+		    zd->endp_out2), request, 16, zd1201_usbfree, zd);
+		err = usb_submit_urb(urb, gfp_mask);
+		if (err)
+			goto err;
+	}
+
+	request = kmalloc(16, gfp_mask);
+	if (!request)
+		return -ENOMEM;
+	urb = usb_alloc_urb(0, gfp_mask);
+	if (!urb) {
+		kfree(request);
+		return -ENOMEM;
+	}
+	*((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ);
+	*((__le16*)&request[4]) = 
+	    cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT);
+	*((__le16*)&request[6]) = cpu_to_le16(rid);
+	*((__le16*)&request[8]) = cpu_to_le16(0);
+	*((__le16*)&request[10]) = cpu_to_le16(0);
+	usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
+	     request, 16, zd1201_usbfree, zd);
+	err = usb_submit_urb(urb, gfp_mask);
+	if (err)
+		goto err;
+	
+	if (wait) {
+		wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+		if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) {
+			dev_dbg(&zd->usb->dev, "wrong or no RID received\n");
+		}
+	}
+
+	return 0;
+err:
+	kfree(request);
+	usb_free_urb(urb);
+	return err;
+}
+
+static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val)
+{
+	int err;
+	__le16 zdval;
+
+	err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16));
+	if (err)
+		return err;
+	*val = le16_to_cpu(zdval);
+	return 0;
+}
+
+static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val)
+{
+	__le16 zdval = cpu_to_le16(val);
+	return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1));
+}
+
+static int zd1201_drvr_start(struct zd1201 *zd)
+{
+	int err, i;
+	short max;
+	__le16 zdmax;
+	unsigned char *buffer;
+	
+	buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	memset(buffer, 0, ZD1201_RXSIZE);
+
+	usb_fill_bulk_urb(zd->rx_urb, zd->usb, 
+	    usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
+	    zd1201_usbrx, zd);
+
+	err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);
+	if (err)
+		goto err_buffer;
+	
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
+	if (err)
+		goto err_urb;
+
+	err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax,
+	    sizeof(__le16));
+	if (err)
+		goto err_urb;
+
+	max = le16_to_cpu(zdmax);
+	for (i=0; i<max; i++) {
+		err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0);
+		if (err)
+			goto err_urb;
+	}
+
+	return 0;
+
+err_urb:
+	usb_kill_urb(zd->rx_urb);
+	return err;
+err_buffer:
+	kfree(buffer);
+	return err;
+}
+
+/*	Magic alert: The firmware doesn't seem to like the MAC state being
+ *	toggled in promisc (aka monitor) mode.
+ *	(It works a number of times, but will halt eventually)
+ *	So we turn it of before disabling and on after enabling if needed.
+ */
+static int zd1201_enable(struct zd1201 *zd)
+{
+	int err;
+
+	if (zd->mac_enabled)
+		return 0;
+
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0);
+	if (!err)
+		zd->mac_enabled = 1;
+
+	if (zd->monitor)
+		err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1);
+
+	return err;
+}
+
+static int zd1201_disable(struct zd1201 *zd)
+{
+	int err;
+	
+	if (!zd->mac_enabled)
+		return 0;
+	if (zd->monitor) {
+		err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
+		if (err)
+			return err;
+	}
+
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0);
+	if (!err)
+		zd->mac_enabled = 0;
+	return err;
+}
+
+static int zd1201_mac_reset(struct zd1201 *zd)
+{
+	if (!zd->mac_enabled)
+		return 0;
+	zd1201_disable(zd);
+	return zd1201_enable(zd);
+}
+
+static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
+{
+	int err, val;
+	char buf[IW_ESSID_MAX_SIZE+2];
+
+	err = zd1201_disable(zd);
+	if (err)
+		return err;
+
+	val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
+	val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY;
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val);
+	if (err)
+		return err;
+
+	*(__le16 *)buf = cpu_to_le16(essidlen);
+	memcpy(buf+2, essid, essidlen);
+	if (!zd->ap) {	/* Normal station */
+		err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
+		    IW_ESSID_MAX_SIZE+2, 1);
+		if (err)
+			return err;
+	} else {	/* AP */
+		err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf,
+		    IW_ESSID_MAX_SIZE+2, 1);
+		if (err)
+			return err;
+	}
+
+	err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
+	    zd->dev->dev_addr, zd->dev->addr_len, 1);
+	if (err)
+		return err;
+
+	err = zd1201_enable(zd);
+	if (err)
+		return err;
+
+	msleep(100);
+	return 0;
+}
+
+static int zd1201_net_open(struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	/* Start MAC with wildcard if no essid set */
+	if (!zd->mac_enabled)
+		zd1201_join(zd, zd->essid, zd->essidlen);
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int zd1201_net_stop(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	
+	return 0;
+}
+
+/*
+	RFC 1042 encapsulates Ethernet frames in 802.11 frames
+	by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0
+	(0x00, 0x00, 0x00). Zd requires an additional padding, copy
+	of ethernet addresses, length of the standard RFC 1042 packet
+	and a command byte (which is nul for tx).
+	
+	tx frame (from Wlan NG):
+	RFC 1042:
+		llc		0xAA 0xAA 0x03 (802.2 LLC)
+		snap		0x00 0x00 0x00 (Ethernet encapsulated)
+		type		2 bytes, Ethernet type field
+		payload		(minus eth header)
+	Zydas specific:
+		padding		1B if (skb->len+8+1)%64==0
+		Eth MAC addr	12 bytes, Ethernet MAC addresses
+		length		2 bytes, RFC 1042 packet length 
+				(llc+snap+type+payload)
+		zd		1 null byte, zd1201 packet type
+ */
+static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	unsigned char *txbuf = zd->txdata;
+	int txbuflen, pad = 0, err;
+	struct urb *urb = zd->tx_urb;
+
+	if (!zd->mac_enabled || zd->monitor) {
+		zd->stats.tx_dropped++;
+		kfree_skb(skb);
+		return 0;
+	}
+	netif_stop_queue(dev);
+
+	txbuflen = skb->len + 8 + 1;
+	if (txbuflen%64 == 0) {
+		pad = 1;
+		txbuflen++;
+	}
+	txbuf[0] = 0xAA;
+	txbuf[1] = 0xAA;
+	txbuf[2] = 0x03;
+	txbuf[3] = 0x00;	/* rfc1042 */
+	txbuf[4] = 0x00;
+	txbuf[5] = 0x00;
+
+	memcpy(txbuf+6, skb->data+12, skb->len-12);
+	if (pad)
+		txbuf[skb->len-12+6]=0;
+	memcpy(txbuf+skb->len-12+6+pad, skb->data, 12);
+	*(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
+	txbuf[txbuflen-1] = 0;
+
+	usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out),
+	    txbuf, txbuflen, zd1201_usbtx, zd);
+
+	err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
+	if (err) {
+		zd->stats.tx_errors++;
+		netif_start_queue(dev);
+		return err;
+	}
+	zd->stats.tx_packets++;
+	zd->stats.tx_bytes += skb->len;
+	dev->trans_start = jiffies;
+	kfree_skb(skb);
+
+	return 0;
+}
+
+static void zd1201_tx_timeout(struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	if (!zd)
+		return;
+	dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
+	    dev->name);
+	zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
+	usb_unlink_urb(zd->tx_urb);
+	zd->stats.tx_errors++;
+	/* Restart the timeout to quiet the watchdog: */
+	dev->trans_start = jiffies;
+}
+
+static int zd1201_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err;
+
+	if (!zd)
+		return -ENODEV;
+
+	err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
+	    addr->sa_data, dev->addr_len, 1);
+	if (err)
+		return err;
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	return zd1201_mac_reset(zd);
+}
+
+static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	return &zd->stats;
+}
+
+static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	return &zd->iwstats;
+}
+
+static void zd1201_set_multicast(struct net_device *dev)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct dev_mc_list *mc = dev->mc_list;
+	unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
+	int i;
+
+	if (dev->mc_count > ZD1201_MAXMULTI)
+		return;
+
+	for (i=0; i<dev->mc_count; i++) {
+		memcpy(reqbuf+i*ETH_ALEN, mc->dmi_addr, ETH_ALEN);
+		mc = mc->next;
+	}
+	zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
+	    dev->mc_count*ETH_ALEN, 0);
+	
+}
+
+static int zd1201_config_commit(struct net_device *dev, 
+    struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_name(struct net_device *dev,
+    struct iw_request_info *info, char *name, char *extra)
+{
+	strcpy(name, "IEEE 802.11b");
+
+	return 0;
+}
+
+static int zd1201_set_freq(struct net_device *dev,
+    struct iw_request_info *info, struct iw_freq *freq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short channel = 0;
+	int err;
+
+	if (freq->e == 0)
+		channel = freq->m;
+	else {
+		if (freq->m >= 2482)
+			channel = 14;
+		if (freq->m >= 2407)
+			channel = (freq->m-2407)/5;
+	}
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
+	if (err)
+		return err;
+
+	zd1201_mac_reset(zd);
+
+	return 0;
+}
+
+static int zd1201_get_freq(struct net_device *dev,
+    struct iw_request_info *info, struct iw_freq *freq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short channel;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel);
+	if (err)
+		return err;
+	freq->e = 0;
+	freq->m = channel;
+
+	return 0;
+}
+
+static int zd1201_set_mode(struct net_device *dev,
+    struct iw_request_info *info, __u32 *mode, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short porttype, monitor = 0;
+	unsigned char buffer[IW_ESSID_MAX_SIZE+2];
+	int err;
+
+	if (zd->ap) {
+		if (*mode != IW_MODE_MASTER)
+			return -EINVAL;
+		return 0;
+	}
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
+	if (err)
+		return err;
+	zd->dev->type = ARPHRD_ETHER;
+	switch(*mode) {
+		case IW_MODE_MONITOR:
+			monitor = 1;
+			zd->dev->type = ARPHRD_IEEE80211;
+			/* Make sure we are no longer associated with by
+			   setting an 'impossible' essid.
+			   (otherwise we mess up firmware)
+			 */
+			zd1201_join(zd, "\0-*#\0", 5);
+			/* Put port in pIBSS */
+		case 8: /* No pseudo-IBSS in wireless extensions (yet) */
+			porttype = ZD1201_PORTTYPE_PSEUDOIBSS;
+			break;
+		case IW_MODE_ADHOC:
+			porttype = ZD1201_PORTTYPE_IBSS;
+			break;
+		case IW_MODE_INFRA:
+			porttype = ZD1201_PORTTYPE_BSS;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
+	if (err)
+		return err;
+	if (zd->monitor && !monitor) {
+			zd1201_disable(zd);
+			*(__le16 *)buffer = cpu_to_le16(zd->essidlen);
+			memcpy(buffer+2, zd->essid, zd->essidlen);
+			err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID,
+			    buffer, IW_ESSID_MAX_SIZE+2, 1);
+			if (err)
+				return err;
+	}
+	zd->monitor=monitor;
+	/* If monitor mode is set we don't actually turn it on here since it
+	 * is done during mac reset anyway (see zd1201_mac_enable).
+	 */
+
+	zd1201_mac_reset(zd);
+
+	return 0;
+}
+
+static int zd1201_get_mode(struct net_device *dev,
+    struct iw_request_info *info, __u32 *mode, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short porttype;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype);
+	if (err)
+		return err;
+	switch(porttype) {
+		case ZD1201_PORTTYPE_IBSS:
+			*mode = IW_MODE_ADHOC;
+			break;
+		case ZD1201_PORTTYPE_BSS:
+			*mode = IW_MODE_INFRA;
+			break;
+		case ZD1201_PORTTYPE_WDS:
+			*mode = IW_MODE_REPEAT;
+			break;
+		case ZD1201_PORTTYPE_PSEUDOIBSS:
+			*mode = 8;/* No Pseudo-IBSS... */
+			break;
+		case ZD1201_PORTTYPE_AP:
+			*mode = IW_MODE_MASTER;
+			break;
+		default:
+			dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n",
+			    porttype);
+			*mode = IW_MODE_AUTO;
+	}
+	if (zd->monitor)
+		*mode = IW_MODE_MONITOR;
+
+	return 0;
+}
+
+static int zd1201_get_range(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *wrq, char *extra)
+{
+	struct iw_range *range = (struct iw_range *)extra;
+
+	wrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = WIRELESS_EXT;
+
+	range->max_qual.qual = 128;
+	range->max_qual.level = 128;
+	range->max_qual.noise = 128;
+	range->max_qual.updated = 7;
+
+	range->encoding_size[0] = 5;
+	range->encoding_size[1] = 13;
+	range->num_encoding_sizes = 2;
+	range->max_encoding_tokens = ZD1201_NUMKEYS;
+
+	range->num_bitrates = 4;
+	range->bitrate[0] = 1000000;
+	range->bitrate[1] = 2000000;
+	range->bitrate[2] = 5500000;
+	range->bitrate[3] = 11000000;
+
+	range->min_rts = 0;
+	range->min_frag = ZD1201_FRAGMIN;
+	range->max_rts = ZD1201_RTSMAX;
+	range->min_frag = ZD1201_FRAGMAX;
+
+	return 0;
+}
+
+/*	Little bit of magic here: we only get the quality if we poll
+ *	for it, and we never get an actual request to trigger such
+ *	a poll. Therefore we 'assume' that the user will soon ask for
+ *	the stats after asking the bssid.
+ */
+static int zd1201_get_wap(struct net_device *dev,
+    struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	unsigned char buffer[6];
+
+	if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
+		/* Unfortunately the quality and noise reported is useless.
+		   they seem to be accumulators that increase until you
+		   read them, unless we poll on a fixed interval we can't
+		   use them
+		 */
+		/*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/
+		zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]);
+		/*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/
+		zd->iwstats.qual.updated = 2;
+	}
+
+	return zd1201_getconfig(zd,ZD1201_RID_CURRENTBSSID,ap_addr->sa_data,6);
+}
+
+static int zd1201_set_scan(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *srq, char *extra)
+{
+	/* We do everything in get_scan */
+	return 0;
+}
+
+static int zd1201_get_scan(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *srq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err, i, j, enabled_save;
+	struct iw_event iwe;
+	char *cev = extra;
+	char *end_buf = extra + IW_SCAN_MAX_DATA;
+
+	/* No scanning in AP mode */
+	if (zd->ap)
+		return -EOPNOTSUPP;
+
+	/* Scan doesn't seem to work if disabled */
+	enabled_save = zd->mac_enabled;
+	zd1201_enable(zd);
+
+	zd->rxdatas = 0;
+	err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, 
+	     ZD1201_INQ_SCANRESULTS, 0, 0);
+	if (err)
+		return err;
+
+	wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+	if (!zd->rxlen)
+		return -EIO;
+
+	if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS)
+		return -EIO;
+
+	for(i=8; i<zd->rxlen; i+=62) {
+		iwe.cmd = SIOCGIWAP;
+		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+		memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
+		cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.length = zd->rxdata[i+16];
+		iwe.u.data.flags = 1;
+		cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18);
+
+		iwe.cmd = SIOCGIWMODE;
+		if (zd->rxdata[i+14]&0x01)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+		
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = zd->rxdata[i+0];
+		iwe.u.freq.e = 0;
+		cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+		
+		iwe.cmd = SIOCGIWRATE;
+		iwe.u.bitrate.fixed = 0;
+		iwe.u.bitrate.disabled = 0;
+		for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
+			iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
+			cev=iwe_stream_add_event(cev, end_buf, &iwe,
+			    IW_EV_PARAM_LEN);
+		}
+		
+		iwe.cmd = SIOCGIWENCODE;
+		iwe.u.data.length = 0;
+		if (zd->rxdata[i+14]&0x10)
+			iwe.u.data.flags = IW_ENCODE_ENABLED;
+		else
+			iwe.u.data.flags = IW_ENCODE_DISABLED;
+		cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+		
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.qual = zd->rxdata[i+4];
+		iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
+		iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
+		iwe.u.qual.updated = 7;
+		cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+	}
+
+	if (!enabled_save)
+		zd1201_disable(zd);
+
+	srq->length = cev - extra;
+	srq->flags = 0;
+
+	return 0;
+}
+
+static int zd1201_set_essid(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	if (data->length > IW_ESSID_MAX_SIZE)
+		return -EINVAL;
+	if (data->length < 1)
+		data->length = 1;
+	zd->essidlen = data->length-1;
+	memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
+	memcpy(zd->essid, essid, data->length);
+	return zd1201_join(zd, zd->essid, zd->essidlen);
+}
+
+static int zd1201_get_essid(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+	memcpy(essid, zd->essid, zd->essidlen);
+	data->flags = 1;
+	data->length = zd->essidlen;
+
+	return 0;
+}
+
+static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
+    struct iw_point *data, char *nick)
+{
+	strcpy(nick, "zd1201");
+	data->flags = 1;
+	data->length = strlen(nick);
+	return 0;
+}
+
+static int zd1201_set_rate(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short rate;
+	int err;
+
+	switch (rrq->value) {
+		case 1000000:
+			rate = ZD1201_RATEB1;
+			break;
+		case 2000000:
+			rate = ZD1201_RATEB2;
+			break;
+		case 5500000:
+			rate = ZD1201_RATEB5;
+			break;
+		case 11000000:
+		default:
+			rate = ZD1201_RATEB11;
+			break;
+	}
+	if (!rrq->fixed) { /* Also enable all lower bitrates */
+		rate |= rate-1;
+	}
+	
+	err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate);
+	if (err)
+		return err;
+
+	return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_rate(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short rate;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate);
+	if (err)
+		return err;
+
+	switch(rate) {
+		case 1:
+			rrq->value = 1000000;
+			break;
+		case 2:
+			rrq->value = 2000000;
+			break;
+		case 5:
+			rrq->value = 5500000;
+			break;
+		case 11:
+			rrq->value = 11000000;
+			break;
+		default:
+			rrq->value = 0;
+	}
+	rrq->fixed = 0;
+	rrq->disabled = 0;
+
+	return 0;
+}
+
+static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
+    struct iw_param *rts, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err;
+	short val = rts->value;
+
+	if (rts->disabled || !rts->fixed)
+		val = ZD1201_RTSMAX;
+	if (val > ZD1201_RTSMAX)
+		return -EINVAL;
+	if (val < 0)
+		return -EINVAL;
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val);
+	if (err)
+		return err;
+	return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
+    struct iw_param *rts, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short rtst;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst);
+	if (err)
+		return err;
+	rts->value = rtst;
+	rts->disabled = (rts->value == ZD1201_RTSMAX);
+	rts->fixed = 1;
+
+	return 0;
+}
+
+static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
+    struct iw_param *frag, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err;
+	short val = frag->value;
+
+	if (frag->disabled || !frag->fixed)
+		val = ZD1201_FRAGMAX;
+	if (val > ZD1201_FRAGMAX)
+		return -EINVAL;
+	if (val < ZD1201_FRAGMIN)
+		return -EINVAL;
+	if (val & 1)
+		return -EINVAL;
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val);
+	if (err)
+		return err;
+	return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
+    struct iw_param *frag, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short fragt;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt);
+	if (err)
+		return err;
+	frag->value = fragt;
+	frag->disabled = (frag->value == ZD1201_FRAGMAX);
+	frag->fixed = 1;
+
+	return 0;
+}
+
+static int zd1201_set_retry(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	return 0;
+}
+
+static int zd1201_get_retry(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	return 0;
+}
+
+static int zd1201_set_encode(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *erq, char *key)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short i;
+	int err, rid;
+
+	if (erq->length > ZD1201_MAXKEYLEN)
+		return -EINVAL;
+
+	i = (erq->flags & IW_ENCODE_INDEX)-1;
+	if (i == -1) {
+		err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i);
+		if (err)
+			return err;
+	} else {
+		err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i);
+		if (err)
+			return err;
+	}
+
+	if (i < 0 || i >= ZD1201_NUMKEYS)
+		return -EINVAL;
+
+	rid = ZD1201_RID_CNFDEFAULTKEY0 + i;
+	err = zd1201_setconfig(zd, rid, key, erq->length, 1);
+	if (err)
+		return err;
+	zd->encode_keylen[i] = erq->length;
+	memcpy(zd->encode_keys[i], key, erq->length);
+
+	i=0;
+	if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) {
+		i |= 0x01;
+		zd->encode_enabled = 1;
+	} else
+		zd->encode_enabled = 0;
+	if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) {
+		i |= 0x02;
+		zd->encode_restricted = 1;
+	} else
+		zd->encode_restricted = 0;
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i);
+	if (err)
+		return err;
+
+	if (zd->encode_enabled)
+		i = ZD1201_CNFAUTHENTICATION_SHAREDKEY;
+	else
+		i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i);
+	if (err)
+		return err;
+
+	return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_encode(struct net_device *dev,
+    struct iw_request_info *info, struct iw_point *erq, char *key)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short i;
+	int err;
+
+	if (zd->encode_enabled)
+		erq->flags = IW_ENCODE_ENABLED;
+	else
+		erq->flags = IW_ENCODE_DISABLED;
+	if (zd->encode_restricted)
+		erq->flags |= IW_ENCODE_RESTRICTED;
+	else
+		erq->flags |= IW_ENCODE_OPEN;
+
+	i = (erq->flags & IW_ENCODE_INDEX) -1;
+	if (i == -1) {
+		err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i);
+		if (err)
+			return err;
+	}
+	if (i<0 || i>= ZD1201_NUMKEYS)
+		return -EINVAL;
+
+	erq->flags |= i+1;
+	
+	erq->length = zd->encode_keylen[i];
+	memcpy(key, zd->encode_keys[i], erq->length);
+
+	return 0;
+}
+
+static int zd1201_set_power(struct net_device *dev, 
+    struct iw_request_info *info, struct iw_param *vwrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short enabled, duration, level;
+	int err;
+
+	enabled = vwrq->disabled ? 0 : 1;
+	if (enabled) {
+		if (vwrq->flags & IW_POWER_PERIOD) {
+			duration = vwrq->value;
+			err = zd1201_setconfig16(zd, 
+			    ZD1201_RID_CNFMAXSLEEPDURATION, duration);
+			if (err)
+				return err;
+			goto out;
+		}
+		if (vwrq->flags & IW_POWER_TIMEOUT) {
+			err = zd1201_getconfig16(zd, 
+			    ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
+			if (err)
+				return err;
+			level = vwrq->value * 4 / duration;
+			if (level > 4)
+				level = 4;
+			if (level < 0)
+				level = 0;
+			err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS,
+			    level);
+			if (err)
+				return err;
+			goto out;
+		}
+		return -EINVAL;
+	}
+out:
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int zd1201_get_power(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *vwrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short enabled, level, duration;
+	int err;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled);
+	if (err)
+		return err;
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level);
+	if (err)
+		return err;
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
+	if (err)
+		return err;
+	vwrq->disabled = enabled ? 0 : 1;
+	if (vwrq->flags & IW_POWER_TYPE) {
+		if (vwrq->flags & IW_POWER_PERIOD) {
+			vwrq->value = duration;
+			vwrq->flags = IW_POWER_PERIOD;
+		} else {
+			vwrq->value = duration * level / 4;
+			vwrq->flags = IW_POWER_TIMEOUT;
+		}
+	}
+	if (vwrq->flags & IW_POWER_MODE) {
+		if (enabled && level)
+			vwrq->flags = IW_POWER_UNICAST_R;
+		else
+			vwrq->flags = IW_POWER_ALL_R;
+	}
+
+	return 0;
+}
+
+
+static const iw_handler zd1201_iw_handler[] =
+{
+	(iw_handler) zd1201_config_commit,	/* SIOCSIWCOMMIT */
+	(iw_handler) zd1201_get_name,    	/* SIOCGIWNAME */
+	(iw_handler) NULL,			/* SIOCSIWNWID */
+	(iw_handler) NULL,			/* SIOCGIWNWID */
+	(iw_handler) zd1201_set_freq,		/* SIOCSIWFREQ */
+	(iw_handler) zd1201_get_freq,		/* SIOCGIWFREQ */
+	(iw_handler) zd1201_set_mode,		/* SIOCSIWMODE */
+	(iw_handler) zd1201_get_mode,		/* SIOCGIWMODE */
+	(iw_handler) NULL,                  	/* SIOCSIWSENS */
+	(iw_handler) NULL,           		/* SIOCGIWSENS */
+	(iw_handler) NULL,			/* SIOCSIWRANGE */
+	(iw_handler) zd1201_get_range,           /* SIOCGIWRANGE */
+	(iw_handler) NULL,			/* SIOCSIWPRIV */
+	(iw_handler) NULL,			/* SIOCGIWPRIV */
+	(iw_handler) NULL,			/* SIOCSIWSTATS */
+	(iw_handler) NULL,			/* SIOCGIWSTATS */
+	(iw_handler) NULL,			/* SIOCSIWSPY */
+	(iw_handler) NULL,			/* SIOCGIWSPY */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL/*zd1201_set_wap*/,		/* SIOCSIWAP */
+	(iw_handler) zd1201_get_wap,		/* SIOCGIWAP */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,       		/* SIOCGIWAPLIST */
+	(iw_handler) zd1201_set_scan,		/* SIOCSIWSCAN */
+	(iw_handler) zd1201_get_scan,		/* SIOCGIWSCAN */
+	(iw_handler) zd1201_set_essid,		/* SIOCSIWESSID */
+	(iw_handler) zd1201_get_essid,		/* SIOCGIWESSID */
+	(iw_handler) NULL,         		/* SIOCSIWNICKN */
+	(iw_handler) zd1201_get_nick, 		/* SIOCGIWNICKN */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) zd1201_set_rate,		/* SIOCSIWRATE */
+	(iw_handler) zd1201_get_rate,		/* SIOCGIWRATE */
+	(iw_handler) zd1201_set_rts,		/* SIOCSIWRTS */
+	(iw_handler) zd1201_get_rts,		/* SIOCGIWRTS */
+	(iw_handler) zd1201_set_frag,		/* SIOCSIWFRAG */
+	(iw_handler) zd1201_get_frag,		/* SIOCGIWFRAG */
+	(iw_handler) NULL,         		/* SIOCSIWTXPOW */
+	(iw_handler) NULL,          		/* SIOCGIWTXPOW */
+	(iw_handler) zd1201_set_retry,		/* SIOCSIWRETRY */
+	(iw_handler) zd1201_get_retry,		/* SIOCGIWRETRY */
+	(iw_handler) zd1201_set_encode,		/* SIOCSIWENCODE */
+	(iw_handler) zd1201_get_encode,		/* SIOCGIWENCODE */
+	(iw_handler) zd1201_set_power,		/* SIOCSIWPOWER */
+	(iw_handler) zd1201_get_power,		/* SIOCGIWPOWER */
+};
+
+static int zd1201_set_hostauth(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err;
+
+	if (!zd->ap)
+		return -EOPNOTSUPP;
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int zd1201_get_hostauth(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short hostauth;
+	int err;
+
+	if (!zd->ap)
+		return -EOPNOTSUPP;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth);
+	if (err)
+		return err;
+	rrq->value = hostauth;
+	rrq->fixed = 1;
+
+	return 0;
+}
+
+static int zd1201_auth_sta(struct net_device *dev,
+    struct iw_request_info *info, struct sockaddr *sta, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	unsigned char buffer[10];
+
+	if (!zd->ap)
+		return -EOPNOTSUPP;
+
+	memcpy(buffer, sta->sa_data, ETH_ALEN);
+	*(short*)(buffer+6) = 0;	/* 0==success, 1==failure */
+	*(short*)(buffer+8) = 0;
+
+	return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1);
+}
+
+static int zd1201_set_maxassoc(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	int err;
+
+	if (!zd->ap)
+		return -EOPNOTSUPP;
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int zd1201_get_maxassoc(struct net_device *dev,
+    struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	short maxassoc;
+	int err;
+
+	if (!zd->ap)
+		return -EOPNOTSUPP;
+
+	err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc);
+	if (err)
+		return err;
+	rrq->value = maxassoc;
+	rrq->fixed = 1;
+
+	return 0;
+}
+
+static const iw_handler zd1201_private_handler[] = {
+	(iw_handler) zd1201_set_hostauth,	/* ZD1201SIWHOSTAUTH */
+	(iw_handler) zd1201_get_hostauth,	/* ZD1201GIWHOSTAUTH */
+	(iw_handler) zd1201_auth_sta,		/* ZD1201SIWAUTHSTA */
+	(iw_handler) NULL,			/* nothing to get */
+	(iw_handler) zd1201_set_maxassoc,	/* ZD1201SIMAXASSOC */
+	(iw_handler) zd1201_get_maxassoc,	/* ZD1201GIMAXASSOC */
+};
+
+static const struct iw_priv_args zd1201_private_args[] = {
+	{ ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	    IW_PRIV_TYPE_NONE, "sethostauth" },
+	{ ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE,
+	    IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" },
+	{ ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 
+	    IW_PRIV_TYPE_NONE, "authstation" },
+	{ ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	    IW_PRIV_TYPE_NONE, "setmaxassoc" },
+	{ ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE,
+	    IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" },
+};
+
+static const struct iw_handler_def zd1201_iw_handlers = {
+	.num_standard 		= sizeof(zd1201_iw_handler)/sizeof(iw_handler),
+	.num_private 		= sizeof(zd1201_private_handler)/sizeof(iw_handler),
+	.num_private_args 	= sizeof(zd1201_private_args)/sizeof(struct iw_priv_args),
+	.standard 		= (iw_handler *)zd1201_iw_handler,
+	.private 		= (iw_handler *)zd1201_private_handler,
+	.private_args 		= (struct iw_priv_args *) zd1201_private_args,
+};
+
+static int zd1201_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
+{
+	struct zd1201 *zd;
+	struct usb_device *usb;
+	int i, err;
+	short porttype;
+	char buf[IW_ESSID_MAX_SIZE+2];
+
+	usb = interface_to_usbdev(interface);
+
+	zd = kmalloc(sizeof(struct zd1201), GFP_KERNEL);
+	if (!zd) {
+		return -ENOMEM;
+	}
+	memset(zd, 0, sizeof(struct zd1201));
+	zd->ap = ap;
+	zd->usb = usb;
+	zd->removed = 0;
+	init_waitqueue_head(&zd->rxdataq);
+	INIT_HLIST_HEAD(&zd->fraglist);
+	
+	err = zd1201_fw_upload(usb, zd->ap);
+	if (err) {
+		dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err);
+		goto err_zd;
+	}
+	
+	zd->endp_in = 1;
+	zd->endp_out = 1;
+	zd->endp_out2 = 2;
+	zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!zd->rx_urb || !zd->tx_urb)
+		goto err_zd;
+
+	for(i = 0; i<100; i++)
+		udelay(1000);
+
+	err = zd1201_drvr_start(zd);
+	if (err)
+		goto err_zd;
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312);
+	if (err)
+		goto err_start;
+
+	err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL,
+	    ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11);
+	if (err)
+		goto err_start;
+
+	zd->dev = alloc_etherdev(0);
+	if (!zd->dev)
+		goto err_start;
+
+	zd->dev->priv = zd;
+	zd->dev->open = zd1201_net_open;
+	zd->dev->stop = zd1201_net_stop;
+	zd->dev->get_stats = zd1201_get_stats;
+	zd->dev->get_wireless_stats = zd1201_get_wireless_stats;
+	zd->dev->wireless_handlers =
+	    (struct iw_handler_def *)&zd1201_iw_handlers;
+	zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
+	zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
+	zd->dev->tx_timeout = zd1201_tx_timeout;
+	zd->dev->set_multicast_list = zd1201_set_multicast;
+	zd->dev->set_mac_address = zd1201_set_mac_address;
+	strcpy(zd->dev->name, "wlan%d");
+
+	err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
+	    zd->dev->dev_addr, zd->dev->addr_len);
+	if (err)
+		goto err_net;
+
+	/* Set wildcard essid to match zd->essid */
+	*(__le16 *)buf = cpu_to_le16(0);
+	err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
+	    IW_ESSID_MAX_SIZE+2, 1);
+	if (err)
+		goto err_net;
+
+	if (zd->ap)
+		porttype = ZD1201_PORTTYPE_AP;
+	else
+		porttype = ZD1201_PORTTYPE_BSS;
+	err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
+	if (err)
+		goto err_net;
+
+	err = register_netdev(zd->dev);
+	if (err)
+		goto err_net;
+	dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
+	    zd->dev->name);
+	
+	usb_set_intfdata(interface, zd);
+	return 0;
+
+err_net:
+	free_netdev(zd->dev);
+err_start:
+	/* Leave the device in reset state */
+	zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
+err_zd:
+	if (zd->tx_urb)
+		usb_free_urb(zd->tx_urb);
+	if (zd->rx_urb)
+		usb_free_urb(zd->rx_urb);
+	kfree(zd);
+	return err;
+}
+
+static void zd1201_disconnect(struct usb_interface *interface)
+{
+	struct zd1201 *zd=(struct zd1201 *)usb_get_intfdata(interface);
+	struct hlist_node *node, *node2;
+	struct zd1201_frag *frag;
+
+	if (!zd)
+		return;
+	usb_set_intfdata(interface, NULL);
+	if (zd->dev) {
+		unregister_netdev(zd->dev);
+		free_netdev(zd->dev);
+	}
+
+	hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) {
+		hlist_del_init(&frag->fnode);
+		kfree_skb(frag->skb);
+		kfree(frag);
+	}
+
+	if (zd->tx_urb) {
+		usb_kill_urb(zd->tx_urb);
+		usb_free_urb(zd->tx_urb);
+	}
+	if (zd->rx_urb) {
+		usb_kill_urb(zd->rx_urb);
+		usb_free_urb(zd->rx_urb);
+	}
+	kfree(zd);
+}
+
+static struct usb_driver zd1201_usb = {
+	.owner = THIS_MODULE,
+	.name = "zd1201",
+	.probe = zd1201_probe,
+	.disconnect = zd1201_disconnect,
+	.id_table = zd1201_table,
+};
+
+static int __init zd1201_init(void)
+{
+	return usb_register(&zd1201_usb);
+}
+
+static void __exit zd1201_cleanup(void)
+{
+	usb_deregister(&zd1201_usb);
+}
+
+module_init(zd1201_init);
+module_exit(zd1201_cleanup);
diff --git a/drivers/usb/net/zd1201.h b/drivers/usb/net/zd1201.h
new file mode 100644
--- /dev/null
+++ b/drivers/usb/net/zd1201.h
@@ -0,0 +1,147 @@
+/*
+ *	Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.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.
+ *
+ *	Parts of this driver have been derived from a wlan-ng version
+ *	modified by ZyDAS.
+ *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ */
+
+#ifndef _INCLUDE_ZD1201_H_
+#define _INCLUDE_ZD1201_H_
+
+#define ZD1201_NUMKEYS		4
+#define ZD1201_MAXKEYLEN	13
+#define ZD1201_MAXMULTI		16
+#define ZD1201_FRAGMAX		2500
+#define ZD1201_FRAGMIN		256
+#define ZD1201_RTSMAX		2500
+
+#define ZD1201_RXSIZE		3000
+
+struct zd1201 {
+	struct usb_device	*usb;
+	int			removed;
+	struct net_device	*dev;
+	struct net_device_stats stats;
+	struct iw_statistics	iwstats;
+
+	int			endp_in;
+	int			endp_out;
+	int			endp_out2;
+	struct urb		*rx_urb;
+	struct urb		*tx_urb;
+
+	unsigned char 		rxdata[ZD1201_RXSIZE];
+	int			rxlen;
+	wait_queue_head_t	rxdataq;
+	int			rxdatas;
+	struct hlist_head	fraglist;
+	unsigned char		txdata[ZD1201_RXSIZE];
+
+	int			ap;
+	char			essid[IW_ESSID_MAX_SIZE+1];
+	int			essidlen;
+	int			mac_enabled;
+	int			monitor;
+	int			encode_enabled;
+	int			encode_restricted;
+	unsigned char		encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN];
+	int			encode_keylen[ZD1201_NUMKEYS];
+};
+
+struct zd1201_frag {
+	struct hlist_node	fnode;
+	int			seq;
+	struct sk_buff		*skb;
+};
+
+#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV
+#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1
+#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2
+#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4
+#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1
+
+#define ZD1201_FW_TIMEOUT	(1000)
+
+#define ZD1201_TX_TIMEOUT	(2000)
+
+#define ZD1201_USB_CMDREQ	0
+#define ZD1201_USB_RESREQ	1
+
+#define	ZD1201_CMDCODE_INIT	0x00
+#define ZD1201_CMDCODE_ENABLE	0x01
+#define ZD1201_CMDCODE_DISABLE	0x02
+#define ZD1201_CMDCODE_ALLOC	0x0a
+#define ZD1201_CMDCODE_INQUIRE	0x11
+#define ZD1201_CMDCODE_SETRXRID	0x17
+#define ZD1201_CMDCODE_ACCESS	0x21
+
+#define ZD1201_PACKET_EVENTSTAT	0x0
+#define ZD1201_PACKET_RXDATA	0x1
+#define ZD1201_PACKET_INQUIRE	0x2
+#define ZD1201_PACKET_RESOURCE	0x3
+
+#define ZD1201_ACCESSBIT	0x0100
+
+#define ZD1201_RID_CNFPORTTYPE		0xfc00
+#define ZD1201_RID_CNFOWNMACADDR	0xfc01
+#define ZD1201_RID_CNFDESIREDSSID	0xfc02
+#define ZD1201_RID_CNFOWNCHANNEL	0xfc03
+#define ZD1201_RID_CNFOWNSSID		0xfc04
+#define ZD1201_RID_CNFMAXDATALEN	0xfc07
+#define ZD1201_RID_CNFPMENABLED		0xfc09
+#define ZD1201_RID_CNFPMEPS		0xfc0a
+#define ZD1201_RID_CNFMAXSLEEPDURATION	0xfc0c
+#define ZD1201_RID_CNFDEFAULTKEYID	0xfc23
+#define ZD1201_RID_CNFDEFAULTKEY0	0xfc24
+#define ZD1201_RID_CNFDEFAULTKEY1	0xfc25
+#define ZD1201_RID_CNFDEFAULTKEY2	0xfc26
+#define ZD1201_RID_CNFDEFAULTKEY3	0xfc27
+#define ZD1201_RID_CNFWEBFLAGS		0xfc28
+#define ZD1201_RID_CNFAUTHENTICATION	0xfc2a
+#define ZD1201_RID_CNFMAXASSOCSTATIONS	0xfc2b
+#define ZD1201_RID_CNFHOSTAUTH		0xfc2e
+#define ZD1201_RID_CNFGROUPADDRESS	0xfc80
+#define ZD1201_RID_CNFFRAGTHRESHOLD	0xfc82
+#define ZD1201_RID_CNFRTSTHRESHOLD	0xfc83
+#define ZD1201_RID_TXRATECNTL		0xfc84
+#define ZD1201_RID_PROMISCUOUSMODE	0xfc85
+#define ZD1201_RID_CNFBASICRATES	0xfcb3
+#define ZD1201_RID_AUTHENTICATESTA	0xfce3
+#define ZD1201_RID_CURRENTBSSID		0xfd42
+#define ZD1201_RID_COMMSQUALITY		0xfd43
+#define ZD1201_RID_CURRENTTXRATE	0xfd44
+#define ZD1201_RID_CNFMAXTXBUFFERNUMBER	0xfda0
+#define ZD1201_RID_CURRENTCHANNEL	0xfdc1
+
+#define ZD1201_INQ_SCANRESULTS		0xf101
+
+#define ZD1201_INF_LINKSTATUS		0xf200
+#define ZD1201_INF_ASSOCSTATUS		0xf201
+#define ZD1201_INF_AUTHREQ		0xf202
+
+#define ZD1201_ASSOCSTATUS_STAASSOC	0x1
+#define ZD1201_ASSOCSTATUS_REASSOC	0x2
+#define ZD1201_ASSOCSTATUS_DISASSOC	0x3
+#define ZD1201_ASSOCSTATUS_ASSOCFAIL	0x4
+#define ZD1201_ASSOCSTATUS_AUTHFAIL	0x5
+
+#define ZD1201_PORTTYPE_IBSS		0
+#define ZD1201_PORTTYPE_BSS		1
+#define ZD1201_PORTTYPE_WDS		2
+#define ZD1201_PORTTYPE_PSEUDOIBSS	3
+#define ZD1201_PORTTYPE_AP		6
+
+#define ZD1201_RATEB1	1
+#define ZD1201_RATEB2	2
+#define ZD1201_RATEB5	4	/* 5.5 really, but 5 is shorter :) */
+#define ZD1201_RATEB11	8
+
+#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM	0x0001
+#define ZD1201_CNFAUTHENTICATION_SHAREDKEY	0x0002
+
+#endif /* _INCLUDE_ZD1201_H_ */
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -53,6 +53,15 @@ config USB_SERIAL_GENERIC
 	  support" be compiled as a module for this driver to be used
 	  properly.
 
+config USB_SERIAL_AIRPRIME
+	tristate "USB AirPrime CDMA Wireless Driver"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use a AirPrime CDMA Wireless PC card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called airprime.
+
 config USB_SERIAL_BELKIN
 	tristate "USB Belkin and Peracom Single Port Serial Driver"
 	depends on USB_SERIAL
@@ -89,6 +98,16 @@ config USB_SERIAL_DIGI_ACCELEPORT
 	  To compile this driver as a module, choose M here: the
 	  module will be called digi_acceleport.
 
+config USB_SERIAL_CP2101
+	tristate "USB CP2101 UART Bridge Controller"
+	depends on USB_SERIAL && EXPERIMENTAL
+	help
+	  Say Y here if you want to use a CP2101/CP2102 based USB to RS232
+	  converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cp2101.
+
 config USB_SERIAL_CYPRESS_M8
 	tristate "USB Cypress M8 USB Serial Driver"
 	depends on USB_SERIAL && EXPERIMENTAL
@@ -385,6 +404,15 @@ config USB_SERIAL_PL2303
 	  To compile this driver as a module, choose M here: the
 	  module will be called pl2303.
 
+config USB_SERIAL_HP4X
+        tristate "USB HP4x Calculators support"
+        depends on USB_SERIAL
+        help
+          Say Y here if you want to use an Hewlett-Packard 4x Calculator.
+
+          To compile this driver as a module, choose M here: the
+          module will be called hp4x.
+
 config USB_SERIAL_SAFE
 	tristate "USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)"
 	depends on USB_SERIAL && EXPERIMENTAL
@@ -427,6 +455,17 @@ config USB_SERIAL_XIRCOM
 	  To compile this driver as a module, choose M here: the
 	  module will be called keyspan_pda.
 
+config USB_SERIAL_OPTION
+	tristate "USB Option PCMCIA serial driver"
+	depends on USB_SERIAL && USB_OHCI_HCD && PCCARD
+	help
+	  Say Y here if you want to use an Option card. This is a
+	  GSM card, controlled by three serial ports which are connected
+	  via an OHCI adapter located on a PC card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called option.
+
 config USB_SERIAL_OMNINET
 	tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
 	depends on USB_SERIAL && EXPERIMENTAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -11,7 +11,9 @@ usbserial-obj-$(CONFIG_USB_EZUSB)		+= ez
 
 usbserial-objs	:= usb-serial.o generic.o bus.o $(usbserial-obj-y)
 
+obj-$(CONFIG_USB_SERIAL_AIRPRIME)		+= airprime.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CP2101)			+= cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)		+= cypress_m8.o
 obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT)	+= digi_acceleport.o
@@ -20,6 +22,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)		+=
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)		+= ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)			+= garmin_gps.o
+obj-$(CONFIG_USB_SERIAL_HP4X)			+= hp4x.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)			+= ipaq.o
 obj-$(CONFIG_USB_SERIAL_IPW)			+= ipw.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
@@ -29,6 +32,7 @@ obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5ku
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
+obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
 obj-$(CONFIG_USB_SERIAL_TI)			+= ti_usb_3410_5052.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/serial/airprime.c
@@ -0,0 +1,63 @@
+/*
+ * AirPrime CDMA Wireless Serial USB driver
+ *
+ * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ *	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/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0xf3d, 0x0112) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver airprime_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"airprime",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+};
+
+static struct usb_serial_device_type airprime_device = {
+	.owner =		THIS_MODULE,
+	.name =			"airprime",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+};
+
+static int __init airprime_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&airprime_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&airprime_driver);
+	if (retval)
+		usb_serial_deregister(&airprime_device);
+	return retval;
+}
+
+static void __exit airprime_exit(void)
+{
+	usb_deregister(&airprime_driver);
+	usb_serial_deregister(&airprime_device);
+}
+
+module_init(airprime_init);
+module_exit(airprime_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -158,7 +158,7 @@ struct belkin_sa_private {
  * ***************************************************************************
  */
 
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
 
 /* assumes that struct usb_serial *serial is available */
 #define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
@@ -202,8 +202,7 @@ static void belkin_sa_shutdown (struct u
 	for (i=0; i < serial->num_ports; ++i) {
 		/* My special items, the standard routines free my urbs */
 		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv)
-			kfree(priv);
+		kfree(priv);
 	}
 }
 
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/serial/cp2101.c
@@ -0,0 +1,778 @@
+/*
+ * Silicon Laboratories CP2101/CP2102 USB to RS232 serial adaptor driver
+ *
+ * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
+ *
+ *	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.
+ *
+ * Support to set flow control line levels using TIOCMGET and TIOCMSET
+ * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
+ * control thanks to Munir Nassar nassarmu@real-time.com
+ *
+ * Outstanding Issues:
+ *  Buffers are not flushed when the port is opened.
+ *  Multiple calls to write() may fail with "Resource temporarily unavailable"
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.04"
+#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
+
+/*
+ * Function Prototypes
+ */
+static int cp2101_open(struct usb_serial_port*, struct file*);
+static void cp2101_cleanup(struct usb_serial_port*);
+static void cp2101_close(struct usb_serial_port*, struct file*);
+static void cp2101_get_termios(struct usb_serial_port*);
+static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
+static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
+		unsigned int, unsigned int);
+static void cp2101_break_ctl(struct usb_serial_port*, int);
+static int cp2101_startup (struct usb_serial *);
+static void cp2101_shutdown(struct usb_serial*);
+
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x10C4, 0xEA60) },	/* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0x80CA) },	/* Degree Controls Inc */
+	{ USB_DEVICE(0x10AB, 0x10C5) },	/* Siemens MC60 Cable */
+	{ } /* Terminating Entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+static struct usb_driver cp2101_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "CP2101",
+	.probe		= usb_serial_probe,
+	.disconnect	= usb_serial_disconnect,
+	.id_table	= id_table,
+};
+
+static struct usb_serial_device_type cp2101_device = {
+	.owner			= THIS_MODULE,
+	.name			= "CP2101",
+	.id_table		= id_table,
+	.num_interrupt_in	= 0,
+	.num_bulk_in		= 0,
+	.num_bulk_out		= 0,
+	.num_ports		= 1,
+	.open			= cp2101_open,
+	.close			= cp2101_close,
+	.break_ctl		= cp2101_break_ctl,
+	.set_termios		= cp2101_set_termios,
+	.tiocmget 		= cp2101_tiocmget,
+	.tiocmset		= cp2101_tiocmset,
+	.attach			= cp2101_startup,
+	.shutdown		= cp2101_shutdown,
+};
+
+/* Config request types */
+#define REQTYPE_HOST_TO_DEVICE	0x41
+#define REQTYPE_DEVICE_TO_HOST	0xc1
+
+/* Config SET requests. To GET, add 1 to the request number */
+#define CP2101_UART 		0x00	/* Enable / Disable */
+#define CP2101_BAUDRATE		0x01	/* (BAUD_RATE_GEN_FREQ / baudrate) */
+#define CP2101_BITS		0x03	/* 0x(0)(databits)(parity)(stopbits) */
+#define CP2101_BREAK		0x05	/* On / Off */
+#define CP2101_CONTROL		0x07	/* Flow control line states */
+#define CP2101_MODEMCTL		0x13	/* Modem controls */
+#define CP2101_CONFIG_6		0x19	/* 6 bytes of config data ??? */
+
+/* CP2101_UART */
+#define UART_ENABLE		0x0001
+#define UART_DISABLE		0x0000
+
+/* CP2101_BAUDRATE */
+#define BAUD_RATE_GEN_FREQ	0x384000
+
+/* CP2101_BITS */
+#define BITS_DATA_MASK		0X0f00
+#define BITS_DATA_5		0X0500
+#define BITS_DATA_6		0X0600
+#define BITS_DATA_7		0X0700
+#define BITS_DATA_8		0X0800
+#define BITS_DATA_9		0X0900
+
+#define BITS_PARITY_MASK	0x00f0
+#define BITS_PARITY_NONE	0x0000
+#define BITS_PARITY_ODD		0x0010
+#define BITS_PARITY_EVEN	0x0020
+#define BITS_PARITY_MARK	0x0030
+#define BITS_PARITY_SPACE	0x0040
+
+#define BITS_STOP_MASK		0x000f
+#define BITS_STOP_1		0x0000
+#define BITS_STOP_1_5		0x0001
+#define BITS_STOP_2		0x0002
+
+/* CP2101_BREAK */
+#define BREAK_ON		0x0000
+#define BREAK_OFF		0x0001
+
+/* CP2101_CONTROL */
+#define CONTROL_DTR		0x0001
+#define CONTROL_RTS		0x0002
+#define CONTROL_CTS		0x0010
+#define CONTROL_DSR		0x0020
+#define CONTROL_RING		0x0040
+#define CONTROL_DCD		0x0080
+#define CONTROL_WRITE_DTR	0x0100
+#define CONTROL_WRITE_RTS	0x0200
+
+/*
+ * cp2101_get_config
+ * Reads from the CP2101 configuration registers
+ * 'size' is specified in bytes.
+ * 'data' is a pointer to a pre-allocated array of integers large
+ * enough to hold 'size' bytes (with 4 bytes to each integer)
+ */
+static int cp2101_get_config(struct usb_serial_port* port, u8 request,
+		unsigned int *data, int size)
+{
+	struct usb_serial *serial = port->serial;
+	u32 *buf;
+	int result, i, length;
+
+	/* Number of integers required to contain the array */
+	length = (((size - 1) | 3) + 1)/4;
+
+	buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
+	memset(buf, 0, length * sizeof(u32));
+
+	if (!buf) {
+		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* For get requests, the request number must be incremented */
+	request++;
+
+	/* Issue the request, attempting to read 'size' bytes */
+	result = usb_control_msg (serial->dev,usb_rcvctrlpipe (serial->dev, 0),
+				request, REQTYPE_DEVICE_TO_HOST, 0x0000,
+				0, buf, size, 300);
+
+	/* Convert data into an array of integers */
+	for (i=0; i<length; i++)
+		data[i] = le32_to_cpu(buf[i]);
+
+	kfree(buf);
+
+	if (result != size) {
+		dev_err(&port->dev, "%s - Unable to send config request, "
+				"request=0x%x size=%d result=%d\n",
+				__FUNCTION__, request, size, result);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+/*
+ * cp2101_set_config
+ * Writes to the CP2101 configuration registers
+ * Values less than 16 bits wide are sent directly
+ * 'size' is specified in bytes.
+ */
+static int cp2101_set_config(struct usb_serial_port* port, u8 request,
+		unsigned int *data, int size)
+{
+	struct usb_serial *serial = port->serial;
+	u32 *buf;
+	int result, i, length;
+
+	/* Number of integers required to contain the array */
+	length = (((size - 1) | 3) + 1)/4;
+
+	buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+	if (!buf) {
+		dev_err(&port->dev, "%s - out of memory.\n",
+				__FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* Array of integers into bytes */
+	for (i = 0; i < length; i++)
+		buf[i] = cpu_to_le32(data[i]);
+
+	if (size > 2) {
+		result = usb_control_msg (serial->dev,
+				usb_sndctrlpipe(serial->dev, 0),
+				request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+				0, buf, size, 300);
+	} else {
+		result = usb_control_msg (serial->dev,
+				usb_sndctrlpipe(serial->dev, 0),
+				request, REQTYPE_HOST_TO_DEVICE, data[0],
+				0, NULL, 0, 300);
+	}
+
+	kfree(buf);
+
+	if ((size > 2 && result != size) || result < 0) {
+		dev_err(&port->dev, "%s - Unable to send request, "
+				"request=0x%x size=%d result=%d\n",
+				__FUNCTION__, request, size, result);
+		return -EPROTO;
+	}
+
+	/* Single data value */
+	result = usb_control_msg (serial->dev,
+			usb_sndctrlpipe(serial->dev, 0),
+			request, REQTYPE_HOST_TO_DEVICE, data[0],
+			0, NULL, 0, 300);
+	return 0;
+}
+
+/*
+ * cp2101_set_config_single
+ * Convenience function for calling cp2101_set_config on single data values
+ * without requiring an integer pointer
+ */
+static inline int cp2101_set_config_single(struct usb_serial_port* port,
+		u8 request, unsigned int data)
+{
+	return cp2101_set_config(port, request, &data, 2);
+}
+
+static int cp2101_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	int result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
+		dev_err(&port->dev, "%s - Unable to enable UART\n",
+				__FUNCTION__);
+		return -EPROTO;
+	}
+
+	/* 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,
+			port);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result) {
+		dev_err(&port->dev, "%s - failed resubmitting read urb, "
+				"error %d\n", __FUNCTION__, result);
+		return result;
+	}
+
+	/* Configure the termios structure */
+	cp2101_get_termios(port);
+
+	/* Set the DTR and RTS pins low */
+	cp2101_tiocmset(port, NULL, TIOCM_DTR | TIOCM_RTS, 0);
+
+	return 0;
+}
+
+static void cp2101_cleanup (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (serial->dev) {
+		/* shutdown any bulk reads that might be going on */
+		if (serial->num_bulk_out)
+			usb_kill_urb(port->write_urb);
+		if (serial->num_bulk_in)
+			usb_kill_urb(port->read_urb);
+	}
+}
+
+static void cp2101_close (struct usb_serial_port *port, struct file * filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* shutdown our urbs */
+	dbg("%s - shutting down urbs", __FUNCTION__);
+	usb_kill_urb(port->write_urb);
+	usb_kill_urb(port->read_urb);
+
+	cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+}
+
+/*
+ * cp2101_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+ * from the device, corrects any unsupported values, and configures the
+ * termios structure to reflect the state of the device
+ */
+static void cp2101_get_termios (struct usb_serial_port *port)
+{
+	unsigned int cflag, modem_ctl[4];
+	int baud;
+	int bits;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg("%s - no tty structures", __FUNCTION__);
+		return;
+	}
+	cflag = port->tty->termios->c_cflag;
+
+	cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
+	/* Convert to baudrate */
+	if (baud)
+		baud = BAUD_RATE_GEN_FREQ / baud;
+
+	dbg("%s - baud rate = %d", __FUNCTION__, baud);
+	cflag &= ~CBAUD;
+	switch (baud) {
+		/*
+		 * The baud rates which are commented out below
+		 * appear to be supported by the device
+		 * but are non-standard
+		 */
+		case 600:	cflag |= B600;		break;
+		case 1200:	cflag |= B1200;		break;
+		case 1800:	cflag |= B1800;		break;
+		case 2400:	cflag |= B2400;		break;
+		case 4800:	cflag |= B4800;		break;
+		/*case 7200:	cflag |= B7200;		break;*/
+		case 9600:	cflag |= B9600;		break;
+		/*case 14400:	cflag |= B14400;	break;*/
+		case 19200:	cflag |= B19200;	break;
+		/*case 28800:	cflag |= B28800;	break;*/
+		case 38400:	cflag |= B38400;	break;
+		/*case 55854:	cflag |= B55054;	break;*/
+		case 57600:	cflag |= B57600;	break;
+		case 115200:	cflag |= B115200;	break;
+		/*case 127117:	cflag |= B127117;	break;*/
+		case 230400:	cflag |= B230400;	break;
+		case 460800:	cflag |= B460800;	break;
+		case 921600:	cflag |= B921600;	break;
+		/*case 3686400:	cflag |= B3686400;	break;*/
+		default:
+			dbg("%s - Baud rate is not supported, "
+					"using 9600 baud", __FUNCTION__);
+			cflag |= B9600;
+			cp2101_set_config_single(port, CP2101_BAUDRATE,
+					(BAUD_RATE_GEN_FREQ/9600));
+			break;
+	}
+
+	cp2101_get_config(port, CP2101_BITS, &bits, 2);
+	cflag &= ~CSIZE;
+	switch(bits & BITS_DATA_MASK) {
+		case BITS_DATA_5:
+			dbg("%s - data bits = 5", __FUNCTION__);
+			cflag |= CS5;
+			break;
+		case BITS_DATA_6:
+			dbg("%s - data bits = 6", __FUNCTION__);
+			cflag |= CS6;
+			break;
+		case BITS_DATA_7:
+			dbg("%s - data bits = 7", __FUNCTION__);
+			cflag |= CS7;
+			break;
+		case BITS_DATA_8:
+			dbg("%s - data bits = 8", __FUNCTION__);
+			cflag |= CS8;
+			break;
+		case BITS_DATA_9:
+			dbg("%s - data bits = 9 (not supported, "
+					"using 8 data bits)", __FUNCTION__);
+			cflag |= CS8;
+			bits &= ~BITS_DATA_MASK;
+			bits |= BITS_DATA_8;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+		default:
+			dbg("%s - Unknown number of data bits, "
+					"using 8", __FUNCTION__);
+			cflag |= CS8;
+			bits &= ~BITS_DATA_MASK;
+			bits |= BITS_DATA_8;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+	}
+
+	switch(bits & BITS_PARITY_MASK) {
+		case BITS_PARITY_NONE:
+			dbg("%s - parity = NONE", __FUNCTION__);
+			cflag &= ~PARENB;
+			break;
+		case BITS_PARITY_ODD:
+			dbg("%s - parity = ODD", __FUNCTION__);
+			cflag |= (PARENB|PARODD);
+			break;
+		case BITS_PARITY_EVEN:
+			dbg("%s - parity = EVEN", __FUNCTION__);
+			cflag &= ~PARODD;
+			cflag |= PARENB;
+			break;
+		case BITS_PARITY_MARK:
+			dbg("%s - parity = MARK (not supported, "
+					"disabling parity)", __FUNCTION__);
+			cflag &= ~PARENB;
+			bits &= ~BITS_PARITY_MASK;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+		case BITS_PARITY_SPACE:
+			dbg("%s - parity = SPACE (not supported, "
+					"disabling parity)", __FUNCTION__);
+			cflag &= ~PARENB;
+			bits &= ~BITS_PARITY_MASK;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+		default:
+			dbg("%s - Unknown parity mode, "
+					"disabling parity", __FUNCTION__);
+			cflag &= ~PARENB;
+			bits &= ~BITS_PARITY_MASK;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+	}
+
+	cflag &= ~CSTOPB;
+	switch(bits & BITS_STOP_MASK) {
+		case BITS_STOP_1:
+			dbg("%s - stop bits = 1", __FUNCTION__);
+			break;
+		case BITS_STOP_1_5:
+			dbg("%s - stop bits = 1.5 (not supported, "
+					"using 1 stop bit)", __FUNCTION__);
+			bits &= ~BITS_STOP_MASK;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+		case BITS_STOP_2:
+			dbg("%s - stop bits = 2", __FUNCTION__);
+			cflag |= CSTOPB;
+			break;
+		default:
+			dbg("%s - Unknown number of stop bits, "
+					"using 1 stop bit", __FUNCTION__);
+			bits &= ~BITS_STOP_MASK;
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
+			break;
+	}
+
+	cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+	if (modem_ctl[0] & 0x0008) {
+		dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+		cflag |= CRTSCTS;
+	} else {
+		dbg("%s - flow control = NONE", __FUNCTION__);
+		cflag &= ~CRTSCTS;
+	}
+
+	port->tty->termios->c_cflag = cflag;
+}
+
+static void cp2101_set_termios (struct usb_serial_port *port,
+		struct termios *old_termios)
+{
+	unsigned int cflag, old_cflag=0;
+	int baud=0, bits;
+	unsigned int modem_ctl[4];
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg("%s - no tty structures", __FUNCTION__);
+		return;
+	}
+	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_cflag = old_termios->c_cflag;
+	}
+
+	/* If the baud rate is to be updated*/
+	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
+		switch (cflag & CBAUD) {
+			/*
+			 * The baud rates which are commented out below
+			 * appear to be supported by the device
+			 * but are non-standard
+			 */
+			case B0:	baud = 0;	break;
+			case B600:	baud = 600;	break;
+			case B1200:	baud = 1200;	break;
+			case B1800:	baud = 1800;	break;
+			case B2400:	baud = 2400;	break;
+			case B4800:	baud = 4800;	break;
+			/*case B7200:	baud = 7200;	break;*/
+			case B9600:	baud = 9600;	break;
+			/*ase B14400:	baud = 14400;	break;*/
+			case B19200:	baud = 19200;	break;
+			/*case B28800:	baud = 28800;	break;*/
+			case B38400:	baud = 38400;	break;
+			/*case B55854:	baud = 55054;	break;*/
+			case B57600:	baud = 57600;	break;
+			case B115200:	baud = 115200;	break;
+			/*case B127117:	baud = 127117;	break;*/
+			case B230400:	baud = 230400;	break;
+			case B460800:	baud = 460800;	break;
+			case B921600:	baud = 921600;	break;
+			/*case B3686400:	baud = 3686400;	break;*/
+			default:
+				dev_err(&port->dev, "cp2101 driver does not "
+					"support the baudrate requested\n");
+				break;
+		}
+
+		if (baud) {
+			dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
+					baud);
+			if (cp2101_set_config_single(port, CP2101_BAUDRATE,
+						(BAUD_RATE_GEN_FREQ / baud)))
+				dev_err(&port->dev, "Baud rate requested not "
+						"supported by device\n");
+		}
+	}
+
+	/* If the number of data bits is to be updated */
+	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
+		bits &= ~BITS_DATA_MASK;
+		switch (cflag & CSIZE) {
+			case CS5:
+				bits |= BITS_DATA_5;
+				dbg("%s - data bits = 5", __FUNCTION__);
+				break;
+			case CS6:
+				bits |= BITS_DATA_6;
+				dbg("%s - data bits = 6", __FUNCTION__);
+				break;
+			case CS7:
+				bits |= BITS_DATA_7;
+				dbg("%s - data bits = 7", __FUNCTION__);
+				break;
+			case CS8:
+				bits |= BITS_DATA_8;
+				dbg("%s - data bits = 8", __FUNCTION__);
+				break;
+			/*case CS9:
+			 	bits |= BITS_DATA_9;
+				dbg("%s - data bits = 9", __FUNCTION__);
+				break;*/
+			default:
+				dev_err(&port->dev, "cp2101 driver does not "
+					"support the number of bits requested,"
+					" using 8 bit mode\n");
+				bits |= BITS_DATA_8;
+				break;
+		}
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+			dev_err(&port->dev, "Number of data bits requested "
+					"not supported by device\n");
+	}
+
+	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
+		bits &= ~BITS_PARITY_MASK;
+		if (cflag & PARENB) {
+			if (cflag & PARODD) {
+				bits |= BITS_PARITY_ODD;
+				dbg("%s - parity = ODD", __FUNCTION__);
+			} else {
+				bits |= BITS_PARITY_EVEN;
+				dbg("%s - parity = EVEN", __FUNCTION__);
+			}
+		}
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+			dev_err(&port->dev, "Parity mode not supported "
+					"by device\n");
+	}
+
+	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
+		bits &= ~BITS_STOP_MASK;
+		if (cflag & CSTOPB) {
+			bits |= BITS_STOP_2;
+			dbg("%s - stop bits = 2", __FUNCTION__);
+		} else {
+			bits |= BITS_STOP_1;
+			dbg("%s - stop bits = 1", __FUNCTION__);
+		}
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+			dev_err(&port->dev, "Number of stop bits requested "
+					"not supported by device\n");
+	}
+
+	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
+		cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+		dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+				__FUNCTION__, modem_ctl[0], modem_ctl[1],
+				modem_ctl[2], modem_ctl[3]);
+
+		if (cflag & CRTSCTS) {
+			modem_ctl[0] &= ~0x7B;
+			modem_ctl[0] |= 0x09;
+			modem_ctl[1] = 0x80;
+			dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+		} else {
+			modem_ctl[0] &= ~0x7B;
+			modem_ctl[0] |= 0x01;
+			modem_ctl[1] |= 0x40;
+			dbg("%s - flow control = NONE", __FUNCTION__);
+		}
+
+		dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+				__FUNCTION__, modem_ctl[0], modem_ctl[1],
+				modem_ctl[2], modem_ctl[3]);
+		cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+	}
+
+}
+
+static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
+		unsigned int set, unsigned int clear)
+{
+	int control = 0;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (set & TIOCM_RTS) {
+		control |= CONTROL_RTS;
+		control |= CONTROL_WRITE_RTS;
+	}
+	if (set & TIOCM_DTR) {
+		control |= CONTROL_DTR;
+		control |= CONTROL_WRITE_DTR;
+	}
+	if (clear & TIOCM_RTS) {
+		control &= ~CONTROL_RTS;
+		control |= CONTROL_WRITE_RTS;
+	}
+	if (clear & TIOCM_DTR) {
+		control &= ~CONTROL_DTR;
+		control |= CONTROL_WRITE_DTR;
+	}
+
+	dbg("%s - control = 0x%.4x", __FUNCTION__, control);
+
+	return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
+
+}
+
+static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
+{
+	int control, result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	cp2101_get_config(port, CP2101_CONTROL, &control, 1);
+
+	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
+		|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
+		|((control & CONTROL_CTS) ? TIOCM_CTS : 0)
+		|((control & CONTROL_DSR) ? TIOCM_DSR : 0)
+		|((control & CONTROL_RING)? TIOCM_RI  : 0)
+		|((control & CONTROL_DCD) ? TIOCM_CD  : 0);
+
+	dbg("%s - control = 0x%.2x", __FUNCTION__, control);
+
+	return result;
+}
+
+static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
+{
+	int state;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+	if (break_state == 0)
+		state = BREAK_OFF;
+	else
+		state = BREAK_ON;
+	dbg("%s - turning break %s", __FUNCTION__,
+			state==BREAK_OFF ? "off" : "on");
+	cp2101_set_config(port, CP2101_BREAK, &state, 2);
+}
+
+static int cp2101_startup (struct usb_serial *serial)
+{
+	/* CP2101 buffers behave strangely unless device is reset */
+	usb_reset_device(serial->dev);
+	return 0;
+}
+
+static void cp2101_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg("%s", __FUNCTION__);
+
+	/* Stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		cp2101_cleanup(serial->port[i]);
+	}
+}
+
+static int __init cp2101_init (void)
+{
+	int retval;
+
+	retval = usb_serial_register(&cp2101_device);
+	if (retval)
+		return retval; /* Failed to register */
+
+	retval = usb_register(&cp2101_driver);
+	if (retval) {
+		/* Failed to register */
+		usb_serial_deregister(&cp2101_device);
+		return retval;
+	}
+
+	/* Success */
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit cp2101_exit (void)
+{
+	usb_deregister (&cp2101_driver);
+	usb_serial_deregister (&cp2101_device);
+}
+
+module_init(cp2101_init);
+module_exit(cp2101_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable verbose debugging messages");
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -4,7 +4,7 @@
  *  Copyright (C) 2001  REINER SCT
  *  Author: Matthias Bruestle
  *
- *  Contact: linux-usb@sii.li (see MAINTAINERS)
+ *  Contact: support@reiner-sct.com (see MAINTAINERS)
  *
  *  This program is largely derived from work by the linux-usb group
  *  and associated source files.  Please see the usb/serial files for
@@ -20,6 +20,11 @@
  *
  *  In case of problems, please write to the contact e-mail address
  *  mentioned above.
+ *
+ *  Please note that later models of the cyberjack reader family are
+ *  supported by a libusb-based userspace device driver.
+ *
+ *  Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux
  */
 
 
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -16,6 +16,14 @@
  * See http://geocities.com/i0xox0i for information on this driver and the
  * earthmate usb device.
  *
+ *  Lonnie Mendez <dignome@gmail.com>
+ *  4-29-2005
+ *	Fixed problem where setting or retreiving the serial config would fail with
+ * 	EPIPE.  Removed CRTS toggling so the driver behaves more like other usbserial
+ * 	adapters.  Issued new interval of 1ms instead of the default 10ms.  As a
+ * 	result, transfer speed has been substantially increased.  From avg. 850bps to
+ * 	avg. 3300bps.  initial termios has also been modified.  Cleaned up code and
+ * 	formatting issues so it is more readable.  Replaced the C++ style comments.
  *
  *  Lonnie Mendez <dignome@gmail.com>
  *  12-15-2004
@@ -32,12 +40,6 @@
  *  10-2003
  *	Driver first released.
  *
- *
- * Long Term TODO:
- *	Improve transfer speeds - both read/write are somewhat slow
- *   at this point.
- *      Improve debugging.  Show modem line status with debug output and
- *   implement filtering for certain data as a module parameter.
  */
 
 /* Thanks to Neil Whelchel for writing the first cypress m8 implementation for linux. */
@@ -57,9 +59,10 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/spinlock.h>
-#include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/serial.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
 
 #include "usb-serial.h"
 #include "cypress_m8.h"
@@ -71,11 +74,12 @@
 	static int debug;
 #endif
 static int stats;
+static int interval;
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.08"
+#define DRIVER_VERSION "v1.09"
 #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
 #define DRIVER_DESC "Cypress USB to Serial Driver"
 
@@ -85,6 +89,7 @@ static int stats;
 
 static struct usb_device_id id_table_earthmate [] = {
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
+	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
 	{ }						/* Terminating entry */
 };
 
@@ -95,6 +100,7 @@ static struct usb_device_id id_table_cyp
 
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
+	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
 	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
 	{ }						/* Terminating entry */
 };
@@ -129,7 +135,6 @@ struct cypress_private {
 	char prev_status, diff_status;	   /* used for TIOCMIWAIT */
 	/* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
 	struct termios tmp_termios; 	   /* stores the old termios settings */
-	char calledfromopen;		   /* used when issuing lines on open - fixes rts drop bug */
 };
 
 /* write buffer structure */
@@ -167,10 +172,8 @@ static void 		  cypress_buf_free(struct 
 static void		  cypress_buf_clear(struct cypress_buf *cb);
 static unsigned int	  cypress_buf_data_avail(struct cypress_buf *cb);
 static unsigned int	  cypress_buf_space_avail(struct cypress_buf *cb);
-static unsigned int	  cypress_buf_put(struct cypress_buf *cb, const char *buf,
-					  unsigned int count);
-static unsigned int	  cypress_buf_get(struct cypress_buf *cb, char *buf,
-					  unsigned int count);
+static unsigned int	  cypress_buf_put(struct cypress_buf *cb, const char *buf, unsigned int count);
+static unsigned int	  cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count);
 
 
 static struct usb_serial_device_type cypress_earthmate_device = {
@@ -233,14 +236,13 @@ static struct usb_serial_device_type cyp
  *****************************************************************************/
 
 
-/* This function can either set or retreive the current serial line settings */
+/* This function can either set or retrieve the current serial line settings */
 static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
 				   int parity_enable, int parity_type, int reset, int cypress_request_type)
 {
-	int i, n_baud_rate = 0, retval = 0;
+	int new_baudrate = 0, retval = 0, tries = 0;
 	struct cypress_private *priv;
-	__u8 feature_buffer[5];
-	__u8 config;
+	__u8 feature_buffer[8];
 	unsigned long flags;
 
 	dbg("%s", __FUNCTION__);
@@ -255,7 +257,8 @@ static int cypress_serial_control (struc
  			 * of 57600bps (I have no idea whether DeLorme chose to use the general purpose
 			 * firmware or not), if you need to modify this speed setting for your own
 			 * project please add your own chiptype and modify the code likewise.  The
-			 * Cypress HID->COM device will work successfully up to 115200bps.
+			 * Cypress HID->COM device will work successfully up to 115200bps (but the
+			 * actual throughput is around 3kBps).
 			 */
 			if (baud_mask != priv->cbr_mask) {
 				dbg("%s - baud rate is changing", __FUNCTION__);
@@ -264,109 +267,114 @@ static int cypress_serial_control (struc
 					 * but are not used with NMEA and SiRF protocols */
 					
 					if ( (baud_mask == B300) || (baud_mask == B600) ) {
-						err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+						err("%s - failed setting baud rate, unsupported speed",
 						    __FUNCTION__);
-						n_baud_rate = 4800;
-					} else if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-						err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+						new_baudrate = priv->baud_rate;
+					} else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+						err("%s - failed setting baud rate, unsupported speed",
 						    __FUNCTION__);
-						n_baud_rate = 4800;
+						new_baudrate = priv->baud_rate;
 					}
 				} else if (priv->chiptype == CT_CYPHIDCOM) {
-					if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-						err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+						err("%s - failed setting baud rate, unsupported speed",
 						    __FUNCTION__);
-						n_baud_rate = 4800;
+						new_baudrate = priv->baud_rate;
 					}
 				} else if (priv->chiptype == CT_GENERIC) {
-					if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
-						err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+						err("%s - failed setting baud rate, unsupported speed",
 						    __FUNCTION__);
-						n_baud_rate = 4800;
+						new_baudrate = priv->baud_rate;
 					}
 				} else {
-					info("%s - please define your chiptype, using 4800bps default", __FUNCTION__);
-					n_baud_rate = 4800;
+					info("%s - please define your chiptype", __FUNCTION__);
+					new_baudrate = priv->baud_rate;
 				}
 			} else {  /* baud rate not changing, keep the old */
-				n_baud_rate = priv->baud_rate;
+				new_baudrate = priv->baud_rate;
 			}
-			dbg("%s - baud rate is being sent as %d", __FUNCTION__, n_baud_rate);
-
+			dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);
 			
-			/*
-			 * This algorithm accredited to Jiang Jay Zhang... thanks for all the help!
-			 */
-			for (i = 0; i < 4; ++i) {
-				feature_buffer[i] = ( n_baud_rate >> (i*8) & 0xFF );
-			}
+			memset(feature_buffer, 0, 8);
+			/* fill the feature_buffer with new configuration */
+			*((u_int32_t *)feature_buffer) = new_baudrate;
 
-			config = 0;	                 // reset config byte
-			config |= data_bits;	         // assign data bits in 2 bit space ( max 3 )
+			feature_buffer[4] |= data_bits;   /* assign data bits in 2 bit space ( max 3 ) */
 			/* 1 bit gap */
-			config |= (stop_bits << 3);      // assign stop bits in 1 bit space
-			config |= (parity_enable << 4);  // assign parity flag in 1 bit space
-			config |= (parity_type << 5); 	 // assign parity type in 1 bit space
+			feature_buffer[4] |= (stop_bits << 3);   /* assign stop bits in 1 bit space */
+			feature_buffer[4] |= (parity_enable << 4);   /* assign parity flag in 1 bit space */
+			feature_buffer[4] |= (parity_type << 5);   /* assign parity type in 1 bit space */
 			/* 1 bit gap */
-			config |= (reset << 7);		 // assign reset at end of byte, 1 bit space
-
-			feature_buffer[4] = config;
+			feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */
 				
 			dbg("%s - device is being sent this feature report:", __FUNCTION__);
 			dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1],
 		            feature_buffer[2], feature_buffer[3], feature_buffer[4]);
 			
+			do {
 			retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
 					  	  HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-					  	  0x0300, 0, feature_buffer, 5, 500);
+						  	  0x0300, 0, feature_buffer, 8, 500);
 
-			if (retval != 5)
+				if (tries++ >= 3)
+					break;
+
+				if (retval == EPIPE)
+					usb_clear_halt(port->serial->dev, 0x00);
+			} while (retval != 8 && retval != ENODEV);
+
+			if (retval != 8)
 				err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
 			else {
 				spin_lock_irqsave(&priv->lock, flags);
-				priv->baud_rate = n_baud_rate;
+				priv->baud_rate = new_baudrate;
 				priv->cbr_mask = baud_mask;
-				priv->current_config = config;
-				++priv->cmd_count;
+				priv->current_config = feature_buffer[4];
 				spin_unlock_irqrestore(&priv->lock, flags);
 			}
 		break;
 		case CYPRESS_GET_CONFIG:
 			dbg("%s - retreiving serial line settings", __FUNCTION__);
-			/* reset values in feature buffer */
-			memset(feature_buffer, 0, 5);
+			/* set initial values in feature buffer */
+			memset(feature_buffer, 0, 8);
 
+			do {
 			retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
 						  HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-						  0x0300, 0, feature_buffer, 5, 500);
+							  0x0300, 0, feature_buffer, 8, 500);
+				
+				if (tries++ >= 3)
+					break;
+
+				if (retval == EPIPE)
+					usb_clear_halt(port->serial->dev, 0x00);
+			} while (retval != 5 && retval != ENODEV);
+
 			if (retval != 5) {
 				err("%s - failed to retreive serial line settings - %d", __FUNCTION__, retval);
 				return retval;
 			} else {
 				spin_lock_irqsave(&priv->lock, flags);
+
 				/* store the config in one byte, and later use bit masks to check values */
 				priv->current_config = feature_buffer[4];
-				/* reverse the process above to get the baud_mask value */
-				n_baud_rate = 0; // reset bits
-				for (i = 0; i < 4; ++i) {
-					n_baud_rate |= ( feature_buffer[i] << (i*8) );
-				}
+				priv->baud_rate = *((u_int32_t *)feature_buffer);
 				
-				priv->baud_rate = n_baud_rate;
-				if ( (priv->cbr_mask = rate_to_mask(n_baud_rate)) == 0x40)
+				if ( (priv->cbr_mask = rate_to_mask(priv->baud_rate)) == 0x40)
 					dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
-				++priv->cmd_count;
 				spin_unlock_irqrestore(&priv->lock, flags);
 			}
-			break;
-		default:
-			err("%s - unsupported serial control command issued", __FUNCTION__);
 	}
+	spin_lock_irqsave(&priv->lock, flags);
+	++priv->cmd_count;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	return retval;
 } /* cypress_serial_control */
 
 
-/* given a baud mask, it will return speed on success */
+/* given a baud mask, it will return integer baud on success */
 static int mask_to_rate (unsigned mask)
 {
 	int rate;
@@ -437,11 +445,12 @@ static int generic_startup (struct usb_s
 	
 	usb_reset_configuration (serial->dev);
 	
+	interval = 1;
 	priv->cmd_ctrl = 0;
 	priv->line_control = 0;
 	priv->termios_initialized = 0;
-	priv->calledfromopen = 0;
 	priv->rx_flags = 0;
+	priv->cbr_mask = B300;
 	usb_set_serial_port_data(serial->port[0], priv);
 	
 	return (0);	
@@ -512,7 +521,6 @@ static int cypress_open (struct usb_seri
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* clear halts before open */
-	usb_clear_halt(serial->dev, 0x00);
 	usb_clear_halt(serial->dev, 0x81);
 	usb_clear_halt(serial->dev, 0x02);
 
@@ -530,7 +538,6 @@ static int cypress_open (struct usb_seri
 	/* raise both lines and set termios */
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->line_control = CONTROL_DTR | CONTROL_RTS;
-	priv->calledfromopen = 1;
 	priv->cmd_ctrl = 1;
 	spin_unlock_irqrestore(&priv->lock, flags);
 	result = cypress_write(port, NULL, 0);
@@ -552,7 +559,7 @@ static int cypress_open (struct usb_seri
 	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
 		usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
 		port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
-		cypress_read_int_callback, port, port->interrupt_in_urb->interval);
+		cypress_read_int_callback, port, interval);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 
 	if (result){
@@ -679,12 +686,12 @@ static void cypress_send(struct usb_seri
 	spin_lock_irqsave(&priv->lock, flags);
 	switch (port->interrupt_out_size) {
 		case 32:
-			// this is for the CY7C64013...
+			/* this is for the CY7C64013... */
 			offset = 2;
 			port->interrupt_out_buffer[0] = priv->line_control;
 			break;
 		case 8:
-			// this is for the CY7C63743...
+			/* this is for the CY7C63743... */
 			offset = 1;
 			port->interrupt_out_buffer[0] = priv->line_control;
 			break;
@@ -737,6 +744,7 @@ send:
 
 	port->interrupt_out_urb->transfer_buffer_length = actual_size;
 	port->interrupt_out_urb->dev = port->serial->dev;
+	port->interrupt_out_urb->interval = interval;
 	result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
 	if (result) {
 		dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
@@ -909,7 +917,7 @@ static void cypress_set_termios (struct 
 	unsigned cflag, iflag, baud_mask;
 	unsigned long flags;
 	__u8 oldlines;
-	int linechange;
+	int linechange = 0;
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -995,15 +1003,7 @@ static void cypress_set_termios (struct 
 			case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
 			default: dbg("%s - unknown masked baud rate", __FUNCTION__);
 		}
-		priv->line_control |= CONTROL_DTR;
-		
-		/* toggle CRTSCTS? - don't do this if being called from cypress_open */
-		if (!priv->calledfromopen) {
-			if (cflag & CRTSCTS)
-				priv->line_control |= CONTROL_RTS;
-			else
-				priv->line_control &= ~CONTROL_RTS;
-		}
+		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	
@@ -1013,9 +1013,6 @@ static void cypress_set_termios (struct 
 	cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
 			       parity_type, 0, CYPRESS_SET_CONFIG);
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(50*HZ/1000); /* give some time between change and read (50ms) */ 
-
 	/* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
          * this should confirm that all is working if it returns what we just set */
 	cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
@@ -1031,7 +1028,6 @@ static void cypress_set_termios (struct 
 		dbg("Using custom termios settings for a baud rate of 4800bps.");
 		/* define custom termios settings for NMEA protocol */
 
-		
 		tty->termios->c_iflag /* input modes - */
 			&= ~(IGNBRK		/* disable ignore break */
 			| BRKINT		/* disable break causes interrupt */
@@ -1052,23 +1048,16 @@ static void cypress_set_termios (struct 
 			| ISIG			/* disable interrupt, quit, and suspend special characters */
 			| IEXTEN);		/* disable non-POSIX special characters */
 
-	} else if (priv->chiptype == CT_CYPHIDCOM) {
+	} /* CT_CYPHIDCOM: Application should handle this for device */
 
-		// Software app handling it for device...	
-
-	}
 	linechange = (priv->line_control != oldlines);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* if necessary, set lines */
-	if (!priv->calledfromopen && linechange) {
+	if (linechange) {
 		priv->cmd_ctrl = 1;
 		cypress_write(port, NULL, 0);
 	}
-
-	if (priv->calledfromopen)
-		priv->calledfromopen = 0;
-	
 } /* cypress_set_termios */
 
  
@@ -1164,7 +1153,7 @@ static void cypress_read_int_callback(st
 	spin_lock_irqsave(&priv->lock, flags);
 	switch(urb->actual_length) {
 		case 32:
-			// This is for the CY7C64013...
+			/* This is for the CY7C64013... */
 			priv->current_status = data[0] & 0xF8;
 			bytes = data[1]+2;
 			i=2;
@@ -1172,7 +1161,7 @@ static void cypress_read_int_callback(st
 				havedata = 1;
 			break;
 		case 8:
-			// This is for the CY7C63743...
+			/* This is for the CY7C63743... */
 			priv->current_status = data[0] & 0xF8;
 			bytes = (data[0] & 0x07)+1;
 			i=1;
@@ -1245,7 +1234,7 @@ continue_read:
 		port->interrupt_in_urb->transfer_buffer,
 		port->interrupt_in_urb->transfer_buffer_length,
 		cypress_read_int_callback, port,
-		port->interrupt_in_urb->interval);
+		interval);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result)
 		dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
@@ -1274,6 +1263,8 @@ static void cypress_write_int_callback(s
 			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
 			priv->write_urb_in_use = 0;
 			return;
+		case -EPIPE: /* no break needed */
+			usb_clear_halt(port->serial->dev, 0x02);
 		default:
 			/* error in the urb, so we have to resubmit it */
 			dbg("%s - Overflow in write", __FUNCTION__);
@@ -1340,9 +1331,8 @@ static struct cypress_buf *cypress_buf_a
 
 static void cypress_buf_free(struct cypress_buf *cb)
 {
-	if (cb != NULL) {
-		if (cb->buf_buf != NULL)
-			kfree(cb->buf_buf);
+	if (cb) {
+		kfree(cb->buf_buf);
 		kfree(cb);
 	}
 }
@@ -1536,3 +1526,5 @@ module_param(debug, bool, S_IRUGO | S_IW
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(stats, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(stats, "Enable statistics or not");
+module_param(interval, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interval, "Overrides interrupt interval");
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -13,6 +13,7 @@
 /* DeLorme Earthmate USB - a GPS device */
 #define	VENDOR_ID_DELORME		 0x1163
 #define PRODUCT_ID_EARTHMATEUSB		 0x0100
+#define PRODUCT_ID_EARTHMATEUSB_LT20	 0x0200
 
 /* Cypress HID->COM RS232 Adapter */
 #define VENDOR_ID_CYPRESS		 0x04b4
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -246,6 +246,7 @@
 #include <linux/workqueue.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
+#include <linux/wait.h>
 #include "usb-serial.h"
 
 /* Defines */
@@ -567,30 +568,23 @@ static struct usb_serial_device_type dig
 *  and the sleep.  In other words, spin_unlock_irqrestore and
 *  interruptible_sleep_on_timeout are "atomic" with respect to
 *  wake ups.  This is used to implement condition variables.
+*
+*  interruptible_sleep_on_timeout is deprecated and has been replaced
+*  with the equivalent code.
 */
 
 static inline long cond_wait_interruptible_timeout_irqrestore(
 	wait_queue_head_t *q, long timeout,
 	spinlock_t *lock, unsigned long flags )
 {
+	DEFINE_WAIT(wait);
 
-	wait_queue_t wait;
-
-
-	init_waitqueue_entry( &wait, current );
-
-	set_current_state( TASK_INTERRUPTIBLE );
-
-	add_wait_queue( q, &wait );
-
-	spin_unlock_irqrestore( lock, flags );
-
+	prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+	spin_unlock_irqrestore(lock, flags);
 	timeout = schedule_timeout(timeout);
+	finish_wait(q, &wait);
 
-	remove_wait_queue( q, &wait );
-
-	return( timeout );
-
+	return timeout;
 }
 
 
@@ -1528,7 +1522,7 @@ dbg( "digi_open: TOP: port=%d, open_coun
 
 static void digi_close( struct usb_serial_port *port, struct file *filp )
 {
-
+	DEFINE_WAIT(wait);
 	int ret;
 	unsigned char buf[32];
 	struct tty_struct *tty = port->tty;
@@ -1604,8 +1598,9 @@ dbg( "digi_close: TOP: port=%d, open_cou
 			dbg( "digi_close: write oob failed, ret=%d", ret );
 
 		/* wait for final commands on oob port to complete */
-		interruptible_sleep_on_timeout( &priv->dp_flush_wait,
-			DIGI_CLOSE_TIMEOUT );
+		prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);
+		schedule_timeout(DIGI_CLOSE_TIMEOUT);
+		finish_wait(&priv->dp_flush_wait, &wait);
 
 		/* shutdown any outstanding bulk writes */
 		usb_kill_urb(port->write_urb);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -550,8 +550,7 @@ failed_usb_register:
 failed_usb_serial_register:
 	for (i = 0; i < NUM_URBS; ++i) {
 		if (write_urb_pool[i]) {
-			if (write_urb_pool[i]->transfer_buffer)
-				kfree(write_urb_pool[i]->transfer_buffer);
+			kfree(write_urb_pool[i]->transfer_buffer);
 			usb_free_urb(write_urb_pool[i]);
 		}
 	}
@@ -575,8 +574,7 @@ static void __exit empeg_exit (void)
 			 * the host controllers get fixed to set urb->dev = NULL after
 			 * the urb is finished.  Otherwise this call oopses. */
 			/* usb_kill_urb(write_urb_pool[i]); */
-			if (write_urb_pool[i]->transfer_buffer)
-				kfree(write_urb_pool[i]->transfer_buffer);
+			kfree(write_urb_pool[i]->transfer_buffer);
 			usb_free_urb (write_urb_pool[i]);
 		}
 	}
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -38,7 +38,7 @@ int ezusb_writememory (struct usb_serial
 		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, 3*HZ);
+	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3000);
 	kfree (transfer_buffer);
 	return result;
 }
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -76,7 +76,7 @@
  *      Defererence pointers after any paranoid checks, not before.
  *
  * (21/Jun/2003) Erik Nygren
- *      Added support for Home Electronics Tira-1 IR tranceiver using FT232BM chip.
+ *      Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
  *      See <http://www.home-electro.com/tira1.htm>.  Only operates properly 
  *      at 100000 and RTS-CTS, so set custom divisor mode on startup.
  *      Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
@@ -91,7 +91,7 @@
  *      Minor whitespace and comment changes.
  *
  * (12/Jun/2003) David Norwood
- *      Added support for USB-UIRT IR tranceiver using 8U232AM chip.
+ *      Added support for USB-UIRT IR transceiver using 8U232AM chip.
  *      See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>.  Only
  *      operates properly at 312500, so set custom divisor mode on startup.
  *
@@ -264,7 +264,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4.1"
+#define DRIVER_VERSION "v1.4.2"
 #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"
 
@@ -272,6 +272,7 @@ static int debug;
 
 static struct usb_device_id id_table_sio [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
+	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
 	{ }						/* Terminating entry */
 };
 
@@ -363,16 +364,20 @@ static struct usb_device_id id_table_8U2
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) },
 	{ USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_RM_VID, FTDI_RMCANVIEW_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) },
 	{ }						/* Terminating entry */
 };
 
@@ -471,6 +476,7 @@ static struct usb_device_id id_table_FT2
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
@@ -483,11 +489,15 @@ static struct usb_device_id id_table_FT2
 	{ USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_RM_VID, FTDI_RMCANVIEW_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -593,7 +603,24 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
  	{ USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
@@ -606,11 +633,16 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
 	{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
-	{ USB_DEVICE(FTDI_RM_VID, FTDI_RMCANVIEW_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
+	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
+	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -623,6 +655,13 @@ static struct usb_driver ftdi_driver = {
 	.id_table =	id_table_combined,
 };
 
+static char *ftdi_chip_name[] = {
+	[SIO] = "SIO",	/* the serial part of FT8U100AX */
+	[FT8U232AM] = "FT8U232AM",
+	[FT232BM] = "FT232BM",
+	[FT2232C] = "FT2232C",
+};
+
 
 /* Constants for read urb and write urb */
 #define BUFSZ 512
@@ -648,6 +687,8 @@ struct ftdi_private {
  	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
 	__u8 rx_flags;		/* receive state flags (throttling) */
 	spinlock_t rx_lock;	/* spinlock for receive state */
+	struct work_struct rx_work;
+	int rx_processed;
 
 	__u16 interface;	/* FT2232C port interface (0 for FT232/245) */
 
@@ -678,7 +719,7 @@ static int  ftdi_write_room		(struct usb
 static int  ftdi_chars_in_buffer	(struct usb_serial_port *port);
 static void ftdi_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
 static void ftdi_read_bulk_callback	(struct urb *urb, struct pt_regs *regs);
-static void ftdi_process_read		(struct usb_serial_port *port);
+static void ftdi_process_read		(void *param);
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_tiocmget               (struct usb_serial_port *port, struct file *file);
 static int  ftdi_tiocmset		(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
@@ -852,7 +893,7 @@ static struct usb_serial_device_type ftd
 
 
 
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
 
 /* High and low are for DTR, RTS etc etc */
 #define HIGH 1
@@ -1001,7 +1042,6 @@ static __u32 get_ftdi_divisor(struct usb
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	__u32 div_value = 0;
 	int div_okay = 1;
-	char *chip_name = "";
 	int baud;
 
 	/*
@@ -1046,7 +1086,6 @@ static __u32 get_ftdi_divisor(struct usb
 	if (!baud) baud = 9600;	
 	switch(priv->chip_type) {
 	case SIO: /* SIO chip */
-		chip_name = "SIO";
 		switch(baud) {
 		case 300: div_value = ftdi_sio_b300; break;
 		case 600: div_value = ftdi_sio_b600; break;
@@ -1066,7 +1105,6 @@ static __u32 get_ftdi_divisor(struct usb
 		}
 		break;
 	case FT8U232AM: /* 8U232AM chip */
-		chip_name = "FT8U232AM";
 		if (baud <= 3000000) {
 			div_value = ftdi_232am_baud_to_divisor(baud);
 		} else {
@@ -1077,11 +1115,6 @@ static __u32 get_ftdi_divisor(struct usb
 		break;
 	case FT232BM: /* FT232BM chip */
 	case FT2232C: /* FT2232C chip */
-		if (priv->chip_type == FT2232C) {
-			chip_name = "FT2232C";
-		} else {
-			chip_name = "FT232BM";
-		}
 		if (baud <= 3000000) {
 			div_value = ftdi_232bm_baud_to_divisor(baud);
 		} else {
@@ -1094,7 +1127,8 @@ static __u32 get_ftdi_divisor(struct usb
 
 	if (div_okay) {
 		dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
-			__FUNCTION__, baud, (unsigned long)div_value, chip_name);
+			__FUNCTION__, baud, (unsigned long)div_value,
+			ftdi_chip_name[priv->chip_type]);
 	}
 
 	return(div_value);
@@ -1184,7 +1218,7 @@ check_and_exit:
  * ***************************************************************************
  */
 
-ssize_t show_latency_timer(struct device *dev, char *buf)
+static ssize_t show_latency_timer(struct device *dev, char *buf)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1211,7 +1245,8 @@ ssize_t show_latency_timer(struct device
 }
 
 /* Write a new value of the latency timer, in units of milliseconds. */
-ssize_t store_latency_timer(struct device *dev, const char *valbuf, size_t count)
+static ssize_t store_latency_timer(struct device *dev, const char *valbuf,
+				   size_t count)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1241,7 +1276,8 @@ ssize_t store_latency_timer(struct devic
 
 /* Write an event character directly to the FTDI register.  The ASCII
    value is in the low 8 bits, with the enable bit in the 9th bit. */
-ssize_t store_event_char(struct device *dev, const char *valbuf, size_t count)
+static ssize_t store_event_char(struct device *dev, const char *valbuf,
+				size_t count)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1269,10 +1305,10 @@ ssize_t store_event_char(struct device *
 	return count;
 }
 
-static DEVICE_ATTR(latency_timer, S_IWUGO | S_IRUGO, show_latency_timer, store_latency_timer);
-static DEVICE_ATTR(event_char, S_IWUGO, NULL, store_event_char);
+static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
+static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
 
-void create_sysfs_attrs(struct usb_serial *serial)
+static void create_sysfs_attrs(struct usb_serial *serial)
 {	
 	struct ftdi_private *priv;
 	struct usb_device *udev;
@@ -1282,14 +1318,18 @@ void create_sysfs_attrs(struct usb_seria
 	priv = usb_get_serial_port_data(serial->port[0]);
 	udev = serial->dev;
 	
-	if (priv->chip_type == FT232BM) {
-		dbg("sysfs attributes for FT232BM");
+	/* XXX I've no idea if the original SIO supports the event_char
+	 * sysfs parameter, so I'm playing it safe.  */
+	if (priv->chip_type != SIO) {
+		dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
 		device_create_file(&udev->dev, &dev_attr_event_char);
-		device_create_file(&udev->dev, &dev_attr_latency_timer);
+		if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+			device_create_file(&udev->dev, &dev_attr_latency_timer);
+		}
 	}
 }
 
-void remove_sysfs_attrs(struct usb_serial *serial)
+static void remove_sysfs_attrs(struct usb_serial *serial)
 {
 	struct ftdi_private *priv;
 	struct usb_device *udev;
@@ -1299,9 +1339,12 @@ void remove_sysfs_attrs(struct usb_seria
 	priv = usb_get_serial_port_data(serial->port[0]);
 	udev = serial->dev;
 	
-	if (priv->chip_type == FT232BM) {
+	/* XXX see create_sysfs_attrs */
+	if (priv->chip_type != SIO) {
 		device_remove_file(&udev->dev, &dev_attr_event_char);
-		device_remove_file(&udev->dev, &dev_attr_latency_timer);
+		if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+			device_remove_file(&udev->dev, &dev_attr_latency_timer);
+		}
 	}
 	
 }
@@ -1335,9 +1378,7 @@ static int ftdi_common_startup (struct u
 	priv->flags = ASYNC_LOW_LATENCY;
 
 	/* Increase the size of read buffers */
-	if (port->bulk_in_buffer) {
-		kfree (port->bulk_in_buffer);
-	}
+	kfree(port->bulk_in_buffer);
 	port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL);
 	if (!port->bulk_in_buffer) {
 		kfree (priv);
@@ -1348,15 +1389,15 @@ static int ftdi_common_startup (struct u
 		port->read_urb->transfer_buffer_length = BUFSZ;
 	}
 
+	INIT_WORK(&priv->rx_work, ftdi_process_read, port);
+
 	/* Free port's existing write urb and transfer buffer. */
 	if (port->write_urb) {
 		usb_free_urb (port->write_urb);
 		port->write_urb = NULL;
 	}
-	if (port->bulk_out_buffer) {
-		kfree (port->bulk_out_buffer);
-		port->bulk_out_buffer = NULL;
-	}
+	kfree(port->bulk_out_buffer);
+	port->bulk_out_buffer = NULL;
 
 	usb_set_serial_port_data(serial->port[0], priv);
 	
@@ -1403,6 +1444,8 @@ static int ftdi_8U232AM_startup (struct 
 	priv->chip_type = FT8U232AM;
 	priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
 	
+	create_sysfs_attrs(serial);
+	
 	return (0);
 } /* ftdi_8U232AM_startup */
 
@@ -1447,13 +1490,15 @@ static int ftdi_FT2232C_startup (struct 
 	inter = serial->interface->altsetting->desc.bInterfaceNumber;
 
 	if (inter) {
-		priv->interface = INTERFACE_B;
+		priv->interface = PIT_SIOB;
 	}
 	else  {
-		priv->interface = INTERFACE_A;
+		priv->interface = PIT_SIOA;
 	}
 	priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */
 	
+	create_sysfs_attrs(serial);
+
 	return (0);
 } /* ftdi_FT2232C_startup */
 
@@ -1576,6 +1621,7 @@ static int  ftdi_open (struct usb_serial
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	/* Start reading from the device */
+	priv->rx_processed = 0;
 	usb_fill_bulk_urb(port->read_urb, dev,
 		      usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
@@ -1626,6 +1672,10 @@ static void ftdi_close (struct usb_seria
 			err("Error from RTS LOW urb");
 		}
 	} /* Note change no line if hupcl is off */
+
+	/* cancel any scheduled reading */
+	cancel_delayed_work(&priv->rx_work);
+	flush_scheduled_work();
 	
 	/* shutdown our bulk read */
 	if (port->read_urb)
@@ -1821,23 +1871,14 @@ static void ftdi_read_bulk_callback (str
 		return;
 	}
 
-	/* If throttled, delay receive processing until unthrottled. */
-	spin_lock(&priv->rx_lock);
-	if (priv->rx_flags & THROTTLED) {
-		dbg("Deferring read urb processing until unthrottled");
-		priv->rx_flags |= ACTUALLY_THROTTLED;
-		spin_unlock(&priv->rx_lock);
-		return;
-	}
-	spin_unlock(&priv->rx_lock);
-
 	ftdi_process_read(port);
 
 } /* ftdi_read_bulk_callback */
 
 
-static void ftdi_process_read (struct usb_serial_port *port)
+static void ftdi_process_read (void *param)
 { /* ftdi_process_read */
+	struct usb_serial_port *port = (struct usb_serial_port*)param;
 	struct urb *urb;
 	struct tty_struct *tty;
 	struct ftdi_private *priv;
@@ -1848,6 +1889,7 @@ static void ftdi_process_read (struct us
 	int result;
 	int need_flip;
 	int packet_offset;
+	unsigned long flags;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1874,12 +1916,18 @@ static void ftdi_process_read (struct us
 
 	data = urb->transfer_buffer;
 
-        /* The first two bytes of every read packet are status */
-	if (urb->actual_length > 2) {
-		usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+	if (priv->rx_processed) {
+		dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__,
+				priv->rx_processed,
+				urb->actual_length - priv->rx_processed);
 	} else {
-                dbg("Status only: %03oo %03oo",data[0],data[1]);
-        }
+		/* The first two bytes of every read packet are status */
+		if (urb->actual_length > 2) {
+			usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+		} else {
+			dbg("Status only: %03oo %03oo",data[0],data[1]);
+		}
+	}
 
 
 	/* TO DO -- check for hung up line and handle appropriately: */
@@ -1888,8 +1936,12 @@ static void ftdi_process_read (struct us
 	/* if CD is dropped and the line is not CLOCAL then we should hangup */
 
 	need_flip = 0;
-	for (packet_offset=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+	for (packet_offset = priv->rx_processed; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+		int length;
+
 		/* Compare new line status to the old one, signal if different */
+		/* N.B. packet may be processed more than once, but differences
+		 * are only processed once.  */
 		if (priv != NULL) {
 			char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK;
 			if (new_status != priv->prev_status) {
@@ -1899,6 +1951,35 @@ static void ftdi_process_read (struct us
 			}
 		}
 
+		length = min(PKTSZ, urb->actual_length-packet_offset)-2;
+		if (length < 0) {
+			err("%s - bad packet length: %d", __FUNCTION__, length+2);
+			length = 0;
+		}
+
+		/* have to make sure we don't overflow the buffer
+		   with tty_insert_flip_char's */
+		if (tty->flip.count+length > TTY_FLIPBUF_SIZE) {
+			tty_flip_buffer_push(tty);
+			need_flip = 0;
+
+			if (tty->flip.count != 0) {
+				/* flip didn't work, this happens when ftdi_process_read() is
+				 * called from ftdi_unthrottle, because TTY_DONT_FLIP is set */
+				dbg("%s - flip buffer push failed", __FUNCTION__);
+				break;
+			}
+		}
+		if (priv->rx_flags & THROTTLED) {
+			dbg("%s - throttled", __FUNCTION__);
+			break;
+		}
+		if (tty->ldisc.receive_room(tty)-tty->flip.count < length) {
+			/* break out & wait for throttling/unthrottling to happen */
+			dbg("%s - receive room low", __FUNCTION__);
+			break;
+		}
+
 		/* Handle errors and break */
 		error_flag = TTY_NORMAL;
 		/* Although the device uses a bitmask and hence can have multiple */
@@ -1921,13 +2002,8 @@ static void ftdi_process_read (struct us
 			error_flag = TTY_FRAME;
 			dbg("FRAMING error");
 		}
-		if (urb->actual_length > packet_offset + 2) {
-			for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) {
-				/* have to make sure we don't overflow the buffer
-				  with tty_insert_flip_char's */
-				if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
-					tty_flip_buffer_push(tty);
-				}
+		if (length > 0) {
+			for (i = 2; i < length+2; i++) {
 				/* Note that the error flag is duplicated for 
 				   every character received since we don't know
 				   which character it applied to */
@@ -1964,6 +2040,35 @@ static void ftdi_process_read (struct us
 		tty_flip_buffer_push(tty);
 	}
 
+	if (packet_offset < urb->actual_length) {
+		/* not completely processed - record progress */
+		priv->rx_processed = packet_offset;
+		dbg("%s - incomplete, %d bytes processed, %d remain",
+				__FUNCTION__, packet_offset,
+				urb->actual_length - packet_offset);
+		/* check if we were throttled while processing */
+		spin_lock_irqsave(&priv->rx_lock, flags);
+		if (priv->rx_flags & THROTTLED) {
+			priv->rx_flags |= ACTUALLY_THROTTLED;
+			spin_unlock_irqrestore(&priv->rx_lock, flags);
+			dbg("%s - deferring remainder until unthrottled",
+					__FUNCTION__);
+			return;
+		}
+		spin_unlock_irqrestore(&priv->rx_lock, flags);
+		/* if the port is closed stop trying to read */
+		if (port->open_count > 0){
+			/* delay processing of remainder */
+			schedule_delayed_work(&priv->rx_work, 1);
+		} else {
+			dbg("%s - port is closed", __FUNCTION__);
+		}
+		return;
+	}
+
+	/* urb is completely processed */
+	priv->rx_processed = 0;
+
 	/* if the port is closed stop trying to read */
 	if (port->open_count > 0){
 		/* Continue trying to always read  */
@@ -2403,7 +2508,7 @@ static void ftdi_unthrottle (struct usb_
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	if (actually_throttled)
-		ftdi_process_read(port);
+		schedule_work(&priv->rx_work);
 }
 
 static int __init ftdi_init (void)
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -136,7 +136,7 @@
 /*
  * Home Electronics (www.home-electro.com) USB gadgets
  */
-#define FTDI_HE_TIRA1_PID	0xFA78	/* Tira-1 IR tranceiver */
+#define FTDI_HE_TIRA1_PID	0xFA78	/* Tira-1 IR transceiver */
 
 /* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
 /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
@@ -144,6 +144,8 @@
 
 /* ELV USB Module UO100 (PID sent by Stefan Frings) */
 #define FTDI_ELV_UO100_PID	0xFB58	/* Product Id */
+/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */
+#define FTDI_ELV_UM100_PID	0xFB5A	/* Product Id */
 
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
@@ -156,7 +158,8 @@
  */
 #define OCT_VID			0x0B39	/* OCT vendor ID */
 /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
-/* Also rebadged as SIIG Inc. model US2308 */
+/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
+/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
 #define OCT_US101_PID		0x0421	/* OCT US101 USB to RS-232 */
 
 /* an infrared receiver for user access control with IR tags */
@@ -235,10 +238,10 @@
 
 /*
  * RM Michaelides CANview USB (http://www.rmcan.com)
- * CAN filedbus interface adapter, addad by port GmbH www.port.de)
+ * CAN fieldbus interface adapter, added by port GmbH www.port.de)
+ * Ian Abbott changed the macro names for consistency.
  */
-#define FTDI_RM_VID		0x0403	/* Vendor  Id */
-#define FTDI_RMCANVIEW_PID	0xfd60	/* Product Id */
+#define FTDI_RM_CANVIEW_PID	0xfd60	/* Product Id */
 
 /*
  * EVER Eco Pro UPS (http://www.ever.com.pl/)
@@ -246,6 +249,26 @@
 
 #define	EVER_ECO_PRO_CDS	0xe520	/* RS-232 converter */
 
+/*
+ * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
+ * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
+ * and I'm not entirely sure which are used by which.
+ */
+#define FTDI_4N_GALAXY_DE_0_PID	0x8372
+#define FTDI_4N_GALAXY_DE_1_PID	0xF3C0
+#define FTDI_4N_GALAXY_DE_2_PID	0xF3C1
+
+/*
+ * Mobility Electronics products.
+ */
+#define MOBILITY_VID			0x1342
+#define MOBILITY_USB_SERIAL_PID		0x0202	/* EasiDock USB 200 serial */
+
+/*
+ * Active Robots product ids.
+ */
+#define FTDI_ACTIVE_ROBOTS_PID	0xE548	/* USB comms board */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
@@ -258,10 +281,6 @@
 #define FTDI_SIO_SET_LATENCY_TIMER	9 /* Set the latency timer */
 #define FTDI_SIO_GET_LATENCY_TIMER	10 /* Get the latency timer */
 
-/* Port interface code for FT2232C */
-#define INTERFACE_A		1
-#define INTERFACE_B		2
-
 
 /*
  *   BmRequestType:  1100 0000b
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -614,8 +614,8 @@ static int gsp_receive(struct garmin_dat
  *
  * return <0 on error, 0 if packet is incomplete or > 0 if packet was sent
  */
-int gsp_send(struct garmin_data * garmin_data_p, const unsigned char *buf,
-              int count)
+static int gsp_send(struct garmin_data * garmin_data_p,
+		    const unsigned char *buf, int count)
 {
 	const unsigned char *src;
 	unsigned char *dst;
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/serial/hp4x.c
@@ -0,0 +1,85 @@
+/*
+ * HP4x Calculators Serial USB driver
+ *
+ * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
+ * Copyright (C) 2001-2005 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.00"
+#define DRIVER_DESC "HP4x (48/49) Generic Serial driver"
+
+#define HP_VENDOR_ID 0x03f0
+#define HP49GP_PRODUCT_ID 0x0121
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver hp49gp_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"HP4X",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+};
+
+static struct usb_serial_device_type hp49gp_device = {
+	.owner =		THIS_MODULE,
+	.name =			"HP4X",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+};
+
+static int __init hp49gp_init(void)
+{
+	int retval;
+	retval = usb_serial_register(&hp49gp_device);
+	if (retval)
+		goto failed_usb_serial_register;
+	retval = usb_register(&hp49gp_driver);
+	if (retval)
+		goto failed_usb_register;
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+failed_usb_register:
+	usb_serial_deregister(&hp49gp_device);
+failed_usb_serial_register:
+	return retval;
+}
+
+static void __exit hp49gp_exit(void)
+{
+	usb_deregister(&hp49gp_driver);
+	usb_serial_deregister(&hp49gp_device);
+}
+
+module_init(hp49gp_init);
+module_exit(hp49gp_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -261,6 +261,7 @@
 #include <linux/spinlock.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include "usb-serial.h"
@@ -950,9 +951,7 @@ static void edge_bulk_out_cmd_callback (
 
 
 	/* clean up the transfer buffer */
-	if (urb->transfer_buffer != NULL) {
-		kfree(urb->transfer_buffer);
-	}
+	kfree(urb->transfer_buffer);
 
 	/* Free the command urb */
 	usb_free_urb (urb);
@@ -971,7 +970,7 @@ static void edge_bulk_out_cmd_callback (
 
 	/* we have completed the command */
 	edge_port->commandPending = FALSE;
-	wake_up_interruptible(&edge_port->wait_command);
+	wake_up(&edge_port->wait_command);
 }
 
 
@@ -991,7 +990,6 @@ static int edge_open (struct usb_serial_
 	struct usb_serial *serial;
 	struct edgeport_serial *edge_serial;
 	int response;
-	int timeout;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1073,10 +1071,7 @@ static int edge_open (struct usb_serial_
 	}
 
 	/* now wait for the port to be completely opened */
-	timeout = OPEN_TIMEOUT;
-	while (timeout && edge_port->openPending == TRUE) {
-		timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
-	}
+	wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
 
 	if (edge_port->open == FALSE) {
 		/* open timed out */
@@ -1128,9 +1123,10 @@ static int edge_open (struct usb_serial_
  ************************************************************************/
 static void block_until_chase_response(struct edgeport_port *edge_port)
 {
+	DEFINE_WAIT(wait);
 	__u16 lastCredits;
 	int timeout = 1*HZ;
-	int wait = 10;
+	int loop = 10;
 
 	while (1) {
 		// Save Last credits
@@ -1148,12 +1144,14 @@ static void block_until_chase_response(s
 		}
 
 		// Block the thread for a while
-		interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+		prepare_to_wait(&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+		schedule_timeout(timeout);
+		finish_wait(&edge_port->wait_chase, &wait);
 
 		if (lastCredits == edge_port->txCredits) {
 			// No activity.. count down.
-			wait--;
-			if (wait == 0) {
+			loop--;
+			if (loop == 0) {
 				edge_port->chaseResponsePending = FALSE;
 				dbg("%s - Chase TIMEOUT", __FUNCTION__);
 				return;
@@ -1161,7 +1159,7 @@ static void block_until_chase_response(s
 		} else {
 			// Reset timout value back to 10 seconds
 			dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
-			wait = 10;
+			loop = 10;
 		}
 	}
 }
@@ -1179,10 +1177,11 @@ static void block_until_chase_response(s
  ************************************************************************/
 static void block_until_tx_empty (struct edgeport_port *edge_port)
 {
+	DEFINE_WAIT(wait);
 	struct TxFifo *fifo = &edge_port->txfifo;
 	__u32 lastCount;
 	int timeout = HZ/10;
-	int wait = 30;
+	int loop = 30;
 
 	while (1) {
 		// Save Last count
@@ -1195,20 +1194,22 @@ static void block_until_tx_empty (struct
 		}
 
 		// Block the thread for a while
-		interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+		prepare_to_wait (&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+		schedule_timeout(timeout);
+		finish_wait(&edge_port->wait_chase, &wait);
 
 		dbg("%s wait", __FUNCTION__);
 
 		if (lastCount == fifo->count) {
 			// No activity.. count down.
-			wait--;
-			if (wait == 0) {
+			loop--;
+			if (loop == 0) {
 				dbg("%s - TIMEOUT", __FUNCTION__);
 				return;
 			}
 		} else {
 			// Reset timout value back to seconds
-			wait = 30;
+			loop = 30;
 		}
 	}
 }
@@ -1263,16 +1264,12 @@ static void edge_close (struct usb_seria
 
 	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);
+		kfree(edge_port->write_urb->transfer_buffer);
+		usb_free_urb(edge_port->write_urb);
 		edge_port->write_urb = NULL;
 	}
-	if (edge_port->txfifo.fifo) {
-		kfree(edge_port->txfifo.fifo);
-		edge_port->txfifo.fifo = NULL;
-	}
+	kfree(edge_port->txfifo.fifo);
+	edge_port->txfifo.fifo = NULL;
 
 	dbg("%s exited", __FUNCTION__);
 }   
@@ -1416,11 +1413,9 @@ static void send_more_port_data(struct e
 	// get a pointer to the write_urb
 	urb = edge_port->write_urb;
 
-	/* if this urb had a transfer buffer already (old transfer) free it */
-	if (urb->transfer_buffer != NULL) {
-		kfree(urb->transfer_buffer);
-		urb->transfer_buffer = NULL;
-	}
+	/* make sure transfer buffer is freed */
+	kfree(urb->transfer_buffer);
+	urb->transfer_buffer = NULL;
 
 	/* build the data header for the buffer and port that we are about to send out */
 	count = fifo->count;
@@ -1836,12 +1831,12 @@ static int get_serial_info(struct edgepo
  *****************************************************************************/
 static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
 {
+	DEFINE_WAIT(wait);
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	struct async_icount cnow;
 	struct async_icount cprev;
 	struct serial_icounter_struct icount;
 
-
 	dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
 
 	switch (cmd) {
@@ -1868,7 +1863,9 @@ static int edge_ioctl (struct usb_serial
 			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
 			cprev = edge_port->icount;
 			while (1) {
-				interruptible_sleep_on(&edge_port->delta_msr_wait);
+				prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE);
+				schedule();
+				finish_wait(&edge_port->delta_msr_wait, &wait);
 				/* see if a signal did it */
 				if (signal_pending(current))
 					return -ERESTARTSYS;
@@ -2108,7 +2105,7 @@ static void process_rcvd_status (struct 
 				// We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
 				// like wait longer in block_until_chase_response, but for now we don't. 
 				edge_port->chaseResponsePending = FALSE;
-				wake_up_interruptible (&edge_port->wait_chase);
+				wake_up (&edge_port->wait_chase);
 				return;
 
 			case IOSP_EXT_STATUS_RX_CHECK_RSP:
@@ -2131,7 +2128,7 @@ static void process_rcvd_status (struct 
 		/* we have completed the open */
 		edge_port->openPending = FALSE;
 		edge_port->open = TRUE;
-		wake_up_interruptible(&edge_port->wait_open);
+		wake_up(&edge_port->wait_open);
 		return;
 	}
 
@@ -2500,9 +2497,7 @@ static int write_cmd_usb (struct edgepor
 	// wait for command to finish
 	timeout = COMMAND_TIMEOUT;
 #if 0
-	while (timeout && edge_port->commandPending == TRUE) {
-		timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout);
-	}
+	wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
 
 	if (edge_port->commandPending == TRUE) {
 		/* command timed out */
@@ -3107,4 +3102,4 @@ module_param(debug, bool, S_IRUGO | S_IW
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 module_param(low_latency, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Low latency enabled or not");
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -273,7 +273,7 @@ static int TIReadVendorRequestSync (stru
 				index,
 				data,
 				size,
-				HZ);
+				1000);
 	if (status < 0)
 		return status;
 	if (status != size) {
@@ -303,8 +303,7 @@ static int TISendVendorRequestSync (stru
 				index,
 				data,
 				size,
-				HZ);
-
+				1000);
 	if (status < 0)
 		return status;
 	if (status != size) {
@@ -985,7 +984,7 @@ static int TISendBulkTransferSync (struc
 				buffer,
 				length,
 				num_sent,
-				HZ);
+				1000);
 	return status;
 }
 
@@ -2846,9 +2845,8 @@ static struct edge_buf *edge_buf_alloc(u
 
 void edge_buf_free(struct edge_buf *eb)
 {
-	if (eb != NULL) {
-		if (eb->buf_buf != NULL)
-			kfree(eb->buf_buf);
+	if (eb) {
+		kfree(eb->buf_buf);
 		kfree(eb);
 	}
 }
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -289,7 +289,7 @@
 //
 
 //
-// Edgeport Compatiblity Descriptor
+// Edgeport Compatibility Descriptor
 //
 // This descriptor is only returned by Edgeport-compatible devices
 // supporting the EPiC spec. True ION devices do not return this
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -662,7 +662,7 @@ static int ipaq_open(struct usb_serial_p
 	while (retries--) {
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
-				0x1, 0, NULL, 0, HZ / 10 + 1);
+				0x1, 0, NULL, 0, 100);
 		if (result == 0) {
 			return 0;
 		}
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -232,7 +232,7 @@ static int ipw_open(struct usb_serial_po
 				 0, /* index */
 				 NULL,
 				 0,
-				 100*HZ);
+				 100000);
 	if (result < 0)
 		dev_err(&port->dev, "Init of modem failed (error = %d)", result);
 
@@ -260,7 +260,7 @@ static int ipw_open(struct usb_serial_po
 				 0, /* index */
 				 NULL,
 				 0,
-				 100*HZ);
+				 100000);
 	if (result < 0) 
 		dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)", result);
 
@@ -273,7 +273,7 @@ static int ipw_open(struct usb_serial_po
 				 0,
 				 buf_flow_init,
 				 0x10,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "initial flowcontrol failed (error = %d)", result);
 
@@ -287,7 +287,7 @@ static int ipw_open(struct usb_serial_po
 				 0,
 				 NULL,
 				 0,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "setting dtr failed (error = %d)", result);
 
@@ -300,7 +300,7 @@ static int ipw_open(struct usb_serial_po
 				 0,
 				 NULL,
 				 0,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "setting dtr failed (error = %d)", result);
 	
@@ -327,7 +327,7 @@ static void ipw_close(struct usb_serial_
 				 0,
 				 NULL,
 				 0,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "dropping dtr failed (error = %d)", result);
 
@@ -339,7 +339,7 @@ static void ipw_close(struct usb_serial_
 				 0,
 				 NULL,
 				 0,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "dropping rts failed (error = %d)", result);
 
@@ -352,7 +352,7 @@ static void ipw_close(struct usb_serial_
 				 0,
 				 NULL,
 				 0,
-				 200*HZ);
+				 200000);
 	if (result < 0)
 		dev_err(&port->dev, "purge failed (error = %d)", result);
 
@@ -365,7 +365,7 @@ static void ipw_close(struct usb_serial_
 				 0, /* index */
 				 NULL,
 				 0,
-				 100*HZ);
+				 100000);
 
 	if (result < 0)
 		dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)", result);
@@ -457,7 +457,7 @@ static struct usb_serial_device_type ipw
 
 
 
-int usb_ipw_init(void)
+static int usb_ipw_init(void)
 {
 	int retval;
 
@@ -473,7 +473,7 @@ int usb_ipw_init(void)
 	return 0;
 }
 
-void usb_ipw_exit(void)
+static void usb_ipw_exit(void)
 {
 	usb_deregister(&usb_ipw_driver);
 	usb_serial_deregister(&ipw_device);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -189,7 +189,7 @@ static struct irda_class_desc *irda_usb_
 	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), HZ);
+			0, ifnum, desc, sizeof(*desc), 1000);
 	
 	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -205,7 +205,7 @@ static void keyspan_pda_request_unthrott
 				 0, /* index */
 				 NULL,
 				 0,
-				 2*HZ);
+				 2000);
 	if (result < 0)
 		dbg("%s - error %d from usb_control_msg", 
 		    __FUNCTION__, result);
@@ -330,7 +330,7 @@ static int keyspan_pda_setbaud (struct u
 			     0, /* index */
 			     NULL, /* &data */
 			     0, /* size */
-			     2*HZ); /* timeout */
+			     2000); /* timeout */
 	return(rc);
 }
 
@@ -348,7 +348,7 @@ static void keyspan_pda_break_ctl (struc
 	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);
+				value, 0, NULL, 0, 2000);
 	if (result < 0)
 		dbg("%s - error %d from usb_control_msg", 
 		    __FUNCTION__, result);
@@ -416,7 +416,7 @@ static int keyspan_pda_get_modem_info(st
 	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			     3, /* get pins */
 			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
-			     0, 0, &data, 1, 2*HZ);
+			     0, 0, &data, 1, 2000);
 	if (rc > 0)
 		*value = data;
 	return rc;
@@ -430,7 +430,7 @@ static int keyspan_pda_set_modem_info(st
 	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			     3, /* set pins */
 			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
-			     value, 0, NULL, 0, 2*HZ);
+			     value, 0, NULL, 0, 2000);
 	return rc;
 }
 
@@ -545,7 +545,7 @@ static int keyspan_pda_write(struct usb_
 				     0, /* index */
 				     &room,
 				     1,
-				     2*HZ);
+				     2000);
 		if (rc < 0) {
 			dbg(" roomquery failed");
 			goto exit;
@@ -653,7 +653,7 @@ static int keyspan_pda_open (struct usb_
 			     0, /* index */
 			     &room,
 			     1,
-			     2*HZ);
+			     2000);
 	if (rc < 0) {
 		dbg("%s - roomquery failed", __FUNCTION__);
 		goto error;
diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h
--- a/drivers/usb/serial/keyspan_usa90msg.h
+++ b/drivers/usb/serial/keyspan_usa90msg.h
@@ -19,7 +19,7 @@
 
         	This file is available under a BSD-style copyright
 
-	2. The name of InnoSys Incorprated may not be used to endorse or promote
+	2. The name of InnoSys Incorporated may not be used to endorse or promote
    	products derived from this software without specific prior written
    	permission.
 
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -178,7 +178,7 @@ struct klsi_105_private {
  */
 
 
-#define KLSI_TIMEOUT	 (HZ * 5 ) /* default urb timeout */
+#define KLSI_TIMEOUT	 5000 /* default urb timeout */
 
 static int klsi_105_chg_port_settings(struct usb_serial_port *port,
 				      struct klsi_105_port_settings *settings)
@@ -236,7 +236,7 @@ static int klsi_105_get_line_state(struc
 			     0, /* value */
 			     0, /* index */
 			     status_buf, KLSI_STATUSBUF_LEN,
-			     10*HZ
+			     10000
 			     );
 	if (rc < 0)
 		err("Reading line status failed (error = %d)", rc);
@@ -341,8 +341,7 @@ static void klsi_105_shutdown (struct us
 					 * finished.  Otherwise this call
 					 * oopses. */
 					/* usb_kill_urb(write_urbs[j]); */
-					if (write_urbs[j]->transfer_buffer)
-						    kfree(write_urbs[j]->transfer_buffer);
+					kfree(write_urbs[j]->transfer_buffer);
 					usb_free_urb (write_urbs[j]);
 				}
 			}
@@ -925,45 +924,34 @@ static int klsi_105_ioctl (struct usb_se
 		/* TODO */
 		dbg("%s - TIOCMIWAIT not handled", __FUNCTION__);
 		return -ENOIOCTLCMD;
-
 	case TIOCGICOUNT:
 		/* return count of modemline transitions */
 		/* TODO */
 		dbg("%s - TIOCGICOUNT not handled", __FUNCTION__);
 		return -ENOIOCTLCMD;
-	case TCGETS: {
-	     /* return current info to caller */
-	     int retval;
-
-	     dbg("%s - TCGETS data faked/incomplete", __FUNCTION__);
-
-	     retval = verify_area(VERIFY_WRITE, user_arg,
-				  sizeof(struct termios));
-	     if (retval)
-			 return retval;
-
-	     if (kernel_termios_to_user_termios((struct termios __user *)arg,
-						&priv->termios))
-		     return -EFAULT;
-	     return(0);
-	     }
-	case TCSETS: {
-		/* set port termios to the one given by the user */
-		int retval;
+	case TCGETS:
+		/* return current info to caller */
+		dbg("%s - TCGETS data faked/incomplete", __FUNCTION__);
+
+		if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios)))
+			return -EFAULT;
 
+		if (kernel_termios_to_user_termios((struct termios __user *)arg,
+						   &priv->termios))
+			return -EFAULT;
+		return 0;
+	case TCSETS:
+		/* set port termios to the one given by the user */
 		dbg("%s - TCSETS not handled", __FUNCTION__);
 
-		retval = verify_area(VERIFY_READ, user_arg,
-				     sizeof(struct termios));
-		if (retval)
-			    return retval;
+		if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios)))
+			return -EFAULT;
 
 		if (user_termios_to_kernel_termios(&priv->termios,
-						  (struct termios __user *)arg))
+						   (struct termios __user *)arg))
 			return -EFAULT;
 		klsi_105_set_termios(port, &priv->termios);
-		return(0);
-	     }
+		return 0;
 	case TCSETSW: {
 		/* set port termios and try to wait for completion of last
 		 * write operation */
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -637,10 +637,9 @@ static int  kobil_ioctl(struct usb_seria
 
 	switch (cmd) {
 	case TCGETS:   // 0x5401
-		result = verify_area(VERIFY_WRITE, user_arg, sizeof(struct termios));
-		if (result) {
-			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
-			return(result);
+		if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) {
+			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
+			return -EFAULT;
 		}
 		if (kernel_termios_to_user_termios((struct termios __user *)arg,
 						   &priv->internal_termios))
@@ -652,10 +651,9 @@ static int  kobil_ioctl(struct usb_seria
 			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
 			return -ENOTTY;
 		}
-		result = verify_area(VERIFY_READ, user_arg, sizeof(struct termios));
-		if (result) {
-			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
-			return result;
+		if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) {
+			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
+			return -EFAULT;
 		}
 		if (user_termios_to_kernel_termios(&priv->internal_termios,
 						   (struct termios __user *)arg))
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -166,7 +166,7 @@ struct mct_u232_private {
  * Handle vendor specific USB requests
  */
 
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
 
 /*
  * Later day 2.6.0-test kernels have new baud rates like B230400 which
@@ -195,16 +195,16 @@ static int mct_u232_calculate_baud_rate(
 		}
 	} else {
 		switch (value) {
-		case    B300: value =     300;
-		case    B600: value =     600;
-		case   B1200: value =    1200;
-		case   B2400: value =    2400;
-		case   B4800: value =    4800;
-		case   B9600: value =    9600;
-		case  B19200: value =   19200;
-		case  B38400: value =   38400;
-		case  B57600: value =   57600;
-		case B115200: value =  115200;
+		case    B300: value =     300; break;
+		case    B600: value =     600; break;
+		case   B1200: value =    1200; break;
+		case   B2400: value =    2400; break;
+		case   B4800: value =    4800; break;
+		case   B9600: value =    9600; break;
+		case  B19200: value =   19200; break;
+		case  B38400: value =   38400; break;
+		case  B57600: value =   57600; break;
+		case B115200: value =  115200; break;
 		default:
 			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
 			    " using default of B9600", value);
@@ -646,7 +646,7 @@ static void mct_u232_set_termios (struct
 	else
 		new_state &= ~(TIOCM_DTR | TIOCM_RTS);
 	if (new_state != control_state) {
-		mct_u232_set_modem_ctrl(serial, control_state);
+		mct_u232_set_modem_ctrl(serial, new_state);
 		control_state = new_state;
 	}
 
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -178,7 +178,6 @@ static void omninet_close (struct usb_se
 {
 	struct usb_serial 	*serial = port->serial;
 	struct usb_serial_port 	*wport;
-	struct omninet_data 	*od;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -186,9 +185,7 @@ static void omninet_close (struct usb_se
 	usb_kill_urb(wport->write_urb);
 	usb_kill_urb(port->read_urb);
 
-	od = usb_get_serial_port_data(port);
-	if (od)
-		kfree(od);
+	kfree(usb_get_serial_port_data(port));
 }
 
 
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/serial/option.c
@@ -0,0 +1,729 @@
+/*
+  Option Card (PCMCIA to) USB to Serial Driver
+
+  Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>
+
+  This driver 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.
+
+  Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+  History:
+
+  2005-05-19  v0.1   Initial version, based on incomplete docs
+                     and analysis of misbehavior of the standard driver
+  2005-05-20  v0.2   Extended the input buffer to avoid losing
+                     random 64-byte chunks of data
+  2005-05-21  v0.3   implemented chars_in_buffer()
+                     turned on low_latency
+                     simplified the code somewhat
+*/
+#define DRIVER_VERSION "v0.3"
+#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
+#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+/* Function prototypes */
+static int  option_open (struct usb_serial_port *port, struct file *filp);
+static void option_close (struct usb_serial_port *port, struct file *filp);
+static int  option_startup (struct usb_serial *serial);
+static void option_shutdown (struct usb_serial *serial);
+static void option_rx_throttle (struct usb_serial_port *port);
+static void option_rx_unthrottle (struct usb_serial_port *port);
+static int  option_write_room (struct usb_serial_port *port);
+
+static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
+
+
+static int  option_write (struct usb_serial_port *port,
+                          const unsigned char *buf, int count);
+
+static int  option_chars_in_buffer (struct usb_serial_port *port);
+static int  option_ioctl (struct usb_serial_port *port, struct file *file,
+                          unsigned int cmd, unsigned long arg);
+static void option_set_termios (struct usb_serial_port *port,
+                                struct termios *old);
+static void option_break_ctl (struct usb_serial_port *port, int break_state);
+static int  option_tiocmget (struct usb_serial_port *port, struct file *file);
+static int  option_tiocmset (struct usb_serial_port *port, struct file *file,
+                             unsigned int set, unsigned int clear);
+static int  option_send_setup (struct usb_serial_port *port);
+
+/* Vendor and product IDs */
+#define OPTION_VENDOR_ID		0x0AF0
+
+#define	OPTION_PRODUCT_OLD		0x5000
+#define	OPTION_PRODUCT_WLAN		0x6000
+
+static struct usb_device_id option_ids[] = {
+	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
+	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_WLAN) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, option_ids);
+
+static struct usb_driver option_driver = {
+	.owner      = THIS_MODULE,
+	.name       = "option",
+	.probe      = usb_serial_probe,
+	.disconnect = usb_serial_disconnect,
+	.id_table   = option_ids,
+};
+
+/* The card has three separate interfaces, wich the serial driver
+ * recognizes separately, thus num_port=1.
+ */
+static struct usb_serial_device_type option_3port_device = {
+	.owner			= THIS_MODULE,
+	.name			= "Option 3-port card",
+	.short_name		= "option",
+	.id_table		= option_ids,
+	.num_interrupt_in	= NUM_DONT_CARE,
+	.num_bulk_in		= NUM_DONT_CARE,
+	.num_bulk_out		= NUM_DONT_CARE,
+	.num_ports		= 1, /* 3 */
+	.open			= option_open,
+	.close			= option_close,
+	.write			= option_write,
+	.write_room		= option_write_room,
+	.chars_in_buffer	= option_chars_in_buffer,
+	.throttle		= option_rx_throttle,
+	.unthrottle		= option_rx_unthrottle,
+	.ioctl			= option_ioctl,
+	.set_termios		= option_set_termios,
+	.break_ctl		= option_break_ctl,
+	.tiocmget		= option_tiocmget,
+	.tiocmset		= option_tiocmset,
+	.attach			= option_startup,
+	.shutdown		= option_shutdown,
+	.read_int_callback	= option_instat_callback,
+};
+
+static int debug;
+
+/* per port private data */
+
+#define N_IN_URB	4
+#define N_OUT_URB	1
+#define IN_BUFLEN	1024
+#define OUT_BUFLEN	1024
+
+struct option_port_private {
+	/* Input endpoints and buffer for this port */
+	struct urb	*in_urbs[N_IN_URB];
+	char		in_buffer[N_IN_URB][IN_BUFLEN];
+	/* Output endpoints and buffer for this port */
+	struct urb	*out_urbs[N_OUT_URB];
+	char		out_buffer[N_OUT_URB][OUT_BUFLEN];
+
+	/* Settings for the port */
+	int		rts_state;	/* Handshaking pins (outputs) */
+	int		dtr_state;
+	int		cts_state;	/* Handshaking pins (inputs) */
+	int		dsr_state;
+	int		dcd_state;
+	int		ri_state;
+	// int		break_on;
+
+	unsigned long	tx_start_time[N_OUT_URB];
+};
+
+
+/* Functions used by new usb-serial code. */
+static int __init
+option_init (void)
+{
+	int retval;
+	retval = usb_serial_register(&option_3port_device);
+	if (retval)
+		goto failed_3port_device_register;
+	retval = usb_register(&option_driver);
+	if (retval)
+		goto failed_driver_register;
+
+	info(DRIVER_DESC ": " DRIVER_VERSION);
+
+	return 0;
+
+failed_driver_register:
+	usb_serial_deregister (&option_3port_device);
+failed_3port_device_register:
+	return retval;
+}
+
+static void __exit
+option_exit (void)
+{
+	usb_deregister (&option_driver);
+	usb_serial_deregister (&option_3port_device);
+}
+
+module_init(option_init);
+module_exit(option_exit);
+
+static void
+option_rx_throttle (struct usb_serial_port *port)
+{
+	dbg("%s", __FUNCTION__);
+}
+
+
+static void
+option_rx_unthrottle (struct usb_serial_port *port)
+{
+	dbg("%s", __FUNCTION__);
+}
+
+
+static void
+option_break_ctl (struct usb_serial_port *port, int break_state)
+{
+	/* Unfortunately, I don't know how to send a break */
+ 	dbg("%s", __FUNCTION__);
+}
+
+
+static void
+option_set_termios (struct usb_serial_port *port,
+				     struct termios *old_termios)
+{
+	dbg("%s", __FUNCTION__);
+
+	option_send_setup(port);
+}
+
+static int
+option_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+	unsigned int			value;
+	struct option_port_private 	*portdata;
+
+	portdata = usb_get_serial_port_data(port);
+
+	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+		((portdata->dtr_state) ? TIOCM_DTR : 0) |
+		((portdata->cts_state) ? TIOCM_CTS : 0) |
+		((portdata->dsr_state) ? TIOCM_DSR : 0) |
+		((portdata->dcd_state) ? TIOCM_CAR : 0) |
+		((portdata->ri_state) ? TIOCM_RNG : 0);
+
+	return value;
+}
+
+static int
+option_tiocmset (struct usb_serial_port *port, struct file *file,
+                 unsigned int set, unsigned int clear)
+{
+	struct option_port_private 	*portdata;
+
+	portdata = usb_get_serial_port_data(port);
+
+	if (set & TIOCM_RTS)
+		portdata->rts_state = 1;
+	if (set & TIOCM_DTR)
+		portdata->dtr_state = 1;
+
+	if (clear & TIOCM_RTS)
+		portdata->rts_state = 0;
+	if (clear & TIOCM_DTR)
+		portdata->dtr_state = 0;
+	return option_send_setup(port);
+}
+
+static int
+option_ioctl (struct usb_serial_port *port, struct file *file,
+              unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+/* Write */
+static int
+option_write(struct usb_serial_port *port,
+			 const unsigned char *buf, int count)
+{
+	struct option_port_private 	*portdata;
+	int				i;
+	int 				left, todo;
+	struct urb			*this_urb = NULL; /* spurious */
+ 	int 				err;
+
+	portdata = usb_get_serial_port_data(port);
+
+	dbg("%s: write (%d chars)", __FUNCTION__, count);
+
+#if 0
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
+		dbg("%s: already writing", __FUNCTION__);
+		return 0;
+	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
+#endif
+
+	i = 0;
+	left = count;
+	while (left>0) {
+		todo = left;
+		if (todo > OUT_BUFLEN)
+			todo = OUT_BUFLEN;
+
+		for (;i < N_OUT_URB; i++) {
+			/* Check we have a valid urb/endpoint before we use it... */
+			this_urb = portdata->out_urbs[i];
+			if (this_urb->status != -EINPROGRESS)
+				break;
+			if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
+				continue;
+			if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
+				continue;
+			this_urb->transfer_flags |= URB_ASYNC_UNLINK;
+			usb_unlink_urb(this_urb);
+		}
+
+		if (i == N_OUT_URB) {
+			/* no bulk out free! */
+			dbg("%s: no output urb -- left %d", __FUNCTION__,count-left);
+#if 0
+			port->write_urb_busy = 0;
+#endif
+			return count-left;
+		}
+
+		dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
+
+		memcpy (this_urb->transfer_buffer, buf, todo);
+
+		/* send the data out the bulk port */
+		this_urb->transfer_buffer_length = todo;
+
+		this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+		this_urb->dev = port->serial->dev;
+		err = usb_submit_urb(this_urb, GFP_ATOMIC);
+		if (err) {
+			dbg("usb_submit_urb %p (write bulk) failed (%d,, has %d)", this_urb, err, this_urb->status);
+			continue;
+		}
+		portdata->tx_start_time[i] = jiffies;
+		buf += todo;
+		left -= todo;
+	}
+
+	count -= left;
+#if 0
+	port->write_urb_busy = 0;
+#endif
+	dbg("%s: wrote (did %d)", __FUNCTION__, count);
+	return count;
+}
+
+static void
+option_indat_callback (struct urb *urb, struct pt_regs *regs)
+{
+	int	i, err;
+	int endpoint;
+	struct usb_serial_port *port;
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+
+	dbg("%s: %p", __FUNCTION__, urb);
+
+	endpoint = usb_pipeendpoint(urb->pipe);
+	port = (struct usb_serial_port *) urb->context;
+
+	if (urb->status) {
+		dbg("%s: nonzero status: %d on endpoint %02x.",
+		    __FUNCTION__, urb->status, endpoint);
+	} else {
+		tty = port->tty;
+		if (urb->actual_length) {
+			for (i = 0; i < urb->actual_length ; ++i) {
+				if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+					tty_flip_buffer_push(tty);
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		} else {
+			dbg("%s: empty read urb received", __FUNCTION__);
+		}
+
+		/* Resubmit urb so we continue receiving */
+		if (port->open_count && urb->status != -ESHUTDOWN) {
+			err = usb_submit_urb(urb, GFP_ATOMIC);
+			if (err)
+				printk(KERN_ERR "%s: resubmit read urb failed. (%d)", __FUNCTION__, err);
+		}
+	}
+	return;
+}
+
+static void
+option_outdat_callback (struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port;
+
+	dbg("%s", __FUNCTION__);
+
+	port = (struct usb_serial_port *) urb->context;
+
+	if (port->open_count)
+		schedule_work(&port->work);
+}
+
+static void
+option_instat_callback (struct urb *urb, struct pt_regs *regs)
+{
+	int err;
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct option_port_private *portdata = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+
+	dbg("%s", __FUNCTION__);
+	dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+
+	if (urb->status == 0) {
+		struct usb_ctrlrequest *req_pkt =
+				(struct usb_ctrlrequest *)urb->transfer_buffer;
+
+		if (!req_pkt) {
+			dbg("%s: NULL req_pkt\n", __FUNCTION__);
+			return;
+		}
+		if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
+			int old_dcd_state;
+			unsigned char signals = *((unsigned char *)
+					urb->transfer_buffer + sizeof(struct usb_ctrlrequest));
+
+			dbg("%s: signal x%x", __FUNCTION__, signals);
+
+			old_dcd_state = portdata->dcd_state;
+			portdata->cts_state = 1;
+			portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+			if (port->tty && !C_CLOCAL(port->tty)
+					&& old_dcd_state && !portdata->dcd_state) {
+				tty_hangup(port->tty);
+			}
+		} else
+			dbg("%s: type %x req %x", __FUNCTION__, req_pkt->bRequestType,req_pkt->bRequest);
+	} else
+		dbg("%s: error %d", __FUNCTION__, urb->status);
+
+	/* Resubmit urb so we continue receiving IRQ data */
+	if (urb->status != -ESHUTDOWN) {
+		urb->dev = serial->dev;
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (err)
+			dbg("%s: resubmit intr urb failed. (%d)", __FUNCTION__, err);
+	}
+}
+
+
+static int
+option_write_room (struct usb_serial_port *port)
+{
+	struct option_port_private *portdata;
+	int i;
+	int data_len = 0;
+	struct urb *this_urb;
+
+	portdata = usb_get_serial_port_data(port);
+
+	for (i=0; i < N_OUT_URB; i++)
+		this_urb = portdata->out_urbs[i];
+		if (this_urb && this_urb->status != -EINPROGRESS)
+			data_len += OUT_BUFLEN;
+
+	dbg("%s: %d", __FUNCTION__, data_len);
+	return data_len;
+}
+
+
+static int
+option_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct option_port_private *portdata;
+	int i;
+	int data_len = 0;
+	struct urb *this_urb;
+
+	portdata = usb_get_serial_port_data(port);
+
+	for (i=0; i < N_OUT_URB; i++)
+		this_urb = portdata->out_urbs[i];
+		if (this_urb && this_urb->status == -EINPROGRESS)
+			data_len += this_urb->transfer_buffer_length;
+
+	dbg("%s: %d", __FUNCTION__, data_len);
+	return data_len;
+}
+
+
+static int
+option_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct option_port_private 	*portdata;
+	struct usb_serial 		*serial = port->serial;
+	int				i, err;
+	struct urb			*urb;
+
+	portdata = usb_get_serial_port_data(port);
+
+	dbg("%s", __FUNCTION__);
+
+	/* Set some sane defaults */
+	portdata->rts_state = 1;
+	portdata->dtr_state = 1;
+
+	/* Reset low level data toggle and start reading from endpoints */
+	for (i = 0; i < N_IN_URB; i++) {
+		urb = portdata->in_urbs[i];
+		if (! urb)
+			continue;
+		if (urb->dev != serial->dev) {
+			dbg("%s: dev %p != %p", __FUNCTION__, urb->dev, serial->dev);
+			continue;
+		}
+
+		/* make sure endpoint data toggle is synchronized with the device */
+
+		usb_clear_halt(urb->dev, urb->pipe);
+
+		err = usb_submit_urb(urb, GFP_KERNEL);
+		if (err) {
+			dbg("%s: submit urb %d failed (%d) %d", __FUNCTION__, i, err,
+				urb->transfer_buffer_length);
+		}
+	}
+
+	/* Reset low level data toggle on out endpoints */
+	for (i = 0; i < N_OUT_URB; i++) {
+		urb = portdata->out_urbs[i];
+		if (! urb)
+			continue;
+		urb->dev = serial->dev;
+		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
+	}
+
+	port->tty->low_latency = 1;
+
+	option_send_setup(port);
+
+	return (0);
+}
+
+static inline void
+stop_urb(struct urb *urb)
+{
+	if (urb && urb->status == -EINPROGRESS) {
+		urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+		usb_kill_urb(urb);
+	}
+}
+
+static void
+option_close(struct usb_serial_port *port, struct file *filp)
+{
+	int			i;
+	struct usb_serial	*serial = port->serial;
+	struct option_port_private 	*portdata;
+
+	dbg("%s", __FUNCTION__);
+	portdata = usb_get_serial_port_data(port);
+
+	portdata->rts_state = 0;
+	portdata->dtr_state = 0;
+
+	if (serial->dev) {
+		option_send_setup(port);
+
+		/* Stop reading/writing urbs */
+		for (i = 0; i < N_IN_URB; i++)
+			stop_urb(portdata->in_urbs[i]);
+		for (i = 0; i < N_OUT_URB; i++)
+			stop_urb(portdata->out_urbs[i]);
+	}
+	port->tty = NULL;
+}
+
+
+/* Helper functions used by option_setup_urbs */
+static struct urb *
+option_setup_urb (struct usb_serial *serial, int endpoint,
+                  int dir, void *ctx, char *buf, int len,
+                  void (*callback)(struct urb *, struct pt_regs *regs))
+{
+	struct urb *urb;
+
+	if (endpoint == -1)
+		return NULL;		/* endpoint not needed */
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
+	if (urb == NULL) {
+		dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+		return NULL;
+	}
+
+		/* Fill URB using supplied data. */
+	usb_fill_bulk_urb(urb, serial->dev,
+		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
+		      buf, len, callback, ctx);
+
+	return urb;
+}
+
+/* Setup urbs */
+static void
+option_setup_urbs(struct usb_serial *serial)
+{
+	int				j;
+	struct usb_serial_port		*port;
+	struct option_port_private	*portdata;
+
+	dbg("%s", __FUNCTION__);
+
+	port = serial->port[0];
+	portdata = usb_get_serial_port_data(port);
+
+	/* Do indat endpoints first */
+	for (j = 0; j <= N_IN_URB; ++j) {
+		portdata->in_urbs[j] = option_setup_urb (serial,
+                  port->bulk_in_endpointAddress, USB_DIR_IN, port,
+                  portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
+	}
+
+	/* outdat endpoints */
+	for (j = 0; j <= N_OUT_URB; ++j) {
+		portdata->out_urbs[j] = option_setup_urb (serial,
+                  port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+                  portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
+	}
+}
+
+
+static int
+option_send_setup(struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	struct option_port_private *portdata;
+
+	dbg("%s", __FUNCTION__);
+
+	portdata = usb_get_serial_port_data(port);
+
+	if (port->tty) {
+		int val = 0;
+		if (portdata->dtr_state)
+			val |= 0x01;
+		if (portdata->rts_state)
+			val |= 0x02;
+
+		return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+					0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+	}
+
+	return 0;
+}
+
+
+static int
+option_startup (struct usb_serial *serial)
+{
+	int				i, err;
+	struct usb_serial_port		*port;
+	struct option_port_private	*portdata;
+
+	dbg("%s", __FUNCTION__);
+
+	/* Now setup per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
+		if (!portdata) {
+			dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i);
+			return (1);
+		}
+		memset(portdata, 0, sizeof(struct option_port_private));
+
+		usb_set_serial_port_data(port, portdata);
+
+		if (! port->interrupt_in_urb)
+			continue;
+		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+		if (err)
+			dbg("%s: submit irq_in urb failed %d", __FUNCTION__, err);
+	}
+
+	option_setup_urbs(serial);
+
+	return (0);
+}
+
+static void
+option_shutdown (struct usb_serial *serial)
+{
+	int				i, j;
+	struct usb_serial_port		*port;
+	struct option_port_private	*portdata;
+
+	dbg("%s", __FUNCTION__);
+
+	/* Stop reading/writing urbs */
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+		for (j = 0; j < N_IN_URB; j++)
+			stop_urb(portdata->in_urbs[j]);
+		for (j = 0; j < N_OUT_URB; j++)
+			stop_urb(portdata->out_urbs[j]);
+	}
+
+	/* Now free them */
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+
+		for (j = 0; j < N_IN_URB; j++) {
+			if (portdata->in_urbs[j]) {
+				usb_free_urb(portdata->in_urbs[j]);
+				portdata->in_urbs[j] = NULL;
+			}
+		}
+		for (j = 0; j < N_OUT_URB; j++) {
+			if (portdata->out_urbs[j]) {
+				usb_free_urb(portdata->out_urbs[j]);
+				portdata->out_urbs[j] = NULL;
+			}
+		}
+	}
+
+	/* Now free per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		kfree(usb_get_serial_port_data(port));
+	}
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
+
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -94,6 +94,7 @@ static struct usb_device_id id_table [] 
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
+	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -677,6 +678,9 @@ static int pl2303_tiocmset (struct usb_s
 	unsigned long flags;
 	u8 control;
 
+	if (!usb_get_intfdata(port->serial->interface))
+		return -ENODEV;
+
 	spin_lock_irqsave (&priv->lock, flags);
 	if (set & TIOCM_RTS)
 		priv->line_control |= CONTROL_RTS;
@@ -702,6 +706,9 @@ static int pl2303_tiocmget (struct usb_s
 
 	dbg("%s (%d)", __FUNCTION__, port->number);
 
+	if (!usb_get_intfdata(port->serial->interface))
+		return -ENODEV;
+
 	spin_lock_irqsave (&priv->lock, flags);
 	mcr = priv->line_control;
 	status = priv->line_status;
@@ -811,15 +818,40 @@ static void pl2303_shutdown (struct usb_
 	}		
 }
 
+static void pl2303_update_line_status(struct usb_serial_port *port,
+				      unsigned char *data,
+				      unsigned int actual_length)
+{
+
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	u8 status_idx = UART_STATE;
+	u8 length = UART_STATE;
+
+	if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
+	    (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65)) {
+		length = 1;
+		status_idx = 0;
+	}
+
+	if (actual_length < length)
+		goto exit;
+
+        /* Save off the uart status for others to look at */
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->line_status = data[status_idx];
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+exit:
+	return;
+}
 
 static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned char *data = urb->transfer_buffer;
-	unsigned long flags;
+	unsigned int actual_length = urb->actual_length;
 	int status;
-	u8 uart_state;
 
 	dbg("%s (%d)", __FUNCTION__, port->number);
 
@@ -838,19 +870,9 @@ static void pl2303_read_int_callback (st
 		goto exit;
 	}
 
-
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+	pl2303_update_line_status(port, data, actual_length);
 
-	if (urb->actual_length < UART_STATE)
-		goto exit;
-
-	/* Save off the uart status for others to look at */
-	uart_state = data[UART_STATE];
-	spin_lock_irqsave(&priv->lock, flags);
-	uart_state |= (priv->line_status & UART_STATE_TRANSIENT_MASK);
-	priv->line_status = uart_state;
-	spin_unlock_irqrestore(&priv->lock, flags);
-		
 exit:
 	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
@@ -1022,9 +1044,8 @@ static struct pl2303_buf *pl2303_buf_all
 
 static void pl2303_buf_free(struct pl2303_buf *pb)
 {
-	if (pb != NULL) {
-		if (pb->buf_buf != NULL)
-			kfree(pb->buf_buf);
+	if (pb) {
+		kfree(pb->buf_buf);
 		kfree(pb);
 	}
 }
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -55,3 +55,6 @@
 
 #define SIEMENS_VENDOR_ID	0x11f5
 #define SIEMENS_PRODUCT_ID_X65	0x0003
+
+#define SYNTECH_VENDOR_ID	0x0745
+#define SYNTECH_PRODUCT_ID	0x0001
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -517,8 +517,7 @@ static void ti_shutdown(struct usb_seria
 		}
 	}
 
-	if (tdev)
-		kfree(tdev);
+	kfree(tdev);
 	usb_set_serial_data(serial, NULL);
 }
 
@@ -1580,7 +1579,7 @@ static int ti_command_out_sync(struct ti
 	status = usb_control_msg(tdev->td_serial->dev,
 		usb_sndctrlpipe(tdev->td_serial->dev, 0), command,
 		(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
-		value, moduleid, data, size, HZ);
+		value, moduleid, data, size, 1000);
 
 	if (status == size)
 		status = 0;
@@ -1600,7 +1599,7 @@ static int ti_command_in_sync(struct ti_
 	status = usb_control_msg(tdev->td_serial->dev,
 		usb_rcvctrlpipe(tdev->td_serial->dev, 0), command,
 		(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN),
-		value, moduleid, data, size, HZ);
+		value, moduleid, data, size, 1000);
 
 	if (status == size)
 		status = 0;
@@ -1685,7 +1684,7 @@ static int ti_download_firmware(struct t
 	dbg("%s - downloading firmware", __FUNCTION__);
 	for (pos = 0; pos < buffer_size; pos += done) {
 		len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
-		status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, HZ);
+		status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, 1000);
 		if (status)
 			break;
 	}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1297,13 +1297,6 @@ static int __init usb_serial_init(void)
 		goto exit_bus;
 	}
 
-	/* register the generic driver, if we should */
-	result = usb_serial_generic_register(debug);
-	if (result < 0) {
-		err("%s - registering generic driver failed", __FUNCTION__);
-		goto exit_generic;
-	}
-
 	usb_serial_tty_driver->owner = THIS_MODULE;
 	usb_serial_tty_driver->driver_name = "usbserial";
 	usb_serial_tty_driver->devfs_name = "usb/tts/";
@@ -1329,17 +1322,24 @@ static int __init usb_serial_init(void)
 		goto exit_tty;
 	}
 
+	/* register the generic driver, if we should */
+	result = usb_serial_generic_register(debug);
+	if (result < 0) {
+		err("%s - registering generic driver failed", __FUNCTION__);
+		goto exit_generic;
+	}
+
 	info(DRIVER_DESC " " DRIVER_VERSION);
 
 	return result;
 
+exit_generic:
+	usb_deregister(&usb_serial_driver);
+
 exit_tty:
 	tty_unregister_driver(usb_serial_tty_driver);
 
 exit_reg_driver:
-	usb_serial_generic_deregister();
-
-exit_generic:
 	bus_unregister(&usb_serial_bus_type);
 
 exit_bus:
@@ -1418,11 +1418,11 @@ void usb_serial_deregister(struct usb_se
 
 /* 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);
-EXPORT_SYMBOL(usb_serial_probe);
-EXPORT_SYMBOL(usb_serial_disconnect);
-EXPORT_SYMBOL(usb_serial_port_softint);
+EXPORT_SYMBOL_GPL(usb_serial_register);
+EXPORT_SYMBOL_GPL(usb_serial_deregister);
+EXPORT_SYMBOL_GPL(usb_serial_probe);
+EXPORT_SYMBOL_GPL(usb_serial_disconnect);
+EXPORT_SYMBOL_GPL(usb_serial_port_softint);
 
 
 /* Module information */
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -215,6 +215,8 @@ static struct usb_device_id id_table [] 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
@@ -237,12 +239,16 @@ static struct usb_device_id id_table [] 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -271,6 +277,7 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
@@ -284,9 +291,11 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
+	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
+	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
 	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -386,6 +395,7 @@ struct visor_private {
 	int bytes_in;
 	int bytes_out;
 	int outstanding_urbs;
+	int throttled;
 };
 
 /* number of outstanding urbs to prevent userspace DoS from happening */
@@ -415,6 +425,7 @@ static int visor_open (struct usb_serial
 	priv->bytes_in = 0;
 	priv->bytes_out = 0;
 	priv->outstanding_urbs = 0;
+	priv->throttled = 0;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/*
@@ -602,6 +613,7 @@ static void visor_read_bulk_callback (st
 	struct tty_struct *tty;
 	unsigned long flags;
 	int i;
+	int throttled;
 	int result;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -627,18 +639,21 @@ static void visor_read_bulk_callback (st
 	}
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->bytes_in += urb->actual_length;
+	throttled = priv->throttled;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb (port->read_urb, port->serial->dev,
-			   usb_rcvbulkpipe(port->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, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+	/* Continue trying to always read if we should */
+	if (!throttled) {
+		usb_fill_bulk_urb (port->read_urb, port->serial->dev,
+				   usb_rcvbulkpipe(port->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, GFP_ATOMIC);
+		if (result)
+			dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+	}
 	return;
 }
 
@@ -683,16 +698,26 @@ exit:
 
 static void visor_throttle (struct usb_serial_port *port)
 {
+	struct visor_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	usb_kill_urb(port->read_urb);
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->throttled = 1;
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 
 static void visor_unthrottle (struct usb_serial_port *port)
 {
+	struct visor_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	int result;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->throttled = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	port->read_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
@@ -891,7 +916,7 @@ static int clie_3_5_startup (struct usb_
 	/* get the config number */
 	result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
-				  0, 0, &data, 1, HZ * 3);
+				  0, 0, &data, 1, 3000);
 	if (result < 0) {
 		dev_err(dev, "%s: get config number failed: %d\n", __FUNCTION__, result);
 		return result;
@@ -905,7 +930,7 @@ static int clie_3_5_startup (struct usb_
 	result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				  USB_REQ_GET_INTERFACE, 
 				  USB_DIR_IN | USB_RECIP_INTERFACE,
-				  0, 0, &data, 1, HZ * 3);
+				  0, 0, &data, 1, 3000);
 	if (result < 0) {
 		dev_err(dev, "%s: get interface number failed: %d\n", __FUNCTION__, result);
 		return result;
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -30,6 +30,7 @@
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
 #define PALM_TUNGSTEN_T_ID		0x0060
+#define PALM_TREO_650			0x0061
 #define PALM_TUNGSTEN_Z_ID		0x0031
 #define PALM_ZIRE31_ID			0x0061
 #define PALM_ZIRE_ID			0x0070
@@ -49,6 +50,9 @@
 #define SAMSUNG_SCH_I330_ID		0x8001
 #define SAMSUNG_SPH_I500_ID		0x6601
 
+#define TAPWAVE_VENDOR_ID		0x12EF
+#define TAPWAVE_ZODIAC_ID		0x0100
+
 #define GARMIN_VENDOR_ID		0x091E
 #define GARMIN_IQUE_3600_ID		0x0004
 
@@ -58,6 +62,9 @@
 #define KYOCERA_VENDOR_ID		0x0C88
 #define KYOCERA_7135_ID			0x0021 
 
+#define FOSSIL_VENDOR_ID		0x0E67
+#define FOSSIL_ABACUS_ID		0x0002
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -254,6 +254,7 @@ static int firm_report_tx_done(struct us
 
 #define COMMAND_PORT		4
 #define COMMAND_TIMEOUT		(2*HZ)	/* 2 second timeout for a command */
+#define	COMMAND_TIMEOUT_MS	2000
 #define CLOSING_DELAY		(30 * HZ)
 
 
@@ -379,7 +380,7 @@ static int whiteheat_attach (struct usb_
          * unlinking bug in disguise. Same for the call below.
          */
 	usb_clear_halt(serial->dev, pipe);
-	ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT);
+	ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS);
 	if (ret) {
 		err("%s: Couldn't send command [%d]", serial->type->name, ret);
 		goto no_firmware;
@@ -391,7 +392,7 @@ static int whiteheat_attach (struct usb_
 	pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress);
 	/* See the comment on the usb_clear_halt() above */
 	usb_clear_halt(serial->dev, pipe);
-	ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT);
+	ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);
 	if (ret) {
 		err("%s: Couldn't get results [%d]", serial->type->name, ret);
 		goto no_firmware;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -3,6 +3,7 @@
 #
 
 comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information"
+	depends on USB
 
 config USB_STORAGE
 	tristate "USB Mass Storage support"
@@ -30,28 +31,6 @@ config USB_STORAGE_DEBUG
 	  Say Y here in order to have the USB Mass Storage code generate
 	  verbose debugging messages.
 
-config USB_STORAGE_RW_DETECT
-	bool "USB Mass Storage Write-Protected Media Detection (EXPERIMENTAL)"
-	depends on USB_STORAGE && EXPERIMENTAL
-	help
-	  Say Y here in order to have the USB Mass Storage code indicate to
-	  the SCSI layer that using MODE SENSE(6) and MODE SENSE(10) to
-	  determine if the media is write-protected is a good thing to do.
-
-	  Many devices have historically had trouble with these commands,
-	  hence the default 2.6.x behavior has been to suppress their use.
-	  2.4.x used these commands with (at best) mixed results, often
-	  crashing the firmware of the device.  However, the SCSI layer now
-	  issues these commands in a manner more consistent with other
-	  "popular" OSes, in an attempt to improve compatibility.
-
-	  Saying Y here allows these commands to be sent to a USB device.
-	  If you find a device this doesn't work for, switch to N and let
-	  us know at <usb-storage@lists.one-eyed-alien.net>
-
-	  If you say N here, the kernel will assume that all disk-like USB
-	  devices are write-enabled.
-
 config USB_STORAGE_DATAFAB
 	bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
 	depends on USB_STORAGE && EXPERIMENTAL
@@ -89,12 +68,26 @@ config USB_STORAGE_DPCM
 	  Say Y here to support the Microtech/ZiO! CompactFlash reader.
 	  There is a web page at <http://www.ziocorp.com/products/>.
 
-config USB_STORAGE_HP8200e
-	bool "HP CD-Writer 82xx support (EXPERIMENTAL)"
+config USB_STORAGE_USBAT
+	bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
 	depends on USB_STORAGE && EXPERIMENTAL
 	help
-	  Say Y here to include additional code to support Hewlett-Packard
-	  8200e/8210e/8230e CD-Writer Plus drives.
+	  Say Y here to include additional code to support storage devices
+	  based on the SCM/Shuttle USBAT/USBAT02 processors.
+
+	  Devices reported to work with this driver include:
+	  - CompactFlash reader included with Kodak DC3800 camera
+	  - Dane-Elec Zmate CompactFlash reader
+	  - Delkin Efilm reader2
+	  - HP 8200e/8210e/8230e CD-Writer Plus drives
+	  - I-JAM JS-50U
+	  - Jessops CompactFlash JESDCFRU BLACK
+	  - Kingston Technology PCREAD-USB/CF
+	  - Maxell UA4 CompactFlash reader
+	  - Memorex UCF-100
+	  - Microtech ZiO! ICS-45 CF2
+	  - RCA LYRA MP3 portable
+	  - Sandisk ImageMate SDDR-05b
 
 config USB_STORAGE_SDDR09
 	bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -10,7 +10,7 @@ EXTRA_CFLAGS	:= -Idrivers/scsi
 obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
 
 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_USBAT)	+= 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
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -57,9 +57,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "datafab.h"
 
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -47,6 +47,7 @@
 #include <linux/cdrom.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
 
 #include "debug.h"
 #include "scsi.h"
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -47,8 +47,6 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 
-struct scsi_cmnd;
-
 #define USB_STORAGE "usb-storage: "
 
 #ifdef CONFIG_USB_STORAGE_DEBUG
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -34,9 +34,9 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "dpcm.h"
 #include "sddr09.h"
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -34,9 +34,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "freecom.h"
 
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -39,6 +39,8 @@
 
 #include <linux/sched.h>
 #include <linux/errno.h>
+
+#include "usb.h"
 #include "initializers.h"
 #include "debug.h"
 #include "transport.h"
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -54,9 +54,9 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "scsiglue.h"
 #include "isd200.h"
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -54,9 +54,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "jumpshot.h"
 
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -47,46 +47,14 @@
 #include <linux/highmem.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
-#include "protocol.h"
+
 #include "usb.h"
+#include "protocol.h"
 #include "debug.h"
 #include "scsiglue.h"
 #include "transport.h"
 
 /***********************************************************************
- * Helper routines
- ***********************************************************************/
-
-/*
- * Fix-up the return data from a READ CAPACITY command. My Feiya reader
- * returns a value that is 1 too large.
- */
-static void fix_read_capacity(struct scsi_cmnd *srb)
-{
-	unsigned int index, offset;
-	__be32 c;
-	unsigned long capacity;
-
-	/* verify that it's a READ CAPACITY command */
-	if (srb->cmnd[0] != READ_CAPACITY)
-		return;
-
-	index = offset = 0;
-	if (usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
-			&index, &offset, FROM_XFER_BUF) != 4)
-		return;
-
-	capacity = be32_to_cpu(c);
-	US_DEBUGP("US: Fixing capacity: from %ld to %ld\n",
-	       capacity+1, capacity);
-	c = cpu_to_be32(capacity - 1);
-
-	index = offset = 0;
-	usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
-			&index, &offset, TO_XFER_BUF);
-}
-
-/***********************************************************************
  * Protocol routines
  ***********************************************************************/
 
@@ -174,12 +142,6 @@ void usb_stor_transparent_scsi_command(s
 {
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
-
-	if (srb->result == SAM_STAT_GOOD) {
-		/* Fix the READ CAPACITY result if necessary */
-		if (us->flags & US_FL_FIX_CAPACITY)
-			fix_read_capacity(srb);
-	}
 }
 
 /***********************************************************************
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -41,9 +41,6 @@
 #ifndef _PROTOCOL_H_
 #define _PROTOCOL_H_
 
-struct scsi_cmnd;
-struct us_data;
-
 /* Sub Classes */
 
 #define US_SC_RBC	0x01		/* Typically, flash devices */
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -53,10 +53,9 @@
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
 
-#include "scsiglue.h"
 #include "usb.h"
+#include "scsiglue.h"
 #include "debug.h"
 #include "transport.h"
 #include "protocol.h"
@@ -83,7 +82,7 @@ static int slave_alloc (struct scsi_devi
 
 static int slave_configure(struct scsi_device *sdev)
 {
-	struct us_data *us = (struct us_data *) sdev->host->hostdata[0];
+	struct us_data *us = host_to_us(sdev->host);
 
 	/* Scatter-gather buffers (all but the last) must have a length
 	 * divisible by the bulk maxpacket size.  Otherwise a data packet
@@ -137,18 +136,25 @@ static int slave_configure(struct scsi_d
 		 * 192 bytes (that's what Windows uses). */
 		sdev->use_192_bytes_for_3f = 1;
 
+		/* Some devices don't like MODE SENSE with page=0x3f,
+		 * which is the command used for checking if a device
+		 * is write-protected.  Now that we tell the sd driver
+		 * to do a 192-byte transfer with this command the
+		 * majority of devices work fine, but a few still can't
+		 * handle it.  The sd driver will simply assume those
+		 * devices are write-enabled. */
+		if (us->flags & US_FL_NO_WP_DETECT)
+			sdev->skip_ms_page_3f = 1;
+
 		/* A number of devices have problems with MODE SENSE for
 		 * page x08, so we will skip it. */
 		sdev->skip_ms_page_8 = 1;
 
-#ifndef CONFIG_USB_STORAGE_RW_DETECT
-		/* Some devices may not like MODE SENSE with page=0x3f.
-		 * Now that we're using 192-byte transfers this may no
-		 * longer be a problem.  So this will be a configuration
-		 * option. */
-		sdev->skip_ms_page_3f = 1;
-#endif
-
+		/* Some disks return the total number of blocks in response
+		 * to READ CAPACITY rather than the highest block number.
+		 * If this device makes that mistake, tell the sd driver. */
+		if (us->flags & US_FL_FIX_CAPACITY)
+			sdev->fix_capacity = 1;
 	} else {
 
 		/* Non-disk-type devices don't need to blacklist any pages
@@ -157,20 +163,24 @@ static int slave_configure(struct scsi_d
 		sdev->use_10_for_ms = 1;
 	}
 
+	/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
+	 * REMOVAL command, so suppress those commands. */
+	if (us->flags & US_FL_NOT_LOCKABLE)
+		sdev->lockable = 0;
+
 	/* this is to satisfy the compiler, tho I don't think the 
 	 * return code is ever checked anywhere. */
 	return 0;
 }
 
 /* queue a command */
-/* This is always called with scsi_lock(srb->host) held */
+/* This is always called with scsi_lock(host) held */
 static int queuecommand(struct scsi_cmnd *srb,
 			void (*done)(struct scsi_cmnd *))
 {
-	struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
+	struct us_data *us = host_to_us(srb->device->host);
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
-	srb->host_scribble = (unsigned char *)us;
 
 	/* check for state-transition errors */
 	if (us->srb != NULL) {
@@ -200,11 +210,10 @@ static int queuecommand(struct scsi_cmnd
  ***********************************************************************/
 
 /* Command timeout and abort */
-/* This is always called with scsi_lock(srb->host) held */
-static int command_abort(struct scsi_cmnd *srb )
+/* This is always called with scsi_lock(host) held */
+static int command_abort(struct scsi_cmnd *srb)
 {
-	struct Scsi_Host *host = srb->device->host;
-	struct us_data *us = (struct us_data *) host->hostdata[0];
+	struct us_data *us = host_to_us(srb->device->host);
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
@@ -224,13 +233,13 @@ static int command_abort(struct scsi_cmn
 		set_bit(US_FLIDX_ABORTING, &us->flags);
 		usb_stor_stop_transport(us);
 	}
-	scsi_unlock(host);
+	scsi_unlock(us_to_host(us));
 
 	/* Wait for the aborted command to finish */
 	wait_for_completion(&us->notify);
 
 	/* Reacquire the lock and allow USB transfers to resume */
-	scsi_lock(host);
+	scsi_lock(us_to_host(us));
 	clear_bit(US_FLIDX_ABORTING, &us->flags);
 	clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
 	return SUCCESS;
@@ -238,15 +247,15 @@ static int command_abort(struct scsi_cmn
 
 /* This invokes the transport reset mechanism to reset the state of the
  * device */
-/* This is always called with scsi_lock(srb->host) held */
+/* This is always called with scsi_lock(host) held */
 static int device_reset(struct scsi_cmnd *srb)
 {
-	struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
+	struct us_data *us = host_to_us(srb->device->host);
 	int result;
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	scsi_unlock(srb->device->host);
+	scsi_unlock(us_to_host(us));
 
 	/* lock the device pointers and do the reset */
 	down(&(us->dev_semaphore));
@@ -258,22 +267,22 @@ static int device_reset(struct scsi_cmnd
 	up(&(us->dev_semaphore));
 
 	/* lock the host for the return */
-	scsi_lock(srb->device->host);
+	scsi_lock(us_to_host(us));
 	return result;
 }
 
 /* This resets the device's USB port. */
 /* It refuses to work if there's more than one interface in
  * the device, so that other users are not affected. */
-/* This is always called with scsi_lock(srb->host) held */
+/* This is always called with scsi_lock(host) held */
 static int bus_reset(struct scsi_cmnd *srb)
 {
-	struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
+	struct us_data *us = host_to_us(srb->device->host);
 	int result, rc;
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	scsi_unlock(srb->device->host);
+	scsi_unlock(us_to_host(us));
 
 	/* The USB subsystem doesn't handle synchronisation between
 	 * a device's several drivers. Therefore we reset only devices
@@ -301,7 +310,7 @@ static int bus_reset(struct scsi_cmnd *s
 	up(&(us->dev_semaphore));
 
 	/* lock the host for the return */
-	scsi_lock(srb->device->host);
+	scsi_lock(us_to_host(us));
 	return result < 0 ? FAILED : SUCCESS;
 }
 
@@ -311,11 +320,12 @@ static int bus_reset(struct scsi_cmnd *s
 void usb_stor_report_device_reset(struct us_data *us)
 {
 	int i;
+	struct Scsi_Host *host = us_to_host(us);
 
-	scsi_report_device_reset(us->host, 0, 0);
+	scsi_report_device_reset(host, 0, 0);
 	if (us->flags & US_FL_SCM_MULT_TARG) {
-		for (i = 1; i < us->host->max_id; ++i)
-			scsi_report_device_reset(us->host, 0, i);
+		for (i = 1; i < host->max_id; ++i)
+			scsi_report_device_reset(host, 0, i);
 	}
 }
 
@@ -327,28 +337,41 @@ void usb_stor_report_device_reset(struct
 #undef SPRINTF
 #define SPRINTF(args...) \
 	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
-#define DO_FLAG(a) \
-	do { if (us->flags & US_FL_##a) pos += sprintf(pos, " " #a); } while(0)
 
-static int proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset,
-		int length, int inout)
+static int proc_info (struct Scsi_Host *host, char *buffer,
+		char **start, off_t offset, int length, int inout)
 {
-	struct us_data *us;
+	struct us_data *us = host_to_us(host);
 	char *pos = buffer;
+	const char *string;
 
 	/* if someone is sending us data, just throw it away */
 	if (inout)
 		return length;
 
-	us = (struct us_data*)hostptr->hostdata[0];
-
 	/* print the controller name */
-	SPRINTF("   Host scsi%d: usb-storage\n", hostptr->host_no);
+	SPRINTF("   Host scsi%d: usb-storage\n", host->host_no);
 
 	/* print product, vendor, and serial number strings */
-	SPRINTF("       Vendor: %s\n", us->vendor);
-	SPRINTF("      Product: %s\n", us->product);
-	SPRINTF("Serial Number: %s\n", us->serial);
+	if (us->pusb_dev->manufacturer)
+		string = us->pusb_dev->manufacturer;
+	else if (us->unusual_dev->vendorName)
+		string = us->unusual_dev->vendorName;
+	else
+		string = "Unknown";
+	SPRINTF("       Vendor: %s\n", string);
+	if (us->pusb_dev->product)
+		string = us->pusb_dev->product;
+	else if (us->unusual_dev->productName)
+		string = us->unusual_dev->productName;
+	else
+		string = "Unknown";
+	SPRINTF("      Product: %s\n", string);
+	if (us->pusb_dev->serial)
+		string = us->pusb_dev->serial;
+	else
+		string = "None";
+	SPRINTF("Serial Number: %s\n", string);
 
 	/* show the protocol and transport */
 	SPRINTF("     Protocol: %s\n", us->protocol_name);
@@ -358,10 +381,10 @@ static int proc_info (struct Scsi_Host *
 	if (pos < buffer + length) {
 		pos += sprintf(pos, "       Quirks:");
 
-		DO_FLAG(SINGLE_LUN);
-		DO_FLAG(SCM_MULT_TARG);
-		DO_FLAG(FIX_INQUIRY);
-		DO_FLAG(FIX_CAPACITY);
+#define US_FLAG(name, value) \
+	if (us->flags & value) pos += sprintf(pos, " " #name);
+US_DO_ALL_FLAGS
+#undef US_FLAG
 
 		*(pos++) = '\n';
 	}
@@ -467,15 +490,6 @@ struct scsi_host_template usb_stor_host_
 	.module =			THIS_MODULE
 };
 
-/* For a device that is "Not Ready" */
-unsigned char usb_stor_sense_notready[18] = {
-	[0]	= 0x70,			    /* current error */
-	[2]	= 0x02,			    /* not ready */
-	[7]	= 0x0a,			    /* additional length */
-	[12]	= 0x04,			    /* not ready */
-	[13]	= 0x03			    /* manual intervention */
-};
-
 /* To Report "Illegal Request: Invalid Field in CDB */
 unsigned char usb_stor_sense_invalidCDB[18] = {
 	[0]	= 0x70,			    /* current error */
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
--- a/drivers/usb/storage/scsiglue.h
+++ b/drivers/usb/storage/scsiglue.h
@@ -41,14 +41,8 @@
 #ifndef _SCSIGLUE_H_
 #define _SCSIGLUE_H_
 
-#include <scsi/scsi_host.h>
-
-struct us_data;
-struct scsi_cmnd;
-
 extern void usb_stor_report_device_reset(struct us_data *us);
 
-extern unsigned char usb_stor_sense_notready[18];
 extern unsigned char usb_stor_sense_invalidCDB[18];
 extern struct scsi_host_template usb_stor_host_template;
 
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -48,9 +48,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "sddr09.h"
 
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -31,9 +31,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "sddr55.h"
 
@@ -119,10 +119,8 @@ static int sddr55_status(struct us_data 
 	/* expect to get short transfer if no card fitted */
 	if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
 		/* 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);
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
 		info->lba_to_pba = NULL;
 		info->pba_to_lba = NULL;
 
@@ -649,18 +647,14 @@ static int sddr55_read_map(struct us_dat
 		return -1;
 	}
 
-	if (info->lba_to_pba)
-		kfree(info->lba_to_pba);
-	if (info->pba_to_lba)
-		kfree(info->pba_to_lba);
+	kfree(info->lba_to_pba);
+	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);
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
 		info->lba_to_pba = NULL;
 		info->pba_to_lba = NULL;
 		kfree(buffer);
@@ -728,10 +722,8 @@ static void sddr55_card_info_destructor(
 	if (!extra)
 		return;
 
-	if (info->lba_to_pba)
-		kfree(info->lba_to_pba);
-	if (info->pba_to_lba)
-		kfree(info->pba_to_lba);
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
 }
 
 
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -4,10 +4,14 @@
  *
  * Current development and maintenance by:
  *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
  *
  * Developed with the assistance of:
  *   (c) 2002 Alan Stern <stern@rowland.org>
  *
+ * Flash support based on earlier work by:
+ *   (c) 2002 Thomas Kreiling <usbdev@sm04.de>
+ *
  * Many originally ATAPI devices were slightly modified to meet the USB
  * market by using some kind of translation from ATAPI to USB on the host,
  * and the peripheral would translate from USB back to ATAPI.
@@ -21,8 +25,8 @@
  * as well. This driver is only guaranteed to work with the ATAPI
  * translation.
  *
- * The only peripheral that I know of (as of 27 Mar 2001) that uses this
- * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus.
+ * See the Kconfig help text for a list of devices known to be supported by
+ * this 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
@@ -47,9 +51,9 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
-#include "usb.h"
 #include "debug.h"
 #include "shuttle_usbat.h"
 
@@ -57,46 +61,154 @@
 #define LSB_of(s) ((s)&0xFF)
 #define MSB_of(s) ((s)>>8)
 
-int transferred = 0;
+static int transferred = 0;
+
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
 
+/*
+ * Convenience function to produce an ATAPI read/write sectors command
+ * Use cmd=0x20 for read, cmd=0x30 for write
+ */
+static void usbat_pack_atapi_sector_cmd(unsigned char *buf,
+					unsigned char thistime,
+					u32 sector, unsigned char cmd)
+{
+	buf[0] = 0;
+	buf[1] = thistime;
+	buf[2] = sector & 0xFF;
+	buf[3] = (sector >>  8) & 0xFF;
+	buf[4] = (sector >> 16) & 0xFF;
+	buf[5] = 0xE0 | ((sector >> 24) & 0x0F);
+	buf[6] = cmd;
+}
+
+/*
+ * Convenience function to get the device type (flash or hp8200)
+ */
+static int usbat_get_device_type(struct us_data *us)
+{
+	return ((struct usbat_info*)us->extra)->devicetype;
+}
+
+/*
+ * Read a register from the device
+ */
 static int usbat_read(struct us_data *us,
 		      unsigned char access,
 		      unsigned char reg,
 		      unsigned char *content)
 {
-	int result;
-
-	result = usb_stor_ctrl_transfer(us,
+	return usb_stor_ctrl_transfer(us,
 		us->recv_ctrl_pipe,
-		access,
+		access | USBAT_CMD_READ_REG,
 		0xC0,
 		(u16)reg,
 		0,
 		content,
 		1);
-
-	return result;
 }
 
+/*
+ * Write to a register on the device
+ */
 static int usbat_write(struct us_data *us,
 		       unsigned char access,
 		       unsigned char reg,
 		       unsigned char content)
 {
-	int result;
-
-	result = usb_stor_ctrl_transfer(us,
+	return usb_stor_ctrl_transfer(us,
 		us->send_ctrl_pipe,
-		access|0x01,
+		access | USBAT_CMD_WRITE_REG,
 		0x40,
 		short_pack(reg, content),
 		0,
 		NULL,
 		0);
+}
 
-	return result;
+/*
+ * Convenience function to perform a bulk read
+ */
+static int usbat_bulk_read(struct us_data *us,
+							 unsigned char *data,
+							 unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("usbat_bulk_read: len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Convenience function to perform a bulk write
+ */
+static int usbat_bulk_write(struct us_data *us,
+							unsigned char *data,
+							unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Some USBAT-specific commands can only be executed over a command transport
+ * This transport allows one (len=8) or two (len=16) vendor-specific commands
+ * to be executed.
+ */
+static int usbat_execute_command(struct us_data *us,
+								 unsigned char *commands,
+								 unsigned int len)
+{
+	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+								  USBAT_CMD_EXEC_CMD, 0x40, 0, 0,
+								  commands, len);
 }
 
+/*
+ * Read the status register
+ */
+static int usbat_get_status(struct us_data *us, unsigned char *status)
+{
+	int rc;
+	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
+
+	US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status));
+	return rc;
+}
+
+/*
+ * Check the device status
+ */
+static int usbat_check_status(struct us_data *us)
+{
+	unsigned char *reply = us->iobuf;
+	int rc;
+
+	if (!us)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_get_status(us, reply);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	if (*reply & 0x20) // device fault
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Stores critical information in internal registers in prepartion for the execution
+ * of a conditional usbat_read_blocks or usbat_write_blocks call.
+ */
 static int usbat_set_shuttle_features(struct us_data *us,
 				      unsigned char external_trigger,
 				      unsigned char epp_control,
@@ -105,76 +217,44 @@ static int usbat_set_shuttle_features(st
 				      unsigned char subcountH,
 				      unsigned char subcountL)
 {
-	int result;
 	unsigned char *command = us->iobuf;
 
 	command[0] = 0x40;
-	command[1] = 0x81;
+	command[1] = USBAT_CMD_SET_FEAT;
+
+	// The only bit relevant to ATA access is bit 6
+	// which defines 8 bit data access (set) or 16 bit (unset)
 	command[2] = epp_control;
+
+	// If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
+	// ET1 and ET2 define an external event to be checked for on event of a
+	// _read_blocks or _write_blocks operation. The read/write will not take
+	// place unless the defined trigger signal is active.
 	command[3] = external_trigger;
+
+	// The resultant byte of the mask operation (see mask_byte) is compared for
+	// equivalence with this test pattern. If equal, the read/write will take
+	// place.
 	command[4] = test_pattern;
+
+	// This value is logically ANDed with the status register field specified
+	// in the read/write command.
 	command[5] = mask_byte;
+
+	// If ALQ is set in the qualifier, this field contains the address of the
+	// registers where the byte count should be read for transferring the data.
+	// If ALQ is not set, then this field contains the number of bytes to be
+	// transferred.
 	command[6] = subcountL;
 	command[7] = subcountH;
 
-	result = usb_stor_ctrl_transfer(us,
-		us->send_ctrl_pipe,
-		0x80,
-		0x40,
-		0,
-		0,
-		command,
-		8);
-
-	return result;
-}
-
-static int usbat_read_block(struct us_data *us,
-			    unsigned char access,
-			    unsigned char reg,
-			    unsigned char *content,
-			    unsigned short len,
-			    int use_sg)
-{
-	int result;
-	unsigned char *command = us->iobuf;
-
-	if (!len)
-		return USB_STOR_TRANSPORT_GOOD;
-
-	command[0] = 0xC0;
-	command[1] = access | 0x02;
-	command[2] = reg;
-	command[3] = 0;
-	command[4] = 0;
-	command[5] = 0;
-	command[6] = LSB_of(len);
-	command[7] = MSB_of(len);
-
-	result = usb_stor_ctrl_transfer(us,
-		us->send_ctrl_pipe,
-		0x80,
-		0x40,
-		0,
-		0,
-		command,
-		8);
-
-	if (result != USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
-
-	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
-			content, len, use_sg, NULL);
-
-	return (result == USB_STOR_XFER_GOOD ?
-			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+	return usbat_execute_command(us, command, 8);
 }
 
 /*
  * Block, waiting for an ATA device to become not busy or to report
  * an error condition.
  */
-
 static int usbat_wait_not_busy(struct us_data *us, int minutes)
 {
 	int i;
@@ -189,7 +269,7 @@ static int usbat_wait_not_busy(struct us
 
 	for (i=0; i<1200+minutes*60; i++) {
 
- 		result = usbat_read(us, USBAT_ATA, 0x17, status);
+ 		result = usbat_get_status(us, status);
 
 		if (result!=USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
@@ -220,12 +300,45 @@ static int usbat_wait_not_busy(struct us
 	return USB_STOR_TRANSPORT_FAILED;
 }
 
+/*
+ * Read block data from the data register
+ */
+static int usbat_read_block(struct us_data *us,
+			    unsigned char *content,
+			    unsigned short len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usbat_bulk_read(us, content, len);
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+/*
+ * Write block data via the data register
+ */
 static int usbat_write_block(struct us_data *us,
-			     unsigned char access, 
-			     unsigned char reg,
+			     unsigned char access,
 			     unsigned char *content,
 			     unsigned short len,
-			     int use_sg, int minutes)
+			     int minutes)
 {
 	int result;
 	unsigned char *command = us->iobuf;
@@ -234,57 +347,48 @@ static int usbat_write_block(struct us_d
 		return USB_STOR_TRANSPORT_GOOD;
 
 	command[0] = 0x40;
-	command[1] = access | 0x03;
-	command[2] = reg;
+	command[1] = access | USBAT_CMD_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
 	command[3] = 0;
 	command[4] = 0;
 	command[5] = 0;
 	command[6] = LSB_of(len);
 	command[7] = MSB_of(len);
 
-	result = usb_stor_ctrl_transfer(us,
-		us->send_ctrl_pipe,
-		0x80,
-		0x40,
-		0,
-		0,
-		command,
-		8);
+	result = usbat_execute_command(us, command, 8);
 
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
-			content, len, use_sg, NULL);
-
+	result = usbat_bulk_write(us, content, len);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
 	return usbat_wait_not_busy(us, minutes);
 }
 
-static int usbat_rw_block_test(struct us_data *us,
-			       unsigned char access,
-			       unsigned char *registers,
-			       unsigned char *data_out,
-			       unsigned short num_registers,
-			       unsigned char data_reg,
-			       unsigned char status_reg,
-			       unsigned char timeout,
-			       unsigned char qualifier,
-			       int direction,
-			       unsigned char *content,
-			       unsigned short len,
-			       int use_sg,
-			       int minutes)
+/*
+ * Process read and write requests
+ */
+static int usbat_hp8200e_rw_block_test(struct us_data *us,
+				       unsigned char access,
+				       unsigned char *registers,
+				       unsigned char *data_out,
+				       unsigned short num_registers,
+				       unsigned char data_reg,
+				       unsigned char status_reg,
+				       unsigned char timeout,
+				       unsigned char qualifier,
+				       int direction,
+				       unsigned char *content,
+				       unsigned short len,
+				       int use_sg,
+				       int minutes)
 {
 	int result;
 	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
 			us->recv_bulk_pipe : us->send_bulk_pipe;
 
-	// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
-	// but that's what came out of the trace every single time.
-
 	unsigned char *command = us->iobuf;
 	int i, j;
 	int cmdlen;
@@ -308,8 +412,11 @@ static int usbat_rw_block_test(struct us
 
 		if (i==0) {
 			cmdlen = 16;
+			// Write to multiple registers
+			// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
+			// but that's what came out of the trace every single time.
 			command[0] = 0x40;
-			command[1] = access | 0x07;
+			command[1] = access | USBAT_CMD_WRITE_REGS;
 			command[2] = 0x07;
 			command[3] = 0x17;
 			command[4] = 0xFC;
@@ -319,9 +426,11 @@ static int usbat_rw_block_test(struct us
 		} else
 			cmdlen = 8;
 
+		// Conditionally read or write blocks
 		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
 		command[cmdlen-7] = access |
-				(direction==DMA_TO_DEVICE ? 0x05 : 0x04);
+				(direction==DMA_TO_DEVICE ?
+				 USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK);
 		command[cmdlen-6] = data_reg;
 		command[cmdlen-5] = status_reg;
 		command[cmdlen-4] = timeout;
@@ -329,14 +438,7 @@ static int usbat_rw_block_test(struct us
 		command[cmdlen-2] = LSB_of(len);
 		command[cmdlen-1] = MSB_of(len);
 
-		result = usb_stor_ctrl_transfer(us,
-			us->send_ctrl_pipe,
-			0x80,
-			0x40,
-			0,
-			0,
-			command,
-			cmdlen);
+		result = usbat_execute_command(us, command, cmdlen);
 
 		if (result != USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
@@ -348,10 +450,7 @@ static int usbat_rw_block_test(struct us
 				data[1+(j<<1)] = data_out[j];
 			}
 
-			result = usb_stor_bulk_transfer_buf(us,
-					us->send_bulk_pipe,
-					data, num_registers*2, NULL);
-
+			result = usbat_bulk_write(us, data, num_registers*2);
 			if (result != USB_STOR_XFER_GOOD)
 				return USB_STOR_TRANSPORT_ERROR;
 
@@ -403,7 +502,8 @@ static int usbat_rw_block_test(struct us
 			 */
 
  			result = usbat_read(us, USBAT_ATA, 
-				direction==DMA_TO_DEVICE ? 0x17 : 0x0E, 
+				direction==DMA_TO_DEVICE ?
+					USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS,
 				status);
 
 			if (result!=USB_STOR_XFER_GOOD)
@@ -430,101 +530,602 @@ static int usbat_rw_block_test(struct us
 }
 
 /*
- * Write data to multiple registers at once. Not meant for large
- * transfers of data!
+ * Write to multiple registers:
+ * Allows us to write specific data to any registers. The data to be written
+ * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN
+ * which gets sent through bulk out.
+ * Not designed for large transfers of data!
  */
-
 static int usbat_multiple_write(struct us_data *us,
-				unsigned char access,
 				unsigned char *registers,
 				unsigned char *data_out,
 				unsigned short num_registers)
 {
-	int result;
+	int i, result;
 	unsigned char *data = us->iobuf;
-	int i;
 	unsigned char *command = us->iobuf;
 
 	BUG_ON(num_registers > US_IOBUF_SIZE/2);
 
+	// Write to multiple registers, ATA access
 	command[0] = 0x40;
-	command[1] = access | 0x07;
+	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
+
+	// No relevance
 	command[2] = 0;
 	command[3] = 0;
 	command[4] = 0;
 	command[5] = 0;
+
+	// Number of bytes to be transferred (incl. addresses and data)
 	command[6] = LSB_of(num_registers*2);
 	command[7] = MSB_of(num_registers*2);
 
-	result = usb_stor_ctrl_transfer(us,
-		us->send_ctrl_pipe,
-		0x80,
-		0x40,
-		0,
-		0,
-		command,
-		8);
-
+	// The setup command
+	result = usbat_execute_command(us, command, 8);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
+	// Create the reg/data, reg/data sequence
 	for (i=0; i<num_registers; i++) {
 		data[i<<1] = registers[i];
 		data[1+(i<<1)] = data_out[i];
 	}
 
-	result = usb_stor_bulk_transfer_buf(us,
-		us->send_bulk_pipe, data, num_registers*2, NULL);
-
+	// Send the data
+	result = usbat_bulk_write(us, data, num_registers*2);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	return usbat_wait_not_busy(us, 0);
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+		return usbat_wait_not_busy(us, 0);
+	else
+		return USB_STOR_TRANSPORT_GOOD;
 }
 
+/*
+ * Conditionally read blocks from device:
+ * Allows us to read blocks from a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the read will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_read_blocks(struct us_data *us,
+							 unsigned char *buffer,
+							 int len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; // Timeout (ms);
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	// Multiple block read setup command
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	// Read the blocks we just asked for
+	result = usbat_bulk_read(us, buffer, len);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally write blocks to device:
+ * Allows us to write blocks to a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the write will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_write_blocks(struct us_data *us,
+							  unsigned char *buffer,
+							  int len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0x40;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; // Timeout (ms)
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	// Multiple block write setup command
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	// Write the data
+	result = usbat_bulk_write(us, buffer, len);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read the User IO register
+ */
 static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
 {
 	int result;
 
 	result = usb_stor_ctrl_transfer(us,
 		us->recv_ctrl_pipe,
-		0x82,
+		USBAT_CMD_UIO,
 		0xC0,
 		0,
 		0,
 		data_flags,
-		1);
+		USBAT_UIO_READ);
+
+	US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags));
 
 	return result;
 }
 
+/*
+ * Write to the User IO register
+ */
 static int usbat_write_user_io(struct us_data *us,
 			       unsigned char enable_flags,
 			       unsigned char data_flags)
 {
-	int result;
-
-	result = usb_stor_ctrl_transfer(us,
+	return usb_stor_ctrl_transfer(us,
 		us->send_ctrl_pipe,
-		0x82,
+		USBAT_CMD_UIO,
 		0x40,
 		short_pack(enable_flags, data_flags),
 		0,
 		NULL,
-		0);
+		USBAT_UIO_WRITE);
+}
+
+/*
+ * Reset the device
+ * Often needed on media change.
+ */
+static int usbat_device_reset(struct us_data *us)
+{
+	int rc;
+
+	// Reset peripheral, enable peripheral control signals
+	// (bring reset signal up)
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+			
+	// Enable peripheral control signals
+	// (bring reset signal down)
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Enable card detect
+ */
+static int usbat_device_enable_cdt(struct us_data *us)
+{
+	int rc;
 
+	// Enable peripheral control signals and card detect
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine if media is present.
+ */
+static int usbat_flash_check_media_present(unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_UI0) {
+		US_DEBUGP("usbat_flash_check_media_present: no media detected\n");
+		return USBAT_FLASH_MEDIA_NONE;
+	}
+
+	return USBAT_FLASH_MEDIA_CF;
+}
+
+/*
+ * Determine if media has changed since last operation
+ */
+static int usbat_flash_check_media_changed(unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_0) {
+		US_DEBUGP("usbat_flash_check_media_changed: media change detected\n");
+		return USBAT_FLASH_MEDIA_CHANGED;
+	}
+
+	return USBAT_FLASH_MEDIA_SAME;
+}
+
+/*
+ * Check for media change / no media and handle the situation appropriately
+ */
+static int usbat_flash_check_media(struct us_data *us,
+				   struct usbat_info *info)
+{
+	int rc;
+	unsigned char *uio = us->iobuf;
+
+	rc = usbat_read_user_io(us, uio);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// Check for media existence
+	rc = usbat_flash_check_media_present(uio);
+	if (rc == USBAT_FLASH_MEDIA_NONE) {
+		info->sense_key = 0x02;
+		info->sense_asc = 0x3A;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	// Check for media change
+	rc = usbat_flash_check_media_changed(uio);
+	if (rc == USBAT_FLASH_MEDIA_CHANGED) {
+
+		// Reset and re-enable card detect
+		rc = usbat_device_reset(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+		rc = usbat_device_enable_cdt(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		msleep(50);
+
+		rc = usbat_read_user_io(us, uio);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		
+		info->sense_key = UNIT_ATTENTION;
+		info->sense_asc = 0x28;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine whether we are controlling a flash-based reader/writer,
+ * or a HP8200-based CD drive.
+ * Sets transport functions as appropriate.
+ */
+static int usbat_identify_device(struct us_data *us,
+				 struct usbat_info *info)
+{
+	int rc;
+	unsigned char status;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_device_reset(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	/*
+	 * By examining the device signature after a reset, we can identify
+	 * whether the device supports the ATAPI packet interface.
+	 * The flash-devices do not support this, whereas the HP CDRW's obviously
+	 * do.
+	 *
+	 * This method is not ideal, but works because no other devices have been
+	 * produced based on the USBAT/USBAT02.
+	 *
+	 * Section 9.1 of the ATAPI-4 spec states (amongst other things) that
+	 * after a device reset, a Cylinder low of 0x14 indicates that the device
+	 * does support packet commands.
+	 */
+	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, &status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("usbat_identify_device: Cylinder low is %02X\n", status);
+
+	if (status == 0x14) {
+		// Device is HP 8200
+		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
+		info->devicetype = USBAT_DEV_HP8200;
+	} else {
+		// Device is a CompactFlash reader/writer
+		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+		info->devicetype = USBAT_DEV_FLASH;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Set the transport function based on the device type
+ */
+static int usbat_set_transport(struct us_data *us,
+			       struct usbat_info *info)
+{
+	int rc;
+
+	if (!info->devicetype) {
+		rc = usbat_identify_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD) {
+			US_DEBUGP("usbat_set_transport: Could not identify device\n");
+			return 1;
+		}
+	}
+
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+		us->transport = usbat_hp8200e_transport;
+	else if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+		us->transport = usbat_flash_transport;
+
+	return 0;
+}
+
+/*
+ * Read the media capacity
+ */
+static int usbat_flash_get_sector_count(struct us_data *us,
+					struct usbat_info *info)
+{
+	unsigned char registers[3] = {
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_CMD,
+	};
+	unsigned char  command[3] = { 0x01, 0xA0, 0xEC };
+	unsigned char *reply;
+	unsigned char status;
+	int rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// ATAPI command : IDENTIFY DEVICE
+	rc = usbat_multiple_write(us, registers, command, 3);
+	if (rc != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// Read device status
+	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	msleep(100);
+
+	// Read the device identification data
+	rc = usbat_read_block(us, reply, 512);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		goto leave;
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+		((u32)(reply[116]) << 16) |
+		((u32)(reply[115]) <<  8) |
+		((u32)(reply[114])      );
+
+	rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+/*
+ * Read data from device
+ */
+static int usbat_flash_read_data(struct us_data *us,
+								 struct usbat_info *info,
+								 u32 sector,
+								 u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	// we're working in LBA mode.  according to the ATA spec,
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+ 
+		// ATAPI command 0x20 (READ SECTORS)
+		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20);
+
+		// Write/execute ATAPI read command
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		// Read the data we just requested
+		result = usbat_read_blocks(us, buffer, len);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+  	 
+		US_DEBUGP("usbat_flash_read_data:  %d bytes\n", len);
+	
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg_idx, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Write data to device
+ */
+static int usbat_flash_write_data(struct us_data *us,
+								  struct usbat_info *info,
+								  u32 sector,
+								  u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	// we're working in LBA mode.  according to the ATA spec,
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg_idx, &sg_offset, FROM_XFER_BUF);
+
+		// ATAPI command 0x30 (WRITE SECTORS)
+		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30);		
+
+		// Write/execute ATAPI write command
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		// Write the data
+		result = usbat_write_blocks(us, buffer, len);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
 	return result;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
 }
 
 /*
  * Squeeze a potentially huge (> 65535 byte) read10 command into
  * a little ( <= 65535 byte) ATAPI pipe
  */
-
-static int usbat_handle_read10(struct us_data *us,
-			       unsigned char *registers,
-			       unsigned char *data,
-			       struct scsi_cmnd *srb)
+static int usbat_hp8200e_handle_read10(struct us_data *us,
+				       unsigned char *registers,
+				       unsigned char *data,
+				       struct scsi_cmnd *srb)
 {
 	int result = USB_STOR_TRANSPORT_GOOD;
 	unsigned char *buffer;
@@ -538,9 +1139,10 @@ static int usbat_handle_read10(struct us
 
 	if (srb->request_bufflen < 0x10000) {
 
-		result = usbat_rw_block_test(us, USBAT_ATA, 
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
-			0x10, 0x17, 0xFD, 0x30,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
 			DMA_FROM_DEVICE,
 			srb->request_buffer, 
 			srb->request_bufflen, srb->use_sg, 1);
@@ -607,9 +1209,10 @@ static int usbat_handle_read10(struct us
 		data[7+7] = MSB_of(len / srb->transfersize); // SCSI command
 		data[7+8] = LSB_of(len / srb->transfersize); // num sectors
 
-		result = usbat_rw_block_test(us, USBAT_ATA, 
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
-			0x10, 0x17, 0xFD, 0x30,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
 			DMA_FROM_DEVICE,
 			buffer,
 			len, 0, 1);
@@ -632,48 +1235,52 @@ static int usbat_handle_read10(struct us
 	return result;
 }
 
-static int hp_8200e_select_and_test_registers(struct us_data *us)
+static int usbat_select_and_test_registers(struct us_data *us)
 {
 	int selector;
 	unsigned char *status = us->iobuf;
+	unsigned char max_selector = 0xB0;
+	if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+		max_selector = 0xA0;
 
 	// try device = master, then device = slave.
 
-	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
+	for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
 
-		if (usbat_write(us, USBAT_ATA, 0x16, selector) != 
+		if (usbat_get_device_type(us) == USBAT_DEV_HP8200 &&
+			usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x17, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x16, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x14, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x15, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_write(us, USBAT_ATA, 0x14, 0x55) != 
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) != 
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x14, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
-		if (usbat_read(us, USBAT_ATA, 0x15, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -681,125 +1288,131 @@ static int hp_8200e_select_and_test_regi
 	return USB_STOR_TRANSPORT_GOOD;
 }
 
-int init_8200e(struct us_data *us)
+/*
+ * Initialize the USBAT processor and the storage device
+ */
+int init_usbat(struct us_data *us)
 {
-	int result;
+	int rc;
+	struct usbat_info *info;
+	unsigned char subcountH = USBAT_ATA_LBA_HI;
+	unsigned char subcountL = USBAT_ATA_LBA_ME;
 	unsigned char *status = us->iobuf;
 
-	// Enable peripheral control signals
+	us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
+	if (!us->extra) {
+		US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+		return 1;
+	}
+	memset(us->extra, 0, sizeof(struct usbat_info));
+	info = (struct usbat_info *) (us->extra);
 
-	if (usbat_write_user_io(us,
-	  USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+	// Enable peripheral control signals
+	rc = usbat_write_user_io(us,
+				 USBAT_UIO_OE1 | USBAT_UIO_OE0,
+				 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 1\n");
 
 	msleep(2000);
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
 
 	US_DEBUGP("INIT 2\n");
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 3\n");
-
-	// Reset peripheral, enable periph control signals
-	// (bring reset signal up)
-
-	if (usbat_write_user_io(us,
-	  USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 4\n");
-
-	// Enable periph control signals
-	// (bring reset signal down)
+	US_DEBUGP("INIT 3\n");
 
-	if (usbat_write_user_io(us,
-	  USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+	// At this point, we need to detect which device we are using
+	if (usbat_set_transport(us, info))
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 5\n");
+	US_DEBUGP("INIT 4\n");
 
-	msleep(250);
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
+		msleep(250);
 
-	// Write 0x80 to ISA port 0x3F
+		// Write 0x80 to ISA port 0x3F
+		rc = usbat_write(us, USBAT_ISA, 0x3F, 0x80);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 
-	if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+		US_DEBUGP("INIT 5\n");
 
-	US_DEBUGP("INIT 6\n");
+		// Read ISA port 0x27
+		rc = usbat_read(us, USBAT_ISA, 0x27, status);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 
-	// Read ISA port 0x27
+		US_DEBUGP("INIT 6\n");
 
-	if (usbat_read(us, USBAT_ISA, 0x27, status) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+		rc = usbat_read_user_io(us, status);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 7\n");
+		US_DEBUGP("INIT 7\n");
+	}
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
 
 	US_DEBUGP("INIT 8\n");
 
-	if ( (result = hp_8200e_select_and_test_registers(us)) !=
-			 USB_STOR_TRANSPORT_GOOD)
-		return result;
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 9\n");
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+	// Enable peripheral control signals and card detect
+	rc = usbat_device_enable_cdt(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
 
 	US_DEBUGP("INIT 10\n");
 
-	// Enable periph control signals and card detect
-
-	if (usbat_write_user_io(us,
-	  USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 11\n");
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
-
-	US_DEBUGP("INIT 12\n");
-
 	msleep(1400);
 
-	if (usbat_read_user_io(us, status) !=
-			USB_STOR_XFER_GOOD)
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 13\n");
+	US_DEBUGP("INIT 12\n");
 
-	if ( (result = hp_8200e_select_and_test_registers(us)) !=
-			 USB_STOR_TRANSPORT_GOOD)
-		return result;
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
 
-	US_DEBUGP("INIT 14\n");
+	US_DEBUGP("INIT 13\n");
 
-	if (usbat_set_shuttle_features(us, 
-			0x83, 0x00, 0x88, 0x08, 0x15, 0x14) !=
-			 USB_STOR_XFER_GOOD)
+	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 
+		subcountH = 0x02;
+		subcountL = 0x00;
+	}
+	rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1),
+									0x00, 0x88, 0x08, subcountH, subcountL);
+	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 15\n");
+	US_DEBUGP("INIT 14\n");
 
 	return USB_STOR_TRANSPORT_GOOD;
 }
@@ -807,7 +1420,7 @@ int init_8200e(struct us_data *us)
 /*
  * Transport for the HP 8200e
  */
-int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
 	int result;
 	unsigned char *status = us->iobuf;
@@ -824,13 +1437,13 @@ int hp8200e_transport(struct scsi_cmnd *
 	   commands... just ATA Packet Commands.
  	 */
 
-	registers[0] = 0x11;
-	registers[1] = 0x12;
-	registers[2] = 0x13;
-	registers[3] = 0x14;
-	registers[4] = 0x15;
-	registers[5] = 0x16;
-	registers[6] = 0x17;
+	registers[0] = USBAT_ATA_FEATURES;
+	registers[1] = USBAT_ATA_SECCNT;
+	registers[2] = USBAT_ATA_SECNUM;
+	registers[3] = USBAT_ATA_LBA_ME;
+	registers[4] = USBAT_ATA_LBA_HI;
+	registers[5] = USBAT_ATA_DEVICE;
+	registers[6] = USBAT_ATA_CMD;
 	data[0] = 0x00;
 	data[1] = 0x00;
 	data[2] = 0x00;
@@ -844,7 +1457,7 @@ int hp8200e_transport(struct scsi_cmnd *
 		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
 	}
 
-	result = usbat_read(us, USBAT_ATA, 0x17, status);
+	result = usbat_get_status(us, status);
 	US_DEBUGP("Status = %02X\n", *status);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
@@ -853,9 +1466,10 @@ int hp8200e_transport(struct scsi_cmnd *
 
 	if (srb->sc_data_direction == DMA_TO_DEVICE) {
 
-		result = usbat_rw_block_test(us, USBAT_ATA, 
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
-			0x10, 0x17, 0xFD, 0x30,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
 			DMA_TO_DEVICE,
 			srb->request_buffer, 
 			len, srb->use_sg, 10);
@@ -870,7 +1484,7 @@ int hp8200e_transport(struct scsi_cmnd *
 	} else if (srb->cmnd[0] == READ_10 ||
 		   srb->cmnd[0] == GPCMD_READ_CD) {
 
-		return usbat_handle_read10(us, registers, data, srb);
+		return usbat_hp8200e_handle_read10(us, registers, data, srb);
 
 	}
 
@@ -881,7 +1495,6 @@ int hp8200e_transport(struct scsi_cmnd *
 	}
 
 	if ( (result = usbat_multiple_write(us, 
-			USBAT_ATA,
 			registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
 		return result;
 	}
@@ -895,7 +1508,7 @@ int hp8200e_transport(struct scsi_cmnd *
 	// AT SPEED 4 IS UNRELIABLE!!!
 
 	if ( (result = usbat_write_block(us, 
-			USBAT_ATA, 0x10, srb->cmnd, 12, 0,
+			USBAT_ATA, srb->cmnd, 12,
 			srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
 				USB_STOR_TRANSPORT_GOOD) {
 		return result;
@@ -908,14 +1521,14 @@ int hp8200e_transport(struct scsi_cmnd *
 
 		// How many bytes to read in? Check cylL register
 
-		if (usbat_read(us, USBAT_ATA, 0x14, status) != 
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
 		    	USB_STOR_XFER_GOOD) {
 			return USB_STOR_TRANSPORT_ERROR;
 		}
 
 		if (len > 0xFF) { // need to read cylH also
 			len = *status;
-			if (usbat_read(us, USBAT_ATA, 0x15, status) !=
+			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
 				    USB_STOR_XFER_GOOD) {
 				return USB_STOR_TRANSPORT_ERROR;
 			}
@@ -925,8 +1538,7 @@ int hp8200e_transport(struct scsi_cmnd *
 			len = *status;
 
 
-		result = usbat_read_block(us, USBAT_ATA, 0x10, 
-			srb->request_buffer, len, srb->use_sg);
+		result = usbat_read_block(us, srb->request_buffer, len);
 
 		/* Debug-print the first 32 bytes of the transfer */
 
@@ -948,4 +1560,153 @@ int hp8200e_transport(struct scsi_cmnd *
 	return result;
 }
 
+/*
+ * Transport for USBAT02-based CompactFlash and similar storage devices
+ */
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+	int rc;
+	struct usbat_info *info = (struct usbat_info *) (us->extra);
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = usbat_flash_get_sector_count(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		// note: must return the sector number of the last sector,
+		// *not* the total number of sectors
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("usbat_flash_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+				((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("usbat_flash_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// I don't think we'll ever see a READ_12 but support it anyway...
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n");
+
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		return usbat_check_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from popping
+		// the media out of the device (no locking doors, etc)
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n",
+			  srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Default transport function. Attempts to detect which transport function
+ * should be called, makes it the new default, and calls it.
+ *
+ * This function should never be called. Our usbat_init() function detects the
+ * device type and changes the us->transport ptr to the transport function
+ * relevant to the device.
+ * However, we'll support this impossible(?) case anyway.
+ */
+int usbat_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct usbat_info *info = (struct usbat_info*) (us->extra);
+
+	if (usbat_set_transport(us, info))
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return us->transport(srb, us);	
+}
 
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
--- a/drivers/usb/storage/shuttle_usbat.h
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -5,8 +5,9 @@
  *
  * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
  *
- * See scm.c for more explanation
+ * See shuttle_usbat.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
@@ -26,13 +27,59 @@
 #ifndef _USB_SHUTTLE_USBAT_H
 #define _USB_SHUTTLE_USBAT_H
 
+/* Supported device types */
+#define USBAT_DEV_HP8200	0x01
+#define USBAT_DEV_FLASH		0x02
+
 #define USBAT_EPP_PORT		0x10
 #define USBAT_EPP_REGISTER	0x30
 #define USBAT_ATA		0x40
 #define USBAT_ISA		0x50
 
-/* SCM User I/O Data registers */
+/* Commands (need to be logically OR'd with an access type */
+#define USBAT_CMD_READ_REG		0x00
+#define USBAT_CMD_WRITE_REG		0x01
+#define USBAT_CMD_READ_BLOCK	0x02
+#define USBAT_CMD_WRITE_BLOCK	0x03
+#define USBAT_CMD_COND_READ_BLOCK	0x04
+#define USBAT_CMD_COND_WRITE_BLOCK	0x05
+#define USBAT_CMD_WRITE_REGS	0x07
+
+/* Commands (these don't need an access type) */
+#define USBAT_CMD_EXEC_CMD	0x80
+#define USBAT_CMD_SET_FEAT	0x81
+#define USBAT_CMD_UIO		0x82
+
+/* Methods of accessing UIO register */
+#define USBAT_UIO_READ	1
+#define USBAT_UIO_WRITE	0
+
+/* Qualifier bits */
+#define USBAT_QUAL_FCQ	0x20 // full compare
+#define USBAT_QUAL_ALQ	0x10 // auto load subcount
+
+/* USBAT Flash Media status types */
+#define USBAT_FLASH_MEDIA_NONE	0
+#define USBAT_FLASH_MEDIA_CF	1
+
+/* USBAT Flash Media change types */
+#define USBAT_FLASH_MEDIA_SAME	0
+#define USBAT_FLASH_MEDIA_CHANGED	1
+
+/* USBAT ATA registers */
+#define USBAT_ATA_DATA      0x10  // read/write data (R/W)
+#define USBAT_ATA_FEATURES  0x11  // set features (W)
+#define USBAT_ATA_ERROR     0x11  // error (R)
+#define USBAT_ATA_SECCNT    0x12  // sector count (R/W)
+#define USBAT_ATA_SECNUM    0x13  // sector number (R/W)
+#define USBAT_ATA_LBA_ME    0x14  // cylinder low (R/W)
+#define USBAT_ATA_LBA_HI    0x15  // cylinder high (R/W)
+#define USBAT_ATA_DEVICE    0x16  // head/device selection (R/W)
+#define USBAT_ATA_STATUS    0x17  // device status (R)
+#define USBAT_ATA_CMD       0x17  // device command (W)
+#define USBAT_ATA_ALTSTATUS 0x0E  // status (no clear IRQ) (R)
 
+/* USBAT User I/O Data registers */
 #define USBAT_UIO_EPAD		0x80 // Enable Peripheral Control Signals
 #define USBAT_UIO_CDT		0x40 // Card Detect (Read Only)
 				     // CDT = ACKD & !UI1 & !UI0
@@ -43,8 +90,7 @@
 #define USBAT_UIO_UI0		0x02 // Input 0
 #define USBAT_UIO_INTR_ACK	0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
 
-/* SCM User I/O Enable registers */
-
+/* USBAT User I/O Enable registers */
 #define USBAT_UIO_DRVRST	0x80 // Reset Peripheral
 #define USBAT_UIO_ACKD		0x40 // Enable Card Detect
 #define USBAT_UIO_OE1		0x20 // I/O 1 set=output/clr=input
@@ -52,8 +98,26 @@
 #define USBAT_UIO_OE0		0x10 // I/O 0 set=output/clr=input
 #define USBAT_UIO_ADPRST	0x01 // Reset SCM chip
 
-/* HP 8200e stuff */
-extern int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int init_8200e(struct us_data *us);
+/* USBAT Features */
+#define USBAT_FEAT_ETEN	0x80 // External trigger enable
+#define USBAT_FEAT_U1	0x08
+#define USBAT_FEAT_U0	0x04
+#define USBAT_FEAT_ET1	0x02
+#define USBAT_FEAT_ET2	0x01
+
+extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int init_usbat(struct us_data *us);
+
+struct usbat_info {
+	int devicetype;
+
+	/* Used for Flash readers only */
+	unsigned long sectors;     // total sector count
+	unsigned long ssize;       // sector size in bytes
+
+	unsigned char sense_key;
+	unsigned long sense_asc;   // additional sense code
+	unsigned long sense_ascq;  // additional sense code qualifier
+};
 
 #endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -54,10 +54,10 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 
+#include "usb.h"
 #include "transport.h"
 #include "protocol.h"
 #include "scsiglue.h"
-#include "usb.h"
 #include "debug.h"
 
 
@@ -383,7 +383,8 @@ int usb_stor_ctrl_transfer(struct us_dat
  * This routine always uses us->recv_intr_pipe as the pipe and
  * us->ep_bInterval as the interrupt interval.
  */
-int usb_stor_intr_transfer(struct us_data *us, void *buf, unsigned int length)
+static int usb_stor_intr_transfer(struct us_data *us, void *buf,
+				  unsigned int length)
 {
 	int result;
 	unsigned int pipe = us->recv_intr_pipe;
@@ -436,7 +437,7 @@ int usb_stor_bulk_transfer_buf(struct us
  * This function does basically the same thing as usb_stor_bulk_transfer_buf()
  * above, but it uses the usbcore scatter-gather library.
  */
-int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
 		struct scatterlist *sg, int num_sg, unsigned int length,
 		unsigned int *act_len)
 {
@@ -991,11 +992,11 @@ int usb_stor_Bulk_transport(struct scsi_
 	/* DATA STAGE */
 	/* send/receive data payload, if there is any */
 
-	/* Genesys Logic interface chips need a 100us delay between the
+	/* Some USB-IDE converter chips need a 100us delay between the
 	 * command phase and the data phase.  Some devices need a little
 	 * more than that, probably because of clock rate inaccuracies. */
-	if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS)
-		udelay(110);
+	if (unlikely(us->flags & US_FL_GO_SLOW))
+		udelay(125);
 
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
@@ -1055,19 +1056,31 @@ int usb_stor_Bulk_transport(struct scsi_
 	US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
 			le32_to_cpu(bcs->Signature), bcs->Tag, 
 			residue, bcs->Status);
-	if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) &&
-		    bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) ||
-			bcs->Tag != srb->serial_number || 
-			bcs->Status > US_BULK_STAT_PHASE) {
+	if (bcs->Tag != srb->serial_number || bcs->Status > US_BULK_STAT_PHASE) {
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
+	/* Some broken devices report odd signatures, so we do not check them
+	 * for validity against the spec. We store the first one we see,
+	 * and check subsequent transfers for validity against this signature.
+	 */
+	if (!us->bcs_signature) {
+		us->bcs_signature = bcs->Signature;
+		if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
+			US_DEBUGP("Learnt BCS signature 0x%08X\n",
+					le32_to_cpu(us->bcs_signature));
+	} else if (bcs->Signature != us->bcs_signature) {
+		US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
+			  le32_to_cpu(bcs->Signature),
+			  le32_to_cpu(us->bcs_signature));
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
 	/* try to compute the actual residue, based on how much data
 	 * was really transferred and what the device tells us */
 	if (residue) {
-		if (!(us->flags & US_FL_IGNORE_RESIDUE) ||
-				srb->sc_data_direction == DMA_TO_DEVICE) {
+		if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
 			residue = min(residue, transfer_length);
 			srb->resid = max(srb->resid, (int) residue);
 		}
@@ -1126,11 +1139,11 @@ static int usb_stor_reset_common(struct 
 	 * RESETTING bit, and clear the ABORTING bit so that the reset
 	 * may proceed.
 	 */
-	scsi_lock(us->host);
+	scsi_lock(us_to_host(us));
 	usb_stor_report_device_reset(us);
 	set_bit(US_FLIDX_RESETTING, &us->flags);
 	clear_bit(US_FLIDX_ABORTING, &us->flags);
-	scsi_unlock(us->host);
+	scsi_unlock(us_to_host(us));
 
 	/* A 20-second timeout may seem rather long, but a LaCie
 	 * StudioDrive USB2 device takes 16+ seconds to get going
@@ -1146,7 +1159,7 @@ static int usb_stor_reset_common(struct 
 
  	/* Give the device some time to recover from the reset,
  	 * but don't delay disconnect processing. */
- 	wait_event_interruptible_timeout(us->dev_reset_wait,
+ 	wait_event_interruptible_timeout(us->delay_wait,
  			test_bit(US_FLIDX_DISCONNECTING, &us->flags),
  			HZ*6);
 	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -43,16 +43,13 @@
 
 #include <linux/config.h>
 #include <linux/blkdev.h>
-#include "usb.h"
-
-struct scsi_cmnd;
 
 /* Protocols */
 
 #define US_PR_CBI	0x00		/* Control/Bulk/Interrupt */
 #define US_PR_CB	0x01		/* Control/Bulk w/o interrupt */
 #define US_PR_BULK	0x50		/* bulk only */
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
 #define US_PR_SCM_ATAPI	0x80		/* SCM-ATAPI bridge */
 #endif
 #ifdef CONFIG_USB_STORAGE_SDDR09
@@ -108,8 +105,6 @@ struct bulk_cs_wrap {
 
 #define US_BULK_CS_WRAP_LEN	13
 #define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
-/* This is for Olympus Camedia digital cameras */
-#define US_BULK_CS_OLYMPUS_SIGN		0x55425355	/* spells out 'USBU' */
 #define US_BULK_STAT_OK		0
 #define US_BULK_STAT_FAIL	1
 #define US_BULK_STAT_PHASE	2
@@ -171,13 +166,8 @@ extern int usb_stor_clear_halt(struct us
 extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
 		u8 request, u8 requesttype, u16 value, u16 index,
 		void *data, u16 size);
-extern int usb_stor_intr_transfer(struct us_data *us, void *buf,
-		unsigned int length);
 extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, unsigned int *act_len);
-extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
-		struct scatterlist *sg, int num_sg, unsigned int length,
-		unsigned int *act_len);
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, int use_sg, int *residual);
 
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1,5 +1,5 @@
 /* Driver for USB Mass Storage compliant devices
- * Ununsual Devices File
+ * Unusual Devices File
  *
  * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $
  *
@@ -48,6 +48,14 @@
  * USB development list <linux-usb-devel@lists.sourceforge.net>.
  */
 
+/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
+ */
+UNUSUAL_DEV(  0x03eb, 0x2002, 0x0100, 0x0100,
+                "ATMEL",
+                "SND1 Storage",
+                US_SC_DEVICE, US_PR_DEVICE, NULL,
+                US_FL_IGNORE_RESIDUE),
+
 UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
 		"Mitsumi",
 		"USB FDD",
@@ -59,16 +67,16 @@ UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x
 		"CD-Writer+",
 		US_SC_8070, US_PR_CB, NULL, 0), 
 
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
 UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001, 
 		"HP",
 		"CD-Writer+ 8200e",
-		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
+		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
 
 UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001, 
 		"HP",
 		"CD-Writer+ CD-4e",
-		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
+		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
 #endif
 
 /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
@@ -123,6 +131,22 @@ UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x
 		"DVD-CAM DZ-MV100A Camcorder",
 		US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
 
+/* Reported by Andreas Bockhold <andreas@bockionline.de> */
+UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D70",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* BENQ DC5330
+ * Reported by Manuel Fombuena <mfombuena@ya.com> and
+ * Frank Copeland <fjc@thingy.apana.org.au> */
+UNUSUAL_DEV(  0x04a5, 0x3010, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Reported by Simon Levitt <simon@whattf.com>
  * This entry needs Sub and Proto fields */
 UNUSUAL_DEV(  0x04b8, 0x0601, 0x0100, 0x0100,
@@ -171,15 +195,12 @@ UNUSUAL_DEV(  0x04da, 0x0d05, 0x0000, 0x
 		"CD-R/RW Drive",
 		US_SC_8070, US_PR_CB, NULL, 0),
 
-/* Reported by Adriaan Penning <a.penning@luon.net>
- * Note that these cameras report "Medium not present" after
- * ALLOW_MEDIUM_REMOVAL, so they also need to be marked
- * NOT_LOCKABLE in the SCSI blacklist (and the vendor is MATSHITA). */
+/* Reported by Adriaan Penning <a.penning@luon.net> */
 UNUSUAL_DEV(  0x04da, 0x2372, 0x0000, 0x9999,
 		"Panasonic",
 		"DMC-LCx Camera",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
 
 /* Most of the following entries were developed with the help of
  * Shuttle/SCM directly.
@@ -268,6 +289,14 @@ UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_BULK32),
 
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
+		"SCM",
+		"SCM USBAT-02",
+		US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+		US_FL_SINGLE_LUN),
+#endif
+
 /* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
 UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
 		"Belkin",
@@ -324,12 +353,11 @@ UNUSUAL_DEV(  0x052b, 0x1911, 0x0100, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
-/* This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450, 
 		"Sony",
 		"DSC-S30/S70/S75/505V/F505/F707/F717/P8", 
 		US_SC_SCSI, US_PR_DEVICE, NULL,
-		US_FL_SINGLE_LUN ),
+		US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
 
 /* This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0500, 
@@ -354,6 +382,13 @@ UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x
 		0 ),
 #endif
 
+/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+		"Sony",
+		"USB Floppy Drive",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
 UNUSUAL_DEV(  0x054c, 0x002d, 0x0100, 0x0100, 
 		"Sony",
 		"Memorystick MSAC-US1",
@@ -490,8 +525,32 @@ UNUSUAL_DEV(  0x05ab, 0x5701, 0x0100, 0x
 		0 ),
 #endif
 
+/* Submitted by Sven Anderson <sven-linux@anderson.de>
+ * There are at least four ProductIDs used for iPods, so I added 0x1202 and
+ * 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears
+ * to change with firmware updates, I changed the range to maximum for all
+ * iPod entries.
+ */
+UNUSUAL_DEV( 0x05ac, 0x1202, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
 /* Reported by Avi Kivity <avi@argo.co.il> */
-UNUSUAL_DEV( 0x05ac, 0x1203, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x05ac, 0x1203, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999,
 		"Apple",
 		"iPod",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -512,6 +571,25 @@ UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
+/* The following two entries are for a Genesys USB to IDE
+ * converter chip, but it changes its ProductId depending
+ * on whether or not a disk or an optical device is enclosed
+ * They were originally reported by Alexander Oltu
+ * <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
+ * respectively.
+ */
+UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Optical",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
 /* Reported by Hanno Boeck <hanno@gmx.de>
  * Taken from the Lycoris Kernel */
 UNUSUAL_DEV(  0x0636, 0x0003, 0x0000, 0x9999,
@@ -540,19 +618,19 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
-/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
-UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
+/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
+UNUSUAL_DEV( 0x067b, 0x2507, 0x0100, 0x0100,
 		"Prolific Technology Inc.",
-		"ATAPI-6 Bridge Controller",
+		"Mass Storage Device",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
 
 /* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
 UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
 		"Prolific Technology Inc.",
 		"ATAPI-6 Bridge Controller",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
 
 /* Submitted by Benny Sjostrand <benny@hostmobility.com> */
 UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
@@ -582,14 +660,6 @@ UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN ),
 
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
-UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009, 
-		"Sandisk",
-		"ImageMate SDDR-31",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_IGNORE_SER ),
-#endif
-
 UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
 		"Sandisk",
 		"ImageMate SDDR-12",
@@ -661,6 +731,13 @@ UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xf
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
 		0 ),
 
+/* Reported by Josef Reisinger <josef.reisinger@netcologne.de> */
+UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"MD2/MD3 Disk enclosure",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_SINGLE_LUN ),
+
 UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
 		"Datafab/Unknown",
 		"Datafab-based Reader",
@@ -712,6 +789,19 @@ UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0x
 		US_FL_SINGLE_LUN ),
 #endif
 
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+/* Reported by Felix Moeller <felix@derklecks.de>
+ * in Germany this is sold by Hama with the productnumber 46952
+ * as "DualSlot CompactFlash(TM) & MStick Drive USB"
+ */
+UNUSUAL_DEV(  0x07c4, 0xa10b, 0x0000, 0xffff,
+                "DataFab Systems Inc.",
+                "USB CF+MS",
+                US_SC_SCSI, US_PR_DATAFAB, NULL,
+                0 ),
+
+#endif
+
 /* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
  * Only revision 1.13 tested (same for all of the above devices,
  * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
@@ -772,6 +862,15 @@ UNUSUAL_DEV(  0x090a, 0x1001, 0x0100, 0x
 		US_SC_DEVICE, US_PR_BULK, NULL,
 		US_FL_NEED_OVERRIDE ),
 
+/* Reported by Filippo Bardelli <filibard@libero.it>
+ * The device reports a subclass of RBC, which is wrong.
+ */
+UNUSUAL_DEV(  0x090a, 0x1050, 0x0100, 0x0100,
+		"Trumpion Microelectronics, Inc.",
+		"33520 USB Digital Voice Recorder",
+		US_SC_UFI, US_PR_DEVICE, NULL,
+		0),
+
 /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
 UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
 		"Trumpion",
@@ -866,6 +965,13 @@ UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Ian McConnell <ian at emit.demon.co.uk> */
+UNUSUAL_DEV(  0x0dda, 0x0301, 0x0012, 0x0012,
+		"PNP_MP3",
+		"PNP_MP3 PLAYER",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
 UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
 		"USB",
@@ -888,6 +994,13 @@ UNUSUAL_DEV(  0x0ea0, 0x6828, 0x0110, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Michael Stattmann <michael@stattmann.com> */
+UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"V800-Vodafone 802",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
@@ -898,6 +1011,13 @@ UNUSUAL_DEV(  0x1019, 0x0c55, 0x0000, 0x
 		US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
 		0 ),
 
+/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
+UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
+		"Minolta",
+		"Dimage Z10",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		0 ),
+
 /* Reported by Kotrla Vitezslav <kotrla@ceb.cz> */
 UNUSUAL_DEV(  0x1370, 0x6828, 0x0110, 0x0110,
 		"SWISSBIT",
@@ -905,6 +1025,13 @@ UNUSUAL_DEV(  0x1370, 0x6828, 0x0110, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
+UNUSUAL_DEV(  0x2735, 0x100b, 0x0000, 0x9999,
+		"MPIO",
+		"HS200",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
 #ifdef CONFIG_USB_STORAGE_SDDR55
 UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x9999, 
 		"Sandisk",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -51,6 +51,9 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -63,7 +66,7 @@
 #include "debug.h"
 #include "initializers.h"
 
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
 #include "shuttle_usbat.h"
 #endif
 #ifdef CONFIG_USB_STORAGE_SDDR09
@@ -89,10 +92,6 @@
 #endif
 
 
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
 MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
@@ -103,6 +102,13 @@ module_param(delay_use, uint, S_IRUGO | 
 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
 
 
+/* These are used to make sure the module doesn't unload before all the
+ * threads have exited.
+ */
+static atomic_t total_threads = ATOMIC_INIT(0);
+static DECLARE_COMPLETION(threads_gone);
+
+
 static int storage_probe(struct usb_interface *iface,
 			 const struct usb_device_id *id);
 
@@ -144,9 +150,7 @@ static struct usb_device_id storage_usb_
 	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
 	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
 	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
 	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
-#endif
 
 	/* Terminating entry */
 	{ }
@@ -220,16 +224,14 @@ static struct us_unusual_dev us_unusual_
 	  .useTransport = US_PR_BULK},
 	{ .useProtocol = US_SC_8070,
 	  .useTransport = US_PR_BULK},
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
 	{ .useProtocol = US_SC_SCSI,
 	  .useTransport = US_PR_BULK},
-#endif
 
 	/* Terminating entry */
 	{ NULL }
 };
 
-struct usb_driver usb_storage_driver = {
+static struct usb_driver usb_storage_driver = {
 	.owner =	THIS_MODULE,
 	.name =		"usb-storage",
 	.probe =	storage_probe,
@@ -282,7 +284,7 @@ void fill_inquiry_response(struct us_dat
 static int usb_stor_control_thread(void * __us)
 {
 	struct us_data *us = (struct us_data *)__us;
-	struct Scsi_Host *host = us->host;
+	struct Scsi_Host *host = us_to_host(us);
 
 	lock_kernel();
 
@@ -291,11 +293,13 @@ static int usb_stor_control_thread(void 
 	 * so get rid of all our resources.
 	 */
 	daemonize("usb-storage");
-
 	current->flags |= PF_NOFREEZE;
-
 	unlock_kernel();
 
+	/* acquire a reference to the host, so it won't be deallocated
+	 * until we're ready to exit */
+	scsi_host_get(host);
+
 	/* signal that we've started the thread */
 	complete(&(us->notify));
 
@@ -309,9 +313,9 @@ static int usb_stor_control_thread(void 
 		/* lock the device pointers */
 		down(&(us->dev_semaphore));
 
-		/* if us->srb is NULL, we are being asked to exit */
-		if (us->srb == NULL) {
-			US_DEBUGP("-- exit command received\n");
+		/* if the device has disconnected, we are free to exit */
+		if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+			US_DEBUGP("-- exiting\n");
 			up(&(us->dev_semaphore));
 			break;
 		}
@@ -325,12 +329,6 @@ static int usb_stor_control_thread(void 
 			goto SkipForAbort;
 		}
 
-		/* don't do anything if we are disconnecting */
-		if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-			US_DEBUGP("No command during disconnect\n");
-			goto SkipForDisconnect;
-		}
-
 		scsi_unlock(host);
 
 		/* reject the command if the direction indicator 
@@ -398,7 +396,6 @@ SkipForAbort:
 			complete(&(us->notify));
 
 		/* finished working on this command */
-SkipForDisconnect:
 		us->srb = NULL;
 		scsi_unlock(host);
 
@@ -406,6 +403,8 @@ SkipForDisconnect:
 		up(&(us->dev_semaphore));
 	} /* for (;;) */
 
+	scsi_host_put(host);
+
 	/* notify the exit routine that we're actually exiting now 
 	 *
 	 * complete()/wait_for_completion() is similar to up()/down(),
@@ -420,7 +419,7 @@ SkipForDisconnect:
 	 * This is important in preemption kernels, which transfer the flow
 	 * of execution immediately upon a complete().
 	 */
-	complete_and_exit(&(us->notify), 0);
+	complete_and_exit(&threads_gone, 0);
 }	
 
 /***********************************************************************
@@ -483,6 +482,13 @@ static void get_device_info(struct us_da
 			unusual_dev->useTransport;
 	us->flags = unusual_dev->flags;
 
+	/*
+	 * This flag is only needed when we're in high-speed, so let's
+	 * disable it if we're in full-speed
+	 */
+	if (dev->speed != USB_SPEED_HIGH)
+		us->flags &= ~US_FL_GO_SLOW;
+
 	/* Log a message if a non-generic unusual_dev entry contains an
 	 * unnecessary subclass or protocol override.  This may stimulate
 	 * reports from users that will help us remove unneeded entries
@@ -515,37 +521,6 @@ static void get_device_info(struct us_da
 				idesc->bInterfaceProtocol,
 				msgs[msg]);
 	}
-
-	/* Read the device's string descriptors */
-	if (dev->descriptor.iManufacturer)
-		usb_string(dev, dev->descriptor.iManufacturer, 
-			   us->vendor, sizeof(us->vendor));
-	if (dev->descriptor.iProduct)
-		usb_string(dev, dev->descriptor.iProduct, 
-			   us->product, sizeof(us->product));
-	if (dev->descriptor.iSerialNumber)
-		usb_string(dev, dev->descriptor.iSerialNumber, 
-			   us->serial, sizeof(us->serial));
-
-	/* Use the unusual_dev strings if the device didn't provide them */
-	if (strlen(us->vendor) == 0) {
-		if (unusual_dev->vendorName)
-			strlcpy(us->vendor, unusual_dev->vendorName,
-				sizeof(us->vendor));
-		else
-			strcpy(us->vendor, "Unknown");
-	}
-	if (strlen(us->product) == 0) {
-		if (unusual_dev->productName)
-			strlcpy(us->product, unusual_dev->productName,
-				sizeof(us->product));
-		else
-			strcpy(us->product, "Unknown");
-	}
-	if (strlen(us->serial) == 0)
-		strcpy(us->serial, "None");
-
-	US_DEBUGP("Vendor: %s,  Product: %s\n", us->vendor, us->product);
 }
 
 /* Get the transport settings */
@@ -572,10 +547,10 @@ static int get_transport(struct us_data 
 		us->transport_reset = usb_stor_Bulk_reset;
 		break;
 
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
 	case US_PR_SCM_ATAPI:
 		us->transport_name = "SCM/ATAPI";
-		us->transport = hp8200e_transport;
+		us->transport = usbat_transport;
 		us->transport_reset = usb_stor_CB_reset;
 		us->max_lun = 1;
 		break;
@@ -785,20 +760,6 @@ static int usb_stor_acquire_resources(st
 
 	up(&us->dev_semaphore);
 
-	/*
-	 * Since this is a new device, we need to register a SCSI
-	 * host definition with the higher SCSI layers.
-	 */
-	us->host = scsi_host_alloc(&usb_stor_host_template, sizeof(us));
-	if (!us->host) {
-		printk(KERN_WARNING USB_STORAGE
-			"Unable to allocate the scsi host\n");
-		return -EBUSY;
-	}
-
-	/* Set the hostdata to prepare for scanning */
-	us->host->hostdata[0] = (unsigned long) us;
-
 	/* Start up our control thread */
 	p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
 	if (p < 0) {
@@ -807,6 +768,7 @@ static int usb_stor_acquire_resources(st
 		return p;
 	}
 	us->pid = p;
+	atomic_inc(&total_threads);
 
 	/* Wait for the thread to start */
 	wait_for_completion(&(us->notify));
@@ -815,37 +777,16 @@ static int usb_stor_acquire_resources(st
 }
 
 /* Release all our dynamic resources */
-void usb_stor_release_resources(struct us_data *us)
+static void usb_stor_release_resources(struct us_data *us)
 {
 	US_DEBUGP("-- %s\n", __FUNCTION__);
 
-	/* Kill the control thread.  The SCSI host must already have been
-	 * removed so it won't try to queue any more commands.
+	/* Tell the control thread to exit.  The SCSI host must
+	 * already have been removed so it won't try to queue
+	 * any more commands.
 	 */
-	if (us->pid) {
-
-		/* Wait for the thread to be idle */
-		down(&us->dev_semaphore);
-		US_DEBUGP("-- sending exit command to thread\n");
-
-		/* If the SCSI midlayer queued a final command just before
-		 * scsi_remove_host() was called, us->srb might not be
-		 * NULL.  We can overwrite it safely, because the midlayer
-		 * will not wait for the command to finish.  Also the
-		 * control thread will already have been awakened.
-		 * That's okay, an extra up() on us->sema won't hurt.
-		 *
-		 * Enqueue the command, wake up the thread, and wait for 
-		 * notification that it has exited.
-		 */
-		scsi_lock(us->host);
-		us->srb = NULL;
-		scsi_unlock(us->host);
-		up(&us->dev_semaphore);
-
-		up(&us->sema);
-		wait_for_completion(&us->notify);
-	}
+	US_DEBUGP("-- sending exit command to thread\n");
+	up(&us->sema);
 
 	/* Call the destructor routine, if it exists */
 	if (us->extra_destructor) {
@@ -853,16 +794,9 @@ void usb_stor_release_resources(struct u
 		us->extra_destructor(us->extra);
 	}
 
-	/* Finish the host removal sequence */
-	if (us->host)
-		scsi_host_put(us->host);
-
 	/* Free the extra data and the URB */
-	if (us->extra)
-		kfree(us->extra);
-	if (us->current_urb)
-		usb_free_urb(us->current_urb);
-
+	kfree(us->extra);
+	usb_free_urb(us->current_urb);
 }
 
 /* Dissociate from the USB device */
@@ -880,9 +814,6 @@ static void dissociate_dev(struct us_dat
 
 	/* Remove our private data from the interface */
 	usb_set_intfdata(us->pusb_intf, NULL);
-
-	/* Free the structure itself */
-	kfree(us);
 }
 
 /* Thread to carry out delayed SCSI-device scanning */
@@ -898,6 +829,13 @@ static int usb_stor_scan_thread(void * _
 	daemonize("usb-stor-scan");
 	unlock_kernel();
 
+	/* Acquire a reference to the host, so it won't be deallocated
+	 * until we're ready to exit */
+	scsi_host_get(us_to_host(us));
+
+	/* Signal that we've started the thread */
+	complete(&(us->notify));
+
 	printk(KERN_DEBUG
 		"usb-storage: device found at %d\n", us->pusb_dev->devnum);
 
@@ -906,7 +844,7 @@ static int usb_stor_scan_thread(void * _
 		printk(KERN_DEBUG "usb-storage: waiting for device "
 				"to settle before scanning\n");
 retry:
-		wait_event_interruptible_timeout(us->scsi_scan_wait,
+		wait_event_interruptible_timeout(us->delay_wait,
 				test_bit(US_FLIDX_DISCONNECTING, &us->flags),
 				delay_use * HZ);
 		if (current->flags & PF_FREEZE) {
@@ -917,11 +855,14 @@ retry:
 
 	/* If the device is still connected, perform the scanning */
 	if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-		scsi_scan_host(us->host);
+		scsi_scan_host(us_to_host(us));
 		printk(KERN_DEBUG "usb-storage: device scan complete\n");
+
+		/* Should we unbind if no devices were detected? */
 	}
 
-	complete_and_exit(&us->scsi_scan_done, 0);
+	scsi_host_put(us_to_host(us));
+	complete_and_exit(&threads_gone, 0);
 }
 
 
@@ -929,25 +870,30 @@ retry:
 static int storage_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
+	struct Scsi_Host *host;
 	struct us_data *us;
 	const int id_index = id - storage_usb_ids; 
 	int result;
 
 	US_DEBUGP("USB Mass Storage device detected\n");
 
-	/* Allocate the us_data structure and initialize the mutexes */
-	us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
-	if (!us) {
-		printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+	/*
+	 * Ask the SCSI layer to allocate a host structure, with extra
+	 * space at the end for our private us_data structure.
+	 */
+	host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
+	if (!host) {
+		printk(KERN_WARNING USB_STORAGE
+			"Unable to allocate the scsi host\n");
 		return -ENOMEM;
 	}
+
+	us = host_to_us(host);
 	memset(us, 0, sizeof(struct us_data));
 	init_MUTEX(&(us->dev_semaphore));
 	init_MUTEX_LOCKED(&(us->sema));
 	init_completion(&(us->notify));
-	init_waitqueue_head(&us->dev_reset_wait);
-	init_waitqueue_head(&us->scsi_scan_wait);
-	init_completion(&us->scsi_scan_done);
+	init_waitqueue_head(&us->delay_wait);
 
 	/* Associate the us_data structure with the USB device */
 	result = associate_dev(us, intf);
@@ -1000,7 +946,7 @@ static int storage_probe(struct usb_inte
 	result = usb_stor_acquire_resources(us);
 	if (result)
 		goto BadDevice;
-	result = scsi_add_host(us->host, &intf->dev);
+	result = scsi_add_host(host, &intf->dev);
 	if (result) {
 		printk(KERN_WARNING USB_STORAGE
 			"Unable to add the scsi host\n");
@@ -1012,17 +958,23 @@ static int storage_probe(struct usb_inte
 	if (result < 0) {
 		printk(KERN_WARNING USB_STORAGE 
 		       "Unable to start the device-scanning thread\n");
-		scsi_remove_host(us->host);
+		scsi_remove_host(host);
 		goto BadDevice;
 	}
+	atomic_inc(&total_threads);
+
+	/* Wait for the thread to start */
+	wait_for_completion(&(us->notify));
 
 	return 0;
 
 	/* We come here if there are any problems */
 BadDevice:
 	US_DEBUGP("storage_probe() failed\n");
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
 	usb_stor_release_resources(us);
 	dissociate_dev(us);
+	scsi_host_put(host);
 	return result;
 }
 
@@ -1034,24 +986,26 @@ static void storage_disconnect(struct us
 	US_DEBUGP("storage_disconnect() called\n");
 
 	/* Prevent new USB transfers, stop the current command, and
-	 * interrupt a device-reset delay */
+	 * interrupt a SCSI-scan or device-reset delay */
 	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
 	usb_stor_stop_transport(us);
-	wake_up(&us->dev_reset_wait);
+	wake_up(&us->delay_wait);
 
-	/* Interrupt the SCSI-device-scanning thread's time delay, and
-	 * wait for the thread to finish */
-	wake_up(&us->scsi_scan_wait);
-	wait_for_completion(&us->scsi_scan_done);
+	/* It doesn't matter if the SCSI-scanning thread is still running.
+	 * The thread will exit when it sees the DISCONNECTING flag. */
 
 	/* Wait for the current command to finish, then remove the host */
 	down(&us->dev_semaphore);
 	up(&us->dev_semaphore);
-	scsi_remove_host(us->host);
+	scsi_remove_host(us_to_host(us));
 
 	/* Wait for everything to become idle and release all our resources */
 	usb_stor_release_resources(us);
 	dissociate_dev(us);
+
+	/* Drop our reference to the host; the SCSI core will free it
+	 * (and "us" along with it) when the refcount becomes 0. */
+	scsi_host_put(us_to_host(us));
 }
 
 /***********************************************************************
@@ -1081,6 +1035,16 @@ static void __exit usb_stor_exit(void)
 	 */
 	US_DEBUGP("-- calling usb_deregister()\n");
 	usb_deregister(&usb_storage_driver) ;
+
+	/* Don't return until all of our control and scanning threads
+	 * have exited.  Since each thread signals threads_gone as its
+	 * last act, we have to call wait_for_completion the right number
+	 * of times.
+	 */
+	while (atomic_read(&total_threads) > 0) {
+		wait_for_completion(&threads_gone);
+		atomic_dec(&total_threads);
+	}
 }
 
 module_init(usb_stor_init);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -48,6 +48,7 @@
 #include <linux/blkdev.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <scsi/scsi_host.h>
 
 struct us_data;
 struct scsi_cmnd;
@@ -65,16 +66,35 @@ struct us_unusual_dev {
 	unsigned int flags;
 };
 
-/* Flag definitions: these entries are static */
-#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0	    */
-#define US_FL_MODE_XLATE      0          /* [no longer used]                */
-#define US_FL_NEED_OVERRIDE   0x00000004 /* unusual_devs entry is necessary */
-#define US_FL_IGNORE_SER      0		 /* [no longer used]		    */
-#define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets	    */
-#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs faking   */
-#define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big  */
-#define US_FL_IGNORE_RESIDUE  0x00000100 /* reported residue is wrong	    */
-#define US_FL_BULK32          0x00000200 /* Uses 32-byte CBW length         */
+/*
+ * Static flag definitions.  We use this roundabout technique so that the
+ * proc_info() routine can automatically display a message for each flag.
+ */
+#define US_DO_ALL_FLAGS						\
+	US_FLAG(SINGLE_LUN,	0x00000001)			\
+		/* allow access to only LUN 0 */		\
+	US_FLAG(NEED_OVERRIDE,	0x00000002)			\
+		/* unusual_devs entry is necessary */		\
+	US_FLAG(SCM_MULT_TARG,	0x00000004)			\
+		/* supports multiple targets */			\
+	US_FLAG(FIX_INQUIRY,	0x00000008)			\
+		/* INQUIRY response needs faking */		\
+	US_FLAG(FIX_CAPACITY,	0x00000010)			\
+		/* READ CAPACITY response too big */		\
+	US_FLAG(IGNORE_RESIDUE,	0x00000020)			\
+		/* reported residue is wrong */			\
+	US_FLAG(BULK32,		0x00000040)			\
+		/* Uses 32-byte CBW length */			\
+	US_FLAG(NOT_LOCKABLE,	0x00000080)			\
+		/* PREVENT/ALLOW not supported */		\
+	US_FLAG(GO_SLOW,	0x00000100)			\
+		/* Need delay after Command phase */		\
+	US_FLAG(NO_WP_DETECT,	0x00000200)			\
+		/* Don't check for write-protect */		\
+
+#define US_FLAG(name, value)	US_FL_##name = value ,
+enum { US_DO_ALL_FLAGS };
+#undef US_FLAG
 
 /* Dynamic flag definitions: used in set_bit() etc. */
 #define US_FLIDX_URB_ACTIVE	18  /* 0x00040000  current_urb is in use  */
@@ -121,11 +141,9 @@ struct us_data {
 	unsigned int		recv_intr_pipe;
 
 	/* information about the device */
-	char			vendor[USB_STOR_STRING_LEN];
-	char			product[USB_STOR_STRING_LEN];
-	char			serial[USB_STOR_STRING_LEN];
 	char			*transport_name;
 	char			*protocol_name;
+	__le32			bcs_signature;
 	u8			subclass;
 	u8			protocol;
 	u8			max_lun;
@@ -139,7 +157,6 @@ struct us_data {
 	proto_cmnd		proto_handler;	 /* protocol handler	   */
 
 	/* SCSI interfaces */
-	struct Scsi_Host	*host;		 /* our dummy host data */
 	struct scsi_cmnd	*srb;		 /* current srb		*/
 
 	/* thread information */
@@ -154,19 +171,22 @@ struct us_data {
 	dma_addr_t		iobuf_dma;
 
 	/* mutual exclusion and synchronization structures */
-	struct semaphore	sema;		 /* to sleep thread on   */
-	struct completion	notify;		 /* thread begin/end	 */
-	wait_queue_head_t	dev_reset_wait;  /* wait during reset    */
-	wait_queue_head_t	scsi_scan_wait;	 /* wait before scanning */
-	struct completion	scsi_scan_done;	 /* scan thread end	 */
+	struct semaphore	sema;		 /* to sleep thread on	    */
+	struct completion	notify;		 /* thread begin/end	    */
+	wait_queue_head_t	delay_wait;	 /* wait during scan, reset */
 
 	/* subdriver information */
 	void			*extra;		 /* Any extra data          */
 	extra_data_destructor	extra_destructor;/* extra data destructor   */
 };
 
-/* The structure which defines our driver */
-extern struct usb_driver usb_storage_driver;
+/* Convert between us_data and the corresponding Scsi_Host */
+static struct Scsi_Host inline *us_to_host(struct us_data *us) {
+	return container_of((void *) us, struct Scsi_Host, hostdata);
+}
+static struct us_data inline *host_to_us(struct Scsi_Host *host) {
+	return (struct us_data *) host->hostdata;
+}
 
 /* Function to fill an inquiry response. See usb.c for details */
 extern void fill_inquiry_response(struct us_data *us,
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -112,6 +112,7 @@ static ssize_t skel_read(struct file *fi
 {
 	struct usb_skel *dev;
 	int retval = 0;
+	int bytes_read;
 
 	dev = (struct usb_skel *)file->private_data;
 	
@@ -120,14 +121,14 @@ static ssize_t skel_read(struct file *fi
 			      usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
 			      dev->bulk_in_buffer,
 			      min(dev->bulk_in_size, count),
-			      &count, HZ*10);
+			      &bytes_read, 10000);
 
 	/* if the read was successful, copy the data to userspace */
 	if (!retval) {
-		if (copy_to_user(buffer, dev->bulk_in_buffer, count))
+		if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
 			retval = -EFAULT;
 		else
-			retval = count;
+			retval = bytes_read;
 	}
 
 	return retval;
@@ -271,7 +272,7 @@ static int skel_probe(struct usb_interfa
 		}
 
 		if (!dev->bulk_out_endpointAddr &&
-		    !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    !(endpoint->bEndpointAddress & USB_DIR_OUT) &&
 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 					== USB_ENDPOINT_XFER_BULK)) {
 			/* we found a bulk out endpoint */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,7 +5,7 @@
 menu "Graphics support"
 
 config FB
-	bool "Support for frame buffer devices"
+	tristate "Support for frame buffer devices"
 	---help---
 	  The frame buffer device provides an abstraction for the graphics
 	  hardware. It represents the frame buffer of some video hardware and
@@ -38,6 +38,47 @@ config FB
 	  (e.g. an accelerated X server) and that are not frame buffer
 	  device-aware may cause unexpected results. If unsure, say N.
 
+config FB_CFB_FILLRECT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_fillrect function for generic software rectangle
+	  filling. This is used by drivers that don't provide their own
+	  (accelerated) version.
+
+config FB_CFB_COPYAREA
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_copyarea function for generic software area copying.
+	  This is used by drivers that don't provide their own (accelerated)
+	  version.
+
+config FB_CFB_IMAGEBLIT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_imageblit function for generic software image
+	  blitting. This is used by drivers that don't provide their own
+	  (accelerated) version.
+
+config FB_SOFT_CURSOR
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the soft_cursor function for generic software cursor support.
+	  This is used by drivers that don't provide their own (accelerated)
+	  version.
+
+config FB_MACMODES
+       tristate
+       depends on FB
+       default n
+
 config FB_MODE_HELPERS
         bool "Enable Video Mode Handling Helpers"
         depends on FB
@@ -70,6 +111,10 @@ config FB_TILEBLITTING
 config FB_CIRRUS
 	tristate "Cirrus Logic support"
 	depends on FB && (ZORRO || PCI)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  This enables support for Cirrus Logic GD542x/543x based boards on
 	  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
@@ -85,6 +130,10 @@ config FB_CIRRUS
 config FB_PM2
 	tristate "Permedia2 support"
 	depends on FB && ((AMIGA && BROKEN) || PCI)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Permedia2 AGP frame
 	  buffer card from ASK, aka `Graphic Blaster Exxtreme'.  There is a
@@ -100,6 +149,10 @@ config FB_PM2_FIFO_DISCONNECT
 config FB_ARMCLCD
 	tristate "ARM PrimeCell PL110 support"
 	depends on FB && ARM && ARM_AMBA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This framebuffer device driver is for the ARM PrimeCell PL110
 	  Colour LCD controller.  ARM PrimeCells provide the building
@@ -112,7 +165,11 @@ config FB_ARMCLCD
 
 config FB_ACORN
 	bool "Acorn VIDC support"
-	depends on FB && ARM && ARCH_ACORN
+	depends on (FB = y) && ARM && (ARCH_ACORN || ARCH_CLPS7500)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Acorn VIDC graphics
 	  hardware found in Acorn RISC PCs and other ARM-based machines.  If
@@ -120,11 +177,19 @@ config FB_ACORN
 
 config FB_CLPS711X
 	bool "CLPS711X LCD support"
-	depends on FB && ARM && ARCH_CLPS711X
+	depends on (FB = y) && ARM && ARCH_CLPS711X
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 
 config FB_SA1100
 	bool "SA-1100 LCD support"
-	depends on FB && ARM && ARCH_SA1100
+	depends on (FB = y) && ARM && ARCH_SA1100
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is a framebuffer device for the SA-1100 LCD Controller.
 	  See <http://www.linux-fbdev.org/> for information on framebuffer
@@ -133,9 +198,21 @@ config FB_SA1100
 	  If you plan to use the LCD display with your SA-1100 system, say
 	  Y here.
 
+config FB_IMX
+	tristate "Motorola i.MX LCD support"
+	depends on FB && ARM && ARCH_IMX
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+
 config FB_CYBER2000
 	tristate "CyberPro 2000/2010/5000 support"
 	depends on FB && PCI && (BROKEN || !SPARC64)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This enables support for the Integraphics CyberPro 20x0 and 5000
 	  VGA chips used in the Rebel.com Netwinder and other machines.
@@ -144,17 +221,25 @@ config FB_CYBER2000
 
 config FB_APOLLO
 	bool
-	depends on FB && APOLLO
+	depends on (FB = y) && APOLLO
 	default y
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 
 config FB_Q40
 	bool
-	depends on FB && Q40
+	depends on (FB = y) && Q40
 	default y
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 
 config FB_AMIGA
 	tristate "Amiga native chipset support"
 	depends on FB && AMIGA
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the builtin graphics
 	  chipset found in Amigas.
@@ -191,6 +276,10 @@ config FB_AMIGA_AGA
 config FB_CYBER
 	tristate "Amiga CyberVision 64 support"
 	depends on FB && ZORRO && BROKEN
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This enables support for the Cybervision 64 graphics card from
 	  Phase5. Please note that its use is not all that intuitive (i.e. if
@@ -201,7 +290,11 @@ config FB_CYBER
 
 config FB_VIRGE
 	bool "Amiga CyberVision 64/3D support "
-	depends on FB && ZORRO && BROKEN
+	depends on (FB = y) && ZORRO && BROKEN
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This enables support for the Cybervision 64/3D graphics card from
 	  Phase5. Please note that its use is not all that intuitive (i.e. if
@@ -212,7 +305,7 @@ config FB_VIRGE
 
 config FB_RETINAZ3
 	tristate "Amiga Retina Z3 support"
-	depends on FB && ZORRO && BROKEN
+	depends on (FB = y) && ZORRO && BROKEN
 	help
 	  This enables support for the Retina Z3 graphics card. Say N unless
 	  you have a Retina Z3 or plan to get one before you next recompile
@@ -220,73 +313,112 @@ config FB_RETINAZ3
 
 config FB_FM2
 	bool "Amiga FrameMaster II/Rainbow II support"
-	depends on FB && ZORRO
+	depends on (FB = y) && ZORRO
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Amiga FrameMaster
 	  card from BSC (exhibited 1992 but not shipped as a CBM product).
 
 config FB_ATARI
 	bool "Atari native chipset support"
-	depends on FB && ATARI && BROKEN
+	depends on (FB = y) && ATARI && BROKEN
 	help
 	  This is the frame buffer device driver for the builtin graphics
 	  chipset found in Ataris.
 
 config FB_OF
 	bool "Open Firmware frame buffer device support"
-	depends on FB && (PPC64 || PPC_OF)
+	depends on (FB = y) && (PPC64 || PPC_OF)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
 	help
 	  Say Y if you want support with Open Firmware for your graphics
 	  board.
 
 config FB_CONTROL
 	bool "Apple \"control\" display support"
-	depends on FB && PPC_PMAC
+	depends on (FB = y) && PPC_PMAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
 	help
 	  This driver supports a frame buffer for the graphics adapter in the
 	  Power Macintosh 7300 and others.
 
 config FB_PLATINUM
 	bool "Apple \"platinum\" display support"
-	depends on FB && PPC_PMAC
+	depends on (FB = y) && PPC_PMAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
 	help
 	  This driver supports a frame buffer for the "platinum" graphics
 	  adapter in some Power Macintoshes.
 
 config FB_VALKYRIE
 	bool "Apple \"valkyrie\" display support"
-	depends on FB && (MAC || PPC_PMAC)
+	depends on (FB = y) && (MAC || PPC_PMAC)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
 	help
 	  This driver supports a frame buffer for the "valkyrie" graphics
 	  adapter in some Power Macintoshes.
 
 config FB_CT65550
 	bool "Chips 65550 display support"
-	depends on FB && PPC
+	depends on (FB = y) && PPC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Chips & Technologies
 	  65550 graphics chip in PowerBooks.
 
 config FB_ASILIANT
 	bool "Chips 69000 display support"
-	depends on FB && PCI
+	depends on (FB = y) && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 
 config FB_IMSTT
 	bool "IMS Twin Turbo display support"
-	depends on FB && PCI
+	depends on (FB = y) && PCI
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
 	help
 	  The IMS Twin Turbo is a PCI-based frame buffer card bundled with
 	  many Macintosh and compatible computers.
 
 config FB_S3TRIO
 	bool "S3 Trio display support"
-	depends on FB && PPC && BROKEN
+	depends on (FB = y) && PPC && BROKEN
 	help
 	  If you have a S3 Trio say Y. Say N for S3 Virge.
 
 config FB_VGA16
 	tristate "VGA 16-color graphics support"
 	depends on FB && (X86 || PPC)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for VGA 16 color graphic
 	  cards. Say Y if you have such a card.
@@ -297,6 +429,10 @@ config FB_VGA16
 config FB_STI
 	tristate "HP STI frame buffer device support"
 	depends on FB && PARISC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	default y
 	---help---
 	  STI refers to the HP "Standard Text Interface" which is a set of
@@ -313,24 +449,40 @@ config FB_STI
 
 config FB_MAC
 	bool "Generic Macintosh display support"
-	depends on FB && MAC
+	depends on (FB = y) && MAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
 
 #      bool '  Apple DAFB display support' CONFIG_FB_DAFB
 config FB_HP300
 	bool
-	depends on FB && HP300
+	depends on (FB = y) && HP300
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	default y
 
 config FB_TGA
 	tristate "TGA framebuffer support"
 	depends on FB && ALPHA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for generic TGA graphic
 	  cards. Say Y if you have one of those.
 
 config FB_VESA
 	bool "VESA VGA graphics support"
-	depends on FB && (X86 || X86_64)
+	depends on (FB = y) && (X86 || X86_64)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for generic VESA 2.0
 	  compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -345,6 +497,10 @@ config VIDEO_SELECT
 config FB_HGA
 	tristate "Hercules mono graphics support"
 	depends on FB && X86
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Say Y here if you have a Hercules mono graphics card.
 
@@ -364,18 +520,26 @@ config FB_HGA_ACCEL
 
 config VIDEO_SELECT
 	bool
-	depends on FB && X86
+	depends on (FB = y) && X86
 	default y
 
 config FB_SGIVW
 	tristate "SGI Visual Workstation framebuffer support"
 	depends on FB && X86_VISWS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  SGI Visual Workstation support for framebuffer graphics.
 
 config FB_GBE
 	bool "SGI Graphics Backend frame buffer support"
-	depends on FB && (SGI_IP32 || X86_VISWS)
+	depends on (FB = y) && (SGI_IP32 || X86_VISWS)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
  	help
 	  This is the frame buffer device driver for SGI Graphics Backend.
 	  This chip is used in SGI O2 and Visual Workstation 320/540.
@@ -390,28 +554,38 @@ config FB_GBE_MEM
 
 config BUS_I2C
 	bool
-	depends on FB && VISWS
+	depends on (FB = y) && VISWS
 	default y
 
 config FB_SUN3
 	bool "Sun3 framebuffer support"
-	depends on FB && (SUN3 || SUN3X) && BROKEN
+	depends on (FB = y) && (SUN3 || SUN3X) && BROKEN
 
 config FB_BW2
 	bool "BWtwo support"
-	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the BWtwo frame buffer.
 
 config FB_CG3
 	bool "CGthree support"
-	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the CGthree frame buffer.
 
 config FB_CG6
 	bool "CGsix (GX,TurboGX) support"
-	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the CGsix (GX, TurboGX)
 	  frame buffer.
@@ -419,6 +593,10 @@ config FB_CG6
 config FB_PVR2
 	tristate "NEC PowerVR 2 display support"
 	depends on FB && SH_DREAMCAST
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  Say Y here if you have a PowerVR 2 card in your box.  If you plan to
 	  run linux on your Dreamcast, you will have to say Y here.
@@ -436,19 +614,58 @@ config FB_PVR2
 
 config FB_EPSON1355
 	bool "Epson 1355 framebuffer support"
-	depends on FB && (SUPERH || ARCH_CEIVA)
+	depends on (FB = y) && (SUPERH || ARCH_CEIVA)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Build in support for the SED1355 Epson Research Embedded RAMDAC
 	  LCD/CRT Controller (since redesignated as the S1D13505) as a
 	  framebuffer.  Product specs at
 	  <http://www.erd.epson.com/vdc/html/products.htm>.
 
+config FB_NVIDIA
+	tristate "nVidia Framebuffer Support"
+	depends on FB && PCI
+	select I2C_ALGOBIT if FB_NVIDIA_I2C
+	select I2C if FB_NVIDIA_I2C
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports graphics boards with the nVidia chips, TNT
+	  and newer. For very old chipsets, such as the RIVA128, then use
+	  the rivafb.
+	  Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nvidiafb.
+
+config FB_NVIDIA_I2C
+       bool "Enable DDC Support"
+       depends on FB_NVIDIA && !PPC_OF
+       help
+	  This enables I2C support for nVidia Chipsets.  This is used
+	  only for getting EDID information from the attached display
+	  allowing for robust video mode handling and switching.
+
+	  Because fbdev-2.6 requires that drivers must be able to
+	  independently validate video mode parameters, you should say Y
+	  here.
+
 config FB_RIVA
 	tristate "nVidia Riva support"
 	depends on FB && PCI
 	select I2C_ALGOBIT if FB_RIVA_I2C
 	select I2C if FB_RIVA_I2C
 	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports graphics boards with the nVidia Riva/Geforce
 	  chips.
@@ -484,6 +701,10 @@ config FB_I810
 	select AGP
 	select AGP_INTEL
 	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports the on-board graphics built in to the Intel 810 
           and 815 chipsets.  Say Y if you have and plan to use such a board.
@@ -522,6 +743,11 @@ config FB_INTEL
 	depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
 	select AGP
 	select AGP_INTEL
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports the on-board graphics built in to the Intel
           830M/845G/852GM/855GM/865G chipsets.
@@ -541,6 +767,12 @@ config FB_INTEL_DEBUG
 config FB_MATROX
 	tristate "Matrox acceleration"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_TILEBLITTING
+	select FB_MACMODES if PPC_PMAC
 	---help---
 	  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
 	  Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
@@ -676,6 +908,11 @@ config FB_MATROX_MULTIHEAD
 config FB_RADEON_OLD
 	tristate "ATI Radeon display support (Old driver)"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
 	help
 	  Choose this option if you want to use an ATI Radeon graphics card as
 	  a framebuffer device.  There are both PCI and AGP versions.  You
@@ -689,6 +926,11 @@ config FB_RADEON
 	select I2C_ALGOBIT if FB_RADEON_I2C
 	select I2C if FB_RADEON_I2C
 	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC_OF
 	help
 	  Choose this option if you want to use an ATI Radeon graphics card as
 	  a framebuffer device.  There are both PCI and AGP versions.  You
@@ -723,6 +965,11 @@ config FB_RADEON_DEBUG
 config FB_ATY128
 	tristate "ATI Rage128 display support"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC_PMAC
 	help
 	  This driver supports graphics boards with the ATI Rage128 chips.
 	  Say Y if you have such a graphics board and read
@@ -734,6 +981,11 @@ config FB_ATY128
 config FB_ATY
 	tristate "ATI Mach64 display support" if PCI || ATARI
 	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
 	help
 	  This driver supports graphics boards with the ATI Mach64 chips.
 	  Say Y if you have such a graphics board.
@@ -781,6 +1033,10 @@ config FB_SAVAGE
 	select I2C_ALGOBIT if FB_SAVAGE_I2C
 	select I2C if FB_SAVAGE_I2C
 	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports notebooks and computers with S3 Savage PCI/AGP
 	  chips.
@@ -791,7 +1047,7 @@ config FB_SAVAGE
 	  will be called savagefb.
 
 config FB_SAVAGE_I2C
-       tristate "Enable DDC2 Support"
+       bool "Enable DDC2 Support"
        depends on FB_SAVAGE
        help
 	  This enables I2C support for S3 Savage Chipsets.  This is used
@@ -803,7 +1059,7 @@ config FB_SAVAGE_I2C
 	  here.
 
 config FB_SAVAGE_ACCEL
-       tristate "Enable Console Acceleration"
+       bool "Enable Console Acceleration"
        depends on FB_SAVAGE
        default n
        help
@@ -814,6 +1070,10 @@ config FB_SAVAGE_ACCEL
 config FB_SIS
 	tristate "SiS acceleration"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the SiS 300, 315 and
 	  330 series VGA chipsets. Specs available at <http://www.sis.com>
@@ -838,6 +1098,10 @@ config FB_NEOMAGIC
 	tristate "NeoMagic display support"
 	depends on FB && PCI
 	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports notebooks with NeoMagic PCI chips.
 	  Say Y if you have such a graphics card. 
@@ -848,6 +1112,10 @@ config FB_NEOMAGIC
 config FB_KYRO
 	tristate "IMG Kyro support"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Say Y here if you have a STG4000 / Kyro / PowerVR 3 based
 	  graphics board.
@@ -858,6 +1126,10 @@ config FB_KYRO
 config FB_3DFX
 	tristate "3Dfx Banshee/Voodoo3 display support"
 	depends on FB && PCI
+	select FB_CFB_IMAGEBLIT
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_SOFT_CURSOR
 	help
 	  This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
 	  chips. Say Y if you have such a graphics board.
@@ -876,6 +1148,10 @@ config FB_3DFX_ACCEL
 config FB_VOODOO1
 	tristate "3Dfx Voodoo Graphics (sst1) support"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or 
 	  Voodoo2 (cvg) based graphics card.
@@ -891,6 +1167,10 @@ config FB_VOODOO1
 config FB_TRIDENT
 	tristate "Trident support"
 	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  This driver is supposed to support graphics boards with the
 	  Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops
@@ -953,17 +1233,22 @@ config PB1500_TFT
 
 config FB_AU1100
 	bool "Au1100 LCD Driver"
-	depends on FB && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+
+source "drivers/video/geode/Kconfig"
 
 config FB_SBUS
 	bool "SBUS and UPA framebuffers"
-	depends on FB && (SPARC32 || SPARC64)
+	depends on (FB = y) && (SPARC32 || SPARC64)
 	help
 	  Say Y if you want support for SBUS or UPA based frame buffer device.
 
 config FB_FFB
 	bool "Creator/Creator3D/Elite3D support"
 	depends on FB_SBUS && SPARC64
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Creator, Creator3D,
 	  and Elite3D graphics boards.
@@ -971,6 +1256,10 @@ config FB_FFB
 config FB_TCX
 	bool "TCX (SS4/SS5 only) support"
 	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the TCX 24/8bit frame
 	  buffer.
@@ -978,6 +1267,10 @@ config FB_TCX
 config FB_CG14
 	bool "CGfourteen (SX) support"
 	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the CGfourteen frame
 	  buffer on Desktop SPARCsystems with the SX graphics option.
@@ -985,6 +1278,10 @@ config FB_CG14
 config FB_P9100
 	bool "P9100 (Sparcbook 3 only) support"
 	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the P9100 card
 	  supported on Sparcbook 3 machines.
@@ -992,17 +1289,25 @@ config FB_P9100
 config FB_LEO
 	bool "Leo (ZX) support"
 	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the SBUS-based Sun ZX
 	  (leo) frame buffer cards.
 
 config FB_PCI
 	bool "PCI framebuffers"
-	depends on FB && PCI && (SPARC64 || SPARC32)
+	depends on (FB = y) && PCI && (SPARC64 || SPARC32)
 
 config FB_IGA
 	bool "IGA 168x display support"
 	depends on SPARC32 && FB_PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the framebuffer device for the INTERGRAPHICS 1680 and
 	  successor frame buffer cards.
@@ -1010,27 +1315,43 @@ config FB_IGA
 config FB_HIT
 	tristate "HD64461 Frame Buffer support"
 	depends on FB && HD64461
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  This is the frame buffer device driver for the Hitachi HD64461 LCD
 	  frame buffer card.
 
 config FB_PMAG_AA
 	bool "PMAG-AA TURBOchannel framebuffer support"
-	depends on FB && MACH_DECSTATION && TC
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1)
 	  used mainly in the MIPS-based DECstation series.
 
 config FB_PMAG_BA
 	bool "PMAG-BA TURBOchannel framebuffer support"
-	depends on FB && MACH_DECSTATION && TC
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8)
 	  used mainly in the MIPS-based DECstation series.
 
 config FB_PMAGB_B
 	bool "PMAGB-B TURBOchannel framebuffer support"
-	depends on FB && MACH_DECSTATION && TC
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Support for the PMAGB-B TURBOchannel framebuffer card used mainly
 	  in the MIPS-based DECstation series. The card is currently only
@@ -1038,7 +1359,11 @@ config FB_PMAGB_B
 
 config FB_MAXINE
 	bool "Maxine (Personal DECstation) onboard framebuffer support"
-	depends on FB && MACH_DECSTATION && TC
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Support for the onboard framebuffer (1024x768x8) in the Personal
 	  DECstation series (Personal DECstation 5000/20, /25, /33, /50,
@@ -1046,7 +1371,11 @@ config FB_MAXINE
 
 config FB_TX3912
 	bool "TMPTX3912/PR31700 frame buffer support"
-	depends on FB && NINO
+	depends on (FB = y) && NINO
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core
 	  see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
@@ -1056,13 +1385,21 @@ config FB_TX3912
 config FB_G364
 	bool
 	depends on MIPS_MAGNUM_4000 || OLIVETTI_M700
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  The G364 driver is the framebuffer used in MIPS Magnum 4000 and
 	  Olivetti M700-10 systems.
 
 config FB_68328
 	bool "Motorola 68328 native frame buffer support"
-	depends on (M68328 || M68EZ328 || M68VZ328)
+	depends on FB && (M68328 || M68EZ328 || M68VZ328)
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	help
 	  Say Y here if you want to support the built-in frame buffer of
 	  the Motorola 68328 CPU family.
@@ -1070,6 +1407,10 @@ config FB_68328
 config FB_PXA
 	tristate "PXA LCD framebuffer support"
 	depends on FB && ARCH_PXA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  Frame buffer driver for the built-in LCD controller in the Intel
 	  PXA2x0 processor.
@@ -1084,6 +1425,10 @@ config FB_PXA
 config FB_W100
 	tristate "W100 frame buffer support"
 	depends on FB && PXA_SHARPSL
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
 
@@ -1111,9 +1456,25 @@ config FB_PXA_PARAMETERS
 
 	  <file:Documentation/fb/pxafb.txt> describes the available parameters.
 
+config FB_S1D13XXX
+	tristate "Epson S1D13XXX framebuffer support"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for S1D13XXX framebuffer device family (currently only
+	  working with S1D13806). Product specs at
+	  <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
+
 config FB_VIRTUAL
 	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
 	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
 	---help---
 	  This is a `virtual' frame buffer device. It operates on a chunk of
 	  unswappable kernel memory instead of on the memory of a graphics
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -8,102 +8,94 @@ obj-$(CONFIG_VT)		  += console/
 obj-$(CONFIG_LOGO)		  += logo/
 obj-$(CONFIG_SYSFS)		  += backlight/
 
-obj-$(CONFIG_FB)                  += fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o softcursor.o
-# Only include macmodes.o if we have FB support and are PPC
-ifeq ($(CONFIG_FB),y)
-obj-$(CONFIG_PPC)                 += macmodes.o
-endif
+obj-$(CONFIG_FB)                  += fb.o
+fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o
+fb-objs                           := $(fb-y)
+
+obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
+obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
+obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SOFT_CURSOR)   += softcursor.o
+obj-$(CONFIG_FB_MACMODES)      += macmodes.o
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
 obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
-obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
-obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PM2)              += pm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 
-obj-$(CONFIG_FB_MATROX)		  += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_RIVA)		  += riva/ cfbimgblt.o cfbfillrect.o \
-				     cfbcopyarea.o vgastate.o
-obj-$(CONFIG_FB_ATY)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_ATY128)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_RADEON)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_SIS)		  += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_KYRO)             += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_SAVAGE)		  += savage/ cfbfillrect.o cfbcopyarea.o \
-				     cfbimgblt.o
-obj-$(CONFIG_FB_I810)             += cfbcopyarea.o cfbfillrect.o cfbimgblt.o \
-				     vgastate.o
-obj-$(CONFIG_FB_INTEL)            += cfbfillrect.o cfbcopyarea.o \
-	                             cfbimgblt.o
-
-obj-$(CONFIG_FB_RADEON_OLD)	  += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o vgastate.o
+obj-$(CONFIG_FB_MATROX)		  += matrox/
+obj-$(CONFIG_FB_RIVA)		  += riva/ vgastate.o
+obj-$(CONFIG_FB_NVIDIA)		  += nvidia/
+obj-$(CONFIG_FB_ATY)		  += aty/ macmodes.o
+obj-$(CONFIG_FB_ATY128)		  += aty/ macmodes.o
+obj-$(CONFIG_FB_RADEON)		  += aty/
+obj-$(CONFIG_FB_SIS)		  += sis/
+obj-$(CONFIG_FB_KYRO)             += kyro/
+obj-$(CONFIG_FB_SAVAGE)		  += savage/
+obj-$(CONFIG_FB_GEODE)		  += geode/
+obj-$(CONFIG_FB_I810)             += vgastate.o
+obj-$(CONFIG_FB_RADEON_OLD)	  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o vgastate.o
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
-obj-$(CONFIG_FB_3DFX)             += tdfxfb.o cfbimgblt.o
-ifneq ($(CONFIG_FB_3DFX_ACCEL),y)
-obj-$(CONFIG_FB_3DFX)             += cfbfillrect.o cfbcopyarea.o
-endif
-obj-$(CONFIG_FB_CONTROL)          += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_CT65550)          += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_IMSTT)            += imsttfb.o cfbimgblt.o
+obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
+obj-$(CONFIG_FB_CONTROL)          += controlfb.o
+obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
+obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
+obj-$(CONFIG_FB_CT65550)          += chipsfb.o
+obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
-obj-$(CONFIG_FB_FM2)              += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_TRIDENT)	  += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o
-obj-$(CONFIG_FB_STI)              += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
-obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o
-obj-$(CONFIG_FB_CG3)              += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_BW2)              += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_CG14)             += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_P9100)            += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_TCX)              += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_LEO)              += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
-				     cfbfillrect.o
-obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_ACORN)            += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_TRIDENT)	  += tridentfb.o
+obj-$(CONFIG_FB_STI)              += stifb.o
+obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o
+obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o
+obj-$(CONFIG_FB_CG3)              += cg3.o sbuslib.o
+obj-$(CONFIG_FB_BW2)              += bw2.o sbuslib.o
+obj-$(CONFIG_FB_CG14)             += cg14.o sbuslib.o
+obj-$(CONFIG_FB_P9100)            += p9100.o sbuslib.o
+obj-$(CONFIG_FB_TCX)              += tcx.o sbuslib.o
+obj-$(CONFIG_FB_LEO)              += leo.o sbuslib.o
+obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+obj-$(CONFIG_FB_ACORN)            += acornfb.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
-obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_HGA)              += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
-obj-$(CONFIG_FB_IGA)              += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_APOLLO)           += dnfb.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_Q40)              += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_TGA)              += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_HP300)            += hpfb.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_G364)             += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_SA1100)           += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_MAC)              += macfb.o
+obj-$(CONFIG_FB_HGA)              += hgafb.o
+obj-$(CONFIG_FB_IGA)              += igafb.o
+obj-$(CONFIG_FB_APOLLO)           += dnfb.o
+obj-$(CONFIG_FB_Q40)              += q40fb.o
+obj-$(CONFIG_FB_TGA)              += tgafb.o
+obj-$(CONFIG_FB_HP300)            += hpfb.o
+obj-$(CONFIG_FB_G364)             += g364fb.o
+obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
-obj-$(CONFIG_FB_HIT)              += hitfb.o cfbfillrect.o cfbimgblt.o
-obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PVR2)             += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_VOODOO1)          += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_68328)            += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_GBE)              += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o
-obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PXA)		  += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
-obj-$(CONFIG_FB_W100)		   += w100fb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
+obj-$(CONFIG_FB_HIT)              += hitfb.o
+obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o
+obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
+obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
+obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
+obj-$(CONFIG_FB_68328)            += 68328fb.o
+obj-$(CONFIG_FB_GBE)              += gbefb.o
+obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
+obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
+obj-$(CONFIG_FB_PXA)		  += pxafb.o
+obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o fbgen.o
-obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_MAXINE)		  += maxinefb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_TX3912)		  += tx3912fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.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_S1D13XXX)	  += s1d13xxxfb.o
+obj-$(CONFIG_FB_IMX)              += imxfb.o
 
 # Platform or fallback drivers go here
-obj-$(CONFIG_FB_VESA)             += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_VGA16)            += vga16fb.o cfbfillrect.o cfbcopyarea.o \
-	                             cfbimgblt.o vgastate.o
-obj-$(CONFIG_FB_OF)               += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o
+obj-$(CONFIG_FB_VESA)             += vesafb.o
+obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
+obj-$(CONFIG_FB_OF)               += offb.o
 
 # the test framebuffer is last
-obj-$(CONFIG_FB_VIRTUAL)          += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -909,7 +909,7 @@ acornfb_mmap(struct fb_info *info, struc
 	 * some updates to the screen occasionally, but process switches
 	 * should cause the caches and buffers to be flushed often enough.
 	 */
-	if (io_remap_page_range(vma, vma->vm_start, off,
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
 				vma->vm_end - vma->vm_start,
 				vma->vm_page_prot))
 		return -EAGAIN;
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -125,28 +125,28 @@ clcdfb_set_bitfields(struct clcd_fb *fb,
 	case 2:
 	case 4:
 	case 8:
-		var->red.length		= 8;
+		var->red.length		= var->bits_per_pixel;
 		var->red.offset		= 0;
-		var->green.length	= 8;
+		var->green.length	= var->bits_per_pixel;
 		var->green.offset	= 0;
-		var->blue.length	= 8;
+		var->blue.length	= var->bits_per_pixel;
 		var->blue.offset	= 0;
 		break;
 	case 16:
 		var->red.length		= 5;
-		var->green.length	= 5;
+		var->green.length	= 6;
 		var->blue.length	= 5;
 		if (fb->panel->cntl & CNTL_BGR) {
-			var->red.offset		= 10;
+			var->red.offset		= 11;
 			var->green.offset	= 5;
 			var->blue.offset	= 0;
 		} else {
 			var->red.offset		= 0;
 			var->green.offset	= 5;
-			var->blue.offset	= 10;
+			var->blue.offset	= 11;
 		}
 		break;
-	case 24:
+	case 32:
 		if (fb->panel->cntl & CNTL_LCDTFT) {
 			var->red.length		= 8;
 			var->green.length	= 8;
@@ -178,6 +178,12 @@ static int clcdfb_check_var(struct fb_va
 
 	if (fb->board->check)
 		ret = fb->board->check(fb, var);
+
+	if (ret == 0 &&
+	    var->xres_virtual * var->bits_per_pixel / 8 *
+	    var->yres_virtual > fb->fb.fix.smem_len)
+		ret = -EINVAL;
+
 	if (ret == 0)
 		ret = clcdfb_set_bitfields(fb, var);
 
@@ -250,7 +256,7 @@ clcdfb_setcolreg(unsigned int regno, uns
 				  convert_bitfield(green, &fb->fb.var.green) |
 				  convert_bitfield(red, &fb->fb.var.red);
 
-	if (fb->fb.var.bits_per_pixel == 8 && regno < 256) {
+	if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
 		int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
 		u32 val, mask, newval;
 
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -3338,7 +3338,7 @@ static int ami_get_var_cursorinfo(struct
 	register short delta;
 	register u_char color;
 	short height, width, bits, words;
-	int i, size, alloc;
+	int size, alloc;
 
 	size = par->crsr.height*par->crsr.width;
 	alloc = var->height*var->width;
@@ -3348,8 +3348,8 @@ static int ami_get_var_cursorinfo(struct
 	var->yspot = par->crsr.spot_y;
 	if (size > var->height*var->width)
 		return -ENAMETOOLONG;
-	if ((i = verify_area(VERIFY_WRITE, (void *)data, size)))
-		return i;
+	if (!access_ok(VERIFY_WRITE, (void *)data, size))
+		return -EFAULT;
 	delta = 1<<par->crsr.fmode;
 	lspr = lofsprite + (delta<<1);
 	if (par->bplcon0 & BPC0_LACE)
@@ -3413,7 +3413,6 @@ static int ami_set_var_cursorinfo(struct
 	register short delta;
 	u_short fmode;
 	short height, width, bits, words;
-	int i;
 
 	if (!var->width)
 		return -EINVAL;
@@ -3429,8 +3428,8 @@ static int ami_set_var_cursorinfo(struct
 		return -EINVAL;
 	if (!var->height)
 		return -EINVAL;
-	if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height)))
-		return i;
+	if (!access_ok(VERIFY_READ, (void *)data, var->width*var->height))
+		return -EFAULT;
 	delta = 1<<fmode;
 	lofsprite = shfsprite = (u_short *)spritememory;
 	lspr = lofsprite + (delta<<1);
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
--- a/drivers/video/asiliantfb.c
+++ b/drivers/video/asiliantfb.c
@@ -46,7 +46,7 @@
 #include <asm/io.h>
 
 /* Built in clock of the 69030 */
-const unsigned Fref = 14318180;
+static const unsigned Fref = 14318180;
 
 #define mmio_base (p->screen_base + 0x400000)
 
@@ -91,11 +91,6 @@ static void mm_write_ar(struct fb_info *
 }
 #define write_ar(num, val)	mm_write_ar(p, num, val)
 
-/*
- * Exported functions
- */
-int asiliantfb_init(void);
-
 static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
 static int asiliantfb_check_var(struct fb_var_screeninfo *var,
 				struct fb_info *info);
@@ -465,7 +460,7 @@ static struct chips_init_reg chips_init_
 	{0xd1, 0x01},
 };
 
-static void __init chips_hw_init(struct fb_info *p)
+static void __devinit chips_hw_init(struct fb_info *p)
 {
 	int i;
 
@@ -488,7 +483,7 @@ static void __init chips_hw_init(struct 
 		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
-static struct fb_fix_screeninfo asiliantfb_fix __initdata = {
+static struct fb_fix_screeninfo asiliantfb_fix __devinitdata = {
 	.id =		"Asiliant 69000",
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_PSEUDOCOLOR,
@@ -497,7 +492,7 @@ static struct fb_fix_screeninfo asiliant
 	.smem_len =	0x200000,	/* 2MB */
 };
 
-static struct fb_var_screeninfo asiliantfb_var __initdata = {
+static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
 	.xres 		= 640,
 	.yres 		= 480,
 	.xres_virtual 	= 640,
@@ -518,7 +513,7 @@ static struct fb_var_screeninfo asiliant
 	.vsync_len 	= 2,
 };
 
-static void __init init_asiliant(struct fb_info *p, unsigned long addr)
+static void __devinit init_asiliant(struct fb_info *p, unsigned long addr)
 {
 	p->fix			= asiliantfb_fix;
 	p->fix.smem_start	= addr;
@@ -604,12 +599,12 @@ static struct pci_driver asiliantfb_driv
 	.remove =	__devexit_p(asiliantfb_remove),
 };
 
-int __init asiliantfb_init(void)
+static int __init asiliantfb_init(void)
 {
 	if (fb_get_options("asiliantfb", NULL))
 		return -ENODEV;
 
-	return pci_module_init(&asiliantfb_driver);
+	return pci_register_driver(&asiliantfb_driver);
 }
 
 module_init(asiliantfb_init);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -166,7 +166,7 @@ static const char *r128_family[] __devin
 static int aty128_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent);
 static void aty128_remove(struct pci_dev *pdev);
-static int aty128_pci_suspend(struct pci_dev *pdev, u32 state);
+static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state);
 static int aty128_pci_resume(struct pci_dev *pdev);
 static int aty128_do_resume(struct pci_dev *pdev);
 
@@ -425,11 +425,6 @@ struct aty128fb_par {
 
 #define round_div(n, d) ((n+(d/2))/d)
 
-    /*
-     *  Interface used by the world
-     */
-int aty128fb_init(void);
-
 static int aty128fb_check_var(struct fb_var_screeninfo *var,
 			      struct fb_info *info);
 static int aty128fb_set_par(struct fb_info *info);
@@ -1648,7 +1643,8 @@ static int aty128fb_sync(struct fb_info 
 	return 0;
 }
 
-int __init aty128fb_setup(char *options)
+#ifndef MODULE
+static int __init aty128fb_setup(char *options)
 {
 	char *this_opt;
 
@@ -1701,6 +1697,7 @@ int __init aty128fb_setup(char *options)
 	}
 	return 0;
 }
+#endif  /*  MODULE  */
 
 
 /*
@@ -2330,7 +2327,7 @@ static void aty128_set_suspend(struct at
 	}
 }
 
-static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
+static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct aty128fb_par *par = info->par;
@@ -2371,6 +2368,14 @@ static int aty128_pci_suspend(struct pci
 	par->asleep = 1;
 	par->lock_blank = 1;
 
+#ifdef CONFIG_PPC_PMAC
+	/* On powermac, we have hooks to properly suspend/resume AGP now,
+	 * use them here. We'll ultimately need some generic support here,
+	 * but the generic code isn't quite ready for that yet
+	 */
+	pmac_suspend_agp_for_card(pdev);
+#endif /* CONFIG_PPC_PMAC */
+
 	/* We need a way to make sure the fbdev layer will _not_ touch the
 	 * framebuffer before we put the chip to suspend state. On 2.4, I
 	 * used dummy fb ops, 2.5 need proper support for this at the
@@ -2413,7 +2418,15 @@ static int aty128_do_resume(struct pci_d
 	par->lock_blank = 0;
 	aty128fb_blank(0, info);
 
-	pdev->dev.power.power_state = 0;
+#ifdef CONFIG_PPC_PMAC
+	/* On powermac, we have hooks to properly suspend/resume AGP now,
+	 * use them here. We'll ultimately need some generic support here,
+	 * but the generic code isn't quite ready for that yet
+	 */
+	pmac_resume_agp_for_card(pdev);
+#endif /* CONFIG_PPC_PMAC */
+
+	pdev->dev.power.power_state = PMSG_ON;
 
 	printk(KERN_DEBUG "aty128fb: resumed !\n");
 
@@ -2432,7 +2445,7 @@ static int aty128_pci_resume(struct pci_
 }
 
 
-int __init aty128fb_init(void)
+static int __init aty128fb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -2442,7 +2455,7 @@ int __init aty128fb_init(void)
 	aty128fb_setup(option);
 #endif
 
-	return pci_module_init(&aty128fb_driver);
+	return pci_register_driver(&aty128fb_driver);
 }
 
 static void __exit aty128fb_exit(void)
@@ -2452,7 +2465,6 @@ static void __exit aty128fb_exit(void)
 
 module_init(aty128fb_init);
 
-#ifdef MODULE
 module_exit(aty128fb_exit);
 
 MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
@@ -2464,5 +2476,4 @@ MODULE_PARM_DESC(mode_option, "Specify r
 module_param_named(nomtrr, mtrr, invbool, 0);
 MODULE_PARM_DESC(nomtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
 #endif
-#endif
 
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -334,7 +334,6 @@ extern u8 aty_ld_pll_ct(int offset, cons
      */
 
 extern int aty_init_cursor(struct fb_info *info);
-extern int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor);
 
     /*
      *  Hardware acceleration
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -100,8 +100,8 @@
 /*
  * Debug flags.
  */
-/*#undef DEBUG*/
-#define DEBUG
+#undef DEBUG
+/*#define DEBUG*/
 
 /* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
 /*  - must be large enough to catch all GUI-Regs   */
@@ -209,7 +209,7 @@ struct pci_mmap_map {
 	unsigned long prot_mask;
 };
 
-static struct fb_fix_screeninfo atyfb_fix __initdata = {
+static struct fb_fix_screeninfo atyfb_fix __devinitdata = {
 	.id		= "ATY Mach64",
 	.type		= FB_TYPE_PACKED_PIXELS,
 	.visual		= FB_VISUAL_PSEUDOCOLOR,
@@ -265,7 +265,7 @@ static int read_aty_sense(const struct a
      *  Interface used by the world
      */
 
-struct fb_var_screeninfo default_var = {
+static struct fb_var_screeninfo default_var = {
 	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
 	640, 480, 640, 480, 0, 0, 8, 0,
 	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -307,6 +307,7 @@ static int vram;
 static int pll;
 static int mclk;
 static int xclk;
+static int comp_sync __initdata = -1;
 static char *mode;
 
 #ifdef CONFIG_PPC
@@ -361,7 +362,7 @@ static struct {
 	const char *name;
 	int pll, mclk, xclk;
 	u32 features;
-} aty_chips[] __initdata = {
+} aty_chips[] __devinitdata = {
 #ifdef CONFIG_FB_ATY_GX
 	/* Mach64 GX */
 	{ PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, ATI_CHIP_88800GX },
@@ -492,31 +493,31 @@ static int __devinit correct_chipset(str
 	return 0;
 }
 
-static char ram_dram[] __initdata = "DRAM";
-static char ram_resv[] __initdata = "RESV";
+static char ram_dram[] __devinitdata = "DRAM";
+static char ram_resv[] __devinitdata = "RESV";
 #ifdef CONFIG_FB_ATY_GX
-static char ram_vram[] __initdata = "VRAM";
+static char ram_vram[] __devinitdata = "VRAM";
 #endif /* CONFIG_FB_ATY_GX */
 #ifdef CONFIG_FB_ATY_CT
-static char ram_edo[] __initdata = "EDO";
-static char ram_sdram[] __initdata = "SDRAM (1:1)";
-static char ram_sgram[] __initdata = "SGRAM (1:1)";
-static char ram_sdram32[] __initdata = "SDRAM (2:1) (32-bit)";
-static char ram_off[] __initdata = "OFF";
+static char ram_edo[] __devinitdata = "EDO";
+static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
+static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
+static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
+static char ram_off[] __devinitdata = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
 
 static u32 pseudo_palette[17];
 
 #ifdef CONFIG_FB_ATY_GX
-static char *aty_gx_ram[8] __initdata = {
+static char *aty_gx_ram[8] __devinitdata = {
 	ram_dram, ram_vram, ram_vram, ram_dram,
 	ram_dram, ram_vram, ram_vram, ram_resv
 };
 #endif /* CONFIG_FB_ATY_GX */
 
 #ifdef CONFIG_FB_ATY_CT
-static char *aty_ct_ram[8] __initdata = {
+static char *aty_ct_ram[8] __devinitdata = {
 	ram_off, ram_dram, ram_edo, ram_edo,
 	ram_sdram, ram_sgram, ram_sdram32, ram_resv
 };
@@ -2016,7 +2017,7 @@ static int aty_power_mgmt(int sleep, str
 	return timeout ? 0 : -EIO;
 }
 
-static int atyfb_pci_suspend(struct pci_dev *pdev, u32 state)
+static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -2091,7 +2092,7 @@ static int atyfb_pci_resume(struct pci_d
 
 	release_console_sem();
 
-	pdev->dev.power.power_state = 0;
+	pdev->dev.power.power_state = PMSG_ON;
 
 	return 0;
 }
@@ -2527,6 +2528,13 @@ static int __init aty_init(struct fb_inf
 	else
 		var.accel_flags |= FB_ACCELF_TEXT;
 
+	if (comp_sync != -1) {
+		if (!comp_sync)
+			var.sync &= ~FB_SYNC_COMP_HIGH_ACT;
+		else
+			var.sync |= FB_SYNC_COMP_HIGH_ACT;
+	}
+
 	if (var.yres == var.yres_virtual) {
 		u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
 		var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
@@ -2990,7 +2998,7 @@ static int __devinit atyfb_setup_sparc(s
 
 #ifdef __i386__
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
 {
 	u32 driv_inf_tab, sig;
 	u16 lcd_ofs;
@@ -3427,8 +3435,7 @@ static int __devinit atyfb_pci_probe(str
 
 err_release_io:
 #ifdef __sparc__
-	if (par->mmap_map)
-		kfree(par->mmap_map);
+	kfree(par->mmap_map);
 #else
 	if (par->ati_regbase)
 		iounmap(par->ati_regbase);
@@ -3436,7 +3443,7 @@ err_release_io:
 		iounmap(info->screen_base);
 #endif
 err_release_mem:
-	if(par->aux_start)
+	if (par->aux_start)
 		release_mem_region(par->aux_start, par->aux_size);
 
 	release_mem_region(par->res_start, par->res_size);
@@ -3543,8 +3550,7 @@ static void __devexit atyfb_remove(struc
 #endif
 #endif
 #ifdef __sparc__
-	if (par->mmap_map)
-		kfree(par->mmap_map);
+	kfree(par->mmap_map);
 #endif
 	if (par->aux_start)
 		release_mem_region(par->aux_start, par->aux_size);
@@ -3589,7 +3595,8 @@ static struct pci_driver atyfb_driver = 
 
 #endif /* CONFIG_PCI */
 
-int __init atyfb_setup(char *options)
+#ifndef MODULE
+static int __init atyfb_setup(char *options)
 {
 	char *this_opt;
 
@@ -3611,6 +3618,8 @@ int __init atyfb_setup(char *options)
 			mclk = simple_strtoul(this_opt + 5, NULL, 0);
 		else if (!strncmp(this_opt, "xclk:", 5))
 			xclk = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "comp_sync:", 10))
+			comp_sync = simple_strtoul(this_opt+10, NULL, 0);
 #ifdef CONFIG_PPC
 		else if (!strncmp(this_opt, "vmode:", 6)) {
 			unsigned int vmode =
@@ -3657,8 +3666,9 @@ int __init atyfb_setup(char *options)
 	}
 	return 0;
 }
+#endif  /*  MODULE  */
 
-int __init atyfb_init(void)
+static int __init atyfb_init(void)
 {
 #ifndef MODULE
     char *option = NULL;
@@ -3669,7 +3679,7 @@ int __init atyfb_init(void)
 #endif
 
 #ifdef CONFIG_PCI
-    pci_module_init(&atyfb_driver);
+    pci_register_driver(&atyfb_driver);
 #endif
 #ifdef CONFIG_ATARI
     atyfb_atari_probe();
@@ -3677,7 +3687,7 @@ int __init atyfb_init(void)
     return 0;
 }
 
-void __exit atyfb_exit(void)
+static void __exit atyfb_exit(void)
 {
 #ifdef CONFIG_PCI
 	pci_unregister_driver(&atyfb_driver);
@@ -3685,9 +3695,7 @@ void __exit atyfb_exit(void)
 }
 
 module_init(atyfb_init);
-#ifdef MODULE
 module_exit(atyfb_exit);
-#endif
 
 MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");
 MODULE_LICENSE("GPL");
@@ -3701,6 +3709,9 @@ module_param(mclk, int, 0);
 MODULE_PARM_DESC(mclk, "int: override memory clock");
 module_param(xclk, int, 0);
 MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");
+module_param(comp_sync, int, 0);
+MODULE_PARM_DESC(comp_sync,
+		 "Set composite sync signal to low (0) or high (1)");
 module_param(mode, charp, 0);
 MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
 #ifdef CONFIG_MTRR
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -359,7 +359,8 @@ void aty_set_pll_ct(const struct fb_info
 #endif
 }
 
-void __init aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
+static void __init aty_get_pll_ct(const struct fb_info *info,
+				  union aty_pll *pll)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u8 tmp, clock;
@@ -382,7 +383,9 @@ void __init aty_get_pll_ct(const struct 
 	}
 }
 
-int __init aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll) {
+static int __init aty_init_pll_ct(const struct fb_info *info,
+				 union aty_pll *pll)
+{
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
 	u32 q, i, memcntl, trp;
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -71,7 +71,7 @@ static const u8 cursor_mask_lookup[16] =
 	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
 };
 
-int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u16 xoff, yoff;
diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
--- a/drivers/video/aty/radeon_accel.c
+++ b/drivers/video/aty/radeon_accel.c
@@ -189,32 +189,6 @@ void radeonfb_engine_reset(struct radeon
 
 	radeon_engine_flush (rinfo);
 
-    	/* Some ASICs have bugs with dynamic-on feature, which are  
-     	 * ASIC-version dependent, so we force all blocks on for now
-     	 * -- from XFree86
-     	 * We don't do that on macs, things just work here with dynamic
-     	 * clocking... --BenH
-	 */
-#ifdef CONFIG_ALL_PPC
-	if (_machine != _MACH_Pmac && rinfo->hasCRTC2)
-#else
-	if (rinfo->has_CRTC2)
-#endif	
-	{
-		u32 tmp;
-
-		tmp = INPLL(SCLK_CNTL);
-		OUTPLL(SCLK_CNTL, ((tmp & ~DYN_STOP_LAT_MASK) |
-				   CP_MAX_DYN_STOP_LAT |
-				   SCLK_FORCEON_MASK));
-
-		if (rinfo->family == CHIP_FAMILY_RV200)
-		{
-			tmp = INPLL(SCLK_MORE_CNTL);
-			OUTPLL(SCLK_MORE_CNTL, tmp | SCLK_MORE_FORCEON);
-		}
-	}
-
 	clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
 	mclk_cntl = INPLL(MCLK_CNTL);
 
@@ -274,8 +248,6 @@ void radeonfb_engine_reset(struct radeon
 
 	OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
 	OUTPLL(MCLK_CNTL, mclk_cntl);
-	if (rinfo->R300_cg_workaround)
-		R300_cg_workardound(rinfo);
 }
 
 void radeonfb_engine_init (struct radeonfb_info *rinfo)
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -1,4 +1,3 @@
-
 /*
  *	drivers/video/aty/radeon_base.c
  *
@@ -531,6 +530,7 @@ static int __devinit radeon_probe_pll_pa
 	}
 
 	ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
+	radeon_pll_errata_after_index(rinfo);
 
 	n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
 	m = (INPLL(PPLL_REF_DIV) & 0x3ff);
@@ -913,7 +913,7 @@ static int radeonfb_ioctl (struct inode 
 
 			OUTREG(CRTC_EXT_CNTL, tmp);
 
-			break;
+			return 0;
 		case FBIO_RADEON_GET_MIRROR:
 			if (!rinfo->is_mobility)
 				return -EINVAL;
@@ -1057,13 +1057,14 @@ static int radeonfb_blank (int blank, st
 	return radeon_screen_blank(rinfo, blank, 0);
 }
 
-static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp, struct fb_info *info)
+static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
+                             unsigned blue, unsigned transp,
+			     struct radeonfb_info *rinfo)
 {
-        struct radeonfb_info *rinfo = info->par;
 	u32 pindex;
 	unsigned int i;
-	
+
+
 	if (regno > 255)
 		return 1;
 
@@ -1078,20 +1079,7 @@ static int radeonfb_setcolreg (unsigned 
         pindex = regno;
 
         if (!rinfo->asleep) {
-        	u32 dac_cntl2, vclk_cntl = 0;
-        	
 		radeon_fifo_wait(9);
-		if (rinfo->is_mobility) {
-			vclk_cntl = INPLL(VCLK_ECP_CNTL);
-			OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
-		}
-
-		/* Make sure we are on first palette */
-		if (rinfo->has_CRTC2) {
-			dac_cntl2 = INREG(DAC_CNTL2);
-			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
-			OUTREG(DAC_CNTL2, dac_cntl2);
-		}
 
 		if (rinfo->bpp == 16) {
 			pindex = regno * 8;
@@ -1101,24 +1089,27 @@ static int radeonfb_setcolreg (unsigned 
 			if (rinfo->depth == 15 && regno > 31)
 				return 1;
 
-			/* For 565, the green component is mixed one order below */
+			/* For 565, the green component is mixed one order
+			 * below
+			 */
 			if (rinfo->depth == 16) {
 		                OUTREG(PALETTE_INDEX, pindex>>1);
-	       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
-	                        	(green << 8) | (rinfo->palette[regno>>1].blue));
+	       	         	OUTREG(PALETTE_DATA,
+				       (rinfo->palette[regno>>1].red << 16) |
+	                        	(green << 8) |
+				       (rinfo->palette[regno>>1].blue));
 	                	green = rinfo->palette[regno<<1].green;
 	        	}
 		}
 
 		if (rinfo->depth != 16 || regno < 32) {
 			OUTREG(PALETTE_INDEX, pindex);
-			OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+			OUTREG(PALETTE_DATA, (red << 16) |
+			       (green << 8) | blue);
 		}
-		if (rinfo->is_mobility)
-			OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
 	}
  	if (regno < 16) {
-		u32 *pal = info->pseudo_palette;
+		u32 *pal = rinfo->info->pseudo_palette;
         	switch (rinfo->depth) {
 		case 15:
 			pal[regno] = (regno << 10) | (regno << 5) | regno;
@@ -1138,8 +1129,87 @@ static int radeonfb_setcolreg (unsigned 
 	return 0;
 }
 
+static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+			       unsigned blue, unsigned transp,
+			       struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+	u32 dac_cntl2, vclk_cntl = 0;
+	int rc;
+
+        if (!rinfo->asleep) {
+		if (rinfo->is_mobility) {
+			vclk_cntl = INPLL(VCLK_ECP_CNTL);
+			OUTPLL(VCLK_ECP_CNTL,
+			       vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+		}
+
+		/* Make sure we are on first palette */
+		if (rinfo->has_CRTC2) {
+			dac_cntl2 = INREG(DAC_CNTL2);
+			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+			OUTREG(DAC_CNTL2, dac_cntl2);
+		}
+	}
+
+	rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo);
+
+	if (!rinfo->asleep && rinfo->is_mobility)
+		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+
+	return rc;
+}
+
+static int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+	u16 *red, *green, *blue, *transp;
+	u32 dac_cntl2, vclk_cntl = 0;
+	int i, start, rc = 0;
+
+        if (!rinfo->asleep) {
+		if (rinfo->is_mobility) {
+			vclk_cntl = INPLL(VCLK_ECP_CNTL);
+			OUTPLL(VCLK_ECP_CNTL,
+			       vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+		}
+
+		/* Make sure we are on first palette */
+		if (rinfo->has_CRTC2) {
+			dac_cntl2 = INREG(DAC_CNTL2);
+			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+			OUTREG(DAC_CNTL2, dac_cntl2);
+		}
+	}
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	for (i = 0; i < cmap->len; i++) {
+		u_int hred, hgreen, hblue, htransp = 0xffff;
+
+		hred = *red++;
+		hgreen = *green++;
+		hblue = *blue++;
+		if (transp)
+			htransp = *transp++;
+		rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp,
+				       rinfo);
+		if (rc)
+			break;
+	}
+
+	if (!rinfo->asleep && rinfo->is_mobility)
+		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+
+	return rc;
+}
 
-void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save)
+static void radeon_save_state (struct radeonfb_info *rinfo,
+			       struct radeon_regs *save)
 {
 	/* CRTC regs */
 	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
@@ -1169,6 +1239,7 @@ void radeon_save_state (struct radeonfb_
 
 	/* PLL regs */
 	save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f;
+	radeon_pll_errata_after_index(rinfo);
 	save->ppll_div_3 = INPLL(PPLL_DIV_3);
 	save->ppll_ref_div = INPLL(PPLL_REF_DIV);
 }
@@ -1198,6 +1269,8 @@ static void radeon_write_pll_regs(struct
 			OUTREGP(CLOCK_CNTL_INDEX,
 				mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
 				~PPLL_DIV_SEL_MASK);
+			radeon_pll_errata_after_index(rinfo);
+			radeon_pll_errata_after_data(rinfo);
             		return;
 		}
 	}
@@ -1214,6 +1287,8 @@ static void radeon_write_pll_regs(struct
 	OUTREGP(CLOCK_CNTL_INDEX,
 		mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
 		~PPLL_DIV_SEL_MASK);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
 
 	/* Set PPLL ref. div */
 	if (rinfo->family == CHIP_FAMILY_R300 ||
@@ -1737,8 +1812,7 @@ static int radeonfb_set_par(struct fb_in
 		} else {
 			/* DFP */
 			newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
-			newmode->tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) &
-							 ~(TMDS_PLLRST);
+			newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST);
 			/* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
 			if (IS_R300_VARIANT(rinfo) ||
 			    (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2)
@@ -1791,6 +1865,7 @@ static struct fb_ops radeonfb_ops = {
 	.fb_check_var		= radeonfb_check_var,
 	.fb_set_par		= radeonfb_set_par,
 	.fb_setcolreg		= radeonfb_setcolreg,
+	.fb_setcmap		= radeonfb_setcmap,
 	.fb_pan_display 	= radeonfb_pan_display,
 	.fb_blank		= radeonfb_blank,
 	.fb_ioctl		= radeonfb_ioctl,
@@ -2231,7 +2306,7 @@ static int radeonfb_pci_register (struct
 	rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0;
 	rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0;
 	rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0;
-		
+
 	/* Set base addrs */
 	rinfo->fb_base_phys = pci_resource_start (pdev, 0);
 	rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
@@ -2254,6 +2329,24 @@ static int radeonfb_pci_register (struct
 
 	rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
 
+	/*
+	 * Check for errata
+	 */
+	rinfo->errata = 0;
+	if (rinfo->family == CHIP_FAMILY_R300 &&
+	    (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK)
+	    == CFG_ATI_REV_A11)
+		rinfo->errata |= CHIP_ERRATA_R300_CG;
+
+	if (rinfo->family == CHIP_FAMILY_RV200 ||
+	    rinfo->family == CHIP_FAMILY_RS200)
+		rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS;
+
+	if (rinfo->family == CHIP_FAMILY_RV100 ||
+	    rinfo->family == CHIP_FAMILY_RS100 ||
+	    rinfo->family == CHIP_FAMILY_RS200)
+		rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
+
 #ifdef CONFIG_PPC_OF
 	/* On PPC, we obtain the OF device-node pointer to the firmware
 	 * data for this chip
@@ -2281,10 +2374,9 @@ static int radeonfb_pci_register (struct
 	} while (   rinfo->fb_base == 0 &&
 		  ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) );
 
-	if (rinfo->fb_base)
-		memset_io(rinfo->fb_base, 0, rinfo->mapped_vram);
-	else {
-		printk (KERN_ERR "radeonfb (%s): cannot map FB\n", pci_name(rinfo->pdev));
+	if (rinfo->fb_base == NULL) {
+		printk (KERN_ERR "radeonfb (%s): cannot map FB\n",
+			pci_name(rinfo->pdev));
 		ret = -EIO;
 		goto err_unmap_rom;
 	}
@@ -2293,13 +2385,6 @@ static int radeonfb_pci_register (struct
 	       rinfo->mapped_vram/1024);
 
 	/*
-	 * Check for required workaround for PLL accesses
-	 */
-	rinfo->R300_cg_workaround = (rinfo->family == CHIP_FAMILY_R300 &&
-				     (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK)
-				     == CFG_ATI_REV_A11);
-
-	/*
 	 * Map the BIOS ROM if any and retreive PLL parameters from
 	 * the BIOS. We skip that on mobility chips as the real panel
 	 * values we need aren't in the ROM but in the BIOS image in
@@ -2359,6 +2444,15 @@ static int radeonfb_pci_register (struct
 	radeon_save_state (rinfo, &rinfo->init_state);
 	memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs));
 
+	/* Setup Power Management capabilities */
+	if (default_dynclk < -1) {
+		/* -2 is special: means  ON on mobility chips and do not
+		 * change on others
+		 */
+		radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+	} else
+		radeonfb_pm_init(rinfo, default_dynclk);
+
 	pci_set_drvdata(pdev, info);
 
 	/* Register with fbdev layer */
@@ -2369,13 +2463,6 @@ static int radeonfb_pci_register (struct
 		goto err_unmap_fb;
 	}
 
-	/* Setup Power Management capabilities */
-	if (default_dynclk < -1) {
-		/* -2 is special: means  ON on mobility chips and do not change on others */
-		radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
-	} else
-		radeonfb_pm_init(rinfo, default_dynclk);
-
 #ifdef CONFIG_MTRR
 	rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys,
 						 rinfo->video_ram,
@@ -2401,10 +2488,8 @@ static int radeonfb_pci_register (struct
 err_unmap_fb:
 	iounmap(rinfo->fb_base);
 err_unmap_rom:
-	if (rinfo->mon1_EDID)
-	    kfree(rinfo->mon1_EDID);
-	if (rinfo->mon2_EDID)
-	    kfree(rinfo->mon2_EDID);
+	kfree(rinfo->mon1_EDID);
+	kfree(rinfo->mon2_EDID);
 	if (rinfo->mon1_modedb)
 		fb_destroy_modedb(rinfo->mon1_modedb);
 	fb_dealloc_cmap(&info->cmap);
@@ -2460,10 +2545,8 @@ static void __devexit radeonfb_pci_unreg
  
  	pci_release_regions(pdev);
 
-	if (rinfo->mon1_EDID)
-		kfree(rinfo->mon1_EDID);
-	if (rinfo->mon2_EDID)
-		kfree(rinfo->mon2_EDID);
+	kfree(rinfo->mon1_EDID);
+	kfree(rinfo->mon2_EDID);
 	if (rinfo->mon1_modedb)
 		fb_destroy_modedb(rinfo->mon1_modedb);
 #ifdef CONFIG_FB_RADEON_I2C
@@ -2486,27 +2569,8 @@ static struct pci_driver radeonfb_driver
 #endif /* CONFIG_PM */
 };
 
-int __init radeonfb_setup (char *options);
-
-int __init radeonfb_init (void)
-{
 #ifndef MODULE
-	char *option = NULL;
-
-	if (fb_get_options("radeonfb", &option))
-		return -ENODEV;
-	radeonfb_setup(option);
-#endif
-	return pci_module_init (&radeonfb_driver);
-}
-
-
-void __exit radeonfb_exit (void)
-{
-	pci_unregister_driver (&radeonfb_driver);
-}
-
-int __init radeonfb_setup (char *options)
+static int __init radeonfb_setup (char *options)
 {
 	char *this_opt;
 
@@ -2540,12 +2604,28 @@ int __init radeonfb_setup (char *options
 	}
 	return 0;
 }
+#endif  /*  MODULE  */
 
-module_init(radeonfb_init);
+static int __init radeonfb_init (void)
+{
+#ifndef MODULE
+	char *option = NULL;
 
-#ifdef MODULE
-module_exit(radeonfb_exit);
+	if (fb_get_options("radeonfb", &option))
+		return -ENODEV;
+	radeonfb_setup(option);
 #endif
+	return pci_register_driver (&radeonfb_driver);
+}
+
+
+static void __exit radeonfb_exit (void)
+{
+	pci_unregister_driver (&radeonfb_driver);
+}
+
+module_init(radeonfb_init);
+module_exit(radeonfb_exit);
 
 MODULE_AUTHOR("Ani Joshi");
 MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -236,6 +236,12 @@ int radeon_probe_i2c_connector(struct ra
 		if (edid)
 			break;
 	}
+	/* Release the DDC lines when done or the Apple Cinema HD display
+	 * will switch off
+	 */
+	OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN));
+	(void)INREG(reg);
+
 	if (out_edid)
 		*out_edid = edid;
 	if (!edid) {
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -618,11 +618,9 @@ void __devinit radeon_probe_screens(stru
 		}
 	}
 	if (ignore_edid) {
-		if (rinfo->mon1_EDID)
-			kfree(rinfo->mon1_EDID);
+		kfree(rinfo->mon1_EDID);
 		rinfo->mon1_EDID = NULL;
-		if (rinfo->mon2_EDID)
-			kfree(rinfo->mon2_EDID);
+		kfree(rinfo->mon2_EDID);
 		rinfo->mon2_EDID = NULL;
 	}
 
@@ -655,8 +653,11 @@ static void radeon_fixup_panel_info(stru
 	 */
 	if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD
 	    && rinfo->is_mobility) {
-		int ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
-		u32 ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel);
+		int ppll_div_sel;
+		u32 ppll_divn;
+		ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
+		radeon_pll_errata_after_index(rinfo);
+		ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel);
 		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
 		rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff;
 		rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7;
@@ -900,7 +901,7 @@ void __devinit radeon_check_modes(struct
  */
 
 /*
- * This is used when looking for modes. We assign a "goodness" value
+ * This is used when looking for modes. We assign a "distance" value
  * to a mode in the modedb depending how "close" it is from what we
  * are looking for.
  * Currently, we don't compare that much, we could do better but
@@ -909,13 +910,11 @@ void __devinit radeon_check_modes(struct
 static int radeon_compare_modes(const struct fb_var_screeninfo *var,
 				const struct fb_videomode *mode)
 {
-	int goodness = 0;
+	int distance = 0;
 
-	if (var->yres == mode->yres)
-		goodness += 10;
-	if (var->xres == mode->xres)
-		goodness += 9;
-	return goodness;
+	distance = mode->yres - var->yres;
+	distance += (mode->xres - var->xres)/2;
+	return distance;
 }
 
 /*
@@ -937,7 +936,7 @@ int  radeon_match_mode(struct radeonfb_i
 	const struct fb_videomode	*db = vesa_modes;
 	int				i, dbsize = 34;
 	int				has_rmx, native_db = 0;
-	int				goodness = 0;
+	int				distance = INT_MAX;
 	const struct fb_videomode	*candidate = NULL;
 
 	/* Start with a copy of the requested mode */
@@ -973,19 +972,19 @@ int  radeon_match_mode(struct radeonfb_i
 	/* Now look for a mode in the database */
 	while (db) {
 		for (i = 0; i < dbsize; i++) {
-			int g;
+			int d;
 
 			if (db[i].yres < src->yres)
 				continue;	
 			if (db[i].xres < src->xres)
 				continue;
-			g = radeon_compare_modes(src, &db[i]);
+			d = radeon_compare_modes(src, &db[i]);
 			/* If the new mode is at least as good as the previous one,
 			 * then it's our new candidate
 			 */
-			if (g >= goodness) {
+			if (d < distance) {
 				candidate = &db[i];
-				goodness = g;
+				distance = d;
 			}
 		}
 		db = NULL;
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -27,7 +27,7 @@
 
 #include "ati_ids.h"
 
-void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
+static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
 {
 	u32 tmp;
 
@@ -229,7 +229,7 @@ void radeon_pm_disable_dynamic_mode(stru
 	radeon_msleep(16);
 }
 
-void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
+static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
 {
 	u32 tmp;
 
@@ -1373,7 +1373,9 @@ static void radeon_pm_start_mclk_sclk(st
 	/* Reconfigure SPLL charge pump, VCO gain, duty cycle */
 	tmp = INPLL(pllSPLL_CNTL);
 	OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
 
 	/* Set SPLL feedback divider */
 	tmp = INPLL(pllM_SPLL_REF_FB_DIV);
@@ -1406,7 +1408,9 @@ static void radeon_pm_start_mclk_sclk(st
 	/* Reconfigure MPLL charge pump, VCO gain, duty cycle */
 	tmp = INPLL(pllMPLL_CNTL);
 	OUTREG8(CLOCK_CNTL_INDEX, pllMPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
 
 	/* Set MPLL feedback divider */
 	tmp = INPLL(pllM_SPLL_REF_FB_DIV);
@@ -1525,7 +1529,9 @@ static void radeon_pm_restore_pixel_pll(
 	u32 tmp;
 
 	OUTREG8(CLOCK_CNTL_INDEX, pllHTOTAL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA, 0);
+	radeon_pll_errata_after_data(rinfo);
 
 	tmp = INPLL(pllVCLK_ECP_CNTL);
 	OUTPLL(pllVCLK_ECP_CNTL, tmp | 0x80);
@@ -1541,11 +1547,9 @@ static void radeon_pm_restore_pixel_pll(
 	 */
 	tmp = INPLL(pllPPLL_CNTL);
 	OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
-
-	/* Not sure what was intended here ... */
-	tmp = INREG(CLOCK_CNTL_INDEX);
-	OUTREG(CLOCK_CNTL_INDEX, tmp);
+	radeon_pll_errata_after_data(rinfo);
 
 	/* Restore our "reference" PPLL divider set by firmware
 	 * according to proper spread spectrum calculations
@@ -1570,6 +1574,8 @@ static void radeon_pm_restore_pixel_pll(
 
 	/* Switch pixel clock to firmware default div 0 */
 	OUTREG8(CLOCK_CNTL_INDEX+1, 0);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
 }
 
 static void radeon_pm_m10_reconfigure_mc(struct radeonfb_info *rinfo)
@@ -2157,7 +2163,9 @@ static void radeon_reinitialize_QW(struc
 
 	tmp = INPLL(MPLL_CNTL);
 	OUTREG8(CLOCK_CNTL_INDEX, MPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
 
 	tmp = INPLL(M_SPLL_REF_FB_DIV);
 	OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x5900);
@@ -2178,7 +2186,9 @@ static void radeon_reinitialize_QW(struc
 
 	tmp = INPLL(SPLL_CNTL);
 	OUTREG8(CLOCK_CNTL_INDEX, SPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
 
 	tmp = INPLL(M_SPLL_REF_FB_DIV);
 	OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x780000);
@@ -2306,7 +2316,9 @@ static void radeon_reinitialize_QW(struc
 	OUTREG(CRTC_H_SYNC_STRT_WID, 0x008e0580);
 	OUTREG(CRTC_H_TOTAL_DISP, 0x009f00d2);
 	OUTREG8(CLOCK_CNTL_INDEX, HTOTAL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA, 0);
+	radeon_pll_errata_after_data(rinfo);
 	OUTREG(CRTC_V_SYNC_STRT_WID, 0x00830403);
 	OUTREG(CRTC_V_TOTAL_DISP, 0x03ff0429);
 	OUTREG(FP_CRTC_H_TOTAL_DISP, 0x009f0033);
@@ -2328,10 +2340,15 @@ static void radeon_reinitialize_QW(struc
 	INPLL(PPLL_REF_DIV);
 
 	OUTREG8(CLOCK_CNTL_INDEX, PPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG8(CLOCK_CNTL_DATA + 1, 0xbc);
+	radeon_pll_errata_after_data(rinfo);
 
 	tmp = INREG(CLOCK_CNTL_INDEX);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG(CLOCK_CNTL_INDEX, tmp & 0xff);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
 
 	OUTPLL(PPLL_DIV_0, 0x48090);
 
@@ -2400,7 +2417,8 @@ static void radeon_set_suspend(struct ra
 	 * including PCI config registers, clocks, AGP conf, ...)
 	 */
 	if (suspend) {
-		printk(KERN_DEBUG "radeonfb: switching to D2 state...\n");
+		printk(KERN_DEBUG "radeonfb (%s): switching to D2 state...\n",
+		       pci_name(rinfo->pdev));
 
 		/* Disable dynamic power management of clocks for the
 		 * duration of the suspend/resume process
@@ -2453,7 +2471,8 @@ static void radeon_set_suspend(struct ra
 			mdelay(500);
 		}
 	} else {
-		printk(KERN_DEBUG "radeonfb: switching to D0 state...\n");
+		printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
+		       pci_name(rinfo->pdev));
 
 		/* Switch back PCI powermanagment to D0 */
 		mdelay(200);
@@ -2501,9 +2520,7 @@ static int radeon_restore_pci_cfg(struct
 }
 
 
-static/*extern*/ int susdisking = 0;
-
-int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state)
+int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
@@ -2522,10 +2539,6 @@ int radeonfb_pci_suspend(struct pci_dev 
 	 */
 	if (state != PM_SUSPEND_MEM)
 		goto done;
-	if (susdisking) {
-		printk("suspending to disk but state = %d\n", state);
-		goto done;
-	}
 
 	acquire_console_sem();
 
@@ -2546,6 +2559,14 @@ int radeonfb_pci_suspend(struct pci_dev 
 	rinfo->lock_blank = 1;
 	del_timer_sync(&rinfo->lvds_timer);
 
+#ifdef CONFIG_PPC_PMAC
+	/* On powermac, we have hooks to properly suspend/resume AGP now,
+	 * use them here. We'll ultimately need some generic support here,
+	 * but the generic code isn't quite ready for that yet
+	 */
+	pmac_suspend_agp_for_card(pdev);
+#endif /* CONFIG_PPC_PMAC */
+
 	/* If we support wakeup from poweroff, we save all regs we can including cfg
 	 * space
 	 */
@@ -2569,12 +2590,11 @@ int radeonfb_pci_suspend(struct pci_dev 
 			OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000);
 			mdelay(20);
 			OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
-
-			// FIXME: Use PCI layer
-			for (i = 0; i < 64; ++i)
-				pci_read_config_dword(rinfo->pdev, i * 4,
-						      &rinfo->cfg_save[i]);
 		}
+		// FIXME: Use PCI layer
+		for (i = 0; i < 64; ++i)
+			pci_read_config_dword(pdev, i * 4, &rinfo->cfg_save[i]);
+		pci_disable_device(pdev);
 	}
 	/* If we support D2, we go to it (should be fixed later with a flag forcing
 	 * D3 only for some laptops)
@@ -2657,13 +2677,22 @@ int radeonfb_pci_resume(struct pci_dev *
 	rinfo->lock_blank = 0;
 	radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1);
 
+#ifdef CONFIG_PPC_PMAC
+	/* On powermac, we have hooks to properly suspend/resume AGP now,
+	 * use them here. We'll ultimately need some generic support here,
+	 * but the generic code isn't quite ready for that yet
+	 */
+	pmac_resume_agp_for_card(pdev);
+#endif /* CONFIG_PPC_PMAC */
+
+
 	/* Check status of dynclk */
 	if (rinfo->dynclk == 1)
 		radeon_pm_enable_dynamic_mode(rinfo);
 	else if (rinfo->dynclk == 0)
 		radeon_pm_disable_dynamic_mode(rinfo);
 
-	pdev->dev.power.power_state = 0;
+	pdev->dev.power.power_state = PMSG_ON;
 
  bail:
 	release_console_sem();
@@ -2727,8 +2756,6 @@ void radeonfb_pm_init(struct radeonfb_in
 		if (!strcmp(rinfo->of_node->name, "ATY,ViaParent")) {
 			rinfo->reinit_func = radeon_reinitialize_M9P;
 			rinfo->pm_mode |= radeon_pm_off;
-			/* Workaround not used for now */
-			rinfo->m9p_workaround = 1;
 		}
 
 		/* If any of the above is set, we assume the machine can sleep/resume.
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -22,11 +22,6 @@
 
 #include <video/radeon.h>
 
-/* Some weird black magic use by Apple driver that we don't use for
- * now --BenH
- */
-#undef HAS_PLL_M9_GPIO_MAGIC
-
 /***************************************************************
  * Most of the definitions here are adapted right from XFree86 *
  ***************************************************************/
@@ -82,6 +77,15 @@ enum radeon_chip_flags {
 	CHIP_HAS_CRTC2		= 0x00040000UL,	
 };
 
+/*
+ * Errata workarounds
+ */
+enum radeon_errata {
+	CHIP_ERRATA_R300_CG		= 0x00000001,
+	CHIP_ERRATA_PLL_DUMMYREADS	= 0x00000002,
+	CHIP_ERRATA_PLL_DELAY		= 0x00000004,
+};
+
 
 /*
  * Monitor types
@@ -300,6 +304,7 @@ struct radeonfb_info {
 	int			chipset;
 	u8			family;
 	u8			rev;
+	unsigned int		errata;
 	unsigned long		video_ram;
 	unsigned long		mapped_vram;
 	int			vram_width;
@@ -310,8 +315,6 @@ struct radeonfb_info {
 	int			has_CRTC2;
 	int			is_mobility;
 	int			is_IGP;
-	int			R300_cg_workaround;
-	int			m9p_workaround;
 	int			reversed_DAC;
 	int			reversed_TMDS;
 	struct panel_info	panel_info;
@@ -375,6 +378,21 @@ struct radeonfb_info {
  * IO macros
  */
 
+/* Note about this function: we have some rare cases where we must not schedule,
+ * this typically happen with our special "wake up early" hook which allows us to
+ * wake up the graphic chip (and thus get the console back) before everything else
+ * on some machines that support that mecanism. At this point, interrupts are off
+ * and scheduling is not permitted
+ */
+static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
+{
+	if (rinfo->no_schedule || oops_in_progress)
+		mdelay(ms);
+	else
+		msleep(ms);
+}
+
+
 #define INREG8(addr)		readb((rinfo->mmio_base)+addr)
 #define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
 #define INREG(addr)		readl((rinfo->mmio_base)+addr)
@@ -396,117 +414,85 @@ static inline void _OUTREGP(struct radeo
 
 #define OUTREGP(addr,val,mask)	_OUTREGP(rinfo, addr, val,mask)
 
-static inline void R300_cg_workardound(struct radeonfb_info *rinfo)
-{
-	u32 save, tmp;
-	save = INREG(CLOCK_CNTL_INDEX);
-	tmp = save & ~(0x3f | PLL_WR_EN);
-	OUTREG(CLOCK_CNTL_INDEX, tmp);
-	tmp = INREG(CLOCK_CNTL_DATA);
-	OUTREG(CLOCK_CNTL_INDEX, save);
-}
-
-
-static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
-{
-	u32 data;
-#ifdef HAS_PLL_M9_GPIO_MAGIC
-	u32 sv[3];
-
-	if (rinfo->m9p_workaround) {
-		sv[0] = INREG(0x19c);
-		sv[1] = INREG(0x1a0);
-		sv[2] = INREG(0x198);
-		OUTREG(0x198, 0);
-		OUTREG(0x1a0, 0);
-		OUTREG(0x19c, 0);
+/*
+ * Note about PLL register accesses:
+ *
+ * I have removed the spinlock on them on purpose. The driver now
+ * expects that it will only manipulate the PLL registers in normal
+ * task environment, where radeon_msleep() will be called, protected
+ * by a semaphore (currently the console semaphore) so that no conflict
+ * will happen on the PLL register index.
+ *
+ * With the latest changes to the VT layer, this is guaranteed for all
+ * calls except the actual drawing/blits which aren't supposed to use
+ * the PLL registers anyway
+ *
+ * This is very important for the workarounds to work properly. The only
+ * possible exception to this rule is the call to unblank(), which may
+ * be done at irq time if an oops is in progress.
+ */
+static inline void radeon_pll_errata_after_index(struct radeonfb_info *rinfo)
+{
+	if (!(rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS))
+		return;
+
+	(void)INREG(CLOCK_CNTL_DATA);
+	(void)INREG(CRTC_GEN_CNTL);
+}
+
+static inline void radeon_pll_errata_after_data(struct radeonfb_info *rinfo)
+{
+	if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
+		/* we can't deal with posted writes here ... */
+		_radeon_msleep(rinfo, 5);
 	}
-#endif /* HAS_PLL_M9_GPIO_MAGIC */
-
-	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
-	data = (INREG(CLOCK_CNTL_DATA));
-
-#ifdef HAS_PLL_M9_GPIO_MAGIC
-	if (rinfo->m9p_workaround) {
-		(void)INREG(CRTC_GEN_CNTL);
-		data = INREG(CLOCK_CNTL_DATA);
-		OUTREG(0x19c, sv[0]);
-		OUTREG(0x1a0, sv[1]);
-		OUTREG(0x198, sv[2]);
+	if (rinfo->errata & CHIP_ERRATA_R300_CG) {
+		u32 save, tmp;
+		save = INREG(CLOCK_CNTL_INDEX);
+		tmp = save & ~(0x3f | PLL_WR_EN);
+		OUTREG(CLOCK_CNTL_INDEX, tmp);
+		tmp = INREG(CLOCK_CNTL_DATA);
+		OUTREG(CLOCK_CNTL_INDEX, save);
 	}
-#endif /* HAS_PLL_M9_GPIO_MAGIC */
-	if (rinfo->R300_cg_workaround)
-		R300_cg_workardound(rinfo);
-	return data;
 }
 
-static inline u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
+static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
 {
-       	unsigned long flags;
 	u32 data;
 
-	spin_lock_irqsave(&rinfo->reg_lock, flags);
-	data = __INPLL(rinfo, addr);
-	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
+	radeon_pll_errata_after_index(rinfo);
+	data = INREG(CLOCK_CNTL_DATA);
+	radeon_pll_errata_after_data(rinfo);
 	return data;
 }
 
-#define INPLL(addr)		_INPLL(rinfo, addr)
-
-
-static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
+static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
+			    u32 val)
 {
-#ifdef HAS_PLL_M9_GPIO_MAGIC
-	u32 sv[3];
-
-	if (rinfo->m9p_workaround) {
-		sv[0] = INREG(0x19c);
-		sv[1] = INREG(0x1a0);
-		sv[2] = INREG(0x198);
-		OUTREG(0x198, 0);
-		OUTREG(0x1a0, 0);
-		OUTREG(0x19c, 0);
-		mdelay(1);
-	}
-#endif /* HAS_PLL_M9_GPIO_MAGIC */
 
 	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
+	radeon_pll_errata_after_index(rinfo);
 	OUTREG(CLOCK_CNTL_DATA, val);
-
-#ifdef HAS_PLL_M9_GPIO_MAGIC
-	if (rinfo->m9p_workaround) {
-		OUTREG(0x19c, sv[0]);
-		OUTREG(0x1a0, sv[1]);
-		OUTREG(0x198, sv[2]);
-	}
-#endif /* HAS_PLL_M9_GPIO_MAGIC */
+	radeon_pll_errata_after_data(rinfo);
 }
 
-static inline void _OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
-{
-       	unsigned long flags;
-	spin_lock_irqsave(&rinfo->reg_lock, flags);
-	__OUTPLL(rinfo, index, val);
-	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
-}
 
-static inline void _OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
-			    u32 val, u32 mask)
+static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+			     u32 val, u32 mask)
 {
-	unsigned long flags;
 	unsigned int tmp;
 
-	spin_lock_irqsave(&rinfo->reg_lock, flags);
 	tmp  = __INPLL(rinfo, index);
 	tmp &= (mask);
 	tmp |= (val);
 	__OUTPLL(rinfo, index, tmp);
-	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
 }
 
 
-#define OUTPLL(index, val)		_OUTPLL(rinfo, index, val)
-#define OUTPLLP(index, val, mask)	_OUTPLLP(rinfo, index, val, mask)
+#define INPLL(addr)			__INPLL(rinfo, addr)
+#define OUTPLL(index, val)		__OUTPLL(rinfo, index, val)
+#define OUTPLLP(index, val, mask)	__OUTPLLP(rinfo, index, val, mask)
 
 
 #define BIOS_IN8(v)  	(readb(rinfo->bios_seg + (v)))
@@ -598,20 +584,6 @@ static inline void _radeon_engine_idle(s
 	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
 }
 
-/* Note about this function: we have some rare cases where we must not schedule,
- * this typically happen with our special "wake up early" hook which allows us to
- * wake up the graphic chip (and thus get the console back) before everything else
- * on some machines that support that mecanism. At this point, interrupts are off
- * and scheduling is not permitted
- */
-static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
-{
-	if (rinfo->no_schedule)
-		mdelay(ms);
-	else
-		msleep(ms);
-}
-
 
 #define radeon_engine_idle()		_radeon_engine_idle(rinfo)
 #define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
@@ -624,7 +596,7 @@ extern void radeon_delete_i2c_busses(str
 extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);
 
 /* PM Functions */
-extern int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state);
+extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int radeonfb_pci_resume(struct pci_dev *pdev);
 extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
 extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
@@ -647,7 +619,6 @@ extern void radeonfb_engine_reset(struct
 
 /* Other functions */
 extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
-extern void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save);
 extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
 			       int reg_only);
 
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -408,7 +408,7 @@ au1100fb_mmap(struct fb_info *_fb,
 	/* This is an IO map - tell maydump to skip this VMA */
 	vma->vm_flags |= VM_IO;
 
-	if (io_remap_page_range(vma, vma->vm_start, off,
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
 				vma->vm_end - vma->vm_start,
 				vma->vm_page_prot)) {
 		return -EAGAIN;
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -111,7 +111,7 @@ static void backlight_class_release(stru
 	kfree(bd);
 }
 
-struct class backlight_class = {
+static struct class backlight_class = {
 	.name = "backlight",
 	.release = backlight_class_release,
 };
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -52,9 +52,9 @@ static void corgibl_send_intensity(int i
 	corgi_ssp_blduty_set(intensity & 0x1f);
 	/* Bit 5 is via SCOOP */
 	if (intensity & 0x0020)
-		set_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT);
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
 	else
-		reset_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT);
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
 	spin_unlock_irqrestore(&bl_lock, flags);
 }
 
@@ -81,7 +81,7 @@ static void corgibl_blank(int blank)
 }
 
 #ifdef CONFIG_PM
-static int corgibl_suspend(struct device *dev, u32 state, u32 level)
+static int corgibl_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_POWER_DOWN)
 		corgibl_blank(FB_BLANK_POWERDOWN);
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -111,7 +111,7 @@ static void lcd_class_release(struct cla
 	kfree(ld);
 }
 
-struct class lcd_class = {
+static struct class lcd_class = {
 	.name = "lcd",
 	.release = lcd_class_release,
 };
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -1,25 +1,29 @@
 /*
  *  Generic function for frame buffer with packed pixels of any depth.
  *
- *      Copyright (C)  June 1999 James Simmons
+ *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
  *
  *  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 is for cfb packed pixels. Iplan and such are incorporated in the 
+ *
+ *  This is for cfb packed pixels. Iplan and such are incorporated in the
  *  drivers that need them.
- * 
+ *
  *  FIXME
- *  The code for 24 bit is horrible. It copies byte by byte size instead of 
- *  longs like the other sizes. Needs to be optimized. 
  *
- *  Also need to add code to deal with cards endians that are different than 
+ *  Also need to add code to deal with cards endians that are different than
  *  the native cpu endians. I also need to deal with MSB position in the word.
- *  
+ *
+ *  The two functions or copying forward and backward could be split up like
+ *  the ones for filling, i.e. in aligned and unaligned versions. This would
+ *  help moving some redundant computations and branches out of the loop, too.
  */
+
+
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -29,58 +33,61 @@
 #include <asm/types.h>
 #include <asm/io.h>
 
-#define LONG_MASK  (BITS_PER_LONG - 1)
-
 #if BITS_PER_LONG == 32
-#define FB_WRITEL fb_writel
-#define FB_READL  fb_readl
-#define SHIFT_PER_LONG 5
-#define BYTES_PER_LONG 4
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
 #else
-#define FB_WRITEL fb_writeq
-#define FB_READL  fb_readq
-#define SHIFT_PER_LONG 6
-#define BYTES_PER_LONG 8
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
 #endif
 
-static void bitcpy(unsigned long __iomem *dst, int dst_idx,
-		   const unsigned long __iomem *src, int src_idx,
-		   unsigned long n)
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+    return ((a ^ b) & mask) ^ b;
+}
+
+    /*
+     *  Generic bitwise copy algorithm
+     */
+
+static void
+bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
+	int src_idx, int bits, unsigned n)
 {
 	unsigned long first, last;
-	int shift = dst_idx-src_idx, left, right;
-	unsigned long d0, d1;
-	int m;
-	
-	if (!n)
-		return;
-	
-	shift = dst_idx-src_idx;
+	int const shift = dst_idx-src_idx;
+	int left, right;
+
 	first = ~0UL >> dst_idx;
-	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-	
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
 	if (!shift) {
 		// Same alignment for source and dest
-		
-		if (dst_idx+n <= BITS_PER_LONG) {
+
+		if (dst_idx+n <= bits) {
 			// Single word
 			if (last)
 				first &= last;
-			FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
+			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
 		} else {
 			// Multiple destination words
+
 			// Leading bits
-			if (first) {
-				
-				FB_WRITEL((FB_READL(src) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+			if (first != ~0UL) {
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
 				dst++;
 				src++;
-				n -= BITS_PER_LONG-dst_idx;
+				n -= bits - dst_idx;
 			}
-			
+
 			// Main chunk
-			n /= BITS_PER_LONG;
+			n /= bits;
 			while (n >= 8) {
 				FB_WRITEL(FB_READL(src++), dst++);
 				FB_WRITEL(FB_READL(src++), dst++);
@@ -94,58 +101,61 @@ static void bitcpy(unsigned long __iomem
 			}
 			while (n--)
 				FB_WRITEL(FB_READL(src++), dst++);
+
 			// Trailing bits
 			if (last)
-				FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
 		}
 	} else {
+		unsigned long d0, d1;
+		int m;
 		// Different alignment for source and dest
-		
-		right = shift & (BITS_PER_LONG-1);
-		left = -shift & (BITS_PER_LONG-1);
-		
-		if (dst_idx+n <= BITS_PER_LONG) {
+
+		right = shift & (bits - 1);
+		left = -shift & (bits - 1);
+
+		if (dst_idx+n <= bits) {
 			// Single destination word
 			if (last)
 				first &= last;
 			if (shift > 0) {
 				// Single source word
-				FB_WRITEL(((FB_READL(src) >> right) & first) | 
-					  (FB_READL(dst) & ~first), dst);
-			} else if (src_idx+n <= BITS_PER_LONG) {
+				FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst);
+			} else if (src_idx+n <= bits) {
 				// Single source word
-				FB_WRITEL(((FB_READL(src) << left) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst);
 			} else {
 				// 2 source words
 				d0 = FB_READL(src++);
 				d1 = FB_READL(src);
-				FB_WRITEL(((d0<<left | d1>>right) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
 			}
 		} else {
 			// Multiple destination words
+			/** We must always remember the last value read, because in case
+			SRC and DST overlap bitwise (e.g. when moving just one pixel in
+			1bpp), we always collect one full long for DST and that might
+			overlap with the current long from SRC. We store this value in
+			'd0'. */
 			d0 = FB_READL(src++);
 			// Leading bits
 			if (shift > 0) {
 				// Single source word
-				FB_WRITEL(((d0 >> right) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst);
 				dst++;
-				n -= BITS_PER_LONG-dst_idx;
+				n -= bits - dst_idx;
 			} else {
 				// 2 source words
 				d1 = FB_READL(src++);
-				FB_WRITEL(((d0<<left | d1>>right) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
 				d0 = d1;
 				dst++;
-				n -= BITS_PER_LONG-dst_idx;
+				n -= bits - dst_idx;
 			}
-			
+
 			// Main chunk
-			m = n % BITS_PER_LONG;
-			n /= BITS_PER_LONG;
+			m = n % bits;
+			n /= bits;
 			while (n >= 4) {
 				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
@@ -166,72 +176,70 @@ static void bitcpy(unsigned long __iomem
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
 			}
-			
+
 			// Trailing bits
 			if (last) {
 				if (m <= right) {
 					// Single source word
-					FB_WRITEL(((d0 << left) & last) | 
-						  (FB_READL(dst) & ~last), 
-						  dst);
+					FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst);
 				} else {
 					// 2 source words
 					d1 = FB_READL(src);
-					FB_WRITEL(((d0<<left | d1>>right) & 
-						   last) | (FB_READL(dst) & 
-							    ~last), dst);
+					FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst);
 				}
 			}
 		}
 	}
 }
 
-static void bitcpy_rev(unsigned long __iomem *dst, int dst_idx,
-		       const unsigned long __iomem *src, int src_idx, unsigned long n)
+    /*
+     *  Generic bitwise copy algorithm, operating backward
+     */
+
+static void
+bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
+		int src_idx, int bits, unsigned n)
 {
 	unsigned long first, last;
-	int shift = dst_idx-src_idx, left, right;
-	unsigned long d0, d1;
-	int m;
-	
-	if (!n)
-		return;
-	
-	dst += (n-1)/BITS_PER_LONG;
-	src += (n-1)/BITS_PER_LONG;
-	if ((n-1) % BITS_PER_LONG) {
-		dst_idx += (n-1) % BITS_PER_LONG;
-		dst += dst_idx >> SHIFT_PER_LONG;
-		dst_idx &= BITS_PER_LONG-1;
-		src_idx += (n-1) % BITS_PER_LONG;
-		src += src_idx >> SHIFT_PER_LONG;
-		src_idx &= BITS_PER_LONG-1;
+	int shift;
+
+	dst += (n-1)/bits;
+	src += (n-1)/bits;
+	if ((n-1) % bits) {
+		dst_idx += (n-1) % bits;
+		dst += dst_idx >> (ffs(bits) - 1);
+		dst_idx &= bits - 1;
+		src_idx += (n-1) % bits;
+		src += src_idx >> (ffs(bits) - 1);
+		src_idx &= bits - 1;
 	}
-	
+
 	shift = dst_idx-src_idx;
-	first = ~0UL << (BITS_PER_LONG-1-dst_idx);
-	last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
-	
+
+	first = ~0UL << (bits - 1 - dst_idx);
+	last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits)));
+
 	if (!shift) {
 		// Same alignment for source and dest
-		
+
 		if ((unsigned long)dst_idx+1 >= n) {
 			// Single word
 			if (last)
 				first &= last;
-			FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst); 
+			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
 		} else {
 			// Multiple destination words
+
 			// Leading bits
-			if (first) {
-				FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst); 
+			if (first != ~0UL) {
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
 				dst--;
 				src--;
 				n -= dst_idx+1;
 			}
-			
+
 			// Main chunk
-			n /= BITS_PER_LONG;
+			n /= bits;
 			while (n >= 8) {
 				FB_WRITEL(FB_READL(src--), dst--);
 				FB_WRITEL(FB_READL(src--), dst--);
@@ -245,59 +253,58 @@ static void bitcpy_rev(unsigned long __i
 			}
 			while (n--)
 				FB_WRITEL(FB_READL(src--), dst--);
-			
+
 			// Trailing bits
 			if (last)
-				FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
 		}
 	} else {
 		// Different alignment for source and dest
-		
-		right = shift & (BITS_PER_LONG-1);
-		left = -shift & (BITS_PER_LONG-1);
-		
+
+		int const left = -shift & (bits-1);
+		int const right = shift & (bits-1);
+
 		if ((unsigned long)dst_idx+1 >= n) {
 			// Single destination word
 			if (last)
 				first &= last;
 			if (shift < 0) {
 				// Single source word
-				FB_WRITEL((FB_READL(src) << left & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst);
 			} else if (1+(unsigned long)src_idx >= n) {
 				// Single source word
-				FB_WRITEL(((FB_READL(src) >> right) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst);
 			} else {
 				// 2 source words
-				d0 = FB_READL(src--);
-				d1 = FB_READL(src);
-				FB_WRITEL(((d0>>right | d1<<left) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst);
 			}
 		} else {
 			// Multiple destination words
+			/** We must always remember the last value read, because in case
+			SRC and DST overlap bitwise (e.g. when moving just one pixel in
+			1bpp), we always collect one full long for DST and that might
+			overlap with the current long from SRC. We store this value in
+			'd0'. */
+			unsigned long d0, d1;
+			int m;
+
 			d0 = FB_READL(src--);
 			// Leading bits
 			if (shift < 0) {
 				// Single source word
-				FB_WRITEL(((d0 << left) & first) | 
-					  (FB_READL(dst) & ~first), dst);
-				dst--;
-				n -= dst_idx+1;
+				FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst);
 			} else {
 				// 2 source words
 				d1 = FB_READL(src--);
-				FB_WRITEL(((d0>>right | d1<<left) & first) | 
-					  (FB_READL(dst) & ~first), dst);
+				FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst);
 				d0 = d1;
-				dst--;
-				n -= dst_idx+1;
 			}
-			
+			dst--;
+			n -= dst_idx+1;
+
 			// Main chunk
-			m = n % BITS_PER_LONG;
-			n /= BITS_PER_LONG;
+			m = n % bits;
+			n /= bits;
 			while (n >= 4) {
 				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
@@ -318,20 +325,16 @@ static void bitcpy_rev(unsigned long __i
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
 			}
-			
+
 			// Trailing bits
 			if (last) {
 				if (m <= left) {
 					// Single source word
-					FB_WRITEL(((d0 >> right) & last) | 
-						  (FB_READL(dst) & ~last), 
-						  dst);
+					FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst);
 				} else {
 					// 2 source words
 					d1 = FB_READL(src);
-					FB_WRITEL(((d0>>right | d1<<left) & 
-						   last) | (FB_READL(dst) & 
-							    ~last), dst);
+					FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst);
 				}
 			}
 		}
@@ -342,30 +345,27 @@ void cfb_copyarea(struct fb_info *p, con
 {
 	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
 	u32 height = area->height, width = area->width;
-	int x2, y2, old_dx, old_dy, vxres, vyres;
-	unsigned long next_line = p->fix.line_length;
-	int dst_idx = 0, src_idx = 0, rev_copy = 0;
+	unsigned long const bits_per_line = p->fix.line_length*8u;
 	unsigned long __iomem *dst = NULL, *src = NULL;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
+	int dst_idx = 0, src_idx = 0, rev_copy = 0;
+	int x2, y2, vxres, vyres;
 
 	if (p->state != FBINFO_STATE_RUNNING)
 		return;
 
 	/* We want rotation but lack hardware to do it for us. */
 	if (!p->fbops->fb_rotate && p->var.rotate) {
-	}	
-	
+	}
+
 	vxres = p->var.xres_virtual;
 	vyres = p->var.yres_virtual;
 
-	if (area->dx > vxres || area->sx > vxres || 
+	if (area->dx > vxres || area->sx > vxres ||
 	    area->dy > vyres || area->sy > vyres)
 		return;
 
-	/* clip the destination */
-	old_dx = area->dx;
-	old_dy = area->dy;
-
-	/*
+	/* clip the destination
 	 * We could use hardware clipping but on many cards you get around
 	 * hardware clipping by writing to framebuffer directly.
 	 */
@@ -378,53 +378,58 @@ void cfb_copyarea(struct fb_info *p, con
 	width = x2 - dx;
 	height = y2 - dy;
 
+	if ((width==0) ||(height==0))
+		return;
+
 	/* update sx1,sy1 */
-	sx += (dx - old_dx);
-	sy += (dy - old_dy);
+	sx += (dx - area->dx);
+	sy += (dy - area->dy);
 
 	/* the source must be completely inside the virtual screen */
-	if (sx < 0 || sy < 0 ||
-	    (sx + width) > vxres ||
-	    (sy + height) > vyres)
+	if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
 		return;
 
-	if ((dy == sy && dx > sx) ||	
-	    (dy > sy)) { 
+	/* if the beginning of the target area might overlap with the end of
+	the source area, be have to copy the area reverse. */
+	if ((dy == sy && dx > sx) || (dy > sy)) {
 		dy += height;
 		sy += height;
 		rev_copy = 1;
 	}
 
-	dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & 
-				      ~(BYTES_PER_LONG-1));
-	dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
-	dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel;
-	src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel;
-	
+	// split the base of the framebuffer into a long-aligned address and the
+	// index of the first bit
+	dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+	// add offset of source and target area
+	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
 	if (p->fbops->fb_sync)
 		p->fbops->fb_sync(p);
+
 	if (rev_copy) {
 		while (height--) {
-			dst_idx -= next_line*8;
-			src_idx -= next_line*8;
-			dst += dst_idx >> SHIFT_PER_LONG;
-			dst_idx &= (BYTES_PER_LONG-1);
-			src += src_idx >> SHIFT_PER_LONG;
-			src_idx &= (BYTES_PER_LONG-1);
-			bitcpy_rev(dst, dst_idx, src, src_idx, 
-				   width*p->var.bits_per_pixel);
-		}	
+			dst_idx -= bits_per_line;
+			src_idx -= bits_per_line;
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+		}
 	} else {
 		while (height--) {
-			dst += dst_idx >> SHIFT_PER_LONG;
-			dst_idx &= (BYTES_PER_LONG-1);
-			src += src_idx >> SHIFT_PER_LONG;
-			src_idx &= (BYTES_PER_LONG-1);
-			bitcpy(dst, dst_idx, src, src_idx, 
-			       width*p->var.bits_per_pixel);
-			dst_idx += next_line*8;
-			src_idx += next_line*8;
-		}	
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+			dst_idx += bits_per_line;
+			src_idx += bits_per_line;
+		}
 	}
 }
 
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -1,7 +1,7 @@
 /*
- *  Generic fillrect for frame buffers with packed pixels of any depth. 
+ *  Generic fillrect for frame buffers with packed pixels of any depth.
  *
- *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org) 
+ *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
  *
  *  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
@@ -9,8 +9,8 @@
  *
  * NOTES:
  *
- *  The code for depths like 24 that don't have integer number of pixels per 
- *  long is broken and needs to be fixed. For now I turned these types of 
+ *  The code for depths like 24 that don't have integer number of pixels per
+ *  long is broken and needs to be fixed. For now I turned these types of
  *  mode off.
  *
  *  Also need to add code to deal with cards endians that are different than
@@ -24,149 +24,129 @@
 #include <asm/types.h>
 
 #if BITS_PER_LONG == 32
-#define FB_WRITEL fb_writel
-#define FB_READL  fb_readl
-#define BYTES_PER_LONG 4
-#define SHIFT_PER_LONG 5
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
 #else
-#define FB_WRITEL fb_writeq
-#define FB_READL  fb_readq
-#define BYTES_PER_LONG 8
-#define SHIFT_PER_LONG 6
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
 #endif
 
-#define EXP1(x)		0xffffffffU*x
-#define EXP2(x)		0x55555555U*x
-#define EXP4(x)		0x11111111U*0x ## x
-
-typedef u32 pixel_t;
-
-static const u32 bpp1tab[2] = {
-    EXP1(0), EXP1(1)
-};
-
-static const u32 bpp2tab[4] = {
-    EXP2(0), EXP2(1), EXP2(2), EXP2(3)
-};
-
-static const u32 bpp4tab[16] = {
-    EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
-    EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
-};
-
     /*
      *  Compose two values, using a bitmask as decision value
      *  This is equivalent to (a & mask) | (b & ~mask)
      */
 
-static inline unsigned long comp(unsigned long a, unsigned long b,
-				 unsigned long mask)
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
 {
     return ((a ^ b) & mask) ^ b;
 }
 
-static inline u32 pixel_to_pat32(const struct fb_info *p, pixel_t pixel)
-{
-    u32 pat = pixel;
+    /*
+     *  Create a pattern with the given pixel's color
+     */
 
-    switch (p->var.bits_per_pixel) {
+#if BITS_PER_LONG == 64
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+	switch (bpp) {
 	case 1:
-	    pat = bpp1tab[pat];
-	    break;
-
+		return 0xfffffffffffffffful*pixel;
 	case 2:
-	    pat = bpp2tab[pat];
-	    break;
-
+		return 0x5555555555555555ul*pixel;
 	case 4:
-	    pat = bpp4tab[pat];
-	    break;
-
+		return 0x1111111111111111ul*pixel;
 	case 8:
-	    pat |= pat << 8;
-	    // Fall through
+		return 0x0101010101010101ul*pixel;
+	case 12:
+		return 0x0001001001001001ul*pixel;
 	case 16:
-	    pat |= pat << 16;
-	    // Fall through
+		return 0x0001000100010001ul*pixel;
+	case 24:
+		return 0x0000000001000001ul*pixel;
 	case 32:
-	    break;
+		return 0x0000000100000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
     }
-    return pat;
 }
-
-    /*
-     *  Expand a pixel value to a generic 32/64-bit pattern and rotate it to
-     *  the correct start position
-     */
-
-static inline unsigned long pixel_to_pat(const struct fb_info *p, 
-					 pixel_t pixel, int left)
+#else
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
 {
-    unsigned long pat = pixel;
-    u32 bpp = p->var.bits_per_pixel;
-    int i;
-
-    /* expand pixel value */
-    for (i = bpp; i < BITS_PER_LONG; i *= 2)
-	pat |= pat << i;
-
-    /* rotate pattern to correct start position */
-    pat = pat << left | pat >> (bpp-left);
-    return pat;
+	switch (bpp) {
+	case 1:
+		return 0xfffffffful*pixel;
+	case 2:
+		return 0x55555555ul*pixel;
+	case 4:
+		return 0x11111111ul*pixel;
+	case 8:
+		return 0x01010101ul*pixel;
+	case 12:
+		return 0x00001001ul*pixel;
+	case 16:
+		return 0x00010001ul*pixel;
+	case 24:
+		return 0x00000001ul*pixel;
+	case 32:
+		return 0x00000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
+    }
 }
+#endif
 
     /*
-     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
+     *  Aligned pattern fill using 32/64-bit memory accesses
      */
 
-void bitfill32(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n)
+static void
+bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
 {
-	unsigned long val = pat;
 	unsigned long first, last;
-	
+
 	if (!n)
 		return;
-	
-#if BITS_PER_LONG == 64
-	val |= val << 32;
-#endif
-	
+
 	first = ~0UL >> dst_idx;
-	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-	
-	if (dst_idx+n <= BITS_PER_LONG) {
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
 		// Single word
 		if (last)
 			first &= last;
-		FB_WRITEL(comp(val, FB_READL(dst), first), dst);
+		FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
 	} else {
 		// Multiple destination words
+
 		// Leading bits
-		if (first) {
-			FB_WRITEL(comp(val, FB_READL(dst), first), dst);
+		if (first!= ~0UL) {
+			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
 			dst++;
-			n -= BITS_PER_LONG-dst_idx;
+			n -= bits - dst_idx;
 		}
-		
+
 		// Main chunk
-		n /= BITS_PER_LONG;
+		n /= bits;
 		while (n >= 8) {
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
-			FB_WRITEL(val, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
 			n -= 8;
 		}
 		while (n--)
-			FB_WRITEL(val, dst++);
-		
+			FB_WRITEL(pat, dst++);
+
 		// Trailing bits
 		if (last)
-			FB_WRITEL(comp(val, FB_READL(dst), first), dst);
+			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
 	}
 }
 
@@ -178,18 +158,19 @@ void bitfill32(unsigned long __iomem *ds
      *  used for the next 32/64-bit word
      */
 
-void bitfill(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left,
-	     int right, u32 n)
+static void
+bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+			int left, int right, unsigned n, int bits)
 {
 	unsigned long first, last;
 
 	if (!n)
 		return;
-	
+
 	first = ~0UL >> dst_idx;
-	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-	
-	if (dst_idx+n <= BITS_PER_LONG) {
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
 		// Single word
 		if (last)
 			first &= last;
@@ -201,11 +182,11 @@ void bitfill(unsigned long __iomem *dst,
 			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
 			dst++;
 			pat = pat << left | pat >> right;
-			n -= BITS_PER_LONG-dst_idx;
+			n -= bits - dst_idx;
 		}
-		
+
 		// Main chunk
-		n /= BITS_PER_LONG;
+		n /= bits;
 		while (n >= 4) {
 			FB_WRITEL(pat, dst++);
 			pat = pat << left | pat >> right;
@@ -221,29 +202,29 @@ void bitfill(unsigned long __iomem *dst,
 			FB_WRITEL(pat, dst++);
 			pat = pat << left | pat >> right;
 		}
-		
+
 		// Trailing bits
 		if (last)
 			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
 	}
 }
 
-void bitfill32_rev(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n)
+    /*
+     *  Aligned pattern invert using 32/64-bit memory accesses
+     */
+static void
+bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
 {
 	unsigned long val = pat, dat;
 	unsigned long first, last;
-	
+
 	if (!n)
 		return;
-	
-#if BITS_PER_LONG == 64
-	val |= val << 32;
-#endif
-	
+
 	first = ~0UL >> dst_idx;
-	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-	
-	if (dst_idx+n <= BITS_PER_LONG) {
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
 		// Single word
 		if (last)
 			first &= last;
@@ -252,15 +233,15 @@ void bitfill32_rev(unsigned long __iomem
 	} else {
 		// Multiple destination words
 		// Leading bits
-		if (first) {
+		if (first!=0UL) {
 			dat = FB_READL(dst);
 			FB_WRITEL(comp(dat ^ val, dat, first), dst);
 			dst++;
-			n -= BITS_PER_LONG-dst_idx;
+			n -= bits - dst_idx;
 		}
-		
+
 		// Main chunk
-		n /= BITS_PER_LONG;
+		n /= bits;
 		while (n >= 8) {
 			FB_WRITEL(FB_READL(dst) ^ val, dst);
 			dst++;
@@ -283,35 +264,36 @@ void bitfill32_rev(unsigned long __iomem
 		while (n--) {
 			FB_WRITEL(FB_READL(dst) ^ val, dst);
 			dst++;
-		}		
+		}
 		// Trailing bits
 		if (last) {
 			dat = FB_READL(dst);
-			FB_WRITEL(comp(dat ^ val, dat, first), dst);
+			FB_WRITEL(comp(dat ^ val, dat, last), dst);
 		}
 	}
 }
 
 
     /*
-     *  Unaligned generic pattern fill using 32/64-bit memory accesses
+     *  Unaligned generic pattern invert using 32/64-bit memory accesses
      *  The pattern must have been expanded to a full 32/64-bit value
      *  Left/right are the appropriate shifts to convert to the pattern to be
      *  used for the next 32/64-bit word
      */
 
-void bitfill_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left,
-	     int right, u32 n)
+static void
+bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+			int left, int right, unsigned n, int bits)
 {
 	unsigned long first, last, dat;
 
 	if (!n)
 		return;
-	
+
 	first = ~0UL >> dst_idx;
-	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-	
-	if (dst_idx+n <= BITS_PER_LONG) {
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
 		// Single word
 		if (last)
 			first &= last;
@@ -319,17 +301,18 @@ void bitfill_rev(unsigned long __iomem *
 		FB_WRITEL(comp(dat ^ pat, dat, first), dst);
 	} else {
 		// Multiple destination words
+
 		// Leading bits
-		if (first) {
+		if (first != 0UL) {
 			dat = FB_READL(dst);
 			FB_WRITEL(comp(dat ^ pat, dat, first), dst);
 			dst++;
 			pat = pat << left | pat >> right;
-			n -= BITS_PER_LONG-dst_idx;
+			n -= bits - dst_idx;
 		}
-		
+
 		// Main chunk
-		n /= BITS_PER_LONG;
+		n /= bits;
 		while (n >= 4) {
 			FB_WRITEL(FB_READL(dst) ^ pat, dst);
 			dst++;
@@ -350,20 +333,20 @@ void bitfill_rev(unsigned long __iomem *
 			dst++;
 			pat = pat << left | pat >> right;
 		}
-		
+
 		// Trailing bits
 		if (last) {
 			dat = FB_READL(dst);
-			FB_WRITEL(comp(dat ^ pat, dat, first), dst);
+			FB_WRITEL(comp(dat ^ pat, dat, last), dst);
 		}
 	}
 }
 
 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
+	unsigned long x2, y2, vxres, vyres, height, width, pat, fg;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
 	u32 bpp = p->var.bits_per_pixel;
-	unsigned long x2, y2, vxres, vyres;
-	unsigned long height, width, fg;
 	unsigned long __iomem *dst;
 	int dst_idx, left;
 
@@ -372,81 +355,91 @@ void cfb_fillrect(struct fb_info *p, con
 
 	/* We want rotation but lack hardware to do it for us. */
 	if (!p->fbops->fb_rotate && p->var.rotate) {
-	}	
-	
+	}
+
 	vxres = p->var.xres_virtual;
 	vyres = p->var.yres_virtual;
 
-	if (!rect->width || !rect->height || 
+	if (!rect->width || !rect->height ||
 	    rect->dx > vxres || rect->dy > vyres)
 		return;
 
 	/* We could use hardware clipping but on many cards you get around
 	 * hardware clipping by writing to framebuffer directly. */
-	
+
 	x2 = rect->dx + rect->width;
 	y2 = rect->dy + rect->height;
 	x2 = x2 < vxres ? x2 : vxres;
 	y2 = y2 < vyres ? y2 : vyres;
 	width = x2 - rect->dx;
 	height = y2 - rect->dy;
-	
+
 	if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
 	    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
 		fg = ((u32 *) (p->pseudo_palette))[rect->color];
 	else
 		fg = rect->color;
-	
-	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & 
-				~(BYTES_PER_LONG-1));
-	dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8;
+
+	pat = pixel_to_pat( bpp, fg);
+
+	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
 	dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
 	/* FIXME For now we support 1-32 bpp only */
-	left = BITS_PER_LONG % bpp;
+	left = bits % bpp;
 	if (p->fbops->fb_sync)
 		p->fbops->fb_sync(p);
 	if (!left) {
-		u32 pat = pixel_to_pat32(p, fg);
-		void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, u32 pat, 
-				  u32 n) = NULL;
-		
+		void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
+		                  unsigned long pat, unsigned n, int bits) = NULL;
+
 		switch (rect->rop) {
 		case ROP_XOR:
-			fill_op32 = bitfill32_rev;
+			fill_op32 = bitfill_aligned_rev;
 			break;
 		case ROP_COPY:
+			fill_op32 = bitfill_aligned;
+			break;
 		default:
-			fill_op32 = bitfill32;
+			printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+			fill_op32 = bitfill_aligned;
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> SHIFT_PER_LONG;
-			dst_idx &= (BITS_PER_LONG-1);
-			fill_op32(dst, dst_idx, pat, width*bpp);
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op32(dst, dst_idx, pat, width*bpp, bits);
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp);
-		int right = bpp-left;
+		int right;
 		int r;
-		void (*fill_op)(unsigned long __iomem *dst, int dst_idx, 
-				unsigned long pat, int left, int right, 
-				u32 n) = NULL;
-		
+		int rot = (left-dst_idx) % bpp;
+		void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
+		                unsigned long pat, int left, int right,
+		                unsigned n, int bits) = NULL;
+
+		/* rotate pattern to correct start position */
+		pat = pat << rot | pat >> (bpp-rot);
+
+		right = bpp-left;
 		switch (rect->rop) {
 		case ROP_XOR:
-			fill_op = bitfill_rev;
+			fill_op = bitfill_unaligned_rev;
 			break;
 		case ROP_COPY:
+			fill_op = bitfill_unaligned;
+			break;
 		default:
-			fill_op = bitfill;
+			printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+			fill_op = bitfill_unaligned;
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> SHIFT_PER_LONG;
-			dst_idx &= (BITS_PER_LONG-1);
-			fill_op(dst, dst_idx, pat, left, right, 
-				width*bpp);
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op(dst, dst_idx, pat, left, right,
+				width*bpp, bits);
 			r = (p->fix.line_length*8) % bpp;
 			pat = pat << (bpp-r) | pat >> r;
 			dst_idx += p->fix.line_length*8;
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -465,7 +465,7 @@ int __init chips_init(void)
 	if (fb_get_options("chipsfb", NULL))
 		return -ENODEV;
 
-	return pci_module_init(&chipsfb_driver);
+	return pci_register_driver(&chipsfb_driver);
 }
 
 module_init(chips_init);
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -515,23 +515,25 @@ static const struct {
 
 
 /*--- Interface used by the world ------------------------------------------*/
-int cirrusfb_init (void);
-int cirrusfb_setup (char *options);
+static int cirrusfb_init (void);
+#ifndef MODULE
+static int cirrusfb_setup (char *options);
+#endif
 
-int cirrusfb_open (struct fb_info *info, int user);
-int cirrusfb_release (struct fb_info *info, int user);
-int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
-			unsigned blue, unsigned transp,
-			struct fb_info *info);
-int cirrusfb_check_var (struct fb_var_screeninfo *var,
-			struct fb_info *info);
-int cirrusfb_set_par (struct fb_info *info);
-int cirrusfb_pan_display (struct fb_var_screeninfo *var,
-			  struct fb_info *info);
-int cirrusfb_blank (int blank_mode, struct fb_info *info);
-void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
-void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
+static int cirrusfb_open (struct fb_info *info, int user);
+static int cirrusfb_release (struct fb_info *info, int user);
+static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+			       unsigned blue, unsigned transp,
+			       struct fb_info *info);
+static int cirrusfb_check_var (struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int cirrusfb_set_par (struct fb_info *info);
+static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info *info);
+static int cirrusfb_blank (int blank_mode, struct fb_info *info);
+static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
+static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
 
 /* function table of the above functions */
 static struct fb_ops cirrusfb_ops = {
@@ -600,7 +602,7 @@ static void cirrusfb_dbg_print_byte (con
 static int opencount = 0;
 
 /*--- Open /dev/fbx ---------------------------------------------------------*/
-int cirrusfb_open (struct fb_info *info, int user)
+static int cirrusfb_open (struct fb_info *info, int user)
 {
 	if (opencount++ == 0)
 		switch_monitor (info->par, 1);
@@ -608,7 +610,7 @@ int cirrusfb_open (struct fb_info *info,
 }
 
 /*--- Close /dev/fbx --------------------------------------------------------*/
-int cirrusfb_release (struct fb_info *info, int user)
+static int cirrusfb_release (struct fb_info *info, int user)
 {
 	if (--opencount == 0)
 		switch_monitor (info->par, 0);
@@ -660,8 +662,8 @@ static long cirrusfb_get_mclk (long freq
 	return mclk;
 }
 
-int cirrusfb_check_var(struct fb_var_screeninfo *var,
-		       struct fb_info *info)
+static int cirrusfb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
 {
 	struct cirrusfb_info *cinfo = info->par;
 	int nom, den;		/* translyting from pixels->bytes */
@@ -1573,15 +1575,15 @@ static int cirrusfb_set_par_foo (struct 
 
 /* for some reason incomprehensible to me, cirrusfb requires that you write
  * the registers twice for the settings to take..grr. -dte */
-int cirrusfb_set_par (struct fb_info *info)
+static int cirrusfb_set_par (struct fb_info *info)
 {
 	cirrusfb_set_par_foo (info);
 	return cirrusfb_set_par_foo (info);
 }
 
-int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
-			unsigned blue, unsigned transp,
-			struct fb_info *info)
+static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+			       unsigned blue, unsigned transp,
+			       struct fb_info *info)
 {
 	struct cirrusfb_info *cinfo = info->par;
 
@@ -1632,8 +1634,8 @@ int cirrusfb_setcolreg (unsigned regno, 
 
 	performs display panning - provided hardware permits this
 **************************************************************************/
-int cirrusfb_pan_display (struct fb_var_screeninfo *var,
-			  struct fb_info *info)
+static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info *info)
 {
 	int xoffset = 0;
 	int yoffset = 0;
@@ -1702,7 +1704,7 @@ int cirrusfb_pan_display (struct fb_var_
 }
 
 
-int cirrusfb_blank (int blank_mode, struct fb_info *info)
+static int cirrusfb_blank (int blank_mode, struct fb_info *info)
 {
 	/*
 	 *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
@@ -2036,7 +2038,7 @@ static void cirrusfb_prim_fillrect(struc
 	return;
 }
 
-void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
+static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
 {
 	struct cirrusfb_info *cinfo = info->par;
 	struct fb_fillrect modded;
@@ -2086,7 +2088,7 @@ static void cirrusfb_prim_copyarea(struc
 }
 
 
-void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
 	struct cirrusfb_info *cinfo = info->par;
 	struct fb_copyarea modded;
@@ -2121,7 +2123,7 @@ void cirrusfb_copyarea(struct fb_info *i
 	cirrusfb_prim_copyarea(cinfo, &modded);
 }
 
-void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
+static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	struct cirrusfb_info *cinfo = info->par;
 
@@ -2459,7 +2461,7 @@ err_out:
 	return ret;
 }
 
-void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
+static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
 	DPRINTK ("ENTER\n");
@@ -2605,7 +2607,7 @@ static struct zorro_driver cirrusfb_zorr
 };
 #endif /* CONFIG_ZORRO */
 
-int __init cirrusfb_init(void)
+static int __init cirrusfb_init(void)
 {
 	int error = 0;
 
@@ -2621,7 +2623,7 @@ int __init cirrusfb_init(void)
 	error |= zorro_module_init(&cirrusfb_zorro_driver);
 #endif
 #ifdef CONFIG_PCI
-	error |= pci_module_init(&cirrusfb_pci_driver);
+	error |= pci_register_driver(&cirrusfb_pci_driver);
 #endif
 	return error;
 }
@@ -2629,7 +2631,7 @@ int __init cirrusfb_init(void)
 
 
 #ifndef MODULE
-int __init cirrusfb_setup(char *options) {
+static int __init cirrusfb_setup(char *options) {
 	char *this_opt, s[32];
 	int i;
 
@@ -2664,7 +2666,7 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff 
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 MODULE_LICENSE("GPL");
 
-void __exit cirrusfb_exit (void)
+static void __exit cirrusfb_exit (void)
 {
 #ifdef CONFIG_PCI
 	pci_unregister_driver(&cirrusfb_pci_driver);
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -43,7 +43,7 @@ config VIDEO_SELECT
 	  about the Video mode selection support. If unsure, say N.
 
 config MDA_CONSOLE
-	depends on !M68K && ISA
+	depends on !M68K && !PARISC && ISA
 	tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
 	---help---
 	  Say Y here if you have an old MDA or monochrome Hercules graphics
@@ -65,30 +65,6 @@ config SGI_NEWPORT_CONSOLE
           card of your Indy.  Most people say Y here.
 
 #  bool 'IODC console' CONFIG_IODC_CONSOLE
-config STI_CONSOLE
-        tristate "STI text console" 
-        depends on PARISC && FRAMEBUFFER_CONSOLE
-        default y
-        help
-          The STI console is the builtin display/keyboard on HP-PARISC
-          machines.  Say Y here to build support for it into your kernel.
-          The alternative is to use your primary serial port as a console.
-
-config DUMMY_CONSOLE_COLUMNS
-        int "Initial number of console screen columns" if STI_CONSOLE
-        depends on PARISC
-        default "160"
-        help
-          The default value is 160, which should fit a 1280x1024 monitor.
-          Select 80 if you use a 640x480 resolution by default.
-
-config DUMMY_CONSOLE_ROWS
-        int "Initial number of console screen rows" if STI_CONSOLE
-        depends on PARISC
-        default "64"
-        help
-          The default value is 64, which should fit a 1280x1024 monitor.
-          Select 25 if you use a 640x480 resolution by default.
 
 config PROM_CONSOLE
 	bool "PROM console"
@@ -102,11 +78,36 @@ config DUMMY_CONSOLE
 	depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y 
 	default y
 
+config DUMMY_CONSOLE_COLUMNS
+        int "Initial number of console screen columns"
+        depends on PARISC && DUMMY_CONSOLE
+        default "160"
+        help
+          The default value is 160, which should fit a 1280x1024 monitor.
+          Select 80 if you use a 640x480 resolution by default.
+
+config DUMMY_CONSOLE_ROWS
+        int "Initial number of console screen rows"
+        depends on PARISC && DUMMY_CONSOLE
+        default "64"
+        help
+          The default value is 64, which should fit a 1280x1024 monitor.
+          Select 25 if you use a 640x480 resolution by default.
+
 config FRAMEBUFFER_CONSOLE
 	tristate "Framebuffer Console support"
 	depends on FB
 	select CRC32
 
+config STI_CONSOLE
+        tristate "STI text console" 
+        depends on PARISC
+        default y
+        help
+          The STI console is the builtin display/keyboard on HP-PARISC
+          machines.  Say Y here to build support for it into your kernel.
+          The alternative is to use your primary serial port as a console.
+
 config FONTS
 	bool "Select compiled-in fonts"
 	depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -21,13 +21,15 @@ font-objs += $(font-objs-y)
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
 obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
-obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o
+obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o font.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
 obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o
-obj-$(CONFIG_FB_TILEBLITTING)     += tileblit.o
+ifeq ($(CONFIG_FB_TILEBLITTING),y)
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
+endif
 
-obj-$(CONFIG_FB_STI)              += sticore.o
+obj-$(CONFIG_FB_STI)              += sticore.o font.o
 
 # Targets that kbuild needs to know about
 targets := promcon_tbl.c
@@ -37,5 +39,5 @@ quiet_cmd_conmakehash = CNMKHSH $@
 		sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \
 		-e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@
 
-$(obj)/promcon_tbl.c: $(src)/prom.uni FORCE
-	$(call if_changed,conmakehash)
+$(obj)/promcon_tbl.c: $(src)/prom.uni
+	$(call cmd,conmakehash)
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -39,7 +39,7 @@ static inline int get_attribute(struct f
 {
 	int attribute = 0;
 
-	if (fb_get_color_depth(info) == 1) {
+	if (fb_get_color_depth(&info->var) == 1) {
 		if (attr_underline(c))
 			attribute |= FBCON_ATTRIBUTE_UNDERLINE;
 		if (attr_reverse(c))
@@ -199,7 +199,10 @@ static void bit_putcs(struct vc_data *vc
 		count -= cnt;
 	}
 
-	if (buf)
+	/* buf is always NULL except when in monochrome mode, so in this case
+	   it's a gain to check buf against NULL even though kfree() handles
+	   NULL pointers just fine */
+	if (unlikely(buf))
 		kfree(buf);
 }
 
@@ -236,7 +239,7 @@ static void bit_clear_margins(struct vc_
 }
 
 static void bit_cursor(struct vc_data *vc, struct fb_info *info,
-		       struct display *p, int mode, int fg, int bg)
+		       struct display *p, int mode, int softback_lines, int fg, int bg)
 {
 	struct fb_cursor cursor;
 	struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
@@ -248,6 +251,15 @@ static void bit_cursor(struct vc_data *v
 
 	cursor.set = 0;
 
+	if (softback_lines) {
+		if (y + softback_lines >= vc->vc_rows) {
+			mode = CM_ERASE;
+			ops->cursor_flash = 0;
+			return;
+		} else
+			y += softback_lines;
+	}
+
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
 	src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
@@ -264,8 +276,7 @@ static void bit_cursor(struct vc_data *v
 		dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
 		if (!dst)
 			return;
-		if (ops->cursor_data)
-			kfree(ops->cursor_data);
+		kfree(ops->cursor_data);
 		ops->cursor_data = dst;
 		update_attr(dst, src, attribute, vc);
 		src = dst;
@@ -312,8 +323,7 @@ static void bit_cursor(struct vc_data *v
 		if (!mask)
 			return;
 
-		if (ops->cursor_state.mask)
-			kfree(ops->cursor_state.mask);
+		kfree(ops->cursor_state.mask);
 		ops->cursor_state.mask = mask;
 
 		p->cursor_shape = vc->vc_cursor_type;
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -42,7 +42,7 @@ static void dummycon_init(struct vc_data
 	vc->vc_cols = DUMMY_COLUMNS;
 	vc->vc_rows = DUMMY_ROWS;
     } else
-	vc_resize(vc->vc_num, DUMMY_COLUMNS, DUMMY_ROWS);
+	vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
 }
 
 static int dummycon_dummy(void)
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,15 +107,15 @@ enum {
 };
 
 struct display fb_display[MAX_NR_CONSOLES];
-signed char con2fb_map[MAX_NR_CONSOLES];
-signed char con2fb_map_boot[MAX_NR_CONSOLES];
+static signed char con2fb_map[MAX_NR_CONSOLES];
+static signed char con2fb_map_boot[MAX_NR_CONSOLES];
 static int logo_height;
 static int logo_lines;
 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
    enums.  */
 static int logo_shown = FBCON_LOGO_CANSHOW;
 /* Software scrollback */
-int fbcon_softback_size = 32768;
+static int fbcon_softback_size = 32768;
 static unsigned long softback_buf, softback_curr;
 static unsigned long softback_in;
 static unsigned long softback_top, softback_end;
@@ -130,6 +130,8 @@ static char fontname[40];
 /* current fb_info */
 static int info_idx = -1;
 
+static const struct consw fb_con;
+
 #define CM_SOFTBACK	(8)
 
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
@@ -182,8 +184,10 @@ static __inline__ void ypan_up(struct vc
 static __inline__ void ypan_down(struct vc_data *vc, int count);
 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
 			    int dy, int dx, int height, int width, u_int y_break);
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc);
-static void fbcon_preset_disp(struct fb_info *info, int unit);
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc);
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
 			      int line, int count, int dy);
 
@@ -202,14 +206,16 @@ static irqreturn_t fb_vbl_detect(int irq
 
 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
 {
+	struct fbcon_ops *ops = info->fbcon_par;
+
 	return (info->state != FBINFO_STATE_RUNNING ||
-		vt_cons[vc->vc_num]->vc_mode != KD_TEXT);
+		vc->vc_mode != KD_TEXT || ops->graphics);
 }
 
 static inline int get_color(struct vc_data *vc, struct fb_info *info,
 	      u16 c, int is_fg)
 {
-	int depth = fb_get_color_depth(info);
+	int depth = fb_get_color_depth(&info->var);
 	int color = 0;
 
 	if (console_blanked) {
@@ -277,7 +283,7 @@ static void fb_flashcursor(void *private
 	c = scr_readw((u16 *) vc->vc_pos);
 	mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
 		CM_ERASE : CM_DRAW;
-	ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1),
+	ops->cursor(vc, info, p, mode, softback_lines, get_color(vc, info, c, 1),
 		    get_color(vc, info, c, 0));
 	release_console_sem();
 }
@@ -305,7 +311,8 @@ static void cursor_timer_handler(unsigne
 	mod_timer(&ops->cursor_timer, jiffies + HZ/5);
 }
 
-int __init fb_console_setup(char *this_opt)
+#ifndef MODULE
+static int __init fb_console_setup(char *this_opt)
 {
 	char *options;
 	int i, j;
@@ -359,6 +366,7 @@ int __init fb_console_setup(char *this_o
 }
 
 __setup("fbcon=", fb_console_setup);
+#endif
 
 static int search_fb_in_map(int idx)
 {
@@ -418,7 +426,7 @@ static void fbcon_prepare_logo(struct vc
 	 * remove underline attribute from erase character
 	 * if black and white framebuffer.
 	 */
-	if (fb_get_color_depth(info) == 1)
+	if (fb_get_color_depth(&info->var) == 1)
 		erase &= ~0x400;
 	logo_height = fb_prepare_logo(info);
 	logo_lines = (logo_height + vc->vc_font.height - 1) /
@@ -456,9 +464,9 @@ static void fbcon_prepare_logo(struct vc
 		    erase,
 		    vc->vc_size_row * logo_lines);
 
-	if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
+	if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
 		fbcon_clear_margins(vc, 0);
-		update_screen(vc->vc_num);
+		update_screen(vc);
 	}
 
 	if (save) {
@@ -591,13 +599,16 @@ static void con2fb_init_display(struct v
 
 	ops->currcon = fg_console;
 
-	if (info->fbops->fb_set_par)
+	if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT))
 		info->fbops->fb_set_par(info);
 
+	ops->flags |= FBCON_FLAGS_INIT;
+	ops->graphics = 0;
+
 	if (vc)
-		fbcon_set_disp(info, vc);
+		fbcon_set_disp(info, &info->var, vc);
 	else
-		fbcon_preset_disp(info, unit);
+		fbcon_preset_disp(info, &info->var, unit);
 
 	if (show_logo) {
 		struct vc_data *fg_vc = vc_cons[fg_console].d;
@@ -609,7 +620,7 @@ static void con2fb_init_display(struct v
 				   fg_vc->vc_rows);
 	}
 
-	switch_screen(fg_console);
+	update_screen(vc_cons[fg_console].d);
 }
 
 /**
@@ -693,6 +704,7 @@ static int var_to_display(struct display
 	disp->green = var->green;
 	disp->blue = var->blue;
 	disp->transp = var->transp;
+	disp->rotate = var->rotate;
 	disp->mode = fb_match_mode(var, &info->modelist);
 	if (disp->mode == NULL)
 		/* This should not happen */
@@ -716,6 +728,7 @@ static void display_to_var(struct fb_var
 	var->green = disp->green;
 	var->blue = disp->blue;
 	var->transp = disp->transp;
+	var->rotate = disp->rotate;
 }
 
 static const char *fbcon_startup(void)
@@ -761,6 +774,7 @@ static const char *fbcon_startup(void)
 
 	memset(ops, 0, sizeof(struct fbcon_ops));
 	ops->currcon = -1;
+	ops->graphics = 1;
 	info->fbcon_par = ops;
 	set_blitting_type(vc, info, NULL);
 
@@ -802,7 +816,7 @@ static const char *fbcon_startup(void)
 
 	cols = info->var.xres / vc->vc_font.width;
 	rows = info->var.yres / vc->vc_font.height;
-	vc_resize(vc->vc_num, cols, rows);
+	vc_resize(vc, cols, rows);
 
 	DPRINTK("mode:   %s\n", info->fix.id);
 	DPRINTK("visual: %d\n", info->fix.visual);
@@ -887,16 +901,19 @@ static const char *fbcon_startup(void)
 static void fbcon_init(struct vc_data *vc, int init)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops;
 	struct vc_data **default_mode = vc->vc_display_fg;
 	struct vc_data *svc = *default_mode;
 	struct display *t, *p = &fb_display[vc->vc_num];
-	int display_fg = (*default_mode)->vc_num;
 	int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
-	int cap = info->flags;
+	int cap;
 
 	if (info_idx == -1 || info == NULL)
 	    return;
-	if (vc->vc_num != display_fg || logo_shown == FBCON_LOGO_DONTSHOW ||
+
+	cap = info->flags;
+
+	if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
 	    (info->fix.type == FB_TYPE_TEXT))
 		logo = 0;
 
@@ -907,7 +924,7 @@ static void fbcon_init(struct vc_data *v
 
 	/* If we are not the first console on this
 	   fb, copy the font from that console */
-	t = &fb_display[display_fg];
+	t = &fb_display[svc->vc_num];
 	if (!vc->vc_font.data) {
 		vc->vc_font.data = p->fontdata = t->fontdata;
 		vc->vc_font.width = (*default_mode)->vc_font.width;
@@ -918,7 +935,7 @@ static void fbcon_init(struct vc_data *v
 	}
 	if (p->userfont)
 		charcnt = FNTCHARCNT(p->fontdata);
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (charcnt == 256) {
 		vc->vc_hi_font_mask = 0;
@@ -929,15 +946,17 @@ static void fbcon_init(struct vc_data *v
 	}
 
 	if (!*svc->vc_uni_pagedir_loc)
-		con_set_default_unimap(display_fg);
+		con_set_default_unimap(svc);
 	if (!*vc->vc_uni_pagedir_loc)
-		con_copy_unimap(vc->vc_num, display_fg);
+		con_copy_unimap(vc, svc);
 
 	cols = vc->vc_cols;
 	rows = vc->vc_rows;
 	new_cols = info->var.xres / vc->vc_font.width;
 	new_rows = info->var.yres / vc->vc_font.height;
-	vc_resize(vc->vc_num, new_cols, new_rows);
+	vc_resize(vc, new_cols, new_rows);
+
+	ops = info->fbcon_par;
 	/*
 	 * We must always set the mode. The mode of the previous console
 	 * driver could be in the same resolution but we are using different
@@ -945,9 +964,14 @@ static void fbcon_init(struct vc_data *v
 	 *
 	 * We need to do it in fbcon_init() to prevent screen corruption.
 	 */
-	if (CON_IS_VISIBLE(vc) && info->fbops->fb_set_par)
-		info->fbops->fb_set_par(info);
+	if (CON_IS_VISIBLE(vc)) {
+		if (info->fbops->fb_set_par &&
+		    !(ops->flags & FBCON_FLAGS_INIT))
+			info->fbops->fb_set_par(info);
+		ops->flags |= FBCON_FLAGS_INIT;
+	}
 
+	ops->graphics = 0;
 
 	if ((cap & FBINFO_HWACCEL_COPYAREA) &&
 	    !(cap & FBINFO_HWACCEL_DISABLED))
@@ -968,7 +992,7 @@ static void fbcon_init(struct vc_data *v
 	if (logo)
 		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-	if (vc->vc_num == display_fg && softback_buf) {
+	if (vc == svc && softback_buf) {
 		int l = fbcon_softback_size / vc->vc_size_row;
 		if (l > 5)
 			softback_end = softback_buf + l * vc->vc_size_row;
@@ -1085,27 +1109,23 @@ static void fbcon_cursor(struct vc_data 
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
-	int y = real_y(p, vc->vc_y);
+	int y;
  	int c = scr_readw((u16 *) vc->vc_pos);
 
 	if (fbcon_is_inactive(vc, info))
 		return;
 
-	ops->cursor_flash = 1;
+	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
 	if (mode & CM_SOFTBACK) {
 		mode &= ~CM_SOFTBACK;
-		if (softback_lines) {
-			if (y + softback_lines >= vc->vc_rows) {
-				mode = CM_ERASE;
-				ops->cursor_flash = 0;
-			}
-			else
-				y += softback_lines;
-		}
-	} else if (softback_lines)
-		fbcon_set_origin(vc);
+		y = softback_lines;
+	} else {
+		if (softback_lines)
+			fbcon_set_origin(vc);
+		y = 0;
+	}
 
-	ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1),
+	ops->cursor(vc, info, p, mode, y, get_color(vc, info, c, 1),
 		    get_color(vc, info, c, 0));
 	vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
@@ -1114,7 +1134,7 @@ static int scrollback_phys_max = 0;
 static int scrollback_max = 0;
 static int scrollback_current = 0;
 
-int update_var(int con, struct fb_info *info)
+static int update_var(int con, struct fb_info *info)
 {
 	if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
 		return fb_pan_display(info, &info->var);
@@ -1124,13 +1144,14 @@ int update_var(int con, struct fb_info *
 /*
  * If no vc is existent yet, just set struct display
  */
-static void fbcon_preset_disp(struct fb_info *info, int unit)
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit)
 {
 	struct display *p = &fb_display[unit];
 	struct display *t = &fb_display[fg_console];
 
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-	if (var_to_display(p, &info->var, info))
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
 		return;
 
 	p->fontdata = t->fontdata;
@@ -1139,18 +1160,18 @@ static void fbcon_preset_disp(struct fb_
 		REFCOUNT(p->fontdata)++;
 }
 
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc)
 {
 	struct display *p = &fb_display[vc->vc_num], *t;
 	struct vc_data **default_mode = vc->vc_display_fg;
 	struct vc_data *svc = *default_mode;
-	int display_fg = (*default_mode)->vc_num;
 	int rows, cols, charcnt = 256;
 
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-	if (var_to_display(p, &info->var, info))
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
 		return;
-	t = &fb_display[display_fg];
+	t = &fb_display[svc->vc_num];
 	if (!vc->vc_font.data) {
 		vc->vc_font.data = p->fontdata = t->fontdata;
 		vc->vc_font.width = (*default_mode)->vc_font.width;
@@ -1162,7 +1183,7 @@ static void fbcon_set_disp(struct fb_inf
 	if (p->userfont)
 		charcnt = FNTCHARCNT(p->fontdata);
 
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (charcnt == 256) {
 		vc->vc_hi_font_mask = 0;
@@ -1173,15 +1194,15 @@ static void fbcon_set_disp(struct fb_inf
 	}
 
 	if (!*svc->vc_uni_pagedir_loc)
-		con_set_default_unimap(display_fg);
+		con_set_default_unimap(svc);
 	if (!*vc->vc_uni_pagedir_loc)
-		con_copy_unimap(vc->vc_num, display_fg);
+		con_copy_unimap(vc, svc);
 
-	cols = info->var.xres / vc->vc_font.width;
-	rows = info->var.yres / vc->vc_font.height;
-	vc_resize(vc->vc_num, cols, rows);
+	cols = var->xres / vc->vc_font.width;
+	rows = var->yres / vc->vc_font.height;
+	vc_resize(vc, cols, rows);
 	if (CON_IS_VISIBLE(vc)) {
-		update_screen(vc->vc_num);
+		update_screen(vc);
 		if (softback_buf) {
 			int l = fbcon_softback_size / vc->vc_size_row;
 
@@ -1873,7 +1894,6 @@ static int fbcon_resize(struct vc_data *
 			var.activate = FB_ACTIVATE_NOW |
 				FB_ACTIVATE_FORCE;
 			fb_set_var(info, &var);
-			info->flags &= ~FBINFO_MISC_MODESWITCH;
 		}
 		var_to_display(p, &info->var, info);
 	}
@@ -1886,7 +1906,7 @@ static int fbcon_switch(struct vc_data *
 	struct fb_info *info;
 	struct display *p = &fb_display[vc->vc_num];
 	struct fb_var_screeninfo var;
-	int i, prev_console, do_set_par = 0;
+	int i, prev_console;
 
 	info = registered_fb[con2fb_map[vc->vc_num]];
 
@@ -1945,19 +1965,14 @@ static int fbcon_switch(struct vc_data *
 	fb_set_var(info, &var);
 
 	if (prev_console != -1 &&
-	    registered_fb[con2fb_map[prev_console]] != info)
-		do_set_par = 1;
-
-	if (do_set_par || info->flags & FBINFO_MISC_MODESWITCH) {
-		if (info->fbops->fb_set_par)
-			info->fbops->fb_set_par(info);
-		info->flags &= ~FBINFO_MISC_MODESWITCH;
-	}
+	    registered_fb[con2fb_map[prev_console]] != info &&
+	    info->fbops->fb_set_par)
+		info->fbops->fb_set_par(info);
 
 	set_blitting_type(vc, info, p);
 	((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
 
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	updatescrollmode(p, info, vc);
 
@@ -1987,7 +2002,7 @@ static int fbcon_switch(struct vc_data *
 		logo_shown = fg_console;
 		/* This is protected above by initmem_freed */
 		fb_show_logo(info);
-		update_region(fg_console,
+		update_region(vc,
 			      vc->vc_origin + vc->vc_size_row * vc->vc_top,
 			      vc->vc_size_row * (vc->vc_bottom -
 						 vc->vc_top) / 2);
@@ -2015,29 +2030,20 @@ static int fbcon_blank(struct vc_data *v
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	struct fbcon_ops *ops = info->fbcon_par;
-	int active = !fbcon_is_inactive(vc, info);
 
 	if (mode_switch) {
 		struct fb_var_screeninfo var = info->var;
-/*
- * HACK ALERT: Some hardware will require reinitializion at this stage,
- *             others will require it to be done as late as possible.
- *             For now, we differentiate this with the
- *             FBINFO_MISC_MODESWITCHLATE bitflag.  Worst case will be
- *             hardware that requires it here and another one later.
- *             A definitive solution may require fixing X or the VT
- *             system.
- */
-		if (info->flags & FBINFO_MISC_MODESWITCHLATE)
-			info->flags |= FBINFO_MISC_MODESWITCH;
 
-		if (!blank && !(info->flags & FBINFO_MISC_MODESWITCHLATE)) {
+		ops->graphics = 1;
+
+		if (!blank) {
 			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
 			fb_set_var(info, &var);
+			ops->graphics = 0;
 		}
 	}
 
- 	if (active) {
+ 	if (!fbcon_is_inactive(vc, info)) {
 		if (ops->blank_state != blank) {
 			ops->blank_state = blank;
 			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
@@ -2048,7 +2054,7 @@ static int fbcon_blank(struct vc_data *v
 		}
 
  		if (!blank)
- 			update_screen(vc->vc_num);
+ 			update_screen(vc);
  	}
 
  	return 0;
@@ -2198,7 +2204,7 @@ static int fbcon_do_set_font(struct vc_d
 	if (resize) {
 		/* reset wrap/pan */
 		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-		vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h);
+		vc_resize(vc, info->var.xres / w, info->var.yres / h);
 		if (CON_IS_VISIBLE(vc) && softback_buf) {
 			int l = fbcon_softback_size / vc->vc_size_row;
 			if (l > 5)
@@ -2211,9 +2217,9 @@ static int fbcon_do_set_font(struct vc_d
 			}
 		}
 	} else if (CON_IS_VISIBLE(vc)
-		   && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
+		   && vc->vc_mode == KD_TEXT) {
 		fbcon_clear_margins(vc, 0);
-		update_screen(vc->vc_num);
+		update_screen(vc);
 	}
 
 	if (old_data && (--REFCOUNT(old_data) == 0))
@@ -2328,7 +2334,10 @@ static int fbcon_set_palette(struct vc_d
 	if (fbcon_is_inactive(vc, info))
 		return -EINVAL;
 
-	depth = fb_get_color_depth(info);
+	if (!CON_IS_VISIBLE(vc))
+		return 0;
+
+	depth = fb_get_color_depth(&info->var);
 	if (depth > 3) {
 		for (i = j = 0; i < 16; i++) {
 			k = table[i];
@@ -2438,7 +2447,7 @@ static int fbcon_scrolldelta(struct vc_d
 	if (softback_top) {
 		if (vc->vc_num != fg_console)
 			return 0;
-		if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT || !lines)
+		if (vc->vc_mode != KD_TEXT || !lines)
 			return 0;
 		if (logo_shown >= 0) {
 			struct vc_data *conp2 = vc_cons[logo_shown].d;
@@ -2464,7 +2473,7 @@ static int fbcon_scrolldelta(struct vc_d
 						    vc->vc_size_row);
 				}
 				softback_in = p;
-				update_region(vc->vc_num, vc->vc_origin,
+				update_region(vc, vc->vc_origin,
 					      logo_lines * vc->vc_cols);
 			}
 			logo_shown = FBCON_LOGO_CANSHOW;
@@ -2545,7 +2554,7 @@ static void fbcon_resumed(struct fb_info
 		return;
 	vc = vc_cons[ops->currcon].d;
 
-	update_screen(vc->vc_num);
+	update_screen(vc);
 }
 
 static void fbcon_modechanged(struct fb_info *info)
@@ -2555,11 +2564,11 @@ static void fbcon_modechanged(struct fb_
 	struct display *p;
 	int rows, cols;
 
-	if (!ops || ops->currcon < 0 || vt_cons[ops->currcon]->vc_mode !=
-	    KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+	if (!ops || ops->currcon < 0)
 		return;
-
 	vc = vc_cons[ops->currcon].d;
+	if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+		return;
 
 	p = &fb_display[vc->vc_num];
 
@@ -2569,13 +2578,13 @@ static void fbcon_modechanged(struct fb_
 		var_to_display(p, &info->var, info);
 		cols = info->var.xres / vc->vc_font.width;
 		rows = info->var.yres / vc->vc_font.height;
-		vc_resize(vc->vc_num, cols, rows);
+		vc_resize(vc, cols, rows);
 		updatescrollmode(p, info, vc);
 		scrollback_max = 0;
 		scrollback_current = 0;
 		update_var(vc->vc_num, info);
 		fbcon_set_palette(vc, color_table);
-		update_screen(vc->vc_num);
+		update_screen(vc);
 		if (softback_buf) {
 			int l = fbcon_softback_size / vc->vc_size_row;
 			if (l > 5)
@@ -2641,25 +2650,47 @@ static int fbcon_fb_registered(int idx)
 static void fbcon_fb_blanked(struct fb_info *info, int blank)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
-	int valid = 1;
+	struct vc_data *vc;
 
-	if (!ops || ops->currcon < 0 ||
-	    vt_cons[ops->currcon]->vc_mode != KD_TEXT ||
-	    registered_fb[con2fb_map[ops->currcon]] != info)
-		valid = 0;
+	if (!ops || ops->currcon < 0)
+		return;
 
-	if (valid) {
-		struct vc_data *vc;
+	vc = vc_cons[ops->currcon].d;
+	if (vc->vc_mode != KD_TEXT ||
+			registered_fb[con2fb_map[ops->currcon]] != info)
+		return;
 
-		vc = vc_cons[ops->currcon].d;
+	if (CON_IS_VISIBLE(vc)) {
+		if (blank)
+			do_blank_screen(0);
+		else
+			do_unblank_screen(0);
+	}
+	ops->blank_state = blank;
+}
+
+static void fbcon_new_modelist(struct fb_info *info)
+{
+	int i;
+	struct vc_data *vc;
+	struct fb_var_screeninfo var;
+	struct fb_videomode *mode;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (registered_fb[con2fb_map[i]] != info)
+			continue;
+		if (!fb_display[i].mode)
+			continue;
+		vc = vc_cons[i].d;
+		display_to_var(&var, &fb_display[i]);
+		mode = fb_find_nearest_mode(&var, &info->modelist);
+		fb_videomode_to_var(&var, mode);
+
+		if (vc)
+			fbcon_set_disp(info, &var, vc);
+		else
+			fbcon_preset_disp(info, &var, i);
 
-		if (CON_IS_VISIBLE(vc)) {
-			if (blank)
-				do_blank_screen(0);
-			else
-				do_unblank_screen(0);
-		}
-		ops->blank_state = blank;
 	}
 }
 
@@ -2701,6 +2732,9 @@ static int fbcon_event_notify(struct not
 	case FB_EVENT_BLANK:
 		fbcon_fb_blanked(info, *(int *)event->data);
 		break;
+	case FB_EVENT_NEW_MODELIST:
+		fbcon_new_modelist(info);
+		break;
 	}
 
 	return ret;
@@ -2710,7 +2744,7 @@ static int fbcon_event_notify(struct not
  *  The console `switch' structure for the frame buffer based console
  */
 
-const struct consw fb_con = {
+static const struct consw fb_con = {
 	.owner			= THIS_MODULE,
 	.con_startup 		= fbcon_startup,
 	.con_init 		= fbcon_init,
@@ -2740,7 +2774,7 @@ static struct notifier_block fbcon_event
 	.notifier_call	= fbcon_event_notify,
 };
 
-int __init fb_console_init(void)
+static int __init fb_console_init(void)
 {
 	int i;
 
@@ -2768,7 +2802,7 @@ module_init(fb_console_init);
 
 #ifdef MODULE
 
-void __exit fb_console_exit(void)
+static void __exit fb_console_exit(void)
 {
 	acquire_console_sem();
 	fb_unregister_client(&fbcon_event_notifier);
@@ -2780,10 +2814,4 @@ module_exit(fb_console_exit);
 
 #endif
 
-/*
- *  Visible symbols for modules
- */
-
-EXPORT_SYMBOL(fb_con);
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -18,6 +18,8 @@
 
 #include <asm/io.h>
 
+#define FBCON_FLAGS_INIT 1
+
    /*
     *    This is the interface between the low-level console driver and the
     *    low-level frame buffer device
@@ -41,6 +43,7 @@ struct display {
     u32 grayscale;
     u32 nonstd;
     u32 accel_flags;
+    u32 rotate;
     struct fb_bitfield red;
     struct fb_bitfield green;
     struct fb_bitfield blue;
@@ -59,7 +62,7 @@ struct fbcon_ops {
 	void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
 			      int bottom_only);
 	void (*cursor)(struct vc_data *vc, struct fb_info *info,
-		       struct display *p, int mode, int fg, int bg);
+		       struct display *p, int mode, int softback_lines, int fg, int bg);
 
 	struct timer_list cursor_timer; /* Cursor timer */
 	struct fb_cursor cursor_state;
@@ -67,6 +70,8 @@ struct fbcon_ops {
 	int    cursor_flash;
 	int    cursor_reset;
 	int    blank_state;
+	int    graphics;
+	int    flags;
 	char  *cursor_data;
 };
     /*
@@ -156,13 +161,10 @@ struct fbcon_ops {
 #define SCROLL_REDRAW	   0x004
 #define SCROLL_PAN_REDRAW  0x005
 
-extern int fb_console_init(void);
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
 			      struct display *p, struct fbcon_ops *ops);
 #endif
 extern void fbcon_set_bitops(struct fbcon_ops *ops);
 
-extern const struct consw fb_con;
-
 #endif /* _VIDEO_FBCON_H */
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -351,10 +351,9 @@ static void mdacon_init(struct vc_data *
 	if (init) {
 		c->vc_cols = mda_num_columns;
 		c->vc_rows = mda_num_lines;
-	} else {
-		vc_resize(c->vc_num, mda_num_columns, mda_num_lines);
-        }
-	
+	} else
+		vc_resize(c, mda_num_columns, mda_num_lines);
+
 	/* make the first MDA console visible */
 
 	if (mda_display_fg == NULL)
@@ -565,7 +564,7 @@ static int mdacon_scroll(struct vc_data 
  *  The console `switch' structure for the MDA based console
  */
 
-const struct consw mda_con = {
+static const struct consw mda_con = {
 	.owner =		THIS_MODULE,
 	.con_startup =		mdacon_startup,
 	.con_init =		mdacon_init,
@@ -592,7 +591,7 @@ int __init mda_console_init(void)
 	return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
 }
 
-void __exit mda_console_exit(void)
+static void __exit mda_console_exit(void)
 {
 	give_up_console(&mda_con);
 }
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -155,9 +155,9 @@ promcon_init_unimap(struct vc_data *conp
 			k++;
 		}
 	set_fs(KERNEL_DS);
-	con_clear_unimap(conp->vc_num, NULL);
-	con_set_unimap(conp->vc_num, k, p);
-	con_protect_unimap(conp->vc_num, 1);
+	con_clear_unimap(conp, NULL);
+	con_set_unimap(conp, k, p);
+	con_protect_unimap(conp, 1);
 	set_fs(old_fs);
 	kfree(p);
 }
@@ -175,7 +175,7 @@ promcon_init(struct vc_data *conp, int i
 	p = *conp->vc_uni_pagedir_loc;
 	if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
 	    !--conp->vc_uni_pagedir_loc[1])
-		con_free_unimap(conp->vc_num);
+		con_free_unimap(conp);
 	conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
 	promcon_uni_pagedir[1]++;
 	if (!promcon_uni_pagedir[0] && p) {
@@ -183,7 +183,7 @@ promcon_init(struct vc_data *conp, int i
 	}
 	if (!init) {
 		if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
-			vc_resize(conp->vc_num, pw + 1, ph + 1);
+			vc_resize(conp, pw + 1, ph + 1);
 	}
 }
 
@@ -192,9 +192,9 @@ promcon_deinit(struct vc_data *conp)
 {
 	/* When closing the last console, reset video origin */
 	if (!--promcon_uni_pagedir[1])
-		con_free_unimap(conp->vc_num);
+		con_free_unimap(conp);
 	conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
-	con_set_default_unimap(conp->vc_num);
+	con_set_default_unimap(conp);
 }
 
 static int
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -87,13 +87,12 @@ static int sticon_set_palette(struct vc_
 
 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)
+
+    if (conp->vc_mode != KD_TEXT)
     	    return;
 #if 0
     if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
@@ -111,15 +110,14 @@ static void sticon_putc(struct vc_data *
 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)
+    if (conp->vc_mode != KD_TEXT)
     	    return;
-    
+
 #if 0
     if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
 	(p->cursor_x < (xpos + count))) {
@@ -217,7 +215,7 @@ static void sticon_init(struct vc_data *
     } 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(c->vc_num, vc_cols, vc_rows); 
+	vc_resize(c, vc_cols, vc_rows);
 /*	vc_resize_con(vc_rows, vc_cols, c->vc_num); */
     }
 }
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -249,13 +249,13 @@ sti_rom_copy(unsigned long base, unsigne
 	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
 	while (count >= 4) {
 		count -= 4;
-		*(u32 *)dest = __raw_readl(base);
+		*(u32 *)dest = gsc_readl(base);
 		base += 4;
 		dest += 4;
 	}
 	while (count) {
 		count--;
-		*(u8 *)dest = __raw_readb(base);
+		*(u8 *)dest = gsc_readb(base);
 		base++;
 		dest++;
 	}
@@ -460,12 +460,20 @@ sti_init_glob_cfg(struct sti_struct *sti
 		/* remap virtually */
 		/* FIXME: add BTLB support if btlb==1 */
 		len = sti->regions[i].region_desc.length * 4096;
-		
+
+/* XXX: Enabling IOREMAP debugging causes a crash, so we must be passing
+ * a virtual address to something expecting a physical address that doesn't
+ * go through a readX macro */
+#if 0
 		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) );
+#else
+		if (len)
+			glob_cfg->region_ptrs[i] = sti->regions_phys[i];
+#endif
 		
 		DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, "
 			 "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
@@ -680,7 +688,7 @@ sti_bmode_rom_copy(unsigned long base, u
 
 	while (count) {
 		count--;
-		*(u8 *)dest = __raw_readl(base);
+		*(u8 *)dest = gsc_readl(base);
 		base += 4;
 		dest++;
 	}
@@ -730,7 +738,7 @@ sti_get_wmode_rom (unsigned long address
 	unsigned long size;
     
 	/* read the ROM size directly from the struct in ROM */ 
-	size = __raw_readl(address + offsetof(struct sti_rom,last_addr));
+	size = gsc_readl(address + offsetof(struct sti_rom,last_addr));
 
 	raw = kmalloc(size, GFP_KERNEL);
 	if(raw)
@@ -790,11 +798,8 @@ sti_read_rom(int wordmode, struct sti_st
 	return 1;
 
 out_err:
-	if(raw)
-		kfree(raw);
-	if(cooked)
-		kfree(cooked);
-
+	kfree(raw);
+	kfree(cooked);
 	return 0;
 }
 
@@ -825,13 +830,13 @@ test_rom:
 	if (pdc_add_valid(address))
 		goto out_err;
 
-	sig = __raw_readl(address);
+	sig = gsc_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);
+		i = gsc_readl(address+0x04);
 		if (i != 1) {
 			/* The ROM could have multiple architecture 
 			 * dependent images (e.g. i386, parisc,...) */
@@ -842,17 +847,17 @@ test_rom:
 		
 		sti->pd = pd;
 
-		i = __raw_readl(address+0x0c);
+		i = gsc_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);
+			*rm++ = gsc_readl(address+rm_offset+0x00);
+			*rm++ = gsc_readl(address+rm_offset+0x04);
+			*rm++ = gsc_readl(address+rm_offset+0x08);
+			*rm++ = gsc_readl(address+rm_offset+0x0c);
 			DPRINTK(("PCI region Mapper offset = %08x: ",
 				rm_offset));
 			for (i=0; i<16; i++)
@@ -860,7 +865,7 @@ test_rom:
 			DPRINTK(("\n"));
 		}
 
-		address += le32_to_cpu(__raw_readl(address+8));
+		address += le32_to_cpu(gsc_readl(address+8));
 		DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address));
 		goto test_rom;
 	}
@@ -1003,17 +1008,17 @@ static void __devexit sticore_pci_remove
 
 
 static struct pci_device_id sti_pci_tbl[] = {
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_EG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FXE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_EG) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX2) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FXE) },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, sti_pci_tbl);
 
 static struct pci_driver pci_sti_driver = {
-	.name		= "sti (pci)",
+	.name		= "sti",
 	.id_table	= sti_pci_tbl,
 	.probe		= sticore_pci_init,
 	.remove		= sticore_pci_remove,
@@ -1026,7 +1031,7 @@ static struct parisc_device_id sti_pa_tb
 };
 
 static struct parisc_driver pa_sti_driver = {
-	.name		= "sti (native)",
+	.name		= "sti",
 	.id_table	= sti_pa_tbl,
 	.probe		= sticore_pa_init,
 };
@@ -1050,7 +1055,7 @@ static void __init sti_init_roms(void)
 
 	/* Register drivers for native & PCI cards */
 	register_parisc_driver(&pa_sti_driver);
-	pci_module_init(&pci_sti_driver);
+	pci_register_driver(&pci_sti_driver);
 
 	/* if we didn't find the given default sti, take the first one */
 	if (!default_sti)
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -81,7 +81,8 @@ static void tile_clear_margins(struct vc
 }
 
 static void tile_cursor(struct vc_data *vc, struct fb_info *info,
-			struct display *p, int mode, int fg, int bg)
+			struct display *p, int mode, int softback_lines,
+			int fg, int bg)
 {
 	struct fb_tilecursor cursor;
 	int use_sw = (vc->vc_cursor_type & 0x01);
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -337,14 +337,16 @@ static void vgacon_init(struct vc_data *
 	c->vc_scan_lines = vga_scan_lines;
 	c->vc_font.height = vga_video_font_height;
 	c->vc_complement_mask = 0x7700;
+	if (vga_512_chars)
+		c->vc_hi_font_mask = 0x0800;
 	p = *c->vc_uni_pagedir_loc;
 	if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
 	    !--c->vc_uni_pagedir_loc[1])
-		con_free_unimap(c->vc_num);
+		con_free_unimap(c);
 	c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
 	vgacon_uni_pagedir[1]++;
 	if (!vgacon_uni_pagedir[0] && p)
-		con_set_default_unimap(c->vc_num);
+		con_set_default_unimap(c);
 }
 
 static inline void vga_set_mem_top(struct vc_data *c)
@@ -358,10 +360,10 @@ static void vgacon_deinit(struct vc_data
 	if (!--vgacon_uni_pagedir[1]) {
 		c->vc_visible_origin = vga_vram_base;
 		vga_set_mem_top(c);
-		con_free_unimap(c->vc_num);
+		con_free_unimap(c);
 	}
 	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
-	con_set_default_unimap(c->vc_num);
+	con_set_default_unimap(c);
 }
 
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
@@ -908,7 +910,7 @@ static int vgacon_adjust_height(struct v
 				c->vc_sw->con_cursor(c, CM_DRAW);
 			}
 			c->vc_font.height = fontheight;
-			vc_resize(c->vc_num, 0, rows);	/* Adjust console size */
+			vc_resize(c, 0, rows);	/* Adjust console size */
 		}
 	}
 	return 0;
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -315,7 +315,7 @@ static int controlfb_mmap(struct fb_info
        		return -EINVAL;
        off += start;
        vma->vm_pgoff = off >> PAGE_SHIFT;
-       if (io_remap_page_range(vma, vma->vm_start, off,
+       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
            vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
 
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -90,9 +90,10 @@ struct cfb_info {
 	 */
 	u_char			ramdac_ctrl;
 	u_char			ramdac_powerdown;
+
+	u32			pseudo_palette[16];
 };
 
-static char default_font_storage[40];
 static char *default_font = "Acorn8x8";
 module_param(default_font, charp, 0);
 MODULE_PARM_DESC(default_font, "Default font name");
@@ -1224,9 +1225,7 @@ cyberpro_alloc_fb_info(unsigned int id, 
 {
 	struct cfb_info *cfb;
 
-	cfb = kmalloc(sizeof(struct cfb_info) +
-		       sizeof(u32) * 16, GFP_KERNEL);
-
+	cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL);
 	if (!cfb)
 		return NULL;
 
@@ -1282,7 +1281,7 @@ cyberpro_alloc_fb_info(unsigned int id, 
 
 	cfb->fb.fbops		= &cyber2000fb_ops;
 	cfb->fb.flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-	cfb->fb.pseudo_palette	= (void *)(cfb + 1);
+	cfb->fb.pseudo_palette	= cfb->pseudo_palette;
 
 	fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
 
@@ -1306,7 +1305,8 @@ cyberpro_free_fb_info(struct cfb_info *c
  * Parse Cyber2000fb options.  Usage:
  *  video=cyber2000:font:fontname
  */
-int
+#ifndef MODULE
+static int
 cyber2000fb_setup(char *options)
 {
 	char *opt;
@@ -1319,6 +1319,8 @@ cyber2000fb_setup(char *options)
 			continue;
 
 		if (strncmp(opt, "font:", 5) == 0) {
+			static char default_font_storage[40];
+
 			strlcpy(default_font_storage, opt + 5, sizeof(default_font_storage));
 			default_font = default_font_storage;
 			continue;
@@ -1328,6 +1330,7 @@ cyber2000fb_setup(char *options)
 	}
 	return 0;
 }
+#endif  /*  MODULE  */
 
 /*
  * The CyberPro chips can be placed on many different bus types.
@@ -1665,7 +1668,7 @@ static void __devexit cyberpro_pci_remov
 	}
 }
 
-static int cyberpro_pci_suspend(struct pci_dev *dev, u32 state)
+static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	return 0;
 }
@@ -1717,7 +1720,7 @@ static struct pci_driver cyberpro_driver
  *
  * Tony: "module_init" is now required
  */
-int __init cyber2000fb_init(void)
+static int __init cyber2000fb_init(void)
 {
 	int ret = -1, err;
 
@@ -1737,7 +1740,7 @@ int __init cyber2000fb_init(void)
 	}
 #endif
 #ifdef CONFIG_PCI
-	err = pci_module_init(&cyberpro_driver);
+	err = pci_register_driver(&cyberpro_driver);
 	if (!err)
 		ret = 0;
 #endif
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -222,8 +222,11 @@ int fb_set_cmap(struct fb_cmap *cmap, st
 	transp = cmap->transp;
 	start = cmap->start;
 
-	if (start < 0 || !info->fbops->fb_setcolreg)
+	if (start < 0 || (!info->fbops->fb_setcolreg &&
+			  !info->fbops->fb_setcmap))
 		return -EINVAL;
+	if (info->fbops->fb_setcmap)
+		return info->fbops->fb_setcmap(cmap, info);
 	for (i = 0; i < cmap->len; i++) {
 		hred = *red++;
 		hgreen = *green++;
@@ -250,8 +253,33 @@ int fb_set_user_cmap(struct fb_cmap_user
 	transp = cmap->transp;
 	start = cmap->start;
 
-	if (start < 0 || !info->fbops->fb_setcolreg)
+	if (start < 0 || (!info->fbops->fb_setcolreg &&
+			  !info->fbops->fb_setcmap))
 		return -EINVAL;
+
+	/* If we can batch, do it */
+	if (info->fbops->fb_setcmap && cmap->len > 1) {
+		struct fb_cmap umap;
+		int size = cmap->len * sizeof(u16);
+		int rc;
+
+		memset(&umap, 0, sizeof(struct fb_cmap));
+		rc = fb_alloc_cmap(&umap, cmap->len, transp != NULL);
+		if (rc)
+			return rc;
+		if (copy_from_user(umap.red, red, size) ||
+		    copy_from_user(umap.green, green, size) ||
+		    copy_from_user(umap.blue, blue, size) ||
+		    (transp && copy_from_user(umap.transp, transp, size))) {
+			rc = -EFAULT;
+		}
+		umap.start = start;
+		if (rc == 0)
+			rc = info->fbops->fb_setcmap(&umap, info);
+		fb_dealloc_cmap(&umap);
+		return rc;
+	}
+
 	for (i = 0; i < cmap->len; i++, red++, blue++, green++) {
 		if (get_user(hred, red) ||
 		    get_user(hgreen, green) ||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -62,10 +62,8 @@ int num_registered_fb;
  * Helpers
  */
 
-int fb_get_color_depth(struct fb_info *info)
+int fb_get_color_depth(struct fb_var_screeninfo *var)
 {
-	struct fb_var_screeninfo *var = &info->var;
-
 	if (var->green.length == var->blue.length &&
 	    var->green.length == var->red.length &&
 	    !var->green.offset && !var->blue.offset &&
@@ -300,7 +298,7 @@ static void fb_set_logo(struct fb_info *
 	const u8 *src = logo->data;
 	u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
 
-	if (fb_get_color_depth(info) == 3)
+	if (fb_get_color_depth(&info->var) == 3)
 		fg = 7;
 
 	switch (depth) {
@@ -365,7 +363,7 @@ static struct logo_data {
 
 int fb_prepare_logo(struct fb_info *info)
 {
-	int depth = fb_get_color_depth(info);
+	int depth = fb_get_color_depth(&info->var);
 
 	memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -448,8 +446,7 @@ int fb_show_logo(struct fb_info *info)
 		logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, 
 				   GFP_KERNEL);
 		if (logo_new == NULL) {
-			if (palette)
-				kfree(palette);
+			kfree(palette);
 			if (saved_pseudo_palette)
 				info->pseudo_palette = saved_pseudo_palette;
 			return 0;
@@ -468,12 +465,10 @@ int fb_show_logo(struct fb_info *info)
 		info->fbops->fb_imageblit(info, &image);
 	}
 	
-	if (palette != NULL)
-		kfree(palette);
+	kfree(palette);
 	if (saved_pseudo_palette != NULL)
 		info->pseudo_palette = saved_pseudo_palette;
-	if (logo_new != NULL)
-		kfree(logo_new);
+	kfree(logo_new);
 	return fb_logo.logo->height;
 }
 #else
@@ -876,7 +871,8 @@ fb_compat_ioctl(struct file *file, unsig
 	int fbidx = iminor(file->f_dentry->d_inode);
 	struct fb_info *info = registered_fb[fbidx];
 	struct fb_ops *fb = info->fbops;
-	int ret;
+	long ret;
+
 	if (fb->fb_compat_ioctl == NULL)
 		return -ENOIOCTLCMD;
 	lock_kernel();
@@ -941,8 +937,8 @@ fb_mmap(struct file *file, struct vm_are
 	/* This is an IO map - tell maydump to skip this VMA */
 	vma->vm_flags |= VM_IO | VM_RESERVED;
 #if defined(__sparc_v9__)
-	if (io_remap_page_range(vma, vma->vm_start, off,
-				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 #else
 #if defined(__mc68000__)
@@ -958,7 +954,9 @@ fb_mmap(struct file *file, struct vm_are
 	}
 #endif
 #elif defined(__powerpc__)
-	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+	vma->vm_page_prot = phys_mem_access_prot(file, off,
+						 vma->vm_end - vma->vm_start,
+						 vma->vm_page_prot);
 #elif defined(__alpha__)
 	/* Caching is off in the I/O space quadrant by design.  */
 #elif defined(__i386__) || defined(__x86_64__)
@@ -978,7 +976,7 @@ fb_mmap(struct file *file, struct vm_are
 #else
 #warning What do we have to do here??
 #endif
-	if (io_remap_page_range(vma, vma->vm_start, off,
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 #endif /* !__sparc_v9__ */
@@ -1058,7 +1056,6 @@ int
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1069,13 +1066,15 @@ register_framebuffer(struct fb_info *fb_
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1134,6 +1133,7 @@ unregister_framebuffer(struct fb_info *f
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
 	return 0;
 }
@@ -1188,7 +1188,7 @@ void fb_set_suspend(struct fb_info *info
  *
  */
 
-int __init
+static int __init
 fbmem_init(void)
 {
 	create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
@@ -1204,16 +1204,67 @@ fbmem_init(void)
 	}
 	return 0;
 }
+
+#ifdef MODULE
+module_init(fbmem_init);
+static void __exit
+fbmem_exit(void)
+{
+	class_simple_destroy(fb_class);
+}
+
+module_exit(fbmem_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer base");
+#else
 subsys_initcall(fbmem_init);
+#endif
+
+int fb_new_modelist(struct fb_info *info)
+{
+	struct fb_event event;
+	struct fb_var_screeninfo var = info->var;
+	struct list_head *pos, *n;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m, mode;
+	int err = 1;
+
+	list_for_each_safe(pos, n, &info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		fb_videomode_to_var(&var, m);
+		var.activate = FB_ACTIVATE_TEST;
+		err = fb_set_var(info, &var);
+		fb_var_to_videomode(&mode, &var);
+		if (err || !fb_mode_is_equal(m, &mode)) {
+			list_del(pos);
+			kfree(pos);
+		}
+	}
+
+	err = 1;
+
+	if (!list_empty(&info->modelist)) {
+		event.info = info;
+		err = notifier_call_chain(&fb_notifier_list,
+					   FB_EVENT_NEW_MODELIST,
+					   &event);
+	}
+
+	return err;
+}
 
 static char *video_options[FB_MAX];
 static int ofonly;
 
+extern const char *global_mode_option;
+
 /**
  * fb_get_options - get kernel boot parameters
- * @name - framebuffer name as it would appear in
- *         the boot parameter line
- *         (video=<name>:<options>)
+ * @name:   framebuffer name as it would appear in
+ *          the boot parameter line
+ *          (video=<name>:<options>)
+ * @option: the option will be stored here
  *
  * NOTE: Needed to maintain backwards compatibility
  */
@@ -1261,10 +1312,7 @@ int fb_get_options(char *name, char **op
  *	Returns zero.
  *
  */
-
-extern const char *global_mode_option;
-
-int __init video_setup(char *options)
+static int __init video_setup(char *options)
 {
 	int i, global = 0;
 
@@ -1317,5 +1365,6 @@ EXPORT_SYMBOL(fb_set_suspend);
 EXPORT_SYMBOL(fb_register_client);
 EXPORT_SYMBOL(fb_unregister_client);
 EXPORT_SYMBOL(fb_get_options);
+EXPORT_SYMBOL(fb_new_modelist);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -34,7 +34,6 @@
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
-#include <video/edid.h>
 #include "edid.h"
 
 /* 
@@ -74,10 +73,9 @@ static struct broken_edid brokendb[] = {
 	},
 };
 
-const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0x00
 };
-const unsigned char edid_v1_descriptor_flag[] = { 0x00, 0x00 };
 
 static void copy_string(unsigned char *c, unsigned char *s)
 {
@@ -518,7 +516,7 @@ static void get_detailed_timing(unsigned
  * This function builds a mode database using the contents of the EDID
  * data
  */
-struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
 {
 	struct fb_videomode *mode, *m;
 	unsigned char *block;
@@ -589,11 +587,10 @@ struct fb_videomode *fb_create_modedb(un
  */
 void fb_destroy_modedb(struct fb_videomode *modedb)
 {
-	if (modedb)
-		kfree(modedb);
+	kfree(modedb);
 }
 
-int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
+static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
 {
 	int i, retval = 1;
 	unsigned char *block;
@@ -872,18 +869,6 @@ void fb_edid_to_monspecs(unsigned char *
 	DPRINTK("========================================\n");
 }
 
-char *get_EDID_from_firmware(struct device *dev)
-{
-	unsigned char *pedid = NULL;
-
-#if defined(CONFIG_EDID_FIRMWARE) && defined(CONFIG_X86)
-	pedid = edid_info.dummy;
-	if (!pedid)
-		return NULL;
-#endif
-	return pedid;
-}
-
 /* 
  * VESA Generalized Timing Formula (GTF) 
  */
@@ -1193,21 +1178,9 @@ void fb_edid_to_monspecs(unsigned char *
 {
 	specs = NULL;
 }
-char *get_EDID_from_firmware(struct device *dev)
-{
-	return NULL;
-}
-struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
-{
-	return NULL;
-}
 void fb_destroy_modedb(struct fb_videomode *modedb)
 {
 }
-int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
-{
-	return 1;
-}
 int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
 		struct fb_info *info)
 {
@@ -1278,10 +1251,7 @@ int fb_validate_mode(const struct fb_var
 
 EXPORT_SYMBOL(fb_parse_edid);
 EXPORT_SYMBOL(fb_edid_to_monspecs);
-EXPORT_SYMBOL(get_EDID_from_firmware);
 
 EXPORT_SYMBOL(fb_get_mode);
 EXPORT_SYMBOL(fb_validate_mode);
-EXPORT_SYMBOL(fb_create_modedb);
 EXPORT_SYMBOL(fb_destroy_modedb);
-EXPORT_SYMBOL(fb_get_monitor_limits);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@ struct fb_info *framebuffer_alloc(size_t
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,317 @@ void framebuffer_release(struct fb_info 
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset,
+		       const struct fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	LIST_HEAD(old_list);
+	int i = count / sizeof(struct fb_videomode);
+
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	acquire_console_sem();
+	list_splice(&fb_info->modelist, &old_list);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i,
+				 &fb_info->modelist);
+	if (fb_new_modelist(fb_info)) {
+		fb_destroy_modelist(&fb_info->modelist);
+		list_splice(&old_list, &fb_info->modelist);
+	} else
+		fb_destroy_modelist(&old_list);
+
+	release_console_sem();
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual,
+	       var.yres_virtual);
+
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
+			fb_info->var.yres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int offset = 0, i;
+
+	if (!fb_info->cmap.red || !fb_info->cmap.blue ||
+	    fb_info->cmap.green || fb_info->cmap.transp)
+		return -EINVAL;
+
+	for (i = 0; i < fb_info->cmap.len; i++) {
+		offset += snprintf(buf, PAGE_SIZE - offset,
+				   "%d,%d,%d,%d,%d\n", i + fb_info->cmap.start,
+				   fb_info->cmap.red[i], fb_info->cmap.blue[i],
+				   fb_info->cmap.green[i],
+				   fb_info->cmap.transp[i]);
+	}
+	return offset;
+}
+
+static ssize_t store_blank(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char *last = NULL;
+	int err;
+
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_blank(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_console(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_console(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_cursor(struct class_device *class_device,
+			    const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cursor(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_pan(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xoffset = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yoffset = simple_strtoul(last, &last, 0);
+
+	acquire_console_sem();
+	err = fb_pan_display(fb_info, &var);
+	release_console_sem();
+
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_pan(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
+			fb_info->var.xoffset);
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+	__ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
+	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+};
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+	class_set_devdata(fb_info->class_device, fb_info);
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_create_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_remove_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+}
+
+
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/Kconfig
@@ -0,0 +1,29 @@
+#
+# Geode family framebuffer configuration
+#
+config FB_GEODE
+	bool "AMD Geode family framebuffer support (EXPERIMENTAL)"
+	default n
+	depends on FB && EXPERIMENTAL && X86
+	---help---
+	  Say 'Y' here to allow you to select framebuffer drivers for
+	  the AMD Geode family of processors.
+
+config FB_GEODE_GX1
+	tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
+	default n
+	depends on FB_GEODE && EXPERIMENTAL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Framebuffer driver for the display controller integrated into the
+	  AMD Geode GX1 processor.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted and removed from the running kernel whenever you want). The
+	  module will be called gx1fb. If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/Makefile
@@ -0,0 +1,5 @@
+# Makefile for the Geode family framebuffer drivers
+
+obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
+
+gx1fb-objs   		:= gx1fb_core.o display_gx1.o video_cs5530.o
diff --git a/drivers/video/geode/display_gx1.c b/drivers/video/geode/display_gx1.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/display_gx1.c
@@ -0,0 +1,214 @@
+/*
+ * drivers/video/geode/display_gx1.c
+ *   -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, 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/spinlock.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "display_gx1.h"
+
+static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED;
+
+static u8 gx1_read_conf_reg(u8 reg)
+{
+	u8 val, ccr3;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gx1_conf_reg_lock, flags);
+
+	outb(CONFIG_CCR3, 0x22);
+	ccr3 = inb(0x23);
+	outb(CONFIG_CCR3, 0x22);
+	outb(ccr3 | CONFIG_CCR3_MAPEN, 0x23);
+	outb(reg, 0x22);
+	val = inb(0x23);
+	outb(CONFIG_CCR3, 0x22);
+	outb(ccr3, 0x23);
+
+	spin_unlock_irqrestore(&gx1_conf_reg_lock, flags);
+
+	return val;
+}
+
+unsigned gx1_gx_base(void)
+{
+	return (gx1_read_conf_reg(CONFIG_GCR) & 0x03) << 30;
+}
+
+int gx1_frame_buffer_size(void)
+{
+	void __iomem *mc_regs;
+	u32 bank_cfg;
+	int d;
+	unsigned dram_size = 0, fb_base;
+
+	mc_regs = ioremap(gx1_gx_base() + 0x8400, 0x100);
+	if (!mc_regs)
+		return -ENOMEM;
+
+
+	/* Calculate the total size of both DIMM0 and DIMM1. */
+	bank_cfg = readl(mc_regs + MC_BANK_CFG);
+
+	for (d = 0; d < 2; d++) {
+		if ((bank_cfg & MC_BCFG_DIMM0_PG_SZ_MASK) != MC_BCFG_DIMM0_PG_SZ_NO_DIMM)
+			dram_size += 0x400000 << ((bank_cfg & MC_BCFG_DIMM0_SZ_MASK) >> 8);
+		bank_cfg >>= 16; /* look at DIMM1 next */
+	}
+
+	fb_base = (readl(mc_regs + MC_GBASE_ADD) & MC_GADD_GBADD_MASK) << 19;
+
+	iounmap(mc_regs);
+
+	return dram_size - fb_base;
+}
+
+static void gx1_set_mode(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 gcfg, tcfg, ocfg, dclk_div, val;
+	int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+	int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+	/* Unlock the display controller registers. */
+	readl(par->dc_regs + DC_UNLOCK);
+	writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+	gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+	tcfg = readl(par->dc_regs + DC_TIMING_CFG);
+
+	/* Blank the display and disable the timing generator. */
+	tcfg &= ~(DC_TCFG_BLKE | DC_TCFG_TGEN);
+	writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+
+	/* Wait for pending memory requests before disabling the FIFO load. */
+	udelay(100);
+
+	/* Disable FIFO load and compression. */
+	gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Setup DCLK and its divisor. */
+	gcfg &= ~DC_GCFG_DCLK_MASK;
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	par->vid_ops->set_dclk(info);
+
+	dclk_div = DC_GCFG_DCLK_DIV_1; /* FIXME: may need to divide DCLK by 2 sometimes? */
+	gcfg |= dclk_div;
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Wait for the clock generatation to settle.  This is needed since
+	 * some of the register writes that follow require that clock to be
+	 * present. */
+	udelay(1000); /* FIXME: seems a little long */
+
+	/*
+	 * Setup new mode.
+	 */
+
+	/* Clear all unused feature bits. */
+	gcfg = DC_GCFG_VRDY | dclk_div;
+
+	/* Set FIFO priority (default 6/5) and enable. */
+	/* FIXME: increase fifo priority for 1280x1024 modes? */
+	gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
+
+	/* FIXME: Set pixel and line double bits if necessary. */
+
+	/* Framebuffer start offset. */
+	writel(0, par->dc_regs + DC_FB_ST_OFFSET);
+
+	/* Line delta and line buffer length. */
+	writel(info->fix.line_length >> 2, par->dc_regs + DC_LINE_DELTA);
+	writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
+	       par->dc_regs + DC_BUF_SIZE);
+
+	/* Output configuration. Enable panel data, set pixel format. */
+	ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH;
+	if (info->var.bits_per_pixel == 8) ocfg |= DC_OCFG_8BPP;
+
+	/* Enable timing generator, sync and FP data. */
+	tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE
+		| DC_TCFG_TGEN;
+
+	/* Horizontal and vertical timings. */
+	hactive = info->var.xres;
+	hblankstart = hactive;
+	hsyncstart = hblankstart + info->var.right_margin;
+	hsyncend =  hsyncstart + info->var.hsync_len;
+	hblankend = hsyncend + info->var.left_margin;
+	htotal = hblankend;
+
+	vactive = info->var.yres;
+	vblankstart = vactive;
+	vsyncstart = vblankstart + info->var.lower_margin;
+	vsyncend =  vsyncstart + info->var.vsync_len;
+	vblankend = vsyncend + info->var.upper_margin;
+	vtotal = vblankend;
+
+	val = (hactive - 1) | ((htotal - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_1);
+	val = (hblankstart - 1) | ((hblankend - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_2);
+	val = (hsyncstart - 1) | ((hsyncend - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_3);
+	writel(val, par->dc_regs + DC_FP_H_TIMING);
+	val = (vactive - 1) | ((vtotal - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_1);
+	val = (vblankstart - 1) | ((vblankend - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_2);
+	val = (vsyncstart - 1) | ((vsyncend - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_3);
+	val = (vsyncstart - 2) | ((vsyncend - 2) << 16);
+	writel(val, par->dc_regs + DC_FP_V_TIMING);
+
+	/* Write final register values. */
+	writel(ocfg, par->dc_regs + DC_OUTPUT_CFG);
+	writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+	udelay(1000); /* delay after TIMING_CFG. FIXME: perhaps a little long */
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	par->vid_ops->configure_display(info);
+
+	/* Relock display controller registers */
+	writel(0, par->dc_regs + DC_UNLOCK);
+
+	/* FIXME: write line_length and bpp to Graphics Pipeline GP_BLT_STATUS
+	 * register. */
+}
+
+static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+				   unsigned red, unsigned green, unsigned blue)
+{
+	struct geodefb_par *par = info->par;
+	int val;
+
+	/* Hardware palette is in RGB 6-6-6 format. */
+	val  = (red   <<  2) & 0x3f000;
+	val |= (green >>  4) & 0x00fc0;
+	val |= (blue  >> 10) & 0x0003f;
+
+	writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+	writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+struct geode_dc_ops gx1_dc_ops = {
+	.set_mode	 = gx1_set_mode,
+	.set_palette_reg = gx1_set_hw_palette_reg,
+};
diff --git a/drivers/video/geode/display_gx1.h b/drivers/video/geode/display_gx1.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/display_gx1.h
@@ -0,0 +1,154 @@
+/*
+ * drivers/video/geode/display_gx1.h
+ *   -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, 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 __DISPLAY_GX1_H__
+#define __DISPLAY_GX1_H__
+
+unsigned gx1_gx_base(void);
+int gx1_frame_buffer_size(void);
+
+extern struct geode_dc_ops gx1_dc_ops;
+
+/* GX1 configuration I/O registers */
+
+#define CONFIG_CCR3 0xc3
+#  define CONFIG_CCR3_MAPEN 0x10
+#define CONFIG_GCR  0xb8
+
+/* Memory controller registers */
+
+#define MC_BANK_CFG		0x08
+#  define MC_BCFG_DIMM0_SZ_MASK		0x00000700
+#  define MC_BCFG_DIMM0_PG_SZ_MASK	0x00000070
+#  define MC_BCFG_DIMM0_PG_SZ_NO_DIMM	0x00000070
+
+#define MC_GBASE_ADD		0x14
+#  define MC_GADD_GBADD_MASK		0x000003ff
+
+/* Display controller registers */
+
+#define DC_PAL_ADDRESS		0x70
+#define DC_PAL_DATA		0x74
+
+#define DC_UNLOCK		0x00
+#  define DC_UNLOCK_CODE		0x00004758
+
+#define DC_GENERAL_CFG		0x04
+#  define DC_GCFG_DFLE			0x00000001
+#  define DC_GCFG_CURE			0x00000002
+#  define DC_GCFG_VCLK_DIV		0x00000004
+#  define DC_GCFG_PLNO			0x00000004
+#  define DC_GCFG_PPC			0x00000008
+#  define DC_GCFG_CMPE			0x00000010
+#  define DC_GCFG_DECE			0x00000020
+#  define DC_GCFG_DCLK_MASK		0x000000C0
+#  define DC_GCFG_DCLK_DIV_1		0x00000080
+#  define DC_GCFG_DFHPSL_MASK		0x00000F00
+#  define DC_GCFG_DFHPSL_POS			 8
+#  define DC_GCFG_DFHPEL_MASK		0x0000F000
+#  define DC_GCFG_DFHPEL_POS			12
+#  define DC_GCFG_CIM_MASK		0x00030000
+#  define DC_GCFG_CIM_POS			16
+#  define DC_GCFG_FDTY			0x00040000
+#  define DC_GCFG_RTPM			0x00080000
+#  define DC_GCFG_DAC_RS_MASK		0x00700000
+#  define DC_GCFG_DAC_RS_POS			20
+#  define DC_GCFG_CKWR			0x00800000
+#  define DC_GCFG_LDBL			0x01000000
+#  define DC_GCFG_DIAG			0x02000000
+#  define DC_GCFG_CH4S			0x04000000
+#  define DC_GCFG_SSLC			0x08000000
+#  define DC_GCFG_VIDE			0x10000000
+#  define DC_GCFG_VRDY			0x20000000
+#  define DC_GCFG_DPCK			0x40000000
+#  define DC_GCFG_DDCK			0x80000000
+
+#define DC_TIMING_CFG		0x08
+#  define DC_TCFG_FPPE			0x00000001
+#  define DC_TCFG_HSYE			0x00000002
+#  define DC_TCFG_VSYE			0x00000004
+#  define DC_TCFG_BLKE			0x00000008
+#  define DC_TCFG_DDCK			0x00000010
+#  define DC_TCFG_TGEN			0x00000020
+#  define DC_TCFG_VIEN			0x00000040
+#  define DC_TCFG_BLNK			0x00000080
+#  define DC_TCFG_CHSP			0x00000100
+#  define DC_TCFG_CVSP			0x00000200
+#  define DC_TCFG_FHSP			0x00000400
+#  define DC_TCFG_FVSP			0x00000800
+#  define DC_TCFG_FCEN			0x00001000
+#  define DC_TCFG_CDCE			0x00002000
+#  define DC_TCFG_PLNR			0x00002000
+#  define DC_TCFG_INTL			0x00004000
+#  define DC_TCFG_PXDB			0x00008000
+#  define DC_TCFG_BKRT			0x00010000
+#  define DC_TCFG_PSD_MASK		0x000E0000
+#  define DC_TCFG_PSD_POS			17
+#  define DC_TCFG_DDCI			0x08000000
+#  define DC_TCFG_SENS			0x10000000
+#  define DC_TCFG_DNA			0x20000000
+#  define DC_TCFG_VNA			0x40000000
+#  define DC_TCFG_VINT			0x80000000
+
+#define DC_OUTPUT_CFG		0x0C
+#  define DC_OCFG_8BPP			0x00000001
+#  define DC_OCFG_555			0x00000002
+#  define DC_OCFG_PCKE			0x00000004
+#  define DC_OCFG_FRME			0x00000008
+#  define DC_OCFG_DITE			0x00000010
+#  define DC_OCFG_2PXE			0x00000020
+#  define DC_OCFG_2XCK			0x00000040
+#  define DC_OCFG_2IND			0x00000080
+#  define DC_OCFG_34ADD			0x00000100
+#  define DC_OCFG_FRMS			0x00000200
+#  define DC_OCFG_CKSL			0x00000400
+#  define DC_OCFG_PRMP			0x00000800
+#  define DC_OCFG_PDEL			0x00001000
+#  define DC_OCFG_PDEH			0x00002000
+#  define DC_OCFG_CFRW			0x00004000
+#  define DC_OCFG_DIAG			0x00008000
+
+#define DC_FB_ST_OFFSET		0x10
+#define DC_CB_ST_OFFSET		0x14
+#define DC_CURS_ST_OFFSET	0x18
+#define DC_ICON_ST_OFFSET	0x1C
+#define DC_VID_ST_OFFSET	0x20
+#define DC_LINE_DELTA		0x24
+#define DC_BUF_SIZE		0x28
+
+#define DC_H_TIMING_1		0x30
+#define DC_H_TIMING_2		0x34
+#define DC_H_TIMING_3		0x38
+#define DC_FP_H_TIMING		0x3C
+
+#define DC_V_TIMING_1		0x40
+#define DC_V_TIMING_2		0x44
+#define DC_V_TIMING_3		0x48
+#define DC_FP_V_TIMING		0x4C
+
+#define DC_CURSOR_X		0x50
+#define DC_ICON_X		0x54
+#define DC_V_LINE_CNT		0x54
+#define DC_CURSOR_Y		0x58
+#define DC_ICON_Y		0x5C
+#define DC_SS_LINE_CMP		0x5C
+#define DC_CURSOR_COLOR		0x60
+#define DC_ICON_COLOR		0x64
+#define DC_BORDER_COLOR		0x68
+#define DC_PAL_ADDRESS		0x70
+#define DC_PAL_DATA		0x74
+#define DC_DFIFO_DIAG		0x78
+#define DC_CFIFO_DIAG		0x7C
+
+#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/geodefb.h
@@ -0,0 +1,39 @@
+/*
+ * drivers/video/geode/geodefb.h
+ *   -- Geode framebuffer driver
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * This program is free software; you can redistribute it 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 __GEODEFB_H__
+#define __GEODEFB_H__
+
+struct geodefb_info;
+
+struct geode_dc_ops {
+	void (*set_mode)(struct fb_info *);
+	void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned);
+};
+
+struct geode_vid_ops {
+	void (*set_dclk)(struct fb_info *);
+	void (*configure_display)(struct fb_info *);
+	int  (*blank_display)(struct fb_info *, int blank_mode);
+};
+
+struct geodefb_par {
+	int enable_crt;
+	int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
+	int panel_y;
+	struct pci_dev *vid_dev;
+	void __iomem *dc_regs;
+	void __iomem *vid_regs;
+	struct geode_dc_ops  *dc_ops;
+	struct geode_vid_ops *vid_ops;
+};
+
+#endif /* !__GEODEFB_H__ */
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/gx1fb_core.c
@@ -0,0 +1,359 @@
+/*
+ * drivers/video/geode/gx1fb_core.c
+ *   -- Geode GX1 framebuffer driver
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * This program is free software; you can redistribute it 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/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 "geodefb.h"
+#include "display_gx1.h"
+#include "video_cs5530.h"
+
+static char mode_option[32] = "640x480-16@60";
+static int  crt_option = 1;
+static char panel_option[32] = "";
+
+static int gx1_line_delta(int xres, int bpp)
+{
+	int line_delta = xres * (bpp >> 3);
+
+	if (line_delta > 2048)
+		line_delta = 4096;
+	else if (line_delta > 1024)
+		line_delta = 2048;
+	else
+		line_delta = 1024;
+	return line_delta;
+}
+
+static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	printk(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+	/* Maximum resolution is 1280x1024. */
+	if (var->xres > 1280 || var->yres > 1024)
+		return -EINVAL;
+
+	if (par->panel_x && (var->xres > par->panel_x || var->yres > par->panel_y))
+		return -EINVAL;
+
+	/* Only 16 bpp and 8 bpp is supported by the hardware. */
+	if (var->bits_per_pixel == 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;
+	} else if (var->bits_per_pixel == 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;
+	} else
+		return -EINVAL;
+
+	/* Enough video memory? */
+	if (gx1_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len)
+		return -EINVAL;
+
+	/* FIXME: Check timing parameters here? */
+
+	return 0;
+}
+
+static int gx1fb_set_par(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.bits_per_pixel == 16) {
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		fb_dealloc_cmap(&info->cmap);
+	} else {
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+	}
+
+	info->fix.line_length = gx1_line_delta(info->var.xres, info->var.bits_per_pixel);
+
+	par->dc_ops->set_mode(info);
+
+	return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int gx1fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 v;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		v  = chan_to_field(red, &info->var.red);
+		v |= chan_to_field(green, &info->var.green);
+		v |= chan_to_field(blue, &info->var.blue);
+
+		pal[regno] = v;
+	} else {
+		if (regno >= 256)
+			return -EINVAL;
+
+		par->dc_ops->set_palette_reg(info, regno, red, green, blue);
+	}
+
+	return 0;
+}
+
+static int gx1fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	return par->vid_ops->blank_display(info, blank_mode);
+}
+
+static int __init gx1fb_map_video_memory(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	unsigned gx_base;
+	int fb_len;
+
+	gx_base = gx1_gx_base();
+	if (!gx_base)
+		return -ENODEV;
+
+	par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX,
+				      PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL);
+	if (!par->vid_dev)
+		return -ENODEV;
+
+	par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1),
+				pci_resource_len(par->vid_dev, 1));
+	if (!par->vid_regs)
+		return -ENOMEM;
+
+	par->dc_regs = ioremap(gx_base + 0x8300, 0x100);
+	if (!par->dc_regs)
+		return -ENOMEM;
+
+	info->fix.smem_start = gx_base + 0x800000;
+	if ((fb_len = gx1_frame_buffer_size()) < 0)
+		return -ENOMEM;
+	info->fix.smem_len = fb_len;
+	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n",
+	       info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start);
+
+	return 0;
+}
+
+static int parse_panel_option(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (strcmp(panel_option, "") != 0) {
+		int x, y;
+		char *s;
+		x = simple_strtol(panel_option, &s, 10);
+		if (!x)
+			return -EINVAL;
+		y = simple_strtol(s + 1, NULL, 10);
+		if (!y)
+			return -EINVAL;
+		par->panel_x = x;
+		par->panel_y = y;
+	}
+	return 0;
+}
+
+static struct fb_ops gx1fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= gx1fb_check_var,
+	.fb_set_par	= gx1fb_set_par,
+	.fb_setcolreg	= gx1fb_setcolreg,
+	.fb_blank       = gx1fb_blank,
+	/* No HW acceleration for now. */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static struct fb_info * __init gx1fb_init_fbinfo(void)
+{
+	struct fb_info *info;
+	struct geodefb_par *par;
+
+	/* Alloc enough space for the pseudo palette. */
+	info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL);
+	if (!info)
+		return NULL;
+
+	par = info->par;
+
+	strcpy(info->fix.id, "GX1");
+
+	info->fix.type		= FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	= 0;
+	info->fix.xpanstep	= 0;
+	info->fix.ypanstep	= 0;
+	info->fix.ywrapstep	= 0;
+	info->fix.accel		= FB_ACCEL_NONE;
+
+	info->var.nonstd	= 0;
+	info->var.activate	= FB_ACTIVATE_NOW;
+	info->var.height	= -1;
+	info->var.width	= -1;
+	info->var.accel_flags = 0;
+	info->var.vmode	= FB_VMODE_NONINTERLACED;
+
+	info->fbops		= &gx1fb_ops;
+	info->flags		= FBINFO_DEFAULT;
+	info->node		= -1;
+
+	info->pseudo_palette	= (void *)par + sizeof(struct geodefb_par);
+
+	info->var.grayscale	= 0;
+
+	/* CRT and panel options */
+	par->enable_crt = crt_option;
+	if (parse_panel_option(info) < 0)
+		printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n",
+		       info->fix.id);
+	if (!par->panel_x)
+		par->enable_crt = 1; /* fall back to CRT if no panel is specified */
+
+	return info;
+}
+
+
+static struct fb_info *gx1fb_info;
+
+static int __init gx1fb_init(void)
+{
+	struct fb_info *info;
+        struct geodefb_par *par;
+	int ret;
+
+#ifndef MODULE
+	if (fb_get_options("gx1fb", NULL))
+		return -ENODEV;
+#endif
+
+	info = gx1fb_init_fbinfo();
+	if (!info)
+		return -ENOMEM;
+	gx1fb_info = info;
+
+	par = info->par;
+
+	/* GX1 display controller and CS5530 video device */
+	par->dc_ops  = &gx1_dc_ops;
+	par->vid_ops = &cs5530_vid_ops;
+
+	if ((ret = gx1fb_map_video_memory(info)) < 0) {
+		printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id);
+		goto err;
+	}
+
+	ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16);
+	if (ret == 0 || ret == 4) {
+		printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id);
+		ret = -EINVAL;
+		goto err;
+	}
+
+        /* Clear the frame buffer of garbage. */
+        memset_io(info->screen_base, 0, info->fix.smem_len);
+
+	gx1fb_check_var(&info->var, info);
+	gx1fb_set_par(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
+	return 0;
+
+  err:
+	if (info->screen_base)
+		iounmap(info->screen_base);
+	if (par->vid_regs)
+		iounmap(par->vid_regs);
+	if (par->dc_regs)
+		iounmap(par->dc_regs);
+	if (par->vid_dev)
+		pci_dev_put(par->vid_dev);
+	if (info)
+		framebuffer_release(info);
+	return ret;
+}
+
+static void __exit gx1fb_cleanup(void)
+{
+	struct fb_info *info = gx1fb_info;
+	struct geodefb_par *par = gx1fb_info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap((void __iomem *)info->screen_base);
+	iounmap(par->vid_regs);
+	iounmap(par->dc_regs);
+
+	pci_dev_put(par->vid_dev);
+
+	framebuffer_release(info);
+}
+
+module_init(gx1fb_init);
+module_exit(gx1fb_cleanup);
+
+module_param_string(mode, mode_option, sizeof(mode_option), 0444);
+MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+
+module_param_named(crt, crt_option, int, 0444);
+MODULE_PARM_DESC(crt, "enable CRT output. 0 = off, 1 = on (default)");
+
+module_param_string(panel, panel_option, sizeof(panel_option), 0444);
+MODULE_PARM_DESC(panel, "size of attached flat panel (<x>x<y>)");
+
+MODULE_DESCRIPTION("framebuffer driver for the AMD Geode GX1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/video_cs5530.c
@@ -0,0 +1,195 @@
+/*
+ * drivers/video/geode/video_cs5530.c
+ *   -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, 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/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "video_cs5530.h"
+
+/*
+ * CS5530 PLL table. This maps pixclocks to the appropriate PLL register
+ * value.
+ */
+struct cs5530_pll_entry {
+	long pixclock; /* ps */
+	u32 pll_value;
+};
+
+static const struct cs5530_pll_entry cs5530_pll_table[] = {
+	{ 39721, 0x31C45801, }, /*  25.1750 MHz */
+	{ 35308, 0x20E36802, }, /*  28.3220 */
+	{ 31746, 0x33915801, }, /*  31.5000 */
+	{ 27777, 0x31EC4801, }, /*  36.0000 */
+	{ 26666, 0x21E22801, }, /*  37.5000 */
+	{ 25000, 0x33088801, }, /*  40.0000 */
+	{ 22271, 0x33E22801, }, /*  44.9000 */
+	{ 20202, 0x336C4801, }, /*  49.5000 */
+	{ 20000, 0x23088801, }, /*  50.0000 */
+	{ 19860, 0x23088801, }, /*  50.3500 */
+	{ 18518, 0x3708A801, }, /*  54.0000 */
+	{ 17777, 0x23E36802, }, /*  56.2500 */
+	{ 17733, 0x23E36802, }, /*  56.3916 */
+	{ 17653, 0x23E36802, }, /*  56.6444 */
+	{ 16949, 0x37C45801, }, /*  59.0000 */
+	{ 15873, 0x23EC4801, }, /*  63.0000 */
+	{ 15384, 0x37911801, }, /*  65.0000 */
+	{ 14814, 0x37963803, }, /*  67.5000 */
+	{ 14124, 0x37058803, }, /*  70.8000 */
+	{ 13888, 0x3710C805, }, /*  72.0000 */
+	{ 13333, 0x37E22801, }, /*  75.0000 */
+	{ 12698, 0x27915801, }, /*  78.7500 */
+	{ 12500, 0x37D8D802, }, /*  80.0000 */
+	{ 11135, 0x27588802, }, /*  89.8000 */
+	{ 10582, 0x27EC4802, }, /*  94.5000 */
+	{ 10101, 0x27AC6803, }, /*  99.0000 */
+	{ 10000, 0x27088801, }, /* 100.0000 */
+	{  9259, 0x2710C805, }, /* 108.0000 */
+	{  8888, 0x27E36802, }, /* 112.5000 */
+	{  7692, 0x27C58803, }, /* 130.0000 */
+	{  7407, 0x27316803, }, /* 135.0000 */
+	{  6349, 0x2F915801, }, /* 157.5000 */
+	{  6172, 0x2F08A801, }, /* 162.0000 */
+	{  5714, 0x2FB11802, }, /* 175.0000 */
+	{  5291, 0x2FEC4802, }, /* 189.0000 */
+	{  4950, 0x2F963803, }, /* 202.0000 */
+	{  4310, 0x2FB1B802, }, /* 232.0000 */
+};
+
+#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry)
+
+static void cs5530_set_dclk_frequency(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	int i;
+	u32 value;
+	long min, diff;
+
+	/* Search the table for the closest pixclock. */
+	value = cs5530_pll_table[0].pll_value;
+	min = cs5530_pll_table[0].pixclock - info->var.pixclock;
+	if (min < 0) min = -min;
+	for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) {
+		diff = cs5530_pll_table[i].pixclock - info->var.pixclock;
+		if (diff < 0L) diff = -diff;
+		if (diff < min) {
+			min = diff;
+			value = cs5530_pll_table[i].pll_value;
+		}
+	}
+
+	writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG);
+	writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */
+	udelay(500); /* wait for PLL to settle */
+	writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */
+	writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */
+}
+
+static void cs5530_configure_display(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg;
+
+	dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	/* Clear bits from existing mode. */
+	dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK
+		  | CS5530_DCFG_CRT_HSYNC_POL   | CS5530_DCFG_CRT_VSYNC_POL
+		  | CS5530_DCFG_FP_PWR_EN       | CS5530_DCFG_FP_DATA_EN
+		  | CS5530_DCFG_DAC_PWR_EN      | CS5530_DCFG_VSYNC_EN
+		  | CS5530_DCFG_HSYNC_EN);
+
+	/* Set default sync skew and power sequence delays.  */
+	dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT
+		 | CS5530_DCFG_GV_PAL_BYP);
+
+	/* Enable DACs, hsync and vsync for CRTs */
+	if (par->enable_crt) {
+		dcfg |= CS5530_DCFG_DAC_PWR_EN;
+		dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN;
+	}
+	/* Enable panel power and data if using a flat panel. */
+	if (par->panel_x > 0) {
+		dcfg |= CS5530_DCFG_FP_PWR_EN;
+		dcfg |= CS5530_DCFG_FP_DATA_EN;
+	}
+
+	/* Sync polarities. */
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		dcfg |= CS5530_DCFG_CRT_HSYNC_POL;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		dcfg |= CS5530_DCFG_CRT_VSYNC_POL;
+
+	writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+}
+
+static int cs5530_blank_display(struct fb_info *info, int blank_mode)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg;
+	int blank, hsync, vsync;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		blank = 0; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_NORMAL:
+		blank = 1; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		blank = 1; hsync = 1; vsync = 0;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		blank = 1; hsync = 0; vsync = 1;
+		break;
+	case FB_BLANK_POWERDOWN:
+		blank = 1; hsync = 0; vsync = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN
+		  | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN
+		  | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN);
+
+	if (par->enable_crt) {
+		if (!blank)
+			dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN;
+		if (hsync)
+			dcfg |= CS5530_DCFG_HSYNC_EN;
+		if (vsync)
+			dcfg |= CS5530_DCFG_VSYNC_EN;
+	}
+	if (par->panel_x > 0) {
+		if (!blank)
+			dcfg |= CS5530_DCFG_FP_DATA_EN;
+		if (hsync && vsync)
+			dcfg |= CS5530_DCFG_FP_PWR_EN;
+	}
+
+	writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	return 0;
+}
+
+struct geode_vid_ops cs5530_vid_ops = {
+	.set_dclk          = cs5530_set_dclk_frequency,
+	.configure_display = cs5530_configure_display,
+	.blank_display     = cs5530_blank_display,
+};
diff --git a/drivers/video/geode/video_cs5530.h b/drivers/video/geode/video_cs5530.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/geode/video_cs5530.h
@@ -0,0 +1,75 @@
+/*
+ * drivers/video/geode/video_cs5530.h
+ *   -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, 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 __VIDEO_CS5530_H__
+#define __VIDEO_CS5530_H__
+
+extern struct geode_vid_ops cs5530_vid_ops;
+
+/* CS5530 Video device registers */
+
+#define CS5530_VIDEO_CONFIG	0x0000
+#  define CS5530_VCFG_VID_EN			0x00000001
+#  define CS5530_VCFG_VID_REG_UPDATE		0x00000002
+#  define CS5530_VCFG_VID_INP_FORMAT		0x0000000C
+#  define CS5530_VCFG_8_BIT_4_2_0		0x00000004
+#  define CS5530_VCFG_16_BIT_4_2_0		0x00000008
+#  define CS5530_VCFG_GV_SEL			0x00000010
+#  define CS5530_VCFG_CSC_BYPASS		0x00000020
+#  define CS5530_VCFG_X_FILTER_EN		0x00000040
+#  define CS5530_VCFG_Y_FILTER_EN		0x00000080
+#  define CS5530_VCFG_LINE_SIZE_LOWER_MASK	0x0000FF00
+#  define CS5530_VCFG_INIT_READ_MASK		0x01FF0000
+#  define CS5530_VCFG_EARLY_VID_RDY		0x02000000
+#  define CS5530_VCFG_LINE_SIZE_UPPER		0x08000000
+#  define CS5530_VCFG_4_2_0_MODE		0x10000000
+#  define CS5530_VCFG_16_BIT_EN			0x20000000
+#  define CS5530_VCFG_HIGH_SPD_INT		0x40000000
+
+#define CS5530_DISPLAY_CONFIG	0x0004
+#  define CS5530_DCFG_DIS_EN			0x00000001
+#  define CS5530_DCFG_HSYNC_EN			0x00000002
+#  define CS5530_DCFG_VSYNC_EN			0x00000004
+#  define CS5530_DCFG_DAC_BL_EN			0x00000008
+#  define CS5530_DCFG_DAC_PWR_EN		0x00000020
+#  define CS5530_DCFG_FP_PWR_EN			0x00000040
+#  define CS5530_DCFG_FP_DATA_EN		0x00000080
+#  define CS5530_DCFG_CRT_HSYNC_POL		0x00000100
+#  define CS5530_DCFG_CRT_VSYNC_POL		0x00000200
+#  define CS5530_DCFG_FP_HSYNC_POL		0x00000400
+#  define CS5530_DCFG_FP_VSYNC_POL		0x00000800
+#  define CS5530_DCFG_XGA_FP			0x00001000
+#  define CS5530_DCFG_FP_DITH_EN		0x00002000
+#  define CS5530_DCFG_CRT_SYNC_SKW_MASK		0x0001C000
+#  define CS5530_DCFG_CRT_SYNC_SKW_INIT		0x00010000
+#  define CS5530_DCFG_PWR_SEQ_DLY_MASK		0x000E0000
+#  define CS5530_DCFG_PWR_SEQ_DLY_INIT		0x00080000
+#  define CS5530_DCFG_VG_CK			0x00100000
+#  define CS5530_DCFG_GV_PAL_BYP		0x00200000
+#  define CS5530_DCFG_DDC_SCL			0x00400000
+#  define CS5530_DCFG_DDC_SDA			0x00800000
+#  define CS5530_DCFG_DDC_OE			0x01000000
+#  define CS5530_DCFG_16_BIT_EN			0x02000000
+
+#define CS5530_VIDEO_X_POS	0x0008
+#define CS5530_VIDEO_Y_POS	0x000C
+#define CS5530_VIDEO_SCALE	0x0010
+#define CS5530_VIDEO_COLOR_KEY	0x0014
+#define CS5530_VIDEO_COLOR_MASK 0x0018
+#define CS5530_PALETTE_ADDRESS	0x001C
+#define CS5530_PALETTE_DATA	0x0020
+#define CS5530_DOT_CLK_CONFIG	0x0024
+#define CS5530_CRCSIG_TFT_TV	0x0028
+
+#endif /* !__VIDEO_CS5530_H__ */
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -412,7 +412,8 @@ static int hgafb_setcolreg(u_int regno, 
  *	A zero is returned on success and %-EINVAL for failure.
  */
 
-int hgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+static int hgafb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
 {
 	if (var->vmode & FB_VMODE_YWRAP) {
 		if (var->yoffset < 0 || 
@@ -548,7 +549,7 @@ static struct fb_ops hgafb_ops = {
 	 *  Initialization
 	 */
 
-int __init hgafb_init(void)
+static int __init hgafb_init(void)
 {
 	if (fb_get_options("hgafb", NULL))
 		return -ENODEV;
@@ -587,15 +588,6 @@ int __init hgafb_init(void)
 	return 0;
 }
 
-	/*
-	 *  Setup
-	 */
-
-int __init hgafb_setup(char *options)
-{
-	return 0;
-}
-
 #ifdef MODULE
 static void __exit hgafb_exit(void)
 {
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -1,6 +1,6 @@
 /*
- * $Id: hitfb.c,v 1.12 2004/03/16 00:07:51 lethal Exp $
  * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device
+ *
  * (C) 1999 Mihai Spatar
  * (C) 2000 YAEGASHI Takeshi
  * (C) 2003, 2004 Paul Mundt
@@ -40,15 +40,15 @@
 static struct fb_var_screeninfo hitfb_var __initdata = {
 	.activate	= FB_ACTIVATE_NOW,
 	.height		= -1,
-	.width 		= -1,
-	.vmode 		= FB_VMODE_NONINTERLACED,
+	.width		= -1,
+	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo hitfb_fix __initdata = {
-	.id 		= "Hitachi HD64461",
-	.type 		= FB_TYPE_PACKED_PIXELS,
-	.ypanstep 	= 8,
-	.accel 		= FB_ACCEL_NONE,
+	.id		= "Hitachi HD64461",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.ypanstep	= 8,
+	.accel		= FB_ACCEL_NONE,
 };
 
 static u32 pseudo_palette[16];
@@ -255,14 +255,14 @@ static int hitfb_setcolreg(unsigned regn
 }
 
 static struct fb_ops hitfb_ops = {
-	.owner 			= THIS_MODULE,
-	.fb_setcolreg 	= hitfb_setcolreg,
-	.fb_blank 		= hitfb_blank,
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= hitfb_setcolreg,
+	.fb_blank	= hitfb_blank,
 	.fb_pan_display = hitfb_pan_display,
-	.fb_fillrect 	= hitfb_fillrect,
-	.fb_copyarea 	= hitfb_copyarea,
-	.fb_imageblit 	= cfb_imageblit,
-	.fb_cursor 		= soft_cursor,
+	.fb_fillrect	= hitfb_fillrect,
+	.fb_copyarea	= hitfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
 };
 
 int __init hitfb_init(void)
@@ -324,7 +324,7 @@ int __init hitfb_init(void)
 	fb_info.var = hitfb_var;
 	fb_info.fix = hitfb_fix;
 	fb_info.pseudo_palette = pseudo_palette;
-	fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	fb_info.flags = FBINFO_DEFAULT;
 
 	fb_info.screen_base = (void *)hitfb_fix.smem_start;
 
@@ -345,9 +345,6 @@ static void __exit hitfb_exit(void)
 }
 
 module_init(hitfb_init);
-
-#ifdef MODULE
 module_exit(hitfb_exit);
-#endif
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/i810/i810_gtf.c b/drivers/video/i810/i810_gtf.c
--- a/drivers/video/i810/i810_gtf.c
+++ b/drivers/video/i810/i810_gtf.c
@@ -26,7 +26,7 @@ struct wm_info {
    u32  wm;
 };
 
-struct wm_info i810_wm_8_100[] = {
+static struct wm_info i810_wm_8_100[] = {
 	{ 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
 	{ 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
 	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
@@ -40,7 +40,7 @@ struct wm_info i810_wm_8_100[] = {
 	{ 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
 };
 
-struct wm_info i810_wm_16_100[] = {
+static struct wm_info i810_wm_16_100[] = {
 	{ 15, 0x0070c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
 	{ 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
 	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
@@ -54,7 +54,7 @@ struct wm_info i810_wm_16_100[] = {
 	{ 218, 0x22416000 }, { 229, 0x22416000 },
 };
 
-struct wm_info i810_wm_24_100[] = {
+static struct wm_info i810_wm_24_100[] = {
 	{ 15, 0x0020c000 },  { 19, 0x0040c000 },  { 25, 0x22009000 },
 	{ 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
 	{ 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
@@ -67,7 +67,7 @@ struct wm_info i810_wm_24_100[] = {
 	{ 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
 };
 
-struct wm_info i810_wm_8_133[] = {
+static struct wm_info i810_wm_8_133[] = {
 	{ 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
 	{ 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
 	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
@@ -81,7 +81,7 @@ struct wm_info i810_wm_8_133[] = {
 	{ 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
 };
 
-struct wm_info i810_wm_16_133[] = {
+static struct wm_info i810_wm_16_133[] = {
 	{ 15, 0x0020c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
 	{ 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
 	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
@@ -95,7 +95,7 @@ struct wm_info i810_wm_16_133[] = {
 	{ 218, 0x22416000 }, { 229, 0x22416000 },
 };
 
-struct wm_info i810_wm_24_133[] = {
+static struct wm_info i810_wm_24_133[] = {
 	{ 15, 0x0020c000 },  { 19, 0x00408000 },  { 25, 0x22009000 },
 	{ 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
 	{ 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -635,7 +635,7 @@ static void i810_save_vga_state(struct i
  * DESCRIPTION:
  * Calculates buffer pitch in bytes.  
  */
-u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
+static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
 {
    	u32 length;
 	
@@ -724,7 +724,7 @@ static void i810_calc_dclk(u32 freq, u32
  * Description:
  * Shows or hides the hardware cursor
  */
-void i810_enable_cursor(u8 __iomem *mmio, int mode)
+static void i810_enable_cursor(u8 __iomem *mmio, int mode)
 {
 	u32 temp;
 	
@@ -999,8 +999,16 @@ static int i810_check_params(struct fb_v
 	info->monspecs.dclkmin = 15000000;
 
 	if (fb_validate_mode(var, info)) {
-		if (fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+		if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
+			int default_sync = (info->monspecs.hfmin-HFMIN)
+						|(info->monspecs.hfmax-HFMAX)
+						|(info->monspecs.vfmin-VFMIN)
+						|(info->monspecs.vfmax-VFMAX);
+			printk("i810fb: invalid video mode%s\n",
+			    default_sync ? "" :
+			    ". Specifying vsyncN/hsyncN parameters may help");
 			return -EINVAL;
+		}
 	}
 	
 	var->xres = xres;
@@ -1492,7 +1500,7 @@ static struct fb_ops i810fb_ops __devini
 /***********************************************************************
  *                         Power Management                            *
  ***********************************************************************/
-static int i810fb_suspend(struct pci_dev *dev, u32 state)
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	struct fb_info *info = pci_get_drvdata(dev);
 	struct i810fb_par *par = (struct i810fb_par *) info->par;
@@ -1524,7 +1532,7 @@ static int i810fb_suspend(struct pci_dev
 		pci_disable_device(dev);
 	}
 	pci_save_state(dev);
-	pci_set_power_state(dev, state);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
 
 	return 0;
 }
@@ -1538,7 +1546,7 @@ static int i810fb_resume(struct pci_dev 
 		return 0;
 
 	pci_restore_state(dev);
-	pci_set_power_state(dev, 0);
+	pci_set_power_state(dev, PCI_D0);
 	pci_enable_device(dev);
 	agp_bind_memory(par->i810_gtt.i810_fb_memory,
 			par->fb.offset);
@@ -1591,40 +1599,41 @@ static int __devinit i810_alloc_agp_mem(
 {
 	struct i810fb_par *par = (struct i810fb_par *) info->par;
 	int size;
+	struct agp_bridge_data *bridge;
 	
 	i810_fix_offsets(par);
 	size = par->fb.size + par->iring.size;
 
-	if (agp_backend_acquire()) {
+	if (!(bridge = agp_backend_acquire(par->dev))) {
 		printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
 		return -ENODEV;
 	}
 	if (!(par->i810_gtt.i810_fb_memory = 
-	      agp_allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) {
+	      agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {
 		printk("i810fb_alloc_fbmem: can't allocate framebuffer "
 		       "memory\n");
-		agp_backend_release();
+		agp_backend_release(bridge);
 		return -ENOMEM;
 	}
 	if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
 			    par->fb.offset)) {
 		printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
-		agp_backend_release();
+		agp_backend_release(bridge);
 		return -EBUSY;
 	}	
 	
 	if (!(par->i810_gtt.i810_cursor_memory = 
-	      agp_allocate_memory(par->cursor_heap.size >> 12,
+	      agp_allocate_memory(bridge, par->cursor_heap.size >> 12,
 				  AGP_PHYSICAL_MEMORY))) {
 		printk("i810fb_alloc_cursormem:  can't allocate" 
 		       "cursor memory\n");
-		agp_backend_release();
+		agp_backend_release(bridge);
 		return -ENOMEM;
 	}
 	if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
 			    par->cursor_heap.offset)) {
 		printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
-		agp_backend_release();
+		agp_backend_release(bridge);
 		return -EBUSY;
 	}	
 
@@ -1632,7 +1641,7 @@ static int __devinit i810_alloc_agp_mem(
 
 	i810_fix_pointers(par);
 
-	agp_backend_release();
+	agp_backend_release(bridge);
 
 	return 0;
 }
@@ -1804,8 +1813,9 @@ i810_allocate_pci_resource(struct i810fb
 
 	return 0;
 }
-	
-int __init i810fb_setup(char *options)
+
+#ifndef MODULE
+static int __init i810fb_setup(char *options)
 {
 	char *this_opt, *suffix = NULL;
 
@@ -1850,6 +1860,7 @@ int __init i810fb_setup(char *options)
 	}
 	return 0;
 }
+#endif
 
 static int __devinit i810fb_init_pci (struct pci_dev *dev, 
 				   const struct pci_device_id *entry)
@@ -1976,7 +1987,7 @@ static void __exit i810fb_remove_pci(str
 }                                                	
 
 #ifndef MODULE
-int __init i810fb_init(void)
+static int __init i810fb_init(void)
 {
 	char *option = NULL;
 
@@ -1994,7 +2005,7 @@ int __init i810fb_init(void)
 
 #ifdef MODULE
 
-int __init i810fb_init(void)
+static int __init i810fb_init(void)
 {
 	hsync1 *= 1000;
 	hsync2 *= 1000;
@@ -2020,10 +2031,10 @@ MODULE_PARM_DESC(vyres, "Virtual vertica
 		 " (default = 480)");
 module_param(hsync1, int, 0);
 MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
-		 " (default = 31)");
+		 " (default = 29)");
 module_param(hsync2, int, 0);
 MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
-		 " (default = 31)");
+		 " (default = 30)");
 module_param(vsync1, int, 0);
 MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
 		 " (default = 50)");
diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h
--- a/drivers/video/i810/i810_main.h
+++ b/drivers/video/i810/i810_main.h
@@ -18,7 +18,7 @@ static int  __devinit i810fb_init_pci (s
 				       const struct pci_device_id *entry);
 static void __exit i810fb_remove_pci(struct pci_dev *dev);
 static int i810fb_resume(struct pci_dev *dev);
-static int i810fb_suspend(struct pci_dev *dev, u32 state);
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
 
 /*
  * voffset - framebuffer offset in MiB from aperture start address.  In order for
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -536,8 +536,7 @@ int __init igafb_init(void)
 	if (!iga_init(info, par)) {
 		iounmap((void *)par->io_base);
 		iounmap(info->screen_base);
-		if (par->mmap_map)
-			kfree(par->mmap_map);
+		kfree(par->mmap_map);
 		kfree(info);
         }
 
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -228,7 +228,7 @@ struct initvalues {
 	__u8 addr, value;
 };
 
-static struct initvalues ibm_initregs[] __initdata = {
+static struct initvalues ibm_initregs[] __devinitdata = {
 	{ CLKCTL,	0x21 },
 	{ SYNCCTL,	0x00 },
 	{ HSYNCPOS,	0x00 },
@@ -275,7 +275,7 @@ static struct initvalues ibm_initregs[] 
 	{ KEYCTL,	0x00 }
 };
 
-static struct initvalues tvp_initregs[] __initdata = {
+static struct initvalues tvp_initregs[] __devinitdata = {
 	{ TVPIRICC,	0x00 },
 	{ TVPIRBRC,	0xe4 },
 	{ TVPIRLAC,	0x06 },
@@ -338,7 +338,7 @@ enum {
 static int inverse = 0;
 static char fontname[40] __initdata = { 0 };
 #if defined(CONFIG_PPC)
-static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
+static signed char init_vmode __devinitdata = -1, init_cmode __devinitdata = -1;
 #endif
 
 static struct imstt_regvals tvp_reg_init_2 = {
@@ -1287,12 +1287,12 @@ imsttfb_ioctl(struct inode *inode, struc
 		case FBIMSTT_SETCMAPREG:
 			if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
-			write_reg_le32(((u_int *)par->cmap_regs), reg[0], reg[1]);
+			write_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0], reg[1]);
 			return 0;
 		case FBIMSTT_GETCMAPREG:
 			if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
-			reg[1] = read_reg_le32(((u_int *)par->cmap_regs), reg[0]);
+			reg[1] = read_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0]);
 			if (copy_to_user((void __user *)(arg + 4), &reg[1], 4))
 				return -EFAULT;
 			return 0;
@@ -1348,7 +1348,7 @@ static struct fb_ops imsttfb_ops = {
 	.fb_ioctl 	= imsttfb_ioctl,
 };
 
-static void __init 
+static void __devinit
 init_imstt(struct fb_info *info)
 {
 	struct imstt_par *par = (struct imstt_par *) info->par;
@@ -1547,7 +1547,7 @@ imsttfb_remove(struct pci_dev *pdev)
 }
 
 #ifndef MODULE
-int __init 
+static int __init
 imsttfb_setup(char *options)
 {
 	char *this_opt;
@@ -1601,7 +1601,7 @@ imsttfb_setup(char *options)
 
 #endif /* MODULE */
 
-int __init imsttfb_init(void)
+static int __init imsttfb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -1611,7 +1611,7 @@ int __init imsttfb_init(void)
 
 	imsttfb_setup(option);
 #endif
-	return pci_module_init(&imsttfb_pci_driver);
+	return pci_register_driver(&imsttfb_pci_driver);
 }
  
 static void __exit imsttfb_exit(void)
@@ -1619,9 +1619,8 @@ static void __exit imsttfb_exit(void)
 	pci_unregister_driver(&imsttfb_pci_driver);
 }
 
-#ifdef MODULE
 MODULE_LICENSE("GPL");
-#endif
+
 module_init(imsttfb_init);
 module_exit(imsttfb_exit);
 
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/imxfb.c
@@ -0,0 +1,695 @@
+/*
+ *  linux/drivers/video/imxfb.c
+ *
+ *  Freescale i.MX Frame Buffer device driver
+ *
+ *  Copyright (C) 2004 Sascha Hauer, Pengutronix
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ * 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.
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ *	linux-arm-kernel@lists.arm.linux.org.uk
+ */
+
+//#define DEBUG 1
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <asm/arch/imxfb.h>
+
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
+
+#include "imxfb.h"
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 8,  .length = 4, },
+	.green	= { .offset = 4,  .length = 4, },
+	.blue	= { .offset = 0,  .length = 4, },
+	.transp = { .offset = 0,  .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset = 0,  .length = 8, },
+	.green	= { .offset = 0,  .length = 8, },
+	.blue	= { .offset = 0,  .length = 8, },
+	.transp = { .offset = 0,  .length = 0, },
+};
+
+static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+#define LCDC_PALETTE(x) __REG2(IMX_LCDC_BASE+0x800, (x)<<2)
+static int
+imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans, struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+	u_int val, ret = 1;
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	if (regno < fbi->palette_size) {
+		val = (CNVT_TOHW(red, 4) << 8) |
+		      (CNVT_TOHW(green,4) << 4) |
+		      CNVT_TOHW(blue,  4);
+
+		LCDC_PALETTE(regno) = val;
+		ret = 0;
+	}
+	return ret;
+}
+
+static int
+imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		   u_int trans, struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If inverse mode was selected, invert all the colours
+	 * rather than the register number.  The register number
+	 * is what you poke into the framebuffer to produce the
+	 * colour you requested.
+	 */
+	if (fbi->cmap_inverse) {
+		red   = 0xffff - red;
+		green = 0xffff - green;
+		blue  = 0xffff - blue;
+	}
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no mater what visual we are using.
+	 */
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+					7471 * blue) >> 16;
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 12 or 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = info->pseudo_palette;
+
+			val  = chan_to_field(red, &info->var.red);
+			val |= chan_to_field(green, &info->var.green);
+			val |= chan_to_field(blue, &info->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = imxfb_setpalettereg(regno, red, green, blue, trans, info);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ *  imxfb_check_var():
+ *    Round up in the following order: bits_per_pixel, xres,
+ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ *    bitfields, horizontal timing, vertical timing.
+ */
+static int
+imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+	int rgbidx;
+
+	if (var->xres < MIN_XRES)
+		var->xres = MIN_XRES;
+	if (var->yres < MIN_YRES)
+		var->yres = MIN_YRES;
+	if (var->xres > fbi->max_xres)
+		var->xres = fbi->max_xres;
+	if (var->yres > fbi->max_yres)
+		var->yres = fbi->max_yres;
+	var->xres_virtual = max(var->xres_virtual, var->xres);
+	var->yres_virtual = max(var->yres_virtual, var->yres);
+
+	pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+	switch (var->bits_per_pixel) {
+	case 16:
+		rgbidx = RGB_16;
+		break;
+	case 8:
+		rgbidx = RGB_8;
+		break;
+	default:
+		rgbidx = RGB_16;
+	}
+
+	/*
+	 * Copy the RGB parameters for this display
+	 * from the machine specific parameters.
+	 */
+	var->red    = fbi->rgb[rgbidx]->red;
+	var->green  = fbi->rgb[rgbidx]->green;
+	var->blue   = fbi->rgb[rgbidx]->blue;
+	var->transp = fbi->rgb[rgbidx]->transp;
+
+	pr_debug("RGBT length = %d:%d:%d:%d\n",
+		var->red.length, var->green.length, var->blue.length,
+		var->transp.length);
+
+	pr_debug("RGBT offset = %d:%d:%d:%d\n",
+		var->red.offset, var->green.offset, var->blue.offset,
+		var->transp.offset);
+
+	return 0;
+}
+
+/*
+ * imxfb_set_par():
+ *	Set the user defined part of the display for the specified console
+ */
+static int imxfb_set_par(struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+
+	pr_debug("set_par\n");
+
+	if (var->bits_per_pixel == 16)
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	else if (!fbi->cmap_static)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else {
+		/*
+		 * Some people have weird ideas about wanting static
+		 * pseudocolor maps.  I suspect their user space
+		 * applications are broken.
+		 */
+		info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+	}
+
+	info->fix.line_length = var->xres_virtual *
+				  var->bits_per_pixel / 8;
+	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+	imxfb_activate_var(var, info);
+
+	return 0;
+}
+
+static void imxfb_enable_controller(struct imxfb_info *fbi)
+{
+	pr_debug("Enabling LCD controller\n");
+
+	/* initialize LCDC */
+	LCDC_RMCR &= ~RMCR_LCDC_EN;		/* just to be safe... */
+
+	LCDC_SSA	= fbi->screen_dma;
+	/* physical screen start address	    */
+	LCDC_VPW	= VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4);
+
+	LCDC_POS	= 0x00000000;   /* panning offset 0 (0 pixel offset)        */
+
+	/* disable hardware cursor */
+	LCDC_CPOS	&= ~(CPOS_CC0 | CPOS_CC1);
+
+	/* fixed burst length (see erratum 11) */
+	LCDC_DMACR = DMACR_BURST | DMACR_HM(8) | DMACR_TM(2);
+
+	LCDC_RMCR = RMCR_LCDC_EN;
+
+	if(fbi->backlight_power)
+		fbi->backlight_power(1);
+	if(fbi->lcd_power)
+		fbi->lcd_power(1);
+}
+
+static void imxfb_disable_controller(struct imxfb_info *fbi)
+{
+	pr_debug("Disabling LCD controller\n");
+
+	if(fbi->backlight_power)
+		fbi->backlight_power(0);
+	if(fbi->lcd_power)
+		fbi->lcd_power(0);
+
+	LCDC_RMCR = 0;
+}
+
+static int imxfb_blank(int blank, struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+
+	pr_debug("imxfb_blank: blank=%d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imxfb_disable_controller(fbi);
+		break;
+
+	case FB_BLANK_UNBLANK:
+		imxfb_enable_controller(fbi);
+		break;
+	}
+	return 0;
+}
+
+static struct fb_ops imxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= imxfb_check_var,
+	.fb_set_par	= imxfb_set_par,
+	.fb_setcolreg	= imxfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imxfb_blank,
+	.fb_cursor	= soft_cursor, /* FIXME: i.MX can do hardware cursor */
+};
+
+/*
+ * imxfb_activate_var():
+ *	Configures LCD Controller based on entries in var parameter.  Settings are
+ *	only written to the controller if changes were made.
+ */
+static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+	pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
+		var->xres, var->hsync_len,
+		var->left_margin, var->right_margin);
+	pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
+		var->yres, var->vsync_len,
+		var->upper_margin, var->lower_margin);
+
+#if DEBUG_VAR
+	if (var->xres < 16        || var->xres > 1024)
+		printk(KERN_ERR "%s: invalid xres %d\n",
+			info->fix.id, var->xres);
+	if (var->hsync_len < 1    || var->hsync_len > 64)
+		printk(KERN_ERR "%s: invalid hsync_len %d\n",
+			info->fix.id, var->hsync_len);
+	if (var->left_margin > 255)
+		printk(KERN_ERR "%s: invalid left_margin %d\n",
+			info->fix.id, var->left_margin);
+	if (var->right_margin > 255)
+		printk(KERN_ERR "%s: invalid right_margin %d\n",
+			info->fix.id, var->right_margin);
+	if (var->yres < 1 || var->yres > 511)
+		printk(KERN_ERR "%s: invalid yres %d\n",
+			info->fix.id, var->yres);
+	if (var->vsync_len > 100)
+		printk(KERN_ERR "%s: invalid vsync_len %d\n",
+			info->fix.id, var->vsync_len);
+	if (var->upper_margin > 63)
+		printk(KERN_ERR "%s: invalid upper_margin %d\n",
+			info->fix.id, var->upper_margin);
+	if (var->lower_margin > 255)
+		printk(KERN_ERR "%s: invalid lower_margin %d\n",
+			info->fix.id, var->lower_margin);
+#endif
+
+	LCDC_HCR	= HCR_H_WIDTH(var->hsync_len) |
+	                  HCR_H_WAIT_1(var->left_margin) |
+			  HCR_H_WAIT_2(var->right_margin);
+
+	LCDC_VCR	= VCR_V_WIDTH(var->vsync_len) |
+	                  VCR_V_WAIT_1(var->upper_margin) |
+			  VCR_V_WAIT_2(var->lower_margin);
+
+	LCDC_SIZE	= SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres);
+	LCDC_PCR	= fbi->pcr;
+	LCDC_PWMR	= fbi->pwmr;
+	LCDC_LSCR1	= fbi->lscr1;
+
+	return 0;
+}
+
+static void imxfb_setup_gpio(struct imxfb_info *fbi)
+{
+	int width;
+
+	LCDC_RMCR	&= ~(RMCR_LCDC_EN | RMCR_SELF_REF);
+
+	if( fbi->pcr & PCR_TFT )
+		width = 16;
+	else
+		width = 1 << ((fbi->pcr >> 28) & 0x3);
+
+	switch(width) {
+	case 16:
+		imx_gpio_mode(PD30_PF_LD15);
+		imx_gpio_mode(PD29_PF_LD14);
+		imx_gpio_mode(PD28_PF_LD13);
+		imx_gpio_mode(PD27_PF_LD12);
+		imx_gpio_mode(PD26_PF_LD11);
+		imx_gpio_mode(PD25_PF_LD10);
+		imx_gpio_mode(PD24_PF_LD9);
+		imx_gpio_mode(PD23_PF_LD8);
+	case 8:
+		imx_gpio_mode(PD22_PF_LD7);
+		imx_gpio_mode(PD21_PF_LD6);
+		imx_gpio_mode(PD20_PF_LD5);
+		imx_gpio_mode(PD19_PF_LD4);
+	case 4:
+		imx_gpio_mode(PD18_PF_LD3);
+		imx_gpio_mode(PD17_PF_LD2);
+	case 2:
+		imx_gpio_mode(PD16_PF_LD1);
+	case 1:
+		imx_gpio_mode(PD15_PF_LD0);
+	}
+
+	/* initialize GPIOs */
+	imx_gpio_mode(PD6_PF_LSCLK);
+	imx_gpio_mode(PD10_PF_SPL_SPR);
+	imx_gpio_mode(PD11_PF_CONTRAST);
+	imx_gpio_mode(PD14_PF_FLM_VSYNC);
+	imx_gpio_mode(PD13_PF_LP_HSYNC);
+	imx_gpio_mode(PD7_PF_REV);
+	imx_gpio_mode(PD8_PF_CLS);
+
+#ifndef CONFIG_MACH_PIMX1
+	/* on PiMX1 used as buffers enable signal
+	 */
+	imx_gpio_mode(PD9_PF_PS);
+#endif
+
+#ifndef CONFIG_MACH_MX1FS2
+	/* on mx1fs2 this pin is used to (de)activate the display, so we need
+	 * it as a normal gpio
+	 */
+	imx_gpio_mode(PD12_PF_ACD_OE);
+#endif
+
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks.  Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int imxfb_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct imxfb_info *fbi = dev_get_drvdata(dev);
+	pr_debug("%s\n",__FUNCTION__);
+
+	if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
+		imxfb_disable_controller(fbi);
+	return 0;
+}
+
+static int imxfb_resume(struct device *dev, u32 level)
+{
+	struct imxfb_info *fbi = dev_get_drvdata(dev);
+	pr_debug("%s\n",__FUNCTION__);
+
+	if (level == RESUME_ENABLE)
+		imxfb_enable_controller(fbi);
+	return 0;
+}
+#else
+#define imxfb_suspend	NULL
+#define imxfb_resume	NULL
+#endif
+
+static int __init imxfb_init_fbinfo(struct device *dev)
+{
+	struct imxfb_mach_info *inf = dev->platform_data;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct imxfb_info *fbi = info->par;
+
+	pr_debug("%s\n",__FUNCTION__);
+
+	info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
+	if (!info->pseudo_palette)
+		return -ENOMEM;
+
+	memset(fbi, 0, sizeof(struct imxfb_info));
+	fbi->dev = dev;
+
+	strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
+
+	info->fix.type	= FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux		= 0;
+	info->fix.xpanstep		= 0;
+	info->fix.ypanstep		= 0;
+	info->fix.ywrapstep		= 0;
+	info->fix.accel	= FB_ACCEL_NONE;
+
+	info->var.nonstd		= 0;
+	info->var.activate		= FB_ACTIVATE_NOW;
+	info->var.height		= -1;
+	info->var.width	= -1;
+	info->var.accel_flags		= 0;
+	info->var.vmode	= FB_VMODE_NONINTERLACED;
+
+	info->fbops			= &imxfb_ops;
+	info->flags			= FBINFO_FLAG_DEFAULT;
+	info->pseudo_palette		= (fbi + 1);
+
+	fbi->rgb[RGB_16]		= &def_rgb_16;
+	fbi->rgb[RGB_8]			= &def_rgb_8;
+
+	fbi->max_xres			= inf->xres;
+	info->var.xres			= inf->xres;
+	info->var.xres_virtual		= inf->xres;
+	fbi->max_yres			= inf->yres;
+	info->var.yres			= inf->yres;
+	info->var.yres_virtual		= inf->yres;
+	fbi->max_bpp			= inf->bpp;
+	info->var.bits_per_pixel	= inf->bpp;
+	info->var.pixclock		= inf->pixclock;
+	info->var.hsync_len		= inf->hsync_len;
+	info->var.left_margin		= inf->left_margin;
+	info->var.right_margin		= inf->right_margin;
+	info->var.vsync_len		= inf->vsync_len;
+	info->var.upper_margin		= inf->upper_margin;
+	info->var.lower_margin		= inf->lower_margin;
+	info->var.sync			= inf->sync;
+	info->var.grayscale		= inf->cmap_greyscale;
+	fbi->cmap_inverse		= inf->cmap_inverse;
+	fbi->pcr			= inf->pcr;
+	fbi->lscr1			= inf->lscr1;
+	fbi->pwmr			= inf->pwmr;
+	fbi->lcd_power			= inf->lcd_power;
+	fbi->backlight_power		= inf->backlight_power;
+	info->fix.smem_len		= fbi->max_xres * fbi->max_yres *
+					  fbi->max_bpp / 8;
+
+	return 0;
+}
+
+/*
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is
+ *	remapped into a non-cached, non-buffered, memory region to
+ *      allow pixel writes to occur without flushing the cache.
+ *      Once this area is remapped, all virtual memory access to the
+ *      video memory should occur at the new region.
+ */
+static int __init imxfb_map_video_memory(struct fb_info *info)
+{
+	struct imxfb_info *fbi = info->par;
+
+	fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
+	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+					&fbi->map_dma,GFP_KERNEL);
+
+	if (fbi->map_cpu) {
+		info->screen_base = fbi->map_cpu;
+		fbi->screen_cpu = fbi->map_cpu;
+		fbi->screen_dma = fbi->map_dma;
+		info->fix.smem_start = fbi->screen_dma;
+	}
+
+	return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+static int __init imxfb_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct imxfb_info *fbi;
+	struct fb_info *info;
+	struct imxfb_mach_info *inf;
+	struct resource *res;
+	int ret;
+
+	printk("i.MX Framebuffer driver\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if(!res)
+		return -ENODEV;
+
+	inf = dev->platform_data;
+	if(!inf) {
+		dev_err(dev,"No platform_data available\n");
+		return -ENOMEM;
+	}
+
+	info = framebuffer_alloc(sizeof(struct imxfb_info), dev);
+	if(!info)
+		return -ENOMEM;
+
+	fbi = info->par;
+
+	dev_set_drvdata(dev, info);
+
+	ret = imxfb_init_fbinfo(dev);
+	if( ret < 0 )
+		goto failed_init;
+
+	res = request_mem_region(res->start, res->end - res->start + 1, "IMXFB");
+	if (!res) {
+		ret = -EBUSY;
+		goto failed_regs;
+	}
+
+	if (!inf->fixed_screen_cpu) {
+		ret = imxfb_map_video_memory(info);
+		if (ret) {
+			dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+			ret = -ENOMEM;
+			goto failed_map;
+		}
+	} else {
+		/* Fixed framebuffer mapping enables location of the screen in eSRAM */
+		fbi->map_cpu = inf->fixed_screen_cpu;
+		fbi->map_dma = inf->fixed_screen_dma;
+		info->screen_base = fbi->map_cpu;
+		fbi->screen_cpu = fbi->map_cpu;
+		fbi->screen_dma = fbi->map_dma;
+		info->fix.smem_start = fbi->screen_dma;
+	}
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	imxfb_check_var(&info->var, info);
+
+	ret = fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+	if (ret < 0)
+		goto failed_cmap;
+
+	imxfb_setup_gpio(fbi);
+
+	imxfb_set_par(info);
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(dev, "failed to register framebuffer\n");
+		goto failed_register;
+	}
+
+	imxfb_enable_controller(fbi);
+
+	return 0;
+
+failed_register:
+	fb_dealloc_cmap(&info->cmap);
+failed_cmap:
+	if (!inf->fixed_screen_cpu)
+		dma_free_writecombine(dev,fbi->map_size,fbi->map_cpu,
+		           fbi->map_dma);
+failed_map:
+	kfree(info->pseudo_palette);
+failed_regs:
+	release_mem_region(res->start, res->end - res->start);
+failed_init:
+	dev_set_drvdata(dev, NULL);
+	framebuffer_release(info);
+	return ret;
+}
+
+static int imxfb_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	/* disable LCD controller */
+	LCDC_RMCR &= ~RMCR_LCDC_EN;
+
+	unregister_framebuffer(info);
+
+	fb_dealloc_cmap(&info->cmap);
+	kfree(info->pseudo_palette);
+	framebuffer_release(info);
+
+	release_mem_region(res->start, res->end - res->start + 1);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+void  imxfb_shutdown(struct device * dev)
+{
+	/* disable LCD Controller */
+	LCDC_RMCR &= ~RMCR_LCDC_EN;
+}
+
+static struct device_driver imxfb_driver = {
+	.name		= "imx-fb",
+	.bus		= &platform_bus_type,
+	.probe		= imxfb_probe,
+	.suspend	= imxfb_suspend,
+	.resume		= imxfb_resume,
+	.remove		= imxfb_remove,
+	.shutdown	= imxfb_shutdown,
+};
+
+int __init imxfb_init(void)
+{
+	return driver_register(&imxfb_driver);
+}
+
+static void __exit imxfb_cleanup(void)
+{
+	driver_unregister(&imxfb_driver);
+}
+
+module_init(imxfb_init);
+module_exit(imxfb_cleanup);
+
+MODULE_DESCRIPTION("Motorola i.MX framebuffer driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imxfb.h b/drivers/video/imxfb.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/imxfb.h
@@ -0,0 +1,72 @@
+/*
+ * linux/drivers/video/imxfb.h
+ *
+ *  Freescale i.MX Frame Buffer device driver
+ *
+ *  Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ *  Copyright (C) 1999 Eric A. Thomas
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ * 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.
+ */
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+#define RGB_16	(0)
+#define RGB_8	(1)
+#define NR_RGB	2
+
+struct imxfb_info {
+	struct device		*dev;
+	struct imxfb_rgb	*rgb[NR_RGB];
+
+	u_int			max_bpp;
+	u_int			max_xres;
+	u_int			max_yres;
+
+	/*
+	 * These are the addresses we mapped
+	 * the framebuffer memory region to.
+	 */
+	dma_addr_t		map_dma;
+	u_char *		map_cpu;
+	u_int			map_size;
+
+	u_char *		screen_cpu;
+	dma_addr_t		screen_dma;
+	u_int			palette_size;
+
+	dma_addr_t		dbar1;
+	dma_addr_t		dbar2;
+
+	u_int			pcr;
+	u_int			pwmr;
+	u_int			lscr1;
+	u_int			cmap_inverse:1,
+				cmap_static:1,
+				unused:30;
+
+	void (*lcd_power)(int);
+	void (*backlight_power)(int);
+};
+
+#define IMX_NAME	"IMX"
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -10,7 +10,7 @@
 /*** Version/name ***/
 #define INTELFB_VERSION			"0.9.2"
 #define INTELFB_MODULE_NAME		"intelfb"
-#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G"
 
 
 /*** Debug/feature defines ***/
@@ -36,7 +36,7 @@
 #endif
 
 #ifndef PREFERRED_MODE
-#define PREFERRED_MODE			"1024x768-16@60"
+#define PREFERRED_MODE			"1024x768-32@70"
 #endif
 
 /*** hw-related values ***/
@@ -46,6 +46,7 @@
 #define PCI_DEVICE_ID_INTEL_845G	0x2562
 #define PCI_DEVICE_ID_INTEL_85XGM	0x3582
 #define PCI_DEVICE_ID_INTEL_865G	0x2572
+#define PCI_DEVICE_ID_INTEL_915G	0x2582
 
 /* Size of MMIO region */
 #define INTEL_REG_SIZE			0x80000
@@ -117,7 +118,8 @@ enum intel_chips {
 	INTEL_852GME,
 	INTEL_855GM,
 	INTEL_855GME,
-	INTEL_865G
+	INTEL_865G,
+	INTEL_915G
 };
 
 struct intelfb_hwstate {
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1,7 +1,7 @@
 /*
  * intelfb
  *
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G
  * integrated graphics chips.
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
@@ -135,9 +135,45 @@
 #endif
 
 #include "intelfb.h"
-#include "intelfbdrv.h"
 #include "intelfbhw.h"
 
+static void __devinit get_initial_mode(struct intelfb_info *dinfo);
+static void update_dinfo(struct intelfb_info *dinfo,
+			 struct fb_var_screeninfo *var);
+static int intelfb_get_fix(struct fb_fix_screeninfo *fix,
+			   struct fb_info *info);
+
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int intelfb_set_par(struct fb_info *info);
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info);
+
+static int intelfb_blank(int blank, struct fb_info *info);
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+
+static void intelfb_fillrect(struct fb_info *info,
+			     const struct fb_fillrect *rect);
+static void intelfb_copyarea(struct fb_info *info,
+			     const struct fb_copyarea *region);
+static void intelfb_imageblit(struct fb_info *info,
+			      const struct fb_image *image);
+static int intelfb_cursor(struct fb_info *info,
+			   struct fb_cursor *cursor);
+
+static int intelfb_sync(struct fb_info *info);
+
+static int intelfb_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg,
+			 struct fb_info *info);
+
+static int __devinit intelfb_pci_register(struct pci_dev *pdev,
+					  const struct pci_device_id *ent);
+static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
+static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
+
 /*
  * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
  * mobile chipsets from being registered.
@@ -153,6 +189,7 @@ static struct pci_device_id intelfb_pci_
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
 	{ 0, }
 };
 
@@ -191,17 +228,17 @@ MODULE_DESCRIPTION(
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
 
-static int accel        __initdata = 1;
-static int vram         __initdata = 4;
-static int hwcursor     __initdata = 1;
-static int mtrr         __initdata = 1;
-static int fixed        __initdata = 0;
-static int noinit       __initdata = 0;
-static int noregister   __initdata = 0;
-static int probeonly    __initdata = 0;
-static int idonly       __initdata = 0;
-static int bailearly    __initdata = 0;
-static char *mode       __initdata = NULL;
+static int accel        = 1;
+static int vram         = 4;
+static int hwcursor     = 1;
+static int mtrr         = 1;
+static int fixed        = 0;
+static int noinit       = 0;
+static int noregister   = 0;
+static int probeonly    = 0;
+static int idonly       = 0;
+static int bailearly    = 0;
+static char *mode       = NULL;
 
 module_param(accel, bool, S_IRUGO);
 MODULE_PARM_DESC(accel, "Enable console acceleration");
@@ -226,42 +263,6 @@ MODULE_PARM_DESC(bailearly, "Bail out ea
 module_param(mode, charp, S_IRUGO);
 MODULE_PARM_DESC(mode,
 		 "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");
-/***************************************************************
- *                     modules entry points                    *
- ***************************************************************/
-
-/* module load/unload entry points */
-int __init
-intelfb_init(void)
-{
-#ifndef MODULE
-	char *option = NULL;
-#endif
-
-	DBG_MSG("intelfb_init\n");
-
-	INF_MSG("Framebuffer driver for "
-		"Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
-	INF_MSG("Version " INTELFB_VERSION "\n");
-
-	if (idonly)
-		return -ENODEV;
-
-#ifndef MODULE
-	if (fb_get_options("intelfb", &option))
-		return -ENODEV;
-	intelfb_setup(option);
-#endif
-
-	return pci_module_init(&intelfb_driver);
-}
-
-static void __exit
-intelfb_exit(void)
-{
-	DBG_MSG("intelfb_exit\n");
-	pci_unregister_driver(&intelfb_driver);
-}
 
 #ifndef MODULE
 #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
@@ -321,7 +322,7 @@ get_opt_bool(const char *this_opt, const
 	return 1;
 }
 
-int __init
+static int __init
 intelfb_setup(char *options)
 {
 	char *this_opt;
@@ -373,12 +374,41 @@ intelfb_setup(char *options)
 
 #endif
 
-module_init(intelfb_init);
+static int __init
+intelfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+#endif
 
-#ifdef MODULE
-module_exit(intelfb_exit);
+	DBG_MSG("intelfb_init\n");
+
+	INF_MSG("Framebuffer driver for "
+		"Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
+	INF_MSG("Version " INTELFB_VERSION "\n");
+
+	if (idonly)
+		return -ENODEV;
+
+#ifndef MODULE
+	if (fb_get_options("intelfb", &option))
+		return -ENODEV;
+	intelfb_setup(option);
 #endif
 
+	return pci_register_driver(&intelfb_driver);
+}
+
+static void __exit
+intelfb_exit(void)
+{
+	DBG_MSG("intelfb_exit\n");
+	pci_unregister_driver(&intelfb_driver);
+}
+
+module_init(intelfb_init);
+module_exit(intelfb_exit);
+
 /***************************************************************
  *                     mtrr support functions                  *
  ***************************************************************/
@@ -470,6 +500,9 @@ intelfb_pci_register(struct pci_dev *pde
 	struct agp_kern_info gtt_info;
 	int agp_memtype;
 	const char *s;
+	struct agp_bridge_data *bridge;
+ 	int aperture_bar = 0;
+ 	int mmio_bar = 1;
 
 	DBG_MSG("intelfb_pci_register\n");
 
@@ -516,13 +549,20 @@ intelfb_pci_register(struct pci_dev *pde
 	}
 
 	/* Set base addresses. */
-	dinfo->aperture.physical = pci_resource_start(pdev, 0);
-	dinfo->aperture.size     = pci_resource_len(pdev, 0);
-	dinfo->mmio_base_phys    = pci_resource_start(pdev, 1);
-
-	DBG_MSG("fb aperture: 0x%lx/0x%lx, MMIO region: 0x%lx/0x%lx\n",
-		pci_resource_start(pdev, 0), pci_resource_len(pdev, 0),
-		pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+	if (ent->device == PCI_DEVICE_ID_INTEL_915G) {
+		aperture_bar = 2;
+		mmio_bar = 0;
+		/* Disable HW cursor on 915G (not implemented yet) */
+		hwcursor = 0;
+	}
+	dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
+	dinfo->aperture.size     = pci_resource_len(pdev, aperture_bar);
+	dinfo->mmio_base_phys    = pci_resource_start(pdev, mmio_bar);
+	DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n",
+		(unsigned long long)pci_resource_start(pdev, aperture_bar),
+		(unsigned long long)pci_resource_len(pdev, aperture_bar),
+		(unsigned long long)pci_resource_start(pdev, mmio_bar),
+		(unsigned long long)pci_resource_len(pdev, mmio_bar));
 
 	/* Reserve the fb and MMIO regions */
 	if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size,
@@ -605,16 +645,16 @@ intelfb_pci_register(struct pci_dev *pde
 	}
 
 	/* Use agpgart to manage the GATT */
-	if (agp_backend_acquire()) {
+	if (!(bridge = agp_backend_acquire(pdev))) {
 		ERR_MSG("cannot acquire agp\n");
 		cleanup(dinfo);
 		return -ENODEV;
 	}
 
 	/* get the current gatt info */
-	if (agp_copy_info(&gtt_info)) {
+	if (agp_copy_info(bridge, &gtt_info)) {
 		ERR_MSG("cannot get agp info\n");
-		agp_backend_release();
+		agp_backend_release(bridge);
 		cleanup(dinfo);
 		return -ENODEV;
 	}
@@ -637,17 +677,17 @@ intelfb_pci_register(struct pci_dev *pde
 	/* Allocate memories (which aren't stolen) */
 	if (dinfo->accel) {
 		if (!(dinfo->gtt_ring_mem =
-		      agp_allocate_memory(dinfo->ring.size >> 12,
+		      agp_allocate_memory(bridge, dinfo->ring.size >> 12,
 					  AGP_NORMAL_MEMORY))) {
 			ERR_MSG("cannot allocate ring buffer memory\n");
-			agp_backend_release();
+			agp_backend_release(bridge);
 			cleanup(dinfo);
 			return -ENOMEM;
 		}
 		if (agp_bind_memory(dinfo->gtt_ring_mem,
 				    dinfo->ring.offset)) {
 			ERR_MSG("cannot bind ring buffer memory\n");
-			agp_backend_release();
+			agp_backend_release(bridge);
 			cleanup(dinfo);
 			return -EBUSY;
 		}
@@ -661,17 +701,17 @@ intelfb_pci_register(struct pci_dev *pde
 		agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
 			: AGP_NORMAL_MEMORY;
 		if (!(dinfo->gtt_cursor_mem =
-		      agp_allocate_memory(dinfo->cursor.size >> 12,
+		      agp_allocate_memory(bridge, dinfo->cursor.size >> 12,
 					  agp_memtype))) {
 			ERR_MSG("cannot allocate cursor memory\n");
-			agp_backend_release();
+			agp_backend_release(bridge);
 			cleanup(dinfo);
 			return -ENOMEM;
 		}
 		if (agp_bind_memory(dinfo->gtt_cursor_mem,
 				    dinfo->cursor.offset)) {
 			ERR_MSG("cannot bind cursor memory\n");
-			agp_backend_release();
+			agp_backend_release(bridge);
 			cleanup(dinfo);
 			return -EBUSY;
 		}
@@ -686,7 +726,7 @@ intelfb_pci_register(struct pci_dev *pde
 	}
 	if (dinfo->fbmem_gart) {
 		if (!(dinfo->gtt_fb_mem =
-		      agp_allocate_memory(dinfo->fb.size >> 12,
+		      agp_allocate_memory(bridge, dinfo->fb.size >> 12,
 					  AGP_NORMAL_MEMORY))) {
 			WRN_MSG("cannot allocate framebuffer memory - use "
 				"the stolen one\n");
@@ -709,7 +749,7 @@ intelfb_pci_register(struct pci_dev *pde
 	dinfo->fb_start = dinfo->fb.offset << 12;
 
 	/* release agpgart */
-	agp_backend_release();
+	agp_backend_release(bridge);
 
 	if (mtrr)
 		set_mtrr(dinfo);
@@ -989,13 +1029,15 @@ intelfb_init_var(struct intelfb_info *di
 	} else {
 		if (mode) {
 			msrc = fb_find_mode(var, dinfo->info, mode,
-					    NULL, 0, NULL, 0);
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
 			if (msrc)
 				msrc |= 8;
 		}
 		if (!msrc) {
 			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
-					    NULL, 0, NULL, 0);
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
 		}
 	}
 
diff --git a/drivers/video/intelfb/intelfbdrv.h b/drivers/video/intelfb/intelfbdrv.h
deleted file mode 100644
--- a/drivers/video/intelfb/intelfbdrv.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _INTELFBDRV_H
-#define _INTELFBDRV_H
-
-/*
- ******************************************************************************
- * intelfb
- *
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G
- * integrated graphics chips.
- *
- * Copyright © 2004 Sylvain Meyer
- *
- * Author: Sylvain Meyer
- *
- ******************************************************************************
- *    This program is free software; you can redistribute it 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.
-*/
-
-int __init intelfb_setup(char *options);
-static void __devinit get_initial_mode(struct intelfb_info *dinfo);
-static void update_dinfo(struct intelfb_info *dinfo,
-			 struct fb_var_screeninfo *var);
-static int intelfb_get_fix(struct fb_fix_screeninfo *fix,
-			   struct fb_info *info);
-
-static int intelfb_check_var(struct fb_var_screeninfo *var,
-			     struct fb_info *info);
-static int intelfb_set_par(struct fb_info *info);
-static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			     unsigned blue, unsigned transp,
-			     struct fb_info *info);
-
-static int intelfb_blank(int blank, struct fb_info *info);
-static int intelfb_pan_display(struct fb_var_screeninfo *var,
-			       struct fb_info *info);
-
-static void intelfb_fillrect(struct fb_info *info,
-			     const struct fb_fillrect *rect);
-static void intelfb_copyarea(struct fb_info *info,
-			     const struct fb_copyarea *region);
-static void intelfb_imageblit(struct fb_info *info,
-			      const struct fb_image *image);
-static int intelfb_cursor(struct fb_info *info,
-			   struct fb_cursor *cursor);
-
-static int intelfb_sync(struct fb_info *info);
-
-static int intelfb_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg,
-			 struct fb_info *info);
-
-static int __devinit intelfb_pci_register(struct pci_dev *pdev,
-					  const struct pci_device_id *ent);
-static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
-static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
-
-#endif
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -98,6 +98,11 @@ intelfbhw_get_chipset(struct pci_dev *pd
 		*chipset = INTEL_865G;
 		*mobile = 0;
 		return 0;
+	case PCI_DEVICE_ID_INTEL_915G:
+		*name = "Intel(R) 915G";
+		*chipset = INTEL_915G;
+		*mobile = 0;
+		return 0;
 	default:
 		return 1;
 	}
@@ -169,6 +174,12 @@ intelfbhw_get_memory(struct pci_dev *pde
 		case INTEL_855_GMCH_GMS_STOLEN_32M:
 			*stolen_size = MB(32) - KB(132);
 			return 0;
+		case INTEL_915G_GMCH_GMS_STOLEN_48M:
+			*stolen_size = MB(48) - KB(132);
+			return 0;
+		case INTEL_915G_GMCH_GMS_STOLEN_64M:
+			*stolen_size = MB(64) - KB(132);
+			return 0;
 		case INTEL_855_GMCH_GMS_DISABLED:
 			ERR_MSG("video memory is disabled\n");
 			return 0;
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -46,6 +46,9 @@
 #define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
 #define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
 
+#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4)
+
 /* HW registers */
 
 /* Fence registers */
diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c
--- a/drivers/video/kyro/STG4000InitDevice.c
+++ b/drivers/video/kyro/STG4000InitDevice.c
@@ -79,8 +79,8 @@ volatile u32 i,count=0; \
     for(i=0;i<X;i++) count++; \
 }
 
-u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg, u32 dwSubSysID,
-			 u32 dwRevID)
+static u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg,
+			      u32 dwSubSysID, u32 dwRevID)
 {
 	u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 };
 	u32 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 };
diff --git a/drivers/video/kyro/STG4000OverlayDevice.c b/drivers/video/kyro/STG4000OverlayDevice.c
--- a/drivers/video/kyro/STG4000OverlayDevice.c
+++ b/drivers/video/kyro/STG4000OverlayDevice.c
@@ -42,8 +42,8 @@
 #define STG4000_OVRL_MAX_HEIGHT 576
 
 /* Decimation and Scaling */
-u32 adwDecim8[33] = {
-	0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,
+static u32 adwDecim8[33] = {
+	    0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,
 	    0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7,
 	    0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab,
 	    0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525,
diff --git a/drivers/video/kyro/STG4000Ramdac.c b/drivers/video/kyro/STG4000Ramdac.c
--- a/drivers/video/kyro/STG4000Ramdac.c
+++ b/drivers/video/kyro/STG4000Ramdac.c
@@ -18,7 +18,6 @@
 
 static u32 STG_PIXEL_BUS_WIDTH = 128;	/* 128 bit bus width      */
 static u32 REF_CLOCK = 14318;
-STG4000REG __iomem *pSTGReg;
 
 int InitialiseRamdac(volatile STG4000REG __iomem * pSTGReg,
 		     u32 displayDepth,
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/video/kyro/kyrofb.c
+ *  linux/drivers/video/kyro/fbdev.c
  *
  *  Copyright (C) 2002 STMicroelectronics
  *  Copyright (C) 2003, 2004 Paul Mundt
@@ -43,14 +43,14 @@
 #define KHZ2PICOS(a) (1000000000UL/(a))
 
 /****************************************************************************/
-static struct fb_fix_screeninfo kyro_fix __initdata = {
+static struct fb_fix_screeninfo kyro_fix __devinitdata = {
 	.id		= "ST Kyro",
 	.type		= FB_TYPE_PACKED_PIXELS,
 	.visual		= FB_VISUAL_TRUECOLOR,
 	.accel		= FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo kyro_var __initdata = {
+static struct fb_var_screeninfo kyro_var __devinitdata = {
 	/* 640x480, 16bpp @ 60 Hz */
 	.xres		= 640,
 	.yres		= 480,
@@ -86,18 +86,18 @@ typedef struct {
 /* global graphics card info structure (one per card) */
 static device_info_t deviceInfo;
 
-static char *mode_option __initdata = NULL;
-static int nopan __initdata = 0;
-static int nowrap __initdata = 1;
+static char *mode_option __devinitdata = NULL;
+static int nopan __devinitdata = 0;
+static int nowrap __devinitdata = 1;
 #ifdef CONFIG_MTRR
-static int nomtrr __initdata = 0;
+static int nomtrr __devinitdata = 0;
 #endif
 
 /* PCI driver prototypes */
 static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static void kyrofb_remove(struct pci_dev *pdev);
 
-static struct fb_videomode kyro_modedb[] __initdata = {
+static struct fb_videomode kyro_modedb[] __devinitdata = {
 	{
 		/* 640x350 @ 85Hz */
 		NULL, 85, 640, 350, KHZ2PICOS(31500),
@@ -307,7 +307,7 @@ enum {
 };
 
 /* Accessors */
-int kyro_dev_video_mode_set(struct fb_info *info)
+static int kyro_dev_video_mode_set(struct fb_info *info)
 {
 	struct kyrofb_info *par = (struct kyrofb_info *)info->par;
 
@@ -339,8 +339,8 @@ int kyro_dev_video_mode_set(struct fb_in
 	return 0;
 }
 
-int kyro_dev_overlay_create(u32 ulWidth,
-			    u32 ulHeight, int bLinear)
+static int kyro_dev_overlay_create(u32 ulWidth,
+				   u32 ulHeight, int bLinear)
 {
 	u32 offset;
 	u32 stride, uvStride;
@@ -376,7 +376,7 @@ int kyro_dev_overlay_create(u32 ulWidth,
 	return 0;
 }
 
-int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight)
+static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight)
 {
 	if (deviceInfo.ulOverlayOffset == 0)
 		/* probably haven't called CreateOverlay yet */
@@ -558,7 +558,8 @@ static int kyrofb_setcolreg(u_int regno,
 	return 0;
 }
 
-int __init kyrofb_setup(char *options)
+#ifndef MODULE
+static int __init kyrofb_setup(char *options)
 {
 	char *this_opt;
 
@@ -583,6 +584,7 @@ int __init kyrofb_setup(char *options)
 
 	return 0;
 }
+#endif
 
 static int kyrofb_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg,
@@ -594,7 +596,8 @@ static int kyrofb_ioctl(struct inode *in
 
 	switch (cmd) {
 	case KYRO_IOCTL_OVERLAY_CREATE:
-		copy_from_user(&ol_create, argp, sizeof(overlay_create));
+		if (copy_from_user(&ol_create, argp, sizeof(overlay_create)))
+			return -EFAULT;
 
 		if (kyro_dev_overlay_create(ol_create.ulWidth,
 					    ol_create.ulHeight, 0) < 0) {
@@ -604,8 +607,9 @@ static int kyrofb_ioctl(struct inode *in
 		}
 		break;
 	case KYRO_IOCTL_OVERLAY_VIEWPORT_SET:
-		copy_from_user(&ol_viewport_set, argp,
-			       sizeof(overlay_viewport_set));
+		if (copy_from_user(&ol_viewport_set, argp,
+			       sizeof(overlay_viewport_set)))
+			return -EFAULT;
 
 		if (kyro_dev_overlay_viewport_set(ol_viewport_set.xOrgin,
 						  ol_viewport_set.yOrgin,
@@ -625,13 +629,16 @@ static int kyrofb_ioctl(struct inode *in
 		}
 		break;
 	case KYRO_IOCTL_UVSTRIDE:
-		copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(unsigned long));
+		if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(unsigned long)))
+			return -EFAULT;
 		break;
 	case KYRO_IOCTL_STRIDE:
-		copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(unsigned long));
+		if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(unsigned long)))
+			return -EFAULT;
 		break;
 	case KYRO_IOCTL_OVERLAY_OFFSET:
-		copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(unsigned long));
+		if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(unsigned long)))
+			return -EFAULT;
 		break;
 	}
 
@@ -786,7 +793,7 @@ static void __devexit kyrofb_remove(stru
 	kfree(info);
 }
 
-int __init kyrofb_init(void)
+static int __init kyrofb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -795,7 +802,7 @@ int __init kyrofb_init(void)
 		return -ENODEV;
 	kyrofb_setup(option);
 #endif
-	return pci_module_init(&kyrofb_pci_driver);
+	return pci_register_driver(&kyrofb_pci_driver);
 }
 
 static void __exit kyrofb_exit(void)
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -25,7 +25,7 @@ config LOGO_LINUX_CLUT224
 
 config LOGO_DEC_CLUT224
 	bool "224-color Digital Equipment Corporation Linux logo"
-	depends on LOGO && MACH_DECSTATION
+	depends on LOGO && (MACH_DECSTATION || ALPHA)
 	default y
 
 config LOGO_MAC_CLUT224
@@ -45,7 +45,7 @@ config LOGO_SGI_CLUT224
 
 config LOGO_SUN_CLUT224
 	bool "224-color Sun Linux logo"
-	depends on LOGO && (SPARC || SPARC64)
+	depends on LOGO && (SPARC32 || SPARC64)
 	default y
 
 config LOGO_SUPERH_MONO
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -23,35 +23,32 @@ logo-cfiles = $(notdir $(patsubst %.$(2)
 # Mono logos
 extra-y += $(call logo-cfiles,_mono,pbm)
 
-quiet_cmd_logo_mono    = MONO    $@
-      cmd_logo_mono    = scripts/pnmtologo -t mono -n $*_mono -o $@ $<
-
-$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE
-	$(call if_changed,logo_mono)
-
 # VGA16 logos
 extra-y += $(call logo-cfiles,_vga16,ppm)
 
-quiet_cmd_logo_vga16   = VGA16   $@
-      cmd_logo_vga16   = scripts/pnmtologo -t vga16 -n $*_vga16 -o $@ $<
-
-$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE
-	$(call if_changed,logo_vga16)
-
-#224 Logos
+# 224 Logos
 extra-y += $(call logo-cfiles,_clut224,ppm)
 
-quiet_cmd_logo_clut224 = CLUT224 $@
-      cmd_logo_clut224 = scripts/pnmtologo -t clut224 -n $*_clut224 -o $@ $<
-
-$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE
-	$(call if_changed,logo_clut224)
-
 # Gray 256
 extra-y += $(call logo-cfiles,_gray256,pgm)
 
-quiet_cmd_logo_gray256 = GRAY256 $@
-      cmd_logo_gray256 = scripts/pnmtologo -t gray256 -n $*_gray256 -o $@ $<
+# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
+quiet_cmd_logo = LOGO	$@
+	cmd_logo = scripts/pnmtologo \
+			-t $(patsubst $*_%,%,$(notdir $(basename $<))) \
+			-n $(notdir $(basename $<)) -o $@ $<
+
+$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE
+	$(call if_changed,logo)
+
+$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE
+	$(call if_changed,logo)
+
+$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE
+	$(call if_changed,logo)
 
 $(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE
-	$(call if_changed,logo_gray256)
+	$(call if_changed,logo)
+
+# Files generated that shall be removed upon make clean
+clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/linux_logo.h>
 #include <linux/stddef.h>
+#include <linux/module.h>
 
 #ifdef CONFIG_M68K
 #include <asm/setup.h>
@@ -66,8 +67,10 @@ const struct linux_logo *fb_find_logo(in
 		logo = &logo_linux_clut224;
 #endif
 #ifdef CONFIG_LOGO_DEC_CLUT224
-		/* DEC Linux logo on MIPS/MIPS64 */
+		/* DEC Linux logo on MIPS/MIPS64 or ALPHA */
+#ifndef CONFIG_ALPHA
 		if (mips_machgroup == MACH_GROUP_DEC)
+#endif
 			logo = &logo_dec_clut224;
 #endif
 #ifdef CONFIG_LOGO_MAC_CLUT224
@@ -97,4 +100,4 @@ const struct linux_logo *fb_find_logo(in
 	}
 	return logo;
 }
-
+EXPORT_SYMBOL_GPL(fb_find_logo);
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/string.h>
+#include <linux/module.h>
 
 #include "macmodes.h"
 
@@ -281,7 +282,7 @@ int mac_vmode_to_var(int vmode, int cmod
     var->vmode = mode->vmode;
     return 0;
 }
-
+EXPORT_SYMBOL(mac_vmode_to_var);
 
 /**
  *	mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair
@@ -326,7 +327,7 @@ int mac_var_to_vmode(const struct fb_var
     }
     return -EINVAL;
 }
-
+EXPORT_SYMBOL(mac_var_to_vmode);
 
 /**
  *	mac_map_monitor_sense - Convert monitor sense to vmode
@@ -348,7 +349,7 @@ int mac_map_monitor_sense(int sense)
 	    break;
     return map->vmode;
 }
-
+EXPORT_SYMBOL(mac_map_monitor_sense);
 
 /**
  *	mac_find_mode - find a video mode
@@ -384,3 +385,6 @@ int __init mac_find_mode(struct fb_var_s
     return fb_find_mode(var, info, mode_option, db, dbsize,
 			&mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp);
 }
+EXPORT_SYMBOL(mac_find_mode);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -438,13 +438,21 @@ static void matroxfb_1bpp_imageblit(WPMI
 		} else if (step == 1) {
 			/* Special case for 1..8bit widths */
 			while (height--) {
-				mga_writel(mmio, 0, *chardata);
+#if defined(__BIG_ENDIAN)
+				fb_writel((*chardata) << 24, mmio.vaddr);
+#else
+				fb_writel(*chardata, mmio.vaddr);
+#endif
 				chardata++;
 			}
 		} else if (step == 2) {
 			/* Special case for 9..15bit widths */
 			while (height--) {
-				mga_writel(mmio, 0, *(u_int16_t*)chardata);
+#if defined(__BIG_ENDIAN)
+				fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
+#else
+				fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
+#endif
 				chardata += 2;
 			}
 		} else {
@@ -454,7 +462,7 @@ static void matroxfb_1bpp_imageblit(WPMI
 				
 				for (i = 0; i < step; i += 4) {
 					/* Hope that there are at least three readable bytes beyond the end of bitmap */
-					mga_writel(mmio, 0, get_unaligned((u_int32_t*)(chardata + i)));
+					fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
 				}
 				chardata += step;
 			}
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -1908,8 +1908,8 @@ fail:;
 	return err;
 }
 
-LIST_HEAD(matroxfb_list);
-LIST_HEAD(matroxfb_driver_list);
+static LIST_HEAD(matroxfb_list);
+static LIST_HEAD(matroxfb_driver_list);
 
 #define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb)
 #define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node)
@@ -2287,7 +2287,7 @@ static void __exit matrox_done(void) {
 
 /* ************************* init in-kernel code ************************** */
 
-int __init matroxfb_setup(char *options) {
+static int __init matroxfb_setup(char *options) {
 	char *this_opt;
 
 	DBG(__FUNCTION__)
@@ -2428,7 +2428,7 @@ int __init matroxfb_setup(char *options)
 
 static int __initdata initialized = 0;
 
-int __init matroxfb_init(void)
+static int __init matroxfb_init(void)
 {
 	char *option = NULL;
 
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -170,14 +170,14 @@ static inline void mga_memcpy_toio(vaddr
 
 	if ((unsigned long)src & 3) {
 		while (len >= 4) {
-			writel(get_unaligned((u32 *)src), addr);
+			fb_writel(get_unaligned((u32 *)src), addr);
 			addr++;
 			len -= 4;
 			src += 4;
 		}
 	} else {
 		while (len >= 4) {
-			writel(*(u32 *)src, addr);
+			fb_writel(*(u32 *)src, addr);
 			addr++;
 			len -= 4;
 			src += 4;
@@ -764,7 +764,6 @@ void matroxfb_unregister_driver(struct m
 #define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags)
 extern void matroxfb_DAC_out(CPMINFO int reg, int val);
 extern int matroxfb_DAC_in(CPMINFO int reg);
-extern struct list_head matroxfb_list;
 extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
 extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc);
 extern int matroxfb_enable_irq(WPMINFO int reenable);
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -404,8 +404,8 @@ static int my_atoi(const char *name)
  *
  */
 
-int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
-		const struct fb_videomode *mode, unsigned int bpp)
+static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+		       const struct fb_videomode *mode, unsigned int bpp)
 {
     int err = 0;
 
@@ -722,6 +722,47 @@ struct fb_videomode *fb_find_best_mode(s
 }
 
 /**
+ * fb_find_nearest_mode - find mode closest video mode
+ *
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to modelist
+ *
+ * Finds best matching videomode, smaller or greater in dimension.
+ * If more than 1 videomode is found, will return the videomode with
+ * the closest refresh rate
+ */
+struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+					  struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode, *best = NULL;
+	u32 diff = -1, diff_refresh = -1;
+
+	list_for_each(pos, head) {
+		u32 d;
+
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+
+		d = abs(mode->xres - var->xres) +
+			abs(mode->yres - var->yres);
+		if (diff > d) {
+			diff = d;
+			best = mode;
+		} else if (diff == d) {
+			d = abs(mode->refresh - best->refresh);
+			if (diff_refresh > d) {
+				diff_refresh = d;
+				best = mode;
+			}
+		}
+	}
+
+	return best;
+}
+
+/**
  * fb_match_mode - find a videomode which exactly matches the timings in var
  * @var: pointer to struct fb_var_screeninfo
  * @head: pointer to struct list_head of modelist
@@ -846,5 +887,6 @@ EXPORT_SYMBOL(fb_delete_videomode);
 EXPORT_SYMBOL(fb_destroy_modelist);
 EXPORT_SYMBOL(fb_match_mode);
 EXPORT_SYMBOL(fb_find_best_mode);
+EXPORT_SYMBOL(fb_find_nearest_mode);
 EXPORT_SYMBOL(fb_videomode_to_modelist);
 EXPORT_SYMBOL(fb_find_mode);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -93,7 +93,7 @@ static int external;
 static int libretto;
 static int nostretch;
 static int nopciburst;
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
 
 #ifdef MODULE
 
@@ -400,21 +400,21 @@ static void neoUnlock(void)
  */
 static int paletteEnabled = 0;
 
-inline void VGAenablePalette(void)
+static inline void VGAenablePalette(void)
 {
 	vga_r(NULL, VGA_IS1_RC);
 	vga_w(NULL, VGA_ATT_W, 0x00);
 	paletteEnabled = 1;
 }
 
-inline void VGAdisablePalette(void)
+static inline void VGAdisablePalette(void)
 {
 	vga_r(NULL, VGA_IS1_RC);
 	vga_w(NULL, VGA_ATT_W, 0x20);
 	paletteEnabled = 0;
 }
 
-inline void VGAwATTR(u8 index, u8 value)
+static inline void VGAwATTR(u8 index, u8 value)
 {
 	if (paletteEnabled)
 		index &= ~0x20;
@@ -425,7 +425,7 @@ inline void VGAwATTR(u8 index, u8 value)
 	vga_wattr(NULL, index, value);
 }
 
-void vgaHWProtect(int on)
+static void vgaHWProtect(int on)
 {
 	unsigned char tmp;
 
@@ -1315,7 +1315,7 @@ static int neofb_setcolreg(u_int regno, 
 /*
  *    (Un)Blank the display.
  */
-int neofb_blank(int blank_mode, struct fb_info *info)
+static int neofb_blank(int blank_mode, struct fb_info *info)
 {
 	/*
 	 *  Blank the screen if blank_mode != 0, else unblank.
@@ -1691,7 +1691,27 @@ static int __devinit neo_map_mmio(struct
 
 	DBG("neo_map_mmio");
 
-	info->fix.mmio_start = pci_resource_start(dev, 1);
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2070:
+			info->fix.mmio_start = pci_resource_start(dev, 0)+
+				0x100000;
+			break;
+		case FB_ACCEL_NEOMAGIC_NM2090:
+		case FB_ACCEL_NEOMAGIC_NM2093:
+			info->fix.mmio_start = pci_resource_start(dev, 0)+
+				0x200000;
+			break;
+		case FB_ACCEL_NEOMAGIC_NM2160:
+		case FB_ACCEL_NEOMAGIC_NM2097:
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230:
+		case FB_ACCEL_NEOMAGIC_NM2360:
+		case FB_ACCEL_NEOMAGIC_NM2380:
+			info->fix.mmio_start = pci_resource_start(dev, 1);
+			break;
+		default:
+			info->fix.mmio_start = pci_resource_start(dev, 0);
+	}
 	info->fix.mmio_len = MMIO_SIZE;
 
 	if (!request_mem_region
@@ -2010,6 +2030,7 @@ static struct fb_info *__devinit neo_all
 
 	par->internal_display = internal;
 	par->external_display = external;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 
 	switch (info->fix.accel) {
 	case FB_ACCEL_NEOMAGIC_NM2070:
@@ -2029,15 +2050,27 @@ static struct fb_info *__devinit neo_all
 		break;
 	case FB_ACCEL_NEOMAGIC_NM2200:
 		sprintf(info->fix.id, "MagicGraph 256AV");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
 		break;
 	case FB_ACCEL_NEOMAGIC_NM2230:
 		sprintf(info->fix.id, "MagicGraph 256AV+");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
 		break;
 	case FB_ACCEL_NEOMAGIC_NM2360:
 		sprintf(info->fix.id, "MagicGraph 256ZX");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
 		break;
 	case FB_ACCEL_NEOMAGIC_NM2380:
 		sprintf(info->fix.id, "MagicGraph 256XL+");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
 		break;
 	}
 
@@ -2049,9 +2082,6 @@ static struct fb_info *__devinit neo_all
 	info->fix.accel = id->driver_data;
 
 	info->fbops = &neofb_ops;
-	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
-		FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA |
-		FBINFO_HWACCEL_COPYAREA;
 	info->pseudo_palette = (void *) (par + 1);
 	return info;
 }
@@ -2230,7 +2260,8 @@ static struct pci_driver neofb_driver = 
 
 /* ************************* init in-kernel code ************************** */
 
-int __init neofb_setup(char *options)
+#ifndef MODULE
+static int __init neofb_setup(char *options)
 {
 	char *this_opt;
 
@@ -2258,8 +2289,9 @@ int __init neofb_setup(char *options)
 	}
 	return 0;
 }
+#endif  /*  MODULE  */
 
-int __init neofb_init(void)
+static int __init neofb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the nVidia framebuffer driver
+#
+
+obj-$(CONFIG_FB_NVIDIA)          += nvidiafb.o
+
+nvidiafb-y                       := nvidia.o nv_hw.o nv_setup.o \
+			            nv_accel.o
+nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_PPC_OF)	 += nv_of.o
+
+nvidiafb-objs                    := $(nvidiafb-y)
\ No newline at end of file
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_accel.c
@@ -0,0 +1,419 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING 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 SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#include <linux/fb.h>
+#include "nv_type.h"
+#include "nv_proto.h"
+#include "nv_dma.h"
+#include "nv_local.h"
+
+/* There is a HW race condition with videoram command buffers.
+   You can't jump to the location of your put offset.  We write put
+   at the jump offset + SKIPS dwords with noop padding in between
+   to solve this problem */
+#define SKIPS  8
+
+static const int NVCopyROP[16] = {
+	0xCC,			/* copy   */
+	0x55			/* invert */
+};
+
+static const int NVCopyROP_PM[16] = {
+	0xCA,			/* copy  */
+	0x5A,			/* invert */
+};
+
+static inline void NVFlush(struct nvidia_par *par)
+{
+	int count = 1000000000;
+
+	while (--count && READ_GET(par) != par->dmaPut) ;
+
+	if (!count) {
+		printk("nvidiafb: DMA Flush lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static inline void NVSync(struct nvidia_par *par)
+{
+	int count = 1000000000;
+
+	while (--count && NV_RD32(par->PGRAPH, 0x0700)) ;
+
+	if (!count) {
+		printk("nvidiafb: DMA Sync lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static void NVDmaKickoff(struct nvidia_par *par)
+{
+	if (par->dmaCurrent != par->dmaPut) {
+		par->dmaPut = par->dmaCurrent;
+		WRITE_PUT(par, par->dmaPut);
+	}
+}
+
+static void NVDmaWait(struct nvidia_par *par, int size)
+{
+	int dmaGet;
+	int count = 1000000000, cnt;
+	size++;
+
+	while (par->dmaFree < size && --count && !par->lockup) {
+		dmaGet = READ_GET(par);
+
+		if (par->dmaPut >= dmaGet) {
+			par->dmaFree = par->dmaMax - par->dmaCurrent;
+			if (par->dmaFree < size) {
+				NVDmaNext(par, 0x20000000);
+				if (dmaGet <= SKIPS) {
+					if (par->dmaPut <= SKIPS)
+						WRITE_PUT(par, SKIPS + 1);
+					cnt = 1000000000;
+					do {
+						dmaGet = READ_GET(par);
+					} while (--cnt && dmaGet <= SKIPS);
+					if (!cnt) {
+						printk("DMA Get lockup\n");
+						par->lockup = 1;
+					}
+				}
+				WRITE_PUT(par, SKIPS);
+				par->dmaCurrent = par->dmaPut = SKIPS;
+				par->dmaFree = dmaGet - (SKIPS + 1);
+			}
+		} else
+			par->dmaFree = dmaGet - par->dmaCurrent - 1;
+	}
+
+	if (!count) {
+		printk("DMA Wait Lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1,
+			 u32 pat0, u32 pat1)
+{
+	NVDmaStart(par, PATTERN_COLOR_0, 4);
+	NVDmaNext(par, clr0);
+	NVDmaNext(par, clr1);
+	NVDmaNext(par, pat0);
+	NVDmaNext(par, pat1);
+}
+
+static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask)
+{
+	if (planemask != ~0) {
+		NVSetPattern(par, 0, planemask, ~0, ~0);
+		if (par->currentRop != (rop + 32)) {
+			NVDmaStart(par, ROP_SET, 1);
+			NVDmaNext(par, NVCopyROP_PM[rop]);
+			par->currentRop = rop + 32;
+		}
+	} else if (par->currentRop != rop) {
+		if (par->currentRop >= 16)
+			NVSetPattern(par, ~0, ~0, ~0, ~0);
+		NVDmaStart(par, ROP_SET, 1);
+		NVDmaNext(par, NVCopyROP[rop]);
+		par->currentRop = rop;
+	}
+}
+
+static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1,
+				   int x2, int y2)
+{
+	struct nvidia_par *par = info->par;
+	int h = y2 - y1 + 1;
+	int w = x2 - x1 + 1;
+
+	NVDmaStart(par, CLIP_POINT, 2);
+	NVDmaNext(par, (y1 << 16) | x1);
+	NVDmaNext(par, (h << 16) | w);
+}
+
+void NVResetGraphics(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	u32 surfaceFormat, patternFormat, rectFormat, lineFormat;
+	int pitch, i;
+
+	pitch = info->fix.line_length;
+
+	par->dmaBase = (u32 __iomem *) (&par->FbStart[par->FbUsableSize]);
+
+	for (i = 0; i < SKIPS; i++)
+		NV_WR32(&par->dmaBase[i], 0, 0x00000000);
+
+	NV_WR32(&par->dmaBase[0x0 + SKIPS], 0, 0x00040000);
+	NV_WR32(&par->dmaBase[0x1 + SKIPS], 0, 0x80000010);
+	NV_WR32(&par->dmaBase[0x2 + SKIPS], 0, 0x00042000);
+	NV_WR32(&par->dmaBase[0x3 + SKIPS], 0, 0x80000011);
+	NV_WR32(&par->dmaBase[0x4 + SKIPS], 0, 0x00044000);
+	NV_WR32(&par->dmaBase[0x5 + SKIPS], 0, 0x80000012);
+	NV_WR32(&par->dmaBase[0x6 + SKIPS], 0, 0x00046000);
+	NV_WR32(&par->dmaBase[0x7 + SKIPS], 0, 0x80000013);
+	NV_WR32(&par->dmaBase[0x8 + SKIPS], 0, 0x00048000);
+	NV_WR32(&par->dmaBase[0x9 + SKIPS], 0, 0x80000014);
+	NV_WR32(&par->dmaBase[0xA + SKIPS], 0, 0x0004A000);
+	NV_WR32(&par->dmaBase[0xB + SKIPS], 0, 0x80000015);
+	NV_WR32(&par->dmaBase[0xC + SKIPS], 0, 0x0004C000);
+	NV_WR32(&par->dmaBase[0xD + SKIPS], 0, 0x80000016);
+	NV_WR32(&par->dmaBase[0xE + SKIPS], 0, 0x0004E000);
+	NV_WR32(&par->dmaBase[0xF + SKIPS], 0, 0x80000017);
+
+	par->dmaPut = 0;
+	par->dmaCurrent = 16 + SKIPS;
+	par->dmaMax = 8191;
+	par->dmaFree = par->dmaMax - par->dmaCurrent;
+
+	switch (info->var.bits_per_pixel) {
+	case 32:
+	case 24:
+		surfaceFormat = SURFACE_FORMAT_DEPTH24;
+		patternFormat = PATTERN_FORMAT_DEPTH24;
+		rectFormat = RECT_FORMAT_DEPTH24;
+		lineFormat = LINE_FORMAT_DEPTH24;
+		break;
+	case 16:
+		surfaceFormat = SURFACE_FORMAT_DEPTH16;
+		patternFormat = PATTERN_FORMAT_DEPTH16;
+		rectFormat = RECT_FORMAT_DEPTH16;
+		lineFormat = LINE_FORMAT_DEPTH16;
+		break;
+	default:
+		surfaceFormat = SURFACE_FORMAT_DEPTH8;
+		patternFormat = PATTERN_FORMAT_DEPTH8;
+		rectFormat = RECT_FORMAT_DEPTH8;
+		lineFormat = LINE_FORMAT_DEPTH8;
+		break;
+	}
+
+	NVDmaStart(par, SURFACE_FORMAT, 4);
+	NVDmaNext(par, surfaceFormat);
+	NVDmaNext(par, pitch | (pitch << 16));
+	NVDmaNext(par, 0);
+	NVDmaNext(par, 0);
+
+	NVDmaStart(par, PATTERN_FORMAT, 1);
+	NVDmaNext(par, patternFormat);
+
+	NVDmaStart(par, RECT_FORMAT, 1);
+	NVDmaNext(par, rectFormat);
+
+	NVDmaStart(par, LINE_FORMAT, 1);
+	NVDmaNext(par, lineFormat);
+
+	par->currentRop = ~0;	/* set to something invalid */
+	NVSetRopSolid(par, ROP_COPY, ~0);
+
+	NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual,
+			       info->var.yres_virtual);
+
+	NVDmaKickoff(par);
+}
+
+u8 byte_rev[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+int nvidiafb_sync(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+
+	if (!par->lockup)
+		NVFlush(par);
+
+	if (!par->lockup)
+		NVSync(par);
+
+	return 0;
+}
+
+void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct nvidia_par *par = info->par;
+
+	if (par->lockup)
+		return cfb_copyarea(info, region);
+
+	NVDmaStart(par, BLIT_POINT_SRC, 3);
+	NVDmaNext(par, (region->sy << 16) | region->sx);
+	NVDmaNext(par, (region->dy << 16) | region->dx);
+	NVDmaNext(par, (region->height << 16) | region->width);
+
+	NVDmaKickoff(par);
+}
+
+void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct nvidia_par *par = info->par;
+	u32 color;
+
+	if (par->lockup)
+		return cfb_fillrect(info, rect);
+
+	if (info->var.bits_per_pixel == 8)
+		color = rect->color;
+	else
+		color = ((u32 *) info->pseudo_palette)[rect->color];
+
+	if (rect->rop != ROP_COPY)
+		NVSetRopSolid(par, rect->rop, ~0);
+
+	NVDmaStart(par, RECT_SOLID_COLOR, 1);
+	NVDmaNext(par, color);
+
+	NVDmaStart(par, RECT_SOLID_RECTS(0), 2);
+	NVDmaNext(par, (rect->dx << 16) | rect->dy);
+	NVDmaNext(par, (rect->width << 16) | rect->height);
+
+	NVDmaKickoff(par);
+
+	if (rect->rop != ROP_COPY)
+		NVSetRopSolid(par, ROP_COPY, ~0);
+}
+
+static void nvidiafb_mono_color_expand(struct fb_info *info,
+				       const struct fb_image *image)
+{
+	struct nvidia_par *par = info->par;
+	u32 fg, bg, mask = ~(~0 >> (32 - info->var.bits_per_pixel));
+	u32 dsize, width, *data = (u32 *) image->data, tmp;
+	int j, k = 0;
+
+	width = (image->width + 31) & ~31;
+	dsize = (width * image->height) >> 5;
+
+	if (info->var.bits_per_pixel == 8) {
+		fg = image->fg_color | mask;
+		bg = image->bg_color | mask;
+	} else {
+		fg = ((u32 *) info->pseudo_palette)[image->fg_color] | mask;
+		bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask;
+	}
+
+	NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
+	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
+	NVDmaNext(par, ((image->dy + image->height) << 16) |
+		  ((image->dx + image->width) & 0xffff));
+	NVDmaNext(par, bg);
+	NVDmaNext(par, fg);
+	NVDmaNext(par, (image->height << 16) | width);
+	NVDmaNext(par, (image->height << 16) | width);
+	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
+
+	while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) {
+		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0),
+			   RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS);
+
+		for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) {
+			tmp = data[k++];
+			reverse_order(&tmp);
+			NVDmaNext(par, tmp);
+		}
+
+		dsize -= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS;
+	}
+
+	if (dsize) {
+		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
+
+		for (j = dsize; j--;) {
+			tmp = data[k++];
+			reverse_order(&tmp);
+			NVDmaNext(par, tmp);
+		}
+	}
+
+	NVDmaKickoff(par);
+}
+
+void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct nvidia_par *par = info->par;
+
+	if (image->depth == 1 && !par->lockup)
+		nvidiafb_mono_color_expand(info, image);
+	else
+		cfb_imageblit(info, image);
+}
diff --git a/drivers/video/nvidia/nv_dma.h b/drivers/video/nvidia/nv_dma.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_dma.h
@@ -0,0 +1,188 @@
+
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING 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 SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#define SURFACE_FORMAT                                              0x00000300
+#define SURFACE_FORMAT_DEPTH8                                       0x00000001
+#define SURFACE_FORMAT_DEPTH15                                      0x00000002
+#define SURFACE_FORMAT_DEPTH16                                      0x00000004
+#define SURFACE_FORMAT_DEPTH24                                      0x00000006
+#define SURFACE_PITCH                                               0x00000304
+#define SURFACE_PITCH_SRC                                           15:0
+#define SURFACE_PITCH_DST                                           31:16
+#define SURFACE_OFFSET_SRC                                          0x00000308
+#define SURFACE_OFFSET_DST                                          0x0000030C
+
+#define ROP_SET                                                     0x00002300
+
+#define PATTERN_FORMAT                                              0x00004300
+#define PATTERN_FORMAT_DEPTH8                                       0x00000003
+#define PATTERN_FORMAT_DEPTH16                                      0x00000001
+#define PATTERN_FORMAT_DEPTH24                                      0x00000003
+#define PATTERN_COLOR_0                                             0x00004310
+#define PATTERN_COLOR_1                                             0x00004314
+#define PATTERN_PATTERN_0                                           0x00004318
+#define PATTERN_PATTERN_1                                           0x0000431C
+
+#define CLIP_POINT                                                  0x00006300
+#define CLIP_POINT_X                                                15:0
+#define CLIP_POINT_Y                                                31:16
+#define CLIP_SIZE                                                   0x00006304
+#define CLIP_SIZE_WIDTH                                             15:0
+#define CLIP_SIZE_HEIGHT                                            31:16
+
+#define LINE_FORMAT                                                 0x00008300
+#define LINE_FORMAT_DEPTH8                                          0x00000003
+#define LINE_FORMAT_DEPTH16                                         0x00000001
+#define LINE_FORMAT_DEPTH24                                         0x00000003
+#define LINE_COLOR                                                  0x00008304
+#define LINE_MAX_LINES                                              16
+#define LINE_LINES(i)                                               0x00008400\
+                                                                    +(i)*8
+#define LINE_LINES_POINT0_X                                         15:0
+#define LINE_LINES_POINT0_Y                                         31:16
+#define LINE_LINES_POINT1_X                                         47:32
+#define LINE_LINES_POINT1_Y                                         63:48
+
+#define BLIT_POINT_SRC                                              0x0000A300
+#define BLIT_POINT_SRC_X                                            15:0
+#define BLIT_POINT_SRC_Y                                            31:16
+#define BLIT_POINT_DST                                              0x0000A304
+#define BLIT_POINT_DST_X                                            15:0
+#define BLIT_POINT_DST_Y                                            31:16
+#define BLIT_SIZE                                                   0x0000A308
+#define BLIT_SIZE_WIDTH                                             15:0
+#define BLIT_SIZE_HEIGHT                                            31:16
+
+#define RECT_FORMAT                                                 0x0000C300
+#define RECT_FORMAT_DEPTH8                                          0x00000003
+#define RECT_FORMAT_DEPTH16                                         0x00000001
+#define RECT_FORMAT_DEPTH24                                         0x00000003
+#define RECT_SOLID_COLOR                                            0x0000C3FC
+#define RECT_SOLID_RECTS_MAX_RECTS                                  32
+#define RECT_SOLID_RECTS(i)                                         0x0000C400\
+                                                                    +(i)*8
+#define RECT_SOLID_RECTS_Y                                          15:0
+#define RECT_SOLID_RECTS_X                                          31:16
+#define RECT_SOLID_RECTS_HEIGHT                                     47:32
+#define RECT_SOLID_RECTS_WIDTH                                      63:48
+
+#define RECT_EXPAND_ONE_COLOR_CLIP                                  0x0000C7EC
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X                         15:0
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y                         31:16
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X                         47:32
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y                         63:48
+#define RECT_EXPAND_ONE_COLOR_COLOR                                 0x0000C7F4
+#define RECT_EXPAND_ONE_COLOR_SIZE                                  0x0000C7F8
+#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH                            15:0
+#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT                           31:16
+#define RECT_EXPAND_ONE_COLOR_POINT                                 0x0000C7FC
+#define RECT_EXPAND_ONE_COLOR_POINT_X                               15:0
+#define RECT_EXPAND_ONE_COLOR_POINT_Y                               31:16
+#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS                       128
+#define RECT_EXPAND_ONE_COLOR_DATA(i)                               0x0000C800\
+                                                                    +(i)*4
+
+#define RECT_EXPAND_TWO_COLOR_CLIP                                  0x0000CBE4
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X                         15:0
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y                         31:16
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X                         47:32
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y                         63:48
+#define RECT_EXPAND_TWO_COLOR_COLOR_0                               0x0000CBEC
+#define RECT_EXPAND_TWO_COLOR_COLOR_1                               0x0000CBF0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN                               0x0000CBF4
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH                         15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT                        31:16
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT                              0x0000CBF8
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH                        15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT                       31:16
+#define RECT_EXPAND_TWO_COLOR_POINT                                 0x0000CBFC
+#define RECT_EXPAND_TWO_COLOR_POINT_X                               15:0
+#define RECT_EXPAND_TWO_COLOR_POINT_Y                               31:16
+#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS                       128
+#define RECT_EXPAND_TWO_COLOR_DATA(i)                               0x0000CC00\
+                                                                    +(i)*4
+
+#define STRETCH_BLIT_FORMAT                                         0x0000E300
+#define STRETCH_BLIT_FORMAT_DEPTH8                                  0x00000004
+#define STRETCH_BLIT_FORMAT_DEPTH16                                 0x00000007
+#define STRETCH_BLIT_FORMAT_DEPTH24                                 0x00000004
+#define STRETCH_BLIT_FORMAT_X8R8G8B8                                0x00000004
+#define STRETCH_BLIT_FORMAT_YUYV                                    0x00000005
+#define STRETCH_BLIT_FORMAT_UYVY                                    0x00000006
+#define STRETCH_BLIT_CLIP_POINT                                     0x0000E308
+#define STRETCH_BLIT_CLIP_POINT_X                                   15:0
+#define STRETCH_BLIT_CLIP_POINT_Y                                   31:16
+#define STRETCH_BLIT_CLIP_POINT                                     0x0000E308
+#define STRETCH_BLIT_CLIP_SIZE                                      0x0000E30C
+#define STRETCH_BLIT_CLIP_SIZE_WIDTH                                15:0
+#define STRETCH_BLIT_CLIP_SIZE_HEIGHT                               31:16
+#define STRETCH_BLIT_DST_POINT                                      0x0000E310
+#define STRETCH_BLIT_DST_POINT_X                                    15:0
+#define STRETCH_BLIT_DST_POINT_Y                                    31:16
+#define STRETCH_BLIT_DST_SIZE                                       0x0000E314
+#define STRETCH_BLIT_DST_SIZE_WIDTH                                 15:0
+#define STRETCH_BLIT_DST_SIZE_HEIGHT                                31:16
+#define STRETCH_BLIT_DU_DX                                          0x0000E318
+#define STRETCH_BLIT_DV_DY                                          0x0000E31C
+#define STRETCH_BLIT_SRC_SIZE                                       0x0000E400
+#define STRETCH_BLIT_SRC_SIZE_WIDTH                                 15:0
+#define STRETCH_BLIT_SRC_SIZE_HEIGHT                                31:16
+#define STRETCH_BLIT_SRC_FORMAT                                     0x0000E404
+#define STRETCH_BLIT_SRC_FORMAT_PITCH                               15:0
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN                              23:16
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER                       0x00000001
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER                       0x00000002
+#define STRETCH_BLIT_SRC_FORMAT_FILTER                              31:24
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE                 0x00000000
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR                     0x00000001
+#define STRETCH_BLIT_SRC_OFFSET                                     0x0000E408
+#define STRETCH_BLIT_SRC_POINT                                      0x0000E40C
+#define STRETCH_BLIT_SRC_POINT_U                                    15:0
+#define STRETCH_BLIT_SRC_POINT_V                                    31:16
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_hw.c
@@ -0,0 +1,1593 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING 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 SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.4 2003/11/03 05:11:25 tsi Exp $ */
+
+#include <linux/pci.h>
+#include "nv_type.h"
+#include "nv_local.h"
+
+void NVLockUnlock(struct nvidia_par *par, int Lock)
+{
+	u8 cr11;
+
+	VGA_WR08(par->PCIO, 0x3D4, 0x1F);
+	VGA_WR08(par->PCIO, 0x3D5, Lock ? 0x99 : 0x57);
+
+	VGA_WR08(par->PCIO, 0x3D4, 0x11);
+	cr11 = VGA_RD08(par->PCIO, 0x3D5);
+	if (Lock)
+		cr11 |= 0x80;
+	else
+		cr11 &= ~0x80;
+	VGA_WR08(par->PCIO, 0x3D5, cr11);
+}
+
+int NVShowHideCursor(struct nvidia_par *par, int ShowHide)
+{
+	int cur = par->CurrentState->cursor1;
+
+	par->CurrentState->cursor1 = (par->CurrentState->cursor1 & 0xFE) |
+	    (ShowHide & 0x01);
+	VGA_WR08(par->PCIO, 0x3D4, 0x31);
+	VGA_WR08(par->PCIO, 0x3D5, par->CurrentState->cursor1);
+
+	if (par->Architecture == NV_ARCH_40)
+		NV_WR32(par->PRAMDAC, 0x0300, NV_RD32(par->PRAMDAC, 0x0300));
+
+	return (cur & 0x01);
+}
+
+/****************************************************************************\
+*                                                                            *
+* The video arbitration routines calculate some "magic" numbers.  Fixes      *
+* the snow seen when accessing the framebuffer without it.                   *
+* It just works (I hope).                                                    *
+*                                                                            *
+\****************************************************************************/
+
+typedef struct {
+	int graphics_lwm;
+	int video_lwm;
+	int graphics_burst_size;
+	int video_burst_size;
+	int valid;
+} nv4_fifo_info;
+
+typedef struct {
+	int pclk_khz;
+	int mclk_khz;
+	int nvclk_khz;
+	char mem_page_miss;
+	char mem_latency;
+	int memory_width;
+	char enable_video;
+	char gr_during_vid;
+	char pix_bpp;
+	char mem_aligned;
+	char enable_mp;
+} nv4_sim_state;
+
+typedef struct {
+	int graphics_lwm;
+	int video_lwm;
+	int graphics_burst_size;
+	int video_burst_size;
+	int valid;
+} nv10_fifo_info;
+
+typedef struct {
+	int pclk_khz;
+	int mclk_khz;
+	int nvclk_khz;
+	char mem_page_miss;
+	char mem_latency;
+	int memory_type;
+	int memory_width;
+	char enable_video;
+	char gr_during_vid;
+	char pix_bpp;
+	char mem_aligned;
+	char enable_mp;
+} nv10_sim_state;
+
+static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
+			unsigned int *NVClk)
+{
+	unsigned int pll, N, M, MB, NB, P;
+
+	if (par->Architecture >= NV_ARCH_40) {
+		pll = NV_RD32(par->PMC, 0x4020);
+		P = (pll >> 16) & 0x03;
+		pll = NV_RD32(par->PMC, 0x4024);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		MB = (pll >> 16) & 0xFF;
+		NB = (pll >> 24) & 0xFF;
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PMC, 0x4000);
+		P = (pll >> 16) & 0x03;
+		pll = NV_RD32(par->PMC, 0x4004);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		MB = (pll >> 16) & 0xFF;
+		NB = (pll >> 24) & 0xFF;
+
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else if (par->twoStagePLL) {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		pll = NV_RD32(par->PRAMDAC0, 0x0574);
+		if (pll & 0x80000000) {
+			MB = pll & 0xFF;
+			NB = (pll >> 8) & 0xFF;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		pll = NV_RD32(par->PRAMDAC0, 0x0570);
+		if (pll & 0x80000000) {
+			MB = pll & 0xFF;
+			NB = (pll >> 8) & 0xFF;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else
+	    if (((par->Chipset & 0x0ff0) == 0x0300) ||
+		((par->Chipset & 0x0ff0) == 0x0330)) {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0x0F;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x07;
+		if (pll & 0x00000080) {
+			MB = (pll >> 4) & 0x07;
+			NB = (pll >> 19) & 0x1f;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0x0F;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x07;
+		if (pll & 0x00000080) {
+			MB = (pll >> 4) & 0x07;
+			NB = (pll >> 19) & 0x1f;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		*MClk = (N * par->CrystalFreqKHz / M) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		*NVClk = (N * par->CrystalFreqKHz / M) >> P;
+	}
+}
+
+static void nv4CalcArbitration(nv4_fifo_info * fifo, nv4_sim_state * arb)
+{
+	int data, pagemiss, cas, width, video_enable, bpp;
+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+	int found, mclk_extra, mclk_loop, cbs, m1, p1;
+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+	int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
+	int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt, clwm;
+
+	fifo->valid = 1;
+	pclk_freq = arb->pclk_khz;
+	mclk_freq = arb->mclk_khz;
+	nvclk_freq = arb->nvclk_khz;
+	pagemiss = arb->mem_page_miss;
+	cas = arb->mem_latency;
+	width = arb->memory_width >> 6;
+	video_enable = arb->enable_video;
+	bpp = arb->pix_bpp;
+	mp_enable = arb->enable_mp;
+	clwm = 0;
+	vlwm = 0;
+	cbs = 128;
+	pclks = 2;
+	nvclks = 2;
+	nvclks += 2;
+	nvclks += 1;
+	mclks = 5;
+	mclks += 3;
+	mclks += 1;
+	mclks += cas;
+	mclks += 1;
+	mclks += 1;
+	mclks += 1;
+	mclks += 1;
+	mclk_extra = 3;
+	nvclks += 2;
+	nvclks += 1;
+	nvclks += 1;
+	nvclks += 1;
+	if (mp_enable)
+		mclks += 4;
+	nvclks += 0;
+	pclks += 0;
+	found = 0;
+	vbs = 0;
+	while (found != 1) {
+		fifo->valid = 1;
+		found = 1;
+		mclk_loop = mclks + mclk_extra;
+		us_m = mclk_loop * 1000 * 1000 / mclk_freq;
+		us_n = nvclks * 1000 * 1000 / nvclk_freq;
+		us_p = nvclks * 1000 * 1000 / pclk_freq;
+		if (video_enable) {
+			video_drain_rate = pclk_freq * 2;
+			crtc_drain_rate = pclk_freq * bpp / 8;
+			vpagemiss = 2;
+			vpagemiss += 1;
+			crtpagemiss = 2;
+			vpm_us =
+			    (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq;
+			if (nvclk_freq * 2 > mclk_freq * width)
+				video_fill_us =
+				    cbs * 1000 * 1000 / 16 / nvclk_freq;
+			else
+				video_fill_us =
+				    cbs * 1000 * 1000 / (8 * width) /
+				    mclk_freq;
+			us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
+			vlwm = us_video * video_drain_rate / (1000 * 1000);
+			vlwm++;
+			vbs = 128;
+			if (vlwm > 128)
+				vbs = 64;
+			if (vlwm > (256 - 64))
+				vbs = 32;
+			if (nvclk_freq * 2 > mclk_freq * width)
+				video_fill_us =
+				    vbs * 1000 * 1000 / 16 / nvclk_freq;
+			else
+				video_fill_us =
+				    vbs * 1000 * 1000 / (8 * width) /
+				    mclk_freq;
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt =
+			    us_video + video_fill_us + cpm_us + us_m + us_n +
+			    us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			clwm++;
+		} else {
+			crtc_drain_rate = pclk_freq * bpp / 8;
+			crtpagemiss = 2;
+			crtpagemiss += 1;
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt = cpm_us + us_m + us_n + us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			clwm++;
+		}
+		m1 = clwm + cbs - 512;
+		p1 = m1 * pclk_freq / mclk_freq;
+		p1 = p1 * bpp / 8;
+		if ((p1 < m1) && (m1 > 0)) {
+			fifo->valid = 0;
+			found = 0;
+			if (mclk_extra == 0)
+				found = 1;
+			mclk_extra--;
+		} else if (video_enable) {
+			if ((clwm > 511) || (vlwm > 255)) {
+				fifo->valid = 0;
+				found = 0;
+				if (mclk_extra == 0)
+					found = 1;
+				mclk_extra--;
+			}
+		} else {
+			if (clwm > 519) {
+				fifo->valid = 0;
+				found = 0;
+				if (mclk_extra == 0)
+					found = 1;
+				mclk_extra--;
+			}
+		}
+		if (clwm < 384)
+			clwm = 384;
+		if (vlwm < 128)
+			vlwm = 128;
+		data = (int)(clwm);
+		fifo->graphics_lwm = data;
+		fifo->graphics_burst_size = 128;
+		data = (int)((vlwm + 15));
+		fifo->video_lwm = data;
+		fifo->video_burst_size = vbs;
+	}
+}
+
+static void nv4UpdateArbitrationSettings(unsigned VClk,
+					 unsigned pixelDepth,
+					 unsigned *burst,
+					 unsigned *lwm, struct nvidia_par *par)
+{
+	nv4_fifo_info fifo_data;
+	nv4_sim_state sim_data;
+	unsigned int MClk, NVClk, cfg1;
+
+	nvGetClocks(par, &MClk, &NVClk);
+
+	cfg1 = NV_RD32(par->PFB, 0x00000204);
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 0;
+	sim_data.enable_mp = 0;
+	sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ?
+	    128 : 64;
+	sim_data.mem_latency = (char)cfg1 & 0x0F;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss =
+	    (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01));
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv4CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+static void nv10CalcArbitration(nv10_fifo_info * fifo, nv10_sim_state * arb)
+{
+	int data, pagemiss, width, video_enable, bpp;
+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
+	int nvclk_fill;
+	int found, mclk_extra, mclk_loop, cbs, m1;
+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+	int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
+	int vus_m;
+	int vpm_us, us_video, cpm_us, us_crt, clwm;
+	int clwm_rnd_down;
+	int m2us, us_pipe_min, p1clk, p2;
+	int min_mclk_extra;
+	int us_min_mclk_extra;
+
+	fifo->valid = 1;
+	pclk_freq = arb->pclk_khz;	/* freq in KHz */
+	mclk_freq = arb->mclk_khz;
+	nvclk_freq = arb->nvclk_khz;
+	pagemiss = arb->mem_page_miss;
+	width = arb->memory_width / 64;
+	video_enable = arb->enable_video;
+	bpp = arb->pix_bpp;
+	mp_enable = arb->enable_mp;
+	clwm = 0;
+
+	cbs = 512;
+
+	pclks = 4;	/* lwm detect. */
+
+	nvclks = 3;	/* lwm -> sync. */
+	nvclks += 2;	/* fbi bus cycles (1 req + 1 busy) */
+	/* 2 edge sync.  may be very close to edge so just put one. */
+	mclks = 1;
+	mclks += 1;	/* arb_hp_req */
+	mclks += 5;	/* ap_hp_req   tiling pipeline */
+
+	mclks += 2;	/* tc_req     latency fifo */
+	mclks += 2;	/* fb_cas_n_  memory request to fbio block */
+	mclks += 7;	/* sm_d_rdv   data returned from fbio block */
+
+	/* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
+	if (arb->memory_type == 0)
+		if (arb->memory_width == 64)	/* 64 bit bus */
+			mclks += 4;
+		else
+			mclks += 2;
+	else if (arb->memory_width == 64)	/* 64 bit bus */
+		mclks += 2;
+	else
+		mclks += 1;
+
+	if ((!video_enable) && (arb->memory_width == 128)) {
+		mclk_extra = (bpp == 32) ? 31 : 42;	/* Margin of error */
+		min_mclk_extra = 17;
+	} else {
+		mclk_extra = (bpp == 32) ? 8 : 4;	/* Margin of error */
+		/* mclk_extra = 4; *//* Margin of error */
+		min_mclk_extra = 18;
+	}
+
+	/* 2 edge sync.  may be very close to edge so just put one. */
+	nvclks += 1;
+	nvclks += 1;		/* fbi_d_rdv_n */
+	nvclks += 1;		/* Fbi_d_rdata */
+	nvclks += 1;		/* crtfifo load */
+
+	if (mp_enable)
+		mclks += 4;	/* Mp can get in with a burst of 8. */
+	/* Extra clocks determined by heuristics */
+
+	nvclks += 0;
+	pclks += 0;
+	found = 0;
+	while (found != 1) {
+		fifo->valid = 1;
+		found = 1;
+		mclk_loop = mclks + mclk_extra;
+		/* Mclk latency in us */
+		us_m = mclk_loop * 1000 * 1000 / mclk_freq;
+		/* Minimum Mclk latency in us */
+		us_m_min = mclks * 1000 * 1000 / mclk_freq;
+		us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq;
+		/* nvclk latency in us */
+		us_n = nvclks * 1000 * 1000 / nvclk_freq;
+		/* nvclk latency in us */
+		us_p = pclks * 1000 * 1000 / pclk_freq;
+		us_pipe_min = us_m_min + us_n + us_p;
+
+		/* Mclk latency in us */
+		vus_m = mclk_loop * 1000 * 1000 / mclk_freq;
+
+		if (video_enable) {
+			crtc_drain_rate = pclk_freq * bpp / 8;	/* MB/s */
+
+			vpagemiss = 1;	/* self generating page miss */
+			vpagemiss += 1;	/* One higher priority before */
+
+			crtpagemiss = 2;	/* self generating page miss */
+			if (mp_enable)
+				crtpagemiss += 1;	/* if MA0 conflict */
+
+			vpm_us =
+			    (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq;
+
+			/* Video has separate read return path */
+			us_video = vpm_us + vus_m;
+
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			/* Wait for video */
+			us_crt = us_video
+			    + cpm_us	/* CRT Page miss */
+			    + us_m + us_n + us_p	/* other latency */
+			    ;
+
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			/* fixed point <= float_point - 1.  Fixes that */
+			clwm++;
+		} else {
+		    /* bpp * pclk/8 */
+			crtc_drain_rate = pclk_freq * bpp / 8;
+
+			crtpagemiss = 1;	/* self generating page miss */
+			crtpagemiss += 1;	/* MA0 page miss */
+			if (mp_enable)
+				crtpagemiss += 1;	/* if MA0 conflict */
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt = cpm_us + us_m + us_n + us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			/* fixed point <= float_point - 1.  Fixes that */
+			clwm++;
+
+			/* Finally, a heuristic check when width == 64 bits */
+			if (width == 1) {
+				nvclk_fill = nvclk_freq * 8;
+				if (crtc_drain_rate * 100 >= nvclk_fill * 102)
+					/*Large number to fail */
+					clwm = 0xfff;
+
+				else if (crtc_drain_rate * 100 >=
+					 nvclk_fill * 98) {
+					clwm = 1024;
+					cbs = 512;
+				}
+			}
+		}
+
+		/*
+		   Overfill check:
+		 */
+
+		clwm_rnd_down = ((int)clwm / 8) * 8;
+		if (clwm_rnd_down < clwm)
+			clwm += 8;
+
+		m1 = clwm + cbs - 1024;	/* Amount of overfill */
+		m2us = us_pipe_min + us_min_mclk_extra;
+
+		/* pclk cycles to drain */
+		p1clk = m2us * pclk_freq / (1000 * 1000);
+		p2 = p1clk * bpp / 8;	/* bytes drained. */
+
+		if ((p2 < m1) && (m1 > 0)) {
+			fifo->valid = 0;
+			found = 0;
+			if (min_mclk_extra == 0) {
+				if (cbs <= 32) {
+					/* Can't adjust anymore! */
+					found = 1;
+				} else {
+					/* reduce the burst size */
+					cbs = cbs / 2;
+				}
+			} else {
+				min_mclk_extra--;
+			}
+		} else {
+			if (clwm > 1023) {	/* Have some margin */
+				fifo->valid = 0;
+				found = 0;
+				if (min_mclk_extra == 0)
+					/* Can't adjust anymore! */
+					found = 1;
+				else
+					min_mclk_extra--;
+			}
+		}
+
+		if (clwm < (1024 - cbs + 8))
+			clwm = 1024 - cbs + 8;
+		data = (int)(clwm);
+		/*  printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n",
+		    clwm, data ); */
+		fifo->graphics_lwm = data;
+		fifo->graphics_burst_size = cbs;
+
+		fifo->video_lwm = 1024;
+		fifo->video_burst_size = 512;
+	}
+}
+
+static void nv10UpdateArbitrationSettings(unsigned VClk,
+					  unsigned pixelDepth,
+					  unsigned *burst,
+					  unsigned *lwm,
+					  struct nvidia_par *par)
+{
+	nv10_fifo_info fifo_data;
+	nv10_sim_state sim_data;
+	unsigned int MClk, NVClk, cfg1;
+
+	nvGetClocks(par, &MClk, &NVClk);
+
+	cfg1 = NV_RD32(par->PFB, 0x0204);
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 1;
+	sim_data.enable_mp = 0;
+	sim_data.memory_type = (NV_RD32(par->PFB, 0x0200) & 0x01) ? 1 : 0;
+	sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ?
+	    128 : 64;
+	sim_data.mem_latency = (char)cfg1 & 0x0F;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss =
+	    (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01));
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv10CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+static void nv30UpdateArbitrationSettings (
+    struct nvidia_par *par,
+    unsigned int      *burst,
+    unsigned int      *lwm
+)
+{
+    unsigned int MClk, NVClk;
+    unsigned int fifo_size, burst_size, graphics_lwm;
+
+    fifo_size = 2048;
+    burst_size = 512;
+    graphics_lwm = fifo_size - burst_size;
+
+    nvGetClocks(par, &MClk, &NVClk);
+
+    *burst = 0;
+    burst_size >>= 5;
+    while(burst_size >>= 1) (*burst)++;
+    *lwm = graphics_lwm >> 3;
+}
+
+static void nForceUpdateArbitrationSettings(unsigned VClk,
+					    unsigned pixelDepth,
+					    unsigned *burst,
+					    unsigned *lwm,
+					    struct nvidia_par *par)
+{
+	nv10_fifo_info fifo_data;
+	nv10_sim_state sim_data;
+	unsigned int M, N, P, pll, MClk, NVClk, memctrl;
+	struct pci_dev *dev;
+
+	if ((par->Chipset & 0x0FF0) == 0x01A0) {
+		unsigned int uMClkPostDiv;
+		dev = pci_find_slot(0, 3);
+		pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
+		uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
+
+		if (!uMClkPostDiv)
+			uMClkPostDiv = 4;
+		MClk = 400000 / uMClkPostDiv;
+	} else {
+		dev = pci_find_slot(0, 5);
+		pci_read_config_dword(dev, 0x4c, &MClk);
+		MClk /= 1000;
+	}
+
+	pll = NV_RD32(par->PRAMDAC0, 0x0500);
+	M = (pll >> 0) & 0xFF;
+	N = (pll >> 8) & 0xFF;
+	P = (pll >> 16) & 0x0F;
+	NVClk = (N * par->CrystalFreqKHz / M) >> P;
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 0;
+	sim_data.enable_mp = 0;
+	pci_find_slot(0, 1);
+	pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+	sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
+	sim_data.memory_width = 64;
+
+	dev = pci_find_slot(0, 3);
+	pci_read_config_dword(dev, 0, &memctrl);
+	memctrl >>= 16;
+
+	if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
+		int dimm[3];
+
+		pci_find_slot(0, 2);
+		pci_read_config_dword(dev, 0x40, &dimm[0]);
+		dimm[0] = (dimm[0] >> 8) & 0x4f;
+		pci_read_config_dword(dev, 0x44, &dimm[1]);
+		dimm[1] = (dimm[1] >> 8) & 0x4f;
+		pci_read_config_dword(dev, 0x48, &dimm[2]);
+		dimm[2] = (dimm[2] >> 8) & 0x4f;
+
+		if ((dimm[0] + dimm[1]) != dimm[2]) {
+			printk("nvidiafb: your nForce DIMMs are not arranged "
+			       "in optimal banks!\n");
+		}
+	}
+
+	sim_data.mem_latency = 3;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss = 10;
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv10CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+/****************************************************************************\
+*                                                                            *
+*                          RIVA Mode State Routines                          *
+*                                                                            *
+\****************************************************************************/
+
+/*
+ * Calculate the Video Clock parameters for the PLL.
+ */
+static void CalcVClock(int clockIn,
+		       int *clockOut, u32 * pllOut, struct nvidia_par *par)
+{
+	unsigned lowM, highM;
+	unsigned DeltaNew, DeltaOld;
+	unsigned VClk, Freq;
+	unsigned M, N, P;
+
+	DeltaOld = 0xFFFFFFFF;
+
+	VClk = (unsigned)clockIn;
+
+	if (par->CrystalFreqKHz == 13500) {
+		lowM = 7;
+		highM = 13;
+	} else {
+		lowM = 8;
+		highM = 14;
+	}
+
+	for (P = 0; P <= 4; P++) {
+		Freq = VClk << P;
+		if ((Freq >= 128000) && (Freq <= 350000)) {
+			for (M = lowM; M <= highM; M++) {
+				N = ((VClk << P) * M) / par->CrystalFreqKHz;
+				if (N <= 255) {
+					Freq =
+					    ((par->CrystalFreqKHz * N) /
+					     M) >> P;
+					if (Freq > VClk)
+						DeltaNew = Freq - VClk;
+					else
+						DeltaNew = VClk - Freq;
+					if (DeltaNew < DeltaOld) {
+						*pllOut =
+						    (P << 16) | (N << 8) | M;
+						*clockOut = Freq;
+						DeltaOld = DeltaNew;
+					}
+				}
+			}
+		}
+	}
+}
+
+static void CalcVClock2Stage(int clockIn,
+			     int *clockOut,
+			     u32 * pllOut,
+			     u32 * pllBOut, struct nvidia_par *par)
+{
+	unsigned DeltaNew, DeltaOld;
+	unsigned VClk, Freq;
+	unsigned M, N, P;
+
+	DeltaOld = 0xFFFFFFFF;
+
+	*pllBOut = 0x80000401;	/* fixed at x4 for now */
+
+	VClk = (unsigned)clockIn;
+
+	for (P = 0; P <= 6; P++) {
+		Freq = VClk << P;
+		if ((Freq >= 400000) && (Freq <= 1000000)) {
+			for (M = 1; M <= 13; M++) {
+				N = ((VClk << P) * M) /
+				    (par->CrystalFreqKHz << 2);
+				if ((N >= 5) && (N <= 255)) {
+					Freq =
+					    (((par->CrystalFreqKHz << 2) * N) /
+					     M) >> P;
+					if (Freq > VClk)
+						DeltaNew = Freq - VClk;
+					else
+						DeltaNew = VClk - Freq;
+					if (DeltaNew < DeltaOld) {
+						*pllOut =
+						    (P << 16) | (N << 8) | M;
+						*clockOut = Freq;
+						DeltaOld = DeltaNew;
+					}
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Calculate extended mode parameters (SVGA) and save in a
+ * mode state structure.
+ */
+void NVCalcStateExt(struct nvidia_par *par,
+		    RIVA_HW_STATE * state,
+		    int bpp,
+		    int width,
+		    int hDisplaySize, int height, int dotClock, int flags)
+{
+	int pixelDepth, VClk;
+	/*
+	 * Save mode parameters.
+	 */
+	state->bpp = bpp;	/* this is not bitsPerPixel, it's 8,15,16,32 */
+	state->width = width;
+	state->height = height;
+	/*
+	 * Extended RIVA registers.
+	 */
+	pixelDepth = (bpp + 1) / 8;
+	if (par->twoStagePLL)
+		CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB,
+				 par);
+	else
+		CalcVClock(dotClock, &VClk, &state->pll, par);
+
+	switch (par->Architecture) {
+	case NV_ARCH_04:
+		nv4UpdateArbitrationSettings(VClk,
+					     pixelDepth * 8,
+					     &(state->arbitration0),
+					     &(state->arbitration1), par);
+		state->cursor0 = 0x00;
+		state->cursor1 = 0xbC;
+		if (flags & FB_VMODE_DOUBLE)
+			state->cursor1 |= 2;
+		state->cursor2 = 0x00000000;
+		state->pllsel = 0x10000700;
+		state->config = 0x00001114;
+		state->general = bpp == 16 ? 0x00101100 : 0x00100100;
+		state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+		break;
+	case NV_ARCH_10:
+	case NV_ARCH_20:
+	case NV_ARCH_30:
+	default:
+		if (((par->Chipset & 0xffff) == 0x01A0) ||
+		    ((par->Chipset & 0xffff) == 0x01f0)) {
+			nForceUpdateArbitrationSettings(VClk,
+							pixelDepth * 8,
+							&(state->arbitration0),
+							&(state->arbitration1),
+							par);
+		} else if (par->Architecture < NV_ARCH_30) {
+			nv10UpdateArbitrationSettings(VClk,
+						      pixelDepth * 8,
+						      &(state->arbitration0),
+						      &(state->arbitration1),
+						      par);
+		} else {
+			nv30UpdateArbitrationSettings(par,
+						      &(state->arbitration0),
+						      &(state->arbitration1));
+		}
+
+		state->cursor0 = 0x80 | (par->CursorStart >> 17);
+		state->cursor1 = (par->CursorStart >> 11) << 2;
+		state->cursor2 = par->CursorStart >> 24;
+		if (flags & FB_VMODE_DOUBLE)
+			state->cursor1 |= 2;
+		state->pllsel = 0x10000700;
+		state->config = NV_RD32(par->PFB, 0x00000200);
+		state->general = bpp == 16 ? 0x00101100 : 0x00100100;
+		state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+		break;
+	}
+
+	if (bpp != 8)		/* DirectColor */
+		state->general |= 0x00000030;
+
+	state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3;
+	state->pixel = (pixelDepth > 2) ? 3 : pixelDepth;
+}
+
+void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
+{
+	int i;
+
+	NV_WR32(par->PMC, 0x0140, 0x00000000);
+	NV_WR32(par->PMC, 0x0200, 0xFFFF00FF);
+	NV_WR32(par->PMC, 0x0200, 0xFFFFFFFF);
+
+	NV_WR32(par->PTIMER, 0x0200 * 4, 0x00000008);
+	NV_WR32(par->PTIMER, 0x0210 * 4, 0x00000003);
+	NV_WR32(par->PTIMER, 0x0140 * 4, 0x00000000);
+	NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF);
+
+	if (par->Architecture == NV_ARCH_04) {
+		NV_WR32(par->PFB, 0x0200, state->config);
+	} else if ((par->Chipset & 0xfff0) == 0x0090) {
+		for (i = 0; i < 15; i++) {
+			NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0);
+			NV_WR32(par->PFB, 0x0604 + (i * 0x10), par->FbMapSize - 1);
+		}
+	} else {
+		for (i = 0; i < 8; i++) {
+			NV_WR32(par->PFB, 0x0240 + (i * 0x10), 0);
+			NV_WR32(par->PFB, 0x0244 + (i * 0x10), par->FbMapSize - 1);
+		}
+	}
+
+	if (par->Architecture >= NV_ARCH_40) {
+		NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010);
+		NV_WR32(par->PRAMIN, 0x0001 * 4, 0x00101202);
+		NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011);
+		NV_WR32(par->PRAMIN, 0x0003 * 4, 0x00101204);
+		NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012);
+		NV_WR32(par->PRAMIN, 0x0005 * 4, 0x00101206);
+		NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013);
+		NV_WR32(par->PRAMIN, 0x0007 * 4, 0x00101208);
+		NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014);
+		NV_WR32(par->PRAMIN, 0x0009 * 4, 0x0010120A);
+		NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015);
+		NV_WR32(par->PRAMIN, 0x000B * 4, 0x0010120C);
+		NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016);
+		NV_WR32(par->PRAMIN, 0x000D * 4, 0x0010120E);
+		NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017);
+		NV_WR32(par->PRAMIN, 0x000F * 4, 0x00101210);
+		NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000);
+		NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1);
+		NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0808 * 4, 0x02080062);
+		NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080A * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x080B * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x080C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4, 0x02080043);
+		NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0818 * 4, 0x02080044);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x02000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4, 0x02080019);
+		NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0828 * 4, 0x020A005C);
+		NV_WR32(par->PRAMIN, 0x0829 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0830 * 4, 0x0208009F);
+		NV_WR32(par->PRAMIN, 0x0831 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0832 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0833 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0834 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0835 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0838 * 4, 0x0208004A);
+		NV_WR32(par->PRAMIN, 0x0839 * 4, 0x02000000);
+		NV_WR32(par->PRAMIN, 0x083A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0840 * 4, 0x02080077);
+		NV_WR32(par->PRAMIN, 0x0841 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0842 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0843 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0844 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0845 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x084C * 4, 0x00003002);
+		NV_WR32(par->PRAMIN, 0x084D * 4, 0x00007FFF);
+		NV_WR32(par->PRAMIN, 0x084E * 4,
+			par->FbUsableSize | 0x00000002);
+
+#ifdef __BIG_ENDIAN
+		NV_WR32(par->PRAMIN, 0x080A * 4,
+			NV_RD32(par->PRAMIN, 0x080A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4,
+			NV_RD32(par->PRAMIN, 0x0812 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4,
+			NV_RD32(par->PRAMIN, 0x081A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4,
+			NV_RD32(par->PRAMIN, 0x0822 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x082A * 4,
+			NV_RD32(par->PRAMIN, 0x082A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0832 * 4,
+			NV_RD32(par->PRAMIN, 0x0832 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x083A * 4,
+			NV_RD32(par->PRAMIN, 0x083A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0842 * 4,
+			NV_RD32(par->PRAMIN, 0x0842 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0839 * 4, 0x01000000);
+#endif
+	} else {
+		NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010);
+		NV_WR32(par->PRAMIN, 0x0001 * 4, 0x80011201);
+		NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011);
+		NV_WR32(par->PRAMIN, 0x0003 * 4, 0x80011202);
+		NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012);
+		NV_WR32(par->PRAMIN, 0x0005 * 4, 0x80011203);
+		NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013);
+		NV_WR32(par->PRAMIN, 0x0007 * 4, 0x80011204);
+		NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014);
+		NV_WR32(par->PRAMIN, 0x0009 * 4, 0x80011205);
+		NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015);
+		NV_WR32(par->PRAMIN, 0x000B * 4, 0x80011206);
+		NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016);
+		NV_WR32(par->PRAMIN, 0x000D * 4, 0x80011207);
+		NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017);
+		NV_WR32(par->PRAMIN, 0x000F * 4, 0x80011208);
+		NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000);
+		NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1);
+		NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0803 * 4, 0x00000002);
+		if (par->Architecture >= NV_ARCH_10)
+			NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008062);
+		else
+			NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008042);
+		NV_WR32(par->PRAMIN, 0x0805 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0806 * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x0807 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0808 * 4, 0x01008043);
+		NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080C * 4, 0x01008044);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x080E * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080F * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4, 0x01008019);
+		NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4, 0x0100A05C);
+		NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0816 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0817 * 4, 0x00000000);
+		if (par->WaitVSyncPossible)
+			NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100809F);
+		else
+			NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100805F);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081C * 4, 0x0100804A);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x081E * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081F * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4, 0x01018077);
+		NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00003002);
+		NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00007FFF);
+		NV_WR32(par->PRAMIN, 0x0826 * 4,
+			par->FbUsableSize | 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0827 * 4, 0x00000002);
+#ifdef __BIG_ENDIAN
+		NV_WR32(par->PRAMIN, 0x0804 * 4,
+			NV_RD32(par->PRAMIN, 0x0804 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0808 * 4,
+			NV_RD32(par->PRAMIN, 0x0808 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x080C * 4,
+			NV_RD32(par->PRAMIN, 0x080C * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4,
+			NV_RD32(par->PRAMIN, 0x0810 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4,
+			NV_RD32(par->PRAMIN, 0x0814 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0818 * 4,
+			NV_RD32(par->PRAMIN, 0x0818 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x081C * 4,
+			NV_RD32(par->PRAMIN, 0x081C * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4,
+			NV_RD32(par->PRAMIN, 0x0820 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000001);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000001);
+#endif
+	}
+	if (par->Architecture < NV_ARCH_10) {
+		if ((par->Chipset & 0x0fff) == 0x0020) {
+			NV_WR32(par->PRAMIN, 0x0824 * 4,
+				NV_RD32(par->PRAMIN, 0x0824 * 4) | 0x00020000);
+			NV_WR32(par->PRAMIN, 0x0826 * 4,
+				NV_RD32(par->PRAMIN,
+					0x0826 * 4) + par->FbAddress);
+		}
+		NV_WR32(par->PGRAPH, 0x0080, 0x000001FF);
+		NV_WR32(par->PGRAPH, 0x0080, 0x1230C000);
+		NV_WR32(par->PGRAPH, 0x0084, 0x72111101);
+		NV_WR32(par->PGRAPH, 0x0088, 0x11D5F071);
+		NV_WR32(par->PGRAPH, 0x008C, 0x0004FF31);
+		NV_WR32(par->PGRAPH, 0x008C, 0x4004FF31);
+		NV_WR32(par->PGRAPH, 0x0140, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0170, 0x10010100);
+		NV_WR32(par->PGRAPH, 0x0710, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0720, 0x00000001);
+		NV_WR32(par->PGRAPH, 0x0810, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF);
+	} else {
+		NV_WR32(par->PGRAPH, 0x0080, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0080, 0x00000000);
+
+		NV_WR32(par->PGRAPH, 0x0140, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0144, 0x10010100);
+		NV_WR32(par->PGRAPH, 0x0714, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0720, 0x00000001);
+		NV_WR32(par->PGRAPH, 0x0710,
+			NV_RD32(par->PGRAPH, 0x0710) & 0x0007ff00);
+		NV_WR32(par->PGRAPH, 0x0710,
+			NV_RD32(par->PGRAPH, 0x0710) | 0x00020100);
+
+		if (par->Architecture == NV_ARCH_10) {
+			NV_WR32(par->PGRAPH, 0x0084, 0x00118700);
+			NV_WR32(par->PGRAPH, 0x0088, 0x24E00810);
+			NV_WR32(par->PGRAPH, 0x008C, 0x55DE0030);
+
+			for (i = 0; i < 32; i++)
+				NV_WR32(&par->PGRAPH[(0x0B00 / 4) + i], 0,
+					NV_RD32(&par->PFB[(0x0240 / 4) + i],
+						0));
+
+			NV_WR32(par->PGRAPH, 0x640, 0);
+			NV_WR32(par->PGRAPH, 0x644, 0);
+			NV_WR32(par->PGRAPH, 0x684, par->FbMapSize - 1);
+			NV_WR32(par->PGRAPH, 0x688, par->FbMapSize - 1);
+
+			NV_WR32(par->PGRAPH, 0x0810, 0x00000000);
+			NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF);
+		} else {
+			if (par->Architecture >= NV_ARCH_40) {
+				NV_WR32(par->PGRAPH, 0x0084, 0x401287c0);
+				NV_WR32(par->PGRAPH, 0x008C, 0x60de8051);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00008000);
+				NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f);
+
+				if ((par->Chipset & 0xfff0) == 0x0040) {
+					NV_WR32(par->PGRAPH, 0x09b0,
+						0x83280fff);
+					NV_WR32(par->PGRAPH, 0x09b4,
+						0x000000a0);
+				} else {
+					NV_WR32(par->PGRAPH, 0x0820,
+						0x83280eff);
+					NV_WR32(par->PGRAPH, 0x0824,
+						0x000000a0);
+				}
+
+				switch (par->Chipset & 0xfff0) {
+				case 0x0040:
+				case 0x0210:
+					NV_WR32(par->PGRAPH, 0x09b8,
+						0x0078e366);
+					NV_WR32(par->PGRAPH, 0x09bc,
+						0x0000014c);
+					NV_WR32(par->PFB, 0x033C,
+						NV_RD32(par->PFB, 0x33C) &
+						0xffff7fff);
+					break;
+				case 0x00C0:
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x007596ff);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x00000108);
+					break;
+				case 0x0160:
+				case 0x01D0:
+					NV_WR32(par->PMC, 0x1700,
+						NV_RD32(par->PFB, 0x020C));
+					NV_WR32(par->PMC, 0x1704, 0);
+					NV_WR32(par->PMC, 0x1708, 0);
+					NV_WR32(par->PMC, 0x170C,
+						NV_RD32(par->PFB, 0x020C));
+					NV_WR32(par->PGRAPH, 0x0860, 0);
+					NV_WR32(par->PGRAPH, 0x0864, 0);
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC,
+							0x0608) | 0x00100000);
+					break;
+				case 0x0140:
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x0072cb77);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x00000108);
+					break;
+				case 0x0220:
+				case 0x0230:
+					NV_WR32(par->PGRAPH, 0x0860, 0);
+					NV_WR32(par->PGRAPH, 0x0864, 0);
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC, 0x0608) |
+						0x00100000);
+					break;
+				case 0x0090:
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC, 0x0608) |
+						0x00100000);
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x07830610);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x0000016A);
+					break;
+				default:
+					break;
+				};
+
+				NV_WR32(par->PGRAPH, 0x0b38, 0x2ffff800);
+				NV_WR32(par->PGRAPH, 0x0b3c, 0x00006000);
+				NV_WR32(par->PGRAPH, 0x032C, 0x01000000);
+				NV_WR32(par->PGRAPH, 0x0220, 0x00001200);
+			} else if (par->Architecture == NV_ARCH_30) {
+				NV_WR32(par->PGRAPH, 0x0084, 0x40108700);
+				NV_WR32(par->PGRAPH, 0x0890, 0x00140000);
+				NV_WR32(par->PGRAPH, 0x008C, 0xf00e0431);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00008000);
+				NV_WR32(par->PGRAPH, 0x0610, 0xf04b1f36);
+				NV_WR32(par->PGRAPH, 0x0B80, 0x1002d888);
+				NV_WR32(par->PGRAPH, 0x0B88, 0x62ff007f);
+			} else {
+				NV_WR32(par->PGRAPH, 0x0084, 0x00118700);
+				NV_WR32(par->PGRAPH, 0x008C, 0xF20E0431);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00000000);
+				NV_WR32(par->PGRAPH, 0x009C, 0x00000040);
+
+				if ((par->Chipset & 0x0ff0) >= 0x0250) {
+					NV_WR32(par->PGRAPH, 0x0890,
+						0x00080000);
+					NV_WR32(par->PGRAPH, 0x0610,
+						0x304B1FB6);
+					NV_WR32(par->PGRAPH, 0x0B80,
+						0x18B82880);
+					NV_WR32(par->PGRAPH, 0x0B84,
+						0x44000000);
+					NV_WR32(par->PGRAPH, 0x0098,
+						0x40000080);
+					NV_WR32(par->PGRAPH, 0x0B88,
+						0x000000ff);
+				} else {
+					NV_WR32(par->PGRAPH, 0x0880,
+						0x00080000);
+					NV_WR32(par->PGRAPH, 0x0094,
+						0x00000005);
+					NV_WR32(par->PGRAPH, 0x0B80,
+						0x45CAA208);
+					NV_WR32(par->PGRAPH, 0x0B84,
+						0x24000000);
+					NV_WR32(par->PGRAPH, 0x0098,
+						0x00000040);
+					NV_WR32(par->PGRAPH, 0x0750,
+						0x00E00038);
+					NV_WR32(par->PGRAPH, 0x0754,
+						0x00000030);
+					NV_WR32(par->PGRAPH, 0x0750,
+						0x00E10038);
+					NV_WR32(par->PGRAPH, 0x0754,
+						0x00000030);
+				}
+			}
+
+			if ((par->Chipset & 0xfff0) == 0x0090) {
+				for (i = 0; i < 60; i++)
+					NV_WR32(par->PGRAPH, 0x0D00 + i,
+						NV_RD32(par->PFB, 0x0600 + i));
+			} else {
+				for (i = 0; i < 32; i++)
+					NV_WR32(par->PGRAPH, 0x0900 + i,
+						NV_RD32(par->PFB, 0x0240 + i));
+			}
+
+			if (par->Architecture >= NV_ARCH_40) {
+				if ((par->Chipset & 0xfff0) == 0x0040) {
+					NV_WR32(par->PGRAPH, 0x09A4,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x09A8,
+						NV_RD32(par->PFB, 0x0204));
+					NV_WR32(par->PGRAPH, 0x69A4,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x69A8,
+						NV_RD32(par->PFB, 0x0204));
+
+					NV_WR32(par->PGRAPH, 0x0820, 0);
+					NV_WR32(par->PGRAPH, 0x0824, 0);
+					NV_WR32(par->PGRAPH, 0x0864,
+						par->FbMapSize - 1);
+					NV_WR32(par->PGRAPH, 0x0868,
+						par->FbMapSize - 1);
+				} else {
+					if((par->Chipset & 0xfff0) == 0x0090) {
+						NV_WR32(par->PGRAPH, 0x0DF0,
+							NV_RD32(par->PFB, 0x0200));
+						NV_WR32(par->PGRAPH, 0x0DF4,
+							NV_RD32(par->PFB, 0x0204));
+					} else {
+						NV_WR32(par->PGRAPH, 0x09F0,
+							NV_RD32(par->PFB, 0x0200));
+						NV_WR32(par->PGRAPH, 0x09F4,
+							NV_RD32(par->PFB, 0x0204));
+					}
+					NV_WR32(par->PGRAPH, 0x69F0,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x69F4,
+						NV_RD32(par->PFB, 0x0204));
+
+					NV_WR32(par->PGRAPH, 0x0840, 0);
+					NV_WR32(par->PGRAPH, 0x0844, 0);
+					NV_WR32(par->PGRAPH, 0x08a0,
+						par->FbMapSize - 1);
+					NV_WR32(par->PGRAPH, 0x08a4,
+						par->FbMapSize - 1);
+				}
+			} else {
+				NV_WR32(par->PGRAPH, 0x09A4,
+					NV_RD32(par->PFB, 0x0200));
+				NV_WR32(par->PGRAPH, 0x09A8,
+					NV_RD32(par->PFB, 0x0204));
+				NV_WR32(par->PGRAPH, 0x0750, 0x00EA0000);
+				NV_WR32(par->PGRAPH, 0x0754,
+					NV_RD32(par->PFB, 0x0200));
+				NV_WR32(par->PGRAPH, 0x0750, 0x00EA0004);
+				NV_WR32(par->PGRAPH, 0x0754,
+					NV_RD32(par->PFB, 0x0204));
+
+				NV_WR32(par->PGRAPH, 0x0820, 0);
+				NV_WR32(par->PGRAPH, 0x0824, 0);
+				NV_WR32(par->PGRAPH, 0x0864,
+					par->FbMapSize - 1);
+				NV_WR32(par->PGRAPH, 0x0868,
+					par->FbMapSize - 1);
+			}
+			NV_WR32(par->PGRAPH, 0x0B20, 0x00000000);
+			NV_WR32(par->PGRAPH, 0x0B04, 0xFFFFFFFF);
+		}
+	}
+	NV_WR32(par->PGRAPH, 0x053C, 0);
+	NV_WR32(par->PGRAPH, 0x0540, 0);
+	NV_WR32(par->PGRAPH, 0x0544, 0x00007FFF);
+	NV_WR32(par->PGRAPH, 0x0548, 0x00007FFF);
+
+	NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0141 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000000);
+	if (par->Architecture >= NV_ARCH_40)
+		NV_WR32(par->PFIFO, 0x0481 * 4, 0x00010000);
+	else
+		NV_WR32(par->PFIFO, 0x0481 * 4, 0x00000100);
+	NV_WR32(par->PFIFO, 0x0490 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0491 * 4, 0x00000000);
+	if (par->Architecture >= NV_ARCH_40)
+		NV_WR32(par->PFIFO, 0x048B * 4, 0x00001213);
+	else
+		NV_WR32(par->PFIFO, 0x048B * 4, 0x00001209);
+	NV_WR32(par->PFIFO, 0x0400 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0414 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0084 * 4, 0x03000100);
+	NV_WR32(par->PFIFO, 0x0085 * 4, 0x00000110);
+	NV_WR32(par->PFIFO, 0x0086 * 4, 0x00000112);
+	NV_WR32(par->PFIFO, 0x0143 * 4, 0x0000FFFF);
+	NV_WR32(par->PFIFO, 0x0496 * 4, 0x0000FFFF);
+	NV_WR32(par->PFIFO, 0x0050 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0040 * 4, 0xFFFFFFFF);
+	NV_WR32(par->PFIFO, 0x0415 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x048C * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x04A0 * 4, 0x00000000);
+#ifdef __BIG_ENDIAN
+	NV_WR32(par->PFIFO, 0x0489 * 4, 0x800F0078);
+#else
+	NV_WR32(par->PFIFO, 0x0489 * 4, 0x000F0078);
+#endif
+	NV_WR32(par->PFIFO, 0x0488 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001);
+	if (par->Architecture >= NV_ARCH_10) {
+		if (par->twoHeads) {
+			NV_WR32(par->PCRTC0, 0x0860, state->head);
+			NV_WR32(par->PCRTC0, 0x2860, state->head2);
+		}
+		NV_WR32(par->PRAMDAC, 0x0404, NV_RD32(par->PRAMDAC, 0x0404) |
+			(1 << 25));
+
+		NV_WR32(par->PMC, 0x8704, 1);
+		NV_WR32(par->PMC, 0x8140, 0);
+		NV_WR32(par->PMC, 0x8920, 0);
+		NV_WR32(par->PMC, 0x8924, 0);
+		NV_WR32(par->PMC, 0x8908, par->FbMapSize - 1);
+		NV_WR32(par->PMC, 0x890C, par->FbMapSize - 1);
+		NV_WR32(par->PMC, 0x1588, 0);
+
+		NV_WR32(par->PCRTC, 0x0810, state->cursorConfig);
+		NV_WR32(par->PCRTC, 0x0830, state->displayV - 3);
+		NV_WR32(par->PCRTC, 0x0834, state->displayV - 1);
+
+		if (par->FlatPanel) {
+			if ((par->Chipset & 0x0ff0) == 0x0110) {
+				NV_WR32(par->PRAMDAC, 0x0528, state->dither);
+			} else if (par->twoHeads) {
+				NV_WR32(par->PRAMDAC, 0x083C, state->dither);
+			}
+
+			VGA_WR08(par->PCIO, 0x03D4, 0x53);
+			VGA_WR08(par->PCIO, 0x03D5, state->timingH);
+			VGA_WR08(par->PCIO, 0x03D4, 0x54);
+			VGA_WR08(par->PCIO, 0x03D5, state->timingV);
+			VGA_WR08(par->PCIO, 0x03D4, 0x21);
+			VGA_WR08(par->PCIO, 0x03D5, 0xfa);
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x41);
+		VGA_WR08(par->PCIO, 0x03D5, state->extra);
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x19);
+	VGA_WR08(par->PCIO, 0x03D5, state->repaint0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1A);
+	VGA_WR08(par->PCIO, 0x03D5, state->repaint1);
+	VGA_WR08(par->PCIO, 0x03D4, 0x25);
+	VGA_WR08(par->PCIO, 0x03D5, state->screen);
+	VGA_WR08(par->PCIO, 0x03D4, 0x28);
+	VGA_WR08(par->PCIO, 0x03D5, state->pixel);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2D);
+	VGA_WR08(par->PCIO, 0x03D5, state->horiz);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	VGA_WR08(par->PCIO, 0x03D5, state->fifo);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1B);
+	VGA_WR08(par->PCIO, 0x03D5, state->arbitration0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x20);
+	VGA_WR08(par->PCIO, 0x03D5, state->arbitration1);
+
+	if(par->Architecture >= NV_ARCH_30) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x47);
+		VGA_WR08(par->PCIO, 0x03D5, state->arbitration1 >> 8);
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x30);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x31);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor1);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2F);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor2);
+	VGA_WR08(par->PCIO, 0x03D4, 0x39);
+	VGA_WR08(par->PCIO, 0x03D5, state->interlace);
+
+	if (!par->FlatPanel) {
+		NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel);
+		NV_WR32(par->PRAMDAC0, 0x0508, state->vpll);
+		if (par->twoHeads)
+			NV_WR32(par->PRAMDAC0, 0x0520, state->vpll2);
+		if (par->twoStagePLL) {
+			NV_WR32(par->PRAMDAC0, 0x0578, state->vpllB);
+			NV_WR32(par->PRAMDAC0, 0x057C, state->vpll2B);
+		}
+	} else {
+		NV_WR32(par->PRAMDAC, 0x0848, state->scale);
+		NV_WR32(par->PRAMDAC, 0x0828, state->crtcSync +
+			par->PanelTweak);
+	}
+
+	NV_WR32(par->PRAMDAC, 0x0600, state->general);
+
+	NV_WR32(par->PCRTC, 0x0140, 0);
+	NV_WR32(par->PCRTC, 0x0100, 1);
+
+	par->CurrentState = state;
+}
+
+void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) {
+	VGA_WR08(par->PCIO, 0x03D4, 0x19);
+	state->repaint0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1A);
+	state->repaint1 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x25);
+	state->screen = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x28);
+	state->pixel = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2D);
+	state->horiz = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	state->fifo         = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1B);
+	state->arbitration0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x20);
+	state->arbitration1 = VGA_RD08(par->PCIO, 0x03D5);
+
+	if(par->Architecture >= NV_ARCH_30) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x47);
+		state->arbitration1 |= (VGA_RD08(par->PCIO, 0x03D5) & 1) << 8;
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x30);
+	state->cursor0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x31);
+	state->cursor1 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2F);
+	state->cursor2 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x39);
+	state->interlace = VGA_RD08(par->PCIO, 0x03D5);
+	state->vpll = NV_RD32(par->PRAMDAC0, 0x0508);
+	if (par->twoHeads)
+		state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
+	if (par->twoStagePLL) {
+		state->vpllB = NV_RD32(par->PRAMDAC0, 0x0578);
+		state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
+	}
+	state->pllsel = NV_RD32(par->PRAMDAC0, 0x050C);
+	state->general = NV_RD32(par->PRAMDAC, 0x0600);
+	state->scale = NV_RD32(par->PRAMDAC, 0x0848);
+	state->config = NV_RD32(par->PFB, 0x0200);
+
+	if (par->Architecture >= NV_ARCH_10) {
+		if (par->twoHeads) {
+			state->head = NV_RD32(par->PCRTC0, 0x0860);
+			state->head2 = NV_RD32(par->PCRTC0, 0x2860);
+			VGA_WR08(par->PCIO, 0x03D4, 0x44);
+			state->crtcOwner = VGA_RD08(par->PCIO, 0x03D5);
+		}
+		VGA_WR08(par->PCIO, 0x03D4, 0x41);
+		state->extra = VGA_RD08(par->PCIO, 0x03D5);
+		state->cursorConfig = NV_RD32(par->PCRTC, 0x0810);
+
+		if ((par->Chipset & 0x0ff0) == 0x0110) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x0528);
+		} else if (par->twoHeads) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x083C);
+		}
+
+		if (par->FlatPanel) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x53);
+			state->timingH = VGA_RD08(par->PCIO, 0x03D5);
+			VGA_WR08(par->PCIO, 0x03D4, 0x54);
+			state->timingV = VGA_RD08(par->PCIO, 0x03D5);
+		}
+	}
+}
+
+void NVSetStartAddress(struct nvidia_par *par, u32 start)
+{
+	NV_WR32(par->PCRTC, 0x800, start);
+}
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -0,0 +1,215 @@
+/*
+ * linux/drivers/video/nvidia/nvidia-i2c.c - nVidia i2c
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based on rivafb-i2c.c
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+
+#include "../edid.h"
+
+static void nvidia_gpio_setscl(void *data, int state)
+{
+	struct nvidia_i2c_chan *chan = data;
+	struct nvidia_par *par = chan->par;
+	u32 val;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x20;
+	else
+		val &= ~0x20;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+}
+
+static void nvidia_gpio_setsda(void *data, int state)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x10;
+	else
+		val &= ~0x10;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+}
+
+static int nvidia_gpio_getscl(void *data)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val = 0;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->PCIO, 0x3d5) & 0x04)
+		val = 1;
+
+	val = VGA_RD08(par->PCIO, 0x3d5);
+
+	return val;
+}
+
+static int nvidia_gpio_getsda(void *data)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val = 0;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->PCIO, 0x3d5) & 0x08)
+		val = 1;
+
+	return val;
+}
+
+#define I2C_ALGO_NVIDIA   0x0e0000
+static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
+{
+	int rc;
+
+	strcpy(chan->adapter.name, name);
+	chan->adapter.owner = THIS_MODULE;
+	chan->adapter.id = I2C_ALGO_NVIDIA;
+	chan->adapter.algo_data = &chan->algo;
+	chan->adapter.dev.parent = &chan->par->pci_dev->dev;
+	chan->algo.setsda = nvidia_gpio_setsda;
+	chan->algo.setscl = nvidia_gpio_setscl;
+	chan->algo.getsda = nvidia_gpio_getsda;
+	chan->algo.getscl = nvidia_gpio_getscl;
+	chan->algo.udelay = 40;
+	chan->algo.timeout = msecs_to_jiffies(2);
+	chan->algo.data = chan;
+
+	i2c_set_adapdata(&chan->adapter, chan);
+
+	/* Raise SCL and SDA */
+	nvidia_gpio_setsda(chan, 1);
+	nvidia_gpio_setscl(chan, 1);
+	udelay(20);
+
+	rc = i2c_bit_add_bus(&chan->adapter);
+	if (rc == 0)
+		dev_dbg(&chan->par->pci_dev->dev,
+			"I2C bus %s registered.\n", name);
+	else {
+		dev_warn(&chan->par->pci_dev->dev,
+			 "Failed to register I2C bus %s.\n", name);
+		chan->par = NULL;
+	}
+
+	return rc;
+}
+
+void nvidia_create_i2c_busses(struct nvidia_par *par)
+{
+	par->bus = 3;
+
+	par->chan[0].par = par;
+	par->chan[1].par = par;
+	par->chan[2].par = par;
+
+	par->chan[0].ddc_base = 0x3e;
+	nvidia_setup_i2c_bus(&par->chan[0], "BUS1");
+
+	par->chan[1].ddc_base = 0x36;
+	nvidia_setup_i2c_bus(&par->chan[1], "BUS2");
+
+	par->chan[2].ddc_base = 0x50;
+	nvidia_setup_i2c_bus(&par->chan[2], "BUS3");
+}
+
+void nvidia_delete_i2c_busses(struct nvidia_par *par)
+{
+	if (par->chan[0].par)
+		i2c_bit_del_bus(&par->chan[0].adapter);
+	par->chan[0].par = NULL;
+
+	if (par->chan[1].par)
+		i2c_bit_del_bus(&par->chan[1].adapter);
+	par->chan[1].par = NULL;
+
+	if (par->chan[2].par)
+		i2c_bit_del_bus(&par->chan[2].adapter);
+	par->chan[2].par = NULL;
+
+}
+
+static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan)
+{
+	u8 start = 0x0;
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = 0x50,
+		 .len = 1,
+		 .buf = &start,
+		 }, {
+		     .addr = 0x50,
+		     .flags = I2C_M_RD,
+		     .len = EDID_LENGTH,
+		     },
+	};
+	u8 *buf;
+
+	if (!chan->par)
+		return NULL;
+
+	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!buf) {
+		dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n");
+		return NULL;
+	}
+	msgs[1].buf = buf;
+
+	if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+		return buf;
+	dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n");
+	kfree(buf);
+	return NULL;
+}
+
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid)
+{
+	u8 *edid = NULL;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		/* Do the real work */
+		edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]);
+		if (edid)
+			break;
+	}
+	if (out_edid)
+		*out_edid = edid;
+	if (!edid)
+		return 1;
+
+	return 0;
+}
diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_local.h
@@ -0,0 +1,107 @@
+/***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING 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 SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#ifndef __NV_LOCAL_H__
+#define __NV_LOCAL_H__
+
+/*
+ * This file includes any environment or machine specific values to access the
+ * HW.  Put all affected includes, typdefs, etc. here so the riva_hw.* files
+ * can stay generic in nature.
+ */
+
+/*
+ * HW access macros.  These assume memory-mapped I/O, and not normal I/O space.
+ */
+#define NV_WR08(p,i,d)  (__raw_writeb((d), (void __iomem *)(p) + (i)))
+#define NV_RD08(p,i)    (__raw_readb((void __iomem *)(p) + (i)))
+#define NV_WR16(p,i,d)  (__raw_writew((d), (void __iomem *)(p) + (i)))
+#define NV_RD16(p,i)    (__raw_readw((void __iomem *)(p) + (i)))
+#define NV_WR32(p,i,d)  (__raw_writel((d), (void __iomem *)(p) + (i)))
+#define NV_RD32(p,i)    (__raw_readl((void __iomem *)(p) + (i)))
+
+/* VGA I/O is now always done through MMIO */
+#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i)))
+#define VGA_RD08(p,i)   (readb((void __iomem *)(p) + (i)))
+
+#define NVDmaNext(par, data) \
+     NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data))
+
+#define NVDmaStart(par, tag, size) {          \
+     if((par)->dmaFree <= (size))             \
+        NVDmaWait(par, size);                 \
+     NVDmaNext(par, ((size) << 18) | (tag));  \
+     (par)->dmaFree -= ((size) + 1);          \
+}
+
+#if defined(__i386__)
+#define _NV_FENCE() outb(0, 0x3D0);
+#else
+#define _NV_FENCE() mb();
+#endif
+
+#define WRITE_PUT(par, data) {                   \
+  _NV_FENCE()                                    \
+  NV_RD08((par)->FbStart, 0);                    \
+  NV_WR32(&(par)->FIFO[0x0010], 0, (data) << 2); \
+  mb();                                          \
+}
+
+#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2)
+
+#define reverse_order(l)        \
+do {                            \
+	u8 *a = (u8 *)(l);      \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a];      \
+} while(0)
+
+#endif				/* __NV_LOCAL_H__ */
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_of.c
@@ -0,0 +1,59 @@
+/*
+ * linux/drivers/video/nvidia/nv_of.c
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based on rivafb-i2c.c
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+
+void nvidia_create_i2c_busses(struct nvidia_par *par) {}
+void nvidia_delete_i2c_busses(struct nvidia_par *par) {}
+
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid)
+{
+	struct device_node *dp;
+	unsigned char *pedid = NULL;
+	unsigned char *disptype = NULL;
+	static char *propnames[] = {
+		"DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
+	int i;
+
+	dp = pci_device_to_OF_node(par->pci_dev);
+	for (; dp != NULL; dp = dp->child) {
+		disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+		if (disptype == NULL)
+			continue;
+		if (strncmp(disptype, "LCD", 3) != 0)
+			continue;
+		for (i = 0; propnames[i] != NULL; ++i) {
+			pedid = (unsigned char *)
+				get_property(dp, propnames[i], NULL);
+			if (pedid != NULL) {
+				*out_edid = pedid;
+				return 0;
+			}
+		}
+	}
+	return 1;
+}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_proto.h
@@ -0,0 +1,58 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_proto.h,v 1.10 2003/07/31 20:24:29 mvojkovi Exp $ */
+
+#ifndef __NV_PROTO_H__
+#define __NV_PROTO_H__
+
+/* in nv_setup.c */
+void NVCommonSetup(struct fb_info *info);
+void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadCrtc(struct nvidia_par *par, u8 index);
+void NVWriteGr(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadGr(struct nvidia_par *par, u8 index);
+void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadSeq(struct nvidia_par *par, u8 index);
+void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadAttr(struct nvidia_par *par, u8 index);
+void NVWriteMiscOut(struct nvidia_par *par, u8 value);
+u8 NVReadMiscOut(struct nvidia_par *par);
+void NVWriteDacMask(struct nvidia_par *par, u8 value);
+void NVWriteDacReadAddr(struct nvidia_par *par, u8 value);
+void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value);
+void NVWriteDacData(struct nvidia_par *par, u8 value);
+u8 NVReadDacData(struct nvidia_par *par);
+
+/* in nv_hw.c */
+void NVCalcStateExt(struct nvidia_par *par, struct _riva_hw_state *,
+		    int, int, int, int, int, int);
+void NVLoadStateExt(struct nvidia_par *par, struct _riva_hw_state *);
+void NVUnloadStateExt(struct nvidia_par *par, struct _riva_hw_state *);
+void NVSetStartAddress(struct nvidia_par *par, u32);
+int NVShowHideCursor(struct nvidia_par *par, int);
+void NVLockUnlock(struct nvidia_par *par, int);
+
+/* in nvidia-i2c.c */
+#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF)
+void nvidia_create_i2c_busses(struct nvidia_par *par);
+void nvidia_delete_i2c_busses(struct nvidia_par *par);
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn,
+			       u8 ** out_edid);
+#else
+#define nvidia_create_i2c_busses(...)
+#define nvidia_delete_i2c_busses(...)
+#define nvidia_probe_i2c_connector(p, c, edid) \
+do {                                           \
+	*(edid) = NULL;                        \
+} while(0)
+#endif
+
+/* in nv_accel.c */
+extern void NVResetGraphics(struct fb_info *info);
+extern void nvidiafb_copyarea(struct fb_info *info,
+			      const struct fb_copyarea *region);
+extern void nvidiafb_fillrect(struct fb_info *info,
+			      const struct fb_fillrect *rect);
+extern void nvidiafb_imageblit(struct fb_info *info,
+			       const struct fb_image *image);
+extern int nvidiafb_sync(struct fb_info *info);
+extern u8 byte_rev[256];
+#endif				/* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_setup.c
@@ -0,0 +1,636 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING 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 SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#include <video/vga.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+/*
+ * Override VGA I/O routines.
+ */
+void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
+	VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
+}
+u8 NVReadCrtc(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
+	return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
+}
+void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_GFX_I, index);
+	VGA_WR08(par->PVIO, VGA_GFX_D, value);
+}
+u8 NVReadGr(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PVIO, VGA_GFX_I, index);
+	return (VGA_RD08(par->PVIO, VGA_GFX_D));
+}
+void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
+	VGA_WR08(par->PVIO, VGA_SEQ_D, value);
+}
+u8 NVReadSeq(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
+	return (VGA_RD08(par->PVIO, VGA_SEQ_D));
+}
+void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	if (par->paletteEnabled)
+		index &= ~0x20;
+	else
+		index |= 0x20;
+	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
+	VGA_WR08(par->PCIO, VGA_ATT_W, value);
+}
+u8 NVReadAttr(struct nvidia_par *par, u8 index)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	if (par->paletteEnabled)
+		index &= ~0x20;
+	else
+		index |= 0x20;
+	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
+	return (VGA_RD08(par->PCIO, VGA_ATT_R));
+}
+void NVWriteMiscOut(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_MIS_W, value);
+}
+u8 NVReadMiscOut(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PVIO, VGA_MIS_R));
+}
+#if 0
+void NVEnablePalette(struct nvidia_par *par)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	VGA_WR08(par->PCIO, VGA_ATT_IW, 0x00);
+	par->paletteEnabled = 1;
+}
+void NVDisablePalette(struct nvidia_par *par)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	VGA_WR08(par->PCIO, VGA_ATT_IW, 0x20);
+	par->paletteEnabled = 0;
+}
+#endif  /*  0  */
+void NVWriteDacMask(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
+}
+#if 0
+u8 NVReadDacMask(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PDIO, VGA_PEL_MSK));
+}
+#endif  /*  0  */
+void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_IR, value);
+}
+void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_IW, value);
+}
+void NVWriteDacData(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_D, value);
+}
+u8 NVReadDacData(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PDIO, VGA_PEL_D));
+}
+
+static int NVIsConnected(struct nvidia_par *par, int output)
+{
+	volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
+	u32 reg52C, reg608;
+	int present;
+
+	if (output)
+		PRAMDAC += 0x800;
+
+	reg52C = NV_RD32(PRAMDAC, 0x052C);
+	reg608 = NV_RD32(PRAMDAC, 0x0608);
+
+	NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
+	msleep(1);
+	NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
+
+	NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
+	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
+		0x00001000);
+
+	msleep(1);
+
+	present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
+
+	if (present)
+		printk("nvidiafb: CRTC%i found\n", output);
+	else
+		printk("nvidiafb: CRTC%i not found\n", output);
+
+	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) &
+		0x0000EFFF);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C);
+	NV_WR32(PRAMDAC, 0x0608, reg608);
+
+	return present;
+}
+
+static void NVSelectHeadRegisters(struct nvidia_par *par, int head)
+{
+	if (head) {
+		par->PCIO = par->PCIO0 + 0x2000;
+		par->PCRTC = par->PCRTC0 + 0x800;
+		par->PRAMDAC = par->PRAMDAC0 + 0x800;
+		par->PDIO = par->PDIO0 + 0x2000;
+	} else {
+		par->PCIO = par->PCIO0;
+		par->PCRTC = par->PCRTC0;
+		par->PRAMDAC = par->PRAMDAC0;
+		par->PDIO = par->PDIO0;
+	}
+}
+
+static void nv4GetConfig(struct nvidia_par *par)
+{
+	if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
+		par->RamAmountKBytes =
+		    ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
+		    1024 * 2;
+	} else {
+		switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
+		case 0:
+			par->RamAmountKBytes = 1024 * 32;
+			break;
+		case 1:
+			par->RamAmountKBytes = 1024 * 4;
+			break;
+		case 2:
+			par->RamAmountKBytes = 1024 * 8;
+			break;
+		case 3:
+		default:
+			par->RamAmountKBytes = 1024 * 16;
+			break;
+		}
+	}
+	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
+	    14318 : 13500;
+	par->CURSOR = &par->PRAMIN[0x1E00];
+	par->MinVClockFreqKHz = 12000;
+	par->MaxVClockFreqKHz = 350000;
+}
+
+static void nv10GetConfig(struct nvidia_par *par)
+{
+	struct pci_dev *dev;
+	u32 implementation = par->Chipset & 0x0ff0;
+
+#ifdef __BIG_ENDIAN
+	/* turn on big endian register access */
+	if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
+		NV_WR32(par->PMC, 0x0004, 0x01000001);
+		mb();
+	}
+#endif
+
+	dev = pci_find_slot(0, 1);
+	if ((par->Chipset && 0xffff) == 0x01a0) {
+		int amt = 0;
+
+		pci_read_config_dword(dev, 0x7c, &amt);
+		par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
+	} else if ((par->Chipset & 0xffff) == 0x01f0) {
+		int amt = 0;
+
+		pci_read_config_dword(dev, 0x84, &amt);
+		par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
+	} else {
+		par->RamAmountKBytes =
+		    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
+	}
+
+	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
+	    14318 : 13500;
+
+	if (par->twoHeads && (implementation != 0x0110)) {
+		if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
+			par->CrystalFreqKHz = 27000;
+	}
+
+	par->CursorStart = (par->RamAmountKBytes - 96) * 1024;
+	par->CURSOR = NULL;	/* can't set this here */
+	par->MinVClockFreqKHz = 12000;
+	par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
+}
+
+void NVCommonSetup(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct fb_var_screeninfo var;
+	u16 implementation = par->Chipset & 0x0ff0;
+	u8 *edidA = NULL, *edidB = NULL;
+	struct fb_monspecs monitorA, monitorB;
+	struct fb_monspecs *monA = NULL, *monB = NULL;
+	int mobile = 0;
+	int tvA = 0;
+	int tvB = 0;
+	int FlatPanel = -1;	/* really means the CRTC is slaved */
+	int Television = 0;
+
+	par->PRAMIN = par->REGS + (0x00710000 / 4);
+	par->PCRTC0 = par->REGS + (0x00600000 / 4);
+	par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
+	par->PFB = par->REGS + (0x00100000 / 4);
+	par->PFIFO = par->REGS + (0x00002000 / 4);
+	par->PGRAPH = par->REGS + (0x00400000 / 4);
+	par->PEXTDEV = par->REGS + (0x00101000 / 4);
+	par->PTIMER = par->REGS + (0x00009000 / 4);
+	par->PMC = par->REGS + (0x00000000 / 4);
+	par->FIFO = par->REGS + (0x00800000 / 4);
+
+	/* 8 bit registers */
+	par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
+	par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
+	par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
+
+	par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
+	    (implementation != 0x0100) &&
+	    (implementation != 0x0150) &&
+	    (implementation != 0x01A0) && (implementation != 0x0200);
+
+	par->fpScaler = (par->FpScale && par->twoHeads &&
+			 (implementation != 0x0110));
+
+	par->twoStagePLL = (implementation == 0x0310) ||
+	    (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
+
+	par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
+	    (implementation != 0x0100);
+
+	par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
+
+	/* look for known laptop chips */
+	switch (par->Chipset & 0xffff) {
+	case 0x0112:
+	case 0x0174:
+	case 0x0175:
+	case 0x0176:
+	case 0x0177:
+	case 0x0179:
+	case 0x017C:
+	case 0x017D:
+	case 0x0186:
+	case 0x0187:
+	case 0x018D:
+	case 0x0286:
+	case 0x028C:
+	case 0x0316:
+	case 0x0317:
+	case 0x031A:
+	case 0x031B:
+	case 0x031C:
+	case 0x031D:
+	case 0x031E:
+	case 0x031F:
+	case 0x0324:
+	case 0x0325:
+	case 0x0328:
+	case 0x0329:
+	case 0x032C:
+	case 0x032D:
+	case 0x0347:
+	case 0x0348:
+	case 0x0349:
+	case 0x034B:
+	case 0x034C:
+	case 0x0160:
+	case 0x0166:
+	case 0x00C8:
+	case 0x00CC:
+	case 0x0144:
+	case 0x0146:
+	case 0x0147:
+	case 0x0148:
+		mobile = 1;
+		break;
+	default:
+		break;
+	}
+
+	if (par->Architecture == NV_ARCH_04)
+		nv4GetConfig(par);
+	else
+		nv10GetConfig(par);
+
+	NVSelectHeadRegisters(par, 0);
+
+	NVLockUnlock(par, 0);
+
+	par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
+
+	par->Television = 0;
+
+	nvidia_create_i2c_busses(par);
+	if (!par->twoHeads) {
+		par->CRTCnumber = 0;
+		nvidia_probe_i2c_connector(par, 1, &edidA);
+		if (edidA && !fb_parse_edid(edidA, &var)) {
+			printk("nvidiafb: EDID found from BUS1\n");
+			monA = &monitorA;
+			fb_edid_to_monspecs(edidA, monA);
+			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
+
+			/* NV4 doesn't support FlatPanels */
+			if ((par->Chipset & 0x0fff) <= 0x0020)
+				FlatPanel = 0;
+		} else {
+			VGA_WR08(par->PCIO, 0x03D4, 0x28);
+			if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
+				VGA_WR08(par->PCIO, 0x03D4, 0x33);
+				if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
+					Television = 1;
+				FlatPanel = 1;
+			} else {
+				FlatPanel = 0;
+			}
+			printk("nvidiafb: HW is currently programmed for %s\n",
+			       FlatPanel ? (Television ? "TV" : "DFP") :
+			       "CRT");
+		}
+
+		if (par->FlatPanel == -1) {
+			par->FlatPanel = FlatPanel;
+			par->Television = Television;
+		} else {
+			printk("nvidiafb: Forcing display type to %s as "
+			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
+		}
+	} else {
+		u8 outputAfromCRTC, outputBfromCRTC;
+		int CRTCnumber = -1;
+		u8 slaved_on_A, slaved_on_B;
+		int analog_on_A, analog_on_B;
+		u32 oldhead;
+		u8 cr44;
+
+		if (implementation != 0x0110) {
+			if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
+				outputAfromCRTC = 1;
+			else
+				outputAfromCRTC = 0;
+			if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
+				outputBfromCRTC = 1;
+			else
+				outputBfromCRTC = 0;
+			analog_on_A = NVIsConnected(par, 0);
+			analog_on_B = NVIsConnected(par, 1);
+		} else {
+			outputAfromCRTC = 0;
+			outputBfromCRTC = 1;
+			analog_on_A = 0;
+			analog_on_B = 0;
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		cr44 = VGA_RD08(par->PCIO, 0x03D5);
+
+		VGA_WR08(par->PCIO, 0x03D5, 3);
+		NVSelectHeadRegisters(par, 1);
+		NVLockUnlock(par, 0);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x28);
+		slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
+		if (slaved_on_B) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x33);
+			tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, 0);
+		NVSelectHeadRegisters(par, 0);
+		NVLockUnlock(par, 0);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x28);
+		slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
+		if (slaved_on_A) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x33);
+			tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
+		}
+
+		oldhead = NV_RD32(par->PCRTC0, 0x00000860);
+		NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
+
+		nvidia_probe_i2c_connector(par, 1, &edidA);
+		if (edidA && !fb_parse_edid(edidA, &var)) {
+			printk("nvidiafb: EDID found from BUS1\n");
+			monA = &monitorA;
+			fb_edid_to_monspecs(edidA, monA);
+		}
+
+		nvidia_probe_i2c_connector(par, 2, &edidB);
+		if (edidB && !fb_parse_edid(edidB, &var)) {
+			printk("nvidiafb: EDID found from BUS2\n");
+			monB = &monitorB;
+			fb_edid_to_monspecs(edidB, monB);
+		}
+
+		if (slaved_on_A && !tvA) {
+			CRTCnumber = 0;
+			FlatPanel = 1;
+			printk("nvidiafb: CRTC 0 is currently programmed for "
+			       "DFP\n");
+		} else if (slaved_on_B && !tvB) {
+			CRTCnumber = 1;
+			FlatPanel = 1;
+			printk("nvidiafb: CRTC 1 is currently programmed "
+			       "for DFP\n");
+		} else if (analog_on_A) {
+			CRTCnumber = outputAfromCRTC;
+			FlatPanel = 0;
+			printk("nvidiafb: CRTC %i appears to have a "
+			       "CRT attached\n", CRTCnumber);
+		} else if (analog_on_B) {
+			CRTCnumber = outputBfromCRTC;
+			FlatPanel = 0;
+			printk("nvidiafb: CRTC %i"
+			       "appears to have a "
+			       "CRT attached\n", CRTCnumber);
+		} else if (slaved_on_A) {
+			CRTCnumber = 0;
+			FlatPanel = 1;
+			Television = 1;
+			printk("nvidiafb: CRTC 0 is currently programmed "
+			       "for TV\n");
+		} else if (slaved_on_B) {
+			CRTCnumber = 1;
+			FlatPanel = 1;
+			Television = 1;
+			printk("nvidiafb: CRTC 1 is currently programmed for "
+			       "TV\n");
+		} else if (monA) {
+			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
+		} else if (monB) {
+			FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
+		}
+
+		if (par->FlatPanel == -1) {
+			if (FlatPanel != -1) {
+				par->FlatPanel = FlatPanel;
+				par->Television = Television;
+			} else {
+				printk("nvidiafb: Unable to detect display "
+				       "type...\n");
+				if (mobile) {
+					printk("...On a laptop, assuming "
+					       "DFP\n");
+					par->FlatPanel = 1;
+				} else {
+					printk("...Using default of CRT\n");
+					par->FlatPanel = 0;
+				}
+			}
+		} else {
+			printk("nvidiafb: Forcing display type to %s as "
+			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
+		}
+
+		if (par->CRTCnumber == -1) {
+			if (CRTCnumber != -1)
+				par->CRTCnumber = CRTCnumber;
+			else {
+				printk("nvidiafb: Unable to detect which "
+				       "CRTCNumber...\n");
+				if (par->FlatPanel)
+					par->CRTCnumber = 1;
+				else
+					par->CRTCnumber = 0;
+				printk("...Defaulting to CRTCNumber %i\n",
+				       par->CRTCnumber);
+			}
+		} else {
+			printk("nvidiafb: Forcing CRTCNumber %i as "
+			       "specified\n", par->CRTCnumber);
+		}
+
+		if (monA) {
+			if (((monA->input & FB_DISP_DDI) &&
+			     par->FlatPanel) ||
+			    ((!(monA->input & FB_DISP_DDI)) &&
+			     !par->FlatPanel)) {
+				if (monB) {
+					fb_destroy_modedb(monB->modedb);
+					monB = NULL;
+				}
+			} else {
+				fb_destroy_modedb(monA->modedb);
+				monA = NULL;
+			}
+		}
+
+		if (monB) {
+			if (((monB->input & FB_DISP_DDI) &&
+			     !par->FlatPanel) ||
+			    ((!(monB->input & FB_DISP_DDI)) &&
+			     par->FlatPanel)) {
+				fb_destroy_modedb(monB->modedb);
+				monB = NULL;
+			} else
+				monA = monB;
+		}
+
+		if (implementation == 0x0110)
+			cr44 = par->CRTCnumber * 0x3;
+
+		NV_WR32(par->PCRTC0, 0x00000860, oldhead);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, cr44);
+		NVSelectHeadRegisters(par, par->CRTCnumber);
+	}
+
+	printk("nvidiafb: Using %s on CRTC %i\n",
+	       par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
+	       par->CRTCnumber);
+
+	if (par->FlatPanel && !par->Television) {
+		par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
+		par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
+		par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
+
+		printk("Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
+	}
+
+	if (monA)
+		info->monspecs = *monA;
+
+	kfree(edidA);
+	kfree(edidB);
+}
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nv_type.h
@@ -0,0 +1,174 @@
+#ifndef __NV_TYPE_H__
+#define __NV_TYPE_H__
+
+#include <linux/fb.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#define NV_ARCH_04  0x04
+#define NV_ARCH_10  0x10
+#define NV_ARCH_20  0x20
+#define NV_ARCH_30  0x30
+#define NV_ARCH_40  0x40
+
+#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1)  << (b))
+#define MASKEXPAND(mask) BITMASK(1?mask,0?mask)
+#define SetBF(mask,value) ((value) << (0?mask))
+#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) )
+#define SetBitField(value,from,to) SetBF(to, GetBF(value,from))
+#define SetBit(n) (1<<(n))
+#define Set8Bits(value) ((value)&0xff)
+
+#define V_DBLSCAN  1
+
+typedef struct {
+	int bitsPerPixel;
+	int depth;
+	int displayWidth;
+	int weight;
+} NVFBLayout;
+
+#define NUM_SEQ_REGS		0x05
+#define NUM_CRT_REGS		0x41
+#define NUM_GRC_REGS		0x09
+#define NUM_ATC_REGS		0x15
+
+struct nvidia_par;
+
+struct nvidia_i2c_chan {
+	struct nvidia_par *par;
+	unsigned long ddc_base;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+};
+
+typedef struct _riva_hw_state {
+	u8 attr[NUM_ATC_REGS];
+	u8 crtc[NUM_CRT_REGS];
+	u8 gra[NUM_GRC_REGS];
+	u8 seq[NUM_SEQ_REGS];
+	u8 misc_output;
+	u32 bpp;
+	u32 width;
+	u32 height;
+	u32 interlace;
+	u32 repaint0;
+	u32 repaint1;
+	u32 screen;
+	u32 scale;
+	u32 dither;
+	u32 extra;
+	u32 fifo;
+	u32 pixel;
+	u32 horiz;
+	u32 arbitration0;
+	u32 arbitration1;
+	u32 pll;
+	u32 pllB;
+	u32 vpll;
+	u32 vpll2;
+	u32 vpllB;
+	u32 vpll2B;
+	u32 pllsel;
+	u32 general;
+	u32 crtcOwner;
+	u32 head;
+	u32 head2;
+	u32 config;
+	u32 cursorConfig;
+	u32 cursor0;
+	u32 cursor1;
+	u32 cursor2;
+	u32 timingH;
+	u32 timingV;
+	u32 displayV;
+	u32 crtcSync;
+} RIVA_HW_STATE;
+
+struct riva_regs {
+	RIVA_HW_STATE ext;
+};
+
+struct nvidia_par {
+	RIVA_HW_STATE SavedReg;
+	RIVA_HW_STATE ModeReg;
+	RIVA_HW_STATE *CurrentState;
+	u32 pseudo_palette[16];
+	struct pci_dev *pci_dev;
+	u32 Architecture;
+	u32 CursorStart;
+	int Chipset;
+	int bus;
+	unsigned long FbAddress;
+	u8 __iomem *FbStart;
+	u32 FbMapSize;
+	u32 FbUsableSize;
+	u32 ScratchBufferSize;
+	u32 ScratchBufferStart;
+	int FpScale;
+	u32 MinVClockFreqKHz;
+	u32 MaxVClockFreqKHz;
+	u32 CrystalFreqKHz;
+	u32 RamAmountKBytes;
+	u32 IOBase;
+	NVFBLayout CurrentLayout;
+	int cursor_reset;
+	int lockup;
+	int videoKey;
+	int FlatPanel;
+	int FPDither;
+	int Television;
+	int CRTCnumber;
+	int alphaCursor;
+	int twoHeads;
+	int twoStagePLL;
+	int fpScaler;
+	int fpWidth;
+	int fpHeight;
+	int PanelTweak;
+	int paneltweak;
+	u32 crtcSync_read;
+	u32 fpSyncs;
+	u32 dmaPut;
+	u32 dmaCurrent;
+	u32 dmaFree;
+	u32 dmaMax;
+	u32 __iomem *dmaBase;
+	u32 currentRop;
+	int WaitVSyncPossible;
+	int BlendingPossible;
+	u32 paletteEnabled;
+	u32 forceCRTC;
+	u8 DDCBase;
+#ifdef CONFIG_MTRR
+	struct {
+		int vram;
+		int vram_valid;
+	} mtrr;
+#endif
+	struct nvidia_i2c_chan chan[3];
+
+	volatile u32 __iomem *REGS;
+	volatile u32 __iomem *PCRTC0;
+	volatile u32 __iomem *PCRTC;
+	volatile u32 __iomem *PRAMDAC0;
+	volatile u32 __iomem *PFB;
+	volatile u32 __iomem *PFIFO;
+	volatile u32 __iomem *PGRAPH;
+	volatile u32 __iomem *PEXTDEV;
+	volatile u32 __iomem *PTIMER;
+	volatile u32 __iomem *PMC;
+	volatile u32 __iomem *PRAMIN;
+	volatile u32 __iomem *FIFO;
+	volatile u32 __iomem *CURSOR;
+	volatile u8 __iomem *PCIO0;
+	volatile u8 __iomem *PCIO;
+	volatile u8 __iomem *PVIO;
+	volatile u8 __iomem *PDIO0;
+	volatile u8 __iomem *PDIO;
+	volatile u32 __iomem *PRAMDAC;
+};
+
+#endif				/* __NV_TYPE_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/nvidia/nvidia.c
@@ -0,0 +1,1745 @@
+/*
+ * linux/drivers/video/nvidia/nvidia.c - nVidia fb driver
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ *
+ * 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/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/pci.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+#include "nv_dma.h"
+
+#ifndef CONFIG_PCI		/* sanity check */
+#error This driver requires PCI support.
+#endif
+
+#undef CONFIG_FB_NVIDIA_DEBUG
+#ifdef CONFIG_FB_NVIDIA_DEBUG
+#define NVTRACE          printk
+#else
+#define NVTRACE          if (0) printk
+#endif
+
+#define NVTRACE_ENTER(...)  NVTRACE("%s START\n", __FUNCTION__)
+#define NVTRACE_LEAVE(...)  NVTRACE("%s END\n", __FUNCTION__)
+
+#ifdef CONFIG_FB_NVIDIA_DEBUG
+#define assert(expr) \
+	if (!(expr)) { \
+	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+	#expr,__FILE__,__FUNCTION__,__LINE__); \
+	BUG(); \
+	}
+#else
+#define assert(expr)
+#endif
+
+#define PFX "nvidiafb: "
+
+/* HW cursor parameters */
+#define MAX_CURS		32
+
+static struct pci_device_id nvidiafb_pci_tbl[] = {
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0252,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0313,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0316,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0317,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031D,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031E,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0329,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x032F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0345,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0349,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x034B,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x034F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x00c0,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x00cd,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0142,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0143,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0144,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0145,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0146,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0147,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0148,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0149,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x014b,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x14c,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x014d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0160,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0162,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0163,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0165,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0169,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016b,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016c,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016e,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0210,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x021d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x021e,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0220,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0221,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0222,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0228,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}			/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
+
+/* command line data, set in nvidiafb_setup() */
+static int flatpanel __devinitdata = -1;	/* Autodetect later */
+static int forceCRTC __devinitdata = -1;
+static int hwcur __devinitdata = 0;
+static int noaccel __devinitdata = 0;
+static int noscale __devinitdata = 0;
+static int paneltweak __devinitdata = 0;
+static int vram __devinitdata = 0;
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata = 0;
+#endif
+
+static char *mode_option __devinitdata = NULL;
+
+static struct fb_fix_screeninfo __devinitdata nvidiafb_fix = {
+	.type = FB_TYPE_PACKED_PIXELS,
+	.xpanstep = 8,
+	.ypanstep = 1,
+};
+
+static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
+	.xres = 640,
+	.yres = 480,
+	.xres_virtual = 640,
+	.yres_virtual = 480,
+	.bits_per_pixel = 8,
+	.red = {0, 8, 0},
+	.green = {0, 8, 0},
+	.blue = {0, 8, 0},
+	.transp = {0, 0, 0},
+	.activate = FB_ACTIVATE_NOW,
+	.height = -1,
+	.width = -1,
+	.pixclock = 39721,
+	.left_margin = 40,
+	.right_margin = 24,
+	.upper_margin = 32,
+	.lower_margin = 11,
+	.hsync_len = 96,
+	.vsync_len = 2,
+	.vmode = FB_VMODE_NONINTERLACED
+};
+
+/*
+ * Backlight control
+ */
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+static int nvidia_backlight_levels[] = {
+	0x158,
+	0x192,
+	0x1c6,
+	0x200,
+	0x234,
+	0x268,
+	0x2a2,
+	0x2d6,
+	0x310,
+	0x344,
+	0x378,
+	0x3b2,
+	0x3e6,
+	0x41a,
+	0x454,
+	0x534,
+};
+
+/* ------------------------------------------------------------------------- *
+ *
+ * Backlight operations
+ *
+ * ------------------------------------------------------------------------- */
+
+static int nvidia_set_backlight_enable(int on, int level, void *data)
+{
+	struct nvidia_par *par = (struct nvidia_par *)data;
+	u32 tmp_pcrt, tmp_pmc, fpcontrol;
+
+	tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+	tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+	fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+	if (on && (level > BACKLIGHT_OFF)) {
+		tmp_pcrt |= 0x1;
+		tmp_pmc |= (1 << 31);	// backlight bit
+		tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
+	}
+
+	if (on)
+		fpcontrol |= par->fpSyncs;
+	else
+		fpcontrol |= 0x20000022;
+
+	NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+	NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+	NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+	return 0;
+}
+
+static int nvidia_set_backlight_level(int level, void *data)
+{
+	return nvidia_set_backlight_enable(1, level, data);
+}
+
+static struct backlight_controller nvidia_backlight_controller = {
+	nvidia_set_backlight_enable,
+	nvidia_set_backlight_level
+};
+
+#endif				/* CONFIG_PMAC_BACKLIGHT */
+
+static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
+				       u16 bg, u16 fg, u32 w, u32 h)
+{
+	int i, j, k = 0;
+	u32 b, tmp;
+	u32 *data = (u32 *) data8;
+
+	w = (w + 1) & ~1;
+
+	for (i = 0; i < h; i++) {
+		b = *data++;
+		reverse_order(&b);
+
+		for (j = 0; j < w / 2; j++) {
+			tmp = 0;
+#if defined (__BIG_ENDIAN)
+			tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
+			b <<= 1;
+			tmp |= (b & (1 << 31)) ? fg : bg;
+			b <<= 1;
+#else
+			tmp = (b & 1) ? fg : bg;
+			b >>= 1;
+			tmp |= (b & 1) ? fg << 16 : bg << 16;
+			b >>= 1;
+#endif
+			NV_WR32(&par->CURSOR[k++], 0, tmp);
+		}
+		k += (MAX_CURS - w) / 2;
+	}
+}
+
+static void nvidia_write_clut(struct nvidia_par *par,
+			      u8 regnum, u8 red, u8 green, u8 blue)
+{
+	NVWriteDacMask(par, 0xff);
+	NVWriteDacWriteAddr(par, regnum);
+	NVWriteDacData(par, red);
+	NVWriteDacData(par, green);
+	NVWriteDacData(par, blue);
+}
+
+static void nvidia_read_clut(struct nvidia_par *par,
+			     u8 regnum, u8 * red, u8 * green, u8 * blue)
+{
+	NVWriteDacMask(par, 0xff);
+	NVWriteDacReadAddr(par, regnum);
+	*red = NVReadDacData(par);
+	*green = NVReadDacData(par);
+	*blue = NVReadDacData(par);
+}
+
+static int nvidia_panel_tweak(struct nvidia_par *par,
+			      struct _riva_hw_state *state)
+{
+	int tweak = 0;
+
+   if (par->paneltweak) {
+	   tweak = par->paneltweak;
+   } else {
+	   /* begin flat panel hacks */
+	   /* This is unfortunate, but some chips need this register
+	      tweaked or else you get artifacts where adjacent pixels are
+	      swapped.  There are no hard rules for what to set here so all
+	      we can do is experiment and apply hacks. */
+
+	   if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
+		   /* At least one NV34 laptop needs this workaround. */
+		   tweak = -1;
+	   }
+
+	   if((par->Chipset & 0xfff0) == 0x0310) {
+		   tweak = 1;
+	   }
+	   /* end flat panel hacks */
+   }
+
+   return tweak;
+}
+
+static void nvidia_save_vga(struct nvidia_par *par,
+			    struct _riva_hw_state *state)
+{
+	int i;
+
+	NVTRACE_ENTER();
+	NVLockUnlock(par, 0);
+
+	NVUnloadStateExt(par, state);
+
+	state->misc_output = NVReadMiscOut(par);
+
+	for (i = 0; i < NUM_CRT_REGS; i++)
+		state->crtc[i] = NVReadCrtc(par, i);
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		state->attr[i] = NVReadAttr(par, i);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		state->gra[i] = NVReadGr(par, i);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		state->seq[i] = NVReadSeq(par, i);
+	NVTRACE_LEAVE();
+}
+
+static void nvidia_write_regs(struct nvidia_par *par)
+{
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i;
+
+	NVTRACE_ENTER();
+	NVWriteCrtc(par, 0x11, 0x00);
+
+	NVLockUnlock(par, 0);
+
+	NVLoadStateExt(par, state);
+
+	NVWriteMiscOut(par, state->misc_output);
+
+	for (i = 0; i < NUM_CRT_REGS; i++) {
+		switch (i) {
+		case 0x19:
+		case 0x20 ... 0x40:
+			break;
+		default:
+			NVWriteCrtc(par, i, state->crtc[i]);
+		}
+	}
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		NVWriteAttr(par, i, state->attr[i]);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		NVWriteGr(par, i, state->gra[i]);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		NVWriteSeq(par, i, state->seq[i]);
+	NVTRACE_LEAVE();
+}
+
+static int nvidia_calc_regs(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i, depth = fb_get_color_depth(&info->var);
+	int h_display = info->var.xres / 8 - 1;
+	int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
+	int h_end = (info->var.xres + info->var.right_margin +
+		     info->var.hsync_len) / 8 - 1;
+	int h_total = (info->var.xres + info->var.right_margin +
+		       info->var.hsync_len + info->var.left_margin) / 8 - 5;
+	int h_blank_s = h_display;
+	int h_blank_e = h_total + 4;
+	int v_display = info->var.yres - 1;
+	int v_start = info->var.yres + info->var.lower_margin - 1;
+	int v_end = (info->var.yres + info->var.lower_margin +
+		     info->var.vsync_len) - 1;
+	int v_total = (info->var.yres + info->var.lower_margin +
+		       info->var.vsync_len + info->var.upper_margin) - 2;
+	int v_blank_s = v_display;
+	int v_blank_e = v_total + 1;
+
+	/*
+	 * Set all CRTC values.
+	 */
+
+	if (info->var.vmode & FB_VMODE_INTERLACED)
+		v_total |= 1;
+
+	if (par->FlatPanel == 1) {
+		v_start = v_total - 3;
+		v_end = v_total - 2;
+		v_blank_s = v_start;
+		h_start = h_total - 5;
+		h_end = h_total - 2;
+		h_blank_e = h_total + 4;
+	}
+
+	state->crtc[0x0] = Set8Bits(h_total);
+	state->crtc[0x1] = Set8Bits(h_display);
+	state->crtc[0x2] = Set8Bits(h_blank_s);
+	state->crtc[0x3] = SetBitField(h_blank_e, 4: 0, 4:0)
+		| SetBit(7);
+	state->crtc[0x4] = Set8Bits(h_start);
+	state->crtc[0x5] = SetBitField(h_blank_e, 5: 5, 7:7)
+		| SetBitField(h_end, 4: 0, 4:0);
+	state->crtc[0x6] = SetBitField(v_total, 7: 0, 7:0);
+	state->crtc[0x7] = SetBitField(v_total, 8: 8, 0:0)
+		| SetBitField(v_display, 8: 8, 1:1)
+		| SetBitField(v_start, 8: 8, 2:2)
+		| SetBitField(v_blank_s, 8: 8, 3:3)
+		| SetBit(4)
+		| SetBitField(v_total, 9: 9, 5:5)
+		| SetBitField(v_display, 9: 9, 6:6)
+		| SetBitField(v_start, 9: 9, 7:7);
+	state->crtc[0x9] = SetBitField(v_blank_s, 9: 9, 5:5)
+		| SetBit(6)
+		| ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0x00);
+	state->crtc[0x10] = Set8Bits(v_start);
+	state->crtc[0x11] = SetBitField(v_end, 3: 0, 3:0) | SetBit(5);
+	state->crtc[0x12] = Set8Bits(v_display);
+	state->crtc[0x13] = ((info->var.xres_virtual / 8) *
+			     (info->var.bits_per_pixel / 8));
+	state->crtc[0x15] = Set8Bits(v_blank_s);
+	state->crtc[0x16] = Set8Bits(v_blank_e);
+
+	state->attr[0x10] = 0x01;
+
+	if (par->Television)
+		state->attr[0x11] = 0x00;
+
+	state->screen = SetBitField(h_blank_e, 6: 6, 4:4)
+		| SetBitField(v_blank_s, 10: 10, 3:3)
+		| SetBitField(v_start, 10: 10, 2:2)
+		| SetBitField(v_display, 10: 10, 1:1)
+		| SetBitField(v_total, 10: 10, 0:0);
+
+	state->horiz = SetBitField(h_total, 8: 8, 0:0)
+		| SetBitField(h_display, 8: 8, 1:1)
+		| SetBitField(h_blank_s, 8: 8, 2:2)
+		| SetBitField(h_start, 8: 8, 3:3);
+
+	state->extra = SetBitField(v_total, 11: 11, 0:0)
+		| SetBitField(v_display, 11: 11, 2:2)
+		| SetBitField(v_start, 11: 11, 4:4)
+		| SetBitField(v_blank_s, 11: 11, 6:6);
+
+	if (info->var.vmode & FB_VMODE_INTERLACED) {
+		h_total = (h_total >> 1) & ~1;
+		state->interlace = Set8Bits(h_total);
+		state->horiz |= SetBitField(h_total, 8: 8, 4:4);
+	} else {
+		state->interlace = 0xff;	/* interlace off */
+	}
+
+	/*
+	 * Calculate the extended registers.
+	 */
+
+	if (depth < 24)
+		i = depth;
+	else
+		i = 32;
+
+	if (par->Architecture >= NV_ARCH_10)
+		par->CURSOR = (volatile u32 __iomem *)(info->screen_base +
+						       par->CursorStart);
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		state->misc_output &= ~0x40;
+	else
+		state->misc_output |= 0x40;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		state->misc_output &= ~0x80;
+	else
+		state->misc_output |= 0x80;
+
+	NVCalcStateExt(par, state, i, info->var.xres_virtual,
+		       info->var.xres, info->var.yres_virtual,
+		       1000000000 / info->var.pixclock, info->var.vmode);
+
+	state->scale = NV_RD32(par->PRAMDAC, 0x00000848) & 0xfff000ff;
+	if (par->FlatPanel == 1) {
+		state->pixel |= (1 << 7);
+
+		if (!par->fpScaler || (par->fpWidth <= info->var.xres)
+		    || (par->fpHeight <= info->var.yres)) {
+			state->scale |= (1 << 8);
+		}
+
+		if (!par->crtcSync_read) {
+			state->crtcSync = NV_RD32(par->PRAMDAC, 0x0828);
+			par->crtcSync_read = 1;
+		}
+
+		par->PanelTweak = nvidia_panel_tweak(par, state);
+	}
+
+	state->vpll = state->pll;
+	state->vpll2 = state->pll;
+	state->vpllB = state->pllB;
+	state->vpll2B = state->pllB;
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	state->fifo = VGA_RD08(par->PCIO, 0x03D5) & ~(1<<5);
+
+	if (par->CRTCnumber) {
+		state->head = NV_RD32(par->PCRTC0, 0x00000860) & ~0x00001000;
+		state->head2 = NV_RD32(par->PCRTC0, 0x00002860) | 0x00001000;
+		state->crtcOwner = 3;
+		state->pllsel |= 0x20000800;
+		state->vpll = NV_RD32(par->PRAMDAC0, 0x00000508);
+		if (par->twoStagePLL)
+			state->vpllB = NV_RD32(par->PRAMDAC0, 0x00000578);
+	} else if (par->twoHeads) {
+		state->head = NV_RD32(par->PCRTC0, 0x00000860) | 0x00001000;
+		state->head2 = NV_RD32(par->PCRTC0, 0x00002860) & ~0x00001000;
+		state->crtcOwner = 0;
+		state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
+		if (par->twoStagePLL)
+			state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
+	}
+
+	state->cursorConfig = 0x00000100;
+
+	if (info->var.vmode & FB_VMODE_DOUBLE)
+		state->cursorConfig |= (1 << 4);
+
+	if (par->alphaCursor) {
+		if ((par->Chipset & 0x0ff0) != 0x0110)
+			state->cursorConfig |= 0x04011000;
+		else
+			state->cursorConfig |= 0x14011000;
+		state->general |= (1 << 29);
+	} else
+		state->cursorConfig |= 0x02000000;
+
+	if (par->twoHeads) {
+		if ((par->Chipset & 0x0ff0) == 0x0110) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x0528) &
+			    ~0x00010000;
+			if (par->FPDither)
+				state->dither |= 0x00010000;
+		} else {
+			state->dither = NV_RD32(par->PRAMDAC, 0x083C) & ~1;
+			if (par->FPDither)
+				state->dither |= 1;
+		}
+	}
+
+	state->timingH = 0;
+	state->timingV = 0;
+	state->displayV = info->var.xres;
+
+	return 0;
+}
+
+static void nvidia_init_vga(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i;
+
+	for (i = 0; i < 0x10; i++)
+		state->attr[i] = i;
+	state->attr[0x10] = 0x41;
+	state->attr[0x11] = 0x01;
+	state->attr[0x12] = 0x0f;
+	state->attr[0x13] = 0x00;
+	state->attr[0x14] = 0x00;
+
+	memset(state->crtc, 0x00, NUM_CRT_REGS);
+	state->crtc[0x0a] = 0x20;
+	state->crtc[0x17] = 0xe3;
+	state->crtc[0x18] = 0xff;
+	state->crtc[0x28] = 0x40;
+
+	memset(state->gra, 0x00, NUM_GRC_REGS);
+	state->gra[0x05] = 0x40;
+	state->gra[0x06] = 0x05;
+	state->gra[0x07] = 0x0f;
+	state->gra[0x08] = 0xff;
+
+	state->seq[0x00] = 0x03;
+	state->seq[0x01] = 0x01;
+	state->seq[0x02] = 0x0f;
+	state->seq[0x03] = 0x00;
+	state->seq[0x04] = 0x0e;
+
+	state->misc_output = 0xeb;
+}
+
+static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct nvidia_par *par = info->par;
+	u8 data[MAX_CURS * MAX_CURS / 8];
+	u16 fg, bg;
+	int i, set = cursor->set;
+
+	if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+		return soft_cursor(info, cursor);
+
+	NVShowHideCursor(par, 0);
+
+	if (par->cursor_reset) {
+		set = FB_CUR_SETALL;
+		par->cursor_reset = 0;
+	}
+
+	if (set & FB_CUR_SETSIZE)
+		memset_io(par->CURSOR, 0, MAX_CURS * MAX_CURS * 2);
+
+	if (set & FB_CUR_SETPOS) {
+		u32 xx, yy, temp;
+
+		yy = cursor->image.dy - info->var.yoffset;
+		xx = cursor->image.dx - info->var.xoffset;
+		temp = xx & 0xFFFF;
+		temp |= yy << 16;
+
+		NV_WR32(par->PRAMDAC, 0x0000300, temp);
+	}
+
+	if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+		u32 bg_idx = cursor->image.bg_color;
+		u32 fg_idx = cursor->image.fg_color;
+		u32 s_pitch = (cursor->image.width + 7) >> 3;
+		u32 d_pitch = MAX_CURS / 8;
+		u8 *dat = (u8 *) cursor->image.data;
+		u8 *msk = (u8 *) cursor->mask;
+		u8 *src;
+
+		src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC);
+
+		if (src) {
+			switch (cursor->rop) {
+			case ROP_XOR:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] ^ msk[i];
+				break;
+			case ROP_COPY:
+			default:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] & msk[i];
+				break;
+			}
+
+			fb_sysmove_buf_aligned(info, &info->pixmap, data,
+					       d_pitch, src, s_pitch,
+					       cursor->image.height);
+
+			bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+			    ((info->cmap.green[bg_idx] & 0xf8) << 2) |
+			    ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | 1 << 15;
+
+			fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+			    ((info->cmap.green[fg_idx] & 0xf8) << 2) |
+			    ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
+
+			NVLockUnlock(par, 0);
+
+			nvidiafb_load_cursor_image(par, data, bg, fg,
+						   cursor->image.width,
+						   cursor->image.height);
+			kfree(src);
+		}
+	}
+
+	if (cursor->enable)
+		NVShowHideCursor(par, 1);
+
+	return 0;
+}
+
+static int nvidiafb_set_par(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+
+	NVTRACE_ENTER();
+
+	NVLockUnlock(par, 1);
+	if (!par->FlatPanel || (info->var.bits_per_pixel != 24) ||
+	    !par->twoHeads)
+		par->FPDither = 0;
+
+	nvidia_init_vga(info);
+	nvidia_calc_regs(info);
+	nvidia_write_regs(par);
+
+	NVLockUnlock(par, 0);
+	if (par->twoHeads) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, par->ModeReg.crtcOwner);
+		NVLockUnlock(par, 0);
+	}
+
+	NVWriteCrtc(par, 0x11, 0x00);
+	info->fix.line_length = (info->var.xres_virtual *
+				 info->var.bits_per_pixel) >> 3;
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+	    FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	if (info->var.accel_flags) {
+		info->fbops->fb_imageblit = nvidiafb_imageblit;
+		info->fbops->fb_fillrect = nvidiafb_fillrect;
+		info->fbops->fb_copyarea = nvidiafb_copyarea;
+		info->fbops->fb_sync = nvidiafb_sync;
+		info->pixmap.scan_align = 4;
+		info->flags &= ~FBINFO_HWACCEL_DISABLED;
+		NVResetGraphics(info);
+	} else {
+		info->fbops->fb_imageblit = cfb_imageblit;
+		info->fbops->fb_fillrect = cfb_fillrect;
+		info->fbops->fb_copyarea = cfb_copyarea;
+		info->fbops->fb_sync = NULL;
+		info->pixmap.scan_align = 1;
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+	}
+
+	par->cursor_reset = 1;
+
+	NVWriteCrtc(par, 0x11, 0xff);
+
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int nvidiafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	int i;
+
+	NVTRACE_ENTER();
+	if (regno >= (1 << info->var.green.length))
+		return -EINVAL;
+
+	if (info->var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		((u32 *) info->pseudo_palette)[regno] =
+		    (regno << info->var.red.offset) |
+		    (regno << info->var.green.offset) |
+		    (regno << info->var.blue.offset);
+	}
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* "transparent" stuff is completely ignored. */
+		nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	case 16:
+		if (info->var.green.length == 5) {
+			for (i = 0; i < 8; i++) {
+				nvidia_write_clut(par, regno * 8 + i, red >> 8,
+						  green >> 8, blue >> 8);
+			}
+		} else {
+			u8 r, g, b;
+
+			if (regno < 32) {
+				for (i = 0; i < 8; i++) {
+					nvidia_write_clut(par, regno * 8 + i,
+							  red >> 8, green >> 8,
+							  blue >> 8);
+				}
+			}
+
+			nvidia_read_clut(par, regno * 4, &r, &g, &b);
+
+			for (i = 0; i < 4; i++)
+				nvidia_write_clut(par, regno * 4 + i, r,
+						  green >> 8, b);
+		}
+		break;
+	case 32:
+		nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int nvidiafb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	int memlen, vramlen, mode_valid = 0;
+	int pitch, err = 0;
+
+	NVTRACE_ENTER();
+
+	var->transp.offset = 0;
+	var->transp.length = 0;
+
+	var->xres &= ~7;
+
+	if (var->bits_per_pixel <= 8)
+		var->bits_per_pixel = 8;
+	else if (var->bits_per_pixel <= 16)
+		var->bits_per_pixel = 16;
+	else
+		var->bits_per_pixel = 32;
+
+	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:
+		var->green.length = (var->green.length < 6) ? 5 : 6;
+		var->red.length = 5;
+		var->blue.length = 5;
+		var->transp.length = 6 - var->green.length;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 5 + var->green.length;
+		var->transp.offset = (5 + var->red.offset) & 15;
+		break;
+	case 32:		/* RGBA 8888 */
+		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.length = 8;
+		var->transp.offset = 24;
+		break;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+		mode_valid = 1;
+
+	/* calculate modeline if supported by monitor */
+	if (!mode_valid && info->monspecs.gtf) {
+		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			mode_valid = 1;
+	}
+
+	if (!mode_valid) {
+		struct fb_videomode *mode;
+
+		mode = fb_find_best_mode(var, &info->modelist);
+		if (mode) {
+			fb_videomode_to_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && info->monspecs.modedb_len)
+		return -EINVAL;
+
+	if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
+					      par->fpHeight < var->yres))
+		return -EINVAL;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	var->xres_virtual = (var->xres_virtual + 63) & ~63;
+
+	vramlen = info->screen_size;
+	pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8;
+	memlen = pitch * var->yres_virtual;
+
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen / pitch;
+
+		if (var->yres_virtual < var->yres) {
+			var->yres_virtual = var->yres;
+			var->xres_virtual = vramlen / var->yres_virtual;
+			var->xres_virtual /= var->bits_per_pixel / 8;
+			var->xres_virtual &= ~63;
+			pitch = (var->xres_virtual *
+				 var->bits_per_pixel + 7) / 8;
+			memlen = pitch * var->yres;
+
+			if (var->xres_virtual < var->xres) {
+				printk("nvidiafb: required video memory, "
+				       "%d bytes, for %dx%d-%d (virtual) "
+				       "is out of range\n",
+				       memlen, var->xres_virtual,
+				       var->yres_virtual, var->bits_per_pixel);
+				err = -ENOMEM;
+			}
+		}
+	}
+
+	if (var->accel_flags) {
+		if (var->yres_virtual > 0x7fff)
+			var->yres_virtual = 0x7fff;
+		if (var->xres_virtual > 0x7fff)
+			var->xres_virtual = 0x7fff;
+	}
+
+	var->xres_virtual &= ~63;
+
+	NVTRACE_LEAVE();
+
+	return err;
+}
+
+static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
+				struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	u32 total;
+
+	total = info->var.yoffset * info->fix.line_length + info->var.xoffset;
+
+	NVSetStartAddress(par, total);
+
+	return 0;
+}
+
+static int nvidiafb_blank(int blank, struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	unsigned char tmp, vesa;
+
+	tmp = NVReadSeq(par, 0x01) & ~0x20;	/* screen on/off */
+	vesa = NVReadCrtc(par, 0x1a) & ~0xc0;	/* sync on/off */
+
+	NVTRACE_ENTER();
+
+	if (blank)
+		tmp |= 0x20;
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		vesa |= 0x80;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		vesa |= 0x40;
+		break;
+	case FB_BLANK_POWERDOWN:
+		vesa |= 0xc0;
+		break;
+	}
+
+	NVWriteSeq(par, 0x01, tmp);
+	NVWriteCrtc(par, 0x1a, vesa);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (par->FlatPanel && _machine == _MACH_Pmac) {
+		set_backlight_enable(!blank);
+	}
+#endif
+
+	NVTRACE_LEAVE();
+
+	return 0;
+}
+
+static struct fb_ops nvidia_fb_ops = {
+	.owner          = THIS_MODULE,
+	.fb_check_var   = nvidiafb_check_var,
+	.fb_set_par     = nvidiafb_set_par,
+	.fb_setcolreg   = nvidiafb_setcolreg,
+	.fb_pan_display = nvidiafb_pan_display,
+	.fb_blank       = nvidiafb_blank,
+	.fb_fillrect    = nvidiafb_fillrect,
+	.fb_copyarea    = nvidiafb_copyarea,
+	.fb_imageblit   = nvidiafb_imageblit,
+	.fb_cursor      = nvidiafb_cursor,
+	.fb_sync        = nvidiafb_sync,
+};
+
+static int __devinit nvidia_set_fbinfo(struct fb_info *info)
+{
+	struct fb_monspecs *specs = &info->monspecs;
+	struct fb_videomode modedb;
+	struct nvidia_par *par = info->par;
+	int lpitch;
+
+	NVTRACE_ENTER();
+	info->flags = FBINFO_DEFAULT
+	    | FBINFO_HWACCEL_IMAGEBLIT
+	    | FBINFO_HWACCEL_FILLRECT
+	    | FBINFO_HWACCEL_COPYAREA
+	    | FBINFO_HWACCEL_YPAN;
+
+	fb_videomode_to_modelist(info->monspecs.modedb,
+				 info->monspecs.modedb_len, &info->modelist);
+	fb_var_to_videomode(&modedb, &nvidiafb_default_var);
+
+	if (specs->modedb != NULL) {
+		/* get preferred timing */
+		if (specs->misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = specs->modedb[0];
+		}
+
+		fb_videomode_to_var(&nvidiafb_default_var, &modedb);
+		nvidiafb_default_var.bits_per_pixel = 8;
+	}
+
+	if (mode_option)
+		fb_find_mode(&nvidiafb_default_var, info, mode_option,
+			     specs->modedb, specs->modedb_len, &modedb, 8);
+
+	info->var = nvidiafb_default_var;
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+	info->pseudo_palette = par->pseudo_palette;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	/* maximize virtual vertical length */
+	lpitch = info->var.xres_virtual *
+		((info->var.bits_per_pixel + 7) >> 3);
+	info->var.yres_virtual = info->screen_size / lpitch;
+
+	info->pixmap.scan_align = 4;
+	info->pixmap.buf_align = 4;
+	info->pixmap.size = 8 * 1024;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+	if (!hwcur)
+		info->fbops->fb_cursor = soft_cursor;
+	info->var.accel_flags = (!noaccel);
+
+	switch (par->Architecture) {
+	case NV_ARCH_04:
+		info->fix.accel = FB_ACCEL_NV4;
+		break;
+	case NV_ARCH_10:
+		info->fix.accel = FB_ACCEL_NV_10;
+		break;
+	case NV_ARCH_20:
+		info->fix.accel = FB_ACCEL_NV_20;
+		break;
+	case NV_ARCH_30:
+		info->fix.accel = FB_ACCEL_NV_30;
+		break;
+	case NV_ARCH_40:
+		info->fix.accel = FB_ACCEL_NV_40;
+		break;
+	}
+
+	NVTRACE_LEAVE();
+
+	return nvidiafb_check_var(&info->var, info);
+}
+
+static u32 __devinit nvidia_get_arch(struct pci_dev *pd)
+{
+	u32 arch = 0;
+
+	switch (pd->device & 0x0ff0) {
+	case 0x0100:		/* GeForce 256 */
+	case 0x0110:		/* GeForce2 MX */
+	case 0x0150:		/* GeForce2 */
+	case 0x0170:		/* GeForce4 MX */
+	case 0x0180:		/* GeForce4 MX (8x AGP) */
+	case 0x01A0:		/* nForce */
+	case 0x01F0:		/* nForce2 */
+		arch = NV_ARCH_10;
+		break;
+	case 0x0200:		/* GeForce3 */
+	case 0x0250:		/* GeForce4 Ti */
+	case 0x0280:		/* GeForce4 Ti (8x AGP) */
+		arch = NV_ARCH_20;
+		break;
+	case 0x0300:		/* GeForceFX 5800 */
+	case 0x0310:		/* GeForceFX 5600 */
+	case 0x0320:		/* GeForceFX 5200 */
+	case 0x0330:		/* GeForceFX 5900 */
+	case 0x0340:		/* GeForceFX 5700 */
+		arch = NV_ARCH_30;
+		break;
+	case 0x0040:
+	case 0x00C0:
+	case 0x0120:
+	case 0x0130:
+	case 0x0140:
+	case 0x0160:
+	case 0x01D0:
+	case 0x0090:
+	case 0x0210:
+	case 0x0220:
+	case 0x0230:
+		arch = NV_ARCH_40;
+		break;
+	case 0x0020:		/* TNT, TNT2 */
+		arch = NV_ARCH_04;
+		break;
+	default:		/* unknown architecture */
+		break;
+	}
+
+	return arch;
+}
+
+static int __devinit nvidiafb_probe(struct pci_dev *pd,
+				    const struct pci_device_id *ent)
+{
+	struct nvidia_par *par;
+	struct fb_info *info;
+	unsigned short cmd;
+
+
+	NVTRACE_ENTER();
+	assert(pd != NULL);
+
+	info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev);
+
+	if (!info)
+		goto err_out;
+
+	par = (struct nvidia_par *)info->par;
+	par->pci_dev = pd;
+
+	info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
+
+	if (info->pixmap.addr == NULL)
+		goto err_out_kfree;
+
+	memset(info->pixmap.addr, 0, 8 * 1024);
+
+	if (pci_enable_device(pd)) {
+		printk(KERN_ERR PFX "cannot enable PCI device\n");
+		goto err_out_enable;
+	}
+
+	if (pci_request_regions(pd, "nvidiafb")) {
+		printk(KERN_ERR PFX "cannot request PCI regions\n");
+		goto err_out_request;
+	}
+
+	par->Architecture = nvidia_get_arch(pd);
+
+	par->Chipset = (pd->vendor << 16) | pd->device;
+	printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
+
+#ifdef CONFIG_PCI_NAMES
+	printk(KERN_INFO PFX "%s\n", pd->pretty_name);
+#endif
+
+	if (par->Architecture == 0) {
+		printk(KERN_ERR PFX "unknown NV_ARCH\n");
+		goto err_out_free_base0;
+	}
+
+	sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
+
+	par->FlatPanel = flatpanel;
+
+	if (flatpanel == 1)
+		printk(KERN_INFO PFX "flatpanel support enabled\n");
+
+	par->CRTCnumber = forceCRTC;
+	par->FpScale = (!noscale);
+	par->paneltweak = paneltweak;
+
+	/* enable IO and mem if not already done */
+	pci_read_config_word(pd, PCI_COMMAND, &cmd);
+	cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_write_config_word(pd, PCI_COMMAND, cmd);
+
+	nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
+	nvidiafb_fix.smem_start = pci_resource_start(pd, 1);
+	nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
+
+	par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
+
+	if (!par->REGS) {
+		printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
+		goto err_out_free_base0;
+	}
+
+	NVCommonSetup(info);
+
+	par->FbAddress = nvidiafb_fix.smem_start;
+	par->FbMapSize = par->RamAmountKBytes * 1024;
+	if (vram && vram * 1024 * 1024 < par->FbMapSize)
+		par->FbMapSize = vram * 1024 * 1024;
+
+	/* Limit amount of vram to 64 MB */
+	if (par->FbMapSize > 64 * 1024 * 1024)
+		par->FbMapSize = 64 * 1024 * 1024;
+
+	par->FbUsableSize = par->FbMapSize - (128 * 1024);
+	par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 :
+	    16 * 1024;
+	par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize;
+	info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize);
+	info->screen_size = par->FbUsableSize;
+	nvidiafb_fix.smem_len = par->RamAmountKBytes * 1024;
+
+	if (!info->screen_base) {
+		printk(KERN_ERR PFX "cannot ioremap FB base\n");
+		goto err_out_free_base1;
+	}
+
+	par->FbStart = info->screen_base;
+
+#ifdef CONFIG_MTRR
+	if (!nomtrr) {
+		par->mtrr.vram = mtrr_add(nvidiafb_fix.smem_start,
+					  par->RamAmountKBytes * 1024,
+					  MTRR_TYPE_WRCOMB, 1);
+		if (par->mtrr.vram < 0) {
+			printk(KERN_ERR PFX "unable to setup MTRR\n");
+		} else {
+			par->mtrr.vram_valid = 1;
+			/* let there be speed */
+			printk(KERN_INFO PFX "MTRR set to ON\n");
+		}
+	}
+#endif				/* CONFIG_MTRR */
+
+	info->fbops = &nvidia_fb_ops;
+	info->fix = nvidiafb_fix;
+
+	if (nvidia_set_fbinfo(info) < 0) {
+		printk(KERN_ERR PFX "error setting initial video mode\n");
+		goto err_out_iounmap_fb;
+	}
+
+	nvidia_save_vga(par, &par->SavedReg);
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
+		goto err_out_iounmap_fb;
+	}
+
+	pci_set_drvdata(pd, info);
+
+	printk(KERN_INFO PFX
+	       "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
+	       info->fix.id,
+	       par->FbMapSize / (1024 * 1024), info->fix.smem_start);
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (par->FlatPanel && _machine == _MACH_Pmac)
+		register_backlight_controller(&nvidia_backlight_controller,
+					      par, "mnca");
+#endif
+	NVTRACE_LEAVE();
+	return 0;
+
+      err_out_iounmap_fb:
+	iounmap(info->screen_base);
+      err_out_free_base1:
+	fb_destroy_modedb(info->monspecs.modedb);
+	nvidia_delete_i2c_busses(par);
+	iounmap(par->REGS);
+      err_out_free_base0:
+	pci_release_regions(pd);
+      err_out_request:
+	pci_disable_device(pd);
+      err_out_enable:
+	kfree(info->pixmap.addr);
+      err_out_kfree:
+	framebuffer_release(info);
+      err_out:
+	return -ENODEV;
+}
+
+static void __exit nvidiafb_remove(struct pci_dev *pd)
+{
+	struct fb_info *info = pci_get_drvdata(pd);
+	struct nvidia_par *par = info->par;
+
+	NVTRACE_ENTER();
+	if (!info)
+		return;
+
+	unregister_framebuffer(info);
+#ifdef CONFIG_MTRR
+	if (par->mtrr.vram_valid)
+		mtrr_del(par->mtrr.vram, info->fix.smem_start,
+			 info->fix.smem_len);
+#endif				/* CONFIG_MTRR */
+
+	iounmap(info->screen_base);
+	fb_destroy_modedb(info->monspecs.modedb);
+	nvidia_delete_i2c_busses(par);
+	iounmap(par->REGS);
+	pci_release_regions(pd);
+	pci_disable_device(pd);
+	kfree(info->pixmap.addr);
+	framebuffer_release(info);
+	pci_set_drvdata(pd, NULL);
+	NVTRACE_LEAVE();
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * initialization
+ *
+ * ------------------------------------------------------------------------- */
+
+#ifndef MODULE
+static int __devinit nvidiafb_setup(char *options)
+{
+	char *this_opt;
+
+	NVTRACE_ENTER();
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "forceCRTC", 9)) {
+			char *p;
+
+			p = this_opt + 9;
+			if (!*p || !*(++p))
+				continue;
+			forceCRTC = *p - '0';
+			if (forceCRTC < 0 || forceCRTC > 1)
+				forceCRTC = -1;
+		} else if (!strncmp(this_opt, "flatpanel", 9)) {
+			flatpanel = 1;
+		} else if (!strncmp(this_opt, "hwcur", 5)) {
+			hwcur = 1;
+		} else if (!strncmp(this_opt, "noaccel", 6)) {
+			noaccel = 1;
+		} else if (!strncmp(this_opt, "noscale", 7)) {
+			noscale = 1;
+		} else if (!strncmp(this_opt, "paneltweak:", 11)) {
+			paneltweak = simple_strtoul(this_opt+11, NULL, 0);
+		} else if (!strncmp(this_opt, "vram:", 5)) {
+			vram = simple_strtoul(this_opt+5, NULL, 0);
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else
+			mode_option = this_opt;
+	}
+	NVTRACE_LEAVE();
+	return 0;
+}
+#endif				/* !MODULE */
+
+static struct pci_driver nvidiafb_driver = {
+	.name = "nvidiafb",
+	.id_table = nvidiafb_pci_tbl,
+	.probe = nvidiafb_probe,
+	.remove = __exit_p(nvidiafb_remove),
+};
+
+/* ------------------------------------------------------------------------- *
+ *
+ * modularization
+ *
+ * ------------------------------------------------------------------------- */
+
+static int __devinit nvidiafb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("nvidiafb", &option))
+		return -ENODEV;
+	nvidiafb_setup(option);
+#endif
+	return pci_register_driver(&nvidiafb_driver);
+}
+
+module_init(nvidiafb_init);
+
+#ifdef MODULE
+static void __exit nvidiafb_exit(void)
+{
+	pci_unregister_driver(&nvidiafb_driver);
+}
+
+module_exit(nvidiafb_exit);
+
+module_param(flatpanel, int, 0);
+MODULE_PARM_DESC(flatpanel,
+		 "Enables experimental flat panel support for some chipsets. "
+		 "(0 or 1=enabled) (default=0)");
+module_param(hwcur, int, 0);
+MODULE_PARM_DESC(hwcur,
+		 "Enables hardware cursor implementation. (0 or 1=enabled) "
+		 "(default=0)");
+module_param(noaccel, int, 0);
+MODULE_PARM_DESC(noaccel,
+		 "Disables hardware acceleration. (0 or 1=disable) "
+		 "(default=0)");
+module_param(noscale, int, 0);
+MODULE_PARM_DESC(noscale,
+		 "Disables screen scaleing. (0 or 1=disable) "
+		 "(default=0, do scaling)");
+module_param(paneltweak, int, 0);
+MODULE_PARM_DESC(paneltweak,
+		 "Tweak display settings for flatpanels. "
+		 "(default=0, no tweaks)");
+module_param(forceCRTC, int, 0);
+MODULE_PARM_DESC(forceCRTC,
+		 "Forces usage of a particular CRTC in case autodetection "
+		 "fails. (0 or 1) (default=autodetect)");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram,
+		 "amount of framebuffer memory to remap in MiB"
+		 "(default=0 - remap entire memory)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
+		 "(default=0)");
+#endif
+
+MODULE_AUTHOR("Antonino Daplas");
+MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset");
+MODULE_LICENSE("GPL");
+#endif				/* MODULE */
+
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -29,6 +29,10 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 
+#ifdef CONFIG_PPC64
+#include <asm/pci-bridge.h>
+#endif
+
 #ifdef CONFIG_PPC32
 #include <asm/bootx.h>
 #endif
@@ -322,7 +326,8 @@ static void __init offb_init_nodriver(st
 	int *pp, i;
 	unsigned int len;
 	int width = 640, height = 480, depth = 8, pitch;
-	unsigned *up, address;
+	unsigned *up;
+	unsigned long address;
 
 	if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
 	    && len == sizeof(int))
@@ -357,6 +362,10 @@ static void __init offb_init_nodriver(st
 
 		address = (u_long) dp->addrs[i].address;
 
+#ifdef CONFIG_PPC64
+		address += dp->phb->pci_mem_offset;
+#endif
+
 		/* kludge for valkyrie */
 		if (strcmp(dp->name, "valkyrie") == 0)
 			address += 0x1000;
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -62,7 +62,7 @@
 /*
  * Driver data 
  */
-static char *mode __initdata = NULL;
+static char *mode __devinitdata = NULL;
 
 /*
  * The XFree GLINT driver will (I think to implement hardware cursor
@@ -73,8 +73,8 @@ static char *mode __initdata = NULL;
  * these flags allow the user to specify that requests for +ve sync
  * should be silently turned in -ve sync.
  */
-static int lowhsync __initdata = 0;
-static int lowvsync __initdata = 0;	
+static int lowhsync __devinitdata = 0;
+static int lowvsync __devinitdata = 0;
 
 /*
  * The hardware state of the graphics card that isn't part of the
@@ -97,7 +97,7 @@ struct pm2fb_par
  * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
  * if we don't use modedb.
  */
-static struct fb_fix_screeninfo pm2fb_fix __initdata = {
+static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
 	.id =		"", 
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_PSEUDOCOLOR,
@@ -110,7 +110,7 @@ static struct fb_fix_screeninfo pm2fb_fi
 /*
  * Default video mode. In case the modedb doesn't work.
  */
-static struct fb_var_screeninfo pm2fb_var __initdata = {
+static struct fb_var_screeninfo pm2fb_var __devinitdata = {
 	/* "640x480, 8 bpp @ 60 Hz */
 	.xres =		640,
 	.yres =		480,
@@ -747,7 +747,7 @@ static int pm2fb_set_par(struct fb_info 
 	}
 	if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
 		video |= PM2F_LINE_DOUBLE;
-	if (info->var.activate==FB_ACTIVATE_NOW)
+	if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW)
 		video |= PM2F_VIDEO_ENABLE;
 	par->video = video;
 
@@ -1243,47 +1243,13 @@ static struct pci_driver pm2fb_driver = 
 MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
 
 
-/*
- *  Initialization
- */
-
-int __init pm2fb_setup(char *options);
-
-int __init pm2fb_init(void)
-{
-#ifndef MODULE
-	char *option = NULL;
-
-	if (fb_get_options("pm2fb", &option))
-		return -ENODEV;
-	pm2fb_setup(option);
-#endif
-
-	return pci_module_init(&pm2fb_driver);
-}
-
-#ifdef MODULE
-/*
- *  Cleanup
- */
-
-static void __exit pm2fb_exit(void)
-{
-	pci_unregister_driver(&pm2fb_driver);
-}
-#endif
-
-/*
- *  Setup
- */
-
 #ifndef MODULE
 /**
  * Parse user speficied options.
  *
  * This is, comma-separated options following `video=pm2fb:'.
  */
-int __init pm2fb_setup(char *options)
+static int __init pm2fb_setup(char *options)
 {
 	char* this_opt;
 
@@ -1306,15 +1272,33 @@ int __init pm2fb_setup(char *options)
 #endif
 
 
-/* ------------------------------------------------------------------------- */
-
-/* ------------------------------------------------------------------------- */
+static int __init pm2fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
 
+	if (fb_get_options("pm2fb", &option))
+		return -ENODEV;
+	pm2fb_setup(option);
+#endif
 
+	return pci_register_driver(&pm2fb_driver);
+}
 
 module_init(pm2fb_init);
 
 #ifdef MODULE
+/*
+ *  Cleanup
+ */
+
+static void __exit pm2fb_exit(void)
+{
+	pci_unregister_driver(&pm2fb_driver);
+}
+#endif
+
+#ifdef MODULE
 module_exit(pm2fb_exit);
 
 module_param(mode, charp, 0);
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -137,9 +137,6 @@ struct pm3fb_info {
 	unsigned long use_current;
 	struct pm3fb_par *current_par;
 	struct pci_dev *dev;    /* PCI device */
-#ifdef SUPPORT_FB_OF
-	struct device_node *dn; /* OF node for the PCI device */
-#endif /* SUPPORT_FB_OF */
 	unsigned long board_type; /* index in the cardbase */
 	unsigned char *fb_base;	/* framebuffer memory base */
 	u32 fb_size;		/* framebuffer memory size */
@@ -665,20 +662,6 @@ static int pm3fb_ioctl(struct inode *ino
 
 
 /* the struct that hold them together */
-#ifdef KERNEL_2_2
-struct fbgen_hwswitch pm3fb_switch = {
-	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
-	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg,
-	pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
-
-static struct fb_ops pm3fb_ops = {
-	fbgen_get_fix, fbgen_get_var, fbgen_set_var,
-	fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl,
-	    NULL, NULL
-};
-#endif /* KERNEL_2_2 */
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 struct fbgen_hwswitch pm3fb_switch = {
 	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
 	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
@@ -697,7 +680,7 @@ static struct fb_ops pm3fb_ops = {
 	.fb_blank =	fbgen_blank,
 	.fb_ioctl =	pm3fb_ioctl,
 };
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
+
 #ifdef PM3FB_USE_ACCEL
 #ifdef FBCON_HAS_CFB32
 static struct display_switch pm3fb_cfb32 = {
@@ -1451,26 +1434,11 @@ static unsigned long pm3fb_size_memory(s
 
 	/* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
 	for (i = 0; i < 32; i++) {
-#ifdef KERNEL_2_2
-#ifdef MUST_BYTESWAP
-		writel(__swab32(i * 0x00345678),
-		       (l_fb_info->v_fb + (i * 1048576)));
-#else
-		writel(i * 0x00345678, (l_fb_info->v_fb + (i * 1048576)));
-#endif
-		mb();
-#ifdef MUST_BYTESWAP
-		temp1 = __swab32(readl((l_fb_info->v_fb + (i * 1048576))));
-#else
-		temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
-#endif
-#endif	/* KERNEL_2_2 */
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 		fb_writel(i * 0x00345678,
 			  (l_fb_info->v_fb + (i * 1048576)));
 		mb();
 		temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
+
 		/* Let's check for wrapover, write will fail at 16MB boundary */
 		if (temp1 == (i * 0x00345678))
 			memsize = i;
@@ -1489,31 +1457,6 @@ static unsigned long pm3fb_size_memory(s
 		}
 
 		for (i = 32; i < 64; i++) {
-#ifdef KERNEL_2_2
-#ifdef MUST_BYTESWAP
-			writel(__swab32(i * 0x00345678),
-			       (l_fb_info->v_fb + (i * 1048576)));
-#else
-			writel(i * 0x00345678,
-			       (l_fb_info->v_fb + (i * 1048576)));
-#endif
-			mb();
-#ifdef MUST_BYTESWAP
-			temp1 =
-			    __swab32(readl
-				     ((l_fb_info->v_fb + (i * 1048576))));
-			temp2 =
-			    __swab32(readl
-				     ((l_fb_info->v_fb +
-				       ((i - 32) * 1048576))));
-#else
-			temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
-			temp2 =
-			    readl((l_fb_info->v_fb +
-				   ((i - 32) * 1048576)));
-#endif
-#endif /* KERNEL_2_2 */
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 			fb_writel(i * 0x00345678,
 				  (l_fb_info->v_fb + (i * 1048576)));
 			mb();
@@ -1522,7 +1465,6 @@ static unsigned long pm3fb_size_memory(s
 			temp2 =
 			    fb_readl((l_fb_info->v_fb +
 				      ((i - 32) * 1048576)));
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
 			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))	/* different value, different RAM... */
 				memsize = i;
 			else
@@ -1565,16 +1507,7 @@ static void pm3fb_clear_memory(struct pm
 
 	for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
 	{
-#ifdef KERNEL_2_2
-#ifdef MUST_BYTESWAP
-		writel(__swab32(cc), (l_fb_info->v_fb + (i * sizeof(u32))));
-#else
-		writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
-#endif
-#endif
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 		fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
-#endif
 	}
 }
 
@@ -3424,89 +3357,63 @@ static void pm3fb_detect(void)
 	for (i = 0; i < PM3_MAX_BOARD; i++) {
 		l_fb_info = &(fb_info[i]);
 		if ((l_fb_info->dev) && (!disable[i])) {	/* PCI device was found and not disabled by user */
-#ifdef SUPPORT_FB_OF
-			struct device_node *dp =
-			    find_pci_device_OFnode(l_fb_info->dev->bus->
-						   number,
-						   l_fb_info->dev->devfn);
-
-			if ((dp) && (!strncmp(dp->name, "formacGA12", 10))) {
-				/* do nothing, init of board is done in pm3fb_of_init */
-			} else {
-#endif
-				DPRINTK(2,
-					"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
-					(unsigned long) l_fb_info->dev,
-					(unsigned long) l_fb_info->dev->
-					vendor,
-					(unsigned long) l_fb_info->dev->
-					device,
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   0),
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   1),
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   2),
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   3),
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   4),
-					(unsigned long)
-					pci_resource_start(l_fb_info->dev,
-							   5),
-					(unsigned long) l_fb_info->dev->
-					irq);
-
-				l_fb_info->pIOBase =
-				    (unsigned char *)
-				    pci_resource_start(l_fb_info->dev, 0);
+			DPRINTK(2,
+				"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
+				(unsigned long) l_fb_info->dev,
+				(unsigned long) l_fb_info->dev->vendor,
+				(unsigned long) l_fb_info->dev->device,
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 0),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 1),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 2),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 3),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 4),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 5),
+				(unsigned long) l_fb_info->dev->irq);
+
+			l_fb_info->pIOBase =
+			    (unsigned char *)
+			    pci_resource_start(l_fb_info->dev, 0);
 #ifdef __BIG_ENDIAN
-				l_fb_info->pIOBase += PM3_REGS_SIZE;
+			l_fb_info->pIOBase += PM3_REGS_SIZE;
 #endif
-				l_fb_info->vIOBase = (unsigned char *) -1;
-				l_fb_info->p_fb =
-				    (unsigned char *)
-				    pci_resource_start(l_fb_info->dev, 1);
-				l_fb_info->v_fb = (unsigned char *) -1;
+			l_fb_info->vIOBase = (unsigned char *) -1;
+			l_fb_info->p_fb =
+			    (unsigned char *)
+			    pci_resource_start(l_fb_info->dev, 1);
+			l_fb_info->v_fb = (unsigned char *) -1;
 
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) 	/* full resource management, new in linux-2.4.x */
-				if (!request_mem_region
-				    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
-				     "pm3fb")) {
-					printk
-					    (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
-					     l_fb_info->board_num);
-					continue;
-				}
 				if (!request_mem_region
-				    ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
-				     "pm3fb I/O regs")) {
-					printk
-					    (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
-					     l_fb_info->board_num);
-					continue;
-				}
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
-				if (forcesize[l_fb_info->board_num])
-					l_fb_info->fb_size = forcesize[l_fb_info->board_num];
-				
-				l_fb_info->fb_size =
-				    pm3fb_size_memory(l_fb_info);
+			    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
+			     "pm3fb")) {
+				printk
+				    (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
+				     l_fb_info->board_num);
+				continue;
+			}
+			if (!request_mem_region
+			    ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
+			     "pm3fb I/O regs")) {
+				printk
+				    (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
+				     l_fb_info->board_num);
+				continue;
+			}
+			if (forcesize[l_fb_info->board_num])
+				l_fb_info->fb_size = forcesize[l_fb_info->board_num];
 
+			l_fb_info->fb_size =
+			    pm3fb_size_memory(l_fb_info);
 				if (l_fb_info->fb_size) {
-					(void) pci_enable_device(l_fb_info->dev);
-					pm3fb_common_init(l_fb_info);
-				} else
-					printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
-				
-#ifdef SUPPORT_FB_OF
-			}
-#endif /* SUPPORT_FB_OF */
+				(void) pci_enable_device(l_fb_info->dev);
+				pm3fb_common_init(l_fb_info);
+			} else
+				printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
 		}
 	}
 }
@@ -3590,12 +3497,7 @@ static int pm3fb_ioctl(struct inode *ino
 /* ***** standard FB API init functions ***** */
 /* ****************************************** */
 
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 int __init pm3fb_setup(char *options)
-#endif
-#ifdef KERNEL_2_2
-__initfunc(void pm3fb_setup(char *options, int *ints))
-#endif
 {
 	long opsi = strlen(options);
 
@@ -3606,17 +3508,10 @@ __initfunc(void pm3fb_setup(char *option
 		PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
 	g_options[PM3_OPTIONS_SIZE - 1] = 0;
 
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 	return (0);
-#endif
 }
 
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 int __init pm3fb_init(void)
-#endif
-#ifdef KERNEL_2_2
-__initfunc(void pm3fb_init(void))
-#endif
 {
 	DTRACE;
 
@@ -3629,82 +3524,8 @@ __initfunc(void pm3fb_init(void))
 	if (!fb_info[0].dev) {	/* not even one board ??? */
 		DPRINTK(1, "No PCI Permedia3 board detected\n");
 	}
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 	return (0);
-#endif
-}
-
-#ifdef SUPPORT_FB_OF		/* linux-2.2.x only */
-__initfunc(void pm3fb_of_init(struct device_node *dp))
-{
-	struct pm3fb_info *l_fb_info = NULL;
-	unsigned long i;
-	long bn = -1;
-	struct device_node *dn;
-
-	DTRACE;
-
-	DPRINTK(2, "OpenFirmware board : %s\n", dp->full_name);
-
-	for (i = 0; i < dp->n_addrs; i++) {
-		DPRINTK(2, "MemRange : 0x%08x - 0x%x\n",
-			dp->addrs[i].address, dp->addrs[i].size);
-	}
-
-	for (i = 0; i < PM3_MAX_BOARD; i++) {	/* find which PCI board is the OF device */
-		if (fb_info[i].dev) {
-			dn = find_pci_device_OFnode(fb_info[i].dev->bus->
-						    number,
-						    fb_info[i].dev->devfn);
-			if (dn == dp) {
-				if (bn == -1)
-					bn = i;
-				else {
-					DPRINTK(1,
-						"Error: Multiple PCI device for a single OpenFirmware node\n");
-				}
-			}
-		}
-	}
-
-	if (bn == -1) {
-		DPRINTK(1, "Warning: non-PCI Permedia3 found\n");
-		i = 0;
-		while (fb_info[i].dev && (i < PM3_MAX_BOARD))
-			i++;
-		if (i < PM3_MAX_BOARD)
-			bn = i;
-		else {
-			printk
-			    (KERN_ERR "pm3fb: Error: Couldn't find room for OpenFirmware device");
-			return;
-		}
-	}
-
-	l_fb_info = &(fb_info[bn]);
-
-	l_fb_info->dn = dp;
-
-	l_fb_info->pIOBase = (unsigned char *) dp->addrs[3].address;
-#ifdef __BIG_ENDIAN
-	l_fb_info->pIOBase += PM3_REGS_SIZE;
-#endif
-	l_fb_info->vIOBase = (unsigned char *) -1;
-	l_fb_info->p_fb = (unsigned char *) dp->addrs[1].address;
-	l_fb_info->v_fb = (unsigned char *) -1;
-
-	l_fb_info->fb_size = pm3fb_size_memory(l_fb_info);	/* (unsigned long)dp->addrs[1].size; *//* OF is a liar ! it claims 256 Mb */
-
-	DPRINTK(2,
-		"OpenFirmware board (#%ld) : IOBase 0x%08lx, p_fb 0x%08lx, fb_size %d KB\n",
-		bn, (unsigned long) l_fb_info->pIOBase,
-		(unsigned long) l_fb_info->p_fb, l_fb_info->fb_size >> 10);
-
-	l_fb_info->use_current = 1;	/* will use current mode by default */
-
-	pm3fb_common_init(l_fb_info);
 }
-#endif /* SUPPORT_FB_OF */
 
 /* ************************* */
 /* **** Module support ***** */
@@ -3808,14 +3629,12 @@ void cleanup_module(void)
 				if (l_fb_info->vIOBase !=
 				    (unsigned char *) -1) {
 					pm3fb_unmapIO(l_fb_info);
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
 					release_mem_region(l_fb_info->p_fb,
 							   l_fb_info->
 							   fb_size);
 					release_mem_region(l_fb_info->
 							   pIOBase,
 							   PM3_REGS_SIZE);
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
 				}
 				unregister_framebuffer(&l_fb_info->gen.
 						       info);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -4,7 +4,7 @@
  * Dreamcast.
  *
  * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org>
- * Copyright (c) 2001, 2002, 2003, 2004 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (c) 2001, 2002, 2003, 2004, 2005 Paul Mundt <lethal@linux-sh.org>
  *
  * This file is part of the LinuxDC project (linuxdc.sourceforge.net).
  *
@@ -33,7 +33,7 @@
  *  Then, when it's time to convert back to hardware settings, the only
  *  constants are the borderstart_* offsets, all other values are derived from
  *  the fb video mode:
- *  
+ *
  *      // PAL
  *      borderstart_h = 116;
  *      borderstart_v = 44;
@@ -939,7 +939,8 @@ static int __devinit pvr2fb_pci_probe(st
 
 	pvr2_fix.mmio_start	= pci_resource_start(pdev, 1);
 	pvr2_fix.mmio_len	= pci_resource_len(pdev, 1);
-	fbinfo->device = &pdev->dev;
+
+	fb_info->device		= &pdev->dev;
 
 	return pvr2fb_common_init();
 }
@@ -966,7 +967,7 @@ static struct pci_driver pvr2fb_pci_driv
 
 static int __init pvr2fb_pci_init(void)
 {
-	return pci_module_init(&pvr2fb_pci_driver);
+	return pci_register_driver(&pvr2fb_pci_driver);
 }
 
 static void pvr2fb_pci_exit(void)
@@ -1068,7 +1069,6 @@ int __init pvr2fb_init(void)
 	size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
 
 	fb_info = kmalloc(size, GFP_KERNEL);
-	
 	if (!fb_info) {
 		printk(KERN_ERR "Failed to allocate memory for fb_info\n");
 		return -ENOMEM;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -942,7 +942,7 @@ pxafb_freq_policy(struct notifier_block 
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int pxafb_suspend(struct device *dev, u32 state, u32 level)
+static int pxafb_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct pxafb_info *fbi = dev_get_drvdata(dev);
 
@@ -1343,8 +1343,7 @@ int __init pxafb_probe(struct device *de
 
 failed:
 	dev_set_drvdata(dev, NULL);
-	if (fbi)
-		kfree(fbi);
+	kfree(fbi);
 	return ret;
 }
 
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
--- a/drivers/video/radeonfb.c
+++ b/drivers/video/radeonfb.c
@@ -657,14 +657,17 @@ static __inline__ int _max(int val1, int
 /*
  * globals
  */
-        
-static char *mode_option __initdata;
+
+#ifndef MODULE
+static char *mode_option;
+#endif
+
 static char noaccel = 0;
 static char mirror = 0;
-static int panel_yres __initdata = 0;
-static char force_dfp __initdata = 0;
+static int panel_yres = 0;
+static char force_dfp = 0;
 static struct radeonfb_info *board_list = NULL;
-static char nomtrr __initdata = 0;
+static char nomtrr = 0;
 
 /*
  * prototypes
@@ -2104,7 +2107,7 @@ static void radeon_write_mode (struct ra
 
 
 	if (rinfo->arch == RADEON_M6) {
-		for (i=0; i<8; i++)
+		for (i=0; i<7; i++)
 			OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val);
 	} else {
 		for (i=0; i<9; i++)
@@ -3109,28 +3112,8 @@ static struct pci_driver radeonfb_driver
 	.remove		= __devexit_p(radeonfb_pci_unregister),
 };
 
-int __init radeonfb_old_setup (char *options);
-
-int __init radeonfb_old_init (void)
-{
 #ifndef MODULE
-	char *option = NULL;
-
-	if (fb_get_options("radeonfb_old", &option))
-		return -ENODEV;
-	radeonfb_old_setup(option);
-#endif
-	return pci_module_init (&radeonfb_driver);
-}
-
-
-void __exit radeonfb_old_exit (void)
-{
-	pci_unregister_driver (&radeonfb_driver);
-}
-
-
-int __init radeonfb_old_setup (char *options)
+static int __init radeonfb_old_setup (char *options)
 {
         char *this_opt;
 
@@ -3156,12 +3139,28 @@ int __init radeonfb_old_setup (char *opt
 
 	return 0;
 }
+#endif  /*  MODULE  */
 
-module_init(radeonfb_old_init);
+static int __init radeonfb_old_init (void)
+{
+#ifndef MODULE
+	char *option = NULL;
 
-#ifdef MODULE
-module_exit(radeonfb_old_exit);
+	if (fb_get_options("radeonfb_old", &option))
+		return -ENODEV;
+	radeonfb_old_setup(option);
 #endif
+	return pci_register_driver (&radeonfb_driver);
+}
+
+
+static void __exit radeonfb_old_exit (void)
+{
+	pci_unregister_driver (&radeonfb_driver);
+}
+
+module_init(radeonfb_old_init);
+module_exit(radeonfb_old_exit);
 
 
 MODULE_AUTHOR("Ani Joshi");
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -208,23 +208,23 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl)
  * ------------------------------------------------------------------------- */
 
 /* command line data, set in rivafb_setup() */
-static int flatpanel __initdata = -1; /* Autodetect later */
-static int forceCRTC __initdata = -1;
-static int noaccel   __initdata = 0;
+static int flatpanel __devinitdata = -1; /* Autodetect later */
+static int forceCRTC __devinitdata = -1;
+static int noaccel   __devinitdata = 0;
 #ifdef CONFIG_MTRR
-static int nomtrr __initdata = 0;
+static int nomtrr __devinitdata = 0;
 #endif
 
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
 static int  strictmode       = 0;
 
-static struct fb_fix_screeninfo __initdata rivafb_fix = {
+static struct fb_fix_screeninfo __devinitdata rivafb_fix = {
 	.type		= FB_TYPE_PACKED_PIXELS,
 	.xpanstep	= 1,
 	.ypanstep	= 1,
 };
 
-static struct fb_var_screeninfo __initdata rivafb_default_var = {
+static struct fb_var_screeninfo __devinitdata rivafb_default_var = {
 	.xres		= 640,
 	.yres		= 480,
 	.xres_virtual	= 640,
@@ -906,7 +906,7 @@ riva_set_pattern(struct riva_par *par, i
 }
 
 /* acceleration routines */
-inline void wait_for_idle(struct riva_par *par)
+static inline void wait_for_idle(struct riva_par *par)
 {
 	while (par->riva.Busy(&par->riva));
 }
@@ -923,7 +923,7 @@ riva_set_rop_solid(struct riva_par *par,
 
 }
 
-void riva_setup_accel(struct fb_info *info)
+static void riva_setup_accel(struct fb_info *info)
 {
 	struct riva_par *par = (struct riva_par *) info->par;
 
@@ -1708,8 +1708,7 @@ static int __devinit riva_set_fbinfo(str
 		    | FBINFO_HWACCEL_YPAN
 		    | FBINFO_HWACCEL_COPYAREA
 		    | FBINFO_HWACCEL_FILLRECT
-		    | FBINFO_HWACCEL_IMAGEBLIT
-	            | FBINFO_MISC_MODESWITCHLATE;
+	            | FBINFO_HWACCEL_IMAGEBLIT;
 
 	/* Accel seems to not work properly on NV30 yet...*/
 	if ((par->riva.Architecture == NV_ARCH_30) || noaccel) {
@@ -2109,8 +2108,7 @@ static void __exit rivafb_remove(struct 
 
 #ifdef CONFIG_FB_RIVA_I2C
 	riva_delete_i2c_busses(par);
-	if (par->EDID)
-		kfree(par->EDID);
+	kfree(par->EDID);
 #endif
 
 	unregister_framebuffer(info);
@@ -2139,7 +2137,7 @@ static void __exit rivafb_remove(struct 
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-int __init rivafb_setup(char *options)
+static int __init rivafb_setup(char *options)
 {
 	char *this_opt;
 
@@ -2189,7 +2187,7 @@ static struct pci_driver rivafb_driver =
  *
  * ------------------------------------------------------------------------- */
 
-int __devinit rivafb_init(void)
+static int __devinit rivafb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -120,8 +120,12 @@ static int riva_setup_i2c_bus(struct riv
 	rc = i2c_bit_add_bus(&chan->adapter);
 	if (rc == 0)
 		dev_dbg(&chan->par->pdev->dev, "I2C bus %s registered.\n", name);
-	else
-		dev_warn(&chan->par->pdev->dev, "Failed to register I2C bus %s.\n", name);
+	else {
+		dev_warn(&chan->par->pdev->dev,
+			 "Failed to register I2C bus %s.\n", name);
+		chan->par = NULL;
+	}
+
 	return rc;
 }
 
@@ -172,6 +176,9 @@ static u8 *riva_do_probe_i2c_edid(struct
 	};
 	u8 *buf;
 
+	if (!chan->par)
+		return NULL;
+
 	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
 	if (!buf) {
 		dev_warn(&chan->par->pdev->dev, "Out of memory!\n");
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/s1d13xxxfb.c
@@ -0,0 +1,772 @@
+/* drivers/video/s1d13xxxfb.c
+ *
+ * (c) 2004 Simtec Electronics
+ * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * Driver for Epson S1D13xxx series framebuffer chips
+ *
+ * Adapted from
+ *  linux/drivers/video/skeletonfb.c
+ *  linux/drivers/video/epson1355fb.c
+ *  linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
+ *
+ * Note, currently only tested on S1D13806 with 16bit CRT.
+ * As such, this driver might still contain some hardcoded bits relating to
+ * S1D13806.
+ * Making it work on other S1D13XXX chips should merely be a matter of adding
+ * a few switch()s, some missing glue here and there maybe, and split header
+ * files.
+ *
+ * TODO: - handle dual screen display (CRT and LCD at the same time).
+ *	 - check_var(), mode change, etc.
+ *	 - PM untested.
+ *	 - Accelerated interfaces.
+ *	 - Probably not SMP safe :)
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <video/s1d13xxxfb.h>
+
+#define PFX "s1d13xxxfb: "
+
+#if 0
+#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
+#else
+#define dbg(fmt, args...) do { } while (0)
+#endif
+
+/*
+ * Here we define the default struct fb_fix_screeninfo
+ */
+static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
+	.id		= S1D_FBID,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 0,
+	.ypanstep	= 1,
+	.ywrapstep	= 0,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static inline u8
+s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
+{
+	return readb(par->regs + regno);
+}
+
+static inline void
+s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
+{
+	writeb(value, par->regs + regno);
+}
+
+static inline void
+s1d13xxxfb_runinit(struct s1d13xxxfb_par *par,
+			const struct s1d13xxxfb_regval *initregs,
+			const unsigned int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+        	if ((initregs[i].addr == S1DREG_DELAYOFF) ||
+				(initregs[i].addr == S1DREG_DELAYON))
+			mdelay((int)initregs[i].value);
+        	else {
+			s1d13xxxfb_writereg(par, initregs[i].addr, initregs[i].value);
+		}
+        }
+
+	/* make sure the hardware can cope with us */
+	mdelay(1);
+}
+
+static inline void
+lcd_enable(struct s1d13xxxfb_par *par, int enable)
+{
+	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+
+	if (enable)
+		mode |= 0x01;
+	else
+		mode &= ~0x01;
+
+	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
+}
+
+static inline void
+crt_enable(struct s1d13xxxfb_par *par, int enable)
+{
+	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+
+	if (enable)
+		mode |= 0x02;
+	else
+		mode &= ~0x02;
+
+	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
+}
+
+/* framebuffer control routines */
+
+static inline void
+s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
+{
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->var.red.length = 4;
+	info->var.green.length = 4;
+	info->var.blue.length = 4;
+}
+
+static inline void
+s1d13xxxfb_setup_truecolour(struct fb_info *info)
+{
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->var.bits_per_pixel = 16;
+
+	info->var.red.length = 5;
+	info->var.red.offset = 11;
+
+	info->var.green.length = 6;
+	info->var.green.offset = 5;
+
+	info->var.blue.length = 5;
+	info->var.blue.offset = 0;
+}
+
+/**
+ *      s1d13xxxfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the depth of the
+ *	framebuffer. This function alters the par AND the
+ *	fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
+ *	fb_info since we are using that data. This means we depend on the
+ *	data in var inside fb_info to be supported by the hardware.
+ *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
+ *
+ *	XXX TODO: write proper s1d13xxxfb_check_var(), without which that
+ *	function is quite useless.
+ */
+static int
+s1d13xxxfb_set_par(struct fb_info *info)
+{
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	unsigned int val;
+
+	dbg("s1d13xxxfb_set_par: bpp=%d\n", info->var.bits_per_pixel);
+
+	if ((s1dfb->display & 0x01))	/* LCD */
+		val = s1d13xxxfb_readreg(s1dfb, S1DREG_LCD_DISP_MODE);   /* read colour control */
+	else	/* CRT */
+		val = s1d13xxxfb_readreg(s1dfb, S1DREG_CRT_DISP_MODE);   /* read colour control */
+
+	val &= ~0x07;
+
+	switch (info->var.bits_per_pixel) {
+		case 4:
+			dbg("pseudo colour 4\n");
+			s1d13xxxfb_setup_pseudocolour(info);
+			val |= 2;
+			break;
+		case 8:
+			dbg("pseudo colour 8\n");
+			s1d13xxxfb_setup_pseudocolour(info);
+			val |= 3;
+			break;
+		case 16:
+			dbg("true colour\n");
+			s1d13xxxfb_setup_truecolour(info);
+			val |= 5;
+			break;
+
+		default:
+			dbg("bpp not supported!\n");
+			return -EINVAL;
+	}
+
+	dbg("writing %02x to display mode register\n", val);
+
+	if ((s1dfb->display & 0x01))	/* LCD */
+		s1d13xxxfb_writereg(s1dfb, S1DREG_LCD_DISP_MODE, val);
+	else	/* CRT */
+		s1d13xxxfb_writereg(s1dfb, S1DREG_CRT_DISP_MODE, val);
+
+	info->fix.line_length  = info->var.xres * info->var.bits_per_pixel;
+	info->fix.line_length /= 8;
+
+	dbg("setting line_length to %d\n", info->fix.line_length);
+
+	dbg("done setup\n");
+
+	return 0;
+}
+
+/**
+ *  	s1d13xxxfb_setcolreg - sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			u_int transp, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	unsigned int pseudo_val;
+
+	if (regno >= S1D_PALETTE_SIZE)
+		return -EINVAL;
+
+	dbg("s1d13xxxfb_setcolreg: %d: rgb=%d,%d,%d, tr=%d\n",
+		    regno, red, green, blue, transp);
+
+	if (info->var.grayscale)
+		red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16;
+
+	switch (info->fix.visual) {
+		case FB_VISUAL_TRUECOLOR:
+			if (regno >= 16)
+				return -EINVAL;
+
+			/* deal with creating pseudo-palette entries */
+
+			pseudo_val  = (red   >> 11) << info->var.red.offset;
+			pseudo_val |= (green >> 10) << info->var.green.offset;
+			pseudo_val |= (blue  >> 11) << info->var.blue.offset;
+
+			dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
+				    regno, pseudo_val);
+
+			((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+
+			break;
+		case FB_VISUAL_PSEUDOCOLOR:
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_ADDR, regno);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, red);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, green);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, blue);
+
+			break;
+		default:
+			return -ENOSYS;
+	}
+
+	dbg("s1d13xxxfb_setcolreg: done\n");
+
+	return 0;
+}
+
+/**
+ *      s1d13xxxfb_blank - blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *par = info->par;
+
+	dbg("s1d13xxxfb_blank: blank=%d, info=%p\n", blank_mode, info);
+
+	switch (blank_mode) {
+		case FB_BLANK_UNBLANK:
+		case FB_BLANK_NORMAL:
+			if ((par->display & 0x01) != 0)
+				lcd_enable(par, 1);
+			if ((par->display & 0x02) != 0)
+				crt_enable(par, 1);
+			break;
+		case FB_BLANK_VSYNC_SUSPEND:
+		case FB_BLANK_HSYNC_SUSPEND:
+			break;
+		case FB_BLANK_POWERDOWN:
+			lcd_enable(par, 0);
+			crt_enable(par, 0);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* let fbcon do a soft blank for us */
+	return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
+}
+
+/**
+ *      s1d13xxxfb_pan_display - Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`yoffset' field of the `var' structure (`xoffset'  not yet supported).
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *par = info->par;
+	u32 start;
+
+	if (var->xoffset != 0)	/* not yet ... */
+		return -EINVAL;
+
+	if (var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	start = (info->fix.line_length >> 1) * var->yoffset;
+
+	if ((par->display & 0x01)) {
+		/* LCD */
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START0, (start & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START1, ((start >> 8) & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START2, ((start >> 16) & 0x0f));
+	} else {
+		/* CRT */
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START0, (start & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START1, ((start >> 8) & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START2, ((start >> 16) & 0x0f));
+	}
+
+	return 0;
+}
+
+
+/* framebuffer information structures */
+
+static struct fb_ops s1d13xxxfb_fbops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= s1d13xxxfb_set_par,
+	.fb_setcolreg	= s1d13xxxfb_setcolreg,
+	.fb_blank	= s1d13xxxfb_blank,
+
+	.fb_pan_display	= s1d13xxxfb_pan_display,
+
+	/* to be replaced by any acceleration we can */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor
+};
+
+static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
+	{4, 8, 16, -1},
+	{9, 12, 18, -1},
+};
+
+/**
+ *      s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
+ *	hardware setup.
+ *      @info: frame buffer structure
+ *
+ *	We setup the framebuffer structures according to the current
+ *	hardware setup. On some machines, the BIOS will have filled
+ *	the chip registers with such info, on others, these values will
+ *	have been written in some init procedure. In any case, the
+ *	software values needs to match the hardware ones. This is what
+ *	this function ensures.
+ *
+ *	Note: some of the hardcoded values here might need some love to
+ *	work on various chips, and might need to no longer be hardcoded.
+ */
+static void __devinit
+s1d13xxxfb_fetch_hw_state(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct s1d13xxxfb_par *par = info->par;
+	u8 panel, display;
+	u16 offset;
+	u32 xres, yres;
+	u32 xres_virtual, yres_virtual;
+	int bpp, lcd_bpp;
+	int is_color, is_dual, is_tft;
+	int lcd_enabled, crt_enabled;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+
+	/* general info */
+	par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+	crt_enabled = (par->display & 0x02) != 0;
+	lcd_enabled = (par->display & 0x01) != 0;
+
+	if (lcd_enabled && crt_enabled)
+		printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n");
+
+	if (lcd_enabled)
+		display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE);
+	else	/* CRT */
+		display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE);
+
+	bpp = display & 0x07;
+
+	switch (bpp) {
+		case 2:	/* 4 bpp */
+		case 3:	/* 8 bpp */
+			var->bits_per_pixel = 8;
+			var->red.offset = var->green.offset = var->blue.offset = 0;
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+		case 5:	/* 16 bpp */
+			s1d13xxxfb_setup_truecolour(info);
+			break;
+		default:
+			dbg("bpp: %i\n", bpp);
+	}
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* LCD info */
+	panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE);
+	is_color = (panel & 0x04) != 0;
+	is_dual = (panel & 0x02) != 0;
+	is_tft = (panel & 0x01) != 0;
+	lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3];
+
+	if (lcd_enabled) {
+		xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8;
+		yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) +
+			((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1);
+
+		offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) +
+			((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8));
+	} else { /* crt */
+		xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8;
+		yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) +
+			((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1);
+
+		offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) +
+			((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8));
+	}
+	xres_virtual = offset * 16 / var->bits_per_pixel;
+	yres_virtual = fix->smem_len / (offset * 2);
+
+	var->xres		= xres;
+	var->yres		= yres;
+	var->xres_virtual	= xres_virtual;
+	var->yres_virtual	= yres_virtual;
+	var->xoffset		= var->yoffset = 0;
+
+	fix->line_length	= offset * 2;
+
+	var->grayscale		= !is_color;
+
+	var->activate		= FB_ACTIVATE_NOW;
+
+	dbg(PFX "bpp=%d, lcd_bpp=%d, "
+		"crt_enabled=%d, lcd_enabled=%d\n",
+		var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled);
+	dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d "
+		"is_color=%d, is_dual=%d, is_tft=%d\n",
+		xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft);
+}
+
+
+static int __devexit
+s1d13xxxfb_remove(struct device *dev)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s1d13xxxfb_par *par = NULL;
+
+	if (info) {
+		par = info->par;
+		if (par && par->regs) {
+			/* disable output & enable powersave */
+			s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00);
+			s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11);
+			iounmap(par->regs);
+		}
+
+		fb_dealloc_cmap(&info->cmap);
+
+		if (info->screen_base)
+			iounmap(info->screen_base);
+
+		framebuffer_release(info);
+	}
+
+	release_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start +1);
+	release_mem_region(pdev->resource[1].start,
+			pdev->resource[1].end - pdev->resource[1].start +1);
+	return 0;
+}
+
+static int __devinit
+s1d13xxxfb_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s1d13xxxfb_par *default_par;
+	struct fb_info *info;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+	int ret = 0;
+	u8 revision;
+
+	dbg("probe called: device is %p\n", dev);
+
+	printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
+
+	/* enable platform-dependent hardware glue, if any */
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+	if (pdata && pdata->platform_init_video)
+		pdata->platform_init_video();
+
+
+	if (pdev->num_resources != 2) {
+		dev_err(&pdev->dev, "invalid num_resources: %i\n",
+		       pdev->num_resources);
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	/* resource[0] is VRAM, resource[1] is registers */
+	if (pdev->resource[0].flags != IORESOURCE_MEM
+			|| pdev->resource[1].flags != IORESOURCE_MEM) {
+		dev_err(&pdev->dev, "invalid resource type\n");
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	if (!request_mem_region(pdev->resource[0].start,
+		pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
+		dev_dbg(dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto bail;
+	}
+
+	if (!request_mem_region(pdev->resource[1].start,
+		pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
+		dev_dbg(dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto bail;
+	}
+
+	info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev);
+	if (!info) {
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	default_par = info->par;
+	default_par->regs = ioremap_nocache(pdev->resource[1].start,
+			pdev->resource[1].end - pdev->resource[1].start +1);
+	if (!default_par->regs) {
+		printk(KERN_ERR PFX "unable to map registers\n");
+		ret = -ENOMEM;
+		goto bail;
+	}
+	info->pseudo_palette = default_par->pseudo_palette;
+
+	info->screen_base = ioremap_nocache(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start +1);
+
+	if (!info->screen_base) {
+		printk(KERN_ERR PFX "unable to map framebuffer\n");
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE);
+	if ((revision >> 2) != S1D_CHIP_REV) {
+		printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2));
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	info->fix = s1d13xxxfb_fix;
+	info->fix.mmio_start = pdev->resource[1].start;
+	info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1;
+	info->fix.smem_start = pdev->resource[0].start;
+	info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1;
+
+	printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
+	       default_par->regs, info->fix.smem_len / 1024, info->screen_base);
+
+	info->par = default_par;
+	info->fbops = &s1d13xxxfb_fbops;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	/* perform "manual" chip initialization, if needed */
+	if (pdata && pdata->initregs)
+		s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize);
+
+	s1d13xxxfb_fetch_hw_state(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto bail;
+	}
+
+	dev_set_drvdata(&pdev->dev, info);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+
+	return 0;
+
+bail:
+	s1d13xxxfb_remove(dev);
+	return ret;
+
+}
+
+#ifdef CONFIG_PM
+static int s1d13xxxfb_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+
+	/* disable display */
+	lcd_enable(s1dfb, 0);
+	crt_enable(s1dfb, 0);
+
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+#if 0
+	if (!s1dfb->disp_save)
+		s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL);
+
+	if (!s1dfb->disp_save) {
+		printk(KERN_ERR PFX "no memory to save screen");
+		return -ENOMEM;
+	}
+
+	memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len);
+#else
+	s1dfb->disp_save = NULL;
+#endif
+
+	if (!s1dfb->regs_save)
+		s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL);
+
+	if (!s1dfb->regs_save) {
+		printk(KERN_ERR PFX "no memory to save registers");
+		return -ENOMEM;
+	}
+
+	/* backup all registers */
+	memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len);
+
+	/* now activate power save mode */
+	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11);
+
+	if (pdata && pdata->platform_suspend_video)
+		return pdata->platform_suspend_video();
+	else
+		return 0;
+}
+
+static int s1d13xxxfb_resume(struct device *dev, u32 level)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	/* awaken the chip */
+	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10);
+
+	/* do not let go until SDRAM "wakes up" */
+	while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
+		udelay(10);
+
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+	if (s1dfb->regs_save) {
+		/* will write RO regs, *should* get away with it :) */
+		memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len);
+		kfree(s1dfb->regs_save);
+	}
+
+	if (s1dfb->disp_save) {
+		memcpy_toio(info->screen_base, s1dfb->disp_save,
+				info->fix.smem_len);
+		kfree(s1dfb->disp_save);	/* XXX kmalloc()'d when? */
+	}
+
+	if ((s1dfb->display & 0x01) != 0)
+		lcd_enable(s1dfb, 1);
+	if ((s1dfb->display & 0x02) != 0)
+		crt_enable(s1dfb, 1);
+
+	if (pdata && pdata->platform_resume_video)
+		return pdata->platform_resume_video();
+	else
+		return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver s1d13xxxfb_driver = {
+	.name		= S1D_DEVICENAME,
+	.bus		= &platform_bus_type,
+	.probe		= s1d13xxxfb_probe,
+	.remove		= s1d13xxxfb_remove,
+#ifdef CONFIG_PM
+	.suspend	= s1d13xxxfb_suspend,
+	.resume		= s1d13xxxfb_resume
+#endif
+};
+
+
+static int __init
+s1d13xxxfb_init(void)
+{
+	if (fb_get_options("s1d13xxxfb", NULL))
+		return -ENODEV;
+
+	return driver_register(&s1d13xxxfb_driver);
+}
+
+
+static void __exit
+s1d13xxxfb_exit(void)
+{
+	driver_unregister(&s1d13xxxfb_driver);
+}
+
+module_init(s1d13xxxfb_init);
+module_exit(s1d13xxxfb_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>");
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -836,7 +836,7 @@ static int sa1100fb_mmap(struct fb_info 
 	vma->vm_pgoff = off >> PAGE_SHIFT;
 	vma->vm_flags |= VM_IO;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	return io_remap_page_range(vma, vma->vm_start, off,
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
 				   vma->vm_end - vma->vm_start,
 				   vma->vm_page_prot);
 }
@@ -1307,7 +1307,7 @@ sa1100fb_freq_policy(struct notifier_blo
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int sa1100fb_suspend(struct device *dev, u32 state, u32 level)
+static int sa1100fb_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	struct sa1100fb_info *fbi = dev_get_drvdata(dev);
 
@@ -1507,8 +1507,7 @@ static int __init sa1100fb_probe(struct 
 
 failed:
 	dev_set_drvdata(dev, NULL);
-	if (fbi)
-		kfree(fbi);
+	kfree(fbi);
 	release_mem_region(0xb0100000, 0x10000);
 	return ret;
 }
diff --git a/drivers/video/savage/Makefile b/drivers/video/savage/Makefile
--- a/drivers/video/savage/Makefile
+++ b/drivers/video/savage/Makefile
@@ -2,7 +2,8 @@
 # Makefile for the S3 Savage framebuffer driver
 #
 
-obj-$(CONFIG_FB_SAVAGE)		+= savagefb.o
-obj-$(CONFIG_FB_SAVAGE_I2C)     += savagefb-i2c.o
-obj-$(CONFIG_FB_SAVAGE_ACCEL)   += savagefb_accel.o
+obj-$(CONFIG_FB_SAVAGE)			+= savagefb.o
 
+savagefb-y				+= savagefb_driver.o
+savagefb-$(CONFIG_FB_SAVAGE_I2C)	+= savagefb-i2c.o
+savagefb-$(CONFIG_FB_SAVAGE_ACCEL)	+= savagefb_accel.o
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -207,7 +207,6 @@ void savagefb_create_i2c_busses(struct f
 
 	savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
 }
-EXPORT_SYMBOL(savagefb_create_i2c_busses);
 
 void savagefb_delete_i2c_busses(struct fb_info *info)
 {
@@ -222,7 +221,6 @@ void savagefb_delete_i2c_busses(struct f
 
 	par->chan.par = NULL;
 }
-EXPORT_SYMBOL(savagefb_delete_i2c_busses);
 
 static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
 {
@@ -280,6 +278,5 @@ int savagefb_probe_i2c_connector(struct 
 
 	return 0;
 }
-EXPORT_SYMBOL(savagefb_probe_i2c_connector);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb.c b/drivers/video/savage/savagefb.c
deleted file mode 100644
--- a/drivers/video/savage/savagefb.c
+++ /dev/null
@@ -1,2276 +0,0 @@
-/*
- * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
- *
- * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
- *                          Sven Neumann <neo@directfb.org>
- *
- *
- * Card specific code is based on XFree86's savage driver.
- * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
- *
- * 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.
- *
- * 0.4.0 (neo)
- *  - hardware accelerated clear and move
- *
- * 0.3.2 (dok)
- *  - wait for vertical retrace before writing to cr67
- *    at the beginning of savagefb_set_par
- *  - use synchronization registers cr23 and cr26
- *
- * 0.3.1 (dok)
- *  - reset 3D engine
- *  - don't return alpha bits for 32bit format
- *
- * 0.3.0 (dok)
- *  - added WaitIdle functions for all Savage types
- *  - do WaitIdle before mode switching
- *  - code cleanup
- *
- * 0.2.0 (dok)
- *  - first working version
- *
- *
- * TODO
- * - clock validations in decode_var
- *
- * BUGS
- * - white margin on bootup
- *
- */
-
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/console.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
-#include "savagefb.h"
-
-
-#define SAVAGEFB_VERSION "0.4.0_2.6"
-
-/* --------------------------------------------------------------------- */
-
-
-static char *mode_option __initdata = NULL;
-static int   paletteEnabled = 0;
-
-#ifdef MODULE
-
-MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
-
-#endif
-
-
-/* --------------------------------------------------------------------- */
-
-static void vgaHWSeqReset (struct savagefb_par *par, int start)
-{
-	if (start)
-		VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
-	else
-		VGAwSEQ (0x00, 0x03);		/* End Reset */
-}
-
-static void vgaHWProtect (struct savagefb_par *par, int on)
-{
-	unsigned char tmp;
-
-	if (on) {
-		/*
-		 * Turn off screen and disable sequencer.
-		 */
-		tmp = VGArSEQ (0x01);
-
-		vgaHWSeqReset (par, 1);	        /* start synchronous reset */
-		VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
-
-		VGAenablePalette();
-	} else {
-		/*
-		 * Reenable sequencer, then turn on screen.
-		 */
-
-		tmp = VGArSEQ (0x01);
-
-		VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
-		vgaHWSeqReset (par, 0);	        /* clear synchronous reset */
-
-		VGAdisablePalette();
-	}
-}
-
-static void vgaHWRestore (struct savagefb_par  *par)
-{
-	int i;
-
-	VGAwMISC (par->MiscOutReg);
-
-	for (i = 1; i < 5; i++)
-		VGAwSEQ (i, par->Sequencer[i]);
-
-	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
-	   CRTC[17] */
-	VGAwCR (17, par->CRTC[17] & ~0x80);
-
-	for (i = 0; i < 25; i++)
-		VGAwCR (i, par->CRTC[i]);
-
-	for (i = 0; i < 9; i++)
-		VGAwGR (i, par->Graphics[i]);
-
-	VGAenablePalette();
-
-	for (i = 0; i < 21; i++)
-		VGAwATTR (i, par->Attribute[i]);
-
-	VGAdisablePalette();
-}
-
-static void vgaHWInit (struct fb_var_screeninfo *var,
-		       struct savagefb_par            *par,
-		       struct xtimings                *timings)
-{
-	par->MiscOutReg = 0x23;
-
-	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
-		par->MiscOutReg |= 0x40;
-
-	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
-		par->MiscOutReg |= 0x80;
-
-	/*
-	 * Time Sequencer
-	 */
-	par->Sequencer[0x00] = 0x00;
-	par->Sequencer[0x01] = 0x01;
-	par->Sequencer[0x02] = 0x0F;
-	par->Sequencer[0x03] = 0x00;          /* Font select */
-	par->Sequencer[0x04] = 0x0E;          /* Misc */
-
-	/*
-	 * CRTC Controller
-	 */
-	par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
-	par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
-	par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
-	par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
-	par->CRTC[0x04] = (timings->HSyncStart >> 3);
-	par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
-		(((timings->HSyncEnd >> 3)) & 0x1f);
-	par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
-	par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
-		(((timings->VDisplay - 1) & 0x100) >> 7) |
-		((timings->VSyncStart & 0x100) >> 6) |
-		(((timings->VSyncStart - 1) & 0x100) >> 5) |
-		0x10 |
-		(((timings->VTotal - 2) & 0x200) >> 4) |
-		(((timings->VDisplay - 1) & 0x200) >> 3) |
-		((timings->VSyncStart & 0x200) >> 2);
-	par->CRTC[0x08] = 0x00;
-	par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
-
-	if (timings->dblscan)
-		par->CRTC[0x09] |= 0x80;
-
-	par->CRTC[0x0a] = 0x00;
-	par->CRTC[0x0b] = 0x00;
-	par->CRTC[0x0c] = 0x00;
-	par->CRTC[0x0d] = 0x00;
-	par->CRTC[0x0e] = 0x00;
-	par->CRTC[0x0f] = 0x00;
-	par->CRTC[0x10] = timings->VSyncStart & 0xff;
-	par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
-	par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
-	par->CRTC[0x13] = var->xres_virtual >> 4;
-	par->CRTC[0x14] = 0x00;
-	par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
-	par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
-	par->CRTC[0x17] = 0xc3;
-	par->CRTC[0x18] = 0xff;
-
-	/*
-	 * are these unnecessary?
-	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
-	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
-	 */
-
-	/*
-	 * Graphics Display Controller
-	 */
-	par->Graphics[0x00] = 0x00;
-	par->Graphics[0x01] = 0x00;
-	par->Graphics[0x02] = 0x00;
-	par->Graphics[0x03] = 0x00;
-	par->Graphics[0x04] = 0x00;
-	par->Graphics[0x05] = 0x40;
-	par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
-	par->Graphics[0x07] = 0x0F;
-	par->Graphics[0x08] = 0xFF;
-
-
-	par->Attribute[0x00]  = 0x00; /* standard colormap translation */
-	par->Attribute[0x01]  = 0x01;
-	par->Attribute[0x02]  = 0x02;
-	par->Attribute[0x03]  = 0x03;
-	par->Attribute[0x04]  = 0x04;
-	par->Attribute[0x05]  = 0x05;
-	par->Attribute[0x06]  = 0x06;
-	par->Attribute[0x07]  = 0x07;
-	par->Attribute[0x08]  = 0x08;
-	par->Attribute[0x09]  = 0x09;
-	par->Attribute[0x0a] = 0x0A;
-	par->Attribute[0x0b] = 0x0B;
-	par->Attribute[0x0c] = 0x0C;
-	par->Attribute[0x0d] = 0x0D;
-	par->Attribute[0x0e] = 0x0E;
-	par->Attribute[0x0f] = 0x0F;
-	par->Attribute[0x10] = 0x41;
-	par->Attribute[0x11] = 0xFF;
-	par->Attribute[0x12] = 0x0F;
-	par->Attribute[0x13] = 0x00;
-	par->Attribute[0x14] = 0x00;
-}
-
-/* -------------------- Hardware specific routines ------------------------- */
-
-/*
- * Hardware Acceleration for SavageFB
- */
-
-/* Wait for fifo space */
-static void
-savage3D_waitfifo(struct savagefb_par *par, int space)
-{
-	int slots = MAXFIFO - space;
-
-	while ((savage_in32(0x48C00) & 0x0000ffff) > slots);
-}
-
-static void
-savage4_waitfifo(struct savagefb_par *par, int space)
-{
-	int slots = MAXFIFO - space;
-
-	while ((savage_in32(0x48C60) & 0x001fffff) > slots);
-}
-
-static void
-savage2000_waitfifo(struct savagefb_par *par, int space)
-{
-	int slots = MAXFIFO - space;
-
-	while ((savage_in32(0x48C60) & 0x0000ffff) > slots);
-}
-
-/* Wait for idle accelerator */
-static void
-savage3D_waitidle(struct savagefb_par *par)
-{
-	while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000);
-}
-
-static void
-savage4_waitidle(struct savagefb_par *par)
-{
-	while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000);
-}
-
-static void
-savage2000_waitidle(struct savagefb_par *par)
-{
-	while ((savage_in32(0x48C60) & 0x009fffff));
-}
-
-
-static void
-SavageSetup2DEngine (struct savagefb_par  *par)
-{
-	unsigned long GlobalBitmapDescriptor;
-
-	GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
-	BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
-	BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
-
-	switch(par->chip) {
-	case S3_SAVAGE3D:
-	case S3_SAVAGE_MX:
-		/* Disable BCI */
-		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
-		/* Setup BCI command overflow buffer */
-		savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29));
-		/* Program shadow status update. */
-		savage_out32(0x48C10, 0x78207220);
-		savage_out32(0x48C0C, 0);
-		/* Enable BCI and command overflow buffer */
-		savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C);
-		break;
-	case S3_SAVAGE4:
-	case S3_PROSAVAGE:
-	case S3_SUPERSAVAGE:
-		/* Disable BCI */
-		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
-		/* Program shadow status update */
-		savage_out32(0x48C10, 0x00700040);
-		savage_out32(0x48C0C, 0);
-		/* Enable BCI without the COB */
-		savage_out32(0x48C18, savage_in32(0x48C18) | 0x08);
-		break;
-	case S3_SAVAGE2000:
-		/* Disable BCI */
-		savage_out32(0x48C18, 0);
-		/* Setup BCI command overflow buffer */
-		savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index));
-		/* Disable shadow status update */
-		savage_out32(0x48A30, 0);
-		/* Enable BCI and command overflow buffer */
-		savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 );
-		break;
-	    default:
-		break;
-	}
-	/* Turn on 16-bit register access. */
-	vga_out8(0x3d4, 0x31);
-	vga_out8(0x3d5, 0x0c);
-
-	/* Set stride to use GBD. */
-	vga_out8 (0x3d4, 0x50);
-	vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1);
-
-	/* Enable 2D engine. */
-	vga_out8 (0x3d4, 0x40 );
-	vga_out8 (0x3d5, 0x01 );
-
-	savage_out32 (MONO_PAT_0, ~0);
-	savage_out32 (MONO_PAT_1, ~0);
-
-	/* Setup plane masks */
-	savage_out32 (0x8128, ~0 ); /* enable all write planes */
-	savage_out32 (0x812C, ~0 ); /* enable all read planes */
-	savage_out16 (0x8134, 0x27 );
-	savage_out16 (0x8136, 0x07 );
-
-	/* Now set the GBD */
-	par->bci_ptr = 0;
-	par->SavageWaitFifo (par, 4);
-
-	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
-	BCI_SEND( 0 );
-	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
-	BCI_SEND( GlobalBitmapDescriptor );
-}
-
-
-static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
-			    int min_n2, int max_n2, long freq_min,
-			    long freq_max, unsigned int *mdiv,
-			    unsigned int *ndiv, unsigned int *r)
-{
-	long diff, best_diff;
-	unsigned int m;
-	unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
-
-	if (freq < freq_min / (1 << max_n2)) {
-		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
-		freq = freq_min / (1 << max_n2);
-	}
-	if (freq > freq_max / (1 << min_n2)) {
-		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
-		freq = freq_max / (1 << min_n2);
-	}
-
-	/* work out suitable timings */
-	best_diff = freq;
-
-	for (n2=min_n2; n2<=max_n2; n2++) {
-		for (n1=min_n1+2; n1<=max_n1+2; n1++) {
-			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
-				BASE_FREQ;
-			if (m < min_m+2 || m > 127+2)
-				continue;
-			if ((m * BASE_FREQ >= freq_min * n1) &&
-			    (m * BASE_FREQ <= freq_max * n1)) {
-				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
-				if (diff < 0)
-					diff = -diff;
-				if (diff < best_diff) {
-					best_diff = diff;
-					best_m = m;
-					best_n1 = n1;
-					best_n2 = n2;
-				}
-			}
-		}
-	}
-
-	*ndiv = best_n1 - 2;
-	*r = best_n2;
-	*mdiv = best_m - 2;
-}
-
-static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
-			     int min_n2, int max_n2, long freq_min,
-			     long freq_max, unsigned char *mdiv,
-			     unsigned char *ndiv)
-{
-	long diff, best_diff;
-	unsigned int m;
-	unsigned char n1, n2;
-	unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
-
-	best_diff = freq;
-
-	for (n2 = min_n2; n2 <= max_n2; n2++) {
-		for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
-			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
-				BASE_FREQ;
-			if (m < min_m + 2 || m > 127+2)
-				continue;
-			if((m * BASE_FREQ >= freq_min * n1) &&
-			   (m * BASE_FREQ <= freq_max * n1)) {
-				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
-				if(diff < 0)
-					diff = -diff;
-				if(diff < best_diff) {
-					best_diff = diff;
-					best_m = m;
-					best_n1 = n1;
-					best_n2 = n2;
-				}
-			}
-		}
-	}
-
-	if(max_n1 == 63)
-		*ndiv = (best_n1 - 2) | (best_n2 << 6);
-	else
-		*ndiv = (best_n1 - 2) | (best_n2 << 5);
-
-	*mdiv = best_m - 2;
-
-	return 0;
-}
-
-#ifdef SAVAGEFB_DEBUG
-/* This function is used to debug, it prints out the contents of s3 regs */
-
-static void SavagePrintRegs(void)
-{
-	unsigned char i;
-	int vgaCRIndex = 0x3d4;
-	int vgaCRReg = 0x3d5;
-
-	printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
-	       "xF" );
-
-	for( i = 0; i < 0x70; i++ ) {
-		if( !(i % 16) )
-			printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
-		vga_out8( 0x3c4, i );
-		printk(KERN_DEBUG " %02x", vga_in8(0x3c5) );
-	}
-
-	printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
-	       "xD xE xF" );
-
-	for( i = 0; i < 0xB7; i++ ) {
-		if( !(i % 16) )
-			printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
-		vga_out8( vgaCRIndex, i );
-		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) );
-	}
-
-	printk(KERN_DEBUG "\n\n");
-}
-#endif
-
-/* --------------------------------------------------------------------- */
-
-static void savage_get_default_par(struct savagefb_par *par)
-{
-	unsigned char cr3a, cr53, cr66;
-
-	vga_out16 (0x3d4, 0x4838);
-	vga_out16 (0x3d4, 0xa039);
-	vga_out16 (0x3c4, 0x0608);
-
-	vga_out8 (0x3d4, 0x66);
-	cr66 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr66 | 0x80);
-	vga_out8 (0x3d4, 0x3a);
-	cr3a = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr3a | 0x80);
-	vga_out8 (0x3d4, 0x53);
-	cr53 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr53 & 0x7f);
-
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, cr66);
-	vga_out8 (0x3d4, 0x3a);
-	vga_out8 (0x3d5, cr3a);
-
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, cr66);
-	vga_out8 (0x3d4, 0x3a);
-	vga_out8 (0x3d5, cr3a);
-
-	/* unlock extended seq regs */
-	vga_out8 (0x3c4, 0x08);
-	par->SR08 = vga_in8 (0x3c5);
-	vga_out8 (0x3c5, 0x06);
-
-	/* now save all the extended regs we need */
-	vga_out8 (0x3d4, 0x31);
-	par->CR31 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x32);
-	par->CR32 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x34);
-	par->CR34 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x36);
-	par->CR36 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x3a);
-	par->CR3A = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x40);
-	par->CR40 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x42);
-	par->CR42 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x45);
-	par->CR45 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x50);
-	par->CR50 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x51);
-	par->CR51 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x53);
-	par->CR53 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x58);
-	par->CR58 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x60);
-	par->CR60 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x66);
-	par->CR66 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x67);
-	par->CR67 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x68);
-	par->CR68 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x69);
-	par->CR69 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x6f);
-	par->CR6F = vga_in8 (0x3d5);
-
-	vga_out8 (0x3d4, 0x33);
-	par->CR33 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x86);
-	par->CR86 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x88);
-	par->CR88 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x90);
-	par->CR90 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x91);
-	par->CR91 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0xb0);
-	par->CRB0 = vga_in8 (0x3d5) | 0x80;
-
-	/* extended mode timing regs */
-	vga_out8 (0x3d4, 0x3b);
-	par->CR3B = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x3c);
-	par->CR3C = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x43);
-	par->CR43 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x5d);
-	par->CR5D = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x5e);
-	par->CR5E = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x65);
-	par->CR65 = vga_in8 (0x3d5);
-
-	/* save seq extended regs for DCLK PLL programming */
-	vga_out8 (0x3c4, 0x0e);
-	par->SR0E = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x0f);
-	par->SR0F = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x10);
-	par->SR10 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x11);
-	par->SR11 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x12);
-	par->SR12 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x13);
-	par->SR13 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x29);
-	par->SR29 = vga_in8 (0x3c5);
-
-	vga_out8 (0x3c4, 0x15);
-	par->SR15 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x30);
-	par->SR30 = vga_in8 (0x3c5);
-	vga_out8 (0x3c4, 0x18);
-	par->SR18 = vga_in8 (0x3c5);
-
-	/* Save flat panel expansion regsters. */
-	if (par->chip == S3_SAVAGE_MX) {
-		int i;
-
-		for (i = 0; i < 8; i++) {
-			vga_out8 (0x3c4, 0x54+i);
-			par->SR54[i] = vga_in8 (0x3c5);
-		}
-	}
-
-	vga_out8 (0x3d4, 0x66);
-	cr66 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr66 | 0x80);
-	vga_out8 (0x3d4, 0x3a);
-	cr3a = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr3a | 0x80);
-
-	/* now save MIU regs */
-	if (par->chip != S3_SAVAGE_MX) {
-		par->MMPR0 = savage_in32(FIFO_CONTROL_REG);
-		par->MMPR1 = savage_in32(MIU_CONTROL_REG);
-		par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG);
-		par->MMPR3 = savage_in32(MISC_TIMEOUT_REG);
-	}
-
-	vga_out8 (0x3d4, 0x3a);
-	vga_out8 (0x3d5, cr3a);
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, cr66);
-}
-
-static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
-{
-	var->xres = var->xres_virtual = modedb->xres;
-	var->yres = modedb->yres;
-        if (var->yres_virtual < var->yres)
-	    var->yres_virtual = var->yres;
-        var->xoffset = var->yoffset = 0;
-        var->pixclock = modedb->pixclock;
-        var->left_margin = modedb->left_margin;
-        var->right_margin = modedb->right_margin;
-        var->upper_margin = modedb->upper_margin;
-        var->lower_margin = modedb->lower_margin;
-        var->hsync_len = modedb->hsync_len;
-        var->vsync_len = modedb->vsync_len;
-        var->sync = modedb->sync;
-        var->vmode = modedb->vmode;
-}
-
-static int savagefb_check_var (struct fb_var_screeninfo   *var,
-			       struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	int memlen, vramlen, mode_valid = 0;
-
-	DBG("savagefb_check_var");
-
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	switch (var->bits_per_pixel) {
-	case 8:
-		var->red.offset = var->green.offset =
-			var->blue.offset = 0;
-		var->red.length = var->green.length =
-			var->blue.length = var->bits_per_pixel;
-		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;
-		break;
-	case 32:
-		var->transp.offset = 24;
-		var->transp.length = 8;
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
-	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
-		mode_valid = 1;
-
-	/* calculate modeline if supported by monitor */
-	if (!mode_valid && info->monspecs.gtf) {
-		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
-			mode_valid = 1;
-	}
-
-	if (!mode_valid) {
-		struct fb_videomode *mode;
-
-		mode = fb_find_best_mode(var, &info->modelist);
-		if (mode) {
-			savage_update_var(var, mode);
-			mode_valid = 1;
-		}
-	}
-
-	if (!mode_valid && info->monspecs.modedb_len)
-		return -EINVAL;
-
-	/* Is the mode larger than the LCD panel? */
-	if (par->SavagePanelWidth &&
-	    (var->xres > par->SavagePanelWidth ||
-	     var->yres > par->SavagePanelHeight)) {
-		printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
-			"(%dx%d)\n", var->xres,  var->yres,
-			par->SavagePanelWidth,
-			par->SavagePanelHeight);
-		return -1;
-	}
-
-	if (var->yres_virtual < var->yres)
-		var->yres_virtual = var->yres;
-	if (var->xres_virtual < var->xres)
-		var->xres_virtual = var->xres;
-
-	vramlen = info->fix.smem_len;
-
-	memlen = var->xres_virtual * var->bits_per_pixel *
-		var->yres_virtual / 8;
-	if (memlen > vramlen) {
-		var->yres_virtual = vramlen * 8 /
-			(var->xres_virtual * var->bits_per_pixel);
-		memlen = var->xres_virtual * var->bits_per_pixel *
-			var->yres_virtual / 8;
-	}
-
-	/* we must round yres/xres down, we already rounded y/xres_virtual up
-	   if it was possible. We should return -EINVAL, but I disagree */
-	if (var->yres_virtual < var->yres)
-		var->yres = var->yres_virtual;
-	if (var->xres_virtual < var->xres)
-		var->xres = var->xres_virtual;
-	if (var->xoffset + var->xres > var->xres_virtual)
-		var->xoffset = var->xres_virtual - var->xres;
-	if (var->yoffset + var->yres > var->yres_virtual)
-		var->yoffset = var->yres_virtual - var->yres;
-
-	return 0;
-}
-
-
-static int savagefb_decode_var (struct fb_var_screeninfo   *var,
-				struct savagefb_par        *par)
-{
-	struct xtimings timings;
-	int width, dclk, i, j; /*, refresh; */
-	unsigned int m, n, r;
-	unsigned char tmp = 0;
-	unsigned int pixclock = var->pixclock;
-
-	DBG("savagefb_decode_var");
-
-	memset (&timings, 0, sizeof(timings));
-
-	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
-	timings.Clock = 1000000000 / pixclock;
-	if (timings.Clock < 1) timings.Clock = 1;
-	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
-	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
-	timings.HDisplay = var->xres;
-	timings.HSyncStart = timings.HDisplay + var->right_margin;
-	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
-	timings.HTotal = timings.HSyncEnd + var->left_margin;
-	timings.VDisplay = var->yres;
-	timings.VSyncStart = timings.VDisplay + var->lower_margin;
-	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
-	timings.VTotal = timings.VSyncEnd + var->upper_margin;
-	timings.sync = var->sync;
-
-
-	par->depth  = var->bits_per_pixel;
-	par->vwidth = var->xres_virtual;
-
-	if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
-		timings.HDisplay *= 2;
-		timings.HSyncStart *= 2;
-		timings.HSyncEnd *= 2;
-		timings.HTotal *= 2;
-	}
-
-	/*
-	 * This will allocate the datastructure and initialize all of the
-	 * generic VGA registers.
-	 */
-	vgaHWInit (var, par, &timings);
-
-	/* We need to set CR67 whether or not we use the BIOS. */
-
-	dclk = timings.Clock;
-	par->CR67 = 0x00;
-
-	switch( var->bits_per_pixel ) {
-	case 8:
-		if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
-			par->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
-		else
-			par->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
-		break;
-	case 15:
-		if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
-		     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
-			par->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
-		else
-			par->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
-		break;
-	case 16:
-		if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
-		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
-			par->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
-		else
-			par->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
-		break;
-	case 24:
-		par->CR67 = 0x70;
-		break;
-	case 32:
-		par->CR67 = 0xd0;
-		break;
-	}
-
-	/*
-	 * Either BIOS use is disabled, or we failed to find a suitable
-	 * match.  Fall back to traditional register-crunching.
-	 */
-
-	vga_out8 (0x3d4, 0x3a);
-	tmp = vga_in8 (0x3d5);
-	if (1 /*FIXME:psav->pci_burst*/)
-		par->CR3A = (tmp & 0x7f) | 0x15;
-	else
-		par->CR3A = tmp | 0x95;
-
-	par->CR53 = 0x00;
-	par->CR31 = 0x8c;
-	par->CR66 = 0x89;
-
-	vga_out8 (0x3d4, 0x58);
-	par->CR58 = vga_in8 (0x3d5) & 0x80;
-	par->CR58 |= 0x13;
-
-	par->SR15 = 0x03 | 0x80;
-	par->SR18 = 0x00;
-	par->CR43 = par->CR45 = par->CR65 = 0x00;
-
-	vga_out8 (0x3d4, 0x40);
-	par->CR40 = vga_in8 (0x3d5) & ~0x01;
-
-	par->MMPR0 = 0x010400;
-	par->MMPR1 = 0x00;
-	par->MMPR2 = 0x0808;
-	par->MMPR3 = 0x08080810;
-
-	SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
-	/* m = 107; n = 4; r = 2; */
-
-	if (par->MCLK <= 0) {
-		par->SR10 = 255;
-		par->SR11 = 255;
-	} else {
-		common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
-				   &par->SR11, &par->SR10);
-		/*      par->SR10 = 80; // MCLK == 286000 */
-		/*      par->SR11 = 125; */
-	}
-
-	par->SR12 = (r << 6) | (n & 0x3f);
-	par->SR13 = m & 0xff;
-	par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
-
-	if (var->bits_per_pixel < 24)
-		par->MMPR0 -= 0x8000;
-	else
-		par->MMPR0 -= 0x4000;
-
-	if (timings.interlaced)
-		par->CR42 = 0x20;
-	else
-		par->CR42 = 0x00;
-
-	par->CR34 = 0x10; /* display fifo */
-
-	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
-		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
-		((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
-		((timings.HSyncStart & 0x800) >> 7);
-
-	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
-		i |= 0x08;
-	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
-		i |= 0x20;
-
-	j = (par->CRTC[0] + ((i & 0x01) << 8) +
-	     par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
-
-	if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
-		if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
-		    par->CRTC[0] + ((i & 0x01) << 8))
-			j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
-		else
-			j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
-	}
-
-	par->CR3B = j & 0xff;
-	i |= (j & 0x100) >> 2;
-	par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
-	par->CR5D = i;
-	par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
-		(((timings.VDisplay - 1) & 0x400) >> 9) |
-		(((timings.VSyncStart) & 0x400) >> 8) |
-		(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
-	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
-	par->CR91 = par->CRTC[19] = 0xff & width;
-	par->CR51 = (0x300 & width) >> 4;
-	par->CR90 = 0x80 | (width >> 8);
-	par->MiscOutReg |= 0x0c;
-
-	/* Set frame buffer description. */
-
-	if (var->bits_per_pixel <= 8)
-		par->CR50 = 0;
-	else if (var->bits_per_pixel <= 16)
-		par->CR50 = 0x10;
-	else
-		par->CR50 = 0x30;
-
-	if (var->xres_virtual <= 640)
-		par->CR50 |= 0x40;
-	else if (var->xres_virtual == 800)
-		par->CR50 |= 0x80;
-	else if (var->xres_virtual == 1024)
-		par->CR50 |= 0x00;
-	else if (var->xres_virtual == 1152)
-		par->CR50 |= 0x01;
-	else if (var->xres_virtual == 1280)
-		par->CR50 |= 0xc0;
-	else if (var->xres_virtual == 1600)
-		par->CR50 |= 0x81;
-	else
-		par->CR50 |= 0xc1;	/* Use GBD */
-
-	if( par->chip == S3_SAVAGE2000 )
-		par->CR33 = 0x08;
-	else
-		par->CR33 = 0x20;
-
-	par->CRTC[0x17] = 0xeb;
-
-	par->CR67 |= 1;
-
-	vga_out8(0x3d4, 0x36);
-	par->CR36 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x68);
-	par->CR68 = vga_in8 (0x3d5);
-	par->CR69 = 0;
-	vga_out8 (0x3d4, 0x6f);
-	par->CR6F = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x86);
-	par->CR86 = vga_in8 (0x3d5);
-	vga_out8 (0x3d4, 0x88);
-	par->CR88 = vga_in8 (0x3d5) | 0x08;
-	vga_out8 (0x3d4, 0xb0);
-	par->CRB0 = vga_in8 (0x3d5) | 0x80;
-
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- *    Set a single color register. Return != 0 for invalid regno.
- */
-static int savagefb_setcolreg(unsigned        regno,
-			      unsigned        red,
-			      unsigned        green,
-			      unsigned        blue,
-			      unsigned        transp,
-			      struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-
-	if (regno >= NR_PALETTE)
-		return -EINVAL;
-
-	par->palette[regno].red    = red;
-	par->palette[regno].green  = green;
-	par->palette[regno].blue   = blue;
-	par->palette[regno].transp = transp;
-
-	switch (info->var.bits_per_pixel) {
-	case 8:
-		vga_out8 (0x3c8, regno);
-
-		vga_out8 (0x3c9, red   >> 10);
-		vga_out8 (0x3c9, green >> 10);
-		vga_out8 (0x3c9, blue  >> 10);
-		break;
-
-	case 16:
-		if (regno < 16)
-			((u32 *)info->pseudo_palette)[regno] =
-				((red   & 0xf800)      ) |
-				((green & 0xfc00) >>  5) |
-				((blue  & 0xf800) >> 11);
-		break;
-
-	case 24:
-		if (regno < 16)
-			((u32 *)info->pseudo_palette)[regno] =
-				((red    & 0xff00) <<  8) |
-				((green  & 0xff00)      ) |
-				((blue   & 0xff00) >>  8);
-		break;
-	case 32:
-		if (regno < 16)
-			((u32 *)info->pseudo_palette)[regno] =
-				((transp & 0xff00) << 16) |
-				((red    & 0xff00) <<  8) |
-				((green  & 0xff00)      ) |
-				((blue   & 0xff00) >>  8);
-		break;
-
-	default:
-		return 1;
-	}
-
-	return 0;
-}
-
-static void savagefb_set_par_int (struct savagefb_par  *par)
-{
-	unsigned char tmp, cr3a, cr66, cr67;
-
-	DBG ("savagefb_set_par_int");
-
-	par->SavageWaitIdle (par);
-
-	vga_out8 (0x3c2, 0x23);
-
-	vga_out16 (0x3d4, 0x4838);
-	vga_out16 (0x3d4, 0xa539);
-	vga_out16 (0x3c4, 0x0608);
-
-	vgaHWProtect (par, 1);
-
-	/*
-	 * Some Savage/MX and /IX systems go nuts when trying to exit the
-	 * server after WindowMaker has displayed a gradient background.  I
-	 * haven't been able to find what causes it, but a non-destructive
-	 * switch to mode 3 here seems to eliminate the issue.
-	 */
-
-	VerticalRetraceWait();
-	vga_out8 (0x3d4, 0x67);
-	cr67 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */
-
-	vga_out8 (0x3d4, 0x23);
-	vga_out8 (0x3d5, 0x00);
-	vga_out8 (0x3d4, 0x26);
-	vga_out8 (0x3d5, 0x00);
-
-	/* restore extended regs */
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, par->CR66);
-	vga_out8 (0x3d4, 0x3a);
-	vga_out8 (0x3d5, par->CR3A);
-	vga_out8 (0x3d4, 0x31);
-	vga_out8 (0x3d5, par->CR31);
-	vga_out8 (0x3d4, 0x32);
-	vga_out8 (0x3d5, par->CR32);
-	vga_out8 (0x3d4, 0x58);
-	vga_out8 (0x3d5, par->CR58);
-	vga_out8 (0x3d4, 0x53);
-	vga_out8 (0x3d5, par->CR53 & 0x7f);
-
-	vga_out16 (0x3c4, 0x0608);
-
-	/* Restore DCLK registers. */
-
-	vga_out8 (0x3c4, 0x0e);
-	vga_out8 (0x3c5, par->SR0E);
-	vga_out8 (0x3c4, 0x0f);
-	vga_out8 (0x3c5, par->SR0F);
-	vga_out8 (0x3c4, 0x29);
-	vga_out8 (0x3c5, par->SR29);
-	vga_out8 (0x3c4, 0x15);
-	vga_out8 (0x3c5, par->SR15);
-
-	/* Restore flat panel expansion regsters. */
-	if( par->chip == S3_SAVAGE_MX ) {
-		int i;
-
-		for( i = 0; i < 8; i++ ) {
-			vga_out8 (0x3c4, 0x54+i);
-			vga_out8 (0x3c5, par->SR54[i]);
-		}
-	}
-
-	vgaHWRestore (par);
-
-	/* extended mode timing registers */
-	vga_out8 (0x3d4, 0x53);
-	vga_out8 (0x3d5, par->CR53);
-	vga_out8 (0x3d4, 0x5d);
-	vga_out8 (0x3d5, par->CR5D);
-	vga_out8 (0x3d4, 0x5e);
-	vga_out8 (0x3d5, par->CR5E);
-	vga_out8 (0x3d4, 0x3b);
-	vga_out8 (0x3d5, par->CR3B);
-	vga_out8 (0x3d4, 0x3c);
-	vga_out8 (0x3d5, par->CR3C);
-	vga_out8 (0x3d4, 0x43);
-	vga_out8 (0x3d5, par->CR43);
-	vga_out8 (0x3d4, 0x65);
-	vga_out8 (0x3d5, par->CR65);
-
-	/* restore the desired video mode with cr67 */
-	vga_out8 (0x3d4, 0x67);
-	/* following part not present in X11 driver */
-	cr67 = vga_in8 (0x3d5) & 0xf;
-	vga_out8 (0x3d5, 0x50 | cr67);
-	udelay (10000);
-	vga_out8 (0x3d4, 0x67);
-	/* end of part */
-	vga_out8 (0x3d5, par->CR67 & ~0x0c);
-
-	/* other mode timing and extended regs */
-	vga_out8 (0x3d4, 0x34);
-	vga_out8 (0x3d5, par->CR34);
-	vga_out8 (0x3d4, 0x40);
-	vga_out8 (0x3d5, par->CR40);
-	vga_out8 (0x3d4, 0x42);
-	vga_out8 (0x3d5, par->CR42);
-	vga_out8 (0x3d4, 0x45);
-	vga_out8 (0x3d5, par->CR45);
-	vga_out8 (0x3d4, 0x50);
-	vga_out8 (0x3d5, par->CR50);
-	vga_out8 (0x3d4, 0x51);
-	vga_out8 (0x3d5, par->CR51);
-
-	/* memory timings */
-	vga_out8 (0x3d4, 0x36);
-	vga_out8 (0x3d5, par->CR36);
-	vga_out8 (0x3d4, 0x60);
-	vga_out8 (0x3d5, par->CR60);
-	vga_out8 (0x3d4, 0x68);
-	vga_out8 (0x3d5, par->CR68);
-	vga_out8 (0x3d4, 0x69);
-	vga_out8 (0x3d5, par->CR69);
-	vga_out8 (0x3d4, 0x6f);
-	vga_out8 (0x3d5, par->CR6F);
-
-	vga_out8 (0x3d4, 0x33);
-	vga_out8 (0x3d5, par->CR33);
-	vga_out8 (0x3d4, 0x86);
-	vga_out8 (0x3d5, par->CR86);
-	vga_out8 (0x3d4, 0x88);
-	vga_out8 (0x3d5, par->CR88);
-	vga_out8 (0x3d4, 0x90);
-	vga_out8 (0x3d5, par->CR90);
-	vga_out8 (0x3d4, 0x91);
-	vga_out8 (0x3d5, par->CR91);
-
-	if (par->chip == S3_SAVAGE4) {
-		vga_out8 (0x3d4, 0xb0);
-		vga_out8 (0x3d5, par->CRB0);
-	}
-
-	vga_out8 (0x3d4, 0x32);
-	vga_out8 (0x3d5, par->CR32);
-
-	/* unlock extended seq regs */
-	vga_out8 (0x3c4, 0x08);
-	vga_out8 (0x3c5, 0x06);
-
-	/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
-	 * that we should leave the default SR10 and SR11 values there.
-	 */
-	if (par->SR10 != 255) {
-		vga_out8 (0x3c4, 0x10);
-		vga_out8 (0x3c5, par->SR10);
-		vga_out8 (0x3c4, 0x11);
-		vga_out8 (0x3c5, par->SR11);
-	}
-
-	/* restore extended seq regs for dclk */
-	vga_out8 (0x3c4, 0x0e);
-	vga_out8 (0x3c5, par->SR0E);
-	vga_out8 (0x3c4, 0x0f);
-	vga_out8 (0x3c5, par->SR0F);
-	vga_out8 (0x3c4, 0x12);
-	vga_out8 (0x3c5, par->SR12);
-	vga_out8 (0x3c4, 0x13);
-	vga_out8 (0x3c5, par->SR13);
-	vga_out8 (0x3c4, 0x29);
-	vga_out8 (0x3c5, par->SR29);
-
-	vga_out8 (0x3c4, 0x18);
-	vga_out8 (0x3c5, par->SR18);
-
-	/* load new m, n pll values for dclk & mclk */
-	vga_out8 (0x3c4, 0x15);
-	tmp = vga_in8 (0x3c5) & ~0x21;
-
-	vga_out8 (0x3c5, tmp | 0x03);
-	vga_out8 (0x3c5, tmp | 0x23);
-	vga_out8 (0x3c5, tmp | 0x03);
-	vga_out8 (0x3c5, par->SR15);
-	udelay (100);
-
-	vga_out8 (0x3c4, 0x30);
-	vga_out8 (0x3c5, par->SR30);
-	vga_out8 (0x3c4, 0x08);
-	vga_out8 (0x3c5, par->SR08);
-
-	/* now write out cr67 in full, possibly starting STREAMS */
-	VerticalRetraceWait();
-	vga_out8 (0x3d4, 0x67);
-	vga_out8 (0x3d5, par->CR67);
-
-	vga_out8 (0x3d4, 0x66);
-	cr66 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr66 | 0x80);
-	vga_out8 (0x3d4, 0x3a);
-	cr3a = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr3a | 0x80);
-
-	if (par->chip != S3_SAVAGE_MX) {
-		VerticalRetraceWait();
-		savage_out32 (FIFO_CONTROL_REG, par->MMPR0);
-		par->SavageWaitIdle (par);
-		savage_out32 (MIU_CONTROL_REG, par->MMPR1);
-		par->SavageWaitIdle (par);
-		savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2);
-		par->SavageWaitIdle (par);
-		savage_out32 (MISC_TIMEOUT_REG, par->MMPR3);
-	}
-
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, cr66);
-	vga_out8 (0x3d4, 0x3a);
-	vga_out8 (0x3d5, cr3a);
-
-	SavageSetup2DEngine (par);
-	vgaHWProtect (par, 0);
-}
-
-static void savagefb_update_start (struct savagefb_par      *par,
-				   struct fb_var_screeninfo *var)
-{
-	int base;
-
-	base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
-		* ((var->bits_per_pixel+7) / 8)) >> 2;
-
-	/* now program the start address registers */
-	vga_out16(0x3d4, (base & 0x00ff00) | 0x0c);
-	vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d);
-	vga_out8 (0x3d4, 0x69);
-	vga_out8 (0x3d5, (base & 0x7f0000) >> 16);
-}
-
-
-static void savagefb_set_fix(struct fb_info *info)
-{
-	info->fix.line_length = info->var.xres_virtual *
-		info->var.bits_per_pixel / 8;
-
-	if (info->var.bits_per_pixel == 8)
-		info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
-	else
-		info->fix.visual      = FB_VISUAL_TRUECOLOR;
-}
-
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-static void savagefb_set_clip(struct fb_info *info)
-{
-    struct savagefb_par *par = (struct savagefb_par *)info->par;
-    int cmd;
-
-    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
-    par->bci_ptr = 0;
-    par->SavageWaitFifo(par,3);
-    BCI_SEND(cmd);
-    BCI_SEND(BCI_CLIP_TL(0, 0));
-    BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
-}
-#endif
-
-static int savagefb_set_par (struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	struct fb_var_screeninfo *var = &info->var;
-	int err;
-
-	DBG("savagefb_set_par");
-	err = savagefb_decode_var (var, par);
-	if (err)
-		return err;
-
-	if (par->dacSpeedBpp <= 0) {
-		if (var->bits_per_pixel > 24)
-			par->dacSpeedBpp = par->clock[3];
-		else if (var->bits_per_pixel >= 24)
-			par->dacSpeedBpp = par->clock[2];
-		else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
-			par->dacSpeedBpp = par->clock[1];
-		else if (var->bits_per_pixel <= 8)
-			par->dacSpeedBpp = par->clock[0];
-	}
-
-	/* Set ramdac limits */
-	par->maxClock = par->dacSpeedBpp;
-	par->minClock = 10000;
-
-	savagefb_set_par_int (par);
-	savagefb_update_start (par, var);
-	fb_set_cmap (&info->cmap, info);
-	savagefb_set_fix(info);
-	savagefb_set_clip(info);
-
-	SavagePrintRegs();
-	return 0;
-}
-
-/*
- *    Pan or Wrap the Display
- */
-static int savagefb_pan_display (struct fb_var_screeninfo *var,
-				 struct fb_info           *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	u_int y_bottom;
-
-	y_bottom = var->yoffset;
-
-	if (!(var->vmode & FB_VMODE_YWRAP))
-		y_bottom += var->yres;
-
-	if (var->xoffset > (var->xres_virtual - var->xres))
-		return -EINVAL;
-	if (y_bottom > info->var.yres_virtual)
-		return -EINVAL;
-
-	savagefb_update_start (par, var);
-
-	info->var.xoffset = var->xoffset;
-	info->var.yoffset = var->yoffset;
-
-	if (var->vmode & FB_VMODE_YWRAP)
-		info->var.vmode |= FB_VMODE_YWRAP;
-	else
-		info->var.vmode &= ~FB_VMODE_YWRAP;
-
-	return 0;
-}
-
-
-static struct fb_ops savagefb_ops = {
-	.owner          = THIS_MODULE,
-	.fb_check_var   = savagefb_check_var,
-	.fb_set_par     = savagefb_set_par,
-	.fb_setcolreg   = savagefb_setcolreg,
-	.fb_pan_display = savagefb_pan_display,
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-	.fb_fillrect    = savagefb_fillrect,
-	.fb_copyarea    = savagefb_copyarea,
-	.fb_imageblit   = savagefb_imageblit,
-	.fb_sync        = savagefb_sync,
-#else
-	.fb_fillrect    = cfb_fillrect,
-	.fb_copyarea    = cfb_copyarea,
-	.fb_imageblit   = cfb_imageblit,
-#endif
-	.fb_cursor      = soft_cursor,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
-	.accel_flags =	FB_ACCELF_TEXT,
-	.xres =		800,
-	.yres =		600,
-	.xres_virtual =  800,
-	.yres_virtual =  600,
-	.bits_per_pixel = 8,
-	.pixclock =	25000,
-	.left_margin =	88,
-	.right_margin =	40,
-	.upper_margin =	23,
-	.lower_margin =	1,
-	.hsync_len =	128,
-	.vsync_len =	4,
-	.sync =		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-	.vmode =	FB_VMODE_NONINTERLACED
-};
-
-static void savage_enable_mmio (struct savagefb_par *par)
-{
-	unsigned char val;
-
-	DBG ("savage_enable_mmio\n");
-
-	val = vga_in8 (0x3c3);
-	vga_out8 (0x3c3, val | 0x01);
-	val = vga_in8 (0x3cc);
-	vga_out8 (0x3c2, val | 0x01);
-
-	if (par->chip >= S3_SAVAGE4) {
-		vga_out8 (0x3d4, 0x40);
-		val = vga_in8 (0x3d5);
-		vga_out8 (0x3d5, val | 1);
-	}
-}
-
-
-void savage_disable_mmio (struct savagefb_par *par)
-{
-	unsigned char val;
-
-	DBG ("savage_disable_mmio\n");
-
-	if(par->chip >= S3_SAVAGE4 ) {
-		vga_out8 (0x3d4, 0x40);
-		val = vga_in8 (0x3d5);
-		vga_out8 (0x3d5, val | 1);
-	}
-}
-
-
-static int __devinit savage_map_mmio (struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	DBG ("savage_map_mmio");
-
-	if (S3_SAVAGE3D_SERIES (par->chip))
-		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
-			SAVAGE_NEWMMIO_REGBASE_S3;
-	else
-		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
-			SAVAGE_NEWMMIO_REGBASE_S4;
-
-	par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
-
-	par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
-	if (!par->mmio.vbase) {
-		printk ("savagefb: unable to map memory mapped IO\n");
-		return -ENOMEM;
-	} else
-		printk (KERN_INFO "savagefb: mapped io at %p\n",
-			par->mmio.vbase);
-
-	info->fix.mmio_start = par->mmio.pbase;
-	info->fix.mmio_len   = par->mmio.len;
-
-	par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
-	par->bci_ptr  = 0;
-
-	savage_enable_mmio (par);
-
-	return 0;
-}
-
-static void __devinit savage_unmap_mmio (struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	DBG ("savage_unmap_mmio");
-
-	savage_disable_mmio(par);
-
-	if (par->mmio.vbase) {
-		iounmap ((void __iomem *)par->mmio.vbase);
-		par->mmio.vbase = NULL;
-	}
-}
-
-static int __devinit savage_map_video (struct fb_info *info,
-				       int video_len)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	int resource;
-
-	DBG("savage_map_video");
-
-	if (S3_SAVAGE3D_SERIES (par->chip))
-		resource = 0;
-	else
-		resource = 1;
-
-	par->video.pbase = pci_resource_start (par->pcidev, resource);
-	par->video.len   = video_len;
-	par->video.vbase = ioremap (par->video.pbase, par->video.len);
-
-	if (!par->video.vbase) {
-		printk ("savagefb: unable to map screen memory\n");
-		return -ENOMEM;
-	} else
-		printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
-			"pbase == %x\n", par->video.vbase, par->video.pbase);
-
-	info->fix.smem_start = par->video.pbase;
-	info->fix.smem_len   = par->video.len - par->cob_size;
-	info->screen_base    = par->video.vbase;
-
-#ifdef CONFIG_MTRR
-	par->video.mtrr = mtrr_add (par->video.pbase, video_len,
-				     MTRR_TYPE_WRCOMB, 1);
-#endif
-	return 0;
-}
-
-static void __devinit savage_unmap_video (struct fb_info *info)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-
-	DBG("savage_unmap_video");
-
-	if (par->video.vbase) {
-#ifdef CONFIG_MTRR
-		mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
-#endif
-
-		iounmap (par->video.vbase);
-		par->video.vbase = NULL;
-		info->screen_base = NULL;
-	}
-}
-
-static int __devinit savage_init_hw (struct savagefb_par *par)
-{
-	unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
-
-	static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
-	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
-	static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
-	static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
-
-	int videoRam, videoRambytes;
-
-	DBG("savage_init_hw");
-
-	/* unprotect CRTC[0-7] */
-	vga_out8(0x3d4, 0x11);
-	tmp = vga_in8(0x3d5);
-	vga_out8(0x3d5, tmp & 0x7f);
-
-	/* unlock extended regs */
-	vga_out16(0x3d4, 0x4838);
-	vga_out16(0x3d4, 0xa039);
-	vga_out16(0x3c4, 0x0608);
-
-	vga_out8(0x3d4, 0x40);
-	tmp = vga_in8(0x3d5);
-	vga_out8(0x3d5, tmp & ~0x01);
-
-	/* unlock sys regs */
-	vga_out8(0x3d4, 0x38);
-	vga_out8(0x3d5, 0x48);
-
-	/* Unlock system registers. */
-	vga_out16(0x3d4, 0x4838);
-
-	/* Next go on to detect amount of installed ram */
-
-	vga_out8(0x3d4, 0x36);            /* for register CR36 (CONFG_REG1), */
-	config1 = vga_in8(0x3d5);           /* get amount of vram installed */
-
-	/* Compute the amount of video memory and offscreen memory. */
-
-	switch  (par->chip) {
-	case S3_SAVAGE3D:
-		videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
-		break;
-
-	case S3_SAVAGE4:
-		/*
-		 * The Savage4 has one ugly special case to consider.  On
-		 * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
-		 * when it really means 8MB.  Why do it the same when you
-		 * can do it different...
-		 */
-		vga_out8(0x3d4, 0x68);	/* memory control 1 */
-		if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) )
-			RamSavage4[1] = 8;
-
-		/*FALLTHROUGH*/
-
-	case S3_SAVAGE2000:
-		videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
-		break;
-
-	case S3_SAVAGE_MX:
-	case S3_SUPERSAVAGE:
-		videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
-		break;
-
-	case S3_PROSAVAGE:
-		videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
-		break;
-
-	default:
-		/* How did we get here? */
-		videoRam = 0;
-		break;
-	}
-
-	videoRambytes = videoRam * 1024;
-
-	printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
-
-	/* reset graphics engine to avoid memory corruption */
-	vga_out8 (0x3d4, 0x66);
-	cr66 = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr66 | 0x02);
-	udelay (10000);
-
-	vga_out8 (0x3d4, 0x66);
-	vga_out8 (0x3d5, cr66 & ~0x02);	/* clear reset flag */
-	udelay (10000);
-
-
-	/*
-	 * reset memory interface, 3D engine, AGP master, PCI master,
-	 * master engine unit, motion compensation/LPB
-	 */
-	vga_out8 (0x3d4, 0x3f);
-	cr3f = vga_in8 (0x3d5);
-	vga_out8 (0x3d5, cr3f | 0x08);
-	udelay (10000);
-
-	vga_out8 (0x3d4, 0x3f);
-	vga_out8 (0x3d5, cr3f & ~0x08);	/* clear reset flags */
-	udelay (10000);
-
-	/* Savage ramdac speeds */
-	par->numClocks = 4;
-	par->clock[0] = 250000;
-	par->clock[1] = 250000;
-	par->clock[2] = 220000;
-	par->clock[3] = 220000;
-
-	/* detect current mclk */
-	vga_out8(0x3c4, 0x08);
-	sr8 = vga_in8(0x3c5);
-	vga_out8(0x3c5, 0x06);
-	vga_out8(0x3c4, 0x10);
-	n = vga_in8(0x3c5);
-	vga_out8(0x3c4, 0x11);
-	m = vga_in8(0x3c5);
-	vga_out8(0x3c4, 0x08);
-	vga_out8(0x3c5, sr8);
-	m &= 0x7f;
-	n1 = n & 0x1f;
-	n2 = (n >> 5) & 0x03;
-	par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
-	printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
-		par->MCLK);
-
-	/* Check LCD panel parrmation */
-
-	if (par->chip == S3_SAVAGE_MX) {
-		unsigned char cr6b = VGArCR( 0x6b );
-
-		int panelX = (VGArSEQ (0x61) +
-			      ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8;
-		int panelY = (VGArSEQ (0x69) +
-			      ((VGArSEQ (0x6e) & 0x70) << 4) + 1);
-
-		char * sTechnology = "Unknown";
-
-		/* OK, I admit it.  I don't know how to limit the max dot clock
-		 * for LCD panels of various sizes.  I thought I copied the
-		 * formula from the BIOS, but many users have parrmed me of
-		 * my folly.
-		 *
-		 * Instead, I'll abandon any attempt to automatically limit the
-		 * clock, and add an LCDClock option to XF86Config.  Some day,
-		 * I should come back to this.
-		 */
-
-		enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
-			ActiveCRT = 0x01,
-			ActiveLCD = 0x02,
-			ActiveTV = 0x04,
-			ActiveCRT2 = 0x20,
-			ActiveDUO = 0x80
-		};
-
-		if ((VGArSEQ (0x39) & 0x03) == 0) {
-			sTechnology = "TFT";
-		} else if ((VGArSEQ (0x30) & 0x01) == 0) {
-			sTechnology = "DSTN";
-		} else 	{
-			sTechnology = "STN";
-		}
-
-		printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
-			panelX, panelY, sTechnology,
-			cr6b & ActiveLCD ? "and active" : "but not active");
-
-		if( cr6b & ActiveLCD ) 	{
-			/*
-			 * If the LCD is active and panel expansion is enabled,
-			 * we probably want to kill the HW cursor.
-			 */
-
-			printk (KERN_INFO "savagefb: Limiting video mode to "
-				"%dx%d\n", panelX, panelY );
-
-			par->SavagePanelWidth = panelX;
-			par->SavagePanelHeight = panelY;
-
-		}
-	}
-
-	savage_get_default_par (par);
-
-	if( S3_SAVAGE4_SERIES(par->chip) ) {
-		/*
-		 * The Savage4 and ProSavage have COB coherency bugs which
-		 * render the buffer useless.  We disable it.
-		 */
-		par->cob_index = 2;
-		par->cob_size = 0x8000 << par->cob_index;
-		par->cob_offset = videoRambytes;
-	} else {
-		/* We use 128kB for the COB on all chips. */
-
-		par->cob_index  = 7;
-		par->cob_size   = 0x400 << par->cob_index;
-		par->cob_offset = videoRambytes - par->cob_size;
-	}
-
-	return videoRambytes;
-}
-
-static int __devinit savage_init_fb_info (struct fb_info *info,
-					  struct pci_dev *dev,
-					  const struct pci_device_id *id)
-{
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-	int err = 0;
-
-	par->pcidev  = dev;
-
-	info->fix.type	   = FB_TYPE_PACKED_PIXELS;
-	info->fix.type_aux	   = 0;
-	info->fix.xpanstep	   = 2;
-	info->fix.ypanstep	   = 1;
-	info->fix.ywrapstep   = 0;
-	info->fix.accel       = id->driver_data;
-
-	switch (info->fix.accel) {
-	case FB_ACCEL_SUPERSAVAGE:
-		par->chip = S3_SUPERSAVAGE;
-		snprintf (info->fix.id, 16, "SuperSavage");
-		break;
-	case FB_ACCEL_SAVAGE4:
-		par->chip = S3_SAVAGE4;
-		snprintf (info->fix.id, 16, "Savage4");
-		break;
-	case FB_ACCEL_SAVAGE3D:
-		par->chip = S3_SAVAGE3D;
-		snprintf (info->fix.id, 16, "Savage3D");
-		break;
-	case FB_ACCEL_SAVAGE3D_MV:
-		par->chip = S3_SAVAGE3D;
-		snprintf (info->fix.id, 16, "Savage3D-MV");
-		break;
-	case FB_ACCEL_SAVAGE2000:
-		par->chip = S3_SAVAGE2000;
-		snprintf (info->fix.id, 16, "Savage2000");
-		break;
-	case FB_ACCEL_SAVAGE_MX_MV:
-		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/MX-MV");
-		break;
-	case FB_ACCEL_SAVAGE_MX:
-		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/MX");
-		break;
-	case FB_ACCEL_SAVAGE_IX_MV:
-		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/IX-MV");
-		break;
-	case FB_ACCEL_SAVAGE_IX:
-		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/IX");
-		break;
-	case FB_ACCEL_PROSAVAGE_PM:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavagePM");
-		break;
-	case FB_ACCEL_PROSAVAGE_KM:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavageKM");
-		break;
-	case FB_ACCEL_S3TWISTER_P:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "TwisterP");
-		break;
-	case FB_ACCEL_S3TWISTER_K:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "TwisterK");
-		break;
-	case FB_ACCEL_PROSAVAGE_DDR:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavageDDR");
-		break;
-	case FB_ACCEL_PROSAVAGE_DDRK:
-		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavage8");
-		break;
-	}
-
-	if (S3_SAVAGE3D_SERIES(par->chip)) {
-		par->SavageWaitIdle = savage3D_waitidle;
-		par->SavageWaitFifo = savage3D_waitfifo;
-	} else if (S3_SAVAGE4_SERIES(par->chip) ||
-		   S3_SUPERSAVAGE == par->chip) {
-		par->SavageWaitIdle = savage4_waitidle;
-		par->SavageWaitFifo = savage4_waitfifo;
-	} else {
-		par->SavageWaitIdle = savage2000_waitidle;
-		par->SavageWaitFifo = savage2000_waitfifo;
-	}
-
-	info->var.nonstd      = 0;
-	info->var.activate    = FB_ACTIVATE_NOW;
-	info->var.width       = -1;
-	info->var.height      = -1;
-	info->var.accel_flags = 0;
-
-	info->fbops          = &savagefb_ops;
-	info->flags          = FBINFO_DEFAULT |
-		               FBINFO_HWACCEL_YPAN |
-		               FBINFO_HWACCEL_XPAN |
-	                       FBINFO_MISC_MODESWITCHLATE;
-
-	info->pseudo_palette = par->pseudo_palette;
-
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-	/* FIFO size + padding for commands */
-	info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
-
-	err = -ENOMEM;
-	if (info->pixmap.addr) {
-		memset(info->pixmap.addr, 0, 8*1024);
-		info->pixmap.size = 8*1024;
-		info->pixmap.scan_align = 4;
-		info->pixmap.buf_align = 4;
-		info->pixmap.access_align = 4;
-
-		fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
-		info->flags |= FBINFO_HWACCEL_COPYAREA |
-	                       FBINFO_HWACCEL_FILLRECT |
-		               FBINFO_HWACCEL_IMAGEBLIT;
-
-		err = 0;
-	}
-#endif
-	return err;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int __devinit savagefb_probe (struct pci_dev* dev,
-				     const struct pci_device_id* id)
-{
-	struct fb_info *info;
-	struct savagefb_par *par;
-	u_int h_sync, v_sync;
-	int err, lpitch;
-	int video_len;
-
-	DBG("savagefb_probe");
-	SavagePrintRegs();
-
-	info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
-	if (!info)
-		return -ENOMEM;
-	par = info->par;
-	err = pci_enable_device(dev);
-	if (err)
-		goto failed_enable;
-
-	if (pci_request_regions(dev, "savagefb")) {
-		printk(KERN_ERR "cannot request PCI regions\n");
-		goto failed_enable;
-	}
-
-	err = -ENOMEM;
-
-	if (savage_init_fb_info(info, dev, id))
-		goto failed_init;
-
-	err = savage_map_mmio(info);
-	if (err)
-		goto failed_mmio;
-
-	video_len = savage_init_hw(par);
-	if (video_len < 0) {
-		err = video_len;
-		goto failed_mmio;
-	}
-
-	err = savage_map_video(info, video_len);
-	if (err)
-		goto failed_video;
-
-	INIT_LIST_HEAD(&info->modelist);
-#if defined(CONFIG_FB_SAVAGE_I2C)
-	savagefb_create_i2c_busses(info);
-	savagefb_probe_i2c_connector(par, &par->edid);
-	fb_edid_to_monspecs(par->edid, &info->monspecs);
-	fb_videomode_to_modelist(info->monspecs.modedb,
-				 info->monspecs.modedb_len,
-				 &info->modelist);
-#endif
-	info->var = savagefb_var800x600x8;
-
-	if (mode_option) {
-		fb_find_mode(&info->var, info, mode_option,
-			     info->monspecs.modedb, info->monspecs.modedb_len,
-			     NULL, 8);
-	} else if (info->monspecs.modedb != NULL) {
-		struct fb_monspecs *specs = &info->monspecs;
-		struct fb_videomode modedb;
-
-		if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
-			int i;
-
-			for (i = 0; i < specs->modedb_len; i++) {
-				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
-					modedb = specs->modedb[i];
-					break;
-				}
-			}
-		} else {
-			/* otherwise, get first mode in database */
-			modedb = specs->modedb[0];
-		}
-
-		savage_update_var(&info->var, &modedb);
-	}
-
-	/* maximize virtual vertical length */
-	lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
-	info->var.yres_virtual = info->fix.smem_len/lpitch;
-
-	if (info->var.yres_virtual < info->var.yres)
-		goto failed;
-
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-	/*
-	 * The clipping coordinates are masked with 0xFFF, so limit our
-	 * virtual resolutions to these sizes.
-	 */
-	if (info->var.yres_virtual > 0x1000)
-		info->var.yres_virtual = 0x1000;
-
-	if (info->var.xres_virtual > 0x1000)
-		info->var.xres_virtual = 0x1000;
-#endif
-	savagefb_check_var(&info->var, info);
-	savagefb_set_fix(info);
-
-	/*
-	 * Calculate the hsync and vsync frequencies.  Note that
-	 * we split the 1e12 constant up so that we can preserve
-	 * the precision and fit the results into 32-bit registers.
-	 *  (1953125000 * 512 = 1e12)
-	 */
-	h_sync = 1953125000 / info->var.pixclock;
-	h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
-				 info->var.right_margin +
-				 info->var.hsync_len);
-	v_sync = h_sync / (info->var.yres + info->var.upper_margin +
-			   info->var.lower_margin + info->var.vsync_len);
-
-	printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
-	       "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
-	       info->fix.smem_len >> 10,
-	       info->var.xres, info->var.yres,
-	       h_sync / 1000, h_sync % 1000, v_sync);
-
-
-	fb_destroy_modedb(info->monspecs.modedb);
-	info->monspecs.modedb = NULL;
-
-	err = register_framebuffer (info);
-	if (err < 0)
-		goto failed;
-
-	printk (KERN_INFO "fb: S3 %s frame buffer device\n",
-		info->fix.id);
-
-	/*
-	 * Our driver data
-	 */
-	pci_set_drvdata(dev, info);
-
-	return 0;
-
- failed:
-#ifdef CONFIG_FB_SAVAGE_I2C
-	savagefb_delete_i2c_busses(info);
-#endif
-	fb_alloc_cmap (&info->cmap, 0, 0);
-	savage_unmap_video(info);
- failed_video:
-	savage_unmap_mmio (info);
- failed_mmio:
-	kfree(info->pixmap.addr);
- failed_init:
-	pci_release_regions(dev);
- failed_enable:
-	framebuffer_release(info);
-
-	return err;
-}
-
-static void __devexit savagefb_remove (struct pci_dev *dev)
-{
-	struct fb_info *info =
-		(struct fb_info *)pci_get_drvdata(dev);
-
-	DBG("savagefb_remove");
-
-	if (info) {
-		/*
-		 * If unregister_framebuffer fails, then
-		 * we will be leaving hooks that could cause
-		 * oopsen laying around.
-		 */
-		if (unregister_framebuffer (info))
-			printk (KERN_WARNING "savagefb: danger danger! "
-				"Oopsen imminent!\n");
-
-#ifdef CONFIG_FB_SAVAGE_I2C
-		savagefb_delete_i2c_busses(info);
-#endif
-		fb_alloc_cmap (&info->cmap, 0, 0);
-		savage_unmap_video (info);
-		savage_unmap_mmio (info);
-		kfree(info->pixmap.addr);
-		pci_release_regions(dev);
-		framebuffer_release(info);
-
-		/*
-		 * Ensure that the driver data is no longer
-		 * valid.
-		 */
-		pci_set_drvdata(dev, NULL);
-	}
-}
-
-static int savagefb_suspend (struct pci_dev* dev, u32 state)
-{
-	struct fb_info *info =
-		(struct fb_info *)pci_get_drvdata(dev);
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-
-	DBG("savagefb_suspend");
-	printk(KERN_DEBUG "state: %u\n", state);
-
-	acquire_console_sem();
-	fb_set_suspend(info, state);
-	savage_disable_mmio(par);
-	release_console_sem();
-
-	pci_disable_device(dev);
-	pci_set_power_state(dev, state);
-
-	return 0;
-}
-
-static int savagefb_resume (struct pci_dev* dev)
-{
-	struct fb_info *info =
-		(struct fb_info *)pci_get_drvdata(dev);
-	struct savagefb_par *par = (struct savagefb_par *)info->par;
-
-	DBG("savage_resume");
-
-	pci_set_power_state(dev, 0);
-	pci_restore_state(dev);
-	if(pci_enable_device(dev))
-		DBG("err");
-
-	SavagePrintRegs();
-
-	acquire_console_sem();
-
-	savage_enable_mmio(par);
-	savage_init_hw(par);
-	savagefb_set_par (info);
-
-	fb_set_suspend (info, 0);
-	release_console_sem();
-
-	return 0;
-}
-
-
-static struct pci_device_id savagefb_devices[] __devinitdata = {
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
-
-	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
-
-	{0, 0, 0, 0, 0, 0, 0}
-};
-
-MODULE_DEVICE_TABLE(pci, savagefb_devices);
-
-static struct pci_driver savagefb_driver = {
-	.name =     "savagefb",
-	.id_table = savagefb_devices,
-	.probe =    savagefb_probe,
-	.suspend =  savagefb_suspend,
-	.resume =   savagefb_resume,
-	.remove =   __devexit_p(savagefb_remove)
-};
-
-/* **************************** exit-time only **************************** */
-
-static void __exit savage_done (void)
-{
-	DBG("savage_done");
-	pci_unregister_driver (&savagefb_driver);
-}
-
-
-/* ************************* init in-kernel code ************************** */
-
-int __init savagefb_setup(char *options)
-{
-#ifndef MODULE
-	char *this_opt;
-
-	if (!options || !*options)
-		return 0;
-
-	while ((this_opt = strsep(&options, ",")) != NULL) {
-		mode_option = this_opt;
-	}
-#endif /* !MODULE */
-	return 0;
-}
-
-int __init savagefb_init(void)
-{
-	char *option;
-
-	DBG("savagefb_init");
-
-	if (fb_get_options("savagefb", &option))
-		return -ENODEV;
-
-	savagefb_setup(option);
-	return pci_register_driver (&savagefb_driver);
-
-}
-
-module_init(savagefb_init);
-module_exit(savage_done);
diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c
--- a/drivers/video/savage/savagefb_accel.c
+++ b/drivers/video/savage/savagefb_accel.c
@@ -26,7 +26,6 @@ int savagefb_sync(struct fb_info *info)
 	par->SavageWaitIdle(par);
 	return 0;
 }
-EXPORT_SYMBOL(savagefb_sync);
 
 void savagefb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
@@ -61,7 +60,6 @@ void savagefb_copyarea(struct fb_info *i
 	BCI_SEND(BCI_X_Y(dx, dy));
 	BCI_SEND(BCI_W_H(region->width, region->height));
 }
-EXPORT_SYMBOL(savagefb_copyarea);
 
 void savagefb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
@@ -89,7 +87,6 @@ void savagefb_fillrect(struct fb_info *i
 	BCI_SEND( BCI_X_Y(rect->dx, rect->dy) );
 	BCI_SEND( BCI_W_H(rect->width, rect->height) );
 }
-EXPORT_SYMBOL(savagefb_fillrect);
 
 void savagefb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
@@ -135,6 +132,5 @@ void savagefb_imageblit(struct fb_info *
 	for (i = 0; i < size; i++)
 		BCI_SEND(src[i]);
 }
-EXPORT_SYMBOL(savagefb_imageblit);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
new file mode 100644
--- /dev/null
+++ b/drivers/video/savage/savagefb_driver.c
@@ -0,0 +1,2279 @@
+/*
+ * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
+ *                          Sven Neumann <neo@directfb.org>
+ *
+ *
+ * Card specific code is based on XFree86's savage driver.
+ * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
+ *
+ * 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.
+ *
+ * 0.4.0 (neo)
+ *  - hardware accelerated clear and move
+ *
+ * 0.3.2 (dok)
+ *  - wait for vertical retrace before writing to cr67
+ *    at the beginning of savagefb_set_par
+ *  - use synchronization registers cr23 and cr26
+ *
+ * 0.3.1 (dok)
+ *  - reset 3D engine
+ *  - don't return alpha bits for 32bit format
+ *
+ * 0.3.0 (dok)
+ *  - added WaitIdle functions for all Savage types
+ *  - do WaitIdle before mode switching
+ *  - code cleanup
+ *
+ * 0.2.0 (dok)
+ *  - first working version
+ *
+ *
+ * TODO
+ * - clock validations in decode_var
+ *
+ * BUGS
+ * - white margin on bootup
+ *
+ */
+
+#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/pci.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "savagefb.h"
+
+
+#define SAVAGEFB_VERSION "0.4.0_2.6"
+
+/* --------------------------------------------------------------------- */
+
+
+static char *mode_option __initdata = NULL;
+static int   paletteEnabled = 0;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static void vgaHWSeqReset (struct savagefb_par *par, int start)
+{
+	if (start)
+		VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
+	else
+		VGAwSEQ (0x00, 0x03);		/* End Reset */
+}
+
+static void vgaHWProtect (struct savagefb_par *par, int on)
+{
+	unsigned char tmp;
+
+	if (on) {
+		/*
+		 * Turn off screen and disable sequencer.
+		 */
+		tmp = VGArSEQ (0x01);
+
+		vgaHWSeqReset (par, 1);	        /* start synchronous reset */
+		VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+
+		VGAenablePalette();
+	} else {
+		/*
+		 * Reenable sequencer, then turn on screen.
+		 */
+
+		tmp = VGArSEQ (0x01);
+
+		VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
+		vgaHWSeqReset (par, 0);	        /* clear synchronous reset */
+
+		VGAdisablePalette();
+	}
+}
+
+static void vgaHWRestore (struct savagefb_par  *par)
+{
+	int i;
+
+	VGAwMISC (par->MiscOutReg);
+
+	for (i = 1; i < 5; i++)
+		VGAwSEQ (i, par->Sequencer[i]);
+
+	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
+	   CRTC[17] */
+	VGAwCR (17, par->CRTC[17] & ~0x80);
+
+	for (i = 0; i < 25; i++)
+		VGAwCR (i, par->CRTC[i]);
+
+	for (i = 0; i < 9; i++)
+		VGAwGR (i, par->Graphics[i]);
+
+	VGAenablePalette();
+
+	for (i = 0; i < 21; i++)
+		VGAwATTR (i, par->Attribute[i]);
+
+	VGAdisablePalette();
+}
+
+static void vgaHWInit (struct fb_var_screeninfo *var,
+		       struct savagefb_par            *par,
+		       struct xtimings                *timings)
+{
+	par->MiscOutReg = 0x23;
+
+	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+		par->MiscOutReg |= 0x40;
+
+	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+		par->MiscOutReg |= 0x80;
+
+	/*
+	 * Time Sequencer
+	 */
+	par->Sequencer[0x00] = 0x00;
+	par->Sequencer[0x01] = 0x01;
+	par->Sequencer[0x02] = 0x0F;
+	par->Sequencer[0x03] = 0x00;          /* Font select */
+	par->Sequencer[0x04] = 0x0E;          /* Misc */
+
+	/*
+	 * CRTC Controller
+	 */
+	par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+	par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+	par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
+	par->CRTC[0x04] = (timings->HSyncStart >> 3);
+	par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+		(((timings->HSyncEnd >> 3)) & 0x1f);
+	par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+	par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+		(((timings->VDisplay - 1) & 0x100) >> 7) |
+		((timings->VSyncStart & 0x100) >> 6) |
+		(((timings->VSyncStart - 1) & 0x100) >> 5) |
+		0x10 |
+		(((timings->VTotal - 2) & 0x200) >> 4) |
+		(((timings->VDisplay - 1) & 0x200) >> 3) |
+		((timings->VSyncStart & 0x200) >> 2);
+	par->CRTC[0x08] = 0x00;
+	par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+
+	if (timings->dblscan)
+		par->CRTC[0x09] |= 0x80;
+
+	par->CRTC[0x0a] = 0x00;
+	par->CRTC[0x0b] = 0x00;
+	par->CRTC[0x0c] = 0x00;
+	par->CRTC[0x0d] = 0x00;
+	par->CRTC[0x0e] = 0x00;
+	par->CRTC[0x0f] = 0x00;
+	par->CRTC[0x10] = timings->VSyncStart & 0xff;
+	par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+	par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+	par->CRTC[0x13] = var->xres_virtual >> 4;
+	par->CRTC[0x14] = 0x00;
+	par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+	par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+	par->CRTC[0x17] = 0xc3;
+	par->CRTC[0x18] = 0xff;
+
+	/*
+	 * are these unnecessary?
+	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+	 */
+
+	/*
+	 * Graphics Display Controller
+	 */
+	par->Graphics[0x00] = 0x00;
+	par->Graphics[0x01] = 0x00;
+	par->Graphics[0x02] = 0x00;
+	par->Graphics[0x03] = 0x00;
+	par->Graphics[0x04] = 0x00;
+	par->Graphics[0x05] = 0x40;
+	par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
+	par->Graphics[0x07] = 0x0F;
+	par->Graphics[0x08] = 0xFF;
+
+
+	par->Attribute[0x00]  = 0x00; /* standard colormap translation */
+	par->Attribute[0x01]  = 0x01;
+	par->Attribute[0x02]  = 0x02;
+	par->Attribute[0x03]  = 0x03;
+	par->Attribute[0x04]  = 0x04;
+	par->Attribute[0x05]  = 0x05;
+	par->Attribute[0x06]  = 0x06;
+	par->Attribute[0x07]  = 0x07;
+	par->Attribute[0x08]  = 0x08;
+	par->Attribute[0x09]  = 0x09;
+	par->Attribute[0x0a] = 0x0A;
+	par->Attribute[0x0b] = 0x0B;
+	par->Attribute[0x0c] = 0x0C;
+	par->Attribute[0x0d] = 0x0D;
+	par->Attribute[0x0e] = 0x0E;
+	par->Attribute[0x0f] = 0x0F;
+	par->Attribute[0x10] = 0x41;
+	par->Attribute[0x11] = 0xFF;
+	par->Attribute[0x12] = 0x0F;
+	par->Attribute[0x13] = 0x00;
+	par->Attribute[0x14] = 0x00;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for SavageFB
+ */
+
+/* Wait for fifo space */
+static void
+savage3D_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C00) & 0x0000ffff) > slots);
+}
+
+static void
+savage4_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C60) & 0x001fffff) > slots);
+}
+
+static void
+savage2000_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C60) & 0x0000ffff) > slots);
+}
+
+/* Wait for idle accelerator */
+static void
+savage3D_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000);
+}
+
+static void
+savage4_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000);
+}
+
+static void
+savage2000_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C60) & 0x009fffff));
+}
+
+
+static void
+SavageSetup2DEngine (struct savagefb_par  *par)
+{
+	unsigned long GlobalBitmapDescriptor;
+
+	GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
+	BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
+	BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+
+	switch(par->chip) {
+	case S3_SAVAGE3D:
+	case S3_SAVAGE_MX:
+		/* Disable BCI */
+		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+		/* Setup BCI command overflow buffer */
+		savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29));
+		/* Program shadow status update. */
+		savage_out32(0x48C10, 0x78207220);
+		savage_out32(0x48C0C, 0);
+		/* Enable BCI and command overflow buffer */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C);
+		break;
+	case S3_SAVAGE4:
+	case S3_PROSAVAGE:
+	case S3_SUPERSAVAGE:
+		/* Disable BCI */
+		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+		/* Program shadow status update */
+		savage_out32(0x48C10, 0x00700040);
+		savage_out32(0x48C0C, 0);
+		/* Enable BCI without the COB */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x08);
+		break;
+	case S3_SAVAGE2000:
+		/* Disable BCI */
+		savage_out32(0x48C18, 0);
+		/* Setup BCI command overflow buffer */
+		savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index));
+		/* Disable shadow status update */
+		savage_out32(0x48A30, 0);
+		/* Enable BCI and command overflow buffer */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 );
+		break;
+	    default:
+		break;
+	}
+	/* Turn on 16-bit register access. */
+	vga_out8(0x3d4, 0x31);
+	vga_out8(0x3d5, 0x0c);
+
+	/* Set stride to use GBD. */
+	vga_out8 (0x3d4, 0x50);
+	vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1);
+
+	/* Enable 2D engine. */
+	vga_out8 (0x3d4, 0x40 );
+	vga_out8 (0x3d5, 0x01 );
+
+	savage_out32 (MONO_PAT_0, ~0);
+	savage_out32 (MONO_PAT_1, ~0);
+
+	/* Setup plane masks */
+	savage_out32 (0x8128, ~0 ); /* enable all write planes */
+	savage_out32 (0x812C, ~0 ); /* enable all read planes */
+	savage_out16 (0x8134, 0x27 );
+	savage_out16 (0x8136, 0x07 );
+
+	/* Now set the GBD */
+	par->bci_ptr = 0;
+	par->SavageWaitFifo (par, 4);
+
+	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
+	BCI_SEND( 0 );
+	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
+	BCI_SEND( GlobalBitmapDescriptor );
+}
+
+
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+			    int min_n2, int max_n2, long freq_min,
+			    long freq_max, unsigned int *mdiv,
+			    unsigned int *ndiv, unsigned int *r)
+{
+	long diff, best_diff;
+	unsigned int m;
+	unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
+
+	if (freq < freq_min / (1 << max_n2)) {
+		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		freq = freq_min / (1 << max_n2);
+	}
+	if (freq > freq_max / (1 << min_n2)) {
+		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		freq = freq_max / (1 << min_n2);
+	}
+
+	/* work out suitable timings */
+	best_diff = freq;
+
+	for (n2=min_n2; n2<=max_n2; n2++) {
+		for (n1=min_n1+2; n1<=max_n1+2; n1++) {
+			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+				BASE_FREQ;
+			if (m < min_m+2 || m > 127+2)
+				continue;
+			if ((m * BASE_FREQ >= freq_min * n1) &&
+			    (m * BASE_FREQ <= freq_max * n1)) {
+				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+				if (diff < 0)
+					diff = -diff;
+				if (diff < best_diff) {
+					best_diff = diff;
+					best_m = m;
+					best_n1 = n1;
+					best_n2 = n2;
+				}
+			}
+		}
+	}
+
+	*ndiv = best_n1 - 2;
+	*r = best_n2;
+	*mdiv = best_m - 2;
+}
+
+static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
+			     int min_n2, int max_n2, long freq_min,
+			     long freq_max, unsigned char *mdiv,
+			     unsigned char *ndiv)
+{
+	long diff, best_diff;
+	unsigned int m;
+	unsigned char n1, n2;
+	unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
+
+	best_diff = freq;
+
+	for (n2 = min_n2; n2 <= max_n2; n2++) {
+		for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
+			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+				BASE_FREQ;
+			if (m < min_m + 2 || m > 127+2)
+				continue;
+			if((m * BASE_FREQ >= freq_min * n1) &&
+			   (m * BASE_FREQ <= freq_max * n1)) {
+				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+				if(diff < 0)
+					diff = -diff;
+				if(diff < best_diff) {
+					best_diff = diff;
+					best_m = m;
+					best_n1 = n1;
+					best_n2 = n2;
+				}
+			}
+		}
+	}
+
+	if(max_n1 == 63)
+		*ndiv = (best_n1 - 2) | (best_n2 << 6);
+	else
+		*ndiv = (best_n1 - 2) | (best_n2 << 5);
+
+	*mdiv = best_m - 2;
+
+	return 0;
+}
+
+#ifdef SAVAGEFB_DEBUG
+/* This function is used to debug, it prints out the contents of s3 regs */
+
+static void SavagePrintRegs(void)
+{
+	unsigned char i;
+	int vgaCRIndex = 0x3d4;
+	int vgaCRReg = 0x3d5;
+
+	printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
+	       "xF" );
+
+	for( i = 0; i < 0x70; i++ ) {
+		if( !(i % 16) )
+			printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
+		vga_out8( 0x3c4, i );
+		printk(KERN_DEBUG " %02x", vga_in8(0x3c5) );
+	}
+
+	printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
+	       "xD xE xF" );
+
+	for( i = 0; i < 0xB7; i++ ) {
+		if( !(i % 16) )
+			printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
+		vga_out8( vgaCRIndex, i );
+		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) );
+	}
+
+	printk(KERN_DEBUG "\n\n");
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static void savage_get_default_par(struct savagefb_par *par)
+{
+	unsigned char cr3a, cr53, cr66;
+
+	vga_out16 (0x3d4, 0x4838);
+	vga_out16 (0x3d4, 0xa039);
+	vga_out16 (0x3c4, 0x0608);
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+	vga_out8 (0x3d4, 0x53);
+	cr53 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr53 & 0x7f);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	/* unlock extended seq regs */
+	vga_out8 (0x3c4, 0x08);
+	par->SR08 = vga_in8 (0x3c5);
+	vga_out8 (0x3c5, 0x06);
+
+	/* now save all the extended regs we need */
+	vga_out8 (0x3d4, 0x31);
+	par->CR31 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x32);
+	par->CR32 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x34);
+	par->CR34 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x36);
+	par->CR36 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x3a);
+	par->CR3A = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x40);
+	par->CR40 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x42);
+	par->CR42 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x45);
+	par->CR45 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x50);
+	par->CR50 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x51);
+	par->CR51 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x53);
+	par->CR53 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x58);
+	par->CR58 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x60);
+	par->CR60 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x66);
+	par->CR66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x67);
+	par->CR67 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x68);
+	par->CR68 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x69);
+	par->CR69 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x6f);
+	par->CR6F = vga_in8 (0x3d5);
+
+	vga_out8 (0x3d4, 0x33);
+	par->CR33 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x86);
+	par->CR86 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x88);
+	par->CR88 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x90);
+	par->CR90 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x91);
+	par->CR91 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0xb0);
+	par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+	/* extended mode timing regs */
+	vga_out8 (0x3d4, 0x3b);
+	par->CR3B = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x3c);
+	par->CR3C = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x43);
+	par->CR43 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x5d);
+	par->CR5D = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x5e);
+	par->CR5E = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x65);
+	par->CR65 = vga_in8 (0x3d5);
+
+	/* save seq extended regs for DCLK PLL programming */
+	vga_out8 (0x3c4, 0x0e);
+	par->SR0E = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x0f);
+	par->SR0F = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x10);
+	par->SR10 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x11);
+	par->SR11 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x12);
+	par->SR12 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x13);
+	par->SR13 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x29);
+	par->SR29 = vga_in8 (0x3c5);
+
+	vga_out8 (0x3c4, 0x15);
+	par->SR15 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x30);
+	par->SR30 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x18);
+	par->SR18 = vga_in8 (0x3c5);
+
+	/* Save flat panel expansion regsters. */
+	if (par->chip == S3_SAVAGE_MX) {
+		int i;
+
+		for (i = 0; i < 8; i++) {
+			vga_out8 (0x3c4, 0x54+i);
+			par->SR54[i] = vga_in8 (0x3c5);
+		}
+	}
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+
+	/* now save MIU regs */
+	if (par->chip != S3_SAVAGE_MX) {
+		par->MMPR0 = savage_in32(FIFO_CONTROL_REG);
+		par->MMPR1 = savage_in32(MIU_CONTROL_REG);
+		par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG);
+		par->MMPR3 = savage_in32(MISC_TIMEOUT_REG);
+	}
+
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+}
+
+static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+{
+	var->xres = var->xres_virtual = modedb->xres;
+	var->yres = modedb->yres;
+        if (var->yres_virtual < var->yres)
+	    var->yres_virtual = var->yres;
+        var->xoffset = var->yoffset = 0;
+        var->pixclock = modedb->pixclock;
+        var->left_margin = modedb->left_margin;
+        var->right_margin = modedb->right_margin;
+        var->upper_margin = modedb->upper_margin;
+        var->lower_margin = modedb->lower_margin;
+        var->hsync_len = modedb->hsync_len;
+        var->vsync_len = modedb->vsync_len;
+        var->sync = modedb->sync;
+        var->vmode = modedb->vmode;
+}
+
+static int savagefb_check_var (struct fb_var_screeninfo   *var,
+			       struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int memlen, vramlen, mode_valid = 0;
+
+	DBG("savagefb_check_var");
+
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset = var->green.offset =
+			var->blue.offset = 0;
+		var->red.length = var->green.length =
+			var->blue.length = var->bits_per_pixel;
+		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;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+		mode_valid = 1;
+
+	/* calculate modeline if supported by monitor */
+	if (!mode_valid && info->monspecs.gtf) {
+		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			mode_valid = 1;
+	}
+
+	if (!mode_valid) {
+		struct fb_videomode *mode;
+
+		mode = fb_find_best_mode(var, &info->modelist);
+		if (mode) {
+			savage_update_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && info->monspecs.modedb_len)
+		return -EINVAL;
+
+	/* Is the mode larger than the LCD panel? */
+	if (par->SavagePanelWidth &&
+	    (var->xres > par->SavagePanelWidth ||
+	     var->yres > par->SavagePanelHeight)) {
+		printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
+			"(%dx%d)\n", var->xres,  var->yres,
+			par->SavagePanelWidth,
+			par->SavagePanelHeight);
+		return -1;
+	}
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	vramlen = info->fix.smem_len;
+
+	memlen = var->xres_virtual * var->bits_per_pixel *
+		var->yres_virtual / 8;
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen * 8 /
+			(var->xres_virtual * var->bits_per_pixel);
+		memlen = var->xres_virtual * var->bits_per_pixel *
+			var->yres_virtual / 8;
+	}
+
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	return 0;
+}
+
+
+static int savagefb_decode_var (struct fb_var_screeninfo   *var,
+				struct savagefb_par        *par)
+{
+	struct xtimings timings;
+	int width, dclk, i, j; /*, refresh; */
+	unsigned int m, n, r;
+	unsigned char tmp = 0;
+	unsigned int pixclock = var->pixclock;
+
+	DBG("savagefb_decode_var");
+
+	memset (&timings, 0, sizeof(timings));
+
+	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+	timings.Clock = 1000000000 / pixclock;
+	if (timings.Clock < 1) timings.Clock = 1;
+	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = var->xres;
+	timings.HSyncStart = timings.HDisplay + var->right_margin;
+	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+	timings.HTotal = timings.HSyncEnd + var->left_margin;
+	timings.VDisplay = var->yres;
+	timings.VSyncStart = timings.VDisplay + var->lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+	timings.VTotal = timings.VSyncEnd + var->upper_margin;
+	timings.sync = var->sync;
+
+
+	par->depth  = var->bits_per_pixel;
+	par->vwidth = var->xres_virtual;
+
+	if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
+		timings.HDisplay *= 2;
+		timings.HSyncStart *= 2;
+		timings.HSyncEnd *= 2;
+		timings.HTotal *= 2;
+	}
+
+	/*
+	 * This will allocate the datastructure and initialize all of the
+	 * generic VGA registers.
+	 */
+	vgaHWInit (var, par, &timings);
+
+	/* We need to set CR67 whether or not we use the BIOS. */
+
+	dclk = timings.Clock;
+	par->CR67 = 0x00;
+
+	switch( var->bits_per_pixel ) {
+	case 8:
+		if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
+			par->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
+		else
+			par->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
+		break;
+	case 15:
+		if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+			par->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
+		else
+			par->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
+		break;
+	case 16:
+		if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+			par->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
+		else
+			par->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
+		break;
+	case 24:
+		par->CR67 = 0x70;
+		break;
+	case 32:
+		par->CR67 = 0xd0;
+		break;
+	}
+
+	/*
+	 * Either BIOS use is disabled, or we failed to find a suitable
+	 * match.  Fall back to traditional register-crunching.
+	 */
+
+	vga_out8 (0x3d4, 0x3a);
+	tmp = vga_in8 (0x3d5);
+	if (1 /*FIXME:psav->pci_burst*/)
+		par->CR3A = (tmp & 0x7f) | 0x15;
+	else
+		par->CR3A = tmp | 0x95;
+
+	par->CR53 = 0x00;
+	par->CR31 = 0x8c;
+	par->CR66 = 0x89;
+
+	vga_out8 (0x3d4, 0x58);
+	par->CR58 = vga_in8 (0x3d5) & 0x80;
+	par->CR58 |= 0x13;
+
+	par->SR15 = 0x03 | 0x80;
+	par->SR18 = 0x00;
+	par->CR43 = par->CR45 = par->CR65 = 0x00;
+
+	vga_out8 (0x3d4, 0x40);
+	par->CR40 = vga_in8 (0x3d5) & ~0x01;
+
+	par->MMPR0 = 0x010400;
+	par->MMPR1 = 0x00;
+	par->MMPR2 = 0x0808;
+	par->MMPR3 = 0x08080810;
+
+	SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
+	/* m = 107; n = 4; r = 2; */
+
+	if (par->MCLK <= 0) {
+		par->SR10 = 255;
+		par->SR11 = 255;
+	} else {
+		common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
+				   &par->SR11, &par->SR10);
+		/*      par->SR10 = 80; // MCLK == 286000 */
+		/*      par->SR11 = 125; */
+	}
+
+	par->SR12 = (r << 6) | (n & 0x3f);
+	par->SR13 = m & 0xff;
+	par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+
+	if (var->bits_per_pixel < 24)
+		par->MMPR0 -= 0x8000;
+	else
+		par->MMPR0 -= 0x4000;
+
+	if (timings.interlaced)
+		par->CR42 = 0x20;
+	else
+		par->CR42 = 0x00;
+
+	par->CR34 = 0x10; /* display fifo */
+
+	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
+		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
+		((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
+		((timings.HSyncStart & 0x800) >> 7);
+
+	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
+		i |= 0x08;
+	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
+		i |= 0x20;
+
+	j = (par->CRTC[0] + ((i & 0x01) << 8) +
+	     par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+
+	if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+		if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+		    par->CRTC[0] + ((i & 0x01) << 8))
+			j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
+		else
+			j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
+	}
+
+	par->CR3B = j & 0xff;
+	i |= (j & 0x100) >> 2;
+	par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
+	par->CR5D = i;
+	par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
+		(((timings.VDisplay - 1) & 0x400) >> 9) |
+		(((timings.VSyncStart) & 0x400) >> 8) |
+		(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
+	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
+	par->CR91 = par->CRTC[19] = 0xff & width;
+	par->CR51 = (0x300 & width) >> 4;
+	par->CR90 = 0x80 | (width >> 8);
+	par->MiscOutReg |= 0x0c;
+
+	/* Set frame buffer description. */
+
+	if (var->bits_per_pixel <= 8)
+		par->CR50 = 0;
+	else if (var->bits_per_pixel <= 16)
+		par->CR50 = 0x10;
+	else
+		par->CR50 = 0x30;
+
+	if (var->xres_virtual <= 640)
+		par->CR50 |= 0x40;
+	else if (var->xres_virtual == 800)
+		par->CR50 |= 0x80;
+	else if (var->xres_virtual == 1024)
+		par->CR50 |= 0x00;
+	else if (var->xres_virtual == 1152)
+		par->CR50 |= 0x01;
+	else if (var->xres_virtual == 1280)
+		par->CR50 |= 0xc0;
+	else if (var->xres_virtual == 1600)
+		par->CR50 |= 0x81;
+	else
+		par->CR50 |= 0xc1;	/* Use GBD */
+
+	if( par->chip == S3_SAVAGE2000 )
+		par->CR33 = 0x08;
+	else
+		par->CR33 = 0x20;
+
+	par->CRTC[0x17] = 0xeb;
+
+	par->CR67 |= 1;
+
+	vga_out8(0x3d4, 0x36);
+	par->CR36 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x68);
+	par->CR68 = vga_in8 (0x3d5);
+	par->CR69 = 0;
+	vga_out8 (0x3d4, 0x6f);
+	par->CR6F = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x86);
+	par->CR86 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x88);
+	par->CR88 = vga_in8 (0x3d5) | 0x08;
+	vga_out8 (0x3d4, 0xb0);
+	par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int savagefb_setcolreg(unsigned        regno,
+			      unsigned        red,
+			      unsigned        green,
+			      unsigned        blue,
+			      unsigned        transp,
+			      struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	if (regno >= NR_PALETTE)
+		return -EINVAL;
+
+	par->palette[regno].red    = red;
+	par->palette[regno].green  = green;
+	par->palette[regno].blue   = blue;
+	par->palette[regno].transp = transp;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		vga_out8 (0x3c8, regno);
+
+		vga_out8 (0x3c9, red   >> 10);
+		vga_out8 (0x3c9, green >> 10);
+		vga_out8 (0x3c9, blue  >> 10);
+		break;
+
+	case 16:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((red   & 0xf800)      ) |
+				((green & 0xfc00) >>  5) |
+				((blue  & 0xf800) >> 11);
+		break;
+
+	case 24:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((red    & 0xff00) <<  8) |
+				((green  & 0xff00)      ) |
+				((blue   & 0xff00) >>  8);
+		break;
+	case 32:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((transp & 0xff00) << 16) |
+				((red    & 0xff00) <<  8) |
+				((green  & 0xff00)      ) |
+				((blue   & 0xff00) >>  8);
+		break;
+
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static void savagefb_set_par_int (struct savagefb_par  *par)
+{
+	unsigned char tmp, cr3a, cr66, cr67;
+
+	DBG ("savagefb_set_par_int");
+
+	par->SavageWaitIdle (par);
+
+	vga_out8 (0x3c2, 0x23);
+
+	vga_out16 (0x3d4, 0x4838);
+	vga_out16 (0x3d4, 0xa539);
+	vga_out16 (0x3c4, 0x0608);
+
+	vgaHWProtect (par, 1);
+
+	/*
+	 * Some Savage/MX and /IX systems go nuts when trying to exit the
+	 * server after WindowMaker has displayed a gradient background.  I
+	 * haven't been able to find what causes it, but a non-destructive
+	 * switch to mode 3 here seems to eliminate the issue.
+	 */
+
+	VerticalRetraceWait();
+	vga_out8 (0x3d4, 0x67);
+	cr67 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */
+
+	vga_out8 (0x3d4, 0x23);
+	vga_out8 (0x3d5, 0x00);
+	vga_out8 (0x3d4, 0x26);
+	vga_out8 (0x3d5, 0x00);
+
+	/* restore extended regs */
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, par->CR66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, par->CR3A);
+	vga_out8 (0x3d4, 0x31);
+	vga_out8 (0x3d5, par->CR31);
+	vga_out8 (0x3d4, 0x32);
+	vga_out8 (0x3d5, par->CR32);
+	vga_out8 (0x3d4, 0x58);
+	vga_out8 (0x3d5, par->CR58);
+	vga_out8 (0x3d4, 0x53);
+	vga_out8 (0x3d5, par->CR53 & 0x7f);
+
+	vga_out16 (0x3c4, 0x0608);
+
+	/* Restore DCLK registers. */
+
+	vga_out8 (0x3c4, 0x0e);
+	vga_out8 (0x3c5, par->SR0E);
+	vga_out8 (0x3c4, 0x0f);
+	vga_out8 (0x3c5, par->SR0F);
+	vga_out8 (0x3c4, 0x29);
+	vga_out8 (0x3c5, par->SR29);
+	vga_out8 (0x3c4, 0x15);
+	vga_out8 (0x3c5, par->SR15);
+
+	/* Restore flat panel expansion regsters. */
+	if( par->chip == S3_SAVAGE_MX ) {
+		int i;
+
+		for( i = 0; i < 8; i++ ) {
+			vga_out8 (0x3c4, 0x54+i);
+			vga_out8 (0x3c5, par->SR54[i]);
+		}
+	}
+
+	vgaHWRestore (par);
+
+	/* extended mode timing registers */
+	vga_out8 (0x3d4, 0x53);
+	vga_out8 (0x3d5, par->CR53);
+	vga_out8 (0x3d4, 0x5d);
+	vga_out8 (0x3d5, par->CR5D);
+	vga_out8 (0x3d4, 0x5e);
+	vga_out8 (0x3d5, par->CR5E);
+	vga_out8 (0x3d4, 0x3b);
+	vga_out8 (0x3d5, par->CR3B);
+	vga_out8 (0x3d4, 0x3c);
+	vga_out8 (0x3d5, par->CR3C);
+	vga_out8 (0x3d4, 0x43);
+	vga_out8 (0x3d5, par->CR43);
+	vga_out8 (0x3d4, 0x65);
+	vga_out8 (0x3d5, par->CR65);
+
+	/* restore the desired video mode with cr67 */
+	vga_out8 (0x3d4, 0x67);
+	/* following part not present in X11 driver */
+	cr67 = vga_in8 (0x3d5) & 0xf;
+	vga_out8 (0x3d5, 0x50 | cr67);
+	udelay (10000);
+	vga_out8 (0x3d4, 0x67);
+	/* end of part */
+	vga_out8 (0x3d5, par->CR67 & ~0x0c);
+
+	/* other mode timing and extended regs */
+	vga_out8 (0x3d4, 0x34);
+	vga_out8 (0x3d5, par->CR34);
+	vga_out8 (0x3d4, 0x40);
+	vga_out8 (0x3d5, par->CR40);
+	vga_out8 (0x3d4, 0x42);
+	vga_out8 (0x3d5, par->CR42);
+	vga_out8 (0x3d4, 0x45);
+	vga_out8 (0x3d5, par->CR45);
+	vga_out8 (0x3d4, 0x50);
+	vga_out8 (0x3d5, par->CR50);
+	vga_out8 (0x3d4, 0x51);
+	vga_out8 (0x3d5, par->CR51);
+
+	/* memory timings */
+	vga_out8 (0x3d4, 0x36);
+	vga_out8 (0x3d5, par->CR36);
+	vga_out8 (0x3d4, 0x60);
+	vga_out8 (0x3d5, par->CR60);
+	vga_out8 (0x3d4, 0x68);
+	vga_out8 (0x3d5, par->CR68);
+	vga_out8 (0x3d4, 0x69);
+	vga_out8 (0x3d5, par->CR69);
+	vga_out8 (0x3d4, 0x6f);
+	vga_out8 (0x3d5, par->CR6F);
+
+	vga_out8 (0x3d4, 0x33);
+	vga_out8 (0x3d5, par->CR33);
+	vga_out8 (0x3d4, 0x86);
+	vga_out8 (0x3d5, par->CR86);
+	vga_out8 (0x3d4, 0x88);
+	vga_out8 (0x3d5, par->CR88);
+	vga_out8 (0x3d4, 0x90);
+	vga_out8 (0x3d5, par->CR90);
+	vga_out8 (0x3d4, 0x91);
+	vga_out8 (0x3d5, par->CR91);
+
+	if (par->chip == S3_SAVAGE4) {
+		vga_out8 (0x3d4, 0xb0);
+		vga_out8 (0x3d5, par->CRB0);
+	}
+
+	vga_out8 (0x3d4, 0x32);
+	vga_out8 (0x3d5, par->CR32);
+
+	/* unlock extended seq regs */
+	vga_out8 (0x3c4, 0x08);
+	vga_out8 (0x3c5, 0x06);
+
+	/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
+	 * that we should leave the default SR10 and SR11 values there.
+	 */
+	if (par->SR10 != 255) {
+		vga_out8 (0x3c4, 0x10);
+		vga_out8 (0x3c5, par->SR10);
+		vga_out8 (0x3c4, 0x11);
+		vga_out8 (0x3c5, par->SR11);
+	}
+
+	/* restore extended seq regs for dclk */
+	vga_out8 (0x3c4, 0x0e);
+	vga_out8 (0x3c5, par->SR0E);
+	vga_out8 (0x3c4, 0x0f);
+	vga_out8 (0x3c5, par->SR0F);
+	vga_out8 (0x3c4, 0x12);
+	vga_out8 (0x3c5, par->SR12);
+	vga_out8 (0x3c4, 0x13);
+	vga_out8 (0x3c5, par->SR13);
+	vga_out8 (0x3c4, 0x29);
+	vga_out8 (0x3c5, par->SR29);
+
+	vga_out8 (0x3c4, 0x18);
+	vga_out8 (0x3c5, par->SR18);
+
+	/* load new m, n pll values for dclk & mclk */
+	vga_out8 (0x3c4, 0x15);
+	tmp = vga_in8 (0x3c5) & ~0x21;
+
+	vga_out8 (0x3c5, tmp | 0x03);
+	vga_out8 (0x3c5, tmp | 0x23);
+	vga_out8 (0x3c5, tmp | 0x03);
+	vga_out8 (0x3c5, par->SR15);
+	udelay (100);
+
+	vga_out8 (0x3c4, 0x30);
+	vga_out8 (0x3c5, par->SR30);
+	vga_out8 (0x3c4, 0x08);
+	vga_out8 (0x3c5, par->SR08);
+
+	/* now write out cr67 in full, possibly starting STREAMS */
+	VerticalRetraceWait();
+	vga_out8 (0x3d4, 0x67);
+	vga_out8 (0x3d5, par->CR67);
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+
+	if (par->chip != S3_SAVAGE_MX) {
+		VerticalRetraceWait();
+		savage_out32 (FIFO_CONTROL_REG, par->MMPR0);
+		par->SavageWaitIdle (par);
+		savage_out32 (MIU_CONTROL_REG, par->MMPR1);
+		par->SavageWaitIdle (par);
+		savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2);
+		par->SavageWaitIdle (par);
+		savage_out32 (MISC_TIMEOUT_REG, par->MMPR3);
+	}
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	SavageSetup2DEngine (par);
+	vgaHWProtect (par, 0);
+}
+
+static void savagefb_update_start (struct savagefb_par      *par,
+				   struct fb_var_screeninfo *var)
+{
+	int base;
+
+	base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
+		* ((var->bits_per_pixel+7) / 8)) >> 2;
+
+	/* now program the start address registers */
+	vga_out16(0x3d4, (base & 0x00ff00) | 0x0c);
+	vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d);
+	vga_out8 (0x3d4, 0x69);
+	vga_out8 (0x3d5, (base & 0x7f0000) >> 16);
+}
+
+
+static void savagefb_set_fix(struct fb_info *info)
+{
+	info->fix.line_length = info->var.xres_virtual *
+		info->var.bits_per_pixel / 8;
+
+	if (info->var.bits_per_pixel == 8)
+		info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual      = FB_VISUAL_TRUECOLOR;
+}
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+static void savagefb_set_clip(struct fb_info *info)
+{
+    struct savagefb_par *par = (struct savagefb_par *)info->par;
+    int cmd;
+
+    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+    par->bci_ptr = 0;
+    par->SavageWaitFifo(par,3);
+    BCI_SEND(cmd);
+    BCI_SEND(BCI_CLIP_TL(0, 0));
+    BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
+}
+#endif
+
+static int savagefb_set_par (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int err;
+
+	DBG("savagefb_set_par");
+	err = savagefb_decode_var (var, par);
+	if (err)
+		return err;
+
+	if (par->dacSpeedBpp <= 0) {
+		if (var->bits_per_pixel > 24)
+			par->dacSpeedBpp = par->clock[3];
+		else if (var->bits_per_pixel >= 24)
+			par->dacSpeedBpp = par->clock[2];
+		else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
+			par->dacSpeedBpp = par->clock[1];
+		else if (var->bits_per_pixel <= 8)
+			par->dacSpeedBpp = par->clock[0];
+	}
+
+	/* Set ramdac limits */
+	par->maxClock = par->dacSpeedBpp;
+	par->minClock = 10000;
+
+	savagefb_set_par_int (par);
+	savagefb_update_start (par, var);
+	fb_set_cmap (&info->cmap, info);
+	savagefb_set_fix(info);
+	savagefb_set_clip(info);
+
+	SavagePrintRegs();
+	return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int savagefb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info           *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	u_int y_bottom;
+
+	y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (y_bottom > info->var.yres_virtual)
+		return -EINVAL;
+
+	savagefb_update_start (par, var);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+
+static struct fb_ops savagefb_ops = {
+	.owner          = THIS_MODULE,
+	.fb_check_var   = savagefb_check_var,
+	.fb_set_par     = savagefb_set_par,
+	.fb_setcolreg   = savagefb_setcolreg,
+	.fb_pan_display = savagefb_pan_display,
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	.fb_fillrect    = savagefb_fillrect,
+	.fb_copyarea    = savagefb_copyarea,
+	.fb_imageblit   = savagefb_imageblit,
+	.fb_sync        = savagefb_sync,
+#else
+	.fb_fillrect    = cfb_fillrect,
+	.fb_copyarea    = cfb_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+#endif
+	.fb_cursor      = soft_cursor,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
+	.accel_flags =	FB_ACCELF_TEXT,
+	.xres =		800,
+	.yres =		600,
+	.xres_virtual =  800,
+	.yres_virtual =  600,
+	.bits_per_pixel = 8,
+	.pixclock =	25000,
+	.left_margin =	88,
+	.right_margin =	40,
+	.upper_margin =	23,
+	.lower_margin =	1,
+	.hsync_len =	128,
+	.vsync_len =	4,
+	.sync =		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+static void savage_enable_mmio (struct savagefb_par *par)
+{
+	unsigned char val;
+
+	DBG ("savage_enable_mmio\n");
+
+	val = vga_in8 (0x3c3);
+	vga_out8 (0x3c3, val | 0x01);
+	val = vga_in8 (0x3cc);
+	vga_out8 (0x3c2, val | 0x01);
+
+	if (par->chip >= S3_SAVAGE4) {
+		vga_out8 (0x3d4, 0x40);
+		val = vga_in8 (0x3d5);
+		vga_out8 (0x3d5, val | 1);
+	}
+}
+
+
+static void savage_disable_mmio (struct savagefb_par *par)
+{
+	unsigned char val;
+
+	DBG ("savage_disable_mmio\n");
+
+	if(par->chip >= S3_SAVAGE4 ) {
+		vga_out8 (0x3d4, 0x40);
+		val = vga_in8 (0x3d5);
+		vga_out8 (0x3d5, val | 1);
+	}
+}
+
+
+static int __devinit savage_map_mmio (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	DBG ("savage_map_mmio");
+
+	if (S3_SAVAGE3D_SERIES (par->chip))
+		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+			SAVAGE_NEWMMIO_REGBASE_S3;
+	else
+		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+			SAVAGE_NEWMMIO_REGBASE_S4;
+
+	par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
+
+	par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
+	if (!par->mmio.vbase) {
+		printk ("savagefb: unable to map memory mapped IO\n");
+		return -ENOMEM;
+	} else
+		printk (KERN_INFO "savagefb: mapped io at %p\n",
+			par->mmio.vbase);
+
+	info->fix.mmio_start = par->mmio.pbase;
+	info->fix.mmio_len   = par->mmio.len;
+
+	par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
+	par->bci_ptr  = 0;
+
+	savage_enable_mmio (par);
+
+	return 0;
+}
+
+static void __devinit savage_unmap_mmio (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	DBG ("savage_unmap_mmio");
+
+	savage_disable_mmio(par);
+
+	if (par->mmio.vbase) {
+		iounmap(par->mmio.vbase);
+		par->mmio.vbase = NULL;
+	}
+}
+
+static int __devinit savage_map_video (struct fb_info *info,
+				       int video_len)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int resource;
+
+	DBG("savage_map_video");
+
+	if (S3_SAVAGE3D_SERIES (par->chip))
+		resource = 0;
+	else
+		resource = 1;
+
+	par->video.pbase = pci_resource_start (par->pcidev, resource);
+	par->video.len   = video_len;
+	par->video.vbase = ioremap (par->video.pbase, par->video.len);
+
+	if (!par->video.vbase) {
+		printk ("savagefb: unable to map screen memory\n");
+		return -ENOMEM;
+	} else
+		printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
+			"pbase == %x\n", par->video.vbase, par->video.pbase);
+
+	info->fix.smem_start = par->video.pbase;
+	info->fix.smem_len   = par->video.len - par->cob_size;
+	info->screen_base    = par->video.vbase;
+
+#ifdef CONFIG_MTRR
+	par->video.mtrr = mtrr_add (par->video.pbase, video_len,
+				     MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	/* Clear framebuffer, it's all white in memory after boot */
+	memset_io (par->video.vbase, 0, par->video.len);
+
+	return 0;
+}
+
+static void __devinit savage_unmap_video (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savage_unmap_video");
+
+	if (par->video.vbase) {
+#ifdef CONFIG_MTRR
+		mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
+#endif
+
+		iounmap (par->video.vbase);
+		par->video.vbase = NULL;
+		info->screen_base = NULL;
+	}
+}
+
+static int __devinit savage_init_hw (struct savagefb_par *par)
+{
+	unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
+
+	static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
+	static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+	static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
+
+	int videoRam, videoRambytes;
+
+	DBG("savage_init_hw");
+
+	/* unprotect CRTC[0-7] */
+	vga_out8(0x3d4, 0x11);
+	tmp = vga_in8(0x3d5);
+	vga_out8(0x3d5, tmp & 0x7f);
+
+	/* unlock extended regs */
+	vga_out16(0x3d4, 0x4838);
+	vga_out16(0x3d4, 0xa039);
+	vga_out16(0x3c4, 0x0608);
+
+	vga_out8(0x3d4, 0x40);
+	tmp = vga_in8(0x3d5);
+	vga_out8(0x3d5, tmp & ~0x01);
+
+	/* unlock sys regs */
+	vga_out8(0x3d4, 0x38);
+	vga_out8(0x3d5, 0x48);
+
+	/* Unlock system registers. */
+	vga_out16(0x3d4, 0x4838);
+
+	/* Next go on to detect amount of installed ram */
+
+	vga_out8(0x3d4, 0x36);            /* for register CR36 (CONFG_REG1), */
+	config1 = vga_in8(0x3d5);           /* get amount of vram installed */
+
+	/* Compute the amount of video memory and offscreen memory. */
+
+	switch  (par->chip) {
+	case S3_SAVAGE3D:
+		videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+		break;
+
+	case S3_SAVAGE4:
+		/*
+		 * The Savage4 has one ugly special case to consider.  On
+		 * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
+		 * when it really means 8MB.  Why do it the same when you
+		 * can do it different...
+		 */
+		vga_out8(0x3d4, 0x68);	/* memory control 1 */
+		if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) )
+			RamSavage4[1] = 8;
+
+		/*FALLTHROUGH*/
+
+	case S3_SAVAGE2000:
+		videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+		break;
+
+	case S3_SAVAGE_MX:
+	case S3_SUPERSAVAGE:
+		videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+		break;
+
+	case S3_PROSAVAGE:
+		videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+		break;
+
+	default:
+		/* How did we get here? */
+		videoRam = 0;
+		break;
+	}
+
+	videoRambytes = videoRam * 1024;
+
+	printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
+
+	/* reset graphics engine to avoid memory corruption */
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x02);
+	udelay (10000);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66 & ~0x02);	/* clear reset flag */
+	udelay (10000);
+
+
+	/*
+	 * reset memory interface, 3D engine, AGP master, PCI master,
+	 * master engine unit, motion compensation/LPB
+	 */
+	vga_out8 (0x3d4, 0x3f);
+	cr3f = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3f | 0x08);
+	udelay (10000);
+
+	vga_out8 (0x3d4, 0x3f);
+	vga_out8 (0x3d5, cr3f & ~0x08);	/* clear reset flags */
+	udelay (10000);
+
+	/* Savage ramdac speeds */
+	par->numClocks = 4;
+	par->clock[0] = 250000;
+	par->clock[1] = 250000;
+	par->clock[2] = 220000;
+	par->clock[3] = 220000;
+
+	/* detect current mclk */
+	vga_out8(0x3c4, 0x08);
+	sr8 = vga_in8(0x3c5);
+	vga_out8(0x3c5, 0x06);
+	vga_out8(0x3c4, 0x10);
+	n = vga_in8(0x3c5);
+	vga_out8(0x3c4, 0x11);
+	m = vga_in8(0x3c5);
+	vga_out8(0x3c4, 0x08);
+	vga_out8(0x3c5, sr8);
+	m &= 0x7f;
+	n1 = n & 0x1f;
+	n2 = (n >> 5) & 0x03;
+	par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
+	printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
+		par->MCLK);
+
+	/* Check LCD panel parrmation */
+
+	if (par->chip == S3_SAVAGE_MX) {
+		unsigned char cr6b = VGArCR( 0x6b );
+
+		int panelX = (VGArSEQ (0x61) +
+			      ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8;
+		int panelY = (VGArSEQ (0x69) +
+			      ((VGArSEQ (0x6e) & 0x70) << 4) + 1);
+
+		char * sTechnology = "Unknown";
+
+		/* OK, I admit it.  I don't know how to limit the max dot clock
+		 * for LCD panels of various sizes.  I thought I copied the
+		 * formula from the BIOS, but many users have parrmed me of
+		 * my folly.
+		 *
+		 * Instead, I'll abandon any attempt to automatically limit the
+		 * clock, and add an LCDClock option to XF86Config.  Some day,
+		 * I should come back to this.
+		 */
+
+		enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+			ActiveCRT = 0x01,
+			ActiveLCD = 0x02,
+			ActiveTV = 0x04,
+			ActiveCRT2 = 0x20,
+			ActiveDUO = 0x80
+		};
+
+		if ((VGArSEQ (0x39) & 0x03) == 0) {
+			sTechnology = "TFT";
+		} else if ((VGArSEQ (0x30) & 0x01) == 0) {
+			sTechnology = "DSTN";
+		} else 	{
+			sTechnology = "STN";
+		}
+
+		printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
+			panelX, panelY, sTechnology,
+			cr6b & ActiveLCD ? "and active" : "but not active");
+
+		if( cr6b & ActiveLCD ) 	{
+			/*
+			 * If the LCD is active and panel expansion is enabled,
+			 * we probably want to kill the HW cursor.
+			 */
+
+			printk (KERN_INFO "savagefb: Limiting video mode to "
+				"%dx%d\n", panelX, panelY );
+
+			par->SavagePanelWidth = panelX;
+			par->SavagePanelHeight = panelY;
+
+		}
+	}
+
+	savage_get_default_par (par);
+
+	if( S3_SAVAGE4_SERIES(par->chip) ) {
+		/*
+		 * The Savage4 and ProSavage have COB coherency bugs which
+		 * render the buffer useless.  We disable it.
+		 */
+		par->cob_index = 2;
+		par->cob_size = 0x8000 << par->cob_index;
+		par->cob_offset = videoRambytes;
+	} else {
+		/* We use 128kB for the COB on all chips. */
+
+		par->cob_index  = 7;
+		par->cob_size   = 0x400 << par->cob_index;
+		par->cob_offset = videoRambytes - par->cob_size;
+	}
+
+	return videoRambytes;
+}
+
+static int __devinit savage_init_fb_info (struct fb_info *info,
+					  struct pci_dev *dev,
+					  const struct pci_device_id *id)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int err = 0;
+
+	par->pcidev  = dev;
+
+	info->fix.type	   = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	   = 0;
+	info->fix.xpanstep	   = 2;
+	info->fix.ypanstep	   = 1;
+	info->fix.ywrapstep   = 0;
+	info->fix.accel       = id->driver_data;
+
+	switch (info->fix.accel) {
+	case FB_ACCEL_SUPERSAVAGE:
+		par->chip = S3_SUPERSAVAGE;
+		snprintf (info->fix.id, 16, "SuperSavage");
+		break;
+	case FB_ACCEL_SAVAGE4:
+		par->chip = S3_SAVAGE4;
+		snprintf (info->fix.id, 16, "Savage4");
+		break;
+	case FB_ACCEL_SAVAGE3D:
+		par->chip = S3_SAVAGE3D;
+		snprintf (info->fix.id, 16, "Savage3D");
+		break;
+	case FB_ACCEL_SAVAGE3D_MV:
+		par->chip = S3_SAVAGE3D;
+		snprintf (info->fix.id, 16, "Savage3D-MV");
+		break;
+	case FB_ACCEL_SAVAGE2000:
+		par->chip = S3_SAVAGE2000;
+		snprintf (info->fix.id, 16, "Savage2000");
+		break;
+	case FB_ACCEL_SAVAGE_MX_MV:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/MX-MV");
+		break;
+	case FB_ACCEL_SAVAGE_MX:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/MX");
+		break;
+	case FB_ACCEL_SAVAGE_IX_MV:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/IX-MV");
+		break;
+	case FB_ACCEL_SAVAGE_IX:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/IX");
+		break;
+	case FB_ACCEL_PROSAVAGE_PM:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavagePM");
+		break;
+	case FB_ACCEL_PROSAVAGE_KM:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavageKM");
+		break;
+	case FB_ACCEL_S3TWISTER_P:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "TwisterP");
+		break;
+	case FB_ACCEL_S3TWISTER_K:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "TwisterK");
+		break;
+	case FB_ACCEL_PROSAVAGE_DDR:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavageDDR");
+		break;
+	case FB_ACCEL_PROSAVAGE_DDRK:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavage8");
+		break;
+	}
+
+	if (S3_SAVAGE3D_SERIES(par->chip)) {
+		par->SavageWaitIdle = savage3D_waitidle;
+		par->SavageWaitFifo = savage3D_waitfifo;
+	} else if (S3_SAVAGE4_SERIES(par->chip) ||
+		   S3_SUPERSAVAGE == par->chip) {
+		par->SavageWaitIdle = savage4_waitidle;
+		par->SavageWaitFifo = savage4_waitfifo;
+	} else {
+		par->SavageWaitIdle = savage2000_waitidle;
+		par->SavageWaitFifo = savage2000_waitfifo;
+	}
+
+	info->var.nonstd      = 0;
+	info->var.activate    = FB_ACTIVATE_NOW;
+	info->var.width       = -1;
+	info->var.height      = -1;
+	info->var.accel_flags = 0;
+
+	info->fbops          = &savagefb_ops;
+	info->flags          = FBINFO_DEFAULT |
+		               FBINFO_HWACCEL_YPAN |
+		               FBINFO_HWACCEL_XPAN;
+
+	info->pseudo_palette = par->pseudo_palette;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	/* FIFO size + padding for commands */
+	info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+
+	err = -ENOMEM;
+	if (info->pixmap.addr) {
+		memset(info->pixmap.addr, 0, 8*1024);
+		info->pixmap.size = 8*1024;
+		info->pixmap.scan_align = 4;
+		info->pixmap.buf_align = 4;
+		info->pixmap.access_align = 4;
+
+		fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
+		info->flags |= FBINFO_HWACCEL_COPYAREA |
+	                       FBINFO_HWACCEL_FILLRECT |
+		               FBINFO_HWACCEL_IMAGEBLIT;
+
+		err = 0;
+	}
+#endif
+	return err;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit savagefb_probe (struct pci_dev* dev,
+				     const struct pci_device_id* id)
+{
+	struct fb_info *info;
+	struct savagefb_par *par;
+	u_int h_sync, v_sync;
+	int err, lpitch;
+	int video_len;
+
+	DBG("savagefb_probe");
+	SavagePrintRegs();
+
+	info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
+	if (!info)
+		return -ENOMEM;
+	par = info->par;
+	err = pci_enable_device(dev);
+	if (err)
+		goto failed_enable;
+
+	if (pci_request_regions(dev, "savagefb")) {
+		printk(KERN_ERR "cannot request PCI regions\n");
+		goto failed_enable;
+	}
+
+	err = -ENOMEM;
+
+	if (savage_init_fb_info(info, dev, id))
+		goto failed_init;
+
+	err = savage_map_mmio(info);
+	if (err)
+		goto failed_mmio;
+
+	video_len = savage_init_hw(par);
+	if (video_len < 0) {
+		err = video_len;
+		goto failed_mmio;
+	}
+
+	err = savage_map_video(info, video_len);
+	if (err)
+		goto failed_video;
+
+	INIT_LIST_HEAD(&info->modelist);
+#if defined(CONFIG_FB_SAVAGE_I2C)
+	savagefb_create_i2c_busses(info);
+	savagefb_probe_i2c_connector(par, &par->edid);
+	fb_edid_to_monspecs(par->edid, &info->monspecs);
+	fb_videomode_to_modelist(info->monspecs.modedb,
+				 info->monspecs.modedb_len,
+				 &info->modelist);
+#endif
+	info->var = savagefb_var800x600x8;
+
+	if (mode_option) {
+		fb_find_mode(&info->var, info, mode_option,
+			     info->monspecs.modedb, info->monspecs.modedb_len,
+			     NULL, 8);
+	} else if (info->monspecs.modedb != NULL) {
+		struct fb_monspecs *specs = &info->monspecs;
+		struct fb_videomode modedb;
+
+		if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = specs->modedb[0];
+		}
+
+		savage_update_var(&info->var, &modedb);
+	}
+
+	/* maximize virtual vertical length */
+	lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
+	info->var.yres_virtual = info->fix.smem_len/lpitch;
+
+	if (info->var.yres_virtual < info->var.yres)
+		goto failed;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	/*
+	 * The clipping coordinates are masked with 0xFFF, so limit our
+	 * virtual resolutions to these sizes.
+	 */
+	if (info->var.yres_virtual > 0x1000)
+		info->var.yres_virtual = 0x1000;
+
+	if (info->var.xres_virtual > 0x1000)
+		info->var.xres_virtual = 0x1000;
+#endif
+	savagefb_check_var(&info->var, info);
+	savagefb_set_fix(info);
+
+	/*
+	 * Calculate the hsync and vsync frequencies.  Note that
+	 * we split the 1e12 constant up so that we can preserve
+	 * the precision and fit the results into 32-bit registers.
+	 *  (1953125000 * 512 = 1e12)
+	 */
+	h_sync = 1953125000 / info->var.pixclock;
+	h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
+				 info->var.right_margin +
+				 info->var.hsync_len);
+	v_sync = h_sync / (info->var.yres + info->var.upper_margin +
+			   info->var.lower_margin + info->var.vsync_len);
+
+	printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
+	       "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	       info->fix.smem_len >> 10,
+	       info->var.xres, info->var.yres,
+	       h_sync / 1000, h_sync % 1000, v_sync);
+
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	err = register_framebuffer (info);
+	if (err < 0)
+		goto failed;
+
+	printk (KERN_INFO "fb: S3 %s frame buffer device\n",
+		info->fix.id);
+
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(dev, info);
+
+	return 0;
+
+ failed:
+#ifdef CONFIG_FB_SAVAGE_I2C
+	savagefb_delete_i2c_busses(info);
+#endif
+	fb_alloc_cmap (&info->cmap, 0, 0);
+	savage_unmap_video(info);
+ failed_video:
+	savage_unmap_mmio (info);
+ failed_mmio:
+	kfree(info->pixmap.addr);
+ failed_init:
+	pci_release_regions(dev);
+ failed_enable:
+	framebuffer_release(info);
+
+	return err;
+}
+
+static void __devexit savagefb_remove (struct pci_dev *dev)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+
+	DBG("savagefb_remove");
+
+	if (info) {
+		/*
+		 * If unregister_framebuffer fails, then
+		 * we will be leaving hooks that could cause
+		 * oopsen laying around.
+		 */
+		if (unregister_framebuffer (info))
+			printk (KERN_WARNING "savagefb: danger danger! "
+				"Oopsen imminent!\n");
+
+#ifdef CONFIG_FB_SAVAGE_I2C
+		savagefb_delete_i2c_busses(info);
+#endif
+		fb_alloc_cmap (&info->cmap, 0, 0);
+		savage_unmap_video (info);
+		savage_unmap_mmio (info);
+		kfree(info->pixmap.addr);
+		pci_release_regions(dev);
+		framebuffer_release(info);
+
+		/*
+		 * Ensure that the driver data is no longer
+		 * valid.
+		 */
+		pci_set_drvdata(dev, NULL);
+	}
+}
+
+static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savagefb_suspend");
+	printk(KERN_DEBUG "state: %u\n", state);
+
+	acquire_console_sem();
+	fb_set_suspend(info, state);
+	savage_disable_mmio(par);
+	release_console_sem();
+
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	return 0;
+}
+
+static int savagefb_resume (struct pci_dev* dev)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savage_resume");
+
+	pci_set_power_state(dev, 0);
+	pci_restore_state(dev);
+	if(pci_enable_device(dev))
+		DBG("err");
+
+	SavagePrintRegs();
+
+	acquire_console_sem();
+
+	savage_enable_mmio(par);
+	savage_init_hw(par);
+	savagefb_set_par (info);
+
+	fb_set_suspend (info, 0);
+	release_console_sem();
+
+	return 0;
+}
+
+
+static struct pci_device_id savagefb_devices[] __devinitdata = {
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
+
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, savagefb_devices);
+
+static struct pci_driver savagefb_driver = {
+	.name =     "savagefb",
+	.id_table = savagefb_devices,
+	.probe =    savagefb_probe,
+	.suspend =  savagefb_suspend,
+	.resume =   savagefb_resume,
+	.remove =   __devexit_p(savagefb_remove)
+};
+
+/* **************************** exit-time only **************************** */
+
+static void __exit savage_done (void)
+{
+	DBG("savage_done");
+	pci_unregister_driver (&savagefb_driver);
+}
+
+
+/* ************************* init in-kernel code ************************** */
+
+static int __init savagefb_setup(char *options)
+{
+#ifndef MODULE
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		mode_option = this_opt;
+	}
+#endif /* !MODULE */
+	return 0;
+}
+
+static int __init savagefb_init(void)
+{
+	char *option;
+
+	DBG("savagefb_init");
+
+	if (fb_get_options("savagefb", &option))
+		return -ENODEV;
+
+	savagefb_setup(option);
+	return pci_register_driver (&savagefb_driver);
+
+}
+
+module_init(savagefb_init);
+module_exit(savage_done);
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -74,10 +74,12 @@ int sbusfb_mmap_helper(struct sbus_mmap_
 		}
 		if (page + map_size > size)
 			map_size = size - page;
-		r = io_remap_page_range(vma,
+		r = io_remap_pfn_range(vma,
 					vma->vm_start + page,
-					map_offset, map_size,
-					vma->vm_page_prot, iospace);
+					MK_IOSPACE_PFN(iospace,
+						map_offset >> PAGE_SHIFT),
+					map_size,
+					vma->vm_page_prot);
 		if (r)
 			return -EAGAIN;
 		page += map_size;
diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c
--- a/drivers/video/sis/init.c
+++ b/drivers/video/sis/init.c
@@ -1384,7 +1384,7 @@ SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_
 /*             HELPER: SetLVDSetc            */
 /*********************************************/
 
-void
+static void
 SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    USHORT temp;
@@ -1625,7 +1625,7 @@ SiS_ResetSegmentRegisters(SiS_Private *S
 /*             HELPER: GetVBType             */
 /*********************************************/
 
-void
+static void
 SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
   USHORT flag=0, rev=0, nolcd=0, p4_0f, p4_25, p4_27;
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -2394,11 +2394,9 @@ void	SiS_SetRegOR(SISIOADDRESS Port,USHO
 void	SiS_DisplayOn(SiS_Private *SiS_Pr);
 void	SiS_DisplayOff(SiS_Private *SiS_Pr);
 void	SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
-void	SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 void	SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
 void	SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
-void	SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 BOOLEAN	SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex);
 UCHAR	SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
 USHORT	SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
@@ -2444,7 +2442,6 @@ extern void     SiS_GetLCDResInfo(SiS_Pr
 extern void     SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 extern void 	SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
 extern void     SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
-extern void     SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 extern void     SiS_DisableBridge(SiS_Private *, PSIS_HW_INFO);
 extern BOOLEAN  SiS_SetCRT2Group(SiS_Private *, PSIS_HW_INFO, USHORT);
 extern USHORT   SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -86,6 +86,7 @@
 #define SiS_I2CDELAYSHORT  150
 
 static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr);
+static void SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx);
 
 /*********************************************/
 /*         HELPER: Lock/Unlock CRT2          */
@@ -100,7 +101,7 @@ SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS
       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
 }
 
-void
+static void
 SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    if(HwInfo->jChipType >= SIS_315H)
@@ -4236,7 +4237,7 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, P
  * from outside the context of a mode switch!
  * MUST call getVBType before calling this
  */
-void
+static void
 SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
   USHORT temp=0,tempah;
@@ -9219,7 +9220,7 @@ SiS_SetCH701x(SiS_Private *SiS_Pr, USHOR
   SiS_SetChReg(SiS_Pr, tempbx, 0);
 }
 
-void
+static void
 SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
@@ -9323,7 +9324,7 @@ SiS_GetCH701x(SiS_Private *SiS_Pr, USHOR
 
 /* Read from Chrontel 70xx */
 /* Parameter is [Register no (S7-S0)] */
-USHORT
+static USHORT
 SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -293,7 +293,6 @@ static UCHAR SiS300_TrumpionData[7][80] 
 #endif
 
 void	SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
-void	SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 void	SiS_EnableCRT2(SiS_Private *SiS_Pr);
 USHORT	SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
 void	SiS_WaitRetrace1(SiS_Private *SiS_Pr);
@@ -310,7 +309,6 @@ USHORT	SiS_GetVCLK2Ptr(SiS_Private *SiS_
                 USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo);
 USHORT	SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex);
 void	SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
-void	SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 BOOLEAN	SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo);
 void	SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 void	SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
@@ -319,8 +317,6 @@ void   	SiS_SetCH700x(SiS_Private *SiS_P
 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);
 void   	SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
 #ifdef SIS315H
 static void   	SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -50,6 +50,7 @@
 #include <linux/fb.h>
 #include <linux/console.h>
 #include <linux/selection.h>
+#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -144,7 +145,7 @@ sisfb_setdefaultparms(void)
 #endif
 }
 
-static void __init
+static void __devinit
 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
 {
 	int i = 0, j = 0;
@@ -4761,7 +4762,8 @@ static void __devinit sisfb_post_sis3153
 #endif
 
 
-int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit sisfb_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
 {
 	struct sisfb_chip_info 	*chipinfo = &sisfb_chip_info[ent->driver_data];
 	struct sis_video_info 	*ivideo = NULL;
@@ -5639,7 +5641,7 @@ static void __devexit sisfb_remove(struc
 	/* Unmap */
 	iounmap(ivideo->video_vbase);
 	iounmap(ivideo->mmio_vbase);
-	if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+	vfree(ivideo->bios_abase);
 
 	/* Release mem regions */
 	release_mem_region(ivideo->video_base, ivideo->video_size);
@@ -5694,7 +5696,7 @@ SISINITSTATIC int __init sisfb_init(void
 	sisfb_setup(options);
 #endif
 #endif
-	return(pci_module_init(&sisfb_driver));
+	return(pci_register_driver(&sisfb_driver));
 }
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
@@ -5939,7 +5941,7 @@ MODULE_PARM_DESC(videoram,
 #endif
 #endif
 
-int __init sisfb_init_module(void)
+static int __devinit sisfb_init_module(void)
 {
 	sisfb_setdefaultparms();
 
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -120,7 +120,7 @@ static struct fb_fix_screeninfo xxxfb_fi
 static struct fb_info info;
 
     /* 
-     * Each one represents the a state of the hardware. Most hardware have 
+     * Each one represents the state of the hardware. Most hardware have
      * just one hardware state. These here represent the default state(s). 
      */
 static struct xxx_par __initdata current_par;
@@ -139,6 +139,8 @@ int xxxfb_setup(char*);
  *	Usually you don't need to provide this function. The case where it 
  *	is used is to change from a text mode hardware state to a graphics
  * 	mode state. 
+ *
+ *	Returns negative errno on error, or zero on success.
  */
 static int xxxfb_open(const struct fb_info *info, int user)
 {
@@ -156,6 +158,8 @@ static int xxxfb_open(const struct fb_in
  *	console system is released. Usually you don't need this function.
  *	The case where it is usually used is to go from a graphics state
  *	to a text mode state.
+ *
+ *	Returns negative errno on error, or zero on success.
  */
 static int xxxfb_release(const struct fb_info *info, int user)
 {
@@ -201,8 +205,9 @@ static int xxxfb_check_var(struct fb_var
  *	fb_info since we are using that data. This means we depend on the
  *	data in var inside fb_info to be supported by the hardware. 
  *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
- *	Again if you can't can't the resolution you don't need this function.
+ *	Again if you can't change the resolution you don't need this function.
  *
+ *	Returns negative errno on error, or zero on success.
  */
 static int xxxfb_set_par(struct fb_info *info)
 {
@@ -217,14 +222,14 @@ static int xxxfb_set_par(struct fb_info 
  *      @red: The red value which can be up to 16 bits wide 
  *	@green: The green value which can be up to 16 bits wide 
  *	@blue:  The blue value which can be up to 16 bits wide.
- *	@transp: If supported the alpha value which can be up to 16 bits wide.	
+ *	@transp: If supported, the alpha value which can be up to 16 bits wide.
  *      @info: frame buffer info structure
  * 
  *  	Set a single color register. The values supplied have a 16 bit
  *  	magnitude which needs to be scaled in this function for the hardware. 
  *	Things to take into consideration are how many color registers, if
  *	any, are supported with the current color visual. With truecolor mode
- *	no color palettes are supported. Here a psuedo palette is created 
+ *	no color palettes are supported. Here a pseudo palette is created
  *	which we store the value in pseudo_palette in struct fb_info. For
  *	pseudocolor mode we have a limited color palette. To deal with this
  *	we can program what color is displayed for a particular pixel value.
@@ -238,7 +243,7 @@ static int xxxfb_setcolreg(unsigned regn
 			   const struct fb_info *info)
 {
     if (regno >= 256)  /* no. of hw registers */
-       return 1;
+       return -EINVAL;
     /*
      * Program hardware... do anything you want with transp
      */
@@ -295,7 +300,7 @@ static int xxxfb_setcolreg(unsigned regn
        u32 v;
 
        if (regno >= 16)
-           return 1;
+           return -EINVAL;
 
        v = (red << info->var.red.offset) |
            (green << info->var.green.offset) |
@@ -563,7 +568,7 @@ int __init xxxfb_init(void)
 #endif
 
     /* 
-     * Here we set the screen_base to the vitrual memory address
+     * Here we set the screen_base to the virtual memory address
      * for the framebuffer. Usually we obtain the resource address
      * from the bus layer and then translate it to virtual memory
      * space via ioremap. Consult ioport.h. 
@@ -621,6 +626,7 @@ static void __exit xxxfb_cleanup(void)
      */
 
     unregister_framebuffer(info);
+    fb_dealloc_cmap(&info.cmap);
     /* ... */
 }
 
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1338,8 +1338,8 @@ static void  __devexit sst_shutdown(stru
 /*
  * Interface to the world
  */
-
-int  __init sstfb_setup(char *options)
+#ifndef MODULE
+static int  __init sstfb_setup(char *options)
 {
 	char *this_opt;
 
@@ -1372,6 +1372,7 @@ int  __init sstfb_setup(char *options)
 	}
 	return 0;
 }
+#endif
 
 static struct fb_ops sstfb_ops = {
 	.owner		= THIS_MODULE,
@@ -1565,7 +1566,7 @@ static struct pci_driver sstfb_driver = 
 };
 
 
-int __devinit sstfb_init(void)
+static int __devinit sstfb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -1574,13 +1575,15 @@ int __devinit sstfb_init(void)
 		return -ENODEV;
 	sstfb_setup(option);
 #endif
-	return pci_module_init(&sstfb_driver);
+	return pci_register_driver(&sstfb_driver);
 }
 
-void __devexit sstfb_exit(void)
+#ifdef MODULE
+static void __devexit sstfb_exit(void)
 {
 	pci_unregister_driver(&sstfb_driver);
 }
+#endif
 
 
 /*
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -112,11 +112,10 @@ struct stifb_info {
 	ngle_rom_t ngle_rom;
 	struct sti_struct *sti;
 	int deviceSpecificConfig;
-	u32 pseudo_palette[16];
+	u32 pseudo_palette[256];
 };
 
-static int __initdata bpp = 8;	/* parameter from modprobe */
-static int __initdata stifb_force_bpp[MAX_STI_ROMS];
+static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
 
 /* ------------------- chipset specific functions -------------------------- */
 
@@ -155,15 +154,15 @@ static int __initdata stifb_force_bpp[MA
 #define REG_44		0x210030
 #define REG_45		0x210034
 
-#define READ_BYTE(fb,reg)		__raw_readb((fb)->info.fix.mmio_start + (reg))
-#define READ_WORD(fb,reg)		__raw_readl((fb)->info.fix.mmio_start + (reg))
+#define READ_BYTE(fb,reg)		gsc_readb((fb)->info.fix.mmio_start + (reg))
+#define READ_WORD(fb,reg)		gsc_readl((fb)->info.fix.mmio_start + (reg))
 
 
 #ifndef DEBUG_STIFB_REGS
 # define  DEBUG_OFF()
 # define  DEBUG_ON()
-# define WRITE_BYTE(value,fb,reg)	__raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
-# define WRITE_WORD(value,fb,reg)	__raw_writel((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_BYTE(value,fb,reg)	gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_WORD(value,fb,reg)	gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
 #else
   static int debug_on = 1;
 # define  DEBUG_OFF() debug_on=0
@@ -171,11 +170,11 @@ static int __initdata stifb_force_bpp[MA
 # define WRITE_BYTE(value,fb,reg)	do { if (debug_on) \
 						printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
 							__FUNCTION__, reg, value, READ_BYTE(fb,reg)); 		  \
-					__raw_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+					gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
 # define WRITE_WORD(value,fb,reg)	do { if (debug_on) \
 						printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
 							__FUNCTION__, reg, value, READ_WORD(fb,reg)); 		  \
-					__raw_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+					gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
 #endif /* DEBUG_STIFB_REGS */
 
 
@@ -1018,6 +1017,15 @@ stifb_setcolreg(u_int regno, u_int red, 
 			 (blue));
 	}
 
+	if (info->var.bits_per_pixel == 32) {
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	} else {
+		((u32 *)(info->pseudo_palette))[regno] = regno;
+	}
+
 	WRITE_IMAGE_COLOR(fb, regno, color);
 	
 	if (fb->id == S9000_ID_HCRX) {
@@ -1031,14 +1039,6 @@ stifb_setcolreg(u_int regno, u_int red, 
 				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
 		START_COLORMAPLOAD(fb, lutBltCtl.all);
 		SETUP_FB(fb);
-
-		/* info->var.bits_per_pixel == 32 */
-		if (regno < 16) 
-		  ((u32 *)(info->pseudo_palette))[regno] =
-			(red   << info->var.red.offset)   |
-			(green << info->var.green.offset) |
-			(blue  << info->var.blue.offset);
-
 	} else {
 		/* cleanup colormap hardware */
 		FINISH_IMAGE_COLORMAP_ACCESS(fb);
@@ -1156,7 +1156,7 @@ static struct fb_ops stifb_ops = {
  */
 
 int __init
-stifb_init_fb(struct sti_struct *sti, int force_bpp)
+stifb_init_fb(struct sti_struct *sti, int bpp_pref)
 {
 	struct fb_fix_screeninfo *fix;
 	struct fb_var_screeninfo *var;
@@ -1257,10 +1257,10 @@ stifb_init_fb(struct sti_struct *sti, in
 #ifdef __LP64__
 	        sti_rom_address |= 0xffffffff00000000;
 #endif
-		fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
+		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
 		if (IS_24_DEVICE(fb)) {
-			if (force_bpp == 8 || force_bpp == 32)
-				bpp = force_bpp;
+			if (bpp_pref == 8 || bpp_pref == 32)
+				bpp = bpp_pref;
 			else
 				bpp = 32;
 		} else
@@ -1409,21 +1409,24 @@ stifb_init(void)
 	
 	def_sti = sti_get_rom(0);
 	if (def_sti) {
-		for (i = 1; i < MAX_STI_ROMS; i++) {
+		for (i = 1; i <= MAX_STI_ROMS; i++) {
 			sti = sti_get_rom(i);
-			if (sti == def_sti && bpp > 0)
-				stifb_force_bpp[i] = bpp;
+			if (!sti)
+				break;
+			if (sti == def_sti) {
+				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
+				break;
+			}
 		}
-		stifb_init_fb(def_sti, stifb_force_bpp[i]);
 	}
 
-	for (i = 1; i < MAX_STI_ROMS; i++) {
+	for (i = 1; i <= MAX_STI_ROMS; i++) {
 		sti = sti_get_rom(i);
-		if (!sti || sti==def_sti)
+		if (!sti)
 			break;
-		if (bpp > 0)
-			stifb_force_bpp[i] = bpp;
-		stifb_init_fb(sti, stifb_force_bpp[i]);
+		if (sti == def_sti)
+			continue;
+		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
 	}
 	return 0;
 }
@@ -1438,7 +1441,7 @@ stifb_cleanup(void)
 	struct sti_struct *sti;
 	int i;
 	
-	for (i = 1; i < MAX_STI_ROMS; i++) {
+	for (i = 1; i <= MAX_STI_ROMS; i++) {
 		sti = sti_get_rom(i);
 		if (!sti)
 			break;
@@ -1470,11 +1473,9 @@ stifb_setup(char *options)
 	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);
-				bpp = -1;
-			} else
+			if (*options++ != ':')
 				break;
+			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
 		}
 	}
 	return 0;
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
--- a/drivers/video/sun3fb.c
+++ b/drivers/video/sun3fb.c
@@ -505,7 +505,7 @@ void sun3fb_palette(int enter)
 			if (fb->restore_palette) {
 				if (enter)
 					fb->restore_palette(fb);
-				else if (vt_cons[i]->vc_mode != KD_GRAPHICS)
+				else if (vc_cons[i].d->vc_mode != KD_GRAPHICS)
 				         vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
 			}
 		}
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -36,6 +36,7 @@ static int tcx_blank(int, struct fb_info
 static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
 static int tcx_ioctl(struct inode *, struct file *, unsigned int,
 		     unsigned long, struct fb_info *);
+static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -45,6 +46,7 @@ static struct fb_ops tcx_ops = {
 	.owner			= THIS_MODULE,
 	.fb_setcolreg		= tcx_setcolreg,
 	.fb_blank		= tcx_blank,
+	.fb_pan_display		= tcx_pan_display,
 	.fb_fillrect		= cfb_fillrect,
 	.fb_copyarea		= cfb_copyarea,
 	.fb_imageblit		= cfb_imageblit,
@@ -153,6 +155,12 @@ static void tcx_reset (struct fb_info *i
 	spin_unlock_irqrestore(&par->lock, flags);
 }
 
+static int tcx_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	tcx_reset(info);
+	return 0;
+}
+
 /**
  *      tcx_setcolreg - Optional function. Sets a color register.
  *      @regno: boolean, 0 copy local, 1 get_user() function
@@ -366,6 +374,9 @@ static void tcx_init_one(struct sbus_dev
 	all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit");
 
 	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+	all->info.var.red.length = 8;
+	all->info.var.green.length = 8;
+	all->info.var.blue.length = 8;
 
 	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
 				       all->info.var.xres);
@@ -439,6 +450,7 @@ static void tcx_init_one(struct sbus_dev
 		return;
 	}
 
+	fb_set_cmap(&all->info.cmap, &all->info);
 	tcx_init_fix(&all->info, linebytes);
 
 	if (register_framebuffer(&all->info) < 0) {
@@ -466,7 +478,7 @@ int __init tcx_init(void)
 		return -ENODEV;
 
 	for_all_sbusdev(sdev, sbus) {
-		if (!strcmp(sdev->prom_name, "tcx"))
+		if (!strcmp(sdev->prom_name, "SUNW,tcx"))
 			tcx_init_one(sdev);
 	}
 
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -89,7 +89,7 @@
 #define VOODOO3_MAX_PIXCLOCK 300000
 #define VOODOO5_MAX_PIXCLOCK 350000
 
-static struct fb_fix_screeninfo tdfx_fix __initdata = {
+static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
 	.id =		"3Dfx",
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_PSEUDOCOLOR, 
@@ -98,7 +98,7 @@ static struct fb_fix_screeninfo tdfx_fix
 	.accel =	FB_ACCEL_3DFX_BANSHEE
 };
 
-static struct fb_var_screeninfo tdfx_var __initdata = {
+static struct fb_var_screeninfo tdfx_var __devinitdata = {
 	/* "640x480, 8 bpp @ 60 Hz */
 	.xres =		640,
 	.yres =		480,
@@ -154,9 +154,6 @@ MODULE_DEVICE_TABLE(pci, tdfxfb_id_table
 /*
  *  Frame buffer device API
  */
-int tdfxfb_init(void);
-void tdfxfb_setup(char *options);
-
 static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); 
 static int tdfxfb_set_par(struct fb_info *info); 
 static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
@@ -202,7 +199,7 @@ static unsigned long do_lfb_size(struct 
  */
 static int  nopan   = 0;
 static int  nowrap  = 1;      // not implemented (yet)
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
 
 /* ------------------------------------------------------------------------- 
  *                      Hardware-specific funcions
@@ -320,30 +317,49 @@ static inline void do_setpalentry(struct
 
 static u32 do_calc_pll(int freq, int* freq_out) 
 {
-	int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+	int m, n, k, best_m, best_n, best_k, best_error;
 	int fref = 14318;
   
-	/* this really could be done with more intelligence --
-	   255*63*4 = 64260 iterations is silly */
 	best_error = freq;
 	best_n = best_m = best_k = 0;
-	for (n = 1; n < 256; n++) {
-		for (m = 1; m < 64; m++) {
-			for (k = 0; k < 4; k++) {
-				f_cur = fref*(n + 2)/(m + 2)/(1 << k);
-				if (abs(f_cur - freq) < best_error) {
-					best_error = abs(f_cur-freq);
-					best_n = n;
-					best_m = m;
-					best_k = k;
+
+	for (k = 3; k >= 0; k--) {
+		for (m = 63; m >= 0; m--) {
+			/*
+			 * Estimate value of n that produces target frequency
+			 * with current m and k
+			 */
+			int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2;
+
+			/* Search neighborhood of estimated n */
+			for (n = max(0, n_estimated - 1);
+					n <= min(255, n_estimated + 1); n++) {
+				/*
+				 * Calculate PLL freqency with current m, k and
+				 * estimated n
+				 */
+				int f = fref * (n + 2) / (m + 2) / (1 << k);
+				int error = abs (f - freq);
+
+				/*
+				 *  If this is the closest we've come to the
+				 * target frequency then remember n, m and k
+				 */
+				if (error  < best_error) {
+					best_error = error;
+					best_n     = n;
+					best_m     = m;
+					best_k     = k;
 				}
 			}
 		}
 	}
+
 	n = best_n;
 	m = best_m;
 	k = best_k;
 	*freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+
 	return (n << 8) | (m << 2) | k;
 }
 
@@ -414,36 +430,35 @@ static void do_write_regs(struct fb_info
 
 static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) 
 {
-	u32 draminit0 = 0;
-	u32 draminit1 = 0;
-	u32 miscinit1 = 0;
-	u32 lfbsize   = 0;
-	int sgram_p   = 0;
+	u32 draminit0;
+	u32 draminit1;
+	u32 miscinit1;
+
+	int num_chips;
+	int chip_size; /* in MB */
+	u32 lfbsize;
+	int has_sgram;
 
 	draminit0 = tdfx_inl(par, DRAMINIT0);  
 	draminit1 = tdfx_inl(par, DRAMINIT1);
+
+	num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
  
-	if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-	    (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) {             	 
-		sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
-  
-	lfbsize = sgram_p ?
-		(((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
-		((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
-		16 * 1024 * 1024;
+	if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
+		/* Banshee/Voodoo3 */
+		has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
+		chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1)
+				      : 2;
 	} else {
 		/* Voodoo4/5 */
-		u32 chips, psize, banks;
+		has_sgram = 0;
+		chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT);
+	}
+	lfbsize = num_chips * chip_size * 1024 * 1024;
 
-		chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
-		psize = 1 << ((draminit0 & 0x38000000) >> 28);
-		banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
-		lfbsize = chips * psize * banks;
-		lfbsize <<= 20;
-	}                 
-	/* disable block writes for SDRAM (why?) */
+	/* disable block writes for SDRAM */
 	miscinit1 = tdfx_inl(par, MISCINIT1);
-	miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+	miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
 	miscinit1 |= MISCINIT1_CLUT_INV;
 
 	banshee_make_room(par, 1); 
@@ -1292,6 +1307,28 @@ out_err:
 	return -ENXIO;
 }
 
+#ifndef MODULE
+void tdfxfb_setup(char *options)
+{
+	char* this_opt;
+
+	if (!options || !*options)
+		return;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if(!strcmp(this_opt, "nopan")) {
+			nopan = 1;
+		} else if(!strcmp(this_opt, "nowrap")) {
+			nowrap = 1;
+		} else {
+			mode_option = this_opt;
+		}
+	}
+}
+#endif
+
 /**
  *      tdfxfb_remove - Device removal
  *
@@ -1321,7 +1358,7 @@ static void __devexit tdfxfb_remove(stru
 	framebuffer_release(info);
 }
 
-int __init tdfxfb_init(void)
+static int __init tdfxfb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -1331,7 +1368,7 @@ int __init tdfxfb_init(void)
 
 	tdfxfb_setup(option);
 #endif
-        return pci_module_init(&tdfxfb_driver);
+        return pci_register_driver(&tdfxfb_driver);
 }
 
 static void __exit tdfxfb_exit(void)
@@ -1345,27 +1382,3 @@ MODULE_LICENSE("GPL");
  
 module_init(tdfxfb_init);
 module_exit(tdfxfb_exit);
-
-
-#ifndef MODULE
-void tdfxfb_setup(char *options)
-{ 
-	char* this_opt;
-
-	if (!options || !*options)
-		return;
-
-	while ((this_opt = strsep(&options, ",")) != NULL) {	
-		if (!*this_opt)
-			continue;
-		if(!strcmp(this_opt, "nopan")) {
-			nopan = 1;
-		} else if(!strcmp(this_opt, "nowrap")) {
-			nowrap = 1;
-		} else {
-			mode_option = this_opt;
-		}
-	} 
-}
-#endif
-
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -45,9 +45,7 @@ static void tgafb_fillrect(struct fb_inf
 static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
 
 static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);
-#ifdef MODULE
 static void tgafb_pci_unregister(struct pci_dev *);
-#endif
 
 static const char *mode_option = "640x480@60";
 
@@ -1484,7 +1482,6 @@ tgafb_pci_register(struct pci_dev *pdev,
 	return ret;
 }
 
-#ifdef MODULE
 static void __exit
 tgafb_pci_unregister(struct pci_dev *pdev)
 {
@@ -1500,6 +1497,7 @@ tgafb_pci_unregister(struct pci_dev *pde
 	kfree(info);
 }
 
+#ifdef MODULE
 static void __exit
 tgafb_exit(void)
 {
@@ -1540,7 +1538,7 @@ tgafb_init(void)
 		return -ENODEV;
 	tgafb_setup(option);
 #endif
-	return pci_module_init(&tgafb_driver);
+	return pci_register_driver(&tgafb_driver);
 }
 
 /*
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -31,7 +31,7 @@ struct tridentfb_par {
 	void __iomem * io_virt;	//iospace virtual memory address
 };
 
-unsigned char eng_oper;		//engine operation...
+static unsigned char eng_oper;		//engine operation...
 static struct fb_ops tridentfb_ops;
 
 static struct tridentfb_par default_par;
@@ -91,7 +91,7 @@ module_param(crt, int, 0);
 static int chip3D;
 static int chipcyber;
 
-int is3Dchip(int id)
+static int is3Dchip(int id)
 {
 	return 	((id == BLADE3D) || (id == CYBERBLADEE4) ||
 		 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
@@ -104,7 +104,7 @@ int is3Dchip(int id)
 		 (id ==	CYBERBLADEXPAi1));
 }
 
-int iscyber(int id)
+static int iscyber(int id)
 {
 	switch (id) {
 		case CYBER9388:		
@@ -1163,7 +1163,7 @@ static int __devinit trident_pci_probe(s
 	fb_info.var = default_var;
 	fb_info.device = &dev->dev;
 	if (register_framebuffer(&fb_info) < 0) {
-		output("Could not register Trident framebuffer\n");
+		printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
 		return -EINVAL;
 	}
 	output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
@@ -1216,33 +1216,13 @@ static struct pci_driver tridentfb_pci_d
 	.remove		= __devexit_p(trident_pci_remove)
 };
 
-int tridentfb_setup(char *options);
-
-int __init tridentfb_init(void)
-{
-#ifndef MODULE
-	char *option = NULL;
-
-	if (fb_get_options("tridentfb", &option))
-		return -ENODEV;
-	tridentfb_setup(option);
-#endif
-	output("Trident framebuffer %s initializing\n", VERSION);
-	return pci_module_init(&tridentfb_pci_driver);
-}
-
-void __exit tridentfb_exit(void)
-{
-	pci_unregister_driver(&tridentfb_pci_driver);
-}
-
-
 /*
  * Parse user specified options (`video=trident:')
  * example:
  * 	video=trident:800x600,bpp=16,noaccel
  */
-int tridentfb_setup(char *options)
+#ifndef MODULE
+static int tridentfb_setup(char *options)
 {
 	char * opt;
 	if (!options || !*options)
@@ -1272,6 +1252,25 @@ int tridentfb_setup(char *options)
 	}
 	return 0;
 }
+#endif
+
+static int __init tridentfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("tridentfb", &option))
+		return -ENODEV;
+	tridentfb_setup(option);
+#endif
+	output("Trident framebuffer %s initializing\n", VERSION);
+	return pci_register_driver(&tridentfb_pci_driver);
+}
+
+static void __exit tridentfb_exit(void)
+{
+	pci_unregister_driver(&tridentfb_pci_driver);
+}
 
 static struct fb_ops tridentfb_ops = {
 	.owner	= THIS_MODULE,
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -19,9 +19,6 @@
 #include <linux/fb.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#ifdef __i386__
-#include <video/edid.h>
-#endif
 #include <asm/io.h>
 #include <asm/mtrr.h>
 
@@ -185,7 +182,7 @@ static struct fb_ops vesafb_ops = {
 	.fb_cursor	= soft_cursor,
 };
 
-int __init vesafb_setup(char *options)
+static int __init vesafb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -434,7 +431,7 @@ static struct platform_device vesafb_dev
 	.name	= "vesafb",
 };
 
-int __init vesafb_init(void)
+static int __init vesafb_init(void)
 {
 	int ret;
 	char *option = NULL;
@@ -453,12 +450,4 @@ int __init vesafb_init(void)
 }
 module_init(vesafb_init);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -72,12 +72,6 @@ static struct fb_fix_screeninfo vfb_fix 
 static int vfb_enable __initdata = 0;	/* disabled by default */
 module_param(vfb_enable, bool, 0);
 
-    /*
-     *  Interface used by the world
-     */
-int vfb_init(void);
-int vfb_setup(char *);
-
 static int vfb_check_var(struct fb_var_screeninfo *var,
 			 struct fb_info *info);
 static int vfb_set_par(struct fb_info *info);
@@ -379,7 +373,8 @@ static int vfb_mmap(struct fb_info *info
 	return -EINVAL;
 }
 
-int __init vfb_setup(char *options)
+#ifndef MODULE
+static int __init vfb_setup(char *options)
 {
 	char *this_opt;
 
@@ -396,6 +391,7 @@ int __init vfb_setup(char *options)
 	}
 	return 1;
 }
+#endif  /*  MODULE  */
 
     /*
      *  Initialisation
@@ -492,7 +488,7 @@ static struct platform_device vfb_device
 	}
 };
 
-int __init vfb_init(void)
+static int __init vfb_init(void)
 {
 	int ret = 0;
 
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -874,7 +874,7 @@ static int vga16fb_blank(int blank, stru
 	return 0;
 }
 
-void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	u32 dx = rect->dx, width = rect->width;
         char oldindex = getindex();
@@ -928,7 +928,7 @@ void vga_8planes_fillrect(struct fb_info
         setindex(oldindex);
 }
 
-void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	int x, x2, y2, vxres, vyres, width, height, line_ofs;
 	char __iomem *dst;
@@ -1003,7 +1003,7 @@ void vga16fb_fillrect(struct fb_info *in
 	}
 }
 
-void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
         char oldindex = getindex();
         char oldmode = setmode(0x41);
@@ -1058,7 +1058,7 @@ void vga_8planes_copyarea(struct fb_info
         setindex(oldindex);
 }
 
-void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
 	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 
 	int x, x2, y2, old_dx, old_dy, vxres, vyres;
@@ -1166,7 +1166,7 @@ static unsigned int transl_l[] =
 #endif
 #endif
 
-void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
+static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
 {
         char oldindex = getindex();
         char oldmode = setmode(0x40);
@@ -1197,7 +1197,7 @@ void vga_8planes_imageblit(struct fb_inf
         setindex(oldindex);
 }
 
-void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
+static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
 {
 	char __iomem *where = info->screen_base + (image->dx/8) +
 		image->dy * info->fix.line_length;
@@ -1261,7 +1261,7 @@ void vga_imageblit_expand(struct fb_info
 	}
 }
 
-void vga_imageblit_color(struct fb_info *info, const struct fb_image *image) 
+static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
 {
 	/*
 	 * Draw logo 
@@ -1306,7 +1306,7 @@ void vga_imageblit_color(struct fb_info 
 	}
 }
 				
-void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
+static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	if (image->depth == 1)
 		vga_imageblit_expand(info, image);
@@ -1329,7 +1329,8 @@ static struct fb_ops vga16fb_ops = {
 	.fb_cursor      = soft_cursor,
 };
 
-int vga16fb_setup(char *options)
+#ifndef MODULE
+static int vga16fb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -1341,8 +1342,9 @@ int vga16fb_setup(char *options)
 	}
 	return 0;
 }
+#endif
 
-int __init vga16fb_init(void)
+static int __init vga16fb_init(void)
 {
 	int i;
 	int ret;
@@ -1427,9 +1429,7 @@ static void __exit vga16fb_exit(void)
     /* XXX unshare VGA regions */
 }
 
-#ifdef MODULE
 MODULE_LICENSE("GPL");
-#endif
 module_init(vga16fb_init);
 module_exit(vga16fb_exit);
 
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -22,7 +22,6 @@
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
-#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <video/w100fb.h>
@@ -90,8 +89,6 @@ struct w100fb_par {
 
 static struct w100fb_par *current_par;
 
-static u16 *gSaveImagePtr = NULL;
-
 /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
 static void *remapped_base;
 static void *remapped_regs;
@@ -494,48 +491,60 @@ static void w100fb_clear_screen(u32 mode
 }
 
 
+/* Need to split up the buffers to stay within the limits of kmalloc */
+#define W100_BUF_NUM	6
+static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
+
 static void w100fb_save_buffer(void)
 {
-	int i;
+	int i, j, bufsize;
 
-	if (gSaveImagePtr != NULL) {
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
-	}
-	gSaveImagePtr = vmalloc(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8);
-	if (gSaveImagePtr != NULL) {
-		for (i = 0; i < (current_par->xres * current_par->yres); i++)
-			*(gSaveImagePtr + i) = readw(remapped_fbuf + (2*i));
-	} else {
-		printk(KERN_WARNING "can't alloc pre-off image buffer\n");
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL)
+			gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
+		if (gSaveImagePtr[i] == NULL) {
+			w100fb_clear_buffer();
+			printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
+			break;
+		}
+		for (j = 0; j < bufsize/4; j++)
+			*(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
 	}
 }
 
 
 static void w100fb_restore_buffer(void)
 {
-	int i;
+	int i, j, bufsize;
 
-	if (gSaveImagePtr != NULL) {
-		for (i = 0; i < (current_par->xres * current_par->yres); i++) {
-				writew(*(gSaveImagePtr + i),remapped_fbuf + (2*i));
-			}
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL) {
+			printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
+			w100fb_clear_buffer();
+			break;
+		}
+		for (j = 0; j < (bufsize/4); j++)
+			writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
+		kfree(gSaveImagePtr[i]);
+		gSaveImagePtr[i] = NULL;
 	}
 }
 
+
 static void w100fb_clear_buffer(void)
 {
-	if (gSaveImagePtr != NULL) {
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
+	int i;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		kfree(gSaveImagePtr[i]);
+		gSaveImagePtr[i] = NULL;
 	}
 }
 
 
 #ifdef CONFIG_PM
-static int w100fb_suspend(struct device *dev, u32 state, u32 level)
+static int w100fb_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_POWER_DOWN) {
 		struct fb_info *info = dev_get_drvdata(dev);
diff --git a/drivers/w1/dscore.c b/drivers/w1/dscore.c
--- a/drivers/w1/dscore.c
+++ b/drivers/w1/dscore.c
@@ -45,9 +45,6 @@ int ds_set_speed(struct ds_device *, int
 int ds_reset(struct ds_device *, struct ds_status *);
 int ds_detect(struct ds_device *, struct ds_status *);
 int ds_stop_pulse(struct ds_device *, int);
-int ds_send_data(struct ds_device *, unsigned char *, int);
-int ds_recv_data(struct ds_device *, unsigned char *, int);
-int ds_recv_status(struct ds_device *, struct ds_status *);
 struct ds_device * ds_get_device(void);
 void ds_put_device(struct ds_device *);
 
@@ -84,7 +81,7 @@ static int ds_send_control_cmd(struct ds
 	int err;
 	
 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
-			CONTROL_CMD, 0x40, value, index, NULL, 0, HZ);
+			CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
 		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n", 
 				value, index, err);
@@ -99,7 +96,7 @@ static int ds_send_control_mode(struct d
 	int err;
 	
 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
-			MODE_CMD, 0x40, value, index, NULL, 0, HZ);
+			MODE_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
 		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n", 
 				value, index, err);
@@ -114,7 +111,7 @@ static int ds_send_control(struct ds_dev
 	int err;
 	
 	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
-			COMM_CMD, 0x40, value, index, NULL, 0, HZ);
+			COMM_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
 		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n", 
 				value, index, err);
@@ -148,7 +145,7 @@ int ds_recv_status_nodump(struct ds_devi
 	return count;
 }
 
-int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
 {
 	unsigned char buf[64];
 	int count, err = 0, i;
@@ -206,14 +203,14 @@ int ds_recv_status(struct ds_device *dev
 	return err;
 }
 
-int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
 {
 	int count, err;
 	struct ds_status st;
 	
 	count = 0;
 	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), 
-				buf, size, &count, HZ);
+				buf, size, &count, 1000);
 	if (err < 0) {
 		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
 		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
@@ -234,12 +231,12 @@ int ds_recv_data(struct ds_device *dev, 
 	return count;
 }
 
-int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
+static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
 {
 	int count, err;
 	
 	count = 0;
-	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, HZ);
+	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
 	if (err < 0) {
 		printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
 		return err;
@@ -774,15 +771,19 @@ EXPORT_SYMBOL(ds_read_block);
 EXPORT_SYMBOL(ds_write_byte);
 EXPORT_SYMBOL(ds_write_bit);
 EXPORT_SYMBOL(ds_write_block);
+EXPORT_SYMBOL(ds_reset);
+EXPORT_SYMBOL(ds_get_device);
+EXPORT_SYMBOL(ds_put_device);
+
+/*
+ * This functions can be used for EEPROM programming, 
+ * when driver will be included into mainline this will 
+ * require uncommenting.
+ */
+#if 0
 EXPORT_SYMBOL(ds_start_pulse);
 EXPORT_SYMBOL(ds_set_speed);
-EXPORT_SYMBOL(ds_reset);
 EXPORT_SYMBOL(ds_detect);
 EXPORT_SYMBOL(ds_stop_pulse);
-EXPORT_SYMBOL(ds_send_data);
-EXPORT_SYMBOL(ds_recv_data);
-EXPORT_SYMBOL(ds_recv_status);
 EXPORT_SYMBOL(ds_search);
-EXPORT_SYMBOL(ds_get_device);
-EXPORT_SYMBOL(ds_put_device);
-
+#endif
diff --git a/drivers/w1/dscore.h b/drivers/w1/dscore.h
--- a/drivers/w1/dscore.h
+++ b/drivers/w1/dscore.h
@@ -161,9 +161,6 @@ int ds_set_speed(struct ds_device *, int
 int ds_reset(struct ds_device *, struct ds_status *);
 int ds_detect(struct ds_device *, struct ds_status *);
 int ds_stop_pulse(struct ds_device *, int);
-int ds_send_data(struct ds_device *, unsigned char *, int);
-int ds_recv_data(struct ds_device *, unsigned char *, int);
-int ds_recv_status(struct ds_device *, struct ds_status *);
 struct ds_device * ds_get_device(void);
 void ds_put_device(struct ds_device *);
 int ds_write_block(struct ds_device *, u8 *, int);
diff --git a/drivers/w1/matrox_w1.c b/drivers/w1/matrox_w1.c
--- a/drivers/w1/matrox_w1.c
+++ b/drivers/w1/matrox_w1.c
@@ -235,7 +235,7 @@ static void __devexit matrox_w1_remove(s
 
 static int __init matrox_w1_init(void)
 {
-	return pci_module_init(&matrox_w1_pci_driver);
+	return pci_register_driver(&matrox_w1_pci_driver);
 }
 
 static void __exit matrox_w1_fini(void)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -19,8 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-#include <asm/atomic.h>
-
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -33,6 +31,8 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
+#include <asm/atomic.h>
+
 #include "w1.h"
 #include "w1_io.h"
 #include "w1_log.h"
@@ -58,7 +58,6 @@ LIST_HEAD(w1_masters);
 static pid_t control_thread;
 static int control_needs_exit;
 static DECLARE_COMPLETION(w1_control_complete);
-static DECLARE_WAIT_QUEUE_HEAD(w1_control_wait);
 
 static int w1_master_match(struct device *dev, struct device_driver *drv)
 {
@@ -100,7 +99,7 @@ static ssize_t w1_default_read_bin(struc
 	return sprintf(buf, "No family registered.\n");
 }
 
-struct bus_type w1_bus_type = {
+static struct bus_type w1_bus_type = {
 	.name = "w1",
 	.match = w1_master_match,
 };
@@ -138,7 +137,7 @@ static struct device_attribute w1_slave_
 	.show = &w1_default_read_name,
 };
 
-ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
 {
 	struct w1_master *md = container_of (dev, struct w1_master, dev);
 	ssize_t count;
@@ -153,7 +152,7 @@ ssize_t w1_master_attribute_show_name(st
 	return count;
 }
 
-ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf)
 {
 	struct w1_master *md = container_of(dev, struct w1_master, dev);
 	ssize_t count;
@@ -167,14 +166,14 @@ ssize_t w1_master_attribute_show_pointer
 	return count;
 }
 
-ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
 {
 	ssize_t count;
 	count = sprintf(buf, "%d\n", w1_timeout);
 	return count;
 }
 
-ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
 {
 	struct w1_master *md = container_of(dev, struct w1_master, dev);
 	ssize_t count;
@@ -188,7 +187,7 @@ ssize_t w1_master_attribute_show_max_sla
 	return count;
 }
 
-ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf)
 {
 	struct w1_master *md = container_of(dev, struct w1_master, dev);
 	ssize_t count;
@@ -202,7 +201,7 @@ ssize_t w1_master_attribute_show_attempt
 	return count;
 }
 
-ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf)
 {
 	struct w1_master *md = container_of(dev, struct w1_master, dev);
 	ssize_t count;
@@ -216,7 +215,7 @@ ssize_t w1_master_attribute_show_slave_c
 	return count;
 }
 
-ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf)
+static ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf)
 
 {
 	struct w1_master *md = container_of(dev, struct w1_master, dev);
@@ -413,7 +412,8 @@ static int w1_attach_slave_device(struct
 	if (!f) {
 		spin_unlock(&w1_flock);
 		dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
-			  rn->family, rn->family, rn->id, rn->crc);
+			  rn->family, rn->family,
+			  (unsigned long long)rn->id, rn->crc);
 		kfree(sl);
 		return -ENODEV;
 	}
@@ -522,9 +522,11 @@ void w1_slave_found(unsigned long data, 
 		slave_count++;
 	}
 
+	rn = cpu_to_le64(rn);
+
 	if (slave_count == dev->slave_count &&
-		rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
-		w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
+		rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
+		w1_attach_slave_device(dev, tmp);
 	}
 			
 	atomic_dec(&dev->refcnt);
@@ -649,7 +651,7 @@ int w1_control(void *data)
 	struct w1_slave *sl;
 	struct w1_master *dev;
 	struct list_head *ent, *ment, *n, *mn;
-	int err, have_to_wait = 0, timeout;
+	int err, have_to_wait = 0;
 
 	daemonize("w1_control");
 	allow_signal(SIGTERM);
@@ -657,11 +659,8 @@ int w1_control(void *data)
 	while (!control_needs_exit || have_to_wait) {
 		have_to_wait = 0;
 
-		timeout = w1_timeout*HZ;
-		do {
-			timeout = interruptible_sleep_on_timeout(&w1_control_wait, timeout);
-			try_to_freeze(PF_FREEZE);
-		} while (!signal_pending(current) && (timeout > 0));
+		try_to_freeze(PF_FREEZE);
+		msleep_interruptible(w1_timeout * 1000);
 
 		if (signal_pending(current))
 			flush_signals(current);
@@ -721,7 +720,6 @@ int w1_control(void *data)
 int w1_process(void *data)
 {
 	struct w1_master *dev = (struct w1_master *) data;
-	unsigned long timeout;
 	struct list_head *ent, *n;
 	struct w1_slave *sl;
 
@@ -729,11 +727,8 @@ int w1_process(void *data)
 	allow_signal(SIGTERM);
 
 	while (!dev->need_exit) {
-		timeout = w1_timeout*HZ;
-		do {
-			timeout = interruptible_sleep_on_timeout(&dev->kwait, timeout);
-			try_to_freeze(PF_FREEZE);
-		} while (!signal_pending(current) && (timeout > 0));
+		try_to_freeze(PF_FREEZE);
+		msleep_interruptible(w1_timeout * 1000);
 
 		if (signal_pending(current))
 			flush_signals(current);
@@ -839,6 +834,3 @@ void w1_fini(void)
 
 module_init(w1_init);
 module_exit(w1_fini);
-
-EXPORT_SYMBOL(w1_create_master_attributes);
-EXPORT_SYMBOL(w1_destroy_master_attributes);
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -24,9 +24,17 @@
 
 struct w1_reg_num
 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u64	family:8,
 		id:48,
 		crc:8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u64	crc:8,
+		id:48,
+		family:8;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 };
 
 #ifdef __KERNEL__
@@ -115,7 +123,6 @@ struct w1_master
 
 	int			need_exit;
 	pid_t			kpid;
-	wait_queue_head_t 	kwait;
 	struct semaphore 	mutex;
 
 	struct device_driver	*driver;
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -138,13 +138,13 @@ void w1_family_get(struct w1_family *f)
 
 void __w1_family_get(struct w1_family *f)
 {
+	smp_mb__before_atomic_inc();
 	atomic_inc(&f->refcnt);
+	smp_mb__after_atomic_inc();
 }
 
 EXPORT_SYMBOL(w1_family_get);
 EXPORT_SYMBOL(w1_family_put);
-EXPORT_SYMBOL(__w1_family_get);
-EXPORT_SYMBOL(__w1_family_put);
 EXPORT_SYMBOL(w1_family_registered);
 EXPORT_SYMBOL(w1_unregister_family);
 EXPORT_SYMBOL(w1_register_family);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -74,7 +74,6 @@ struct w1_master * w1_alloc_dev(u32 id, 
 	INIT_LIST_HEAD(&dev->slist);
 	init_MUTEX(&dev->mutex);
 
-	init_waitqueue_head(&dev->kwait);
 	init_completion(&dev->dev_released);
 	init_completion(&dev->dev_exited);
 
@@ -217,8 +216,5 @@ void w1_remove_master_device(struct w1_b
 	__w1_remove_master_device(dev);
 }
 
-EXPORT_SYMBOL(w1_alloc_dev);
-EXPORT_SYMBOL(w1_free_dev);
 EXPORT_SYMBOL(w1_add_master_device);
 EXPORT_SYMBOL(w1_remove_master_device);
-EXPORT_SYMBOL(__w1_remove_master_device);
diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c
--- a/drivers/w1/w1_smem.c
+++ b/drivers/w1/w1_smem.c
@@ -60,7 +60,7 @@ static ssize_t w1_smem_read_val(struct d
 	int i;
 	ssize_t count = 0;
 	
-	for (i = 0; i < 9; ++i)
+	for (i = 0; i < 8; ++i)
 		count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
 	count += sprintf(buf + count, "\n");
 
@@ -87,7 +87,7 @@ static ssize_t w1_smem_read_bin(struct k
 		count = 0;
 		goto out;
 	}
-	for (i = 0; i < 9; ++i)
+	for (i = 0; i < 8; ++i)
 		count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
 	count += sprintf(buf + count, "\n");
 	
diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c
--- a/drivers/w1/w1_therm.c
+++ b/drivers/w1/w1_therm.c
@@ -26,6 +26,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 
 #include "w1.h"
 #include "w1_io.h"
@@ -103,6 +104,7 @@ static ssize_t w1_therm_read_bin(struct 
 	int i, max_trying = 10;
 
 	atomic_inc(&sl->refcnt);
+	smp_mb__after_atomic_inc();
 	if (down_interruptible(&sl->master->mutex)) {
 		count = 0;
 		goto out_dec;
@@ -128,7 +130,7 @@ static ssize_t w1_therm_read_bin(struct 
 		if (!w1_reset_bus (dev)) {
 			int count = 0;
 			u8 match[9] = {W1_MATCH_ROM, };
-			unsigned long tm;
+			unsigned int tm = 750;
 
 			memcpy(&match[1], (u64 *) & sl->reg_num, 8);
 			
@@ -136,11 +138,8 @@ static ssize_t w1_therm_read_bin(struct 
 
 			w1_write_8(dev, W1_CONVERT_TEMP);
 
-			tm = jiffies + msecs_to_jiffies(750);
-			while(time_before(jiffies, tm)) {
-				set_current_state(TASK_INTERRUPTIBLE);
-				schedule_timeout(tm-jiffies);
-
+			while (tm) {
+				tm = msleep_interruptible(tm);
 				if (signal_pending(current))
 					flush_signals(current);
 			}
@@ -181,6 +180,7 @@ static ssize_t w1_therm_read_bin(struct 
 out:
 	up(&dev->mutex);
 out_dec:
+	smp_mb__before_atomic_inc();
 	atomic_dec(&sl->refcnt);
 
 	return count;
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -134,7 +134,7 @@ static int __init zorro_init(void)
     if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
 	return 0;
 
-    printk("Zorro: Probing AutoConfig expansion devices: %d device%s\n",
+    pr_info("Zorro: Probing AutoConfig expansion devices: %d device%s\n",
 	   zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
 
     /* Initialize the Zorro bus */
diff --git a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -936,6 +936,7 @@ config HFS_FS
 config HFSPLUS_FS
 	tristate "Apple Extended HFS file system support"
 	select NLS
+	select NLS_UTF8
 	help
 	  If you say Y here, you will be able to mount extended format
 	  Macintosh-formatted hard drive partitions with full read-write access.
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -65,23 +65,6 @@ static inline int adfs_readname(char *bu
 	return buf - old_buf;
 }
 
-static inline void adfs_writename(char *to, char *from, int maxlen)
-{
-	int i;
-
-	for (i = 0; i < maxlen; i++) {
-		if (from[i] == '\0')
-			break;
-		if (from[i] == '.')
-			to[i] = '/';
-		else
-			to[i] = from[i];
-	}
-
-	for (; i < maxlen; i++)
-		to[i] = '\0';
-}
-
 #define ror13(v) ((v >> 13) | (v << 19))
 
 #define dir_u8(idx)				\
diff --git a/fs/afs/file.c b/fs/afs/file.c
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -131,8 +131,7 @@ static int afs_file_readpage(struct file
 
 	vnode = AFS_FS_I(inode);
 
-	if (!PageLocked(page))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
 
 	ret = -ESTALE;
 	if (vnode->flags & AFS_VNODE_DELETED)
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
--- a/fs/afs/kafsasyncd.c
+++ b/fs/afs/kafsasyncd.c
@@ -116,6 +116,8 @@ static int kafsasyncd(void *arg)
 		remove_wait_queue(&kafsasyncd_sleepq, &myself);
 		set_current_state(TASK_RUNNING);
 
+		try_to_freeze(PF_FREEZE);
+
 		/* discard pending signals */
 		afs_discard_my_signals();
 
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
--- a/fs/afs/kafstimod.c
+++ b/fs/afs/kafstimod.c
@@ -91,6 +91,8 @@ static int kafstimod(void *arg)
 			complete_and_exit(&kafstimod_dead, 0);
 		}
 
+		try_to_freeze(PF_FREEZE);
+
 		/* discard pending signals */
 		afs_discard_my_signals();
 
diff --git a/fs/afs/main.c b/fs/afs/main.c
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -29,18 +29,9 @@
 
 struct rxrpc_transport *afs_transport;
 
-static int afs_init(void);
-static void afs_exit(void);
 static int afs_adding_peer(struct rxrpc_peer *peer);
 static void afs_discarding_peer(struct rxrpc_peer *peer);
 
-/* XXX late_initcall is kludgy, but the only alternative seems to create
- * a transport upon the first mount, which is worse. Or is it?
- */
-/* module_init(afs_init); */
-late_initcall(afs_init);	/* must be called after net/ to create socket */
-
-module_exit(afs_exit);
 
 MODULE_DESCRIPTION("AFS Client File System");
 MODULE_AUTHOR("Red Hat, Inc.");
@@ -76,7 +67,7 @@ struct cachefs_netfs afs_cache_netfs = {
 /*
  * initialise the AFS client FS module
  */
-static int afs_init(void)
+static int __init afs_init(void)
 {
 	int loop, ret;
 
@@ -156,6 +147,10 @@ static int afs_init(void)
 	return ret;
 } /* end afs_init() */
 
+/* XXX late_initcall is kludgy, but the only alternative seems to create
+ * a transport upon the first mount, which is worse. Or is it?
+ */
+late_initcall(afs_init);	/* must be called after net/ to create socket */
 /*****************************************************************************/
 /*
  * clean up on module removal
@@ -179,6 +174,8 @@ static void __exit afs_exit(void)
 
 } /* end afs_exit() */
 
+module_exit(afs_exit);
+
 /*****************************************************************************/
 /*
  * notification that new peer record is being added
diff --git a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1,6 +1,6 @@
 /*
  *	An async IO implementation for Linux
- *	Written by Benjamin LaHaise <bcrl@redhat.com>
+ *	Written by Benjamin LaHaise <bcrl@kvack.org>
  *
  *	Implements an efficient asynchronous io interface.
  *
@@ -40,9 +40,6 @@
 #define dprintk(x...)	do { ; } while (0)
 #endif
 
-long aio_run = 0; /* for testing only */
-long aio_wakeups = 0; /* for testing only */
-
 /*------ sysctl variables----*/
 atomic_t aio_nr = ATOMIC_INIT(0);	/* current system wide number of aio requests */
 unsigned aio_max_nr = 0x10000;	/* system wide maximum number of aio requests */
@@ -58,7 +55,7 @@ static void aio_fput_routine(void *);
 static DECLARE_WORK(fput_work, aio_fput_routine, NULL);
 
 static DEFINE_SPINLOCK(fput_lock);
-LIST_HEAD(fput_head);
+static LIST_HEAD(fput_head);
 
 static void aio_kick_handler(void *);
 
@@ -290,7 +287,7 @@ static void aio_cancel_all(struct kioctx
 	spin_unlock_irq(&ctx->ctx_lock);
 }
 
-void wait_for_all_aios(struct kioctx *ctx)
+static void wait_for_all_aios(struct kioctx *ctx)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
@@ -405,7 +402,6 @@ static struct kiocb fastcall *__aio_get_
 	req->ki_ctx = ctx;
 	req->ki_cancel = NULL;
 	req->ki_retry = NULL;
-	req->ki_obj.user = NULL;
 	req->ki_dtor = NULL;
 	req->private = NULL;
 	INIT_LIST_HEAD(&req->ki_run_list);
@@ -451,11 +447,6 @@ static inline void really_put_req(struct
 {
 	if (req->ki_dtor)
 		req->ki_dtor(req);
-	req->ki_ctx = NULL;
-	req->ki_filp = NULL;
-	req->ki_obj.user = NULL;
-	req->ki_dtor = NULL;
-	req->private = NULL;
 	kmem_cache_free(kiocb_cachep, req);
 	ctx->reqs_active--;
 
@@ -592,7 +583,7 @@ static void use_mm(struct mm_struct *mm)
  * Comments: Called with ctx->ctx_lock held. This nests
  * task_lock instead ctx_lock.
  */
-void unuse_mm(struct mm_struct *mm)
+static void unuse_mm(struct mm_struct *mm)
 {
 	struct task_struct *tsk = current;
 
@@ -623,7 +614,6 @@ static inline int __queue_kicked_iocb(st
 	if (list_empty(&iocb->ki_run_list)) {
 		list_add_tail(&iocb->ki_run_list,
 			&ctx->run_list);
-		iocb->ki_queued++;
 		return 1;
 	}
 	return 0;
@@ -664,10 +654,8 @@ static ssize_t aio_run_iocb(struct kiocb
 	}
 
 	if (!(iocb->ki_retried & 0xff)) {
-		pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n",
-			iocb->ki_retried,
-			iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
-			iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+		pr_debug("%ld retry: %d of %d\n", iocb->ki_retried,
+			iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
 	}
 
 	if (!(retry = iocb->ki_retry)) {
@@ -774,7 +762,6 @@ out:
 static int __aio_run_iocbs(struct kioctx *ctx)
 {
 	struct kiocb *iocb;
-	int count = 0;
 	LIST_HEAD(run_list);
 
 	list_splice_init(&ctx->run_list, &run_list);
@@ -789,9 +776,7 @@ static int __aio_run_iocbs(struct kioctx
 		aio_run_iocb(iocb);
 		if (__aio_put_req(ctx, iocb))  /* drop extra ref */
 			put_ioctx(ctx);
-		count++;
  	}
-	aio_run++;
 	if (!list_empty(&ctx->run_list))
 		return 1;
 	return 0;
@@ -879,7 +864,7 @@ static void aio_kick_handler(void *data)
  * and if required activate the aio work queue to process
  * it
  */
-void queue_kicked_iocb(struct kiocb *iocb)
+static void queue_kicked_iocb(struct kiocb *iocb)
 {
  	struct kioctx	*ctx = iocb->ki_ctx;
 	unsigned long flags;
@@ -890,10 +875,8 @@ void queue_kicked_iocb(struct kiocb *ioc
 	spin_lock_irqsave(&ctx->ctx_lock, flags);
 	run = __queue_kicked_iocb(iocb);
 	spin_unlock_irqrestore(&ctx->ctx_lock, flags);
-	if (run) {
+	if (run)
 		aio_queue_work(ctx);
-		aio_wakeups++;
-	}
 }
 
 /*
@@ -913,7 +896,6 @@ void fastcall kick_iocb(struct kiocb *io
 		return;
 	}
 
-	iocb->ki_kicked++;
 	/* If its already kicked we shouldn't queue it again */
 	if (!kiocbTryKick(iocb)) {
 		queue_kicked_iocb(iocb);
@@ -984,7 +966,8 @@ int fastcall aio_complete(struct kiocb *
 
 	tail = info->tail;
 	event = aio_ring_event(info, tail, KM_IRQ0);
-	tail = (tail + 1) % info->nr;
+	if (++tail >= info->nr)
+		tail = 0;
 
 	event->obj = (u64)(unsigned long)iocb->ki_obj.user;
 	event->data = iocb->ki_user_data;
@@ -1008,10 +991,8 @@ int fastcall aio_complete(struct kiocb *
 
 	pr_debug("added to ring %p at [%lu]\n", iocb, tail);
 
-	pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n",
-		iocb->ki_retried,
-		iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
-		iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+	pr_debug("%ld retries: %d of %d\n", iocb->ki_retried,
+		iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
 put_rq:
 	/* everything turned out well, dispose of the aiocb. */
 	ret = __aio_put_req(ctx, iocb);
@@ -1119,7 +1100,6 @@ static int read_events(struct kioctx *ct
 	int			i = 0;
 	struct io_event		ent;
 	struct aio_timeout	to;
-	int 			event_loop = 0; /* testing only */
 	int			retry = 0;
 
 	/* needed to zero any padding within an entry (there shouldn't be 
@@ -1186,7 +1166,6 @@ retry:
 			if (to.timed_out)	/* Only check after read evt */
 				break;
 			schedule();
-			event_loop++;
 			if (signal_pending(tsk)) {
 				ret = -EINTR;
 				break;
@@ -1214,9 +1193,6 @@ retry:
 	if (timeout)
 		clear_timeout(&to);
 out:
-	pr_debug("event loop executed %d times\n", event_loop);
-	pr_debug("aio_run %ld\n", aio_run);
-	pr_debug("aio_wakeups %ld\n", aio_wakeups);
 	return i ? i : ret;
 }
 
@@ -1401,7 +1377,7 @@ static ssize_t aio_fsync(struct kiocb *i
  *	Performs the initial checks and aio retry method
  *	setup for the kiocb at the time of io submission.
  */
-ssize_t aio_setup_iocb(struct kiocb *kiocb)
+static ssize_t aio_setup_iocb(struct kiocb *kiocb)
 {
 	struct file *file = kiocb->ki_filp;
 	ssize_t ret = 0;
@@ -1470,7 +1446,8 @@ ssize_t aio_setup_iocb(struct kiocb *kio
  * because this callback isn't used for wait queues which
  * are nested inside ioctx lock (i.e. ctx->wait)
  */
-int aio_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+static int aio_wake_function(wait_queue_t *wait, unsigned mode,
+			     int sync, void *key)
 {
 	struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait);
 
@@ -1514,8 +1491,7 @@ int fastcall io_submit_one(struct kioctx
 	}
 
 	req->ki_filp = file;
-	iocb->aio_key = req->ki_key;
-	ret = put_user(iocb->aio_key, &user_iocb->aio_key);
+	ret = put_user(req->ki_key, &user_iocb->aio_key);
 	if (unlikely(ret)) {
 		dprintk("EFAULT: aio_key\n");
 		goto out_put_req;
@@ -1530,13 +1506,7 @@ int fastcall io_submit_one(struct kioctx
 	req->ki_opcode = iocb->aio_lio_opcode;
 	init_waitqueue_func_entry(&req->ki_wait, aio_wake_function);
 	INIT_LIST_HEAD(&req->ki_wait.task_list);
-	req->ki_run_list.next = req->ki_run_list.prev = NULL;
-	req->ki_retry = NULL;
 	req->ki_retried = 0;
-	req->ki_kicked = 0;
-	req->ki_queued = 0;
-	aio_run = 0;
-	aio_wakeups = 0;
 
 	ret = aio_setup_iocb(req);
 
@@ -1544,10 +1514,14 @@ int fastcall io_submit_one(struct kioctx
 		goto out_put_req;
 
 	spin_lock_irq(&ctx->ctx_lock);
-	list_add_tail(&req->ki_run_list, &ctx->run_list);
-	/* drain the run list */
-	while (__aio_run_iocbs(ctx))
-		;
+	if (likely(list_empty(&ctx->run_list))) {
+		aio_run_iocb(req);
+	} else {
+		list_add_tail(&req->ki_run_list, &ctx->run_list);
+		/* drain the run list */
+		while (__aio_run_iocbs(ctx))
+			;
+	}
 	spin_unlock_irq(&ctx->ctx_lock);
 	aio_put_req(req);	/* drop extra ref to req */
 	return 0;
@@ -1620,7 +1594,8 @@ asmlinkage long sys_io_submit(aio_contex
  *	Finds a given iocb for cancellation.
  *	MUST be called with ctx->ctx_lock held.
  */
-struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, u32 key)
+static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb,
+				  u32 key)
 {
 	struct list_head *pos;
 	/* TODO: use a hash or array, this sucks. */
diff --git a/fs/attr.c b/fs/attr.c
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -135,14 +135,17 @@ int setattr_mask(unsigned int ia_valid)
 int notify_change(struct dentry * dentry, struct iattr * attr)
 {
 	struct inode *inode = dentry->d_inode;
-	mode_t mode = inode->i_mode;
+	mode_t mode;
 	int error;
-	struct timespec now = current_fs_time(inode->i_sb);
+	struct timespec now;
 	unsigned int ia_valid = attr->ia_valid;
 
 	if (!inode)
 		BUG();
 
+	mode = inode->i_mode;
+	now = current_fs_time(inode->i_sb);
+
 	attr->ia_ctime = now;
 	if (!(ia_valid & ATTR_ATIME_SET))
 		attr->ia_atime = now;
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -84,6 +84,7 @@ struct autofs_wait_queue {
 	char *name;
 	/* This is for status reporting upon return */
 	int status;
+	atomic_t notified;
 	atomic_t wait_ctr;
 };
 
@@ -101,6 +102,7 @@ struct autofs_sb_info {
 	int needs_reghost;
 	struct super_block *sb;
 	struct semaphore wq_sem;
+	spinlock_t fs_lock;
 	struct autofs_wait_queue *queues; /* Wait queue pointer */
 };
 
@@ -126,9 +128,18 @@ static inline int autofs4_oz_mode(struct
 static inline int autofs4_ispending(struct dentry *dentry)
 {
 	struct autofs_info *inf = autofs4_dentry_ino(dentry);
+	int pending = 0;
 
-	return (dentry->d_flags & DCACHE_AUTOFS_PENDING) ||
-		(inf != NULL && inf->flags & AUTOFS_INF_EXPIRING);
+	if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
+		return 1;
+
+	if (inf) {
+		spin_lock(&inf->sbi->fs_lock);
+		pending = inf->flags & AUTOFS_INF_EXPIRING;
+		spin_unlock(&inf->sbi->fs_lock);
+	}
+
+	return pending;
 }
 
 static inline void autofs4_copy_atime(struct file *src, struct file *dst)
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfs
 	if (!autofs4_can_expire(top, timeout, do_now))
 		return 0;
 
+	/* Is someone visiting anywhere in the tree ? */
+	if (may_umount_tree(mnt))
+		return 0;
+
 	spin_lock(&dcache_lock);
 repeat:
 	next = this_parent->d_subdirs.next;
@@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(str
 
 		/* Case 2: tree mount, expire iff entire tree is not busy */
 		if (!exp_leaves) {
+			/* Lock the tree as we must expire as a whole */
+			spin_lock(&sbi->fs_lock);
 			if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
-			expired = dentry;
-			break;
+				struct autofs_info *inf = autofs4_dentry_ino(dentry);
+
+				/* Set this flag early to catch sys_chdir and the like */
+				inf->flags |= AUTOFS_INF_EXPIRING;
+				spin_unlock(&sbi->fs_lock);
+				expired = dentry;
+				break;
 			}
+			spin_unlock(&sbi->fs_lock);
 		/* Case 3: direct mount, expire individual leaves */
 		} else {
 			expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_bloc
 	sbi->version = 0;
 	sbi->sub_version = 0;
 	init_MUTEX(&sbi->wq_sem);
+	spin_lock_init(&sbi->fs_lock);
 	sbi->queues = NULL;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -605,7 +605,9 @@ static int autofs4_dir_rmdir(struct inod
 		spin_unlock(&dcache_lock);
 		return -ENOTEMPTY;
 	}
+	spin_lock(&dentry->d_lock);
 	__d_drop(dentry);
+	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 
 	dput(ino->dentry);
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -210,24 +210,27 @@ int autofs4_wait(struct autofs_sb_info *
 		wq->len = len;
 		wq->status = -EINTR; /* Status return if interrupted */
 		atomic_set(&wq->wait_ctr, 2);
+		atomic_set(&wq->notified, 1);
 		up(&sbi->wq_sem);
-
-		DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d",
-			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
-		/* autofs4_notify_daemon() may block */
-		if (notify != NFY_NONE) {
-			autofs4_notify_daemon(sbi,wq, 
-					notify == NFY_MOUNT ?
-						  autofs_ptype_missing :
-						  autofs_ptype_expire_multi);
-		}
 	} else {
 		atomic_inc(&wq->wait_ctr);
 		up(&sbi->wq_sem);
+		kfree(name);
 		DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
 			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
 	}
 
+	if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) {
+		int type = (notify == NFY_MOUNT ?
+			autofs_ptype_missing : autofs_ptype_expire_multi);
+
+		DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
+
+		/* autofs4_notify_daemon() may block */
+		autofs4_notify_daemon(sbi, wq, type);
+	}
+
 	/* wq->name is NULL if and only if the lock is already released */
 
 	if ( sbi->catatonic ) {
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -15,17 +15,6 @@
 #include <linux/smp_lock.h>
 #include <linux/namei.h>
 
-/*
- * The follow_link operation is special: it must behave as a no-op
- * so that a bad root inode can at least be unmounted. To do this
- * we must dput() the base and return the dentry with a dget().
- */
-static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
-{
-	nd_set_link(nd, ERR_PTR(-EIO));
-	return 0;
-}
-
 static int return_EIO(void)
 {
 	return -EIO;
@@ -58,7 +47,7 @@ static struct file_operations bad_file_o
 	.get_unmapped_area = EIO_ERROR,
 };
 
-struct inode_operations bad_inode_ops =
+static struct inode_operations bad_inode_ops =
 {
 	.create		= EIO_ERROR,
 	.lookup		= EIO_ERROR,
@@ -70,7 +59,8 @@ struct inode_operations bad_inode_ops =
 	.mknod		= EIO_ERROR,
 	.rename		= EIO_ERROR,
 	.readlink	= EIO_ERROR,
-	.follow_link	= bad_follow_link,
+	/* follow_link must be no-op, otherwise unmounting this inode
+	   won't work */
 	.truncate	= EIO_ERROR,
 	.permission	= EIO_ERROR,
 	.getattr	= EIO_ERROR,
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -148,14 +148,14 @@ static int aout_core_dump(long signr, st
 /* make sure we actually have a data and stack area to dump */
 	set_fs(USER_DS);
 #ifdef __sparc__
-	if (verify_area(VERIFY_READ, (void __user *)START_DATA(dump), dump.u_dsize))
+	if (!access_ok(VERIFY_READ, (void __user *)START_DATA(dump), dump.u_dsize))
 		dump.u_dsize = 0;
-	if (verify_area(VERIFY_READ, (void __user *)START_STACK(dump), dump.u_ssize))
+	if (!access_ok(VERIFY_READ, (void __user *)START_STACK(dump), dump.u_ssize))
 		dump.u_ssize = 0;
 #else
-	if (verify_area(VERIFY_READ, (void __user *)START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
+	if (!access_ok(VERIFY_READ, (void __user *)START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 		dump.u_dsize = 0;
-	if (verify_area(VERIFY_READ, (void __user *)START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
+	if (!access_ok(VERIFY_READ, (void __user *)START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
 		dump.u_ssize = 0;
 #endif
 
@@ -317,7 +317,7 @@ static int load_aout_binary(struct linux
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = current->mm->mmap_base;
 
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -37,6 +37,7 @@
 #include <linux/pagemap.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/random.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
@@ -165,21 +166,14 @@ create_elf_tables(struct linux_binprm *b
 	if (k_platform) {
 		size_t len = strlen(k_platform) + 1;
 
-#ifdef CONFIG_X86_HT
 		/*
 		 * In some cases (e.g. Hyper-Threading), we want to avoid L1
 		 * evictions by the processes running on the same package. One
 		 * thing we can do is to shuffle the initial stack for them.
-		 *
-		 * The conditionals here are unneeded, but kept in to make the
-		 * code behaviour the same as pre change unless we have
-		 * hyperthreaded processors. This should be cleaned up
-		 * before 2.6
 		 */
 	 
-		if (smp_num_siblings > 1)
-			STACK_ALLOC(p, ((current->pid % 64) << 7));
-#endif
+		p = arch_align_stack(p);
+
 		u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
 		if (__copy_to_user(u_platform, k_platform, len))
 			return -EFAULT;
@@ -257,7 +251,7 @@ create_elf_tables(struct linux_binprm *b
 	}
 
 	/* Populate argv and envp */
-	p = current->mm->arg_start;
+	p = current->mm->arg_end = current->mm->arg_start;
 	while (argc-- > 0) {
 		size_t len;
 		__put_user((elf_addr_t)p, argv++);
@@ -501,6 +495,19 @@ out:
 #define INTERPRETER_ELF 2
 
 
+static unsigned long randomize_stack_top(unsigned long stack_top)
+{
+	unsigned int random_variable = 0;
+
+	if (current->flags & PF_RANDOMIZE)
+		random_variable = get_random_int() % (8*1024*1024);
+#ifdef CONFIG_STACK_GROWSUP
+	return PAGE_ALIGN(stack_top + random_variable);
+#else
+	return PAGE_ALIGN(stack_top - random_variable);
+#endif
+}
+
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
 	struct file *interpreter = NULL; /* to shut gcc up */
@@ -760,13 +767,16 @@ static int load_elf_binary(struct linux_
 	if (elf_read_implies_exec(loc->elf_ex, executable_stack))
 		current->personality |= READ_IMPLIES_EXEC;
 
+	if ( !(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+		current->flags |= PF_RANDOMIZE;
 	arch_pick_mmap_layout(current->mm);
 
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 	current->mm->free_area_cache = current->mm->mmap_base;
-	retval = setup_arg_pages(bprm, STACK_TOP, executable_stack);
+	retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
+				 executable_stack);
 	if (retval < 0) {
 		send_sig(SIGKILL, current, 0);
 		goto out_free_dentry;
@@ -931,6 +941,14 @@ static int load_elf_binary(struct linux_
 
 	set_binfmt(&elf_format);
 
+#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
+	retval = arch_setup_additional_pages(bprm, executable_stack);
+	if (retval < 0) {
+		send_sig(SIGKILL, current, 0);
+		goto out;
+	}
+#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
+
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	create_elf_tables(bprm, &loc->elf_ex, (interpreter_type == INTERPRETER_AOUT),
@@ -1008,6 +1026,7 @@ out_free_ph:
 static int load_elf_library(struct file *file)
 {
 	struct elf_phdr *elf_phdata;
+	struct elf_phdr *eppnt;
 	unsigned long elf_bss, bss, len;
 	int retval, error, i, j;
 	struct elfhdr elf_ex;
@@ -1031,44 +1050,47 @@ static int load_elf_library(struct file 
 	/* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */
 
 	error = -ENOMEM;
-	elf_phdata = (struct elf_phdr *) kmalloc(j, GFP_KERNEL);
+	elf_phdata = kmalloc(j, GFP_KERNEL);
 	if (!elf_phdata)
 		goto out;
 
+	eppnt = elf_phdata;
 	error = -ENOEXEC;
-	retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata, j);
+	retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j);
 	if (retval != j)
 		goto out_free_ph;
 
 	for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
-		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
+		if ((eppnt + i)->p_type == PT_LOAD)
+			j++;
 	if (j != 1)
 		goto out_free_ph;
 
-	while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
+	while (eppnt->p_type != PT_LOAD)
+		eppnt++;
 
 	/* Now use mmap to map the library into memory. */
 	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file,
-			ELF_PAGESTART(elf_phdata->p_vaddr),
-			(elf_phdata->p_filesz +
-			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
+			ELF_PAGESTART(eppnt->p_vaddr),
+			(eppnt->p_filesz +
+			 ELF_PAGEOFFSET(eppnt->p_vaddr)),
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
-			(elf_phdata->p_offset -
-			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
+			(eppnt->p_offset -
+			 ELF_PAGEOFFSET(eppnt->p_vaddr)));
 	up_write(&current->mm->mmap_sem);
-	if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
+	if (error != ELF_PAGESTART(eppnt->p_vaddr))
 		goto out_free_ph;
 
-	elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+	elf_bss = eppnt->p_vaddr + eppnt->p_filesz;
 	if (padzero(elf_bss)) {
 		error = -EFAULT;
 		goto out_free_ph;
 	}
 
-	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
-	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+	len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + ELF_MIN_ALIGN - 1);
+	bss = eppnt->p_memsz + eppnt->p_vaddr;
 	if (bss > len) {
 		down_write(&current->mm->mmap_sem);
 		do_brk(len, bss - len);
@@ -1103,7 +1125,7 @@ static int dump_write(struct file *file,
 	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
 }
 
-static int dump_seek(struct file *file, off_t off)
+static int dump_seek(struct file *file, loff_t off)
 {
 	if (file->f_op->llseek) {
 		if (file->f_op->llseek(file, off, 0) != off)
@@ -1122,10 +1144,14 @@ static int dump_seek(struct file *file, 
  */
 static int maydump(struct vm_area_struct *vma)
 {
-	/* Do not dump I/O mapped devices, shared memory, or special mappings */
-	if (vma->vm_flags & (VM_IO | VM_SHARED | VM_RESERVED))
+	/* Do not dump I/O mapped devices or special mappings */
+	if (vma->vm_flags & (VM_IO | VM_RESERVED))
 		return 0;
 
+	/* Dump shared memory only if mapped from an anonymous file.  */
+	if (vma->vm_flags & VM_SHARED)
+		return vma->vm_file->f_dentry->d_inode->i_nlink == 0;
+
 	/* If it hasn't been written to, don't write it out */
 	if (!vma->anon_vma)
 		return 0;
@@ -1275,7 +1301,7 @@ static void fill_prstatus(struct elf_prs
 static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 		       struct mm_struct *mm)
 {
-	int i, len;
+	unsigned int i, len;
 	
 	/* first copy the parameters from user space */
 	memset(psinfo, 0, sizeof(struct elf_prpsinfo));
@@ -1585,7 +1611,7 @@ static int elf_core_dump(long signr, str
 					DUMP_SEEK (file->f_pos + PAGE_SIZE);
 				} else {
 					void *kaddr;
-					flush_cache_page(vma, addr);
+					flush_cache_page(vma, addr, page_to_pfn(page));
 					kaddr = kmap(page);
 					if ((size += PAGE_SIZE) > limit ||
 					    !dump_write(file, kaddr,
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -299,7 +299,7 @@ static int load_elf_fdpic_binary(struct 
 	/* do this so that we can load the interpreter, if need be
 	 * - we will change some of these later
 	 */
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 
 #ifdef CONFIG_MMU
 	retval = setup_arg_pages(bprm, current->mm->start_stack, executable_stack);
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -520,7 +520,7 @@ static int load_flat_file(struct linux_b
 		DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
 
 		down_write(&current->mm->mmap_sem);
-		textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0);
+		textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0);
 		up_write(&current->mm->mmap_sem);
 		if (!textpos  || textpos >= (unsigned long) -4096) {
 			if (!textpos)
@@ -532,7 +532,7 @@ static int load_flat_file(struct linux_b
 		down_write(&current->mm->mmap_sem);
 		realdatastart = do_mmap(0, 0, data_len + extra +
 				MAX_SHARED_LIBS * sizeof(unsigned long),
-				PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0);
+				PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
 		up_write(&current->mm->mmap_sem);
 
 		if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
@@ -574,7 +574,7 @@ static int load_flat_file(struct linux_b
 		down_write(&current->mm->mmap_sem);
 		textpos = do_mmap(0, 0, text_len + data_len + extra +
 					MAX_SHARED_LIBS * sizeof(unsigned long),
-				PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0);
+				PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
 		up_write(&current->mm->mmap_sem);
 		if (!textpos  || textpos >= (unsigned long) -4096) {
 			if (!textpos)
@@ -650,7 +650,7 @@ static int load_flat_file(struct linux_b
 		current->mm->start_brk = datapos + data_len + bss_len;
 		current->mm->brk = (current->mm->start_brk + 3) & ~3;
 		current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
-		current->mm->rss = 0;
+		set_mm_counter(current->mm, rss, 0);
 	}
 
 	if (flags & FLAT_FLAG_KTRACE)
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -259,7 +259,7 @@ load_som_binary(struct linux_binprm * bp
 	create_som_tables(bprm);
 
 	current->mm->start_stack = bprm->p;
-	current->mm->rss = 0;
+	set_mm_counter(current->mm, rss, 0);
 
 #if 0
 	printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk);
diff --git a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -28,7 +28,6 @@
 
 #define BIO_POOL_SIZE 256
 
-static mempool_t *bio_pool;
 static kmem_cache_t *bio_slab;
 
 #define BIOVEC_NR_POOLS 6
@@ -40,11 +39,10 @@ static kmem_cache_t *bio_slab;
 #define BIO_SPLIT_ENTRIES 8	
 mempool_t *bio_split_pool;
 
-struct biovec_pool {
+struct biovec_slab {
 	int nr_vecs;
 	char *name; 
 	kmem_cache_t *slab;
-	mempool_t *pool;
 };
 
 /*
@@ -54,15 +52,32 @@ struct biovec_pool {
  */
 
 #define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = {
+static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] = {
 	BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
 };
 #undef BV
 
-static inline struct bio_vec *bvec_alloc(int gfp_mask, int nr, unsigned long *idx)
+/*
+ * bio_set is used to allow other portions of the IO system to
+ * allocate their own private memory pools for bio and iovec structures.
+ * These memory pools in turn all allocate from the bio_slab
+ * and the bvec_slabs[].
+ */
+struct bio_set {
+	mempool_t *bio_pool;
+	mempool_t *bvec_pools[BIOVEC_NR_POOLS];
+};
+
+/*
+ * fs_bio_set is the bio_set containing bio and iovec memory pools used by
+ * IO code that does not need private memory pools.
+ */
+static struct bio_set *fs_bio_set;
+
+static inline struct bio_vec *bvec_alloc_bs(unsigned int __nocast gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
 {
-	struct biovec_pool *bp;
 	struct bio_vec *bvl;
+	struct biovec_slab *bp;
 
 	/*
 	 * see comment near bvec_array define!
@@ -80,26 +95,27 @@ static inline struct bio_vec *bvec_alloc
 	/*
 	 * idx now points to the pool we want to allocate from
 	 */
-	bp = bvec_array + *idx;
 
-	bvl = mempool_alloc(bp->pool, gfp_mask);
+	bp = bvec_slabs + *idx;
+	bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
 	if (bvl)
 		memset(bvl, 0, bp->nr_vecs * sizeof(struct bio_vec));
+
 	return bvl;
 }
 
 /*
- * default destructor for a bio allocated with bio_alloc()
+ * default destructor for a bio allocated with bio_alloc_bioset()
  */
 static void bio_destructor(struct bio *bio)
 {
 	const int pool_idx = BIO_POOL_IDX(bio);
-	struct biovec_pool *bp = bvec_array + pool_idx;
+	struct bio_set *bs = bio->bi_set;
 
 	BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
 
-	mempool_free(bio->bi_io_vec, bp->pool);
-	mempool_free(bio, bio_pool);
+	mempool_free(bio->bi_io_vec, bs->bvec_pools[pool_idx]);
+	mempool_free(bio, bs->bio_pool);
 }
 
 inline void bio_init(struct bio *bio)
@@ -121,18 +137,22 @@ inline void bio_init(struct bio *bio)
 }
 
 /**
- * bio_alloc - allocate a bio for I/O
+ * bio_alloc_bioset - allocate a bio for I/O
  * @gfp_mask:   the GFP_ mask given to the slab allocator
  * @nr_iovecs:	number of iovecs to pre-allocate
+ * @bs:		the bio_set to allocate from
  *
  * Description:
- *   bio_alloc will first try it's on mempool to satisfy the allocation.
+ *   bio_alloc_bioset will first try it's on mempool to satisfy the allocation.
  *   If %__GFP_WAIT is set then we will block on the internal pool waiting
  *   for a &struct bio to become free.
+ *
+ *   allocate bio and iovecs from the memory pools specified by the
+ *   bio_set structure.
  **/
-struct bio *bio_alloc(int gfp_mask, int nr_iovecs)
+struct bio *bio_alloc_bioset(unsigned int __nocast gfp_mask, int nr_iovecs, struct bio_set *bs)
 {
-	struct bio *bio = mempool_alloc(bio_pool, gfp_mask);
+	struct bio *bio = mempool_alloc(bs->bio_pool, gfp_mask);
 
 	if (likely(bio)) {
 		struct bio_vec *bvl = NULL;
@@ -141,22 +161,43 @@ struct bio *bio_alloc(int gfp_mask, int 
 		if (likely(nr_iovecs)) {
 			unsigned long idx;
 
-			bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
+			bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
 			if (unlikely(!bvl)) {
-				mempool_free(bio, bio_pool);
+				mempool_free(bio, bs->bio_pool);
 				bio = NULL;
 				goto out;
 			}
 			bio->bi_flags |= idx << BIO_POOL_OFFSET;
-			bio->bi_max_vecs = bvec_array[idx].nr_vecs;
+			bio->bi_max_vecs = bvec_slabs[idx].nr_vecs;
 		}
 		bio->bi_io_vec = bvl;
 		bio->bi_destructor = bio_destructor;
+		bio->bi_set = bs;
 	}
 out:
 	return bio;
 }
 
+struct bio *bio_alloc(unsigned int __nocast gfp_mask, int nr_iovecs)
+{
+	return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+}
+
+void zero_fill_bio(struct bio *bio)
+{
+	unsigned long flags;
+	struct bio_vec *bv;
+	int i;
+
+	bio_for_each_segment(bv, bio, i) {
+		char *data = bvec_kmap_irq(bv, &flags);
+		memset(data, 0, bv->bv_len);
+		flush_dcache_page(bv->bv_page);
+		bvec_kunmap_irq(data, &flags);
+	}
+}
+EXPORT_SYMBOL(zero_fill_bio);
+
 /**
  * bio_put - release a reference to a bio
  * @bio:   bio to release reference to
@@ -231,9 +272,9 @@ inline void __bio_clone(struct bio *bio,
  *
  * 	Like __bio_clone, only also allocates the returned bio
  */
-struct bio *bio_clone(struct bio *bio, int gfp_mask)
+struct bio *bio_clone(struct bio *bio, unsigned int __nocast gfp_mask)
 {
-	struct bio *b = bio_alloc(gfp_mask, bio->bi_max_vecs);
+	struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
 
 	if (b)
 		__bio_clone(b, bio);
@@ -589,6 +630,7 @@ out:
 
 /**
  *	bio_map_user	-	map user address into bio
+ *	@q: the request_queue_t for the bio
  *	@bdev: destination block device
  *	@uaddr: start of user address
  *	@len: length in bytes
@@ -894,7 +936,7 @@ struct bio_pair *bio_split(struct bio *b
 	return bp;
 }
 
-static void *bio_pair_alloc(int gfp_flags, void *data)
+static void *bio_pair_alloc(unsigned int __nocast gfp_flags, void *data)
 {
 	return kmalloc(sizeof(struct bio_pair), gfp_flags);
 }
@@ -904,11 +946,99 @@ static void bio_pair_free(void *bp, void
 	kfree(bp);
 }
 
-static void __init biovec_init_pools(void)
+
+/*
+ * create memory pools for biovec's in a bio_set.
+ * use the global biovec slabs created for general use.
+ */
+static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
+{
+	int i;
+
+	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
+		struct biovec_slab *bp = bvec_slabs + i;
+		mempool_t **bvp = bs->bvec_pools + i;
+
+		if (i >= scale)
+			pool_entries >>= 1;
+
+		*bvp = mempool_create(pool_entries, mempool_alloc_slab,
+					mempool_free_slab, bp->slab);
+		if (!*bvp)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+static void biovec_free_pools(struct bio_set *bs)
+{
+	int i;
+
+	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
+		mempool_t *bvp = bs->bvec_pools[i];
+
+		if (bvp)
+			mempool_destroy(bvp);
+	}
+
+}
+
+void bioset_free(struct bio_set *bs)
+{
+	if (bs->bio_pool)
+		mempool_destroy(bs->bio_pool);
+
+	biovec_free_pools(bs);
+
+	kfree(bs);
+}
+
+struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
+{
+	struct bio_set *bs = kmalloc(sizeof(*bs), GFP_KERNEL);
+
+	if (!bs)
+		return NULL;
+
+	memset(bs, 0, sizeof(*bs));
+	bs->bio_pool = mempool_create(bio_pool_size, mempool_alloc_slab,
+			mempool_free_slab, bio_slab);
+
+	if (!bs->bio_pool)
+		goto bad;
+
+	if (!biovec_create_pools(bs, bvec_pool_size, scale))
+		return bs;
+
+bad:
+	bioset_free(bs);
+	return NULL;
+}
+
+static void __init biovec_init_slabs(void)
+{
+	int i;
+
+	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
+		int size;
+		struct biovec_slab *bvs = bvec_slabs + i;
+
+		size = bvs->nr_vecs * sizeof(struct bio_vec);
+		bvs->slab = kmem_cache_create(bvs->name, size, 0,
+                                SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+	}
+}
+
+static int __init init_bio(void)
 {
-	int i, size, megabytes, pool_entries = BIO_POOL_SIZE;
+	int megabytes, bvec_pool_entries;
 	int scale = BIOVEC_NR_POOLS;
 
+	bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
+				SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+
+	biovec_init_slabs();
+
 	megabytes = nr_free_pages() >> (20 - PAGE_SHIFT);
 
 	/*
@@ -928,38 +1058,13 @@ static void __init biovec_init_pools(voi
 	/*
 	 * scale number of entries
 	 */
-	pool_entries = megabytes * 2;
-	if (pool_entries > 256)
-		pool_entries = 256;
-
-	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-		struct biovec_pool *bp = bvec_array + i;
-
-		size = bp->nr_vecs * sizeof(struct bio_vec);
-
-		bp->slab = kmem_cache_create(bp->name, size, 0,
-				SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
-
-		if (i >= scale)
-			pool_entries >>= 1;
-
-		bp->pool = mempool_create(pool_entries, mempool_alloc_slab,
-					mempool_free_slab, bp->slab);
-		if (!bp->pool)
-			panic("biovec: can't init mempool\n");
-	}
-}
-
-static int __init init_bio(void)
-{
-	bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
-				SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
-	bio_pool = mempool_create(BIO_POOL_SIZE, mempool_alloc_slab,
-				mempool_free_slab, bio_slab);
-	if (!bio_pool)
-		panic("bio: can't create mempool\n");
-
-	biovec_init_pools();
+	bvec_pool_entries = megabytes * 2;
+	if (bvec_pool_entries > 256)
+		bvec_pool_entries = 256;
+
+	fs_bio_set = bioset_create(BIO_POOL_SIZE, bvec_pool_entries, scale);
+	if (!fs_bio_set)
+		panic("bio: can't allocate bios\n");
 
 	bio_split_pool = mempool_create(BIO_SPLIT_ENTRIES,
 				bio_pair_alloc, bio_pair_free, NULL);
@@ -988,3 +1093,6 @@ EXPORT_SYMBOL(bio_split);
 EXPORT_SYMBOL(bio_split_pool);
 EXPORT_SYMBOL(bio_copy_user);
 EXPORT_SYMBOL(bio_uncopy_user);
+EXPORT_SYMBOL(bioset_create);
+EXPORT_SYMBOL(bioset_free);
+EXPORT_SYMBOL(bio_alloc_bioset);
diff --git a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -530,7 +530,7 @@ int check_disk_change(struct block_devic
 	if (!bdops->media_changed(bdev->bd_disk))
 		return 0;
 
-	if (__invalidate_device(bdev, 0))
+	if (__invalidate_device(bdev))
 		printk("VFS: busy inodes on changed media.\n");
 
 	if (bdops->revalidate_disk)
diff --git a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -39,6 +39,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/bitops.h>
+#include <linux/mpage.h>
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 static void invalidate_bh_lrus(void);
@@ -217,7 +218,7 @@ struct super_block *freeze_bdev(struct b
 	sb = get_super(bdev);
 	if (sb && !(sb->s_flags & MS_RDONLY)) {
 		sb->s_frozen = SB_FREEZE_WRITE;
-		wmb();
+		smp_wmb();
 
 		sync_inodes_sb(sb, 0);
 		DQUOT_SYNC(sb);
@@ -234,7 +235,7 @@ struct super_block *freeze_bdev(struct b
 		sync_inodes_sb(sb, 1);
 
 		sb->s_frozen = SB_FREEZE_TRANS;
-		wmb();
+		smp_wmb();
 
 		sync_blockdev(sb->s_bdev);
 
@@ -262,7 +263,7 @@ void thaw_bdev(struct block_device *bdev
 		if (sb->s_op->unlockfs)
 			sb->s_op->unlockfs(sb);
 		sb->s_frozen = SB_UNFROZEN;
-		wmb();
+		smp_wmb();
 		wake_up(&sb->s_wait_unfrozen);
 		drop_super(sb);
 	}
@@ -773,15 +774,14 @@ repeat:
 /**
  * sync_mapping_buffers - write out and wait upon a mapping's "associated"
  *                        buffers
- * @buffer_mapping - the mapping which backs the buffers' data
- * @mapping - the mapping which wants those buffers written
+ * @mapping: the mapping which wants those buffers written
  *
  * Starts I/O against the buffers at mapping->private_list, and waits upon
  * that I/O.
  *
- * Basically, this is a convenience function for fsync().  @buffer_mapping is
- * the blockdev which "owns" the buffers and @mapping is a file or directory
- * which needs those buffers to be written for a successful fsync().
+ * Basically, this is a convenience function for fsync().
+ * @mapping is a file or directory which needs those buffers to be written for
+ * a successful fsync().
  */
 int sync_mapping_buffers(struct address_space *mapping)
 {
@@ -875,15 +875,15 @@ int __set_page_dirty_buffers(struct page
 	spin_unlock(&mapping->private_lock);
 
 	if (!TestSetPageDirty(page)) {
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 		if (page->mapping) {	/* Race with truncate? */
-			if (!mapping->backing_dev_info->memory_backed)
+			if (mapping_cap_account_dirty(mapping))
 				inc_page_state(nr_dirty);
 			radix_tree_tag_set(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
 	}
 	
@@ -1210,7 +1210,7 @@ grow_buffers(struct block_device *bdev, 
 	return 1;
 }
 
-struct buffer_head *
+static struct buffer_head *
 __getblk_slow(struct block_device *bdev, sector_t block, int size)
 {
 	/* Size must be multiple of hard sectorsize */
@@ -1262,6 +1262,7 @@ __getblk_slow(struct block_device *bdev,
 
 /**
  * mark_buffer_dirty - mark a buffer_head as needing writeout
+ * @bh: the buffer_head to mark dirty
  *
  * mark_buffer_dirty() will set the dirty bit against the buffer, then set its
  * backing page dirty, then tag the page as dirty in its address_space's radix
@@ -1500,6 +1501,7 @@ EXPORT_SYMBOL(__breadahead);
 
 /**
  *  __bread() - reads a specified block and returns the bh
+ *  @bdev: the block_device to read from
  *  @block: number of block
  *  @size: size (in bytes) to read
  * 
@@ -1807,7 +1809,6 @@ static int __block_write_full_page(struc
 	} while (bh != head);
 
 	do {
-		get_bh(bh);
 		if (!buffer_mapped(bh))
 			continue;
 		/*
@@ -1836,7 +1837,6 @@ static int __block_write_full_page(struc
 	 */
 	BUG_ON(PageWriteback(page));
 	set_page_writeback(page);
-	unlock_page(page);
 
 	do {
 		struct buffer_head *next = bh->b_this_page;
@@ -1844,9 +1844,9 @@ static int __block_write_full_page(struc
 			submit_bh(WRITE, bh);
 			nr_underway++;
 		}
-		put_bh(bh);
 		bh = next;
 	} while (bh != head);
+	unlock_page(page);
 
 	err = 0;
 done:
@@ -1885,7 +1885,6 @@ recover:
 	bh = head;
 	/* Recovery: lock and submit the mapped buffers */
 	do {
-		get_bh(bh);
 		if (buffer_mapped(bh) && buffer_dirty(bh)) {
 			lock_buffer(bh);
 			mark_buffer_async_write(bh);
@@ -1908,7 +1907,6 @@ recover:
 			submit_bh(WRITE, bh);
 			nr_underway++;
 		}
-		put_bh(bh);
 		bh = next;
 	} while (bh != head);
 	goto done;
@@ -1951,7 +1949,7 @@ static int __block_prepare_write(struct 
 		if (!buffer_mapped(bh)) {
 			err = get_block(inode, block, bh, 1);
 			if (err)
-				goto out;
+				break;
 			if (buffer_new(bh)) {
 				clear_buffer_new(bh);
 				unmap_underlying_metadata(bh->b_bdev,
@@ -1993,10 +1991,12 @@ static int __block_prepare_write(struct 
 	while(wait_bh > wait) {
 		wait_on_buffer(*--wait_bh);
 		if (!buffer_uptodate(*wait_bh))
-			return -EIO;
+			err = -EIO;
 	}
-	return 0;
-out:
+	if (!err)
+		return err;
+
+	/* Error case: */
 	/*
 	 * Zero out any newly allocated blocks to avoid exposing stale
 	 * data.  If BH_New is set, we know that the block was newly
@@ -2077,8 +2077,7 @@ int block_read_full_page(struct page *pa
 	int nr, i;
 	int fully_mapped = 1;
 
-	if (!PageLocked(page))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
 	blocksize = 1 << inode->i_blkbits;
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
@@ -2095,9 +2094,12 @@ int block_read_full_page(struct page *pa
 			continue;
 
 		if (!buffer_mapped(bh)) {
+			int err = 0;
+
 			fully_mapped = 0;
 			if (iblock < lblock) {
-				if (get_block(inode, iblock, bh, 0))
+				err = get_block(inode, iblock, bh, 0);
+				if (err)
 					SetPageError(page);
 			}
 			if (!buffer_mapped(bh)) {
@@ -2105,7 +2107,8 @@ int block_read_full_page(struct page *pa
 				memset(kaddr + i * blocksize, 0, blocksize);
 				flush_dcache_page(page);
 				kunmap_atomic(kaddr, KM_USER0);
-				set_buffer_uptodate(bh);
+				if (!err)
+					set_buffer_uptodate(bh);
 				continue;
 			}
 			/*
@@ -2509,6 +2512,61 @@ int nobh_commit_write(struct file *file,
 EXPORT_SYMBOL(nobh_commit_write);
 
 /*
+ * nobh_writepage() - based on block_full_write_page() except
+ * that it tries to operate without attaching bufferheads to
+ * the page.
+ */
+int nobh_writepage(struct page *page, get_block_t *get_block,
+			struct writeback_control *wbc)
+{
+	struct inode * const inode = page->mapping->host;
+	loff_t i_size = i_size_read(inode);
+	const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+	unsigned offset;
+	void *kaddr;
+	int ret;
+
+	/* Is the page fully inside i_size? */
+	if (page->index < end_index)
+		goto out;
+
+	/* Is the page fully outside i_size? (truncate in progress) */
+	offset = i_size & (PAGE_CACHE_SIZE-1);
+	if (page->index >= end_index+1 || !offset) {
+		/*
+		 * The page may have dirty, unmapped buffers.  For example,
+		 * they may have been added in ext3_writepage().  Make them
+		 * freeable here, so the page does not leak.
+		 */
+#if 0
+		/* Not really sure about this  - do we need this ? */
+		if (page->mapping->a_ops->invalidatepage)
+			page->mapping->a_ops->invalidatepage(page, offset);
+#endif
+		unlock_page(page);
+		return 0; /* don't care */
+	}
+
+	/*
+	 * The page straddles i_size.  It must be zeroed out on each and every
+	 * writepage invocation because it may be mmapped.  "A file is mapped
+	 * in multiples of the page size.  For a file that is not a multiple of
+	 * the  page size, the remaining memory is zeroed when mapped, and
+	 * writes to that region are not written out to the file."
+	 */
+	kaddr = kmap_atomic(page, KM_USER0);
+	memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+out:
+	ret = mpage_writepage(page, get_block, wbc);
+	if (ret == -EAGAIN)
+		ret = __block_write_full_page(inode, page, get_block, wbc);
+	return ret;
+}
+EXPORT_SYMBOL(nobh_writepage);
+
+/*
  * This function assumes that ->prepare_write() uses nobh_prepare_write().
  */
 int nobh_truncate_page(struct address_space *mapping, loff_t from)
@@ -2782,14 +2840,14 @@ void ll_rw_block(int rw, int nr, struct 
 
 		get_bh(bh);
 		if (rw == WRITE) {
-			bh->b_end_io = end_buffer_write_sync;
 			if (test_clear_buffer_dirty(bh)) {
+				bh->b_end_io = end_buffer_write_sync;
 				submit_bh(WRITE, bh);
 				continue;
 			}
 		} else {
-			bh->b_end_io = end_buffer_read_sync;
 			if (!buffer_uptodate(bh)) {
+				bh->b_end_io = end_buffer_read_sync;
 				submit_bh(rw, bh);
 				continue;
 			}
@@ -2861,7 +2919,7 @@ drop_buffers(struct page *page, struct b
 
 	bh = head;
 	do {
-		if (buffer_write_io_error(bh))
+		if (buffer_write_io_error(bh) && page->mapping)
 			set_bit(AS_EIO, &page->mapping->flags);
 		if (buffer_busy(bh))
 			goto failed;
@@ -2996,7 +3054,7 @@ static void recalc_bh_state(void)
 	buffer_heads_over_limit = (tot > max_buffer_heads);
 }
 	
-struct buffer_head *alloc_buffer_head(int gfp_flags)
+struct buffer_head *alloc_buffer_head(unsigned int __nocast gfp_flags)
 {
 	struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
 	if (ret) {
@@ -3059,7 +3117,7 @@ void __init buffer_init(void)
 
 	bh_cachep = kmem_cache_create("buffer_head",
 			sizeof(struct buffer_head), 0,
-			SLAB_PANIC, init_buffer_head, NULL);
+			SLAB_RECLAIM_ACCOUNT|SLAB_PANIC, init_buffer_head, NULL);
 
 	/*
 	 * Limit the bh occupancy to 10% of ZONE_NORMAL
diff --git a/fs/char_dev.c b/fs/char_dev.c
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -28,7 +28,7 @@ static struct kobj_map *cdev_map;
 
 #define MAX_PROBE_HASH 255	/* random */
 
-static DEFINE_RWLOCK(chrdevs_lock);
+static DECLARE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
 	struct char_device_struct *next;
@@ -54,13 +54,13 @@ int get_chrdev_list(char *page)
 
 	len = sprintf(page, "Character devices:\n");
 
-	read_lock(&chrdevs_lock);
+	down(&chrdevs_lock);
 	for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
 		for (cd = chrdevs[i]; cd; cd = cd->next)
 			len += sprintf(page+len, "%3d %s\n",
 				       cd->major, cd->name);
 	}
-	read_unlock(&chrdevs_lock);
+	up(&chrdevs_lock);
 
 	return len;
 }
@@ -90,7 +90,7 @@ __register_chrdev_region(unsigned int ma
 
 	memset(cd, 0, sizeof(struct char_device_struct));
 
-	write_lock_irq(&chrdevs_lock);
+	down(&chrdevs_lock);
 
 	/* temporary */
 	if (major == 0) {
@@ -125,10 +125,10 @@ __register_chrdev_region(unsigned int ma
 	}
 	cd->next = *cp;
 	*cp = cd;
-	write_unlock_irq(&chrdevs_lock);
+	up(&chrdevs_lock);
 	return cd;
 out:
-	write_unlock_irq(&chrdevs_lock);
+	up(&chrdevs_lock);
 	kfree(cd);
 	return ERR_PTR(ret);
 }
@@ -139,7 +139,7 @@ __unregister_chrdev_region(unsigned majo
 	struct char_device_struct *cd = NULL, **cp;
 	int i = major_to_index(major);
 
-	write_lock_irq(&chrdevs_lock);
+	up(&chrdevs_lock);
 	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 		if ((*cp)->major == major &&
 		    (*cp)->baseminor == baseminor &&
@@ -149,7 +149,7 @@ __unregister_chrdev_region(unsigned majo
 		cd = *cp;
 		*cp = cd->next;
 	}
-	write_unlock_irq(&chrdevs_lock);
+	up(&chrdevs_lock);
 	return cd;
 }
 
@@ -328,7 +328,7 @@ void cd_forget(struct inode *inode)
 	spin_unlock(&cdev_lock);
 }
 
-void cdev_purge(struct cdev *cdev)
+static void cdev_purge(struct cdev *cdev)
 {
 	spin_lock(&cdev_lock);
 	while (!list_empty(&cdev->list)) {
@@ -380,8 +380,6 @@ void cdev_del(struct cdev *p)
 }
 
 
-static decl_subsys(cdev, NULL, NULL);
-
 static void cdev_default_release(struct kobject *kobj)
 {
 	struct cdev *p = container_of(kobj, struct cdev, kobj);
@@ -434,13 +432,7 @@ static struct kobject *base_probe(dev_t 
 
 void __init chrdev_init(void)
 {
-/*
- * Keep cdev_subsys around because (and only because) the kobj_map code
- * depends on the rwsem it contains.  We don't make it public in sysfs,
- * however.
- */
-	subsystem_init(&cdev_subsys);
-	cdev_map = kobj_map_init(base_probe, &cdev_subsys);
+	cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
 }
 
 
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -4,13 +4,16 @@ Steve French (sfrench@samba.org)
 
 The author wishes to express his appreciation and thanks to:
 Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
-improvements. Thanks to IBM for allowing me the time and test resources to pursue
-this project. Jim McDonough from IBM (and the Samba Team) for his help.
-The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+improvements. Thanks to IBM for allowing me time and test resources to pursue
+this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
+the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Jeremy Allison of the Samba team has done invaluable work in adding the server
+side of the original CIFS Unix extensions and reviewing and implementing
+portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
 Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
-for proving years ago that a very good smb/cifs client could be done on a Unix like 
-operating system.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin 
-and others for their work on the Linux smbfs module over the years. Thanks to
+for proving years ago that very good smb/cifs clients could be done on Unix-like
+operating systems.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John 
+Newbigin and others for their work on the Linux smbfs module.  Thanks to
 the other members of the Storage Network Industry Association CIFS Technical
 Workgroup for their work specifying this highly complex protocol and finally
 thanks to the Samba team for their technical advice and encouragement.
@@ -24,7 +27,11 @@ Shobhit Dayal
 Sergey Vlasov
 Richard Hughes
 Yury Umanets
-Mark Hamzy
+Mark Hamzy (for some of the early cifs IPv6 work)
+Domen Puncer
+Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
+Vince Negri and Dave Stahl (for finding an important caching bug)
+Adrian Bunk (kcalloc cleanups)
 
 Test case and Bug Report contributors
 -------------------------------------
@@ -34,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexande
 Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
 Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
 mention to the Stanford Checker (SWAT) which pointed out many minor
-bugs in error paths.
+bugs in error paths.  Valuable suggestions also have come from Al Viro
+and Dave Miller.
 
 And thanks to the IBM LTC and Power test teams and SuSE testers for
 finding multiple bugs during excellent stress test runs.
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,69 @@
+Version 1.34
+------------
+Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
+Do not oops if root user kills cifs oplock kernel thread or
+kills the cifsd thread (NB: killing the cifs kernel threads is not
+recommended, unmount and rmmod cifs will kill them when they are
+no longer needed).  Fix readdir to ASCII servers (ie older servers
+which do not support Unicode) and also require asterik.
+Fix out of memory case in which data could be written one page
+off in the page cache.
+
+Version 1.33
+------------
+Fix caching problem, in which readdir of directory containing a file
+which was cached could cause the file's time stamp to be updated
+without invalidating the readahead data (so we could get stale
+file data on the client for that file even as the server copy changed).
+Cleanup response processing so cifsd can not loop when abnormally
+terminated.
+
+
+Version 1.32
+------------
+Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
+transact response for an SMB request and search entry split across two frames.
+Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
+as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
+unless server explicitly claims to support them in CIFS Unix extensions
+POSIX ACL capability bit. Fix packet signing when multiuser mounting with
+different users from the same client to the same server. Fix oops in
+cifs_close. Add mount option for remapping reserved characters in
+filenames (also allow recognizing files with created by SFU which have any
+of these seven reserved characters, except backslash, to be recognized).
+Fix invalid transact2 message (we were sometimes trying to interpret
+oplock breaks as SMB responses). Add ioctl for checking that the
+current uid matches the uid of the mounter (needed by umount.cifs).
+Reduce the number of large buffer allocations in cifs response processing
+(significantly reduces memory pressure under heavy stress with multiple
+processes accessing the same server at the same time).
+
+Version 1.31
+------------
+Fix updates of DOS attributes and time fields so that files on NT4 servers
+do not get marked delete on close. Display sizes of cifs buffer pools in
+cifs stats. Fix oops in unmount when cifsd thread being killed by 
+shutdown. Add generic readv/writev and aio support. Report inode numbers 
+consistently in readdir and lookup (when serverino mount option is
+specified use the inode number that the server reports - for both lookup
+and readdir, otherwise by default the locally generated inode number is used
+for inodes created in either path since servers are not always able to 
+provide unique inode numbers when exporting multiple volumes from under one
+sharename).
+
+Version 1.30
+------------
+Allow new nouser_xattr mount parm to disable xattr support for user namespace.
+Do not flag user_xattr mount parm in dmesg.  Retry failures setting file time  
+(mostly affects NT4 servers) by retry with handle based network operation. 
+Add new POSIX Query FS Info for returning statfs info more accurately.
+Handle passwords with multiple commas in them.
+
+Version 1.29
+------------
+Fix default mode in sysfs of cifs module parms.  Remove old readdir routine.
+Fix capabilities flags for large readx so as to allow reads larger than 64K.
+
 Version 1.28
 ------------
 Add module init parm for large SMB buffer size (to allow it to be changed
@@ -7,7 +73,8 @@ returning from mount when experimental E
 SpnegoNegotiated returning invalid error. Fix case to retry better when 
 peek returns from 1 to 3 bytes on socket which should have more data.
 Fixed path based calls (such as cifs lookup) to handle path names
-longer than 530 (now can handle PATH_MAX).
+longer than 530 (now can handle PATH_MAX). Fix pass through authentication
+from Samba server to DC (Samba required dummy LM password).
 
 Version 1.27
 ------------
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o
diff --git a/fs/cifs/README b/fs/cifs/README
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -32,9 +32,9 @@ the cifs download to your kernel build d
 6) make modules (or "make" if CIFS VFS not to be built as a module)
 
 For Linux 2.6:
-1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper
-at bk://linux.bkbits.net/linux-2.5) and change directory into the top
-of the kernel directory tree (e.g. /usr/src/linux-2.5.73)
+1) Download the kernel (e.g. from http://www.kernel.org)
+and change directory into the top of the kernel directory tree
+(e.g. /usr/src/linux-2.5.73)
 2) make menuconfig (or make xconfig)
 3) select cifs from within the network filesystem choices
 4) save and exit
@@ -75,7 +75,7 @@ Allowing User Mounts
 ====================
 To permit users to mount and unmount over directories they own is possible
 with the cifs vfs.  A way to enable such mounting is to mark the mount.cifs
-utility as suid (e.g. "chmod +s /sbin/mount/cifs). To enable users to 
+utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to 
 umount shares they mount requires
 1) mount.cifs version 1.4 or later
 2) an entry for the share in /etc/fstab indicating that a user may
@@ -97,6 +97,26 @@ mount.cifs with the following flag: 
 There is a corresponding manual page for cifs mounting in the Samba 3.0 and
 later source tree in docs/manpages/mount.cifs.8 
 
+Allowing User Unmounts
+======================
+To permit users to ummount directories that they have user mounted (see above),
+the utility umount.cifs may be used.  It may be invoked directly, or if 
+umount.cifs is placed in /sbin, umount can invoke the cifs umount helper
+(at least for most versions of the umount utility) for umount of cifs
+mounts, unless umount is invoked with -i (which will avoid invoking a umount
+helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked
+as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions
+allow adding entries to a file to the /etc/permissions file to achieve the
+equivalent suid effect).  For this utility to succeed the target path
+must be a cifs mount, and the uid of the current user must match the uid
+of the user who mounted the resource.
+
+Also note that the customary way of allowing user mounts and unmounts is 
+(instead of using mount.cifs and unmount.cifs as suid) to add a line
+to the file /etc/fstab for each //server/share you wish to mount, but
+this can become unwieldy when potential mount targets include many
+or  unpredictable UNC names.
+
 Samba Considerations 
 ==================== 
 To get the maximum benefit from the CIFS VFS, we recommend using a server that 
@@ -122,12 +142,14 @@ cifs client, and that EA support is pres
 3.0.6 and later (also EA support works in all versions of Windows, at least to
 shares on NTFS filesystems).  Extended Attribute (xattr) support is an optional
 feature of most Linux filesystems which may require enabling via
-make menuconfig.
+make menuconfig. Client support for extended attributes (user xattr) can be
+disabled on a per-mount basis by specifying "nouser_xattr" on mount.
 
 The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers
 version 3.10 and later.  Setting POSIX ACLs requires enabling both XATTR and 
 then POSIX support in the CIFS configuration options when building the cifs
-module.
+module.  POSIX ACL support can be disabled on a per mount basic by specifying
+"noacl" on mount.
  
 Some administrators may want to change Samba's smb.conf "map archive" and 
 "create mask" parameters from the default.  Unless the create mask is changed
@@ -349,7 +371,7 @@ A partial list of the supported mount op
 		on newly created files, directories, and devices (create, 
 		mkdir, mknod) which will result in the server setting the
 		uid and gid to the default (usually the server uid of the
-		usern who mounted the share).  Letting the server (rather than
+		user who mounted the share).  Letting the server (rather than
 		the client) set the uid and gid is the default. This
 		parameter has no effect if the CIFS Unix Extensions are not
 		negotiated.
@@ -362,7 +384,7 @@ A partial list of the supported mount op
 		client (e.g. when the application is doing large sequential
 		reads bigger than page size without rereading the same data) 
 		this can provide better performance than the default
-		behavior which caches reads (reaadahead) and writes 
+		behavior which caches reads (readahead) and writes 
 		(writebehind) through the local Linux client pagecache 
 		if oplock (caching token) is granted and held. Note that
 		direct allows write operations larger than page size
@@ -370,6 +392,23 @@ A partial list of the supported mount op
   acl   	Allow setfacl and getfacl to manage posix ACLs if server
 		supports them.  (default)
   noacl 	Do not allow setfacl and getfacl calls on this mount
+  user_xattr    Allow getting and setting user xattrs as OS/2 EAs (extended
+		attributes) to the server (default) e.g. via setfattr 
+		and getfattr utilities. 
+  nouser_xattr  Do not allow getfattr/setfattr to get/set xattrs 
+  mapchars      Translate six of the seven reserved characters (not backslash)
+			*?<>|:
+		to the remap range (above 0xF000), which also
+		allows the CIFS client to recognize files created with
+		such characters by Windows's POSIX emulation. This can
+		also be useful when mounting to most versions of Samba
+		(which also forbids creating and opening files
+		whose names contain any of these seven characters).
+		This has no effect if the server does not support
+		Unicode on the wire.
+ nomapchars     Do not translate any of these seven characters (default).
+ remount        remount the share (often used to change from ro to rw mounts
+	        or vice versa)
 		
 The mount.cifs mount helper also accepts a few mount options before -o
 including:
@@ -386,7 +425,7 @@ Misc /proc/fs/cifs Flags and Debug Info
 =======================================
 Informational pseudo-files:
 DebugData		Displays information about active CIFS sessions
-			and shares.
+			and shares, as well as the cifs.ko version.
 Stats			Lists summary resource usage information as well as per
 			share statistics, if CONFIG_CIFS_STATS in enabled
 			in the kernel configuration.
@@ -443,7 +482,7 @@ and for more extensive tracing including
 Two other experimental features are under development and to test 
 require enabling CONFIG_CIFS_EXPERIMENTAL
 
-	More efficient write operations and SMB buffer handling
+	More efficient write operations
 
 	DNOTIFY fcntl: needed for support of directory change 
 			    notification and perhaps later for file leases)
@@ -461,8 +500,8 @@ returned success.
 	
 Also note that "cat /proc/fs/cifs/DebugData" will display information about 
 the active sessions and the shares that are mounted.  Note: NTLMv2 enablement 
-will not work since they its implementation is not quite complete yet.
-Do not alter these configuration values unless you are doing specific testing.  
+will not work since its implementation is not quite complete yet. Do not alter
+the ExtendedSecurity configuration value unless you are doing specific testing.
 Enabling extended security works to Windows 2000 Workstations and XP but not to 
 Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" 
 (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not 
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.22 July 30, 2004 
+version 1.34 April 29, 2005
 
 A Partial List of Missing Features
 ==================================
@@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. 
 better)
 
 c) multi-user mounts - multiplexed sessionsetups over single vc
-(ie tcp session) - prettying up needed, and more testing needed
+(ie tcp session) - more testing needed
 
 d) Kerberos/SPNEGO session setup support - (started)
 
@@ -67,12 +67,26 @@ q) implement support for security and tr
 
 r) Implement O_DIRECT flag on open (already supported on mount)
 
-KNOWN BUGS (updated December 10, 2004)
+s) Allow remapping of last remaining character (\) to +0xF000 which
+(this character is valid for POSIX but not for Windows)
+
+t) Create UID mapping facility so server UIDs can be mapped on a per
+mount or a per server basis to client UIDs or nobody if no mapping
+exists.  This is helpful when Unix extensions are negotiated to
+allow better permission checking when UIDs differ on the server
+and client.  Add new protocol request to the CIFS protocol 
+standard for asking the server for the corresponding name of a
+particular uid.
+
+KNOWN BUGS (updated April 29, 2005)
 ====================================
+See http://bugzilla.samba.org - search on product "CifsVFS" for
+current bug list.
+
 1) existing symbolic links (Windows reparse points) are recognized but
 can not be created remotely. They are implemented for Samba and those that
-support the CIFS Unix extensions but Samba has a bug currently handling
-symlink text beginning with slash
+support the CIFS Unix extensions, although earlier versions of Samba
+overly restrict the pathnames.
 2) follow_link and readdir code does not follow dfs junctions
 but recognizes them
 3) create of new files to FAT partitions on Windows servers can
@@ -98,7 +112,5 @@ there are some easy changes that can be 
 and when signing is disabled to request larger read sizes (larger than 
 negotiated size) and send larger write sizes to modern servers.
 
-4) More exhaustively test the recently added NT4 support against various
-NT4 service pack levels, and fix cifs_setattr for setting file times and 
-size to fall back to level 1 when error invalid level returned.
-
+4) More exhaustively test against less common servers.  More testing
+against Windows 9x, Windows ME servers.
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -26,6 +26,7 @@
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
+#include "cifsproto.h"
 
 /*****************************************************************************
  *
@@ -77,8 +78,8 @@
 
 #define SPNEGO_OID_LEN 7
 #define NTLMSSP_OID_LEN  10
-unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
-unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
+static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
+static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
 
 /* 
  * ASN.1 context.
@@ -210,7 +211,7 @@ asn1_eoc_decode(struct asn1_ctx *ctx, un
 {
 	unsigned char ch;
 
-	if (eoc == 0) {
+	if (eoc == NULL) {
 		if (!asn1_octet_decode(ctx, &ch))
 			return 0;
 
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs_debug.c
  *
- *   Copyright (C) International Business Machines  Corp., 2000,2003
+ *   Copyright (C) International Business Machines  Corp., 2000,2005
  *
  *   Modified by Steve French (sfrench@us.ibm.com)
  *
@@ -29,6 +29,7 @@
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "cifsfs.h"
 
 void
 cifs_dump_mem(char *label, void *data, int length)
@@ -57,7 +58,7 @@ cifs_dump_mem(char *label, void *data, i
 }
 
 #ifdef CONFIG_PROC_FS
-int
+static int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 		     int count, int *eof, void *data)
 {
@@ -78,8 +79,9 @@ cifs_debug_data_read(char *buf, char **b
 		    "Display Internal CIFS Data Structures for Debugging\n"
 		    "---------------------------------------------------\n");
 	buf += length;
-
-	length = sprintf(buf, "Servers:\n");
+	length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
+	buf += length;
+	length = sprintf(buf, "Servers:");
 	buf += length;
 
 	i = 0;
@@ -87,19 +89,29 @@ cifs_debug_data_read(char *buf, char **b
 	list_for_each(tmp, &GlobalSMBSessionList) {
 		i++;
 		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-		length =
-		    sprintf(buf,
-			    "\n%d) Name: %s  Domain: %s Mounts: %d ServerOS: %s  \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d",
-				i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
-				ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus);
-		buf += length;
+		if((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
+		   (ses->serverNOS == NULL)) {
+			buf += sprintf("\nentry for %s not fully displayed\n\t",
+					ses->serverName);
+			
+		} else {
+			length =
+			    sprintf(buf,
+				    "\n%d) Name: %s  Domain: %s Mounts: %d ServerOS: %s  \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
+				i, ses->serverName, ses->serverDomain,
+				atomic_read(&ses->inUse),
+				ses->serverOS, ses->serverNOS,
+				ses->capabilities,ses->status);
+			buf += length;
+		}
 		if(ses->server) {
-			buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
+			buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
+				ses->server->tcpStatus,
 				atomic_read(&ses->server->socketUseCount),
 				ses->server->secMode,
 				atomic_read(&ses->server->inFlight));
 			
-			length = sprintf(buf, "\nMIDs: \n");
+			length = sprintf(buf, "\nMIDs:\n");
 			buf += length;
 
 			spin_lock(&GlobalMid_Lock);
@@ -108,7 +120,12 @@ cifs_debug_data_read(char *buf, char **b
 					mid_q_entry,
 					qhead);
 				if(mid_entry) {
-					length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid);
+					length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",
+						mid_entry->midState,
+						(int)mid_entry->command,
+						mid_entry->pid,
+						mid_entry->tsk,
+						mid_entry->mid);
 					buf += length;
 				}
 			}
@@ -120,7 +137,7 @@ cifs_debug_data_read(char *buf, char **b
 	sprintf(buf, "\n");
 	buf++;
 
-	length = sprintf(buf, "\nShares:\n");
+	length = sprintf(buf, "Shares:");
 	buf += length;
 
 	i = 0;
@@ -178,7 +195,7 @@ cifs_debug_data_read(char *buf, char **b
 }
 
 #ifdef CONFIG_CIFS_STATS
-int
+static int
 cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 		  int count, int *eof, void *data)
 {
@@ -198,13 +215,14 @@ cifs_stats_read(char *buf, char **beginB
 	length += item_length;
 	buf += item_length;      
 	item_length = 
-		sprintf(buf,"SMB Request/Response Buffer: %d\n",
-			bufAllocCount.counter);
+		sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n",
+			bufAllocCount.counter,
+			cifs_min_rcv + tcpSesAllocCount.counter);
 	length += item_length;
 	buf += item_length;
 	item_length = 
-		sprintf(buf,"SMB Small Req/Resp Buffer: %d\n",
-			smBufAllocCount.counter);
+		sprintf(buf,"SMB Small Req/Resp Buffer: %d Pool size: %d\n",
+			smBufAllocCount.counter,cifs_min_small);
 	length += item_length;
 	buf += item_length;
 	item_length = 
@@ -286,7 +304,7 @@ cifs_stats_read(char *buf, char **beginB
 }
 #endif
 
-struct proc_dir_entry *proc_fs_cifs;
+static struct proc_dir_entry *proc_fs_cifs;
 read_proc_t cifs_txanchor_read;
 static read_proc_t cifsFYI_read;
 static write_proc_t cifsFYI_write;
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -21,7 +21,9 @@
 #define CIFS_MOUNT_NO_PERM      1 /* do not do client vfs_perm check */
 #define CIFS_MOUNT_SET_UID      2 /* set current->euid in create etc. */
 #define CIFS_MOUNT_SERVER_INUM  4 /* inode numbers from uniqueid from server */
-#define CIFS_MOUNT_DIRECT_IO          8 /* do not write nor read through page cache */
+#define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
+#define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
+#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -76,8 +76,8 @@ cifs_strtoUCS(wchar_t * to, const char *
 				charlen));
 			to[i] = cpu_to_le16(0x003f);	/* a question mark */
 			charlen = 1;
-		}
-		to[i] = cpu_to_le16(to[i]);
+		} else 
+			to[i] = cpu_to_le16(to[i]);
 
 	}
 
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -25,6 +25,7 @@
 #include "cifs_debug.h"
 #include "md5.h"
 #include "cifs_unicode.h"
+#include "cifsproto.h"
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
 /* the 16 byte signature must be allocated by the caller  */
@@ -49,7 +50,7 @@ static int cifs_calculate_signature(cons
 	return 0;
 }
 
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
 	__u32 * pexpected_response_sequence_number)
 {
 	int rc = 0;
@@ -58,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_
 	/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
 	/* BB remember to add code to save expected sequence number in midQ entry BB */
 
-	if((cifs_pdu == NULL) || (ses == NULL))
+	if((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
 	if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) 
 		return rc;
 
 	spin_lock(&GlobalMid_Lock);
-	cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+	cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
 	cifs_pdu->Signature.Sequence.Reserved = 0;
 	
-	*pexpected_response_sequence_number = ses->sequence_number++;
-	ses->sequence_number++;
+	*pexpected_response_sequence_number = server->sequence_number++;
+	server->sequence_number++;
 	spin_unlock(&GlobalMid_Lock);
 
-	rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+	rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
 	if(rc)
 		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
 	else
@@ -189,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct ci
 	hmac_md5_update((const unsigned char *) unicode_buf,
 		(user_name_len+dom_name_len)*2,&ctx);
 
-	hmac_md5_final(ses->mac_signing_key,&ctx);
+	hmac_md5_final(ses->server->mac_signing_key,&ctx);
 	kfree(ucase_buf);
 	kfree(unicode_buf);
 	return 0;
@@ -199,7 +200,7 @@ void CalcNTLMv2_response(const struct ci
 	struct HMACMD5Context context;
 	memcpy(v2_session_response + 8, ses->server->cryptKey,8);
 	/* gen_blob(v2_session_response + 16); */
-	hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
+	hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
 	hmac_md5_update(ses->server->cryptKey,8,&context);
 /*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
new file mode 100644
--- /dev/null
+++ b/fs/cifs/cifsencrypt.h
@@ -0,0 +1,34 @@
+/*
+ *   fs/cifs/cifsencrypt.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2005
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   Externs for misc. small encryption routines
+ *   so we do not have to put them in cifsproto.h
+ *
+ *   This 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.
+ *
+ *   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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* md4.c */
+extern void mdfour(unsigned char *out, unsigned char *in, int n);
+/* smbdes.c */
+extern void E_P16(unsigned char *p14, unsigned char *p16);
+extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
+extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
+
+
+
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -57,29 +57,28 @@ unsigned int multiuser_mount = 0;
 unsigned int extended_security = 0;
 unsigned int ntlmv2_support = 0;
 unsigned int sign_CIFS_PDUs = 1;
+extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
-module_param(CIFSMaxBufSize, int, CIFS_MAX_MSGSIZE);
+module_param(CIFSMaxBufSize, int, 0);
 MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
 unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
-module_param(cifs_min_rcv, int, CIFS_MIN_RCV_POOL);
+module_param(cifs_min_rcv, int, 0);
 MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
 unsigned int cifs_min_small = 30;
-module_param(cifs_min_small, int, 30);
-MODULE_PARM_DESC(cifs_small_rcv,"Small network buffers in pool. Default: 30 Range: 2 to 256");
+module_param(cifs_min_small, int, 0);
+MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256");
 unsigned int cifs_max_pending = CIFS_MAX_REQ;
-module_param(cifs_max_pending, int, CIFS_MAX_REQ);
+module_param(cifs_max_pending, int, 0);
 MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
 
-
-extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
-			const char *);
-extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
-void cifs_proc_init(void);
-void cifs_proc_clean(void);
-
 static DECLARE_COMPLETION(cifs_oplock_exited);
 
+extern mempool_t *cifs_sm_req_poolp;
+extern mempool_t *cifs_req_poolp;
+extern mempool_t *cifs_mid_poolp;
+
+extern kmem_cache_t *cifs_oplock_cachep;
 
 static int
 cifs_read_super(struct super_block *sb, void *data,
@@ -170,7 +169,8 @@ cifs_put_super(struct super_block *sb)
 static int
 cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
-	int xid, rc;
+	int xid; 
+	int rc = -EOPNOTSUPP;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 
@@ -182,22 +182,34 @@ cifs_statfs(struct super_block *sb, stru
 	buf->f_type = CIFS_MAGIC_NUMBER;
 
 	/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
-	buf->f_namelen = PATH_MAX;	/* PATH_MAX may be too long - it would presumably
-					   be length of total path, note that some servers may be 
-					   able to support more than this, but best to be safe
-					   since Win2k and others can not handle very long filenames */
+	buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would 
+				      presumably be total path, but note
+				      that some servers (includinng Samba 3)
+				      have a shorter maximum path */
 	buf->f_files = 0;	/* undefined */
 	buf->f_ffree = 0;	/* unlimited */
 
-	rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+/* BB we could add a second check for a QFS Unix capability bit */
+/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
+    if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
+			le64_to_cpu(pTcon->fsUnixInfo.Capability)))
+	    rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
+
+    /* Only need to call the old QFSInfo if failed
+    on newer one */
+    if(rc)
+#endif /* CIFS_EXPERIMENTAL */
+	rc = CIFSSMBQFSInfo(xid, pTcon, buf);
 
 	/*     
 	   int f_type;
 	   __fsid_t f_fsid;
 	   int f_namelen;  */
-	/* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+	/* BB get from info in tcon struct at mount time call to QFSAttrInfo */
 	FreeXid(xid);
-	return 0;		/* always return success? what if volume is no longer available? */
+	return 0;		/* always return success? what if volume is no
+				   longer available? */
 }
 
 static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
@@ -228,9 +240,7 @@ static struct inode *
 cifs_alloc_inode(struct super_block *sb)
 {
 	struct cifsInodeInfo *cifs_inode;
-	cifs_inode =
-	    (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep,
-						      SLAB_KERNEL);
+	cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL);
 	if (!cifs_inode)
 		return NULL;
 	cifs_inode->cifsAttrs = 0x20;	/* default */
@@ -437,28 +447,13 @@ static ssize_t
 cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
           loff_t * poffset)
 {
-	if(file == NULL)
-		return -EIO;
-	else if(file->f_dentry == NULL)
+	if(file->f_dentry == NULL)
 		return -EIO;
 	else if(file->f_dentry->d_inode == NULL)
 		return -EIO;
 
 	cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset));
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-	/* check whether we can cache writes locally */
-	if(file->f_dentry->d_sb) {
-		struct cifs_sb_info *cifs_sb;
-		cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-		if(cifs_sb != NULL) {
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-				return cifs_user_read(file,read_data,
-							read_size,poffset);
-		}
-	}
-#endif /* CIFS_EXPERIMENTAL */
-
 	if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
 		return generic_file_read(file,read_data,read_size,poffset);
 	} else {
@@ -482,28 +477,13 @@ cifs_write_wrapper(struct file * file, c
 {
 	ssize_t written;
 
-	if(file == NULL)
-		return -EIO;
-	else if(file->f_dentry == NULL)
+	if(file->f_dentry == NULL)
 		return -EIO;
 	else if(file->f_dentry->d_inode == NULL)
 		return -EIO;
 
 	cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset));
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL    /* BB fixme - fix user char * to kernel char * mapping here BB */
-	/* check whether we can cache writes locally */
-	if(file->f_dentry->d_sb) {
-		struct cifs_sb_info *cifs_sb;
-		cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-		if(cifs_sb != NULL) {
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-				return cifs_user_write(file,write_data,
-							write_size,poffset);
-			}
-		}
-	}
-#endif /* CIFS_EXPERIMENTAL */
 	written = generic_file_write(file,write_data,write_size,poffset);
 	if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll)  {
 		if(file->f_dentry->d_inode->i_mapping) {
@@ -583,6 +563,34 @@ struct file_operations cifs_file_ops = {
 	.flush = cifs_flush,
 	.mmap  = cifs_file_mmap,
 	.sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl	= cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	.readv = generic_file_readv,
+	.writev = generic_file_writev,
+	.aio_read = generic_file_aio_read,
+	.aio_write = generic_file_aio_write,
+	.dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+};
+
+struct file_operations cifs_file_direct_ops = {
+	/* no mmap, no aio, no readv - 
+	   BB reevaluate whether they can be done with directio, no cache */
+	.read = cifs_user_read,
+	.write = cifs_user_write,
+	.open = cifs_open,
+	.release = cifs_close,
+	.lock = cifs_lock,
+	.fsync = cifs_fsync,
+	.flush = cifs_flush,
+	.sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl  = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
@@ -595,12 +603,13 @@ struct file_operations cifs_dir_ops = {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
+        .ioctl  = cifs_ioctl,
 };
 
 static void
 cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags)
 {
-	struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode;
+	struct cifsInodeInfo *cifsi = inode;
 
 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
@@ -653,7 +662,7 @@ cifs_init_request_bufs(void)
 		cifs_min_rcv = 1;
 	else if (cifs_min_rcv > 64) {
 		cifs_min_rcv = 64;
-		cFYI(1,("cifs_min_rcv set to maximum (64)"));
+		cERROR(1,("cifs_min_rcv set to maximum (64)"));
 	}
 
 	cifs_req_poolp = mempool_create(cifs_min_rcv,
@@ -826,6 +835,7 @@ static int cifs_oplock_thread(void * dum
 		}
 	} while(!signal_pending(current));
 	complete_and_exit (&cifs_oplock_exited, 0);
+	oplockThread = NULL;
 }
 
 static int __init
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsfs.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   Copyright (c) International Business Machines  Corp., 2002, 2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -42,8 +42,10 @@ extern void cifs_delete_inode(struct ino
 
 /* Functions related to inodes */
 extern struct inode_operations cifs_dir_inode_ops;
-extern int cifs_create(struct inode *, struct dentry *, int, struct nameidata *);
-extern struct dentry *cifs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern int cifs_create(struct inode *, struct dentry *, int, 
+		       struct nameidata *);
+extern struct dentry * cifs_lookup(struct inode *, struct dentry *,
+				  struct nameidata *);
 extern int cifs_unlink(struct inode *, struct dentry *);
 extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
 extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t);
@@ -60,6 +62,7 @@ extern struct inode_operations cifs_syml
 
 /* Functions related to files and directories */
 extern struct file_operations cifs_file_ops;
+extern struct file_operations cifs_file_direct_ops; /* if directio mount */
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
@@ -82,13 +85,16 @@ extern struct dentry_operations cifs_den
 /* Functions related to symlinks */
 extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
 extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd);
-extern int cifs_readlink(struct dentry *direntry, char __user *buffer, int buflen);
+extern int cifs_readlink(struct dentry *direntry, char __user *buffer, 
+			 int buflen);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
 			const char *symname);
 extern int	cifs_removexattr(struct dentry *, const char *);
 extern int 	cifs_setxattr(struct dentry *, const char *, const void *,
-			 size_t, int);
+			size_t, int);
 extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION   "1.28"
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
+		       unsigned int command, unsigned long arg);
+#define CIFS_VERSION   "1.35"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -149,6 +149,8 @@ struct TCP_Server_Info {
 	__u16 timeZone;
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
 	char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+	__u32 sequence_number; /* needed for CIFS PDU signature */
+	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
 };
 
 /*
@@ -174,20 +176,22 @@ struct cifsSesInfo {
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	atomic_t inUse; /* # of mounts (tree connections) on this ses */
 	enum statusEnum status;
-	__u32 sequence_number;  /* needed for CIFS PDU signature */
 	__u16 ipc_tid;		/* special tid for connection to IPC share */
-	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];	
-	char *serverOS;		/* name of operating system underlying the server */
-	char *serverNOS;	/* name of network operating system that the server is running */
+	__u16 flags;
+	char *serverOS;		/* name of operating system underlying server */
+	char *serverNOS;	/* name of network operating system of server */
 	char *serverDomain;	/* security realm of server */
 	int Suid;		/* remote smb uid  */
 	uid_t linux_uid;        /* local Linux uid */
 	int capabilities;
-	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for 
+				TCP names - will ipv6 and sctp addresses fit? */
 	char userName[MAX_USERNAME_SIZE + 1];
 	char domainName[MAX_USERNAME_SIZE + 1];
 	char * password;
 };
+/* session flags */
+#define CIFS_SES_NT4 1
 
 /*
  * there is one of these for each connection to a resource on a particular
@@ -309,12 +313,15 @@ struct mid_q_entry {
 	__u16 mid;		/* multiplex id */
 	__u16 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
-	__u16 command;		/* smb command code */
 	struct timeval when_sent;	/* time when smb sent */
 	struct cifsSesInfo *ses;	/* smb was sent to this server */
 	struct task_struct *tsk;	/* task waiting for response */
 	struct smb_hdr *resp_buf;	/* response buffer */
 	int midState;	/* wish this were enum but can not pass to wait_event */
+	__u8 command;	/* smb command code */
+	unsigned multiPart:1;	/* multiple responses to one SMB request */
+	unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
+	unsigned multiResp:1;   /* multiple trans2 responses for one request  */
 };
 
 struct oplock_q_entry {
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -36,6 +36,7 @@
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
+#define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
 #define SMB_COM_READ_ANDX             0x2E
@@ -329,7 +330,7 @@ struct smb_hdr {
 };
 /* given a pointer to an smb_hdr retrieve the value of byte count */
 #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
-
+#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
 /* given a pointer to an smb_hdr retrieve the pointer to the byte area */
 #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
 
@@ -568,7 +569,6 @@ typedef struct smb_com_tconx_rsp {
 #define SMB_SHARE_IS_IN_DFS     0x0002
 
 typedef struct smb_com_logoff_andx_req {
-
 	struct smb_hdr hdr;	/* wct = 2 */
 	__u8 AndXCommand;
 	__u8 AndXReserved;
@@ -695,7 +695,8 @@ typedef struct smb_com_write_rsp {
 	__le16 AndXOffset;
 	__le16 Count;
 	__le16 Remaining;
-	__le32 Reserved;
+	__le16 CountHigh;
+	__u16  Reserved;
 	__u16 ByteCount;
 } WRITE_RSP;
 
@@ -761,6 +762,16 @@ typedef struct smb_com_lock_req {
 	LOCKING_ANDX_RANGE Locks[1];
 } LOCK_REQ;
 
+
+typedef struct cifs_posix_lock {
+	__le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
+	__le16  lock_flags; /* 1 = Wait (only valid for setlock) */
+	__le32  pid;
+	__le64	start;
+	__le64	length;
+	/* BB what about additional owner info to identify network client */
+} CIFS_POSIX_LOCK;
+
 typedef struct smb_com_lock_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
 	__u8 AndXCommand;
@@ -865,6 +876,24 @@ typedef struct smb_com_create_directory_
 	__u16 ByteCount;	/* bct = 0 */
 } CREATE_DIRECTORY_RSP;
 
+typedef struct smb_com_setattr_req {
+	struct smb_hdr hdr; /* wct = 8 */
+	__le16 attr;
+	__le16 time_low;
+	__le16 time_high;
+	__le16 reserved[5]; /* must be zero */
+	__u16  ByteCount;
+	__u8   BufferFormat; /* 4 = ASCII */
+	unsigned char fileName[1];
+} SETATTR_REQ;
+
+typedef struct smb_com_setattr_rsp {
+	struct smb_hdr hdr;     /* wct = 0 */
+	__u16 ByteCount;        /* bct = 0 */
+} SETATTR_RSP;
+
+/* empty wct response to setattr */
+
 /***************************************************/
 /* NT Transact structure defintions follow         */
 /* Currently only ioctl and notify are implemented */
@@ -1078,6 +1107,9 @@ struct smb_t2_rsp {
 #define SMB_QUERY_FILE_UNIX_LINK        0x201
 #define SMB_QUERY_POSIX_ACL             0x204
 #define SMB_QUERY_XATTR                 0x205
+#define SMB_QUERY_ATTR_FLAGS            0x206  /* append,immutable etc. */
+#define SMB_QUERY_POSIX_PERMISSION      0x207
+#define SMB_QUERY_POSIX_LOCK            0x208
 #define SMB_QUERY_FILE_INTERNAL_INFO    0x3ee
 #define SMB_QUERY_FILE_ACCESS_INFO      0x3f0
 #define SMB_QUERY_FILE_NAME_INFO2       0x3f1 /* 0x30 bytes */
@@ -1095,6 +1127,8 @@ struct smb_t2_rsp {
 #define SMB_SET_FILE_UNIX_HLINK         0x203
 #define SMB_SET_POSIX_ACL               0x204
 #define SMB_SET_XATTR                   0x205
+#define SMB_SET_ATTR_FLAGS              0x206  /* append, immutable etc. */
+#define SMB_SET_POSIX_LOCK              0x208
 #define SMB_SET_FILE_BASIC_INFO2        0x3ec
 #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
 #define SMB_FILE_ALL_INFO2              0x3fa
@@ -1216,9 +1250,25 @@ struct smb_com_transaction2_sfi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+	__u16 Reserved2;	/* parameter word reserved - 
+					present for infolevels > 100 */
 };
 
+struct smb_t2_qfi_req {
+        struct	smb_hdr hdr;
+        struct	trans2_req t2;
+	__u8	Pad;
+	__u16	Fid;
+	__le16	InformationLevel;
+};
+
+struct smb_t2_qfi_rsp {
+        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
+        struct trans2_resp t2;
+        __u16 ByteCount;
+        __u16 Reserved2;        /* parameter word reserved - 
+					present for infolevels > 100 */
+};
 
 /*
  * Flags on T2 FINDFIRST and FINDNEXT 
@@ -1325,6 +1375,7 @@ typedef struct smb_com_transaction2_fnex
 #define SMB_QUERY_FS_DEVICE_INFO    0x104
 #define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
 #define SMB_QUERY_CIFS_UNIX_INFO    0x200
+#define SMB_QUERY_POSIX_FS_INFO     0x201
 #define SMB_QUERY_LABEL_INFO        0x3ea
 #define SMB_QUERY_FS_QUOTA_INFO     0x3ee
 #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef
@@ -1502,8 +1553,31 @@ typedef struct {
 } FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
-#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002
-#define CIFS_UNIX_XATTR_CAP             0x00000004 /*support for new namespace*/
+#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
+#define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
+#define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
+#define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
+typedef struct {
+	/* For undefined recommended transfer size return -1 in that field */
+	__le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
+	__le32 BlockSize; 
+    /* The next three fields are in terms of the block size.
+	(above). If block size is unknown, 4096 would be a
+	reasonable block size for a server to report. 
+	Note that returning the blocks/blocksavail removes need
+	to make a second call (to QFSInfo level 0x103 to get this info.
+	UserBlockAvail is typically less than or equal to BlocksAvail,
+	if no distinction is made return the same value in each */
+	__le64 TotalBlocks;
+	__le64 BlocksAvail;       /* bfree */
+	__le64 UserBlocksAvail;   /* bavail */
+    /* For undefined Node fields or FSID return -1 */
+	__le64 TotalFileNodes;
+	__le64 FreeFileNodes;
+	__le64 FileSysIdentifier;   /* fsid */
+	/* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */
+	/* NB flags can come from FILE_SYSTEM_DEVICE_INFO call   */
+} FILE_SYSTEM_POSIX_INFO;
 
 /* DeviceType Flags */
 #define FILE_DEVICE_CD_ROM              0x00000002
@@ -1592,17 +1666,32 @@ typedef struct {
 	char LinkDest[1];
 } FILE_UNIX_LINK_INFO;		/* level 0x201 QPathInfo */
 
+/* The following three structures are needed only for
+	setting time to NT4 and some older servers via
+	the primitive DOS time format */
+typedef struct {
+	__u16 Day:5;
+	__u16 Month:4;
+	__u16 Year:7;
+} SMB_DATE;
+
 typedef struct {
-	__u16 CreationDate;
-	__u16 CreationTime;
-	__u16 LastAccessDate;
-	__u16 LastAccessTime;
-	__u16 LastWriteDate;
-	__u16 LastWriteTime;
-	__u32 DataSize; /* File Size (EOF) */
-	__u32 AllocationSize;
-	__u16 Attributes; /* verify not u32 */
-	__u32 EASize;
+	__u16 TwoSeconds:5;
+	__u16 Minutes:6;
+	__u16 Hours:5;
+} SMB_TIME;
+
+typedef struct {
+	__le16 CreationDate; /* SMB Date see above */
+	__le16 CreationTime; /* SMB Time */
+	__le16 LastAccessDate;
+	__le16 LastAccessTime;
+	__le16 LastWriteDate;
+	__le16 LastWriteTime;
+	__le32 DataSize; /* File Size (EOF) */
+	__le32 AllocationSize;
+	__le16 Attributes; /* verify not u32 */
+	__le32 EASize;
 } FILE_INFO_STANDARD;  /* level 1 SetPath/FileInfo */
 
 typedef struct {
@@ -1912,14 +2001,39 @@ struct xsymlink {
 	char path[1024];  
 };
 
-typedef struct {
+typedef struct file_xattr_info {
 	/* BB do we need another field for flags? BB */
 	__u32 xattr_name_len;
 	__u32 xattr_value_len;
 	char  xattr_name[0];
 	/* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO;	/* extended attribute, info level 205 */
+} FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
+
 
+/* flags for chattr command */
+#define EXT_SECURE_DELETE		0x00000001 /* EXT3_SECRM_FL */
+#define EXT_ENABLE_UNDELETE		0x00000002 /* EXT3_UNRM_FL */
+/* Reserved for compress file 0x4 */
+#define EXT_SYNCHRONOUS			0x00000008 /* EXT3_SYNC_FL */
+#define EXT_IMMUTABLE_FL		0x00000010 /* EXT3_IMMUTABLE_FL */
+#define EXT_OPEN_APPEND_ONLY		0x00000020 /* EXT3_APPEND_FL */
+#define EXT_DO_NOT_BACKUP		0x00000040 /* EXT3_NODUMP_FL */
+#define EXT_NO_UPDATE_ATIME		0x00000080 /* EXT3_NOATIME_FL */
+/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
+#define EXT_HASH_TREE_INDEXED_DIR	0x00001000 /* GET-ONLY EXT3_INDEX_FL */
+/* 0x2000 reserved for IMAGIC_FL */
+#define EXT_JOURNAL_THIS_FILE	0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
+/* 0x8000 reserved for EXT3_NOTAIL_FL */
+#define EXT_SYNCHRONOUS_DIR		0x00010000 /* EXT3_DIRSYNC_FL */
+#define EXT_TOPDIR			0x00020000 /* EXT3_TOPDIR_FL */
+
+#define EXT_SET_MASK			0x000300FF
+#define EXT_GET_MASK			0x0003DFFF
+
+typedef struct file_chattr_info {
+	__le64	mask; /* list of all possible attribute bits */
+	__le64	mode; /* list of actual attribute bits on this inode */
+} FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
 
 #endif 
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2004
+ *   Copyright (c) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -50,16 +50,19 @@ extern int SendReceive(const unsigned in
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
+extern int is_size_safe_to_change(struct cifsInodeInfo *);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			enum securityEnum *secType);
+extern int cifs_inet_pton(int, char * source, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
-			const struct cifsTconInfo *, int
-			/* length of fixed section (word count) in two byte units  */
+			const struct cifsTconInfo *, int /* specifies length
+			    of fixed section (word count) in two byte units */
 			);
-struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *);
-void DeleteOplockQEntry(struct oplock_q_entry *);
+extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
+						 struct cifsTconInfo *);
+extern void DeleteOplockQEntry(struct oplock_q_entry *);
 extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern int cifs_get_inode_info(struct inode **pinode,
@@ -70,6 +73,12 @@ extern int cifs_get_inode_info_unix(stru
 			const unsigned char *search_path,
 			struct super_block *sb,int xid);
 
+extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
+			const char *);
+extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+void cifs_proc_init(void);
+void cifs_proc_clean(void);
+
 extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, 
 			struct nls_table * nls_info);
 extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
@@ -79,18 +88,11 @@ extern int CIFSTCon(unsigned int xid, st
 			const struct nls_table *);
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
-			const char *searchName,
-			FILE_DIRECTORY_INFO * findData,
-			T2_FFIRST_RSP_PARMS * findParms,
-			const struct nls_table *nls_codepage,
-			int *pUnicodeFlag,
-			int *pUnixFlag /* if Unix extensions used */ );
+            const char *searchName, const struct nls_table *nls_codepage,
+            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
+
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-			FILE_DIRECTORY_INFO * findData,
-			T2_FNEXT_RSP_PARMS * findParms,
-			const __u16 searchHandle, char * resume_name,
-			int name_length, __u32 resume_key,
-			int *UnicodeFlag, int *pUnixFlag);
+            __u16 searchHandle, struct cifs_search_info * psrch_inf);
 
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
 			const __u16 search_handle);
@@ -98,71 +100,93 @@ extern int CIFSFindClose(const int, stru
 extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName,
 			FILE_ALL_INFO * findData,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSSMBUnixQPathInfo(const int xid,
 			struct cifsTconInfo *tcon,
 			const unsigned char *searchName,
 			FILE_UNIX_BASIC_INFO * pFindData,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 			const unsigned char *searchName,
 			unsigned char **targetUNCs,
 			unsigned int *number_of_UNC_in_array,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, int remap);
 
 extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			const char *old_path,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, int remap);
 extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-			const char *old_path, const struct nls_table *nls_codepage, 
-			unsigned int *pnum_referrals, unsigned char ** preferrals);
+			const char *old_path, 
+			const struct nls_table *nls_codepage,
+			unsigned int *pnum_referrals, 
+			unsigned char ** preferrals,
+			int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
-			struct kstatfs *FSData,
-			const struct nls_table *nls_codepage);
+			struct kstatfs *FSData);
 extern int CIFSSMBQFSAttributeInfo(const int xid,
-			struct cifsTconInfo *tcon,
-			const struct nls_table *nls_codepage);
-extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
-			const struct nls_table *nls_codepage);
-extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
-			const struct nls_table *nls_codepage);
+			struct cifsTconInfo *tcon);
+extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+			struct kstatfs *FSData);
 
 extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
 			const char *fileName, const FILE_BASIC_INFO * data,
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
+extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
+			const FILE_BASIC_INFO * data, __u16 fid);
+#if 0
+extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
+			char *fileName, __u16 dos_attributes,
 			const struct nls_table *nls_codepage);
+#endif /* possibly unneeded function */
 extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
-			const char *fileName, __u64 size,int setAllocationSizeFlag,
-			const struct nls_table *nls_codepage);
+			const char *fileName, __u64 size,
+			int setAllocationSizeFlag,
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
-			 __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
+			 __u64 size, __u16 fileHandle,__u32 opener_pid, 
+			int AllocSizeFlag);
 extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
 			char *full_path, __u64 mode, __u64 uid,
-			__u64 gid, dev_t dev, const struct nls_table *nls_codepage);
+			__u64 gid, dev_t dev, 
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 
 extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
 			const char *newName,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
-			const char *name, const struct nls_table *nls_codepage);
+			const char *name, const struct nls_table *nls_codepage,
+			int remap_special_chars);
 
 extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
 			const char *name,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
 			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
-			int netfid, char * target_name, const struct nls_table *nls_codepage);
+			int netfid, char * target_name, 
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSCreateHardLink(const int xid,
 			struct cifsTconInfo *tcon,
 			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern int CIFSUnixCreateHardLink(const int xid,
 			struct cifsTconInfo *tcon,
 			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, 
+			int remap_special_chars);
 extern int CIFSUnixCreateSymLink(const int xid,
 			struct cifsTconInfo *tcon,
 			const char *fromName, const char *toName,
@@ -182,7 +206,7 @@ extern int CIFSSMBOpen(const int xid, st
 			const char *fileName, const int disposition,
 			const int access_flags, const int omode,
 			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 
@@ -194,6 +218,21 @@ extern int CIFSSMBWrite(const int xid, s
 			const __u64 lseek, unsigned int *nbytes,
 			const char *buf, const char __user *ubuf, 
 			const int long_op);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+			const int netfid, const unsigned int count,
+			const __u64 offset, unsigned int *nbytes, 
+			const char __user *buf,const int long_op);
+extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
+			const unsigned char *searchName, __u64 * inode_number,
+			const struct nls_table *nls_codepage, 
+			int remap_special_chars);
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
+			const struct nls_table * codepage);
+extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
+			const struct nls_table * cp, int mapChars);
+
 extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 			const __u16 netfid, const __u64 len,
 			const __u64 offset, const __u32 numUnlock,
@@ -210,38 +249,42 @@ extern void tconInfoFree(struct cifsTcon
 
 extern int cifs_reconnect(struct TCP_Server_Info *server);
 
-extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
-extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key,
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
+extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
 	__u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
 extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
 extern int CIFSSMBCopy(int xid,
 			struct cifsTconInfo *source_tcon,
 			const char *fromName,
 			const __u16 target_tid,
 			const char *toName, const int flags,
-			const struct nls_table *nls_codepage);
+			const struct nls_table *nls_codepage, 
+			int remap_special_chars);
 extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
-			const int notify_subdirs,const __u16 netfid,__u32 filter,
-			const struct nls_table *nls_codepage);
+			const int notify_subdirs,const __u16 netfid,
+			__u32 filter, const struct nls_table *nls_codepage);
 extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, char * EAData,
-			size_t bufsize, const struct nls_table *nls_codepage);
+			size_t bufsize, const struct nls_table *nls_codepage,
+			int remap_special_chars);
 extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
 		const unsigned char * searchName,const unsigned char * ea_name,
 		unsigned char * ea_value, size_t buf_size, 
-		const struct nls_table *nls_codepage);
+		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, 
 		const char *fileName, const char * ea_name, 
 		const void * ea_value, const __u16 ea_value_len, 
-		const struct nls_table *nls_codepage);
+		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
 		const unsigned char *searchName,
 		char *acl_inf, const int buflen,const int acl_type,
-		const struct nls_table *nls_codepage);
+		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
 		const unsigned char *fileName,
 		const char *local_acl, const int buflen, const int acl_type,
-		const struct nls_table *nls_codepage);
+		const struct nls_table *nls_codepage, int remap_special_chars);
+extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -75,9 +75,11 @@ static void mark_open_files_invalid(stru
 		}
 	}
 	write_unlock(&GlobalSMBSeslock);
-	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
+	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
+	   to this tcon */
 }
 
+/* If the return code is zero, this function must fill in request_buf pointer */
 static int
 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 	 void **request_buf /* returned */)
@@ -88,11 +90,12 @@ small_smb_init(int smb_command, int wct,
 	   check for tcp and smb session status done differently
 	   for those three - in the calling routine */
 	if(tcon) {
-		if((tcon->ses) && (tcon->ses->server)){
+		if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+				  (tcon->ses->server)){
 			struct nls_table *nls_codepage;
 				/* Give Demultiplex thread up to 10 seconds to 
-					reconnect, should be greater than cifs socket
-					timeout which is 7 seconds */
+				   reconnect, should be greater than cifs socket
+				   timeout which is 7 seconds */
 			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 				wait_event_interruptible_timeout(tcon->ses->server->response_q,
 					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
@@ -102,8 +105,9 @@ small_smb_init(int smb_command, int wct,
 					   (tcon->ses->status == CifsExiting)) {
 						cFYI(1,("gave up waiting on reconnect in smb_init"));
 						return -EHOSTDOWN;
-					} /* else "hard" mount - keep retrying until 
-					process is killed or server comes back up */
+					} /* else "hard" mount - keep retrying
+					     until process is killed or server
+					     comes back on-line */
 				} else /* TCP session is reestablished now */
 					break;
 				 
@@ -114,23 +118,24 @@ small_smb_init(int smb_command, int wct,
 		simultaneously reconnect the same SMB session */
 			down(&tcon->ses->sesSem);
 			if(tcon->ses->status == CifsNeedReconnect)
-				rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+				rc = cifs_setup_session(0, tcon->ses, 
+							nls_codepage);
 			if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 				mark_open_files_invalid(tcon);
-				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
-					nls_codepage);
+				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
+					, nls_codepage);
 				up(&tcon->ses->sesSem);
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
 				cFYI(1, ("reconnect tcon rc = %d", rc));
 				/* Removed call to reopen open files here - 
-					it is safer (and faster) to reopen files
-					one at a time as needed in read and write */
+				   it is safer (and faster) to reopen files
+				   one at a time as needed in read and write */
 
 				/* Check if handle based operation so we 
-					know whether we can continue or not without
-					returning to caller to reset file handle */
+				   know whether we can continue or not without
+				   returning to caller to reset file handle */
 				switch(smb_command) {
 					case SMB_COM_READ_ANDX:
 					case SMB_COM_WRITE_ANDX:
@@ -154,7 +159,7 @@ small_smb_init(int smb_command, int wct,
 		return rc;
 
 	*request_buf = cifs_small_buf_get();
-	if (*request_buf == 0) {
+	if (*request_buf == NULL) {
 		/* BB should we add a retry in here if not a writepage? */
 		return -ENOMEM;
 	}
@@ -169,6 +174,7 @@ small_smb_init(int smb_command, int wct,
 	return rc;
 }  
 
+/* If the return code is zero, this function must fill in request_buf pointer */
 static int
 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 	 void **request_buf /* returned */ ,
@@ -180,22 +186,25 @@ smb_init(int smb_command, int wct, struc
 	   check for tcp and smb session status done differently
 	   for those three - in the calling routine */
 	if(tcon) {
-		if((tcon->ses) && (tcon->ses->server)){
+		if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
+				  (tcon->ses->server)){
 			struct nls_table *nls_codepage;
-				/* Give Demultiplex thread up to 10 seconds to 
-					reconnect, should be greater than cifs socket
-					timeout which is 7 seconds */
+				/* Give Demultiplex thread up to 10 seconds to
+				   reconnect, should be greater than cifs socket
+				   timeout which is 7 seconds */
 			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 				wait_event_interruptible_timeout(tcon->ses->server->response_q,
 					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
-				if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+				if(tcon->ses->server->tcpStatus == 
+						CifsNeedReconnect) {
 					/* on "soft" mounts we wait once */
 					if((tcon->retry == FALSE) || 
 					   (tcon->ses->status == CifsExiting)) {
 						cFYI(1,("gave up waiting on reconnect in smb_init"));
 						return -EHOSTDOWN;
-					} /* else "hard" mount - keep retrying until 
-					process is killed or server comes back up */
+					} /* else "hard" mount - keep retrying
+					     until process is killed or server
+					     comes on-line */
 				} else /* TCP session is reestablished now */
 					break;
 				 
@@ -206,23 +215,24 @@ smb_init(int smb_command, int wct, struc
 		simultaneously reconnect the same SMB session */
 			down(&tcon->ses->sesSem);
 			if(tcon->ses->status == CifsNeedReconnect)
-				rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+				rc = cifs_setup_session(0, tcon->ses, 
+							nls_codepage);
 			if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 				mark_open_files_invalid(tcon);
-				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
-					nls_codepage);
+				rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+					      tcon, nls_codepage);
 				up(&tcon->ses->sesSem);
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
 				cFYI(1, ("reconnect tcon rc = %d", rc));
 				/* Removed call to reopen open files here - 
-					it is safer (and faster) to reopen files
-					one at a time as needed in read and write */
+				   it is safer (and faster) to reopen files
+				   one at a time as needed in read and write */
 
 				/* Check if handle based operation so we 
-					know whether we can continue or not without
-					returning to caller to reset file handle */
+				   know whether we can continue or not without
+				   returning to caller to reset file handle */
 				switch(smb_command) {
 					case SMB_COM_READ_ANDX:
 					case SMB_COM_WRITE_ANDX:
@@ -246,7 +256,7 @@ smb_init(int smb_command, int wct, struc
 		return rc;
 
 	*request_buf = cifs_buf_get();
-	if (*request_buf == 0) {
+	if (*request_buf == NULL) {
 		/* BB should we add a retry in here if not a writepage? */
 		return -ENOMEM;
 	}
@@ -284,7 +294,8 @@ static int validate_t2(struct smb_t2_rsp
 			if(total_size < 512) {
 				total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
 				/* BCC le converted in SendReceive */
-				pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + 
+				pBCC = (pSMB->hdr.WordCount * 2) + 
+					sizeof(struct smb_hdr) +
 					(char *)pSMB;
 				if((total_size <= (*(u16 *)pBCC)) && 
 				   (total_size < 
@@ -335,8 +346,10 @@ CIFSSMBNegotiate(unsigned int xid, struc
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc == 0) {
 		server->secMode = pSMBr->SecurityMode;	
-		server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
-		/* one byte - no need to convert this or EncryptionKeyLen from le,*/
+		server->secType = NTLM; /* BB override default for 
+					   NTLMv2 or kerberos v5 */
+		/* one byte - no need to convert this or EncryptionKeyLen
+		   from little endian */
 		server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
 		/* probably no need to store and check maxvcs */
 		server->maxBuf =
@@ -372,7 +385,7 @@ CIFSSMBNegotiate(unsigned int xid, struc
 						pSMBr->u.extended_response.
 						GUID, 16) != 0) {
 						cFYI(1,
-							("UID of server does not match previous connection to same ip address"));
+						     ("UID of server does not match previous connection to same ip address"));
 						memcpy(server->
 							server_GUID,
 							pSMBr->u.
@@ -448,21 +461,22 @@ CIFSSMBTDis(const int xid, struct cifsTc
 		return 0;  
 	}
 
-	if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
+	if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
 		up(&tcon->tconSem);
 		return -EIO;
 	}
-	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer);
+	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
+			    (void **)&smb_buffer);
 	if (rc) {
 		up(&tcon->tconSem);
 		return rc;
 	} else {
 		smb_buffer_response = smb_buffer; /* BB removeme BB */
-    }
+	}
 	rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
 			 &length, 0);
 	if (rc)
-		cFYI(1, (" Tree disconnect failed %d", rc));
+		cFYI(1, ("Tree disconnect failed %d", rc));
 
 	if (smb_buffer)
 		cifs_small_buf_release(smb_buffer);
@@ -496,6 +510,11 @@ CIFSSMBLogoff(const int xid, struct cifs
 		return -EBUSY;
 	}
 	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
+	if (rc) {
+		up(&ses->sesSem);
+		return rc;
+	}
+
 	smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
 	
 	if(ses->server) {
@@ -504,11 +523,6 @@ CIFSSMBLogoff(const int xid, struct cifs
 			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 	}
 
-	if (rc) {
-		up(&ses->sesSem);
-		return rc;
-	}
-
 	pSMB->hdr.Uid = ses->Suid;
 
 	pSMB->AndXCommand = 0xFF;
@@ -536,8 +550,8 @@ CIFSSMBLogoff(const int xid, struct cifs
 }
 
 int
-CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
-	       const char *fileName, const struct nls_table *nls_codepage)
+CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+	       const struct nls_table *nls_codepage, int remap)
 {
 	DELETE_FILE_REQ *pSMB = NULL;
 	DELETE_FILE_RSP *pSMBr = NULL;
@@ -553,12 +567,11 @@ DelFileRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {		/* BB improve check for buffer overruns BB */
 		name_len = strnlen(fileName, PATH_MAX);
 		name_len++;	/* trailing null */
 		strncpy(pSMB->fileName, fileName, name_len);
@@ -579,8 +592,7 @@ DelFileRetry:
         }
 #endif
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto DelFileRetry;
 
@@ -588,8 +600,8 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
-	     const char *dirName, const struct nls_table *nls_codepage)
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
+	     const struct nls_table *nls_codepage, int remap)
 {
 	DELETE_DIRECTORY_REQ *pSMB = NULL;
 	DELETE_DIRECTORY_RSP *pSMBr = NULL;
@@ -605,12 +617,11 @@ RmDirRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX
-				/* find define for this maxpathcomponent */
-				, nls_codepage);
+		name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
+					 PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {		/* BB improve check for buffer overruns BB */
 		name_len = strnlen(dirName, PATH_MAX);
 		name_len++;	/* trailing null */
 		strncpy(pSMB->DirName, dirName, name_len);
@@ -630,8 +641,7 @@ RmDirRetry:
         }
 #endif
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto RmDirRetry;
 	return rc;
@@ -639,7 +649,7 @@ RmDirRetry:
 
 int
 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
-	     const char *name, const struct nls_table *nls_codepage)
+	     const char *name, const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	CREATE_DIRECTORY_REQ *pSMB = NULL;
@@ -655,12 +665,11 @@ MkDirRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX
-					 /* find define for this maxpathcomponent */
-					 , nls_codepage);
+		name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
+					    PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {		/* BB improve check for buffer overruns BB */
 		name_len = strnlen(name, PATH_MAX);
 		name_len++;	/* trailing null */
 		strncpy(pSMB->DirName, name, name_len);
@@ -679,8 +688,7 @@ MkDirRetry:
 		atomic_inc(&tcon->num_mkdirs);
         }
 #endif
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto MkDirRetry;
 	return rc;
@@ -691,7 +699,7 @@ CIFSSMBOpen(const int xid, struct cifsTc
 	    const char *fileName, const int openDisposition,
 	    const int access_flags, const int create_options, __u16 * netfid,
 	    int *pOplock, FILE_ALL_INFO * pfile_info, 
-	    const struct nls_table *nls_codepage)
+	    const struct nls_table *nls_codepage, int remap)
 {
 	int rc = -EACCES;
 	OPEN_REQ *pSMB = NULL;
@@ -711,14 +719,12 @@ openRetry:
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		count = 1;	/* account for one byte pad to word boundary */
 		name_len =
-		    cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
-				  fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
+				     fileName, PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 		pSMB->NameLength = cpu_to_le16(name_len);
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {		/* BB improve check for buffer overruns BB */
 		count = 0;	/* no pad */
 		name_len = strnlen(fileName, PATH_MAX);
 		name_len++;	/* trailing null */
@@ -747,7 +753,8 @@ openRetry:
 	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
 	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
 	pSMB->CreateOptions = cpu_to_le32(create_options);
-	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);	/* BB ??*/
+	/* BB Expirement with various impersonation levels and verify */
+	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
 	pSMB->SecurityFlags =
 	    SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
 
@@ -761,7 +768,7 @@ openRetry:
 	if (rc) {
 		cFYI(1, ("Error in Open = %d", rc));
 	} else {
-		*pOplock = pSMBr->OplockLevel;	/* one byte no need to le_to_cpu */
+		*pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
 		*netfid = pSMBr->Fid;	/* cifs fid stays in le */
 		/* Let caller know file was created so we can set the mode. */
 		/* Do we care about the CreateAction in any other cases? */
@@ -780,8 +787,7 @@ openRetry:
 		atomic_inc(&tcon->num_opens);
 #endif
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto openRetry;
 	return rc;
@@ -802,6 +808,8 @@ CIFSSMBRead(const int xid, struct cifsTc
 	char *pReadData = NULL;
 	int bytes_returned;
 
+	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+
 	*nbytes = 0;
 	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
@@ -817,8 +825,8 @@ CIFSSMBRead(const int xid, struct cifsTc
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
 	pSMB->Remaining = 0;
-	pSMB->MaxCount = cpu_to_le16(count);
-	pSMB->MaxCountHigh = 0;
+	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
+	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
 	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -826,8 +834,11 @@ CIFSSMBRead(const int xid, struct cifsTc
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
-		__u16 data_length = le16_to_cpu(pSMBr->DataLength);
+		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
+		data_length = data_length << 16;
+		data_length += le16_to_cpu(pSMBr->DataLength);
 		*nbytes = data_length;
+
 		/*check that DataLength would not go beyond end of SMB */
 		if ((data_length > CIFSMaxBufSize) 
 				|| (data_length > count)) {
@@ -846,12 +857,10 @@ CIFSSMBRead(const int xid, struct cifsTc
 			    memcpy(*buf,pReadData,data_length);
 		}
 	}
-	if (pSMB) {
-		if(*buf)
-			cifs_buf_release(pSMB);
-		else
-			*buf = (char *)pSMB;
-	}
+	if(*buf)
+		cifs_buf_release(pSMB);
+	else
+		*buf = (char *)pSMB;
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
@@ -868,9 +877,10 @@ CIFSSMBWrite(const int xid, struct cifsT
 	WRITE_REQ *pSMB = NULL;
 	WRITE_RSP *pSMBr = NULL;
 	int bytes_returned;
-	unsigned bytes_sent;
+	__u32 bytes_sent;
 	__u16 byte_count;
 
+	/* cFYI(1,("write at %lld %d bytes",offset,count));*/
 	rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
@@ -886,31 +896,39 @@ CIFSSMBWrite(const int xid, struct cifsT
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
-	/* BB can relax this if buffer is big enough in some cases - ie we can 
-	send more  if LARGE_WRITE_X capability returned by the server and if
+
+	/* Can increase buffer size if buffer is big enough in some cases - ie we 
+	can send more if LARGE_WRITE_X capability returned by the server and if
 	our buffer is big enough or if we convert to iovecs on socket writes
 	and eliminate the copy to the CIFS buffer */
-	bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+	if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
+	} else {
+		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
+			 & ~0xFF;
+	}
+
 	if (bytes_sent > count)
 		bytes_sent = count;
-	pSMB->DataLengthHigh = 0;
 	pSMB->DataOffset =
 	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
-    if(buf)
+	if(buf)
 	    memcpy(pSMB->Data,buf,bytes_sent);
-	else if(ubuf)
-		copy_from_user(pSMB->Data,ubuf,bytes_sent);
-    else {
-		/* No buffer */
-		if(pSMB)
+	else if(ubuf) {
+		if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
 			cifs_buf_release(pSMB);
+			return -EFAULT;
+		}
+	} else {
+		/* No buffer */
+		cifs_buf_release(pSMB);
 		return -EINVAL;
 	}
 
-	byte_count = bytes_sent + 1 /* pad */ ;
-	pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
-	pSMB->DataLengthHigh = 0;
-	pSMB->hdr.smb_buf_length += byte_count;
+	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
+	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
+	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+	pSMB->hdr.smb_buf_length += bytes_sent+1;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -918,11 +936,13 @@ CIFSSMBWrite(const int xid, struct cifsT
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
-	} else
-		*nbytes = le16_to_cpu(pSMBr->Count);
+	} else {
+		*nbytes = le16_to_cpu(pSMBr->CountHigh);
+		*nbytes = (*nbytes) << 16;
+		*nbytes += le16_to_cpu(pSMBr->Count);
+	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
@@ -944,10 +964,12 @@ int CIFSSMBWrite2(const int xid, struct 
 	__u16 byte_count;
 
 	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
-	pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
     
-    if (rc)
+	if (rc)
 		return rc;
+	
+	pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
+
 	/* tcon and ses pointer are checked in smb_init */
 	if (tcon->ses->server == NULL)
 		return -ECONNABORTED;
@@ -980,8 +1002,7 @@ int CIFSSMBWrite2(const int xid, struct 
 	} else
 		*nbytes = le16_to_cpu(pSMBr->Count);
 
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
+	cifs_small_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
@@ -1004,11 +1025,13 @@ CIFSSMBLock(const int xid, struct cifsTc
 	__u16 count;
 
 	cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
-	rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
+	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
+
 	if (rc)
 		return rc;
 
+	pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
+
 	if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
 		timeout = -1; /* no response expected */
 		pSMB->Timeout = 0;
@@ -1046,8 +1069,7 @@ CIFSSMBLock(const int xid, struct cifsTc
 	if (rc) {
 		cFYI(1, ("Send error in Lock = %d", rc));
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_small_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 	since file handle passed in no longer valid */
@@ -1065,12 +1087,13 @@ CIFSSMBClose(const int xid, struct cifsT
 
 /* do not retry on dead session on close */
 	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
-	pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
 	if(rc == -EAGAIN)
 		return 0;
 	if (rc)
 		return rc;
 
+	pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
+
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->LastWriteTime = 0;
 	pSMB->ByteCount = 0;
@@ -1083,8 +1106,7 @@ CIFSSMBClose(const int xid, struct cifsT
 		}
 	}
 
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
+	cifs_small_buf_release(pSMB);
 
 	/* Since session is dead, file will be closed on server already */
 	if(rc == -EAGAIN)
@@ -1096,7 +1118,7 @@ CIFSSMBClose(const int xid, struct cifsT
 int
 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
 	      const char *fromName, const char *toName,
-	      const struct nls_table *nls_codepage)
+	      const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	RENAME_REQ *pSMB = NULL;
@@ -1119,18 +1141,16 @@ renameRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 		pSMB->OldFileName[name_len] = 0x04;	/* pad */
 	/* protocol requires ASCII signature byte on Unicode string */
 		pSMB->OldFileName[name_len + 1] = 0x00;
 		name_len2 =
-		    cifs_strtoUCS((wchar_t *) & pSMB->
-				  OldFileName[name_len + 2], toName, PATH_MAX,
-				  nls_codepage);
+		    cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
+				     toName, PATH_MAX, nls_codepage, remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -1161,8 +1181,7 @@ renameRetry:
 	}
 #endif
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto renameRetry;
@@ -1171,7 +1190,8 @@ renameRetry:
 }
 
 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
-		int netfid, char * target_name, const struct nls_table * nls_codepage) 
+		int netfid, char * target_name, 
+		const struct nls_table * nls_codepage, int remap)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
 	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -1216,9 +1236,11 @@ int CIFSSMBRenameOpenFile(const int xid,
 	/* unicode only call */
 	if(target_name == NULL) {
 		sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
-	        len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
+	        len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
+					dummy_string, 24, nls_codepage, remap);
 	} else {
-		len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage);
+		len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
+					target_name, PATH_MAX, nls_codepage, remap);
 	}
 	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
 	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
@@ -1241,8 +1263,7 @@ int CIFSSMBRenameOpenFile(const int xid,
 		atomic_inc(&pTcon->num_t2renames);
 	}
 #endif
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
 		since file handle passed in no longer valid */
@@ -1253,7 +1274,7 @@ int CIFSSMBRenameOpenFile(const int xid,
 int
 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
             const __u16 target_tid, const char *toName, const int flags,
-            const struct nls_table *nls_codepage)
+            const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	COPY_REQ *pSMB = NULL;
@@ -1275,18 +1296,16 @@ copyRetry:
 	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
-				fromName, 
-				PATH_MAX /* find define for this maxpathcomponent */,
-				nls_codepage);
+		name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
+					    fromName, PATH_MAX, nls_codepage,
+					    remap);
 		name_len++;     /* trailing null */
 		name_len *= 2;
 		pSMB->OldFileName[name_len] = 0x04;     /* pad */
 		/* protocol requires ASCII signature byte on Unicode string */
 		pSMB->OldFileName[name_len + 1] = 0x00;
-		name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
-				OldFileName[name_len + 2], toName, PATH_MAX,
-				nls_codepage);
+		name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
+				toName, PATH_MAX, nls_codepage, remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2; /* convert to bytes */
 	} else {                /* BB improve the check for buffer overruns BB */
@@ -1415,7 +1434,7 @@ createSymLinkRetry:
 int
 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
 		       const char *fromName, const char *toName,
-		       const struct nls_table *nls_codepage)
+		       const struct nls_table *nls_codepage, int remap)
 {
 	TRANSACTION2_SPI_REQ *pSMB = NULL;
 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -1434,9 +1453,8 @@ createHardLinkRetry:
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX
-					 /* find define for this maxpathcomponent */
-					 , nls_codepage);
+		name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
+					    PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 
@@ -1458,9 +1476,8 @@ createHardLinkRetry:
 	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len_target =
-		    cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
+				     nls_codepage, remap);
 		name_len_target++;	/* trailing null */
 		name_len_target *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -1492,8 +1509,7 @@ createHardLinkRetry:
 		cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
 	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto createHardLinkRetry;
 
@@ -1503,7 +1519,7 @@ createHardLinkRetry:
 int
 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
 		   const char *fromName, const char *toName,
-		   const struct nls_table *nls_codepage)
+		   const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	NT_RENAME_REQ *pSMB = NULL;
@@ -1530,17 +1546,15 @@ winCreateHardLinkRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 		pSMB->OldFileName[name_len] = 0;	/* pad */
 		pSMB->OldFileName[name_len + 1] = 0x04; 
 		name_len2 =
-		    cifs_strtoUCS((wchar_t *) & pSMB->
-				  OldFileName[name_len + 2], toName, PATH_MAX,
-				  nls_codepage);
+		    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
+				     toName, PATH_MAX, nls_codepage, remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -1564,8 +1578,7 @@ winCreateHardLinkRetry:
 	if (rc) {
 		cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto winCreateHardLinkRetry;
 
@@ -1651,6 +1664,7 @@ querySymLinkRetry:
 				name_len = UniStrnlen((wchar_t *) ((char *)
 					&pSMBr->hdr.Protocol +data_offset),
 					min_t(const int, buflen,count) / 2);
+			/* BB FIXME investigate remapping reserved chars here */
 				cifs_strfromUCS_le(symlinkinfo,
 					(wchar_t *) ((char *)&pSMBr->hdr.Protocol +
 						data_offset),
@@ -1665,15 +1679,12 @@ querySymLinkRetry:
 	/* just in case so calling code does not go off the end of buffer */
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto querySymLinkRetry;
 	return rc;
 }
 
-
-
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName,
@@ -1723,9 +1734,23 @@ CIFSSMBQueryReparseLinkInfo(const int xi
 			rc = -EIO;	/* bad smb */
 		else {
 			if(data_count && (data_count < 2048)) {
-		/* could also validate reparse tag && better check name length */
+				char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
+
 				struct reparse_data * reparse_buf = (struct reparse_data *)
 					((char *)&pSMBr->hdr.Protocol + data_offset);
+				if((char*)reparse_buf >= end_of_smb) {
+					rc = -EIO;
+					goto qreparse_out;
+				}
+				if((reparse_buf->LinkNamesBuf + 
+					reparse_buf->TargetNameOffset +
+					reparse_buf->TargetNameLen) >
+						end_of_smb) {
+					cFYI(1,("reparse buf extended beyond SMB"));
+					rc = -EIO;
+					goto qreparse_out;
+				}
+				
 				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
 					name_len = UniStrnlen((wchar_t *)
 							(reparse_buf->LinkNamesBuf + 
@@ -1749,6 +1774,7 @@ CIFSSMBQueryReparseLinkInfo(const int xi
 			cFYI(1,("readlink result - %s ",symlinkinfo));
 		}
 	}
+qreparse_out:
 	if (pSMB)
 		cifs_buf_release(pSMB);
 
@@ -1773,7 +1799,8 @@ static void cifs_convert_ace(posix_acl_x
 }
 
 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area)
+static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
+				const int acl_type,const int size_of_data_area)
 {
 	int size =  0;
 	int i;
@@ -1826,7 +1853,7 @@ static int cifs_copy_posix_acl(char * tr
 	return size;
 }
 
-__u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
+static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
 			const posix_acl_xattr_entry * local_ace)
 {
 	__u16 rc = 0; /* 0 = ACL converted ok */
@@ -1844,7 +1871,7 @@ __u16 convert_ace_to_cifs_ace(struct cif
 }
 
 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
-__u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
+static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
 		const int acl_type)
 {
 	__u16 rc = 0;
@@ -1892,7 +1919,7 @@ int
 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
                         const unsigned char *searchName,
                         char *acl_inf, const int buflen, const int acl_type,
-                        const struct nls_table *nls_codepage)
+                        const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_POSIX_ACL */
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -1912,15 +1939,14 @@ queryAclRetry:
                                                                                                                                              
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-			cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				/* BB fixme find define for this maxpathcomponent */
-				, nls_codepage);
+			cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+					 PATH_MAX, nls_codepage, remap);
 		name_len++;     /* trailing null */
 		name_len *= 2;
 		pSMB->FileName[name_len] = 0;
 		pSMB->FileName[name_len+1] = 0;
 	} else {                /* BB improve the check for buffer overruns BB */
-		name_len = strnlen(searchName, PATH_MAX /* BB fixme */);
+		name_len = strnlen(searchName, PATH_MAX);
 		name_len++;     /* trailing null */
 		strncpy(pSMB->FileName, searchName, name_len);
 	}
@@ -1969,8 +1995,7 @@ queryAclRetry:
 				buflen,acl_type,count);
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto queryAclRetry;
 	return rc;
@@ -1979,8 +2004,9 @@ queryAclRetry:
 int
 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
                         const unsigned char *fileName,
-                        const char *local_acl, const int buflen, const int acl_type,
-                        const struct nls_table *nls_codepage)
+                        const char *local_acl, const int buflen, 
+			const int acl_type,
+                        const struct nls_table *nls_codepage, int remap)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -1996,11 +2022,10 @@ setAclRetry:
                       (void **) &pSMBr);
 	if (rc)
 		return rc;
-                                                                                                               	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-			cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				/* BB fixme find define for this maxpathcomponent */
-				, nls_codepage);
+			cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+				      PATH_MAX, nls_codepage, remap);
 		name_len++;     /* trailing null */
 		name_len *= 2;
 	} else {                /* BB improve the check for buffer overruns BB */
@@ -2049,20 +2074,102 @@ setAclRetry:
 	}
 
 setACLerrorExit:
-	if (pSMB)
-		cifs_buf_release(pSMB);
-                                                                                                            	if (rc == -EAGAIN)
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
 		goto setAclRetry;
-                                                                                                           	return rc;
+	return rc;
+}
+
+/* BB fix tabs in this function FIXME BB */
+int
+CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+{
+        int rc = 0;
+        struct smb_t2_qfi_req *pSMB = NULL;
+        struct smb_t2_qfi_rsp *pSMBr = NULL;
+        int bytes_returned;
+        __u16 params, byte_count;
+
+        cFYI(1,("In GetExtAttr"));
+        if(tcon == NULL)
+                return -ENODEV;
+
+GetExtAttrRetry:
+        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+        if (rc)
+                return rc;
+
+        params = 2 /* level */ +2 /* fid */;
+        pSMB->t2.TotalDataCount = 0;
+        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+        /* BB find exact max data count below from sess structure BB */
+        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+        pSMB->t2.MaxSetupCount = 0;
+        pSMB->t2.Reserved = 0;
+        pSMB->t2.Flags = 0;
+        pSMB->t2.Timeout = 0;
+        pSMB->t2.Reserved2 = 0;
+        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+			Fid) - 4);
+        pSMB->t2.DataCount = 0;
+        pSMB->t2.DataOffset = 0;
+        pSMB->t2.SetupCount = 1;
+        pSMB->t2.Reserved3 = 0;
+        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+        byte_count = params + 1 /* pad */ ;
+        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+        pSMB->Pad = 0;
+	pSMB->Fid = netfid;
+        pSMB->hdr.smb_buf_length += byte_count;
+        pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+        if (rc) {
+                cFYI(1, ("error %d in GetExtAttr", rc));
+        } else {
+                /* decode response */
+                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+                if (rc || (pSMBr->ByteCount < 2))
+                /* BB also check enough total bytes returned */
+                        /* If rc should we check for EOPNOSUPP and
+                        disable the srvino flag? or in caller? */
+                        rc = -EIO;      /* bad smb */
+                else {
+                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                        struct file_chattr_info * pfinfo;
+                        /* BB Do we need a cast or hash here ? */
+                        if(count != 16) {
+                                cFYI(1, ("Illegal size ret in GetExtAttr"));
+                                rc = -EIO;
+                                goto GetExtAttrOut;
+                        }
+                        pfinfo = (struct file_chattr_info *)
+                                (data_offset + (char *) &pSMBr->hdr.Protocol);
+                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+			*pMask = le64_to_cpu(pfinfo->mask);
+                }
+        }
+GetExtAttrOut:
+        cifs_buf_release(pSMB);
+        if (rc == -EAGAIN)
+                goto GetExtAttrRetry;
+        return rc;
 }
 
-#endif
+
+#endif /* CONFIG_POSIX */
 
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
 		 const unsigned char *searchName,
 		 FILE_ALL_INFO * pFindData,
-		 const struct nls_table *nls_codepage)
+		 const struct nls_table *nls_codepage, int remap)
 {
 /* level 263 SMB_QUERY_FILE_ALL_INFO */
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2072,7 +2179,7 @@ CIFSSMBQPathInfo(const int xid, struct c
 	int name_len;
 	__u16 params, byte_count;
 
-/* cFYI(1, ("In QPathInfo path %s", searchName)); */ /* BB fixme BB */
+/* cFYI(1, ("In QPathInfo path %s", searchName)); */
 QPathInfoRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
@@ -2081,9 +2188,8 @@ QPathInfoRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -2133,8 +2239,7 @@ QPathInfoRetry:
 		} else
 		    rc = -ENOMEM;
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto QPathInfoRetry;
 
@@ -2145,7 +2250,7 @@ int
 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
 		     const unsigned char *searchName,
 		     FILE_UNIX_BASIC_INFO * pFindData,
-		     const struct nls_table *nls_codepage)
+		     const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_FILE_UNIX_BASIC */
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2164,9 +2269,8 @@ UnixQPathInfoRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+				  PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -2217,17 +2321,15 @@ UnixQPathInfoRetry:
 			       sizeof (FILE_UNIX_BASIC_INFO));
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto UnixQPathInfoRetry;
 
 	return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL  /* function unused at present */
-int
-CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
+#if 0  /* function unused at present */
+int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
 	       const char *searchName, FILE_ALL_INFO * findData,
 	       const struct nls_table *nls_codepage)
 {
@@ -2248,7 +2350,7 @@ findUniqueRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
 				  /* find define for this maxpathcomponent */
 				  , nls_codepage);
 		name_len++;	/* trailing null */
@@ -2297,131 +2399,22 @@ findUniqueRetry:
 
 		/* BB fill in */
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
-	if (rc == -EAGAIN)
-		goto findUniqueRetry;
-
-	return rc;
-}
-#endif /* CIFS_EXPERIMENTAL */
-
-int
-CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
-	      const char *searchName, FILE_DIRECTORY_INFO * findData,
-	      T2_FFIRST_RSP_PARMS * findParms,
-	      const struct nls_table *nls_codepage, int *pUnicodeFlag,
-	      int *pUnixFlag)
-{
-/* level 257 SMB_ */
-	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
-	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
-	char *response_data;
-	int rc = 0;
-	int bytes_returned;
-	int name_len;
-	__u16 params, byte_count;
-
-	cFYI(1, ("In FindFirst"));
-findFirstRetry:
-	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
-	if (rc)
-		return rc;
-
-	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
-		name_len++;	/* trailing null */
-		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(searchName, PATH_MAX);
-		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, searchName, name_len);
-	}
-
-	params = 12 + name_len /* includes null */ ;
-	pSMB->TotalDataCount = 0;	/* no EAs */
-	pSMB->MaxParameterCount = cpu_to_le16(10);
-	pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
-					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
-	pSMB->MaxSetupCount = 0;
-	pSMB->Reserved = 0;
-	pSMB->Flags = 0;
-	pSMB->Timeout = 0;
-	pSMB->Reserved2 = 0;
-	byte_count = params + 1 /* pad */ ;
-	pSMB->TotalParameterCount = cpu_to_le16(params);
-	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	pSMB->ParameterOffset = cpu_to_le16(
-		offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
-	pSMB->DataCount = 0;
-	pSMB->DataOffset = 0;
-	pSMB->SetupCount = 1;	/* one byte no need to make endian neutral */
-	pSMB->Reserved3 = 0;
-	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
-	pSMB->SearchAttributes =
-	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
-			ATTR_DIRECTORY);
-	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_DIRECTORY_INFO));	/* should this be shrunk even more ? */
-	pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
-
-	/* test for Unix extensions */
-	if (tcon->ses->capabilities & CAP_UNIX) {
-		pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
-		*pUnixFlag = TRUE;
-	} else {
-		pSMB->InformationLevel =
-		    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-		*pUnixFlag = FALSE;
-	}
-	pSMB->SearchStorageType = 0;	/* BB what should we set this to? It is not clear if it matters BB */
-	pSMB->hdr.smb_buf_length += byte_count;
-	pSMB->ByteCount = cpu_to_le16(byte_count);
-
-	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-
-	if (rc) {		/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
-		cFYI(1, ("Error in FindFirst = %d", rc));
-	} else {
-		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-		if(!rc) {
-		/* decode response */
-		/* BB add safety checks for these memcpys */
-			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-				*pUnicodeFlag = TRUE;
-			else
-				*pUnicodeFlag = FALSE;
-			memcpy(findParms,
-			       (char *) &pSMBr->hdr.Protocol +
-			       le16_to_cpu(pSMBr->t2.ParameterOffset),
-			       sizeof (T2_FFIRST_RSP_PARMS));
-			response_data =
-			    (char *) &pSMBr->hdr.Protocol +
-			    le16_to_cpu(pSMBr->t2.DataOffset);
-			memcpy(findData, response_data, 
-				le16_to_cpu(pSMBr->t2.DataCount));
-		}
-	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
 
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
-		goto findFirstRetry;
+		goto findUniqueRetry;
 
 	return rc;
 }
+#endif /* end unused (temporarily) function */
 
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
-CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon,
+CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
 	      const char *searchName, 
 	      const struct nls_table *nls_codepage,
 	      __u16 *	pnetfid,
-	      struct cifs_search_info * psrch_inf)
+	      struct cifs_search_info * psrch_inf, int remap)
 {
 /* level 257 SMB_ */
 	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2432,9 +2425,9 @@ CIFSFindFirst2(const int xid, struct cif
 	int name_len;
 	__u16 params, byte_count;
 
-	cFYI(1, ("In FindFirst2"));
+	cFYI(1, ("In FindFirst for %s",searchName));
 
-findFirst2Retry:
+findFirstRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
@@ -2442,20 +2435,30 @@ findFirst2Retry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName,
-				 PATH_MAX, nls_codepage);
-		name_len++;	/* trailing null */
+		    cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
+				 PATH_MAX, nls_codepage, remap);
+		/* We can not add the asterik earlier in case
+		it got remapped to 0xF03A as if it were part of the
+		directory name instead of a wildcard */
 		name_len *= 2;
+		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len+1] = 0;
+		pSMB->FileName[name_len+2] = '*';
+		pSMB->FileName[name_len+3] = 0;
+		name_len += 4; /* now the trailing null */
 		pSMB->FileName[name_len] = 0; /* null terminate just in case */
 		pSMB->FileName[name_len+1] = 0;
+		name_len += 2;
 	} else {	/* BB add check for overrun of SMB buf BB */
 		name_len = strnlen(searchName, PATH_MAX);
-		name_len++;	/* trailing null */
 /* BB fix here and in unicode clause above ie
 		if(name_len > buffersize-header)
 			free buffer exit; BB */
 		strncpy(pSMB->FileName, searchName, name_len);
-		pSMB->FileName[name_len] = 0; /* just in case */
+		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len+1] = '*';
+		pSMB->FileName[name_len+2] = 0;
+		name_len += 3;
 	}
 
 	params = 12 + name_len /* includes null */ ;
@@ -2504,7 +2507,7 @@ findFirst2Retry:
 		/* BB eventually could optimize out free and realloc of buf */
 		/*    for this case */
 		if (rc == -EAGAIN)
-			goto findFirst2Retry;
+			goto findFirstRetry;
 	} else { /* decode response */
 		/* BB remember to free buffer if error BB */
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
@@ -2518,7 +2521,6 @@ findFirst2Retry:
 			psrch_inf->srch_entries_start = 
 				(char *) &pSMBr->hdr.Protocol + 
 					le16_to_cpu(pSMBr->t2.DataOffset);
-
 			parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
 			       le16_to_cpu(pSMBr->t2.ParameterOffset));
 
@@ -2530,18 +2532,16 @@ findFirst2Retry:
 			psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
 			psrch_inf->index_of_last_entry = 
 				psrch_inf->entries_in_buffer;
-/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry));  */
 			*pnetfid = parms->SearchHandle;
 		} else {
-			if(pSMB)
-				cifs_buf_release(pSMB);
+			cifs_buf_release(pSMB);
 		}
 	}
 
 	return rc;
 }
 
-int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
+int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
             __u16 searchHandle, struct cifs_search_info * psrch_inf)
 {
 	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
@@ -2552,7 +2552,7 @@ int CIFSFindNext2(const int xid, struct 
 	int bytes_returned, name_len;
 	__u16 params, byte_count;
 
-	cFYI(1, ("In FindNext2"));
+	cFYI(1, ("In FindNext"));
 
 	if(psrch_inf->endOfSearch == TRUE)
 		return -ENOENT;
@@ -2659,137 +2659,31 @@ int CIFSFindNext2(const int xid, struct 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
 	since file handle passed in no longer valid */
 FNext2_err_exit:
-	if ((rc != 0) && pSMB)
+	if (rc != 0)
 		cifs_buf_release(pSMB);
                                                                                               
 	return rc;
 }
 
 int
-CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-		FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
-		const __u16 searchHandle, char * resume_file_name, int name_len,
-		__u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
 {
-/* level 257 SMB_ */
-	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
-	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
-	char *response_data;
 	int rc = 0;
+	FINDCLOSE_REQ *pSMB = NULL;
+	CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
 	int bytes_returned;
-	__u16 params, byte_count;
 
-	cFYI(1, ("In FindNext"));
+	cFYI(1, ("In CIFSSMBFindClose"));
+	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
 
-	if(resume_file_name == NULL) {
-		return -EIO;
-	}
-	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
+	/* no sense returning error if session restarted
+		as file handle has been closed */
+	if(rc == -EAGAIN)
+		return 0;
 	if (rc)
 		return rc;
 
-	params = 14;	/* includes 2 bytes of null string, converted to LE below */
-	byte_count = 0;
-	pSMB->TotalDataCount = 0;	/* no EAs */
-	pSMB->MaxParameterCount = cpu_to_le16(8);
-	pSMB->MaxDataCount =
-	    cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
-	pSMB->MaxSetupCount = 0;
-	pSMB->Reserved = 0;
-	pSMB->Flags = 0;
-	pSMB->Timeout = 0;
-	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =  cpu_to_le16(
-           offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
-	pSMB->DataCount = 0;
-	pSMB->DataOffset = 0;
-	pSMB->SetupCount = 1;
-	pSMB->Reserved3 = 0;
-	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
-	pSMB->SearchHandle = searchHandle;	/* always kept as le */
-	findParms->SearchCount = 0;	/* set to zero in case of error */
-	pSMB->SearchCount =
-	    cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
-	/* test for Unix extensions */
-	if (tcon->ses->capabilities & CAP_UNIX) {
-		pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
-		*pUnixFlag = TRUE;
-	} else {
-		pSMB->InformationLevel =
-		    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-		*pUnixFlag = FALSE;
-	}
-	pSMB->ResumeKey = resume_key;
-	pSMB->SearchFlags =
-	    cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
-	/* BB add check to make sure we do not cross end of smb */
-	if(name_len < PATH_MAX) {
-		memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
-		byte_count += name_len;
-	}
-	params += name_len;
-	byte_count = params + 1 /* pad */ ;
-	pSMB->TotalParameterCount = cpu_to_le16(params);
-	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	/* BB improve error handling here */
-	pSMB->hdr.smb_buf_length += byte_count;
-	pSMB->ByteCount = cpu_to_le16(byte_count);
-
-	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-
-	if (rc) {
-		if (rc == -EBADF)
-			rc = 0;	/* search probably was closed at end of search above */
-		else
-			cFYI(1, ("FindNext returned = %d", rc));
-	} else {		/* decode response */
-		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-
-		/* BB add safety checks for these memcpys */
-		if(rc == 0) {
-			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-				*pUnicodeFlag = TRUE;
-			else
-				*pUnicodeFlag = FALSE;
-			memcpy(findParms,
-			       (char *) &pSMBr->hdr.Protocol +
-			       le16_to_cpu(pSMBr->t2.ParameterOffset),
-			       sizeof (T2_FNEXT_RSP_PARMS));
-			response_data =
-			    (char *) &pSMBr->hdr.Protocol +
-			    le16_to_cpu(pSMBr->t2.DataOffset);
-			memcpy(findData,response_data,le16_to_cpu(pSMBr->t2.DataCount));
-		}
-	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
-
-	/* Note: On -EAGAIN error only caller can retry on handle based calls
-		since file handle passed in no longer valid */
-
-	return rc;
-}
-
-int
-CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
-{
-	int rc = 0;
-	FINDCLOSE_REQ *pSMB = NULL;
-	CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
-	int bytes_returned;
-
-	cFYI(1, ("In CIFSSMBFindClose"));
-	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
 	pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
-	/* no sense returning error if session restarted
-		file handle has been closed */
-	if(rc == -EAGAIN)
-		return 0;
-	if (rc)
-		return rc;
-
 	pSMB->FileID = searchHandle;
 	pSMB->ByteCount = 0;
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -2797,8 +2691,7 @@ CIFSFindClose(const int xid, struct cifs
 	if (rc) {
 		cERROR(1, ("Send error in FindClose = %d", rc));
 	}
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
+	cifs_small_buf_release(pSMB);
 
 	/* Since session is dead, search handle closed on server already */
 	if (rc == -EAGAIN)
@@ -2812,28 +2705,91 @@ int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
                 __u64 * inode_number,
-                const struct nls_table *nls_codepage)
+                const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int name_len, bytes_returned;
+	__u16 params, byte_count;
 
-	cFYI(1,("In GetSrvInodeNumber for %s",searchName));
+	cFYI(1,("In GetSrvInodeNum for %s",searchName));
 	if(tcon == NULL)
 		return -ENODEV; 
 
-        cFYI(1, ("In QPathInfo path %s", searchName));
 GetInodeNumberRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
                       (void **) &pSMBr);
 	if (rc)
 		return rc;
 
-/* BB add missing code here */
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
-                                                                                                                         
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+				PATH_MAX,nls_codepage, remap);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max data count below from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(4000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+		struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("error %d in QueryInternalInfo", rc));
+	} else {
+		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc || (pSMBr->ByteCount < 2))
+		/* BB also check enough total bytes returned */
+			/* If rc should we check for EOPNOSUPP and
+			disable the srvino flag? or in caller? */
+			rc = -EIO;      /* bad smb */
+                else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+			struct file_internal_info * pfinfo;
+			/* BB Do we need a cast or hash here ? */
+			if(count < 8) {
+				cFYI(1, ("Illegal size ret in QryIntrnlInf"));
+				rc = -EIO;
+				goto GetInodeNumOut;
+			}
+			pfinfo = (struct file_internal_info *)
+				(data_offset + (char *) &pSMBr->hdr.Protocol);
+			*inode_number = pfinfo->UniqueId;
+		}
+	}
+GetInodeNumOut:
+	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto GetInodeNumberRetry;
 	return rc;
@@ -2845,7 +2801,7 @@ CIFSGetDFSRefer(const int xid, struct ci
 		const unsigned char *searchName,
 		unsigned char **targetUNCs,
 		unsigned int *number_of_UNC_in_array,
-		const struct nls_table *nls_codepage)
+		const struct nls_table *nls_codepage, int remap)
 {
 /* TRANS2_GET_DFS_REFERRAL */
 	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
@@ -2881,10 +2837,8 @@ getDFSRetry:
 	if (ses->capabilities & CAP_UNICODE) {
 		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
-				  searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
+				     searchName, PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -3012,8 +2966,7 @@ GetDFSRefExit:
 }
 
 int
-CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
-	       struct kstatfs *FSData, const struct nls_table *nls_codepage)
+CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
 {
 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3087,8 +3040,7 @@ QFSInfoRetry:
 			      FSData->f_bsize));
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto QFSInfoRetry;
@@ -3097,8 +3049,7 @@ QFSInfoRetry:
 }
 
 int
-CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
-			const struct nls_table *nls_codepage)
+CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
 {
 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3157,8 +3108,7 @@ QFSAttributeRetry:
 			       sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto QFSAttributeRetry;
@@ -3167,8 +3117,7 @@ QFSAttributeRetry:
 }
 
 int
-CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
-		     const struct nls_table *nls_codepage)
+CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
 {
 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3221,15 +3170,14 @@ QFSDeviceRetry:
 		else {
 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
 			response_data =
-			    (FILE_SYSTEM_DEVICE_INFO
-			     *) (((char *) &pSMBr->hdr.Protocol) +
+			    (FILE_SYSTEM_DEVICE_INFO *)
+				(((char *) &pSMBr->hdr.Protocol) +
 				 data_offset);
 			memcpy(&tcon->fsDevInfo, response_data,
 			       sizeof (FILE_SYSTEM_DEVICE_INFO));
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto QFSDeviceRetry;
@@ -3238,8 +3186,7 @@ QFSDeviceRetry:
 }
 
 int
-CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
-		   const struct nls_table *nls_codepage)
+CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
 {
 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3298,8 +3245,7 @@ QFSUnixRetry:
 			       sizeof (FILE_SYSTEM_UNIX_INFO));
 		}
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto QFSUnixRetry;
@@ -3308,6 +3254,93 @@ QFSUnixRetry:
 	return rc;
 }
 
+
+int
+CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+		   struct kstatfs *FSData)
+{
+/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_POSIX_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSPosixInfo"));
+QFSPosixRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
+        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 13)) {
+			rc = -EIO;	/* bad smb */
+		} else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			response_data =
+			    (FILE_SYSTEM_POSIX_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			FSData->f_bsize =
+					le32_to_cpu(response_data->BlockSize);
+			FSData->f_blocks =
+					le64_to_cpu(response_data->TotalBlocks);
+			FSData->f_bfree =
+			    le64_to_cpu(response_data->BlocksAvail);
+			if(response_data->UserBlocksAvail == -1) {
+				FSData->f_bavail = FSData->f_bfree;
+			} else {
+				FSData->f_bavail =
+					le64_to_cpu(response_data->UserBlocksAvail);
+			}
+			if(response_data->TotalFileNodes != -1)
+				FSData->f_files =
+					le64_to_cpu(response_data->TotalFileNodes);
+			if(response_data->FreeFileNodes != -1)
+				FSData->f_ffree =
+					le64_to_cpu(response_data->FreeFileNodes);
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSPosixRetry;
+
+	return rc;
+}
+
+
 /* We can not use write of zero bytes trick to 
    set file size due to need for large file support.  Also note that 
    this SetPathInfo is preferred to SetFileInfo based method in next 
@@ -3316,7 +3349,8 @@ QFSUnixRetry:
 
 int
 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-	      __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
+	      __u64 size, int SetAllocation, 
+	      const struct nls_table *nls_codepage, int remap)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -3335,9 +3369,8 @@ SetEOFRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -3396,8 +3429,7 @@ SetEOFRetry:
 		cFYI(1, ("SetPathInfo (file size) returned %d", rc));
 	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto SetEOFRetry;
@@ -3419,11 +3451,13 @@ CIFSSMBSetFileSize(const int xid, struct
 
 	cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
 			(long long)size));
-	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
 	if (rc)
 		return rc;
 
+	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
     
@@ -3483,7 +3517,7 @@ CIFSSMBSetFileSize(const int xid, struct
 	}
 
 	if (pSMB)
-		cifs_buf_release(pSMB);
+		cifs_small_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
@@ -3491,90 +3525,89 @@ CIFSSMBSetFileSize(const int xid, struct
 	return rc;
 }
 
+/* Some legacy servers such as NT4 require that the file times be set on 
+   an open handle, rather than by pathname - this is awkward due to
+   potential access conflicts on the open, but it is unavoidable for these
+   old servers since the only other choice is to go from 100 nanosecond DCE
+   time and resort to the original setpathinfo level which takes the ancient
+   DOS time format with 2 second granularity */
 int
-CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-		const FILE_BASIC_INFO * data, 
-		const struct nls_table *nls_codepage)
+CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
+                   __u16 fid)
 {
-	TRANSACTION2_SPI_REQ *pSMB = NULL;
-	TRANSACTION2_SPI_RSP *pSMBr = NULL;
-	int name_len;
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
 	int rc = 0;
 	int bytes_returned = 0;
-	char *data_offset;
 	__u16 params, param_offset, offset, byte_count, count;
 
-	cFYI(1, ("In SetTimes"));
+	cFYI(1, ("Set Times (via SetFileInfo)"));
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
 
-SetTimesRetry:
-	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
 	if (rc)
 		return rc;
 
-	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
-		name_len++;	/* trailing null */
-		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
-		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, fileName, name_len);
-	}
+	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
 
-	params = 6 + name_len;
-	count = sizeof (FILE_BASIC_INFO);
-	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	/* At this point there is no need to override the current pid
+	with the pid of the opener, but that could change if we someday
+	use an existing handle (rather than opening one on the fly) */
+	/* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
+    
+	params = 6;
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
 	offset = param_offset + params;
-	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-	pSMB->ParameterOffset = cpu_to_le16(param_offset);
-	pSMB->DataOffset = cpu_to_le16(offset);
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
+
+	count = sizeof (FILE_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB PDU from sess */
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
-	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
 	byte_count = 3 /* pad */  + params + count;
-
 	pSMB->DataCount = cpu_to_le16(count);
 	pSMB->ParameterCount = cpu_to_le16(params);
 	pSMB->TotalDataCount = pSMB->DataCount;
 	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = fid;
 	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
 	else
 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
 	pSMB->Reserved4 = 0;
 	pSMB->hdr.smb_buf_length += byte_count;
-	memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
 	pSMB->ByteCount = cpu_to_le16(byte_count);
+	memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc) {
-		cFYI(1, ("SetPathInfo (times) returned %d", rc));
+		cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
 	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_small_buf_release(pSMB);
 
-	if (rc == -EAGAIN)
-		goto SetTimesRetry;
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
 
 	return rc;
 }
 
+
 int
-CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
-		FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage)
+CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+		const FILE_BASIC_INFO * data, 
+		const struct nls_table *nls_codepage, int remap)
 {
 	TRANSACTION2_SPI_REQ *pSMB = NULL;
 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -3582,11 +3615,11 @@ CIFSSMBSetTimesLegacy(int xid, struct ci
 	int rc = 0;
 	int bytes_returned = 0;
 	char *data_offset;
-	__u16 params, param_offset, count, offset, byte_count;
+	__u16 params, param_offset, offset, byte_count, count;
 
-	cFYI(1, ("In SetTimesLegacy"));
+	cFYI(1, ("In SetTimes"));
 
-SetTimesRetryLegacy:
+SetTimesRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
@@ -3594,9 +3627,8 @@ SetTimesRetryLegacy:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -3604,10 +3636,9 @@ SetTimesRetryLegacy:
 		name_len++;	/* trailing null */
 		strncpy(pSMB->FileName, fileName, name_len);
 	}
-/* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info
-	in parent function, from the better and ususal FILE_BASIC_INFO */
+
 	params = 6 + name_len;
-	count = sizeof (FILE_INFO_STANDARD);
+	count = sizeof (FILE_BASIC_INFO);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
 	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
 	pSMB->MaxSetupCount = 0;
@@ -3630,30 +3661,86 @@ SetTimesRetryLegacy:
 	pSMB->ParameterCount = cpu_to_le16(params);
 	pSMB->TotalDataCount = pSMB->DataCount;
 	pSMB->TotalParameterCount = pSMB->ParameterCount;
-	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
+	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+	else
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
 	pSMB->Reserved4 = 0;
 	pSMB->hdr.smb_buf_length += byte_count;
-	memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD));
+	memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc) {
-		cFYI(1, ("SetPathInfo (times legacy) returned %d", rc));
+		cFYI(1, ("SetPathInfo (times) returned %d", rc));
 	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SetTimesRetry;
+
+	return rc;
+}
+
+/* Can not be used to set time stamps yet (due to old DOS time format) */
+/* Can be used to set attributes */
+#if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
+	  handling it anyway and NT4 was what we thought it would be needed for
+	  Do not delete it until we prove whether needed for Win9x though */
+int
+CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
+		__u16 dos_attrs, const struct nls_table *nls_codepage)
+{
+	SETATTR_REQ *pSMB = NULL;
+	SETATTR_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In SetAttrLegacy"));
+
+SetAttrLgcyRetry:
+	rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+				PATH_MAX, nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	pSMB->attr = cpu_to_le16(dos_attrs);
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += name_len + 1;
+	pSMB->ByteCount = cpu_to_le16(name_len + 1);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in LegacySetAttr = %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
-		goto SetTimesRetryLegacy;
+		goto SetAttrLgcyRetry;
 
 	return rc;
 }
+#endif /* temporarily unneeded SetAttr legacy function */
 
 int
 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
-		    char *fileName, __u64 mode, __u64 uid, __u64 gid,
-		    dev_t device, const struct nls_table *nls_codepage)
+		    char *fileName, __u64 mode, __u64 uid, __u64 gid, 
+		    dev_t device, const struct nls_table *nls_codepage, 
+		    int remap)
 {
 	TRANSACTION2_SPI_REQ *pSMB = NULL;
 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -3672,9 +3759,8 @@ setPermsRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -3789,10 +3875,7 @@ int CIFSSMBNotify(const int xid, struct 
 	if (rc) {
 		cFYI(1, ("Error in Notify = %d", rc));
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
-/*		if (rc == -EAGAIN)
-			goto NotifyRetry; */
+	cifs_buf_release(pSMB);
 	return rc;	
 }
 #ifdef CONFIG_CIFS_XATTR
@@ -3800,7 +3883,7 @@ ssize_t
 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
 		 const unsigned char *searchName,
 		 char * EAData, size_t buf_size,
-		 const struct nls_table *nls_codepage)
+		 const struct nls_table *nls_codepage, int remap)
 {
 		/* BB assumes one setup word */
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3821,9 +3904,8 @@ QAllEAsRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
@@ -3945,7 +4027,7 @@ QAllEAsRetry:
 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
 		const unsigned char * searchName,const unsigned char * ea_name,
 		unsigned char * ea_value, size_t buf_size, 
-		const struct nls_table *nls_codepage)
+		const struct nls_table *nls_codepage, int remap)
 {
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
@@ -3965,9 +4047,8 @@ QEARetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
@@ -4093,7 +4174,8 @@ QEARetry:
 int
 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
 		const char * ea_name, const void * ea_value, 
-		const __u16 ea_value_len, const struct nls_table *nls_codepage)
+		const __u16 ea_value_len, const struct nls_table *nls_codepage,
+		int remap)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -4112,9 +4194,8 @@ SetEARetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				  /* find define for this maxpathcomponent */
-				  , nls_codepage);
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve the check for buffer overruns BB */
@@ -4162,7 +4243,8 @@ SetEARetry:
 	/* we checked above that name len is less than 255 */
 	parm_data->list[0].name_len = (__u8)name_len;;
 	/* EA names are always ASCII */
-	strncpy(parm_data->list[0].name,ea_name,name_len);
+	if(ea_name)
+		strncpy(parm_data->list[0].name,ea_name,name_len);
 	parm_data->list[0].name[name_len] = 0;
 	parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
 	/* caller ensures that ea_value_len is less than 64K but
@@ -4185,8 +4267,7 @@ SetEARetry:
 		cFYI(1, ("SetPathInfo (EA) returned %d", rc));
 	}
 
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
 		goto SetEARetry;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2004
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
 #include <linux/ctype.h>
 #include <linux/utsname.h>
 #include <linux/mempool.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -47,7 +48,6 @@ extern void SMBencrypt(unsigned char *pa
 		       unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
 			 unsigned char *p24);
-extern int cifs_inet_pton(int, const char *, void *dst);
 
 extern mempool_t *cifs_req_poolp;
 
@@ -70,8 +70,10 @@ struct smb_vol {
 	unsigned setuids:1;
 	unsigned noperm:1;
 	unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
+	unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/
 	unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
 	unsigned direct_io:1;
+	unsigned remap:1;   /* set to remap seven reserved chars in filenames */
 	unsigned int rsize;
 	unsigned int wsize;
 	unsigned int sockopt;
@@ -114,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *s
 	spin_unlock(&GlobalMid_Lock);
 	server->maxBuf = 0;
 
-	cFYI(1, ("Reconnecting tcp session "));
+	cFYI(1, ("Reconnecting tcp session"));
 
 	/* before reconnecting the tcp session, mark the smb session (uid)
 		and the tid bad so they are not used until reconnected */
@@ -155,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *s
 					qhead);
 		if(mid_entry) {
 			if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
-				/* Mark other intransit requests as needing retry so 
-				  we do not immediately mark the session bad again 
-				  (ie after we reconnect below) as they timeout too */
+				/* Mark other intransit requests as needing
+				   retry so we do not immediately mark the
+				   session bad again (ie after we reconnect
+				   below) as they timeout too */
 				mid_entry->midState = MID_RETRY_NEEDED;
 			}
 		}
@@ -175,14 +178,14 @@ cifs_reconnect(struct TCP_Server_Info *s
 					server->workstation_RFC1001_name);
 		}
 		if(rc) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(3 * HZ);
+			msleep(3000);
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
 			spin_lock(&GlobalMid_Lock);
 			if(server->tcpStatus != CifsExiting)
 				server->tcpStatus = CifsGood;
-			spin_unlock(&GlobalMid_Lock);
+			server->sequence_number = 0;
+			spin_unlock(&GlobalMid_Lock);			
 	/*		atomic_set(&server->inFlight,0);*/
 			wake_up(&server->response_q);
 		}
@@ -190,12 +193,129 @@ cifs_reconnect(struct TCP_Server_Info *s
 	return rc;
 }
 
+/* 
+	return codes:
+		0 	not a transact2, or all data present
+		>0 	transact2 with that much data missing
+		-EINVAL = invalid transact2
+
+ */
+static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+{
+	struct smb_t2_rsp * pSMBt;
+        int total_data_size;
+	int data_in_this_rsp;
+	int remaining;
+
+	if(pSMB->Command != SMB_COM_TRANSACTION2)
+		return 0;
+
+        /* check for plausible wct, bcc and t2 data and parm sizes */
+        /* check for parm and data offset going beyond end of smb */
+	if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+		cFYI(1,("invalid transact2 word count"));
+		return -EINVAL;
+	}
+
+	pSMBt = (struct smb_t2_rsp *)pSMB;
+
+	total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+	data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+	remaining = total_data_size - data_in_this_rsp;
+
+	if(remaining == 0)
+		return 0;
+	else if(remaining < 0) {
+		cFYI(1,("total data %d smaller than data in frame %d",
+			total_data_size, data_in_this_rsp));
+		return -EINVAL;
+	} else {
+		cFYI(1,("missing %d bytes from transact2, check next response",
+			remaining));
+		if(total_data_size > maxBufSize) {
+			cERROR(1,("TotalDataSize %d is over maximum buffer %d",
+				total_data_size,maxBufSize));
+			return -EINVAL; 
+		}
+		return remaining;
+	}
+}
+
+static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+{
+	struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
+	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
+	int total_data_size;
+	int total_in_buf;
+	int remaining;
+	int total_in_buf2;
+	char * data_area_of_target;
+	char * data_area_of_buf2;
+	__u16 byte_count;
+
+	total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+
+	if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+		cFYI(1,("total data sizes of primary and secondary t2 differ"));
+	}
+
+	total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+	remaining = total_data_size - total_in_buf;
+	
+	if(remaining < 0)
+		return -EINVAL;
+
+	if(remaining == 0) /* nothing to do, ignore */
+		return 0;
+	
+	total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+	if(remaining < total_in_buf2) {
+		cFYI(1,("transact2 2nd response contains too much data"));
+	}
+
+	/* find end of first SMB data area */
+	data_area_of_target = (char *)&pSMBt->hdr.Protocol + 
+				le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+	/* validate target area */
+
+	data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
+                                        le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+
+	data_area_of_target += total_in_buf;
+
+	/* copy second buffer into end of first buffer */
+	memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+	total_in_buf += total_in_buf2;
+	pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
+	byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
+	byte_count += total_in_buf2;
+	BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
+
+	byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+	byte_count += total_in_buf2;
+
+	/* BB also add check that we are not beyond maximum buffer size */
+		
+	pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+
+	if(remaining == total_in_buf2) {
+		cFYI(1,("found the last secondary response"));
+		return 0; /* we are done */
+	} else /* more responses to go */
+		return 1;
+
+}
+
 static int
 cifs_demultiplex_thread(struct TCP_Server_Info *server)
 {
 	int length;
 	unsigned int pdu_length, total_read;
 	struct smb_hdr *smb_buffer = NULL;
+	struct smb_hdr *bigbuf = NULL;
+	struct smb_hdr *smallbuf = NULL;
 	struct msghdr smb_msg;
 	struct kvec iov;
 	struct socket *csocket = server->ssocket;
@@ -204,13 +324,16 @@ cifs_demultiplex_thread(struct TCP_Serve
 	struct task_struct *task_to_wake = NULL;
 	struct mid_q_entry *mid_entry;
 	char *temp;
+	int isLargeBuf = FALSE;
+	int isMultiRsp;
+	int reconnect;
 
 	daemonize("cifsd");
 	allow_signal(SIGKILL);
 	current->flags |= PF_MEMALLOC;
 	server->tsk = current;	/* save process info to wake at shutdown */
 	cFYI(1, ("Demultiplex PID: %d", current->pid));
-	write_lock(&GlobalSMBSeslock);
+	write_lock(&GlobalSMBSeslock); 
 	atomic_inc(&tcpSesAllocCount);
 	length = tcpSesAllocCount.counter;
 	write_unlock(&GlobalSMBSeslock);
@@ -221,233 +344,296 @@ cifs_demultiplex_thread(struct TCP_Serve
 	}
 
 	while (server->tcpStatus != CifsExiting) {
-		if (smb_buffer == NULL)
-			smb_buffer = cifs_buf_get();
-		else
-			memset(smb_buffer, 0, sizeof (struct smb_hdr));
-
-		if (smb_buffer == NULL) {
-			cERROR(1,("Can not get memory for SMB response"));
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(HZ * 3); /* give system time to free memory */
-			continue;
+		if (bigbuf == NULL) {
+			bigbuf = cifs_buf_get();
+			if(bigbuf == NULL) {
+				cERROR(1,("No memory for large SMB response"));
+				msleep(3000);
+				/* retry will check if exiting */
+				continue;
+			}
+		} else if(isLargeBuf) {
+			/* we are reusing a dirtry large buf, clear its start */
+			memset(bigbuf, 0, sizeof (struct smb_hdr));
 		}
+
+		if (smallbuf == NULL) {
+			smallbuf = cifs_small_buf_get();
+			if(smallbuf == NULL) {
+				cERROR(1,("No memory for SMB response"));
+				msleep(1000);
+				/* retry will check if exiting */
+				continue;
+			}
+			/* beginning of smb buffer is cleared in our buf_get */
+		} else /* if existing small buf clear beginning */
+			memset(smallbuf, 0, sizeof (struct smb_hdr));
+
+		isLargeBuf = FALSE;
+		isMultiRsp = FALSE;
+		smb_buffer = smallbuf;
 		iov.iov_base = smb_buffer;
-		iov.iov_len = sizeof (struct smb_hdr) - 1;	
-        /* 1 byte less above since wct is not always returned in error cases */
+		iov.iov_len = 4;
 		smb_msg.msg_control = NULL;
 		smb_msg.msg_controllen = 0;
-
 		length =
 		    kernel_recvmsg(csocket, &smb_msg,
-				   &iov, 1,
-				   sizeof (struct smb_hdr) -
-				   1 /* RFC1001 header and SMB header */ ,
-				   MSG_PEEK /* flags see socket.h */ );
+				 &iov, 1, 4, 0 /* BB see socket.h flags */);
 
 		if(server->tcpStatus == CifsExiting) {
 			break;
 		} else if (server->tcpStatus == CifsNeedReconnect) {
-			cFYI(1,("Reconnecting after server stopped responding"));
+			cFYI(1,("Reconnect after server stopped responding"));
 			cifs_reconnect(server);
 			cFYI(1,("call to reconnect done"));
 			csocket = server->ssocket;
 			continue;
-		} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)
-				|| ((length > 0) && (length <= 3)) ) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(1); /* minimum sleep to prevent looping
+		} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
+			msleep(1); /* minimum sleep to prevent looping
 				allowing socket to clear and app threads to set
 				tcpStatus CifsNeedReconnect if server hung */
 			continue;
 		} else if (length <= 0) {
 			if(server->tcpStatus == CifsNew) {
-				cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
-				/* some servers kill tcp session rather than returning
-					smb negprot error in which case reconnecting here is
-					not going to help - return error to mount */
+				cFYI(1,("tcp session abend after SMBnegprot"));
+				/* some servers kill the TCP session rather than
+				   returning an SMB negprot error, in which
+				   case reconnecting here is not going to help,
+				   and so simply return error to mount */
 				break;
 			}
 			if(length == -EINTR) { 
 				cFYI(1,("cifsd thread killed"));
 				break;
 			}
-			cFYI(1,("Reconnecting after unexpected peek error %d",length));
+			cFYI(1,("Reconnect after unexpected peek error %d",
+				length));
+			cifs_reconnect(server);
+			csocket = server->ssocket;
+			wake_up(&server->response_q);
+			continue;
+		} else if (length < 4) {
+			cFYI(1,
+			    ("Frame under four bytes received (%d bytes long)",
+			      length));
 			cifs_reconnect(server);
 			csocket = server->ssocket;
 			wake_up(&server->response_q);
 			continue;
 		}
 
-		pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
-		/* Only read pdu_length after below checks for too short (due
-		   to e.g. int overflow) and too long ie beyond end of buf */
-		cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
+		/* the right amount was read from socket - 4 bytes */
+
+		pdu_length = ntohl(smb_buffer->smb_buf_length);
+		cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
 
 		temp = (char *) smb_buffer;
-		if (length > 3) {
-			if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
-				iov.iov_base = smb_buffer;
-				iov.iov_len = 4;
-				length = kernel_recvmsg(csocket, &smb_msg,
-							&iov, 1, 4, 0);
-				cFYI(0,("Received 4 byte keep alive packet"));
-			} else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
-				iov.iov_base = smb_buffer;
-				iov.iov_len = 4;
-				length = kernel_recvmsg(csocket, &smb_msg,
-							&iov, 1, 4, 0);
-					cFYI(1,("Good RFC 1002 session rsp"));
-			} else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
-				   && (length == 5)) {
-				/* we get this from Windows 98 instead of error on SMB negprot response */
-				cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
-				if(server->tcpStatus == CifsNew) {
-					/* if nack on negprot (rather than 
-					ret of smb negprot error) reconnecting
-					not going to help, ret error to mount */
-					break;
-				} else {
-					/* give server a second to
-					clean up before reconnect attempt */
-					set_current_state(TASK_INTERRUPTIBLE);
-					schedule_timeout(HZ);
-					/* always try 445 first on reconnect
-					since we get NACK on some if we ever
-					connected to port 139 (the NACK is 
-					since we do not begin with RFC1001
-					session initialize frame) */
-					server->addr.sockAddr.sin_port = htons(CIFS_PORT);
-					cifs_reconnect(server);
-					csocket = server->ssocket;
-					wake_up(&server->response_q);
-					continue;
-				}
-			} else if (temp[0] != (char) 0) {
-				cERROR(1,("Unknown RFC 1002 frame"));
-				cifs_dump_mem(" Received Data: ", temp, length);
+		if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+			continue; 
+		} else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+			cFYI(1,("Good RFC 1002 session rsp"));
+			continue;
+		} else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+			/* we get this from Windows 98 instead of 
+			   an error on SMB negprot response */
+			cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+				temp[4]));
+			if(server->tcpStatus == CifsNew) {
+				/* if nack on negprot (rather than 
+				ret of smb negprot error) reconnecting
+				not going to help, ret error to mount */
+				break;
+			} else {
+				/* give server a second to
+				clean up before reconnect attempt */
+				msleep(1000);
+				/* always try 445 first on reconnect
+				since we get NACK on some if we ever
+				connected to port 139 (the NACK is 
+				since we do not begin with RFC1001
+				session initialize frame) */
+				server->addr.sockAddr.sin_port = 
+					htons(CIFS_PORT);
 				cifs_reconnect(server);
 				csocket = server->ssocket;
+				wake_up(&server->response_q);
 				continue;
-			} else {
-				if (length < 16) {
-					/* We can not validate the SMB unless 
-					at least this much of SMB available
-					so give the socket time to copy
-					a few more bytes and retry */ 
-					set_current_state(TASK_INTERRUPTIBLE);
-					schedule_timeout(10);
-					continue;
-				} else if( (pdu_length >
-					CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
-				    || (pdu_length <
-					sizeof (struct smb_hdr) - 1)
-				    || (checkSMBhdr
-				     (smb_buffer, smb_buffer->Mid))) {
-					cERROR(1,
-					    ("Invalid size or format for SMB found with length %d and pdu_length %d",
-						length, pdu_length));
-					cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)+3);
-					/* could we fix this network corruption by finding next 
-						smb header (instead of killing the session) and
-						restart reading from next valid SMB found? */
-					cifs_reconnect(server);
-					csocket = server->ssocket;
-					continue;
-				} else {	/* length ok */
+			}
+		} else if (temp[0] != (char) 0) {
+			cERROR(1,("Unknown RFC 1002 frame"));
+			cifs_dump_mem(" Received Data: ", temp, length);
+			cifs_reconnect(server);
+			csocket = server->ssocket;
+			continue;
+		}
 
-					length = 0;
-					iov.iov_base = smb_buffer;
-					iov.iov_len = pdu_length;
-					for (total_read = 0; 
-					     total_read < pdu_length;
-					     total_read += length) {	
-						length = kernel_recvmsg(csocket, &smb_msg, 
-							&iov, 1,
-							pdu_length - total_read, 0);
-						if (length == 0) {
-							cERROR(1,
-							       ("Zero length receive when expecting %d ",
-								pdu_length - total_read));
-							cifs_reconnect(server);
-							csocket = server->ssocket;
-							continue;
-						}
-					}
-				}
+		/* else we have an SMB response */
+		if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+			    (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
+			cERROR(1, ("Invalid size SMB length %d pdu_length %d",
+					length, pdu_length+4));
+			cifs_reconnect(server);
+			csocket = server->ssocket;
+			wake_up(&server->response_q);
+			continue;
+		} 
 
-				dump_smb(smb_buffer, length);
-				if (checkSMB
-				    (smb_buffer, smb_buffer->Mid, total_read)) {
-					cERROR(1, ("Bad SMB Received "));
-					continue;
-				}
+		/* else length ok */
+		reconnect = 0;
 
-				task_to_wake = NULL;
-				spin_lock(&GlobalMid_Lock);
-				list_for_each(tmp, &server->pending_mid_q) {
-					mid_entry = list_entry(tmp, struct
-							       mid_q_entry,
-							       qhead);
+		if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+			isLargeBuf = TRUE;
+			memcpy(bigbuf, smallbuf, 4);
+			smb_buffer = bigbuf;
+		}
+		length = 0;
+		iov.iov_base = 4 + (char *)smb_buffer;
+		iov.iov_len = pdu_length;
+		for (total_read = 0; total_read < pdu_length; 
+		     total_read += length) {
+			length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
+						pdu_length - total_read, 0);
+			if((server->tcpStatus == CifsExiting) ||
+			    (length == -EINTR)) {
+				/* then will exit */
+				reconnect = 2;
+				break;
+			} else if (server->tcpStatus == CifsNeedReconnect) {
+				cifs_reconnect(server);
+				csocket = server->ssocket;
+			        /* Reconnect wakes up rspns q */
+				/* Now we will reread sock */
+				reconnect = 1;
+				break;
+			} else if ((length == -ERESTARTSYS) || 
+				   (length == -EAGAIN)) {
+				msleep(1); /* minimum sleep to prevent looping,
+                                              allowing socket to clear and app 
+					      threads to set tcpStatus
+					      CifsNeedReconnect if server hung*/
+				continue;
+			} else if (length <= 0) {
+				cERROR(1,("Received no data, expecting %d",
+					      pdu_length - total_read));
+				cifs_reconnect(server);
+				csocket = server->ssocket;
+				reconnect = 1;
+				break;
+			}
+		}
+		if(reconnect == 2)
+			break;
+		else if(reconnect == 1)
+			continue;
 
-					if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
-						cFYI(1,
-						     (" Mid 0x%x matched - waking up ",mid_entry->mid));
-						task_to_wake = mid_entry->tsk;
-						mid_entry->resp_buf =
-						    smb_buffer;
-						mid_entry->midState =
-						    MID_RESPONSE_RECEIVED;
+		length += 4; /* account for rfc1002 hdr */
+	
+
+		dump_smb(smb_buffer, length);
+		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+			cERROR(1, ("Bad SMB Received "));
+			continue;
+		}
+
+
+		task_to_wake = NULL;
+		spin_lock(&GlobalMid_Lock);
+		list_for_each(tmp, &server->pending_mid_q) {
+			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+
+			if ((mid_entry->mid == smb_buffer->Mid) && 
+			    (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
+			    (mid_entry->command == smb_buffer->Command)) {
+				if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+					/* We have a multipart transact2 resp */
+					isMultiRsp = TRUE;
+					if(mid_entry->resp_buf) {
+						/* merge response - fix up 1st*/
+						if(coalesce_t2(smb_buffer, 
+							mid_entry->resp_buf)) {
+							break;
+						} else {
+							/* all parts received */
+							goto multi_t2_fnd; 
+						}
+					} else {
+						if(!isLargeBuf) {
+							cERROR(1,("1st trans2 resp needs bigbuf"));
+					/* BB maybe we can fix this up,  switch
+				   	   to already allocated large buffer? */
+						} else {
+							/* Have first buffer */
+							mid_entry->resp_buf =
+								 smb_buffer;
+							mid_entry->largeBuf = 1;
+							bigbuf = NULL;
+						}
 					}
-				}
-				spin_unlock(&GlobalMid_Lock);
-				if (task_to_wake) {
-					smb_buffer = NULL;	/* will be freed by users thread after he is done */
-					wake_up_process(task_to_wake);
-				} else if (is_valid_oplock_break(smb_buffer) == FALSE) {                          
-					cERROR(1, ("No task to wake, unknown frame rcvd!"));
-					cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
-				}
+					break;
+				} 
+				mid_entry->resp_buf = smb_buffer;
+				if(isLargeBuf)
+					mid_entry->largeBuf = 1;
+				else
+					mid_entry->largeBuf = 0;
+multi_t2_fnd:
+				task_to_wake = mid_entry->tsk;
+				mid_entry->midState = MID_RESPONSE_RECEIVED;
+				break;
 			}
-		} else {
-			cFYI(0,
-			     ("Frame less than four bytes received  %d bytes long.",
-			      length));
-			if (length > 0) {
-				length = kernel_recvmsg(csocket, &smb_msg,
-					&iov, 1,
-					length, 0);	/* throw away junk frame */
-				cFYI(1,
-				     (" with junk  0x%x in it ",
-				      *(__u32 *) smb_buffer));
+		}
+		spin_unlock(&GlobalMid_Lock);
+		if (task_to_wake) {
+			/* Was previous buf put in mpx struct for multi-rsp? */
+			if(!isMultiRsp) {
+				/* smb buffer will be freed by user thread */
+				if(isLargeBuf) {
+					bigbuf = NULL;
+				} else
+					smallbuf = NULL;
 			}
+			wake_up_process(task_to_wake);
+		} else if ((is_valid_oplock_break(smb_buffer) == FALSE)
+		    && (isMultiRsp == FALSE)) {                          
+			cERROR(1, ("No task to wake, unknown frame rcvd!"));
+			cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
 		}
-	}
+	} /* end while !EXITING */
+
 	spin_lock(&GlobalMid_Lock);
 	server->tcpStatus = CifsExiting;
 	server->tsk = NULL;
-	atomic_set(&server->inFlight, 0);
+	/* check if we have blocked requests that need to free */
+	/* Note that cifs_max_pending is normally 50, but
+	can be set at module install time to as little as two */
+	if(atomic_read(&server->inFlight) >= cifs_max_pending)
+		atomic_set(&server->inFlight, cifs_max_pending - 1);
+	/* We do not want to set the max_pending too low or we
+	could end up with the counter going negative */
 	spin_unlock(&GlobalMid_Lock);
 	/* Although there should not be any requests blocked on 
 	this queue it can not hurt to be paranoid and try to wake up requests
-	that may haven been blocked when more than 50 at time were on the wire 
+	that may haven been blocked when more than 50 at time were on the wire
 	to the same server - they now will see the session is in exit state
 	and get out of SendReceive.  */
 	wake_up_all(&server->request_q);
 	/* give those requests time to exit */
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(HZ/8);
-
+	msleep(125);
+	
 	if(server->ssocket) {
 		sock_release(csocket);
 		server->ssocket = NULL;
 	}
-	if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
-		cifs_buf_release(smb_buffer);
+	/* buffer usuallly freed in free_mid - need to free it here on exit */
+	if (bigbuf != NULL)
+		cifs_buf_release(bigbuf);
+	if (smallbuf != NULL)
+		cifs_small_buf_release(smallbuf);
 
 	read_lock(&GlobalSMBSeslock);
 	if (list_empty(&server->pending_mid_q)) {
-		/* loop through server session structures attached to this and mark them dead */
+		/* loop through server session structures attached to this and
+		    mark them dead */
 		list_for_each(tmp, &GlobalSMBSessionList) {
 			ses =
 			    list_entry(tmp, struct cifsSesInfo,
@@ -459,12 +645,23 @@ cifs_demultiplex_thread(struct TCP_Serve
 		}
 		read_unlock(&GlobalSMBSeslock);
 	} else {
+		/* although we can not zero the server struct pointer yet,
+		since there are active requests which may depnd on them,
+		mark the corresponding SMB sessions as exiting too */
+		list_for_each(tmp, &GlobalSMBSessionList) {
+			ses = list_entry(tmp, struct cifsSesInfo,
+					 cifsSessionList);
+			if (ses->server == server) {
+				ses->status = CifsExiting;
+			}
+		}
+
 		spin_lock(&GlobalMid_Lock);
 		list_for_each(tmp, &server->pending_mid_q) {
 		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 			if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
 				cFYI(1,
-					 (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+				  ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
 				task_to_wake = mid_entry->tsk;
 				if(task_to_wake) {
 					wake_up_process(task_to_wake);
@@ -473,47 +670,51 @@ cifs_demultiplex_thread(struct TCP_Serve
 		}
 		spin_unlock(&GlobalMid_Lock);
 		read_unlock(&GlobalSMBSeslock);
-		set_current_state(TASK_INTERRUPTIBLE);
 		/* 1/8th of sec is more than enough time for them to exit */
-		schedule_timeout(HZ/8); 
+		msleep(125);
 	}
 
 	if (list_empty(&server->pending_mid_q)) {
 		/* mpx threads have not exited yet give them 
 		at least the smb send timeout time for long ops */
+		/* due to delays on oplock break requests, we need
+		to wait at least 45 seconds before giving up
+		on a request getting a response and going ahead
+		and killing cifsd */
 		cFYI(1, ("Wait for exit from demultiplex thread"));
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(46 * HZ);	
+		msleep(46000);
 		/* if threads still have not exited they are probably never
 		coming home not much else we can do but free the memory */
 	}
-	kfree(server);
 
 	write_lock(&GlobalSMBSeslock);
 	atomic_dec(&tcpSesAllocCount);
 	length = tcpSesAllocCount.counter;
+
+	/* last chance to mark ses pointers invalid
+	if there are any pointing to this (e.g
+	if a crazy root user tried to kill cifsd 
+	kernel thread explicitly this might happen) */
+	list_for_each(tmp, &GlobalSMBSessionList) {
+		ses = list_entry(tmp, struct cifsSesInfo,
+				cifsSessionList);
+		if (ses->server == server) {
+			ses->server = NULL;
+		}
+	}
 	write_unlock(&GlobalSMBSeslock);
+
+	kfree(server);
 	if(length  > 0) {
 		mempool_resize(cifs_req_poolp,
 			length + cifs_min_rcv,
 			GFP_KERNEL);
 	}
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(HZ/4);
+	
+	msleep(250);
 	return 0;
 }
 
-static void * 
-cifs_kcalloc(size_t size, int type)
-{
-	void *addr;
-	addr = kmalloc(size, type);
-	if (addr)
-		memset(addr, 0, size);
-	return addr;
-}
-
 static int
 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 {
@@ -530,7 +731,8 @@ cifs_parse_mount_options(char *options, 
 		/* does not have to be a perfect mapping since the field is
 		informational, only used for servers that do not support
 		port 445 and it can be overridden at mount time */
-		vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+		vol->source_rfc1001_name[i] = 
+			toupper(system_utsname.nodename[i]);
 	}
 	vol->source_rfc1001_name[15] = 0;
 
@@ -560,7 +762,12 @@ cifs_parse_mount_options(char *options, 
 			continue;
 		if ((value = strchr(data, '=')) != NULL)
 			*value++ = '\0';
-		if (strnicmp(data, "user", 4) == 0) {
+
+		if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
+			vol->no_xattr = 0;
+		} else if (strnicmp(data, "nouser_xattr",12) == 0) {
+			vol->no_xattr = 1;
+		} else if (strnicmp(data, "user", 4) == 0) {
 			if (!value || !*value) {
 				printk(KERN_WARNING
 				       "CIFS: invalid or missing username\n");
@@ -573,9 +780,18 @@ cifs_parse_mount_options(char *options, 
 				return 1;
 			}
 		} else if (strnicmp(data, "pass", 4) == 0) {
-			if (!value || !*value) {
+			if (!value) {
 				vol->password = NULL;
 				continue;
+			} else if(value[0] == 0) {
+				/* check if string begins with double comma
+				   since that would mean the password really
+				   does start with a comma, and would not
+				   indicate an empty string */
+				if(value[1] != separator[0]) {
+					vol->password = NULL;
+					continue;
+				}
 			}
 			temp_len = strlen(value);
 			/* removed password length check, NTLM passwords
@@ -590,15 +806,23 @@ cifs_parse_mount_options(char *options, 
 
 			/* NB: password legally can have multiple commas and
 			the only illegal character in a password is null */
-				
-			if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+
+			if ((value[temp_len] == 0) && 
+			    (value[temp_len+1] == separator[0])) {
 				/* reinsert comma */
 				value[temp_len] = separator[0];
 				temp_len+=2;  /* move after the second comma */
 				while(value[temp_len] != 0)  {
-					if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
-						/* single comma indicating start of next parm */
-						break;
+					if (value[temp_len] == separator[0]) {
+						if (value[temp_len+1] == 
+						     separator[0]) {
+						/* skip second comma */
+							temp_len++;
+						} else { 
+						/* single comma indicating start
+							 of next parm */
+							break;
+						}
 					}
 					temp_len++;
 				}
@@ -606,22 +830,32 @@ cifs_parse_mount_options(char *options, 
 					options = NULL;
 				} else {
 					value[temp_len] = 0;
-					/* move options to point to start of next parm */
+					/* point option to start of next parm */
 					options = value + temp_len + 1;
 				}
-				/* go from value to (value + temp_len) condensing double commas to singles */
-				vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
+				/* go from value to value + temp_len condensing 
+				double commas to singles. Note that this ends up
+				allocating a few bytes too many, which is ok */
+				vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+				if(vol->password == NULL) {
+					printk("CIFS: no memory for pass\n");
+					return 1;
+				}
 				for(i=0,j=0;i<temp_len;i++,j++) {
 					vol->password[j] = value[i];
-					if(value[i] == separator[0] && value[i+1] == separator[0]) {
+					if(value[i] == separator[0]
+						&& value[i+1] == separator[0]) {
 						/* skip second comma */
 						i++;
 					}
 				}
-				/* value[temp_len] is zeroed above so
-					 vol->password[temp_len] guaranteed to be null */
+				vol->password[j] = 0;
 			} else {
-				vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
+				vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+				if(vol->password == NULL) {
+					printk("CIFS: no memory for pass\n");
+					return 1;
+				}
 				strcpy(vol->password, value);
 			}
 		} else if (strnicmp(data, "ip", 2) == 0) {
@@ -785,6 +1019,10 @@ cifs_parse_mount_options(char *options, 
 			vol->noperm = 0;
 		} else if (strnicmp(data, "noperm", 6) == 0) {
 			vol->noperm = 1;
+		} else if (strnicmp(data, "mapchars", 8) == 0) {
+			vol->remap = 1;
+		} else if (strnicmp(data, "nomapchars", 10) == 0) {
+			vol->remap = 0;
 		} else if (strnicmp(data, "setuids", 7) == 0) {
 			vol->setuids = 1;
 		} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -845,7 +1083,7 @@ cifs_parse_mount_options(char *options, 
 			return 1;
 		}
 	}
-	if(vol->UNCip == 0)
+	if(vol->UNCip == NULL)
 		vol->UNCip = &vol->UNC[2];
 
 	return 0;
@@ -933,14 +1171,15 @@ find_unc(__be32 new_target_ip_addr, char
 
 int
 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-		    const char *old_path, const struct nls_table *nls_codepage)
+		    const char *old_path, const struct nls_table *nls_codepage,
+		    int remap)
 {
 	unsigned char *referrals = NULL;
 	unsigned int num_referrals;
 	int rc = 0;
 
 	rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
-			&num_referrals, &referrals);
+			&num_referrals, &referrals, remap);
 
 	/* BB Add in code to: if valid refrl, if not ip address contact
 		the helper that resolves tcp names, mount to it, try to 
@@ -955,7 +1194,8 @@ connect_to_dfs_path(int xid, struct cifs
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			const char *old_path, const struct nls_table *nls_codepage, 
-			unsigned int *pnum_referrals, unsigned char ** preferrals)
+			unsigned int *pnum_referrals, 
+			unsigned char ** preferrals, int remap)
 {
 	char *temp_unc;
 	int rc = 0;
@@ -980,7 +1220,7 @@ get_dfs_path(int xid, struct cifsSesInfo
 	}
 	if (rc == 0)
 		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
-				     pnum_referrals, nls_codepage);
+				     pnum_referrals, nls_codepage, remap);
 
 	return rc;
 }
@@ -1077,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_se
 		sessinit is sent but no second negprot */
 		struct rfc1002_session_packet * ses_init_buf;
 		struct smb_hdr * smb_buf;
-		ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+		ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
 		if(ses_init_buf) {
 			ses_init_buf->trailer.session_req.called_len = 32;
 			rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1212,6 +1452,7 @@ cifs_mount(struct super_block *sb, struc
 	}
 
 	if (volume_info.username) {
+		/* BB fixme parse for domain name here */
 		cFYI(1, ("Username: %s ", volume_info.username));
 
 	} else {
@@ -1366,6 +1607,7 @@ cifs_mount(struct super_block *sb, struc
 			} else
 				rc = 0;
 			memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+			srvTcp->sequence_number = 0;
 		}
 	}
 
@@ -1409,14 +1651,14 @@ cifs_mount(struct super_block *sb, struc
     
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+		if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
 			cifs_sb->rsize = volume_info.rsize;
 		else
 			cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
-		if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+		if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
 			cifs_sb->wsize = volume_info.wsize;
 		else
-			cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+			cifs_sb->wsize = CIFSMaxBufSize; /* default */
 		if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
 			cifs_sb->rsize = PAGE_CACHE_SIZE;
 			cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
@@ -1433,6 +1675,10 @@ cifs_mount(struct super_block *sb, struc
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
 		if(volume_info.server_ino)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+		if(volume_info.remap)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+		if(volume_info.no_xattr)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
 		if(volume_info.direct_io) {
 			cERROR(1,("mounting share using direct i/o"));
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -1459,11 +1705,10 @@ cifs_mount(struct super_block *sb, struc
 				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
 				    && (strchr(volume_info.UNC + 3, '/') ==
 					NULL)) {
-					rc = connect_to_dfs_path(xid,
-								 pSesInfo,
-								 "",
-								 cifs_sb->
-								 local_nls);
+					rc = connect_to_dfs_path(xid, pSesInfo,
+							"", cifs_sb->local_nls,
+							cifs_sb->mnt_cifs_flags & 
+							  CIFS_MOUNT_MAP_SPECIAL_CHR);
 					if(volume_info.UNC)
 						kfree(volume_info.UNC);
 					FreeXid(xid);
@@ -1504,7 +1749,7 @@ cifs_mount(struct super_block *sb, struc
 		 /* If find_unc succeeded then rc == 0 so we can not end */
 		if (tcon)  /* up accidently freeing someone elses tcon struct */
 			tconInfoFree(tcon);
-		if (existingCifsSes == 0) {
+		if (existingCifsSes == NULL) {
 			if (pSesInfo) {
 				if ((pSesInfo->server) && 
 				    (pSesInfo->status == CifsGood)) {
@@ -1526,10 +1771,10 @@ cifs_mount(struct super_block *sb, struc
 		tcon->ses = pSesInfo;
 
 		/* do not care if following two calls succeed - informational only */
-		CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
-		CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
+		CIFSSMBQFSDeviceInfo(xid, tcon);
+		CIFSSMBQFSAttributeInfo(xid, tcon);
 		if (tcon->ses->capabilities & CAP_UNIX) {
-			if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
+			if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
 				if(!volume_info.no_psx_acl) {
 					if(CIFS_UNIX_POSIX_ACL_CAP & 
 					   le64_to_cpu(tcon->fsUnixInfo.Capability))
@@ -1575,7 +1820,7 @@ CIFSSessSetup(unsigned int xid, struct c
 	user = ses->userName;
 	domain = ses->domainName;
 	smb_buffer = cifs_buf_get();
-	if (smb_buffer == 0) {
+	if (smb_buffer == NULL) {
 		return -ENOMEM;
 	}
 	smb_buffer_response = smb_buffer;
@@ -1592,7 +1837,8 @@ CIFSSessSetup(unsigned int xid, struct c
 	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
 		smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+		CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 	if (ses->capabilities & CAP_UNICODE) {
 		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
 		capabilities |= CAP_UNICODE;
@@ -1619,7 +1865,7 @@ CIFSSessSetup(unsigned int xid, struct c
 	bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
 	if (ses->capabilities & CAP_UNICODE) {
-		if ((long) bcc_ptr % 2) {	/* must be word aligned for Unicode */
+		if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
@@ -1629,7 +1875,8 @@ CIFSSessSetup(unsigned int xid, struct c
 			bytes_returned =
 			        cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
 					nls_codepage);
-		bcc_ptr += 2 * bytes_returned;	/* convert num 16 bit words to bytes */
+		/* convert number of 16 bit words to bytes */
+		bcc_ptr += 2 * bytes_returned;
 		bcc_ptr += 2;	/* trailing null */
 		if (domain == NULL)
 			bytes_returned =
@@ -1646,8 +1893,8 @@ CIFSSessSetup(unsigned int xid, struct c
 				  32, nls_codepage);
 		bcc_ptr += 2 * bytes_returned;
 		bytes_returned =
-		    cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
-				  nls_codepage);
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
+				  32, nls_codepage);
 		bcc_ptr += 2 * bytes_returned;
 		bcc_ptr += 2;
 		bytes_returned =
@@ -1717,7 +1964,9 @@ CIFSSessSetup(unsigned int xid, struct c
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-				ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+				ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+				if(ses->serverOS == NULL)
+					goto sesssetup_nomem;
 				cifs_strfromUCS_le(ses->serverOS,
 					   (wchar_t *)bcc_ptr, len,nls_codepage);
 				bcc_ptr += 2 * (len + 1);
@@ -1727,18 +1976,27 @@ CIFSSessSetup(unsigned int xid, struct c
 				if (remaining_words > 0) {
 					len = UniStrnlen((wchar_t *)bcc_ptr,
 							 remaining_words-1);
-					ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
+					ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+					if(ses->serverNOS == NULL)
+						goto sesssetup_nomem;
 					cifs_strfromUCS_le(ses->serverNOS,
 							   (wchar_t *)bcc_ptr,len,nls_codepage);
 					bcc_ptr += 2 * (len + 1);
 					ses->serverNOS[2 * len] = 0;
 					ses->serverNOS[1 + (2 * len)] = 0;
+					if(strncmp(ses->serverNOS,
+						"NT LAN Manager 4",16) == 0) {
+						cFYI(1,("NT4 server"));
+						ses->flags |= CIFS_SES_NT4;
+					}
 					remaining_words -= len + 1;
 					if (remaining_words > 0) {
-						len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
+						len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
 						ses->serverDomain =
-						    cifs_kcalloc(2*(len+1),GFP_KERNEL);
+						    kcalloc(1, 2*(len+1),GFP_KERNEL);
+						if(ses->serverDomain == NULL)
+							goto sesssetup_nomem;
 						cifs_strfromUCS_le(ses->serverDomain,
 						     (wchar_t *)bcc_ptr,len,nls_codepage);
 						bcc_ptr += 2 * (len + 1);
@@ -1746,21 +2004,25 @@ CIFSSessSetup(unsigned int xid, struct c
 						ses->serverDomain[1+(2*len)] = 0;
 					} /* else no more room so create dummy domain string */
 					else
-						ses->serverDomain =
-						    cifs_kcalloc(2,
-							    GFP_KERNEL);
+						ses->serverDomain = 
+							kcalloc(1, 2, GFP_KERNEL);
 				} else {	/* no room so create dummy domain and NOS string */
+					/* if these kcallocs fail not much we
+					   can do, but better to not fail the
+					   sesssetup itself */
 					ses->serverDomain =
-					    cifs_kcalloc(2, GFP_KERNEL);
+					    kcalloc(1, 2, GFP_KERNEL);
 					ses->serverNOS =
-					    cifs_kcalloc(2, GFP_KERNEL);
+					    kcalloc(1, 2, GFP_KERNEL);
 				}
 			} else {	/* ASCII */
 				len = strnlen(bcc_ptr, 1024);
 				if (((long) bcc_ptr + len) - (long)
 				    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
-					ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+					ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+					if(ses->serverOS == NULL)
+						goto sesssetup_nomem;
 					strncpy(ses->serverOS,bcc_ptr, len);
 
 					bcc_ptr += len;
@@ -1768,14 +2030,18 @@ CIFSSessSetup(unsigned int xid, struct c
 					bcc_ptr++;
 
 					len = strnlen(bcc_ptr, 1024);
-					ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+					ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+					if(ses->serverNOS == NULL)
+						goto sesssetup_nomem;
 					strncpy(ses->serverNOS, bcc_ptr, len);
 					bcc_ptr += len;
 					bcc_ptr[0] = 0;
 					bcc_ptr++;
 
 					len = strnlen(bcc_ptr, 1024);
-					ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
+					ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+					if(ses->serverDomain == NULL)
+						goto sesssetup_nomem;
 					strncpy(ses->serverDomain, bcc_ptr, len);
 					bcc_ptr += len;
 					bcc_ptr[0] = 0;
@@ -1795,7 +2061,9 @@ CIFSSessSetup(unsigned int xid, struct c
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
-	
+sesssetup_nomem:	/* do not return an error on nomem for the info strings,
+			   since that could make reconnection harder, and
+			   reconnection might be needed to free memory */
 	if (smb_buffer)
 		cifs_buf_release(smb_buffer);
 
@@ -1828,7 +2096,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 	domain = ses->domainName;
 
 	smb_buffer = cifs_buf_get();
-	if (smb_buffer == 0) {
+	if (smb_buffer == NULL) {
 		return -ENOMEM;
 	}
 	smb_buffer_response = smb_buffer;
@@ -1972,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
 					ses->serverOS =
-					    cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+					    kcalloc(1, 2 * (len + 1), GFP_KERNEL);
 					cifs_strfromUCS_le(ses->serverOS,
 							   (wchar_t *)
 							   bcc_ptr, len,
@@ -1986,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 								 remaining_words
 								 - 1);
 						ses->serverNOS =
-						    cifs_kcalloc(2 * (len + 1),
+						    kcalloc(1, 2 * (len + 1),
 							    GFP_KERNEL);
 						cifs_strfromUCS_le(ses->serverNOS,
 								   (wchar_t *)bcc_ptr,
@@ -1999,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 						if (remaining_words > 0) {
 							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-							ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
+							ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
 							cifs_strfromUCS_le(ses->serverDomain,
 							     (wchar_t *)bcc_ptr, 
                                  len,
@@ -2010,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 						} /* else no more room so create dummy domain string */
 						else
 							ses->serverDomain =
-							    cifs_kcalloc(2,GFP_KERNEL);
+							    kcalloc(1, 2,GFP_KERNEL);
 					} else {	/* no room so create dummy domain and NOS string */
-						ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
-						ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+						ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+						ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
 					}
 				} else {	/* ASCII */
 
@@ -2021,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 					if (((long) bcc_ptr + len) - (long)
 					    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
-						ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
+						ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
 						strncpy(ses->serverOS, bcc_ptr, len);
 
 						bcc_ptr += len;
@@ -2029,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, st
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
-						ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+						ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
 						strncpy(ses->serverNOS, bcc_ptr, len);
 						bcc_ptr += len;
 						bcc_ptr[0] = 0;
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
-						ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
+						ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
 						strncpy(ses->serverDomain, bcc_ptr, len);
 						bcc_ptr += len;
 						bcc_ptr[0] = 0;
@@ -2093,7 +2361,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 	domain = ses->domainName;
 	*pNTLMv2_flag = FALSE;
 	smb_buffer = cifs_buf_get();
-	if (smb_buffer == 0) {
+	if (smb_buffer == NULL) {
 		return -ENOMEM;
 	}
 	smb_buffer_response = smb_buffer;
@@ -2286,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
 					ses->serverOS =
-					    cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+					    kcalloc(1, 2 * (len + 1), GFP_KERNEL);
 					cifs_strfromUCS_le(ses->serverOS,
 							   (wchar_t *)
 							   bcc_ptr, len,
@@ -2301,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 								 remaining_words
 								 - 1);
 						ses->serverNOS =
-						    cifs_kcalloc(2 * (len + 1),
+						    kcalloc(1, 2 * (len + 1),
 							    GFP_KERNEL);
 						cifs_strfromUCS_le(ses->
 								   serverNOS,
@@ -2318,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
 							ses->serverDomain =
-							    cifs_kcalloc(2 *
+							    kcalloc(1, 2 *
 								    (len +
 								     1),
 								    GFP_KERNEL);
@@ -2344,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 						} /* else no more room so create dummy domain string */
 						else
 							ses->serverDomain =
-							    cifs_kcalloc(2,
+							    kcalloc(1, 2,
 								    GFP_KERNEL);
 					} else {	/* no room so create dummy domain and NOS string */
 						ses->serverDomain =
-						    cifs_kcalloc(2, GFP_KERNEL);
+						    kcalloc(1, 2, GFP_KERNEL);
 						ses->serverNOS =
-						    cifs_kcalloc(2, GFP_KERNEL);
+						    kcalloc(1, 2, GFP_KERNEL);
 					}
 				} else {	/* ASCII */
 					len = strnlen(bcc_ptr, 1024);
@@ -2358,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 					    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
 						ses->serverOS =
-						    cifs_kcalloc(len + 1,
+						    kcalloc(1, len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverOS,
 							bcc_ptr, len);
@@ -2369,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 
 						len = strnlen(bcc_ptr, 1024);
 						ses->serverNOS =
-						    cifs_kcalloc(len + 1,
+						    kcalloc(1, len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverNOS, bcc_ptr, len);
 						bcc_ptr += len;
@@ -2378,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
 
 						len = strnlen(bcc_ptr, 1024);
 						ses->serverDomain =
-						    cifs_kcalloc(len + 1,
+						    kcalloc(1, len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverDomain, bcc_ptr, len);	
 						bcc_ptr += len;
@@ -2435,7 +2703,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
 	user = ses->userName;
 	domain = ses->domainName;
 	smb_buffer = cifs_buf_get();
-	if (smb_buffer == 0) {
+	if (smb_buffer == NULL) {
 		return -ENOMEM;
 	}
 	smb_buffer_response = smb_buffer;
@@ -2680,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
 					ses->serverOS =
-					    cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+					    kcalloc(1, 2 * (len + 1), GFP_KERNEL);
 					cifs_strfromUCS_le(ses->serverOS,
 							   (wchar_t *)
 							   bcc_ptr, len,
@@ -2695,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
 								 remaining_words
 								 - 1);
 						ses->serverNOS =
-						    cifs_kcalloc(2 * (len + 1),
+						    kcalloc(1, 2 * (len + 1),
 							    GFP_KERNEL);
 						cifs_strfromUCS_le(ses->
 								   serverNOS,
@@ -2711,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
 							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
 							ses->serverDomain =
-							    cifs_kcalloc(2 *
+							    kcalloc(1, 2 *
 								    (len +
 								     1),
 								    GFP_KERNEL);
@@ -2736,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
 							    = 0;
 						} /* else no more room so create dummy domain string */
 						else
-							ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+							ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
 					} else {  /* no room so create dummy domain and NOS string */
-						ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
-						ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+						ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+						ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
 					}
 				} else {	/* ASCII */
 					len = strnlen(bcc_ptr, 1024);
 					if (((long) bcc_ptr + len) - 
                         (long) pByteArea(smb_buffer_response) 
                             <= BCC(smb_buffer_response)) {
-						ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+						ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
 						strncpy(ses->serverOS,bcc_ptr, len);
 
 						bcc_ptr += len;
@@ -2754,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
-						ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+						ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
 						strncpy(ses->serverNOS, bcc_ptr, len);	
 						bcc_ptr += len;
 						bcc_ptr[0] = 0;
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
-						ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
+						ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
 						strncpy(ses->serverDomain, bcc_ptr, len);
 						bcc_ptr += len;
 						bcc_ptr[0] = 0;
@@ -2809,7 +3077,7 @@ CIFSTCon(unsigned int xid, struct cifsSe
 		return -EIO;
 
 	smb_buffer = cifs_buf_get();
-	if (smb_buffer == 0) {
+	if (smb_buffer == NULL) {
 		return -ENOMEM;
 	}
 	smb_buffer_response = smb_buffer;
@@ -2873,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSe
 				if(tcon->nativeFileSystem)
 					kfree(tcon->nativeFileSystem);
 				tcon->nativeFileSystem =
-				    cifs_kcalloc(length + 2, GFP_KERNEL);
+				    kcalloc(1, length + 2, GFP_KERNEL);
 				cifs_strfromUCS_le(tcon->nativeFileSystem,
 						   (wchar_t *) bcc_ptr,
 						   length, nls_codepage);
@@ -2891,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSe
 				if(tcon->nativeFileSystem)
 					kfree(tcon->nativeFileSystem);
 				tcon->nativeFileSystem =
-				    cifs_kcalloc(length + 1, GFP_KERNEL);
+				    kcalloc(1, length + 1, GFP_KERNEL);
 				strncpy(tcon->nativeFileSystem, bcc_ptr,
 					length);
 			}
@@ -2937,7 +3205,8 @@ cifs_umount(struct super_block *sb, stru
 				return 0;
 			} else if (rc == -ESHUTDOWN) {
 				cFYI(1,("Waking up socket by sending it signal"));
-				send_sig(SIGKILL,cifsd_task,1);
+				if(cifsd_task)
+					send_sig(SIGKILL,cifsd_task,1);
 				rc = 0;
 			} /* else - we have an smb session
 				left on this socket do not kill cifsd */
@@ -2963,6 +3232,7 @@ int cifs_setup_session(unsigned int xid,
 	int rc = 0;
 	char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
 	int ntlmv2_flag = FALSE;
+	int first_time = 0;
 
 	/* what if server changes its buffer size after dropping the session? */
 	if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
@@ -2981,12 +3251,13 @@ int cifs_setup_session(unsigned int xid,
 			spin_unlock(&GlobalMid_Lock);
 
 		}
+		first_time = 1;
 	}
 	if (!rc) {
 		pSesInfo->capabilities = pSesInfo->server->capabilities;
 		if(linuxExtEnabled == 0)
 			pSesInfo->capabilities &= (~CAP_UNIX);
-		pSesInfo->sequence_number = 0;
+	/*	pSesInfo->sequence_number = 0;*/
 		cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
 			pSesInfo->server->secMode,
 			pSesInfo->server->capabilities,
@@ -3011,25 +3282,35 @@ int cifs_setup_session(unsigned int xid,
 				if(ntlmv2_flag) {
 					char * v2_response;
 					cFYI(1,("Can use more secure NTLM version 2 password hash"));
-					CalcNTLMv2_partial_mac_key(pSesInfo, 
-						nls_info);
-					v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
+					if(CalcNTLMv2_partial_mac_key(pSesInfo, 
+						nls_info)) {
+						rc = -ENOMEM;
+						goto ss_err_exit;
+					} else
+						v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
 					if(v2_response) {
 						CalcNTLMv2_response(pSesInfo,v2_response);
-/*						cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+				/*		if(first_time)
+							cifs_calculate_ntlmv2_mac_key(
+							  pSesInfo->server->mac_signing_key, 
+							  response, ntlm_session_key, */
 						kfree(v2_response);
 					/* BB Put dummy sig in SessSetup PDU? */
-					} else
+					} else {
 						rc = -ENOMEM;
+						goto ss_err_exit;
+					}
 
 				} else {
 					SMBNTencrypt(pSesInfo->password,
 						pSesInfo->server->cryptKey,
 						ntlm_session_key);
 
-					cifs_calculate_mac_key(pSesInfo->mac_signing_key,
-						ntlm_session_key,
-						pSesInfo->password);
+					if(first_time)
+						cifs_calculate_mac_key(
+							pSesInfo->server->mac_signing_key,
+							ntlm_session_key,
+							pSesInfo->password);
 				}
 			/* for better security the weaker lanman hash not sent
 			   in AuthSessSetup so we no longer calculate it */
@@ -3045,8 +3326,11 @@ int cifs_setup_session(unsigned int xid,
 				pSesInfo->server->cryptKey,
 				ntlm_session_key);
 
-			cifs_calculate_mac_key(pSesInfo->mac_signing_key, 
-				ntlm_session_key, pSesInfo->password);
+			if(first_time) 		
+				cifs_calculate_mac_key(
+					pSesInfo->server->mac_signing_key,
+					ntlm_session_key, pSesInfo->password);
+
 			rc = CIFSSessSetup(xid, pSesInfo,
 				ntlm_session_key, nls_info);
 		}
@@ -3057,6 +3341,7 @@ int cifs_setup_session(unsigned int xid,
 			pSesInfo->status = CifsGood;
 		}
 	}
+ss_err_exit:
 	return rc;
 }
 
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -101,68 +101,15 @@ cifs_bp_rename_retry:
 	return full_path;
 }
 
-/* Note: caller must free return buffer */
-char *
-build_wildcard_path_from_dentry(struct dentry *direntry)
+/* char * build_wildcard_path_from_dentry(struct dentry *direntry)
 {
-	struct dentry *temp;
-	int namelen = 0;
-	char *full_path;
-
-	if(direntry == NULL)
-		return NULL;  /* not much we can do if dentry is freed and
-		we need to reopen the file after it was closed implicitly
-		when the server crashed */
-
-cifs_bwp_rename_retry:
-	for (temp = direntry; !IS_ROOT(temp);) {
-		namelen += (1 + temp->d_name.len);
-		temp = temp->d_parent;
-		if(temp == NULL) {
-			cERROR(1,("corrupt dentry"));
-			return NULL;
-		}
-	}
-
-	full_path = kmalloc(namelen+3, GFP_KERNEL);
 	if(full_path == NULL)
 		return full_path;
 
 	full_path[namelen] = '\\';
 	full_path[namelen+1] = '*';
-	full_path[namelen+2] = 0;  /* trailing null */
-
-	for (temp = direntry; !IS_ROOT(temp);) {
-		namelen -= 1 + temp->d_name.len;
-		if (namelen < 0) {
-			break;
-		} else {
-			full_path[namelen] = '\\';
-			strncpy(full_path + namelen + 1, temp->d_name.name,
-				temp->d_name.len);
-			cFYI(0, (" name: %s ", full_path + namelen));
-		}
-		temp = temp->d_parent;
-		if(temp == NULL) {
-			cERROR(1,("corrupt dentry"));
-			kfree(full_path);
-			return NULL;
-		}
-	}
-	if (namelen != 0) {
-		cERROR(1,
-		       ("We did not end path lookup where we expected namelen is %d",
-			namelen));
-		/* presumably this is only possible if we were racing with a rename 
-		of one of the parent directories  (we can not lock the dentries
-		above us to prevent this, but retrying should be harmless) */
-		kfree(full_path);
-		namelen = 0;
-		goto cifs_bwp_rename_retry;
-	}
-
-	return full_path;
-}
+	full_path[namelen+2] = 0;
+BB remove above eight lines BB */
 
 /* Inode operations in similar order to how they appear in the Linux file fs.h */
 
@@ -235,7 +182,8 @@ cifs_create(struct inode *inode, struct 
 
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
 			 desiredAccess, CREATE_NOT_DIR,
-			 &fileHandle, &oplock, buf, cifs_sb->local_nls);
+			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, ("cifs_create returned 0x%x ", rc));
 	} else {
@@ -248,13 +196,17 @@ cifs_create(struct inode *inode, struct 
 					(__u64)current->euid,
 					(__u64)current->egid,
 					0 /* dev */,
-					cifs_sb->local_nls);
+					cifs_sb->local_nls, 
+					cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			} else {
 				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
 					(__u64)-1,
 					(__u64)-1,
 					0 /* dev */,
-					cifs_sb->local_nls);
+					cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
 		else {
 			/* BB implement via Windows security descriptors */
@@ -284,51 +236,48 @@ cifs_create(struct inode *inode, struct 
 			/* mknod case - do not leave file open */
 			CIFSSMBClose(xid, pTcon, fileHandle);
 		} else if(newinode) {
-			pCifsFile = (struct cifsFileInfo *)
+			pCifsFile =
 			   kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
-		
-			if (pCifsFile) {
-				memset((char *)pCifsFile, 0,
-				       sizeof (struct cifsFileInfo));
-				pCifsFile->netfid = fileHandle;
-				pCifsFile->pid = current->tgid;
-				pCifsFile->pInode = newinode;
-				pCifsFile->invalidHandle = FALSE;
-				pCifsFile->closePend     = FALSE;
-				init_MUTEX(&pCifsFile->fh_sem);
-				/* put the following in at open now */
-				/* pCifsFile->pfile = file; */ 
-				write_lock(&GlobalSMBSeslock);
-				list_add(&pCifsFile->tlist,&pTcon->openFileList);
-				pCifsInode = CIFS_I(newinode);
-				if(pCifsInode) {
+			
+			if(pCifsFile == NULL)
+				goto cifs_create_out;
+			memset((char *)pCifsFile, 0,
+			       sizeof (struct cifsFileInfo));
+			pCifsFile->netfid = fileHandle;
+			pCifsFile->pid = current->tgid;
+			pCifsFile->pInode = newinode;
+			pCifsFile->invalidHandle = FALSE;
+			pCifsFile->closePend     = FALSE;
+			init_MUTEX(&pCifsFile->fh_sem);
+			/* set the following in open now 
+				pCifsFile->pfile = file; */
+			write_lock(&GlobalSMBSeslock);
+			list_add(&pCifsFile->tlist,&pTcon->openFileList);
+			pCifsInode = CIFS_I(newinode);
+			if(pCifsInode) {
 				/* if readable file instance put first in list*/
-					if (write_only == TRUE) {
-                                        	list_add_tail(&pCifsFile->flist,
-							&pCifsInode->openFileList);
-					} else {
-						list_add(&pCifsFile->flist,
-							&pCifsInode->openFileList);
-					}
-					if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-						pCifsInode->clientCanCacheAll = TRUE;
-						pCifsInode->clientCanCacheRead = TRUE;
-						cFYI(1,("Exclusive Oplock granted on inode %p",
-							newinode));
-					} else if((oplock & 0xF) == OPLOCK_READ)
-						pCifsInode->clientCanCacheRead = TRUE;
+				if (write_only == TRUE) {
+                                       	list_add_tail(&pCifsFile->flist,
+						&pCifsInode->openFileList);
+				} else {
+					list_add(&pCifsFile->flist,
+						&pCifsInode->openFileList);
 				}
-				write_unlock(&GlobalSMBSeslock);
+				if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+					pCifsInode->clientCanCacheAll = TRUE;
+					pCifsInode->clientCanCacheRead = TRUE;
+					cFYI(1,("Exclusive Oplock for inode %p",
+						newinode));
+				} else if((oplock & 0xF) == OPLOCK_READ)
+					pCifsInode->clientCanCacheRead = TRUE;
 			}
+			write_unlock(&GlobalSMBSeslock);
 		}
 	} 
-
-	if (buf)
-	    kfree(buf);
-	if (full_path)
-	    kfree(full_path);
+cifs_create_out:
+	kfree(buf);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
@@ -359,11 +308,15 @@ int cifs_mknod(struct inode *inode, stru
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 			rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
 				mode,(__u64)current->euid,(__u64)current->egid,
-				device_number, cifs_sb->local_nls);
+				device_number, cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 		} else {
 			rc = CIFSSMBUnixSetPerms(xid, pTcon,
 				full_path, mode, (__u64)-1, (__u64)-1,
-				device_number, cifs_sb->local_nls);
+				device_number, cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 		}
 
 		if(!rc) {
@@ -375,10 +328,8 @@ int cifs_mknod(struct inode *inode, stru
 		}
 	}
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
@@ -441,49 +392,18 @@ cifs_lookup(struct inode *parent_dir_ino
 		rc = 0;
 		d_add(direntry, NULL);
 	} else {
-		cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
+		cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s",
+			   rc,full_path));
 		/* BB special case check for Access Denied - watch security 
 		exposure of returning dir info implicitly via different rc 
 		if file exists or not but no access BB */
 	}
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return ERR_PTR(rc);
 }
 
-int
-cifs_dir_open(struct inode *inode, struct file *file)
-{				/* NB: currently unused since searches are opened in readdir */
-	int rc = 0;
-	int xid;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
-	char *full_path = NULL;
-
-	xid = GetXid();
-
-	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
-
-	if(file->f_dentry) {
-		down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-		full_path = build_wildcard_path_from_dentry(file->f_dentry);
-		up(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	} else {
-		FreeXid(xid);
-		return -EIO;
-	}
-
-	cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
-
-	if (full_path)
-		kfree(full_path);
-	FreeXid(xid);
-	return rc;
-}
-
 static int
 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 {
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -27,8 +27,9 @@
 #include "cifsproto.h"
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
+#include "cifsfs.h"
 
-__u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
+static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
 {
 	__u32 cifs_ntfy_flags = 0;
 
@@ -91,7 +92,8 @@ int cifs_dir_notify(struct file * file, 
 		cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
 		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
 			GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
-			&netfid, &oplock,NULL, cifs_sb->local_nls);
+			&netfid, &oplock,NULL, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 		/* BB fixme - add this handle to a notify handle list */
 		if(rc) {
 			cERROR(1,("Could not open directory for notify"));  /* BB remove BB */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -35,10 +35,117 @@
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
 
-extern int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir); /* BB removeme BB */
+static inline struct cifsFileInfo *cifs_init_private(
+	struct cifsFileInfo *private_data, struct inode *inode,
+	struct file *file, __u16 netfid)
+{
+	memset(private_data, 0, sizeof(struct cifsFileInfo));
+	private_data->netfid = netfid;
+	private_data->pid = current->tgid;	
+	init_MUTEX(&private_data->fh_sem);
+	private_data->pfile = file; /* needed for writepage */
+	private_data->pInode = inode;
+	private_data->invalidHandle = FALSE;
+	private_data->closePend = FALSE;
+
+	return private_data;
+}
+
+static inline int cifs_convert_flags(unsigned int flags)
+{
+	if ((flags & O_ACCMODE) == O_RDONLY)
+		return GENERIC_READ;
+	else if ((flags & O_ACCMODE) == O_WRONLY)
+		return GENERIC_WRITE;
+	else if ((flags & O_ACCMODE) == O_RDWR) {
+		/* GENERIC_ALL is too much permission to request
+		   can cause unnecessary access denied on create */
+		/* return GENERIC_ALL; */
+		return (GENERIC_READ | GENERIC_WRITE);
+	}
+
+	return 0x20197;
+}
+
+static inline int cifs_get_disposition(unsigned int flags)
+{
+	if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+		return FILE_CREATE;
+	else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+		return FILE_OVERWRITE_IF;
+	else if ((flags & O_CREAT) == O_CREAT)
+		return FILE_OPEN_IF;
+	else
+		return FILE_OPEN;
+}
+
+/* all arguments to this function must be checked for validity in caller */
+static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
+	struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
+	struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
+	char *full_path, int xid)
+{
+	struct timespec temp;
+	int rc;
+
+	/* want handles we can use to read with first
+	   in the list so we do not have to walk the
+	   list to search for one in prepare_write */
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		list_add_tail(&pCifsFile->flist, 
+			      &pCifsInode->openFileList);
+	} else {
+		list_add(&pCifsFile->flist,
+			 &pCifsInode->openFileList);
+	}
+	write_unlock(&GlobalSMBSeslock);
+	write_unlock(&file->f_owner.lock);
+	if (pCifsInode->clientCanCacheRead) {
+		/* we have the inode open somewhere else
+		   no need to discard cache data */
+		goto client_can_cache;
+	}
+
+	/* BB need same check in cifs_create too? */
+	/* if not oplocked, invalidate inode pages if mtime or file
+	   size changed */
+	temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
+	if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) && 
+			   (file->f_dentry->d_inode->i_size == 
+			    (loff_t)le64_to_cpu(buf->EndOfFile))) {
+		cFYI(1, ("inode unchanged on server"));
+	} else {
+		if (file->f_dentry->d_inode->i_mapping) {
+		/* BB no need to lock inode until after invalidate
+		   since namei code should already have it locked? */
+			filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
+			filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
+		}
+		cFYI(1, ("invalidating remote inode since open detected it "
+			 "changed"));
+		invalidate_remote_inode(file->f_dentry->d_inode);
+	}
+
+client_can_cache:
+	if (pTcon->ses->capabilities & CAP_UNIX)
+		rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
+			full_path, inode->i_sb, xid);
+	else
+		rc = cifs_get_inode_info(&file->f_dentry->d_inode,
+			full_path, buf, inode->i_sb, xid);
+
+	if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+		pCifsInode->clientCanCacheAll = TRUE;
+		pCifsInode->clientCanCacheRead = TRUE;
+		cFYI(1, ("Exclusive Oplock granted on inode %p",
+			 file->f_dentry->d_inode));
+	} else if ((*oplock & 0xF) == OPLOCK_READ)
+		pCifsInode->clientCanCacheRead = TRUE;
+
+	return rc;
+}
 
-int
-cifs_open(struct inode *inode, struct file *file)
+int cifs_open(struct inode *inode, struct file *file)
 {
 	int rc = -EACCES;
 	int xid, oplock;
@@ -46,12 +153,12 @@ cifs_open(struct inode *inode, struct fi
 	struct cifsTconInfo *pTcon;
 	struct cifsFileInfo *pCifsFile;
 	struct cifsInodeInfo *pCifsInode;
-	struct list_head * tmp;
+	struct list_head *tmp;
 	char *full_path = NULL;
-	int desiredAccess = 0x20197;
+	int desiredAccess;
 	int disposition;
 	__u16 netfid;
-	FILE_ALL_INFO * buf = NULL;
+	FILE_ALL_INFO *buf = NULL;
 
 	xid = GetXid();
 
@@ -59,48 +166,46 @@ cifs_open(struct inode *inode, struct fi
 	pTcon = cifs_sb->tcon;
 
 	if (file->f_flags & O_CREAT) {
-		/* search inode for this file and fill in file->private_data = */
+		/* search inode for this file and fill in file->private_data */
 		pCifsInode = CIFS_I(file->f_dentry->d_inode);
 		read_lock(&GlobalSMBSeslock);
-		list_for_each(tmp, &pCifsInode->openFileList) {            
-			pCifsFile = list_entry(tmp,struct cifsFileInfo, flist);           
-			if((pCifsFile->pfile == NULL)&& (pCifsFile->pid == current->tgid)){
-			/* mode set in cifs_create */
-				pCifsFile->pfile = file; /* needed for writepage */
+		list_for_each(tmp, &pCifsInode->openFileList) {
+			pCifsFile = list_entry(tmp, struct cifsFileInfo,
+					       flist);
+			if ((pCifsFile->pfile == NULL) &&
+			    (pCifsFile->pid == current->tgid)) {
+				/* mode set in cifs_create */
+
+				/* needed for writepage */
+				pCifsFile->pfile = file;
+				
 				file->private_data = pCifsFile;
 				break;
 			}
 		}
 		read_unlock(&GlobalSMBSeslock);
-		if(file->private_data != NULL) {
+		if (file->private_data != NULL) {
 			rc = 0;
 			FreeXid(xid);
 			return rc;
 		} else {
-			if(file->f_flags & O_EXCL)
-				cERROR(1,("could not find file instance for new file %p ",file));
+			if (file->f_flags & O_EXCL)
+				cERROR(1, ("could not find file instance for "
+					   "new file %p ", file));
 		}
 	}
 
 	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(file->f_dentry);
 	up(&inode->i_sb->s_vfs_rename_sem);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-		desiredAccess = GENERIC_READ;
-	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
-		desiredAccess = GENERIC_WRITE;
-	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
-		/* GENERIC_ALL is too much permission to request */
-		/* can cause unnecessary access denied on create */
-		/* desiredAccess = GENERIC_ALL; */
-		desiredAccess = GENERIC_READ | GENERIC_WRITE;
-	}
+	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+		 inode, file->f_flags, full_path));
+	desiredAccess = cifs_convert_flags(file->f_flags);
 
 /*********************************************************************
  *  open flag mapping table:
@@ -126,14 +231,7 @@ cifs_open(struct inode *inode, struct fi
  *	 O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
  *********************************************************************/
 
-	if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
-		disposition = FILE_CREATE;
-	else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
-		disposition = FILE_OVERWRITE_IF;
-	else if((file->f_flags & O_CREAT) == O_CREAT)
-		disposition = FILE_OPEN_IF;
-	else
-		disposition = FILE_OPEN;
+	disposition = cifs_get_disposition(file->f_flags);
 
 	if (oplockEnabled)
 		oplock = REQ_OPLOCK;
@@ -142,125 +240,76 @@ cifs_open(struct inode *inode, struct fi
 
 	/* BB pass O_SYNC flag through on file attributes .. BB */
 
-	/* Also refresh inode by passing in file_info buf returned by SMBOpen 
-	   and calling get_inode_info with returned buf (at least 
-	   helps non-Unix server case */
+	/* Also refresh inode by passing in file_info buf returned by SMBOpen
+	   and calling get_inode_info with returned buf (at least helps
+	   non-Unix server case) */
 
 	/* BB we can not do this if this is the second open of a file 
-	and the first handle has writebehind data, we might be 
-	able to simply do a filemap_fdatawrite/filemap_fdatawait first */
-	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
-	if(buf== NULL) {
-		if (full_path)
-			kfree(full_path);
-		FreeXid(xid);
-		return -ENOMEM;
+	   and the first handle has writebehind data, we might be 
+	   able to simply do a filemap_fdatawrite/filemap_fdatawait first */
+	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto out;
 	}
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-			CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
+			 CREATE_NOT_DIR, &netfid, &oplock, buf,
+			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, ("cifs_open returned 0x%x ", rc));
-		cFYI(1, ("oplock: %d ", oplock));	
+		goto out;
+	}
+	file->private_data =
+		kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+	if (file->private_data == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
+	write_lock(&file->f_owner.lock);
+	write_lock(&GlobalSMBSeslock);
+	list_add(&pCifsFile->tlist, &pTcon->openFileList);
+
+	pCifsInode = CIFS_I(file->f_dentry->d_inode);
+	if (pCifsInode) {
+		rc = cifs_open_inode_helper(inode, file, pCifsInode,
+					    pCifsFile, pTcon,
+					    &oplock, buf, full_path, xid);
 	} else {
-		file->private_data =
-			kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
-		if (file->private_data) {
-			memset(file->private_data, 0, sizeof(struct cifsFileInfo));
-			pCifsFile = (struct cifsFileInfo *) file->private_data;
-			pCifsFile->netfid = netfid;
-			pCifsFile->pid = current->tgid;
-			init_MUTEX(&pCifsFile->fh_sem);
-			pCifsFile->pfile = file; /* needed for writepage */
-			pCifsFile->pInode = inode;
-			pCifsFile->invalidHandle = FALSE;
-			pCifsFile->closePend     = FALSE;
-			write_lock(&file->f_owner.lock);
-			write_lock(&GlobalSMBSeslock);
-			list_add(&pCifsFile->tlist,&pTcon->openFileList);
-			pCifsInode = CIFS_I(file->f_dentry->d_inode);
-			if(pCifsInode) {
-				/* want handles we can use to read with first */
-				/* in the list so we do not have to walk the */
-				/* list to search for one in prepare_write */
-				if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-					list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
-				} else {
-					list_add(&pCifsFile->flist,&pCifsInode->openFileList);
-				}
-				write_unlock(&GlobalSMBSeslock);
-				write_unlock(&file->f_owner.lock);
-				if(pCifsInode->clientCanCacheRead) {
-					/* we have the inode open somewhere else
-					   no need to discard cache data */
-				} else {
-					if(buf) {
-					/* BB need same check in cifs_create too? */
-
-					/* if not oplocked, invalidate inode pages if mtime 
-					   or file size changed */
-						struct timespec temp;
-						temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
-						if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && 
-							(file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
-							cFYI(1,("inode unchanged on server"));
-						} else {
-							if(file->f_dentry->d_inode->i_mapping) {
-							/* BB no need to lock inode until after invalidate*/
-							/* since namei code should already have it locked?*/
-								filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
-								filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
-							}
-							cFYI(1,("invalidating remote inode since open detected it changed"));
-							invalidate_remote_inode(file->f_dentry->d_inode);
-						}
-					}
-				}
-				if (pTcon->ses->capabilities & CAP_UNIX)
-					rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
-						full_path, inode->i_sb,xid);
-				else
-					rc = cifs_get_inode_info(&file->f_dentry->d_inode,
-						full_path, buf, inode->i_sb,xid);
+		write_unlock(&GlobalSMBSeslock);
+		write_unlock(&file->f_owner.lock);
+	}
 
-				if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-					pCifsInode->clientCanCacheAll = TRUE;
-					pCifsInode->clientCanCacheRead = TRUE;
-					cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
-				} else if((oplock & 0xF) == OPLOCK_READ)
-					pCifsInode->clientCanCacheRead = TRUE;
-			} else {
-				write_unlock(&GlobalSMBSeslock);
-				write_unlock(&file->f_owner.lock);
-			}
-			if(oplock & CIFS_CREATE_ACTION) {           
-				/* time to set mode which we can not set earlier due
-				 to problems creating new read-only files */
-				if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
-					CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
-						(__u64)-1, 
-						(__u64)-1,
-						0 /* dev */,
-						cifs_sb->local_nls);
-				else {/* BB implement via Windows security descriptors */
-			/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
-			/* in the meantime could set r/o dos attribute when perms are eg:
-					mode & 0222 == 0 */
-				}
-			}
+	if (oplock & CIFS_CREATE_ACTION) {           
+		/* time to set mode which we can not set earlier due to
+		   problems creating new read-only files */
+		if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+			CIFSSMBUnixSetPerms(xid, pTcon, full_path,
+					    inode->i_mode,
+					    (__u64)-1, (__u64)-1, 0 /* dev */,
+					    cifs_sb->local_nls,
+					    cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		} else {
+			/* BB implement via Windows security descriptors eg
+			   CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
+					      -1, -1, local_nls);
+			   in the meantime could set r/o dos attribute when
+			   perms are eg: mode & 0222 == 0 */
 		}
 	}
 
-	if (buf)
-		kfree(buf);
-	if (full_path)
-		kfree(full_path);
+out:
+	kfree(buf);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
 
 /* Try to reaquire byte range locks that were released when session */
 /* to server was lost */
-static int cifs_relock_file(struct cifsFileInfo * cifsFile)
+static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 {
 	int rc = 0;
 
@@ -269,7 +318,8 @@ static int cifs_relock_file(struct cifsF
 	return rc;
 }
 
-static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
+static int cifs_reopen_file(struct inode *inode, struct file *file, 
+	int can_flush)
 {
 	int rc = -EACCES;
 	int xid, oplock;
@@ -278,78 +328,70 @@ static int cifs_reopen_file(struct inode
 	struct cifsFileInfo *pCifsFile;
 	struct cifsInodeInfo *pCifsInode;
 	char *full_path = NULL;
-	int desiredAccess = 0x20197;
+	int desiredAccess;
 	int disposition = FILE_OPEN;
 	__u16 netfid;
 
-	if(inode == NULL)
+	if (inode == NULL)
 		return -EBADF;
 	if (file->private_data) {
-		pCifsFile = (struct cifsFileInfo *) file->private_data;
+		pCifsFile = (struct cifsFileInfo *)file->private_data;
 	} else
 		return -EBADF;
 
 	xid = GetXid();
 	down(&pCifsFile->fh_sem);
-	if(pCifsFile->invalidHandle == FALSE) {
+	if (pCifsFile->invalidHandle == FALSE) {
 		up(&pCifsFile->fh_sem);
 		FreeXid(xid);
 		return 0;
 	}
 
-	if(file->f_dentry == NULL) {
+	if (file->f_dentry == NULL) {
 		up(&pCifsFile->fh_sem);
-		cFYI(1,("failed file reopen, no valid name if dentry freed"));
+		cFYI(1, ("failed file reopen, no valid name if dentry freed"));
 		FreeXid(xid);
 		return -EBADF;
 	}
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 /* can not grab rename sem here because various ops, including
-those that already have the rename sem can end up causing writepage
-to get called and if the server was down that means we end up here,
-and we can never tell if the caller already has the rename_sem */
+   those that already have the rename sem can end up causing writepage
+   to get called and if the server was down that means we end up here,
+   and we can never tell if the caller already has the rename_sem */
 	full_path = build_path_from_dentry(file->f_dentry);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		up(&pCifsFile->fh_sem);
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-		desiredAccess = GENERIC_READ;
-	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
-		desiredAccess = GENERIC_WRITE;
-	else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
-		/* GENERIC_ALL is too much permission to request */
-		/* can cause unnecessary access denied on create */
-		/* desiredAccess = GENERIC_ALL; */
-		desiredAccess = GENERIC_READ | GENERIC_WRITE;
-	}
+	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+		 inode, file->f_flags,full_path));
+	desiredAccess = cifs_convert_flags(file->f_flags);
 
 	if (oplockEnabled)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = FALSE;
 
-	
 	/* Can not refresh inode by passing in file_info buf to be returned
-	 by SMBOpen and then calling get_inode_info with returned buf 
-	 since file might have write behind data that needs to be flushed 
-	 and server version of file size can be stale. If we 
-	 knew for sure that inode was not dirty locally we could do this */
+	   by SMBOpen and then calling get_inode_info with returned buf 
+	   since file might have write behind data that needs to be flushed 
+	   and server version of file size can be stale. If we knew for sure
+	   that inode was not dirty locally we could do this */
 
-/*	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
-	if(buf==0) {
+/*	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+	if (buf == 0) {
 		up(&pCifsFile->fh_sem);
-		if (full_path)
-			kfree(full_path);
+		kfree(full_path);
 		FreeXid(xid);
 		return -ENOMEM;
-	}*/
+	} */
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-				CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
+			 CREATE_NOT_DIR, &netfid, &oplock, NULL,
+			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		up(&pCifsFile->fh_sem);
 		cFYI(1, ("cifs_open returned 0x%x ", rc));
@@ -359,104 +401,105 @@ and we can never tell if the caller alre
 		pCifsFile->invalidHandle = FALSE;
 		up(&pCifsFile->fh_sem);
 		pCifsInode = CIFS_I(inode);
-		if(pCifsInode) {
-			if(can_flush) {
+		if (pCifsInode) {
+			if (can_flush) {
 				filemap_fdatawrite(inode->i_mapping);
 				filemap_fdatawait(inode->i_mapping);
 			/* temporarily disable caching while we
-			go to server to get inode info */
+			   go to server to get inode info */
 				pCifsInode->clientCanCacheAll = FALSE;
 				pCifsInode->clientCanCacheRead = FALSE;
 				if (pTcon->ses->capabilities & CAP_UNIX)
 					rc = cifs_get_inode_info_unix(&inode,
-						full_path, inode->i_sb,xid);
+						full_path, inode->i_sb, xid);
 				else
 					rc = cifs_get_inode_info(&inode,
-						full_path, NULL, inode->i_sb,xid);
+						full_path, NULL, inode->i_sb,
+						xid);
 			} /* else we are writing out data to server already
-			and could deadlock if we tried to flush data, and 
-			since we do not know if we have data that would
-			invalidate the current end of file on the server
-			we can not go to the server to get the new
-			inod info */
-			if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-				pCifsInode->clientCanCacheAll =  TRUE;
+			     and could deadlock if we tried to flush data, and
+			     since we do not know if we have data that would
+			     invalidate the current end of file on the server
+			     we can not go to the server to get the new inod
+			     info */
+			if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+				pCifsInode->clientCanCacheAll = TRUE;
 				pCifsInode->clientCanCacheRead = TRUE;
-				cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
-			} else if((oplock & 0xF) == OPLOCK_READ) {
+				cFYI(1, ("Exclusive Oplock granted on inode %p",
+					 file->f_dentry->d_inode));
+			} else if ((oplock & 0xF) == OPLOCK_READ) {
 				pCifsInode->clientCanCacheRead = TRUE;
-				pCifsInode->clientCanCacheAll =  FALSE;
+				pCifsInode->clientCanCacheAll = FALSE;
 			} else {
 				pCifsInode->clientCanCacheRead = FALSE;
-				pCifsInode->clientCanCacheAll =  FALSE;
+				pCifsInode->clientCanCacheAll = FALSE;
 			}
 			cifs_relock_file(pCifsFile);
 		}
 	}
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
 
-int
-cifs_close(struct inode *inode, struct file *file)
+int cifs_close(struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	struct cifsFileInfo *pSMBFile =
-		(struct cifsFileInfo *) file->private_data;
+		(struct cifsFileInfo *)file->private_data;
 
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 	if (pSMBFile) {
-		pSMBFile->closePend    = TRUE;
+		pSMBFile->closePend = TRUE;
 		write_lock(&file->f_owner.lock);
-		if(pTcon) {
+		if (pTcon) {
 			/* no sense reconnecting to close a file that is
-				already closed */
+			   already closed */
 			if (pTcon->tidStatus != CifsNeedReconnect) {
 				write_unlock(&file->f_owner.lock);
-				rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
+				rc = CIFSSMBClose(xid, pTcon,
+						  pSMBFile->netfid);
 				write_lock(&file->f_owner.lock);
 			}
 		}
+		write_lock(&GlobalSMBSeslock);
 		list_del(&pSMBFile->flist);
 		list_del(&pSMBFile->tlist);
+		write_unlock(&GlobalSMBSeslock);
 		write_unlock(&file->f_owner.lock);
-		if(pSMBFile->search_resume_name)
-			kfree(pSMBFile->search_resume_name);
+		kfree(pSMBFile->search_resume_name);
 		kfree(file->private_data);
 		file->private_data = NULL;
 	} else
 		rc = -EBADF;
 
-	if(list_empty(&(CIFS_I(inode)->openFileList))) {
-		cFYI(1,("closing last open instance for inode %p",inode));
-		/* if the file is not open we do not know if we can cache
-		info on this inode, much less write behind and read ahead */
+	if (list_empty(&(CIFS_I(inode)->openFileList))) {
+		cFYI(1, ("closing last open instance for inode %p", inode));
+		/* if the file is not open we do not know if we can cache info
+		   on this inode, much less write behind and read ahead */
 		CIFS_I(inode)->clientCanCacheRead = FALSE;
 		CIFS_I(inode)->clientCanCacheAll  = FALSE;
 	}
-	if((rc ==0) && CIFS_I(inode)->write_behind_rc)
+	if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
 		rc = CIFS_I(inode)->write_behind_rc;
 	FreeXid(xid);
 	return rc;
 }
 
-int
-cifs_closedir(struct inode *inode, struct file *file)
+int cifs_closedir(struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int xid;
 	struct cifsFileInfo *pCFileStruct =
-	    (struct cifsFileInfo *) file->private_data;
-	char * ptmp;
+	    (struct cifsFileInfo *)file->private_data;
+	char *ptmp;
 
 	cFYI(1, ("Closedir inode = 0x%p with ", inode));
 
@@ -464,27 +507,29 @@ cifs_closedir(struct inode *inode, struc
 
 	if (pCFileStruct) {
 		struct cifsTconInfo *pTcon;
-		struct cifs_sb_info * cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+		struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 
 		pTcon = cifs_sb->tcon;
 
 		cFYI(1, ("Freeing private data in close dir"));
-		if(pCFileStruct->srch_inf.endOfSearch == FALSE) {
+		if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
+		   (pCFileStruct->invalidHandle == FALSE)) {
 			pCFileStruct->invalidHandle = TRUE;
 			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
-			cFYI(1,("Closing uncompleted readdir with rc %d",rc));
-			/* not much we can do if it fails anywway, ignore rc */
+			cFYI(1, ("Closing uncompleted readdir with rc %d",
+				 rc));
+			/* not much we can do if it fails anyway, ignore rc */
 			rc = 0;
 		}
 		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
-		if(ptmp) {
-			cFYI(1,("freeing smb buf in srch struct in closedir")); /* BB removeme BB */
+		if (ptmp) {
+   /* BB removeme BB */	cFYI(1, ("freeing smb buf in srch struct in closedir"));
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
 			cifs_buf_release(ptmp);
 		}
 		ptmp = pCFileStruct->search_resume_name;
-		if(ptmp) {
-			cFYI(1,("freeing resume name in closedir")); /* BB removeme BB */
+		if (ptmp) {
+   /* BB removeme BB */	cFYI(1, ("freeing resume name in closedir"));
 			pCFileStruct->search_resume_name = NULL;
 			kfree(ptmp);
 		}
@@ -496,8 +541,7 @@ cifs_closedir(struct inode *inode, struc
 	return rc;
 }
 
-int
-cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
+int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 {
 	int rc, xid;
 	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
@@ -507,16 +551,15 @@ cifs_lock(struct file *file, int cmd, st
 	int wait_flag = FALSE;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
-	length = 1 + pfLock->fl_end - pfLock->fl_start;
 
+	length = 1 + pfLock->fl_end - pfLock->fl_start;
 	rc = -EACCES;
-
 	xid = GetXid();
 
-	cFYI(1,
-	     ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
-	      cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
-	      pfLock->fl_end));
+	cFYI(1, ("Lock parm: 0x%x flockflags: "
+		 "0x%x flocktype: 0x%x start: %lld end: %lld",
+	        cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
+	        pfLock->fl_end));
 
 	if (pfLock->fl_flags & FL_POSIX)
 		cFYI(1, ("Posix "));
@@ -527,11 +570,13 @@ cifs_lock(struct file *file, int cmd, st
 		wait_flag = TRUE;
 	}
 	if (pfLock->fl_flags & FL_ACCESS)
-		cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
+		cFYI(1, ("Process suspended by mandatory locking - "
+			 "not implemented yet "));
 	if (pfLock->fl_flags & FL_LEASE)
 		cFYI(1, ("Lease on file - not implemented yet"));
-	if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
-		cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
+	if (pfLock->fl_flags & 
+	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
+		cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
 
 	if (pfLock->fl_type == F_WRLCK) {
 		cFYI(1, ("F_WRLCK "));
@@ -563,7 +608,7 @@ cifs_lock(struct file *file, int cmd, st
 
 	if (IS_GETLK(cmd)) {
 		rc = CIFSSMBLock(xid, pTcon,
-				 ((struct cifsFileInfo *) file->
+				 ((struct cifsFileInfo *)file->
 				  private_data)->netfid,
 				 length,
 				 pfLock->fl_start, 0, 1, lockType,
@@ -578,14 +623,15 @@ cifs_lock(struct file *file, int cmd, st
 					 0 /* wait flag */ );
 			pfLock->fl_type = F_UNLCK;
 			if (rc != 0)
-				cERROR(1,
-					("Error unlocking previously locked range %d during test of lock ",
-					rc));
+				cERROR(1, ("Error unlocking previously locked "
+					   "range %d during test of lock ",
+					   rc));
 			rc = 0;
 
 		} else {
 			/* if rc == ERR_SHARING_VIOLATION ? */
-			rc = 0;	/* do not change lock type to unlock since range in use */
+			rc = 0;	/* do not change lock type to unlock
+				   since range in use */
 		}
 
 		FreeXid(xid);
@@ -603,9 +649,8 @@ cifs_lock(struct file *file, int cmd, st
 	return rc;
 }
 
-ssize_t
-cifs_user_write(struct file * file, const char __user * write_data,
-	   size_t write_size, loff_t * poffset)
+ssize_t cifs_user_write(struct file *file, const char __user *write_data,
+	size_t write_size, loff_t *poffset)
 {
 	int rc = 0;
 	unsigned int bytes_written = 0;
@@ -613,77 +658,78 @@ cifs_user_write(struct file * file, cons
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	int xid, long_op;
-	struct cifsFileInfo * open_file;
+	struct cifsFileInfo *open_file;
 
-	if(file->f_dentry == NULL)
+	if (file->f_dentry == NULL)
 		return -EBADF;
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-	if(cifs_sb == NULL) {
+	if (cifs_sb == NULL)
 		return -EBADF;
-	}
+
 	pTcon = cifs_sb->tcon;
 
-	/*cFYI(1,
+	/* cFYI(1,
 	   (" write %d bytes to offset %lld of %s", write_size,
 	   *poffset, file->f_dentry->d_name.name)); */
 
-	if (file->private_data == NULL) {
+	if (file->private_data == NULL)
 		return -EBADF;
-	} else {
+	else
 		open_file = (struct cifsFileInfo *) file->private_data;
-	}
 	
 	xid = GetXid();
-	if(file->f_dentry->d_inode == NULL) {
+	if (file->f_dentry->d_inode == NULL) {
 		FreeXid(xid);
 		return -EBADF;
 	}
 
 	if (*poffset > file->f_dentry->d_inode->i_size)
-		long_op = 2;  /* writes past end of file can take a long time */
+		long_op = 2; /* writes past end of file can take a long time */
 	else
 		long_op = 1;
 
 	for (total_written = 0; write_size > total_written;
 	     total_written += bytes_written) {
 		rc = -EAGAIN;
-		while(rc == -EAGAIN) {
-			if(file->private_data == NULL) {
+		while (rc == -EAGAIN) {
+			if (file->private_data == NULL) {
 				/* file has been closed on us */
 				FreeXid(xid);
 			/* if we have gotten here we have written some data
-			and blocked, and the file has been freed on us
-			while we blocked so return what we managed to write */
+			   and blocked, and the file has been freed on us while
+			   we blocked so return what we managed to write */
 				return total_written;
 			} 
-			if(open_file->closePend) {
+			if (open_file->closePend) {
 				FreeXid(xid);
-				if(total_written)
+				if (total_written)
 					return total_written;
 				else
 					return -EBADF;
 			}
 			if (open_file->invalidHandle) {
-				if((file->f_dentry == NULL) ||
-				   (file->f_dentry->d_inode == NULL)) {
+				if ((file->f_dentry == NULL) ||
+				    (file->f_dentry->d_inode == NULL)) {
 					FreeXid(xid);
 					return total_written;
 				}
 				/* we could deadlock if we called
-				 filemap_fdatawait from here so tell
-				reopen_file not to flush data to server now */
+				   filemap_fdatawait from here so tell
+				   reopen_file not to flush data to server
+				   now */
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
-					file,FALSE);
-				if(rc != 0)
+					file, FALSE);
+				if (rc != 0)
 					break;
 			}
 
 			rc = CIFSSMBWrite(xid, pTcon,
-				  open_file->netfid,
-				  write_size - total_written, *poffset,
-				  &bytes_written,
-				  NULL, write_data + total_written, long_op);
+				open_file->netfid,
+				min_t(const int, cifs_sb->wsize,
+				      write_size - total_written),
+				*poffset, &bytes_written,
+				NULL, write_data + total_written, long_op);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -694,11 +740,12 @@ cifs_user_write(struct file * file, cons
 			}
 		} else
 			*poffset += bytes_written;
-		long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
+		long_op = FALSE; /* subsequent writes fast -
+				    15 seconds is plenty */
 	}
 
 #ifdef CONFIG_CIFS_STATS
-	if(total_written > 0) {
+	if (total_written > 0) {
 		atomic_inc(&pTcon->num_writes);
 		spin_lock(&pTcon->stat_lock);
 		pTcon->bytes_written += total_written;
@@ -707,14 +754,15 @@ cifs_user_write(struct file * file, cons
 #endif		
 
 	/* since the write may have blocked check these pointers again */
-	if(file->f_dentry) {
-		if(file->f_dentry->d_inode) {
+	if (file->f_dentry) {
+		if (file->f_dentry->d_inode) {
 			struct inode *inode = file->f_dentry->d_inode;
 			inode->i_ctime = inode->i_mtime =
 				current_fs_time(inode->i_sb);
 			if (total_written > 0) {
 				if (*poffset > file->f_dentry->d_inode->i_size)
-					i_size_write(file->f_dentry->d_inode, *poffset);
+					i_size_write(file->f_dentry->d_inode,
+					*poffset);
 			}
 			mark_inode_dirty_sync(file->f_dentry->d_inode);
 		}
@@ -723,9 +771,8 @@ cifs_user_write(struct file * file, cons
 	return total_written;
 }
 
-static ssize_t
-cifs_write(struct file * file, const char *write_data,
-	   size_t write_size, loff_t * poffset)
+static ssize_t cifs_write(struct file *file, const char *write_data,
+	size_t write_size, loff_t *poffset)
 {
 	int rc = 0;
 	unsigned int bytes_written = 0;
@@ -733,77 +780,79 @@ cifs_write(struct file * file, const cha
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	int xid, long_op;
-	struct cifsFileInfo * open_file;
+	struct cifsFileInfo *open_file;
 
-	if(file->f_dentry == NULL)
+	if (file->f_dentry == NULL)
 		return -EBADF;
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-	if(cifs_sb == NULL) {
+	if (cifs_sb == NULL)
 		return -EBADF;
-	}
+
 	pTcon = cifs_sb->tcon;
 
-	/*cFYI(1,
+	/* cFYI(1,
 	   (" write %d bytes to offset %lld of %s", write_size,
 	   *poffset, file->f_dentry->d_name.name)); */
 
-	if (file->private_data == NULL) {
+	if (file->private_data == NULL)
 		return -EBADF;
-	} else {
-		open_file = (struct cifsFileInfo *) file->private_data;
-	}
+	else
+		open_file = (struct cifsFileInfo *)file->private_data;
 	
 	xid = GetXid();
-	if(file->f_dentry->d_inode == NULL) {
+	if (file->f_dentry->d_inode == NULL) {
 		FreeXid(xid);
 		return -EBADF;
 	}
 
 	if (*poffset > file->f_dentry->d_inode->i_size)
-		long_op = 2;  /* writes past end of file can take a long time */
+		long_op = 2; /* writes past end of file can take a long time */
 	else
 		long_op = 1;
 
 	for (total_written = 0; write_size > total_written;
 	     total_written += bytes_written) {
 		rc = -EAGAIN;
-		while(rc == -EAGAIN) {
-			if(file->private_data == NULL) {
+		while (rc == -EAGAIN) {
+			if (file->private_data == NULL) {
 				/* file has been closed on us */
 				FreeXid(xid);
 			/* if we have gotten here we have written some data
-			and blocked, and the file has been freed on us
-			while we blocked so return what we managed to write */
+			   and blocked, and the file has been freed on us
+			   while we blocked so return what we managed to 
+			   write */
 				return total_written;
 			} 
-			if(open_file->closePend) {
+			if (open_file->closePend) {
 				FreeXid(xid);
-				if(total_written)
+				if (total_written)
 					return total_written;
 				else
 					return -EBADF;
 			}
 			if (open_file->invalidHandle) {
-				if((file->f_dentry == NULL) ||
+				if ((file->f_dentry == NULL) ||
 				   (file->f_dentry->d_inode == NULL)) {
 					FreeXid(xid);
 					return total_written;
 				}
 				/* we could deadlock if we called
-				 filemap_fdatawait from here so tell
-				reopen_file not to flush data to server now */
+				   filemap_fdatawait from here so tell
+				   reopen_file not to flush data to 
+				   server now */
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
-					file,FALSE);
-				if(rc != 0)
+					file, FALSE);
+				if (rc != 0)
 					break;
 			}
 
 			rc = CIFSSMBWrite(xid, pTcon,
-				  open_file->netfid,
-				  write_size - total_written, *poffset,
-				  &bytes_written,
-				  write_data + total_written, NULL, long_op);
+				 open_file->netfid,
+				 min_t(const int, cifs_sb->wsize, 
+				       write_size - total_written),
+				 *poffset, &bytes_written,
+				 write_data + total_written, NULL, long_op);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -814,11 +863,12 @@ cifs_write(struct file * file, const cha
 			}
 		} else
 			*poffset += bytes_written;
-		long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
+		long_op = FALSE; /* subsequent writes fast - 
+				    15 seconds is plenty */
 	}
 
 #ifdef CONFIG_CIFS_STATS
-	if(total_written > 0) {
+	if (total_written > 0) {
 		atomic_inc(&pTcon->num_writes);
 		spin_lock(&pTcon->stat_lock);
 		pTcon->bytes_written += total_written;
@@ -827,13 +877,14 @@ cifs_write(struct file * file, const cha
 #endif		
 
 	/* since the write may have blocked check these pointers again */
-	if(file->f_dentry) {
-		if(file->f_dentry->d_inode) {
-			file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
-				CURRENT_TIME;
+	if (file->f_dentry) {
+		if (file->f_dentry->d_inode) {
+			file->f_dentry->d_inode->i_ctime = 
+			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
 			if (total_written > 0) {
 				if (*poffset > file->f_dentry->d_inode->i_size)
-					i_size_write(file->f_dentry->d_inode, *poffset);
+					i_size_write(file->f_dentry->d_inode, 
+						     *poffset);
 			}
 			mark_inode_dirty_sync(file->f_dentry->d_inode);
 		}
@@ -842,12 +893,11 @@ cifs_write(struct file * file, const cha
 	return total_written;
 }
 
-static int
-cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
+static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 {
 	struct address_space *mapping = page->mapping;
 	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
-	char * write_data;
+	char *write_data;
 	int rc = -EFAULT;
 	int bytes_written = 0;
 	struct cifs_sb_info *cifs_sb;
@@ -858,11 +908,8 @@ cifs_partialpagewrite(struct page *page,
 	struct list_head *tmp;
 	struct list_head *tmp1;
 
-	if (!mapping) {
-		return -EFAULT;
-	} else if(!mapping->host) {
+	if (!mapping || !mapping->host)
 		return -EFAULT;
-	}
 
 	inode = page->mapping->host;
 	cifs_sb = CIFS_SB(inode->i_sb);
@@ -872,64 +919,65 @@ cifs_partialpagewrite(struct page *page,
 	write_data = kmap(page);
 	write_data += from;
 
-	if((to > PAGE_CACHE_SIZE) || (from > to)) {
+	if ((to > PAGE_CACHE_SIZE) || (from > to)) {
 		kunmap(page);
 		return -EIO;
 	}
 
 	/* racing with truncate? */
-	if(offset > mapping->host->i_size) {
+	if (offset > mapping->host->i_size) {
 		kunmap(page);
 		return 0; /* don't care */
 	}
 
 	/* check to make sure that we are not extending the file */
-	if(mapping->host->i_size - offset < (loff_t)to)
+	if (mapping->host->i_size - offset < (loff_t)to)
 		to = (unsigned)(mapping->host->i_size - offset); 
-		
 
 	cifsInode = CIFS_I(mapping->host);
 	read_lock(&GlobalSMBSeslock); 
 	/* BB we should start at the end */
 	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp,struct cifsFileInfo, flist);
-		if(open_file->closePend)
+		open_file = list_entry(tmp, struct cifsFileInfo, flist);
+		if (open_file->closePend)
 			continue;
 		/* We check if file is open for writing first */
-		if((open_file->pfile) && 
+		if ((open_file->pfile) && 
 		   ((open_file->pfile->f_flags & O_RDWR) || 
 			(open_file->pfile->f_flags & O_WRONLY))) {
 			read_unlock(&GlobalSMBSeslock);
-			bytes_written = cifs_write(open_file->pfile, write_data,
-					to-from, &offset);
+			bytes_written = cifs_write(open_file->pfile,
+						write_data, to-from,
+						&offset);
 			read_lock(&GlobalSMBSeslock);
 		/* Does mm or vfs already set times? */
-			inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
+			inode->i_atime = 
+			inode->i_mtime = current_fs_time(inode->i_sb);
 			if ((bytes_written > 0) && (offset)) {
 				rc = 0;
-			} else if(bytes_written < 0) {
-				if(rc == -EBADF) {
-				/* have seen a case in which
-				kernel seemed to have closed/freed a file
-				even with writes active so we might as well
-				see if there are other file structs to try
-				for the same inode before giving up */
+			} else if (bytes_written < 0) {
+				if (rc == -EBADF) {
+				/* have seen a case in which kernel seemed to
+				   have closed/freed a file even with writes
+				   active so we might as well see if there are
+				   other file structs to try for the same
+				   inode before giving up */
 					continue;
 				} else
 					rc = bytes_written;
 			}
-			break;  /* now that we found a valid file handle
-				and tried to write to it we are done, no
-				sense continuing to loop looking for another */
+			break;  /* now that we found a valid file handle and
+				   tried to write to it we are done, no sense
+				   continuing to loop looking for another */
 		}
-		if(tmp->next == NULL) {
-			cFYI(1,("File instance %p removed",tmp));
+		if (tmp->next == NULL) {
+			cFYI(1, ("File instance %p removed", tmp));
 			break;
 		}
 	}
 	read_unlock(&GlobalSMBSeslock);
-	if(open_file == NULL) {
-		cFYI(1,("No writeable filehandles for inode"));
+	if (open_file == NULL) {
+		cFYI(1, ("No writeable filehandles for inode"));
 		rc = -EIO;
 	}
 
@@ -938,21 +986,24 @@ cifs_partialpagewrite(struct page *page,
 }
 
 #if 0
-static int
-cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
+static int cifs_writepages(struct address_space *mapping,
+	struct writeback_control *wbc)
 {
 	int rc = -EFAULT;
 	int xid;
 
 	xid = GetXid();
-/* call 16K write then Setpageuptodate */
+
+	/* Find contiguous pages then iterate through repeating
+	   call 16K write then Setpageuptodate or if LARGE_WRITE_X
+	   support then send larger writes via kevec so as to eliminate
+	   a memcpy */
 	FreeXid(xid);
 	return rc;
 }
 #endif
 
-static int
-cifs_writepage(struct page* page, struct writeback_control *wbc)
+static int cifs_writepage(struct page* page, struct writeback_control *wbc)
 {
 	int rc = -EFAULT;
 	int xid;
@@ -961,10 +1012,10 @@ cifs_writepage(struct page* page, struct
 /* BB add check for wbc flags */
 	page_cache_get(page);
         if (!PageUptodate(page)) {
-		cFYI(1,("ppw - page not up to date"));
+		cFYI(1, ("ppw - page not up to date"));
 	}
 	
-	rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
+	rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
 	SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
 	unlock_page(page);
 	page_cache_release(page);	
@@ -972,66 +1023,67 @@ cifs_writepage(struct page* page, struct
 	return rc;
 }
 
-static int
-cifs_commit_write(struct file *file, struct page *page, unsigned offset,
-		  unsigned to)
+static int cifs_commit_write(struct file *file, struct page *page,
+	unsigned offset, unsigned to)
 {
 	int xid;
 	int rc = 0;
 	struct inode *inode = page->mapping->host;
 	loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
-	char * page_data;
+	char *page_data;
 
 	xid = GetXid();
-	cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
-	if (position > inode->i_size){
+	cFYI(1, ("commit write for page %p up to position %lld for %d", 
+		 page, position, to));
+	if (position > inode->i_size) {
 		i_size_write(inode, position);
-		/*if (file->private_data == NULL) {
+		/* if (file->private_data == NULL) {
 			rc = -EBADF;
 		} else {
 			open_file = (struct cifsFileInfo *)file->private_data;
 			cifs_sb = CIFS_SB(inode->i_sb);
 			rc = -EAGAIN;
-			while(rc == -EAGAIN) {
-				if((open_file->invalidHandle) && 
-				  (!open_file->closePend)) {
-					rc = cifs_reopen_file(file->f_dentry->d_inode,file);
-					if(rc != 0)
+			while (rc == -EAGAIN) {
+				if ((open_file->invalidHandle) && 
+				    (!open_file->closePend)) {
+					rc = cifs_reopen_file(
+						file->f_dentry->d_inode, file);
+					if (rc != 0)
 						break;
 				}
-				if(!open_file->closePend) {
-					rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, 
-						position, open_file->netfid,
-						open_file->pid,FALSE);
+				if (!open_file->closePend) {
+					rc = CIFSSMBSetFileSize(xid,
+						cifs_sb->tcon, position,
+						open_file->netfid,
+						open_file->pid, FALSE);
 				} else {
 					rc = -EBADF;
 					break;
 				}
 			}
-			cFYI(1,(" SetEOF (commit write) rc = %d",rc));
-		}*/
+			cFYI(1, (" SetEOF (commit write) rc = %d", rc));
+		} */
 	}
 	if (!PageUptodate(page)) {
 		position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
 		/* can not rely on (or let) writepage write this data */
-		if(to < offset) {
-			cFYI(1,("Illegal offsets, can not copy from %d to %d",
-				offset,to));
+		if (to < offset) {
+			cFYI(1, ("Illegal offsets, can not copy from %d to %d",
+				offset, to));
 			FreeXid(xid);
 			return rc;
 		}
-		/* this is probably better than directly calling 
-		partialpage_write since in this function
-		the file handle is known which we might as well
-		leverage */
-		/* BB check if anything else missing out of ppw */
-		/* such as updating last write time */
+		/* this is probably better than directly calling
+		   partialpage_write since in this function the file handle is
+		   known which we might as well	leverage */
+		/* BB check if anything else missing out of ppw
+		   such as updating last write time */
 		page_data = kmap(page);
-		rc = cifs_write(file, page_data+offset,to-offset,
-                                        &position);
-		if(rc > 0)
+		rc = cifs_write(file, page_data + offset, to-offset,
+				&position);
+		if (rc > 0)
 			rc = 0;
-		/* else if rc < 0 should we set writebehind rc? */
+		/* else if (rc < 0) should we set writebehind rc? */
 		kunmap(page);
 	} else {	
 		set_page_dirty(page);
@@ -1041,12 +1093,11 @@ cifs_commit_write(struct file *file, str
 	return rc;
 }
 
-int
-cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
 	int xid;
 	int rc = 0;
-	struct inode * inode = file->f_dentry->d_inode;
+	struct inode *inode = file->f_dentry->d_inode;
 
 	xid = GetXid();
 
@@ -1054,14 +1105,13 @@ cifs_fsync(struct file *file, struct den
 		dentry->d_name.name, datasync));
 	
 	rc = filemap_fdatawrite(inode->i_mapping);
-	if(rc == 0)
+	if (rc == 0)
 		CIFS_I(inode)->write_behind_rc = 0;
 	FreeXid(xid);
 	return rc;
 }
 
-/* static int
-cifs_sync_page(struct page *page)
+/* static int cifs_sync_page(struct page *page)
 {
 	struct address_space *mapping;
 	struct inode *inode;
@@ -1069,18 +1119,18 @@ cifs_sync_page(struct page *page)
 	unsigned int rpages = 0;
 	int rc = 0;
 
-	cFYI(1,("sync page %p",page));
+	cFYI(1, ("sync page %p",page));
 	mapping = page->mapping;
 	if (!mapping)
 		return 0;
 	inode = mapping->host;
 	if (!inode)
-		return 0;*/
+		return 0; */
 
 /*	fill in rpages then 
-    result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
+	result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
-/*   cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
+/*	cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
 
 	if (rc < 0)
 		return rc;
@@ -1090,35 +1140,32 @@ cifs_sync_page(struct page *page)
 /*
  * As file closes, flush all cached write data for this inode checking
  * for write behind errors.
- *
  */
 int cifs_flush(struct file *file)
 {
 	struct inode * inode = file->f_dentry->d_inode;
 	int rc = 0;
 
-	/* Rather than do the steps manually: */
-	/* lock the inode for writing */
-	/* loop through pages looking for write behind data (dirty pages) */
-	/* coalesce into contiguous 16K (or smaller) chunks to write to server */
-	/* send to server (prefer in parallel) */
-	/* deal with writebehind errors */
-	/* unlock inode for writing */
-	/* filemapfdatawrite appears easier for the time being */
+	/* Rather than do the steps manually:
+	   lock the inode for writing
+	   loop through pages looking for write behind data (dirty pages)
+	   coalesce into contiguous 16K (or smaller) chunks to write to server
+	   send to server (prefer in parallel)
+	   deal with writebehind errors
+	   unlock inode for writing
+	   filemapfdatawrite appears easier for the time being */
 
 	rc = filemap_fdatawrite(inode->i_mapping);
-	if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
+	if (!rc) /* reset wb rc if we were able to write out dirty pages */
 		CIFS_I(inode)->write_behind_rc = 0;
 		
-	cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
+	cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
 
 	return rc;
 }
 
-
-ssize_t
-cifs_user_read(struct file * file, char __user *read_data, size_t read_size,
-	  loff_t * poffset)
+ssize_t cifs_user_read(struct file *file, char __user *read_data,
+	size_t read_size, loff_t *poffset)
 {
 	int rc = -EACCES;
 	unsigned int bytes_read = 0;
@@ -1127,10 +1174,10 @@ cifs_user_read(struct file * file, char 
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	int xid;
-	struct cifsFileInfo * open_file;
-	char * smb_read_data;
-	char __user * current_offset;
-	struct smb_com_read_rsp * pSMBr;
+	struct cifsFileInfo *open_file;
+	char *smb_read_data;
+	char __user *current_offset;
+	struct smb_com_read_rsp *pSMBr;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1142,20 +1189,22 @@ cifs_user_read(struct file * file, char 
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
 
-	if((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		cFYI(1,("attempting read on write only file instance"));
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		cFYI(1, ("attempting read on write only file instance"));
 	}
-
-	for (total_read = 0,current_offset=read_data; read_size > total_read;
-				total_read += bytes_read,current_offset+=bytes_read) {
-		current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
+	for (total_read = 0, current_offset = read_data;
+	     read_size > total_read;
+	     total_read += bytes_read, current_offset += bytes_read) {
+		current_read_size = min_t(const int, read_size - total_read, 
+					  cifs_sb->rsize);
 		rc = -EAGAIN;
 		smb_read_data = NULL;
-		while(rc == -EAGAIN) {
-			if ((open_file->invalidHandle) && (!open_file->closePend)) {
+		while (rc == -EAGAIN) {
+			if ((open_file->invalidHandle) && 
+			    (!open_file->closePend)) {
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
-					file,TRUE);
-				if(rc != 0)
+					file, TRUE);
+				if (rc != 0)
 					break;
 			}
 
@@ -1165,9 +1214,15 @@ cifs_user_read(struct file * file, char 
 				 &bytes_read, &smb_read_data);
 
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
-			copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/
-				+ le16_to_cpu(pSMBr->DataOffset), bytes_read);
-			if(smb_read_data) {
+			if (copy_to_user(current_offset, 
+					 smb_read_data + 4 /* RFC1001 hdr */
+					 + le16_to_cpu(pSMBr->DataOffset), 
+					 bytes_read)) {
+				rc = -EFAULT;
+				FreeXid(xid);
+				return rc;
+            }
+			if (smb_read_data) {
 				cifs_buf_release(smb_read_data);
 				smb_read_data = NULL;
 			}
@@ -1193,9 +1248,9 @@ cifs_user_read(struct file * file, char 
 	return total_read;
 }
 
-static ssize_t
-cifs_read(struct file * file, char *read_data, size_t read_size,
-	  loff_t * poffset)
+
+static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
+	loff_t *poffset)
 {
 	int rc = -EACCES;
 	unsigned int bytes_read = 0;
@@ -1204,8 +1259,8 @@ cifs_read(struct file * file, char *read
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	int xid;
-	char * current_offset;
-	struct cifsFileInfo * open_file;
+	char *current_offset;
+	struct cifsFileInfo *open_file;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1217,19 +1272,21 @@ cifs_read(struct file * file, char *read
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
 
-	if((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		cFYI(1,("attempting read on write only file instance"));
-	}
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+		cFYI(1, ("attempting read on write only file instance"));
 
-	for (total_read = 0,current_offset=read_data; read_size > total_read;
-				total_read += bytes_read,current_offset+=bytes_read) {
-		current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
+	for (total_read = 0, current_offset = read_data; 
+	     read_size > total_read;
+	     total_read += bytes_read, current_offset += bytes_read) {
+		current_read_size = min_t(const int, read_size - total_read,
+					  cifs_sb->rsize);
 		rc = -EAGAIN;
-		while(rc == -EAGAIN) {
-			if ((open_file->invalidHandle) && (!open_file->closePend)) {
+		while (rc == -EAGAIN) {
+			if ((open_file->invalidHandle) && 
+			    (!open_file->closePend)) {
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
-					file,TRUE);
-				if(rc != 0)
+					file, TRUE);
+				if (rc != 0)
 					break;
 			}
 
@@ -1259,26 +1316,15 @@ cifs_read(struct file * file, char *read
 	return total_read;
 }
 
-int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
+int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct dentry * dentry = file->f_dentry;
-	int	rc, xid;
-
-#ifdef CIFS_EXPERIMENTAL   /* BB fixme reenable when cifs_read_wrapper fixed */
-	if(dentry->d_sb) {
-		struct cifs_sb_info *cifs_sb;
-		cifs_sb = CIFS_SB(sb);
-		if(cifs_sb != NULL) {
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-				return -ENODEV
-		}
-	}
-#endif /* CIFS_EXPERIMENTAL */
+	struct dentry *dentry = file->f_dentry;
+	int rc, xid;
 
 	xid = GetXid();
 	rc = cifs_revalidate(dentry);
 	if (rc) {
-		cFYI(1,("Validation prior to mmap failed, error=%d", rc));
+		cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
 		FreeXid(xid);
 		return rc;
 	}
@@ -1287,38 +1333,43 @@ int cifs_file_mmap(struct file * file, s
 	return rc;
 }
 
+
 static void cifs_copy_cache_pages(struct address_space *mapping, 
-		struct list_head *pages, int bytes_read, 
-		char *data,struct pagevec * plru_pvec)
+	struct list_head *pages, int bytes_read, char *data,
+	struct pagevec *plru_pvec)
 {
 	struct page *page;
-	char * target;
+	char *target;
 
 	while (bytes_read > 0) {
-		if(list_empty(pages))
+		if (list_empty(pages))
 			break;
 
 		page = list_entry(pages->prev, struct page, lru);
 		list_del(&page->lru);
 
-		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
+		if (add_to_page_cache(page, mapping, page->index,
+				      GFP_KERNEL)) {
 			page_cache_release(page);
-			cFYI(1,("Add page cache failed"));
+			cFYI(1, ("Add page cache failed"));
+			data += PAGE_CACHE_SIZE;
+			bytes_read -= PAGE_CACHE_SIZE;
 			continue;
 		}
 
 		target = kmap_atomic(page,KM_USER0);
 
-		if(PAGE_CACHE_SIZE > bytes_read) {
-			memcpy(target,data,bytes_read);
+		if (PAGE_CACHE_SIZE > bytes_read) {
+			memcpy(target, data, bytes_read);
 			/* zero the tail end of this partial page */
-			memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
+			memset(target + bytes_read, 0, 
+			       PAGE_CACHE_SIZE - bytes_read);
 			bytes_read = 0;
 		} else {
-			memcpy(target,data,PAGE_CACHE_SIZE);
+			memcpy(target, data, PAGE_CACHE_SIZE);
 			bytes_read -= PAGE_CACHE_SIZE;
 		}
-		kunmap_atomic(target,KM_USER0);
+		kunmap_atomic(target, KM_USER0);
 
 		flush_dcache_page(page);
 		SetPageUptodate(page);
@@ -1330,23 +1381,21 @@ static void cifs_copy_cache_pages(struct
 	return;
 }
 
-
-static int
-cifs_readpages(struct file *file, struct address_space *mapping,
-		struct list_head *page_list, unsigned num_pages)
+static int cifs_readpages(struct file *file, struct address_space *mapping,
+	struct list_head *page_list, unsigned num_pages)
 {
 	int rc = -EACCES;
 	int xid;
 	loff_t offset;
-	struct page * page;
+	struct page *page;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	int bytes_read = 0;
 	unsigned int read_size,i;
-	char * smb_read_data = NULL;
-	struct smb_com_read_rsp * pSMBr;
+	char *smb_read_data = NULL;
+	struct smb_com_read_rsp *pSMBr;
 	struct pagevec lru_pvec;
-	struct cifsFileInfo * open_file;
+	struct cifsFileInfo *open_file;
 
 	xid = GetXid();
 	if (file->private_data == NULL) {
@@ -1359,44 +1408,46 @@ cifs_readpages(struct file *file, struct
 
 	pagevec_init(&lru_pvec, 0);
 
-	for(i = 0;i<num_pages;) {
+	for (i = 0; i < num_pages; ) {
 		unsigned contig_pages;
-		struct page * tmp_page;
+		struct page *tmp_page;
 		unsigned long expected_index;
 
-		if(list_empty(page_list)) {
+		if (list_empty(page_list))
 			break;
-		}
+
 		page = list_entry(page_list->prev, struct page, lru);
 		offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 
 		/* count adjacent pages that we will read into */
 		contig_pages = 0;
-		expected_index = list_entry(page_list->prev,struct page,lru)->index;
+		expected_index = 
+			list_entry(page_list->prev, struct page, lru)->index;
 		list_for_each_entry_reverse(tmp_page,page_list,lru) {
-			if(tmp_page->index == expected_index) {
+			if (tmp_page->index == expected_index) {
 				contig_pages++;
 				expected_index++;
-			} else {
+			} else
 				break; 
-			}
 		}
-		if(contig_pages + i >  num_pages) {
+		if (contig_pages + i >  num_pages)
 			contig_pages = num_pages - i;
-		}
 
-		/* for reads over a certain size could initiate async read ahead */
+		/* for reads over a certain size could initiate async
+		   read ahead */
 
 		read_size = contig_pages * PAGE_CACHE_SIZE;
 		/* Read size needs to be in multiples of one page */
-		read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
+		read_size = min_t(const unsigned int, read_size,
+				  cifs_sb->rsize & PAGE_CACHE_MASK);
 
 		rc = -EAGAIN;
-		while(rc == -EAGAIN) {
-			if ((open_file->invalidHandle) && (!open_file->closePend)) {
+		while (rc == -EAGAIN) {
+			if ((open_file->invalidHandle) && 
+			    (!open_file->closePend)) {
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
 					file, TRUE);
-				if(rc != 0)
+				if (rc != 0)
 					break;
 			}
 
@@ -1405,18 +1456,19 @@ cifs_readpages(struct file *file, struct
 				read_size, offset,
 				&bytes_read, &smb_read_data);
 			/* BB need to check return code here */
-			if(rc== -EAGAIN) {
-				if(smb_read_data) {
+			if (rc== -EAGAIN) {
+				if (smb_read_data) {
 					cifs_buf_release(smb_read_data);
 					smb_read_data = NULL;
 				}
 			}
 		}
 		if ((rc < 0) || (smb_read_data == NULL)) {
-			cFYI(1,("Read error in readpages: %d",rc));
+			cFYI(1, ("Read error in readpages: %d", rc));
 			/* clean up remaing pages off list */
 			while (!list_empty(page_list) && (i < num_pages)) {
-				page = list_entry(page_list->prev, struct page, lru);
+				page = list_entry(page_list->prev, struct page,
+						  lru);
 				list_del(&page->lru);
 				page_cache_release(page);
 			}
@@ -1434,31 +1486,40 @@ cifs_readpages(struct file *file, struct
 			pTcon->bytes_read += bytes_read;
 			spin_unlock(&pTcon->stat_lock);
 #endif
-			if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
+			if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
 				i++; /* account for partial page */
 
-				/* server copy of file can have smaller size than client */
-				/* BB do we need to verify this common case ? this case is ok - 
-				if we are at server EOF we will hit it on next read */
-
-			/* while(!list_empty(page_list) && (i < num_pages)) {
-					page = list_entry(page_list->prev,struct page, list);
+				/* server copy of file can have smaller size 
+				   than client */
+				/* BB do we need to verify this common case ? 
+				   this case is ok - if we are at server EOF 
+				   we will hit it on next read */
+
+			/* while (!list_empty(page_list) && (i < num_pages)) {
+					page = list_entry(page_list->prev, 
+							  struct page, list);
 					list_del(&page->list);
 					page_cache_release(page);
 				}
 				break; */
 			}
 		} else {
-			cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); 
-			/* BB turn off caching and do new lookup on file size at server? */
+			cFYI(1, ("No bytes read (%d) at offset %lld . "
+				 "Cleaning remaining pages from readahead list",
+				 bytes_read, offset));
+			/* BB turn off caching and do new lookup on 
+			   file size at server? */
 			while (!list_empty(page_list) && (i < num_pages)) {
-				page = list_entry(page_list->prev, struct page, lru);
+				page = list_entry(page_list->prev, struct page,
+						  lru);
 				list_del(&page->lru);
-				page_cache_release(page); /* BB removeme - replace with zero of page? */
+
+				/* BB removeme - replace with zero of page? */
+				page_cache_release(page);
 			}
 			break;
 		}
-		if(smb_read_data) {
+		if (smb_read_data) {
 			cifs_buf_release(smb_read_data);
 			smb_read_data = NULL;
 		}
@@ -1468,7 +1529,7 @@ cifs_readpages(struct file *file, struct
 	pagevec_lru_add(&lru_pvec);
 
 /* need to free smb_read_data buf before exit */
-	if(smb_read_data) {
+	if (smb_read_data) {
 		cifs_buf_release(smb_read_data);
 		smb_read_data = NULL;
 	} 
@@ -1477,9 +1538,10 @@ cifs_readpages(struct file *file, struct
 	return rc;
 }
 
-static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
+static int cifs_readpage_worker(struct file *file, struct page *page,
+	loff_t *poffset)
 {
-	char * read_data;
+	char *read_data;
 	int rc;
 
 	page_cache_get(page);
@@ -1490,16 +1552,15 @@ static int cifs_readpage_worker(struct f
                                                                                                                            
 	if (rc < 0)
 		goto io_error;
-	else {
-		cFYI(1,("Bytes read %d ",rc));
-	}
+	else
+		cFYI(1, ("Bytes read %d ",rc));
                                                                                                                            
 	file->f_dentry->d_inode->i_atime =
 		current_fs_time(file->f_dentry->d_inode->i_sb);
                                                                                                                            
-	if(PAGE_CACHE_SIZE > rc) {
-		memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
-	}
+	if (PAGE_CACHE_SIZE > rc)
+		memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
+
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	rc = 0;
@@ -1510,8 +1571,7 @@ io_error:
 	return rc;
 }
 
-static int
-cifs_readpage(struct file *file, struct page *page)
+static int cifs_readpage(struct file *file, struct page *page)
 {
 	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	int rc = -EACCES;
@@ -1524,9 +1584,10 @@ cifs_readpage(struct file *file, struct 
 		return -EBADF;
 	}
 
-	cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
+	cFYI(1, ("readpage %p at offset %d 0x%x\n", 
+		 page, (int)offset, (int)offset));
 
-	rc = cifs_readpage_worker(file,page,&offset);
+	rc = cifs_readpage_worker(file, page, &offset);
 
 	unlock_page(page);
 
@@ -1540,35 +1601,34 @@ cifs_readpage(struct file *file, struct 
    refreshing the inode only on increases in the file size 
    but this is tricky to do without racing with writebehind
    page caching in the current Linux kernel design */
-   
-int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
+int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
 {
 	struct list_head *tmp;
 	struct list_head *tmp1;
 	struct cifsFileInfo *open_file = NULL;
 	int rc = TRUE;
 
-	if(cifsInode == NULL)
+	if (cifsInode == NULL)
 		return rc;
 
 	read_lock(&GlobalSMBSeslock); 
 	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp,struct cifsFileInfo, flist);
-		if(open_file == NULL)
+		open_file = list_entry(tmp, struct cifsFileInfo, flist);
+		if (open_file == NULL)
 			break;
-		if(open_file->closePend)
+		if (open_file->closePend)
 			continue;
 	/* We check if file is open for writing,   
-	BB we could supplement this with a check to see if file size
-	changes have been flushed to server - ie inode metadata dirty */
-		if((open_file->pfile) && 
-	   ((open_file->pfile->f_flags & O_RDWR) || 
-		(open_file->pfile->f_flags & O_WRONLY))) {
-			 rc = FALSE;
-			 break;
+	   BB we could supplement this with a check to see if file size
+	   changes have been flushed to server - ie inode metadata dirty */
+		if ((open_file->pfile) && 
+		    ((open_file->pfile->f_flags & O_RDWR) || 
+		    (open_file->pfile->f_flags & O_WRONLY))) {
+			rc = FALSE;
+			break;
 		}
-		if(tmp->next == NULL) {
-			cFYI(1,("File instance %p removed",tmp));
+		if (tmp->next == NULL) {
+			cFYI(1, ("File instance %p removed", tmp));
 			break;
 		}
 	}
@@ -1577,829 +1637,12 @@ int is_size_safe_to_change(struct cifsIn
 }
 
 
-void
-fill_in_inode(struct inode *tmp_inode,
-	      FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
-{
-	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
-	__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
-	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-
-	cifsInfo->cifsAttrs = attr;
-	cifsInfo->time = jiffies;
-
-	/* Linux can not store file creation time unfortunately so ignore it */
-	tmp_inode->i_atime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
-	tmp_inode->i_mtime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
-	tmp_inode->i_ctime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
-	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
-	/* 2767 perms - indicate mandatory locking */
-		/* BB fill in uid and gid here? with help from winbind? 
-			or retrieve from NTFS stream extended attribute */
-	if(atomic_read(&cifsInfo->inUse) == 0) {
-		tmp_inode->i_uid = cifs_sb->mnt_uid;
-		tmp_inode->i_gid = cifs_sb->mnt_gid;
-		/* set default mode. will override for dirs below */
-		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
-	}
-
-	cFYI(0,
-	     ("CIFS FFIRST: Attributes came in as 0x%x",
-	      attr));
-	if (attr & ATTR_DIRECTORY) {
-		*pobject_type = DT_DIR;
-		/* override default perms since we do not lock dirs */
-		if(atomic_read(&cifsInfo->inUse) == 0) {
-			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
-		}
-		tmp_inode->i_mode |= S_IFDIR;
-/* we no longer mark these because we could not follow them */
-/*        } else if (attr & ATTR_REPARSE) {
-                *pobject_type = DT_LNK;
-                tmp_inode->i_mode |= S_IFLNK;*/
-	} else {
-		*pobject_type = DT_REG;
-		tmp_inode->i_mode |= S_IFREG;
-		if(attr & ATTR_READONLY)
-			tmp_inode->i_mode &= ~(S_IWUGO);
-	}/* could add code here - to validate if device or weird share type? */
-
-	/* can not fill in nlink here as in qpathinfo version and Unx search */
-	if(atomic_read(&cifsInfo->inUse) == 0) {
-		atomic_set(&cifsInfo->inUse,1);
-	}
-
-	if(is_size_safe_to_change(cifsInfo)) {
-		/* can not safely change the file size here if the 
-		client is writing to it due to potential races */
-		i_size_write(tmp_inode,end_of_file);
-
-	/* 512 bytes (2**9) is the fake blocksize that must be used */
-	/* for this calculation, even though the reported blocksize is larger */
-		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
-	}
-
-	if (allocation_size < end_of_file)
-		cFYI(1, ("Possible sparse file: allocation size less than end of file "));
-	cFYI(1,
-	     ("File Size %ld and blocks %ld and blocksize %ld",
-	      (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
-	      tmp_inode->i_blksize));
-	if (S_ISREG(tmp_inode->i_mode)) {
-		cFYI(1, (" File inode "));
-		tmp_inode->i_op = &cifs_file_inode_ops;
-		tmp_inode->i_fop = &cifs_file_ops;
-		tmp_inode->i_data.a_ops = &cifs_addr_ops;
-	} else if (S_ISDIR(tmp_inode->i_mode)) {
-		cFYI(1, (" Directory inode"));
-		tmp_inode->i_op = &cifs_dir_inode_ops;
-		tmp_inode->i_fop = &cifs_dir_ops;
-	} else if (S_ISLNK(tmp_inode->i_mode)) {
-		cFYI(1, (" Symbolic Link inode "));
-		tmp_inode->i_op = &cifs_symlink_inode_ops;
-	} else {
-		cFYI(1, (" Init special inode "));
-		init_special_inode(tmp_inode, tmp_inode->i_mode,
-				   tmp_inode->i_rdev);
-	}
-}
-
-void
-unix_fill_in_inode(struct inode *tmp_inode,
-		   FILE_UNIX_INFO * pfindData, int *pobject_type)
-{
-	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-	__u32 type = le32_to_cpu(pfindData->Type);
-	__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
-	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-	cifsInfo->time = jiffies;
-	atomic_inc(&cifsInfo->inUse);
-
-	tmp_inode->i_atime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
-	tmp_inode->i_mtime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
-	tmp_inode->i_ctime =
-	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
-
-	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
-	if (type == UNIX_FILE) {
-		*pobject_type = DT_REG;
-		tmp_inode->i_mode |= S_IFREG;
-	} else if (type == UNIX_SYMLINK) {
-		*pobject_type = DT_LNK;
-		tmp_inode->i_mode |= S_IFLNK;
-	} else if (type == UNIX_DIR) {
-		*pobject_type = DT_DIR;
-		tmp_inode->i_mode |= S_IFDIR;
-	} else if (type == UNIX_CHARDEV) {
-		*pobject_type = DT_CHR;
-		tmp_inode->i_mode |= S_IFCHR;
-		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-	} else if (type == UNIX_BLOCKDEV) {
-		*pobject_type = DT_BLK;
-		tmp_inode->i_mode |= S_IFBLK;
-		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-	} else if (type == UNIX_FIFO) {
-		*pobject_type = DT_FIFO;
-		tmp_inode->i_mode |= S_IFIFO;
-	} else if (type == UNIX_SOCKET) {
-		*pobject_type = DT_SOCK;
-		tmp_inode->i_mode |= S_IFSOCK;
-	}
-
-	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
-	tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
-	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
-
-
-	if(is_size_safe_to_change(cifsInfo)) {
-		/* can not safely change the file size here if the 
-		client is writing to it due to potential races */
-		i_size_write(tmp_inode,end_of_file);
-
-	/* 512 bytes (2**9) is the fake blocksize that must be used */
-	/* for this calculation, not the real blocksize */
-		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
-	}
-
-	if (S_ISREG(tmp_inode->i_mode)) {
-		cFYI(1, ("File inode"));
-		tmp_inode->i_op = &cifs_file_inode_ops;
-		tmp_inode->i_fop = &cifs_file_ops;
-		tmp_inode->i_data.a_ops = &cifs_addr_ops;
-	} else if (S_ISDIR(tmp_inode->i_mode)) {
-		cFYI(1, ("Directory inode"));
-		tmp_inode->i_op = &cifs_dir_inode_ops;
-		tmp_inode->i_fop = &cifs_dir_ops;
-	} else if (S_ISLNK(tmp_inode->i_mode)) {
-		cFYI(1, ("Symbolic Link inode"));
-		tmp_inode->i_op = &cifs_symlink_inode_ops;
-/* tmp_inode->i_fop = *//* do not need to set to anything */
-	} else {
-		cFYI(1, ("Special inode")); 
-		init_special_inode(tmp_inode, tmp_inode->i_mode,
-				   tmp_inode->i_rdev);
-	}
-}
-
-/* Returns one if new inode created (which therefore needs to be hashed) */
-/* Might check in the future if inode number changed so we can rehash inode */
-int
-construct_dentry(struct qstr *qstring, struct file *file,
-		 struct inode **ptmp_inode, struct dentry **pnew_dentry)
-{
-	struct dentry *tmp_dentry;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
-	int rc = 0;
-
-	cFYI(1, ("For %s ", qstring->name));
-	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-	pTcon = cifs_sb->tcon;
-
-	qstring->hash = full_name_hash(qstring->name, qstring->len);
-	tmp_dentry = d_lookup(file->f_dentry, qstring);
-	if (tmp_dentry) {
-		cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
-		*ptmp_inode = tmp_dentry->d_inode;
-		/* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
-		if(*ptmp_inode == NULL) {
-	                *ptmp_inode = new_inode(file->f_dentry->d_sb);
-			if(*ptmp_inode == NULL)
-				return rc;
-			rc = 1;
-			d_instantiate(tmp_dentry, *ptmp_inode);
-		}
-	} else {
-		tmp_dentry = d_alloc(file->f_dentry, qstring);
-		if(tmp_dentry == NULL) {
-			cERROR(1,("Failed allocating dentry"));
-			*ptmp_inode = NULL;
-			return rc;
-		}
-			
-		*ptmp_inode = new_inode(file->f_dentry->d_sb);
-		tmp_dentry->d_op = &cifs_dentry_ops;
-		if(*ptmp_inode == NULL)
-			return rc;
-		rc = 1;
-		d_instantiate(tmp_dentry, *ptmp_inode);
-		d_rehash(tmp_dentry);
-	}
-
-	tmp_dentry->d_time = jiffies;
-	*pnew_dentry = tmp_dentry;
-	return rc; 
-}
-
-static void reset_resume_key(struct file * dir_file, 
-				unsigned char * filename, 
-				unsigned int len,int Unicode,struct nls_table * nls_tab) {
-	struct cifsFileInfo *cifsFile;
-
-	cifsFile = (struct cifsFileInfo *)dir_file->private_data;
-	if(cifsFile == NULL)
-		return;
-	if(cifsFile->search_resume_name) {
-		kfree(cifsFile->search_resume_name);
-	}
-
-	if(Unicode) 
-		len *= 2;
-	cifsFile->resume_name_length = len;
-
-	cifsFile->search_resume_name = 
-		kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
-
-	if(cifsFile->search_resume_name == NULL) {
-		cERROR(1,("failed new resume key allocate, length %d",
-				  cifsFile->resume_name_length));
-		return;
-	}
-	if(Unicode)
-		cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
-			filename, len, nls_tab);
-	else
-		memcpy(cifsFile->search_resume_name, filename, 
-		   cifsFile->resume_name_length);
-	cFYI(1,("Reset resume key to: %s with len %d",filename,len));
-	return;
-}
-
-
-
-static int
-cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
-	     struct file *file, filldir_t filldir, void *direntry)
-{
-	struct inode *tmp_inode;
-	struct dentry *tmp_dentry;
-	int object_type,rc;
-
-	pqstring->name = pfindData->FileName;
-	/* pqstring->len is already set by caller */
-
-	rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
-	if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
-		return -ENOMEM;
-	}
-	fill_in_inode(tmp_inode, pfindData, &object_type);
-	if(rc) {
-		/* We have no reliable way to get inode numbers
-		from servers w/o Unix extensions yet so we can not set
-		i_ino from pfindData yet */
-
-		/* new inode created, let us hash it */
-		insert_inode_hash(tmp_inode);
-	} /* else if inode number changed do we rehash it? */
-	rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
-		tmp_inode->i_ino, object_type);
-	if(rc) {
-		/* due to readdir error we need to recalculate resume 
-		key so next readdir will restart on right entry */
-		cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
-	}
-	dput(tmp_dentry);
-	return rc;
-}
-
-static int
-cifs_filldir_unix(struct qstr *pqstring,
-		  FILE_UNIX_INFO * pUnixFindData, struct file *file,
-		  filldir_t filldir, void *direntry)
-{
-	struct inode *tmp_inode;
-	struct dentry *tmp_dentry;
-	int object_type, rc;
-
-	pqstring->name = pUnixFindData->FileName;
-	pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
-
-	rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
-	if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
-		return -ENOMEM;
-	} 
-	if(rc) {
-		struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-			tmp_inode->i_ino = 
-				(unsigned long)pUnixFindData->UniqueId;
-		}
-		insert_inode_hash(tmp_inode);
-	} /* else if i_ino has changed should we rehash it? */
-	unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
-	rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
-		file->f_pos, tmp_inode->i_ino, object_type);
-	if(rc) {
-		/* due to readdir error we need to recalculate resume 
-			key so next readdir will restart on right entry */
-		cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
-	}
-	dput(tmp_dentry);
-	return rc;
-}
-
-int
-cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
-{
-	int rc = 0;
-	int xid;
-	int Unicode = FALSE;
-	int UnixSearch = FALSE;
-	unsigned int bufsize, i;
-	__u16 searchHandle;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
-	struct cifsFileInfo *cifsFile = NULL;
-	char *full_path = NULL;
-	char *data;
-	struct qstr qstring;
-	T2_FFIRST_RSP_PARMS findParms;
-	T2_FNEXT_RSP_PARMS findNextParms;
-	FILE_DIRECTORY_INFO *pfindData;
-	FILE_DIRECTORY_INFO *lastFindData;
-	FILE_UNIX_INFO *pfindDataUnix;
-
-
-    /* BB removeme begin */
-	if(!experimEnabled)
-		return cifs_readdir2(file,direntry,filldir);
-    /* BB removeme end */
-
-
-	xid = GetXid();
-
-	if(file->f_dentry == NULL) {
-		rc = -EIO;
-		FreeXid(xid);
-		return rc;
-	}
-	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
-	pTcon = cifs_sb->tcon;
-	bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
-	if(bufsize > CIFSMaxBufSize) {
-		rc = -EIO;
-		FreeXid(xid);
-		return rc;
-	}
-	data = kmalloc(bufsize, GFP_KERNEL);
-	pfindData = (FILE_DIRECTORY_INFO *) data;
-	if(data == NULL) {
-		rc = -ENOMEM;
-		FreeXid(xid);
-		return rc;
-	}
-	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_wildcard_path_from_dentry(file->f_dentry);
-	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
-
-	if(full_path == NULL) {
-		kfree(data);
-		FreeXid(xid);
-		return -ENOMEM;
-	}
-	cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
-
-	switch ((int) file->f_pos) {
-	case 0:
-		if (filldir(direntry, ".", 1, file->f_pos,
-		     file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
-			cERROR(1, ("Filldir for current dir failed "));
-			break;
-		}
-		file->f_pos++;
-		/* fallthrough */
-	case 1:
-		if (filldir(direntry, "..", 2, file->f_pos,
-		     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
-			cERROR(1, ("Filldir for parent dir failed "));
-			break;
-		}
-		file->f_pos++;
-		/* fallthrough */
-	case 2:
-		if (file->private_data != NULL) {
-			cifsFile =
-				(struct cifsFileInfo *) file->private_data;
-			if (cifsFile->srch_inf.endOfSearch) {
-				if(cifsFile->srch_inf.emptyDir) {
-					cFYI(1, ("End of search, empty dir"));
-					rc = 0;
-					break;
-				}
-			} else {
-				cifsFile->invalidHandle = TRUE;
-				CIFSFindClose(xid, pTcon, cifsFile->netfid);
-			}
-			if(cifsFile->search_resume_name) {
-				kfree(cifsFile->search_resume_name);
-				cifsFile->search_resume_name = NULL;
-			}
-		}
-		rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
-				&findParms, cifs_sb->local_nls,
-				&Unicode, &UnixSearch);
-		cFYI(1, ("Count: %d  End: %d ",
-			le16_to_cpu(findParms.SearchCount),
-			le16_to_cpu(findParms.EndofSearch)));
- 
-		if (rc == 0) {
-			__u16 count = le16_to_cpu(findParms.SearchCount);
-			searchHandle = findParms.SearchHandle;
-			if(file->private_data == NULL)
-				file->private_data =
-					kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
-			if (file->private_data) {
-				memset(file->private_data, 0,
-				       sizeof (struct cifsFileInfo));
-				cifsFile =
-				    (struct cifsFileInfo *) file->private_data;
-				cifsFile->netfid = searchHandle;
-				cifsFile->invalidHandle = FALSE;
-				init_MUTEX(&cifsFile->fh_sem);
-			} else {
-				rc = -ENOMEM;
-				break;
-			}
-
-			renew_parental_timestamps(file->f_dentry);
-			lastFindData = 
-				(FILE_DIRECTORY_INFO *) ((char *) pfindData + 
-					le16_to_cpu(findParms.LastNameOffset));
-			if((char *)lastFindData > (char *)pfindData + bufsize) {
-				cFYI(1,("last search entry past end of packet"));
-				rc = -EIO;
-				break;
-			}
-			/* Offset of resume key same for levels 257 and 514 */
-			cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
-			if(UnixSearch == FALSE) {
-				cifsFile->resume_name_length = 
-					le32_to_cpu(lastFindData->FileNameLength);
-				if(cifsFile->resume_name_length > bufsize - 64) {
-					cFYI(1,("Illegal resume file name length %d",
-						cifsFile->resume_name_length));
-					rc = -ENOMEM;
-					break;
-				}
-				cifsFile->search_resume_name = 
-					kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
-				cFYI(1,("Last file: %s with name %d bytes long",
-					lastFindData->FileName,
-					cifsFile->resume_name_length));
-				if(cifsFile->search_resume_name == NULL) {
-					rc = -ENOMEM;
-					break;
-				}
-				memcpy(cifsFile->search_resume_name,
-					lastFindData->FileName, 
-					cifsFile->resume_name_length);
-			} else {
-				pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
-				if (Unicode == TRUE) {
-					for(i=0;(pfindDataUnix->FileName[i] 
-						    | pfindDataUnix->FileName[i+1]);
-						i+=2) {
-						if(i > bufsize-64)
-							break;
-					}
-					cifsFile->resume_name_length = i + 2;
-				} else {
-					cifsFile->resume_name_length = 
-						strnlen(pfindDataUnix->FileName,
-							bufsize-63);
-				}
-				if(cifsFile->resume_name_length > bufsize - 64) {
-					cFYI(1,("Illegal resume file name length %d",
-						cifsFile->resume_name_length));
-					rc = -ENOMEM;
-					break;
-				}
-				cifsFile->search_resume_name = 
-					kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
-				cFYI(1,("Last file: %s with name %d bytes long",
-					pfindDataUnix->FileName,
-					cifsFile->resume_name_length));
-				if(cifsFile->search_resume_name == NULL) {
-					rc = -ENOMEM;
-					break;
-				}
-				memcpy(cifsFile->search_resume_name,
-					pfindDataUnix->FileName, 
-					cifsFile->resume_name_length);
-			}
-			for (i = 2; i < count + 2; i++) {
-				if (UnixSearch == FALSE) {
-					__u32 len = le32_to_cpu(pfindData->FileNameLength);
-					if (Unicode == TRUE)
-						len =
-						    cifs_strfromUCS_le
-						    (pfindData->FileName,
-						     (wchar_t *)
-						     pfindData->FileName,
-						     len / 2,
-						     cifs_sb->local_nls);
-					qstring.len = len;
-					if (((len != 1)
-					     || (pfindData->FileName[0] != '.'))
-					    && ((len != 2)
-						|| (pfindData->
-						    FileName[0] != '.')
-						|| (pfindData->
-						    FileName[1] != '.'))) {
-						if(cifs_filldir(&qstring,
-							     pfindData,
-							     file, filldir,
-							     direntry)) {
-							/* do not end search if
-								kernel not ready to take
-								remaining entries yet */
-							reset_resume_key(file, pfindData->FileName,qstring.len,
-								Unicode, cifs_sb->local_nls);
-							findParms.EndofSearch = 0;
-							break;
-						}
-						file->f_pos++;
-					}
-				} else {	/* UnixSearch */
-					pfindDataUnix =
-					    (FILE_UNIX_INFO *) pfindData;
-					if (Unicode == TRUE)
-						qstring.len =
-							cifs_strfromUCS_le
-							(pfindDataUnix->FileName,
-							(wchar_t *)
-							pfindDataUnix->FileName,
-							MAX_PATHCONF,
-							cifs_sb->local_nls);
-					else
-						qstring.len =
-							strnlen(pfindDataUnix->
-							  FileName,
-							  MAX_PATHCONF);
-					if (((qstring.len != 1)
-					     || (pfindDataUnix->
-						 FileName[0] != '.'))
-					    && ((qstring.len != 2)
-						|| (pfindDataUnix->
-						    FileName[0] != '.')
-						|| (pfindDataUnix->
-						    FileName[1] != '.'))) {
-						if(cifs_filldir_unix(&qstring,
-								  pfindDataUnix,
-								  file,
-								  filldir,
-								  direntry)) {
-							/* do not end search if
-								kernel not ready to take
-								remaining entries yet */
-							findParms.EndofSearch = 0;
-							reset_resume_key(file, pfindDataUnix->FileName,
-								qstring.len,Unicode,cifs_sb->local_nls);
-							break;
-						}
-						file->f_pos++;
-					}
-				}
-				/* works also for Unix ff struct since first field of both */
-				pfindData = 
-					(FILE_DIRECTORY_INFO *) ((char *) pfindData
-						 + le32_to_cpu(pfindData->NextEntryOffset));
-				/* BB also should check to make sure that pointer is not beyond the end of the SMB */
-				/* if(pfindData > lastFindData) rc = -EIO; break; */
-			}	/* end for loop */
-			if ((findParms.EndofSearch != 0) && cifsFile) {
-				cifsFile->srch_inf.endOfSearch = TRUE;
-				if(findParms.SearchCount == cpu_to_le16(2))
-					cifsFile->srch_inf.emptyDir = TRUE;
-			}
-		} else {
-			if (cifsFile)
-				cifsFile->srch_inf.endOfSearch = TRUE;
-			/* unless parent directory gone do not return error */
-			rc = 0;
-		}
-		break;
-	default:
-		if (file->private_data == NULL) {
-			rc = -EBADF;
-			cFYI(1,
-			     ("Readdir on closed srch, pos = %lld",
-			      file->f_pos));
-		} else {
-			cifsFile = (struct cifsFileInfo *) file->private_data;
-			if (cifsFile->srch_inf.endOfSearch) {
-				rc = 0;
-				cFYI(1, ("End of search "));
-				break;
-			}
-			searchHandle = cifsFile->netfid;
-			rc = CIFSFindNext(xid, pTcon, pfindData,
-				&findNextParms, searchHandle, 
-				cifsFile->search_resume_name,
-				cifsFile->resume_name_length,
-				cifsFile->srch_inf.resume_key,
-				&Unicode, &UnixSearch);
-			cFYI(1,("Count: %d  End: %d ",
-			      le16_to_cpu(findNextParms.SearchCount),
-			      le16_to_cpu(findNextParms.EndofSearch)));
-			if ((rc == 0) && (findNextParms.SearchCount != 0)) {
-			/* BB save off resume key, key name and name length  */
-				__u16 count = le16_to_cpu(findNextParms.SearchCount);
-				lastFindData = 
-					(FILE_DIRECTORY_INFO *) ((char *) pfindData 
-					+ le16_to_cpu(findNextParms.LastNameOffset));
-				if((char *)lastFindData > (char *)pfindData + bufsize) {
-					cFYI(1,("last search entry past end of packet"));
-					rc = -EIO;
-					break;
-				}
-				/* Offset of resume key same for levels 257 and 514 */
-				cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
-
-				if(UnixSearch == FALSE) {
-					cifsFile->resume_name_length = 
-						le32_to_cpu(lastFindData->FileNameLength);
-					if(cifsFile->resume_name_length > bufsize - 64) {
-						cFYI(1,("Illegal resume file name length %d",
-							cifsFile->resume_name_length));
-						rc = -ENOMEM;
-						break;
-					}
-					/* Free the memory allocated by previous findfirst 
-					or findnext call - we can not reuse the memory since
-					the resume name may not be same string length */
-					if(cifsFile->search_resume_name)
-						kfree(cifsFile->search_resume_name);
-					cifsFile->search_resume_name = 
-						kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
-					cFYI(1,("Last file: %s with name %d bytes long",
-						lastFindData->FileName,
-						cifsFile->resume_name_length));
-					if(cifsFile->search_resume_name == NULL) {
-						rc = -ENOMEM;
-						break;
-					}
-					
-					memcpy(cifsFile->search_resume_name,
-						lastFindData->FileName, 
-						cifsFile->resume_name_length);
-				} else {
-					pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
-					if (Unicode == TRUE) {
-						for(i=0;(pfindDataUnix->FileName[i] 
-								| pfindDataUnix->FileName[i+1]);
-							i+=2) {
-							if(i > bufsize-64)
-								break;
-						}
-						cifsFile->resume_name_length = i + 2;
-					} else {
-						cifsFile->resume_name_length = 
-							strnlen(pfindDataUnix->
-							 FileName,
-							 MAX_PATHCONF);
-					}
-					if(cifsFile->resume_name_length > bufsize - 64) {
-						cFYI(1,("Illegal resume file name length %d",
-								cifsFile->resume_name_length));
-						rc = -ENOMEM;
-						break;
-					}
-					/* Free the memory allocated by previous findfirst 
-					or findnext call - we can not reuse the memory since
-					the resume name may not be same string length */
-					if(cifsFile->search_resume_name)
-						kfree(cifsFile->search_resume_name);
-					cifsFile->search_resume_name = 
-						kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
-					cFYI(1,("fnext last file: %s with name %d bytes long",
-						pfindDataUnix->FileName,
-						cifsFile->resume_name_length));
-					if(cifsFile->search_resume_name == NULL) {
-						rc = -ENOMEM;
-						break;
-					}
-					memcpy(cifsFile->search_resume_name,
-						pfindDataUnix->FileName, 
-						cifsFile->resume_name_length);
-				}
-
-				for (i = 0; i < count; i++) {
-					__u32 len = le32_to_cpu(pfindData->
-							FileNameLength);
-					if (UnixSearch == FALSE) {
-						if (Unicode == TRUE)
-							len =
-							  cifs_strfromUCS_le
-							  (pfindData->FileName,
-							  (wchar_t *)
-							  pfindData->FileName,
-							  len / 2,
-							  cifs_sb->local_nls);
-						qstring.len = len;
-						if (((len != 1)
-						    || (pfindData->FileName[0] != '.'))
-						    && ((len != 2)
-							|| (pfindData->FileName[0] != '.')
-							|| (pfindData->FileName[1] !=
-							    '.'))) {
-							if(cifs_filldir
-							    (&qstring,
-							     pfindData,
-							     file, filldir,
-							     direntry)) {
-							/* do not end search if
-								kernel not ready to take
-								remaining entries yet */
-								findNextParms.EndofSearch = 0;
-								reset_resume_key(file, pfindData->FileName,qstring.len,
-									Unicode,cifs_sb->local_nls);
-								break;
-							}
-							file->f_pos++;
-						}
-					} else {	/* UnixSearch */
-						pfindDataUnix =
-						    (FILE_UNIX_INFO *)
-						    pfindData;
-						if (Unicode == TRUE)
-							qstring.len =
-							  cifs_strfromUCS_le
-							  (pfindDataUnix->FileName,
-							  (wchar_t *)
-							  pfindDataUnix->FileName,
-							  MAX_PATHCONF,
-							  cifs_sb->local_nls);
-						else
-							qstring.len =
-							  strnlen
-							  (pfindDataUnix->
-							  FileName,
-							  MAX_PATHCONF);
-						if (((qstring.len != 1)
-						     || (pfindDataUnix->
-							 FileName[0] != '.'))
-						    && ((qstring.len != 2)
-							|| (pfindDataUnix->
-							    FileName[0] != '.')
-							|| (pfindDataUnix->
-							    FileName[1] !=
-							    '.'))) {
-							if(cifs_filldir_unix
-							    (&qstring,
-							     pfindDataUnix,
-							     file, filldir,
-							     direntry)) {
-								/* do not end search if
-								kernel not ready to take
-								remaining entries yet */
-								findNextParms.EndofSearch = 0;
-								reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
-									Unicode,cifs_sb->local_nls);
-								break;
-							}
-							file->f_pos++;
-						}
-					}
-					pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
-						le32_to_cpu(pfindData->NextEntryOffset));
-	/* works also for Unix find struct since first field of both */
-	/* BB also should check to ensure pointer not beyond end of SMB */
-				} /* end for loop */
-				if (findNextParms.EndofSearch != 0) {
-					cifsFile->srch_inf.endOfSearch = TRUE;
-				}
-			} else {
-				cifsFile->srch_inf.endOfSearch = TRUE;
-				rc = 0;	/* unless parent directory disappeared - do not
-				return error here (eg Access Denied or no more files) */
-			}
-		}
-	} /* end switch */
-	if (data)
-		kfree(data);
-	if (full_path)
-		kfree(full_path);
-	FreeXid(xid);
-
-	return rc;
-}
-int cifs_prepare_write(struct file *file, struct page *page,
-			unsigned from, unsigned to)
+static int cifs_prepare_write(struct file *file, struct page *page,
+	unsigned from, unsigned to)
 {
 	int rc = 0;
         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
-	cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
+	cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
 	if (!PageUptodate(page)) {
 	/*	if (to - from != PAGE_CACHE_SIZE) {
 			void *kaddr = kmap_atomic(page, KM_USER0);
@@ -2409,33 +1652,33 @@ int cifs_prepare_write(struct file *file
 			kunmap_atomic(kaddr, KM_USER0);
 		} */
 		/* If we are writing a full page it will be up to date,
-		no need to read from the server */
-		if((to==PAGE_CACHE_SIZE) && (from == 0))
+		   no need to read from the server */
+		if ((to == PAGE_CACHE_SIZE) && (from == 0))
 			SetPageUptodate(page);
 
 		/* might as well read a page, it is fast enough */
-		if((file->f_flags & O_ACCMODE) != O_WRONLY) {
-			rc = cifs_readpage_worker(file,page,&offset);
+		if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+			rc = cifs_readpage_worker(file, page, &offset);
 		} else {
-		/* should we try using another
-		file handle if there is one - how would we lock it
-		to prevent close of that handle racing with this read? */
-		/* In any case this will be written out by commit_write */
+		/* should we try using another file handle if there is one -
+		   how would we lock it to prevent close of that handle
+		   racing with this read?
+		   In any case this will be written out by commit_write */
 		}
 	}
 
-	/* BB should we pass any errors back? e.g. if we do not have read access to the file */
+	/* BB should we pass any errors back? 
+	   e.g. if we do not have read access to the file */
 	return 0;
 }
 
-
 struct address_space_operations cifs_addr_ops = {
 	.readpage = cifs_readpage,
 	.readpages = cifs_readpages,
 	.writepage = cifs_writepage,
-	.prepare_write = cifs_prepare_write, 
+	.prepare_write = cifs_prepare_write,
 	.commit_write = cifs_commit_write,
 	.set_page_dirty = __set_page_dirty_nobuffers,
-   /* .sync_page = cifs_sync_page, */
-	/*.direct_IO = */
+	/* .sync_page = cifs_sync_page, */
+	/* .direct_IO = */
 };
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/inode.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -30,12 +30,8 @@
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
 
-extern int is_size_safe_to_change(struct cifsInodeInfo *);
-
-int
-cifs_get_inode_info_unix(struct inode **pinode,
-			 const unsigned char *search_path,
-			 struct super_block *sb,int xid)
+int cifs_get_inode_info_unix(struct inode **pinode,
+	const unsigned char *search_path, struct super_block *sb, int xid)
 {
 	int rc = 0;
 	FILE_UNIX_BASIC_INFO findData;
@@ -46,34 +42,37 @@ cifs_get_inode_info_unix(struct inode **
 
 	pTcon = cifs_sb->tcon;
 	cFYI(1, (" Getting info on %s ", search_path));
-	/* we could have done a find first instead but this returns more info */
+	/* could have done a find first instead but this returns more info */
 	rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
-				  cifs_sb->local_nls);
-	/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
+				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+/*	dump_mem("\nUnixQPathInfo return data", &findData,
+		 sizeof(findData)); */
 	if (rc) {
 		if (rc == -EREMOTE) {
 			tmp_path =
-			    kmalloc(strnlen
-				    (pTcon->treeName,
-				     MAX_TREE_SIZE + 1) +
+			    kmalloc(strnlen(pTcon->treeName,
+					    MAX_TREE_SIZE + 1) +
 				    strnlen(search_path, MAX_PATHCONF) + 1,
 				    GFP_KERNEL);
 			if (tmp_path == NULL) {
 				return -ENOMEM;
 			}
-        /* have to skip first of the double backslash of UNC name */
-			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);	
+        		/* have to skip first of the double backslash of
+			   UNC name */
+			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
 			strncat(tmp_path, search_path, MAX_PATHCONF);
 			rc = connect_to_dfs_path(xid, pTcon->ses,
 						 /* treename + */ tmp_path,
-						 cifs_sb->local_nls);
+						 cifs_sb->local_nls, 
+						 cifs_sb->mnt_cifs_flags & 
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 			kfree(tmp_path);
 
 			/* BB fix up inode etc. */
 		} else if (rc) {
 			return rc;
 		}
-
 	} else {
 		struct cifsInodeInfo *cifsInfo;
 		__u32 type = le32_to_cpu(findData.Type);
@@ -83,25 +82,26 @@ cifs_get_inode_info_unix(struct inode **
 		/* get new inode */
 		if (*pinode == NULL) {
 			*pinode = new_inode(sb);
-			if(*pinode == NULL) 
+			if (*pinode == NULL) 
 				return -ENOMEM;
 			/* Is an i_ino of zero legal? */
 			/* Are there sanity checks we can use to ensure that
-			the server is really filling in that field? */
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-				(*pinode)->i_ino = 
+			   the server is really filling in that field? */
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+				(*pinode)->i_ino =
 					(unsigned long)findData.UniqueId;
 			} /* note ino incremented to unique num in new_inode */
 			insert_inode_hash(*pinode);
 		}
-			
+
 		inode = *pinode;
 		cifsInfo = CIFS_I(inode);
 
 		cFYI(1, (" Old time %ld ", cifsInfo->time));
 		cifsInfo->time = jiffies;
 		cFYI(1, (" New time %ld ", cifsInfo->time));
-		atomic_set(&cifsInfo->inUse,1);	/* ok to set on every refresh of inode */
+		/* this is ok to set on every inode revalidate */
+		atomic_set(&cifsInfo->inUse,1);
 
 		inode->i_atime =
 		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
@@ -134,23 +134,20 @@ cifs_get_inode_info_unix(struct inode **
 		inode->i_gid = le64_to_cpu(findData.Gid);
 		inode->i_nlink = le64_to_cpu(findData.Nlinks);
 
-		if(is_size_safe_to_change(cifsInfo)) {
-		/* can not safely change the file size here if the 
+		if (is_size_safe_to_change(cifsInfo)) {
+		/* can not safely change the file size here if the
 		   client is writing to it due to potential races */
 
 			i_size_write(inode, end_of_file);
-/* blksize needs to be multiple of two. So safer to default to blksize
-	and blkbits set in superblock so 2**blkbits and blksize will match */
-/*		inode->i_blksize =
-		    (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
-
-		/* This seems incredibly stupid but it turns out that
-		i_blocks is not related to (i_size / i_blksize), instead a
-		size of 512 is required to be used for calculating num blocks */
-		 
 
-/*		inode->i_blocks = 
-	                (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/
+		/* blksize needs to be multiple of two. So safer to default to
+		blksize and blkbits set in superblock so 2**blkbits and blksize
+		will match rather than setting to:
+		(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
+
+		/* This seems incredibly stupid but it turns out that i_blocks
+		   is not related to (i_size / i_blksize), instead 512 byte size
+		   is required for calculating num blocks */
 
 		/* 512 bytes (2**9) is the fake blocksize that must be used */
 		/* for this calculation */
@@ -158,14 +155,17 @@ cifs_get_inode_info_unix(struct inode **
 		}
 
 		if (num_of_bytes < end_of_file)
-			cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
+			cFYI(1, ("allocation size less than end of file "));
 		cFYI(1,
-		     ("Size %ld and blocks %ld ",
+		     ("Size %ld and blocks %ld",
 		      (unsigned long) inode->i_size, inode->i_blocks));
 		if (S_ISREG(inode->i_mode)) {
 			cFYI(1, (" File inode "));
 			inode->i_op = &cifs_file_inode_ops;
-			inode->i_fop = &cifs_file_ops;
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+				inode->i_fop = &cifs_file_direct_ops;
+			else
+				inode->i_fop = &cifs_file_ops;
 			inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode"));
@@ -174,7 +174,7 @@ cifs_get_inode_info_unix(struct inode **
 		} else if (S_ISLNK(inode->i_mode)) {
 			cFYI(1, (" Symbolic Link inode "));
 			inode->i_op = &cifs_symlink_inode_ops;
-/* tmp_inode->i_fop = *//* do not need to set to anything */
+		/* tmp_inode->i_fop = */ /* do not need to set to anything */
 		} else {
 			cFYI(1, (" Init special inode "));
 			init_special_inode(inode, inode->i_mode,
@@ -184,9 +184,9 @@ cifs_get_inode_info_unix(struct inode **
 	return rc;
 }
 
-int
-cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, 
-		FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
+int cifs_get_inode_info(struct inode **pinode,
+	const unsigned char *search_path, FILE_ALL_INFO *pfindData,
+	struct super_block *sb, int xid)
 {
 	int rc = 0;
 	struct cifsTconInfo *pTcon;
@@ -198,22 +198,23 @@ cifs_get_inode_info(struct inode **pinod
 	pTcon = cifs_sb->tcon;
 	cFYI(1,("Getting info on %s ", search_path));
 
-	if((pfindData == NULL) && (*pinode != NULL)) {
-		if(CIFS_I(*pinode)->clientCanCacheRead) {
-			cFYI(1,("No need to revalidate inode sizes on cached file "));
+	if ((pfindData == NULL) && (*pinode != NULL)) {
+		if (CIFS_I(*pinode)->clientCanCacheRead) {
+			cFYI(1,("No need to revalidate cached inode sizes"));
 			return rc;
 		}
 	}
 
 	/* if file info not passed in then get it from server */
-	if(pfindData == NULL) {
-		buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
-		if(buf == NULL)
+	if (pfindData == NULL) {
+		buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+		if (buf == NULL)
 			return -ENOMEM;
 		pfindData = (FILE_ALL_INFO *)buf;
-	/* could do find first instead but this returns more info */
+		/* could do find first instead but this returns more info */
 		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
-			      cifs_sb->local_nls);
+			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
 	}
 	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
 	if (rc) {
@@ -225,8 +226,7 @@ cifs_get_inode_info(struct inode **pinod
 				    strnlen(search_path, MAX_PATHCONF) + 1,
 				    GFP_KERNEL);
 			if (tmp_path == NULL) {
-				if(buf)
-					kfree(buf);
+				kfree(buf);
 				return -ENOMEM;
 			}
 
@@ -234,12 +234,13 @@ cifs_get_inode_info(struct inode **pinod
 			strncat(tmp_path, search_path, MAX_PATHCONF);
 			rc = connect_to_dfs_path(xid, pTcon->ses,
 						 /* treename + */ tmp_path,
-						 cifs_sb->local_nls);
+						 cifs_sb->local_nls, 
+						 cifs_sb->mnt_cifs_flags & 
+						   CIFS_MOUNT_MAP_SPECIAL_CHR);
 			kfree(tmp_path);
 			/* BB fix up inode etc. */
 		} else if (rc) {
-			if(buf)
-				kfree(buf);
+			kfree(buf);
 			return rc;
 		}
 	} else {
@@ -249,23 +250,40 @@ cifs_get_inode_info(struct inode **pinod
 		/* get new inode */
 		if (*pinode == NULL) {
 			*pinode = new_inode(sb);
-			if(*pinode == NULL)
+			if (*pinode == NULL)
 				return -ENOMEM;
-			/* Is an i_ino of zero legal? */
-			/* Are there sanity checks we can use to ensure that
-			the server is really filling in that field? */
-
-			/* We can not use the IndexNumber from either
-			Windows or Samba as it is frequently set to zero */
-			/* There may be higher info levels that work but
-			Are there Windows server or network appliances
-			for which IndexNumber field is not guaranteed unique? */
-		
-			/* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-				(*pinode)->i_ino = 
-					(unsigned long)pfindData->IndexNumber;
-			} */ /*NB: ino incremented to unique num in new_inode*/
-
+			/* Is an i_ino of zero legal? Can we use that to check
+			   if the server supports returning inode numbers?  Are
+			   there other sanity checks we can use to ensure that
+			   the server is really filling in that field? */
+
+			/* We can not use the IndexNumber field by default from
+			   Windows or Samba (in ALL_INFO buf) but we can request
+			   it explicitly.  It may not be unique presumably if
+			   the server has multiple devices mounted under one
+			   share */
+
+			/* There may be higher info levels that work but are
+			   there Windows server or network appliances for which
+			   IndexNumber field is not guaranteed unique? */
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL		
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
+				int rc1 = 0;
+				__u64 inode_num;
+
+				rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 
+					search_path, &inode_num, 
+					cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (rc1) {
+					cFYI(1,("GetSrvInodeNum rc %d", rc1));
+					/* BB EOPNOSUPP disable SERVER_INUM? */
+				} else /* do we need cast or hash to ino? */
+					(*pinode)->i_ino = inode_num;
+			} /* else ino incremented to unique num in new_inode*/
+#endif /* CIFS_EXPERIMENTAL */
 			insert_inode_hash(*pinode);
 		}
 		inode = *pinode;
@@ -275,10 +293,10 @@ cifs_get_inode_info(struct inode **pinod
 		cifsInfo->time = jiffies;
 		cFYI(1, (" New time %ld ", cifsInfo->time));
 
-/* blksize needs to be multiple of two. So safer to default to blksize
-        and blkbits set in superblock so 2**blkbits and blksize will match */
-/*		inode->i_blksize =
-		    (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
+		/* blksize needs to be multiple of two. So safer to default to
+		blksize and blkbits set in superblock so 2**blkbits and blksize
+		will match rather than setting to:
+		(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
 
 		/* Linux can not store file creation time unfortunately so we ignore it */
 		inode->i_atime =
@@ -287,56 +305,60 @@ cifs_get_inode_info(struct inode **pinod
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
 		inode->i_ctime =
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
-		cFYI(0,
-		     (" Attributes came in as 0x%x ", attr));
+		cFYI(0, (" Attributes came in as 0x%x ", attr));
 
 		/* set default mode. will override for dirs below */
-		if(atomic_read(&cifsInfo->inUse) == 0)
+		if (atomic_read(&cifsInfo->inUse) == 0)
 			/* new inode, can safely set these fields */
 			inode->i_mode = cifs_sb->mnt_file_mode;
 
 /*		if (attr & ATTR_REPARSE)  */
-/* 		We no longer handle these as symlinks because we could not */
-/* 		follow them due to the absolute path with drive letter */
+		/* We no longer handle these as symlinks because we could not
+		   follow them due to the absolute path with drive letter */
 		if (attr & ATTR_DIRECTORY) {
-	/* override default perms since we do not do byte range locking on dirs */
+		/* override default perms since we do not do byte range locking
+		   on dirs */
 			inode->i_mode = cifs_sb->mnt_dir_mode;
 			inode->i_mode |= S_IFDIR;
 		} else {
 			inode->i_mode |= S_IFREG;
-			/* treat the dos attribute of read-only as read-only mode e.g. 555 */
-			if(cifsInfo->cifsAttrs & ATTR_READONLY)
+			/* treat the dos attribute of read-only as read-only
+			   mode e.g. 555 */
+			if (cifsInfo->cifsAttrs & ATTR_READONLY)
 				inode->i_mode &= ~(S_IWUGO);
-   /* BB add code here - validate if device or weird share or device type? */
+		/* BB add code here -
+		   validate if device or weird share or device type? */
 		}
-		if(is_size_safe_to_change(cifsInfo)) {
-		/* can not safely change the file size here if the 
-		client is writing to it due to potential races */
-
+		if (is_size_safe_to_change(cifsInfo)) {
+			/* can not safely change the file size here if the
+			   client is writing to it due to potential races */
 			i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
 
-		/* 512 bytes (2**9) is the fake blocksize that must be used */
-		/* for this calculation */
-			inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))
-				 >> 9;
+			/* 512 bytes (2**9) is the fake blocksize that must be
+			   used for this calculation */
+			inode->i_blocks = (512 - 1 + le64_to_cpu(
+					   pfindData->AllocationSize)) >> 9;
 		}
 
 		inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
 		/* BB fill in uid and gid here? with help from winbind? 
-			or retrieve from NTFS stream extended attribute */
-		if(atomic_read(&cifsInfo->inUse) == 0) {
+		   or retrieve from NTFS stream extended attribute */
+		if (atomic_read(&cifsInfo->inUse) == 0) {
 			inode->i_uid = cifs_sb->mnt_uid;
 			inode->i_gid = cifs_sb->mnt_gid;
 			/* set so we do not keep refreshing these fields with
-			bad data after user has changed them in memory */
+			   bad data after user has changed them in memory */
 			atomic_set(&cifsInfo->inUse,1);
 		}
-		
+
 		if (S_ISREG(inode->i_mode)) {
 			cFYI(1, (" File inode "));
 			inode->i_op = &cifs_file_inode_ops;
-			inode->i_fop = &cifs_file_ops;
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+				inode->i_fop = &cifs_file_direct_ops;
+			else
+				inode->i_fop = &cifs_file_ops;
 			inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode "));
@@ -350,14 +372,13 @@ cifs_get_inode_info(struct inode **pinod
 					   inode->i_rdev);
 		}
 	}
-	if(buf)
-	    kfree(buf);
+	kfree(buf);
 	return rc;
 }
 
-void
-cifs_read_inode(struct inode *inode)
-{				/* gets root inode */
+/* gets root inode */
+void cifs_read_inode(struct inode *inode)
+{
 	int xid;
 	struct cifs_sb_info *cifs_sb;
 
@@ -371,8 +392,7 @@ cifs_read_inode(struct inode *inode)
 	_FreeXid(xid);
 }
 
-int
-cifs_unlink(struct inode *inode, struct dentry *direntry)
+int cifs_unlink(struct inode *inode, struct dentry *direntry)
 {
 	int rc = 0;
 	int xid;
@@ -380,7 +400,7 @@ cifs_unlink(struct inode *inode, struct 
 	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
 	struct cifsInodeInfo *cifsInode;
-	FILE_BASIC_INFO * pinfo_buf;
+	FILE_BASIC_INFO *pinfo_buf;
 
 	cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
 
@@ -389,80 +409,137 @@ cifs_unlink(struct inode *inode, struct 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-/* Unlink can be called from rename so we can not grab
-	the sem here since we deadlock otherwise */
+	/* Unlink can be called from rename so we can not grab the sem here
+	   since we deadlock otherwise */
 /*	down(&direntry->d_sb->s_vfs_rename_sem);*/
 	full_path = build_path_from_dentry(direntry);
 /*	up(&direntry->d_sb->s_vfs_rename_sem);*/
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
-	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 	if (!rc) {
-		direntry->d_inode->i_nlink--;
+		if (direntry->d_inode)
+			direntry->d_inode->i_nlink--;
 	} else if (rc == -ENOENT) {
 		d_drop(direntry);
 	} else if (rc == -ETXTBSY) {
 		int oplock = FALSE;
 		__u16 netfid;
 
-		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, 
-				CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
-				&netfid, &oplock, NULL, cifs_sb->local_nls);
-		if(rc==0) {
-			CIFSSMBRenameOpenFile(xid,pTcon,netfid,
-				NULL, cifs_sb->local_nls);
+		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
+				 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+				 &netfid, &oplock, NULL, cifs_sb->local_nls,
+				 cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc==0) {
+			CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
+					      cifs_sb->local_nls, 
+					      cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			CIFSSMBClose(xid, pTcon, netfid);
-			direntry->d_inode->i_nlink--;
+			if (direntry->d_inode)
+				direntry->d_inode->i_nlink--;
 		}
 	} else if (rc == -EACCES) {
 		/* try only if r/o attribute set in local lookup data? */
-		pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
-		if(pinfo_buf) {
-			memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));        
-		/* ATTRS set to normal clears r/o bit */
+		pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
+		if (pinfo_buf) {
+			memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
+			/* ATTRS set to normal clears r/o bit */
 			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
-			rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
-				cifs_sb->local_nls);
+			if (!(pTcon->ses->flags & CIFS_SES_NT4))
+				rc = CIFSSMBSetTimes(xid, pTcon, full_path,
+						     pinfo_buf,
+						     cifs_sb->local_nls,
+						     cifs_sb->mnt_cifs_flags & 
+							CIFS_MOUNT_MAP_SPECIAL_CHR);
+			else
+				rc = -EOPNOTSUPP;
+
+			if (rc == -EOPNOTSUPP) {
+				int oplock = FALSE;
+				__u16 netfid;
+			/*	rc = CIFSSMBSetAttrLegacy(xid, pTcon,
+							  full_path,
+							  (__u16)ATTR_NORMAL,
+							  cifs_sb->local_nls); 
+			   For some strange reason it seems that NT4 eats the
+			   old setattr call without actually setting the
+			   attributes so on to the third attempted workaround
+			   */
+
+			/* BB could scan to see if we already have it open
+			   and pass in pid of opener to function */
+				rc = CIFSSMBOpen(xid, pTcon, full_path,
+						 FILE_OPEN, SYNCHRONIZE |
+						 FILE_WRITE_ATTRIBUTES, 0,
+						 &netfid, &oplock, NULL,
+						 cifs_sb->local_nls,
+						 cifs_sb->mnt_cifs_flags & 
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (rc==0) {
+					rc = CIFSSMBSetFileTimes(xid, pTcon,
+								 pinfo_buf,
+								 netfid);
+					CIFSSMBClose(xid, pTcon, netfid);
+				}
+			}
 			kfree(pinfo_buf);
 		}
-		if(rc==0) {
-			rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+		if (rc==0) {
+			rc = CIFSSMBDelFile(xid, pTcon, full_path, 
+					    cifs_sb->local_nls, 
+					    cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			if (!rc) {
-				direntry->d_inode->i_nlink--;
+				if (direntry->d_inode)
+					direntry->d_inode->i_nlink--;
 			} else if (rc == -ETXTBSY) {
 				int oplock = FALSE;
 				__u16 netfid;
 
-				rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
-						CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
-						&netfid, &oplock, NULL, cifs_sb->local_nls);
-				if(rc==0) {
-					CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
+				rc = CIFSSMBOpen(xid, pTcon, full_path,
+						 FILE_OPEN, DELETE,
+						 CREATE_NOT_DIR |
+						 CREATE_DELETE_ON_CLOSE,
+						 &netfid, &oplock, NULL,
+						 cifs_sb->local_nls, 
+						 cifs_sb->mnt_cifs_flags & 
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (rc==0) {
+					CIFSSMBRenameOpenFile(xid, pTcon,
+						netfid, NULL,
+						cifs_sb->local_nls,
+						cifs_sb->mnt_cifs_flags &
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 					CIFSSMBClose(xid, pTcon, netfid);
-		                        direntry->d_inode->i_nlink--;
+					if (direntry->d_inode)
+			                        direntry->d_inode->i_nlink--;
 				}
 			/* BB if rc = -ETXTBUSY goto the rename logic BB */
 			}
 		}
 	}
-	cifsInode = CIFS_I(direntry->d_inode);
-	cifsInode->time = 0;	/* will force revalidate to get info when needed */
-	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
-	    current_fs_time(inode->i_sb);
+	if (direntry->d_inode) {
+		cifsInode = CIFS_I(direntry->d_inode);
+		cifsInode->time = 0;	/* will force revalidate to get info
+					   when needed */
+		direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
+	}
+	inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
 	cifsInode = CIFS_I(inode);
 	cifsInode->time = 0;	/* force revalidate of dir as well */
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
 
-int
-cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
+int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
 	int rc = 0;
 	int xid;
@@ -481,12 +558,13 @@ cifs_mkdir(struct inode *inode, struct d
 	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
-	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
+	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
+			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
 		d_drop(direntry);
@@ -496,40 +574,43 @@ cifs_mkdir(struct inode *inode, struct d
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						      inode->i_sb,xid);
 		else
-			rc = cifs_get_inode_info(&newinode, full_path,NULL,
+			rc = cifs_get_inode_info(&newinode, full_path, NULL,
 						 inode->i_sb,xid);
 
 		direntry->d_op = &cifs_dentry_ops;
 		d_instantiate(direntry, newinode);
-		if(direntry->d_inode)
+		if (direntry->d_inode)
 			direntry->d_inode->i_nlink = 2;
 		if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-						(__u64)current->euid,  
-						(__u64)current->egid,
-						0 /* dev_t */,
-						cifs_sb->local_nls);
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+				CIFSSMBUnixSetPerms(xid, pTcon, full_path,
+						    mode,
+						    (__u64)current->euid,
+						    (__u64)current->egid,
+						    0 /* dev_t */,
+						    cifs_sb->local_nls,
+						    cifs_sb->mnt_cifs_flags &
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 			} else {
-				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-						(__u64)-1,  
-						(__u64)-1,
-						0 /* dev_t */,
-						cifs_sb->local_nls);
+				CIFSSMBUnixSetPerms(xid, pTcon, full_path,
+						    mode, (__u64)-1,
+						    (__u64)-1, 0 /* dev_t */,
+						    cifs_sb->local_nls,
+						    cifs_sb->mnt_cifs_flags & 
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
-		else { /* BB to be implemented via Windows secrty descriptors*/
-		/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+		else {
+			/* BB to be implemented via Windows secrty descriptors
+			   eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
+						 -1, -1, local_nls); */
 		}
 	}
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
-int
-cifs_rmdir(struct inode *inode, struct dentry *direntry)
+int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 {
 	int rc = 0;
 	int xid;
@@ -548,12 +629,13 @@ cifs_rmdir(struct inode *inode, struct d
 	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
+	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
+			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 	if (!rc) {
 		inode->i_nlink--;
@@ -562,19 +644,18 @@ cifs_rmdir(struct inode *inode, struct d
 	}
 
 	cifsInode = CIFS_I(direntry->d_inode);
-	cifsInode->time = 0;	/* force revalidate to go get info when needed */
+	cifsInode->time = 0;	/* force revalidate to go get info when
+				   needed */
 	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
-	    current_fs_time(inode->i_sb);
+		current_fs_time(inode->i_sb);
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
 
-int
-cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
-	    struct inode *target_inode, struct dentry *target_direntry)
+int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
+	struct inode *target_inode, struct dentry *target_direntry)
 {
 	char *fromName;
 	char *toName;
@@ -591,83 +672,103 @@ cifs_rename(struct inode *source_inode, 
 	pTcon = cifs_sb_source->tcon;
 
 	if (pTcon != cifs_sb_target->tcon) {
-		FreeXid(xid);    
-		return -EXDEV;	/* BB actually could be allowed if same server, but
-                     different share. Might eventually add support for this */
+		FreeXid(xid);
+		return -EXDEV;	/* BB actually could be allowed if same server,
+				   but different share.
+				   Might eventually add support for this */
 	}
 
-	/* we already  have the rename sem so we do not need
-	to grab it again here to protect the path integrity */
+	/* we already  have the rename sem so we do not need to grab it again
+	   here to protect the path integrity */
 	fromName = build_path_from_dentry(source_direntry);
 	toName = build_path_from_dentry(target_direntry);
-	if((fromName == NULL) || (toName == NULL)) {
+	if ((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
 	rc = CIFSSMBRename(xid, pTcon, fromName, toName,
-			   cifs_sb_source->local_nls);
-	if(rc == -EEXIST) {
-		/* check if they are the same file 
-		because rename of hardlinked files is a noop */
-		FILE_UNIX_BASIC_INFO * info_buf_source;
-		FILE_UNIX_BASIC_INFO * info_buf_target;
-
-		info_buf_source = 
-			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
-		if(info_buf_source != NULL) {
-			info_buf_target = info_buf_source+1;
-			rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, 
-				info_buf_source, cifs_sb_source->local_nls);
-			if(rc == 0) {
-				rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
+			   cifs_sb_source->local_nls,
+			   cifs_sb_source->mnt_cifs_flags &
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc == -EEXIST) {
+		/* check if they are the same file because rename of hardlinked
+		   files is a noop */
+		FILE_UNIX_BASIC_INFO *info_buf_source;
+		FILE_UNIX_BASIC_INFO *info_buf_target;
+
+		info_buf_source =
+			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+		if (info_buf_source != NULL) {
+			info_buf_target = info_buf_source + 1;
+			rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+				info_buf_source, cifs_sb_source->local_nls, 
+				cifs_sb_source->mnt_cifs_flags &
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+			if (rc == 0) {
+				rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
 						info_buf_target,
-						cifs_sb_target->local_nls);
+						cifs_sb_target->local_nls,
+						/* remap based on source sb */
+						cifs_sb_source->mnt_cifs_flags &
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
-			if((rc == 0) && 
-				(info_buf_source->UniqueId == 
-				 info_buf_target->UniqueId)) {
-			/* do not rename since the files are hardlinked 
-			   which is a noop */
+			if ((rc == 0) &&
+			    (info_buf_source->UniqueId ==
+			     info_buf_target->UniqueId)) {
+			/* do not rename since the files are hardlinked which
+			   is a noop */
 			} else {
 			/* we either can not tell the files are hardlinked
-			(as with Windows servers) or files are not hardlinked 
-			so delete the target manually before renaming to
-			follow POSIX rather than Windows semantics */
+			   (as with Windows servers) or files are not
+			   hardlinked so delete the target manually before
+			   renaming to follow POSIX rather than Windows
+			   semantics */
 				cifs_unlink(target_inode, target_direntry);
-				rc = CIFSSMBRename(xid, pTcon, fromName, toName,
-					cifs_sb_source->local_nls);
+				rc = CIFSSMBRename(xid, pTcon, fromName,
+						   toName,
+						   cifs_sb_source->local_nls,
+						   cifs_sb_source->mnt_cifs_flags
+						   & CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
 			kfree(info_buf_source);
 		} /* if we can not get memory just leave rc as EEXIST */
 	}
 
-	if((rc == -EIO)||(rc == -EEXIST)) {
+	if (rc) {
+		cFYI(1, ("rename rc %d", rc));
+	}
+
+	if ((rc == -EIO) || (rc == -EEXIST)) {
 		int oplock = FALSE;
 		__u16 netfid;
 
+		/* BB FIXME Is Generic Read correct for rename? */
+		/* if renaming directory - we should not say CREATE_NOT_DIR,
+		   need to test renaming open directory, also GENERIC_READ
+		   might not right be right access to request */
 		rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
-					CREATE_NOT_DIR,
-					&netfid, &oplock, NULL, cifs_sb_source->local_nls);
-		if(rc==0) {
-			CIFSSMBRenameOpenFile(xid,pTcon,netfid,
-					toName, cifs_sb_source->local_nls);
+				 CREATE_NOT_DIR, &netfid, &oplock, NULL,
+				 cifs_sb_source->local_nls, 
+				 cifs_sb_source->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc==0) {
+			CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
+					      cifs_sb_source->local_nls, 
+					      cifs_sb_source->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			CIFSSMBClose(xid, pTcon, netfid);
 		}
 	}
 
 cifs_rename_exit:
-	if (fromName)
-		kfree(fromName);
-	if (toName)
-		kfree(toName);
-
+	kfree(fromName);
+	kfree(toName);
 	FreeXid(xid);
 	return rc;
 }
 
-int
-cifs_revalidate(struct dentry *direntry)
+int cifs_revalidate(struct dentry *direntry)
 {
 	int xid;
 	int rc = 0;
@@ -678,118 +779,120 @@ cifs_revalidate(struct dentry *direntry)
 	struct timespec local_mtime;
 	int invalidate_inode = FALSE;
 
-	if(direntry->d_inode == NULL)
+	if (direntry->d_inode == NULL)
 		return -ENOENT;
 
 	cifsInode = CIFS_I(direntry->d_inode);
 
-	if(cifsInode == NULL)
+	if (cifsInode == NULL)
 		return -ENOENT;
 
 	/* no sense revalidating inode info on file that no one can write */
-	if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
+	if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
 		return rc;
 
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(direntry->d_sb);
 
-	/* can not safely grab the rename sem here if
-	rename calls revalidate since that would deadlock */
+	/* can not safely grab the rename sem here if rename calls revalidate
+	   since that would deadlock */
 	full_path = build_path_from_dentry(direntry);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
-	cFYI(1,
-	     ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
-	      full_path, direntry->d_inode,
-	      direntry->d_inode->i_count.counter, direntry,
-	      direntry->d_time, jiffies));
+	cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
+		 "jiffies %ld", full_path, direntry->d_inode,
+		 direntry->d_inode->i_count.counter, direntry,
+		 direntry->d_time, jiffies));
 
-	if (cifsInode->time == 0){
+	if (cifsInode->time == 0) {
 		/* was set to zero previously to force revalidate */
-	} else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
-	    if((S_ISREG(direntry->d_inode->i_mode) == 0) || 
-			(direntry->d_inode->i_nlink == 1)) {  
-			if (full_path)
-				kfree(full_path);
+	} else if (time_before(jiffies, cifsInode->time + HZ) &&
+		   lookupCacheEnabled) {
+		if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
+		    (direntry->d_inode->i_nlink == 1)) {
+			kfree(full_path);
 			FreeXid(xid);
 			return rc;
 		} else {
-			cFYI(1,("Have to revalidate file due to hardlinks"));
-		}            
+			cFYI(1, ("Have to revalidate file due to hardlinks"));
+		}
 	}
-	
+
 	/* save mtime and size */
 	local_mtime = direntry->d_inode->i_mtime;
-	local_size  = direntry->d_inode->i_size;
+	local_size = direntry->d_inode->i_size;
 
 	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
 		rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
-					 direntry->d_sb,xid);
-		if(rc) {
-			cFYI(1,("error on getting revalidate info %d",rc));
-/*			if(rc != -ENOENT)
-				rc = 0; */ /* BB should we cache info on certain errors? */
+					      direntry->d_sb,xid);
+		if (rc) {
+			cFYI(1, ("error on getting revalidate info %d", rc));
+/*			if (rc != -ENOENT)
+				rc = 0; */	/* BB should we cache info on
+						   certain errors? */
 		}
 	} else {
 		rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
-				    direntry->d_sb,xid);
-		if(rc) {
-			cFYI(1,("error on getting revalidate info %d",rc));
-/*			if(rc != -ENOENT)
-				rc = 0; */  /* BB should we cache info on certain errors? */
+					 direntry->d_sb,xid);
+		if (rc) {
+			cFYI(1, ("error on getting revalidate info %d", rc));
+/*			if (rc != -ENOENT)
+				rc = 0; */	/* BB should we cache info on
+						   certain errors? */
 		}
 	}
 	/* should we remap certain errors, access denied?, to zero */
 
-	/* if not oplocked, we invalidate inode pages if mtime 
-	   or file size had changed on server */
+	/* if not oplocked, we invalidate inode pages if mtime or file size
+	   had changed on server */
 
-	if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
-		(local_size == direntry->d_inode->i_size)) {
-		cFYI(1,("cifs_revalidate - inode unchanged"));
+	if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
+	    (local_size == direntry->d_inode->i_size)) {
+		cFYI(1, ("cifs_revalidate - inode unchanged"));
 	} else {
 		/* file may have changed on server */
-		if(cifsInode->clientCanCacheRead) {
-			/* no need to invalidate inode pages since we were
-			   the only ones who could have modified the file and
-			   the server copy is staler than ours */
+		if (cifsInode->clientCanCacheRead) {
+			/* no need to invalidate inode pages since we were the
+			   only ones who could have modified the file and the
+			   server copy is staler than ours */
 		} else {
 			invalidate_inode = TRUE;
 		}
 	}
 
-	/* can not grab this sem since kernel filesys locking
-		documentation indicates i_sem may be taken by the kernel 
-		on lookup and rename which could deadlock if we grab
-		the i_sem here as well */
+	/* can not grab this sem since kernel filesys locking documentation
+	   indicates i_sem may be taken by the kernel on lookup and rename
+	   which could deadlock if we grab the i_sem here as well */
 /*	down(&direntry->d_inode->i_sem);*/
 	/* need to write out dirty pages here  */
-	if(direntry->d_inode->i_mapping) {
-		/* do we need to lock inode until after invalidate completes below? */
+	if (direntry->d_inode->i_mapping) {
+		/* do we need to lock inode until after invalidate completes
+		   below? */
 		filemap_fdatawrite(direntry->d_inode->i_mapping);
 	}
-	if(invalidate_inode) {
-		filemap_fdatawait(direntry->d_inode->i_mapping);
+	if (invalidate_inode) {
+		if (direntry->d_inode->i_mapping)
+			filemap_fdatawait(direntry->d_inode->i_mapping);
 		/* may eventually have to do this for open files too */
-		if(list_empty(&(cifsInode->openFileList))) {
+		if (list_empty(&(cifsInode->openFileList))) {
 			/* Has changed on server - flush read ahead pages */
-			cFYI(1,("Invalidating read ahead data on closed file"));
+			cFYI(1, ("Invalidating read ahead data on "
+				 "closed file"));
 			invalidate_remote_inode(direntry->d_inode);
 		}
 	}
-/*	up(&direntry->d_inode->i_sem);*/
+/*	up(&direntry->d_inode->i_sem); */
 	
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
-int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+	struct kstat *stat)
 {
 	int err = cifs_revalidate(dentry);
 	if (!err)
@@ -800,7 +903,7 @@ int cifs_getattr(struct vfsmount *mnt, s
 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
 {
 	pgoff_t index = from >> PAGE_CACHE_SHIFT;
-	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	unsigned offset = from & (PAGE_CACHE_SIZE - 1);
 	struct page *page;
 	char *kaddr;
 	int rc = 0;
@@ -818,8 +921,7 @@ static int cifs_truncate_page(struct add
 	return rc;
 }
 
-int
-cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 {
 	int xid;
 	struct cifs_sb_info *cifs_sb;
@@ -834,20 +936,19 @@ cifs_setattr(struct dentry *direntry, st
 	__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
 	__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
 	struct cifsInodeInfo *cifsInode;
-	struct list_head * tmp;
+	struct list_head *tmp;
 
 	xid = GetXid();
 
-	cFYI(1,
-	     (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
-	      direntry->d_name.name, attrs->ia_valid));
+	cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
+		 direntry->d_name.name, attrs->ia_valid));
 	cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
 	up(&direntry->d_sb->s_vfs_rename_sem);
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
@@ -856,73 +957,86 @@ cifs_setattr(struct dentry *direntry, st
 	/* BB check if we need to refresh inode from server now ? BB */
 
 	/* need to flush data before changing file size on server */
-	filemap_fdatawrite(direntry->d_inode->i_mapping); 
+	filemap_fdatawrite(direntry->d_inode->i_mapping);
 	filemap_fdatawait(direntry->d_inode->i_mapping);
 
 	if (attrs->ia_valid & ATTR_SIZE) {
-		read_lock(&GlobalSMBSeslock); 
-		/* To avoid spurious oplock breaks from server, in the case
-			of inodes that we already have open, avoid doing path
-			based setting of file size if we can do it by handle.
-			This keeps our caching token (oplock) and avoids
-			timeouts when the local oplock break takes longer to flush
-			writebehind data than the SMB timeout for the SetPathInfo 
-			request would allow */
-		list_for_each(tmp, &cifsInode->openFileList) {            
-			open_file = list_entry(tmp,struct cifsFileInfo, flist);
+		read_lock(&GlobalSMBSeslock);
+		/* To avoid spurious oplock breaks from server, in the case of
+		   inodes that we already have open, avoid doing path based
+		   setting of file size if we can do it by handle.
+		   This keeps our caching token (oplock) and avoids timeouts
+		   when the local oplock break takes longer to flush
+		   writebehind data than the SMB timeout for the SetPathInfo
+		   request would allow */
+		list_for_each(tmp, &cifsInode->openFileList) {
+			open_file = list_entry(tmp, struct cifsFileInfo,
+					       flist);
 			/* We check if file is open for writing first */
-			if((open_file->pfile) &&
-				((open_file->pfile->f_flags & O_RDWR) || 
-				 (open_file->pfile->f_flags & O_WRONLY))) {
-				if(open_file->invalidHandle == FALSE) {
-					/* we found a valid, writeable network file 
-					handle to use to try to set the file size */
+			if ((open_file->pfile) &&
+			    ((open_file->pfile->f_flags & O_RDWR) ||
+			    (open_file->pfile->f_flags & O_WRONLY))) {
+				if (open_file->invalidHandle == FALSE) {
+					/* we found a valid, writeable network
+					   file handle to use to try to set the
+					   file size */
 					__u16 nfid = open_file->netfid;
 					__u32 npid = open_file->pid;
 					read_unlock(&GlobalSMBSeslock);
 					found = TRUE;
-					rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
-					   nfid,npid,FALSE);
-					cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
-				/* Do not need reopen and retry on EAGAIN since we will
-					retry by pathname below */
-
-					break;  /* now that we found one valid file handle no
-						sense continuing to loop trying others */
+					rc = CIFSSMBSetFileSize(xid, pTcon,
+						attrs->ia_size, nfid, npid,
+						FALSE);
+					cFYI(1, ("SetFileSize by handle "
+						 "(setattrs) rc = %d", rc));
+					/* Do not need reopen and retry on
+					   EAGAIN since we will retry by
+					   pathname below */
+
+					/* now that we found one valid file
+					   handle no sense continuing to loop
+					   trying others, so break here */
+					break;
 				}
 			}
 		}
-		if(found == FALSE) {
+		if (found == FALSE)
 			read_unlock(&GlobalSMBSeslock);
-		}
-
 
-		if(rc != 0) {
-			/* Set file size by pathname rather than by handle either
-			because no valid, writeable file handle for it was found or
-			because there was an error setting it by handle */
-			rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
-				   cifs_sb->local_nls);
-			cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
-		}
-        
-	/*  Server is ok setting allocation size implicitly - no need to call: */
-	/*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
+		if (rc != 0) {
+			/* Set file size by pathname rather than by handle
+			   either because no valid, writeable file handle for
+			   it was found or because there was an error setting
+			   it by handle */
+			rc = CIFSSMBSetEOF(xid, pTcon, full_path,
+					   attrs->ia_size, FALSE,
+					   cifs_sb->local_nls, 
+					   cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+			cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
+		}
+
+		/* Server is ok setting allocation size implicitly - no need
+		   to call:
+		CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
+			 cifs_sb->local_nls);
+		   */
 
 		if (rc == 0) {
 			rc = vmtruncate(direntry->d_inode, attrs->ia_size);
-			cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
+			cifs_truncate_page(direntry->d_inode->i_mapping,
+					   direntry->d_inode->i_size);
 		}
 	}
 	if (attrs->ia_valid & ATTR_UID) {
 		cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
 		uid = attrs->ia_uid;
-		/*        entry->uid = cpu_to_le16(attr->ia_uid); */
+		/* entry->uid = cpu_to_le16(attr->ia_uid); */
 	}
 	if (attrs->ia_valid & ATTR_GID) {
 		cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
 		gid = attrs->ia_gid;
-		/*      entry->gid = cpu_to_le16(attr->ia_gid); */
+		/* entry->gid = cpu_to_le16(attr->ia_gid); */
 	}
 
 	time_buf.Attributes = 0;
@@ -935,19 +1049,25 @@ cifs_setattr(struct dentry *direntry, st
 	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
 	    && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
 		rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
-				0 /* dev_t */, cifs_sb->local_nls);
+					 0 /* dev_t */, cifs_sb->local_nls,
+					 cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else if (attrs->ia_valid & ATTR_MODE) {
-		if((mode & S_IWUGO) == 0) /* not writeable */ {
-			if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
-				time_buf.Attributes = 
-					cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
-		} else if((mode & S_IWUGO) == S_IWUGO) {
-			if(cifsInode->cifsAttrs & ATTR_READONLY)
-				time_buf.Attributes = 
-					cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
-		}
-		/* BB to be implemented - via Windows security descriptors or streams */
-		/* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
+		if ((mode & S_IWUGO) == 0) /* not writeable */ {
+			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
+				time_buf.Attributes =
+					cpu_to_le32(cifsInode->cifsAttrs |
+						    ATTR_READONLY);
+		} else if ((mode & S_IWUGO) == S_IWUGO) {
+			if (cifsInode->cifsAttrs & ATTR_READONLY)
+				time_buf.Attributes =
+					cpu_to_le32(cifsInode->cifsAttrs &
+						    (~ATTR_READONLY));
+		}
+		/* BB to be implemented -
+		   via Windows security descriptors or streams */
+		/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
+				      cifs_sb->local_nls); */
 	}
 
 	if (attrs->ia_valid & ATTR_ATIME) {
@@ -966,45 +1086,67 @@ cifs_setattr(struct dentry *direntry, st
 
 	if (attrs->ia_valid & ATTR_CTIME) {
 		set_time = TRUE;
-		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
+		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
 		time_buf.ChangeTime =
 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
 	} else
 		time_buf.ChangeTime = 0;
 
 	if (set_time || time_buf.Attributes) {
-		/* BB what if setting one attribute fails  
-			(such as size) but time setting works */
+		/* BB what if setting one attribute fails (such as size) but
+		   time setting works? */
 		time_buf.CreationTime = 0;	/* do not change */
 		/* In the future we should experiment - try setting timestamps
-			 via Handle (SetFileInfo) instead of by path */
-		rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
-				cifs_sb->local_nls);
-		if(rc == -EOPNOTSUPP) {
-			cFYI(1,("OS2 level of SetPathInfo not implemented"));
-			/* Need to convert time_buf into old format, 
-			but probably better to do that inside the function
-			below rather than here */
-			/* Better to return EOPNOTSUPP until function
-			below is ready */
-			/* CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
-        	        FILE_INFO_STANDARD * data, cifs_sb->local_nls); */
+		   via Handle (SetFileInfo) instead of by path */
+		if (!(pTcon->ses->flags & CIFS_SES_NT4))
+			rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
+					     cifs_sb->local_nls,
+					     cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		else
+			rc = -EOPNOTSUPP;
+
+		if (rc == -EOPNOTSUPP) {
+			int oplock = FALSE;
+			__u16 netfid;
+
+			cFYI(1, ("calling SetFileInfo since SetPathInfo for "
+				 "times not supported by this server"));
+			/* BB we could scan to see if we already have it open
+			   and pass in pid of opener to function */
+			rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
+					 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+					 CREATE_NOT_DIR, &netfid, &oplock,
+					 NULL, cifs_sb->local_nls,
+					 cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+			if (rc==0) {
+				rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
+							 netfid);
+				CIFSSMBClose(xid, pTcon, netfid);
+			} else {
+			/* BB For even older servers we could convert time_buf
+			   into old DOS style which uses two second
+			   granularity */
+
+			/* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
+        	        		&time_buf, cifs_sb->local_nls); */
+			}
 		}
 	}
 
-	/* do not  need local check to inode_check_ok since the server does that */
+	/* do not need local check to inode_check_ok since the server does
+	   that */
 	if (!rc)
 		rc = inode_setattr(direntry->d_inode, attrs);
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
 
-void
-cifs_delete_inode(struct inode *inode)
+void cifs_delete_inode(struct inode *inode)
 {
 	cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
 	/* may have to add back in if and when safe distributed caching of
-		directories added e.g. via FindNotify */
+	   directories added e.g. via FindNotify */
 }
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
new file mode 100644
--- /dev/null
+++ b/fs/cifs/ioctl.c
@@ -0,0 +1,112 @@
+/*
+ *   fs/cifs/ioctl.c
+ *
+ *   vfs operations that deal with io control
+ *
+ *   Copyright (C) International Business Machines  Corp., 2005
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This 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.
+ *
+ *   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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; 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/ext2_fs.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifsfs.h"
+
+#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
+
+int cifs_ioctl (struct inode * inode, struct file * filep, 
+		unsigned int command, unsigned long arg)
+{
+	int rc = -ENOTTY; /* strange error - but the precedent */
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+#ifdef CONFIG_CIFS_POSIX
+	__u64	ExtAttrBits = 0;
+	__u64	ExtAttrMask = 0;
+	__u64   caps;
+	struct cifsTconInfo *tcon;
+	struct cifsFileInfo *pSMBFile =
+		(struct cifsFileInfo *)filep->private_data;
+#endif /* CONFIG_CIFS_POSIX */
+
+	xid = GetXid();
+
+        cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+
+#ifdef CONFIG_CIFS_POSIX
+	tcon = cifs_sb->tcon;
+	if(tcon)
+		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	else {
+		rc = -EIO;
+		FreeXid(xid);
+		return -EIO;
+	}
+#endif /* CONFIG_CIFS_POSIX */
+
+	switch(command) {
+		case CIFS_IOC_CHECKUMOUNT:
+			cFYI(1,("User unmount attempted"));
+			if(cifs_sb->mnt_uid == current->uid)
+				rc = 0;
+			else {
+				rc = -EACCES;
+				cFYI(1,("uids do not match"));
+			}
+			break;
+#ifdef CONFIG_CIFS_POSIX
+		case EXT2_IOC_GETFLAGS:
+			if(CIFS_UNIX_EXTATTR_CAP & caps) {
+				if (pSMBFile == NULL)
+					break;
+				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+					&ExtAttrBits, &ExtAttrMask);
+				if(rc == 0)
+					rc = put_user(ExtAttrBits &
+						EXT2_FL_USER_VISIBLE,
+						(int __user *)arg);
+			}
+			break;
+
+		case EXT2_IOC_SETFLAGS:
+			if(CIFS_UNIX_EXTATTR_CAP & caps) {
+				if(get_user(ExtAttrBits,(int __user *)arg)) {
+					rc = -EFAULT;
+					break;
+				}
+				if (pSMBFile == NULL)
+					break;
+				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
+					extAttrBits, &ExtAttrMask);*/
+				
+			}
+			cFYI(1,("set flags not implemented yet"));
+			break;
+#endif /* CONFIG_CIFS_POSIX */
+		default:
+			cFYI(1,("unsupported ioctl"));
+			break;
+	}
+
+	FreeXid(xid);
+	return rc;
+} 
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -59,10 +59,14 @@ cifs_hardlink(struct dentry *old_file, s
 
 	if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
 		rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
-					    cifs_sb_target->local_nls);
+					    cifs_sb_target->local_nls, 
+					    cifs_sb_target->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else {
 		rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-					cifs_sb_target->local_nls);
+					cifs_sb_target->local_nls, 
+					cifs_sb_target->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 		if(rc == -EIO)
 			rc = -EOPNOTSUPP;  
 	}
@@ -260,7 +264,10 @@ cifs_readlink(struct dentry *direntry, c
 				cifs_sb->local_nls);
 	else {
 		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
-				OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
+				OPEN_REPARSE_POINT,&fid, &oplock, NULL, 
+				cifs_sb->local_nls, 
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 		if(!rc) {
 			rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
 				tmpbuffer,
@@ -279,7 +286,10 @@ cifs_readlink(struct dentry *direntry, c
 					strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
 					strncat(tmp_path, full_path, MAX_PATHCONF);
 					rc = get_dfs_path(xid, pTcon->ses, tmp_path,
-						cifs_sb->local_nls, &num_referrals, &referrals);
+						cifs_sb->local_nls,
+						&num_referrals, &referrals,
+						cifs_sb->mnt_cifs_flags &
+						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 					cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
 					if((num_referrals == 0) && (rc == 0))
 						rc = -EACCES;
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c
--- a/fs/cifs/md4.c
+++ b/fs/cifs/md4.c
@@ -21,6 +21,8 @@
 */
 #include <linux/module.h>
 #include <linux/fs.h>
+#include "cifsencrypt.h"
+
 /* NOTE: This code makes no attempt to be fast! */
 
 static __u32
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -28,12 +28,13 @@
 #include "cifs_debug.h"
 #include "smberr.h"
 #include "nterr.h"
+#include "cifs_unicode.h"
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern struct task_struct * oplockThread;
 
-__u16 GlobalMid;		/* multiplex id - rotating counter */
+static __u16 GlobalMid;		/* multiplex id - rotating counter */
 
 /* The xid serves as a useful identifier for each incoming vfs request, 
    in a similar way to the mid which is useful to track each sent smb, 
@@ -353,10 +354,14 @@ checkSMB(struct smb_hdr *smb, __u16 mid,
 	if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
 	    (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
 		if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
-			cERROR(1, ("Length less than 2 + sizeof smb_hdr "));
-			if (((unsigned int)length >= sizeof (struct smb_hdr) - 1)
-			    && (smb->Status.CifsError != 0))
+			if (((unsigned int)length >= 
+				sizeof (struct smb_hdr) - 1)
+			    && (smb->Status.CifsError != 0)) {
+				smb->WordCount = 0;
 				return 0;	/* some error cases do not return wct and bcc */
+			} else {
+				cERROR(1, ("Length less than smb header size"));
+			}
 
 		}
 		if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
@@ -447,25 +452,30 @@ is_valid_oplock_break(struct smb_hdr *bu
 			atomic_inc(&tcon->num_oplock_brks);
 #endif
 			list_for_each(tmp1,&tcon->openFileList){
-				netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
+				netfile = list_entry(tmp1,struct cifsFileInfo,
+						     tlist);
 				if(pSMB->Fid == netfile->netfid) {
 					struct cifsInodeInfo *pCifsInode;
 					read_unlock(&GlobalSMBSeslock);
-					cFYI(1,("Matching file id, processing oplock break"));
+					cFYI(1,("file id match, oplock break"));
 					pCifsInode = 
 						CIFS_I(netfile->pInode);
 					pCifsInode->clientCanCacheAll = FALSE;
 					if(pSMB->OplockLevel == 0)
-						pCifsInode->clientCanCacheRead = FALSE;
+						pCifsInode->clientCanCacheRead
+							= FALSE;
 					pCifsInode->oplockPending = TRUE;
-					AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
+					AllocOplockQEntry(netfile->pInode,
+							  netfile->netfid,
+							  tcon);
 					cFYI(1,("about to wake up oplock thd"));
-					wake_up_process(oplockThread);               
+					if(oplockThread)
+					    wake_up_process(oplockThread);
 					return TRUE;
 				}
 			}
 			read_unlock(&GlobalSMBSeslock);
-			cFYI(1,("No matching file for oplock break on connection"));
+			cFYI(1,("No matching file for oplock break"));
 			return TRUE;
 		}
 	}
@@ -486,7 +496,7 @@ dump_smb(struct smb_hdr *smb_buf, int sm
 
 	buffer = (unsigned char *) smb_buf;
 	for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
-		if (i % 8 == 0) {	/* we have reached the beginning of line  */
+		if (i % 8 == 0) {	/* have reached the beginning of line */
 			printk(KERN_DEBUG "| ");
 			j = 0;
 		}
@@ -497,7 +507,7 @@ dump_smb(struct smb_hdr *smb_buf, int sm
 		else
 			debug_line[1 + (2 * j)] = '_';
 
-		if (i % 8 == 7) {	/* we have reached end of line, time to print ascii */
+		if (i % 8 == 7) { /* reached end of line, time to print ascii */
 			debug_line[16] = 0;
 			printk(" | %s\n", debug_line);
 		}
@@ -510,3 +520,142 @@ dump_smb(struct smb_hdr *smb_buf, int sm
 	printk( " | %s\n", debug_line);
 	return;
 }
+
+/* Windows maps these to the user defined 16 bit Unicode range since they are
+   reserved symbols (along with \ and /), otherwise illegal to store
+   in filenames in NTFS */
+#define UNI_ASTERIK     (__u16) ('*' + 0xF000)
+#define UNI_QUESTION    (__u16) ('?' + 0xF000)
+#define UNI_COLON       (__u16) (':' + 0xF000)
+#define UNI_GRTRTHAN    (__u16) ('>' + 0xF000)
+#define UNI_LESSTHAN    (__u16) ('<' + 0xF000)
+#define UNI_PIPE        (__u16) ('|' + 0xF000)
+#define UNI_SLASH       (__u16) ('\\' + 0xF000)
+
+/* Convert 16 bit Unicode pathname from wire format to string in current code
+   page.  Conversion may involve remapping up the seven characters that are
+   only legal in POSIX-like OS (if they are present in the string). Path
+   names are little endian 16 bit Unicode on the wire */
+int
+cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
+		    const struct nls_table * cp)
+{
+	int i,j,len;
+	__u16 src_char;
+
+	for(i = 0, j = 0; i < maxlen; i++) {
+		src_char = le16_to_cpu(source[i]);
+		switch (src_char) {
+			case 0:
+				goto cUCS_out; /* BB check this BB */
+			case UNI_COLON:
+				target[j] = ':';
+				break;
+			case UNI_ASTERIK:
+				target[j] = '*';
+				break;
+			case UNI_QUESTION:
+				target[j] = '?';
+				break;
+			/* BB We can not handle remapping slash until
+			   all the calls to build_path_from_dentry
+			   are modified, as they use slash as separator BB */
+			/* case UNI_SLASH:
+				target[j] = '\\';
+				break;*/
+			case UNI_PIPE:
+				target[j] = '|';
+				break;
+			case UNI_GRTRTHAN:
+				target[j] = '>';
+				break;
+			case UNI_LESSTHAN:
+				target[j] = '<';
+				break;
+			default: 
+				len = cp->uni2char(src_char, &target[j], 
+						NLS_MAX_CHARSET_SIZE);
+				if(len > 0) {
+					j += len;
+					continue;
+				} else {
+					target[j] = '?';
+				}
+		}
+		j++;
+		/* make sure we do not overrun callers allocated temp buffer */
+		if(j >= (2 * NAME_MAX))
+			break;
+	}
+cUCS_out:
+	target[j] = 0;
+	return j;
+}
+
+/* Convert 16 bit Unicode pathname to wire format from string in current code
+   page.  Conversion may involve remapping up the seven characters that are
+   only legal in POSIX-like OS (if they are present in the string). Path
+   names are little endian 16 bit Unicode on the wire */
+int
+cifsConvertToUCS(__le16 * target, const char *source, int maxlen, 
+		 const struct nls_table * cp, int mapChars)
+{
+	int i,j,charlen;
+	int len_remaining = maxlen;
+	char src_char;
+
+	if(!mapChars) 
+		return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
+
+	for(i = 0, j = 0; i < maxlen; j++) {
+		src_char = source[i];
+		switch (src_char) {
+			case 0:
+				goto ctoUCS_out;
+			case ':':
+				target[j] = cpu_to_le16(UNI_COLON);
+				break;
+			case '*':
+				target[j] = cpu_to_le16(UNI_ASTERIK);
+				break;
+			case '?':
+				target[j] = cpu_to_le16(UNI_QUESTION);
+				break;
+			case '<':
+				target[j] = cpu_to_le16(UNI_LESSTHAN);
+				break;
+			case '>':
+				target[j] = cpu_to_le16(UNI_GRTRTHAN);
+				break;
+			case '|':
+				target[j] = cpu_to_le16(UNI_PIPE);
+				break;			
+			/* BB We can not handle remapping slash until
+			   all the calls to build_path_from_dentry
+			   are modified, as they use slash as separator BB */
+			/* case '\\':
+				target[j] = cpu_to_le16(UNI_SLASH);
+				break;*/
+			default:
+				charlen = cp->char2uni(source+i,
+					len_remaining, target+j);
+				/* if no match, use question mark, which
+				at least in some cases servers as wild card */
+				if(charlen < 1) {
+					target[j] = cpu_to_le16(0x003f);
+					charlen = 1;
+				}
+				len_remaining -= charlen;
+				/* character may take more than one byte in the
+				   the source string, but will take exactly two
+				   bytes in the target string */
+				i+= charlen;
+				continue;
+		}
+		i++; /* move to next char in source string */
+		len_remaining--;
+	}
+
+ctoUCS_out:
+	return i;
+}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -43,7 +43,7 @@ struct smb_to_posix_error {
 	int posix_code;
 };
 
-const struct smb_to_posix_error mapping_table_ERRDOS[] = {
+static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 	{ERRbadfunc, -EINVAL},
 	{ERRbadfile, -ENOENT},
 	{ERRbadpath, -ENOTDIR},
@@ -78,10 +78,11 @@ const struct smb_to_posix_error mapping_
 	{ErrQuota, -EDQUOT},
 	{ErrNotALink, -ENOLINK},
 	{ERRnetlogonNotStarted,-ENOPROTOOPT},
+	{ErrTooManyLinks,-EMLINK},
 	{0, 0}
 };
 
-const struct smb_to_posix_error mapping_table_ERRSRV[] = {
+static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
 	{ERRerror, -EIO},
 	{ERRbadpw, -EPERM},
 	{ERRbadtype, -EREMOTE},
@@ -120,7 +121,7 @@ const struct smb_to_posix_error mapping_
 	{0, 0}
 };
 
-const struct smb_to_posix_error mapping_table_ERRHRD[] = {
+static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
 	{0, 0}
 };
 
@@ -206,7 +207,7 @@ static const struct {
 	{
 	ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
 	ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
-	ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
+	ERRDOS, ERRinvlevel, NT_STATUS_INVALID_INFO_CLASS}, {
 	ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
 	ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
 	ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
@@ -742,7 +743,7 @@ static const struct {
 	ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
 	ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
 	ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
-	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
+	ERRDOS, ErrTooManyLinks, NT_STATUS_TOO_MANY_LINKS}, {
 	ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
 	ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
 	ERRDOS, 21, 0xc000026e}, {
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -35,7 +35,7 @@
 #define NTLMSSP_NEGOTIATE_SIGN        0x0010	// Request signature capability
 #define NTLMSSP_NEGOTIATE_SEAL        0x0020	// Request confidentiality
 #define NTLMSSP_NEGOTIATE_DGRAM       0x0040
-#define NTLMSSP_NEGOTIATE_LM_KEY      0x0080	// Use LM session key for sign/seal
+#define NTLMSSP_NEGOTIATE_LM_KEY      0x0080 // Use LM session key for sign/seal
 #define NTLMSSP_NEGOTIATE_NTLM        0x0200	// NTLM authentication
 #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -3,7 +3,7 @@
  *
  *   Directory search handling
  * 
- *   Copyright (C) International Business Machines  Corp., 2004
+ *   Copyright (C) International Business Machines  Corp., 2004, 2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -29,31 +29,15 @@
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
-
-extern int CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon,
-            const char *searchName, const struct nls_table *nls_codepage,
-            __u16 *searchHandle, struct cifs_search_info * psrch_inf);
-
-extern int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
-            __u16 searchHandle, struct cifs_search_info * psrch_inf);
-
-extern int construct_dentry(struct qstr *qstring, struct file *file,
-		 struct inode **ptmp_inode, struct dentry **pnew_dentry);
-
-extern void fill_in_inode(struct inode *tmp_inode,
-	      FILE_DIRECTORY_INFO * pfindData, int *pobject_type);
-
-extern void unix_fill_in_inode(struct inode *tmp_inode,
-	      FILE_UNIX_INFO * pfindData, int *pobject_type);
-
+#include "cifsfs.h"
 
 /* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file * file, char * label)
+/* static void dump_cifs_file_struct(struct file *file, char *label)
 {
 	struct cifsFileInfo * cf;
 
 	if(file) {
-		cf = (struct cifsFileInfo *)file->private_data;
+		cf = file->private_data;
 		if(cf == NULL) {
 			cFYI(1,("empty cifs private file data"));
 			return;
@@ -71,7 +55,271 @@ extern void unix_fill_in_inode(struct in
 	}
 } */
 
-static int initiate_cifs_search(const int xid, struct file * file)
+/* Returns one if new inode created (which therefore needs to be hashed) */
+/* Might check in the future if inode number changed so we can rehash inode */
+static int construct_dentry(struct qstr *qstring, struct file *file,
+	struct inode **ptmp_inode, struct dentry **pnew_dentry)
+{
+	struct dentry *tmp_dentry;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	int rc = 0;
+
+	cFYI(1, ("For %s", qstring->name));
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	qstring->hash = full_name_hash(qstring->name, qstring->len);
+	tmp_dentry = d_lookup(file->f_dentry, qstring);
+	if (tmp_dentry) {
+		cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
+		*ptmp_inode = tmp_dentry->d_inode;
+/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
+		if(*ptmp_inode == NULL) {
+			*ptmp_inode = new_inode(file->f_dentry->d_sb);
+			if(*ptmp_inode == NULL)
+				return rc;
+			rc = 1;
+			d_instantiate(tmp_dentry, *ptmp_inode);
+		}
+	} else {
+		tmp_dentry = d_alloc(file->f_dentry, qstring);
+		if(tmp_dentry == NULL) {
+			cERROR(1,("Failed allocating dentry"));
+			*ptmp_inode = NULL;
+			return rc;
+		}
+
+		*ptmp_inode = new_inode(file->f_dentry->d_sb);
+		tmp_dentry->d_op = &cifs_dentry_ops;
+		if(*ptmp_inode == NULL)
+			return rc;
+		rc = 1;
+		d_instantiate(tmp_dentry, *ptmp_inode);
+		d_rehash(tmp_dentry);
+	}
+
+	tmp_dentry->d_time = jiffies;
+	*pnew_dentry = tmp_dentry;
+	return rc;
+}
+
+static void fill_in_inode(struct inode *tmp_inode,
+	FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
+{
+	loff_t local_size;
+	struct timespec local_mtime;
+
+	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
+	__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
+	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
+
+	cifsInfo->cifsAttrs = attr;
+	cifsInfo->time = jiffies;
+
+	/* save mtime and size */
+	local_mtime = tmp_inode->i_mtime;
+	local_size  = tmp_inode->i_size;
+
+	/* Linux can not store file creation time unfortunately so ignore it */
+	tmp_inode->i_atime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+	tmp_inode->i_mtime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+	tmp_inode->i_ctime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
+	/* 2767 perms - indicate mandatory locking */
+		/* BB fill in uid and gid here? with help from winbind? 
+		   or retrieve from NTFS stream extended attribute */
+	if (atomic_read(&cifsInfo->inUse) == 0) {
+		tmp_inode->i_uid = cifs_sb->mnt_uid;
+		tmp_inode->i_gid = cifs_sb->mnt_gid;
+		/* set default mode. will override for dirs below */
+		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
+	}
+
+	if (attr & ATTR_DIRECTORY) {
+		*pobject_type = DT_DIR;
+		/* override default perms since we do not lock dirs */
+		if(atomic_read(&cifsInfo->inUse) == 0) {
+			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
+		}
+		tmp_inode->i_mode |= S_IFDIR;
+/* we no longer mark these because we could not follow them */
+/*        } else if (attr & ATTR_REPARSE) {
+                *pobject_type = DT_LNK;
+                tmp_inode->i_mode |= S_IFLNK; */
+	} else {
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+		if (attr & ATTR_READONLY)
+			tmp_inode->i_mode &= ~(S_IWUGO);
+	} /* could add code here - to validate if device or weird share type? */
+
+	/* can not fill in nlink here as in qpathinfo version and Unx search */
+	if (atomic_read(&cifsInfo->inUse) == 0) {
+		atomic_set(&cifsInfo->inUse, 1);
+	}
+
+	if (is_size_safe_to_change(cifsInfo)) {
+		/* can not safely change the file size here if the 
+		client is writing to it due to potential races */
+		i_size_write(tmp_inode, end_of_file);
+
+	/* 512 bytes (2**9) is the fake blocksize that must be used */
+	/* for this calculation, even though the reported blocksize is larger */
+		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
+	}
+
+	if (allocation_size < end_of_file)
+		cFYI(1, ("May be sparse file, allocation less than file size"));
+	cFYI(1,
+	     ("File Size %ld and blocks %ld and blocksize %ld",
+	      (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
+	      tmp_inode->i_blksize));
+	if (S_ISREG(tmp_inode->i_mode)) {
+		cFYI(1, ("File inode"));
+		tmp_inode->i_op = &cifs_file_inode_ops;
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+			tmp_inode->i_fop = &cifs_file_direct_ops;
+		else
+			tmp_inode->i_fop = &cifs_file_ops;
+		tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+		if(isNewInode)
+			return; /* No sense invalidating pages for new inode since we
+					   have not started caching readahead file data yet */
+
+		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+			(local_size == tmp_inode->i_size)) {
+			cFYI(1, ("inode exists but unchanged"));
+		} else {
+			/* file may have changed on server */
+			cFYI(1, ("invalidate inode, readdir detected change"));
+			invalidate_remote_inode(tmp_inode);
+		}
+	} else if (S_ISDIR(tmp_inode->i_mode)) {
+		cFYI(1, ("Directory inode"));
+		tmp_inode->i_op = &cifs_dir_inode_ops;
+		tmp_inode->i_fop = &cifs_dir_ops;
+	} else if (S_ISLNK(tmp_inode->i_mode)) {
+		cFYI(1, ("Symbolic Link inode"));
+		tmp_inode->i_op = &cifs_symlink_inode_ops;
+	} else {
+		cFYI(1, ("Init special inode"));
+		init_special_inode(tmp_inode, tmp_inode->i_mode,
+				   tmp_inode->i_rdev);
+	}
+}
+
+static void unix_fill_in_inode(struct inode *tmp_inode,
+	FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode)
+{
+	loff_t local_size;
+	struct timespec local_mtime;
+
+	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+
+	__u32 type = le32_to_cpu(pfindData->Type);
+	__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
+	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
+	cifsInfo->time = jiffies;
+	atomic_inc(&cifsInfo->inUse);
+
+	/* save mtime and size */
+	local_mtime = tmp_inode->i_mtime;
+	local_size  = tmp_inode->i_size;
+
+	tmp_inode->i_atime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+	tmp_inode->i_mtime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
+	tmp_inode->i_ctime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
+
+	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
+	if (type == UNIX_FILE) {
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+	} else if (type == UNIX_SYMLINK) {
+		*pobject_type = DT_LNK;
+		tmp_inode->i_mode |= S_IFLNK;
+	} else if (type == UNIX_DIR) {
+		*pobject_type = DT_DIR;
+		tmp_inode->i_mode |= S_IFDIR;
+	} else if (type == UNIX_CHARDEV) {
+		*pobject_type = DT_CHR;
+		tmp_inode->i_mode |= S_IFCHR;
+		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
+				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
+	} else if (type == UNIX_BLOCKDEV) {
+		*pobject_type = DT_BLK;
+		tmp_inode->i_mode |= S_IFBLK;
+		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
+				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
+	} else if (type == UNIX_FIFO) {
+		*pobject_type = DT_FIFO;
+		tmp_inode->i_mode |= S_IFIFO;
+	} else if (type == UNIX_SOCKET) {
+		*pobject_type = DT_SOCK;
+		tmp_inode->i_mode |= S_IFSOCK;
+	}
+
+	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+	tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
+
+	if (is_size_safe_to_change(cifsInfo)) {
+		/* can not safely change the file size here if the 
+		client is writing to it due to potential races */
+		i_size_write(tmp_inode,end_of_file);
+
+	/* 512 bytes (2**9) is the fake blocksize that must be used */
+	/* for this calculation, not the real blocksize */
+		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
+	}
+
+	if (S_ISREG(tmp_inode->i_mode)) {
+		cFYI(1, ("File inode"));
+		tmp_inode->i_op = &cifs_file_inode_ops;
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+			tmp_inode->i_fop = &cifs_file_direct_ops;
+		else
+			tmp_inode->i_fop = &cifs_file_ops;
+		tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+		if(isNewInode)
+			return; /* No sense invalidating pages for new inode since we
+					   have not started caching readahead file data yet */
+
+		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+			(local_size == tmp_inode->i_size)) {
+			cFYI(1, ("inode exists but unchanged"));
+		} else {
+			/* file may have changed on server */
+			cFYI(1, ("invalidate inode, readdir detected change"));
+			invalidate_remote_inode(tmp_inode);
+		}
+	} else if (S_ISDIR(tmp_inode->i_mode)) {
+		cFYI(1, ("Directory inode"));
+		tmp_inode->i_op = &cifs_dir_inode_ops;
+		tmp_inode->i_fop = &cifs_dir_ops;
+	} else if (S_ISLNK(tmp_inode->i_mode)) {
+		cFYI(1, ("Symbolic Link inode"));
+		tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+	} else {
+		cFYI(1, ("Special inode")); 
+		init_special_inode(tmp_inode, tmp_inode->i_mode,
+				   tmp_inode->i_rdev);
+	}
+}
+
+static int initiate_cifs_search(const int xid, struct file *file)
 {
 	int rc = 0;
 	char * full_path;
@@ -89,10 +337,13 @@ static int initiate_cifs_search(const in
 	} else {
 		memset(file->private_data,0,sizeof(struct cifsFileInfo));
 	}
-	cifsFile = (struct cifsFileInfo *)file->private_data;
+	cifsFile = file->private_data;
 	cifsFile->invalidHandle = TRUE;
 	cifsFile->srch_inf.endOfSearch = FALSE;
 
+	if(file->f_dentry == NULL)
+		return -ENOENT;
+
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	if(cifs_sb == NULL)
 		return -EINVAL;
@@ -101,39 +352,42 @@ static int initiate_cifs_search(const in
 	if(pTcon == NULL)
 		return -EINVAL;
 
-	if(file->f_dentry == NULL)
-		return -ENOENT;
-
 	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_wildcard_path_from_dentry(file->f_dentry);
+	full_path = build_path_from_dentry(file->f_dentry);
 	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
 		return -ENOMEM;
 	}
 
-	cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
+	cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
 
+ffirst_retry:
 	/* test for Unix extensions */
 	if (pTcon->ses->capabilities & CAP_UNIX) {
-		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 
 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
 	} else /* not srvinos - BB fixme add check for backlevel? */ {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
 	}
 
-	rc = CIFSFindFirst2(xid, pTcon,full_path,cifs_sb->local_nls, 
-		&cifsFile->netfid, &cifsFile->srch_inf); 
+	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
+		&cifsFile->netfid, &cifsFile->srch_inf,
+		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
-	if(full_path)
-		kfree(full_path);
+	if((rc == -EOPNOTSUPP) && 
+		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+		goto ffirst_retry;
+	}
+	kfree(full_path);
 	return rc;
 }
 
 /* return length of unicode string in bytes */
-static int cifs_unicode_bytelen(char * str)
+static int cifs_unicode_bytelen(char *str)
 {
 	int len;
 	__le16 * ustr = (__le16 *)str;
@@ -146,7 +400,7 @@ static int cifs_unicode_bytelen(char * s
 	return len << 1;
 }
 
-static char * nxt_dir_entry(char * old_entry, char * end_of_smb)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
 {
 	char * new_entry;
 	FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
@@ -155,10 +409,15 @@ static char * nxt_dir_entry(char * old_e
 	cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
 	/* validate that new_entry is not past end of SMB */
 	if(new_entry >= end_of_smb) {
-		cFYI(1,("search entry %p began after end of SMB %p old entry %p",
-			new_entry,end_of_smb,old_entry)); 
+		cERROR(1,
+		      ("search entry %p began after end of SMB %p old entry %p",
+			new_entry, end_of_smb, old_entry)); 
 		return NULL;
-	} else
+	} else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+		cERROR(1,("search entry %p extends after end of SMB %p",
+			new_entry, end_of_smb));
+		return NULL;
+	} else 
 		return new_entry;
 
 }
@@ -166,7 +425,7 @@ static char * nxt_dir_entry(char * old_e
 #define UNICODE_DOT cpu_to_le16(0x2e)
 
 /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
-static int cifs_entry_is_dot(char * current_entry, struct cifsFileInfo * cfile)
+static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 {
 	int rc = 0;
 	char * filename = NULL;
@@ -238,14 +497,14 @@ static int cifs_entry_is_dot(char * curr
    assume that they are located in the findfirst return buffer.*/
 /* We start counting in the buffer with entry 2 and increment for every
    entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const int xid, struct cifsTconInfo * pTcon, 
-		struct file * file, char ** ppCurrentEntry,int * num_to_ret) 
+static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
+	struct file *file, char **ppCurrentEntry, int *num_to_ret) 
 {
 	int rc = 0;
 	int pos_in_buf = 0;
 	loff_t first_entry_in_buffer;
 	loff_t index_to_find = file->f_pos;
-	struct cifsFileInfo * cifsFile = (struct cifsFileInfo *)file->private_data;
+	struct cifsFileInfo * cifsFile = file->private_data;
 	/* check if index in the buffer */
 	
 	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL))
@@ -261,12 +520,10 @@ static int find_cifs_entry(const int xid
 		cFYI(1,("search backing up - close and restart search"));
 		cifsFile->invalidHandle = TRUE;
 		CIFSFindClose(xid, pTcon, cifsFile->netfid);
-		if(cifsFile->search_resume_name) {
-			kfree(cifsFile->search_resume_name);
-			cifsFile->search_resume_name = NULL;
-		}
+		kfree(cifsFile->search_resume_name);
+		cifsFile->search_resume_name = NULL;
 		if(cifsFile->srch_inf.ntwrk_buf_start) {
-			cFYI(1,("freeing SMB ff cache buf on search rewind")); 
+			cFYI(1,("freeing SMB ff cache buf on search rewind"));
 			cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
 		}
 		rc = initiate_cifs_search(xid,file);
@@ -279,7 +536,7 @@ static int find_cifs_entry(const int xid
 	while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
 	      (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
 	 	cFYI(1,("calling findnext2"));
-		rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
+		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
 		if(rc)
 			return -ENOENT;
 	}
@@ -289,10 +546,11 @@ static int find_cifs_entry(const int xid
 		int i;
 		char * current_entry;
 		char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
-			smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start);
+			smbCalcSize((struct smb_hdr *)
+				cifsFile->srch_inf.ntwrk_buf_start);
 /*	dump_cifs_file_struct(file,"found entry in fce "); */
-		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry -
-			cifsFile->srch_inf.entries_in_buffer;
+		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
+					- cifsFile->srch_inf.entries_in_buffer;
 		pos_in_buf = index_to_find - first_entry_in_buffer;
 		cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
 		current_entry = cifsFile->srch_inf.srch_entries_start;
@@ -311,7 +569,10 @@ static int find_cifs_entry(const int xid
 			current_entry = nxt_dir_entry(current_entry,end_of_smb);
 		}
 		if((current_entry == NULL) && (i < pos_in_buf)) {
-			cERROR(1,("reached end of buf searching for pos in buf %d index to find %lld rc %d",pos_in_buf,index_to_find,rc)); /* BB removeme BB */
+			/* BB fixme - check if we should flag this error */
+			cERROR(1,("reached end of buf searching for pos in buf"
+			  " %d index to find %lld rc %d",
+			  pos_in_buf,index_to_find,rc));
 		}
 		rc = 0;
 		*ppCurrentEntry = current_entry;
@@ -331,13 +592,14 @@ static int find_cifs_entry(const int xid
 }
 
 /* inode num, inode type and filename returned */
-static int cifs_get_name_from_search_buf(struct qstr * pqst,char * current_entry,
-			__u16 level,unsigned int unicode,struct nls_table * nlt,
-			ino_t * pinum)
+static int cifs_get_name_from_search_buf(struct qstr *pqst,
+	char *current_entry, __u16 level, unsigned int unicode,
+	struct cifs_sb_info * cifs_sb, ino_t *pinum)
 {
 	int rc = 0;
 	unsigned int len = 0;
 	char * filename;
+	struct nls_table * nlt = cifs_sb->local_nls;
 
 	*pinum = 0;
 
@@ -353,7 +615,8 @@ static int cifs_get_name_from_search_buf
 		}
 
 		/* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */
-		*pinum = pFindData->UniqueId;
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+			*pinum = pFindData->UniqueId;
 	} else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
 		FILE_DIRECTORY_INFO * pFindData = 
 			(FILE_DIRECTORY_INFO *)current_entry;
@@ -382,7 +645,12 @@ static int cifs_get_name_from_search_buf
 	if(unicode) {
 		/* BB fixme - test with long names */
 		/* Note converted filename can be longer than in unicode */
-		pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt);
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+			pqst->len = cifs_convertUCSpath((char *)pqst->name,
+					(__le16 *)filename, len/2, nlt);
+		else
+			pqst->len = cifs_strfromUCS_le((char *)pqst->name,
+					(wchar_t *)filename,len/2,nlt);
 	} else {
 		pqst->name = filename;
 		pqst->len = len;
@@ -392,10 +660,8 @@ static int cifs_get_name_from_search_buf
 	return rc;
 }
 
-
-static int
-cifs_filldir2(char * pfindEntry, struct file *file, 
-			  filldir_t filldir, void *direntry,char * scratch_buf)
+static int cifs_filldir(char *pfindEntry, struct file *file,
+	filldir_t filldir, void *direntry, char *scratch_buf)
 {
 	int rc = 0;
 	struct qstr qstring;
@@ -425,7 +691,7 @@ cifs_filldir2(char * pfindEntry, struct 
 	qstring.name = scratch_buf;
 	rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
 			pCifsF->srch_inf.info_level,
-			pCifsF->srch_inf.unicode,cifs_sb->local_nls,
+			pCifsF->srch_inf.unicode,cifs_sb,
 			&inum /* returned */);
 
 	if(rc)
@@ -444,10 +710,15 @@ cifs_filldir2(char * pfindEntry, struct 
 		insert_inode_hash(tmp_inode);
 	}
 
+	/* we pass in rc below, indicating whether it is a new inode,
+	   so we can figure out whether to invalidate the inode cached
+	   data if the file has changed */
 	if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
-		unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type);
+		unix_fill_in_inode(tmp_inode,
+				   (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
 	} else {
-		fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type);
+		fill_in_inode(tmp_inode,
+			      (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
 	}
 	
 	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
@@ -459,7 +730,8 @@ cifs_filldir2(char * pfindEntry, struct 
 	return rc;
 }
 
-int cifs_save_resume_key(const char * current_entry,struct cifsFileInfo * cifsFile)
+static int cifs_save_resume_key(const char *current_entry,
+	struct cifsFileInfo *cifsFile)
 {
 	int rc = 0;
 	unsigned int len = 0;
@@ -515,7 +787,7 @@ int cifs_save_resume_key(const char * cu
 	return rc;
 }
 
-int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir)
+int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
 	int rc = 0;
 	int xid,i;
@@ -579,7 +851,7 @@ int cifs_readdir2(struct file *file, voi
 			FreeXid(xid);
 			return rc;
 		}
-		cifsFile = (struct cifsFileInfo *) file->private_data;
+		cifsFile = file->private_data;
 		if (cifsFile->srch_inf.endOfSearch) {
 			if(cifsFile->srch_inf.emptyDir) {
 				cFYI(1, ("End of search, empty dir"));
@@ -590,11 +862,10 @@ int cifs_readdir2(struct file *file, voi
 			cifsFile->invalidHandle = TRUE;
 			CIFSFindClose(xid, pTcon, cifsFile->netfid);
 		} 
-		if(cifsFile->search_resume_name) {
-			kfree(cifsFile->search_resume_name);
-			cifsFile->search_resume_name = NULL;
-		} */
-/* BB account for . and .. in f_pos */
+		kfree(cifsFile->search_resume_name);
+		cifsFile->search_resume_name = NULL; */
+
+		/* BB account for . and .. in f_pos as special case */
 		/* dump_cifs_file_struct(file, "rdir after default ");*/
 
 		rc = find_cifs_entry(xid,pTcon, file,
@@ -610,33 +881,34 @@ int cifs_readdir2(struct file *file, voi
 		}
 		cFYI(1,("loop through %d times filling dir for net buf %p",
 			num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 
-		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
-			smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start);
-		tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL);
+		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
+			smbCalcSize((struct smb_hdr *)
+				    cifsFile->srch_inf.ntwrk_buf_start);
+		/* To be safe - for UCS to UTF-8 with strings loaded
+		with the rare long characters alloc more to account for
+		such multibyte target UTF-8 characters. cifs_unicode.c,
+		which actually does the conversion, has the same limit */
+		tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
 		for(i=0;(i<num_to_fill) && (rc == 0);i++) {
 			if(current_entry == NULL) {
-				cERROR(1,("beyond end of smb with num to fill %d i %d",num_to_fill,i)); /* BB removeme BB */
+				/* evaluate whether this case is an error */
+				cERROR(1,("past end of SMB num to fill %d i %d",
+					  num_to_fill, i));
 				break;
 			}
-/*			if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || 
-			   (cifsFile->srch_inf.info_level != something that supports server inodes)) {
-				create dentry
-				create inode
-				fill in inode new_inode (which makes number locally)
-			}
-			also create local inode for per reasons unless new mount parm says otherwise */
-			rc = cifs_filldir2(current_entry, file, 
+
+			rc = cifs_filldir(current_entry, file, 
 					filldir, direntry,tmp_buf);
 			file->f_pos++;
 			if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
-				cFYI(1,("last entry in buf at pos %lld %s",file->f_pos,tmp_buf)); /* BB removeme BB */
+				cFYI(1,("last entry in buf at pos %lld %s",
+					file->f_pos,tmp_buf)); /* BB removeme BB */
 				cifs_save_resume_key(current_entry,cifsFile);
 				break;
 			} else 
 				current_entry = nxt_dir_entry(current_entry,end_of_smb);
 		}
-		if(tmp_buf != NULL)
-			kfree(tmp_buf);
+		kfree(tmp_buf);
 		break;
 	} /* end switch */
 
@@ -645,4 +917,3 @@ rddir2_exit:
 	FreeXid(xid);
 	return rc;
 }
-
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -45,6 +45,7 @@
    up with a different answer to the one above)
 */
 #include <linux/slab.h>
+#include "cifsencrypt.h"
 #define uchar unsigned char
 
 static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
@@ -376,7 +377,9 @@ E_old_pw_hash(unsigned char *p14, unsign
 	smbhash(out, in, p14, 1);
 	smbhash(out + 8, in + 8, p14 + 7, 1);
 }
-
+#if 0
+/* these routines are currently unneeded, but may be
+	needed later */
 void
 cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
 {
@@ -406,3 +409,4 @@ cred_hash3(unsigned char *out, unsigned 
 	key2[0] = key[7];
 	smbhash(out + 8, in + 8, key2, forw);
 }
+#endif /* unneeded routines */
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -32,6 +32,7 @@
 #include "cifspdu.h"
 #include "md5.h"
 #include "cifs_debug.h"
+#include "cifsencrypt.h"
 
 #ifndef FALSE
 #define FALSE 0
@@ -45,27 +46,12 @@
 #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
 #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
 
-/*The following definitions come from  lib/md4.c  */
-
-void mdfour(unsigned char *out, unsigned char *in, int n);
-
-/*The following definitions come from  libsmb/smbdes.c  */
-
-void E_P16(unsigned char *p14, unsigned char *p16);
-void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
-void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
-void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out);
-void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key);
-void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key);
-void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key,
-		int forw);
-
 /*The following definitions come from  libsmb/smbencrypt.c  */
 
 void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
 void E_md4hash(const unsigned char *passwd, unsigned char *p16);
 void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
-void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
 		   unsigned char p24[24]);
 void NTLMSSPOWFencrypt(unsigned char passwd[8],
 		       unsigned char *ntlmchalresp, unsigned char p24[24]);
@@ -186,7 +172,8 @@ nt_lm_owf_gen(char *pwd, unsigned char n
 }
 
 /* Does the NTLMv2 owfs of a user's password */
-void
+#if 0  /* function not needed yet - but will be soon */
+static void
 ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
 		const char *domain_n, unsigned char kr_buf[16],
 		const struct nls_table *nls_codepage)
@@ -219,9 +206,10 @@ ntv2_owf_gen(const unsigned char owf[16]
 
 	kfree(user_u);
 }
+#endif 
 
 /* Does the des encryption from the NT or LM MD4 hash. */
-void
+static void
 SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
 	      unsigned char p24[24])
 {
@@ -260,8 +248,11 @@ SMBNTencrypt(unsigned char *passwd, unsi
 	SMBOWFencrypt(p21, c8, p24);
 }
 
+
 /* Does the md5 encryption from the NT hash for NTLMv2. */
-void
+/* These routines will be needed later */
+#if 0
+static void
 SMBOWFencrypt_ntv2(const unsigned char kr[16],
                    const struct data_blob * srv_chal,
                    const struct data_blob * cli_chal, unsigned char resp_buf[16])
@@ -274,7 +265,7 @@ SMBOWFencrypt_ntv2(const unsigned char k
         hmac_md5_final(resp_buf, &ctx);
 }
 
-void
+static void
 SMBsesskeygen_ntv2(const unsigned char kr[16],
 		   const unsigned char *nt_resp, __u8 sess_key[16])
 {
@@ -285,9 +276,10 @@ SMBsesskeygen_ntv2(const unsigned char k
 	hmac_md5_final((unsigned char *) sess_key, &ctx);
 }
 
-void
+static void
 SMBsesskeygen_ntv1(const unsigned char kr[16],
 		   const unsigned char *nt_resp, __u8 sess_key[16])
 {
 	mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
 }
+#endif
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -22,94 +22,159 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#define SUCCESS 0		/* The request was successful. */
-#define ERRDOS 0x01		/* Error is from the core DOS operating system set */
-#define ERRSRV 0x02		/* Error is generated by the file server daemon */
-#define ERRHRD 0x03		/* Error is a hardware error. */
-#define ERRCMD 0xFF		/*  Command was not in the "SMB" format. */
+#define SUCCESS	0x00	/* The request was successful. */
+#define ERRDOS	0x01	/* Error is from the core DOS operating system set */
+#define ERRSRV	0x02	/* Error is generated by the file server daemon */
+#define ERRHRD	0x03	/* Error is a hardware error. */
+#define ERRCMD	0xFF	/* Command was not in the "SMB" format. */
 
 /* The following error codes may be generated with the SUCCESS error class.*/
 
-#define SUCCESS 0		/* The request was successful. */
+/*#define SUCCESS	0	The request was successful. */
 
 /* The following error codes may be generated with the ERRDOS error class.*/
 
-#define ERRbadfunc 1		/* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
-#define ERRbadfile 2		/*File not found. The last component of a file's pathname could not be found. */
-#define ERRbadpath 3		/* Directory invalid. A directory component in a pathname could not be found. */
-#define ERRnofids 4		/* Too many open files. The server has no file handles available. */
-#define ERRnoaccess 5		/* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
-#define ERRbadfid 6		/* Invalid file handle. The file handle specified was not recognized by the server. */
-#define ERRbadmcb 7		/* Memory control blocks destroyed. */
-#define ERRnomem 8		/* Insufficient server memory to perform the requested function. */
-#define ERRbadmem 9		/* Invalid memory block address. */
-#define ERRbadenv 10		/* Invalid environment. */
-#define ERRbadformat 11		/* Invalid format. */
-#define ERRbadaccess 12		/* Invalid open mode. */
-#define ERRbaddata 13		/* Invalid data (generated only by IOCTL calls within the server). */
-#define ERRbaddrive 15		/* Invalid drive specified. */
-#define ERRremcd 16		/* A Delete Directory request attempted to remove the server's current directory. */
-#define ERRdiffdevice 17	/* Not same device (e.g., a cross volume rename was attempted */
-#define ERRnofiles 18		/* A File Search command can find no more files matching the specified criteria. */
-#define ERRgeneral 31
-#define ERRbadshare 32		/* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
-#define ERRlock 33		/* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
-#define ERRunsup     50
-#define ERRnosuchshare 67
-#define ERRfilexists 80		/* The file named in the request already exists. */
-#define ERRinvparm   87
-#define ERRdiskfull  112
-#define ERRinvname   123
-#define ERRinvlevel  124
-#define ERRdirnotempty 145
-#define ERRnotlocked   158
-#define ERRalreadyexists 183
-#define ERRbadpipe 230
-#define ERRpipebusy 231
-#define ERRpipeclosing 232
-#define ERRnotconnected 233
-#define ERRmoredata    234
-#define ERReasnotsupported 282
-#define ErrQuota 0x200		/* The operation would cause a quota limit to be exceeded. */
-#define ErrNotALink 0x201	/* A link operation was performed on a pathname that
-				   was not a link. */
-
-/* Following error codes may be generated with the ERRSRV error
-class.*/
-
-#define ERRerror 1		/* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
-#define ERRbadpw 2		/* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
-#define ERRbadtype 3		/* used for indicating DFS referral needed */
-#define ERRaccess 4		/* The client does not have the necessary access rights within the specified context for requested function. */
-#define ERRinvtid 5		/* The Tid specified in a command was invalid. */
-#define ERRinvnetname 6		/* Invalid network name in tree connect. */
-#define ERRinvdevice 7		/* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
-#define ERRqfull 49		/* Print queue full (files) -- returned by open print file. */
-#define ERRqtoobig 50		/* Print queue full -- no space. */
-#define ERRqeof         51	/* EOF on print queue dump */
-#define ERRinvpfid      52	/* Invalid print file FID. */
-#define ERRsmbcmd       64	/* The server did not recognize the command received. */
-#define ERRsrverror     65	/* The server encountered an internal error, e.g., system file unavailable. */
-#define ERRbadBID       66	/* (obsolete) */
-#define ERRfilespecs    67	/* The Fid and pathname parameters contained an invalid combination of values. */
-#define ERRbadLink      68	/* (obsolete) */
-#define ERRbadpermits   69	/* The access permissions specified for a file or directory are not a valid combination. */
-#define ERRbadPID       70
-#define ERRsetattrmode  71	/* attribute (mode) is invalid */
-#define ERRpaused       81	/* Server is paused */
-#define ERRmsgoff	82	/* reserved - messaging off */
-#define ERRnoroom       83	/* reserved - no room for message */
-#define ERRrmuns        87	/* reserved - too many remote names */
-#define ERRtimeout      88	/* operation timed out */
-#define ERRnoresource   89	/* No resources available for request */
-#define ERRtoomanyuids  90	/* Too many UIDs active on this session */
-#define ERRbaduid       91	/* The UID is not known as a valid user */
-#define ERRusempx      250	/* temporarily unable to use raw */
-#define ERRusestd      251	/* temporarily unable to use either raw or mpx */
-#define ERR_NOTIFY_ENUM_DIR 1024
-#define ERRaccountexpired 2239
-#define ERRbadclient      2240
-#define ERRbadLogonTime   2241
-#define ERRpasswordExpired 2242
-#define ERRnetlogonNotStarted 2455
-#define ERRnosupport       0xFFFF
+#define ERRbadfunc		1	/* Invalid function. The server did not
+					   recognize or could not perform a
+					   system call generated by the server,
+					   e.g., set the DIRECTORY attribute on
+					   a data file, invalid seek mode. */
+#define ERRbadfile		2	/* File not found. The last component
+					   of a file's pathname could not be
+					   found. */
+#define ERRbadpath		3	/* Directory invalid. A directory
+					   component in a pathname could not be
+					   found. */
+#define ERRnofids		4	/* Too many open files. The server has
+					   no file handles available. */
+#define ERRnoaccess		5	/* Access denied, the client's context
+					   does not permit the requested
+					   function. This includes the
+					   following conditions: invalid rename
+					   command, write to Fid open for read
+					   only, read on Fid open for write
+					   only, attempt to delete a non-empty
+					   directory */
+#define ERRbadfid		6	/* Invalid file handle. The file handle
+					   specified was not recognized by the
+					   server. */
+#define ERRbadmcb		7	/* Memory control blocks destroyed. */
+#define ERRnomem		8	/* Insufficient server memory to
+					   perform the requested function. */
+#define ERRbadmem		9	/* Invalid memory block address. */
+#define ERRbadenv		10	/* Invalid environment. */
+#define ERRbadformat		11	/* Invalid format. */
+#define ERRbadaccess		12	/* Invalid open mode. */
+#define ERRbaddata		13	/* Invalid data (generated only by
+					   IOCTL calls within the server). */
+#define ERRbaddrive		15	/* Invalid drive specified. */
+#define ERRremcd		16	/* A Delete Directory request attempted
+					   to remove the server's current
+					   directory. */
+#define ERRdiffdevice		17	/* Not same device (e.g., a cross
+					   volume rename was attempted */
+#define ERRnofiles		18	/* A File Search command can find no
+					   more files matching the specified
+					   criteria. */
+#define ERRgeneral		31
+#define ERRbadshare		32	/* The sharing mode specified for an
+					   Open conflicts with existing FIDs on
+					   the file. */
+#define ERRlock			33	/* A Lock request conflicted with an
+					   existing lock or specified an
+					   invalid mode, or an Unlock requested
+					   attempted to remove a lock held by
+					   another process. */
+#define ERRunsup		50
+#define ERRnosuchshare		67
+#define ERRfilexists		80	/* The file named in the request
+					   already exists. */
+#define ERRinvparm		87
+#define ERRdiskfull		112
+#define ERRinvname		123
+#define ERRinvlevel		124
+#define ERRdirnotempty		145
+#define ERRnotlocked		158
+#define ERRalreadyexists	183
+#define ERRbadpipe		230
+#define ERRpipebusy		231
+#define ERRpipeclosing		232
+#define ERRnotconnected		233
+#define ERRmoredata		234
+#define ERReasnotsupported	282
+#define ErrQuota		0x200	/* The operation would cause a quota
+					   limit to be exceeded. */
+#define ErrNotALink		0x201	/* A link operation was performed on a
+					   pathname that was not a link. */
+
+/* Below errors are used internally (do not come over the wire) for passthrough
+   from STATUS codes to POSIX only  */
+#define ErrTooManyLinks         0xFFFE   
+
+/* Following error codes may be generated with the ERRSRV error class.*/
+
+#define ERRerror		1	/* Non-specific error code. It is
+					   returned under the following
+					   conditions: resource other than disk
+					   space exhausted (e.g. TIDs), first
+					   SMB command was not negotiate,
+					   multiple negotiates attempted, and
+					   internal server error. */
+#define ERRbadpw		2	/* Bad password - name/password pair in
+					   a TreeConnect or Session Setup are
+					   invalid. */
+#define ERRbadtype		3	/* used for indicating DFS referral
+					   needed */
+#define ERRaccess		4	/* The client does not have the
+					   necessary access rights within the
+					   specified context for requested
+					   function. */
+#define ERRinvtid		5	/* The Tid specified in a command was
+					   invalid. */
+#define ERRinvnetname		6	/* Invalid network name in tree
+					   connect. */
+#define ERRinvdevice		7	/* Invalid device - printer request
+					   made to non-printer connection or
+					   non-printer request made to printer
+					   connection. */
+#define ERRqfull		49	/* Print queue full (files) -- returned
+					   by open print file. */
+#define ERRqtoobig		50	/* Print queue full -- no space. */
+#define ERRqeof			51	/* EOF on print queue dump */
+#define ERRinvpfid		52	/* Invalid print file FID. */
+#define ERRsmbcmd		64	/* The server did not recognize the
+					   command received. */
+#define ERRsrverror		65	/* The server encountered an internal
+					   error, e.g., system file
+					   unavailable. */
+#define ERRbadBID		66	/* (obsolete) */
+#define ERRfilespecs		67	/* The Fid and pathname parameters
+					   contained an invalid combination of
+					   values. */
+#define ERRbadLink		68	/* (obsolete) */
+#define ERRbadpermits		69	/* The access permissions specified for
+					   a file or directory are not a valid
+					   combination. */
+#define ERRbadPID		70
+#define ERRsetattrmode		71	/* attribute (mode) is invalid */
+#define ERRpaused		81	/* Server is paused */
+#define ERRmsgoff		82	/* reserved - messaging off */
+#define ERRnoroom		83	/* reserved - no room for message */
+#define ERRrmuns		87	/* reserved - too many remote names */
+#define ERRtimeout		88	/* operation timed out */
+#define ERRnoresource		89	/* No resources available for request
+					   */
+#define ERRtoomanyuids		90	/* Too many UIDs active on this session
+					   */
+#define ERRbaduid		91	/* The UID is not known as a valid user
+					   */
+#define ERRusempx		250	/* temporarily unable to use raw */
+#define ERRusestd		251	/* temporarily unable to use either raw
+					   or mpx */
+#define ERR_NOTIFY_ENUM_DIR	1024
+#define ERRaccountexpired	2239
+#define ERRbadclient		2240
+#define ERRbadLogonTime		2241
+#define ERRpasswordExpired	2242
+#define ERRnetlogonNotStarted	2455
+#define ERRnosupport		0xFFFF
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/transport.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2004
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/net.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <linux/mempool.h>
@@ -34,13 +35,13 @@
 extern mempool_t *cifs_mid_poolp;
 extern kmem_cache_t *cifs_oplock_cachep;
 
-struct mid_q_entry *
+static struct mid_q_entry *
 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
 {
 	struct mid_q_entry *temp;
 
 	if (ses == NULL) {
-		cERROR(1, ("Null session passed in to AllocMidQEntry "));
+		cERROR(1, ("Null session passed in to AllocMidQEntry"));
 		return NULL;
 	}
 	if (ses->server == NULL) {
@@ -70,7 +71,7 @@ AllocMidQEntry(struct smb_hdr *smb_buffe
 	return temp;
 }
 
-void
+static void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
 	spin_lock(&GlobalMid_Lock);
@@ -78,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midE
 	list_del(&midEntry->qhead);
 	atomic_dec(&midCount);
 	spin_unlock(&GlobalMid_Lock);
-	cifs_buf_release(midEntry->resp_buf);
+	if(midEntry->largeBuf)
+		cifs_buf_release(midEntry->resp_buf);
+	else
+		cifs_small_buf_release(midEntry->resp_buf);
 	mempool_free(midEntry, cifs_mid_poolp);
 }
 
@@ -156,8 +160,7 @@ smb_send(struct socket *ssocket, struct 
 				rc = -EAGAIN;
 				break;
 			}
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(HZ/2);
+			msleep(500);
 			continue;
 		}
 		if (rc < 0) 
@@ -179,6 +182,71 @@ smb_send(struct socket *ssocket, struct 
 #ifdef CIFS_EXPERIMENTAL
 /* BB finish off this function, adding support for writing set of pages as iovec */
 /* and also adding support for operations that need to parse the response smb    */
+
+int
+smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
+	 unsigned int smb_buf_length, struct kvec * write_vector 
+	  /* page list */, struct sockaddr *sin)
+{
+	int rc = 0;
+	int i = 0;
+	struct msghdr smb_msg;
+	number_of_pages += 1; /* account for SMB header */
+	struct kvec * piov  = kmalloc(number_of_pages * sizeof(struct kvec));
+	unsigned len = smb_buf_length + 4;
+
+	if(ssocket == NULL)
+		return -ENOTSOCK; /* BB eventually add reconnect code here */
+	iov.iov_base = smb_buffer;
+	iov.iov_len = len;
+
+	smb_msg.msg_name = sin;
+	smb_msg.msg_namelen = sizeof (struct sockaddr);
+	smb_msg.msg_control = NULL;
+	smb_msg.msg_controllen = 0;
+	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
+
+	/* smb header is converted in header_assemble. bcc and rest of SMB word
+	   area, and byte area if necessary, is converted to littleendian in 
+	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
+	   Flags2 is converted in SendReceive */
+
+	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
+	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+	dump_smb(smb_buffer, len);
+
+	while (len > 0) {
+		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 
+				    len);
+		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
+			i++;
+			if(i > 60) {
+				cERROR(1,
+				   ("sends on sock %p stuck for 30 seconds",
+				    ssocket));
+				rc = -EAGAIN;
+				break;
+			}
+			msleep(500);
+			continue;
+		}
+		if (rc < 0) 
+			break;
+		iov.iov_base += rc;
+		iov.iov_len -= rc;
+		len -= rc;
+	}
+
+	if (rc < 0) {
+		cERROR(1,("Error %d sending data on socket to server.", rc));
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+
 int
 CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 	    struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op)
@@ -202,6 +270,9 @@ CIFSSendRcv(const unsigned int xid, stru
 
   
 
+	if(ses->server->tcpStatus == CIFS_EXITING)
+		return -ENOENT;
+
 	/* Ensure that we do not send more than 50 overlapping requests 
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
@@ -282,11 +353,12 @@ CIFSSendRcv(const unsigned int xid, stru
 	}
 
 	/* BB can we sign efficiently in this path? */
-	rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
-/*	rc = smb_send2(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
-		      (struct sockaddr *) &(ses->server->addr.sockAddr));*/
+/*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+		       piovec, 
+		       (struct sockaddr *) &(ses->server->addr.sockAddr));*/
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
@@ -332,6 +404,9 @@ SendReceive(const unsigned int xid, stru
 		return -EIO;
 	}
 
+	if(ses->server->tcpStatus == CifsExiting)
+		return -ENOENT;
+
 	/* Ensure that we do not send more than 50 overlapping requests 
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
@@ -341,7 +416,8 @@ SendReceive(const unsigned int xid, stru
 	} else {
 		spin_lock(&GlobalMid_Lock); 
 		while(1) {        
-			if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+			if(atomic_read(&ses->server->inFlight) >= 
+					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
@@ -411,7 +487,7 @@ SendReceive(const unsigned int xid, stru
 		return -EIO;
 	}
 
-	rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
@@ -429,7 +505,7 @@ SendReceive(const unsigned int xid, stru
 		up(&ses->server->tcpSem);
 	if (long_op == -1)
 		goto cifs_no_response_exit;
-	else if (long_op == 2) /* writes past end of file can take looooong time */
+	else if (long_op == 2) /* writes past end of file can take loong time */
 		timeout = 300 * HZ;
 	else if (long_op == 1)
 		timeout = 45 * HZ; /* should be greater than 
@@ -495,8 +571,7 @@ SendReceive(const unsigned int xid, stru
 	}
   
 	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-		cERROR(1,
-		       ("Frame too large received.  Length: %d  Xid: %d",
+		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
 			receive_len, xid));
 		rc = -EIO;
 	} else {		/* rcvd frame is ok */
@@ -511,15 +586,20 @@ SendReceive(const unsigned int xid, stru
 			dump_smb(out_buf, 92);
 			/* convert the length into a more usable form */
 			if((receive_len > 24) &&
-			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
-				if(rc)
-					cFYI(1,("Unexpected signature received from server"));
+			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					SECMODE_SIGN_ENABLED))) {
+				rc = cifs_verify_signature(out_buf,
+						ses->server->mac_signing_key,
+						midQ->sequence_number+1);
+				if(rc) {
+					cERROR(1,("Unexpected SMB signature"));
+					/* BB FIXME add code to kill session */
+				}
 			}
 
 			*pbytes_returned = out_buf->smb_buf_length;
 
-			/* BB special case reconnect tid and reconnect uid here? */
+			/* BB special case reconnect tid and uid here? */
 			rc = map_smb_to_linux_error(out_buf);
 
 			/* convert ByteCount if necessary */
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -71,16 +71,22 @@ int cifs_removexattr(struct dentry * dir
 	}
 	if(ea_name == NULL) {
 		cFYI(1,("Null xattr names not supported"));
-	} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
+	} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)
+		&& (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) {
 		cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
 		/* BB what if no namespace prefix? */
 		/* Should we just pass them to server, except for
 		system and perhaps security prefixes? */
 	} else {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+			goto remove_ea_exit;
+
 		ea_name+=5; /* skip past user. prefix */
 		rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL,
-			(__u16)0, cifs_sb->local_nls);
+			(__u16)0, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	}
+remove_ea_exit:
 	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
@@ -135,34 +141,47 @@ int cifs_setxattr(struct dentry * dirent
 	if(ea_name == NULL) {
 		cFYI(1,("Null xattr names not supported"));
 	} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+			goto set_ea_exit;
 		if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
 			cFYI(1,("attempt to set cifs inode metadata"));
 		}
 		ea_name += 5; /* skip past user. prefix */
 		rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
-			(__u16)value_size, cifs_sb->local_nls);
+			(__u16)value_size, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+			goto set_ea_exit;
+
 		ea_name += 4; /* skip past os2. prefix */
 		rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
-			(__u16)value_size, cifs_sb->local_nls);
+			(__u16)value_size, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else {
 		int temp; 
 		temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
 			strlen(POSIX_ACL_XATTR_ACCESS));
 		if (temp == 0) {
 #ifdef CONFIG_CIFS_POSIX
-			rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
-				(const int)value_size, ACL_TYPE_ACCESS,
-				cifs_sb->local_nls);
+			if(sb->s_flags & MS_POSIXACL)
+				rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
+					ea_value, (const int)value_size, 
+					ACL_TYPE_ACCESS,cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cFYI(1,("set POSIX ACL rc %d",rc));
 #else
 			cFYI(1,("set POSIX ACL not supported"));
 #endif
 		} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-			rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
-				(const int)value_size, ACL_TYPE_DEFAULT,
-				cifs_sb->local_nls);
+			if(sb->s_flags & MS_POSIXACL)
+				rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
+					ea_value, (const int)value_size, 
+					ACL_TYPE_DEFAULT, cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags & 
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cFYI(1,("set POSIX default ACL rc %d",rc));
 #else
 			cFYI(1,("set default POSIX ACL not supported"));
@@ -174,7 +193,8 @@ int cifs_setxattr(struct dentry * dirent
 		  system and perhaps security prefixes? */
 		}
 	}
- 
+
+set_ea_exit:
 	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
@@ -218,30 +238,44 @@ ssize_t cifs_getxattr(struct dentry * di
 	if(ea_name == NULL) {
 		cFYI(1,("Null xattr names not supported"));
 	} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+			goto get_ea_exit;
+
 		if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
 			cFYI(1,("attempt to query cifs inode metadata"));
 			/* revalidate/getattr then populate from inode */
 		} /* BB add else when above is implemented */
 		ea_name += 5; /* skip past user. prefix */
 		rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
-			buf_size, cifs_sb->local_nls);
+			buf_size, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+			goto get_ea_exit;
+
 		ea_name += 4; /* skip past os2. prefix */
 		rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
-			buf_size, cifs_sb->local_nls);
+			buf_size, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-		rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+		if(sb->s_flags & MS_POSIXACL)
+			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				ea_value, buf_size, ACL_TYPE_ACCESS, 
-				cifs_sb->local_nls);
+				cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 #else 
 		cFYI(1,("query POSIX ACL not supported yet"));
 #endif /* CONFIG_CIFS_POSIX */
 	} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-		rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+		if(sb->s_flags & MS_POSIXACL)
+			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				ea_value, buf_size, ACL_TYPE_DEFAULT, 
-				cifs_sb->local_nls);
+				cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 #else 
 		cFYI(1,("query POSIX default ACL not supported yet"));
 #endif
@@ -263,6 +297,7 @@ ssize_t cifs_getxattr(struct dentry * di
 	if(rc == -EINVAL)
 		rc = -EOPNOTSUPP; 
 
+get_ea_exit:
 	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
@@ -306,7 +341,9 @@ ssize_t cifs_listxattr(struct dentry * d
 		search server for EAs or streams to 
 		returns as xattrs */
 	rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size,
-				cifs_sb->local_nls);
+				cifs_sb->local_nls,
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 	if (full_path)
 		kfree(full_path);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -15,7 +15,6 @@
  */
 
 #include <asm/system.h>
-#include <asm/signal.h>
 #include <linux/signal.h>
 
 #include <linux/types.h>
diff --git a/fs/compat.c b/fs/compat.c
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -31,6 +31,7 @@
 #include <linux/smb.h>
 #include <linux/smb_mount.h>
 #include <linux/ncp_mount.h>
+#include <linux/nfs4_mount.h>
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
@@ -131,7 +132,7 @@ static int put_compat_statfs(struct comp
 		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 			return -EOVERFLOW;
 	}
-	if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 	    __put_user(kbuf->f_type, &ubuf->f_type) ||
 	    __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 	    __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
@@ -205,7 +206,7 @@ static int put_compat_statfs64(struct co
 		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 			return -EOVERFLOW;
 	}
-	if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 	    __put_user(kbuf->f_type, &ubuf->f_type) ||
 	    __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 	    __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
@@ -806,10 +807,79 @@ static void *do_smb_super_data_conv(void
 	return raw_data;
 }
 
+struct compat_nfs_string {
+	compat_uint_t len;
+	compat_uptr_t data;
+};
+
+static inline void compat_nfs_string(struct nfs_string *dst,
+				     struct compat_nfs_string *src)
+{
+	dst->data = compat_ptr(src->data);
+	dst->len = src->len;
+}
+
+struct compat_nfs4_mount_data_v1 {
+	compat_int_t version;
+	compat_int_t flags;
+	compat_int_t rsize;
+	compat_int_t wsize;
+	compat_int_t timeo;
+	compat_int_t retrans;
+	compat_int_t acregmin;
+	compat_int_t acregmax;
+	compat_int_t acdirmin;
+	compat_int_t acdirmax;
+	struct compat_nfs_string client_addr;
+	struct compat_nfs_string mnt_path;
+	struct compat_nfs_string hostname;
+	compat_uint_t host_addrlen;
+	compat_uptr_t host_addr;
+	compat_int_t proto;
+	compat_int_t auth_flavourlen;
+	compat_uptr_t auth_flavours;
+};
+
+static int do_nfs4_super_data_conv(void *raw_data)
+{
+	int version = *(compat_uint_t *) raw_data;
+
+	if (version == 1) {
+		struct compat_nfs4_mount_data_v1 *raw = raw_data;
+		struct nfs4_mount_data *real = raw_data;
+
+		/* copy the fields backwards */
+		real->auth_flavours = compat_ptr(raw->auth_flavours);
+		real->auth_flavourlen = raw->auth_flavourlen;
+		real->proto = raw->proto;
+		real->host_addr = compat_ptr(raw->host_addr);
+		real->host_addrlen = raw->host_addrlen;
+		compat_nfs_string(&real->hostname, &raw->hostname);
+		compat_nfs_string(&real->mnt_path, &raw->mnt_path);
+		compat_nfs_string(&real->client_addr, &raw->client_addr);
+		real->acdirmax = raw->acdirmax;
+		real->acdirmin = raw->acdirmin;
+		real->acregmax = raw->acregmax;
+		real->acregmin = raw->acregmin;
+		real->retrans = raw->retrans;
+		real->timeo = raw->timeo;
+		real->wsize = raw->wsize;
+		real->rsize = raw->rsize;
+		real->flags = raw->flags;
+		real->version = raw->version;
+	}
+	else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 extern int copy_mount_options (const void __user *, unsigned long *);
 
 #define SMBFS_NAME      "smbfs"
 #define NCPFS_NAME      "ncpfs"
+#define NFS4_NAME	"nfs4"
 
 asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
 				 char __user * type, unsigned long flags,
@@ -845,6 +915,9 @@ asmlinkage long compat_sys_mount(char __
 			do_smb_super_data_conv((void *)data_page);
 		} else if (!strcmp((char *)type_page, NCPFS_NAME)) {
 			do_ncp_super_data_conv((void *)data_page);
+		} else if (!strcmp((char *)type_page, NFS4_NAME)) {
+			if (do_nfs4_super_data_conv((void *) data_page))
+				goto out4;
 		}
 	}
 
@@ -853,6 +926,7 @@ asmlinkage long compat_sys_mount(char __
 			flags, (void*)data_page);
 	unlock_kernel();
 
+ out4:
 	free_page(data_page);
  out3:
 	free_page(dev_page);
@@ -1152,7 +1226,7 @@ static ssize_t compat_do_readv_writev(in
 			goto out;
 	}
 	ret = -EFAULT;
-	if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
+	if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
 		goto out;
 
 	/*
@@ -1537,7 +1611,7 @@ int compat_get_fd_set(unsigned long nr, 
 	if (ufdset) {
 		unsigned long odd;
 
-		if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
+		if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
 			return -EFAULT;
 
 		odd = nr & 1UL;
@@ -1620,18 +1694,19 @@ compat_sys_select(int n, compat_ulong_t 
 	fd_set_bits fds;
 	char *bits;
 	long timeout;
-	int ret, size, max_fdset;
+	int size, max_fdset, ret = -EINVAL;
 
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
 
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
+		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
+		    || __get_user(sec, &tvp->tv_sec)
+		    || __get_user(usec, &tvp->tv_usec)) {
+			ret = -EFAULT;
 			goto out_nofds;
+		}
 
-		ret = -EINVAL;
 		if (sec < 0 || usec < 0)
 			goto out_nofds;
 
@@ -1641,7 +1716,6 @@ compat_sys_select(int n, compat_ulong_t 
 		}
 	}
 
-	ret = -EINVAL;
 	if (n < 0)
 		goto out_nofds;
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1281,35 +1281,9 @@ struct mtpos32 {
 };
 #define MTIOCPOS32	_IOR('m', 3, struct mtpos32)
 
-struct mtconfiginfo32 {
-	compat_long_t	mt_type;
-	compat_long_t	ifc_type;
-	unsigned short	irqnr;
-	unsigned short	dmanr;
-	unsigned short	port;
-	compat_ulong_t	debug;
-	compat_uint_t	have_dens:1;
-	compat_uint_t	have_bsf:1;
-	compat_uint_t	have_fsr:1;
-	compat_uint_t	have_bsr:1;
-	compat_uint_t	have_eod:1;
-	compat_uint_t	have_seek:1;
-	compat_uint_t	have_tell:1;
-	compat_uint_t	have_ras1:1;
-	compat_uint_t	have_ras2:1;
-	compat_uint_t	have_ras3:1;
-	compat_uint_t	have_qfa:1;
-	compat_uint_t	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 mtconfiginfo32 __user *uinfo32;
 	struct mtget get;
 	struct mtget32 __user *umget32;
 	struct mtpos pos;
@@ -1327,27 +1301,6 @@ static int mt_ioctl_trans(unsigned int f
 		kcmd = MTIOCGET;
 		karg = &get;
 		break;
-	case MTIOCGETCONFIG32:
-		kcmd = MTIOCGETCONFIG;
-		karg = &info;
-		break;
-	case MTIOCSETCONFIG32:
-		kcmd = MTIOCSETCONFIG;
-		karg = &info;
-		uinfo32 = compat_ptr(arg);
-		err = __get_user(info.mt_type, &uinfo32->mt_type);
-		err |= __get_user(info.ifc_type, &uinfo32->ifc_type);
-		err |= __get_user(info.irqnr, &uinfo32->irqnr);
-		err |= __get_user(info.dmanr, &uinfo32->dmanr);
-		err |= __get_user(info.port, &uinfo32->port);
-		err |= __get_user(info.debug, &uinfo32->debug);
-		err |= __copy_from_user((char *)&info.debug
-				     + sizeof(info.debug),
-				     (char __user *)&uinfo32->debug
-				     + sizeof(uinfo32->debug), sizeof(__u32));
-		if (err)
-			return -EFAULT;
-		break;
 	default:
 		do {
 			static int count;
@@ -1378,20 +1331,6 @@ static int mt_ioctl_trans(unsigned int f
 		err |= __put_user(get.mt_fileno, &umget32->mt_fileno);
 		err |= __put_user(get.mt_blkno, &umget32->mt_blkno);
 		break;
-	case MTIOCGETCONFIG32:
-		uinfo32 = compat_ptr(arg);
-		err = __put_user(info.mt_type, &uinfo32->mt_type);
-		err |= __put_user(info.ifc_type, &uinfo32->ifc_type);
-		err |= __put_user(info.irqnr, &uinfo32->irqnr);
-		err |= __put_user(info.dmanr, &uinfo32->dmanr);
-		err |= __put_user(info.port, &uinfo32->port);
-		err |= __put_user(info.debug, &uinfo32->debug);
-		err |= __copy_to_user((char __user *)&uinfo32->debug
-			    		   + sizeof(uinfo32->debug),
-					   (char *)&info.debug + sizeof(info.debug), sizeof(__u32));
-		break;
-	case MTIOCSETCONFIG32:
-		break;
 	}
 	return err ? -EFAULT: 0;
 }
@@ -1620,7 +1559,7 @@ static int do_fontx_ioctl(unsigned int f
 		    get_user(data, &user_cfd->chardata))
 			return -EFAULT;
 		op.data = compat_ptr(data);
-		return con_font_op(fg_console, &op);
+		return con_font_op(vc_cons[fg_console].d, &op);
 	case GIO_FONTX:
 		op.op = KD_FONT_OP_GET;
 		op.flags = 0;
@@ -1632,7 +1571,7 @@ static int do_fontx_ioctl(unsigned int f
 		if (!data)
 			return 0;
 		op.data = compat_ptr(data);
-		i = con_font_op(fg_console, &op);
+		i = con_font_op(vc_cons[fg_console].d, &op);
 		if (i)
 			return i;
 		if (put_user(op.height, &user_cfd->charheight) ||
@@ -1658,7 +1597,7 @@ static int do_kdfontop_ioctl(unsigned in
 	struct console_font_op op;
 	struct console_font_op32 __user *fontop = compat_ptr(arg);
 	int perm = vt_check(file), i;
-	struct vt_struct *vt;
+	struct vc_data *vc;
 	
 	if (perm < 0) return perm;
 	
@@ -1668,9 +1607,10 @@ static int do_kdfontop_ioctl(unsigned in
 		return -EPERM;
 	op.data = compat_ptr(((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;
+	vc = ((struct tty_struct *)file->private_data)->driver_data;
+	i = con_font_op(vc, &op);
+	if (i)
+		return i;
 	((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
 	if (copy_to_user(fontop, &op, sizeof(struct console_font_op32)))
 		return -EFAULT;
@@ -1694,9 +1634,9 @@ static int do_unimap_ioctl(unsigned int 
 	switch (cmd) {
 	case PIO_UNIMAP:
 		if (!perm) return -EPERM;
-		return con_set_unimap(fg_console, tmp.entry_ct, compat_ptr(tmp.entries));
+		return con_set_unimap(vc_cons[fg_console].d, tmp.entry_ct, compat_ptr(tmp.entries));
 	case GIO_UNIMAP:
-		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries));
+		return con_get_unimap(vc_cons[fg_console].d, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries));
 	}
 	return 0;
 }
@@ -2342,11 +2282,8 @@ static int mtd_rw_oob(unsigned int fd, u
 static long
 put_dirent32 (struct dirent *d, struct compat_dirent __user *d32)
 {
-        int ret;
-
-        if ((ret = verify_area(VERIFY_WRITE, d32,
-                               sizeof(struct compat_dirent))))
-                return ret;
+        if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
+                return -EFAULT;
 
         __put_user(d->d_ino, &d32->d_ino);
         __put_user(d->d_off, &d32->d_off);
@@ -2354,7 +2291,7 @@ put_dirent32 (struct dirent *d, struct c
         if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
 		return -EFAULT;
 
-        return ret;
+        return 0;
 }
 
 static int vfat_ioctl32(unsigned fd, unsigned cmd, unsigned long arg)
@@ -2405,9 +2342,8 @@ static int get_raw32_request(struct raw_
 {
         int ret;
 
-        if ((ret = verify_area(VERIFY_READ, user_req,
-                               sizeof(struct raw32_config_request))))
-                return ret;
+        if (!access_ok(VERIFY_READ, user_req, sizeof(struct raw32_config_request)))
+                return -EFAULT;
 
         ret = __get_user(req->raw_minor, &user_req->raw_minor);
         ret |= __get_user(req->block_major, &user_req->block_major);
@@ -2420,9 +2356,8 @@ static int set_raw32_request(struct raw_
 {
 	int ret;
 
-        if ((ret = verify_area(VERIFY_WRITE, user_req,
-                               sizeof(struct raw32_config_request))))
-                return ret;
+        if (!access_ok(VERIFY_WRITE, user_req, sizeof(struct raw32_config_request)))
+                return -EFAULT;
 
         ret = __put_user(req->raw_minor, &user_req->raw_minor);
         ret |= __put_user(req->block_major, &user_req->block_major);
@@ -2494,7 +2429,7 @@ static int serial_struct_ioctl(unsigned 
         __u32 udata;
 
         if (cmd == TIOCSSERIAL) {
-                if (verify_area(VERIFY_READ, ss32, sizeof(SS32)))
+                if (!access_ok(VERIFY_READ, ss32, sizeof(SS32)))
                         return -EFAULT;
                 if (__copy_from_user(&ss, ss32, offsetof(SS32, iomem_base)))
 			return -EFAULT;
@@ -2508,7 +2443,7 @@ static int serial_struct_ioctl(unsigned 
                 err = sys_ioctl(fd,cmd,(unsigned long)(&ss));
         set_fs(oldseg);
         if (cmd == TIOCGSERIAL && err >= 0) {
-                if (verify_area(VERIFY_WRITE, ss32, sizeof(SS32)))
+                if (!access_ok(VERIFY_WRITE, ss32, sizeof(SS32)))
                         return -EFAULT;
                 if (__copy_to_user(ss32,&ss,offsetof(SS32,iomem_base)))
 			return -EFAULT;
@@ -2575,229 +2510,11 @@ static int do_usbdevfs_bulk(unsigned int
         return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p);
 }
 
-/* This needs more work before we can enable it.  Unfortunately
- * because of the fancy asynchronous way URB status/error is written
- * back to userspace, we'll need to fiddle with USB devio internals
- * and/or reimplement entirely the frontend of it ourselves. -DaveM
- *
- * The issue is:
- *
- *	When an URB is submitted via usbdevicefs it is put onto an
- *	asynchronous queue.  When the URB completes, it may be reaped
- *	via another ioctl.  During this reaping the status is written
- *	back to userspace along with the length of the transfer.
- *
- *	We must translate into 64-bit kernel types so we pass in a kernel
- *	space copy of the usbdevfs_urb structure.  This would mean that we
- *	must do something to deal with the async entry reaping.  First we
- *	have to deal somehow with this transitory memory we've allocated.
- *	This is problematic since there are many call sites from which the
- *	async entries can be destroyed (and thus when we'd need to free up
- *	this kernel memory).  One of which is the close() op of usbdevicefs.
- *	To handle that we'd need to make our own file_operations struct which
- *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
- *	real release op then frees up the kernel memory.
- *
- *	But how to keep track of these kernel buffers?  We'd need to either
- *	keep track of them in some table _or_ know about usbdevicefs internals
- *	(ie. the exact layout of its file private, which is actually defined
- *	in linux/usbdevice_fs.h, the layout of the async queues are private to
- *	devio.c)
- *
- * There is one possible other solution I considered, also involving knowledge
- * of usbdevicefs internals:
- *
- *	After an URB is submitted, we "fix up" the address back to the user
- *	space one.  This would work if the status/length fields written back
- *	by the async URB completion lines up perfectly in the 32-bit type with
- *	the 64-bit kernel type.  Unfortunately, it does not because the iso
- *	frame descriptors, at the end of the struct, can be written back.
- *
- * I think we'll just need to simply duplicate the devio URB engine here.
- */
-#if 0
-struct usbdevfs_urb32 {
-	unsigned char type;
-	unsigned char endpoint;
-	compat_int_t status;
-	compat_uint_t flags;
-	compat_caddr_t buffer;
-	compat_int_t buffer_length;
-	compat_int_t actual_length;
-	compat_int_t start_frame;
-	compat_int_t number_of_packets;
-	compat_int_t error_count;
-	compat_uint_t signr;
-	compat_caddr_t usercontext; /* unused */
-	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
-};
-
-#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
-
-static int get_urb32(struct usbdevfs_urb *kurb,
-		     struct usbdevfs_urb32 *uurb)
-{
-	if (get_user(kurb->type, &uurb->type) ||
-	    __get_user(kurb->endpoint, &uurb->endpoint) ||
-	    __get_user(kurb->status, &uurb->status) ||
-	    __get_user(kurb->flags, &uurb->flags) ||
-	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
-	    __get_user(kurb->actual_length, &uurb->actual_length) ||
-	    __get_user(kurb->start_frame, &uurb->start_frame) ||
-	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
-	    __get_user(kurb->error_count, &uurb->error_count) ||
-	    __get_user(kurb->signr, &uurb->signr))
-		return -EFAULT;
-
-	kurb->usercontext = 0; /* unused currently */
-
-	return 0;
-}
-
-/* Just put back the values which usbdevfs actually changes. */
-static int put_urb32(struct usbdevfs_urb *kurb,
-		     struct usbdevfs_urb32 *uurb)
-{
-	if (put_user(kurb->status, &uurb->status) ||
-	    __put_user(kurb->actual_length, &uurb->actual_length) ||
-	    __put_user(kurb->error_count, &uurb->error_count))
-		return -EFAULT;
-
-	if (kurb->number_of_packets != 0) {
-		int i;
-
-		for (i = 0; i < kurb->number_of_packets; i++) {
-			if (__put_user(kurb->iso_frame_desc[i].actual_length,
-				       &uurb->iso_frame_desc[i].actual_length) ||
-			    __put_user(kurb->iso_frame_desc[i].status,
-				       &uurb->iso_frame_desc[i].status))
-				return -EFAULT;
-		}
-	}
-
-	return 0;
-}
-
-static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
-			       struct usbdevfs_urb32 *uurb)
-{
-	unsigned int totlen;
-	int i;
-
-	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
-		kurb->number_of_packets = 0;
-		return 0;
-	}
-
-	if (kurb->number_of_packets < 1 ||
-	    kurb->number_of_packets > 128)
-		return -EINVAL;
-
-	if (copy_from_user(&kurb->iso_frame_desc[0],
-			   &uurb->iso_frame_desc[0],
-			   sizeof(struct usbdevfs_iso_packet_desc) *
-			   kurb->number_of_packets))
-		return -EFAULT;
-
-	totlen = 0;
-	for (i = 0; i < kurb->number_of_packets; i++) {
-		unsigned int this_len;
-
-		this_len = kurb->iso_frame_desc[i].length;
-		if (this_len > 1023)
-			return -EINVAL;
-
-		totlen += this_len;
-	}
 
-	if (totlen > 32768)
-		return -EINVAL;
-
-	kurb->buffer_length = totlen;
-
-	return 0;
-}
-
-static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct usbdevfs_urb *kurb;
-	struct usbdevfs_urb32 *uurb;
-	mm_segment_t old_fs;
-	__u32 udata;
-	void *uptr, *kptr;
-	unsigned int buflen;
-	int err;
-
-	uurb = compat_ptr(arg);
-
-	err = -ENOMEM;
-	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
-		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
-		       GFP_KERNEL);
-	if (!kurb)
-		goto out;
-
-	err = -EFAULT;
-	if (get_urb32(kurb, uurb))
-		goto out;
-
-	err = get_urb32_isoframes(kurb, uurb);
-	if (err)
-		goto out;
-
-	err = -EFAULT;
-	if (__get_user(udata, &uurb->buffer))
-		goto out;
-	uptr = compat_ptr(udata);
-
-	buflen = kurb->buffer_length;
-	err = verify_area(VERIFY_WRITE, uptr, buflen);
-	if (err)
-		goto out;
-
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
-	set_fs(old_fs);
-
-	if (err >= 0) {
-		/* RED-PEN Shit, this doesn't work for async URBs :-( XXX */
-		if (put_urb32(kurb, uurb)) {
-			err = -EFAULT;
-		}
-	}
-
-out:
-	kfree(kurb);
-	return err;
-}
-#endif
-
-#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
-#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
-
-static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-        mm_segment_t old_fs;
-        void *kptr;
-        int err;
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        err = sys_ioctl(fd,
-                        (cmd == USBDEVFS_REAPURB32 ?
-                         USBDEVFS_REAPURB :
-                         USBDEVFS_REAPURBNDELAY),
-                        (unsigned long) &kptr);
-        set_fs(old_fs);
-
-        if (err >= 0 &&
-            put_user((u32)(u64)kptr, (u32 __user *)compat_ptr(arg)))
-                err = -EFAULT;
-
-        return err;
-}
+/*
+ *  USBDEVFS_SUBMITURB, USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY
+ *  are handled in usbdevfs core.			-Christopher Li
+ */
 
 struct usbdevfs_disconnectsignal32 {
         compat_int_t signr;
@@ -2903,11 +2620,11 @@ static int do_i2c_smbus_ioctl(unsigned i
 	tdata = compat_alloc_user_space(sizeof(*tdata));
 	if (tdata == NULL)
 		return -ENOMEM;
-	if (verify_area(VERIFY_WRITE, tdata, sizeof(*tdata)))
+	if (!access_ok(VERIFY_WRITE, tdata, sizeof(*tdata)))
 		return -EFAULT;
 
 	udata = compat_ptr(arg);
-	if (verify_area(VERIFY_READ, udata, sizeof(*udata)))
+	if (!access_ok(VERIFY_READ, udata, sizeof(*udata)))
 		return -EFAULT;
 
 	if (__copy_in_user(&tdata->read_write, &udata->read_write, 2 * sizeof(u8)))
@@ -2944,7 +2661,7 @@ static int do_wireless_ioctl(unsigned in
 
 	iwp = &iwr->u.data;
 
-	if (verify_area(VERIFY_WRITE, iwr, sizeof(*iwr)))
+	if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
 		return -EFAULT;
 
 	if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
@@ -3259,8 +2976,6 @@ HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fpr
 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)
-HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans)
 HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
 HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
 HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
@@ -3331,9 +3046,6 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_
 /* Usbdevfs */
 HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
 HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
-/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
-HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
-HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
 /* i2c */
 HANDLE_IOCTL(I2C_FUNCS, w_long)
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -70,6 +70,7 @@ static struct inode *get_cramfs_inode(st
 			inode->i_data.a_ops = &cramfs_aops;
 		} else {
 			inode->i_size = 0;
+			inode->i_blocks = 0;
 			init_special_inode(inode, inode->i_mode,
 				old_decode_dev(cramfs_inode->size));
 		}
diff --git a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -36,9 +36,10 @@
 /* #define DCACHE_DEBUG 1 */
 
 int sysctl_vfs_cache_pressure = 100;
+EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
-seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
+static seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
 
 EXPORT_SYMBOL(dcache_lock);
 
@@ -340,13 +341,16 @@ restart:
 	tmp = head;
 	while ((tmp = tmp->next) != head) {
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+		spin_lock(&dentry->d_lock);
 		if (!atomic_read(&dentry->d_count)) {
 			__dget_locked(dentry);
 			__d_drop(dentry);
+			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
 			dput(dentry);
 			goto restart;
 		}
+		spin_unlock(&dentry->d_lock);
 	}
 	spin_unlock(&dcache_lock);
 }
@@ -1529,7 +1533,6 @@ int is_subdir(struct dentry * new_dentry
 	struct dentry * saved = new_dentry;
 	unsigned long seq;
 
-	result = 0;
 	/* need rcu_readlock to protect against the d_parent trashing due to
 	 * d_move
 	 */
@@ -1537,6 +1540,7 @@ int is_subdir(struct dentry * new_dentry
         do {
 		/* for restarting inner loop in case of seq retry */
 		new_dentry = saved;
+		result = 0;
 		seq = read_seqbegin(&rename_lock);
 		for (;;) {
 			if (new_dentry != old_dentry) {
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -52,7 +52,7 @@ static ssize_t read_file_##type(struct f
 	char buf[32];								\
 	type *val = file->private_data;						\
 										\
-	snprintf(buf, sizeof(buf), format, *val);				\
+	snprintf(buf, sizeof(buf), format "\n", *val);				\
 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\
 }										\
 static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\
@@ -186,7 +186,7 @@ static ssize_t read_file_bool(struct fil
 	char buf[3];
 	u32 *val = file->private_data;
 	
-	if (val)
+	if (*val)
 		buf[0] = 'Y';
 	else
 		buf[0] = 'N';
diff --git a/fs/direct-io.c b/fs/direct-io.c
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -66,6 +66,7 @@ struct dio {
 	struct bio *bio;		/* bio under assembly */
 	struct inode *inode;
 	int rw;
+	loff_t i_size;			/* i_size when submitted */
 	int lock_type;			/* doesn't change */
 	unsigned blkbits;		/* doesn't change */
 	unsigned blkfactor;		/* When we're using an alignment which
@@ -230,17 +231,29 @@ static void finished_one_bio(struct dio 
 	spin_lock_irqsave(&dio->bio_lock, flags);
 	if (dio->bio_count == 1) {
 		if (dio->is_async) {
+			ssize_t transferred;
+			loff_t offset;
+
 			/*
 			 * Last reference to the dio is going away.
 			 * Drop spinlock and complete the DIO.
 			 */
 			spin_unlock_irqrestore(&dio->bio_lock, flags);
-			dio_complete(dio, dio->block_in_file << dio->blkbits,
-					dio->result);
+
+			/* Check for short read case */
+			transferred = dio->result;
+			offset = dio->iocb->ki_pos;
+
+			if ((dio->rw == READ) &&
+			    ((offset + transferred) > dio->i_size))
+				transferred = dio->i_size - offset;
+
+			dio_complete(dio, offset, transferred);
+
 			/* Complete AIO later if falling back to buffered i/o */
 			if (dio->result == dio->size ||
 				((dio->rw == READ) && dio->result)) {
-				aio_complete(dio->iocb, dio->result, 0);
+				aio_complete(dio->iocb, transferred, 0);
 				kfree(dio);
 				return;
 			} else {
@@ -951,6 +964,7 @@ direct_io_worker(int rw, struct kiocb *i
 	dio->page_errors = 0;
 	dio->result = 0;
 	dio->iocb = iocb;
+	dio->i_size = i_size_read(inode);
 
 	/*
 	 * BIO completion state.
@@ -1206,7 +1220,8 @@ __blockdev_direct_IO(int rw, struct kioc
 	 */
 	dio->lock_type = dio_lock_type;
 	if (dio_lock_type != DIO_NO_LOCKING) {
-		if (rw == READ) {
+		/* watch out for a 0 len io from a tricksy fs */
+		if (rw == READ && end > offset) {
 			struct address_space *mapping;
 
 			mapping = iocb->ki_filp->f_mapping;
@@ -1214,7 +1229,9 @@ __blockdev_direct_IO(int rw, struct kioc
 				down(&inode->i_sem);
 				reader_with_isem = 1;
 			}
-			retval = filemap_write_and_wait(mapping);
+
+			retval = filemap_write_and_wait_range(mapping, offset,
+							      end - 1);
 			if (retval) {
 				kfree(dio);
 				goto out;
diff --git a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -505,14 +505,12 @@ static void prune_dqcache(int count)
 
 static int shrink_dqcache_memory(int nr, unsigned int gfp_mask)
 {
-	int ret;
-
-	spin_lock(&dq_list_lock);
-	if (nr)
+	if (nr) {
+		spin_lock(&dq_list_lock);
 		prune_dqcache(nr);
-	ret = dqstats.allocated_dquots;
-	spin_unlock(&dq_list_lock);
-	return ret;
+		spin_unlock(&dq_list_lock);
+	}
+	return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure;
 }
 
 /*
@@ -1092,7 +1090,7 @@ warn_put_all:
 }
 
 /*
- * This is a non-blocking operation.
+ * This operation can block, but only after everything is updated
  */
 int dquot_free_space(struct inode *inode, qsize_t number)
 {
@@ -1128,7 +1126,7 @@ out_sub:
 }
 
 /*
- * This is a non-blocking operation.
+ * This operation can block, but only after everything is updated
  */
 int dquot_free_inode(const struct inode *inode, unsigned long number)
 {
@@ -1163,6 +1161,7 @@ int dquot_free_inode(const struct inode 
  * Transfer the number of inode and blocks from one diskquota to an other.
  *
  * This operation can block, but only after everything is updated
+ * A transaction must be started when entering this function.
  */
 int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
@@ -1444,6 +1443,7 @@ static int vfs_quota_on_inode(struct ino
 	oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA);
 	inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
 	up_write(&dqopt->dqptr_sem);
+	sb->dq_op->drop(inode);
 
 	error = -EIO;
 	dqopt->files[type] = igrab(inode);
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -320,7 +320,7 @@ static struct super_block *eventpollfs_g
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
  */
-struct semaphore epsem;
+static struct semaphore epsem;
 
 /* Safe wake up implementation */
 static struct poll_safewake psw;
@@ -619,6 +619,7 @@ eexit_1:
 	return error;
 }
 
+#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
 
 /*
  * Implement the event wait interface for the eventpoll file. It is the kernel
@@ -635,12 +636,14 @@ asmlinkage long sys_epoll_wait(int epfd,
 		     current, epfd, events, maxevents, timeout));
 
 	/* The maximum number of event must be greater than zero */
-	if (maxevents <= 0)
+	if (maxevents <= 0 || maxevents > MAX_EVENTS)
 		return -EINVAL;
 
 	/* Verify that the area passed by the user is writeable */
-	if ((error = verify_area(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))))
+	if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
+		error = -EFAULT;
 		goto eexit_1;
+	}
 
 	/* Get the "struct file *" for the eventpoll file */
 	error = -EBADF;
diff --git a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -197,7 +197,8 @@ static int count(char __user * __user * 
  * 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_strings(int argc,char __user * __user * argv, struct linux_binprm *bprm)
+static int copy_strings(int argc, char __user * __user * argv,
+			struct linux_binprm *bprm)
 {
 	struct page *kmapped_page = NULL;
 	char *kaddr = NULL;
@@ -326,9 +327,9 @@ void install_arg_page(struct vm_area_str
 		pte_unmap(pte);
 		goto out;
 	}
-	mm->rss++;
+	inc_mm_counter(mm, rss);
 	lru_cache_add_active(page);
-	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(
+	set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(
 					page, vma->vm_page_prot))));
 	page_add_anon_rmap(page, vma, address);
 	pte_unmap(pte);
@@ -400,7 +401,8 @@ int setup_arg_pages(struct linux_binprm 
 	while (i < MAX_ARG_PAGES)
 		bprm->page[i++] = NULL;
 #else
-	stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE;
+	stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE);
+	stack_base = PAGE_ALIGN(stack_base);
 	bprm->p += stack_base;
 	mm->arg_start = bprm->p;
 	arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);
@@ -814,7 +816,7 @@ void get_task_comm(char *buf, struct tas
 {
 	/* buf must be at least sizeof(tsk->comm) in size */
 	task_lock(tsk);
-	memcpy(buf, tsk->comm, sizeof(tsk->comm));
+	strncpy(buf, tsk->comm, sizeof(tsk->comm));
 	task_unlock(tsk);
 }
 
@@ -867,9 +869,11 @@ int flush_old_exec(struct linux_binprm *
 	if (current->euid == current->uid && current->egid == current->gid)
 		current->mm->dumpable = 1;
 	name = bprm->filename;
+
+	/* Copies the binary name from after last slash */
 	for (i=0; (ch = *(name++)) != '\0';) {
 		if (ch == '/')
-			i = 0;
+			i = 0; /* overwrite what we wrote */
 		else
 			if (i < (sizeof(tcomm) - 1))
 				tcomm[i++] = ch;
@@ -877,6 +881,7 @@ int flush_old_exec(struct linux_binprm *
 	tcomm[i] = '\0';
 	set_task_comm(current, tcomm);
 
+	current->flags &= ~PF_RANDOMIZE;
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
@@ -1191,8 +1196,8 @@ int do_execve(char * filename,
 
 		/* execve success */
 		security_bprm_free(bprm);
-		acct_update_integrals();
-		update_mem_hiwater();
+		acct_update_integrals(current);
+		update_mem_hiwater(current);
 		kfree(bprm);
 		return retval;
 	}
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -55,7 +55,7 @@ find_exported_dentry(struct super_block 
 	struct list_head *le, *head;
 	struct dentry *toput = NULL;
 	int noprogress;
-
+	char nbuf[NAME_MAX+1];
 
 	/*
 	 * Attempt to find the inode.
@@ -176,7 +176,6 @@ find_exported_dentry(struct super_block 
 			 */
 			struct dentry *ppd;
 			struct dentry *npd;
-			char nbuf[NAME_MAX+1];
 
 			down(&pd->d_inode->i_sem);
 			ppd = CALL(nops,get_parent)(pd);
@@ -241,7 +240,6 @@ find_exported_dentry(struct super_block 
 	/* if we weren't after a directory, have one more step to go */
 	if (result != target_dir) {
 		struct dentry *nresult;
-		char nbuf[NAME_MAX+1];
 		err = CALL(nops,get_name)(target_dir, nbuf, result);
 		if (!err) {
 			down(&target_dir->d_inode->i_sem);
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -283,6 +283,8 @@ ext2_check_acl(struct inode *inode, int 
 {
 	struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
 
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
 	if (acl) {
 		int error = posix_acl_permission(inode, acl, mask);
 		posix_acl_release(acl);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -592,6 +592,7 @@ int ext2_make_empty(struct inode *inode,
 		goto fail;
 	}
 	kaddr = kmap_atomic(page, KM_USER0);
+       memset(kaddr, 0, chunk_size);
 	de = (struct ext2_dir_entry_2 *)kaddr;
 	de->name_len = 1;
 	de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -116,6 +116,7 @@ extern unsigned long ext2_count_free (st
 /* inode.c */
 extern void ext2_read_inode (struct inode *);
 extern int ext2_write_inode (struct inode *, int);
+extern void ext2_put_inode (struct inode *);
 extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern void ext2_discard_prealloc (struct inode *);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -53,6 +53,19 @@ static inline int ext2_inode_is_fast_sym
 }
 
 /*
+ * Called at each iput().
+ *
+ * The inode may be "bad" if ext2_read_inode() saw an error from
+ * ext2_get_inode(), so we need to check that to avoid freeing random disk
+ * blocks.
+ */
+void ext2_put_inode(struct inode *inode)
+{
+	if (!is_bad_inode(inode))
+		ext2_discard_prealloc(inode);
+}
+
+/*
  * Called at the last iput() if i_nlink is zero.
  */
 void ext2_delete_inode (struct inode * inode)
@@ -626,6 +639,12 @@ ext2_nobh_prepare_write(struct file *fil
 	return nobh_prepare_write(page,from,to,ext2_get_block);
 }
 
+static int ext2_nobh_writepage(struct page *page,
+			struct writeback_control *wbc)
+{
+	return nobh_writepage(page, ext2_get_block, wbc);
+}
+
 static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,ext2_get_block);
@@ -675,7 +694,7 @@ struct address_space_operations ext2_aop
 struct address_space_operations ext2_nobh_aops = {
 	.readpage		= ext2_readpage,
 	.readpages		= ext2_readpages,
-	.writepage		= ext2_writepage,
+	.writepage		= ext2_nobh_writepage,
 	.sync_page		= block_sync_page,
 	.prepare_write		= ext2_nobh_prepare_write,
 	.commit_write		= nobh_commit_write,
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -198,11 +198,8 @@ static void ext2_clear_inode(struct inod
 		ei->i_default_acl = EXT2_ACL_NOT_CACHED;
 	}
 #endif
-	if (!is_bad_inode(inode))
-		ext2_discard_prealloc(inode);
 }
 
-
 #ifdef CONFIG_QUOTA
 static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);
 static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);
@@ -213,6 +210,7 @@ static struct super_operations ext2_sops
 	.destroy_inode	= ext2_destroy_inode,
 	.read_inode	= ext2_read_inode,
 	.write_inode	= ext2_write_inode,
+	.put_inode	= ext2_put_inode,
 	.delete_inode	= ext2_delete_inode,
 	.put_super	= ext2_put_super,
 	.write_super	= ext2_write_super,
@@ -518,12 +516,18 @@ static int ext2_check_descriptors (struc
 static loff_t ext2_max_size(int bits)
 {
 	loff_t res = EXT2_NDIR_BLOCKS;
+	/* This constant is calculated to be the largest file size for a
+	 * dense, 4k-blocksize file such that the total number of
+	 * sectors in the file, including data and all indirect blocks,
+	 * does not exceed 2^32. */
+	const loff_t upper_limit = 0x1ff7fffd000LL;
+
 	res += 1LL << (bits-2);
 	res += 1LL << (2*(bits-2));
 	res += 1LL << (3*(bits-2));
 	res <<= bits;
-	if (res > (512LL << 32) - (1 << bits))
-		res = (512LL << 32) - (1 << bits);
+	if (res > upper_limit)
+		res = upper_limit;
 	return res;
 }
 
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -197,8 +197,7 @@ ext3_get_acl(struct inode *inode, int ty
 		acl = NULL;
 	else
 		acl = ERR_PTR(retval);
-	if (value)
-		kfree(value);
+	kfree(value);
 
 	if (!IS_ERR(acl)) {
 		switch(type) {
@@ -267,8 +266,7 @@ ext3_set_acl(handle_t *handle, struct in
 	error = ext3_xattr_set_handle(handle, inode, name_index, "",
 				      value, size, 0);
 
-	if (value)
-		kfree(value);
+	kfree(value);
 	if (!error) {
 		switch(type) {
 			case ACL_TYPE_ACCESS:
@@ -288,6 +286,8 @@ ext3_check_acl(struct inode *inode, int 
 {
 	struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
 
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
 	if (acl) {
 		int error = posix_acl_permission(inode, acl, mask);
 		posix_acl_release(acl);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -43,34 +43,34 @@ struct ext3_group_desc * ext3_get_group_
 					     struct buffer_head ** bh)
 {
 	unsigned long group_desc;
-	unsigned long desc;
-	struct ext3_group_desc * gdp;
+	unsigned long offset;
+	struct ext3_group_desc * desc;
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
 
-	if (block_group >= EXT3_SB(sb)->s_groups_count) {
+	if (block_group >= sbi->s_groups_count) {
 		ext3_error (sb, "ext3_get_group_desc",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, EXT3_SB(sb)->s_groups_count);
+			    block_group, sbi->s_groups_count);
 
 		return NULL;
 	}
 	smp_rmb();
 
 	group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb);
-	desc = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1);
-	if (!EXT3_SB(sb)->s_group_desc[group_desc]) {
+	offset = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1);
+	if (!sbi->s_group_desc[group_desc]) {
 		ext3_error (sb, "ext3_get_group_desc",
 			    "Group descriptor not loaded - "
 			    "block_group = %d, group_desc = %lu, desc = %lu",
-			     block_group, group_desc, desc);
+			     block_group, group_desc, offset);
 		return NULL;
 	}
 
-	gdp = (struct ext3_group_desc *) 
-	      EXT3_SB(sb)->s_group_desc[group_desc]->b_data;
+	desc = (struct ext3_group_desc *) sbi->s_group_desc[group_desc]->b_data;
 	if (bh)
-		*bh = EXT3_SB(sb)->s_group_desc[group_desc];
-	return gdp + desc;
+		*bh = sbi->s_group_desc[group_desc];
+	return desc + offset;
 }
 
 /*
@@ -250,7 +250,7 @@ static void rsv_window_remove(struct sup
 {
 	rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
 	rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
-	atomic_set(&rsv->rsv_alloc_hit, 0);
+	rsv->rsv_alloc_hit = 0;
 	rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root);
 }
 
@@ -259,16 +259,50 @@ static inline int rsv_is_empty(struct ex
 	/* a valid reservation end block could not be 0 */
 	return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED);
 }
+void ext3_init_block_alloc_info(struct inode *inode)
+{
+	struct ext3_inode_info *ei = EXT3_I(inode);
+	struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info;
+	struct super_block *sb = inode->i_sb;
+
+	block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
+	if (block_i) {
+		struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node;
+
+		rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+		rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+
+	 	/*
+		 * if filesystem is mounted with NORESERVATION, the goal
+		 * reservation window size is set to zero to indicate
+		 * block reservation is off
+		 */
+		if (!test_opt(sb, RESERVATION))
+			rsv->rsv_goal_size = 0;
+		else
+			rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS;
+		rsv->rsv_alloc_hit = 0;
+		block_i->last_alloc_logical_block = 0;
+		block_i->last_alloc_physical_block = 0;
+	}
+	ei->i_block_alloc_info = block_i;
+}
 
 void ext3_discard_reservation(struct inode *inode)
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
-	struct ext3_reserve_window_node *rsv = &ei->i_rsv_window;
+	struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info;
+	struct ext3_reserve_window_node *rsv;
 	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
 
+	if (!block_i)
+		return;
+
+	rsv = &block_i->rsv_window_node;
 	if (!rsv_is_empty(&rsv->rsv_window)) {
 		spin_lock(rsv_lock);
-		rsv_window_remove(inode->i_sb, rsv);
+		if (!rsv_is_empty(&rsv->rsv_window))
+			rsv_window_remove(inode->i_sb, rsv);
 		spin_unlock(rsv_lock);
 	}
 }
@@ -284,14 +318,15 @@ void ext3_free_blocks_sb(handle_t *handl
 	unsigned long bit;
 	unsigned long i;
 	unsigned long overflow;
-	struct ext3_group_desc * gdp;
+	struct ext3_group_desc * desc;
 	struct ext3_super_block * es;
 	struct ext3_sb_info *sbi;
 	int err = 0, ret;
+	unsigned group_freed;
 
 	*pdquot_freed_blocks = 0;
 	sbi = EXT3_SB(sb);
-	es = EXT3_SB(sb)->s_es;
+	es = sbi->s_es;
 	if (block < le32_to_cpu(es->s_first_data_block) ||
 	    block + count < block ||
 	    block + count > le32_to_cpu(es->s_blocks_count)) {
@@ -301,7 +336,7 @@ void ext3_free_blocks_sb(handle_t *handl
 		goto error_return;
 	}
 
-	ext3_debug ("freeing block %lu\n", block);
+	ext3_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1);
 
 do_more:
 	overflow = 0;
@@ -321,16 +356,16 @@ do_more:
 	bitmap_bh = read_block_bitmap(sb, block_group);
 	if (!bitmap_bh)
 		goto error_return;
-	gdp = ext3_get_group_desc (sb, block_group, &gd_bh);
-	if (!gdp)
+	desc = ext3_get_group_desc (sb, block_group, &gd_bh);
+	if (!desc)
 		goto error_return;
 
-	if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
-	    in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
-	    in_range (block, le32_to_cpu(gdp->bg_inode_table),
-		      EXT3_SB(sb)->s_itb_per_group) ||
-	    in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-		      EXT3_SB(sb)->s_itb_per_group))
+	if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) ||
+	    in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) ||
+	    in_range (block, le32_to_cpu(desc->bg_inode_table),
+		      sbi->s_itb_per_group) ||
+	    in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
+		      sbi->s_itb_per_group))
 		ext3_error (sb, "ext3_free_blocks",
 			    "Freeing blocks in system zones - "
 			    "Block = %lu, count = %lu",
@@ -342,7 +377,7 @@ do_more:
 	 */
 	/* @@@ check errors */
 	BUFFER_TRACE(bitmap_bh, "getting undo access");
-	err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
+	err = ext3_journal_get_undo_access(handle, bitmap_bh);
 	if (err)
 		goto error_return;
 
@@ -358,7 +393,7 @@ do_more:
 
 	jbd_lock_bh_state(bitmap_bh);
 
-	for (i = 0; i < count; i++) {
+	for (i = 0, group_freed = 0; i < count; i++) {
 		/*
 		 * An HJ special.  This is expensive...
 		 */
@@ -421,15 +456,15 @@ do_more:
 			jbd_lock_bh_state(bitmap_bh);
 			BUFFER_TRACE(bitmap_bh, "bit already cleared");
 		} else {
-			(*pdquot_freed_blocks)++;
+			group_freed++;
 		}
 	}
 	jbd_unlock_bh_state(bitmap_bh);
 
 	spin_lock(sb_bgl_lock(sbi, block_group));
-	gdp->bg_free_blocks_count =
-		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) +
-			*pdquot_freed_blocks);
+	desc->bg_free_blocks_count =
+		cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
+			group_freed);
 	spin_unlock(sb_bgl_lock(sbi, block_group));
 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
 
@@ -441,6 +476,7 @@ do_more:
 	BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
 	ret = ext3_journal_dirty_metadata(handle, gd_bh);
 	if (!err) err = ret;
+	*pdquot_freed_blocks += group_freed;
 
 	if (overflow && !err) {
 		block += count;
@@ -838,7 +874,7 @@ static int alloc_new_reservation(struct 
 	else
 		start_block = goal + group_first_block;
 
-	size = atomic_read(&my_rsv->rsv_goal_size);
+	size = my_rsv->rsv_goal_size;
 	if (!rsv_is_empty(&my_rsv->rsv_window)) {
 		/*
 		 * if the old reservation is cross group boundary
@@ -859,7 +895,7 @@ static int alloc_new_reservation(struct 
 				(start_block >= my_rsv->rsv_start))
 			return -1;
 
-		if ((atomic_read(&my_rsv->rsv_alloc_hit) >
+		if ((my_rsv->rsv_alloc_hit >
 		     (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
 			/*
 			 * if we previously allocation hit ration is greater than half
@@ -869,7 +905,7 @@ static int alloc_new_reservation(struct 
 			size = size * 2;
 			if (size > EXT3_MAX_RESERVE_BLOCKS)
 				size = EXT3_MAX_RESERVE_BLOCKS;
-			atomic_set(&my_rsv->rsv_goal_size, size);
+			my_rsv->rsv_goal_size= size;
 		}
 	}
 	/*
@@ -944,7 +980,7 @@ found_rsv_window:
 	}
 	my_rsv->rsv_start = reservable_space_start;
 	my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
-	atomic_set(&my_rsv->rsv_alloc_hit, 0);
+	my_rsv->rsv_alloc_hit = 0;
 	if (my_rsv != prev_rsv)  {
 		ext3_rsv_window_add(sb, my_rsv);
 	}
@@ -991,7 +1027,6 @@ ext3_try_to_allocate_with_rsv(struct sup
 	unsigned long group_first_block;
 	int ret = 0;
 	int fatal;
-	int credits = 0;
 
 	*errp = 0;
 
@@ -1001,7 +1036,7 @@ ext3_try_to_allocate_with_rsv(struct sup
 	 * if the buffer is in BJ_Forget state in the committing transaction.
 	 */
 	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
-	fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
+	fatal = ext3_journal_get_undo_access(handle, bitmap_bh);
 	if (fatal) {
 		*errp = fatal;
 		return -1;
@@ -1044,23 +1079,17 @@ ext3_try_to_allocate_with_rsv(struct sup
 	 */
 	while (1) {
 		struct ext3_reserve_window rsv_copy;
-		unsigned int seq;
 
-		do {
-			seq = read_seqbegin(&my_rsv->rsv_seqlock);
-			rsv_copy._rsv_start = my_rsv->rsv_start;
-			rsv_copy._rsv_end = my_rsv->rsv_end;
-		} while (read_seqretry(&my_rsv->rsv_seqlock, seq));
+		rsv_copy._rsv_start = my_rsv->rsv_start;
+		rsv_copy._rsv_end = my_rsv->rsv_end;
 
 		if (rsv_is_empty(&rsv_copy) || (ret < 0) ||
 			!goal_in_my_reservation(&rsv_copy, goal, group, sb)) {
 			spin_lock(rsv_lock);
-			write_seqlock(&my_rsv->rsv_seqlock);
 			ret = alloc_new_reservation(my_rsv, goal, sb,
 							group, bitmap_bh);
 			rsv_copy._rsv_start = my_rsv->rsv_start;
 			rsv_copy._rsv_end = my_rsv->rsv_end;
-			write_sequnlock(&my_rsv->rsv_seqlock);
 			spin_unlock(rsv_lock);
 			if (ret < 0)
 				break;			/* failed */
@@ -1074,8 +1103,7 @@ ext3_try_to_allocate_with_rsv(struct sup
 		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
 					   &rsv_copy);
 		if (ret >= 0) {
-			if (!read_seqretry(&my_rsv->rsv_seqlock, seq))
-				atomic_inc(&my_rsv->rsv_alloc_hit);
+			my_rsv->rsv_alloc_hit++;
 			break;				/* succeed */
 		}
 	}
@@ -1092,7 +1120,7 @@ out:
 	}
 
 	BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
-	ext3_journal_release_buffer(handle, bitmap_bh, credits);
+	ext3_journal_release_buffer(handle, bitmap_bh);
 	return ret;
 }
 
@@ -1152,7 +1180,7 @@ int ext3_new_block(handle_t *handle, str
 	struct ext3_super_block *es;
 	struct ext3_sb_info *sbi;
 	struct ext3_reserve_window_node *my_rsv = NULL;
-	struct ext3_reserve_window_node *rsv = &EXT3_I(inode)->i_rsv_window;
+	struct ext3_block_alloc_info *block_i;
 	unsigned short windowsz = 0;
 #ifdef EXT3FS_DEBUG
 	static int goal_hits, goal_attempts;
@@ -1185,10 +1213,10 @@ int ext3_new_block(handle_t *handle, str
 	 * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off
 	 * reservation on that particular file)
 	 */
-	windowsz = atomic_read(&rsv->rsv_goal_size);
-	if (test_opt(sb, RESERVATION) &&
-		S_ISREG(inode->i_mode) && (windowsz > 0))
-		my_rsv = rsv;
+	block_i = EXT3_I(inode)->i_block_alloc_info;
+	if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
+		my_rsv = &block_i->rsv_window_node;
+
 	if (!ext3_has_free_blocks(sbi)) {
 		*errp = -ENOSPC;
 		goto out;
@@ -1209,6 +1237,14 @@ int ext3_new_block(handle_t *handle, str
 	goal_group = group_no;
 retry:
 	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+	/*
+	 * if there is not enough free blocks to make a new resevation
+	 * turn off reservation for this allocation
+	 */
+	if (my_rsv && (free_blocks < windowsz)
+		&& (rsv_is_empty(&my_rsv->rsv_window)))
+		my_rsv = NULL;
+
 	if (free_blocks > 0) {
 		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
 				EXT3_BLOCKS_PER_GROUP(sb));
@@ -1429,9 +1465,8 @@ unsigned long ext3_count_free_blocks(str
 #endif
 }
 
-static inline int block_in_use(unsigned long block,
-				struct super_block * sb,
-				unsigned char * map)
+static inline int
+block_in_use(unsigned long block, struct super_block *sb, unsigned char *map)
 {
 	return ext3_test_bit ((block -
 		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) %
@@ -1451,8 +1486,10 @@ static int ext3_group_sparse(int group)
 {
 	if (group <= 1)
 		return 1;
-	return (test_root(group, 3) || test_root(group, 5) ||
-		test_root(group, 7));
+	if (!(group & 1))
+		return 0;
+	return (test_root(group, 7) || test_root(group, 5) ||
+		test_root(group, 3));
 }
 
 /**
diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c
--- a/fs/ext3/hash.c
+++ b/fs/ext3/hash.c
@@ -13,6 +13,7 @@
 #include <linux/jbd.h>
 #include <linux/sched.h>
 #include <linux/ext3_fs.h>
+#include <linux/cryptohash.h>
 
 #define DELTA 0x9E3779B9
 
@@ -33,73 +34,6 @@ static void TEA_transform(__u32 buf[4], 
 	buf[1] += b1;
 }
 
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s)	\
-	(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
-#define K1 0
-#define K2 013240474631UL
-#define K3 015666365641UL
-
-/*
- * Basic cut-down MD4 transform.  Returns only 32 bits of result.
- */
-static void halfMD4Transform (__u32 buf[4], __u32 const in[])
-{
-	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
-	/* Round 1 */
-	ROUND(F, a, b, c, d, in[0] + K1,  3);
-	ROUND(F, d, a, b, c, in[1] + K1,  7);
-	ROUND(F, c, d, a, b, in[2] + K1, 11);
-	ROUND(F, b, c, d, a, in[3] + K1, 19);
-	ROUND(F, a, b, c, d, in[4] + K1,  3);
-	ROUND(F, d, a, b, c, in[5] + K1,  7);
-	ROUND(F, c, d, a, b, in[6] + K1, 11);
-	ROUND(F, b, c, d, a, in[7] + K1, 19);
-
-	/* Round 2 */
-	ROUND(G, a, b, c, d, in[1] + K2,  3);
-	ROUND(G, d, a, b, c, in[3] + K2,  5);
-	ROUND(G, c, d, a, b, in[5] + K2,  9);
-	ROUND(G, b, c, d, a, in[7] + K2, 13);
-	ROUND(G, a, b, c, d, in[0] + K2,  3);
-	ROUND(G, d, a, b, c, in[2] + K2,  5);
-	ROUND(G, c, d, a, b, in[4] + K2,  9);
-	ROUND(G, b, c, d, a, in[6] + K2, 13);
-
-	/* Round 3 */
-	ROUND(H, a, b, c, d, in[3] + K3,  3);
-	ROUND(H, d, a, b, c, in[7] + K3,  9);
-	ROUND(H, c, d, a, b, in[2] + K3, 11);
-	ROUND(H, b, c, d, a, in[6] + K3, 15);
-	ROUND(H, a, b, c, d, in[1] + K3,  3);
-	ROUND(H, d, a, b, c, in[5] + K3,  9);
-	ROUND(H, c, d, a, b, in[0] + K3, 11);
-	ROUND(H, b, c, d, a, in[4] + K3, 15);
-
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
-}
-
-#undef ROUND
-#undef F
-#undef G
-#undef H
-#undef K1
-#undef K2
-#undef K3
 
 /* The old legacy hash */
 static __u32 dx_hack_hash (const char *name, int len)
@@ -187,7 +121,7 @@ int ext3fs_dirhash(const char *name, int
 		p = name;
 		while (len > 0) {
 			str2hashbuf(p, len, in, 8);
-			halfMD4Transform(buf, in);
+			half_md4_transform(buf, in);
 			len -= 32;
 			p += 32;
 		}
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -460,9 +460,12 @@ struct inode *ext3_new_inode(handle_t *h
 		goto out;
 
 	for (i = 0; i < sbi->s_groups_count; i++) {
+		err = -EIO;
+
 		gdp = ext3_get_group_desc(sb, group, &bh2);
+		if (!gdp)
+			goto fail;
 
-		err = -EIO;
 		brelse(bitmap_bh);
 		bitmap_bh = read_inode_bitmap(sb, group);
 		if (!bitmap_bh)
@@ -474,11 +477,9 @@ repeat_in_this_group:
 		ino = ext3_find_next_zero_bit((unsigned long *)
 				bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino);
 		if (ino < EXT3_INODES_PER_GROUP(sb)) {
-			int credits = 0;
 
 			BUFFER_TRACE(bitmap_bh, "get_write_access");
-			err = ext3_journal_get_write_access_credits(handle,
-							bitmap_bh, &credits);
+			err = ext3_journal_get_write_access(handle, bitmap_bh);
 			if (err)
 				goto fail;
 
@@ -494,7 +495,7 @@ repeat_in_this_group:
 				goto got;
 			}
 			/* we lost it */
-			journal_release_buffer(handle, bitmap_bh, credits);
+			journal_release_buffer(handle, bitmap_bh);
 
 			if (++ino < EXT3_INODES_PER_GROUP(sb))
 				goto repeat_in_this_group;
@@ -561,8 +562,6 @@ got:
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 
 	memset(ei->i_data, 0, sizeof(ei->i_data));
-	ei->i_next_alloc_block = 0;
-	ei->i_next_alloc_goal = 0;
 	ei->i_dir_start_lookup = 0;
 	ei->i_disksize = 0;
 
@@ -580,11 +579,7 @@ got:
 	ei->i_file_acl = 0;
 	ei->i_dir_acl = 0;
 	ei->i_dtime = 0;
-	ei->i_rsv_window.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
-	ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
-	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
-	atomic_set(&ei->i_rsv_window.rsv_alloc_hit, 0);
-	seqlock_init(&ei->i_rsv_window.rsv_seqlock);
+	ei->i_block_alloc_info = NULL;
 	ei->i_block_group = group;
 
 	ext3_set_inode_flags(inode);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -455,34 +455,24 @@ static unsigned long ext3_find_near(stru
  *	@goal:	place to store the result.
  *
  *	Normally this function find the prefered place for block allocation,
- *	stores it in *@goal and returns zero. If the branch had been changed
- *	under us we return -EAGAIN.
+ *	stores it in *@goal and returns zero.
  */
 
-static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
-			  Indirect *partial, unsigned long *goal)
+static unsigned long ext3_find_goal(struct inode *inode, long block,
+		Indirect chain[4], Indirect *partial)
 {
-	struct ext3_inode_info *ei = EXT3_I(inode);
-	/* Writer: ->i_next_alloc* */
-	if ((block == ei->i_next_alloc_block + 1)&& ei->i_next_alloc_goal) {
-		ei->i_next_alloc_block++;
-		ei->i_next_alloc_goal++;
-	}
-	/* Writer: end */
-	/* Reader: pointers, ->i_next_alloc* */
-	if (verify_chain(chain, partial)) {
-		/*
-		 * try the heuristic for sequential allocation,
-		 * failing that at least try to get decent locality.
-		 */
-		if (block == ei->i_next_alloc_block)
-			*goal = ei->i_next_alloc_goal;
-		if (!*goal)
-			*goal = ext3_find_near(inode, partial);
-		return 0;
+	struct ext3_block_alloc_info *block_i =  EXT3_I(inode)->i_block_alloc_info;
+
+	/*
+	 * try the heuristic for sequential allocation,
+	 * failing that at least try to get decent locality.
+	 */
+	if (block_i && (block == block_i->last_alloc_logical_block + 1)
+		&& (block_i->last_alloc_physical_block != 0)) {
+		return block_i->last_alloc_physical_block + 1;
 	}
-	/* Reader: end */
-	return -EAGAIN;
+
+	return ext3_find_near(inode, partial);
 }
 
 /**
@@ -586,12 +576,9 @@ static int ext3_alloc_branch(handle_t *h
  *	@where: location of missing link
  *	@num:   number of blocks we are adding
  *
- *	This function verifies that chain (up to the missing link) had not
- *	changed, fills the missing link and does all housekeeping needed in
+ *	This function fills the missing link and does all housekeeping needed in
  *	inode (->i_blocks, etc.). In case of success we end up with the full
- *	chain to new block and return 0. Otherwise (== chain had been changed)
- *	we free the new blocks (forgetting their buffer_heads, indeed) and
- *	return -EAGAIN.
+ *	chain to new block and return 0.
  */
 
 static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
@@ -599,7 +586,7 @@ static int ext3_splice_branch(handle_t *
 {
 	int i;
 	int err = 0;
-	struct ext3_inode_info *ei = EXT3_I(inode);
+	struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info;
 
 	/*
 	 * If we're splicing into a [td]indirect block (as opposed to the
@@ -612,19 +599,19 @@ static int ext3_splice_branch(handle_t *
 		if (err)
 			goto err_out;
 	}
-	/* Verify that place we are splicing to is still there and vacant */
-
-	/* Writer: pointers, ->i_next_alloc* */
-	if (!verify_chain(chain, where-1) || *where->p)
-		/* Writer: end */
-		goto changed;
-
 	/* That's it */
 
 	*where->p = where->key;
-	ei->i_next_alloc_block = block;
-	ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
-	/* Writer: end */
+
+	/*
+	 * update the most recently allocated logical & physical block
+	 * in i_block_alloc_info, to assist find the proper goal block for next
+	 * allocation
+	 */
+	if (block_i) {
+		block_i->last_alloc_logical_block = block;
+		block_i->last_alloc_physical_block = le32_to_cpu(where[num-1].key);
+	}
 
 	/* We are done with atomic stuff, now do the rest of housekeeping */
 
@@ -655,26 +642,11 @@ static int ext3_splice_branch(handle_t *
 	}
 	return err;
 
-changed:
-	/*
-	 * AKPM: if where[i].bh isn't part of the current updating
-	 * transaction then we explode nastily.  Test this code path.
-	 */
-	jbd_debug(1, "the chain changed: try again\n");
-	err = -EAGAIN;
-
 err_out:
 	for (i = 1; i < num; i++) {
 		BUFFER_TRACE(where[i].bh, "call journal_forget");
 		ext3_journal_forget(handle, where[i].bh);
 	}
-	/* For the normal collision cleanup case, we free up the blocks.
-	 * On genuine filesystem errors we don't even think about doing
-	 * that. */
-	if (err == -EAGAIN)
-		for (i = 0; i < num; i++)
-			ext3_free_blocks(handle, inode, 
-					 le32_to_cpu(where[i].key), 1);
 	return err;
 }
 
@@ -706,7 +678,7 @@ ext3_get_block_handle(handle_t *handle, 
 	unsigned long goal;
 	int left;
 	int boundary = 0;
-	int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
+	const int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
 	struct ext3_inode_info *ei = EXT3_I(inode);
 
 	J_ASSERT(handle != NULL || create == 0);
@@ -714,48 +686,55 @@ ext3_get_block_handle(handle_t *handle, 
 	if (depth == 0)
 		goto out;
 
-reread:
 	partial = ext3_get_branch(inode, depth, offsets, chain, &err);
 
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
 		clear_buffer_new(bh_result);
-got_it:
-		map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
-		if (boundary)
-			set_buffer_boundary(bh_result);
-		/* Clean up and exit */
-		partial = chain+depth-1; /* the whole chain */
-		goto cleanup;
+		goto got_it;
 	}
 
 	/* Next simple case - plain lookup or failed read of indirect block */
-	if (!create || err == -EIO) {
-cleanup:
+	if (!create || err == -EIO)
+		goto cleanup;
+
+	down(&ei->truncate_sem);
+
+	/*
+	 * If the indirect block is missing while we are reading
+	 * the chain(ext3_get_branch() returns -EAGAIN err), or
+	 * if the chain has been changed after we grab the semaphore,
+	 * (either because another process truncated this branch, or
+	 * another get_block allocated this branch) re-grab the chain to see if
+	 * the request block has been allocated or not.
+	 *
+	 * Since we already block the truncate/other get_block
+	 * at this point, we will have the current copy of the chain when we
+	 * splice the branch into the tree.
+	 */
+	if (err == -EAGAIN || !verify_chain(chain, partial)) {
 		while (partial > chain) {
-			BUFFER_TRACE(partial->bh, "call brelse");
 			brelse(partial->bh);
 			partial--;
 		}
-		BUFFER_TRACE(bh_result, "returned");
-out:
-		return err;
+		partial = ext3_get_branch(inode, depth, offsets, chain, &err);
+		if (!partial) {
+			up(&ei->truncate_sem);
+			if (err)
+				goto cleanup;
+			clear_buffer_new(bh_result);
+			goto got_it;
+		}
 	}
 
 	/*
-	 * Indirect block might be removed by truncate while we were
-	 * reading it. Handling of that case (forget what we've got and
-	 * reread) is taken out of the main path.
-	 */
-	if (err == -EAGAIN)
-		goto changed;
+	 * Okay, we need to do block allocation.  Lazily initialize the block
+	 * allocation info here if necessary
+	*/
+	if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
+		ext3_init_block_alloc_info(inode);
 
-	goal = 0;
-	down(&ei->truncate_sem);
-	if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) {
-		up(&ei->truncate_sem);
-		goto changed;
-	}
+	goal = ext3_find_goal(inode, iblock, chain, partial);
 
 	left = (chain + depth) - partial;
 
@@ -763,38 +742,45 @@ out:
 	 * Block out ext3_truncate while we alter the tree
 	 */
 	err = ext3_alloc_branch(handle, inode, left, goal,
-					offsets+(partial-chain), partial);
+				offsets + (partial - chain), partial);
 
-	/* The ext3_splice_branch call will free and forget any buffers
+	/*
+	 * The ext3_splice_branch call will free and forget any buffers
 	 * on the new chain if there is a failure, but that risks using
 	 * up transaction credits, especially for bitmaps where the
 	 * credits cannot be returned.  Can we handle this somehow?  We
-	 * may need to return -EAGAIN upwards in the worst case.  --sct */
+	 * may need to return -EAGAIN upwards in the worst case.  --sct
+	 */
 	if (!err)
 		err = ext3_splice_branch(handle, inode, iblock, chain,
 					 partial, left);
-	/* i_disksize growing is protected by truncate_sem
-	 * don't forget to protect it if you're about to implement
-	 * concurrent ext3_get_block() -bzzz */
+	/*
+	 * i_disksize growing is protected by truncate_sem.  Don't forget to
+	 * protect it if you're about to implement concurrent
+	 * ext3_get_block() -bzzz
+	*/
 	if (!err && extend_disksize && inode->i_size > ei->i_disksize)
 		ei->i_disksize = inode->i_size;
 	up(&ei->truncate_sem);
-	if (err == -EAGAIN)
-		goto changed;
 	if (err)
 		goto cleanup;
 
 	set_buffer_new(bh_result);
-	goto got_it;
-
-changed:
+got_it:
+	map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+	if (boundary)
+		set_buffer_boundary(bh_result);
+	/* Clean up and exit */
+	partial = chain + depth - 1;	/* the whole chain */
+cleanup:
 	while (partial > chain) {
-		jbd_debug(1, "buffer chain changed, retrying\n");
-		BUFFER_TRACE(partial->bh, "brelsing");
+		BUFFER_TRACE(partial->bh, "call brelse");
 		brelse(partial->bh);
 		partial--;
 	}
-	goto reread;
+	BUFFER_TRACE(bh_result, "returned");
+out:
+	return err;
 }
 
 static int ext3_get_block(struct inode *inode, sector_t iblock,
@@ -1010,7 +996,10 @@ retry:
 		ret = PTR_ERR(handle);
 		goto out;
 	}
-	ret = block_prepare_write(page, from, to, ext3_get_block);
+	if (test_opt(inode->i_sb, NOBH))
+		ret = nobh_prepare_write(page, from, to, ext3_get_block);
+	else
+		ret = block_prepare_write(page, from, to, ext3_get_block);
 	if (ret)
 		goto prepare_write_failed;
 
@@ -1094,7 +1083,12 @@ static int ext3_writeback_commit_write(s
 	new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 	if (new_i_size > EXT3_I(inode)->i_disksize)
 		EXT3_I(inode)->i_disksize = new_i_size;
-	ret = generic_commit_write(file, page, from, to);
+
+	if (test_opt(inode->i_sb, NOBH))
+		ret = nobh_commit_write(file, page, from, to);
+	else
+		ret = generic_commit_write(file, page, from, to);
+
 	ret2 = ext3_journal_stop(handle);
 	if (!ret)
 		ret = ret2;
@@ -1340,7 +1334,11 @@ static int ext3_writeback_writepage(stru
 		goto out_fail;
 	}
 
-	ret = block_write_full_page(page, ext3_get_block, wbc);
+	if (test_opt(inode->i_sb, NOBH))
+		ret = nobh_writepage(page, ext3_get_block, wbc);
+	else
+		ret = block_write_full_page(page, ext3_get_block, wbc);
+
 	err = ext3_journal_stop(handle);
 	if (!ret)
 		ret = err;
@@ -1439,6 +1437,8 @@ static int ext3_releasepage(struct page 
 	journal_t *journal = EXT3_JOURNAL(page->mapping->host);
 
 	WARN_ON(PageChecked(page));
+	if (!page_has_buffers(page))
+		return 0;
 	return journal_try_to_free_buffers(journal, page, wait);
 }
 
@@ -1600,13 +1600,28 @@ static int ext3_block_truncate_page(hand
 	unsigned blocksize, iblock, length, pos;
 	struct inode *inode = mapping->host;
 	struct buffer_head *bh;
-	int err;
+	int err = 0;
 	void *kaddr;
 
 	blocksize = inode->i_sb->s_blocksize;
 	length = blocksize - (offset & (blocksize - 1));
 	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 
+	/*
+	 * For "nobh" option,  we can only work if we don't need to
+	 * read-in the page - otherwise we create buffers to do the IO.
+	 */
+	if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH)) {
+		if (PageUptodate(page)) {
+			kaddr = kmap_atomic(page, KM_USER0);
+			memset(kaddr + offset, 0, length);
+			flush_dcache_page(page);
+			kunmap_atomic(kaddr, KM_USER0);
+			set_page_dirty(page);
+			goto unlock;
+		}
+	}
+
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 
@@ -2074,8 +2089,6 @@ void ext3_truncate(struct inode * inode)
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
 
-	ext3_discard_reservation(inode);
-
 	/*
 	 * We have to lock the EOF page here, because lock_page() nests
 	 * outside journal_start().
@@ -2200,6 +2213,9 @@ do_indirects:
 		case EXT3_TIND_BLOCK:
 			;
 	}
+
+	ext3_discard_reservation(inode);
+
 	up(&ei->truncate_sem);
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 	ext3_mark_inode_dirty(handle, inode);
@@ -2419,7 +2435,7 @@ void ext3_read_inode(struct inode * inod
 	ei->i_acl = EXT3_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT3_ACL_NOT_CACHED;
 #endif
-	ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+	ei->i_block_alloc_info = NULL;
 
 	if (__ext3_get_inode_loc(inode, &iloc, 0))
 		goto bad_inode;
@@ -2440,8 +2456,6 @@ void ext3_read_inode(struct inode * inod
 	inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
 
 	ei->i_state = 0;
-	ei->i_next_alloc_block = 0;
-	ei->i_next_alloc_goal = 0;
 	ei->i_dir_start_lookup = 0;
 	ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
 	/* We now have enough fields to check if the inode was active or not.
@@ -2481,10 +2495,6 @@ void ext3_read_inode(struct inode * inod
 	ei->i_disksize = inode->i_size;
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
 	ei->i_block_group = iloc.block_group;
-	ei->i_rsv_window.rsv_start = 0;
-	ei->i_rsv_window.rsv_end= 0;
-	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
-	seqlock_init(&ei->i_rsv_window.rsv_seqlock);
 	/*
 	 * NOTE! The in-memory inode i_data array is in little-endian order
 	 * even on big-endian machines: we do NOT byteswap the block numbers!
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -153,12 +153,15 @@ flags_err:
 		}
 #endif
 	case EXT3_IOC_GETRSVSZ:
-		if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) {
-			rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size);
+		if (test_opt(inode->i_sb, RESERVATION)
+			&& S_ISREG(inode->i_mode)
+			&& ei->i_block_alloc_info) {
+			rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
 			return put_user(rsv_window_size, (int __user *)arg);
 		}
 		return -ENOTTY;
-	case EXT3_IOC_SETRSVSZ:
+	case EXT3_IOC_SETRSVSZ: {
+
 		if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
 			return -ENOTTY;
 
@@ -173,8 +176,22 @@ flags_err:
 
 		if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS)
 			rsv_window_size = EXT3_MAX_RESERVE_BLOCKS;
-		atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size);
+
+		/*
+		 * need to allocate reservation structure for this inode
+		 * before set the window size
+		 */
+		down(&ei->truncate_sem);
+		if (!ei->i_block_alloc_info)
+			ext3_init_block_alloc_info(inode);
+
+		if (ei->i_block_alloc_info){
+			struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
+			rsv->rsv_goal_size = rsv_window_size;
+		}
+		up(&ei->truncate_sem);
 		return 0;
+	}
 	case EXT3_IOC_GROUP_EXTEND: {
 		unsigned long n_blocks_count;
 		struct super_block *sb = inode->i_sb;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -225,8 +225,16 @@ void __ext3_std_error (struct super_bloc
 		       int errno)
 {
 	char nbuf[16];
-	const char *errstr = ext3_decode_error(sb, errno, nbuf);
+	const char *errstr;
+
+	/* Special case: if the error is EROFS, and we're not already
+	 * inside a transaction, then there's really no point in logging
+	 * an error. */
+	if (errno == -EROFS && journal_current_handle() == NULL &&
+	    (sb->s_flags & MS_RDONLY))
+		return;
 
+	errstr = ext3_decode_error(sb, errno, nbuf);
 	printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n",
 		sb->s_id, function, errstr);
 
@@ -395,10 +403,8 @@ static void ext3_put_super (struct super
 	percpu_counter_destroy(&sbi->s_dirs_counter);
 	brelse(sbi->s_sbh);
 #ifdef CONFIG_QUOTA
-	for (i = 0; i < MAXQUOTAS; i++) {
-		if (sbi->s_qf_names[i])
-			kfree(sbi->s_qf_names[i]);
-	}
+	for (i = 0; i < MAXQUOTAS; i++)
+		kfree(sbi->s_qf_names[i]);
 #endif
 
 	/* Debugging code just in case the in-memory inode orphan list
@@ -441,7 +447,7 @@ static struct inode *ext3_alloc_inode(st
 	ei->i_acl = EXT3_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT3_ACL_NOT_CACHED;
 #endif
-	ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+	ei->i_block_alloc_info = NULL;
 	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
@@ -485,6 +491,7 @@ static void destroy_inodecache(void)
 
 static void ext3_clear_inode(struct inode *inode)
 {
+	struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
        if (EXT3_I(inode)->i_acl &&
            EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
@@ -498,6 +505,8 @@ static void ext3_clear_inode(struct inod
        }
 #endif
 	ext3_discard_reservation(inode);
+	EXT3_I(inode)->i_block_alloc_info = NULL;
+	kfree(rsv);
 }
 
 #ifdef CONFIG_QUOTA
@@ -576,7 +585,7 @@ enum {
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
 	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
-	Opt_reservation, Opt_noreservation, Opt_noload,
+	Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -611,6 +620,7 @@ static match_table_t tokens = {
 	{Opt_reservation, "reservation"},
 	{Opt_noreservation, "noreservation"},
 	{Opt_noload, "noload"},
+	{Opt_nobh, "nobh"},
 	{Opt_commit, "commit=%u"},
 	{Opt_journal_update, "journal=update"},
 	{Opt_journal_inum, "journal=%u"},
@@ -879,10 +889,8 @@ clear_qf_name:
 					"quota turned on.\n");
 				return 0;
 			}
-			if (sbi->s_qf_names[qtype]) {
-				kfree(sbi->s_qf_names[qtype]);
-				sbi->s_qf_names[qtype] = NULL;
-			}
+			kfree(sbi->s_qf_names[qtype]);
+			sbi->s_qf_names[qtype] = NULL;
 			break;
 		case Opt_jqfmt_vfsold:
 			sbi->s_jquota_fmt = QFMT_VFS_OLD;
@@ -924,6 +932,9 @@ clear_qf_name:
 			match_int(&args[0], &option);
 			*n_blocks_count = option;
 			break;
+		case Opt_nobh:
+			set_opt(sbi->s_mount_opt, NOBH);
+			break;
 		default:
 			printk (KERN_ERR
 				"EXT3-fs: Unrecognized mount option \"%s\" "
@@ -1193,12 +1204,18 @@ static void ext3_orphan_cleanup (struct 
 static loff_t ext3_max_size(int bits)
 {
 	loff_t res = EXT3_NDIR_BLOCKS;
+	/* This constant is calculated to be the largest file size for a
+	 * dense, 4k-blocksize file such that the total number of
+	 * sectors in the file, including data and all indirect blocks,
+	 * does not exceed 2^32. */
+	const loff_t upper_limit = 0x1ff7fffd000LL;
+
 	res += 1LL << (bits-2);
 	res += 1LL << (2*(bits-2));
 	res += 1LL << (3*(bits-2));
 	res <<= bits;
-	if (res > (512LL << 32) - (1 << bits))
-		res = (512LL << 32) - (1 << bits);
+	if (res > upper_limit)
+		res = upper_limit;
 	return res;
 }
 
@@ -1496,8 +1513,8 @@ static int ext3_fill_super (struct super
 	 * _much_ simpler. */
 	sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
 	sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
-	atomic_set(&sbi->s_rsv_window_head.rsv_alloc_hit, 0);
-	atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0);
+	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
+	sbi->s_rsv_window_head.rsv_goal_size = 0;
 	ext3_rsv_window_add(sb, &sbi->s_rsv_window_head);
 
 	/*
@@ -1563,6 +1580,19 @@ static int ext3_fill_super (struct super
 		break;
 	}
 
+	if (test_opt(sb, NOBH)) {
+		if (sb->s_blocksize_bits != PAGE_CACHE_SHIFT) {
+			printk(KERN_WARNING "EXT3-fs: Ignoring nobh option "
+				"since filesystem blocksize doesn't match "
+				"pagesize\n");
+			clear_opt(sbi->s_mount_opt, NOBH);
+		}
+		if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
+			printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - "
+				"its supported only with writeback mode\n");
+			clear_opt(sbi->s_mount_opt, NOBH);
+		}
+	}
 	/*
 	 * The journal_load will have done any necessary log recovery,
 	 * so we can safely mount the rest of the filesystem now.
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_FAT_FS) += fat.o
 
-fat-objs := cache.o dir.o file.o inode.o misc.o
+fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -203,124 +203,6 @@ void fat_cache_inval_inode(struct inode 
 	spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
 }
 
-static int __fat_access(struct super_block *sb, int nr, int new_value)
-{
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	struct buffer_head *bh, *bh2, *c_bh, *c_bh2;
-	unsigned char *p_first, *p_last;
-	int copy, first, last, next, b;
-
-	if (sbi->fat_bits == 32) {
-		first = last = nr*4;
-	} else if (sbi->fat_bits == 16) {
-		first = last = nr*2;
-	} else {
-		first = nr*3/2;
-		last = first+1;
-	}
-	b = sbi->fat_start + (first >> sb->s_blocksize_bits);
-	if (!(bh = sb_bread(sb, b))) {
-		printk(KERN_ERR "FAT: bread(block %d) in"
-		       " fat_access failed\n", b);
-		return -EIO;
-	}
-	if ((first >> sb->s_blocksize_bits) == (last >> sb->s_blocksize_bits)) {
-		bh2 = bh;
-	} else {
-		if (!(bh2 = sb_bread(sb, b + 1))) {
-			brelse(bh);
-			printk(KERN_ERR "FAT: bread(block %d) in"
-			       " fat_access failed\n", b + 1);
-			return -EIO;
-		}
-	}
-	if (sbi->fat_bits == 32) {
-		p_first = p_last = NULL; /* GCC needs that stuff */
-		next = le32_to_cpu(((__le32 *) bh->b_data)[(first &
-		    (sb->s_blocksize - 1)) >> 2]);
-		/* Fscking Microsoft marketing department. Their "32" is 28. */
-		next &= 0x0fffffff;
-	} else if (sbi->fat_bits == 16) {
-		p_first = p_last = NULL; /* GCC needs that stuff */
-		next = le16_to_cpu(((__le16 *) bh->b_data)[(first &
-		    (sb->s_blocksize - 1)) >> 1]);
-	} else {
-		p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)];
-		p_last = &((__u8 *)bh2->b_data)[(first + 1) & (sb->s_blocksize - 1)];
-		if (nr & 1)
-			next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
-		else
-			next = (*p_first+(*p_last << 8)) & 0xfff;
-	}
-	if (new_value != -1) {
-		if (sbi->fat_bits == 32) {
-			((__le32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2]
-				= cpu_to_le32(new_value);
-		} else if (sbi->fat_bits == 16) {
-			((__le16 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 1]
-				= cpu_to_le16(new_value);
-		} else {
-			if (nr & 1) {
-				*p_first = (*p_first & 0xf) | (new_value << 4);
-				*p_last = new_value >> 4;
-			}
-			else {
-				*p_first = new_value & 0xff;
-				*p_last = (*p_last & 0xf0) | (new_value >> 8);
-			}
-			mark_buffer_dirty(bh2);
-		}
-		mark_buffer_dirty(bh);
-		for (copy = 1; copy < sbi->fats; copy++) {
-			b = sbi->fat_start + (first >> sb->s_blocksize_bits)
-				+ sbi->fat_length * copy;
-			if (!(c_bh = sb_bread(sb, b)))
-				break;
-			if (bh != bh2) {
-				if (!(c_bh2 = sb_bread(sb, b+1))) {
-					brelse(c_bh);
-					break;
-				}
-				memcpy(c_bh2->b_data, bh2->b_data, sb->s_blocksize);
-				mark_buffer_dirty(c_bh2);
-				brelse(c_bh2);
-			}
-			memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
-			mark_buffer_dirty(c_bh);
-			brelse(c_bh);
-		}
-	}
-	brelse(bh);
-	if (bh != bh2)
-		brelse(bh2);
-	return next;
-}
-
-/*
- * Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
- * new_value is != -1, that FAT entry is replaced by it.
- */
-int fat_access(struct super_block *sb, int nr, int new_value)
-{
-	int next;
-
-	next = -EIO;
-	if (nr < FAT_START_ENT || MSDOS_SB(sb)->max_cluster <= nr) {
-		fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", nr);
-		goto out;
-	}
-	if (new_value == FAT_ENT_EOF)
-		new_value = EOF_FAT(sb);
-
-	next = __fat_access(sb, nr, new_value);
-	if (next < 0)
-		goto out;
-	if (next >= BAD_FAT(sb))
-		next = FAT_ENT_EOF;
-out:
-	return next;
-}
-
 static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
 {
 	cid->nr_contig++;
@@ -339,6 +221,7 @@ int fat_get_cluster(struct inode *inode,
 {
 	struct super_block *sb = inode->i_sb;
 	const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+	struct fat_entry fatent;
 	struct fat_cache_id cid;
 	int nr;
 
@@ -357,34 +240,40 @@ int fat_get_cluster(struct inode *inode,
 		cache_init(&cid, -1, -1);
 	}
 
+	fatent_init(&fatent);
 	while (*fclus < cluster) {
 		/* prevent the infinite loop of cluster chain */
 		if (*fclus > limit) {
 			fat_fs_panic(sb, "%s: detected the cluster chain loop"
 				     " (i_pos %lld)", __FUNCTION__,
 				     MSDOS_I(inode)->i_pos);
-			return -EIO;
+			nr = -EIO;
+			goto out;
 		}
 
-		nr = fat_access(sb, *dclus, -1);
+		nr = fat_ent_read(inode, &fatent, *dclus);
 		if (nr < 0)
-			return nr;
+			goto out;
 		else if (nr == FAT_ENT_FREE) {
 			fat_fs_panic(sb, "%s: invalid cluster chain"
 				     " (i_pos %lld)", __FUNCTION__,
 				     MSDOS_I(inode)->i_pos);
-			return -EIO;
+			nr = -EIO;
+			goto out;
 		} else if (nr == FAT_ENT_EOF) {
 			fat_cache_add(inode, &cid);
-			return FAT_ENT_EOF;
+			goto out;
 		}
 		(*fclus)++;
 		*dclus = nr;
 		if (!cache_contiguous(&cid, *dclus))
 			cache_init(&cid, *fclus, *dclus);
 	}
+	nr = 0;
 	fat_cache_add(inode, &cid);
-	return 0;
+out:
+	fatent_brelse(&fatent);
+	return nr;
 }
 
 static int fat_bmap_cluster(struct inode *inode, int cluster)
@@ -414,9 +303,7 @@ int fat_bmap(struct inode *inode, sector
 	int cluster, offset;
 
 	*phys = 0;
-	if ((sbi->fat_bits != 32) &&
-	    (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
-	     !MSDOS_I(inode)->i_start))) {
+	if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) {
 		if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
 			*phys = sector + sbi->dir_start;
 		return 0;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -22,6 +22,72 @@
 #include <linux/buffer_head.h>
 #include <asm/uaccess.h>
 
+static inline loff_t fat_make_i_pos(struct super_block *sb,
+				    struct buffer_head *bh,
+				    struct msdos_dir_entry *de)
+{
+	return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits)
+		| (de - (struct msdos_dir_entry *)bh->b_data);
+}
+
+/* Returns the inode number of the directory entry at offset pos. If bh is
+   non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
+   returned in bh.
+   AV. Most often we do it item-by-item. Makes sense to optimize.
+   AV. OK, there we go: if both bh and de are non-NULL we assume that we just
+   AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
+   AV. It's done in fat_get_entry() (inlined), here the slow case lives.
+   AV. Additionally, when we return -1 (i.e. reached the end of directory)
+   AV. we make bh NULL.
+ */
+static int fat__get_entry(struct inode *dir, loff_t *pos,
+			  struct buffer_head **bh, struct msdos_dir_entry **de)
+{
+	struct super_block *sb = dir->i_sb;
+	sector_t phys, iblock;
+	int offset;
+	int err;
+
+next:
+	if (*bh)
+		brelse(*bh);
+
+	*bh = NULL;
+	iblock = *pos >> sb->s_blocksize_bits;
+	err = fat_bmap(dir, iblock, &phys);
+	if (err || !phys)
+		return -1;	/* beyond EOF or error */
+
+	*bh = sb_bread(sb, phys);
+	if (*bh == NULL) {
+		printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
+		       (unsigned long long)phys);
+		/* skip this block */
+		*pos = (iblock + 1) << sb->s_blocksize_bits;
+		goto next;
+	}
+
+	offset = *pos & (sb->s_blocksize - 1);
+	*pos += sizeof(struct msdos_dir_entry);
+	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+
+	return 0;
+}
+
+static inline int fat_get_entry(struct inode *dir, loff_t *pos,
+				struct buffer_head **bh,
+				struct msdos_dir_entry **de)
+{
+	/* Fast stuff first */
+	if (*bh && *de &&
+	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
+		*pos += sizeof(struct msdos_dir_entry);
+		(*de)++;
+		return 0;
+	}
+	return fat__get_entry(dir, pos, bh, de);
+}
+
 /*
  * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
  * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
@@ -136,28 +202,31 @@ fat_shortname2uni(struct nls_table *nls,
  * value is the total amount of slots, including the shortname entry.
  */
 int fat_search_long(struct inode *inode, const unsigned char *name,
-		    int name_len, int anycase, loff_t *spos, loff_t *lpos)
+		    int name_len, struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh = NULL;
 	struct msdos_dir_entry *de;
-	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
-	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+	struct nls_table *nls_io = sbi->nls_io;
+	struct nls_table *nls_disk = sbi->nls_disk;
 	wchar_t bufuname[14];
-	unsigned char xlate_len, long_slots;
+	unsigned char xlate_len, nr_slots;
 	wchar_t *unicode = NULL;
 	unsigned char work[8], bufname[260];	/* 256 + 4 */
-	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
-	int utf8 = MSDOS_SB(sb)->options.utf8;
-	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
-	int chl, i, j, last_u, res = 0;
-	loff_t i_pos, cpos = 0;
+	int uni_xlate = sbi->options.unicode_xlate;
+	int utf8 = sbi->options.utf8;
+	int anycase = (sbi->options.name_check != 's');
+	unsigned short opt_shortname = sbi->options.shortname;
+	loff_t cpos = 0;
+	int chl, i, j, last_u, err;
 
+	err = -ENOENT;
 	while(1) {
-		if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+		if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 			goto EODir;
 parse_record:
-		long_slots = 0;
+		nr_slots = 0;
 		if (de->name[0] == DELETED_FLAG)
 			continue;
 		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
@@ -189,7 +258,7 @@ parse_long:
 			slots = id & ~0x40;
 			if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */
 				continue;
-			long_slots = slots;
+			nr_slots = slots;
 			alias_checksum = ds->alias_checksum;
 
 			slot = slots;
@@ -205,7 +274,7 @@ parse_long:
 				if (ds->id & 0x40) {
 					unicode[offset + 13] = 0;
 				}
-				if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0)
+				if (fat_get_entry(inode, &cpos, &bh, &de) < 0)
 					goto EODir;
 				if (slot == 0)
 					break;
@@ -226,7 +295,7 @@ parse_long:
 			for (sum = 0, i = 0; i < 11; i++)
 				sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
 			if (sum != alias_checksum)
-				long_slots = 0;
+				nr_slots = 0;
 		}
 
 		memcpy(work, de->name, sizeof(de->name));
@@ -274,7 +343,7 @@ parse_long:
 								xlate_len)))
 				goto Found;
 
-		if (long_slots) {
+		if (nr_slots) {
 			xlate_len = utf8
 				?utf8_wcstombs(bufname, unicode, sizeof(bufname))
 				:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
@@ -288,15 +357,18 @@ parse_long:
 	}
 
 Found:
-	res = long_slots + 1;
-	*spos = cpos - sizeof(struct msdos_dir_entry);
-	*lpos = cpos - res*sizeof(struct msdos_dir_entry);
+	nr_slots++;	/* include the de */
+	sinfo->slot_off = cpos - nr_slots * sizeof(*de);
+	sinfo->nr_slots = nr_slots;
+	sinfo->de = de;
+	sinfo->bh = bh;
+	sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
+	err = 0;
 EODir:
-	brelse(bh);
-	if (unicode) {
-		free_page((unsigned long) unicode);
-	}
-	return res;
+	if (unicode)
+		free_page((unsigned long)unicode);
+
+	return err;
 }
 
 EXPORT_SYMBOL(fat_search_long);
@@ -315,10 +387,11 @@ static int fat_readdirx(struct inode *in
 			filldir_t filldir, int short_only, int both)
 {
 	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
-	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+	struct nls_table *nls_io = sbi->nls_io;
+	struct nls_table *nls_disk = sbi->nls_disk;
 	unsigned char long_slots;
 	const char *fill_name;
 	int fill_len;
@@ -326,14 +399,14 @@ static int fat_readdirx(struct inode *in
 	wchar_t *unicode = NULL;
 	unsigned char c, work[8], bufname[56], *ptname = bufname;
 	unsigned long lpos, dummy, *furrfu = &lpos;
-	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
-	int isvfat = MSDOS_SB(sb)->options.isvfat;
-	int utf8 = MSDOS_SB(sb)->options.utf8;
-	int nocase = MSDOS_SB(sb)->options.nocase;
-	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+	int uni_xlate = sbi->options.unicode_xlate;
+	int isvfat = sbi->options.isvfat;
+	int utf8 = sbi->options.utf8;
+	int nocase = sbi->options.nocase;
+	unsigned short opt_shortname = sbi->options.shortname;
 	unsigned long inum;
 	int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
-	loff_t i_pos, cpos;
+	loff_t cpos;
 	int ret = 0;
 
 	lock_kernel();
@@ -361,7 +434,7 @@ static int fat_readdirx(struct inode *in
 	bh = NULL;
 GetNew:
 	long_slots = 0;
-	if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 		goto EODir;
 	/* Check for long filename entry */
 	if (isvfat) {
@@ -418,7 +491,7 @@ ParseLong:
 			if (ds->id & 0x40) {
 				unicode[offset + 13] = 0;
 			}
-			if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+			if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 				goto EODir;
 			if (slot == 0)
 				break;
@@ -442,9 +515,13 @@ ParseLong:
 			long_slots = 0;
 	}
 
-	if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
-		*ptname++ = '.';
-		dotoffset = 1;
+	if (sbi->options.dotsOK) {
+		ptname = bufname;
+		dotoffset = 0;
+		if (de->attr & ATTR_HIDDEN) {
+			*ptname++ = '.';
+			dotoffset = 1;
+		}
 	}
 
 	memcpy(work, de->name, sizeof(de->name));
@@ -501,11 +578,12 @@ ParseLong:
 	j = last_u;
 
 	lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
-	if (!memcmp(de->name,MSDOS_DOT,11))
+	if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
 		inum = inode->i_ino;
-	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
+	else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
 		inum = parent_ino(filp->f_dentry);
 	} else {
+		loff_t i_pos = fat_make_i_pos(sb, bh, de);
 		struct inode *tmp = fat_iget(sb, i_pos);
 		if (tmp) {
 			inum = tmp->i_ino;
@@ -639,7 +717,7 @@ static int fat_dir_ioctl(struct inode * 
 		both = 1;
 		break;
 	default:
-		return -EINVAL;
+		return fat_generic_ioctl(inode, filp, cmd, arg);
 	}
 
 	d1 = (struct dirent __user *)arg;
@@ -676,9 +754,9 @@ struct file_operations fat_dir_operation
 
 static int fat_get_short_entry(struct inode *dir, loff_t *pos,
 			       struct buffer_head **bh,
-			       struct msdos_dir_entry **de, loff_t *i_pos)
+			       struct msdos_dir_entry **de)
 {
-	while (fat_get_entry(dir, pos, bh, de, i_pos) >= 0) {
+	while (fat_get_entry(dir, pos, bh, de) >= 0) {
 		/* free entry or long name entry or volume label */
 		if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
 			return 0;
@@ -686,17 +764,39 @@ static int fat_get_short_entry(struct in
 	return -ENOENT;
 }
 
+/*
+ * The ".." entry can not provide the "struct fat_slot_info" informations
+ * for inode. So, this function provide the some informations only.
+ */
+int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+			 struct msdos_dir_entry **de, loff_t *i_pos)
+{
+	loff_t offset;
+
+	offset = 0;
+	*bh = NULL;
+	while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {
+		if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) {
+			*i_pos = fat_make_i_pos(dir->i_sb, *bh, *de);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+EXPORT_SYMBOL(fat_get_dotdot_entry);
+
 /* See if directory is empty */
 int fat_dir_empty(struct inode *dir)
 {
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	loff_t cpos, i_pos;
+	loff_t cpos;
 	int result = 0;
 
 	bh = NULL;
 	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+	while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
 		if (strncmp(de->name, MSDOS_DOT   , MSDOS_NAME) &&
 		    strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
 			result = -ENOTEMPTY;
@@ -717,12 +817,12 @@ int fat_subdirs(struct inode *dir)
 {
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	loff_t cpos, i_pos;
+	loff_t cpos;
 	int count = 0;
 
 	bh = NULL;
 	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+	while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
 		if (de->attr & ATTR_DIR)
 			count++;
 	}
@@ -735,140 +835,437 @@ int fat_subdirs(struct inode *dir)
  * Returns an error code or zero.
  */
 int fat_scan(struct inode *dir, const unsigned char *name,
-	     struct buffer_head **bh, struct msdos_dir_entry **de,
-	     loff_t *i_pos)
+	     struct fat_slot_info *sinfo)
 {
-	loff_t cpos;
+	struct super_block *sb = dir->i_sb;
 
-	*bh = NULL;
-	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, bh, de, i_pos) >= 0) {
-		if (!strncmp((*de)->name, name, MSDOS_NAME))
+	sinfo->slot_off = 0;
+	sinfo->bh = NULL;
+	while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
+				   &sinfo->de) >= 0) {
+		if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
+			sinfo->slot_off -= sizeof(*sinfo->de);
+			sinfo->nr_slots = 1;
+			sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
 			return 0;
+		}
 	}
 	return -ENOENT;
 }
 
 EXPORT_SYMBOL(fat_scan);
 
-static struct buffer_head *fat_extend_dir(struct inode *inode)
+static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
 {
-	struct super_block *sb = inode->i_sb;
-	struct buffer_head *bh, *res = NULL;
-	int nr, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
-	sector_t sector, last_sector;
-
-	if (MSDOS_SB(sb)->fat_bits != 32) {
-		if (inode->i_ino == MSDOS_ROOT_INO)
-			return ERR_PTR(-ENOSPC);
-	}
-
-	nr = fat_add_cluster(inode);
-	if (nr < 0)
-		return ERR_PTR(nr);
-
-	sector = fat_clus_to_blknr(MSDOS_SB(sb), nr);
-	last_sector = sector + sec_per_clus;
-	for ( ; sector < last_sector; sector++) {
-		if ((bh = sb_getblk(sb, sector))) {
-			memset(bh->b_data, 0, sb->s_blocksize);
-			set_buffer_uptodate(bh);
-			mark_buffer_dirty(bh);
-			if (!res)
-				res = bh;
-			else
-				brelse(bh);
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh;
+	struct msdos_dir_entry *de, *endp;
+	int err = 0, orig_slots;
+
+	while (nr_slots) {
+		bh = NULL;
+		if (fat_get_entry(dir, &pos, &bh, &de) < 0) {
+			err = -EIO;
+			break;
 		}
+
+		orig_slots = nr_slots;
+		endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
+		while (nr_slots && de < endp) {
+			de->name[0] = DELETED_FLAG;
+			de++;
+			nr_slots--;
+		}
+		mark_buffer_dirty(bh);
+		if (IS_DIRSYNC(dir))
+			err = sync_dirty_buffer(bh);
+		brelse(bh);
+		if (err)
+			break;
+
+		/* pos is *next* de's position, so this does `- sizeof(de)' */
+		pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
 	}
-	if (res == NULL)
-		res = ERR_PTR(-EIO);
-	if (inode->i_size & (sb->s_blocksize - 1)) {
-		fat_fs_panic(sb, "Odd directory size");
-		inode->i_size = (inode->i_size + sb->s_blocksize)
-			& ~((loff_t)sb->s_blocksize - 1);
+
+	return err;
+}
+
+int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
+{
+	struct msdos_dir_entry *de;
+	struct buffer_head *bh;
+	int err = 0, nr_slots;
+
+	/*
+	 * First stage: Remove the shortname. By this, the directory
+	 * entry is removed.
+	 */
+	nr_slots = sinfo->nr_slots;
+	de = sinfo->de;
+	sinfo->de = NULL;
+	bh = sinfo->bh;
+	sinfo->bh = NULL;
+	while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
+		de->name[0] = DELETED_FLAG;
+		de--;
+		nr_slots--;
+	}
+	mark_buffer_dirty(bh);
+	if (IS_DIRSYNC(dir))
+		err = sync_dirty_buffer(bh);
+	brelse(bh);
+	if (err)
+		return err;
+	dir->i_version++;
+
+	if (nr_slots) {
+		/*
+		 * Second stage: remove the remaining longname slots.
+		 * (This directory entry is already removed, and so return
+		 * the success)
+		 */
+		err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
+		if (err) {
+			printk(KERN_WARNING
+			       "FAT: Couldn't remove the long name slots\n");
+		}
 	}
-	inode->i_size += MSDOS_SB(sb)->cluster_size;
-	MSDOS_I(inode)->mmu_private += MSDOS_SB(sb)->cluster_size;
 
-	return res;
+	dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
+
+	return 0;
 }
 
-/* This assumes that size of cluster is above the 32*slots */
+EXPORT_SYMBOL(fat_remove_entries);
 
-int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
-		  struct msdos_dir_entry **de, loff_t *i_pos)
+static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
+			      struct buffer_head **bhs, int nr_bhs)
 {
 	struct super_block *sb = dir->i_sb;
-	loff_t offset, curr;
-	int row;
-	struct buffer_head *new_bh;
+	sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus;
+	int err, i, n;
 
-	offset = curr = 0;
-	*bh = NULL;
-	row = 0;
-	while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) {
-		/* check the maximum size of directory */
-		if (curr >= FAT_MAX_DIR_SIZE) {
-			brelse(*bh);
-			return -ENOSPC;
+	/* Zeroing the unused blocks on this cluster */
+	blknr += nr_used;
+	n = nr_used;
+	while (blknr < last_blknr) {
+		bhs[n] = sb_getblk(sb, blknr);
+		if (!bhs[n]) {
+			err = -ENOMEM;
+			goto error;
 		}
-
-		if (IS_FREE((*de)->name)) {
-			if (++row == slots)
-				return offset;
-		} else {
-			row = 0;
-			offset = curr;
+		memset(bhs[n]->b_data, 0, sb->s_blocksize);
+		set_buffer_uptodate(bhs[n]);
+		mark_buffer_dirty(bhs[n]);
+
+		n++;
+		blknr++;
+		if (n == nr_bhs) {
+			if (IS_DIRSYNC(dir)) {
+				err = fat_sync_bhs(bhs, n);
+				if (err)
+					goto error;
+			}
+			for (i = 0; i < n; i++)
+				brelse(bhs[i]);
+			n = 0;
 		}
 	}
-	if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
-		return -ENOSPC;
-	new_bh = fat_extend_dir(dir);
-	if (IS_ERR(new_bh))
-		return PTR_ERR(new_bh);
-	brelse(new_bh);
-	do {
-		fat_get_entry(dir, &curr, bh, de, i_pos);
-	} while (++row < slots);
+	if (IS_DIRSYNC(dir)) {
+		err = fat_sync_bhs(bhs, n);
+		if (err)
+			goto error;
+	}
+	for (i = 0; i < n; i++)
+		brelse(bhs[i]);
 
-	return offset;
-}
+	return 0;
 
-EXPORT_SYMBOL(fat_add_entries);
+error:
+	for (i = 0; i < n; i++)
+		bforget(bhs[i]);
+	return err;
+}
 
-int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
+int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
 {
-	struct buffer_head *bh;
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
 	struct msdos_dir_entry *de;
+	sector_t blknr;
 	__le16 date, time;
+	int err, cluster;
 
-	bh = fat_extend_dir(dir);
-	if (IS_ERR(bh))
-		return PTR_ERR(bh);
-
-	/* zeroed out, so... */
-	fat_date_unix2dos(dir->i_mtime.tv_sec,&time,&date);
-	de = (struct msdos_dir_entry*)&bh->b_data[0];
-	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
-	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
-	de[0].attr = de[1].attr = ATTR_DIR;
+	err = fat_alloc_clusters(dir, &cluster, 1);
+	if (err)
+		goto error;
+
+	blknr = fat_clus_to_blknr(sbi, cluster);
+	bhs[0] = sb_getblk(sb, blknr);
+	if (!bhs[0]) {
+		err = -ENOMEM;
+		goto error_free;
+	}
+
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+
+	de = (struct msdos_dir_entry *)bhs[0]->b_data;
+	/* filling the new directory slots ("." and ".." entries) */
+	memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
+	memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
+	de->attr = de[1].attr = ATTR_DIR;
+	de[0].lcase = de[1].lcase = 0;
 	de[0].time = de[1].time = time;
 	de[0].date = de[1].date = date;
-	if (is_vfat) {	/* extra timestamps */
+	de[0].ctime_cs = de[1].ctime_cs = 0;
+	if (sbi->options.isvfat) {
+		/* extra timestamps */
 		de[0].ctime = de[1].ctime = time;
-		de[0].adate = de[0].cdate =
-			de[1].adate = de[1].cdate = date;
+		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
+	} else {
+		de[0].ctime = de[1].ctime = 0;
+		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
 	}
-	de[0].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
-	de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart>>16);
-	de[1].start = cpu_to_le16(MSDOS_I(parent)->i_logstart);
-	de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart>>16);
-	mark_buffer_dirty(bh);
-	brelse(bh);
-	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(dir);
+	de[0].start = cpu_to_le16(cluster);
+	de[0].starthi = cpu_to_le16(cluster >> 16);
+	de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
+	de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
+	de[0].size = de[1].size = 0;
+	memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de));
+	set_buffer_uptodate(bhs[0]);
+	mark_buffer_dirty(bhs[0]);
+
+	err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE);
+	if (err)
+		goto error_free;
+
+	return cluster;
+
+error_free:
+	fat_free_clusters(dir, cluster);
+error:
+	return err;
+}
+
+EXPORT_SYMBOL(fat_alloc_new_dir);
+
+static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
+			       int *nr_cluster, struct msdos_dir_entry **de,
+			       struct buffer_head **bh, loff_t *i_pos)
+{
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	sector_t blknr, start_blknr, last_blknr;
+	unsigned long size, copy;
+	int err, i, n, offset, cluster[2];
+
+	/*
+	 * The minimum cluster size is 512bytes, and maximum entry
+	 * size is 32*slots (672bytes).  So, iff the cluster size is
+	 * 512bytes, we may need two clusters.
+	 */
+	size = nr_slots * sizeof(struct msdos_dir_entry);
+	*nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits;
+	BUG_ON(*nr_cluster > 2);
+
+	err = fat_alloc_clusters(dir, cluster, *nr_cluster);
+	if (err)
+		goto error;
+
+	/*
+	 * First stage: Fill the directory entry.  NOTE: This cluster
+	 * is not referenced from any inode yet, so updates order is
+	 * not important.
+	 */
+	i = n = copy = 0;
+	do {
+		start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]);
+		last_blknr = start_blknr + sbi->sec_per_clus;
+		while (blknr < last_blknr) {
+			bhs[n] = sb_getblk(sb, blknr);
+			if (!bhs[n]) {
+				err = -ENOMEM;
+				goto error_nomem;
+			}
+
+			/* fill the directory entry */
+			copy = min(size, sb->s_blocksize);
+			memcpy(bhs[n]->b_data, slots, copy);
+			slots += copy;
+			size -= copy;
+			set_buffer_uptodate(bhs[n]);
+			mark_buffer_dirty(bhs[n]);
+			if (!size)
+				break;
+			n++;
+			blknr++;
+		}
+	} while (++i < *nr_cluster);
+
+	memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy);
+	offset = copy - sizeof(struct msdos_dir_entry);
+	get_bh(bhs[n]);
+	*bh = bhs[n];
+	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+	*i_pos = fat_make_i_pos(sb, *bh, *de);
+
+	/* Second stage: clear the rest of cluster, and write outs */
+	err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
+	if (err)
+		goto error_free;
+
+	return cluster[0];
+
+error_free:
+	brelse(*bh);
+	*bh = NULL;
+	n = 0;
+error_nomem:
+	for (i = 0; i < n; i++)
+		bforget(bhs[i]);
+	fat_free_clusters(dir, cluster[0]);
+error:
+	return err;
+}
+
+int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+		    struct fat_slot_info *sinfo)
+{
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
+	struct msdos_dir_entry *de;
+	int err, free_slots, i, nr_bhs;
+	loff_t pos, i_pos;
+
+	sinfo->nr_slots = nr_slots;
+
+	/* First stage: search free direcotry entries */
+	free_slots = nr_bhs = 0;
+	bh = prev = NULL;
+	pos = 0;
+	err = -ENOSPC;
+	while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
+		/* check the maximum size of directory */
+		if (pos >= FAT_MAX_DIR_SIZE)
+			goto error;
+
+		if (IS_FREE(de->name)) {
+			if (prev != bh) {
+				get_bh(bh);
+				bhs[nr_bhs] = prev = bh;
+				nr_bhs++;
+			}
+			free_slots++;
+			if (free_slots == nr_slots)
+				goto found;
+		} else {
+			for (i = 0; i < nr_bhs; i++)
+				brelse(bhs[i]);
+			prev = NULL;
+			free_slots = nr_bhs = 0;
+		}
+	}
+	if (dir->i_ino == MSDOS_ROOT_INO) {
+		if (sbi->fat_bits != 32)
+			goto error;
+	} else if (MSDOS_I(dir)->i_start == 0) {
+		printk(KERN_ERR "FAT: Corrupted directory (i_pos %lld)\n",
+		       MSDOS_I(dir)->i_pos);
+		err = -EIO;
+		goto error;
+	}
+
+found:
+	err = 0;
+	pos -= free_slots * sizeof(*de);
+	nr_slots -= free_slots;
+	if (free_slots) {
+		/*
+		 * Second stage: filling the free entries with new entries.
+		 * NOTE: If this slots has shortname, first, we write
+		 * the long name slots, then write the short name.
+		 */
+		int size = free_slots * sizeof(*de);
+		int offset = pos & (sb->s_blocksize - 1);
+		int long_bhs = nr_bhs - (nr_slots == 0);
+
+		/* Fill the long name slots. */
+		for (i = 0; i < long_bhs; i++) {
+			int copy = min_t(int, sb->s_blocksize - offset, size);
+			memcpy(bhs[i]->b_data + offset, slots, copy);
+			mark_buffer_dirty(bhs[i]);
+			offset = 0;
+			slots += copy;
+			size -= copy;
+		}
+		if (long_bhs && IS_DIRSYNC(dir))
+			err = fat_sync_bhs(bhs, long_bhs);
+		if (!err && i < nr_bhs) {
+			/* Fill the short name slot. */
+			int copy = min_t(int, sb->s_blocksize - offset, size);
+			memcpy(bhs[i]->b_data + offset, slots, copy);
+			mark_buffer_dirty(bhs[i]);
+			if (IS_DIRSYNC(dir))
+				err = sync_dirty_buffer(bhs[i]);
+		}
+		for (i = 0; i < nr_bhs; i++)
+			brelse(bhs[i]);
+		if (err)
+			goto error_remove;
+	}
+
+	if (nr_slots) {
+		int cluster, nr_cluster;
+
+		/*
+		 * Third stage: allocate the cluster for new entries.
+		 * And initialize the cluster with new entries, then
+		 * add the cluster to dir.
+		 */
+		cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
+					      &de, &bh, &i_pos);
+		if (cluster < 0) {
+			err = cluster;
+			goto error_remove;
+		}
+		err = fat_chain_add(dir, cluster, nr_cluster);
+		if (err) {
+			fat_free_clusters(dir, cluster);
+			goto error_remove;
+		}
+		if (dir->i_size & (sbi->cluster_size - 1)) {
+			fat_fs_panic(sb, "Odd directory size");
+			dir->i_size = (dir->i_size + sbi->cluster_size - 1)
+				& ~((loff_t)sbi->cluster_size - 1);
+		}
+		dir->i_size += nr_cluster << sbi->cluster_bits;
+		MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
+	}
+	sinfo->slot_off = pos;
+	sinfo->de = de;
+	sinfo->bh = bh;
+	sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
 
 	return 0;
+
+error:
+	brelse(bh);
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	return err;
+
+error_remove:
+	brelse(bh);
+	if (free_slots)
+		__fat_remove_entries(dir, pos, free_slots);
+	return err;
 }
 
-EXPORT_SYMBOL(fat_new_dir);
+EXPORT_SYMBOL(fat_add_entries);
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
new file mode 100644
--- /dev/null
+++ b/fs/fat/fatent.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2004, OGAWA Hirofumi
+ * Released under GPL v2.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+struct fatent_operations {
+	void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
+	void (*ent_set_ptr)(struct fat_entry *, int);
+	int (*ent_bread)(struct super_block *, struct fat_entry *,
+			 int, sector_t);
+	int (*ent_get)(struct fat_entry *);
+	void (*ent_put)(struct fat_entry *, int);
+	int (*ent_next)(struct fat_entry *);
+};
+
+static void fat12_ent_blocknr(struct super_block *sb, int entry,
+			      int *offset, sector_t *blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int bytes = entry + (entry >> 1);
+	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+	*offset = bytes & (sb->s_blocksize - 1);
+	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat_ent_blocknr(struct super_block *sb, int entry,
+			    int *offset, sector_t *blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int bytes = (entry << sbi->fatent_shift);
+	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+	*offset = bytes & (sb->s_blocksize - 1);
+	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	struct buffer_head **bhs = fatent->bhs;
+	if (fatent->nr_bhs == 1) {
+		WARN_ON(offset >= (bhs[0]->b_size - 1));
+		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+		fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1);
+	} else {
+		WARN_ON(offset != (bhs[0]->b_size - 1));
+		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+		fatent->u.ent12_p[1] = bhs[1]->b_data;
+	}
+}
+
+static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	WARN_ON(offset & (2 - 1));
+	fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	WARN_ON(offset & (4 - 1));
+	fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+			   int offset, sector_t blocknr)
+{
+	struct buffer_head **bhs = fatent->bhs;
+
+	WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
+	bhs[0] = sb_bread(sb, blocknr);
+	if (!bhs[0])
+		goto err;
+
+	if ((offset + 1) < sb->s_blocksize)
+		fatent->nr_bhs = 1;
+	else {
+		/* This entry is block boundary, it needs the next block */
+		blocknr++;
+		bhs[1] = sb_bread(sb, blocknr);
+		if (!bhs[1])
+			goto err_brelse;
+		fatent->nr_bhs = 2;
+	}
+	fat12_ent_set_ptr(fatent, offset);
+	return 0;
+
+err_brelse:
+	brelse(bhs[0]);
+err:
+	printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+	       (unsigned long long)blocknr);
+	return -EIO;
+}
+
+static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+			 int offset, sector_t blocknr)
+{
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+
+	WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
+	fatent->bhs[0] = sb_bread(sb, blocknr);
+	if (!fatent->bhs[0]) {
+		printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+		       (unsigned long long)blocknr);
+		return -EIO;
+	}
+	fatent->nr_bhs = 1;
+	ops->ent_set_ptr(fatent, offset);
+	return 0;
+}
+
+static int fat12_ent_get(struct fat_entry *fatent)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+	int next;
+
+	if (fatent->entry & 1)
+		next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
+	else
+		next = (*ent12_p[1] << 8) | *ent12_p[0];
+	next &= 0x0fff;
+	if (next >= BAD_FAT12)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static int fat16_ent_get(struct fat_entry *fatent)
+{
+	int next = le16_to_cpu(*fatent->u.ent16_p);
+	WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1));
+	if (next >= BAD_FAT16)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static int fat32_ent_get(struct fat_entry *fatent)
+{
+	int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff;
+	WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1));
+	if (next >= BAD_FAT32)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static void fat12_ent_put(struct fat_entry *fatent, int new)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT12;
+
+	if (fatent->entry & 1) {
+		*ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
+		*ent12_p[1] = new >> 4;
+	} else {
+		*ent12_p[0] = new & 0xff;
+		*ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
+	}
+
+	mark_buffer_dirty(fatent->bhs[0]);
+	if (fatent->nr_bhs == 2)
+		mark_buffer_dirty(fatent->bhs[1]);
+}
+
+static void fat16_ent_put(struct fat_entry *fatent, int new)
+{
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT16;
+
+	*fatent->u.ent16_p = cpu_to_le16(new);
+	mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static void fat32_ent_put(struct fat_entry *fatent, int new)
+{
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT32;
+
+	WARN_ON(new & 0xf0000000);
+	new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff;
+	*fatent->u.ent32_p = cpu_to_le32(new);
+	mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static int fat12_ent_next(struct fat_entry *fatent)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+	struct buffer_head **bhs = fatent->bhs;
+	u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1);
+
+	fatent->entry++;
+	if (fatent->nr_bhs == 1) {
+		WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2)));
+		WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
+		if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) {
+			ent12_p[0] = nextp - 1;
+			ent12_p[1] = nextp;
+			return 1;
+		}
+	} else {
+		WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
+		WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data);
+		ent12_p[0] = nextp - 1;
+		ent12_p[1] = nextp;
+		brelse(bhs[0]);
+		bhs[0] = bhs[1];
+		fatent->nr_bhs = 1;
+		return 1;
+	}
+	ent12_p[0] = NULL;
+	ent12_p[1] = NULL;
+	return 0;
+}
+
+static int fat16_ent_next(struct fat_entry *fatent)
+{
+	const struct buffer_head *bh = fatent->bhs[0];
+	fatent->entry++;
+	if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) {
+		fatent->u.ent16_p++;
+		return 1;
+	}
+	fatent->u.ent16_p = NULL;
+	return 0;
+}
+
+static int fat32_ent_next(struct fat_entry *fatent)
+{
+	const struct buffer_head *bh = fatent->bhs[0];
+	fatent->entry++;
+	if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) {
+		fatent->u.ent32_p++;
+		return 1;
+	}
+	fatent->u.ent32_p = NULL;
+	return 0;
+}
+
+static struct fatent_operations fat12_ops = {
+	.ent_blocknr	= fat12_ent_blocknr,
+	.ent_set_ptr	= fat12_ent_set_ptr,
+	.ent_bread	= fat12_ent_bread,
+	.ent_get	= fat12_ent_get,
+	.ent_put	= fat12_ent_put,
+	.ent_next	= fat12_ent_next,
+};
+
+static struct fatent_operations fat16_ops = {
+	.ent_blocknr	= fat_ent_blocknr,
+	.ent_set_ptr	= fat16_ent_set_ptr,
+	.ent_bread	= fat_ent_bread,
+	.ent_get	= fat16_ent_get,
+	.ent_put	= fat16_ent_put,
+	.ent_next	= fat16_ent_next,
+};
+
+static struct fatent_operations fat32_ops = {
+	.ent_blocknr	= fat_ent_blocknr,
+	.ent_set_ptr	= fat32_ent_set_ptr,
+	.ent_bread	= fat_ent_bread,
+	.ent_get	= fat32_ent_get,
+	.ent_put	= fat32_ent_put,
+	.ent_next	= fat32_ent_next,
+};
+
+static inline void lock_fat(struct msdos_sb_info *sbi)
+{
+	down(&sbi->fat_lock);
+}
+
+static inline void unlock_fat(struct msdos_sb_info *sbi)
+{
+	up(&sbi->fat_lock);
+}
+
+void fat_ent_access_init(struct super_block *sb)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+
+	init_MUTEX(&sbi->fat_lock);
+
+	switch (sbi->fat_bits) {
+	case 32:
+		sbi->fatent_shift = 2;
+		sbi->fatent_ops = &fat32_ops;
+		break;
+	case 16:
+		sbi->fatent_shift = 1;
+		sbi->fatent_ops = &fat16_ops;
+		break;
+	case 12:
+		sbi->fatent_shift = -1;
+		sbi->fatent_ops = &fat12_ops;
+		break;
+	}
+}
+
+static inline int fat_ent_update_ptr(struct super_block *sb,
+				     struct fat_entry *fatent,
+				     int offset, sector_t blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct buffer_head **bhs = fatent->bhs;
+
+	/* Is this fatent's blocks including this entry? */
+	if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr)
+		return 0;
+	/* Does this entry need the next block? */
+	if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) {
+		if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1))
+			return 0;
+	}
+	ops->ent_set_ptr(fatent, offset);
+	return 1;
+}
+
+int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	int err, offset;
+	sector_t blocknr;
+
+	if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
+		fatent_brelse(fatent);
+		fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry);
+		return -EIO;
+	}
+
+	fatent_set_entry(fatent, entry);
+	ops->ent_blocknr(sb, entry, &offset, &blocknr);
+
+	if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) {
+		fatent_brelse(fatent);
+		err = ops->ent_bread(sb, fatent, offset, blocknr);
+		if (err)
+			return err;
+	}
+	return ops->ent_get(fatent);
+}
+
+/* FIXME: We can write the blocks as more big chunk. */
+static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
+			  int nr_bhs)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *c_bh;
+	int err, n, copy;
+
+	err = 0;
+	for (copy = 1; copy < sbi->fats; copy++) {
+		sector_t backup_fat = sbi->fat_length * copy;
+
+		for (n = 0; n < nr_bhs; n++) {
+			c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr);
+			if (!c_bh) {
+				err = -ENOMEM;
+				goto error;
+			}
+			memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize);
+			set_buffer_uptodate(c_bh);
+			mark_buffer_dirty(c_bh);
+			if (sb->s_flags & MS_SYNCHRONOUS)
+				err = sync_dirty_buffer(c_bh);
+			brelse(c_bh);
+			if (err)
+				goto error;
+		}
+	}
+error:
+	return err;
+}
+
+int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+		  int new, int wait)
+{
+	struct super_block *sb = inode->i_sb;
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+	int err;
+
+	ops->ent_put(fatent, new);
+	if (wait) {
+		err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs);
+		if (err)
+			return err;
+	}
+	return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs);
+}
+
+static inline int fat_ent_next(struct msdos_sb_info *sbi,
+			       struct fat_entry *fatent)
+{
+	if (sbi->fatent_ops->ent_next(fatent)) {
+		if (fatent->entry < sbi->max_cluster)
+			return 1;
+	}
+	return 0;
+}
+
+static inline int fat_ent_read_block(struct super_block *sb,
+				     struct fat_entry *fatent)
+{
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+	sector_t blocknr;
+	int offset;
+
+	fatent_brelse(fatent);
+	ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
+	return ops->ent_bread(sb, fatent, offset, blocknr);
+}
+
+static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs,
+			    struct fat_entry *fatent)
+{
+	int n, i;
+
+	for (n = 0; n < fatent->nr_bhs; n++) {
+		for (i = 0; i < *nr_bhs; i++) {
+			if (fatent->bhs[n] == bhs[i])
+				break;
+		}
+		if (i == *nr_bhs) {
+			get_bh(fatent->bhs[n]);
+			bhs[i] = fatent->bhs[n];
+			(*nr_bhs)++;
+		}
+	}
+}
+
+int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent, prev_ent;
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	int i, count, err, nr_bhs, idx_clus;
+
+	BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2));	/* fixed limit */
+
+	lock_fat(sbi);
+	if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) {
+		unlock_fat(sbi);
+		return -ENOSPC;
+	}
+
+	err = nr_bhs = idx_clus = 0;
+	count = FAT_START_ENT;
+	fatent_init(&prev_ent);
+	fatent_init(&fatent);
+	fatent_set_entry(&fatent, sbi->prev_free + 1);
+	while (count < sbi->max_cluster) {
+		if (fatent.entry >= sbi->max_cluster)
+			fatent.entry = FAT_START_ENT;
+		fatent_set_entry(&fatent, fatent.entry);
+		err = fat_ent_read_block(sb, &fatent);
+		if (err)
+			goto out;
+
+		/* Find the free entries in a block */
+		do {
+			if (ops->ent_get(&fatent) == FAT_ENT_FREE) {
+				int entry = fatent.entry;
+
+				/* make the cluster chain */
+				ops->ent_put(&fatent, FAT_ENT_EOF);
+				if (prev_ent.nr_bhs)
+					ops->ent_put(&prev_ent, entry);
+
+				fat_collect_bhs(bhs, &nr_bhs, &fatent);
+
+				sbi->prev_free = entry;
+				if (sbi->free_clusters != -1)
+					sbi->free_clusters--;
+
+				cluster[idx_clus] = entry;
+				idx_clus++;
+				if (idx_clus == nr_cluster)
+					goto out;
+
+				/*
+				 * fat_collect_bhs() gets ref-count of bhs,
+				 * so we can still use the prev_ent.
+				 */
+				prev_ent = fatent;
+			}
+			count++;
+			if (count == sbi->max_cluster)
+				break;
+		} while (fat_ent_next(sbi, &fatent));
+	}
+
+	/* Couldn't allocate the free entries */
+	sbi->free_clusters = 0;
+	err = -ENOSPC;
+
+out:
+	unlock_fat(sbi);
+	fatent_brelse(&fatent);
+	if (!err) {
+		if (inode_needs_sync(inode))
+			err = fat_sync_bhs(bhs, nr_bhs);
+		if (!err)
+			err = fat_mirror_bhs(sb, bhs, nr_bhs);
+	}
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	fat_clusters_flush(sb);
+
+	if (err && idx_clus)
+		fat_free_clusters(inode, cluster[0]);
+
+	return err;
+}
+
+int fat_free_clusters(struct inode *inode, int cluster)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent;
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	int i, err, nr_bhs;
+
+	nr_bhs = 0;
+	fatent_init(&fatent);
+	lock_fat(sbi);
+	do {
+		cluster = fat_ent_read(inode, &fatent, cluster);
+		if (cluster < 0) {
+			err = cluster;
+			goto error;
+		} else if (cluster == FAT_ENT_FREE) {
+			fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
+				     __FUNCTION__);
+			err = -EIO;
+			goto error;
+		}
+
+		ops->ent_put(&fatent, FAT_ENT_FREE);
+		if (sbi->free_clusters != -1)
+			sbi->free_clusters++;
+
+		if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
+			if (sb->s_flags & MS_SYNCHRONOUS) {
+				err = fat_sync_bhs(bhs, nr_bhs);
+				if (err)
+					goto error;
+			}
+			err = fat_mirror_bhs(sb, bhs, nr_bhs);
+			if (err)
+				goto error;
+			for (i = 0; i < nr_bhs; i++)
+				brelse(bhs[i]);
+			nr_bhs = 0;
+		}
+		fat_collect_bhs(bhs, &nr_bhs, &fatent);
+	} while (cluster != FAT_ENT_EOF);
+
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		err = fat_sync_bhs(bhs, nr_bhs);
+		if (err)
+			goto error;
+	}
+	err = fat_mirror_bhs(sb, bhs, nr_bhs);
+error:
+	fatent_brelse(&fatent);
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	unlock_fat(sbi);
+
+	fat_clusters_flush(sb);
+
+	return err;
+}
+
+EXPORT_SYMBOL(fat_free_clusters);
+
+int fat_count_free_clusters(struct super_block *sb)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent;
+	int err = 0, free;
+
+	lock_fat(sbi);
+	if (sbi->free_clusters != -1)
+		goto out;
+
+	free = 0;
+	fatent_init(&fatent);
+	fatent_set_entry(&fatent, FAT_START_ENT);
+	while (fatent.entry < sbi->max_cluster) {
+		err = fat_ent_read_block(sb, &fatent);
+		if (err)
+			goto out;
+
+		do {
+			if (ops->ent_get(&fatent) == FAT_ENT_FREE)
+				free++;
+		} while (fat_ent_next(sbi, &fatent));
+	}
+	sbi->free_clusters = free;
+	fatent_brelse(&fatent);
+out:
+	unlock_fat(sbi);
+	return err;
+}
diff --git a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -12,13 +12,31 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 
-static ssize_t fat_file_write(struct file *filp, const char __user *buf,
-			      size_t count, loff_t *ppos)
+static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf,
+				  size_t count, loff_t pos)
+{
+	struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+	int retval;
+
+	retval = generic_file_aio_write(iocb, buf, count, pos);
+	if (retval > 0) {
+		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+		mark_inode_dirty(inode);
+//		check the locking rules
+//		if (IS_SYNC(inode))
+//			fat_sync_inode(inode);
+	}
+	return retval;
+}
+
+static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov,
+			       unsigned long nr_segs, loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	int retval;
 
-	retval = generic_file_write(filp, buf, count, ppos);
+	retval = generic_file_writev(filp, iov, nr_segs, ppos);
 	if (retval > 0) {
 		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -27,14 +45,115 @@ static ssize_t fat_file_write(struct fil
 	return retval;
 }
 
+int fat_generic_ioctl(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	u32 __user *user_attr = (u32 __user *)arg;
+
+	switch (cmd) {
+	case FAT_IOCTL_GET_ATTRIBUTES:
+	{
+		u32 attr;
+
+		if (inode->i_ino == MSDOS_ROOT_INO)
+			attr = ATTR_DIR;
+		else
+			attr = fat_attr(inode);
+
+		return put_user(attr, user_attr);
+	}
+	case FAT_IOCTL_SET_ATTRIBUTES:
+	{
+		u32 attr, oldattr;
+		int err, is_dir = S_ISDIR(inode->i_mode);
+		struct iattr ia;
+
+		err = get_user(attr, user_attr);
+		if (err)
+			return err;
+
+		down(&inode->i_sem);
+
+		if (IS_RDONLY(inode)) {
+			err = -EROFS;
+			goto up;
+		}
+
+		/*
+		 * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+		 * prevents the user from turning us into a VFAT
+		 * longname entry.  Also, we obviously can't set
+		 * any of the NTFS attributes in the high 24 bits.
+		 */
+		attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
+		/* Merge in ATTR_VOLUME and ATTR_DIR */
+		attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
+			(is_dir ? ATTR_DIR : 0);
+		oldattr = fat_attr(inode);
+
+		/* Equivalent to a chmod() */
+		ia.ia_valid = ATTR_MODE | ATTR_CTIME;
+		if (is_dir) {
+			ia.ia_mode = MSDOS_MKMODE(attr,
+				S_IRWXUGO & ~sbi->options.fs_dmask)
+				| S_IFDIR;
+		} else {
+			ia.ia_mode = MSDOS_MKMODE(attr,
+				(S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO))
+				& ~sbi->options.fs_fmask)
+				| S_IFREG;
+		}
+
+		/* The root directory has no attributes */
+		if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
+			err = -EINVAL;
+			goto up;
+		}
+
+		if (sbi->options.sys_immutable) {
+			if ((attr | oldattr) & ATTR_SYS) {
+				if (!capable(CAP_LINUX_IMMUTABLE)) {
+					err = -EPERM;
+					goto up;
+				}
+			}
+		}
+
+		/* This MUST be done before doing anything irreversible... */
+		err = notify_change(filp->f_dentry, &ia);
+		if (err)
+			goto up;
+
+		if (sbi->options.sys_immutable) {
+			if (attr & ATTR_SYS)
+				inode->i_flags |= S_IMMUTABLE;
+			else
+				inode->i_flags &= S_IMMUTABLE;
+		}
+
+		MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED;
+		mark_inode_dirty(inode);
+	up:
+		up(&inode->i_sem);
+		return err;
+	}
+	default:
+		return -ENOTTY;	/* Inappropriate ioctl for device */
+	}
+}
+
 struct file_operations fat_file_operations = {
 	.llseek		= generic_file_llseek,
-	.read		= generic_file_read,
-	.write		= fat_file_write,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.readv		= generic_file_readv,
+	.writev		= fat_file_writev,
+	.aio_read	= generic_file_aio_read,
+	.aio_write	= fat_file_aio_write,
 	.mmap		= generic_file_mmap,
+	.ioctl		= fat_generic_ioctl,
 	.fsync		= file_fsync,
-	.readv		= generic_file_readv,
-	.writev		= generic_file_writev,
 	.sendfile	= generic_file_sendfile,
 };
 
@@ -93,62 +212,74 @@ EXPORT_SYMBOL(fat_notify_change);
 static int fat_free(struct inode *inode, int skip)
 {
 	struct super_block *sb = inode->i_sb;
-	int nr, ret, fclus, dclus;
+	int err, wait, free_start, i_start, i_logstart;
 
 	if (MSDOS_I(inode)->i_start == 0)
 		return 0;
 
+	/*
+	 * Write a new EOF, and get the remaining cluster chain for freeing.
+	 */
+	wait = IS_DIRSYNC(inode);
 	if (skip) {
+		struct fat_entry fatent;
+		int ret, fclus, dclus;
+
 		ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
 		if (ret < 0)
 			return ret;
 		else if (ret == FAT_ENT_EOF)
 			return 0;
 
-		nr = fat_access(sb, dclus, -1);
-		if (nr == FAT_ENT_EOF)
+		fatent_init(&fatent);
+		ret = fat_ent_read(inode, &fatent, dclus);
+		if (ret == FAT_ENT_EOF) {
+			fatent_brelse(&fatent);
 			return 0;
-		else if (nr > 0) {
-			/*
-			 * write a new EOF, and get the remaining cluster
-			 * chain for freeing.
-			 */
-			nr = fat_access(sb, dclus, FAT_ENT_EOF);
+		} else if (ret == FAT_ENT_FREE) {
+			fat_fs_panic(sb,
+				     "%s: invalid cluster chain (i_pos %lld)",
+				     __FUNCTION__, MSDOS_I(inode)->i_pos);
+			ret = -EIO;
+		} else if (ret > 0) {
+			err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
+			if (err)
+				ret = err;
 		}
-		if (nr < 0)
-			return nr;
+		fatent_brelse(&fatent);
+		if (ret < 0)
+			return ret;
 
+		free_start = ret;
+		i_start = i_logstart = 0;
 		fat_cache_inval_inode(inode);
 	} else {
 		fat_cache_inval_inode(inode);
 
-		nr = MSDOS_I(inode)->i_start;
+		i_start = free_start = MSDOS_I(inode)->i_start;
+		i_logstart = MSDOS_I(inode)->i_logstart;
 		MSDOS_I(inode)->i_start = 0;
 		MSDOS_I(inode)->i_logstart = 0;
-		mark_inode_dirty(inode);
 	}
-
-	lock_fat(sb);
-	do {
-		nr = fat_access(sb, nr, FAT_ENT_FREE);
-		if (nr < 0)
-			goto error;
-		else if (nr == FAT_ENT_FREE) {
-			fat_fs_panic(sb, "%s: deleting beyond EOF (i_pos %lld)",
-				     __FUNCTION__, MSDOS_I(inode)->i_pos);
-			nr = -EIO;
+	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+	if (wait) {
+		err = fat_sync_inode(inode);
+		if (err)
 			goto error;
-		}
-		if (MSDOS_SB(sb)->free_clusters != -1)
-			MSDOS_SB(sb)->free_clusters++;
-		inode->i_blocks -= MSDOS_SB(sb)->cluster_size >> 9;
-	} while (nr != FAT_ENT_EOF);
-	fat_clusters_flush(sb);
-	nr = 0;
-error:
-	unlock_fat(sb);
+	} else
+		mark_inode_dirty(inode);
+	inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
+
+	/* Freeing the remained cluster chain */
+	return fat_free_clusters(inode, free_start);
 
-	return nr;
+error:
+	if (i_start) {
+		MSDOS_I(inode)->i_start = i_start;
+		MSDOS_I(inode)->i_logstart = i_logstart;
+	}
+	return err;
 }
 
 void fat_truncate(struct inode *inode)
@@ -168,10 +299,7 @@ void fat_truncate(struct inode *inode)
 
 	lock_kernel();
 	fat_free(inode, nr_clusters);
-	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 	unlock_kernel();
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
 }
 
 struct inode_operations fat_file_inode_operations = {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -33,6 +33,21 @@ static int fat_default_codepage = CONFIG
 static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
 
 
+static int fat_add_cluster(struct inode *inode)
+{
+	int err, cluster;
+
+	err = fat_alloc_clusters(inode, &cluster, 1);
+	if (err)
+		return err;
+	/* FIXME: this cluster should be added after data of this
+	 * cluster is writed */
+	err = fat_chain_add(inode, cluster, 1);
+	if (err)
+		fat_free_clusters(inode, cluster);
+	return err;
+}
+
 static int fat_get_block(struct inode *inode, sector_t iblock,
 			 struct buffer_head *bh_result, int create)
 {
@@ -55,11 +70,9 @@ static int fat_get_block(struct inode *i
 		return -EIO;
 	}
 	if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
-		int error;
-
-		error = fat_add_cluster(inode);
-		if (error < 0)
-			return error;
+		err = fat_add_cluster(inode);
+		if (err)
+			return err;
 	}
 	MSDOS_I(inode)->mmu_private += sb->s_blocksize;
 	err = fat_bmap(inode, iblock, &phys);
@@ -220,8 +233,7 @@ static int fat_calc_dir_size(struct inod
 /* doesn't deal with root inode */
 static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
-	struct super_block *sb = inode->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 	int error;
 
 	MSDOS_I(inode)->i_pos = 0;
@@ -266,9 +278,10 @@ static int fat_fill_inode(struct inode *
 		inode->i_mapping->a_ops = &fat_aops;
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 	}
-	if(de->attr & ATTR_SYS)
+	if (de->attr & ATTR_SYS) {
 		if (sbi->options.sys_immutable)
 			inode->i_flags |= S_IMMUTABLE;
+	}
 	MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = sbi->cluster_size;
@@ -277,34 +290,39 @@ static int fat_fill_inode(struct inode *
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec =
 		date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date));
 	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0;
-	inode->i_ctime.tv_sec =
-		MSDOS_SB(sb)->options.isvfat
-		? date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate))
-		: inode->i_mtime.tv_sec;
-	inode->i_ctime.tv_nsec = de->ctime_ms * 1000000;
-	MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
+	if (sbi->options.isvfat) {
+		int secs = de->ctime_cs / 100;
+		int csecs = de->ctime_cs % 100;
+		inode->i_ctime.tv_sec  =
+			date_dos2unix(le16_to_cpu(de->ctime),
+				      le16_to_cpu(de->cdate)) + secs;
+		inode->i_ctime.tv_nsec = csecs * 10000000;
+	} else
+		inode->i_ctime = inode->i_mtime;
 
 	return 0;
 }
 
 struct inode *fat_build_inode(struct super_block *sb,
-			struct msdos_dir_entry *de, loff_t i_pos, int *res)
+			struct msdos_dir_entry *de, loff_t i_pos)
 {
 	struct inode *inode;
-	*res = 0;
+	int err;
+
 	inode = fat_iget(sb, i_pos);
 	if (inode)
 		goto out;
 	inode = new_inode(sb);
-	*res = -ENOMEM;
-	if (!inode)
+	if (!inode) {
+		inode = ERR_PTR(-ENOMEM);
 		goto out;
+	}
 	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
 	inode->i_version = 1;
-	*res = fat_fill_inode(inode, de);
-	if (*res < 0) {
+	err = fat_fill_inode(inode, de);
+	if (err) {
 		iput(inode);
-		inode = NULL;
+		inode = ERR_PTR(err);
 		goto out;
 	}
 	fat_attach(inode, i_pos);
@@ -413,41 +431,27 @@ static void __exit fat_destroy_inodecach
 
 static int fat_remount(struct super_block *sb, int *flags, char *data)
 {
-	*flags |= MS_NODIRATIME;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	*flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME);
 	return 0;
 }
 
 static int fat_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int free, nr, ret;
 
-	if (sbi->free_clusters != -1)
-		free = sbi->free_clusters;
-	else {
-		lock_fat(sb);
-		if (sbi->free_clusters != -1)
-			free = sbi->free_clusters;
-		else {
-			free = 0;
-			for (nr = FAT_START_ENT; nr < sbi->max_cluster; nr++) {
-				ret = fat_access(sb, nr, -1);
-				if (ret < 0) {
-					unlock_fat(sb);
-					return ret;
-				} else if (ret == FAT_ENT_FREE)
-					free++;
-			}
-			sbi->free_clusters = free;
-		}
-		unlock_fat(sb);
+	/* If the count of free cluster is still unknown, counts it here. */
+	if (sbi->free_clusters == -1) {
+		int err = fat_count_free_clusters(sb);
+		if (err)
+			return err;
 	}
 
 	buf->f_type = sb->s_magic;
 	buf->f_bsize = sbi->cluster_size;
 	buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
-	buf->f_bfree = free;
-	buf->f_bavail = free;
+	buf->f_bfree = sbi->free_clusters;
+	buf->f_bavail = sbi->free_clusters;
 	buf->f_namelen = sbi->options.isvfat ? 260 : 12;
 
 	return 0;
@@ -460,18 +464,20 @@ static int fat_write_inode(struct inode 
 	struct buffer_head *bh;
 	struct msdos_dir_entry *raw_entry;
 	loff_t i_pos;
+	int err = 0;
 
 retry:
 	i_pos = MSDOS_I(inode)->i_pos;
-	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
+	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
 		return 0;
-	}
+
 	lock_kernel();
-	if (!(bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits))) {
+	bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
+	if (!bh) {
 		printk(KERN_ERR "FAT: unable to read inode block "
 		       "for updating (i_pos %lld)\n", i_pos);
-		unlock_kernel();
-		return -EIO;
+		err = -EIO;
+		goto out;
 	}
 	spin_lock(&sbi->inode_hash_lock);
 	if (i_pos != MSDOS_I(inode)->i_pos) {
@@ -483,30 +489,36 @@ retry:
 
 	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
 	    [i_pos & (sbi->dir_per_block - 1)];
-	if (S_ISDIR(inode->i_mode)) {
-		raw_entry->attr = ATTR_DIR;
+	if (S_ISDIR(inode->i_mode))
 		raw_entry->size = 0;
-	}
-	else {
-		raw_entry->attr = ATTR_NONE;
+	else
 		raw_entry->size = cpu_to_le32(inode->i_size);
-	}
-	raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
-	    MSDOS_I(inode)->i_attrs;
+	raw_entry->attr = fat_attr(inode);
 	raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
 	raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
 	fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date);
 	if (sbi->options.isvfat) {
 		fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate);
-		raw_entry->ctime_ms = MSDOS_I(inode)->i_ctime_ms; /* use i_ctime.tv_nsec? */
+		raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
+			inode->i_ctime.tv_nsec / 10000000;
 	}
 	spin_unlock(&sbi->inode_hash_lock);
 	mark_buffer_dirty(bh);
+	if (wait)
+		err = sync_dirty_buffer(bh);
 	brelse(bh);
+out:
 	unlock_kernel();
-	return 0;
+	return err;
 }
 
+int fat_sync_inode(struct inode *inode)
+{
+	return fat_write_inode(inode, 1);
+}
+
+EXPORT_SYMBOL(fat_sync_inode);
+
 static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
 static struct super_operations fat_sops = {
 	.alloc_inode	= fat_alloc_inode,
@@ -636,39 +648,35 @@ fat_encode_fh(struct dentry *de, __u32 *
 
 static struct dentry *fat_get_parent(struct dentry *child)
 {
-	struct buffer_head *bh=NULL;
-	struct msdos_dir_entry *de = NULL;
-	struct dentry *parent = NULL;
-	int res;
-	loff_t i_pos = 0;
+	struct buffer_head *bh;
+	struct msdos_dir_entry *de;
+	loff_t i_pos;
+	struct dentry *parent;
 	struct inode *inode;
+	int err;
 
 	lock_kernel();
-	res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
 
-	if (res < 0)
+	err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos);
+	if (err) {
+		parent = ERR_PTR(err);
 		goto out;
-	inode = fat_build_inode(child->d_sb, de, i_pos, &res);
-	if (res)
+	}
+	inode = fat_build_inode(child->d_sb, de, i_pos);
+	brelse(bh);
+	if (IS_ERR(inode)) {
+		parent = ERR_PTR(PTR_ERR(inode));
 		goto out;
-	if (!inode)
-		res = -EACCES;
-	else {
-		parent = d_alloc_anon(inode);
-		if (!parent) {
-			iput(inode);
-			res = -ENOMEM;
-		}
 	}
-
- out:
-	if(bh)
-		brelse(bh);
+	parent = d_alloc_anon(inode);
+	if (!parent) {
+		iput(inode);
+		parent = ERR_PTR(-ENOMEM);
+	}
+out:
 	unlock_kernel();
-	if (res)
-		return ERR_PTR(res);
-	else
-		return parent;
+
+	return parent;
 }
 
 static struct export_operations fat_export_ops = {
@@ -1026,10 +1034,9 @@ static int fat_read_root(struct inode *i
 	MSDOS_I(inode)->i_logstart = 0;
 	MSDOS_I(inode)->mmu_private = inode->i_size;
 
-	MSDOS_I(inode)->i_attrs = 0;
+	MSDOS_I(inode)->i_attrs = ATTR_NONE;
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
 	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
-	MSDOS_I(inode)->i_ctime_ms = 0;
 	inode->i_nlink = fat_subdirs(inode)+2;
 
 	return 0;
@@ -1068,10 +1075,6 @@ int fat_fill_super(struct super_block *s
 	if (error)
 		goto out_fail;
 
-	/* set up enough so that it can read an inode */
-	fat_hash_init(sb);
-	init_MUTEX(&sbi->fat_lock);
-
 	error = -EIO;
 	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
@@ -1161,7 +1164,7 @@ int fat_fill_super(struct super_block *s
 	sbi->fat_length = le16_to_cpu(b->fat_length);
 	sbi->root_cluster = 0;
 	sbi->free_clusters = -1;	/* Don't know yet */
-	sbi->prev_free = -1;
+	sbi->prev_free = FAT_START_ENT;
 
 	if (!sbi->fat_length && b->fat32_length) {
 		struct fat_boot_fsinfo *fsinfo;
@@ -1245,9 +1248,17 @@ int fat_fill_super(struct super_block *s
 	/* check the free_clusters, it's not necessarily correct */
 	if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters)
 		sbi->free_clusters = -1;
+	/* check the prev_free, it's not necessarily correct */
+	sbi->prev_free %= sbi->max_cluster;
+	if (sbi->prev_free < FAT_START_ENT)
+		sbi->prev_free = FAT_START_ENT;
 
 	brelse(bh);
 
+	/* set up enough so that it can read an inode */
+	fat_hash_init(sb);
+	fat_ent_access_init(sb);
+
 	/*
 	 * The low byte of FAT's first entry must have same value with
 	 * media-field.  But in real world, too many devices is
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -33,15 +33,7 @@ void fat_fs_panic(struct super_block *s,
 	}
 }
 
-void lock_fat(struct super_block *sb)
-{
-	down(&(MSDOS_SB(sb)->fat_lock));
-}
-
-void unlock_fat(struct super_block *sb)
-{
-	up(&(MSDOS_SB(sb)->fat_lock));
-}
+EXPORT_SYMBOL(fat_fs_panic);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
@@ -56,7 +48,7 @@ void fat_clusters_flush(struct super_blo
 
 	bh = sb_bread(sb, sbi->fsinfo_sector);
 	if (bh == NULL) {
-		printk(KERN_ERR "FAT bread failed in fat_clusters_flush\n");
+		printk(KERN_ERR "FAT: bread failed in fat_clusters_flush\n");
 		return;
 	}
 
@@ -75,31 +67,29 @@ void fat_clusters_flush(struct super_blo
 		if (sbi->prev_free != -1)
 			fsinfo->next_cluster = cpu_to_le32(sbi->prev_free);
 		mark_buffer_dirty(bh);
+		if (sb->s_flags & MS_SYNCHRONOUS)
+			sync_dirty_buffer(bh);
 	}
 	brelse(bh);
 }
 
 /*
- * fat_add_cluster tries to allocate a new cluster and adds it to the
- * file represented by inode.
+ * fat_chain_add() adds a new cluster to the chain of clusters represented
+ * by inode.
  */
-int fat_add_cluster(struct inode *inode)
+int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int ret, count, limit, new_dclus, new_fclus, last;
-	int cluster_bits = sbi->cluster_bits;
+	int ret, new_fclus, last;
 
 	/*
 	 * We must locate the last cluster of the file to add this new
 	 * one (new_dclus) to the end of the link list (the FAT).
-	 *
-	 * In order to confirm that the cluster chain is valid, we
-	 * find out EOF first.
 	 */
 	last = new_fclus = 0;
 	if (MSDOS_I(inode)->i_start) {
-		int ret, fclus, dclus;
+		int fclus, dclus;
 
 		ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
 		if (ret < 0)
@@ -108,66 +98,42 @@ int fat_add_cluster(struct inode *inode)
 		last = dclus;
 	}
 
-	/* find free FAT entry */
-	lock_fat(sb);
-
-	if (sbi->free_clusters == 0) {
-		unlock_fat(sb);
-		return -ENOSPC;
-	}
-
-	limit = sbi->max_cluster;
-	new_dclus = sbi->prev_free + 1;
-	for (count = FAT_START_ENT; count < limit; count++, new_dclus++) {
-		new_dclus = new_dclus % limit;
-		if (new_dclus < FAT_START_ENT)
-			new_dclus = FAT_START_ENT;
-
-		ret = fat_access(sb, new_dclus, -1);
-		if (ret < 0) {
-			unlock_fat(sb);
-			return ret;
-		} else if (ret == FAT_ENT_FREE)
-			break;
-	}
-	if (count >= limit) {
-		sbi->free_clusters = 0;
-		unlock_fat(sb);
-		return -ENOSPC;
-	}
-
-	ret = fat_access(sb, new_dclus, FAT_ENT_EOF);
-	if (ret < 0) {
-		unlock_fat(sb);
-		return ret;
-	}
-
-	sbi->prev_free = new_dclus;
-	if (sbi->free_clusters != -1)
-		sbi->free_clusters--;
-	fat_clusters_flush(sb);
-
-	unlock_fat(sb);
-
 	/* add new one to the last of the cluster chain */
 	if (last) {
-		ret = fat_access(sb, last, new_dclus);
+		struct fat_entry fatent;
+
+		fatent_init(&fatent);
+		ret = fat_ent_read(inode, &fatent, last);
+		if (ret >= 0) {
+			int wait = inode_needs_sync(inode);
+			ret = fat_ent_write(inode, &fatent, new_dclus, wait);
+			fatent_brelse(&fatent);
+		}
 		if (ret < 0)
 			return ret;
 //		fat_cache_add(inode, new_fclus, new_dclus);
 	} else {
 		MSDOS_I(inode)->i_start = new_dclus;
 		MSDOS_I(inode)->i_logstart = new_dclus;
-		mark_inode_dirty(inode);
+		/*
+		 * Since generic_osync_inode() synchronize later if
+		 * this is not directory, we don't here.
+		 */
+		if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) {
+			ret = fat_sync_inode(inode);
+			if (ret)
+				return ret;
+		} else
+			mark_inode_dirty(inode);
 	}
-	if (new_fclus != (inode->i_blocks >> (cluster_bits - 9))) {
+	if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
 		fat_fs_panic(sb, "clusters badly computed (%d != %lu)",
-			new_fclus, inode->i_blocks >> (cluster_bits - 9));
+			new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9));
 		fat_cache_inval_inode(inode);
 	}
-	inode->i_blocks += sbi->cluster_size >> 9;
+	inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
 
-	return new_dclus;
+	return 0;
 }
 
 extern struct timezone sys_tz;
@@ -230,52 +196,30 @@ void fat_date_unix2dos(int unix_date, __
 
 EXPORT_SYMBOL(fat_date_unix2dos);
 
-/* Returns the inode number of the directory entry at offset pos. If bh is
-   non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
-   returned in bh.
-   AV. Most often we do it item-by-item. Makes sense to optimize.
-   AV. OK, there we go: if both bh and de are non-NULL we assume that we just
-   AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
-   AV. It's done in fat_get_entry() (inlined), here the slow case lives.
-   AV. Additionally, when we return -1 (i.e. reached the end of directory)
-   AV. we make bh NULL.
- */
-
-int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
-		   struct msdos_dir_entry **de, loff_t *i_pos)
+int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
 {
-	struct super_block *sb = dir->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	sector_t phys, iblock;
-	loff_t offset;
-	int err;
-
-next:
-	offset = *pos;
-	if (*bh)
-		brelse(*bh);
-
-	*bh = NULL;
-	iblock = *pos >> sb->s_blocksize_bits;
-	err = fat_bmap(dir, iblock, &phys);
-	if (err || !phys)
-		return -1;	/* beyond EOF or error */
-
-	*bh = sb_bread(sb, phys);
-	if (*bh == NULL) {
-		printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
-		       (unsigned long long)phys);
-		/* skip this block */
-		*pos = (iblock + 1) << sb->s_blocksize_bits;
-		goto next;
-	}
-
-	offset &= sb->s_blocksize - 1;
-	*pos += sizeof(struct msdos_dir_entry);
-	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
-	*i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+	int i, e, err = 0;
 
-	return 0;
+	for (i = 0; i < nr_bhs; i++) {
+		lock_buffer(bhs[i]);
+		if (test_clear_buffer_dirty(bhs[i])) {
+			get_bh(bhs[i]);
+			bhs[i]->b_end_io = end_buffer_write_sync;
+			e = submit_bh(WRITE, bhs[i]);
+			if (!err && e)
+				err = e;
+		} else
+			unlock_buffer(bhs[i]);
+	}
+	for (i = 0; i < nr_bhs; i++) {
+		wait_on_buffer(bhs[i]);
+		if (buffer_eopnotsupp(bhs[i])) {
+			clear_buffer_eopnotsupp(bhs[i]);
+			err = -EOPNOTSUPP;
+		} else if (!err && !buffer_uptodate(bhs[i]))
+			err = -EIO;
+	}
+	return err;
 }
 
-EXPORT_SYMBOL(fat__get_entry);
+EXPORT_SYMBOL(fat_sync_bhs);
diff --git a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/signal.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
@@ -308,7 +309,7 @@ static long do_fcntl(int fd, unsigned in
 		break;
 	case F_SETSIG:
 		/* arg == 0 restores default behaviour. */
-		if (arg < 0 || arg > _NSIG) {
+		if (!valid_signal(arg)) {
 			break;
 		}
 		err = 0;
@@ -437,7 +438,7 @@ static void send_sigio_to_task(struct ta
 			else
 				si.si_band = band_table[reason - POLL_IN];
 			si.si_fd    = fd;
-			if (!send_sig_info(fown->signum, &si, p))
+			if (!send_group_sig_info(fown->signum, &si, p))
 				break;
 		/* fall-through: fall back on the old plain SIGIO signal */
 		case 0:
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -315,7 +315,7 @@ sync_sb_inodes(struct super_block *sb, s
 		struct backing_dev_info *bdi = mapping->backing_dev_info;
 		long pages_skipped;
 
-		if (bdi->memory_backed) {
+		if (!bdi_cap_writeback_dirty(bdi)) {
 			list_move(&inode->i_list, &sb->s_dirty);
 			if (sb == blockdev_superblock) {
 				/*
@@ -512,7 +512,8 @@ restart:
 }
 
 /**
- * sync_inodes
+ * sync_inodes - writes all inodes to disk
+ * @wait: wait for completion
  *
  * sync_inodes() goes through each super block's dirty inode list, writes the
  * inodes out, waits on the writeout and puts the inodes back on the normal
@@ -566,7 +567,7 @@ int write_inode_now(struct inode *inode,
 		.sync_mode = WB_SYNC_ALL,
 	};
 
-	if (inode->i_mapping->backing_dev_info->memory_backed)
+	if (!mapping_cap_writeback_dirty(inode->i_mapping))
 		return 0;
 
 	might_sleep();
@@ -604,6 +605,7 @@ EXPORT_SYMBOL(sync_inode);
 /**
  * generic_osync_inode - flush all dirty data for a given inode to disk
  * @inode: inode to write
+ * @mapping: the address_space that should be flushed
  * @what:  what to write and wait upon
  *
  * This can be called by file_write functions for files which have the
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -285,6 +285,10 @@ static struct hfs_bnode *__hfs_bnode_cre
 		page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL);
 		if (IS_ERR(page))
 			goto fail;
+		if (PageError(page)) {
+			page_cache_release(page);
+			goto fail;
+		}
 #if !REF_PAGES
 		page_cache_release(page);
 #endif
@@ -326,12 +330,16 @@ struct hfs_bnode *hfs_bnode_find(struct 
 		hfs_bnode_get(node);
 		spin_unlock(&tree->hash_lock);
 		wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+		if (test_bit(HFS_BNODE_ERROR, &node->flags))
+			goto node_error;
 		return node;
 	}
 	spin_unlock(&tree->hash_lock);
 	node = __hfs_bnode_create(tree, num);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
+	if (test_bit(HFS_BNODE_ERROR, &node->flags))
+		goto node_error;
 	if (!test_bit(HFS_BNODE_NEW, &node->flags))
 		return node;
 
@@ -416,6 +424,10 @@ struct hfs_bnode *hfs_bnode_create(struc
 	node = __hfs_bnode_create(tree, num);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
+	if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
+		hfs_bnode_put(node);
+		return ERR_PTR(-EIO);
+	}
 
 	pagep = node->page;
 	memset(kmap(*pagep) + node->page_offset, 0,
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c
--- a/fs/hfs/brec.c
+++ b/fs/hfs/brec.c
@@ -10,6 +10,10 @@
 
 #include "btree.h"
 
+static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
+static int hfs_brec_update_parent(struct hfs_find_data *fd);
+static int hfs_btree_inc_height(struct hfs_btree *tree);
+
 /* Get the length and offset of the given record in the given node */
 u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
 {
@@ -211,7 +215,7 @@ skip:
 	return 0;
 }
 
-struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
+static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
 {
 	struct hfs_btree *tree;
 	struct hfs_bnode *node, *new_node;
@@ -320,7 +324,7 @@ struct hfs_bnode *hfs_bnode_split(struct
 	return new_node;
 }
 
-int hfs_brec_update_parent(struct hfs_find_data *fd)
+static int hfs_brec_update_parent(struct hfs_find_data *fd)
 {
 	struct hfs_btree *tree;
 	struct hfs_bnode *node, *new_node, *parent;
@@ -418,7 +422,7 @@ out:
 	return 0;
 }
 
-int hfs_btree_inc_height(struct hfs_btree *tree)
+static int hfs_btree_inc_height(struct hfs_btree *tree)
 {
 	struct hfs_bnode *node, *new_node;
 	struct hfs_bnode_desc node_desc;
diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h
--- a/fs/hfs/btree.h
+++ b/fs/hfs/btree.h
@@ -111,9 +111,6 @@ extern u16 hfs_brec_lenoff(struct hfs_bn
 extern u16 hfs_brec_keylen(struct hfs_bnode *, u16);
 extern int hfs_brec_insert(struct hfs_find_data *, void *, int);
 extern int hfs_brec_remove(struct hfs_find_data *);
-extern struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *);
-extern int hfs_brec_update_parent(struct hfs_find_data *);
-extern int hfs_btree_inc_height(struct hfs_btree *);
 
 /* bfind.c */
 extern int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -33,7 +33,7 @@ void hfs_cat_build_key(btree_key *key, u
 	}
 }
 
-int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
+static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
 {
 	__be32 mtime = hfs_mtime();
 
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -17,8 +17,8 @@
 /*
  * hfs_lookup()
  */
-struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
-			  struct nameidata *nd)
+static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
+				 struct nameidata *nd)
 {
 	hfs_cat_rec rec;
 	struct hfs_find_data fd;
@@ -51,7 +51,7 @@ done:
 /*
  * hfs_readdir
  */
-int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct super_block *sb = inode->i_sb;
@@ -177,8 +177,8 @@ static int hfs_dir_release(struct inode 
  * a directory and return a corresponding inode, given the inode for
  * the directory and the name (and its length) of the new file.
  */
-int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
-	       struct nameidata *nd)
+static int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
+		      struct nameidata *nd)
 {
 	struct inode *inode;
 	int res;
@@ -207,7 +207,7 @@ int hfs_create(struct inode *dir, struct
  * in a directory, given the inode for the parent directory and the
  * name (and its length) of the new directory.
  */
-int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct inode *inode;
 	int res;
@@ -236,7 +236,7 @@ int hfs_mkdir(struct inode *dir, struct 
  * file, given the inode for the parent directory and the name
  * (and its length) of the existing file.
  */
-int hfs_unlink(struct inode *dir, struct dentry *dentry)
+static int hfs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode;
 	int res;
@@ -262,7 +262,7 @@ int hfs_unlink(struct inode *dir, struct
  * directory, given the inode for the parent directory and the name
  * (and its length) of the existing directory.
  */
-int hfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode;
 	int res;
@@ -291,8 +291,8 @@ int hfs_rmdir(struct inode *dir, struct 
  * new file/directory.
  * XXX: how do you handle must_be dir?
  */
-int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
-	       struct inode *new_dir, struct dentry *new_dentry)
+static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		      struct inode *new_dir, struct dentry *new_dentry)
 {
 	int res;
 
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c
--- a/fs/hfs/extent.c
+++ b/fs/hfs/extent.c
@@ -49,22 +49,21 @@ static void hfs_ext_build_key(hfs_btree_
  *   This function has no side-effects */
 int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2)
 {
-	unsigned int tmp;
-	int retval;
+	__be32 fnum1, fnum2;
+	__be16 block1, block2;
 
-	tmp = be32_to_cpu(key1->ext.FNum) - be32_to_cpu(key2->ext.FNum);
-	if (tmp != 0) {
-		retval = (int)tmp;
-	} else {
-		tmp = (unsigned char)key1->ext.FkType - (unsigned char)key2->ext.FkType;
-		if (tmp != 0) {
-			retval = (int)tmp;
-		} else {
-			retval = (int)(be16_to_cpu(key1->ext.FABN)
-				       - be16_to_cpu(key2->ext.FABN));
-		}
-	}
-	return retval;
+	fnum1 = key1->ext.FNum;
+	fnum2 = key2->ext.FNum;
+	if (fnum1 != fnum2)
+		return be32_to_cpu(fnum1) < be32_to_cpu(fnum2) ? -1 : 1;
+	if (key1->ext.FkType != key2->ext.FkType)
+		return key1->ext.FkType < key2->ext.FkType ? -1 : 1;
+
+	block1 = key1->ext.FABN;
+	block2 = key2->ext.FABN;
+	if (block1 == block2)
+		return 0;
+	return be16_to_cpu(block1) < be16_to_cpu(block2) ? -1 : 1;
 }
 
 /*
@@ -231,8 +230,8 @@ static int hfs_add_extent(struct hfs_ext
 	return -EIO;
 }
 
-int hfs_free_extents(struct super_block *sb, struct hfs_extent *extent,
-		     u16 offset, u16 block_nr)
+static int hfs_free_extents(struct super_block *sb, struct hfs_extent *extent,
+			    u16 offset, u16 block_nr)
 {
 	u16 count, start;
 	int i;
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -174,12 +174,6 @@ extern void hfs_cat_build_key(btree_key 
 extern struct file_operations hfs_dir_operations;
 extern struct inode_operations hfs_dir_inode_operations;
 
-extern int hfs_mkdir(struct inode *, struct dentry *, int);
-extern int hfs_unlink(struct inode *, struct dentry *);
-extern int hfs_rmdir(struct inode *, struct dentry *);
-extern int hfs_rename(struct inode *, struct dentry *,
-		      struct inode *, struct dentry *);
-
 /* extent.c */
 extern int hfs_ext_keycmp(const btree_key *, const btree_key *);
 extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int);
@@ -187,10 +181,6 @@ extern void hfs_ext_write_extent(struct 
 extern int hfs_extend_file(struct inode *);
 extern void hfs_file_truncate(struct inode *);
 
-/* file.c */
-extern struct inode_operations hfs_file_inode_operations;
-extern struct file_operations hfs_file_operations;
-
 extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 /* inode.c */
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -18,6 +18,9 @@
 #include "hfs_fs.h"
 #include "btree.h"
 
+static struct file_operations hfs_file_operations;
+static struct inode_operations hfs_file_inode_operations;
+
 /*================ Variable-like macros ================*/
 
 #define HFS_VALID_MODE_BITS  (S_IFREG | S_IFDIR | S_IRWXUGO)
@@ -43,7 +46,7 @@ static sector_t hfs_bmap(struct address_
 	return generic_block_bmap(mapping, block, hfs_get_block);
 }
 
-int hfs_releasepage(struct page *page, int mask)
+static int hfs_releasepage(struct page *page, int mask)
 {
 	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
@@ -71,12 +74,6 @@ int hfs_releasepage(struct page *page, i
 			;
 		else if (atomic_read(&node->refcnt))
 			res = 0;
-		else for (i = 0; i < tree->pages_per_bnode; i++) {
-			if (PageActive(node->page[i])) {
-				res = 0;
-				break;
-			}
-		}
 		if (res && node) {
 			hfs_bnode_unhash(node);
 			hfs_bnode_free(node);
@@ -100,7 +97,7 @@ int hfs_releasepage(struct page *page, i
 		spin_unlock(&tree->hash_lock);
 	}
 	//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
-	return res;
+	return res ? try_to_free_buffers(page) : 0;
 }
 
 static int hfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
@@ -174,14 +171,16 @@ struct inode *hfs_new_inode(struct inode
 	HFS_I(inode)->flags = 0;
 	HFS_I(inode)->rsrc_inode = NULL;
 	HFS_I(inode)->fs_blocks = 0;
-	if (S_ISDIR(inode->i_mode)) {
+	if (S_ISDIR(mode)) {
 		inode->i_size = 2;
 		HFS_SB(sb)->folder_count++;
 		if (dir->i_ino == HFS_ROOT_CNID)
 			HFS_SB(sb)->root_dirs++;
 		inode->i_op = &hfs_dir_inode_operations;
 		inode->i_fop = &hfs_dir_operations;
-	} else if (S_ISREG(inode->i_mode)) {
+		inode->i_mode |= S_IRWXUGO;
+		inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask;
+	} else if (S_ISREG(mode)) {
 		HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
 		HFS_SB(sb)->file_count++;
 		if (dir->i_ino == HFS_ROOT_CNID)
@@ -189,6 +188,10 @@ struct inode *hfs_new_inode(struct inode
 		inode->i_op = &hfs_file_inode_operations;
 		inode->i_fop = &hfs_file_operations;
 		inode->i_mapping->a_ops = &hfs_aops;
+		inode->i_mode |= S_IRUGO|S_IXUGO;
+		if (mode & S_IWUSR)
+			inode->i_mode |= S_IWUGO;
+		inode->i_mode &= ~HFS_SB(inode->i_sb)->s_file_umask;
 		HFS_I(inode)->phys_size = 0;
 		HFS_I(inode)->alloc_blocks = 0;
 		HFS_I(inode)->first_blocks = 0;
@@ -259,7 +262,7 @@ struct hfs_iget_data {
 	hfs_cat_rec *rec;
 };
 
-int hfs_test_inode(struct inode *inode, void *data)
+static int hfs_test_inode(struct inode *inode, void *data)
 {
 	struct hfs_iget_data *idata = data;
 	hfs_cat_rec *rec;
@@ -279,7 +282,7 @@ int hfs_test_inode(struct inode *inode, 
 /*
  * hfs_read_inode
  */
-int hfs_read_inode(struct inode *inode, void *data)
+static int hfs_read_inode(struct inode *inode, void *data)
 {
 	struct hfs_iget_data *idata = data;
 	struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
@@ -317,7 +320,7 @@ int hfs_read_inode(struct inode *inode, 
 		inode->i_mode = S_IRUGO | S_IXUGO;
 		if (!(rec->file.Flags & HFS_FIL_LOCK))
 			inode->i_mode |= S_IWUGO;
-		inode->i_mode &= hsb->s_file_umask;
+		inode->i_mode &= ~hsb->s_file_umask;
 		inode->i_mode |= S_IFREG;
 		inode->i_ctime = inode->i_atime = inode->i_mtime =
 				hfs_m_to_utime(rec->file.MdDat);
@@ -329,7 +332,7 @@ int hfs_read_inode(struct inode *inode, 
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
-		inode->i_mode = S_IFDIR | (S_IRWXUGO & hsb->s_dir_umask);
+		inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
 		inode->i_ctime = inode->i_atime = inode->i_mtime =
 				hfs_m_to_utime(rec->dir.MdDat);
 		inode->i_op = &hfs_dir_inode_operations;
@@ -611,7 +614,7 @@ int hfs_inode_setattr(struct dentry *den
 }
 
 
-struct file_operations hfs_file_operations = {
+static struct file_operations hfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
@@ -622,7 +625,7 @@ struct file_operations hfs_file_operatio
 	.release	= hfs_file_release,
 };
 
-struct inode_operations hfs_file_inode_operations = {
+static struct inode_operations hfs_file_inode_operations = {
 	.lookup		= hfs_file_lookup,
 	.truncate	= hfs_file_truncate,
 	.setattr	= hfs_inode_setattr,
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -333,6 +333,8 @@ void hfs_mdb_close(struct super_block *s
  * Release the resources associated with the in-core MDB.  */
 void hfs_mdb_put(struct super_block *sb)
 {
+	if (!HFS_SB(sb))
+		return;
 	/* free the B-trees */
 	hfs_btree_close(HFS_SB(sb)->ext_tree);
 	hfs_btree_close(HFS_SB(sb)->cat_tree);
@@ -340,4 +342,7 @@ void hfs_mdb_put(struct super_block *sb)
 	/* free the buffers holding the primary and alternate MDBs */
 	brelse(HFS_SB(sb)->mdb_bh);
 	brelse(HFS_SB(sb)->alt_mdb_bh);
+
+	kfree(HFS_SB(sb));
+	sb->s_fs_info = NULL;
 }
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -16,13 +16,12 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/parser.h>
 #include <linux/vfs.h>
 
 #include "hfs_fs.h"
 #include "btree.h"
 
-const char hfs_version[]="0.96";
-
 static kmem_cache_t *hfs_inode_cachep;
 
 MODULE_LICENSE("GPL");
@@ -92,7 +91,7 @@ static int hfs_statfs(struct super_block
 	return 0;
 }
 
-int hfs_remount(struct super_block *sb, int *flags, char *data)
+static int hfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	*flags |= MS_NODIRATIME;
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
@@ -136,6 +135,34 @@ static struct super_operations hfs_super
 	.remount_fs     = hfs_remount,
 };
 
+enum {
+	opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
+	opt_part, opt_session, opt_type, opt_creator, opt_quiet,
+	opt_err
+};
+
+static match_table_t tokens = {
+	{ opt_uid, "uid=%u" },
+	{ opt_gid, "gid=%u" },
+	{ opt_umask, "umask=%o" },
+	{ opt_file_umask, "file_umask=%o" },
+	{ opt_dir_umask, "dir_umask=%o" },
+	{ opt_part, "part=%u" },
+	{ opt_session, "session=%u" },
+	{ opt_type, "type=%s" },
+	{ opt_creator, "creator=%s" },
+	{ opt_quiet, "quiet" },
+	{ opt_err, NULL }
+};
+
+static inline int match_fourchar(substring_t *arg, u32 *result)
+{
+	if (arg->to - arg->from != 4)
+		return -EINVAL;
+	memcpy(result, arg->from, 4);
+	return 0;
+}
+
 /*
  * parse_options()
  *
@@ -144,13 +171,15 @@ static struct super_operations hfs_super
  */
 static int parse_options(char *options, struct hfs_sb_info *hsb)
 {
-	char *this_char, *value;
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+	int tmp, token;
 
 	/* initialize the sb with defaults */
 	hsb->s_uid = current->uid;
 	hsb->s_gid = current->gid;
-	hsb->s_file_umask = 0644;
-	hsb->s_dir_umask = 0755;
+	hsb->s_file_umask = 0133;
+	hsb->s_dir_umask = 0022;
 	hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f);	/* == '????' */
 	hsb->s_quiet = 0;
 	hsb->part = -1;
@@ -159,77 +188,82 @@ static int parse_options(char *options, 
 	if (!options)
 		return 1;
 
-	while ((this_char = strsep(&options, ",")) != 0) {
-		if (!*this_char)
+	while ((p = strsep(&options, ",")) != NULL) {
+		if (!*p)
 			continue;
-		value = strchr(this_char, '=');
-		if (value)
-			*value++ = 0;
-
-	/* Numeric-valued options */
-		if (!strcmp(this_char, "uid")) {
-			if (!value || !*value)
-				return 0;
-			hsb->s_uid = simple_strtoul(value, &value, 0);
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "gid")) {
-			if (!value || !*value)
-				return 0;
-			hsb->s_gid = simple_strtoul(value, &value, 0);
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "umask")) {
-			if (!value || !*value)
-				return 0;
-			hsb->s_file_umask = simple_strtoul(value, &value, 8);
-			hsb->s_dir_umask = hsb->s_file_umask;
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "file_umask")) {
-			if (!value || !*value)
-				return 0;
-			hsb->s_file_umask = simple_strtoul(value, &value, 8);
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "dir_umask")) {
-			if (!value || !*value)
-				return 0;
-			hsb->s_dir_umask = simple_strtoul(value, &value, 8);
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "part")) {
-			if (!value || !*value)
-				return 0;
-			hsb->part = simple_strtoul(value, &value, 0);
-			if (*value)
-				return 0;
-		} else if (!strcmp(this_char, "session")) {
-			if (!value || !*value)
-				return 0;
-			hsb->session = simple_strtoul(value, &value, 0);
-			if (*value)
-				return 0;
-	/* String-valued options */
-		} else if (!strcmp(this_char, "type") && value) {
-			if (strlen(value) != 4)
-				return 0;
-			memcpy(&hsb->s_type, value, 4);
-		} else if (!strcmp(this_char, "creator") && value) {
-			if (strlen(value) != 4)
-				return 0;
-			memcpy(&hsb->s_creator, value, 4);
-	/* Boolean-valued options */
-		} else if (!strcmp(this_char, "quiet")) {
-			if (value)
-				return 0;
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case opt_uid:
+			if (match_int(&args[0], &tmp)) {
+				printk("HFS: uid requires an argument\n");
+				return 0;
+			}
+			hsb->s_uid = (uid_t)tmp;
+			break;
+		case opt_gid:
+			if (match_int(&args[0], &tmp)) {
+				printk("HFS: gid requires an argument\n");
+				return 0;
+			}
+			hsb->s_gid = (gid_t)tmp;
+			break;
+		case opt_umask:
+			if (match_octal(&args[0], &tmp)) {
+				printk("HFS: umask requires a value\n");
+				return 0;
+			}
+			hsb->s_file_umask = (umode_t)tmp;
+			hsb->s_dir_umask = (umode_t)tmp;
+			break;
+		case opt_file_umask:
+			if (match_octal(&args[0], &tmp)) {
+				printk("HFS: file_umask requires a value\n");
+				return 0;
+			}
+			hsb->s_file_umask = (umode_t)tmp;
+			break;
+		case opt_dir_umask:
+			if (match_octal(&args[0], &tmp)) {
+				printk("HFS: dir_umask requires a value\n");
+				return 0;
+			}
+			hsb->s_dir_umask = (umode_t)tmp;
+			break;
+		case opt_part:
+			if (match_int(&args[0], &hsb->part)) {
+				printk("HFS: part requires an argument\n");
+				return 0;
+			}
+			break;
+		case opt_session:
+			if (match_int(&args[0], &hsb->session)) {
+				printk("HFS: session requires an argument\n");
+				return 0;
+			}
+			break;
+		case opt_type:
+			if (match_fourchar(&args[0], &hsb->s_type)) {
+				printk("HFS+-fs: type requires a 4 character value\n");
+				return 0;
+			}
+			break;
+		case opt_creator:
+			if (match_fourchar(&args[0], &hsb->s_creator)) {
+				printk("HFS+-fs: creator requires a 4 character value\n");
+				return 0;
+			}
+			break;
+		case opt_quiet:
 			hsb->s_quiet = 1;
-		} else
+			break;
+		default:
 			return 0;
+		}
 	}
 
 	hsb->s_dir_umask &= 0777;
-	hsb->s_file_umask &= 0777;
+	hsb->s_file_umask &= 0577;
 
 	return 1;
 }
@@ -263,7 +297,7 @@ static int hfs_fill_super(struct super_b
 	res = -EINVAL;
 	if (!parse_options((char *)data, sbi)) {
 		hfs_warn("hfs_fs: unable to parse mount options.\n");
-		goto bail3;
+		goto bail;
 	}
 
 	sb->s_op = &hfs_super_operations;
@@ -276,7 +310,7 @@ static int hfs_fill_super(struct super_b
 			hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
 				hfs_mdb_name(sb));
 		res = -EINVAL;
-		goto bail2;
+		goto bail;
 	}
 
 	/* try to get the root inode */
@@ -306,10 +340,8 @@ bail_iput:
 	iput(root_inode);
 bail_no_root:
 	hfs_warn("hfs_fs: get root inode failed.\n");
+bail:
 	hfs_mdb_put(sb);
-bail2:
-bail3:
-	kfree(sbi);
 	return res;
 }
 
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -446,6 +446,10 @@ static struct hfs_bnode *__hfs_bnode_cre
 		page = read_cache_page(mapping, block, (filler_t *)mapping->a_ops->readpage, NULL);
 		if (IS_ERR(page))
 			goto fail;
+		if (PageError(page)) {
+			page_cache_release(page);
+			goto fail;
+		}
 #if !REF_PAGES
 		page_cache_release(page);
 #endif
@@ -487,12 +491,16 @@ struct hfs_bnode *hfs_bnode_find(struct 
 		hfs_bnode_get(node);
 		spin_unlock(&tree->hash_lock);
 		wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+		if (test_bit(HFS_BNODE_ERROR, &node->flags))
+			goto node_error;
 		return node;
 	}
 	spin_unlock(&tree->hash_lock);
 	node = __hfs_bnode_create(tree, num);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
+	if (test_bit(HFS_BNODE_ERROR, &node->flags))
+		goto node_error;
 	if (!test_bit(HFS_BNODE_NEW, &node->flags))
 		return node;
 
@@ -579,6 +587,10 @@ struct hfs_bnode *hfs_bnode_create(struc
 	node = __hfs_bnode_create(tree, num);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
+	if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
+		hfs_bnode_put(node);
+		return ERR_PTR(-EIO);
+	}
 
 	pagep = node->page;
 	memset(kmap(*pagep) + node->page_offset, 0,
@@ -648,14 +660,3 @@ void hfs_bnode_put(struct hfs_bnode *nod
 	}
 }
 
-void hfsplus_lock_bnode(struct hfs_bnode *node)
-{
-	wait_event(node->lock_wq, !test_and_set_bit(HFS_BNODE_LOCK, &node->flags));
-}
-
-void hfsplus_unlock_bnode(struct hfs_bnode *node)
-{
-	clear_bit(HFS_BNODE_LOCK, &node->flags);
-	if (waitqueue_active(&node->lock_wq))
-		wake_up(&node->lock_wq);
-}
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c
--- a/fs/hfsplus/brec.c
+++ b/fs/hfsplus/brec.c
@@ -11,6 +11,10 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 
+static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
+static int hfs_brec_update_parent(struct hfs_find_data *fd);
+static int hfs_btree_inc_height(struct hfs_btree *);
+
 /* Get the length and offset of the given record in the given node */
 u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
 {
@@ -209,7 +213,7 @@ skip:
 	return 0;
 }
 
-struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
+static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
 {
 	struct hfs_btree *tree;
 	struct hfs_bnode *node, *new_node;
@@ -318,7 +322,7 @@ struct hfs_bnode *hfs_bnode_split(struct
 	return new_node;
 }
 
-int hfs_brec_update_parent(struct hfs_find_data *fd)
+static int hfs_brec_update_parent(struct hfs_find_data *fd)
 {
 	struct hfs_btree *tree;
 	struct hfs_bnode *node, *new_node, *parent;
@@ -414,7 +418,7 @@ out:
 	return 0;
 }
 
-int hfs_btree_inc_height(struct hfs_btree *tree)
+static int hfs_btree_inc_height(struct hfs_btree *tree)
 {
 	struct hfs_bnode *node, *new_node;
 	struct hfs_bnode_desc node_desc;
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -25,14 +25,14 @@ int hfsplus_cat_cmp_key(hfsplus_btree_ke
 	return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name);
 }
 
-void hfsplus_cat_build_key(hfsplus_btree_key *key, u32 parent,
-			  struct qstr *str)
+void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
+			   u32 parent, struct qstr *str)
 {
 	int len;
 
 	key->cat.parent = cpu_to_be32(parent);
 	if (str) {
-		hfsplus_asc2uni(&key->cat.name, str->name, str->len);
+		hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len);
 		len = be16_to_cpu(key->cat.name.length);
 	} else {
 		key->cat.name.length = 0;
@@ -113,13 +113,14 @@ static int hfsplus_cat_build_record(hfsp
 	}
 }
 
-static int hfsplus_fill_cat_thread(hfsplus_cat_entry *entry, int type,
+static int hfsplus_fill_cat_thread(struct super_block *sb,
+				   hfsplus_cat_entry *entry, int type,
 				   u32 parentid, struct qstr *str)
 {
 	entry->type = cpu_to_be16(type);
 	entry->thread.reserved = 0;
 	entry->thread.parentID = cpu_to_be32(parentid);
-	hfsplus_asc2uni(&entry->thread.nodeName, str->name, str->len);
+	hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len);
 	return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2;
 }
 
@@ -131,7 +132,7 @@ int hfsplus_find_cat(struct super_block 
 	int err;
 	u16 type;
 
-	hfsplus_cat_build_key(fd->search_key, cnid, NULL);
+	hfsplus_cat_build_key(sb, fd->search_key, cnid, NULL);
 	err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
 	if (err)
 		return err;
@@ -159,8 +160,8 @@ int hfsplus_create_cat(u32 cnid, struct 
 	sb = dir->i_sb;
 	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
 
-	hfsplus_cat_build_key(fd.search_key, cnid, NULL);
-	entry_size = hfsplus_fill_cat_thread(&entry, S_ISDIR(inode->i_mode) ?
+	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
+	entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
 			HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
 			dir->i_ino, str);
 	err = hfs_brec_find(&fd);
@@ -173,7 +174,7 @@ int hfsplus_create_cat(u32 cnid, struct 
 	if (err)
 		goto err2;
 
-	hfsplus_cat_build_key(fd.search_key, dir->i_ino, str);
+	hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
 	entry_size = hfsplus_cat_build_record(&entry, cnid, inode);
 	err = hfs_brec_find(&fd);
 	if (err != -ENOENT) {
@@ -193,7 +194,7 @@ int hfsplus_create_cat(u32 cnid, struct 
 	return 0;
 
 err1:
-	hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
 	if (!hfs_brec_find(&fd))
 		hfs_brec_remove(&fd);
 err2:
@@ -217,7 +218,7 @@ int hfsplus_delete_cat(u32 cnid, struct 
 	if (!str) {
 		int len;
 
-		hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+		hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
 		err = hfs_brec_find(&fd);
 		if (err)
 			goto out;
@@ -229,7 +230,7 @@ int hfsplus_delete_cat(u32 cnid, struct 
 		hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
 		fd.search_key->key_len = cpu_to_be16(6 + len);
 	} else
-		hfsplus_cat_build_key(fd.search_key, dir->i_ino, str);
+		hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
 
 	err = hfs_brec_find(&fd);
 	if (err)
@@ -259,7 +260,7 @@ int hfsplus_delete_cat(u32 cnid, struct 
 	if (err)
 		goto out;
 
-	hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
 	err = hfs_brec_find(&fd);
 	if (err)
 		goto out;
@@ -294,7 +295,7 @@ int hfsplus_rename_cat(u32 cnid,
 	dst_fd = src_fd;
 
 	/* find the old dir entry and read the data */
-	hfsplus_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+	hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
 	err = hfs_brec_find(&src_fd);
 	if (err)
 		goto out;
@@ -303,7 +304,7 @@ int hfsplus_rename_cat(u32 cnid,
 				src_fd.entrylength);
 
 	/* create new dir entry with the data from the old entry */
-	hfsplus_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
+	hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
 	err = hfs_brec_find(&dst_fd);
 	if (err != -ENOENT) {
 		if (!err)
@@ -319,7 +320,7 @@ int hfsplus_rename_cat(u32 cnid,
 	mark_inode_dirty(dst_dir);
 
 	/* finally remove the old entry */
-	hfsplus_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+	hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
 	err = hfs_brec_find(&src_fd);
 	if (err)
 		goto out;
@@ -331,7 +332,7 @@ int hfsplus_rename_cat(u32 cnid,
 	mark_inode_dirty(src_dir);
 
 	/* remove old thread entry */
-	hfsplus_cat_build_key(src_fd.search_key, cnid, NULL);
+	hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
 	err = hfs_brec_find(&src_fd);
 	if (err)
 		goto out;
@@ -341,8 +342,8 @@ int hfsplus_rename_cat(u32 cnid,
 		goto out;
 
 	/* create new thread entry */
-	hfsplus_cat_build_key(dst_fd.search_key, cnid, NULL);
-	entry_size = hfsplus_fill_cat_thread(&entry, type, dst_dir->i_ino, dst_name);
+	hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
+	entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name);
 	err = hfs_brec_find(&dst_fd);
 	if (err != -ENOENT) {
 		if (!err)
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -40,7 +40,7 @@ static struct dentry *hfsplus_lookup(str
 	sb = dir->i_sb;
 	dentry->d_fsdata = NULL;
 	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
-	hfsplus_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
+	hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
 again:
 	err = hfs_brec_read(&fd, &entry, sizeof(entry));
 	if (err) {
@@ -80,7 +80,7 @@ again:
 			linkid = be32_to_cpu(entry.file.permissions.dev);
 			str.len = sprintf(name, "iNode%d", linkid);
 			str.name = name;
-			hfsplus_cat_build_key(fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
+			hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
 			goto again;
 		} else if (!dentry->d_fsdata)
 			dentry->d_fsdata = (void *)(unsigned long)cnid;
@@ -118,7 +118,7 @@ static int hfsplus_readdir(struct file *
 		return 0;
 
 	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
-	hfsplus_cat_build_key(fd.search_key, inode->i_ino, NULL);
+	hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
 	err = hfs_brec_find(&fd);
 	if (err)
 		goto out;
@@ -164,7 +164,7 @@ static int hfsplus_readdir(struct file *
 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
 		type = be16_to_cpu(entry.type);
 		len = HFSPLUS_MAX_STRLEN;
-		err = hfsplus_uni2asc(&fd.key->cat.name, strbuf, &len);
+		err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
 		if (err)
 			goto out;
 		if (type == HFSPLUS_FOLDER) {
@@ -228,8 +228,8 @@ static int hfsplus_dir_release(struct in
 	return 0;
 }
 
-int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
-		   struct nameidata *nd)
+static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
+			  struct nameidata *nd)
 {
 	struct inode *inode;
 	int res;
@@ -250,7 +250,8 @@ int hfsplus_create(struct inode *dir, st
 	return 0;
 }
 
-int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, struct dentry *dst_dentry)
+static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
+			struct dentry *dst_dentry)
 {
 	struct super_block *sb = dst_dir->i_sb;
 	struct inode *inode = src_dentry->d_inode;
@@ -302,7 +303,7 @@ int hfsplus_link(struct dentry *src_dent
 	return 0;
 }
 
-int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
+static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = dentry->d_inode;
@@ -346,7 +347,7 @@ int hfsplus_unlink(struct inode *dir, st
 	return res;
 }
 
-int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct inode *inode;
 	int res;
@@ -367,7 +368,7 @@ int hfsplus_mkdir(struct inode *dir, str
 	return 0;
 }
 
-int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
+static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode;
 	int res;
@@ -385,7 +386,8 @@ int hfsplus_rmdir(struct inode *dir, str
 	return 0;
 }
 
-int hfsplus_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
+			   const char *symname)
 {
 	struct super_block *sb;
 	struct inode *inode;
@@ -415,7 +417,8 @@ int hfsplus_symlink(struct inode *dir, s
 	return res;
 }
 
-int hfsplus_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
+static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
+			 int mode, dev_t rdev)
 {
 	struct super_block *sb;
 	struct inode *inode;
@@ -440,8 +443,8 @@ int hfsplus_mknod(struct inode *dir, str
 	return 0;
 }
 
-int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
-		   struct inode *new_dir, struct dentry *new_dentry)
+static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
+			  struct inode *new_dir, struct dentry *new_dentry)
 {
 	int res;
 
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -37,8 +37,8 @@ int hfsplus_ext_cmp_key(hfsplus_btree_ke
 	return be32_to_cpu(k1s) < be32_to_cpu(k2s) ? -1 : 1;
 }
 
-void hfsplus_ext_build_key(hfsplus_btree_key *key, u32 cnid,
-			  u32 block, u8 type)
+static void hfsplus_ext_build_key(hfsplus_btree_key *key, u32 cnid,
+				  u32 block, u8 type)
 {
 	key->key_len = cpu_to_be16(HFSPLUS_EXT_KEYLEN - 2);
 	key->ext.cnid = cpu_to_be32(cnid);
@@ -263,8 +263,9 @@ static int hfsplus_add_extent(struct hfs
 	return -EIO;
 }
 
-int hfsplus_free_extents(struct super_block *sb, struct hfsplus_extent *extent,
-			 u32 offset, u32 block_nr)
+static int hfsplus_free_extents(struct super_block *sb,
+				struct hfsplus_extent *extent,
+				u32 offset, u32 block_nr)
 {
 	u32 count, start;
 	int i;
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -114,6 +114,7 @@ struct hfsplus_sb_info {
 	struct hfs_btree *attr_tree;
 	struct inode *alloc_file;
 	struct inode *hidden_dir;
+	struct nls_table *nls;
 
 	/* Runtime variables */
 	u32 blockoffset;
@@ -150,6 +151,7 @@ struct hfsplus_sb_info {
 };
 
 #define HFSPLUS_SB_WRITEBACKUP	0x0001
+#define HFSPLUS_SB_NODECOMPOSE	0x0002
 
 
 struct hfsplus_inode_info {
@@ -230,9 +232,6 @@ struct hfsplus_readdir_data {
 #define hfs_brec_keylen hfsplus_brec_keylen
 #define hfs_brec_insert hfsplus_brec_insert
 #define hfs_brec_remove hfsplus_brec_remove
-#define hfs_bnode_split hfsplus_bnode_split
-#define hfs_brec_update_parent hfsplus_brec_update_parent
-#define hfs_btree_inc_height hfsplus_btree_inc_height
 #define hfs_find_init hfsplus_find_init
 #define hfs_find_exit hfsplus_find_exit
 #define __hfs_brec_find __hplusfs_brec_find
@@ -297,9 +296,6 @@ u16 hfs_brec_lenoff(struct hfs_bnode *, 
 u16 hfs_brec_keylen(struct hfs_bnode *, u16);
 int hfs_brec_insert(struct hfs_find_data *, void *, int);
 int hfs_brec_remove(struct hfs_find_data *);
-struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *);
-int hfs_brec_update_parent(struct hfs_find_data *);
-int hfs_btree_inc_height(struct hfs_btree *);
 
 /* bfind.c */
 int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
@@ -311,7 +307,7 @@ int hfs_brec_goto(struct hfs_find_data *
 
 /* catalog.c */
 int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *);
-void hfsplus_cat_build_key(hfsplus_btree_key *, u32, struct qstr *);
+void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *);
 int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
 int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
 int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
@@ -320,7 +316,6 @@ int hfsplus_rename_cat(u32, struct inode
 
 /* extents.c */
 int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *);
-void hfsplus_ext_build_key(hfsplus_btree_key *, u32, u32, u8);
 void hfsplus_ext_write_extent(struct inode *);
 int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
 int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int);
@@ -352,12 +347,14 @@ int parse_options(char *, struct hfsplus
 void fill_defaults(struct hfsplus_sb_info *);
 
 /* tables.c */
-extern u16 case_fold_table[];
+extern u16 hfsplus_case_fold_table[];
+extern u16 hfsplus_decompose_table[];
+extern u16 hfsplus_compose_table[];
 
 /* unicode.c */
 int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_uni2asc(const struct hfsplus_unistr *, char *, int *);
-int hfsplus_asc2uni(struct hfsplus_unistr *, const char *, int);
+int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
+int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
 
 /* wrapper.c */
 int hfsplus_read_wrapper(struct super_block *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -40,7 +40,7 @@ static sector_t hfsplus_bmap(struct addr
 	return generic_block_bmap(mapping, block, hfsplus_get_block);
 }
 
-int hfsplus_releasepage(struct page *page, int mask)
+static int hfsplus_releasepage(struct page *page, int mask)
 {
 	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
@@ -71,12 +71,6 @@ int hfsplus_releasepage(struct page *pag
 			;
 		else if (atomic_read(&node->refcnt))
 			res = 0;
-		else for (i = 0; i < tree->pages_per_bnode; i++) {
-			if (PageActive(node->page[i])) {
-				res = 0;
-				break;
-			}
-		}
 		if (res && node) {
 			hfs_bnode_unhash(node);
 			hfs_bnode_free(node);
@@ -100,7 +94,7 @@ int hfsplus_releasepage(struct page *pag
 		spin_unlock(&tree->hash_lock);
 	}
 	//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
-	return res;
+	return res ? try_to_free_buffers(page) : 0;
 }
 
 static int hfsplus_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
@@ -297,7 +291,7 @@ static int hfsplus_file_release(struct i
 extern struct inode_operations hfsplus_dir_inode_operations;
 extern struct file_operations hfsplus_dir_operations;
 
-struct inode_operations hfsplus_file_inode_operations = {
+static struct inode_operations hfsplus_file_inode_operations = {
 	.lookup		= hfsplus_file_lookup,
 	.truncate	= hfsplus_file_truncate,
 	.permission	= hfsplus_permission,
@@ -306,7 +300,7 @@ struct inode_operations hfsplus_file_ino
 	.listxattr	= hfsplus_listxattr,
 };
 
-struct file_operations hfsplus_file_operations = {
+static struct file_operations hfsplus_file_operations = {
 	.llseek 	= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -11,8 +11,32 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/parser.h>
+#include <linux/nls.h>
 #include "hfsplus_fs.h"
 
+enum {
+	opt_creator, opt_type,
+	opt_umask, opt_uid, opt_gid,
+	opt_part, opt_session, opt_nls,
+	opt_nodecompose, opt_decompose,
+	opt_err
+};
+
+static match_table_t tokens = {
+	{ opt_creator, "creator=%s" },
+	{ opt_type, "type=%s" },
+	{ opt_umask, "umask=%o" },
+	{ opt_uid, "uid=%u" },
+	{ opt_gid, "gid=%u" },
+	{ opt_part, "part=%u" },
+	{ opt_session, "session=%u" },
+	{ opt_nls, "nls=%s" },
+	{ opt_decompose, "decompose" },
+	{ opt_nodecompose, "nodecompose" },
+	{ opt_err, NULL }
+};
+
 /* Initialize an options object to reasonable defaults */
 void fill_defaults(struct hfsplus_sb_info *opts)
 {
@@ -29,99 +53,110 @@ void fill_defaults(struct hfsplus_sb_inf
 }
 
 /* convert a "four byte character" to a 32 bit int with error checks */
-static int fill_fourchar(u32 *result, char *input)
-{
-	u32 out;
-	int i;
-
-	if (!result || !input || !*input || (strlen(input) != 4))
-		return 0;
-
-	for (out = 0, i = 0; i < 4; i++) {
-		out <<= 8;
-		out |= ((int)(input[i])) & 0xFF;
-	}
-	*result = out;
-	return 1;
-}
-
-/* convert a string to int with error checks */
-static int fill_int(int *result, char *input, int base)
+static inline int match_fourchar(substring_t *arg, u32 *result)
 {
-	char *tmp = input;
-	int intval;
-
-	if (!result || !input || !*input)
-		return 0;
-
-	intval = simple_strtoul(tmp, &tmp, base);
-	if (*tmp)
-		return 0;
-
-	*result = intval;
-	return 1;
+	if (arg->to - arg->from != 4)
+		return -EINVAL;
+	memcpy(result, arg->from, 4);
+	return 0;
 }
 
 /* Parse options from mount. Returns 0 on failure */
 /* input is the options passed to mount() as a string */
-int parse_options(char *input, struct hfsplus_sb_info *results)
+int parse_options(char *input, struct hfsplus_sb_info *sbi)
 {
-	char *curropt, *value;
-	int tmp;
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+	int tmp, token;
 
 	if (!input)
-		return 1;
+		goto done;
 
-	while ((curropt = strsep(&input,",")) != NULL) {
-		if (!*curropt)
+	while ((p = strsep(&input, ",")) != NULL) {
+		if (!*p)
 			continue;
 
-		if ((value = strchr(curropt, '=')) != NULL)
-			*value++ = '\0';
-
-		if (!strcmp(curropt, "creator")) {
-			if (!fill_fourchar(&(results->creator), value)) {
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case opt_creator:
+			if (match_fourchar(&args[0], &sbi->creator)) {
 				printk("HFS+-fs: creator requires a 4 character value\n");
 				return 0;
 			}
-		} else if (!strcmp(curropt, "type")) {
-			if (!fill_fourchar(&(results->type), value)) {
+			break;
+		case opt_type:
+			if (match_fourchar(&args[0], &sbi->type)) {
 				printk("HFS+-fs: type requires a 4 character value\n");
 				return 0;
 			}
-		} else if (!strcmp(curropt, "umask")) {
-			if (!fill_int(&tmp, value, 8)) {
+			break;
+		case opt_umask:
+			if (match_octal(&args[0], &tmp)) {
 				printk("HFS+-fs: umask requires a value\n");
 				return 0;
 			}
-			results->umask = (umode_t)tmp;
-		} else if (!strcmp(curropt, "uid")) {
-			if (!fill_int(&tmp, value, 0)) {
+			sbi->umask = (umode_t)tmp;
+			break;
+		case opt_uid:
+			if (match_int(&args[0], &tmp)) {
 				printk("HFS+-fs: uid requires an argument\n");
 				return 0;
 			}
-			results->uid = (uid_t)tmp;
-		} else if (!strcmp(curropt, "gid")) {
-			if (!fill_int(&tmp, value, 0)) {
+			sbi->uid = (uid_t)tmp;
+			break;
+		case opt_gid:
+			if (match_int(&args[0], &tmp)) {
 				printk("HFS+-fs: gid requires an argument\n");
 				return 0;
 			}
-			results->gid = (gid_t)tmp;
-		} else if (!strcmp(curropt, "part")) {
-			if (!fill_int(&results->part, value, 0)) {
+			sbi->gid = (gid_t)tmp;
+			break;
+		case opt_part:
+			if (match_int(&args[0], &sbi->part)) {
 				printk("HFS+-fs: part requires an argument\n");
 				return 0;
 			}
-		} else if (!strcmp(curropt, "session")) {
-			if (!fill_int(&results->session, value, 0)) {
+			break;
+		case opt_session:
+			if (match_int(&args[0], &sbi->session)) {
 				printk("HFS+-fs: session requires an argument\n");
 				return 0;
 			}
-		} else {
-			printk("HFS+-fs: unknown option %s\n", curropt);
+			break;
+		case opt_nls:
+			if (sbi->nls) {
+				printk("HFS+-fs: unable to change nls mapping\n");
+				return 0;
+			}
+			p = match_strdup(&args[0]);
+			sbi->nls = load_nls(p);
+			if (!sbi->nls) {
+				printk("HFS+-fs: unable to load nls mapping \"%s\"\n", p);
+				kfree(p);
+				return 0;
+			}
+			kfree(p);
+			break;
+		case opt_decompose:
+			sbi->flags &= ~HFSPLUS_SB_NODECOMPOSE;
+			break;
+		case opt_nodecompose:
+			sbi->flags |= HFSPLUS_SB_NODECOMPOSE;
+			break;
+		default:
 			return 0;
 		}
 	}
 
+done:
+	if (!sbi->nls) {
+		/* try utf8 first, as this is the old default behaviour */
+		sbi->nls = load_nls("utf8");
+		if (!sbi->nls)
+			sbi->nls = load_nls_default();
+		if (!sbi->nls)
+			return 0;
+	}
+
 	return 1;
 }
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/vfs.h>
+#include <linux/nls.h>
 
 static struct inode *hfsplus_alloc_inode(struct super_block *sb);
 static void hfsplus_destroy_inode(struct inode *inode);
@@ -94,7 +95,7 @@ static void hfsplus_read_inode(struct in
 	make_bad_inode(inode);
 }
 
-int hfsplus_write_inode(struct inode *inode, int unused)
+static int hfsplus_write_inode(struct inode *inode, int unused)
 {
 	struct hfsplus_vh *vhdr;
 	int ret = 0;
@@ -207,7 +208,9 @@ static void hfsplus_write_super(struct s
 static void hfsplus_put_super(struct super_block *sb)
 {
 	dprint(DBG_SUPER, "hfsplus_put_super\n");
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!sb->s_fs_info)
+		return;
+	if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) {
 		struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
 
 		vhdr->modify_date = hfsp_now2mt();
@@ -223,6 +226,10 @@ static void hfsplus_put_super(struct sup
 	iput(HFSPLUS_SB(sb).alloc_file);
 	iput(HFSPLUS_SB(sb).hidden_dir);
 	brelse(HFSPLUS_SB(sb).s_vhbh);
+	if (HFSPLUS_SB(sb).nls)
+		unload_nls(HFSPLUS_SB(sb).nls);
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
 }
 
 static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -239,7 +246,7 @@ static int hfsplus_statfs(struct super_b
 	return 0;
 }
 
-int hfsplus_remount(struct super_block *sb, int *flags, char *data)
+static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 {
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
@@ -280,13 +287,13 @@ static int hfsplus_fill_super(struct sup
 	struct hfs_find_data fd;
 	struct inode *root;
 	struct qstr str;
+	struct nls_table *nls = NULL;
 	int err = -EINVAL;
 
 	sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL);
-	if (!sbi) {
-		err = -ENOMEM;
-		goto out2;
-	}
+	if (!sbi)
+		return -ENOMEM;
+
 	memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
 	sb->s_fs_info = sbi;
 	INIT_HLIST_HEAD(&sbi->rsrc_inodes);
@@ -295,7 +302,16 @@ static int hfsplus_fill_super(struct sup
 		if (!silent)
 			printk("HFS+-fs: unable to parse mount options\n");
 		err = -EINVAL;
-		goto out2;
+		goto cleanup;
+	}
+
+	/* temporarily use utf8 to correctly find the hidden dir below */
+	nls = sbi->nls;
+	sbi->nls = load_nls("utf8");
+	if (!nls) {
+		printk("HFS+: unable to load nls for utf8\n");
+		err = -EINVAL;
+		goto cleanup;
 	}
 
 	/* Grab the volume header */
@@ -303,7 +319,7 @@ static int hfsplus_fill_super(struct sup
 		if (!silent)
 			printk("HFS+-fs: unable to find HFS+ superblock\n");
 		err = -EINVAL;
-		goto out2;
+		goto cleanup;
 	}
 	vhdr = HFSPLUS_SB(sb).s_vhdr;
 
@@ -376,7 +392,7 @@ static int hfsplus_fill_super(struct sup
 	str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
 	str.name = HFSP_HIDDENDIR_NAME;
 	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
-	hfsplus_cat_build_key(fd.search_key, HFSPLUS_ROOT_CNID, &str);
+	hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
 	if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
 		hfs_find_exit(&fd);
 		if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
@@ -410,11 +426,14 @@ static int hfsplus_fill_super(struct sup
 		mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir);
 	}
 out:
+	unload_nls(sbi->nls);
+	sbi->nls = nls;
 	return 0;
 
 cleanup:
 	hfsplus_put_super(sb);
-out2:
+	if (nls)
+		unload_nls(nls);
 	return err;
 }
 
diff --git a/fs/hfsplus/tables.c b/fs/hfsplus/tables.c
--- a/fs/hfsplus/tables.c
+++ b/fs/hfsplus/tables.c
@@ -11,7 +11,7 @@
  *  (HFS Plus Volume Format)
  */
 
-u16 case_fold_table[] = {
+u16 hfsplus_case_fold_table[] = {
 /*
  *  The lower case table consists of a 256-entry high-byte table followed by
  *  some number of 256-entry subtables. The high-byte table contains either an
@@ -406,3 +406,2840 @@ u16 case_fold_table[] = {
     /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
             0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
 };
+
+u16 hfsplus_decompose_table[] = {
+	/* base table */
+	0x0010, 0x04c0, 0x0000, 0x06f0, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x07b0,
+	/* char table 0x0___ */
+	0x0020, 0x0070, 0x0160, 0x0190, 0x0230, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x02d0, 0x0340, 0x0360, 0x03b0, 0x03e0, 0x0400, 0x0430,
+	/* char table 0x00__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0030, 0x0040, 0x0050, 0x0060,
+	/* char values 0x00c_ */
+	0x2042, 0x204a, 0x2052, 0x205a, 0x2062, 0x206a, 0x0000, 0x2072,
+	0x207a, 0x2082, 0x208a, 0x2092, 0x209a, 0x20a2, 0x20aa, 0x20b2,
+	/* char values 0x00d_ */
+	0x0000, 0x20ba, 0x20c2, 0x20ca, 0x20d2, 0x20da, 0x20e2, 0x0000,
+	0x0000, 0x20ea, 0x20f2, 0x20fa, 0x2102, 0x210a, 0x0000, 0x0000,
+	/* char values 0x00e_ */
+	0x2112, 0x211a, 0x2122, 0x212a, 0x2132, 0x213a, 0x0000, 0x2142,
+	0x214a, 0x2152, 0x215a, 0x2162, 0x216a, 0x2172, 0x217a, 0x2182,
+	/* char values 0x00f_ */
+	0x0000, 0x218a, 0x2192, 0x219a, 0x21a2, 0x21aa, 0x21b2, 0x0000,
+	0x0000, 0x21ba, 0x21c2, 0x21ca, 0x21d2, 0x21da, 0x0000, 0x21e2,
+	/* char table 0x01__ */
+	0x0080, 0x0090, 0x00a0, 0x00b0, 0x00c0, 0x00d0, 0x00e0, 0x00f0,
+	0x0000, 0x0000, 0x0100, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150,
+	/* char values 0x010_ */
+	0x21ea, 0x21f2, 0x21fa, 0x2202, 0x220a, 0x2212, 0x221a, 0x2222,
+	0x222a, 0x2232, 0x223a, 0x2242, 0x224a, 0x2252, 0x225a, 0x2262,
+	/* char values 0x011_ */
+	0x0000, 0x0000, 0x226a, 0x2272, 0x227a, 0x2282, 0x228a, 0x2292,
+	0x229a, 0x22a2, 0x22aa, 0x22b2, 0x22ba, 0x22c2, 0x22ca, 0x22d2,
+	/* char values 0x012_ */
+	0x22da, 0x22e2, 0x22ea, 0x22f2, 0x22fa, 0x2302, 0x0000, 0x0000,
+	0x230a, 0x2312, 0x231a, 0x2322, 0x232a, 0x2332, 0x233a, 0x2342,
+	/* char values 0x013_ */
+	0x234a, 0x0000, 0x0000, 0x0000, 0x2352, 0x235a, 0x2362, 0x236a,
+	0x0000, 0x2372, 0x237a, 0x2382, 0x238a, 0x2392, 0x239a, 0x0000,
+	/* char values 0x014_ */
+	0x0000, 0x0000, 0x0000, 0x23a2, 0x23aa, 0x23b2, 0x23ba, 0x23c2,
+	0x23ca, 0x0000, 0x0000, 0x0000, 0x23d2, 0x23da, 0x23e2, 0x23ea,
+	/* char values 0x015_ */
+	0x23f2, 0x23fa, 0x0000, 0x0000, 0x2402, 0x240a, 0x2412, 0x241a,
+	0x2422, 0x242a, 0x2432, 0x243a, 0x2442, 0x244a, 0x2452, 0x245a,
+	/* char values 0x016_ */
+	0x2462, 0x246a, 0x2472, 0x247a, 0x2482, 0x248a, 0x0000, 0x0000,
+	0x2492, 0x249a, 0x24a2, 0x24aa, 0x24b2, 0x24ba, 0x24c2, 0x24ca,
+	/* char values 0x017_ */
+	0x24d2, 0x24da, 0x24e2, 0x24ea, 0x24f2, 0x24fa, 0x2502, 0x250a,
+	0x2512, 0x251a, 0x2522, 0x252a, 0x2532, 0x253a, 0x2542, 0x0000,
+	/* char values 0x01a_ */
+	0x254a, 0x2552, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x255a,
+	/* char values 0x01b_ */
+	0x2562, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x01c_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x256a, 0x2572, 0x257a,
+	/* char values 0x01d_ */
+	0x2582, 0x258a, 0x2592, 0x259a, 0x25a2, 0x25ab, 0x25b7, 0x25c3,
+	0x25cf, 0x25db, 0x25e7, 0x25f3, 0x25ff, 0x0000, 0x260b, 0x2617,
+	/* char values 0x01e_ */
+	0x2623, 0x262f, 0x263a, 0x2642, 0x0000, 0x0000, 0x264a, 0x2652,
+	0x265a, 0x2662, 0x266a, 0x2672, 0x267b, 0x2687, 0x2692, 0x269a,
+	/* char values 0x01f_ */
+	0x26a2, 0x0000, 0x0000, 0x0000, 0x26aa, 0x26b2, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x26bb, 0x26c7, 0x26d2, 0x26da, 0x26e2, 0x26ea,
+	/* char table 0x02__ */
+	0x0170, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x020_ */
+	0x26f2, 0x26fa, 0x2702, 0x270a, 0x2712, 0x271a, 0x2722, 0x272a,
+	0x2732, 0x273a, 0x2742, 0x274a, 0x2752, 0x275a, 0x2762, 0x276a,
+	/* char values 0x021_ */
+	0x2772, 0x277a, 0x2782, 0x278a, 0x2792, 0x279a, 0x27a2, 0x27aa,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x03__ */
+	0x0000, 0x01a0, 0x0000, 0x0000, 0x01b0, 0x0000, 0x0000, 0x01c0,
+	0x01d0, 0x01e0, 0x01f0, 0x0200, 0x0210, 0x0220, 0x0000, 0x0000,
+	/* char values 0x031_ */
+	0x27b2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x034_ */
+	0x27b9, 0x27bd, 0x0000, 0x27c1, 0x27c6, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x037_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x27cd, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x27d1, 0x0000,
+	/* char values 0x038_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x27d6, 0x27de, 0x27e5,
+	0x27ea, 0x27f2, 0x27fa, 0x0000, 0x2802, 0x0000, 0x280a, 0x2812,
+	/* char values 0x039_ */
+	0x281b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x03a_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x2826, 0x282e, 0x2836, 0x283e, 0x2846, 0x284e,
+	/* char values 0x03b_ */
+	0x2857, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x03c_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x2862, 0x286a, 0x2872, 0x287a, 0x2882, 0x0000,
+	/* char values 0x03d_ */
+	0x0000, 0x0000, 0x0000, 0x288a, 0x2892, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x04__ */
+	0x0240, 0x0250, 0x0000, 0x0260, 0x0000, 0x0270, 0x0000, 0x0280,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0290, 0x02a0, 0x02b0, 0x02c0,
+	/* char values 0x040_ */
+	0x0000, 0x289a, 0x0000, 0x28a2, 0x0000, 0x0000, 0x0000, 0x28aa,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x28b2, 0x0000, 0x28ba, 0x0000,
+	/* char values 0x041_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x28c2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x043_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x28ca, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x045_ */
+	0x0000, 0x28d2, 0x0000, 0x28da, 0x0000, 0x0000, 0x0000, 0x28e2,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x28ea, 0x0000, 0x28f2, 0x0000,
+	/* char values 0x047_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x28fa, 0x2902,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x04c_ */
+	0x0000, 0x290a, 0x2912, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x04d_ */
+	0x291a, 0x2922, 0x292a, 0x2932, 0x2939, 0x293d, 0x2942, 0x294a,
+	0x2951, 0x2955, 0x295a, 0x2962, 0x296a, 0x2972, 0x297a, 0x2982,
+	/* char values 0x04e_ */
+	0x2989, 0x298d, 0x2992, 0x299a, 0x29a2, 0x29aa, 0x29b2, 0x29ba,
+	0x29c1, 0x29c5, 0x29ca, 0x29d2, 0x0000, 0x0000, 0x29da, 0x29e2,
+	/* char values 0x04f_ */
+	0x29ea, 0x29f2, 0x29fa, 0x2a02, 0x2a0a, 0x2a12, 0x0000, 0x0000,
+	0x2a1a, 0x2a22, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x09__ */
+	0x0000, 0x0000, 0x02e0, 0x02f0, 0x0000, 0x0300, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0310, 0x0320, 0x0330, 0x0000, 0x0000,
+	/* char values 0x092_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2a2a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x093_ */
+	0x0000, 0x2a32, 0x0000, 0x0000, 0x2a3a, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x095_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x2a42, 0x2a4a, 0x2a52, 0x2a5a, 0x2a62, 0x2a6a, 0x2a72, 0x2a7a,
+	/* char values 0x09b_ */
+	0x2a82, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x09c_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x2a8a, 0x2a92, 0x0000, 0x0000, 0x0000,
+	/* char values 0x09d_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x2a9a, 0x2aa2, 0x0000, 0x2aaa,
+	/* char table 0x0a__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0350, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0a5_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2ab2, 0x2aba, 0x2ac2, 0x2aca, 0x0000, 0x2ad2, 0x0000,
+	/* char table 0x0b__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0370, 0x0380, 0x0000, 0x0000,
+	0x0000, 0x0390, 0x0000, 0x0000, 0x03a0, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0b4_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x2ada, 0x0000, 0x0000, 0x2ae2, 0x2aea, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0b5_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x2af2, 0x2afa, 0x0000, 0x2b02,
+	/* char values 0x0b9_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x2b0a, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0bc_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x2b12, 0x2b1a, 0x2b22, 0x0000, 0x0000, 0x0000,
+	/* char table 0x0c__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x03d0, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0c4_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x2b2a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0cc_ */
+	0x2b32, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b3a,
+	0x2b42, 0x0000, 0x2b4a, 0x2b53, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x0d__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0d4_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x2b5e, 0x2b66, 0x2b6e, 0x0000, 0x0000, 0x0000,
+	/* char table 0x0e__ */
+	0x0000, 0x0000, 0x0000, 0x0410, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0420, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0e3_ */
+	0x0000, 0x0000, 0x0000, 0x2b76, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0eb_ */
+	0x0000, 0x0000, 0x0000, 0x2b7e, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x0f__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0440, 0x0450, 0x0460, 0x0470,
+	0x0480, 0x0490, 0x04a0, 0x04b0, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0f4_ */
+	0x0000, 0x0000, 0x0000, 0x2b86, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b8e, 0x0000, 0x0000,
+	/* char values 0x0f5_ */
+	0x0000, 0x0000, 0x2b96, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b9e,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x2ba6, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0f6_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2bae, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0f7_ */
+	0x0000, 0x0000, 0x0000, 0x2bb6, 0x0000, 0x2bbe, 0x2bc6, 0x2bcf,
+	0x2bda, 0x2be3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0f8_ */
+	0x0000, 0x2bee, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0f9_ */
+	0x0000, 0x0000, 0x0000, 0x2bf6, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2bfe, 0x0000, 0x0000,
+	/* char values 0x0fa_ */
+	0x0000, 0x0000, 0x2c06, 0x0000, 0x0000, 0x0000, 0x0000, 0x2c0e,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x2c16, 0x0000, 0x0000, 0x0000,
+	/* char values 0x0fb_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2c1e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x1___ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x04d0, 0x05e0,
+	/* char table 0x1e__ */
+	0x04e0, 0x04f0, 0x0500, 0x0510, 0x0520, 0x0530, 0x0540, 0x0550,
+	0x0560, 0x0570, 0x0580, 0x0590, 0x05a0, 0x05b0, 0x05c0, 0x05d0,
+	/* char values 0x1e0_ */
+	0x2c26, 0x2c2e, 0x2c36, 0x2c3e, 0x2c46, 0x2c4e, 0x2c56, 0x2c5e,
+	0x2c67, 0x2c73, 0x2c7e, 0x2c86, 0x2c8e, 0x2c96, 0x2c9e, 0x2ca6,
+	/* char values 0x1e1_ */
+	0x2cae, 0x2cb6, 0x2cbe, 0x2cc6, 0x2ccf, 0x2cdb, 0x2ce7, 0x2cf3,
+	0x2cfe, 0x2d06, 0x2d0e, 0x2d16, 0x2d1f, 0x2d2b, 0x2d36, 0x2d3e,
+	/* char values 0x1e2_ */
+	0x2d46, 0x2d4e, 0x2d56, 0x2d5e, 0x2d66, 0x2d6e, 0x2d76, 0x2d7e,
+	0x2d86, 0x2d8e, 0x2d96, 0x2d9e, 0x2da6, 0x2dae, 0x2db7, 0x2dc3,
+	/* char values 0x1e3_ */
+	0x2dce, 0x2dd6, 0x2dde, 0x2de6, 0x2dee, 0x2df6, 0x2dfe, 0x2e06,
+	0x2e0f, 0x2e1b, 0x2e26, 0x2e2e, 0x2e36, 0x2e3e, 0x2e46, 0x2e4e,
+	/* char values 0x1e4_ */
+	0x2e56, 0x2e5e, 0x2e66, 0x2e6e, 0x2e76, 0x2e7e, 0x2e86, 0x2e8e,
+	0x2e96, 0x2e9e, 0x2ea6, 0x2eae, 0x2eb7, 0x2ec3, 0x2ecf, 0x2edb,
+	/* char values 0x1e5_ */
+	0x2ee7, 0x2ef3, 0x2eff, 0x2f0b, 0x2f16, 0x2f1e, 0x2f26, 0x2f2e,
+	0x2f36, 0x2f3e, 0x2f46, 0x2f4e, 0x2f57, 0x2f63, 0x2f6e, 0x2f76,
+	/* char values 0x1e6_ */
+	0x2f7e, 0x2f86, 0x2f8e, 0x2f96, 0x2f9f, 0x2fab, 0x2fb7, 0x2fc3,
+	0x2fcf, 0x2fdb, 0x2fe6, 0x2fee, 0x2ff6, 0x2ffe, 0x3006, 0x300e,
+	/* char values 0x1e7_ */
+	0x3016, 0x301e, 0x3026, 0x302e, 0x3036, 0x303e, 0x3046, 0x304e,
+	0x3057, 0x3063, 0x306f, 0x307b, 0x3086, 0x308e, 0x3096, 0x309e,
+	/* char values 0x1e8_ */
+	0x30a6, 0x30ae, 0x30b6, 0x30be, 0x30c6, 0x30ce, 0x30d6, 0x30de,
+	0x30e6, 0x30ee, 0x30f6, 0x30fe, 0x3106, 0x310e, 0x3116, 0x311e,
+	/* char values 0x1e9_ */
+	0x3126, 0x312e, 0x3136, 0x313e, 0x3146, 0x314e, 0x3156, 0x315e,
+	0x3166, 0x316e, 0x0000, 0x3176, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x1ea_ */
+	0x317e, 0x3186, 0x318e, 0x3196, 0x319f, 0x31ab, 0x31b7, 0x31c3,
+	0x31cf, 0x31db, 0x31e7, 0x31f3, 0x31ff, 0x320b, 0x3217, 0x3223,
+	/* char values 0x1eb_ */
+	0x322f, 0x323b, 0x3247, 0x3253, 0x325f, 0x326b, 0x3277, 0x3283,
+	0x328e, 0x3296, 0x329e, 0x32a6, 0x32ae, 0x32b6, 0x32bf, 0x32cb,
+	/* char values 0x1ec_ */
+	0x32d7, 0x32e3, 0x32ef, 0x32fb, 0x3307, 0x3313, 0x331f, 0x332b,
+	0x3336, 0x333e, 0x3346, 0x334e, 0x3356, 0x335e, 0x3366, 0x336e,
+	/* char values 0x1ed_ */
+	0x3377, 0x3383, 0x338f, 0x339b, 0x33a7, 0x33b3, 0x33bf, 0x33cb,
+	0x33d7, 0x33e3, 0x33ef, 0x33fb, 0x3407, 0x3413, 0x341f, 0x342b,
+	/* char values 0x1ee_ */
+	0x3437, 0x3443, 0x344f, 0x345b, 0x3466, 0x346e, 0x3476, 0x347e,
+	0x3487, 0x3493, 0x349f, 0x34ab, 0x34b7, 0x34c3, 0x34cf, 0x34db,
+	/* char values 0x1ef_ */
+	0x34e7, 0x34f3, 0x34fe, 0x3506, 0x350e, 0x3516, 0x351e, 0x3526,
+	0x352e, 0x3536, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x1f__ */
+	0x05f0, 0x0600, 0x0610, 0x0620, 0x0630, 0x0640, 0x0650, 0x0660,
+	0x0670, 0x0680, 0x0690, 0x06a0, 0x06b0, 0x06c0, 0x06d0, 0x06e0,
+	/* char values 0x1f0_ */
+	0x353e, 0x3546, 0x354f, 0x355b, 0x3567, 0x3573, 0x357f, 0x358b,
+	0x3596, 0x359e, 0x35a7, 0x35b3, 0x35bf, 0x35cb, 0x35d7, 0x35e3,
+	/* char values 0x1f1_ */
+	0x35ee, 0x35f6, 0x35ff, 0x360b, 0x3617, 0x3623, 0x0000, 0x0000,
+	0x362e, 0x3636, 0x363f, 0x364b, 0x3657, 0x3663, 0x0000, 0x0000,
+	/* char values 0x1f2_ */
+	0x366e, 0x3676, 0x367f, 0x368b, 0x3697, 0x36a3, 0x36af, 0x36bb,
+	0x36c6, 0x36ce, 0x36d7, 0x36e3, 0x36ef, 0x36fb, 0x3707, 0x3713,
+	/* char values 0x1f3_ */
+	0x371e, 0x3726, 0x372f, 0x373b, 0x3747, 0x3753, 0x375f, 0x376b,
+	0x3776, 0x377e, 0x3787, 0x3793, 0x379f, 0x37ab, 0x37b7, 0x37c3,
+	/* char values 0x1f4_ */
+	0x37ce, 0x37d6, 0x37df, 0x37eb, 0x37f7, 0x3803, 0x0000, 0x0000,
+	0x380e, 0x3816, 0x381f, 0x382b, 0x3837, 0x3843, 0x0000, 0x0000,
+	/* char values 0x1f5_ */
+	0x384e, 0x3856, 0x385f, 0x386b, 0x3877, 0x3883, 0x388f, 0x389b,
+	0x0000, 0x38a6, 0x0000, 0x38af, 0x0000, 0x38bb, 0x0000, 0x38c7,
+	/* char values 0x1f6_ */
+	0x38d2, 0x38da, 0x38e3, 0x38ef, 0x38fb, 0x3907, 0x3913, 0x391f,
+	0x392a, 0x3932, 0x393b, 0x3947, 0x3953, 0x395f, 0x396b, 0x3977,
+	/* char values 0x1f7_ */
+	0x3982, 0x398a, 0x3992, 0x399a, 0x39a2, 0x39aa, 0x39b2, 0x39ba,
+	0x39c2, 0x39ca, 0x39d2, 0x39da, 0x39e2, 0x39ea, 0x0000, 0x0000,
+	/* char values 0x1f8_ */
+	0x39f3, 0x39ff, 0x3a0c, 0x3a1c, 0x3a2c, 0x3a3c, 0x3a4c, 0x3a5c,
+	0x3a6b, 0x3a77, 0x3a84, 0x3a94, 0x3aa4, 0x3ab4, 0x3ac4, 0x3ad4,
+	/* char values 0x1f9_ */
+	0x3ae3, 0x3aef, 0x3afc, 0x3b0c, 0x3b1c, 0x3b2c, 0x3b3c, 0x3b4c,
+	0x3b5b, 0x3b67, 0x3b74, 0x3b84, 0x3b94, 0x3ba4, 0x3bb4, 0x3bc4,
+	/* char values 0x1fa_ */
+	0x3bd3, 0x3bdf, 0x3bec, 0x3bfc, 0x3c0c, 0x3c1c, 0x3c2c, 0x3c3c,
+	0x3c4b, 0x3c57, 0x3c64, 0x3c74, 0x3c84, 0x3c94, 0x3ca4, 0x3cb4,
+	/* char values 0x1fb_ */
+	0x3cc2, 0x3cca, 0x3cd3, 0x3cde, 0x3ce7, 0x0000, 0x3cf2, 0x3cfb,
+	0x3d06, 0x3d0e, 0x3d16, 0x3d1e, 0x3d26, 0x0000, 0x3d2d, 0x0000,
+	/* char values 0x1fc_ */
+	0x0000, 0x3d32, 0x3d3b, 0x3d46, 0x3d4f, 0x0000, 0x3d5a, 0x3d63,
+	0x3d6e, 0x3d76, 0x3d7e, 0x3d86, 0x3d8e, 0x3d96, 0x3d9e, 0x3da6,
+	/* char values 0x1fd_ */
+	0x3dae, 0x3db6, 0x3dbf, 0x3dcb, 0x0000, 0x0000, 0x3dd6, 0x3ddf,
+	0x3dea, 0x3df2, 0x3dfa, 0x3e02, 0x0000, 0x3e0a, 0x3e12, 0x3e1a,
+	/* char values 0x1fe_ */
+	0x3e22, 0x3e2a, 0x3e33, 0x3e3f, 0x3e4a, 0x3e52, 0x3e5a, 0x3e63,
+	0x3e6e, 0x3e76, 0x3e7e, 0x3e86, 0x3e8e, 0x3e96, 0x3e9e, 0x3ea5,
+	/* char values 0x1ff_ */
+	0x0000, 0x0000, 0x3eab, 0x3eb6, 0x3ebf, 0x0000, 0x3eca, 0x3ed3,
+	0x3ede, 0x3ee6, 0x3eee, 0x3ef6, 0x3efe, 0x3f05, 0x0000, 0x0000,
+	/* char table 0x3___ */
+	0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0x30__ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0710, 0x0720, 0x0730, 0x0740,
+	0x0000, 0x0750, 0x0760, 0x0770, 0x0780, 0x0790, 0x0000, 0x07a0,
+	/* char values 0x304_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x3f0a, 0x0000, 0x3f12, 0x0000,
+	/* char values 0x305_ */
+	0x3f1a, 0x0000, 0x3f22, 0x0000, 0x3f2a, 0x0000, 0x3f32, 0x0000,
+	0x3f3a, 0x0000, 0x3f42, 0x0000, 0x3f4a, 0x0000, 0x3f52, 0x0000,
+	/* char values 0x306_ */
+	0x3f5a, 0x0000, 0x3f62, 0x0000, 0x0000, 0x3f6a, 0x0000, 0x3f72,
+	0x0000, 0x3f7a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x307_ */
+	0x3f82, 0x3f8a, 0x0000, 0x3f92, 0x3f9a, 0x0000, 0x3fa2, 0x3faa,
+	0x0000, 0x3fb2, 0x3fba, 0x0000, 0x3fc2, 0x3fca, 0x0000, 0x0000,
+	/* char values 0x309_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x3fd2, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3fda, 0x0000,
+	/* char values 0x30a_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x3fe2, 0x0000, 0x3fea, 0x0000,
+	/* char values 0x30b_ */
+	0x3ff2, 0x0000, 0x3ffa, 0x0000, 0x4002, 0x0000, 0x400a, 0x0000,
+	0x4012, 0x0000, 0x401a, 0x0000, 0x4022, 0x0000, 0x402a, 0x0000,
+	/* char values 0x30c_ */
+	0x4032, 0x0000, 0x403a, 0x0000, 0x0000, 0x4042, 0x0000, 0x404a,
+	0x0000, 0x4052, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0x30d_ */
+	0x405a, 0x4062, 0x0000, 0x406a, 0x4072, 0x0000, 0x407a, 0x4082,
+	0x0000, 0x408a, 0x4092, 0x0000, 0x409a, 0x40a2, 0x0000, 0x0000,
+	/* char values 0x30f_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x40aa, 0x0000, 0x0000, 0x40b2,
+	0x40ba, 0x40c2, 0x40ca, 0x0000, 0x0000, 0x0000, 0x40d2, 0x0000,
+	/* char table 0xf___ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x07c0, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char table 0xfb__ */
+	0x0000, 0x07d0, 0x07e0, 0x07f0, 0x0800, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	/* char values 0xfb1_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x40da,
+	/* char values 0xfb2_ */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x40e2, 0x40ea, 0x40f3, 0x40ff, 0x410a, 0x4112,
+	/* char values 0xfb3_ */
+	0x411a, 0x4122, 0x412a, 0x4132, 0x413a, 0x4142, 0x414a, 0x0000,
+	0x4152, 0x415a, 0x4162, 0x416a, 0x4172, 0x0000, 0x417a, 0x0000,
+	/* char values 0xfb4_ */
+	0x4182, 0x418a, 0x0000, 0x4192, 0x419a, 0x0000, 0x41a2, 0x41aa,
+	0x41b2, 0x41ba, 0x41c2, 0x41ca, 0x41d2, 0x41da, 0x41e2, 0x0000,
+	/* decomposed characters */
+	0x0041, 0x0300, 0x0041, 0x0301, 0x0041, 0x0302, 0x0041, 0x0303,
+	0x0041, 0x0308, 0x0041, 0x030a, 0x0043, 0x0327, 0x0045, 0x0300,
+	0x0045, 0x0301, 0x0045, 0x0302, 0x0045, 0x0308, 0x0049, 0x0300,
+	0x0049, 0x0301, 0x0049, 0x0302, 0x0049, 0x0308, 0x004e, 0x0303,
+	0x004f, 0x0300, 0x004f, 0x0301, 0x004f, 0x0302, 0x004f, 0x0303,
+	0x004f, 0x0308, 0x0055, 0x0300, 0x0055, 0x0301, 0x0055, 0x0302,
+	0x0055, 0x0308, 0x0059, 0x0301, 0x0061, 0x0300, 0x0061, 0x0301,
+	0x0061, 0x0302, 0x0061, 0x0303, 0x0061, 0x0308, 0x0061, 0x030a,
+	0x0063, 0x0327, 0x0065, 0x0300, 0x0065, 0x0301, 0x0065, 0x0302,
+	0x0065, 0x0308, 0x0069, 0x0300, 0x0069, 0x0301, 0x0069, 0x0302,
+	0x0069, 0x0308, 0x006e, 0x0303, 0x006f, 0x0300, 0x006f, 0x0301,
+	0x006f, 0x0302, 0x006f, 0x0303, 0x006f, 0x0308, 0x0075, 0x0300,
+	0x0075, 0x0301, 0x0075, 0x0302, 0x0075, 0x0308, 0x0079, 0x0301,
+	0x0079, 0x0308, 0x0041, 0x0304, 0x0061, 0x0304, 0x0041, 0x0306,
+	0x0061, 0x0306, 0x0041, 0x0328, 0x0061, 0x0328, 0x0043, 0x0301,
+	0x0063, 0x0301, 0x0043, 0x0302, 0x0063, 0x0302, 0x0043, 0x0307,
+	0x0063, 0x0307, 0x0043, 0x030c, 0x0063, 0x030c, 0x0044, 0x030c,
+	0x0064, 0x030c, 0x0045, 0x0304, 0x0065, 0x0304, 0x0045, 0x0306,
+	0x0065, 0x0306, 0x0045, 0x0307, 0x0065, 0x0307, 0x0045, 0x0328,
+	0x0065, 0x0328, 0x0045, 0x030c, 0x0065, 0x030c, 0x0047, 0x0302,
+	0x0067, 0x0302, 0x0047, 0x0306, 0x0067, 0x0306, 0x0047, 0x0307,
+	0x0067, 0x0307, 0x0047, 0x0327, 0x0067, 0x0327, 0x0048, 0x0302,
+	0x0068, 0x0302, 0x0049, 0x0303, 0x0069, 0x0303, 0x0049, 0x0304,
+	0x0069, 0x0304, 0x0049, 0x0306, 0x0069, 0x0306, 0x0049, 0x0328,
+	0x0069, 0x0328, 0x0049, 0x0307, 0x004a, 0x0302, 0x006a, 0x0302,
+	0x004b, 0x0327, 0x006b, 0x0327, 0x004c, 0x0301, 0x006c, 0x0301,
+	0x004c, 0x0327, 0x006c, 0x0327, 0x004c, 0x030c, 0x006c, 0x030c,
+	0x004e, 0x0301, 0x006e, 0x0301, 0x004e, 0x0327, 0x006e, 0x0327,
+	0x004e, 0x030c, 0x006e, 0x030c, 0x004f, 0x0304, 0x006f, 0x0304,
+	0x004f, 0x0306, 0x006f, 0x0306, 0x004f, 0x030b, 0x006f, 0x030b,
+	0x0052, 0x0301, 0x0072, 0x0301, 0x0052, 0x0327, 0x0072, 0x0327,
+	0x0052, 0x030c, 0x0072, 0x030c, 0x0053, 0x0301, 0x0073, 0x0301,
+	0x0053, 0x0302, 0x0073, 0x0302, 0x0053, 0x0327, 0x0073, 0x0327,
+	0x0053, 0x030c, 0x0073, 0x030c, 0x0054, 0x0327, 0x0074, 0x0327,
+	0x0054, 0x030c, 0x0074, 0x030c, 0x0055, 0x0303, 0x0075, 0x0303,
+	0x0055, 0x0304, 0x0075, 0x0304, 0x0055, 0x0306, 0x0075, 0x0306,
+	0x0055, 0x030a, 0x0075, 0x030a, 0x0055, 0x030b, 0x0075, 0x030b,
+	0x0055, 0x0328, 0x0075, 0x0328, 0x0057, 0x0302, 0x0077, 0x0302,
+	0x0059, 0x0302, 0x0079, 0x0302, 0x0059, 0x0308, 0x005a, 0x0301,
+	0x007a, 0x0301, 0x005a, 0x0307, 0x007a, 0x0307, 0x005a, 0x030c,
+	0x007a, 0x030c, 0x004f, 0x031b, 0x006f, 0x031b, 0x0055, 0x031b,
+	0x0075, 0x031b, 0x0041, 0x030c, 0x0061, 0x030c, 0x0049, 0x030c,
+	0x0069, 0x030c, 0x004f, 0x030c, 0x006f, 0x030c, 0x0055, 0x030c,
+	0x0075, 0x030c, 0x0055, 0x0308, 0x0304, 0x0075, 0x0308, 0x0304,
+	0x0055, 0x0308, 0x0301, 0x0075, 0x0308, 0x0301, 0x0055, 0x0308,
+	0x030c, 0x0075, 0x0308, 0x030c, 0x0055, 0x0308, 0x0300, 0x0075,
+	0x0308, 0x0300, 0x0041, 0x0308, 0x0304, 0x0061, 0x0308, 0x0304,
+	0x0041, 0x0307, 0x0304, 0x0061, 0x0307, 0x0304, 0x00c6, 0x0304,
+	0x00e6, 0x0304, 0x0047, 0x030c, 0x0067, 0x030c, 0x004b, 0x030c,
+	0x006b, 0x030c, 0x004f, 0x0328, 0x006f, 0x0328, 0x004f, 0x0328,
+	0x0304, 0x006f, 0x0328, 0x0304, 0x01b7, 0x030c, 0x0292, 0x030c,
+	0x006a, 0x030c, 0x0047, 0x0301, 0x0067, 0x0301, 0x0041, 0x030a,
+	0x0301, 0x0061, 0x030a, 0x0301, 0x00c6, 0x0301, 0x00e6, 0x0301,
+	0x00d8, 0x0301, 0x00f8, 0x0301, 0x0041, 0x030f, 0x0061, 0x030f,
+	0x0041, 0x0311, 0x0061, 0x0311, 0x0045, 0x030f, 0x0065, 0x030f,
+	0x0045, 0x0311, 0x0065, 0x0311, 0x0049, 0x030f, 0x0069, 0x030f,
+	0x0049, 0x0311, 0x0069, 0x0311, 0x004f, 0x030f, 0x006f, 0x030f,
+	0x004f, 0x0311, 0x006f, 0x0311, 0x0052, 0x030f, 0x0072, 0x030f,
+	0x0052, 0x0311, 0x0072, 0x0311, 0x0055, 0x030f, 0x0075, 0x030f,
+	0x0055, 0x0311, 0x0075, 0x0311, 0x0306, 0x0307, 0x0300, 0x0301,
+	0x0313, 0x0308, 0x030d, 0x02b9, 0x003b, 0x00a8, 0x030d, 0x0391,
+	0x030d, 0x00b7, 0x0395, 0x030d, 0x0397, 0x030d, 0x0399, 0x030d,
+	0x039f, 0x030d, 0x03a5, 0x030d, 0x03a9, 0x030d, 0x03b9, 0x0308,
+	0x030d, 0x0399, 0x0308, 0x03a5, 0x0308, 0x03b1, 0x030d, 0x03b5,
+	0x030d, 0x03b7, 0x030d, 0x03b9, 0x030d, 0x03c5, 0x0308, 0x030d,
+	0x03b9, 0x0308, 0x03c5, 0x0308, 0x03bf, 0x030d, 0x03c5, 0x030d,
+	0x03c9, 0x030d, 0x03d2, 0x030d, 0x03d2, 0x0308, 0x0415, 0x0308,
+	0x0413, 0x0301, 0x0406, 0x0308, 0x041a, 0x0301, 0x0423, 0x0306,
+	0x0418, 0x0306, 0x0438, 0x0306, 0x0435, 0x0308, 0x0433, 0x0301,
+	0x0456, 0x0308, 0x043a, 0x0301, 0x0443, 0x0306, 0x0474, 0x030f,
+	0x0475, 0x030f, 0x0416, 0x0306, 0x0436, 0x0306, 0x0410, 0x0306,
+	0x0430, 0x0306, 0x0410, 0x0308, 0x0430, 0x0308, 0x00c6, 0x00e6,
+	0x0415, 0x0306, 0x0435, 0x0306, 0x018f, 0x0259, 0x018f, 0x0308,
+	0x0259, 0x0308, 0x0416, 0x0308, 0x0436, 0x0308, 0x0417, 0x0308,
+	0x0437, 0x0308, 0x01b7, 0x0292, 0x0418, 0x0304, 0x0438, 0x0304,
+	0x0418, 0x0308, 0x0438, 0x0308, 0x041e, 0x0308, 0x043e, 0x0308,
+	0x019f, 0x0275, 0x019f, 0x0308, 0x0275, 0x0308, 0x0423, 0x0304,
+	0x0443, 0x0304, 0x0423, 0x0308, 0x0443, 0x0308, 0x0423, 0x030b,
+	0x0443, 0x030b, 0x0427, 0x0308, 0x0447, 0x0308, 0x042b, 0x0308,
+	0x044b, 0x0308, 0x0928, 0x093c, 0x0930, 0x093c, 0x0933, 0x093c,
+	0x0915, 0x093c, 0x0916, 0x093c, 0x0917, 0x093c, 0x091c, 0x093c,
+	0x0921, 0x093c, 0x0922, 0x093c, 0x092b, 0x093c, 0x092f, 0x093c,
+	0x09ac, 0x09bc, 0x09c7, 0x09be, 0x09c7, 0x09d7, 0x09a1, 0x09bc,
+	0x09a2, 0x09bc, 0x09af, 0x09bc, 0x0a16, 0x0a3c, 0x0a17, 0x0a3c,
+	0x0a1c, 0x0a3c, 0x0a21, 0x0a3c, 0x0a2b, 0x0a3c, 0x0b47, 0x0b56,
+	0x0b47, 0x0b3e, 0x0b47, 0x0b57, 0x0b21, 0x0b3c, 0x0b22, 0x0b3c,
+	0x0b2f, 0x0b3c, 0x0b92, 0x0bd7, 0x0bc6, 0x0bbe, 0x0bc7, 0x0bbe,
+	0x0bc6, 0x0bd7, 0x0c46, 0x0c56, 0x0cbf, 0x0cd5, 0x0cc6, 0x0cd5,
+	0x0cc6, 0x0cd6, 0x0cc6, 0x0cc2, 0x0cc6, 0x0cc2, 0x0cd5, 0x0d46,
+	0x0d3e, 0x0d47, 0x0d3e, 0x0d46, 0x0d57, 0x0e4d, 0x0e32, 0x0ecd,
+	0x0eb2, 0x0f42, 0x0fb7, 0x0f4c, 0x0fb7, 0x0f51, 0x0fb7, 0x0f56,
+	0x0fb7, 0x0f5b, 0x0fb7, 0x0f40, 0x0fb5, 0x0f72, 0x0f71, 0x0f74,
+	0x0f71, 0x0fb2, 0x0f80, 0x0fb2, 0x0f80, 0x0f71, 0x0fb3, 0x0f80,
+	0x0fb3, 0x0f80, 0x0f71, 0x0f80, 0x0f71, 0x0f92, 0x0fb7, 0x0f9c,
+	0x0fb7, 0x0fa1, 0x0fb7, 0x0fa6, 0x0fb7, 0x0fab, 0x0fb7, 0x0f90,
+	0x0fb5, 0x0041, 0x0325, 0x0061, 0x0325, 0x0042, 0x0307, 0x0062,
+	0x0307, 0x0042, 0x0323, 0x0062, 0x0323, 0x0042, 0x0331, 0x0062,
+	0x0331, 0x0043, 0x0327, 0x0301, 0x0063, 0x0327, 0x0301, 0x0044,
+	0x0307, 0x0064, 0x0307, 0x0044, 0x0323, 0x0064, 0x0323, 0x0044,
+	0x0331, 0x0064, 0x0331, 0x0044, 0x0327, 0x0064, 0x0327, 0x0044,
+	0x032d, 0x0064, 0x032d, 0x0045, 0x0304, 0x0300, 0x0065, 0x0304,
+	0x0300, 0x0045, 0x0304, 0x0301, 0x0065, 0x0304, 0x0301, 0x0045,
+	0x032d, 0x0065, 0x032d, 0x0045, 0x0330, 0x0065, 0x0330, 0x0045,
+	0x0327, 0x0306, 0x0065, 0x0327, 0x0306, 0x0046, 0x0307, 0x0066,
+	0x0307, 0x0047, 0x0304, 0x0067, 0x0304, 0x0048, 0x0307, 0x0068,
+	0x0307, 0x0048, 0x0323, 0x0068, 0x0323, 0x0048, 0x0308, 0x0068,
+	0x0308, 0x0048, 0x0327, 0x0068, 0x0327, 0x0048, 0x032e, 0x0068,
+	0x032e, 0x0049, 0x0330, 0x0069, 0x0330, 0x0049, 0x0308, 0x0301,
+	0x0069, 0x0308, 0x0301, 0x004b, 0x0301, 0x006b, 0x0301, 0x004b,
+	0x0323, 0x006b, 0x0323, 0x004b, 0x0331, 0x006b, 0x0331, 0x004c,
+	0x0323, 0x006c, 0x0323, 0x004c, 0x0323, 0x0304, 0x006c, 0x0323,
+	0x0304, 0x004c, 0x0331, 0x006c, 0x0331, 0x004c, 0x032d, 0x006c,
+	0x032d, 0x004d, 0x0301, 0x006d, 0x0301, 0x004d, 0x0307, 0x006d,
+	0x0307, 0x004d, 0x0323, 0x006d, 0x0323, 0x004e, 0x0307, 0x006e,
+	0x0307, 0x004e, 0x0323, 0x006e, 0x0323, 0x004e, 0x0331, 0x006e,
+	0x0331, 0x004e, 0x032d, 0x006e, 0x032d, 0x004f, 0x0303, 0x0301,
+	0x006f, 0x0303, 0x0301, 0x004f, 0x0303, 0x0308, 0x006f, 0x0303,
+	0x0308, 0x004f, 0x0304, 0x0300, 0x006f, 0x0304, 0x0300, 0x004f,
+	0x0304, 0x0301, 0x006f, 0x0304, 0x0301, 0x0050, 0x0301, 0x0070,
+	0x0301, 0x0050, 0x0307, 0x0070, 0x0307, 0x0052, 0x0307, 0x0072,
+	0x0307, 0x0052, 0x0323, 0x0072, 0x0323, 0x0052, 0x0323, 0x0304,
+	0x0072, 0x0323, 0x0304, 0x0052, 0x0331, 0x0072, 0x0331, 0x0053,
+	0x0307, 0x0073, 0x0307, 0x0053, 0x0323, 0x0073, 0x0323, 0x0053,
+	0x0301, 0x0307, 0x0073, 0x0301, 0x0307, 0x0053, 0x030c, 0x0307,
+	0x0073, 0x030c, 0x0307, 0x0053, 0x0323, 0x0307, 0x0073, 0x0323,
+	0x0307, 0x0054, 0x0307, 0x0074, 0x0307, 0x0054, 0x0323, 0x0074,
+	0x0323, 0x0054, 0x0331, 0x0074, 0x0331, 0x0054, 0x032d, 0x0074,
+	0x032d, 0x0055, 0x0324, 0x0075, 0x0324, 0x0055, 0x0330, 0x0075,
+	0x0330, 0x0055, 0x032d, 0x0075, 0x032d, 0x0055, 0x0303, 0x0301,
+	0x0075, 0x0303, 0x0301, 0x0055, 0x0304, 0x0308, 0x0075, 0x0304,
+	0x0308, 0x0056, 0x0303, 0x0076, 0x0303, 0x0056, 0x0323, 0x0076,
+	0x0323, 0x0057, 0x0300, 0x0077, 0x0300, 0x0057, 0x0301, 0x0077,
+	0x0301, 0x0057, 0x0308, 0x0077, 0x0308, 0x0057, 0x0307, 0x0077,
+	0x0307, 0x0057, 0x0323, 0x0077, 0x0323, 0x0058, 0x0307, 0x0078,
+	0x0307, 0x0058, 0x0308, 0x0078, 0x0308, 0x0059, 0x0307, 0x0079,
+	0x0307, 0x005a, 0x0302, 0x007a, 0x0302, 0x005a, 0x0323, 0x007a,
+	0x0323, 0x005a, 0x0331, 0x007a, 0x0331, 0x0068, 0x0331, 0x0074,
+	0x0308, 0x0077, 0x030a, 0x0079, 0x030a, 0x017f, 0x0307, 0x0041,
+	0x0323, 0x0061, 0x0323, 0x0041, 0x0309, 0x0061, 0x0309, 0x0041,
+	0x0302, 0x0301, 0x0061, 0x0302, 0x0301, 0x0041, 0x0302, 0x0300,
+	0x0061, 0x0302, 0x0300, 0x0041, 0x0302, 0x0309, 0x0061, 0x0302,
+	0x0309, 0x0041, 0x0302, 0x0303, 0x0061, 0x0302, 0x0303, 0x0041,
+	0x0323, 0x0302, 0x0061, 0x0323, 0x0302, 0x0041, 0x0306, 0x0301,
+	0x0061, 0x0306, 0x0301, 0x0041, 0x0306, 0x0300, 0x0061, 0x0306,
+	0x0300, 0x0041, 0x0306, 0x0309, 0x0061, 0x0306, 0x0309, 0x0041,
+	0x0306, 0x0303, 0x0061, 0x0306, 0x0303, 0x0041, 0x0323, 0x0306,
+	0x0061, 0x0323, 0x0306, 0x0045, 0x0323, 0x0065, 0x0323, 0x0045,
+	0x0309, 0x0065, 0x0309, 0x0045, 0x0303, 0x0065, 0x0303, 0x0045,
+	0x0302, 0x0301, 0x0065, 0x0302, 0x0301, 0x0045, 0x0302, 0x0300,
+	0x0065, 0x0302, 0x0300, 0x0045, 0x0302, 0x0309, 0x0065, 0x0302,
+	0x0309, 0x0045, 0x0302, 0x0303, 0x0065, 0x0302, 0x0303, 0x0045,
+	0x0323, 0x0302, 0x0065, 0x0323, 0x0302, 0x0049, 0x0309, 0x0069,
+	0x0309, 0x0049, 0x0323, 0x0069, 0x0323, 0x004f, 0x0323, 0x006f,
+	0x0323, 0x004f, 0x0309, 0x006f, 0x0309, 0x004f, 0x0302, 0x0301,
+	0x006f, 0x0302, 0x0301, 0x004f, 0x0302, 0x0300, 0x006f, 0x0302,
+	0x0300, 0x004f, 0x0302, 0x0309, 0x006f, 0x0302, 0x0309, 0x004f,
+	0x0302, 0x0303, 0x006f, 0x0302, 0x0303, 0x004f, 0x0323, 0x0302,
+	0x006f, 0x0323, 0x0302, 0x004f, 0x031b, 0x0301, 0x006f, 0x031b,
+	0x0301, 0x004f, 0x031b, 0x0300, 0x006f, 0x031b, 0x0300, 0x004f,
+	0x031b, 0x0309, 0x006f, 0x031b, 0x0309, 0x004f, 0x031b, 0x0303,
+	0x006f, 0x031b, 0x0303, 0x004f, 0x031b, 0x0323, 0x006f, 0x031b,
+	0x0323, 0x0055, 0x0323, 0x0075, 0x0323, 0x0055, 0x0309, 0x0075,
+	0x0309, 0x0055, 0x031b, 0x0301, 0x0075, 0x031b, 0x0301, 0x0055,
+	0x031b, 0x0300, 0x0075, 0x031b, 0x0300, 0x0055, 0x031b, 0x0309,
+	0x0075, 0x031b, 0x0309, 0x0055, 0x031b, 0x0303, 0x0075, 0x031b,
+	0x0303, 0x0055, 0x031b, 0x0323, 0x0075, 0x031b, 0x0323, 0x0059,
+	0x0300, 0x0079, 0x0300, 0x0059, 0x0323, 0x0079, 0x0323, 0x0059,
+	0x0309, 0x0079, 0x0309, 0x0059, 0x0303, 0x0079, 0x0303, 0x03b1,
+	0x0313, 0x03b1, 0x0314, 0x03b1, 0x0313, 0x0300, 0x03b1, 0x0314,
+	0x0300, 0x03b1, 0x0313, 0x0301, 0x03b1, 0x0314, 0x0301, 0x03b1,
+	0x0313, 0x0342, 0x03b1, 0x0314, 0x0342, 0x0391, 0x0313, 0x0391,
+	0x0314, 0x0391, 0x0313, 0x0300, 0x0391, 0x0314, 0x0300, 0x0391,
+	0x0313, 0x0301, 0x0391, 0x0314, 0x0301, 0x0391, 0x0313, 0x0342,
+	0x0391, 0x0314, 0x0342, 0x03b5, 0x0313, 0x03b5, 0x0314, 0x03b5,
+	0x0313, 0x0300, 0x03b5, 0x0314, 0x0300, 0x03b5, 0x0313, 0x0301,
+	0x03b5, 0x0314, 0x0301, 0x0395, 0x0313, 0x0395, 0x0314, 0x0395,
+	0x0313, 0x0300, 0x0395, 0x0314, 0x0300, 0x0395, 0x0313, 0x0301,
+	0x0395, 0x0314, 0x0301, 0x03b7, 0x0313, 0x03b7, 0x0314, 0x03b7,
+	0x0313, 0x0300, 0x03b7, 0x0314, 0x0300, 0x03b7, 0x0313, 0x0301,
+	0x03b7, 0x0314, 0x0301, 0x03b7, 0x0313, 0x0342, 0x03b7, 0x0314,
+	0x0342, 0x0397, 0x0313, 0x0397, 0x0314, 0x0397, 0x0313, 0x0300,
+	0x0397, 0x0314, 0x0300, 0x0397, 0x0313, 0x0301, 0x0397, 0x0314,
+	0x0301, 0x0397, 0x0313, 0x0342, 0x0397, 0x0314, 0x0342, 0x03b9,
+	0x0313, 0x03b9, 0x0314, 0x03b9, 0x0313, 0x0300, 0x03b9, 0x0314,
+	0x0300, 0x03b9, 0x0313, 0x0301, 0x03b9, 0x0314, 0x0301, 0x03b9,
+	0x0313, 0x0342, 0x03b9, 0x0314, 0x0342, 0x0399, 0x0313, 0x0399,
+	0x0314, 0x0399, 0x0313, 0x0300, 0x0399, 0x0314, 0x0300, 0x0399,
+	0x0313, 0x0301, 0x0399, 0x0314, 0x0301, 0x0399, 0x0313, 0x0342,
+	0x0399, 0x0314, 0x0342, 0x03bf, 0x0313, 0x03bf, 0x0314, 0x03bf,
+	0x0313, 0x0300, 0x03bf, 0x0314, 0x0300, 0x03bf, 0x0313, 0x0301,
+	0x03bf, 0x0314, 0x0301, 0x039f, 0x0313, 0x039f, 0x0314, 0x039f,
+	0x0313, 0x0300, 0x039f, 0x0314, 0x0300, 0x039f, 0x0313, 0x0301,
+	0x039f, 0x0314, 0x0301, 0x03c5, 0x0313, 0x03c5, 0x0314, 0x03c5,
+	0x0313, 0x0300, 0x03c5, 0x0314, 0x0300, 0x03c5, 0x0313, 0x0301,
+	0x03c5, 0x0314, 0x0301, 0x03c5, 0x0313, 0x0342, 0x03c5, 0x0314,
+	0x0342, 0x03a5, 0x0314, 0x03a5, 0x0314, 0x0300, 0x03a5, 0x0314,
+	0x0301, 0x03a5, 0x0314, 0x0342, 0x03c9, 0x0313, 0x03c9, 0x0314,
+	0x03c9, 0x0313, 0x0300, 0x03c9, 0x0314, 0x0300, 0x03c9, 0x0313,
+	0x0301, 0x03c9, 0x0314, 0x0301, 0x03c9, 0x0313, 0x0342, 0x03c9,
+	0x0314, 0x0342, 0x03a9, 0x0313, 0x03a9, 0x0314, 0x03a9, 0x0313,
+	0x0300, 0x03a9, 0x0314, 0x0300, 0x03a9, 0x0313, 0x0301, 0x03a9,
+	0x0314, 0x0301, 0x03a9, 0x0313, 0x0342, 0x03a9, 0x0314, 0x0342,
+	0x03b1, 0x0300, 0x03b1, 0x0301, 0x03b5, 0x0300, 0x03b5, 0x0301,
+	0x03b7, 0x0300, 0x03b7, 0x0301, 0x03b9, 0x0300, 0x03b9, 0x0301,
+	0x03bf, 0x0300, 0x03bf, 0x0301, 0x03c5, 0x0300, 0x03c5, 0x0301,
+	0x03c9, 0x0300, 0x03c9, 0x0301, 0x03b1, 0x0345, 0x0313, 0x03b1,
+	0x0345, 0x0314, 0x03b1, 0x0345, 0x0313, 0x0300, 0x03b1, 0x0345,
+	0x0314, 0x0300, 0x03b1, 0x0345, 0x0313, 0x0301, 0x03b1, 0x0345,
+	0x0314, 0x0301, 0x03b1, 0x0345, 0x0313, 0x0342, 0x03b1, 0x0345,
+	0x0314, 0x0342, 0x0391, 0x0345, 0x0313, 0x0391, 0x0345, 0x0314,
+	0x0391, 0x0345, 0x0313, 0x0300, 0x0391, 0x0345, 0x0314, 0x0300,
+	0x0391, 0x0345, 0x0313, 0x0301, 0x0391, 0x0345, 0x0314, 0x0301,
+	0x0391, 0x0345, 0x0313, 0x0342, 0x0391, 0x0345, 0x0314, 0x0342,
+	0x03b7, 0x0345, 0x0313, 0x03b7, 0x0345, 0x0314, 0x03b7, 0x0345,
+	0x0313, 0x0300, 0x03b7, 0x0345, 0x0314, 0x0300, 0x03b7, 0x0345,
+	0x0313, 0x0301, 0x03b7, 0x0345, 0x0314, 0x0301, 0x03b7, 0x0345,
+	0x0313, 0x0342, 0x03b7, 0x0345, 0x0314, 0x0342, 0x0397, 0x0345,
+	0x0313, 0x0397, 0x0345, 0x0314, 0x0397, 0x0345, 0x0313, 0x0300,
+	0x0397, 0x0345, 0x0314, 0x0300, 0x0397, 0x0345, 0x0313, 0x0301,
+	0x0397, 0x0345, 0x0314, 0x0301, 0x0397, 0x0345, 0x0313, 0x0342,
+	0x0397, 0x0345, 0x0314, 0x0342, 0x03c9, 0x0345, 0x0313, 0x03c9,
+	0x0345, 0x0314, 0x03c9, 0x0345, 0x0313, 0x0300, 0x03c9, 0x0345,
+	0x0314, 0x0300, 0x03c9, 0x0345, 0x0313, 0x0301, 0x03c9, 0x0345,
+	0x0314, 0x0301, 0x03c9, 0x0345, 0x0313, 0x0342, 0x03c9, 0x0345,
+	0x0314, 0x0342, 0x03a9, 0x0345, 0x0313, 0x03a9, 0x0345, 0x0314,
+	0x03a9, 0x0345, 0x0313, 0x0300, 0x03a9, 0x0345, 0x0314, 0x0300,
+	0x03a9, 0x0345, 0x0313, 0x0301, 0x03a9, 0x0345, 0x0314, 0x0301,
+	0x03a9, 0x0345, 0x0313, 0x0342, 0x03a9, 0x0345, 0x0314, 0x0342,
+	0x03b1, 0x0306, 0x03b1, 0x0304, 0x03b1, 0x0345, 0x0300, 0x03b1,
+	0x0345, 0x03b1, 0x0345, 0x0301, 0x03b1, 0x0342, 0x03b1, 0x0345,
+	0x0342, 0x0391, 0x0306, 0x0391, 0x0304, 0x0391, 0x0300, 0x0391,
+	0x0301, 0x0391, 0x0345, 0x03b9, 0x00a8, 0x0342, 0x03b7, 0x0345,
+	0x0300, 0x03b7, 0x0345, 0x03b7, 0x0345, 0x0301, 0x03b7, 0x0342,
+	0x03b7, 0x0345, 0x0342, 0x0395, 0x0300, 0x0395, 0x0301, 0x0397,
+	0x0300, 0x0397, 0x0301, 0x0397, 0x0345, 0x1fbf, 0x0300, 0x1fbf,
+	0x0301, 0x1fbf, 0x0342, 0x03b9, 0x0306, 0x03b9, 0x0304, 0x03b9,
+	0x0308, 0x0300, 0x03b9, 0x0308, 0x0301, 0x03b9, 0x0342, 0x03b9,
+	0x0308, 0x0342, 0x0399, 0x0306, 0x0399, 0x0304, 0x0399, 0x0300,
+	0x0399, 0x0301, 0x1ffe, 0x0300, 0x1ffe, 0x0301, 0x1ffe, 0x0342,
+	0x03c5, 0x0306, 0x03c5, 0x0304, 0x03c5, 0x0308, 0x0300, 0x03c5,
+	0x0308, 0x0301, 0x03c1, 0x0313, 0x03c1, 0x0314, 0x03c5, 0x0342,
+	0x03c5, 0x0308, 0x0342, 0x03a5, 0x0306, 0x03a5, 0x0304, 0x03a5,
+	0x0300, 0x03a5, 0x0301, 0x03a1, 0x0314, 0x00a8, 0x0300, 0x00a8,
+	0x0301, 0x0060, 0x03c9, 0x0345, 0x0300, 0x03c9, 0x0345, 0x03bf,
+	0x0345, 0x0301, 0x03c9, 0x0342, 0x03c9, 0x0345, 0x0342, 0x039f,
+	0x0300, 0x039f, 0x0301, 0x03a9, 0x0300, 0x03a9, 0x0301, 0x03a9,
+	0x0345, 0x00b4, 0x304b, 0x3099, 0x304d, 0x3099, 0x304f, 0x3099,
+	0x3051, 0x3099, 0x3053, 0x3099, 0x3055, 0x3099, 0x3057, 0x3099,
+	0x3059, 0x3099, 0x305b, 0x3099, 0x305d, 0x3099, 0x305f, 0x3099,
+	0x3061, 0x3099, 0x3064, 0x3099, 0x3066, 0x3099, 0x3068, 0x3099,
+	0x306f, 0x3099, 0x306f, 0x309a, 0x3072, 0x3099, 0x3072, 0x309a,
+	0x3075, 0x3099, 0x3075, 0x309a, 0x3078, 0x3099, 0x3078, 0x309a,
+	0x307b, 0x3099, 0x307b, 0x309a, 0x3046, 0x3099, 0x309d, 0x3099,
+	0x30ab, 0x3099, 0x30ad, 0x3099, 0x30af, 0x3099, 0x30b1, 0x3099,
+	0x30b3, 0x3099, 0x30b5, 0x3099, 0x30b7, 0x3099, 0x30b9, 0x3099,
+	0x30bb, 0x3099, 0x30bd, 0x3099, 0x30bf, 0x3099, 0x30c1, 0x3099,
+	0x30c4, 0x3099, 0x30c6, 0x3099, 0x30c8, 0x3099, 0x30cf, 0x3099,
+	0x30cf, 0x309a, 0x30d2, 0x3099, 0x30d2, 0x309a, 0x30d5, 0x3099,
+	0x30d5, 0x309a, 0x30d8, 0x3099, 0x30d8, 0x309a, 0x30db, 0x3099,
+	0x30db, 0x309a, 0x30a6, 0x3099, 0x30ef, 0x3099, 0x30f0, 0x3099,
+	0x30f1, 0x3099, 0x30f2, 0x3099, 0x30fd, 0x3099, 0x05f2, 0x05b7,
+	0x05e9, 0x05c1, 0x05e9, 0x05c2, 0x05e9, 0x05bc, 0x05c1, 0x05e9,
+	0x05bc, 0x05c2, 0x05d0, 0x05b7, 0x05d0, 0x05b8, 0x05d0, 0x05bc,
+	0x05d1, 0x05bc, 0x05d2, 0x05bc, 0x05d3, 0x05bc, 0x05d4, 0x05bc,
+	0x05d5, 0x05bc, 0x05d6, 0x05bc, 0x05d8, 0x05bc, 0x05d9, 0x05bc,
+	0x05da, 0x05bc, 0x05db, 0x05bc, 0x05dc, 0x05bc, 0x05de, 0x05bc,
+	0x05e0, 0x05bc, 0x05e1, 0x05bc, 0x05e3, 0x05bc, 0x05e4, 0x05bc,
+	0x05e6, 0x05bc, 0x05e7, 0x05bc, 0x05e8, 0x05bc, 0x05e9, 0x05bc,
+	0x05ea, 0x05bc, 0x05d5, 0x05b9, 0x05d1, 0x05bf, 0x05db, 0x05bf,
+	0x05e4, 0x05bf
+};
+
+u16 hfsplus_compose_table[] = {
+	/* base */
+	0x0000, 0x0050,  0x0300, 0x00a4,  0x0301, 0x00e4,  0x0302, 0x015c,
+	0x0303, 0x0192,  0x0304, 0x01b4,  0x0306, 0x01e6,  0x0307, 0x0220,
+	0x0308, 0x0270,  0x0309, 0x02d2,  0x030a, 0x02ec,  0x030b, 0x02fa,
+	0x030c, 0x0308,  0x030d, 0x034c,  0x030f, 0x0370,  0x0311, 0x038e,
+	0x0313, 0x03a8,  0x0314, 0x03c6,  0x031b, 0x03e8,  0x0323, 0x03f2,
+	0x0324, 0x0440,  0x0325, 0x0446,  0x0327, 0x044c,  0x0328, 0x047a,
+	0x032d, 0x0490,  0x032e, 0x04aa,  0x0330, 0x04b0,  0x0331, 0x04be,
+	0x0342, 0x04e2,  0x0345, 0x04f4,  0x05b7, 0x0504,  0x05b8, 0x050a,
+	0x05b9, 0x050e,  0x05bc, 0x0512,  0x05bf, 0x0540,  0x05c1, 0x0548,
+	0x05c2, 0x054c,  0x093c, 0x0550,  0x09bc, 0x0568,  0x09be, 0x0572,
+	0x09d7, 0x0576,  0x0a3c, 0x057a,  0x0b3c, 0x0586,  0x0b3e, 0x058e,
+	0x0b56, 0x0592,  0x0b57, 0x0596,  0x0bbe, 0x059a,  0x0bd7, 0x05a0,
+	0x0c56, 0x05a6,  0x0cc2, 0x05aa,  0x0cd5, 0x05ae,  0x0cd6, 0x05b4,
+	0x0d3e, 0x05b8,  0x0d57, 0x05be,  0x0e32, 0x05c2,  0x0eb2, 0x05c6,
+	0x0f71, 0x05ca,  0x0f80, 0x05d2,  0x0fb5, 0x05d8,  0x0fb7, 0x05de,
+	0x1100, 0x00a2,  0x1101, 0x00a2,  0x1102, 0x00a2,  0x1103, 0x00a2,
+	0x1104, 0x00a2,  0x1105, 0x00a2,  0x1106, 0x00a2,  0x1107, 0x00a2,
+	0x1108, 0x00a2,  0x1109, 0x00a2,  0x110a, 0x00a2,  0x110b, 0x00a2,
+	0x110c, 0x00a2,  0x110d, 0x00a2,  0x110e, 0x00a2,  0x110f, 0x00a2,
+	0x1110, 0x00a2,  0x1111, 0x00a2,  0x1112, 0x00a2,  0x3099, 0x05f4,
+	0x309a, 0x0656,
+	/* hangul marker */
+	0xffff, 0x0000,
+	/* 0x0300 */
+	0x0340, 0x001f,  0x0041, 0x066c,  0x0045, 0x066e,  0x0049, 0x0670,
+	0x004f, 0x0672,  0x0055, 0x0674,  0x0057, 0x0676,  0x0059, 0x0678,
+	0x0061, 0x067a,  0x0065, 0x067c,  0x0069, 0x067e,  0x006f, 0x0680,
+	0x0075, 0x0682,  0x0077, 0x0684,  0x0079, 0x0686,  0x00a8, 0x0688,
+	0x0391, 0x068a,  0x0395, 0x068c,  0x0397, 0x068e,  0x0399, 0x0690,
+	0x039f, 0x0692,  0x03a5, 0x0694,  0x03a9, 0x0696,  0x03b1, 0x0698,
+	0x03b5, 0x069a,  0x03b7, 0x069c,  0x03b9, 0x069e,  0x03bf, 0x06a0,
+	0x03c5, 0x06a2,  0x03c9, 0x06a4,  0x1fbf, 0x06a6,  0x1ffe, 0x06a8,
+	/* 0x0301 */
+	0x0341, 0x003b,  0x0041, 0x06aa,  0x0043, 0x06ac,  0x0045, 0x06ae,
+	0x0047, 0x06b0,  0x0049, 0x06b2,  0x004b, 0x06b4,  0x004c, 0x06b6,
+	0x004d, 0x06b8,  0x004e, 0x06ba,  0x004f, 0x06bc,  0x0050, 0x06be,
+	0x0052, 0x06c0,  0x0053, 0x06c2,  0x0055, 0x06c6,  0x0057, 0x06c8,
+	0x0059, 0x06ca,  0x005a, 0x06cc,  0x0061, 0x06ce,  0x0063, 0x06d0,
+	0x0065, 0x06d2,  0x0067, 0x06d4,  0x0069, 0x06d6,  0x006b, 0x06d8,
+	0x006c, 0x06da,  0x006d, 0x06dc,  0x006e, 0x06de,  0x006f, 0x06e0,
+	0x0070, 0x06e2,  0x0072, 0x06e4,  0x0073, 0x06e6,  0x0075, 0x06ea,
+	0x0077, 0x06ec,  0x0079, 0x06ee,  0x007a, 0x06f0,  0x00a8, 0x06f2,
+	0x00c6, 0x06f4,  0x00d8, 0x06f6,  0x00e6, 0x06f8,  0x00f8, 0x06fa,
+	0x0391, 0x06fc,  0x0395, 0x06fe,  0x0397, 0x0700,  0x0399, 0x0702,
+	0x039f, 0x0704,  0x03a5, 0x0706,  0x03a9, 0x0708,  0x03b1, 0x070a,
+	0x03b5, 0x070c,  0x03b7, 0x070e,  0x03b9, 0x0710,  0x03bf, 0x0712,
+	0x03c5, 0x0714,  0x03c9, 0x0716,  0x0413, 0x0718,  0x041a, 0x071a,
+	0x0433, 0x071c,  0x043a, 0x071e,  0x1fbf, 0x0720,  0x1ffe, 0x0722,
+	/* 0x0302 */
+	0x0000, 0x001a,  0x0041, 0x0724,  0x0043, 0x072e,  0x0045, 0x0730,
+	0x0047, 0x073a,  0x0048, 0x073c,  0x0049, 0x073e,  0x004a, 0x0740,
+	0x004f, 0x0742,  0x0053, 0x074c,  0x0055, 0x074e,  0x0057, 0x0750,
+	0x0059, 0x0752,  0x005a, 0x0754,  0x0061, 0x0756,  0x0063, 0x0760,
+	0x0065, 0x0762,  0x0067, 0x076c,  0x0068, 0x076e,  0x0069, 0x0770,
+	0x006a, 0x0772,  0x006f, 0x0774,  0x0073, 0x077e,  0x0075, 0x0780,
+	0x0077, 0x0782,  0x0079, 0x0784,  0x007a, 0x0786,
+	/* 0x0303 */
+	0x0000, 0x0010,  0x0041, 0x0788,  0x0045, 0x078a,  0x0049, 0x078c,
+	0x004e, 0x078e,  0x004f, 0x0790,  0x0055, 0x0796,  0x0056, 0x079a,
+	0x0059, 0x079c,  0x0061, 0x079e,  0x0065, 0x07a0,  0x0069, 0x07a2,
+	0x006e, 0x07a4,  0x006f, 0x07a6,  0x0075, 0x07ac,  0x0076, 0x07b0,
+	0x0079, 0x07b2,
+	/* 0x0304 */
+	0x0000, 0x0018,  0x0041, 0x07b4,  0x0045, 0x07b6,  0x0047, 0x07bc,
+	0x0049, 0x07be,  0x004f, 0x07c0,  0x0055, 0x07c6,  0x0061, 0x07ca,
+	0x0065, 0x07cc,  0x0067, 0x07d2,  0x0069, 0x07d4,  0x006f, 0x07d6,
+	0x0075, 0x07dc,  0x00c6, 0x07e0,  0x00e6, 0x07e2,  0x0391, 0x07e4,
+	0x0399, 0x07e6,  0x03a5, 0x07e8,  0x03b1, 0x07ea,  0x03b9, 0x07ec,
+	0x03c5, 0x07ee,  0x0418, 0x07f0,  0x0423, 0x07f2,  0x0438, 0x07f4,
+	0x0443, 0x07f6,
+	/* 0x0306 */
+	0x0000, 0x001c,  0x0041, 0x07f8,  0x0045, 0x0802,  0x0047, 0x0804,
+	0x0049, 0x0806,  0x004f, 0x0808,  0x0055, 0x080a,  0x0061, 0x080c,
+	0x0065, 0x0816,  0x0067, 0x0818,  0x0069, 0x081a,  0x006f, 0x081c,
+	0x0075, 0x081e,  0x0391, 0x0820,  0x0399, 0x0822,  0x03a5, 0x0824,
+	0x03b1, 0x0826,  0x03b9, 0x0828,  0x03c5, 0x082a,  0x0410, 0x082c,
+	0x0415, 0x082e,  0x0416, 0x0830,  0x0418, 0x0832,  0x0423, 0x0834,
+	0x0430, 0x0836,  0x0435, 0x0838,  0x0436, 0x083a,  0x0438, 0x083c,
+	0x0443, 0x083e,
+	/* 0x0307 */
+	0x0000, 0x0027,  0x0041, 0x0840,  0x0042, 0x0844,  0x0043, 0x0846,
+	0x0044, 0x0848,  0x0045, 0x084a,  0x0046, 0x084c,  0x0047, 0x084e,
+	0x0048, 0x0850,  0x0049, 0x0852,  0x004d, 0x0854,  0x004e, 0x0856,
+	0x0050, 0x0858,  0x0052, 0x085a,  0x0053, 0x085c,  0x0054, 0x085e,
+	0x0057, 0x0860,  0x0058, 0x0862,  0x0059, 0x0864,  0x005a, 0x0866,
+	0x0061, 0x0868,  0x0062, 0x086c,  0x0063, 0x086e,  0x0064, 0x0870,
+	0x0065, 0x0872,  0x0066, 0x0874,  0x0067, 0x0876,  0x0068, 0x0878,
+	0x006d, 0x087a,  0x006e, 0x087c,  0x0070, 0x087e,  0x0072, 0x0880,
+	0x0073, 0x0882,  0x0074, 0x0884,  0x0077, 0x0886,  0x0078, 0x0888,
+	0x0079, 0x088a,  0x007a, 0x088c,  0x017f, 0x088e,  0x0306, 0x0890,
+	/* 0x0308 */
+	0x0000, 0x0030,  0x0041, 0x0892,  0x0045, 0x0896,  0x0048, 0x0898,
+	0x0049, 0x089a,  0x004f, 0x089e,  0x0055, 0x08a0,  0x0057, 0x08aa,
+	0x0058, 0x08ac,  0x0059, 0x08ae,  0x0061, 0x08b0,  0x0065, 0x08b4,
+	0x0068, 0x08b6,  0x0069, 0x08b8,  0x006f, 0x08bc,  0x0074, 0x08be,
+	0x0075, 0x08c0,  0x0077, 0x08ca,  0x0078, 0x08cc,  0x0079, 0x08ce,
+	0x018f, 0x08d0,  0x019f, 0x08d2,  0x0259, 0x08d4,  0x0275, 0x08d6,
+	0x0399, 0x08d8,  0x03a5, 0x08da,  0x03b9, 0x08dc,  0x03c5, 0x08e6,
+	0x03d2, 0x08f0,  0x0406, 0x08f2,  0x0410, 0x08f4,  0x0415, 0x08f6,
+	0x0416, 0x08f8,  0x0417, 0x08fa,  0x0418, 0x08fc,  0x041e, 0x08fe,
+	0x0423, 0x0900,  0x0427, 0x0902,  0x042b, 0x0904,  0x0430, 0x0906,
+	0x0435, 0x0908,  0x0436, 0x090a,  0x0437, 0x090c,  0x0438, 0x090e,
+	0x043e, 0x0910,  0x0443, 0x0912,  0x0447, 0x0914,  0x044b, 0x0916,
+	0x0456, 0x0918,
+	/* 0x0309 */
+	0x0000, 0x000c,  0x0041, 0x091a,  0x0045, 0x091c,  0x0049, 0x091e,
+	0x004f, 0x0920,  0x0055, 0x0922,  0x0059, 0x0924,  0x0061, 0x0926,
+	0x0065, 0x0928,  0x0069, 0x092a,  0x006f, 0x092c,  0x0075, 0x092e,
+	0x0079, 0x0930,
+	/* 0x030a */
+	0x0000, 0x0006,  0x0041, 0x0932,  0x0055, 0x0936,  0x0061, 0x0938,
+	0x0075, 0x093c,  0x0077, 0x093e,  0x0079, 0x0940,
+	/* 0x030b */
+	0x0000, 0x0006,  0x004f, 0x0942,  0x0055, 0x0944,  0x006f, 0x0946,
+	0x0075, 0x0948,  0x0423, 0x094a,  0x0443, 0x094c,
+	/* 0x030c */
+	0x0000, 0x0021,  0x0041, 0x094e,  0x0043, 0x0950,  0x0044, 0x0952,
+	0x0045, 0x0954,  0x0047, 0x0956,  0x0049, 0x0958,  0x004b, 0x095a,
+	0x004c, 0x095c,  0x004e, 0x095e,  0x004f, 0x0960,  0x0052, 0x0962,
+	0x0053, 0x0964,  0x0054, 0x0968,  0x0055, 0x096a,  0x005a, 0x096c,
+	0x0061, 0x096e,  0x0063, 0x0970,  0x0064, 0x0972,  0x0065, 0x0974,
+	0x0067, 0x0976,  0x0069, 0x0978,  0x006a, 0x097a,  0x006b, 0x097c,
+	0x006c, 0x097e,  0x006e, 0x0980,  0x006f, 0x0982,  0x0072, 0x0984,
+	0x0073, 0x0986,  0x0074, 0x098a,  0x0075, 0x098c,  0x007a, 0x098e,
+	0x01b7, 0x0990,  0x0292, 0x0992,
+	/* 0x030d */
+	0x0000, 0x0011,  0x00a8, 0x0994,  0x0308, 0x0996,  0x0391, 0x0998,
+	0x0395, 0x099a,  0x0397, 0x099c,  0x0399, 0x099e,  0x039f, 0x09a0,
+	0x03a5, 0x09a2,  0x03a9, 0x09a4,  0x03b1, 0x09a6,  0x03b5, 0x09a8,
+	0x03b7, 0x09aa,  0x03b9, 0x09ac,  0x03bf, 0x09ae,  0x03c5, 0x09b0,
+	0x03c9, 0x09b2,  0x03d2, 0x09b4,
+	/* 0x030f */
+	0x0000, 0x000e,  0x0041, 0x09b6,  0x0045, 0x09b8,  0x0049, 0x09ba,
+	0x004f, 0x09bc,  0x0052, 0x09be,  0x0055, 0x09c0,  0x0061, 0x09c2,
+	0x0065, 0x09c4,  0x0069, 0x09c6,  0x006f, 0x09c8,  0x0072, 0x09ca,
+	0x0075, 0x09cc,  0x0474, 0x09ce,  0x0475, 0x09d0,
+	/* 0x0311 */
+	0x0000, 0x000c,  0x0041, 0x09d2,  0x0045, 0x09d4,  0x0049, 0x09d6,
+	0x004f, 0x09d8,  0x0052, 0x09da,  0x0055, 0x09dc,  0x0061, 0x09de,
+	0x0065, 0x09e0,  0x0069, 0x09e2,  0x006f, 0x09e4,  0x0072, 0x09e6,
+	0x0075, 0x09e8,
+	/* 0x0313 */
+	0x0343, 0x000e,  0x0391, 0x09ea,  0x0395, 0x09f2,  0x0397, 0x09f8,
+	0x0399, 0x0a00,  0x039f, 0x0a08,  0x03a9, 0x0a0e,  0x03b1, 0x0a16,
+	0x03b5, 0x0a1e,  0x03b7, 0x0a24,  0x03b9, 0x0a2c,  0x03bf, 0x0a34,
+	0x03c1, 0x0a3a,  0x03c5, 0x0a3c,  0x03c9, 0x0a44,
+	/* 0x0314 */
+	0x0000, 0x0010,  0x0391, 0x0a4c,  0x0395, 0x0a54,  0x0397, 0x0a5a,
+	0x0399, 0x0a62,  0x039f, 0x0a6a,  0x03a1, 0x0a70,  0x03a5, 0x0a72,
+	0x03a9, 0x0a7a,  0x03b1, 0x0a82,  0x03b5, 0x0a8a,  0x03b7, 0x0a90,
+	0x03b9, 0x0a98,  0x03bf, 0x0aa0,  0x03c1, 0x0aa6,  0x03c5, 0x0aa8,
+	0x03c9, 0x0ab0,
+	/* 0x031b */
+	0x0000, 0x0004,  0x004f, 0x0ab8,  0x0055, 0x0ac4,  0x006f, 0x0ad0,
+	0x0075, 0x0adc,
+	/* 0x0323 */
+	0x0000, 0x0026,  0x0041, 0x0ae8,  0x0042, 0x0aee,  0x0044, 0x0af0,
+	0x0045, 0x0af2,  0x0048, 0x0af6,  0x0049, 0x0af8,  0x004b, 0x0afa,
+	0x004c, 0x0afc,  0x004d, 0x0b00,  0x004e, 0x0b02,  0x004f, 0x0b04,
+	0x0052, 0x0b08,  0x0053, 0x0b0c,  0x0054, 0x0b10,  0x0055, 0x0b12,
+	0x0056, 0x0b14,  0x0057, 0x0b16,  0x0059, 0x0b18,  0x005a, 0x0b1a,
+	0x0061, 0x0b1c,  0x0062, 0x0b22,  0x0064, 0x0b24,  0x0065, 0x0b26,
+	0x0068, 0x0b2a,  0x0069, 0x0b2c,  0x006b, 0x0b2e,  0x006c, 0x0b30,
+	0x006d, 0x0b34,  0x006e, 0x0b36,  0x006f, 0x0b38,  0x0072, 0x0b3c,
+	0x0073, 0x0b40,  0x0074, 0x0b44,  0x0075, 0x0b46,  0x0076, 0x0b48,
+	0x0077, 0x0b4a,  0x0079, 0x0b4c,  0x007a, 0x0b4e,
+	/* 0x0324 */
+	0x0000, 0x0002,  0x0055, 0x0b50,  0x0075, 0x0b52,
+	/* 0x0325 */
+	0x0000, 0x0002,  0x0041, 0x0b54,  0x0061, 0x0b56,
+	/* 0x0327 */
+	0x0000, 0x0016,  0x0043, 0x0b58,  0x0044, 0x0b5c,  0x0045, 0x0b5e,
+	0x0047, 0x0b62,  0x0048, 0x0b64,  0x004b, 0x0b66,  0x004c, 0x0b68,
+	0x004e, 0x0b6a,  0x0052, 0x0b6c,  0x0053, 0x0b6e,  0x0054, 0x0b70,
+	0x0063, 0x0b72,  0x0064, 0x0b76,  0x0065, 0x0b78,  0x0067, 0x0b7c,
+	0x0068, 0x0b7e,  0x006b, 0x0b80,  0x006c, 0x0b82,  0x006e, 0x0b84,
+	0x0072, 0x0b86,  0x0073, 0x0b88,  0x0074, 0x0b8a,
+	/* 0x0328 */
+	0x0000, 0x000a,  0x0041, 0x0b8c,  0x0045, 0x0b8e,  0x0049, 0x0b90,
+	0x004f, 0x0b92,  0x0055, 0x0b96,  0x0061, 0x0b98,  0x0065, 0x0b9a,
+	0x0069, 0x0b9c,  0x006f, 0x0b9e,  0x0075, 0x0ba2,
+	/* 0x032d */
+	0x0000, 0x000c,  0x0044, 0x0ba4,  0x0045, 0x0ba6,  0x004c, 0x0ba8,
+	0x004e, 0x0baa,  0x0054, 0x0bac,  0x0055, 0x0bae,  0x0064, 0x0bb0,
+	0x0065, 0x0bb2,  0x006c, 0x0bb4,  0x006e, 0x0bb6,  0x0074, 0x0bb8,
+	0x0075, 0x0bba,
+	/* 0x032e */
+	0x0000, 0x0002,  0x0048, 0x0bbc,  0x0068, 0x0bbe,
+	/* 0x0330 */
+	0x0000, 0x0006,  0x0045, 0x0bc0,  0x0049, 0x0bc2,  0x0055, 0x0bc4,
+	0x0065, 0x0bc6,  0x0069, 0x0bc8,  0x0075, 0x0bca,
+	/* 0x0331 */
+	0x0000, 0x0011,  0x0042, 0x0bcc,  0x0044, 0x0bce,  0x004b, 0x0bd0,
+	0x004c, 0x0bd2,  0x004e, 0x0bd4,  0x0052, 0x0bd6,  0x0054, 0x0bd8,
+	0x005a, 0x0bda,  0x0062, 0x0bdc,  0x0064, 0x0bde,  0x0068, 0x0be0,
+	0x006b, 0x0be2,  0x006c, 0x0be4,  0x006e, 0x0be6,  0x0072, 0x0be8,
+	0x0074, 0x0bea,  0x007a, 0x0bec,
+	/* 0x0342 */
+	0x0000, 0x0008,  0x00a8, 0x0bee,  0x03b1, 0x0bf0,  0x03b7, 0x0bf2,
+	0x03b9, 0x0bf4,  0x03c5, 0x0bf6,  0x03c9, 0x0bf8,  0x1fbf, 0x0bfa,
+	0x1ffe, 0x0bfc,
+	/* 0x0345 */
+	0x0000, 0x0007,  0x0391, 0x0bfe,  0x0397, 0x0c04,  0x03a9, 0x0c0a,
+	0x03b1, 0x0c10,  0x03b7, 0x0c1c,  0x03bf, 0x0c28,  0x03c9, 0x0c2c,
+	/* 0x05b7 */
+	0x0000, 0x0002,  0x05d0, 0x0c36,  0x05f2, 0x0c38,
+	/* 0x05b8 */
+	0x0000, 0x0001,  0x05d0, 0x0c3a,
+	/* 0x05b9 */
+	0x0000, 0x0001,  0x05d5, 0x0c3c,
+	/* 0x05bc */
+	0x0000, 0x0016,  0x05d0, 0x0c3e,  0x05d1, 0x0c40,  0x05d2, 0x0c42,
+	0x05d3, 0x0c44,  0x05d4, 0x0c46,  0x05d5, 0x0c48,  0x05d6, 0x0c4a,
+	0x05d8, 0x0c4c,  0x05d9, 0x0c4e,  0x05da, 0x0c50,  0x05db, 0x0c52,
+	0x05dc, 0x0c54,  0x05de, 0x0c56,  0x05e0, 0x0c58,  0x05e1, 0x0c5a,
+	0x05e3, 0x0c5c,  0x05e4, 0x0c5e,  0x05e6, 0x0c60,  0x05e7, 0x0c62,
+	0x05e8, 0x0c64,  0x05e9, 0x0c66,  0x05ea, 0x0c6c,
+	/* 0x05bf */
+	0x0000, 0x0003,  0x05d1, 0x0c6e,  0x05db, 0x0c70,  0x05e4, 0x0c72,
+	/* 0x05c1 */
+	0x0000, 0x0001,  0x05e9, 0x0c74,
+	/* 0x05c2 */
+	0x0000, 0x0001,  0x05e9, 0x0c76,
+	/* 0x093c */
+	0x0000, 0x000b,  0x0915, 0x0c78,  0x0916, 0x0c7a,  0x0917, 0x0c7c,
+	0x091c, 0x0c7e,  0x0921, 0x0c80,  0x0922, 0x0c82,  0x0928, 0x0c84,
+	0x092b, 0x0c86,  0x092f, 0x0c88,  0x0930, 0x0c8a,  0x0933, 0x0c8c,
+	/* 0x09bc */
+	0x0000, 0x0004,  0x09a1, 0x0c8e,  0x09a2, 0x0c90,  0x09ac, 0x0c92,
+	0x09af, 0x0c94,
+	/* 0x09be */
+	0x0000, 0x0001,  0x09c7, 0x0c96,
+	/* 0x09d7 */
+	0x0000, 0x0001,  0x09c7, 0x0c98,
+	/* 0x0a3c */
+	0x0000, 0x0005,  0x0a16, 0x0c9a,  0x0a17, 0x0c9c,  0x0a1c, 0x0c9e,
+	0x0a21, 0x0ca0,  0x0a2b, 0x0ca2,
+	/* 0x0b3c */
+	0x0000, 0x0003,  0x0b21, 0x0ca4,  0x0b22, 0x0ca6,  0x0b2f, 0x0ca8,
+	/* 0x0b3e */
+	0x0000, 0x0001,  0x0b47, 0x0caa,
+	/* 0x0b56 */
+	0x0000, 0x0001,  0x0b47, 0x0cac,
+	/* 0x0b57 */
+	0x0000, 0x0001,  0x0b47, 0x0cae,
+	/* 0x0bbe */
+	0x0000, 0x0002,  0x0bc6, 0x0cb0,  0x0bc7, 0x0cb2,
+	/* 0x0bd7 */
+	0x0000, 0x0002,  0x0b92, 0x0cb4,  0x0bc6, 0x0cb6,
+	/* 0x0c56 */
+	0x0000, 0x0001,  0x0c46, 0x0cb8,
+	/* 0x0cc2 */
+	0x0000, 0x0001,  0x0cc6, 0x0cba,
+	/* 0x0cd5 */
+	0x0000, 0x0002,  0x0cbf, 0x0cbe,  0x0cc6, 0x0cc0,
+	/* 0x0cd6 */
+	0x0000, 0x0001,  0x0cc6, 0x0cc2,
+	/* 0x0d3e */
+	0x0000, 0x0002,  0x0d46, 0x0cc4,  0x0d47, 0x0cc6,
+	/* 0x0d57 */
+	0x0000, 0x0001,  0x0d46, 0x0cc8,
+	/* 0x0e32 */
+	0x0000, 0x0001,  0x0e4d, 0x0cca,
+	/* 0x0eb2 */
+	0x0000, 0x0001,  0x0ecd, 0x0ccc,
+	/* 0x0f71 */
+	0x0000, 0x0003,  0x0f72, 0x0cce,  0x0f74, 0x0cd0,  0x0f80, 0x0cd2,
+	/* 0x0f80 */
+	0x0000, 0x0002,  0x0fb2, 0x0cd4,  0x0fb3, 0x0cd8,
+	/* 0x0fb5 */
+	0x0000, 0x0002,  0x0f40, 0x0cdc,  0x0f90, 0x0cde,
+	/* 0x0fb7 */
+	0x0000, 0x000a,  0x0f42, 0x0ce0,  0x0f4c, 0x0ce2,  0x0f51, 0x0ce4,
+	0x0f56, 0x0ce6,  0x0f5b, 0x0ce8,  0x0f92, 0x0cea,  0x0f9c, 0x0cec,
+	0x0fa1, 0x0cee,  0x0fa6, 0x0cf0,  0x0fab, 0x0cf2,
+	/* 0x3099 */
+	0x0000, 0x0030,  0x3046, 0x0cf4,  0x304b, 0x0cf6,  0x304d, 0x0cf8,
+	0x304f, 0x0cfa,  0x3051, 0x0cfc,  0x3053, 0x0cfe,  0x3055, 0x0d00,
+	0x3057, 0x0d02,  0x3059, 0x0d04,  0x305b, 0x0d06,  0x305d, 0x0d08,
+	0x305f, 0x0d0a,  0x3061, 0x0d0c,  0x3064, 0x0d0e,  0x3066, 0x0d10,
+	0x3068, 0x0d12,  0x306f, 0x0d14,  0x3072, 0x0d16,  0x3075, 0x0d18,
+	0x3078, 0x0d1a,  0x307b, 0x0d1c,  0x309d, 0x0d1e,  0x30a6, 0x0d20,
+	0x30ab, 0x0d22,  0x30ad, 0x0d24,  0x30af, 0x0d26,  0x30b1, 0x0d28,
+	0x30b3, 0x0d2a,  0x30b5, 0x0d2c,  0x30b7, 0x0d2e,  0x30b9, 0x0d30,
+	0x30bb, 0x0d32,  0x30bd, 0x0d34,  0x30bf, 0x0d36,  0x30c1, 0x0d38,
+	0x30c4, 0x0d3a,  0x30c6, 0x0d3c,  0x30c8, 0x0d3e,  0x30cf, 0x0d40,
+	0x30d2, 0x0d42,  0x30d5, 0x0d44,  0x30d8, 0x0d46,  0x30db, 0x0d48,
+	0x30ef, 0x0d4a,  0x30f0, 0x0d4c,  0x30f1, 0x0d4e,  0x30f2, 0x0d50,
+	0x30fd, 0x0d52,
+	/* 0x309a */
+	0x0000, 0x000a,  0x306f, 0x0d54,  0x3072, 0x0d56,  0x3075, 0x0d58,
+	0x3078, 0x0d5a,  0x307b, 0x0d5c,  0x30cf, 0x0d5e,  0x30d2, 0x0d60,
+	0x30d5, 0x0d62,  0x30d8, 0x0d64,  0x30db, 0x0d66,
+	/* 0x0041 0x0300 */
+	0x00c0, 0x0000,
+	/* 0x0045 0x0300 */
+	0x00c8, 0x0000,
+	/* 0x0049 0x0300 */
+	0x00cc, 0x0000,
+	/* 0x004f 0x0300 */
+	0x00d2, 0x0000,
+	/* 0x0055 0x0300 */
+	0x00d9, 0x0000,
+	/* 0x0057 0x0300 */
+	0x1e80, 0x0000,
+	/* 0x0059 0x0300 */
+	0x1ef2, 0x0000,
+	/* 0x0061 0x0300 */
+	0x00e0, 0x0000,
+	/* 0x0065 0x0300 */
+	0x00e8, 0x0000,
+	/* 0x0069 0x0300 */
+	0x00ec, 0x0000,
+	/* 0x006f 0x0300 */
+	0x00f2, 0x0000,
+	/* 0x0075 0x0300 */
+	0x00f9, 0x0000,
+	/* 0x0077 0x0300 */
+	0x1e81, 0x0000,
+	/* 0x0079 0x0300 */
+	0x1ef3, 0x0000,
+	/* 0x00a8 0x0300 */
+	0x1fed, 0x0000,
+	/* 0x0391 0x0300 */
+	0x1fba, 0x0000,
+	/* 0x0395 0x0300 */
+	0x1fc8, 0x0000,
+	/* 0x0397 0x0300 */
+	0x1fca, 0x0000,
+	/* 0x0399 0x0300 */
+	0x1fda, 0x0000,
+	/* 0x039f 0x0300 */
+	0x1ff8, 0x0000,
+	/* 0x03a5 0x0300 */
+	0x1fea, 0x0000,
+	/* 0x03a9 0x0300 */
+	0x1ffa, 0x0000,
+	/* 0x03b1 0x0300 */
+	0x1f70, 0x0000,
+	/* 0x03b5 0x0300 */
+	0x1f72, 0x0000,
+	/* 0x03b7 0x0300 */
+	0x1f74, 0x0000,
+	/* 0x03b9 0x0300 */
+	0x1f76, 0x0000,
+	/* 0x03bf 0x0300 */
+	0x1f78, 0x0000,
+	/* 0x03c5 0x0300 */
+	0x1f7a, 0x0000,
+	/* 0x03c9 0x0300 */
+	0x1f7c, 0x0000,
+	/* 0x1fbf 0x0300 */
+	0x1fcd, 0x0000,
+	/* 0x1ffe 0x0300 */
+	0x1fdd, 0x0000,
+	/* 0x0041 0x0301 */
+	0x00c1, 0x0000,
+	/* 0x0043 0x0301 */
+	0x0106, 0x0000,
+	/* 0x0045 0x0301 */
+	0x00c9, 0x0000,
+	/* 0x0047 0x0301 */
+	0x01f4, 0x0000,
+	/* 0x0049 0x0301 */
+	0x00cd, 0x0000,
+	/* 0x004b 0x0301 */
+	0x1e30, 0x0000,
+	/* 0x004c 0x0301 */
+	0x0139, 0x0000,
+	/* 0x004d 0x0301 */
+	0x1e3e, 0x0000,
+	/* 0x004e 0x0301 */
+	0x0143, 0x0000,
+	/* 0x004f 0x0301 */
+	0x00d3, 0x0000,
+	/* 0x0050 0x0301 */
+	0x1e54, 0x0000,
+	/* 0x0052 0x0301 */
+	0x0154, 0x0000,
+	/* 0x0053 0x0301 */
+	0x015a, 0x0001,  0x0307, 0x0d68,
+	/* 0x0055 0x0301 */
+	0x00da, 0x0000,
+	/* 0x0057 0x0301 */
+	0x1e82, 0x0000,
+	/* 0x0059 0x0301 */
+	0x00dd, 0x0000,
+	/* 0x005a 0x0301 */
+	0x0179, 0x0000,
+	/* 0x0061 0x0301 */
+	0x00e1, 0x0000,
+	/* 0x0063 0x0301 */
+	0x0107, 0x0000,
+	/* 0x0065 0x0301 */
+	0x00e9, 0x0000,
+	/* 0x0067 0x0301 */
+	0x01f5, 0x0000,
+	/* 0x0069 0x0301 */
+	0x00ed, 0x0000,
+	/* 0x006b 0x0301 */
+	0x1e31, 0x0000,
+	/* 0x006c 0x0301 */
+	0x013a, 0x0000,
+	/* 0x006d 0x0301 */
+	0x1e3f, 0x0000,
+	/* 0x006e 0x0301 */
+	0x0144, 0x0000,
+	/* 0x006f 0x0301 */
+	0x00f3, 0x0000,
+	/* 0x0070 0x0301 */
+	0x1e55, 0x0000,
+	/* 0x0072 0x0301 */
+	0x0155, 0x0000,
+	/* 0x0073 0x0301 */
+	0x015b, 0x0001,  0x0307, 0x0d6a,
+	/* 0x0075 0x0301 */
+	0x00fa, 0x0000,
+	/* 0x0077 0x0301 */
+	0x1e83, 0x0000,
+	/* 0x0079 0x0301 */
+	0x00fd, 0x0000,
+	/* 0x007a 0x0301 */
+	0x017a, 0x0000,
+	/* 0x00a8 0x0301 */
+	0x1fee, 0x0000,
+	/* 0x00c6 0x0301 */
+	0x01fc, 0x0000,
+	/* 0x00d8 0x0301 */
+	0x01fe, 0x0000,
+	/* 0x00e6 0x0301 */
+	0x01fd, 0x0000,
+	/* 0x00f8 0x0301 */
+	0x01ff, 0x0000,
+	/* 0x0391 0x0301 */
+	0x1fbb, 0x0000,
+	/* 0x0395 0x0301 */
+	0x1fc9, 0x0000,
+	/* 0x0397 0x0301 */
+	0x1fcb, 0x0000,
+	/* 0x0399 0x0301 */
+	0x1fdb, 0x0000,
+	/* 0x039f 0x0301 */
+	0x1ff9, 0x0000,
+	/* 0x03a5 0x0301 */
+	0x1feb, 0x0000,
+	/* 0x03a9 0x0301 */
+	0x1ffb, 0x0000,
+	/* 0x03b1 0x0301 */
+	0x1f71, 0x0000,
+	/* 0x03b5 0x0301 */
+	0x1f73, 0x0000,
+	/* 0x03b7 0x0301 */
+	0x1f75, 0x0000,
+	/* 0x03b9 0x0301 */
+	0x1f77, 0x0000,
+	/* 0x03bf 0x0301 */
+	0x1f79, 0x0000,
+	/* 0x03c5 0x0301 */
+	0x1f7b, 0x0000,
+	/* 0x03c9 0x0301 */
+	0x1f7d, 0x0000,
+	/* 0x0413 0x0301 */
+	0x0403, 0x0000,
+	/* 0x041a 0x0301 */
+	0x040c, 0x0000,
+	/* 0x0433 0x0301 */
+	0x0453, 0x0000,
+	/* 0x043a 0x0301 */
+	0x045c, 0x0000,
+	/* 0x1fbf 0x0301 */
+	0x1fce, 0x0000,
+	/* 0x1ffe 0x0301 */
+	0x1fde, 0x0000,
+	/* 0x0041 0x0302 */
+	0x00c2, 0x0004,  0x0300, 0x0d6c,  0x0301, 0x0d6e,  0x0303, 0x0d70,
+	0x0309, 0x0d72,
+	/* 0x0043 0x0302 */
+	0x0108, 0x0000,
+	/* 0x0045 0x0302 */
+	0x00ca, 0x0004,  0x0300, 0x0d74,  0x0301, 0x0d76,  0x0303, 0x0d78,
+	0x0309, 0x0d7a,
+	/* 0x0047 0x0302 */
+	0x011c, 0x0000,
+	/* 0x0048 0x0302 */
+	0x0124, 0x0000,
+	/* 0x0049 0x0302 */
+	0x00ce, 0x0000,
+	/* 0x004a 0x0302 */
+	0x0134, 0x0000,
+	/* 0x004f 0x0302 */
+	0x00d4, 0x0004,  0x0300, 0x0d7c,  0x0301, 0x0d7e,  0x0303, 0x0d80,
+	0x0309, 0x0d82,
+	/* 0x0053 0x0302 */
+	0x015c, 0x0000,
+	/* 0x0055 0x0302 */
+	0x00db, 0x0000,
+	/* 0x0057 0x0302 */
+	0x0174, 0x0000,
+	/* 0x0059 0x0302 */
+	0x0176, 0x0000,
+	/* 0x005a 0x0302 */
+	0x1e90, 0x0000,
+	/* 0x0061 0x0302 */
+	0x00e2, 0x0004,  0x0300, 0x0d84,  0x0301, 0x0d86,  0x0303, 0x0d88,
+	0x0309, 0x0d8a,
+	/* 0x0063 0x0302 */
+	0x0109, 0x0000,
+	/* 0x0065 0x0302 */
+	0x00ea, 0x0004,  0x0300, 0x0d8c,  0x0301, 0x0d8e,  0x0303, 0x0d90,
+	0x0309, 0x0d92,
+	/* 0x0067 0x0302 */
+	0x011d, 0x0000,
+	/* 0x0068 0x0302 */
+	0x0125, 0x0000,
+	/* 0x0069 0x0302 */
+	0x00ee, 0x0000,
+	/* 0x006a 0x0302 */
+	0x0135, 0x0000,
+	/* 0x006f 0x0302 */
+	0x00f4, 0x0004,  0x0300, 0x0d94,  0x0301, 0x0d96,  0x0303, 0x0d98,
+	0x0309, 0x0d9a,
+	/* 0x0073 0x0302 */
+	0x015d, 0x0000,
+	/* 0x0075 0x0302 */
+	0x00fb, 0x0000,
+	/* 0x0077 0x0302 */
+	0x0175, 0x0000,
+	/* 0x0079 0x0302 */
+	0x0177, 0x0000,
+	/* 0x007a 0x0302 */
+	0x1e91, 0x0000,
+	/* 0x0041 0x0303 */
+	0x00c3, 0x0000,
+	/* 0x0045 0x0303 */
+	0x1ebc, 0x0000,
+	/* 0x0049 0x0303 */
+	0x0128, 0x0000,
+	/* 0x004e 0x0303 */
+	0x00d1, 0x0000,
+	/* 0x004f 0x0303 */
+	0x00d5, 0x0002,  0x0301, 0x0d9c,  0x0308, 0x0d9e,
+	/* 0x0055 0x0303 */
+	0x0168, 0x0001,  0x0301, 0x0da0,
+	/* 0x0056 0x0303 */
+	0x1e7c, 0x0000,
+	/* 0x0059 0x0303 */
+	0x1ef8, 0x0000,
+	/* 0x0061 0x0303 */
+	0x00e3, 0x0000,
+	/* 0x0065 0x0303 */
+	0x1ebd, 0x0000,
+	/* 0x0069 0x0303 */
+	0x0129, 0x0000,
+	/* 0x006e 0x0303 */
+	0x00f1, 0x0000,
+	/* 0x006f 0x0303 */
+	0x00f5, 0x0002,  0x0301, 0x0da2,  0x0308, 0x0da4,
+	/* 0x0075 0x0303 */
+	0x0169, 0x0001,  0x0301, 0x0da6,
+	/* 0x0076 0x0303 */
+	0x1e7d, 0x0000,
+	/* 0x0079 0x0303 */
+	0x1ef9, 0x0000,
+	/* 0x0041 0x0304 */
+	0x0100, 0x0000,
+	/* 0x0045 0x0304 */
+	0x0112, 0x0002,  0x0300, 0x0da8,  0x0301, 0x0daa,
+	/* 0x0047 0x0304 */
+	0x1e20, 0x0000,
+	/* 0x0049 0x0304 */
+	0x012a, 0x0000,
+	/* 0x004f 0x0304 */
+	0x014c, 0x0002,  0x0300, 0x0dac,  0x0301, 0x0dae,
+	/* 0x0055 0x0304 */
+	0x016a, 0x0001,  0x0308, 0x0db0,
+	/* 0x0061 0x0304 */
+	0x0101, 0x0000,
+	/* 0x0065 0x0304 */
+	0x0113, 0x0002,  0x0300, 0x0db2,  0x0301, 0x0db4,
+	/* 0x0067 0x0304 */
+	0x1e21, 0x0000,
+	/* 0x0069 0x0304 */
+	0x012b, 0x0000,
+	/* 0x006f 0x0304 */
+	0x014d, 0x0002,  0x0300, 0x0db6,  0x0301, 0x0db8,
+	/* 0x0075 0x0304 */
+	0x016b, 0x0001,  0x0308, 0x0dba,
+	/* 0x00c6 0x0304 */
+	0x01e2, 0x0000,
+	/* 0x00e6 0x0304 */
+	0x01e3, 0x0000,
+	/* 0x0391 0x0304 */
+	0x1fb9, 0x0000,
+	/* 0x0399 0x0304 */
+	0x1fd9, 0x0000,
+	/* 0x03a5 0x0304 */
+	0x1fe9, 0x0000,
+	/* 0x03b1 0x0304 */
+	0x1fb1, 0x0000,
+	/* 0x03b9 0x0304 */
+	0x1fd1, 0x0000,
+	/* 0x03c5 0x0304 */
+	0x1fe1, 0x0000,
+	/* 0x0418 0x0304 */
+	0x04e2, 0x0000,
+	/* 0x0423 0x0304 */
+	0x04ee, 0x0000,
+	/* 0x0438 0x0304 */
+	0x04e3, 0x0000,
+	/* 0x0443 0x0304 */
+	0x04ef, 0x0000,
+	/* 0x0041 0x0306 */
+	0x0102, 0x0004,  0x0300, 0x0dbc,  0x0301, 0x0dbe,  0x0303, 0x0dc0,
+	0x0309, 0x0dc2,
+	/* 0x0045 0x0306 */
+	0x0114, 0x0000,
+	/* 0x0047 0x0306 */
+	0x011e, 0x0000,
+	/* 0x0049 0x0306 */
+	0x012c, 0x0000,
+	/* 0x004f 0x0306 */
+	0x014e, 0x0000,
+	/* 0x0055 0x0306 */
+	0x016c, 0x0000,
+	/* 0x0061 0x0306 */
+	0x0103, 0x0004,  0x0300, 0x0dc4,  0x0301, 0x0dc6,  0x0303, 0x0dc8,
+	0x0309, 0x0dca,
+	/* 0x0065 0x0306 */
+	0x0115, 0x0000,
+	/* 0x0067 0x0306 */
+	0x011f, 0x0000,
+	/* 0x0069 0x0306 */
+	0x012d, 0x0000,
+	/* 0x006f 0x0306 */
+	0x014f, 0x0000,
+	/* 0x0075 0x0306 */
+	0x016d, 0x0000,
+	/* 0x0391 0x0306 */
+	0x1fb8, 0x0000,
+	/* 0x0399 0x0306 */
+	0x1fd8, 0x0000,
+	/* 0x03a5 0x0306 */
+	0x1fe8, 0x0000,
+	/* 0x03b1 0x0306 */
+	0x1fb0, 0x0000,
+	/* 0x03b9 0x0306 */
+	0x1fd0, 0x0000,
+	/* 0x03c5 0x0306 */
+	0x1fe0, 0x0000,
+	/* 0x0410 0x0306 */
+	0x04d0, 0x0000,
+	/* 0x0415 0x0306 */
+	0x04d6, 0x0000,
+	/* 0x0416 0x0306 */
+	0x04c1, 0x0000,
+	/* 0x0418 0x0306 */
+	0x0419, 0x0000,
+	/* 0x0423 0x0306 */
+	0x040e, 0x0000,
+	/* 0x0430 0x0306 */
+	0x04d1, 0x0000,
+	/* 0x0435 0x0306 */
+	0x04d7, 0x0000,
+	/* 0x0436 0x0306 */
+	0x04c2, 0x0000,
+	/* 0x0438 0x0306 */
+	0x0439, 0x0000,
+	/* 0x0443 0x0306 */
+	0x045e, 0x0000,
+	/* 0x0041 0x0307 */
+	0x0000, 0x0001,  0x0304, 0x0dcc,
+	/* 0x0042 0x0307 */
+	0x1e02, 0x0000,
+	/* 0x0043 0x0307 */
+	0x010a, 0x0000,
+	/* 0x0044 0x0307 */
+	0x1e0a, 0x0000,
+	/* 0x0045 0x0307 */
+	0x0116, 0x0000,
+	/* 0x0046 0x0307 */
+	0x1e1e, 0x0000,
+	/* 0x0047 0x0307 */
+	0x0120, 0x0000,
+	/* 0x0048 0x0307 */
+	0x1e22, 0x0000,
+	/* 0x0049 0x0307 */
+	0x0130, 0x0000,
+	/* 0x004d 0x0307 */
+	0x1e40, 0x0000,
+	/* 0x004e 0x0307 */
+	0x1e44, 0x0000,
+	/* 0x0050 0x0307 */
+	0x1e56, 0x0000,
+	/* 0x0052 0x0307 */
+	0x1e58, 0x0000,
+	/* 0x0053 0x0307 */
+	0x1e60, 0x0000,
+	/* 0x0054 0x0307 */
+	0x1e6a, 0x0000,
+	/* 0x0057 0x0307 */
+	0x1e86, 0x0000,
+	/* 0x0058 0x0307 */
+	0x1e8a, 0x0000,
+	/* 0x0059 0x0307 */
+	0x1e8e, 0x0000,
+	/* 0x005a 0x0307 */
+	0x017b, 0x0000,
+	/* 0x0061 0x0307 */
+	0x0000, 0x0001,  0x0304, 0x0dce,
+	/* 0x0062 0x0307 */
+	0x1e03, 0x0000,
+	/* 0x0063 0x0307 */
+	0x010b, 0x0000,
+	/* 0x0064 0x0307 */
+	0x1e0b, 0x0000,
+	/* 0x0065 0x0307 */
+	0x0117, 0x0000,
+	/* 0x0066 0x0307 */
+	0x1e1f, 0x0000,
+	/* 0x0067 0x0307 */
+	0x0121, 0x0000,
+	/* 0x0068 0x0307 */
+	0x1e23, 0x0000,
+	/* 0x006d 0x0307 */
+	0x1e41, 0x0000,
+	/* 0x006e 0x0307 */
+	0x1e45, 0x0000,
+	/* 0x0070 0x0307 */
+	0x1e57, 0x0000,
+	/* 0x0072 0x0307 */
+	0x1e59, 0x0000,
+	/* 0x0073 0x0307 */
+	0x1e61, 0x0000,
+	/* 0x0074 0x0307 */
+	0x1e6b, 0x0000,
+	/* 0x0077 0x0307 */
+	0x1e87, 0x0000,
+	/* 0x0078 0x0307 */
+	0x1e8b, 0x0000,
+	/* 0x0079 0x0307 */
+	0x1e8f, 0x0000,
+	/* 0x007a 0x0307 */
+	0x017c, 0x0000,
+	/* 0x017f 0x0307 */
+	0x1e9b, 0x0000,
+	/* 0x0306 0x0307 */
+	0x0310, 0x0000,
+	/* 0x0041 0x0308 */
+	0x00c4, 0x0001,  0x0304, 0x0dd0,
+	/* 0x0045 0x0308 */
+	0x00cb, 0x0000,
+	/* 0x0048 0x0308 */
+	0x1e26, 0x0000,
+	/* 0x0049 0x0308 */
+	0x00cf, 0x0001,  0x0301, 0x0dd2,
+	/* 0x004f 0x0308 */
+	0x00d6, 0x0000,
+	/* 0x0055 0x0308 */
+	0x00dc, 0x0004,  0x0300, 0x0dd4,  0x0301, 0x0dd6,  0x0304, 0x0dd8,
+	0x030c, 0x0dda,
+	/* 0x0057 0x0308 */
+	0x1e84, 0x0000,
+	/* 0x0058 0x0308 */
+	0x1e8c, 0x0000,
+	/* 0x0059 0x0308 */
+	0x0178, 0x0000,
+	/* 0x0061 0x0308 */
+	0x00e4, 0x0001,  0x0304, 0x0ddc,
+	/* 0x0065 0x0308 */
+	0x00eb, 0x0000,
+	/* 0x0068 0x0308 */
+	0x1e27, 0x0000,
+	/* 0x0069 0x0308 */
+	0x00ef, 0x0001,  0x0301, 0x0dde,
+	/* 0x006f 0x0308 */
+	0x00f6, 0x0000,
+	/* 0x0074 0x0308 */
+	0x1e97, 0x0000,
+	/* 0x0075 0x0308 */
+	0x00fc, 0x0004,  0x0300, 0x0de0,  0x0301, 0x0de2,  0x0304, 0x0de4,
+	0x030c, 0x0de6,
+	/* 0x0077 0x0308 */
+	0x1e85, 0x0000,
+	/* 0x0078 0x0308 */
+	0x1e8d, 0x0000,
+	/* 0x0079 0x0308 */
+	0x00ff, 0x0000,
+	/* 0x018f 0x0308 */
+	0x04da, 0x0000,
+	/* 0x019f 0x0308 */
+	0x04ea, 0x0000,
+	/* 0x0259 0x0308 */
+	0x04db, 0x0000,
+	/* 0x0275 0x0308 */
+	0x04eb, 0x0000,
+	/* 0x0399 0x0308 */
+	0x03aa, 0x0000,
+	/* 0x03a5 0x0308 */
+	0x03ab, 0x0000,
+	/* 0x03b9 0x0308 */
+	0x03ca, 0x0004,  0x0300, 0x0de8,  0x0301, 0x0dea,  0x030d, 0x0dec,
+	0x0342, 0x0dee,
+	/* 0x03c5 0x0308 */
+	0x03cb, 0x0004,  0x0300, 0x0df0,  0x0301, 0x0df2,  0x030d, 0x0df4,
+	0x0342, 0x0df6,
+	/* 0x03d2 0x0308 */
+	0x03d4, 0x0000,
+	/* 0x0406 0x0308 */
+	0x0407, 0x0000,
+	/* 0x0410 0x0308 */
+	0x04d2, 0x0000,
+	/* 0x0415 0x0308 */
+	0x0401, 0x0000,
+	/* 0x0416 0x0308 */
+	0x04dc, 0x0000,
+	/* 0x0417 0x0308 */
+	0x04de, 0x0000,
+	/* 0x0418 0x0308 */
+	0x04e4, 0x0000,
+	/* 0x041e 0x0308 */
+	0x04e6, 0x0000,
+	/* 0x0423 0x0308 */
+	0x04f0, 0x0000,
+	/* 0x0427 0x0308 */
+	0x04f4, 0x0000,
+	/* 0x042b 0x0308 */
+	0x04f8, 0x0000,
+	/* 0x0430 0x0308 */
+	0x04d3, 0x0000,
+	/* 0x0435 0x0308 */
+	0x0451, 0x0000,
+	/* 0x0436 0x0308 */
+	0x04dd, 0x0000,
+	/* 0x0437 0x0308 */
+	0x04df, 0x0000,
+	/* 0x0438 0x0308 */
+	0x04e5, 0x0000,
+	/* 0x043e 0x0308 */
+	0x04e7, 0x0000,
+	/* 0x0443 0x0308 */
+	0x04f1, 0x0000,
+	/* 0x0447 0x0308 */
+	0x04f5, 0x0000,
+	/* 0x044b 0x0308 */
+	0x04f9, 0x0000,
+	/* 0x0456 0x0308 */
+	0x0457, 0x0000,
+	/* 0x0041 0x0309 */
+	0x1ea2, 0x0000,
+	/* 0x0045 0x0309 */
+	0x1eba, 0x0000,
+	/* 0x0049 0x0309 */
+	0x1ec8, 0x0000,
+	/* 0x004f 0x0309 */
+	0x1ece, 0x0000,
+	/* 0x0055 0x0309 */
+	0x1ee6, 0x0000,
+	/* 0x0059 0x0309 */
+	0x1ef6, 0x0000,
+	/* 0x0061 0x0309 */
+	0x1ea3, 0x0000,
+	/* 0x0065 0x0309 */
+	0x1ebb, 0x0000,
+	/* 0x0069 0x0309 */
+	0x1ec9, 0x0000,
+	/* 0x006f 0x0309 */
+	0x1ecf, 0x0000,
+	/* 0x0075 0x0309 */
+	0x1ee7, 0x0000,
+	/* 0x0079 0x0309 */
+	0x1ef7, 0x0000,
+	/* 0x0041 0x030a */
+	0x00c5, 0x0001,  0x0301, 0x0df8,
+	/* 0x0055 0x030a */
+	0x016e, 0x0000,
+	/* 0x0061 0x030a */
+	0x00e5, 0x0001,  0x0301, 0x0dfa,
+	/* 0x0075 0x030a */
+	0x016f, 0x0000,
+	/* 0x0077 0x030a */
+	0x1e98, 0x0000,
+	/* 0x0079 0x030a */
+	0x1e99, 0x0000,
+	/* 0x004f 0x030b */
+	0x0150, 0x0000,
+	/* 0x0055 0x030b */
+	0x0170, 0x0000,
+	/* 0x006f 0x030b */
+	0x0151, 0x0000,
+	/* 0x0075 0x030b */
+	0x0171, 0x0000,
+	/* 0x0423 0x030b */
+	0x04f2, 0x0000,
+	/* 0x0443 0x030b */
+	0x04f3, 0x0000,
+	/* 0x0041 0x030c */
+	0x01cd, 0x0000,
+	/* 0x0043 0x030c */
+	0x010c, 0x0000,
+	/* 0x0044 0x030c */
+	0x010e, 0x0000,
+	/* 0x0045 0x030c */
+	0x011a, 0x0000,
+	/* 0x0047 0x030c */
+	0x01e6, 0x0000,
+	/* 0x0049 0x030c */
+	0x01cf, 0x0000,
+	/* 0x004b 0x030c */
+	0x01e8, 0x0000,
+	/* 0x004c 0x030c */
+	0x013d, 0x0000,
+	/* 0x004e 0x030c */
+	0x0147, 0x0000,
+	/* 0x004f 0x030c */
+	0x01d1, 0x0000,
+	/* 0x0052 0x030c */
+	0x0158, 0x0000,
+	/* 0x0053 0x030c */
+	0x0160, 0x0001,  0x0307, 0x0dfc,
+	/* 0x0054 0x030c */
+	0x0164, 0x0000,
+	/* 0x0055 0x030c */
+	0x01d3, 0x0000,
+	/* 0x005a 0x030c */
+	0x017d, 0x0000,
+	/* 0x0061 0x030c */
+	0x01ce, 0x0000,
+	/* 0x0063 0x030c */
+	0x010d, 0x0000,
+	/* 0x0064 0x030c */
+	0x010f, 0x0000,
+	/* 0x0065 0x030c */
+	0x011b, 0x0000,
+	/* 0x0067 0x030c */
+	0x01e7, 0x0000,
+	/* 0x0069 0x030c */
+	0x01d0, 0x0000,
+	/* 0x006a 0x030c */
+	0x01f0, 0x0000,
+	/* 0x006b 0x030c */
+	0x01e9, 0x0000,
+	/* 0x006c 0x030c */
+	0x013e, 0x0000,
+	/* 0x006e 0x030c */
+	0x0148, 0x0000,
+	/* 0x006f 0x030c */
+	0x01d2, 0x0000,
+	/* 0x0072 0x030c */
+	0x0159, 0x0000,
+	/* 0x0073 0x030c */
+	0x0161, 0x0001,  0x0307, 0x0dfe,
+	/* 0x0074 0x030c */
+	0x0165, 0x0000,
+	/* 0x0075 0x030c */
+	0x01d4, 0x0000,
+	/* 0x007a 0x030c */
+	0x017e, 0x0000,
+	/* 0x01b7 0x030c */
+	0x01ee, 0x0000,
+	/* 0x0292 0x030c */
+	0x01ef, 0x0000,
+	/* 0x00a8 0x030d */
+	0x0385, 0x0000,
+	/* 0x0308 0x030d */
+	0x0344, 0x0000,
+	/* 0x0391 0x030d */
+	0x0386, 0x0000,
+	/* 0x0395 0x030d */
+	0x0388, 0x0000,
+	/* 0x0397 0x030d */
+	0x0389, 0x0000,
+	/* 0x0399 0x030d */
+	0x038a, 0x0000,
+	/* 0x039f 0x030d */
+	0x038c, 0x0000,
+	/* 0x03a5 0x030d */
+	0x038e, 0x0000,
+	/* 0x03a9 0x030d */
+	0x038f, 0x0000,
+	/* 0x03b1 0x030d */
+	0x03ac, 0x0000,
+	/* 0x03b5 0x030d */
+	0x03ad, 0x0000,
+	/* 0x03b7 0x030d */
+	0x03ae, 0x0000,
+	/* 0x03b9 0x030d */
+	0x03af, 0x0000,
+	/* 0x03bf 0x030d */
+	0x03cc, 0x0000,
+	/* 0x03c5 0x030d */
+	0x03cd, 0x0000,
+	/* 0x03c9 0x030d */
+	0x03ce, 0x0000,
+	/* 0x03d2 0x030d */
+	0x03d3, 0x0000,
+	/* 0x0041 0x030f */
+	0x0200, 0x0000,
+	/* 0x0045 0x030f */
+	0x0204, 0x0000,
+	/* 0x0049 0x030f */
+	0x0208, 0x0000,
+	/* 0x004f 0x030f */
+	0x020c, 0x0000,
+	/* 0x0052 0x030f */
+	0x0210, 0x0000,
+	/* 0x0055 0x030f */
+	0x0214, 0x0000,
+	/* 0x0061 0x030f */
+	0x0201, 0x0000,
+	/* 0x0065 0x030f */
+	0x0205, 0x0000,
+	/* 0x0069 0x030f */
+	0x0209, 0x0000,
+	/* 0x006f 0x030f */
+	0x020d, 0x0000,
+	/* 0x0072 0x030f */
+	0x0211, 0x0000,
+	/* 0x0075 0x030f */
+	0x0215, 0x0000,
+	/* 0x0474 0x030f */
+	0x0476, 0x0000,
+	/* 0x0475 0x030f */
+	0x0477, 0x0000,
+	/* 0x0041 0x0311 */
+	0x0202, 0x0000,
+	/* 0x0045 0x0311 */
+	0x0206, 0x0000,
+	/* 0x0049 0x0311 */
+	0x020a, 0x0000,
+	/* 0x004f 0x0311 */
+	0x020e, 0x0000,
+	/* 0x0052 0x0311 */
+	0x0212, 0x0000,
+	/* 0x0055 0x0311 */
+	0x0216, 0x0000,
+	/* 0x0061 0x0311 */
+	0x0203, 0x0000,
+	/* 0x0065 0x0311 */
+	0x0207, 0x0000,
+	/* 0x0069 0x0311 */
+	0x020b, 0x0000,
+	/* 0x006f 0x0311 */
+	0x020f, 0x0000,
+	/* 0x0072 0x0311 */
+	0x0213, 0x0000,
+	/* 0x0075 0x0311 */
+	0x0217, 0x0000,
+	/* 0x0391 0x0313 */
+	0x1f08, 0x0003,  0x0300, 0x0e00,  0x0301, 0x0e02,  0x0342, 0x0e04,
+	/* 0x0395 0x0313 */
+	0x1f18, 0x0002,  0x0300, 0x0e06,  0x0301, 0x0e08,
+	/* 0x0397 0x0313 */
+	0x1f28, 0x0003,  0x0300, 0x0e0a,  0x0301, 0x0e0c,  0x0342, 0x0e0e,
+	/* 0x0399 0x0313 */
+	0x1f38, 0x0003,  0x0300, 0x0e10,  0x0301, 0x0e12,  0x0342, 0x0e14,
+	/* 0x039f 0x0313 */
+	0x1f48, 0x0002,  0x0300, 0x0e16,  0x0301, 0x0e18,
+	/* 0x03a9 0x0313 */
+	0x1f68, 0x0003,  0x0300, 0x0e1a,  0x0301, 0x0e1c,  0x0342, 0x0e1e,
+	/* 0x03b1 0x0313 */
+	0x1f00, 0x0003,  0x0300, 0x0e20,  0x0301, 0x0e22,  0x0342, 0x0e24,
+	/* 0x03b5 0x0313 */
+	0x1f10, 0x0002,  0x0300, 0x0e26,  0x0301, 0x0e28,
+	/* 0x03b7 0x0313 */
+	0x1f20, 0x0003,  0x0300, 0x0e2a,  0x0301, 0x0e2c,  0x0342, 0x0e2e,
+	/* 0x03b9 0x0313 */
+	0x1f30, 0x0003,  0x0300, 0x0e30,  0x0301, 0x0e32,  0x0342, 0x0e34,
+	/* 0x03bf 0x0313 */
+	0x1f40, 0x0002,  0x0300, 0x0e36,  0x0301, 0x0e38,
+	/* 0x03c1 0x0313 */
+	0x1fe4, 0x0000,
+	/* 0x03c5 0x0313 */
+	0x1f50, 0x0003,  0x0300, 0x0e3a,  0x0301, 0x0e3c,  0x0342, 0x0e3e,
+	/* 0x03c9 0x0313 */
+	0x1f60, 0x0003,  0x0300, 0x0e40,  0x0301, 0x0e42,  0x0342, 0x0e44,
+	/* 0x0391 0x0314 */
+	0x1f09, 0x0003,  0x0300, 0x0e46,  0x0301, 0x0e48,  0x0342, 0x0e4a,
+	/* 0x0395 0x0314 */
+	0x1f19, 0x0002,  0x0300, 0x0e4c,  0x0301, 0x0e4e,
+	/* 0x0397 0x0314 */
+	0x1f29, 0x0003,  0x0300, 0x0e50,  0x0301, 0x0e52,  0x0342, 0x0e54,
+	/* 0x0399 0x0314 */
+	0x1f39, 0x0003,  0x0300, 0x0e56,  0x0301, 0x0e58,  0x0342, 0x0e5a,
+	/* 0x039f 0x0314 */
+	0x1f49, 0x0002,  0x0300, 0x0e5c,  0x0301, 0x0e5e,
+	/* 0x03a1 0x0314 */
+	0x1fec, 0x0000,
+	/* 0x03a5 0x0314 */
+	0x1f59, 0x0003,  0x0300, 0x0e60,  0x0301, 0x0e62,  0x0342, 0x0e64,
+	/* 0x03a9 0x0314 */
+	0x1f69, 0x0003,  0x0300, 0x0e66,  0x0301, 0x0e68,  0x0342, 0x0e6a,
+	/* 0x03b1 0x0314 */
+	0x1f01, 0x0003,  0x0300, 0x0e6c,  0x0301, 0x0e6e,  0x0342, 0x0e70,
+	/* 0x03b5 0x0314 */
+	0x1f11, 0x0002,  0x0300, 0x0e72,  0x0301, 0x0e74,
+	/* 0x03b7 0x0314 */
+	0x1f21, 0x0003,  0x0300, 0x0e76,  0x0301, 0x0e78,  0x0342, 0x0e7a,
+	/* 0x03b9 0x0314 */
+	0x1f31, 0x0003,  0x0300, 0x0e7c,  0x0301, 0x0e7e,  0x0342, 0x0e80,
+	/* 0x03bf 0x0314 */
+	0x1f41, 0x0002,  0x0300, 0x0e82,  0x0301, 0x0e84,
+	/* 0x03c1 0x0314 */
+	0x1fe5, 0x0000,
+	/* 0x03c5 0x0314 */
+	0x1f51, 0x0003,  0x0300, 0x0e86,  0x0301, 0x0e88,  0x0342, 0x0e8a,
+	/* 0x03c9 0x0314 */
+	0x1f61, 0x0003,  0x0300, 0x0e8c,  0x0301, 0x0e8e,  0x0342, 0x0e90,
+	/* 0x004f 0x031b */
+	0x01a0, 0x0005,  0x0300, 0x0e92,  0x0301, 0x0e94,  0x0303, 0x0e96,
+	0x0309, 0x0e98,  0x0323, 0x0e9a,
+	/* 0x0055 0x031b */
+	0x01af, 0x0005,  0x0300, 0x0e9c,  0x0301, 0x0e9e,  0x0303, 0x0ea0,
+	0x0309, 0x0ea2,  0x0323, 0x0ea4,
+	/* 0x006f 0x031b */
+	0x01a1, 0x0005,  0x0300, 0x0ea6,  0x0301, 0x0ea8,  0x0303, 0x0eaa,
+	0x0309, 0x0eac,  0x0323, 0x0eae,
+	/* 0x0075 0x031b */
+	0x01b0, 0x0005,  0x0300, 0x0eb0,  0x0301, 0x0eb2,  0x0303, 0x0eb4,
+	0x0309, 0x0eb6,  0x0323, 0x0eb8,
+	/* 0x0041 0x0323 */
+	0x1ea0, 0x0002,  0x0302, 0x0eba,  0x0306, 0x0ebc,
+	/* 0x0042 0x0323 */
+	0x1e04, 0x0000,
+	/* 0x0044 0x0323 */
+	0x1e0c, 0x0000,
+	/* 0x0045 0x0323 */
+	0x1eb8, 0x0001,  0x0302, 0x0ebe,
+	/* 0x0048 0x0323 */
+	0x1e24, 0x0000,
+	/* 0x0049 0x0323 */
+	0x1eca, 0x0000,
+	/* 0x004b 0x0323 */
+	0x1e32, 0x0000,
+	/* 0x004c 0x0323 */
+	0x1e36, 0x0001,  0x0304, 0x0ec0,
+	/* 0x004d 0x0323 */
+	0x1e42, 0x0000,
+	/* 0x004e 0x0323 */
+	0x1e46, 0x0000,
+	/* 0x004f 0x0323 */
+	0x1ecc, 0x0001,  0x0302, 0x0ec2,
+	/* 0x0052 0x0323 */
+	0x1e5a, 0x0001,  0x0304, 0x0ec4,
+	/* 0x0053 0x0323 */
+	0x1e62, 0x0001,  0x0307, 0x0ec6,
+	/* 0x0054 0x0323 */
+	0x1e6c, 0x0000,
+	/* 0x0055 0x0323 */
+	0x1ee4, 0x0000,
+	/* 0x0056 0x0323 */
+	0x1e7e, 0x0000,
+	/* 0x0057 0x0323 */
+	0x1e88, 0x0000,
+	/* 0x0059 0x0323 */
+	0x1ef4, 0x0000,
+	/* 0x005a 0x0323 */
+	0x1e92, 0x0000,
+	/* 0x0061 0x0323 */
+	0x1ea1, 0x0002,  0x0302, 0x0ec8,  0x0306, 0x0eca,
+	/* 0x0062 0x0323 */
+	0x1e05, 0x0000,
+	/* 0x0064 0x0323 */
+	0x1e0d, 0x0000,
+	/* 0x0065 0x0323 */
+	0x1eb9, 0x0001,  0x0302, 0x0ecc,
+	/* 0x0068 0x0323 */
+	0x1e25, 0x0000,
+	/* 0x0069 0x0323 */
+	0x1ecb, 0x0000,
+	/* 0x006b 0x0323 */
+	0x1e33, 0x0000,
+	/* 0x006c 0x0323 */
+	0x1e37, 0x0001,  0x0304, 0x0ece,
+	/* 0x006d 0x0323 */
+	0x1e43, 0x0000,
+	/* 0x006e 0x0323 */
+	0x1e47, 0x0000,
+	/* 0x006f 0x0323 */
+	0x1ecd, 0x0001,  0x0302, 0x0ed0,
+	/* 0x0072 0x0323 */
+	0x1e5b, 0x0001,  0x0304, 0x0ed2,
+	/* 0x0073 0x0323 */
+	0x1e63, 0x0001,  0x0307, 0x0ed4,
+	/* 0x0074 0x0323 */
+	0x1e6d, 0x0000,
+	/* 0x0075 0x0323 */
+	0x1ee5, 0x0000,
+	/* 0x0076 0x0323 */
+	0x1e7f, 0x0000,
+	/* 0x0077 0x0323 */
+	0x1e89, 0x0000,
+	/* 0x0079 0x0323 */
+	0x1ef5, 0x0000,
+	/* 0x007a 0x0323 */
+	0x1e93, 0x0000,
+	/* 0x0055 0x0324 */
+	0x1e72, 0x0000,
+	/* 0x0075 0x0324 */
+	0x1e73, 0x0000,
+	/* 0x0041 0x0325 */
+	0x1e00, 0x0000,
+	/* 0x0061 0x0325 */
+	0x1e01, 0x0000,
+	/* 0x0043 0x0327 */
+	0x00c7, 0x0001,  0x0301, 0x0ed6,
+	/* 0x0044 0x0327 */
+	0x1e10, 0x0000,
+	/* 0x0045 0x0327 */
+	0x0000, 0x0001,  0x0306, 0x0ed8,
+	/* 0x0047 0x0327 */
+	0x0122, 0x0000,
+	/* 0x0048 0x0327 */
+	0x1e28, 0x0000,
+	/* 0x004b 0x0327 */
+	0x0136, 0x0000,
+	/* 0x004c 0x0327 */
+	0x013b, 0x0000,
+	/* 0x004e 0x0327 */
+	0x0145, 0x0000,
+	/* 0x0052 0x0327 */
+	0x0156, 0x0000,
+	/* 0x0053 0x0327 */
+	0x015e, 0x0000,
+	/* 0x0054 0x0327 */
+	0x0162, 0x0000,
+	/* 0x0063 0x0327 */
+	0x00e7, 0x0001,  0x0301, 0x0eda,
+	/* 0x0064 0x0327 */
+	0x1e11, 0x0000,
+	/* 0x0065 0x0327 */
+	0x0000, 0x0001,  0x0306, 0x0edc,
+	/* 0x0067 0x0327 */
+	0x0123, 0x0000,
+	/* 0x0068 0x0327 */
+	0x1e29, 0x0000,
+	/* 0x006b 0x0327 */
+	0x0137, 0x0000,
+	/* 0x006c 0x0327 */
+	0x013c, 0x0000,
+	/* 0x006e 0x0327 */
+	0x0146, 0x0000,
+	/* 0x0072 0x0327 */
+	0x0157, 0x0000,
+	/* 0x0073 0x0327 */
+	0x015f, 0x0000,
+	/* 0x0074 0x0327 */
+	0x0163, 0x0000,
+	/* 0x0041 0x0328 */
+	0x0104, 0x0000,
+	/* 0x0045 0x0328 */
+	0x0118, 0x0000,
+	/* 0x0049 0x0328 */
+	0x012e, 0x0000,
+	/* 0x004f 0x0328 */
+	0x01ea, 0x0001,  0x0304, 0x0ede,
+	/* 0x0055 0x0328 */
+	0x0172, 0x0000,
+	/* 0x0061 0x0328 */
+	0x0105, 0x0000,
+	/* 0x0065 0x0328 */
+	0x0119, 0x0000,
+	/* 0x0069 0x0328 */
+	0x012f, 0x0000,
+	/* 0x006f 0x0328 */
+	0x01eb, 0x0001,  0x0304, 0x0ee0,
+	/* 0x0075 0x0328 */
+	0x0173, 0x0000,
+	/* 0x0044 0x032d */
+	0x1e12, 0x0000,
+	/* 0x0045 0x032d */
+	0x1e18, 0x0000,
+	/* 0x004c 0x032d */
+	0x1e3c, 0x0000,
+	/* 0x004e 0x032d */
+	0x1e4a, 0x0000,
+	/* 0x0054 0x032d */
+	0x1e70, 0x0000,
+	/* 0x0055 0x032d */
+	0x1e76, 0x0000,
+	/* 0x0064 0x032d */
+	0x1e13, 0x0000,
+	/* 0x0065 0x032d */
+	0x1e19, 0x0000,
+	/* 0x006c 0x032d */
+	0x1e3d, 0x0000,
+	/* 0x006e 0x032d */
+	0x1e4b, 0x0000,
+	/* 0x0074 0x032d */
+	0x1e71, 0x0000,
+	/* 0x0075 0x032d */
+	0x1e77, 0x0000,
+	/* 0x0048 0x032e */
+	0x1e2a, 0x0000,
+	/* 0x0068 0x032e */
+	0x1e2b, 0x0000,
+	/* 0x0045 0x0330 */
+	0x1e1a, 0x0000,
+	/* 0x0049 0x0330 */
+	0x1e2c, 0x0000,
+	/* 0x0055 0x0330 */
+	0x1e74, 0x0000,
+	/* 0x0065 0x0330 */
+	0x1e1b, 0x0000,
+	/* 0x0069 0x0330 */
+	0x1e2d, 0x0000,
+	/* 0x0075 0x0330 */
+	0x1e75, 0x0000,
+	/* 0x0042 0x0331 */
+	0x1e06, 0x0000,
+	/* 0x0044 0x0331 */
+	0x1e0e, 0x0000,
+	/* 0x004b 0x0331 */
+	0x1e34, 0x0000,
+	/* 0x004c 0x0331 */
+	0x1e3a, 0x0000,
+	/* 0x004e 0x0331 */
+	0x1e48, 0x0000,
+	/* 0x0052 0x0331 */
+	0x1e5e, 0x0000,
+	/* 0x0054 0x0331 */
+	0x1e6e, 0x0000,
+	/* 0x005a 0x0331 */
+	0x1e94, 0x0000,
+	/* 0x0062 0x0331 */
+	0x1e07, 0x0000,
+	/* 0x0064 0x0331 */
+	0x1e0f, 0x0000,
+	/* 0x0068 0x0331 */
+	0x1e96, 0x0000,
+	/* 0x006b 0x0331 */
+	0x1e35, 0x0000,
+	/* 0x006c 0x0331 */
+	0x1e3b, 0x0000,
+	/* 0x006e 0x0331 */
+	0x1e49, 0x0000,
+	/* 0x0072 0x0331 */
+	0x1e5f, 0x0000,
+	/* 0x0074 0x0331 */
+	0x1e6f, 0x0000,
+	/* 0x007a 0x0331 */
+	0x1e95, 0x0000,
+	/* 0x00a8 0x0342 */
+	0x1fc1, 0x0000,
+	/* 0x03b1 0x0342 */
+	0x1fb6, 0x0000,
+	/* 0x03b7 0x0342 */
+	0x1fc6, 0x0000,
+	/* 0x03b9 0x0342 */
+	0x1fd6, 0x0000,
+	/* 0x03c5 0x0342 */
+	0x1fe6, 0x0000,
+	/* 0x03c9 0x0342 */
+	0x1ff6, 0x0000,
+	/* 0x1fbf 0x0342 */
+	0x1fcf, 0x0000,
+	/* 0x1ffe 0x0342 */
+	0x1fdf, 0x0000,
+	/* 0x0391 0x0345 */
+	0x1fbc, 0x0002,  0x0313, 0x0ee2,  0x0314, 0x0eea,
+	/* 0x0397 0x0345 */
+	0x1fcc, 0x0002,  0x0313, 0x0ef2,  0x0314, 0x0efa,
+	/* 0x03a9 0x0345 */
+	0x1ffc, 0x0002,  0x0313, 0x0f02,  0x0314, 0x0f0a,
+	/* 0x03b1 0x0345 */
+	0x1fb3, 0x0005,  0x0300, 0x0f12,  0x0301, 0x0f14,  0x0313, 0x0f16,
+	0x0314, 0x0f1e,  0x0342, 0x0f26,
+	/* 0x03b7 0x0345 */
+	0x1fc3, 0x0005,  0x0300, 0x0f28,  0x0301, 0x0f2a,  0x0313, 0x0f2c,
+	0x0314, 0x0f34,  0x0342, 0x0f3c,
+	/* 0x03bf 0x0345 */
+	0x0000, 0x0001,  0x0301, 0x0f3e,
+	/* 0x03c9 0x0345 */
+	0x1ff3, 0x0004,  0x0300, 0x0f40,  0x0313, 0x0f42,  0x0314, 0x0f4a,
+	0x0342, 0x0f52,
+	/* 0x05d0 0x05b7 */
+	0xfb2e, 0x0000,
+	/* 0x05f2 0x05b7 */
+	0xfb1f, 0x0000,
+	/* 0x05d0 0x05b8 */
+	0xfb2f, 0x0000,
+	/* 0x05d5 0x05b9 */
+	0xfb4b, 0x0000,
+	/* 0x05d0 0x05bc */
+	0xfb30, 0x0000,
+	/* 0x05d1 0x05bc */
+	0xfb31, 0x0000,
+	/* 0x05d2 0x05bc */
+	0xfb32, 0x0000,
+	/* 0x05d3 0x05bc */
+	0xfb33, 0x0000,
+	/* 0x05d4 0x05bc */
+	0xfb34, 0x0000,
+	/* 0x05d5 0x05bc */
+	0xfb35, 0x0000,
+	/* 0x05d6 0x05bc */
+	0xfb36, 0x0000,
+	/* 0x05d8 0x05bc */
+	0xfb38, 0x0000,
+	/* 0x05d9 0x05bc */
+	0xfb39, 0x0000,
+	/* 0x05da 0x05bc */
+	0xfb3a, 0x0000,
+	/* 0x05db 0x05bc */
+	0xfb3b, 0x0000,
+	/* 0x05dc 0x05bc */
+	0xfb3c, 0x0000,
+	/* 0x05de 0x05bc */
+	0xfb3e, 0x0000,
+	/* 0x05e0 0x05bc */
+	0xfb40, 0x0000,
+	/* 0x05e1 0x05bc */
+	0xfb41, 0x0000,
+	/* 0x05e3 0x05bc */
+	0xfb43, 0x0000,
+	/* 0x05e4 0x05bc */
+	0xfb44, 0x0000,
+	/* 0x05e6 0x05bc */
+	0xfb46, 0x0000,
+	/* 0x05e7 0x05bc */
+	0xfb47, 0x0000,
+	/* 0x05e8 0x05bc */
+	0xfb48, 0x0000,
+	/* 0x05e9 0x05bc */
+	0xfb49, 0x0002,  0x05c1, 0x0f54,  0x05c2, 0x0f56,
+	/* 0x05ea 0x05bc */
+	0xfb4a, 0x0000,
+	/* 0x05d1 0x05bf */
+	0xfb4c, 0x0000,
+	/* 0x05db 0x05bf */
+	0xfb4d, 0x0000,
+	/* 0x05e4 0x05bf */
+	0xfb4e, 0x0000,
+	/* 0x05e9 0x05c1 */
+	0xfb2a, 0x0000,
+	/* 0x05e9 0x05c2 */
+	0xfb2b, 0x0000,
+	/* 0x0915 0x093c */
+	0x0958, 0x0000,
+	/* 0x0916 0x093c */
+	0x0959, 0x0000,
+	/* 0x0917 0x093c */
+	0x095a, 0x0000,
+	/* 0x091c 0x093c */
+	0x095b, 0x0000,
+	/* 0x0921 0x093c */
+	0x095c, 0x0000,
+	/* 0x0922 0x093c */
+	0x095d, 0x0000,
+	/* 0x0928 0x093c */
+	0x0929, 0x0000,
+	/* 0x092b 0x093c */
+	0x095e, 0x0000,
+	/* 0x092f 0x093c */
+	0x095f, 0x0000,
+	/* 0x0930 0x093c */
+	0x0931, 0x0000,
+	/* 0x0933 0x093c */
+	0x0934, 0x0000,
+	/* 0x09a1 0x09bc */
+	0x09dc, 0x0000,
+	/* 0x09a2 0x09bc */
+	0x09dd, 0x0000,
+	/* 0x09ac 0x09bc */
+	0x09b0, 0x0000,
+	/* 0x09af 0x09bc */
+	0x09df, 0x0000,
+	/* 0x09c7 0x09be */
+	0x09cb, 0x0000,
+	/* 0x09c7 0x09d7 */
+	0x09cc, 0x0000,
+	/* 0x0a16 0x0a3c */
+	0x0a59, 0x0000,
+	/* 0x0a17 0x0a3c */
+	0x0a5a, 0x0000,
+	/* 0x0a1c 0x0a3c */
+	0x0a5b, 0x0000,
+	/* 0x0a21 0x0a3c */
+	0x0a5c, 0x0000,
+	/* 0x0a2b 0x0a3c */
+	0x0a5e, 0x0000,
+	/* 0x0b21 0x0b3c */
+	0x0b5c, 0x0000,
+	/* 0x0b22 0x0b3c */
+	0x0b5d, 0x0000,
+	/* 0x0b2f 0x0b3c */
+	0x0b5f, 0x0000,
+	/* 0x0b47 0x0b3e */
+	0x0b4b, 0x0000,
+	/* 0x0b47 0x0b56 */
+	0x0b48, 0x0000,
+	/* 0x0b47 0x0b57 */
+	0x0b4c, 0x0000,
+	/* 0x0bc6 0x0bbe */
+	0x0bca, 0x0000,
+	/* 0x0bc7 0x0bbe */
+	0x0bcb, 0x0000,
+	/* 0x0b92 0x0bd7 */
+	0x0b94, 0x0000,
+	/* 0x0bc6 0x0bd7 */
+	0x0bcc, 0x0000,
+	/* 0x0c46 0x0c56 */
+	0x0c48, 0x0000,
+	/* 0x0cc6 0x0cc2 */
+	0x0cca, 0x0001,  0x0cd5, 0x0f58,
+	/* 0x0cbf 0x0cd5 */
+	0x0cc0, 0x0000,
+	/* 0x0cc6 0x0cd5 */
+	0x0cc7, 0x0000,
+	/* 0x0cc6 0x0cd6 */
+	0x0cc8, 0x0000,
+	/* 0x0d46 0x0d3e */
+	0x0d4a, 0x0000,
+	/* 0x0d47 0x0d3e */
+	0x0d4b, 0x0000,
+	/* 0x0d46 0x0d57 */
+	0x0d4c, 0x0000,
+	/* 0x0e4d 0x0e32 */
+	0x0e33, 0x0000,
+	/* 0x0ecd 0x0eb2 */
+	0x0eb3, 0x0000,
+	/* 0x0f72 0x0f71 */
+	0x0f73, 0x0000,
+	/* 0x0f74 0x0f71 */
+	0x0f75, 0x0000,
+	/* 0x0f80 0x0f71 */
+	0x0f81, 0x0000,
+	/* 0x0fb2 0x0f80 */
+	0x0f76, 0x0001,  0x0f71, 0x0f5a,
+	/* 0x0fb3 0x0f80 */
+	0x0f78, 0x0001,  0x0f71, 0x0f5c,
+	/* 0x0f40 0x0fb5 */
+	0x0f69, 0x0000,
+	/* 0x0f90 0x0fb5 */
+	0x0fb9, 0x0000,
+	/* 0x0f42 0x0fb7 */
+	0x0f43, 0x0000,
+	/* 0x0f4c 0x0fb7 */
+	0x0f4d, 0x0000,
+	/* 0x0f51 0x0fb7 */
+	0x0f52, 0x0000,
+	/* 0x0f56 0x0fb7 */
+	0x0f57, 0x0000,
+	/* 0x0f5b 0x0fb7 */
+	0x0f5c, 0x0000,
+	/* 0x0f92 0x0fb7 */
+	0x0f93, 0x0000,
+	/* 0x0f9c 0x0fb7 */
+	0x0f9d, 0x0000,
+	/* 0x0fa1 0x0fb7 */
+	0x0fa2, 0x0000,
+	/* 0x0fa6 0x0fb7 */
+	0x0fa7, 0x0000,
+	/* 0x0fab 0x0fb7 */
+	0x0fac, 0x0000,
+	/* 0x3046 0x3099 */
+	0x3094, 0x0000,
+	/* 0x304b 0x3099 */
+	0x304c, 0x0000,
+	/* 0x304d 0x3099 */
+	0x304e, 0x0000,
+	/* 0x304f 0x3099 */
+	0x3050, 0x0000,
+	/* 0x3051 0x3099 */
+	0x3052, 0x0000,
+	/* 0x3053 0x3099 */
+	0x3054, 0x0000,
+	/* 0x3055 0x3099 */
+	0x3056, 0x0000,
+	/* 0x3057 0x3099 */
+	0x3058, 0x0000,
+	/* 0x3059 0x3099 */
+	0x305a, 0x0000,
+	/* 0x305b 0x3099 */
+	0x305c, 0x0000,
+	/* 0x305d 0x3099 */
+	0x305e, 0x0000,
+	/* 0x305f 0x3099 */
+	0x3060, 0x0000,
+	/* 0x3061 0x3099 */
+	0x3062, 0x0000,
+	/* 0x3064 0x3099 */
+	0x3065, 0x0000,
+	/* 0x3066 0x3099 */
+	0x3067, 0x0000,
+	/* 0x3068 0x3099 */
+	0x3069, 0x0000,
+	/* 0x306f 0x3099 */
+	0x3070, 0x0000,
+	/* 0x3072 0x3099 */
+	0x3073, 0x0000,
+	/* 0x3075 0x3099 */
+	0x3076, 0x0000,
+	/* 0x3078 0x3099 */
+	0x3079, 0x0000,
+	/* 0x307b 0x3099 */
+	0x307c, 0x0000,
+	/* 0x309d 0x3099 */
+	0x309e, 0x0000,
+	/* 0x30a6 0x3099 */
+	0x30f4, 0x0000,
+	/* 0x30ab 0x3099 */
+	0x30ac, 0x0000,
+	/* 0x30ad 0x3099 */
+	0x30ae, 0x0000,
+	/* 0x30af 0x3099 */
+	0x30b0, 0x0000,
+	/* 0x30b1 0x3099 */
+	0x30b2, 0x0000,
+	/* 0x30b3 0x3099 */
+	0x30b4, 0x0000,
+	/* 0x30b5 0x3099 */
+	0x30b6, 0x0000,
+	/* 0x30b7 0x3099 */
+	0x30b8, 0x0000,
+	/* 0x30b9 0x3099 */
+	0x30ba, 0x0000,
+	/* 0x30bb 0x3099 */
+	0x30bc, 0x0000,
+	/* 0x30bd 0x3099 */
+	0x30be, 0x0000,
+	/* 0x30bf 0x3099 */
+	0x30c0, 0x0000,
+	/* 0x30c1 0x3099 */
+	0x30c2, 0x0000,
+	/* 0x30c4 0x3099 */
+	0x30c5, 0x0000,
+	/* 0x30c6 0x3099 */
+	0x30c7, 0x0000,
+	/* 0x30c8 0x3099 */
+	0x30c9, 0x0000,
+	/* 0x30cf 0x3099 */
+	0x30d0, 0x0000,
+	/* 0x30d2 0x3099 */
+	0x30d3, 0x0000,
+	/* 0x30d5 0x3099 */
+	0x30d6, 0x0000,
+	/* 0x30d8 0x3099 */
+	0x30d9, 0x0000,
+	/* 0x30db 0x3099 */
+	0x30dc, 0x0000,
+	/* 0x30ef 0x3099 */
+	0x30f7, 0x0000,
+	/* 0x30f0 0x3099 */
+	0x30f8, 0x0000,
+	/* 0x30f1 0x3099 */
+	0x30f9, 0x0000,
+	/* 0x30f2 0x3099 */
+	0x30fa, 0x0000,
+	/* 0x30fd 0x3099 */
+	0x30fe, 0x0000,
+	/* 0x306f 0x309a */
+	0x3071, 0x0000,
+	/* 0x3072 0x309a */
+	0x3074, 0x0000,
+	/* 0x3075 0x309a */
+	0x3077, 0x0000,
+	/* 0x3078 0x309a */
+	0x307a, 0x0000,
+	/* 0x307b 0x309a */
+	0x307d, 0x0000,
+	/* 0x30cf 0x309a */
+	0x30d1, 0x0000,
+	/* 0x30d2 0x309a */
+	0x30d4, 0x0000,
+	/* 0x30d5 0x309a */
+	0x30d7, 0x0000,
+	/* 0x30d8 0x309a */
+	0x30da, 0x0000,
+	/* 0x30db 0x309a */
+	0x30dd, 0x0000,
+	/* 0x0307 0x0053 0x0301 */
+	0x1e64, 0x0000,
+	/* 0x0307 0x0073 0x0301 */
+	0x1e65, 0x0000,
+	/* 0x0300 0x0041 0x0302 */
+	0x1ea6, 0x0000,
+	/* 0x0301 0x0041 0x0302 */
+	0x1ea4, 0x0000,
+	/* 0x0303 0x0041 0x0302 */
+	0x1eaa, 0x0000,
+	/* 0x0309 0x0041 0x0302 */
+	0x1ea8, 0x0000,
+	/* 0x0300 0x0045 0x0302 */
+	0x1ec0, 0x0000,
+	/* 0x0301 0x0045 0x0302 */
+	0x1ebe, 0x0000,
+	/* 0x0303 0x0045 0x0302 */
+	0x1ec4, 0x0000,
+	/* 0x0309 0x0045 0x0302 */
+	0x1ec2, 0x0000,
+	/* 0x0300 0x004f 0x0302 */
+	0x1ed2, 0x0000,
+	/* 0x0301 0x004f 0x0302 */
+	0x1ed0, 0x0000,
+	/* 0x0303 0x004f 0x0302 */
+	0x1ed6, 0x0000,
+	/* 0x0309 0x004f 0x0302 */
+	0x1ed4, 0x0000,
+	/* 0x0300 0x0061 0x0302 */
+	0x1ea7, 0x0000,
+	/* 0x0301 0x0061 0x0302 */
+	0x1ea5, 0x0000,
+	/* 0x0303 0x0061 0x0302 */
+	0x1eab, 0x0000,
+	/* 0x0309 0x0061 0x0302 */
+	0x1ea9, 0x0000,
+	/* 0x0300 0x0065 0x0302 */
+	0x1ec1, 0x0000,
+	/* 0x0301 0x0065 0x0302 */
+	0x1ebf, 0x0000,
+	/* 0x0303 0x0065 0x0302 */
+	0x1ec5, 0x0000,
+	/* 0x0309 0x0065 0x0302 */
+	0x1ec3, 0x0000,
+	/* 0x0300 0x006f 0x0302 */
+	0x1ed3, 0x0000,
+	/* 0x0301 0x006f 0x0302 */
+	0x1ed1, 0x0000,
+	/* 0x0303 0x006f 0x0302 */
+	0x1ed7, 0x0000,
+	/* 0x0309 0x006f 0x0302 */
+	0x1ed5, 0x0000,
+	/* 0x0301 0x004f 0x0303 */
+	0x1e4c, 0x0000,
+	/* 0x0308 0x004f 0x0303 */
+	0x1e4e, 0x0000,
+	/* 0x0301 0x0055 0x0303 */
+	0x1e78, 0x0000,
+	/* 0x0301 0x006f 0x0303 */
+	0x1e4d, 0x0000,
+	/* 0x0308 0x006f 0x0303 */
+	0x1e4f, 0x0000,
+	/* 0x0301 0x0075 0x0303 */
+	0x1e79, 0x0000,
+	/* 0x0300 0x0045 0x0304 */
+	0x1e14, 0x0000,
+	/* 0x0301 0x0045 0x0304 */
+	0x1e16, 0x0000,
+	/* 0x0300 0x004f 0x0304 */
+	0x1e50, 0x0000,
+	/* 0x0301 0x004f 0x0304 */
+	0x1e52, 0x0000,
+	/* 0x0308 0x0055 0x0304 */
+	0x1e7a, 0x0000,
+	/* 0x0300 0x0065 0x0304 */
+	0x1e15, 0x0000,
+	/* 0x0301 0x0065 0x0304 */
+	0x1e17, 0x0000,
+	/* 0x0300 0x006f 0x0304 */
+	0x1e51, 0x0000,
+	/* 0x0301 0x006f 0x0304 */
+	0x1e53, 0x0000,
+	/* 0x0308 0x0075 0x0304 */
+	0x1e7b, 0x0000,
+	/* 0x0300 0x0041 0x0306 */
+	0x1eb0, 0x0000,
+	/* 0x0301 0x0041 0x0306 */
+	0x1eae, 0x0000,
+	/* 0x0303 0x0041 0x0306 */
+	0x1eb4, 0x0000,
+	/* 0x0309 0x0041 0x0306 */
+	0x1eb2, 0x0000,
+	/* 0x0300 0x0061 0x0306 */
+	0x1eb1, 0x0000,
+	/* 0x0301 0x0061 0x0306 */
+	0x1eaf, 0x0000,
+	/* 0x0303 0x0061 0x0306 */
+	0x1eb5, 0x0000,
+	/* 0x0309 0x0061 0x0306 */
+	0x1eb3, 0x0000,
+	/* 0x0304 0x0041 0x0307 */
+	0x01e0, 0x0000,
+	/* 0x0304 0x0061 0x0307 */
+	0x01e1, 0x0000,
+	/* 0x0304 0x0041 0x0308 */
+	0x01de, 0x0000,
+	/* 0x0301 0x0049 0x0308 */
+	0x1e2e, 0x0000,
+	/* 0x0300 0x0055 0x0308 */
+	0x01db, 0x0000,
+	/* 0x0301 0x0055 0x0308 */
+	0x01d7, 0x0000,
+	/* 0x0304 0x0055 0x0308 */
+	0x01d5, 0x0000,
+	/* 0x030c 0x0055 0x0308 */
+	0x01d9, 0x0000,
+	/* 0x0304 0x0061 0x0308 */
+	0x01df, 0x0000,
+	/* 0x0301 0x0069 0x0308 */
+	0x1e2f, 0x0000,
+	/* 0x0300 0x0075 0x0308 */
+	0x01dc, 0x0000,
+	/* 0x0301 0x0075 0x0308 */
+	0x01d8, 0x0000,
+	/* 0x0304 0x0075 0x0308 */
+	0x01d6, 0x0000,
+	/* 0x030c 0x0075 0x0308 */
+	0x01da, 0x0000,
+	/* 0x0300 0x03b9 0x0308 */
+	0x1fd2, 0x0000,
+	/* 0x0301 0x03b9 0x0308 */
+	0x1fd3, 0x0000,
+	/* 0x030d 0x03b9 0x0308 */
+	0x0390, 0x0000,
+	/* 0x0342 0x03b9 0x0308 */
+	0x1fd7, 0x0000,
+	/* 0x0300 0x03c5 0x0308 */
+	0x1fe2, 0x0000,
+	/* 0x0301 0x03c5 0x0308 */
+	0x1fe3, 0x0000,
+	/* 0x030d 0x03c5 0x0308 */
+	0x03b0, 0x0000,
+	/* 0x0342 0x03c5 0x0308 */
+	0x1fe7, 0x0000,
+	/* 0x0301 0x0041 0x030a */
+	0x01fa, 0x0000,
+	/* 0x0301 0x0061 0x030a */
+	0x01fb, 0x0000,
+	/* 0x0307 0x0053 0x030c */
+	0x1e66, 0x0000,
+	/* 0x0307 0x0073 0x030c */
+	0x1e67, 0x0000,
+	/* 0x0300 0x0391 0x0313 */
+	0x1f0a, 0x0000,
+	/* 0x0301 0x0391 0x0313 */
+	0x1f0c, 0x0000,
+	/* 0x0342 0x0391 0x0313 */
+	0x1f0e, 0x0000,
+	/* 0x0300 0x0395 0x0313 */
+	0x1f1a, 0x0000,
+	/* 0x0301 0x0395 0x0313 */
+	0x1f1c, 0x0000,
+	/* 0x0300 0x0397 0x0313 */
+	0x1f2a, 0x0000,
+	/* 0x0301 0x0397 0x0313 */
+	0x1f2c, 0x0000,
+	/* 0x0342 0x0397 0x0313 */
+	0x1f2e, 0x0000,
+	/* 0x0300 0x0399 0x0313 */
+	0x1f3a, 0x0000,
+	/* 0x0301 0x0399 0x0313 */
+	0x1f3c, 0x0000,
+	/* 0x0342 0x0399 0x0313 */
+	0x1f3e, 0x0000,
+	/* 0x0300 0x039f 0x0313 */
+	0x1f4a, 0x0000,
+	/* 0x0301 0x039f 0x0313 */
+	0x1f4c, 0x0000,
+	/* 0x0300 0x03a9 0x0313 */
+	0x1f6a, 0x0000,
+	/* 0x0301 0x03a9 0x0313 */
+	0x1f6c, 0x0000,
+	/* 0x0342 0x03a9 0x0313 */
+	0x1f6e, 0x0000,
+	/* 0x0300 0x03b1 0x0313 */
+	0x1f02, 0x0000,
+	/* 0x0301 0x03b1 0x0313 */
+	0x1f04, 0x0000,
+	/* 0x0342 0x03b1 0x0313 */
+	0x1f06, 0x0000,
+	/* 0x0300 0x03b5 0x0313 */
+	0x1f12, 0x0000,
+	/* 0x0301 0x03b5 0x0313 */
+	0x1f14, 0x0000,
+	/* 0x0300 0x03b7 0x0313 */
+	0x1f22, 0x0000,
+	/* 0x0301 0x03b7 0x0313 */
+	0x1f24, 0x0000,
+	/* 0x0342 0x03b7 0x0313 */
+	0x1f26, 0x0000,
+	/* 0x0300 0x03b9 0x0313 */
+	0x1f32, 0x0000,
+	/* 0x0301 0x03b9 0x0313 */
+	0x1f34, 0x0000,
+	/* 0x0342 0x03b9 0x0313 */
+	0x1f36, 0x0000,
+	/* 0x0300 0x03bf 0x0313 */
+	0x1f42, 0x0000,
+	/* 0x0301 0x03bf 0x0313 */
+	0x1f44, 0x0000,
+	/* 0x0300 0x03c5 0x0313 */
+	0x1f52, 0x0000,
+	/* 0x0301 0x03c5 0x0313 */
+	0x1f54, 0x0000,
+	/* 0x0342 0x03c5 0x0313 */
+	0x1f56, 0x0000,
+	/* 0x0300 0x03c9 0x0313 */
+	0x1f62, 0x0000,
+	/* 0x0301 0x03c9 0x0313 */
+	0x1f64, 0x0000,
+	/* 0x0342 0x03c9 0x0313 */
+	0x1f66, 0x0000,
+	/* 0x0300 0x0391 0x0314 */
+	0x1f0b, 0x0000,
+	/* 0x0301 0x0391 0x0314 */
+	0x1f0d, 0x0000,
+	/* 0x0342 0x0391 0x0314 */
+	0x1f0f, 0x0000,
+	/* 0x0300 0x0395 0x0314 */
+	0x1f1b, 0x0000,
+	/* 0x0301 0x0395 0x0314 */
+	0x1f1d, 0x0000,
+	/* 0x0300 0x0397 0x0314 */
+	0x1f2b, 0x0000,
+	/* 0x0301 0x0397 0x0314 */
+	0x1f2d, 0x0000,
+	/* 0x0342 0x0397 0x0314 */
+	0x1f2f, 0x0000,
+	/* 0x0300 0x0399 0x0314 */
+	0x1f3b, 0x0000,
+	/* 0x0301 0x0399 0x0314 */
+	0x1f3d, 0x0000,
+	/* 0x0342 0x0399 0x0314 */
+	0x1f3f, 0x0000,
+	/* 0x0300 0x039f 0x0314 */
+	0x1f4b, 0x0000,
+	/* 0x0301 0x039f 0x0314 */
+	0x1f4d, 0x0000,
+	/* 0x0300 0x03a5 0x0314 */
+	0x1f5b, 0x0000,
+	/* 0x0301 0x03a5 0x0314 */
+	0x1f5d, 0x0000,
+	/* 0x0342 0x03a5 0x0314 */
+	0x1f5f, 0x0000,
+	/* 0x0300 0x03a9 0x0314 */
+	0x1f6b, 0x0000,
+	/* 0x0301 0x03a9 0x0314 */
+	0x1f6d, 0x0000,
+	/* 0x0342 0x03a9 0x0314 */
+	0x1f6f, 0x0000,
+	/* 0x0300 0x03b1 0x0314 */
+	0x1f03, 0x0000,
+	/* 0x0301 0x03b1 0x0314 */
+	0x1f05, 0x0000,
+	/* 0x0342 0x03b1 0x0314 */
+	0x1f07, 0x0000,
+	/* 0x0300 0x03b5 0x0314 */
+	0x1f13, 0x0000,
+	/* 0x0301 0x03b5 0x0314 */
+	0x1f15, 0x0000,
+	/* 0x0300 0x03b7 0x0314 */
+	0x1f23, 0x0000,
+	/* 0x0301 0x03b7 0x0314 */
+	0x1f25, 0x0000,
+	/* 0x0342 0x03b7 0x0314 */
+	0x1f27, 0x0000,
+	/* 0x0300 0x03b9 0x0314 */
+	0x1f33, 0x0000,
+	/* 0x0301 0x03b9 0x0314 */
+	0x1f35, 0x0000,
+	/* 0x0342 0x03b9 0x0314 */
+	0x1f37, 0x0000,
+	/* 0x0300 0x03bf 0x0314 */
+	0x1f43, 0x0000,
+	/* 0x0301 0x03bf 0x0314 */
+	0x1f45, 0x0000,
+	/* 0x0300 0x03c5 0x0314 */
+	0x1f53, 0x0000,
+	/* 0x0301 0x03c5 0x0314 */
+	0x1f55, 0x0000,
+	/* 0x0342 0x03c5 0x0314 */
+	0x1f57, 0x0000,
+	/* 0x0300 0x03c9 0x0314 */
+	0x1f63, 0x0000,
+	/* 0x0301 0x03c9 0x0314 */
+	0x1f65, 0x0000,
+	/* 0x0342 0x03c9 0x0314 */
+	0x1f67, 0x0000,
+	/* 0x0300 0x004f 0x031b */
+	0x1edc, 0x0000,
+	/* 0x0301 0x004f 0x031b */
+	0x1eda, 0x0000,
+	/* 0x0303 0x004f 0x031b */
+	0x1ee0, 0x0000,
+	/* 0x0309 0x004f 0x031b */
+	0x1ede, 0x0000,
+	/* 0x0323 0x004f 0x031b */
+	0x1ee2, 0x0000,
+	/* 0x0300 0x0055 0x031b */
+	0x1eea, 0x0000,
+	/* 0x0301 0x0055 0x031b */
+	0x1ee8, 0x0000,
+	/* 0x0303 0x0055 0x031b */
+	0x1eee, 0x0000,
+	/* 0x0309 0x0055 0x031b */
+	0x1eec, 0x0000,
+	/* 0x0323 0x0055 0x031b */
+	0x1ef0, 0x0000,
+	/* 0x0300 0x006f 0x031b */
+	0x1edd, 0x0000,
+	/* 0x0301 0x006f 0x031b */
+	0x1edb, 0x0000,
+	/* 0x0303 0x006f 0x031b */
+	0x1ee1, 0x0000,
+	/* 0x0309 0x006f 0x031b */
+	0x1edf, 0x0000,
+	/* 0x0323 0x006f 0x031b */
+	0x1ee3, 0x0000,
+	/* 0x0300 0x0075 0x031b */
+	0x1eeb, 0x0000,
+	/* 0x0301 0x0075 0x031b */
+	0x1ee9, 0x0000,
+	/* 0x0303 0x0075 0x031b */
+	0x1eef, 0x0000,
+	/* 0x0309 0x0075 0x031b */
+	0x1eed, 0x0000,
+	/* 0x0323 0x0075 0x031b */
+	0x1ef1, 0x0000,
+	/* 0x0302 0x0041 0x0323 */
+	0x1eac, 0x0000,
+	/* 0x0306 0x0041 0x0323 */
+	0x1eb6, 0x0000,
+	/* 0x0302 0x0045 0x0323 */
+	0x1ec6, 0x0000,
+	/* 0x0304 0x004c 0x0323 */
+	0x1e38, 0x0000,
+	/* 0x0302 0x004f 0x0323 */
+	0x1ed8, 0x0000,
+	/* 0x0304 0x0052 0x0323 */
+	0x1e5c, 0x0000,
+	/* 0x0307 0x0053 0x0323 */
+	0x1e68, 0x0000,
+	/* 0x0302 0x0061 0x0323 */
+	0x1ead, 0x0000,
+	/* 0x0306 0x0061 0x0323 */
+	0x1eb7, 0x0000,
+	/* 0x0302 0x0065 0x0323 */
+	0x1ec7, 0x0000,
+	/* 0x0304 0x006c 0x0323 */
+	0x1e39, 0x0000,
+	/* 0x0302 0x006f 0x0323 */
+	0x1ed9, 0x0000,
+	/* 0x0304 0x0072 0x0323 */
+	0x1e5d, 0x0000,
+	/* 0x0307 0x0073 0x0323 */
+	0x1e69, 0x0000,
+	/* 0x0301 0x0043 0x0327 */
+	0x1e08, 0x0000,
+	/* 0x0306 0x0045 0x0327 */
+	0x1e1c, 0x0000,
+	/* 0x0301 0x0063 0x0327 */
+	0x1e09, 0x0000,
+	/* 0x0306 0x0065 0x0327 */
+	0x1e1d, 0x0000,
+	/* 0x0304 0x004f 0x0328 */
+	0x01ec, 0x0000,
+	/* 0x0304 0x006f 0x0328 */
+	0x01ed, 0x0000,
+	/* 0x0313 0x0391 0x0345 */
+	0x1f88, 0x0003,  0x0300, 0x0f5e,  0x0301, 0x0f60,  0x0342, 0x0f62,
+	/* 0x0314 0x0391 0x0345 */
+	0x1f89, 0x0003,  0x0300, 0x0f64,  0x0301, 0x0f66,  0x0342, 0x0f68,
+	/* 0x0313 0x0397 0x0345 */
+	0x1f98, 0x0003,  0x0300, 0x0f6a,  0x0301, 0x0f6c,  0x0342, 0x0f6e,
+	/* 0x0314 0x0397 0x0345 */
+	0x1f99, 0x0003,  0x0300, 0x0f70,  0x0301, 0x0f72,  0x0342, 0x0f74,
+	/* 0x0313 0x03a9 0x0345 */
+	0x1fa8, 0x0003,  0x0300, 0x0f76,  0x0301, 0x0f78,  0x0342, 0x0f7a,
+	/* 0x0314 0x03a9 0x0345 */
+	0x1fa9, 0x0003,  0x0300, 0x0f7c,  0x0301, 0x0f7e,  0x0342, 0x0f80,
+	/* 0x0300 0x03b1 0x0345 */
+	0x1fb2, 0x0000,
+	/* 0x0301 0x03b1 0x0345 */
+	0x1fb4, 0x0000,
+	/* 0x0313 0x03b1 0x0345 */
+	0x1f80, 0x0003,  0x0300, 0x0f82,  0x0301, 0x0f84,  0x0342, 0x0f86,
+	/* 0x0314 0x03b1 0x0345 */
+	0x1f81, 0x0003,  0x0300, 0x0f88,  0x0301, 0x0f8a,  0x0342, 0x0f8c,
+	/* 0x0342 0x03b1 0x0345 */
+	0x1fb7, 0x0000,
+	/* 0x0300 0x03b7 0x0345 */
+	0x1fc2, 0x0000,
+	/* 0x0301 0x03b7 0x0345 */
+	0x1fc4, 0x0000,
+	/* 0x0313 0x03b7 0x0345 */
+	0x1f90, 0x0003,  0x0300, 0x0f8e,  0x0301, 0x0f90,  0x0342, 0x0f92,
+	/* 0x0314 0x03b7 0x0345 */
+	0x1f91, 0x0003,  0x0300, 0x0f94,  0x0301, 0x0f96,  0x0342, 0x0f98,
+	/* 0x0342 0x03b7 0x0345 */
+	0x1fc7, 0x0000,
+	/* 0x0301 0x03bf 0x0345 */
+	0x1ff4, 0x0000,
+	/* 0x0300 0x03c9 0x0345 */
+	0x1ff2, 0x0000,
+	/* 0x0313 0x03c9 0x0345 */
+	0x1fa0, 0x0003,  0x0300, 0x0f9a,  0x0301, 0x0f9c,  0x0342, 0x0f9e,
+	/* 0x0314 0x03c9 0x0345 */
+	0x1fa1, 0x0003,  0x0300, 0x0fa0,  0x0301, 0x0fa2,  0x0342, 0x0fa4,
+	/* 0x0342 0x03c9 0x0345 */
+	0x1ff7, 0x0000,
+	/* 0x05c1 0x05e9 0x05bc */
+	0xfb2c, 0x0000,
+	/* 0x05c2 0x05e9 0x05bc */
+	0xfb2d, 0x0000,
+	/* 0x0cd5 0x0cc6 0x0cc2 */
+	0x0ccb, 0x0000,
+	/* 0x0f71 0x0fb2 0x0f80 */
+	0x0f77, 0x0000,
+	/* 0x0f71 0x0fb3 0x0f80 */
+	0x0f79, 0x0000,
+	/* 0x0300 0x0313 0x0391 0x0345 */
+	0x1f8a, 0x0000,
+	/* 0x0301 0x0313 0x0391 0x0345 */
+	0x1f8c, 0x0000,
+	/* 0x0342 0x0313 0x0391 0x0345 */
+	0x1f8e, 0x0000,
+	/* 0x0300 0x0314 0x0391 0x0345 */
+	0x1f8b, 0x0000,
+	/* 0x0301 0x0314 0x0391 0x0345 */
+	0x1f8d, 0x0000,
+	/* 0x0342 0x0314 0x0391 0x0345 */
+	0x1f8f, 0x0000,
+	/* 0x0300 0x0313 0x0397 0x0345 */
+	0x1f9a, 0x0000,
+	/* 0x0301 0x0313 0x0397 0x0345 */
+	0x1f9c, 0x0000,
+	/* 0x0342 0x0313 0x0397 0x0345 */
+	0x1f9e, 0x0000,
+	/* 0x0300 0x0314 0x0397 0x0345 */
+	0x1f9b, 0x0000,
+	/* 0x0301 0x0314 0x0397 0x0345 */
+	0x1f9d, 0x0000,
+	/* 0x0342 0x0314 0x0397 0x0345 */
+	0x1f9f, 0x0000,
+	/* 0x0300 0x0313 0x03a9 0x0345 */
+	0x1faa, 0x0000,
+	/* 0x0301 0x0313 0x03a9 0x0345 */
+	0x1fac, 0x0000,
+	/* 0x0342 0x0313 0x03a9 0x0345 */
+	0x1fae, 0x0000,
+	/* 0x0300 0x0314 0x03a9 0x0345 */
+	0x1fab, 0x0000,
+	/* 0x0301 0x0314 0x03a9 0x0345 */
+	0x1fad, 0x0000,
+	/* 0x0342 0x0314 0x03a9 0x0345 */
+	0x1faf, 0x0000,
+	/* 0x0300 0x0313 0x03b1 0x0345 */
+	0x1f82, 0x0000,
+	/* 0x0301 0x0313 0x03b1 0x0345 */
+	0x1f84, 0x0000,
+	/* 0x0342 0x0313 0x03b1 0x0345 */
+	0x1f86, 0x0000,
+	/* 0x0300 0x0314 0x03b1 0x0345 */
+	0x1f83, 0x0000,
+	/* 0x0301 0x0314 0x03b1 0x0345 */
+	0x1f85, 0x0000,
+	/* 0x0342 0x0314 0x03b1 0x0345 */
+	0x1f87, 0x0000,
+	/* 0x0300 0x0313 0x03b7 0x0345 */
+	0x1f92, 0x0000,
+	/* 0x0301 0x0313 0x03b7 0x0345 */
+	0x1f94, 0x0000,
+	/* 0x0342 0x0313 0x03b7 0x0345 */
+	0x1f96, 0x0000,
+	/* 0x0300 0x0314 0x03b7 0x0345 */
+	0x1f93, 0x0000,
+	/* 0x0301 0x0314 0x03b7 0x0345 */
+	0x1f95, 0x0000,
+	/* 0x0342 0x0314 0x03b7 0x0345 */
+	0x1f97, 0x0000,
+	/* 0x0300 0x0313 0x03c9 0x0345 */
+	0x1fa2, 0x0000,
+	/* 0x0301 0x0313 0x03c9 0x0345 */
+	0x1fa4, 0x0000,
+	/* 0x0342 0x0313 0x03c9 0x0345 */
+	0x1fa6, 0x0000,
+	/* 0x0300 0x0314 0x03c9 0x0345 */
+	0x1fa3, 0x0000,
+	/* 0x0301 0x0314 0x03c9 0x0345 */
+	0x1fa5, 0x0000,
+	/* 0x0342 0x0314 0x03c9 0x0345 */
+	0x1fa7, 0x0000,
+};
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -19,9 +19,9 @@ static inline u16 case_fold(u16 c)
 {
         u16 tmp;
 
-        tmp = case_fold_table[(c>>8)];
+        tmp = hfsplus_case_fold_table[c >> 8];
         if (tmp)
-                tmp = case_fold_table[tmp + (c & 0xFF)];
+                tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
         else
                 tmp = c;
         return tmp;
@@ -59,69 +59,175 @@ int hfsplus_unistrcmp(const struct hfspl
 	}
 }
 
-int hfsplus_uni2asc(const struct hfsplus_unistr *ustr, char *astr, int *len)
+#define Hangul_SBase	0xac00
+#define Hangul_LBase	0x1100
+#define Hangul_VBase	0x1161
+#define Hangul_TBase	0x11a7
+#define Hangul_SCount	11172
+#define Hangul_LCount	19
+#define Hangul_VCount	21
+#define Hangul_TCount	28
+#define Hangul_NCount	(Hangul_VCount * Hangul_TCount)
+
+
+static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
+{
+	int i, s, e;
+
+	s = 1;
+	e = p[1];
+	if (!e || cc < p[s * 2] || cc > p[e * 2])
+		return NULL;
+	do {
+		i = (s + e) / 2;
+		if (cc > p[i * 2])
+			s = i + 1;
+		else if (cc < p[i * 2])
+			e = i - 1;
+		else
+			return hfsplus_compose_table + p[i * 2 + 1];
+	} while (s <= e);
+	return NULL;
+}
+
+int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
 {
 	const hfsplus_unichr *ip;
+	struct nls_table *nls = HFSPLUS_SB(sb).nls;
 	u8 *op;
-	u16 ustrlen, cc;
-	int size, tmp;
+	u16 cc, c0, c1;
+	u16 *ce1, *ce2;
+	int i, len, ustrlen, res, compose;
 
 	op = astr;
 	ip = ustr->unicode;
 	ustrlen = be16_to_cpu(ustr->length);
-	tmp = *len;
-	while (ustrlen > 0 && tmp > 0) {
-		cc = be16_to_cpu(*ip);
-		switch (cc) {
+	len = *len_p;
+	ce1 = NULL;
+	compose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+
+	while (ustrlen > 0) {
+		c0 = be16_to_cpu(*ip++);
+		ustrlen--;
+		/* search for single decomposed char */
+		if (likely(compose))
+			ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
+		if (ce1 && (cc = ce1[0])) {
+			/* start of a possibly decomposed Hangul char */
+			if (cc != 0xffff)
+				goto done;
+			if (!ustrlen)
+				goto same;
+			c1 = be16_to_cpu(*ip) - Hangul_VBase;
+			if (c1 < Hangul_VCount) {
+				/* compose the Hangul char */
+				cc = (c0 - Hangul_LBase) * Hangul_VCount;
+				cc = (cc + c1) * Hangul_TCount;
+				cc += Hangul_SBase;
+				ip++;
+				ustrlen--;
+				if (!ustrlen)
+					goto done;
+				c1 = be16_to_cpu(*ip) - Hangul_TBase;
+				if (c1 > 0 && c1 < Hangul_TCount) {
+					cc += c1;
+					ip++;
+					ustrlen--;
+				}
+				goto done;
+			}
+		}
+		while (1) {
+			/* main loop for common case of not composed chars */
+			if (!ustrlen)
+				goto same;
+			c1 = be16_to_cpu(*ip);
+			if (likely(compose))
+				ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1);
+			if (ce1)
+				break;
+			switch (c0) {
+			case 0:
+				c0 = 0x2400;
+				break;
+			case '/':
+				c0 = ':';
+				break;
+			}
+			res = nls->uni2char(c0, op, len);
+			if (res < 0) {
+				if (res == -ENAMETOOLONG)
+					goto out;
+				*op = '?';
+				res = 1;
+			}
+			op += res;
+			len -= res;
+			c0 = c1;
+			ip++;
+			ustrlen--;
+		}
+		ce2 = hfsplus_compose_lookup(ce1, c0);
+		if (ce2) {
+			i = 1;
+			while (i < ustrlen) {
+				ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i]));
+				if (!ce1)
+					break;
+				i++;
+				ce2 = ce1;
+			}
+			if ((cc = ce2[0])) {
+				ip += i;
+				ustrlen -= i;
+				goto done;
+			}
+		}
+	same:
+		switch (c0) {
 		case 0:
 			cc = 0x2400;
 			break;
 		case '/':
 			cc = ':';
 			break;
+		default:
+			cc = c0;
 		}
-		if (cc > 0x7f) {
-			size = utf8_wctomb(op, cc, tmp);
-			if (size == -1) {
-				/* ignore */
-			} else {
-				op += size;
-				tmp -= size;
-			}
-		} else {
-			*op++ = (u8) cc;
-			tmp--;
+	done:
+		res = nls->uni2char(cc, op, len);
+		if (res < 0) {
+			if (res == -ENAMETOOLONG)
+				goto out;
+			*op = '?';
+			res = 1;
 		}
-		ip++;
-		ustrlen--;
+		op += res;
+		len -= res;
 	}
-	*len = (char *)op - astr;
-	if (ustrlen)
-		return -ENAMETOOLONG;
-	return 0;
+	res = 0;
+out:
+	*len_p = (char *)op - astr;
+	return res;
 }
 
-int hfsplus_asc2uni(struct hfsplus_unistr *ustr, const char *astr, int len)
+int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len)
 {
-	int tmp;
+	struct nls_table *nls = HFSPLUS_SB(sb).nls;
+	int size, off, decompose;
 	wchar_t c;
 	u16 outlen = 0;
 
-	while (outlen <= HFSPLUS_MAX_STRLEN && len > 0) {
-		if (*astr & 0x80) {
-			tmp = utf8_mbtowc(&c, astr, len);
-			if (tmp < 0) {
-				astr++;
-				len--;
-				continue;
-			} else {
-				astr += tmp;
-				len -= tmp;
-			}
-		} else {
-			c = *astr++;
-			len--;
+	decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+
+	while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
+		size = nls->char2uni(astr, len, &c);
+		if (size <= 0) {
+			c = '?';
+			size = 1;
 		}
+		astr += size;
+		len -= size;
 		switch (c) {
 		case 0x2400:
 			c = 0;
@@ -130,8 +236,33 @@ int hfsplus_asc2uni(struct hfsplus_unist
 			c = '/';
 			break;
 		}
-		ustr->unicode[outlen] = cpu_to_be16(c);
-		outlen++;
+		if (c >= 0xc0 && decompose) {
+			off = hfsplus_decompose_table[(c >> 12) & 0xf];
+			if (!off)
+				goto done;
+			if (off == 0xffff) {
+				goto done;
+			}
+			off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)];
+			if (!off)
+				goto done;
+			off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)];
+			if (!off)
+				goto done;
+			off = hfsplus_decompose_table[off + (c & 0xf)];
+			size = off & 3;
+			if (!size)
+				goto done;
+			off /= 4;
+			if (outlen + size > HFSPLUS_MAX_STRLEN)
+				break;
+			do {
+				ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]);
+			} while (--size > 0);
+			continue;
+		}
+	done:
+		ustr->unicode[outlen++] = cpu_to_be16(c);
 	}
 	ustr->length = cpu_to_be16(outlen);
 	if (len > 0)
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
--- a/fs/hostfs/Makefile
+++ b/fs/hostfs/Makefile
@@ -3,24 +3,9 @@
 # Licensed under the GPL
 #
 
-# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
-# to __st_ino.  It stayed in the same place, so as long as the correct name
-# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
-
-STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
-				echo __)st_ino
-
 hostfs-objs := hostfs_kern.o hostfs_user.o
 
-obj-y =
+obj-y :=
 obj-$(CONFIG_HOSTFS) += hostfs.o
 
-SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
-
-USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
-
-$(USER_OBJS) : %.o: %.c
-	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -23,7 +23,6 @@
 #include "kern_util.h"
 #include "kern.h"
 #include "user_util.h"
-#include "2_5compat.h"
 #include "init.h"
 
 struct hostfs_inode_info {
@@ -521,7 +520,7 @@ int hostfs_commit_write(struct file *fil
 static struct address_space_operations hostfs_aops = {
 	.writepage 	= hostfs_writepage,
 	.readpage	= hostfs_readpage,
-/* 	.set_page_dirty = __set_page_dirty_nobuffers, */
+	.set_page_dirty = __set_page_dirty_nobuffers,
 	.prepare_write	= hostfs_prepare_write,
 	.commit_write	= hostfs_commit_write
 };
@@ -806,15 +805,21 @@ int hostfs_permission(struct inode *ino,
 	char *name;
 	int r = 0, w = 0, x = 0, err;
 
-	if(desired & MAY_READ) r = 1;
-	if(desired & MAY_WRITE) w = 1;
-	if(desired & MAY_EXEC) x = 1;
+	if (desired & MAY_READ) r = 1;
+	if (desired & MAY_WRITE) w = 1;
+	if (desired & MAY_EXEC) x = 1;
 	name = inode_name(ino, 0);
-	if(name == NULL) return(-ENOMEM);
-	err = access_file(name, r, w, x);
+	if (name == NULL) return(-ENOMEM);
+
+	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
+			S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
+		err = 0;
+	else
+		err = access_file(name, r, w, x);
 	kfree(name);
-	if(!err) err = generic_permission(ino, desired, NULL);
-	return(err);
+	if(!err)
+		err = generic_permission(ino, desired, NULL);
+	return err;
 }
 
 int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -845,7 +850,7 @@ int hostfs_setattr(struct dentry *dentry
 	if(attr->ia_valid & ATTR_GID){
 		if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) &&
 		   (attr->ia_gid == 0))
-			attr->ia_gid = getuid();
+			attr->ia_gid = getgid();
 		attrs.ia_valid |= HOSTFS_ATTR_GID;
 		attrs.ia_gid = attr->ia_gid;
 	}
@@ -985,13 +990,17 @@ static int hostfs_fill_sb_common(struct 
 		goto out_put;
 
 	err = read_inode(root_inode);
-	if(err)
-		goto out_put;
+	if(err){
+                /* No iput in this case because the dput does that for us */
+                dput(sb->s_root);
+                sb->s_root = NULL;
+		goto out_free;
+        }
 
 	return(0);
 
  out_put:
-	iput(root_inode);
+        iput(root_inode);
  out_free:
 	kfree(name);
  out:
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -28,10 +28,7 @@ int stat_file(const char *path, unsigned
 	if(lstat64(path, &buf) < 0)
 		return(-errno);
 
-	/* See the Makefile for why STAT64_INO_FIELD is passed in
-	 * by the build
-	 */
-	if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
+	if(inode_out != NULL) *inode_out = buf.st_ino;
 	if(mode_out != NULL) *mode_out = buf.st_mode;
 	if(nlink_out != NULL) *nlink_out = buf.st_nlink;
 	if(uid_out != NULL) *uid_out = buf.st_uid;
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
--- a/fs/hpfs/alloc.c
+++ b/fs/hpfs/alloc.c
@@ -8,6 +8,8 @@
 
 #include "hpfs_fn.h"
 
+static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec);
+
 /*
  * Check if a sector is allocated in bitmap
  * This is really slow. Turned on only if chk==2
@@ -243,7 +245,7 @@ static secno alloc_in_dirband(struct sup
 
 /* Alloc sector if it's free */
 
-int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec)
+static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec)
 {
 	struct quad_buffer_head qbh;
 	unsigned *bmp;
diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c
--- a/fs/hpfs/dentry.c
+++ b/fs/hpfs/dentry.c
@@ -12,7 +12,7 @@
  * Note: the dentry argument is the parent dentry.
  */
 
-int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
 {
 	unsigned long	 hash;
 	int		 i;
@@ -34,7 +34,7 @@ int hpfs_hash_dentry(struct dentry *dent
 	return 0;
 }
 
-int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
 {
 	unsigned al=a->len;
 	unsigned bl=b->len;
@@ -49,7 +49,7 @@ int hpfs_compare_dentry(struct dentry *d
 	return 0;
 }
 
-struct dentry_operations hpfs_dentry_operations = {
+static struct dentry_operations hpfs_dentry_operations = {
 	.d_hash		= hpfs_hash_dentry,
 	.d_compare	= hpfs_compare_dentry,
 };
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c
--- a/fs/hpfs/dnode.c
+++ b/fs/hpfs/dnode.c
@@ -78,7 +78,7 @@ static void for_all_poss(struct inode *i
 	return;
 }
 
-void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t)
+static void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t)
 {
 	if (*p == f) *p = t;
 }
@@ -88,7 +88,7 @@ void hpfs_pos_subst(loff_t *p, loff_t f,
 	if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f);
 }*/
 
-void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c)
+static void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c)
 {
 	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
 		int n = (*p & 0x3f) + c;
@@ -97,7 +97,7 @@ void hpfs_pos_ins(loff_t *p, loff_t d, l
 	}
 }
 
-void hpfs_pos_del(loff_t *p, loff_t d, loff_t c)
+static void hpfs_pos_del(loff_t *p, loff_t d, loff_t c)
 {
 	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
 		int n = (*p & 0x3f) - c;
@@ -189,7 +189,8 @@ struct hpfs_dirent *hpfs_add_de(struct s
 
 /* Delete dirent and don't care about its subtree */
 
-void hpfs_delete_de(struct super_block *s, struct dnode *d, struct hpfs_dirent *de)
+static void hpfs_delete_de(struct super_block *s, struct dnode *d,
+			   struct hpfs_dirent *de)
 {
 	if (de->last) {
 		hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self);
@@ -221,8 +222,9 @@ static void fix_up_ptrs(struct super_blo
 
 /* Add an entry to dnode and do dnode splitting if required */
 
-int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, unsigned char *name, unsigned namelen,
-		      struct hpfs_dirent *new_de, dnode_secno down_ptr)
+static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
+			     unsigned char *name, unsigned namelen,
+			     struct hpfs_dirent *new_de, dnode_secno down_ptr)
 {
 	struct quad_buffer_head qbh, qbh1, qbh2;
 	struct dnode *d, *ad, *rd, *nd = NULL;
diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h
--- a/fs/hpfs/hpfs.h
+++ b/fs/hpfs/hpfs.h
@@ -27,6 +27,8 @@ typedef secno dnode_secno;		/* sector nu
 typedef secno fnode_secno;		/* sector number of an fnode */
 typedef secno anode_secno;		/* sector number of an anode */
 
+typedef u32 time32_t;		/* 32-bit time_t type */
+
 /* sector 0 */
 
 /* The boot block is very like a FAT boot block, except that the
@@ -84,9 +86,9 @@ struct hpfs_super_block
   unsigned zero1;			/* 0 */
   secno badblocks;			/* bad block list */
   unsigned zero3;			/* 0 */
-  time_t last_chkdsk;			/* date last checked, 0 if never */
+  time32_t last_chkdsk;			/* date last checked, 0 if never */
   /*unsigned zero4;*/			/* 0 */
-  time_t last_optimize;			/* date last optimized, 0 if never */
+  time32_t last_optimize;			/* date last optimized, 0 if never */
   secno n_dir_band;			/* number of sectors in dir band */
   secno dir_band_start;			/* first sector in dir band */
   secno dir_band_end;			/* last sector in dir band */
@@ -287,10 +289,10 @@ struct hpfs_dirent {
   unsigned not_8x3: 1;			/* name is not 8.3 */
   unsigned flag15: 1;
   fnode_secno fnode;			/* fnode giving allocation info */
-  time_t write_date;			/* mtime */
+  time32_t write_date;			/* mtime */
   unsigned file_size;			/* file length, bytes */
-  time_t read_date;			/* atime */
-  time_t creation_date;			/* ctime */
+  time32_t read_date;			/* atime */
+  time32_t creation_date;			/* ctime */
   unsigned ea_size;			/* total EA length, bytes */
   unsigned char no_of_acls : 3;		/* number of ACL's */
   unsigned char reserver : 5;
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -202,7 +202,6 @@ static inline unsigned tstbits(unsigned 
 
 int hpfs_chk_sectors(struct super_block *, secno, int, char *);
 secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int, int);
-int hpfs_alloc_if_possible_nolock(struct super_block *, secno);
 int hpfs_alloc_if_possible(struct super_block *, secno);
 void hpfs_free_sectors(struct super_block *, secno, unsigned);
 int hpfs_check_free_dnodes(struct super_block *, int);
@@ -247,8 +246,6 @@ extern struct file_operations hpfs_dir_o
 void hpfs_add_pos(struct inode *, loff_t *);
 void hpfs_del_pos(struct inode *, loff_t *);
 struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, unsigned char *, unsigned, secno);
-void hpfs_delete_de(struct super_block *, struct dnode *, struct hpfs_dirent *);
-int hpfs_add_to_dnode(struct inode *, dnode_secno, unsigned char *, unsigned, struct hpfs_dirent *, dnode_secno);
 int hpfs_add_dirent(struct inode *, unsigned char *, unsigned, struct hpfs_dirent *, int);
 int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int);
 void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *);
@@ -276,7 +273,6 @@ extern struct address_space_operations h
 
 void hpfs_init_inode(struct inode *);
 void hpfs_read_inode(struct inode *);
-void hpfs_write_inode_ea(struct inode *, struct fnode *);
 void hpfs_write_inode(struct inode *);
 void hpfs_write_inode_nolock(struct inode *);
 int hpfs_notify_change(struct dentry *, struct iattr *);
@@ -329,13 +325,13 @@ unsigned hpfs_count_one_bitmap(struct su
  * local time (HPFS) to GMT (Unix)
  */
 
-static inline time_t local_to_gmt(struct super_block *s, time_t t)
+static inline time_t local_to_gmt(struct super_block *s, time32_t t)
 {
 	extern struct timezone sys_tz;
 	return t + sys_tz.tz_minuteswest * 60 + hpfs_sb(s)->sb_timeshift;
 }
 
-static inline time_t gmt_to_local(struct super_block *s, time_t t)
+static inline time32_t gmt_to_local(struct super_block *s, time_t t)
 {
 	extern struct timezone sys_tz;
 	return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift;
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -141,7 +141,7 @@ void hpfs_read_inode(struct inode *i)
 	brelse(bh);
 }
 
-void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
+static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
 {
 	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	/*if (fnode->acl_size_l || fnode->acl_size_s) {
diff --git a/fs/hpfs/name.c b/fs/hpfs/name.c
--- a/fs/hpfs/name.c
+++ b/fs/hpfs/name.c
@@ -8,12 +8,12 @@
 
 #include "hpfs_fn.h"
 
-char *text_postfix[]={
+static char *text_postfix[]={
 ".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF",
 ".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS",
 ".RC", ".TEX", ".TXT", ".Y", ""};
 
-char *text_prefix[]={
+static char *text_prefix[]={
 "AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ",
 "MAKEFILE", "READ.ME", "README", "TERMCAP", ""};
 
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -246,9 +246,9 @@ static match_table_t tokens = {
 	{Opt_err, NULL},
 };
 
-int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
-	       int *lowercase, int *conv, int *eas, int *chk, int *errs,
-	       int *chkdsk, int *timeshift)
+static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
+		      int *lowercase, int *conv, int *eas, int *chk, int *errs,
+		      int *chkdsk, int *timeshift)
 {
 	char *p;
 	int option;
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
--- a/fs/hppfs/Makefile
+++ b/fs/hppfs/Makefile
@@ -7,13 +7,3 @@ hppfs-objs := hppfs_kern.o
 
 obj-y =
 obj-$(CONFIG_HPPFS) += hppfs.o
-
-clean:
-
-modules:
-
-fastdep:
-
-dep:
-
-archmrproper: clean
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -40,7 +40,7 @@ static struct inode_operations hugetlbfs
 
 static struct backing_dev_info hugetlbfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
 int sysctl_hugetlb_shm_group;
diff --git a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -26,7 +26,6 @@
  * This is needed for the following functions:
  *  - inode_has_buffers
  *  - invalidate_inode_buffers
- *  - fsync_bdev
  *  - invalidate_bdev
  *
  * FIXME: remove all knowledge of the buffer layer from this file
@@ -118,7 +117,6 @@ static struct inode *alloc_inode(struct 
 		inode->i_blkbits = sb->s_blocksize_bits;
 		inode->i_flags = 0;
 		atomic_set(&inode->i_count, 1);
-		inode->i_sock = 0;
 		inode->i_op = &empty_iops;
 		inode->i_fop = &empty_fops;
 		inode->i_nlink = 1;
@@ -196,7 +194,7 @@ void inode_init_once(struct inode *inode
 	sema_init(&inode->i_sem, 1);
 	init_rwsem(&inode->i_alloc_sem);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
-	spin_lock_init(&inode->i_data.tree_lock);
+	rwlock_init(&inode->i_data.tree_lock);
 	spin_lock_init(&inode->i_data.i_mmap_lock);
 	INIT_LIST_HEAD(&inode->i_data.private_list);
 	spin_lock_init(&inode->i_data.private_lock);
@@ -333,14 +331,6 @@ static int invalidate_list(struct list_h
 	return busy;
 }
 
-/*
- * This is a two-stage process. First we collect all
- * offending inodes onto the throw-away list, and in
- * the second stage we actually dispose of them. This
- * is because we don't want to sleep while messing
- * with the global lists..
- */
- 
 /**
  *	invalidate_inodes	- discard the inodes on a device
  *	@sb: superblock
@@ -367,16 +357,11 @@ int invalidate_inodes(struct super_block
 
 EXPORT_SYMBOL(invalidate_inodes);
  
-int __invalidate_device(struct block_device *bdev, int do_sync)
+int __invalidate_device(struct block_device *bdev)
 {
-	struct super_block *sb;
-	int res;
+	struct super_block *sb = get_super(bdev);
+	int res = 0;
 
-	if (do_sync)
-		fsync_bdev(bdev);
-
-	res = 0;
-	sb = get_super(bdev);
 	if (sb) {
 		/*
 		 * no need to lock the super, get_super holds the
@@ -391,7 +376,6 @@ int __invalidate_device(struct block_dev
 	invalidate_bdev(bdev, 0);
 	return res;
 }
-
 EXPORT_SYMBOL(__invalidate_device);
 
 static int can_unuse(struct inode *inode)
@@ -1098,15 +1082,16 @@ static inline void iput_final(struct ino
  *	@inode: inode to put
  *
  *	Puts an inode, dropping its usage count. If the inode use count hits
- *	zero the inode is also then freed and may be destroyed.
+ *	zero, the inode is then freed and may also be destroyed.
+ *
+ *	Consequently, iput() can sleep.
  */
 void iput(struct inode *inode)
 {
 	if (inode) {
 		struct super_operations *op = inode->i_sb->s_op;
 
-		if (inode->i_state == I_CLEAR)
-			BUG();
+		BUG_ON(inode->i_state == I_CLEAR);
 
 		if (op && op->put_inode)
 			op->put_inode(inode);
@@ -1336,7 +1321,7 @@ void __init inode_init(unsigned long mem
 
 	/* inode slab cache */
 	inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
-				0, SLAB_PANIC, init_once, NULL);
+				0, SLAB_RECLAIM_ACCOUNT|SLAB_PANIC, init_once, NULL);
 	set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
 
 	/* Hash may have been set up in inode_init_early */
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -18,29 +18,12 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-
-#include <linux/stat.h>
-#include <linux/time.h>
-#include <linux/iso_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/nls.h>
-#include <linux/ctype.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
+
 #include <linux/vmalloc.h>
 #include <linux/zlib.h>
-#include <linux/buffer_head.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
+#include "isofs.h"
 #include "zisofs.h"
 
 /* This should probably be global. */
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -10,20 +10,9 @@
  * 
  *  isofs directory handling functions
  */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/iso_fs.h>
-#include <linux/kernel.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/time.h>
 #include <linux/config.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
-
-#include <asm/uaccess.h>
+#include "isofs.h"
 
 static int isofs_readdir(struct file *, void *, filldir_t);
 
diff --git a/fs/isofs/export.c b/fs/isofs/export.c
--- a/fs/isofs/export.c
+++ b/fs/isofs/export.c
@@ -13,11 +13,7 @@
  *     fs/exportfs/expfs.c.
  */
 
-#include <linux/buffer_head.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/iso_fs.h>
-#include <linux/kernel.h>
+#include "isofs.h"
 
 static struct dentry *
 isofs_export_iget(struct super_block *sb,
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -12,29 +12,18 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
-#include <linux/stat.h>
-#include <linux/time.h>
-#include <linux/iso_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/cdrom.h>
-#include <linux/init.h>
 #include <linux/nls.h>
 #include <linux/ctype.h>
 #include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/vfs.h>
+#include <linux/statfs.h>
+#include <linux/cdrom.h>
 #include <linux/parser.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
 
+#include "isofs.h"
 #include "zisofs.h"
 
 #define BEQUIET
@@ -685,6 +674,8 @@ root_found:
 	  sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
 	  sbi->s_max_size = isonum_733(h_pri->volume_space_size);
 	} else {
+	  if (!pri)
+	    goto out_freebh;
 	  rootp = (struct iso_directory_record *) pri->root_directory_record;
 	  sbi->s_nzones = isonum_733 (pri->volume_space_size);
 	  sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
@@ -1395,6 +1386,9 @@ struct inode *isofs_iget(struct super_bl
 	struct inode *inode;
 	struct isofs_iget5_callback_data data;
 
+	if (offset >= 1ul << sb->s_blocksize_bits)
+		return NULL;
+
 	data.block = block;
 	data.offset = offset;
 
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
new file mode 100644
--- /dev/null
+++ b/fs/isofs/isofs.h
@@ -0,0 +1,190 @@
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/iso_fs.h>
+#include <asm/unaligned.h>
+
+enum isofs_file_format {
+	isofs_file_normal = 0,
+	isofs_file_sparse = 1,
+	isofs_file_compressed = 2,
+};
+	
+/*
+ * iso fs inode data in memory
+ */
+struct iso_inode_info {
+	unsigned long i_iget5_block;
+	unsigned long i_iget5_offset;
+	unsigned int i_first_extent;
+	unsigned char i_file_format;
+	unsigned char i_format_parm[3];
+	unsigned long i_next_section_block;
+	unsigned long i_next_section_offset;
+	off_t i_section_size;
+	struct inode vfs_inode;
+};
+
+/*
+ * iso9660 super-block data in memory
+ */
+struct isofs_sb_info {
+	unsigned long s_ninodes;
+	unsigned long s_nzones;
+	unsigned long s_firstdatazone;
+	unsigned long s_log_zone_size;
+	unsigned long s_max_size;
+	
+	unsigned char s_high_sierra; /* A simple flag */
+	unsigned char s_mapping;
+	int           s_rock_offset; /* offset of SUSP fields within SU area */
+	unsigned char s_rock;
+	unsigned char s_joliet_level;
+	unsigned char s_utf8;
+	unsigned char s_cruft; /* Broken disks with high
+				  byte of length containing
+				  junk */
+	unsigned char s_unhide;
+	unsigned char s_nosuid;
+	unsigned char s_nodev;
+	unsigned char s_nocompress;
+
+	mode_t s_mode;
+	gid_t s_gid;
+	uid_t s_uid;
+	struct nls_table *s_nls_iocharset; /* Native language support table */
+};
+
+static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+static inline struct iso_inode_info *ISOFS_I(struct inode *inode)
+{
+	return container_of(inode, struct iso_inode_info, vfs_inode);
+}
+
+static inline int isonum_711(char *p)
+{
+	return *(u8 *)p;
+}
+static inline int isonum_712(char *p)
+{
+	return *(s8 *)p;
+}
+static inline unsigned int isonum_721(char *p)
+{
+	return le16_to_cpu(get_unaligned((__le16 *)p));
+}
+static inline unsigned int isonum_722(char *p)
+{
+	return be16_to_cpu(get_unaligned((__le16 *)p));
+}
+static inline unsigned int isonum_723(char *p)
+{
+	/* Ignore bigendian datum due to broken mastering programs */
+	return le16_to_cpu(get_unaligned((__le16 *)p));
+}
+static inline unsigned int isonum_731(char *p)
+{
+	return le32_to_cpu(get_unaligned((__le32 *)p));
+}
+static inline unsigned int isonum_732(char *p)
+{
+	return be32_to_cpu(get_unaligned((__le32 *)p));
+}
+static inline unsigned int isonum_733(char *p)
+{
+	/* Ignore bigendian datum due to broken mastering programs */
+	return le32_to_cpu(get_unaligned((__le32 *)p));
+}
+extern int iso_date(char *, int);
+
+struct inode;		/* To make gcc happy */
+
+extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
+extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
+
+int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
+int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
+
+extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct buffer_head *isofs_bread(struct inode *, sector_t);
+extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
+
+extern struct inode *isofs_iget(struct super_block *sb,
+                                unsigned long block,
+                                unsigned long offset);
+
+/* Because the inode number is no longer relevant to finding the
+ * underlying meta-data for an inode, we are free to choose a more
+ * convenient 32-bit number as the inode number.  The inode numbering
+ * scheme was recommended by Sergey Vlasov and Eric Lammerts. */
+static inline unsigned long isofs_get_ino(unsigned long block,
+					  unsigned long offset,
+					  unsigned long bufbits)
+{
+	return (block << (bufbits - 5)) | (offset >> 5);
+}
+
+/* Every directory can have many redundant directory entries scattered
+ * throughout the directory tree.  First there is the directory entry
+ * with the name of the directory stored in the parent directory.
+ * Then, there is the "." directory entry stored in the directory
+ * itself.  Finally, there are possibly many ".." directory entries
+ * stored in all the subdirectories.
+ *
+ * In order for the NFS get_parent() method to work and for the
+ * general consistency of the dcache, we need to make sure the
+ * "i_iget5_block" and "i_iget5_offset" all point to exactly one of
+ * the many redundant entries for each directory.  We normalize the
+ * block and offset by always making them point to the "."  directory.
+ *
+ * Notice that we do not use the entry for the directory with the name
+ * that is located in the parent directory.  Even though choosing this
+ * first directory is more natural, it is much easier to find the "."
+ * entry in the NFS get_parent() method because it is implicitly
+ * encoded in the "extent + ext_attr_length" fields of _all_ the
+ * redundant entries for the directory.  Thus, it can always be
+ * reached regardless of which directory entry you have in hand.
+ *
+ * This works because the "." entry is simply the first directory
+ * record when you start reading the file that holds all the directory
+ * records, and this file starts at "extent + ext_attr_length" blocks.
+ * Because the "." entry is always the first entry listed in the
+ * directories file, the normalized "offset" value is always 0.
+ *
+ * You should pass the directory entry in "de".  On return, "block"
+ * and "offset" will hold normalized values.  Only directories are
+ * affected making it safe to call even for non-directory file
+ * types. */
+static inline void
+isofs_normalize_block_and_offset(struct iso_directory_record* de,
+				 unsigned long *block,
+				 unsigned long *offset)
+{
+	/* Only directories are normalized. */
+	if (de->flags[0] & 2) {
+		*offset = 0;
+		*block = (unsigned long)isonum_733(de->extent)
+			+ (unsigned long)isonum_711(de->ext_attr_length);
+	}
+}
+
+extern struct inode_operations isofs_dir_inode_operations;
+extern struct file_operations isofs_dir_operations;
+extern struct address_space_operations isofs_symlink_aops;
+extern struct export_operations isofs_export_ops;
+
+/* The following macros are used to check for memory leaks. */
+#ifdef LEAK_CHECK
+#define free_s leak_check_free_s
+#define malloc leak_check_malloc
+#define sb_bread leak_check_bread
+#define brelse leak_check_brelse
+extern void * leak_check_malloc(unsigned int size);
+extern void leak_check_free_s(void * obj, int size);
+extern struct buffer_head * leak_check_bread(struct super_block *sb, int block);
+extern void leak_check_brelse(struct buffer_head * bh);
+#endif /* LEAK_CHECK */
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -6,11 +6,9 @@
  *  Joliet: Microsoft's Unicode extensions to iso9660
  */
 
-#include <linux/string.h>
+#include <linux/types.h>
 #include <linux/nls.h>
-#include <linux/mm.h>
-#include <linux/iso_fs.h>
-#include <asm/unaligned.h>
+#include "isofs.h"
 
 /*
  * Convert Unicode 16 to UTF8 or ASCII.
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -6,20 +6,9 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#include <linux/time.h>
-#include <linux/iso_fs.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
 #include <linux/config.h>	/* Joliet? */
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
-#include <linux/dcache.h>
-
-#include <asm/uaccess.h>
+#include "isofs.h"
 
 /*
  * ok, we cannot use strncmp, as the name is not in our data space.
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -6,17 +6,11 @@
  *  Rock Ridge Extensions to iso9660
  */
 
-#include <linux/stat.h>
-#include <linux/time.h>
-#include <linux/iso_fs.h>
-#include <linux/string.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
-#include <asm/page.h>
 
+#include "isofs.h"
 #include "rock.h"
 
 /* These functions are designed to read the system areas of a directory record
@@ -53,6 +47,7 @@
   if(LEN & 1) LEN++;						\
   CHR = ((unsigned char *) DE) + LEN;				\
   LEN = *((unsigned char *) DE) - LEN;                          \
+  if (LEN<0) LEN=0;                                             \
   if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1)                \
   {                                                             \
      LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset;                \
@@ -73,6 +68,10 @@
     offset1 = 0; \
     pbh = sb_bread(DEV->i_sb, block); \
     if(pbh){       \
+      if (offset > pbh->b_size || offset + cont_size > pbh->b_size){	\
+	brelse(pbh); \
+	goto out; \
+      } \
       memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
       brelse(pbh); \
       chr = (unsigned char *) buffer; \
@@ -103,12 +102,13 @@ int get_rock_ridge_filename(struct iso_d
     struct rock_ridge * rr;
     int sig;
     
-    while (len > 1){ /* There may be one byte for padding somewhere */
+    while (len > 2){ /* There may be one byte for padding somewhere */
       rr = (struct rock_ridge *) chr;
-      if (rr->len == 0) goto out; /* Something got screwed up here */
+      if (rr->len < 3) goto out; /* Something got screwed up here */
       sig = isonum_721(chr);
       chr += rr->len; 
       len -= rr->len;
+      if (len < 0) goto out;	/* corrupted isofs */
 
       switch(sig){
       case SIG('R','R'):
@@ -122,6 +122,7 @@ int get_rock_ridge_filename(struct iso_d
 	break;
       case SIG('N','M'):
 	if (truncate) break;
+	if (rr->len < 5) break;
         /*
 	 * If the flags are 2 or 4, this indicates '.' or '..'.
 	 * We don't want to do anything with this, because it
@@ -186,12 +187,13 @@ parse_rock_ridge_inode_internal(struct i
     struct rock_ridge * rr;
     int rootflag;
     
-    while (len > 1){ /* There may be one byte for padding somewhere */
+    while (len > 2){ /* There may be one byte for padding somewhere */
       rr = (struct rock_ridge *) chr;
-      if (rr->len == 0) goto out; /* Something got screwed up here */
+      if (rr->len < 3) goto out; /* Something got screwed up here */
       sig = isonum_721(chr);
       chr += rr->len; 
       len -= rr->len;
+      if (len < 0) goto out;	/* corrupted isofs */
       
       switch(sig){
 #ifndef CONFIG_ZISOFS		/* No flag for SF or ZF */
@@ -462,7 +464,7 @@ static int rock_ridge_symlink_readpage(s
 	struct rock_ridge *rr;
 
 	if (!ISOFS_SB(inode->i_sb)->s_rock)
-		panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
+		goto error;
 
 	block = ei->i_iget5_block;
 	lock_kernel();
@@ -487,13 +489,15 @@ static int rock_ridge_symlink_readpage(s
 	SETUP_ROCK_RIDGE(raw_inode, chr, len);
 
       repeat:
-	while (len > 1) { /* There may be one byte for padding somewhere */
+	while (len > 2) { /* There may be one byte for padding somewhere */
 		rr = (struct rock_ridge *) chr;
-		if (rr->len == 0)
+		if (rr->len < 3)
 			goto out;	/* Something got screwed up here */
 		sig = isonum_721(chr);
 		chr += rr->len;
 		len -= rr->len;
+		if (len < 0)
+			goto out;	/* corrupted isofs */
 
 		switch (sig) {
 		case SIG('R', 'R'):
@@ -543,6 +547,7 @@ static int rock_ridge_symlink_readpage(s
       fail:
 	brelse(bh);
 	unlock_kernel();
+      error:
 	SetPageError(page);
 	kunmap(page);
 	unlock_page(page);
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -2,9 +2,7 @@
  *  linux/fs/isofs/util.c
  */
 
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/iso_fs.h>
+#include "isofs.h"
 
 /* 
  * We have to convert from a MM/DD/YY format to the Unix ctime format.
@@ -80,4 +78,3 @@ int iso_date(char * p, int flag)
 	}
 	return crtime;
 }		
-	
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -188,7 +188,6 @@ static int __cleanup_transaction(journal
 		} else {
 			jbd_unlock_bh_state(bh);
 		}
-		jh = next_jh;
 	} while (jh != last_jh);
 
 	return ret;
@@ -339,8 +338,10 @@ int log_do_checkpoint(journal_t *journal
 			}
 		} while (jh != last_jh && !retry);
 
-		if (batch_count)
+		if (batch_count) {
 			__flush_batch(journal, bhs, &batch_count);
+			retry = 1;
+		}
 
 		/*
 		 * If someone cleaned up this transaction while we slept, we're
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -93,6 +93,73 @@ static int inverted_lock(journal_t *jour
 	return 1;
 }
 
+/* Done it all: now write the commit record.  We should have
+ * cleaned up our previous buffers by now, so if we are in abort
+ * mode we can now just skip the rest of the journal write
+ * entirely.
+ *
+ * Returns 1 if the journal needs to be aborted or 0 on success
+ */
+static int journal_write_commit_record(journal_t *journal,
+					transaction_t *commit_transaction)
+{
+	struct journal_head *descriptor;
+	struct buffer_head *bh;
+	int i, ret;
+	int barrier_done = 0;
+
+	if (is_journal_aborted(journal))
+		return 0;
+
+	descriptor = journal_get_descriptor_buffer(journal);
+	if (!descriptor)
+		return 1;
+
+	bh = jh2bh(descriptor);
+
+	/* AKPM: buglet - add `i' to tmp! */
+	for (i = 0; i < bh->b_size; i += 512) {
+		journal_header_t *tmp = (journal_header_t*)bh->b_data;
+		tmp->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER);
+		tmp->h_blocktype = cpu_to_be32(JFS_COMMIT_BLOCK);
+		tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid);
+	}
+
+	JBUFFER_TRACE(descriptor, "write commit block");
+	set_buffer_dirty(bh);
+	if (journal->j_flags & JFS_BARRIER) {
+		set_buffer_ordered(bh);
+		barrier_done = 1;
+	}
+	ret = sync_dirty_buffer(bh);
+	/* is it possible for another commit to fail at roughly
+	 * the same time as this one?  If so, we don't want to
+	 * trust the barrier flag in the super, but instead want
+	 * to remember if we sent a barrier request
+	 */
+	if (ret == -EOPNOTSUPP && barrier_done) {
+		char b[BDEVNAME_SIZE];
+
+		printk(KERN_WARNING
+			"JBD: barrier-based sync failed on %s - "
+			"disabling barriers\n",
+			bdevname(journal->j_dev, b));
+		spin_lock(&journal->j_state_lock);
+		journal->j_flags &= ~JFS_BARRIER;
+		spin_unlock(&journal->j_state_lock);
+
+		/* And try again, without the barrier */
+		clear_buffer_ordered(bh);
+		set_buffer_uptodate(bh);
+		set_buffer_dirty(bh);
+		ret = sync_dirty_buffer(bh);
+	}
+	put_bh(bh);		/* One for getblk() */
+	journal_put_journal_head(descriptor);
+
+	return (ret == -EIO);
+}
+
 /*
  * journal_commit_transaction
  *
@@ -103,7 +170,7 @@ void journal_commit_transaction(journal_
 {
 	transaction_t *commit_transaction;
 	struct journal_head *jh, *new_jh, *descriptor;
-	struct buffer_head *wbuf[64];
+	struct buffer_head **wbuf = journal->j_wbuf;
 	int bufs;
 	int flags;
 	int err;
@@ -229,6 +296,22 @@ void journal_commit_transaction(journal_
 	jbd_debug (3, "JBD: commit phase 2\n");
 
 	/*
+	 * First, drop modified flag: all accesses to the buffers
+	 * will be tracked for a new trasaction only -bzzz
+	 */
+	spin_lock(&journal->j_list_lock);
+	if (commit_transaction->t_buffers) {
+		new_jh = jh = commit_transaction->t_buffers->b_tnext;
+		do {
+			J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
+					new_jh->b_modified == 0);
+			new_jh->b_modified = 0;
+			new_jh = new_jh->b_tnext;
+		} while (new_jh != jh);
+	}
+	spin_unlock(&journal->j_list_lock);
+
+	/*
 	 * Now start flushing things to disk, in the order they appear
 	 * on the transaction lists.  Data blocks go first.
 	 */
@@ -258,7 +341,7 @@ write_out_data:
 			BUFFER_TRACE(bh, "locked");
 			if (!inverted_lock(journal, bh))
 				goto write_out_data;
-			__journal_unfile_buffer(jh);
+			__journal_temp_unlink_buffer(jh);
 			__journal_file_buffer(jh, commit_transaction,
 						BJ_Locked);
 			jbd_unlock_bh_state(bh);
@@ -271,7 +354,7 @@ write_out_data:
 				BUFFER_TRACE(bh, "start journal writeout");
 				get_bh(bh);
 				wbuf[bufs++] = bh;
-				if (bufs == ARRAY_SIZE(wbuf)) {
+				if (bufs == journal->j_wbufsize) {
 					jbd_debug(2, "submit %d writes\n",
 							bufs);
 					spin_unlock(&journal->j_list_lock);
@@ -487,7 +570,7 @@ write_out_data:
 		/* If there's no more to do, or if the descriptor is full,
 		   let the IO rip! */
 
-		if (bufs == ARRAY_SIZE(wbuf) ||
+		if (bufs == journal->j_wbufsize ||
 		    commit_transaction->t_buffers == NULL ||
 		    space_left < sizeof(journal_block_tag_t) + 16) {
 
@@ -616,79 +699,17 @@ wait_for_iobuf:
 
 	jbd_debug(3, "JBD: commit phase 6\n");
 
-	if (is_journal_aborted(journal))
-		goto skip_commit;
+	if (journal_write_commit_record(journal, commit_transaction))
+		err = -EIO;
 
-	/* Done it all: now write the commit record.  We should have
-	 * cleaned up our previous buffers by now, so if we are in abort
-	 * mode we can now just skip the rest of the journal write
-	 * entirely. */
-
-	descriptor = journal_get_descriptor_buffer(journal);
-	if (!descriptor) {
+	if (err)
 		__journal_abort_hard(journal);
-		goto skip_commit;
-	}
-
-	/* AKPM: buglet - add `i' to tmp! */
-	for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
-		journal_header_t *tmp =
-			(journal_header_t*)jh2bh(descriptor)->b_data;
-		tmp->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER);
-		tmp->h_blocktype = cpu_to_be32(JFS_COMMIT_BLOCK);
-		tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid);
-	}
-
-	JBUFFER_TRACE(descriptor, "write commit block");
-	{
-		struct buffer_head *bh = jh2bh(descriptor);
-		int ret;
-		int barrier_done = 0;
-
-		set_buffer_dirty(bh);
-		if (journal->j_flags & JFS_BARRIER) {
-			set_buffer_ordered(bh);
-			barrier_done = 1;
-		}
-		ret = sync_dirty_buffer(bh);
-		/* is it possible for another commit to fail at roughly
-		 * the same time as this one?  If so, we don't want to
-		 * trust the barrier flag in the super, but instead want
-		 * to remember if we sent a barrier request
-		 */
-		if (ret == -EOPNOTSUPP && barrier_done) {
-			char b[BDEVNAME_SIZE];
-
-			printk(KERN_WARNING
-				"JBD: barrier-based sync failed on %s - "
-				"disabling barriers\n",
-				bdevname(journal->j_dev, b));
-			spin_lock(&journal->j_state_lock);
-			journal->j_flags &= ~JFS_BARRIER;
-			spin_unlock(&journal->j_state_lock);
-
-			/* And try again, without the barrier */
-			clear_buffer_ordered(bh);
-			set_buffer_uptodate(bh);
-			set_buffer_dirty(bh);
-			ret = sync_dirty_buffer(bh);
-		}
-		if (unlikely(ret == -EIO))
-			err = -EIO;
-		put_bh(bh);		/* One for getblk() */
-		journal_put_journal_head(descriptor);
-	}
 
 	/* 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: /* The journal should be unlocked by now. */
-
-	if (err)
-		__journal_abort_hard(journal);
-
 	jbd_debug(3, "JBD: commit phase 7\n");
 
 	J_ASSERT(commit_transaction->t_sync_datalist == NULL);
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -721,6 +721,7 @@ journal_t * journal_init_dev(struct bloc
 {
 	journal_t *journal = journal_init_common();
 	struct buffer_head *bh;
+	int n;
 
 	if (!journal)
 		return NULL;
@@ -736,6 +737,17 @@ journal_t * journal_init_dev(struct bloc
 	journal->j_sb_buffer = bh;
 	journal->j_superblock = (journal_superblock_t *)bh->b_data;
 
+	/* journal descriptor can store up to n blocks -bzzz */
+	n = journal->j_blocksize / sizeof(journal_block_tag_t);
+	journal->j_wbufsize = n;
+	journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+	if (!journal->j_wbuf) {
+		printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+			__FUNCTION__);
+		kfree(journal);
+		journal = NULL;
+	}
+
 	return journal;
 }
  
@@ -752,6 +764,7 @@ journal_t * journal_init_inode (struct i
 	struct buffer_head *bh;
 	journal_t *journal = journal_init_common();
 	int err;
+	int n;
 	unsigned long blocknr;
 
 	if (!journal)
@@ -768,6 +781,17 @@ journal_t * journal_init_inode (struct i
 	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
 	journal->j_blocksize = inode->i_sb->s_blocksize;
 
+	/* journal descriptor can store up to n blocks -bzzz */
+	n = journal->j_blocksize / sizeof(journal_block_tag_t);
+	journal->j_wbufsize = n;
+	journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+	if (!journal->j_wbuf) {
+		printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+			__FUNCTION__);
+		kfree(journal);
+		return NULL;
+	}
+
 	err = journal_bmap(journal, 0, &blocknr);
 	/* If that failed, give up */
 	if (err) {
@@ -1141,12 +1165,17 @@ void journal_destroy(journal_t *journal)
 		iput(journal->j_inode);
 	if (journal->j_revoke)
 		journal_destroy_revoke(journal);
+	kfree(journal->j_wbuf);
 	kfree(journal);
 }
 
 
 /**
  *int journal_check_used_features () - Check if features specified are used.
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
  * 
  * Check whether the journal uses all of a given set of
  * features.  Return true (non-zero) if it does. 
@@ -1174,6 +1203,10 @@ int journal_check_used_features (journal
 
 /**
  * int journal_check_available_features() - Check feature set in journalling layer
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
  * 
  * Check whether the journaling code supports the use of
  * all of a given set of features on this journal.  Return true
@@ -1206,6 +1239,10 @@ int journal_check_available_features (jo
 
 /**
  * int journal_set_features () - Mark a given journal feature in the superblock
+ * @journal: Journal to act on.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
  *
  * Mark a given journal feature as present on the
  * superblock.  Returns true if the requested features could be set. 
@@ -1238,6 +1275,7 @@ int journal_set_features (journal_t *jou
 
 /**
  * int journal_update_format () - Update on-disk journal structure.
+ * @journal: Journal to act on.
  *
  * Given an initialised but unloaded journal struct, poke about in the
  * on-disk structure to update it to the most recent supported version.
@@ -1538,6 +1576,7 @@ int journal_errno(journal_t *journal)
 
 /** 
  * int journal_clear_err () - clears the journal's error state
+ * @journal: journal to act on.
  *
  * An error must be cleared or Acked to take a FS out of readonly
  * mode.
@@ -1557,6 +1596,7 @@ int journal_clear_err(journal_t *journal
 
 /** 
  * void journal_ack_err() - Ack journal err.
+ * @journal: journal to act on.
  *
  * An error must be cleared or Acked to take a FS out of readonly
  * mode.
@@ -1575,11 +1615,7 @@ int journal_blocks_per_page(struct inode
 }
 
 /*
- * Simple support for retying memory allocations.  Introduced to help to
- * debug different VM deadlock avoidance strategies. 
- */
-/*
- * Simple support for retying memory allocations.  Introduced to help to
+ * Simple support for retrying memory allocations.  Introduced to help to
  * debug different VM deadlock avoidance strategies. 
  */
 void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry)
@@ -1767,6 +1803,7 @@ static void __journal_remove_journal_hea
 		if (jh->b_transaction == NULL &&
 				jh->b_next_transaction == NULL &&
 				jh->b_cp_transaction == NULL) {
+			J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
 			J_ASSERT_BH(bh, buffer_jbd(bh));
 			J_ASSERT_BH(bh, jh2bh(jh) == bh);
 			BUFFER_TRACE(bh, "remove journal_head");
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -522,7 +522,7 @@ static void jbd_unexpected_dirty_buffer(
  */
 static int
 do_get_write_access(handle_t *handle, struct journal_head *jh,
-			int force_copy, int *credits) 
+			int force_copy)
 {
 	struct buffer_head *bh;
 	transaction_t *transaction;
@@ -604,11 +604,6 @@ repeat:
 		JBUFFER_TRACE(jh, "has frozen data");
 		J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
 		jh->b_next_transaction = transaction;
-
-		J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
-		handle->h_buffer_credits--;
-		if (credits)
-			(*credits)++;
 		goto done;
 	}
 
@@ -688,10 +683,6 @@ repeat:
 		jh->b_next_transaction = transaction;
 	}
 
-	J_ASSERT(handle->h_buffer_credits > 0);
-	handle->h_buffer_credits--;
-	if (credits)
-		(*credits)++;
 
 	/*
 	 * Finally, if the buffer is not journaled right now, we need to make
@@ -742,6 +733,7 @@ out:
  * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
  * @handle: transaction to add buffer modifications to
  * @bh:     bh to be used for metadata writes
+ * @credits: variable that will receive credits for the buffer
  *
  * Returns an error code or 0 on success.
  *
@@ -749,8 +741,7 @@ out:
  * because we're write()ing a buffer which is also part of a shared mapping.
  */
 
-int journal_get_write_access(handle_t *handle,
-			struct buffer_head *bh, int *credits)
+int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
 {
 	struct journal_head *jh = journal_add_journal_head(bh);
 	int rc;
@@ -758,7 +749,7 @@ int journal_get_write_access(handle_t *h
 	/* We do not want to get caught playing with fields which the
 	 * log thread also manipulates.  Make sure that the buffer
 	 * completes any outstanding IO before proceeding. */
-	rc = do_get_write_access(handle, jh, 0, credits);
+	rc = do_get_write_access(handle, jh, 0);
 	journal_put_journal_head(jh);
 	return rc;
 }
@@ -814,9 +805,6 @@ int journal_get_create_access(handle_t *
 	J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
 	J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
 
-	J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
-	handle->h_buffer_credits--;
-
 	if (jh->b_transaction == NULL) {
 		jh->b_transaction = transaction;
 		JBUFFER_TRACE(jh, "file as BJ_Reserved");
@@ -869,8 +857,7 @@ out:
  *
  * Returns error number or 0 on success.
  */
-int journal_get_undo_access(handle_t *handle, struct buffer_head *bh,
-				int *credits)
+int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
 {
 	int err;
 	struct journal_head *jh = journal_add_journal_head(bh);
@@ -883,7 +870,7 @@ int journal_get_undo_access(handle_t *ha
 	 * make sure that obtaining the committed_data is done
 	 * atomically wrt. completion of any outstanding commits.
 	 */
-	err = do_get_write_access(handle, jh, 1, credits);
+	err = do_get_write_access(handle, jh, 1);
 	if (err)
 		goto out;
 
@@ -1044,7 +1031,12 @@ int journal_dirty_data(handle_t *handle,
 			/* journal_clean_data_list() may have got there first */
 			if (jh->b_transaction != NULL) {
 				JBUFFER_TRACE(jh, "unfile from commit");
-				__journal_unfile_buffer(jh);
+				__journal_temp_unlink_buffer(jh);
+				/* It still points to the committing
+				 * transaction; move it to this one so
+				 * that the refile assert checks are
+				 * happy. */
+				jh->b_transaction = handle->h_transaction;
 			}
 			/* The buffer will be refiled below */
 
@@ -1058,7 +1050,8 @@ int journal_dirty_data(handle_t *handle,
 		if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
 			JBUFFER_TRACE(jh, "not on correct data list: unfile");
 			J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
-			__journal_unfile_buffer(jh);
+			__journal_temp_unlink_buffer(jh);
+			jh->b_transaction = handle->h_transaction;
 			JBUFFER_TRACE(jh, "file as data");
 			__journal_file_buffer(jh, handle->h_transaction,
 						BJ_SyncData);
@@ -1111,6 +1104,17 @@ int journal_dirty_metadata(handle_t *han
 
 	jbd_lock_bh_state(bh);
 
+	if (jh->b_modified == 0) {
+		/*
+		 * This buffer's got modified and becoming part
+		 * of the transaction. This needs to be done
+		 * once a transaction -bzzz
+		 */
+		jh->b_modified = 1;
+		J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
+		handle->h_buffer_credits--;
+	}
+
 	/*
 	 * fastpath, to avoid expensive locking.  If this buffer is already
 	 * on the running transaction's metadata list there is nothing to do.
@@ -1161,24 +1165,11 @@ out:
  * journal_release_buffer: undo a get_write_access without any buffer
  * updates, if the update decided in the end that it didn't need access.
  *
- * The caller passes in the number of credits which should be put back for
- * this buffer (zero or one).
- *
- * We leave the buffer attached to t_reserved_list because even though this
- * handle doesn't want it, some other concurrent handle may want to journal
- * this buffer.  If that handle is curently in between get_write_access() and
- * journal_dirty_metadata() then it expects the buffer to be reserved.  If
- * we were to rip it off t_reserved_list here, the other handle will explode
- * when journal_dirty_metadata is presented with a non-reserved buffer.
- *
- * If nobody really wants to journal this buffer then it will be thrown
- * away at the start of commit.
  */
 void
-journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
+journal_release_buffer(handle_t *handle, struct buffer_head *bh)
 {
 	BUFFER_TRACE(bh, "entry");
-	handle->h_buffer_credits += credits;
 }
 
 /** 
@@ -1203,6 +1194,7 @@ int journal_forget (handle_t *handle, st
 	transaction_t *transaction = handle->h_transaction;
 	journal_t *journal = transaction->t_journal;
 	struct journal_head *jh;
+	int drop_reserve = 0;
 	int err = 0;
 
 	BUFFER_TRACE(bh, "entry");
@@ -1222,6 +1214,12 @@ int journal_forget (handle_t *handle, st
 		goto not_jbd;
 	}
 
+	/*
+	 * The buffer's going from the transaction, we must drop
+	 * all references -bzzz
+	 */
+	jh->b_modified = 0;
+
 	if (jh->b_transaction == handle->h_transaction) {
 		J_ASSERT_JH(jh, !jh->b_frozen_data);
 
@@ -1233,7 +1231,7 @@ int journal_forget (handle_t *handle, st
 
 		JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
 
-		__journal_unfile_buffer(jh);
+		drop_reserve = 1;
 
 		/* 
 		 * We are no longer going to journal this buffer.
@@ -1248,15 +1246,17 @@ int journal_forget (handle_t *handle, st
 		 */
 
 		if (jh->b_cp_transaction) {
+			__journal_temp_unlink_buffer(jh);
 			__journal_file_buffer(jh, transaction, BJ_Forget);
 		} else {
+			__journal_unfile_buffer(jh);
 			journal_remove_journal_head(bh);
 			__brelse(bh);
 			if (!buffer_jbd(bh)) {
 				spin_unlock(&journal->j_list_lock);
 				jbd_unlock_bh_state(bh);
 				__bforget(bh);
-				return 0;
+				goto drop;
 			}
 		}
 	} else if (jh->b_transaction) {
@@ -1271,6 +1271,7 @@ int journal_forget (handle_t *handle, st
 		if (jh->b_next_transaction) {
 			J_ASSERT(jh->b_next_transaction == transaction);
 			jh->b_next_transaction = NULL;
+			drop_reserve = 1;
 		}
 	}
 
@@ -1278,6 +1279,11 @@ not_jbd:
 	spin_unlock(&journal->j_list_lock);
 	jbd_unlock_bh_state(bh);
 	__brelse(bh);
+drop:
+	if (drop_reserve) {
+		/* no need to reserve log space for this block -bzzz */
+		handle->h_buffer_credits++;
+	}
 	return err;
 }
 
@@ -1469,7 +1475,7 @@ __blist_del_buffer(struct journal_head *
  *
  * Called under j_list_lock.  The journal may not be locked.
  */
-void __journal_unfile_buffer(struct journal_head *jh)
+void __journal_temp_unlink_buffer(struct journal_head *jh)
 {
 	struct journal_head **list = NULL;
 	transaction_t *transaction;
@@ -1486,7 +1492,7 @@ void __journal_unfile_buffer(struct jour
 
 	switch (jh->b_jlist) {
 	case BJ_None:
-		goto out;
+		return;
 	case BJ_SyncData:
 		list = &transaction->t_sync_datalist;
 		break;
@@ -1519,7 +1525,11 @@ void __journal_unfile_buffer(struct jour
 	jh->b_jlist = BJ_None;
 	if (test_clear_buffer_jbddirty(bh))
 		mark_buffer_dirty(bh);	/* Expose it to the VM */
-out:
+}
+
+void __journal_unfile_buffer(struct journal_head *jh)
+{
+	__journal_temp_unlink_buffer(jh);
 	jh->b_transaction = NULL;
 }
 
@@ -1578,7 +1588,7 @@ out:
  * int journal_try_to_free_buffers() - try to free page buffers.
  * @journal: journal for operation
  * @page: to try and free
- * @gfp_mask: 'IO' mode for try_to_free_buffers()
+ * @unused_gfp_mask: unused
  *
  * 
  * For all the buffers on this page,
@@ -1775,10 +1785,10 @@ static int journal_unmap_buffer(journal_
 			JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget");
 			ret = __dispose_buffer(jh,
 					journal->j_running_transaction);
+			journal_put_journal_head(jh);
 			spin_unlock(&journal->j_list_lock);
 			jbd_unlock_bh_state(bh);
 			spin_unlock(&journal->j_state_lock);
-			journal_put_journal_head(jh);
 			return ret;
 		} else {
 			/* There is no currently-running transaction. So the
@@ -1789,10 +1799,10 @@ static int journal_unmap_buffer(journal_
 				JBUFFER_TRACE(jh, "give to committing trans");
 				ret = __dispose_buffer(jh,
 					journal->j_committing_transaction);
+				journal_put_journal_head(jh);
 				spin_unlock(&journal->j_list_lock);
 				jbd_unlock_bh_state(bh);
 				spin_unlock(&journal->j_state_lock);
-				journal_put_journal_head(jh);
 				return ret;
 			} else {
 				/* The orphan record's transaction has
@@ -1802,7 +1812,17 @@ static int journal_unmap_buffer(journal_
 			}
 		}
 	} else if (transaction == journal->j_committing_transaction) {
-		/* If it is committing, we simply cannot touch it.  We
+		if (jh->b_jlist == BJ_Locked) {
+			/*
+			 * The buffer is on the committing transaction's locked
+			 * list.  We have the buffer locked, so I/O has
+			 * completed.  So we can nail the buffer now.
+			 */
+			may_free = __dispose_buffer(jh, transaction);
+			goto zap_buffer;
+		}
+		/*
+		 * If it is committing, we simply cannot touch it.  We
 		 * can remove it's next_transaction pointer from the
 		 * running transaction if that is set, but nothing
 		 * else. */
@@ -1813,10 +1833,10 @@ static int journal_unmap_buffer(journal_
 					journal->j_running_transaction);
 			jh->b_next_transaction = NULL;
 		}
+		journal_put_journal_head(jh);
 		spin_unlock(&journal->j_list_lock);
 		jbd_unlock_bh_state(bh);
 		spin_unlock(&journal->j_state_lock);
-		journal_put_journal_head(jh);
 		return 0;
 	} else {
 		/* Good, the buffer belongs to the running transaction.
@@ -1877,7 +1897,6 @@ int journal_invalidatepage(journal_t *jo
 		unsigned int next_off = curr_off + bh->b_size;
 		next = bh->b_this_page;
 
-		/* AKPM: doing lock_buffer here may be overly paranoid */
 		if (offset <= curr_off) {
 		 	/* This block is wholly outside the truncation point */
 			lock_buffer(bh);
@@ -1929,7 +1948,7 @@ void __journal_file_buffer(struct journa
 	}
 
 	if (jh->b_transaction)
-		__journal_unfile_buffer(jh);
+		__journal_temp_unlink_buffer(jh);
 	jh->b_transaction = transaction;
 
 	switch (jlist) {
@@ -2012,7 +2031,7 @@ void __journal_refile_buffer(struct jour
 	 */
 
 	was_dirty = test_clear_buffer_jbddirty(bh);
-	__journal_unfile_buffer(jh);
+	__journal_temp_unlink_buffer(jh);
 	jh->b_transaction = jh->b_next_transaction;
 	jh->b_next_transaction = NULL;
 	__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -334,7 +334,7 @@ out:
 } /* jffs_notify_change()  */
 
 
-struct inode *
+static struct inode *
 jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
 	       int * err)
 {
@@ -376,7 +376,7 @@ jffs_new_inode(const struct inode * dir,
 }
 
 /* Get statistics of the file system.  */
-int
+static int
 jffs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct jffs_control *c = (struct jffs_control *) sb->s_fs_info;
@@ -410,7 +410,7 @@ jffs_statfs(struct super_block *sb, stru
 
 
 /* Rename a file.  */
-int
+static int
 jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	    struct inode *new_dir, struct dentry *new_dentry)
 {
@@ -1739,7 +1739,7 @@ jffs_read_inode(struct inode *inode)
 }
 
 
-void
+static void
 jffs_delete_inode(struct inode *inode)
 {
 	struct jffs_file *f;
@@ -1762,7 +1762,7 @@ jffs_delete_inode(struct inode *inode)
 }
 
 
-void
+static void
 jffs_write_super(struct super_block *sb)
 {
 	struct jffs_control *c = (struct jffs_control *)sb->s_fs_info;
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -72,7 +72,7 @@
 #include "jffs_fm.h"
 
 long no_jffs_node = 0;
-long no_jffs_file = 0;
+static long no_jffs_file = 0;
 #if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG
 long no_jffs_control = 0;
 long no_jffs_raw_inode = 0;
@@ -85,6 +85,32 @@ long no_name = 0;
 
 static int jffs_scan_flash(struct jffs_control *c);
 static int jffs_update_file(struct jffs_file *f, struct jffs_node *node);
+static int jffs_build_file(struct jffs_file *f);
+static int jffs_free_file(struct jffs_file *f);
+static int jffs_free_node_list(struct jffs_file *f);
+static int jffs_garbage_collect_now(struct jffs_control *c);
+static int jffs_insert_file_into_hash(struct jffs_file *f);
+static int jffs_remove_redundant_nodes(struct jffs_file *f);
+
+/* Is there enough space on the flash?  */
+static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c, __u32 space)
+{
+	struct jffs_fmcontrol *fmc = c->fmc;
+
+	while (1) {
+		if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size))
+			>= fmc->min_free_size + space) {
+			return 1;
+		}
+		if (fmc->dirty_size < fmc->sector_size)
+			return 0;
+
+		if (jffs_garbage_collect_now(c)) {
+		  D1(printk("JFFS_ENOUGH_SPACE: jffs_garbage_collect_now() failed.\n"));
+		  return 0;
+		}
+	}
+}
 
 #if CONFIG_JFFS_FS_VERBOSE > 0
 static __u8
@@ -331,7 +357,7 @@ flash_erase_region(struct mtd_info *mtd,
 }
 
 /* This routine calculates checksums in JFFS.  */
-__u32
+static __u32
 jffs_checksum(const void *data, int size)
 {
 	__u32 sum = 0;
@@ -344,7 +370,7 @@ jffs_checksum(const void *data, int size
 }
 
 
-int
+static int
 jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result)
 {
 	__u32 sum = 0;
@@ -646,7 +672,7 @@ jffs_build_fs_fail:
   a (even) higher degree of confidence in your mount process. 
   A higher number would of course slow down your mount.
 */
-int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){
+static int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){
 
 #define NUM_REREADS             4 /* see note above */
 #define READ_AHEAD_BYTES        4096 /* must be a multiple of 4, 
@@ -1478,7 +1504,7 @@ jffs_classify_node(struct jffs_node *nod
 
 /* Remove redundant nodes from a file.  Mark the on-flash memory
    as dirty.  */
-int
+static int
 jffs_remove_redundant_nodes(struct jffs_file *f)
 {
 	struct jffs_node *newest_node;
@@ -1532,7 +1558,7 @@ jffs_remove_redundant_nodes(struct jffs_
 
 
 /* Insert a file into the hash table.  */
-int
+static int
 jffs_insert_file_into_hash(struct jffs_file *f)
 {
 	int i = f->ino % f->c->hash_len;
@@ -1580,7 +1606,7 @@ jffs_insert_file_into_tree(struct jffs_f
 
 
 /* Remove a file from the hash table.  */
-int
+static int
 jffs_unlink_file_from_hash(struct jffs_file *f)
 {
 	D3(printk("jffs_unlink_file_from_hash(): f: 0x%p, "
@@ -2038,7 +2064,7 @@ jffs_foreach_file(struct jffs_control *c
 
 
 /* Free all nodes associated with a file.  */
-int
+static int
 jffs_free_node_list(struct jffs_file *f)
 {
 	struct jffs_node *node;
@@ -2058,7 +2084,7 @@ jffs_free_node_list(struct jffs_file *f)
 
 
 /* Free a file and its name.  */
-int
+static int
 jffs_free_file(struct jffs_file *f)
 {
 	D3(printk("jffs_free_file: f #%u, \"%s\"\n",
@@ -2073,7 +2099,7 @@ jffs_free_file(struct jffs_file *f)
 	return 0;
 }
 
-long
+static long
 jffs_get_file_count(void)
 {
 	return no_jffs_file;
@@ -2127,7 +2153,7 @@ jffs_file_count(struct jffs_file *f)
 
 /* Build up a file's range list from scratch by going through the
    version list.  */
-int
+static int
 jffs_build_file(struct jffs_file *f)
 {
 	struct jffs_node *n;
@@ -2481,7 +2507,6 @@ jffs_update_file(struct jffs_file *f, st
 	return 0;
 }
 
-
 /* Print the contents of a node.  */
 void
 jffs_print_node(struct jffs_node *n)
@@ -2541,6 +2566,7 @@ jffs_print_raw_inode(struct jffs_raw_ino
 
 
 /* Print the contents of a file.  */
+#if 0
 int
 jffs_print_file(struct jffs_file *f)
 {
@@ -2580,7 +2606,7 @@ jffs_print_file(struct jffs_file *f)
 	D(printk("}\n"));
 	return 0;
 }
-
+#endif  /*  0  */
 
 void
 jffs_print_hash_table(struct jffs_control *c)
@@ -2655,7 +2681,7 @@ jffs_print_memory_allocation_statistics(
 
 
 /* Rewrite `size' bytes, and begin at `node'.  */
-int
+static int
 jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, __u32 size)
 {
 	struct jffs_control *c = f->c;
@@ -2858,7 +2884,7 @@ retry:
    process and is often called multiple times at each occasion of a
    garbage collect.  */
 
-int
+static int
 jffs_garbage_collect_next(struct jffs_control *c)
 {
 	struct jffs_fmcontrol *fmc = c->fmc;
@@ -3097,7 +3123,7 @@ jffs_clear_end_of_node(struct jffs_contr
 } /* jffs_clear_end_of_node()  */
 
 /* Try to erase as much as possible of the dirt in the flash memory.  */
-long
+static long
 jffs_try_to_erase(struct jffs_control *c)
 {
 	struct jffs_fmcontrol *fmc = c->fmc;
@@ -3198,7 +3224,7 @@ jffs_try_to_erase(struct jffs_control *c
    collection can be.  */
 
 
-int
+static int
 jffs_garbage_collect_now(struct jffs_control *c)
 {
 	struct jffs_fmcontrol *fmc = c->fmc;
diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h
--- a/fs/jffs/intrep.h
+++ b/fs/jffs/intrep.h
@@ -20,9 +20,6 @@
 struct jffs_node *jffs_alloc_node(void);
 void jffs_free_node(struct jffs_node *n);
 int jffs_get_node_inuse(void);
-long jffs_get_file_count(void);
-
-__u32 jffs_checksum(const void *data, int size);
 
 void jffs_cleanup_control(struct jffs_control *c);
 int jffs_build_fs(struct super_block *sb);
@@ -36,15 +33,9 @@ struct jffs_file *jffs_find_child(struct
 void jffs_free_node(struct jffs_node *node);
 
 int jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *));
-int jffs_free_node_list(struct jffs_file *f);
-int jffs_free_file(struct jffs_file *f);
 int jffs_possibly_delete_file(struct jffs_file *f);
-int jffs_build_file(struct jffs_file *f);
-int jffs_insert_file_into_hash(struct jffs_file *f);
 int jffs_insert_file_into_tree(struct jffs_file *f);
-int jffs_unlink_file_from_hash(struct jffs_file *f);
 int jffs_unlink_file_from_tree(struct jffs_file *f);
-int jffs_remove_redundant_nodes(struct jffs_file *f);
 int jffs_file_count(struct jffs_file *f);
 
 int jffs_write_node(struct jffs_control *c, struct jffs_node *node,
@@ -56,32 +47,13 @@ int jffs_read_data(struct jffs_file *f, 
 /* Garbage collection stuff.  */
 int jffs_garbage_collect_thread(void *c);
 void jffs_garbage_collect_trigger(struct jffs_control *c);
-int jffs_garbage_collect_now(struct jffs_control *c);
-
-/* Is there enough space on the flash?  */
-static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c, __u32 space)
-{
-	struct jffs_fmcontrol *fmc = c->fmc;
-
-	while (1) {
-		if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size)) 
-			>= fmc->min_free_size + space) {
-			return 1;
-		}
-		if (fmc->dirty_size < fmc->sector_size)
-			return 0;
-
-		if (jffs_garbage_collect_now(c)) {
-		  D1(printk("JFFS_ENOUGH_SPACE: jffs_garbage_collect_now() failed.\n"));
-		  return 0;
-		}
-	}
-}
 
 /* For debugging purposes.  */
 void jffs_print_node(struct jffs_node *n);
 void jffs_print_raw_inode(struct jffs_raw_inode *raw_inode);
+#if 0
 int jffs_print_file(struct jffs_file *f);
+#endif  /*  0  */
 void jffs_print_hash_table(struct jffs_control *c);
 void jffs_print_tree(struct jffs_file *first_file, int indent);
 
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -25,6 +25,9 @@
 static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset);
 #endif
 
+static struct jffs_fm *jffs_alloc_fm(void);
+static void jffs_free_fm(struct jffs_fm *n);
+
 extern kmem_cache_t     *fm_cache;
 extern kmem_cache_t     *node_cache;
 
@@ -602,7 +605,7 @@ jffs_mark_obsolete(struct jffs_fmcontrol
 /* check if it's possible to erase the wanted range, and if not, return
  * the range that IS erasable, or a negative error code.
  */
-long
+static long
 jffs_flash_erasable_size(struct mtd_info *mtd, __u32 offset, __u32 size)
 {
          u_long ssize;
@@ -700,7 +703,7 @@ jffs_erasable_size(struct jffs_fmcontrol
 	return (ret >= 0 ? ret : 0);
 }
 
-struct jffs_fm *jffs_alloc_fm(void)
+static struct jffs_fm *jffs_alloc_fm(void)
 {
 	struct jffs_fm *fm;
 
@@ -710,7 +713,7 @@ struct jffs_fm *jffs_alloc_fm(void)
 	return fm;
 }
 
-void jffs_free_fm(struct jffs_fm *n)
+static void jffs_free_fm(struct jffs_fm *n)
 {
 	kmem_cache_free(fm_cache,n);
 	DJM(no_jffs_fm--);
@@ -778,6 +781,7 @@ jffs_print_fm(struct jffs_fm *fm)
 	D(printk("}\n"));
 }
 
+#if 0
 void
 jffs_print_node_ref(struct jffs_node_ref *ref)
 {
@@ -787,3 +791,5 @@ jffs_print_node_ref(struct jffs_node_ref
 	D(printk("       0x%p, /* next  */\n", ref->next));
 	D(printk("}\n"));
 }
+#endif  /*  0  */
+
diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h
--- a/fs/jffs/jffs_fm.h
+++ b/fs/jffs/jffs_fm.h
@@ -64,10 +64,6 @@
 
 
 
-void jffs_free_fm(struct jffs_fm *n);
-struct jffs_fm *jffs_alloc_fm(void);
-
-
 struct jffs_node_ref
 {
 	struct jffs_node *node;
@@ -145,6 +141,8 @@ void jffs_fmfree_partly(struct jffs_fmco
 
 void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc);
 void jffs_print_fm(struct jffs_fm *fm);
+#if 0
 void jffs_print_node_ref(struct jffs_node_ref *ref);
+#endif  /*  0  */
 
 #endif /* __LINUX_JFFS_FM_H__  */
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -23,16 +23,6 @@ static LIST_HEAD(jffs2_compressor_list);
 /* Actual compression mode */
 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
 
-void jffs2_set_compression_mode(int mode) 
-{
-        jffs2_compression_mode = mode;
-}
-
-int jffs2_get_compression_mode(void)
-{
-        return jffs2_compression_mode;
-}
-
 /* Statistics for blocks stored without compression */
 static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
 
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
--- a/fs/jffs2/compr.h
+++ b/fs/jffs2/compr.h
@@ -41,9 +41,6 @@
 #define JFFS2_COMPR_MODE_PRIORITY   1
 #define JFFS2_COMPR_MODE_SIZE       2
 
-void jffs2_set_compression_mode(int mode);
-int jffs2_get_compression_mode(void);
-
 struct jffs2_compressor {
         struct list_head list;
         int priority;              /* used by prirority comr. mode */
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
--- a/fs/jffs2/compr_rtime.c
+++ b/fs/jffs2/compr_rtime.c
@@ -29,8 +29,10 @@
 #include "compr.h"
 
 /* _compress returns the compressed size, -1 if bigger */
-int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
+static int jffs2_rtime_compress(unsigned char *data_in,
+				unsigned char *cpage_out,
+				uint32_t *sourcelen, uint32_t *dstlen,
+				void *model)
 {
 	short positions[256];
 	int outpos = 0;
@@ -69,8 +71,10 @@ int jffs2_rtime_compress(unsigned char *
 }		   
 
 
-int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen, void *model)
+static int jffs2_rtime_decompress(unsigned char *data_in,
+				  unsigned char *cpage_out,
+				  uint32_t srclen, uint32_t destlen,
+				  void *model)
 {
 	short positions[256];
 	int outpos = 0;
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c
--- a/fs/jffs2/compr_rubin.c
+++ b/fs/jffs2/compr_rubin.c
@@ -228,8 +228,10 @@ int jffs2_rubinmips_compress(unsigned ch
 	return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
 }
 #endif
-int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
+static int jffs2_dynrubin_compress(unsigned char *data_in,
+				   unsigned char *cpage_out,
+				   uint32_t *sourcelen, uint32_t *dstlen,
+				   void *model)
 {
 	int bits[8];
 	unsigned char histo[256];
@@ -306,15 +308,19 @@ static void rubin_do_decompress(int bit_
 }		   
 
 
-int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t sourcelen, uint32_t dstlen, void *model)
+static int jffs2_rubinmips_decompress(unsigned char *data_in,
+				      unsigned char *cpage_out,
+				      uint32_t sourcelen, uint32_t dstlen,
+				      void *model)
 {
 	rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
         return 0;
 }
 
-int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t sourcelen, uint32_t dstlen, void *model)
+static int jffs2_dynrubin_decompress(unsigned char *data_in,
+				     unsigned char *cpage_out,
+				     uint32_t sourcelen, uint32_t dstlen,
+				     void *model)
 {
 	int bits[8];
 	int c;
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -69,8 +69,10 @@ static void free_workspaces(void)
 #define free_workspaces() do { } while(0)
 #endif /* __KERNEL__ */
 
-int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
+static int jffs2_zlib_compress(unsigned char *data_in,
+			       unsigned char *cpage_out,
+			       uint32_t *sourcelen, uint32_t *dstlen,
+			       void *model)
 {
 	int ret;
 
@@ -135,8 +137,10 @@ int jffs2_zlib_compress(unsigned char *d
 	return ret;
 }
 
-int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen, void *model)
+static int jffs2_zlib_decompress(unsigned char *data_in,
+				 unsigned char *cpage_out,
+				 uint32_t srclen, uint32_t destlen,
+				 void *model)
 {
 	int ret;
 	int wbits = MAX_WBITS;
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -33,7 +33,8 @@ static void jffs2_erase_succeeded(struct
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 
-void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_block(struct jffs2_sb_info *c,
+			      struct jffs2_eraseblock *jeb)
 {
 	int ret;
 	uint32_t bad_offset;
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -25,6 +25,11 @@
 extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
 
+static int jffs2_commit_write (struct file *filp, struct page *pg,
+			       unsigned start, unsigned end);
+static int jffs2_prepare_write (struct file *filp, struct page *pg,
+				unsigned start, unsigned end);
+static int jffs2_readpage (struct file *filp, struct page *pg);
 
 int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
@@ -65,7 +70,7 @@ struct address_space_operations jffs2_fi
 	.commit_write =	jffs2_commit_write
 };
 
-int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
+static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
 {
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
@@ -74,8 +79,7 @@ int jffs2_do_readpage_nolock (struct ino
 
 	D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
 
-	if (!PageLocked(pg))
-                PAGE_BUG(pg);
+	BUG_ON(!PageLocked(pg));
 
 	pg_buf = kmap(pg);
 	/* FIXME: Can kmap fail? */
@@ -105,7 +109,7 @@ int jffs2_do_readpage_unlock(struct inod
 }
 
 
-int jffs2_readpage (struct file *filp, struct page *pg)
+static int jffs2_readpage (struct file *filp, struct page *pg)
 {
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
 	int ret;
@@ -116,7 +120,8 @@ int jffs2_readpage (struct file *filp, s
 	return ret;
 }
 
-int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
+static int jffs2_prepare_write (struct file *filp, struct page *pg,
+				unsigned start, unsigned end)
 {
 	struct inode *inode = pg->mapping->host;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -198,7 +203,8 @@ int jffs2_prepare_write (struct file *fi
 	return ret;
 }
 
-int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
+static int jffs2_commit_write (struct file *filp, struct page *pg,
+			       unsigned start, unsigned end)
 {
 	/* 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
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -25,6 +25,7 @@
 #include <linux/crc32.h>
 #include "nodelist.h"
 
+static int jffs2_flash_setup(struct jffs2_sb_info *c);
 
 static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
 {
@@ -644,7 +645,7 @@ void jffs2_gc_release_page(struct jffs2_
 	page_cache_release(pg);
 }
 
-int jffs2_flash_setup(struct jffs2_sb_info *c) {
+static int jffs2_flash_setup(struct jffs2_sb_info *c) {
 	int ret = 0;
 	
 	if (jffs2_cleanmarker_oob(c)) {
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -460,7 +460,6 @@ void jffs2_rotate_lists(struct jffs2_sb_
 int jffs2_do_mount_fs(struct jffs2_sb_info *c);
 
 /* erase.c */
-void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
 
 #ifdef CONFIG_JFFS2_FS_NAND
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -173,11 +173,7 @@ extern struct file_operations jffs2_file
 extern struct inode_operations jffs2_file_inode_operations;
 extern struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, struct dentry *, int);
-int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
-int jffs2_readpage (struct file *, struct page *);
-int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
-int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
 
 /* ioctl.c */
 int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
@@ -208,7 +204,6 @@ unsigned char *jffs2_gc_fetch_page(struc
 void jffs2_gc_release_page(struct jffs2_sb_info *c,
 			   unsigned char *pg,
 			   unsigned long *priv);
-int jffs2_flash_setup(struct jffs2_sb_info *c);
 void jffs2_flash_cleanup(struct jffs2_sb_info *c);
      
 
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1087,7 +1087,7 @@ static struct nand_oobinfo jffs2_oobinfo
 };
 
 
-int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
+static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
 {
 	struct nand_oobinfo *oinfo = &c->mtd->oobinfo;
 
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -52,8 +52,6 @@ void jfs_read_inode(struct inode *inode)
 	} 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;
-		mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
 	} else if (S_ISLNK(inode->i_mode)) {
 		if (inode->i_size >= IDATASIZE) {
 			inode->i_op = &page_symlink_inode_operations;
@@ -176,41 +174,23 @@ jfs_get_blocks(struct inode *ip, sector_
 			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;
+	s32 xlen = max_blocks;
 
 	/*
-	 * 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, max_blocks, &xflag, &xaddr, &xlen, no_size_check)
-	     == 0) && xlen) {
+	if (create)
+		IWRITE_LOCK(ip);
+	else
+		IREAD_LOCK(ip);
+
+	if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
+	    (!xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0)) &&
+	    xaddr) {
 		if (xflag & XAD_NOTRECORDED) {
 			if (!create)
 				/*
@@ -249,7 +229,7 @@ jfs_get_blocks(struct inode *ip, sector_
 #ifdef _JFS_4K
 	if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
 		goto unlock;
-	rc = extAlloc(ip, max_blocks, lblock64, &xad, FALSE);
+	rc = extAlloc(ip, xlen, lblock64, &xad, FALSE);
 	if (rc)
 		goto unlock;
 
@@ -269,12 +249,10 @@ jfs_get_blocks(struct inode *ip, sector_
 	/*
 	 * Release lock on inode
 	 */
-	if (take_locks) {
-		if (create)
-			IWRITE_UNLOCK(ip);
-		else
-			IREAD_UNLOCK(ip);
-	}
+	if (create)
+		IWRITE_UNLOCK(ip);
+	else
+		IREAD_UNLOCK(ip);
 	return rc;
 }
 
@@ -286,7 +264,7 @@ static int jfs_get_block(struct inode *i
 
 static int jfs_writepage(struct page *page, struct writeback_control *wbc)
 {
-	return block_write_full_page(page, jfs_get_block, wbc);
+	return nobh_writepage(page, jfs_get_block, wbc);
 }
 
 static int jfs_writepages(struct address_space *mapping,
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -471,6 +471,7 @@ dbUpdatePMap(struct inode *ipbmap,
 	struct metapage *mp;
 	struct jfs_log *log;
 	int lsn, difft, diffp;
+	unsigned long flags;
 
 	/* the blocks better be within the mapsize. */
 	if (blkno + nblocks > bmp->db_mapsize) {
@@ -504,6 +505,7 @@ dbUpdatePMap(struct inode *ipbmap,
 					   0);
 			if (mp == NULL)
 				return -EIO;
+			metapage_wait_for_io(mp);
 		}
 		dp = (struct dmap *) mp->data;
 
@@ -578,34 +580,32 @@ dbUpdatePMap(struct inode *ipbmap,
 		if (mp->lsn != 0) {
 			/* inherit older/smaller lsn */
 			logdiff(diffp, mp->lsn, log);
+			LOGSYNC_LOCK(log, flags);
 			if (difft < diffp) {
 				mp->lsn = lsn;
 
 				/* move bp after tblock in logsync list */
-				LOGSYNC_LOCK(log);
 				list_move(&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);
+			LOGSYNC_UNLOCK(log, flags);
 		} else {
 			mp->log = log;
 			mp->lsn = lsn;
 
 			/* insert bp after tblock in logsync list */
-			LOGSYNC_LOCK(log);
+			LOGSYNC_LOCK(log, flags);
 
 			log->count++;
 			list_add(&mp->synclist, &tblk->synclist);
 
 			mp->clsn = tblk->clsn;
-			LOGSYNC_UNLOCK(log);
+			LOGSYNC_UNLOCK(log, flags);
 		}
 	}
 
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -212,7 +212,7 @@ static struct metapage *read_index_page(
 	s32 xlen;
 
 	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
-	if (rc || (xlen == 0))
+	if (rc || (xaddr == 0))
 		return NULL;
 
 	return read_metapage(inode, xaddr, PSIZE, 1);
@@ -231,7 +231,7 @@ static struct metapage *get_index_page(s
 	s32 xlen;
 
 	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
-	if (rc || (xlen == 0))
+	if (rc || (xaddr == 0))
 		return NULL;
 
 	return get_metapage(inode, xaddr, PSIZE, 1);
@@ -268,7 +268,7 @@ static struct dir_table_slot *find_index
 		return NULL;
 	}
 
-	if (jfs_ip->next_index <= (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+	if (jfs_dirtable_inline(ip)) {
 		/*
 		 * Inline directory table
 		 */
@@ -2828,7 +2828,7 @@ void dtInitRoot(tid_t tid, struct inode 
 	 * the old directory table.
 	 */
 	if (DO_INDEX(ip)) {
-		if (jfs_ip->next_index > (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+		if (!jfs_dirtable_inline(ip)) {
 			struct tblock *tblk = tid_to_tblock(tid);
 			/*
 			 * We're playing games with the tid's xflag.  If
@@ -3181,7 +3181,7 @@ int jfs_readdir(struct file *filp, void 
 			d = (struct ldtentry *) & p->slot[stbl[i]];
 
 			if (((long) jfs_dirent + d->namlen + 1) >
-			    (dirent_buf + PSIZE)) {
+			    (dirent_buf + PAGE_SIZE)) {
 				/* DBCS codepages could overrun dirent_buf */
 				index = i;
 				overflow = 1;
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -502,7 +502,7 @@ struct inode *diReadSpecial(struct super
 
 	}
 
-	ip->i_mapping->a_ops = &jfs_aops;
+	ip->i_mapping->a_ops = &jfs_metapage_aops;
 	mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
 
 	/* Allocations to metadata inodes should not affect quotas */
@@ -2573,9 +2573,18 @@ diNewIAG(struct inomap * imap, int *iagn
 			goto out;
 		}
 
-		/* assign a buffer for the page */
-		mp = get_metapage(ipimap, xaddr, PSIZE, 1);
-		if (!mp) {
+		/*
+		 * start transaction of update of the inode map
+		 * addressing structure pointing to the new iag page;
+		 */
+		tid = txBegin(sb, COMMIT_FORCE);
+		down(&JFS_IP(ipimap)->commit_sem);
+
+		/* update the inode map addressing structure to point to it */
+		if ((rc =
+		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+			txEnd(tid);
+			up(&JFS_IP(ipimap)->commit_sem);
 			/* Free the blocks allocated for the iag since it was
 			 * not successfully added to the inode map
 			 */
@@ -2584,6 +2593,29 @@ diNewIAG(struct inomap * imap, int *iagn
 			/* release the inode map lock */
 			IWRITE_UNLOCK(ipimap);
 
+			goto out;
+		}
+
+		/* update the inode map's inode to reflect the extension */
+		ipimap->i_size += PSIZE;
+		inode_add_bytes(ipimap, PSIZE);
+
+		/* assign a buffer for the page */
+		mp = get_metapage(ipimap, blkno, PSIZE, 0);
+		if (!mp) {
+			/*
+			 * This is very unlikely since we just created the
+			 * extent, but let's try to handle it correctly
+			 */
+			xtTruncate(tid, ipimap, ipimap->i_size - PSIZE,
+				   COMMIT_PWMAP);
+
+			txAbort(tid, 0);
+			txEnd(tid);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
 			rc = -EIO;
 			goto out;
 		}
@@ -2605,41 +2637,11 @@ diNewIAG(struct inomap * imap, int *iagn
 			iagp->inosmap[i] = cpu_to_le32(ONES);
 
 		/*
-		 * Invalidate the page after writing and syncing it.
-		 * After it's initialized, we access it in a different
-		 * address space
+		 * Write and sync the metapage
 		 */
-		set_bit(META_discard, &mp->flag);
 		flush_metapage(mp);
 
 		/*
-		 * start tyransaction of update of the inode map
-		 * addressing structure pointing to the new iag page;
-		 */
-		tid = txBegin(sb, COMMIT_FORCE);
-		down(&JFS_IP(ipimap)->commit_sem);
-
-		/* update the inode map addressing structure to point to it */
-		if ((rc =
-		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
-			txEnd(tid);
-			up(&JFS_IP(ipimap)->commit_sem);
-			/* 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;
-		inode_add_bytes(ipimap, PSIZE);
-
-		/*
 		 * 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);
@@ -2789,6 +2791,7 @@ diUpdatePMap(struct inode *ipimap,
 	u32 mask;
 	struct jfs_log *log;
 	int lsn, difft, diffp;
+	unsigned long flags;
 
 	imap = JFS_IP(ipimap)->i_imap;
 	/* get the iag number containing the inode */
@@ -2805,6 +2808,7 @@ diUpdatePMap(struct inode *ipimap,
 	IREAD_UNLOCK(ipimap);
 	if (rc)
 		return (rc);
+	metapage_wait_for_io(mp);
 	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.
@@ -2868,30 +2872,28 @@ diUpdatePMap(struct inode *ipimap,
 		/* inherit older/smaller lsn */
 		logdiff(difft, lsn, log);
 		logdiff(diffp, mp->lsn, log);
+		LOGSYNC_LOCK(log, flags);
 		if (difft < diffp) {
 			mp->lsn = lsn;
 			/* move mp after tblock in logsync list */
-			LOGSYNC_LOCK(log);
 			list_move(&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);
+		LOGSYNC_UNLOCK(log, flags);
 	} else {
 		mp->log = log;
 		mp->lsn = lsn;
 		/* insert mp after tblock in logsync list */
-		LOGSYNC_LOCK(log);
+		LOGSYNC_LOCK(log, flags);
 		log->count++;
 		list_add(&mp->synclist, &tblk->synclist);
 		mp->clsn = tblk->clsn;
-		LOGSYNC_UNLOCK(log);
+		LOGSYNC_UNLOCK(log, flags);
 	}
 	write_metapage(mp);
 	return (0);
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -165,6 +165,7 @@ struct jfs_sb_info {
         /* Formerly in ipbmap */
 	struct bmap	*bmap;		/* incore bmap descriptor	*/
 	struct nls_table *nls_tab;	/* current codepage		*/
+	struct inode *direct_inode;	/* metadata inode */
 	uint		state;		/* mount/recovery state	*/
 	unsigned long	flag;		/* mount time flags */
 	uint		p_state;	/* state prior to going no integrity */
@@ -178,6 +179,11 @@ static inline struct jfs_inode_info *JFS
 	return list_entry(inode, struct jfs_inode_info, vfs_inode);
 }
 
+static inline int jfs_dirtable_inline(struct inode *inode)
+{
+	return (JFS_IP(inode)->next_index <= (MAX_INLINE_DIRTABLE_ENTRY + 1));
+}
+
 static inline struct jfs_sb_info *JFS_SBI(struct super_block *sb)
 {
 	return sb->s_fs_info;
@@ -189,5 +195,4 @@ static inline int isReadOnly(struct inod
 		return 0;
 	return 1;
 }
-
 #endif /* _H_JFS_INCORE */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -67,6 +67,7 @@
 #include <linux/buffer_head.h>		/* for sync_blockdev() */
 #include <linux/bio.h>
 #include <linux/suspend.h>
+#include <linux/delay.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
@@ -233,6 +234,7 @@ int lmLog(struct jfs_log * log, struct t
 	int lsn;
 	int diffp, difft;
 	struct metapage *mp = NULL;
+	unsigned long flags;
 
 	jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
 		 log, tblk, lrd, tlck);
@@ -253,7 +255,7 @@ int lmLog(struct jfs_log * log, struct t
 	 */
 	lsn = log->lsn;
 
-	LOGSYNC_LOCK(log);
+	LOGSYNC_LOCK(log, flags);
 
 	/*
 	 * initialize page lsn if first log write of the page
@@ -309,7 +311,7 @@ int lmLog(struct jfs_log * log, struct t
 		}
 	}
 
-	LOGSYNC_UNLOCK(log);
+	LOGSYNC_UNLOCK(log, flags);
 
 	/*
 	 *      write the log record
@@ -333,7 +335,6 @@ int lmLog(struct jfs_log * log, struct t
 	return lsn;
 }
 
-
 /*
  * NAME:	lmWriteRecord()
  *
@@ -926,9 +927,8 @@ static void lmPostGC(struct lbuf * bp)
  *	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.
+ * PARAMETERS:	log	- log structure
+ * 		nosyncwait - 1 if called asynchronously
  *
  * RETURN:	0
  *			
@@ -944,6 +944,15 @@ static int lmLogSync(struct jfs_log * lo
 	struct lrd lrd;
 	int lsn;
 	struct logsyncblk *lp;
+	struct jfs_sb_info *sbi;
+	unsigned long flags;
+
+	/* push dirty metapages out to disk */
+	list_for_each_entry(sbi, &log->sb_list, log_list) {
+		filemap_flush(sbi->ipbmap->i_mapping);
+		filemap_flush(sbi->ipimap->i_mapping);
+		filemap_flush(sbi->direct_inode->i_mapping);
+	}
 
 	/*
 	 *      forward syncpt
@@ -953,10 +962,7 @@ static int lmLogSync(struct jfs_log * lo
 	 */
 
 	if (log->sync == log->syncpt) {
-		LOGSYNC_LOCK(log);
-		/* ToDo: push dirty metapages out to disk */
-//              bmLogSync(log);
-
+		LOGSYNC_LOCK(log, flags);
 		if (list_empty(&log->synclist))
 			log->sync = log->lsn;
 		else {
@@ -964,7 +970,7 @@ static int lmLogSync(struct jfs_log * lo
 					struct logsyncblk, synclist);
 			log->sync = lp->lsn;
 		}
-		LOGSYNC_UNLOCK(log);
+		LOGSYNC_UNLOCK(log, flags);
 
 	}
 
@@ -973,27 +979,6 @@ static int lmLogSync(struct jfs_log * lo
 	 * reset syncpt = sync
 	 */
 	if (log->sync != log->syncpt) {
-		struct jfs_sb_info *sbi;
-
-		/*
-		 * We need to make sure all of the "written" metapages
-		 * actually make it to disk
-		 */
-		list_for_each_entry(sbi, &log->sb_list, log_list) {
-			if (sbi->flag & JFS_NOINTEGRITY)
-				continue;
-			filemap_fdatawrite(sbi->ipbmap->i_mapping);
-			filemap_fdatawrite(sbi->ipimap->i_mapping);
-			filemap_fdatawrite(sbi->sb->s_bdev->bd_inode->i_mapping);
-		}
-		list_for_each_entry(sbi, &log->sb_list, log_list) {
-			if (sbi->flag & JFS_NOINTEGRITY)
-				continue;
-			filemap_fdatawait(sbi->ipbmap->i_mapping);
-			filemap_fdatawait(sbi->ipimap->i_mapping);
-			filemap_fdatawait(sbi->sb->s_bdev->bd_inode->i_mapping);
-		}
-
 		lrd.logtid = 0;
 		lrd.backchain = 0;
 		lrd.type = cpu_to_le16(LOG_SYNCPT);
@@ -1065,6 +1050,18 @@ static int lmLogSync(struct jfs_log * lo
 	return lsn;
 }
 
+/*
+ * NAME:	jfs_syncpt
+ *
+ * FUNCTION:	write log SYNCPT record for specified log
+ *
+ * PARAMETERS:	log	- log structure
+ */
+void jfs_syncpt(struct jfs_log *log)
+{	LOG_LOCK(log);
+	lmLogSync(log, 1);
+	LOG_UNLOCK(log);
+}
 
 /*
  * NAME:	lmLogOpen()
@@ -1118,6 +1115,7 @@ int lmLogOpen(struct super_block *sb)
 	}
 	memset(log, 0, sizeof(struct jfs_log));
 	INIT_LIST_HEAD(&log->sb_list);
+	init_waitqueue_head(&log->syncwait);
 
 	/*
 	 *      external log as separate logical volume
@@ -1191,6 +1189,7 @@ static int open_inline_log(struct super_
 		return -ENOMEM;
 	memset(log, 0, sizeof(struct jfs_log));
 	INIT_LIST_HEAD(&log->sb_list);
+	init_waitqueue_head(&log->syncwait);
 
 	set_bit(log_INLINELOG, &log->flag);
 	log->bdev = sb->s_bdev;
@@ -1228,6 +1227,7 @@ static int open_dummy_log(struct super_b
 		}
 		memset(dummy_log, 0, sizeof(struct jfs_log));
 		INIT_LIST_HEAD(&dummy_log->sb_list);
+		init_waitqueue_head(&dummy_log->syncwait);
 		dummy_log->no_integrity = 1;
 		/* Make up some stuff */
 		dummy_log->base = 0;
@@ -1290,8 +1290,6 @@ int lmLogInit(struct jfs_log * log)
 
 	INIT_LIST_HEAD(&log->synclist);
 
-	init_waitqueue_head(&log->syncwait);
-
 	INIT_LIST_HEAD(&log->cqueue);
 	log->flush_tblk = NULL;
 
@@ -1545,6 +1543,7 @@ void jfs_flush_journal(struct jfs_log *l
 {
 	int i;
 	struct tblock *target = NULL;
+	struct jfs_sb_info *sbi;
 
 	/* jfs_write_inode may call us during read-only mount */
 	if (!log)
@@ -1606,21 +1605,43 @@ void jfs_flush_journal(struct jfs_log *l
 	if (wait < 2)
 		return;
 
+	list_for_each_entry(sbi, &log->sb_list, log_list) {
+		filemap_fdatawrite(sbi->ipbmap->i_mapping);
+		filemap_fdatawrite(sbi->ipimap->i_mapping);
+		filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	}
+
 	/*
 	 * If there was recent activity, we may need to wait
 	 * for the lazycommit thread to catch up
 	 */
 	if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
-		for (i = 0; i < 800; i++) {	/* Too much? */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ / 4);
+		for (i = 0; i < 200; i++) {	/* Too much? */
+			msleep(250);
 			if (list_empty(&log->cqueue) &&
 			    list_empty(&log->synclist))
 				break;
 		}
 	}
 	assert(list_empty(&log->cqueue));
-	assert(list_empty(&log->synclist));
+	if (!list_empty(&log->synclist)) {
+		struct logsyncblk *lp;
+
+		list_for_each_entry(lp, &log->synclist, synclist) {
+			if (lp->xflag & COMMIT_PAGE) {
+				struct metapage *mp = (struct metapage *)lp;
+				dump_mem("orphan metapage", lp,
+					 sizeof(struct metapage));
+				dump_mem("page", mp->page, sizeof(struct page));
+			}
+			else
+				dump_mem("orphan tblock", lp,
+					 sizeof(struct tblock));
+		}
+//		current->state = TASK_INTERRUPTIBLE;
+//		schedule();
+	}
+	//assert(list_empty(&log->synclist));
 	clear_bit(log_FLUSH, &log->flag);
 }
 
@@ -1668,6 +1689,7 @@ int lmLogShutdown(struct jfs_log * log)
 	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
 	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
 	lbmIOWait(log->bp, lbmFREE);
+	log->bp = NULL;
 
 	/*
 	 * synchronous update log superblock
@@ -1818,20 +1840,34 @@ static int lbmLogInit(struct jfs_log * l
 
 	log->lbuf_free = NULL;
 
-	for (i = 0; i < LOGPAGES; i++) {
-		lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
-		if (lbuf == 0)
-			goto error;
-		lbuf->l_ldata = (char *) get_zeroed_page(GFP_KERNEL);
-		if (lbuf->l_ldata == 0) {
-			kfree(lbuf);
+	for (i = 0; i < LOGPAGES;) {
+		char *buffer;
+		uint offset;
+		struct page *page;
+
+		buffer = (char *) get_zeroed_page(GFP_KERNEL);
+		if (buffer == NULL)
 			goto error;
+		page = virt_to_page(buffer);
+		for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
+			lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
+			if (lbuf == NULL) {
+				if (offset == 0)
+					free_page((unsigned long) buffer);
+				goto error;
+			}
+			if (offset) /* we already have one reference */
+				get_page(page);
+			lbuf->l_offset = offset;
+			lbuf->l_ldata = buffer + offset;
+			lbuf->l_page = page;
+			lbuf->l_log = log;
+			init_waitqueue_head(&lbuf->l_ioevent);
+
+			lbuf->l_freelist = log->lbuf_free;
+			log->lbuf_free = lbuf;
+			i++;
 		}
-		lbuf->l_log = log;
-		init_waitqueue_head(&lbuf->l_ioevent);
-
-		lbuf->l_freelist = log->lbuf_free;
-		log->lbuf_free = lbuf;
 	}
 
 	return (0);
@@ -1856,12 +1892,10 @@ static void lbmLogShutdown(struct jfs_lo
 	lbuf = log->lbuf_free;
 	while (lbuf) {
 		struct lbuf *next = lbuf->l_freelist;
-		free_page((unsigned long) lbuf->l_ldata);
+		__free_page(lbuf->l_page);
 		kfree(lbuf);
 		lbuf = next;
 	}
-
-	log->bp = NULL;
 }
 
 
@@ -1973,9 +2007,9 @@ static int lbmRead(struct jfs_log * log,
 
 	bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
 	bio->bi_bdev = log->bdev;
-	bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+	bio->bi_io_vec[0].bv_page = bp->l_page;
 	bio->bi_io_vec[0].bv_len = LOGPSIZE;
-	bio->bi_io_vec[0].bv_offset = 0;
+	bio->bi_io_vec[0].bv_offset = bp->l_offset;
 
 	bio->bi_vcnt = 1;
 	bio->bi_idx = 0;
@@ -2114,9 +2148,9 @@ static void lbmStartIO(struct lbuf * bp)
 	bio = bio_alloc(GFP_NOFS, 1);
 	bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
 	bio->bi_bdev = log->bdev;
-	bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+	bio->bi_io_vec[0].bv_page = bp->l_page;
 	bio->bi_io_vec[0].bv_len = LOGPSIZE;
-	bio->bi_io_vec[0].bv_offset = 0;
+	bio->bi_io_vec[0].bv_offset = bp->l_offset;
 
 	bio->bi_vcnt = 1;
 	bio->bi_idx = 0;
@@ -2126,16 +2160,13 @@ static void lbmStartIO(struct lbuf * bp)
 	bio->bi_private = bp;
 
 	/* check if journaling to disk has been disabled */
-	if (!log->no_integrity) {
+	if (log->no_integrity) {
+		bio->bi_size = 0;
+		lbmIODone(bio, 0, 0);
+	} else {
 		submit_bio(WRITE_SYNC, bio);
 		INCREMENT(lmStat.submitted);
 	}
-	else {
-		bio->bi_size = 0;
-		lbmIODone(bio, 0, 0); /* 2nd argument appears to not be used => 0
-				       *  3rd argument appears to not be used => 0
-				       */
-	}
 }
 
 
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -463,9 +463,10 @@ struct lbuf {
 
 	s64 l_blkno;		/* 8: log page block number */
 	caddr_t l_ldata;	/* 4: data page */
+	struct page *l_page;	/* The page itself */
+	uint l_offset;		/* Offset of l_ldata within the 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 */
@@ -489,8 +490,9 @@ struct logsyncblk {
  */
 
 #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)
+#define LOGSYNC_LOCK(log, flags) spin_lock_irqsave(&(log)->synclock, flags)
+#define LOGSYNC_UNLOCK(log, flags) \
+	spin_unlock_irqrestore(&(log)->synclock, flags)
 
 /* compute the difference in bytes of lsn from sync point */
 #define logdiff(diff, lsn, log)\
@@ -506,5 +508,6 @@ extern int lmLogShutdown(struct jfs_log 
 extern int lmLogInit(struct jfs_log * log);
 extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
 extern void jfs_flush_journal(struct jfs_log * log, int wait);
+extern void jfs_syncpt(struct jfs_log *log);
 
 #endif				/* _H_JFS_LOGMGR */
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2005
  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -18,6 +18,8 @@
  */
 
 #include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
 #include <linux/init.h>
 #include <linux/buffer_head.h>
 #include <linux/mempool.h>
@@ -28,8 +30,6 @@
 #include "jfs_txnmgr.h"
 #include "jfs_debug.h"
 
-static DEFINE_SPINLOCK(meta_lock);
-
 #ifdef CONFIG_JFS_STATISTICS
 static struct {
 	uint	pagealloc;	/* # of page allocations */
@@ -38,22 +38,8 @@ static struct {
 } 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);
-}
+#define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
+#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)
 
 static inline void unlock_metapage(struct metapage *mp)
 {
@@ -61,26 +47,26 @@ static inline void unlock_metapage(struc
 	wake_up(&mp->wait);
 }
 
-static void __lock_metapage(struct metapage *mp)
+static inline 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);
+			unlock_page(mp->page);
 			schedule();
-			spin_lock(&meta_lock);
+			lock_page(mp->page);
 		}
 	} while (trylock_metapage(mp));
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&mp->wait, &wait);
 }
 
-/* needs meta_lock */
+/*
+ * Must have mp->page locked
+ */
 static inline void lock_metapage(struct metapage *mp)
 {
 	if (trylock_metapage(mp))
@@ -91,6 +77,110 @@ static inline void lock_metapage(struct 
 static kmem_cache_t *metapage_cache;
 static mempool_t *metapage_mempool;
 
+#define MPS_PER_PAGE (PAGE_CACHE_SIZE >> L2PSIZE)
+
+#if MPS_PER_PAGE > 1
+
+struct meta_anchor {
+	int mp_count;
+	atomic_t io_count;
+	struct metapage *mp[MPS_PER_PAGE];
+};
+#define mp_anchor(page) ((struct meta_anchor *)page->private)
+
+static inline struct metapage *page_to_mp(struct page *page, uint offset)
+{
+	if (!PagePrivate(page))
+		return NULL;
+	return mp_anchor(page)->mp[offset >> L2PSIZE];
+}
+
+static inline int insert_metapage(struct page *page, struct metapage *mp)
+{
+	struct meta_anchor *a;
+	int index;
+	int l2mp_blocks;	/* log2 blocks per metapage */
+
+	if (PagePrivate(page))
+		a = mp_anchor(page);
+	else {
+		a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS);
+		if (!a)
+			return -ENOMEM;
+		memset(a, 0, sizeof(struct meta_anchor));
+		page->private = (unsigned long)a;
+		SetPagePrivate(page);
+		kmap(page);
+	}
+
+	if (mp) {
+		l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
+		index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
+		a->mp_count++;
+		a->mp[index] = mp;
+	}
+
+	return 0;
+}
+
+static inline void remove_metapage(struct page *page, struct metapage *mp)
+{
+	struct meta_anchor *a = mp_anchor(page);
+	int l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
+	int index;
+
+	index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
+
+	BUG_ON(a->mp[index] != mp);
+
+	a->mp[index] = NULL;
+	if (--a->mp_count == 0) {
+		kfree(a);
+		page->private = 0;
+		ClearPagePrivate(page);
+		kunmap(page);
+	}
+}
+
+static inline void inc_io(struct page *page)
+{
+	atomic_inc(&mp_anchor(page)->io_count);
+}
+
+static inline void dec_io(struct page *page, void (*handler) (struct page *))
+{
+	if (atomic_dec_and_test(&mp_anchor(page)->io_count))
+		handler(page);
+}
+
+#else
+static inline struct metapage *page_to_mp(struct page *page, uint offset)
+{
+	return PagePrivate(page) ? (struct metapage *)page->private : NULL;
+}
+
+static inline int insert_metapage(struct page *page, struct metapage *mp)
+{
+	if (mp) {
+		page->private = (unsigned long)mp;
+		SetPagePrivate(page);
+		kmap(page);
+	}
+	return 0;
+}
+
+static inline void remove_metapage(struct page *page, struct metapage *mp)
+{
+	page->private = 0;
+	ClearPagePrivate(page);
+	kunmap(page);
+}
+
+#define inc_io(page) do {} while(0)
+#define dec_io(page, handler) handler(page)
+
+#endif
+
 static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
 {
 	struct metapage *mp = (struct metapage *)foo;
@@ -138,16 +228,6 @@ int __init metapage_init(void)
 		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;
 }
@@ -158,73 +238,388 @@ void metapage_exit(void)
 	kmem_cache_destroy(metapage_cache);
 }
 
+static inline void drop_metapage(struct page *page, struct metapage *mp)
+{
+	if (mp->count || mp->nohomeok || test_bit(META_dirty, &mp->flag) ||
+	    test_bit(META_io, &mp->flag))
+		return;
+	remove_metapage(page, mp);
+	INCREMENT(mpStat.pagefree);
+	free_metapage(mp);
+}
+
 /*
- * Basically same hash as in pagemap.h, but using our hash table
+ * Metapage address space operations
  */
-static struct metapage **meta_hash(struct address_space *mapping,
-				   unsigned long index)
+
+static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
+				    unsigned int *len)
+{
+	int rc = 0;
+	int xflag;
+	s64 xaddr;
+	sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >>
+			       inode->i_blkbits;
+
+	if (lblock >= file_blocks)
+		return 0;
+	if (lblock + *len > file_blocks)
+		*len = file_blocks - lblock;
+
+	if (inode->i_ino) {
+		rc = xtLookup(inode, (s64)lblock, *len, &xflag, &xaddr, len, 0);
+		if ((rc == 0) && *len)
+			lblock = (sector_t)xaddr;
+		else
+			lblock = 0;
+	} /* else no mapping */
+
+	return lblock;
+}
+
+static void last_read_complete(struct page *page)
+{
+	if (!PageError(page))
+		SetPageUptodate(page);
+	unlock_page(page);
+}
+
+static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done,
+				int err)
 {
-#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;
+	struct page *page = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
+
+	if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+		printk(KERN_ERR "metapage_read_end_io: I/O error\n");
+		SetPageError(page);
 	}
 
-	return NULL;
+	dec_io(page, last_read_complete);
+	bio_put(bio);
+
+	return 0;
 }
 
-static void add_to_hash(struct metapage * mp, struct metapage ** hash_ptr)
+static void remove_from_logsync(struct metapage *mp)
 {
-	if (*hash_ptr)
-		(*hash_ptr)->hash_prev = mp;
+	struct jfs_log *log = mp->log;
+	unsigned long flags;
+/*
+ * This can race.  Recheck that log hasn't been set to null, and after
+ * acquiring logsync lock, recheck lsn
+ */
+	if (!log)
+		return;
 
-	mp->hash_prev = NULL;
-	mp->hash_next = *hash_ptr;
-	*hash_ptr = mp;
+	LOGSYNC_LOCK(log, flags);
+	if (mp->lsn) {
+		mp->log = NULL;
+		mp->lsn = 0;
+		mp->clsn = 0;
+		log->count--;
+		list_del(&mp->synclist);
+	}
+	LOGSYNC_UNLOCK(log, flags);
 }
 
-static void remove_from_hash(struct metapage * mp, struct metapage ** hash_ptr)
+static void last_write_complete(struct page *page)
 {
-	if (mp->hash_prev)
-		mp->hash_prev->hash_next = mp->hash_next;
-	else {
-		assert(*hash_ptr == mp);
-		*hash_ptr = mp->hash_next;
+	struct metapage *mp;
+	unsigned int offset;
+
+	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+		mp = page_to_mp(page, offset);
+		if (mp && test_bit(META_io, &mp->flag)) {
+			if (mp->lsn)
+				remove_from_logsync(mp);
+			clear_bit(META_io, &mp->flag);
+		}
+		/*
+		 * I'd like to call drop_metapage here, but I don't think it's
+		 * safe unless I have the page locked
+		 */
+	}
+	end_page_writeback(page);
+}
+
+static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done,
+				 int err)
+{
+	struct page *page = bio->bi_private;
+
+	BUG_ON(!PagePrivate(page));
+
+	if (bio->bi_size)
+		return 1;
+
+	if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+		printk(KERN_ERR "metapage_write_end_io: I/O error\n");
+		SetPageError(page);
+	}
+	dec_io(page, last_write_complete);
+	bio_put(bio);
+	return 0;
+}
+
+static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct bio *bio = NULL;
+	unsigned int block_offset;	/* block offset of mp within page */
+	struct inode *inode = page->mapping->host;
+	unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
+	unsigned int len;
+	unsigned int xlen;
+	struct metapage *mp;
+	int redirty = 0;
+	sector_t lblock;
+	sector_t pblock;
+	sector_t next_block = 0;
+	sector_t page_start;
+	unsigned long bio_bytes = 0;
+	unsigned long bio_offset = 0;
+	unsigned int offset;
+
+	page_start = (sector_t)page->index <<
+		     (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	BUG_ON(!PageLocked(page));
+	BUG_ON(PageWriteback(page));
+
+	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+		mp = page_to_mp(page, offset);
+
+		if (!mp || !test_bit(META_dirty, &mp->flag))
+			continue;
+
+		if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) {
+			redirty = 1;
+			continue;
+		}
+
+		clear_bit(META_dirty, &mp->flag);
+		block_offset = offset >> inode->i_blkbits;
+		lblock = page_start + block_offset;
+		if (bio) {
+			if (xlen && lblock == next_block) {
+				/* Contiguous, in memory & on disk */
+				len = min(xlen, blocks_per_mp);
+				xlen -= len;
+				bio_bytes += len << inode->i_blkbits;
+				set_bit(META_io, &mp->flag);
+				continue;
+			}
+			/* Not contiguous */
+			if (bio_add_page(bio, page, bio_bytes, bio_offset) <
+			    bio_bytes)
+				goto add_failed;
+			/*
+			 * Increment counter before submitting i/o to keep
+			 * count from hitting zero before we're through
+			 */
+			inc_io(page);
+			if (!bio->bi_size)
+				goto dump_bio;
+			submit_bio(WRITE, bio);
+			bio = NULL;
+		} else {
+			set_page_writeback(page);
+			inc_io(page);
+		}
+		xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
+		pblock = metapage_get_blocks(inode, lblock, &xlen);
+		if (!pblock) {
+			/* Need better error handling */
+			printk(KERN_ERR "JFS: metapage_get_blocks failed\n");
+			dec_io(page, last_write_complete);
+			continue;
+		}
+		set_bit(META_io, &mp->flag);
+		len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage);
+
+		bio = bio_alloc(GFP_NOFS, 1);
+		bio->bi_bdev = inode->i_sb->s_bdev;
+		bio->bi_sector = pblock << (inode->i_blkbits - 9);
+		bio->bi_end_io = metapage_write_end_io;
+		bio->bi_private = page;
+
+		/* Don't call bio_add_page yet, we may add to this vec */
+		bio_offset = offset;
+		bio_bytes = len << inode->i_blkbits;
+
+		xlen -= len;
+		next_block = lblock + len;
+	}
+	if (bio) {
+		if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes)
+				goto add_failed;
+		if (!bio->bi_size)
+			goto dump_bio;
+		
+		submit_bio(WRITE, bio);
+	}
+	if (redirty)
+		redirty_page_for_writepage(wbc, page);
+
+	unlock_page(page);
+
+	return 0;
+add_failed:
+	/* We should never reach here, since we're only adding one vec */
+	printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
+	goto skip;
+dump_bio:
+	dump_mem("bio", bio, sizeof(*bio));
+skip:
+	bio_put(bio);
+	unlock_page(page);
+	dec_io(page, last_write_complete);
+
+	return -EIO;
+}
+
+static int metapage_readpage(struct file *fp, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	struct bio *bio = NULL;
+	unsigned int block_offset;
+	unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+	sector_t page_start;	/* address of page in fs blocks */
+	sector_t pblock;
+	unsigned int xlen;
+	unsigned int len;
+	unsigned int offset;
+
+	BUG_ON(!PageLocked(page));
+	page_start = (sector_t)page->index <<
+		     (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+	block_offset = 0;
+	while (block_offset < blocks_per_page) {
+		xlen = blocks_per_page - block_offset;
+		pblock = metapage_get_blocks(inode, page_start + block_offset,
+					     &xlen);
+		if (pblock) {
+			if (!PagePrivate(page))
+				insert_metapage(page, NULL);
+			inc_io(page);
+			if (bio)
+				submit_bio(READ, bio);
+
+			bio = bio_alloc(GFP_NOFS, 1);
+			bio->bi_bdev = inode->i_sb->s_bdev;
+			bio->bi_sector = pblock << (inode->i_blkbits - 9);
+			bio->bi_end_io = metapage_read_end_io;
+			bio->bi_private = page;
+			len = xlen << inode->i_blkbits;
+			offset = block_offset << inode->i_blkbits;
+			if (bio_add_page(bio, page, len, offset) < len)
+				goto add_failed;
+			block_offset += xlen;
+		} else
+			block_offset++;
 	}
+	if (bio)
+		submit_bio(READ, bio);
+	else
+		unlock_page(page);
 
-	if (mp->hash_next)
-		mp->hash_next->hash_prev = mp->hash_prev;
+	return 0;
+
+add_failed:
+	printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
+	bio_put(bio);
+	dec_io(page, last_read_complete);
+	return -EIO;
 }
 
+static int metapage_releasepage(struct page *page, int gfp_mask)
+{
+	struct metapage *mp;
+	int busy = 0;
+	unsigned int offset;
+
+	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+		mp = page_to_mp(page, offset);
+
+		if (!mp)
+			continue;
+
+		jfs_info("metapage_releasepage: mp = 0x%p", mp);
+		if (mp->count || mp->nohomeok) {
+			jfs_info("count = %ld, nohomeok = %d", mp->count,
+				 mp->nohomeok);
+			busy = 1;
+			continue;
+		}
+		wait_on_page_writeback(page);
+		//WARN_ON(test_bit(META_dirty, &mp->flag));
+		if (test_bit(META_dirty, &mp->flag)) {
+			dump_mem("dirty mp in metapage_releasepage", mp,
+				 sizeof(struct metapage));
+			dump_mem("page", page, sizeof(struct page));
+			dump_stack();
+		}
+		WARN_ON(mp->lsn);
+		if (mp->lsn)
+			remove_from_logsync(mp);
+		remove_metapage(page, mp);
+		INCREMENT(mpStat.pagefree);
+		free_metapage(mp);
+	}
+	if (busy)
+		return -1;
+
+	return 0;
+}
+
+static int metapage_invalidatepage(struct page *page, unsigned long offset)
+{
+	BUG_ON(offset);
+
+	if (PageWriteback(page))
+		return 0;
+
+	return metapage_releasepage(page, 0);
+}
+
+struct address_space_operations jfs_metapage_aops = {
+	.readpage	= metapage_readpage,
+	.writepage	= metapage_writepage,
+	.sync_page	= block_sync_page,
+	.releasepage	= metapage_releasepage,
+	.invalidatepage	= metapage_invalidatepage,
+	.set_page_dirty	= __set_page_dirty_nobuffers,
+};
+
 struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
 				unsigned int size, int absolute,
 				unsigned long new)
 {
-	struct metapage **hash_ptr;
 	int l2BlocksPerPage;
 	int l2bsize;
 	struct address_space *mapping;
-	struct metapage *mp;
+	struct metapage *mp = NULL;
+	struct page *page;
 	unsigned long page_index;
 	unsigned long page_offset;
 
-	jfs_info("__get_metapage: inode = 0x%p, lblock = 0x%lx", inode, lblock);
+	jfs_info("__get_metapage: ino = %ld, lblock = 0x%lx, abs=%d",
+		 inode->i_ino, lblock, absolute);
 
+	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) {
+		jfs_err("MetaData crosses page boundary!!");
+		jfs_err("lblock = %lx, size  = %d", lblock, size);
+		dump_stack();
+		return NULL;
+	}
 	if (absolute)
-		mapping = inode->i_sb->s_bdev->bd_inode->i_mapping;
+		mapping = JFS_SBI(inode->i_sb)->direct_inode->i_mapping;
 	else {
 		/*
 		 * If an nfs client tries to read an inode that is larger
@@ -236,323 +631,212 @@ struct metapage *__get_metapage(struct i
 		mapping = inode->i_mapping;
 	}
 
-	hash_ptr = meta_hash(mapping, lblock);
-again:
-	spin_lock(&meta_lock);
-	mp = search_hash(hash_ptr, mapping, lblock);
+	if (new && (PSIZE == PAGE_CACHE_SIZE)) {
+		page = grab_cache_page(mapping, page_index);
+		if (!page) {
+			jfs_err("grab_cache_page failed!");
+			return NULL;
+		}
+		SetPageUptodate(page);
+	} else {
+		page = read_cache_page(mapping, page_index,
+			    (filler_t *)mapping->a_ops->readpage, NULL);
+		if (IS_ERR(page)) {
+			jfs_err("read_cache_page failed!");
+			return NULL;
+		}
+		lock_page(page);
+	}
+
+	mp = page_to_mp(page, page_offset);
 	if (mp) {
-	      page_found:
+		if (mp->logical_size != size) {
+			jfs_error(inode->i_sb,
+				  "__get_metapage: mp->logical_size != size");
+			jfs_err("logical_size = %d, size = %d",
+				mp->logical_size, size);
+			dump_stack();
+			goto unlock; 
+		}
 		mp->count++;
 		lock_metapage(mp);
-		spin_unlock(&meta_lock);
-		if (test_bit(META_stale, &mp->flag)) {
-			release_metapage(mp);
-			yield();	/* Let other waiters release it, too */
-			goto again;
-		}
 		if (test_bit(META_discard, &mp->flag)) {
 			if (!new) {
 				jfs_error(inode->i_sb,
 					  "__get_metapage: using a "
 					  "discarded metapage");
-				release_metapage(mp);
-				return NULL;
+				discard_metapage(mp);
+				goto unlock; 
 			}
 			clear_bit(META_discard, &mp->flag);
 		}
-		jfs_info("__get_metapage: found 0x%p, in hash", mp);
-		if (mp->logical_size != size) {
-			jfs_error(inode->i_sb,
-				  "__get_metapage: mp->logical_size != size");
-			release_metapage(mp);
-			return NULL;
-		}
 	} 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);
-			jfs_err("MetaData crosses page boundary!!");
-			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.
-		 */
-		mp = NULL;
-		if (JFS_IP(inode)->fileset == AGGREGATE_I) {
-			mp = alloc_metapage(GFP_ATOMIC);
-			if (!mp) {
-				/*
-				 * mempool is supposed to protect us from
-				 * failing here.  We will try a blocking
-				 * call, but a deadlock is possible here
-				 */
-				printk(KERN_WARNING
-				       "__get_metapage: atomic call to mempool_alloc failed.\n");
-				printk(KERN_WARNING
-				       "Will attempt blocking call\n");
-			}
-		}
-		if (!mp) {
-			struct metapage *mp2;
-
-			spin_unlock(&meta_lock);
-			mp = alloc_metapage(GFP_NOFS);
-			spin_lock(&meta_lock);
-
-			/* we dropped the meta_lock, we need to search the
-			 * hash again.
-			 */
-			mp2 = search_hash(hash_ptr, mapping, lblock);
-			if (mp2) {
-				free_metapage(mp);
-				mp = mp2;
-				goto page_found;
-			}
-		}
+		INCREMENT(mpStat.pagealloc);
+		mp = alloc_metapage(GFP_NOFS);
+		mp->page = page;
 		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 = NULL;
+		mp->nohomeok = 0;
 		mp->logical_size = size;
-		add_to_hash(mp, hash_ptr);
-		spin_unlock(&meta_lock);
-
-		if (new) {
-			jfs_info("__get_metapage: Calling grab_cache_page");
-			mp->page = grab_cache_page(mapping, page_index);
-			if (!mp->page) {
-				jfs_err("grab_cache_page failed!");
-				goto freeit;
-			} else {
-				INCREMENT(mpStat.pagealloc);
-				unlock_page(mp->page);
-			}
-		} else {
-			jfs_info("__get_metapage: Calling read_cache_page");
-			mp->page = read_cache_page(mapping, lblock,
-				    (filler_t *)mapping->a_ops->readpage, NULL);
-			if (IS_ERR(mp->page)) {
-				jfs_err("read_cache_page failed!");
-				goto freeit;
-			} else
-				INCREMENT(mpStat.pagealloc);
+		mp->data = page_address(page) + page_offset;
+		mp->index = lblock;
+		if (unlikely(insert_metapage(page, mp))) {
+			free_metapage(mp);
+			goto unlock;
 		}
-		mp->data = kmap(mp->page) + page_offset;
+		lock_metapage(mp);
 	}
 
-	if (new)
+	if (new) {
+		jfs_info("zeroing mp = 0x%p", mp);
 		memset(mp->data, 0, PSIZE);
+	}
 
-	jfs_info("__get_metapage: returning = 0x%p", mp);
+	unlock_page(page);
+	jfs_info("__get_metapage: returning = 0x%p data = 0x%p", mp, mp->data);
 	return mp;
 
-freeit:
-	spin_lock(&meta_lock);
-	remove_from_hash(mp, hash_ptr);
-	free_metapage(mp);
-	spin_unlock(&meta_lock);
+unlock:
+	unlock_page(page);
 	return NULL;
 }
 
-void hold_metapage(struct metapage * mp, int force)
+void grab_metapage(struct metapage * mp)
 {
-	spin_lock(&meta_lock);
-
+	jfs_info("grab_metapage: mp = 0x%p", mp);
+	page_cache_get(mp->page);
+	lock_page(mp->page);
 	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);
+	lock_metapage(mp);
+	unlock_page(mp->page);
 }
 
-static void __write_metapage(struct metapage * mp)
+void force_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;
-
-	jfs_info("__write_metapage: mp = 0x%p", mp);
-
-	page_index = mp->page->index;
-	page_offset =
-	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
+	struct page *page = mp->page;
+	jfs_info("force_metapage: mp = 0x%p", mp);
+	set_bit(META_forcewrite, &mp->flag);
+	clear_bit(META_sync, &mp->flag);
+	page_cache_get(page);
+	lock_page(page);
+	set_page_dirty(page);
+	write_one_page(page, 1);
+	clear_bit(META_forcewrite, &mp->flag);
+	page_cache_release(page);
+}
 
+extern void hold_metapage(struct metapage *mp)
+{
 	lock_page(mp->page);
-	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
-					       page_offset +
-					       mp->logical_size);
-	if (rc) {
-		jfs_err("prepare_write return %d!", rc);
-		ClearPageUptodate(mp->page);
+}
+
+extern void put_metapage(struct metapage *mp)
+{
+	if (mp->count || mp->nohomeok) {
+		/* Someone else will release this */
 		unlock_page(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) {
-		jfs_err("commit_write returned %d", rc);
-	}
-
+	page_cache_get(mp->page);
+	mp->count++;
+	lock_metapage(mp);
 	unlock_page(mp->page);
-	clear_bit(META_dirty, &mp->flag);
-
-	jfs_info("__write_metapage done");
-}
-
-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_has_buffers(page))
-		write_one_page(page, 1);
-	else
-		unlock_page(page);
-	page_cache_release(page);
+	release_metapage(mp);
 }
 
 void release_metapage(struct metapage * mp)
 {
-	struct jfs_log *log;
-
+	struct page *page = mp->page;
 	jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", 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;
-	}
+	BUG_ON(!page);
+
+	lock_page(page);
+	unlock_metapage(mp);
 
 	assert(mp->count);
-	if (--mp->count || atomic_read(&mp->nohomeok)) {
-		unlock_metapage(mp);
-		spin_unlock(&meta_lock);
+	if (--mp->count || mp->nohomeok) {
+		unlock_page(page);
+		page_cache_release(page);
 		return;
 	}
 
-	if (mp->page) {
-		/* Releasing spinlock, we have to check mp->count later */
-		set_bit(META_stale, &mp->flag);
-		spin_unlock(&meta_lock);
-		kunmap(mp->page);
-		mp->data = NULL;
-		if (test_bit(META_dirty, &mp->flag))
-			__write_metapage(mp);
+	if (test_bit(META_dirty, &mp->flag)) {
+		set_page_dirty(page);
 		if (test_bit(META_sync, &mp->flag)) {
-			sync_metapage(mp);
 			clear_bit(META_sync, &mp->flag);
+			write_one_page(page, 1);
+			lock_page(page); /* write_one_page unlocks the page */
 		}
+	} else if (mp->lsn)	/* discard_metapage doesn't remove it */
+		remove_from_logsync(mp);
 
-		if (test_bit(META_discard, &mp->flag)) {
-			lock_page(mp->page);
-			block_invalidatepage(mp->page, 0);
-			unlock_page(mp->page);
-		}
-
-		page_cache_release(mp->page);
-		mp->page = NULL;
-		INCREMENT(mpStat.pagefree);
-		spin_lock(&meta_lock);
-	}
+#if MPS_PER_PAGE == 1
+	/*
+	 * If we know this is the only thing in the page, we can throw
+	 * the page out of the page cache.  If pages are larger, we
+	 * don't want to do this.
+	 */
 
-	if (mp->lsn) {
-		/*
-		 * Remove metapage from logsynclist.
-		 */
-		log = mp->log;
-		LOGSYNC_LOCK(log);
-		mp->log = NULL;
-		mp->lsn = 0;
-		mp->clsn = 0;
-		log->count--;
-		list_del(&mp->synclist);
-		LOGSYNC_UNLOCK(log);
-	}
-	if (mp->count) {
-		/* Someone else is trying to get this metpage */
-		unlock_metapage(mp);
-		spin_unlock(&meta_lock);
-		return;
+	/* Retest mp->count since we may have released page lock */
+	if (test_bit(META_discard, &mp->flag) && !mp->count) {
+		clear_page_dirty(page);
+		ClearPageUptodate(page);
+#ifdef _NOT_YET
+		if (page->mapping) {
+		/* Remove from page cache and page cache reference */
+			remove_from_page_cache(page);
+			page_cache_release(page);
+			metapage_releasepage(page, 0);
+		}
+#endif
 	}
-	remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
-	spin_unlock(&meta_lock);
-
-	free_metapage(mp);
+#else
+	/* Try to keep metapages from using up too much memory */
+	drop_metapage(page, mp);
+#endif
+	unlock_page(page);
+	page_cache_release(page);
 }
 
 void __invalidate_metapages(struct inode *ip, s64 addr, int len)
 {
-	struct metapage **hash_ptr;
-	unsigned long lblock;
+	sector_t lblock;
 	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
+	int BlocksPerPage = 1 << l2BlocksPerPage;
 	/* All callers are interested in block device's mapping */
-	struct address_space *mapping = ip->i_sb->s_bdev->bd_inode->i_mapping;
+	struct address_space *mapping =
+		JFS_SBI(ip->i_sb)->direct_inode->i_mapping;
 	struct metapage *mp;
 	struct page *page;
+	unsigned int offset;
 
 	/*
-	 * First, mark metapages to discard.  They will eventually be
+	 * 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);
-again:
-		spin_lock(&meta_lock);
-		mp = search_hash(hash_ptr, mapping, lblock);
-		if (mp) {
-			if (test_bit(META_stale, &mp->flag)) {
-				/* Racing with release_metapage */
-				mp->count++;
-				lock_metapage(mp);
-				spin_unlock(&meta_lock);
-				/* racing release_metapage should be done now */
-				release_metapage(mp);
-				goto again;
-			}
+	for (lblock = addr & ~(BlocksPerPage - 1); lblock < addr + len;
+	     lblock += BlocksPerPage) {
+		page = find_lock_page(mapping, lblock >> l2BlocksPerPage);
+		if (!page)
+			continue;
+		for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+			mp = page_to_mp(page, offset);
+			if (!mp)
+				continue;
+			if (mp->index < addr)
+				continue;
+			if (mp->index >= addr + len)
+				break;
 
 			clear_bit(META_dirty, &mp->flag);
 			set_bit(META_discard, &mp->flag);
-			spin_unlock(&meta_lock);
-		} else {
-			spin_unlock(&meta_lock);
-			page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
-			if (page) {
-				block_invalidatepage(page, 0);
-				unlock_page(page);
-				page_cache_release(page);
-			}
+			if (mp->lsn)
+				remove_from_logsync(mp);
 		}
+		unlock_page(page);
+		page_cache_release(page);
 	}
 }
 
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
--- a/fs/jfs/jfs_metapage.h
+++ b/fs/jfs/jfs_metapage.h
@@ -33,38 +33,27 @@ struct metapage {
 	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 */
-
-	/*
-	 * 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;
+	sector_t index; 	/* block address of page */
 	wait_queue_head_t wait;
 
 	/* implementation */
 	struct page *page;
-	unsigned long logical_size;
+	unsigned int logical_size;
 
 	/* Journal management */
 	int clsn;
-	atomic_t nohomeok;
+	int 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 META_stale	7
+#define META_free	1
+#define META_dirty	2
+#define META_sync	3
+#define META_discard	4
+#define META_forcewrite	5
+#define META_io		6
 
 #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
 
@@ -80,7 +69,16 @@ extern struct metapage *__get_metapage(s
 	 __get_metapage(inode, lblock, size, absolute, TRUE)
 
 extern void release_metapage(struct metapage *);
-extern void hold_metapage(struct metapage *, int);
+extern void grab_metapage(struct metapage *);
+extern void force_metapage(struct metapage *);
+
+/*
+ * hold_metapage and put_metapage are used in conjuction.  The page lock
+ * is not dropped between the two, so no other threads can get or release
+ * the metapage
+ */
+extern void hold_metapage(struct metapage *);
+extern void put_metapage(struct metapage *);
 
 static inline void write_metapage(struct metapage *mp)
 {
@@ -101,6 +99,46 @@ static inline void discard_metapage(stru
 	release_metapage(mp);
 }
 
+static inline void metapage_nohomeok(struct metapage *mp)
+{
+	struct page *page = mp->page;
+	lock_page(page);
+	if (!mp->nohomeok++) {
+		mark_metapage_dirty(mp);
+		page_cache_get(page);
+		wait_on_page_writeback(page);
+	}
+	unlock_page(page);
+}
+
+/*
+ * This serializes access to mp->lsn when metapages are added to logsynclist
+ * without setting nohomeok.  i.e. updating imap & dmap
+ */
+static inline void metapage_wait_for_io(struct metapage *mp)
+{
+	if (test_bit(META_io, &mp->flag))
+		wait_on_page_writeback(mp->page);
+}
+
+/*
+ * This is called when already holding the metapage
+ */
+static inline void _metapage_homeok(struct metapage *mp)
+{
+	if (!--mp->nohomeok)
+		page_cache_release(mp->page);
+}
+
+static inline void metapage_homeok(struct metapage *mp)
+{
+	hold_metapage(mp);
+	_metapage_homeok(mp);
+	put_metapage(mp);
+}
+
+extern struct address_space_operations jfs_metapage_aops;
+
 /*
  * This routines invalidate all pages for an extent.
  */
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -285,11 +285,6 @@ int jfs_mount_rw(struct super_block *sb,
 	 */
 	logMOUNT(sb);
 
-	/*
-	 * Set page cache allocation policy
-	 */
-	mapping_set_gfp_mask(sb->s_bdev->bd_inode->i_mapping, GFP_NOFS);
-
 	return rc;
 }
 
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2004
+ *   Copyright (C) International Business Machines Corp., 2000-2005
  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -93,15 +93,15 @@ static struct {
 } TxStat;
 #endif
 
-static int nTxBlock = 512;	/* number of transaction blocks */
+static int nTxBlock = -1;	/* number of transaction blocks */
 module_param(nTxBlock, int, 0);
 MODULE_PARM_DESC(nTxBlock,
-		 "Number of transaction blocks (default:512, max:65536)");
+		 "Number of transaction blocks (max:65536)");
 
-static int nTxLock = 4096;	/* number of transaction locks */
+static int nTxLock = -1;	/* number of transaction locks */
 module_param(nTxLock, int, 0);
 MODULE_PARM_DESC(nTxLock,
-		 "Number of transaction locks (default:4096, max:65536)");
+		 "Number of transaction locks (max:65536)");
 
 struct tblock *TxBlock;	        /* transaction block table */
 static int TxLockLWM;		/* Low water mark for number of txLocks used */
@@ -124,6 +124,7 @@ static DEFINE_SPINLOCK(jfsTxnLock);
 
 DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
 DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
+static int jfs_commit_thread_waking;
 
 /*
  * Retry logic exist outside these macros to protect from spurrious wakeups.
@@ -226,6 +227,7 @@ static lid_t txLockAlloc(void)
 
 static void txLockFree(lid_t lid)
 {
+	TxLock[lid].tid = 0;
 	TxLock[lid].next = TxAnchor.freelock;
 	TxAnchor.freelock = lid;
 	TxAnchor.tlocksInUse--;
@@ -249,6 +251,25 @@ static void txLockFree(lid_t lid)
 int txInit(void)
 {
 	int k, size;
+	struct sysinfo si;
+
+	/* Set defaults for nTxLock and nTxBlock if unset */
+
+	if (nTxLock == -1) {
+		if (nTxBlock == -1) {
+			/* Base default on memory size */
+			si_meminfo(&si);
+			if (si.totalram > (256 * 1024)) /* 1 GB */
+				nTxLock = 64 * 1024;
+			else
+				nTxLock = si.totalram >> 2;
+		} else if (nTxBlock > (8 * 1024))
+			nTxLock = 64 * 1024;
+		else
+			nTxLock = nTxBlock << 3;
+	}
+	if (nTxBlock == -1)
+		nTxBlock = nTxLock >> 3;
 
 	/* Verify tunable parameters */
 	if (nTxBlock < 16)
@@ -259,6 +280,9 @@ int txInit(void)
 		nTxLock = 256;	/* No one should set it this low */
 	if (nTxLock > 65536)
 		nTxLock = 65536;
+
+	printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
+	       nTxBlock, nTxLock);
 	/*
 	 * initialize transaction block (tblock) table
 	 *
@@ -266,8 +290,8 @@ int txInit(void)
 	 * tid = 0 is reserved.
 	 */
 	TxLockLWM = (nTxLock * 4) / 10;
-	TxLockHWM = (nTxLock * 8) / 10;
-	TxLockVHWM = (nTxLock * 9) / 10;
+	TxLockHWM = (nTxLock * 7) / 10;
+	TxLockVHWM = (nTxLock * 8) / 10;
 
 	size = sizeof(struct tblock) * nTxBlock;
 	TxBlock = (struct tblock *) vmalloc(size);
@@ -543,9 +567,6 @@ void txEnd(tid_t tid)
 		 * synchronize with logsync barrier
 		 */
 		if (test_bit(log_SYNCBARRIER, &log->flag)) {
-			/* forward log syncpt */
-			/* lmSync(log); */
-
 			jfs_info("log barrier off: 0x%x", log->lsn);
 
 			/* enable new transactions start */
@@ -553,15 +574,22 @@ void txEnd(tid_t tid)
 
 			/* wakeup all waitors for logsync barrier */
 			TXN_WAKEUP(&log->syncwait);
+
+			TXN_UNLOCK();
+
+			/* forward log syncpt */
+			jfs_syncpt(log);
+
+			goto wakeup;
 		}
 	}
 
+	TXN_UNLOCK();
+wakeup:
 	/*
 	 * wakeup all waitors for a free tblock
 	 */
 	TXN_WAKEUP(&TxAnchor.freewait);
-
-	TXN_UNLOCK();
 }
 
 
@@ -610,8 +638,10 @@ struct tlock *txLock(tid_t tid, struct i
 
 	/* is page locked by the requester transaction ? */
 	tlck = lid_to_tlock(lid);
-	if ((xtid = tlck->tid) == tid)
+	if ((xtid = tlck->tid) == tid) {
+		TXN_UNLOCK();
 		goto grantLock;
+	}
 
 	/*
 	 * is page locked by anonymous transaction/lock ?
@@ -626,6 +656,7 @@ struct tlock *txLock(tid_t tid, struct i
 	 */
 	if (xtid == 0) {
 		tlck->tid = tid;
+		TXN_UNLOCK();
 		tblk = tid_to_tblock(tid);
 		/*
 		 * The order of the tlocks in the transaction is important
@@ -683,17 +714,18 @@ struct tlock *txLock(tid_t tid, struct i
 	 */
 	tlck->tid = tid;
 
+	TXN_UNLOCK();
+
 	/* 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);
+		metapage_nohomeok(mp);
 
 		jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
-			 mp, atomic_read(&mp->nohomeok), tid, tlck);
+			 mp, mp->nohomeok, tid, tlck);
 
 		/* if anonymous transaction, and buffer is on the group
 		 * commit synclist, mark inode to show this.  This will
@@ -739,8 +771,10 @@ struct tlock *txLock(tid_t tid, struct i
 		if (tlck->next == 0) {
 			/* This inode's first anonymous transaction */
 			jfs_ip->atltail = lid;
+			TXN_LOCK();
 			list_add_tail(&jfs_ip->anon_inode_list,
 				      &TxAnchor.anon_list);
+			TXN_UNLOCK();
 		}
 	}
 
@@ -798,8 +832,6 @@ struct tlock *txLock(tid_t tid, struct i
       grantLock:
 	tlck->type |= type;
 
-	TXN_UNLOCK();
-
 	return tlck;
 
 	/*
@@ -818,11 +850,19 @@ struct tlock *txLock(tid_t tid, struct i
 		BUG();
 	}
 	INCREMENT(stattx.waitlock);	/* statistics */
+	TXN_UNLOCK();
 	release_metapage(mp);
+	TXN_LOCK();
+	xtid = tlck->tid;	/* reaquire after dropping TXN_LOCK */
 
 	jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
 		 tid, xtid, lid);
-	TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+
+	/* Recheck everything since dropping TXN_LOCK */
+	if (xtid && (tlck->mp == mp) && (mp->lid == lid))
+		TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+	else
+		TXN_UNLOCK();
 	jfs_info("txLock: awakened     tid = %d, lid = %d", tid, lid);
 
 	return NULL;
@@ -883,6 +923,7 @@ static void txUnlock(struct tblock * tbl
 	struct metapage *mp;
 	struct jfs_log *log;
 	int difft, diffp;
+	unsigned long flags;
 
 	jfs_info("txUnlock: tblk = 0x%p", tblk);
 	log = JFS_SBI(tblk->sb)->log;
@@ -902,19 +943,14 @@ static void txUnlock(struct tblock * tbl
 			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);
+			hold_metapage(mp);
 
-			assert(atomic_read(&mp->nohomeok) > 0);
-			atomic_dec(&mp->nohomeok);
+			assert(mp->nohomeok > 0);
+			_metapage_homeok(mp);
 
 			/* inherit younger/larger clsn */
-			LOGSYNC_LOCK(log);
+			LOGSYNC_LOCK(log, flags);
 			if (mp->clsn) {
 				logdiff(difft, tblk->clsn, log);
 				logdiff(diffp, mp->clsn, log);
@@ -922,16 +958,11 @@ static void txUnlock(struct tblock * tbl
 					mp->clsn = tblk->clsn;
 			} else
 				mp->clsn = tblk->clsn;
-			LOGSYNC_UNLOCK(log);
+			LOGSYNC_UNLOCK(log, flags);
 
 			assert(!(tlck->flag & tlckFREEPAGE));
 
-			if (tlck->flag & tlckWRITEPAGE) {
-				write_metapage(mp);
-			} else {
-				/* release page which has been forced */
-				release_metapage(mp);
-			}
+			put_metapage(mp);
 		}
 
 		/* insert tlock, and linelock(s) of the tlock if any,
@@ -958,10 +989,10 @@ static void txUnlock(struct tblock * tbl
 	 * has been inserted in logsync list at txUpdateMap())
 	 */
 	if (tblk->lsn) {
-		LOGSYNC_LOCK(log);
+		LOGSYNC_LOCK(log, flags);
 		log->count--;
 		list_del(&tblk->synclist);
-		LOGSYNC_UNLOCK(log);
+		LOGSYNC_UNLOCK(log, flags);
 	}
 }
 
@@ -1544,14 +1575,14 @@ static int dataLog(struct jfs_log * log,
 	/* log after-image for logredo(): */
 	lrd->type = cpu_to_le16(LOG_REDOPAGE);
 
-	if (JFS_IP(tlck->ip)->next_index < MAX_INLINE_DIRTABLE_ENTRY) {
+	if (jfs_dirtable_inline(tlck->ip)) {
 		/*
 		 * The table has been truncated, we've must have deleted
 		 * the last entry, so don't bother logging this
 		 */
 		mp->lid = 0;
-		hold_metapage(mp, 0);
-		atomic_dec(&mp->nohomeok);
+		grab_metapage(mp);
+		metapage_homeok(mp);
 		discard_metapage(mp);
 		tlck->mp = NULL;
 		return 0;
@@ -1689,7 +1720,7 @@ static void xtLog(struct jfs_log * log, 
 	struct maplock *maplock;
 	struct xdlistlock *xadlock;
 	struct pxd_lock *pxdlock;
-	pxd_t *pxd;
+	pxd_t *page_pxd;
 	int next, lwm, hwm;
 
 	ip = tlck->ip;
@@ -1699,7 +1730,7 @@ static void xtLog(struct jfs_log * log, 
 	lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
 	lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
 
-	pxd = &lrd->log.redopage.pxd;
+	page_pxd = &lrd->log.redopage.pxd;
 
 	if (tlck->type & tlckBTROOT) {
 		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
@@ -1729,9 +1760,9 @@ static void xtLog(struct jfs_log * log, 
 		 * 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,
+//              *page_pxd = mp->cm_pxd;
+		PXDaddress(page_pxd, mp->index);
+		PXDlength(page_pxd,
 			  mp->logical_size >> tblk->sb->s_blocksize_bits);
 		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
 
@@ -1753,25 +1784,31 @@ static void xtLog(struct jfs_log * log, 
 		tlck->flag |= tlckUPDATEMAP;
 		xadlock->flag = mlckALLOCXADLIST;
 		xadlock->count = next - lwm;
-		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+		if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
 			int i;
+			pxd_t *pxd;
 			/*
 			 * Lazy commit may allow xtree to be modified before
 			 * txUpdateMap runs.  Copy xad into linelock to
 			 * preserve correct data.
+			 *
+			 * We can fit twice as may pxd's as xads in the lock
 			 */
-			xadlock->xdlist = &xtlck->pxdlock;
-			memcpy(xadlock->xdlist, &p->xad[lwm],
-			       sizeof(xad_t) * xadlock->count);
-
-			for (i = 0; i < xadlock->count; i++)
+			xadlock->flag = mlckALLOCPXDLIST;
+			pxd = xadlock->xdlist = &xtlck->pxdlock;
+			for (i = 0; i < xadlock->count; i++) {
+				PXDaddress(pxd, addressXAD(&p->xad[lwm + i]));
+				PXDlength(pxd, lengthXAD(&p->xad[lwm + i]));
 				p->xad[lwm + i].flag &=
 				    ~(XAD_NEW | XAD_EXTENDED);
+				pxd++;
+			}
 		} else {
 			/*
 			 * xdlist will point to into inode's xtree, ensure
 			 * that transaction is not committed lazily.
 			 */
+			xadlock->flag = mlckALLOCXADLIST;
 			xadlock->xdlist = &p->xad[lwm];
 			tblk->xflag &= ~COMMIT_LAZY;
 		}
@@ -1813,8 +1850,8 @@ static void xtLog(struct jfs_log * log, 
 		if (tblk->xflag & COMMIT_TRUNCATE) {
 			/* write NOREDOPAGE for the page */
 			lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
-			PXDaddress(pxd, mp->index);
-			PXDlength(pxd,
+			PXDaddress(page_pxd, mp->index);
+			PXDlength(page_pxd,
 				  mp->logical_size >> tblk->sb->
 				  s_blocksize_bits);
 			lrd->backchain =
@@ -1849,22 +1886,32 @@ static void xtLog(struct jfs_log * log, 
 		 * deleted page itself;
 		 */
 		tlck->flag |= tlckUPDATEMAP;
-		xadlock->flag = mlckFREEXADLIST;
 		xadlock->count = hwm - XTENTRYSTART + 1;
-		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+		if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
+			int i;
+			pxd_t *pxd;
 			/*
 			 * Lazy commit may allow xtree to be modified before
 			 * txUpdateMap runs.  Copy xad into linelock to
 			 * preserve correct data.
+			 *
+			 * We can fit twice as may pxd's as xads in the lock
 			 */
-			xadlock->xdlist = &xtlck->pxdlock;
-			memcpy(xadlock->xdlist, &p->xad[XTENTRYSTART],
-			       sizeof(xad_t) * xadlock->count);
+			xadlock->flag = mlckFREEPXDLIST;
+			pxd = xadlock->xdlist = &xtlck->pxdlock;
+			for (i = 0; i < xadlock->count; i++) {
+				PXDaddress(pxd,
+					addressXAD(&p->xad[XTENTRYSTART + i]));
+				PXDlength(pxd,
+					lengthXAD(&p->xad[XTENTRYSTART + i]));
+				pxd++;
+			}
 		} else {
 			/*
 			 * xdlist will point to into inode's xtree, ensure
 			 * that transaction is not committed lazily.
 			 */
+			xadlock->flag = mlckFREEXADLIST;
 			xadlock->xdlist = &p->xad[XTENTRYSTART];
 			tblk->xflag &= ~COMMIT_LAZY;
 		}
@@ -1895,7 +1942,7 @@ static void xtLog(struct jfs_log * log, 
 	 * header ?
 	 */
 	if (tlck->type & tlckTRUNCATE) {
-		pxd_t tpxd;	/* truncated extent of xad */
+		pxd_t pxd;	/* truncated extent of xad */
 		int twm;
 
 		/*
@@ -1924,8 +1971,9 @@ static void xtLog(struct jfs_log * log, 
 		 * 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);
+		PXDaddress(page_pxd, mp->index);
+		PXDlength(page_pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
 		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
 
 		/*
@@ -1943,7 +1991,7 @@ static void xtLog(struct jfs_log * log, 
 			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 */
+			pxd = pxdlock->pxd;	/* save to format maplock */
 			lrd->backchain =
 			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
 		}
@@ -2012,7 +2060,7 @@ static void xtLog(struct jfs_log * log, 
 			pxdlock = (struct pxd_lock *) xadlock;
 			pxdlock->flag = mlckFREEPXD;
 			pxdlock->count = 1;
-			pxdlock->pxd = tpxd;
+			pxdlock->pxd = pxd;
 
 			jfs_info("xtLog: truncate ip:0x%p mp:0x%p count:%d "
 				 "hwm:%d", ip, mp, pxdlock->count, hwm);
@@ -2230,7 +2278,8 @@ void txForce(struct tblock * tblk)
 				tlck->flag &= ~tlckWRITEPAGE;
 
 				/* do not release page to freelist */
-
+				force_metapage(mp);
+#if 0
 				/*
 				 * The "right" thing to do here is to
 				 * synchronously write the metadata.
@@ -2242,9 +2291,10 @@ void txForce(struct tblock * tblk)
 				 * we can get by with synchronously writing
 				 * the pages when they are released.
 				 */
-				assert(atomic_read(&mp->nohomeok));
+				assert(mp->nohomeok);
 				set_bit(META_dirty, &mp->flag);
 				set_bit(META_sync, &mp->flag);
+#endif
 			}
 		}
 	}
@@ -2304,7 +2354,7 @@ static void txUpdateMap(struct tblock * 
 			 */
 			mp = tlck->mp;
 			ASSERT(mp->xflag & COMMIT_PAGE);
-			hold_metapage(mp, 0);
+			grab_metapage(mp);
 		}
 
 		/*
@@ -2354,8 +2404,8 @@ static void txUpdateMap(struct tblock * 
 				ASSERT(mp->lid == lid);
 				tlck->mp->lid = 0;
 			}
-			assert(atomic_read(&mp->nohomeok) == 1);
-			atomic_dec(&mp->nohomeok);
+			assert(mp->nohomeok == 1);
+			metapage_homeok(mp);
 			discard_metapage(mp);
 			tlck->mp = NULL;
 		}
@@ -2732,6 +2782,7 @@ int jfs_lazycommit(void *arg)
 
 	do {
 		LAZY_LOCK(flags);
+		jfs_commit_thread_waking = 0;	/* OK to wake another thread */
 		while (!list_empty(&TxAnchor.unlock_queue)) {
 			WorkDone = 0;
 			list_for_each_entry(tblk, &TxAnchor.unlock_queue,
@@ -2772,6 +2823,8 @@ int jfs_lazycommit(void *arg)
 			if (!WorkDone)
 				break;
 		}
+		/* In case a wakeup came while all threads were active */
+		jfs_commit_thread_waking = 0;
 
 		if (current->flags & PF_FREEZE) {
 			LAZY_UNLOCK(flags);
@@ -2804,10 +2857,13 @@ void txLazyUnlock(struct tblock * tblk)
 	list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
 	/*
 	 * Don't wake up a commit thread if there is already one servicing
-	 * this superblock.
+	 * this superblock, or if the last one we woke up hasn't started yet.
 	 */
-	if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT))
+	if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT) &&
+	    !jfs_commit_thread_waking) {
+		jfs_commit_thread_waking = 1;
 		wake_up(&jfs_commit_thread_wait);
+	}
 	LAZY_UNLOCK(flags);
 }
 
@@ -2815,24 +2871,9 @@ static void LogSyncRelease(struct metapa
 {
 	struct jfs_log *log = mp->log;
 
-	assert(atomic_read(&mp->nohomeok));
+	assert(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);
+	metapage_homeok(mp);
 }
 
 /*
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -49,7 +49,6 @@
  */
 int jfs_umount(struct super_block *sb)
 {
-	struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	struct inode *ipbmap = sbi->ipbmap;
 	struct inode *ipimap = sbi->ipimap;
@@ -109,8 +108,8 @@ int jfs_umount(struct super_block *sb)
 	 * Make sure all metadata makes it to disk before we mark
 	 * the superblock as clean
 	 */
-	filemap_fdatawrite(bdev_mapping);
-	filemap_fdatawait(bdev_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
 
 	/*
 	 * ensure all file system file pages are propagated to their
@@ -123,9 +122,6 @@ int jfs_umount(struct super_block *sb)
 	if (log) {		/* log = NULL if read-only mount */
 		updateSuper(sb, FM_CLEAN);
 
-		/* Restore default gfp_mask for bdev */
-		mapping_set_gfp_mask(bdev_mapping, GFP_USER);
-
 		/*
 		 * close log: 
 		 *
@@ -140,7 +136,6 @@ int jfs_umount(struct super_block *sb)
 
 int jfs_umount_rw(struct super_block *sb)
 {
-	struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	struct jfs_log *log = sbi->log;
 
@@ -166,13 +161,10 @@ int jfs_umount_rw(struct super_block *sb
 	 * mark the superblock clean before everything is flushed to
 	 * disk.
 	 */
-	filemap_fdatawrite(bdev_mapping);
-	filemap_fdatawait(bdev_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
 
 	updateSuper(sb, FM_CLEAN);
 
-	/* Restore default gfp_mask for bdev */
-	mapping_set_gfp_mask(bdev_mapping, GFP_USER);
-
 	return lmLogClose(sb);
 }
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2004
+ *   Copyright (C) International Business Machines Corp., 2000-2005
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -111,8 +111,8 @@ static struct {
 /*
  * forward references
  */
-static int xtSearch(struct inode *ip,
-		    s64 xoff, int *cmpp, struct btstack * btstack, int flag);
+static int xtSearch(struct inode *ip, s64 xoff, s64 *next, int *cmpp,
+		    struct btstack * btstack, int flag);
 
 static int xtSplitUp(tid_t tid,
 		     struct inode *ip,
@@ -159,11 +159,12 @@ int xtLookup(struct inode *ip, s64 lstar
 	xtpage_t *p;
 	int index;
 	xad_t *xad;
-	s64 size, xoff, xend;
+	s64 next, size, xoff, xend;
 	int xlen;
 	s64 xaddr;
 
-	*plen = 0;
+	*paddr = 0;
+	*plen = llen;
 
 	if (!no_check) {
 		/* is lookup offset beyond eof ? */
@@ -180,7 +181,7 @@ int xtLookup(struct inode *ip, s64 lstar
 	 * search for the xad entry covering the logical extent
 	 */
 //search:
-	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) {
+	if ((rc = xtSearch(ip, lstart, &next, &cmp, &btstack, 0))) {
 		jfs_err("xtLookup: xtSearch returned %d", rc);
 		return rc;
 	}
@@ -198,8 +199,11 @@ int xtLookup(struct inode *ip, s64 lstar
 	 * lstart is a page start address,
 	 * i.e., lstart cannot start in a hole;
 	 */
-	if (cmp)
+	if (cmp) {
+		if (next)
+			*plen = min(next - lstart, llen);
 		goto out;
+	}
 
 	/*
 	 * lxd covered by xad
@@ -284,7 +288,7 @@ int xtLookupList(struct inode *ip, struc
 	if (lstart >= size)
 		return 0;
 
-	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0)))
+	if ((rc = xtSearch(ip, lstart, NULL, &cmp, &btstack, 0)))
 		return rc;
 
 	/*
@@ -488,6 +492,7 @@ int xtLookupList(struct inode *ip, struc
  * parameters:
  *      ip      - file object;
  *      xoff    - extent offset;
+ *      nextp	- address of next extent (if any) for search miss
  *      cmpp    - comparison result:
  *      btstack - traverse stack;
  *      flag    - search process flag (XT_INSERT);
@@ -497,7 +502,7 @@ int xtLookupList(struct inode *ip, struc
  *      *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 */
+static int xtSearch(struct inode *ip, s64 xoff,	s64 *nextp,
 		    int *cmpp, struct btstack * btstack, int flag)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
@@ -511,6 +516,7 @@ static int xtSearch(struct inode *ip, s6
 	struct btframe *btsp;
 	int nsplit = 0;		/* number of pages to split */
 	s64 t64;
+	s64 next = 0;
 
 	INCREMENT(xtStat.search);
 
@@ -579,6 +585,7 @@ static int xtSearch(struct inode *ip, s6
 						 * previous and this entry
 						 */
 						*cmpp = 1;
+						next = t64;
 						goto out;
 					}
 
@@ -623,6 +630,9 @@ static int xtSearch(struct inode *ip, s6
 			/* update sequential access heuristics */
 			jfs_ip->btindex = index;
 
+			if (nextp)
+				*nextp = next;
+
 			INCREMENT(xtStat.fastSearch);
 			return 0;
 		}
@@ -675,10 +685,11 @@ static int xtSearch(struct inode *ip, s6
 
 					return 0;
 				}
-
 				/* search hit - internal page:
 				 * descend/search its child page
 				 */
+				if (index < le16_to_cpu(p->header.nextindex)-1)
+					next = offsetXAD(&p->xad[index + 1]);
 				goto next;
 			}
 
@@ -694,6 +705,8 @@ static int xtSearch(struct inode *ip, s6
 		 * base is the smallest index with key (Kj) greater than
 		 * search key (K) and may be zero or maxentry index.
 		 */
+		if (base < le16_to_cpu(p->header.nextindex))
+			next = offsetXAD(&p->xad[base]);
 		/*
 		 * search miss - leaf page:
 		 *
@@ -727,6 +740,9 @@ static int xtSearch(struct inode *ip, s6
 				jfs_ip->btorder = BT_RANDOM;
 			jfs_ip->btindex = base;
 
+			if (nextp)
+				*nextp = next;
+
 			return 0;
 		}
 
@@ -793,6 +809,7 @@ int xtInsert(tid_t tid,		/* transaction 
 	struct xtsplit split;	/* split information */
 	xad_t *xad;
 	int cmp;
+	s64 next;
 	struct tlock *tlck;
 	struct xtlock *xtlck;
 
@@ -806,7 +823,7 @@ int xtInsert(tid_t tid,		/* transaction 
 	 * n.b. xtSearch() may return index of maxentry of
 	 * the full page.
 	 */
-	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+	if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
 	/* retrieve search result */
@@ -814,7 +831,7 @@ int xtInsert(tid_t tid,		/* transaction 
 
 	/* This test must follow XT_GETSEARCH since mp must be valid if
 	 * we branch to out: */
-	if (cmp == 0) {
+	if ((cmp == 0) || (next && (xlen > next - xoff))) {
 		rc = -EEXIST;
 		goto out;
 	}
@@ -1626,7 +1643,7 @@ int xtExtend(tid_t tid,		/* transaction 
 	jfs_info("xtExtend: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
 
 	/* there must exist extent to be extended */
-	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
+	if ((rc = xtSearch(ip, xoff - 1, NULL, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
 	/* retrieve search result */
@@ -1794,7 +1811,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x
 */
 
 	/* there must exist extent to be tailgated */
-	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+	if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
 	/* retrieve search result */
@@ -1977,7 +1994,7 @@ int xtUpdate(tid_t tid, struct inode *ip
 	nxlen = lengthXAD(nxad);
 	nxaddr = addressXAD(nxad);
 
-	if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+	if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
 	/* retrieve search result */
@@ -2291,7 +2308,7 @@ int xtUpdate(tid_t tid, struct inode *ip
 	if (nextindex == le16_to_cpu(p->header.maxentry)) {
 		XT_PUTPAGE(mp);
 
-		if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+		if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
 			return rc;
 
 		/* retrieve search result */
@@ -2438,6 +2455,7 @@ int xtAppend(tid_t tid,		/* transaction 
 	int nsplit, nblocks, xlen;
 	struct pxdlist pxdlist;
 	pxd_t *pxd;
+	s64 next;
 
 	xaddr = *xaddrp;
 	xlen = *xlenp;
@@ -2452,7 +2470,7 @@ int xtAppend(tid_t tid,		/* transaction 
 	 * n.b. xtSearch() may return index of maxentry of
 	 * the full page.
 	 */
-	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+	if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
 	/* retrieve search result */
@@ -2462,6 +2480,9 @@ int xtAppend(tid_t tid,		/* transaction 
 		rc = -EEXIST;
 		goto out;
 	}
+
+	if (next)
+		xlen = min(xlen, (int)(next - xoff));
 //insert:
 	/*
 	 *      insert entry for new extent
@@ -2600,7 +2621,7 @@ int xtDelete(tid_t tid, struct inode *ip
 	/*
 	 * find the matching entry; xtSearch() pins the page
 	 */
-	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+	if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0)))
 		return rc;
 
 	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
@@ -2852,7 +2873,7 @@ xtRelocate(tid_t tid, struct inode * ip,
 	 */
 	if (xtype == DATAEXT) {
 		/* search in leaf entry */
-		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
 
@@ -2958,7 +2979,7 @@ xtRelocate(tid_t tid, struct inode * ip,
 		}
 
 		/* get back parent page */
-		if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+		if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0)))
 			return rc;
 
 		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
@@ -3991,7 +4012,7 @@ s64 xtTruncate_pmap(tid_t tid, struct in
 
 	if (committed_size) {
 		xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
-		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
 
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -262,8 +262,6 @@ static int jfs_mkdir(struct inode *dip, 
 	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;
-	mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
 
 	insert_inode_hash(ip);
 	mark_inode_dirty(ip);
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
--- a/fs/jfs/resize.c
+++ b/fs/jfs/resize.c
@@ -209,6 +209,9 @@ int jfs_extendfs(struct super_block *sb,
 	 */
 	txQuiesce(sb);
 
+	/* Reset size of direct inode */
+	sbi->direct_inode->i_size =  sb->s_bdev->bd_inode->i_size;
+
 	if (sbi->mntflag & JFS_INLINELOG) {
 		/*
 		 * deactivate old inline log
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -210,6 +210,10 @@ static void jfs_put_super(struct super_b
 		unload_nls(sbi->nls_tab);
 	sbi->nls_tab = NULL;
 
+	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
+	iput(sbi->direct_inode);
+	sbi->direct_inode = NULL;
+
 	kfree(sbi);
 }
 
@@ -235,7 +239,7 @@ static match_table_t tokens = {
 static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
 			 int *flag)
 {
-	void *nls_map = NULL;
+	void *nls_map = (void *)-1;	/* -1: no change;  NULL: none */
 	char *p;
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 
@@ -263,12 +267,17 @@ static int parse_options(char *options, 
 			/* Don't do anything ;-) */
 			break;
 		case Opt_iocharset:
-			if (nls_map)	/* specified iocharset twice! */
+			if (nls_map && nls_map != (void *) -1)
 				unload_nls(nls_map);
-			nls_map = load_nls(args[0].from);
-			if (!nls_map) {
-				printk(KERN_ERR "JFS: charset not found\n");
-				goto cleanup;
+			if (!strcmp(args[0].from, "none"))
+				nls_map = NULL;
+			else {
+				nls_map = load_nls(args[0].from);
+				if (!nls_map) {
+					printk(KERN_ERR
+					       "JFS: charset not found\n");
+					goto cleanup;
+				}
 			}
 			break;
 		case Opt_resize:
@@ -318,7 +327,7 @@ static int parse_options(char *options, 
 		}
 	}
 
-	if (nls_map) {
+	if (nls_map != (void *) -1) {
 		/* Discard old (if remount) */
 		if (sbi->nls_tab)
 			unload_nls(sbi->nls_tab);
@@ -327,7 +336,7 @@ static int parse_options(char *options, 
 	return 1;
 
 cleanup:
-	if (nls_map)
+	if (nls_map && nls_map != (void *) -1)
 		unload_nls(nls_map);
 	return 0;
 }
@@ -353,6 +362,12 @@ static int jfs_remount(struct super_bloc
 	}
 
 	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+		/*
+		 * Invalidate any previously read metadata.  fsck may have
+		 * changed the on-disk data since we mounted r/o
+		 */
+		truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);
+
 		JFS_SBI(sb)->flag = flag;
 		return jfs_mount_rw(sb, 1);
 	}
@@ -423,12 +438,26 @@ static int jfs_fill_super(struct super_b
 	sb->s_op = &jfs_super_operations;
 	sb->s_export_op = &jfs_export_operations;
 
+	/*
+	 * Initialize direct-mapping inode/address-space
+	 */
+	inode = new_inode(sb);
+	if (inode == NULL)
+		goto out_kfree;
+	inode->i_ino = 0;
+	inode->i_nlink = 1;
+	inode->i_size = sb->s_bdev->bd_inode->i_size;
+	inode->i_mapping->a_ops = &jfs_metapage_aops;
+	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+
+	sbi->direct_inode = inode;
+
 	rc = jfs_mount(sb);
 	if (rc) {
 		if (!silent) {
 			jfs_err("jfs_mount failed w/return code = %d", rc);
 		}
-		goto out_kfree;
+		goto out_mount_failed;
 	}
 	if (sb->s_flags & MS_RDONLY)
 		sbi->log = NULL;
@@ -477,6 +506,13 @@ out_no_rw:
 	if (rc) {
 		jfs_err("jfs_umount failed with return code %d", rc);
 	}
+out_mount_failed:
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
+	make_bad_inode(sbi->direct_inode);
+	iput(sbi->direct_inode);
+	sbi->direct_inode = NULL;
 out_kfree:
 	if (sbi->nls_tab)
 		unload_nls(sbi->nls_tab);
@@ -522,8 +558,10 @@ static int jfs_sync_fs(struct super_bloc
 	struct jfs_log *log = JFS_SBI(sb)->log;
 
 	/* log == NULL indicates read-only mount */
-	if (log)
+	if (log) {
 		jfs_flush_journal(log, wait);
+		jfs_syncpt(log);
+	}
 
 	return 0;
 }
@@ -622,7 +660,7 @@ static int __init init_jfs_fs(void)
 
 	if (commit_threads < 1)
 		commit_threads = num_online_cpus();
-	else if (commit_threads > MAX_COMMIT_THREADS)
+	if (commit_threads > MAX_COMMIT_THREADS)
 		commit_threads = MAX_COMMIT_THREADS;
 
 	for (i = 0; i < commit_threads; i++) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -312,6 +312,7 @@ static int nlm_wait_on_grace(wait_queue_
 	prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
 	if (!signalled ()) {
 		schedule_timeout(NLMCLNT_GRACE_WAIT);
+		try_to_freeze(PF_FREEZE);
 		if (!signalled ())
 			status = 0;
 	}
@@ -322,14 +323,13 @@ static int nlm_wait_on_grace(wait_queue_
 /*
  * Generic NLM call
  */
-int
+static int
 nlmclnt_call(struct nlm_rqst *req, u32 proc)
 {
 	struct nlm_host	*host = req->a_host;
 	struct rpc_clnt	*clnt;
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_res	*resp = &req->a_res;
-	struct file	*filp = argp->lock.fl.fl_file;
 	struct rpc_message msg = {
 		.rpc_argp	= argp,
 		.rpc_resp	= resp,
@@ -339,9 +339,6 @@ nlmclnt_call(struct nlm_rqst *req, u32 p
 	dprintk("lockd: call procedure %d on %s\n",
 			(int)proc, host->h_name);
 
-	if (filp)
-		msg.rpc_cred = nfs_file_cred(filp);
-
 	do {
 		if (host->h_reclaiming && !argp->reclaim)
 			goto in_grace_period;
@@ -428,14 +425,13 @@ nlmsvc_async_call(struct nlm_rqst *req, 
 	return status;
 }
 
-int
+static int
 nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
 {
 	struct nlm_host	*host = req->a_host;
 	struct rpc_clnt	*clnt;
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_res	*resp = &req->a_res;
-	struct file	*file = argp->lock.fl.fl_file;
 	struct rpc_message msg = {
 		.rpc_argp	= argp,
 		.rpc_resp	= resp,
@@ -450,11 +446,9 @@ nlmclnt_async_call(struct nlm_rqst *req,
 		return -ENOLCK;
 	msg.rpc_proc = &clnt->cl_procinfo[proc];
 
-        /* bootstrap and kick off the async RPC call */
-	if (file)
-		msg.rpc_cred = nfs_file_cred(file);
 	/* Increment host refcount */
 	nlm_get_host(host);
+        /* bootstrap and kick off the async RPC call */
         status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
 	if (status < 0)
 		nlm_release_host(host);
@@ -516,6 +510,24 @@ static void nlmclnt_locks_init_private(s
 	fl->fl_ops = &nlmclnt_lock_ops;
 }
 
+static void do_vfs_lock(struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(fl->fl_file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(fl->fl_file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+}
+
 /*
  * LOCK: Try to create a lock
  *
@@ -564,9 +576,7 @@ nlmclnt_lock(struct nlm_rqst *req, struc
 		fl->fl_u.nfs_fl.state = host->h_state;
 		fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
 		fl->fl_flags |= FL_SLEEP;
-		if (posix_lock_file_wait(fl->fl_file, fl) < 0)
-				printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
-						__FUNCTION__);
+		do_vfs_lock(fl);
 	}
 	status = nlm_stat_to_errno(resp->status);
 out:
@@ -635,7 +645,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str
 					nlmclnt_unlock_callback);
 		/* Hrmf... Do the unlock early since locks_remove_posix()
 		 * really expects us to free the lock synchronously */
-		posix_lock_file(fl->fl_file, fl);
+		do_vfs_lock(fl);
 		if (status < 0) {
 			nlmclnt_release_lockargs(req);
 			kfree(req);
@@ -648,7 +658,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str
 	if (status < 0)
 		return status;
 
-	posix_lock_file(fl->fl_file, fl);
+	do_vfs_lock(fl);
 	if (resp->status == NLM_LCK_GRANTED)
 		return 0;
 
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -110,7 +110,6 @@ nlm_lookup_host(int server, struct socka
 	host->h_addr.sin_port = 0;	/* ouch! */
 	host->h_version    = version;
 	host->h_proto      = proto;
-	host->h_authflavor = RPC_AUTH_UNIX;
 	host->h_rpcclnt    = NULL;
 	init_MUTEX(&host->h_sema);
 	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
@@ -191,8 +190,9 @@ nlm_bind_host(struct nlm_host *host)
 
 		xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
 
+		/* Existing NLM servers accept AUTH_UNIX only */
 		clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
-					host->h_version, host->h_authflavor);
+					host->h_version, RPC_AUTH_UNIX);
 		if (IS_ERR(clnt)) {
 			xprt_destroy(xprt);
 			goto forgetit;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -403,6 +403,38 @@ static int param_set_##name(const char *
 	return 0;							\
 }
 
+static inline int is_callback(u32 proc)
+{
+	return proc == NLMPROC_GRANTED
+		|| proc == NLMPROC_GRANTED_MSG
+		|| proc == NLMPROC_TEST_RES
+		|| proc == NLMPROC_LOCK_RES
+		|| proc == NLMPROC_CANCEL_RES
+		|| proc == NLMPROC_UNLOCK_RES
+		|| proc == NLMPROC_NSM_NOTIFY;
+}
+
+
+static int lockd_authenticate(struct svc_rqst *rqstp)
+{
+	rqstp->rq_client = NULL;
+	switch (rqstp->rq_authop->flavour) {
+		case RPC_AUTH_NULL:
+		case RPC_AUTH_UNIX:
+			if (rqstp->rq_proc == 0)
+				return SVC_OK;
+			if (is_callback(rqstp->rq_proc)) {
+				/* Leave it to individual procedures to
+				 * call nlmsvc_lookup_host(rqstp)
+				 */
+				return SVC_OK;
+			}
+			return svc_set_client(rqstp);
+	}
+	return SVC_DENIED;
+}
+
+
 param_set_min_max(port, int, simple_strtol, 0, 65535)
 param_set_min_max(grace_period, unsigned long, simple_strtoul,
 		  nlm_grace_period_min, nlm_grace_period_max)
@@ -483,4 +515,5 @@ static struct svc_program	nlmsvc_program
 	.pg_name		= "lockd",		/* service name */
 	.pg_class		= "nfsd",		/* share authentication with nfsd */
 	.pg_stats		= &nlmsvc_stats,	/* stats table */
+	.pg_authenticate = &lockd_authenticate	/* export authentication */
 };
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -641,7 +641,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqst
 		} else {
 			/* Lock is now held by client, or has been rejected.
 			 * In both cases, the block should be removed. */
-			file->f_count++;
 			up(&file->f_sema);
 			if (status == NLM_LCK_GRANTED)
 				nlmsvc_delete_block(block, 0);
diff --git a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -406,9 +406,16 @@ static void lease_release_private_callba
 	fl->fl_file->f_owner.signum = 0;
 }
 
-struct lock_manager_operations lease_manager_ops = {
+static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try)
+{
+	return fl->fl_file == try->fl_file;
+}
+
+static struct lock_manager_operations lease_manager_ops = {
 	.fl_break = lease_break_callback,
 	.fl_release_private = lease_release_private_callback,
+	.fl_mylease = lease_mylease_callback,
+	.fl_change = lease_modify,
 };
 
 /*
@@ -1058,7 +1065,7 @@ int locks_mandatory_area(int read_write,
 EXPORT_SYMBOL(locks_mandatory_area);
 
 /* We already had a lease on this file; just change its type */
-static int lease_modify(struct file_lock **before, int arg)
+int lease_modify(struct file_lock **before, int arg)
 {
 	struct file_lock *fl = *before;
 	int error = assign_type(fl, arg);
@@ -1071,6 +1078,8 @@ static int lease_modify(struct file_lock
 	return 0;
 }
 
+EXPORT_SYMBOL(lease_modify);
+
 static void time_out_leases(struct inode *inode)
 {
 	struct file_lock **before;
@@ -1090,24 +1099,6 @@ static void time_out_leases(struct inode
 	}
 }
 
- /**
-*	remove_lease - let time_out_leases remove the lease.
-*	@@file_lock: the lease to remove
-*/
-void remove_lease(struct file_lock *fl)
-{
-	lock_kernel();
-	if (!fl || !IS_LEASE(fl))
-		goto out;
-	fl->fl_type = F_UNLCK | F_INPROGRESS;
-	fl->fl_break_time = jiffies - 10;
-	time_out_leases(fl->fl_file->f_dentry->d_inode);
-out:
-	unlock_kernel();
-}
-
-EXPORT_SYMBOL(remove_lease);
-
 /**
  *	__break_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
@@ -1172,10 +1163,8 @@ int __break_lease(struct inode *inode, u
 		if (fl->fl_type != future) {
 			fl->fl_type = future;
 			fl->fl_break_time = break_time;
-			if (fl->fl_lmops && fl->fl_lmops->fl_break)
-				fl->fl_lmops->fl_break(fl);
-			else    /* lease must have lmops break callback */
-				BUG();
+			/* lease must have lmops break callback */
+			fl->fl_lmops->fl_break(fl);
 		}
 	}
 
@@ -1285,7 +1274,7 @@ int fcntl_getlease(struct file *filp)
  *
  *	Called with kernel lock held.
  */
-int __setlease(struct file *filp, long arg, struct file_lock **flp)
+static int __setlease(struct file *filp, long arg, struct file_lock **flp)
 {
 	struct file_lock *fl, **before, **my_before = NULL, *lease = *flp;
 	struct dentry *dentry = filp->f_dentry;
@@ -1317,7 +1306,7 @@ int __setlease(struct file *filp, long a
 	for (before = &inode->i_flock;
 			((fl = *before) != NULL) && IS_LEASE(fl);
 			before = &fl->fl_next) {
-		if (fl->fl_file == filp)
+		if (lease->fl_lmops->fl_mylease(fl, lease))
 			my_before = before;
 		else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
 			/*
@@ -1335,7 +1324,7 @@ int __setlease(struct file *filp, long a
 		goto out;
 
 	if (my_before != NULL) {
-		error = lease_modify(my_before, arg);
+		error = lease->fl_lmops->fl_change(my_before, arg);
 		goto out;
 	}
 
@@ -1876,8 +1865,13 @@ void locks_remove_flock(struct file *fil
 		return;
 
 	if (filp->f_op && filp->f_op->flock) {
-		struct file_lock fl = { .fl_flags = FL_FLOCK,
-					.fl_type = F_UNLCK };
+		struct file_lock fl = {
+			.fl_pid = current->tgid,
+			.fl_file = filp,
+			.fl_flags = FL_FLOCK,
+			.fl_type = F_UNLCK,
+			.fl_end = OFFSET_MAX,
+		};
 		filp->f_op->flock(filp, F_SETLKW, &fl);
 	}
 
diff --git a/fs/mbcache.c b/fs/mbcache.c
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -57,7 +57,7 @@
 
 #define MB_CACHE_WRITER ((unsigned short)~0U >> 1)
 
-DECLARE_WAIT_QUEUE_HEAD(mb_cache_queue);
+static DECLARE_WAIT_QUEUE_HEAD(mb_cache_queue);
 		
 MODULE_AUTHOR("Andreas Gruenbacher <a.gruenbacher@computer.org>");
 MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
@@ -225,7 +225,7 @@ mb_cache_shrink_fn(int nr_to_scan, unsig
 						   e_lru_list), gfp_mask);
 	}
 out:
-	return count;
+	return (count / 100) * sysctl_vfs_cache_pressure;
 }
 
 
diff --git a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -79,15 +79,18 @@ static int mpage_end_io_write(struct bio
 		if (--bvec >= bio->bi_io_vec)
 			prefetchw(&bvec->bv_page->flags);
 
-		if (!uptodate)
+		if (!uptodate){
 			SetPageError(page);
+			if (page->mapping)
+				set_bit(AS_EIO, &page->mapping->flags);
+		}
 		end_page_writeback(page);
 	} while (bvec >= bio->bi_io_vec);
 	bio_put(bio);
 	return 0;
 }
 
-struct bio *mpage_bio_submit(int rw, struct bio *bio)
+static struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
 	bio->bi_end_io = mpage_end_io_read;
 	if (rw == WRITE)
@@ -98,7 +101,8 @@ struct bio *mpage_bio_submit(int rw, str
 
 static struct bio *
 mpage_alloc(struct block_device *bdev,
-		sector_t first_sector, int nr_vecs, int gfp_flags)
+		sector_t first_sector, int nr_vecs,
+		unsigned int __nocast gfp_flags)
 {
 	struct bio *bio;
 
@@ -159,52 +163,6 @@ map_buffer_to_page(struct page *page, st
 	} while (page_bh != head);
 }
 
-/**
- * mpage_readpages - populate an address space with some pages, and
- *                       start reads against them.
- *
- * @mapping: the address_space
- * @pages: The address of a list_head which contains the target pages.  These
- *   pages have their ->index populated and are otherwise uninitialised.
- *
- *   The page at @pages->prev has the lowest file offset, and reads should be
- *   issued in @pages->prev to @pages->next order.
- *
- * @nr_pages: The number of pages at *@pages
- * @get_block: The filesystem's block mapper function.
- *
- * This function walks the pages and the blocks within each page, building and
- * emitting large BIOs.
- *
- * If anything unusual happens, such as:
- *
- * - encountering a page which has buffers
- * - encountering a page which has a non-hole after a hole
- * - encountering a page with non-contiguous blocks
- *
- * then this code just gives up and calls the buffer_head-based read function.
- * It does handle a page which has holes at the end - that is a common case:
- * the end-of-file on blocksize < PAGE_CACHE_SIZE setups.
- *
- * BH_Boundary explanation:
- *
- * There is a problem.  The mpage read code assembles several pages, gets all
- * their disk mappings, and then submits them all.  That's fine, but obtaining
- * the disk mappings may require I/O.  Reads of indirect blocks, for example.
- *
- * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be
- * submitted in the following order:
- * 	12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
- * because the indirect block has to be read to get the mappings of blocks
- * 13,14,15,16.  Obviously, this impacts performance.
- * 
- * So what we do it to allow the filesystem's get_block() function to set
- * BH_Boundary when it maps block 11.  BH_Boundary says: mapping of the block
- * after this one will require I/O against a block which is probably close to
- * this one.  So you should push what I/O you have currently accumulated.
- *
- * This all causes the disk requests to be issued in the correct order.
- */
 static struct bio *
 do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
 			sector_t *last_block_in_bio, get_block_t get_block)
@@ -319,6 +277,52 @@ confused:
 	goto out;
 }
 
+/**
+ * mpage_readpages - populate an address space with some pages, and
+ *                       start reads against them.
+ *
+ * @mapping: the address_space
+ * @pages: The address of a list_head which contains the target pages.  These
+ *   pages have their ->index populated and are otherwise uninitialised.
+ *
+ *   The page at @pages->prev has the lowest file offset, and reads should be
+ *   issued in @pages->prev to @pages->next order.
+ *
+ * @nr_pages: The number of pages at *@pages
+ * @get_block: The filesystem's block mapper function.
+ *
+ * This function walks the pages and the blocks within each page, building and
+ * emitting large BIOs.
+ *
+ * If anything unusual happens, such as:
+ *
+ * - encountering a page which has buffers
+ * - encountering a page which has a non-hole after a hole
+ * - encountering a page with non-contiguous blocks
+ *
+ * then this code just gives up and calls the buffer_head-based read function.
+ * It does handle a page which has holes at the end - that is a common case:
+ * the end-of-file on blocksize < PAGE_CACHE_SIZE setups.
+ *
+ * BH_Boundary explanation:
+ *
+ * There is a problem.  The mpage read code assembles several pages, gets all
+ * their disk mappings, and then submits them all.  That's fine, but obtaining
+ * the disk mappings may require I/O.  Reads of indirect blocks, for example.
+ *
+ * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be
+ * submitted in the following order:
+ * 	12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
+ * because the indirect block has to be read to get the mappings of blocks
+ * 13,14,15,16.  Obviously, this impacts performance.
+ *
+ * So what we do it to allow the filesystem's get_block() function to set
+ * BH_Boundary when it maps block 11.  BH_Boundary says: mapping of the block
+ * after this one will require I/O against a block which is probably close to
+ * this one.  So you should push what I/O you have currently accumulated.
+ *
+ * This all causes the disk requests to be issued in the correct order.
+ */
 int
 mpage_readpages(struct address_space *mapping, struct list_head *pages,
 				unsigned nr_pages, get_block_t get_block)
@@ -386,8 +390,9 @@ EXPORT_SYMBOL(mpage_readpage);
  * just allocate full-size (16-page) BIOs.
  */
 static struct bio *
-mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
-	sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc)
+__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
+	sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc,
+	writepage_t writepage_fn)
 {
 	struct address_space *mapping = page->mapping;
 	struct inode *inode = page->mapping->host;
@@ -580,7 +585,13 @@ alloc_new:
 confused:
 	if (bio)
 		bio = mpage_bio_submit(WRITE, bio);
-	*ret = page->mapping->a_ops->writepage(page, wbc);
+
+	if (writepage_fn) {
+		*ret = (*writepage_fn)(page, wbc);
+	} else {
+		*ret = -EAGAIN;
+		goto out;
+	}
 	/*
 	 * The caller has a ref on the inode, so *mapping is stable
 	 */
@@ -706,9 +717,12 @@ retry:
 							&mapping->flags);
 				}
 			} else {
-				bio = mpage_writepage(bio, page, get_block,
-						&last_block_in_bio, &ret, wbc);
+				bio = __mpage_writepage(bio, page, get_block,
+						&last_block_in_bio, &ret, wbc,
+						page->mapping->a_ops->writepage);
 			}
+			if (unlikely(ret == WRITEPAGE_ACTIVATE))
+				unlock_page(page);
 			if (ret || (--(wbc->nr_to_write) <= 0))
 				done = 1;
 			if (wbc->nonblocking && bdi_write_congested(bdi)) {
@@ -735,3 +749,19 @@ retry:
 	return ret;
 }
 EXPORT_SYMBOL(mpage_writepages);
+
+int mpage_writepage(struct page *page, get_block_t get_block,
+	struct writeback_control *wbc)
+{
+	int ret = 0;
+	struct bio *bio;
+	sector_t last_block_in_bio = 0;
+
+	bio = __mpage_writepage(NULL, page, get_block,
+			&last_block_in_bio, &ret, wbc, NULL);
+	if (bio)
+		mpage_bio_submit(WRITE, bio);
+
+	return ret;
+}
+EXPORT_SYMBOL(mpage_writepage);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -137,29 +137,29 @@ static int msdos_format_name(const unsig
 
 /***** Locates a directory entry.  Uses unformatted name. */
 static int msdos_find(struct inode *dir, const unsigned char *name, int len,
-		      struct buffer_head **bh, struct msdos_dir_entry **de,
-		      loff_t *i_pos)
+		      struct fat_slot_info *sinfo)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
 	unsigned char msdos_name[MSDOS_NAME];
-	char dotsOK;
-	int res;
+	int err;
 
-	dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
-	res = msdos_format_name(name, len, msdos_name,
-				&MSDOS_SB(dir->i_sb)->options);
-	if (res < 0)
+	err = msdos_format_name(name, len, msdos_name, &sbi->options);
+	if (err)
 		return -ENOENT;
-	res = fat_scan(dir, msdos_name, bh, de, i_pos);
-	if (!res && dotsOK) {
+
+	err = fat_scan(dir, msdos_name, sinfo);
+	if (!err && sbi->options.dotsOK) {
 		if (name[0] == '.') {
-			if (!((*de)->attr & ATTR_HIDDEN))
-				res = -ENOENT;
+			if (!(sinfo->de->attr & ATTR_HIDDEN))
+				err = -ENOENT;
 		} else {
-			if ((*de)->attr & ATTR_HIDDEN)
-				res = -ENOENT;
+			if (sinfo->de->attr & ATTR_HIDDEN)
+				err = -ENOENT;
 		}
+		if (err)
+			brelse(sinfo->bh);
 	}
-	return res;
+	return err;
 }
 
 /*
@@ -221,31 +221,30 @@ static struct dentry *msdos_lookup(struc
 				   struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
+	struct fat_slot_info sinfo;
 	struct inode *inode = NULL;
-	struct msdos_dir_entry *de;
-	struct buffer_head *bh = NULL;
-	loff_t i_pos;
 	int res;
 
 	dentry->d_op = &msdos_dentry_operations;
 
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
-			 &de, &i_pos);
+	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (res == -ENOENT)
 		goto add;
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, i_pos, &res);
-	if (res)
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
+		res = PTR_ERR(inode);
 		goto out;
+	}
 add:
 	res = 0;
 	dentry = d_splice_alias(inode, dentry);
 	if (dentry)
 		dentry->d_op = &msdos_dentry_operations;
 out:
-	brelse(bh);
 	unlock_kernel();
 	if (!res)
 		return dentry;
@@ -254,31 +253,38 @@ out:
 
 /***** Creates a directory entry (name is already formatted). */
 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
-			   struct buffer_head **bh,
-			   struct msdos_dir_entry **de,
-			   loff_t *i_pos, int is_dir, int is_hid)
+			   int is_dir, int is_hid, int cluster,
+			   struct timespec *ts, struct fat_slot_info *sinfo)
 {
-	int res;
-
-	res = fat_add_entries(dir, 1, bh, de, i_pos);
-	if (res < 0)
-		return res;
-
-	/*
-	 * XXX all times should be set by caller upon successful completion.
-	 */
-	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(dir);
+	struct msdos_dir_entry de;
+	__le16 time, date;
+	int err;
 
-	memcpy((*de)->name, name, MSDOS_NAME);
-	(*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+	memcpy(de.name, name, MSDOS_NAME);
+	de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 	if (is_hid)
-		(*de)->attr |= ATTR_HIDDEN;
-	(*de)->start = 0;
-	(*de)->starthi = 0;
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
-	(*de)->size = 0;
-	mark_buffer_dirty(*bh);
+		de.attr |= ATTR_HIDDEN;
+	de.lcase = 0;
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+	de.cdate = de.adate = 0;
+	de.ctime = 0;
+	de.ctime_cs = 0;
+	de.time = time;
+	de.date = date;
+	de.start = cpu_to_le16(cluster);
+	de.starthi = cpu_to_le16(cluster >> 16);
+	de.size = 0;
+
+	err = fat_add_entries(dir, &de, 1, sinfo);
+	if (err)
+		return err;
+
+	dir->i_ctime = dir->i_mtime = *ts;
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
+
 	return 0;
 }
 
@@ -287,320 +293,366 @@ static int msdos_create(struct inode *di
 			struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
 	struct inode *inode;
-	loff_t i_pos;
-	int res, is_hid;
+	struct fat_slot_info sinfo;
+	struct timespec ts;
 	unsigned char msdos_name[MSDOS_NAME];
+	int err, is_hid;
 
 	lock_kernel();
-	res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
-	if (res < 0) {
-		unlock_kernel();
-		return res;
-	}
+	if (err)
+		goto out;
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* Have to do it due to foo vs. .foo conflicts */
-	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
-		brelse(bh);
-		unlock_kernel();
-		return -EINVAL;
-	}
-	inode = NULL;
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
-	if (res) {
-		unlock_kernel();
-		return res;
+	if (!fat_scan(dir, msdos_name, &sinfo)) {
+		brelse(sinfo.bh);
+		err = -EINVAL;
+		goto out;
 	}
-	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
-	brelse(bh);
-	if (!inode) {
-		unlock_kernel();
-		return res;
+
+	ts = CURRENT_TIME_SEC;
+	err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
+	if (err)
+		goto out;
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
+		goto out;
 	}
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
 	d_instantiate(dentry, inode);
+out:
 	unlock_kernel();
-	return 0;
+	return err;
 }
 
 /***** Remove a directory */
 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	loff_t i_pos;
-	int res;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
+	int err;
 
-	bh = NULL;
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			 &bh, &de, &i_pos);
-	if (res < 0)
-		goto rmdir_done;
 	/*
 	 * Check whether the directory is not in use, then check
 	 * whether it is empty.
 	 */
-	res = fat_dir_empty(inode);
-	if (res)
-		goto rmdir_done;
+	err = fat_dir_empty(inode);
+	if (err)
+		goto out;
+	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+	if (err)
+		goto out;
 
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	fat_detach(inode);
-	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
 	dir->i_nlink--;
-	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	res = 0;
 
-rmdir_done:
-	brelse(bh);
+	inode->i_nlink = 0;
+	inode->i_ctime = CURRENT_TIME_SEC;
+	fat_detach(inode);
+out:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 /***** Make a directory */
 static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct super_block *sb = dir->i_sb;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
 	struct inode *inode;
-	int res, is_hid;
 	unsigned char msdos_name[MSDOS_NAME];
-	loff_t i_pos;
+	struct timespec ts;
+	int err, is_hid, cluster;
 
 	lock_kernel();
-	res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
-	if (res < 0) {
-		unlock_kernel();
-		return res;
-	}
+	if (err)
+		goto out;
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* foo vs .foo situation */
-	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
-		goto out_exist;
-
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
-	if (res)
-		goto out_unlock;
-	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
-	if (!inode) {
-		brelse(bh);
-		goto out_unlock;
+	if (!fat_scan(dir, msdos_name, &sinfo)) {
+		brelse(sinfo.bh);
+		err = -EINVAL;
+		goto out;
 	}
-	res = 0;
 
+	ts = CURRENT_TIME_SEC;
+	cluster = fat_alloc_new_dir(dir, &ts);
+	if (cluster < 0) {
+		err = cluster;
+		goto out;
+	}
+	err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
+	if (err)
+		goto out_free;
 	dir->i_nlink++;
-	inode->i_nlink = 2;	/* no need to mark them dirty */
 
-	res = fat_new_dir(inode, dir, 0);
-	if (res)
-		goto mkdir_error;
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
+		/* the directory was completed, just return a error */
+		goto out;
+	}
+	inode->i_nlink = 2;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-	brelse(bh);
 	d_instantiate(dentry, inode);
-	res = 0;
 
-out_unlock:
 	unlock_kernel();
-	return res;
-
-mkdir_error:
-	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	dir->i_nlink--;
-	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	brelse(bh);
-	fat_detach(inode);
-	iput(inode);
-	goto out_unlock;
+	return 0;
 
-out_exist:
-	brelse(bh);
-	res = -EINVAL;
-	goto out_unlock;
+out_free:
+	fat_free_clusters(dir, cluster);
+out:
+	unlock_kernel();
+	return err;
 }
 
 /***** Unlink a file */
 static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	loff_t i_pos;
-	int res;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
+	int err;
 
-	bh = NULL;
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			 &bh, &de, &i_pos);
-	if (res < 0)
-		goto unlink_done;
+	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+	if (err)
+		goto out;
 
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	fat_detach(inode);
-	brelse(bh);
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
 	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	res = 0;
-unlink_done:
+	inode->i_ctime = CURRENT_TIME_SEC;
+	fat_detach(inode);
+out:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
 			   struct dentry *old_dentry,
 			   struct inode *new_dir, unsigned char *new_name,
-			   struct dentry *new_dentry,
-			   struct buffer_head *old_bh,
-			   struct msdos_dir_entry *old_de, loff_t old_i_pos,
-			   int is_hid)
+			   struct dentry *new_dentry, int is_hid)
 {
-	struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
-	struct msdos_dir_entry *new_de, *dotdot_de;
+	struct buffer_head *dotdot_bh;
+	struct msdos_dir_entry *dotdot_de;
+	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
-	loff_t new_i_pos, dotdot_i_pos;
-	int error;
-	int is_dir;
+	struct fat_slot_info old_sinfo, sinfo;
+	struct timespec ts;
+	int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
 
+	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
+
+	err = fat_scan(old_dir, old_name, &old_sinfo);
+	if (err) {
+		err = -EIO;
+		goto out;
+	}
+
 	is_dir = S_ISDIR(old_inode->i_mode);
+	update_dotdot = (is_dir && old_dir != new_dir);
+	if (update_dotdot) {
+		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+					 &dotdot_i_pos) < 0) {
+			err = -EIO;
+			goto out;
+		}
+	}
 
-	if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 &&
-	    !new_inode)
-		goto degenerate_case;
-	if (is_dir) {
-		if (new_inode) {
-			error = fat_dir_empty(new_inode);
-			if (error)
+	old_attrs = MSDOS_I(old_inode)->i_attrs;
+	err = fat_scan(new_dir, new_name, &sinfo);
+	if (!err) {
+		if (!new_inode) {
+			/* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
+			if (sinfo.de != old_sinfo.de) {
+				err = -EINVAL;
 				goto out;
-		}
-		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-			     &dotdot_de, &dotdot_i_pos) < 0) {
-			error = -EIO;
+			}
+			if (is_hid)
+				MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
+			else
+				MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
+			if (IS_DIRSYNC(old_dir)) {
+				err = fat_sync_inode(old_inode);
+				if (err) {
+					MSDOS_I(old_inode)->i_attrs = old_attrs;
+					goto out;
+				}
+			} else
+				mark_inode_dirty(old_inode);
+
+			old_dir->i_version++;
+			old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+			if (IS_DIRSYNC(old_dir))
+				(void)fat_sync_inode(old_dir);
+			else
+				mark_inode_dirty(old_dir);
 			goto out;
 		}
 	}
-	if (!new_bh) {
-		error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
-					&new_i_pos, is_dir, is_hid);
-		if (error)
+
+	ts = CURRENT_TIME_SEC;
+	if (new_inode) {
+		if (err)
+			goto out;
+		if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+			/* WTF??? Cry and fail. */
+			printk(KERN_WARNING "msdos_rename: fs corrupted\n");
+			goto out;
+		}
+
+		if (is_dir) {
+			err = fat_dir_empty(new_inode);
+			if (err)
+				goto out;
+		}
+		fat_detach(new_inode);
+	} else {
+		err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
+				      &ts, &sinfo);
+		if (err)
 			goto out;
 	}
 	new_dir->i_version++;
 
-	/* There we go */
-
-	if (new_inode)
-		fat_detach(new_inode);
-	old_de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(old_bh);
 	fat_detach(old_inode);
-	fat_attach(old_inode, new_i_pos);
+	fat_attach(old_inode, sinfo.i_pos);
 	if (is_hid)
 		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
-	mark_inode_dirty(old_inode);
-	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(old_dir);
-	if (new_inode) {
-		new_inode->i_nlink--;
-		new_inode->i_ctime = CURRENT_TIME_SEC;
-		mark_inode_dirty(new_inode);
-	}
-	if (dotdot_bh) {
-		dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
-		dotdot_de->starthi =
-			cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
+	if (IS_DIRSYNC(new_dir)) {
+		err = fat_sync_inode(old_inode);
+		if (err)
+			goto error_inode;
+	} else
+		mark_inode_dirty(old_inode);
+
+	if (update_dotdot) {
+		int start = MSDOS_I(new_dir)->i_logstart;
+		dotdot_de->start = cpu_to_le16(start);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
 		mark_buffer_dirty(dotdot_bh);
+		if (IS_DIRSYNC(new_dir)) {
+			err = sync_dirty_buffer(dotdot_bh);
+			if (err)
+				goto error_dotdot;
+		}
 		old_dir->i_nlink--;
+		if (!new_inode)
+			new_dir->i_nlink++;
+	}
+
+	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
+	old_sinfo.bh = NULL;
+	if (err)
+		goto error_dotdot;
+	old_dir->i_version++;
+	old_dir->i_ctime = old_dir->i_mtime = ts;
+	if (IS_DIRSYNC(old_dir))
+		(void)fat_sync_inode(old_dir);
+	else
 		mark_inode_dirty(old_dir);
-		if (new_inode) {
+
+	if (new_inode) {
+		if (is_dir)
+			new_inode->i_nlink -= 2;
+		else
 			new_inode->i_nlink--;
-			mark_inode_dirty(new_inode);
-		} else {
-			new_dir->i_nlink++;
-			mark_inode_dirty(new_dir);
-		}
+		new_inode->i_ctime = ts;
 	}
-	error = 0;
 out:
-	brelse(new_bh);
+	brelse(sinfo.bh);
 	brelse(dotdot_bh);
-	return error;
+	brelse(old_sinfo.bh);
+	return err;
 
-degenerate_case:
-	error = -EINVAL;
-	if (new_de != old_de)
-		goto out;
-	if (is_hid)
-		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
-	else
-		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
-	mark_inode_dirty(old_inode);
-	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(old_dir);
-	return 0;
+error_dotdot:
+	/* data cluster is shared, serious corruption */
+	corrupt = 1;
+
+	if (update_dotdot) {
+		int start = MSDOS_I(old_dir)->i_logstart;
+		dotdot_de->start = cpu_to_le16(start);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
+		mark_buffer_dirty(dotdot_bh);
+		corrupt |= sync_dirty_buffer(dotdot_bh);
+	}
+error_inode:
+	fat_detach(old_inode);
+	fat_attach(old_inode, old_sinfo.i_pos);
+	MSDOS_I(old_inode)->i_attrs = old_attrs;
+	if (new_inode) {
+		fat_attach(new_inode, sinfo.i_pos);
+		if (corrupt)
+			corrupt |= fat_sync_inode(new_inode);
+	} else {
+		/*
+		 * If new entry was not sharing the data cluster, it
+		 * shouldn't be serious corruption.
+		 */
+		int err2 = fat_remove_entries(new_dir, &sinfo);
+		if (corrupt)
+			corrupt |= err2;
+		sinfo.bh = NULL;
+	}
+	if (corrupt < 0) {
+		fat_fs_panic(new_dir->i_sb,
+			     "%s: Filesystem corrupted (i_pos %lld)",
+			     __FUNCTION__, sinfo.i_pos);
+	}
+	goto out;
 }
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct buffer_head *old_bh;
-	struct msdos_dir_entry *old_de;
-	loff_t old_i_pos;
-	int error, is_hid, old_hid; /* if new file and old file are hidden */
 	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
+	int err, is_hid;
 
 	lock_kernel();
-	error = msdos_format_name(old_dentry->d_name.name,
-				  old_dentry->d_name.len, old_msdos_name,
-				  &MSDOS_SB(old_dir->i_sb)->options);
-	if (error < 0)
-		goto rename_done;
-	error = msdos_format_name(new_dentry->d_name.name,
-				  new_dentry->d_name.len, new_msdos_name,
-				  &MSDOS_SB(new_dir->i_sb)->options);
-	if (error < 0)
-		goto rename_done;
+
+	err = msdos_format_name(old_dentry->d_name.name,
+				old_dentry->d_name.len, old_msdos_name,
+				&MSDOS_SB(old_dir->i_sb)->options);
+	if (err)
+		goto out;
+	err = msdos_format_name(new_dentry->d_name.name,
+				new_dentry->d_name.len, new_msdos_name,
+				&MSDOS_SB(new_dir->i_sb)->options);
+	if (err)
+		goto out;
 
 	is_hid =
 	     (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
-	old_hid =
-	     (old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
 
-	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
-	if (error < 0)
-		goto rename_done;
-
-	error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
-				new_dir, new_msdos_name, new_dentry,
-				old_bh, old_de, old_i_pos, is_hid);
-	brelse(old_bh);
-
-rename_done:
+	err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
+			      new_dir, new_msdos_name, new_dentry, is_hid);
+out:
 	unlock_kernel();
-	return error;
+	return err;
 }
 
 static struct inode_operations msdos_dir_inode_operations = {
@@ -621,6 +673,7 @@ static int msdos_fill_super(struct super
 	if (res)
 		return res;
 
+	sb->s_flags |= MS_NOATIME;
 	sb->s_root->d_op = &msdos_dentry_operations;
 	return 0;
 }
diff --git a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -148,11 +148,22 @@ char * getname(const char __user * filen
 			result = ERR_PTR(retval);
 		}
 	}
-	if (unlikely(current->audit_context) && !IS_ERR(result) && result)
-		audit_getname(result);
+	audit_getname(result);
 	return result;
 }
 
+#ifdef CONFIG_AUDITSYSCALL
+void putname(const char *name)
+{
+	if (unlikely(current->audit_context))
+		audit_putname(name);
+	else
+		__putname(name);
+}
+EXPORT_SYMBOL(putname);
+#endif
+
+
 /**
  * generic_permission  -  check for access rights on a Posix-like filesystem
  * @inode:	inode to check access rights for
@@ -482,12 +493,21 @@ fail:
 	return PTR_ERR(link);
 }
 
-static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
+struct path {
+	struct vfsmount *mnt;
+	struct dentry *dentry;
+};
+
+static inline int __do_follow_link(struct path *path, struct nameidata *nd)
 {
 	int error;
+	struct dentry *dentry = path->dentry;
 
-	touch_atime(nd->mnt, dentry);
+	touch_atime(path->mnt, dentry);
 	nd_set_link(nd, NULL);
+
+	if (path->mnt == nd->mnt)
+		mntget(path->mnt);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
 	if (!error) {
 		char *s = nd_get_link(nd);
@@ -496,6 +516,8 @@ static inline int __do_follow_link(struc
 		if (dentry->d_inode->i_op->put_link)
 			dentry->d_inode->i_op->put_link(dentry, nd);
 	}
+	dput(dentry);
+	mntput(path->mnt);
 
 	return error;
 }
@@ -507,7 +529,7 @@ static inline int __do_follow_link(struc
  * Without that kind of total limit, nasty chains of consecutive
  * symlinks can cause almost arbitrarily long lookups. 
  */
-static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
+static inline int do_follow_link(struct path *path, struct nameidata *nd)
 {
 	int err = -ELOOP;
 	if (current->link_count >= MAX_NESTED_LINKS)
@@ -516,17 +538,20 @@ static inline int do_follow_link(struct 
 		goto loop;
 	BUG_ON(nd->depth >= MAX_NESTED_LINKS);
 	cond_resched();
-	err = security_inode_follow_link(dentry, nd);
+	err = security_inode_follow_link(path->dentry, nd);
 	if (err)
 		goto loop;
 	current->link_count++;
 	current->total_link_count++;
 	nd->depth++;
-	err = __do_follow_link(dentry, nd);
+	err = __do_follow_link(path, nd);
 	current->link_count--;
 	nd->depth--;
 	return err;
 loop:
+	dput(path->dentry);
+	if (path->mnt != nd->mnt)
+		mntput(path->mnt);
 	path_release(nd);
 	return err;
 }
@@ -554,87 +579,91 @@ int follow_up(struct vfsmount **mnt, str
 /* no need for dcache_lock, as serialization is taken care in
  * namespace.c
  */
-static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
+static int __follow_mount(struct path *path)
 {
 	int res = 0;
+	while (d_mountpoint(path->dentry)) {
+		struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
+		if (!mounted)
+			break;
+		dput(path->dentry);
+		if (res)
+			mntput(path->mnt);
+		path->mnt = mounted;
+		path->dentry = dget(mounted->mnt_root);
+		res = 1;
+	}
+	return res;
+}
+
+static void follow_mount(struct vfsmount **mnt, struct dentry **dentry)
+{
 	while (d_mountpoint(*dentry)) {
 		struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
 		if (!mounted)
 			break;
+		dput(*dentry);
 		mntput(*mnt);
 		*mnt = mounted;
-		dput(*dentry);
 		*dentry = dget(mounted->mnt_root);
-		res = 1;
 	}
-	return res;
 }
 
 /* no need for dcache_lock, as serialization is taken care in
  * namespace.c
  */
-static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
+int follow_down(struct vfsmount **mnt, struct dentry **dentry)
 {
 	struct vfsmount *mounted;
 
 	mounted = lookup_mnt(*mnt, *dentry);
 	if (mounted) {
+		dput(*dentry);
 		mntput(*mnt);
 		*mnt = mounted;
-		dput(*dentry);
 		*dentry = dget(mounted->mnt_root);
 		return 1;
 	}
 	return 0;
 }
 
-int follow_down(struct vfsmount **mnt, struct dentry **dentry)
-{
-	return __follow_down(mnt,dentry);
-}
- 
-static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
+static inline void follow_dotdot(struct nameidata *nd)
 {
 	while(1) {
 		struct vfsmount *parent;
-		struct dentry *old = *dentry;
+		struct dentry *old = nd->dentry;
 
                 read_lock(&current->fs->lock);
-		if (*dentry == current->fs->root &&
-		    *mnt == current->fs->rootmnt) {
+		if (nd->dentry == current->fs->root &&
+		    nd->mnt == current->fs->rootmnt) {
                         read_unlock(&current->fs->lock);
 			break;
 		}
                 read_unlock(&current->fs->lock);
 		spin_lock(&dcache_lock);
-		if (*dentry != (*mnt)->mnt_root) {
-			*dentry = dget((*dentry)->d_parent);
+		if (nd->dentry != nd->mnt->mnt_root) {
+			nd->dentry = dget(nd->dentry->d_parent);
 			spin_unlock(&dcache_lock);
 			dput(old);
 			break;
 		}
 		spin_unlock(&dcache_lock);
 		spin_lock(&vfsmount_lock);
-		parent = (*mnt)->mnt_parent;
-		if (parent == *mnt) {
+		parent = nd->mnt->mnt_parent;
+		if (parent == nd->mnt) {
 			spin_unlock(&vfsmount_lock);
 			break;
 		}
 		mntget(parent);
-		*dentry = dget((*mnt)->mnt_mountpoint);
+		nd->dentry = dget(nd->mnt->mnt_mountpoint);
 		spin_unlock(&vfsmount_lock);
 		dput(old);
-		mntput(*mnt);
-		*mnt = parent;
+		mntput(nd->mnt);
+		nd->mnt = parent;
 	}
-	follow_mount(mnt, dentry);
+	follow_mount(&nd->mnt, &nd->dentry);
 }
 
-struct path {
-	struct vfsmount *mnt;
-	struct dentry *dentry;
-};
-
 /*
  *  It's more convoluted than I'd like it to be, but... it's still fairly
  *  small and for now I'd prefer to have fast path as straight as possible.
@@ -653,6 +682,7 @@ static int do_lookup(struct nameidata *n
 done:
 	path->mnt = mnt;
 	path->dentry = dentry;
+	__follow_mount(path);
 	return 0;
 
 need_lookup:
@@ -675,13 +705,13 @@ fail:
 
 /*
  * Name resolution.
+ * This is the basic name resolution function, turning a pathname into
+ * the final dentry. We expect 'base' to be positive and a directory.
  *
- * This is the basic name resolution function, turning a pathname
- * into the final dentry.
- *
- * We expect 'base' to be positive and a directory.
+ * Returns 0 and nd will have valid dentry and mnt on success.
+ * Returns error and drops reference to input namei data on failure.
  */
-int fastcall link_path_walk(const char * name, struct nameidata *nd)
+static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
 {
 	struct path next;
 	struct inode *inode;
@@ -740,7 +770,7 @@ int fastcall link_path_walk(const char *
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				follow_dotdot(&nd->mnt, &nd->dentry);
+				follow_dotdot(nd);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
@@ -760,8 +790,6 @@ int fastcall link_path_walk(const char *
 		err = do_lookup(nd, &this, &next);
 		if (err)
 			break;
-		/* Check mountpoints.. */
-		follow_mount(&next.mnt, &next.dentry);
 
 		err = -ENOENT;
 		inode = next.dentry->d_inode;
@@ -772,10 +800,7 @@ int fastcall link_path_walk(const char *
 			goto out_dput;
 
 		if (inode->i_op->follow_link) {
-			mntget(next.mnt);
-			err = do_follow_link(next.dentry, nd);
-			dput(next.dentry);
-			mntput(next.mnt);
+			err = do_follow_link(&next, nd);
 			if (err)
 				goto return_err;
 			err = -ENOENT;
@@ -787,6 +812,8 @@ int fastcall link_path_walk(const char *
 				break;
 		} else {
 			dput(nd->dentry);
+			if (nd->mnt != next.mnt)
+				mntput(nd->mnt);
 			nd->mnt = next.mnt;
 			nd->dentry = next.dentry;
 		}
@@ -808,7 +835,7 @@ last_component:
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				follow_dotdot(&nd->mnt, &nd->dentry);
+				follow_dotdot(nd);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
@@ -822,19 +849,17 @@ last_component:
 		err = do_lookup(nd, &this, &next);
 		if (err)
 			break;
-		follow_mount(&next.mnt, &next.dentry);
 		inode = next.dentry->d_inode;
 		if ((lookup_flags & LOOKUP_FOLLOW)
 		    && inode && inode->i_op && inode->i_op->follow_link) {
-			mntget(next.mnt);
-			err = do_follow_link(next.dentry, nd);
-			dput(next.dentry);
-			mntput(next.mnt);
+			err = do_follow_link(&next, nd);
 			if (err)
 				goto return_err;
 			inode = nd->dentry->d_inode;
 		} else {
 			dput(nd->dentry);
+			if (nd->mnt != next.mnt)
+				mntput(nd->mnt);
 			nd->mnt = next.mnt;
 			nd->dentry = next.dentry;
 		}
@@ -874,6 +899,8 @@ return_base:
 		return 0;
 out_dput:
 		dput(next.dentry);
+		if (nd->mnt != next.mnt)
+			mntput(next.mnt);
 		break;
 	}
 	path_release(nd);
@@ -881,14 +908,47 @@ return_err:
 	return err;
 }
 
+/*
+ * Wrapper to retry pathname resolution whenever the underlying
+ * file system returns an ESTALE.
+ *
+ * Retry the whole path once, forcing real lookup requests
+ * instead of relying on the dcache.
+ */
+int fastcall link_path_walk(const char *name, struct nameidata *nd)
+{
+	struct nameidata save = *nd;
+	int result;
+
+	/* make sure the stuff we saved doesn't go away */
+	dget(save.dentry);
+	mntget(save.mnt);
+
+	result = __link_path_walk(name, nd);
+	if (result == -ESTALE) {
+		*nd = save;
+		dget(nd->dentry);
+		mntget(nd->mnt);
+		nd->flags |= LOOKUP_REVAL;
+		result = __link_path_walk(name, nd);
+	}
+
+	dput(save.dentry);
+	mntput(save.mnt);
+
+	return result;
+}
+
 int fastcall path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
 	return link_path_walk(name, nd);
 }
 
-/* SMP-safe */
-/* returns 1 if everything is done */
+/* 
+ * SMP-safe: Returns 1 and nd will have valid dentry and mnt, if
+ * everything is done. Returns 0 and drops input nd, if lookup failed;
+ */
 static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
 {
 	if (path_walk(name, nd))
@@ -952,9 +1012,10 @@ set_it:
 	}
 }
 
+/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
 int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
 {
-	int retval;
+	int retval = 0;
 
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
@@ -967,7 +1028,7 @@ int fastcall path_lookup(const char *nam
 			nd->dentry = dget(current->fs->altroot);
 			read_unlock(&current->fs->lock);
 			if (__emul_lookup_dentry(name,nd))
-				return 0;
+				goto out; /* found in altroot */
 			read_lock(&current->fs->lock);
 		}
 		nd->mnt = mntget(current->fs->rootmnt);
@@ -979,11 +1040,10 @@ int fastcall path_lookup(const char *nam
 	read_unlock(&current->fs->lock);
 	current->total_link_count = 0;
 	retval = link_path_walk(name, nd);
+out:
 	if (unlikely(current->audit_context
 		     && nd && nd->dentry && nd->dentry->d_inode))
-		audit_inode(name,
-			    nd->dentry->d_inode->i_ino,
-			    nd->dentry->d_inode->i_rdev);
+		audit_inode(name, nd->dentry->d_inode);
 	return retval;
 }
 
@@ -1354,7 +1414,7 @@ int may_open(struct nameidata *nd, int a
 int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
 {
 	int acc_mode, error = 0;
-	struct dentry *dentry;
+	struct path path;
 	struct dentry *dir;
 	int count = 0;
 
@@ -1398,23 +1458,24 @@ int open_namei(const char * pathname, in
 	dir = nd->dentry;
 	nd->flags &= ~LOOKUP_PARENT;
 	down(&dir->d_inode->i_sem);
-	dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.mnt = nd->mnt;
 
 do_last:
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry)) {
+	error = PTR_ERR(path.dentry);
+	if (IS_ERR(path.dentry)) {
 		up(&dir->d_inode->i_sem);
 		goto exit;
 	}
 
 	/* Negative dentry, just create the file */
-	if (!dentry->d_inode) {
+	if (!path.dentry->d_inode) {
 		if (!IS_POSIXACL(dir->d_inode))
 			mode &= ~current->fs->umask;
-		error = vfs_create(dir->d_inode, dentry, mode, nd);
+		error = vfs_create(dir->d_inode, path.dentry, mode, nd);
 		up(&dir->d_inode->i_sem);
 		dput(nd->dentry);
-		nd->dentry = dentry;
+		nd->dentry = path.dentry;
 		if (error)
 			goto exit;
 		/* Don't check for write permission, don't truncate */
@@ -1432,22 +1493,24 @@ do_last:
 	if (flag & O_EXCL)
 		goto exit_dput;
 
-	if (d_mountpoint(dentry)) {
+	if (__follow_mount(&path)) {
 		error = -ELOOP;
 		if (flag & O_NOFOLLOW)
 			goto exit_dput;
-		while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
 	}
 	error = -ENOENT;
-	if (!dentry->d_inode)
+	if (!path.dentry->d_inode)
 		goto exit_dput;
-	if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
+	if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
 		goto do_link;
 
 	dput(nd->dentry);
-	nd->dentry = dentry;
+	nd->dentry = path.dentry;
+	if (nd->mnt != path.mnt)
+		mntput(nd->mnt);
+	nd->mnt = path.mnt;
 	error = -EISDIR;
-	if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+	if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
 		goto exit;
 ok:
 	error = may_open(nd, acc_mode, flag);
@@ -1456,7 +1519,9 @@ ok:
 	return 0;
 
 exit_dput:
-	dput(dentry);
+	dput(path.dentry);
+	if (nd->mnt != path.mnt)
+		mntput(path.mnt);
 exit:
 	path_release(nd);
 	return error;
@@ -1476,18 +1541,15 @@ do_link:
 	 * are done. Procfs-like symlinks just set LAST_BIND.
 	 */
 	nd->flags |= LOOKUP_PARENT;
-	error = security_inode_follow_link(dentry, nd);
+	error = security_inode_follow_link(path.dentry, nd);
 	if (error)
 		goto exit_dput;
-	error = __do_follow_link(dentry, nd);
-	dput(dentry);
+	error = __do_follow_link(&path, nd);
 	if (error)
 		return error;
 	nd->flags &= ~LOOKUP_PARENT;
-	if (nd->last_type == LAST_BIND) {
-		dentry = nd->dentry;
+	if (nd->last_type == LAST_BIND)
 		goto ok;
-	}
 	error = -EISDIR;
 	if (nd->last_type != LAST_NORM)
 		goto exit;
@@ -1502,7 +1564,8 @@ do_link:
 	}
 	dir = nd->dentry;
 	down(&dir->d_inode->i_sem);
-	dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.mnt = nd->mnt;
 	putname(nd->last.name);
 	goto do_last;
 }
@@ -1536,6 +1599,7 @@ enoent:
 fail:
 	return dentry;
 }
+EXPORT_SYMBOL_GPL(lookup_create);
 
 int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
@@ -1685,17 +1749,13 @@ out:
 void dentry_unhash(struct dentry *dentry)
 {
 	dget(dentry);
-	spin_lock(&dcache_lock);
-	switch (atomic_read(&dentry->d_count)) {
-	default:
-		spin_unlock(&dcache_lock);
+	if (atomic_read(&dentry->d_count))
 		shrink_dcache_parent(dentry);
-		spin_lock(&dcache_lock);
-		if (atomic_read(&dentry->d_count) != 2)
-			break;
-	case 2:
+	spin_lock(&dcache_lock);
+	spin_lock(&dentry->d_lock);
+	if (atomic_read(&dentry->d_count) == 2)
 		__d_drop(dentry);
-	}
+	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 }
 
@@ -2031,8 +2091,8 @@ exit:
  *	   ->i_sem on parents, which works but leads to some truely excessive
  *	   locking].
  */
-int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
-	       struct inode *new_dir, struct dentry *new_dentry)
+static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+			  struct inode *new_dir, struct dentry *new_dentry)
 {
 	int error = 0;
 	struct inode *target;
@@ -2076,8 +2136,8 @@ int vfs_rename_dir(struct inode *old_dir
 	return error;
 }
 
-int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
-	       struct inode *new_dir, struct dentry *new_dentry)
+static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+			    struct inode *new_dir, struct dentry *new_dentry)
 {
 	struct inode *target;
 	int error;
diff --git a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1255,10 +1255,19 @@ static void chroot_fs_refs(struct nameid
 }
 
 /*
- * Moves the current root to put_root, and sets root/cwd of all processes
- * which had them on the old root to new_root.
+ * pivot_root Semantics:
+ * Moves the root file system of the current process to the directory put_old,
+ * makes new_root as the new root file system of the current process, and sets
+ * root/cwd of all processes which had them on the current root to new_root.
  *
- * Note:
+ * Restrictions:
+ * The new_root and put_old must be directories, and  must not be on the
+ * same file  system as the current process root. The put_old  must  be
+ * underneath new_root,  i.e. adding a non-zero number of /.. to the string
+ * pointed to by put_old must yield the same directory as new_root. No other
+ * file system may be mounted on put_old. After all, new_root is a mountpoint.
+ *
+ * Notes:
  *  - we don't move root/cwd if they are not at the root (reason: if something
  *    cared enough to change them, it's probably wrong to force them elsewhere)
  *  - it's okay to pick a root that isn't the root of a file system, e.g.
@@ -1313,10 +1322,10 @@ asmlinkage long sys_pivot_root(const cha
 		goto out2;
 	error = -EBUSY;
 	if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt)
-		goto out2; /* loop */
+		goto out2; /* loop, on the same file system  */
 	error = -EINVAL;
 	if (user_nd.mnt->mnt_root != user_nd.dentry)
-		goto out2;
+		goto out2; /* not a mountpoint */
 	if (new_nd.mnt->mnt_root != new_nd.dentry)
 		goto out2; /* not a mountpoint */
 	tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
@@ -1324,7 +1333,7 @@ asmlinkage long sys_pivot_root(const cha
 	if (tmp != new_nd.mnt) {
 		for (;;) {
 			if (tmp->mnt_parent == tmp)
-				goto out3;
+				goto out3; /* already mounted on put_old */
 			if (tmp->mnt_parent == new_nd.mnt)
 				break;
 			tmp = tmp->mnt_parent;
@@ -1335,8 +1344,8 @@ asmlinkage long sys_pivot_root(const cha
 		goto out3;
 	detach_mnt(new_nd.mnt, &parent_nd);
 	detach_mnt(user_nd.mnt, &root_parent);
-	attach_mnt(user_nd.mnt, &old_nd);
-	attach_mnt(new_nd.mnt, &root_parent);
+	attach_mnt(user_nd.mnt, &old_nd);     /* mount old root on put_old */
+	attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
 	spin_unlock(&vfsmount_lock);
 	chroot_fs_refs(&user_nd, &new_nd);
 	security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1392,16 +1401,14 @@ static void __init init_mount_tree(void)
 void __init mnt_init(unsigned long mempages)
 {
 	struct list_head *d;
-	unsigned long order;
 	unsigned int nr_hash;
 	int i;
 
 	mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
 			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
 
-	order = 0; 
 	mount_hashtable = (struct list_head *)
-		__get_free_pages(GFP_ATOMIC, order);
+		__get_free_page(GFP_ATOMIC);
 
 	if (!mount_hashtable)
 		panic("Failed to allocate mount hash table\n");
@@ -1411,7 +1418,7 @@ void __init mnt_init(unsigned long mempa
 	 * We don't guarantee that "sizeof(struct list_head)" is necessarily
 	 * a power-of-two.
 	 */
-	nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct list_head);
+	nr_hash = PAGE_SIZE / sizeof(struct list_head);
 	hash_bits = 0;
 	do {
 		hash_bits++;
@@ -1425,8 +1432,7 @@ void __init mnt_init(unsigned long mempa
 	nr_hash = 1UL << hash_bits;
 	hash_mask = nr_hash-1;
 
-	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",
-			nr_hash, order, (PAGE_SIZE << order));
+	printk("Mount-cache hash table entries: %d\n", nr_hash);
 
 	/* And initialize the newly allocated array */
 	d = mount_hashtable;
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -933,7 +933,7 @@ int ncp_search_for_fileset(struct ncp_se
 	return 0;
 }
 
-int
+static int
 ncp_RenameNSEntry(struct ncp_server *server,
 		  struct inode *old_dir, char *old_name, __le16 old_type,
 		  struct inode *new_dir, char *new_name)
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
--- a/fs/ncpfs/ncpsign_kernel.c
+++ b/fs/ncpfs/ncpsign_kernel.c
@@ -11,10 +11,9 @@
 
 #include <linux/string.h>
 #include <linux/ncp.h>
+#include <linux/bitops.h>
 #include "ncpsign_kernel.h"
 
-#define rol32(i,c) (((((i)&0xffffffff)<<c)&0xffffffff)| \
-                    (((i)&0xffffffff)>>(32-c)))
 /* i386: 32-bit, little endian, handles mis-alignment */
 #ifdef __i386__
 #define GET_LE32(p) (*(int *)(p))
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -139,133 +139,10 @@ out:
 	return ret;
 }
 
-/*
- * AUTH_NULL authentication
- */
-static int nfs_callback_null_accept(struct svc_rqst *rqstp, u32 *authp)
-{
-	struct kvec    *argv = &rqstp->rq_arg.head[0];
-	struct kvec    *resv = &rqstp->rq_res.head[0];
-
-	if (argv->iov_len < 3*4)
-		return SVC_GARBAGE;
-
-	if (svc_getu32(argv) != 0) {
-		dprintk("svc: bad null cred\n");
-		*authp = rpc_autherr_badcred;
-		return SVC_DENIED;
-	}
-	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
-		dprintk("svc: bad null verf\n");
-		 *authp = rpc_autherr_badverf;
-		 return SVC_DENIED;
-	}
-
-	/* Signal that mapping to nobody uid/gid is required */
-	rqstp->rq_cred.cr_uid = (uid_t) -1;
-	rqstp->rq_cred.cr_gid = (gid_t) -1;
-	rqstp->rq_cred.cr_group_info = groups_alloc(0);
-	if (rqstp->rq_cred.cr_group_info == NULL)
-		return SVC_DROP; /* kmalloc failure - client must retry */
-
-	/* Put NULL verifier */
-	svc_putu32(resv, RPC_AUTH_NULL);
-	svc_putu32(resv, 0);
-	dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
-	return SVC_OK;
-}
-
-static int nfs_callback_null_release(struct svc_rqst *rqstp)
-{
-	if (rqstp->rq_cred.cr_group_info)
-		put_group_info(rqstp->rq_cred.cr_group_info);
-	rqstp->rq_cred.cr_group_info = NULL;
-	return 0; /* don't drop */
-}
-
-static struct auth_ops nfs_callback_auth_null = {
-	.name = "null",
-	.flavour = RPC_AUTH_NULL,
-	.accept = nfs_callback_null_accept,
-	.release = nfs_callback_null_release,
-};
-
-/*
- * AUTH_SYS authentication
- */
-static int nfs_callback_unix_accept(struct svc_rqst *rqstp, u32 *authp)
-{
-	struct kvec    *argv = &rqstp->rq_arg.head[0];
-	struct kvec    *resv = &rqstp->rq_res.head[0];
-	struct svc_cred *cred = &rqstp->rq_cred;
-	u32 slen, i;
-	int len = argv->iov_len;
-
-	dprintk("%s: start\n", __FUNCTION__);
-	cred->cr_group_info = NULL;
-	rqstp->rq_client = NULL;
-	if ((len -= 3*4) < 0)
-		return SVC_GARBAGE;
-
-	/* Get length, time stamp and machine name */
-	svc_getu32(argv);
-	svc_getu32(argv);
-	slen = XDR_QUADLEN(ntohl(svc_getu32(argv)));
-	if (slen > 64 || (len -= (slen + 3)*4) < 0)
-		goto badcred;
-	argv->iov_base = (void*)((u32*)argv->iov_base + slen);
-	argv->iov_len -= slen*4;
-
-	cred->cr_uid = ntohl(svc_getu32(argv));
-	cred->cr_gid = ntohl(svc_getu32(argv));
-	slen = ntohl(svc_getu32(argv));
-	if (slen > 16 || (len -= (slen + 2)*4) < 0)
-		goto badcred;
-	cred->cr_group_info = groups_alloc(slen);
-	if (cred->cr_group_info == NULL)
-		return SVC_DROP;
-	for (i = 0; i < slen; i++)
-		GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
-
-	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
-		*authp = rpc_autherr_badverf;
-		return SVC_DENIED;
-	}
-	/* Put NULL verifier */
-	svc_putu32(resv, RPC_AUTH_NULL);
-	svc_putu32(resv, 0);
-	dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
-	return SVC_OK;
-badcred:
-	*authp = rpc_autherr_badcred;
-	return SVC_DENIED;
-}
-
-static int nfs_callback_unix_release(struct svc_rqst *rqstp)
-{
-	if (rqstp->rq_cred.cr_group_info)
-		put_group_info(rqstp->rq_cred.cr_group_info);
-	rqstp->rq_cred.cr_group_info = NULL;
-	return 0;
-}
-
-static struct auth_ops nfs_callback_auth_unix = {
-	.name = "unix",
-	.flavour = RPC_AUTH_UNIX,
-	.accept = nfs_callback_unix_accept,
-	.release = nfs_callback_unix_release,
-};
-
-/*
- * Hook the authentication protocol
- */
-static int nfs_callback_auth(struct svc_rqst *rqstp, u32 *authp)
+static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 {
 	struct in_addr *addr = &rqstp->rq_addr.sin_addr;
 	struct nfs4_client *clp;
-	struct kvec *argv = &rqstp->rq_arg.head[0];
-	int flavour;
-	int retval;
 
 	/* Don't talk to strangers */
 	clp = nfs4_find_client(addr);
@@ -273,34 +150,19 @@ static int nfs_callback_auth(struct svc_
 		return SVC_DROP;
 	dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
 	nfs4_put_client(clp);
-	flavour = ntohl(svc_getu32(argv));
-	switch(flavour) {
+	switch (rqstp->rq_authop->flavour) {
 		case RPC_AUTH_NULL:
-			if (rqstp->rq_proc != CB_NULL) {
-				*authp = rpc_autherr_tooweak;
-				retval = SVC_DENIED;
-				break;
-			}
-			rqstp->rq_authop = &nfs_callback_auth_null;
-			retval = nfs_callback_null_accept(rqstp, authp);
+			if (rqstp->rq_proc != CB_NULL)
+				return SVC_DENIED;
 			break;
 		case RPC_AUTH_UNIX:
-			/* Eat the authentication flavour */
-			rqstp->rq_authop = &nfs_callback_auth_unix;
-			retval = nfs_callback_unix_accept(rqstp, authp);
 			break;
+		case RPC_AUTH_GSS:
+			/* FIXME: RPCSEC_GSS handling? */
 		default:
-			/* FIXME: need to add RPCSEC_GSS upcalls */
-#if 0
-			svc_ungetu32(argv);
-			retval = svc_authenticate(rqstp, authp);
-#else
-			*authp = rpc_autherr_rejectedcred;
-			retval = SVC_DENIED;
-#endif
+			return SVC_DENIED;
 	}
-	dprintk("%s: flavour %d returning error %d\n", __FUNCTION__, flavour, retval);
-	return retval;
+	return SVC_OK;
 }
 
 /*
@@ -321,5 +183,5 @@ static struct svc_program nfs4_callback_
 	.pg_name = "NFSv4 callback",			/* service name */
 	.pg_class = "nfs",				/* authentication class */
 	.pg_stats = &nfs4_callback_stats,
-	.pg_authenticate = nfs_callback_auth,
+	.pg_authenticate = nfs_callback_authenticate,
 };
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -528,14 +528,45 @@ static inline void nfs_renew_times(struc
 	dentry->d_time = jiffies;
 }
 
+/*
+ * Return the intent data that applies to this particular path component
+ *
+ * Note that the current set of intents only apply to the very last
+ * component of the path.
+ * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT.
+ */
+static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask)
+{
+	if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))
+		return 0;
+	return nd->flags & mask;
+}
+
+/*
+ * Inode and filehandle revalidation for lookups.
+ *
+ * We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
+ * or if the intent information indicates that we're about to open this
+ * particular file and the "nocto" mount flag is not set.
+ *
+ */
 static inline
-int nfs_lookup_verify_inode(struct inode *inode, int isopen)
+int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
 
-	if (isopen && !(server->flags & NFS_MOUNT_NOCTO))
-		return __nfs_revalidate_inode(server, inode);
+	if (nd != NULL) {
+		/* VFS wants an on-the-wire revalidation */
+		if (nd->flags & LOOKUP_REVAL)
+			goto out_force;
+		/* This is an open(2) */
+		if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
+				!(server->flags & NFS_MOUNT_NOCTO))
+			goto out_force;
+	}
 	return nfs_revalidate_inode(server, inode);
+out_force:
+	return __nfs_revalidate_inode(server, inode);
 }
 
 /*
@@ -549,12 +580,8 @@ static inline
 int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
 		       struct nameidata *nd)
 {
-	int ndflags = 0;
-
-	if (nd)
-		ndflags = nd->flags;
 	/* Don't revalidate a negative dentry if we're creating a new file */
-	if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
+	if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
 		return 0;
 	return !nfs_check_verifier(dir, dentry);
 }
@@ -579,16 +606,12 @@ static int nfs_lookup_revalidate(struct 
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
 	unsigned long verifier;
-	int isopen = 0;
 
 	parent = dget_parent(dentry);
 	lock_kernel();
 	dir = parent->d_inode;
 	inode = dentry->d_inode;
 
-	if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN))
-		isopen = 1;
-
 	if (!inode) {
 		if (nfs_neg_need_reval(dir, dentry, nd))
 			goto out_bad;
@@ -602,11 +625,12 @@ static int nfs_lookup_revalidate(struct 
 	}
 
 	/* Revalidate parent directory attribute cache */
-	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+	if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+		goto out_zap_parent;
 
 	/* Force a full look up iff the parent directory has changed */
 	if (nfs_check_verifier(dir, dentry)) {
-		if (nfs_lookup_verify_inode(inode, isopen))
+		if (nfs_lookup_verify_inode(inode, nd))
 			goto out_zap_parent;
 		goto out_valid;
 	}
@@ -692,12 +716,16 @@ struct dentry_operations nfs_dentry_oper
 	.d_iput		= nfs_dentry_iput,
 };
 
+/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
 static inline
 int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
 {
 	if (NFS_PROTO(dir)->version == 2)
 		return 0;
-	if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
+	if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
 		return 0;
 	return (nd->intent.open.flags & O_EXCL) != 0;
 }
@@ -722,7 +750,11 @@ static struct dentry *nfs_lookup(struct 
 
 	lock_kernel();
 	/* Revalidate parent directory attribute cache */
-	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+	error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
+	if (error < 0) {
+		res = ERR_PTR(error);
+		goto out_unlock;
+	}
 
 	/* If we're doing an exclusive create, optimize away the lookup */
 	if (nfs_is_exclusive_create(dir, nd))
@@ -760,12 +792,13 @@ struct dentry_operations nfs4_dentry_ope
 	.d_iput		= nfs_dentry_iput,
 };
 
+/*
+ * Use intent information to determine whether we need to substitute
+ * the NFSv4-style stateful OPEN for the LOOKUP call
+ */
 static int is_atomic_open(struct inode *dir, struct nameidata *nd)
 {
-	if (!nd)
-		return 0;
-	/* Check that we are indeed trying to open this file */
-	if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN))
+	if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
 		return 0;
 	/* NFS does not (yet) have a stateful open for directories */
 	if (nd->flags & LOOKUP_DIRECTORY)
@@ -780,6 +813,7 @@ static struct dentry *nfs_atomic_lookup(
 {
 	struct dentry *res = NULL;
 	struct inode *inode = NULL;
+	int error;
 
 	/* Check that we are indeed trying to open this file */
 	if (!is_atomic_open(dir, nd))
@@ -798,7 +832,11 @@ static struct dentry *nfs_atomic_lookup(
 	/* Open the file on the server */
 	lock_kernel();
 	/* Revalidate parent directory attribute cache */
-	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+	error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
+	if (error < 0) {
+		res = ERR_PTR(error);
+		goto out;
+	}
 
 	if (nd->intent.open.flags & O_CREAT) {
 		nfs_begin_data_update(dir);
@@ -808,7 +846,7 @@ static struct dentry *nfs_atomic_lookup(
 		inode = nfs4_atomic_open(dir, dentry, nd);
 	unlock_kernel();
 	if (IS_ERR(inode)) {
-		int error = PTR_ERR(inode);
+		error = PTR_ERR(inode);
 		switch (error) {
 			/* Make a negative dentry */
 			case -ENOENT:
@@ -938,7 +976,7 @@ static struct dentry *nfs_readdir_lookup
 /*
  * Code common to create, mkdir, and mknod.
  */
-static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
 				struct nfs_fattr *fattr)
 {
 	struct inode *inode;
@@ -959,14 +997,12 @@ static int nfs_instantiate(struct dentry
 		if (error < 0)
 			goto out_err;
 	}
-	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
-	if (inode) {
-		d_instantiate(dentry, inode);
-		nfs_renew_times(dentry);
-		nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));
-		return 0;
-	}
 	error = -ENOMEM;
+	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
+	if (inode == NULL)
+		goto out_err;
+	d_instantiate(dentry, inode);
+	return 0;
 out_err:
 	d_drop(dentry);
 	return error;
@@ -982,7 +1018,6 @@ static int nfs_create(struct inode *dir,
 		struct nameidata *nd)
 {
 	struct iattr attr;
-	struct inode *inode;
 	int error;
 	int open_flags = 0;
 
@@ -997,18 +1032,17 @@ static int nfs_create(struct inode *dir,
 
 	lock_kernel();
 	nfs_begin_data_update(dir);
-	inode = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
+	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
 	nfs_end_data_update(dir);
-	if (!IS_ERR(inode)) {
-		d_instantiate(dentry, inode);
-		nfs_renew_times(dentry);
-		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-		error = 0;
-	} else {
-		error = PTR_ERR(inode);
-		d_drop(dentry);
-	}
+	if (error != 0)
+		goto out_err;
+	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 	unlock_kernel();
+	return 0;
+out_err:
+	unlock_kernel();
+	d_drop(dentry);
 	return error;
 }
 
@@ -1019,9 +1053,7 @@ static int
 nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
 {
 	struct iattr attr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
-	int error;
+	int status;
 
 	dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id,
 		dir->i_ino, dentry->d_name.name);
@@ -1034,15 +1066,18 @@ nfs_mknod(struct inode *dir, struct dent
 
 	lock_kernel();
 	nfs_begin_data_update(dir);
-	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
-					&fhandle, &fattr);
+	status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
 	nfs_end_data_update(dir);
-	if (!error)
-		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	else
-		d_drop(dentry);
+	if (status != 0)
+		goto out_err;
+	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 	unlock_kernel();
-	return error;
+	return 0;
+out_err:
+	unlock_kernel();
+	d_drop(dentry);
+	return status;
 }
 
 /*
@@ -1051,8 +1086,6 @@ nfs_mknod(struct inode *dir, struct dent
 static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct iattr attr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
 	int error;
 
 	dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id,
@@ -1062,23 +1095,17 @@ static int nfs_mkdir(struct inode *dir, 
 	attr.ia_mode = mode | S_IFDIR;
 
 	lock_kernel();
-#if 0
-	/*
-	 * Always drop the dentry, we can't always depend on
-	 * the fattr returned by the server (AIX seems to be
-	 * broken). We're better off doing another lookup than
-	 * depending on potentially bogus information.
-	 */
-	d_drop(dentry);
-#endif
 	nfs_begin_data_update(dir);
-	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
-					&fattr);
+	error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
 	nfs_end_data_update(dir);
-	if (!error)
-		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	else
-		d_drop(dentry);
+	if (error != 0)
+		goto out_err;
+	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+	unlock_kernel();
+	return 0;
+out_err:
+	d_drop(dentry);
 	unlock_kernel();
 	return error;
 }
@@ -1107,7 +1134,7 @@ static int nfs_sillyrename(struct inode 
 	static unsigned int sillycounter;
 	const int      i_inosize  = sizeof(dir->i_ino)*2;
 	const int      countersize = sizeof(sillycounter)*2;
-	const int      slen       = strlen(".nfs") + i_inosize + countersize;
+	const int      slen       = sizeof(".nfs") + i_inosize + countersize - 1;
 	char           silly[slen+1];
 	struct qstr    qsilly;
 	struct dentry *sdentry;
@@ -1466,8 +1493,8 @@ void nfs_access_add_cache(struct inode *
 		if (cache->cred)
 			put_rpccred(cache->cred);
 		cache->cred = get_rpccred(set->cred);
-		NFS_FLAGS(inode) &= ~NFS_INO_INVALID_ACCESS;
 	}
+	NFS_FLAGS(inode) &= ~NFS_INO_INVALID_ACCESS;
 	cache->jiffies = set->jiffies;
 	cache->mask = set->mask;
 }
@@ -1498,34 +1525,52 @@ out:
 int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
 	struct rpc_cred *cred;
-	int res;
+	int res = 0;
 
 	if (mask == 0)
-		return 0;
+		goto out;
+	/* Is this sys_access() ? */
+	if (nd != NULL && (nd->flags & LOOKUP_ACCESS))
+		goto force_lookup;
 
-	/* Are we checking permissions on anything other than lookup/execute? */
-	if ((mask & MAY_EXEC) == 0) {
-		/* We only need to check permissions on file open() and access() */
-		if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))
-			return 0;
-		/* NFSv4 has atomic_open... */
-		if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN))
-			return 0;
+	switch (inode->i_mode & S_IFMT) {
+		case S_IFLNK:
+			goto out;
+		case S_IFREG:
+			/* NFSv4 has atomic_open... */
+			if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
+					&& nd != NULL
+					&& (nd->flags & LOOKUP_OPEN))
+				goto out;
+			break;
+		case S_IFDIR:
+			/*
+			 * Optimize away all write operations, since the server
+			 * will check permissions when we perform the op.
+			 */
+			if ((mask & MAY_WRITE) && !(mask & MAY_READ))
+				goto out;
 	}
 
+force_lookup:
 	lock_kernel();
 
 	if (!NFS_PROTO(inode)->access)
 		goto out_notsup;
 
 	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
-	res = nfs_do_access(inode, cred, mask);
-	put_rpccred(cred);
+	if (!IS_ERR(cred)) {
+		res = nfs_do_access(inode, cred, mask);
+		put_rpccred(cred);
+	} else
+		res = PTR_ERR(cred);
 	unlock_kernel();
+out:
 	return res;
 out_notsup:
-	nfs_revalidate_inode(NFS_SERVER(inode), inode);
-	res = generic_permission(inode, mask, NULL);
+	res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	if (res == 0)
+		res = generic_permission(inode, mask, NULL);
 	unlock_kernel();
 	return res;
 }
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -37,6 +37,7 @@
 
 static int nfs_file_open(struct inode *, struct file *);
 static int nfs_file_release(struct inode *, struct file *);
+static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
 static int  nfs_file_mmap(struct file *, struct vm_area_struct *);
 static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
 static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
@@ -44,9 +45,11 @@ static ssize_t nfs_file_write(struct kio
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 static int nfs_check_flags(int flags);
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
 
 struct file_operations nfs_file_operations = {
-	.llseek		= remote_llseek,
+	.llseek		= nfs_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
 	.aio_read		= nfs_file_read,
@@ -57,6 +60,7 @@ struct file_operations nfs_file_operatio
 	.release	= nfs_file_release,
 	.fsync		= nfs_fsync,
 	.lock		= nfs_lock,
+	.flock		= nfs_flock,
 	.sendfile	= nfs_file_sendfile,
 	.check_flags	= nfs_check_flags,
 };
@@ -105,9 +109,51 @@ nfs_file_open(struct inode *inode, struc
 static int
 nfs_file_release(struct inode *inode, struct file *filp)
 {
+	/* Ensure that dirty pages are flushed out with the right creds */
+	if (filp->f_mode & FMODE_WRITE)
+		filemap_fdatawrite(filp->f_mapping);
 	return NFS_PROTO(inode)->file_release(inode, filp);
 }
 
+/**
+ * nfs_revalidate_size - Revalidate the file size
+ * @inode - pointer to inode struct
+ * @file - pointer to struct file
+ *
+ * Revalidates the file length. This is basically a wrapper around
+ * nfs_revalidate_inode() that takes into account the fact that we may
+ * have cached writes (in which case we don't care about the server's
+ * idea of what the file length is), or O_DIRECT (in which case we
+ * shouldn't trust the cache).
+ */
+static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
+{
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	if (server->flags & NFS_MOUNT_NOAC)
+		goto force_reval;
+	if (filp->f_flags & O_DIRECT)
+		goto force_reval;
+	if (nfsi->npages != 0)
+		return 0;
+	return nfs_revalidate_inode(server, inode);
+force_reval:
+	return __nfs_revalidate_inode(server, inode);
+}
+
+static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
+{
+	/* origin == SEEK_END => we must revalidate the cached file length */
+	if (origin == 2) {
+		struct inode *inode = filp->f_mapping->host;
+		int retval = nfs_revalidate_file_size(inode, filp);
+		if (retval < 0)
+			return (loff_t)retval;
+	}
+	return remote_llseek(filp, offset, origin);
+}
+
 /*
  * Flush all dirty pages, and check for write errors.
  *
@@ -312,6 +358,25 @@ static int do_getlk(struct file *filp, i
 	return status;
 }
 
+static int do_vfs_lock(struct file *file, struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+	return res;
+}
+
 static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
 {
 	struct inode *inode = filp->f_mapping->host;
@@ -338,7 +403,7 @@ static int do_unlk(struct file *filp, in
 	if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
 		status = NFS_PROTO(inode)->lock(filp, cmd, fl);
 	else
-		status = posix_lock_file_wait(filp, fl);
+		status = do_vfs_lock(filp, fl);
 	unlock_kernel();
 	rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
 	return status;
@@ -377,9 +442,9 @@ static int do_setlk(struct file *filp, i
 		 * the process exits.
 		 */
 		if (status == -EINTR || status == -ERESTARTSYS)
-			posix_lock_file_wait(filp, fl);
+			do_vfs_lock(filp, fl);
 	} else
-		status = posix_lock_file_wait(filp, fl);
+		status = do_vfs_lock(filp, fl);
 	unlock_kernel();
 	if (status < 0)
 		goto out;
@@ -401,8 +466,7 @@ out:
 /*
  * Lock a (portion of) a file
  */
-int
-nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
 	struct inode * inode = filp->f_mapping->host;
 
@@ -418,6 +482,27 @@ nfs_lock(struct file *filp, int cmd, str
 	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
 		return -ENOLCK;
 
+	if (IS_GETLK(cmd))
+		return do_getlk(filp, cmd, fl);
+	if (fl->fl_type == F_UNLCK)
+		return do_unlk(filp, cmd, fl);
+	return do_setlk(filp, cmd, fl);
+}
+
+/*
+ * Lock a (portion of) a file
+ */
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
+{
+	struct inode * inode = filp->f_mapping->host;
+
+	dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
+			inode->i_sb->s_id, inode->i_ino,
+			fl->fl_type, fl->fl_flags);
+
+	if (!inode)
+		return -EINVAL;
+
 	/*
 	 * No BSD flocks over NFS allowed.
 	 * Note: we could try to fake a POSIX lock request here by
@@ -425,11 +510,14 @@ nfs_lock(struct file *filp, int cmd, str
 	 * Not sure whether that would be unique, though, or whether
 	 * that would break in other places.
 	 */
-	if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
+	if (!(fl->fl_flags & FL_FLOCK))
 		return -ENOLCK;
 
-	if (IS_GETLK(cmd))
-		return do_getlk(filp, cmd, fl);
+	/* We're simulating flock() locks using posix locks on the server */
+	fl->fl_owner = (fl_owner_t)filp;
+	fl->fl_start = 0;
+	fl->fl_end = OFFSET_MAX;
+
 	if (fl->fl_type == F_UNLCK)
 		return do_unlk(filp, cmd, fl);
 	return do_setlk(filp, cmd, fl);
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -79,7 +79,7 @@ static ssize_t   idmap_pipe_upcall(struc
 		     char __user *, size_t);
 static ssize_t   idmap_pipe_downcall(struct file *, const char __user *,
 		     size_t);
-void             idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
+static void      idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 
 static unsigned int fnvhash32(const void *, size_t);
 
@@ -434,7 +434,7 @@ out:
 	return ret;
 }
 
-void
+static void
 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
 	struct idmap_msg *im = msg->data;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -64,6 +64,8 @@ static void nfs_umount_begin(struct supe
 static int  nfs_statfs(struct super_block *, struct kstatfs *);
 static int  nfs_show_options(struct seq_file *, struct vfsmount *);
 
+static struct rpc_program	nfs_program;
+
 static struct super_operations nfs_sops = { 
 	.alloc_inode	= nfs_alloc_inode,
 	.destroy_inode	= nfs_destroy_inode,
@@ -78,7 +80,7 @@ static struct super_operations nfs_sops 
 /*
  * RPC cruft for NFS
  */
-struct rpc_stat			nfs_rpcstat = {
+static struct rpc_stat		nfs_rpcstat = {
 	.program		= &nfs_program
 };
 static struct rpc_version *	nfs_version[] = {
@@ -95,7 +97,7 @@ static struct rpc_version *	nfs_version[
 #endif
 };
 
-struct rpc_program		nfs_program = {
+static struct rpc_program	nfs_program = {
 	.name			= "nfs",
 	.number			= NFS_PROGRAM,
 	.nrvers			= sizeof(nfs_version) / sizeof(nfs_version[0]),
@@ -247,6 +249,7 @@ nfs_sb_init(struct super_block *sb, rpc_
 			.fattr = &fattr,
 	};
 	int no_root_error = 0;
+	unsigned long max_rpc_payload;
 
 	/* We probably want something more informative here */
 	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
@@ -283,6 +286,12 @@ nfs_sb_init(struct super_block *sb, rpc_
 	if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
 		server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
 
+	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
+	if (server->rsize > max_rpc_payload)
+		server->rsize = max_rpc_payload;
+	if (server->wsize > max_rpc_payload)
+		server->wsize = max_rpc_payload;
+
 	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	if (server->rpages > NFS_READ_MAXIOV) {
 		server->rpages = NFS_READ_MAXIOV;
@@ -317,6 +326,9 @@ nfs_sb_init(struct super_block *sb, rpc_
 	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
 		sb->s_maxbytes = MAX_LFS_FILESIZE; 
 
+	server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+	server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
+
 	/* We're airborne Set socket buffersize */
 	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 	return 0;
@@ -364,9 +376,8 @@ nfs_create_client(struct nfs_server *ser
 		goto out_fail;
 	}
 
-	clnt->cl_intr     = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
-	clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
-	clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
+	clnt->cl_intr     = 1;
+	clnt->cl_softrtry = 1;
 	clnt->cl_chatty   = 1;
 
 	return clnt;
@@ -538,7 +549,6 @@ static int nfs_show_options(struct seq_f
 		{ NFS_MOUNT_NOCTO, ",nocto", "" },
 		{ NFS_MOUNT_NOAC, ",noac", "" },
 		{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
-		{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
 		{ 0, NULL, NULL }
 	};
 	struct proc_nfs_info *nfs_infop;
@@ -792,7 +802,7 @@ nfs_setattr(struct dentry *dentry, struc
  * Wait for the inode to get unlocked.
  * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
  */
-int
+static int
 nfs_wait_on_inode(struct inode *inode, int flag)
 {
 	struct rpc_clnt	*clnt = NFS_CLIENT(inode);
@@ -856,6 +866,12 @@ struct nfs_open_context *get_nfs_open_co
 void put_nfs_open_context(struct nfs_open_context *ctx)
 {
 	if (atomic_dec_and_test(&ctx->count)) {
+		if (!list_empty(&ctx->list)) {
+			struct inode *inode = ctx->dentry->d_inode;
+			spin_lock(&inode->i_lock);
+			list_del(&ctx->list);
+			spin_unlock(&inode->i_lock);
+		}
 		if (ctx->state != NULL)
 			nfs4_close_state(ctx->state, ctx->mode);
 		if (ctx->cred != NULL)
@@ -904,7 +920,7 @@ void nfs_file_clear_open_context(struct 
 	if (ctx) {
 		filp->private_data = NULL;
 		spin_lock(&inode->i_lock);
-		list_del(&ctx->list);
+		list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
 		spin_unlock(&inode->i_lock);
 		put_nfs_open_context(ctx);
 	}
@@ -918,8 +934,9 @@ int nfs_open(struct inode *inode, struct
 	struct nfs_open_context *ctx;
 	struct rpc_cred *cred;
 
-	if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
-		return -ENOMEM;
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
 	ctx = alloc_nfs_open_context(filp->f_dentry, cred);
 	put_rpccred(cred);
 	if (ctx == NULL)
@@ -1542,6 +1559,7 @@ static int nfs4_fill_super(struct super_
 	if (data->wsize != 0)
 		server->wsize = nfs_block_size(data->wsize, NULL);
 	server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+	server->caps = NFS_CAP_ATOMIC_OPEN;
 
 	server->acregmin = data->acregmin*HZ;
 	server->acregmax = data->acregmax*HZ;
@@ -1609,9 +1627,17 @@ static int nfs4_fill_super(struct super_
 			err = PTR_ERR(clnt);
 			goto out_fail;
 		}
+		clnt->cl_intr     = 1;
+		clnt->cl_softrtry = 1;
 		clnt->cl_chatty   = 1;
 		clp->cl_rpcclient = clnt;
 		clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+		if (IS_ERR(clp->cl_cred)) {
+			up_write(&clp->cl_sem);
+			err = PTR_ERR(clp->cl_cred);
+			clp->cl_cred = NULL;
+			goto out_fail;
+		}
 		memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
 		nfs_idmap_new(clp);
 	}
@@ -1634,8 +1660,6 @@ static int nfs4_fill_super(struct super_
 		return PTR_ERR(clnt);
 	}
 
-	clnt->cl_intr     = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
-	clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
 	server->client    = clnt;
 
 	if (server->nfs4_state->cl_idmap == NULL) {
@@ -1880,7 +1904,7 @@ static void init_once(void * foo, kmem_c
 	}
 }
  
-int nfs_init_inodecache(void)
+static int nfs_init_inodecache(void)
 {
 	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
 					     sizeof(struct nfs_inode),
@@ -1892,7 +1916,7 @@ int nfs_init_inodecache(void)
 	return 0;
 }
 
-void nfs_destroy_inodecache(void)
+static void nfs_destroy_inodecache(void)
 {
 	if (kmem_cache_destroy(nfs_inode_cachep))
 		printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -31,7 +31,7 @@
 
 static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *,
 								int, int);
-struct rpc_program		mnt_program;
+static struct rpc_program	mnt_program;
 
 struct mnt_fhstatus {
 	unsigned int		status;
@@ -174,7 +174,7 @@ static struct rpc_version *	mnt_version[
 
 static struct rpc_stat		mnt_stats;
 
-struct rpc_program	mnt_program = {
+static struct rpc_program	mnt_program = {
 	.name		= "mount",
 	.number		= NFS_MNT_PROGRAM,
 	.nrvers		= sizeof(mnt_version)/sizeof(mnt_version[0]),
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -295,7 +295,7 @@ static int nfs3_proc_commit(struct nfs_w
  * Create a regular file.
  * For now, we don't implement O_EXCL.
  */
-static struct inode *
+static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
@@ -342,29 +342,19 @@ again:
 				break;
 
 			case NFS3_CREATE_UNCHECKED:
-				goto exit;
+				goto out;
 		}
 		goto again;
 	}
 
-exit:
-	dprintk("NFS reply create: %d\n", status);
-
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (status != 0)
 		goto out;
-	if (fhandle.size == 0 || !(fattr.valid & NFS_ATTR_FATTR)) {
-		status = nfs3_proc_lookup(dir, &dentry->d_name, &fhandle, &fattr);
-		if (status != 0)
-			goto out;
-	}
 
 	/* When we created the file with exclusive semantics, make
 	 * sure we set the attributes afterwards. */
 	if (arg.createmode == NFS3_CREATE_EXCLUSIVE) {
-		struct nfs3_sattrargs	arg = {
-			.fh		= &fhandle,
-			.sattr		= sattr,
-		};
 		dprintk("NFS call  setattr (post-create)\n");
 
 		if (!(sattr->ia_valid & ATTR_ATIME_SET))
@@ -375,20 +365,13 @@ exit:
 		/* Note: we could use a guarded setattr here, but I'm
 		 * not sure this buys us anything (and I'd have
 		 * to revamp the NFSv3 XDR code) */
-		fattr.valid = 0;
-		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR,
-						&arg, &fattr, 0);
+		status = nfs3_proc_setattr(dentry, &fattr, sattr);
+		nfs_refresh_inode(dentry->d_inode, &fattr);
 		dprintk("NFS reply setattr (post-create): %d\n", status);
 	}
-	if (status == 0) {
-		struct inode *inode;
-		inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
-		if (inode)
-			return inode;
-		status = -ENOMEM;
-	}
 out:
-	return ERR_PTR(status);
+	dprintk("NFS reply create: %d\n", status);
+	return status;
 }
 
 static int
@@ -540,28 +523,30 @@ nfs3_proc_symlink(struct inode *dir, str
 }
 
 static int
-nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
-		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 {
-	struct nfs_fattr	dir_attr;
+	struct nfs_fh fhandle;
+	struct nfs_fattr fattr, dir_attr;
 	struct nfs3_mkdirargs	arg = {
 		.fh		= NFS_FH(dir),
-		.name		= name->name,
-		.len		= name->len,
+		.name		= dentry->d_name.name,
+		.len		= dentry->d_name.len,
 		.sattr		= sattr
 	};
 	struct nfs3_diropres	res = {
 		.dir_attr	= &dir_attr,
-		.fh		= fhandle,
-		.fattr		= fattr
+		.fh		= &fhandle,
+		.fattr		= &fattr
 	};
 	int			status;
 
-	dprintk("NFS call  mkdir %s\n", name->name);
+	dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
 	dir_attr.valid = 0;
-	fattr->valid = 0;
+	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
 	nfs_refresh_inode(dir, &dir_attr);
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
@@ -639,23 +624,24 @@ nfs3_proc_readdir(struct dentry *dentry,
 }
 
 static int
-nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
-		dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+		dev_t rdev)
 {
-	struct nfs_fattr	dir_attr;
+	struct nfs_fh fh;
+	struct nfs_fattr fattr, dir_attr;
 	struct nfs3_mknodargs	arg = {
 		.fh		= NFS_FH(dir),
-		.name		= name->name,
-		.len		= name->len,
+		.name		= dentry->d_name.name,
+		.len		= dentry->d_name.len,
 		.sattr		= sattr,
 		.rdev		= rdev
 	};
 	struct nfs3_diropres	res = {
 		.dir_attr	= &dir_attr,
-		.fh		= fh,
-		.fattr		= fattr
+		.fh		= &fh,
+		.fattr		= &fattr
 	};
-	int			status;
+	int status;
 
 	switch (sattr->ia_mode & S_IFMT) {
 	case S_IFBLK:	arg.type = NF3BLK;  break;
@@ -665,12 +651,14 @@ nfs3_proc_mknod(struct inode *dir, struc
 	default:	return -EINVAL;
 	}
 
-	dprintk("NFS call  mknod %s %u:%u\n", name->name,
+	dprintk("NFS call  mknod %s %u:%u\n", dentry->d_name.name,
 			MAJOR(rdev), MINOR(rdev));
 	dir_attr.valid = 0;
-	fattr->valid = 0;
+	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
 	nfs_refresh_inode(dir, &dir_attr);
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fh, &fattr);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -37,6 +37,7 @@
 
 #include <linux/mm.h>
 #include <linux/utsname.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/sunrpc/clnt.h>
@@ -57,16 +58,17 @@
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
+static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
 extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
 
 extern nfs4_stateid zero_stateid;
 
 /* Prevent leaks of NFSv4 errors into userland */
-static inline int nfs4_map_errors(int err)
+int nfs4_map_errors(int err)
 {
 	if (err < -1000) {
-		printk(KERN_WARNING "%s could not handle NFSv4 error %d\n",
+		dprintk("%s could not handle NFSv4 error %d\n",
 				__FUNCTION__, -err);
 		return -EIO;
 	}
@@ -188,6 +190,23 @@ static void update_changeattr(struct ino
 		nfsi->change_attr = cinfo->after;
 }
 
+static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
+{
+	struct inode *inode = state->inode;
+
+	open_flags &= (FMODE_READ|FMODE_WRITE);
+	/* Protect against nfs4_find_state() */
+	spin_lock(&inode->i_lock);
+	state->state |= open_flags;
+	/* NB! List reordering - see the reclaim code for why.  */
+	if ((open_flags & FMODE_WRITE) && 0 == state->nwriters++)
+		list_move(&state->open_states, &state->owner->so_states);
+	if (open_flags & FMODE_READ)
+		state->nreaders++;
+	memcpy(&state->stateid, stateid, sizeof(state->stateid));
+	spin_unlock(&inode->i_lock);
+}
+
 /*
  * OPEN_RECLAIM:
  * 	reclaim state on the server after a reboot.
@@ -244,7 +263,7 @@ static int _nfs4_open_reclaim(struct nfs
 	return status;
 }
 
-int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
+static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(state->inode);
 	struct nfs4_exception exception = { };
@@ -332,7 +351,7 @@ int nfs4_open_delegation_recall(struct d
 	return err;
 }
 
-static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid)
+static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid)
 {
 	struct nfs_open_confirmargs arg = {
 		.fh             = fh,
@@ -355,11 +374,49 @@ static int _nfs4_proc_open_confirm(struc
 	return status;
 }
 
-static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
+static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner  *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res)
+{
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
+		.rpc_argp = o_arg,
+		.rpc_resp = o_res,
+		.rpc_cred = sp->so_cred,
+	};
+	int status;
+
+	/* Update sequence id. The caller must serialize! */
+	o_arg->seqid = sp->so_seqid;
+	o_arg->id = sp->so_id;
+	o_arg->clientid = sp->so_client->cl_clientid;
+
+	status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
+	nfs4_increment_seqid(status, sp);
+	if (status != 0)
+		goto out;
+	update_changeattr(dir, &o_res->cinfo);
+	if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
+		status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
+				sp, &o_res->stateid);
+		if (status != 0)
+			goto out;
+	}
+	if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
+		status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
+out:
+	return status;
+}
+
+static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
 {
 	struct nfs_access_entry cache;
+	int mask = 0;
 	int status;
 
+	if (openflags & FMODE_READ)
+		mask |= MAY_READ;
+	if (openflags & FMODE_WRITE)
+		mask |= MAY_WRITE;
 	status = nfs_access_get_cached(inode, cred, &cache);
 	if (status == 0)
 		goto out;
@@ -379,9 +436,103 @@ out:
 }
 
 /*
+ * OPEN_EXPIRED:
+ * 	reclaim state on the server after a network partition.
+ * 	Assumes caller holds the appropriate lock
+ */
+static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+{
+	struct dentry *parent = dget_parent(dentry);
+	struct inode *dir = parent->d_inode;
+	struct inode *inode = state->inode;
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs_delegation *delegation = NFS_I(inode)->delegation;
+	struct nfs_fattr        f_attr = {
+		.valid = 0,
+	};
+	struct nfs_openargs o_arg = {
+		.fh = NFS_FH(dir),
+		.open_flags = state->state,
+		.name = &dentry->d_name,
+		.bitmask = server->attr_bitmask,
+		.claim = NFS4_OPEN_CLAIM_NULL,
+	};
+	struct nfs_openres o_res = {
+		.f_attr = &f_attr,
+		.server = server,
+	};
+	int status = 0;
+
+	if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
+		status = _nfs4_do_access(inode, sp->so_cred, state->state);
+		if (status < 0)
+			goto out;
+		memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid));
+		set_bit(NFS_DELEGATED_STATE, &state->flags);
+		goto out;
+	}
+	status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
+	if (status != 0)
+		goto out_nodeleg;
+	/* Check if files differ */
+	if ((f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		goto out_stale;
+	/* Has the file handle changed? */
+	if (nfs_compare_fh(&o_res.fh, NFS_FH(inode)) != 0) {
+		/* Verify if the change attributes are the same */
+		if (f_attr.change_attr != NFS_I(inode)->change_attr)
+			goto out_stale;
+		if (nfs_size_to_loff_t(f_attr.size) != inode->i_size)
+			goto out_stale;
+		/* Lets just pretend that this is the same file */
+		nfs_copy_fh(NFS_FH(inode), &o_res.fh);
+		NFS_I(inode)->fileid = f_attr.fileid;
+	}
+	memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
+	if (o_res.delegation_type != 0) {
+		if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM))
+			nfs_inode_set_delegation(inode, sp->so_cred, &o_res);
+		else
+			nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
+	}
+out_nodeleg:
+	clear_bit(NFS_DELEGATED_STATE, &state->flags);
+out:
+	dput(parent);
+	return status;
+out_stale:
+	status = -ESTALE;
+	/* Invalidate the state owner so we don't ever use it again */
+	nfs4_drop_state_owner(sp);
+	d_drop(dentry);
+	/* Should we be trying to close that stateid? */
+	goto out_nodeleg;
+}
+
+static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+{
+	struct nfs_inode *nfsi = NFS_I(state->inode);
+	struct nfs_open_context *ctx;
+	int status;
+
+	spin_lock(&state->inode->i_lock);
+	list_for_each_entry(ctx, &nfsi->open_files, list) {
+		if (ctx->state != state)
+			continue;
+		get_nfs_open_context(ctx);
+		spin_unlock(&state->inode->i_lock);
+		status = _nfs4_open_expired(sp, state, ctx->dentry);
+		put_nfs_open_context(ctx);
+		return status;
+	}
+	spin_unlock(&state->inode->i_lock);
+	return -ENOENT;
+}
+
+/*
  * Returns an nfs4_state + an extra reference to the inode
  */
-int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res)
 {
 	struct nfs_delegation *delegation;
 	struct nfs_server *server = NFS_SERVER(inode);
@@ -390,7 +541,6 @@ int _nfs4_open_delegated(struct inode *i
 	struct nfs4_state_owner *sp = NULL;
 	struct nfs4_state *state = NULL;
 	int open_flags = flags & (FMODE_READ|FMODE_WRITE);
-	int mask = 0;
 	int err;
 
 	/* Protect against reboot recovery - NOTE ORDER! */
@@ -424,20 +574,12 @@ int _nfs4_open_delegated(struct inode *i
 		goto out_err;
 
 	lock_kernel();
-	err = _nfs4_do_access(inode, cred, mask);
+	err = _nfs4_do_access(inode, cred, open_flags);
 	unlock_kernel();
 	if (err != 0)
 		goto out_err;
-	spin_lock(&inode->i_lock);
-	memcpy(state->stateid.data, delegation->stateid.data,
-			sizeof(state->stateid.data));
-	state->state |= open_flags;
-	if (open_flags & FMODE_READ)
-		state->nreaders++;
-	if (open_flags & FMODE_WRITE)
-		state->nwriters++;
 	set_bit(NFS_DELEGATED_STATE, &state->flags);
-	spin_unlock(&inode->i_lock);
+	update_open_stateid(state, &delegation->stateid, open_flags);
 out_ok:
 	up(&sp->so_sema);
 	nfs4_put_state_owner(sp);
@@ -500,12 +642,6 @@ static int _nfs4_do_open(struct inode *d
 		.f_attr         = &f_attr,
 		.server         = server,
 	};
-	struct rpc_message msg = {
-		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
-		.rpc_argp       = &o_arg,
-		.rpc_resp       = &o_res,
-		.rpc_cred	= cred,
-	};
 
 	/* Protect against reboot recovery conflicts */
 	down_read(&clp->cl_sem);
@@ -522,26 +658,10 @@ static int _nfs4_do_open(struct inode *d
 		o_arg.u.attrs = sattr;
 	/* Serialization for the sequence id */
 	down(&sp->so_sema);
-	o_arg.seqid = sp->so_seqid;
-	o_arg.id = sp->so_id;
-	o_arg.clientid = clp->cl_clientid,
 
-	status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
-	nfs4_increment_seqid(status, sp);
-	if (status)
+	status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
+	if (status != 0)
 		goto out_err;
-	update_changeattr(dir, &o_res.cinfo);
-	if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
-		status = _nfs4_proc_open_confirm(server->client, &o_res.fh,
-				sp, &o_res.stateid);
-		if (status != 0)
-			goto out_err;
-	}
-	if (!(f_attr.valid & NFS_ATTR_FATTR)) {
-		status = server->rpc_ops->getattr(server, &o_res.fh, &f_attr);
-		if (status < 0)
-			goto out_err;
-	}
 
 	status = -ENOMEM;
 	inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
@@ -550,14 +670,7 @@ static int _nfs4_do_open(struct inode *d
 	state = nfs4_get_open_state(inode, sp);
 	if (!state)
 		goto out_err;
-	memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
-	spin_lock(&inode->i_lock);
-	if (flags & FMODE_READ)
-		state->nreaders++;
-	if (flags & FMODE_WRITE)
-		state->nwriters++;
-	state->state |= flags & (FMODE_READ|FMODE_WRITE);
-	spin_unlock(&inode->i_lock);
+	update_open_stateid(state, &o_res.stateid, flags);
 	if (o_res.delegation_type != 0)
 		nfs_inode_set_delegation(inode, cred, &o_res);
 	up(&sp->so_sema);
@@ -581,7 +694,7 @@ out_err:
 }
 
 
-struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
@@ -645,7 +758,7 @@ static int _nfs4_do_setattr(struct nfs_s
 	return rpc_call_sync(server->client, &msg, 0);
 }
 
-int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
                 struct nfs_fh *fhandle, struct iattr *sattr,
                 struct nfs4_state *state)
 {
@@ -680,7 +793,6 @@ static void nfs4_close_done(struct rpc_t
 	nfs4_increment_seqid(task->tk_status, sp);
 	switch (task->tk_status) {
 		case 0:
-			state->state = calldata->arg.open_flags;
 			memcpy(&state->stateid, &calldata->res.stateid,
 					sizeof(state->stateid));
 			break;
@@ -695,6 +807,7 @@ static void nfs4_close_done(struct rpc_t
 				return;
 			}
 	}
+	state->state = calldata->arg.open_flags;
 	nfs4_put_open_state(state);
 	up(&sp->so_sema);
 	nfs4_put_state_owner(sp);
@@ -774,6 +887,8 @@ nfs4_atomic_open(struct inode *dir, stru
 	}
 
 	cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
+	if (IS_ERR(cred))
+		return (struct inode *)cred;
 	state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state))
@@ -789,6 +904,8 @@ nfs4_open_revalidate(struct inode *dir, 
 	struct inode *inode;
 
 	cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
 	state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
 	if (IS_ERR(state))
 		state = nfs4_do_open(dir, dentry, openflags, NULL, cred);
@@ -1009,6 +1126,8 @@ nfs4_proc_setattr(struct dentry *dentry,
 	
 	if (size_change) {
 		struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
+		if (IS_ERR(cred))
+			return PTR_ERR(cred);
 		state = nfs4_find_state(inode, cred, FMODE_WRITE);
 		if (state == NULL) {
 			state = nfs4_open_delegated(dentry->d_inode,
@@ -1315,33 +1434,37 @@ static int nfs4_proc_commit(struct nfs_w
  * opens the file O_RDONLY. This will all be resolved with the VFS changes.
  */
 
-static struct inode *
+static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                  int flags)
 {
-	struct inode *inode;
-	struct nfs4_state *state = NULL;
+	struct nfs4_state *state;
 	struct rpc_cred *cred;
+	int status = 0;
 
 	cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
+	if (IS_ERR(cred)) {
+		status = PTR_ERR(cred);
+		goto out;
+	}
 	state = nfs4_do_open(dir, dentry, flags, sattr, cred);
 	put_rpccred(cred);
-	if (!IS_ERR(state)) {
-		inode = state->inode;
-		if (flags & O_EXCL) {
-			struct nfs_fattr fattr;
-			int status;
-			status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,
-			                     NFS_FH(inode), sattr, state);
-			if (status != 0) {
-				nfs4_close_state(state, flags);
-				iput(inode);
-				inode = ERR_PTR(status);
-			}
-		}
-	} else
-		inode = (struct inode *)state;
-	return inode;
+	if (IS_ERR(state)) {
+		status = PTR_ERR(state);
+		goto out;
+	}
+	d_instantiate(dentry, state->inode);
+	if (flags & O_EXCL) {
+		struct nfs_fattr fattr;
+		status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,
+		                     NFS_FH(state->inode), sattr, state);
+		if (status == 0)
+			goto out;
+	} else if (flags != 0)
+		goto out;
+	nfs4_close_state(state, flags);
+out:
+	return status;
 }
 
 static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
@@ -1539,23 +1662,24 @@ static int nfs4_proc_symlink(struct inod
 	return err;
 }
 
-static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
-		struct iattr *sattr, struct nfs_fh *fhandle,
-		struct nfs_fattr *fattr)
+static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+		struct iattr *sattr)
 {
 	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs_fh fhandle;
+	struct nfs_fattr fattr;
 	struct nfs4_create_arg arg = {
 		.dir_fh = NFS_FH(dir),
 		.server = server,
-		.name = name,
+		.name = &dentry->d_name,
 		.attrs = sattr,
 		.ftype = NF4DIR,
 		.bitmask = server->attr_bitmask,
 	};
 	struct nfs4_create_res res = {
 		.server = server,
-		.fh = fhandle,
-		.fattr = fattr,
+		.fh = &fhandle,
+		.fattr = &fattr,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
@@ -1564,24 +1688,24 @@ static int _nfs4_proc_mkdir(struct inode
 	};
 	int			status;
 
-	fattr->valid = 0;
+	fattr.valid = 0;
 	
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
-	if (!status)
+	if (!status) {
 		update_changeattr(dir, &res.dir_cinfo);
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
+	}
 	return status;
 }
 
-static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
-		struct iattr *sattr, struct nfs_fh *fhandle,
-		struct nfs_fattr *fattr)
+static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mkdir(dir, name, sattr,
-					fhandle, fattr),
+				_nfs4_proc_mkdir(dir, dentry, sattr),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -1596,6 +1720,7 @@ static int _nfs4_proc_readdir(struct den
 		.pages = &page,
 		.pgbase = 0,
 		.count = count,
+		.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
 	};
 	struct nfs4_readdir_res res;
 	struct rpc_message msg = {
@@ -1630,22 +1755,23 @@ static int nfs4_proc_readdir(struct dent
 	return err;
 }
 
-static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name,
-		struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
-		struct nfs_fattr *fattr)
+static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs_fh fh;
+	struct nfs_fattr fattr;
 	struct nfs4_create_arg arg = {
 		.dir_fh = NFS_FH(dir),
 		.server = server,
-		.name = name,
+		.name = &dentry->d_name,
 		.attrs = sattr,
 		.bitmask = server->attr_bitmask,
 	};
 	struct nfs4_create_res res = {
 		.server = server,
-		.fh = fh,
-		.fattr = fattr,
+		.fh = &fh,
+		.fattr = &fattr,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
@@ -1655,7 +1781,7 @@ static int _nfs4_proc_mknod(struct inode
 	int			status;
 	int                     mode = sattr->ia_mode;
 
-	fattr->valid = 0;
+	fattr.valid = 0;
 
 	BUG_ON(!(sattr->ia_valid & ATTR_MODE));
 	BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
@@ -1675,21 +1801,21 @@ static int _nfs4_proc_mknod(struct inode
 		arg.ftype = NF4SOCK;
 	
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
-	if (!status)
+	if (status == 0) {
 		update_changeattr(dir, &res.dir_cinfo);
+		status = nfs_instantiate(dentry, &fh, &fattr);
+	}
 	return status;
 }
 
-static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
-		struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
-		struct nfs_fattr *fattr)
+static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mknod(dir, name, sattr, rdev,
-					fh, fattr),
+				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -2001,8 +2127,8 @@ nfs4_proc_file_open(struct inode *inode,
 
 	/* Find our open stateid */
 	cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
-	if (unlikely(cred == NULL))
-		return -ENOMEM;
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
 	ctx = alloc_nfs_open_context(dentry, cred);
 	put_rpccred(cred);
 	if (unlikely(ctx == NULL))
@@ -2067,7 +2193,7 @@ nfs4_async_handle_error(struct rpc_task 
 	return 0;
 }
 
-int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
+static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
 {
 	DEFINE_WAIT(wait);
 	sigset_t oldset;
@@ -2151,9 +2277,7 @@ int nfs4_handle_exception(struct nfs_ser
 
 int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port)
 {
-	static nfs4_verifier sc_verifier;
-	static int initialized;
-	
+	nfs4_verifier sc_verifier;
 	struct nfs4_setclientid setclientid = {
 		.sc_verifier = &sc_verifier,
 		.sc_prog = program,
@@ -2164,27 +2288,38 @@ int nfs4_proc_setclientid(struct nfs4_cl
 		.rpc_resp = clp,
 		.rpc_cred = clp->cl_cred,
 	};
+	u32 *p;
+	int loop = 0;
+	int status;
 
-	if (!initialized) {
-		struct timespec boot_time;
-		u32 *p;
-
-		initialized = 1;
-		boot_time = CURRENT_TIME;
-		p = (u32*)sc_verifier.data;
-		*p++ = htonl((u32)boot_time.tv_sec);
-		*p = htonl((u32)boot_time.tv_nsec);
-	}
-	setclientid.sc_name_len = scnprintf(setclientid.sc_name,
-			sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u",
-			clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr));
-	setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
-			sizeof(setclientid.sc_netid), "tcp");
-	setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
-			sizeof(setclientid.sc_uaddr), "%s.%d.%d",
-			clp->cl_ipaddr, port >> 8, port & 255);
+	p = (u32*)sc_verifier.data;
+	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
+	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
+
+	for(;;) {
+		setclientid.sc_name_len = scnprintf(setclientid.sc_name,
+				sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u",
+				clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr),
+				clp->cl_cred->cr_ops->cr_name,
+				clp->cl_id_uniquifier);
+		setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
+				sizeof(setclientid.sc_netid), "tcp");
+		setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
+				sizeof(setclientid.sc_uaddr), "%s.%d.%d",
+				clp->cl_ipaddr, port >> 8, port & 255);
 
-	return rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+		status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+		if (status != -NFS4ERR_CLID_INUSE)
+			break;
+		if (signalled())
+			break;
+		if (loop++ & 1)
+			ssleep(clp->cl_lease_time + 1);
+		else
+			if (++clp->cl_id_uniquifier == 0)
+				break;
+	}
+	return status;
 }
 
 int
@@ -2361,6 +2496,25 @@ static int nfs4_proc_getlk(struct nfs4_s
 	return err;
 }
 
+static int do_vfs_lock(struct file *file, struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+	return res;
+}
+
 static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
 	struct inode *inode = state->inode;
@@ -2408,7 +2562,7 @@ static int _nfs4_proc_unlck(struct nfs4_
 out:
 	up(&state->lock_sema);
 	if (status == 0)
-		posix_lock_file(request->fl_file, request);
+		do_vfs_lock(request->fl_file, request);
 	up_read(&clp->cl_sem);
 	return status;
 }
@@ -2500,11 +2654,16 @@ static int _nfs4_do_setlk(struct nfs4_st
 	return status;
 }
 
-int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
+static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
 {
 	return _nfs4_do_setlk(state, F_SETLK, request, 1);
 }
 
+static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
+{
+	return _nfs4_do_setlk(state, F_SETLK, request, 0);
+}
+
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
 	struct nfs4_client *clp = state->owner->so_client;
@@ -2517,7 +2676,7 @@ static int _nfs4_proc_setlk(struct nfs4_
 	if (status == 0) {
 		/* Note: we always want to sleep here! */
 		request->fl_flags |= FL_SLEEP;
-		if (posix_lock_file_wait(request->fl_file, request) < 0)
+		if (do_vfs_lock(request->fl_file, request) < 0)
 			printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
 	}
 	up_read(&clp->cl_sem);
@@ -2574,6 +2733,16 @@ nfs4_proc_lock(struct file *filp, int cm
 	return status;
 }
 
+struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
+	.recover_open	= nfs4_open_reclaim,
+	.recover_lock	= nfs4_lock_reclaim,
+};
+
+struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = {
+	.recover_open	= nfs4_open_expired,
+	.recover_lock	= nfs4_lock_expired,
+};
+
 struct nfs_rpc_ops	nfs_v4_clientops = {
 	.version	= 4,			/* protocol version */
 	.dentry_ops	= &nfs4_dentry_operations,
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -116,6 +116,7 @@ nfs4_alloc_client(struct in_addr *addr)
 	INIT_LIST_HEAD(&clp->cl_superblocks);
 	init_waitqueue_head(&clp->cl_waitq);
 	rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
+	clp->cl_boot_time = CURRENT_TIME;
 	clp->cl_state = 1 << NFS4CLNT_OK;
 	return clp;
 }
@@ -205,7 +206,7 @@ nfs4_put_client(struct nfs4_client *clp)
 	nfs4_free_client(clp);
 }
 
-int nfs4_init_client(struct nfs4_client *clp)
+static int __nfs4_init_client(struct nfs4_client *clp)
 {
 	int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport);
 	if (status == 0)
@@ -215,6 +216,11 @@ int nfs4_init_client(struct nfs4_client 
 	return status;
 }
 
+int nfs4_init_client(struct nfs4_client *clp)
+{
+	return nfs4_map_errors(__nfs4_init_client(clp));
+}
+
 u32
 nfs4_alloc_lockowner_id(struct nfs4_client *clp)
 {
@@ -274,8 +280,8 @@ nfs4_alloc_state_owner(void)
 	return sp;
 }
 
-static void
-nfs4_unhash_state_owner(struct nfs4_state_owner *sp)
+void
+nfs4_drop_state_owner(struct nfs4_state_owner *sp)
 {
 	struct nfs4_client *clp = sp->so_client;
 	spin_lock(&clp->cl_lock);
@@ -441,7 +447,9 @@ nfs4_get_open_state(struct inode *inode,
 	if (state == NULL && new != NULL) {
 		state = new;
 		/* Caller *must* be holding owner->so_sem */
-		list_add(&state->open_states, &owner->so_states);
+		/* Note: The reclaim code dictates that we add stateless
+		 * and read-only stateids to the end of the list */
+		list_add_tail(&state->open_states, &owner->so_states);
 		state->owner = owner;
 		atomic_inc(&owner->so_count);
 		list_add(&state->inode_states, &nfsi->open_states);
@@ -497,8 +505,12 @@ void nfs4_close_state(struct nfs4_state 
 		state->nreaders--;
 	if (mode & FMODE_WRITE)
 		state->nwriters--;
-	if (state->nwriters == 0 && state->nreaders == 0)
-		list_del_init(&state->inode_states);
+	if (state->nwriters == 0) {
+		if (state->nreaders == 0)
+			list_del_init(&state->inode_states);
+		/* See reclaim code */
+		list_move_tail(&state->open_states, &owner->so_states);
+	}
 	spin_unlock(&inode->i_lock);
 	newstate = 0;
 	if (state->state != 0) {
@@ -708,7 +720,7 @@ void nfs4_increment_seqid(int status, st
 		sp->so_seqid++;
 	/* If the server returns BAD_SEQID, unhash state_owner here */
 	if (status == -NFS4ERR_BAD_SEQID)
-		nfs4_unhash_state_owner(sp);
+		nfs4_drop_state_owner(sp);
 }
 
 static int reclaimer(void *);
@@ -753,7 +765,7 @@ nfs4_schedule_state_recovery(struct nfs4
 		schedule_work(&clp->cl_recoverd);
 }
 
-static int nfs4_reclaim_locks(struct nfs4_state *state)
+static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state)
 {
 	struct inode *inode = state->inode;
 	struct file_lock *fl;
@@ -764,7 +776,7 @@ static int nfs4_reclaim_locks(struct nfs
 			continue;
 		if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
 			continue;
-		status = nfs4_lock_reclaim(state, fl);
+		status = ops->recover_lock(state, fl);
 		if (status >= 0)
 			continue;
 		switch (status) {
@@ -786,20 +798,28 @@ out_err:
 	return status;
 }
 
-static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
+static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct nfs4_state_owner *sp)
 {
 	struct nfs4_state *state;
 	struct nfs4_lock_state *lock;
 	int status = 0;
 
+	/* Note: we rely on the sp->so_states list being ordered 
+	 * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
+	 * states first.
+	 * This is needed to ensure that the server won't give us any
+	 * read delegations that we have to return if, say, we are
+	 * recovering after a network partition or a reboot from a
+	 * server that doesn't support a grace period.
+	 */
 	list_for_each_entry(state, &sp->so_states, open_states) {
 		if (state->state == 0)
 			continue;
-		status = nfs4_open_reclaim(sp, state);
+		status = ops->recover_open(sp, state);
 		list_for_each_entry(lock, &state->lock_states, ls_locks)
 			lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
 		if (status >= 0) {
-			status = nfs4_reclaim_locks(state);
+			status = nfs4_reclaim_locks(ops, state);
 			if (status < 0)
 				goto out_err;
 			list_for_each_entry(lock, &state->lock_states, ls_locks) {
@@ -813,8 +833,7 @@ static int nfs4_reclaim_open_state(struc
 			default:
 				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
 						__FUNCTION__, status);
-			case -NFS4ERR_EXPIRED:
-			case -NFS4ERR_NO_GRACE:
+			case -ENOENT:
 			case -NFS4ERR_RECLAIM_BAD:
 			case -NFS4ERR_RECLAIM_CONFLICT:
 				/*
@@ -826,6 +845,8 @@ static int nfs4_reclaim_open_state(struc
 				/* Mark the file as being 'closed' */
 				state->state = 0;
 				break;
+			case -NFS4ERR_EXPIRED:
+			case -NFS4ERR_NO_GRACE:
 			case -NFS4ERR_STALE_CLIENTID:
 				goto out_err;
 		}
@@ -840,6 +861,7 @@ static int reclaimer(void *ptr)
 	struct reclaimer_args *args = (struct reclaimer_args *)ptr;
 	struct nfs4_client *clp = args->clp;
 	struct nfs4_state_owner *sp;
+	struct nfs4_state_recovery_ops *ops;
 	int status = 0;
 
 	daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
@@ -856,20 +878,34 @@ static int reclaimer(void *ptr)
 		goto out;
 restart_loop:
 	status = nfs4_proc_renew(clp);
-	if (status == 0 || status == -NFS4ERR_CB_PATH_DOWN)
-		goto out;
-	status = nfs4_init_client(clp);
+	switch (status) {
+		case 0:
+		case -NFS4ERR_CB_PATH_DOWN:
+			goto out;
+		case -NFS4ERR_STALE_CLIENTID:
+		case -NFS4ERR_LEASE_MOVED:
+			ops = &nfs4_reboot_recovery_ops;
+			break;
+		default:
+			ops = &nfs4_network_partition_recovery_ops;
+	};
+	status = __nfs4_init_client(clp);
 	if (status)
 		goto out_error;
-	/* Mark all delagations for reclaim */
+	/* Mark all delegations for reclaim */
 	nfs_delegation_mark_reclaim(clp);
 	/* Note: list is protected by exclusive lock on cl->cl_sem */
 	list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
-		status = nfs4_reclaim_open_state(sp);
+		status = nfs4_reclaim_open_state(ops, sp);
 		if (status < 0) {
+			if (status == -NFS4ERR_NO_GRACE) {
+				ops = &nfs4_network_partition_recovery_ops;
+				status = nfs4_reclaim_open_state(ops, sp);
+			}
 			if (status == -NFS4ERR_STALE_CLIENTID)
 				goto restart_loop;
-			goto out_error;
+			if (status == -NFS4ERR_EXPIRED)
+				goto restart_loop;
 		}
 	}
 	nfs_delegation_reap_unclaimed(clp);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1010,8 +1010,13 @@ static int encode_readdir(struct xdr_str
 	WRITE32(readdir->count >> 1);  /* We're not doing readdirplus */
 	WRITE32(readdir->count);
 	WRITE32(2);
-	WRITE32(FATTR4_WORD0_FILEID);
-	WRITE32(0);
+	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) {
+		WRITE32(0);
+		WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID);
+	} else {
+		WRITE32(FATTR4_WORD0_FILEID);
+		WRITE32(0);
+	}
 
 	/* set up reply kvec
 	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
@@ -3175,7 +3180,7 @@ static int decode_setclientid(struct xdr
 		READ_BUF(4);
 		READ32(len);
 		READ_BUF(len);
-		return -EEXIST;
+		return -NFSERR_CLID_INUSE;
 	} else
 		return -nfs_stat_to_errno(nfserr);
 
@@ -3857,7 +3862,7 @@ static int nfs4_xdr_dec_delegreturn(stru
 
 uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
 {
-	uint32_t bitmap[1] = {0};
+	uint32_t bitmap[2] = {0};
 	uint32_t len;
 
 	if (!*p++) {
@@ -3881,13 +3886,18 @@ uint32_t *nfs4_decode_dirent(uint32_t *p
 	entry->ino = 1;
 
 	len = ntohl(*p++);		/* bitmap length */
-	if (len > 0) {
-		bitmap[0] = ntohl(*p);
-		p += len;
+	if (len-- > 0) {
+		bitmap[0] = ntohl(*p++);
+		if (len-- > 0) {
+			bitmap[1] = ntohl(*p++);
+			p += len;
+		}
 	}
 	len = XDR_QUADLEN(ntohl(*p++));	/* attribute buffer length */
 	if (len > 0) {
-		if (bitmap[0] == FATTR4_WORD0_FILEID)
+		if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
+			xdr_decode_hyper(p, &entry->ino);
+		else if (bitmap[0] == FATTR4_WORD0_FILEID)
 			xdr_decode_hyper(p, &entry->ino);
 		p += len;
 	}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -124,7 +124,6 @@ enum {
 	Opt_soft, Opt_hard, Opt_intr,
 	Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, 
 	Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
-	Opt_broken_suid,
 	/* Error token */
 	Opt_err
 };
@@ -159,7 +158,6 @@ static match_table_t __initdata tokens =
 	{Opt_udp, "udp"},
 	{Opt_tcp, "proto=tcp"},
 	{Opt_tcp, "tcp"},
-	{Opt_broken_suid, "broken_suid"},
 	{Opt_err, NULL}
 	
 };
@@ -268,9 +266,6 @@ static int __init root_nfs_parse(char *n
 			case Opt_tcp:
 				nfs_data.flags |= NFS_MOUNT_TCP;
 				break;
-			case Opt_broken_suid:
-				nfs_data.flags |= NFS_MOUNT_BROKEN_SUID;
-				break;
 			default : 
 				return 0;
 		}
@@ -351,7 +346,7 @@ static void __init root_nfs_print(void)
 #endif
 
 
-int __init root_nfs_init(void)
+static int __init root_nfs_init(void)
 {
 #ifdef NFSROOT_DEBUG
 	nfs_debug |= NFSDBG_ROOT;
@@ -379,15 +374,15 @@ int __init root_nfs_init(void)
  *  Parse NFS server and directory information passed on the kernel
  *  command line.
  */
-int __init nfs_root_setup(char *line)
+static int __init nfs_root_setup(char *line)
 {
 	ROOT_DEV = Root_NFS;
 	if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
 		strlcpy(nfs_root_name, line, sizeof(nfs_root_name));
 	} else {
-		int n = strlen(line) + strlen(NFS_ROOT);
+		int n = strlen(line) + sizeof(NFS_ROOT) - 1;
 		if (n >= sizeof(nfs_root_name))
-			line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
+			line[sizeof(nfs_root_name) - sizeof(NFS_ROOT) - 2] = '\0';
 		sprintf(nfs_root_name, NFS_ROOT, line);
 	}
 	root_server_addr = root_nfs_parse_addr(nfs_root_name);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -212,7 +212,7 @@ static int nfs_proc_write(struct nfs_wri
 	return status < 0? status : wdata->res.count;
 }
 
-static struct inode *
+static int
 nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		int flags)
 {
@@ -233,37 +233,34 @@ nfs_proc_create(struct inode *dir, struc
 	fattr.valid = 0;
 	dprintk("NFS call  create %s\n", dentry->d_name.name);
 	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	dprintk("NFS reply create: %d\n", status);
-	if (status == 0) {
-		struct inode *inode;
-		inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
-		if (inode)
-			return inode;
-		status = -ENOMEM;
-	}
-	return ERR_PTR(status);
+	return status;
 }
 
 /*
  * In NFSv2, mknod is grafted onto the create call.
  */
 static int
-nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
-	       dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+	       dev_t rdev)
 {
+	struct nfs_fh fhandle;
+	struct nfs_fattr fattr;
 	struct nfs_createargs	arg = {
 		.fh		= NFS_FH(dir),
-		.name		= name->name,
-		.len		= name->len,
+		.name		= dentry->d_name.name,
+		.len		= dentry->d_name.len,
 		.sattr		= sattr
 	};
 	struct nfs_diropok	res = {
-		.fh		= fhandle,
-		.fattr		= fattr
+		.fh		= &fhandle,
+		.fattr		= &fattr
 	};
-	int			status, mode;
+	int status, mode;
 
-	dprintk("NFS call  mknod %s\n", name->name);
+	dprintk("NFS call  mknod %s\n", dentry->d_name.name);
 
 	mode = sattr->ia_mode;
 	if (S_ISFIFO(mode)) {
@@ -274,14 +271,16 @@ nfs_proc_mknod(struct inode *dir, struct
 		sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */
 	}
 
-	fattr->valid = 0;
+	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 
 	if (status == -EINVAL && S_ISFIFO(mode)) {
 		sattr->ia_mode = mode;
-		fattr->valid = 0;
+		fattr.valid = 0;
 		status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 	}
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
@@ -398,24 +397,27 @@ nfs_proc_symlink(struct inode *dir, stru
 }
 
 static int
-nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
-	       struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 {
+	struct nfs_fh fhandle;
+	struct nfs_fattr fattr;
 	struct nfs_createargs	arg = {
 		.fh		= NFS_FH(dir),
-		.name		= name->name,
-		.len		= name->len,
+		.name		= dentry->d_name.name,
+		.len		= dentry->d_name.len,
 		.sattr		= sattr
 	};
 	struct nfs_diropok	res = {
-		.fh		= fhandle,
-		.fattr		= fattr
+		.fh		= &fhandle,
+		.fattr		= &fattr
 	};
 	int			status;
 
-	dprintk("NFS call  mkdir %s\n", name->name);
-	fattr->valid = 0;
+	dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
+	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0);
+	if (status == 0)
+		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -370,7 +370,7 @@ out_bad:
 	return -ENOMEM;
 }
 
-int
+static int
 nfs_pagein_list(struct list_head *head, int rpages)
 {
 	LIST_HEAD(one_request);
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -167,6 +167,11 @@ nfs_async_unlink(struct dentry *dentry)
 		goto out;
 	memset(data, 0, sizeof(*data));
 
+	data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+	if (IS_ERR(data->cred)) {
+		status = PTR_ERR(data->cred);
+		goto out_free;
+	}
 	data->dir = dget(dir);
 	data->dentry = dentry;
 
@@ -183,12 +188,14 @@ nfs_async_unlink(struct dentry *dentry)
 	spin_lock(&dentry->d_lock);
 	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
 	spin_unlock(&dentry->d_lock);
-	data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
 
 	rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL);
 	status = 0;
  out:
 	return status;
+out_free:
+	kfree(data);
+	return status;
 }
 
 /**
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -80,14 +80,31 @@ static void nfs_writeback_done_partial(s
 static void nfs_writeback_done_full(struct nfs_write_data *, int);
 static int nfs_wait_on_write_congestion(struct address_space *, int);
 static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int);
+static int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
+			   unsigned int npages, int how);
 
 static kmem_cache_t *nfs_wdata_cachep;
 mempool_t *nfs_wdata_mempool;
-mempool_t *nfs_commit_mempool;
+static mempool_t *nfs_commit_mempool;
 
 static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
 
-void nfs_writedata_release(struct rpc_task *task)
+static inline struct nfs_write_data *nfs_commit_alloc(void)
+{
+	struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		INIT_LIST_HEAD(&p->pages);
+	}
+	return p;
+}
+
+static inline void nfs_commit_free(struct nfs_write_data *p)
+{
+	mempool_free(p, nfs_commit_mempool);
+}
+
+static void nfs_writedata_release(struct rpc_task *task)
 {
 	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
 	nfs_writedata_free(wdata);
@@ -990,7 +1007,7 @@ static int nfs_flush_one(struct list_hea
 	return -ENOMEM;
 }
 
-int
+static int
 nfs_flush_list(struct list_head *head, int wpages, int how)
 {
 	LIST_HEAD(one_request);
@@ -1240,7 +1257,7 @@ static void nfs_commit_rpcsetup(struct l
 /*
  * Commit dirty pages
  */
-int
+static int
 nfs_commit_list(struct list_head *head, int how)
 {
 	struct nfs_write_data	*data;
@@ -1314,8 +1331,8 @@ nfs_commit_done(struct rpc_task *task)
 }
 #endif
 
-int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
-		   unsigned int npages, int how)
+static int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
+			   unsigned int npages, int how)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	LIST_HEAD(head);
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -79,9 +79,9 @@ void expkey_put(struct cache_head *item,
 	}
 }
 
-void expkey_request(struct cache_detail *cd,
-		    struct cache_head *h,
-		    char **bpp, int *blen)
+static void expkey_request(struct cache_detail *cd,
+			   struct cache_head *h,
+			   char **bpp, int *blen)
 {
 	/* client fsidtype \xfsid */
 	struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
@@ -95,7 +95,7 @@ void expkey_request(struct cache_detail 
 }
 
 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
-int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
+static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
 {
 	/* client fsidtype fsid [path] */
 	char *buf;
@@ -284,9 +284,9 @@ void svc_export_put(struct cache_head *i
 	}
 }
 
-void svc_export_request(struct cache_detail *cd,
-			struct cache_head *h,
-			char **bpp, int *blen)
+static void svc_export_request(struct cache_detail *cd,
+			       struct cache_head *h,
+			       char **bpp, int *blen)
 {
 	/*  client path */
 	struct svc_export *exp = container_of(h, struct svc_export, h);
@@ -340,7 +340,7 @@ static int check_export(struct inode *in
 
 }
 
-int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
+static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
 {
 	/* client path expiry [flags anonuid anongid fsid] */
 	char *buf;
@@ -510,8 +510,8 @@ exp_find_key(svc_client *clp, int fsid_t
 	return ek;
 }
 
-int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, 
-		struct svc_export *exp)
+static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
+		       struct svc_export *exp)
 {
 	struct svc_expkey key, *ek;
 
@@ -999,7 +999,7 @@ static void e_stop(struct seq_file *m, v
 	exp_readunlock();
 }
 
-struct flags {
+static struct flags {
 	int flag;
 	char *name[2];
 } expflags[] = {
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -60,7 +60,7 @@ nlm_fclose(struct file *filp)
 	fput(filp);
 }
 
-struct nlmsvc_binding		nfsd_nlm_ops = {
+static struct nlmsvc_binding	nfsd_nlm_ops = {
 	.fopen		= nlm_fopen,		/* open file for locking */
 	.fclose		= nlm_fclose,		/* close file */
 };
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -171,7 +171,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, 
 	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
 	fh_copy(&resp->fh, &argp->fh);
-	nfserr = nfsd_read(rqstp, &resp->fh,
+	nfserr = nfsd_read(rqstp, &resp->fh, NULL,
 				  argp->offset,
 			   	  argp->vec, argp->vlen,
 				  &resp->count);
@@ -201,7 +201,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp,
 
 	fh_copy(&resp->fh, &argp->fh);
 	resp->committed = argp->stable;
-	nfserr = nfsd_write(rqstp, &resp->fh,
+	nfserr = nfsd_write(rqstp, &resp->fh, NULL,
 				   argp->offset,
 				   argp->vec, argp->vlen,
 				   argp->len,
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -801,6 +801,11 @@ compose_entry_fh(struct nfsd3_readdirres
 	if (isdotent(name, namlen)) {
 		if (namlen == 2) {
 			dchild = dget_parent(dparent);
+			if (dchild == dparent) {
+				/* filesystem root - cannot return filehandle for ".." */
+				dput(dchild);
+				return 1;
+			}
 		} else
 			dchild = dget(dparent);
 	} else
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -49,12 +49,16 @@
 
 
 /* mode bit translations: */
-#define NFS4_READ_MODE (NFS4_ACE_READ_DATA | NFS4_ACE_READ_NAMED_ATTRS)
-#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_WRITE_NAMED_ATTRS | NFS4_ACE_APPEND_DATA)
+#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
+#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
 #define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
 #define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
 #define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
 
+/* We don't support these bits; insist they be neither allowed nor denied */
+#define NFS4_MASK_UNSUPP (NFS4_ACE_DELETE | NFS4_ACE_WRITE_OWNER \
+		| NFS4_ACE_READ_NAMED_ATTRS | NFS4_ACE_WRITE_NAMED_ATTRS)
+
 /* flags used to simulate posix default ACLs */
 #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
 		| NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
@@ -83,12 +87,15 @@ mask_from_posix(unsigned short perm, uns
 static u32
 deny_mask(u32 allow_mask, unsigned int flags)
 {
-	u32 ret = ~allow_mask & ~NFS4_ACE_DELETE;
+	u32 ret = ~allow_mask & ~NFS4_MASK_UNSUPP;
 	if (!(flags & NFS4_ACL_DIR))
 		ret &= ~NFS4_ACE_DELETE_CHILD;
 	return ret;
 }
 
+/* XXX: modify functions to return NFS errors; they're only ever
+ * used by nfs code, after all.... */
+
 static int
 mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
 {
@@ -940,35 +947,8 @@ match_who(struct nfs4_ace *ace, uid_t ow
 	}
 }
 
-/* 0 = granted, -EACCES = denied; mask is an nfsv4 mask, not mode bits */
-int
-nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
-			uid_t who, u32 mask)
-{
-	struct nfs4_ace *ace;
-	u32 allowed = 0;
-
-	list_for_each_entry(ace, &acl->ace_head, l_ace) {
-		if (!match_who(ace, group, owner, who))
-			continue;
-		switch (ace->type) {
-			case NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE:
-				allowed |= ace->access_mask;
-				if ((allowed & mask) == mask)
-					return 0;
-				break;
-			case NFS4_ACE_ACCESS_DENIED_ACE_TYPE:
-				if (ace->access_mask & mask)
-					return -EACCES;
-				break;
-		}
-	}
-	return -EACCES;
-}
-
 EXPORT_SYMBOL(nfs4_acl_new);
 EXPORT_SYMBOL(nfs4_acl_free);
 EXPORT_SYMBOL(nfs4_acl_add_ace);
 EXPORT_SYMBOL(nfs4_acl_get_whotype);
 EXPORT_SYMBOL(nfs4_acl_write_who);
-EXPORT_SYMBOL(nfs4_acl_permission);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -38,6 +38,7 @@
 #include <linux/list.h>
 #include <linux/inet.h>
 #include <linux/errno.h>
+#include <linux/delay.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
@@ -246,6 +247,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *
 {
 	struct xdr_stream xdr;
 	struct nfs4_cb_compound_hdr hdr = {
+		.ident = args->cbr_ident,
 		.nops   = 1,
 	};
 
@@ -308,7 +310,7 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *
 	if (status)
 		goto out;
 	status = decode_cb_op_hdr(&xdr, OP_CB_RECALL);
-out	:
+out:
 	return status;
 }
 
@@ -351,10 +353,8 @@ nfsd4_lookupcred(struct nfs4_client *clp
 {
         struct auth_cred acred;
 	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
-        struct rpc_cred *ret = NULL;
+	struct rpc_cred *ret;
 
-	if (!clnt)
-		goto out;
         get_group_info(clp->cl_cred.cr_group_info);
         acred.uid = clp->cl_cred.cr_uid;
         acred.gid = clp->cl_cred.cr_gid;
@@ -364,7 +364,6 @@ nfsd4_lookupcred(struct nfs4_client *clp
                 clnt->cl_auth->au_ops->au_name);
         ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags);
         put_group_info(clp->cl_cred.cr_group_info);
-out:
         return ret;
 }
 
@@ -401,12 +400,13 @@ nfsd4_probe_callback(struct nfs4_client 
 
 	/* Initialize timeout */
 	timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ;
-	timeparms.to_retries = 5;
+	timeparms.to_retries = 0;
 	timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ;
 	timeparms.to_exponential = 1;
 
 	/* Create RPC transport */
-	if (!(xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms))) {
+	xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms);
+	if (IS_ERR(xprt)) {
 		dprintk("NFSD: couldn't create callback transport!\n");
 		goto out_err;
 	}
@@ -427,14 +427,14 @@ nfsd4_probe_callback(struct nfs4_client 
 	 * XXX AUTH_UNIX only - need AUTH_GSS....
 	 */
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
-	if (!(clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX))) {
+	clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
+	if (IS_ERR(clnt)) {
 		dprintk("NFSD: couldn't create callback client\n");
 		goto out_xprt;
 	}
-	clnt->cl_intr = 1;
+	clnt->cl_intr = 0;
 	clnt->cl_softrtry = 1;
 	clnt->cl_chatty = 1;
-	cb->cb_client = clnt;
 
 	/* Kick rpciod, put the call on the wire. */
 
@@ -444,10 +444,14 @@ nfsd4_probe_callback(struct nfs4_client 
 	}
 
 	/* the task holds a reference to the nfs4_client struct */
+	cb->cb_client = clnt;
 	atomic_inc(&clp->cl_count);
 
 	msg.rpc_cred = nfsd4_lookupcred(clp,0);
+	if (IS_ERR(msg.rpc_cred))
+		goto out_rpciod;
 	status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL);
+	put_rpccred(msg.rpc_cred);
 
 	if (status != 0) {
 		dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
@@ -456,6 +460,7 @@ nfsd4_probe_callback(struct nfs4_client 
 	return;
 
 out_rpciod:
+	atomic_dec(&clp->cl_count);
 	rpciod_down();
 out_clnt:
 	rpc_shutdown_client(clnt);
@@ -489,95 +494,56 @@ out:
 }
 
 /*
- *  Called with dp->dl_count incremented
- */
-static void
-nfs4_cb_recall_done(struct rpc_task *task)
-{
-	struct nfs4_cb_recall *cbr = (struct nfs4_cb_recall *)task->tk_calldata;
-	struct nfs4_delegation *dp = cbr->cbr_dp;
-	int status;
-
-	/* all is well... */
-	if (task->tk_status == 0)
-		goto out;
-
-	/* network partition, retry nfsd4_cb_recall once.  */
-	if (task->tk_status == -EIO) {
-		if (atomic_read(&dp->dl_recall_cnt) == 0)
-			goto retry;
-		else
-			/* callback channel no longer available */
-			atomic_set(&dp->dl_client->cl_callback.cb_set, 0);
-	}
-
-	/* Race: a recall occurred miliseconds after a delegation was granted.
-	* Client may have received recall prior to delegation. retry recall
-	* once.
-	*/
-	if ((task->tk_status == -EBADHANDLE) || (task->tk_status == -NFS4ERR_BAD_STATEID)){
-		if (atomic_read(&dp->dl_recall_cnt) == 0)
-			goto retry;
-	}
-	atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE);
-
-out:
-	if (atomic_dec_and_test(&dp->dl_count))
-		atomic_set(&dp->dl_state, NFS4_REAP_DELEG);
-	BUG_ON(atomic_read(&dp->dl_count) < 0);
-	dprintk("NFSD: nfs4_cb_recall_done: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
-	return;
-
-retry:
-	atomic_inc(&dp->dl_recall_cnt);
-	/* sleep 2 seconds before retrying recall */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(2*HZ);
-	status = nfsd4_cb_recall(dp);
-	dprintk("NFSD: nfs4_cb_recall_done: retry status: %d  dp %p dl_flock %p\n",status,dp, dp->dl_flock);
-}
-
-/*
  * called with dp->dl_count inc'ed.
  * nfs4_lock_state() may or may not have been called.
  */
-int
+void
 nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
-	struct nfs4_client *clp;
-	struct rpc_clnt *clnt;
+	struct nfs4_client *clp = dp->dl_client;
+	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+	struct nfs4_cb_recall *cbr = &dp->dl_recall;
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
+		.rpc_argp = cbr,
 	};
-	struct nfs4_cb_recall *cbr = &dp->dl_recall;
-	int status;
+	int retries = 1;
+	int status = 0;
 
-	dprintk("NFSD: nfsd4_cb_recall NFS4_enc_cb_recall_sz %d NFS4_dec_cb_recall_sz %d \n",NFS4_enc_cb_recall_sz,NFS4_dec_cb_recall_sz);
-
-	clp = dp->dl_client;
-	clnt = clp->cl_callback.cb_client;
-	status = EIO;
 	if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
-		goto out_free;
+		return;
 
-	msg.rpc_argp = cbr;
-	msg.rpc_resp = cbr;
-	msg.rpc_cred = nfsd4_lookupcred(clp,0);
+	msg.rpc_cred = nfsd4_lookupcred(clp, 0);
+	if (IS_ERR(msg.rpc_cred))
+		goto out;
 
 	cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
 	cbr->cbr_dp = dp;
 
-	if ((status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
-		nfs4_cb_recall_done, cbr ))) {
-		dprintk("NFSD: recall_delegation: rpc_call_async failed %d\n",
-			status);
-		goto out_fail;
+	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+	while (retries--) {
+		switch (status) {
+			case -EIO:
+				/* Network partition? */
+			case -EBADHANDLE:
+			case -NFS4ERR_BAD_STATEID:
+				/* Race: client probably got cb_recall
+				 * before open reply granting delegation */
+				break;
+			default:
+				goto out_put_cred;
+		}
+		ssleep(2);
+		status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
 	}
+out_put_cred:
+	put_rpccred(msg.rpc_cred);
 out:
-	return status;
-out_fail:
-	status = nfserrno(status);
-	out_free:
-	kfree(cbr);
-	goto out;
+	if (status == -EIO)
+		atomic_set(&clp->cl_callback.cb_set, 0);
+	/* Success or failure, now we're either waiting for lease expiration
+	 * or deleg_return. */
+	dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+	nfs4_put_delegation(dp);
+	return;
 }
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -117,7 +117,6 @@ do_open_lookup(struct svc_rqst *rqstp, s
 
 		/* set reply cache */
 		fh_dup2(current_fh, &resfh);
-		/* XXXJBF: keep a saved svc_fh struct instead?? */
 		open->op_stateowner->so_replay.rp_openfh_len =
 			resfh.fh_handle.fh_size;
 		memcpy(open->op_stateowner->so_replay.rp_openfh,
@@ -153,7 +152,7 @@ do_open_fhandle(struct svc_rqst *rqstp, 
 		current_fh->fh_handle.fh_size);
 
 	open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
-	!open->op_iattr.ia_size;
+		(open->op_iattr.ia_size == 0);
 
 	status = do_open_permission(rqstp, current_fh, open);
 
@@ -198,30 +197,40 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	}
 	if (status)
 		goto out;
-	if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) {
-	/*
-	 * This block of code will (1) set CURRENT_FH to the file being opened,
-	 * creating it if necessary, (2) set open->op_cinfo, 
-	 * (3) set open->op_truncate if the file is to be truncated 
-	 * after opening, (4) do permission checking.
-	 */
-		status = do_open_lookup(rqstp, current_fh, open);
-		if (status)
+	switch (open->op_claim_type) {
+		case NFS4_OPEN_CLAIM_NULL:
+			/*
+			 * (1) set CURRENT_FH to the file being opened,
+			 * creating it if necessary, (2) set open->op_cinfo,
+			 * (3) set open->op_truncate if the file is to be
+			 * truncated after opening, (4) do permission checking.
+			 */
+			status = do_open_lookup(rqstp, current_fh, open);
+			if (status)
+				goto out;
+			break;
+		case NFS4_OPEN_CLAIM_PREVIOUS:
+			/*
+			 * The CURRENT_FH is already set to the file being
+			 * opened.  (1) set open->op_cinfo, (2) set
+			 * open->op_truncate if the file is to be truncated
+			 * after opening, (3) do permission checking.
+			*/
+			status = do_open_fhandle(rqstp, current_fh, open);
+			if (status)
+				goto out;
+			break;
+		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+             	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+			printk("NFSD: unsupported OPEN claim type %d\n",
+				open->op_claim_type);
+			status = nfserr_notsupp;
 			goto out;
-	} else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
-	/*
-	* The CURRENT_FH is already set to the file being opened. This
-	* block of code will (1) set open->op_cinfo, (2) set
-	* open->op_truncate if the file is to be truncated after opening,
-	* (3) do permission checking.
-	*/
-		status = do_open_fhandle(rqstp, current_fh, open);
-		if (status)
+		default:
+			printk("NFSD: Invalid OPEN claim type %d\n",
+				open->op_claim_type);
+			status = nfserr_inval;
 			goto out;
-	} else {
-		printk("NFSD: unsupported OPEN claim type\n");
-		status = nfserr_inval;
-		goto out;
 	}
 	/*
 	 * nfsd4_process_open2() does the actual opening of the file.  If
@@ -464,37 +473,17 @@ static inline int
 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
 {
 	int status;
+	struct file *filp = NULL;
 
 	/* no need to check permission - this will be done in nfsd_read() */
-	if (nfs4_in_grace())
-		return nfserr_grace;
 
 	if (read->rd_offset >= OFFSET_MAX)
 		return nfserr_inval;
 
 	nfs4_lock_state();
-	status = nfs_ok;
-	/* For stateid -1, we don't check share reservations.  */
-	if (ONE_STATEID(&read->rd_stateid)) {
-		dprintk("NFSD: nfsd4_read: -1 stateid...\n");
-		goto out;
-	}
-	/*
-	* For stateid 0, the client doesn't have to have the file open, but
-	* we still check for share reservation conflicts. 
-	*/
-	if (ZERO_STATEID(&read->rd_stateid)) {
-		dprintk("NFSD: nfsd4_read: zero stateid...\n");
-		if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_READ))) {
-			dprintk("NFSD: nfsd4_read: conflicting share reservation!\n");
-			goto out;
-		}
-		status = nfs_ok;
-		goto out;
-	}
 	/* check stateid */
-	if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, 
-					CHECK_FH | RD_STATE))) {
+	if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
+					CHECK_FH | RD_STATE, &filp))) {
 		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
 		goto out;
 	}
@@ -503,6 +492,7 @@ out:
 	nfs4_unlock_state();
 	read->rd_rqstp = rqstp;
 	read->rd_fhp = current_fh;
+	read->rd_filp = filp;
 	return status;
 }
 
@@ -587,25 +577,15 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
 {
 	int status = nfs_ok;
 
-	if (nfs4_in_grace())
-		return nfserr_grace;
-
 	if (!current_fh->fh_dentry)
 		return nfserr_nofilehandle;
 
 	status = nfs_ok;
 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
-
-		status = nfserr_bad_stateid;
-		if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) {
-			dprintk("NFSD: nfsd4_setattr: magic stateid!\n");
-			goto out;
-		}
-
 		nfs4_lock_state();
-		if ((status = nfs4_preprocess_stateid_op(current_fh, 
-						&setattr->sa_stateid, 
-						CHECK_FH | WR_STATE))) {
+		if ((status = nfs4_preprocess_stateid_op(current_fh,
+						&setattr->sa_stateid,
+						CHECK_FH | WR_STATE, NULL))) {
 			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
 			goto out_unlock;
 		}
@@ -629,44 +609,33 @@ static inline int
 nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
 {
 	stateid_t *stateid = &write->wr_stateid;
+	struct file *filp = NULL;
 	u32 *p;
 	int status = nfs_ok;
 
-	if (nfs4_in_grace())
-		return nfserr_grace;
-
 	/* no need to check permission - this will be done in nfsd_write() */
 
 	if (write->wr_offset >= OFFSET_MAX)
 		return nfserr_inval;
 
 	nfs4_lock_state();
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
-		dprintk("NFSD: nfsd4_write: zero stateid...\n");
-		if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_WRITE))) {
-			dprintk("NFSD: nfsd4_write: conflicting share reservation!\n");
-			goto out;
-		}
-		goto zero_stateid;
-	}
-	if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, 
-					CHECK_FH | WR_STATE))) {
+	if ((status = nfs4_preprocess_stateid_op(current_fh, stateid,
+					CHECK_FH | WR_STATE, &filp))) {
 		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
 		goto out;
 	}
-
-zero_stateid:
-
 	nfs4_unlock_state();
+
 	write->wr_bytes_written = write->wr_buflen;
 	write->wr_how_written = write->wr_stable_how;
 	p = (u32 *)write->wr_verifier.data;
 	*p++ = nfssvc_boot.tv_sec;
 	*p++ = nfssvc_boot.tv_usec;
 
-	status =  nfsd_write(rqstp, current_fh, write->wr_offset,
-			  write->wr_vec, write->wr_vlen, write->wr_buflen,
-			  &write->wr_how_written);
+	status =  nfsd_write(rqstp, current_fh, filp, write->wr_offset,
+			write->wr_vec, write->wr_vlen, write->wr_buflen,
+			&write->wr_how_written);
+
 	if (status == nfserr_symlink)
 		status = nfserr_inval;
 	return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -72,19 +72,15 @@ u32 add_perclient = 0;
 u32 del_perclient = 0;
 u32 alloc_file = 0;
 u32 free_file = 0;
-u32 alloc_sowner = 0;
-u32 free_sowner = 0;
 u32 vfsopen = 0;
 u32 vfsclose = 0;
-u32 alloc_lsowner= 0;
 u32 alloc_delegation= 0;
 u32 free_delegation= 0;
 
 /* forward declarations */
 struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
-static void release_delegation(struct nfs4_delegation *dp);
-static void release_stateid_lockowner(struct nfs4_stateid *open_stp);
+static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
 
 /* Locking:
  *
@@ -133,9 +129,11 @@ spinlock_t recall_lock;
 static struct list_head del_recall_lru;
 
 static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, struct svc_fh *current_fh, u32 type)
+alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
 	struct nfs4_delegation *dp;
+	struct nfs4_file *fp = stp->st_file;
+	struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 
 	dprintk("NFSD alloc_init_deleg\n");
 	if ((dp = kmalloc(sizeof(struct nfs4_delegation),
@@ -147,10 +145,11 @@ alloc_init_deleg(struct nfs4_client *clp
 	dp->dl_client = clp;
 	dp->dl_file = fp;
 	dp->dl_flock = NULL;
-	dp->dl_stp = NULL;
+	get_file(stp->st_vfs_file);
+	dp->dl_vfs_file = stp->st_vfs_file;
 	dp->dl_type = type;
 	dp->dl_recall.cbr_dp = NULL;
-	dp->dl_recall.cbr_ident = 0;
+	dp->dl_recall.cbr_ident = cb->cb_ident;
 	dp->dl_recall.cbr_trunc = 0;
 	dp->dl_stateid.si_boot = boot_time;
 	dp->dl_stateid.si_stateownerid = current_delegid++;
@@ -160,74 +159,54 @@ alloc_init_deleg(struct nfs4_client *clp
 	memcpy(dp->dl_fhval, &current_fh->fh_handle.fh_base,
 		        current_fh->fh_handle.fh_size);
 	dp->dl_time = 0;
-	atomic_set(&dp->dl_state, NFS4_NO_RECALL);
 	atomic_set(&dp->dl_count, 1);
-	atomic_set(&dp->dl_recall_cnt, 0);
 	list_add(&dp->dl_del_perfile, &fp->fi_del_perfile);
 	list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
 	alloc_delegation++;
 	return dp;
 }
 
-/*
- * Free the delegation structure.
- * Called with the recall_lock held.
- */
-static void
-nfs4_free_delegation(struct nfs4_delegation *dp)
+void
+nfs4_put_delegation(struct nfs4_delegation *dp)
 {
-	dprintk("NFSD: nfs4_free_delegation freeing dp %p\n",dp);
-	list_del(&dp->dl_recall_lru);
-	kfree(dp);
-	free_delegation++;
+	if (atomic_dec_and_test(&dp->dl_count)) {
+		dprintk("NFSD: freeing dp %p\n",dp);
+		kfree(dp);
+		free_delegation++;
+	}
 }
 
-/* release_delegation:
- *
- * Remove the associated file_lock first, then remove the delegation.
+/* Remove the associated file_lock first, then remove the delegation.
  * lease_modify() is called to remove the FS_LEASE file_lock from
  * the i_flock list, eventually calling nfsd's lock_manager
  * fl_release_callback.
- *
- * call either:
- *   nfsd_close : if last close, locks_remove_flock calls lease_modify.
- *                otherwise, recalled state set to NFS4_RECALL_COMPLETE
- *                so that it will be reaped by the laundromat service.
- * or
- *   remove_lease (calls time_out_lease which calls lease_modify).
- *   and nfs4_free_delegation.
- *
- * Called with nfs_lock_state() held.
- * Called with the recall_lock held.
  */
+static void
+nfs4_close_delegation(struct nfs4_delegation *dp)
+{
+	struct file *filp = dp->dl_vfs_file;
 
+	dprintk("NFSD: close_delegation dp %p\n",dp);
+	dp->dl_vfs_file = NULL;
+	/* The following nfsd_close may not actually close the file,
+	 * but we want to remove the lease in any case. */
+	if (dp->dl_flock)
+		setlease(filp, F_UNLCK, &dp->dl_flock);
+	nfsd_close(filp);
+	vfsclose++;
+}
+
+/* Called under the state lock. */
 static void
-release_delegation(struct nfs4_delegation *dp)
-{
-	/* delayed nfsd_close */
-	if (dp->dl_stp) {
-		struct file *filp = dp->dl_stp->st_vfs_file;
-
-		dprintk("NFSD: release_delegation CLOSE\n");
-		release_stateid_lockowner(dp->dl_stp);
-		kfree(dp->dl_stp);
-		dp->dl_stp = NULL;
-		atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE);
-		nfsd_close(filp);
-		vfsclose++;
-	} else {
-		dprintk("NFSD: release_delegation remove lease dl_flock %p\n",
-			dp->dl_flock);
-		remove_lease(dp->dl_flock);
-		list_del_init(&dp->dl_del_perfile);
-		list_del_init(&dp->dl_del_perclnt);
-		/* dl_count > 0 => outstanding recall rpc */
-		dprintk("NFSD: release_delegation free deleg dl_count %d\n",
-			           atomic_read(&dp->dl_count));
-		if ((atomic_read(&dp->dl_state) == NFS4_REAP_DELEG)
-		     || atomic_dec_and_test(&dp->dl_count))
-			nfs4_free_delegation(dp);
-	}
+unhash_delegation(struct nfs4_delegation *dp)
+{
+	list_del_init(&dp->dl_del_perfile);
+	list_del_init(&dp->dl_del_perclnt);
+	spin_lock(&recall_lock);
+	list_del_init(&dp->dl_recall_lru);
+	spin_unlock(&recall_lock);
+	nfs4_close_delegation(dp);
+	nfs4_put_delegation(dp);
 }
 
 /* 
@@ -260,7 +239,7 @@ release_delegation(struct nfs4_delegatio
  * for last close replay.
  */
 static struct list_head	reclaim_str_hashtbl[CLIENT_HASH_SIZE];
-static int reclaim_str_hashtbl_size;
+static int reclaim_str_hashtbl_size = 0;
 static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
@@ -339,6 +318,7 @@ expire_client(struct nfs4_client *clp)
 	struct nfs4_delegation *dp;
 	struct nfs4_callback *cb = &clp->cl_callback;
 	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+	struct list_head reaplist;
 
 	dprintk("NFSD: expire_client cl_count %d\n",
 	                    atomic_read(&clp->cl_count));
@@ -348,17 +328,22 @@ expire_client(struct nfs4_client *clp)
 		rpc_shutdown_client(clnt);
 		clnt = clp->cl_callback.cb_client = NULL;
 	}
+
+	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&recall_lock);
 	while (!list_empty(&clp->cl_del_perclnt)) {
 		dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt);
-		dprintk("NFSD: expire client. dp %p, dl_state %d, fp %p\n",
-				dp, atomic_read(&dp->dl_state), dp->dl_flock);
-
-		/* force release of delegation. */
-		atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE);
-		release_delegation(dp);
+		dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
+				dp->dl_flock);
+		list_del_init(&dp->dl_del_perclnt);
+		list_move(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&recall_lock);
+	while (!list_empty(&reaplist)) {
+		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
+		unhash_delegation(dp);
+	}
 	list_del(&clp->cl_idhash);
 	list_del(&clp->cl_strhash);
 	list_del(&clp->cl_lru);
@@ -474,8 +459,9 @@ add_to_unconfirmed(struct nfs4_client *c
 }
 
 void
-move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval)
+move_to_confirmed(struct nfs4_client *clp)
 {
+	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
 	unsigned int strhashval;
 
 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
@@ -488,6 +474,31 @@ move_to_confirmed(struct nfs4_client *cl
 	renew_client(clp);
 }
 
+static struct nfs4_client *
+find_confirmed_client(clientid_t *clid)
+{
+	struct nfs4_client *clp;
+	unsigned int idhashval = clientid_hashval(clid->cl_id);
+
+	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
+		if (cmp_clid(&clp->cl_clientid, clid))
+			return clp;
+	}
+	return NULL;
+}
+
+static struct nfs4_client *
+find_unconfirmed_client(clientid_t *clid)
+{
+	struct nfs4_client *clp;
+	unsigned int idhashval = clientid_hashval(clid->cl_id);
+
+	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
+		if (cmp_clid(&clp->cl_clientid, clid))
+			return clp;
+	}
+	return NULL;
+}
 
 /* a helper function for parse_callback */
 static int
@@ -796,7 +807,6 @@ int
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
 {
 	u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
-	unsigned int idhashval;
 	struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
 	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
 	clientid_t * clid = &setclientid_confirm->sc_clientid;
@@ -809,12 +819,9 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	 * We get here on a DRC miss.
 	 */
 
-	idhashval = clientid_hashval(clid->cl_id);
 	nfs4_lock_state();
-	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-		if (!cmp_clid(&clp->cl_clientid, clid))
-			continue;
-
+	clp = find_confirmed_client(clid);
+	if (clp) {
 		status = nfserr_inval;
 		/* 
 		 * Found a record for this clientid. If the IP addresses
@@ -828,11 +835,9 @@ nfsd4_setclientid_confirm(struct svc_rqs
 			goto out;
 		}
 		conf = clp;
-		break;
 	}
-	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
-		if (!cmp_clid(&clp->cl_clientid, clid))
-			continue;
+	clp = find_unconfirmed_client(clid);
+	if (clp) {
 		status = nfserr_inval;
 		if (clp->cl_addr != ip_addr) { 
 			printk("NFSD: setclientid: string in use by client"
@@ -841,7 +846,6 @@ nfsd4_setclientid_confirm(struct svc_rqs
 			goto out;
 		}
 		unconf = clp;
-		break;
 	}
 	/* CASE 1: 
 	* unconf record that matches input clientid and input confirm.
@@ -858,7 +862,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 		else {
 			expire_client(conf);
 			clp = unconf;
-			move_to_confirmed(unconf, idhashval);
+			move_to_confirmed(unconf);
 			status = nfs_ok;
 		}
 		goto out;
@@ -891,7 +895,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 		} else {
 			status = nfs_ok;
 			clp = unconf;
-			move_to_confirmed(unconf, idhashval);
+			move_to_confirmed(unconf);
 		}
 		goto out;
 	}
@@ -952,8 +956,11 @@ static struct list_head stateid_hashtbl[
 
 /* OPEN Share state helper functions */
 static inline struct nfs4_file *
-alloc_init_file(unsigned int hashval, struct inode *ino) {
+alloc_init_file(struct inode *ino)
+{
 	struct nfs4_file *fp;
+	unsigned int hashval = file_hashval(ino);
+
 	if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
 		INIT_LIST_HEAD(&fp->fi_hash);
 		INIT_LIST_HEAD(&fp->fi_perfile);
@@ -985,15 +992,38 @@ release_all_files(void)
 	}
 }
 
-/* should use a slab cache */
+kmem_cache_t *stateowner_slab = NULL;
+
+static int
+nfsd4_init_slabs(void)
+{
+	stateowner_slab = kmem_cache_create("nfsd4_stateowners",
+			sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+	if (stateowner_slab == NULL) {
+		dprintk("nfsd4: out of memory while initializing nfsv4\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void
+nfsd4_free_slabs(void)
+{
+	int status = 0;
+
+	if (stateowner_slab)
+		status = kmem_cache_destroy(stateowner_slab);
+	stateowner_slab = NULL;
+	BUG_ON(status);
+}
+
 void
 nfs4_free_stateowner(struct kref *kref)
 {
 	struct nfs4_stateowner *sop =
 		container_of(kref, struct nfs4_stateowner, so_ref);
 	kfree(sop->so_owner.data);
-	kfree(sop);
-	free_sowner++;
+	kmem_cache_free(stateowner_slab, sop);
 }
 
 static inline struct nfs4_stateowner *
@@ -1001,14 +1031,14 @@ alloc_stateowner(struct xdr_netobj *owne
 {
 	struct nfs4_stateowner *sop;
 
-	if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) {
+	if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) {
 		if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
 			memcpy(sop->so_owner.data, owner->data, owner->len);
 			sop->so_owner.len = owner->len;
 			kref_init(&sop->so_ref);
 			return sop;
 		} 
-		kfree(sop);
+		kmem_cache_free(stateowner_slab, sop);
 	}
 	return NULL;
 }
@@ -1042,12 +1072,11 @@ alloc_init_open_stateowner(unsigned int 
 	rp->rp_status = NFSERR_SERVERFAULT;
 	rp->rp_buflen = 0;
 	rp->rp_buf = rp->rp_ibuf;
-	alloc_sowner++;
 	return sop;
 }
 
 static void
-release_stateid_lockowner(struct nfs4_stateid *open_stp)
+release_stateid_lockowners(struct nfs4_stateid *open_stp)
 {
 	struct nfs4_stateowner *lock_sop;
 
@@ -1067,9 +1096,11 @@ unhash_stateowner(struct nfs4_stateowner
 
 	list_del(&sop->so_idhash);
 	list_del(&sop->so_strhash);
-	list_del(&sop->so_perclient);
+	if (sop->so_is_open_owner) {
+		list_del(&sop->so_perclient);
+		del_perclient++;
+	}
 	list_del(&sop->so_perlockowner);
-	del_perclient++;
 	while (!list_empty(&sop->so_perfilestate)) {
 		stp = list_entry(sop->so_perfilestate.next, 
 			struct nfs4_stateid, st_perfilestate);
@@ -1089,7 +1120,8 @@ release_stateowner(struct nfs4_stateowne
 }
 
 static inline void
-init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {
+init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+	struct nfs4_stateowner *sop = open->op_stateowner;
 	unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
 
 	INIT_LIST_HEAD(&stp->st_hash);
@@ -1112,37 +1144,22 @@ init_stateid(struct nfs4_stateid *stp, s
 	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
 }
 
-/*
-* Because nfsd_close() can call locks_remove_flock() which removes leases,
-* delay nfsd_close() for delegations from the nfsd_open() clientid
-* until the delegation is reaped.
-*/
 static void
 release_stateid(struct nfs4_stateid *stp, int flags)
 {
-	struct nfs4_delegation *dp;
-	struct nfs4_file *fp = stp->st_file;
+	struct file *filp = stp->st_vfs_file;
 
 	list_del(&stp->st_hash);
 	list_del_perfile++;
 	list_del(&stp->st_perfile);
 	list_del(&stp->st_perfilestate);
-	if ((stp->st_vfs_set) && (flags & OPEN_STATE)) {
-		list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
-			if(cmp_clid(&dp->dl_client->cl_clientid,
-			    &stp->st_stateowner->so_client->cl_clientid)) {
-				dp->dl_stp = stp;
-				return;
-			}
-		}
-		release_stateid_lockowner(stp);
-		nfsd_close(stp->st_vfs_file);
+	if (flags & OPEN_STATE) {
+		release_stateid_lockowners(stp);
+		stp->st_vfs_file = NULL;
+		nfsd_close(filp);
 		vfsclose++;
-	} else if ((stp->st_vfs_set) && (flags & LOCK_STATE)) {
-		struct file *filp = stp->st_vfs_file;
-
+	} else if (flags & LOCK_STATE)
 		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
-	}
 	kfree(stp);
 	stp = NULL;
 }
@@ -1167,8 +1184,7 @@ move_to_close_lru(struct nfs4_stateowner
 }
 
 void
-release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
-		int flag)
+release_state_owner(struct nfs4_stateid *stp, int flag)
 {
 	struct nfs4_stateowner *sop = stp->st_stateowner;
 	struct nfs4_file *fp = stp->st_file;
@@ -1195,49 +1211,30 @@ cmp_owner_str(struct nfs4_stateowner *so
 	  (sop->so_client->cl_clientid.cl_id == clid->cl_id));
 }
 
-/* search ownerstr_hashtbl[] for owner */
-static int
-find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {
-	struct nfs4_stateowner *local = NULL;
-
-	list_for_each_entry(local, &ownerstr_hashtbl[hashval], so_strhash) {
-		if (!cmp_owner_str(local, &open->op_owner, &open->op_clientid))
-			continue;
-		*op = local;
-		return(1);
-	}
-	return 0;
-}
-
-/* see if clientid is in confirmed hash table */
-static int
-verify_clientid(struct nfs4_client **client, clientid_t *clid) {
-
-	struct nfs4_client *clp;
-	unsigned int idhashval = clientid_hashval(clid->cl_id);
+static struct nfs4_stateowner *
+find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
+{
+	struct nfs4_stateowner *so = NULL;
 
-	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-		if (!cmp_clid(&clp->cl_clientid, clid))
-			continue;
-		*client = clp;
-		return 1;
+	list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
+		if (cmp_owner_str(so, &open->op_owner, &open->op_clientid))
+			return so;
 	}
-	*client = NULL;
-	return 0;
+	return NULL;
 }
 
 /* search file_hashtbl[] for file */
-static int
-find_file(unsigned int hashval, struct inode *ino, struct nfs4_file **fp) {
-	struct nfs4_file *local = NULL;
+static struct nfs4_file *
+find_file(struct inode *ino)
+{
+	unsigned int hashval = file_hashval(ino);
+	struct nfs4_file *fp;
 
-	list_for_each_entry(local, &file_hashtbl[hashval], fi_hash) {
-		if (local->fi_inode == ino) {
-			*fp = local;
-			return(1);
-		}
+	list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
+		if (fp->fi_inode == ino)
+			return fp;
 	}
-	return 0;
+	return NULL;
 }
 
 #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
@@ -1284,14 +1281,13 @@ int
 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 {
 	struct inode *ino = current_fh->fh_dentry->d_inode;
-	unsigned int fi_hashval;
 	struct nfs4_file *fp;
 	struct nfs4_stateid *stp;
 
 	dprintk("NFSD: nfs4_share_conflict\n");
 
-	fi_hashval = file_hashval(ino);
-	if (find_file(fi_hashval, ino, &fp)) {
+	fp = find_file(ino);
+	if (fp) {
 	/* Search for conflicting share reservations */
 		list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
 			if (test_bit(deny_type, &stp->st_deny_bmap) ||
@@ -1321,7 +1317,6 @@ do_recall(void *__dp)
 
 	daemonize("nfsv4-recall");
 
-	atomic_inc(&dp->dl_count);
 	nfsd4_cb_recall(dp);
 	return 0;
 }
@@ -1330,8 +1325,9 @@ do_recall(void *__dp)
  * Spawn a thread to perform a recall on the delegation represented
  * by the lease (file_lock)
  *
- * Called from break_lease() with lock_kernel() held,
- *
+ * Called from break_lease() with lock_kernel() held.
+ * Note: we assume break_lease will only call this *once* for any given
+ * lease.
  */
 static
 void nfsd_break_deleg_cb(struct file_lock *fl)
@@ -1343,9 +1339,14 @@ void nfsd_break_deleg_cb(struct file_loc
 	if (!dp)
 		return;
 
-	/* schedule delegation for recall */
+	/* We're assuming the state code never drops its reference
+	 * without first removing the lease.  Since we're in this lease
+	 * callback (and since the lease code is serialized by the kernel
+	 * lock) we know the server hasn't removed the lease yet, we know
+	 * it's safe to take a reference: */
+	atomic_inc(&dp->dl_count);
+
 	spin_lock(&recall_lock);
-	atomic_set(&dp->dl_state, NFS4_RECALL_IN_PROGRESS);
 	list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
 	spin_unlock(&recall_lock);
 
@@ -1362,6 +1363,7 @@ void nfsd_break_deleg_cb(struct file_loc
 		printk(KERN_INFO "NFSD: Callback thread failed for "
 			"for client (clientid %08x/%08x)\n",
 			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+		nfs4_put_delegation(dp);
 	}
 }
 
@@ -1375,11 +1377,10 @@ void nfsd_release_deleg_cb(struct file_l
 {
 	struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
 
-	dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d, dl_state %d\n", fl,dp, atomic_read(&dp->dl_count), atomic_read(&dp->dl_state));
+	dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));
 
 	if (!(fl->fl_flags & FL_LEASE) || !dp)
 		return;
-	atomic_set(&dp->dl_state,NFS4_RECALL_COMPLETE);
 	dp->dl_flock = NULL;
 }
 
@@ -1399,14 +1400,42 @@ void nfsd_copy_lock_deleg_cb(struct file
 	dp->dl_flock = new;
 }
 
+/*
+ * Called from __setlease() with lock_kernel() held
+ */
+static
+int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
+{
+	struct nfs4_delegation *onlistd =
+		(struct nfs4_delegation *)onlist->fl_owner;
+	struct nfs4_delegation *tryd =
+		(struct nfs4_delegation *)try->fl_owner;
+
+	if (onlist->fl_lmops != try->fl_lmops)
+		return 0;
+
+	return onlistd->dl_client == tryd->dl_client;
+}
+
+
+static
+int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
+{
+	if (arg & F_UNLCK)
+		return lease_modify(onlist, arg);
+	else
+		return -EAGAIN;
+}
+
 struct lock_manager_operations nfsd_lease_mng_ops = {
-        .fl_break = nfsd_break_deleg_cb,
-        .fl_release_private = nfsd_release_deleg_cb,
-        .fl_copy_lock = nfsd_copy_lock_deleg_cb,
+	.fl_break = nfsd_break_deleg_cb,
+	.fl_release_private = nfsd_release_deleg_cb,
+	.fl_copy_lock = nfsd_copy_lock_deleg_cb,
+	.fl_mylease = nfsd_same_client_deleg_cb,
+	.fl_change = nfsd_change_deleg_cb,
 };
 
 
-
 /*
  * nfsd4_process_open1()
  * 	lookup stateowner.
@@ -1436,65 +1465,60 @@ nfsd4_process_open1(struct nfsd4_open *o
 	if (!check_name(open->op_owner))
 		goto out;
 
-	status = nfserr_stale_clientid;
 	if (STALE_CLIENTID(&open->op_clientid))
-		return status;
+		return nfserr_stale_clientid;
 
 	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
-	if (find_openstateowner_str(strhashval, open, &sop)) {
+	sop = find_openstateowner_str(strhashval, open);
+	if (sop) {
 		open->op_stateowner = sop;
 		/* check for replay */
 		if (open->op_seqid == sop->so_seqid){
-			if (!sop->so_replay.rp_buflen) {
-			/*
-			* The original OPEN failed in so spectacularly that we
-			* don't even have replay data saved!  Therefore, we
-			* have no choice but to continue processing
-			* this OPEN; presumably, we'll fail again for the same
-			* reason.
-			*/
-				dprintk("nfsd4_process_open1: replay with no replay cache\n");
-				status = NFS_OK;
+			if (sop->so_replay.rp_buflen)
+				return NFSERR_REPLAY_ME;
+			else {
+				/* The original OPEN failed so spectacularly
+				 * that we don't even have replay data saved!
+				 * Therefore, we have no choice but to continue
+				 * processing this OPEN; presumably, we'll
+				 * fail again for the same reason.
+				 */
+				dprintk("nfsd4_process_open1:"
+					" replay with no replay cache\n");
 				goto renew;
 			}
-			/* replay: indicate to calling function */
-			status = NFSERR_REPLAY_ME;
-			return status;
-		}
-		if (sop->so_confirmed) {
-			if (open->op_seqid == sop->so_seqid + 1) { 
-				status = nfs_ok;
+		} else if (sop->so_confirmed) {
+			if (open->op_seqid == sop->so_seqid + 1)
 				goto renew;
-			} 
 			status = nfserr_bad_seqid;
 			goto out;
+		} else {
+			/* If we get here, we received an OPEN for an
+			 * unconfirmed nfs4_stateowner. Since the seqid's are
+			 * different, purge the existing nfs4_stateowner, and
+			 * instantiate a new one.
+			 */
+			clp = sop->so_client;
+			release_stateowner(sop);
 		}
-		/* If we get here, we received and OPEN for an unconfirmed
-		 * nfs4_stateowner. 
-		 * Since the sequid's are different, purge the 
-		 * existing nfs4_stateowner, and instantiate a new one.
+	} else {
+		/* nfs4_stateowner not found.
+		 * Verify clientid and instantiate new nfs4_stateowner.
+		 * If verify fails this is presumably the result of the
+		 * client's lease expiring.
 		 */
-		clp = sop->so_client;
-		release_stateowner(sop);
-		goto instantiate_new_owner;
-	} 
-	/* nfs4_stateowner not found. 
-	* verify clientid and instantiate new nfs4_stateowner
-	* if verify fails this is presumably the result of the 
-	* client's lease expiring.
-	*
-	* XXX compare clp->cl_addr with rqstp addr? 
-	*/
-	status = nfserr_expired;
-	if (!verify_clientid(&clp, clientid))
-		goto out;
-instantiate_new_owner:
+		status = nfserr_expired;
+		clp = find_confirmed_client(clientid);
+		if (clp == NULL)
+			goto out;
+	}
 	status = nfserr_resource;
-	if (!(sop = alloc_init_open_stateowner(strhashval, clp, open))) 
+	sop = alloc_init_open_stateowner(strhashval, clp, open);
+	if (sop == NULL)
 		goto out;
 	open->op_stateowner = sop;
-	status = nfs_ok;
 renew:
+	status = nfs_ok;
 	renew_client(sop->so_client);
 out:
 	if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
@@ -1503,57 +1527,19 @@ out:
 }
 
 static int
-nfs4_deleg_conflict(u32 share, u32 dtype)
-{
-	return (((share & NFS4_SHARE_ACCESS_WRITE) &&
-		dtype == NFS4_OPEN_DELEGATE_READ) ||
-		((share & NFS4_SHARE_ACCESS_READ) &&
-		dtype == NFS4_OPEN_DELEGATE_WRITE));
-}
-
-#define DONT_DELEGATE  8
-
-/*
- * nfs4_check_deleg_recall()
- *
- * Test any delegation that is currently within an incompleted recalled
- * state, and return NFSERR_DELAY for conflicting open share.
- * flag is set to DONT_DELEGATE for shares that match the deleg type.
- */
-static int
-nfs4_check_deleg_recall(struct nfs4_file *fp, struct nfsd4_open *op, int *flag)
-{
-	struct nfs4_delegation *dp;
-	int status = 0;
-
-	list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
-		dprintk("NFSD: found delegation %p with dl_state %d\n",
-		 	                 dp, atomic_read(&dp->dl_state));
-		if (atomic_read(&dp->dl_state) == NFS4_RECALL_IN_PROGRESS) {
-			if(nfs4_deleg_conflict(op->op_share_access, dp->dl_type))
-				status = nfserr_jukebox;
-			else
-				*flag = DONT_DELEGATE;
-		}
-	}
-	return status;
-}
-
-static int
-nfs4_check_open(struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open, struct nfs4_stateid **stpp)
+nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
 {
 	struct nfs4_stateid *local;
 	int status = nfserr_share_denied;
+	struct nfs4_stateowner *sop = open->op_stateowner;
 
 	list_for_each_entry(local, &fp->fi_perfile, st_perfile) {
-		/* have we seen this open owner */
-		if (local->st_stateowner == sop) {
-			*stpp = local;
-			continue;
-		}
 		/* ignore lock owners */
 		if (local->st_stateowner->so_is_open_owner == 0)
 			continue;
+		/* remember if we have seen this open owner */
+		if (local->st_stateowner == sop)
+			*stpp = local;
 		/* check for conflicting share reservations */
 		if (!test_share(local, open))
 			goto out;
@@ -1582,11 +1568,25 @@ nfs4_new_open(struct svc_rqst *rqstp, st
 		return status;
 	}
 	vfsopen++;
-	stp->st_vfs_set = 1;
 	*stpp = stp;
 	return 0;
 }
 
+static inline int
+nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
+		struct nfsd4_open *open)
+{
+	struct iattr iattr = {
+		.ia_valid = ATTR_SIZE,
+		.ia_size = 0,
+	};
+	if (!open->op_truncate)
+		return 0;
+	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+		return -EINVAL;
+	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
+}
+
 static int
 nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
 {
@@ -1599,29 +1599,22 @@ nfs4_upgrade_open(struct svc_rqst *rqstp
 	share_access = ~share_access;
 	share_access &= open->op_share_access;
 
-	/* update the struct file */
-	if (share_access & NFS4_SHARE_ACCESS_WRITE) {
-		status = get_write_access(inode);
-		if (status)
-			return nfserrno(status);
-		if (open->op_truncate) {
-			struct iattr iattr = {
-				.ia_valid = ATTR_SIZE,
-				.ia_size = 0,
-			};
-			status = nfsd_setattr(rqstp, cur_fh, &iattr, 0,
-					(time_t)0);
-			if (status) {
-				put_write_access(inode);
-				return status;
-			}
-		}
+	if (!(share_access & NFS4_SHARE_ACCESS_WRITE))
+		return nfsd4_truncate(rqstp, cur_fh, open);
 
-		/* remember the open */
-		filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ;
-		set_bit(open->op_share_access, &stp->st_access_bmap);
-		set_bit(open->op_share_deny, &stp->st_deny_bmap);
+	status = get_write_access(inode);
+	if (status)
+		return nfserrno(status);
+	status = nfsd4_truncate(rqstp, cur_fh, open);
+	if (status) {
+		put_write_access(inode);
+		return status;
 	}
+	/* remember the open */
+	filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ;
+	set_bit(open->op_share_access, &stp->st_access_bmap);
+	set_bit(open->op_share_deny, &stp->st_deny_bmap);
+
 	return nfs_ok;
 }
 
@@ -1644,33 +1637,29 @@ nfs4_set_claim_prev(struct nfsd4_open *o
  * Attempt to hand out a delegation.
  */
 static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp, int *flag)
+nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp)
 {
 	struct nfs4_delegation *dp;
 	struct nfs4_stateowner *sop = stp->st_stateowner;
 	struct nfs4_callback *cb = &sop->so_client->cl_callback;
 	struct file_lock fl, *flp = &fl;
-	int status;
-
-	if (*flag == DONT_DELEGATE) {
-		*flag = NFS4_OPEN_DELEGATE_NONE;
-		return;
-	}
+	int status, flag = 0;
 
-	/* set flag */
-	*flag = NFS4_OPEN_DELEGATE_NONE;
+	flag = NFS4_OPEN_DELEGATE_NONE;
 	if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL
 	     || !atomic_read(&cb->cb_set) || !sop->so_confirmed)
-		return;
-
-	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
-		*flag = NFS4_OPEN_DELEGATE_READ;
+		goto out;
 
-	else if (!(open->op_share_access & NFS4_SHARE_ACCESS_READ))
-		*flag = NFS4_OPEN_DELEGATE_WRITE;
+	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
+		flag = NFS4_OPEN_DELEGATE_WRITE;
+	else
+		flag = NFS4_OPEN_DELEGATE_READ;
 
-	if (!(dp = alloc_init_deleg(sop->so_client, stp->st_file, fh, *flag)))
-		return;
+	dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
+	if (dp == NULL) {
+		flag = NFS4_OPEN_DELEGATE_NONE;
+		goto out;
+	}
 	locks_init_lock(&fl);
 	fl.fl_lmops = &nfsd_lease_mng_ops;
 	fl.fl_flags = FL_LEASE;
@@ -1679,15 +1668,15 @@ nfs4_open_delegation(struct svc_fh *fh, 
 	fl.fl_file = stp->st_vfs_file;
 	fl.fl_pid = current->tgid;
 
+	/* setlease checks to see if delegation should be handed out.
+	 * the lock_manager callbacks fl_mylease and fl_change are used
+	 */
 	if ((status = setlease(stp->st_vfs_file,
-		*flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
+		flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
 		dprintk("NFSD: setlease failed [%d], no delegation\n", status);
-		list_del(&dp->dl_del_perfile);
-		list_del(&dp->dl_del_perclnt);
-		kfree(dp);
-		free_delegation++;
-		*flag = NFS4_OPEN_DELEGATE_NONE;
-		return;
+		unhash_delegation(dp);
+		flag = NFS4_OPEN_DELEGATE_NONE;
+		goto out;
 	}
 
 	memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
@@ -1697,6 +1686,8 @@ nfs4_open_delegation(struct svc_fh *fh, 
 	             dp->dl_stateid.si_stateownerid,
 	             dp->dl_stateid.si_fileid,
 	             dp->dl_stateid.si_generation);
+out:
+	open->op_delegate_type = flag;
 }
 
 /*
@@ -1705,12 +1696,10 @@ nfs4_open_delegation(struct svc_fh *fh, 
 int
 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
-	struct nfs4_stateowner *sop = open->op_stateowner;
 	struct nfs4_file *fp = NULL;
 	struct inode *ino = current_fh->fh_dentry->d_inode;
-	unsigned int fi_hashval;
 	struct nfs4_stateid *stp = NULL;
-	int status, delegflag = 0;
+	int status;
 
 	status = nfserr_inval;
 	if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
@@ -1720,15 +1709,14 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	 * and check for delegations in the process of being recalled.
 	 * If not found, create the nfs4_file struct
 	 */
-	fi_hashval = file_hashval(ino);
-	if (find_file(fi_hashval, ino, &fp)) {
-		if ((status = nfs4_check_open(fp, sop, open, &stp)))
-			goto out;
-		if ((status = nfs4_check_deleg_recall(fp, open, &delegflag)))
+	fp = find_file(ino);
+	if (fp) {
+		if ((status = nfs4_check_open(fp, open, &stp)))
 			goto out;
 	} else {
 		status = nfserr_resource;
-		if ((fp = alloc_init_file(fi_hashval, ino)) == NULL)
+		fp = alloc_init_file(ino);
+		if (fp == NULL)
 			goto out;
 	}
 
@@ -1750,18 +1738,11 @@ nfsd4_process_open2(struct svc_rqst *rqs
 			flags = MAY_READ;
 		if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags)))
 			goto out;
-		init_stateid(stp, fp, sop, open);
-		if (open->op_truncate) {
-			struct iattr iattr = {
-				.ia_valid = ATTR_SIZE,
-				.ia_size = 0,
-			};
-			status = nfsd_setattr(rqstp, current_fh, &iattr, 0,
-					(time_t)0);
-			if (status) {
-				release_stateid(stp, OPEN_STATE);
-				goto out;
-			}
+		init_stateid(stp, fp, open);
+		status = nfsd4_truncate(rqstp, current_fh, open);
+		if (status) {
+			release_stateid(stp, OPEN_STATE);
+			goto out;
 		}
 	}
 	memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
@@ -1770,8 +1751,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	* Attempt to hand out a delegation. No error return, because the
 	* OPEN succeeds even if we fail.
 	*/
-	nfs4_open_delegation(current_fh, open, stp, &delegflag);
-	open->op_delegate_type = delegflag;
+	nfs4_open_delegation(current_fh, open, stp);
 
 	status = nfs_ok;
 
@@ -1780,7 +1760,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
 out:
 	/* take the opportunity to clean up unused state */
-	if (fp && list_empty(&fp->fi_perfile))
+	if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile))
 		release_file(fp);
 
 	/* CLAIM_PREVIOUS has different error returns */
@@ -1803,7 +1783,6 @@ int 
 nfsd4_renew(clientid_t *clid)
 {
 	struct nfs4_client *clp;
-	unsigned int idhashval;
 	int status;
 
 	nfs4_lock_state();
@@ -1812,27 +1791,19 @@ nfsd4_renew(clientid_t *clid)
 	status = nfserr_stale_clientid;
 	if (STALE_CLIENTID(clid))
 		goto out;
-	status = nfs_ok;
-	idhashval = clientid_hashval(clid->cl_id);
-	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-		if (!cmp_clid(&clp->cl_clientid, clid))
-			continue;
-		renew_client(clp);
+	clp = find_confirmed_client(clid);
+	status = nfserr_expired;
+	if (clp == NULL) {
+		/* We assume the client took too long to RENEW. */
+		dprintk("nfsd4_renew: clientid not found!\n");
 		goto out;
 	}
-	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
-		if (!cmp_clid(&clp->cl_clientid, clid))
-			continue;
-		renew_client(clp);
-	goto out;
-	}
-	/*
-	* Couldn't find an nfs4_client for this clientid.  
-	* Presumably this is because the client took too long to 
-	* RENEW, so return NFS4ERR_EXPIRED.
-	*/
-	dprintk("nfsd4_renew: clientid not found!\n");
-	status = nfserr_expired;
+	renew_client(clp);
+	status = nfserr_cb_path_down;
+	if (!list_empty(&clp->cl_del_perclnt)
+			&& !atomic_read(&clp->cl_callback.cb_set))
+		goto out;
+	status = nfs_ok;
 out:
 	nfs4_unlock_state();
 	return status;
@@ -1844,7 +1815,7 @@ nfs4_laundromat(void)
 	struct nfs4_client *clp;
 	struct nfs4_stateowner *sop;
 	struct nfs4_delegation *dp;
-	struct list_head *pos, *next;
+	struct list_head *pos, *next, reaplist;
 	time_t cutoff = get_seconds() - NFSD_LEASE_TIME;
 	time_t t, clientid_val = NFSD_LEASE_TIME;
 	time_t u, test_val = NFSD_LEASE_TIME;
@@ -1864,23 +1835,26 @@ nfs4_laundromat(void)
 			clp->cl_clientid.cl_id);
 		expire_client(clp);
 	}
+	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&recall_lock);
 	list_for_each_safe(pos, next, &del_recall_lru) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
-		if (atomic_read(&dp->dl_state) == NFS4_RECALL_COMPLETE)
-			goto reap;
 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
 			u = dp->dl_time - cutoff;
 			if (test_val > u)
 				test_val = u;
 			break;
 		}
-reap:
 		dprintk("NFSD: purging unused delegation dp %p, fp %p\n",
 			            dp, dp->dl_flock);
-		release_delegation(dp);
+		list_move(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&recall_lock);
+	list_for_each_safe(pos, next, &reaplist) {
+		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
+		unhash_delegation(dp);
+	}
 	test_val = NFSD_LEASE_TIME;
 	list_for_each_safe(pos, next, &close_lru) {
 		sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
@@ -1931,8 +1905,7 @@ find_openstateowner_id(u32 st_id, int fl
 static inline int
 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
 {
-	return (stp->st_vfs_set == 0 ||
-		fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode);
+	return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode;
 }
 
 static int
@@ -1950,7 +1923,8 @@ static inline int
 access_permit_read(unsigned long access_bmap)
 {
 	return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
-		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
+		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) ||
+		test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap);
 }
 
 static inline int
@@ -1974,34 +1948,69 @@ out:
 	return status;
 }
 
-static int
+static inline int
 nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
 {
-	int status = nfserr_openmode;
+	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
+		return nfserr_openmode;
+	else
+		return nfs_ok;
+}
 
-	if ((flags & WR_STATE) & (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
-		goto out;
-	if ((flags & RD_STATE) & (dp->dl_type == NFS4_OPEN_DELEGATE_WRITE))
-		goto out;
-	status = nfs_ok;
-out:
-	return status;
+static inline int
+check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
+{
+	/* Trying to call delegreturn with a special stateid? Yuch: */
+	if (!(flags & (RD_STATE | WR_STATE)))
+		return nfserr_bad_stateid;
+	else if (ONE_STATEID(stateid) && (flags & RD_STATE))
+		return nfs_ok;
+	else if (nfs4_in_grace()) {
+		/* Answer in remaining cases depends on existance of
+		 * conflicting state; so we must wait out the grace period. */
+		return nfserr_grace;
+	} else if (flags & WR_STATE)
+		return nfs4_share_conflict(current_fh,
+				NFS4_SHARE_DENY_WRITE);
+	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
+		return nfs4_share_conflict(current_fh,
+				NFS4_SHARE_DENY_READ);
+}
+
+/*
+ * Allow READ/WRITE during grace period on recovered state only for files
+ * that are not able to provide mandatory locking.
+ */
+static inline int
+io_during_grace_disallowed(struct inode *inode, int flags)
+{
+	return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
+		&& MANDATORY_LOCK(inode);
 }
 
 /*
 * Checks for stateid operations
 */
 int
-nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags)
+nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp)
 {
 	struct nfs4_stateid *stp = NULL;
 	struct nfs4_delegation *dp = NULL;
 	stateid_t *stidp;
+	struct inode *ino = current_fh->fh_dentry->d_inode;
 	int status;
 
 	dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
 		stateid->si_boot, stateid->si_stateownerid, 
 		stateid->si_fileid, stateid->si_generation); 
+	if (filpp)
+		*filpp = NULL;
+
+	if (io_during_grace_disallowed(ino, flags))
+		return nfserr_grace;
+
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+		return check_special_stateids(current_fh, stateid, flags);
 
 	/* STALE STATEID */
 	status = nfserr_stale_stateid;
@@ -2011,16 +2020,18 @@ nfs4_preprocess_stateid_op(struct svc_fh
 	/* BAD STATEID */
 	status = nfserr_bad_stateid;
 	if (!stateid->si_fileid) { /* delegation stateid */
-		struct inode *ino = current_fh->fh_dentry->d_inode;
-
 		if(!(dp = find_delegation_stateid(ino, stateid))) {
 			dprintk("NFSD: delegation stateid not found\n");
+			if (nfs4_in_grace())
+				status = nfserr_grace;
 			goto out;
 		}
 		stidp = &dp->dl_stateid;
 	} else { /* open or lock stateid */
 		if (!(stp = find_stateid(stateid, flags))) {
 			dprintk("NFSD: open or lock stateid not found\n");
+			if (nfs4_in_grace())
+				status = nfserr_grace;
 			goto out;
 		}
 		if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp))
@@ -2040,16 +2051,16 @@ nfs4_preprocess_stateid_op(struct svc_fh
 		if ((status = nfs4_check_openmode(stp,flags)))
 			goto out;
 		renew_client(stp->st_stateowner->so_client);
+		if (filpp)
+			*filpp = stp->st_vfs_file;
 	} else if (dp) {
 		if ((status = nfs4_check_delegmode(dp, flags)))
 			goto out;
 		renew_client(dp->dl_client);
-		if (flags & DELEG_RET) {
-			atomic_set(&dp->dl_state,NFS4_RECALL_COMPLETE);
-			spin_lock(&recall_lock);
-			release_delegation(dp);
-			spin_unlock(&recall_lock);
-		}
+		if (flags & DELEG_RET)
+			unhash_delegation(dp);
+		if (filpp)
+			*filpp = dp->dl_vfs_file;
 	}
 	status = nfs_ok;
 out:
@@ -2117,7 +2128,6 @@ nfs4_preprocess_seqid_op(struct svc_fh *
 
 	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
 		printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
-		stp->st_vfs_set = 0;
 		goto out;
 	}
 
@@ -2188,17 +2198,6 @@ check_replay:
 	goto out;
 }
 
-/*
- * eventually, this will perform an upcall to the 'state daemon' as well as
- * set the cl_first_state field.
- */
-void
-first_state(struct nfs4_client *clp)
-{
-	if (!clp->cl_first_state)
-		clp->cl_first_state = get_seconds();
-}
-
 int
 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
 {
@@ -2231,8 +2230,6 @@ nfsd4_open_confirm(struct svc_rqst *rqst
 		         stp->st_stateid.si_stateownerid,
 		         stp->st_stateid.si_fileid,
 		         stp->st_stateid.si_generation);
-	status = nfs_ok;
-	first_state(sop->so_client);
 out:
 	if (oc->oc_stateowner)
 		nfs4_get_stateowner(oc->oc_stateowner);
@@ -2342,7 +2339,7 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 	memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
 
 	/* release_state_owner() calls nfsd_close() if needed */
-	release_state_owner(stp, &close->cl_stateowner, OPEN_STATE);
+	release_state_owner(stp, OPEN_STATE);
 out:
 	if (close->cl_stateowner)
 		nfs4_get_stateowner(close->cl_stateowner);
@@ -2359,7 +2356,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp
 		goto out;
 
 	nfs4_lock_state();
-	status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET);
+	status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET, NULL);
 	nfs4_unlock_state();
 out:
 	return status;
@@ -2376,8 +2373,15 @@ out:
 
 #define lockownerid_hashval(id) \
         ((id) & LOCK_HASH_MASK)
-#define lock_ownerstr_hashval(x, clientid, ownername) \
-        ((file_hashval(x) + (clientid) + opaque_hashval((ownername.data), (ownername.len))) & LOCK_HASH_MASK)
+
+static inline unsigned int
+lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
+		struct xdr_netobj *ownername)
+{
+	return (file_hashval(inode) + cl_id
+			+ opaque_hashval(ownername->data, ownername->len))
+		& LOCK_HASH_MASK;
+}
 
 static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
 static struct list_head	lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
@@ -2418,17 +2422,14 @@ find_delegation_stateid(struct inode *in
 	struct nfs4_delegation *dp = NULL;
 	struct nfs4_file *fp = NULL;
 	u32 st_id;
-	unsigned int fi_hashval;
 
 	dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
                     stid->si_boot, stid->si_stateownerid,
                     stid->si_fileid, stid->si_generation);
 
-	if(!ino || !stid)
-		return NULL;
 	st_id = stid->si_stateownerid;
-	fi_hashval = file_hashval(ino);
-	if (find_file(fi_hashval, ino, &fp)) {
+	fp = find_file(ino);
+	if (fp) {
 		list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
 			if(dp->dl_stateid.si_stateownerid == st_id) {
 				dprintk("NFSD: find_delegation dp %p\n",dp);
@@ -2512,18 +2513,18 @@ find_lockstateowner(struct xdr_netobj *o
 	return NULL;
 }
 
-static int
-find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid_t *clid, struct nfs4_stateowner **op) {
-	struct nfs4_stateowner *local = NULL;
+static struct nfs4_stateowner *
+find_lockstateowner_str(struct inode *inode, clientid_t *clid,
+		struct xdr_netobj *owner)
+{
+	unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
+	struct nfs4_stateowner *op;
 
-	list_for_each_entry(local, &lock_ownerstr_hashtbl[hashval], so_strhash) {
-		if (!cmp_owner_str(local, owner, clid))
-			continue;
-		*op = local;
-		return(1);
+	list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
+		if (cmp_owner_str(op, owner, clid))
+			return op;
 	}
-	*op = NULL;
-	return 0;
+	return NULL;
 }
 
 /*
@@ -2553,9 +2554,7 @@ alloc_init_lock_stateowner(unsigned int 
 	sop->so_time = 0;
 	list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
 	list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
-	list_add(&sop->so_perclient, &clp->cl_perclient);
 	list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);
-	add_perclient++;
 	sop->so_is_open_owner = 0;
 	sop->so_id = current_ownerid++;
 	sop->so_client = clp;
@@ -2565,7 +2564,6 @@ alloc_init_lock_stateowner(unsigned int 
 	rp->rp_status = NFSERR_SERVERFAULT;
 	rp->rp_buflen = 0;
 	rp->rp_buf = rp->rp_ibuf;
-	alloc_lsowner++;
 	return sop;
 }
 
@@ -2593,7 +2591,6 @@ alloc_init_lock_stateid(struct nfs4_stat
 	stp->st_stateid.si_fileid = fp->fi_id;
 	stp->st_stateid.si_generation = 0;
 	stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
-	stp->st_vfs_set = open_stp->st_vfs_set;
 	stp->st_access_bmap = open_stp->st_access_bmap;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 
@@ -2672,7 +2669,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 		fp = open_stp->st_file;
 		strhashval = lock_ownerstr_hashval(fp->fi_inode, 
 				open_sop->so_client->cl_clientid.cl_id, 
-				lock->v.new.owner);
+				&lock->v.new.owner);
 		/* 
 		 * If we already have this lock owner, the client is in 
 		 * error (or our bookeeping is wrong!) 
@@ -2785,7 +2782,7 @@ out_destroy_new_stateid:
 		if (!seqid_mutating_err(status))
 			open_sop->so_seqid--;
 
-		release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);
+		release_state_owner(lock_stp, LOCK_STATE);
 	}
 out:
 	if (lock->lk_stateowner)
@@ -2804,7 +2801,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 	struct file file;
 	struct file_lock file_lock;
 	struct file_lock *conflicting_lock;
-	unsigned int strhashval;
 	int status;
 
 	if (nfs4_in_grace())
@@ -2846,12 +2842,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 		goto out;
 	}
 
-	strhashval = lock_ownerstr_hashval(inode, 
-			lockt->lt_clientid.cl_id, lockt->lt_owner);
-
-	find_lockstateowner_str(strhashval, &lockt->lt_owner,
-					&lockt->lt_clientid, 
-					&lockt->lt_stateowner);
+	lockt->lt_stateowner = find_lockstateowner_str(inode,
+			&lockt->lt_clientid, &lockt->lt_owner);
 	if (lockt->lt_stateowner)
 		file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
 	file_lock.fl_pid = current->tgid;
@@ -3005,10 +2997,8 @@ nfsd4_release_lockowner(struct svc_rqst 
 		status = nfserr_locks_held;
 		list_for_each_entry(stp, &local->so_perfilestate,
 				st_perfilestate) {
-			if (stp->st_vfs_set) {
-				if (check_for_locks(stp->st_vfs_file, local))
-					goto out;
-			}
+			if (check_for_locks(stp->st_vfs_file, local))
+				goto out;
 		}
 		/* no locks held by (lock) stateowner */
 		status = nfs_ok;
@@ -3039,21 +3029,21 @@ alloc_reclaim(int namelen)
  * failure => all reset bets are off, nfserr_no_grace...
  */
 static int
-nfs4_client_to_reclaim(struct nfs4_client *clp)
+nfs4_client_to_reclaim(char *name, int namlen)
 {
 	unsigned int strhashval;
 	struct nfs4_client_reclaim *crp = NULL;
 
-	crp = alloc_reclaim(clp->cl_name.len);
+	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name);
+	crp = alloc_reclaim(namlen);
 	if (!crp)
 		return 0;
-	strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
+	strhashval = clientstr_hashval(name, namlen);
 	INIT_LIST_HEAD(&crp->cr_strhash);
 	list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
-	memcpy(crp->cr_name.data, clp->cl_name.data, clp->cl_name.len);
-	crp->cr_name.len = clp->cl_name.len;
-	crp->cr_first_state = clp->cl_first_state;
-	crp->cr_expired = 0;
+	memcpy(crp->cr_name.data, name, namlen);
+	crp->cr_name.len = namlen;
+	reclaim_str_hashtbl_size++;
 	return 1;
 }
 
@@ -3082,27 +3072,23 @@ nfs4_release_reclaim(void)
 struct nfs4_client_reclaim *
 nfs4_find_reclaim_client(clientid_t *clid)
 {
-	unsigned int idhashval = clientid_hashval(clid->cl_id);
 	unsigned int strhashval;
-	struct nfs4_client *clp, *client = NULL;
+	struct nfs4_client *clp;
 	struct nfs4_client_reclaim *crp = NULL;
 
 
 	/* find clientid in conf_id_hashtbl */
-	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-		if (cmp_clid(&clp->cl_clientid, clid)) {
-			client = clp;
-			break;
-		}
-	}
-	if (!client)
+	clp = find_confirmed_client(clid);
+	if (clp == NULL)
 		return NULL;
 
+	dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n",
+		            clp->cl_name.len, clp->cl_name.data);
+
 	/* find clp->cl_name in reclaim_str_hashtbl */
-	strhashval = clientstr_hashval(client->cl_name.data,
-	                              client->cl_name.len);
+	strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
 	list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
-		if (cmp_name(&crp->cr_name, &client->cl_name)) {
+		if (cmp_name(&crp->cr_name, &clp->cl_name)) {
 			return crp;
 		}
 	}
@@ -3119,8 +3105,6 @@ nfs4_check_open_reclaim(clientid_t *clid
 
 	if ((crp = nfs4_find_reclaim_client(clid)) == NULL)
 		return nfserr_reclaim_bad;
-	if (crp->cr_expired)
-		return nfserr_no_grace;
 	return nfs_ok;
 }
 
@@ -3129,14 +3113,12 @@ nfs4_check_open_reclaim(clientid_t *clid
  * Start and stop routines
  */
 
-void 
-nfs4_state_init(void)
+static void
+__nfs4_state_init(void)
 {
 	int i;
 	time_t grace_time;
 
-	if (nfs4_init)
-		return;
 	if (!nfs4_reclaim_init) {
 		for (i = 0; i < CLIENT_HASH_SIZE; i++)
 			INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
@@ -3180,7 +3162,21 @@ nfs4_state_init(void)
 	grace_end = boot_time + grace_time;
 	INIT_WORK(&laundromat_work,laundromat_main, NULL);
 	schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
+}
+
+int
+nfs4_state_init(void)
+{
+	int status;
+
+	if (nfs4_init)
+		return 0;
+	status = nfsd4_init_slabs();
+	if (status)
+		return status;
+	__nfs4_state_init();
 	nfs4_init = 1;
+	return 0;
 }
 
 int
@@ -3208,7 +3204,14 @@ __nfs4_state_shutdown(void)
 	int i;
 	struct nfs4_client *clp = NULL;
 	struct nfs4_delegation *dp = NULL;
-	struct list_head *pos, *next;
+	struct nfs4_stateowner *sop = NULL;
+	struct list_head *pos, *next, reaplist;
+
+	list_for_each_safe(pos, next, &close_lru) {
+		sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
+		list_del(&sop->so_close_lru);
+		nfs4_put_stateowner(sop);
+	}
 
 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
 		while (!list_empty(&conf_id_hashtbl[i])) {
@@ -3220,13 +3223,18 @@ __nfs4_state_shutdown(void)
 			expire_client(clp);
 		}
 	}
+	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&recall_lock);
 	list_for_each_safe(pos, next, &del_recall_lru) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
-		atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE);
-		release_delegation(dp);
+		list_move(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&recall_lock);
+	list_for_each_safe(pos, next, &reaplist) {
+		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
+		unhash_delegation(dp);
+	}
 
 	release_all_files();
 	cancel_delayed_work(&laundromat_work);
@@ -3238,8 +3246,6 @@ __nfs4_state_shutdown(void)
 			add_perclient, del_perclient);
 	dprintk("NFSD: alloc_file %d free_file %d\n",
 			alloc_file, free_file);
-	dprintk("NFSD: alloc_sowner %d alloc_lsowner %d free_sowner %d\n",
-			alloc_sowner, alloc_lsowner, free_sowner);
 	dprintk("NFSD: vfsopen %d vfsclose %d\n",
 			vfsopen, vfsclose);
 	dprintk("NFSD: alloc_delegation %d free_delegation %d\n",
@@ -3253,6 +3259,7 @@ nfs4_state_shutdown(void)
 	nfs4_lock_state();
 	nfs4_release_reclaim();
 	__nfs4_state_shutdown();
+	nfsd4_free_slabs();
 	nfs4_unlock_state();
 }
 
@@ -3296,16 +3303,16 @@ nfs4_reset_lease(time_t leasetime)
 	/* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */
 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
 		list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) {
-			if (!nfs4_client_to_reclaim(clp)) {
+			if (!nfs4_client_to_reclaim(clp->cl_name.data,
+						clp->cl_name.len)) {
 				nfs4_release_reclaim();
 				goto init_state;
 			}
-			reclaim_str_hashtbl_size++;
 		}
 	}
 init_state:
 	__nfs4_state_shutdown();
-	nfs4_state_init();
+	__nfs4_state_init();
 	nfs4_unlock_state();
 }
 
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -60,121 +60,6 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
-static const char utf8_byte_len[256] = {
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0
-};
-
-static inline int
-is_legal_utf8_sequence(unsigned char *source, int length)
-{
-	unsigned char *ptr;
-	unsigned char c;
-
-	if (length==1) return 1;
-
-	/* Check for overlong sequence, and check second byte */
-	c = *(source + 1);
-	switch (*source) {
-	case 0xE0: /* 3 bytes */
-		if ( c < 0xA0 ) return 0;
-		break;
-	case 0xF0: /* 4 bytes */
-		if ( c < 0x90 ) return 0;
-		break;
-	case 0xF8: /* 5 bytes */
-		if ( c < 0xC8 ) return 0;
-		break;
-	case 0xFC: /* 6 bytes */
-		if ( c < 0x84 ) return 0;
-		break;
-	default:
-		if ( (c & 0xC0) != 0x80) return 0;
-	}
-
-	/* Check that trailing bytes look like 10xxxxxx */
-	for (ptr = source++ + length - 1; ptr>source; ptr--)
-		if ( ((*ptr) & 0xC0) != 0x80 ) return 0;
-	return 1;
-}
-
-/* This does some screening on disallowed unicode characters.  It is NOT
- * comprehensive.
- */
-static int
-is_allowed_utf8_char(unsigned char *source, int length)
-{
-	/* We assume length and source point to a valid utf8 sequence */
-	unsigned char c;
-
-	/* Disallow F0000 and up (in utf8, F3B08080) */
-	if (*source > 0xF3 ) return 0;
-	c = *(source + 1);
-	switch (*source) {
-	case 0xF3:
-		if (c >= 0xB0) return 0;
-		break;
-	/* Disallow D800-F8FF (in utf8, EDA080-EFA3BF */
-	case 0xED:
-		if (c >= 0xA0) return 0;
-		break;
-	case 0xEE:
-		return 0;
-		break;
-	case 0xEF:
-		if (c <= 0xA3) return 0;
-	/* Disallow FFF9-FFFF (EFBFB9-EFBFBF) */
-		if (c==0xBF)
-			/* Don't need to check <=0xBF, since valid utf8 */
-			if ( *(source+2) >= 0xB9) return 0;
-		break;
-	}
-	return 1;
-}
-
-/* This routine should really check to see that the proper stringprep
- * mappings have been applied.  Instead, we do a simple screen of some
- * of the more obvious illegal values by calling is_allowed_utf8_char.
- * This will allow many illegal strings through, but if a client behaves,
- * it will get full functionality.  The other option (apart from full
- * stringprep checking) is to limit everything to an easily handled subset,
- * such as 7-bit ascii.
- *
- * Note - currently calling routines ignore return value except as boolean.
- */
-static int
-check_utf8(char *str, int len)
-{
-	unsigned char *chunk, *sourceend;
-	int chunklen;
-
-	chunk = str;
-	sourceend = str + len;
-
-	while (chunk < sourceend) {
-		chunklen = utf8_byte_len[*chunk];
-		if (!chunklen)
-			return nfserr_inval;
-		if (chunk + chunklen > sourceend)
-			return nfserr_inval;
-		if (!is_legal_utf8_sequence(chunk, chunklen))
-			return nfserr_inval;
-		if (!is_allowed_utf8_char(chunk, chunklen))
-			return nfserr_inval;
-		if ( (chunklen==1) && (!*chunk) )
-			return nfserr_inval; /* Disallow embedded nulls */
-		chunk += chunklen;
-	}
-
-	return 0;
-}
-
 static int
 check_filename(char *str, int len, int err)
 {
@@ -187,7 +72,7 @@ check_filename(char *str, int len, int e
 	for (i = 0; i < len; i++)
 		if (str[i] == '/')
 			return err;
-	return check_utf8(str, len);
+	return 0;
 }
 
 /*
@@ -403,8 +288,6 @@ nfsd4_decode_fattr(struct nfsd4_compound
 			READ_BUF(dummy32);
 			len += XDR_QUADLEN(dummy32) << 2;
 			READMEM(buf, dummy32);
-			if (check_utf8(buf, dummy32))
-				return nfserr_inval;
 			ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
 			status = 0;
 			if (ace.whotype != NFS4_ACL_WHO_NAMED)
@@ -439,8 +322,6 @@ nfsd4_decode_fattr(struct nfsd4_compound
 		READ_BUF(dummy32);
 		len += (XDR_QUADLEN(dummy32) << 2);
 		READMEM(buf, dummy32);
-		if (check_utf8(buf, dummy32))
-			return nfserr_inval;
 		if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
 			goto out_nfserr;
 		iattr->ia_valid |= ATTR_UID;
@@ -452,8 +333,6 @@ nfsd4_decode_fattr(struct nfsd4_compound
 		READ_BUF(dummy32);
 		len += (XDR_QUADLEN(dummy32) << 2);
 		READMEM(buf, dummy32);
-		if (check_utf8(buf, dummy32))
-			return nfserr_inval;
 		if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
 			goto out_nfserr;
 		iattr->ia_valid |= ATTR_GID;
@@ -585,8 +464,6 @@ nfsd4_decode_create(struct nfsd4_compoun
 		READ32(create->cr_linklen);
 		READ_BUF(create->cr_linklen);
 		SAVEMEM(create->cr_linkname, create->cr_linklen);
-		if (check_utf8(create->cr_linkname, create->cr_linklen))
-			return nfserr_inval;
 		break;
 	case NF4BLK:
 	case NF4CHR:
@@ -1454,7 +1331,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 		if (bmval0 & FATTR4_WORD0_ACL) {
 			if (status == -EOPNOTSUPP)
 				bmval0 &= ~FATTR4_WORD0_ACL;
-			else if (status != 0)
+			else if (status == -EINVAL) {
+				status = nfserr_attrnotsupp;
+				goto out;
+			} else if (status != 0)
 				goto out_nfserr;
 		}
 	}
@@ -2191,10 +2071,10 @@ nfsd4_encode_read(struct nfsd4_compoundr
 	}
 	read->rd_vlen = v;
 
-	nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp,
-			   read->rd_offset,
-			   read->rd_iov, read->rd_vlen,
-			   &maxcount);
+	nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
+			read->rd_offset, read->rd_iov, read->rd_vlen,
+			&maxcount);
+
 	if (nfserr == nfserr_symlink)
 		nfserr = nfserr_inval;
 	if (nfserr)
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
+#include <linux/list.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -30,15 +31,8 @@
 #define HASHSIZE		64
 #define REQHASH(xid)		((((xid) >> 24) ^ (xid)) & (HASHSIZE-1))
 
-struct nfscache_head {
-	struct svc_cacherep *	next;
-	struct svc_cacherep *	prev;
-};
-
-static struct nfscache_head *	hash_list;
-static struct svc_cacherep *	lru_head;
-static struct svc_cacherep *	lru_tail;
-static struct svc_cacherep *	nfscache;
+static struct hlist_head *	hash_list;
+static struct list_head 	lru_head;
 static int			cache_disabled = 1;
 
 static int	nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
@@ -54,46 +48,32 @@ void
 nfsd_cache_init(void)
 {
 	struct svc_cacherep	*rp;
-	struct nfscache_head	*rh;
-	size_t			i;
-	unsigned long		order;
+	int			i;
 
-
-	i = CACHESIZE * sizeof (struct svc_cacherep);
-	for (order = 0; (PAGE_SIZE << order) < i; order++)
-		;
-	nfscache = (struct svc_cacherep *)
-		__get_free_pages(GFP_KERNEL, order);
-	if (!nfscache) {
-		printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for reply cache\n", i);
-		return;
+	INIT_LIST_HEAD(&lru_head);
+	i = CACHESIZE;
+	while(i) {
+		rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+		if (!rp) break;
+		list_add(&rp->c_lru, &lru_head);
+		rp->c_state = RC_UNUSED;
+		rp->c_type = RC_NOCACHE;
+		INIT_HLIST_NODE(&rp->c_hash);
+		i--;
 	}
-	memset(nfscache, 0, i);
 
-	i = HASHSIZE * sizeof (struct nfscache_head);
-	hash_list = kmalloc (i, GFP_KERNEL);
+	if (i)
+		printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
+			CACHESIZE, CACHESIZE-i);
+
+	hash_list = kmalloc (HASHSIZE * sizeof(struct hlist_head), GFP_KERNEL);
 	if (!hash_list) {
-		free_pages ((unsigned long)nfscache, order);
-		nfscache = NULL;
-		printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", i);
+		nfsd_cache_shutdown();
+		printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
+			HASHSIZE * sizeof(struct hlist_head));
 		return;
 	}
-
-	for (i = 0, rh = hash_list; i < HASHSIZE; i++, rh++)
-		rh->next = rh->prev = (struct svc_cacherep *) rh;
-
-	for (i = 0, rp = nfscache; i < CACHESIZE; i++, rp++) {
-		rp->c_state = RC_UNUSED;
-		rp->c_type = RC_NOCACHE;
-		rp->c_hash_next =
-		rp->c_hash_prev = rp;
-		rp->c_lru_next = rp + 1;
-		rp->c_lru_prev = rp - 1;
-	}
-	lru_head = nfscache;
-	lru_tail = nfscache + CACHESIZE - 1;
-	lru_head->c_lru_prev = NULL;
-	lru_tail->c_lru_next = NULL;
+	memset(hash_list, 0, HASHSIZE * sizeof(struct hlist_head));
 
 	cache_disabled = 0;
 }
@@ -102,48 +82,30 @@ void
 nfsd_cache_shutdown(void)
 {
 	struct svc_cacherep	*rp;
-	size_t			i;
-	unsigned long		order;
 
-	for (rp = lru_head; rp; rp = rp->c_lru_next) {
+	while (!list_empty(&lru_head)) {
+		rp = list_entry(lru_head.next, struct svc_cacherep, c_lru);
 		if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
 			kfree(rp->c_replvec.iov_base);
+		list_del(&rp->c_lru);
+		kfree(rp);
 	}
 
 	cache_disabled = 1;
 
-	i = CACHESIZE * sizeof (struct svc_cacherep);
-	for (order = 0; (PAGE_SIZE << order) < i; order++)
-		;
-	free_pages ((unsigned long)nfscache, order);
-	nfscache = NULL;
-	kfree (hash_list);
+	if (hash_list)
+		kfree (hash_list);
 	hash_list = NULL;
 }
 
 /*
- * Move cache entry to front of LRU list
+ * Move cache entry to end of LRU list
  */
 static void
-lru_put_front(struct svc_cacherep *rp)
+lru_put_end(struct svc_cacherep *rp)
 {
-	struct svc_cacherep	*prev = rp->c_lru_prev,
-				*next = rp->c_lru_next;
-
-	if (prev)
-		prev->c_lru_next = next;
-	else
-		lru_head = next;
-	if (next)
-		next->c_lru_prev = prev;
-	else
-		lru_tail = prev;
-
-	rp->c_lru_next = lru_head;
-	rp->c_lru_prev = NULL;
-	if (lru_head)
-		lru_head->c_lru_prev = rp;
-	lru_head = rp;
+	list_del(&rp->c_lru);
+	list_add_tail(&rp->c_lru, &lru_head);
 }
 
 /*
@@ -152,17 +114,8 @@ lru_put_front(struct svc_cacherep *rp)
 static void
 hash_refile(struct svc_cacherep *rp)
 {
-	struct svc_cacherep	*prev = rp->c_hash_prev,
-				*next = rp->c_hash_next;
-	struct nfscache_head	*head = hash_list + REQHASH(rp->c_xid);
-
-	prev->c_hash_next = next;
-	next->c_hash_prev = prev;
-
-	rp->c_hash_next = head->next;
-	rp->c_hash_prev = (struct svc_cacherep *) head;
-	head->next->c_hash_prev = rp;
-	head->next = rp;
+	hlist_del_init(&rp->c_hash);
+	hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid));
 }
 
 /*
@@ -173,7 +126,9 @@ hash_refile(struct svc_cacherep *rp)
 int
 nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
 {
-	struct svc_cacherep	*rh, *rp;
+	struct hlist_node	*hn;
+	struct hlist_head 	*rh;
+	struct svc_cacherep	*rp;
 	u32			xid = rqstp->rq_xid,
 				proto =  rqstp->rq_prot,
 				vers = rqstp->rq_vers,
@@ -190,8 +145,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp
 	spin_lock(&cache_lock);
 	rtn = RC_DOIT;
 
-	rp = rh = (struct svc_cacherep *) &hash_list[REQHASH(xid)];
-	while ((rp = rp->c_hash_next) != rh) {
+	rh = &hash_list[REQHASH(xid)];
+	hlist_for_each_entry(rp, hn, rh, c_hash) {
 		if (rp->c_state != RC_UNUSED &&
 		    xid == rp->c_xid && proc == rp->c_proc &&
 		    proto == rp->c_prot && vers == rp->c_vers &&
@@ -206,7 +161,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp
 	/* This loop shouldn't take more than a few iterations normally */
 	{
 	int	safe = 0;
-	for (rp = lru_tail; rp; rp = rp->c_lru_prev) {
+	list_for_each_entry(rp, &lru_head, c_lru) {
 		if (rp->c_state != RC_INPROG)
 			break;
 		if (safe++ > CACHESIZE) {
@@ -254,7 +209,7 @@ found_entry:
 	/* We found a matching entry which is either in progress or done. */
 	age = jiffies - rp->c_timestamp;
 	rp->c_timestamp = jiffies;
-	lru_put_front(rp);
+	lru_put_end(rp);
 
 	rtn = RC_DROPIT;
 	/* Request being processed or excessive rexmits */
@@ -343,7 +298,7 @@ nfsd_cache_update(struct svc_rqst *rqstp
 		break;
 	}
 	spin_lock(&cache_lock);
-	lru_put_front(rp);
+	lru_put_end(rp);
 	rp->c_secure = rqstp->rq_secure;
 	rp->c_type = cachetype;
 	rp->c_state = RC_DONE;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -41,7 +41,7 @@ extern struct export_operations export_o
  * if not, require that we can walk up to exp->ex_dentry
  * doing some checks on the 'x' bits
  */
-int nfsd_acceptable(void *expv, struct dentry *dentry)
+static int nfsd_acceptable(void *expv, struct dentry *dentry)
 {
 	struct svc_export *exp = expv;
 	int rv;
@@ -280,8 +280,8 @@ out:
  * an inode.  In this case a call to fh_update should be made
  * before the fh goes out on the wire ...
  */
-inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
-		      __u32 *datap, int *maxsize)
+static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
+			     __u32 *datap, int *maxsize)
 {
 	struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
 	
@@ -297,8 +297,9 @@ inline int _fh_update(struct dentry *den
 /*
  * for composing old style file handles
  */
-inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp,
-			   struct knfsd_fh *fh)
+static inline void _fh_update_old(struct dentry *dentry,
+				  struct svc_export *exp,
+				  struct knfsd_fh *fh)
 {
 	fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino);
 	fh->ofh_generation = dentry->d_inode->i_generation;
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -137,7 +137,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, s
 	svc_reserve(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
-	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
+	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
 				  argp->offset,
 			   	  argp->vec, argp->vlen,
 				  &resp->count);
@@ -160,7 +160,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, 
 		SVCFH_fmt(&argp->fh),
 		argp->len, argp->offset);
 
-	nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
+	nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
 				   argp->offset,
 				   argp->vec, argp->vlen,
 				   argp->len,
@@ -590,6 +590,7 @@ nfserrno (int errno)
 		{ nfserr_dropit, -EAGAIN },
 		{ nfserr_dropit, -ENOMEM },
 		{ nfserr_badname, -ESRCH },
+		{ nfserr_io, -ETXTBSY },
 		{ -1, -EIO }
 	};
 	int	i;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -60,7 +60,7 @@ struct nfsd_list {
 	struct list_head 	list;
 	struct task_struct	*task;
 };
-struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
+static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
 
 /*
  * Maximum number of nfsd processes
@@ -92,7 +92,9 @@ nfsd_svc(unsigned short port, int nrserv
 	
 	/* Readahead param cache - will no-op if it already exists */
 	error =	nfsd_racache_init(2*nrservs);
-	nfs4_state_init();
+	if (error<0)
+		goto out;
+	error = nfs4_state_init();
 	if (error<0)
 		goto out;
 	if (!nfsd_serv) {
@@ -256,6 +258,8 @@ nfsd(struct svc_rqst *rqstp)
 				break;
 		err = signo;
 	}
+	/* Clear signals before calling lockd_down() and svc_exit_thread() */
+	flush_signals(current);
 
 	lock_kernel();
 
@@ -378,4 +382,6 @@ struct svc_program		nfsd_program = {
 	.pg_name		= "nfsd",		/* program name */
 	.pg_class		= "nfsd",		/* authentication class */
 	.pg_stats		= &nfsd_svcstats,	/* version table */
+	.pg_authenticate	= &svc_set_client,	/* export authentication */
+
 };
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/namei.h>
 #include <linux/vfs.h>
+#include <linux/delay.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #ifdef CONFIG_NFSD_V3
@@ -392,7 +393,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
 	}
 out:
 	kfree(buf);
-	return (error);
+	return error;
 }
 
 int
@@ -416,7 +417,10 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
 		flags = NFS4_ACL_DIR;
 
 	error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
-	if (error < 0)
+	if (error == -EINVAL) {
+		error = nfserr_attrnotsupp;
+		goto out;
+	} else if (error < 0)
 		goto out_nfserr;
 
 	if (pacl) {
@@ -707,8 +711,8 @@ nfsd_close(struct file *filp)
  * As this calls fsync (not fdatasync) there is no need for a write_inode
  * after it.
  */
-inline void nfsd_dosync(struct file *filp, struct dentry *dp, 
-			struct file_operations *fop)
+static inline void nfsd_dosync(struct file *filp, struct dentry *dp,
+			       struct file_operations *fop)
 {
 	struct inode *inode = dp->d_inode;
 	int (*fsync) (struct file *, struct dentry *, int);
@@ -720,7 +724,7 @@ inline void nfsd_dosync(struct file *fil
 }
 	
 
-void
+static void
 nfsd_sync(struct file *filp)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
@@ -730,7 +734,7 @@ nfsd_sync(struct file *filp)
 	up(&inode->i_sem);
 }
 
-void
+static void
 nfsd_sync_dir(struct dentry *dp)
 {
 	nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
@@ -810,30 +814,21 @@ nfsd_read_actor(read_descriptor_t *desc,
 	return size;
 }
 
-/*
- * Read data from a file. count must contain the requested read count
- * on entry. On return, *count contains the number of bytes actually read.
- * N.B. After this call fhp needs an fh_put
- */
-int
-nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-          struct kvec *vec, int vlen, unsigned long *count)
+static inline int
+nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+              loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
+	struct inode *inode;
 	struct raparms	*ra;
 	mm_segment_t	oldfs;
 	int		err;
-	struct file	*file;
-	struct inode	*inode;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
-	if (err)
-		goto out;
 	err = nfserr_perm;
 	inode = file->f_dentry->d_inode;
 #ifdef MSNFS
 	if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 		(!lock_may_read(inode, offset, *count)))
-		goto out_close;
+		goto out;
 #endif
 
 	/* Get readahead parameters */
@@ -869,41 +864,28 @@ nfsd_read(struct svc_rqst *rqstp, struct
 		dnotify_parent(file->f_dentry, DN_ACCESS);
 	} else 
 		err = nfserrno(err);
-out_close:
-	nfsd_close(file);
 out:
 	return err;
 }
 
-/*
- * Write data to a file.
- * The stable flag requests synchronous writes.
- * N.B. After this call fhp needs an fh_put
- */
-int
-nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-				struct kvec *vec, int vlen,
+static inline int
+nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+				loff_t offset, struct kvec *vec, int vlen,
 	   			unsigned long cnt, int *stablep)
 {
 	struct svc_export	*exp;
-	struct file		*file;
 	struct dentry		*dentry;
 	struct inode		*inode;
 	mm_segment_t		oldfs;
 	int			err = 0;
 	int			stable = *stablep;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
-	if (err)
-		goto out;
-	if (!cnt)
-		goto out_close;
 	err = nfserr_perm;
 
 #ifdef MSNFS
 	if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 		(!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
-		goto out_close;
+		goto out;
 #endif
 
 	dentry = file->f_dentry;
@@ -968,8 +950,7 @@ nfsd_write(struct svc_rqst *rqstp, struc
 			if (atomic_read(&inode->i_writecount) > 1
 			    || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) {
 				dprintk("nfsd: write defer %d\n", current->pid);
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout((HZ+99)/100);
+				msleep(10);
 				dprintk("nfsd: write resume %d\n", current->pid);
 			}
 
@@ -990,12 +971,71 @@ nfsd_write(struct svc_rqst *rqstp, struc
 		err = 0;
 	else 
 		err = nfserrno(err);
-out_close:
-	nfsd_close(file);
 out:
 	return err;
 }
 
+/*
+ * Read data from a file. count must contain the requested read count
+ * on entry. On return, *count contains the number of bytes actually read.
+ * N.B. After this call fhp needs an fh_put
+ */
+int
+nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+		loff_t offset, struct kvec *vec, int vlen,
+		unsigned long *count)
+{
+	int		err;
+
+	if (file) {
+		err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+				MAY_READ|MAY_OWNER_OVERRIDE);
+		if (err)
+			goto out;
+		err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+	} else {
+		err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
+		if (err)
+			goto out;
+		err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+		nfsd_close(file);
+	}
+out:
+	return err;
+}
+
+/*
+ * Write data to a file.
+ * The stable flag requests synchronous writes.
+ * N.B. After this call fhp needs an fh_put
+ */
+int
+nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+		loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
+		int *stablep)
+{
+	int			err = 0;
+
+	if (file) {
+		err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+				MAY_WRITE|MAY_OWNER_OVERRIDE);
+		if (err)
+			goto out;
+		err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
+				stablep);
+	} else {
+		err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
+		if (err)
+			goto out;
+
+		if (cnt)
+			err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
+					     cnt, stablep);
+		nfsd_close(file);
+	}
+out:
+	return err;
+}
 
 #ifdef CONFIG_NFSD_V3
 /*
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -243,7 +243,7 @@ void unload_nls(struct nls_table *nls)
 	module_put(nls->owner);
 }
 
-wchar_t charset2uni[256] = {
+static wchar_t charset2uni[256] = {
 	/* 0x00*/
 	0x0000, 0x0001, 0x0002, 0x0003,
 	0x0004, 0x0005, 0x0006, 0x0007,
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -203,7 +203,7 @@ config ULTRIX_PARTITION
 
 config SUN_PARTITION
 	bool "Sun partition tables support" if PARTITION_ADVANCED
-	default y if (SPARC32 || SPARC64)
+	default y if (SPARC32 || SPARC64 || SUN3 || SUN3X)
 	---help---
 	  Like most systems, SunOS uses its own hard disk partition table
 	  format, incompatible with all others. Saying Y here allows you to
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -337,6 +337,7 @@ void register_disk(struct gendisk *disk)
 	if ((err = kobject_add(&disk->kobj)))
 		return;
 	disk_sysfs_symlinks(disk);
+	kobject_hotplug(&disk->kobj, KOBJ_ADD);
 
 	/* No minors to use for partitions */
 	if (disk->minors == 1) {
@@ -441,5 +442,6 @@ void del_gendisk(struct gendisk *disk)
 		sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
 		put_device(disk->driverfs_dev);
 	}
+	kobject_hotplug(&disk->kobj, KOBJ_REMOVE);
 	kobject_del(&disk->kobj);
 }
diff --git a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -224,6 +224,7 @@ pipe_writev(struct file *filp, const str
 	int do_wakeup;
 	struct iovec *iov = (struct iovec *)_iov;
 	size_t total_len;
+	ssize_t chars;
 
 	total_len = iov_length(iov, nr_segs);
 	/* Null write succeeds. */
@@ -242,24 +243,26 @@ pipe_writev(struct file *filp, const str
 	}
 
 	/* We try to merge small writes */
-	if (info->nrbufs && total_len < PAGE_SIZE) {
+	chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
+	if (info->nrbufs && chars != 0) {
 		int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1);
 		struct pipe_buffer *buf = info->bufs + lastbuf;
 		struct pipe_buf_operations *ops = buf->ops;
 		int offset = buf->offset + buf->len;
-		if (ops->can_merge && offset + total_len <= PAGE_SIZE) {
+		if (ops->can_merge && offset + chars <= PAGE_SIZE) {
 			void *addr = ops->map(filp, info, buf);
-			int error = pipe_iov_copy_from_user(offset + addr, iov, total_len);
+			int error = pipe_iov_copy_from_user(offset + addr, iov, chars);
 			ops->unmap(info, buf);
 			ret = error;
 			do_wakeup = 1;
 			if (error)
 				goto out;
-			buf->len += total_len;
-			ret = total_len;
-			goto out;
+			buf->len += chars;
+			total_len -= chars;
+			ret = chars;
+			if (!total_len)
+				goto out;
 		}
-			
 	}
 
 	for (;;) {
@@ -271,7 +274,6 @@ pipe_writev(struct file *filp, const str
 		}
 		bufs = info->nrbufs;
 		if (bufs < PIPE_BUFFERS) {
-			ssize_t chars;
 			int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1);
 			struct pipe_buffer *buf = info->bufs + newbuf;
 			struct page *page = info->tmp_page;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -35,7 +35,7 @@ EXPORT_SYMBOL(posix_acl_permission);
  * Allocate a new ACL with the specified number of entries.
  */
 struct posix_acl *
-posix_acl_alloc(int count, int flags)
+posix_acl_alloc(int count, unsigned int __nocast flags)
 {
 	const size_t size = sizeof(struct posix_acl) +
 	                    count * sizeof(struct posix_acl_entry);
@@ -51,7 +51,7 @@ posix_acl_alloc(int count, int flags)
  * Clone an ACL.
  */
 struct posix_acl *
-posix_acl_clone(const struct posix_acl *acl, int flags)
+posix_acl_clone(const struct posix_acl *acl, unsigned int __nocast flags)
 {
 	struct posix_acl *clone = NULL;
 
@@ -185,7 +185,7 @@ posix_acl_equiv_mode(const struct posix_
  * Create an ACL representing the file mode permission bits of an inode.
  */
 struct posix_acl *
-posix_acl_from_mode(mode_t mode, int flags)
+posix_acl_from_mode(mode_t mode, unsigned int __nocast flags)
 {
 	struct posix_acl *acl = posix_acl_alloc(3, flags);
 	if (!acl)
diff --git a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -73,6 +73,7 @@
 #include <linux/highmem.h>
 #include <linux/file.h>
 #include <linux/times.h>
+#include <linux/cpuset.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -239,6 +240,8 @@ static inline char * task_sig(struct tas
 {
 	sigset_t pending, shpending, blocked, ignored, caught;
 	int num_threads = 0;
+	unsigned long qsize = 0;
+	unsigned long qlim = 0;
 
 	sigemptyset(&pending);
 	sigemptyset(&shpending);
@@ -255,11 +258,14 @@ static inline char * task_sig(struct tas
 		blocked = p->blocked;
 		collect_sigign_sigcatch(p, &ignored, &caught);
 		num_threads = atomic_read(&p->signal->count);
+		qsize = atomic_read(&p->user->sigpending);
+		qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
 		spin_unlock_irq(&p->sighand->siglock);
 	}
 	read_unlock(&tasklist_lock);
 
 	buffer += sprintf(buffer, "Threads:\t%d\n", num_threads);
+	buffer += sprintf(buffer, "SigQ:\t%lu/%lu\n", qsize, qlim);
 
 	/* render them all */
 	buffer = render_sigset_t("SigPnd:\t", &pending, buffer);
@@ -295,6 +301,7 @@ int proc_pid_status(struct task_struct *
 	}
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
+	buffer = cpuset_task_status_allowed(task, buffer);
 #if defined(CONFIG_ARCH_S390)
 	buffer = task_show_regs(task, buffer);
 #endif
@@ -317,6 +324,7 @@ static int do_task_stat(struct task_stru
 	unsigned long  min_flt = 0,  maj_flt = 0;
 	cputime_t cutime, cstime, utime, stime;
 	unsigned long rsslim = 0;
+	unsigned long it_real_value = 0;
 	struct task_struct *t;
 	char tcomm[sizeof(task->comm)];
 
@@ -372,6 +380,7 @@ static int do_task_stat(struct task_stru
 			utime = cputime_add(utime, task->signal->utime);
 			stime = cputime_add(stime, task->signal->stime);
 		}
+		it_real_value = task->signal->it_real_value;
 	}
 	ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
 	read_unlock(&tasklist_lock);
@@ -420,10 +429,10 @@ static int do_task_stat(struct task_stru
 		priority,
 		nice,
 		num_threads,
-		jiffies_to_clock_t(task->it_real_value),
+		jiffies_to_clock_t(it_real_value),
 		start_time,
 		vsize,
-		mm ? mm->rss : 0, /* you might want to shift this left 3 */
+		mm ? get_mm_counter(mm, rss) : 0, /* you might want to shift this left 3 */
 	        rsslim,
 		mm ? mm->start_code : 0,
 		mm ? mm->end_code : 0,
diff --git a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -32,6 +32,9 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/seccomp.h>
+#include <linux/cpuset.h>
+#include <linux/audit.h>
 #include "internal.h"
 
 /*
@@ -49,6 +52,9 @@ enum pid_directory_inos {
 	PROC_TGID_TASK,
 	PROC_TGID_STATUS,
 	PROC_TGID_MEM,
+#ifdef CONFIG_SECCOMP
+	PROC_TGID_SECCOMP,
+#endif
 	PROC_TGID_CWD,
 	PROC_TGID_ROOT,
 	PROC_TGID_EXE,
@@ -64,6 +70,9 @@ enum pid_directory_inos {
 #ifdef CONFIG_SCHEDSTATS
 	PROC_TGID_SCHEDSTAT,
 #endif
+#ifdef CONFIG_CPUSETS
+	PROC_TGID_CPUSET,
+#endif
 #ifdef CONFIG_SECURITY
 	PROC_TGID_ATTR,
 	PROC_TGID_ATTR_CURRENT,
@@ -80,6 +89,9 @@ enum pid_directory_inos {
 	PROC_TID_INO,
 	PROC_TID_STATUS,
 	PROC_TID_MEM,
+#ifdef CONFIG_SECCOMP
+	PROC_TID_SECCOMP,
+#endif
 	PROC_TID_CWD,
 	PROC_TID_ROOT,
 	PROC_TID_EXE,
@@ -95,6 +107,9 @@ enum pid_directory_inos {
 #ifdef CONFIG_SCHEDSTATS
 	PROC_TID_SCHEDSTAT,
 #endif
+#ifdef CONFIG_CPUSETS
+	PROC_TID_CPUSET,
+#endif
 #ifdef CONFIG_SECURITY
 	PROC_TID_ATTR,
 	PROC_TID_ATTR_CURRENT,
@@ -130,6 +145,9 @@ static struct pid_entry tgid_base_stuff[
 	E(PROC_TGID_STATM,     "statm",   S_IFREG|S_IRUGO),
 	E(PROC_TGID_MAPS,      "maps",    S_IFREG|S_IRUGO),
 	E(PROC_TGID_MEM,       "mem",     S_IFREG|S_IRUSR|S_IWUSR),
+#ifdef CONFIG_SECCOMP
+	E(PROC_TGID_SECCOMP,   "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+#endif
 	E(PROC_TGID_CWD,       "cwd",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
@@ -143,6 +161,9 @@ static struct pid_entry tgid_base_stuff[
 #ifdef CONFIG_SCHEDSTATS
 	E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
 #endif
+#ifdef CONFIG_CPUSETS
+	E(PROC_TGID_CPUSET,    "cpuset",  S_IFREG|S_IRUGO),
+#endif
 	E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
 	E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
 #ifdef CONFIG_AUDITSYSCALL
@@ -160,6 +181,9 @@ static struct pid_entry tid_base_stuff[]
 	E(PROC_TID_STATM,      "statm",   S_IFREG|S_IRUGO),
 	E(PROC_TID_MAPS,       "maps",    S_IFREG|S_IRUGO),
 	E(PROC_TID_MEM,        "mem",     S_IFREG|S_IRUSR|S_IWUSR),
+#ifdef CONFIG_SECCOMP
+	E(PROC_TID_SECCOMP,    "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+#endif
 	E(PROC_TID_CWD,        "cwd",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
@@ -173,6 +197,9 @@ static struct pid_entry tid_base_stuff[]
 #ifdef CONFIG_SCHEDSTATS
 	E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
 #endif
+#ifdef CONFIG_CPUSETS
+	E(PROC_TID_CPUSET,     "cpuset",  S_IFREG|S_IRUGO),
+#endif
 	E(PROC_TID_OOM_SCORE,  "oom_score",S_IFREG|S_IRUGO),
 	E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
 #ifdef CONFIG_AUDITSYSCALL
@@ -689,7 +716,7 @@ static struct file_operations proc_mem_o
 	.open		= mem_open,
 };
 
-static ssize_t oom_adjust_read(struct file *file, char *buf,
+static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 				size_t count, loff_t *ppos)
 {
 	struct task_struct *task = proc_task(file->f_dentry->d_inode);
@@ -709,7 +736,7 @@ static ssize_t oom_adjust_read(struct fi
 	return count;
 }
 
-static ssize_t oom_adjust_write(struct file *file, const char *buf,
+static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
 	struct task_struct *task = proc_task(file->f_dentry->d_inode);
@@ -724,7 +751,7 @@ static ssize_t oom_adjust_write(struct f
 	if (copy_from_user(buffer, buf, count))
 		return -EFAULT;
 	oom_adjust = simple_strtol(buffer, &end, 0);
-	if (oom_adjust < -16 || oom_adjust > 15)
+	if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
 		return -EINVAL;
 	if (*end == '\n')
 		end++;
@@ -735,8 +762,8 @@ static ssize_t oom_adjust_write(struct f
 }
 
 static struct file_operations proc_oom_adjust_operations = {
-	read:		oom_adjust_read,
-	write:		oom_adjust_write,
+	.read		= oom_adjust_read,
+	.write		= oom_adjust_write,
 };
 
 static struct inode_operations proc_mem_inode_operations = {
@@ -793,7 +820,7 @@ static ssize_t proc_loginuid_write(struc
 		goto out_free_page;
 
 	}
-	length = audit_set_loginuid(task->audit_context, loginuid);
+	length = audit_set_loginuid(task, loginuid);
 	if (likely(length == 0))
 		length = count;
 
@@ -808,6 +835,61 @@ static struct file_operations proc_login
 };
 #endif
 
+#ifdef CONFIG_SECCOMP
+static ssize_t seccomp_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+	char __buf[20];
+	loff_t __ppos = *ppos;
+	size_t len;
+
+	/* no need to print the trailing zero, so use only len */
+	len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
+	if (__ppos >= len)
+		return 0;
+	if (count > len - __ppos)
+		count = len - __ppos;
+	if (copy_to_user(buf, __buf + __ppos, count))
+		return -EFAULT;
+	*ppos = __ppos + count;
+	return count;
+}
+
+static ssize_t seccomp_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+	char __buf[20], *end;
+	unsigned int seccomp_mode;
+
+	/* can set it only once to be even more secure */
+	if (unlikely(tsk->seccomp.mode))
+		return -EPERM;
+
+	memset(__buf, 0, sizeof(__buf));
+	count = min(count, sizeof(__buf) - 1);
+	if (copy_from_user(__buf, buf, count))
+		return -EFAULT;
+	seccomp_mode = simple_strtoul(__buf, &end, 0);
+	if (*end == '\n')
+		end++;
+	if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
+		tsk->seccomp.mode = seccomp_mode;
+		set_tsk_thread_flag(tsk, TIF_SECCOMP);
+	} else
+		return -EINVAL;
+	if (unlikely(!(end - __buf)))
+		return -EIO;
+	return end - __buf;
+}
+
+static struct file_operations proc_seccomp_operations = {
+	.read		= seccomp_read,
+	.write		= seccomp_write,
+};
+#endif /* CONFIG_SECCOMP */
+
 static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
@@ -1337,6 +1419,8 @@ static struct file_operations proc_tgid_
 static struct inode_operations proc_tgid_attr_inode_operations;
 #endif
 
+static int get_tid_list(int index, unsigned int *tids, struct inode *dir);
+
 /* SMP-safe */
 static struct dentry *proc_pident_lookup(struct inode *dir, 
 					 struct dentry *dentry,
@@ -1376,7 +1460,7 @@ static struct dentry *proc_pident_lookup
 	 */
 	switch(p->type) {
 		case PROC_TGID_TASK:
-			inode->i_nlink = 3;
+			inode->i_nlink = 2 + get_tid_list(2, NULL, dir);
 			inode->i_op = &proc_task_inode_operations;
 			inode->i_fop = &proc_task_operations;
 			break;
@@ -1443,6 +1527,12 @@ static struct dentry *proc_pident_lookup
 			inode->i_op = &proc_mem_inode_operations;
 			inode->i_fop = &proc_mem_operations;
 			break;
+#ifdef CONFIG_SECCOMP
+		case PROC_TID_SECCOMP:
+		case PROC_TGID_SECCOMP:
+			inode->i_fop = &proc_seccomp_operations;
+			break;
+#endif /* CONFIG_SECCOMP */
 		case PROC_TID_MOUNTS:
 		case PROC_TGID_MOUNTS:
 			inode->i_fop = &proc_mounts_operations;
@@ -1483,6 +1573,12 @@ static struct dentry *proc_pident_lookup
 			ei->op.proc_read = proc_pid_schedstat;
 			break;
 #endif
+#ifdef CONFIG_CPUSETS
+		case PROC_TID_CPUSET:
+		case PROC_TGID_CPUSET:
+			inode->i_fop = &proc_cpuset_operations;
+			break;
+#endif
 		case PROC_TID_OOM_SCORE:
 		case PROC_TGID_OOM_SCORE:
 			inode->i_fop = &proc_info_file_operations;
@@ -1607,13 +1703,13 @@ static struct inode_operations proc_self
 };
 
 /**
- * proc_pid_unhash -  Unhash /proc/<pid> entry from the dcache.
+ * proc_pid_unhash -  Unhash /proc/@pid entry from the dcache.
  * @p: task that should be flushed.
  *
- * Drops the /proc/<pid> dcache entry from the hash chains.
+ * Drops the /proc/@pid dcache entry from the hash chains.
  *
- * Dropping /proc/<pid> entries and detach_pid must be synchroneous,
- * otherwise e.g. /proc/<pid>/exe might point to the wrong executable,
+ * Dropping /proc/@pid entries and detach_pid must be synchroneous,
+ * otherwise e.g. /proc/@pid/exe might point to the wrong executable,
  * if the pid value is immediately reused. This is enforced by
  * - caller must acquire spin_lock(p->proc_lock)
  * - must be called before detach_pid()
@@ -1630,19 +1726,23 @@ struct dentry *proc_pid_unhash(struct ta
 	if (proc_dentry != NULL) {
 
 		spin_lock(&dcache_lock);
+		spin_lock(&proc_dentry->d_lock);
 		if (!d_unhashed(proc_dentry)) {
 			dget_locked(proc_dentry);
 			__d_drop(proc_dentry);
-		} else
+			spin_unlock(&proc_dentry->d_lock);
+		} else {
+			spin_unlock(&proc_dentry->d_lock);
 			proc_dentry = NULL;
+		}
 		spin_unlock(&dcache_lock);
 	}
 	return proc_dentry;
 }
 
 /**
- * proc_pid_flush - recover memory used by stale /proc/<pid>/x entries
- * @proc_entry: directoy to prune.
+ * proc_pid_flush - recover memory used by stale /proc/@pid/x entries
+ * @proc_dentry: directoy to prune.
  *
  * Shrink the /proc directory that was used by the just killed thread.
  */
@@ -1702,8 +1802,12 @@ struct dentry *proc_pid_lookup(struct in
 	inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
 	inode->i_op = &proc_tgid_base_inode_operations;
 	inode->i_fop = &proc_tgid_base_operations;
-	inode->i_nlink = 3;
 	inode->i_flags|=S_IMMUTABLE;
+#ifdef CONFIG_SECURITY
+	inode->i_nlink = 5;
+#else
+	inode->i_nlink = 4;
+#endif
 
 	dentry->d_op = &pid_base_dentry_operations;
 
@@ -1757,8 +1861,12 @@ static struct dentry *proc_task_lookup(s
 	inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
 	inode->i_op = &proc_tid_base_inode_operations;
 	inode->i_fop = &proc_tid_base_operations;
-	inode->i_nlink = 3;
 	inode->i_flags|=S_IMMUTABLE;
+#ifdef CONFIG_SECURITY
+	inode->i_nlink = 4;
+#else
+	inode->i_nlink = 3;
+#endif
 
 	dentry->d_op = &pid_base_dentry_operations;
 
@@ -1837,7 +1945,8 @@ static int get_tid_list(int index, unsig
 
 		if (--index >= 0)
 			continue;
-		tids[nr_tids] = tid;
+		if (tids != NULL)
+			tids[nr_tids] = tid;
 		nr_tids++;
 		if (nr_tids >= PROC_MAXPIDS)
 			break;
@@ -1937,6 +2046,7 @@ static int proc_task_readdir(struct file
 	}
 
 	nr_tids = get_tid_list(pos, tid_array, inode);
+	inode->i_nlink = pos + nr_tids;
 
 	for (i = 0; i < nr_tids; i++) {
 		unsigned long j = PROC_NUMBUF;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -14,7 +14,6 @@
 #include <linux/limits.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/parser.h>
 #include <linux/smp_lock.h>
 
 #include <asm/system.h>
@@ -143,51 +142,6 @@ static struct super_operations proc_sops
 	.remount_fs	= proc_remount,
 };
 
-enum {
-	Opt_uid, Opt_gid, Opt_err
-};
-
-static match_table_t tokens = {
-	{Opt_uid, "uid=%u"},
-	{Opt_gid, "gid=%u"},
-	{Opt_err, NULL}
-};
-
-static int parse_options(char *options,uid_t *uid,gid_t *gid)
-{
-	char *p;
-	int option;
-
-	*uid = current->uid;
-	*gid = current->gid;
-	if (!options)
-		return 1;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		substring_t args[MAX_OPT_ARGS];
-		int token;
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_uid:
-			if (match_int(args, &option))
-				return 0;
-			*uid = option;
-			break;
-		case Opt_gid:
-			if (match_int(args, &option))
-				return 0;
-			*gid = option;
-			break;
-		default:
-			return 0;
-		}
-	}
-	return 1;
-}
-
 struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
 				struct proc_dir_entry *de)
 {
@@ -249,10 +203,11 @@ int proc_fill_super(struct super_block *
 	 * Fixup the root inode's nlink value
 	 */
 	root_inode->i_nlink += nr_processes();
+	root_inode->i_uid = 0;
+	root_inode->i_gid = 0;
 	s->s_root = d_alloc_root(root_inode);
 	if (!s->s_root)
 		goto out_no_root;
-	parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
 	return 0;
 
 out_no_root:
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -84,7 +84,7 @@ static size_t get_kcore_size(int *nphdr,
 	}
 	*elf_buflen =	sizeof(struct elfhdr) + 
 			(*nphdr + 2)*sizeof(struct elf_phdr) + 
-			3 * sizeof(struct memelfnote) +
+			3 * (sizeof(struct elf_note) + 4) +
 			sizeof(struct elf_prstatus) +
 			sizeof(struct elf_prpsinfo) +
 			sizeof(struct task_struct);
diff --git a/fs/proc/mmu.c b/fs/proc/mmu.c
--- a/fs/proc/mmu.c
+++ b/fs/proc/mmu.c
@@ -50,13 +50,23 @@ void get_vmalloc_info(struct vmalloc_inf
 		read_lock(&vmlist_lock);
 
 		for (vma = vmlist; vma; vma = vma->next) {
+			unsigned long addr = (unsigned long) vma->addr;
+
+			/*
+			 * Some archs keep another range for modules in vmlist
+			 */
+			if (addr < VMALLOC_START)
+				continue;
+			if (addr >= VMALLOC_END)
+				break;
+
 			vmi->used += vma->size;
 
-			free_area_size = (unsigned long) vma->addr - prev_end;
+			free_area_size = addr - prev_end;
 			if (vmi->largest_chunk < free_area_size)
 				vmi->largest_chunk = free_area_size;
 
-			prev_end = vma->size + (unsigned long) vma->addr;
+			prev_end = vma->size + addr;
 		}
 
 		if (VMALLOC_END - prev_end > vmi->largest_chunk)
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -12,15 +12,8 @@
 #include <asm/uaccess.h>
 
 #ifndef HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de)
-{
-}
-
-static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de)
-{
-}
-
-static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de)
+static inline void set_node_proc_entry(struct device_node *np,
+				       struct proc_dir_entry *de)
 {
 }
 #endif
@@ -58,89 +51,67 @@ static int property_read_proc(char *page
 /*
  * Process a node, adding entries for its children and its properties.
  */
-void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de)
+void proc_device_tree_add_node(struct device_node *np,
+			       struct proc_dir_entry *de)
 {
 	struct property *pp;
 	struct proc_dir_entry *ent;
-	struct device_node *child, *sib;
-	const char *p, *at;
-	int l;
-	struct proc_dir_entry *list, **lastp, *al;
+	struct device_node *child;
+	struct proc_dir_entry *list = NULL, **lastp;
+	const char *p;
 
 	set_node_proc_entry(np, de);
 	lastp = &list;
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		/*
-		 * Unfortunately proc_register puts each new entry
-		 * at the beginning of the list.  So we rearrange them.
-		 */
-		ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ?
-					     S_IRUGO : S_IRUSR, de, property_read_proc, pp);
-		if (ent == 0)
-			break;
-		if (!strncmp(pp->name, "security-", 9))
-		     ent->size = 0; /* don't leak number of password chars */
-		else
-		     ent->size = pp->length;
-		*lastp = ent;
-		lastp = &ent->next;
-	}
-	child = NULL;
-	while ((child = of_get_next_child(np, child))) {
+	for (child = NULL; (child = of_get_next_child(np, child));) {
 		p = strrchr(child->full_name, '/');
 		if (!p)
 			p = child->full_name;
 		else
 			++p;
-		/* chop off '@0' if the name ends with that */
-		l = strlen(p);
-		if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
-			l -= 2;
 		ent = proc_mkdir(p, de);
 		if (ent == 0)
 			break;
 		*lastp = ent;
+		ent->next = NULL;
 		lastp = &ent->next;
 		proc_device_tree_add_node(child, ent);
-
-		/*
-		 * If we left the address part on the name, consider
-		 * adding symlinks from the name and address parts.
-		 */
-		if (p[l] != 0 || (at = strchr(p, '@')) == 0)
-			continue;
-
+	}
+	of_node_put(child);
+	for (pp = np->properties; pp != 0; pp = pp->next) {
 		/*
-		 * If this is the first node with a given name property,
-		 * add a symlink with the name property as its name.
+		 * Yet another Apple device-tree bogosity: on some machines,
+		 * they have properties & nodes with the same name. Those
+		 * properties are quite unimportant for us though, thus we
+		 * simply "skip" them here, but we do have to check.
 		 */
-		sib = NULL;
-		while ((sib = of_get_next_child(np, sib)) && sib != child)
-			if (sib->name && strcmp(sib->name, child->name) == 0)
-				break;
-		if (sib == child && strncmp(p, child->name, l) != 0) {
-			al = proc_symlink(child->name, de, ent->name);
-			if (al == 0) {
-				of_node_put(sib);
+		for (ent = list; ent != NULL; ent = ent->next)
+			if (!strcmp(ent->name, pp->name))
 				break;
-			}
-			set_node_name_link(child, al);
-			*lastp = al;
-			lastp = &al->next;
+		if (ent != NULL) {
+			printk(KERN_WARNING "device-tree: property \"%s\" name"
+			       " conflicts with node in %s\n", pp->name,
+			       np->full_name);
+			continue;
 		}
-		of_node_put(sib);
+
 		/*
-		 * Add another directory with the @address part as its name.
+		 * Unfortunately proc_register puts each new entry
+		 * at the beginning of the list.  So we rearrange them.
 		 */
-		al = proc_symlink(at, de, ent->name);
-		if (al == 0)
+		ent = create_proc_read_entry(pp->name,
+					     strncmp(pp->name, "security-", 9)
+					     ? S_IRUGO : S_IRUSR, de,
+					     property_read_proc, pp);
+		if (ent == 0)
 			break;
-		set_node_addr_link(child, al);
-		*lastp = al;
-		lastp = &al->next;
+		if (!strncmp(pp->name, "security-", 9))
+		     ent->size = 0; /* don't leak number of password chars */
+		else
+		     ent->size = pp->length;
+		ent->next = NULL;
+		*lastp = ent;
+		lastp = &ent->next;
 	}
-	of_node_put(child);
-	*lastp = NULL;
 	de->subdir = list;
 }
 
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -126,6 +126,7 @@ static int meminfo_read_proc(char *page,
 	unsigned long committed;
 	unsigned long allowed;
 	struct vmalloc_info vmi;
+	long cached;
 
 	get_page_state(&ps);
 	get_zone_counts(&active, &inactive, &free);
@@ -140,6 +141,10 @@ static int meminfo_read_proc(char *page,
 	allowed = ((totalram_pages - hugetlb_total_pages())
 		* sysctl_overcommit_ratio / 100) + total_swap_pages;
 
+	cached = get_page_cache_size() - total_swapcache_pages - i.bufferram;
+	if (cached < 0)
+		cached = 0;
+
 	get_vmalloc_info(&vmi);
 
 	/*
@@ -172,7 +177,7 @@ static int meminfo_read_proc(char *page,
 		K(i.totalram),
 		K(i.freeram),
 		K(i.bufferram),
-		K(get_page_cache_size()-total_swapcache_pages-i.bufferram),
+		K(cached),
 		K(total_swapcache_pages),
 		K(active),
 		K(inactive),
@@ -189,7 +194,7 @@ static int meminfo_read_proc(char *page,
 		K(allowed),
 		K(committed),
 		K(ps.nr_page_table_pages),
-		VMALLOC_TOTAL >> 10,
+		(unsigned long)VMALLOC_TOTAL >> 10,
 		vmi.used >> 10,
 		vmi.largest_chunk >> 10
 		);
@@ -524,7 +529,7 @@ static ssize_t write_sysrq_trigger(struc
 
 		if (get_user(c, buf))
 			return -EFAULT;
-		__handle_sysrq(c, NULL, NULL);
+		__handle_sysrq(c, NULL, NULL, 0);
 	}
 	return count;
 }
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -24,7 +24,7 @@ char *task_mem(struct mm_struct *mm, cha
 		"VmPTE:\t%8lu kB\n",
 		(mm->total_vm - mm->reserved_vm) << (PAGE_SHIFT-10),
 		mm->locked_vm << (PAGE_SHIFT-10),
-		mm->rss << (PAGE_SHIFT-10),
+		get_mm_counter(mm, rss) << (PAGE_SHIFT-10),
 		data << (PAGE_SHIFT-10),
 		mm->stack_vm << (PAGE_SHIFT-10), text, lib,
 		(PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10);
@@ -39,11 +39,13 @@ unsigned long task_vsize(struct mm_struc
 int task_statm(struct mm_struct *mm, int *shared, int *text,
 	       int *data, int *resident)
 {
-	*shared = mm->rss - mm->anon_rss;
+	int rss = get_mm_counter(mm, rss);
+
+	*shared = rss - get_mm_counter(mm, anon_rss);
 	*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
 								>> PAGE_SHIFT;
 	*data = mm->total_vm - mm->shared_vm;
-	*resident = mm->rss;
+	*resident = rss;
 	return mm->total_vm;
 }
 
@@ -77,9 +79,19 @@ out:
 	return result;
 }
 
+static void pad_len_spaces(struct seq_file *m, int len)
+{
+	len = 25 + sizeof(void*) * 6 - len;
+	if (len < 1)
+		len = 1;
+	seq_printf(m, "%*c", len, ' ');
+}
+
 static int show_map(struct seq_file *m, void *v)
 {
+	struct task_struct *task = m->private;
 	struct vm_area_struct *map = v;
+	struct mm_struct *mm = map->vm_mm;
 	struct file *file = map->vm_file;
 	int flags = map->vm_flags;
 	unsigned long ino = 0;
@@ -102,38 +114,93 @@ static int show_map(struct seq_file *m, 
 			map->vm_pgoff << PAGE_SHIFT,
 			MAJOR(dev), MINOR(dev), ino, &len);
 
+	/*
+	 * Print the dentry name for named mappings, and a
+	 * special [heap] marker for the heap:
+	 */
 	if (map->vm_file) {
-		len = 25 + sizeof(void*) * 6 - len;
-		if (len < 1)
-			len = 1;
-		seq_printf(m, "%*c", len, ' ');
+		pad_len_spaces(m, len);
 		seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+	} else {
+		if (mm) {
+			if (map->vm_start <= mm->start_brk &&
+						map->vm_end >= mm->brk) {
+				pad_len_spaces(m, len);
+				seq_puts(m, "[heap]");
+			} else {
+				if (map->vm_start <= mm->start_stack &&
+					map->vm_end >= mm->start_stack) {
+
+					pad_len_spaces(m, len);
+					seq_puts(m, "[stack]");
+				}
+			}
+		} else {
+			pad_len_spaces(m, len);
+			seq_puts(m, "[vdso]");
+		}
 	}
 	seq_putc(m, '\n');
+	if (m->count < m->size)  /* map is copied successfully */
+		m->version = (map != get_gate_vma(task))? map->vm_start: 0;
 	return 0;
 }
 
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
 	struct task_struct *task = m->private;
-	struct mm_struct *mm = get_task_mm(task);
-	struct vm_area_struct * map;
+	unsigned long last_addr = m->version;
+	struct mm_struct *mm;
+	struct vm_area_struct *map, *tail_map;
 	loff_t l = *pos;
 
+	/*
+	 * We remember last_addr rather than next_addr to hit with
+	 * mmap_cache most of the time. We have zero last_addr at
+	 * the begining and also after lseek. We will have -1 last_addr
+	 * after the end of the maps.
+	 */
+
+	if (last_addr == -1UL)
+		return NULL;
+
+	mm = get_task_mm(task);
 	if (!mm)
 		return NULL;
 
+	tail_map = get_gate_vma(task);
 	down_read(&mm->mmap_sem);
-	map = mm->mmap;
-	while (l-- && map)
+
+	/* Start with last addr hint */
+	if (last_addr && (map = find_vma(mm, last_addr))) {
 		map = map->vm_next;
-	if (!map) {
-		up_read(&mm->mmap_sem);
-		mmput(mm);
-		if (l == -1)
-			map = get_gate_vma(task);
+		goto out;
+	}
+
+	/*
+	 * Check the map index is within the range and do
+	 * sequential scan until m_index.
+	 */
+	map = NULL;
+	if ((unsigned long)l < mm->map_count) {
+		map = mm->mmap;
+		while (l-- && map)
+			map = map->vm_next;
+		goto out;
 	}
-	return map;
+
+	if (l != mm->map_count)
+		tail_map = NULL; /* After gate map */
+
+out:
+	if (map)
+		return map;
+
+	/* End of maps has reached */
+	m->version = (tail_map != NULL)? 0: -1UL;
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+	return tail_map;
 }
 
 static void m_stop(struct seq_file *m, void *v)
@@ -151,13 +218,13 @@ static void *m_next(struct seq_file *m, 
 {
 	struct task_struct *task = m->private;
 	struct vm_area_struct *map = v;
+	struct vm_area_struct *tail_map = get_gate_vma(task);
+
 	(*pos)++;
-	if (map->vm_next)
+	if (map && (map != tail_map) && map->vm_next)
 		return map->vm_next;
 	m_stop(m, v);
-	if (map != get_gate_vma(task))
-		return get_gate_vma(task);
-	return NULL;
+	return (map != tail_map)? tail_map: NULL;
 }
 
 struct seq_operations proc_pid_maps_op = {
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -28,8 +28,8 @@ int qnx4_new_block(struct super_block *s
 	return 0;
 }
 
-void count_bits(register const char *bmPart, register int size,
-		int *const tf)
+static void count_bits(register const char *bmPart, register int size,
+		       int *const tf)
 {
 	char b;
 	int tot = *tf;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -162,8 +162,8 @@ static int qnx4_remount(struct super_blo
 	return 0;
 }
 
-struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
-				 int create)
+static struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
+				       int create)
 {
 	struct buffer_head *result = NULL;
 
@@ -212,7 +212,7 @@ struct buffer_head *qnx4_bread(struct in
 	return NULL;
 }
 
-int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
+static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
 {
 	unsigned long phys;
 
@@ -447,7 +447,7 @@ static sector_t qnx4_bmap(struct address
 {
 	return generic_block_bmap(mapping,block,qnx4_get_block);
 }
-struct address_space_operations qnx4_aops = {
+static struct address_space_operations qnx4_aops = {
 	.readpage	= qnx4_readpage,
 	.writepage	= qnx4_writepage,
 	.sync_page	= block_sync_page,
diff --git a/fs/quota.c b/fs/quota.c
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -16,8 +16,8 @@
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h>
 
-/* Check validity of quotactl */
-static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+/* Check validity of generic quotactl commands */
+static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
 {
 	if (type >= MAXQUOTAS)
 		return -EINVAL;
@@ -58,6 +58,48 @@ static int check_quotactl_valid(struct s
 			if (sb && !sb->s_qcop->quota_sync)
 				return -ENOSYS;
 			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* Is quota turned on for commands which need it? */
+	switch (cmd) {
+		case Q_GETFMT:
+		case Q_GETINFO:
+		case Q_QUOTAOFF:
+		case Q_SETINFO:
+		case Q_SETQUOTA:
+		case Q_GETQUOTA:
+			/* This is just informative test so we are satisfied without a lock */
+			if (!sb_has_quota_enabled(sb, type))
+				return -ESRCH;
+	}
+
+	/* Check privileges */
+	if (cmd == Q_GETQUOTA) {
+		if (((type == USRQUOTA && current->euid != id) ||
+		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		    !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO)
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+	return 0;
+}
+
+/* Check validity of XFS Quota Manager commands */
+static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	if (type >= XQM_MAXQUOTAS)
+		return -EINVAL;
+	if (!sb)
+		return -ENODEV;
+	if (!sb->s_qcop)
+		return -ENOSYS;
+
+	switch (cmd) {
 		case Q_XQUOTAON:
 		case Q_XQUOTAOFF:
 		case Q_XQUOTARM:
@@ -80,30 +122,31 @@ static int check_quotactl_valid(struct s
 			return -EINVAL;
 	}
 
-	/* Is quota turned on for commands which need it? */
-	switch (cmd) {
-		case Q_GETFMT:
-		case Q_GETINFO:
-		case Q_QUOTAOFF:
-		case Q_SETINFO:
-		case Q_SETQUOTA:
-		case Q_GETQUOTA:
-			/* This is just informative test so we are satisfied without a lock */
-			if (!sb_has_quota_enabled(sb, type))
-				return -ESRCH;
-	}
 	/* Check privileges */
-	if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
-		if (((type == USRQUOTA && current->euid != id) ||
-		     (type == GRPQUOTA && !in_egroup_p(id))) &&
-		    !capable(CAP_SYS_ADMIN))
+	if (cmd == Q_XGETQUOTA) {
+		if (((type == XQM_USRQUOTA && current->euid != id) ||
+		     (type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
+		     !capable(CAP_SYS_ADMIN))
 			return -EPERM;
-	}
-	else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
+	} else if (cmd != Q_XGETQSTAT) {
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
+	}
+
+	return 0;
+}
+
+static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	int error;
 
-	return security_quotactl (cmd, type, id, sb);
+	if (XQM_COMMAND(cmd))
+		error = xqm_quotactl_valid(sb, type, cmd, id);
+	else
+		error = generic_quotactl_valid(sb, type, cmd, id);
+	if (!error)
+		error = security_quotactl(cmd, type, id, sb);
+	return error;
 }
 
 static struct super_block *get_super_to_sync(int type)
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -503,7 +503,8 @@ static int remove_tree(struct dquot *dqu
 		int i;
 		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
 		for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);	/* Block got empty? */
-		if (i == V2_DQBLKSIZE) {
+		/* Don't put the root block into the free block list */
+		if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
 			put_free_dqblk(sb, type, buf, *blk);
 			*blk = 0;
 		}
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -45,7 +45,9 @@ static struct inode_operations ramfs_dir
 
 static struct backing_dev_info ramfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
+			  BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
+			  BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
 };
 
 struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
diff --git a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -467,10 +467,10 @@ static ssize_t do_readv_writev(int type,
 		void __user *buf = iov[seg].iov_base;
 		ssize_t len = (ssize_t)iov[seg].iov_len;
 
-		if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
-			goto Efault;
 		if (len < 0)	/* size_t not fitting an ssize_t .. */
 			goto out;
+		if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
+			goto Efault;
 		tot_len += len;
 		if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
 			goto out;
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -260,8 +260,9 @@ static inline int block_group_used(struc
 /*
  * the packing is returned in disk byte order
  */
-u32 reiserfs_choose_packing(struct inode *dir) {
-    u32 packing;
+__le32 reiserfs_choose_packing(struct inode *dir)
+{
+    __le32 packing;
     if (TEST_OPTION(packing_groups, dir->i_sb)) {
 	u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
 	/*
@@ -655,7 +656,7 @@ static int get_left_neighbor(reiserfs_bl
     struct buffer_head * bh;
     struct item_head * ih;
     int pos_in_item;
-    __u32 * item;
+    __le32 * item;
     int ret = 0;
 
     if (!hint->path)		/* reiserfs code can call this function w/o pointer to path
@@ -736,7 +737,7 @@ static inline int this_blocknr_allocatio
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
 static inline void displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
 {
-    struct reiserfs_key * key = &hint->key;
+    struct in_core_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);
@@ -777,7 +778,7 @@ static inline int old_way (reiserfs_bloc
 
 static inline void hundredth_slices (reiserfs_blocknr_hint_t * hint)
 {
-    struct reiserfs_key * key = &hint->key;
+    struct in_core_key * key = &hint->key;
     b_blocknr_t slice_start;
 
     slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -209,8 +209,8 @@ static int reiserfs_readdir (struct file
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
 /* the last four params are LE */
-void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
-			     __u32 par_dirid, __u32 par_objid)
+void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid,
+			     __le32 par_dirid, __le32 par_objid)
 {
     struct reiserfs_de_head * deh;
 
@@ -242,8 +242,8 @@ void make_empty_dir_item_v1 (char * body
 }
 
 /* compose directory item containing "." and ".." entries */
-void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
-			  __u32 par_dirid, __u32 par_objid)
+void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
+			  __le32 par_dirid, __le32 par_objid)
 {
     struct reiserfs_de_head * deh;
 
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -166,7 +166,7 @@ static int reiserfs_allocate_blocks_for_
     struct cpu_key key; // cpu key of item that we are going to deal with
     struct item_head *ih; // pointer to item head that we are going to deal with
     struct buffer_head *bh; // Buffer head that contains items that we are going to deal with
-    __u32 * item; // pointer to item we are going to deal with
+    __le32 * item; // pointer to item we are going to deal with
     INITIALIZE_PATH(path); // path to item, that we are going to deal with.
     b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored.
     reiserfs_blocknr_hint_t hint; // hint structure for block allocator.
@@ -891,7 +891,7 @@ static int reiserfs_prepare_file_region_
     struct item_head *ih = NULL; // pointer to item head that we are going to deal with
     struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with
     INITIALIZE_PATH(path); // path to item, that we are going to deal with.
-    __u32 * item=NULL; // pointer to item we are going to deal with
+    __le32 * item=NULL; // pointer to item we are going to deal with
     int item_pos=-1; /* Position in indirect item */
 
 
@@ -1284,10 +1284,11 @@ static ssize_t reiserfs_file_write( stru
 	reiserfs_claim_blocks_to_be_allocated(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
 	reiserfs_write_unlock(inode->i_sb);
 
-	if ( !num_pages ) { /* If we do not have enough space even for */
-	    res = -ENOSPC;  /* single page, return -ENOSPC */
-	    if ( pos > (inode->i_size & (inode->i_sb->s_blocksize-1)))
-		break; // In case we are writing past the file end, break.
+	if ( !num_pages ) { /* If we do not have enough space even for a single page... */
+	    if ( pos > inode->i_size+inode->i_sb->s_blocksize-(pos & (inode->i_sb->s_blocksize-1))) {
+		res = -ENOSPC;
+		break; // In case we are writing past the end of the last file block, break.
+	    }
 	    // Otherwise we are possibly overwriting the file, so
 	    // let's set write size to be equal or less than blocksize.
 	    // This way we get it correctly for file holes.
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -173,7 +173,7 @@ static inline void fix_tail_page_for_wri
    done already or non-hole position has been found in the indirect item */
 static inline int allocation_needed (int retval, b_blocknr_t allocated, 
 				     struct item_head * ih,
-				     __u32 * item, int pos_in_item)
+				     __le32 * item, int pos_in_item)
 {
   if (allocated)
 	 return 0;
@@ -278,7 +278,7 @@ research:
     bh = get_last_bh (&path);
     ih = get_ih (&path);
     if (is_indirect_le_ih (ih)) {
-	__u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih);
+	__le32 * ind_item = (__le32 *)B_I_PITEM (bh, ih);
 	
 	/* FIXME: here we could cache indirect item or part of it in
 	   the inode to avoid search_by_key in case of subsequent
@@ -581,7 +581,7 @@ int reiserfs_get_block (struct inode * i
     struct cpu_key key;
     struct buffer_head * bh, * unbh = NULL;
     struct item_head * ih, tmp_ih;
-    __u32 * item;
+    __le32 * item;
     int done;
     int fs_gen;
     struct reiserfs_transaction_handle *th = NULL;
@@ -746,7 +746,7 @@ start_trans:
     done = 0;
     do {
 	if (is_statdata_le_ih (ih)) {
-	    __u32 unp = 0;
+	    __le32 unp = 0;
 	    struct cpu_key tmp_key;
 
 	    /* indirect item has to be inserted */
@@ -1341,8 +1341,8 @@ void reiserfs_read_locked_inode (struct 
     key.version = KEY_FORMAT_3_5;
     key.on_disk_key.k_dir_id = dirino;
     key.on_disk_key.k_objectid = inode->i_ino;
-    key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET;
-    key.on_disk_key.u.k_offset_v1.k_uniqueness = SD_UNIQUENESS;
+    key.on_disk_key.k_offset = 0;
+    key.on_disk_key.k_type = 0;
 
     /* look for the object's stat data */
     retval = search_item (inode->i_sb, &key, &path_to_sd);
@@ -1843,6 +1843,8 @@ int reiserfs_new_inode (struct reiserfs_
     } else if (inode->i_sb->s_flags & MS_POSIXACL) {
 	reiserfs_warning (inode->i_sb, "ACLs aren't enabled in the fs, "
 			  "but vfs thinks they are!");
+    } else if (is_reiserfs_priv_object (dir)) {
+	reiserfs_mark_inode_private (inode);
     }
 
     insert_inode_hash (inode);
@@ -2065,7 +2067,7 @@ static int map_block_for_writepage(struc
     struct item_head tmp_ih ;
     struct item_head *ih ;
     struct buffer_head *bh ;
-    __u32 *item ;
+    __le32 *item ;
     struct cpu_key key ;
     INITIALIZE_PATH(path) ;
     int pos_in_item ;
diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
--- a/fs/reiserfs/item_ops.c
+++ b/fs/reiserfs/item_ops.c
@@ -296,10 +296,11 @@ static void print_sequence (__u32 start,
 static void indirect_print_item (struct item_head * ih, char * item)
 {
     int j;
-    __u32 * unp, prev = INT_MAX;
+    __le32 * unp;
+    __u32 prev = INT_MAX;
     int num;
 
-    unp = (__u32 *)item;
+    unp = (__le32 *)item;
 
     if (ih_item_len(ih) % UNFM_P_SIZE)
 	reiserfs_warning (NULL, "indirect_print_item: invalid item len");
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2306,13 +2306,16 @@ static int journal_init_dev( struct supe
 	if( !IS_ERR( journal -> j_dev_file ) ) {
 		struct inode *jdev_inode = journal->j_dev_file->f_mapping->host;
 		if( !S_ISBLK( jdev_inode -> i_mode ) ) {
-			reiserfs_warning  (super, "journal_init_dev: '%s' is "
-					   "not a block device", jdev_name );
+			reiserfs_warning(super, "journal_init_dev: '%s' is "
+					 "not a block device", jdev_name );
 			result = -ENOTBLK;
+			release_journal_dev( super, journal );
 		} else  {
 			/* ok */
 			journal->j_dev_bd = I_BDEV(jdev_inode);
 			set_blocksize(journal->j_dev_bd, super->s_blocksize);
+			reiserfs_info(super, "journal_init_dev: journal device: %s\n",
+				      bdevname(journal->j_dev_bd, b));
 		}
 	} else {
 		result = PTR_ERR( journal -> j_dev_file );
@@ -2321,11 +2324,6 @@ static int journal_init_dev( struct supe
 				  "journal_init_dev: Cannot open '%s': %i",
 				  jdev_name, result );
 	}
-	if( result != 0 ) {
-		release_journal_dev( super, journal );
-	}
-	reiserfs_info(super, "journal_init_dev: journal device: %s\n",
-		bdevname(journal->j_dev_bd, b));
 	return result;
 }
 
@@ -2393,7 +2391,7 @@ int journal_init(struct super_block *p_s
      jh = (struct reiserfs_journal_header *)(bhjh->b_data);
      
      /* make sure that journal matches to the super block */
-     if (is_reiserfs_jr(rs) && (jh->jh_journal.jp_journal_magic != sb_jp_journal_magic(rs))) {
+     if (is_reiserfs_jr(rs) && (le32_to_cpu(jh->jh_journal.jp_journal_magic) != sb_jp_journal_magic(rs))) {
 	 reiserfs_warning (p_s_sb, "sh-460: journal header magic %x "
 			   "(device %s) does not match to magic found in super "
 			   "block %x",
@@ -3011,6 +3009,8 @@ static int remove_from_transaction(struc
 
   if (!already_cleaned) {
     clear_buffer_journal_dirty (bh);
+    clear_buffer_dirty(bh);
+    clear_buffer_journal_test (bh);
     put_bh(bh) ;
     if (atomic_read(&(bh->b_count)) < 0) {
       reiserfs_warning (p_s_sb, "journal-1752: remove from trans, b_count < 0");
@@ -3317,6 +3317,8 @@ int journal_mark_freed(struct reiserfs_t
 	    ** in the current trans
 	    */
             clear_buffer_journal_dirty (cn->bh);
+	    clear_buffer_dirty(cn->bh);
+	    clear_buffer_journal_test(cn->bh);
 	    cleaned = 1 ;
 	    put_bh(cn->bh) ;
 	    if (atomic_read(&(cn->bh->b_count)) < 0) {
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -353,7 +353,7 @@ static struct dentry * reiserfs_lookup (
 
 	/* Propogate the priv_object flag so we know we're in the priv tree */
 	if (is_reiserfs_priv_object (dir))
-	    REISERFS_I(inode)->i_flags |= i_priv_object;
+	    reiserfs_mark_inode_private (inode);
     }
     reiserfs_write_unlock(dir->i_sb);
     if ( retval == IO_ERROR ) {
@@ -608,7 +608,7 @@ static int reiserfs_create (struct inode
         goto out_failed;
     }
 
-    retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
     if (retval)
         goto out_failed;
 	
@@ -1255,7 +1255,6 @@ static int reiserfs_rename (struct inode
         return retval;
     }
 
-
     /* add new entry (or find the existing one) */
     retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
 				 old_inode, 0);
@@ -1283,8 +1282,13 @@ static int reiserfs_rename (struct inode
 
     while (1) {
 	// look for old name using corresponding entry key (found by reiserfs_find_entry)
-	if (search_by_entry_key (new_dir->i_sb, &old_de.de_entry_key, &old_entry_path, &old_de) != NAME_FOUND)
-	    BUG ();
+	if ((retval = search_by_entry_key (new_dir->i_sb, &old_de.de_entry_key,
+					   &old_entry_path, &old_de)) != NAME_FOUND) {
+	    pathrelse(&old_entry_path);
+	    journal_end(&th, old_dir->i_sb, jbegin_count);
+	    reiserfs_write_unlock(old_dir->i_sb);
+	    return -EIO;
+	}
 
 	copy_item_head(&old_entry_ih, get_ih(&old_entry_path)) ;
 
@@ -1296,16 +1300,28 @@ static int reiserfs_rename (struct inode
 				      &new_entry_path, &new_de);
 	// reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from
         // reiserfs_add_entry above, and we'll catch any i/o errors before we get here.
-	if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND)
-	    BUG ();
+	if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND) {
+	    pathrelse(&new_entry_path);
+	    pathrelse(&old_entry_path);
+	    journal_end(&th, old_dir->i_sb, jbegin_count);
+	    reiserfs_write_unlock(old_dir->i_sb);
+	    return -EIO;
+	}
 
 	copy_item_head(&new_entry_ih, get_ih(&new_entry_path)) ;
 
 	reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1) ;
 
 	if (S_ISDIR(old_inode->i_mode)) {
-	    if (search_by_entry_key (new_dir->i_sb, &dot_dot_de.de_entry_key, &dot_dot_entry_path, &dot_dot_de) != NAME_FOUND)
-		BUG ();
+	    if ((retval = search_by_entry_key (new_dir->i_sb, &dot_dot_de.de_entry_key,
+					       &dot_dot_entry_path, &dot_dot_de)) != NAME_FOUND) {
+		pathrelse(&dot_dot_entry_path);
+		pathrelse(&new_entry_path);
+		pathrelse(&old_entry_path);
+		journal_end(&th, old_dir->i_sb, jbegin_count);
+		reiserfs_write_unlock(old_dir->i_sb);
+		return -EIO;
+	    }
 	    copy_item_head(&dot_dot_ih, get_ih(&dot_dot_entry_path)) ;
 	    // node containing ".." gets into transaction
 	    reiserfs_prepare_for_journal(old_inode->i_sb, dot_dot_de.de_bh, 1) ;
diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
--- a/fs/reiserfs/objectid.c
+++ b/fs/reiserfs/objectid.c
@@ -11,13 +11,13 @@
 
 // find where objectid map starts
 #define objectid_map(s,rs) (old_format_only (s) ? \
-                         (__u32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
-			 (__u32 *)((rs) + 1))
+                         (__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
+			 (__le32 *)((rs) + 1))
 
 
 #ifdef CONFIG_REISERFS_CHECK
 
-static void check_objectid_map (struct super_block * s, __u32 * map)
+static void check_objectid_map (struct super_block * s, __le32 * map)
 {
     if (le32_to_cpu (map[0]) != 1)
 	reiserfs_panic (s, "vs-15010: check_objectid_map: map corrupted: %lx",
@@ -27,7 +27,7 @@ static void check_objectid_map (struct s
 }
 
 #else
-static void check_objectid_map (struct super_block * s, __u32 * map)
+static void check_objectid_map (struct super_block * s, __le32 * map)
 {;}
 #endif
 
@@ -52,7 +52,7 @@ __u32 reiserfs_get_unused_objectid (stru
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
-    __u32 * map = objectid_map (s, rs);
+    __le32 * map = objectid_map (s, rs);
     __u32 unused_objectid;
 
     BUG_ON (!th->t_trans_id);
@@ -97,7 +97,7 @@ void reiserfs_release_objectid (struct r
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
-    __u32 * map = objectid_map (s, rs);
+    __le32 * map = objectid_map (s, rs);
     int i = 0;
 
     BUG_ON (!th->t_trans_id);
@@ -172,12 +172,12 @@ int reiserfs_convert_objectid_map_v1(str
     int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2 ;
     int old_max = sb_oid_maxsize(disk_sb);
     struct reiserfs_super_block_v1 *disk_sb_v1 ;
-    __u32 *objectid_map, *new_objectid_map ;
+    __le32 *objectid_map, *new_objectid_map ;
     int i ;
 
     disk_sb_v1=(struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
-    objectid_map = (__u32 *)(disk_sb_v1 + 1) ;
-    new_objectid_map = (__u32 *)(disk_sb + 1) ;
+    objectid_map = (__le32 *)(disk_sb_v1 + 1) ;
+    new_objectid_map = (__le32 *)(disk_sb + 1) ;
 
     if (cur_size > new_size) {
 	/* mark everyone used that was listed as free at the end of the objectid
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -73,8 +73,8 @@ int reiserfs_global_version_in_proc( cha
 #define DFL( x ) D4C( rs -> s_v1.x )
 
 #define objectid_map( s, rs ) (old_format_only (s) ?				\
-                         (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) :	\
-			 (__u32 *)(rs + 1))
+                         (__le32 *)((struct reiserfs_super_block_v1 *)rs + 1) :	\
+			 (__le32 *)(rs + 1))
 #define MAP( i ) D4C( objectid_map( sb, rs )[ i ] )
 
 #define DJF( x ) le32_to_cpu( rs -> x )
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -87,22 +87,20 @@ inline void copy_item_head(struct item_h
 inline int  comp_short_keys (const struct reiserfs_key * le_key,
 			     const struct cpu_key * cpu_key)
 {
-  __u32 * p_s_le_u32, * p_s_cpu_u32;
-  int n_key_length = REISERFS_SHORT_KEY_LEN;
-
-  p_s_le_u32 = (__u32 *)le_key;
-  p_s_cpu_u32 = (__u32 *)&cpu_key->on_disk_key;
-  for( ; n_key_length--; ++p_s_le_u32, ++p_s_cpu_u32 ) {
-    if ( le32_to_cpu (*p_s_le_u32) < *p_s_cpu_u32 )
+  __u32 n;
+  n = le32_to_cpu(le_key->k_dir_id);
+  if (n < cpu_key->on_disk_key.k_dir_id)
       return -1;
-    if ( le32_to_cpu (*p_s_le_u32) > *p_s_cpu_u32 )
+  if (n > cpu_key->on_disk_key.k_dir_id)
+      return 1;
+  n = le32_to_cpu(le_key->k_objectid);
+  if (n < cpu_key->on_disk_key.k_objectid)
+      return -1;
+  if (n > cpu_key->on_disk_key.k_objectid)
       return 1;
-  }
-
   return 0;
 }
 
-
 /* k1 is pointer to on-disk structure which is stored in little-endian
    form. k2 is pointer to cpu variable.
    Compare keys using all 4 key fields.
@@ -152,18 +150,15 @@ inline int comp_short_le_keys (const str
 
 inline void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from)
 {
+    int version;
     to->on_disk_key.k_dir_id = le32_to_cpu (from->k_dir_id);
     to->on_disk_key.k_objectid = le32_to_cpu (from->k_objectid);
     
     // find out version of the key
-    to->version = le_key_version (from);
-    if (to->version == KEY_FORMAT_3_5) {
-	to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset);
-	to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness);
-    } else {
-	to->on_disk_key.u.k_offset_v2.k_offset = offset_v2_k_offset(&from->u.k_offset_v2);
-	to->on_disk_key.u.k_offset_v2.k_type = offset_v2_k_type(&from->u.k_offset_v2);
-    } 
+    version = le_key_version (from);
+    to->version = version;
+    to->on_disk_key.k_offset = le_key_k_offset(version, from);
+    to->on_disk_key.k_type = le_key_k_type(version, from);
 }
 
 
@@ -228,7 +223,12 @@ extern struct tree_balance * cur_tb;
 const struct reiserfs_key  MIN_KEY = {0, 0, {{0, 0},}};
 
 /* Maximal possible key. It is never in the tree. */
-const struct reiserfs_key  MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};
+const struct reiserfs_key  MAX_KEY = {
+	__constant_cpu_to_le32(0xffffffff),
+	__constant_cpu_to_le32(0xffffffff),
+	{{__constant_cpu_to_le32(0xffffffff),
+	__constant_cpu_to_le32(0xffffffff)},}
+};
 
 
 /* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom
@@ -997,7 +997,7 @@ static char  prepare_for_delete_or_cut(
 	int                   n_unfm_number,    /* Number of the item unformatted nodes. */
 	    n_counter,
 	    n_blk_size;
-	__u32               * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
+	__le32               * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
 	__u32 tmp;
 	struct item_head      s_ih;           /* Item header. */
 	char                  c_mode;           /* Returned mode of the balance. */
@@ -1059,7 +1059,7 @@ static char  prepare_for_delete_or_cut(
 	    /* pointers to be cut */
 	    n_unfm_number -= pos_in_item (p_s_path);
 	    /* Set pointer to the last unformatted node pointer that is to be cut. */
-	    p_n_unfm_pointer = (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed;
+	    p_n_unfm_pointer = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed;
 
 
 	    /* We go through the unformatted nodes pointers of the indirect
@@ -1081,8 +1081,8 @@ static char  prepare_for_delete_or_cut(
 		    need_research = 1 ;
 		    break;
 		}
-		RFALSE( p_n_unfm_pointer < (__u32 *)B_I_PITEM(p_s_bh, &s_ih) ||
-			p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
+		RFALSE( p_n_unfm_pointer < (__le32 *)B_I_PITEM(p_s_bh, &s_ih) ||
+			p_n_unfm_pointer > (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
 			"vs-5265: pointer out of range");
 
 		/* Hole, nothing to remove. */
@@ -1431,7 +1431,7 @@ int reiserfs_delete_object (struct reise
 #if defined( USE_INODE_GENERATION_COUNTER )
     if( !old_format_only ( th -> t_super ) )
       {
-       __u32 *inode_generation;
+       __le32 *inode_generation;
        
        inode_generation = 
          &REISERFS_SB(th -> t_super) -> s_rs -> s_inode_generation;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -110,7 +110,7 @@ static void reiserfs_unlockfs(struct sup
   reiserfs_allow_writes(s) ;
 }
 
-extern const struct reiserfs_key  MAX_KEY;
+extern const struct in_core_key  MAX_IN_CORE_KEY;
 
 
 /* this is used to delete "save link" when there are no items of a
@@ -164,7 +164,9 @@ static int finish_unfinished (struct sup
  
     /* compose key to look for "save" links */
     max_cpu_key.version = KEY_FORMAT_3_5;
-    max_cpu_key.on_disk_key = MAX_KEY;
+    max_cpu_key.on_disk_key.k_dir_id = ~0U;
+    max_cpu_key.on_disk_key.k_objectid = ~0U;
+    set_cpu_key_k_offset (&max_cpu_key, ~0U);
     max_cpu_key.key_length = 3;
 
 #ifdef CONFIG_QUOTA
@@ -216,10 +218,10 @@ static int finish_unfinished (struct sup
  
         /* reiserfs_iget needs k_dirid and k_objectid only */
         item = B_I_PITEM (bh, ih);
-        obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item);
+        obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__le32 *)item);
         obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
-	obj_key.on_disk_key.u.k_offset_v1.k_offset = 0;
-	obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0;
+	obj_key.on_disk_key.k_offset = 0;
+	obj_key.on_disk_key.k_type = 0;
 	
         pathrelse (&path);
  
@@ -304,7 +306,7 @@ void add_save_link (struct reiserfs_tran
     int retval;
     struct cpu_key key;
     struct item_head ih;
-    __u32 link;
+    __le32 link;
 
     BUG_ON (!th->t_trans_id);
 
@@ -889,12 +891,18 @@ static int reiserfs_parse_options (struc
 	    char * p;
 	    
 	    p = NULL;
-	    /* "resize=NNN" */
-	    *blocks = simple_strtoul (arg, &p, 0);
-	    if (*p != '\0') {
-		/* NNN does not look like a number */
-		reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
-		return 0;
+	    /* "resize=NNN" or "resize=auto" */
+
+	    if (!strcmp(arg, "auto")) {
+		    /* From JFS code, to auto-get the size.*/
+		    *blocks = s->s_bdev->bd_inode->i_size >> s->s_blocksize_bits;
+	    } else {
+		    *blocks = simple_strtoul (arg, &p, 0);
+		    if (*p != '\0') {
+			/* NNN does not look like a number */
+			reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
+			return 0;
+		    }
 	    }
 	}
 
@@ -903,7 +911,8 @@ static int reiserfs_parse_options (struc
 		unsigned long val = simple_strtoul (arg, &p, 0);
 		/* commit=NNN (time in seconds) */
 		if ( *p != '\0' || val >= (unsigned int)-1) {
-			reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);			return 0;
+			reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
+			return 0;
 		}
 		*commit_max_age = (unsigned int)val;
 	}
@@ -1329,7 +1338,7 @@ static int read_super_block (struct supe
 	return 1;
     }
 
-    if ( rs->s_v1.s_root_block == -1 ) {
+    if ( rs->s_v1.s_root_block == cpu_to_le32(-1) ) {
        brelse(bh) ;
        reiserfs_warning (s, "Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
               "reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -181,8 +181,6 @@ open_xa_dir (const struct inode *inode, 
             dput (xadir);
             return ERR_PTR (-ENODATA);
         }
-        /* Newly created object.. Need to mark it private */
-        REISERFS_I(xadir->d_inode)->i_flags |= i_priv_object;
     }
 
     dput (xaroot);
@@ -230,8 +228,6 @@ get_xa_file_dentry (const struct inode *
             dput (xafile);
             goto out;
         }
-        /* Newly created object.. Need to mark it private */
-        REISERFS_I(xafile->d_inode)->i_flags |= i_priv_object;
     }
 
 out:
@@ -1316,7 +1312,7 @@ reiserfs_xattr_init (struct super_block 
 
       if (!err && dentry) {
           s->s_root->d_op = &xattr_lookup_poison_ops;
-          REISERFS_I(dentry->d_inode)->i_flags |= i_priv_object;
+          reiserfs_mark_inode_private (dentry->d_inode);
           REISERFS_SB(s)->priv_root = dentry;
       } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
           /* If we're read-only it just means that the dir hasn't been
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -339,7 +339,7 @@ reiserfs_inherit_default_acl (struct ino
      * would be useless since permissions are ignored, and a pain because
      * it introduces locking cycles */
     if (is_reiserfs_priv_object (dir)) {
-        REISERFS_I(inode)->i_flags |= i_priv_object;
+        reiserfs_mark_inode_private (inode);
         goto apply_umask;
     }
 
diff --git a/fs/select.c b/fs/select.c
--- a/fs/select.c
+++ b/fs/select.c
@@ -55,7 +55,8 @@ struct poll_table_page {
  * as all select/poll functions have to call it to add an entry to the
  * poll table.
  */
-void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p);
+static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
+		       poll_table *p);
 
 void poll_initwait(struct poll_wqueues *pwq)
 {
@@ -87,7 +88,8 @@ void poll_freewait(struct poll_wqueues *
 
 EXPORT_SYMBOL(poll_freewait);
 
-void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *_p)
+static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
+		       poll_table *_p)
 {
 	struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt);
 	struct poll_table_page *table = p->table;
@@ -302,10 +304,12 @@ sys_select(int n, fd_set __user *inp, fd
 	if (tvp) {
 		time_t sec, usec;
 
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
+		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
+		    || __get_user(sec, &tvp->tv_sec)
+		    || __get_user(usec, &tvp->tv_usec)) {
+			ret = -EFAULT;
 			goto out_nofds;
+		}
 
 		ret = -EINVAL;
 		if (sec < 0 || usec < 0)
diff --git a/fs/seq_file.c b/fs/seq_file.c
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -36,6 +36,13 @@ int seq_open(struct file *file, struct s
 	p->op = op;
 	file->private_data = p;
 
+	/*
+	 * Wrappers around seq_open(e.g. swaps_open) need to be
+	 * aware of this. If they set f_version themselves, they
+	 * should call seq_open first and then set f_version.
+	 */
+	file->f_version = 0;
+
 	/* SEQ files support lseek, but not pread/pwrite */
 	file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
 	return 0;
@@ -44,7 +51,10 @@ EXPORT_SYMBOL(seq_open);
 
 /**
  *	seq_read -	->read() method for sequential files.
- *	@file, @buf, @size, @ppos: see file_operations method
+ *	@file: the file to read from
+ *	@buf: the buffer to read to
+ *	@size: the maximum number of bytes to read
+ *	@ppos: the current position in the file
  *
  *	Ready-made ->f_op->read()
  */
@@ -58,6 +68,18 @@ ssize_t seq_read(struct file *file, char
 	int err = 0;
 
 	down(&m->sem);
+	/*
+	 * seq_file->op->..m_start/m_stop/m_next may do special actions
+	 * or optimisations based on the file->f_version, so we want to
+	 * pass the file->f_version to those methods.
+	 *
+	 * seq_file->version is just copy of f_version, and seq_file
+	 * methods can treat it simply as file version.
+	 * It is copied in first and copied out after all operations.
+	 * It is convenient to have it as  part of structure to avoid the
+	 * need of passing another argument to all the seq_file methods.
+	 */
+	m->version = file->f_version;
 	/* grab buffer if we didn't have one */
 	if (!m->buf) {
 		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
@@ -98,6 +120,7 @@ ssize_t seq_read(struct file *file, char
 		if (!m->buf)
 			goto Enomem;
 		m->count = 0;
+		m->version = 0;
 	}
 	m->op->stop(m, p);
 	m->count = 0;
@@ -136,6 +159,7 @@ Done:
 		copied = err;
 	else
 		*ppos += copied;
+	file->f_version = m->version;
 	up(&m->sem);
 	return copied;
 Enomem:
@@ -153,6 +177,7 @@ static int traverse(struct seq_file *m, 
 	int error = 0;
 	void *p;
 
+	m->version = 0;
 	m->index = 0;
 	m->count = m->from = 0;
 	if (!offset)
@@ -197,7 +222,9 @@ Eoverflow:
 
 /**
  *	seq_lseek -	->llseek() method for sequential files.
- *	@file, @offset, @origin: see file_operations method
+ *	@file: the file in question
+ *	@offset: new position
+ *	@origin: 0 for absolute, 1 for relative position
  *
  *	Ready-made ->f_op->llseek()
  */
@@ -207,6 +234,7 @@ loff_t seq_lseek(struct file *file, loff
 	long long retval = -EINVAL;
 
 	down(&m->sem);
+	m->version = file->f_version;
 	switch (origin) {
 		case 1:
 			offset += file->f_pos;
@@ -220,6 +248,7 @@ loff_t seq_lseek(struct file *file, loff
 				if (retval) {
 					/* with extreme prejudice... */
 					file->f_pos = 0;
+					m->version = 0;
 					m->index = 0;
 					m->count = 0;
 				} else {
@@ -228,6 +257,7 @@ loff_t seq_lseek(struct file *file, loff
 			}
 	}
 	up(&m->sem);
+	file->f_version = m->version;
 	return retval;
 }
 EXPORT_SYMBOL(seq_lseek);
diff --git a/fs/super.c b/fs/super.c
--- a/fs/super.c
+++ b/fs/super.c
@@ -143,7 +143,7 @@ int __put_super_and_need_restart(struct 
 
 /**
  *	put_super	-	drop a temporary reference to superblock
- *	@s: superblock in question
+ *	@sb: superblock in question
  *
  *	Drops a temporary reference, frees superblock if there's no
  *	references left.
@@ -732,7 +732,7 @@ void kill_block_super(struct super_block
 
 	bdev_uevent(bdev, KOBJ_UMOUNT);
 	generic_shutdown_super(sb);
-	set_blocksize(bdev, sb->s_old_blocksize);
+	sync_blockdev(bdev);
 	close_bdev_excl(bdev);
 }
 
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -96,7 +96,7 @@ static int fill_read_buffer(struct dentr
 /**
  *	flush_read_buffer - push buffer to userspace.
  *	@buffer:	data buffer for file.
- *	@userbuf:	user-passed buffer.
+ *	@buf:		user-passed buffer.
  *	@count:		number of bytes requested.
  *	@ppos:		file position.
  *
@@ -164,7 +164,7 @@ out:
 /**
  *	fill_write_buffer - copy buffer from userspace.
  *	@buffer:	data buffer for file.
- *	@userbuf:	data from user.
+ *	@buf:		data from user.
  *	@count:		number of bytes in @userbuf.
  *
  *	Allocate @buffer->page if it hasn't been already, then
@@ -428,6 +428,41 @@ int sysfs_update_file(struct kobject * k
 
 
 /**
+ * sysfs_chmod_file - update the modified mode value on an object attribute.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @mode: file permissions.
+ *
+ */
+int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+{
+	struct dentry *dir = kobj->dentry;
+	struct dentry *victim;
+	struct sysfs_dirent *sd;
+	umode_t umode = (mode & S_IALLUGO) | S_IFREG;
+	int res = -ENOENT;
+
+	down(&dir->d_inode->i_sem);
+	victim = sysfs_get_dentry(dir, attr->name);
+	if (!IS_ERR(victim)) {
+		if (victim->d_inode &&
+		    (victim->d_parent->d_inode == dir->d_inode)) {
+			sd = victim->d_fsdata;
+			attr->mode = mode;
+			sd->s_mode = umode;
+			victim->d_inode->i_mode = umode;
+			dput(victim);
+			res = 0;
+		}
+	}
+	up(&dir->d_inode->i_sem);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(sysfs_chmod_file);
+
+
+/**
  *	sysfs_remove_file - remove an object attribute.
  *	@kobj:	object we're acting for.
  *	@attr:	attribute descriptor.
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -23,7 +23,7 @@ static struct address_space_operations s
 
 static struct backing_dev_info sysfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
 struct inode * sysfs_new_inode(mode_t mode)
@@ -129,13 +129,17 @@ void sysfs_drop_dentry(struct sysfs_dire
 
 	if (dentry) {
 		spin_lock(&dcache_lock);
+		spin_lock(&dentry->d_lock);
 		if (!(d_unhashed(dentry) && dentry->d_inode)) {
 			dget_locked(dentry);
 			__d_drop(dentry);
+			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
 			simple_unlink(parent->d_inode, dentry);
-		} else
+		} else {
+			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
+		}
 	}
 }
 
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -93,6 +93,7 @@ int __init sysfs_init(void)
 			printk(KERN_ERR "sysfs: could not mount!\n");
 			err = PTR_ERR(sysfs_mount);
 			sysfs_mount = NULL;
+			unregister_filesystem(&sysfs_fs_type);
 			goto out_err;
 		}
 	} else
@@ -101,5 +102,6 @@ out:
 	return err;
 out_err:
 	kmem_cache_destroy(sysfs_dir_cachep);
+	sysfs_dir_cachep = NULL;
 	goto out;
 }
diff --git a/fs/udf/file.c b/fs/udf/file.c
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -49,8 +49,7 @@ static int udf_adinicb_readpage(struct f
 	struct inode *inode = page->mapping->host;
 	char *kaddr;
 
-	if (!PageLocked(page))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
 
 	kaddr = kmap(page);
 	memset(kaddr, 0, PAGE_CACHE_SIZE);
@@ -67,8 +66,7 @@ static int udf_adinicb_writepage(struct 
 	struct inode *inode = page->mapping->host;
 	char *kaddr;
 
-	if (!PageLocked(page))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
 
 	kaddr = kmap(page);
 	memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -167,8 +167,8 @@ void udf_expand_file_adinicb(struct inod
 	}
 
 	page = grab_cache_page(inode->i_mapping, 0);
-	if (!PageLocked(page))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
+
 	if (!PageUptodate(page))
 	{
 		kaddr = kmap(page);
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -46,7 +46,7 @@
 #endif
 
 /* How many days come before each month (0-12).  */
-const unsigned short int __mon_yday[2][13] =
+static const unsigned short int __mon_yday[2][13] =
 {
 	/* Normal years.  */
 	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
@@ -103,7 +103,7 @@ udf_stamp_to_time(time_t *dest, long *de
 		offset = 0;
 
 	if ((src.year < EPOCH_YEAR) ||
-		(src.year > EPOCH_YEAR+MAX_YEAR_SECONDS))
+		(src.year >= EPOCH_YEAR+MAX_YEAR_SECONDS))
 	{
 		*dest = -1;
 		*dest_usec = -1;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1196,6 +1196,11 @@ static void destroy_inodecache(void)
 		printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
 }
 
+#ifdef CONFIG_QUOTA
+static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t);
+static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t);
+#endif
+
 static struct super_operations ufs_super_ops = {
 	.alloc_inode	= ufs_alloc_inode,
 	.destroy_inode	= ufs_destroy_inode,
@@ -1206,8 +1211,102 @@ static struct super_operations ufs_super
 	.write_super	= ufs_write_super,
 	.statfs		= ufs_statfs,
 	.remount_fs	= ufs_remount,
+#ifdef CONFIG_QUOTA
+	.quota_read	= ufs_quota_read,
+	.quota_write	= ufs_quota_write,
+#endif
 };
 
+#ifdef CONFIG_QUOTA
+
+/* Read data from quotafile - avoid pagecache and such because we cannot afford
+ * acquiring the locks... As quota files are never truncated and quota code
+ * itself serializes the operations (and noone else should touch the files)
+ * we don't have to be afraid of races */
+static ssize_t ufs_quota_read(struct super_block *sb, int type, char *data,
+			       size_t len, loff_t off)
+{
+	struct inode *inode = sb_dqopt(sb)->files[type];
+	sector_t blk = off >> sb->s_blocksize_bits;
+	int err = 0;
+	int offset = off & (sb->s_blocksize - 1);
+	int tocopy;
+	size_t toread;
+	struct buffer_head *bh;
+	loff_t i_size = i_size_read(inode);
+
+	if (off > i_size)
+		return 0;
+	if (off+len > i_size)
+		len = i_size-off;
+	toread = len;
+	while (toread > 0) {
+		tocopy = sb->s_blocksize - offset < toread ?
+				sb->s_blocksize - offset : toread;
+
+		bh = ufs_bread(inode, blk, 0, &err);
+		if (err)
+			return err;
+		if (!bh)	/* A hole? */
+			memset(data, 0, tocopy);
+		else {
+			memcpy(data, bh->b_data+offset, tocopy);
+			brelse(bh);
+		}
+		offset = 0;
+		toread -= tocopy;
+		data += tocopy;
+		blk++;
+	}
+	return len;
+}
+
+/* Write to quotafile */
+static ssize_t ufs_quota_write(struct super_block *sb, int type,
+				const char *data, size_t len, loff_t off)
+{
+	struct inode *inode = sb_dqopt(sb)->files[type];
+	sector_t blk = off >> sb->s_blocksize_bits;
+	int err = 0;
+	int offset = off & (sb->s_blocksize - 1);
+	int tocopy;
+	size_t towrite = len;
+	struct buffer_head *bh;
+
+	down(&inode->i_sem);
+	while (towrite > 0) {
+		tocopy = sb->s_blocksize - offset < towrite ?
+				sb->s_blocksize - offset : towrite;
+
+		bh = ufs_bread(inode, blk, 1, &err);
+		if (!bh)
+			goto out;
+		lock_buffer(bh);
+		memcpy(bh->b_data+offset, data, tocopy);
+		flush_dcache_page(bh->b_page);
+		set_buffer_uptodate(bh);
+		mark_buffer_dirty(bh);
+		unlock_buffer(bh);
+		brelse(bh);
+		offset = 0;
+		towrite -= tocopy;
+		data += tocopy;
+		blk++;
+	}
+out:
+	if (len == towrite)
+		return err;
+	if (inode->i_size < off+len-towrite)
+		i_size_write(inode, off+len-towrite);
+	inode->i_version++;
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+	mark_inode_dirty(inode);
+	up(&inode->i_sem);
+	return len - towrite;
+}
+
+#endif
+
 static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -208,15 +208,11 @@ static int vfat_valid_longname(const uns
 
 static int vfat_find_form(struct inode *dir, unsigned char *name)
 {
-	struct msdos_dir_entry *de;
-	struct buffer_head *bh = NULL;
-	loff_t i_pos;
-	int res;
-
-	res = fat_scan(dir, name, &bh, &de, &i_pos);
-	brelse(bh);
-	if (res < 0)
+	struct fat_slot_info sinfo;
+	int err = fat_scan(dir, name, &sinfo);
+	if (err)
 		return -ENOENT;
+	brelse(sinfo.bh);
 	return 0;
 }
 
@@ -305,6 +301,7 @@ static int vfat_create_shortname(struct 
 				 wchar_t *uname, int ulen,
 				 unsigned char *name_res, unsigned char *lcase)
 {
+	struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options;
 	wchar_t *ip, *ext_start, *end, *name_start;
 	unsigned char base[9], ext[4], buf[8], *p;
 	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
@@ -312,7 +309,6 @@ static int vfat_create_shortname(struct 
 	int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
 	int is_shortname;
 	struct shortname_info base_info, ext_info;
-	unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
 
 	is_shortname = 1;
 	INIT_SHORTNAME_INFO(&base_info);
@@ -425,9 +421,9 @@ static int vfat_create_shortname(struct 
 		if (vfat_find_form(dir, name_res) == 0)
 			return -EEXIST;
 
-		if (opt_shortname & VFAT_SFN_CREATE_WIN95) {
+		if (opts->shortname & VFAT_SFN_CREATE_WIN95) {
 			return (base_info.upper && ext_info.upper);
-		} else if (opt_shortname & VFAT_SFN_CREATE_WINNT) {
+		} else if (opts->shortname & VFAT_SFN_CREATE_WINNT) {
 			if ((base_info.upper || base_info.lower) &&
 			    (ext_info.upper || ext_info.lower)) {
 				if (!base_info.upper && base_info.lower)
@@ -442,7 +438,7 @@ static int vfat_create_shortname(struct 
 		}
 	}
 
-	if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
+	if (opts->numtail == 0)
 		if (vfat_find_form(dir, name_res) < 0)
 			return 0;
 
@@ -579,8 +575,9 @@ xlate_to_uni(const unsigned char *name, 
 }
 
 static int vfat_build_slots(struct inode *dir, const unsigned char *name,
-			    int len, struct msdos_dir_slot *ds,
-			    int *slots, int is_dir)
+			    int len, int is_dir, int cluster,
+			    struct timespec *ts,
+			    struct msdos_dir_slot *slots, int *nr_slots)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
 	struct fat_mount_options *opts = &sbi->options;
@@ -590,193 +587,144 @@ static int vfat_build_slots(struct inode
 	unsigned char cksum, lcase;
 	unsigned char msdos_name[MSDOS_NAME];
 	wchar_t *uname;
-	int res, slot, ulen, usize, i;
+	__le16 time, date;
+	int err, ulen, usize, i;
 	loff_t offset;
 
-	*slots = 0;
-	res = vfat_valid_longname(name, len);
-	if (res)
-		return res;
+	*nr_slots = 0;
+	err = vfat_valid_longname(name, len);
+	if (err)
+		return err;
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
 	uname = (wchar_t *)page;
-	res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
+	err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
 			   opts->unicode_xlate, opts->utf8, sbi->nls_io);
-	if (res < 0)
+	if (err)
 		goto out_free;
 
-	res = vfat_is_used_badchars(uname, ulen);
-	if (res < 0)
+	err = vfat_is_used_badchars(uname, ulen);
+	if (err)
 		goto out_free;
 
-	res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
+	err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
 				    msdos_name, &lcase);
-	if (res < 0)
+	if (err < 0)
 		goto out_free;
-	else if (res == 1) {
-		de = (struct msdos_dir_entry *)ds;
-		res = 0;
+	else if (err == 1) {
+		de = (struct msdos_dir_entry *)slots;
+		err = 0;
 		goto shortname;
 	}
 
 	/* build the entry of long file name */
-	*slots = usize / 13;
 	for (cksum = i = 0; i < 11; i++)
 		cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
 
-	for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
-		ps->id = slot;
+	*nr_slots = usize / 13;
+	for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {
+		ps->id = i;
 		ps->attr = ATTR_EXT;
 		ps->reserved = 0;
 		ps->alias_checksum = cksum;
 		ps->start = 0;
-		offset = (slot - 1) * 13;
+		offset = (i - 1) * 13;
 		fatwchar_to16(ps->name0_4, uname + offset, 5);
 		fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
 		fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
 	}
-	ds[0].id |= 0x40;
+	slots[0].id |= 0x40;
 	de = (struct msdos_dir_entry *)ps;
 
 shortname:
 	/* build the entry of 8.3 alias name */
-	(*slots)++;
+	(*nr_slots)++;
 	memcpy(de->name, msdos_name, MSDOS_NAME);
 	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 	de->lcase = lcase;
-	de->adate = de->cdate = de->date = 0;
-	de->ctime = de->time = 0;
-	de->ctime_ms = 0;
-	de->start = 0;
-	de->starthi = 0;
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+	de->time = de->ctime = time;
+	de->date = de->cdate = de->adate = date;
+	de->ctime_cs = 0;
+	de->start = cpu_to_le16(cluster);
+	de->starthi = cpu_to_le16(cluster >> 16);
 	de->size = 0;
-
 out_free:
 	free_page(page);
-	return res;
+	return err;
 }
 
-static int vfat_add_entry(struct inode *dir, struct qstr *qname,
-			  int is_dir, struct vfat_slot_info *sinfo_out,
-			  struct buffer_head **bh, struct msdos_dir_entry **de)
+static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
+			  int cluster, struct timespec *ts,
+			  struct fat_slot_info *sinfo)
 {
-	struct msdos_dir_slot *dir_slots;
-	loff_t offset;
-	int res, slots, slot;
+	struct msdos_dir_slot *slots;
 	unsigned int len;
-	struct msdos_dir_entry *dummy_de;
-	struct buffer_head *dummy_bh;
-	loff_t dummy_i_pos;
+	int err, nr_slots;
 
 	len = vfat_striptail_len(qname);
 	if (len == 0)
 		return -ENOENT;
 
-	dir_slots = kmalloc(sizeof(*dir_slots) * MSDOS_SLOTS, GFP_KERNEL);
-	if (dir_slots == NULL)
+	slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_KERNEL);
+	if (slots == NULL)
 		return -ENOMEM;
 
-	res = vfat_build_slots(dir, qname->name, len,
-			       dir_slots, &slots, is_dir);
-	if (res < 0)
+	err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,
+			       slots, &nr_slots);
+	if (err)
 		goto cleanup;
 
-	/* build the empty directory entry of number of slots */
-	offset =
-	    fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
-	if (offset < 0) {
-		res = offset;
+	err = fat_add_entries(dir, slots, nr_slots, sinfo);
+	if (err)
 		goto cleanup;
-	}
-	brelse(dummy_bh);
 
-	/* Now create the new entry */
-	*bh = NULL;
-	for (slot = 0; slot < slots; slot++) {
-		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
-			res = -EIO;
-			goto cleanup;
-		}
-		memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
-		mark_buffer_dirty(*bh);
-	}
-
-	res = 0;
 	/* update timestamp */
-	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
-	mark_inode_dirty(dir);
-
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
-	dir->i_mtime.tv_nsec = 0;
-	(*de)->ctime = (*de)->time;
-	(*de)->adate = (*de)->cdate = (*de)->date;
-
-	mark_buffer_dirty(*bh);
-
-	/* slots can't be less than 1 */
-	sinfo_out->long_slots = slots - 1;
-	sinfo_out->longname_offset =
-		offset - sizeof(struct msdos_dir_slot) * slots;
-
+	dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
 cleanup:
-	kfree(dir_slots);
-	return res;
+	kfree(slots);
+	return err;
 }
 
 static int vfat_find(struct inode *dir, struct qstr *qname,
-		     struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
-		     struct msdos_dir_entry **last_de)
+		     struct fat_slot_info *sinfo)
 {
-	struct super_block *sb = dir->i_sb;
-	loff_t offset;
-	unsigned int len;
-	int res;
-
-	len = vfat_striptail_len(qname);
+	unsigned int len = vfat_striptail_len(qname);
 	if (len == 0)
 		return -ENOENT;
-
-	res = fat_search_long(dir, qname->name, len,
-			      (MSDOS_SB(sb)->options.name_check != 's'),
-			      &offset, &sinfo->longname_offset);
-	if (res > 0) {
-		sinfo->long_slots = res - 1;
-		if (fat_get_entry(dir, &offset, last_bh, last_de, &sinfo->i_pos) >= 0)
-			return 0;
-		res = -EIO;
-	}
-	return res ? res : -ENOENT;
+	return fat_search_long(dir, qname->name, len, sinfo);
 }
 
 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 				  struct nameidata *nd)
 {
-	int res;
-	struct vfat_slot_info sinfo;
-	struct inode *inode;
+	struct super_block *sb = dir->i_sb;
+	struct fat_slot_info sinfo;
+	struct inode *inode = NULL;
 	struct dentry *alias;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	int table;
+	int err, table;
 
 	lock_kernel();
-	table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
+	table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
 	dentry->d_op = &vfat_dentry_ops[table];
 
-	inode = NULL;
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
-	if (res < 0) {
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err) {
 		table++;
 		goto error;
 	}
-	inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
-	brelse(bh);
-	if (res) {
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
 		unlock_kernel();
-		return ERR_PTR(res);
+		return ERR_PTR(PTR_ERR(inode));
 	}
 	alias = d_find_alias(inode);
 	if (alias) {
@@ -805,245 +753,274 @@ static int vfat_create(struct inode *dir
 		       struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode = NULL;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	struct vfat_slot_info sinfo;
-	int res;
+	struct inode *inode;
+	struct fat_slot_info sinfo;
+	struct timespec ts;
+	int err;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
-	if (res < 0)
+
+	ts = CURRENT_TIME_SEC;
+	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
+	if (err)
 		goto out;
-	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
-	brelse(bh);
-	if (!inode)
+	dir->i_version++;
+
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
 		goto out;
-	res = 0;
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
+	}
 	inode->i_version++;
-	dir->i_version++;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out:
 	unlock_kernel();
-	return res;
-}
-
-static void vfat_remove_entry(struct inode *dir, struct vfat_slot_info *sinfo,
-			      struct buffer_head *bh,
-			      struct msdos_dir_entry *de)
-{
-	loff_t offset, i_pos;
-	int i;
-
-	/* remove the shortname */
-	dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
-	dir->i_version++;
-	mark_inode_dirty(dir);
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	/* remove the longname */
-	offset = sinfo->longname_offset;
-	de = NULL;
-	for (i = sinfo->long_slots; i > 0; --i) {
-		if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
-			continue;
-		de->name[0] = DELETED_FLAG;
-		de->attr = ATTR_NONE;
-		mark_buffer_dirty(bh);
-	}
-	brelse(bh);
+	return err;
 }
 
 static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	int res;
+	struct fat_slot_info sinfo;
+	int err;
 
 	lock_kernel();
-	res = fat_dir_empty(inode);
-	if (res)
+
+	err = fat_dir_empty(inode);
+	if (err)
+		goto out;
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err)
 		goto out;
 
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
-	if (res < 0)
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
 		goto out;
+	dir->i_nlink--;
 
-	res = 0;
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
-	/* releases bh */
-	vfat_remove_entry(dir, &sinfo, bh, de);
-	dir->i_nlink--;
 out:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	int res;
+	struct fat_slot_info sinfo;
+	int err;
 
 	lock_kernel();
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
-	if (res < 0)
+
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err)
+		goto out;
+
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
 		goto out;
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
-	/* releases bh */
-	vfat_remove_entry(dir, &sinfo, bh, de);
 out:
 	unlock_kernel();
 
-	return res;
+	return err;
 }
 
 static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode = NULL;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	int res;
+	struct inode *inode;
+	struct fat_slot_info sinfo;
+	struct timespec ts;
+	int err, cluster;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
-	if (res < 0)
+
+	ts = CURRENT_TIME_SEC;
+	cluster = fat_alloc_new_dir(dir, &ts);
+	if (cluster < 0) {
+		err = cluster;
 		goto out;
-	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
-	if (!inode)
-		goto out_brelse;
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
-	inode->i_version++;
+	}
+	err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
+	if (err)
+		goto out_free;
 	dir->i_version++;
 	dir->i_nlink++;
-	inode->i_nlink = 2;	/* no need to mark them dirty */
-	res = fat_new_dir(inode, dir, 1);
-	if (res < 0)
-		goto mkdir_failed;
+
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
+		/* the directory was completed, just return a error */
+		goto out;
+	}
+	inode->i_version++;
+	inode->i_nlink = 2;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
-out_brelse:
-	brelse(bh);
-out:
+
 	unlock_kernel();
-	return res;
+	return 0;
 
-mkdir_failed:
-	inode->i_nlink = 0;
-	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
-	fat_detach(inode);
-	mark_inode_dirty(inode);
-	/* releases bh */
-	vfat_remove_entry(dir, &sinfo, bh, de);
-	iput(inode);
-	dir->i_nlink--;
-	goto out;
+out_free:
+	fat_free_clusters(dir, cluster);
+out:
+	unlock_kernel();
+	return err;
 }
 
 static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
 		       struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct buffer_head *old_bh, *new_bh, *dotdot_bh;
-	struct msdos_dir_entry *old_de, *new_de, *dotdot_de;
+	struct buffer_head *dotdot_bh;
+	struct msdos_dir_entry *dotdot_de;
 	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
-	int res, is_dir;
-	struct vfat_slot_info old_sinfo, sinfo;
+	struct fat_slot_info old_sinfo, sinfo;
+	struct timespec ts;
+	int err, is_dir, update_dotdot, corrupt = 0;
 
-	old_bh = new_bh = dotdot_bh = NULL;
+	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
 	lock_kernel();
-	res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo, &old_bh,
-			&old_de);
-	if (res < 0)
-		goto rename_done;
+	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
+	if (err)
+		goto out;
 
 	is_dir = S_ISDIR(old_inode->i_mode);
-
-	if (is_dir) {
-		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-			     &dotdot_de, &dotdot_i_pos) < 0) {
-			res = -EIO;
-			goto rename_done;
+	update_dotdot = (is_dir && old_dir != new_dir);
+	if (update_dotdot) {
+		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+					 &dotdot_i_pos) < 0) {
+			err = -EIO;
+			goto out;
 		}
 	}
 
-	if (new_dentry->d_inode) {
-		res = vfat_find(new_dir, &new_dentry->d_name, &sinfo, &new_bh,
-				&new_de);
-		if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+	ts = CURRENT_TIME_SEC;
+	if (new_inode) {
+		err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
+		if (err)
+			goto out;
+		if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
-			goto rename_done;
+			goto out;
 		}
 
 		if (is_dir) {
-			res = fat_dir_empty(new_inode);
-			if (res)
-				goto rename_done;
+			err = fat_dir_empty(new_inode);
+			if (err)
+				goto out;
 		}
 		fat_detach(new_inode);
 	} else {
-		res = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
-				     &sinfo, &new_bh, &new_de);
-		if (res < 0)
-			goto rename_done;
+		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
+				     &ts, &sinfo);
+		if (err)
+			goto out;
 	}
-
 	new_dir->i_version++;
 
-	/* releases old_bh */
-	vfat_remove_entry(old_dir, &old_sinfo, old_bh, old_de);
-	old_bh = NULL;
 	fat_detach(old_inode);
 	fat_attach(old_inode, sinfo.i_pos);
-	mark_inode_dirty(old_inode);
+	if (IS_DIRSYNC(new_dir)) {
+		err = fat_sync_inode(old_inode);
+		if (err)
+			goto error_inode;
+	} else
+		mark_inode_dirty(old_inode);
 
-	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(old_dir);
-	if (new_inode) {
-		new_inode->i_nlink--;
-		new_inode->i_ctime = CURRENT_TIME_SEC;
-	}
-
-	if (is_dir) {
+	if (update_dotdot) {
 		int start = MSDOS_I(new_dir)->i_logstart;
 		dotdot_de->start = cpu_to_le16(start);
-		dotdot_de->starthi = cpu_to_le16(start>>16);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
 		mark_buffer_dirty(dotdot_bh);
-		old_dir->i_nlink--;
-		if (new_inode) {
-			new_inode->i_nlink--;
-		} else {
-			new_dir->i_nlink++;
-			mark_inode_dirty(new_dir);
+		if (IS_DIRSYNC(new_dir)) {
+			err = sync_dirty_buffer(dotdot_bh);
+			if (err)
+				goto error_dotdot;
 		}
+		old_dir->i_nlink--;
+		if (!new_inode)
+ 			new_dir->i_nlink++;
 	}
 
-rename_done:
+	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
+	old_sinfo.bh = NULL;
+	if (err)
+		goto error_dotdot;
+	old_dir->i_version++;
+	old_dir->i_ctime = old_dir->i_mtime = ts;
+	if (IS_DIRSYNC(old_dir))
+		(void)fat_sync_inode(old_dir);
+	else
+		mark_inode_dirty(old_dir);
+
+	if (new_inode) {
+		if (is_dir)
+			new_inode->i_nlink -= 2;
+		else
+			new_inode->i_nlink--;
+		new_inode->i_ctime = ts;
+	}
+out:
+	brelse(sinfo.bh);
 	brelse(dotdot_bh);
-	brelse(old_bh);
-	brelse(new_bh);
+	brelse(old_sinfo.bh);
 	unlock_kernel();
-	return res;
+
+	return err;
+
+error_dotdot:
+	/* data cluster is shared, serious corruption */
+	corrupt = 1;
+
+	if (update_dotdot) {
+		int start = MSDOS_I(old_dir)->i_logstart;
+		dotdot_de->start = cpu_to_le16(start);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
+		mark_buffer_dirty(dotdot_bh);
+		corrupt |= sync_dirty_buffer(dotdot_bh);
+	}
+error_inode:
+	fat_detach(old_inode);
+	fat_attach(old_inode, old_sinfo.i_pos);
+	if (new_inode) {
+		fat_attach(new_inode, sinfo.i_pos);
+		if (corrupt)
+			corrupt |= fat_sync_inode(new_inode);
+	} else {
+		/*
+		 * If new entry was not sharing the data cluster, it
+		 * shouldn't be serious corruption.
+		 */
+		int err2 = fat_remove_entries(new_dir, &sinfo);
+		if (corrupt)
+			corrupt |= err2;
+		sinfo.bh = NULL;
+	}
+	if (corrupt < 0) {
+		fat_fs_panic(new_dir->i_sb,
+			     "%s: Filesystem corrupted (i_pos %lld)",
+			     __FUNCTION__, sinfo.i_pos);
+	}
+	goto out;
 }
 
 static struct inode_operations vfat_dir_inode_operations = {
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -49,7 +49,7 @@ ifeq ($(CONFIG_XFS_TRACE),y)
 	EXTRA_CFLAGS += -DXFS_LOG_TRACE
 	EXTRA_CFLAGS += -DXFS_RW_TRACE
 	EXTRA_CFLAGS += -DPAGEBUF_TRACE
-	# EXTRA_CFLAGS += -DXFS_VNODE_TRACE
+	EXTRA_CFLAGS += -DXFS_VNODE_TRACE
 endif
 
 obj-$(CONFIG_XFS_FS)		+= xfs.o
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -125,12 +125,6 @@ kmem_zone_destroy(kmem_zone_t *zone)
 		BUG();
 }
 
-static __inline int
-kmem_zone_shrink(kmem_zone_t *zone)
-{
-	return kmem_cache_shrink(zone);
-}
-
 extern void	    *kmem_zone_zalloc(kmem_zone_t *, int);
 extern void	    *kmem_zone_alloc(kmem_zone_t *, int);
 
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -558,7 +558,8 @@ xfs_submit_page(
 	int			i;
 
 	BUG_ON(PageWriteback(page));
-	set_page_writeback(page);
+	if (bh_count)
+		set_page_writeback(page);
 	if (clear_dirty)
 		clear_page_dirty(page);
 	unlock_page(page);
@@ -578,9 +579,6 @@ xfs_submit_page(
 
 		if (probed_page && clear_dirty)
 			wbc->nr_to_write--;	/* Wrote an "extra" page */
-	} else {
-		end_page_writeback(page);
-		wbc->pages_skipped++;	/* We didn't write this page */
 	}
 }
 
@@ -602,21 +600,26 @@ xfs_convert_page(
 {
 	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
 	xfs_iomap_t		*mp = iomapp, *tmp;
-	unsigned long		end, offset;
-	pgoff_t			end_index;
-	int			i = 0, index = 0;
+	unsigned long		offset, end_offset;
+	int			index = 0;
 	int			bbits = inode->i_blkbits;
+	int			len, page_dirty;
 
-	end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
-	if (page->index < end_index) {
-		end = PAGE_CACHE_SIZE;
-	} else {
-		end = i_size_read(inode) & (PAGE_CACHE_SIZE-1);
-	}
+	end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1));
+
+	/*
+	 * page_dirty is initially a count of buffers on the page before
+	 * EOF and is decrememted as we move each into a cleanable state.
+	 */
+	len = 1 << inode->i_blkbits;
+	end_offset = max(end_offset, PAGE_CACHE_SIZE);
+	end_offset = roundup(end_offset, len);
+	page_dirty = end_offset / len;
+
+	offset = 0;
 	bh = head = page_buffers(page);
 	do {
-		offset = i << bbits;
-		if (offset >= end)
+		if (offset >= end_offset)
 			break;
 		if (!(PageUptodate(page) || buffer_uptodate(bh)))
 			continue;
@@ -625,6 +628,7 @@ xfs_convert_page(
 			if (startio) {
 				lock_buffer(bh);
 				bh_arr[index++] = bh;
+				page_dirty--;
 			}
 			continue;
 		}
@@ -657,10 +661,11 @@ xfs_convert_page(
 			unlock_buffer(bh);
 			mark_buffer_dirty(bh);
 		}
-	} while (i++, (bh = bh->b_this_page) != head);
+		page_dirty--;
+	} while (offset += len, (bh = bh->b_this_page) != head);
 
-	if (startio) {
-		xfs_submit_page(page, wbc, bh_arr, index, 1, index == i);
+	if (startio && index) {
+		xfs_submit_page(page, wbc, bh_arr, index, 1, !page_dirty);
 	} else {
 		unlock_page(page);
 	}
@@ -725,8 +730,11 @@ xfs_page_state_convert(
 	__uint64_t              end_offset;
 	pgoff_t                 end_index, last_index, tlast;
 	int			len, err, i, cnt = 0, uptodate = 1;
-	int			flags = startio ? 0 : BMAPI_TRYLOCK;
-	int			page_dirty, delalloc = 0;
+	int			flags;
+	int			page_dirty;
+
+	/* wait for other IO threads? */
+	flags = (startio && wbc->sync_mode != WB_SYNC_NONE) ? 0 : BMAPI_TRYLOCK;
 
 	/* Is this page beyond the end of the file? */
 	offset = i_size_read(inode);
@@ -740,19 +748,22 @@ xfs_page_state_convert(
 		}
 	}
 
-	offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	end_offset = min_t(unsigned long long,
-			offset + PAGE_CACHE_SIZE, i_size_read(inode));
-
-	bh = head = page_buffers(page);
-	iomp = NULL;
+			(loff_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset);
+	offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 
 	/*
-	 * page_dirty is initially a count of buffers on the page and
-	 * is decrememted as we move each into a cleanable state.
+	 * page_dirty is initially a count of buffers on the page before
+	 * EOF and is decrememted as we move each into a cleanable state.
 	 */
-	len = bh->b_size;
-	page_dirty = PAGE_CACHE_SIZE / len;
+	len = 1 << inode->i_blkbits;
+	p_offset = max(p_offset, PAGE_CACHE_SIZE);
+	p_offset = roundup(p_offset, len);
+	page_dirty = p_offset / len;
+
+	iomp = NULL;
+	p_offset = 0;
+	bh = head = page_buffers(page);
 
 	do {
 		if (offset >= end_offset)
@@ -804,7 +815,6 @@ xfs_page_state_convert(
 		 */
 		} else if (buffer_delay(bh)) {
 			if (!iomp) {
-				delalloc = 1;
 				err = xfs_map_blocks(inode, offset, len, &iomap,
 						BMAPI_ALLOCATE | flags);
 				if (err) {
@@ -875,14 +885,14 @@ xfs_page_state_convert(
 	if (uptodate && bh == head)
 		SetPageUptodate(page);
 
-	if (startio)
-		xfs_submit_page(page, wbc, bh_arr, cnt, 0, 1);
+	if (startio) {
+		xfs_submit_page(page, wbc, bh_arr, cnt, 0, !page_dirty);
+	}
 
 	if (iomp) {
-		tlast = (iomp->iomap_offset + iomp->iomap_bsize - 1) >>
+		offset = (iomp->iomap_offset + iomp->iomap_bsize - 1) >>
 					PAGE_CACHE_SHIFT;
-		if (delalloc && (tlast > last_index))
-			tlast = last_index;
+		tlast = min_t(pgoff_t, offset, last_index);
 		xfs_cluster_write(inode, page->index + 1, iomp, wbc,
 					startio, unmapped, tlast);
 	}
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -966,7 +966,7 @@ pagebuf_cond_lock(			/* lock buffer, if 
 	return(locked ? 0 : -EBUSY);
 }
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(XFS_BLI_TRACE)
 /*
  *	pagebuf_lock_value
  *
@@ -1283,7 +1283,7 @@ STATIC void
 _pagebuf_ioapply(
 	xfs_buf_t		*pb)
 {
-	int			i, map_i, total_nr_pages, nr_pages;
+	int			i, rw, map_i, total_nr_pages, nr_pages;
 	struct bio		*bio;
 	int			offset = pb->pb_offset;
 	int			size = pb->pb_count_desired;
@@ -1294,6 +1294,13 @@ _pagebuf_ioapply(
 	total_nr_pages = pb->pb_page_count;
 	map_i = 0;
 
+	if (pb->pb_flags & _PBF_RUN_QUEUES) {
+		pb->pb_flags &= ~_PBF_RUN_QUEUES;
+		rw = (pb->pb_flags & PBF_READ) ? READ_SYNC : WRITE_SYNC;
+	} else {
+		rw = (pb->pb_flags & PBF_READ) ? READ : WRITE;
+	}
+
 	/* Special code path for reading a sub page size pagebuf in --
 	 * we populate up the whole page, and hence the other metadata
 	 * in the same page.  This optimization is only valid when the
@@ -1365,19 +1372,13 @@ next_chunk:
 
 submit_io:
 	if (likely(bio->bi_size)) {
-		submit_bio((pb->pb_flags & PBF_READ) ? READ : WRITE, bio);
+		submit_bio(rw, bio);
 		if (size)
 			goto next_chunk;
 	} else {
 		bio_put(bio);
 		pagebuf_ioerror(pb, EIO);
 	}
-
-	if (pb->pb_flags & _PBF_RUN_QUEUES) {
-		pb->pb_flags &= ~_PBF_RUN_QUEUES;
-		if (atomic_read(&pb->pb_io_remaining) > 1)
-			blk_run_address_space(pb->pb_target->pbr_mapping);
-	}
 }
 
 /*
@@ -1745,13 +1746,15 @@ STATIC DECLARE_COMPLETION(pagebuf_daemon
 STATIC struct task_struct *pagebuf_daemon_task;
 STATIC int pagebuf_daemon_active;
 STATIC int force_flush;
-
+STATIC int force_sleep;
 
 STATIC int
 pagebuf_daemon_wakeup(
 	int			priority,
 	unsigned int		mask)
 {
+	if (force_sleep)
+		return 0;
 	force_flush = 1;
 	barrier();
 	wake_up_process(pagebuf_daemon_task);
@@ -1777,7 +1780,12 @@ pagebuf_daemon(
 
 	INIT_LIST_HEAD(&tmp);
 	do {
-		try_to_freeze(PF_FREEZE);
+		if (unlikely(current->flags & PF_FREEZE)) {
+			force_sleep = 1;
+			refrigerator(PF_FREEZE);
+		} else {
+			force_sleep = 0;
+		}
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout((xfs_buf_timer_centisecs * HZ) / 100);
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -31,6 +31,25 @@
  */
 
 #include "xfs.h"
+#include "xfs_types.h"
+#include "xfs_dmapi.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_dir.h"
+#include "xfs_mount.h"
+#include "xfs_export.h"
+
+/*
+ * XFS encode and decodes the fileid portion of NFS filehandles
+ * itself instead of letting the generic NFS code do it.  This
+ * allows filesystems with 64 bit inode numbers to be exported.
+ *
+ * Note that a side effect is that xfs_vget() won't be passed a
+ * zero inode/generation pair under normal circumstances.  As
+ * however a malicious client could send us such data, the check
+ * remains in that code.
+ */
 
 
 STATIC struct dentry *
@@ -44,26 +63,87 @@ linvfs_decode_fh(
 		struct dentry	*de),
 	void			*context)
 {
-	__u32 parent[2];
-	parent[0] = parent[1] = 0;
-	
-	if (fh_len < 2 || fileid_type > 2)
+	xfs_fid2_t		ifid;
+	xfs_fid2_t		pfid;
+	void			*parent = NULL;
+	int			is64 = 0;
+	__u32			*p = fh;
+
+#if XFS_BIG_INUMS
+	is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG);
+	fileid_type &= ~XFS_FILEID_TYPE_64FLAG;
+#endif
+
+	/*
+	 * Note that we only accept fileids which are long enough
+	 * rather than allow the parent generation number to default
+	 * to zero.  XFS considers zero a valid generation number not
+	 * an invalid/wildcard value.  There's little point printk'ing
+	 * a warning here as we don't have the client information
+	 * which would make such a warning useful.
+	 */
+	if (fileid_type > 2 ||
+	    fh_len < xfs_fileid_length((fileid_type == 2), is64))
 		return NULL;
-	
-	if (fileid_type == 2 && fh_len > 2) {
-		if (fh_len == 3) {
-			printk(KERN_WARNING
-			       "XFS: detected filehandle without "
-			       "parent inode generation information.");
-			return ERR_PTR(-ESTALE);
-		}
-			
-		parent[0] = fh[2];
-		parent[1] = fh[3];
+
+	p = xfs_fileid_decode_fid2(p, &ifid, is64);
+
+	if (fileid_type == 2) {
+		p = xfs_fileid_decode_fid2(p, &pfid, is64);
+		parent = &pfid;
 	}
 	
+	fh = (__u32 *)&ifid;
 	return find_exported_dentry(sb, fh, parent, acceptable, context);
+}
+
 
+STATIC int
+linvfs_encode_fh(
+	struct dentry		*dentry,
+	__u32			*fh,
+	int			*max_len,
+	int			connectable)
+{
+	struct inode		*inode = dentry->d_inode;
+	int			type = 1;
+	__u32			*p = fh;
+	int			len;
+	int			is64 = 0;
+#if XFS_BIG_INUMS
+	vfs_t			*vfs = LINVFS_GET_VFS(inode->i_sb);
+	xfs_mount_t		*mp = XFS_VFSTOM(vfs);
+	
+	if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT)) {
+		/* filesystem may contain 64bit inode numbers */
+		is64 = XFS_FILEID_TYPE_64FLAG;
+	}
+#endif
+
+	/* Directories don't need their parent encoded, they have ".." */
+	if (S_ISDIR(inode->i_mode))
+	    connectable = 0;
+
+	/*
+	 * Only encode if there is enough space given.  In practice
+	 * this means we can't export a filesystem with 64bit inodes
+	 * over NFSv2 with the subtree_check export option; the other
+	 * seven combinations work.  The real answer is "don't use v2".
+	 */
+	len = xfs_fileid_length(connectable, is64);
+	if (*max_len < len)
+		return 255;
+	*max_len = len;
+
+	p = xfs_fileid_encode_inode(p, inode, is64);
+	if (connectable) {
+		spin_lock(&dentry->d_lock);
+		p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64);
+		spin_unlock(&dentry->d_lock);
+		type = 2;
+	}
+	BUG_ON((p - fh) != len);
+	return type | is64;
 }
 
 STATIC struct dentry *
@@ -74,16 +154,10 @@ linvfs_get_dentry(
 	vnode_t			*vp;
 	struct inode		*inode;
 	struct dentry		*result;
-	xfs_fid2_t		xfid;
 	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 	int			error;
 
-	xfid.fid_len = sizeof(xfs_fid2_t) - sizeof(xfid.fid_len);
-	xfid.fid_pad = 0;
-	xfid.fid_gen = ((__u32 *)data)[1];
-	xfid.fid_ino = ((__u32 *)data)[0];
-
-	VFS_VGET(vfsp, &vp, (fid_t *)&xfid, error);
+	VFS_VGET(vfsp, &vp, (fid_t *)data, error);
 	if (error || vp == NULL)
 		return ERR_PTR(-ESTALE) ;
 
@@ -125,6 +199,7 @@ linvfs_get_parent(
 
 struct export_operations linvfs_export_ops = {
 	.decode_fh		= linvfs_decode_fh,
+	.encode_fh		= linvfs_encode_fh,
 	.get_parent		= linvfs_get_parent,
 	.get_dentry		= linvfs_get_dentry,
 };
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h
new file mode 100644
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_export.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_EXPORT_H__
+#define __XFS_EXPORT_H__
+
+/*
+ * Common defines for code related to exporting XFS filesystems over NFS.
+ *
+ * The NFS fileid goes out on the wire as an array of
+ * 32bit unsigned ints in host order.  There are 5 possible
+ * formats.
+ *
+ * (1)	fileid_type=0x00
+ *	(no fileid data; handled by the generic code)
+ *
+ * (2)	fileid_type=0x01
+ *	inode-num
+ *	generation
+ *
+ * (3)	fileid_type=0x02
+ *	inode-num
+ *	generation
+ *	parent-inode-num
+ *	parent-generation
+ *
+ * (4)	fileid_type=0x81
+ *	inode-num-lo32
+ *	inode-num-hi32
+ *	generation
+ *
+ * (5)	fileid_type=0x82
+ *	inode-num-lo32
+ *	inode-num-hi32
+ *	generation
+ *	parent-inode-num-lo32
+ *	parent-inode-num-hi32
+ *	parent-generation
+ *
+ * Note, the NFS filehandle also includes an fsid portion which
+ * may have an inode number in it.  That number is hardcoded to
+ * 32bits and there is no way for XFS to intercept it.  In
+ * practice this means when exporting an XFS filesytem with 64bit
+ * inodes you should either export the mountpoint (rather than
+ * a subdirectory) or use the "fsid" export option.
+ */
+
+/* This flag goes on the wire.  Don't play with it. */
+#define XFS_FILEID_TYPE_64FLAG	0x80	/* NFS fileid has 64bit inodes */
+
+/* Calculate the length in u32 units of the fileid data */
+static inline int
+xfs_fileid_length(int hasparent, int is64)
+{
+	return hasparent ? (is64 ? 6 : 4) : (is64 ? 3 : 2);
+}
+
+/*
+ * Decode encoded inode information (either for the inode itself
+ * or the parent) into an xfs_fid2_t structure.  Advances and
+ * returns the new data pointer
+ */
+static inline __u32 *
+xfs_fileid_decode_fid2(__u32 *p, xfs_fid2_t *fid, int is64)
+{
+	fid->fid_len = sizeof(xfs_fid2_t) - sizeof(fid->fid_len);
+	fid->fid_pad = 0;
+	fid->fid_ino = *p++;
+#if XFS_BIG_INUMS
+	if (is64)
+		fid->fid_ino |= (((__u64)(*p++)) << 32);
+#endif
+	fid->fid_gen = *p++;
+	return p;
+}
+
+/*
+ * Encode inode information (either for the inode itself or the
+ * parent) into a fileid buffer.  Advances and returns the new
+ * data pointer.
+ */
+static inline __u32 *
+xfs_fileid_encode_inode(__u32 *p, struct inode *inode, int is64)
+{
+	*p++ = (__u32)inode->i_ino;
+#if XFS_BIG_INUMS
+	if (is64)
+		*p++ = (__u32)(inode->i_ino >> 32);
+#endif
+	*p++ = inode->i_generation;
+	return p;
+}
+
+#endif	/* __XFS_EXPORT_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -482,11 +482,82 @@ linvfs_mprotect(
 }
 #endif /* HAVE_VMOP_MPROTECT */
 
+#ifdef HAVE_FOP_OPEN_EXEC
+/* If the user is attempting to execute a file that is offline then
+ * we have to trigger a DMAPI READ event before the file is marked as busy
+ * otherwise the invisible I/O will not be able to write to the file to bring
+ * it back online.
+ */
+STATIC int
+linvfs_open_exec(
+	struct inode	*inode)
+{
+	vnode_t		*vp = LINVFS_GET_VP(inode);
+	xfs_mount_t	*mp = XFS_VFSTOM(vp->v_vfsp);
+	int		error = 0;
+	bhv_desc_t	*bdp;
+	xfs_inode_t	*ip;
+
+	if (vp->v_vfsp->vfs_flag & VFS_DMI) {
+		bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
+		if (!bdp) {
+			error = -EINVAL;
+			goto open_exec_out;
+		}
+		ip = XFS_BHVTOI(bdp);
+		if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) {
+			error = -XFS_SEND_DATA(mp, DM_EVENT_READ, vp,
+					       0, 0, 0, NULL);
+		}
+	}
+open_exec_out:
+	return error;
+}
+#endif /* HAVE_FOP_OPEN_EXEC */
+
+/*
+ * Temporary workaround to the AIO direct IO write problem.
+ * This code can go and we can revert to do_sync_write once
+ * the writepage(s) rework is merged.
+ */
+STATIC ssize_t
+linvfs_write(
+	struct file	*filp,
+	const char	__user *buf,
+	size_t		len,
+	loff_t		*ppos)
+{
+	struct kiocb	kiocb;
+	ssize_t		ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	kiocb.ki_pos = *ppos;
+	ret = __linvfs_write(&kiocb, buf, 0, len, kiocb.ki_pos);
+	*ppos = kiocb.ki_pos;
+	return ret;
+}
+STATIC ssize_t
+linvfs_write_invis(
+	struct file	*filp,
+	const char	__user *buf,
+	size_t		len,
+	loff_t		*ppos)
+{
+	struct kiocb	kiocb;
+	ssize_t		ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	kiocb.ki_pos = *ppos;
+	ret = __linvfs_write(&kiocb, buf, IO_INVIS, len, kiocb.ki_pos);
+	*ppos = kiocb.ki_pos;
+	return ret;
+}
+
 
 struct file_operations linvfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
-	.write		= do_sync_write,
+	.write		= linvfs_write,
 	.readv		= linvfs_readv,
 	.writev		= linvfs_writev,
 	.aio_read	= linvfs_aio_read,
@@ -494,18 +565,21 @@ struct file_operations linvfs_file_opera
 	.sendfile	= linvfs_sendfile,
 	.unlocked_ioctl	= linvfs_ioctl,
 #ifdef CONFIG_COMPAT
-	.compat_ioctl   = xfs_compat_ioctl,
+	.compat_ioctl	= linvfs_compat_ioctl,
 #endif
 	.mmap		= linvfs_file_mmap,
 	.open		= linvfs_open,
 	.release	= linvfs_release,
 	.fsync		= linvfs_fsync,
+#ifdef HAVE_FOP_OPEN_EXEC
+	.open_exec	= linvfs_open_exec,
+#endif
 };
 
 struct file_operations linvfs_invis_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
-	.write		= do_sync_write,
+	.write		= linvfs_write_invis,
 	.readv		= linvfs_readv_invis,
 	.writev		= linvfs_writev_invis,
 	.aio_read	= linvfs_aio_read_invis,
@@ -513,7 +587,7 @@ struct file_operations linvfs_invis_file
 	.sendfile	= linvfs_sendfile,
 	.unlocked_ioctl	= linvfs_ioctl_invis,
 #ifdef CONFIG_COMPAT
-	.compat_ioctl   = xfs_compat_invis_ioctl,
+	.compat_ioctl	= linvfs_compat_invis_ioctl,
 #endif
 	.mmap		= linvfs_file_mmap,
 	.open		= linvfs_open,
@@ -526,6 +600,9 @@ struct file_operations linvfs_dir_operat
 	.read		= generic_read_dir,
 	.readdir	= linvfs_readdir,
 	.unlocked_ioctl	= linvfs_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= linvfs_compat_ioctl,
+#endif
 	.fsync		= linvfs_fsync,
 };
 
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -202,10 +202,6 @@ STATIC int
 xfs_vget_fsop_handlereq(
 	xfs_mount_t		*mp,
 	struct inode		*parinode,	/* parent inode pointer    */
-	int			cap,		/* capability level for op */
-	void			__user *arg,	/* userspace data pointer  */
-	unsigned long		size,		/* size of expected struct */
-	/* output arguments */
 	xfs_fsop_handlereq_t	*hreq,
 	vnode_t			**vp,
 	struct inode		**inode)
@@ -222,22 +218,12 @@ xfs_vget_fsop_handlereq(
 	__u32			igen;
 	int			error;
 
-	if (!capable(cap))
-		return XFS_ERROR(EPERM);
-
 	/*
 	 * Only allow handle opens under a directory.
 	 */
 	if (!S_ISDIR(parinode->i_mode))
 		return XFS_ERROR(ENOTDIR);
 
-	/*
-	 * Copy the handle down from the user and validate
-	 * that it looks to be in the correct format.
-	 */
-	if (copy_from_user(hreq, arg, size))
-		return XFS_ERROR(EFAULT);
-
 	hanp = hreq->ihandle;
 	hlen = hreq->ihandlen;
 	handlep = &handle;
@@ -305,9 +291,12 @@ xfs_open_by_handle(
 	vnode_t			*vp;
 	xfs_fsop_handlereq_t	hreq;
 
-	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
-					sizeof(xfs_fsop_handlereq_t),
-					&hreq, &vp, &inode);
+	if (!capable(CAP_SYS_ADMIN))
+		return -XFS_ERROR(EPERM);
+	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
+		return -XFS_ERROR(EFAULT);
+
+	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);
 	if (error)
 		return -error;
 
@@ -387,9 +376,12 @@ xfs_readlink_by_handle(
 	vnode_t			*vp;
 	__u32			olen;
 
-	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
-					sizeof(xfs_fsop_handlereq_t),
-					&hreq, &vp, &inode);
+	if (!capable(CAP_SYS_ADMIN))
+		return -XFS_ERROR(EPERM);
+	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
+		return -XFS_ERROR(EFAULT);
+
+	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);
 	if (error)
 		return -error;
 
@@ -432,10 +424,12 @@ xfs_fssetdm_by_handle(
 	bhv_desc_t		*bdp;
 	vnode_t			*vp;
 
-	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_MKNOD, arg,
-					sizeof(xfs_fsop_setdm_handlereq_t),
-					(xfs_fsop_handlereq_t *)&dmhreq,
-					&vp, &inode);
+	if (!capable(CAP_MKNOD))
+		return -XFS_ERROR(EPERM);
+	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
+		return -XFS_ERROR(EFAULT);
+
+	error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode);
 	if (error)
 		return -error;
 
@@ -470,21 +464,113 @@ xfs_attrlist_by_handle(
 	xfs_fsop_attrlist_handlereq_t al_hreq;
 	struct inode		*inode;
 	vnode_t			*vp;
+	char			*kbuf;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -XFS_ERROR(EPERM);
+	if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
+		return -XFS_ERROR(EFAULT);
+	if (al_hreq.buflen > XATTR_LIST_MAX)
+		return -XFS_ERROR(EINVAL);
 
-	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
-					sizeof(xfs_fsop_attrlist_handlereq_t),
-					(xfs_fsop_handlereq_t *)&al_hreq,
-					&vp, &inode);
+	error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq,
+			&vp, &inode);
 	if (error)
-		return -error;
+		goto out;
+
+	kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
+	if (!kbuf)
+		goto out_vn_rele;
 
 	cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
-	VOP_ATTR_LIST(vp, al_hreq.buffer, al_hreq.buflen, al_hreq.flags,
+	VOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags,
 			cursor, NULL, error);
+	if (error)
+		goto out_kfree;
+
+	if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
+		error = -EFAULT;
+
+ out_kfree:
+	kfree(kbuf);
+ out_vn_rele:
 	VN_RELE(vp);
+ out:
+	return -error;
+}
+
+STATIC int
+xfs_attrmulti_attr_get(
+	struct vnode		*vp,
+	char			*name,
+	char			__user *ubuf,
+	__uint32_t		*len,
+	__uint32_t		flags)
+{
+	char			*kbuf;
+	int			error = EFAULT;
+	
+	if (*len > XATTR_SIZE_MAX)
+		return EINVAL;
+	kbuf = kmalloc(*len, GFP_KERNEL);
+	if (!kbuf)
+		return ENOMEM;
+
+	VOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error);
 	if (error)
-		return -error;
-	return 0;
+		goto out_kfree;
+
+	if (copy_to_user(ubuf, kbuf, *len))
+		error = EFAULT;
+
+ out_kfree:
+	kfree(kbuf);
+	return error;
+}
+
+STATIC int
+xfs_attrmulti_attr_set(
+	struct vnode		*vp,
+	char			*name,
+	const char		__user *ubuf,
+	__uint32_t		len,
+	__uint32_t		flags)
+{
+	char			*kbuf;
+	int			error = EFAULT;
+
+	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
+		return EPERM;
+	if (len > XATTR_SIZE_MAX)
+		return EINVAL;
+
+	kbuf = kmalloc(len, GFP_KERNEL);
+	if (!kbuf)
+		return ENOMEM;
+
+	if (copy_from_user(kbuf, ubuf, len))
+		goto out_kfree;
+			
+	VOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error);
+
+ out_kfree:
+	kfree(kbuf);
+	return error;
+}
+
+STATIC int
+xfs_attrmulti_attr_remove(
+	struct vnode		*vp,
+	char			*name,
+	__uint32_t		flags)
+{
+	int			error;
+
+	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
+		return EPERM;
+
+	VOP_ATTR_REMOVE(vp, name, flags, NULL, error);
+	return error;
 }
 
 STATIC int
@@ -500,55 +586,59 @@ xfs_attrmulti_by_handle(
 	struct inode		*inode;
 	vnode_t			*vp;
 	unsigned int		i, size;
+	char			*attr_name;
 
-	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
-					sizeof(xfs_fsop_attrmulti_handlereq_t),
-					(xfs_fsop_handlereq_t *)&am_hreq,
-					&vp, &inode);
+	if (!capable(CAP_SYS_ADMIN))
+		return -XFS_ERROR(EPERM);
+	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
+		return -XFS_ERROR(EFAULT);
+
+	error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode);
 	if (error)
-		return -error;
+		goto out;
 
+	error = E2BIG;
 	size = am_hreq.opcount * sizeof(attr_multiop_t);
-	if (!size || size > 16 * PAGE_SIZE) {
-		VN_RELE(vp);
-		return -XFS_ERROR(E2BIG);
-	}
+	if (!size || size > 16 * PAGE_SIZE)
+		goto out_vn_rele;
 
-	ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
-	if (!ops) {
-		VN_RELE(vp);
-		return -XFS_ERROR(ENOMEM);
-	}
+	error = ENOMEM;
+	ops = kmalloc(size, GFP_KERNEL);
+	if (!ops)
+		goto out_vn_rele;
+
+	error = EFAULT;
+	if (copy_from_user(ops, am_hreq.ops, size))
+		goto out_kfree_ops;
+
+	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
+	if (!attr_name)
+		goto out_kfree_ops;
 
-	if (copy_from_user(ops, am_hreq.ops, size)) {
-		kfree(ops);
-		VN_RELE(vp);
-		return -XFS_ERROR(EFAULT);
-	}
 
+	error = 0;
 	for (i = 0; i < am_hreq.opcount; i++) {
-		switch(ops[i].am_opcode) {
+		ops[i].am_error = strncpy_from_user(attr_name,
+				ops[i].am_attrname, MAXNAMELEN);
+		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
+			error = -ERANGE;
+		if (ops[i].am_error < 0)
+			break;
+
+		switch (ops[i].am_opcode) {
 		case ATTR_OP_GET:
-			VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
-					&ops[i].am_length, ops[i].am_flags,
-					NULL, ops[i].am_error);
+			ops[i].am_error = xfs_attrmulti_attr_get(vp,
+					attr_name, ops[i].am_attrvalue,
+					&ops[i].am_length, ops[i].am_flags);
 			break;
 		case ATTR_OP_SET:
-			if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-				ops[i].am_error = EPERM;
-				break;
-			}
-			VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
-					ops[i].am_length, ops[i].am_flags,
-					NULL, ops[i].am_error);
+			ops[i].am_error = xfs_attrmulti_attr_set(vp,
+					attr_name, ops[i].am_attrvalue,
+					ops[i].am_length, ops[i].am_flags);
 			break;
 		case ATTR_OP_REMOVE:
-			if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-				ops[i].am_error = EPERM;
-				break;
-			}
-			VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
-					NULL, ops[i].am_error);
+			ops[i].am_error = xfs_attrmulti_attr_remove(vp,
+					attr_name, ops[i].am_flags);
 			break;
 		default:
 			ops[i].am_error = EINVAL;
@@ -556,11 +646,15 @@ xfs_attrmulti_by_handle(
 	}
 
 	if (copy_to_user(am_hreq.ops, ops, size))
-		error = -XFS_ERROR(EFAULT);
+		error = XFS_ERROR(EFAULT);
 
+	kfree(attr_name);
+ out_kfree_ops:
 	kfree(ops);
+ out_vn_rele:
 	VN_RELE(vp);
-	return error;
+ out:
+	return -error;
 }
 
 /* prototypes for a few of the stack-hungry cases that have
@@ -1149,7 +1243,7 @@ xfs_ioc_xattr(
 
 		va.va_mask = XFS_AT_XFLAGS;
 		va.va_xflags = xfs_merge_ioc_xflags(flags,
-				xfs_dic2xflags(&ip->i_d, ARCH_NOCONVERT));
+				xfs_ip2xflags(ip));
 
 		VOP_SETATTR(vp, &va, attr_flags, NULL, error);
 		if (!error)
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -58,8 +58,9 @@ typedef struct xfs_fsop_bulkreq32 {
 	__s32		ocount;		/* output count pointer		*/
 } xfs_fsop_bulkreq32_t;
 
-static unsigned long
-xfs_ioctl32_bulkstat(unsigned long arg)
+STATIC unsigned long
+xfs_ioctl32_bulkstat(
+	unsigned long		arg)
 {
 	xfs_fsop_bulkreq32_t	__user *p32 = (void __user *)arg;
 	xfs_fsop_bulkreq_t	__user *p = compat_alloc_user_space(sizeof(*p));
@@ -78,11 +79,11 @@ xfs_ioctl32_bulkstat(unsigned long arg)
 }
 #endif
 
-static long
-__xfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
+STATIC long
+__linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
 {
 	int		error;
-	struct inode *inode = f->f_dentry->d_inode;
+	struct		inode *inode = f->f_dentry->d_inode;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 
 	switch (cmd) {
@@ -152,12 +153,20 @@ __xfs_compat_ioctl(int mode, struct file
 	return error;
 }
 
-long xfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
+long
+linvfs_compat_ioctl(
+	struct file		*f,
+	unsigned		cmd,
+	unsigned long		arg)
 {
-	return __xfs_compat_ioctl(0, f, cmd, arg);
+	return __linvfs_compat_ioctl(0, f, cmd, arg);
 }
 
-long xfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg)
+long
+linvfs_compat_invis_ioctl(
+	struct file		*f,
+	unsigned		cmd,
+	unsigned long		arg)
 {
-	return __xfs_compat_ioctl(IO_INVIS, f, cmd, arg);
+	return __linvfs_compat_ioctl(IO_INVIS, f, cmd, arg);
 }
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/linux-2.6/xfs_ioctl32.h
--- a/fs/xfs/linux-2.6/xfs_ioctl32.h
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -30,5 +30,5 @@
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
-long xfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
-long xfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg);
+long linvfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
+long linvfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg);
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -88,6 +88,7 @@
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
+#include <linux/sort.h>
 
 #include <asm/page.h>
 #include <asm/div64.h>
@@ -368,4 +369,6 @@ static inline __uint64_t roundup_64(__ui
 	return(x * y);
 }
 
+#define qsort(a, n, s, cmp) sort(a, n, s, cmp, NULL)
+
 #endif /* __XFS_LINUX__ */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -683,6 +683,9 @@ xfs_write(
 			(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
 				mp->m_rtdev_targp : mp->m_ddev_targp;
 
+		if (ioflags & IO_ISAIO)
+			return XFS_ERROR(-ENOSYS);
+
 		if ((pos & target->pbr_smask) || (count & target->pbr_smask))
 			return XFS_ERROR(-EINVAL);
 
@@ -871,6 +874,7 @@ retry:
 			goto out_unlock_isem;
 		xfs_rwlock(bdp, locktype);
 		pos = xip->i_d.di_size;
+		ret = 0;
 		goto retry;
 	}
 
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -66,7 +66,6 @@
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
 #include "xfs_version.h"
-#include "xfs_ioctl32.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
@@ -76,7 +75,6 @@
 STATIC struct quotactl_ops linvfs_qops;
 STATIC struct super_operations linvfs_sops;
 STATIC kmem_zone_t *linvfs_inode_zone;
-STATIC kmem_shaker_t xfs_inode_shaker;
 
 STATIC struct xfs_mount_args *
 xfs_args_allocate(
@@ -91,6 +89,10 @@ xfs_args_allocate(
 	/* Copy the already-parsed mount(2) flags we're interested in */
 	if (sb->s_flags & MS_NOATIME)
 		args->flags |= XFSMNT_NOATIME;
+	if (sb->s_flags & MS_DIRSYNC)
+		args->flags |= XFSMNT_DIRSYNC;
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		args->flags |= XFSMNT_WSYNC;
 
 	/* Default to 32 bit inodes on Linux all the time */
 	args->flags |= XFSMNT_32BITINODES;
@@ -286,18 +288,6 @@ linvfs_destroy_inode(
 	kmem_cache_free(linvfs_inode_zone, LINVFS_GET_VP(inode));
 }
 
-STATIC int
-xfs_inode_shake(
-	int		priority,
-	unsigned int	gfp_mask)
-{
-	int		pages;
-
-	pages = kmem_zone_shrink(linvfs_inode_zone);
-	pages += kmem_zone_shrink(xfs_inode_zone);
-	return pages;
-}
-
 STATIC void
 init_once(
 	void			*data,
@@ -885,12 +875,6 @@ init_xfs_fs( void )
 	uuid_init();
 	vfs_initquota();
 
-	xfs_inode_shaker = kmem_shake_register(xfs_inode_shake);
-	if (!xfs_inode_shaker) {
-		error = -ENOMEM;
-		goto undo_shaker;
-	}
-
 	error = register_filesystem(&xfs_fs_type);
 	if (error)
 		goto undo_register;
@@ -898,9 +882,6 @@ init_xfs_fs( void )
 	return 0;
 
 undo_register:
-	kmem_shake_deregister(xfs_inode_shaker);
-
-undo_shaker:
 	pagebuf_terminate();
 
 undo_pagebuf:
@@ -916,7 +897,6 @@ exit_xfs_fs( void )
 	vfs_exitquota();
 	XFS_DM_EXIT(&xfs_fs_type);
 	unregister_filesystem(&xfs_fs_type);
-	kmem_shake_deregister(xfs_inode_shaker);
 	xfs_cleanup();
 	pagebuf_terminate();
 	destroy_inodecache();
diff --git a/fs/xfs/linux-2.6/xfs_vfs.c b/fs/xfs/linux-2.6/xfs_vfs.c
--- a/fs/xfs/linux-2.6/xfs_vfs.c
+++ b/fs/xfs/linux-2.6/xfs_vfs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c
--- a/fs/xfs/linux-2.6/xfs_vnode.c
+++ b/fs/xfs/linux-2.6/xfs_vnode.c
@@ -156,7 +156,6 @@ vn_initialize(
 
 #ifdef	XFS_VNODE_TRACE
 	vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
-	printk("Allocated VNODE_TRACE at 0x%p\n", vp->v_trace);
 #endif	/* XFS_VNODE_TRACE */
 
 	vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);
@@ -424,13 +423,13 @@ vn_remove(
  * Vnode tracing code.
  */
 void
-vn_trace_entry(vnode_t *vp, char *func, inst_t *ra)
+vn_trace_entry(vnode_t *vp, const char *func, inst_t *ra)
 {
 	KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra);
 }
 
 void
-vn_trace_exit(vnode_t *vp, char *func, inst_t *ra)
+vn_trace_exit(vnode_t *vp, const char *func, inst_t *ra)
 {
 	KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra);
 }
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -86,10 +86,11 @@ typedef struct vnode {
 	vnumber_t	v_number;		/* in-core vnode number */
 	vn_bhv_head_t	v_bh;			/* behavior head */
 	spinlock_t	v_lock;			/* VN_LOCK/VN_UNLOCK */
-	struct inode	v_inode;		/* Linux inode */
 #ifdef XFS_VNODE_TRACE
 	struct ktrace	*v_trace;		/* trace header structure    */
 #endif
+	struct inode	v_inode;		/* Linux inode */
+	/* inode MUST be last */
 } vnode_t;
 
 #define v_fbhv			v_bh.bh_first	       /* first behavior */
@@ -409,7 +410,7 @@ typedef struct vattr {
 	int		va_mask;	/* bit-mask of attributes present */
 	enum vtype	va_type;	/* vnode type (for create) */
 	mode_t		va_mode;	/* file access mode and type */
-	nlink_t		va_nlink;	/* number of references to file */
+	xfs_nlink_t	va_nlink;	/* number of references to file */
 	uid_t		va_uid;		/* owner user id */
 	gid_t		va_gid;		/* owner group id */
 	xfs_ino_t	va_nodeid;	/* file id */
@@ -625,6 +626,7 @@ static inline int VN_BAD(struct vnode *v
 #define	ATTR_DMI	0x08	/* invocation from a DMI function */
 #define	ATTR_LAZY	0x80	/* set/get attributes lazily */
 #define	ATTR_NONBLOCK	0x100	/* return EAGAIN if operation would block */
+#define ATTR_NOLOCK	0x200	/* Don't grab any conflicting locks */
 
 /*
  * Flags to VOP_FSYNC and VOP_RECLAIM.
@@ -646,8 +648,8 @@ static inline int VN_BAD(struct vnode *v
 #define	VNODE_KTRACE_REF	4
 #define	VNODE_KTRACE_RELE	5
 
-extern void vn_trace_entry(struct vnode *, char *, inst_t *);
-extern void vn_trace_exit(struct vnode *, char *, inst_t *);
+extern void vn_trace_entry(struct vnode *, const char *, inst_t *);
+extern void vn_trace_exit(struct vnode *, const char *, inst_t *);
 extern void vn_trace_hold(struct vnode *, char *, int, inst_t *);
 extern void vn_trace_ref(struct vnode *, char *, int, inst_t *);
 extern void vn_trace_rele(struct vnode *, char *, int, inst_t *);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -261,21 +261,19 @@ xfs_qm_adjust_dqlimits(
 {
 	xfs_quotainfo_t		*q = mp->m_quotainfo;
 
-	ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT));
+	ASSERT(d->d_id);
 
-	if (q->qi_bsoftlimit && INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT))
+	if (q->qi_bsoftlimit && !d->d_blk_softlimit)
 		INT_SET(d->d_blk_softlimit, ARCH_CONVERT, q->qi_bsoftlimit);
-	if (q->qi_bhardlimit && INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT))
+	if (q->qi_bhardlimit && !d->d_blk_hardlimit)
 		INT_SET(d->d_blk_hardlimit, ARCH_CONVERT, q->qi_bhardlimit);
-	if (q->qi_isoftlimit && INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT))
+	if (q->qi_isoftlimit && !d->d_ino_softlimit)
 		INT_SET(d->d_ino_softlimit, ARCH_CONVERT, q->qi_isoftlimit);
-	if (q->qi_ihardlimit && INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT))
+	if (q->qi_ihardlimit && !d->d_ino_hardlimit)
 		INT_SET(d->d_ino_hardlimit, ARCH_CONVERT, q->qi_ihardlimit);
-	if (q->qi_rtbsoftlimit &&
-	    INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT))
+	if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)
 		INT_SET(d->d_rtb_softlimit, ARCH_CONVERT, q->qi_rtbsoftlimit);
-	if (q->qi_rtbhardlimit &&
-	    INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT))
+	if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)
 		INT_SET(d->d_rtb_hardlimit, ARCH_CONVERT, q->qi_rtbhardlimit);
 }
 
@@ -295,7 +293,7 @@ xfs_qm_adjust_dqtimers(
 	xfs_mount_t		*mp,
 	xfs_disk_dquot_t	*d)
 {
-	ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT));
+	ASSERT(d->d_id);
 
 #ifdef QUOTADEBUG
 	if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT))
@@ -308,7 +306,7 @@ xfs_qm_adjust_dqtimers(
 		ASSERT(INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) <=
 			INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT));
 #endif
-	if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) {
+	if (!d->d_btimer) {
 		if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
 		    (INT_GET(d->d_bcount, ARCH_CONVERT) >=
 				INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) ||
@@ -319,17 +317,17 @@ xfs_qm_adjust_dqtimers(
 				get_seconds() + XFS_QI_BTIMELIMIT(mp));
 		}
 	} else {
-		if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
+		if ((!d->d_blk_softlimit ||
 		    (INT_GET(d->d_bcount, ARCH_CONVERT) <
 				INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) &&
-		    (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) ||
+		    (!d->d_blk_hardlimit ||
 		    (INT_GET(d->d_bcount, ARCH_CONVERT) <
 				INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
-			INT_ZERO(d->d_btimer, ARCH_CONVERT);
+			d->d_btimer = 0;
 		}
 	}
 
-	if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) {
+	if (!d->d_itimer) {
 		if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) &&
 		    (INT_GET(d->d_icount, ARCH_CONVERT) >=
 				INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) ||
@@ -340,17 +338,17 @@ xfs_qm_adjust_dqtimers(
 				get_seconds() + XFS_QI_ITIMELIMIT(mp));
 		}
 	} else {
-		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) ||
+		if ((!d->d_ino_softlimit ||
 		    (INT_GET(d->d_icount, ARCH_CONVERT) <
 				INT_GET(d->d_ino_softlimit, ARCH_CONVERT)))  &&
-		    (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) ||
+		    (!d->d_ino_hardlimit ||
 		    (INT_GET(d->d_icount, ARCH_CONVERT) <
 				INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
-			INT_ZERO(d->d_itimer, ARCH_CONVERT);
+			d->d_itimer = 0;
 		}
 	}
 
-	if (INT_ISZERO(d->d_rtbtimer, ARCH_CONVERT)) {
+	if (!d->d_rtbtimer) {
 		if ((INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) &&
 		    (INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
 				INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) ||
@@ -361,13 +359,13 @@ xfs_qm_adjust_dqtimers(
 				get_seconds() + XFS_QI_RTBTIMELIMIT(mp));
 		}
 	} else {
-		if ((INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT) ||
+		if ((!d->d_rtb_softlimit ||
 		    (INT_GET(d->d_rtbcount, ARCH_CONVERT) <
 				INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) &&
-		    (INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT) ||
+		    (!d->d_rtb_hardlimit ||
 		    (INT_GET(d->d_rtbcount, ARCH_CONVERT) <
 				INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
-			INT_ZERO(d->d_rtbtimer, ARCH_CONVERT);
+			d->d_rtbtimer = 0;
 		}
 	}
 }
@@ -385,7 +383,7 @@ xfs_qm_dqwarn(
 	/*
 	 * root's limits are not real limits.
 	 */
-	if (INT_ISZERO(d->d_id, ARCH_CONVERT))
+	if (!d->d_id)
 		return (0);
 
 	warned = 0;
@@ -397,10 +395,10 @@ xfs_qm_dqwarn(
 			warned++;
 		}
 	} else {
-		if (INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
+		if (!d->d_blk_softlimit ||
 		    (INT_GET(d->d_bcount, ARCH_CONVERT) <
 		     INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
-			INT_ZERO(d->d_bwarns, ARCH_CONVERT);
+			d->d_bwarns = 0;
 		}
 	}
 
@@ -412,10 +410,10 @@ xfs_qm_dqwarn(
 			warned++;
 		}
 	} else {
-		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) ||
+		if (!d->d_ino_softlimit ||
 		    (INT_GET(d->d_icount, ARCH_CONVERT) <
 		     INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
-			INT_ZERO(d->d_iwarns, ARCH_CONVERT);
+			d->d_iwarns = 0;
 		}
 	}
 #ifdef QUOTADEBUG
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -1211,8 +1211,7 @@ xfs_dqtest_cmp2(
 	if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
 	    INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >=
 	    INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
-		if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) &&
-		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+		if (!dqp->q_core.d_btimer && dqp->q_core.d_id) {
 			cmn_err(CE_DEBUG,
 				"%d [%s] [0x%p] BLK TIMER NOT STARTED",
 				d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
@@ -1222,8 +1221,7 @@ xfs_dqtest_cmp2(
 	if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
 	    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
 	    INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
-		if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
-		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+		if (!dqp->q_core.d_itimer && dqp->q_core.d_id) {
 			cmn_err(CE_DEBUG,
 				"%d [%s] [0x%p] INO TIMER NOT STARTED",
 				d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
--- a/fs/xfs/quota/xfs_quota_priv.h
+++ b/fs/xfs/quota/xfs_quota_priv.h
@@ -104,15 +104,15 @@ static inline int XQMISLCKD(struct xfs_d
 #define XFS_IS_DQTYPE_ON(mp, type)   (type == XFS_DQ_USER ? \
 				      XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
 #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
-	INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT)	      && \
-	INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT)      && \
-	INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT))
+	!dqp->q_core.d_blk_hardlimit && \
+	!dqp->q_core.d_blk_softlimit && \
+	!dqp->q_core.d_rtb_hardlimit && \
+	!dqp->q_core.d_rtb_softlimit && \
+	!dqp->q_core.d_ino_hardlimit && \
+	!dqp->q_core.d_ino_softlimit && \
+	!dqp->q_core.d_bcount && \
+	!dqp->q_core.d_rtbcount && \
+	!dqp->q_core.d_icount)
 
 #define HL_PREVP	dq_hashlist.ql_prevp
 #define HL_NEXT		dq_hashlist.ql_next
@@ -174,7 +174,7 @@ for ((dqp) = (qlist)->qh_next; (dqp) != 
 					 (tp)->t_dqinfo->dqa_usrdquots : \
 					 (tp)->t_dqinfo->dqa_grpdquots)
 #define XFS_IS_SUSER_DQUOT(dqp)		\
-	(INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT))
+	(!((dqp)->q_core.d_id))
 
 #define XFS_PURGE_INODE(ip)		\
 	{				\
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -455,7 +455,7 @@ xfs_trans_apply_dquot_deltas(
 			 * Get any default limits in use.
 			 * Start/reset the timer(s) if needed.
 			 */
-			if (!INT_ISZERO(d->d_id, ARCH_CONVERT)) {
+			if (d->d_id) {
 				xfs_qm_adjust_dqlimits(tp->t_mountp, d);
 				xfs_qm_adjust_dqtimers(tp->t_mountp, d);
 			}
@@ -669,7 +669,7 @@ xfs_trans_dqresv(
 	error = 0;
 
 	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
-	    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
+	    dqp->q_core.d_id &&
 	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
 #ifdef QUOTADEBUG
 		cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
@@ -694,7 +694,7 @@ xfs_trans_dqresv(
 				 * return EDQUOT
 				 */
 				if ((btimer != 0 && get_seconds() > btimer) ||
-				    (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
+				    (dqp->q_core.d_bwarns &&
 				     INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
 				     XFS_QI_BWARNLIMIT(dqp->q_mount))) {
 					error = EDQUOT;
@@ -719,9 +719,9 @@ xfs_trans_dqresv(
 				 * If timer or warnings has expired,
 				 * return EDQUOT
 				 */
-				if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
+				if ((dqp->q_core.d_itimer &&
 				     get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
-				    (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
+				    (dqp->q_core.d_iwarns &&
 				     INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
 				     XFS_QI_IWARNLIMIT(dqp->q_mount))) {
 					error = EDQUOT;
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -403,38 +403,6 @@ xfs_acl_allow_set(
 }
 
 /*
- * Look for any effective exec access, to allow CAP_DAC_OVERRIDE for exec.
- * Ignore checking for exec in USER_OBJ when there is no mask, because
- * in this "minimal acl" case we don't have any actual acls, and we
- * won't even be here.
- */
-STATIC int
-xfs_acl_find_any_exec(
-	xfs_acl_t	*fap)
-{
-	int		i;
-	int		masked_aces = 0;
-	int		mask = 0;
-
-	for (i = 0; i < fap->acl_cnt; i++) {
-		if (fap->acl_entry[i].ae_perm & ACL_EXECUTE) {
-			if (fap->acl_entry[i].ae_tag & (ACL_USER_OBJ|ACL_OTHER))
-				return 1;
-
-			if (fap->acl_entry[i].ae_tag == ACL_MASK)
-				mask = fap->acl_entry[i].ae_perm;
-			else
-				masked_aces |= fap->acl_entry[i].ae_perm;
-
-			if ((mask & masked_aces) & ACL_EXECUTE)
-				return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*
  * The access control process to determine the access permission:
  *	if uid == file owner id, use the file owner bits.
  *	if gid == file owner group id, use the file group bits.
@@ -443,24 +411,19 @@ xfs_acl_find_any_exec(
  *	until all acl entries are exhausted. The final permission produced
  *	by matching acl entry or entries needs to be & with group permission.
  *	if not owner, owning group, or matching entry in ACL, use file
- *	other bits.  Don't allow CAP_DAC_OVERRIDE on exec access unless
- *	there is some effective exec access somewhere.
+ *	other bits.  
  */
 STATIC int
 xfs_acl_capability_check(
 	mode_t		mode,
-	cred_t		*cr,
-	xfs_acl_t	*fap)
+	cred_t		*cr)
 {
 	if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH))
 		return EACCES;
 	if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
 		return EACCES;
-	if ((mode & ACL_EXECUTE) &&
-	    (!capable_cred(cr, CAP_DAC_OVERRIDE) ||
-	     !xfs_acl_find_any_exec(fap))) {
+	if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
 		return EACCES;
-	}
 
 	return 0;
 }
@@ -567,7 +530,7 @@ xfs_acl_access(
 		break;
 	}
 
-	return xfs_acl_capability_check(md, cr, fap);
+	return xfs_acl_capability_check(md, cr);
 }
 
 /*
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -2009,7 +2009,7 @@ xfs_alloc_get_freelist(
 	/*
 	 * Freelist is empty, give up.
 	 */
-	if (INT_ISZERO(agf->agf_flcount, ARCH_CONVERT)) {
+	if (!agf->agf_flcount) {
 		*bnop = NULLAGBLOCK;
 		return 0;
 	}
@@ -2028,7 +2028,7 @@ xfs_alloc_get_freelist(
 	INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1);
 	xfs_trans_brelse(tp, agflbp);
 	if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE(mp))
-		INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
+		agf->agf_flfirst = 0;
 	pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)];
 	INT_MOD(agf->agf_flcount, ARCH_CONVERT, -1);
 	xfs_trans_agflist_delta(tp, -1);
@@ -2128,7 +2128,7 @@ xfs_alloc_put_freelist(
 	agfl = XFS_BUF_TO_AGFL(agflbp);
 	INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1);
 	if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE(mp))
-		INT_ZERO(agf->agf_fllast, ARCH_CONVERT);
+		agf->agf_fllast = 0;
 	pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)];
 	INT_MOD(agf->agf_flcount, ARCH_CONVERT, 1);
 	xfs_trans_agflist_delta(tp, 1);
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -209,7 +209,7 @@ xfs_alloc_delrec(
 		 * No free extents left.
 		 */
 		else
-			INT_ZERO(agf->agf_longest, ARCH_CONVERT);
+			agf->agf_longest = 0;
 		mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest =
 			INT_GET(agf->agf_longest, ARCH_CONVERT);
 		xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp,
diff --git a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h
--- a/fs/xfs/xfs_arch.h
+++ b/fs/xfs/xfs_arch.h
@@ -72,69 +72,18 @@
     ((sizeof(type) == 2) ? INT_SWAP16(type,var) : \
     (var))))
 
-#define INT_SWAP_UNALIGNED_32(from,to) \
-    { \
-	((__u8*)(to))[0] = ((__u8*)(from))[3]; \
-	((__u8*)(to))[1] = ((__u8*)(from))[2]; \
-	((__u8*)(to))[2] = ((__u8*)(from))[1]; \
-	((__u8*)(to))[3] = ((__u8*)(from))[0]; \
-    }
-
-#define INT_SWAP_UNALIGNED_64(from,to) \
-    { \
-	INT_SWAP_UNALIGNED_32( ((__u8*)(from)) + 4, ((__u8*)(to))); \
-	INT_SWAP_UNALIGNED_32( ((__u8*)(from)), ((__u8*)(to)) + 4); \
-    }
-
 /*
  * get and set integers from potentially unaligned locations
  */
 
-#define INT_GET_UNALIGNED_16_LE(pointer) \
-   ((__u16)((((__u8*)(pointer))[0]	) | (((__u8*)(pointer))[1] << 8 )))
 #define INT_GET_UNALIGNED_16_BE(pointer) \
    ((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1])))
-#define INT_SET_UNALIGNED_16_LE(pointer,value) \
-    { \
-	((__u8*)(pointer))[0] = (((value)     ) & 0xff); \
-	((__u8*)(pointer))[1] = (((value) >> 8) & 0xff); \
-    }
 #define INT_SET_UNALIGNED_16_BE(pointer,value) \
     { \
 	((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \
 	((__u8*)(pointer))[1] = (((value)     ) & 0xff); \
     }
 
-#define INT_GET_UNALIGNED_32_LE(pointer) \
-   ((__u32)((((__u8*)(pointer))[0]	) | (((__u8*)(pointer))[1] << 8 ) \
-	   |(((__u8*)(pointer))[2] << 16) | (((__u8*)(pointer))[3] << 24)))
-#define INT_GET_UNALIGNED_32_BE(pointer) \
-   ((__u32)((((__u8*)(pointer))[0] << 24) | (((__u8*)(pointer))[1] << 16) \
-	   |(((__u8*)(pointer))[2] << 8)  | (((__u8*)(pointer))[3]	)))
-
-#define INT_GET_UNALIGNED_64_LE(pointer) \
-   (((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))+4)) << 32 ) \
-   |((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))	 ))	  ))
-#define INT_GET_UNALIGNED_64_BE(pointer) \
-   (((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))	 )) << 32  ) \
-   |((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))+4))	   ))
-
-/*
- * now pick the right ones for our MACHINE ARCHITECTURE
- */
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define INT_GET_UNALIGNED_16(pointer)	    INT_GET_UNALIGNED_16_LE(pointer)
-#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_LE(pointer,value)
-#define INT_GET_UNALIGNED_32(pointer)	    INT_GET_UNALIGNED_32_LE(pointer)
-#define INT_GET_UNALIGNED_64(pointer)	    INT_GET_UNALIGNED_64_LE(pointer)
-#else
-#define INT_GET_UNALIGNED_16(pointer)	    INT_GET_UNALIGNED_16_BE(pointer)
-#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_BE(pointer,value)
-#define INT_GET_UNALIGNED_32(pointer)	    INT_GET_UNALIGNED_32_BE(pointer)
-#define INT_GET_UNALIGNED_64(pointer)	    INT_GET_UNALIGNED_64_BE(pointer)
-#endif
-
 /* define generic INT_ macros */
 
 #define INT_GET(reference,arch) \
@@ -213,64 +162,52 @@
     } \
 }
 
-#define INT_ISZERO(reference,arch) \
-    ((reference) == 0)
-
-#define INT_ZERO(reference,arch) \
-    ((reference) = 0)
-
-#define INT_GET_UNALIGNED_16_ARCH(pointer,arch) \
-    ( ((arch) == ARCH_NOCONVERT) \
-	? \
-	    (INT_GET_UNALIGNED_16(pointer)) \
-	: \
-	    (INT_GET_UNALIGNED_16_BE(pointer)) \
-    )
-#define INT_SET_UNALIGNED_16_ARCH(pointer,value,arch) \
-    if ((arch) == ARCH_NOCONVERT) { \
-	INT_SET_UNALIGNED_16(pointer,value); \
-    } else { \
-	INT_SET_UNALIGNED_16_BE(pointer,value); \
-    }
-
-#define DIRINO4_GET_ARCH(pointer,arch) \
-    ( ((arch) == ARCH_NOCONVERT) \
-	? \
-	    (INT_GET_UNALIGNED_32(pointer)) \
-	: \
-	    (INT_GET_UNALIGNED_32_BE(pointer)) \
-    )
+/*
+ * In directories inode numbers are stored as unaligned arrays of unsigned
+ * 8bit integers on disk.
+ *
+ * For v1 directories or v2 directories that contain inode numbers that
+ * do not fit into 32bit the array has eight members, but the first member
+ * is always zero:
+ *
+ *  |unused|48-55|40-47|32-39|24-31|16-23| 8-15| 0- 7|
+ *
+ * For v2 directories that only contain entries with inode numbers that fit
+ * into 32bits a four-member array is used:
+ *
+ *  |24-31|16-23| 8-15| 0- 7|
+ */ 
 
-#if XFS_BIG_INUMS
-#define DIRINO_GET_ARCH(pointer,arch) \
-    ( ((arch) == ARCH_NOCONVERT) \
-	? \
-	    (INT_GET_UNALIGNED_64(pointer)) \
-	: \
-	    (INT_GET_UNALIGNED_64_BE(pointer)) \
-    )
-#else
-/* MACHINE ARCHITECTURE dependent */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define DIRINO_GET_ARCH(pointer,arch) \
-    DIRINO4_GET_ARCH((((__u8*)pointer)+4),arch)
-#else
-#define DIRINO_GET_ARCH(pointer,arch) \
-    DIRINO4_GET_ARCH(pointer,arch)
-#endif
-#endif
-
-#define DIRINO_COPY_ARCH(from,to,arch) \
-    if ((arch) == ARCH_NOCONVERT) { \
-	memcpy(to,from,sizeof(xfs_ino_t)); \
-    } else { \
-	INT_SWAP_UNALIGNED_64(from,to); \
-    }
-#define DIRINO4_COPY_ARCH(from,to,arch) \
-    if ((arch) == ARCH_NOCONVERT) { \
-	memcpy(to,(((__u8*)from+4)),sizeof(xfs_dir2_ino4_t)); \
-    } else { \
-	INT_SWAP_UNALIGNED_32(from,to); \
-    }
+#define XFS_GET_DIR_INO4(di) \
+	(((u32)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
 
+#define XFS_PUT_DIR_INO4(from, di) \
+do { \
+	(di).i[0] = (((from) & 0xff000000ULL) >> 24); \
+	(di).i[1] = (((from) & 0x00ff0000ULL) >> 16); \
+	(di).i[2] = (((from) & 0x0000ff00ULL) >> 8); \
+	(di).i[3] = ((from) & 0x000000ffULL); \
+} while (0)
+
+#define XFS_DI_HI(di) \
+	(((u32)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
+#define XFS_DI_LO(di) \
+	(((u32)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | ((di).i[7]))
+
+#define XFS_GET_DIR_INO8(di)        \
+	(((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
+	 ((xfs_ino_t)XFS_DI_HI(di) << 32))
+
+#define XFS_PUT_DIR_INO8(from, di) \
+do { \
+	(di).i[0] = 0; \
+	(di).i[1] = (((from) & 0x00ff000000000000ULL) >> 48); \
+	(di).i[2] = (((from) & 0x0000ff0000000000ULL) >> 40); \
+	(di).i[3] = (((from) & 0x000000ff00000000ULL) >> 32); \
+	(di).i[4] = (((from) & 0x00000000ff000000ULL) >> 24); \
+	(di).i[5] = (((from) & 0x0000000000ff0000ULL) >> 16); \
+	(di).i[6] = (((from) & 0x000000000000ff00ULL) >> 8); \
+	(di).i[7] = ((from) & 0x00000000000000ffULL); \
+} while (0)
+	
 #endif	/* __XFS_ARCH_H__ */
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -1884,7 +1884,7 @@ xfs_attr_node_list(xfs_attr_list_context
 			return(XFS_ERROR(EFSCORRUPTED));
 		}
 		error = xfs_attr_leaf_list_int(bp, context);
-		if (error || (INT_ISZERO(leaf->hdr.info.forw, ARCH_CONVERT)))
+		if (error || !leaf->hdr.info.forw)
 			break;	/* not really an error, buffer full or EOF */
 		cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
 		xfs_da_brelse(NULL, bp);
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -129,7 +129,7 @@ xfs_attr_shortform_create(xfs_da_args_t 
 	}
 	xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
 	hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
-	INT_ZERO(hdr->count, ARCH_CONVERT);
+	hdr->count = 0;
 	INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr));
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 	return(0);
@@ -443,7 +443,7 @@ xfs_attr_shortform_list(xfs_attr_list_co
 	ASSERT(dp->i_afp != NULL);
 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
 	ASSERT(sf != NULL);
-	if (INT_ISZERO(sf->hdr.count, ARCH_CONVERT))
+	if (!sf->hdr.count)
 		return(0);
 	cursor = context->cursor;
 	ASSERT(cursor != NULL);
@@ -686,7 +686,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *
 	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
 		if (entry->flags & XFS_ATTR_INCOMPLETE)
 			continue;	/* don't copy partial entries */
-		if (INT_ISZERO(entry->nameidx, ARCH_CONVERT))
+		if (!entry->nameidx)
 			continue;
 		ASSERT(entry->flags & XFS_ATTR_LOCAL);
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
@@ -795,7 +795,7 @@ xfs_attr_leaf_create(xfs_da_args_t *args
 	hdr = &leaf->hdr;
 	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);
 	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
-	if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) {
+	if (!hdr->firstused) {
 		INT_SET(hdr->firstused, ARCH_CONVERT,
 			XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN);
 	}
@@ -898,7 +898,7 @@ xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_d
 			sum += INT_GET(map->size, ARCH_CONVERT);
 			continue;
 		}
-		if (INT_ISZERO(map->size, ARCH_CONVERT))
+		if (!map->size)
 			continue;	/* no space in this map */
 		tmp = entsize;
 		if (INT_GET(map->base, ARCH_CONVERT)
@@ -1031,8 +1031,8 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, 
 		memcpy((char *)name_rmt->name, args->name, args->namelen);
 		entry->flags |= XFS_ATTR_INCOMPLETE;
 		/* just in case */
-		INT_ZERO(name_rmt->valuelen, ARCH_CONVERT);
-		INT_ZERO(name_rmt->valueblk, ARCH_CONVERT);
+		name_rmt->valuelen = 0;
+		name_rmt->valueblk = 0;
 		args->rmtblkno = 1;
 		args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen);
 	}
@@ -1097,12 +1097,12 @@ xfs_attr_leaf_compact(xfs_trans_t *trans
 	hdr_d->info = hdr_s->info;	/* struct copy */
 	INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp));
 	/* handle truncation gracefully */
-	if (INT_ISZERO(hdr_d->firstused, ARCH_CONVERT)) {
+	if (!hdr_d->firstused) {
 		INT_SET(hdr_d->firstused, ARCH_CONVERT,
 				XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN);
 	}
-	INT_ZERO(hdr_d->usedbytes, ARCH_CONVERT);
-	INT_ZERO(hdr_d->count, ARCH_CONVERT);
+	hdr_d->usedbytes = 0;
+	hdr_d->count = 0;
 	hdr_d->holes = 0;
 	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT,
 					sizeof(xfs_attr_leaf_hdr_t));
@@ -1456,7 +1456,7 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *s
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
+		forward = info->forw;
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1617,8 +1617,8 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xf
 			INT_MOD(map->size, ARCH_CONVERT,
 				INT_GET(hdr->freemap[after].size,
 							ARCH_CONVERT));
-			INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT);
-			INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT);
+			hdr->freemap[after].base = 0;
+			hdr->freemap[after].size = 0;
 		} else if (before >= 0) {
 			map = &hdr->freemap[before];
 			INT_MOD(map->size, ARCH_CONVERT, entsize);
@@ -1686,7 +1686,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xf
 				tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
 		}
 		INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
-		if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) {
+		if (!hdr->firstused) {
 			INT_SET(hdr->firstused, ARCH_CONVERT,
 					tmp - XFS_ATTR_LEAF_NAME_ALIGN);
 		}
@@ -1772,13 +1772,13 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *
 		tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer;
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info;	/* struct copy */
-		INT_ZERO(tmp_hdr->count, ARCH_CONVERT);
+		tmp_hdr->count = 0;
 		INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
-		if (INT_ISZERO(tmp_hdr->firstused, ARCH_CONVERT)) {
+		if (!tmp_hdr->firstused) {
 			INT_SET(tmp_hdr->firstused, ARCH_CONVERT,
 				state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN);
 		}
-		INT_ZERO(tmp_hdr->usedbytes, ARCH_CONVERT);
+		tmp_hdr->usedbytes = 0;
 		if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
 				(int)INT_GET(drop_hdr->count, ARCH_CONVERT),
@@ -1860,8 +1860,8 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp
 		else
 			break;
 	}
-	ASSERT((probe >= 0) && \
-	       ((INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))
+	ASSERT((probe >= 0) && 
+	       (!leaf->hdr.count
 	       || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
 	ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT)
 							== hashval));
@@ -2151,10 +2151,10 @@ xfs_attr_leaf_moveents(xfs_attr_leafbloc
 	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT,
 				INT_GET(hdr_d->firstused, ARCH_CONVERT)
 			      - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
-	INT_ZERO(hdr_d->freemap[1].base, ARCH_CONVERT);
-	INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT);
-	INT_ZERO(hdr_d->freemap[1].size, ARCH_CONVERT);
-	INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT);
+	hdr_d->freemap[1].base = 0;
+	hdr_d->freemap[2].base = 0;
+	hdr_d->freemap[1].size = 0;
+	hdr_d->freemap[2].size = 0;
 	hdr_s->holes = 1;	/* leaf may not be compact */
 }
 
@@ -2199,7 +2199,7 @@ xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, 
 						== XFS_ATTR_LEAF_MAGIC);
 	if (count)
 		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-	if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))
+	if (!leaf->hdr.count)
 		return(0);
 	return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count,
 				ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
@@ -2543,8 +2543,8 @@ xfs_attr_leaf_setflag(xfs_da_args_t *arg
 			XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
 	if ((entry->flags & XFS_ATTR_LOCAL) == 0) {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
-		INT_ZERO(name_rmt->valueblk, ARCH_CONVERT);
-		INT_ZERO(name_rmt->valuelen, ARCH_CONVERT);
+		name_rmt->valueblk = 0;
+		name_rmt->valuelen = 0;
 		xfs_da_log_buf(args->trans, bp,
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
@@ -2661,8 +2661,8 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *a
 			  XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2)));
 	if ((entry2->flags & XFS_ATTR_LOCAL) == 0) {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2);
-		INT_ZERO(name_rmt->valueblk, ARCH_CONVERT);
-		INT_ZERO(name_rmt->valuelen, ARCH_CONVERT);
+		name_rmt->valueblk = 0;
+		name_rmt->valuelen = 0;
 		xfs_da_log_buf(args->trans, bp2,
 			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
 	}
@@ -2871,7 +2871,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **tra
 		if (   INT_GET(entry->nameidx, ARCH_CONVERT)
 		    && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
-			if (!INT_ISZERO(name_rmt->valueblk, ARCH_CONVERT))
+			if (name_rmt->valueblk)
 				count++;
 		}
 	}
@@ -2899,7 +2899,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **tra
 		if (   INT_GET(entry->nameidx, ARCH_CONVERT)
 		    && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
-			if (!INT_ISZERO(name_rmt->valueblk, ARCH_CONVERT)) {
+			if (name_rmt->valueblk) {
 				/* both on-disk, don't endian flip twice */
 				lp->valueblk = name_rmt->valueblk;
 				INT_SET(lp->valuelen, ARCH_CONVERT,
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -3261,7 +3261,7 @@ xfs_bmap_extents_to_btree(
 	 */
 	ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
 	INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);
-	INT_ZERO(ablock->bb_level, ARCH_CONVERT);
+	ablock->bb_level = 0;
 	INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO);
 	INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO);
 	arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -2017,7 +2017,7 @@ xfs_bmbt_get_state(
 				ext_flag);
 }
 
-#if ARCH_CONVERT != ARCH_NOCONVERT
+#if __BYTE_ORDER != __BIG_ENDIAN
 /* Endian flipping versions of the bmbt extraction functions */
 void
 xfs_bmbt_disk_get_all(
@@ -2545,7 +2545,7 @@ xfs_bmbt_set_allf(
 #endif	/* XFS_BIG_BLKNOS */
 }
 
-#if ARCH_CONVERT != ARCH_NOCONVERT
+#if __BYTE_ORDER != __BIG_ENDIAN
 /*
  * Set all the fields in a bmap extent record from the uncompressed form.
  */
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
--- a/fs/xfs/xfs_bmap_btree.h
+++ b/fs/xfs/xfs_bmap_btree.h
@@ -505,7 +505,7 @@ xfs_exntst_t
 xfs_bmbt_get_state(
 	xfs_bmbt_rec_t	*r);
 
-#if ARCH_CONVERT != ARCH_NOCONVERT
+#if __BYTE_ORDER != __BIG_ENDIAN
 void
 xfs_bmbt_disk_get_all(
 	xfs_bmbt_rec_t	*r,
@@ -631,7 +631,7 @@ xfs_bmbt_set_state(
 	xfs_bmbt_rec_t	*r,
 	xfs_exntst_t	v);
 
-#if ARCH_CONVERT != ARCH_NOCONVERT
+#if __BYTE_ORDER != __BIG_ENDIAN
 void
 xfs_bmbt_disk_set_all(
 	xfs_bmbt_rec_t	*r,
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -208,10 +208,10 @@ xfs_btree_check_lblock(
 		INT_GET(block->bb_level, ARCH_CONVERT) == level &&
 		INT_GET(block->bb_numrecs, ARCH_CONVERT) <=
 			xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) &&
-		!INT_ISZERO(block->bb_leftsib, ARCH_CONVERT) &&
+		block->bb_leftsib &&
 		(INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO ||
 		 XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_leftsib, ARCH_CONVERT))) &&
-		!INT_ISZERO(block->bb_rightsib, ARCH_CONVERT) &&
+		block->bb_rightsib &&
 		(INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO ||
 		 XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_rightsib, ARCH_CONVERT)));
 	if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK,
@@ -329,10 +329,10 @@ xfs_btree_check_sblock(
 			xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) &&
 		(INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK ||
 		 INT_GET(block->bb_leftsib, ARCH_CONVERT) < agflen) &&
-		!INT_ISZERO(block->bb_leftsib, ARCH_CONVERT) &&
+		block->bb_leftsib &&
 		(INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK ||
 		 INT_GET(block->bb_rightsib, ARCH_CONVERT) < agflen) &&
-		!INT_ISZERO(block->bb_rightsib, ARCH_CONVERT);
+		block->bb_rightsib;
 	if (unlikely(XFS_TEST_ERROR(!sblock_ok, cur->bc_mp,
 			XFS_ERRTAG_BTREE_CHECK_SBLOCK,
 			XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
@@ -484,7 +484,7 @@ xfs_btree_firstrec(
 	/*
 	 * It's empty, there is no such record.
 	 */
-	if (INT_ISZERO(block->bb_h.bb_numrecs, ARCH_CONVERT))
+	if (!block->bb_h.bb_numrecs)
 		return 0;
 	/*
 	 * Set the ptr value to 1, that's the first record/key.
@@ -698,7 +698,7 @@ xfs_btree_lastrec(
 	/*
 	 * It's empty, there is no such record.
 	 */
-	if (INT_ISZERO(block->bb_h.bb_numrecs, ARCH_CONVERT))
+	if (!block->bb_h.bb_numrecs)
 		return 0;
 	/*
 	 * Set the ptr value to numrecs, that's the last record/key.
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
--- a/fs/xfs/xfs_clnt.h
+++ b/fs/xfs/xfs_clnt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -103,5 +103,8 @@ struct xfs_mount_args {
 #define XFSMNT_IDELETE		0x08000000	/* inode cluster delete */
 #define XFSMNT_SWALLOC		0x10000000	/* turn on stripe width
 						 * allocation */
+#define XFSMNT_IHASHSIZE	0x20000000	/* inode hash table size */
+#define XFSMNT_DIRSYNC		0x40000000	/* sync creat,link,unlink,rename
+						 * symlink,mkdir,rmdir,mknod */
 
 #endif	/* __XFS_CLNT_H__ */
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -137,11 +137,11 @@ xfs_da_node_create(xfs_da_args_t *args, 
 		return(error);
 	ASSERT(bp != NULL);
 	node = bp->data;
-	INT_ZERO(node->hdr.info.forw, ARCH_CONVERT);
-	INT_ZERO(node->hdr.info.back, ARCH_CONVERT);
+	node->hdr.info.forw = 0;
+	node->hdr.info.back = 0;
 	INT_SET(node->hdr.info.magic, ARCH_CONVERT, XFS_DA_NODE_MAGIC);
-	INT_ZERO(node->hdr.info.pad, ARCH_CONVERT);
-	INT_ZERO(node->hdr.count, ARCH_CONVERT);
+	node->hdr.info.pad = 0;
+	node->hdr.count = 0;
 	INT_SET(node->hdr.level, ARCH_CONVERT, level);
 
 	xfs_da_log_buf(tp, bp,
@@ -306,7 +306,7 @@ xfs_da_split(xfs_da_state_t *state)
 	 */
 
 	node = oldblk->bp->data;
-	if (!INT_ISZERO(node->hdr.info.forw, ARCH_CONVERT)) {
+	if (node->hdr.info.forw) {
 		if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) == addblk->blkno) {
 			bp = addblk->bp;
 		} else {
@@ -791,8 +791,8 @@ xfs_da_root_join(xfs_da_state_t *state, 
 	ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
 	oldroot = root_blk->bp->data;
 	ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-	ASSERT(INT_ISZERO(oldroot->hdr.info.forw, ARCH_CONVERT));
-	ASSERT(INT_ISZERO(oldroot->hdr.info.back, ARCH_CONVERT));
+	ASSERT(!oldroot->hdr.info.forw);
+	ASSERT(!oldroot->hdr.info.back);
 
 	/*
 	 * If the root has more than one child, then don't do anything.
@@ -818,8 +818,8 @@ xfs_da_root_join(xfs_da_state_t *state, 
 	} else {
 		ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
 	}
-	ASSERT(INT_ISZERO(blkinfo->forw, ARCH_CONVERT));
-	ASSERT(INT_ISZERO(blkinfo->back, ARCH_CONVERT));
+	ASSERT(!blkinfo->forw);
+	ASSERT(!blkinfo->back);
 	memcpy(root_blk->bp->data, bp->data, state->blocksize);
 	xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
 	error = xfs_da_shrink_inode(args, child, bp);
@@ -871,7 +871,7 @@ xfs_da_node_toosmall(xfs_da_state_t *sta
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
+		forward = info->forw;
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1416,7 +1416,7 @@ xfs_da_node_lasthash(xfs_dabuf_t *bp, in
 	ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
 	if (count)
 		*count = INT_GET(node->hdr.count, ARCH_CONVERT);
-	if (INT_ISZERO(node->hdr.count, ARCH_CONVERT))
+	if (!node->hdr.count)
 		return(0);
 	return(INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
 }
@@ -1627,40 +1627,38 @@ xfs_da_hashname(uchar_t *name, int namel
 {
 	xfs_dahash_t hash;
 
-#define	ROTL(x,y)	(((x) << (y)) | ((x) >> (32 - (y))))
 #ifdef SLOWVERSION
 	/*
 	 * This is the old one-byte-at-a-time version.
 	 */
-	for (hash = 0; namelen > 0; namelen--) {
-		hash = *name++ ^ ROTL(hash, 7);
-	}
+	for (hash = 0; namelen > 0; namelen--)
+		hash = *name++ ^ rol32(hash, 7);
+
 	return(hash);
 #else
 	/*
 	 * Do four characters at a time as long as we can.
 	 */
-	for (hash = 0; namelen >= 4; namelen -= 4, name += 4) {
+	for (hash = 0; namelen >= 4; namelen -= 4, name += 4)
 		hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
-		       (name[3] << 0) ^ ROTL(hash, 7 * 4);
-	}
+		       (name[3] << 0) ^ rol32(hash, 7 * 4);
+
 	/*
 	 * Now do the rest of the characters.
 	 */
 	switch (namelen) {
 	case 3:
 		return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
-		       ROTL(hash, 7 * 3);
+		       rol32(hash, 7 * 3);
 	case 2:
-		return (name[0] << 7) ^ (name[1] << 0) ^ ROTL(hash, 7 * 2);
+		return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
 	case 1:
-		return (name[0] << 0) ^ ROTL(hash, 7 * 1);
+		return (name[0] << 0) ^ rol32(hash, 7 * 1);
 	case 0:
 		return hash;
 	}
 	/* NOTREACHED */
 #endif
-#undef ROTL
 	return 0; /* keep gcc happy */
 }
 
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -182,7 +182,7 @@ xfs_swapext(
 
 	if (VN_CACHED(tvp) != 0)
 		xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore),
-						(loff_t)0, 0, 0);
+						(xfs_off_t)0, 0, 0);
 
 	/* Verify O_DIRECT for ftmp */
 	if (VN_CACHED(tvp) != 0) {
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
--- a/fs/xfs/xfs_dinode.h
+++ b/fs/xfs/xfs_dinode.h
@@ -204,58 +204,59 @@ int xfs_litino(struct xfs_mount *mp);
  * Inode data & attribute fork sizes, per inode.
  */
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_Q)
-int xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch);
+int xfs_cfork_q_disk(xfs_dinode_core_t *dcp);
 int xfs_cfork_q(xfs_dinode_core_t *dcp);
-#define	XFS_CFORK_Q_ARCH(dcp,arch)          xfs_cfork_q_arch(dcp,arch)
+#define	XFS_CFORK_Q_DISK(dcp)               xfs_cfork_q_disk(dcp)
 #define	XFS_CFORK_Q(dcp)                    xfs_cfork_q(dcp)
 #else
-#define	XFS_CFORK_Q_ARCH(dcp,arch)	    (!INT_ISZERO((dcp)->di_forkoff, arch))
+#define	XFS_CFORK_Q_DISK(dcp)		    ((dcp)->di_forkoff != 0)
 #define XFS_CFORK_Q(dcp)                    ((dcp)->di_forkoff != 0)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_BOFF)
-int xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch);
+int xfs_cfork_boff_disk(xfs_dinode_core_t *dcp);
 int xfs_cfork_boff(xfs_dinode_core_t *dcp);
-#define	XFS_CFORK_BOFF_ARCH(dcp,arch)	    xfs_cfork_boff_arch(dcp,arch)
+#define	XFS_CFORK_BOFF_DISK(dcp)	    xfs_cfork_boff_disk(dcp)
 #define	XFS_CFORK_BOFF(dcp)	            xfs_cfork_boff(dcp)
 #else
-#define	XFS_CFORK_BOFF_ARCH(dcp,arch)	    ((int)(INT_GET((dcp)->di_forkoff, arch) << 3))
+#define	XFS_CFORK_BOFF_DISK(dcp)	    ((int)(INT_GET((dcp)->di_forkoff, ARCH_CONVERT) << 3))
 #define XFS_CFORK_BOFF(dcp)                 ((int)((dcp)->di_forkoff << 3))
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_DSIZE)
-int xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch);
+int xfs_cfork_dsize_disk(xfs_dinode_core_t *dcp, struct xfs_mount *mp);
 int xfs_cfork_dsize(xfs_dinode_core_t *dcp, struct xfs_mount *mp);
-#define	XFS_CFORK_DSIZE_ARCH(dcp,mp,arch)   xfs_cfork_dsize_arch(dcp,mp,arch)
+#define	XFS_CFORK_DSIZE_DISK(dcp,mp)        xfs_cfork_dsize_disk(dcp,mp)
 #define	XFS_CFORK_DSIZE(dcp,mp)             xfs_cfork_dsize(dcp,mp)
 #else
-#define	XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) \
-	(XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_CFORK_BOFF_ARCH(dcp, arch) : XFS_LITINO(mp))
+#define	XFS_CFORK_DSIZE_DISK(dcp,mp) \
+	(XFS_CFORK_Q_DISK(dcp) ? XFS_CFORK_BOFF_DISK(dcp) : XFS_LITINO(mp))
 #define XFS_CFORK_DSIZE(dcp,mp) \
 	(XFS_CFORK_Q(dcp) ? XFS_CFORK_BOFF(dcp) : XFS_LITINO(mp))
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_ASIZE)
-int xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch);
+int xfs_cfork_asize_disk(xfs_dinode_core_t *dcp, struct xfs_mount *mp);
 int xfs_cfork_asize(xfs_dinode_core_t *dcp, struct xfs_mount *mp);
-#define	XFS_CFORK_ASIZE_ARCH(dcp,mp,arch)   xfs_cfork_asize_arch(dcp,mp,arch)
+#define	XFS_CFORK_ASIZE_DISK(dcp,mp)        xfs_cfork_asize_disk(dcp,mp)
 #define	XFS_CFORK_ASIZE(dcp,mp)             xfs_cfork_asize(dcp,mp)
 #else
-#define	XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) \
-	(XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_ARCH(dcp, arch) : 0)
+#define	XFS_CFORK_ASIZE_DISK(dcp,mp) \
+	(XFS_CFORK_Q_DISK(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_DISK(dcp) : 0)
 #define XFS_CFORK_ASIZE(dcp,mp) \
 	(XFS_CFORK_Q(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF(dcp) : 0)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_SIZE)
-int xfs_cfork_size_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w, xfs_arch_t arch);
+int xfs_cfork_size_disk(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w);
 int xfs_cfork_size(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w);
-#define	XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch)  xfs_cfork_size_arch(dcp,mp,w,arch)
+#define	XFS_CFORK_SIZE_DISK(dcp,mp,w)       xfs_cfork_size_disk(dcp,mp,w)
 #define	XFS_CFORK_SIZE(dcp,mp,w)            xfs_cfork_size(dcp,mp,w)
 #else
-#define	XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) \
+#define	XFS_CFORK_SIZE_DISK(dcp,mp,w) \
 	((w) == XFS_DATA_FORK ? \
-		XFS_CFORK_DSIZE_ARCH(dcp, mp, arch) : XFS_CFORK_ASIZE_ARCH(dcp, mp, arch))
+		XFS_CFORK_DSIZE_DISK(dcp, mp) : \
+	 	XFS_CFORK_ASIZE_DISK(dcp, mp))
 #define XFS_CFORK_SIZE(dcp,mp,w) \
 	((w) == XFS_DATA_FORK ? \
 		XFS_CFORK_DSIZE(dcp, mp) : XFS_CFORK_ASIZE(dcp, mp))
@@ -263,33 +264,24 @@ int xfs_cfork_size(xfs_dinode_core_t *dc
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DSIZE)
-int xfs_dfork_dsize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch);
 int xfs_dfork_dsize(xfs_dinode_t *dip, struct xfs_mount *mp);
-#define	XFS_DFORK_DSIZE_ARCH(dip,mp,arch)   xfs_dfork_dsize_arch(dip,mp,arch)
 #define	XFS_DFORK_DSIZE(dip,mp)             xfs_dfork_dsize(dip,mp)
 #else
-#define	XFS_DFORK_DSIZE_ARCH(dip,mp,arch)   XFS_CFORK_DSIZE_ARCH(&(dip)->di_core, mp, arch)
-#define XFS_DFORK_DSIZE(dip,mp)             XFS_DFORK_DSIZE_ARCH(dip,mp,ARCH_NOCONVERT)
+#define XFS_DFORK_DSIZE(dip,mp)             XFS_CFORK_DSIZE_DISK(&(dip)->di_core, mp)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_ASIZE)
-int xfs_dfork_asize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch);
 int xfs_dfork_asize(xfs_dinode_t *dip, struct xfs_mount *mp);
-#define	XFS_DFORK_ASIZE_ARCH(dip,mp,arch)   xfs_dfork_asize_arch(dip,mp,arch)
 #define	XFS_DFORK_ASIZE(dip,mp)             xfs_dfork_asize(dip,mp)
 #else
-#define	XFS_DFORK_ASIZE_ARCH(dip,mp,arch)   XFS_CFORK_ASIZE_ARCH(&(dip)->di_core, mp, arch)
-#define XFS_DFORK_ASIZE(dip,mp)             XFS_DFORK_ASIZE_ARCH(dip,mp,ARCH_NOCONVERT)
+#define XFS_DFORK_ASIZE(dip,mp)             XFS_CFORK_ASIZE_DISK(&(dip)->di_core, mp)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_SIZE)
-int xfs_dfork_size_arch(xfs_dinode_t *dip, struct xfs_mount *mp, int w, xfs_arch_t arch);
 int xfs_dfork_size(xfs_dinode_t *dip, struct xfs_mount *mp, int w);
-#define	XFS_DFORK_SIZE_ARCH(dip,mp,w,arch)  xfs_dfork_size_arch(dip,mp,w,arch)
 #define	XFS_DFORK_SIZE(dip,mp,w)            xfs_dfork_size(dip,mp,w)
 #else
-#define	XFS_DFORK_SIZE_ARCH(dip,mp,w,arch)  XFS_CFORK_SIZE_ARCH(&(dip)->di_core, mp, w, arch)
-#define XFS_DFORK_SIZE(dip,mp,w)            XFS_DFORK_SIZE_ARCH(dip,mp,w,ARCH_NOCONVERT)
+#define	XFS_DFORK_SIZE(dip,mp,w)	    XFS_CFORK_SIZE_DISK(&(dip)->di_core, mp, w)
 
 #endif
 
@@ -297,143 +289,89 @@ int xfs_dfork_size(xfs_dinode_t *dip, st
  * Macros for accessing per-fork disk inode information.
  */
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_Q)
-int xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch);
 int xfs_dfork_q(xfs_dinode_t *dip);
-#define	XFS_DFORK_Q_ARCH(dip,arch)	    xfs_dfork_q_arch(dip,arch)
 #define	XFS_DFORK_Q(dip)	            xfs_dfork_q(dip)
 #else
-#define	XFS_DFORK_Q_ARCH(dip,arch)	    XFS_CFORK_Q_ARCH(&(dip)->di_core, arch)
-#define XFS_DFORK_Q(dip)                    XFS_DFORK_Q_ARCH(dip,ARCH_NOCONVERT)
+#define	XFS_DFORK_Q(dip)                    XFS_CFORK_Q_DISK(&(dip)->di_core)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_BOFF)
-int xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch);
 int xfs_dfork_boff(xfs_dinode_t *dip);
-#define	XFS_DFORK_BOFF_ARCH(dip,arch)	    xfs_dfork_boff_arch(dip,arch)
-#define	XFS_DFORK_BOFF(dip)	            xfs_dfork_boff(dip)
+#define	XFS_DFORK_BOFF(dip)		    xfs_dfork_boff(dip)
 #else
-#define	XFS_DFORK_BOFF_ARCH(dip,arch)	    XFS_CFORK_BOFF_ARCH(&(dip)->di_core, arch)
-#define XFS_DFORK_BOFF(dip)                 XFS_DFORK_BOFF_ARCH(dip,ARCH_NOCONVERT)
+#define	XFS_DFORK_BOFF(dip)		    XFS_CFORK_BOFF_DISK(&(dip)->di_core)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DPTR)
-char *xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch);
 char *xfs_dfork_dptr(xfs_dinode_t *dip);
-#define	XFS_DFORK_DPTR_ARCH(dip,arch)	    xfs_dfork_dptr_arch(dip,arch)
 #define	XFS_DFORK_DPTR(dip)	            xfs_dfork_dptr(dip)
 #else
-#define	XFS_DFORK_DPTR_ARCH(dip,arch)	    ((dip)->di_u.di_c)
-#define XFS_DFORK_DPTR(dip)                 XFS_DFORK_DPTR_ARCH(dip,ARCH_NOCONVERT)
+#define	XFS_DFORK_DPTR(dip)		    ((dip)->di_u.di_c)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_APTR)
-char *xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch);
 char *xfs_dfork_aptr(xfs_dinode_t *dip);
-#define	XFS_DFORK_APTR_ARCH(dip,arch)       xfs_dfork_aptr_arch(dip,arch)
 #define	XFS_DFORK_APTR(dip)                 xfs_dfork_aptr(dip)
 #else
-#define	XFS_DFORK_APTR_ARCH(dip,arch)	    ((dip)->di_u.di_c + XFS_DFORK_BOFF_ARCH(dip, arch))
-#define XFS_DFORK_APTR(dip)                 XFS_DFORK_APTR_ARCH(dip,ARCH_NOCONVERT)
+#define	XFS_DFORK_APTR(dip)		    ((dip)->di_u.di_c + XFS_DFORK_BOFF(dip))
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_PTR)
-char *xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch);
 char *xfs_dfork_ptr(xfs_dinode_t *dip, int w);
-#define	XFS_DFORK_PTR_ARCH(dip,w,arch)      xfs_dfork_ptr_arch(dip,w,arch)
 #define	XFS_DFORK_PTR(dip,w)                xfs_dfork_ptr(dip,w)
 #else
-#define	XFS_DFORK_PTR_ARCH(dip,w,arch)	\
-	((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR_ARCH(dip, arch) : XFS_DFORK_APTR_ARCH(dip, arch))
-#define XFS_DFORK_PTR(dip,w)                XFS_DFORK_PTR_ARCH(dip,w,ARCH_NOCONVERT)
+#define	XFS_DFORK_PTR(dip,w)	\
+	((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip))
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FORMAT)
-int xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch);
 int xfs_cfork_format(xfs_dinode_core_t *dcp, int w);
-#define	XFS_CFORK_FORMAT_ARCH(dcp,w,arch)   xfs_cfork_format_arch(dcp,w,arch)
 #define	XFS_CFORK_FORMAT(dcp,w)             xfs_cfork_format(dcp,w)
 #else
-#define	XFS_CFORK_FORMAT_ARCH(dcp,w,arch) \
-	((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_format, arch) : INT_GET((dcp)->di_aformat, arch))
-#define XFS_CFORK_FORMAT(dcp,w)             XFS_CFORK_FORMAT_ARCH(dcp,w,ARCH_NOCONVERT)
+#define	XFS_CFORK_FORMAT(dcp,w) \
+	((w) == XFS_DATA_FORK ? (dcp)->di_format : (dcp)->di_aformat)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FMT_SET)
-void xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch);
 void xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n);
-#define	XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) xfs_cfork_fmt_set_arch(dcp,w,n,arch)
 #define	XFS_CFORK_FMT_SET(dcp,w,n)           xfs_cfork_fmt_set(dcp,w,n)
 #else
-#define	XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) \
+#define	XFS_CFORK_FMT_SET(dcp,w,n) \
 	((w) == XFS_DATA_FORK ? \
-		(INT_SET((dcp)->di_format, arch, (n))) : \
-		(INT_SET((dcp)->di_aformat, arch, (n))))
-#define XFS_CFORK_FMT_SET(dcp,w,n)           XFS_CFORK_FMT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT)
+		((dcp)->di_format = (n)) : \
+		((dcp)->di_aformat = (n)))
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXTENTS)
-int xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch);
+int xfs_cfork_nextents_disk(xfs_dinode_core_t *dcp, int w);
 int xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w);
-#define	XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch)  xfs_cfork_nextents_arch(dcp,w,arch)
+#define	XFS_CFORK_NEXTENTS_DISK(dcp,w)       xfs_cfork_nextents_disk(dcp,w)
 #define	XFS_CFORK_NEXTENTS(dcp,w)            xfs_cfork_nextents(dcp,w)
 #else
-#define	XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) \
-	((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_nextents, arch) : INT_GET((dcp)->di_anextents, arch))
-#define XFS_CFORK_NEXTENTS(dcp,w)            XFS_CFORK_NEXTENTS_ARCH(dcp,w,ARCH_NOCONVERT)
+#define	XFS_CFORK_NEXTENTS_DISK(dcp,w) \
+	((w) == XFS_DATA_FORK ? \
+	 	INT_GET((dcp)->di_nextents, ARCH_CONVERT) : \
+	 	INT_GET((dcp)->di_anextents, ARCH_CONVERT))
+#define XFS_CFORK_NEXTENTS(dcp,w) \
+	((w) == XFS_DATA_FORK ? (dcp)->di_nextents : (dcp)->di_anextents)
 
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXT_SET)
-void xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch);
 void xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n);
-#define	XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch)	xfs_cfork_next_set_arch(dcp,w,n,arch)
 #define	XFS_CFORK_NEXT_SET(dcp,w,n)	        xfs_cfork_next_set(dcp,w,n)
 #else
-#define	XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) \
+#define	XFS_CFORK_NEXT_SET(dcp,w,n) \
 	((w) == XFS_DATA_FORK ? \
-		(INT_SET((dcp)->di_nextents, arch, (n))) : \
-		(INT_SET((dcp)->di_anextents, arch, (n))))
-#define XFS_CFORK_NEXT_SET(dcp,w,n)             XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT)
+		((dcp)->di_nextents = (n)) : \
+		((dcp)->di_anextents = (n)))
 
 #endif
-#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FORMAT)
-int xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch);
-int xfs_dfork_format(xfs_dinode_t *dip, int w);
-#define	XFS_DFORK_FORMAT_ARCH(dip,w,arch)   xfs_dfork_format_arch(dip,w,arch)
-#define	XFS_DFORK_FORMAT(dip,w)             xfs_dfork_format(dip,w)
-#else
-#define	XFS_DFORK_FORMAT_ARCH(dip,w,arch)   XFS_CFORK_FORMAT_ARCH(&(dip)->di_core, w, arch)
-#define XFS_DFORK_FORMAT(dip,w)             XFS_DFORK_FORMAT_ARCH(dip,w,ARCH_NOCONVERT)
-
-#endif
-#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FMT_SET)
-void xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch);
-void xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n);
-#define	XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch)    xfs_dfork_fmt_set_arch(dip,w,n,arch)
-#define	XFS_DFORK_FMT_SET(dip,w,n)              xfs_dfork_fmt_set(dip,w,n)
-#else
-#define	XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch)	XFS_CFORK_FMT_SET_ARCH(&(dip)->di_core, w, n, arch)
-#define XFS_DFORK_FMT_SET(dip,w,n)              XFS_DFORK_FMT_SET_ARCH(dip,w,n,ARCH_NOCONVERT)
 
-#endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXTENTS)
-int xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch);
 int xfs_dfork_nextents(xfs_dinode_t *dip, int w);
-#define	XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) xfs_dfork_nextents_arch(dip,w,arch)
-#define	XFS_DFORK_NEXTENTS(dip,w)           xfs_dfork_nextents(dip,w)
+#define	XFS_DFORK_NEXTENTS(dip,w) xfs_dfork_nextents(dip,w)
 #else
-#define	XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) XFS_CFORK_NEXTENTS_ARCH(&(dip)->di_core, w, arch)
-#define XFS_DFORK_NEXTENTS(dip,w)           XFS_DFORK_NEXTENTS_ARCH(dip,w,ARCH_NOCONVERT)
-
-#endif
-#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXT_SET)
-void xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch);
-void xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n);
-#define	XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch)   xfs_dfork_next_set_arch(dip,w,n,arch)
-#define	XFS_DFORK_NEXT_SET(dip,w,n)             xfs_dfork_next_set(dip,w,n)
-#else
-#define	XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch)	XFS_CFORK_NEXT_SET_ARCH(&(dip)->di_core, w, n, arch)
-#define XFS_DFORK_NEXT_SET(dip,w,n)             XFS_DFORK_NEXT_SET_ARCH(dip,w,n,ARCH_NOCONVERT)
-
+#define	XFS_DFORK_NEXTENTS(dip,w) XFS_CFORK_NEXTENTS_DISK(&(dip)->di_core, w)
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE)
diff --git a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
--- a/fs/xfs/xfs_dir.c
+++ b/fs/xfs/xfs_dir.c
@@ -557,7 +557,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mo
 		return 1;
 	}
 	sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf);
-	ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT);
+	ino = XFS_GET_DIR_INO8(sf->hdr.parent);
 	if (xfs_dir_ino_validate(mp, ino))
 		return 1;
 
@@ -575,7 +575,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mo
 	namelen_sum = 0;
 	sfe = &sf->list[0];
 	for (i = sf->hdr.count - 1; i >= 0; i--) {
-		ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT);
+		ino = XFS_GET_DIR_INO8(sfe->inumber);
 		xfs_dir_ino_validate(mp, ino);
 		if (sfe->namelen >= XFS_LITINO(mp)) {
 			xfs_fs_cmn_err(CE_WARN, mp,
@@ -716,7 +716,7 @@ xfs_dir_leaf_replace(xfs_da_args_t *args
 		entry = &leaf->entries[index];
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 		/* XXX - replace assert? */
-		XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT);
+		XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
 		xfs_da_buf_done(bp);
@@ -1065,7 +1065,7 @@ xfs_dir_node_replace(xfs_da_args_t *args
 		entry = &leaf->entries[blk->index];
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 		/* XXX - replace assert ? */
-		XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT);
+		XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
 		xfs_da_buf_done(bp);
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -165,7 +165,7 @@ xfs_dir2_isempty(
 	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
 		return 0;
 	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
-	return INT_ISZERO(sfp->hdr.count, ARCH_CONVERT);
+	return !sfp->hdr.count;
 }
 
 /*
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -135,11 +135,11 @@ xfs_dir2_block_addname(
 	 */
 	bf = block->hdr.bestfree;
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * No stale entries?  Need space for entry and new leaf.
 	 */
-	if (INT_ISZERO(btp->stale, ARCH_CONVERT)) {
+	if (!btp->stale) {
 		/*
 		 * Tag just before the first leaf entry.
 		 */
@@ -327,7 +327,7 @@ xfs_dir2_block_addname(
 	/*
 	 * No stale entries, will use enddup space to hold new leaf.
 	 */
-	if (INT_ISZERO(btp->stale, ARCH_CONVERT)) {
+	if (!btp->stale) {
 		/*
 		 * Mark the space needed for the new leaf entry, now in use.
 		 */
@@ -494,7 +494,7 @@ xfs_dir2_block_getdents(
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
 	ptr = (char *)block->u;
-	endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	p.dbp = dbp;
 	p.put = put;
 	p.uio = uio;
@@ -585,7 +585,7 @@ xfs_dir2_block_log_leaf(
 	mp = tp->t_mountp;
 	block = bp->data;
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block),
 		(uint)((char *)&blp[last + 1] - (char *)block - 1));
 }
@@ -639,7 +639,7 @@ xfs_dir2_block_lookup(
 	block = bp->data;
 	xfs_dir2_data_check(dp, bp);
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * Get the offset from the leaf entry, to point to the data.
 	 */
@@ -691,7 +691,7 @@ xfs_dir2_block_lookup_int(
 	block = bp->data;
 	xfs_dir2_data_check(dp, bp);
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * Loop doing a binary search for our hash value.
 	 * Find our entry, ENOENT if it's not there.
@@ -784,7 +784,7 @@ xfs_dir2_block_removename(
 	mp = dp->i_mount;
 	block = bp->data;
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * Point to the data entry using the leaf entry.
 	 */
@@ -860,7 +860,7 @@ xfs_dir2_block_replace(
 	mp = dp->i_mount;
 	block = bp->data;
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * Point to the data entry we need to change.
 	 */
@@ -936,7 +936,7 @@ xfs_dir2_leaf_to_block(
 	 * These will show up in the leaf bests table.
 	 */
 	while (dp->i_d.di_size > mp->m_dirblksize) {
-		bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
+		bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
 		if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) ==
 		    mp->m_dirblksize - (uint)sizeof(block->hdr)) {
 			if ((error =
@@ -991,12 +991,12 @@ xfs_dir2_leaf_to_block(
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
 	INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
-	INT_ZERO(btp->stale, ARCH_CONVERT);
+	btp->stale = 0;
 	xfs_dir2_block_log_tail(tp, dbp);
 	/*
 	 * Initialize the block leaf area.  We compact out stale entries.
 	 */
-	lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	lep = XFS_DIR2_BLOCK_LEAF_P(btp);
 	for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
 		if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
 			continue;
@@ -1137,8 +1137,8 @@ xfs_dir2_sf_to_block(
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
 	INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2);	/* ., .. */
-	INT_ZERO(btp->stale, ARCH_CONVERT);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	btp->stale = 0;
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	endoffset = (uint)((char *)blp - (char *)block);
 	/*
 	 * Remove the freespace, we'll manage it.
@@ -1164,7 +1164,7 @@ xfs_dir2_sf_to_block(
 	 */
 	dep = (xfs_dir2_data_entry_t *)
 		((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
-	INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT));
+	INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
 	dep->namelen = 2;
 	dep->name[0] = dep->name[1] = '.';
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -1191,7 +1191,7 @@ xfs_dir2_sf_to_block(
 		if (sfep == NULL)
 			newoffset = endoffset;
 		else
-			newoffset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT);
+			newoffset = XFS_DIR2_SF_GET_OFFSET(sfep);
 		/*
 		 * There should be a hole here, make one.
 		 */
@@ -1200,7 +1200,7 @@ xfs_dir2_sf_to_block(
 			      ((char *)block + offset);
 			INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
 			INT_SET(dup->length, ARCH_CONVERT, newoffset - offset);
-			INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT,
+			INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT,
 				(xfs_dir2_data_off_t)
 				((char *)dup - (char *)block));
 			xfs_dir2_data_log_unused(tp, bp, dup);
@@ -1213,8 +1213,8 @@ xfs_dir2_sf_to_block(
 		 * Copy a real entry.
 		 */
 		dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
-		INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-				XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT));
+		INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp,
+				XFS_DIR2_SF_INUMBERP(sfep)));
 		dep->namelen = sfep->namelen;
 		memcpy(dep->name, sfep->name, dep->namelen);
 		tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
diff --git a/fs/xfs/xfs_dir2_block.h b/fs/xfs/xfs_dir2_block.h
--- a/fs/xfs/xfs_dir2_block.h
+++ b/fs/xfs/xfs_dir2_block.h
@@ -87,13 +87,12 @@ xfs_dir2_block_tail_p(struct xfs_mount *
  * Pointer to the leaf entries embedded in a data block (1-block format)
  */
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_LEAF_P)
-struct xfs_dir2_leaf_entry *xfs_dir2_block_leaf_p_arch(
-	xfs_dir2_block_tail_t *btp, xfs_arch_t arch);
-#define	XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \
-	xfs_dir2_block_leaf_p_arch(btp,arch)
+struct xfs_dir2_leaf_entry *xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp);
+#define	XFS_DIR2_BLOCK_LEAF_P(btp) \
+	xfs_dir2_block_leaf_p(btp)
 #else
-#define	XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch)	\
-	(((struct xfs_dir2_leaf_entry *)(btp)) - INT_GET((btp)->count, arch))
+#define	XFS_DIR2_BLOCK_LEAF_P(btp)	\
+	(((struct xfs_dir2_leaf_entry *)(btp)) - INT_GET((btp)->count, ARCH_CONVERT))
 #endif
 
 /*
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -98,7 +98,7 @@ xfs_dir2_data_check(
 	p = (char *)d->u;
 	if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
-		lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+		lep = XFS_DIR2_BLOCK_LEAF_P(btp);
 		endp = (char *)lep;
 	} else
 		endp = (char *)d + mp->m_dirblksize;
@@ -106,16 +106,16 @@ xfs_dir2_data_check(
 	/*
 	 * Account for zero bestfree entries.
 	 */
-	if (INT_ISZERO(bf[0].length, ARCH_CONVERT)) {
-		ASSERT(INT_ISZERO(bf[0].offset, ARCH_CONVERT));
+	if (!bf[0].length) {
+		ASSERT(!bf[0].offset);
 		freeseen |= 1 << 0;
 	}
-	if (INT_ISZERO(bf[1].length, ARCH_CONVERT)) {
-		ASSERT(INT_ISZERO(bf[1].offset, ARCH_CONVERT));
+	if (!bf[1].length) {
+		ASSERT(!bf[1].offset);
 		freeseen |= 1 << 1;
 	}
-	if (INT_ISZERO(bf[2].length, ARCH_CONVERT)) {
-		ASSERT(INT_ISZERO(bf[2].offset, ARCH_CONVERT));
+	if (!bf[2].length) {
+		ASSERT(!bf[2].offset);
 		freeseen |= 1 << 2;
 	}
 	ASSERT(INT_GET(bf[0].length, ARCH_CONVERT) >= INT_GET(bf[1].length, ARCH_CONVERT));
@@ -132,7 +132,7 @@ xfs_dir2_data_check(
 		 */
 		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
 			ASSERT(lastfree == 0);
-			ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) ==
+			ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT) ==
 			       (char *)dup - (char *)d);
 			dfp = xfs_dir2_data_freefind(d, dup);
 			if (dfp) {
@@ -217,8 +217,8 @@ xfs_dir2_data_freefind(
 	for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0;
 	     dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT];
 	     dfp++) {
-		if (INT_ISZERO(dfp->offset, ARCH_CONVERT)) {
-			ASSERT(INT_ISZERO(dfp->length, ARCH_CONVERT));
+		if (!dfp->offset) {
+			ASSERT(!dfp->length);
 			seenzero = 1;
 			continue;
 		}
@@ -247,7 +247,7 @@ xfs_dir2_data_freefind(
 	for (dfp = &d->hdr.bestfree[0];
 	     dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT];
 	     dfp++) {
-		if (INT_ISZERO(dfp->offset, ARCH_CONVERT))
+		if (!dfp->offset)
 			return NULL;
 		if (INT_GET(dfp->offset, ARCH_CONVERT) == off)
 			return dfp;
@@ -334,8 +334,8 @@ xfs_dir2_data_freeremove(
 	/*
 	 * Clear the 3rd entry, must be zero now.
 	 */
-	INT_ZERO(d->hdr.bestfree[2].length, ARCH_CONVERT);
-	INT_ZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT);
+	d->hdr.bestfree[2].length = 0;
+	d->hdr.bestfree[2].offset = 0;
 	*loghead = 1;
 }
 
@@ -372,7 +372,7 @@ xfs_dir2_data_freescan(
 		endp = aendp;
 	else if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
-		endp = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+		endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	} else
 		endp = (char *)d + mp->m_dirblksize;
 	/*
@@ -385,7 +385,7 @@ xfs_dir2_data_freescan(
 		 */
 		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
 			ASSERT((char *)dup - (char *)d ==
-			       INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT));
+			       INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT));
 			xfs_dir2_data_freeinsert(d, dup, loghead);
 			p += INT_GET(dup->length, ARCH_CONVERT);
 		}
@@ -440,8 +440,8 @@ xfs_dir2_data_init(
 	INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC);
 	INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr));
 	for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
-		INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT);
-		INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT);
+		d->hdr.bestfree[i].length = 0;
+		d->hdr.bestfree[i].offset = 0;
 	}
 	/*
 	 * Set up an unused entry for the block's body.
@@ -452,7 +452,7 @@ xfs_dir2_data_init(
 	t=mp->m_dirblksize - (uint)sizeof(d->hdr);
 	INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t);
 	INT_SET(dup->length, ARCH_CONVERT, t);
-	INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT,
+	INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT,
 		(xfs_dir2_data_off_t)((char *)dup - (char *)d));
 	/*
 	 * Log it and return it.
@@ -523,8 +523,8 @@ xfs_dir2_data_log_unused(
 	 * Log the end (tag) of the unused entry.
 	 */
 	xfs_da_log_buf(tp, bp,
-		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d),
-		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d +
+		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d),
+		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d +
 		       sizeof(xfs_dir2_data_off_t) - 1));
 }
 
@@ -562,7 +562,7 @@ xfs_dir2_data_make_free(
 
 		ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
-		endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+		endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	}
 	/*
 	 * If this isn't the start of the block, then back up to
@@ -608,12 +608,12 @@ xfs_dir2_data_make_free(
 		 * since the third bestfree is there, there might be more
 		 * entries.
 		 */
-		needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT);
+		needscan = d->hdr.bestfree[2].length;
 		/*
 		 * Fix up the new big freespace.
 		 */
 		INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, prevdup);
 		if (!needscan) {
@@ -637,8 +637,8 @@ xfs_dir2_data_make_free(
 			dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp);
 			ASSERT(dfp == &d->hdr.bestfree[0]);
 			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT));
-			ASSERT(INT_ISZERO(dfp[1].length, ARCH_CONVERT));
-			ASSERT(INT_ISZERO(dfp[2].length, ARCH_CONVERT));
+			ASSERT(!dfp[1].length);
+			ASSERT(!dfp[2].length);
 		}
 	}
 	/*
@@ -647,7 +647,7 @@ xfs_dir2_data_make_free(
 	else if (prevdup) {
 		dfp = xfs_dir2_data_freefind(d, prevdup);
 		INT_MOD(prevdup->length, ARCH_CONVERT, len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, prevdup);
 		/*
@@ -673,7 +673,7 @@ xfs_dir2_data_make_free(
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
 		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
 		INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
@@ -698,7 +698,7 @@ xfs_dir2_data_make_free(
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
 		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
 		INT_SET(newdup->length, ARCH_CONVERT, len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
@@ -734,7 +734,7 @@ xfs_dir2_data_use_free(
 	ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG);
 	ASSERT(offset >= (char *)dup - (char *)d);
 	ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d);
-	ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT));
+	ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT));
 	/*
 	 * Look up the entry in the bestfree table.
 	 */
@@ -754,7 +754,7 @@ xfs_dir2_data_use_free(
 	 */
 	if (matchfront && matchback) {
 		if (dfp) {
-			needscan = !INT_ISZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT);
+			needscan = d->hdr.bestfree[2].offset;
 			if (!needscan)
 				xfs_dir2_data_freeremove(d, dfp, needlogp);
 		}
@@ -767,7 +767,7 @@ xfs_dir2_data_use_free(
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
 		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
 		INT_SET(newdup->length, ARCH_CONVERT, oldlen - len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
@@ -795,7 +795,7 @@ xfs_dir2_data_use_free(
 		newdup = dup;
 		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)
 			(((char *)d + offset) - (char *)newdup));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
@@ -823,13 +823,13 @@ xfs_dir2_data_use_free(
 		newdup = dup;
 		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)
 			(((char *)d + offset) - (char *)newdup));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
 		INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
 		INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT,
+		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup2), ARCH_CONVERT,
 			(xfs_dir2_data_off_t)((char *)newdup2 - (char *)d));
 		xfs_dir2_data_log_unused(tp, bp, newdup2);
 		/*
@@ -841,7 +841,7 @@ xfs_dir2_data_use_free(
 		 * the 2 new will work.
 		 */
 		if (dfp) {
-			needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT);
+			needscan = d->hdr.bestfree[2].length;
 			if (!needscan) {
 				xfs_dir2_data_freeremove(d, dfp, needlogp);
 				(void)xfs_dir2_data_freeinsert(d, newdup,
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h
--- a/fs/xfs/xfs_dir2_data.h
+++ b/fs/xfs/xfs_dir2_data.h
@@ -163,14 +163,13 @@ xfs_dir2_data_off_t *xfs_dir2_data_entry
  * Pointer to a freespace's tag word.
  */
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P)
-xfs_dir2_data_off_t *xfs_dir2_data_unused_tag_p_arch(
-	xfs_dir2_data_unused_t *dup, xfs_arch_t arch);
-#define	XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \
-	xfs_dir2_data_unused_tag_p_arch(dup,arch)
+xfs_dir2_data_off_t *xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup);
+#define	XFS_DIR2_DATA_UNUSED_TAG_P(dup) \
+	xfs_dir2_data_unused_tag_p(dup)
 #else
-#define	XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch)	\
+#define	XFS_DIR2_DATA_UNUSED_TAG_P(dup)	\
 	((xfs_dir2_data_off_t *)\
-	 ((char *)(dup) + INT_GET((dup)->length, arch) \
+	 ((char *)(dup) + INT_GET((dup)->length, ARCH_CONVERT) \
 			- (uint)sizeof(xfs_dir2_data_off_t)))
 #endif
 
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -127,7 +127,7 @@ xfs_dir2_block_to_leaf(
 	block = dbp->data;
 	xfs_dir2_data_check(dp, dbp);
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	/*
 	 * Set the counts in the leaf header.
 	 */
@@ -162,7 +162,7 @@ xfs_dir2_block_to_leaf(
 	 */
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
 	INT_SET(ltp->bestcount, ARCH_CONVERT, 1);
-	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
+	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
 	INT_COPY(bestsp[0], block->hdr.bestfree[0].length, ARCH_CONVERT);
 	/*
 	 * Log the data header and leaf bests table.
@@ -233,7 +233,7 @@ xfs_dir2_leaf_addname(
 	index = xfs_dir2_leaf_search_hash(args, lbp);
 	leaf = lbp->data;
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
+	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
 	length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
 	/*
 	 * See if there are any entries with the same hash value
@@ -274,7 +274,7 @@ xfs_dir2_leaf_addname(
 	 * How many bytes do we need in the leaf block?
 	 */
 	needbytes =
-		(!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT) ? 0 : (uint)sizeof(leaf->ents[0])) +
+		(leaf->hdr.stale ? 0 : (uint)sizeof(leaf->ents[0])) +
 		(use_block != -1 ? 0 : (uint)sizeof(leaf->bests[0]));
 	/*
 	 * Now kill use_block if it refers to a missing block, so we
@@ -456,7 +456,7 @@ xfs_dir2_leaf_addname(
 	 * Now we need to make room to insert the leaf entry.
 	 * If there are no stale entries, we just insert a hole at index.
 	 */
-	if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
+	if (!leaf->hdr.stale) {
 		/*
 		 * lep is still good as the index leaf entry.
 		 */
@@ -595,7 +595,7 @@ xfs_dir2_leaf_check(
 	 * Leaves and bests don't overlap.
 	 */
 	ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <=
-	       (char *)XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT));
+	       (char *)XFS_DIR2_LEAF_BESTS_P(ltp));
 	/*
 	 * Check hash value order, count stale entries.
 	 */
@@ -625,7 +625,7 @@ xfs_dir2_leaf_compact(
 	int		to;		/* target leaf index */
 
 	leaf = bp->data;
-	if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
+	if (!leaf->hdr.stale) {
 		return;
 	}
 	/*
@@ -649,7 +649,7 @@ xfs_dir2_leaf_compact(
 	 */
 	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to);
 	INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT)));
-	INT_ZERO(leaf->hdr.stale, ARCH_CONVERT);
+	leaf->hdr.stale = 0;
 	xfs_dir2_leaf_log_header(args->trans, bp);
 	if (loglow != -1)
 		xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1);
@@ -1192,10 +1192,10 @@ xfs_dir2_leaf_init(
 	 * Initialize the header.
 	 */
 	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic);
-	INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT);
-	INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT);
-	INT_ZERO(leaf->hdr.count, ARCH_CONVERT);
-	INT_ZERO(leaf->hdr.stale, ARCH_CONVERT);
+	leaf->hdr.info.forw = 0;
+	leaf->hdr.info.back = 0;
+	leaf->hdr.count = 0;
+	leaf->hdr.stale = 0;
 	xfs_dir2_leaf_log_header(tp, bp);
 	/*
 	 * If it's a leaf-format directory initialize the tail.
@@ -1204,7 +1204,7 @@ xfs_dir2_leaf_init(
 	 */
 	if (magic == XFS_DIR2_LEAF1_MAGIC) {
 		ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-		INT_ZERO(ltp->bestcount, ARCH_CONVERT);
+		ltp->bestcount = 0;
 		xfs_dir2_leaf_log_tail(tp, bp);
 	}
 	*bpp = bp;
@@ -1229,8 +1229,8 @@ xfs_dir2_leaf_log_bests(
 	leaf = bp->data;
 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
 	ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf);
-	firstb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + first;
-	lastb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + last;
+	firstb = XFS_DIR2_LEAF_BESTS_P(ltp) + first;
+	lastb = XFS_DIR2_LEAF_BESTS_P(ltp) + last;
 	xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
 		(uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));
 }
@@ -1497,7 +1497,7 @@ xfs_dir2_leaf_removename(
 	needscan = needlog = 0;
 	oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT);
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
+	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
 	ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest);
 	/*
 	 * Mark the former data entry unused.
@@ -1658,7 +1658,7 @@ xfs_dir2_leaf_search_hash(
 
 	leaf = lbp->data;
 #ifndef __KERNEL__
-	if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))
+	if (!leaf->hdr.count)
 		return 0;
 #endif
 	/*
@@ -1749,7 +1749,7 @@ xfs_dir2_leaf_trim_data(
 	/*
 	 * Eliminate the last bests entry from the table.
 	 */
-	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
+	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
 	INT_MOD(ltp->bestcount, ARCH_CONVERT, -1);
 	memmove(&bestsp[1], &bestsp[0], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
 	xfs_dir2_leaf_log_tail(tp, lbp);
@@ -1835,7 +1835,7 @@ xfs_dir2_node_to_leaf(
 	}
 	free = fbp->data;
 	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
-	ASSERT(INT_ISZERO(free->hdr.firstdb, ARCH_CONVERT));
+	ASSERT(!free->hdr.firstdb);
 	/*
 	 * Now see if the leafn and free data will fit in a leaf1.
 	 * If not, release the buffer and give up.
@@ -1865,7 +1865,7 @@ xfs_dir2_node_to_leaf(
 	/*
 	 * Set up the leaf bests table.
 	 */
-	memcpy(XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), free->bests,
+	memcpy(XFS_DIR2_LEAF_BESTS_P(ltp), free->bests,
 		INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0]));
 	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
 	xfs_dir2_leaf_log_tail(tp, lbp);
diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h
--- a/fs/xfs/xfs_dir2_leaf.h
+++ b/fs/xfs/xfs_dir2_leaf.h
@@ -144,11 +144,11 @@ xfs_dir2_leaf_tail_p(struct xfs_mount *m
  */
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_BESTS_P)
 xfs_dir2_data_off_t *
-xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch);
-#define	XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch)	xfs_dir2_leaf_bests_p_arch(ltp,arch)
+xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp);
+#define	XFS_DIR2_LEAF_BESTS_P(ltp)	xfs_dir2_leaf_bests_p(ltp)
 #else
-#define	XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch)	\
-	((xfs_dir2_data_off_t *)(ltp) - INT_GET((ltp)->bestcount, arch))
+#define	XFS_DIR2_LEAF_BESTS_P(ltp)	\
+	((xfs_dir2_data_off_t *)(ltp) - INT_GET((ltp)->bestcount, ARCH_CONVERT))
 #endif
 
 /*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -172,14 +172,14 @@ xfs_dir2_leaf_to_node(
 	 * Initialize the freespace block header.
 	 */
 	INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC);
-	INT_ZERO(free->hdr.firstdb, ARCH_CONVERT);
+	free->hdr.firstdb = 0;
 	ASSERT(INT_GET(ltp->bestcount, ARCH_CONVERT) <= (uint)dp->i_d.di_size / mp->m_dirblksize);
 	INT_COPY(free->hdr.nvalid, ltp->bestcount, ARCH_CONVERT);
 	/*
 	 * Copy freespace entries from the leaf block to the new block.
 	 * Count active entries.
 	 */
-	for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), to = free->bests;
+	for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P(ltp), to = free->bests;
 	     i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++, from++, to++) {
 		if ((off = INT_GET(*from, ARCH_CONVERT)) != NULLDATAOFF)
 			n++;
@@ -240,7 +240,7 @@ xfs_dir2_leafn_add(
 	 */
 
 	if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
-		if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT))
+		if (!leaf->hdr.stale)
 			return XFS_ERROR(ENOSPC);
 		compact = INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1;
 	} else
@@ -263,14 +263,14 @@ xfs_dir2_leafn_add(
 	/*
 	 * Set impossible logging indices for this case.
 	 */
-	else if (!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
+	else if (leaf->hdr.stale) {
 		lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT);
 		lfloghigh = -1;
 	}
 	/*
 	 * No stale entries, just insert a space for the new entry.
 	 */
-	if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
+	if (!leaf->hdr.stale) {
 		lep = &leaf->ents[index];
 		if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
 			memmove(lep + 1, lep,
@@ -403,7 +403,7 @@ xfs_dir2_leafn_lasthash(
 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
 	if (count)
 		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-	if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))
+	if (!leaf->hdr.count)
 		return 0;
 	return INT_GET(leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
 }
@@ -690,7 +690,7 @@ xfs_dir2_leafn_moveents(
 	 * If the source has stale leaves, count the ones in the copy range
 	 * so we can update the header correctly.
 	 */
-	if (!INT_ISZERO(leaf_s->hdr.stale, ARCH_CONVERT)) {
+	if (leaf_s->hdr.stale) {
 		int	i;			/* temp leaf index */
 
 		for (i = start_s, stale = 0; i < start_s + count; i++) {
@@ -1020,7 +1020,7 @@ xfs_dir2_leafn_remove(
 			 * If there are no useful entries left in the block,
 			 * get rid of the block if we can.
 			 */
-			if (INT_ISZERO(free->hdr.nused, ARCH_CONVERT)) {
+			if (!free->hdr.nused) {
 				error = xfs_dir2_shrink_inode(args, fdb, fbp);
 				if (error == 0) {
 					fbp = NULL;
@@ -1182,7 +1182,7 @@ xfs_dir2_leafn_toosmall(
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
+		forward = info->forw;
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward, 0,
 			&rval);
@@ -1634,8 +1634,8 @@ xfs_dir2_node_addname_int(
 			INT_SET(free->hdr.firstdb, ARCH_CONVERT,
 				(fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
 				XFS_DIR2_MAX_FREE_BESTS(mp));
-			INT_ZERO(free->hdr.nvalid, ARCH_CONVERT);
-			INT_ZERO(free->hdr.nused, ARCH_CONVERT);
+			free->hdr.nvalid = 0;
+			free->hdr.nused = 0;
 		} else {
 			free = fbp->data;
 			ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -114,7 +114,7 @@ xfs_dir2_block_sfsize(
 
 	count = i8count = namelen = 0;
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 
 	/*
 	 * Iterate over the block's data entries by using the leaf pointers.
@@ -163,7 +163,7 @@ xfs_dir2_block_sfsize(
 	 */
 	sfhp->count = count;
 	sfhp->i8count = i8count;
-	XFS_DIR2_SF_PUT_INUMBER_ARCH((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent, ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_INUMBER((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
 	return size;
 }
 
@@ -230,7 +230,7 @@ xfs_dir2_block_to_sf(
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
 	ptr = (char *)block->u;
-	endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+	endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
 	/*
 	 * Loop over the active and unused entries.
@@ -257,19 +257,19 @@ xfs_dir2_block_to_sf(
 		else if (dep->namelen == 2 &&
 			 dep->name[0] == '.' && dep->name[1] == '.')
 			ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) ==
-			       XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT));
+			       XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
 		/*
 		 * Normal entry, copy it into shortform.
 		 */
 		else {
 			sfep->namelen = dep->namelen;
-			XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,
+			XFS_DIR2_SF_PUT_OFFSET(sfep,
 				(xfs_dir2_data_aoff_t)
-				((char *)dep - (char *)block), ARCH_CONVERT);
+				((char *)dep - (char *)block));
 			memcpy(sfep->name, dep->name, dep->namelen);
 			temp=INT_GET(dep->inumber, ARCH_CONVERT);
-			XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp,
-				XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+			XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
+				XFS_DIR2_SF_INUMBERP(sfep));
 			sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
 		}
 		ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
@@ -427,10 +427,10 @@ xfs_dir2_sf_addname_easy(
 	 * Fill in the new entry.
 	 */
 	sfep->namelen = args->namelen;
-	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
 	memcpy(sfep->name, args->name, sfep->namelen);
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
-		XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
+		XFS_DIR2_SF_INUMBERP(sfep));
 	/*
 	 * Update the header and inode.
 	 */
@@ -494,7 +494,7 @@ xfs_dir2_sf_addname_hard(
 	     offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen),
 	      oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep),
 	      eof = (char *)oldsfep == &buf[old_isize]) {
-		new_offset = XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT);
+		new_offset = XFS_DIR2_SF_GET_OFFSET(oldsfep);
 		if (offset + add_datasize <= new_offset)
 			break;
 	}
@@ -519,10 +519,10 @@ xfs_dir2_sf_addname_hard(
 	 * Fill in the new entry, and update the header counts.
 	 */
 	sfep->namelen = args->namelen;
-	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
 	memcpy(sfep->name, args->name, sfep->namelen);
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
-		XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
+		XFS_DIR2_SF_INUMBERP(sfep));
 	sfp->hdr.count++;
 #if XFS_BIG_INUMS
 	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@@ -579,8 +579,8 @@ xfs_dir2_sf_addname_pick(
 	 */
 	for (i = 0; i < sfp->hdr.count; i++) {
 		if (!holefit)
-			holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT);
-		offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) +
+			holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET(sfep);
+		offset = XFS_DIR2_SF_GET_OFFSET(sfep) +
 			 XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
 		sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
 	}
@@ -641,17 +641,17 @@ xfs_dir2_sf_check(
 
 	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
 	offset = XFS_DIR2_DATA_FIRST_OFFSET;
-	ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT);
+	ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
 	i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
 
 	for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
 	     i < sfp->hdr.count;
 	     i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
-		ASSERT(XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) >= offset);
-		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+		ASSERT(XFS_DIR2_SF_GET_OFFSET(sfep) >= offset);
+		ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
 		i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
 		offset =
-			XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) +
+			XFS_DIR2_SF_GET_OFFSET(sfep) +
 			XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
 	}
 	ASSERT(i8count == sfp->hdr.i8count);
@@ -708,7 +708,7 @@ xfs_dir2_sf_create(
 	/*
 	 * Now can put in the inode number, since i8count is set.
 	 */
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &pino, &sfp->hdr.parent, ARCH_CONVERT);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, &pino, &sfp->hdr.parent);
 	sfp->hdr.count = 0;
 	dp->i_d.di_size = size;
 	xfs_dir2_sf_check(args);
@@ -800,8 +800,7 @@ xfs_dir2_sf_getdents(
 					       XFS_DIR2_DATA_DOTDOT_OFFSET)) {
 		p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
 						XFS_DIR2_DATA_FIRST_OFFSET);
-		p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent,
-						ARCH_CONVERT);
+		p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
 #if XFS_BIG_INUMS
 		p.ino += mp->m_inoadd;
 #endif
@@ -826,7 +825,7 @@ xfs_dir2_sf_getdents(
 			     i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
 
 		off = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
-				XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT));
+				XFS_DIR2_SF_GET_OFFSET(sfep));
 
 		if (dir_offset > off)
 			continue;
@@ -834,11 +833,10 @@ xfs_dir2_sf_getdents(
 		p.namelen = sfep->namelen;
 
 		p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
-			XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) +
+			XFS_DIR2_SF_GET_OFFSET(sfep) +
 			XFS_DIR2_DATA_ENTSIZE(p.namelen));
 
-		p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-				XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+		p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
 #if XFS_BIG_INUMS
 		p.ino += mp->m_inoadd;
 #endif
@@ -904,7 +902,7 @@ xfs_dir2_sf_lookup(
 	 */
 	if (args->namelen == 2 &&
 	    args->name[0] == '.' && args->name[1] == '.') {
-		args->inumber = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT);
+		args->inumber = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
 		return XFS_ERROR(EEXIST);
 	}
 	/*
@@ -917,8 +915,8 @@ xfs_dir2_sf_lookup(
 		    sfep->name[0] == args->name[0] &&
 		    memcmp(args->name, sfep->name, args->namelen) == 0) {
 			args->inumber =
-				XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+				XFS_DIR2_SF_GET_INUMBER(sfp,
+					XFS_DIR2_SF_INUMBERP(sfep));
 			return XFS_ERROR(EEXIST);
 		}
 	}
@@ -971,8 +969,8 @@ xfs_dir2_sf_removename(
 		if (sfep->namelen == args->namelen &&
 		    sfep->name[0] == args->name[0] &&
 		    memcmp(sfep->name, args->name, args->namelen) == 0) {
-			ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) ==
+			ASSERT(XFS_DIR2_SF_GET_INUMBER(sfp,
+					XFS_DIR2_SF_INUMBERP(sfep)) ==
 				args->inumber);
 			break;
 		}
@@ -1093,10 +1091,10 @@ xfs_dir2_sf_replace(
 	if (args->namelen == 2 &&
 	    args->name[0] == '.' && args->name[1] == '.') {
 #if XFS_BIG_INUMS || defined(DEBUG)
-		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT);
+		ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
 		ASSERT(args->inumber != ino);
 #endif
-		XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, &sfp->hdr.parent, ARCH_CONVERT);
+		XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber, &sfp->hdr.parent);
 	}
 	/*
 	 * Normal entry, look for the name.
@@ -1109,12 +1107,12 @@ xfs_dir2_sf_replace(
 			    sfep->name[0] == args->name[0] &&
 			    memcmp(args->name, sfep->name, args->namelen) == 0) {
 #if XFS_BIG_INUMS || defined(DEBUG)
-				ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+				ino = XFS_DIR2_SF_GET_INUMBER(sfp,
+					XFS_DIR2_SF_INUMBERP(sfep));
 				ASSERT(args->inumber != ino);
 #endif
-				XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
-					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+				XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
+					XFS_DIR2_SF_INUMBERP(sfep));
 				break;
 			}
 		}
@@ -1215,8 +1213,8 @@ xfs_dir2_sf_toino4(
 	 */
 	sfp->hdr.count = oldsfp->hdr.count;
 	sfp->hdr.i8count = 0;
-	ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT);
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT);
+	ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
 	/*
 	 * Copy the entries field by field.
 	 */
@@ -1228,9 +1226,9 @@ xfs_dir2_sf_toino4(
 		sfep->namelen = oldsfep->namelen;
 		sfep->offset = oldsfep->offset;
 		memcpy(sfep->name, oldsfep->name, sfep->namelen);
-		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
-			XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
-		XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+		ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
+			XFS_DIR2_SF_INUMBERP(oldsfep));
+		XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
 	}
 	/*
 	 * Clean up the inode.
@@ -1292,8 +1290,8 @@ xfs_dir2_sf_toino8(
 	 */
 	sfp->hdr.count = oldsfp->hdr.count;
 	sfp->hdr.i8count = 1;
-	ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT);
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT);
+	ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
 	/*
 	 * Copy the entries field by field.
 	 */
@@ -1305,9 +1303,9 @@ xfs_dir2_sf_toino8(
 		sfep->namelen = oldsfep->namelen;
 		sfep->offset = oldsfep->offset;
 		memcpy(sfep->name, oldsfep->name, sfep->namelen);
-		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
-			XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
-		XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
+		ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
+			XFS_DIR2_SF_INUMBERP(oldsfep));
+		XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
 	}
 	/*
 	 * Clean up the inode.
diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h
--- a/fs/xfs/xfs_dir2_sf.h
+++ b/fs/xfs/xfs_dir2_sf.h
@@ -59,21 +59,12 @@ struct xfs_trans;
  */
 typedef	struct { __uint8_t i[8]; } xfs_dir2_ino8_t;
 
-#define	XFS_DIR2_SF_GET_INO8_ARCH(di,arch)	\
-	(xfs_ino_t)(DIRINO_GET_ARCH(&di,arch))
-#define	XFS_DIR2_SF_GET_INO8(di)	        \
-	XFS_DIR2_SF_GET_INO8_ARCH(di,ARCH_NOCONVERT)
-
 /*
  * Inode number stored as 4 8-bit values.
  * Works a lot of the time, when all the inode numbers in a directory
  * fit in 32 bits.
  */
 typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t;
-#define	XFS_DIR2_SF_GET_INO4_ARCH(di,arch)	\
-	(xfs_ino_t)(DIRINO4_GET_ARCH(&di,arch))
-#define	XFS_DIR2_SF_GET_INO4(di)	        \
-	XFS_DIR2_SF_GET_INO4_ARCH(di,ARCH_NOCONVERT)
 
 typedef union {
 	xfs_dir2_ino8_t	i8;
@@ -132,51 +123,48 @@ xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xf
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_INUMBER)
-xfs_intino_t xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from,
-					    xfs_arch_t arch);
-#define	XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch)	\
-	xfs_dir2_sf_get_inumber_arch(sfp, from, arch)
+xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from);
+#define	XFS_DIR2_SF_GET_INUMBER(sfp, from)	\
+	xfs_dir2_sf_get_inumber(sfp, from)
 
 #else
-#define	XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch)	\
+#define	XFS_DIR2_SF_GET_INUMBER(sfp, from)	\
 	((sfp)->hdr.i8count == 0 ? \
-		(xfs_intino_t)XFS_DIR2_SF_GET_INO4_ARCH(*(from), arch) : \
-		(xfs_intino_t)XFS_DIR2_SF_GET_INO8_ARCH(*(from), arch))
+		(xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
+		(xfs_intino_t)XFS_GET_DIR_INO8((from)->i8))
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_INUMBER)
-void xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from,
-				     xfs_dir2_inou_t *to, xfs_arch_t arch);
-#define	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch)	\
-	xfs_dir2_sf_put_inumber_arch(sfp,from,to,arch)
+void xfs_dir2_sf_put_inumber(xfs_dir2_sf_t *sfp, xfs_ino_t *from,
+				     xfs_dir2_inou_t *to);
+#define	XFS_DIR2_SF_PUT_INUMBER(sfp,from,to)	\
+	xfs_dir2_sf_put_inumber(sfp,from,to)
 #else
-#define	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch)	\
+#define	XFS_DIR2_SF_PUT_INUMBER(sfp,from,to)	\
 	if ((sfp)->hdr.i8count == 0) { \
-	    DIRINO4_COPY_ARCH(from,to,arch); \
+		XFS_PUT_DIR_INO4(*(from), (to)->i4); \
 	} else { \
-	    DIRINO_COPY_ARCH(from,to,arch); \
+		XFS_PUT_DIR_INO8(*(from), (to)->i8); \
 	}
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_OFFSET)
-xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep,
-						    xfs_arch_t arch);
 xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep);
-#define	XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch)	\
-	xfs_dir2_sf_get_offset_arch(sfep,arch)
+#define	XFS_DIR2_SF_GET_OFFSET(sfep)	\
+	xfs_dir2_sf_get_offset(sfep)
 #else
-#define	XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch)	\
-	INT_GET_UNALIGNED_16_ARCH(&(sfep)->offset.i,arch)
+#define	XFS_DIR2_SF_GET_OFFSET(sfep)	\
+	INT_GET_UNALIGNED_16_BE(&(sfep)->offset.i)
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_OFFSET)
-void xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep,
-				    xfs_dir2_data_aoff_t off, xfs_arch_t arch);
-#define	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \
-	xfs_dir2_sf_put_offset_arch(sfep,off,arch)
+void xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep,
+				    xfs_dir2_data_aoff_t off);
+#define	XFS_DIR2_SF_PUT_OFFSET(sfep,off) \
+	xfs_dir2_sf_put_offset(sfep,off)
 #else
-#define	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch)	\
-	INT_SET_UNALIGNED_16_ARCH(&(sfep)->offset.i,off,arch)
+#define	XFS_DIR2_SF_PUT_OFFSET(sfep,off)	\
+	INT_SET_UNALIGNED_16_BE(&(sfep)->offset.i,off)
 #endif
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME)
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c
--- a/fs/xfs/xfs_dir_leaf.c
+++ b/fs/xfs/xfs_dir_leaf.c
@@ -160,9 +160,9 @@ xfs_dir_shortform_create(xfs_da_args_t *
 	ASSERT(dp->i_df.if_bytes == 0);
 	xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK);
 	hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;
-	XFS_DIR_SF_PUT_DIRINO_ARCH(&parent, &hdr->parent, ARCH_CONVERT);
+	XFS_DIR_SF_PUT_DIRINO(&parent, &hdr->parent);
 
-	INT_ZERO(hdr->count, ARCH_CONVERT);
+	hdr->count = 0;
 	dp->i_d.di_size = sizeof(*hdr);
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
 	return(0);
@@ -208,7 +208,7 @@ xfs_dir_shortform_addname(xfs_da_args_t 
 	sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
 	sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset);
 
-	XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
+	XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
 	sfe->namelen = args->namelen;
 	memcpy(sfe->name, args->name, sfe->namelen);
 	INT_MOD(sf->hdr.count, ARCH_CONVERT, +1);
@@ -298,7 +298,7 @@ xfs_dir_shortform_lookup(xfs_da_args_t *
 	sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
 	if (args->namelen == 2 &&
 	    args->name[0] == '.' && args->name[1] == '.') {
-		XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &args->inumber, ARCH_CONVERT);
+		XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &args->inumber);
 		return(XFS_ERROR(EEXIST));
 	}
 	if (args->namelen == 1 && args->name[0] == '.') {
@@ -310,7 +310,7 @@ xfs_dir_shortform_lookup(xfs_da_args_t *
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
 		    memcmp(args->name, sfe->name, args->namelen) == 0) {
-			XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT);
+			XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args->inumber);
 			return(XFS_ERROR(EEXIST));
 		}
 		sfe = XFS_DIR_SF_NEXTENTRY(sfe);
@@ -353,7 +353,7 @@ xfs_dir_shortform_to_leaf(xfs_da_args_t 
 	memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size);
 
 	sf = (xfs_dir_shortform_t *)tmpbuffer;
-	XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT);
+	XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &inumber);
 
 	xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
 	dp->i_d.di_size = 0;
@@ -398,7 +398,7 @@ xfs_dir_shortform_to_leaf(xfs_da_args_t 
 		args.namelen = sfe->namelen;
 		args.hashval = xfs_da_hashname((char *)(sfe->name),
 					       sfe->namelen);
-		XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args.inumber, ARCH_CONVERT);
+		XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args.inumber);
 		retval = xfs_dir_leaf_addname(&args);
 		if (retval)
 			goto out;
@@ -470,7 +470,7 @@ xfs_dir_shortform_getdents(xfs_inode_t *
 	sbp->entno = 1;
 	sbp->seqno = 0;
 	sbp->hash = xfs_dir_hash_dotdot;
-	sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT);
+	sbp->ino = XFS_GET_DIR_INO8(sf->hdr.parent);
 	sbp->name = "..";
 	sbp->namelen = 2;
 	sbp++;
@@ -494,7 +494,7 @@ xfs_dir_shortform_getdents(xfs_inode_t *
 		sbp->entno = i + 2;
 		sbp->seqno = 0;
 		sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen);
-		sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT);
+		sbp->ino = XFS_GET_DIR_INO8(sfe->inumber);
 		sbp->name = (char *)sfe->name;
 		sbp->namelen = sfe->namelen;
 		sfe = XFS_DIR_SF_NEXTENTRY(sfe);
@@ -612,7 +612,7 @@ xfs_dir_shortform_replace(xfs_da_args_t 
 	if (args->namelen == 2 &&
 	    args->name[0] == '.' && args->name[1] == '.') {
 		/* XXX - replace assert? */
-		XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sf->hdr.parent, ARCH_CONVERT);
+		XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sf->hdr.parent);
 		xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
 		return(0);
 	}
@@ -624,7 +624,7 @@ xfs_dir_shortform_replace(xfs_da_args_t 
 		    memcmp(args->name, sfe->name, args->namelen) == 0) {
 			ASSERT(memcmp((char *)&args->inumber,
 				(char *)&sfe->inumber, sizeof(xfs_ino_t)));
-			XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
+			XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
 			xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
 			return(0);
 		}
@@ -675,10 +675,10 @@ xfs_dir_leaf_to_shortform(xfs_da_args_t 
 		if ((entry->namelen == 2) &&
 		    (namest->name[0] == '.') &&
 		    (namest->name[1] == '.')) {
-			XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &parent, ARCH_CONVERT);
-			INT_ZERO(entry->nameidx, ARCH_CONVERT);
+			XFS_DIR_SF_GET_DIRINO(&namest->inumber, &parent);
+			entry->nameidx = 0;
 		} else if ((entry->namelen == 1) && (namest->name[0] == '.')) {
-			INT_ZERO(entry->nameidx, ARCH_CONVERT);
+			entry->nameidx = 0;
 		}
 	}
 	retval = xfs_da_shrink_inode(iargs, 0, bp);
@@ -701,13 +701,13 @@ xfs_dir_leaf_to_shortform(xfs_da_args_t 
 	args.justcheck = 0;
 	args.addname = args.oknoent = 1;
 	for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
-		if (INT_ISZERO(entry->nameidx, ARCH_CONVERT))
+		if (!entry->nameidx)
 			continue;
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 		args.name = (char *)(namest->name);
 		args.namelen = entry->namelen;
 		args.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
-		XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args.inumber, ARCH_CONVERT);
+		XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args.inumber);
 		xfs_dir_shortform_addname(&args);
 	}
 
@@ -801,7 +801,7 @@ xfs_dir_leaf_create(xfs_da_args_t *args,
 	hdr = &leaf->hdr;
 	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC);
 	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
-	if (INT_ISZERO(hdr->firstused, ARCH_CONVERT))
+	if (!hdr->firstused)
 		INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1);
 	INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
 	INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT));
@@ -895,7 +895,7 @@ xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da
 			sum += INT_GET(map->size, ARCH_CONVERT);
 			continue;
 		}
-		if (INT_ISZERO(map->size, ARCH_CONVERT))
+		if (!map->size)
 			continue;	/* no space in this map */
 		tmp = entsize;
 		if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
@@ -995,7 +995,7 @@ xfs_dir_leaf_add_work(xfs_dabuf_t *bp, x
 	 * Copy the string and inode number into the new space.
 	 */
 	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-	XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT);
+	XFS_DIR_SF_PUT_DIRINO(&args->inumber, &namest->inumber);
 	memcpy(namest->name, args->name, args->namelen);
 	xfs_da_log_buf(args->trans, bp,
 	    XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)));
@@ -1060,10 +1060,10 @@ xfs_dir_leaf_compact(xfs_trans_t *trans,
 	hdr_d = &leaf_d->hdr;
 	hdr_d->info = hdr_s->info;	/* struct copy */
 	INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize);
-	if (INT_ISZERO(hdr_d->firstused, ARCH_CONVERT))
+	if (!hdr_d->firstused)
 		INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1);
-	INT_ZERO(hdr_d->namebytes, ARCH_CONVERT);
-	INT_ZERO(hdr_d->count, ARCH_CONVERT);
+	hdr_d->namebytes = 0;
+	hdr_d->count = 0;
 	hdr_d->holes = 0;
 	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
 	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
@@ -1366,7 +1366,7 @@ xfs_dir_leaf_toosmall(xfs_da_state_t *st
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
+		forward = info->forw;
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1515,8 +1515,8 @@ xfs_dir_leaf_remove(xfs_trans_t *trans, 
 			map = &hdr->freemap[before];
 			INT_MOD(map->size, ARCH_CONVERT, entsize);
 			INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
-			INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT);
-			INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT);
+			hdr->freemap[after].base = 0;
+			hdr->freemap[after].size = 0;
 		} else if (before >= 0) {
 			map = &hdr->freemap[before];
 			INT_MOD(map->size, ARCH_CONVERT, entsize);
@@ -1576,7 +1576,7 @@ xfs_dir_leaf_remove(xfs_trans_t *trans, 
 				tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
 		}
 		INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
-		if (INT_ISZERO(hdr->firstused, ARCH_CONVERT))
+		if (!hdr->firstused)
 			INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1);
 	} else {
 		hdr->holes = 1;		/* mark as needing compaction */
@@ -1656,11 +1656,11 @@ xfs_dir_leaf_unbalance(xfs_da_state_t *s
 		tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer;
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info;	/* struct copy */
-		INT_ZERO(tmp_hdr->count, ARCH_CONVERT);
+		tmp_hdr->count = 0;
 		INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
-		if (INT_ISZERO(tmp_hdr->firstused, ARCH_CONVERT))
+		if (!tmp_hdr->firstused)
 			INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1);
-		INT_ZERO(tmp_hdr->namebytes, ARCH_CONVERT);
+		tmp_hdr->namebytes = 0;
 		if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
 						 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
@@ -1732,7 +1732,7 @@ xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp,
 			break;
 	}
 	ASSERT((probe >= 0) && \
-	       ((INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
+	       ((!leaf->hdr.count) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
 	ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval));
 
 	/*
@@ -1761,7 +1761,7 @@ xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp,
 		if (entry->namelen == args->namelen &&
 		    namest->name[0] == args->name[0] &&
 		    memcmp(args->name, namest->name, args->namelen) == 0) {
-			XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT);
+			XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args->inumber);
 			*index = probe;
 			return(XFS_ERROR(EEXIST));
 		}
@@ -1886,8 +1886,8 @@ xfs_dir_leaf_moveents(xfs_dir_leafblock_
 	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t));
 	INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t));
 	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
-	INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT));
-	INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT));
+	INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, (hdr_d->freemap[2].base = 0));
+	INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, (hdr_d->freemap[2].size = 0));
 	hdr_s->holes = 1;	/* leaf may not be compact */
 }
 
@@ -1925,7 +1925,7 @@ xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, i
 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
 	if (count)
 		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-	if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))
+	if (!leaf->hdr.count)
 		return(0);
 	return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
 }
@@ -2140,7 +2140,7 @@ xfs_dir_leaf_getdents_int(
 		 * then restore the UIO to the first entry in the current
 		 * run of equal-hashval entries (probably one 1 entry long).
 		 */
-		p.ino = XFS_GET_DIR_INO_ARCH(mp, namest->inumber, ARCH_CONVERT);
+		p.ino = XFS_GET_DIR_INO8(namest->inumber);
 #if XFS_BIG_INUMS
 		p.ino += mp->m_inoadd;
 #endif
diff --git a/fs/xfs/xfs_dir_leaf.h b/fs/xfs/xfs_dir_leaf.h
--- a/fs/xfs/xfs_dir_leaf.h
+++ b/fs/xfs/xfs_dir_leaf.h
@@ -140,11 +140,6 @@ typedef union {
 #define	XFS_PUT_COOKIE(c,mp,bno,entry,hash)	\
 	((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash))
 
-#define	XFS_GET_DIR_INO_ARCH(mp,di,arch) \
-    DIRINO_GET_ARCH(&(di),arch)
-#define	XFS_GET_DIR_INO(mp,di) \
-    XFS_GET_DIR_INO_ARCH(mp,di,ARCH_NOCONVERT)
-
 typedef struct xfs_dir_put_args
 {
 	xfs_dircook_t	cook;		/* cookie of (next) entry */
diff --git a/fs/xfs/xfs_dir_sf.h b/fs/xfs/xfs_dir_sf.h
--- a/fs/xfs/xfs_dir_sf.h
+++ b/fs/xfs/xfs_dir_sf.h
@@ -77,22 +77,16 @@ typedef struct xfs_dir_sf_sort {
 } xfs_dir_sf_sort_t;
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_GET_DIRINO)
-void xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch);
 void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to);
-#define	XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch)    xfs_dir_sf_get_dirino_arch(from, to, arch)
 #define	XFS_DIR_SF_GET_DIRINO(from,to)		    xfs_dir_sf_get_dirino(from, to)
 #else
-#define	XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch)    DIRINO_COPY_ARCH(from,to,arch)
-#define	XFS_DIR_SF_GET_DIRINO(from,to)	            DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT)
+#define	XFS_DIR_SF_GET_DIRINO(from,to)		    (*(to) = XFS_GET_DIR_INO8(*from))
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_PUT_DIRINO)
-void xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch);
 void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to);
-#define	XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch)    xfs_dir_sf_put_dirino_arch(from, to, arch)
-#define	XFS_DIR_SF_PUT_DIRINO(from,to)		    xfs_dir_sf_put_dirino(from, to)
+#define	XFS_DIR_SF_PUT_DIRINO(from,to)    xfs_dir_sf_put_dirino(from, to)
 #else
-#define	XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch)    DIRINO_COPY_ARCH(from,to,arch)
-#define	XFS_DIR_SF_PUT_DIRINO(from,to)	            DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT)
+#define	XFS_DIR_SF_PUT_DIRINO(from,to)    XFS_PUT_DIR_INO8(*(from), *(to))
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME)
 int xfs_dir_sf_entsize_byname(int len);
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -220,9 +220,9 @@ xfs_growfs_data_private(
 			XFS_CNT_BLOCK(mp));
 		INT_SET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT, 1);
 		INT_SET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT, 1);
-		INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
+		agf->agf_flfirst = 0;
 		INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE(mp) - 1);
-		INT_ZERO(agf->agf_flcount, ARCH_CONVERT);
+		agf->agf_flcount = 0;
 		tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
 		INT_SET(agf->agf_freeblks, ARCH_CONVERT, tmpsize);
 		INT_SET(agf->agf_longest, ARCH_CONVERT, tmpsize);
@@ -242,10 +242,10 @@ xfs_growfs_data_private(
 		INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION);
 		INT_SET(agi->agi_seqno, ARCH_CONVERT, agno);
 		INT_SET(agi->agi_length, ARCH_CONVERT, agsize);
-		INT_ZERO(agi->agi_count, ARCH_CONVERT);
+		agi->agi_count = 0;
 		INT_SET(agi->agi_root, ARCH_CONVERT, XFS_IBT_BLOCK(mp));
 		INT_SET(agi->agi_level, ARCH_CONVERT, 1);
-		INT_ZERO(agi->agi_freecount, ARCH_CONVERT);
+		agi->agi_freecount = 0;
 		INT_SET(agi->agi_newino, ARCH_CONVERT, NULLAGINO);
 		INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO);
 		for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
@@ -264,7 +264,7 @@ xfs_growfs_data_private(
 		block = XFS_BUF_TO_SBLOCK(bp);
 		memset(block, 0, mp->m_sb.sb_blocksize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC);
-		INT_ZERO(block->bb_level, ARCH_CONVERT);
+		block->bb_level = 0;
 		INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
 		INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
 		INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
@@ -287,7 +287,7 @@ xfs_growfs_data_private(
 		block = XFS_BUF_TO_SBLOCK(bp);
 		memset(block, 0, mp->m_sb.sb_blocksize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC);
-		INT_ZERO(block->bb_level, ARCH_CONVERT);
+		block->bb_level = 0;
 		INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
 		INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
 		INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
@@ -311,8 +311,8 @@ xfs_growfs_data_private(
 		block = XFS_BUF_TO_SBLOCK(bp);
 		memset(block, 0, mp->m_sb.sb_blocksize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC);
-		INT_ZERO(block->bb_level, ARCH_CONVERT);
-		INT_ZERO(block->bb_numrecs, ARCH_CONVERT);
+		block->bb_level = 0;
+		block->bb_numrecs = 0;
 		INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
 		INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
 		error = xfs_bwrite(mp, bp);
@@ -393,7 +393,7 @@ xfs_growfs_data_private(
 			break;
 		}
 		sbp = XFS_BUF_TO_SBP(bp);
-		xfs_xlatesb(sbp, &mp->m_sb, -1, ARCH_CONVERT, XFS_SB_ALL_BITS);
+		xfs_xlatesb(sbp, &mp->m_sb, -1, XFS_SB_ALL_BITS);
 		/*
 		 * If we get an error writing out the alternate superblocks,
 		 * just issue a warning and continue.  The real work is
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -580,7 +580,7 @@ xfs_dialloc(
 	 * allocation groups upward, wrapping at the end.
 	 */
 	*alloc_done = B_FALSE;
-	while (INT_ISZERO(agi->agi_freecount, ARCH_CONVERT)) {
+	while (!agi->agi_freecount) {
 		/*
 		 * Don't do anything if we're not supposed to allocate
 		 * any blocks, just go on to the next ag.
@@ -662,7 +662,7 @@ nextag:
 		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 		do {
 			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-					&rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT)))
+					&rec.ir_freecount, &rec.ir_free, &i)))
 				goto error0;
 			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 			freecount += rec.ir_freecount;
@@ -682,7 +682,7 @@ nextag:
 			goto error0;
 		if (i != 0 &&
 		    (error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-			    &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 &&
+			    &rec.ir_freecount, &rec.ir_free, &j)) == 0 &&
 		    j == 1 &&
 		    rec.ir_freecount > 0) {
 			/*
@@ -717,7 +717,7 @@ nextag:
 				if ((error = xfs_inobt_get_rec(tcur,
 						&trec.ir_startino,
 						&trec.ir_freecount,
-						&trec.ir_free, &i, ARCH_NOCONVERT)))
+						&trec.ir_free, &i)))
 					goto error1;
 				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
 			}
@@ -731,7 +731,7 @@ nextag:
 				if ((error = xfs_inobt_get_rec(cur,
 						&rec.ir_startino,
 						&rec.ir_freecount,
-						&rec.ir_free, &i, ARCH_NOCONVERT)))
+						&rec.ir_free, &i)))
 					goto error1;
 				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
 			}
@@ -795,7 +795,7 @@ nextag:
 							    tcur,
 							    &trec.ir_startino,
 							    &trec.ir_freecount,
-							    &trec.ir_free, &i, ARCH_NOCONVERT)))
+							    &trec.ir_free, &i)))
 							goto error1;
 						XFS_WANT_CORRUPTED_GOTO(i == 1,
 							error1);
@@ -815,7 +815,7 @@ nextag:
 							    cur,
 							    &rec.ir_startino,
 							    &rec.ir_freecount,
-							    &rec.ir_free, &i, ARCH_NOCONVERT)))
+							    &rec.ir_free, &i)))
 							goto error1;
 						XFS_WANT_CORRUPTED_GOTO(i == 1,
 							error1);
@@ -835,7 +835,7 @@ nextag:
 			goto error0;
 		if (i == 1 &&
 		    (error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-			    &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 &&
+			    &rec.ir_freecount, &rec.ir_free, &j)) == 0 &&
 		    j == 1 &&
 		    rec.ir_freecount > 0) {
 			/*
@@ -856,7 +856,7 @@ nextag:
 				if ((error = xfs_inobt_get_rec(cur,
 						&rec.ir_startino,
 						&rec.ir_freecount, &rec.ir_free,
-						&i, ARCH_NOCONVERT)))
+						&i)))
 					goto error0;
 				XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 				if (rec.ir_freecount > 0)
@@ -873,7 +873,7 @@ nextag:
 	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
 				   XFS_INODES_PER_CHUNK) == 0);
 	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
-	XFS_INOBT_CLR_FREE(&rec, offset, ARCH_NOCONVERT);
+	XFS_INOBT_CLR_FREE(&rec, offset);
 	rec.ir_freecount--;
 	if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount,
 			rec.ir_free)))
@@ -891,7 +891,7 @@ nextag:
 			goto error0;
 		do {
 			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-					&rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT)))
+					&rec.ir_freecount, &rec.ir_free, &i)))
 				goto error0;
 			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 			freecount += rec.ir_freecount;
@@ -998,7 +998,7 @@ xfs_difree(
 			goto error0;
 		do {
 			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-					&rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT)))
+					&rec.ir_freecount, &rec.ir_free, &i)))
 				goto error0;
 			if (i) {
 				freecount += rec.ir_freecount;
@@ -1021,7 +1021,7 @@ xfs_difree(
 	}
 	XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 	if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount,
-			&rec.ir_free, &i, ARCH_NOCONVERT))) {
+			&rec.ir_free, &i))) {
 		cmn_err(CE_WARN,
 			"xfs_difree: xfs_inobt_get_rec()  returned an error %d on %s.  Returning error.",
 			error, mp->m_fsname);
@@ -1033,11 +1033,11 @@ xfs_difree(
 	 */
 	off = agino - rec.ir_startino;
 	ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK);
-	ASSERT(!XFS_INOBT_IS_FREE(&rec, off, ARCH_NOCONVERT));
+	ASSERT(!XFS_INOBT_IS_FREE(&rec, off));
 	/*
 	 * Mark the inode free & increment the count.
 	 */
-	XFS_INOBT_SET_FREE(&rec, off, ARCH_NOCONVERT);
+	XFS_INOBT_SET_FREE(&rec, off);
 	rec.ir_freecount++;
 
 	/*
@@ -1103,8 +1103,7 @@ xfs_difree(
 			if ((error = xfs_inobt_get_rec(cur,
 					&rec.ir_startino,
 					&rec.ir_freecount,
-					&rec.ir_free, &i,
-					ARCH_NOCONVERT)))
+					&rec.ir_free, &i)))
 				goto error0;
 			if (i) {
 				freecount += rec.ir_freecount;
@@ -1232,7 +1231,7 @@ xfs_dilocate(
 			goto error0;
 		}
 		if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
-				&chunk_free, &i, ARCH_NOCONVERT))) {
+				&chunk_free, &i))) {
 #ifdef DEBUG
 			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
 					"xfs_inobt_get_rec() failed");
@@ -1392,7 +1391,7 @@ xfs_ialloc_read_agi(
 		int	i;
 
 		for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++)
-			ASSERT(!INT_ISZERO(agi->agi_unlinked[i], ARCH_CONVERT));
+			ASSERT(agi->agi_unlinked[i]);
 	}
 #endif
 
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -1801,8 +1801,7 @@ xfs_inobt_get_rec(
 	xfs_agino_t		*ino,	/* output: starting inode of chunk */
 	__int32_t		*fcnt,	/* output: number of free inodes */
 	xfs_inofree_t		*free,	/* output: free inode mask */
-	int			*stat,	/* output: success/failure */
-	xfs_arch_t              arch)   /* input: architecture */
+	int			*stat)	/* output: success/failure */
 {
 	xfs_inobt_block_t	*block;	/* btree block */
 	xfs_buf_t		*bp;	/* buffer containing btree block */
@@ -1830,16 +1829,9 @@ xfs_inobt_get_rec(
 	 * Point to the record and extract its data.
 	 */
 	rec = XFS_INOBT_REC_ADDR(block, ptr, cur);
-	ASSERT(arch == ARCH_NOCONVERT || arch == ARCH_CONVERT);
-	if (arch == ARCH_NOCONVERT) {
-	    *ino = INT_GET(rec->ir_startino, ARCH_CONVERT);
-	    *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT);
-	    *free = INT_GET(rec->ir_free, ARCH_CONVERT);
-	} else {
-	    INT_COPY(*ino, rec->ir_startino, ARCH_CONVERT);
-	    INT_COPY(*fcnt, rec->ir_freecount, ARCH_CONVERT);
-	    INT_COPY(*free, rec->ir_free, ARCH_CONVERT);
-	}
+	*ino = INT_GET(rec->ir_startino, ARCH_CONVERT);
+	*fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT);
+	*free = INT_GET(rec->ir_free, ARCH_CONVERT);
 	*stat = 1;
 	return 0;
 }
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h
--- a/fs/xfs/xfs_ialloc_btree.h
+++ b/fs/xfs/xfs_ialloc_btree.h
@@ -99,23 +99,22 @@ xfs_inofree_t xfs_inobt_mask(int i);
 #define	XFS_INOBT_MASK(i)		((xfs_inofree_t)1 << (i))
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE)
-int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch);
-#define	XFS_INOBT_IS_FREE(rp,i,arch)	xfs_inobt_is_free(rp,i,arch)
+int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i);
+#define	XFS_INOBT_IS_FREE(rp,i)	xfs_inobt_is_free(rp,i)
 #else
-#define	XFS_INOBT_IS_FREE(rp,i,arch)	((INT_GET((rp)->ir_free, arch) \
-					 & XFS_INOBT_MASK(i)) != 0)
+#define	XFS_INOBT_IS_FREE(rp,i)	(((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE)
-void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch);
-#define	XFS_INOBT_SET_FREE(rp,i,arch)	xfs_inobt_set_free(rp,i,arch)
+void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i);
+#define	XFS_INOBT_SET_FREE(rp,i)	xfs_inobt_set_free(rp,i)
 #else
-#define	XFS_INOBT_SET_FREE(rp,i,arch)	(INT_MOD_EXPR((rp)->ir_free, arch, |= XFS_INOBT_MASK(i)))
+#define	XFS_INOBT_SET_FREE(rp,i)	((rp)->ir_free |= XFS_INOBT_MASK(i))
 #endif
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_CLR_FREE)
-void xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch);
-#define	XFS_INOBT_CLR_FREE(rp,i,arch)	xfs_inobt_clr_free(rp,i,arch)
+void xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i);
+#define	XFS_INOBT_CLR_FREE(rp,i)	xfs_inobt_clr_free(rp,i)
 #else
-#define	XFS_INOBT_CLR_FREE(rp,i,arch)	(INT_MOD_EXPR((rp)->ir_free, arch, &= ~XFS_INOBT_MASK(i)))
+#define	XFS_INOBT_CLR_FREE(rp,i)	((rp)->ir_free &= ~XFS_INOBT_MASK(i))
 #endif
 
 /*
@@ -244,8 +243,7 @@ xfs_inobt_get_rec(
 	xfs_agino_t		*ino,	/* output: starting inode of chunk */
 	__int32_t		*fcnt,	/* output: number of free inodes */
 	xfs_inofree_t		*free,	/* output: free inode mask */
-	int			*stat,	/* output: success/failure */
-	xfs_arch_t		arch);	/* output: architecture */
+	int			*stat);	/* output: success/failure */
 
 /*
  * Increment cursor by one record at the level.
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -61,7 +61,8 @@
  * Initialize the inode hash table for the newly mounted file system.
  * Choose an initial table size based on user specified value, else
  * use a simple algorithm using the maximum number of inodes as an
- * indicator for table size, and cap it at 16 pages (gettin' big).
+ * indicator for table size, and clamp it between one and some large
+ * number of pages.
  */
 void
 xfs_ihash_init(xfs_mount_t *mp)
@@ -72,8 +73,10 @@ xfs_ihash_init(xfs_mount_t *mp)
 	if (!mp->m_ihsize) {
 		icount = mp->m_maxicount ? mp->m_maxicount :
 			 (mp->m_sb.sb_dblocks << mp->m_sb.sb_inopblog);
-		mp->m_ihsize = 1 << max_t(uint, xfs_highbit64(icount) / 3, 8);
-		mp->m_ihsize = min_t(uint, mp->m_ihsize, 16 * PAGE_SIZE);
+		mp->m_ihsize = 1 << max_t(uint, 8,
+					(xfs_highbit64(icount) + 1) / 2);
+		mp->m_ihsize = min_t(uint, mp->m_ihsize,
+					(64 * NBPP) / sizeof(xfs_ihash_t));
 	}
 
 	while (!(mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize *
@@ -133,6 +136,40 @@ xfs_chash_free(xfs_mount_t *mp)
 }
 
 /*
+ * Try to move an inode to the front of its hash list if possible
+ * (and if its not there already).  Called right after obtaining
+ * the list version number and then dropping the read_lock on the
+ * hash list in question (which is done right after looking up the
+ * inode in question...).
+ */
+STATIC void
+xfs_ihash_promote(
+	xfs_ihash_t	*ih,
+	xfs_inode_t	*ip,
+	ulong		version)
+{
+	xfs_inode_t	*iq;
+
+	if ((ip->i_prevp != &ih->ih_next) && write_trylock(&ih->ih_lock)) {
+		if (likely(version == ih->ih_version)) {
+			/* remove from list */
+			if ((iq = ip->i_next)) {
+				iq->i_prevp = ip->i_prevp;
+			}
+			*ip->i_prevp = iq;
+
+			/* insert at list head */
+			iq = ih->ih_next;
+			iq->i_prevp = &ip->i_next;
+			ip->i_next = iq;
+			ip->i_prevp = &ih->ih_next;
+			ih->ih_next = ip;
+		}
+		write_unlock(&ih->ih_lock);
+	}
+}
+
+/*
  * Look up an inode by number in the given file system.
  * The inode is looked up in the hash table for the file system
  * represented by the mount point parameter mp.  Each bucket of
@@ -226,7 +263,9 @@ again:
 				XFS_STATS_INC(xs_ig_found);
 
 				ip->i_flags &= ~XFS_IRECLAIMABLE;
+				version = ih->ih_version;
 				read_unlock(&ih->ih_lock);
+				xfs_ihash_promote(ih, ip, version);
 
 				XFS_MOUNT_ILOCK(mp);
 				list_del_init(&ip->i_reclaim);
@@ -256,8 +295,15 @@ again:
 						inode_vp, vp);
 			}
 
+			/*
+			 * Inode cache hit: if ip is not at the front of
+			 * its hash chain, move it there now.
+			 * Do this with the lock held for update, but
+			 * do statistics after releasing the lock.
+			 */
+			version = ih->ih_version;
 			read_unlock(&ih->ih_lock);
-
+			xfs_ihash_promote(ih, ip, version);
 			XFS_STATS_INC(xs_ig_found);
 
 finish_inode:
@@ -490,6 +536,11 @@ inode_allocate:
 				goto retry;
 			}
 
+			if (is_bad_inode(inode)) {
+				iput(inode);
+				return EIO;
+			}
+
 			bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
 			if (bdp == NULL) {
 				XFS_STATS_INC(xs_ig_dup);
@@ -539,6 +590,7 @@ xfs_inode_incore(xfs_mount_t	*mp,
 {
 	xfs_ihash_t	*ih;
 	xfs_inode_t	*ip;
+	ulong		version;
 
 	ih = XFS_IHASH(mp, ino);
 	read_lock(&ih->ih_lock);
@@ -546,11 +598,15 @@ xfs_inode_incore(xfs_mount_t	*mp,
 		if (ip->i_ino == ino) {
 			/*
 			 * If we find it and tp matches, return it.
+			 * Also move it to the front of the hash list
+			 * if we find it and it is not already there.
 			 * Otherwise break from the loop and return
 			 * NULL.
 			 */
 			if (ip->i_transp == tp) {
+				version = ih->ih_version;
 				read_unlock(&ih->ih_lock);
+				xfs_ihash_promote(ih, ip, version);
 				return (ip);
 			}
 			break;
@@ -677,6 +733,7 @@ xfs_iextract(
 		iq->i_prevp = ip->i_prevp;
 	}
 	*ip->i_prevp = iq;
+	ih->ih_version++;
 	write_unlock(&ih->ih_lock);
 
 	/*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -135,11 +135,11 @@ xfs_inobp_check(
 	for (i = 0; i < j; i++) {
 		dip = (xfs_dinode_t *)xfs_buf_offset(bp,
 					i * mp->m_sb.sb_inodesize);
-		if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT))  {
+		if (!dip->di_next_unlinked)  {
 			xfs_fs_cmn_err(CE_ALERT, mp,
 				"Detected a bogus zero next_unlinked field in incore inode buffer 0x%p.  About to pop an ASSERT.",
 				bp);
-			ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT));
+			ASSERT(dip->di_next_unlinked);
 		}
 	}
 }
@@ -176,7 +176,7 @@ xfs_inobp_bwcheck(xfs_buf_t *bp)
 			xfs_fs_cmn_err(CE_WARN, mp,
 				"corrupt, unmount and run xfs_repair");
 		}
-		if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT))  {
+		if (!dip->di_next_unlinked)  {
 			cmn_err(CE_WARN,
 "Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x",
 				(__uint64_t)(__psunsigned_t) bp,
@@ -520,8 +520,7 @@ xfs_iformat(
 			}
 
 			di_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT);
-			if (unlikely(di_size >
-			    XFS_DFORK_DSIZE_ARCH(dip, ip->i_mount, ARCH_CONVERT))) {
+			if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
 				xfs_fs_cmn_err(CE_WARN, ip->i_mount,
 					"corrupt inode %Lu (bad size %Ld for local inode).  Unmount and run xfs_repair.",
 					(unsigned long long) ip->i_ino,
@@ -555,7 +554,7 @@ xfs_iformat(
 	if (error) {
 		return error;
 	}
-	if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT))
+	if (!XFS_DFORK_Q(dip))
 		return 0;
 	ASSERT(ip->i_afp == NULL);
 	ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
@@ -563,7 +562,7 @@ xfs_iformat(
 		XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
 	switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) {
 	case XFS_DINODE_FMT_LOCAL:
-		atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
+		atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
 		size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT);
 		error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
 		break;
@@ -610,11 +609,11 @@ xfs_iformat_local(
 	 * is wrong and we just bail out rather than crash in
 	 * kmem_alloc() or memcpy() below.
 	 */
-	if (unlikely(size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT))) {
+	if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
 		xfs_fs_cmn_err(CE_WARN, ip->i_mount,
 			"corrupt inode %Lu (bad size %d for local fork, size = %d).  Unmount and run xfs_repair.",
 			(unsigned long long) ip->i_ino, size,
-			XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT));
+			XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
 		XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
 				     ip->i_mount, dip);
 		return XFS_ERROR(EFSCORRUPTED);
@@ -632,8 +631,7 @@ xfs_iformat_local(
 	ifp->if_bytes = size;
 	ifp->if_real_bytes = real_size;
 	if (size)
-		memcpy(ifp->if_u1.if_data,
-			XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), size);
+		memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
 	ifp->if_flags &= ~XFS_IFEXTENTS;
 	ifp->if_flags |= XFS_IFINLINE;
 	return 0;
@@ -662,7 +660,7 @@ xfs_iformat_extents(
 	int		i;
 
 	ifp = XFS_IFORK_PTR(ip, whichfork);
-	nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT);
+	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
 	size = nex * (uint)sizeof(xfs_bmbt_rec_t);
 
 	/*
@@ -670,7 +668,7 @@ xfs_iformat_extents(
 	 * is wrong and we just bail out rather than crash in
 	 * kmem_alloc() or memcpy() below.
 	 */
-	if (unlikely(size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT))) {
+	if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
 		xfs_fs_cmn_err(CE_WARN, ip->i_mount,
 			"corrupt inode %Lu ((a)extents = %d).  Unmount and run xfs_repair.",
 			(unsigned long long) ip->i_ino, nex);
@@ -692,8 +690,7 @@ xfs_iformat_extents(
 	ifp->if_bytes = size;
 	ifp->if_real_bytes = real_size;
 	if (size) {
-		dp = (xfs_bmbt_rec_t *)
-			XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
+		dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
 		xfs_validate_extents(dp, nex, 1, XFS_EXTFMT_INODE(ip));
 		ep = ifp->if_u1.if_extents;
 		for (i = 0; i < nex; i++, ep++, dp++) {
@@ -739,7 +736,7 @@ xfs_iformat_btree(
 	int			size;
 
 	ifp = XFS_IFORK_PTR(ip, whichfork);
-	dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
+	dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
 	size = XFS_BMAP_BROOT_SPACE(dfp);
 	nrecs = XFS_BMAP_BROOT_NUMRECS(dfp);
 
@@ -752,7 +749,7 @@ xfs_iformat_btree(
 	 */
 	if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max
 	    || XFS_BMDR_SPACE_CALC(nrecs) >
-			XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)
+			XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)
 	    || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
 		xfs_fs_cmn_err(CE_WARN, ip->i_mount,
 			"corrupt inode %Lu (btree).  Unmount and run xfs_repair.",
@@ -769,7 +766,7 @@ xfs_iformat_btree(
 	 * Copy and convert from the on-disk structure
 	 * to the in-memory structure.
 	 */
-	xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT),
+	xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
 		ifp->if_broot, size);
 	ifp->if_flags &= ~XFS_IFEXTENTS;
 	ifp->if_flags |= XFS_IFBROOT;
@@ -785,29 +782,18 @@ xfs_iformat_btree(
  * dip  = native representation
  * dir  = direction - +ve -> disk to native
  *                    -ve -> native to disk
- * arch = on-disk architecture
  */
 void
 xfs_xlate_dinode_core(
 	xfs_caddr_t		buf,
 	xfs_dinode_core_t	*dip,
-	int			dir,
-	xfs_arch_t		arch)
+	int			dir)
 {
 	xfs_dinode_core_t	*buf_core = (xfs_dinode_core_t *)buf;
 	xfs_dinode_core_t	*mem_core = (xfs_dinode_core_t *)dip;
+	xfs_arch_t		arch = ARCH_CONVERT;
 
 	ASSERT(dir);
-	if (arch == ARCH_NOCONVERT) {
-		if (dir > 0) {
-			memcpy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core,
-				sizeof(xfs_dinode_core_t));
-		} else {
-			memcpy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core,
-				sizeof(xfs_dinode_core_t));
-		}
-		return;
-	}
 
 	INT_XLATE(buf_core->di_magic, mem_core->di_magic, dir, arch);
 	INT_XLATE(buf_core->di_mode, mem_core->di_mode, dir, arch);
@@ -854,16 +840,13 @@ xfs_xlate_dinode_core(
 	INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch);
 }
 
-uint
-xfs_dic2xflags(
+STATIC uint
+_xfs_dic2xflags(
 	xfs_dinode_core_t	*dic,
-	xfs_arch_t		arch)
+	__uint16_t		di_flags)
 {
-	__uint16_t		di_flags;
-	uint			flags;
+	uint			flags = 0;
 
-	di_flags = INT_GET(dic->di_flags, arch);
-	flags = XFS_CFORK_Q_ARCH(dic, arch) ? XFS_XFLAG_HASATTR : 0;
 	if (di_flags & XFS_DIFLAG_ANY) {
 		if (di_flags & XFS_DIFLAG_REALTIME)
 			flags |= XFS_XFLAG_REALTIME;
@@ -886,9 +869,28 @@ xfs_dic2xflags(
 		if (di_flags & XFS_DIFLAG_NOSYMLINKS)
 			flags |= XFS_XFLAG_NOSYMLINKS;
 	}
+
 	return flags;
 }
 
+uint
+xfs_ip2xflags(
+	xfs_inode_t		*ip)
+{
+	xfs_dinode_core_t	*dic = &ip->i_d;
+
+	return _xfs_dic2xflags(dic, dic->di_flags) |
+		(XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0);
+}
+
+uint
+xfs_dic2xflags(
+	xfs_dinode_core_t	*dic)
+{
+	return _xfs_dic2xflags(dic, INT_GET(dic->di_flags, ARCH_CONVERT)) |
+		(XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0);
+}
+
 /*
  * Given a mount structure and an inode number, return a pointer
  * to a newly allocated in-core inode coresponding to the given
@@ -974,9 +976,9 @@ xfs_iread(
 	 * specific information.
 	 * Otherwise, just get the truly permanent information.
 	 */
-	if (!INT_ISZERO(dip->di_core.di_mode, ARCH_CONVERT)) {
+	if (dip->di_core.di_mode) {
 		xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core,
-		     &(ip->i_d), 1, ARCH_CONVERT);
+		     &(ip->i_d), 1);
 		error = xfs_iformat(ip, dip);
 		if (error)  {
 			kmem_zone_free(xfs_inode_zone, ip);
@@ -1128,7 +1130,7 @@ xfs_ialloc(
 	xfs_trans_t	*tp,
 	xfs_inode_t	*pip,
 	mode_t		mode,
-	nlink_t		nlink,
+	xfs_nlink_t	nlink,
 	xfs_dev_t	rdev,
 	cred_t		*cr,
 	xfs_prid_t	prid,
@@ -1931,7 +1933,7 @@ xfs_iunlink(
 	agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
 	ASSERT(agino != 0);
 	bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
-	ASSERT(!INT_ISZERO(agi->agi_unlinked[bucket_index], ARCH_CONVERT));
+	ASSERT(agi->agi_unlinked[bucket_index]);
 	ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != agino);
 
 	if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO) {
@@ -1946,7 +1948,7 @@ xfs_iunlink(
 			return error;
 		}
 		ASSERT(INT_GET(dip->di_next_unlinked, ARCH_CONVERT) == NULLAGINO);
-		ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT));
+		ASSERT(dip->di_next_unlinked);
 		/* both on-disk, don't endian flip twice */
 		dip->di_next_unlinked = agi->agi_unlinked[bucket_index];
 		offset = ip->i_boffset +
@@ -2039,7 +2041,7 @@ xfs_iunlink_remove(
 	ASSERT(agino != 0);
 	bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
 	ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO);
-	ASSERT(!INT_ISZERO(agi->agi_unlinked[bucket_index], ARCH_CONVERT));
+	ASSERT(agi->agi_unlinked[bucket_index]);
 
 	if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) == agino) {
 		/*
@@ -3015,7 +3017,7 @@ xfs_iflush_fork(
 		ASSERT(whichfork == XFS_ATTR_FORK);
 		return 0;
 	}
-	cp = XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
+	cp = XFS_DFORK_PTR(dip, whichfork);
 	mp = ip->i_mount;
 	switch (XFS_IFORK_FORMAT(ip, whichfork)) {
 	case XFS_DINODE_FMT_LOCAL:
@@ -3056,7 +3058,7 @@ xfs_iflush_fork(
 				XFS_BROOT_SIZE_ADJ));
 			xfs_bmbt_to_bmdr(ifp->if_broot, ifp->if_broot_bytes,
 				(xfs_bmdr_block_t *)cp,
-				XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT));
+				XFS_DFORK_SIZE(dip, mp, whichfork));
 		}
 		break;
 
@@ -3474,8 +3476,7 @@ xfs_iflush_int(
 	 * because if the inode is dirty at all the core must
 	 * be.
 	 */
-	xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d),
-		-1, ARCH_CONVERT);
+	xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1);
 
 	/* Wrap, we never let the log put out DI_MAX_FLUSH */
 	if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
@@ -3505,7 +3506,7 @@ xfs_iflush_int(
 			ip->i_d.di_version = XFS_DINODE_VERSION_2;
 			INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2);
 			ip->i_d.di_onlink = 0;
-			INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT);
+			dip->di_core.di_onlink = 0;
 			memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 			memset(&(dip->di_core.di_pad[0]), 0,
 			      sizeof(dip->di_core.di_pad));
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -495,12 +495,13 @@ int		xfs_itobp(struct xfs_mount *, struc
 int		xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
 			  xfs_inode_t **, xfs_daddr_t);
 int		xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
-int		xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t,
-			   xfs_dev_t, struct cred *, xfs_prid_t, int,
-			   struct xfs_buf **, boolean_t *, xfs_inode_t **);
+int		xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
+			   xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t,
+			   int, struct xfs_buf **, boolean_t *, xfs_inode_t **);
 void		xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *,
-					int, xfs_arch_t);
-uint		xfs_dic2xflags(struct xfs_dinode_core *, xfs_arch_t);
+					int);
+uint		xfs_ip2xflags(struct xfs_inode *);
+uint		xfs_dic2xflags(struct xfs_dinode_core *);
 int		xfs_ifree(struct xfs_trans *, xfs_inode_t *,
 			   struct xfs_bmap_free *);
 void		xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -339,7 +339,7 @@ xfs_inode_item_format(
 			nrecs = ip->i_df.if_bytes /
 				(uint)sizeof(xfs_bmbt_rec_t);
 			ASSERT(nrecs > 0);
-#if ARCH_CONVERT == ARCH_NOCONVERT
+#if __BYTE_ORDER == __BIG_ENDIAN
 			if (nrecs == ip->i_d.di_nextents) {
 				/*
 				 * There are no delayed allocation
@@ -467,7 +467,7 @@ xfs_inode_item_format(
 #endif
 			ASSERT(nrecs > 0);
 			ASSERT(nrecs == ip->i_d.di_anextents);
-#if ARCH_CONVERT == ARCH_NOCONVERT
+#if __BYTE_ORDER == __BIG_ENDIAN
 			/*
 			 * There are not delayed allocation extents
 			 * for attributes, so just point at the array.
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -278,7 +278,9 @@ phase2:
 	switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) {
 	case BMAPI_WRITE:
 		/* If we found an extent, return it */
-		if (nimaps && (imap.br_startblock != HOLESTARTBLOCK)) {
+		if (nimaps &&
+		    (imap.br_startblock != HOLESTARTBLOCK) && 
+		    (imap.br_startblock != DELAYSTARTBLOCK)) {
 			xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,
 					offset, count, iomapp, &imap, flags);
 			break;
@@ -308,7 +310,8 @@ phase2:
 			break;
 		}
 
-		error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps);
+		error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count,
+						 &imap, &nimaps);
 		break;
 	case BMAPI_UNWRITTEN:
 		lockmode = 0;
@@ -365,7 +368,7 @@ xfs_flush_space(
 int
 xfs_iomap_write_direct(
 	xfs_inode_t	*ip,
-	loff_t		offset,
+	xfs_off_t	offset,
 	size_t		count,
 	int		flags,
 	xfs_bmbt_irec_t *ret_imap,
@@ -541,7 +544,7 @@ error_out:
 int
 xfs_iomap_write_delay(
 	xfs_inode_t	*ip,
-	loff_t		offset,
+	xfs_off_t	offset,
 	size_t		count,
 	int		ioflag,
 	xfs_bmbt_irec_t *ret_imap,
@@ -746,6 +749,8 @@ write_map:
 int
 xfs_iomap_write_allocate(
 	xfs_inode_t	*ip,
+	xfs_off_t	offset,
+	size_t		count,
 	xfs_bmbt_irec_t *map,
 	int		*retmap)
 {
@@ -770,9 +775,9 @@ xfs_iomap_write_allocate(
 	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
 		return XFS_ERROR(error);
 
-	offset_fsb = map->br_startoff;
+	offset_fsb = XFS_B_TO_FSBT(mp, offset);
 	count_fsb = map->br_blockcount;
-	map_start_fsb = offset_fsb;
+	map_start_fsb = map->br_startoff;
 
 	XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
 
@@ -868,9 +873,9 @@ xfs_iomap_write_allocate(
 					imap[i].br_startoff,
 				        imap[i].br_blockcount,imap[i].br_state);
                         }
-			if ((map->br_startoff >= imap[i].br_startoff) &&
-			    (map->br_startoff < (imap[i].br_startoff +
-						 imap[i].br_blockcount))) {
+			if ((offset_fsb >= imap[i].br_startoff) &&
+			    (offset_fsb < (imap[i].br_startoff +
+					   imap[i].br_blockcount))) {
 				*map = imap[i];
 				*retmap = 1;
 				XFS_STATS_INC(xs_xstrat_quick);
@@ -883,9 +888,8 @@ xfs_iomap_write_allocate(
 		 * file, just surrounding data, try again.
 		 */
 		nimaps--;
-		offset_fsb = imap[nimaps].br_startoff +
-			     imap[nimaps].br_blockcount;
-		map_start_fsb = offset_fsb;
+		map_start_fsb = imap[nimaps].br_startoff +
+				imap[nimaps].br_blockcount;
 	}
 
 trans_cancel:
@@ -899,7 +903,7 @@ error0:
 int
 xfs_iomap_write_unwritten(
 	xfs_inode_t	*ip,
-	loff_t		offset,
+	xfs_off_t	offset,
 	size_t		count)
 {
 	xfs_mount_t	*mp = ip->i_mount;
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003,2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -29,9 +29,6 @@
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-
-
-
 #ifndef __XFS_IOMAP_H__
 #define __XFS_IOMAP_H__
 
@@ -56,7 +53,7 @@ typedef enum {
 	BMAPI_UNWRITTEN  = (1 << 3),	/* unwritten extents to real extents */
 	/* modifiers */
 	BMAPI_IGNSTATE = (1 << 4),	/* ignore unwritten state on read */
-	BMAPI_DIRECT = (1 << 5),		/* direct instead of buffered write */
+	BMAPI_DIRECT = (1 << 5),	/* direct instead of buffered write */
 	BMAPI_MMAP = (1 << 6),		/* allocate for mmap write */
 	BMAPI_SYNC = (1 << 7),		/* sync write to flush delalloc space */
 	BMAPI_TRYLOCK = (1 << 8),	/* non-blocking request */
@@ -67,13 +64,13 @@ typedef enum {
 /*
  * xfs_iomap_t:  File system I/O map
  *
- * The iomap_bn field is expressed in 512-byte blocks, and is where the 
+ * The iomap_bn field is expressed in 512-byte blocks, and is where the
  * mapping starts on disk.
  *
  * The iomap_offset, iomap_bsize and iomap_delta fields are in bytes.
  * iomap_offset is the offset of the mapping in the file itself.
- * iomap_bsize is the size of the mapping,  iomap_delta is the 
- * desired data's offset into the mapping, given the offset supplied 
+ * iomap_bsize is the size of the mapping,  iomap_delta is the
+ * desired data's offset into the mapping, given the offset supplied
  * to the file I/O map routine.
  *
  * When a request is made to read beyond the logical end of the object,
@@ -84,8 +81,8 @@ typedef enum {
 typedef struct xfs_iomap {
 	xfs_daddr_t		iomap_bn;	/* first 512b blk of mapping */
 	xfs_buftarg_t		*iomap_target;
-	loff_t			iomap_offset;	/* offset of mapping, bytes */
-	loff_t			iomap_bsize;	/* size of mapping, bytes */
+	xfs_off_t		iomap_offset;	/* offset of mapping, bytes */
+	xfs_off_t		iomap_bsize;	/* size of mapping, bytes */
 	size_t			iomap_delta;	/* offset into mapping, bytes */
 	iomap_flags_t		iomap_flags;
 } xfs_iomap_t;
@@ -96,12 +93,12 @@ struct xfs_bmbt_irec;
 
 extern int xfs_iomap(struct xfs_iocore *, xfs_off_t, ssize_t, int,
 		     struct xfs_iomap *, int *);
-extern int xfs_iomap_write_direct(struct xfs_inode *, loff_t, size_t,
+extern int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t,
 				  int, struct xfs_bmbt_irec *, int *, int);
-extern int xfs_iomap_write_delay(struct xfs_inode *, loff_t, size_t, int,
+extern int xfs_iomap_write_delay(struct xfs_inode *, xfs_off_t, size_t, int,
 				 struct xfs_bmbt_irec *, int *);
-extern int xfs_iomap_write_allocate(struct xfs_inode *,
+extern int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, size_t,
 				struct xfs_bmbt_irec *, int *);
-extern int xfs_iomap_write_unwritten(struct xfs_inode *, loff_t, size_t);
+extern int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, size_t);
 
 #endif /* __XFS_IOMAP_H__*/
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -60,128 +60,137 @@
 #define unuseracc(ubuffer, size, flags)
 #endif
 
-/*
- * Return stat information for one inode.
- * Return 0 if ok, else errno.
- */
-int		       		/* error status */
-xfs_bulkstat_one(
+STATIC int
+xfs_bulkstat_one_iget(
 	xfs_mount_t	*mp,		/* mount point for filesystem */
 	xfs_ino_t	ino,		/* inode number to get data for */
-	void		__user *buffer,	/* buffer to place output in */
-	int		ubsize,		/* size of buffer */
-	void		*private_data,	/* my private data */
 	xfs_daddr_t	bno,		/* starting bno of inode cluster */
-	int		*ubused,	/* bytes used by me */
-	void		*dibuff,	/* on-disk inode buffer */
+	xfs_bstat_t	*buf,		/* return buffer */
 	int		*stat)		/* BULKSTAT_RV_... */
 {
-	xfs_bstat_t	*buf;		/* return buffer */
-	int		error;		/* error value */
-	xfs_dinode_t	*dip;		/* dinode inode pointer */
 	xfs_dinode_core_t *dic;		/* dinode core info pointer */
-	xfs_inode_t	*ip = NULL;	/* incore inode pointer */
-	xfs_arch_t      arch;           /* these are set according to      */
-
-	dip = (xfs_dinode_t *)dibuff;
+	xfs_inode_t	*ip;		/* incore inode pointer */
+	int		error;
 
-	if (!buffer || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
-	    (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
-	     (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) {
+	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
+	if (error) {
 		*stat = BULKSTAT_RV_NOTHING;
-		return XFS_ERROR(EINVAL);
+		return error;
 	}
-	if (ubsize < sizeof(*buf)) {
+
+	ASSERT(ip != NULL);
+	ASSERT(ip->i_blkno != (xfs_daddr_t)0);
+	if (ip->i_d.di_mode == 0) {
 		*stat = BULKSTAT_RV_NOTHING;
-		return XFS_ERROR(ENOMEM);
+		error = XFS_ERROR(ENOENT);
+		goto out_iput;
 	}
 
-	buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
+	dic = &ip->i_d;
 
-	if (dip == NULL) {
-		/* We're not being passed a pointer to a dinode.  This happens
-		 * if BULKSTAT_FG_IGET is selected.  Do the iget.
-		 */
-		error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
-		if (error) {
-			*stat = BULKSTAT_RV_NOTHING;
-			return error;
-		}
-		ASSERT(ip != NULL);
-		ASSERT(ip->i_blkno != (xfs_daddr_t)0);
-		if (ip->i_d.di_mode == 0) {
-			xfs_iput_new(ip, XFS_ILOCK_SHARED);
-			*stat = BULKSTAT_RV_NOTHING;
-			kmem_free(buf, sizeof(*buf));
-			return XFS_ERROR(ENOENT);
-		}
-		dic = &ip->i_d;
-		arch = ARCH_NOCONVERT;		/* in-core! */
-		ASSERT(dic != NULL);
+	/* xfs_iget returns the following without needing
+	 * further change.
+	 */
+	buf->bs_nlink = dic->di_nlink;
+	buf->bs_projid = dic->di_projid;
+	buf->bs_ino = ino;
+	buf->bs_mode = dic->di_mode;
+	buf->bs_uid = dic->di_uid;
+	buf->bs_gid = dic->di_gid;
+	buf->bs_size = dic->di_size;
+	buf->bs_atime.tv_sec = dic->di_atime.t_sec;
+	buf->bs_atime.tv_nsec = dic->di_atime.t_nsec;
+	buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
+	buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
+	buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
+	buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
+	buf->bs_xflags = xfs_ip2xflags(ip);
+	buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
+	buf->bs_extents = dic->di_nextents;
+	buf->bs_gen = dic->di_gen;
+	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
+	buf->bs_dmevmask = dic->di_dmevmask;
+	buf->bs_dmstate = dic->di_dmstate;
+	buf->bs_aextents = dic->di_anextents;
 
-		/* xfs_iget returns the following without needing
-		 * further change.
-		 */
-		buf->bs_nlink = dic->di_nlink;
-		buf->bs_projid = dic->di_projid;
+	switch (dic->di_format) {
+	case XFS_DINODE_FMT_DEV:
+		buf->bs_rdev = ip->i_df.if_u2.if_rdev;
+		buf->bs_blksize = BLKDEV_IOSIZE;
+		buf->bs_blocks = 0;
+		break;
+	case XFS_DINODE_FMT_LOCAL:
+	case XFS_DINODE_FMT_UUID:
+		buf->bs_rdev = 0;
+		buf->bs_blksize = mp->m_sb.sb_blocksize;
+		buf->bs_blocks = 0;
+		break;
+	case XFS_DINODE_FMT_EXTENTS:
+	case XFS_DINODE_FMT_BTREE:
+		buf->bs_rdev = 0;
+		buf->bs_blksize = mp->m_sb.sb_blocksize;
+		buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;
+		break;
+	}
 
-	} else {
-		dic = &dip->di_core;
-		ASSERT(dic != NULL);
+ out_iput:
+	xfs_iput(ip, XFS_ILOCK_SHARED);
+	return error;
+}
 
-		/* buffer dinode_core is in on-disk arch */
-		arch = ARCH_CONVERT;
+STATIC int
+xfs_bulkstat_one_dinode(
+	xfs_mount_t	*mp,		/* mount point for filesystem */
+	xfs_ino_t	ino,		/* inode number to get data for */
+	xfs_dinode_t	*dip,		/* dinode inode pointer */
+	xfs_bstat_t	*buf)		/* return buffer */
+{
+	xfs_dinode_core_t *dic;		/* dinode core info pointer */
 
-		/*
-		 * The inode format changed when we moved the link count and
-		 * made it 32 bits long.  If this is an old format inode,
-		 * convert it in memory to look like a new one.  If it gets
-		 * flushed to disk we will convert back before flushing or
-		 * logging it.  We zero out the new projid field and the old link
-		 * count field.  We'll handle clearing the pad field (the remains
-		 * of the old uuid field) when we actually convert the inode to
-		 * the new format. We don't change the version number so that we
-		 * can distinguish this from a real new format inode.
-		 */
-		if (INT_GET(dic->di_version, arch) == XFS_DINODE_VERSION_1) {
-			buf->bs_nlink = INT_GET(dic->di_onlink, arch);
-			buf->bs_projid = 0;
-		}
-		else {
-			buf->bs_nlink = INT_GET(dic->di_nlink, arch);
-			buf->bs_projid = INT_GET(dic->di_projid, arch);
-		}
+	dic = &dip->di_core;
 
+	/*
+	 * The inode format changed when we moved the link count and
+	 * made it 32 bits long.  If this is an old format inode,
+	 * convert it in memory to look like a new one.  If it gets
+	 * flushed to disk we will convert back before flushing or
+	 * logging it.  We zero out the new projid field and the old link
+	 * count field.  We'll handle clearing the pad field (the remains
+	 * of the old uuid field) when we actually convert the inode to
+	 * the new format. We don't change the version number so that we
+	 * can distinguish this from a real new format inode.
+	 */
+	if (INT_GET(dic->di_version, ARCH_CONVERT) == XFS_DINODE_VERSION_1) {
+		buf->bs_nlink = INT_GET(dic->di_onlink, ARCH_CONVERT);
+		buf->bs_projid = 0;
+	} else {
+		buf->bs_nlink = INT_GET(dic->di_nlink, ARCH_CONVERT);
+		buf->bs_projid = INT_GET(dic->di_projid, ARCH_CONVERT);
 	}
 
 	buf->bs_ino = ino;
-	buf->bs_mode = INT_GET(dic->di_mode, arch);
-	buf->bs_uid = INT_GET(dic->di_uid, arch);
-	buf->bs_gid = INT_GET(dic->di_gid, arch);
-	buf->bs_size = INT_GET(dic->di_size, arch);
-	buf->bs_atime.tv_sec = INT_GET(dic->di_atime.t_sec, arch);
-	buf->bs_atime.tv_nsec = INT_GET(dic->di_atime.t_nsec, arch);
-	buf->bs_mtime.tv_sec = INT_GET(dic->di_mtime.t_sec, arch);
-	buf->bs_mtime.tv_nsec = INT_GET(dic->di_mtime.t_nsec, arch);
-	buf->bs_ctime.tv_sec = INT_GET(dic->di_ctime.t_sec, arch);
-	buf->bs_ctime.tv_nsec = INT_GET(dic->di_ctime.t_nsec, arch);
-	buf->bs_xflags = xfs_dic2xflags(dic, arch);
-	buf->bs_extsize = INT_GET(dic->di_extsize, arch) << mp->m_sb.sb_blocklog;
-	buf->bs_extents = INT_GET(dic->di_nextents, arch);
-	buf->bs_gen = INT_GET(dic->di_gen, arch);
+	buf->bs_mode = INT_GET(dic->di_mode, ARCH_CONVERT);
+	buf->bs_uid = INT_GET(dic->di_uid, ARCH_CONVERT);
+	buf->bs_gid = INT_GET(dic->di_gid, ARCH_CONVERT);
+	buf->bs_size = INT_GET(dic->di_size, ARCH_CONVERT);
+	buf->bs_atime.tv_sec = INT_GET(dic->di_atime.t_sec, ARCH_CONVERT);
+	buf->bs_atime.tv_nsec = INT_GET(dic->di_atime.t_nsec, ARCH_CONVERT);
+	buf->bs_mtime.tv_sec = INT_GET(dic->di_mtime.t_sec, ARCH_CONVERT);
+	buf->bs_mtime.tv_nsec = INT_GET(dic->di_mtime.t_nsec, ARCH_CONVERT);
+	buf->bs_ctime.tv_sec = INT_GET(dic->di_ctime.t_sec, ARCH_CONVERT);
+	buf->bs_ctime.tv_nsec = INT_GET(dic->di_ctime.t_nsec, ARCH_CONVERT);
+	buf->bs_xflags = xfs_dic2xflags(dic);
+	buf->bs_extsize = INT_GET(dic->di_extsize, ARCH_CONVERT) << mp->m_sb.sb_blocklog;
+	buf->bs_extents = INT_GET(dic->di_nextents, ARCH_CONVERT);
+	buf->bs_gen = INT_GET(dic->di_gen, ARCH_CONVERT);
 	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
-	buf->bs_dmevmask = INT_GET(dic->di_dmevmask, arch);
-	buf->bs_dmstate = INT_GET(dic->di_dmstate, arch);
-	buf->bs_aextents = INT_GET(dic->di_anextents, arch);
+	buf->bs_dmevmask = INT_GET(dic->di_dmevmask, ARCH_CONVERT);
+	buf->bs_dmstate = INT_GET(dic->di_dmstate, ARCH_CONVERT);
+	buf->bs_aextents = INT_GET(dic->di_anextents, ARCH_CONVERT);
 
-	switch (INT_GET(dic->di_format, arch)) {
+	switch (INT_GET(dic->di_format, ARCH_CONVERT)) {
 	case XFS_DINODE_FMT_DEV:
-		if ( ip ) {
-			buf->bs_rdev = ip->i_df.if_u2.if_rdev;
-		} else {
-			buf->bs_rdev = INT_GET(dip->di_u.di_dev, arch);
-		}
-
+		buf->bs_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT);
 		buf->bs_blksize = BLKDEV_IOSIZE;
 		buf->bs_blocks = 0;
 		break;
@@ -195,29 +204,72 @@ xfs_bulkstat_one(
 	case XFS_DINODE_FMT_BTREE:
 		buf->bs_rdev = 0;
 		buf->bs_blksize = mp->m_sb.sb_blocksize;
-		if ( ip ) {
-			buf->bs_blocks = INT_GET(dic->di_nblocks, arch) + ip->i_delayed_blks;
-		} else {
-			buf->bs_blocks = INT_GET(dic->di_nblocks, arch);
-		}
+		buf->bs_blocks = INT_GET(dic->di_nblocks, ARCH_CONVERT);
 		break;
 	}
 
-	if (ip) {
-		xfs_iput(ip, XFS_ILOCK_SHARED);
+	return 0;
+}
+
+/*
+ * Return stat information for one inode.
+ * Return 0 if ok, else errno.
+ */
+int		       		/* error status */
+xfs_bulkstat_one(
+	xfs_mount_t	*mp,		/* mount point for filesystem */
+	xfs_ino_t	ino,		/* inode number to get data for */
+	void		__user *buffer,	/* buffer to place output in */
+	int		ubsize,		/* size of buffer */
+	void		*private_data,	/* my private data */
+	xfs_daddr_t	bno,		/* starting bno of inode cluster */
+	int		*ubused,	/* bytes used by me */
+	void		*dibuff,	/* on-disk inode buffer */
+	int		*stat)		/* BULKSTAT_RV_... */
+{
+	xfs_bstat_t	*buf;		/* return buffer */
+	int		error = 0;	/* error value */
+	xfs_dinode_t	*dip;		/* dinode inode pointer */
+
+	dip = (xfs_dinode_t *)dibuff;
+
+	if (!buffer || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
+	    (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+	     (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) {
+		*stat = BULKSTAT_RV_NOTHING;
+		return XFS_ERROR(EINVAL);
+	}
+	if (ubsize < sizeof(*buf)) {
+		*stat = BULKSTAT_RV_NOTHING;
+		return XFS_ERROR(ENOMEM);
+	}
+
+	buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
+
+	if (dip == NULL) {
+		/* We're not being passed a pointer to a dinode.  This happens
+		 * if BULKSTAT_FG_IGET is selected.  Do the iget.
+		 */
+		error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat);
+		if (error)
+			goto out_free;
+	} else {
+		xfs_bulkstat_one_dinode(mp, ino, dip, buf);
 	}
 
 	if (copy_to_user(buffer, buf, sizeof(*buf)))  {
-		kmem_free(buf, sizeof(*buf));
 		*stat = BULKSTAT_RV_NOTHING;
-		return EFAULT;
+		error =  EFAULT;
+		goto out_free;
 	}
 
-	kmem_free(buf, sizeof(*buf));
 	*stat = BULKSTAT_RV_DIDONE;
 	if (ubused)
 		*ubused = sizeof(*buf);
-	return 0;
+
+ out_free:
+	kmem_free(buf, sizeof(*buf));
+	return error;
 }
 
 /*
@@ -352,7 +404,7 @@ xfs_bulkstat(
 			    tmp &&	/* lookup succeeded */
 					/* got the record, should always work */
 			    !(error = xfs_inobt_get_rec(cur, &gino, &gcnt,
-				    &gfree, &i, ARCH_NOCONVERT)) &&
+				    &gfree, &i)) &&
 			    i == 1 &&
 					/* this is the right chunk */
 			    agino < gino + XFS_INODES_PER_CHUNK &&
@@ -421,7 +473,7 @@ xfs_bulkstat(
 			 */
 			if (error ||
 			    (error = xfs_inobt_get_rec(cur, &gino, &gcnt,
-				    &gfree, &i, ARCH_NOCONVERT)) ||
+				    &gfree, &i)) ||
 			    i == 0) {
 				end_of_ag = 1;
 				break;
@@ -744,7 +796,7 @@ xfs_inumbers(
 			}
 		}
 		if ((error = xfs_inobt_get_rec(cur, &gino, &gcnt, &gfree,
-			&i, ARCH_NOCONVERT)) ||
+			&i)) ||
 		    i == 0) {
 			xfs_buf_relse(agbp);
 			agbp = NULL;
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -175,8 +175,8 @@ xlog_trace_loggrant(xlog_t *log, xlog_ti
 		     (void *)((unsigned long)log->l_grant_write_bytes),
 		     (void *)((unsigned long)log->l_curr_cycle),
 		     (void *)((unsigned long)log->l_curr_block),
-		     (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT)),
-		     (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)),
+		     (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn)),
+		     (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn)),
 		     (void *)string,
 		     (void *)((unsigned long)13),
 		     (void *)((unsigned long)14),
@@ -890,8 +890,8 @@ xlog_space_left(xlog_t *log, int cycle, 
 	int tail_bytes;
 	int tail_cycle;
 
-	tail_bytes = BBTOB(BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT));
-	tail_cycle = CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT);
+	tail_bytes = BBTOB(BLOCK_LSN(log->l_tail_lsn));
+	tail_cycle = CYCLE_LSN(log->l_tail_lsn);
 	if ((tail_cycle == cycle) && (bytes >= tail_bytes)) {
 		free_bytes = log->l_logsize - (bytes - tail_bytes);
 	} else if ((tail_cycle + 1) < cycle) {
@@ -1164,7 +1164,7 @@ xlog_alloc_log(xfs_mount_t	*mp,
 	log->l_flags	   |= XLOG_ACTIVE_RECOVERY;
 
 	log->l_prev_block  = -1;
-	ASSIGN_ANY_LSN(log->l_tail_lsn, 1, 0, ARCH_NOCONVERT);
+	ASSIGN_ANY_LSN_HOST(log->l_tail_lsn, 1, 0);
 	/* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */
 	log->l_last_sync_lsn = log->l_tail_lsn;
 	log->l_curr_cycle  = 1;	    /* 0 is bad since this is initial value */
@@ -1321,19 +1321,19 @@ xlog_grant_push_ail(xfs_mount_t	*mp,
     free_threshold = MAX(free_threshold, (log->l_logBBsize >> 2));
     free_threshold = MAX(free_threshold, 256);
     if (free_blocks < free_threshold) {
-	threshold_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) + free_threshold;
-	threshold_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT);
+	threshold_block = BLOCK_LSN(tail_lsn) + free_threshold;
+	threshold_cycle = CYCLE_LSN(tail_lsn);
 	if (threshold_block >= log->l_logBBsize) {
 	    threshold_block -= log->l_logBBsize;
 	    threshold_cycle += 1;
 	}
-	ASSIGN_ANY_LSN(threshold_lsn, threshold_cycle,
-		       threshold_block, ARCH_NOCONVERT);
+	ASSIGN_ANY_LSN_HOST(threshold_lsn, threshold_cycle,
+		       threshold_block);
 
 	/* Don't pass in an lsn greater than the lsn of the last
 	 * log record known to be on disk.
 	 */
-	if (XFS_LSN_CMP_ARCH(threshold_lsn, log->l_last_sync_lsn, ARCH_NOCONVERT) > 0)
+	if (XFS_LSN_CMP(threshold_lsn, log->l_last_sync_lsn) > 0)
 	    threshold_lsn = log->l_last_sync_lsn;
     }
     GRANT_UNLOCK(log, s);
@@ -1435,7 +1435,7 @@ xlog_sync(xlog_t		*log,
 	bp	    = iclog->ic_bp;
 	ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long)1);
 	XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2);
-	XFS_BUF_SET_ADDR(bp, BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT));
+	XFS_BUF_SET_ADDR(bp, BLOCK_LSN(INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)));
 
 	XFS_STATS_ADD(xs_log_blocks, BTOBB(count));
 
@@ -1728,9 +1728,9 @@ xlog_write(xfs_mount_t *	mp,
 		logop_head		= (xlog_op_header_t *)ptr;
 		INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid);
 		logop_head->oh_clientid = ticket->t_clientid;
-		INT_ZERO(logop_head->oh_len, ARCH_CONVERT);
+		logop_head->oh_len	= 0;
 		logop_head->oh_flags    = XLOG_START_TRANS;
-		INT_ZERO(logop_head->oh_res2, ARCH_CONVERT);
+		logop_head->oh_res2	= 0;
 		ticket->t_flags		&= ~XLOG_TIC_INITED;	/* clear bit */
 		record_cnt++;
 
@@ -1742,7 +1742,7 @@ xlog_write(xfs_mount_t *	mp,
 	    logop_head			= (xlog_op_header_t *)ptr;
 	    INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid);
 	    logop_head->oh_clientid	= ticket->t_clientid;
-	    INT_ZERO(logop_head->oh_res2, ARCH_CONVERT);
+	    logop_head->oh_res2		= 0;
 
 	    /* header copied directly */
 	    xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t));
@@ -1888,10 +1888,10 @@ xlog_state_clean_log(xlog_t *log)
 				 */
 				changed = 2;
 			}
-			INT_ZERO(iclog->ic_header.h_num_logops, ARCH_CONVERT);
+			iclog->ic_header.h_num_logops = 0;
 			memset(iclog->ic_header.h_cycle_data, 0,
 			      sizeof(iclog->ic_header.h_cycle_data));
-			INT_ZERO(iclog->ic_header.h_lsn, ARCH_CONVERT);
+			iclog->ic_header.h_lsn = 0;
 		} else if (iclog->ic_state == XLOG_STATE_ACTIVE)
 			/* do nothing */;
 		else
@@ -1948,7 +1948,7 @@ xlog_get_lowest_lsn(
 	    if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) {
 		lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT);
 		if ((lsn && !lowest_lsn) ||
-		    (XFS_LSN_CMP_ARCH(lsn, lowest_lsn, ARCH_NOCONVERT) < 0)) {
+		    (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) {
 			lowest_lsn = lsn;
 		}
 	    }
@@ -2049,10 +2049,9 @@ xlog_state_do_callback(
 
 				lowest_lsn = xlog_get_lowest_lsn(log);
 				if (lowest_lsn && (
-					XFS_LSN_CMP_ARCH(
+					XFS_LSN_CMP(
 						lowest_lsn,
-						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT),
-						ARCH_NOCONVERT
+						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)
 					)<0)) {
 					iclog = iclog->ic_next;
 					continue; /* Leave this iclog for
@@ -2068,10 +2067,9 @@ xlog_state_do_callback(
 				 * No one else can be here except us.
 				 */
 				s = GRANT_LOCK(log);
-				ASSERT(XFS_LSN_CMP_ARCH(
+				ASSERT(XFS_LSN_CMP(
 						log->l_last_sync_lsn,
-						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT),
-						ARCH_NOCONVERT
+						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)
 					)<=0);
 				log->l_last_sync_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT);
 				GRANT_UNLOCK(log, s);
@@ -2285,7 +2283,7 @@ restart:
 	if (log_offset == 0) {
 		ticket->t_curr_res -= log->l_iclog_hsize;
 		INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle);
-		ASSIGN_LSN(head->h_lsn, log, ARCH_CONVERT);
+		ASSIGN_LSN(head->h_lsn, log);
 		ASSERT(log->l_curr_block >= 0);
 	}
 
@@ -2427,9 +2425,9 @@ redo:
 	 * Otherwise, make sure that the cycles differ by exactly one and
 	 * check the byte count.
 	 */
-	if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) {
-		ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT));
-		ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT)));
+	if (CYCLE_LSN(tail_lsn) != log->l_grant_write_cycle) {
+		ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn));
+		ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn)));
 	}
 #endif
 	xlog_trace_loggrant(log, tic, "xlog_grant_log_space: exit");
@@ -2560,9 +2558,9 @@ redo:
 	XLOG_GRANT_ADD_SPACE(log, need_bytes, 'w'); /* we've got enough space */
 #ifdef DEBUG
 	tail_lsn = log->l_tail_lsn;
-	if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) {
-		ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT));
-		ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT)));
+	if (CYCLE_LSN(tail_lsn) != log->l_grant_write_cycle) {
+		ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn));
+		ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn)));
 	}
 #endif
 
@@ -3269,18 +3267,18 @@ xlog_verify_tail_lsn(xlog_t	    *log,
 {
     int blocks;
 
-    if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_cycle) {
+    if (CYCLE_LSN(tail_lsn) == log->l_prev_cycle) {
 	blocks =
-	    log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn, ARCH_NOCONVERT));
+	    log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn));
 	if (blocks < BTOBB(iclog->ic_offset)+BTOBB(log->l_iclog_hsize))
 	    xlog_panic("xlog_verify_tail_lsn: ran out of log space");
     } else {
-	ASSERT(CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)+1 == log->l_prev_cycle);
+	ASSERT(CYCLE_LSN(tail_lsn)+1 == log->l_prev_cycle);
 
-	if (BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_block)
+	if (BLOCK_LSN(tail_lsn) == log->l_prev_block)
 	    xlog_panic("xlog_verify_tail_lsn: tail wrapped");
 
-	blocks = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) - log->l_prev_block;
+	blocks = BLOCK_LSN(tail_lsn) - log->l_prev_block;
 	if (blocks < BTOBB(iclog->ic_offset) + 1)
 	    xlog_panic("xlog_verify_tail_lsn: ran out of log space");
     }
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -32,20 +32,12 @@
 #ifndef	__XFS_LOG_H__
 #define __XFS_LOG_H__
 
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define LSN_FIELD_CYCLE(arch) (((arch)==ARCH_NOCONVERT)?1:0)
-#define LSN_FIELD_BLOCK(arch) (((arch)==ARCH_NOCONVERT)?0:1)
-#else
-#define LSN_FIELD_CYCLE(arch) (0)
-#define LSN_FIELD_BLOCK(arch) (1)
-#endif
-
 /* get lsn fields */
 
-#define CYCLE_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch))
-#define BLOCK_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch))
+#define CYCLE_LSN(lsn) ((uint)((lsn)>>32))
+#define BLOCK_LSN(lsn) ((uint)(lsn))
 /* this is used in a spot where we might otherwise double-endian-flip */
-#define CYCLE_LSN_NOCONV(lsn,arch) (((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)])
+#define CYCLE_LSN_DISK(lsn) (((uint *)&(lsn))[0])
 
 #ifdef __KERNEL__
 /*
@@ -58,21 +50,18 @@ __attribute__((unused))	/* gcc 2.95, 2.9
 #else
 __inline__
 #endif
-xfs_lsn_t	_lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2, xfs_arch_t arch)
+xfs_lsn_t	_lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 {
-	if (CYCLE_LSN(lsn1, arch) != CYCLE_LSN(lsn2, arch))
-		return (CYCLE_LSN(lsn1, arch)<CYCLE_LSN(lsn2, arch))? -999 : 999;
+	if (CYCLE_LSN(lsn1) != CYCLE_LSN(lsn2))
+		return (CYCLE_LSN(lsn1)<CYCLE_LSN(lsn2))? -999 : 999;
 
-	if (BLOCK_LSN(lsn1, arch) != BLOCK_LSN(lsn2, arch))
-		return (BLOCK_LSN(lsn1, arch)<BLOCK_LSN(lsn2, arch))? -999 : 999;
+	if (BLOCK_LSN(lsn1) != BLOCK_LSN(lsn2))
+		return (BLOCK_LSN(lsn1)<BLOCK_LSN(lsn2))? -999 : 999;
 
 	return 0;
 }
 
-#define	XFS_LSN_CMP_ARCH(x,y,arch)	_lsn_cmp(x, y, arch)
-#define	XFS_LSN_CMP(x,y) XFS_LSN_CMP_ARCH(x,y,ARCH_NOCONVERT)
-#define	XFS_LSN_DIFF_ARCH(x,y,arch)	_lsn_cmp(x, y, arch)
-#define	XFS_LSN_DIFF(x,y) XFS_LSN_DIFF_ARCH(x,y,ARCH_NOCONVERT)
+#define	XFS_LSN_CMP(x,y) _lsn_cmp(x,y)
 
 /*
  * Macros, structures, prototypes for interface to the log manager.
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -74,17 +74,17 @@ struct xfs_mount;
  *  set lsns
  */
 
-#define ASSIGN_LSN_CYCLE(lsn,cycle,arch) \
-    INT_SET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch, (cycle));
-#define ASSIGN_LSN_BLOCK(lsn,block,arch) \
-    INT_SET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch, (block));
-#define ASSIGN_ANY_LSN(lsn,cycle,block,arch)  \
+#define ASSIGN_ANY_LSN_HOST(lsn,cycle,block)  \
     { \
-	ASSIGN_LSN_CYCLE(lsn,cycle,arch); \
-	ASSIGN_LSN_BLOCK(lsn,block,arch); \
+	(lsn) = ((xfs_lsn_t)(cycle)<<32)|(block); \
     }
-#define ASSIGN_LSN(lsn,log,arch) \
-    ASSIGN_ANY_LSN(lsn,(log)->l_curr_cycle,(log)->l_curr_block,arch);
+#define ASSIGN_ANY_LSN_DISK(lsn,cycle,block)  \
+    { \
+	INT_SET(((uint *)&(lsn))[0], ARCH_CONVERT, (cycle)); \
+	INT_SET(((uint *)&(lsn))[1], ARCH_CONVERT, (block)); \
+    }
+#define ASSIGN_LSN(lsn,log) \
+    ASSIGN_ANY_LSN_DISK(lsn,(log)->l_curr_cycle,(log)->l_curr_block);
 
 #define XLOG_SET(f,b)		(((f) & (b)) == (b))
 
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -873,7 +873,7 @@ xlog_find_tail(
 
 	/* find blk_no of tail of log */
 	rhead = (xlog_rec_header_t *)offset;
-	*tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT);
+	*tail_blk = BLOCK_LSN(INT_GET(rhead->h_tail_lsn, ARCH_CONVERT));
 
 	/*
 	 * Reset log values according to the state of the log when we
@@ -940,10 +940,10 @@ xlog_find_tail(
 			 * log records will point recovery to after the
 			 * current unmount record.
 			 */
-			ASSIGN_ANY_LSN(log->l_tail_lsn, log->l_curr_cycle,
-					after_umount_blk, ARCH_NOCONVERT);
-			ASSIGN_ANY_LSN(log->l_last_sync_lsn, log->l_curr_cycle,
-					after_umount_blk, ARCH_NOCONVERT);
+			ASSIGN_ANY_LSN_HOST(log->l_tail_lsn, log->l_curr_cycle,
+					after_umount_blk);
+			ASSIGN_ANY_LSN_HOST(log->l_last_sync_lsn, log->l_curr_cycle,
+					after_umount_blk);
 			*tail_blk = after_umount_blk;
 		}
 	}
@@ -1110,8 +1110,8 @@ xlog_add_record(
 	INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);
 	INT_SET(recp->h_version, ARCH_CONVERT,
 			XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1);
-	ASSIGN_ANY_LSN(recp->h_lsn, cycle, block, ARCH_CONVERT);
-	ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT);
+	ASSIGN_ANY_LSN_DISK(recp->h_lsn, cycle, block);
+	ASSIGN_ANY_LSN_DISK(recp->h_tail_lsn, tail_cycle, tail_block);
 	INT_SET(recp->h_fmt, ARCH_CONVERT, XLOG_FMT);
 	memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t));
 }
@@ -1217,8 +1217,8 @@ xlog_clear_stale_blocks(
 	int		distance;
 	int		error;
 
-	tail_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT);
-	tail_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT);
+	tail_cycle = CYCLE_LSN(tail_lsn);
+	tail_block = BLOCK_LSN(tail_lsn);
 	head_cycle = log->l_curr_cycle;
 	head_block = log->l_curr_block;
 
@@ -2047,11 +2047,11 @@ xfs_qm_dqcheck(
 		errs++;
 	}
 
-	if (! errs && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
+	if (!errs && ddq->d_id) {
 		if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
 		    INT_GET(ddq->d_bcount, ARCH_CONVERT) >=
 				INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
-			if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT)) {
+			if (!ddq->d_btimer) {
 				if (flags & XFS_QMOPT_DOWARN)
 					cmn_err(CE_ALERT,
 					"%s : Dquot ID 0x%x (0x%p) "
@@ -2064,7 +2064,7 @@ xfs_qm_dqcheck(
 		if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
 		    INT_GET(ddq->d_icount, ARCH_CONVERT) >=
 				INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
-			if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT)) {
+			if (!ddq->d_itimer) {
 				if (flags & XFS_QMOPT_DOWARN)
 					cmn_err(CE_ALERT,
 					"%s : Dquot ID 0x%x (0x%p) "
@@ -2077,7 +2077,7 @@ xfs_qm_dqcheck(
 		if (INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT) &&
 		    INT_GET(ddq->d_rtbcount, ARCH_CONVERT) >=
 				INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT)) {
-			if (INT_ISZERO(ddq->d_rtbtimer, ARCH_CONVERT)) {
+			if (!ddq->d_rtbtimer) {
 				if (flags & XFS_QMOPT_DOWARN)
 					cmn_err(CE_ALERT,
 					"%s : Dquot ID 0x%x (0x%p) "
@@ -2452,8 +2452,8 @@ xlog_recover_do_inode_trans(
 
 	/* The core is in in-core format */
 	xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core,
-			      (xfs_dinode_core_t*)item->ri_buf[1].i_addr,
-			      -1, ARCH_CONVERT);
+			      (xfs_dinode_core_t*)item->ri_buf[1].i_addr, -1);
+
 	/* the rest is in on-disk format */
 	if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) {
 		memcpy((xfs_caddr_t) dip + sizeof(xfs_dinode_core_t),
@@ -3395,7 +3395,7 @@ xlog_pack_data(
 
 	xlog_pack_data_checksum(log, iclog, size);
 
-	cycle_lsn = CYCLE_LSN_NOCONV(iclog->ic_header.h_lsn, ARCH_CONVERT);
+	cycle_lsn = CYCLE_LSN_DISK(iclog->ic_header.h_lsn);
 
 	dp = iclog->ic_datap;
 	for (i = 0; i < BTOBB(size) &&
@@ -3438,7 +3438,7 @@ xlog_unpack_data_checksum(
 		up++;
 	}
 	if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) {
-	    if (!INT_ISZERO(rhead->h_chksum, ARCH_CONVERT) ||
+	    if (rhead->h_chksum ||
 		((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) {
 		    cmn_err(CE_DEBUG,
 			"XFS: LogR chksum mismatch: was (0x%x) is (0x%x)",
@@ -3501,7 +3501,7 @@ xlog_valid_rec_header(
 		return XFS_ERROR(EFSCORRUPTED);
 	}
 	if (unlikely(
-	    (INT_ISZERO(rhead->h_version, ARCH_CONVERT) ||
+	    (!rhead->h_version ||
 	    (INT_GET(rhead->h_version, ARCH_CONVERT) &
 			(~XLOG_VERSION_OKBITS)) != 0))) {
 		xlog_warn("XFS: %s: unrecognised log version (%d).",
@@ -3894,7 +3894,7 @@ xlog_do_recover(
 
 	/* Convert superblock from on-disk format */
 	sbp = &log->l_mp->m_sb;
-	xfs_xlatesb(XFS_BUF_TO_SBP(bp), sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
+	xfs_xlatesb(XFS_BUF_TO_SBP(bp), sbp, 1, XFS_SB_ALL_BITS);
 	ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
 	ASSERT(XFS_SB_GOOD_VERSION(sbp));
 	xfs_buf_relse(bp);
@@ -4073,7 +4073,7 @@ xlog_recover_check_summary(
 	sbbp = xfs_getsb(mp, 0);
 #ifdef XFS_LOUD_RECOVERY
 	sbp = &mp->m_sb;
-	xfs_xlatesb(XFS_BUF_TO_SBP(sbbp), sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
+	xfs_xlatesb(XFS_BUF_TO_SBP(sbbp), sbp, 1, XFS_SB_ALL_BITS);
 	cmn_err(CE_NOTE,
 		"xlog_recover_check_summary: sb_icount %Lu itotal %Lu",
 		sbp->sb_icount, itotal);
diff --git a/fs/xfs/xfs_macros.c b/fs/xfs/xfs_macros.c
--- a/fs/xfs/xfs_macros.c
+++ b/fs/xfs/xfs_macros.c
@@ -705,9 +705,9 @@ xfs_buf_to_sbp(xfs_buf_t *bp)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_ASIZE)
 int
-xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch)
+xfs_cfork_asize_disk(xfs_dinode_core_t *dcp, xfs_mount_t *mp)
 {
-	return XFS_CFORK_ASIZE_ARCH(dcp, mp, arch);
+	return XFS_CFORK_ASIZE_DISK(dcp, mp);
 }
 int
 xfs_cfork_asize(xfs_dinode_core_t *dcp, xfs_mount_t *mp)
@@ -718,9 +718,9 @@ xfs_cfork_asize(xfs_dinode_core_t *dcp, 
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_BOFF)
 int
-xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch)
+xfs_cfork_boff_disk(xfs_dinode_core_t *dcp)
 {
-	return XFS_CFORK_BOFF_ARCH(dcp, arch);
+	return XFS_CFORK_BOFF_DISK(dcp);
 }
 int
 xfs_cfork_boff(xfs_dinode_core_t *dcp)
@@ -731,9 +731,9 @@ xfs_cfork_boff(xfs_dinode_core_t *dcp)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_DSIZE)
 int
-xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch)
+xfs_cfork_dsize_disk(xfs_dinode_core_t *dcp, xfs_mount_t *mp)
 {
-	return XFS_CFORK_DSIZE_ARCH(dcp, mp, arch);
+	return XFS_CFORK_DSIZE_DISK(dcp, mp);
 }
 int
 xfs_cfork_dsize(xfs_dinode_core_t *dcp, xfs_mount_t *mp)
@@ -744,11 +744,6 @@ xfs_cfork_dsize(xfs_dinode_core_t *dcp, 
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FMT_SET)
 void
-xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch)
-{
-	XFS_CFORK_FMT_SET_ARCH(dcp, w, n, arch);
-}
-void
 xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n)
 {
 	XFS_CFORK_FMT_SET(dcp, w, n);
@@ -757,11 +752,6 @@ xfs_cfork_fmt_set(xfs_dinode_core_t *dcp
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FORMAT)
 int
-xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch)
-{
-	return XFS_CFORK_FORMAT_ARCH(dcp, w, arch);
-}
-int
 xfs_cfork_format(xfs_dinode_core_t *dcp, int w)
 {
 	return XFS_CFORK_FORMAT(dcp, w);
@@ -770,11 +760,6 @@ xfs_cfork_format(xfs_dinode_core_t *dcp,
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXT_SET)
 void
-xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch)
-{
-	XFS_CFORK_NEXT_SET_ARCH(dcp, w, n, arch);
-}
-void
 xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n)
 {
 	XFS_CFORK_NEXT_SET(dcp, w, n);
@@ -783,9 +768,9 @@ xfs_cfork_next_set(xfs_dinode_core_t *dc
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXTENTS)
 int
-xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch)
+xfs_cfork_nextents_disk(xfs_dinode_core_t *dcp, int w)
 {
-	return XFS_CFORK_NEXTENTS_ARCH(dcp, w, arch);
+	return XFS_CFORK_NEXTENTS_DISK(dcp, w);
 }
 int
 xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w)
@@ -796,9 +781,9 @@ xfs_cfork_nextents(xfs_dinode_core_t *dc
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_Q)
 int
-xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch)
+xfs_cfork_q_disk(xfs_dinode_core_t *dcp)
 {
-	return XFS_CFORK_Q_ARCH(dcp, arch);
+	return XFS_CFORK_Q_DISK(dcp);
 }
 int
 xfs_cfork_q(xfs_dinode_core_t *dcp)
@@ -809,9 +794,9 @@ xfs_cfork_q(xfs_dinode_core_t *dcp)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_SIZE)
 int
-xfs_cfork_size_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w, xfs_arch_t arch)
+xfs_cfork_size_disk(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w)
 {
-	return XFS_CFORK_SIZE_ARCH(dcp, mp, w, arch);
+	return XFS_CFORK_SIZE_DISK(dcp, mp, w);
 }
 int
 xfs_cfork_size(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w)
@@ -896,11 +881,6 @@ xfs_daddr_to_fsb(xfs_mount_t *mp, xfs_da
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_APTR)
 char *
-xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch)
-{
-	return XFS_DFORK_APTR_ARCH(dip, arch);
-}
-char *
 xfs_dfork_aptr(xfs_dinode_t *dip)
 {
 	return XFS_DFORK_APTR(dip);
@@ -909,11 +889,6 @@ xfs_dfork_aptr(xfs_dinode_t *dip)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_ASIZE)
 int
-xfs_dfork_asize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch)
-{
-	return XFS_DFORK_ASIZE_ARCH(dip, mp, arch);
-}
-int
 xfs_dfork_asize(xfs_dinode_t *dip, xfs_mount_t *mp)
 {
 	return XFS_DFORK_ASIZE(dip, mp);
@@ -922,11 +897,6 @@ xfs_dfork_asize(xfs_dinode_t *dip, xfs_m
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_BOFF)
 int
-xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch)
-{
-	return XFS_DFORK_BOFF_ARCH(dip, arch);
-}
-int
 xfs_dfork_boff(xfs_dinode_t *dip)
 {
 	return XFS_DFORK_BOFF(dip);
@@ -935,11 +905,6 @@ xfs_dfork_boff(xfs_dinode_t *dip)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DPTR)
 char *
-xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch)
-{
-	return XFS_DFORK_DPTR_ARCH(dip, arch);
-}
-char *
 xfs_dfork_dptr(xfs_dinode_t *dip)
 {
 	return XFS_DFORK_DPTR(dip);
@@ -948,63 +913,14 @@ xfs_dfork_dptr(xfs_dinode_t *dip)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DSIZE)
 int
-xfs_dfork_dsize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch)
-{
-	return XFS_DFORK_DSIZE_ARCH(dip, mp, arch);
-}
-int
 xfs_dfork_dsize(xfs_dinode_t *dip, xfs_mount_t *mp)
 {
 	return XFS_DFORK_DSIZE(dip, mp);
 }
 #endif
 
-#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FMT_SET)
-void
-xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch)
-{
-	XFS_DFORK_FMT_SET_ARCH(dip, w, n, arch);
-}
-void
-xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n)
-{
-	XFS_DFORK_FMT_SET(dip, w, n);
-}
-#endif
-
-#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FORMAT)
-int
-xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch)
-{
-	return XFS_DFORK_FORMAT_ARCH(dip, w, arch);
-}
-int
-xfs_dfork_format(xfs_dinode_t *dip, int w)
-{
-	return XFS_DFORK_FORMAT(dip, w);
-}
-#endif
-
-#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXT_SET)
-void
-xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch)
-{
-	XFS_DFORK_NEXT_SET_ARCH(dip, w, n, arch);
-}
-void
-xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n)
-{
-	XFS_DFORK_NEXT_SET(dip, w, n);
-}
-#endif
-
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXTENTS)
 int
-xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch)
-{
-	return XFS_DFORK_NEXTENTS_ARCH(dip, w, arch);
-}
-int
 xfs_dfork_nextents(xfs_dinode_t *dip, int w)
 {
 	return XFS_DFORK_NEXTENTS(dip, w);
@@ -1013,11 +929,6 @@ xfs_dfork_nextents(xfs_dinode_t *dip, in
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_PTR)
 char *
-xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch)
-{
-	return XFS_DFORK_PTR_ARCH(dip, w, arch);
-}
-char *
 xfs_dfork_ptr(xfs_dinode_t *dip, int w)
 {
 	return XFS_DFORK_PTR(dip, w);
@@ -1026,11 +937,6 @@ xfs_dfork_ptr(xfs_dinode_t *dip, int w)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_Q)
 int
-xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch)
-{
-	return XFS_DFORK_Q_ARCH(dip, arch);
-}
-int
 xfs_dfork_q(xfs_dinode_t *dip)
 {
 	return XFS_DFORK_Q(dip);
@@ -1039,11 +945,6 @@ xfs_dfork_q(xfs_dinode_t *dip)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_SIZE)
 int
-xfs_dfork_size_arch(xfs_dinode_t *dip, xfs_mount_t *mp, int w, xfs_arch_t arch)
-{
-	return XFS_DFORK_SIZE_ARCH(dip, mp, w, arch);
-}
-int
 xfs_dfork_size(xfs_dinode_t *dip, xfs_mount_t *mp, int w)
 {
 	return XFS_DFORK_SIZE(dip, mp, w);
@@ -1108,11 +1009,6 @@ xfs_dir_sf_entsize_byname(int len)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_GET_DIRINO)
 void
-xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch)
-{
-	XFS_DIR_SF_GET_DIRINO_ARCH(from, to, arch);
-}
-void
 xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to)
 {
 	XFS_DIR_SF_GET_DIRINO(from, to);
@@ -1129,11 +1025,6 @@ xfs_dir_sf_nextentry(xfs_dir_sf_entry_t 
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_PUT_DIRINO)
 void
-xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch)
-{
-	XFS_DIR_SF_PUT_DIRINO_ARCH(from, to, arch);
-}
-void
 xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to)
 {
 	XFS_DIR_SF_PUT_DIRINO(from, to);
@@ -1142,9 +1033,9 @@ xfs_dir_sf_put_dirino(xfs_ino_t *from, x
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BLOCK_LEAF_P)
 xfs_dir2_leaf_entry_t *
-xfs_dir2_block_leaf_p_arch(xfs_dir2_block_tail_t *btp, xfs_arch_t arch)
+xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
 {
-	return XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch);
+	return XFS_DIR2_BLOCK_LEAF_P(btp);
 }
 #endif
 
@@ -1223,9 +1114,9 @@ xfs_dir2_data_entsize(int n)
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P)
 xfs_dir2_data_off_t *
-xfs_dir2_data_unused_tag_p_arch(xfs_dir2_data_unused_t *dup, xfs_arch_t arch)
+xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup)
 {
-	return XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch);
+	return XFS_DIR2_DATA_UNUSED_TAG_P(dup);
 }
 #endif
 
@@ -1298,9 +1189,9 @@ xfs_dir2_db_to_fdindex(xfs_mount_t *mp, 
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_LEAF_BESTS_P)
 xfs_dir2_data_off_t *
-xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch)
+xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
 {
-	return XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, arch);
+	return XFS_DIR2_LEAF_BESTS_P(ltp);
 }
 #endif
 
@@ -1346,17 +1237,17 @@ xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_INUMBER)
 xfs_intino_t
-xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, xfs_arch_t arch)
+xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from)
 {
-	return XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch);
+	return XFS_DIR2_SF_GET_INUMBER(sfp, from);
 }
 #endif
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_OFFSET)
 xfs_dir2_data_aoff_t
-xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_arch_t arch)
+xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep)
 {
-	return XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, arch);
+	return XFS_DIR2_SF_GET_OFFSET(sfep);
 }
 #endif
 
@@ -1386,17 +1277,17 @@ xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_INUMBER)
 void
-xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, xfs_dir2_inou_t *to, xfs_arch_t arch)
+xfs_dir2_sf_put_inumber(xfs_dir2_sf_t *sfp, xfs_ino_t *from, xfs_dir2_inou_t *to)
 {
-	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, from, to, arch);
+	XFS_DIR2_SF_PUT_INUMBER(sfp, from, to);
 }
 #endif
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_OFFSET)
 void
-xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off, xfs_arch_t arch)
+xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off)
 {
-	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, off, arch);
+	XFS_DIR2_SF_PUT_OFFSET(sfep, off);
 }
 #endif
 
@@ -1755,17 +1646,17 @@ xfs_inobt_block_size(int lev, xfs_btree_
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_CLR_FREE)
 void
-xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch)
+xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i)
 {
-	XFS_INOBT_CLR_FREE(rp, i, arch);
+	XFS_INOBT_CLR_FREE(rp, i);
 }
 #endif
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_FREE)
 int
-xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch)
+xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i)
 {
-	return XFS_INOBT_IS_FREE(rp, i, arch);
+	return XFS_INOBT_IS_FREE(rp, i);
 }
 #endif
 
@@ -1821,9 +1712,9 @@ xfs_inobt_rec_addr(xfs_inobt_block_t *bb
 
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_SET_FREE)
 void
-xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch)
+xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i)
 {
-	XFS_INOBT_SET_FREE(rp, i, arch);
+	XFS_INOBT_SET_FREE(rp, i);
 }
 #endif
 
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -65,8 +65,6 @@ STATIC void	xfs_mount_log_sbunit(xfs_mou
 STATIC int	xfs_uuid_mount(xfs_mount_t *);
 STATIC void	xfs_uuid_unmount(xfs_mount_t *mp);
 
-void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t);
-
 static struct {
     short offset;
     short type;     /* 0 = integer
@@ -303,6 +301,15 @@ xfs_mount_validate_sb(
 	}
 
 	/*
+	 * Version 1 directory format has never worked on Linux.
+	 */
+	if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) {
+		cmn_err(CE_WARN,
+	"XFS: Attempted to mount file system using version 1 directory format");
+		return XFS_ERROR(ENOSYS);
+	}
+
+	/*
 	 * Until this is fixed only page-sized or smaller data blocks work.
 	 */
 	if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
@@ -387,7 +394,6 @@ xfs_initialize_perag(xfs_mount_t *mp, xf
  *     sb         - a superblock
  *     dir        - conversion direction: <0 - convert sb to buf
  *                                        >0 - convert buf to sb
- *     arch       - architecture to read/write from/to buf
  *     fields     - which fields to copy (bitmask)
  */
 void
@@ -395,7 +401,6 @@ xfs_xlatesb(
 	void		*data,
 	xfs_sb_t	*sb,
 	int		dir,
-	xfs_arch_t	arch,
 	__int64_t	fields)
 {
 	xfs_caddr_t	buf_ptr;
@@ -420,9 +425,7 @@ xfs_xlatesb(
 
 		ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);
 
-		if (arch == ARCH_NOCONVERT ||
-		    size == 1 ||
-		    xfs_sb_info[f].type == 1) {
+		if (size == 1 || xfs_sb_info[f].type == 1) {
 			if (dir > 0) {
 				memcpy(mem_ptr + first, buf_ptr + first, size);
 			} else {
@@ -433,16 +436,16 @@ xfs_xlatesb(
 			case 2:
 				INT_XLATE(*(__uint16_t*)(buf_ptr+first),
 					  *(__uint16_t*)(mem_ptr+first),
-					  dir, arch);
+					  dir, ARCH_CONVERT);
 				break;
 			case 4:
 				INT_XLATE(*(__uint32_t*)(buf_ptr+first),
 					  *(__uint32_t*)(mem_ptr+first),
-					  dir, arch);
+					  dir, ARCH_CONVERT);
 				break;
 			case 8:
 				INT_XLATE(*(__uint64_t*)(buf_ptr+first),
-					  *(__uint64_t*)(mem_ptr+first), dir, arch);
+					  *(__uint64_t*)(mem_ptr+first), dir, ARCH_CONVERT);
 				break;
 			default:
 				ASSERT(0);
@@ -493,8 +496,7 @@ xfs_readsb(xfs_mount_t *mp)
 	 * But first do some basic consistency checking.
 	 */
 	sbp = XFS_BUF_TO_SBP(bp);
-	xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1,
-				ARCH_CONVERT, XFS_SB_ALL_BITS);
+	xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, XFS_SB_ALL_BITS);
 
 	error = xfs_mount_validate_sb(mp, &(mp->m_sb));
 	if (error) {
@@ -1227,7 +1229,7 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fi
 
 	/* translate/copy */
 
-	xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, ARCH_CONVERT, fields);
+	xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, fields);
 
 	/* find modified range */
 
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -210,15 +210,16 @@ typedef int		(*xfs_bmapi_t)(struct xfs_t
 				struct xfs_bmap_free *);
 typedef int		(*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *);
 typedef int		(*xfs_iomap_write_direct_t)(
-				void *, loff_t, size_t, int,
+				void *, xfs_off_t, size_t, int,
 				struct xfs_bmbt_irec *, int *, int);
 typedef int		(*xfs_iomap_write_delay_t)(
-				void *, loff_t, size_t, int,
+				void *, xfs_off_t, size_t, int,
 				struct xfs_bmbt_irec *, int *);
 typedef int		(*xfs_iomap_write_allocate_t)(
-				void *, struct xfs_bmbt_irec *, int *);
+				void *, xfs_off_t, size_t,
+				struct xfs_bmbt_irec *, int *);
 typedef int		(*xfs_iomap_write_unwritten_t)(
-				void *, loff_t, size_t);
+				void *, xfs_off_t, size_t);
 typedef uint		(*xfs_lck_map_shared_t)(void *);
 typedef void		(*xfs_lock_t)(void *, uint);
 typedef void		(*xfs_lock_demote_t)(void *, uint);
@@ -258,9 +259,9 @@ typedef struct xfs_ioops {
 #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \
 	(*(mp)->m_io_ops.xfs_iomap_write_delay) \
 		((io)->io_obj, offset, count, flags, mval, nmap)
-#define XFS_IOMAP_WRITE_ALLOCATE(mp, io, mval, nmap) \
+#define XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, mval, nmap) \
 	(*(mp)->m_io_ops.xfs_iomap_write_allocate) \
-		((io)->io_obj, mval, nmap)
+		((io)->io_obj, offset, count, mval, nmap)
 #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \
 	(*(mp)->m_io_ops.xfs_iomap_write_unwritten) \
 		((io)->io_obj, offset, count)
@@ -418,6 +419,8 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_IDELETE	0x00040000	/* delete empty inode clusters*/
 #define XFS_MOUNT_SWALLOC	0x00080000	/* turn on stripe width
 						 * allocation */
+#define XFS_MOUNT_IHASHSIZE	0x00100000	/* inode hash table size */
+#define XFS_MOUNT_DIRSYNC	0x00200000	/* synchronous directory ops */
 
 /*
  * Default minimum read and write sizes.
@@ -426,10 +429,10 @@ typedef struct xfs_mount {
 #define XFS_WRITEIO_LOG_LARGE	16
 
 /*
- * Max and min values for UIO and mount-option defined I/O sizes;
- * min value can't be less than a page.  Currently unused.
+ * Max and min values for mount-option defined I/O
+ * preallocation sizes.
  */
-#define XFS_MAX_IO_LOG		16	/* 64K */
+#define XFS_MAX_IO_LOG		30	/* 1G */
 #define XFS_MIN_IO_LOG		PAGE_SHIFT
 
 /*
@@ -554,8 +557,7 @@ extern void	xfs_freesb(xfs_mount_t *);
 extern void	xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
 extern int	xfs_syncsub(xfs_mount_t *, int, int, int *);
 extern xfs_agnumber_t	xfs_initialize_perag(xfs_mount_t *, xfs_agnumber_t);
-extern void	xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t,
-			__int64_t);
+extern void	xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t);
 
 extern struct vfsops xfs_vfsops;
 extern struct vnodeops xfs_vnodeops;
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -589,7 +589,7 @@ xfs_rename(
 	 * rename transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
--- a/fs/xfs/xfs_types.h
+++ b/fs/xfs/xfs_types.h
@@ -63,6 +63,7 @@ typedef __u64			xfs_ino_t;	/* <inode> ty
 typedef __s64			xfs_daddr_t;	/* <disk address> type */
 typedef char *			xfs_caddr_t;	/* <core address> type */
 typedef __u32			xfs_dev_t;
+typedef __u32			xfs_nlink_t;
 
 /* __psint_t is the same size as a pointer */
 #if (BITS_PER_LONG == 32)
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -147,7 +147,7 @@ xfs_dir_ialloc(
 	xfs_inode_t	*dp,		/* directory within whose allocate
 					   the inode. */
 	mode_t		mode,
-	nlink_t		nlink,
+	xfs_nlink_t	nlink,
 	xfs_dev_t	rdev,
 	cred_t		*credp,
 	prid_t		prid,		/* project id */
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
--- a/fs/xfs/xfs_utils.h
+++ b/fs/xfs/xfs_utils.h
@@ -42,7 +42,7 @@ extern int xfs_get_dir_entry (vname_t *,
 extern int xfs_dir_lookup_int (bhv_desc_t *, uint, vname_t *, xfs_ino_t *,
 				xfs_inode_t **);
 extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *);
-extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, nlink_t,
+extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
 				xfs_dev_t, cred_t *, prid_t, int,
 				xfs_inode_t **, int *);
 extern int xfs_droplink (xfs_trans_t *, xfs_inode_t *);
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -1,7 +1,7 @@
 /*
  * XFS filesystem operations.
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -258,11 +258,6 @@ xfs_start_flags(
 	mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP);
 	strcpy(mp->m_fsname, ap->fsname);
 
-	/*
-	 * Pull in the 'wsync' and 'ino64' mount options before we do the real
-	 * work of mounting and recovery.  The arg pointer will
-	 * be NULL when we are being called from the root mount code.
-	 */
 	if (ap->flags & XFSMNT_WSYNC)
 		mp->m_flags |= XFS_MOUNT_WSYNC;
 #if XFS_BIG_INUMS
@@ -302,9 +297,16 @@ xfs_start_flags(
 		mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
 		mp->m_readio_log = mp->m_writeio_log = ap->iosizelog;
 	}
+
+	if (ap->flags & XFSMNT_IHASHSIZE)
+		mp->m_flags |= XFS_MOUNT_IHASHSIZE;
+
 	if (ap->flags & XFSMNT_IDELETE)
 		mp->m_flags |= XFS_MOUNT_IDELETE;
 
+	if (ap->flags & XFSMNT_DIRSYNC)
+		mp->m_flags |= XFS_MOUNT_DIRSYNC;
+
 	/*
 	 * no recovery flag requires a read-only mount
 	 */
@@ -1647,6 +1649,7 @@ xfs_vget(
 #define MNTOPT_SWIDTH	"swidth"	/* data volume stripe width */
 #define MNTOPT_NOUUID	"nouuid"	/* ignore filesystem UUID */
 #define MNTOPT_MTPT	"mtpt"		/* filesystem mount point */
+#define MNTOPT_ALLOCSIZE    "allocsize"    /* preferred allocation size */
 #define MNTOPT_IHASHSIZE    "ihashsize"    /* size of inode hash table */
 #define MNTOPT_NORECOVERY   "norecovery"   /* don't run XFS recovery */
 #define MNTOPT_NOLOGFLUSH   "nologflush"   /* don't hard flush on log writes */
@@ -1655,6 +1658,28 @@ xfs_vget(
 #define MNTOPT_IKEEP	"ikeep"		/* do not free empty inode clusters */
 #define MNTOPT_NOIKEEP	"noikeep"	/* free empty inode clusters */
 
+STATIC unsigned long
+suffix_strtoul(const char *cp, char **endp, unsigned int base)
+{
+	int	last, shift_left_factor = 0;
+	char	*value = (char *)cp;
+
+	last = strlen(value) - 1;
+	if (value[last] == 'K' || value[last] == 'k') {
+		shift_left_factor = 10;
+		value[last] = '\0';
+	}
+	if (value[last] == 'M' || value[last] == 'm') {
+		shift_left_factor = 20;
+		value[last] = '\0';
+	}
+	if (value[last] == 'G' || value[last] == 'g') {
+		shift_left_factor = 30;
+		value[last] = '\0';
+	}
+
+	return simple_strtoul(cp, endp, base) << shift_left_factor;
+}
 
 int
 xfs_parseargs(
@@ -1686,62 +1711,63 @@ xfs_parseargs(
 		if (!strcmp(this_char, MNTOPT_LOGBUFS)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_LOGBUFS);
+					this_char);
 				return EINVAL;
 			}
 			args->logbufs = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
-			int	last, in_kilobytes = 0;
-
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_LOGBSIZE);
+					this_char);
 				return EINVAL;
 			}
-			last = strlen(value) - 1;
-			if (value[last] == 'K' || value[last] == 'k') {
-				in_kilobytes = 1;
-				value[last] = '\0';
-			}
-			args->logbufsize = simple_strtoul(value, &eov, 10);
-			if (in_kilobytes)
-				args->logbufsize <<= 10;
+			args->logbufsize = suffix_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_LOGDEV);
+					this_char);
 				return EINVAL;
 			}
 			strncpy(args->logname, value, MAXNAMELEN);
 		} else if (!strcmp(this_char, MNTOPT_MTPT)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_MTPT);
+					this_char);
 				return EINVAL;
 			}
 			strncpy(args->mtpt, value, MAXNAMELEN);
 		} else if (!strcmp(this_char, MNTOPT_RTDEV)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_RTDEV);
+					this_char);
 				return EINVAL;
 			}
 			strncpy(args->rtname, value, MAXNAMELEN);
 		} else if (!strcmp(this_char, MNTOPT_BIOSIZE)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_BIOSIZE); 
+					this_char);
 				return EINVAL;
 			}
 			iosize = simple_strtoul(value, &eov, 10);
 			args->flags |= XFSMNT_IOSIZE;
 			args->iosizelog = (uint8_t) iosize;
+		} else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					this_char);
+				return EINVAL;
+			}
+			iosize = suffix_strtoul(value, &eov, 10);
+			args->flags |= XFSMNT_IOSIZE;
+			args->iosizelog = ffs(iosize) - 1;
 		} else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					this_char); 
+					this_char);
 				return EINVAL;
 			}
+			args->flags |= XFSMNT_IHASHSIZE;
 			args->ihashsize = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_WSYNC)) {
 			args->flags |= XFSMNT_WSYNC;
@@ -1753,7 +1779,7 @@ xfs_parseargs(
 			args->flags |= XFSMNT_INO64;
 #if !XFS_BIG_INUMS
 			printk("XFS: %s option not allowed on this system\n",
-				MNTOPT_INO64);
+				this_char);
 			return EINVAL;
 #endif
 		} else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
@@ -1763,14 +1789,14 @@ xfs_parseargs(
 		} else if (!strcmp(this_char, MNTOPT_SUNIT)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_SUNIT);
+					this_char);
 				return EINVAL;
 			}
 			dsunit = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
-					MNTOPT_SWIDTH);
+					this_char);
 				return EINVAL;
 			}
 			dswidth = simple_strtoul(value, &eov, 10);
@@ -1778,7 +1804,7 @@ xfs_parseargs(
 			args->flags &= ~XFSMNT_32BITINODES;
 #if !XFS_BIG_INUMS
 			printk("XFS: %s option not allowed on this system\n",
-				MNTOPT_64BITINODE);
+				this_char);
 			return EINVAL;
 #endif
 		} else if (!strcmp(this_char, MNTOPT_NOUUID)) {
@@ -1870,8 +1896,11 @@ xfs_showargs(
 			seq_puts(m, xfs_infop->str);
 	}
 
+	if (mp->m_flags & XFS_MOUNT_IHASHSIZE)
+		seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", mp->m_ihsize);
+
 	if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
-		seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log);
+		seq_printf(m, "," MNTOPT_ALLOCSIZE "=%d", 1<<mp->m_writeio_log);
 
 	if (mp->m_logbufs > 0)
 		seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs);
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -248,7 +248,7 @@ xfs_getattr(
 	/*
 	 * Convert di_flags to xflags.
 	 */
-	vap->va_xflags = xfs_dic2xflags(&ip->i_d, ARCH_NOCONVERT);
+	vap->va_xflags = xfs_ip2xflags(ip);
 
 	/*
 	 * Exit for inode revalidate.  See if any of the rest of
@@ -305,7 +305,7 @@ xfs_setattr(
 	int			mandlock_before, mandlock_after;
 	struct xfs_dquot	*udqp, *gdqp, *olddquot1, *olddquot2;
 	int			file_owner;
-	int			need_iolock = (flags & ATTR_DMI) == 0;
+	int			need_iolock = 1;
 
 	vp = BHV_TO_VNODE(bdp);
 	vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -384,6 +384,9 @@ xfs_setattr(
 	 */
 	tp = NULL;
 	lock_flags = XFS_ILOCK_EXCL;
+	ASSERT(flags & ATTR_NOLOCK ? flags & ATTR_DMI : 1);
+	if (flags & ATTR_NOLOCK)
+		need_iolock = 0;
 	if (!(mask & XFS_AT_SIZE)) {
 		if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) ||
 		    (mp->m_flags & XFS_MOUNT_WSYNC)) {
@@ -1995,7 +1998,7 @@ xfs_create(
 	 * create transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -2492,7 +2495,7 @@ xfs_remove(
 	 * remove transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -2704,7 +2707,7 @@ xfs_link(
 	 * link transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -2921,7 +2924,7 @@ xfs_mkdir(
 	 * mkdir transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -3168,7 +3171,7 @@ xfs_rmdir(
 	 * rmdir transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -3520,7 +3523,7 @@ xfs_symlink(
 	 * symlink transaction goes to disk before returning to
 	 * the user.
 	 */
-	if (mp->m_flags & XFS_MOUNT_WSYNC) {
+	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 		xfs_trans_set_sync(tp);
 	}
 
@@ -4320,7 +4323,7 @@ xfs_free_file_space(
 	int			rt;
 	xfs_fileoff_t		startoffset_fsb;
 	xfs_trans_t		*tp;
-	int			need_iolock = (attr_flags & ATTR_DMI) == 0;
+	int			need_iolock = 1;
 
 	vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
 	mp = ip->i_mount;
@@ -4348,8 +4351,12 @@ xfs_free_file_space(
 			return(error);
 	}
 
+	ASSERT(attr_flags & ATTR_NOLOCK ? attr_flags & ATTR_DMI : 1);
+	if (attr_flags & ATTR_NOLOCK)
+		need_iolock = 0;
 	if (need_iolock)
 		xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
 	rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
 			(__uint8_t)NBPP);
 	ilen = len + (offset & (rounding - 1));
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20050211
+#define ACPI_CA_VERSION                 0x20050309
 
 /*
  * OS name, used for the _OS object.  The _OS object is essentially obsolete,
@@ -198,7 +198,7 @@
 
 /* Number of strings associated with the _OSI reserved method */
 
-#define ACPI_NUM_OSI_STRINGS            9
+#define ACPI_NUM_OSI_STRINGS            10
 
 
 /******************************************************************************
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -75,6 +75,11 @@ extern const char                       
 extern const char                       *acpi_gbl_TYPdecode[4];
 extern const char                       *acpi_gbl_BMdecode[2];
 extern const char                       *acpi_gbl_SIZdecode[4];
+extern const char                       *acpi_gbl_TTPdecode[2];
+extern const char                       *acpi_gbl_MTPdecode[4];
+extern const char                       *acpi_gbl_TRSdecode[2];
+
+
 extern const char                       *acpi_gbl_lock_rule[ACPI_NUM_LOCK_RULES];
 extern const char                       *acpi_gbl_access_types[ACPI_NUM_ACCESS_TYPES];
 extern const char                       *acpi_gbl_update_rules[ACPI_NUM_UPDATE_RULES];
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -374,6 +374,16 @@ acpi_ds_create_node (
 
 /* dsutils - Parser/Interpreter interface utility routines */
 
+void
+acpi_ds_clear_implicit_return (
+	struct acpi_walk_state          *walk_state);
+
+u8
+acpi_ds_do_implicit_return (
+	union acpi_operand_object       *return_desc,
+	struct acpi_walk_state          *walk_state,
+	u8                              add_reference);
+
 u8
 acpi_ds_is_result_used (
 	union acpi_parse_object         *op,
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -617,7 +617,6 @@ acpi_ex_store_object_to_object (
 
 acpi_status
 acpi_ex_store_buffer_to_buffer (
-	acpi_object_type                original_src_type,
 	union acpi_operand_object       *source_desc,
 	union acpi_operand_object       *target_desc);
 
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -774,6 +774,7 @@ struct acpi_bit_register_info
 #define ACPI_BITMASK_POWER_BUTTON_STATUS        0x0100
 #define ACPI_BITMASK_SLEEP_BUTTON_STATUS        0x0200
 #define ACPI_BITMASK_RT_CLOCK_STATUS            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_STATUS         0x4000    /* ACPI 3.0 */
 #define ACPI_BITMASK_WAKE_STATUS                0x8000
 
 #define ACPI_BITMASK_ALL_FIXED_STATUS           (ACPI_BITMASK_TIMER_STATUS          | \
@@ -789,6 +790,7 @@ struct acpi_bit_register_info
 #define ACPI_BITMASK_POWER_BUTTON_ENABLE        0x0100
 #define ACPI_BITMASK_SLEEP_BUTTON_ENABLE        0x0200
 #define ACPI_BITMASK_RT_CLOCK_ENABLE            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE        0x4000    /* ACPI 3.0 */
 
 #define ACPI_BITMASK_SCI_ENABLE                 0x0001
 #define ACPI_BITMASK_BUS_MASTER_RLD             0x0002
@@ -807,6 +809,7 @@ struct acpi_bit_register_info
 #define ACPI_BITPOSITION_POWER_BUTTON_STATUS    0x08
 #define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS    0x09
 #define ACPI_BITPOSITION_RT_CLOCK_STATUS        0x0A
+#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS     0x0E    /* ACPI 3.0 */
 #define ACPI_BITPOSITION_WAKE_STATUS            0x0F
 
 #define ACPI_BITPOSITION_TIMER_ENABLE           0x00
@@ -814,6 +817,7 @@ struct acpi_bit_register_info
 #define ACPI_BITPOSITION_POWER_BUTTON_ENABLE    0x08
 #define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE    0x09
 #define ACPI_BITPOSITION_RT_CLOCK_ENABLE        0x0A
+#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE    0x0E    /* ACPI 3.0 */
 
 #define ACPI_BITPOSITION_SCI_ENABLE             0x00
 #define ACPI_BITPOSITION_BUS_MASTER_RLD         0x01
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -328,7 +328,6 @@ int acpi_bus_receive_event (struct acpi_
 int acpi_bus_register_driver (struct acpi_driver *driver);
 int acpi_bus_unregister_driver (struct acpi_driver *driver);
 int acpi_bus_scan (struct acpi_device *start);
-int acpi_bus_trim(struct acpi_device *start, int rmdevice);
 int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent,
 		acpi_handle handle, int type);
 
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -56,7 +56,8 @@
 /* ACPI PCI Interrupt Link (pci_link.c) */
 
 int acpi_irq_penalty_init (void);
-int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low);
+int acpi_pci_link_get_irq (acpi_handle handle, int index, int *edge_level,
+	int *active_high_low, char **name);
 
 /* ACPI PCI Interrupt Routing (pci_irq.c) */
 
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -94,6 +94,7 @@ struct acpi_walk_state
 	union acpi_generic_state            *control_state;                     /* List of control states (nested IFs) */
 	struct acpi_namespace_node          *deferred_node;                     /* Used when executing deferred opcodes */
 	struct acpi_gpe_event_info          *gpe_event_info;                    /* Info for GPE (_Lxx/_Exx methods only */
+	union acpi_operand_object           *implicit_return_obj;
 	struct acpi_namespace_node          local_variables[ACPI_METHOD_NUM_LOCALS];    /* Control method locals */
 	struct acpi_namespace_node          *method_call_node;                  /* Called method Node*/
 	union acpi_parse_object             *method_call_op;                    /* method_call Op if running a method */
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -261,6 +261,8 @@ struct madt_local_sapic
 	u8                              local_sapic_eid;        /* SAPIC EID */
 	u8                              reserved [3];           /* Reserved - must be zero */
 	LOCAL_APIC_FLAGS
+	u32                             processor_uID;          /* Numeric UID - ACPI 3.0 */
+	char                            processor_uIDstring[1]; /* String UID  - ACPI 3.0 */
 };
 
 struct madt_interrupt_source
@@ -272,7 +274,7 @@ struct madt_interrupt_source
 	u8                              processor_eid;          /* Processor EID */
 	u8                              io_sapic_vector;        /* Vector value for PMI interrupts */
 	u32                             interrupt;              /* Global system interrupt */
-	u32                             reserved;               /* Reserved - must be zero */
+	u32                             flags;                  /* Interrupt Source Flags */
 };
 
 
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -108,7 +108,7 @@ struct facs_descriptor_rev2
 
 
 /*
- * ACPI 2.0 Generic Address Structure (GAS)
+ * ACPI 2.0+ Generic Address Structure (GAS)
  */
 struct acpi_generic_address
 {
@@ -159,7 +159,7 @@ struct acpi_generic_address
 	u16                             iapc_boot_arch;     /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/
 
 /*
- * ACPI 2.0 Fixed ACPI Description Table (FADT)
+ * ACPI 2.0+ Fixed ACPI Description Table (FADT)
  */
 struct fadt_descriptor_rev2
 {
@@ -174,17 +174,25 @@ struct fadt_descriptor_rev2
 	u32                             sleep_button : 1;   /* Sleep button is handled as a generic feature, or not present */
 	u32                             fixed_rTC   : 1;    /* RTC wakeup stat not in fixed register space */
 	u32                             rtcs4       : 1;    /* RTC wakeup stat not possible from S4 */
-	u32                             tmr_val_ext : 1;    /* Indicates tmr_val is 32 bits 0=24-bits*/
+	u32                             tmr_val_ext : 1;    /* Indicates tmr_val is 32 bits 0=24-bits */
 	u32                             dock_cap    : 1;    /* Supports Docking */
-	u32                             reset_reg_sup : 1;  /* Indicates system supports system reset via the FADT RESET_REG*/
-	u32                             sealed_case : 1;    /* Indicates system has no internal expansion capabilities and case is sealed. */
-	u32                             headless    : 1;    /* Indicates system does not have local video capabilities or local input devices.*/
+	u32                             reset_reg_sup : 1;  /* Indicates system supports system reset via the FADT RESET_REG */
+	u32                             sealed_case : 1;    /* Indicates system has no internal expansion capabilities and case is sealed */
+	u32                             headless    : 1;    /* Indicates system does not have local video capabilities or local input devices */
 	u32                             cpu_sw_sleep : 1;   /* Indicates to OSPM that a processor native instruction */
-			   /* Must be executed after writing the SLP_TYPx register. */
-	u32                             reserved6   : 18;   /* Reserved - must be zero */
+			   /* must be executed after writing the SLP_TYPx register */
+	/* ACPI 3.0 flag bits */
+
+	u32                             pci_exp_wak                         : 1; /* System supports PCIEXP_WAKE (STS/EN) bits */
+	u32                             use_platform_clock                  : 1; /* OSPM should use platform-provided timer */
+	u32                             S4rtc_sts_valid                     : 1; /* Contents of RTC_STS valid after S4 wake */
+	u32                             remote_power_on_capable             : 1; /* System is compatible with remote power on */
+	u32                             force_apic_cluster_model            : 1; /* All local APICs must use cluster model */
+	u32                             force_apic_physical_destination_mode : 1; /* all local x_aPICs must use physical dest mode */
+	u32                             reserved6                           : 12;/* Reserved - must be zero */
 
 	struct acpi_generic_address     reset_register;     /* Reset register address in GAS format */
-	u8                              reset_value;        /* Value to write to the reset_register port to reset the system. */
+	u8                              reset_value;        /* Value to write to the reset_register port to reset the system */
 	u8                              reserved7[3];       /* These three bytes must be zero */
 	u64                             xfirmware_ctrl;     /* 64-bit physical address of FACS */
 	u64                             Xdsdt;              /* 64-bit physical address of DSDT */
@@ -199,7 +207,7 @@ struct fadt_descriptor_rev2
 };
 
 
-/* "Downrevved" ACPI 2.0 FADT descriptor */
+/* "Down-revved" ACPI 2.0 FADT descriptor */
 
 struct fadt_descriptor_rev2_minus
 {
@@ -213,7 +221,7 @@ struct fadt_descriptor_rev2_minus
 };
 
 
-/* Embedded Controller */
+/* ECDT - Embedded Controller Boot Resources Table */
 
 struct ec_boot_resources
 {
@@ -226,6 +234,55 @@ struct ec_boot_resources
 };
 
 
+/* SRAT - System Resource Affinity Table */
+
+struct static_resource_alloc
+{
+	u8                              type;
+	u8                              length;
+	u8                              proximity_domain_lo;
+	u8                              apic_id;
+	u32                             enabled         :1;
+	u32                             reserved3       :31;
+	u8                              local_sapic_eid;
+	u8                              proximity_domain_hi[3];
+	u32                             reserved4;
+};
+
+struct memory_affinity
+{
+	u8                              type;
+	u8                              length;
+	u32                             proximity_domain;
+	u16                             reserved3;
+	u64                             base_address;
+	u64                             address_length;
+	u32                             reserved4;
+	u32                             enabled         :1;
+	u32                             hot_pluggable   :1;
+	u32                             non_volatile    :1;
+	u32                             reserved5       :29;
+	u64                             reserved6;
+};
+
+struct system_resource_affinity
+{
+	ACPI_TABLE_HEADER_DEF
+	u32                             reserved1;          /* Must be value '1' */
+	u64                             reserved2;
+};
+
+
+/* SLIT - System Locality Distance Information Table */
+
+struct system_locality_info
+{
+	ACPI_TABLE_HEADER_DEF
+	u64                             locality_count;
+	u8                              entry[1][1];
+};
+
+
 #pragma pack()
 
 #endif /* __ACTBL2_H__ */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -653,24 +653,26 @@ typedef u8                              
 #define ACPI_BITREG_SLEEP_BUTTON_STATUS         0x04
 #define ACPI_BITREG_RT_CLOCK_STATUS             0x05
 #define ACPI_BITREG_WAKE_STATUS                 0x06
+#define ACPI_BITREG_PCIEXP_WAKE_STATUS          0x07
 
-#define ACPI_BITREG_TIMER_ENABLE                0x07
-#define ACPI_BITREG_GLOBAL_LOCK_ENABLE          0x08
-#define ACPI_BITREG_POWER_BUTTON_ENABLE         0x09
-#define ACPI_BITREG_SLEEP_BUTTON_ENABLE         0x0A
-#define ACPI_BITREG_RT_CLOCK_ENABLE             0x0B
-#define ACPI_BITREG_WAKE_ENABLE                 0x0C
-
-#define ACPI_BITREG_SCI_ENABLE                  0x0D
-#define ACPI_BITREG_BUS_MASTER_RLD              0x0E
-#define ACPI_BITREG_GLOBAL_LOCK_RELEASE         0x0F
-#define ACPI_BITREG_SLEEP_TYPE_A                0x10
-#define ACPI_BITREG_SLEEP_TYPE_B                0x11
-#define ACPI_BITREG_SLEEP_ENABLE                0x12
+#define ACPI_BITREG_TIMER_ENABLE                0x08
+#define ACPI_BITREG_GLOBAL_LOCK_ENABLE          0x09
+#define ACPI_BITREG_POWER_BUTTON_ENABLE         0x0A
+#define ACPI_BITREG_SLEEP_BUTTON_ENABLE         0x0B
+#define ACPI_BITREG_RT_CLOCK_ENABLE             0x0C
+#define ACPI_BITREG_WAKE_ENABLE                 0x0D
+#define ACPI_BITREG_PCIEXP_WAKE_DISABLE         0x0E
+
+#define ACPI_BITREG_SCI_ENABLE                  0x0F
+#define ACPI_BITREG_BUS_MASTER_RLD              0x10
+#define ACPI_BITREG_GLOBAL_LOCK_RELEASE         0x11
+#define ACPI_BITREG_SLEEP_TYPE_A                0x12
+#define ACPI_BITREG_SLEEP_TYPE_B                0x13
+#define ACPI_BITREG_SLEEP_ENABLE                0x14
 
-#define ACPI_BITREG_ARB_DISABLE                 0x13
+#define ACPI_BITREG_ARB_DISABLE                 0x15
 
-#define ACPI_BITREG_MAX                         0x13
+#define ACPI_BITREG_MAX                         0x15
 #define ACPI_NUM_BITREG                         ACPI_BITREG_MAX + 1
 
 
@@ -1206,6 +1208,7 @@ struct acpi_resource_address64
 	u64                                 max_address_range;
 	u64                                 address_translation_offset;
 	u64                                 address_length;
+	u64                                 type_specific_attributes;
 	struct acpi_resource_source         resource_source;
 };
 
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -226,6 +226,7 @@
  */
 
 #define ACPI_STRSTR(s1,s2)      strstr((s1), (s2))
+#define ACPI_STRCHR(s1,c)       strchr((s1), (c))
 
 #ifdef ACPI_FUTURE_USAGE
 #define ACPI_STRUPR(s)          (void) acpi_ut_strupr ((s))
@@ -294,6 +295,7 @@ typedef char *va_list;
 
 
 #define ACPI_STRSTR(s1,s2)      acpi_ut_strstr ((s1), (s2))
+#define ACPI_STRCHR(s1,c)       acpi_ut_strchr ((s1), (c))
 
 #ifdef ACPI_FUTURE_USAGE
 #define ACPI_STRUPR(s)          (void) acpi_ut_strupr ((s))
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -201,7 +201,6 @@ static inline int acpi_processor_ppc_has
 /* in processor_throttling.c */
 int acpi_processor_get_throttling_info (struct acpi_processor *pr);
 int acpi_processor_set_throttling (struct acpi_processor *pr, int state);
-int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file);
 ssize_t acpi_processor_write_throttling (
         struct file		*file,
         const char		__user *buffer,
@@ -217,7 +216,6 @@ int acpi_processor_power_exit(struct acp
 
 /* in processor_thermal.c */
 int acpi_processor_get_limit_info (struct acpi_processor *pr);
-int acpi_processor_limit_open_fs(struct inode *inode, struct file *file);
 ssize_t acpi_processor_write_limit (
 	struct file		*file,
 	const char		__user *buffer,
diff --git a/include/asm-alpha/agp.h b/include/asm-alpha/agp.h
--- a/include/asm-alpha/agp.h
+++ b/include/asm-alpha/agp.h
@@ -10,4 +10,14 @@
 #define flush_agp_mappings() 
 #define flush_agp_cache() mb()
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -353,9 +353,9 @@ static inline unsigned long hweight64(un
 	return __kernel_ctpop(w);
 }
 
-#define hweight32(x) hweight64((x) & 0xfffffffful)
-#define hweight16(x) hweight64((x) & 0xfffful)
-#define hweight8(x)  hweight64((x) & 0xfful)
+#define hweight32(x)	(unsigned int) hweight64((x) & 0xfffffffful)
+#define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
+#define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
 #else
 static inline unsigned long hweight64(unsigned long w)
 {
diff --git a/include/asm-alpha/bug.h b/include/asm-alpha/bug.h
--- a/include/asm-alpha/bug.h
+++ b/include/asm-alpha/bug.h
@@ -1,6 +1,7 @@
 #ifndef _ALPHA_BUG_H
 #define _ALPHA_BUG_H
 
+#ifdef CONFIG_BUG
 #include <asm/pal.h>
 
 /* ??? Would be nice to use .gprel32 here, but we can't be sure that the
@@ -10,6 +11,8 @@
 		       : : "i" (PAL_bugchk), "i"(__LINE__), "i"(__FILE__))
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-alpha/cacheflush.h b/include/asm-alpha/cacheflush.h
--- a/include/asm-alpha/cacheflush.h
+++ b/include/asm-alpha/cacheflush.h
@@ -8,7 +8,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-alpha/errno.h b/include/asm-alpha/errno.h
--- a/include/asm-alpha/errno.h
+++ b/include/asm-alpha/errno.h
@@ -116,4 +116,8 @@
 #define	EKEYREVOKED	134	/* Key has been revoked */
 #define	EKEYREJECTED	135	/* Key was rejected by service */
 
+/* for robust mutexes */
+#define	EOWNERDEAD	136	/* Owner died */
+#define	ENOTRECOVERABLE	137	/* State not recoverable */
+
 #endif
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -666,6 +666,17 @@ isa_memcpy_toio(unsigned long offset, co
 #define writeq writeq
 #define readq readq
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* __ALPHA_IO_H */
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -223,22 +223,21 @@ pci_dac_dma_sync_single_for_device(struc
 	/* Nothing to do. */
 }
 
+/* TODO: integrate with include/asm-generic/pci.h ? */
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+	return channel ? 15 : 14;
+}
+
 extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
 				    struct resource *);
 
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
-static inline int
-pci_name_bus(char *name, struct pci_bus *bus)
+static inline int pci_proc_domain(struct pci_bus *bus)
 {
 	struct pci_controller *hose = bus->sysdata;
-
-	if (likely(hose->need_domain_info == 0)) {
-		sprintf(name, "%02x", bus->number);
-	} else {
-		sprintf(name, "%04x:%02x", hose->index, bus->number);
-	}
-	return 0;
+	return hose->need_domain_info;
 }
 
 static inline void
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -22,6 +22,7 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define PMD_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3))
@@ -41,7 +42,7 @@
 #define PTRS_PER_PMD	(1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PGD	(1UL << (PAGE_SHIFT-3))
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 /* Number of pointers that fit on a page:  this will go away. */
 #define PTRS_PER_PAGE	(1UL << (PAGE_SHIFT-3))
@@ -235,7 +236,10 @@ extern inline unsigned long pgd_page(pgd
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
-extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+	pte_val(*ptep) = 0;
+}
 
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE; }
@@ -336,6 +340,13 @@ extern inline pte_t mk_swap_pte(unsigned
 	remap_pfn_range(vma, start, pfn, size, prot);		\
 })
 
+#define io_remap_pfn_range(vma, start, pfn, size, prot)	\
+		remap_pfn_range(vma, start, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
diff --git a/include/asm-alpha/resource.h b/include/asm-alpha/resource.h
--- a/include/asm-alpha/resource.h
+++ b/include/asm-alpha/resource.h
@@ -2,32 +2,20 @@
 #define _ALPHA_RESOURCE_H
 
 /*
- * Resource limits
+ * Alpha/Linux-specific ordering of these four resource limit IDs,
+ * the rest comes from the generic header:
  */
-
-#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_NOFILE	6		/* max number of open files */
-#define RLIMIT_AS	7		/* address space limit(?) */
-#define RLIMIT_NPROC	8		/* max number of processes */
-#define RLIMIT_MEMLOCK	9		/* max locked-in-memory address space */
-#define RLIMIT_LOCKS	10		/* maximum file locks held */
-#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
-#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
-
-#define RLIM_NLIMITS	13
-#define __ARCH_RLIMIT_ORDER
+#define RLIMIT_NOFILE		6	/* max number of open files */
+#define RLIMIT_AS		7	/* address space limit */
+#define RLIMIT_NPROC		8	/* max number of processes */
+#define RLIMIT_MEMLOCK		9	/* max locked-in-memory address space */
 
 /*
  * SuS says limits have to be unsigned.  Fine, it's unsigned, but
  * we retain the old value for compatibility, especially with DU. 
  * When you run into the 2^63 barrier, you call me.
  */
-#define RLIM_INFINITY	0x7ffffffffffffffful
+#define RLIM_INFINITY		0x7ffffffffffffffful
 
 #include <asm-generic/resource.h>
 
diff --git a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h
--- a/include/asm-alpha/siginfo.h
+++ b/include/asm-alpha/siginfo.h
@@ -4,8 +4,6 @@
 #define __ARCH_SI_PREAMBLE_SIZE		(4 * sizeof(int))
 #define __ARCH_SI_TRAPNO
 
-#define SIGEV_PAD_SIZE			((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-
 #include <asm-generic/siginfo.h>
 
 #endif
diff --git a/include/asm-alpha/signal.h b/include/asm-alpha/signal.h
--- a/include/asm-alpha/signal.h
+++ b/include/asm-alpha/signal.h
@@ -109,34 +109,11 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ	4096
 #define SIGSTKSZ	16384
 
-
-#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		0x40000000
-#endif
-
 #define SIG_BLOCK          1	/* for blocking signals */
 #define SIG_UNBLOCK        2	/* for unblocking signals */
 #define SIG_SETMASK        3	/* for setting the signal mask */
 
-/* Type of a signal handler.  */
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct osf_sigaction {
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -15,7 +15,7 @@
  */
 
 typedef struct {
-	volatile unsigned int lock /*__attribute__((aligned(32))) */;
+	volatile unsigned int lock;
 #ifdef CONFIG_DEBUG_SPINLOCK
 	int on_cpu;
 	int line_no;
@@ -23,40 +23,26 @@ typedef struct {
 	struct task_struct * task;
 	const char *base_file;
 #endif
-#ifdef CONFIG_PREEMPT
-	unsigned int break_lock;
-#endif
 } spinlock_t;
 
 #ifdef CONFIG_DEBUG_SPINLOCK
-#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, NULL, NULL, NULL}
-#define spin_lock_init(x)						\
-	((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = NULL, (x)->task = NULL)
+#define SPIN_LOCK_UNLOCKED	(spinlock_t){ 0, -1, 0, NULL, NULL, NULL }
 #else
-#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
-#define spin_lock_init(x)	((x)->lock = 0)
+#define SPIN_LOCK_UNLOCKED	(spinlock_t){ 0 }
 #endif
 
+#define spin_lock_init(x)	do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
 #define spin_is_locked(x)	((x)->lock != 0)
-#define spin_unlock_wait(x)	({ do { barrier(); } while ((x)->lock); })
-#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+#define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
 #ifdef CONFIG_DEBUG_SPINLOCK
 extern void _raw_spin_unlock(spinlock_t * lock);
 extern void debug_spin_lock(spinlock_t * lock, const char *, int);
 extern int debug_spin_trylock(spinlock_t * lock, const char *, int);
-
-#define _raw_spin_lock(LOCK) debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
-#define _raw_spin_trylock(LOCK) debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
-
-#define spin_lock_own(LOCK, LOCATION)					\
-do {									\
-	if (!((LOCK)->lock && (LOCK)->on_cpu == smp_processor_id()))	\
-		printk("%s: called on %d from %p but lock %s on %d\n",	\
-		       LOCATION, smp_processor_id(),			\
-		       __builtin_return_address(0),			\
-		       (LOCK)->lock ? "taken" : "freed", (LOCK)->on_cpu); \
-} while (0)
+#define _raw_spin_lock(LOCK) \
+	debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
+#define _raw_spin_trylock(LOCK) \
+	debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
 #else
 static inline void _raw_spin_unlock(spinlock_t * lock)
 {
@@ -68,19 +54,16 @@ static inline void _raw_spin_lock(spinlo
 {
 	long tmp;
 
-	/* Use sub-sections to put the actual loop at the end
-	   of this object file's text section so as to perfect
-	   branch prediction.  */
 	__asm__ __volatile__(
 	"1:	ldl_l	%0,%1\n"
-	"	blbs	%0,2f\n"
-	"	or	%0,1,%0\n"
+	"	bne	%0,2f\n"
+	"	lda	%0,1\n"
 	"	stl_c	%0,%1\n"
 	"	beq	%0,2f\n"
 	"	mb\n"
 	".subsection 2\n"
 	"2:	ldl	%0,%1\n"
-	"	blbs	%0,2b\n"
+	"	bne	%0,2b\n"
 	"	br	1b\n"
 	".previous"
 	: "=&r" (tmp), "=m" (lock->lock)
@@ -91,22 +74,29 @@ static inline int _raw_spin_trylock(spin
 {
 	return !test_and_set_bit(0, &lock->lock);
 }
-
-#define spin_lock_own(LOCK, LOCATION)	((void)0)
 #endif /* CONFIG_DEBUG_SPINLOCK */
 
+#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+
 /***********************************************************/
 
 typedef struct {
-	volatile unsigned int write_lock:1, read_counter:31;
-#ifdef CONFIG_PREEMPT
-	unsigned int break_lock;
-#endif
-} /*__attribute__((aligned(32)))*/ rwlock_t;
+	volatile unsigned int lock;
+} rwlock_t;
+
+#define RW_LOCK_UNLOCKED	(rwlock_t){ 0 }
 
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
-#define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+static inline int read_can_lock(rwlock_t *lock)
+{
+	return (lock->lock & 1) == 0;
+}
+
+static inline int write_can_lock(rwlock_t *lock)
+{
+	return lock->lock == 0;
+}
 
 #ifdef CONFIG_DEBUG_RWLOCK
 extern void _raw_write_lock(rwlock_t * lock);
@@ -119,7 +109,7 @@ static inline void _raw_write_lock(rwloc
 	__asm__ __volatile__(
 	"1:	ldl_l	%1,%0\n"
 	"	bne	%1,6f\n"
-	"	or	$31,1,%1\n"
+	"	lda	%1,1\n"
 	"	stl_c	%1,%0\n"
 	"	beq	%1,6f\n"
 	"	mb\n"
@@ -142,7 +132,7 @@ static inline void _raw_read_lock(rwlock
 	"	subl	%1,2,%1\n"
 	"	stl_c	%1,%0\n"
 	"	beq	%1,6f\n"
-	"4:	mb\n"
+	"	mb\n"
 	".subsection 2\n"
 	"6:	ldl	%1,%0\n"
 	"	blbs	%1,6b\n"
@@ -153,6 +143,28 @@ static inline void _raw_read_lock(rwlock
 }
 #endif /* CONFIG_DEBUG_RWLOCK */
 
+static inline int _raw_read_trylock(rwlock_t * lock)
+{
+	long regx;
+	int success;
+
+	__asm__ __volatile__(
+	"1:	ldl_l	%1,%0\n"
+	"	lda	%2,0\n"
+	"	blbs	%1,2f\n"
+	"	subl	%1,2,%2\n"
+	"	stl_c	%2,%0\n"
+	"	beq	%2,6f\n"
+	"2:	mb\n"
+	".subsection 2\n"
+	"6:	br	1b\n"
+	".previous"
+	: "=m" (*lock), "=&r" (regx), "=&r" (success)
+	: "m" (*lock) : "memory");
+
+	return success;
+}
+
 static inline int _raw_write_trylock(rwlock_t * lock)
 {
 	long regx;
@@ -162,10 +174,9 @@ static inline int _raw_write_trylock(rwl
 	"1:	ldl_l	%1,%0\n"
 	"	lda	%2,0\n"
 	"	bne	%1,2f\n"
-	"	or	$31,1,%1\n"
-	"	stl_c	%1,%0\n"
-	"	beq	%1,6f\n"
 	"	lda	%2,1\n"
+	"	stl_c	%2,%0\n"
+	"	beq	%2,6f\n"
 	"2:	mb\n"
 	".subsection 2\n"
 	"6:	br	1b\n"
@@ -179,7 +190,7 @@ static inline int _raw_write_trylock(rwl
 static inline void _raw_write_unlock(rwlock_t * lock)
 {
 	mb();
-	*(volatile int *)lock = 0;
+	lock->lock = 0;
 }
 
 static inline void _raw_read_unlock(rwlock_t * lock)
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -621,4 +621,6 @@ __cmpxchg(volatile void *ptr, unsigned l
 
 #endif /* __ASSEMBLY__ */
 
+#define arch_align_stack(x) (x)
+
 #endif
diff --git a/include/asm-alpha/timex.h b/include/asm-alpha/timex.h
--- a/include/asm-alpha/timex.h
+++ b/include/asm-alpha/timex.h
@@ -20,7 +20,6 @@
  */
 
 typedef unsigned int cycles_t;
-extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles (void)
 {
diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h
--- a/include/asm-alpha/uaccess.h
+++ b/include/asm-alpha/uaccess.h
@@ -48,7 +48,8 @@
 	__access_ok(((unsigned long)(addr)),(size),get_fs());	\
 })
 
-extern inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-alpha/unaligned.h b/include/asm-alpha/unaligned.h
--- a/include/asm-alpha/unaligned.h
+++ b/include/asm-alpha/unaligned.h
@@ -1,114 +1,6 @@
 #ifndef __ALPHA_UNALIGNED_H
 #define __ALPHA_UNALIGNED_H
 
-/* 
- * The main single-value unaligned transfer routines.
- */
-#define get_unaligned(ptr) \
-	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
-#define put_unaligned(x,ptr) \
-	__put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
-
-/*
- * This is a silly but good way to make sure that
- * the get/put functions are indeed always optimized,
- * and that we use the correct sizes.
- */
-extern void bad_unaligned_access_length(void) __attribute__((noreturn));
-
-/*
- * EGCS 1.1 knows about arbitrary unaligned loads.  Define some
- * packed structures to talk about such things with.
- */
-
-struct __una_u64 { __u64 x __attribute__((packed)); };
-struct __una_u32 { __u32 x __attribute__((packed)); };
-struct __una_u16 { __u16 x __attribute__((packed)); };
-
-/*
- * Elemental unaligned loads 
- */
-
-extern inline unsigned long __uldq(const unsigned long * r11)
-{
-	const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
-	return ptr->x;
-}
-
-extern inline unsigned long __uldl(const unsigned int * r11)
-{
-	const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
-	return ptr->x;
-}
-
-extern inline unsigned long __uldw(const unsigned short * r11)
-{
-	const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
-	return ptr->x;
-}
-
-/*
- * Elemental unaligned stores 
- */
-
-extern inline void __ustq(unsigned long r5, unsigned long * r11)
-{
-	struct __una_u64 *ptr = (struct __una_u64 *) r11;
-	ptr->x = r5;
-}
-
-extern inline void __ustl(unsigned long r5, unsigned int * r11)
-{
-	struct __una_u32 *ptr = (struct __una_u32 *) r11;
-	ptr->x = r5;
-}
-
-extern inline void __ustw(unsigned long r5, unsigned short * r11)
-{
-	struct __una_u16 *ptr = (struct __una_u16 *) r11;
-	ptr->x = r5;
-}
-
-extern inline unsigned long __get_unaligned(const void *ptr, size_t size)
-{
-	unsigned long val;
-	switch (size) {
-	      case 1:
-		val = *(const unsigned char *)ptr;
-		break;
-	      case 2:
-		val = __uldw((const unsigned short *)ptr);
-		break;
-	      case 4:
-		val = __uldl((const unsigned int *)ptr);
-		break;
-	      case 8:
-		val = __uldq((const unsigned long *)ptr);
-		break;
-	      default:
-		bad_unaligned_access_length();
-	}
-	return val;
-}
-
-extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size)
-{
-	switch (size) {
-	      case 1:
-		*(unsigned char *)ptr = (val);
-	        break;
-	      case 2:
-		__ustw(val, (unsigned short *)ptr);
-		break;
-	      case 4:
-		__ustl(val, (unsigned int *)ptr);
-		break;
-	      case 8:
-		__ustq(val, (unsigned long *)ptr);
-		break;
-	      default:
-	    	bad_unaligned_access_length();
-	}
-}
+#include <asm-generic/unaligned.h>
 
 #endif
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
--- a/include/asm-alpha/unistd.h
+++ b/include/asm-alpha/unistd.h
@@ -374,8 +374,11 @@
 #define __NR_mq_notify			436
 #define __NR_mq_getsetattr		437
 #define __NR_waitid			438
+#define __NR_add_key			439
+#define __NR_request_key		440
+#define __NR_keyctl			441
 
-#define NR_SYSCALLS			439
+#define NR_SYSCALLS			442
 
 #if defined(__GNUC__)
 
@@ -651,6 +654,6 @@ asmlinkage long sys_rt_sigaction(int sig
    have declarations.  If we use no prototype, then we get warnings from
    -Wstrict-prototypes.  Ho hum.  */
 
-#define cond_syscall(x)  asm(".weak\t" #x "\n" #x " = sys_ni_syscall");
+#define cond_syscall(x)  asm(".weak\t" #x "\n" #x " = sys_ni_syscall")
 
 #endif /* _ALPHA_UNISTD_H */
diff --git a/include/asm-arm/arch-cl7500/hardware.h b/include/asm-arm/arch-cl7500/hardware.h
--- a/include/asm-arm/arch-cl7500/hardware.h
+++ b/include/asm-arm/arch-cl7500/hardware.h
@@ -13,6 +13,12 @@
 #include <asm/arch/memory.h>
 #include <asm/hardware/iomd.h>
 
+#ifdef __ASSEMBLY__
+#define IOMEM(x) x
+#else
+#define IOMEM(x) ((void __iomem *)(x))
+#endif
+
 /*
  * What hardware must be present
  */
@@ -27,7 +33,7 @@
 
 #define IO_START		0x03000000	/* I/O */
 #define IO_SIZE			0x01000000
-#define IO_BASE			0xe0000000
+#define IO_BASE			IOMEM(0xe0000000)
 
 #define ISA_START		0x0c000000	/* ISA */
 #define ISA_SIZE		0x00010000
@@ -49,11 +55,11 @@
 
 #define FLUSH_BASE		0xdf000000
 
-#define VIDC_BASE		0xe0400000
-#define IOMD_BASE		0xe0200000
-#define IOC_BASE		0xe0200000
-#define FLOPPYDMA_BASE		0xe002a000
-#define PCIO_BASE		0xe0010000
+#define VIDC_BASE		(void __iomem *)0xe0400000
+#define IOMD_BASE		IOMEM(0xe0200000)
+#define IOC_BASE		IOMEM(0xe0200000)
+#define FLOPPYDMA_BASE		IOMEM(0xe002a000)
+#define PCIO_BASE		IOMEM(0xe0010000)
 
 #define FLUSH_BASE_PHYS		0x00000000	/* ROM */
 
@@ -63,4 +69,3 @@
 #define ISASLOT_IO		0x80400000
 
 #endif
-
diff --git a/include/asm-arm/arch-cl7500/vmalloc.h b/include/asm-arm/arch-cl7500/vmalloc.h
--- a/include/asm-arm/arch-cl7500/vmalloc.h
+++ b/include/asm-arm/arch-cl7500/vmalloc.h
@@ -1,15 +1,4 @@
 /*
  * linux/include/asm-arm/arch-cl7500/vmalloc.h
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
diff --git a/include/asm-arm/arch-clps711x/vmalloc.h b/include/asm-arm/arch-clps711x/vmalloc.h
--- a/include/asm-arm/arch-clps711x/vmalloc.h
+++ b/include/asm-arm/arch-clps711x/vmalloc.h
@@ -17,15 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-ebsa110/vmalloc.h b/include/asm-arm/arch-ebsa110/vmalloc.h
--- a/include/asm-arm/arch-ebsa110/vmalloc.h
+++ b/include/asm-arm/arch-ebsa110/vmalloc.h
@@ -7,15 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x1f000000)
diff --git a/include/asm-arm/arch-ebsa285/debug-macro.S b/include/asm-arm/arch-ebsa285/debug-macro.S
--- a/include/asm-arm/arch-ebsa285/debug-macro.S
+++ b/include/asm-arm/arch-ebsa285/debug-macro.S
@@ -45,9 +45,12 @@
 		.equ	dc21285_low,  ARMCSR_BASE & 0x00ffffff
 
 		.macro	addruart,rx
-		mov	\rx, #dc21285_high
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #0x42000000
+		movne	\rx, #dc21285_high
 		.if	dc21285_low
-		orr	\rx, \rx, #dc21285_low
+		orrne	\rx, \rx, #dc21285_low
 		.endif
 		.endm
 
diff --git a/include/asm-arm/arch-ebsa285/vmalloc.h b/include/asm-arm/arch-ebsa285/vmalloc.h
--- a/include/asm-arm/arch-ebsa285/vmalloc.h
+++ b/include/asm-arm/arch-ebsa285/vmalloc.h
@@ -8,17 +8,6 @@
 
 #include <linux/config.h>
 
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-
 #ifdef CONFIG_ARCH_FOOTBRIDGE
 #define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
 #else
diff --git a/include/asm-arm/arch-epxa10db/vmalloc.h b/include/asm-arm/arch-epxa10db/vmalloc.h
--- a/include/asm-arm/arch-epxa10db/vmalloc.h
+++ b/include/asm-arm/arch-epxa10db/vmalloc.h
@@ -17,15 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-h720x/vmalloc.h b/include/asm-arm/arch-h720x/vmalloc.h
--- a/include/asm-arm/arch-h720x/vmalloc.h
+++ b/include/asm-arm/arch-h720x/vmalloc.h
@@ -5,17 +5,6 @@
 #ifndef __ARCH_ARM_VMALLOC_H
 #define __ARCH_ARM_VMALLOC_H
 
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
 
 #endif
diff --git a/include/asm-arm/arch-imx/hardware.h b/include/asm-arm/arch-imx/hardware.h
--- a/include/asm-arm/arch-imx/hardware.h
+++ b/include/asm-arm/arch-imx/hardware.h
@@ -26,9 +26,7 @@
 #ifndef __ASSEMBLY__
 # define __REG(x)	(*((volatile u32 *)IO_ADDRESS(x)))
 
-# define __REG2(x,y)	\
-	( __builtin_constant_p(y) ? (__REG((x) + (y))) \
-			  : (*(volatile u32 *)((u32)&__REG(x) + (y))) )
+# define __REG2(x,y)        (*(volatile u32 *)((u32)&__REG(x) + (y)))
 #endif
 
 /*
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -228,6 +228,30 @@
 #define PD31_BIN_SPI2_TXD    ( GPIO_PORTD | GPIO_BIN | 31 )
 
 /*
+ * PWM controller
+ */
+#define PWMC	__REG(IMX_PWM_BASE + 0x00)	/* PWM Control Register		*/
+#define PWMS	__REG(IMX_PWM_BASE + 0x04)	/* PWM Sample Register		*/
+#define PWMP	__REG(IMX_PWM_BASE + 0x08)	/* PWM Period Register		*/
+#define PWMCNT	__REG(IMX_PWM_BASE + 0x0C)	/* PWM Counter Register		*/
+
+#define PWMC_HCTR		(0x01<<18)		/* Halfword FIFO Data Swapping	*/
+#define PWMC_BCTR		(0x01<<17)		/* Byte FIFO Data Swapping	*/
+#define PWMC_SWR		(0x01<<16)		/* Software Reset		*/
+#define PWMC_CLKSRC		(0x01<<15)		/* Clock Source			*/
+#define PWMC_PRESCALER(x)	(((x-1) & 0x7F) << 8)	/* PRESCALER			*/
+#define PWMC_IRQ		(0x01<< 7)		/* Interrupt Request		*/
+#define PWMC_IRQEN		(0x01<< 6)		/* Interrupt Request Enable	*/
+#define PWMC_FIFOAV		(0x01<< 5)		/* FIFO Available		*/
+#define PWMC_EN			(0x01<< 4)		/* Enables/Disables the PWM	*/
+#define PWMC_REPEAT(x)		(((x) & 0x03) << 2)	/* Sample Repeats		*/
+#define PWMC_CLKSEL(x)		(((x) & 0x03) << 0)	/* Clock Selection		*/
+
+#define PWMS_SAMPLE(x)		((x) & 0xFFFF)		/* Contains a two-sample word	*/
+#define PWMP_PERIOD(x)		((x) & 0xFFFF)		/* Represents the PWM's period	*/
+#define PWMC_COUNTER(x)		((x) & 0xFFFF)		/* Represents the current count value	*/
+
+/*
  *  DMA Controller
  */
 #define DCR     __REG(IMX_DMAC_BASE +0x00)	/* DMA Control Register */
diff --git a/include/asm-arm/arch-imx/imxfb.h b/include/asm-arm/arch-imx/imxfb.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-imx/imxfb.h
@@ -0,0 +1,35 @@
+/*
+ * This structure describes the machine which we are running on.
+ */
+struct imxfb_mach_info {
+	u_long		pixclock;
+
+	u_short		xres;
+	u_short		yres;
+
+	u_char		bpp;
+	u_char		hsync_len;
+	u_char		left_margin;
+	u_char		right_margin;
+
+	u_char		vsync_len;
+	u_char		upper_margin;
+	u_char		lower_margin;
+	u_char		sync;
+
+	u_int		cmap_greyscale:1,
+			cmap_inverse:1,
+			cmap_static:1,
+			unused:29;
+
+	u_int		pcr;
+	u_int		pwmr;
+	u_int		lscr1;
+
+	u_char * fixed_screen_cpu;
+	dma_addr_t fixed_screen_dma;
+
+	void (*lcd_power)(int);
+	void (*backlight_power)(int);
+};
+void set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info);
diff --git a/include/asm-arm/arch-imx/vmalloc.h b/include/asm-arm/arch-imx/vmalloc.h
--- a/include/asm-arm/arch-imx/vmalloc.h
+++ b/include/asm-arm/arch-imx/vmalloc.h
@@ -17,16 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-integrator/cm.h b/include/asm-arm/arch-integrator/cm.h
--- a/include/asm-arm/arch-integrator/cm.h
+++ b/include/asm-arm/arch-integrator/cm.h
@@ -24,9 +24,9 @@ void cm_control(u32, u32);
 #define CM_CTRL_LCDBIASDN		(1 << 10)
 #define CM_CTRL_LCDMUXSEL_MASK		(7 << 11)
 #define CM_CTRL_LCDMUXSEL_GENLCD	(1 << 11)
-#define CM_CTRL_LCDMUXSEL_SHARPLCD1	(3 << 11)
-#define CM_CTRL_LCDMUXSEL_SHARPLCD2	(4 << 11)
-#define CM_CTRL_LCDMUXSEL_VGA		(7 << 11)
+#define CM_CTRL_LCDMUXSEL_VGA_16BPP	(2 << 11)
+#define CM_CTRL_LCDMUXSEL_SHARPLCD	(3 << 11)
+#define CM_CTRL_LCDMUXSEL_VGA_8421BPP	(4 << 11)
 #define CM_CTRL_LCDEN0			(1 << 14)
 #define CM_CTRL_LCDEN1			(1 << 15)
 #define CM_CTRL_STATIC1			(1 << 16)
diff --git a/include/asm-arm/arch-integrator/lm.h b/include/asm-arm/arch-integrator/lm.h
--- a/include/asm-arm/arch-integrator/lm.h
+++ b/include/asm-arm/arch-integrator/lm.h
@@ -10,7 +10,7 @@ struct lm_driver {
 	struct device_driver	drv;
 	int			(*probe)(struct lm_device *);
 	void			(*remove)(struct lm_device *);
-	int			(*suspend)(struct lm_device *, u32);
+	int			(*suspend)(struct lm_device *, pm_message_t);
 	int			(*resume)(struct lm_device *);
 };
 
diff --git a/include/asm-arm/arch-integrator/platform.h b/include/asm-arm/arch-integrator/platform.h
--- a/include/asm-arm/arch-integrator/platform.h
+++ b/include/asm-arm/arch-integrator/platform.h
@@ -20,14 +20,14 @@
  * * Copyright © ARM Limited 1998.  All rights reserved.
  * ***********************************************************************/
 /* ************************************************************************
- * 
+ *
  *   Integrator address map
- * 
+ *
  * 	NOTE: This is a multi-hosted header file for use with uHAL and
  * 	      supported debuggers.
- * 
+ *
  * 	$Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $
- * 
+ *
  * ***********************************************************************/
 
 #ifndef __address_h
@@ -40,22 +40,22 @@
  *  Memory definitions
  * ------------------------------------------------------------------------
  *  Integrator memory map
- * 
+ *
  */
 #define INTEGRATOR_BOOT_ROM_LO          0x00000000
 #define INTEGRATOR_BOOT_ROM_HI          0x20000000
 #define INTEGRATOR_BOOT_ROM_BASE        INTEGRATOR_BOOT_ROM_HI	 /*  Normal position */
 #define INTEGRATOR_BOOT_ROM_SIZE        SZ_512K
 
-/* 
+/*
  *  New Core Modules have different amounts of SSRAM, the amount of SSRAM
  *  fitted can be found in HDR_STAT.
- * 
+ *
  *  The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to
  *  the minimum amount of SSRAM fitted on any core module.
- * 
+ *
  *  New Core Modules also alias the SSRAM.
- * 
+ *
  */
 #define INTEGRATOR_SSRAM_BASE           0x00000000
 #define INTEGRATOR_SSRAM_ALIAS_BASE     0x10800000
@@ -67,9 +67,9 @@
 #define INTEGRATOR_MBRD_SSRAM_BASE      0x28000000
 #define INTEGRATOR_MBRD_SSRAM_SIZE      SZ_512K
 
-/* 
+/*
  *  SDRAM is a SIMM therefore the size is not known.
- * 
+ *
  */
 #define INTEGRATOR_SDRAM_BASE           0x00040000
 
@@ -79,9 +79,9 @@
 #define INTEGRATOR_HDR2_SDRAM_BASE      0xA0000000
 #define INTEGRATOR_HDR3_SDRAM_BASE      0xB0000000
 
-/* 
+/*
  *  Logic expansion modules
- * 
+ *
  */
 #define INTEGRATOR_LOGIC_MODULES_BASE   0xC0000000
 #define INTEGRATOR_LOGIC_MODULE0_BASE   0xC0000000
@@ -92,7 +92,7 @@
 /* ------------------------------------------------------------------------
  *  Integrator header card registers
  * ------------------------------------------------------------------------
- * 
+ *
  */
 #define INTEGRATOR_HDR_ID_OFFSET        0x00
 #define INTEGRATOR_HDR_PROC_OFFSET      0x04
@@ -185,12 +185,12 @@
 /* ------------------------------------------------------------------------
  *  Integrator system registers
  * ------------------------------------------------------------------------
- * 
+ *
  */
 
-/* 
+/*
  *  System Controller
- * 
+ *
  */
 #define INTEGRATOR_SC_ID_OFFSET         0x00
 #define INTEGRATOR_SC_OSC_OFFSET        0x04
@@ -230,11 +230,11 @@
 #define INTEGRATOR_SC_CTRL_URTS1        (1 << 6)
 #define INTEGRATOR_SC_CTRL_UDTR1        (1 << 7)
 
-/* 
+/*
  *  External Bus Interface
- * 
+ *
  */
-#define INTEGRATOR_EBI_BASE             0x12000000 
+#define INTEGRATOR_EBI_BASE             0x12000000
 
 #define INTEGRATOR_EBI_CSR0_OFFSET      0x00
 #define INTEGRATOR_EBI_CSR1_OFFSET      0x04
@@ -279,9 +279,9 @@
 #define INTEGRATOR_KBD_BASE             0x18000000	 /*  Keyboard */
 #define INTEGRATOR_MOUSE_BASE           0x19000000	 /*  Mouse */
 
-/* 
+/*
  *  LED's & Switches
- * 
+ *
  */
 #define INTEGRATOR_DBG_ALPHA_OFFSET     0x00
 #define INTEGRATOR_DBG_LEDS_OFFSET      0x04
@@ -293,14 +293,18 @@
 #define INTEGRATOR_DBG_SWITCH           (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET)
 
 
+#if defined(CONFIG_ARCH_INTEGRATOR_AP)
 #define INTEGRATOR_GPIO_BASE            0x1B000000	 /*  GPIO */
+#elif defined(CONFIG_ARCH_INTEGRATOR_CP)
+#define INTEGRATOR_GPIO_BASE            0xC9000000	 /*  GPIO */
+#endif
 
 /* ------------------------------------------------------------------------
  *  KMI keyboard/mouse definitions
  * ------------------------------------------------------------------------
  */
 /* PS2 Keyboard interface */
-#define KMI0_BASE                       INTEGRATOR_KBD_BASE		
+#define KMI0_BASE                       INTEGRATOR_KBD_BASE
 
 /* PS2 Mouse interface */
 #define KMI1_BASE                       INTEGRATOR_MOUSE_BASE
@@ -313,7 +317,7 @@
  *  This represents a fairly liberal usage of address space.  Even though
  *  the V3 only has two windows (therefore we need to map stuff on the fly),
  *  we maintain the same addresses, even if they're not mapped.
- * 
+ *
  */
 #define PHYS_PCI_MEM_BASE               0x40000000   /* 512M to xxx */
 /*  unused 256M from A0000000-AFFFFFFF might be used for I2O ???
@@ -326,7 +330,7 @@
  */
 #define PHYS_PCI_V3_BASE                0x62000000
 
-#define PCI_DRAMSIZE                    INTEGRATOR_SSRAM_SIZE	
+#define PCI_DRAMSIZE                    INTEGRATOR_SSRAM_SIZE
 
 /* 'export' these to UHAL */
 #define UHAL_PCI_IO                     PCI_IO_BASE
@@ -334,7 +338,7 @@
 #define UHAL_PCI_ALLOC_IO_BASE          0x00004000
 #define UHAL_PCI_ALLOC_MEM_BASE         PCI_MEM_BASE
 #define UHAL_PCI_MAX_SLOT               20
-	
+
 /* ========================================================================
  *  Start of uHAL definitions
  * ========================================================================
@@ -343,17 +347,17 @@
 /* ------------------------------------------------------------------------
  *  Integrator Interrupt Controllers
  * ------------------------------------------------------------------------
- * 
- *  Offsets from interrupt controller base 
- * 
+ *
+ *  Offsets from interrupt controller base
+ *
  *  System Controller interrupt controller base is
- * 
+ *
  * 	INTEGRATOR_IC_BASE + (header_number << 6)
- * 
+ *
  *  Core Module interrupt controller base is
- * 
- * 	INTEGRATOR_HDR_IC 
- * 
+ *
+ * 	INTEGRATOR_HDR_IC
+ *
  */
 #define IRQ_STATUS                      0
 #define IRQ_RAW_STATUS                  0x04
@@ -374,22 +378,22 @@
 /* ------------------------------------------------------------------------
  *  Interrupts
  * ------------------------------------------------------------------------
- * 
- *  
+ *
+ *
  *  Each Core Module has two interrupts controllers, one on the core module
  *  itself and one in the system controller on the motherboard.  The
  *  READ_INT macro in target.s reads both interrupt controllers and returns
  *  a 32 bit bitmask, bits 0 to 23 are interrupts from the system controller
  *  and bits 24 to 31 are from the core module.
- *  
+ *
  *  The following definitions relate to the bitmask returned by READ_INT.
- * 
+ *
  */
 
 /* ------------------------------------------------------------------------
  *  LED's - The header LED is not accessible via the uHAL API
  * ------------------------------------------------------------------------
- * 
+ *
  */
 #define GREEN_LED                       0x01
 #define YELLOW_LED                      0x02
@@ -399,44 +403,44 @@
 
 #define LED_BANK                        INTEGRATOR_DBG_LEDS
 
-/* 
+/*
  *  Memory definitions - run uHAL out of SSRAM.
- * 
+ *
  */
 #define uHAL_MEMORY_SIZE                INTEGRATOR_SSRAM_SIZE
 
-/* 
+/*
  *  Application Flash
- * 
+ *
  */
 #define FLASH_BASE                      INTEGRATOR_FLASH_BASE
 #define FLASH_SIZE                      INTEGRATOR_FLASH_SIZE
 #define FLASH_END                       (FLASH_BASE + FLASH_SIZE - 1)
 #define FLASH_BLOCK_SIZE                SZ_128K
 
-/* 
+/*
  *  Boot Flash
- * 
+ *
  */
 #define EPROM_BASE                      INTEGRATOR_BOOT_ROM_HI
 #define EPROM_SIZE                      INTEGRATOR_BOOT_ROM_SIZE
 #define EPROM_END                       (EPROM_BASE + EPROM_SIZE - 1)
 
-/* 
+/*
  *  Clean base - dummy
- * 
+ *
  */
 #define CLEAN_BASE                      EPROM_BASE
 
-/* 
+/*
  *  Timer definitions
- * 
+ *
  *  Only use timer 1 & 2
  *  (both run at 24MHz and will need the clock divider set to 16).
- * 
+ *
  *  Timer 0 runs at bus frequency and therefore could vary and currently
  *  uHAL can't handle that.
- * 
+ *
  */
 
 #define INTEGRATOR_TIMER0_BASE          INTEGRATOR_CT_BASE
@@ -447,9 +451,9 @@
 #define MAX_PERIOD                      699050
 #define TICKS_PER_uSEC                  24
 
-/* 
- *  These are useconds NOT ticks.  
- * 
+/*
+ *  These are useconds NOT ticks.
+ *
  */
 #define mSEC_1                          1000
 #define mSEC_5                          (mSEC_1 * 5)
diff --git a/include/asm-arm/arch-integrator/vmalloc.h b/include/asm-arm/arch-integrator/vmalloc.h
--- a/include/asm-arm/arch-integrator/vmalloc.h
+++ b/include/asm-arm/arch-integrator/vmalloc.h
@@ -17,15 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-iop3xx/vmalloc.h b/include/asm-arm/arch-iop3xx/vmalloc.h
--- a/include/asm-arm/arch-iop3xx/vmalloc.h
+++ b/include/asm-arm/arch-iop3xx/vmalloc.h
@@ -10,9 +10,6 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 //#define VMALLOC_END       (0xe8000000)
 /* increase usable physical RAM to ~992M per RMK */
 #define VMALLOC_END       (0xfe000000)
diff --git a/include/asm-arm/arch-ixp2000/entry-macro.S b/include/asm-arm/arch-ixp2000/entry-macro.S
--- a/include/asm-arm/arch-ixp2000/entry-macro.S
+++ b/include/asm-arm/arch-ixp2000/entry-macro.S
@@ -15,8 +15,7 @@
 
 		mov	\irqnr, #0x0              @clear out irqnr as default
                 mov	\base, #0xfe000000
-		orr	\base, \base, #0x00ff0000
-		orr	\base, \base, #0x0000a000
+		orr	\base, \base, #0x00e00000
 		orr	\base, \base, #0x08
 		ldr	\irqstat, [\base]         @ get interrupts
 
@@ -35,8 +34,8 @@
 		bne	1001f
 
 		mov	\base, #0xfe000000
-		orr	\base, \base, #0x00fd0000
-		orr	\base, \base, #0x0000e100
+		orr	\base, \base, #0x00c00000
+		orr	\base, \base, #0x00000100
 		orr	\base, \base, #0x00000058
 		ldr	\irqstat, [\base]
 
diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h
--- a/include/asm-arm/arch-ixp2000/io.h
+++ b/include/asm-arm/arch-ixp2000/io.h
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-ixdp2000/io.h
+ * linux/include/asm-arm/arch-ixp2000/io.h
  *
  * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
  * Maintainer: Deepak Saxena <dsaxena@plexity.net>
@@ -17,20 +17,20 @@
 
 #define IO_SPACE_LIMIT		0xffffffff
 #define __mem_pci(a)		(a)
-
-/*
- * Pick up VMALLOC_END
- */
 #define ___io(p)		((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
 
 /*
- * IXP2000 does not do proper byte-lane conversion for PCI addresses,
- * so we need to override standard functions.
+ * The IXP2400 before revision B0 asserts byte lanes for PCI I/O
+ * transactions the other way round (MEM transactions don't have this
+ * issue), so we need to override the standard functions.  B0 and later
+ * have a bit that can be set to 1 to get the 'proper' behavior, but
+ * since that isn't available on the A? revisions we just keep doing
+ * things manually.
  */
-#define alignb(addr)		(((unsigned long)addr & ~3) + (3 - ((unsigned long)addr & 3)))
-#define alignw(addr)		(((unsigned long)addr & ~2) + (2 - ((unsigned long)addr & 2)))
+#define alignb(addr)		(void __iomem *)((unsigned long)addr ^ 3)
+#define alignw(addr)		(void __iomem *)((unsigned long)addr ^ 2)
 
-#define outb(v,p)		__raw_writeb(v,alignb(___io(p)))
+#define outb(v,p)		__raw_writeb((v),alignb(___io(p)))
 #define outw(v,p)		__raw_writew((v),alignw(___io(p)))
 #define outl(v,p)		__raw_writel((v),___io(p))
 
@@ -53,8 +53,8 @@
 /*
  * This is an ugly hack but the CS8900 on the 2x01's does not sit in any sort
  * of "I/O space" and is just direct mapped into a 32-bit-only addressable
- * bus. The address space for this bus is such that we can't really easilly
- * make it contigous to the PCI I/O address range, and it also does not
+ * bus. The address space for this bus is such that we can't really easily
+ * make it contiguous to the PCI I/O address range, and it also does not
  * need swapping like PCI addresses do (IXDP2x01 is a BE platform).
  * B/C of this we can't use the standard in/out functions and need to
  * runtime check if the incoming address is a PCI address or for
@@ -75,8 +75,8 @@ static inline void insw(u32 ptr, void *b
 	 * Is this cycle meant for the CS8900?
 	 */
 	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
-		((port >= IXDP2X01_CS8900_VIRT_BASE) && 
-		 (port <= IXDP2X01_CS8900_VIRT_END))) {
+		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
+		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
 		u8 *buf8 = (u8*)buf;
 		register u32 tmp32;
 
@@ -100,8 +100,8 @@ static inline void outsw(u32 ptr, void *
 	 * Is this cycle meant for the CS8900?
 	 */
 	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
-		((port >= IXDP2X01_CS8900_VIRT_BASE) && 
-		 (port <= IXDP2X01_CS8900_VIRT_END))) {
+		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
+		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
 		register u32 tmp32;
 		u8 *buf8 = (u8*)buf;
 		do {
@@ -124,8 +124,8 @@ static inline u16 inw(u32 ptr)
 	 * Is this cycle meant for the CS8900?
 	 */
 	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
-		((port >= IXDP2X01_CS8900_VIRT_BASE) && 
-		 (port <= IXDP2X01_CS8900_VIRT_END))) {
+		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
+		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
 		return (u16)(*port);  
 	}
 
@@ -137,8 +137,8 @@ static inline void outw(u16 value, u32 p
 	register volatile u32 *port = (volatile u32 *)ptr;
 
 	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
-		((port >= IXDP2X01_CS8900_VIRT_BASE) && 
-		 (port <= IXDP2X01_CS8900_VIRT_END))) {
+		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
+		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
 		*port = value;  
 		return;
 	}
diff --git a/include/asm-arm/arch-ixp2000/irqs.h b/include/asm-arm/arch-ixp2000/irqs.h
--- a/include/asm-arm/arch-ixp2000/irqs.h
+++ b/include/asm-arm/arch-ixp2000/irqs.h
@@ -45,12 +45,12 @@
 #define	IRQ_IXP2000_ME_ATTN       	14 
 #define	IRQ_IXP2000_PCI   		15 /* PCI INTA or INTB */
 #define	IRQ_IXP2000_THDA0   		16 /* thread 0-31A */
-#define	IRQ_IXP2000_THDA1  		17 /* thread 32-63A */
-#define	IRQ_IXP2000_THDA2		18 /* thread 64-95A, IXP2800 only */
+#define	IRQ_IXP2000_THDA1  		17 /* thread 32-63A, IXP2800 only */
+#define	IRQ_IXP2000_THDA2		18 /* thread 64-95A */
 #define	IRQ_IXP2000_THDA3 		19 /* thread 96-127A, IXP2800 only */
 #define	IRQ_IXP2000_THDB0		24 /* thread 0-31B */
-#define	IRQ_IXP2000_THDB1		25 /* thread 32-63B */
-#define	IRQ_IXP2000_THDB2		26 /* thread 64-95B, IXP2800 only */
+#define	IRQ_IXP2000_THDB1		25 /* thread 32-63B, IXP2800 only */
+#define	IRQ_IXP2000_THDB2		26 /* thread 64-95B */
 #define	IRQ_IXP2000_THDB3		27 /* thread 96-127B, IXP2800 only */
 
 /* define generic GPIOs */
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x00.h b/include/asm-arm/arch-ixp2000/ixdp2x00.h
--- a/include/asm-arm/arch-ixp2000/ixdp2x00.h
+++ b/include/asm-arm/arch-ixp2000/ixdp2x00.h
@@ -21,7 +21,7 @@
  * On board CPLD memory map
  */
 #define IXDP2X00_PHYS_CPLD_BASE		0xc7000000
-#define IXDP2X00_VIRT_CPLD_BASE		0xfefdd000
+#define IXDP2X00_VIRT_CPLD_BASE		0xfafff000
 #define IXDP2X00_CPLD_SIZE		0x00001000
 
 
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h
--- a/include/asm-arm/arch-ixp2000/ixdp2x01.h
+++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h
@@ -1,5 +1,5 @@
 /*
- * include/asm/arch/ixdp2x01.h
+ * include/asm-arm/arch-ixp2000/ixdp2x01.h
  *
  * Platform definitions for IXDP2X01 && IXDP2801 systems
  *
@@ -18,10 +18,10 @@
 #define __IXDP2X01_H__
 
 #define	IXDP2X01_PHYS_CPLD_BASE		0xc6024000
-#define	IXDP2X01_VIRT_CPLD_BASE		0xfefdd000
-#define	IXDP2X01_CPLD_REGION_SIZE	0x1000
+#define	IXDP2X01_VIRT_CPLD_BASE		0xfafff000
+#define	IXDP2X01_CPLD_REGION_SIZE	0x00001000
 
-#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile u32*)(IXDP2X01_VIRT_CPLD_BASE | reg)
+#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg)
 #define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg)
 
 #define IXDP2X01_UART1_VIRT_BASE	IXDP2X01_CPLD_VIRT_REG(0x40)
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
--- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h
+++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
@@ -19,41 +19,57 @@
 #define _IXP2000_REGS_H_
 
 /* 
- * Static I/O regions. The manual defines each region as being several
- * MB in size, but all the registers are within the first 4K, so there's
- * no purpose in mapping the whole region in.
- */
-#define	IXP2000_SLOWPORT_CSR_PHYS_BASE	0xc0080000
-#define	IXP2000_SLOWPORT_CSR_VIRT_BASE	0xfefff000
-#define	IXP2000_SLOWPORT_CSR_SIZE	0x1000
-
-#define	IXP2000_GLOBAL_REG_PHYS_BASE	0xc0004000
-#define	IXP2000_GLOBAL_REG_VIRT_BASE	0xfeffe000
-#define	IXP2000_GLOBAL_REG_SIZE		0x1000
+ * Static I/O regions.
+ *
+ * Most of the registers are clumped in 4K regions spread throughout
+ * the 0xc0000000 -> 0xc0100000 address range, but we just map in
+ * the whole range using a single 1 MB section instead of small
+ * 4K pages.  This has two advantages for us:
+ *
+ * 1) We use only one TLB entry for large number of on-chip I/O devices.
+ *
+ * 2) We can easily set the Section attributes to XCB=101 on the IXP2400
+ *    as required per erratum #66.  We accomplish this by using a
+ *    new MT_IXP2000_DEVICE memory type with the bits set as required.
+ *
+ * CAP stands for CSR Access Proxy.
+ *
+ * If you change the virtual address of this mapping, please propagate
+ * the change to arch/arm/kernel/debug.S, which hardcodes the virtual
+ * address of the UART located in this region.
+ */
+
+#define	IXP2000_CAP_PHYS_BASE		0xc0000000
+#define	IXP2000_CAP_VIRT_BASE		0xfef00000
+#define	IXP2000_CAP_SIZE		0x00100000
 
+/*
+ * Addresses for specific on-chip peripherals
+ */
+#define	IXP2000_SLOWPORT_CSR_VIRT_BASE	0xfef80000
+#define	IXP2000_GLOBAL_REG_VIRT_BASE	0xfef04000
 #define	IXP2000_UART_PHYS_BASE		0xc0030000
 #define	IXP2000_UART_VIRT_BASE		0xfef30000
-#define IXP2000_UART_SIZE		0x1000
-
-#define	IXP2000_TIMER_PHYS_BASE		0xc0020000
-#define	IXP2000_TIMER_VIRT_BASE		0xfeffc000
-#define	IXP2000_TIMER_SIZE		0x1000
-
-#define	IXP2000_GPIO_PHYS_BASE		0xc0010000
-#define	IXP2000_GPIO_VIRT_BASE		0xfeffb000
-#define	IXP2000_GPIO_SIZE		0x1000
+#define	IXP2000_TIMER_VIRT_BASE		0xfef20000
+#define	IXP2000_GPIO_VIRT_BASE		0Xfef10000
 
+/*
+ * Devices outside of the 0xc0000000 -> 0xc0100000 range.  The virtual
+ * addresses of the INTCTL and PCI_CSR mappings are hardcoded in
+ * entry-macro.S, so if you ever change these please propagate
+ * the change.
+ */
 #define IXP2000_INTCTL_PHYS_BASE	0xd6000000
-#define	IXP2000_INTCTL_VIRT_BASE	0xfeffa000
-#define	IXP2000_INTCTL_SIZE		0x01000
+#define	IXP2000_INTCTL_VIRT_BASE	0xfee00000
+#define	IXP2000_INTCTL_SIZE		0x00100000
 
 #define IXP2000_PCI_CREG_PHYS_BASE	0xde000000
-#define	IXP2000_PCI_CREG_VIRT_BASE	0xfeff0000
-#define	IXP2000_PCI_CREG_SIZE		0x1000
+#define	IXP2000_PCI_CREG_VIRT_BASE	0xfed00000
+#define	IXP2000_PCI_CREG_SIZE		0x00100000
 
 #define IXP2000_PCI_CSR_PHYS_BASE	0xdf000000
-#define	IXP2000_PCI_CSR_VIRT_BASE	0xfefde000
-#define	IXP2000_PCI_CSR_SIZE		0x1000
+#define	IXP2000_PCI_CSR_VIRT_BASE	0xfec00000
+#define	IXP2000_PCI_CSR_SIZE		0x00100000
 
 #define IXP2000_PCI_IO_PHYS_BASE	0xd8000000
 #define	IXP2000_PCI_IO_VIRT_BASE	0xfd000000
@@ -67,7 +83,6 @@
 #define IXP2000_PCI_CFG1_VIRT_BASE	0xfb000000
 #define IXP2000_PCI_CFG1_SIZE		0x01000000
 
-
 /* 
  * Timers
  */
@@ -113,6 +128,30 @@
 #define IXP2000_IRQ_ERR_ENABLE_SET	IXP2000_INTCTL_REG(0x2c)
 #define IXP2000_FIQ_ERR_ENABLE_CLR	IXP2000_INTCTL_REG(0x30)
 #define IXP2000_IRQ_ERR_ENABLE_CLR	IXP2000_INTCTL_REG(0x34)
+#define IXP2000_IRQ_THD_RAW_STATUS_A_0	IXP2000_INTCTL_REG(0x60)
+#define IXP2000_IRQ_THD_RAW_STATUS_A_1	IXP2000_INTCTL_REG(0x64)
+#define IXP2000_IRQ_THD_RAW_STATUS_A_2	IXP2000_INTCTL_REG(0x68)
+#define IXP2000_IRQ_THD_RAW_STATUS_A_3	IXP2000_INTCTL_REG(0x6c)
+#define IXP2000_IRQ_THD_RAW_STATUS_B_0	IXP2000_INTCTL_REG(0x80)
+#define IXP2000_IRQ_THD_RAW_STATUS_B_1	IXP2000_INTCTL_REG(0x84)
+#define IXP2000_IRQ_THD_RAW_STATUS_B_2	IXP2000_INTCTL_REG(0x88)
+#define IXP2000_IRQ_THD_RAW_STATUS_B_3	IXP2000_INTCTL_REG(0x8c)
+#define IXP2000_IRQ_THD_ENABLE_SET_A_0	IXP2000_INTCTL_REG(0x160)
+#define IXP2000_IRQ_THD_ENABLE_SET_A_1	IXP2000_INTCTL_REG(0x164)
+#define IXP2000_IRQ_THD_ENABLE_SET_A_2	IXP2000_INTCTL_REG(0x168)
+#define IXP2000_IRQ_THD_ENABLE_SET_A_3	IXP2000_INTCTL_REG(0x16c)
+#define IXP2000_IRQ_THD_ENABLE_SET_B_0	IXP2000_INTCTL_REG(0x180)
+#define IXP2000_IRQ_THD_ENABLE_SET_B_1	IXP2000_INTCTL_REG(0x184)
+#define IXP2000_IRQ_THD_ENABLE_SET_B_2	IXP2000_INTCTL_REG(0x188)
+#define IXP2000_IRQ_THD_ENABLE_SET_B_3	IXP2000_INTCTL_REG(0x18c)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_0	IXP2000_INTCTL_REG(0x1e0)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_1	IXP2000_INTCTL_REG(0x1e4)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_2	IXP2000_INTCTL_REG(0x1e8)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_3	IXP2000_INTCTL_REG(0x1ec)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_0	IXP2000_INTCTL_REG(0x200)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_1	IXP2000_INTCTL_REG(0x204)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_2	IXP2000_INTCTL_REG(0x208)
+#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_3	IXP2000_INTCTL_REG(0x20c)
 
 /*
  * Mask of valid IRQs in the 32-bit IRQ register. We use
@@ -195,7 +234,7 @@
 
 #define IXP2000_PCICNTL_PNR		(1<<17)	/* PCI not Reset bit of PCI_CONTROL */
 #define IXP2000_PCICNTL_PCF		(1<<28)	/* PCI Centrolfunction bit */
-#define IXP2000_XSCALE_INT		(1<<1)	/* Interrupt from  XScale to PCI */
+#define IXP2000_XSCALE_INT		(1<<1)	/* Interrupt from XScale to PCI */
 
 /* These are from the IRQ register in the PCI ISR register */
 #define PCI_CONTROL_BE_DEO		(1 << 22)	/* Big Endian Data Enable Out */
diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h
--- a/include/asm-arm/arch-ixp2000/platform.h
+++ b/include/asm-arm/arch-ixp2000/platform.h
@@ -1,5 +1,5 @@
 /*
- * include/asm-arh/arch-ixp2000/platform.h
+ * include/asm-arm/arch-ixp2000/platform.h
  *
  * Various bits of code used by platform-level code.
  *
@@ -20,7 +20,7 @@
  * to on-chip I/O register to not complete fully. What this means is
  * that if you have a write to on-chip I/O followed by a back-to-back
  * read or write, the first write will happen twice. OR...if it's
- * not a back-to-back trasaction, the read or write will generate 
+ * not a back-to-back transaction, the read or write will generate
  * incorrect data.
  *
  * The official work around for this is to set the on-chip I/O regions
@@ -50,7 +50,7 @@ static inline void ixp2000_reg_write(vol
  * Boards may multiplex different devices on the 2nd channel of 
  * the slowport interface that each need different configuration 
  * settings.  For example, the IXDP2400 uses channel 2 on the interface 
- * to access the CPLD, the switch fabric card, and te media card.  Each 
+ * to access the CPLD, the switch fabric card, and the media card.  Each
  * one needs a different mode so drivers must save/restore the mode 
  * before and after each operation.  
  *
@@ -121,6 +121,7 @@ unsigned long ixp2000_gettimeoffset(void
 
 struct pci_sys_data;
 
+u32 *ixp2000_pci_config_addr(unsigned int bus, unsigned int devfn, int where);
 void ixp2000_pci_preinit(void);
 int ixp2000_pci_setup(int, struct pci_sys_data*);
 struct pci_bus* ixp2000_pci_scan_bus(int, struct pci_sys_data*);
diff --git a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h
--- a/include/asm-arm/arch-ixp2000/system.h
+++ b/include/asm-arm/arch-ixp2000/system.h
@@ -19,7 +19,7 @@ static inline void arch_idle(void)
 
 static inline void arch_reset(char mode)
 {
-	cli();
+	local_irq_disable();
 
 	/*
 	 * Reset flash banking register so that we are pointing at
diff --git a/include/asm-arm/arch-ixp2000/vmalloc.h b/include/asm-arm/arch-ixp2000/vmalloc.h
--- a/include/asm-arm/arch-ixp2000/vmalloc.h
+++ b/include/asm-arm/arch-ixp2000/vmalloc.h
@@ -17,7 +17,4 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_OFFSET	    (8*1024*1024)
-#define VMALLOC_START	    (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x)   ((unsigned long)(x))
-#define VMALLOC_END	    0xfb000000
+#define VMALLOC_END	    0xfaffefff
diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
--- a/include/asm-arm/arch-ixp4xx/platform.h
+++ b/include/asm-arm/arch-ixp4xx/platform.h
@@ -15,6 +15,12 @@
 
 #include <asm/types.h>
 
+#ifndef	__ARMEB__
+#define	REG_OFFSET	0
+#else
+#define	REG_OFFSET	3
+#endif
+
 /*
  * Expansion bus memory regions
  */
diff --git a/include/asm-arm/arch-ixp4xx/vmalloc.h b/include/asm-arm/arch-ixp4xx/vmalloc.h
--- a/include/asm-arm/arch-ixp4xx/vmalloc.h
+++ b/include/asm-arm/arch-ixp4xx/vmalloc.h
@@ -1,17 +1,5 @@
 /*
  * linux/include/asm-arm/arch-ixp4xx/vmalloc.h
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END       (0xFF000000)
 
diff --git a/include/asm-arm/arch-l7200/vmalloc.h b/include/asm-arm/arch-l7200/vmalloc.h
--- a/include/asm-arm/arch-l7200/vmalloc.h
+++ b/include/asm-arm/arch-l7200/vmalloc.h
@@ -1,15 +1,4 @@
 /*
  * linux/include/asm-arm/arch-l7200/vmalloc.h
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-lh7a40x/vmalloc.h b/include/asm-arm/arch-lh7a40x/vmalloc.h
--- a/include/asm-arm/arch-lh7a40x/vmalloc.h
+++ b/include/asm-arm/arch-lh7a40x/vmalloc.h
@@ -7,15 +7,4 @@
  *  version 2 as published by the Free Software Foundation.
  *
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after
- * the physical memory until the kernel virtual memory starts.  That
- * means that any out-of-bounds memory accesses will hopefully be
- * caught.  The vmalloc() routines leaves a hole of 4kB (one page)
- * between each vmalloced area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (0xe8000000)
diff --git a/include/asm-arm/arch-omap/aic23.h b/include/asm-arm/arch-omap/aic23.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-omap/aic23.h
@@ -0,0 +1,112 @@
+/*
+ * linux/include/asm-arm/arch-omap/aic23.h
+ *
+ * Hardware definitions for TI TLV320AIC23 audio codec
+ *
+ * Copyright (C) 2002 RidgeRun, Inc.
+ * Author: Steve Johnson
+ *
+ * This program is free software; you can redistribute it 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 __ASM_ARCH_AIC23_H
+#define __ASM_ARCH_AIC23_H
+
+// Codec TLV320AIC23
+#define LEFT_LINE_VOLUME_ADDR		0x00
+#define RIGHT_LINE_VOLUME_ADDR		0x01
+#define LEFT_CHANNEL_VOLUME_ADDR	0x02
+#define RIGHT_CHANNEL_VOLUME_ADDR	0x03
+#define ANALOG_AUDIO_CONTROL_ADDR	0x04
+#define DIGITAL_AUDIO_CONTROL_ADDR	0x05
+#define POWER_DOWN_CONTROL_ADDR		0x06
+#define DIGITAL_AUDIO_FORMAT_ADDR	0x07
+#define SAMPLE_RATE_CONTROL_ADDR	0x08
+#define DIGITAL_INTERFACE_ACT_ADDR	0x09
+#define RESET_CONTROL_ADDR		0x0F
+
+// Left (right) line input volume control register
+#define LRS_ENABLED			0x0100
+#define LIM_MUTED			0x0080
+#define LIV_DEFAULT			0x0017
+#define LIV_MAX				0x001f
+#define LIV_MIN				0x0000
+
+// Left (right) channel headphone volume control register
+#define LZC_ON				0x0080
+#define LHV_DEFAULT			0x0079
+#define LHV_MAX				0x007f
+#define LHV_MIN				0x0000
+
+// Analog audio path control register
+#define STE_ENABLED			0x0020
+#define DAC_SELECTED			0x0010
+#define BYPASS_ON			0x0008
+#define INSEL_MIC			0x0004
+#define MICM_MUTED			0x0002
+#define MICB_20DB			0x0001
+
+// Digital audio path control register
+#define DACM_MUTE			0x0008
+#define DEEMP_32K			0x0002
+#define DEEMP_44K			0x0004
+#define DEEMP_48K			0x0006
+#define ADCHP_ON			0x0001
+
+// Power control down register
+#define DEVICE_POWER_OFF	  	0x0080
+#define CLK_OFF				0x0040
+#define OSC_OFF				0x0020
+#define OUT_OFF				0x0010
+#define DAC_OFF				0x0008
+#define ADC_OFF				0x0004
+#define MIC_OFF				0x0002
+#define LINE_OFF			0x0001
+
+// Digital audio interface register
+#define MS_MASTER			0x0040
+#define LRSWAP_ON			0x0020
+#define LRP_ON				0x0010
+#define IWL_16				0x0000
+#define IWL_20				0x0004
+#define IWL_24				0x0008
+#define IWL_32				0x000C
+#define FOR_I2S				0x0002
+#define FOR_DSP				0x0003
+
+// Sample rate control register
+#define CLKOUT_HALF			0x0080
+#define CLKIN_HALF			0x0040
+#define BOSR_384fs			0x0002 // BOSR_272fs when in USB mode
+#define USB_CLK_ON			0x0001
+#define SR_MASK                         0xf
+#define CLKOUT_SHIFT                    7
+#define CLKIN_SHIFT                     6
+#define SR_SHIFT                        2
+#define BOSR_SHIFT                      1
+
+// Digital interface register
+#define ACT_ON				0x0001
+
+#define TLV320AIC23ID1                  (0x1a)	// cs low
+#define TLV320AIC23ID2                  (0x1b)	// cs high
+
+#endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-omap/board-h2.h b/include/asm-arm/arch-omap/board-h2.h
--- a/include/asm-arm/arch-omap/board-h2.h
+++ b/include/asm-arm/arch-omap/board-h2.h
@@ -21,8 +21,8 @@
  * (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.,
+ * You 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.
  */
 
@@ -32,9 +32,7 @@
 /* Placeholder for H2 specific defines */
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
-#define OMAP1610_ETHR_BASE		0xE8000000
-#define OMAP1610_ETHR_SIZE		SZ_4K
-#define OMAP1610_ETHR_START		0x04000000
+#define OMAP1610_ETHR_START		0x04000300
 
 /* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
 #define OMAP_NOR_FLASH_SIZE             SZ_32M
diff --git a/include/asm-arm/arch-omap/board-h3.h b/include/asm-arm/arch-omap/board-h3.h
--- a/include/asm-arm/arch-omap/board-h3.h
+++ b/include/asm-arm/arch-omap/board-h3.h
@@ -28,9 +28,7 @@
 #define __ASM_ARCH_OMAP_H3_H
 
 /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
-#define OMAP1710_ETHR_BASE		0xE8000000
-#define OMAP1710_ETHR_SIZE		SZ_4K
-#define OMAP1710_ETHR_START		0x04000000
+#define OMAP1710_ETHR_START		0x04000300
 
 /* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
 #define OMAP_NOR_FLASH_SIZE             SZ_32M
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -21,8 +21,8 @@
  * (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.,
+ * You 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.
  */
 
diff --git a/include/asm-arm/arch-omap/board-innovator.h b/include/asm-arm/arch-omap/board-innovator.h
--- a/include/asm-arm/arch-omap/board-innovator.h
+++ b/include/asm-arm/arch-omap/board-innovator.h
@@ -19,8 +19,8 @@
  * (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.,
+ * You 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 __ASM_ARCH_OMAP_INNOVATOR_H
@@ -74,8 +74,7 @@ unsigned char fpga_read(int reg);
 #if defined (CONFIG_ARCH_OMAP16XX)
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
-#define INNOVATOR1610_ETHR_START	0x04000000
-#define INNOVATOR1610_ETHR_SIZE		SZ_4K
+#define INNOVATOR1610_ETHR_START	0x04000300
 
 #endif /* CONFIG_ARCH_OMAP1610 */
 #endif /* __ASM_ARCH_OMAP_INNOVATOR_H */
diff --git a/include/asm-arm/arch-omap/board-netstar.h b/include/asm-arm/arch-omap/board-netstar.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-omap/board-netstar.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Hardware definitions for OMAP5910 based NetStar board.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_NETSTAR_H
+#define __ASM_ARCH_NETSTAR_H
+
+#include <asm/arch/tc.h>
+
+#define OMAP_NAND_FLASH_START1		OMAP_CS1_PHYS + (1 << 23)
+#define OMAP_NAND_FLASH_START2		OMAP_CS1_PHYS + (2 << 23)
+
+#endif /*  __ASM_ARCH_NETSTAR_H */
diff --git a/include/asm-arm/arch-omap/board-osk.h b/include/asm-arm/arch-omap/board-osk.h
--- a/include/asm-arm/arch-omap/board-osk.h
+++ b/include/asm-arm/arch-omap/board-osk.h
@@ -21,8 +21,8 @@
  * (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.,
+ * You 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.
  */
 
@@ -30,9 +30,7 @@
 #define __ASM_ARCH_OMAP_OSK_H
 
 /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
-#define OMAP_OSK_ETHR_BASE		0xE8800000
-#define OMAP_OSK_ETHR_SIZE		SZ_4K
-#define OMAP_OSK_ETHR_START		0x04800000
+#define OMAP_OSK_ETHR_START		0x04800300
 
 /* Micron NOR flash at CS3 mapped to address 0x0 if BM bit is 1 */
 #define OMAP_OSK_NOR_FLASH_BASE		0xD8000000
diff --git a/include/asm-arm/arch-omap/board-voiceblue.h b/include/asm-arm/arch-omap/board-voiceblue.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-omap/board-voiceblue.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Hardware definitions for OMAP5910 based VoiceBlue board.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_VOICEBLUE_H
+#define __ASM_ARCH_VOICEBLUE_H
+
+#if (EXTERNAL_MAX_NR_PORTS < 4)
+#undef EXTERNAL_MAX_NR_PORTS
+#define EXTERNAL_MAX_NR_PORTS	4
+#endif
+
+extern void voiceblue_wdt_enable(void);
+extern void voiceblue_wdt_disable(void);
+extern void voiceblue_wdt_ping(void);
+extern void voiceblue_reset(void);
+
+#endif /*  __ASM_ARCH_VOICEBLUE_H */
+
diff --git a/include/asm-arm/arch-omap/clocks.h b/include/asm-arm/arch-omap/clocks.h
deleted file mode 100644
--- a/include/asm-arm/arch-omap/clocks.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * OMAP clock interface
- *
- * Copyright (C) 2001 RidgeRun, Inc
- * Written by Gordon McNutt <gmcnutt@ridgerun.com>
- * Updated 2004 for Linux 2.6 by Tony Lindgren <tony@atomide.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.
- */
-
-#ifndef __ASM_ARM_CLOCKS_H
-#define __ASM_ARM_CLOCKS_H
-
-#include <linux/config.h>
-
-/* ARM_CKCTL bit shifts */
-#define PERDIV			0
-#define LCDDIV			2
-#define ARMDIV			4
-#define DSPDIV			6
-#define TCDIV			8
-#define DSPMMUDIV		10
-#define ARM_TIMXO		12
-#define EN_DSPCK		13
-#define ARM_INTHCK_SEL		14 /* REVISIT: Where is this used? */
-
-/* ARM_IDLECT1 bit shifts */
-#define IDLWDT_ARM	0
-#define IDLXORP_ARM	1
-#define IDLPER_ARM	2
-#define IDLLCD_ARM	3
-#define IDLLB_ARM	4
-#define IDLHSAB_ARM	5
-#define IDLIF_ARM	6
-#define IDLDPLL_ARM	7
-#define IDLAPI_ARM	8
-#define IDLTIM_ARM	9
-#define SETARM_IDLE	11
-
-/* ARM_IDLECT2 bit shifts */
-#define EN_WDTCK	0
-#define EN_XORPCK	1
-#define EN_PERCK	2
-#define EN_LCDCK	3
-#define EN_LBCK		4
-#define EN_HSABCK	5
-#define EN_APICK	6
-#define EN_TIMCK	7
-#define DMACK_REQ	8
-#define EN_GPIOCK	9
-#define EN_LBFREECK	10
-
-/*
- * OMAP clocks
- */
-typedef enum {
-	/* Fixed system clock */
-	OMAP_CLKIN = 0,
-
-	/* DPLL1 */
-	OMAP_CK_GEN1, OMAP_CK_GEN2, OMAP_CK_GEN3,
-
-	/* TC usually needs to be checked before anything else */
-	OMAP_TC_CK,
-
-	/* CLKM1 */
-	OMAP_ARM_CK, OMAP_MPUPER_CK, OMAP_ARM_GPIO_CK, OMAP_MPUXOR_CK,
-	OMAP_MPUTIM_CK, OMAP_MPUWD_CK,
-
-	/* CLKM2 */
-	OMAP_DSP_CK, OMAP_DSPMMU_CK,
-#if 0
-	/* Accessible only from the dsp */
-	OMAP_DSPPER_CK, OMAP_GPIO_CK, OMAP_DSPXOR_CK, OMAP_DSPTIM_CK,
-	OMAP_DSPWD_CK, OMAP_UART_CK,
-#endif
-	/* CLKM3 */
-	OMAP_DMA_CK, OMAP_API_CK, OMAP_HSAB_CK, OMAP_LBFREE_CK,
-	OMAP_LB_CK, OMAP_LCD_CK
-} ck_t;
-
-typedef enum {
-	/* Reset the MPU */
-	OMAP_ARM_RST,
-
-	/* Reset the DSP */
-	OMAP_DSP_RST,
-
-	/* Reset priority registers, EMIF config, and MPUI control logic */
-	OMAP_API_RST,
-
-	/* Reset DSP, MPU, and Peripherals */
-	OMAP_SW_RST,
-} reset_t;
-
-#define OMAP_CK_MIN			OMAP_CLKIN
-#define OMAP_CK_MAX			OMAP_LCD_CK
-
-#if defined(CONFIG_OMAP_ARM_30MHZ)
-#define OMAP_CK_MAX_RATE		30
-#elif defined(CONFIG_OMAP_ARM_60MHZ)
-#define OMAP_CK_MAX_RATE		60
-#elif defined(CONFIG_OMAP_ARM_96MHZ)
-#define OMAP_CK_MAX_RATE		96
-#elif defined(CONFIG_OMAP_ARM_120MHZ)
-#define OMAP_CK_MAX_RATE		120
-#elif defined(CONFIG_OMAP_ARM_168MHZ)
-#define OMAP_CK_MAX_RATE		168
-#elif defined(CONFIG_OMAP_ARM_182MHZ)
-#define OMAP_CK_MAX_RATE		182
-#elif defined(CONFIG_OMAP_ARM_192MHZ)
-#define OMAP_CK_MAX_RATE		192
-#elif defined(CONFIG_OMAP_ARM_195MHZ)
-#define OMAP_CK_MAX_RATE		195
-#endif
-
-#define CK_DPLL_MASK			0x0fe0
-
-/* Shared by CK and DSPC */
-#define MPUI_STROBE_MAX_1509		24
-#define MPUI_STROBE_MAX_1510		30
-
-/*
- * ----------------------------------------------------------------------------
- * Clock interface functions
- * ----------------------------------------------------------------------------
- */
-
-/*  Clock initialization.  */
-int init_ck(void);
-
-/*
- * For some clocks you have a choice of which "parent" clocks they are derived
- * from. Use this to select a "parent". See the platform documentation for
- * valid combinations.
- */
-int ck_can_set_input(ck_t);
-int ck_set_input(ck_t ck, ck_t input);
-int ck_get_input(ck_t ck, ck_t *input);
-
-/*
- * Use this to set a clock rate. If other clocks are derived from this one,
- * their rates will all change too. If this is a derived clock and I can't
- * change it to match your request unless I also change the parent clock, then
- * tough luck -- I won't change the parent automatically. I'll return an error
- * if I can't get the clock within 10% of what you want. Otherwise I'll return
- * the value I actually set it to. If I have to switch parents to get the rate
- * then I will do this automatically (since it only affects this clock and its
- * descendants).
- */
-int ck_can_set_rate(ck_t);
-int ck_set_rate(ck_t ck, int val_in_mhz);
-int ck_get_rate(ck_t ck);
-
-/*
- * Use this to get a bitmap of available rates for the clock. Caller allocates
- *  the buffer and passes in the length. Clock module fills up to len bytes of
- *  the buffer & passes back actual bytes used.
- */
-int ck_get_rates(ck_t ck, void *buf, int len);
-int ck_valid_rate(int rate);
-
-/*
- * Idle a clock. What happens next depends on the clock ;). For example, if
- * you idle the ARM_CK you might well end up in sleep mode on some platforms.
- * If you try to idle a clock that doesn't support it I'll return an error.
- * Note that idling a clock does not always take affect until certain h/w
- * conditions are met. Consult the platform specs to learn more.
- */
-int ck_can_idle(ck_t);
-int ck_idle(ck_t);
-int ck_activate(ck_t);
-int ck_is_idle(ck_t);
-
-/*
- * Enable/disable a clock. I'll return an error if the h/w doesn't support it.
- * If you disable a clock being used by an active device then you probably
- * just screwed it. YOU are responsible for making sure this doesn't happen.
- */
-int ck_can_disable(ck_t);
-int ck_enable(ck_t);
-int ck_disable(ck_t);
-int ck_is_enabled(ck_t);
-
-/* Enable/reset ARM peripherals (remove/set reset signal) */
-void ck_enable_peripherals(void);
-void ck_reset_peripherals(void);
-
-/* Generate/clear a MPU or DSP reset */
-void ck_generate_reset(reset_t reset);
-void ck_release_from_reset(reset_t reset);
-
-/* This gets a string representation of the clock's name. Useful for proc. */
-char *ck_get_name(ck_t);
-
-extern void start_mputimer1(unsigned long);
-
-#endif
diff --git a/include/asm-arm/arch-omap/fpga.h b/include/asm-arm/arch-omap/fpga.h
--- a/include/asm-arm/arch-omap/fpga.h
+++ b/include/asm-arm/arch-omap/fpga.h
@@ -38,8 +38,7 @@ extern void omap1510_fpga_init_irq(void)
 #define H2P2_DBG_FPGA_SIZE		SZ_4K		/* SIZE */
 #define H2P2_DBG_FPGA_START		0x04000000	/* PA */
 
-#define H2P2_DBG_FPGA_ETHR_START	H2P2_DBG_FPGA_START
-#define H2P2_DBG_FPGA_ETHR_BASE		H2P2_DBG_FPGA_BASE
+#define H2P2_DBG_FPGA_ETHR_START	(H2P2_DBG_FPGA_START + 0x300)
 #define H2P2_DBG_FPGA_FPGA_REV		(H2P2_DBG_FPGA_BASE + 0x10)	/* FPGA Revision */
 #define H2P2_DBG_FPGA_BOARD_REV		(H2P2_DBG_FPGA_BASE + 0x12)	/* Board Revision */
 #define H2P2_DBG_FPGA_GPIO		(H2P2_DBG_FPGA_BASE + 0x14)	/* GPIO outputs */
@@ -48,12 +47,31 @@ extern void omap1510_fpga_init_irq(void)
 #define H2P2_DBG_FPGA_LAN_STATUS	(H2P2_DBG_FPGA_BASE + 0x1A)	/* LAN Status line */
 #define H2P2_DBG_FPGA_LAN_RESET		(H2P2_DBG_FPGA_BASE + 0x1C)	/* LAN Reset line */
 
-/* LEDs definition on debug board (16 LEDs) */
-#define H2P2_DBG_FPGA_LED_CLAIMRELEASE	(1 << 15)
-#define H2P2_DBG_FPGA_LED_STARTSTOP	(1 << 14)
-#define H2P2_DBG_FPGA_LED_HALTED	(1 << 13)
-#define H2P2_DBG_FPGA_LED_IDLE		(1 << 12)
-#define H2P2_DBG_FPGA_LED_TIMER		(1 << 11)
+/* NOTE:  most boards don't have a static mapping for the FPGA ... */
+struct h2p2_dbg_fpga {
+	/* offset 0x00 */
+	u16		smc91x[8];
+	/* offset 0x10 */
+	u16		fpga_rev;
+	u16		board_rev;
+	u16		gpio_outputs;
+	u16		leds;
+	/* offset 0x18 */
+	u16		misc_inputs;
+	u16		lan_status;
+	u16		lan_reset;
+	u16		reserved0;
+	/* offset 0x20 */
+	u16		ps2_data;
+	u16		ps2_ctrl;
+	/* plus also 4 rs232 ports ... */
+};
+
+/* LEDs definition on debug board (16 LEDs, all physically green) */
+#define H2P2_DBG_FPGA_LED_GREEN		(1 << 15)
+#define H2P2_DBG_FPGA_LED_AMBER		(1 << 14)
+#define H2P2_DBG_FPGA_LED_RED		(1 << 13)
+#define H2P2_DBG_FPGA_LED_BLUE		(1 << 12)
 /*  cpu0 load-meter LEDs */
 #define H2P2_DBG_FPGA_LOAD_METER	(1 << 0)	// A bit of fun on our board ...
 #define H2P2_DBG_FPGA_LOAD_METER_SIZE	11
@@ -116,7 +134,6 @@ extern void omap1510_fpga_init_irq(void)
 #define INNOVATOR_FPGA_IMR2			(OMAP1510_FPGA_BASE + 0x210)
 
 #define OMAP1510_FPGA_ETHR_START		(OMAP1510_FPGA_START + 0x300)
-#define OMAP1510_FPGA_ETHR_BASE			(OMAP1510_FPGA_BASE + 0x300)
 
 /*
  * Power up Giga UART driver, turn on HID clock.
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -89,58 +89,31 @@
 #define ULPD_REG_BASE		(0xfffe0800)
 #define ULPD_IT_STATUS		(ULPD_REG_BASE + 0x14)
 #define ULPD_CLOCK_CTRL		(ULPD_REG_BASE + 0x30)
+#	define DIS_USB_PVCI_CLK		(1 << 5)	/* no USB/FAC synch */
+#	define USB_MCLK_EN		(1 << 4)	/* enable W4_USB_CLKO */
 #define ULPD_SOFT_REQ		(ULPD_REG_BASE + 0x34)
+#	define SOFT_UDC_REQ		(1 << 4)
+#	define SOFT_USB_CLK_REQ		(1 << 3)
+#	define SOFT_DPLL_REQ		(1 << 0)
 #define ULPD_DPLL_CTRL		(ULPD_REG_BASE + 0x3c)
 #define ULPD_STATUS_REQ		(ULPD_REG_BASE + 0x40)
 #define ULPD_APLL_CTRL		(ULPD_REG_BASE + 0x4c)
 #define ULPD_POWER_CTRL		(ULPD_REG_BASE + 0x50)
+#define ULPD_SOFT_DISABLE_REQ_REG	(ULPD_REG_BASE + 0x68)
+#	define DIS_MMC2_DPLL_REQ	(1 << 11)
+#	define DIS_MMC1_DPLL_REQ	(1 << 10)
+#	define DIS_UART3_DPLL_REQ	(1 << 9)
+#	define DIS_UART2_DPLL_REQ	(1 << 8)
+#	define DIS_UART1_DPLL_REQ	(1 << 7)
+#	define DIS_USB_HOST_DPLL_REQ	(1 << 6)
+#define ULPD_SDW_CLK_DIV_CTRL_SEL	(ULPD_REG_BASE + 0x74)
 #define ULPD_CAM_CLK_CTRL	(ULPD_REG_BASE + 0x7c)
 
 /*
  * ---------------------------------------------------------------------------
- * Timers
+ * Watchdog timer
  * ---------------------------------------------------------------------------
  */
-#define OMAP_32kHz_TIMER_BASE 0xfffb9000
-
-/* 32k Timer Registers */
-#define TIMER32k_CR		0x08
-#define TIMER32k_TVR		0x00
-#define TIMER32k_TCR		0x04
-
-/* 32k Timer Control Register definition */
-#define TIMER32k_TSS		(1<<0)
-#define TIMER32k_TRB		(1<<1)
-#define TIMER32k_INT		(1<<2)
-#define TIMER32k_ARL		(1<<3)
-
-/* MPU Timer base addresses */
-#define OMAP_TIMER1_BASE	(0xfffec500)
-#define OMAP_TIMER2_BASE	(0xfffec600)
-#define OMAP_TIMER3_BASE	(0xfffec700)
-#define OMAP_MPUTIMER_BASE	OMAP_TIMER1_BASE
-#define OMAP_MPUTIMER_OFFSET	0x100
-
-/* MPU Timer Registers */
-#define OMAP_TIMER1_CNTL	(OMAP_TIMER_BASE1 + 0x0)
-#define OMAP_TIMER1_LOAD_TIM	(OMAP_TIMER_BASE1 + 0x4)
-#define OMAP_TIMER1_READ_TIM	(OMAP_TIMER_BASE1 + 0x8)
-
-#define OMAP_TIMER2_CNTL	(OMAP_TIMER_BASE2 + 0x0)
-#define OMAP_TIMER2_LOAD_TIM	(OMAP_TIMER_BASE2 + 0x4)
-#define OMAP_TIMER2_READ_TIM	(OMAP_TIMER_BASE2 + 0x8)
-
-#define OMAP_TIMER3_CNTL	(OMAP_TIMER_BASE3 + 0x0)
-#define OMAP_TIMER3_LOAD_TIM	(OMAP_TIMER_BASE3 + 0x4)
-#define OMAP_TIMER3_READ_TIM	(OMAP_TIMER_BASE3 + 0x8)
-
-/* CNTL_TIMER register bits */
-#define MPUTIM_FREE		(1<<6)
-#define MPUTIM_CLOCK_ENABLE	(1<<5)
-#define MPUTIM_PTV_MASK		(0x7<<MPUTIM_PTV_BIT)
-#define MPUTIM_PTV_BIT		2
-#define MPUTIM_AR		(1<<1)
-#define MPUTIM_ST		(1<<0)
 
 /* Watchdog timer within the OMAP3.2 gigacell */
 #define OMAP_MPU_WATCHDOG_BASE	(0xfffec800)
@@ -183,29 +156,6 @@
 #define IRQ_GMR_REG_OFFSET	0xa0
 
 /*
- * ---------------------------------------------------------------------------
- * Traffic controller memory interface
- * ---------------------------------------------------------------------------
- */
-#define TCMIF_BASE		0xfffecc00
-#define IMIF_PRIO		(TCMIF_BASE + 0x00)
-#define EMIFS_PRIO		(TCMIF_BASE + 0x04)
-#define EMIFF_PRIO		(TCMIF_BASE + 0x08)
-#define EMIFS_CONFIG		(TCMIF_BASE + 0x0c)
-#define EMIFS_CS0_CONFIG	(TCMIF_BASE + 0x10)
-#define EMIFS_CS1_CONFIG	(TCMIF_BASE + 0x14)
-#define EMIFS_CS2_CONFIG	(TCMIF_BASE + 0x18)
-#define EMIFS_CS3_CONFIG	(TCMIF_BASE + 0x1c)
-#define EMIFF_SDRAM_CONFIG	(TCMIF_BASE + 0x20)
-#define EMIFF_MRS		(TCMIF_BASE + 0x24)
-#define TC_TIMEOUT1		(TCMIF_BASE + 0x28)
-#define TC_TIMEOUT2		(TCMIF_BASE + 0x2c)
-#define TC_TIMEOUT3		(TCMIF_BASE + 0x30)
-#define TC_ENDIANISM		(TCMIF_BASE + 0x34)
-#define EMIFF_SDRAM_CONFIG_2	(TCMIF_BASE + 0x3c)
-#define EMIF_CFG_DYNAMIC_WS	(TCMIF_BASE + 0x40)
-
-/*
  * ----------------------------------------------------------------------------
  * System control registers
  * ----------------------------------------------------------------------------
@@ -279,6 +229,18 @@
 #define MPUI_DSP_BOOT_CONFIG		(MPUI_BASE + 0x18)
 #define MPUI_DSP_API_CONFIG		(MPUI_BASE + 0x1c)
 
+/*
+ * ----------------------------------------------------------------------------
+ * LED Pulse Generator
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_LPG1_BASE			0xfffbd000
+#define OMAP_LPG2_BASE			0xfffbd800
+#define OMAP_LPG1_LCR			(OMAP_LPG1_BASE + 0x00)
+#define OMAP_LPG1_PMR			(OMAP_LPG1_BASE + 0x04)
+#define OMAP_LPG2_LCR			(OMAP_LPG2_BASE + 0x00)
+#define OMAP_LPG2_PMR			(OMAP_LPG2_BASE + 0x04)
+
 #ifndef __ASSEMBLER__
 
 /*
@@ -293,12 +255,12 @@
 #define OMAP1510_BASE_BAUD	(12000000/16)
 #define OMAP16XX_BASE_BAUD	(48000000/16)
 
-#define is_omap_port(p)	({int __ret = 0;				\
-			if (p == (char*)IO_ADDRESS(OMAP_UART1_BASE) ||	\
-			    p == (char*)IO_ADDRESS(OMAP_UART2_BASE) ||	\
-			    p == (char*)IO_ADDRESS(OMAP_UART3_BASE))	\
-				__ret = 1;				\
-			__ret;						\
+#define is_omap_port(p)	({int __ret = 0;			\
+			if (p == IO_ADDRESS(OMAP_UART1_BASE) ||	\
+			    p == IO_ADDRESS(OMAP_UART2_BASE) ||	\
+			    p == IO_ADDRESS(OMAP_UART3_BASE))	\
+				__ret = 1;			\
+			__ret;					\
 			})
 
 /*
@@ -349,6 +311,14 @@
 #include "board-osk.h"
 #endif
 
+#ifdef CONFIG_MACH_VOICEBLUE
+#include "board-voiceblue.h"
+#endif
+
+#ifdef CONFIG_MACH_NETSTAR
+#include "board-netstar.h"
+#endif
+
 #endif /* !__ASSEMBLER__ */
 
 #endif	/* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -149,9 +149,16 @@
 #define INT_1610_McBSP2RX_OF	(31 + IH2_BASE)
 #define INT_1610_STI		(32 + IH2_BASE)
 #define INT_1610_STI_WAKEUP	(33 + IH2_BASE)
+#define INT_1610_GPTIMER3	(34 + IH2_BASE)
+#define INT_1610_GPTIMER4	(35 + IH2_BASE)
+#define INT_1610_GPTIMER5	(36 + IH2_BASE)
+#define INT_1610_GPTIMER6	(37 + IH2_BASE)
+#define INT_1610_GPTIMER7	(38 + IH2_BASE)
+#define INT_1610_GPTIMER8	(39 + IH2_BASE)
 #define INT_1610_GPIO_BANK2	(40 + IH2_BASE)
 #define INT_1610_GPIO_BANK3	(41 + IH2_BASE)
 #define INT_1610_MMC2		(42 + IH2_BASE)
+#define INT_1610_CF		(43 + IH2_BASE)
 #define INT_1610_GPIO_BANK4	(48 + IH2_BASE)
 #define INT_1610_SPI		(49 + IH2_BASE)
 #define INT_1610_DMA_CH6	(53 + IH2_BASE)
diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
--- a/include/asm-arm/arch-omap/mcbsp.h
+++ b/include/asm-arm/arch-omap/mcbsp.h
@@ -250,4 +250,8 @@ int omap_mcbsp_recv_buffer(unsigned int 
 /* SPI specific API */
 void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
 
+/* Polled read/write functions */
+int omap_mcbsp_pollread(unsigned int id, u16 * buf);
+int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
+
 #endif
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h
--- a/include/asm-arm/arch-omap/memory.h
+++ b/include/asm-arm/arch-omap/memory.h
@@ -25,8 +25,8 @@
  * (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.,
+ * You 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.
  */
 
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -174,6 +174,7 @@ typedef enum {
 	M14_1510_GPIO2,
 
 	/* OMAP1610 GPIO */
+	P18_1610_GPIO3,
 	Y15_1610_GPIO17,
 
 	/* OMAP-1710 GPIO */
@@ -239,6 +240,7 @@ typedef enum {
 	V5_1610_GPIO24,
 	AA20_1610_GPIO_41,
 	W19_1610_GPIO48,
+	M7_1610_GPIO62,
 
 	/* OMAP-1610 uWire */
 	V19_1610_UWIRE_SCLK,
@@ -316,6 +318,12 @@ typedef enum {
 	R10_1610_MCLK_ON,
 	R10_1610_MCLK_OFF,
 
+	/* CompactFlash controller */
+	P11_1610_CF_CD2,
+	R11_1610_CF_IOIS16,
+	V10_1610_CF_IREQ,
+	W10_1610_CF_RESET,
+	W11_1610_CF_CD1,
 } reg_cfg_t;
 
 #if defined(__MUX_C__) && defined(CONFIG_OMAP_MUX)
@@ -355,7 +363,8 @@ MUX_CFG("PWL",		 	 6,    3,    1,	  0,  
 /* USB internal master generic */
 MUX_CFG("R18_USB_VBUS",		 7,    9,    2,	  1,  11,   0,	 NA,	 0,  1)
 MUX_CFG("R18_1510_USB_GPIO0",	 7,    9,    0,	  1,  11,   1,	 NA,	 0,  1)
-MUX_CFG("W4_USB_PUEN",		 D,    3,    0,	  3,   5,   1,	 NA,	 0,  1)
+/* works around erratum:  W4_USB_PUEN and W4_USB_PUDIS are switched! */
+MUX_CFG("W4_USB_PUEN",		 D,    3,    3,	  3,   5,   1,	 NA,	 0,  1)
 MUX_CFG("W4_USB_CLKO",		 D,    3,    1,	  3,   5,   0,	 NA,	 0,  1)
 MUX_CFG("W4_USB_HIGHZ",		 D,    3,    4,	  3,   5,   0,	  3,	 0,  1)
 MUX_CFG("W4_GPIO58",		 D,    3,    7,	  3,   5,   0,	  3,	 0,  1)
@@ -388,6 +397,7 @@ MUX_CFG("R19_1510_GPIO1",	 7,    6,    0
 MUX_CFG("M14_1510_GPIO2",	 7,    3,    0,   1,   9,   1,    0,     0,  1)
 
 /* OMAP1610 GPIO */
+MUX_CFG("P18_1610_GPIO3",	 7,    0,    0,   1,   8,   0,   NA,     0,  1)
 MUX_CFG("Y15_1610_GPIO17",	 A,    0,    7,   2,   6,   0,   NA,     0,  1)
 
 /* OMAP-1710 GPIO */
@@ -454,6 +464,7 @@ MUX_CFG("P10_1610_GPIO22",	 C,    0,    
 MUX_CFG("V5_1610_GPIO24",	 B,   15,    7,	  2,  21,   0,	  2,	 1,  1)
 MUX_CFG("AA20_1610_GPIO_41",	 9,    9,    7,	  1,  31,   0,	  1,	 1,  1)
 MUX_CFG("W19_1610_GPIO48",	 8,   15,    7,   1,  23,   1,    1,     0,  1)
+MUX_CFG("M7_1610_GPIO62",	10,    0,    0,   4,  24,   0,    4,     0,  1)
 
 /* OMAP-1610 uWire */
 MUX_CFG("V19_1610_UWIRE_SCLK",	 8,    6,    0,	  1,  20,   0,	  1,	 1,  1)
@@ -528,6 +539,13 @@ MUX_CFG("V5_1710_MCLK_ON",	 B,   15,    
 MUX_CFG("V5_1710_MCLK_OFF",	 B,   15,    6,	  NA,   0,   0,   NA,	 0,  0)
 MUX_CFG("R10_1610_MCLK_ON",	 B,   18,    0,	  NA,  22,   0,	  NA,	 1,  0)
 MUX_CFG("R10_1610_MCLK_OFF",	 B,   18,    6,	  2,   22,   1,	  2,	 1,  1)
+
+/* CompactFlash controller, conflicts with MMC1 */
+MUX_CFG("P11_1610_CF_CD2",	 A,   27,    3,	  2,   15,   1,	  2,	 1,  1)
+MUX_CFG("R11_1610_CF_IOIS16",	 B,    0,    3,	  2,   16,   1,	  2,	 1,  1)
+MUX_CFG("V10_1610_CF_IREQ",	 A,   24,    3,	  2,   14,   0,	  2,	 0,  1)
+MUX_CFG("W10_1610_CF_RESET",	 A,   18,    3,	  2,   12,   1,	  2,	 1,  1)
+MUX_CFG("W11_1610_CF_CD1",	10,   15,    3,	  3,    8,   1,	  3,	 1,  1)
 };
 
 #endif	/* __MUX_C__ */
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -121,6 +121,13 @@
 #define OMAP16XX_SUBLVDS_CONF_VALID	(1 << 13)
 
 /*
+ * ----------------------------------------------------------------------------
+ * System control registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP1610_RESET_CONTROL  0xfffe1140
+
+/*
  * ---------------------------------------------------------------------------
  * TIPB bus interface
  * ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/param.h b/include/asm-arm/arch-omap/param.h
--- a/include/asm-arm/arch-omap/param.h
+++ b/include/asm-arm/arch-omap/param.h
@@ -1,24 +1,8 @@
 /*
  *  linux/include/asm-arm/arch-omap/param.h
  *
- *  Initially based on linux/include/asm-arm/arch-integrator/param.h
- *  Copyright (C) 1999 ARM Limited
- *
- *  BRIEF MODULE DESCRIPTION
- *   a place holder
- *
- * This program is free software; you can redistribute it 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 CONFIG_OMAP_32K_TIMER_HZ
+#define HZ	CONFIG_OMAP_32K_TIMER_HZ
+#endif
diff --git a/include/asm-arm/arch-omap/tc.h b/include/asm-arm/arch-omap/tc.h
--- a/include/asm-arm/arch-omap/tc.h
+++ b/include/asm-arm/arch-omap/tc.h
@@ -24,22 +24,33 @@
 #ifndef __ASM_ARCH_TC_H
 #define __ASM_ARCH_TC_H
 
-#define OMAP_TC_OCPT1_PRIOR	0xFFFECC00
-#define OMAP_TC_EMIFS_PRIOR	0xFFFECC04
-#define OMAP_TC_EMIFF_PRIOR	0xFFFECC08
-#define OMAP_TC_OCPT2_PRIOR	0xFFFECCD0
-
-
-/* EMIF Slow Interface Configuration Register */
-#define	OMAP_EMIFS_CONFIG_REG	__REG32(EMIFS_CONFIG)
-
-#define OMAP_EMIFS_CONFIG_FR		(1 << 4)
-#define OMAP_EMIFS_CONFIG_PDE		(1 << 3)
-#define OMAP_EMIFS_CONFIG_PWD_EN	(1 << 2)
-#define OMAP_EMIFS_CONFIG_BM		(1 << 1)
-#define OMAP_EMIFS_CONFIG_WP		(1 << 0)
+#define TCMIF_BASE		0xfffecc00
+#define OMAP_TC_OCPT1_PRIOR	(TCMIF_BASE + 0x00)
+#define OMAP_TC_EMIFS_PRIOR	(TCMIF_BASE + 0x04)
+#define OMAP_TC_EMIFF_PRIOR	(TCMIF_BASE + 0x08)
+#define EMIFS_CONFIG		(TCMIF_BASE + 0x0c)
+#define EMIFS_CS0_CONFIG	(TCMIF_BASE + 0x10)
+#define EMIFS_CS1_CONFIG	(TCMIF_BASE + 0x14)
+#define EMIFS_CS2_CONFIG	(TCMIF_BASE + 0x18)
+#define EMIFS_CS3_CONFIG	(TCMIF_BASE + 0x1c)
+#define EMIFF_SDRAM_CONFIG	(TCMIF_BASE + 0x20)
+#define EMIFF_MRS		(TCMIF_BASE + 0x24)
+#define TC_TIMEOUT1		(TCMIF_BASE + 0x28)
+#define TC_TIMEOUT2		(TCMIF_BASE + 0x2c)
+#define TC_TIMEOUT3		(TCMIF_BASE + 0x30)
+#define TC_ENDIANISM		(TCMIF_BASE + 0x34)
+#define EMIFF_SDRAM_CONFIG_2	(TCMIF_BASE + 0x3c)
+#define EMIF_CFG_DYNAMIC_WS	(TCMIF_BASE + 0x40)
+#define EMIFS_ACS0		(TCMIF_BASE + 0x50)
+#define EMIFS_ACS1		(TCMIF_BASE + 0x54)
+#define EMIFS_ACS2		(TCMIF_BASE + 0x58)
+#define EMIFS_ACS3		(TCMIF_BASE + 0x5c)
+#define OMAP_TC_OCPT2_PRIOR	(TCMIF_BASE + 0xd0)
 
 /* external EMIFS chipselect regions */
+#define	OMAP_CS0_PHYS		0x00000000
+#define	OMAP_CS0_SIZE		SZ_64M
+
 #define	OMAP_CS1_PHYS		0x04000000
 #define	OMAP_CS1_SIZE		SZ_64M
 
@@ -61,4 +72,37 @@
 #define	OMAP_CS3_PHYS		0x0c000000
 #define	OMAP_CS3_SIZE		SZ_64M
 
+#ifndef	__ASSEMBLER__
+
+/* EMIF Slow Interface Configuration Register */
+#define	OMAP_EMIFS_CONFIG_REG	__REG32(EMIFS_CONFIG)
+
+#define OMAP_EMIFS_CONFIG_FR		(1 << 4)
+#define OMAP_EMIFS_CONFIG_PDE		(1 << 3)
+#define OMAP_EMIFS_CONFIG_PWD_EN	(1 << 2)
+#define OMAP_EMIFS_CONFIG_BM		(1 << 1)
+#define OMAP_EMIFS_CONFIG_WP		(1 << 0)
+
+#define EMIFS_CCS(n)		__REG32(EMIFS_CS0_CONFIG + (4 * (n)))
+#define EMIFS_ACS(n)		__REG32(EMIFS_ACS0 + (4 * (n)))
+
+/* Almost all documentation for chip and board memory maps assumes
+ * BM is clear.  Most devel boards have a switch to control booting
+ * from NOR flash (using external chipselect 3) rather than mask ROM,
+ * which uses BM to interchange the physical CS0 and CS3 addresses.
+ */
+static inline u32 omap_cs0_phys(void)
+{
+	return (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM)
+			?  OMAP_CS3_PHYS : 0;
+}
+
+static inline u32 omap_cs3_phys(void)
+{
+	return (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM)
+			? 0 : OMAP_CS3_PHYS;
+}
+
+#endif	/* __ASSEMBLER__ */
+
 #endif	/* __ASM_ARCH_TC_H */
diff --git a/include/asm-arm/arch-omap/vmalloc.h b/include/asm-arm/arch-omap/vmalloc.h
--- a/include/asm-arm/arch-omap/vmalloc.h
+++ b/include/asm-arm/arch-omap/vmalloc.h
@@ -17,17 +17,5 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
 
diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h
--- a/include/asm-arm/arch-pxa/corgi.h
+++ b/include/asm-arm/arch-pxa/corgi.h
@@ -100,39 +100,9 @@
 
 
 /*
- * Corgi Parameter Area Definitions
+ * Shared data structures
  */
-#define FLASH_MEM_BASE	0xa0000a00
-#define FLASH_MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 )  | ( b << 8 ) | a )
-
-#define FLASH_COMADJ_MAJIC	FLASH_MAGIC_CHG('C','M','A','D')
-#define	FLASH_COMADJ_MAGIC_ADR	0x00
-#define	FLASH_COMADJ_DATA_ADR	0x04
-
-#define FLASH_PHAD_MAJIC	FLASH_MAGIC_CHG('P','H','A','D')
-#define	FLASH_PHAD_MAGIC_ADR	0x38
-#define	FLASH_PHAD_DATA_ADR	0x3C
-
-struct sharpsl_flash_param_info {
-  unsigned int comadj_keyword;
-  unsigned int comadj;
-
-  unsigned int uuid_keyword;
-  unsigned char uuid[16];
-
-  unsigned int touch_keyword;
-  unsigned int touch1;
-  unsigned int touch2;
-  unsigned int touch3;
-  unsigned int touch4;
-
-  unsigned int adadj_keyword;
-  unsigned int adadj;
-
-  unsigned int phad_keyword;
-  unsigned int phadadj;
-};
-
+extern struct platform_device corgiscoop_device;
 
 /*
  * External Functions
diff --git a/include/asm-arm/arch-pxa/idp.h b/include/asm-arm/arch-pxa/idp.h
--- a/include/asm-arm/arch-pxa/idp.h
+++ b/include/asm-arm/arch-pxa/idp.h
@@ -10,20 +10,20 @@
  * 2001-09-13: Cliff Brake <cbrake@accelent.com>
  *             Initial code
  *
+ * 2005-02-15: Cliff Brake <cliff.brake@gmail.com>
+ *             <http://www.vibren.com> <http://bec-systems.com>
+ *             Changes for 2.6 kernel.
  */
 
 #include <linux/config.h>
 
 /*
  * Note: this file must be safe to include in assembly files
+ *
+ * Support for the Vibren PXA255 IDP requires rev04 or later
+ * IDP hardware.
  */
 
-/* comment out following if you have a rev01 board */
-#define PXA_IDP_REV02	1
-
-#ifdef PXA_IDP_REV02
-//Use this as well for 0017-x004 and greater pcb's:
-#define PXA_IDP_REV04 1
 
 #define IDP_FLASH_PHYS		(PXA_CS0_PHYS)
 #define IDP_ALT_FLASH_PHYS	(PXA_CS1_PHYS)
@@ -38,26 +38,18 @@
  * virtual memory map
  */
 
-#define IDP_IDE_BASE		(0xf0000000)
-#define IDP_IDE_SIZE		(1*1024*1024)
-#define IDE_REG_STRIDE		4
-
-#define IDP_ETH_BASE		(IDP_IDE_BASE + IDP_IDE_SIZE)
-#define IDP_ETH_SIZE		(1*1024*1024)
-#define ETH_BASE		IDP_ETH_BASE //smc9194 driver compatibility issue
-
-#define IDP_COREVOLT_BASE	(IDP_ETH_BASE + IDP_ETH_SIZE)
+#define IDP_COREVOLT_VIRT	(0xf0000000)
 #define IDP_COREVOLT_SIZE	(1*1024*1024)
 
-#define IDP_CPLD_BASE		(IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
+#define IDP_CPLD_VIRT		(IDP_COREVOLT_VIRT + IDP_COREVOLT_SIZE)
 #define IDP_CPLD_SIZE		(1*1024*1024)
 
-#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
+#if (IDP_CPLD_VIRT + IDP_CPLD_SIZE) > 0xfc000000
 #error Your custom IO space is getting a bit large !!
 #endif
 
-#define CPLD_P2V(x)		((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
-#define CPLD_V2P(x)		((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
+#define CPLD_P2V(x)		((x) - IDP_CPLD_PHYS + IDP_CPLD_VIRT)
+#define CPLD_V2P(x)		((x) - IDP_CPLD_VIRT + IDP_CPLD_PHYS)
 
 #ifndef __ASSEMBLY__
 #  define __CPLD_REG(x)		(*((volatile unsigned long *)CPLD_P2V(x)))
@@ -65,7 +57,7 @@
 #  define __CPLD_REG(x)		CPLD_P2V(x)
 #endif
 
-/* board level registers in the CPLD: (offsets from CPLD_BASE) */
+/* board level registers in the CPLD: (offsets from CPLD_VIRT) */
 
 #define _IDP_CPLD_REV			(IDP_CPLD_PHYS + 0x00)
 #define _IDP_CPLD_PERIPH_PWR		(IDP_CPLD_PHYS + 0x04)
@@ -142,32 +134,10 @@
 
 #define PCC_DETECT(x)	(GPLR(7 + (x)) & GPIO_bit(7 + (x)))
 
-/*
- * Macros for LCD Driver
- */
-
-#ifdef CONFIG_FB_PXA
-
-#define FB_BACKLIGHT_ON()	(IDP_CPLD_LCD |= (1<<1))
-#define FB_BACKLIGHT_OFF() 	(IDP_CPLD_LCD &= ~(1<<1))
-
-#define FB_PWR_ON() 		(IDP_CPLD_LCD |= (1<< 0))
-#define FB_PWR_OFF() 		(IDP_CPLD_LCD &= ~(1<<0))
-
-#define FB_VLCD_ON()		(IDP_CPLD_LCD |= (1<<2))
-#define FB_VLCD_OFF() 		(IDP_CPLD_LCD &= ~(1<<2))
-
-#endif
-
 /* A listing of interrupts used by external hardware devices */
 
-#ifdef PXA_IDP_REV04
 #define TOUCH_PANEL_IRQ			IRQ_GPIO(5)
 #define IDE_IRQ				IRQ_GPIO(21)
-#else
-#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
-#define IDE_IRQ				IRQ_GPIO(5)
-#endif
 
 #define TOUCH_PANEL_IRQ_EDGE		IRQT_FALLING
 
@@ -196,8 +166,6 @@
 
 #define IDP_LEDS_MASK	(IDP_HB_LED | IDP_BUSY_LED)
 
-#define IDP_WRITE_LEDS(value)	(IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value))
-
 /*
  * macros for MTD driver
  */
@@ -229,238 +197,4 @@
 	inputs = (IDP_CPLD_KB_ROW & 0x7f);\
 }
 
-#else
-
-/*
- * following is for rev01 boards only
- */
-
-#define IDP_FLASH_PHYS		(PXA_CS0_PHYS)
-#define IDP_ALT_FLASH_PHYS	(PXA_CS1_PHYS)
-#define IDP_MEDIAQ_PHYS		(PXA_CS3_PHYS)
-#define IDP_CTRL_PORT_PHYS	(PXA_CS5_PHYS + 0x02C00000)
-#define IDP_IDE_PHYS		(PXA_CS5_PHYS + 0x03000000)
-#define IDP_ETH_PHYS		(PXA_CS5_PHYS + 0x03400000)
-#define IDP_COREVOLT_PHYS	(PXA_CS5_PHYS + 0x03800000)
-#define IDP_CPLD_PHYS		(PXA_CS5_PHYS + 0x03C00000)
-
-
-/*
- * virtual memory map
- */
-
-#define IDP_CTRL_PORT_BASE	(0xf0000000)
-#define IDP_CTRL_PORT_SIZE	(1*1024*1024)
-
-#define IDP_IDE_BASE		(IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE)
-#define IDP_IDE_SIZE		(1*1024*1024)
 
-#define IDP_ETH_BASE		(IDP_IDE_BASE + IDP_IDE_SIZE)
-#define IDP_ETH_SIZE		(1*1024*1024)
-
-#define IDP_COREVOLT_BASE	(IDP_ETH_BASE + IDP_ETH_SIZE)
-#define IDP_COREVOLT_SIZE	(1*1024*1024)
-
-#define IDP_CPLD_BASE		(IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
-#define IDP_CPLD_SIZE		(1*1024*1024)
-
-#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
-#error Your custom IO space is getting a bit large !!
-#endif
-
-#define CPLD_P2V(x)		((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
-#define CPLD_V2P(x)		((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
-
-#ifndef __ASSEMBLY__
-#  define __CPLD_REG(x)		(*((volatile unsigned long *)CPLD_P2V(x)))
-#else
-#  define __CPLD_REG(x)		CPLD_P2V(x)
-#endif
-
-/* board level registers in the CPLD: (offsets from CPLD_BASE) */
-
-#define _IDP_CPLD_LED_CONTROL		(IDP_CPLD_PHYS + 0x00)
-#define _IDP_CPLD_PERIPH_PWR		(IDP_CPLD_PHYS + 0x04)
-#define _IDP_CPLD_CIR			(IDP_CPLD_PHYS + 0x08)
-#define _IDP_CPLD_KB_COL_HIGH		(IDP_CPLD_PHYS + 0x0C)
-#define _IDP_CPLD_KB_COL_LOW		(IDP_CPLD_PHYS + 0x10)
-#define _IDP_CPLD_PCCARD_EN		(IDP_CPLD_PHYS + 0x14)
-#define _IDP_CPLD_GPIOH_DIR		(IDP_CPLD_PHYS + 0x18)
-#define _IDP_CPLD_GPIOH_VALUE		(IDP_CPLD_PHYS + 0x1C)
-#define _IDP_CPLD_GPIOL_DIR		(IDP_CPLD_PHYS + 0x20)
-#define _IDP_CPLD_GPIOL_VALUE		(IDP_CPLD_PHYS + 0x24)
-#define _IDP_CPLD_MISC			(IDP_CPLD_PHYS + 0x28)
-#define _IDP_CPLD_PCCARD0_STATUS	(IDP_CPLD_PHYS + 0x2C)
-#define _IDP_CPLD_PCCARD1_STATUS	(IDP_CPLD_PHYS + 0x30)
-
-/* FPGA register virtual addresses */
-#define IDP_CPLD_LED_CONTROL		__CPLD_REG(_IDP_CPLD_LED_CONTROL)	/* write only */
-#define IDP_CPLD_PERIPH_PWR		__CPLD_REG(_IDP_CPLD_PERIPH_PWR)	/* write only */
-#define IDP_CPLD_CIR			__CPLD_REG(_IDP_CPLD_CIR)		/* write only */
-#define IDP_CPLD_KB_COL_HIGH		__CPLD_REG(_IDP_CPLD_KB_COL_HIGH)	/* write only */
-#define IDP_CPLD_KB_COL_LOW		__CPLD_REG(_IDP_CPLD_KB_COL_LOW)	/* write only */
-#define IDP_CPLD_PCCARD_EN		__CPLD_REG(_IDP_CPLD_PCCARD_EN)		/* write only */
-#define IDP_CPLD_GPIOH_DIR		__CPLD_REG(_IDP_CPLD_GPIOH_DIR)		/* write only */
-#define IDP_CPLD_GPIOH_VALUE		__CPLD_REG(_IDP_CPLD_GPIOH_VALUE)	/* write only */
-#define IDP_CPLD_GPIOL_DIR		__CPLD_REG(_IDP_CPLD_GPIOL_DIR)		/* write only */
-#define IDP_CPLD_GPIOL_VALUE		__CPLD_REG(_IDP_CPLD_GPIOL_VALUE)	/* write only */
-#define IDP_CPLD_MISC			__CPLD_REG(_IDP_CPLD_MISC)		/* read only */
-#define IDP_CPLD_PCCARD0_STATUS		__CPLD_REG(_IDP_CPLD_PCCARD0_STATUS)	/* read only */
-#define IDP_CPLD_PCCARD1_STATUS		__CPLD_REG(_IDP_CPLD_PCCARD1_STATUS)	/* read only */
-
-
-#ifndef __ASSEMBLY__
-
-/* shadow registers for write only registers */
-extern unsigned int idp_cpld_led_control_shadow;
-extern unsigned int idp_cpld_periph_pwr_shadow;
-extern unsigned int idp_cpld_cir_shadow;
-extern unsigned int idp_cpld_kb_col_high_shadow;
-extern unsigned int idp_cpld_kb_col_low_shadow;
-extern unsigned int idp_cpld_pccard_en_shadow;
-extern unsigned int idp_cpld_gpioh_dir_shadow;
-extern unsigned int idp_cpld_gpioh_value_shadow;
-extern unsigned int idp_cpld_gpiol_dir_shadow;
-extern unsigned int idp_cpld_gpiol_value_shadow;
-
-extern unsigned int idp_control_port_shadow;
-
-/*
- * macros to write to write only register
- *
- * none of these macros are protected from
- * multiple drivers using them in interrupt context.
- */
-
-#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \
-{\
-	idp_cpld_led_control_shadow = (((value & mask) | (idp_cpld_led_control_shadow & ~mask)));\
-	IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
-}
-#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \
-{\
-	idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\
-	IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\
-}
-#define WRITE_IDP_CPLD_CIR(value, mask) \
-{\
-	idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\
-	IDP_CPLD_CIR = idp_cpld_cir_shadow;\
-}
-#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \
-{\
-	idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\
-	IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\
-}
-#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \
-{\
-	idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\
-	IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\
-}
-#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \
-{\
-	idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
-	IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
-}
-#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \
-{\
-	idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\
-	IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\
-}
-#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \
-{\
-	idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\
-	IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\
-}
-#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \
-{\
-	idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\
-	IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\
-}
-#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \
-{\
-	idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\
-	IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\
-}
-
-#define WRITE_IDP_CONTROL_PORT(value, mask) \
-{\
-	idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\
-	(*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\
-}
-
-#endif
-
-/* A listing of interrupts used by external hardware devices */
-
-#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
-#define TOUCH_PANEL_IRQ_EGDE		IRQT_FALLING
-
-#define ETHERNET_IRQ			IRQ_GPIO(4)
-#define ETHERNET_IRQ_EDGE		IRQT_RISING
-
-/*
- * Bit masks for various registers
- */
-
-
-/* control port */
-#define IDP_CONTROL_PORT_PCSLOT0_0	(1 << 0)
-#define IDP_CONTROL_PORT_PCSLOT0_1	(1 << 1)
-#define IDP_CONTROL_PORT_PCSLOT0_2	(1 << 2)
-#define IDP_CONTROL_PORT_PCSLOT0_3	(1 << 3)
-#define IDP_CONTROL_PORT_PCSLOT1_1	(1 << 4)
-#define IDP_CONTROL_PORT_PCSLOT1_2	(1 << 5)
-#define IDP_CONTROL_PORT_PCSLOT1_3	(1 << 6)
-#define IDP_CONTROL_PORT_PCSLOT1_4	(1 << 7)
-#define IDP_CONTROL_PORT_SERIAL1_EN	(1 << 9)
-#define IDP_CONTROL_PORT_SERIAL2_EN	(1 << 10)
-#define IDP_CONTROL_PORT_SERIAL3_EN	(1 << 11)
-#define IDP_CONTROL_PORT_IRDA_FIR	(1 << 12)
-#define IDP_CONTROL_PORT_IRDA_M0	(1 << 13)
-#define IDP_CONTROL_PORT_IRDA_M1	(1 << 14)
-#define IDP_CONTROL_PORT_I2S_PWR	(1 << 15)
-#define IDP_CONTROL_PORT_FLASH_WP	(1 << 19)
-#define IDP_CONTROL_PORT_MILL_EN	(1 << 20)
-#define IDP_CONTROL_PORT_LCD_PWR	(1 << 21)
-#define IDP_CONTROL_PORT_LCD_BKLEN	(1 << 22)
-#define IDP_CONTROL_PORT_LCD_ENAVLCD	(1 << 23)
-
-/*
- * Macros for LCD Driver
- */
-
-#ifdef CONFIG_FB_PXA
-
-#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN)
-#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN)
-
-#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR)
-#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR)
-
-#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD)
-#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD)
-
-#endif
-
-
-/*
- * Macros for LED Driver
- */
-
-/* leds 0 = ON */
-#define IDP_HB_LED	0x1
-#define IDP_BUSY_LED	0x2
-
-#define IDP_LEDS_MASK	(IDP_HB_LED | IDP_BUSY_LED)
-
-#define IDP_WRITE_LEDS(value) 	WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK)
-
-/*
- * macros for MTD driver
- */
-
-#define FLASH_WRITE_PROTECT_DISABLE()	WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP)
-#define FLASH_WRITE_PROTECT_ENABLE()	WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP)
-
-#endif
diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
--- a/include/asm-arm/arch-pxa/irqs.h
+++ b/include/asm-arm/arch-pxa/irqs.h
@@ -140,14 +140,41 @@
 #define IRQ_S0_BVD1_STSCHG	(IRQ_BOARD_END + 53)
 #define IRQ_S1_BVD1_STSCHG	(IRQ_BOARD_END + 54)
 
+#define IRQ_LOCOMO_START	(IRQ_BOARD_END)
+#define IRQ_LOCOMO_KEY		(IRQ_BOARD_END + 0)
+#define IRQ_LOCOMO_GPIO0	(IRQ_BOARD_END + 1)
+#define IRQ_LOCOMO_GPIO1	(IRQ_BOARD_END + 2)
+#define IRQ_LOCOMO_GPIO2	(IRQ_BOARD_END + 3)
+#define IRQ_LOCOMO_GPIO3	(IRQ_BOARD_END + 4)
+#define IRQ_LOCOMO_GPIO4	(IRQ_BOARD_END + 5)
+#define IRQ_LOCOMO_GPIO5	(IRQ_BOARD_END + 6)
+#define IRQ_LOCOMO_GPIO6	(IRQ_BOARD_END + 7)
+#define IRQ_LOCOMO_GPIO7	(IRQ_BOARD_END + 8)
+#define IRQ_LOCOMO_GPIO8	(IRQ_BOARD_END + 9)
+#define IRQ_LOCOMO_GPIO9	(IRQ_BOARD_END + 10)
+#define IRQ_LOCOMO_GPIO10	(IRQ_BOARD_END + 11)
+#define IRQ_LOCOMO_GPIO11	(IRQ_BOARD_END + 12)
+#define IRQ_LOCOMO_GPIO12	(IRQ_BOARD_END + 13)
+#define IRQ_LOCOMO_GPIO13	(IRQ_BOARD_END + 14)
+#define IRQ_LOCOMO_GPIO14	(IRQ_BOARD_END + 15)
+#define IRQ_LOCOMO_GPIO15	(IRQ_BOARD_END + 16)
+#define IRQ_LOCOMO_LT		(IRQ_BOARD_END + 17)
+#define IRQ_LOCOMO_SPI_RFR	(IRQ_BOARD_END + 18)
+#define IRQ_LOCOMO_SPI_RFW	(IRQ_BOARD_END + 19)
+#define IRQ_LOCOMO_SPI_OVRN	(IRQ_BOARD_END + 20)
+#define IRQ_LOCOMO_SPI_TEND	(IRQ_BOARD_END + 21)
+
 /*
  * Figure out the MAX IRQ number.
  *
  * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
+ * If we have an LoCoMo, the max IRQ is IRQ_LOCOMO_SPI_TEND+1
  * Otherwise, we have the standard IRQs only.
  */
 #ifdef CONFIG_SA1111
 #define NR_IRQS			(IRQ_S1_BVD1_STSCHG + 1)
+#elif defined(CONFIG_SHARP_LOCOMO)
+#define NR_IRQS			(IRQ_LOCOMO_SPI_TEND + 1)
 #elif defined(CONFIG_ARCH_LUBBOCK) || \
       defined(CONFIG_MACH_MAINSTONE)
 #define NR_IRQS			(IRQ_BOARD_END)
@@ -185,3 +212,8 @@
 #define MAINSTONE_S1_STSCHG_IRQ	MAINSTONE_IRQ(14)
 #define MAINSTONE_S1_IRQ	MAINSTONE_IRQ(15)
 
+/* LoCoMo Interrupts (CONFIG_SHARP_LOCOMO) */
+#define IRQ_LOCOMO_KEY_BASE	(IRQ_BOARD_START + 0)
+#define IRQ_LOCOMO_GPIO_BASE	(IRQ_BOARD_START + 1)
+#define IRQ_LOCOMO_LT_BASE	(IRQ_BOARD_START + 2)
+#define IRQ_LOCOMO_SPI_BASE	(IRQ_BOARD_START + 3)
diff --git a/include/asm-arm/arch-pxa/poodle.h b/include/asm-arm/arch-pxa/poodle.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-pxa/poodle.h
@@ -0,0 +1,70 @@
+/*
+ * linux/include/asm-arm/arch-pxa/poodle.h
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Based on:
+ *   linux/include/asm-arm/arch-sa1100/collie.h
+ *
+ * ChangeLog:
+ *   04-06-2001 Lineo Japan, Inc.
+ *   04-16-2001 SHARP Corporation
+ *   Update to 2.6 John Lenz
+ */
+#ifndef __ASM_ARCH_POODLE_H
+#define __ASM_ARCH_POODLE_H  1
+
+/*
+ * GPIOs
+ */
+/* PXA GPIOs */
+#define POODLE_GPIO_ON_KEY		(0)
+#define POODLE_GPIO_AC_IN		(1)
+#define POODLE_GPIO_CO			16
+#define POODLE_GPIO_TP_INT		(5)
+#define POODLE_GPIO_WAKEUP		(11)	/* change battery */
+#define POODLE_GPIO_GA_INT		(10)
+#define POODLE_GPIO_IR_ON		(22)
+#define POODLE_GPIO_HP_IN		(4)
+#define POODLE_GPIO_CF_IRQ		(17)
+#define POODLE_GPIO_CF_CD		(14)
+#define POODLE_GPIO_CF_STSCHG		(14)
+#define POODLE_GPIO_SD_PWR		(33)
+#define POODLE_GPIO_nSD_CLK		(6)
+#define POODLE_GPIO_nSD_WP		(7)
+#define POODLE_GPIO_nSD_INT		(8)
+#define POODLE_GPIO_nSD_DETECT		(9)
+#define POODLE_GPIO_MAIN_BAT_LOW	(13)
+#define POODLE_GPIO_BAT_COVER		(13)
+#define POODLE_GPIO_ADC_TEMP_ON		(21)
+#define POODLE_GPIO_BYPASS_ON		(36)
+#define POODLE_GPIO_CHRG_ON		(38)
+#define POODLE_GPIO_CHRG_FULL		(16)
+
+/* PXA GPIOs */
+#define POODLE_IRQ_GPIO_ON_KEY		IRQ_GPIO0
+#define POODLE_IRQ_GPIO_AC_IN		IRQ_GPIO1
+#define POODLE_IRQ_GPIO_HP_IN		IRQ_GPIO4
+#define POODLE_IRQ_GPIO_CO		IRQ_GPIO16
+#define POODLE_IRQ_GPIO_TP_INT		IRQ_GPIO5
+#define POODLE_IRQ_GPIO_WAKEUP		IRQ_GPIO11
+#define POODLE_IRQ_GPIO_GA_INT		IRQ_GPIO10
+#define POODLE_IRQ_GPIO_CF_IRQ		IRQ_GPIO17
+#define POODLE_IRQ_GPIO_CF_CD		IRQ_GPIO14
+#define POODLE_IRQ_GPIO_nSD_INT		IRQ_GPIO8
+#define POODLE_IRQ_GPIO_nSD_DETECT	IRQ_GPIO9
+#define POODLE_IRQ_GPIO_MAIN_BAT_LOW	IRQ_GPIO13
+
+/* SCOOP GPIOs */
+#define POODLE_SCOOP_CHARGE_ON	SCOOP_GPCR_PA11
+#define POODLE_SCOOP_CP401	SCOOP_GPCR_PA13
+#define POODLE_SCOOP_VPEN	SCOOP_GPCR_PA18
+#define POODLE_SCOOP_L_PCLK	SCOOP_GPCR_PA20
+#define POODLE_SCOOP_L_LCLK	SCOOP_GPCR_PA21
+#define POODLE_SCOOP_HS_OUT	SCOOP_GPCR_PA22
+
+#define POODLE_SCOOP_IO_DIR	( POODLE_SCOOP_VPEN | POODLE_SCOOP_HS_OUT )
+#define POODLE_SCOOP_IO_OUT	( 0 )
+
+#endif /* __ASM_ARCH_POODLE_H  */
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1296,6 +1296,7 @@
 #define GPIO111_MMCDAT3		111	/* MMC DAT3 (PXA27x) */
 #define GPIO111_MMCCS1		111	/* MMC Chip Select 1 (PXA27x) */
 #define GPIO112_MMCCMD		112	/* MMC CMD (PXA27x) */
+#define GPIO113_I2S_SYSCLK	113	/* I2S System Clock (PXA27x) */
 #define GPIO113_AC97_RESET_N	113	/* AC97 NRESET on (PXA27x) */
 
 /* GPIO alternate function mode & direction */
@@ -1428,6 +1429,7 @@
 #define GPIO111_MMCDAT3_MD	(111 | GPIO_ALT_FN_1_OUT)
 #define GPIO110_MMCCS1_MD	(111 | GPIO_ALT_FN_1_OUT)
 #define GPIO112_MMCCMD_MD	(112 | GPIO_ALT_FN_1_OUT)
+#define GPIO113_I2S_SYSCLK_MD	(113 | GPIO_ALT_FN_1_OUT)
 #define GPIO113_AC97_RESET_N_MD	(113 | GPIO_ALT_FN_2_OUT)
 #define GPIO117_I2CSCL_MD	(117 | GPIO_ALT_FN_1_OUT)
 #define GPIO118_I2CSDA_MD	(118 | GPIO_ALT_FN_1_IN)
diff --git a/include/asm-arm/arch-pxa/vmalloc.h b/include/asm-arm/arch-pxa/vmalloc.h
--- a/include/asm-arm/arch-pxa/vmalloc.h
+++ b/include/asm-arm/arch-pxa/vmalloc.h
@@ -8,15 +8,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (0xe8000000)
diff --git a/include/asm-arm/arch-rpc/debug-macro.S b/include/asm-arm/arch-rpc/debug-macro.S
--- a/include/asm-arm/arch-rpc/debug-macro.S
+++ b/include/asm-arm/arch-rpc/debug-macro.S
@@ -12,7 +12,10 @@
 */
 
 		.macro	addruart,rx
-		mov	\rx, #0xe0000000
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #0x03000000
+		movne	\rx, #0xe0000000
 		orr	\rx, \rx, #0x00010000
 		orr	\rx, \rx, #0x00000fe0
 		.endm
diff --git a/include/asm-arm/arch-rpc/hardware.h b/include/asm-arm/arch-rpc/hardware.h
--- a/include/asm-arm/arch-rpc/hardware.h
+++ b/include/asm-arm/arch-rpc/hardware.h
@@ -14,6 +14,12 @@
 
 #include <asm/arch/memory.h>
 
+#ifndef __ASSEMBLY__
+#define IOMEM(x) ((void __iomem *)(x))
+#else
+#define IOMEM(x) x
+#endif /* __ASSEMBLY__ */
+
 /*
  * What hardware must be present
  */
@@ -34,7 +40,7 @@
 
 #define IO_START		0x03000000	/* I/O */
 #define IO_SIZE			0x01000000
-#define IO_BASE			0xe0000000
+#define IO_BASE			IOMEM(0xe0000000)
 
 #define SCREEN_START		0x02000000	/* VRAM */
 #define SCREEN_END		0xdfc00000
@@ -46,12 +52,12 @@
 /*
  * IO Addresses
  */
-#define VIDC_BASE		0xe0400000
+#define VIDC_BASE		(void __iomem *)0xe0400000
 #define EXPMASK_BASE		0xe0360000
-#define IOMD_BASE		0xe0200000
-#define IOC_BASE		0xe0200000
-#define PCIO_BASE		0xe0010000
-#define FLOPPYDMA_BASE		0xe002a000
+#define IOMD_BASE		IOMEM(0xe0200000)
+#define IOC_BASE		IOMEM(0xe0200000)
+#define PCIO_BASE		IOMEM(0xe0010000)
+#define FLOPPYDMA_BASE		IOMEM(0xe002a000)
 
 #define FLUSH_BASE_PHYS		0x00000000	/* ROM */
 
diff --git a/include/asm-arm/arch-rpc/io.h b/include/asm-arm/arch-rpc/io.h
--- a/include/asm-arm/arch-rpc/io.h
+++ b/include/asm-arm/arch-rpc/io.h
@@ -128,9 +128,9 @@ static inline void __iomem *__ioaddr(uns
 {
 	void __iomem *ret;
 	if (__PORT_PCIO(port))
-		ret = (void __iomem *)PCIO_BASE;
+		ret = PCIO_BASE;
 	else
-		ret = (void __iomem *)IO_BASE;
+		ret = IO_BASE;
 	return ret + (port << 2);
 }
 
@@ -230,8 +230,8 @@ DECLARE_IO(int,l,"")
 	result;									\
 })
 
-#define __ioaddrc(port)								\
-	((void __iomem *)(__PORT_PCIO((port)) ? PCIO_BASE : IO_BASE) + ((port) << 2))
+#define __ioaddrc(port)		\
+	((__PORT_PCIO(port) ? PCIO_BASE : IO_BASE) + ((port) << 2))
 
 #define inb(p)	 	(__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
 #define inw(p)	 	(__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
diff --git a/include/asm-arm/arch-rpc/vmalloc.h b/include/asm-arm/arch-rpc/vmalloc.h
--- a/include/asm-arm/arch-rpc/vmalloc.h
+++ b/include/asm-arm/arch-rpc/vmalloc.h
@@ -7,15 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S
--- a/include/asm-arm/arch-s3c2410/debug-macro.S
+++ b/include/asm-arm/arch-s3c2410/debug-macro.S
@@ -11,6 +11,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
+ * Modifications:
+ *     10-Mar-2005 LCVR  Changed S3C2410_VA to S3C24XX_VA
 */
 
 #include <asm/arch/map.h>
@@ -24,7 +26,7 @@
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1
 		ldreq	\rx, = S3C2410_PA_UART
-		ldrne	\rx, = S3C2410_VA_UART
+		ldrne	\rx, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C2410_UART != 0
 		add	\rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART)
 #endif
@@ -43,7 +45,7 @@
 		mrc	p15, 0, \rd, c1, c0
 		tst	\rd, #1
 		addeq	\rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART)
-		addne	\rd, \rx, #(S3C2410_VA_GPIO - S3C2410_VA_UART)
+		addne	\rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
 		bic	\rd, \rd, #0xff000
 		ldr	\rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
 		and	\rd, \rd, #0x00ff0000
@@ -74,7 +76,7 @@
 		mrc	p15, 0, \rd, c1, c0
 		tst	\rd, #1
 		addeq	\rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART)
-		addne	\rd, \rx, #(S3C2410_VA_GPIO - S3C2410_VA_UART)
+		addne	\rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
 		bic	\rd, \rd, #0xff000
 		ldr	\rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
 		and	\rd, \rd, #0x00ff0000
diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S
--- a/include/asm-arm/arch-s3c2410/entry-macro.S
+++ b/include/asm-arm/arch-s3c2410/entry-macro.S
@@ -6,12 +6,15 @@
  * This file is licensed under  the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
+
+ * Modifications:
+ *     10-Mar-2005 LCVR  Changed S3C2410_VA to S3C24XX_VA
  */
 
 
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 
-		mov	\tmp, #S3C2410_VA_IRQ
+		mov	\tmp, #S3C24XX_VA_IRQ
 		ldr	\irqnr, [ \tmp, #0x14 ]		@ get irq no
 30000:
 		teq	\irqnr, #4
@@ -45,7 +48,7 @@
 		.align	4
 20004:
 		mov	r1, #1
-		mov	\tmp, #S3C2410_VA_IRQ
+		mov	\tmp, #S3C24XX_VA_IRQ
 		ldmfd	r13!, { r0 - r4 , r8-r12, r14 }
 #endif
 
@@ -83,7 +86,7 @@
 
 		@ we get here from no main or external interrupts pending
 1002:
-		add	\tmp, \tmp, #S3C2410_VA_GPIO - S3C2410_VA_IRQ
+		add	\tmp, \tmp, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
 		ldr	\irqstat, [ \tmp, # 0xa8 ]	@ EXTINTPEND
 		ldr	\irqnr, [ \tmp, # 0xa4 ]	@ EXTINTMASK
 
diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h
--- a/include/asm-arm/arch-s3c2410/hardware.h
+++ b/include/asm-arm/arch-s3c2410/hardware.h
@@ -97,11 +97,7 @@ extern unsigned int s3c2410_modify_miscc
 #include <asm/sizes.h>
 #include <asm/arch/map.h>
 
-/* machine specific includes, such as the BAST */
-
-#if defined(CONFIG_ARCH_BAST)
-#include <asm/arch/bast-cpld.h>
-#endif
+/* machine specific hardware definitions should go after this */
 
 /* currently here until moved into config (todo) */
 #define CONFIG_NO_MULTIWORD_IO
diff --git a/include/asm-arm/arch-s3c2410/io.h b/include/asm-arm/arch-s3c2410/io.h
--- a/include/asm-arm/arch-s3c2410/io.h
+++ b/include/asm-arm/arch-s3c2410/io.h
@@ -8,6 +8,7 @@
  * Modifications:
  *  06-Dec-1997	RMK	Created.
  *  02-Sep-2003 BJD	Modified for S3C2410
+ *  10-Mar-2005 LCVR	Changed S3C2410_VA to S3C24XX_VA
  *
  */
 
@@ -26,10 +27,10 @@
 
 #define __PORT_PCIO(x)	((x) < (1<<28))
 
-#define PCIO_BASE	 (S3C2410_VA_ISA_WORD)
-#define PCIO_BASE_b	 (S3C2410_VA_ISA_BYTE)
-#define PCIO_BASE_w	 (S3C2410_VA_ISA_WORD)
-#define PCIO_BASE_l	 (S3C2410_VA_ISA_WORD)
+#define PCIO_BASE	 (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_b	 (S3C24XX_VA_ISA_BYTE)
+#define PCIO_BASE_w	 (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_l	 (S3C24XX_VA_ISA_WORD)
 /*
  * Dynamic IO functions - let the compiler
  * optimize the expressions
@@ -65,9 +66,9 @@ static inline unsigned sz __in##fnsuffix
 	return (unsigned sz)value;					\
 }
 
-static inline void __iomem *__ioaddr (unsigned int port)
+static inline void __iomem *__ioaddr (unsigned long port)
 {
-	return (void __iomem *)(__PORT_PCIO(port) ? PCIO_BASE + port : port);
+	return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port;
 }
 
 #define DECLARE_IO(sz,fnsuffix,instr)	\
@@ -167,7 +168,7 @@ DECLARE_IO(int,l,"")
 	result;								\
 })
 
-#define __ioaddrc(port)	((void __iomem *)(__PORT_PCIO(port) ? PCIO_BASE + (port) : (port)))
+#define __ioaddrc(port)	((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port)))
 
 #define inb(p)		(__builtin_constant_p((p)) ? __inbc(p)	   : __inb(p))
 #define inw(p)		(__builtin_constant_p((p)) ? __inwc(p)	   : __inw(p))
@@ -177,7 +178,7 @@ DECLARE_IO(int,l,"")
 #define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
 #define __ioaddr(p)	(__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
 /* the following macro is deprecated */
-#define ioaddr(port)			__ioaddr((port))
+#define ioaddr(port)	__ioaddr((port))
 
 #define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l)
 #define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l)
diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
--- a/include/asm-arm/arch-s3c2410/irqs.h
+++ b/include/asm-arm/arch-s3c2410/irqs.h
@@ -1,6 +1,6 @@
 /* linux/include/asm-arm/arch-s3c2410/irqs.h
  *
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003-2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,8 @@
  *  12-May-2003 BJD  Created file
  *  08-Jan-2003 BJD  Linux 2.6.0 version, moved BAST bits out
  *  12-Mar-2004 BJD  Fixed bug in header protection
+ *  10-Feb-2005 BJD  Added camera IRQ from guillaume.gourat@nexvision.tv
+ *  28-Feb-2005 BJD  Updated s3c2440 IRQs
  */
 
 
@@ -35,7 +37,8 @@
 #define IRQ_EINT3      S3C2410_IRQ(3)
 #define IRQ_EINT4t7    S3C2410_IRQ(4)	    /* 20 */
 #define IRQ_EINT8t23   S3C2410_IRQ(5)
-#define IRQ_RESERVED6  S3C2410_IRQ(6)
+#define IRQ_RESERVED6  S3C2410_IRQ(6)	    /* for s3c2410 */
+#define IRQ_CAM        S3C2410_IRQ(6)	    /* for s3c2440 */
 #define IRQ_BATT_FLT   S3C2410_IRQ(7)
 #define IRQ_TICK       S3C2410_IRQ(8)	    /* 24 */
 #define IRQ_WDT	       S3C2410_IRQ(9)
@@ -54,6 +57,7 @@
 #define IRQ_SPI0       S3C2410_IRQ(22)
 #define IRQ_UART1      S3C2410_IRQ(23)
 #define IRQ_RESERVED24 S3C2410_IRQ(24)	    /* 40 */
+#define IRQ_NFCON      S3C2410_IRQ(24)	    /* for s3c2440 */
 #define IRQ_USBD       S3C2410_IRQ(25)
 #define IRQ_USBH       S3C2410_IRQ(26)
 #define IRQ_IIC	       S3C2410_IRQ(27)
@@ -109,7 +113,14 @@
 #define IRQ_TC		 S3C2410_IRQ(63)
 #define IRQ_ADC		 S3C2410_IRQ(64)
 
-#define NR_IRQS (IRQ_ADC+1)
+/* extra irqs for s3c2440 */
+
+#define IRQ_S3C2440_CAM_C	S3C2410_IRQ(65)
+#define IRQ_S3C2440_CAM_P	S3C2410_IRQ(66)
+#define IRQ_S3C2440_WDT		S3C2410_IRQ(67)
+#define IRQ_S3C2440_AC97	S3C2410_IRQ(68)
+
+#define NR_IRQS (IRQ_S3C2440_AC97+1)
 
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
--- a/include/asm-arm/arch-s3c2410/map.h
+++ b/include/asm-arm/arch-s3c2410/map.h
@@ -10,8 +10,10 @@
  * published by the Free Software Foundation.
  *
  * Changelog:
- *  12-May-2003 BJD  Created file
- *  06-Jan-2003 BJD  Linux 2.6.0 version, moved bast specifics out
+ *  12-May-2003 BJD   Created file
+ *  06-Jan-2003 BJD   Linux 2.6.0 version, moved bast specifics out
+ *  10-Feb-2005 BJD   Added CAMIF definition from guillaume.gourat@nexvision.tv
+ *  10-Mar-2005 LCVR  Added support to S3C2400, changed {VA,SZ} names
 */
 
 #ifndef __ASM_ARCH_MAP_H
@@ -28,108 +30,139 @@
  * as they are only useful to certain drivers...
  */
 
+#ifndef __ASSEMBLY__
+#define S3C2410_ADDR(x)	  ((void __iomem *)0xF0000000 + (x))
+#else
 #define S3C2410_ADDR(x)	  (0xF0000000 + (x))
+#endif
+
+#define S3C2400_ADDR(x)	  S3C2410_ADDR(x)
 
 /* interrupt controller is the first thing we put in, to make
  * the assembly code for the irq detection easier
  */
-#define S3C2410_VA_IRQ	   S3C2410_ADDR(0x00000000)
+#define S3C24XX_VA_IRQ	   S3C2410_ADDR(0x00000000)
+#define S3C2400_PA_IRQ	   (0x14400000)
 #define S3C2410_PA_IRQ	   (0x4A000000)
-#define S3C2410_SZ_IRQ	   SZ_1M
+#define S3C24XX_SZ_IRQ	   SZ_1M
 
 /* memory controller registers */
-#define S3C2410_VA_MEMCTRL S3C2410_ADDR(0x00100000)
+#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000)
+#define S3C2400_PA_MEMCTRL (0x14000000)
 #define S3C2410_PA_MEMCTRL (0x48000000)
-#define S3C2410_SZ_MEMCTRL SZ_1M
+#define S3C24XX_SZ_MEMCTRL SZ_1M
 
 /* USB host controller */
-#define S3C2410_VA_USBHOST S3C2410_ADDR(0x00200000)
+#define S3C24XX_VA_USBHOST S3C2410_ADDR(0x00200000)
+#define S3C2400_PA_USBHOST (0x14200000)
 #define S3C2410_PA_USBHOST (0x49000000)
-#define S3C2410_SZ_USBHOST SZ_1M
+#define S3C24XX_SZ_USBHOST SZ_1M
 
 /* DMA controller */
-#define S3C2410_VA_DMA	   S3C2410_ADDR(0x00300000)
+#define S3C24XX_VA_DMA	   S3C2410_ADDR(0x00300000)
+#define S3C2400_PA_DMA	   (0x14600000)
 #define S3C2410_PA_DMA	   (0x4B000000)
-#define S3C2410_SZ_DMA	   SZ_1M
+#define S3C24XX_SZ_DMA	   SZ_1M
 
 /* Clock and Power management */
-#define S3C2410_VA_CLKPWR  S3C2410_ADDR(0x00400000)
+#define S3C24XX_VA_CLKPWR  S3C2410_ADDR(0x00400000)
+#define S3C2400_PA_CLKPWR  (0x14800000)
 #define S3C2410_PA_CLKPWR  (0x4C000000)
-#define S3C2410_SZ_CLKPWR  SZ_1M
+#define S3C24XX_SZ_CLKPWR  SZ_1M
 
 /* LCD controller */
-#define S3C2410_VA_LCD	   S3C2410_ADDR(0x00600000)
+#define S3C24XX_VA_LCD	   S3C2410_ADDR(0x00600000)
+#define S3C2400_PA_LCD	   (0x14A00000)
 #define S3C2410_PA_LCD	   (0x4D000000)
-#define S3C2410_SZ_LCD	   SZ_1M
+#define S3C24XX_SZ_LCD	   SZ_1M
 
 /* NAND flash controller */
-#define S3C2410_VA_NAND	   S3C2410_ADDR(0x00700000)
+#define S3C24XX_VA_NAND	   S3C2410_ADDR(0x00700000)
 #define S3C2410_PA_NAND	   (0x4E000000)
-#define S3C2410_SZ_NAND	   SZ_1M
+#define S3C24XX_SZ_NAND	   SZ_1M
+
+/* MMC controller - available on the S3C2400 */
+#define S3C2400_VA_MMC 	   S3C2400_ADDR(0x00700000)
+#define S3C2400_PA_MMC 	   (0x15A00000)
+#define S3C2400_SZ_MMC 	   SZ_1M
 
 /* UARTs */
-#define S3C2410_VA_UART	   S3C2410_ADDR(0x00800000)
+#define S3C24XX_VA_UART	   S3C2410_ADDR(0x00800000)
+#define S3C2400_PA_UART	   (0x15000000)
 #define S3C2410_PA_UART	   (0x50000000)
-#define S3C2410_SZ_UART	   SZ_1M
+#define S3C24XX_SZ_UART	   SZ_1M
 
 /* Timers */
-#define S3C2410_VA_TIMER   S3C2410_ADDR(0x00900000)
+#define S3C24XX_VA_TIMER   S3C2410_ADDR(0x00900000)
+#define S3C2400_PA_TIMER   (0x15100000)
 #define S3C2410_PA_TIMER   (0x51000000)
-#define S3C2410_SZ_TIMER   SZ_1M
+#define S3C24XX_SZ_TIMER   SZ_1M
 
 /* USB Device port */
-#define S3C2410_VA_USBDEV  S3C2410_ADDR(0x00A00000)
+#define S3C24XX_VA_USBDEV  S3C2410_ADDR(0x00A00000)
+#define S3C2400_PA_USBDEV  (0x15200140)
 #define S3C2410_PA_USBDEV  (0x52000000)
-#define S3C2410_SZ_USBDEV  SZ_1M
+#define S3C24XX_SZ_USBDEV  SZ_1M
 
 /* Watchdog */
-#define S3C2410_VA_WATCHDOG S3C2410_ADDR(0x00B00000)
+#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00B00000)
+#define S3C2400_PA_WATCHDOG (0x15300000)
 #define S3C2410_PA_WATCHDOG (0x53000000)
-#define S3C2410_SZ_WATCHDOG SZ_1M
+#define S3C24XX_SZ_WATCHDOG SZ_1M
 
 /* IIC hardware controller */
-#define S3C2410_VA_IIC	   S3C2410_ADDR(0x00C00000)
+#define S3C24XX_VA_IIC	   S3C2410_ADDR(0x00C00000)
+#define S3C2400_PA_IIC	   (0x15400000)
 #define S3C2410_PA_IIC	   (0x54000000)
-#define S3C2410_SZ_IIC	   SZ_1M
+#define S3C24XX_SZ_IIC	   SZ_1M
 
-#define VA_IIC_BASE	   (S3C2410_VA_IIC)
+#define VA_IIC_BASE	   (S3C24XX_VA_IIC)
 
 /* IIS controller */
-#define S3C2410_VA_IIS	   S3C2410_ADDR(0x00D00000)
+#define S3C24XX_VA_IIS	   S3C2410_ADDR(0x00D00000)
+#define S3C2400_PA_IIS	   (0x15508000)
 #define S3C2410_PA_IIS	   (0x55000000)
-#define S3C2410_SZ_IIS	   SZ_1M
+#define S3C24XX_SZ_IIS	   SZ_1M
 
 /* GPIO ports */
-#define S3C2410_VA_GPIO	   S3C2410_ADDR(0x00E00000)
+#define S3C24XX_VA_GPIO	   S3C2410_ADDR(0x00E00000)
+#define S3C2400_PA_GPIO	   (0x15600000)
 #define S3C2410_PA_GPIO	   (0x56000000)
-#define S3C2410_SZ_GPIO	   SZ_1M
+#define S3C24XX_SZ_GPIO	   SZ_1M
 
 /* RTC */
-#define S3C2410_VA_RTC	   S3C2410_ADDR(0x00F00000)
+#define S3C24XX_VA_RTC	   S3C2410_ADDR(0x00F00000)
+#define S3C2400_PA_RTC	   (0x15700040)
 #define S3C2410_PA_RTC	   (0x57000000)
-#define S3C2410_SZ_RTC	   SZ_1M
+#define S3C24XX_SZ_RTC	   SZ_1M
 
 /* ADC */
-#define S3C2410_VA_ADC	   S3C2410_ADDR(0x01000000)
+#define S3C24XX_VA_ADC	   S3C2410_ADDR(0x01000000)
+#define S3C2400_PA_ADC	   (0x15800000)
 #define S3C2410_PA_ADC	   (0x58000000)
-#define S3C2410_SZ_ADC	   SZ_1M
+#define S3C24XX_SZ_ADC	   SZ_1M
 
 /* SPI */
-#define S3C2410_VA_SPI	   S3C2410_ADDR(0x01100000)
+#define S3C24XX_VA_SPI	   S3C2410_ADDR(0x01100000)
+#define S3C2400_PA_SPI	   (0x15900000)
 #define S3C2410_PA_SPI	   (0x59000000)
-#define S3C2410_SZ_SPI	   SZ_1M
+#define S3C24XX_SZ_SPI	   SZ_1M
 
 /* SDI */
-#define S3C2410_VA_SDI	   S3C2410_ADDR(0x01200000)
+#define S3C24XX_VA_SDI	   S3C2410_ADDR(0x01200000)
 #define S3C2410_PA_SDI	   (0x5A000000)
-#define S3C2410_SZ_SDI	   SZ_1M
+#define S3C24XX_SZ_SDI	   SZ_1M
+
+/* CAMIF */
+#define S3C2440_PA_CAMIF   (0x4F000000)
+#define S3C2440_SZ_CAMIF   SZ_1M
 
 /* ISA style IO, for each machine to sort out mappings for, if it
  * implements it. We reserve two 16M regions for ISA.
  */
 
-#define S3C2410_VA_ISA_WORD  S3C2410_ADDR(0x02000000)
-#define S3C2410_VA_ISA_BYTE  S3C2410_ADDR(0x03000000)
+#define S3C24XX_VA_ISA_WORD  S3C2410_ADDR(0x02000000)
+#define S3C24XX_VA_ISA_BYTE  S3C2410_ADDR(0x03000000)
 
 /* physical addresses of all the chip-select areas */
 
@@ -144,5 +177,16 @@
 
 #define S3C2410_SDRAM_PA    (S3C2410_CS6)
 
+#define S3C2400_CS0 (0x00000000)
+#define S3C2400_CS1 (0x02000000)
+#define S3C2400_CS2 (0x04000000)
+#define S3C2400_CS3 (0x06000000)
+#define S3C2400_CS4 (0x08000000)
+#define S3C2400_CS5 (0x0A000000)
+#define S3C2400_CS6 (0x0C000000)
+#define S3C2400_CS7 (0x0E000000)
+
+#define S3C2400_SDRAM_PA    (S3C2400_CS6)
+
 
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/include/asm-arm/arch-s3c2410/memory.h b/include/asm-arm/arch-s3c2410/memory.h
--- a/include/asm-arm/arch-s3c2410/memory.h
+++ b/include/asm-arm/arch-s3c2410/memory.h
@@ -17,15 +17,21 @@
  *   21-Mar-1999 RMK	Renamed to memory.h
  *		 RMK	Added TASK_SIZE and PAGE_OFFSET
  *   05-Apr-2004 BJD    Copied and altered for arch-s3c2410
+ *   17-Mar-2005 LCVR   Modified for S3C2400
 */
 
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
 /*
- * DRAM starts at 0x30000000
+ * DRAM starts at 0x30000000 for S3C2410/S3C2440
+ * and at 0x0C000000 for S3C2400
  */
+#ifdef CONFIG_CPU_S3C2400
+#define PHYS_OFFSET	(0x0C000000UL)
+#else
 #define PHYS_OFFSET	(0x30000000UL)
+#endif
 
 /*
  * These are exactly the same on the S3C2410 as the
diff --git a/include/asm-arm/arch-s3c2410/otom-map.h b/include/asm-arm/arch-s3c2410/otom-map.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/otom-map.h
@@ -0,0 +1,30 @@
+/* linux/include/asm-arm/arch-s3c2410/otom-map.h
+ *
+ * (c) 2005 Guillaume GOURAT / NexVision
+ *          guillaume.gourat@nexvision.fr
+ *
+ * NexVision OTOM board memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+/* ok, we've used up to 0x01300000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space.
+ */
+
+#ifndef __ASM_ARCH_OTOMMAP_H
+#define __ASM_ARCH_OTOMMAP_H
+
+#define OTOM_PA_CS8900A_BASE       (S3C2410_CS3 + 0x01000000)	/* nGCS3 +0x01000000 */
+#define OTOM_VA_CS8900A_BASE       S3C2410_ADDR(0x04000000)		/* 0xF4000000 */
+
+/* physical offset addresses for the peripherals */
+
+#define OTOM_PA_FLASH0_BASE        (S3C2410_CS0)				/* Bank 0 */
+
+#endif /* __ASM_ARCH_OTOMMAP_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/regs-adc.h
@@ -0,0 +1,63 @@
+/* linux/include/asm/arch-s3c2410/regs-adc.h
+ *
+ * Copyright (c) 2004 Shannon Holland <holland@loser.net>
+ *
+ * This program is free software; yosu 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.
+ *
+ * S3C2410 ADC registers
+ *
+ *  Changelog:
+ *    27-09-2004     SAH     Created file
+*/
+
+#ifndef __ASM_ARCH_REGS_ADC_H
+#define __ASM_ARCH_REGS_ADC_H "regs-adc.h"
+
+#define S3C2410_ADCREG(x) (x)
+
+#define S3C2410_ADCCON	   S3C2410_ADCREG(0x00)
+#define S3C2410_ADCTSC	   S3C2410_ADCREG(0x04)
+#define S3C2410_ADCDLY	   S3C2410_ADCREG(0x08)
+#define S3C2410_ADCDAT0	   S3C2410_ADCREG(0x0C)
+#define S3C2410_ADCDAT1	   S3C2410_ADCREG(0x10)
+
+
+/* ADCCON Register Bits */
+#define S3C2410_ADCCON_ECFLG		(1<<15)
+#define S3C2410_ADCCON_PRSCEN		(1<<14)
+#define S3C2410_ADCCON_PRSCVL(x)	(((x)&0xFF)<<6)
+#define S3C2410_ADCCON_PRSCVLMASK	(0xFF<<6)
+#define S3C2410_ADCCON_SELMUX(x)	(((x)&0x7)<<3)
+#define S3C2410_ADCCON_MUXMASK		(0x7<<3)
+#define S3C2410_ADCCON_STDBM		(1<<2)
+#define S3C2410_ADCCON_READ_START	(1<<1)
+#define S3C2410_ADCCON_ENABLE_START	(1<<0)
+#define S3C2410_ADCCON_STARTMASK	(0x3<<0)
+
+
+/* ADCTSC Register Bits */
+#define S3C2410_ADCTSC_YM_SEN		(1<<7)
+#define S3C2410_ADCTSC_YP_SEN		(1<<6)
+#define S3C2410_ADCTSC_XM_SEN		(1<<5)
+#define S3C2410_ADCTSC_XP_SEN		(1<<4)
+#define S3C2410_ADCTSC_PULL_UP_DISABLE	(1<<3)
+#define S3C2410_ADCTSC_AUTO_PST		(1<<2)
+#define S3C2410_ADCTSC_XY_PST		(0x3<<0)
+
+/* ADCDAT0 Bits */
+#define S3C2410_ADCDAT0_UPDOWN		(1<<15)
+#define S3C2410_ADCDAT0_AUTO_PST	(1<<14)
+#define S3C2410_ADCDAT0_XY_PST		(0x3<<12)
+#define S3C2410_ADCDAT0_XPDATA_MASK	(0x03FF)
+
+/* ADCDAT1 Bits */
+#define S3C2410_ADCDAT1_UPDOWN		(1<<15)
+#define S3C2410_ADCDAT1_AUTO_PST	(1<<14)
+#define S3C2410_ADCDAT1_XY_PST		(0x3<<12)
+#define S3C2410_ADCDAT1_YPDATA_MASK	(0x03FF)
+
+#endif /* __ASM_ARCH_REGS_ADC_H */
+
+
diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
--- a/include/asm-arm/arch-s3c2410/regs-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-clock.h
@@ -10,18 +10,19 @@
  * S3C2410 clock register definitions
  *
  *  Changelog:
- *    18-Aug-2004 Ben Dooks      Added 2440 definitions
- *    08-Aug-2004 Herbert Pötzl  Added CLKCON definitions
- *    19-06-2003  Ben Dooks      Created file
- *    12-03-2004  Ben Dooks      Updated include protection
- *    29-Sep-2004 Ben Dooks	 Fixed usage for assembly inclusion
- *    10-Feb-2005 Ben Dooks	 Fixed CAMDIVN address (Guillaume Gourat)
+ *    18-Aug-2004 Ben Dooks         Added 2440 definitions
+ *    08-Aug-2004 Herbert Pötzl     Added CLKCON definitions
+ *    19-06-2003  Ben Dooks         Created file
+ *    12-03-2004  Ben Dooks         Updated include protection
+ *    29-Sep-2004 Ben Dooks	    Fixed usage for assembly inclusion
+ *    10-Feb-2005 Ben Dooks	    Fixed CAMDIVN address (Guillaume Gourat)
+ *    10-Mar-2005 Lucas Villa Real  Changed S3C2410_VA to S3C24XX_VA
  */
 
 #ifndef __ASM_ARM_REGS_CLOCK
 #define __ASM_ARM_REGS_CLOCK "$Id: clock.h,v 1.4 2003/04/30 14:50:51 ben Exp $"
 
-#define S3C2410_CLKREG(x) ((x) + S3C2410_VA_CLKPWR)
+#define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR)
 
 #define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s)))
 
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -18,6 +18,8 @@
  *    17-10-2004     BJD     Added GSTATUS1 register definitions
  *    18-11-2004     BJD     Fixed definitions of GPE3, GPE4, GPE5 and GPE6
  *    18-11-2004     BJD     Added S3C2440 AC97 controls
+ *    10-Mar-2005    LCVR    Changed S3C2410_VA to S3C24XX_VA
+ *    28-Mar-2005    LCVR    Fixed definition of GPB10
 */
 
 
@@ -35,7 +37,7 @@
 #define S3C2410_GPIO_BANKG   (32*6)
 #define S3C2410_GPIO_BANKH   (32*7)
 
-#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C2410_VA_GPIO)
+#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
 #define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
 
 /* general configuration options */
@@ -44,7 +46,7 @@
 
 /* configure GPIO ports A..G */
 
-#define S3C2410_GPIOREG(x) ((x) + S3C2410_VA_GPIO)
+#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
 
 /* port A - 22bits, zero in bit X makes pin X output
  * 1 makes port special function, this is default
@@ -211,9 +213,9 @@
 #define S3C2410_GPB9_nXDACK0 (0x02 << 18)
 
 #define S3C2410_GPB10        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 10)
-#define S3C2410_GPB10_INP    (0x00 << 18)
-#define S3C2410_GPB10_OUTP   (0x01 << 18)
-#define S3C2410_GPB10_nXDRE0 (0x02 << 18)
+#define S3C2410_GPB10_INP    (0x00 << 20)
+#define S3C2410_GPB10_OUTP   (0x01 << 20)
+#define S3C2410_GPB10_nXDRE0 (0x02 << 20)
 
 /* Port C consits of 16 GPIO/Special function
  *
diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h
--- a/include/asm-arm/arch-s3c2410/regs-iis.h
+++ b/include/asm-arm/arch-s3c2410/regs-iis.h
@@ -13,6 +13,8 @@
  *    19-06-2003     BJD     Created file
  *    26-06-2003     BJD     Finished off definitions for register addresses
  *    12-03-2004     BJD     Updated include protection
+ *    07-03-2005     BJD     Added FIFO size flags and S3C2440 MPLL
+ *    05-04-2005     LCVR    Added IISFCON definitions for the S3C2400
  */
 
 #ifndef __ASM_ARCH_REGS_IIS_H
@@ -20,6 +22,7 @@
 
 #define S3C2410_IISCON	 (0x00)
 
+#define S3C2440_IISCON_MPLL	  (1<<9)
 #define S3C2410_IISCON_LRINDEX	  (1<<8)
 #define S3C2410_IISCON_TXFIFORDY  (1<<7)
 #define S3C2410_IISCON_RXFIFORDY  (1<<6)
@@ -42,6 +45,7 @@
 #define S3C2410_IISMOD_MSB	  (1<<4)
 #define S3C2410_IISMOD_8BIT	  (0<<3)
 #define S3C2410_IISMOD_16BIT	  (1<<3)
+#define S3C2410_IISMOD_BITMASK	  (1<<3)
 #define S3C2410_IISMOD_256FS	  (0<<1)
 #define S3C2410_IISMOD_384FS	  (1<<1)
 #define S3C2410_IISMOD_16FS	  (0<<0)
@@ -50,7 +54,7 @@
 
 #define S3C2410_IISPSR		(0x08)
 #define S3C2410_IISPSR_INTMASK	(31<<5)
-#define S3C2410_IISPSR_INTSHFIT	(5)
+#define S3C2410_IISPSR_INTSHIFT	(5)
 #define S3C2410_IISPSR_EXTMASK	(31<<0)
 #define S3C2410_IISPSR_EXTSHFIT	(0)
 
@@ -60,8 +64,19 @@
 #define S3C2410_IISFCON_RXDMA	  (1<<14)
 #define S3C2410_IISFCON_TXENABLE  (1<<13)
 #define S3C2410_IISFCON_RXENABLE  (1<<12)
+#define S3C2410_IISFCON_TXMASK	  (0x3f << 6)
+#define S3C2410_IISFCON_TXSHIFT	  (6)
+#define S3C2410_IISFCON_RXMASK	  (0x3f)
+#define S3C2410_IISFCON_RXSHIFT	  (0)
+
+#define S3C2400_IISFCON_TXDMA     (1<<11)
+#define S3C2400_IISFCON_RXDMA     (1<<10)
+#define S3C2400_IISFCON_TXENABLE  (1<<9)
+#define S3C2400_IISFCON_RXENABLE  (1<<8)
+#define S3C2400_IISFCON_TXMASK	  (0x07 << 4)
+#define S3C2400_IISFCON_TXSHIFT	  (4)
+#define S3C2400_IISFCON_RXMASK	  (0x07)
+#define S3C2400_IISFCON_RXSHIFT	  (0)
 
 #define S3C2410_IISFIFO  (0x10)
-
 #endif /* __ASM_ARCH_REGS_IIS_H */
-
diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h
--- a/include/asm-arm/arch-s3c2410/regs-irq.h
+++ b/include/asm-arm/arch-s3c2410/regs-irq.h
@@ -12,6 +12,7 @@
  *  Changelog:
  *    19-06-2003     BJD     Created file
  *    12-03-2004     BJD     Updated include protection
+ *    10-03-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA
  */
 
 
@@ -20,8 +21,8 @@
 
 /* interrupt controller */
 
-#define S3C2410_IRQREG(x)   ((x) + S3C2410_VA_IRQ)
-#define S3C2410_EINTREG(x)  ((x) + S3C2410_VA_GPIO)
+#define S3C2410_IRQREG(x)   ((x) + S3C24XX_VA_IRQ)
+#define S3C2410_EINTREG(x)  ((x) + S3C24XX_VA_GPIO)
 
 #define S3C2410_SRCPND	       S3C2410_IRQREG(0x000)
 #define S3C2410_INTMOD	       S3C2410_IRQREG(0x004)
diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h
--- a/include/asm-arm/arch-s3c2410/regs-lcd.h
+++ b/include/asm-arm/arch-s3c2410/regs-lcd.h
@@ -13,13 +13,14 @@
  *    12-06-2003     BJD     Created file
  *    26-06-2003     BJD     Updated LCDCON register definitions
  *    12-03-2004     BJD     Updated include protection
+ *    10-03-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA
 */
 
 
 #ifndef ___ASM_ARCH_REGS_LCD_H
 #define ___ASM_ARCH_REGS_LCD_H "$Id: lcd.h,v 1.3 2003/06/26 13:25:06 ben Exp $"
 
-#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD)
+#define S3C2410_LCDREG(x) ((x) + S3C24XX_VA_LCD)
 
 /* LCD control registers */
 #define S3C2410_LCDCON1	    S3C2410_LCDREG(0x00)
diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h
--- a/include/asm-arm/arch-s3c2410/regs-mem.h
+++ b/include/asm-arm/arch-s3c2410/regs-mem.h
@@ -11,6 +11,8 @@
  *
  *  Changelog:
  *	29-Sep-2004  BJD  Initial include for Linux
+ *      10-Mar-2005  LCVR Changed S3C2410_VA to S3C24XX_VA
+ *      04-Apr-2005  LCVR Added S3C2400 DRAM/BANKSIZE_MASK definitions
  *
 */
 
@@ -18,7 +20,7 @@
 #define __ASM_ARM_MEMREGS_H "$Id: regs.h,v 1.8 2003/05/01 15:55:41 ben Exp $"
 
 #ifndef S3C2410_MEMREG
-#define S3C2410_MEMREG(x) (S3C2410_VA_MEMCTRL + (x))
+#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
 #endif
 
 /* bus width, and wait state control */
@@ -133,8 +135,29 @@
 #define S3C2410_BANKCON_Tacs4		(0x3 << 13)
 
 #define S3C2410_BANKCON_SRAM		(0x0 << 15)
+#define S3C2400_BANKCON_EDODRAM		(0x2 << 15)
 #define S3C2410_BANKCON_SDRAM		(0x3 << 15)
 
+/* next bits only for EDO DRAM in 6,7 */
+#define S3C2400_BANKCON_EDO_Trdc1      (0x00 << 4)
+#define S3C2400_BANKCON_EDO_Trdc2      (0x01 << 4)
+#define S3C2400_BANKCON_EDO_Trdc3      (0x02 << 4)
+#define S3C2400_BANKCON_EDO_Trdc4      (0x03 << 4)
+
+/* CAS pulse width */
+#define S3C2400_BANKCON_EDO_PULSE1     (0x00 << 3)
+#define S3C2400_BANKCON_EDO_PULSE2     (0x01 << 3)
+
+/* CAS pre-charge */
+#define S3C2400_BANKCON_EDO_TCP1       (0x00 << 2)
+#define S3C2400_BANKCON_EDO_TCP2       (0x01 << 2)
+
+/* control column address select */
+#define S3C2400_BANKCON_EDO_SCANb8     (0x00 << 0)
+#define S3C2400_BANKCON_EDO_SCANb9     (0x01 << 0)
+#define S3C2400_BANKCON_EDO_SCANb10    (0x02 << 0)
+#define S3C2400_BANKCON_EDO_SCANb11    (0x03 << 0)
+
 /* next bits only for SDRAM in 6,7 */
 #define S3C2410_BANKCON_Trdc2		(0x00 << 2)
 #define S3C2410_BANKCON_Trdc3		(0x01 << 2)
@@ -161,6 +184,12 @@
 #define S3C2410_REFRESH_TRP_3clk	(1<<20)
 #define S3C2410_REFRESH_TRP_4clk	(2<<20)
 
+#define S3C2400_REFRESH_DRAM_TRP_MASK   (3<<20)
+#define S3C2400_REFRESH_DRAM_TRP_1_5clk (0<<20)
+#define S3C2400_REFRESH_DRAM_TRP_2_5clk (1<<20)
+#define S3C2400_REFRESH_DRAM_TRP_3_5clk (2<<20)
+#define S3C2400_REFRESH_DRAM_TRP_4_5clk (3<<20)
+
 #define S3C2410_REFRESH_TSRC_MASK	(3<<18)
 #define S3C2410_REFRESH_TSRC_4clk	(0<<18)
 #define S3C2410_REFRESH_TSRC_5clk	(1<<18)
@@ -183,6 +212,7 @@
 #define S3C2410_BANKSIZE_4M		(0x5 << 0)
 #define S3C2410_BANKSIZE_2M		(0x4 << 0)
 #define S3C2410_BANKSIZE_MASK		(0x7 << 0)
+#define S3C2400_BANKSIZE_MASK           (0x4 << 0)
 #define S3C2410_BANKSIZE_SCLK_EN	(1<<4)
 #define S3C2410_BANKSIZE_SCKE_EN	(1<<5)
 #define S3C2410_BANKSIZE_BURST		(1<<7)
diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/arch-s3c2410/regs-nand.h
--- a/include/asm-arm/arch-s3c2410/regs-nand.h
+++ b/include/asm-arm/arch-s3c2410/regs-nand.h
@@ -1,16 +1,17 @@
 /* linux/include/asm-arm/arch-s3c2410/regs-nand.h
  *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ * Copyright (c) 2004,2005 Simtec Electronics <linux@simtec.co.uk>
  *		      http://www.simtec.co.uk/products/SWLINUX/
  *
  * 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.
  *
- * S3C2410 clock register definitions
+ * S3C2410 NAND register definitions
  *
  *  Changelog:
  *    18-Aug-2004    BJD     Copied file from 2.4 and updated
+ *    01-May-2005    BJD     Added definitions for s3c2440 controller
 */
 
 #ifndef __ASM_ARM_REGS_NAND
@@ -26,6 +27,22 @@
 #define S3C2410_NFSTAT  S3C2410_NFREG(0x10)
 #define S3C2410_NFECC   S3C2410_NFREG(0x14)
 
+#define S3C2440_NFCONT   S3C2410_NFREG(0x04)
+#define S3C2440_NFCMD    S3C2410_NFREG(0x08)
+#define S3C2440_NFADDR   S3C2410_NFREG(0x0C)
+#define S3C2440_NFDATA   S3C2410_NFREG(0x10)
+#define S3C2440_NFECCD0  S3C2410_NFREG(0x14)
+#define S3C2440_NFECCD1  S3C2410_NFREG(0x18)
+#define S3C2440_NFECCD   S3C2410_NFREG(0x1C)
+#define S3C2440_NFSTAT   S3C2410_NFREG(0x20)
+#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
+#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
+#define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
+#define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
+#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
+#define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
+
 #define S3C2410_NFCONF_EN          (1<<15)
 #define S3C2410_NFCONF_512BYTE     (1<<14)
 #define S3C2410_NFCONF_4STEP       (1<<13)
@@ -37,7 +54,28 @@
 
 #define S3C2410_NFSTAT_BUSY        (1<<0)
 
-/* think ECC can only be 8bit read? */
+#define S3C2440_NFCONF_BUSWIDTH_8	(0<<0)
+#define S3C2440_NFCONF_BUSWIDTH_16	(1<<0)
+#define S3C2440_NFCONF_ADVFLASH		(1<<3)
+#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
+#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
+#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
+
+#define S3C2440_NFCONT_LOCKTIGHT	(1<<13)
+#define S3C2440_NFCONT_SOFTLOCK		(1<<12)
+#define S3C2440_NFCONT_ILLEGALACC_EN	(1<<10)
+#define S3C2440_NFCONT_RNBINT_EN	(1<<9)
+#define S3C2440_NFCONT_RN_FALLING	(1<<8)
+#define S3C2440_NFCONT_SPARE_ECCLOCK	(1<<6)
+#define S3C2440_NFCONT_MAIN_ECCLOCK	(1<<5)
+#define S3C2440_NFCONT_INITECC		(1<<4)
+#define S3C2440_NFCONT_nFCE		(1<<1)
+#define S3C2440_NFCONT_ENABLE		(1<<0)
+
+#define S3C2440_NFSTAT_READY		(1<<0)
+#define S3C2440_NFSTAT_nCE		(1<<1)
+#define S3C2440_NFSTAT_RnB_CHANGE	(1<<2)
+#define S3C2440_NFSTAT_ILLEGAL_ACCESS	(1<<3)
 
 #endif /* __ASM_ARM_REGS_NAND */
 
diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/arch-s3c2410/regs-rtc.h
--- a/include/asm-arm/arch-s3c2410/regs-rtc.h
+++ b/include/asm-arm/arch-s3c2410/regs-rtc.h
@@ -12,12 +12,13 @@
  *  Changelog:
  *    19-06-2003     BJD     Created file
  *    12-03-2004     BJD     Updated include protection
+ *    15-01-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA (s3c2400 support)
 */
 
 #ifndef __ASM_ARCH_REGS_RTC_H
 #define __ASM_ARCH_REGS_RTC_H __FILE__
 
-#define S3C2410_RTCREG(x) ((x) + S3C2410_VA_RTC)
+#define S3C2410_RTCREG(x) ((x) + S3C24XX_VA_RTC)
 
 #define S3C2410_RTCCON	      S3C2410_RTCREG(0x40)
 #define S3C2410_RTCCON_RTCEN  (1<<0)
diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h
--- a/include/asm-arm/arch-s3c2410/regs-serial.h
+++ b/include/asm-arm/arch-s3c2410/regs-serial.h
@@ -27,14 +27,17 @@
  * You 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
+ *
+ * Modifications:
+ *     10-Mar-2005 LCVR  Changed S3C2410_VA to S3C24XX_VA (s3c2400 support)
  */
 
 #ifndef __ASM_ARM_REGS_SERIAL_H
 #define __ASM_ARM_REGS_SERIAL_H
 
-#define S3C2410_VA_UART0      (S3C2410_VA_UART)
-#define S3C2410_VA_UART1      (S3C2410_VA_UART + 0x4000 )
-#define S3C2410_VA_UART2      (S3C2410_VA_UART + 0x8000 )
+#define S3C24XX_VA_UART0      (S3C24XX_VA_UART)
+#define S3C24XX_VA_UART1      (S3C24XX_VA_UART + 0x4000 )
+#define S3C24XX_VA_UART2      (S3C24XX_VA_UART + 0x8000 )
 
 #define S3C2410_PA_UART0      (S3C2410_PA_UART)
 #define S3C2410_PA_UART1      (S3C2410_PA_UART + 0x4000 )
@@ -73,6 +76,11 @@
 #define S3C2440_UCON_UCLK	  (1<<10)
 #define S3C2440_UCON_PCLK2	  (2<<10)
 #define S3C2440_UCON_FCLK	  (3<<10)
+#define S3C2440_UCON2_FCLK_EN	  (1<<15)
+#define S3C2440_UCON0_DIVMASK	  (15 << 12)
+#define S3C2440_UCON1_DIVMASK	  (15 << 12)
+#define S3C2440_UCON2_DIVMASK	  (7 << 12)
+#define S3C2440_UCON_DIVSHIFT	  (12)
 
 #define S3C2410_UCON_UCLK	  (1<<10)
 #define S3C2410_UCON_SBREAK	  (1<<4)
diff --git a/include/asm-arm/arch-s3c2410/regs-spi.h b/include/asm-arm/arch-s3c2410/regs-spi.h
--- a/include/asm-arm/arch-s3c2410/regs-spi.h
+++ b/include/asm-arm/arch-s3c2410/regs-spi.h
@@ -12,6 +12,7 @@
  *    20-04-2004     KF      Created file
  *    04-10-2004     BJD     Removed VA address (no longer mapped)
  *			     tidied file for submission
+ *    03-04-2005     LCVR    Added S3C2400_SPPIN_nCS definition
  */
 
 #ifndef __ASM_ARCH_REGS_SPI_H
@@ -46,6 +47,7 @@
 
 #define S3C2410_SPPIN_ENMUL	  (1<<2)	/* Multi Master Error detect */
 #define S3C2410_SPPIN_RESERVED	  (1<<1)
+#define S3C2400_SPPIN_nCS     	  (1<<1)	/* SPI Card Select */
 #define S3C2410_SPPIN_KEEP	  (1<<0)	/* Master Out keep */
 
 
diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h
--- a/include/asm-arm/arch-s3c2410/regs-timer.h
+++ b/include/asm-arm/arch-s3c2410/regs-timer.h
@@ -13,13 +13,15 @@
  *    05-06-2003     BJD     Created file
  *    26-06-2003     BJD     Added more timer definitions to mux / control
  *    12-03-2004     BJD     Updated include protection
+ *    10-02-2005     BJD     Added S3C2410_TCFG1_MUX4_SHIFT (Guillaume Gourat)
+ *    10-03-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA
 */
 
 
 #ifndef __ASM_ARCH_REGS_TIMER_H
 #define __ASM_ARCH_REGS_TIMER_H "$Id: timer.h,v 1.4 2003/05/06 19:30:50 ben Exp $"
 
-#define S3C2410_TIMERREG(x) (S3C2410_VA_TIMER + (x))
+#define S3C2410_TIMERREG(x) (S3C24XX_VA_TIMER + (x))
 #define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c))
 
 #define S3C2410_TCFG0	      S3C2410_TIMERREG(0x00)
@@ -38,6 +40,7 @@
 #define S3C2410_TCFG1_MUX4_DIV16  (3<<16)
 #define S3C2410_TCFG1_MUX4_TCLK1  (4<<16)
 #define S3C2410_TCFG1_MUX4_MASK	  (15<<16)
+#define S3C2410_TCFG1_MUX4_SHIFT  (16)
 
 #define S3C2410_TCFG1_MUX3_DIV2	  (0<<12)
 #define S3C2410_TCFG1_MUX3_DIV4	  (1<<12)
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/arch-s3c2410/regs-udc.h
@@ -11,13 +11,14 @@
  *    01-08-2004	Initial creation
  *    12-09-2004	Cleanup for submission
  *    24-10-2004	Fixed S3C2410_UDC_MAXP_REG definition
+ *    10-03-2005	Changed S3C2410_VA to S3C24XX_VA
  */
 
 #ifndef __ASM_ARCH_REGS_UDC_H
 #define __ASM_ARCH_REGS_UDC_H
 
 
-#define S3C2410_USBDREG(x) ((x) + S3C2410_VA_USBDEV)
+#define S3C2410_USBDREG(x) ((x) + S3C24XX_VA_USBDEV)
 
 #define S3C2410_UDC_FUNC_ADDR_REG	S3C2410_USBDREG(0x0140)
 #define S3C2410_UDC_PWR_REG		S3C2410_USBDREG(0x0144)
diff --git a/include/asm-arm/arch-s3c2410/regs-watchdog.h b/include/asm-arm/arch-s3c2410/regs-watchdog.h
--- a/include/asm-arm/arch-s3c2410/regs-watchdog.h
+++ b/include/asm-arm/arch-s3c2410/regs-watchdog.h
@@ -12,13 +12,14 @@
  *  Changelog:
  *    21-06-2003     BJD     Created file
  *    12-03-2004     BJD     Updated include protection
+ *    10-03-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA
 */
 
 
 #ifndef __ASM_ARCH_REGS_WATCHDOG_H
 #define __ASM_ARCH_REGS_WATCHDOG_H "$Id: watchdog.h,v 1.2 2003/04/29 13:31:09 ben Exp $"
 
-#define S3C2410_WDOGREG(x) ((x) + S3C2410_VA_WATCHDOG)
+#define S3C2410_WDOGREG(x) ((x) + S3C24XX_VA_WATCHDOG)
 
 #define S3C2410_WTCON	   S3C2410_WDOGREG(0x00)
 #define S3C2410_WTDAT	   S3C2410_WDOGREG(0x04)
diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
--- a/include/asm-arm/arch-s3c2410/system.h
+++ b/include/asm-arm/arch-s3c2410/system.h
@@ -30,7 +30,7 @@ void (*s3c24xx_idle)(void);
 
 void s3c24xx_default_idle(void)
 {
-	unsigned long reg = S3C2410_CLKCON;
+	void __iomem *reg = S3C2410_CLKCON;
 	unsigned long tmp;
 	int i;
 
diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h
--- a/include/asm-arm/arch-s3c2410/uncompress.h
+++ b/include/asm-arm/arch-s3c2410/uncompress.h
@@ -15,6 +15,8 @@
  *  12-Mar-2004 BJD  Updated header protection
  *  12-Oct-2004 BJD  Take account of debug uart configuration
  *  15-Nov-2004 BJD  Fixed uart configuration
+ *  22-Feb-2005 BJD  Added watchdog to uncompress
+ *  04-Apr-2005 LCVR Added support to S3C2400 (no cpuid at GSTATUS1)
 */
 
 #ifndef __ASM_ARCH_UNCOMPRESS_H
@@ -25,12 +27,16 @@
 /* defines for UART registers */
 #include "asm/arch/regs-serial.h"
 #include "asm/arch/regs-gpio.h"
+#include "asm/arch/regs-watchdog.h"
 
 #include <asm/arch/map.h>
 
 /* working in physical space... */
 #undef S3C2410_GPIOREG
+#undef S3C2410_WDOGREG
+
 #define S3C2410_GPIOREG(x) ((S3C2410_PA_GPIO + (x)))
+#define S3C2410_WDOGREG(x) ((S3C2410_PA_WATCHDOG + (x)))
 
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX	 (14)
@@ -56,21 +62,6 @@ uart_rd(unsigned int reg)
 }
 
 
-/* currently we do not need the watchdog... */
-#define arch_decomp_wdog()
-
-
-static void error(char *err);
-
-static void
-arch_decomp_setup(void)
-{
-	/* we may need to setup the uart(s) here if we are not running
-	 * on an BAST... the BAST will have left the uarts configured
-	 * after calling linux.
-	 */
-}
-
 /* we can deal with the case the UARTs are being run
  * in FIFO mode, so that we don't hold up our execution
  * waiting for tx to happen...
@@ -79,9 +70,12 @@ arch_decomp_setup(void)
 static void
 putc(char ch)
 {
-	int cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
+	int cpuid = S3C2410_GSTATUS1_2410;
 
+#ifndef CONFIG_CPU_S3C2400
+	cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
 	cpuid &= S3C2410_GSTATUS1_IDMASK;
+#endif
 
 	if (ch == '\n')
 		putc('\r');    /* expand newline to \r\n */
@@ -122,4 +116,47 @@ putstr(const char *ptr)
 	}
 }
 
+/* CONFIG_S3C2410_BOOT_WATCHDOG
+ *
+ * Simple boot-time watchdog setup, to reboot the system if there is
+ * any problem with the boot process
+*/
+
+#ifdef CONFIG_S3C2410_BOOT_WATCHDOG
+
+#define WDOG_COUNT (0xff00)
+
+#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
+
+static inline void arch_decomp_wdog(void)
+{
+	__raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+}
+
+static void arch_decomp_wdog_start(void)
+{
+	__raw_writel(WDOG_COUNT, S3C2410_WTDAT);
+	__raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+	__raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+}
+
+#else
+#define arch_decomp_wdog_start()
+#define arch_decomp_wdog()
+#endif
+
+static void error(char *err);
+
+static void
+arch_decomp_setup(void)
+{
+	/* we may need to setup the uart(s) here if we are not running
+	 * on an BAST... the BAST will have left the uarts configured
+	 * after calling linux.
+	 */
+
+	arch_decomp_wdog_start();
+}
+
+
 #endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/include/asm-arm/arch-s3c2410/vmalloc.h b/include/asm-arm/arch-s3c2410/vmalloc.h
--- a/include/asm-arm/arch-s3c2410/vmalloc.h
+++ b/include/asm-arm/arch-s3c2410/vmalloc.h
@@ -19,18 +19,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	  (0xE0000000)
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/include/asm-arm/arch-sa1100/collie.h b/include/asm-arm/arch-sa1100/collie.h
--- a/include/asm-arm/arch-sa1100/collie.h
+++ b/include/asm-arm/arch-sa1100/collie.h
@@ -66,34 +66,6 @@
 #define COLLIE_LCM_IRQ_GPIO_nSD_DETECT	IRQ_LOCOMO_GPIO13
 #define COLLIE_LCM_IRQ_GPIO_nSD_WP	IRQ_LOCOMO_GPIO14
 
-/*
- * Flash Memory mappings
- *
- */
-
-#define FLASH_MEM_BASE 0xe8ffc000
-#define	FLASH_DATA(adr) (*(volatile unsigned int*)(FLASH_MEM_BASE+(adr)))
-#define	FLASH_DATA_F(adr) (*(volatile float32 *)(FLASH_MEM_BASE+(adr)))
-#define FLASH_MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 )  | ( b << 8 ) | a )
-
-// COMADJ
-#define FLASH_COMADJ_MAJIC	FLASH_MAGIC_CHG('C','M','A','D')
-#define	FLASH_COMADJ_MAGIC_ADR	0x00
-#define	FLASH_COMADJ_DATA_ADR	0x04
-
-// TOUCH PANEL
-#define FLASH_TOUCH_MAJIC	FLASH_MAGIC_CHG('T','U','C','H')
-#define	FLASH_TOUCH_MAGIC_ADR	0x1C
-#define	FLASH_TOUCH_XP_DATA_ADR	0x20
-#define	FLASH_TOUCH_YP_DATA_ADR	0x24
-#define	FLASH_TOUCH_XD_DATA_ADR	0x28
-#define	FLASH_TOUCH_YD_DATA_ADR	0x2C
-
-// AD
-#define FLASH_AD_MAJIC	FLASH_MAGIC_CHG('B','V','A','D')
-#define	FLASH_AD_MAGIC_ADR	0x30
-#define	FLASH_AD_DATA_ADR	0x34
-
 /* GPIO's on the TC35143AF (Toshiba Analog Frontend) */
 #define COLLIE_TC35143_GPIO_VERSION0    UCB_IO_0	/* GPIO0=Version                 */
 #define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1	/* GPIO1=TBL_CHK                 */
diff --git a/include/asm-arm/arch-sa1100/vmalloc.h b/include/asm-arm/arch-sa1100/vmalloc.h
--- a/include/asm-arm/arch-sa1100/vmalloc.h
+++ b/include/asm-arm/arch-sa1100/vmalloc.h
@@ -1,15 +1,4 @@
 /*
  * linux/include/asm-arm/arch-sa1100/vmalloc.h
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (0xe8000000)
diff --git a/include/asm-arm/arch-shark/vmalloc.h b/include/asm-arm/arch-shark/vmalloc.h
--- a/include/asm-arm/arch-shark/vmalloc.h
+++ b/include/asm-arm/arch-shark/vmalloc.h
@@ -1,15 +1,4 @@
 /*
  * linux/include/asm-arm/arch-rpc/vmalloc.h
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-versatile/platform.h b/include/asm-arm/arch-versatile/platform.h
--- a/include/asm-arm/arch-versatile/platform.h
+++ b/include/asm-arm/arch-versatile/platform.h
@@ -498,11 +498,17 @@
 /*
  * IB2 Versatile/AB expansion board definitions
  */
-#define VERSATILE_IB2_CAMERA_BANK	0x24000000
-#define VERSATILE_IB2_KBD_DATAREG	0x25000000
-#define VERSATILE_IB2_IER		0x26000000	/* for VICINTSOURCE27 */
-#define VERSATILE_IB2_CTRL		0x27000000
-#define VERSATILE_IB2_STAT		0x27000004
+#define VERSATILE_IB2_CAMERA_BANK	VERSATILE_IB2_BASE
+#define VERSATILE_IB2_KBD_DATAREG	(VERSATILE_IB2_BASE + 0x01000000)
+
+/* VICINTSOURCE27 */
+#define VERSATILE_IB2_INT_BASE		(VERSATILE_IB2_BASE + 0x02000000)
+#define VERSATILE_IB2_IER		(VERSATILE_IB2_INT_BASE + 0)
+#define VERSATILE_IB2_ISR		(VERSATILE_IB2_INT_BASE + 4)
+
+#define VERSATILE_IB2_CTL_BASE		(VERSATILE_IB2_BASE + 0x03000000)
+#define VERSATILE_IB2_CTRL		(VERSATILE_IB2_CTL_BASE + 0)
+#define VERSATILE_IB2_STAT		(VERSATILE_IB2_CTL_BASE + 4)
 #endif
 
 #endif
diff --git a/include/asm-arm/arch-versatile/vmalloc.h b/include/asm-arm/arch-versatile/vmalloc.h
--- a/include/asm-arm/arch-versatile/vmalloc.h
+++ b/include/asm-arm/arch-versatile/vmalloc.h
@@ -18,16 +18,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET		(8*1024*1024)
-#define VMALLOC_START		(((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x)	((unsigned long)(x))
 #define VMALLOC_END		(PAGE_OFFSET + 0x18000000)
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -151,6 +151,7 @@ static inline void atomic_clear_mask(uns
 #define atomic_dec_and_test(v)	(atomic_sub_return(1, v) == 0)
 #define atomic_inc_return(v)    (atomic_add_return(1, v))
 #define atomic_dec_return(v)    (atomic_sub_return(1, v))
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
 
 #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
 
diff --git a/include/asm-arm/bug.h b/include/asm-arm/bug.h
--- a/include/asm-arm/bug.h
+++ b/include/asm-arm/bug.h
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 extern volatile void __bug(const char *file, int line, void *data);
 
@@ -17,6 +18,8 @@ extern volatile void __bug(const char *f
 #endif
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -237,16 +237,16 @@ extern void dmac_flush_range(unsigned lo
  * space" model to handle this.
  */
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
-		flush_dcache_page(page);	\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
+		flush_dcache_page(page);			\
 	} while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
 	} while (0)
 
 /*
@@ -269,7 +269,7 @@ flush_cache_range(struct vm_area_struct 
 }
 
 static inline void
-flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr)
+flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
 {
 	if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
 		unsigned long addr = user_addr & PAGE_MASK;
@@ -312,9 +312,9 @@ flush_cache_page(struct vm_area_struct *
 extern void flush_dcache_page(struct page *);
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_user_range(vma,page,addr,len) \
 	flush_dcache_page(page)
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
--- a/include/asm-arm/dma-mapping.h
+++ b/include/asm-arm/dma-mapping.h
@@ -21,6 +21,9 @@ extern void consistent_sync(void *kaddr,
  * properly.  For example, if your device can only drive the low 24-bits
  * during bus mastering, then you would pass 0x00ffffff as the mask
  * to this function.
+ *
+ * FIXME: This should really be a platform specific issue - we should
+ * return false if GFP_DMA allocations may not satisfy the supplied 'mask'.
  */
 static inline int dma_supported(struct device *dev, u64 mask)
 {
diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h
--- a/include/asm-arm/ecard.h
+++ b/include/asm-arm/ecard.h
@@ -155,8 +155,8 @@ struct expansion_card {
 	struct resource		resource[ECARD_NUM_RESOURCES];
 
 	/* Public data */
-	volatile unsigned char *irqaddr;	/* address of IRQ register	*/
-	volatile unsigned char *fiqaddr;	/* address of FIQ register	*/
+	void __iomem		*irqaddr;	/* address of IRQ register	*/
+	void __iomem		*fiqaddr;	/* address of FIQ register	*/
 	unsigned char		irqmask;	/* IRQ mask			*/
 	unsigned char		fiqmask;	/* FIQ mask			*/
 	unsigned char  		claimed;	/* Card claimed?		*/
@@ -207,9 +207,16 @@ struct in_chunk_dir {
 extern int ecard_readchunk (struct in_chunk_dir *cd, struct expansion_card *ec, int id, int num);
 
 /*
- * Obtain the address of a card
+ * Obtain the address of a card.  This returns the "old style" address
+ * and should no longer be used.
  */
-extern __deprecated unsigned int ecard_address (struct expansion_card *ec, card_type_t card_type, card_speed_t speed);
+static inline unsigned int __deprecated
+ecard_address(struct expansion_card *ec, card_type_t type, card_speed_t speed)
+{
+	extern unsigned int __ecard_address(struct expansion_card *,
+					    card_type_t, card_speed_t);
+	return __ecard_address(ec, type, speed);
+}
 
 /*
  * Request and release ecard resources
diff --git a/include/asm-arm/elf.h b/include/asm-arm/elf.h
--- a/include/asm-arm/elf.h
+++ b/include/asm-arm/elf.h
@@ -38,9 +38,9 @@ typedef struct user_fp elf_fpregset_t;
  */
 #define ELF_CLASS	ELFCLASS32
 #ifdef __ARMEB__
-#define ELF_DATA	ELFDATA2MSB;
+#define ELF_DATA	ELFDATA2MSB
 #else
-#define ELF_DATA	ELFDATA2LSB;
+#define ELF_DATA	ELFDATA2LSB
 #endif
 #define ELF_ARCH	EM_ARM
 
diff --git a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h
--- a/include/asm-arm/hardware/amba.h
+++ b/include/asm-arm/hardware/amba.h
@@ -31,7 +31,7 @@ struct amba_driver {
 	int			(*probe)(struct amba_device *, void *);
 	int			(*remove)(struct amba_device *);
 	void			(*shutdown)(struct amba_device *);
-	int			(*suspend)(struct amba_device *, u32);
+	int			(*suspend)(struct amba_device *, pm_message_t);
 	int			(*resume)(struct amba_device *);
 	struct amba_id		*id_table;
 };
diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h
--- a/include/asm-arm/hardware/amba_clcd.h
+++ b/include/asm-arm/hardware/amba_clcd.h
@@ -153,7 +153,7 @@ struct clcd_fb {
 
 static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 {
-	u32 val;
+	u32 val, cpl;
 
 	/*
 	 * Program the CLCD controller registers and start the CLCD
@@ -164,7 +164,10 @@ static inline void clcdfb_decode(struct 
 	val |= (fb->fb.var.left_margin - 1) << 24;
 	regs->tim0 = val;
 
-	val = fb->fb.var.yres - 1;
+	val = fb->fb.var.yres;
+	if (fb->panel->cntl & CNTL_LCDDUAL)
+		val /= 2;
+	val -= 1;
 	val |= (fb->fb.var.vsync_len - 1) << 10;
 	val |= fb->fb.var.lower_margin << 16;
 	val |= fb->fb.var.upper_margin << 24;
@@ -174,13 +177,17 @@ static inline void clcdfb_decode(struct 
 	val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
 	val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
 
-	if (fb->panel->cntl & CNTL_LCDTFT)
-		val |= (fb->fb.var.xres_virtual - 1) << 16;
-	else if (fb->panel->cntl & CNTL_LCDBW)
-		printk("what value for CPL for stnmono panels?");
-	else
-		val |= ((fb->fb.var.xres_virtual * 8 / 3) - 1) << 16;
-	regs->tim2 = val;
+	cpl = fb->fb.var.xres_virtual;
+	if (fb->panel->cntl & CNTL_LCDTFT)	  /* TFT */
+		/* / 1 */;
+	else if (!fb->fb.var.grayscale)		  /* STN color */
+		cpl = cpl * 8 / 3;
+	else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
+		cpl /= 8;
+	else					  /* STN monochrome, 4bit */
+		cpl /= 4;
+
+	regs->tim2 = val | ((cpl - 1) << 16);
 
 	regs->tim3 = fb->panel->tim3;
 
@@ -204,7 +211,7 @@ static inline void clcdfb_decode(struct 
 	case 16:
 		val |= CNTL_LCDBPP16;
 		break;
-	case 24:
+	case 32:
 		val |= CNTL_LCDBPP24;
 		break;
 	}
@@ -215,8 +222,8 @@ static inline void clcdfb_decode(struct 
 
 static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
 {
-	var->xres_virtual = var->xres = (var->xres + 7) & ~7;
-	var->yres_virtual = var->yres;
+	var->xres_virtual = var->xres = (var->xres + 15) & ~15;
+	var->yres_virtual = var->yres = (var->yres + 1) & ~1;
 
 #define CHECK(e,l,h) (var->e < l || var->e > h)
 	if (CHECK(right_margin, (5+1), 256) ||	/* back porch */
diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h
--- a/include/asm-arm/hardware/clock.h
+++ b/include/asm-arm/hardware/clock.h
@@ -26,10 +26,13 @@ struct clk;
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
- * @id: device ID
+ * @id: clock comsumer ID
  *
  * Returns a struct clk corresponding to the clock producer, or
- * valid IS_ERR() condition containing errno.
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer.  (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
  */
 struct clk *clk_get(struct device *dev, const char *id);
 
diff --git a/include/asm-arm/hardware/locomo.h b/include/asm-arm/hardware/locomo.h
--- a/include/asm-arm/hardware/locomo.h
+++ b/include/asm-arm/hardware/locomo.h
@@ -35,146 +35,139 @@
 #define LOCOMO_MCSX3	0x1c
 
 /* Touch panel controller */
-#define LOCOMO_ASD	0x20	/* AD start delay */
-#define LOCOMO_HSD	0x28	/* HSYS delay */
-#define LOCOMO_HSC	0x2c	/* HSYS period */
-#define LOCOMO_TADC	0x30	/* tablet ADC clock */
-
-/* TFT signal */
-#define LOCOMO_TC	0x38	/* TFT control signal */
-#define LOCOMO_CPSD	0x3c	/* CPS delay */
-
-/* Key controller */
-#define LOCOMO_KIB	0x40	/* KIB level */
-#define LOCOMO_KSC	0x44	/* KSTRB control */
-#define LOCOMO_KCMD	0x48	/* KSTRB command */
-#define LOCOMO_KIC	0x4c	/* Key interrupt */
+#define LOCOMO_ASD	0x20		/* AD start delay */
+#define LOCOMO_HSD	0x28		/* HSYS delay */
+#define LOCOMO_HSC	0x2c		/* HSYS period */
+#define LOCOMO_TADC	0x30		/* tablet ADC clock */
 
-/* Audio clock */
-#define LOCOMO_ACC	0x54
-
-/* SPI interface */
-#define LOCOMO_SPIMD	0x60	/* SPI mode setting */
-#define LOCOMO_SPICT	0x64	/* SPI mode control */
-#define LOCOMO_SPIST	0x68	/* SPI status */
-#define LOCOMO_SPIIS	0x70	/* SPI interrupt status */
-#define LOCOMO_SPIWE	0x74	/* SPI interrupt status write enable */
-#define LOCOMO_SPIIE	0x78	/* SPI interrupt enable */
-#define LOCOMO_SPIIR	0x7c	/* SPI interrupt request */
-#define LOCOMO_SPITD	0x80	/* SPI transfer data write */
-#define LOCOMO_SPIRD	0x84	/* SPI receive data read */
-#define LOCOMO_SPITS	0x88	/* SPI transfer data shift */
-#define LOCOMO_SPIRS	0x8C	/* SPI receive data shift */
-
-#define	LOCOMO_SPI_TEND	(1 << 3)	/* Transfer end bit */
-#define	LOCOMO_SPI_OVRN	(1 << 2)	/* Over Run bit */
-#define	LOCOMO_SPI_RFW	(1 << 1)	/* write buffer bit */
-#define	LOCOMO_SPI_RFR	(1)		/* read buffer bit */
-
-/* GPIO */
-#define LOCOMO_GPD	0x90	/* GPIO direction */
-#define LOCOMO_GPE	0x94	/* GPIO input enable */
-#define LOCOMO_GPL	0x98	/* GPIO level */
-#define LOCOMO_GPO	0x9c	/* GPIO out data setteing */
-#define LOCOMO_GRIE	0xa0	/* GPIO rise detection */
-#define LOCOMO_GFIE	0xa4	/* GPIO fall detection */
-#define LOCOMO_GIS	0xa8	/* GPIO edge detection status */
-#define LOCOMO_GWE	0xac	/* GPIO status write enable */
-#define LOCOMO_GIE	0xb0	/* GPIO interrupt enable */
-#define LOCOMO_GIR	0xb4	/* GPIO interrupt request */
-
-#define LOCOMO_GPIO0	(1<<0)
-#define LOCOMO_GPIO1	(1<<1)
-#define LOCOMO_GPIO2	(1<<2)
-#define LOCOMO_GPIO3	(1<<3)
-#define LOCOMO_GPIO4	(1<<4)
-#define LOCOMO_GPIO5	(1<<5)
-#define LOCOMO_GPIO6	(1<<6)
-#define LOCOMO_GPIO7	(1<<7)
-#define LOCOMO_GPIO8	(1<<8)
-#define LOCOMO_GPIO9	(1<<9)
-#define LOCOMO_GPIO10	(1<<10)
-#define LOCOMO_GPIO11	(1<<11)
-#define LOCOMO_GPIO12	(1<<12)
-#define LOCOMO_GPIO13	(1<<13)
-#define LOCOMO_GPIO14	(1<<14)
-#define LOCOMO_GPIO15	(1<<15)
-
-/* Front light adjustment controller */
-#define LOCOMO_ALS	0xc8	/* Adjust light cycle */
-#define LOCOMO_ALD	0xcc	/* Adjust light duty */
-
-/* PCM audio interface */
-#define LOCOMO_PAIF	0xd0
 
 /* Long time timer */
-#define LOCOMO_LTC	0xd8	/* LTC interrupt setting */
-#define LOCOMO_LTINT	0xdc	/* LTC interrupt */
+#define LOCOMO_LTC	0xd8		/* LTC interrupt setting */
+#define LOCOMO_LTINT	0xdc		/* LTC interrupt */
 
 /* DAC control signal for LCD (COMADJ ) */
-#define LOCOMO_DAC	0xe0
-
+#define LOCOMO_DAC		0xe0
 /* DAC control */
 #define	LOCOMO_DAC_SCLOEB	0x08	/* SCL pin output data       */
 #define	LOCOMO_DAC_TEST		0x04	/* Test bit                  */
 #define	LOCOMO_DAC_SDA		0x02	/* SDA pin level (read-only) */
 #define	LOCOMO_DAC_SDAOEB	0x01	/* SDA pin output data       */
 
-/* LED controller */
-#define LOCOMO_LPT0		0xe8	/* LEDPWM0 timer */
-#define LOCOMO_LPT1		0xec	/* LEDPWM1 timer */
+/* SPI interface */
+#define LOCOMO_SPIMD	0x60		/* SPI mode setting */
+#define LOCOMO_SPICT	0x64		/* SPI mode control */
+#define LOCOMO_SPIST	0x68		/* SPI status */
+#define LOCOMO_SPIIS	0x70		/* SPI interrupt status */
+#define LOCOMO_SPIWE	0x74		/* SPI interrupt status write enable */
+#define LOCOMO_SPIIE	0x78		/* SPI interrupt enable */
+#define LOCOMO_SPIIR	0x7c		/* SPI interrupt request */
+#define LOCOMO_SPITD	0x80		/* SPI transfer data write */
+#define LOCOMO_SPIRD	0x84		/* SPI receive data read */
+#define LOCOMO_SPITS	0x88		/* SPI transfer data shift */
+#define LOCOMO_SPIRS	0x8C		/* SPI receive data shift */
+#define	LOCOMO_SPI_TEND	(1 << 3)	/* Transfer end bit */
+#define	LOCOMO_SPI_OVRN	(1 << 2)	/* Over Run bit */
+#define	LOCOMO_SPI_RFW	(1 << 1)	/* write buffer bit */
+#define	LOCOMO_SPI_RFR	(1)		/* read buffer bit */
 
-#define LOCOMO_LPT_TOFH		0x80			/* */
-#define LOCOMO_LPT_TOFL		0x08			/* */
-#define LOCOMO_LPT_TOH(TOH)	((TOH & 0x7) << 4)	/* */
-#define LOCOMO_LPT_TOL(TOL)	((TOL & 0x7))		/* */
+/* GPIO */
+#define LOCOMO_GPD		0x90	/* GPIO direction */
+#define LOCOMO_GPE		0x94	/* GPIO input enable */
+#define LOCOMO_GPL		0x98	/* GPIO level */
+#define LOCOMO_GPO		0x9c	/* GPIO out data setteing */
+#define LOCOMO_GRIE		0xa0	/* GPIO rise detection */
+#define LOCOMO_GFIE		0xa4	/* GPIO fall detection */
+#define LOCOMO_GIS		0xa8	/* GPIO edge detection status */
+#define LOCOMO_GWE		0xac	/* GPIO status write enable */
+#define LOCOMO_GIE		0xb0	/* GPIO interrupt enable */
+#define LOCOMO_GIR		0xb4	/* GPIO interrupt request */
+#define	LOCOMO_GPIO(Nb)		(0x01 << (Nb))
+#define LOCOMO_GPIO_RTS		LOCOMO_GPIO(0)
+#define LOCOMO_GPIO_CTS		LOCOMO_GPIO(1)
+#define LOCOMO_GPIO_DSR		LOCOMO_GPIO(2)
+#define LOCOMO_GPIO_DTR		LOCOMO_GPIO(3)
+#define LOCOMO_GPIO_LCD_VSHA_ON	LOCOMO_GPIO(4)
+#define LOCOMO_GPIO_LCD_VSHD_ON	LOCOMO_GPIO(5)
+#define LOCOMO_GPIO_LCD_VEE_ON	LOCOMO_GPIO(6)
+#define LOCOMO_GPIO_LCD_MOD	LOCOMO_GPIO(7)
+#define LOCOMO_GPIO_DAC_ON	LOCOMO_GPIO(8)
+#define LOCOMO_GPIO_FL_VR	LOCOMO_GPIO(9)
+#define LOCOMO_GPIO_DAC_SDATA	LOCOMO_GPIO(10)
+#define LOCOMO_GPIO_DAC_SCK	LOCOMO_GPIO(11)
+#define LOCOMO_GPIO_DAC_SLOAD	LOCOMO_GPIO(12)
+
+/* Start the definitions of the devices.  Each device has an initial
+ * base address and a series of offsets from that base address. */
+
+/* Keyboard controller */
+#define LOCOMO_KEYBOARD		0x40
+#define LOCOMO_KIB		0x00	/* KIB level */
+#define LOCOMO_KSC		0x04	/* KSTRB control */
+#define LOCOMO_KCMD		0x08	/* KSTRB command */
+#define LOCOMO_KIC		0x0c	/* Key interrupt */
 
+/* Front light adjustment controller */
+#define LOCOMO_FRONTLIGHT	0xc8
+#define LOCOMO_ALS		0x00	/* Adjust light cycle */
+#define LOCOMO_ALD		0x04	/* Adjust light duty */
+
+/* Backlight controller: TFT signal */
+#define LOCOMO_BACKLIGHT	0x38
+#define LOCOMO_TC		0x00		/* TFT control signal */
+#define LOCOMO_CPSD		0x04		/* CPS delay */
+
+/* Audio controller */
+#define LOCOMO_AUDIO		0x54
+#define LOCOMO_ACC		0x00	/* Audio clock */
+#define LOCOMO_PAIF		0x7C	/* PCM audio interface */
 /* Audio clock */
-#define	LOCOMO_ACC_XON		0x80	/*  */
-#define	LOCOMO_ACC_XEN		0x40	/*  */
-#define	LOCOMO_ACC_XSEL0	0x00	/*  */
-#define	LOCOMO_ACC_XSEL1	0x20	/*  */
-#define	LOCOMO_ACC_MCLKEN	0x10	/*  */
-#define	LOCOMO_ACC_64FSEN	0x08	/*  */
+#define	LOCOMO_ACC_XON		0x80
+#define	LOCOMO_ACC_XEN		0x40
+#define	LOCOMO_ACC_XSEL0	0x00
+#define	LOCOMO_ACC_XSEL1	0x20
+#define	LOCOMO_ACC_MCLKEN	0x10
+#define	LOCOMO_ACC_64FSEN	0x08
 #define	LOCOMO_ACC_CLKSEL000	0x00	/* mclk  2 */
 #define	LOCOMO_ACC_CLKSEL001	0x01	/* mclk  3 */
 #define	LOCOMO_ACC_CLKSEL010	0x02	/* mclk  4 */
 #define	LOCOMO_ACC_CLKSEL011	0x03	/* mclk  6 */
 #define	LOCOMO_ACC_CLKSEL100	0x04	/* mclk  8 */
 #define	LOCOMO_ACC_CLKSEL101	0x05	/* mclk 12 */
-
 /* PCM audio interface */
-#define	LOCOMO_PAIF_SCINV	0x20	/*  */
-#define	LOCOMO_PAIF_SCEN	0x10	/*  */
-#define	LOCOMO_PAIF_LRCRST	0x08	/*  */
-#define	LOCOMO_PAIF_LRCEVE	0x04	/*  */
-#define	LOCOMO_PAIF_LRCINV	0x02	/*  */
-#define	LOCOMO_PAIF_LRCEN	0x01	/*  */
+#define	LOCOMO_PAIF_SCINV	0x20
+#define	LOCOMO_PAIF_SCEN	0x10
+#define	LOCOMO_PAIF_LRCRST	0x08
+#define	LOCOMO_PAIF_LRCEVE	0x04
+#define	LOCOMO_PAIF_LRCINV	0x02
+#define	LOCOMO_PAIF_LRCEN	0x01
 
-/* GPIO */
-#define	LOCOMO_GPIO(Nb)		(0x01 << (Nb))	/* LoCoMo GPIO [0...15] */
-#define LOCOMO_GPIO_RTS		LOCOMO_GPIO(0)	/* LoCoMo GPIO  [0] */
-#define LOCOMO_GPIO_CTS		LOCOMO_GPIO(1)	/* LoCoMo GPIO  [1] */
-#define LOCOMO_GPIO_DSR		LOCOMO_GPIO(2)	/* LoCoMo GPIO  [2] */
-#define LOCOMO_GPIO_DTR		LOCOMO_GPIO(3)	/* LoCoMo GPIO  [3] */
-#define LOCOMO_GPIO_LCD_VSHA_ON	LOCOMO_GPIO(4)	/* LoCoMo GPIO  [4] */
-#define LOCOMO_GPIO_LCD_VSHD_ON	LOCOMO_GPIO(5)	/* LoCoMo GPIO  [5] */
-#define LOCOMO_GPIO_LCD_VEE_ON	LOCOMO_GPIO(6)	/* LoCoMo GPIO  [6] */
-#define LOCOMO_GPIO_LCD_MOD	LOCOMO_GPIO(7)	/* LoCoMo GPIO  [7] */
-#define LOCOMO_GPIO_DAC_ON	LOCOMO_GPIO(8)	/* LoCoMo GPIO  [8] */
-#define LOCOMO_GPIO_FL_VR	LOCOMO_GPIO(9)	/* LoCoMo GPIO  [9] */
-#define LOCOMO_GPIO_DAC_SDATA	LOCOMO_GPIO(10)	/* LoCoMo GPIO [10] */
-#define LOCOMO_GPIO_DAC_SCK	LOCOMO_GPIO(11)	/* LoCoMo GPIO [11] */
-#define LOCOMO_GPIO_DAC_SLOAD	LOCOMO_GPIO(12)	/* LoCoMo GPIO [12] */
+/* LED controller */
+#define LOCOMO_LED		0xe8
+#define LOCOMO_LPT0		0x00
+#define LOCOMO_LPT1		0x04
+/* LED control */
+#define LOCOMO_LPT_TOFH		0x80
+#define LOCOMO_LPT_TOFL		0x08
+#define LOCOMO_LPT_TOH(TOH)	((TOH & 0x7) << 4)
+#define LOCOMO_LPT_TOL(TOL)	((TOL & 0x7))
 
 extern struct bus_type locomo_bus_type;
 
+#define LOCOMO_DEVID_KEYBOARD	0
+#define LOCOMO_DEVID_FRONTLIGHT	1
+#define LOCOMO_DEVID_BACKLIGHT	2
+#define LOCOMO_DEVID_AUDIO	3
+#define LOCOMO_DEVID_LED	4
+#define LOCOMO_DEVID_UART	5
+
 struct locomo_dev {
 	struct device	dev;
 	unsigned int	devid;
-	struct resource	res;
-	void		*mapbase;
 	unsigned int	irq[1];
+
+	void		*mapbase;
+	unsigned long	length;
+
 	u64		dma_mask;
 };
 
@@ -188,7 +181,7 @@ struct locomo_driver {
 	unsigned int		devid;
 	int (*probe)(struct locomo_dev *);
 	int (*remove)(struct locomo_dev *);
-	int (*suspend)(struct locomo_dev *, u32);
+	int (*suspend)(struct locomo_dev *, pm_message_t);
 	int (*resume)(struct locomo_dev *);
 };
 
@@ -201,4 +194,13 @@ void locomo_lcd_power(struct locomo_dev 
 int locomo_driver_register(struct locomo_driver *);
 void locomo_driver_unregister(struct locomo_driver *);
 
+/* GPIO control functions */
+void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir);
+unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits);
+unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits);
+void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set);
+
+/* M62332 control function */
+void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel);
+
 #endif
diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
--- a/include/asm-arm/hardware/sa1111.h
+++ b/include/asm-arm/hardware/sa1111.h
@@ -567,7 +567,7 @@ struct sa1111_driver {
 	unsigned int		devid;
 	int (*probe)(struct sa1111_dev *);
 	int (*remove)(struct sa1111_dev *);
-	int (*suspend)(struct sa1111_dev *, u32);
+	int (*suspend)(struct sa1111_dev *, pm_message_t);
 	int (*resume)(struct sa1111_dev *);
 };
 
diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h
--- a/include/asm-arm/hardware/scoop.h
+++ b/include/asm-arm/hardware/scoop.h
@@ -40,8 +40,8 @@ struct scoop_config {
 	unsigned short io_dir;
 };
 
-void reset_scoop(void);
-unsigned short set_scoop_gpio(unsigned short bit);
-unsigned short reset_scoop_gpio(unsigned short bit);
-unsigned short read_scoop_reg(unsigned short reg);
-void write_scoop_reg(unsigned short reg, unsigned short data);
+void reset_scoop(struct device *dev);
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit);
+unsigned short read_scoop_reg(struct device *dev, unsigned short reg);
+void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data);
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -47,13 +47,13 @@ extern void __raw_readsb(void __iomem *a
 extern void __raw_readsw(void __iomem *addr, void *data, int wordlen);
 extern void __raw_readsl(void __iomem *addr, void *data, int longlen);
 
-#define __raw_writeb(v,a)	(*(volatile unsigned char __force  *)(a) = (v))
-#define __raw_writew(v,a)	(*(volatile unsigned short __force *)(a) = (v))
-#define __raw_writel(v,a)	(*(volatile unsigned int __force   *)(a) = (v))
-
-#define __raw_readb(a)		(*(volatile unsigned char __force  *)(a))
-#define __raw_readw(a)		(*(volatile unsigned short __force *)(a))
-#define __raw_readl(a)		(*(volatile unsigned int __force   *)(a))
+#define __raw_writeb(v,a)	(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a) = (v))
+#define __raw_writew(v,a)	(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
+#define __raw_writel(v,a)	(__chk_io_ptr(a), *(volatile unsigned int __force   *)(a) = (v))
+
+#define __raw_readb(a)		(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a))
+#define __raw_readw(a)		(__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+#define __raw_readl(a)		(__chk_io_ptr(a), *(volatile unsigned int __force   *)(a))
 
 /*
  * Bad read/write accesses...
@@ -99,12 +99,16 @@ extern void __readwrite_bug(const char *
  */
 #ifdef __io
 #define outb(v,p)		__raw_writeb(v,__io(p))
-#define outw(v,p)		__raw_writew(cpu_to_le16(v),__io(p))
-#define outl(v,p)		__raw_writel(cpu_to_le32(v),__io(p))
-
-#define inb(p)	({ unsigned int __v = __raw_readb(__io(p)); __v; })
-#define inw(p)	({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; })
-#define inl(p)	({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; })
+#define outw(v,p)		__raw_writew((__force __u16) \
+					cpu_to_le16(v),__io(p))
+#define outl(v,p)		__raw_writel((__force __u32) \
+					cpu_to_le32(v),__io(p))
+
+#define inb(p)	({ __u8 __v = __raw_readb(__io(p)); __v; })
+#define inw(p)	({ __u16 __v = le16_to_cpu((__force __le16) \
+			__raw_readw(__io(p))); __v; })
+#define inl(p)	({ __u32 __v = le32_to_cpu((__force __le32) \
+			__raw_readl(__io(p))); __v; })
 
 #define outsb(p,d,l)		__raw_writesb(__io(p),d,l)
 #define outsw(p,d,l)		__raw_writesw(__io(p),d,l)
@@ -149,9 +153,11 @@ extern void _memset_io(void __iomem *, i
  * IO port primitives for more information.
  */
 #ifdef __mem_pci
-#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; })
-#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; })
-#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; })
+#define readb(c) ({ __u8  __v = __raw_readb(__mem_pci(c)); __v; })
+#define readw(c) ({ __u16 __v = le16_to_cpu((__force __le16) \
+					__raw_readw(__mem_pci(c))); __v; })
+#define readl(c) ({ __u32 __v = le32_to_cpu((__force __le32) \
+					__raw_readl(__mem_pci(c))); __v; })
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
@@ -161,8 +167,10 @@ extern void _memset_io(void __iomem *, i
 #define readsl(p,d,l)		__raw_readsl(__mem_pci(p),d,l)
 
 #define writeb(v,c)		__raw_writeb(v,__mem_pci(c))
-#define writew(v,c)		__raw_writew(cpu_to_le16(v),__mem_pci(c))
-#define writel(v,c)		__raw_writel(cpu_to_le32(v),__mem_pci(c))
+#define writew(v,c)		__raw_writew((__force __u16) \
+					cpu_to_le16(v),__mem_pci(c))
+#define writel(v,c)		__raw_writel((__force __u32) \
+					cpu_to_le32(v),__mem_pci(c))
 
 #define writesb(p,d,l)		__raw_writesb(__mem_pci(p),d,l)
 #define writesw(p,d,l)		__raw_writesw(__mem_pci(p),d,l)
@@ -271,5 +279,16 @@ extern void __iounmap(void __iomem *addr
 #define BIOVEC_MERGEABLE(vec1, vec2)	\
 	((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif	/* __KERNEL__ */
 #endif	/* __ASM_ARM_IO_H */
diff --git a/include/asm-arm/ipc.h b/include/asm-arm/ipc.h
--- a/include/asm-arm/ipc.h
+++ b/include/asm-arm/ipc.h
@@ -1,28 +1 @@
-#ifndef __ASMARM_IPC_H
-#define __ASMARM_IPC_H
-
-/* 
- * These are used to wrap system calls on ARM.
- *
- * See arch/arm/kernel/sys-arm.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#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 IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h
--- a/include/asm-arm/mach/arch.h
+++ b/include/asm-arm/mach/arch.h
@@ -16,7 +16,7 @@ struct sys_timer;
 
 struct machine_desc {
 	/*
-	 * Note! The first four elements are used
+	 * Note! The first five elements are used
 	 * by assembler code in head-armv.S
 	 */
 	unsigned int		nr;		/* architecture number	*/
diff --git a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h
--- a/include/asm-arm/mach/map.h
+++ b/include/asm-arm/mach/map.h
@@ -18,13 +18,14 @@ struct map_desc {
 
 struct meminfo;
 
-#define MT_DEVICE	0
-#define MT_CACHECLEAN	1
-#define MT_MINICLEAN	2
-#define MT_LOW_VECTORS	3
-#define MT_HIGH_VECTORS	4
-#define MT_MEMORY	5
-#define MT_ROM		6
+#define MT_DEVICE		0
+#define MT_CACHECLEAN		1
+#define MT_MINICLEAN		2
+#define MT_LOW_VECTORS		3
+#define MT_HIGH_VECTORS		4
+#define MT_MEMORY		5
+#define MT_ROM			6
+#define MT_IXP2000_DEVICE	7
 
 extern void create_memmap_holes(struct meminfo *);
 extern void memtable_init(struct meminfo *);
diff --git a/include/asm-arm/mach/sharpsl_param.h b/include/asm-arm/mach/sharpsl_param.h
new file mode 100644
--- /dev/null
+++ b/include/asm-arm/mach/sharpsl_param.h
@@ -0,0 +1,37 @@
+/*
+ * Hardware parameter area specific to Sharp SL series devices
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches
+ *
+ * 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.
+ *
+ */
+
+struct sharpsl_param_info {
+  unsigned int comadj_keyword;
+  unsigned int comadj;
+
+  unsigned int uuid_keyword;
+  unsigned char uuid[16];
+
+  unsigned int touch_keyword;
+  unsigned int touch_xp;
+  unsigned int touch_yp;
+  unsigned int touch_xd;
+  unsigned int touch_yd;
+
+  unsigned int adadj_keyword;
+  unsigned int adadj;
+
+  unsigned int phad_keyword;
+  unsigned int phadadj;
+} __attribute__((packed));
+
+
+extern struct sharpsl_param_info sharpsl_param;
+extern void sharpsl_save_param(void);
+
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
--- a/include/asm-arm/page.h
+++ b/include/asm-arm/page.h
@@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *t
 				 unsigned long user);
 #endif
 
-#define clear_user_page(addr,vaddr,pg)			\
-	do {						\
-		preempt_disable();			\
-		__cpu_clear_user_page(addr, vaddr);	\
-		preempt_enable();			\
-	} while (0)
-
-#define copy_user_page(to,from,vaddr,pg)		\
-	do {						\
-		preempt_disable();			\
-		__cpu_copy_user_page(to, from, vaddr);	\
-		preempt_enable();			\
-	} while (0)
+#define clear_user_page(addr,vaddr,pg)	 __cpu_clear_user_page(addr, vaddr)
+#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
 
 #define clear_page(page)	memzero((void *)(page), PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
@@ -171,6 +160,9 @@ typedef unsigned long pgprot_t;
 
 #endif /* STRICT_MM_TYPECHECKS */
 
+/* the upper-most page table pointer */
+extern pmd_t *top_pmd;
+
 /* Pure 2^n version of get_order */
 static inline int get_order(unsigned long size)
 {
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -17,6 +17,23 @@
 #include <asm/arch/vmalloc.h>
 
 /*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ *
+ * Note that platforms may override VMALLOC_START, but they must provide
+ * VMALLOC_END.  VMALLOC_END defines the (exclusive) limit of this space,
+ * which may not overlap IO space.
+ */
+#ifndef VMALLOC_START
+#define VMALLOC_OFFSET		(8*1024*1024)
+#define VMALLOC_START		(((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#endif
+
+/*
  * Hardware-wise, we have a two level page table structure, where the first
  * level has 4096 entries, and the second level has 256 entries.  Each entry
  * is one 32-bit word.  Most of the bits in the second level entry are used
@@ -102,10 +119,24 @@ extern void __pgd_error(const char *file
 #define PGDIR_SIZE		(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK		(~(PGDIR_SIZE-1))
 
+/*
+ * This is the lowest virtual address we can permit any user space
+ * mapping to be mapped at.  This is particularly important for
+ * non-high vector CPUs.
+ */
+#define FIRST_USER_ADDRESS	PAGE_SIZE
+
 #define FIRST_USER_PGD_NR	1
 #define USER_PTRS_PER_PGD	((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
 
 /*
+ * ARMv6 supersection address mask and size definitions.
+ */
+#define SUPERSECTION_SHIFT	24
+#define SUPERSECTION_SIZE	(1UL << SUPERSECTION_SHIFT)
+#define SUPERSECTION_MASK	(~(SUPERSECTION_SIZE-1))
+
+/*
  * Hardware page table definitions.
  *
  * + Level 1 descriptor (PMD)
@@ -129,6 +160,7 @@ extern void __pgd_error(const char *file
 #define PMD_SECT_APX		(1 << 15)	/* v6 */
 #define PMD_SECT_S		(1 << 16)	/* v6 */
 #define PMD_SECT_nG		(1 << 17)	/* v6 */
+#define PMD_SECT_SUPER		(1 << 18)	/* v6 */
 
 #define PMD_SECT_UNCACHED	(0)
 #define PMD_SECT_BUFFERED	(PMD_SECT_BUFFERABLE)
@@ -254,7 +286,7 @@ extern struct page *empty_zero_page;
 #define pfn_pte(pfn,prot)	(__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 
 #define pte_none(pte)		(!pte_val(pte))
-#define pte_clear(ptep)		set_pte((ptep), __pte(0))
+#define pte_clear(mm,addr,ptep)	set_pte_at((mm),(addr),(ptep), __pte(0))
 #define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
 #define pte_offset_kernel(dir,addr)	(pmd_page_kernel(*(dir)) + __pte_index(addr))
 #define pte_offset_map(dir,addr)	(pmd_page_kernel(*(dir)) + __pte_index(addr))
@@ -263,6 +295,7 @@ extern struct page *empty_zero_page;
 #define pte_unmap_nested(pte)	do { } while (0)
 
 #define set_pte(ptep, pte)	cpu_set_pte(ptep,pte)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 /*
  * The following only work if pte_present() is true.
@@ -308,12 +341,6 @@ PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
 #define pmd_present(pmd)	(pmd_val(pmd))
 #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
 
-#define set_pmd(pmdp,pmd)		\
-	do {				\
-		*(pmdp) = pmd;		\
-		flush_pmd_entry(pmdp);	\
-	} while (0)
-
 #define copy_pmd(pmdpd,pmdps)		\
 	do {				\
 		pmdpd[0] = pmdps[0];	\
@@ -416,6 +443,13 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD
 #define io_remap_page_range(vma,from,phys,size,prot) \
 		remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+		remap_pfn_range(vma, from, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define pgtable_cache_init() do { } while (0)
 
 #endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -23,8 +23,6 @@
 #include <asm/procinfo.h>
 #include <asm/types.h>
 
-#define KERNEL_STACK_SIZE	PAGE_SIZE
-
 union debug_insn {
 	u32	arm;
 	u16	thumb;
@@ -87,8 +85,9 @@ unsigned long get_wchan(struct task_stru
  */
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
-#define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019])
-#define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1017])
+#define KSTK_REGS(tsk)	(((struct pt_regs *)(THREAD_START_SP + (unsigned long)(tsk)->thread_info)) - 1)
+#define KSTK_EIP(tsk)	KSTK_REGS(tsk)->ARM_pc
+#define KSTK_ESP(tsk)	KSTK_REGS(tsk)->ARM_sp
 
 /*
  * Prefetching support - only ARMv5.
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -17,6 +17,9 @@
 #define PTRACE_GETFPREGS	14
 #define PTRACE_SETFPREGS	15
 
+#define PTRACE_GETWMMXREGS	18
+#define PTRACE_SETWMMXREGS	19
+
 #define PTRACE_OLDSETOPTIONS	21
 
 #define PTRACE_GET_THREAD_AREA	22
@@ -139,11 +142,8 @@ extern unsigned long profile_pc(struct p
 #endif
 
 #ifdef __KERNEL__
-extern void show_regs(struct pt_regs *);
-
-#define predicate(x)	(x & 0xf0000000)
+#define predicate(x)		((x) & 0xf0000000)
 #define PREDICATE_ALWAYS	0xe0000000
-
 #endif
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/asm-arm/rtc.h b/include/asm-arm/rtc.h
--- a/include/asm-arm/rtc.h
+++ b/include/asm-arm/rtc.h
@@ -18,15 +18,16 @@ struct rtc_ops {
 	void		(*release)(void);
 	int		(*ioctl)(unsigned int, unsigned long);
 
-	void		(*read_time)(struct rtc_time *);
+	int		(*read_time)(struct rtc_time *);
 	int		(*set_time)(struct rtc_time *);
-	void		(*read_alarm)(struct rtc_wkalrm *);
+	int		(*read_alarm)(struct rtc_wkalrm *);
 	int		(*set_alarm)(struct rtc_wkalrm *);
 	int		(*proc)(char *buf);
 };
 
 void rtc_time_to_tm(unsigned long, struct rtc_time *);
 int rtc_tm_to_time(struct rtc_time *, unsigned long *);
+int rtc_valid_tm(struct rtc_time *);
 void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
 void rtc_update(unsigned long, unsigned long);
 int register_rtc(struct rtc_ops *);
diff --git a/include/asm-arm/signal.h b/include/asm-arm/signal.h
--- a/include/asm-arm/signal.h
+++ b/include/asm-arm/signal.h
@@ -114,34 +114,10 @@ typedef unsigned long sigset_t;
 #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		0x80000000
-#define SA_SAMPLE_RANDOM	0x10000000
 #define SA_IRQNOMASK		0x08000000
-#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 __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-arm/string.h b/include/asm-arm/string.h
--- a/include/asm-arm/string.h
+++ b/include/asm-arm/string.h
@@ -29,15 +29,22 @@ extern void __memzero(void *ptr, __kerne
 
 #define memset(p,v,n)							\
 	({								\
-		if ((n) != 0) {						\
+	 	void *__p = (p); size_t __n = n;			\
+		if ((__n) != 0) {					\
 			if (__builtin_constant_p((v)) && (v) == 0)	\
-				__memzero((p),(n));			\
+				__memzero((__p),(__n));			\
 			else						\
-				memset((p),(v),(n));			\
+				memset((__p),(v),(__n));		\
 		}							\
-		(p);							\
+		(__p);							\
 	})
 
-#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); })
+#define memzero(p,n) 							\
+	({ 								\
+	 	void *__p = (p); size_t __n = n;			\
+	 	if ((__n) != 0) 					\
+	 		__memzero((__p),(__n)); 			\
+	 	(__p); 							\
+	 })
 
 #endif
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -99,6 +99,9 @@ void hook_fault_code(int nr, int (*fn)(u
 #define tas(ptr) (xchg((ptr),1))
 
 extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
+extern void __show_regs(struct pt_regs *);
 
 extern int cpu_architecture(void);
 
@@ -383,6 +386,8 @@ static inline unsigned long __xchg(unsig
 
 #endif /* __ASSEMBLY__ */
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -14,6 +14,10 @@
 
 #include <asm/fpstate.h>
 
+#define THREAD_SIZE_ORDER	1
+#define THREAD_SIZE		8192
+#define THREAD_START_SP		(THREAD_SIZE - 8)
+
 #ifndef __ASSEMBLY__
 
 struct task_struct;
@@ -77,8 +81,6 @@ struct thread_info {
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
-#define THREAD_SIZE		8192
-
 /*
  * how to get the thread information struct from C
  */
diff --git a/include/asm-arm/timex.h b/include/asm-arm/timex.h
--- a/include/asm-arm/timex.h
+++ b/include/asm-arm/timex.h
@@ -16,8 +16,6 @@
 
 typedef unsigned long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h
--- a/include/asm-arm/tlb.h
+++ b/include/asm-arm/tlb.h
@@ -54,38 +54,44 @@ tlb_finish_mmu(struct mmu_gather *tlb, u
 {
 	struct mm_struct *mm = tlb->mm;
 	unsigned long freed = tlb->freed;
-	int rss = mm->rss;
+	int rss = get_mm_counter(mm, rss);
 
 	if (rss < freed)
 		freed = rss;
-	mm->rss = rss - freed;
+	add_mm_counter(mm, rss, -freed);
 
-	if (freed) {
+	if (tlb->fullmm)
 		flush_tlb_mm(mm);
-		tlb->flushes++;
-	} else {
-		tlb->avoided_flushes++;
-	}
 
 	/* keep the page table cache within bounds */
 	check_pgt_cache();
 }
 
-static inline unsigned int
-tlb_is_full_mm(struct mmu_gather *tlb)
+static inline unsigned int tlb_is_full_mm(struct mmu_gather *tlb)
 {
-     return tlb->fullmm;
+	return tlb->fullmm;
 }
 
 #define tlb_remove_tlb_entry(tlb,ptep,address)	do { } while (0)
 
-#define tlb_start_vma(tlb,vma)						\
-	do {								\
-		if (!tlb->fullmm)					\
-			flush_cache_range(vma, vma->vm_start, vma->vm_end); \
-	} while (0)
+/*
+ * In the case of tlb vma handling, we can optimise these away in the
+ * case where we're doing a full MM flush.  When we're doing a munmap,
+ * the vmas are adjusted to only cover the region to be torn down.
+ */
+static inline void
+tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+	if (!tlb->fullmm)
+		flush_cache_range(vma, vma->vm_start, vma->vm_end);
+}
 
-#define tlb_end_vma(tlb,vma)			do { } while (0)
+static inline void
+tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+	if (!tlb->fullmm)
+		flush_tlb_range(vma, vma->vm_start, vma->vm_end);
+}
 
 #define tlb_remove_page(tlb,page)	free_page_and_swap_cache(page)
 #define pte_free_tlb(tlb,ptep)		pte_free(ptep)
diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
--- a/include/asm-arm/uaccess.h
+++ b/include/asm-arm/uaccess.h
@@ -77,7 +77,8 @@ static inline void set_fs (mm_segment_t 
 
 #define access_ok(type,addr,size)	(__range_ok(addr,size) == 0)
 
-static inline int verify_area(int type, const void __user *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/unistd.h
  *
- *  Copyright (C) 2001-2003 Russell King
+ *  Copyright (C) 2001-2005 Russell King
  *
  * 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
@@ -307,6 +307,50 @@
 #define __NR_mq_getsetattr		(__NR_SYSCALL_BASE+279)
 #define __NR_waitid			(__NR_SYSCALL_BASE+280)
 
+#if 0 /* reserve these for un-muxing socketcall */
+#define __NR_socket			(__NR_SYSCALL_BASE+281)
+#define __NR_bind			(__NR_SYSCALL_BASE+282)
+#define __NR_connect			(__NR_SYSCALL_BASE+283)
+#define __NR_listen			(__NR_SYSCALL_BASE+284)
+#define __NR_accept			(__NR_SYSCALL_BASE+285)
+#define __NR_getsockname		(__NR_SYSCALL_BASE+286)
+#define __NR_getpeername		(__NR_SYSCALL_BASE+287)
+#define __NR_socketpair			(__NR_SYSCALL_BASE+288)
+#define __NR_send			(__NR_SYSCALL_BASE+289)
+#define __NR_sendto			(__NR_SYSCALL_BASE+290)
+#define __NR_recv			(__NR_SYSCALL_BASE+291)
+#define __NR_recvfrom			(__NR_SYSCALL_BASE+292)
+#define __NR_shutdown			(__NR_SYSCALL_BASE+293)
+#define __NR_setsockopt			(__NR_SYSCALL_BASE+294)
+#define __NR_getsockopt			(__NR_SYSCALL_BASE+295)
+#define __NR_sendmsg			(__NR_SYSCALL_BASE+296)
+#define __NR_recvmsg			(__NR_SYSCALL_BASE+297)
+#endif
+
+#if 0 /* reserve these for un-muxing ipc */
+#define __NR_semop			(__NR_SYSCALL_BASE+298)
+#define __NR_semget			(__NR_SYSCALL_BASE+299)
+#define __NR_semctl			(__NR_SYSCALL_BASE+300)
+#define __NR_msgsnd			(__NR_SYSCALL_BASE+301)
+#define __NR_msgrcv			(__NR_SYSCALL_BASE+302)
+#define __NR_msgget			(__NR_SYSCALL_BASE+303)
+#define __NR_msgctl			(__NR_SYSCALL_BASE+304)
+#define __NR_shmat			(__NR_SYSCALL_BASE+305)
+#define __NR_shmdt			(__NR_SYSCALL_BASE+306)
+#define __NR_shmget			(__NR_SYSCALL_BASE+307)
+#define __NR_shmctl			(__NR_SYSCALL_BASE+308)
+#endif
+
+#define __NR_add_key			(__NR_SYSCALL_BASE+309)
+#define __NR_request_key		(__NR_SYSCALL_BASE+310)
+#define __NR_keyctl			(__NR_SYSCALL_BASE+311)
+
+#if 0 /* reserved for un-muxing ipc */
+#define __NR_semtimedop			(__NR_SYSCALL_BASE+312)
+#endif
+
+#define __NR_vserver			(__NR_SYSCALL_BASE+313)
+
 /*
  * The following SWIs are ARM private.
  */
@@ -315,8 +359,7 @@
 #define __ARM_NR_cacheflush		(__ARM_NR_BASE+2)
 #define __ARM_NR_usr26			(__ARM_NR_BASE+3)
 #define __ARM_NR_usr32			(__ARM_NR_BASE+4)
-
-#define __ARM_NR_set_tls		(__ARM_NR_BASE+0x800)
+#define __ARM_NR_set_tls		(__ARM_NR_BASE+5)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
@@ -335,7 +378,7 @@
 
 #define __syscall_return(type, res)					\
 do {									\
-	if ((unsigned long)(res) >= (unsigned long)(-125)) {		\
+	if ((unsigned long)(res) >= (unsigned long)(-129)) {		\
 		errno = -(res);						\
 		res = -1;						\
 	}								\
@@ -509,6 +552,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* __ASM_ARM_UNISTD_H */
diff --git a/include/asm-arm26/bug.h b/include/asm-arm26/bug.h
--- a/include/asm-arm26/bug.h
+++ b/include/asm-arm26/bug.h
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 extern volatile void __bug(const char *file, int line, void *data);
 /* give file/line information */
@@ -12,6 +13,8 @@ extern volatile void __bug(const char *f
 #endif
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-arm26/cacheflush.h b/include/asm-arm26/cacheflush.h
--- a/include/asm-arm26/cacheflush.h
+++ b/include/asm-arm26/cacheflush.h
@@ -23,7 +23,7 @@
 #define flush_cache_all()                       do { } while (0)
 #define flush_cache_mm(mm)                      do { } while (0)
 #define flush_cache_range(vma,start,end)        do { } while (0)
-#define flush_cache_page(vma,vmaddr)            do { } while (0)
+#define flush_cache_page(vma,vmaddr,pfn)        do { } while (0)
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
diff --git a/include/asm-arm26/elf.h b/include/asm-arm26/elf.h
--- a/include/asm-arm26/elf.h
+++ b/include/asm-arm26/elf.h
@@ -36,7 +36,7 @@ typedef struct { void *null; } elf_fpreg
  * These are used to set parameters in the core dumps.
  */
 #define ELF_CLASS	ELFCLASS32
-#define ELF_DATA	ELFDATA2LSB;
+#define ELF_DATA	ELFDATA2LSB
 #define ELF_ARCH	EM_ARM
 
 #define USE_ELF_CORE_DUMP
diff --git a/include/asm-arm26/io.h b/include/asm-arm26/io.h
--- a/include/asm-arm26/io.h
+++ b/include/asm-arm26/io.h
@@ -420,5 +420,16 @@ extern void consistent_sync(void *vaddr,
 #define BIOVEC_MERGEABLE(vec1, vec2)	\
 	((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif	/* __KERNEL__ */
 #endif	/* __ASM_ARM_IO_H */
diff --git a/include/asm-arm26/ipc.h b/include/asm-arm26/ipc.h
--- a/include/asm-arm26/ipc.h
+++ b/include/asm-arm26/ipc.h
@@ -1,28 +1 @@
-#ifndef __ASMARM_IPC_H
-#define __ASMARM_IPC_H
-
-/* 
- * These are used to wrap system calls on ARM.
- *
- * See arch/arm/kernel/sys-arm.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#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 IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -62,6 +62,13 @@
 #define PTRS_PER_PMD            1
 #define PTRS_PER_PTE            32
 
+/*
+ * This is the lowest virtual address we can permit any user space
+ * mapping to be mapped at.  This is particularly important for
+ * non-high vector CPUs.
+ */
+#define FIRST_USER_ADDRESS	PAGE_SIZE
+
 #define FIRST_USER_PGD_NR       1
 #define USER_PTRS_PER_PGD       ((TASK_SIZE/PGD_SIZE) - FIRST_USER_PGD_NR)
 
@@ -154,7 +161,8 @@ extern struct page *empty_zero_page;
 #define pte_none(pte)           (!pte_val(pte))
 #define pte_present(pte)        (pte_val(pte) & _PAGE_PRESENT)
 #define set_pte(pte_ptr, pte)   ((*(pte_ptr)) = (pte))
-#define pte_clear(ptep)         set_pte((ptep), __pte(0))
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+#define pte_clear(mm,addr,ptep)	set_pte_at((mm),(addr),(ptep), __pte(0))
 
 /* macros to ease the getting of pointers to stuff... */
 #define pgd_offset(mm, addr)	((pgd_t *)(mm)->pgd        + __pgd_index(addr))
@@ -292,6 +300,13 @@ static inline pte_t mk_pte_phys(unsigned
 #define io_remap_page_range(vma,from,phys,size,prot) \
 		remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+		remap_pfn_range(vma, from, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASMARM_PGTABLE_H */
diff --git a/include/asm-arm26/signal.h b/include/asm-arm26/signal.h
--- a/include/asm-arm26/signal.h
+++ b/include/asm-arm26/signal.h
@@ -114,30 +114,10 @@ typedef unsigned long sigset_t;
 #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		0x80000000
-#define SA_SAMPLE_RANDOM	0x10000000
 #define SA_IRQNOMASK		0x08000000
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
@@ -186,9 +166,6 @@ typedef struct sigaltstack {
 #include <asm/sigcontext.h>
 
 #define sigmask(sig)	(1UL << ((sig) - 1))
-//FIXME!!!
-//#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
-
 #endif
 
 
diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h
--- a/include/asm-arm26/system.h
+++ b/include/asm-arm26/system.h
@@ -245,6 +245,8 @@ static inline unsigned long __xchg(unsig
 
 #endif /* __ASSEMBLY__ */
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/asm-arm26/timex.h b/include/asm-arm26/timex.h
--- a/include/asm-arm26/timex.h
+++ b/include/asm-arm26/timex.h
@@ -21,8 +21,6 @@
 
 typedef unsigned long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-arm26/tlb.h b/include/asm-arm26/tlb.h
--- a/include/asm-arm26/tlb.h
+++ b/include/asm-arm26/tlb.h
@@ -37,11 +37,11 @@ tlb_finish_mmu(struct mmu_gather *tlb, u
 {
         struct mm_struct *mm = tlb->mm;
         unsigned long freed = tlb->freed;
-        int rss = mm->rss;
+        int rss = get_mm_counter(mm, rss);
 
         if (rss < freed)
                 freed = rss;
-        mm->rss = rss - freed;
+        add_mm_counter(mm, rss, -freed);
 
         if (freed) {
                 flush_tlb_mm(mm);
diff --git a/include/asm-arm26/uaccess.h b/include/asm-arm26/uaccess.h
--- a/include/asm-arm26/uaccess.h
+++ b/include/asm-arm26/uaccess.h
@@ -40,7 +40,8 @@ extern int fixup_exception(struct pt_reg
 
 #define access_ok(type,addr,size)	(__range_ok(addr,size) == 0)
 
-static inline int verify_area(int type, const void * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h
--- a/include/asm-arm26/unistd.h
+++ b/include/asm-arm26/unistd.h
@@ -495,6 +495,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* __ASM_ARM_UNISTD_H */
diff --git a/include/asm-cris/cacheflush.h b/include/asm-cris/cacheflush.h
--- a/include/asm-cris/cacheflush.h
+++ b/include/asm-cris/cacheflush.h
@@ -10,7 +10,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h
--- a/include/asm-cris/io.h
+++ b/include/asm-cris/io.h
@@ -86,4 +86,15 @@ extern void iounmap(void *addr);
 #define outsw(x,y,z)
 #define outsl(x,y,z)
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif
diff --git a/include/asm-cris/ipc.h b/include/asm-cris/ipc.h
--- a/include/asm-cris/ipc.h
+++ b/include/asm-cris/ipc.h
@@ -1,35 +1 @@
-#ifndef __CRIS_IPC_H__
-#define __CRIS_IPC_H__
-
-/* 
- * These are used to wrap system calls on CRIS.
- *
- * See arch/cris/kernel/sys_cris.c for ugly details..
- *
- * Same as x86 version.
- *
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
--- a/include/asm-cris/page.h
+++ b/include/asm-cris/page.h
@@ -77,10 +77,6 @@ typedef struct { unsigned long pgprot; }
   printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 } while (0)
 
-#define PAGE_BUG(page) do { \
-         BUG(); \
-} while (0)
-
 /* Pure 2^n version of get_order */
 static inline int get_order(unsigned long size)
 {
diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h
--- a/include/asm-cris/pgalloc.h
+++ b/include/asm-cris/pgalloc.h
@@ -1,7 +1,6 @@
 #ifndef _CRIS_PGALLOC_H
 #define _CRIS_PGALLOC_H
 
-#include <asm/page.h>
 #include <linux/threads.h>
 #include <linux/mm.h>
 
diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
--- a/include/asm-cris/pgtable.h
+++ b/include/asm-cris/pgtable.h
@@ -34,6 +34,8 @@ extern void paging_init(void);
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
 /*
  * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -74,7 +76,7 @@ extern void paging_init(void);
  */
 
 #define USER_PTRS_PER_PGD       (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR       0
+#define FIRST_USER_ADDRESS      0
 
 /* zero page used for uninitialized stuff */
 #ifndef __ASSEMBLY__
@@ -101,7 +103,7 @@ extern unsigned long empty_zero_page;
 
 #define pte_none(x)	(!pte_val(x))
 #define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
-#define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
+#define pte_clear(mm,addr,xp)	do { pte_val(*(xp)) = 0; } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
 /* by removing the _PAGE_KERNEL bit from the comparision, the same pmd_bad
diff --git a/include/asm-cris/signal.h b/include/asm-cris/signal.h
--- a/include/asm-cris/signal.h
+++ b/include/asm-cris/signal.h
@@ -108,30 +108,7 @@ typedef unsigned long sigset_t;
 #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
- */
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h
--- a/include/asm-cris/system.h
+++ b/include/asm-cris/system.h
@@ -69,4 +69,6 @@ extern inline unsigned long __xchg(unsig
   return x;
 }
 
+#define arch_align_stack(x) (x)
+
 #endif
diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h
--- a/include/asm-cris/uaccess.h
+++ b/include/asm-cris/uaccess.h
@@ -91,7 +91,8 @@
 #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 __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h
--- a/include/asm-cris/unistd.h
+++ b/include/asm-cris/unistd.h
@@ -387,6 +387,6 @@ extern inline _syscall3(pid_t,waitpid,pi
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _ASM_CRIS_UNISTD_H_ */
diff --git a/include/asm-frv/bug.h b/include/asm-frv/bug.h
--- a/include/asm-frv/bug.h
+++ b/include/asm-frv/bug.h
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 /*
  * Tell the user there is some problem.
  */
@@ -45,6 +46,7 @@ do {						\
 #define HAVE_ARCH_KGDB_BAD_PAGE
 #define kgdb_bad_page(page) do { kgdb_raise(SIGABRT); } while(0)
 #endif
+#endif
 
 #include <asm-generic/bug.h>
 
diff --git a/include/asm-frv/cacheflush.h b/include/asm-frv/cacheflush.h
--- a/include/asm-frv/cacheflush.h
+++ b/include/asm-frv/cacheflush.h
@@ -21,7 +21,7 @@
 #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_cache_page(vma, vmaddr, pfn)	do {} while(0)
 #define flush_cache_vmap(start, end)		do {} while(0)
 #define flush_cache_vunmap(start, end)		do {} while(0)
 #define flush_dcache_mmap_lock(mapping)		do {} while(0)
diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h
--- a/include/asm-frv/highmem.h
+++ b/include/asm-frv/highmem.h
@@ -44,8 +44,6 @@ extern unsigned long highstart_pfn, high
 #define kmap_pte ______kmap_pte_in_TLB
 extern pte_t *pkmap_page_table;
 
-extern void kmap_init(void);
-
 #define flush_cache_kmaps()  do { } while (0)
 
 /*
diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h
--- a/include/asm-frv/io.h
+++ b/include/asm-frv/io.h
@@ -273,6 +273,18 @@ static inline void flush_write_buffers(v
 	__asm__ __volatile__ ("membar" : : :"memory");
 }
 
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_IO_H */
diff --git a/include/asm-frv/ipc.h b/include/asm-frv/ipc.h
--- a/include/asm-frv/ipc.h
+++ b/include/asm-frv/ipc.h
@@ -1,33 +1 @@
-#ifndef __ASM_IPC_H__
-#define __ASM_IPC_H__
-
-/*
- * These are used to wrap system calls on FR-V
- *
- * See arch/frv/kernel/sys_frv.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC		25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
-
+#include <asm-generic/ipc.h>
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -141,7 +141,7 @@ extern unsigned long empty_zero_page;
 #define PTRS_PER_PTE		4096
 
 #define USER_PGDS_IN_LAST_PML4	(TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define USER_PGD_PTRS		(PAGE_OFFSET >> PGDIR_SHIFT)
 #define KERNEL_PGD_PTRS		(PTRS_PER_PGD - USER_PGD_PTRS)
@@ -173,6 +173,7 @@ do {							\
 	*(pteptr) = (pteval);				\
 	asm volatile("dcf %M0" :: "U"(*pteptr));	\
 } while(0)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 #define set_pte_atomic(pteptr, pteval)		set_pte((pteptr), (pteval))
 
@@ -348,12 +349,12 @@ static inline pmd_t *pmd_offset(pud_t *d
 
 /*
  * Define this to warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
+ * done without a 'access_ok(VERIFY_WRITE,..)'
  */
-#undef TEST_VERIFY_AREA
+#undef TEST_ACCESS_OK
 
 #define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
-#define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
+#define pte_clear(mm,addr,xp)	do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
@@ -390,39 +391,33 @@ static inline pte_t pte_mkdirty(pte_t pt
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte &= ~_PAGE_WP; return pte; }
 
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	int i = test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
 	asm volatile("dcf %M0" :: "U"(*ptep));
 	return i;
 }
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	int i = test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
 	asm volatile("dcf %M0" :: "U"(*ptep));
 	return i;
 }
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long x = xchg(&ptep->pte, 0);
 	asm volatile("dcf %M0" :: "U"(*ptep));
 	return __pte(x);
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	set_bit(_PAGE_BIT_WP, ptep);
 	asm volatile("dcf %M0" :: "U"(*ptep));
 }
 
-static inline void ptep_mkdirty(pte_t *ptep)
-{
-	set_bit(_PAGE_BIT_DIRTY, ptep);
-	asm volatile("dcf %M0" :: "U"(*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.
@@ -508,11 +503,17 @@ static inline int pte_file(pte_t pte)
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-frv/signal.h b/include/asm-frv/signal.h
--- a/include/asm-frv/signal.h
+++ b/include/asm-frv/signal.h
@@ -107,30 +107,7 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -123,4 +123,6 @@ do {						\
 extern void die_if_kernel(const char *, ...) __attribute__((format(printf, 1, 2)));
 extern void free_initmem(void);
 
+#define arch_align_stack(x) (x)
+
 #endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-frv/tlbflush.h b/include/asm-frv/tlbflush.h
--- a/include/asm-frv/tlbflush.h
+++ b/include/asm-frv/tlbflush.h
@@ -58,7 +58,8 @@ do {								\
 #define __flush_tlb_global()			flush_tlb_all()
 #define flush_tlb()				flush_tlb_all()
 #define flush_tlb_kernel_range(start, end)	flush_tlb_all()
-#define flush_tlb_pgtables(mm,start,end)	asm volatile("movgs gr0,scr0 ! movgs gr0,scr1");
+#define flush_tlb_pgtables(mm,start,end) \
+	asm volatile("movgs %0,scr0 ! movgs %0,scr1" :: "r"(ULONG_MAX) : "memory");
 
 #else
 
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h
--- a/include/asm-frv/uaccess.h
+++ b/include/asm-frv/uaccess.h
@@ -67,7 +67,8 @@ static inline int ___range_ok(unsigned l
 #define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0)
 #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
 
-static inline int verify_area(int type, const void * addr, unsigned long size)
+/* this function will go away soon - use access_ok() / __range_ok() instead */
+static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
 {
 	return __range_ok(addr, size);
 }
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -495,7 +495,7 @@ static inline pid_t wait(int * wait_stat
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* _ASM_UNISTD_H_ */
diff --git a/include/asm-generic/4level-fixup.h b/include/asm-generic/4level-fixup.h
--- a/include/asm-generic/4level-fixup.h
+++ b/include/asm-generic/4level-fixup.h
@@ -2,6 +2,7 @@
 #define _4LEVEL_FIXUP_H
 
 #define __ARCH_HAS_4LEVEL_HACK
+#define __PAGETABLE_PUD_FOLDED
 
 #define PUD_SIZE			PGDIR_SIZE
 #define PUD_MASK			PGDIR_MASK
@@ -31,4 +32,7 @@
 #define pud_free(x)			do { } while (0)
 #define __pud_free_tlb(tlb, x)		do { } while (0)
 
+#undef  pud_addr_end
+#define pud_addr_end(addr, end)		(end)
+
 #endif
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -4,6 +4,7 @@
 #include <linux/compiler.h>
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 #ifndef HAVE_ARCH_BUG
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
@@ -11,13 +12,6 @@
 } while (0)
 #endif
 
-#ifndef HAVE_ARCH_PAGE_BUG
-#define PAGE_BUG(page) do { \
-	printk("page BUG for page at %p\n", page); \
-	BUG(); \
-} while (0)
-#endif
-
 #ifndef HAVE_ARCH_BUG_ON
 #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
 #endif
@@ -31,4 +25,18 @@
 } while (0)
 #endif
 
+#else /* !CONFIG_BUG */
+#ifndef HAVE_ARCH_BUG
+#define BUG()
+#endif
+
+#ifndef HAVE_ARCH_BUG_ON
+#define BUG_ON(condition) do { if (condition) ; } while(0)
+#endif
+
+#ifndef HAVE_ARCH_WARN_ON
+#define WARN_ON(condition) do { if (condition) ; } while(0)
+#endif
+#endif
+
 #endif
diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h
--- a/include/asm-generic/cputime.h
+++ b/include/asm-generic/cputime.h
@@ -10,6 +10,8 @@ typedef unsigned long cputime_t;
 #define cputime_max			((~0UL >> 1) - 1)
 #define cputime_add(__a, __b)		((__a) +  (__b))
 #define cputime_sub(__a, __b)		((__a) -  (__b))
+#define cputime_div(__a, __n)		((__a) /  (__n))
+#define cputime_halve(__a)		((__a) >> 1)
 #define cputime_eq(__a, __b)		((__a) == (__b))
 #define cputime_gt(__a, __b)		((__a) >  (__b))
 #define cputime_ge(__a, __b)		((__a) >= (__b))
diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
--- a/include/asm-generic/dma-mapping.h
+++ b/include/asm-generic/dma-mapping.h
@@ -35,7 +35,7 @@ dma_set_mask(struct device *dev, u64 dma
 
 static inline void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		   int flag)
+		   unsigned int __nocast flag)
 {
 	BUG_ON(dev->bus != &pci_bus_type);
 
@@ -168,7 +168,7 @@ dma_set_mask(struct device *dev, u64 dma
 
 static inline void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		   int flag)
+		   unsigned int __nocast flag)
 {
 	BUG();
 	return NULL;
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -102,4 +102,8 @@
 #define	EKEYREVOKED	128	/* Key has been revoked */
 #define	EKEYREJECTED	129	/* Key was rejected by service */
 
+/* for robust mutexes */
+#define	EOWNERDEAD	130	/* Owner died */
+#define	ENOTRECOVERABLE	131	/* State not recoverable */
+
 #endif
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -2,6 +2,7 @@
 #define __GENERIC_IO_H
 
 #include <linux/linkage.h>
+#include <asm/byteorder.h>
 
 /*
  * These are the "generic" interfaces for doing new-style
@@ -26,11 +27,15 @@
  */
 extern unsigned int fastcall ioread8(void __iomem *);
 extern unsigned int fastcall ioread16(void __iomem *);
+extern unsigned int fastcall ioread16be(void __iomem *);
 extern unsigned int fastcall ioread32(void __iomem *);
+extern unsigned int fastcall ioread32be(void __iomem *);
 
 extern void fastcall iowrite8(u8, void __iomem *);
 extern void fastcall iowrite16(u16, void __iomem *);
+extern void fastcall iowrite16be(u16, void __iomem *);
 extern void fastcall iowrite32(u32, void __iomem *);
+extern void fastcall iowrite32be(u32, void __iomem *);
 
 /*
  * "string" versions of the above. Note that they
diff --git a/include/asm-generic/ipc.h b/include/asm-generic/ipc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-generic/ipc.h
@@ -0,0 +1,31 @@
+#ifndef _ASM_GENERIC_IPC_H
+#define _ASM_GENERIC_IPC_H
+/*
+ * These are used to wrap system calls.
+ *
+ * See architecture code for ugly details..
+ */
+struct ipc_kludge {
+	struct msgbuf __user *msgp;
+	long msgtyp;
+};
+
+#define SEMOP		 1
+#define SEMGET		 2
+#define SEMCTL		 3
+#define SEMTIMEDOP	 4
+#define MSGSND		11
+#define MSGRCV		12
+#define MSGGET		13
+#define MSGCTL		14
+#define SHMAT		21
+#define SHMDT		22
+#define SHMGET		23
+#define SHMCTL		24
+
+/* Used by the DIPC package, try and avoid reusing it */
+#define DIPC            25
+
+#define IPCCALL(version,op)	((version)<<16 | (op))
+
+#endif	/* _ASM_GENERIC_IPC_H */
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -5,6 +5,8 @@
 
 #include <asm-generic/pgtable-nopud.h>
 
+#define __PAGETABLE_PMD_FOLDED
+
 /*
  * Having the pmd type consist of a pud gets the size right, and allows
  * us to conceptually access the pud entry that this pmd is folded into
@@ -55,6 +57,9 @@ static inline pmd_t * pmd_offset(pud_t *
 #define pmd_free(x)				do { } while (0)
 #define __pmd_free_tlb(tlb, x)			do { } while (0)
 
+#undef  pmd_addr_end
+#define pmd_addr_end(addr, end)			(end)
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _PGTABLE_NOPMD_H */
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -3,6 +3,8 @@
 
 #ifndef __ASSEMBLY__
 
+#define __PAGETABLE_PUD_FOLDED
+
 /*
  * Having the pud type consist of a pgd gets the size right, and allows
  * us to conceptually access the pgd entry that this pud is folded into
@@ -52,5 +54,8 @@ static inline pud_t * pud_offset(pgd_t *
 #define pud_free(x)				do { } while (0)
 #define __pud_free_tlb(tlb, x)			do { } while (0)
 
+#undef  pud_addr_end
+#define pud_addr_end(addr, end)			(end)
+
 #endif /* __ASSEMBLY__ */
 #endif /* _PGTABLE_NOPUD_H */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -16,7 +16,7 @@
 #ifndef __HAVE_ARCH_SET_PTE_ATOMIC
 #define ptep_establish(__vma, __address, __ptep, __entry)		\
 do {				  					\
-	set_pte(__ptep, __entry);					\
+	set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);	\
 	flush_tlb_page(__vma, __address);				\
 } while (0)
 #else /* __HAVE_ARCH_SET_PTE_ATOMIC */
@@ -37,26 +37,30 @@ do {				  					\
  */
 #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
 do {				  					  \
-	set_pte(__ptep, __entry);					  \
+	set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);	  \
 	flush_tlb_page(__vma, __address);				  \
 } while (0)
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int ptep_test_and_clear_young(pte_t *ptep)
-{
-	pte_t pte = *ptep;
-	if (!pte_young(pte))
-		return 0;
-	set_pte(ptep, pte_mkold(pte));
-	return 1;
-}
+#define ptep_test_and_clear_young(__vma, __address, __ptep)		\
+({									\
+	pte_t __pte = *(__ptep);					\
+	int r = 1;							\
+	if (!pte_young(__pte))						\
+		r = 0;							\
+	else								\
+		set_pte_at((__vma)->vm_mm, (__address),			\
+			   (__ptep), pte_mkold(__pte));			\
+	r;								\
+})
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
 #define ptep_clear_flush_young(__vma, __address, __ptep)		\
 ({									\
-	int __young = ptep_test_and_clear_young(__ptep);		\
+	int __young;							\
+	__young = ptep_test_and_clear_young(__vma, __address, __ptep);	\
 	if (__young)							\
 		flush_tlb_page(__vma, __address);			\
 	__young;							\
@@ -64,20 +68,24 @@ static inline int ptep_test_and_clear_yo
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
-{
-	pte_t pte = *ptep;
-	if (!pte_dirty(pte))
-		return 0;
-	set_pte(ptep, pte_mkclean(pte));
-	return 1;
-}
+#define ptep_test_and_clear_dirty(__vma, __address, __ptep)		\
+({									\
+	pte_t __pte = *__ptep;						\
+	int r = 1;							\
+	if (!pte_dirty(__pte))						\
+		r = 0;							\
+	else								\
+		set_pte_at((__vma)->vm_mm, (__address), (__ptep),	\
+			   pte_mkclean(__pte));				\
+	r;								\
+})
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
 #define ptep_clear_flush_dirty(__vma, __address, __ptep)		\
 ({									\
-	int __dirty = ptep_test_and_clear_dirty(__ptep);		\
+	int __dirty;							\
+	__dirty = ptep_test_and_clear_dirty(__vma, __address, __ptep);	\
 	if (__dirty)							\
 		flush_tlb_page(__vma, __address);			\
 	__dirty;							\
@@ -85,36 +93,29 @@ static inline int ptep_test_and_clear_di
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
-{
-	pte_t pte = *ptep;
-	pte_clear(ptep);
-	return pte;
-}
+#define ptep_get_and_clear(__mm, __address, __ptep)			\
+({									\
+	pte_t __pte = *(__ptep);					\
+	pte_clear((__mm), (__address), (__ptep));			\
+	__pte;								\
+})
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
 #define ptep_clear_flush(__vma, __address, __ptep)			\
 ({									\
-	pte_t __pte = ptep_get_and_clear(__ptep);			\
+	pte_t __pte;							\
+	__pte = ptep_get_and_clear((__vma)->vm_mm, __address, __ptep);	\
 	flush_tlb_page(__vma, __address);				\
 	__pte;								\
 })
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT
-static inline void ptep_set_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
 {
 	pte_t old_pte = *ptep;
-	set_pte(ptep, pte_wrprotect(old_pte));
-}
-#endif
-
-#ifndef __HAVE_ARCH_PTEP_MKDIRTY
-static inline void ptep_mkdirty(pte_t *ptep)
-{
-	pte_t old_pte = *ptep;
-	set_pte(ptep, pte_mkdirty(old_pte));
+	set_pte_at(mm, address, ptep, pte_wrprotect(old_pte));
 }
 #endif
 
@@ -134,4 +135,77 @@ static inline void ptep_mkdirty(pte_t *p
 #define pgd_offset_gate(mm, addr)	pgd_offset(mm, addr)
 #endif
 
+#ifndef __HAVE_ARCH_LAZY_MMU_PROT_UPDATE
+#define lazy_mmu_prot_update(pte)	do { } while (0)
+#endif
+
+/*
+ * When walking page tables, get the address of the next boundary,
+ * or the end address of the range if that comes earlier.  Although no
+ * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
+ */
+
+#define pgd_addr_end(addr, end)						\
+({	unsigned long __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK;	\
+	(__boundary - 1 < (end) - 1)? __boundary: (end);		\
+})
+
+#ifndef pud_addr_end
+#define pud_addr_end(addr, end)						\
+({	unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK;	\
+	(__boundary - 1 < (end) - 1)? __boundary: (end);		\
+})
+#endif
+
+#ifndef pmd_addr_end
+#define pmd_addr_end(addr, end)						\
+({	unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK;	\
+	(__boundary - 1 < (end) - 1)? __boundary: (end);		\
+})
+#endif
+
+#ifndef __ASSEMBLY__
+/*
+ * When walking page tables, we usually want to skip any p?d_none entries;
+ * and any p?d_bad entries - reporting the error before resetting to none.
+ * Do the tests inline, but report and clear the bad entry in mm/memory.c.
+ */
+void pgd_clear_bad(pgd_t *);
+void pud_clear_bad(pud_t *);
+void pmd_clear_bad(pmd_t *);
+
+static inline int pgd_none_or_clear_bad(pgd_t *pgd)
+{
+	if (pgd_none(*pgd))
+		return 1;
+	if (unlikely(pgd_bad(*pgd))) {
+		pgd_clear_bad(pgd);
+		return 1;
+	}
+	return 0;
+}
+
+static inline int pud_none_or_clear_bad(pud_t *pud)
+{
+	if (pud_none(*pud))
+		return 1;
+	if (unlikely(pud_bad(*pud))) {
+		pud_clear_bad(pud);
+		return 1;
+	}
+	return 0;
+}
+
+static inline int pmd_none_or_clear_bad(pmd_t *pmd)
+{
+	if (pmd_none(*pmd))
+		return 1;
+	if (unlikely(pmd_bad(*pmd))) {
+		pmd_clear_bad(pmd);
+		return 1;
+	}
+	return 0;
+}
+#endif /* !__ASSEMBLY__ */
+
 #endif /* _ASM_GENERIC_PGTABLE_H */
diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h
--- a/include/asm-generic/resource.h
+++ b/include/asm-generic/resource.h
@@ -2,57 +2,90 @@
 #define _ASM_GENERIC_RESOURCE_H
 
 /*
- * Resource limits
+ * Resource limit IDs
+ *
+ * ( Compatibility detail: there are architectures that have
+ *   a different rlimit ID order in the 5-9 range and want
+ *   to keep that order for binary compatibility. The reasons
+ *   are historic and all new rlimits are identical across all
+ *   arches. If an arch has such special order for some rlimits
+ *   then it defines them prior including asm-generic/resource.h. )
  */
 
-/* Allow arch to control resource order */
-#ifndef __ARCH_RLIMIT_ORDER
 #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 */
+
+#ifndef RLIMIT_RSS
+# define RLIMIT_RSS		5	/* max resident set size */
+#endif
+
+#ifndef RLIMIT_NPROC
+# define RLIMIT_NPROC		6	/* max number of processes */
+#endif
+
+#ifndef RLIMIT_NOFILE
+# define RLIMIT_NOFILE		7	/* max number of open files */
+#endif
+
+#ifndef RLIMIT_MEMLOCK
+# define RLIMIT_MEMLOCK		8	/* max locked-in-memory address space */
+#endif
+
+#ifndef RLIMIT_AS
+# define RLIMIT_AS		9	/* address space limit */
+#endif
+
 #define RLIMIT_LOCKS		10	/* maximum file locks held */
 #define RLIMIT_SIGPENDING	11	/* max number of pending signals */
 #define RLIMIT_MSGQUEUE		12	/* maximum bytes in POSIX mqueues */
+#define RLIMIT_NICE		13	/* max nice prio allowed to raise to
+					   0-39 for nice level 19 .. -20 */
+#define RLIMIT_RTPRIO		14	/* maximum realtime priority */
 
-#define RLIM_NLIMITS		13
-#endif
+#define RLIM_NLIMITS		15
 
 /*
  * SuS says limits have to be unsigned.
  * Which makes a ton more sense anyway.
+ *
+ * Some architectures override this (for compatibility reasons):
  */
 #ifndef RLIM_INFINITY
-#define RLIM_INFINITY	(~0UL)
+# define RLIM_INFINITY		(~0UL)
 #endif
 
+/*
+ * RLIMIT_STACK default maximum - some architectures override it:
+ */
 #ifndef _STK_LIM_MAX
-#define _STK_LIM_MAX	RLIM_INFINITY
+# define _STK_LIM_MAX		RLIM_INFINITY
 #endif
 
 #ifdef __KERNEL__
 
+/*
+ * boot-time rlimit defaults for the init task:
+ */
 #define INIT_RLIMITS							\
 {									\
-	[RLIMIT_CPU]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_FSIZE]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_DATA]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_STACK]		= {      _STK_LIM, _STK_LIM_MAX  },	\
-	[RLIMIT_CORE]		= {             0, RLIM_INFINITY },	\
-	[RLIMIT_RSS]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_NPROC]		= {             0,             0 },	\
-	[RLIMIT_NOFILE]		= {      INR_OPEN,     INR_OPEN  },	\
-	[RLIMIT_MEMLOCK]	= {   MLOCK_LIMIT,   MLOCK_LIMIT },	\
-	[RLIMIT_AS]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_LOCKS]		= { RLIM_INFINITY, RLIM_INFINITY },	\
-	[RLIMIT_SIGPENDING]	= { MAX_SIGPENDING, MAX_SIGPENDING },	\
-	[RLIMIT_MSGQUEUE]	= { MQ_BYTES_MAX, MQ_BYTES_MAX },	\
+	[RLIMIT_CPU]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_FSIZE]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_DATA]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_STACK]		= {       _STK_LIM,   _STK_LIM_MAX },	\
+	[RLIMIT_CORE]		= {              0,  RLIM_INFINITY },	\
+	[RLIMIT_RSS]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_NPROC]		= {              0,              0 },	\
+	[RLIMIT_NOFILE]		= {       INR_OPEN,       INR_OPEN },	\
+	[RLIMIT_MEMLOCK]	= {    MLOCK_LIMIT,    MLOCK_LIMIT },	\
+	[RLIMIT_AS]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_LOCKS]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+	[RLIMIT_SIGPENDING]	= { 		0,	       0 },	\
+	[RLIMIT_MSGQUEUE]	= {   MQ_BYTES_MAX,   MQ_BYTES_MAX },	\
+	[RLIMIT_NICE]		= { 0, 0 },				\
+	[RLIMIT_RTPRIO]		= { 0, 0 },				\
 }
 
 #endif	/* __KERNEL__ */
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -8,6 +8,8 @@ extern char _data[], _sdata[], _edata[];
 extern char __bss_start[], __bss_stop[];
 extern char __init_begin[], __init_end[];
 extern char _sinittext[], _einittext[];
+extern char _sextratext[] __attribute__((weak));
+extern char _eextratext[] __attribute__((weak));
 extern char _end[];
 
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
--- a/include/asm-generic/siginfo.h
+++ b/include/asm-generic/siginfo.h
@@ -3,7 +3,6 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <linux/resource.h>
 
 typedef union sigval {
 	int sival_int;
@@ -237,11 +236,18 @@ typedef struct siginfo {
 #define SIGEV_THREAD	2	/* deliver via thread creation */
 #define SIGEV_THREAD_ID 4	/* deliver to thread */
 
-#define SIGEV_MAX_SIZE	64
-#ifndef SIGEV_PAD_SIZE
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+/*
+ * This works because the alignment is ok on all current architectures
+ * but we leave open this being overridden in the future
+ */
+#ifndef __ARCH_SIGEV_PREAMBLE_SIZE
+#define __ARCH_SIGEV_PREAMBLE_SIZE	(sizeof(int) * 2 + sizeof(sigval_t))
 #endif
 
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \
+		/ sizeof(int))
+
 typedef struct sigevent {
 	sigval_t sigev_value;
 	int sigev_signo;
diff --git a/include/asm-generic/signal.h b/include/asm-generic/signal.h
new file mode 100644
--- /dev/null
+++ b/include/asm-generic/signal.h
@@ -0,0 +1,21 @@
+#ifndef SIG_BLOCK
+#define SIG_BLOCK          0	/* for blocking signals */
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK        1	/* for unblocking signals */
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK        2	/* for setting the signal mask */
+#endif
+
+#ifndef __ASSEMBLY__
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
+
+typedef void __restorefn_t(void);
+typedef __restorefn_t __user *__sigrestore_t;
+
+#define SIG_DFL	((__force __sighandler_t)0)	/* default signal handling */
+#define SIG_IGN	((__force __sighandler_t)1)	/* ignore signal */
+#define SIG_ERR	((__force __sighandler_t)-1)	/* error return from signal */
+#endif
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -88,11 +88,11 @@ tlb_finish_mmu(struct mmu_gather *tlb, u
 {
 	int freed = tlb->freed;
 	struct mm_struct *mm = tlb->mm;
-	int rss = mm->rss;
+	int rss = get_mm_counter(mm, rss);
 
 	if (rss < freed)
 		freed = rss;
-	mm->rss = rss - freed;
+	add_mm_counter(mm, rss, -freed);
 	tlb_flush_mmu(tlb, start, end);
 
 	/* keep the page table cache within bounds */
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
--- a/include/asm-generic/unaligned.h
+++ b/include/asm-generic/unaligned.h
@@ -4,17 +4,119 @@
 /*
  * For the benefit of those who are trying to port Linux to another
  * architecture, here are some C-language equivalents. 
+ *
+ * This is based almost entirely upon Richard Henderson's
+ * asm-alpha/unaligned.h implementation.  Some comments were
+ * taken from David Mosberger's asm-ia64/unaligned.h header.
  */
 
-#include <asm/string.h>
-
+#include <linux/types.h>
 
+/* 
+ * The main single-value unaligned transfer routines.
+ */
 #define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+#define put_unaligned(x,ptr) \
+	__put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
+
+/*
+ * This function doesn't actually exist.  The idea is that when
+ * someone uses the macros below with an unsupported size (datatype),
+ * the linker will alert us to the problem via an unresolved reference
+ * error.
+ */
+extern void bad_unaligned_access_length(void) __attribute__((noreturn));
+
+struct __una_u64 { __u64 x __attribute__((packed)); };
+struct __una_u32 { __u32 x __attribute__((packed)); };
+struct __una_u16 { __u16 x __attribute__((packed)); };
+
+/*
+ * Elemental unaligned loads 
+ */
+
+static inline unsigned long __uldq(const __u64 *addr)
+{
+	const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
+	return ptr->x;
+}
+
+static inline unsigned long __uldl(const __u32 *addr)
+{
+	const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
+	return ptr->x;
+}
+
+static inline unsigned long __uldw(const __u16 *addr)
+{
+	const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
+	return ptr->x;
+}
+
+/*
+ * Elemental unaligned stores 
+ */
+
+static inline void __ustq(__u64 val, __u64 *addr)
+{
+	struct __una_u64 *ptr = (struct __una_u64 *) addr;
+	ptr->x = val;
+}
+
+static inline void __ustl(__u32 val, __u32 *addr)
+{
+	struct __una_u32 *ptr = (struct __una_u32 *) addr;
+	ptr->x = val;
+}
+
+static inline void __ustw(__u16 val, __u16 *addr)
+{
+	struct __una_u16 *ptr = (struct __una_u16 *) addr;
+	ptr->x = val;
+}
+
+#define __get_unaligned(ptr, size) ({		\
+	const void *__gu_p = ptr;		\
+	unsigned long val;			\
+	switch (size) {				\
+	case 1:					\
+		val = *(const __u8 *)__gu_p;	\
+		break;				\
+	case 2:					\
+		val = __uldw(__gu_p);		\
+		break;				\
+	case 4:					\
+		val = __uldl(__gu_p);		\
+		break;				\
+	case 8:					\
+		val = __uldq(__gu_p);		\
+		break;				\
+	default:				\
+		bad_unaligned_access_length();	\
+	};					\
+	val;					\
+})
 
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memcpy((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#define __put_unaligned(val, ptr, size)		\
+do {						\
+	void *__gu_p = ptr;			\
+	switch (size) {				\
+	case 1:					\
+		*(__u8 *)__gu_p = val;		\
+	        break;				\
+	case 2:					\
+		__ustw(val, __gu_p);		\
+		break;				\
+	case 4:					\
+		__ustl(val, __gu_p);		\
+		break;				\
+	case 8:					\
+		__ustq(val, __gu_p);		\
+		break;				\
+	default:				\
+	    	bad_unaligned_access_length();	\
+	};					\
+} while(0)
 
 #endif /* _ASM_GENERIC_UNALIGNED_H */
diff --git a/include/asm-h8300/cacheflush.h b/include/asm-h8300/cacheflush.h
--- a/include/asm-h8300/cacheflush.h
+++ b/include/asm-h8300/cacheflush.h
@@ -13,7 +13,7 @@
 #define flush_cache_all()
 #define	flush_cache_mm(mm)
 #define	flush_cache_range(vma,a,b)
-#define	flush_cache_page(vma,p)
+#define	flush_cache_page(vma,p,pfn)
 #define	flush_dcache_page(page)
 #define	flush_dcache_mmap_lock(mapping)
 #define	flush_dcache_mmap_unlock(mapping)
diff --git a/include/asm-h8300/io.h b/include/asm-h8300/io.h
--- a/include/asm-h8300/io.h
+++ b/include/asm-h8300/io.h
@@ -317,6 +317,17 @@ static __inline__ void ctrl_outl(unsigne
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* _H8300_IO_H */
diff --git a/include/asm-h8300/ipc.h b/include/asm-h8300/ipc.h
--- a/include/asm-h8300/ipc.h
+++ b/include/asm-h8300/ipc.h
@@ -1,31 +1 @@
-#ifndef __H8300_IPC_H__
-#define __H8300_IPC_H__
-
-/* 
- * These are used to wrap system calls on H8/300.
- *
- * See arch/h8300/kernel/sys_h8300.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#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
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC		25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-h8300/kmap_types.h b/include/asm-h8300/kmap_types.h
--- a/include/asm-h8300/kmap_types.h
+++ b/include/asm-h8300/kmap_types.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_KMAP_TYPES_H
-#define _ASM_KMAP_TYPES_H
+#ifndef _ASM_H8300_KMAP_TYPES_H
+#define _ASM_H8300_KMAP_TYPES_H
 
 enum km_type {
 	KM_BOUNCE_READ,
@@ -13,6 +13,8 @@ enum km_type {
 	KM_PTE1,
 	KM_IRQ0,
 	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
 	KM_TYPE_NR
 };
 
diff --git a/include/asm-h8300/mman.h b/include/asm-h8300/mman.h
--- a/include/asm-h8300/mman.h
+++ b/include/asm-h8300/mman.h
@@ -4,6 +4,7 @@
 #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_SEM	0x8		/* page may be used for atomic ops */
 #define PROT_NONE	0x0		/* page can not be accessed */
 #define PROT_GROWSDOWN	0x01000000	/* mprotect flag: extend change to start of growsdown vma */
 #define PROT_GROWSUP	0x02000000	/* mprotect flag: extend change to end of growsup vma */
@@ -19,6 +20,8 @@
 #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 MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define MAP_NONBLOCK	0x10000		/* do not block on IO */
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h
--- a/include/asm-h8300/page.h
+++ b/include/asm-h8300/page.h
@@ -79,7 +79,7 @@ extern unsigned long memory_end;
 
 #ifndef __ASSEMBLY__
 
-#define __pa(vaddr)		virt_to_phys((void *)vaddr)
+#define __pa(vaddr)		virt_to_phys(vaddr)
 #define __va(paddr)		phys_to_virt((unsigned long)paddr)
 
 #define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
@@ -89,7 +89,7 @@ extern unsigned long memory_end;
 #define virt_to_page(addr)	(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
 #define virt_to_page(addr)	(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
 #define page_to_virt(page)	((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define pfn_valid(page)	        (page < max_mapnr)
 
 #define pfn_to_page(pfn)	virt_to_page(pfn_to_virt(pfn))
 #define page_to_pfn(page)	virt_to_pfn(page_to_virt(page))
diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h
--- a/include/asm-h8300/pgtable.h
+++ b/include/asm-h8300/pgtable.h
@@ -55,6 +55,13 @@ extern int is_in_rom(unsigned long);
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
diff --git a/include/asm-h8300/signal.h b/include/asm-h8300/signal.h
--- a/include/asm-h8300/signal.h
+++ b/include/asm-h8300/signal.h
@@ -107,29 +107,7 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-h8300/system.h b/include/asm-h8300/system.h
--- a/include/asm-h8300/system.h
+++ b/include/asm-h8300/system.h
@@ -144,4 +144,6 @@ static inline unsigned long __xchg(unsig
         asm("jmp @@0");			\
 })
 
+#define arch_align_stack(x) (x)
+
 #endif /* _H8300_SYSTEM_H */
diff --git a/include/asm-h8300/uaccess.h b/include/asm-h8300/uaccess.h
--- a/include/asm-h8300/uaccess.h
+++ b/include/asm-h8300/uaccess.h
@@ -24,7 +24,8 @@ static inline int __access_ok(unsigned l
 	return(RANGE_CHECK_OK(addr, size, 0L, (unsigned long)&_ramend));
 }
 
-static inline int verify_area(int type, const void *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
 {
 	return access_ok(type,addr,size)?0:-EFAULT;
 }
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
--- a/include/asm-h8300/unistd.h
+++ b/include/asm-h8300/unistd.h
@@ -310,163 +310,155 @@ do { \
 	return (type) (res); \
 } while (0)
 
-#define _syscall0(type, name)							\
-type name(void)									\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%1,er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name)					\
-			: "cc");						\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {			\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-
-#define _syscall1(type, name, atype, a)						\
-type name(atype a)								\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%2, er1\n\t"					\
-  			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a)						\
-			: "cc", "er1");					\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {			\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-
-#define _syscall2(type, name, atype, a, btype, b)				\
-type name(atype a, btype b)							\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%3, er2\n\t"					\
-  			"mov.l	%2, er1\n\t"					\
-			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a),					\
-			  "g" ((long)b)						\
-			: "cc", "er1", "er2"); 				\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {			\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-
-#define _syscall3(type, name, atype, a, btype, b, ctype, c)			\
-type name(atype a, btype b, ctype c)						\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%4, er3\n\t"					\
-			"mov.l	%3, er2\n\t"					\
-  			"mov.l	%2, er1\n\t"					\
-			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a),					\
-			  "g" ((long)b),					\
-			  "g" ((long)c)						\
-			: "cc", "er1", "er2", "er3");  			\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {			\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-
-#define _syscall4(type, name, atype, a, btype, b, ctype, c, dtype, d)		\
-type name(atype a, btype b, ctype c, dtype d)					\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%5, er4\n\t"					\
-			"mov.l	%4, er3\n\t"					\
-			"mov.l	%3, er2\n\t"					\
-  			"mov.l	%2, er1\n\t"					\
-			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a),					\
-			  "g" ((long)b),					\
-			  "g" ((long)c),					\
-			  "g" ((long)d)						\
-			: "cc", "er1", "er2", "er3", "er4");			\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {			\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-
-#define _syscall5(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e)	\
-type name(atype a, btype b, ctype c, dtype d, etype e)				\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	%6, er5\n\t"					\
-			"mov.l	%5, er4\n\t"					\
-			"mov.l	%4, er3\n\t"					\
-			"mov.l	%3, er2\n\t"					\
-  			"mov.l	%2, er1\n\t"					\
-			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a),					\
-			  "g" ((long)b),					\
-			  "g" ((long)c),					\
-			  "g" ((long)d),					\
-			  "m" ((long)e)						\
-			: "cc", "er1", "er2", "er3", "er4", "er5");		\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {		       	\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
-}
-		
-#define _syscall6(type, name, atype, a, btype, b, ctype, c, dtype, d,           \
-                              etype, e, ftype, f)	                        \
-type name(atype a, btype b, ctype c, dtype d, etype e, ftype f)			\
-{										\
-  register long __res __asm__("er0");						\
-  __asm__ __volatile__ ("mov.l	er6,@-sp\n\t"					\
-                        "mov.l	%7, er6\n\t"					\
-                        "mov.l	%6, er5\n\t"					\
-			"mov.l	%5, er4\n\t"					\
-			"mov.l	%4, er3\n\t"					\
-			"mov.l	%3, er2\n\t"					\
-  			"mov.l	%2, er1\n\t"					\
-			"mov.l	%1, er0\n\t"					\
-  			"trapa	#0\n\t"						\
-  			"mov.l	@sp+,er6"					\
-			: "=r" (__res)						\
-			: "ir" (__NR_##name),					\
-			  "g" ((long)a),					\
-			  "g" ((long)b),					\
-			  "g" ((long)c),					\
-			  "g" ((long)d),					\
-			  "m" ((long)e),					\
-			  "m" ((long)e)						\
-			: "cc", "er1", "er2", "er3", "er4", "er5");		\
-  if ((unsigned long)(__res) >= (unsigned long)(-125)) {		       	\
-    errno = -__res;								\
-    __res = -1;									\
-  }										\
-  return (type)__res;								\
+#define _syscall0(type, name)				\
+type name(void)						\
+{							\
+  register long __res __asm__("er0");			\
+  __asm__ __volatile__ ("mov.l %1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name)		\
+			: "cc", "memory");		\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall1(type, name, atype, a)			\
+type name(atype a)					\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  _a = (long)a;						\
+  __asm__ __volatile__ ("mov.l %1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a)			\
+			: "cc", "memory");	 	\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall2(type, name, atype, a, btype, b)	\
+type name(atype a, btype b)				\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  register long _b __asm__("er2");			\
+  _a = (long)a;						\
+  _b = (long)b;						\
+  __asm__ __volatile__ ("mov.l %1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a),			\
+			  "g" (_b)			\
+			: "cc", "memory");	 	\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall3(type, name, atype, a, btype, b, ctype, c)	\
+type name(atype a, btype b, ctype c)			\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  register long _b __asm__("er2");			\
+  register long _c __asm__("er3");			\
+  _a = (long)a;						\
+  _b = (long)b;						\
+  _c = (long)c;						\
+  __asm__ __volatile__ ("mov.l %1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a),			\
+			  "g" (_b),			\
+			  "g" (_c)			\
+			: "cc", "memory");		\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall4(type, name, atype, a, btype, b,	\
+                  ctype, c, dtype, d)			\
+type name(atype a, btype b, ctype c, dtype d)		\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  register long _b __asm__("er2");			\
+  register long _c __asm__("er3");			\
+  register long _d __asm__("er4");			\
+  _a = (long)a;						\
+  _b = (long)b;						\
+  _c = (long)c;						\
+  _d = (long)d;						\
+  __asm__ __volatile__ ("mov.l	%1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a),			\
+			  "g" (_b),			\
+			  "g" (_c),			\
+			  "g" (_d)			\
+			: "cc", "memory");		\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall5(type, name, atype, a, btype, b,	\
+                  ctype, c, dtype, d, etype, e)		\
+type name(atype a, btype b, ctype c, dtype d, etype e)	\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  register long _b __asm__("er2");			\
+  register long _c __asm__("er3");			\
+  register long _d __asm__("er4");			\
+  register long _e __asm__("er5");			\
+  _a = (long)a;                                       	\
+  _b = (long)b;                                       	\
+  _c = (long)c;                                       	\
+  _d = (long)d;                                       	\
+  _e = (long)e;                                       	\
+  __asm__ __volatile__ ("mov.l	%1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a),			\
+			  "g" (_b),			\
+			  "g" (_c),			\
+			  "g" (_d),			\
+			  "g" (_e)			\
+			: "cc", "memory");		\
+  __syscall_return(type, __res);			\
+}
+
+#define _syscall6(type, name, atype, a, btype, b,	\
+                  ctype, c, dtype, d, etype, e, ftype, f)	\
+type name(atype a, btype b, ctype c, dtype d, etype e, ftype f)	\
+{							\
+  register long __res __asm__("er0");			\
+  register long _a __asm__("er1");			\
+  register long _b __asm__("er2");			\
+  register long _c __asm__("er3");			\
+  register long _d __asm__("er4");			\
+  register long _e __asm__("er5");			\
+  register long _f __asm__("er6");			\
+  _a = (long)a;                                       	\
+  _b = (long)b;                                       	\
+  _c = (long)c;                                       	\
+  _d = (long)d;                                       	\
+  _e = (long)e;                                       	\
+  _f = (long)f;                                       	\
+  __asm__ __volatile__ ("mov.l	%1,er0\n\t"		\
+                        "trapa	#0\n\t"			\
+			: "=r" (__res)			\
+			: "g" (__NR_##name),		\
+			  "g" (_a),			\
+			  "g" (_b),			\
+			  "g" (_c),			\
+			  "g" (_d),			\
+			  "g" (_e)			\
+			  "g" (_f)			\
+			: "cc", "memory");		\
+  __syscall_return(type, __res);			\
 }
-		
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -174,7 +174,6 @@ static inline int acpi_irq_balance_set(c
 
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
-extern int acpi_save_state_disk(void);
 extern void acpi_restore_state_mem(void);
 
 extern unsigned long acpi_wakeup_address;
diff --git a/include/asm-i386/agp.h b/include/asm-i386/agp.h
--- a/include/asm-i386/agp.h
+++ b/include/asm-i386/agp.h
@@ -21,4 +21,14 @@ int unmap_page_from_agp(struct page *pag
    worth it. Would need a page for it. */
 #define flush_agp_cache() asm volatile("wbinvd":::"memory")
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -109,7 +109,6 @@ extern int APIC_init_uniprocessor (void)
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 
-extern int check_nmi_watchdog (void);
 extern void enable_NMI_through_LVT0 (void * dummy);
 
 extern unsigned int nmi_watchdog;
diff --git a/include/asm-i386/bug.h b/include/asm-i386/bug.h
--- a/include/asm-i386/bug.h
+++ b/include/asm-i386/bug.h
@@ -9,6 +9,8 @@
  * undefined" opcode for parsing in the trap handler.
  */
 
+#ifdef CONFIG_BUG
+#define HAVE_ARCH_BUG
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #define BUG()				\
  __asm__ __volatile__(	"ud2\n"		\
@@ -18,8 +20,7 @@
 #else
 #define BUG() __asm__ __volatile__("ud2\n")
 #endif
+#endif
 
-#define HAVE_ARCH_BUG
 #include <asm-generic/bug.h>
-
 #endif
diff --git a/include/asm-i386/cacheflush.h b/include/asm-i386/cacheflush.h
--- a/include/asm-i386/cacheflush.h
+++ b/include/asm-i386/cacheflush.h
@@ -8,7 +8,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h
--- a/include/asm-i386/checksum.h
+++ b/include/asm-i386/checksum.h
@@ -33,7 +33,7 @@ asmlinkage unsigned int csum_partial_cop
  *	passed in an incorrect kernel address to one of these functions.
  *
  *	If you use these functions directly please don't forget the
- *	verify_area().
+ *	access_ok().
  */
 static __inline__
 unsigned int csum_partial_copy_nocheck (const unsigned char *src, unsigned char *dst,
diff --git a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h
--- a/include/asm-i386/cpu.h
+++ b/include/asm-i386/cpu.h
@@ -11,7 +11,6 @@
 struct i386_cpu {
 	struct cpu cpu;
 };
-extern struct i386_cpu cpu_devices[NR_CPUS];
 extern int arch_register_cpu(int num);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void arch_unregister_cpu(int);
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -87,8 +87,8 @@
 #define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* on-CPU crypto enabled */
 
 /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
-#define X86_FEATURE_LAHF_LM	(5*32+ 0) /* LAHF/SAHF in long mode */
-#define X86_FEATURE_CMP_LEGACY	(5*32+ 1) /* If yes HyperThreading not valid */
+#define X86_FEATURE_LAHF_LM	(6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY	(6*32+ 1) /* If yes HyperThreading not valid */
 
 #define cpu_has(c, bit)		test_bit(bit, (c)->x86_capability)
 #define boot_cpu_has(bit)	test_bit(bit, boot_cpu_data.x86_capability)
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
--- a/include/asm-i386/desc.h
+++ b/include/asm-i386/desc.h
@@ -4,6 +4,8 @@
 #include <asm/ldt.h>
 #include <asm/segment.h>
 
+#define CPU_16BIT_STACK_SIZE 1024
+
 #ifndef __ASSEMBLY__
 
 #include <linux/preempt.h>
@@ -15,6 +17,8 @@
 extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
 DECLARE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]);
 
+DECLARE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
+
 struct Xgt_desc_struct {
 	unsigned short size;
 	unsigned long address __attribute__((packed));
diff --git a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h
--- a/include/asm-i386/dma-mapping.h
+++ b/include/asm-i386/dma-mapping.h
@@ -11,7 +11,7 @@
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, int flag);
+			   dma_addr_t *dma_handle, unsigned int __nocast flag);
 
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle);
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -13,7 +13,7 @@
 #define __E820_HEADER
 
 #define E820MAP	0x2d0		/* our map */
-#define E820MAX	32		/* number of entries in E820MAP */
+#define E820MAX	128		/* number of entries in E820MAP */
 #define E820NR	0x1e8		/* # entries in E820MAP */
 
 #define E820_RAM	1
diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
--- a/include/asm-i386/floppy.h
+++ b/include/asm-i386/floppy.h
@@ -257,7 +257,7 @@ static int hard_dma_setup(char *addr, un
 	return 0;
 }
 
-struct fd_routine_l {
+static 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);
diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h
+++ b/include/asm-i386/hardirq.h
@@ -12,8 +12,13 @@ typedef struct {
 	unsigned int apic_timer_irqs;	/* arch dependent */
 } ____cacheline_aligned irq_cpustat_t;
 
-#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
+extern irq_cpustat_t irq_stat[];
+
+#define __ARCH_IRQ_STAT
+#define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member)
 
 void ack_bad_irq(unsigned int irq);
+#include <linux/irq_cpustat.h>
 
 #endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -33,8 +33,6 @@ extern pte_t *kmap_pte;
 extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
 
-extern void kmap_init(void);
-
 /*
  * Right now we initialize only a single pte table. It can be extended
  * easily, subsequent pte tables have to be allocated in one physical
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -90,9 +90,9 @@
  */
 #define HPET_MIN_PERIOD (100000UL)
 
-extern unsigned long hpet_period;	/* fsecs / HPET clock */
 extern unsigned long hpet_tick;  	/* hpet clks count per tick */
 extern unsigned long hpet_address;	/* hpet memory map physical address */
+extern int hpet_use_timer;
 
 extern int hpet_rtc_timer_init(void);
 extern int hpet_enable(void);
@@ -100,7 +100,6 @@ extern int hpet_reenable(void);
 extern int is_hpet_enabled(void);
 extern int is_hpet_capable(void);
 extern int hpet_readl(unsigned long a);
-extern void hpet_writel(unsigned long d, unsigned long a);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h
--- a/include/asm-i386/i387.h
+++ b/include/asm-i386/i387.h
@@ -17,7 +17,6 @@
 #include <asm/sigcontext.h>
 #include <asm/user.h>
 
-extern unsigned long mxcsr_feature_mask;
 extern void mxcsr_feature_mask_init(void);
 extern void init_fpu(struct task_struct *);
 /*
@@ -86,13 +85,8 @@ static inline void save_init_fpu( struct
  */
 extern unsigned short get_fpu_cwd( struct task_struct *tsk );
 extern unsigned short get_fpu_swd( struct task_struct *tsk );
-extern unsigned short get_fpu_twd( struct task_struct *tsk );
 extern unsigned short get_fpu_mxcsr( struct task_struct *tsk );
 
-extern void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd );
-extern void set_fpu_swd( struct task_struct *tsk, unsigned short swd );
-extern void set_fpu_twd( struct task_struct *tsk, unsigned short twd );
-
 /*
  * Signal frame handlers...
  */
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -49,6 +49,17 @@
 
 #include <linux/vmalloc.h>
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 /**
  *	virt_to_phys	-	map virtual addresses to physical
  *	@address: address to remap
diff --git a/include/asm-i386/ipc.h b/include/asm-i386/ipc.h
--- a/include/asm-i386/ipc.h
+++ b/include/asm-i386/ipc.h
@@ -1,32 +1 @@
-#ifndef __i386_IPC_H__
-#define __i386_IPC_H__
-
-/* 
- * These are used to wrap system calls on x86.
- *
- * See arch/i386/kernel/sys_i386.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-i386/linkage.h b/include/asm-i386/linkage.h
--- a/include/asm-i386/linkage.h
+++ b/include/asm-i386/linkage.h
@@ -5,9 +5,7 @@
 #define FASTCALL(x)	x __attribute__((regparm(3)))
 #define fastcall	__attribute__((regparm(3)))
 
-#ifdef CONFIG_REGPARM
-# define prevent_tail_call(ret) __asm__ ("" : "=r" (ret) : "0" (ret))
-#endif
+#define prevent_tail_call(ret) __asm__ ("" : "=r" (ret) : "0" (ret))
 
 #ifdef CONFIG_X86_ALIGNMENT_16
 #define __ALIGN .align 16,0x90
diff --git a/include/asm-i386/mach-default/mach_traps.h b/include/asm-i386/mach-default/mach_traps.h
--- a/include/asm-i386/mach-default/mach_traps.h
+++ b/include/asm-i386/mach-default/mach_traps.h
@@ -7,6 +7,8 @@
 #ifndef _MACH_TRAPS_H
 #define _MACH_TRAPS_H
 
+#include <asm/mc146818rtc.h>
+
 static inline void clear_mem_error(unsigned char reason)
 {
 	reason = (reason & 0xf) | 4;
@@ -20,10 +22,20 @@ static inline unsigned char get_nmi_reas
 
 static inline void reassert_nmi(void)
 {
+	int old_reg = -1;
+
+	if (do_i_have_lock_cmos())
+		old_reg = current_lock_cmos_reg();
+	else
+		lock_cmos(0); /* register doesn't matter here */
 	outb(0x8f, 0x70);
 	inb(0x71);		/* dummy */
 	outb(0x0f, 0x70);
 	inb(0x71);		/* dummy */
+	if (old_reg >= 0)
+		outb(old_reg, 0x70);
+	else
+		unlock_cmos();
 }
 
 #endif /* !_MACH_TRAPS_H */
diff --git a/include/asm-i386/mach-numaq/mach_ipi.h b/include/asm-i386/mach-numaq/mach_ipi.h
--- a/include/asm-i386/mach-numaq/mach_ipi.h
+++ b/include/asm-i386/mach-numaq/mach_ipi.h
@@ -1,7 +1,7 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-inline void send_IPI_mask_sequence(cpumask_t, int vector);
+void send_IPI_mask_sequence(cpumask_t, int vector);
 
 static inline void send_IPI_mask(cpumask_t mask, int vector)
 {
diff --git a/include/asm-i386/mc146818rtc.h b/include/asm-i386/mc146818rtc.h
--- a/include/asm-i386/mc146818rtc.h
+++ b/include/asm-i386/mc146818rtc.h
@@ -5,24 +5,89 @@
 #define _ASM_MC146818RTC_H
 
 #include <asm/io.h>
+#include <asm/system.h>
+#include <linux/mc146818rtc.h>
 
 #ifndef RTC_PORT
 #define RTC_PORT(x)	(0x70 + (x))
 #define RTC_ALWAYS_BCD	1	/* RTC operates in binary mode */
 #endif
 
+#ifdef __HAVE_ARCH_CMPXCHG
+/*
+ * This lock provides nmi access to the CMOS/RTC registers.  It has some
+ * special properties.  It is owned by a CPU and stores the index register
+ * currently being accessed (if owned).  The idea here is that it works
+ * like a normal lock (normally).  However, in an NMI, the NMI code will
+ * first check to see if its CPU owns the lock, meaning that the NMI
+ * interrupted during the read/write of the device.  If it does, it goes ahead
+ * and performs the access and then restores the index register.  If it does
+ * not, it locks normally.
+ *
+ * Note that since we are working with NMIs, we need this lock even in
+ * a non-SMP machine just to mark that the lock is owned.
+ *
+ * This only works with compare-and-swap.  There is no other way to
+ * atomically claim the lock and set the owner.
+ */
+#include <linux/smp.h>
+extern volatile unsigned long cmos_lock;
+
+/*
+ * All of these below must be called with interrupts off, preempt
+ * disabled, etc.
+ */
+
+static inline void lock_cmos(unsigned char reg)
+{
+	unsigned long new;
+	new = ((smp_processor_id()+1) << 8) | reg;
+	for (;;) {
+		if (cmos_lock)
+			continue;
+		if (__cmpxchg(&cmos_lock, 0, new, sizeof(cmos_lock)) == 0)
+			return;
+	}
+}
+
+static inline void unlock_cmos(void)
+{
+	cmos_lock = 0;
+}
+static inline int do_i_have_lock_cmos(void)
+{
+	return (cmos_lock >> 8) == (smp_processor_id()+1);
+}
+static inline unsigned char current_lock_cmos_reg(void)
+{
+	return cmos_lock & 0xff;
+}
+#define lock_cmos_prefix(reg) \
+	do {					\
+		unsigned long cmos_flags;	\
+		local_irq_save(cmos_flags);	\
+		lock_cmos(reg)
+#define lock_cmos_suffix(reg) \
+		unlock_cmos();			\
+		local_irq_restore(cmos_flags);	\
+	} while (0)
+#else
+#define lock_cmos_prefix(reg) do {} while (0)
+#define lock_cmos_suffix(reg) do {} while (0)
+#define lock_cmos(reg)
+#define unlock_cmos()
+#define do_i_have_lock_cmos() 0
+#define current_lock_cmos_reg() 0
+#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)); \
-})
+#define CMOS_READ(addr) rtc_cmos_read(addr)
+#define CMOS_WRITE(val, addr) rtc_cmos_write(val, addr)
+unsigned char rtc_cmos_read(unsigned char addr);
+void rtc_cmos_write(unsigned char val, unsigned char addr);
 
 #define RTC_IRQ 8
 
diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h
--- a/include/asm-i386/module.h
+++ b/include/asm-i386/module.h
@@ -52,6 +52,8 @@ struct mod_arch_specific
 #define MODULE_PROC_FAMILY "CYRIXIII "
 #elif defined CONFIG_MVIAC3_2
 #define MODULE_PROC_FAMILY "VIAC3-2 "
+#elif CONFIG_MGEODEGX1
+#define MODULE_PROC_FAMILY "GEODEGX1 "
 #else
 #error unknown processor family
 #endif
diff --git a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h
+++ b/include/asm-i386/mpspec.h
@@ -22,7 +22,6 @@ 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;
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -32,6 +32,21 @@ static inline void wrmsrl (unsigned long
 	wrmsr (msr, lo, hi);
 }
 
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ 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 4\n\t"							\
+		     "   .long 	2b,3b\n\t"						\
+		     ".previous"							\
+		     : "=a" (ret__)							\
+		     : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
+	ret__; })
+
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
 
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -2,7 +2,6 @@
 #define _I386_PGALLOC_H
 
 #include <linux/config.h>
-#include <asm/processor.h>
 #include <asm/fixmap.h>
 #include <linux/threads.h>
 #include <linux/mm.h>		/* for struct page */
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -14,10 +14,11 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 #define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
 
-#define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte_low, 0))
+#define ptep_get_and_clear(mm,addr,xp)	__pte(xchg(&(xp)->pte_low, 0))
 #define pte_same(a, b)		((a).pte_low == (b).pte_low)
 #define pte_page(x)		pfn_to_page(pte_pfn(x))
 #define pte_none(x)		(!(x).pte_low)
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -56,6 +56,8 @@ static inline void set_pte(pte_t *ptep, 
 	smp_wmb();
 	ptep->pte_low = pte.pte_low;
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
 #define __HAVE_ARCH_SET_PTE_ATOMIC
 #define set_pte_atomic(pteptr,pteval) \
 		set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
@@ -88,7 +90,7 @@ static inline void pud_clear (pud_t * pu
 #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
 			pmd_index(address))
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t res;
 
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -60,7 +60,7 @@ void paging_init(void);
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
 #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
@@ -193,15 +193,15 @@ extern unsigned long long __PAGE_KERNEL,
 /*
  * Define this if things work differently on an i386 and an i486:
  * it will (on an i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
+ * done without a 'access_ok(VERIFY_WRITE,..)'
  */
-#undef TEST_VERIFY_AREA
+#undef TEST_ACCESS_OK
 
 /* The boot page tables (all created as a single array) */
 extern unsigned long pg0[];
 
 #define pte_present(x)	((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
+#define pte_clear(mm,addr,xp)	do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
@@ -243,22 +243,24 @@ static inline pte_t pte_mkwrite(pte_t pt
 # include <asm/pgtable-2level.h>
 #endif
 
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	if (!pte_dirty(*ptep))
 		return 0;
 	return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
 }
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	if (!pte_young(*ptep))
 		return 0;
 	return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, &ptep->pte_low); }
-static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+	clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
+}
 
 /*
  * Macro to mark a page protection value as "uncacheable".  On processors which do not support
@@ -403,11 +405,17 @@ extern void noexec_setup(const char *str
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -98,12 +98,12 @@ extern struct cpuinfo_x86 cpu_data[];
 #endif
 
 extern	int phys_proc_id[NR_CPUS];
+extern	int cpu_core_id[NR_CPUS];
 extern char ignore_fpu_irq;
 
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
-extern void dodgy_tsc(void);
 
 #ifdef CONFIG_X86_HT
 extern void detect_ht(struct cpuinfo_x86 *c);
@@ -137,7 +137,7 @@ static inline void detect_ht(struct cpui
  * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
  * resulting in stale register contents being returned.
  */
-static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
 {
 	__asm__("cpuid"
 		: "=a" (*eax),
@@ -147,6 +147,18 @@ static inline void cpuid(int op, int *ea
 		: "0" (op), "c"(0));
 }
 
+/* Some CPUID calls want 'count' to be placed in ecx */
+static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+	       	int *edx)
+{
+	__asm__("cpuid"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op), "c" (count));
+}
+
 /*
  * CPUID functions returning a single datum
  */
@@ -488,6 +500,14 @@ static inline void load_esp0(struct tss_
 	regs->esp = new_esp;					\
 } while (0)
 
+/*
+ * This special macro can be used to load a debugging register
+ */
+#define loaddebug(thread,register) \
+               __asm__("movl %0,%%db" #register  \
+                       : /* no output */ \
+                       :"r" ((thread)->debugreg[register]))
+
 /* Forward declaration, a strange C thing */
 struct task_struct;
 struct mm_struct;
diff --git a/include/asm-i386/seccomp.h b/include/asm-i386/seccomp.h
new file mode 100644
--- /dev/null
+++ b/include/asm-i386/seccomp.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h>
+
+#ifdef TIF_32BIT
+#error "unexpected TIF_32BIT on i386"
+#endif
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/include/asm-i386/segment.h b/include/asm-i386/segment.h
--- a/include/asm-i386/segment.h
+++ b/include/asm-i386/segment.h
@@ -38,7 +38,7 @@
  *  24 - APM BIOS support
  *  25 - APM BIOS support 
  *
- *  26 - unused
+ *  26 - ESPFIX small SS
  *  27 - unused
  *  28 - unused
  *  29 - unused
@@ -71,6 +71,9 @@
 #define GDT_ENTRY_PNPBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 6)
 #define GDT_ENTRY_APMBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 11)
 
+#define GDT_ENTRY_ESPFIX_SS		(GDT_ENTRY_KERNEL_BASE + 14)
+#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
+
 #define GDT_ENTRY_DOUBLEFAULT_TSS	31
 
 /*
diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h
--- a/include/asm-i386/semaphore.h
+++ b/include/asm-i386/semaphore.h
@@ -92,11 +92,6 @@ fastcall int  __down_failed_interruptibl
 fastcall int  __down_failed_trylock(void  /* params in registers */);
 fastcall void __up_wakeup(void /* special register calling convention */);
 
-fastcall void __down(struct semaphore * sem);
-fastcall int  __down_interruptible(struct semaphore * sem);
-fastcall int  __down_trylock(struct semaphore * sem);
-fastcall 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
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -16,7 +16,7 @@
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 #define MAX_NONPAE_PFN	(1 << 20)
 
-#define PARAM_SIZE 2048
+#define PARAM_SIZE 4096
 #define COMMAND_LINE_SIZE 256
 
 #define OLD_CL_MAGIC_ADDR	0x90020
diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h
--- a/include/asm-i386/signal.h
+++ b/include/asm-i386/signal.h
@@ -110,34 +110,7 @@ typedef unsigned long sigset_t;
 #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 __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
@@ -223,7 +196,14 @@ static __inline__ int sigfindinword(unsi
 
 struct pt_regs;
 extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#define ptrace_signal_deliver(regs, cookie)		\
+	do {						\
+		if (current->ptrace & PT_DTRACE) {	\
+			current->ptrace &= ~PT_DTRACE;	\
+			(regs)->eflags &= ~TF_MASK;	\
+		}					\
+	} while (0)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -35,6 +35,7 @@ extern void smp_alloc_memory(void);
 extern int pic_mode;
 extern int smp_num_siblings;
 extern cpumask_t cpu_sibling_map[];
+extern cpumask_t cpu_core_map[];
 
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
@@ -62,9 +63,6 @@ static inline int num_booting_cpus(void)
 	return cpus_weight(cpu_callout_map);
 }
 
-extern void map_cpu_to_logical_apicid(void);
-extern void unmap_cpu_to_logical_apicid(int cpu);
-
 #ifdef CONFIG_X86_LOCAL_APIC
 
 #ifdef APIC_DEFINITION
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -198,47 +198,80 @@ static inline void * __memcpy(void * to,
 int 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:"
+	"movl %4,%%ecx\n\t"
+	"andl $3,%%ecx\n\t"
+#if 1	/* want to pay 2 byte penalty for a chance to skip microcoded rep? */
+	"jz 1f\n\t"
+#endif
+	"rep ; movsb\n\t"
+	"1:"
 	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
-	:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+	: "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from)
 	: "memory");
 return (to);
 }
 
 /*
- * This looks horribly ugly, but the compiler can optimize it totally,
+ * This looks ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
 static inline void * __constant_memcpy(void * to, const void * from, size_t n)
 {
-	if (n <= 128)
-		return __builtin_memcpy(to, from, n);
-
-#define COMMON(x) \
-__asm__ __volatile__( \
-	"rep ; movsl" \
-	x \
-	: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
-	: "0" (n/4),"1" ((long) to),"2" ((long) from) \
-	: "memory");
-{
-	int d0, d1, d2;
+	long esi, edi;
+	if (!n) return to;
+#if 1	/* want to do small copies with non-string ops? */
+	switch (n) {
+		case 1: *(char*)to = *(char*)from; return to;
+		case 2: *(short*)to = *(short*)from; return to;
+		case 4: *(int*)to = *(int*)from; return to;
+#if 1	/* including those doable with two moves? */
+		case 3: *(short*)to = *(short*)from;
+			*((char*)to+2) = *((char*)from+2); return to;
+		case 5: *(int*)to = *(int*)from;
+			*((char*)to+4) = *((char*)from+4); return to;
+		case 6: *(int*)to = *(int*)from;
+			*((short*)to+2) = *((short*)from+2); return to;
+		case 8: *(int*)to = *(int*)from;
+			*((int*)to+1) = *((int*)from+1); return to;
+#endif
+	}
+#endif
+	esi = (long) from;
+	edi = (long) to;
+	if (n >= 5*4) {
+		/* large block: use rep prefix */
+		int ecx;
+		__asm__ __volatile__(
+			"rep ; movsl"
+			: "=&c" (ecx), "=&D" (edi), "=&S" (esi)
+			: "0" (n/4), "1" (edi),"2" (esi)
+			: "memory"
+		);
+	} else {
+		/* small block: don't clobber ecx + smaller code */
+		if (n >= 4*4) __asm__ __volatile__("movsl"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+		if (n >= 3*4) __asm__ __volatile__("movsl"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+		if (n >= 2*4) __asm__ __volatile__("movsl"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+		if (n >= 1*4) __asm__ __volatile__("movsl"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+	}
 	switch (n % 4) {
-		case 0: COMMON(""); return to;
-		case 1: COMMON("\n\tmovsb"); return to;
-		case 2: COMMON("\n\tmovsw"); return to;
-		default: COMMON("\n\tmovsw\n\tmovsb"); return to;
+		/* tail */
+		case 0: return to;
+		case 1: __asm__ __volatile__("movsb"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+			return to;
+		case 2: __asm__ __volatile__("movsw"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+			return to;
+		default: __asm__ __volatile__("movsw\n\tmovsb"
+			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+			return to;
 	}
 }
-  
-#undef COMMON
-}
 
 #define __HAVE_ARCH_MEMCPY
 
diff --git a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
--- a/include/asm-i386/suspend.h
+++ b/include/asm-i386/suspend.h
@@ -10,10 +10,12 @@ static inline int
 arch_prepare_suspend(void)
 {
 	/* If you want to make non-PSE machine work, turn off paging
-           in do_magic. swsusp_pg_dir should have identity mapping, so
+           in swsusp_arch_suspend. swsusp_pg_dir should have identity mapping, so
            it could work...  */
-	if (!cpu_has_pse)
+	if (!cpu_has_pse) {
+		printk(KERN_ERR "PSE is required for swsusp.\n");
 		return -EPERM;
+	}
 	return 0;
 }
 
@@ -34,11 +36,6 @@ struct saved_context {
 	unsigned long return_address;
 } __attribute__((packed));
 
-#define loaddebug(thread,register) \
-               __asm__("movl %0,%%db" #register  \
-                       : /* no output */ \
-                       :"r" ((thread)->debugreg[register]))
-
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
 extern unsigned long saved_esp;
@@ -61,5 +58,4 @@ static inline void acpi_save_register_st
 
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
-extern int acpi_save_state_disk(void);
 #endif
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -81,7 +81,7 @@ static inline unsigned long _get_base(ch
 #define loadsegment(seg,value)			\
 	asm volatile("\n"			\
 		"1:\t"				\
-		"movl %0,%%" #seg "\n"		\
+		"mov %0,%%" #seg "\n"		\
 		"2:\n"				\
 		".section .fixup,\"ax\"\n"	\
 		"3:\t"				\
@@ -93,13 +93,13 @@ static inline unsigned long _get_base(ch
 		".align 4\n\t"			\
 		".long 1b,3b\n"			\
 		".previous"			\
-		: :"m" (*(unsigned int *)&(value)))
+		: :"m" (value))
 
 /*
  * Save a segment register away
  */
 #define savesegment(seg, value) \
-	asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+	asm volatile("mov %%" #seg ",%0":"=m" (value))
 
 /*
  * Clear and set 'TS' bit respectively
@@ -468,4 +468,6 @@ void enable_hlt(void);
 extern int es7000_plat;
 void cpu_idle_wait(void);
 
+extern unsigned long arch_align_stack(unsigned long sp);
+
 #endif
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -140,6 +140,7 @@ register unsigned long current_stack_poi
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_IRET		5	/* return with iret */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+#define TIF_SECCOMP		8	/* secure computing */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 
@@ -150,12 +151,14 @@ register unsigned long current_stack_poi
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
-#define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
+/* work to do on any return to u-space */
+#define _TIF_ALLWORK_MASK	(0x0000FFFF & ~_TIF_SECCOMP)
 
 /*
  * Thread-synchronous status.
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -53,6 +53,7 @@ extern struct init_timer_opts timer_cycl
 
 extern unsigned long calibrate_tsc(void);
 extern void init_cpu_khz(void);
+extern int recalibrate_cpu_khz(void);
 #ifdef CONFIG_HPET_TIMER
 extern struct init_timer_opts timer_hpet_init;
 extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
diff --git a/include/asm-i386/timex.h b/include/asm-i386/timex.h
--- a/include/asm-i386/timex.h
+++ b/include/asm-i386/timex.h
@@ -32,8 +32,6 @@
  */
 typedef unsigned long long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles (void)
 {
 	unsigned long long ret=0;
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -60,11 +60,12 @@ static inline int node_to_first_cpu(int 
 	return first_cpu(mask);
 }
 
-/* Returns the number of the node containing PCI bus 'bus' */
-static inline cpumask_t pcibus_to_cpumask(int bus)
+/* Returns the number of the node containing PCI bus number 'busnr' */
+static inline cpumask_t __pcibus_to_cpumask(int busnr)
 {
-	return node_to_cpumask(mp_bus_id_to_node[bus]);
+	return node_to_cpumask(mp_bus_id_to_node[busnr]);
 }
+#define pcibus_to_cpumask(bus)	__pcibus_to_cpumask(bus->number)
 
 /* sched_domains SD_NODE_INIT for NUMAQ machines */
 #define SD_NODE_INIT (struct sched_domain) {		\
@@ -88,6 +89,12 @@ static inline cpumask_t pcibus_to_cpumas
 	.nr_balance_failed	= 0,			\
 }
 
+extern unsigned long node_start_pfn[];
+extern unsigned long node_end_pfn[];
+extern unsigned long node_remap_size[];
+
+#define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid])
+
 #else /* !CONFIG_NUMA */
 /*
  * Other i386 platforms should define their own version of the 
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -84,7 +84,8 @@ extern struct movsl_mask {
 #define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
 
 /**
- * verify_area: - Obsolete, use access_ok()
+ * verify_area: - Obsolete/deprecated and will go away soon,
+ * use access_ok() instead.
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
  * @addr: User space pointer to start of block to check
  * @size: Size of block to check
@@ -100,7 +101,7 @@ extern struct movsl_mask {
  *
  * See access_ok() for more details.
  */
-static inline int verify_area(int type, const void __user * addr, unsigned long size)
+static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -185,6 +186,21 @@ extern void __get_user_4(void);
 
 extern void __put_user_bad(void);
 
+/*
+ * Strange magic calling convention: pointer in %ecx,
+ * value in %eax(:%edx), return value in %eax, no clobbers.
+ */
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+extern void __put_user_8(void);
+
+#define __put_user_1(x, ptr) __asm__ __volatile__("call __put_user_1":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_2(x, ptr) __asm__ __volatile__("call __put_user_2":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_4(x, ptr) __asm__ __volatile__("call __put_user_4":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_8(x, ptr) __asm__ __volatile__("call __put_user_8":"=a" (__ret_pu):"A" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_X(x, ptr) __asm__ __volatile__("call __put_user_X":"=a" (__ret_pu):"c" (ptr))
+
 /**
  * put_user: - Write a simple value into user space.
  * @x:   Value to copy to user space.
@@ -201,10 +217,36 @@ extern void __put_user_bad(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define put_user(x,ptr)							\
-  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+#ifdef CONFIG_X86_WP_WORKS_OK
+
+#define put_user(x,ptr)						\
+({	int __ret_pu;						\
+	__chk_user_ptr(ptr);					\
+	switch(sizeof(*(ptr))) {				\
+	case 1: __put_user_1(x, ptr); break;			\
+	case 2: __put_user_2(x, ptr); break;			\
+	case 4: __put_user_4(x, ptr); break;			\
+	case 8: __put_user_8(x, ptr); break;			\
+	default:__put_user_X(x, ptr); break;			\
+	}							\
+	__ret_pu;						\
+})
+
+#else
+#define put_user(x,ptr)						\
+({								\
+ 	int __ret_pu;						\
+	__typeof__(*(ptr)) __pus_tmp = x;			\
+	__ret_pu=0;						\
+	if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp,		\
+				sizeof(*(ptr))) != 0))		\
+ 		__ret_pu=-EFAULT;				\
+ 	__ret_pu;						\
+ })
 
 
+#endif
+
 /**
  * __get_user: - Get a simple variable from user space, with less checking.
  * @x:   Variable to store result.
@@ -259,16 +301,6 @@ extern void __put_user_bad(void);
 })
 
 
-#define __put_user_check(x,ptr,size)					\
-({									\
-	long __pu_err = -EFAULT;					\
-	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
-	might_sleep();						\
-	if (access_ok(VERIFY_WRITE,__pu_addr,size))			\
-		__put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT);	\
-	__pu_err;							\
-})							
-
 #define __put_user_u64(x, addr, err)				\
 	__asm__ __volatile__(					\
 		"1:	movl %%eax,0(%2)\n"			\
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -460,7 +460,7 @@ asmlinkage long sys_rt_sigaction(int sig
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* _ASM_I386_UNISTD_H_ */
diff --git a/include/asm-ia64/agp.h b/include/asm-ia64/agp.h
--- a/include/asm-ia64/agp.h
+++ b/include/asm-ia64/agp.h
@@ -18,4 +18,14 @@
 #define flush_agp_mappings()		/* nothing */
 #define flush_agp_cache()		mb()
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif /* _ASM_IA64_AGP_H */
diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
--- a/include/asm-ia64/bitops.h
+++ b/include/asm-ia64/bitops.h
@@ -314,8 +314,8 @@ __ffs (unsigned long x)
 #ifdef __KERNEL__
 
 /*
- * find_last_zero_bit - find the last zero bit in a 64 bit quantity
- * @x: The value to search
+ * Return bit number of last (most-significant) bit set.  Undefined
+ * for x==0.  Bits are numbered from 0..63 (e.g., ia64_fls(9) == 3).
  */
 static inline unsigned long
 ia64_fls (unsigned long x)
@@ -327,10 +327,23 @@ ia64_fls (unsigned long x)
 	return exp - 0xffff;
 }
 
+/*
+ * Find the last (most significant) bit set.  Returns 0 for x==0 and
+ * bits are numbered from 1..32 (e.g., fls(9) == 4).
+ */
 static inline int
-fls (int x)
+fls (int t)
 {
-	return ia64_fls((unsigned int) x);
+	unsigned long x = t & 0xffffffffu;
+
+	if (!x)
+		return 0;
+	x |= x >> 1;
+	x |= x >> 2;
+	x |= x >> 4;
+	x |= x >> 8;
+	x |= x >> 16;
+	return ia64_popcnt(x);
 }
 
 /*
@@ -353,9 +366,9 @@ hweight64 (unsigned long x)
 	return result;
 }
 
-#define hweight32(x) hweight64 ((x) & 0xfffffffful)
-#define hweight16(x) hweight64 ((x) & 0xfffful)
-#define hweight8(x)  hweight64 ((x) & 0xfful)
+#define hweight32(x)	(unsigned int) hweight64((x) & 0xfffffffful)
+#define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
+#define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ia64/bug.h b/include/asm-ia64/bug.h
--- a/include/asm-ia64/bug.h
+++ b/include/asm-ia64/bug.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_IA64_BUG_H
 #define _ASM_IA64_BUG_H
 
+#ifdef CONFIG_BUG
 #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
 # define ia64_abort()	__builtin_trap()
 #else
@@ -8,8 +9,10 @@
 #endif
 #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
 
-/* should this BUG should be made generic? */
+/* should this BUG be made generic? */
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-ia64/cacheflush.h b/include/asm-ia64/cacheflush.h
--- a/include/asm-ia64/cacheflush.h
+++ b/include/asm-ia64/cacheflush.h
@@ -19,7 +19,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_icache_page(vma,page)		do { } while (0)
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
diff --git a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h
--- a/include/asm-ia64/gcc_intrin.h
+++ b/include/asm-ia64/gcc_intrin.h
@@ -133,13 +133,17 @@ register unsigned long ia64_r13 asm ("r1
 	ia64_intri_res;								\
 })
 
-#define ia64_popcnt(x)						\
-({								\
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define ia64_popcnt(x)		__builtin_popcountl(x)
+#else
+# define ia64_popcnt(x)						\
+  ({								\
 	__u64 ia64_intri_res;					\
 	asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x));	\
 								\
 	ia64_intri_res;						\
-})
+  })
+#endif
 
 #define ia64_getf_exp(x)					\
 ({								\
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -81,6 +81,7 @@ extern __u8 isa_irq_to_vector_map[16];
 
 extern struct hw_interrupt_type irq_type_ia64_lsapic;	/* CPU-internal interrupt controller */
 
+extern int assign_irq_vector_nopanic (int irq); /* allocate a free vector without panic */
 extern int assign_irq_vector (int irq);	/* allocate a free vector */
 extern void free_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
diff --git a/include/asm-ia64/ioctl32.h b/include/asm-ia64/ioctl32.h
deleted file mode 100644
--- a/include/asm-ia64/ioctl32.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <linux/ioctl32.h>
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -137,9 +137,9 @@ typedef union ia64_va {
 # define htlbpage_to_page(x)	(((unsigned long) REGION_NUMBER(x) << 61)			\
 				 | (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT)))
 # define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
-# define is_hugepage_only_range(addr, len)		\
+# define is_hugepage_only_range(mm, addr, len)		\
 	 (REGION_NUMBER(addr) == REGION_HPAGE &&	\
-	  REGION_NUMBER((addr)+(len)) == REGION_HPAGE)
+	  REGION_NUMBER((addr)+(len)-1) == REGION_HPAGE)
 extern unsigned int hpage_shift;
 #endif
 
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -67,6 +67,7 @@
 #define PAL_REGISTER_INFO	39	/* return AR and CR register information*/
 #define PAL_SHUTDOWN		40	/* enter processor shutdown state */
 #define PAL_PREFETCH_VISIBILITY	41	/* Make Processor Prefetches Visible */
+#define PAL_LOGICAL_TO_PHYSICAL 42	/* returns information on logical to physical processor mapping */
 
 #define PAL_COPY_PAL		256	/* relocate PAL procedures and PAL PMI */
 #define PAL_HALT_INFO		257	/* return the low power capabilities of processor */
@@ -1559,6 +1560,73 @@ ia64_pal_prefetch_visibility (s64 trans_
 	return iprv.status;
 }
 
+/* data structure for getting information on logical to physical mappings */
+typedef union pal_log_overview_u {
+	struct {
+		u64	num_log		:16,	/* Total number of logical
+						 * processors on this die
+						 */
+			tpc		:8,	/* Threads per core */
+			reserved3	:8,	/* Reserved */
+			cpp		:8,	/* Cores per processor */
+			reserved2	:8,	/* Reserved */
+			ppid		:8,	/* Physical processor ID */
+			reserved1	:8;	/* Reserved */
+	} overview_bits;
+	u64 overview_data;
+} pal_log_overview_t;
+
+typedef union pal_proc_n_log_info1_u{
+	struct {
+		u64	tid		:16,	/* Thread id */
+			reserved2	:16,	/* Reserved */
+			cid		:16,	/* Core id */
+			reserved1	:16;	/* Reserved */
+	} ppli1_bits;
+	u64	ppli1_data;
+} pal_proc_n_log_info1_t;
+
+typedef union pal_proc_n_log_info2_u {
+	struct {
+		u64	la		:16,	/* Logical address */
+			reserved	:48;	/* Reserved */
+	} ppli2_bits;
+	u64	ppli2_data;
+} pal_proc_n_log_info2_t;
+
+typedef struct pal_logical_to_physical_s
+{
+	pal_log_overview_t overview;
+	pal_proc_n_log_info1_t ppli1;
+	pal_proc_n_log_info2_t ppli2;
+} pal_logical_to_physical_t;
+
+#define overview_num_log	overview.overview_bits.num_log
+#define overview_tpc		overview.overview_bits.tpc
+#define overview_cpp		overview.overview_bits.cpp
+#define overview_ppid		overview.overview_bits.ppid
+#define log1_tid		ppli1.ppli1_bits.tid
+#define log1_cid		ppli1.ppli1_bits.cid
+#define log2_la			ppli2.ppli2_bits.la
+
+/* Get information on logical to physical processor mappings. */
+static inline s64
+ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping)
+{
+	struct ia64_pal_retval iprv;
+
+	PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0);
+
+	if (iprv.status == PAL_STATUS_SUCCESS)
+	{
+		if (proc_number == 0)
+			mapping->overview.overview_data = iprv.v0;
+		mapping->ppli1.ppli1_data = iprv.v1;
+		mapping->ppli2.ppli2_data = iprv.v2;
+	}
+
+	return iprv.status;
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_IA64_PAL_H */
diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h
+++ b/include/asm-ia64/pci.h
@@ -121,14 +121,9 @@ struct pci_controller {
 
 extern struct pci_ops pci_root_ops;
 
-static inline int pci_name_bus(char *name, struct pci_bus *bus)
+static inline int pci_proc_domain(struct pci_bus *bus)
 {
-	if (pci_domain_nr(bus) == 0) {
-		sprintf(name, "%02x", bus->number);
-	} else {
-		sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
-	}
-	return 0;
+	return (pci_domain_nr(bus) != 0);
 }
 
 static inline void pcibios_add_platform_entries(struct pci_dev *dev)
diff --git a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h
--- a/include/asm-ia64/perfmon.h
+++ b/include/asm-ia64/perfmon.h
@@ -177,6 +177,10 @@ typedef union {
 
 extern long perfmonctl(int fd, int cmd, void *arg, int narg);
 
+typedef struct {
+	void (*handler)(int irq, void *arg, struct pt_regs *regs);
+} pfm_intr_handler_desc_t;
+
 extern void pfm_save_regs (struct task_struct *);
 extern void pfm_load_regs (struct task_struct *);
 
@@ -187,6 +191,10 @@ extern void pfm_syst_wide_update_task(st
 extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs);
 extern void pfm_init_percpu(void);
 extern void pfm_handle_work(void);
+extern int  pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
+extern int  pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
+
+
 
 /*
  * Reset PMD register flags
@@ -254,6 +262,18 @@ extern int pfm_mod_write_dbrs(struct tas
 #define PFM_CPUINFO_DCR_PP	0x2	/* if set the system wide session has started */
 #define PFM_CPUINFO_EXCL_IDLE	0x4	/* the system wide session excludes the idle task */
 
+/*
+ * sysctl control structure. visible to sampling formats
+ */
+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 */
+	int	expert_mode;	/* turn on/off value checking */
+} pfm_sysctl_t;
+extern pfm_sysctl_t pfm_sysctl;
+
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_IA64_PERFMON_H */
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -21,148 +21,125 @@
 #include <linux/threads.h>
 
 #include <asm/mmu_context.h>
-#include <asm/processor.h>
 
-/*
- * Very stupidly, we used to get new pgd's and pmd's, init their contents
- * to point to the NULL versions of the next level page table, later on
- * completely re-init them the same way, then free them up.  This wasted
- * a lot of work and caused unnecessary memory traffic.  How broken...
- * We fix this by caching them.
- */
-#define pgd_quicklist		(local_cpu_data->pgd_quick)
-#define pmd_quicklist		(local_cpu_data->pmd_quick)
-#define pgtable_cache_size	(local_cpu_data->pgtable_cache_sz)
+DECLARE_PER_CPU(unsigned long *, __pgtable_quicklist);
+#define pgtable_quicklist __ia64_per_cpu_var(__pgtable_quicklist)
+DECLARE_PER_CPU(long, __pgtable_quicklist_size);
+#define pgtable_quicklist_size __ia64_per_cpu_var(__pgtable_quicklist_size)
 
-static inline pgd_t*
-pgd_alloc_one_fast (struct mm_struct *mm)
+static inline long pgtable_quicklist_total_size(void)
+{
+	long ql_size = 0;
+	int cpuid;
+
+	for_each_online_cpu(cpuid) {
+		ql_size += per_cpu(__pgtable_quicklist_size, cpuid);
+	}
+	return ql_size;
+}
+
+static inline void *pgtable_quicklist_alloc(void)
 {
 	unsigned long *ret = NULL;
 
 	preempt_disable();
 
-	ret = pgd_quicklist;
+	ret = pgtable_quicklist;
 	if (likely(ret != NULL)) {
-		pgd_quicklist = (unsigned long *)(*ret);
+		pgtable_quicklist = (unsigned long *)(*ret);
 		ret[0] = 0;
-		--pgtable_cache_size;
-	} else
-		ret = NULL;
-
-	preempt_enable();
+		--pgtable_quicklist_size;
+		preempt_enable();
+	} else {
+		preempt_enable();
+		ret = (unsigned long *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+	}
 
-	return (pgd_t *) ret;
+	return ret;
 }
 
-static inline pgd_t*
-pgd_alloc (struct mm_struct *mm)
+static inline void pgtable_quicklist_free(void *pgtable_entry)
 {
-	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
-	pgd_t *pgd = pgd_alloc_one_fast(mm);
+#ifdef CONFIG_NUMA
+	unsigned long nid = page_to_nid(virt_to_page(pgtable_entry));
 
-	if (unlikely(pgd == NULL)) {
-		pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+	if (unlikely(nid != numa_node_id())) {
+		free_page((unsigned long)pgtable_entry);
+		return;
 	}
-	return pgd;
-}
+#endif
 
-static inline void
-pgd_free (pgd_t *pgd)
-{
 	preempt_disable();
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	++pgtable_cache_size;
+	*(unsigned long *)pgtable_entry = (unsigned long)pgtable_quicklist;
+	pgtable_quicklist = (unsigned long *)pgtable_entry;
+	++pgtable_quicklist_size;
 	preempt_enable();
 }
 
-static inline void
-pud_populate (struct mm_struct *mm, pud_t *pud_entry, pmd_t *pmd)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	pud_val(*pud_entry) = __pa(pmd);
+	return pgtable_quicklist_alloc();
 }
 
-static inline pmd_t*
-pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
+static inline void pgd_free(pgd_t * pgd)
 {
-	unsigned long *ret = NULL;
-
-	preempt_disable();
-
-	ret = (unsigned long *)pmd_quicklist;
-	if (likely(ret != NULL)) {
-		pmd_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		--pgtable_cache_size;
-	}
-
-	preempt_enable();
-
-	return (pmd_t *)ret;
+	pgtable_quicklist_free(pgd);
 }
 
-static inline pmd_t*
-pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
+static inline void
+pud_populate(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd)
 {
-	pmd_t *pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+	pud_val(*pud_entry) = __pa(pmd);
+}
 
-	return pmd;
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	return pgtable_quicklist_alloc();
 }
 
-static inline void
-pmd_free (pmd_t *pmd)
+static inline void pmd_free(pmd_t * pmd)
 {
-	preempt_disable();
-	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
-	pmd_quicklist = (unsigned long *) pmd;
-	++pgtable_cache_size;
-	preempt_enable();
+	pgtable_quicklist_free(pmd);
 }
 
 #define __pmd_free_tlb(tlb, pmd)	pmd_free(pmd)
 
 static inline void
-pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, struct page *pte)
+pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte)
 {
 	pmd_val(*pmd_entry) = page_to_phys(pte);
 }
 
 static inline void
-pmd_populate_kernel (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte)
+pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte)
 {
 	pmd_val(*pmd_entry) = __pa(pte);
 }
 
-static inline struct page *
-pte_alloc_one (struct mm_struct *mm, unsigned long addr)
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+					 unsigned long addr)
 {
-	struct page *pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
-
-	return pte;
+	return virt_to_page(pgtable_quicklist_alloc());
 }
 
-static inline pte_t *
-pte_alloc_one_kernel (struct mm_struct *mm, unsigned long addr)
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+					  unsigned long addr)
 {
-	pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
-
-	return pte;
+	return pgtable_quicklist_alloc();
 }
 
-static inline void
-pte_free (struct page *pte)
+static inline void pte_free(struct page *pte)
 {
-	__free_page(pte);
+	pgtable_quicklist_free(page_address(pte));
 }
 
-static inline void
-pte_free_kernel (pte_t *pte)
+static inline void pte_free_kernel(pte_t * pte)
 {
-	free_page((unsigned long) pte);
+	pgtable_quicklist_free(pte);
 }
 
-#define __pte_free_tlb(tlb, pte)	tlb_remove_page((tlb), (pte))
+#define __pte_free_tlb(tlb, pte)	pte_free(pte)
 
-extern void check_pgt_cache (void);
+extern void check_pgt_cache(void);
 
-#endif /* _ASM_IA64_PGALLOC_H */
+#endif				/* _ASM_IA64_PGALLOC_H */
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -8,7 +8,7 @@
  * This hopefully works with any (fixed) IA-64 page-size, as defined
  * in <asm/page.h>.
  *
- * Copyright (C) 1998-2004 Hewlett-Packard Co
+ * Copyright (C) 1998-2005 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -93,7 +93,7 @@
 #define PGDIR_MASK		(~(PGDIR_SIZE-1))
 #define PTRS_PER_PGD		(1UL << (PAGE_SHIFT-3))
 #define USER_PTRS_PER_PGD	(5*PTRS_PER_PGD/8)	/* regions 0-4 are user regions */
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 /*
  * Definitions for second level:
@@ -202,6 +202,7 @@ ia64_phys_addr_valid (unsigned long addr
  * the PTE in a page table.  Nothing special needs to be on IA-64.
  */
 #define set_pte(ptep, pteval)	(*(ptep) = (pteval))
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 #define RGN_SIZE	(1UL << 61)
 #define RGN_KERNEL	7
@@ -243,7 +244,7 @@ ia64_phys_addr_valid (unsigned long addr
 
 #define pte_none(pte) 			(!pte_val(pte))
 #define pte_present(pte)		(pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE))
-#define pte_clear(pte)			(pte_val(*(pte)) = 0UL)
+#define pte_clear(mm,addr,pte)		(pte_val(*(pte)) = 0UL)
 /* pte_page() returns the "struct page *" corresponding to the PTE: */
 #define pte_page(pte)			virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET))
 
@@ -345,7 +346,7 @@ pgd_offset (struct mm_struct *mm, unsign
 /* atomic versions of the some PTE manipulations: */
 
 static inline int
-ptep_test_and_clear_young (pte_t *ptep)
+ptep_test_and_clear_young (struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	if (!pte_young(*ptep))
@@ -355,13 +356,13 @@ ptep_test_and_clear_young (pte_t *ptep)
 	pte_t pte = *ptep;
 	if (!pte_young(pte))
 		return 0;
-	set_pte(ptep, pte_mkold(pte));
+	set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte));
 	return 1;
 #endif
 }
 
 static inline int
-ptep_test_and_clear_dirty (pte_t *ptep)
+ptep_test_and_clear_dirty (struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	if (!pte_dirty(*ptep))
@@ -371,25 +372,25 @@ ptep_test_and_clear_dirty (pte_t *ptep)
 	pte_t pte = *ptep;
 	if (!pte_dirty(pte))
 		return 0;
-	set_pte(ptep, pte_mkclean(pte));
+	set_pte_at(vma->vm_mm, addr, ptep, pte_mkclean(pte));
 	return 1;
 #endif
 }
 
 static inline pte_t
-ptep_get_and_clear (pte_t *ptep)
+ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	return __pte(xchg((long *) ptep, 0));
 #else
 	pte_t pte = *ptep;
-	pte_clear(ptep);
+	pte_clear(mm, addr, ptep);
 	return pte;
 #endif
 }
 
 static inline void
-ptep_set_wrprotect (pte_t *ptep)
+ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	unsigned long new, old;
@@ -400,18 +401,7 @@ ptep_set_wrprotect (pte_t *ptep)
 	} 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(_PAGE_D_BIT, ptep);
-#else
-	pte_t old_pte = *ptep;
-	set_pte(ptep, pte_mkdirty(old_pte));
+	set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 #endif
 }
 
@@ -421,6 +411,8 @@ pte_same (pte_t a, pte_t b)
 	return pte_val(a) == pte_val(b);
 }
 
+#define update_mmu_cache(vma, address, pte) do { } while (0)
+
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init (void);
 
@@ -457,6 +449,13 @@ extern void paging_init (void);
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
@@ -473,8 +472,8 @@ extern struct page *zero_page_memmap_ptr
 #define HUGETLB_PGDIR_SIZE	(__IA64_UL(1) << HUGETLB_PGDIR_SHIFT)
 #define HUGETLB_PGDIR_MASK	(~(HUGETLB_PGDIR_SIZE-1))
 struct mmu_gather;
-extern void hugetlb_free_pgtables(struct mmu_gather *tlb,
-	struct vm_area_struct * prev, unsigned long start, unsigned long end);
+void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
+		unsigned long end, unsigned long floor, unsigned long ceiling);
 #endif
 
 /*
@@ -482,7 +481,7 @@ extern void hugetlb_free_pgtables(struct
  * information.  However, we use this routine to take care of any (delayed) i-cache
  * flushing that may be necessary.
  */
-extern void update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte);
+extern void lazy_mmu_prot_update (pte_t pte);
 
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 /*
@@ -552,16 +551,21 @@ do {											\
 
 /* These tell get_user_pages() that the first gate page is accessible from user-level.  */
 #define FIXADDR_USER_START	GATE_ADDR
-#define FIXADDR_USER_END	(GATE_ADDR + 2*PERCPU_PAGE_SIZE)
+#ifdef HAVE_BUGGY_SEGREL
+# define FIXADDR_USER_END	(GATE_ADDR + 2*PAGE_SIZE)
+#else
+# define FIXADDR_USER_END	(GATE_ADDR + 2*PERCPU_PAGE_SIZE)
+#endif
 
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #define __HAVE_ARCH_PGD_OFFSET_GATE
-#include <asm-generic/pgtable.h>
+#define __HAVE_ARCH_LAZY_MMU_PROT_UPDATE
+
 #include <asm-generic/pgtable-nopud.h>
+#include <asm-generic/pgtable.h>
 
 #endif /* _ASM_IA64_PGTABLE_H */
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -43,14 +43,6 @@
 #define TASK_SIZE		(current->thread.task_size)
 
 /*
- * MM_VM_SIZE(mm) gives the maximum address (plus 1) which may contain a mapping for
- * address-space MM.  Note that with 32-bit tasks, this is still DEFAULT_TASK_SIZE,
- * because the kernel may have installed helper-mappings above TASK_SIZE.  For example,
- * for x86 emulation, the LDT and GDT are mapped above TASK_SIZE.
- */
-#define MM_VM_SIZE(mm)		DEFAULT_TASK_SIZE
-
-/*
  * This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
@@ -145,9 +137,6 @@ struct cpuinfo_ia64 {
 	__u64 nsec_per_cyc;	/* (1000000000<<IA64_NSEC_PER_CYC_SHIFT)/itc_freq */
 	__u64 unimpl_va_mask;	/* mask of unimplemented virtual address bits (from PAL) */
 	__u64 unimpl_pa_mask;	/* mask of unimplemented physical address bits (from PAL) */
-	__u64 *pgd_quick;
-	__u64 *pmd_quick;
-	__u64 pgtable_cache_sz;
 	__u64 itc_freq;		/* frequency of ITC counter */
 	__u64 proc_freq;	/* frequency of processor */
 	__u64 cyc_per_usec;	/* itc_freq/1000000 */
@@ -159,6 +148,13 @@ struct cpuinfo_ia64 {
 #ifdef CONFIG_SMP
 	__u64 loops_per_jiffy;
 	int cpu;
+	__u32 socket_id;	/* physical processor socket id */
+	__u16 core_id;		/* core id */
+	__u16 thread_id;	/* thread id */
+	__u16 num_log;		/* Total number of logical processors on
+				 * this socket that were successfully booted */
+	__u8  cores_per_socket;	/* Cores per processor socket */
+	__u8  threads_per_core;	/* Threads per core */
 #endif
 
 	/* CPUID-derived information: */
@@ -407,7 +403,10 @@ extern void ia64_setreg_unknown_kr (void
  * task_struct at this point.
  */
 
-/* Return TRUE if task T owns the fph partition of the CPU we're running on. */
+/*
+ * Return TRUE if task T owns the fph partition of the CPU we're running on.
+ * Must be called from code that has preemption disabled.
+ */
 #define ia64_is_local_fpu_owner(t)								\
 ({												\
 	struct task_struct *__ia64_islfo_task = (t);						\
@@ -415,7 +414,10 @@ extern void ia64_setreg_unknown_kr (void
 	 && __ia64_islfo_task == (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER));	\
 })
 
-/* Mark task T as owning the fph partition of the CPU we're running on. */
+/*
+ * Mark task T as owning the fph partition of the CPU we're running on.
+ * Must be called from code that has preemption disabled.
+ */
 #define ia64_set_local_fpu_owner(t) do {						\
 	struct task_struct *__ia64_slfo_task = (t);					\
 	__ia64_slfo_task->thread.last_fph_cpu = smp_processor_id();			\
diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
--- a/include/asm-ia64/sal.h
+++ b/include/asm-ia64/sal.h
@@ -91,6 +91,7 @@ extern spinlock_t sal_lock;
 #define SAL_PCI_CONFIG_READ		0x01000010
 #define SAL_PCI_CONFIG_WRITE		0x01000011
 #define SAL_FREQ_BASE			0x01000012
+#define SAL_PHYSICAL_ID_INFO		0x01000013
 
 #define SAL_UPDATE_PAL			0x01000020
 
@@ -815,6 +816,17 @@ ia64_sal_update_pal (u64 param_buf, u64 
 	return isrv.status;
 }
 
+/* Get physical processor die mapping in the platform. */
+static inline s64
+ia64_sal_physical_id_info(u16 *splid)
+{
+	struct ia64_sal_retval isrv;
+	SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0);
+	if (splid)
+		*splid = isrv.v0;
+	return isrv.status;
+}
+
 extern unsigned long sal_platform_features;
 
 extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *);
@@ -832,6 +844,44 @@ extern int ia64_sal_oemcall_nolock(struc
 				   u64, u64, u64, u64, u64);
 extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64,
 				      u64, u64, u64, u64, u64);
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * System Abstraction Layer Specification
+ * Section 3.2.5.1: OS_BOOT_RENDEZ to SAL return State.
+ * Note: region regs are stored first in head.S _start. Hence they must
+ * stay up front.
+ */
+struct sal_to_os_boot {
+	u64 rr[8];		/* Region Registers */
+	u64	br[6];		/* br0: return addr into SAL boot rendez routine */
+	u64 gr1;		/* SAL:GP */
+	u64 gr12;		/* SAL:SP */
+	u64 gr13;		/* SAL: Task Pointer */
+	u64 fpsr;
+	u64	pfs;
+	u64 rnat;
+	u64 unat;
+	u64 bspstore;
+	u64 dcr;		/* Default Control Register */
+	u64 iva;
+	u64 pta;
+	u64 itv;
+	u64 pmv;
+	u64 cmcv;
+	u64 lrr[2];
+	u64 gr[4];
+	u64 pr;			/* Predicate registers */
+	u64 lc;			/* Loop Count */
+	struct ia64_fpreg fp[20];
+};
+
+/*
+ * Global array allocated for NR_CPUS at boot time
+ */
+extern struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS];
+
+extern void ia64_jump_to_sal(struct sal_to_os_boot *);
+#endif
 
 extern void ia64_sal_handler_init(void *entry_point, void *gpval);
 
diff --git a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h
--- a/include/asm-ia64/siginfo.h
+++ b/include/asm-ia64/siginfo.h
@@ -8,9 +8,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
-
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
+#define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
 
 #define HAVE_ARCH_SIGINFO_T
 #define HAVE_ARCH_COPY_SIGINFO
diff --git a/include/asm-ia64/signal.h b/include/asm-ia64/signal.h
--- a/include/asm-ia64/signal.h
+++ b/include/asm-ia64/signal.h
@@ -114,27 +114,11 @@
 #define _NSIG_BPW	64
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
-/*
- * 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
 #define SA_PERCPU_IRQ		0x02000000
 
 #endif /* __KERNEL__ */
 
-#define SIG_BLOCK          0	/* for blocking signals */
-#define SIG_UNBLOCK        1	/* for unblocking signals */
-#define SIG_SETMASK        2	/* for setting the signal mask */
-
-#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 */
+#include <asm-generic/signal.h>
 
 # ifndef __ASSEMBLY__
 
@@ -143,9 +127,6 @@
 /* Avoid too many header ordering problems.  */
 struct siginfo;
 
-/* Type of a signal handler.  */
-typedef void __user (*__sighandler_t)(int);
-
 typedef struct sigaltstack {
 	void __user *ss_sp;
 	int ss_flags;
diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
--- a/include/asm-ia64/smp.h
+++ b/include/asm-ia64/smp.h
@@ -3,16 +3,14 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2001-2003 Hewlett-Packard Co
+ * (c) Copyright 2001-2003, 2005 Hewlett-Packard Development Company, L.P.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 #ifndef _ASM_IA64_SMP_H
 #define _ASM_IA64_SMP_H
 
 #include <linux/config.h>
-
-#ifdef CONFIG_SMP
-
 #include <linux/init.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
@@ -24,6 +22,25 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 
+static inline unsigned int
+ia64_get_lid (void)
+{
+	union {
+		struct {
+			unsigned long reserved : 16;
+			unsigned long eid : 8;
+			unsigned long id : 8;
+			unsigned long ignored : 32;
+		} f;
+		unsigned long bits;
+	} lid;
+
+	lid.bits = ia64_getreg(_IA64_REG_CR_LID);
+	return lid.f.id << 8 | lid.f.eid;
+}
+
+#ifdef CONFIG_SMP
+
 #define XTP_OFFSET		0x1e0008
 
 #define SMP_IRQ_REDIRECTION	(1 << 0)
@@ -39,6 +56,10 @@ extern struct smp_boot_data {
 extern char no_int_routing __devinitdata;
 
 extern cpumask_t cpu_online_map;
+extern cpumask_t cpu_core_map[NR_CPUS];
+extern cpumask_t cpu_sibling_map[NR_CPUS];
+extern int smp_num_siblings;
+extern int smp_num_cpucores;
 extern void __iomem *ipi_base_addr;
 extern unsigned char smp_int_redirect;
 
@@ -90,22 +111,7 @@ max_xtp (void)
 		writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
 }
 
-static inline unsigned int
-hard_smp_processor_id (void)
-{
-	union {
-		struct {
-			unsigned long reserved : 16;
-			unsigned long eid : 8;
-			unsigned long id : 8;
-			unsigned long ignored : 32;
-		} f;
-		unsigned long bits;
-	} lid;
-
-	lid.bits = ia64_getreg(_IA64_REG_CR_LID);
-	return lid.f.id << 8 | lid.f.eid;
-}
+#define hard_smp_processor_id()		ia64_get_lid()
 
 /* Upping and downing of CPUs */
 extern int __cpu_disable (void);
@@ -122,10 +128,12 @@ extern int smp_call_function_single (int
 extern void smp_send_reschedule (int cpu);
 extern void lock_ipi_calllock(void);
 extern void unlock_ipi_calllock(void);
+extern void identify_siblings (struct cpuinfo_ia64 *);
 
 #else
 
-#define cpu_logical_id(cpuid)		0
+#define cpu_logical_id(i)		0
+#define cpu_physical_id(i)		ia64_get_lid()
 
 #endif /* CONFIG_SMP */
 #endif /* _ASM_IA64_SMP_H */
diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h
--- a/include/asm-ia64/sn/addrs.h
+++ b/include/asm-ia64/sn/addrs.h
@@ -11,6 +11,7 @@
 
 #include <asm/percpu.h>
 #include <asm/sn/types.h>
+#include <asm/sn/arch.h>
 #include <asm/sn/pda.h>
 
 /*
@@ -57,9 +58,9 @@
 /*
  * Define basic shift & mask constants for manipulating NASIDs and AS values.
  */
-#define NASID_BITMASK		(pda->nasid_bitmask)
-#define NASID_SHIFT		(pda->nasid_shift)
-#define AS_SHIFT		(pda->as_shift)
+#define NASID_BITMASK		(sn_hub_info->nasid_bitmask)
+#define NASID_SHIFT		(sn_hub_info->nasid_shift)
+#define AS_SHIFT		(sn_hub_info->as_shift)
 #define AS_BITMASK		0x3UL
 
 #define NASID_MASK              ((u64)NASID_BITMASK << NASID_SHIFT)
@@ -135,6 +136,7 @@
  */
 #define CAC_BASE		(CACHED   | AS_CAC_SPACE)
 #define AMO_BASE		(UNCACHED | AS_AMO_SPACE)
+#define AMO_PHYS_BASE		(UNCACHED_PHYS | AS_AMO_SPACE)
 #define GET_BASE		(CACHED   | AS_GET_SPACE)
 
 /*
@@ -153,12 +155,20 @@
  *           the chiplet id is zero.  If we implement TIO-TIO dma, we might need
  *           to insert a chiplet id into this macro.  However, it is our belief
  *           right now that this chiplet id will be ICE, which is also zero.
+ *           Nasid starts on bit 40.
  */
-#define PHYS_TO_TIODMA(x)	( (((u64)(x) & NASID_MASK) << 2) | NODE_OFFSET(x))
+#define PHYS_TO_TIODMA(x)	( (((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
 #define PHYS_TO_DMA(x)          ( (((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
 
 
 /*
+ * Macros to test for address type.
+ */
+#define IS_AMO_ADDRESS(x)	(((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_BASE)
+#define IS_AMO_PHYS_ADDRESS(x)	(((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_PHYS_BASE)
+
+
+/*
  * The following definitions pertain to the IO special address
  * space.  They define the location of the big and little windows
  * of any given node.
@@ -167,7 +177,10 @@
 #define TIO_BWIN_SIZE_BITS		30	/* big window size: 1G */
 #define NODE_SWIN_BASE(n, w)		((w == 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \
 		: RAW_NODE_SWIN_BASE(n, w))
+#define TIO_SWIN_BASE(n, w) 		(TIO_IO_BASE(n) + \
+					    ((u64) (w) << TIO_SWIN_SIZE_BITS))
 #define NODE_IO_BASE(n)			(GLOBAL_MMR_SPACE | NASID_SPACE(n))
+#define TIO_IO_BASE(n)                  (UNCACHED | NASID_SPACE(n))
 #define BWIN_SIZE			(1UL << BWIN_SIZE_BITS)
 #define NODE_BWIN_BASE0(n)		(NODE_IO_BASE(n) + BWIN_SIZE)
 #define NODE_BWIN_BASE(n, w)		(NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS))
diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h
--- a/include/asm-ia64/sn/arch.h
+++ b/include/asm-ia64/sn/arch.h
@@ -5,17 +5,41 @@
  *
  * SGI specific setup.
  *
- * Copyright (C) 1995-1997,1999,2001-2004 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (C) 1995-1997,1999,2001-2005 Silicon Graphics, Inc.  All rights reserved.
  * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
  */
 #ifndef _ASM_IA64_SN_ARCH_H
 #define _ASM_IA64_SN_ARCH_H
 
 #include <asm/types.h>
+#include <asm/percpu.h>
 #include <asm/sn/types.h>
 #include <asm/sn/sn_cpuid.h>
 
 /*
+ * The following defines attributes of the HUB chip. These attributes are
+ * frequently referenced. They are kept in the per-cpu data areas of each cpu.
+ * They are kept together in a struct to minimize cache misses.
+ */
+struct sn_hub_info_s {
+	u8 shub2;
+	u8 nasid_shift;
+	u8 as_shift;
+	u8 shub_1_1_found;
+	u16 nasid_bitmask;
+};
+DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
+#define sn_hub_info 	(&__get_cpu_var(__sn_hub_info))
+#define is_shub2()	(sn_hub_info->shub2)
+#define is_shub1()	(sn_hub_info->shub2 == 0)
+
+/*
+ * Use this macro to test if shub 1.1 wars should be enabled
+ */
+#define enable_shub_wars_1_1()	(sn_hub_info->shub_1_1_found)
+
+
+/*
  * This is the maximum number of nodes that can be part of a kernel.
  * Effectively, it's the maximum number of compact node ids (cnodeid_t).
  * This is not necessarily the same as MAX_NASIDS.
@@ -23,6 +47,21 @@
 #define MAX_COMPACT_NODES	2048
 #define CPUS_PER_NODE		4
 
+
+/*
+ * Compact node ID to nasid mappings kept in the per-cpu data areas of each
+ * cpu.
+ */
+DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_NUMNODES]);
+#define sn_cnodeid_to_nasid	(&__get_cpu_var(__sn_cnodeid_to_nasid[0]))
+
+
+
+extern u8 sn_partition_id;
+extern u8 sn_system_size;
+extern u8 sn_sharing_domain_size;
+extern u8 sn_region_size;
+
 extern void sn_flush_all_caches(long addr, long bytes);
 
 #endif /* _ASM_IA64_SN_ARCH_H */
diff --git a/include/asm-ia64/sn/bte.h b/include/asm-ia64/sn/bte.h
--- a/include/asm-ia64/sn/bte.h
+++ b/include/asm-ia64/sn/bte.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -13,8 +13,12 @@
 #include <linux/timer.h>
 #include <linux/spinlock.h>
 #include <linux/cache.h>
+#include <asm/sn/pda.h>
 #include <asm/sn/types.h>
+#include <asm/sn/shub_mmr.h>
 
+#define IBCT_NOTIFY             (0x1UL << 4)
+#define IBCT_ZFIL_MODE          (0x1UL << 0)
 
 /* #define BTE_DEBUG */
 /* #define BTE_DEBUG_VERBOSE */
@@ -39,8 +43,36 @@
 
 
 /* Define hardware */
-#define BTES_PER_NODE 2
+#define BTES_PER_NODE (is_shub2() ? 4 : 2)
+#define MAX_BTES_PER_NODE 4
 
+#define BTE2OFF_CTRL	(0)
+#define BTE2OFF_SRC	(SH2_BT_ENG_SRC_ADDR_0 - SH2_BT_ENG_CSR_0)
+#define BTE2OFF_DEST	(SH2_BT_ENG_DEST_ADDR_0 - SH2_BT_ENG_CSR_0)
+#define BTE2OFF_NOTIFY	(SH2_BT_ENG_NOTIF_ADDR_0 - SH2_BT_ENG_CSR_0)
+
+#define BTE_BASE_ADDR(interface) 				\
+    (is_shub2() ? (interface == 0) ? SH2_BT_ENG_CSR_0 :		\
+		  (interface == 1) ? SH2_BT_ENG_CSR_1 :		\
+		  (interface == 2) ? SH2_BT_ENG_CSR_2 :		\
+		  		     SH2_BT_ENG_CSR_3 		\
+		: (interface == 0) ? IIO_IBLS0 : IIO_IBLS1)
+
+#define BTE_SOURCE_ADDR(base)					\
+    (is_shub2() ? base + (BTE2OFF_SRC/8) 			\
+		: base + (BTEOFF_SRC/8))
+
+#define BTE_DEST_ADDR(base)					\
+    (is_shub2() ? base + (BTE2OFF_DEST/8) 			\
+		: base + (BTEOFF_DEST/8))
+
+#define BTE_CTRL_ADDR(base)					\
+    (is_shub2() ? base + (BTE2OFF_CTRL/8) 			\
+		: base + (BTEOFF_CTRL/8))
+
+#define BTE_NOTIF_ADDR(base)					\
+    (is_shub2() ? base + (BTE2OFF_NOTIFY/8) 			\
+		: base + (BTEOFF_NOTIFY/8))
 
 /* Define hardware modes */
 #define BTE_NOTIFY (IBCT_NOTIFY)
@@ -68,14 +100,18 @@
 #define BTE_LNSTAT_STORE(_bte, _x)					\
 			HUB_S(_bte->bte_base_addr, (_x))
 #define BTE_SRC_STORE(_bte, _x)						\
-			HUB_S(_bte->bte_base_addr + (BTEOFF_SRC/8), (_x))
+			HUB_S(_bte->bte_source_addr, (_x))
 #define BTE_DEST_STORE(_bte, _x)					\
-			HUB_S(_bte->bte_base_addr + (BTEOFF_DEST/8), (_x))
+			HUB_S(_bte->bte_destination_addr, (_x))
 #define BTE_CTRL_STORE(_bte, _x)					\
-			HUB_S(_bte->bte_base_addr + (BTEOFF_CTRL/8), (_x))
+			HUB_S(_bte->bte_control_addr, (_x))
 #define BTE_NOTIF_STORE(_bte, _x)					\
-			HUB_S(_bte->bte_base_addr + (BTEOFF_NOTIFY/8), (_x))
+			HUB_S(_bte->bte_notify_addr, (_x))
 
+#define BTE_START_TRANSFER(_bte, _len, _mode)				\
+	is_shub2() ? BTE_CTRL_STORE(_bte, IBLS_BUSY | (_mode << 24) | _len) \
+		: BTE_LNSTAT_STORE(_bte, _len);				\
+		  BTE_CTRL_STORE(_bte, _mode)
 
 /* Possible results from bte_copy and bte_unaligned_copy */
 /* The following error codes map into the BTE hardware codes
@@ -110,6 +146,10 @@ typedef enum {
 struct bteinfo_s {
 	volatile u64 notify ____cacheline_aligned;
 	u64 *bte_base_addr ____cacheline_aligned;
+	u64 *bte_source_addr;
+	u64 *bte_destination_addr;
+	u64 *bte_control_addr;
+	u64 *bte_notify_addr;
 	spinlock_t spinlock;
 	cnodeid_t bte_cnode;	/* cnode                            */
 	int bte_error_count;	/* Number of errors encountered     */
@@ -117,6 +157,7 @@ struct bteinfo_s {
 	int cleanup_active;	/* Interface is locked for cleanup  */
 	volatile bte_result_t bh_error;	/* error while processing   */
 	volatile u64 *most_rcnt_na;
+	struct bteinfo_s *btes_to_try[MAX_BTES_PER_NODE];
 };
 
 
diff --git a/include/asm-ia64/sn/fetchop.h b/include/asm-ia64/sn/fetchop.h
deleted file mode 100644
--- a/include/asm-ia64/sn/fetchop.h
+++ /dev/null
@@ -1,85 +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-2004 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_FETCHOP_H
-#define _ASM_IA64_SN_FETCHOP_H
-
-#include <linux/config.h>
-
-#define FETCHOP_BASENAME	"sgi_fetchop"
-#define FETCHOP_FULLNAME	"/dev/sgi_fetchop"
-
-
-
-#define FETCHOP_VAR_SIZE 64 /* 64 byte per fetchop variable */
-
-#define FETCHOP_LOAD		0
-#define FETCHOP_INCREMENT	8
-#define FETCHOP_DECREMENT	16
-#define FETCHOP_CLEAR		24
-
-#define FETCHOP_STORE		0
-#define FETCHOP_AND		24
-#define FETCHOP_OR		32
-
-#define FETCHOP_CLEAR_CACHE	56
-
-#define FETCHOP_LOAD_OP(addr, op) ( \
-         *(volatile long *)((char*) (addr) + (op)))
-
-#define FETCHOP_STORE_OP(addr, op, x) ( \
-         *(volatile long *)((char*) (addr) + (op)) = (long) (x))
-
-#ifdef __KERNEL__
-
-/*
- * Convert a region 6 (kaddr) address to the address of the fetchop variable
- */
-#define FETCHOP_KADDR_TO_MSPEC_ADDR(kaddr)	TO_MSPEC(kaddr)
-
-
-/*
- * Each Atomic Memory Operation (AMO formerly known as fetchop)
- * variable is 64 bytes long.  The first 8 bytes are used.  The
- * remaining 56 bytes are unaddressable due to the operation taking
- * that portion of the address.
- * 
- * NOTE: The AMO_t _MUST_ be placed in either the first or second half
- * of the cache line.  The cache line _MUST NOT_ be used for anything
- * other than additional AMO_t entries.  This is because there are two
- * addresses which reference the same physical cache line.  One will
- * be a cached entry with the memory type bits all set.  This address
- * may be loaded into processor cache.  The AMO_t will be referenced
- * uncached via the memory special memory type.  If any portion of the
- * cached cache-line is modified, when that line is flushed, it will
- * overwrite the uncached value in physical memory and lead to
- * inconsistency.
- */
-typedef struct {
-        u64 variable;
-        u64 unused[7];
-} AMO_t;
-
-
-/*
- * The following APIs are externalized to the kernel to allocate/free pages of
- * fetchop variables.
- *	fetchop_kalloc_page	- Allocate/initialize 1 fetchop page on the
- *				  specified cnode. 
- *	fetchop_kfree_page	- Free a previously allocated fetchop page
- */
-
-unsigned long fetchop_kalloc_page(int nid);
-void fetchop_kfree_page(unsigned long maddr);
-
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_IA64_SN_FETCHOP_H */
-
diff --git a/include/asm-ia64/sn/geo.h b/include/asm-ia64/sn/geo.h
--- a/include/asm-ia64/sn/geo.h
+++ b/include/asm-ia64/sn/geo.h
@@ -18,32 +18,34 @@
 #define GEOID_SIZE	8	/* Would 16 be better?  The size can
 				   be different on different platforms. */
 
-#define MAX_SLABS	0xe	/* slabs per module */
+#define MAX_SLOTS	0xf	/* slots per module */
+#define MAX_SLABS	0xf	/* slabs per slot */
 
 typedef unsigned char	geo_type_t;
 
 /* Fields common to all substructures */
-typedef struct geo_any_s {
+typedef struct geo_common_s {
     moduleid_t	module;		/* The module (box) this h/w lives in */
     geo_type_t	type;		/* What type of h/w is named by this geoid_t */
-    slabid_t	slab;		/* The logical assembly within the module */
-} geo_any_t;
+    slabid_t	slab:4;		/* slab (ASIC), 0 .. 15 within slot */
+    slotid_t	slot:4;		/* slot (Blade), 0 .. 15 within module */
+} geo_common_t;
 
 /* Additional fields for particular types of hardware */
 typedef struct geo_node_s {
-    geo_any_t	any;		/* No additional fields needed */
+    geo_common_t	common;		/* No additional fields needed */
 } geo_node_t;
 
 typedef struct geo_rtr_s {
-    geo_any_t	any;		/* No additional fields needed */
+    geo_common_t	common;		/* No additional fields needed */
 } geo_rtr_t;
 
 typedef struct geo_iocntl_s {
-    geo_any_t	any;		/* No additional fields needed */
+    geo_common_t	common;		/* No additional fields needed */
 } geo_iocntl_t;
 
 typedef struct geo_pcicard_s {
-    geo_iocntl_t	any;
+    geo_iocntl_t	common;
     char		bus;	/* Bus/widget number */
     char		slot;	/* PCI slot number */
 } geo_pcicard_t;
@@ -62,14 +64,14 @@ typedef struct geo_mem_s {
 
 
 typedef union geoid_u {
-    geo_any_t	any;
-    geo_node_t	node;
+    geo_common_t	common;
+    geo_node_t		node;
     geo_iocntl_t	iocntl;
     geo_pcicard_t	pcicard;
-    geo_rtr_t	rtr;
-    geo_cpu_t	cpu;
-    geo_mem_t	mem;
-    char	padsize[GEOID_SIZE];
+    geo_rtr_t		rtr;
+    geo_cpu_t		cpu;
+    geo_mem_t		mem;
+    char		padsize[GEOID_SIZE];
 } geoid_t;
 
 
@@ -104,19 +106,26 @@ typedef union geoid_u {
 #define INVALID_CNODEID         ((cnodeid_t)-1)
 #define INVALID_PNODEID         ((pnodeid_t)-1)
 #define INVALID_SLAB            (slabid_t)-1
+#define INVALID_SLOT            (slotid_t)-1
 #define INVALID_MODULE          ((moduleid_t)-1)
 #define INVALID_PARTID          ((partid_t)-1)
 
 static inline slabid_t geo_slab(geoid_t g)
 {
-	return (g.any.type == GEO_TYPE_INVALID) ?
-		INVALID_SLAB : g.any.slab;
+	return (g.common.type == GEO_TYPE_INVALID) ?
+		INVALID_SLAB : g.common.slab;
+}
+
+static inline slotid_t geo_slot(geoid_t g)
+{
+	return (g.common.type == GEO_TYPE_INVALID) ?
+		INVALID_SLOT : g.common.slot;
 }
 
 static inline moduleid_t geo_module(geoid_t g)
 {
-	return (g.any.type == GEO_TYPE_INVALID) ?
-		INVALID_MODULE : g.any.module;
+	return (g.common.type == GEO_TYPE_INVALID) ?
+		INVALID_MODULE : g.common.module;
 }
 
 extern geoid_t cnodeid_get_geoid(cnodeid_t cnode);
diff --git a/include/asm-ia64/sn/l1.h b/include/asm-ia64/sn/l1.h
--- a/include/asm-ia64/sn/l1.h
+++ b/include/asm-ia64/sn/l1.h
@@ -29,8 +29,9 @@
 #define L1_BRICKTYPE_CHI_CG     0x76            /* v */
 #define L1_BRICKTYPE_X          0x78            /* x */
 #define L1_BRICKTYPE_X2         0x79            /* y */
-#define L1_BRICKTYPE_SA		0x5e            /* ^ */ /* TIO bringup brick */
+#define L1_BRICKTYPE_SA		0x5e            /* ^ */
 #define L1_BRICKTYPE_PA		0x6a            /* j */
 #define L1_BRICKTYPE_IA		0x6b            /* k */
+#define L1_BRICKTYPE_ATHENA	0x2b            /* + */
 
 #endif /* _ASM_IA64_SN_L1_H */
diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h
--- a/include/asm-ia64/sn/nodepda.h
+++ b/include/asm-ia64/sn/nodepda.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_NODEPDA_H
 #define _ASM_IA64_SN_NODEPDA_H
@@ -13,7 +13,6 @@
 #include <asm/irq.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/intr.h>
-#include <asm/sn/pda.h>
 #include <asm/sn/bte.h>
 
 /*
@@ -43,7 +42,7 @@ struct nodepda_s {
 	/*
 	 * The BTEs on this node are shared by the local cpus
 	 */
-	struct bteinfo_s	bte_if[BTES_PER_NODE];	/* Virtual Interface */
+	struct bteinfo_s	bte_if[MAX_BTES_PER_NODE];	/* Virtual Interface */
 	struct timer_list	bte_recovery_timer;
 	spinlock_t		bte_recovery_lock;
 
@@ -67,20 +66,18 @@ typedef struct nodepda_s nodepda_t;
  * The next set of definitions provides this.
  * Routines are expected to use 
  *
- *	nodepda			-> to access node PDA for the node on which code is running
- *	subnodepda		-> to access subnode PDA for the subnode on which code is running
- *
- *	NODEPDA(cnode)		-> to access node PDA for cnodeid 
- *	SUBNODEPDA(cnode,sn)	-> to access subnode PDA for cnodeid/subnode
+ *	sn_nodepda   - to access node PDA for the node on which code is running
+ *	NODEPDA(cnodeid)   - to access node PDA for cnodeid
  */
 
-#define	nodepda		pda->p_nodepda		/* Ptr to this node's PDA */
-#define	NODEPDA(cnode)		(nodepda->pernode_pdaindr[cnode])
+DECLARE_PER_CPU(struct nodepda_s *, __sn_nodepda);
+#define sn_nodepda		(__get_cpu_var(__sn_nodepda))
+#define	NODEPDA(cnodeid)	(sn_nodepda->pernode_pdaindr[cnodeid])
 
 /*
  * Check if given a compact node id the corresponding node has all the
  * cpus disabled. 
  */
-#define is_headless_node(cnode)		(nr_cpus_node(cnode) == 0)
+#define is_headless_node(cnodeid)	(nr_cpus_node(cnodeid) == 0)
 
 #endif /* _ASM_IA64_SN_NODEPDA_H */
diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/pcibus_provider_defs.h
@@ -0,0 +1,52 @@
+/*
+ * 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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+
+/*
+ * SN pci asic types.  Do not ever renumber these or reuse values.  The
+ * values must agree with what prom thinks they are.
+ */
+
+#define PCIIO_ASIC_TYPE_UNKNOWN	0
+#define PCIIO_ASIC_TYPE_PPB	1
+#define PCIIO_ASIC_TYPE_PIC	2
+#define PCIIO_ASIC_TYPE_TIOCP	3
+#define PCIIO_ASIC_TYPE_TIOCA	4
+
+#define PCIIO_ASIC_MAX_TYPES	5
+
+/*
+ * Common pciio bus provider data.  There should be one of these as the
+ * first field in any pciio based provider soft structure (e.g. pcibr_soft
+ * tioca_soft, etc).
+ */
+
+struct pcibus_bussoft {
+	uint32_t		bs_asic_type;	/* chipset type */
+	uint32_t		bs_xid;		/* xwidget id */
+	uint64_t		bs_persist_busnum; /* Persistent Bus Number */
+	uint64_t		bs_legacy_io;	/* legacy io pio addr */
+	uint64_t		bs_legacy_mem;	/* legacy mem pio addr */
+	uint64_t		bs_base;	/* widget base */
+	struct xwidget_info	*bs_xwidget_info;
+};
+
+/*
+ * SN pci bus indirection
+ */
+
+struct sn_pcibus_provider {
+	dma_addr_t	(*dma_map)(struct pci_dev *, unsigned long, size_t);
+	dma_addr_t	(*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
+	void		(*dma_unmap)(struct pci_dev *, dma_addr_t, int);
+	void *		(*bus_fixup)(struct pcibus_bussoft *);
+};
+
+extern struct sn_pcibus_provider *sn_pci_provider[];
+#endif				/* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/pcidev.h
@@ -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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PCIDEV_H
+#define _ASM_IA64_SN_PCI_PCIDEV_H
+
+#include <linux/pci.h>
+
+extern struct sn_irq_info **sn_irq;
+
+#define SN_PCIDEV_INFO(pci_dev) \
+        ((struct pcidev_info *)(pci_dev)->sysdata)
+
+/*
+ * Given a pci_bus, return the sn pcibus_bussoft struct.  Note that
+ * this only works for root busses, not for busses represented by PPB's.
+ */
+
+#define SN_PCIBUS_BUSSOFT(pci_bus) \
+        ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
+
+/*
+ * Given a struct pci_dev, return the sn pcibus_bussoft struct.  Note
+ * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
+ * due to possible PPB's in the path.
+ */
+
+#define SN_PCIDEV_BUSSOFT(pci_dev) \
+	(SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info)
+
+#define SN_PCIDEV_BUSPROVIDER(pci_dev) \
+	(SN_PCIDEV_INFO(pci_dev)->pdi_provider)
+
+#define PCIIO_BUS_NONE	255      /* bus 255 reserved */
+#define PCIIO_SLOT_NONE 255
+#define PCIIO_FUNC_NONE 255
+#define PCIIO_VENDOR_ID_NONE	(-1)
+
+struct pcidev_info {
+	uint64_t		pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */
+	uint64_t		pdi_slot_host_handle;	/* Bus and devfn Host pci_dev */
+
+	struct pcibus_bussoft	*pdi_pcibus_info;	/* Kernel common bus soft */
+	struct pcidev_info	*pdi_host_pcidev_info;	/* Kernel Host pci_dev */
+	struct pci_dev		*pdi_linux_pcidev;	/* Kernel pci_dev */
+
+	struct sn_irq_info	*pdi_sn_irq_info;
+	struct sn_pcibus_provider *pdi_provider;	/* sn pci ops */
+};
+
+extern void sn_irq_fixup(struct pci_dev *pci_dev,
+			 struct sn_irq_info *sn_irq_info);
+
+#endif				/* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h
--- a/include/asm-ia64/sn/pda.h
+++ b/include/asm-ia64/sn/pda.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_PDA_H
 #define _ASM_IA64_SN_PDA_H
@@ -11,7 +11,6 @@
 #include <linux/cache.h>
 #include <asm/percpu.h>
 #include <asm/system.h>
-#include <asm/sn/bte.h>
 
 
 /*
@@ -25,23 +24,10 @@
 
 typedef struct pda_s {
 
-	/* Having a pointer in the begining of PDA tends to increase
-	 * the chance of having this pointer in cache. (Yes something
-	 * else gets pushed out). Doing this reduces the number of memory
-	 * access to all nodepda variables to be one
-	 */
-	struct nodepda_s *p_nodepda;		/* Pointer to Per node PDA */
-	struct subnodepda_s *p_subnodepda;	/* Pointer to CPU  subnode PDA */
-
 	/*
 	 * Support for SN LEDs
 	 */
 	volatile short	*led_address;
-	u16		nasid_bitmask;
-	u8		shub2;
-	u8		nasid_shift;
-	u8		as_shift;
-	u8		shub_1_1_found;
 	u8		led_state;
 	u8		hb_state;	/* supports blinking heartbeat leds */
 	unsigned int	hb_count;
@@ -53,11 +39,8 @@ typedef struct pda_s {
 	unsigned long pio_write_status_val;
 	volatile unsigned long *pio_shub_war_cam_addr;
 
-	struct bteinfo_s *cpu_bte_if[BTES_PER_NODE];	/* cpu interface order */
-
 	unsigned long	sn_soft_irr[4];
 	unsigned long	sn_in_service_ivecs[4];
-	short		cnodeid_to_nasid_table[MAX_NUMNODES];
 	int		sn_lb_int_war_ticks;
 	int		sn_last_irq;
 	int		sn_first_irq;
@@ -84,12 +67,4 @@ DECLARE_PER_CPU(struct pda_s, pda_percpu
 
 #define pdacpu(cpu)	(&per_cpu(pda_percpu, cpu))
 
-/*
- * Use this macro to test if shub 1.1 wars should be enabled
- */
-#define enable_shub_wars_1_1()	(pda->shub_1_1_found)
-
-#define is_shub2()	(pda->shub2)
-#define is_shub1()	(pda->shub2 == 0)
-
 #endif /* _ASM_IA64_SN_PDA_H */
diff --git a/include/asm-ia64/sn/shub_mmr.h b/include/asm-ia64/sn/shub_mmr.h
--- a/include/asm-ia64/sn/shub_mmr.h
+++ b/include/asm-ia64/sn/shub_mmr.h
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001-2004 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2005 Silicon Graphics, Inc.  All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SHUB_MMR_H
@@ -129,6 +129,23 @@
 #define SH_EVENT_OCCURRED_II_INT1_SHFT           30
 #define SH_EVENT_OCCURRED_II_INT1_MASK           0x0000000040000000
 
+/*   SH2_EVENT_OCCURRED_EXTIO_INT2                                      */
+/*   Description:  Pending SHUB 2 EXT IO INT2                           */
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT       33
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK       0x0000000200000000
+
+/*   SH2_EVENT_OCCURRED_EXTIO_INT3                                      */
+/*   Description:  Pending SHUB 2 EXT IO INT3                           */
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT       34
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK       0x0000000400000000
+
+#define SH_ALL_INT_MASK \
+	(SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \
+	 SH_EVENT_OCCURRED_II_INT0_MASK | SH_EVENT_OCCURRED_II_INT1_MASK | \
+	 SH_EVENT_OCCURRED_II_INT1_MASK | SH2_EVENT_OCCURRED_EXTIO_INT2_MASK | \
+	 SH2_EVENT_OCCURRED_EXTIO_INT3_MASK)
+
+
 /* ==================================================================== */
 /*                         LEDS                                         */
 /* ==================================================================== */
@@ -368,6 +385,17 @@
 #define SH_EVENT_OCCURRED_RTC3_INT_MASK          0x0000000004000000
 
 /* ==================================================================== */
+/*                       Register "SH_IPI_ACCESS"                       */
+/*                 CPU interrupt Access Permission Bits                 */
+/* ==================================================================== */
+
+#define SH1_IPI_ACCESS                           0x0000000110060480
+#define SH2_IPI_ACCESS0                          0x0000000010060c00
+#define SH2_IPI_ACCESS1                          0x0000000010060c80
+#define SH2_IPI_ACCESS2                          0x0000000010060d00
+#define SH2_IPI_ACCESS3                          0x0000000010060d80
+
+/* ==================================================================== */
 /*                        Register "SH_INT_CMPB"                        */
 /*                  RTC Compare Value for Processor B                   */
 /* ==================================================================== */
@@ -412,6 +440,19 @@
 #define SH_INT_CMPD_REAL_TIME_CMPD_SHFT          0
 #define SH_INT_CMPD_REAL_TIME_CMPD_MASK          0x007fffffffffffff
 
+/* ==================================================================== */
+/*                Register "SH_MD_DQLP_MMR_DIR_PRIVEC0"                 */
+/*                      privilege vector for acc=0                      */
+/* ==================================================================== */
+
+#define SH1_MD_DQLP_MMR_DIR_PRIVEC0              0x0000000100030300
+
+/* ==================================================================== */
+/*                Register "SH_MD_DQRP_MMR_DIR_PRIVEC0"                 */
+/*                      privilege vector for acc=0                      */
+/* ==================================================================== */
+
+#define SH1_MD_DQRP_MMR_DIR_PRIVEC0              0x0000000100050300
 
 /* ==================================================================== */
 /* Some MMRs are functionally identical (or close enough) on both SHUB1 */
@@ -438,4 +479,22 @@
 #define SH_INT_CMPC		shubmmr(SH, INT_CMPC)
 #define SH_INT_CMPD		shubmmr(SH, INT_CMPD)
 
+/* ========================================================================== */
+/*                        Register "SH2_BT_ENG_CSR_0"                         */
+/*                    Engine 0 Control and Status Register                    */
+/* ========================================================================== */
+
+#define SH2_BT_ENG_CSR_0                         0x0000000030040000
+#define SH2_BT_ENG_SRC_ADDR_0                    0x0000000030040080
+#define SH2_BT_ENG_DEST_ADDR_0                   0x0000000030040100
+#define SH2_BT_ENG_NOTIF_ADDR_0                  0x0000000030040180
+
+/* ========================================================================== */
+/*                       BTE interfaces 1-3                                   */
+/* ========================================================================== */
+
+#define SH2_BT_ENG_CSR_1                         0x0000000030050000
+#define SH2_BT_ENG_CSR_2                         0x0000000030060000
+#define SH2_BT_ENG_CSR_3                         0x0000000030070000
+
 #endif /* _ASM_IA64_SN_SHUB_MMR_H */
diff --git a/include/asm-ia64/sn/shubio.h b/include/asm-ia64/sn/shubio.h
--- a/include/asm-ia64/sn/shubio.h
+++ b/include/asm-ia64/sn/shubio.h
@@ -3,292 +3,287 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SHUBIO_H
 #define _ASM_IA64_SN_SHUBIO_H
 
-#define HUB_WIDGET_ID_MAX 0xf
-#define IIO_NUM_ITTES   7
-#define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
-
-#define    IIO_WID                   0x00400000    /* Crosstalk Widget Identification */
-                                                   /* This register is also accessible from
-                                                    * Crosstalk at address 0x0.  */
-#define    IIO_WSTAT                 0x00400008    /* Crosstalk Widget Status */
-#define    IIO_WCR                   0x00400020    /* Crosstalk Widget Control Register */
-#define    IIO_ILAPR                 0x00400100    /* IO Local Access Protection Register */
-#define    IIO_ILAPO                 0x00400108    /* IO Local Access Protection Override */
-#define    IIO_IOWA                  0x00400110    /* IO Outbound Widget Access */
-#define    IIO_IIWA                  0x00400118    /* IO Inbound Widget Access */
-#define    IIO_IIDEM                 0x00400120    /* IO Inbound Device Error Mask */
-#define    IIO_ILCSR                 0x00400128    /* IO LLP Control and Status Register */
-#define    IIO_ILLR                  0x00400130    /* IO LLP Log Register    */
-#define    IIO_IIDSR                 0x00400138    /* IO Interrupt Destination */
-
-#define    IIO_IGFX0                 0x00400140    /* IO Graphics Node-Widget Map 0 */
-#define    IIO_IGFX1                 0x00400148    /* IO Graphics Node-Widget Map 1 */
-
-#define    IIO_ISCR0                 0x00400150    /* IO Scratch Register 0 */
-#define    IIO_ISCR1                 0x00400158    /* IO Scratch Register 1 */
-
-#define    IIO_ITTE1                 0x00400160    /* IO Translation Table Entry 1 */
-#define    IIO_ITTE2                 0x00400168    /* IO Translation Table Entry 2 */
-#define    IIO_ITTE3                 0x00400170    /* IO Translation Table Entry 3 */
-#define    IIO_ITTE4                 0x00400178    /* IO Translation Table Entry 4 */
-#define    IIO_ITTE5                 0x00400180    /* IO Translation Table Entry 5 */
-#define    IIO_ITTE6                 0x00400188    /* IO Translation Table Entry 6 */
-#define    IIO_ITTE7                 0x00400190    /* IO Translation Table Entry 7 */
-
-#define    IIO_IPRB0                 0x00400198    /* IO PRB Entry 0         */
-#define    IIO_IPRB8                 0x004001A0    /* IO PRB Entry 8         */
-#define    IIO_IPRB9                 0x004001A8    /* IO PRB Entry 9         */
-#define    IIO_IPRBA                 0x004001B0    /* IO PRB Entry A         */
-#define    IIO_IPRBB                 0x004001B8    /* IO PRB Entry B         */
-#define    IIO_IPRBC                 0x004001C0    /* IO PRB Entry C         */
-#define    IIO_IPRBD                 0x004001C8    /* IO PRB Entry D         */
-#define    IIO_IPRBE                 0x004001D0    /* IO PRB Entry E         */
-#define    IIO_IPRBF                 0x004001D8    /* IO PRB Entry F         */
-
-#define    IIO_IXCC                  0x004001E0    /* IO Crosstalk Credit Count Timeout */
-#define    IIO_IMEM                  0x004001E8    /* IO Miscellaneous Error Mask */
-#define    IIO_IXTT                  0x004001F0    /* IO Crosstalk Timeout Threshold */
-#define    IIO_IECLR                 0x004001F8    /* IO Error Clear Register */
-#define    IIO_IBCR                  0x00400200    /* IO BTE Control Register */
-
-#define    IIO_IXSM                  0x00400208    /* IO Crosstalk Spurious Message */
-#define    IIO_IXSS                  0x00400210    /* IO Crosstalk Spurious Sideband */
-
-#define    IIO_ILCT                  0x00400218    /* IO LLP Channel Test    */
-
-#define    IIO_IIEPH1                0x00400220    /* IO Incoming Error Packet Header, Part 1 */
-#define    IIO_IIEPH2                0x00400228    /* IO Incoming Error Packet Header, Part 2 */
-
-
-#define    IIO_ISLAPR                0x00400230    /* IO SXB Local Access Protection Regster */
-#define    IIO_ISLAPO                0x00400238    /* IO SXB Local Access Protection Override */
-
-#define    IIO_IWI                   0x00400240    /* IO Wrapper Interrupt Register */
-#define    IIO_IWEL                  0x00400248    /* IO Wrapper Error Log Register */
-#define    IIO_IWC                   0x00400250    /* IO Wrapper Control Register */
-#define    IIO_IWS                   0x00400258    /* IO Wrapper Status Register */
-#define    IIO_IWEIM                 0x00400260    /* IO Wrapper Error Interrupt Masking Register */
-
-#define    IIO_IPCA                  0x00400300    /* IO PRB Counter Adjust */
-
-#define    IIO_IPRTE0_A              0x00400308    /* IO PIO Read Address Table Entry 0, Part A */
-#define    IIO_IPRTE1_A              0x00400310    /* IO PIO Read Address Table Entry 1, Part A */
-#define    IIO_IPRTE2_A              0x00400318    /* IO PIO Read Address Table Entry 2, Part A */
-#define    IIO_IPRTE3_A               0x00400320    /* IO PIO Read Address Table Entry 3, Part A */
-#define    IIO_IPRTE4_A               0x00400328    /* IO PIO Read Address Table Entry 4, Part A */
-#define    IIO_IPRTE5_A               0x00400330    /* IO PIO Read Address Table Entry 5, Part A */
-#define    IIO_IPRTE6_A               0x00400338    /* IO PIO Read Address Table Entry 6, Part A */
-#define    IIO_IPRTE7_A               0x00400340    /* IO PIO Read Address Table Entry 7, Part A */
-
-#define    IIO_IPRTE0_B              0x00400348    /* IO PIO Read Address Table Entry 0, Part B */
-#define    IIO_IPRTE1_B              0x00400350    /* IO PIO Read Address Table Entry 1, Part B */
-#define    IIO_IPRTE2_B              0x00400358    /* IO PIO Read Address Table Entry 2, Part B */
-#define    IIO_IPRTE3_B               0x00400360    /* IO PIO Read Address Table Entry 3, Part B */
-#define    IIO_IPRTE4_B               0x00400368    /* IO PIO Read Address Table Entry 4, Part B */
-#define    IIO_IPRTE5_B               0x00400370    /* IO PIO Read Address Table Entry 5, Part B */
-#define    IIO_IPRTE6_B               0x00400378    /* IO PIO Read Address Table Entry 6, Part B */
-#define    IIO_IPRTE7_B               0x00400380    /* IO PIO Read Address Table Entry 7, Part B */
-
-#define    IIO_IPDR                  0x00400388    /* IO PIO Deallocation Register */
-#define    IIO_ICDR                  0x00400390    /* IO CRB Entry Deallocation Register */
-#define    IIO_IFDR                  0x00400398    /* IO IOQ FIFO Depth Register */
-#define    IIO_IIAP                  0x004003A0    /* IO IIQ Arbitration Parameters */
-#define    IIO_ICMR                  0x004003A8    /* IO CRB Management Register */
-#define    IIO_ICCR                  0x004003B0    /* IO CRB Control Register */
-#define    IIO_ICTO                  0x004003B8    /* IO CRB Timeout         */
-#define    IIO_ICTP                  0x004003C0    /* IO CRB Timeout Prescalar */
-
-#define    IIO_ICRB0_A               0x00400400    /* IO CRB Entry 0_A       */
-#define    IIO_ICRB0_B               0x00400408    /* IO CRB Entry 0_B       */
-#define    IIO_ICRB0_C               0x00400410    /* IO CRB Entry 0_C       */
-#define    IIO_ICRB0_D               0x00400418    /* IO CRB Entry 0_D       */
-#define    IIO_ICRB0_E               0x00400420    /* IO CRB Entry 0_E       */
-
-#define    IIO_ICRB1_A               0x00400430    /* IO CRB Entry 1_A       */
-#define    IIO_ICRB1_B               0x00400438    /* IO CRB Entry 1_B       */
-#define    IIO_ICRB1_C               0x00400440    /* IO CRB Entry 1_C       */
-#define    IIO_ICRB1_D               0x00400448    /* IO CRB Entry 1_D       */
-#define    IIO_ICRB1_E               0x00400450    /* IO CRB Entry 1_E       */
-
-#define    IIO_ICRB2_A               0x00400460    /* IO CRB Entry 2_A       */
-#define    IIO_ICRB2_B               0x00400468    /* IO CRB Entry 2_B       */
-#define    IIO_ICRB2_C               0x00400470    /* IO CRB Entry 2_C       */
-#define    IIO_ICRB2_D               0x00400478    /* IO CRB Entry 2_D       */
-#define    IIO_ICRB2_E               0x00400480    /* IO CRB Entry 2_E       */
-
-#define    IIO_ICRB3_A               0x00400490    /* IO CRB Entry 3_A       */
-#define    IIO_ICRB3_B               0x00400498    /* IO CRB Entry 3_B       */
-#define    IIO_ICRB3_C               0x004004a0    /* IO CRB Entry 3_C       */
-#define    IIO_ICRB3_D               0x004004a8    /* IO CRB Entry 3_D       */
-#define    IIO_ICRB3_E               0x004004b0    /* IO CRB Entry 3_E       */
-
-#define    IIO_ICRB4_A               0x004004c0    /* IO CRB Entry 4_A       */
-#define    IIO_ICRB4_B               0x004004c8    /* IO CRB Entry 4_B       */
-#define    IIO_ICRB4_C               0x004004d0    /* IO CRB Entry 4_C       */
-#define    IIO_ICRB4_D               0x004004d8    /* IO CRB Entry 4_D       */
-#define    IIO_ICRB4_E               0x004004e0    /* IO CRB Entry 4_E       */
-
-#define    IIO_ICRB5_A               0x004004f0    /* IO CRB Entry 5_A       */
-#define    IIO_ICRB5_B               0x004004f8    /* IO CRB Entry 5_B       */
-#define    IIO_ICRB5_C               0x00400500    /* IO CRB Entry 5_C       */
-#define    IIO_ICRB5_D               0x00400508    /* IO CRB Entry 5_D       */
-#define    IIO_ICRB5_E               0x00400510    /* IO CRB Entry 5_E       */
-
-#define    IIO_ICRB6_A               0x00400520    /* IO CRB Entry 6_A       */
-#define    IIO_ICRB6_B               0x00400528    /* IO CRB Entry 6_B       */
-#define    IIO_ICRB6_C               0x00400530    /* IO CRB Entry 6_C       */
-#define    IIO_ICRB6_D               0x00400538    /* IO CRB Entry 6_D       */
-#define    IIO_ICRB6_E               0x00400540    /* IO CRB Entry 6_E       */
-
-#define    IIO_ICRB7_A               0x00400550    /* IO CRB Entry 7_A       */
-#define    IIO_ICRB7_B               0x00400558    /* IO CRB Entry 7_B       */
-#define    IIO_ICRB7_C               0x00400560    /* IO CRB Entry 7_C       */
-#define    IIO_ICRB7_D               0x00400568    /* IO CRB Entry 7_D       */
-#define    IIO_ICRB7_E               0x00400570    /* IO CRB Entry 7_E       */
-
-#define    IIO_ICRB8_A               0x00400580    /* IO CRB Entry 8_A       */
-#define    IIO_ICRB8_B               0x00400588    /* IO CRB Entry 8_B       */
-#define    IIO_ICRB8_C               0x00400590    /* IO CRB Entry 8_C       */
-#define    IIO_ICRB8_D               0x00400598    /* IO CRB Entry 8_D       */
-#define    IIO_ICRB8_E               0x004005a0    /* IO CRB Entry 8_E       */
-
-#define    IIO_ICRB9_A               0x004005b0    /* IO CRB Entry 9_A       */
-#define    IIO_ICRB9_B               0x004005b8    /* IO CRB Entry 9_B       */
-#define    IIO_ICRB9_C               0x004005c0    /* IO CRB Entry 9_C       */
-#define    IIO_ICRB9_D               0x004005c8    /* IO CRB Entry 9_D       */
-#define    IIO_ICRB9_E               0x004005d0    /* IO CRB Entry 9_E       */
-
-#define    IIO_ICRBA_A               0x004005e0    /* IO CRB Entry A_A       */
-#define    IIO_ICRBA_B               0x004005e8    /* IO CRB Entry A_B       */
-#define    IIO_ICRBA_C               0x004005f0    /* IO CRB Entry A_C       */
-#define    IIO_ICRBA_D               0x004005f8    /* IO CRB Entry A_D       */
-#define    IIO_ICRBA_E               0x00400600    /* IO CRB Entry A_E       */
-
-#define    IIO_ICRBB_A               0x00400610    /* IO CRB Entry B_A       */
-#define    IIO_ICRBB_B               0x00400618    /* IO CRB Entry B_B       */
-#define    IIO_ICRBB_C               0x00400620    /* IO CRB Entry B_C       */
-#define    IIO_ICRBB_D               0x00400628    /* IO CRB Entry B_D       */
-#define    IIO_ICRBB_E               0x00400630    /* IO CRB Entry B_E       */
-
-#define    IIO_ICRBC_A               0x00400640    /* IO CRB Entry C_A       */
-#define    IIO_ICRBC_B               0x00400648    /* IO CRB Entry C_B       */
-#define    IIO_ICRBC_C               0x00400650    /* IO CRB Entry C_C       */
-#define    IIO_ICRBC_D               0x00400658    /* IO CRB Entry C_D       */
-#define    IIO_ICRBC_E               0x00400660    /* IO CRB Entry C_E       */
-
-#define    IIO_ICRBD_A               0x00400670    /* IO CRB Entry D_A       */
-#define    IIO_ICRBD_B               0x00400678    /* IO CRB Entry D_B       */
-#define    IIO_ICRBD_C               0x00400680    /* IO CRB Entry D_C       */
-#define    IIO_ICRBD_D               0x00400688    /* IO CRB Entry D_D       */
-#define    IIO_ICRBD_E               0x00400690    /* IO CRB Entry D_E       */
-
-#define    IIO_ICRBE_A               0x004006a0    /* IO CRB Entry E_A       */
-#define    IIO_ICRBE_B               0x004006a8    /* IO CRB Entry E_B       */
-#define    IIO_ICRBE_C               0x004006b0    /* IO CRB Entry E_C       */
-#define    IIO_ICRBE_D               0x004006b8    /* IO CRB Entry E_D       */
-#define    IIO_ICRBE_E               0x004006c0    /* IO CRB Entry E_E       */
-
-#define    IIO_ICSML                 0x00400700    /* IO CRB Spurious Message Low */
-#define    IIO_ICSMM                 0x00400708    /* IO CRB Spurious Message Middle */
-#define    IIO_ICSMH                 0x00400710    /* IO CRB Spurious Message High */
-
-#define    IIO_IDBSS                 0x00400718    /* IO Debug Submenu Select */
-
-#define    IIO_IBLS0                 0x00410000    /* IO BTE Length Status 0 */
-#define    IIO_IBSA0                 0x00410008    /* IO BTE Source Address 0 */
-#define    IIO_IBDA0                 0x00410010    /* IO BTE Destination Address 0 */
-#define    IIO_IBCT0                 0x00410018    /* IO BTE Control Terminate 0 */
-#define    IIO_IBNA0                 0x00410020    /* IO BTE Notification Address 0 */
-#define    IIO_IBIA0                 0x00410028    /* IO BTE Interrupt Address 0 */
-#define    IIO_IBLS1                 0x00420000    /* IO BTE Length Status 1 */
-#define    IIO_IBSA1                 0x00420008    /* IO BTE Source Address 1 */
-#define    IIO_IBDA1                 0x00420010    /* IO BTE Destination Address 1 */
-#define    IIO_IBCT1                 0x00420018    /* IO BTE Control Terminate 1 */
-#define    IIO_IBNA1                 0x00420020    /* IO BTE Notification Address 1 */
-#define    IIO_IBIA1                 0x00420028    /* IO BTE Interrupt Address 1 */
-
-#define    IIO_IPCR                  0x00430000    /* IO Performance Control */
-#define    IIO_IPPR                  0x00430008    /* IO Performance Profiling */
+#define HUB_WIDGET_ID_MAX	0xf
+#define IIO_NUM_ITTES		7
+#define HUB_NUM_BIG_WINDOW	(IIO_NUM_ITTES - 1)
+
+#define		IIO_WID			0x00400000	/* Crosstalk Widget Identification */
+							/* This register is also accessible from
+							 * Crosstalk at address 0x0.  */
+#define		IIO_WSTAT		0x00400008	/* Crosstalk Widget Status */
+#define		IIO_WCR			0x00400020	/* Crosstalk Widget Control Register */
+#define		IIO_ILAPR		0x00400100	/* IO Local Access Protection Register */
+#define		IIO_ILAPO		0x00400108	/* IO Local Access Protection Override */
+#define		IIO_IOWA		0x00400110	/* IO Outbound Widget Access */
+#define		IIO_IIWA		0x00400118	/* IO Inbound Widget Access */
+#define		IIO_IIDEM		0x00400120	/* IO Inbound Device Error Mask */
+#define		IIO_ILCSR		0x00400128	/* IO LLP Control and Status Register */
+#define		IIO_ILLR		0x00400130	/* IO LLP Log Register    */
+#define		IIO_IIDSR		0x00400138	/* IO Interrupt Destination */
+
+#define		IIO_IGFX0		0x00400140	/* IO Graphics Node-Widget Map 0 */
+#define		IIO_IGFX1		0x00400148	/* IO Graphics Node-Widget Map 1 */
+
+#define		IIO_ISCR0		0x00400150	/* IO Scratch Register 0 */
+#define		IIO_ISCR1		0x00400158	/* IO Scratch Register 1 */
+
+#define		IIO_ITTE1		0x00400160	/* IO Translation Table Entry 1 */
+#define		IIO_ITTE2		0x00400168	/* IO Translation Table Entry 2 */
+#define		IIO_ITTE3		0x00400170	/* IO Translation Table Entry 3 */
+#define		IIO_ITTE4		0x00400178	/* IO Translation Table Entry 4 */
+#define		IIO_ITTE5		0x00400180	/* IO Translation Table Entry 5 */
+#define		IIO_ITTE6		0x00400188	/* IO Translation Table Entry 6 */
+#define		IIO_ITTE7		0x00400190	/* IO Translation Table Entry 7 */
+
+#define		IIO_IPRB0		0x00400198	/* IO PRB Entry 0   */
+#define		IIO_IPRB8		0x004001A0	/* IO PRB Entry 8   */
+#define		IIO_IPRB9		0x004001A8	/* IO PRB Entry 9   */
+#define		IIO_IPRBA		0x004001B0	/* IO PRB Entry A   */
+#define		IIO_IPRBB		0x004001B8	/* IO PRB Entry B   */
+#define		IIO_IPRBC		0x004001C0	/* IO PRB Entry C   */
+#define		IIO_IPRBD		0x004001C8	/* IO PRB Entry D   */
+#define		IIO_IPRBE		0x004001D0	/* IO PRB Entry E   */
+#define		IIO_IPRBF		0x004001D8	/* IO PRB Entry F   */
+
+#define		IIO_IXCC		0x004001E0	/* IO Crosstalk Credit Count Timeout */
+#define		IIO_IMEM		0x004001E8	/* IO Miscellaneous Error Mask */
+#define		IIO_IXTT		0x004001F0	/* IO Crosstalk Timeout Threshold */
+#define		IIO_IECLR		0x004001F8	/* IO Error Clear Register */
+#define		IIO_IBCR		0x00400200	/* IO BTE Control Register */
+
+#define		IIO_IXSM		0x00400208	/* IO Crosstalk Spurious Message */
+#define		IIO_IXSS		0x00400210	/* IO Crosstalk Spurious Sideband */
+
+#define		IIO_ILCT		0x00400218	/* IO LLP Channel Test    */
+
+#define		IIO_IIEPH1 		0x00400220	/* IO Incoming Error Packet Header, Part 1 */
+#define		IIO_IIEPH2 		0x00400228	/* IO Incoming Error Packet Header, Part 2 */
+
+#define		IIO_ISLAPR 		0x00400230	/* IO SXB Local Access Protection Regster */
+#define		IIO_ISLAPO 		0x00400238	/* IO SXB Local Access Protection Override */
+
+#define		IIO_IWI			0x00400240	/* IO Wrapper Interrupt Register */
+#define		IIO_IWEL		0x00400248	/* IO Wrapper Error Log Register */
+#define		IIO_IWC			0x00400250	/* IO Wrapper Control Register */
+#define		IIO_IWS			0x00400258	/* IO Wrapper Status Register */
+#define		IIO_IWEIM		0x00400260	/* IO Wrapper Error Interrupt Masking Register */
+
+#define		IIO_IPCA		0x00400300	/* IO PRB Counter Adjust */
+
+#define		IIO_IPRTE0_A		0x00400308	/* IO PIO Read Address Table Entry 0, Part A */
+#define		IIO_IPRTE1_A		0x00400310	/* IO PIO Read Address Table Entry 1, Part A */
+#define		IIO_IPRTE2_A		0x00400318	/* IO PIO Read Address Table Entry 2, Part A */
+#define		IIO_IPRTE3_A		0x00400320	/* IO PIO Read Address Table Entry 3, Part A */
+#define		IIO_IPRTE4_A		0x00400328	/* IO PIO Read Address Table Entry 4, Part A */
+#define		IIO_IPRTE5_A		0x00400330	/* IO PIO Read Address Table Entry 5, Part A */
+#define		IIO_IPRTE6_A		0x00400338	/* IO PIO Read Address Table Entry 6, Part A */
+#define		IIO_IPRTE7_A		0x00400340	/* IO PIO Read Address Table Entry 7, Part A */
+
+#define		IIO_IPRTE0_B		0x00400348	/* IO PIO Read Address Table Entry 0, Part B */
+#define		IIO_IPRTE1_B		0x00400350	/* IO PIO Read Address Table Entry 1, Part B */
+#define		IIO_IPRTE2_B		0x00400358	/* IO PIO Read Address Table Entry 2, Part B */
+#define		IIO_IPRTE3_B		0x00400360	/* IO PIO Read Address Table Entry 3, Part B */
+#define		IIO_IPRTE4_B		0x00400368	/* IO PIO Read Address Table Entry 4, Part B */
+#define		IIO_IPRTE5_B		0x00400370	/* IO PIO Read Address Table Entry 5, Part B */
+#define		IIO_IPRTE6_B		0x00400378	/* IO PIO Read Address Table Entry 6, Part B */
+#define		IIO_IPRTE7_B		0x00400380	/* IO PIO Read Address Table Entry 7, Part B */
+
+#define		IIO_IPDR		0x00400388	/* IO PIO Deallocation Register */
+#define		IIO_ICDR		0x00400390	/* IO CRB Entry Deallocation Register */
+#define		IIO_IFDR		0x00400398	/* IO IOQ FIFO Depth Register */
+#define		IIO_IIAP		0x004003A0	/* IO IIQ Arbitration Parameters */
+#define		IIO_ICMR		0x004003A8	/* IO CRB Management Register */
+#define		IIO_ICCR		0x004003B0	/* IO CRB Control Register */
+#define		IIO_ICTO		0x004003B8	/* IO CRB Timeout   */
+#define		IIO_ICTP		0x004003C0	/* IO CRB Timeout Prescalar */
+
+#define		IIO_ICRB0_A		0x00400400	/* IO CRB Entry 0_A */
+#define		IIO_ICRB0_B		0x00400408	/* IO CRB Entry 0_B */
+#define		IIO_ICRB0_C		0x00400410	/* IO CRB Entry 0_C */
+#define		IIO_ICRB0_D		0x00400418	/* IO CRB Entry 0_D */
+#define		IIO_ICRB0_E		0x00400420	/* IO CRB Entry 0_E */
+
+#define		IIO_ICRB1_A		0x00400430	/* IO CRB Entry 1_A */
+#define		IIO_ICRB1_B		0x00400438	/* IO CRB Entry 1_B */
+#define		IIO_ICRB1_C		0x00400440	/* IO CRB Entry 1_C */
+#define		IIO_ICRB1_D		0x00400448	/* IO CRB Entry 1_D */
+#define		IIO_ICRB1_E		0x00400450	/* IO CRB Entry 1_E */
+
+#define		IIO_ICRB2_A		0x00400460	/* IO CRB Entry 2_A */
+#define		IIO_ICRB2_B		0x00400468	/* IO CRB Entry 2_B */
+#define		IIO_ICRB2_C		0x00400470	/* IO CRB Entry 2_C */
+#define		IIO_ICRB2_D		0x00400478	/* IO CRB Entry 2_D */
+#define		IIO_ICRB2_E		0x00400480	/* IO CRB Entry 2_E */
+
+#define		IIO_ICRB3_A		0x00400490	/* IO CRB Entry 3_A */
+#define		IIO_ICRB3_B		0x00400498	/* IO CRB Entry 3_B */
+#define		IIO_ICRB3_C		0x004004a0	/* IO CRB Entry 3_C */
+#define		IIO_ICRB3_D		0x004004a8	/* IO CRB Entry 3_D */
+#define		IIO_ICRB3_E		0x004004b0	/* IO CRB Entry 3_E */
+
+#define		IIO_ICRB4_A		0x004004c0	/* IO CRB Entry 4_A */
+#define		IIO_ICRB4_B		0x004004c8	/* IO CRB Entry 4_B */
+#define		IIO_ICRB4_C		0x004004d0	/* IO CRB Entry 4_C */
+#define		IIO_ICRB4_D		0x004004d8	/* IO CRB Entry 4_D */
+#define		IIO_ICRB4_E		0x004004e0	/* IO CRB Entry 4_E */
+
+#define		IIO_ICRB5_A		0x004004f0	/* IO CRB Entry 5_A */
+#define		IIO_ICRB5_B		0x004004f8	/* IO CRB Entry 5_B */
+#define		IIO_ICRB5_C		0x00400500	/* IO CRB Entry 5_C */
+#define		IIO_ICRB5_D		0x00400508	/* IO CRB Entry 5_D */
+#define		IIO_ICRB5_E		0x00400510	/* IO CRB Entry 5_E */
+
+#define		IIO_ICRB6_A		0x00400520	/* IO CRB Entry 6_A */
+#define		IIO_ICRB6_B		0x00400528	/* IO CRB Entry 6_B */
+#define		IIO_ICRB6_C		0x00400530	/* IO CRB Entry 6_C */
+#define		IIO_ICRB6_D		0x00400538	/* IO CRB Entry 6_D */
+#define		IIO_ICRB6_E		0x00400540	/* IO CRB Entry 6_E */
+
+#define		IIO_ICRB7_A		0x00400550	/* IO CRB Entry 7_A */
+#define		IIO_ICRB7_B		0x00400558	/* IO CRB Entry 7_B */
+#define		IIO_ICRB7_C		0x00400560	/* IO CRB Entry 7_C */
+#define		IIO_ICRB7_D		0x00400568	/* IO CRB Entry 7_D */
+#define		IIO_ICRB7_E		0x00400570	/* IO CRB Entry 7_E */
+
+#define		IIO_ICRB8_A		0x00400580	/* IO CRB Entry 8_A */
+#define		IIO_ICRB8_B		0x00400588	/* IO CRB Entry 8_B */
+#define		IIO_ICRB8_C		0x00400590	/* IO CRB Entry 8_C */
+#define		IIO_ICRB8_D		0x00400598	/* IO CRB Entry 8_D */
+#define		IIO_ICRB8_E		0x004005a0	/* IO CRB Entry 8_E */
+
+#define		IIO_ICRB9_A		0x004005b0	/* IO CRB Entry 9_A */
+#define		IIO_ICRB9_B		0x004005b8	/* IO CRB Entry 9_B */
+#define		IIO_ICRB9_C		0x004005c0	/* IO CRB Entry 9_C */
+#define		IIO_ICRB9_D		0x004005c8	/* IO CRB Entry 9_D */
+#define		IIO_ICRB9_E		0x004005d0	/* IO CRB Entry 9_E */
+
+#define		IIO_ICRBA_A		0x004005e0	/* IO CRB Entry A_A */
+#define		IIO_ICRBA_B		0x004005e8	/* IO CRB Entry A_B */
+#define		IIO_ICRBA_C		0x004005f0	/* IO CRB Entry A_C */
+#define		IIO_ICRBA_D		0x004005f8	/* IO CRB Entry A_D */
+#define		IIO_ICRBA_E		0x00400600	/* IO CRB Entry A_E */
+
+#define		IIO_ICRBB_A		0x00400610	/* IO CRB Entry B_A */
+#define		IIO_ICRBB_B		0x00400618	/* IO CRB Entry B_B */
+#define		IIO_ICRBB_C		0x00400620	/* IO CRB Entry B_C */
+#define		IIO_ICRBB_D		0x00400628	/* IO CRB Entry B_D */
+#define		IIO_ICRBB_E		0x00400630	/* IO CRB Entry B_E */
+
+#define		IIO_ICRBC_A		0x00400640	/* IO CRB Entry C_A */
+#define		IIO_ICRBC_B		0x00400648	/* IO CRB Entry C_B */
+#define		IIO_ICRBC_C		0x00400650	/* IO CRB Entry C_C */
+#define		IIO_ICRBC_D		0x00400658	/* IO CRB Entry C_D */
+#define		IIO_ICRBC_E		0x00400660	/* IO CRB Entry C_E */
+
+#define		IIO_ICRBD_A		0x00400670	/* IO CRB Entry D_A */
+#define		IIO_ICRBD_B		0x00400678	/* IO CRB Entry D_B */
+#define		IIO_ICRBD_C		0x00400680	/* IO CRB Entry D_C */
+#define		IIO_ICRBD_D		0x00400688	/* IO CRB Entry D_D */
+#define		IIO_ICRBD_E		0x00400690	/* IO CRB Entry D_E */
+
+#define		IIO_ICRBE_A		0x004006a0	/* IO CRB Entry E_A */
+#define		IIO_ICRBE_B		0x004006a8	/* IO CRB Entry E_B */
+#define		IIO_ICRBE_C		0x004006b0	/* IO CRB Entry E_C */
+#define		IIO_ICRBE_D		0x004006b8	/* IO CRB Entry E_D */
+#define		IIO_ICRBE_E		0x004006c0	/* IO CRB Entry E_E */
+
+#define		IIO_ICSML		0x00400700	/* IO CRB Spurious Message Low */
+#define		IIO_ICSMM		0x00400708	/* IO CRB Spurious Message Middle */
+#define		IIO_ICSMH		0x00400710	/* IO CRB Spurious Message High */
+
+#define		IIO_IDBSS		0x00400718	/* IO Debug Submenu Select */
+
+#define		IIO_IBLS0		0x00410000	/* IO BTE Length Status 0 */
+#define		IIO_IBSA0		0x00410008	/* IO BTE Source Address 0 */
+#define		IIO_IBDA0		0x00410010	/* IO BTE Destination Address 0 */
+#define		IIO_IBCT0		0x00410018	/* IO BTE Control Terminate 0 */
+#define		IIO_IBNA0		0x00410020	/* IO BTE Notification Address 0 */
+#define		IIO_IBIA0		0x00410028	/* IO BTE Interrupt Address 0 */
+#define		IIO_IBLS1		0x00420000	/* IO BTE Length Status 1 */
+#define		IIO_IBSA1		0x00420008	/* IO BTE Source Address 1 */
+#define		IIO_IBDA1		0x00420010	/* IO BTE Destination Address 1 */
+#define		IIO_IBCT1		0x00420018	/* IO BTE Control Terminate 1 */
+#define		IIO_IBNA1		0x00420020	/* IO BTE Notification Address 1 */
+#define		IIO_IBIA1		0x00420028	/* IO BTE Interrupt Address 1 */
 
+#define		IIO_IPCR		0x00430000	/* IO Performance Control */
+#define		IIO_IPPR		0x00430008	/* IO Performance Profiling */
 
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register echoes some information from the         *
  * LB_REV_ID register. It is available through Crosstalk as described   *
  * above. The REV_NUM and MFG_NUM fields receive their values from      *
  * the REVISION and MANUFACTURER fields in the LB_REV_ID register.      *
  * The PART_NUM field's value is the Crosstalk device ID number that    *
  * Steve Miller assigned to the SHub chip.                              *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_wid_u {
-	uint64_t	ii_wid_regval;
-	struct	{
-		uint64_t	w_rsvd_1		  :	 1;
-		uint64_t	w_mfg_num		  :	11;
-		uint64_t	w_part_num		  :	16;
-		uint64_t	w_rev_num		  :	 4;
-		uint64_t	w_rsvd			  :	32;
+	uint64_t ii_wid_regval;
+	struct {
+		uint64_t w_rsvd_1:1;
+		uint64_t w_mfg_num:11;
+		uint64_t w_part_num:16;
+		uint64_t w_rev_num:4;
+		uint64_t w_rsvd:32;
 	} ii_wid_fld_s;
 } ii_wid_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  The fields in this register are set upon detection of an error      *
  * and cleared by various mechanisms, as explained in the               *
  * description.                                                         *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_wstat_u {
-	uint64_t	ii_wstat_regval;
-	struct	{
-		uint64_t	w_pending		  :	 4;
-		uint64_t	w_xt_crd_to		  :	 1;
-		uint64_t	w_xt_tail_to		  :	 1;
-		uint64_t	w_rsvd_3		  :	 3;
-		uint64_t       w_tx_mx_rty               :      1;
-		uint64_t	w_rsvd_2		  :	 6;
-		uint64_t	w_llp_tx_cnt		  :	 8;
-		uint64_t	w_rsvd_1		  :	 8;
-		uint64_t	w_crazy			  :	 1;
-		uint64_t	w_rsvd			  :	31;
+	uint64_t ii_wstat_regval;
+	struct {
+		uint64_t w_pending:4;
+		uint64_t w_xt_crd_to:1;
+		uint64_t w_xt_tail_to:1;
+		uint64_t w_rsvd_3:3;
+		uint64_t w_tx_mx_rty:1;
+		uint64_t w_rsvd_2:6;
+		uint64_t w_llp_tx_cnt:8;
+		uint64_t w_rsvd_1:8;
+		uint64_t w_crazy:1;
+		uint64_t w_rsvd:31;
 	} ii_wstat_fld_s;
 } ii_wstat_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This is a read-write enabled register. It controls     *
  * various aspects of the Crosstalk flow control.                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_wcr_u {
-	uint64_t	ii_wcr_regval;
-	struct	{
-		uint64_t	w_wid			  :	 4;
-		uint64_t	w_tag			  :	 1;
-		uint64_t	w_rsvd_1		  :	 8;
-		uint64_t	w_dst_crd		  :	 3;
-		uint64_t	w_f_bad_pkt		  :	 1;
-		uint64_t	w_dir_con		  :	 1;
-		uint64_t	w_e_thresh		  :	 5;
-		uint64_t	w_rsvd			  :	41;
+	uint64_t ii_wcr_regval;
+	struct {
+		uint64_t w_wid:4;
+		uint64_t w_tag:1;
+		uint64_t w_rsvd_1:8;
+		uint64_t w_dst_crd:3;
+		uint64_t w_f_bad_pkt:1;
+		uint64_t w_dir_con:1;
+		uint64_t w_e_thresh:5;
+		uint64_t w_rsvd:41;
 	} ii_wcr_fld_s;
 } ii_wcr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register's value is a bit vector that guards      *
  * access to local registers within the II as well as to external       *
  * Crosstalk widgets. Each bit in the register corresponds to a         *
@@ -311,21 +306,18 @@ typedef union ii_wcr_u {
  * region ID bits are enabled in this same register. It can also be     *
  * accessed through the IAlias space by the local processors.           *
  * The reset value of this register allows access by all nodes.         *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ilapr_u {
-	uint64_t	ii_ilapr_regval;
-	struct  {
-		uint64_t	i_region                  :	64;
+	uint64_t ii_ilapr_regval;
+	struct {
+		uint64_t i_region:64;
 	} ii_ilapr_fld_s;
 } ii_ilapr_u_t;
 
-
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  A write to this register of the 64-bit value           *
  * "SGIrules" in ASCII, will cause the bit in the ILAPR register        *
  * corresponding to the region of the requestor to be set (allow        *
@@ -334,59 +326,54 @@ typedef union ii_ilapr_u {
  * This register can also be accessed through the IAlias space.         *
  * However, this access will not change the access permissions in the   *
  * ILAPR.                                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ilapo_u {
-	uint64_t	ii_ilapo_regval;
-	struct	{
-		uint64_t	i_io_ovrride            :	64;
+	uint64_t ii_ilapo_regval;
+	struct {
+		uint64_t i_io_ovrride:64;
 	} ii_ilapo_fld_s;
 } ii_ilapo_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register qualifies all the PIO and Graphics writes launched    *
  * from the SHUB towards a widget.                                      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iowa_u {
-	uint64_t	ii_iowa_regval;
-	struct	{
-		uint64_t	i_w0_oac		  :	 1;
-		uint64_t	i_rsvd_1		  :	 7;
-                uint64_t       i_wx_oac                  :      8;
-		uint64_t	i_rsvd			  :	48;
+	uint64_t ii_iowa_regval;
+	struct {
+		uint64_t i_w0_oac:1;
+		uint64_t i_rsvd_1:7;
+		uint64_t i_wx_oac:8;
+		uint64_t i_rsvd:48;
 	} ii_iowa_fld_s;
 } ii_iowa_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register qualifies all the requests launched      *
  * from a widget towards the Shub. This register is intended to be      *
  * used by software in case of misbehaving widgets.                     *
- *                                                                      *
- *                                                                      *
+ *									*
+ *									*
  ************************************************************************/
 
 typedef union ii_iiwa_u {
-	uint64_t	ii_iiwa_regval;
-	struct  {
-		uint64_t	i_w0_iac                  :	 1;
-		uint64_t	i_rsvd_1		  :	 7;
-		uint64_t	i_wx_iac		  :	 8;
-		uint64_t	i_rsvd			  :	48;
+	uint64_t ii_iiwa_regval;
+	struct {
+		uint64_t i_w0_iac:1;
+		uint64_t i_rsvd_1:7;
+		uint64_t i_wx_iac:8;
+		uint64_t i_rsvd:48;
 	} ii_iiwa_fld_s;
 } ii_iiwa_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register qualifies all the operations launched    *
  * from a widget towards the SHub. It allows individual access          *
  * control for up to 8 devices per widget. A device refers to           *
@@ -401,72 +388,69 @@ typedef union ii_iiwa_u {
  * The bits in this field are set by writing a 1 to them. Incoming      *
  * replies from Crosstalk are not subject to this access control        *
  * mechanism.                                                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iidem_u {
-	uint64_t	ii_iidem_regval;
-	struct	{
-		uint64_t	i_w8_dxs		  :	 8;
-		uint64_t	i_w9_dxs		  :	 8;
-		uint64_t	i_wa_dxs		  :	 8;
-		uint64_t	i_wb_dxs		  :	 8;
-		uint64_t	i_wc_dxs		  :	 8;
-		uint64_t	i_wd_dxs		  :	 8;
-		uint64_t	i_we_dxs		  :	 8;
-		uint64_t	i_wf_dxs		  :	 8;
+	uint64_t ii_iidem_regval;
+	struct {
+		uint64_t i_w8_dxs:8;
+		uint64_t i_w9_dxs:8;
+		uint64_t i_wa_dxs:8;
+		uint64_t i_wb_dxs:8;
+		uint64_t i_wc_dxs:8;
+		uint64_t i_wd_dxs:8;
+		uint64_t i_we_dxs:8;
+		uint64_t i_wf_dxs:8;
 	} ii_iidem_fld_s;
 } ii_iidem_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the various programmable fields necessary    *
  * for controlling and observing the LLP signals.                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ilcsr_u {
-	uint64_t	ii_ilcsr_regval;
-	struct  {
-		uint64_t	i_nullto                  :	 6;
-		uint64_t	i_rsvd_4		  :	 2;
-		uint64_t	i_wrmrst		  :	 1;
-		uint64_t	i_rsvd_3		  :	 1;
-		uint64_t	i_llp_en		  :	 1;
-		uint64_t	i_bm8			  :	 1;
-		uint64_t	i_llp_stat		  :	 2;
-		uint64_t	i_remote_power		  :	 1;
-		uint64_t	i_rsvd_2		  :	 1;
-		uint64_t	i_maxrtry		  :	10;
-		uint64_t	i_d_avail_sel		  :	 2;
-		uint64_t	i_rsvd_1		  :	 4;
-		uint64_t	i_maxbrst		  :	10;
-                uint64_t       i_rsvd                    :     22;
+	uint64_t ii_ilcsr_regval;
+	struct {
+		uint64_t i_nullto:6;
+		uint64_t i_rsvd_4:2;
+		uint64_t i_wrmrst:1;
+		uint64_t i_rsvd_3:1;
+		uint64_t i_llp_en:1;
+		uint64_t i_bm8:1;
+		uint64_t i_llp_stat:2;
+		uint64_t i_remote_power:1;
+		uint64_t i_rsvd_2:1;
+		uint64_t i_maxrtry:10;
+		uint64_t i_d_avail_sel:2;
+		uint64_t i_rsvd_1:4;
+		uint64_t i_maxbrst:10;
+		uint64_t i_rsvd:22;
 
 	} ii_ilcsr_fld_s;
 } ii_ilcsr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This is simply a status registers that monitors the LLP error       *
- * rate.                                                                *
- *                                                                      *
+ * rate.								*
+ *									*
  ************************************************************************/
 
 typedef union ii_illr_u {
-	uint64_t	ii_illr_regval;
-	struct	{
-		uint64_t	i_sn_cnt		  :	16;
-		uint64_t	i_cb_cnt		  :	16;
-		uint64_t	i_rsvd			  :	32;
+	uint64_t ii_illr_regval;
+	struct {
+		uint64_t i_sn_cnt:16;
+		uint64_t i_cb_cnt:16;
+		uint64_t i_rsvd:32;
 	} ii_illr_fld_s;
 } ii_illr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  All II-detected non-BTE error interrupts are           *
  * specified via this register.                                         *
  * NOTE: The PI interrupt register address is hardcoded in the II. If   *
@@ -476,107 +460,100 @@ typedef union ii_illr_u {
  * PI_ID==1, then the II sends the interrupt request to address         *
  * offset 0x01A0_0090 within the local register address space of PI1    *
  * on the node specified by the NODE field.                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iidsr_u {
-	uint64_t	ii_iidsr_regval;
-	struct  {
-		uint64_t	i_level                   :	 8;
-		uint64_t	i_pi_id			  :	 1;
-		uint64_t	i_node			  :	11;
-		uint64_t       i_rsvd_3                  :      4;
-		uint64_t	i_enable		  :	 1;
-		uint64_t	i_rsvd_2		  :	 3;
-		uint64_t	i_int_sent		  :	 2;
-		uint64_t       i_rsvd_1                  :      2;
-		uint64_t	i_pi0_forward_int	  :	 1;
-		uint64_t	i_pi1_forward_int	  :	 1;
-		uint64_t	i_rsvd			  :	30;
+	uint64_t ii_iidsr_regval;
+	struct {
+		uint64_t i_level:8;
+		uint64_t i_pi_id:1;
+		uint64_t i_node:11;
+		uint64_t i_rsvd_3:4;
+		uint64_t i_enable:1;
+		uint64_t i_rsvd_2:3;
+		uint64_t i_int_sent:2;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_pi0_forward_int:1;
+		uint64_t i_pi1_forward_int:1;
+		uint64_t i_rsvd:30;
 	} ii_iidsr_fld_s;
 } ii_iidsr_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are two instances of this register. This register is used     *
  * for matching up the incoming responses from the graphics widget to   *
  * the processor that initiated the graphics operation. The             *
  * write-responses are converted to graphics credits and returned to    *
  * the processor so that the processor interface can manage the flow    *
  * control.                                                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_igfx0_u {
-	uint64_t	ii_igfx0_regval;
-	struct	{
-		uint64_t	i_w_num			  :	 4;
-		uint64_t       i_pi_id                   :      1;
-		uint64_t	i_n_num			  :	12;
-		uint64_t       i_p_num                   :      1;
-		uint64_t       i_rsvd                    :     46;
+	uint64_t ii_igfx0_regval;
+	struct {
+		uint64_t i_w_num:4;
+		uint64_t i_pi_id:1;
+		uint64_t i_n_num:12;
+		uint64_t i_p_num:1;
+		uint64_t i_rsvd:46;
 	} ii_igfx0_fld_s;
 } ii_igfx0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are two instances of this register. This register is used     *
  * for matching up the incoming responses from the graphics widget to   *
  * the processor that initiated the graphics operation. The             *
  * write-responses are converted to graphics credits and returned to    *
  * the processor so that the processor interface can manage the flow    *
  * control.                                                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_igfx1_u {
-	uint64_t	ii_igfx1_regval;
-	struct  {
-		uint64_t	i_w_num			  :	 4;
-		uint64_t       i_pi_id                   :      1;
-		uint64_t	i_n_num			  :	12;
-		uint64_t       i_p_num                   :      1;
-		uint64_t       i_rsvd                    :     46;
+	uint64_t ii_igfx1_regval;
+	struct {
+		uint64_t i_w_num:4;
+		uint64_t i_pi_id:1;
+		uint64_t i_n_num:12;
+		uint64_t i_p_num:1;
+		uint64_t i_rsvd:46;
 	} ii_igfx1_fld_s;
 } ii_igfx1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are two instances of this registers. These registers are      *
  * used as scratch registers for software use.                          *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iscr0_u {
-	uint64_t	ii_iscr0_regval;
-	struct  {
-		uint64_t	i_scratch                 :	64;
+	uint64_t ii_iscr0_regval;
+	struct {
+		uint64_t i_scratch:64;
 	} ii_iscr0_fld_s;
 } ii_iscr0_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are two instances of this registers. These registers are      *
  * used as scratch registers for software use.                          *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iscr1_u {
-	uint64_t	ii_iscr1_regval;
-	struct  {
-		uint64_t	i_scratch                 :	64;
+	uint64_t ii_iscr1_regval;
+	struct {
+		uint64_t i_scratch:64;
 	} ii_iscr1_fld_s;
 } ii_iscr1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a Shub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -599,23 +576,22 @@ typedef union ii_iscr1_u {
  * Crosstalk space addressable by the Shub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte1_u {
-	uint64_t	ii_itte1_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_w_num			  :	 4;
-		uint64_t	i_iosp			  :	 1;
-		uint64_t	i_rsvd			  :	51;
+	uint64_t ii_itte1_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte1_fld_s;
 } ii_itte1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a Shub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -638,23 +614,22 @@ typedef union ii_itte1_u {
  * Crosstalk space addressable by the Shub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte2_u {
-	uint64_t	ii_itte2_regval;
-	struct	{
-		uint64_t	i_offset		  :	 5;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_w_num			  :	 4;
-		uint64_t	i_iosp			  :	 1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte2_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte2_fld_s;
 } ii_itte2_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a Shub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -677,23 +652,22 @@ typedef union ii_itte2_u {
  * Crosstalk space addressable by the SHub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte3_u {
-	uint64_t	ii_itte3_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t       i_rsvd_1                  :      3;
-		uint64_t       i_w_num                   :      4;
-		uint64_t       i_iosp                    :      1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte3_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte3_fld_s;
 } ii_itte3_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a SHub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -716,23 +690,22 @@ typedef union ii_itte3_u {
  * Crosstalk space addressable by the SHub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte4_u {
-	uint64_t	ii_itte4_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t       i_w_num                   :      4;
-		uint64_t       i_iosp                    :      1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte4_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte4_fld_s;
 } ii_itte4_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a SHub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -755,23 +728,22 @@ typedef union ii_itte4_u {
  * Crosstalk space addressable by the Shub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte5_u {
-	uint64_t	ii_itte5_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t       i_rsvd_1                  :      3;
-		uint64_t       i_w_num                   :      4;
-		uint64_t       i_iosp                    :      1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte5_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte5_fld_s;
 } ii_itte5_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a Shub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -794,23 +766,22 @@ typedef union ii_itte5_u {
  * Crosstalk space addressable by the Shub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte6_u {
-	uint64_t	ii_itte6_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t       i_rsvd_1                  :      3;
-		uint64_t       i_w_num                   :      4;
-		uint64_t       i_iosp                    :      1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte6_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte6_fld_s;
 } ii_itte6_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are seven instances of translation table entry   *
  * registers. Each register maps a Shub Big Window to a 48-bit          *
  * address on Crosstalk.                                                *
@@ -833,23 +804,22 @@ typedef union ii_itte6_u {
  * Crosstalk space addressable by the SHub is thus the lower            *
  * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
  * of this space can be accessed.                                       *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_itte7_u {
-	uint64_t	ii_itte7_regval;
-	struct  {
-		uint64_t	i_offset                  :	 5;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t       i_w_num                   :      4;
-		uint64_t       i_iosp                    :      1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_itte7_regval;
+	struct {
+		uint64_t i_offset:5;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_w_num:4;
+		uint64_t i_iosp:1;
+		uint64_t i_rsvd:51;
 	} ii_itte7_fld_s;
 } ii_itte7_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -868,33 +838,32 @@ typedef union ii_itte7_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprb0_u {
-	uint64_t	ii_iprb0_regval;
-	struct  {
-		uint64_t	i_c                       :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t       i_rsvd_2                  :      2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprb0_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprb0_fld_s;
 } ii_iprb0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -913,33 +882,32 @@ typedef union ii_iprb0_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprb8_u {
-	uint64_t	ii_iprb8_regval;
-	struct  {
-		uint64_t	i_c                       :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t       i_rsvd_2                  :      2;
-		uint64_t	i_nb			  :	14;
-		uint64_t       i_rsvd_1                  :      2;
-		uint64_t       i_m                       :      2;
-		uint64_t       i_f                       :      1;
-		uint64_t       i_of_cnt                  :      5;
-		uint64_t       i_error                   :      1;
-		uint64_t       i_rd_to                   :      1;
-		uint64_t       i_spur_wr                 :      1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t       i_rsvd                    :     11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprb8_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprb8_fld_s;
 } ii_iprb8_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -958,33 +926,32 @@ typedef union ii_iprb8_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprb9_u {
-	uint64_t	ii_iprb9_regval;
-	struct	{
-		uint64_t	i_c			  :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprb9_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprb9_fld_s;
 } ii_iprb9_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.        *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1003,33 +970,32 @@ typedef union ii_iprb9_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- *                                                                      *
- *                                                                      *
+ *									*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprba_u {
-	uint64_t	ii_iprba_regval;
-	struct  {
-		uint64_t	i_c                       :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t       i_rsvd_2                  :      2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprba_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprba_fld_s;
 } ii_iprba_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1048,33 +1014,32 @@ typedef union ii_iprba_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprbb_u {
-	uint64_t	ii_iprbb_regval;
-	struct	{
-		uint64_t	i_c			  :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprbb_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprbb_fld_s;
 } ii_iprbb_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1093,33 +1058,32 @@ typedef union ii_iprbb_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprbc_u {
-	uint64_t	ii_iprbc_regval;
-	struct	{
-		uint64_t	i_c			  :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprbc_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprbc_fld_s;
 } ii_iprbc_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1138,33 +1102,32 @@ typedef union ii_iprbc_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprbd_u {
-	uint64_t	ii_iprbd_regval;
-	struct	{
-		uint64_t	i_c			  :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprbd_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprbd_fld_s;
 } ii_iprbd_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of SHub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1183,33 +1146,32 @@ typedef union ii_iprbd_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprbe_u {
-	uint64_t	ii_iprbe_regval;
-	struct	{
-		uint64_t	i_c			  :	 8;
-		uint64_t	i_na			  :	14;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_nb			  :	14;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_m			  :	 2;
-		uint64_t	i_f			  :	 1;
-		uint64_t	i_of_cnt		  :	 5;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rd_to			  :	 1;
-		uint64_t	i_spur_wr		  :	 1;
-		uint64_t	i_spur_rd		  :	 1;
-		uint64_t	i_rsvd			  :	11;
-		uint64_t	i_mult_err		  :	 1;
+	uint64_t ii_iprbe_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
 	} ii_iprbe_fld_s;
 } ii_iprbe_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 9 instances of this register, one per        *
  * actual widget in this implementation of Shub and Crossbow.           *
  * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
@@ -1228,33 +1190,32 @@ typedef union ii_iprbe_u {
  * register; the write will correct the C field and capture its new     *
  * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
  * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                    *
- *                                                                      *
+ * .    								*
+ *									*
  ************************************************************************/
 
 typedef union ii_iprbf_u {
-        uint64_t       ii_iprbf_regval;
-        struct  {
-                uint64_t       i_c                       :      8;
-                uint64_t       i_na                      :     14;
-                uint64_t       i_rsvd_2                  :      2;
-                uint64_t       i_nb                      :     14;
-                uint64_t       i_rsvd_1                  :      2;
-                uint64_t       i_m                       :      2;
-                uint64_t       i_f                       :      1;
-                uint64_t       i_of_cnt                  :      5;
-                uint64_t       i_error                   :      1;
-                uint64_t       i_rd_to                   :      1;
-                uint64_t       i_spur_wr                 :      1;
-                uint64_t       i_spur_rd                 :      1;
-                uint64_t       i_rsvd                    :     11;
-                uint64_t       i_mult_err                :      1;
-        } ii_iprbe_fld_s;
+	uint64_t ii_iprbf_regval;
+	struct {
+		uint64_t i_c:8;
+		uint64_t i_na:14;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_nb:14;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_m:2;
+		uint64_t i_f:1;
+		uint64_t i_of_cnt:5;
+		uint64_t i_error:1;
+		uint64_t i_rd_to:1;
+		uint64_t i_spur_wr:1;
+		uint64_t i_spur_rd:1;
+		uint64_t i_rsvd:11;
+		uint64_t i_mult_err:1;
+	} ii_iprbe_fld_s;
 } ii_iprbf_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register specifies the timeout value to use for monitoring     *
  * Crosstalk credits which are used outbound to Crosstalk. An           *
  * internal counter called the Crosstalk Credit Timeout Counter         *
@@ -1267,20 +1228,19 @@ typedef union ii_iprbf_u {
  * Crosstalk Credit Timeout has occurred. The internal counter is not   *
  * readable from software, and stops counting at its maximum value,     *
  * so it cannot cause more than one interrupt.                          *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ixcc_u {
-	uint64_t	ii_ixcc_regval;
-	struct  {
-		uint64_t	i_time_out                :	26;
-		uint64_t	i_rsvd			  :	38;
+	uint64_t ii_ixcc_regval;
+	struct {
+		uint64_t i_time_out:26;
+		uint64_t i_rsvd:38;
 	} ii_ixcc_fld_s;
 } ii_ixcc_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register qualifies all the PIO and DMA            *
  * operations launched from widget 0 towards the SHub. In               *
  * addition, it also qualifies accesses by the BTE streams.             *
@@ -1292,27 +1252,25 @@ typedef union ii_ixcc_u {
  * the Wx_IAC field. The bits in this field are set by writing a 1 to   *
  * them. Incoming replies from Crosstalk are not subject to this        *
  * access control mechanism.                                            *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_imem_u {
-	uint64_t	ii_imem_regval;
-	struct  {
-		uint64_t	i_w0_esd                  :	 1;
-		uint64_t	i_rsvd_3		  :	 3;
-		uint64_t	i_b0_esd		  :	 1;
-		uint64_t	i_rsvd_2		  :	 3;
-		uint64_t	i_b1_esd		  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_clr_precise		  :	 1;
-		uint64_t       i_rsvd                    :     51;
+	uint64_t ii_imem_regval;
+	struct {
+		uint64_t i_w0_esd:1;
+		uint64_t i_rsvd_3:3;
+		uint64_t i_b0_esd:1;
+		uint64_t i_rsvd_2:3;
+		uint64_t i_b1_esd:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_clr_precise:1;
+		uint64_t i_rsvd:51;
 	} ii_imem_fld_s;
 } ii_imem_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register specifies the timeout value to use for   *
  * monitoring Crosstalk tail flits coming into the Shub in the          *
  * TAIL_TO field. An internal counter associated with this register     *
@@ -1332,90 +1290,87 @@ typedef union ii_imem_u {
  * the value in the RRSP_TO field, a Read Response Timeout has          *
  * occurred, and error handling occurs as described in the Error        *
  * Handling section of this document.                                   *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ixtt_u {
-	uint64_t	ii_ixtt_regval;
-	struct  {
-		uint64_t	i_tail_to                 :	26;
-		uint64_t	i_rsvd_1		  :	 6;
-		uint64_t	i_rrsp_ps		  :	23;
-		uint64_t	i_rrsp_to		  :	 5;
-		uint64_t	i_rsvd			  :	 4;
+	uint64_t ii_ixtt_regval;
+	struct {
+		uint64_t i_tail_to:26;
+		uint64_t i_rsvd_1:6;
+		uint64_t i_rrsp_ps:23;
+		uint64_t i_rrsp_to:5;
+		uint64_t i_rsvd:4;
 	} ii_ixtt_fld_s;
 } ii_ixtt_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  Writing a 1 to the fields of this register clears the appropriate   *
  * error bits in other areas of SHub. Note that when the                *
  * E_PRB_x bits are used to clear error bits in PRB registers,          *
  * SPUR_RD and SPUR_WR may persist, because they require additional     *
  * action to clear them. See the IPRBx and IXSS Register                *
  * specifications.                                                      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ieclr_u {
-	uint64_t	ii_ieclr_regval;
-	struct  {
-		uint64_t	i_e_prb_0                 :	 1;
-		uint64_t	i_rsvd			  :	 7;
-		uint64_t	i_e_prb_8		  :	 1;
-		uint64_t	i_e_prb_9		  :	 1;
-		uint64_t	i_e_prb_a		  :	 1;
-		uint64_t	i_e_prb_b		  :	 1;
-		uint64_t	i_e_prb_c		  :	 1;
-		uint64_t	i_e_prb_d		  :	 1;
-		uint64_t	i_e_prb_e		  :	 1;
-		uint64_t	i_e_prb_f		  :	 1;
-		uint64_t	i_e_crazy		  :	 1;
-		uint64_t	i_e_bte_0		  :	 1;
-		uint64_t	i_e_bte_1		  :	 1;
-		uint64_t	i_reserved_1		  :	10;
-		uint64_t	i_spur_rd_hdr		  :	 1;
-		uint64_t	i_cam_intr_to		  :	 1;
-		uint64_t	i_cam_overflow		  :	 1;
-		uint64_t	i_cam_read_miss		  :	 1;
-		uint64_t	i_ioq_rep_underflow	  :	 1;
-		uint64_t	i_ioq_req_underflow	  :	 1;
-		uint64_t	i_ioq_rep_overflow	  :	 1;
-		uint64_t	i_ioq_req_overflow	  :	 1;
-		uint64_t	i_iiq_rep_overflow	  :	 1;
-		uint64_t	i_iiq_req_overflow	  :	 1;
-		uint64_t	i_ii_xn_rep_cred_overflow :	 1;
-		uint64_t	i_ii_xn_req_cred_overflow :	 1;
-		uint64_t	i_ii_xn_invalid_cmd	  :	 1;
-		uint64_t	i_xn_ii_invalid_cmd	  :	 1;
-		uint64_t	i_reserved_2		  :	21;
+	uint64_t ii_ieclr_regval;
+	struct {
+		uint64_t i_e_prb_0:1;
+		uint64_t i_rsvd:7;
+		uint64_t i_e_prb_8:1;
+		uint64_t i_e_prb_9:1;
+		uint64_t i_e_prb_a:1;
+		uint64_t i_e_prb_b:1;
+		uint64_t i_e_prb_c:1;
+		uint64_t i_e_prb_d:1;
+		uint64_t i_e_prb_e:1;
+		uint64_t i_e_prb_f:1;
+		uint64_t i_e_crazy:1;
+		uint64_t i_e_bte_0:1;
+		uint64_t i_e_bte_1:1;
+		uint64_t i_reserved_1:10;
+		uint64_t i_spur_rd_hdr:1;
+		uint64_t i_cam_intr_to:1;
+		uint64_t i_cam_overflow:1;
+		uint64_t i_cam_read_miss:1;
+		uint64_t i_ioq_rep_underflow:1;
+		uint64_t i_ioq_req_underflow:1;
+		uint64_t i_ioq_rep_overflow:1;
+		uint64_t i_ioq_req_overflow:1;
+		uint64_t i_iiq_rep_overflow:1;
+		uint64_t i_iiq_req_overflow:1;
+		uint64_t i_ii_xn_rep_cred_overflow:1;
+		uint64_t i_ii_xn_req_cred_overflow:1;
+		uint64_t i_ii_xn_invalid_cmd:1;
+		uint64_t i_xn_ii_invalid_cmd:1;
+		uint64_t i_reserved_2:21;
 	} ii_ieclr_fld_s;
 } ii_ieclr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register controls both BTEs. SOFT_RESET is intended for        *
  * recovery after an error. COUNT controls the total number of CRBs     *
  * that both BTEs (combined) can use, which affects total BTE           *
  * bandwidth.                                                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibcr_u {
-	uint64_t	ii_ibcr_regval;
-	struct  {
-		uint64_t	i_count                   :	 4;
-		uint64_t	i_rsvd_1		  :	 4;
-		uint64_t	i_soft_reset		  :	 1;
-		uint64_t	i_rsvd			  :	55;
+	uint64_t ii_ibcr_regval;
+	struct {
+		uint64_t i_count:4;
+		uint64_t i_rsvd_1:4;
+		uint64_t i_soft_reset:1;
+		uint64_t i_rsvd:55;
 	} ii_ibcr_fld_s;
 } ii_ibcr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the header of a spurious read response       *
  * received from Crosstalk. A spurious read response is defined as a    *
  * read response received by II from a widget for which (1) the SIDN    *
@@ -1440,49 +1395,47 @@ typedef union ii_ibcr_u {
  * will be set. Any SPUR_RD bits in any other PRB registers indicate    *
  * spurious messages from other widets which were detected after the    *
  * header was captured..                                                *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ixsm_u {
-	uint64_t	ii_ixsm_regval;
-	struct  {
-		uint64_t	i_byte_en                 :	32;
-		uint64_t	i_reserved		  :	 1;
-		uint64_t	i_tag			  :	 3;
-		uint64_t	i_alt_pactyp		  :	 4;
-		uint64_t	i_bo			  :	 1;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_vbpm			  :	 1;
-		uint64_t	i_gbr			  :	 1;
-		uint64_t	i_ds			  :	 2;
-		uint64_t	i_ct			  :	 1;
-		uint64_t	i_tnum			  :	 5;
-		uint64_t	i_pactyp		  :	 4;
-		uint64_t	i_sidn			  :	 4;
-		uint64_t	i_didn			  :	 4;
+	uint64_t ii_ixsm_regval;
+	struct {
+		uint64_t i_byte_en:32;
+		uint64_t i_reserved:1;
+		uint64_t i_tag:3;
+		uint64_t i_alt_pactyp:4;
+		uint64_t i_bo:1;
+		uint64_t i_error:1;
+		uint64_t i_vbpm:1;
+		uint64_t i_gbr:1;
+		uint64_t i_ds:2;
+		uint64_t i_ct:1;
+		uint64_t i_tnum:5;
+		uint64_t i_pactyp:4;
+		uint64_t i_sidn:4;
+		uint64_t i_didn:4;
 	} ii_ixsm_fld_s;
 } ii_ixsm_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the sideband bits of a spurious read         *
  * response received from Crosstalk.                                    *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ixss_u {
-	uint64_t	ii_ixss_regval;
-	struct  {
-		uint64_t	i_sideband                :	 8;
-		uint64_t	i_rsvd			  :	55;
-		uint64_t	i_valid			  :	 1;
+	uint64_t ii_ixss_regval;
+	struct {
+		uint64_t i_sideband:8;
+		uint64_t i_rsvd:55;
+		uint64_t i_valid:1;
 	} ii_ixss_fld_s;
 } ii_ixss_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register enables software to access the II LLP's test port.    *
  * Refer to the LLP 2.5 documentation for an explanation of the test    *
  * port. Software can write to this register to program the values      *
@@ -1490,27 +1443,26 @@ typedef union ii_ixss_u {
  * TestMask and TestSeed). Similarly, software can read from this       *
  * register to obtain the values of the test port's status outputs      *
  * (TestCBerr, TestValid and TestData).                                 *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ilct_u {
-	uint64_t	ii_ilct_regval;
-	struct  {
-		uint64_t	i_test_seed               :	20;
-		uint64_t	i_test_mask               :	 8;
-		uint64_t	i_test_data               :	20;
-		uint64_t	i_test_valid              :	 1;
-		uint64_t	i_test_cberr              :	 1;
-		uint64_t	i_test_flit               :	 3;
-		uint64_t	i_test_clear              :	 1;
-		uint64_t	i_test_err_capture        :	 1;
-		uint64_t	i_rsvd                    :	 9;
+	uint64_t ii_ilct_regval;
+	struct {
+		uint64_t i_test_seed:20;
+		uint64_t i_test_mask:8;
+		uint64_t i_test_data:20;
+		uint64_t i_test_valid:1;
+		uint64_t i_test_cberr:1;
+		uint64_t i_test_flit:3;
+		uint64_t i_test_clear:1;
+		uint64_t i_test_err_capture:1;
+		uint64_t i_rsvd:9;
 	} ii_ilct_fld_s;
 } ii_ilct_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  If the II detects an illegal incoming Duplonet packet (request or   *
  * reply) when VALID==0 in the IIEPH1 register, then it saves the       *
  * contents of the packet's header flit in the IIEPH1 and IIEPH2        *
@@ -1526,575 +1478,549 @@ typedef union ii_ilct_u {
  * packet when VALID==1 in the IIEPH1 register, then it merely sets     *
  * the OVERRUN bit to indicate that a subsequent error has happened,    *
  * and does nothing further.                                            *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iieph1_u {
-	uint64_t	ii_iieph1_regval;
-	struct	{
-		uint64_t	i_command		  :	 7;
-		uint64_t	i_rsvd_5		  :	 1;
-		uint64_t	i_suppl			  :	14;
-		uint64_t	i_rsvd_4		  :	 1;
-		uint64_t	i_source		  :	14;
-		uint64_t	i_rsvd_3		  :	 1;
-		uint64_t	i_err_type		  :	 4;
-		uint64_t	i_rsvd_2		  :	 4;
-		uint64_t	i_overrun		  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_valid			  :	 1;
-		uint64_t	i_rsvd			  :	13;
+	uint64_t ii_iieph1_regval;
+	struct {
+		uint64_t i_command:7;
+		uint64_t i_rsvd_5:1;
+		uint64_t i_suppl:14;
+		uint64_t i_rsvd_4:1;
+		uint64_t i_source:14;
+		uint64_t i_rsvd_3:1;
+		uint64_t i_err_type:4;
+		uint64_t i_rsvd_2:4;
+		uint64_t i_overrun:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_valid:1;
+		uint64_t i_rsvd:13;
 	} ii_iieph1_fld_s;
 } ii_iieph1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register holds the Address field from the header flit of an    *
  * incoming erroneous Duplonet packet, along with the tail bit which    *
  * accompanied this header flit. This register is essentially an        *
  * extension of IIEPH1. Two registers were necessary because the 64     *
  * bits available in only a single register were insufficient to        *
  * capture the entire header flit of an erroneous packet.               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iieph2_u {
-	uint64_t	ii_iieph2_regval;
-	struct  {
-		uint64_t	i_rsvd_0		  :	 3;
-		uint64_t	i_address                 :	47;
-		uint64_t	i_rsvd_1		  :	10;
-		uint64_t	i_tail			  :	 1;
-		uint64_t	i_rsvd			  :	 3;
+	uint64_t ii_iieph2_regval;
+	struct {
+		uint64_t i_rsvd_0:3;
+		uint64_t i_address:47;
+		uint64_t i_rsvd_1:10;
+		uint64_t i_tail:1;
+		uint64_t i_rsvd:3;
 	} ii_iieph2_fld_s;
 } ii_iieph2_u_t;
 
-
 /******************************/
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register's value is a bit vector that guards access from SXBs  *
  * to local registers within the II as well as to external Crosstalk    *
  * widgets								*
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_islapr_u {
-	uint64_t	ii_islapr_regval;
-	struct  {
-		uint64_t	i_region		  :	64;
+	uint64_t ii_islapr_regval;
+	struct {
+		uint64_t i_region:64;
 	} ii_islapr_fld_s;
 } ii_islapr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  A write to this register of the 56-bit value "Pup+Bun" will cause	*
  * the bit in the ISLAPR register corresponding to the region of the	*
  * requestor to be set (access allowed).				(
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_islapo_u {
-	uint64_t	ii_islapo_regval;
-	struct  {
-		uint64_t	i_io_sbx_ovrride	  :	56;
-		uint64_t	i_rsvd			  :	 8;
+	uint64_t ii_islapo_regval;
+	struct {
+		uint64_t i_io_sbx_ovrride:56;
+		uint64_t i_rsvd:8;
 	} ii_islapo_fld_s;
 } ii_islapo_u_t;
 
 /************************************************************************
- *                                                                      *
+ *									*
  *  Determines how long the wrapper will wait aftr an interrupt is	*
  * initially issued from the II before it times out the outstanding	*
  * interrupt and drops it from the interrupt queue.			* 
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iwi_u {
-	uint64_t	ii_iwi_regval;
-	struct  {
-		uint64_t	i_prescale		  :	24;
-		uint64_t	i_rsvd			  :	 8;
-		uint64_t	i_timeout		  :	 8;
-		uint64_t	i_rsvd1			  :	 8;
-		uint64_t	i_intrpt_retry_period	  :	 8;
-		uint64_t	i_rsvd2			  :	 8;
+	uint64_t ii_iwi_regval;
+	struct {
+		uint64_t i_prescale:24;
+		uint64_t i_rsvd:8;
+		uint64_t i_timeout:8;
+		uint64_t i_rsvd1:8;
+		uint64_t i_intrpt_retry_period:8;
+		uint64_t i_rsvd2:8;
 	} ii_iwi_fld_s;
 } ii_iwi_u_t;
 
 /************************************************************************
- *                                                                      *
+ *									*
  *  Log errors which have occurred in the II wrapper. The errors are	*
  * cleared by writing to the IECLR register.				* 
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iwel_u {
-	uint64_t	ii_iwel_regval;
-	struct  {
-		uint64_t	i_intr_timed_out	  :	 1;
-		uint64_t	i_rsvd			  :	 7;
-		uint64_t	i_cam_overflow		  :	 1;
-		uint64_t	i_cam_read_miss		  :	 1;
-		uint64_t	i_rsvd1			  :	 2;
-		uint64_t	i_ioq_rep_underflow	  :	 1;
-		uint64_t	i_ioq_req_underflow	  :	 1;
-		uint64_t	i_ioq_rep_overflow	  :	 1;
-		uint64_t	i_ioq_req_overflow	  :	 1;
-		uint64_t	i_iiq_rep_overflow	  :	 1;
-		uint64_t	i_iiq_req_overflow	  :	 1;
-		uint64_t	i_rsvd2			  :	 6;
-		uint64_t	i_ii_xn_rep_cred_over_under:	 1;
-		uint64_t	i_ii_xn_req_cred_over_under:	 1;
-		uint64_t	i_rsvd3			  :	 6;
-		uint64_t	i_ii_xn_invalid_cmd	  :	 1;
-		uint64_t	i_xn_ii_invalid_cmd	  :	 1;
-		uint64_t	i_rsvd4			  :	30;
+	uint64_t ii_iwel_regval;
+	struct {
+		uint64_t i_intr_timed_out:1;
+		uint64_t i_rsvd:7;
+		uint64_t i_cam_overflow:1;
+		uint64_t i_cam_read_miss:1;
+		uint64_t i_rsvd1:2;
+		uint64_t i_ioq_rep_underflow:1;
+		uint64_t i_ioq_req_underflow:1;
+		uint64_t i_ioq_rep_overflow:1;
+		uint64_t i_ioq_req_overflow:1;
+		uint64_t i_iiq_rep_overflow:1;
+		uint64_t i_iiq_req_overflow:1;
+		uint64_t i_rsvd2:6;
+		uint64_t i_ii_xn_rep_cred_over_under:1;
+		uint64_t i_ii_xn_req_cred_over_under:1;
+		uint64_t i_rsvd3:6;
+		uint64_t i_ii_xn_invalid_cmd:1;
+		uint64_t i_xn_ii_invalid_cmd:1;
+		uint64_t i_rsvd4:30;
 	} ii_iwel_fld_s;
 } ii_iwel_u_t;
 
 /************************************************************************
- *                                                                      *
+ *									*
  *  Controls the II wrapper.						* 
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iwc_u {
-	uint64_t	ii_iwc_regval;
-	struct  {
-		uint64_t	i_dma_byte_swap		  :	 1;
-		uint64_t	i_rsvd			  :	 3;
-		uint64_t	i_cam_read_lines_reset	  :	 1;
-		uint64_t	i_rsvd1			  :	 3;
-		uint64_t	i_ii_xn_cred_over_under_log:	 1;
-		uint64_t	i_rsvd2			  :	19;
-		uint64_t	i_xn_rep_iq_depth	  :	 5;
-		uint64_t	i_rsvd3			  :	 3;
-		uint64_t	i_xn_req_iq_depth	  :	 5;
-		uint64_t	i_rsvd4			  :	 3;
-		uint64_t	i_iiq_depth		  :	 6;
-		uint64_t	i_rsvd5			  :	12;
-		uint64_t	i_force_rep_cred	  :	 1;
-		uint64_t	i_force_req_cred	  :	 1;
+	uint64_t ii_iwc_regval;
+	struct {
+		uint64_t i_dma_byte_swap:1;
+		uint64_t i_rsvd:3;
+		uint64_t i_cam_read_lines_reset:1;
+		uint64_t i_rsvd1:3;
+		uint64_t i_ii_xn_cred_over_under_log:1;
+		uint64_t i_rsvd2:19;
+		uint64_t i_xn_rep_iq_depth:5;
+		uint64_t i_rsvd3:3;
+		uint64_t i_xn_req_iq_depth:5;
+		uint64_t i_rsvd4:3;
+		uint64_t i_iiq_depth:6;
+		uint64_t i_rsvd5:12;
+		uint64_t i_force_rep_cred:1;
+		uint64_t i_force_req_cred:1;
 	} ii_iwc_fld_s;
 } ii_iwc_u_t;
 
 /************************************************************************
- *                                                                      *
+ *									*
  *  Status in the II wrapper.						* 
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iws_u {
-	uint64_t	ii_iws_regval;
-	struct  {
-		uint64_t	i_xn_rep_iq_credits	  :	 5;
-		uint64_t	i_rsvd			  :	 3;
-		uint64_t	i_xn_req_iq_credits	  :	 5;
-		uint64_t	i_rsvd1			  :	51;
+	uint64_t ii_iws_regval;
+	struct {
+		uint64_t i_xn_rep_iq_credits:5;
+		uint64_t i_rsvd:3;
+		uint64_t i_xn_req_iq_credits:5;
+		uint64_t i_rsvd1:51;
 	} ii_iws_fld_s;
 } ii_iws_u_t;
 
 /************************************************************************
- *                                                                      *
+ *									*
  *  Masks errors in the IWEL register.					*
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iweim_u {
-	uint64_t	ii_iweim_regval;
-	struct  {
-		uint64_t	i_intr_timed_out	  :	 1;
-		uint64_t	i_rsvd			  :	 7;
-		uint64_t	i_cam_overflow		  :	 1;
-		uint64_t	i_cam_read_miss		  :	 1;
-		uint64_t	i_rsvd1			  :	 2;
-		uint64_t	i_ioq_rep_underflow	  :	 1;
-		uint64_t	i_ioq_req_underflow	  :	 1;
-		uint64_t	i_ioq_rep_overflow	  :	 1;
-		uint64_t	i_ioq_req_overflow	  :	 1;
-		uint64_t	i_iiq_rep_overflow	  :	 1;
-		uint64_t	i_iiq_req_overflow	  :	 1;
-		uint64_t	i_rsvd2			  :	 6;
-		uint64_t	i_ii_xn_rep_cred_overflow :	 1;
-		uint64_t	i_ii_xn_req_cred_overflow :	 1;
-		uint64_t	i_rsvd3			  :	 6;
-		uint64_t	i_ii_xn_invalid_cmd	  :	 1;
-		uint64_t	i_xn_ii_invalid_cmd	  :	 1;
-		uint64_t	i_rsvd4			  :	30;
+	uint64_t ii_iweim_regval;
+	struct {
+		uint64_t i_intr_timed_out:1;
+		uint64_t i_rsvd:7;
+		uint64_t i_cam_overflow:1;
+		uint64_t i_cam_read_miss:1;
+		uint64_t i_rsvd1:2;
+		uint64_t i_ioq_rep_underflow:1;
+		uint64_t i_ioq_req_underflow:1;
+		uint64_t i_ioq_rep_overflow:1;
+		uint64_t i_ioq_req_overflow:1;
+		uint64_t i_iiq_rep_overflow:1;
+		uint64_t i_iiq_req_overflow:1;
+		uint64_t i_rsvd2:6;
+		uint64_t i_ii_xn_rep_cred_overflow:1;
+		uint64_t i_ii_xn_req_cred_overflow:1;
+		uint64_t i_rsvd3:6;
+		uint64_t i_ii_xn_invalid_cmd:1;
+		uint64_t i_xn_ii_invalid_cmd:1;
+		uint64_t i_rsvd4:30;
 	} ii_iweim_fld_s;
 } ii_iweim_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  A write to this register causes a particular field in the           *
  * corresponding widget's PRB entry to be adjusted up or down by 1.     *
  * This counter should be used when recovering from error and reset     *
  * conditions. Note that software would be capable of causing           *
  * inadvertent overflow or underflow of these counters.                 *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ipca_u {
-	uint64_t	ii_ipca_regval;
-	struct  {
-		uint64_t	i_wid                     :	 4;
-		uint64_t	i_adjust		  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_field			  :	 2;
-		uint64_t	i_rsvd			  :	54;
+	uint64_t ii_ipca_regval;
+	struct {
+		uint64_t i_wid:4;
+		uint64_t i_adjust:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_field:2;
+		uint64_t i_rsvd:54;
 	} ii_ipca_fld_s;
 } ii_ipca_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
-
 typedef union ii_iprte0a_u {
-	uint64_t	ii_iprte0a_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t       i_vld                     :      1;
+	uint64_t ii_iprte0a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte0a_fld_s;
 } ii_iprte0a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte1a_u {
-	uint64_t	ii_iprte1a_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t       i_vld                     :      1;
+	uint64_t ii_iprte1a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte1a_fld_s;
 } ii_iprte1a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte2a_u {
-	uint64_t	ii_iprte2a_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t       i_vld                     :      1;
+	uint64_t ii_iprte2a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte2a_fld_s;
 } ii_iprte2a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte3a_u {
-	uint64_t	ii_iprte3a_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t	i_vld			  :	 1;
+	uint64_t ii_iprte3a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte3a_fld_s;
 } ii_iprte3a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte4a_u {
-	uint64_t	ii_iprte4a_regval;
-	struct	{
-		uint64_t	i_rsvd_1		  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t	i_vld			  :	 1;
+	uint64_t ii_iprte4a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte4a_fld_s;
 } ii_iprte4a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte5a_u {
-	uint64_t	ii_iprte5a_regval;
-	struct	{
-		uint64_t	i_rsvd_1		  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t	i_vld			  :	 1;
+	uint64_t ii_iprte5a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte5a_fld_s;
 } ii_iprte5a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte6a_u {
-	uint64_t	ii_iprte6a_regval;
-	struct	{
-		uint64_t	i_rsvd_1		  :	54;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t	i_vld			  :	 1;
+	uint64_t ii_iprte6a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} ii_iprte6a_fld_s;
 } ii_iprte6a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte7a_u {
-        uint64_t       ii_iprte7a_regval;
-        struct  {
-                uint64_t       i_rsvd_1                  :     54;
-                uint64_t       i_widget                  :      4;
-                uint64_t       i_to_cnt                  :      5;
-                uint64_t       i_vld                     :      1;
-        } ii_iprtea7_fld_s;
+	uint64_t ii_iprte7a_regval;
+	struct {
+		uint64_t i_rsvd_1:54;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
+	} ii_iprtea7_fld_s;
 } ii_iprte7a_u_t;
 
-
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
-
 typedef union ii_iprte0b_u {
-	uint64_t	ii_iprte0b_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte0b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte0b_fld_s;
 } ii_iprte0b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte1b_u {
-	uint64_t	ii_iprte1b_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte1b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte1b_fld_s;
 } ii_iprte1b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte2b_u {
-	uint64_t	ii_iprte2b_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte2b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte2b_fld_s;
 } ii_iprte2b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte3b_u {
-	uint64_t	ii_iprte3b_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte3b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte3b_fld_s;
 } ii_iprte3b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte4b_u {
-	uint64_t	ii_iprte4b_regval;
-	struct	{
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte4b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte4b_fld_s;
 } ii_iprte4b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte5b_u {
-	uint64_t	ii_iprte5b_regval;
-	struct	{
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte5b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 	} ii_iprte5b_fld_s;
 } ii_iprte5b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte6b_u {
-	uint64_t	ii_iprte6b_regval;
-	struct	{
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
+	uint64_t ii_iprte6b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
 
 	} ii_iprte6b_fld_s;
 } ii_iprte6b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  There are 8 instances of this register. This register contains      *
  * the information that the II has to remember once it has launched a   *
  * PIO Read operation. The contents are used to form the correct        *
  * Router Network packet and direct the Crosstalk reply to the          *
  * appropriate processor.                                               *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iprte7b_u {
-        uint64_t       ii_iprte7b_regval;
-        struct  {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_address		  :	47;
-		uint64_t	i_init			  :	 3;
-		uint64_t       i_source                  :     11;
-        } ii_iprte7b_fld_s;
+	uint64_t ii_iprte7b_regval;
+	struct {
+		uint64_t i_rsvd_1:3;
+		uint64_t i_address:47;
+		uint64_t i_init:3;
+		uint64_t i_source:11;
+	} ii_iprte7b_fld_s;
 } ii_iprte7b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  SHub II contains a feature which did not exist in      *
  * the Hub which automatically cleans up after a Read Response          *
  * timeout, including deallocation of the IPRTE and recovery of IBuf    *
@@ -2108,23 +2034,22 @@ typedef union ii_iprte7b_u {
  * Note that this register does not affect the contents of the IPRTE    *
  * registers. The Valid bits in those registers have to be              *
  * specifically turned off by software.                                 *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ipdr_u {
-	uint64_t	ii_ipdr_regval;
-	struct  {
-		uint64_t	i_te                      :	 3;
-		uint64_t	i_rsvd_1		  :	 1;
-		uint64_t	i_pnd			  :	 1;
-		uint64_t	i_init_rpcnt		  :	 1;
-		uint64_t	i_rsvd			  :	58;
+	uint64_t ii_ipdr_regval;
+	struct {
+		uint64_t i_te:3;
+		uint64_t i_rsvd_1:1;
+		uint64_t i_pnd:1;
+		uint64_t i_init_rpcnt:1;
+		uint64_t i_rsvd:58;
 	} ii_ipdr_fld_s;
 } ii_ipdr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  A write to this register causes a CRB entry to be returned to the   *
  * queue of free CRBs. The entry should have previously been cleared    *
  * (mark bit) via backdoor access to the pertinent CRB entry. This      *
@@ -2137,21 +2062,20 @@ typedef union ii_ipdr_u {
  * software clears the mark bit, and finally 4) software writes to      *
  * the ICDR register to return the CRB entry to the list of free CRB    *
  * entries.                                                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icdr_u {
-	uint64_t	ii_icdr_regval;
-	struct  {
-		uint64_t	i_crb_num                 :	 4;
-		uint64_t	i_pnd			  :	 1;
-		uint64_t       i_rsvd                    :     59;
+	uint64_t ii_icdr_regval;
+	struct {
+		uint64_t i_crb_num:4;
+		uint64_t i_pnd:1;
+		uint64_t i_rsvd:59;
 	} ii_icdr_fld_s;
 } ii_icdr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register provides debug access to two FIFOs inside of II.      *
  * Both IOQ_MAX* fields of this register contain the instantaneous      *
  * depth (in units of the number of available entries) of the           *
@@ -2164,130 +2088,124 @@ typedef union ii_icdr_u {
  * this register is written. If there are any active entries in any     *
  * of these FIFOs when this register is written, the results are        *
  * undefined.                                                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ifdr_u {
-	uint64_t	ii_ifdr_regval;
-	struct  {
-		uint64_t	i_ioq_max_rq              :	 7;
-		uint64_t	i_set_ioq_rq		  :	 1;
-		uint64_t	i_ioq_max_rp		  :	 7;
-		uint64_t	i_set_ioq_rp		  :	 1;
-		uint64_t	i_rsvd			  :	48;
+	uint64_t ii_ifdr_regval;
+	struct {
+		uint64_t i_ioq_max_rq:7;
+		uint64_t i_set_ioq_rq:1;
+		uint64_t i_ioq_max_rp:7;
+		uint64_t i_set_ioq_rp:1;
+		uint64_t i_rsvd:48;
 	} ii_ifdr_fld_s;
 } ii_ifdr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register allows the II to become sluggish in removing          *
  * messages from its inbound queue (IIQ). This will cause messages to   *
  * back up in either virtual channel. Disabling the "molasses" mode     *
  * subsequently allows the II to be tested under stress. In the         *
  * sluggish ("Molasses") mode, the localized effects of congestion      *
  * can be observed.                                                     *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iiap_u {
-        uint64_t       ii_iiap_regval;
-        struct  {
-                uint64_t       i_rq_mls                  :      6;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_rp_mls		  :	 6;
-		uint64_t       i_rsvd                    :     50;
-        } ii_iiap_fld_s;
+	uint64_t ii_iiap_regval;
+	struct {
+		uint64_t i_rq_mls:6;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_rp_mls:6;
+		uint64_t i_rsvd:50;
+	} ii_iiap_fld_s;
 } ii_iiap_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register allows several parameters of CRB operation to be      *
  * set. Note that writing to this register can have catastrophic side   *
  * effects, if the CRB is not quiescent, i.e. if the CRB is             *
  * processing protocol messages when the write occurs.                  *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icmr_u {
-	uint64_t	ii_icmr_regval;
-	struct  {
-		uint64_t	i_sp_msg                  :	 1;
-		uint64_t	i_rd_hdr		  :	 1;
-		uint64_t	i_rsvd_4		  :	 2;
-		uint64_t	i_c_cnt			  :	 4;
-		uint64_t	i_rsvd_3		  :	 4;
-		uint64_t	i_clr_rqpd		  :	 1;
-		uint64_t	i_clr_rppd		  :	 1;
-		uint64_t	i_rsvd_2		  :	 2;
-		uint64_t	i_fc_cnt		  :	 4;
-		uint64_t	i_crb_vld		  :	15;
-		uint64_t	i_crb_mark		  :	15;
-		uint64_t	i_rsvd_1		  :	 2;
-		uint64_t	i_precise		  :	 1;
-		uint64_t	i_rsvd			  :	11;
+	uint64_t ii_icmr_regval;
+	struct {
+		uint64_t i_sp_msg:1;
+		uint64_t i_rd_hdr:1;
+		uint64_t i_rsvd_4:2;
+		uint64_t i_c_cnt:4;
+		uint64_t i_rsvd_3:4;
+		uint64_t i_clr_rqpd:1;
+		uint64_t i_clr_rppd:1;
+		uint64_t i_rsvd_2:2;
+		uint64_t i_fc_cnt:4;
+		uint64_t i_crb_vld:15;
+		uint64_t i_crb_mark:15;
+		uint64_t i_rsvd_1:2;
+		uint64_t i_precise:1;
+		uint64_t i_rsvd:11;
 	} ii_icmr_fld_s;
 } ii_icmr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register allows control of the table portion of the CRB        *
  * logic via software. Control operations from this register have       *
  * priority over all incoming Crosstalk or BTE requests.                *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_iccr_u {
-	uint64_t	ii_iccr_regval;
-	struct  {
-		uint64_t	i_crb_num                 :	 4;
-		uint64_t	i_rsvd_1		  :	 4;
-		uint64_t	i_cmd			  :	 8;
-		uint64_t	i_pending		  :	 1;
-		uint64_t	i_rsvd			  :	47;
+	uint64_t ii_iccr_regval;
+	struct {
+		uint64_t i_crb_num:4;
+		uint64_t i_rsvd_1:4;
+		uint64_t i_cmd:8;
+		uint64_t i_pending:1;
+		uint64_t i_rsvd:47;
 	} ii_iccr_fld_s;
 } ii_iccr_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register allows the maximum timeout value to be programmed.    *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icto_u {
-	uint64_t	ii_icto_regval;
-	struct  {
-		uint64_t	i_timeout                 :	 8;
-		uint64_t	i_rsvd			  :	56;
+	uint64_t ii_icto_regval;
+	struct {
+		uint64_t i_timeout:8;
+		uint64_t i_rsvd:56;
 	} ii_icto_fld_s;
 } ii_icto_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register allows the timeout prescalar to be programmed. An     *
  * internal counter is associated with this register. When the          *
  * internal counter reaches the value of the PRESCALE field, the        *
  * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT]   *
  * field). The internal counter resets to zero, and then continues      *
  * counting.                                                            *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ictp_u {
-	uint64_t	ii_ictp_regval;
-	struct  {
-		uint64_t	i_prescale                :	24;
-		uint64_t	i_rsvd			  :	40;
+	uint64_t ii_ictp_regval;
+	struct {
+		uint64_t i_prescale:24;
+		uint64_t i_rsvd:40;
 	} ii_ictp_fld_s;
 } ii_ictp_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
  * used for Crosstalk operations (both cacheline and partial            *
  * operations) or BTE/IO. Because the CRB entries are very wide, five   *
@@ -2306,243 +2224,234 @@ typedef union ii_ictp_u {
  * recovering any potential error state from before the reset).         *
  * The following four tables summarize the format for the four          *
  * registers that are used for each ICRB# Entry.                        *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icrb0_a_u {
-	uint64_t	ii_icrb0_a_regval;
-	struct  {
-		uint64_t	ia_iow                    :	 1;
-		uint64_t	ia_vld			  :	 1;
-		uint64_t	ia_addr			  :	47;
-		uint64_t	ia_tnum			  :	 5;
-		uint64_t	ia_sidn			  :	 4;
-		uint64_t       ia_rsvd                   :      6;
+	uint64_t ii_icrb0_a_regval;
+	struct {
+		uint64_t ia_iow:1;
+		uint64_t ia_vld:1;
+		uint64_t ia_addr:47;
+		uint64_t ia_tnum:5;
+		uint64_t ia_sidn:4;
+		uint64_t ia_rsvd:6;
 	} ii_icrb0_a_fld_s;
 } ii_icrb0_a_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
  * used for Crosstalk operations (both cacheline and partial            *
  * operations) or BTE/IO. Because the CRB entries are very wide, five   *
  * registers (_A to _E) are required to read and write each entry.      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icrb0_b_u {
-	uint64_t	ii_icrb0_b_regval;
-	struct	{
-		uint64_t	ib_xt_err		  :	 1;
-		uint64_t	ib_mark			  :	 1;
-		uint64_t	ib_ln_uce		  :	 1;
-		uint64_t	ib_errcode		  :	 3;
-		uint64_t	ib_error		  :	 1;
-		uint64_t	ib_stall__bte_1		  :	 1;
-		uint64_t	ib_stall__bte_0		  :	 1;
-		uint64_t	ib_stall__intr		  :	 1;
-		uint64_t	ib_stall_ib		  :	 1;
-		uint64_t	ib_intvn		  :	 1;
-		uint64_t	ib_wb			  :	 1;
-		uint64_t	ib_hold			  :	 1;
-		uint64_t	ib_ack			  :	 1;
-		uint64_t	ib_resp			  :	 1;
-		uint64_t	ib_ack_cnt		  :	11;
-		uint64_t	ib_rsvd			  :	 7;
-		uint64_t	ib_exc			  :	 5;
-		uint64_t	ib_init			  :	 3;
-		uint64_t	ib_imsg			  :	 8;
-		uint64_t	ib_imsgtype		  :	 2;
-		uint64_t	ib_use_old		  :	 1;
-		uint64_t	ib_rsvd_1		  :	11;
+	uint64_t ii_icrb0_b_regval;
+	struct {
+		uint64_t ib_xt_err:1;
+		uint64_t ib_mark:1;
+		uint64_t ib_ln_uce:1;
+		uint64_t ib_errcode:3;
+		uint64_t ib_error:1;
+		uint64_t ib_stall__bte_1:1;
+		uint64_t ib_stall__bte_0:1;
+		uint64_t ib_stall__intr:1;
+		uint64_t ib_stall_ib:1;
+		uint64_t ib_intvn:1;
+		uint64_t ib_wb:1;
+		uint64_t ib_hold:1;
+		uint64_t ib_ack:1;
+		uint64_t ib_resp:1;
+		uint64_t ib_ack_cnt:11;
+		uint64_t ib_rsvd:7;
+		uint64_t ib_exc:5;
+		uint64_t ib_init:3;
+		uint64_t ib_imsg:8;
+		uint64_t ib_imsgtype:2;
+		uint64_t ib_use_old:1;
+		uint64_t ib_rsvd_1:11;
 	} ii_icrb0_b_fld_s;
 } ii_icrb0_b_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
  * used for Crosstalk operations (both cacheline and partial            *
  * operations) or BTE/IO. Because the CRB entries are very wide, five   *
  * registers (_A to _E) are required to read and write each entry.      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icrb0_c_u {
-	uint64_t	ii_icrb0_c_regval;
-	struct	{
-		uint64_t	ic_source		  :	15;
-		uint64_t	ic_size			  :	 2;
-		uint64_t	ic_ct			  :	 1;
-		uint64_t	ic_bte_num		  :	 1;
-		uint64_t	ic_gbr			  :	 1;
-		uint64_t	ic_resprqd		  :	 1;
-		uint64_t	ic_bo			  :	 1;
-		uint64_t	ic_suppl		  :	15;
-		uint64_t	ic_rsvd			  :	27;
+	uint64_t ii_icrb0_c_regval;
+	struct {
+		uint64_t ic_source:15;
+		uint64_t ic_size:2;
+		uint64_t ic_ct:1;
+		uint64_t ic_bte_num:1;
+		uint64_t ic_gbr:1;
+		uint64_t ic_resprqd:1;
+		uint64_t ic_bo:1;
+		uint64_t ic_suppl:15;
+		uint64_t ic_rsvd:27;
 	} ii_icrb0_c_fld_s;
 } ii_icrb0_c_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
  * used for Crosstalk operations (both cacheline and partial            *
  * operations) or BTE/IO. Because the CRB entries are very wide, five   *
  * registers (_A to _E) are required to read and write each entry.      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icrb0_d_u {
-	uint64_t	ii_icrb0_d_regval;
-	struct  {
-		uint64_t	id_pa_be                  :	43;
-		uint64_t	id_bte_op		  :	 1;
-		uint64_t	id_pr_psc		  :	 4;
-		uint64_t	id_pr_cnt		  :	 4;
-		uint64_t	id_sleep		  :	 1;
-		uint64_t	id_rsvd			  :	11;
+	uint64_t ii_icrb0_d_regval;
+	struct {
+		uint64_t id_pa_be:43;
+		uint64_t id_bte_op:1;
+		uint64_t id_pr_psc:4;
+		uint64_t id_pr_cnt:4;
+		uint64_t id_sleep:1;
+		uint64_t id_rsvd:11;
 	} ii_icrb0_d_fld_s;
 } ii_icrb0_d_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
  * used for Crosstalk operations (both cacheline and partial            *
  * operations) or BTE/IO. Because the CRB entries are very wide, five   *
  * registers (_A to _E) are required to read and write each entry.      *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icrb0_e_u {
-	uint64_t	ii_icrb0_e_regval;
-	struct  {
-		uint64_t	ie_timeout                :	 8;
-		uint64_t	ie_context		  :	15;
-		uint64_t	ie_rsvd			  :	 1;
-		uint64_t	ie_tvld			  :	 1;
-		uint64_t	ie_cvld			  :	 1;
-		uint64_t	ie_rsvd_0		  :	38;
+	uint64_t ii_icrb0_e_regval;
+	struct {
+		uint64_t ie_timeout:8;
+		uint64_t ie_context:15;
+		uint64_t ie_rsvd:1;
+		uint64_t ie_tvld:1;
+		uint64_t ie_cvld:1;
+		uint64_t ie_rsvd_0:38;
 	} ii_icrb0_e_fld_s;
 } ii_icrb0_e_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the lower 64 bits of the header of the       *
  * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
  * register is set.                                                     *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icsml_u {
-	uint64_t	ii_icsml_regval;
-	struct  {
-		uint64_t	i_tt_addr                 :	47;
-		uint64_t	i_newsuppl_ex		  :	14;
-		uint64_t	i_reserved		  :	 2;
-		uint64_t       i_overflow                :      1;
+	uint64_t ii_icsml_regval;
+	struct {
+		uint64_t i_tt_addr:47;
+		uint64_t i_newsuppl_ex:14;
+		uint64_t i_reserved:2;
+		uint64_t i_overflow:1;
 	} ii_icsml_fld_s;
 } ii_icsml_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the middle 64 bits of the header of the      *
  * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
  * register is set.                                                     *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icsmm_u {
-	uint64_t	ii_icsmm_regval;
-	struct  {
-		uint64_t	i_tt_ack_cnt              :	11;
-		uint64_t	i_reserved		  :	53;
+	uint64_t ii_icsmm_regval;
+	struct {
+		uint64_t i_tt_ack_cnt:11;
+		uint64_t i_reserved:53;
 	} ii_icsmm_fld_s;
 } ii_icsmm_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the microscopic state, all the inputs to     *
  * the protocol table, captured with the spurious message. Valid when   *
  * the SP_MSG bit in the ICMR register is set.                          *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_icsmh_u {
-	uint64_t	ii_icsmh_regval;
-	struct  {
-		uint64_t	i_tt_vld                  :	 1;
-		uint64_t	i_xerr			  :	 1;
-		uint64_t	i_ft_cwact_o		  :	 1;
-		uint64_t	i_ft_wact_o		  :	 1;
-		uint64_t       i_ft_active_o             :      1;
-		uint64_t	i_sync			  :	 1;
-		uint64_t	i_mnusg			  :	 1;
-		uint64_t	i_mnusz			  :	 1;
-		uint64_t	i_plusz			  :	 1;
-		uint64_t	i_plusg			  :	 1;
-		uint64_t	i_tt_exc		  :	 5;
-		uint64_t	i_tt_wb			  :	 1;
-		uint64_t	i_tt_hold		  :	 1;
-		uint64_t	i_tt_ack		  :	 1;
-		uint64_t	i_tt_resp		  :	 1;
-		uint64_t	i_tt_intvn		  :	 1;
-		uint64_t	i_g_stall_bte1		  :	 1;
-		uint64_t	i_g_stall_bte0		  :	 1;
-		uint64_t	i_g_stall_il		  :	 1;
-		uint64_t	i_g_stall_ib		  :	 1;
-		uint64_t	i_tt_imsg		  :	 8;
-		uint64_t	i_tt_imsgtype		  :	 2;
-		uint64_t	i_tt_use_old		  :	 1;
-		uint64_t	i_tt_respreqd		  :	 1;
-		uint64_t	i_tt_bte_num		  :	 1;
-		uint64_t	i_cbn			  :	 1;
-		uint64_t	i_match			  :	 1;
-		uint64_t	i_rpcnt_lt_34		  :	 1;
-		uint64_t	i_rpcnt_ge_34		  :	 1;
-		uint64_t	i_rpcnt_lt_18		  :	 1;
-		uint64_t	i_rpcnt_ge_18		  :	 1;
-		uint64_t       i_rpcnt_lt_2              :      1;
-		uint64_t	i_rpcnt_ge_2		  :	 1;
-		uint64_t	i_rqcnt_lt_18		  :	 1;
-		uint64_t	i_rqcnt_ge_18		  :	 1;
-		uint64_t	i_rqcnt_lt_2		  :	 1;
-		uint64_t	i_rqcnt_ge_2		  :	 1;
-		uint64_t	i_tt_device		  :	 7;
-		uint64_t	i_tt_init		  :	 3;
-		uint64_t	i_reserved		  :	 5;
+	uint64_t ii_icsmh_regval;
+	struct {
+		uint64_t i_tt_vld:1;
+		uint64_t i_xerr:1;
+		uint64_t i_ft_cwact_o:1;
+		uint64_t i_ft_wact_o:1;
+		uint64_t i_ft_active_o:1;
+		uint64_t i_sync:1;
+		uint64_t i_mnusg:1;
+		uint64_t i_mnusz:1;
+		uint64_t i_plusz:1;
+		uint64_t i_plusg:1;
+		uint64_t i_tt_exc:5;
+		uint64_t i_tt_wb:1;
+		uint64_t i_tt_hold:1;
+		uint64_t i_tt_ack:1;
+		uint64_t i_tt_resp:1;
+		uint64_t i_tt_intvn:1;
+		uint64_t i_g_stall_bte1:1;
+		uint64_t i_g_stall_bte0:1;
+		uint64_t i_g_stall_il:1;
+		uint64_t i_g_stall_ib:1;
+		uint64_t i_tt_imsg:8;
+		uint64_t i_tt_imsgtype:2;
+		uint64_t i_tt_use_old:1;
+		uint64_t i_tt_respreqd:1;
+		uint64_t i_tt_bte_num:1;
+		uint64_t i_cbn:1;
+		uint64_t i_match:1;
+		uint64_t i_rpcnt_lt_34:1;
+		uint64_t i_rpcnt_ge_34:1;
+		uint64_t i_rpcnt_lt_18:1;
+		uint64_t i_rpcnt_ge_18:1;
+		uint64_t i_rpcnt_lt_2:1;
+		uint64_t i_rpcnt_ge_2:1;
+		uint64_t i_rqcnt_lt_18:1;
+		uint64_t i_rqcnt_ge_18:1;
+		uint64_t i_rqcnt_lt_2:1;
+		uint64_t i_rqcnt_ge_2:1;
+		uint64_t i_tt_device:7;
+		uint64_t i_tt_init:3;
+		uint64_t i_reserved:5;
 	} ii_icsmh_fld_s;
 } ii_icsmh_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  The Shub DEBUG unit provides a 3-bit selection signal to the        *
  * II core and a 3-bit selection signal to the fsbclk domain in the II  *
  * wrapper.                                                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_idbss_u {
-	uint64_t	ii_idbss_regval;
-	struct  {
-		uint64_t	i_iioclk_core_submenu     :	 3;
-		uint64_t	i_rsvd			  :	 5;
-		uint64_t	i_fsbclk_wrapper_submenu  :	 3;
-		uint64_t	i_rsvd_1		  :	 5;
-		uint64_t	i_iioclk_menu		  :	 5;
-		uint64_t	i_rsvd_2		  :	43;
+	uint64_t ii_idbss_regval;
+	struct {
+		uint64_t i_iioclk_core_submenu:3;
+		uint64_t i_rsvd:5;
+		uint64_t i_fsbclk_wrapper_submenu:3;
+		uint64_t i_rsvd_1:5;
+		uint64_t i_iioclk_menu:5;
+		uint64_t i_rsvd_2:43;
 	} ii_idbss_fld_s;
 } ii_idbss_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register is used to set up the length for a       *
  * transfer and then to monitor the progress of that transfer. This     *
  * register needs to be initialized before a transfer is started. A     *
@@ -2553,63 +2462,60 @@ typedef union ii_idbss_u {
  * transfer completes, hardware will clear the Busy bit. The length     *
  * field will also contain the number of cache lines left to be         *
  * transferred.                                                         *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibls0_u {
-	uint64_t	ii_ibls0_regval;
-	struct	{
-		uint64_t	i_length		  :	16;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_busy			  :	 1;
-		uint64_t       i_rsvd                    :     43;
+	uint64_t ii_ibls0_regval;
+	struct {
+		uint64_t i_length:16;
+		uint64_t i_error:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_busy:1;
+		uint64_t i_rsvd:43;
 	} ii_ibls0_fld_s;
 } ii_ibls0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register should be loaded before a transfer is started. The    *
  * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
  * address as described in Section 1.3, Figure2 and Figure3. Since      *
  * the bottom 7 bits of the address are always taken to be zero, BTE    *
  * transfers are always cacheline-aligned.                              *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibsa0_u {
-	uint64_t	ii_ibsa0_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	42;
-		uint64_t       i_rsvd                    :     15;
+	uint64_t ii_ibsa0_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:42;
+		uint64_t i_rsvd:15;
 	} ii_ibsa0_fld_s;
 } ii_ibsa0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register should be loaded before a transfer is started. The    *
  * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
  * address as described in Section 1.3, Figure2 and Figure3. Since      *
  * the bottom 7 bits of the address are always taken to be zero, BTE    *
  * transfers are always cacheline-aligned.                              *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibda0_u {
-	uint64_t	ii_ibda0_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	42;
-		uint64_t	i_rsvd			  :	15;
+	uint64_t ii_ibda0_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:42;
+		uint64_t i_rsvd:15;
 	} ii_ibda0_fld_s;
 } ii_ibda0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  Writing to this register sets up the attributes of the transfer     *
  * and initiates the transfer operation. Reading this register has      *
  * the side effect of terminating any transfer in progress. Note:       *
@@ -2617,61 +2523,58 @@ typedef union ii_ibda0_u {
  * other BTE. If a BTE stream has to be stopped (due to error           *
  * handling for example), both BTE streams should be stopped and        *
  * their transfers discarded.                                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibct0_u {
-	uint64_t	ii_ibct0_regval;
-	struct  {
-		uint64_t	i_zerofill                :	 1;
-		uint64_t	i_rsvd_2		  :	 3;
-		uint64_t	i_notify		  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t       i_poison                  :      1;
-		uint64_t       i_rsvd                    :     55;
+	uint64_t ii_ibct0_regval;
+	struct {
+		uint64_t i_zerofill:1;
+		uint64_t i_rsvd_2:3;
+		uint64_t i_notify:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_poison:1;
+		uint64_t i_rsvd:55;
 	} ii_ibct0_fld_s;
 } ii_ibct0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the address to which the WINV is sent.       *
  * This address has to be cache line aligned.                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibna0_u {
-	uint64_t	ii_ibna0_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	42;
-		uint64_t	i_rsvd			  :	15;
+	uint64_t ii_ibna0_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:42;
+		uint64_t i_rsvd:15;
 	} ii_ibna0_fld_s;
 } ii_ibna0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the programmable level as well as the node   *
  * ID and PI unit of the processor to which the interrupt will be       *
- * sent.                                                                *
- *                                                                      *
+ * sent.								*
+ *									*
  ************************************************************************/
 
 typedef union ii_ibia0_u {
-	uint64_t	ii_ibia0_regval;
-	struct  {
-		uint64_t	i_rsvd_2                   :	 1;
-		uint64_t	i_node_id		  :	11;
-		uint64_t	i_rsvd_1		  :	 4;
-		uint64_t	i_level			  :	 7;
-		uint64_t       i_rsvd                    :     41;
+	uint64_t ii_ibia0_regval;
+	struct {
+		uint64_t i_rsvd_2:1;
+		uint64_t i_node_id:11;
+		uint64_t i_rsvd_1:4;
+		uint64_t i_level:7;
+		uint64_t i_rsvd:41;
 	} ii_ibia0_fld_s;
 } ii_ibia0_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  * Description:  This register is used to set up the length for a       *
  * transfer and then to monitor the progress of that transfer. This     *
  * register needs to be initialized before a transfer is started. A     *
@@ -2682,63 +2585,60 @@ typedef union ii_ibia0_u {
  * transfer completes, hardware will clear the Busy bit. The length     *
  * field will also contain the number of cache lines left to be         *
  * transferred.                                                         *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibls1_u {
-	uint64_t	ii_ibls1_regval;
-	struct  {
-		uint64_t	i_length                  :	16;
-		uint64_t	i_error			  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_busy			  :	 1;
-		uint64_t       i_rsvd                    :     43;
+	uint64_t ii_ibls1_regval;
+	struct {
+		uint64_t i_length:16;
+		uint64_t i_error:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_busy:1;
+		uint64_t i_rsvd:43;
 	} ii_ibls1_fld_s;
 } ii_ibls1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register should be loaded before a transfer is started. The    *
  * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
  * address as described in Section 1.3, Figure2 and Figure3. Since      *
  * the bottom 7 bits of the address are always taken to be zero, BTE    *
  * transfers are always cacheline-aligned.                              *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibsa1_u {
-	uint64_t	ii_ibsa1_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	33;
-		uint64_t	i_rsvd			  :	24;
+	uint64_t ii_ibsa1_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:33;
+		uint64_t i_rsvd:24;
 	} ii_ibsa1_fld_s;
 } ii_ibsa1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register should be loaded before a transfer is started. The    *
  * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
  * address as described in Section 1.3, Figure2 and Figure3. Since      *
  * the bottom 7 bits of the address are always taken to be zero, BTE    *
  * transfers are always cacheline-aligned.                              *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibda1_u {
-	uint64_t	ii_ibda1_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	33;
-		uint64_t	i_rsvd			  :	24;
+	uint64_t ii_ibda1_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:33;
+		uint64_t i_rsvd:24;
 	} ii_ibda1_fld_s;
 } ii_ibda1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  Writing to this register sets up the attributes of the transfer     *
  * and initiates the transfer operation. Reading this register has      *
  * the side effect of terminating any transfer in progress. Note:       *
@@ -2746,61 +2646,58 @@ typedef union ii_ibda1_u {
  * other BTE. If a BTE stream has to be stopped (due to error           *
  * handling for example), both BTE streams should be stopped and        *
  * their transfers discarded.                                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibct1_u {
-	uint64_t	ii_ibct1_regval;
-	struct  {
-		uint64_t	i_zerofill                :	 1;
-		uint64_t	i_rsvd_2		  :	 3;
-		uint64_t	i_notify		  :	 1;
-		uint64_t	i_rsvd_1		  :	 3;
-		uint64_t	i_poison		  :	 1;
-		uint64_t	i_rsvd			  :	55;
+	uint64_t ii_ibct1_regval;
+	struct {
+		uint64_t i_zerofill:1;
+		uint64_t i_rsvd_2:3;
+		uint64_t i_notify:1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_poison:1;
+		uint64_t i_rsvd:55;
 	} ii_ibct1_fld_s;
 } ii_ibct1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the address to which the WINV is sent.       *
  * This address has to be cache line aligned.                           *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ibna1_u {
-	uint64_t	ii_ibna1_regval;
-	struct  {
-		uint64_t	i_rsvd_1                  :	 7;
-		uint64_t	i_addr			  :	33;
-		uint64_t       i_rsvd                    :     24;
+	uint64_t ii_ibna1_regval;
+	struct {
+		uint64_t i_rsvd_1:7;
+		uint64_t i_addr:33;
+		uint64_t i_rsvd:24;
 	} ii_ibna1_fld_s;
 } ii_ibna1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register contains the programmable level as well as the node   *
  * ID and PI unit of the processor to which the interrupt will be       *
- * sent.                                                                *
- *                                                                      *
+ * sent.								*
+ *									*
  ************************************************************************/
 
 typedef union ii_ibia1_u {
-	uint64_t	ii_ibia1_regval;
-	struct  {
-		uint64_t	i_pi_id                   :	 1;
-		uint64_t	i_node_id		  :	 8;
-		uint64_t	i_rsvd_1		  :	 7;
-		uint64_t	i_level			  :	 7;
-		uint64_t	i_rsvd			  :	41;
+	uint64_t ii_ibia1_regval;
+	struct {
+		uint64_t i_pi_id:1;
+		uint64_t i_node_id:8;
+		uint64_t i_rsvd_1:7;
+		uint64_t i_level:7;
+		uint64_t i_rsvd:41;
 	} ii_ibia1_fld_s;
 } ii_ibia1_u_t;
 
-
 /************************************************************************
- *                                                                      *
+ *									*
  *  This register defines the resources that feed information into      *
  * the two performance counters located in the IO Performance           *
  * Profiling Register. There are 17 different quantities that can be    *
@@ -2811,133 +2708,129 @@ typedef union ii_ibia1_u {
  * other is available from the other performance counter. Hence, the    *
  * II supports all 17*16=272 possible combinations of quantities to     *
  * measure.                                                             *
- *                                                                      *
+ *									*
  ************************************************************************/
 
 typedef union ii_ipcr_u {
-	uint64_t	ii_ipcr_regval;
-	struct  {
-		uint64_t	i_ippr0_c                 :	 4;
-		uint64_t	i_ippr1_c		  :	 4;
-		uint64_t	i_icct			  :	 8;
-		uint64_t       i_rsvd                    :     48;
+	uint64_t ii_ipcr_regval;
+	struct {
+		uint64_t i_ippr0_c:4;
+		uint64_t i_ippr1_c:4;
+		uint64_t i_icct:8;
+		uint64_t i_rsvd:48;
 	} ii_ipcr_fld_s;
 } ii_ipcr_u_t;
 
-
 /************************************************************************
- *                                                                      *
- *                                                                      *
- *                                                                      *
+ *									*
+ *									*
+ *									*
  ************************************************************************/
 
 typedef union ii_ippr_u {
-	uint64_t	ii_ippr_regval;
-	struct  {
-		uint64_t	i_ippr0                   :	32;
-		uint64_t	i_ippr1			  :	32;
+	uint64_t ii_ippr_regval;
+	struct {
+		uint64_t i_ippr0:32;
+		uint64_t i_ippr1:32;
 	} ii_ippr_fld_s;
 } ii_ippr_u_t;
 
-
-
-/**************************************************************************
- *                                                                        *
- * The following defines which were not formed into structures are        *
- * probably indentical to another register, and the name of the           *
- * register is provided against each of these registers. This             *
- * information needs to be checked carefully                              *
- *                                                                        *
- *           IIO_ICRB1_A                IIO_ICRB0_A                       *
- *           IIO_ICRB1_B                IIO_ICRB0_B                       *
- *           IIO_ICRB1_C                IIO_ICRB0_C                       *
- *           IIO_ICRB1_D                IIO_ICRB0_D                       *
- *           IIO_ICRB1_E                IIO_ICRB0_E                       *
- *           IIO_ICRB2_A                IIO_ICRB0_A                       *
- *           IIO_ICRB2_B                IIO_ICRB0_B                       *
- *           IIO_ICRB2_C                IIO_ICRB0_C                       *
- *           IIO_ICRB2_D                IIO_ICRB0_D                       *
- *           IIO_ICRB2_E                IIO_ICRB0_E                       *
- *           IIO_ICRB3_A                IIO_ICRB0_A                       *
- *           IIO_ICRB3_B                IIO_ICRB0_B                       *
- *           IIO_ICRB3_C                IIO_ICRB0_C                       *
- *           IIO_ICRB3_D                IIO_ICRB0_D                       *
- *           IIO_ICRB3_E                IIO_ICRB0_E                       *
- *           IIO_ICRB4_A                IIO_ICRB0_A                       *
- *           IIO_ICRB4_B                IIO_ICRB0_B                       *
- *           IIO_ICRB4_C                IIO_ICRB0_C                       *
- *           IIO_ICRB4_D                IIO_ICRB0_D                       *
- *           IIO_ICRB4_E                IIO_ICRB0_E                       *
- *           IIO_ICRB5_A                IIO_ICRB0_A                       *
- *           IIO_ICRB5_B                IIO_ICRB0_B                       *
- *           IIO_ICRB5_C                IIO_ICRB0_C                       *
- *           IIO_ICRB5_D                IIO_ICRB0_D                       *
- *           IIO_ICRB5_E                IIO_ICRB0_E                       *
- *           IIO_ICRB6_A                IIO_ICRB0_A                       *
- *           IIO_ICRB6_B                IIO_ICRB0_B                       *
- *           IIO_ICRB6_C                IIO_ICRB0_C                       *
- *           IIO_ICRB6_D                IIO_ICRB0_D                       *
- *           IIO_ICRB6_E                IIO_ICRB0_E                       *
- *           IIO_ICRB7_A                IIO_ICRB0_A                       *
- *           IIO_ICRB7_B                IIO_ICRB0_B                       *
- *           IIO_ICRB7_C                IIO_ICRB0_C                       *
- *           IIO_ICRB7_D                IIO_ICRB0_D                       *
- *           IIO_ICRB7_E                IIO_ICRB0_E                       *
- *           IIO_ICRB8_A                IIO_ICRB0_A                       *
- *           IIO_ICRB8_B                IIO_ICRB0_B                       *
- *           IIO_ICRB8_C                IIO_ICRB0_C                       *
- *           IIO_ICRB8_D                IIO_ICRB0_D                       *
- *           IIO_ICRB8_E                IIO_ICRB0_E                       *
- *           IIO_ICRB9_A                IIO_ICRB0_A                       *
- *           IIO_ICRB9_B                IIO_ICRB0_B                       *
- *           IIO_ICRB9_C                IIO_ICRB0_C                       *
- *           IIO_ICRB9_D                IIO_ICRB0_D                       *
- *           IIO_ICRB9_E                IIO_ICRB0_E                       *
- *           IIO_ICRBA_A                IIO_ICRB0_A                       *
- *           IIO_ICRBA_B                IIO_ICRB0_B                       *
- *           IIO_ICRBA_C                IIO_ICRB0_C                       *
- *           IIO_ICRBA_D                IIO_ICRB0_D                       *
- *           IIO_ICRBA_E                IIO_ICRB0_E                       *
- *           IIO_ICRBB_A                IIO_ICRB0_A                       *
- *           IIO_ICRBB_B                IIO_ICRB0_B                       *
- *           IIO_ICRBB_C                IIO_ICRB0_C                       *
- *           IIO_ICRBB_D                IIO_ICRB0_D                       *
- *           IIO_ICRBB_E                IIO_ICRB0_E                       *
- *           IIO_ICRBC_A                IIO_ICRB0_A                       *
- *           IIO_ICRBC_B                IIO_ICRB0_B                       *
- *           IIO_ICRBC_C                IIO_ICRB0_C                       *
- *           IIO_ICRBC_D                IIO_ICRB0_D                       *
- *           IIO_ICRBC_E                IIO_ICRB0_E                       *
- *           IIO_ICRBD_A                IIO_ICRB0_A                       *
- *           IIO_ICRBD_B                IIO_ICRB0_B                       *
- *           IIO_ICRBD_C                IIO_ICRB0_C                       *
- *           IIO_ICRBD_D                IIO_ICRB0_D                       *
- *           IIO_ICRBD_E                IIO_ICRB0_E                       *
- *           IIO_ICRBE_A                IIO_ICRB0_A                       *
- *           IIO_ICRBE_B                IIO_ICRB0_B                       *
- *           IIO_ICRBE_C                IIO_ICRB0_C                       *
- *           IIO_ICRBE_D                IIO_ICRB0_D                       *
- *           IIO_ICRBE_E                IIO_ICRB0_E                       *
- *                                                                        *
- **************************************************************************/
-
+/************************************************************************
+ *									*
+ * The following defines which were not formed into structures are	*
+ * probably indentical to another register, and the name of the		*
+ * register is provided against each of these registers. This		*
+ * information needs to be checked carefully				*
+ *									*
+ *		IIO_ICRB1_A		IIO_ICRB0_A			*
+ *		IIO_ICRB1_B		IIO_ICRB0_B			*
+ *		IIO_ICRB1_C		IIO_ICRB0_C			*
+ *		IIO_ICRB1_D		IIO_ICRB0_D			*
+ *		IIO_ICRB1_E		IIO_ICRB0_E			*
+ *		IIO_ICRB2_A		IIO_ICRB0_A			*
+ *		IIO_ICRB2_B		IIO_ICRB0_B			*
+ *		IIO_ICRB2_C		IIO_ICRB0_C			*
+ *		IIO_ICRB2_D		IIO_ICRB0_D			*
+ *		IIO_ICRB2_E		IIO_ICRB0_E			*
+ *		IIO_ICRB3_A		IIO_ICRB0_A			*
+ *		IIO_ICRB3_B		IIO_ICRB0_B			*
+ *		IIO_ICRB3_C		IIO_ICRB0_C			*
+ *		IIO_ICRB3_D		IIO_ICRB0_D			*
+ *		IIO_ICRB3_E		IIO_ICRB0_E			*
+ *		IIO_ICRB4_A		IIO_ICRB0_A			*
+ *		IIO_ICRB4_B		IIO_ICRB0_B			*
+ *		IIO_ICRB4_C		IIO_ICRB0_C			*
+ *		IIO_ICRB4_D		IIO_ICRB0_D			*
+ *		IIO_ICRB4_E		IIO_ICRB0_E			*
+ *		IIO_ICRB5_A		IIO_ICRB0_A			*
+ *		IIO_ICRB5_B		IIO_ICRB0_B			*
+ *		IIO_ICRB5_C		IIO_ICRB0_C			*
+ *		IIO_ICRB5_D		IIO_ICRB0_D			*
+ *		IIO_ICRB5_E		IIO_ICRB0_E			*
+ *		IIO_ICRB6_A		IIO_ICRB0_A			*
+ *		IIO_ICRB6_B		IIO_ICRB0_B			*
+ *		IIO_ICRB6_C		IIO_ICRB0_C			*
+ *		IIO_ICRB6_D		IIO_ICRB0_D			*
+ *		IIO_ICRB6_E		IIO_ICRB0_E			*
+ *		IIO_ICRB7_A		IIO_ICRB0_A			*
+ *		IIO_ICRB7_B		IIO_ICRB0_B			*
+ *		IIO_ICRB7_C		IIO_ICRB0_C			*
+ *		IIO_ICRB7_D		IIO_ICRB0_D			*
+ *		IIO_ICRB7_E		IIO_ICRB0_E			*
+ *		IIO_ICRB8_A		IIO_ICRB0_A			*
+ *		IIO_ICRB8_B		IIO_ICRB0_B			*
+ *		IIO_ICRB8_C		IIO_ICRB0_C			*
+ *		IIO_ICRB8_D		IIO_ICRB0_D			*
+ *		IIO_ICRB8_E		IIO_ICRB0_E			*
+ *		IIO_ICRB9_A		IIO_ICRB0_A			*
+ *		IIO_ICRB9_B		IIO_ICRB0_B			*
+ *		IIO_ICRB9_C		IIO_ICRB0_C			*
+ *		IIO_ICRB9_D		IIO_ICRB0_D			*
+ *		IIO_ICRB9_E		IIO_ICRB0_E			*
+ *		IIO_ICRBA_A		IIO_ICRB0_A			*
+ *		IIO_ICRBA_B		IIO_ICRB0_B			*
+ *		IIO_ICRBA_C		IIO_ICRB0_C			*
+ *		IIO_ICRBA_D		IIO_ICRB0_D			*
+ *		IIO_ICRBA_E		IIO_ICRB0_E			*
+ *		IIO_ICRBB_A		IIO_ICRB0_A			*
+ *		IIO_ICRBB_B		IIO_ICRB0_B			*
+ *		IIO_ICRBB_C		IIO_ICRB0_C			*
+ *		IIO_ICRBB_D		IIO_ICRB0_D			*
+ *		IIO_ICRBB_E		IIO_ICRB0_E			*
+ *		IIO_ICRBC_A		IIO_ICRB0_A			*
+ *		IIO_ICRBC_B		IIO_ICRB0_B			*
+ *		IIO_ICRBC_C		IIO_ICRB0_C			*
+ *		IIO_ICRBC_D		IIO_ICRB0_D			*
+ *		IIO_ICRBC_E		IIO_ICRB0_E			*
+ *		IIO_ICRBD_A		IIO_ICRB0_A			*
+ *		IIO_ICRBD_B		IIO_ICRB0_B			*
+ *		IIO_ICRBD_C		IIO_ICRB0_C			*
+ *		IIO_ICRBD_D		IIO_ICRB0_D			*
+ *		IIO_ICRBD_E		IIO_ICRB0_E			*
+ *		IIO_ICRBE_A		IIO_ICRB0_A			*
+ *		IIO_ICRBE_B		IIO_ICRB0_B			*
+ *		IIO_ICRBE_C		IIO_ICRB0_C			*
+ *		IIO_ICRBE_D		IIO_ICRB0_D			*
+ *		IIO_ICRBE_E		IIO_ICRB0_E			*
+ *									*
+ ************************************************************************/
 
 /*
  * Slightly friendlier names for some common registers.
  */
-#define IIO_WIDGET              IIO_WID      /* Widget identification */
-#define IIO_WIDGET_STAT         IIO_WSTAT    /* Widget status register */
-#define IIO_WIDGET_CTRL         IIO_WCR      /* Widget control register */
-#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 */
-#define IIO_INWIDGET_ACCESS     IIO_IIWA     /* Inbound widget access */
-#define IIO_INDEV_ERR_MASK      IIO_IIDEM    /* Inbound device error mask */
-#define IIO_LLP_CSR             IIO_ILCSR    /* LLP control and status */
-#define IIO_LLP_LOG             IIO_ILLR     /* LLP log */
-#define IIO_XTALKCC_TOUT        IIO_IXCC     /* Xtalk credit count timeout*/
-#define IIO_XTALKTT_TOUT        IIO_IXTT     /* Xtalk tail timeout */
-#define IIO_IO_ERR_CLR          IIO_IECLR    /* IO error clear */
+#define IIO_WIDGET              IIO_WID		/* Widget identification */
+#define IIO_WIDGET_STAT         IIO_WSTAT	/* Widget status register */
+#define IIO_WIDGET_CTRL         IIO_WCR		/* Widget control register */
+#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 */
+#define IIO_INWIDGET_ACCESS     IIO_IIWA	/* Inbound widget access */
+#define IIO_INDEV_ERR_MASK      IIO_IIDEM	/* Inbound device error mask */
+#define IIO_LLP_CSR             IIO_ILCSR	/* LLP control and status */
+#define IIO_LLP_LOG             IIO_ILLR	/* LLP log */
+#define IIO_XTALKCC_TOUT        IIO_IXCC	/* Xtalk credit count timeout */
+#define IIO_XTALKTT_TOUT        IIO_IXTT	/* Xtalk tail timeout */
+#define IIO_IO_ERR_CLR          IIO_IECLR	/* IO error clear */
 #define IIO_IGFX_0 		IIO_IGFX0
 #define IIO_IGFX_1 		IIO_IGFX1
 #define IIO_IBCT_0		IIO_IBCT0
@@ -2957,12 +2850,12 @@ typedef union ii_ippr_u {
 #define IIO_PRTE_A(_x)		(IIO_IPRTE0_A + (8 * (_x)))
 #define IIO_PRTE_B(_x)		(IIO_IPRTE0_B + (8 * (_x)))
 #define IIO_NUM_PRTES		8	/* Total number of PRB table entries */
-#define IIO_WIDPRTE_A(x)	IIO_PRTE_A(((x) - 8)) /* widget ID to its PRTE num */
-#define IIO_WIDPRTE_B(x)	IIO_PRTE_B(((x) - 8)) /* widget ID to its PRTE num */
+#define IIO_WIDPRTE_A(x)	IIO_PRTE_A(((x) - 8))	/* widget ID to its PRTE num */
+#define IIO_WIDPRTE_B(x)	IIO_PRTE_B(((x) - 8))	/* widget ID to its PRTE num */
 
-#define IIO_NUM_IPRBS 		(9) 
+#define IIO_NUM_IPRBS 		9
 
-#define IIO_LLP_CSR_IS_UP               0x00002000
+#define IIO_LLP_CSR_IS_UP		0x00002000
 #define IIO_LLP_CSR_LLP_STAT_MASK       0x00003000
 #define IIO_LLP_CSR_LLP_STAT_SHFT       12
 
@@ -2970,30 +2863,29 @@ typedef union ii_ippr_u {
 #define IIO_LLP_SN_MAX  0xffff	/* in ILLR SN_CNT, Max Sequence Number errors */
 
 /* key to IIO_PROTECT_OVRRD */
-#define IIO_PROTECT_OVRRD_KEY   0x53474972756c6573ull   /* "SGIrules" */
+#define IIO_PROTECT_OVRRD_KEY   0x53474972756c6573ull	/* "SGIrules" */
 
 /* BTE register names */
-#define IIO_BTE_STAT_0          IIO_IBLS_0   /* Also BTE length/status 0 */
-#define IIO_BTE_SRC_0           IIO_IBSA_0   /* Also BTE source address  0 */
-#define IIO_BTE_DEST_0          IIO_IBDA_0   /* Also BTE dest. address 0 */
-#define IIO_BTE_CTRL_0          IIO_IBCT_0   /* Also BTE control/terminate 0 */
-#define IIO_BTE_NOTIFY_0        IIO_IBNA_0   /* Also BTE notification 0 */
-#define IIO_BTE_INT_0           IIO_IBIA_0   /* Also BTE interrupt 0 */
-#define IIO_BTE_OFF_0           0            /* Base offset from BTE 0 regs. */
-#define IIO_BTE_OFF_1   	(IIO_IBLS_1 - IIO_IBLS_0) /* Offset from base to BTE 1 */
+#define IIO_BTE_STAT_0          IIO_IBLS_0	/* Also BTE length/status 0 */
+#define IIO_BTE_SRC_0           IIO_IBSA_0	/* Also BTE source address  0 */
+#define IIO_BTE_DEST_0          IIO_IBDA_0	/* Also BTE dest. address 0 */
+#define IIO_BTE_CTRL_0          IIO_IBCT_0	/* Also BTE control/terminate 0 */
+#define IIO_BTE_NOTIFY_0        IIO_IBNA_0	/* Also BTE notification 0 */
+#define IIO_BTE_INT_0           IIO_IBIA_0	/* Also BTE interrupt 0 */
+#define IIO_BTE_OFF_0           0	/* Base offset from BTE 0 regs. */
+#define IIO_BTE_OFF_1   	(IIO_IBLS_1 - IIO_IBLS_0)	/* Offset from base to BTE 1 */
 
 /* BTE register offsets from base */
 #define BTEOFF_STAT             0
-#define BTEOFF_SRC              (IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
-#define BTEOFF_DEST             (IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
-#define BTEOFF_CTRL             (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
-#define BTEOFF_NOTIFY           (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
-#define BTEOFF_INT              (IIO_BTE_INT_0 - IIO_BTE_STAT_0)
-
+#define BTEOFF_SRC      	(IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
+#define BTEOFF_DEST     	(IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
+#define BTEOFF_CTRL     	(IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
+#define BTEOFF_NOTIFY   	(IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
+#define BTEOFF_INT      	(IIO_BTE_INT_0 - IIO_BTE_STAT_0)
 
 /* names used in shub diags */
-#define IIO_BASE_BTE0   IIO_IBLS_0		
-#define IIO_BASE_BTE1   IIO_IBLS_1		
+#define IIO_BASE_BTE0   IIO_IBLS_0
+#define IIO_BASE_BTE1   IIO_IBLS_1
 
 /*
  * Macro which takes the widget number, and returns the
@@ -3001,10 +2893,9 @@ typedef union ii_ippr_u {
  * 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 ? \
-                        (_x) : \
-                        (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) )
-
+#define IIO_IOPRB(_x)	(IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \
+                	(_x) : \
+                	(_x) - (HUB_WIDGET_ID_MIN-1)) << 3) )
 
 /* GFX Flow Control Node/Widget Register */
 #define IIO_IGFX_W_NUM_BITS	4	/* size of widget num field */
@@ -3025,7 +2916,6 @@ typedef union ii_ippr_u {
 	(((node)   & IIO_IGFX_N_NUM_MASK) << IIO_IGFX_N_NUM_SHIFT) |	 \
 	(((cpu)    & IIO_IGFX_P_NUM_MASK) << IIO_IGFX_P_NUM_SHIFT))
 
-
 /* Scratch registers (all bits available) */
 #define IIO_SCRATCH_REG0        IIO_ISCR0
 #define IIO_SCRATCH_REG1        IIO_ISCR1
@@ -3046,21 +2936,21 @@ typedef union ii_ippr_u {
 #define IIO_SCRATCH_BIT1_0      0x0000000000000001UL
 #define IIO_SCRATCH_BIT1_1      0x0000000000000002UL
 /* IO Translation Table Entries */
-#define IIO_NUM_ITTES   7               /* ITTEs numbered 0..6 */
-                                        /* Hw manuals number them 1..7! */
+#define IIO_NUM_ITTES   7	/* ITTEs numbered 0..6 */
+					/* Hw manuals number them 1..7! */
 /*
  * IIO_IMEM Register fields.
  */
-#define IIO_IMEM_W0ESD  0x1UL             /* Widget 0 shut down due to error */
-#define IIO_IMEM_B0ESD  (1UL << 4)        /* BTE 0 shut down due to error */
-#define IIO_IMEM_B1ESD  (1UL << 8)        /* BTE 1 Shut down due to error */
+#define IIO_IMEM_W0ESD  0x1UL	/* Widget 0 shut down due to error */
+#define IIO_IMEM_B0ESD	(1UL << 4)	/* BTE 0 shut down due to error */
+#define IIO_IMEM_B1ESD	(1UL << 8)	/* BTE 1 Shut down due to error */
 
 /*
  * As a permanent workaround for a bug in the PI side of the shub, we've
  * redefined big window 7 as small window 0.
  XXX does this still apply for SN1??
  */
-#define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
+#define HUB_NUM_BIG_WINDOW	(IIO_NUM_ITTES - 1)
 
 /*
  * Use the top big window as a surrogate for the first small window
@@ -3071,11 +2961,11 @@ typedef union ii_ippr_u {
 
 /*
  * CRB manipulation macros
- *      The CRB macros are slightly complicated, since there are up to
- *      four registers associated with each CRB entry.
+ *	The CRB macros are slightly complicated, since there are up to
+ *	four registers associated with each CRB entry.
  */
-#define IIO_NUM_CRBS            15      /* Number of CRBs */
-#define IIO_NUM_PC_CRBS         4       /* Number of partial cache CRBs */
+#define IIO_NUM_CRBS            15	/* Number of CRBs */
+#define IIO_NUM_PC_CRBS         4	/* Number of partial cache CRBs */
 #define IIO_ICRB_OFFSET         8
 #define IIO_ICRB_0              IIO_ICRB0_A
 #define IIO_ICRB_ADDR_SHFT	2	/* Shift to get proper address */
@@ -3083,43 +2973,43 @@ typedef union ii_ippr_u {
         #define IIO_FIRST_PC_ENTRY 12
  */
 
-#define IIO_ICRB_A(_x)  ((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))))
-#define IIO_ICRB_B(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET))
-#define IIO_ICRB_C(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET))
-#define IIO_ICRB_D(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET))
-#define IIO_ICRB_E(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET))
+#define IIO_ICRB_A(_x)	((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))))
+#define IIO_ICRB_B(_x)	((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET))
+#define IIO_ICRB_C(_x)	((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET))
+#define IIO_ICRB_D(_x)	((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET))
+#define IIO_ICRB_E(_x)	((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET))
 
 #define TNUM_TO_WIDGET_DEV(_tnum)	(_tnum & 0x7)
 
 /*
  * 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
-                                         * e.g. WINV to a Read only line. */
-#define IIO_ICRB_ECODE_AERR     3       /* Access error caused by IIO access */
-#define IIO_ICRB_ECODE_PWERR    4       /* Error on partial write       */
-#define IIO_ICRB_ECODE_PRERR    5       /* Error on partial read        */
-#define IIO_ICRB_ECODE_TOUT     6       /* CRB timeout before deallocating */
-#define IIO_ICRB_ECODE_XTERR    7       /* Incoming xtalk pkt had error bit */
+#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
+					 * e.g. WINV to a Read only line. */
+#define IIO_ICRB_ECODE_AERR     3	/* Access error caused by IIO access */
+#define IIO_ICRB_ECODE_PWERR    4	/* Error on partial write */
+#define IIO_ICRB_ECODE_PRERR    5	/* Error on partial read  */
+#define IIO_ICRB_ECODE_TOUT     6	/* CRB timeout before deallocating */
+#define IIO_ICRB_ECODE_XTERR    7	/* Incoming xtalk pkt had error bit */
 
 /*
  * Values for field imsgtype
  */
-#define IIO_ICRB_IMSGT_XTALK    0       /* Incoming Meessage from Xtalk */
-#define IIO_ICRB_IMSGT_BTE      1       /* Incoming message from BTE    */
-#define IIO_ICRB_IMSGT_SN1NET   2       /* Incoming message from SN1 net */
-#define IIO_ICRB_IMSGT_CRB      3       /* Incoming message from CRB ???  */
+#define IIO_ICRB_IMSGT_XTALK    0	/* Incoming Meessage from Xtalk */
+#define IIO_ICRB_IMSGT_BTE      1	/* Incoming message from BTE    */
+#define IIO_ICRB_IMSGT_SN1NET   2	/* Incoming message from SN1 net */
+#define IIO_ICRB_IMSGT_CRB      3	/* Incoming message from CRB ???  */
 
 /*
  * values for field initiator.
  */
-#define IIO_ICRB_INIT_XTALK     0       /* Message originated in xtalk  */
-#define IIO_ICRB_INIT_BTE0      0x1     /* Message originated in BTE 0  */
-#define IIO_ICRB_INIT_SN1NET    0x2     /* Message originated in SN1net */
-#define IIO_ICRB_INIT_CRB       0x3     /* Message originated in CRB ?  */
-#define IIO_ICRB_INIT_BTE1      0x5     /* MEssage originated in BTE 1  */
+#define IIO_ICRB_INIT_XTALK     0	/* Message originated in xtalk  */
+#define IIO_ICRB_INIT_BTE0      0x1	/* Message originated in BTE 0  */
+#define IIO_ICRB_INIT_SN1NET    0x2	/* Message originated in SN1net */
+#define IIO_ICRB_INIT_CRB       0x3	/* Message originated in CRB ?  */
+#define IIO_ICRB_INIT_BTE1      0x5	/* MEssage originated in BTE 1  */
 
 /*
  * Number of credits Hub widget has while sending req/response to
@@ -3127,8 +3017,8 @@ typedef union ii_ippr_u {
  * Value of 3 is required by Xbow 1.1
  * We may be able to increase this to 4 with Xbow 1.2.
  */
-#define       HUBII_XBOW_CREDIT       3
-#define       HUBII_XBOW_REV2_CREDIT  4
+#define		   HUBII_XBOW_CREDIT       3
+#define		   HUBII_XBOW_REV2_CREDIT  4
 
 /*
  * Number of credits that xtalk devices should use when communicating
@@ -3159,28 +3049,28 @@ typedef union ii_ippr_u {
  */
 
 #define IIO_ICMR_CRB_VLD_SHFT   20
-#define IIO_ICMR_CRB_VLD_MASK   (0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
+#define IIO_ICMR_CRB_VLD_MASK	(0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
 
 #define IIO_ICMR_FC_CNT_SHFT    16
-#define IIO_ICMR_FC_CNT_MASK    (0xf << IIO_ICMR_FC_CNT_SHFT)
+#define IIO_ICMR_FC_CNT_MASK	(0xf << IIO_ICMR_FC_CNT_SHFT)
 
 #define IIO_ICMR_C_CNT_SHFT     4
-#define IIO_ICMR_C_CNT_MASK     (0xf << IIO_ICMR_C_CNT_SHFT)
+#define IIO_ICMR_C_CNT_MASK	(0xf << IIO_ICMR_C_CNT_SHFT)
 
-#define IIO_ICMR_PRECISE        (1UL << 52)
-#define IIO_ICMR_CLR_RPPD       (1UL << 13)
-#define IIO_ICMR_CLR_RQPD       (1UL << 12)
+#define IIO_ICMR_PRECISE	(1UL << 52)
+#define IIO_ICMR_CLR_RPPD	(1UL << 13)
+#define IIO_ICMR_CLR_RQPD	(1UL << 12)
 
 /*
  * IIO PIO Deallocation register field masks : (IIO_IPDR)
  XXX present but not needed in bedrock?  See the manual.
  */
-#define IIO_IPDR_PND    (1 << 4)
+#define IIO_IPDR_PND    	(1 << 4)
 
 /*
  * IIO CRB deallocation register field masks: (IIO_ICDR)
  */
-#define IIO_ICDR_PND    (1 << 4)
+#define IIO_ICDR_PND    	(1 << 4)
 
 /* 
  * IO BTE Length/Status (IIO_IBLS) register bit field definitions
@@ -3223,35 +3113,35 @@ typedef union ii_ippr_u {
 /*
  * IO Error Clear register bit field definitions
  */
-#define IECLR_PI1_FWD_INT	(1UL << 31)  /* clear PI1_FORWARD_INT in iidsr */
-#define IECLR_PI0_FWD_INT	(1UL << 30)  /* clear PI0_FORWARD_INT in iidsr */
-#define IECLR_SPUR_RD_HDR	(1UL << 29)  /* clear valid bit in ixss reg */
-#define IECLR_BTE1		(1UL << 18)  /* clear bte error 1 */
-#define IECLR_BTE0		(1UL << 17)  /* clear bte error 0 */
-#define IECLR_CRAZY		(1UL << 16)  /* clear crazy bit in wstat reg */
-#define IECLR_PRB_F		(1UL << 15)  /* clear err bit in PRB_F reg */
-#define IECLR_PRB_E		(1UL << 14)  /* clear err bit in PRB_E reg */
-#define IECLR_PRB_D		(1UL << 13)  /* clear err bit in PRB_D reg */
-#define IECLR_PRB_C		(1UL << 12)  /* clear err bit in PRB_C reg */
-#define IECLR_PRB_B		(1UL << 11)  /* clear err bit in PRB_B reg */
-#define IECLR_PRB_A		(1UL << 10)  /* clear err bit in PRB_A reg */
-#define IECLR_PRB_9		(1UL << 9)   /* clear err bit in PRB_9 reg */
-#define IECLR_PRB_8		(1UL << 8)   /* clear err bit in PRB_8 reg */
-#define IECLR_PRB_0		(1UL << 0)   /* clear err bit in PRB_0 reg */
+#define IECLR_PI1_FWD_INT	(1UL << 31)	/* clear PI1_FORWARD_INT in iidsr */
+#define IECLR_PI0_FWD_INT	(1UL << 30)	/* clear PI0_FORWARD_INT in iidsr */
+#define IECLR_SPUR_RD_HDR	(1UL << 29)	/* clear valid bit in ixss reg */
+#define IECLR_BTE1		(1UL << 18)	/* clear bte error 1 */
+#define IECLR_BTE0		(1UL << 17)	/* clear bte error 0 */
+#define IECLR_CRAZY		(1UL << 16)	/* clear crazy bit in wstat reg */
+#define IECLR_PRB_F		(1UL << 15)	/* clear err bit in PRB_F reg */
+#define IECLR_PRB_E		(1UL << 14)	/* clear err bit in PRB_E reg */
+#define IECLR_PRB_D		(1UL << 13)	/* clear err bit in PRB_D reg */
+#define IECLR_PRB_C		(1UL << 12)	/* clear err bit in PRB_C reg */
+#define IECLR_PRB_B		(1UL << 11)	/* clear err bit in PRB_B reg */
+#define IECLR_PRB_A		(1UL << 10)	/* clear err bit in PRB_A reg */
+#define IECLR_PRB_9		(1UL << 9)	/* clear err bit in PRB_9 reg */
+#define IECLR_PRB_8		(1UL << 8)	/* clear err bit in PRB_8 reg */
+#define IECLR_PRB_0		(1UL << 0)	/* clear err bit in PRB_0 reg */
 
 /*
  * IIO CRB control register Fields: IIO_ICCR 
  */
-#define	IIO_ICCR_PENDING	(0x10000)
-#define	IIO_ICCR_CMD_MASK	(0xFF)
-#define	IIO_ICCR_CMD_SHFT	(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_PENDING	0x10000
+#define	IIO_ICCR_CMD_MASK	0xFF
+#define	IIO_ICCR_CMD_SHFT	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
 					 * via a WB
 					 */
-#define	IIO_ICCR_CMD_FLUSH	(0x800)
+#define	IIO_ICCR_CMD_FLUSH	0x800
 
 /*
  *
@@ -3283,8 +3173,8 @@ typedef union ii_ippr_u {
  * Easy access macros for CRBs, all 5 registers (A-E)
  */
 typedef ii_icrb0_a_u_t icrba_t;
-#define a_sidn          ii_icrb0_a_fld_s.ia_sidn
-#define a_tnum          ii_icrb0_a_fld_s.ia_tnum
+#define a_sidn		ii_icrb0_a_fld_s.ia_sidn
+#define a_tnum		ii_icrb0_a_fld_s.ia_tnum
 #define a_addr          ii_icrb0_a_fld_s.ia_addr
 #define a_valid         ii_icrb0_a_fld_s.ia_vld
 #define a_iow           ii_icrb0_a_fld_s.ia_iow
@@ -3324,14 +3214,13 @@ typedef ii_icrb0_c_u_t icrbc_t;
 #define c_source        ii_icrb0_c_fld_s.ic_source
 #define c_regvalue	ii_icrb0_c_regval
 
-
 typedef ii_icrb0_d_u_t icrbd_t;
 #define d_sleep         ii_icrb0_d_fld_s.id_sleep
 #define d_pricnt        ii_icrb0_d_fld_s.id_pr_cnt
 #define d_pripsc        ii_icrb0_d_fld_s.id_pr_psc
 #define d_bteop         ii_icrb0_d_fld_s.id_bte_op
-#define d_bteaddr       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
-#define d_benable       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
+#define d_bteaddr       ii_icrb0_d_fld_s.id_pa_be	/* ic_pa_be fld has 2 names */
+#define d_benable       ii_icrb0_d_fld_s.id_pa_be	/* ic_pa_be fld has 2 names */
 #define d_regvalue	ii_icrb0_d_regval
 
 typedef ii_icrb0_e_u_t icrbe_t;
@@ -3341,7 +3230,6 @@ typedef ii_icrb0_e_u_t icrbe_t;
 #define icrbe_timeout   ii_icrb0_e_fld_s.ie_timeout
 #define e_regvalue	ii_icrb0_e_regval
 
-
 /* Number of widgets supported by shub */
 #define HUB_NUM_WIDGET          9
 #define HUB_WIDGET_ID_MIN       0x8
@@ -3367,27 +3255,27 @@ typedef ii_icrb0_e_u_t icrbe_t;
 
 #define LNK_STAT_WORKING        0x2		/* LLP is working */
 
-#define IIO_WSTAT_ECRAZY        (1ULL << 32)    /* Hub gone crazy */
-#define IIO_WSTAT_TXRETRY       (1ULL << 9)     /* Hub Tx Retry timeout */
-#define IIO_WSTAT_TXRETRY_MASK  (0x7F)   /* should be 0xFF?? */
-#define IIO_WSTAT_TXRETRY_SHFT  (16)
-#define IIO_WSTAT_TXRETRY_CNT(w)        (((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
-                                          IIO_WSTAT_TXRETRY_MASK)
+#define IIO_WSTAT_ECRAZY	(1ULL << 32)	/* Hub gone crazy */
+#define IIO_WSTAT_TXRETRY	(1ULL << 9)	/* Hub Tx Retry timeout */
+#define IIO_WSTAT_TXRETRY_MASK  0x7F		/* should be 0xFF?? */
+#define IIO_WSTAT_TXRETRY_SHFT  16
+#define IIO_WSTAT_TXRETRY_CNT(w)	(((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
+                          		IIO_WSTAT_TXRETRY_MASK)
 
 /* Number of II perf. counters we can multiplex at once */
 
 #define IO_PERF_SETS	32
 
 /* Bit for the widget in inbound access register */
-#define IIO_IIWA_WIDGET(_w)     ((uint64_t)(1ULL << _w))
+#define IIO_IIWA_WIDGET(_w)	((uint64_t)(1ULL << _w))
 /* Bit for the widget in outbound access register */
-#define IIO_IOWA_WIDGET(_w)     ((uint64_t)(1ULL << _w))
+#define IIO_IOWA_WIDGET(_w)	((uint64_t)(1ULL << _w))
 
 /* NOTE: The following define assumes that we are going to get
  * widget numbers from 8 thru F and the device numbers within
  * widget from 0 thru 7.
  */
-#define IIO_IIDEM_WIDGETDEV_MASK(w, d)  ((uint64_t)(1ULL << (8 * ((w) - 8) + (d))))
+#define IIO_IIDEM_WIDGETDEV_MASK(w, d)	((uint64_t)(1ULL << (8 * ((w) - 8) + (d))))
 
 /* IO Interrupt Destination Register */
 #define IIO_IIDSR_SENT_SHIFT    28
@@ -3402,11 +3290,11 @@ typedef ii_icrb0_e_u_t icrbe_t;
 #define IIO_IIDSR_LVL_MASK      0x000000ff
 
 /* Xtalk timeout threshhold register (IIO_IXTT) */
-#define IXTT_RRSP_TO_SHFT	55	   /* read response timeout */
+#define IXTT_RRSP_TO_SHFT	55	/* read response timeout */
 #define IXTT_RRSP_TO_MASK	(0x1FULL << IXTT_RRSP_TO_SHFT)
-#define IXTT_RRSP_PS_SHFT	32	   /* read responsed TO prescalar */
+#define IXTT_RRSP_PS_SHFT	32	/* read responsed TO prescalar */
 #define IXTT_RRSP_PS_MASK	(0x7FFFFFULL << IXTT_RRSP_PS_SHFT)
-#define IXTT_TAIL_TO_SHFT	0	   /* tail timeout counter threshold */
+#define IXTT_TAIL_TO_SHFT	0	/* tail timeout counter threshold */
 #define IXTT_TAIL_TO_MASK	(0x3FFFFFFULL << IXTT_TAIL_TO_SHFT)
 
 /*
@@ -3414,17 +3302,17 @@ typedef ii_icrb0_e_u_t icrbe_t;
  */
 
 typedef union hubii_wcr_u {
-        uint64_t      wcr_reg_value;
-        struct {
-	  uint64_t	wcr_widget_id:   4,     /* LLP crossbar credit */
-			wcr_tag_mode:	 1,	/* Tag mode */
-			wcr_rsvd1:	 8,	/* Reserved */
-			wcr_xbar_crd:	 3,	/* LLP crossbar credit */
-			wcr_f_bad_pkt:	 1,	/* Force bad llp pkt enable */
-			wcr_dir_con:	 1,	/* widget direct connect */
-			wcr_e_thresh:	 5,	/* elasticity threshold */
-			wcr_rsvd:	41;	/* unused */
-        } wcr_fields_s;
+	uint64_t wcr_reg_value;
+	struct {
+		uint64_t wcr_widget_id:4,	/* LLP crossbar credit */
+		 wcr_tag_mode:1,	/* Tag mode */
+		 wcr_rsvd1:8,	/* Reserved */
+		 wcr_xbar_crd:3,	/* LLP crossbar credit */
+		 wcr_f_bad_pkt:1,	/* Force bad llp pkt enable */
+		 wcr_dir_con:1,	/* widget direct connect */
+		 wcr_e_thresh:5,	/* elasticity threshold */
+		 wcr_rsvd:41;	/* unused */
+	} wcr_fields_s;
 } hubii_wcr_t;
 
 #define iwcr_dir_con    wcr_fields_s.wcr_dir_con
@@ -3436,41 +3324,35 @@ performance registers */
    performed */
 
 typedef union io_perf_sel {
-        uint64_t perf_sel_reg;
-        struct {
-               uint64_t	perf_ippr0 :  4,
-				perf_ippr1 :  4,
-				perf_icct  :  8,
-				perf_rsvd  : 48;
-        } perf_sel_bits;
+	uint64_t perf_sel_reg;
+	struct {
+		uint64_t perf_ippr0:4, perf_ippr1:4, perf_icct:8, perf_rsvd:48;
+	} perf_sel_bits;
 } io_perf_sel_t;
 
 /* io_perf_cnt is to extract the count from the shub registers. Due to
    hardware problems there is only one counter, not two. */
 
 typedef union io_perf_cnt {
-        uint64_t      perf_cnt;
-        struct {
-               uint64_t	perf_cnt   : 20,
-				perf_rsvd2 : 12,
-				perf_rsvd1 : 32;
-        } perf_cnt_bits;
+	uint64_t perf_cnt;
+	struct {
+		uint64_t perf_cnt:20, perf_rsvd2:12, perf_rsvd1:32;
+	} perf_cnt_bits;
 
 } io_perf_cnt_t;
 
 typedef union iprte_a {
-	uint64_t	entry;
+	uint64_t entry;
 	struct {
-		uint64_t	i_rsvd_1                  :	 3;
-		uint64_t	i_addr			  :	38;
-		uint64_t	i_init			  :	 3;
-		uint64_t	i_source		  :	 8;
-		uint64_t	i_rsvd			  :	 2;
-		uint64_t	i_widget		  :	 4;
-		uint64_t	i_to_cnt		  :	 5;
-		uint64_t       i_vld                     :      1;
+		uint64_t i_rsvd_1:3;
+		uint64_t i_addr:38;
+		uint64_t i_init:3;
+		uint64_t i_source:8;
+		uint64_t i_rsvd:2;
+		uint64_t i_widget:4;
+		uint64_t i_to_cnt:5;
+		uint64_t i_vld:1;
 	} iprte_fields;
 } iprte_a_t;
 
-#endif /* _ASM_IA64_SN_SHUBIO_H */
-
+#endif				/* _ASM_IA64_SN_SHUBIO_H */
diff --git a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h
--- a/include/asm-ia64/sn/sn_cpuid.h
+++ b/include/asm-ia64/sn/sn_cpuid.h
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 
@@ -92,24 +92,24 @@
  * NOTE: on non-MP systems, only cpuid 0 exists
  */
 
-extern short physical_node_map[];			/* indexed by nasid to get cnode */
+extern short physical_node_map[];	/* indexed by nasid to get cnode */
 
 /*
  * Macros for retrieving info about current cpu
  */
-#define get_nasid()			(nodepda->phys_cpuid[smp_processor_id()].nasid)
-#define get_subnode()			(nodepda->phys_cpuid[smp_processor_id()].subnode)
-#define get_slice()			(nodepda->phys_cpuid[smp_processor_id()].slice)
-#define get_cnode()			(nodepda->phys_cpuid[smp_processor_id()].cnode)
-#define get_sapicid()			((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
+#define get_nasid()	(sn_nodepda->phys_cpuid[smp_processor_id()].nasid)
+#define get_subnode()	(sn_nodepda->phys_cpuid[smp_processor_id()].subnode)
+#define get_slice()	(sn_nodepda->phys_cpuid[smp_processor_id()].slice)
+#define get_cnode()	(sn_nodepda->phys_cpuid[smp_processor_id()].cnode)
+#define get_sapicid()	((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
 
 /*
  * Macros for retrieving info about an arbitrary cpu
  *	cpuid - logical cpu id
  */
-#define cpuid_to_nasid(cpuid)		(nodepda->phys_cpuid[cpuid].nasid)
-#define cpuid_to_subnode(cpuid)		(nodepda->phys_cpuid[cpuid].subnode)
-#define cpuid_to_slice(cpuid)		(nodepda->phys_cpuid[cpuid].slice)
+#define cpuid_to_nasid(cpuid)		(sn_nodepda->phys_cpuid[cpuid].nasid)
+#define cpuid_to_subnode(cpuid)		(sn_nodepda->phys_cpuid[cpuid].subnode)
+#define cpuid_to_slice(cpuid)		(sn_nodepda->phys_cpuid[cpuid].slice)
 #define cpuid_to_cnodeid(cpuid)		(physical_node_map[cpuid_to_nasid(cpuid)])
 
 
@@ -123,11 +123,8 @@ extern int nasid_slice_to_cpuid(int, int
 
 /*
  * cnodeid_to_nasid - convert a cnodeid to a NASID
- *	Macro relies on pg_data for a node being on the node itself.
- *	Just extract the NASID from the pointer.
- *
  */
-#define cnodeid_to_nasid(cnodeid)	pda->cnodeid_to_nasid_table[cnodeid]
+#define cnodeid_to_nasid(cnodeid)	(sn_cnodeid_to_nasid[cnodeid])
  
 /*
  * nasid_to_cnodeid - convert a NASID to a cnodeid
@@ -135,9 +132,10 @@ extern int nasid_slice_to_cpuid(int, int
 #define nasid_to_cnodeid(nasid)		(physical_node_map[nasid])
 
 /*
- * partition_coherence_id - cget the coherence ID of the current partition
+ * partition_coherence_id - get the coherence ID of the current partition
  */
-#define partition_coherence_id()	(get_nasid() >> 9)
+extern u8 sn_coherency_id;
+#define partition_coherence_id()	(sn_coherency_id)
 
 #endif /* _ASM_IA64_SN_SN_CPUID_H */
 
diff --git a/include/asm-ia64/sn/sn_fru.h b/include/asm-ia64/sn/sn_fru.h
deleted file mode 100644
--- a/include/asm-ia64/sn/sn_fru.h
+++ /dev/null
@@ -1,44 +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) 1992-1997,1999-2004 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_SN_FRU_H
-#define _ASM_IA64_SN_SN_FRU_H
-
-#define MAX_DIMMS			8	 /* max # of dimm banks */
-#define MAX_PCIDEV			8	 /* max # of pci devices on a pci bus */
-
-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_dimm[MAX_DIMMS];
-				    /* confidence level that dimm[i] is bad
-				     *I think this is the right number
-				     */
-
-} kf_mem_t;
-
-typedef struct kf_cpu_s {
-	confidence_t	kc_confidence; /* confidence level that cpu is bad */
-	confidence_t	kc_icache; /* confidence level that instr. cache is bad */
-	confidence_t	kc_dcache; /* confidence level that data   cache is bad */
-	confidence_t	kc_scache; /* confidence level that sec.   cache is bad */
-	confidence_t	kc_sysbus; /* confidence level that sysad/cmd/state bus is bad */
-} kf_cpu_t;
-
-
-typedef struct kf_pci_bus_s {
-	confidence_t	kpb_belief;	/* confidence level  that the  pci bus is bad */
-	confidence_t	kpb_pcidev_belief[MAX_PCIDEV];
-					/* confidence level that the pci dev is bad */
-} kf_pci_bus_t;
-
-
-#endif /* _ASM_IA64_SN_SN_FRU_H */
-
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -8,7 +8,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
@@ -18,6 +18,7 @@
 #include <asm/sn/arch.h>
 #include <asm/sn/geo.h>
 #include <asm/sn/nodepda.h>
+#include <asm/sn/shub_mmr.h>
 
 // SGI Specific Calls
 #define  SN_SAL_POD_MODE                           0x02000001
@@ -34,8 +35,8 @@
 #define  SN_SAL_PRINT_ERROR			   0x02000012
 #define  SN_SAL_SET_ERROR_HANDLING_FEATURES	   0x0200001a	// reentrant
 #define  SN_SAL_GET_FIT_COMPT			   0x0200001b	// reentrant
-#define  SN_SAL_GET_HUB_INFO                       0x0200001c
 #define  SN_SAL_GET_SAPIC_INFO                     0x0200001d
+#define  SN_SAL_GET_SN_INFO                        0x0200001e
 #define  SN_SAL_CONSOLE_PUTC                       0x02000021
 #define  SN_SAL_CONSOLE_GETC                       0x02000022
 #define  SN_SAL_CONSOLE_PUTS                       0x02000023
@@ -63,6 +64,7 @@
 
 #define  SN_SAL_SYSCTL_IOBRICK_PCI_OP		   0x02000042	// reentrant
 #define	 SN_SAL_IROUTER_OP			   0x02000043
+#define  SN_SAL_SYSCTL_EVENT                       0x02000044
 #define  SN_SAL_IOIF_INTERRUPT			   0x0200004a
 #define  SN_SAL_HWPERF_OP			   0x02000050   // lock
 #define  SN_SAL_IOIF_ERROR_INTERRUPT		   0x02000051
@@ -75,7 +77,8 @@
 #define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST	   0x02000058
 
 #define SN_SAL_HUB_ERROR_INTERRUPT		   0x02000060
-
+#define SN_SAL_BTE_RECOVER			   0x02000061
+#define SN_SAL_IOIF_GET_PCI_TOPOLOGY	           0x02000062
 
 /*
  * Service-specific constants
@@ -112,6 +115,13 @@
 #define SAL_IROUTER_INTR_XMIT	SAL_CONSOLE_INTR_XMIT
 #define SAL_IROUTER_INTR_RECV	SAL_CONSOLE_INTR_RECV
 
+/*
+ * Error Handling Features
+ */
+#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV	0x1
+#define SAL_ERR_FEAT_LOG_SBES			0x2
+#define SAL_ERR_FEAT_MFR_OVERRIDE		0x4
+#define SAL_ERR_FEAT_SBE_THRESHOLD		0xffff0000
 
 /*
  * SAL Error Codes
@@ -339,6 +349,25 @@ ia64_sn_plat_cpei_handler(void)
 }
 
 /*
+ * Set Error Handling Features
+ */
+static inline u64
+ia64_sn_plat_set_error_handling_features(void)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+	ret_stuff.v1 = 0;
+	ret_stuff.v2 = 0;
+	SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES,
+		(SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV | SAL_ERR_FEAT_LOG_SBES),
+		0, 0, 0, 0, 0, 0);
+
+	return ret_stuff.status;
+}
+
+/*
  * Checks for console input.
  */
 static inline u64
@@ -469,7 +498,7 @@ static inline u64
 ia64_sn_pod_mode(void)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_REENTRANT(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0);
 	if (isrv.status)
 		return 0;
 	return isrv.v0;
@@ -554,7 +583,8 @@ static inline u64
 ia64_sn_partition_serial_get(void)
 {
 	struct ia64_sal_retval ret_stuff;
-	SAL_CALL(ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0, 0, 0, 0, 0, 0, 0);
+	ia64_sal_oemcall_reentrant(&ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0,
+				   0, 0, 0, 0, 0, 0);
 	if (ret_stuff.status != 0)
 	    return 0;
 	return ret_stuff.v0;
@@ -562,11 +592,10 @@ ia64_sn_partition_serial_get(void)
 
 static inline u64
 sn_partition_serial_number_val(void) {
-	if (sn_partition_serial_number) {
-		return(sn_partition_serial_number);
-	} else {
-		return(sn_partition_serial_number = ia64_sn_partition_serial_get());
+	if (unlikely(sn_partition_serial_number == 0)) {
+		sn_partition_serial_number = ia64_sn_partition_serial_get();
 	}
+	return sn_partition_serial_number;
 }
 
 /*
@@ -577,8 +606,8 @@ static inline partid_t
 ia64_sn_sysctl_partition_get(nasid_t nasid)
 {
 	struct ia64_sal_retval ret_stuff;
-	SAL_CALL(ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
-		 0, 0, 0, 0, 0, 0);
+	ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
+				0, 0, 0, 0, 0, 0);
 	if (ret_stuff.status != 0)
 	    return INVALID_PARTID;
 	return ((partid_t)ret_stuff.v0);
@@ -592,11 +621,38 @@ extern partid_t sn_partid;
 
 static inline partid_t
 sn_local_partid(void) {
-	if (sn_partid < 0) {
-		return (sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id())));
-	} else {
-		return sn_partid;
+	if (unlikely(sn_partid < 0)) {
+		sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id()));
 	}
+	return sn_partid;
+}
+
+/*
+ * Returns the physical address of the partition's reserved page through
+ * an iterative number of calls.
+ *
+ * On first call, 'cookie' and 'len' should be set to 0, and 'addr'
+ * set to the nasid of the partition whose reserved page's address is
+ * being sought.
+ * On subsequent calls, pass the values, that were passed back on the
+ * previous call.
+ *
+ * While the return status equals SALRET_MORE_PASSES, keep calling
+ * this function after first copying 'len' bytes starting at 'addr'
+ * into 'buf'. Once the return status equals SALRET_OK, 'addr' will
+ * be the physical address of the partition's reserved page. If the
+ * return status equals neither of these, an error as occurred.
+ */
+static inline s64
+sn_partition_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
+{
+	struct ia64_sal_retval rv;
+	ia64_sal_oemcall_reentrant(&rv, SN_SAL_GET_PARTITION_ADDR, *cookie,
+				   *addr, buf, *len, 0, 0, 0);
+	*cookie = rv.v0;
+	*addr = rv.v1;
+	*len = rv.v2;
+	return rv.status;
 }
 
 /*
@@ -618,8 +674,8 @@ static inline int
 sn_register_xp_addr_region(u64 paddr, u64 len, int operation)
 {
 	struct ia64_sal_retval ret_stuff;
-	SAL_CALL(ret_stuff, SN_SAL_XP_ADDR_REGION, paddr, len, (u64)operation,
-		 0, 0, 0, 0);
+	ia64_sal_oemcall(&ret_stuff, SN_SAL_XP_ADDR_REGION, paddr, len,
+			 (u64)operation, 0, 0, 0, 0);
 	return ret_stuff.status;
 }
 
@@ -643,8 +699,8 @@ sn_register_nofault_code(u64 start_addr,
 	} else {
 		call = SN_SAL_NO_FAULT_ZONE_PHYSICAL;
 	}
-	SAL_CALL(ret_stuff, call, start_addr, end_addr, return_addr, (u64)1,
-		 0, 0, 0);
+	ia64_sal_oemcall(&ret_stuff, call, start_addr, end_addr, return_addr,
+			 (u64)1, 0, 0, 0);
 	return ret_stuff.status;
 }
 
@@ -665,8 +721,8 @@ static inline int
 sn_change_coherence(u64 *new_domain, u64 *old_domain)
 {
 	struct ia64_sal_retval ret_stuff;
-	SAL_CALL(ret_stuff, SN_SAL_COHERENCE, new_domain, old_domain, 0, 0,
-		 0, 0, 0);
+	ia64_sal_oemcall(&ret_stuff, SN_SAL_COHERENCE, (u64)new_domain,
+			 (u64)old_domain, 0, 0, 0, 0, 0);
 	return ret_stuff.status;
 }
 
@@ -685,8 +741,8 @@ sn_change_memprotect(u64 paddr, u64 len,
 	cnodeid = nasid_to_cnodeid(get_node_number(paddr));
 	// spin_lock(&NODEPDA(cnodeid)->bist_lock);
 	local_irq_save(irq_flags);
-	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_MEMPROTECT, paddr, len, nasid_array,
-		 perms, 0, 0, 0);
+	ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_MEMPROTECT, paddr, len,
+				(u64)nasid_array, perms, 0, 0, 0);
 	local_irq_restore(irq_flags);
 	// spin_unlock(&NODEPDA(cnodeid)->bist_lock);
 	return ret_stuff.status;
@@ -848,6 +904,19 @@ ia64_sn_irtr_intr_disable(nasid_t nasid,
 	return (int) rv.v0;
 }
 
+/*
+ * Set up a node as the point of contact for system controller
+ * environmental event delivery.
+ */
+static inline int
+ia64_sn_sysctl_event_init(nasid_t nasid)
+{
+        struct ia64_sal_retval rv;
+        SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_EVENT, (u64) nasid,
+			   0, 0, 0, 0, 0, 0);
+        return (int) rv.v0;
+}
+
 /**
  * ia64_sn_get_fit_compt - read a FIT entry from the PROM header
  * @nasid: NASID of node to read
@@ -935,15 +1004,24 @@ ia64_sn_get_sapic_info(int sapicid, int 
 /*
  * Returns information about the HUB/SHUB.
  *  In:
- *	arg0 - SN_SAL_GET_HUB_INFO
+ *	arg0 - SN_SAL_GET_SN_INFO
  * 	arg1 - 0 (other values reserved for future use)
  *  Out:
- *	v0 - shub type (0=shub1, 1=shub2)
- *	v1 - masid mask (ex., 0x7ff for 11 bit nasid)
- *	v2 - bit position of low nasid bit
+ *	v0 
+ *		[7:0]   - shub type (0=shub1, 1=shub2)
+ *		[15:8]  - Log2 max number of nodes in entire system (includes
+ *			  C-bricks, I-bricks, etc)
+ *		[23:16] - Log2 of nodes per sharing domain			 
+ * 		[31:24] - partition ID
+ * 		[39:32] - coherency_id
+ * 		[47:40] - regionsize
+ *	v1 
+ *		[15:0]  - nasid mask (ex., 0x7ff for 11 bit nasid)
+ *	 	[23:15] - bit position of low nasid bit
  */
 static inline u64
-ia64_sn_get_hub_info(int fc, u64 *arg1, u64 *arg2, u64 *arg3)
+ia64_sn_get_sn_info(int fc, u8 *shubtype, u16 *nasid_bitmask, u8 *nasid_shift, 
+		u8 *systemsize, u8 *sharing_domain_size, u8 *partid, u8 *coher, u8 *reg)
 {
 	struct ia64_sal_retval ret_stuff;
 
@@ -951,13 +1029,22 @@ ia64_sn_get_hub_info(int fc, u64 *arg1, 
 	ret_stuff.v0 = 0;
 	ret_stuff.v1 = 0;
 	ret_stuff.v2 = 0;
-	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_HUB_INFO, fc, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, fc, 0, 0, 0, 0, 0, 0);
 
 /***** BEGIN HACK - temp til old proms no longer supported ********/
 	if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) {
-		if (arg1) *arg1 = 0;
-		if (arg2) *arg2 = 0x7ff;
-		if (arg3) *arg3 = 38;
+		int nasid = get_sapicid() & 0xfff;;
+#define SH_SHUB_ID_NODES_PER_BIT_MASK 0x001f000000000000UL                                               
+#define SH_SHUB_ID_NODES_PER_BIT_SHFT 48                                                               
+		if (shubtype) *shubtype = 0;
+		if (nasid_bitmask) *nasid_bitmask = 0x7ff;
+		if (nasid_shift) *nasid_shift = 38;
+		if (systemsize) *systemsize = 11;
+		if (sharing_domain_size) *sharing_domain_size = 9;
+		if (partid) *partid = ia64_sn_sysctl_partition_get(nasid);
+		if (coher) *coher = nasid >> 9;
+		if (reg) *reg = (HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_SHUB_ID)) & SH_SHUB_ID_NODES_PER_BIT_MASK) >>
+			SH_SHUB_ID_NODES_PER_BIT_SHFT;
 		return 0;
 	}
 /***** END HACK *******/
@@ -965,9 +1052,14 @@ ia64_sn_get_hub_info(int fc, u64 *arg1, 
 	if (ret_stuff.status < 0)
 		return ret_stuff.status;
 
-	if (arg1) *arg1 = ret_stuff.v0;
-	if (arg2) *arg2 = ret_stuff.v1;
-	if (arg3) *arg3 = ret_stuff.v2;
+	if (shubtype) *shubtype = ret_stuff.v0 & 0xff;
+	if (systemsize) *systemsize = (ret_stuff.v0 >> 8) & 0xff;
+	if (sharing_domain_size) *sharing_domain_size = (ret_stuff.v0 >> 16) & 0xff;
+	if (partid) *partid = (ret_stuff.v0 >> 24) & 0xff;
+	if (coher) *coher = (ret_stuff.v0 >> 32) & 0xff;
+	if (reg) *reg = (ret_stuff.v0 >> 40) & 0xff;
+	if (nasid_bitmask) *nasid_bitmask = (ret_stuff.v1 & 0xffff);
+	if (nasid_shift) *nasid_shift = (ret_stuff.v1 >> 16) & 0xff;
 	return 0;
 }
  
@@ -988,4 +1080,29 @@ ia64_sn_hwperf_op(nasid_t nasid, u64 opc
 	return (int) rv.status;
 }
 
+static inline int
+ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab,
+			      u64 buf, u64 len)
+{
+	struct ia64_sal_retval rv;
+	SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY,
+		rack, bay, slot, slab, buf, len, 0);
+	return (int) rv.status;
+}
+
+/*
+ * BTE error recovery is implemented in SAL
+ */
+static inline int
+ia64_sn_bte_recovery(nasid_t nasid)
+{
+	struct ia64_sal_retval rv;
+
+	rv.status = 0;
+	SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, 0, 0, 0, 0, 0, 0, 0);
+	if (rv.status == SALRET_NOT_IMPLEMENTED)
+		return 0;
+	return (int) rv.status;
+}
+
 #endif /* _ASM_IA64_SN_SN_SAL_H */
diff --git a/include/asm-ia64/sn/sndrv.h b/include/asm-ia64/sn/sndrv.h
deleted file mode 100644
--- a/include/asm-ia64/sn/sndrv.h
+++ /dev/null
@@ -1,47 +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) 2002-2004 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#ifndef _ASM_IA64_SN_SNDRV_H
-#define _ASM_IA64_SN_SNDRV_H
-
-/* ioctl commands */
-#define SNDRV_GET_ROUTERINFO		1
-#define SNDRV_GET_INFOSIZE		2
-#define SNDRV_GET_HUBINFO		3
-#define SNDRV_GET_FLASHLOGSIZE		4
-#define SNDRV_SET_FLASHSYNC		5
-#define SNDRV_GET_FLASHLOGDATA		6
-#define SNDRV_GET_FLASHLOGALL		7
-
-#define SNDRV_SET_HISTOGRAM_TYPE	14
-
-#define SNDRV_ELSC_COMMAND		19
-#define	SNDRV_CLEAR_LOG			20
-#define	SNDRV_INIT_LOG			21
-#define	SNDRV_GET_PIMM_PSC		22
-#define SNDRV_SET_PARTITION		23
-#define SNDRV_GET_PARTITION		24
-
-/* see synergy_perf_ioctl() */
-#define SNDRV_GET_SYNERGY_VERSION	30
-#define SNDRV_GET_SYNERGY_STATUS	31
-#define SNDRV_GET_SYNERGYINFO		32
-#define SNDRV_SYNERGY_APPEND		33
-#define SNDRV_SYNERGY_ENABLE		34
-#define SNDRV_SYNERGY_FREQ		35
-
-/* Devices */
-#define SNDRV_UKNOWN_DEVICE		-1
-#define SNDRV_ROUTER_DEVICE		1
-#define SNDRV_HUB_DEVICE		2
-#define SNDRV_ELSC_NVRAM_DEVICE		3
-#define SNDRV_ELSC_CONTROLLER_DEVICE	4
-#define SNDRV_SYSCTL_SUBCH		5
-#define SNDRV_SYNERGY_DEVICE		6
-
-#endif /* _ASM_IA64_SN_SNDRV_H */
diff --git a/include/asm-ia64/sn/tioca.h b/include/asm-ia64/sn/tioca.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/tioca.h
@@ -0,0 +1,596 @@
+#ifndef _ASM_IA64_SN_TIO_TIOCA_H
+#define _ASM_IA64_SN_TIO_TIOCA_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) 2003-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#define TIOCA_PART_NUM	0xE020
+#define TIOCA_MFGR_NUM	0x24
+#define TIOCA_REV_A	0x1
+
+/*
+ * Register layout for TIO:CA.  See below for bitmasks for each register.
+ */
+
+struct tioca {
+	uint64_t	ca_id;				/* 0x000000 */
+	uint64_t	ca_control1;			/* 0x000008 */
+	uint64_t	ca_control2;			/* 0x000010 */
+	uint64_t	ca_status1;			/* 0x000018 */
+	uint64_t	ca_status2;			/* 0x000020 */
+	uint64_t	ca_gart_aperature;		/* 0x000028 */
+	uint64_t	ca_gfx_detach;			/* 0x000030 */
+	uint64_t	ca_inta_dest_addr;		/* 0x000038 */
+	uint64_t	ca_intb_dest_addr;		/* 0x000040 */
+	uint64_t	ca_err_int_dest_addr;		/* 0x000048 */
+	uint64_t	ca_int_status;			/* 0x000050 */
+	uint64_t	ca_int_status_alias;		/* 0x000058 */
+	uint64_t	ca_mult_error;			/* 0x000060 */
+	uint64_t	ca_mult_error_alias;		/* 0x000068 */
+	uint64_t	ca_first_error;			/* 0x000070 */
+	uint64_t	ca_int_mask;			/* 0x000078 */
+	uint64_t	ca_crm_pkterr_type;		/* 0x000080 */
+	uint64_t	ca_crm_pkterr_type_alias;	/* 0x000088 */
+	uint64_t	ca_crm_ct_error_detail_1;	/* 0x000090 */
+	uint64_t	ca_crm_ct_error_detail_2;	/* 0x000098 */
+	uint64_t	ca_crm_tnumto;			/* 0x0000A0 */
+	uint64_t	ca_gart_err;			/* 0x0000A8 */
+	uint64_t	ca_pcierr_type;			/* 0x0000B0 */
+	uint64_t	ca_pcierr_addr;			/* 0x0000B8 */
+
+	uint64_t	ca_pad_0000C0[3];		/* 0x0000{C0..D0} */
+
+	uint64_t	ca_pci_rd_buf_flush;		/* 0x0000D8 */
+	uint64_t	ca_pci_dma_addr_extn;		/* 0x0000E0 */
+	uint64_t	ca_agp_dma_addr_extn;		/* 0x0000E8 */
+	uint64_t	ca_force_inta;			/* 0x0000F0 */
+	uint64_t	ca_force_intb;			/* 0x0000F8 */
+	uint64_t	ca_debug_vector_sel;		/* 0x000100 */
+	uint64_t	ca_debug_mux_core_sel;		/* 0x000108 */
+	uint64_t	ca_debug_mux_pci_sel;		/* 0x000110 */
+	uint64_t	ca_debug_domain_sel;		/* 0x000118 */
+
+	uint64_t	ca_pad_000120[28];		/* 0x0001{20..F8} */
+
+	uint64_t	ca_gart_ptr_table;		/* 0x200 */
+	uint64_t	ca_gart_tlb_addr[8];		/* 0x2{08..40} */
+};
+
+/*
+ * Mask/shift definitions for TIO:CA registers.  The convention here is
+ * to mainly use the names as they appear in the "TIO AEGIS Programmers'
+ * Reference" with a CA_ prefix added.  Some exceptions were made to fix
+ * duplicate field names or to generalize fields that are common to
+ * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for
+ * example).
+ *
+ * Fields consisting of a single bit have a single #define have a single
+ * macro declaration to mask the bit.  Fields consisting of multiple bits
+ * have two declarations: one to mask the proper bits in a register, and 
+ * a second with the suffix "_SHFT" to identify how far the mask needs to
+ * be shifted right to get its base value.
+ */
+
+/* ==== ca_control1 */
+#define CA_SYS_BIG_END			(1ull << 0)
+#define CA_DMA_AGP_SWAP			(1ull << 1)
+#define CA_DMA_PCI_SWAP			(1ull << 2)
+#define CA_PIO_IO_SWAP			(1ull << 3)
+#define CA_PIO_MEM_SWAP			(1ull << 4)
+#define CA_GFX_WR_SWAP			(1ull << 5)
+#define CA_AGP_FW_ENABLE		(1ull << 6)
+#define CA_AGP_CAL_CYCLE		(0x7ull << 7)
+#define CA_AGP_CAL_CYCLE_SHFT		7
+#define CA_AGP_CAL_PRSCL_BYP		(1ull << 10)
+#define CA_AGP_INIT_CAL_ENB		(1ull << 11)
+#define CA_INJ_ADDR_PERR		(1ull << 12)
+#define CA_INJ_DATA_PERR		(1ull << 13)
+	/* bits 15:14 unused */
+#define CA_PCIM_IO_NBE_AD		(0x7ull << 16)
+#define CA_PCIM_IO_NBE_AD_SHFT		16
+#define CA_PCIM_FAST_BTB_ENB		(1ull << 19)
+	/* bits 23:20 unused */
+#define CA_PIO_ADDR_OFFSET		(0xffull << 24)
+#define CA_PIO_ADDR_OFFSET_SHFT		24
+	/* bits 35:32 unused */
+#define CA_AGPDMA_OP_COMBDELAY		(0x1full << 36)
+#define CA_AGPDMA_OP_COMBDELAY_SHFT	36
+	/* bit 41 unused */
+#define CA_AGPDMA_OP_ENB_COMBDELAY	(1ull << 42)
+#define	CA_PCI_INT_LPCNT		(0xffull << 44)
+#define CA_PCI_INT_LPCNT_SHFT		44
+	/* bits 63:52 unused */
+
+/* ==== ca_control2 */
+#define CA_AGP_LATENCY_TO		(0xffull << 0)
+#define CA_AGP_LATENCY_TO_SHFT		0
+#define CA_PCI_LATENCY_TO		(0xffull << 8)
+#define CA_PCI_LATENCY_TO_SHFT		8
+#define CA_PCI_MAX_RETRY		(0x3ffull << 16)
+#define CA_PCI_MAX_RETRY_SHFT		16
+	/* bits 27:26 unused */
+#define CA_RT_INT_EN			(0x3ull << 28)
+#define CA_RT_INT_EN_SHFT			28
+#define CA_MSI_INT_ENB			(1ull << 30)
+#define CA_PCI_ARB_ERR_ENB		(1ull << 31)
+#define CA_GART_MEM_PARAM		(0x3ull << 32)
+#define CA_GART_MEM_PARAM_SHFT		32
+#define CA_GART_RD_PREFETCH_ENB		(1ull << 34)
+#define CA_GART_WR_PREFETCH_ENB		(1ull << 35)
+#define CA_GART_FLUSH_TLB		(1ull << 36)
+	/* bits 39:37 unused */
+#define CA_CRM_TNUMTO_PERIOD		(0x1fffull << 40)
+#define CA_CRM_TNUMTO_PERIOD_SHFT	40
+	/* bits 55:53 unused */
+#define CA_CRM_TNUMTO_ENB		(1ull << 56)
+#define CA_CRM_PRESCALER_BYP		(1ull << 57)
+	/* bits 59:58 unused */
+#define CA_CRM_MAX_CREDIT		(0x7ull << 60)
+#define CA_CRM_MAX_CREDIT_SHFT		60
+	/* bit 63 unused */
+
+/* ==== ca_status1 */
+#define CA_CORELET_ID			(0x3ull << 0)
+#define CA_CORELET_ID_SHFT		0
+#define CA_INTA_N			(1ull << 2)
+#define CA_INTB_N			(1ull << 3)
+#define CA_CRM_CREDIT_AVAIL		(0x7ull << 4)
+#define CA_CRM_CREDIT_AVAIL_SHFT	4
+	/* bit 7 unused */
+#define CA_CRM_SPACE_AVAIL		(0x7full << 8)
+#define CA_CRM_SPACE_AVAIL_SHFT		8
+	/* bit 15 unused */
+#define CA_GART_TLB_VAL			(0xffull << 16)
+#define CA_GART_TLB_VAL_SHFT		16
+	/* bits 63:24 unused */
+
+/* ==== ca_status2 */
+#define CA_GFX_CREDIT_AVAIL		(0xffull << 0)
+#define CA_GFX_CREDIT_AVAIL_SHFT	0
+#define CA_GFX_OPQ_AVAIL		(0xffull << 8)
+#define CA_GFX_OPQ_AVAIL_SHFT		8
+#define CA_GFX_WRBUFF_AVAIL		(0xffull << 16)
+#define CA_GFX_WRBUFF_AVAIL_SHFT	16
+#define CA_ADMA_OPQ_AVAIL		(0xffull << 24)
+#define CA_ADMA_OPQ_AVAIL_SHFT		24
+#define CA_ADMA_WRBUFF_AVAIL		(0xffull << 32)
+#define CA_ADMA_WRBUFF_AVAIL_SHFT	32
+#define CA_ADMA_RDBUFF_AVAIL		(0x7full << 40)
+#define CA_ADMA_RDBUFF_AVAIL_SHFT	40
+#define CA_PCI_PIO_OP_STAT		(1ull << 47)
+#define CA_PDMA_OPQ_AVAIL		(0xfull << 48)
+#define CA_PDMA_OPQ_AVAIL_SHFT		48
+#define CA_PDMA_WRBUFF_AVAIL		(0xfull << 52)
+#define CA_PDMA_WRBUFF_AVAIL_SHFT	52
+#define CA_PDMA_RDBUFF_AVAIL		(0x3ull << 56)
+#define CA_PDMA_RDBUFF_AVAIL_SHFT	56
+	/* bits 63:58 unused */
+
+/* ==== ca_gart_aperature */
+#define CA_GART_AP_ENB_AGP		(1ull << 0)
+#define CA_GART_PAGE_SIZE		(1ull << 1)
+#define CA_GART_AP_ENB_PCI		(1ull << 2)
+	/* bits 11:3 unused */
+#define CA_GART_AP_SIZE			(0x3ffull << 12)
+#define CA_GART_AP_SIZE_SHFT		12
+#define CA_GART_AP_BASE			(0x3ffffffffffull << 22)
+#define CA_GART_AP_BASE_SHFT		22
+
+/* ==== ca_inta_dest_addr
+   ==== ca_intb_dest_addr 
+   ==== ca_err_int_dest_addr */
+	/* bits 2:0 unused */
+#define CA_INT_DEST_ADDR		(0x7ffffffffffffull << 3)
+#define CA_INT_DEST_ADDR_SHFT		3
+	/* bits 55:54 unused */
+#define CA_INT_DEST_VECT		(0xffull << 56)
+#define CA_INT_DEST_VECT_SHFT		56
+
+/* ==== ca_int_status */
+/* ==== ca_int_status_alias */
+/* ==== ca_mult_error */
+/* ==== ca_mult_error_alias */
+/* ==== ca_first_error */
+/* ==== ca_int_mask */
+#define CA_PCI_ERR			(1ull << 0)
+	/* bits 3:1 unused */
+#define CA_GART_FETCH_ERR		(1ull << 4)
+#define CA_GFX_WR_OVFLW			(1ull << 5)
+#define CA_PIO_REQ_OVFLW		(1ull << 6)
+#define CA_CRM_PKTERR			(1ull << 7)
+#define CA_CRM_DVERR			(1ull << 8)
+#define CA_TNUMTO			(1ull << 9)
+#define CA_CXM_RSP_CRED_OVFLW		(1ull << 10)
+#define CA_CXM_REQ_CRED_OVFLW		(1ull << 11)
+#define CA_PIO_INVALID_ADDR		(1ull << 12)
+#define CA_PCI_ARB_TO			(1ull << 13)
+#define CA_AGP_REQ_OFLOW		(1ull << 14)
+#define CA_SBA_TYPE1_ERR		(1ull << 15)
+	/* bit 16 unused */
+#define CA_INTA				(1ull << 17)
+#define CA_INTB				(1ull << 18)
+#define CA_MULT_INTA			(1ull << 19)
+#define CA_MULT_INTB			(1ull << 20)
+#define CA_GFX_CREDIT_OVFLW		(1ull << 21)
+	/* bits 63:22 unused */
+
+/* ==== ca_crm_pkterr_type */
+/* ==== ca_crm_pkterr_type_alias */
+#define CA_CRM_PKTERR_SBERR_HDR		(1ull << 0)
+#define CA_CRM_PKTERR_DIDN		(1ull << 1)
+#define CA_CRM_PKTERR_PACTYPE		(1ull << 2)
+#define CA_CRM_PKTERR_INV_TNUM		(1ull << 3)
+#define CA_CRM_PKTERR_ADDR_RNG		(1ull << 4)
+#define CA_CRM_PKTERR_ADDR_ALGN		(1ull << 5)
+#define CA_CRM_PKTERR_HDR_PARAM		(1ull << 6)
+#define CA_CRM_PKTERR_CW_ERR		(1ull << 7)
+#define CA_CRM_PKTERR_SBERR_NH		(1ull << 8)
+#define CA_CRM_PKTERR_EARLY_TERM	(1ull << 9)
+#define CA_CRM_PKTERR_EARLY_TAIL	(1ull << 10)
+#define CA_CRM_PKTERR_MSSNG_TAIL	(1ull << 11)
+#define CA_CRM_PKTERR_MSSNG_HDR		(1ull << 12)
+	/* bits 15:13 unused */
+#define CA_FIRST_CRM_PKTERR_SBERR_HDR	(1ull << 16)
+#define CA_FIRST_CRM_PKTERR_DIDN	(1ull << 17)
+#define CA_FIRST_CRM_PKTERR_PACTYPE	(1ull << 18)
+#define CA_FIRST_CRM_PKTERR_INV_TNUM	(1ull << 19)
+#define CA_FIRST_CRM_PKTERR_ADDR_RNG	(1ull << 20)
+#define CA_FIRST_CRM_PKTERR_ADDR_ALGN	(1ull << 21)
+#define CA_FIRST_CRM_PKTERR_HDR_PARAM	(1ull << 22)
+#define CA_FIRST_CRM_PKTERR_CW_ERR	(1ull << 23)
+#define CA_FIRST_CRM_PKTERR_SBERR_NH	(1ull << 24)
+#define CA_FIRST_CRM_PKTERR_EARLY_TERM	(1ull << 25)
+#define CA_FIRST_CRM_PKTERR_EARLY_TAIL	(1ull << 26)
+#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL	(1ull << 27)
+#define CA_FIRST_CRM_PKTERR_MSSNG_HDR	(1ull << 28)
+	/* bits 63:29 unused */
+
+/* ==== ca_crm_ct_error_detail_1 */
+#define CA_PKT_TYPE			(0xfull << 0)
+#define CA_PKT_TYPE_SHFT		0
+#define CA_SRC_ID			(0x3ull << 4)
+#define CA_SRC_ID_SHFT			4
+#define CA_DATA_SZ			(0x3ull << 6)
+#define CA_DATA_SZ_SHFT			6
+#define CA_TNUM				(0xffull << 8)
+#define CA_TNUM_SHFT			8
+#define CA_DW_DATA_EN			(0xffull << 16)
+#define CA_DW_DATA_EN_SHFT		16
+#define CA_GFX_CRED			(0xffull << 24)
+#define CA_GFX_CRED_SHFT		24
+#define CA_MEM_RD_PARAM			(0x3ull << 32)
+#define CA_MEM_RD_PARAM_SHFT		32
+#define CA_PIO_OP			(1ull << 34)
+#define CA_CW_ERR			(1ull << 35)
+	/* bits 62:36 unused */
+#define CA_VALID			(1ull << 63)
+
+/* ==== ca_crm_ct_error_detail_2 */
+	/* bits 2:0 unused */
+#define CA_PKT_ADDR			(0x1fffffffffffffull << 3)
+#define CA_PKT_ADDR_SHFT		3
+	/* bits 63:56 unused */
+
+/* ==== ca_crm_tnumto */
+#define CA_CRM_TNUMTO_VAL		(0xffull << 0)
+#define CA_CRM_TNUMTO_VAL_SHFT		0
+#define CA_CRM_TNUMTO_WR		(1ull << 8)
+	/* bits 63:9 unused */
+
+/* ==== ca_gart_err */
+#define CA_GART_ERR_SOURCE		(0x3ull << 0)
+#define CA_GART_ERR_SOURCE_SHFT		0
+	/* bits 3:2 unused */
+#define CA_GART_ERR_ADDR		(0xfffffffffull << 4)
+#define CA_GART_ERR_ADDR_SHFT		4
+	/* bits 63:40 unused */
+
+/* ==== ca_pcierr_type */
+#define CA_PCIERR_DATA			(0xffffffffull << 0)
+#define CA_PCIERR_DATA_SHFT		0
+#define CA_PCIERR_ENB			(0xfull << 32)
+#define CA_PCIERR_ENB_SHFT		32
+#define CA_PCIERR_CMD			(0xfull << 36)
+#define CA_PCIERR_CMD_SHFT		36
+#define CA_PCIERR_A64			(1ull << 40)
+#define CA_PCIERR_SLV_SERR		(1ull << 41)
+#define CA_PCIERR_SLV_WR_PERR		(1ull << 42)
+#define CA_PCIERR_SLV_RD_PERR		(1ull << 43)
+#define CA_PCIERR_MST_SERR		(1ull << 44)
+#define CA_PCIERR_MST_WR_PERR		(1ull << 45)
+#define CA_PCIERR_MST_RD_PERR		(1ull << 46)
+#define CA_PCIERR_MST_MABT		(1ull << 47)
+#define CA_PCIERR_MST_TABT		(1ull << 48)
+#define CA_PCIERR_MST_RETRY_TOUT	(1ull << 49)
+
+#define CA_PCIERR_TYPES \
+	(CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \
+	 CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \
+	 CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \
+	 CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT)
+
+	/* bits 63:50 unused */
+
+/* ==== ca_pci_dma_addr_extn */
+#define CA_UPPER_NODE_OFFSET		(0x3full << 0)
+#define CA_UPPER_NODE_OFFSET_SHFT	0
+	/* bits 7:6 unused */
+#define CA_CHIPLET_ID			(0x3ull << 8)
+#define CA_CHIPLET_ID_SHFT		8
+	/* bits 11:10 unused */
+#define CA_PCI_DMA_NODE_ID		(0xffffull << 12)
+#define CA_PCI_DMA_NODE_ID_SHFT		12
+	/* bits 27:26 unused */
+#define CA_PCI_DMA_PIO_MEM_TYPE		(1ull << 28)
+	/* bits 63:29 unused */
+
+
+/* ==== ca_agp_dma_addr_extn */
+	/* bits 19:0 unused */
+#define CA_AGP_DMA_NODE_ID		(0xffffull << 20)
+#define CA_AGP_DMA_NODE_ID_SHFT		20
+	/* bits 27:26 unused */
+#define CA_AGP_DMA_PIO_MEM_TYPE		(1ull << 28)
+	/* bits 63:29 unused */
+
+/* ==== ca_debug_vector_sel */
+#define CA_DEBUG_MN_VSEL		(0xfull << 0)
+#define CA_DEBUG_MN_VSEL_SHFT		0
+#define CA_DEBUG_PP_VSEL		(0xfull << 4)
+#define CA_DEBUG_PP_VSEL_SHFT		4
+#define CA_DEBUG_GW_VSEL		(0xfull << 8)
+#define CA_DEBUG_GW_VSEL_SHFT		8
+#define CA_DEBUG_GT_VSEL		(0xfull << 12)
+#define CA_DEBUG_GT_VSEL_SHFT		12
+#define CA_DEBUG_PD_VSEL		(0xfull << 16)
+#define CA_DEBUG_PD_VSEL_SHFT		16
+#define CA_DEBUG_AD_VSEL		(0xfull << 20)
+#define CA_DEBUG_AD_VSEL_SHFT		20
+#define CA_DEBUG_CX_VSEL		(0xfull << 24)
+#define CA_DEBUG_CX_VSEL_SHFT		24
+#define CA_DEBUG_CR_VSEL		(0xfull << 28)
+#define CA_DEBUG_CR_VSEL_SHFT		28
+#define CA_DEBUG_BA_VSEL		(0xfull << 32)
+#define CA_DEBUG_BA_VSEL_SHFT		32
+#define CA_DEBUG_PE_VSEL		(0xfull << 36)
+#define CA_DEBUG_PE_VSEL_SHFT		36
+#define CA_DEBUG_BO_VSEL		(0xfull << 40)
+#define CA_DEBUG_BO_VSEL_SHFT		40
+#define CA_DEBUG_BI_VSEL		(0xfull << 44)
+#define CA_DEBUG_BI_VSEL_SHFT		44
+#define CA_DEBUG_AS_VSEL		(0xfull << 48)
+#define CA_DEBUG_AS_VSEL_SHFT		48
+#define CA_DEBUG_PS_VSEL		(0xfull << 52)
+#define CA_DEBUG_PS_VSEL_SHFT		52
+#define CA_DEBUG_PM_VSEL		(0xfull << 56)
+#define CA_DEBUG_PM_VSEL_SHFT		56
+	/* bits 63:60 unused */
+
+/* ==== ca_debug_mux_core_sel */
+/* ==== ca_debug_mux_pci_sel */
+#define CA_DEBUG_MSEL0			(0x7ull << 0)
+#define CA_DEBUG_MSEL0_SHFT		0
+	/* bit 3 unused */
+#define CA_DEBUG_NSEL0			(0x7ull << 4)
+#define CA_DEBUG_NSEL0_SHFT		4
+	/* bit 7 unused */
+#define CA_DEBUG_MSEL1			(0x7ull << 8)
+#define CA_DEBUG_MSEL1_SHFT		8
+	/* bit 11 unused */
+#define CA_DEBUG_NSEL1			(0x7ull << 12)
+#define CA_DEBUG_NSEL1_SHFT		12
+	/* bit 15 unused */
+#define CA_DEBUG_MSEL2			(0x7ull << 16)
+#define CA_DEBUG_MSEL2_SHFT		16
+	/* bit 19 unused */
+#define CA_DEBUG_NSEL2			(0x7ull << 20)
+#define CA_DEBUG_NSEL2_SHFT		20
+	/* bit 23 unused */
+#define CA_DEBUG_MSEL3			(0x7ull << 24)
+#define CA_DEBUG_MSEL3_SHFT		24
+	/* bit 27 unused */
+#define CA_DEBUG_NSEL3			(0x7ull << 28)
+#define CA_DEBUG_NSEL3_SHFT		28
+	/* bit 31 unused */
+#define CA_DEBUG_MSEL4			(0x7ull << 32)
+#define CA_DEBUG_MSEL4_SHFT		32
+	/* bit 35 unused */
+#define CA_DEBUG_NSEL4			(0x7ull << 36)
+#define CA_DEBUG_NSEL4_SHFT		36
+	/* bit 39 unused */
+#define CA_DEBUG_MSEL5			(0x7ull << 40)
+#define CA_DEBUG_MSEL5_SHFT		40
+	/* bit 43 unused */
+#define CA_DEBUG_NSEL5			(0x7ull << 44)
+#define CA_DEBUG_NSEL5_SHFT		44
+	/* bit 47 unused */
+#define CA_DEBUG_MSEL6			(0x7ull << 48)
+#define CA_DEBUG_MSEL6_SHFT		48
+	/* bit 51 unused */
+#define CA_DEBUG_NSEL6			(0x7ull << 52)
+#define CA_DEBUG_NSEL6_SHFT		52
+	/* bit 55 unused */
+#define CA_DEBUG_MSEL7			(0x7ull << 56)
+#define CA_DEBUG_MSEL7_SHFT		56
+	/* bit 59 unused */
+#define CA_DEBUG_NSEL7			(0x7ull << 60)
+#define CA_DEBUG_NSEL7_SHFT		60
+	/* bit 63 unused */
+
+
+/* ==== ca_debug_domain_sel */
+#define CA_DEBUG_DOMAIN_L		(1ull << 0)
+#define CA_DEBUG_DOMAIN_H		(1ull << 1)
+	/* bits 63:2 unused */
+
+/* ==== ca_gart_ptr_table */
+#define CA_GART_PTR_VAL			(1ull << 0)
+	/* bits 11:1 unused */
+#define CA_GART_PTR_ADDR		(0xfffffffffffull << 12)
+#define CA_GART_PTR_ADDR_SHFT		12
+	/* bits 63:56 unused */
+
+/* ==== ca_gart_tlb_addr[0-7] */
+#define CA_GART_TLB_ADDR		(0xffffffffffffffull << 0)
+#define CA_GART_TLB_ADDR_SHFT		0
+	/* bits 62:56 unused */
+#define CA_GART_TLB_ENTRY_VAL		(1ull << 63)
+
+/*
+ * PIO address space ranges for TIO:CA
+ */
+
+/* CA internal registers */
+#define CA_PIO_ADMIN			0x00000000
+#define CA_PIO_ADMIN_LEN		0x00010000
+
+/* GFX Write Buffer - Diagnostics */
+#define CA_PIO_GFX			0x00010000
+#define CA_PIO_GFX_LEN			0x00010000
+
+/* AGP DMA Write Buffer - Diagnostics */
+#define CA_PIO_AGP_DMAWRITE		0x00020000
+#define CA_PIO_AGP_DMAWRITE_LEN		0x00010000
+
+/* AGP DMA READ Buffer - Diagnostics */
+#define CA_PIO_AGP_DMAREAD		0x00030000
+#define CA_PIO_AGP_DMAREAD_LEN		0x00010000
+
+/* PCI Config Type 0 */
+#define CA_PIO_PCI_TYPE0_CONFIG		0x01000000
+#define CA_PIO_PCI_TYPE0_CONFIG_LEN	0x01000000
+
+/* PCI Config Type 1 */
+#define CA_PIO_PCI_TYPE1_CONFIG		0x02000000
+#define CA_PIO_PCI_TYPE1_CONFIG_LEN	0x01000000
+
+/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */
+#define CA_PIO_PCI_IO			0x03000000
+#define CA_PIO_PCI_IO_LEN		0x05000000
+
+/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */
+/*	use Fast Write if enabled and coretalk packet type is a GFX request */
+#define CA_PIO_PCI_MEM_OFFSET		0x08000000
+#define CA_PIO_PCI_MEM_OFFSET_LEN	0x08000000
+
+/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */
+/*	use Fast Write if enabled and coretalk packet type is a GFX request */
+#define CA_PIO_PCI_MEM			0x40000000
+#define CA_PIO_PCI_MEM_LEN		0xc0000000
+
+/*
+ * DMA space
+ *
+ * The CA aperature (ie. bus address range) mapped by the GART is segmented into
+ * two parts.  The lower portion of the aperature is used for mapping 32 bit
+ * PCI addresses which are managed by the dma interfaces in this file.  The
+ * upper poprtion of the aperature is used for mapping 48 bit AGP addresses.
+ * The AGP portion of the aperature is managed by the agpgart_be.c driver
+ * in drivers/linux/agp.  There are ca-specific hooks in that driver to
+ * manipulate the gart, but management of the AGP portion of the aperature
+ * is the responsibility of that driver.
+ *
+ * CA allows three main types of DMA mapping:
+ *
+ * PCI 64-bit	Managed by this driver
+ * PCI 32-bit 	Managed by this driver
+ * AGP 48-bit	Managed by hooks in the /dev/agpgart driver
+ *
+ * All of the above can optionally be remapped through the GART.  The following
+ * table lists the combinations of addressing types and GART remapping that
+ * is currently supported by the driver (h/w supports all, s/w limits this):
+ *
+ *		PCI64		PCI32		AGP48
+ * GART		no		yes		yes
+ * Direct	yes		yes		no
+ *
+ * GART remapping of PCI64 is not done because there is no need to.  The
+ * 64 bit PCI address holds all of the information necessary to target any
+ * memory in the system.
+ *
+ * AGP48 is always mapped through the GART.  Management of the AGP48 portion
+ * of the aperature is the responsibility of code in the agpgart_be driver.
+ *
+ * The non-64 bit bus address space will currently be partitioned like this:
+ *
+ *	0xffff_ffff_ffff	+--------
+ *				| AGP48 direct
+ *				| Space managed by this driver
+ *	CA_AGP_DIRECT_BASE	+--------
+ *				| AGP GART mapped (gfx aperature)
+ *				| Space managed by /dev/agpgart driver
+ *				| This range is exposed to the agpgart
+ * 				| driver as the "graphics aperature"
+ *	CA_AGP_MAPPED_BASE	+-----
+ *				| PCI GART mapped
+ *				| Space managed by this driver		
+ *	CA_PCI32_MAPPED_BASE	+----
+ *				| PCI32 direct
+ *				| Space managed by this driver
+ *	0xC000_0000		+--------
+ *	(CA_PCI32_DIRECT_BASE)
+ *
+ * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE
+ * is what we call the CA aperature.  Addresses falling in this range will
+ * be remapped using the GART.
+ *
+ * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE
+ * is what we call the graphics aperature.  This is a subset of the CA
+ * aperature and is under the control of the agpgart_be driver.
+ *
+ * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are
+ * somewhat arbitrary values.  The known constraints on choosing these is:
+ *
+ * 1)  CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size)
+ *     must be one of the values supported by the ca_gart_aperature register.
+ *     Currently valid values are: 4MB through 4096MB in powers of 2 increments
+ *
+ * 2)  CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size)
+ *     must be in MB units since that's what the agpgart driver assumes.
+ */
+
+/*
+ * Define Bus DMA ranges.  These are configurable (see constraints above)
+ * and will probably need tuning based on experience.
+ */
+
+
+/*
+ * 11/24/03
+ * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it
+ * generally unusable.  The problem is that for PCI direct 32 
+ * DMA's, all 32 bits of the bus address are used to form the lower 32 bits
+ * of the coretalk address, and coretalk bits 38:32 come from a register.
+ * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available
+ * for DMA (the rest is allocated to PIO), host node addresses need to be
+ * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range
+ * as well.  So there can be no PCI32 direct DMA below 3GB!!  For this
+ * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes
+ * tioca_dma_direct32() a noop but preserves the code flow should this issue
+ * be fixed in a respin.
+ *
+ * For now, all PCI32 DMA's must be mapped through the GART.
+ */
+
+#define CA_PCI32_DIRECT_BASE	0xC0000000UL	/* BASE not configurable */
+#define CA_PCI32_DIRECT_SIZE	0x00000000UL	/* 0 MB */
+
+#define CA_PCI32_MAPPED_BASE	0xC0000000UL
+#define CA_PCI32_MAPPED_SIZE	0x40000000UL	/* 2GB */
+
+#define CA_AGP_MAPPED_BASE	0x80000000UL
+#define CA_AGP_MAPPED_SIZE	0x40000000UL	/* 2GB */
+
+#define CA_AGP_DIRECT_BASE	0x40000000UL	/* 2GB */
+#define CA_AGP_DIRECT_SIZE	0x40000000UL
+
+#define CA_APERATURE_BASE	(CA_AGP_MAPPED_BASE)
+#define CA_APERATURE_SIZE	(CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE)
+
+#endif  /* _ASM_IA64_SN_TIO_TIOCA_H */
diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/tioca_provider.h
@@ -0,0 +1,206 @@
+/*
+ * 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) 2003-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H
+#define _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H
+
+#include <asm/sn/tioca.h>
+
+/*
+ * WAR enables
+ * Defines for individual WARs. Each is a bitmask of applicable
+ * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B,
+ * (3 << 1) == (rev A or rev B), etc
+ */
+
+#define TIOCA_WAR_ENABLED(pv, tioca_common) \
+	((1 << tioca_common->ca_rev) & pv)
+
+  /* TIO:ICE:FRZ:Freezer loses a PIO data ucred on PIO RD RSP with CW error */
+#define PV907908 (1 << 1)
+  /* ATI config space problems after BIOS execution starts */
+#define PV908234 (1 << 1)
+  /* CA:AGPDMA write request data mismatch with ABC1CL merge */
+#define PV895469 (1 << 1)
+  /* TIO:CA TLB invalidate of written GART entries possibly not occuring in CA*/
+#define PV910244 (1 << 1)
+
+struct tioca_dmamap{
+	struct list_head	cad_list;	/* headed by ca_list */
+
+	dma_addr_t		cad_dma_addr;	/* Linux dma handle */
+	uint			cad_gart_entry; /* start entry in ca_gart_pagemap */
+	uint			cad_gart_size;	/* #entries for this map */
+};
+
+/*
+ * Kernel only fields.  Prom may look at this stuff for debugging only.
+ * Access this structure through the ca_kernel_private ptr.
+ */
+
+struct tioca_common ;
+
+struct tioca_kernel {
+	struct tioca_common	*ca_common;	/* tioca this belongs to */
+	struct list_head	ca_list;	/* list of all ca's */
+	struct list_head	ca_dmamaps;
+	spinlock_t		ca_lock;	/* Kernel lock */
+	cnodeid_t		ca_closest_node;
+	struct list_head	*ca_devices;	/* bus->devices */
+
+	/*
+	 * General GART stuff
+	 */
+	uint64_t	ca_ap_size;		/* size of aperature in bytes */
+	uint32_t	ca_gart_entries;	/* # uint64_t entries in gart */
+	uint32_t	ca_ap_pagesize; 	/* aperature page size in bytes */
+	uint64_t	ca_ap_bus_base; 	/* bus address of CA aperature */
+	uint64_t	ca_gart_size;		/* gart size in bytes */
+	uint64_t	*ca_gart;		/* gart table vaddr */
+	uint64_t	ca_gart_coretalk_addr;	/* gart coretalk addr */
+	uint8_t		ca_gart_iscoherent;	/* used in tioca_tlbflush */
+
+	/* PCI GART convenience values */
+	uint64_t	ca_pciap_base;		/* pci aperature bus base address */
+	uint64_t	ca_pciap_size;		/* pci aperature size (bytes) */
+	uint64_t	ca_pcigart_base;	/* gfx GART bus base address */
+	uint64_t	*ca_pcigart;		/* gfx GART vm address */
+	uint32_t	ca_pcigart_entries;
+	uint32_t	ca_pcigart_start;	/* PCI start index in ca_gart */
+	void		*ca_pcigart_pagemap;
+
+	/* AGP GART convenience values */
+	uint64_t	ca_gfxap_base;		/* gfx aperature bus base address */
+	uint64_t	ca_gfxap_size;		/* gfx aperature size (bytes) */
+	uint64_t	ca_gfxgart_base;	/* gfx GART bus base address */
+	uint64_t	*ca_gfxgart;		/* gfx GART vm address */
+	uint32_t	ca_gfxgart_entries;
+	uint32_t	ca_gfxgart_start;	/* agpgart start index in ca_gart */
+};
+
+/*
+ * Common tioca info shared between kernel and prom
+ *
+ * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES
+ * TO THE PROM VERSION.
+ */
+
+struct tioca_common {
+	struct pcibus_bussoft	ca_common;	/* common pciio header */
+
+	uint32_t		ca_rev;
+	uint32_t		ca_closest_nasid;
+
+	uint64_t		ca_prom_private;
+	uint64_t		ca_kernel_private;
+};
+
+/**
+ * tioca_paddr_to_gart - Convert an SGI coretalk address to a CA GART entry
+ * @paddr: page address to convert
+ *
+ * Convert a system [coretalk] address to a GART entry.  GART entries are
+ * formed using the following:
+ *
+ *     data = ( (1<<63) |  ( (REMAP_NODE_ID << 40) | (MD_CHIPLET_ID << 38) | 
+ * (REMAP_SYS_ADDR) ) >> 12 )
+ *
+ * DATA written to 1 GART TABLE Entry in system memory is remapped system
+ * addr for 1 page 
+ *
+ * The data is for coretalk address format right shifted 12 bits with a
+ * valid bit.
+ *
+ *	GART_TABLE_ENTRY [ 25:0 ]  -- REMAP_SYS_ADDRESS[37:12].
+ *	GART_TABLE_ENTRY [ 27:26 ] -- SHUB MD chiplet id.
+ *	GART_TABLE_ENTRY [ 41:28 ] -- REMAP_NODE_ID.
+ *	GART_TABLE_ENTRY [ 63 ]    -- Valid Bit 
+ */
+static inline u64
+tioca_paddr_to_gart(unsigned long paddr)
+{
+	/*
+	 * We are assuming right now that paddr already has the correct
+	 * format since the address from xtalk_dmaXXX should already have
+	 * NODE_ID, CHIPLET_ID, and SYS_ADDR in the correct locations.
+	 */
+
+	return ((paddr) >> 12) | (1UL << 63);
+}
+
+/**
+ * tioca_physpage_to_gart - Map a host physical page for SGI CA based DMA
+ * @page_addr: system page address to map
+ */
+
+static inline unsigned long
+tioca_physpage_to_gart(uint64_t page_addr)
+{
+	uint64_t coretalk_addr;
+
+	coretalk_addr = PHYS_TO_TIODMA(page_addr);
+	if (!coretalk_addr) {
+		return 0;
+	}
+
+	return tioca_paddr_to_gart(coretalk_addr);
+}
+
+/**
+ * tioca_tlbflush - invalidate cached SGI CA GART TLB entries
+ * @tioca_kernel: CA context 
+ *
+ * Invalidate tlb entries for a given CA GART.  Main complexity is to account
+ * for revA bug.
+ */
+static inline void
+tioca_tlbflush(struct tioca_kernel *tioca_kernel)
+{
+	volatile uint64_t tmp;
+	volatile struct tioca *ca_base;
+	struct tioca_common *tioca_common;
+
+	tioca_common = tioca_kernel->ca_common;
+	ca_base = (struct tioca *)tioca_common->ca_common.bs_base;
+
+	/*
+	 * Explicit flushes not needed if GART is in cached mode
+	 */
+	if (tioca_kernel->ca_gart_iscoherent) {
+		if (TIOCA_WAR_ENABLED(PV910244, tioca_common)) {
+			/*
+			 * PV910244:  RevA CA needs explicit flushes.
+			 * Need to put GART into uncached mode before
+			 * flushing otherwise the explicit flush is ignored.
+			 *
+			 * Alternate WAR would be to leave GART cached and
+			 * touch every CL aligned GART entry.
+			 */
+
+			ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM);
+			ca_base->ca_control2 |= CA_GART_FLUSH_TLB;
+			ca_base->ca_control2 |=
+			    (0x2ull << CA_GART_MEM_PARAM_SHFT);
+			tmp = ca_base->ca_control2;
+		}
+
+		return;
+	}
+
+	/*
+	 * Gart in uncached mode ... need an explicit flush.
+	 */
+
+	ca_base->ca_control2 |= CA_GART_FLUSH_TLB;
+	tmp = ca_base->ca_control2;
+}
+
+extern uint32_t	tioca_gart_found;
+extern int tioca_init_provider(void);
+extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern);
+#endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */
diff --git a/include/asm-ia64/sn/tiocx.h b/include/asm-ia64/sn/tiocx.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/tiocx.h
@@ -0,0 +1,71 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_TIO_TIOCX_H
+#define _ASM_IA64_SN_TIO_TIOCX_H
+
+#ifdef __KERNEL__
+
+struct cx_id_s {
+	unsigned int part_num;
+	unsigned int mfg_num;
+	int nasid;
+};
+
+struct cx_dev {
+	struct cx_id_s cx_id;
+	void *soft;			/* driver specific */
+	struct hubdev_info *hubdev;
+	struct device dev;
+	struct cx_drv *driver;
+};
+
+struct cx_device_id {
+	unsigned int part_num;
+	unsigned int mfg_num;
+};
+
+struct cx_drv {
+	char *name;
+	const struct cx_device_id *id_table;
+	struct device_driver driver;
+	int (*probe) (struct cx_dev * dev, const struct cx_device_id * id);
+	int (*remove) (struct cx_dev * dev);
+};
+
+/* create DMA address by stripping AS bits */
+#define TIOCX_DMA_ADDR(a) (uint64_t)((uint64_t)(a) & 0xffffcfffffffffUL)
+
+#define TIOCX_TO_TIOCX_DMA_ADDR(a) (uint64_t)(((uint64_t)(a) & 0xfffffffff) |  \
+                                  ((((uint64_t)(a)) & 0xffffc000000000UL) <<2))
+
+#define TIO_CE_ASIC_PARTNUM 0xce00
+#define TIOCX_CORELET 3
+
+/* These are taken from tio_mmr_as.h */
+#define TIO_ICE_FRZ_CFG               TIO_MMR_ADDR_MOD(0x00000000b0008100UL)
+#define TIO_ICE_PMI_TX_CFG            TIO_MMR_ADDR_MOD(0x00000000b000b100UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL
+
+#define to_cx_dev(n) container_of(n, struct cx_dev, dev)
+#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver)
+
+extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int);
+extern void tiocx_irq_free(struct sn_irq_info *);
+extern int cx_device_unregister(struct cx_dev *);
+extern int cx_device_register(nasid_t, int, int, struct hubdev_info *);
+extern int cx_driver_unregister(struct cx_drv *);
+extern int cx_driver_register(struct cx_drv *);
+extern uint64_t tiocx_dma_addr(uint64_t addr);
+extern uint64_t tiocx_swin_base(int nasid);
+extern void tiocx_mmr_store(int nasid, uint64_t offset, uint64_t value);
+extern uint64_t tiocx_mmr_load(int nasid, uint64_t offset);
+
+#endif				//  __KERNEL__
+#endif				// _ASM_IA64_SN_TIO_TIOCX__
diff --git a/include/asm-ia64/sn/types.h b/include/asm-ia64/sn/types.h
--- a/include/asm-ia64/sn/types.h
+++ b/include/asm-ia64/sn/types.h
@@ -16,7 +16,8 @@ typedef signed short	nasid_t;	/* node id
 typedef signed char	partid_t;	/* partition ID type */
 typedef unsigned int    moduleid_t;     /* user-visible module number type */
 typedef unsigned int    cmoduleid_t;    /* kernel compact module id type */
-typedef signed char     slabid_t;
+typedef unsigned char	slotid_t;	/* slot (blade) within module */
+typedef unsigned char	slabid_t;	/* slab (asic) within slot */
 typedef u64 nic_t;
 typedef unsigned long iopaddr_t;
 typedef unsigned long paddr_t;
diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ia64/sn/xp.h
@@ -0,0 +1,436 @@
+/*
+ * 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) 2004-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+/*
+ * External Cross Partition (XP) structures and defines.
+ */
+
+
+#ifndef _ASM_IA64_SN_XP_H
+#define _ASM_IA64_SN_XP_H
+
+
+#include <linux/version.h>
+#include <linux/cache.h>
+#include <linux/hardirq.h>
+#include <asm/sn/types.h>
+#include <asm/sn/bte.h>
+
+
+#ifdef USE_DBUG_ON
+#define DBUG_ON(condition)	BUG_ON(condition)
+#else
+#define DBUG_ON(condition)
+#endif
+
+
+/*
+ * Define the maximum number of logically defined partitions the system
+ * can support. It is constrained by the maximum number of hardware
+ * partitionable regions. The term 'region' in this context refers to the
+ * minimum number of nodes that can comprise an access protection grouping.
+ * The access protection is in regards to memory, IPI and IOI.
+ *
+ * The maximum number of hardware partitionable regions is equal to the
+ * maximum number of nodes in the entire system divided by the minimum number
+ * of nodes that comprise an access protection grouping.
+ */
+#define XP_MAX_PARTITIONS	64
+
+
+/*
+ * Define the number of u64s required to represent all the C-brick nasids
+ * as a bitmap.  The cross-partition kernel modules deal only with
+ * C-brick nasids, thus the need for bitmaps which don't account for
+ * odd-numbered (non C-brick) nasids.
+ */
+#define XP_MAX_PHYSNODE_ID	(MAX_PHYSNODE_ID / 2)
+#define XP_NASID_MASK_BYTES	((XP_MAX_PHYSNODE_ID + 7) / 8)
+#define XP_NASID_MASK_WORDS	((XP_MAX_PHYSNODE_ID + 63) / 64)
+
+
+/*
+ * Wrapper for bte_copy() that should it return a failure status will retry
+ * the bte_copy() once in the hope that the failure was due to a temporary
+ * aberration (i.e., the link going down temporarily).
+ *
+ * See bte_copy for definition of the input parameters.
+ *
+ * Note: xp_bte_copy() should never be called while holding a spinlock.
+ */
+static inline bte_result_t
+xp_bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
+{
+	bte_result_t ret;
+
+
+	ret = bte_copy(src, dest, len, mode, notification);
+
+	if (ret != BTE_SUCCESS) {
+		if (!in_interrupt()) {
+			cond_resched();
+		}
+		ret = bte_copy(src, dest, len, mode, notification);
+	}
+
+	return ret;
+}
+
+
+/*
+ * XPC establishes channel connections between the local partition and any
+ * other partition that is currently up. Over these channels, kernel-level
+ * `users' can communicate with their counterparts on the other partitions.
+ *
+ * The maxinum number of channels is limited to eight. For performance reasons,
+ * the internal cross partition structures require sixteen bytes per channel,
+ * and eight allows all of this interface-shared info to fit in one cache line.
+ *
+ * XPC_NCHANNELS reflects the total number of channels currently defined.
+ * If the need for additional channels arises, one can simply increase
+ * XPC_NCHANNELS accordingly. If the day should come where that number
+ * exceeds the MAXIMUM number of channels allowed (eight), then one will need
+ * to make changes to the XPC code to allow for this.
+ */
+#define XPC_MEM_CHANNEL		0	/* memory channel number */
+#define	XPC_NET_CHANNEL		1	/* network channel number */
+
+#define	XPC_NCHANNELS		2	/* #of defined channels */
+#define XPC_MAX_NCHANNELS	8	/* max #of channels allowed */
+
+#if XPC_NCHANNELS > XPC_MAX_NCHANNELS
+#error	XPC_NCHANNELS exceeds MAXIMUM allowed.
+#endif
+
+
+/*
+ * The format of an XPC message is as follows:
+ *
+ *      +-------+--------------------------------+
+ *      | flags |////////////////////////////////|
+ *      +-------+--------------------------------+
+ *      |             message #                  |
+ *      +----------------------------------------+
+ *      |     payload (user-defined message)     |
+ *      |                                        |
+ *         		:
+ *      |                                        |
+ *      +----------------------------------------+
+ *
+ * The size of the payload is defined by the user via xpc_connect(). A user-
+ * defined message resides in the payload area.
+ *
+ * The user should have no dealings with the message header, but only the
+ * message's payload. When a message entry is allocated (via xpc_allocate())
+ * a pointer to the payload area is returned and not the actual beginning of
+ * the XPC message. The user then constructs a message in the payload area
+ * and passes that pointer as an argument on xpc_send() or xpc_send_notify().
+ *
+ * The size of a message entry (within a message queue) must be a cacheline
+ * sized multiple in order to facilitate the BTE transfer of messages from one
+ * message queue to another. A macro, XPC_MSG_SIZE(), is provided for the user
+ * that wants to fit as many msg entries as possible in a given memory size
+ * (e.g. a memory page).
+ */
+struct xpc_msg {
+	u8 flags;		/* FOR XPC INTERNAL USE ONLY */
+	u8 reserved[7];		/* FOR XPC INTERNAL USE ONLY */
+	s64 number;		/* FOR XPC INTERNAL USE ONLY */
+
+	u64 payload;		/* user defined portion of message */
+};
+
+
+#define XPC_MSG_PAYLOAD_OFFSET	(u64) (&((struct xpc_msg *)0)->payload)
+#define XPC_MSG_SIZE(_payload_size) \
+		L1_CACHE_ALIGN(XPC_MSG_PAYLOAD_OFFSET + (_payload_size))
+
+
+/*
+ * Define the return values and values passed to user's callout functions.
+ * (It is important to add new value codes at the end just preceding
+ * xpcUnknownReason, which must have the highest numerical value.)
+ */
+enum xpc_retval {
+	xpcSuccess = 0,
+
+	xpcNotConnected,	/*  1: channel is not connected */
+	xpcConnected,		/*  2: channel connected (opened) */
+	xpcRETIRED1,		/*  3: (formerly xpcDisconnected) */
+
+	xpcMsgReceived,		/*  4: message received */
+	xpcMsgDelivered,	/*  5: message delivered and acknowledged */
+
+	xpcRETIRED2,		/*  6: (formerly xpcTransferFailed) */
+
+	xpcNoWait,		/*  7: operation would require wait */
+	xpcRetry,		/*  8: retry operation */
+	xpcTimeout,		/*  9: timeout in xpc_allocate_msg_wait() */
+	xpcInterrupted,		/* 10: interrupted wait */
+
+	xpcUnequalMsgSizes,	/* 11: message size disparity between sides */
+	xpcInvalidAddress,	/* 12: invalid address */
+
+	xpcNoMemory,		/* 13: no memory available for XPC structures */
+	xpcLackOfResources,	/* 14: insufficient resources for operation */
+	xpcUnregistered,	/* 15: channel is not registered */
+	xpcAlreadyRegistered,	/* 16: channel is already registered */
+
+	xpcPartitionDown,	/* 17: remote partition is down */
+	xpcNotLoaded,		/* 18: XPC module is not loaded */
+	xpcUnloading,		/* 19: this side is unloading XPC module */
+
+	xpcBadMagic,		/* 20: XPC MAGIC string not found */
+
+	xpcReactivating,	/* 21: remote partition was reactivated */
+
+	xpcUnregistering,	/* 22: this side is unregistering channel */
+	xpcOtherUnregistering,	/* 23: other side is unregistering channel */
+
+	xpcCloneKThread,	/* 24: cloning kernel thread */
+	xpcCloneKThreadFailed,	/* 25: cloning kernel thread failed */
+
+	xpcNoHeartbeat,		/* 26: remote partition has no heartbeat */
+
+	xpcPioReadError,	/* 27: PIO read error */
+	xpcPhysAddrRegFailed,	/* 28: registration of phys addr range failed */
+
+	xpcBteDirectoryError,	/* 29: maps to BTEFAIL_DIR */
+	xpcBtePoisonError,	/* 30: maps to BTEFAIL_POISON */
+	xpcBteWriteError,	/* 31: maps to BTEFAIL_WERR */
+	xpcBteAccessError,	/* 32: maps to BTEFAIL_ACCESS */
+	xpcBtePWriteError,	/* 33: maps to BTEFAIL_PWERR */
+	xpcBtePReadError,	/* 34: maps to BTEFAIL_PRERR */
+	xpcBteTimeOutError,	/* 35: maps to BTEFAIL_TOUT */
+	xpcBteXtalkError,	/* 36: maps to BTEFAIL_XTERR */
+	xpcBteNotAvailable,	/* 37: maps to BTEFAIL_NOTAVAIL */
+	xpcBteUnmappedError,	/* 38: unmapped BTEFAIL_ error */
+
+	xpcBadVersion,		/* 39: bad version number */
+	xpcVarsNotSet,		/* 40: the XPC variables are not set up */
+	xpcNoRsvdPageAddr,	/* 41: unable to get rsvd page's phys addr */
+	xpcInvalidPartid,	/* 42: invalid partition ID */
+	xpcLocalPartid,		/* 43: local partition ID */
+
+	xpcUnknownReason	/* 44: unknown reason -- must be last in list */
+};
+
+
+/*
+ * Define the callout function types used by XPC to update the user on
+ * connection activity and state changes (via the user function registered by
+ * xpc_connect()) and to notify them of messages received and delivered (via
+ * the user function registered by xpc_send_notify()).
+ *
+ * The two function types are xpc_channel_func and xpc_notify_func and
+ * both share the following arguments, with the exception of "data", which
+ * only xpc_channel_func has.
+ *
+ * Arguments:
+ *
+ *	reason - reason code. (See following table.)
+ *	partid - partition ID associated with condition.
+ *	ch_number - channel # associated with condition.
+ *	data - pointer to optional data. (See following table.)
+ *	key - pointer to optional user-defined value provided as the "key"
+ *	      argument to xpc_connect() or xpc_send_notify().
+ *
+ * In the following table the "Optional Data" column applies to callouts made
+ * to functions registered by xpc_connect(). A "NA" in that column indicates
+ * that this reason code can be passed to functions registered by
+ * xpc_send_notify() (i.e. they don't have data arguments).
+ *
+ * Also, the first three reason codes in the following table indicate
+ * success, whereas the others indicate failure. When a failure reason code
+ * is received, one can assume that the channel is not connected.
+ *
+ *
+ * Reason Code          | Cause                          | Optional Data
+ * =====================+================================+=====================
+ * xpcConnected         | connection has been established| max #of entries
+ *                      | to the specified partition on  | allowed in message
+ *                      | the specified channel          | queue
+ * ---------------------+--------------------------------+---------------------
+ * xpcMsgReceived       | an XPC message arrived from    | address of payload
+ *                      | the specified partition on the |
+ *                      | specified channel              | [the user must call
+ *                      |                                | xpc_received() when
+ *                      |                                | finished with the
+ *                      |                                | payload]
+ * ---------------------+--------------------------------+---------------------
+ * xpcMsgDelivered      | notification that the message  | NA
+ *                      | was delivered to the intended  |
+ *                      | recipient and that they have   |
+ *                      | acknowledged its receipt by    |
+ *                      | calling xpc_received()         |
+ * =====================+================================+=====================
+ * xpcUnequalMsgSizes   | can't connect to the specified | NULL
+ *                      | partition on the specified     |
+ *                      | channel because of mismatched  |
+ *                      | message sizes                  |
+ * ---------------------+--------------------------------+---------------------
+ * xpcNoMemory          | insufficient memory avaiable   | NULL
+ *                      | to allocate message queue      |
+ * ---------------------+--------------------------------+---------------------
+ * xpcLackOfResources   | lack of resources to create    | NULL
+ *                      | the necessary kthreads to      |
+ *                      | support the channel            |
+ * ---------------------+--------------------------------+---------------------
+ * xpcUnregistering     | this side's user has           | NULL or NA
+ *                      | unregistered by calling        |
+ *                      | xpc_disconnect()               |
+ * ---------------------+--------------------------------+---------------------
+ * xpcOtherUnregistering| the other side's user has      | NULL or NA
+ *                      | unregistered by calling        |
+ *                      | xpc_disconnect()               |
+ * ---------------------+--------------------------------+---------------------
+ * xpcNoHeartbeat       | the other side's XPC is no     | NULL or NA
+ *                      | longer heartbeating            |
+ *                      |                                |
+ * ---------------------+--------------------------------+---------------------
+ * xpcUnloading         | this side's XPC module is      | NULL or NA
+ *                      | being unloaded                 |
+ *                      |                                |
+ * ---------------------+--------------------------------+---------------------
+ * xpcOtherUnloading    | the other side's XPC module is | NULL or NA
+ *                      | is being unloaded              |
+ *                      |                                |
+ * ---------------------+--------------------------------+---------------------
+ * xpcPioReadError      | xp_nofault_PIOR() returned an  | NULL or NA
+ *                      | error while sending an IPI     |
+ *                      |                                |
+ * ---------------------+--------------------------------+---------------------
+ * xpcInvalidAddress    | the address either received or | NULL or NA
+ *                      | sent by the specified partition|
+ *                      | is invalid                     |
+ * ---------------------+--------------------------------+---------------------
+ * xpcBteNotAvailable   | attempt to pull data from the  | NULL or NA
+ * xpcBtePoisonError    | specified partition over the   |
+ * xpcBteWriteError     | specified channel via a        |
+ * xpcBteAccessError    | bte_copy() failed              |
+ * xpcBteTimeOutError   |                                |
+ * xpcBteXtalkError     |                                |
+ * xpcBteDirectoryError |                                |
+ * xpcBteGenericError   |                                |
+ * xpcBteUnmappedError  |                                |
+ * ---------------------+--------------------------------+---------------------
+ * xpcUnknownReason     | the specified channel to the   | NULL or NA
+ *                      | specified partition was        |
+ *                      | unavailable for unknown reasons|
+ * =====================+================================+=====================
+ */
+
+typedef void (*xpc_channel_func)(enum xpc_retval reason, partid_t partid,
+		int ch_number, void *data, void *key);
+
+typedef void (*xpc_notify_func)(enum xpc_retval reason, partid_t partid,
+		int ch_number, void *key);
+
+
+/*
+ * The following is a registration entry. There is a global array of these,
+ * one per channel. It is used to record the connection registration made
+ * by the users of XPC. As long as a registration entry exists, for any
+ * partition that comes up, XPC will attempt to establish a connection on
+ * that channel. Notification that a connection has been made will occur via
+ * the xpc_channel_func function.
+ *
+ * The 'func' field points to the function to call when aynchronous
+ * notification is required for such events as: a connection established/lost,
+ * or an incomming message received, or an error condition encountered. A
+ * non-NULL 'func' field indicates that there is an active registration for
+ * the channel.
+ */
+struct xpc_registration {
+	struct semaphore sema;
+	xpc_channel_func func;		/* function to call */
+	void *key;			/* pointer to user's key */
+	u16 nentries;			/* #of msg entries in local msg queue */
+	u16 msg_size;			/* message queue's message size */
+	u32 assigned_limit;		/* limit on #of assigned kthreads */
+	u32 idle_limit;			/* limit on #of idle kthreads */
+} ____cacheline_aligned;
+
+
+#define XPC_CHANNEL_REGISTERED(_c)	(xpc_registrations[_c].func != NULL)
+
+
+/* the following are valid xpc_allocate() flags */
+#define XPC_WAIT	0		/* wait flag */
+#define XPC_NOWAIT	1		/* no wait flag */
+
+
+struct xpc_interface {
+	void (*connect)(int);
+	void (*disconnect)(int);
+	enum xpc_retval (*allocate)(partid_t, int, u32, void **);
+	enum xpc_retval (*send)(partid_t, int, void *);
+	enum xpc_retval (*send_notify)(partid_t, int, void *,
+						xpc_notify_func, void *);
+	void (*received)(partid_t, int, void *);
+	enum xpc_retval (*partid_to_nasids)(partid_t, void *);
+};
+
+
+extern struct xpc_interface xpc_interface;
+
+extern void xpc_set_interface(void (*)(int),
+		void (*)(int),
+		enum xpc_retval (*)(partid_t, int, u32, void **),
+		enum xpc_retval (*)(partid_t, int, void *),
+		enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func,
+								void *),
+		void (*)(partid_t, int, void *),
+		enum xpc_retval (*)(partid_t, void *));
+extern void xpc_clear_interface(void);
+
+
+extern enum xpc_retval xpc_connect(int, xpc_channel_func, void *, u16,
+						u16, u32, u32);
+extern void xpc_disconnect(int);
+
+static inline enum xpc_retval
+xpc_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+{
+	return xpc_interface.allocate(partid, ch_number, flags, payload);
+}
+
+static inline enum xpc_retval
+xpc_send(partid_t partid, int ch_number, void *payload)
+{
+	return xpc_interface.send(partid, ch_number, payload);
+}
+
+static inline enum xpc_retval
+xpc_send_notify(partid_t partid, int ch_number, void *payload,
+			xpc_notify_func func, void *key)
+{
+	return xpc_interface.send_notify(partid, ch_number, payload, func, key);
+}
+
+static inline void
+xpc_received(partid_t partid, int ch_number, void *payload)
+{
+	return xpc_interface.received(partid, ch_number, payload);
+}
+
+static inline enum xpc_retval
+xpc_partid_to_nasids(partid_t partid, void *nasids)
+{
+	return xpc_interface.partid_to_nasids(partid, nasids);
+}
+
+
+extern u64 xp_nofault_PIOR_target;
+extern int xp_nofault_PIOR(void *);
+extern int xp_error_PIOR(void);
+
+
+#endif /* _ASM_IA64_SN_XP_H */
+
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -285,6 +285,9 @@ do {						\
 #define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
 
 void cpu_idle_wait(void);
+
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h
--- a/include/asm-ia64/tlb.h
+++ b/include/asm-ia64/tlb.h
@@ -161,11 +161,11 @@ tlb_finish_mmu (struct mmu_gather *tlb, 
 {
 	unsigned long freed = tlb->freed;
 	struct mm_struct *mm = tlb->mm;
-	unsigned long rss = mm->rss;
+	unsigned long rss = get_mm_counter(mm, rss);
 
 	if (rss < freed)
 		freed = rss;
-	mm->rss = rss - freed;
+	add_mm_counter(mm, rss, -freed);
 	/*
 	 * Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
 	 * tlb->end_addr.
diff --git a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
--- a/include/asm-ia64/uaccess.h
+++ b/include/asm-ia64/uaccess.h
@@ -35,9 +35,12 @@
 #include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/page-flags.h>
+#include <linux/mm.h>
 
 #include <asm/intrinsics.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 
 /*
  * For historical reasons, the following macros are grossly misnamed:
@@ -69,7 +72,8 @@
 })
 #define access_ok(type, addr, size)	__access_ok((addr), (size), get_fs())
 
-static inline int
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated
 verify_area (int type, const void __user *addr, unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
@@ -367,4 +371,38 @@ ia64_done_with_exception (struct pt_regs
 	return 0;
 }
 
+#define ARCH_HAS_TRANSLATE_MEM_PTR	1
+static __inline__ char *
+xlate_dev_mem_ptr (unsigned long p)
+{
+	struct page *page;
+	char * ptr;
+
+	page = pfn_to_page(p >> PAGE_SHIFT);
+	if (PageUncached(page))
+		ptr = (char *)p + __IA64_UNCACHED_OFFSET;
+	else
+		ptr = __va(p);
+
+	return ptr;
+}
+
+/*
+ * Convert a virtual cached kernel memory pointer to an uncached pointer
+ */
+static __inline__ char *
+xlate_dev_kmem_ptr (char * p)
+{
+	struct page *page;
+	char * ptr;
+
+	page = virt_to_page((unsigned long)p >> PAGE_SHIFT);
+	if (PageUncached(page))
+		ptr = (char *)__pa(p) + __IA64_UNCACHED_OFFSET;
+	else
+		ptr = p;
+
+	return ptr;
+}
+
 #endif /* _ASM_IA64_UACCESS_H */
diff --git a/include/asm-ia64/unaligned.h b/include/asm-ia64/unaligned.h
--- a/include/asm-ia64/unaligned.h
+++ b/include/asm-ia64/unaligned.h
@@ -1,121 +1,6 @@
 #ifndef _ASM_IA64_UNALIGNED_H
 #define _ASM_IA64_UNALIGNED_H
 
-#include <linux/types.h>
-
-/*
- * The main single-value unaligned transfer routines.
- *
- * Based on <asm-alpha/unaligned.h>.
- *
- * Copyright (C) 1998, 1999, 2003 Hewlett-Packard Co
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- */
-#define get_unaligned(ptr) \
-	((__typeof__(*(ptr)))ia64_get_unaligned((ptr), sizeof(*(ptr))))
-
-#define put_unaligned(x,ptr) \
-	ia64_put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
-
-struct __una_u64 { __u64 x __attribute__((packed)); };
-struct __una_u32 { __u32 x __attribute__((packed)); };
-struct __una_u16 { __u16 x __attribute__((packed)); };
-
-static inline unsigned long
-__uld8 (const unsigned long * addr)
-{
-	const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
-	return ptr->x;
-}
-
-static inline unsigned long
-__uld4 (const unsigned int * addr)
-{
-	const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
-	return ptr->x;
-}
-
-static inline unsigned long
-__uld2 (const unsigned short * addr)
-{
-	const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
-	return ptr->x;
-}
-
-static inline void
-__ust8 (unsigned long val, unsigned long * addr)
-{
-	struct __una_u64 *ptr = (struct __una_u64 *) addr;
-	ptr->x = val;
-}
-
-static inline void
-__ust4 (unsigned long val, unsigned int * addr)
-{
-	struct __una_u32 *ptr = (struct __una_u32 *) addr;
-	ptr->x = val;
-}
-
-static inline void
-__ust2 (unsigned long val, unsigned short * addr)
-{
-	struct __una_u16 *ptr = (struct __una_u16 *) addr;
-	ptr->x = val;
-}
-
-
-/*
- * This function doesn't actually exist.  The idea is that when someone uses the macros
- * below with an unsupported size (datatype), the linker will alert us to the problem via
- * an unresolved reference error.
- */
-extern unsigned long ia64_bad_unaligned_access_length (void);
-
-#define ia64_get_unaligned(_ptr,size)						\
-({										\
-	const void *__ia64_ptr = (_ptr);					\
-	unsigned long __ia64_val;						\
-										\
-	switch (size) {								\
-	      case 1:								\
-		__ia64_val = *(const unsigned char *) __ia64_ptr;		\
-		break;								\
-	      case 2:								\
-		__ia64_val = __uld2((const unsigned short *)__ia64_ptr);	\
-		break;								\
-	      case 4:								\
-		__ia64_val = __uld4((const unsigned int *)__ia64_ptr);		\
-		break;								\
-	      case 8:								\
-		__ia64_val = __uld8((const unsigned long *)__ia64_ptr);		\
-		break;								\
-	      default:								\
-		__ia64_val = ia64_bad_unaligned_access_length();		\
-	}									\
-	__ia64_val;								\
-})
-
-#define ia64_put_unaligned(_val,_ptr,size)				\
-do {									\
-	const void *__ia64_ptr = (_ptr);				\
-	unsigned long __ia64_val = (_val);				\
-									\
-	switch (size) {							\
-	      case 1:							\
-		*(unsigned char *)__ia64_ptr = (__ia64_val);		\
-	        break;							\
-	      case 2:							\
-		__ust2(__ia64_val, (unsigned short *)__ia64_ptr);	\
-		break;							\
-	      case 4:							\
-		__ust4(__ia64_val, (unsigned int *)__ia64_ptr);		\
-		break;							\
-	      case 8:							\
-		__ust8(__ia64_val, (unsigned long *)__ia64_ptr);	\
-		break;							\
-	      default:							\
-	    	ia64_bad_unaligned_access_length();			\
-	}								\
-} while (0)
+#include <asm-generic/unaligned.h>
 
 #endif /* _ASM_IA64_UNALIGNED_H */
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -392,7 +392,7 @@ asmlinkage long sys_rt_sigaction(int sig
  * proper prototype, but we can't use __typeof__ either, because not all cond_syscall()
  * declarations have prototypes at the moment.
  */
-#define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall")));
+#define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall")))
 
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
diff --git a/include/asm-m32r/bug.h b/include/asm-m32r/bug.h
--- a/include/asm-m32r/bug.h
+++ b/include/asm-m32r/bug.h
@@ -1,22 +1,4 @@
 #ifndef _M32R_BUG_H
 #define _M32R_BUG_H
-
-#define BUG()	do { \
-	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-} while (0)
-
-#define PAGE_BUG(page)	do { BUG(); } while (0)
-
-#define BUG_ON(condition) \
-	do { if (unlikely((condition)!=0)) BUG(); } while(0)
-
-#define WARN_ON(condition) do { \
-	if (unlikely((condition)!=0)) { \
-		printk("Badness in %s at %s:%d\n", __FUNCTION__, \
-		__FILE__, __LINE__); \
-		dump_stack(); \
-	} \
-} while (0)
-
-#endif /* _M32R_BUG_H */
-
+#include <asm-generic/bug.h>
+#endif
diff --git a/include/asm-m32r/cacheflush.h b/include/asm-m32r/cacheflush.h
--- a/include/asm-m32r/cacheflush.h
+++ b/include/asm-m32r/cacheflush.h
@@ -11,7 +11,7 @@ extern void _flush_cache_copyback_all(vo
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -31,7 +31,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -43,7 +43,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-m32r/io.h b/include/asm-m32r/io.h
--- a/include/asm-m32r/io.h
+++ b/include/asm-m32r/io.h
@@ -216,6 +216,17 @@ memcpy_toio(volatile void __iomem *dst, 
 	memcpy((void __force *) dst, src, count);
 }
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif  /* __KERNEL__ */
 
 #endif  /* _ASM_M32R_IO_H */
diff --git a/include/asm-m32r/ipc.h b/include/asm-m32r/ipc.h
--- a/include/asm-m32r/ipc.h
+++ b/include/asm-m32r/ipc.h
@@ -1,35 +1 @@
-#ifndef __M32R_IPC_H__
-#define __M32R_IPC_H__
-
-/* orig : i386/ipc.h 2.6.0-test3 */
-
-/*
- * These are used to wrap system calls on x86.
- *
- * See arch/i386/kernel/sys_i386.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif	/* __M32R_IPC_H__ */
-
+#include <asm-generic/ipc.h>
diff --git a/include/asm-m32r/mmu.h b/include/asm-m32r/mmu.h
--- a/include/asm-m32r/mmu.h
+++ b/include/asm-m32r/mmu.h
@@ -1,25 +1,12 @@
 #ifndef _ASM_M32R_MMU_H
 #define _ASM_M32R_MMU_H
 
-/* $Id$ */
-
 #include <linux/config.h>
 
 #if !defined(CONFIG_MMU)
-struct mm_rblock_struct {
-  int     size;
-  int     refcount;
-  void    *kblock;
-};
-
-struct mm_tblock_struct {
-  struct mm_rblock_struct *rblock;
-  struct mm_tblock_struct *next;
-};
-
 typedef struct {
-  struct mm_tblock_struct tblock;
-  unsigned long           end_brk;
+	struct vm_list_struct	*vmlist;
+	unsigned long		end_brk;
 } mm_context_t;
 #else
 
@@ -32,4 +19,3 @@ typedef unsigned long mm_context_t[NR_CP
 
 #endif  /* CONFIG_MMU */
 #endif  /* _ASM_M32R_MMU_H */
-
diff --git a/include/asm-m32r/pgalloc.h b/include/asm-m32r/pgalloc.h
--- a/include/asm-m32r/pgalloc.h
+++ b/include/asm-m32r/pgalloc.h
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 
 #include <asm/io.h>
-#include <asm/pgtable.h>
 
 #define pmd_populate_kernel(mm, pmd, pte)	\
 	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
--- a/include/asm-m32r/pgtable-2level.h
+++ b/include/asm-m32r/pgtable-2level.h
@@ -44,6 +44,7 @@ static inline int pgd_present(pgd_t pgd)
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 #define set_pte_atomic(pteptr, pteval)	set_pte(pteptr, pteval)
 /*
  * (pmds are folded into pgds so this doesnt get actually called,
@@ -60,7 +61,7 @@ static inline pmd_t *pmd_offset(pgd_t * 
 	return (pmd_t *) dir;
 }
 
-#define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte, 0))
+#define ptep_get_and_clear(mm,addr,xp)	__pte(xchg(&(xp)->pte, 0))
 #define pte_same(a, b)		(pte_val(a) == pte_val(b))
 #define pte_page(x)		pfn_to_page(pte_pfn(x))
 #define pte_none(x)		(!pte_val(x))
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -51,7 +51,7 @@ extern unsigned long empty_zero_page[102
 #define PGDIR_MASK	(~(PGDIR_SIZE - 1))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #ifndef __ASSEMBLY__
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
@@ -176,7 +176,7 @@ extern unsigned long empty_zero_page[102
 /* page table for 0-4MB for everybody */
 
 #define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
+#define pte_clear(mm,addr,xp)	do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
@@ -282,26 +282,21 @@ static inline pte_t pte_mkwrite(pte_t pt
 	return pte;
 }
 
-static inline  int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline  int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
 }
 
-static inline  int ptep_test_and_clear_young(pte_t *ptep)
+static inline  int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	clear_bit(_PAGE_BIT_WRITE, ptep);
 }
 
-static inline void ptep_mkdirty(pte_t *ptep)
-{
-	set_bit(_PAGE_BIT_DIRTY, ptep);
-}
-
 /*
  * Macro and implementation to make a page protection as uncachable.
  */
@@ -386,11 +381,17 @@ static inline void pmd_set(pmd_t * pmdp,
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)	\
 	remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)	\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-m32r/serial.h b/include/asm-m32r/serial.h
--- a/include/asm-m32r/serial.h
+++ b/include/asm-m32r/serial.h
@@ -1,151 +1,10 @@
 #ifndef _ASM_M32R_SERIAL_H
 #define _ASM_M32R_SERIAL_H
 
-/* $Id$ */
-
-/* orig : i386 2.4.18 */
-
-/*
- * include/asm-m32r/serial.h
- */
+/* include/asm-m32r/serial.h */
 
 #include <linux/config.h>
-#include <asm/m32r.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 */
-
-
-#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
-
-#ifndef CONFIG_PLAT_USRV
-#define SERIAL_PORT_DFNS		\
-	STD_SERIAL_PORT_DEFNS		\
-	EXTRA_SERIAL_PORT_DEFNS		\
-	HUB6_SERIAL_PORT_DFNS		\
-	MCA_SERIAL_PORT_DFNS
-
-#else	/* CONFIG_PLAT_USRV */
 
-#define SERIAL_PORT_DFNS		\
-	/* UART CLK   PORT IRQ     FLAGS        */			\
-	{ 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS },	/* ttyS1 */
-#endif	/* CONFIG_PLAT_USRV */
+#define BASE_BAUD	115200
 
 #endif  /* _ASM_M32R_SERIAL_H */
diff --git a/include/asm-m32r/signal.h b/include/asm-m32r/signal.h
--- a/include/asm-m32r/signal.h
+++ b/include/asm-m32r/signal.h
@@ -114,34 +114,7 @@ typedef unsigned long sigset_t;
 #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 __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h
--- a/include/asm-m32r/spinlock.h
+++ b/include/asm-m32r/spinlock.h
@@ -102,10 +102,8 @@ static inline void _raw_spin_lock(spinlo
 	unsigned long tmp0, tmp1;
 
 #ifdef CONFIG_DEBUG_SPINLOCK
-	__label__ here;
-here:
-	if (lock->magic != SPINLOCK_MAGIC) {
-		printk("pc: %p\n", &&here);
+	if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+		printk("pc: %p\n", __builtin_return_address(0));
 		BUG();
 	}
 #endif
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -294,4 +294,6 @@ static __inline__ unsigned long __xchg(u
 #define set_mb(var, value) do { xchg(&var, value); } while (0)
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
+#define arch_align_stack(x) (x)
+
 #endif  /* _ASM_M32R_SYSTEM_H */
diff --git a/include/asm-m32r/timex.h b/include/asm-m32r/timex.h
--- a/include/asm-m32r/timex.h
+++ b/include/asm-m32r/timex.h
@@ -25,8 +25,6 @@
 
 typedef unsigned long long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static __inline__ cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-m32r/uaccess.h b/include/asm-m32r/uaccess.h
--- a/include/asm-m32r/uaccess.h
+++ b/include/asm-m32r/uaccess.h
@@ -121,7 +121,8 @@ static inline int access_ok(int type, co
 #endif /* CONFIG_MMU */
 
 /**
- * verify_area: - Obsolete, use access_ok()
+ * verify_area: - Obsolete/deprecated and will go away soon,
+ * use access_ok() instead.
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
  * @addr: User space pointer to start of block to check
  * @size: Size of block to check
@@ -137,7 +138,7 @@ static inline int access_ok(int type, co
  *
  * See access_ok() for more details.
  */
-static inline int verify_area(int type, const void __user *addr,
+static inline int __deprecated verify_area(int type, const void __user *addr,
 			      unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h
--- a/include/asm-m32r/unistd.h
+++ b/include/asm-m32r/unistd.h
@@ -468,7 +468,7 @@ asmlinkage long sys_rt_sigaction(int sig
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* _ASM_M32R_UNISTD_H */
diff --git a/include/asm-m68k/bug.h b/include/asm-m68k/bug.h
--- a/include/asm-m68k/bug.h
+++ b/include/asm-m68k/bug.h
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #ifndef CONFIG_SUN3
 #define BUG() do { \
@@ -22,6 +23,8 @@
 #endif
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
--- a/include/asm-m68k/cacheflush.h
+++ b/include/asm-m68k/cacheflush.h
@@ -99,8 +99,7 @@ static inline void flush_cache_range(str
 	        __flush_cache_030();
 }
 
-static inline void flush_cache_page(struct vm_area_struct *vma,
-				    unsigned long vmaddr)
+static inline void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
 {
 	if (vma->vm_mm == current->mm)
 	        __flush_cache_030();
@@ -134,15 +133,15 @@ static inline void __flush_page_to_ram(v
 #define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
 	} while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
 	} while (0)
 
 extern void flush_icache_range(unsigned long address, unsigned long endaddr);
diff --git a/include/asm-m68k/checksum.h b/include/asm-m68k/checksum.h
--- a/include/asm-m68k/checksum.h
+++ b/include/asm-m68k/checksum.h
@@ -43,20 +43,21 @@ static inline unsigned short
 ip_fast_csum(unsigned char *iph, unsigned int ihl)
 {
 	unsigned int sum = 0;
+	unsigned long tmp;
 
 	__asm__ ("subqw #1,%2\n"
 		 "1:\t"
-		 "movel %1@+,%/d0\n\t"
-		 "addxl %/d0,%0\n\t"
+		 "movel %1@+,%3\n\t"
+		 "addxl %3,%0\n\t"
 		 "dbra  %2,1b\n\t"
-		 "movel %0,%/d0\n\t"
-		 "swap  %/d0\n\t"
-		 "addxw %/d0,%0\n\t"
-		 "clrw  %/d0\n\t"
-		 "addxw %/d0,%0\n\t"
-		 : "=d" (sum), "=a" (iph), "=d" (ihl)
+		 "movel %0,%3\n\t"
+		 "swap  %3\n\t"
+		 "addxw %3,%0\n\t"
+		 "clrw  %3\n\t"
+		 "addxw %3,%0\n\t"
+		 : "=d" (sum), "=&a" (iph), "=&d" (ihl), "=&d" (tmp)
 		 : "0" (sum), "1" (iph), "2" (ihl)
-		 : "d0");
+		 : "memory");
 	return ~sum;
 }
 
@@ -72,31 +73,31 @@ static inline unsigned int csum_fold(uns
 		"clrw %1\n\t"
 		"addxw %1, %0"
 		: "=&d" (sum), "=&d" (tmp)
-		: "0" (sum), "1" (sum));
+		: "0" (sum), "1" (tmp));
 	return ~sum;
 }
 
 
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-
 static inline unsigned int
 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
 		  unsigned short proto, unsigned int sum)
 {
-	__asm__ ("addl  %1,%0\n\t"
+	__asm__ ("addl  %2,%0\n\t"
+		 "addxl %3,%0\n\t"
 		 "addxl %4,%0\n\t"
-		 "addxl %5,%0\n\t"
 		 "clrl %1\n\t"
 		 "addxl %1,%0"
-		 : "=&d" (sum), "=&d" (saddr)
-		 : "0" (daddr), "1" (saddr), "d" (len + proto),
-		   "d"(sum));
+		 : "=&d" (sum), "=d" (saddr)
+		 : "g" (daddr), "1" (saddr), "d" (len + proto),
+		   "0" (sum));
 	return sum;
 }
 
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
 static inline unsigned short int
 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
 		  unsigned short proto, unsigned int sum)
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -359,4 +359,18 @@ extern void dma_cache_inv(unsigned long 
 #endif
 
 #endif /* __KERNEL__ */
+
+#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED		1
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* _IO_H */
diff --git a/include/asm-m68k/ipc.h b/include/asm-m68k/ipc.h
--- a/include/asm-m68k/ipc.h
+++ b/include/asm-m68k/ipc.h
@@ -1,31 +1 @@
-#ifndef __m68k_IPC_H__
-#define __m68k_IPC_H__
-
-/*
- * These are used to wrap system calls on m68k.
- *
- * See arch/m68k/kernel/sys_m68k.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#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
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC		25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-m68k/motorola_pgtable.h b/include/asm-m68k/motorola_pgtable.h
--- a/include/asm-m68k/motorola_pgtable.h
+++ b/include/asm-m68k/motorola_pgtable.h
@@ -129,7 +129,7 @@ static inline void pgd_set(pgd_t *pgdp, 
 
 #define pte_none(pte)		(!pte_val(pte))
 #define pte_present(pte)	(pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(ptep)		({ pte_val(*(ptep)) = 0; })
+#define pte_clear(mm,addr,ptep)		({ pte_val(*(ptep)) = 0; })
 
 #define pte_page(pte)		(mem_map + ((unsigned long)(__va(pte_val(pte)) - PAGE_OFFSET) >> PAGE_SHIFT))
 #define pte_pfn(pte)		(pte_val(pte) >> PAGE_SHIFT)
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -26,6 +26,7 @@
 	do{							\
 		*(pteptr) = (pteval);				\
 	} while(0)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
@@ -60,7 +61,7 @@
 #define PTRS_PER_PGD	128
 #endif
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 /* Virtual address region for use by kernel_map() */
 #ifdef CONFIG_SUN3
@@ -143,6 +144,13 @@ static inline void update_mmu_cache(stru
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /* MMU-specific headers */
 
 #ifdef CONFIG_SUN3
diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
--- a/include/asm-m68k/processor.h
+++ b/include/asm-m68k/processor.h
@@ -62,7 +62,8 @@ struct task_work {
 	char          need_resched;
 	unsigned char delayed_trace;	/* single step a syscall */
 	unsigned char syscall_trace;	/* count of syscall interceptors */
-	unsigned char pad[3];
+	unsigned char memdie;		/* task was selected to be killed */
+	unsigned char pad[2];
 };
 
 struct thread_struct {
diff --git a/include/asm-m68k/setup.h b/include/asm-m68k/setup.h
--- a/include/asm-m68k/setup.h
+++ b/include/asm-m68k/setup.h
@@ -360,14 +360,14 @@ extern int m68k_is040or060;
 #define COMMAND_LINE_SIZE	CL_SIZE
 
 #ifndef __ASSEMBLY__
-extern int m68k_num_memory;		/* # of memory blocks found (and used) */
-extern int m68k_realnum_memory;		/* real # of memory blocks found */
-extern struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
-
 struct mem_info {
 	unsigned long addr;		/* physical address of memory chunk */
 	unsigned long size;		/* length of memory chunk (in bytes) */
 };
+
+extern int m68k_num_memory;		/* # of memory blocks found (and used) */
+extern int m68k_realnum_memory;		/* real # of memory blocks found */
+extern struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
--- a/include/asm-m68k/signal.h
+++ b/include/asm-m68k/signal.h
@@ -105,42 +105,20 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
 	__sighandler_t sa_handler;
 	old_sigset_t sa_mask;
 	unsigned long sa_flags;
-	void (*sa_restorer)(void);
+	__sigrestore_t sa_restorer;
 };
 
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
-	void (*sa_restorer)(void);
+	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
 
@@ -213,7 +191,7 @@ static inline int sigfindinword(unsigned
 	return word ^ 31;
 }
 
-#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+extern void ptrace_signal_deliver(struct pt_regs *regs, void *cookie);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-m68k/sun3_pgtable.h b/include/asm-m68k/sun3_pgtable.h
--- a/include/asm-m68k/sun3_pgtable.h
+++ b/include/asm-m68k/sun3_pgtable.h
@@ -123,7 +123,10 @@ static inline void pgd_set(pgd_t *pgdp, 
 
 static inline int pte_none (pte_t pte) { return !pte_val (pte); }
 static inline int pte_present (pte_t pte) { return pte_val (pte) & SUN3_PAGE_VALID; }
-static inline void pte_clear (pte_t *ptep) { pte_val (*ptep) = 0; }
+static inline void pte_clear (struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+	pte_val (*ptep) = 0;
+}
 
 #define pte_pfn(pte)            (pte_val(pte) & SUN3_PAGE_PGNUM_MASK)
 #define pfn_pte(pfn, pgprot) \
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -194,6 +194,8 @@ static inline unsigned long __cmpxchg(vo
 					(unsigned long)(n),sizeof(*(ptr))))
 #endif
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_SYSTEM_H */
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -68,6 +68,9 @@ extern int thread_flag_fixme(void);
 	case TIF_SYSCALL_TRACE:				\
 		tsk->thread.work.syscall_trace = val;	\
 		break;					\
+	case TIF_MEMDIE:				\
+		tsk->thread.work.memdie = val;		\
+		break;					\
 	default:					\
 		thread_flag_fixme();			\
 	}						\
@@ -85,6 +88,9 @@ extern int thread_flag_fixme(void);
 	case TIF_SYSCALL_TRACE:				\
 		___res = tsk->thread.work.syscall_trace;\
 		break;					\
+	case TIF_MEMDIE:				\
+		___res = tsk->thread.work.memdie;\
+		break;					\
 	default:					\
 		___res = thread_flag_fixme();		\
 	}						\
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -14,9 +14,10 @@
 /* We let the MMU do all checking */
 #define access_ok(type,addr,size) 1
 
-static inline int verify_area(int type, const void *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
 {
-	return access_ok(type,addr,size)?0:-EFAULT;
+	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
 
 /*
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
--- a/include/asm-m68k/unistd.h
+++ b/include/asm-m68k/unistd.h
@@ -460,6 +460,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _ASM_M68K_UNISTD_H_ */
diff --git a/include/asm-m68knommu/MC68328.h b/include/asm-m68knommu/MC68328.h
--- a/include/asm-m68knommu/MC68328.h
+++ b/include/asm-m68knommu/MC68328.h
@@ -993,7 +993,7 @@ typedef volatile struct {
   volatile unsigned short int pad1;
   volatile unsigned short int pad2;
   volatile unsigned short int pad3;
-} m68328_uart __attribute__((packed));
+} __attribute__((packed)) m68328_uart;
 
 
 /**********
diff --git a/include/asm-m68knommu/MC68EZ328.h b/include/asm-m68knommu/MC68EZ328.h
--- a/include/asm-m68knommu/MC68EZ328.h
+++ b/include/asm-m68knommu/MC68EZ328.h
@@ -815,7 +815,7 @@ typedef volatile struct {
   volatile unsigned short int nipr;
   volatile unsigned short int pad1;
   volatile unsigned short int pad2;
-} m68328_uart __attribute__((packed));
+} __attribute__((packed)) m68328_uart;
 
 
 /**********
diff --git a/include/asm-m68knommu/MC68VZ328.h b/include/asm-m68knommu/MC68VZ328.h
--- a/include/asm-m68knommu/MC68VZ328.h
+++ b/include/asm-m68knommu/MC68VZ328.h
@@ -909,7 +909,7 @@ typedef struct {
   volatile unsigned short int nipr;
   volatile unsigned short int hmark;
   volatile unsigned short int unused;
-} m68328_uart __attribute__((packed));
+} __attribute__((packed)) m68328_uart;
 
 
 
diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h
--- a/include/asm-m68knommu/cacheflush.h
+++ b/include/asm-m68knommu/cacheflush.h
@@ -9,7 +9,7 @@
 #define flush_cache_all()			__flush_cache_all()
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_range(start,len)		do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
diff --git a/include/asm-m68knommu/entry.h b/include/asm-m68knommu/entry.h
--- a/include/asm-m68knommu/entry.h
+++ b/include/asm-m68knommu/entry.h
@@ -22,8 +22,9 @@
  *	24(sp) - orig_d0
  *	28(sp) - stack adjustment
  *	2C(sp) - [ sr              ] [ format & vector ]
- *	2E(sp) - [ pc              ] [ sr              ]
- *	30(sp) - [ format & vector ] [ pc              ]
+ *	2E(sp) - [ pc-hiword       ] [ sr              ]
+ *	30(sp) - [ pc-loword       ] [ pc-hiword       ]
+ *	32(sp) - [ format & vector ] [ pc-loword       ]
  *		  ^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^
  *			M68K		  COLDFIRE
  */
@@ -42,12 +43,6 @@ PF_DTRACE_BIT = 5
 
 LENOSYS = 38
 
-LD0		= 0x20
-LORIG_D0	= 0x24
-LFORMATVEC	= 0x2c
-LSR		= 0x2e
-LPC		= 0x30
-
 #define SWITCH_STACK_SIZE (6*4+4)	/* Includes return address */
 
 /*
@@ -72,36 +67,36 @@ LPC		= 0x30
 	addql	#8,sw_usp		/* remove exception */
 	movel	sw_ksp,%sp		/* kernel sp */
 	subql	#8,%sp			/* room for exception */
-	clrl	%sp@-			/* stk_adj */
+	clrl	%sp@-			/* stkadj */
 	movel	%d0,%sp@-		/* orig d0 */
 	movel	%d0,%sp@-		/* d0 */
-	subl	#32,%sp			/* space for 8 regs */
+	lea	%sp@(-32),%sp		/* space for 8 regs */
 	moveml	%d1-%d5/%a0-%a2,%sp@
 	movel	sw_usp,%a0		/* get usp */
-	moveml	%a0@(-8),%d1-%d2	/* get exception */
-	moveml	%d1-%d2,%sp@(LFORMATVEC) /* copy exception */
+	movel	%a0@-,%sp@(PT_PC)	/* copy exception program counter */
+	movel	%a0@-,%sp@(PT_FORMATVEC)/* copy exception format/vector/sr */
 	bra	7f
 	6:
-	clrl	%sp@-			/* stk_adj */
+	clrl	%sp@-			/* stkadj */
 	movel	%d0,%sp@-		/* orig d0 */
 	movel	%d0,%sp@-		/* d0 */
-	subl	#32,%sp			/* space for 7 regs */
+	lea	%sp@(-32),%sp		/* space for 8 regs */
 	moveml	%d1-%d5/%a0-%a2,%sp@
 	7:
 .endm
 
 .macro RESTORE_ALL
-	btst	#5,%sp@(LSR)		/* going user? */
+	btst	#5,%sp@(PT_SR)		/* going user? */
 	bnes	8f			/* no, skip */
 	move	#0x2700,%sr		/* disable intrs */
 	movel	sw_usp,%a0		/* get usp */
-	moveml	%sp@(LFORMATVEC),%d1-%d2 /* copy exception */
-	moveml	%d1-%d2,%a0@(-8)
+	movel	%sp@(PT_PC),%a0@-	/* copy exception program counter */
+	movel	%sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */
 	moveml	%sp@,%d1-%d5/%a0-%a2
-	addl	#32,%sp			/* space for 8 regs */
+	lea	%sp@(32),%sp		/* space for 8 regs */
 	movel	%sp@+,%d0
 	addql	#4,%sp			/* orig d0 */
-	addl	%sp@+,%sp		/* stk adj */
+	addl	%sp@+,%sp		/* stkadj */
 	addql	#8,%sp			/* remove exception */
 	movel	%sp,sw_ksp		/* save ksp */
 	subql	#8,sw_usp		/* set exception */
@@ -109,10 +104,10 @@ LPC		= 0x30
 	rte
 	8:
 	moveml	%sp@,%d1-%d5/%a0-%a2
-	addl	#32,%sp			/* space for 8 regs */
+	lea	%sp@(32),%sp		/* space for 8 regs */
 	movel	%sp@+,%d0
 	addql	#4,%sp			/* orig d0 */
-	addl	%sp@+,%sp		/* stk adj */
+	addl	%sp@+,%sp		/* stkadj */
 	rte
 .endm
 
@@ -121,30 +116,30 @@ LPC		= 0x30
  */
 .macro SAVE_LOCAL
 	move	#0x2700,%sr		/* disable intrs */
-	clrl	%sp@-			/* stk_adj */
+	clrl	%sp@-			/* stkadj */
 	movel	%d0,%sp@-		/* orig d0 */
 	movel	%d0,%sp@-		/* d0 */
-	subl	#32,%sp			/* space for 8 regs */
+	lea	%sp@(-32),%sp		/* space for 8 regs */
 	moveml	%d1-%d5/%a0-%a2,%sp@
 .endm
 
 .macro RESTORE_LOCAL
 	moveml	%sp@,%d1-%d5/%a0-%a2
-	addl	#32,%sp			/* space for 8 regs */
+	lea	%sp@(32),%sp		/* space for 8 regs */
 	movel	%sp@+,%d0
 	addql	#4,%sp			/* orig d0 */
-	addl	%sp@+,%sp		/* stk adj */
+	addl	%sp@+,%sp		/* stkadj */
 	rte
 .endm
 
 .macro SAVE_SWITCH_STACK
-	subl    #24,%sp			/* 6 regs */
+	lea	%sp@(-24),%sp		/* 6 regs */
 	moveml	%a3-%a6/%d6-%d7,%sp@
 .endm
 
 .macro RESTORE_SWITCH_STACK
 	moveml	%sp@,%a3-%a6/%d6-%d7
-	addl	#24,%sp			/* 6 regs */
+	lea	%sp@(24),%sp		/* 6 regs */
 .endm
 
 /*
@@ -161,7 +156,7 @@ LPC		= 0x30
  * Standard 68k interrupt entry and exit macros.
  */
 .macro SAVE_ALL
-	clrl	%sp@-			/* stk_adj */
+	clrl	%sp@-			/* stkadj */
 	movel	%d0,%sp@-		/* orig d0 */
 	movel	%d0,%sp@-		/* d0 */
 	moveml	%d1-%d5/%a0-%a2,%sp@-
@@ -171,7 +166,7 @@ LPC		= 0x30
 	moveml	%sp@+,%a0-%a2/%d1-%d5
 	movel	%sp@+,%d0
 	addql	#4,%sp			/* orig d0 */
-	addl	%sp@+,%sp		/* stk adj */
+	addl	%sp@+,%sp		/* stkadj */
 	rte
 .endm
 
diff --git a/include/asm-m68knommu/io.h b/include/asm-m68knommu/io.h
--- a/include/asm-m68knommu/io.h
+++ b/include/asm-m68knommu/io.h
@@ -187,6 +187,17 @@ extern void iounmap(void *addr);
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68KNOMMU_IO_H */
diff --git a/include/asm-m68knommu/io_hw_swap.h b/include/asm-m68knommu/io_hw_swap.h
deleted file mode 100644
--- a/include/asm-m68knommu/io_hw_swap.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef _M68K_IO_HW_SWAP_H
-#define _M68K_IO_HW_SWAP_H
-
-/*
- * swap functions are sometimes needed to interface little-endian hardware
- */
-static inline unsigned short _swapw(volatile unsigned short v)
-{
-    return ((v << 8) | (v >> 8));
-}
-
-static inline unsigned int _swapl(volatile unsigned long v)
-{
-    return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
-}
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the m68k architecture, we just read/write the
- * memory location directly.
- */
-/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
- * two accesses to memory, which may be undesireable for some devices.
- */
-#define readb(addr) \
-    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
-#define readw(addr) \
-    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
-#define readl(addr) \
-    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-
-#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))
-
-/* There is no difference between I/O and memory on 68k, these are the same */
-#define inb(addr) \
-    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
-#define inw(addr) \
-    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); \
-       _swapw(__v); })
-#define inl(addr) \
-    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); _swapl(__v); })
-
-#define outb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define outw(b,addr) ((*(volatile unsigned short *) (addr)) = (_swapw(b)))
-#define outl(b,addr) ((*(volatile unsigned int *) (addr)) = (_swapl(b)))
-
-/* FIXME: these need to be optimized.  Watch out for byte swapping, they
- * are used mostly for Intel devices... */
-#define outsw(addr,buf,len) \
-    ({ unsigned short * __p = (unsigned short *)(buf); \
-       unsigned short * __e = (unsigned short *)(__p) + (len); \
-       while (__p < __e) { \
-	  *(volatile unsigned short *)(addr) = *__p++;\
-       } \
-     })
-
-#define insw(addr,buf,len) \
-    ({ unsigned short * __p = (unsigned short *)(buf); \
-       unsigned short * __e = (unsigned short *)(__p) + (len); \
-       while (__p < __e) { \
-          *(__p++) = *(volatile unsigned short *)(addr); \
-       } \
-     })
-
-
-static inline unsigned char get_user_byte_io(const char * addr)
-{
-	register unsigned char _v;
-
-	__asm__ __volatile__ ("moveb %1,%0":"=dm" (_v):"m" (*addr));
-	return _v;
-}
-#define inb_p(addr) get_user_byte_io((char *)(addr))
-
-static inline void put_user_byte_io(char val,char *addr)
-{
-	__asm__ __volatile__ ("moveb %0,%1"
-			      : /* no outputs */
-			      :"idm" (val),"m" (*addr)
-			      : "memory");
-}
-#define outb_p(x,addr) put_user_byte_io((x),(char *)(addr))
-
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
- */
-extern unsigned long mm_vtop(unsigned long addr);
-extern unsigned long mm_ptov(unsigned long addr);
-
-extern inline unsigned long virt_to_phys(volatile void * address)
-{
-	return (unsigned long) mm_vtop((unsigned long)address);
-}
-
-extern inline void * phys_to_virt(unsigned long address)
-{
-	return (void *) mm_ptov(address);
-}
-
-/*
- * 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
-
-
-#endif /* _M68K_IO_HW_SWAP_H */
diff --git a/include/asm-m68knommu/ipc.h b/include/asm-m68knommu/ipc.h
--- a/include/asm-m68knommu/ipc.h
+++ b/include/asm-m68knommu/ipc.h
@@ -1 +1 @@
-#include <asm-m68k/ipc.h>
+#include <asm-generic/ipc.h>
diff --git a/include/asm-m68knommu/kmap_types.h b/include/asm-m68knommu/kmap_types.h
--- a/include/asm-m68knommu/kmap_types.h
+++ b/include/asm-m68knommu/kmap_types.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_KMAP_TYPES_H
-#define _ASM_KMAP_TYPES_H
+#ifndef __ASM_M68K_KMAP_TYPES_H
+#define __ASM_M68K_KMAP_TYPES_H
 
 enum km_type {
 	KM_BOUNCE_READ,
@@ -13,6 +13,8 @@ enum km_type {
 	KM_PTE1,
 	KM_IRQ0,
 	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
 	KM_TYPE_NR
 };
 
diff --git a/include/asm-m68knommu/mcfcache.h b/include/asm-m68knommu/mcfcache.h
--- a/include/asm-m68knommu/mcfcache.h
+++ b/include/asm-m68knommu/mcfcache.h
@@ -15,14 +15,14 @@
 
 /*
  *	The different ColdFire families have different cache arrangments.
- *	Everything from a small linstruction only cache, to configurable
+ *	Everything from a small instruction only cache, to configurable
  *	data and/or instruction cache, to unified instruction/data, to 
  *	harvard style separate instruction and data caches.
  */
 
 #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272)
 /*
- *	Simple verion 2 core cache. These have instruction cache only,
+ *	Simple version 2 core cache. These have instruction cache only,
  *	we just need to invalidate it and enable it.
  */
 .macro CACHE_ENABLE
@@ -98,7 +98,7 @@
 
 #if defined(CONFIG_M5407)
 /*
- *	Version 4 cores have a true hardvard style separate instruction
+ *	Version 4 cores have a true harvard style separate instruction
  *	and data cache. Invalidate and enable cache, also enable write
  *	buffers and branch accelerator.
  */
diff --git a/include/asm-m68knommu/mmu.h b/include/asm-m68knommu/mmu.h
--- a/include/asm-m68knommu/mmu.h
+++ b/include/asm-m68knommu/mmu.h
@@ -3,19 +3,8 @@
 
 /* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
 
-struct mm_rblock_struct {
-	int	size;
-	int	refcount;
-	void	*kblock;
-};
-
-struct mm_tblock_struct {
-	struct mm_rblock_struct	*rblock;
-	struct mm_tblock_struct	*next;
-};
-
 typedef struct {
-	struct mm_tblock_struct	tblock;
+	struct vm_list_struct	*vmlist;
 	unsigned long		end_brk;
 } mm_context_t;
 
diff --git a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h
--- a/include/asm-m68knommu/page.h
+++ b/include/asm-m68knommu/page.h
@@ -13,12 +13,6 @@
 
 #include <asm/setup.h>
 
-#if !defined(CONFIG_SMALL_TASKS) && PAGE_SHIFT < 13
-#define THREAD_SIZE (8192)
-#else
-#define THREAD_SIZE PAGE_SIZE
-#endif
- 
 #ifndef __ASSEMBLY__
  
 #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -59,6 +59,13 @@ extern int is_in_rom(unsigned long);
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
diff --git a/include/asm-m68knommu/semp3.h b/include/asm-m68knommu/semp3.h
deleted file mode 100644
--- a/include/asm-m68knommu/semp3.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************/
-
-/*
- *	semp.h -- SecureEdge MP3 hardware platform support.
- *
- *	(C) Copyright 2001-2002, Greg Ungerer (gerg@snapgear.com).
- */
-
-/****************************************************************************/
-#ifndef	semp3_h
-#define	semp3_h
-/****************************************************************************/
-
-#include <linux/config.h>
-
-/****************************************************************************/
-#ifdef CONFIG_SECUREEDGEMP3
-/****************************************************************************/
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*
- *	The ColdFire UARTs do not have any support for DTR/DCD lines.
- *	We have wired them onto some of the parallel IO lines.
- */
-#define	MCFPP_DCD1	0x0004
-#define	MCFPP_DCD0	0x0000		/* No DCD line on port 0 */
-#define	MCFPP_DTR1	0x0080
-#define	MCFPP_DTR0	0x0000		/* No DTR line on port 0 */
-
-
-#ifndef __ASSEMBLY__
-
-extern volatile unsigned short ppdata;
-
-/*
- *	These functions defined to give quasi generic access to the
- *	PPIO bits used for DTR/DCD.
- */
-static __inline__ unsigned int mcf_getppdata(void)
-{
-	volatile unsigned short *pp;
-	pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT);
-	return((unsigned int) *pp);
-}
-
-static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits)
-{
-	volatile unsigned short *pp;
-	pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT);
-	ppdata = (ppdata & ~mask) | bits;
-	*pp = ppdata;
-}
-#endif
-
-/****************************************************************************/
-#endif /* CONFIG_SECUREEDGEMP3 */
-/****************************************************************************/
-#endif	/* semp3_h */
diff --git a/include/asm-m68knommu/signal.h b/include/asm-m68knommu/signal.h
--- a/include/asm-m68knommu/signal.h
+++ b/include/asm-m68knommu/signal.h
@@ -105,29 +105,7 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h
--- a/include/asm-m68knommu/system.h
+++ b/include/asm-m68knommu/system.h
@@ -281,5 +281,6 @@ cmpxchg(volatile int *p, int old, int ne
 })
 #endif
 #endif
+#define arch_align_stack(x) (x)
 
 #endif /* _M68KNOMMU_SYSTEM_H */
diff --git a/include/asm-m68knommu/thread_info.h b/include/asm-m68knommu/thread_info.h
--- a/include/asm-m68knommu/thread_info.h
+++ b/include/asm-m68knommu/thread_info.h
@@ -15,8 +15,21 @@
 #ifndef __ASSEMBLY__
 
 /*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE_ORDER (0)
+#else
+#define THREAD_SIZE_ORDER (1)
+#endif
+                                                                                
+/*
+ * for asm files, THREAD_SIZE is now generated by asm-offsets.c
+ */
+#define THREAD_SIZE (PAGE_SIZE<<THREAD_SIZE_ORDER)
+
+/*
  * low level task data.
- * If you change this, change the TI_* offsets below to match.
  */
 struct thread_info {
 	struct task_struct *task;		/* main task structure */
@@ -60,20 +73,12 @@ static inline struct thread_info *curren
 
 /* thread information allocation */
 #define alloc_thread_info(tsk) ((struct thread_info *) \
-				__get_free_pages(GFP_KERNEL, 1))
-#define free_thread_info(ti)	free_pages((unsigned long) (ti), 1)
+				__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER))
+#define free_thread_info(ti)	free_pages((unsigned long) (ti), THREAD_SIZE_ORDER)
 #define get_thread_info(ti)	get_task_struct((ti)->task)
 #define put_thread_info(ti)	put_task_struct((ti)->task)
 #endif /* __ASSEMBLY__ */
 
-/*
- * Offsets in thread_info structure, used in assembly code
- */
-#define TI_TASK		0
-#define TI_EXECDOMAIN	4
-#define TI_FLAGS	8
-#define TI_CPU		12
-
 #define	PREEMPT_ACTIVE	0x4000000
 
 /*
diff --git a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h
--- a/include/asm-m68knommu/uaccess.h
+++ b/include/asm-m68knommu/uaccess.h
@@ -23,7 +23,8 @@ static inline int _access_ok(unsigned lo
 		(is_in_rom(addr) && is_in_rom(addr+size)));
 }
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size)?0:-EFAULT;
 }
diff --git a/include/asm-m68knommu/unaligned.h b/include/asm-m68knommu/unaligned.h
--- a/include/asm-m68knommu/unaligned.h
+++ b/include/asm-m68knommu/unaligned.h
@@ -5,15 +5,7 @@
 
 #ifdef CONFIG_COLDFIRE
 
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #else
 /*
diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h
--- a/include/asm-m68knommu/unistd.h
+++ b/include/asm-m68knommu/unistd.h
@@ -524,6 +524,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _ASM_M68K_UNISTD_H_ */
diff --git a/include/asm-mips/bug.h b/include/asm-mips/bug.h
--- a/include/asm-mips/bug.h
+++ b/include/asm-mips/bug.h
@@ -3,12 +3,14 @@
 
 #include <asm/break.h>
 
+#ifdef CONFIG_BUG
+#define HAVE_ARCH_BUG
 #define BUG()								\
 do {									\
 	__asm__ __volatile__("break %0" : : "i" (BRK_BUG));		\
 } while (0)
+#endif
 
-#define HAVE_ARCH_BUG
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -17,7 +17,7 @@
  *
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
- *  - flush_cache_page(mm, vmaddr) flushes a single page
+ *  - flush_cache_page(mm, vmaddr, pfn) flushes a single page
  *  - flush_cache_range(vma, start, end) flushes a range of pages
  *  - flush_icache_range(start, end) flush a range of instructions
  *  - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
@@ -34,8 +34,7 @@ extern void (*__flush_cache_all)(void);
 extern void (*flush_cache_mm)(struct mm_struct *mm);
 extern void (*flush_cache_range)(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end);
-extern void (*flush_cache_page)(struct vm_area_struct *vma,
-	unsigned long page);
+extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
 
 static inline void flush_dcache_page(struct page *page)
diff --git a/include/asm-mips/errno.h b/include/asm-mips/errno.h
--- a/include/asm-mips/errno.h
+++ b/include/asm-mips/errno.h
@@ -115,6 +115,10 @@
 #define	EKEYREVOKED	163	/* Key has been revoked */
 #define	EKEYREJECTED	164	/* Key was rejected by service */
 
+/* for robust mutexes */
+#define	EOWNERDEAD	165	/* Owner died */
+#define	ENOTRECOVERABLE	166	/* State not recoverable */
+
 #define EDQUOT		1133	/* Quota exceeded */
 
 #ifdef __KERNEL__
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -616,4 +616,15 @@ extern void (*_dma_cache_inv)(unsigned l
 #define csr_out32(v,a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v))
 #define csr_in32(a)    (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST))
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* _ASM_IO_H */
diff --git a/include/asm-mips/ipc.h b/include/asm-mips/ipc.h
--- a/include/asm-mips/ipc.h
+++ b/include/asm-mips/ipc.h
@@ -1,33 +1 @@
-#ifndef _ASM_IPC_H
-#define _ASM_IPC_H
-
-/*
- * These are used to wrap system calls on MIPS.
- *
- * See arch/mips/kernel/sysmips.c for ugly details..
- * FIXME: split up into ordinary syscalls ...
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC		25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif /* _ASM_IPC_H */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -137,17 +137,10 @@ extern void pcibios_resource_to_bus(stru
 
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
-static inline int
-pci_name_bus(char *name, struct pci_bus *bus)
+static inline int pci_proc_domain(struct pci_bus *bus)
 {
 	struct pci_controller *hose = bus->sysdata;
-
-	if (likely(hose->need_domain_info == 0)) {
-		sprintf(name, "%02x", bus->number);
-	} else {
-		sprintf(name, "%04x:%02x", hose->index, bus->number);
-	}
-	return 0;
+	return hose->need_domain_info;
 }
 
 #endif /* CONFIG_PCI_DOMAINS */
diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h
--- a/include/asm-mips/pgtable-32.h
+++ b/include/asm-mips/pgtable-32.h
@@ -74,7 +74,7 @@ extern int add_temporary_entry(unsigned 
 #define PTRS_PER_PTE	((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
 
 #define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define VMALLOC_START     KSEG2
 
diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h
--- a/include/asm-mips/pgtable-64.h
+++ b/include/asm-mips/pgtable-64.h
@@ -89,7 +89,7 @@
 #define PTRS_PER_PTE	((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define VMALLOC_START		XKSEG
 #define VMALLOC_END	\
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -100,14 +100,15 @@ static inline void set_pte(pte_t *ptep, 
 			buddy->pte_low |= _PAGE_GLOBAL;
 	}
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
-static inline void pte_clear(pte_t *ptep)
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	/* Preserve global status for the pair */
 	if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL)
-		set_pte(ptep, __pte(_PAGE_GLOBAL));
+		set_pte_at(mm, addr, ptep, __pte(_PAGE_GLOBAL));
 	else
-		set_pte(ptep, __pte(0));
+		set_pte_at(mm, addr, ptep, __pte(0));
 }
 #else
 /*
@@ -130,16 +131,17 @@ static inline void set_pte(pte_t *ptep, 
 	}
 #endif
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
-static inline void pte_clear(pte_t *ptep)
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 #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));
+		set_pte_at(mm, addr, ptep, __pte(_PAGE_GLOBAL));
 	else
 #endif
-		set_pte(ptep, __pte(0));
+		set_pte_at(mm, addr, ptep, __pte(0));
 }
 #endif
 
@@ -365,11 +367,27 @@ static inline int io_remap_page_range(st
 	phys_t phys_addr_high = fixup_bigphys_addr(paddr, size);
 	return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot);
 }
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+		unsigned long vaddr,
+		unsigned long pfn,
+		unsigned long size,
+		pgprot_t prot)
+{
+	phys_t phys_addr_high = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+	return remap_pfn_range(vma, vaddr, pfn, size, prot);
+}
 #else
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
-	remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #include <asm-generic/pgtable.h>
 
 /*
diff --git a/include/asm-mips/resource.h b/include/asm-mips/resource.h
--- a/include/asm-mips/resource.h
+++ b/include/asm-mips/resource.h
@@ -9,36 +9,26 @@
 #ifndef _ASM_RESOURCE_H
 #define _ASM_RESOURCE_H
 
+#include <linux/config.h>
+
 /*
- * Resource limits
+ * These five resource limit IDs have a MIPS/Linux-specific ordering,
+ * the rest comes from the generic header:
  */
-#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_NOFILE 5			/* max number of open files */
-#define RLIMIT_AS 6			/* mapped memory */
-#define RLIMIT_RSS 7			/* max resident set size */
-#define RLIMIT_NPROC 8			/* max number of processes */
-#define RLIMIT_MEMLOCK 9		/* max locked-in-memory address space */
-#define RLIMIT_LOCKS 10			/* maximum file locks held */
-#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
-#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
-
-#define RLIM_NLIMITS 13			/* Number of limit flavors.  */
-#define __ARCH_RLIMIT_ORDER
+#define RLIMIT_NOFILE		5	/* max number of open files */
+#define RLIMIT_AS		6	/* address space limit */
+#define RLIMIT_RSS		7	/* max resident set size */
+#define RLIMIT_NPROC		8	/* max number of processes */
+#define RLIMIT_MEMLOCK		9	/* max locked-in-memory address space */
 
 /*
  * SuS says limits have to be unsigned.
- * Which makes a ton more sense anyway.
+ * Which makes a ton more sense anyway,
+ * but we keep the old value on MIPS32,
+ * for compatibility:
  */
-#include <linux/config.h>
 #ifdef CONFIG_MIPS32
-#define RLIM_INFINITY	0x7fffffffUL
-#endif
-#ifdef CONFIG_MIPS64
-#define RLIM_INFINITY	(~0UL)
+# define RLIM_INFINITY		0x7fffffffUL
 #endif
 
 #include <asm-generic/resource.h>
diff --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h
--- a/include/asm-mips/siginfo.h
+++ b/include/asm-mips/siginfo.h
@@ -11,8 +11,6 @@
 
 #include <linux/config.h>
 
-#define SIGEV_HEAD_SIZE	(sizeof(long) + 2*sizeof(int))
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE-SIGEV_HEAD_SIZE) / sizeof(int))
 #undef __ARCH_SI_TRAPNO	/* exception code needs to fill this ...  */
 
 #define HAVE_ARCH_SIGINFO_T
diff --git a/include/asm-mips/signal.h b/include/asm-mips/signal.h
--- a/include/asm-mips/signal.h
+++ b/include/asm-mips/signal.h
@@ -98,34 +98,12 @@ typedef unsigned long old_sigset_t;		/* 
 #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 flag is for shared interrupt support on PCI and EISA.
- */
-#define SA_PROBE		SA_ONESHOT
-#define SA_SAMPLE_RANDOM	SA_RESTART
-#define SA_SHIRQ		0x02000000
-
-#endif /* __KERNEL__ */
-
 #define SIG_BLOCK	1	/* for blocking signals */
 #define SIG_UNBLOCK	2	/* for unblocking signals */
 #define SIG_SETMASK	3	/* for setting the signal mask */
 #define SIG_SETMASK32	256	/* Goodie from SGI for BSD compatibility:
 				   set only the low 32 bit of the sigset.  */
-
-/* Type of a signal handler.  */
-typedef void (*__sighandler_t)(int);
-
-/* Fake signal functions */
-#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 */
+#include <asm-generic/signal.h>
 
 struct sigaction {
 	unsigned int	sa_flags;
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -433,4 +433,6 @@ do {						\
 #define finish_arch_switch(rq, prev)	spin_unlock_irq(&(prev)->switch_lock)
 #define task_running(rq, p) 		((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
 
+#define arch_align_stack(x) (x)
+
 #endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h
--- a/include/asm-mips/timex.h
+++ b/include/asm-mips/timex.h
@@ -45,7 +45,6 @@
  */
 
 typedef unsigned int cycles_t;
-extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles (void)
 {
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
--- a/include/asm-mips/uaccess.h
+++ b/include/asm-mips/uaccess.h
@@ -112,7 +112,8 @@
 	likely(__access_ok((unsigned long)(addr), (size),__access_mask))
 
 /*
- * verify_area: - Obsolete, use access_ok()
+ * verify_area: - Obsolete/deprecated and will go away soon,
+ * use access_ok() instead.
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
  * @addr: User space pointer to start of block to check
  * @size: Size of block to check
@@ -128,7 +129,7 @@
  *
  * See access_ok() for more details.
  */
-static inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
@@ -257,7 +258,8 @@ struct __large_struct { unsigned long bu
 									\
 	might_sleep();							\
 	__gu_addr = (long) (ptr);					\
-	__gu_err = verify_area(VERIFY_READ, (void *) __gu_addr, size);	\
+	__gu_err = access_ok(VERIFY_READ, (void *) __gu_addr, size)	\
+				? 0 : -EFAULT;				\
 									\
 	if (likely(!__gu_err)) {					\
 		switch (size) {						\
@@ -352,7 +354,8 @@ extern void __get_user_unknown(void);
 	might_sleep();							\
 	__pu_val = (x);							\
 	__pu_addr = (long) (ptr);					\
-	__pu_err = verify_area(VERIFY_WRITE, (void *) __pu_addr, size);	\
+	__pu_err = access_ok(VERIFY_WRITE, (void *) __pu_addr, size)	\
+				? 0 : -EFAULT;				\
 									\
 	if (likely(!__pu_err)) {					\
 		switch (size) {						\
diff --git a/include/asm-mips/unaligned.h b/include/asm-mips/unaligned.h
--- a/include/asm-mips/unaligned.h
+++ b/include/asm-mips/unaligned.h
@@ -9,136 +9,6 @@
 #ifndef _ASM_UNALIGNED_H
 #define _ASM_UNALIGNED_H
 
-#include <linux/types.h>
-
-/*
- * 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) \
-	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(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(x,ptr) \
-	__put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
-
-/*
- * This is a silly but good way to make sure that
- * the get/put functions are indeed always optimized,
- * and that we use the correct sizes.
- */
-extern void bad_unaligned_access_length(void);
-
-/*
- * EGCS 1.1 knows about arbitrary unaligned loads.  Define some
- * packed structures to talk about such things with.
- */
-
-struct __una_u64 { __u64 x __attribute__((packed)); };
-struct __una_u32 { __u32 x __attribute__((packed)); };
-struct __una_u16 { __u16 x __attribute__((packed)); };
-
-/*
- * Elemental unaligned loads 
- */
-
-static inline __u64 __uldq(const __u64 * r11)
-{
-	const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
-	return ptr->x;
-}
-
-static inline __u32 __uldl(const __u32 * r11)
-{
-	const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
-	return ptr->x;
-}
-
-static inline __u16 __uldw(const __u16 * r11)
-{
-	const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
-	return ptr->x;
-}
-
-/*
- * Elemental unaligned stores 
- */
-
-static inline void __ustq(__u64 r5, __u64 * r11)
-{
-	struct __una_u64 *ptr = (struct __una_u64 *) r11;
-	ptr->x = r5;
-}
-
-static inline void __ustl(__u32 r5, __u32 * r11)
-{
-	struct __una_u32 *ptr = (struct __una_u32 *) r11;
-	ptr->x = r5;
-}
-
-static inline void __ustw(__u16 r5, __u16 * r11)
-{
-	struct __una_u16 *ptr = (struct __una_u16 *) r11;
-	ptr->x = r5;
-}
-
-static inline __u64 __get_unaligned(const void *ptr, size_t size)
-{
-	__u64 val;
-
-	switch (size) {
-	case 1:
-		val = *(const __u8 *)ptr;
-		break;
-	case 2:
-		val = __uldw((const __u16 *)ptr);
-		break;
-	case 4:
-		val = __uldl((const __u32 *)ptr);
-		break;
-	case 8:
-		val = __uldq((const __u64 *)ptr);
-		break;
-	default:
-		bad_unaligned_access_length();
-	}
-	return val;
-}
-
-static inline void __put_unaligned(__u64 val, void *ptr, size_t size)
-{
-	switch (size) {
-	      case 1:
-		*(__u8 *)ptr = (val);
-	        break;
-	      case 2:
-		__ustw(val, (__u16 *)ptr);
-		break;
-	      case 4:
-		__ustl(val, (__u32 *)ptr);
-		break;
-	      case 8:
-		__ustq(val, (__u64 *)ptr);
-		break;
-	      default:
-	    	bad_unaligned_access_length();
-	}
-}
+#include <asm-generic/unaligned.h>
 
 #endif /* _ASM_UNALIGNED_H */
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -1180,6 +1180,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall")
 
 #endif /* _ASM_UNISTD_H */
diff --git a/include/asm-mips/vr41xx/pci.h b/include/asm-mips/vr41xx/pci.h
new file mode 100644
--- /dev/null
+++ b/include/asm-mips/vr41xx/pci.h
@@ -0,0 +1,90 @@
+/*
+ *  Include file for NEC VR4100 series PCI Control Unit.
+ *
+ *  Copyright (C) 2004-2005  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.
+ *
+ *  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 __NEC_VR41XX_PCI_H
+#define __NEC_VR41XX_PCI_H
+
+#define PCI_MASTER_ADDRESS_MASK	0x7fffffffU
+
+struct pci_master_address_conversion {
+	uint32_t bus_base_address;
+	uint32_t address_mask;
+	uint32_t pci_base_address;
+};
+
+struct pci_target_address_conversion {
+	uint32_t address_mask;
+	uint32_t bus_base_address;
+};
+
+typedef enum {
+	CANNOT_LOCK_FROM_DEVICE,
+	CAN_LOCK_FROM_DEVICE,
+} pci_exclusive_access_t;
+
+struct pci_mailbox_address {
+	uint32_t base_address;
+};
+
+struct pci_target_address_window {
+	uint32_t base_address;
+};
+
+typedef enum {
+	PCI_ARBITRATION_MODE_FAIR,
+	PCI_ARBITRATION_MODE_ALTERNATE_0,
+	PCI_ARBITRATION_MODE_ALTERNATE_B,
+} pci_arbiter_priority_control_t;
+
+typedef enum {
+	PCI_TAKE_AWAY_GNT_DISABLE,
+	PCI_TAKE_AWAY_GNT_ENABLE,
+} pci_take_away_gnt_mode_t;
+
+struct pci_controller_unit_setup {
+	struct pci_master_address_conversion *master_memory1;
+	struct pci_master_address_conversion *master_memory2;
+
+	struct pci_target_address_conversion *target_memory1;
+	struct pci_target_address_conversion *target_memory2;
+
+	struct pci_master_address_conversion *master_io;
+
+	pci_exclusive_access_t exclusive_access;
+
+	uint32_t pci_clock_max;
+	uint8_t wait_time_limit_from_irdy_to_trdy;	/* Only VR4122 is supported */
+
+	struct pci_mailbox_address *mailbox;
+	struct pci_target_address_window *target_window1;
+	struct pci_target_address_window *target_window2;
+
+	uint8_t master_latency_timer;
+	uint8_t retry_limit;
+
+	pci_arbiter_priority_control_t arbiter_priority_control;
+	pci_take_away_gnt_mode_t take_away_gnt_mode;
+
+	struct resource *mem_resource;
+	struct resource *io_resource;
+};
+
+extern void vr41xx_pciu_setup(struct pci_controller_unit_setup *setup);
+
+#endif /* __NEC_VR41XX_PCI_H */
diff --git a/include/asm-mips/vr41xx/siu.h b/include/asm-mips/vr41xx/siu.h
new file mode 100644
--- /dev/null
+++ b/include/asm-mips/vr41xx/siu.h
@@ -0,0 +1,50 @@
+/*
+ *  Include file for NEC VR4100 series Serial Interface Unit.
+ *
+ *  Copyright (C) 2005  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.
+ *
+ *  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 __NEC_VR41XX_SIU_H
+#define __NEC_VR41XX_SIU_H
+
+typedef enum {
+	SIU_INTERFACE_RS232C,
+	SIU_INTERFACE_IRDA,
+} siu_interface_t;
+
+extern void vr41xx_select_siu_interface(siu_interface_t interface);
+
+typedef enum {
+	SIU_USE_IRDA,
+	FIR_USE_IRDA,
+} irda_use_t;
+
+extern void vr41xx_use_irda(irda_use_t use);
+
+typedef enum {
+	SHARP_IRDA,
+	TEMIC_IRDA,
+	HP_IRDA,
+} irda_module_t;
+
+typedef enum {
+	IRDA_TX_1_5MBPS,
+	IRDA_TX_4MBPS,
+} irda_speed_t;
+
+extern void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed);
+
+#endif /* __NEC_VR41XX_SIU_H */
diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h
--- a/include/asm-mips/vr41xx/vr41xx.h
+++ b/include/asm-mips/vr41xx/vr41xx.h
@@ -45,6 +45,7 @@
 /*
  * Bus Control Uint
  */
+extern unsigned long vr41xx_calculate_clock_frequency(void);
 extern unsigned long vr41xx_get_vtclock_frequency(void);
 extern unsigned long vr41xx_get_tclock_frequency(void);
 
@@ -83,7 +84,7 @@ extern void vr41xx_mask_clock(vr41xx_clo
 #define INT2_CASCADE_IRQ	MIPS_CPU_IRQ(4)
 #define INT3_CASCADE_IRQ	MIPS_CPU_IRQ(5)
 #define INT4_CASCADE_IRQ	MIPS_CPU_IRQ(6)
-#define MIPS_COUNTER_IRQ	MIPS_CPU_IRQ(7)
+#define TIMER_IRQ		MIPS_CPU_IRQ(7)
 
 /* SYINT1 Interrupt Numbers */
 #define SYSINT1_IRQ_BASE	8
@@ -197,22 +198,6 @@ extern void vr41xx_enable_bcuint(void);
 extern void vr41xx_disable_bcuint(void);
 
 /*
- * Power Management Unit
- */
-
-/*
- * RTC
- */
-extern void vr41xx_set_rtclong1_cycle(uint32_t cycles);
-extern uint32_t vr41xx_read_rtclong1_counter(void);
-
-extern void vr41xx_set_rtclong2_cycle(uint32_t cycles);
-extern uint32_t vr41xx_read_rtclong2_counter(void);
-
-extern void vr41xx_set_tclock_cycle(uint32_t cycles);
-extern uint32_t vr41xx_read_tclock_counter(void);
-
-/*
  * General-Purpose I/O Unit
  */
 enum {
@@ -246,102 +231,4 @@ enum {
 	DATA_HIGH
 };
 
-/*
- * Serial Interface Unit
- */
-extern void vr41xx_siu_init(void);
-extern int vr41xx_serial_ports;
-
-/* SIU interfaces */
-typedef enum {
-	SIU_RS232C,
-	SIU_IRDA
-} siu_interface_t;
-
-/* IrDA interfaces */
-typedef enum {
-	IRDA_NONE,
-	IRDA_SHARP,
-	IRDA_TEMIC,
-	IRDA_HP
-} irda_module_t;
-
-extern void vr41xx_select_siu_interface(siu_interface_t interface,
-                                        irda_module_t module);
-
-/*
- * Debug Serial Interface Unit
- */
-extern void vr41xx_dsiu_init(void);
-
-/*
- * PCI Control Unit
- */
-#define PCI_MASTER_ADDRESS_MASK	0x7fffffffU
-
-struct pci_master_address_conversion {
-	uint32_t bus_base_address;
-	uint32_t address_mask;
-	uint32_t pci_base_address;
-};
-
-struct pci_target_address_conversion {
-	uint32_t address_mask;
-	uint32_t bus_base_address;
-};
-
-typedef enum {
-	CANNOT_LOCK_FROM_DEVICE,
-	CAN_LOCK_FROM_DEVICE,
-} pci_exclusive_access_t;
-
-struct pci_mailbox_address {
-	uint32_t base_address;
-};
-
-struct pci_target_address_window {
-	uint32_t base_address;
-};
-
-typedef enum {
-	PCI_ARBITRATION_MODE_FAIR,
-	PCI_ARBITRATION_MODE_ALTERNATE_0,
-	PCI_ARBITRATION_MODE_ALTERNATE_B,
-} pci_arbiter_priority_control_t;
-
-typedef enum {
-	PCI_TAKE_AWAY_GNT_DISABLE,
-	PCI_TAKE_AWAY_GNT_ENABLE,
-} pci_take_away_gnt_mode_t;
-
-struct pci_controller_unit_setup {
-	struct pci_master_address_conversion *master_memory1;
-	struct pci_master_address_conversion *master_memory2;
-
-	struct pci_target_address_conversion *target_memory1;
-	struct pci_target_address_conversion *target_memory2;
-
-	struct pci_master_address_conversion *master_io;
-
-	pci_exclusive_access_t exclusive_access;
-
-	uint32_t pci_clock_max;
-	uint8_t wait_time_limit_from_irdy_to_trdy;	/* Only VR4122 is supported */
-
-	struct pci_mailbox_address *mailbox;
-	struct pci_target_address_window *target_window1;
-	struct pci_target_address_window *target_window2;
-
-	uint8_t master_latency_timer;
-	uint8_t retry_limit;
-
-	pci_arbiter_priority_control_t arbiter_priority_control;
-	pci_take_away_gnt_mode_t take_away_gnt_mode;
-
-	struct resource *mem_resource;
-	struct resource *io_resource;
-};
-
-extern void vr41xx_pciu_setup(struct pci_controller_unit_setup *setup);
-
 #endif /* __NEC_VR41XX_H */
diff --git a/include/asm-mips/vr41xx/vrc4171.h b/include/asm-mips/vr41xx/vrc4171.h
deleted file mode 100644
--- a/include/asm-mips/vr41xx/vrc4171.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  vrc4171.h, Include file for NEC VRC4171.
- *
- *  Copyright (C) 2003  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.
- *
- *  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 __NEC_VRC4171_H 
-#define __NEC_VRC4171_H 
-
-/*
- * Configuration 1
- */
-enum {
-	SLOTB_IS_NONE,       
-	SLOTB_IS_PCCARD,
-	SLOTB_IS_CF,
-	SLOTB_IS_FLASHROM
-};
-
-extern void vrc4171_set_multifunction_pin(int config);
-
-/*
- * Interrupt Status Mask
- */
-#define IRQ_A	0x02
-#define IRQ_B	0x04
-
-extern uint16_t vrc4171_get_irq_status(void);
-
-#endif /* __NEC_VRC4171_H */
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -37,6 +37,7 @@
 #define LDREGX  ldwx,s
 #define LDREGM	ldwm
 #define STREGM	stwm
+#define SHRREG  shr
 #define RP_OFFSET	20
 #define FRAME_SIZE	64
 #define CALLEE_SAVE_FRAME_SIZE	128
@@ -44,7 +45,7 @@
 
 #ifdef CONFIG_PA20
 #define BL		b,l
-# ifdef CONFIG_PARISC64
+# ifdef CONFIG_64BIT
 #  define LEVEL		2.0w
 # else
 #  define LEVEL		2.0
diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h
--- a/include/asm-parisc/bitops.h
+++ b/include/asm-parisc/bitops.h
@@ -446,14 +446,14 @@ found_middle:
  * disabling interrupts.
  */
 #ifdef __LP64__
-#define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x38, (unsigned long *)addr)
+#define ext2_set_bit(nr, addr)		__test_and_set_bit((nr) ^ 0x38, (unsigned long *)addr)
 #define ext2_set_bit_atomic(l,nr,addr)  test_and_set_bit((nr) ^ 0x38, (unsigned long *)addr)
-#define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x38, (unsigned long *)addr)
+#define ext2_clear_bit(nr, addr)	__test_and_clear_bit((nr) ^ 0x38, (unsigned long *)addr)
 #define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x38, (unsigned long *)addr)
 #else
-#define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x18, (unsigned long *)addr)
+#define ext2_set_bit(nr, addr)		__test_and_set_bit((nr) ^ 0x18, (unsigned long *)addr)
 #define ext2_set_bit_atomic(l,nr,addr)  test_and_set_bit((nr) ^ 0x18, (unsigned long *)addr)
-#define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, (unsigned long *)addr)
+#define ext2_clear_bit(nr, addr)	__test_and_clear_bit((nr) ^ 0x18, (unsigned long *)addr)
 #define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x18, (unsigned long *)addr)
 #endif
 
diff --git a/include/asm-parisc/bug.h b/include/asm-parisc/bug.h
--- a/include/asm-parisc/bug.h
+++ b/include/asm-parisc/bug.h
@@ -1,12 +1,14 @@
 #ifndef _PARISC_BUG_H
 #define _PARISC_BUG_H
 
+#ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	dump_stack(); \
 	panic("BUG!"); \
 } while (0)
+#endif
 
 #include <asm-generic/bug.h>
 #endif
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -57,9 +57,9 @@ flush_user_icache_range(unsigned long st
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
@@ -67,14 +67,14 @@ extern void flush_dcache_page(struct pag
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 do { \
-	flush_cache_page(vma, vaddr); \
+	flush_cache_page(vma, vaddr, page_to_pfn(page)); \
 	memcpy(dst, src, len); \
 	flush_kernel_dcache_range_asm((unsigned long)dst, (unsigned long)dst + len); \
 } while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
 do { \
-	flush_cache_page(vma, vaddr); \
+	flush_cache_page(vma, vaddr, page_to_pfn(page)); \
 	memcpy(dst, src, len); \
 } while (0)
 
@@ -170,7 +170,7 @@ __flush_cache_page(struct vm_area_struct
 }
 
 static inline void
-flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
+flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
 {
 	BUG_ON(!vma->vm_mm->context);
 
diff --git a/include/asm-parisc/checksum.h b/include/asm-parisc/checksum.h
--- a/include/asm-parisc/checksum.h
+++ b/include/asm-parisc/checksum.h
@@ -30,8 +30,8 @@ extern unsigned int csum_partial_copy_no
  * this is a new version of the above that records errors it finds in *errp,
  * but continues and zeros the rest of the buffer.
  */
-extern unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
-						int len, unsigned int sum, int *errp);
+extern unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+		unsigned char *dst, int len, unsigned int sum, int *errp);
 
 /*
  *	Optimized for IP headers, which always checksum on 4 octet boundaries.
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -131,15 +131,15 @@ typedef u32		compat_sigset_word;
  */
 typedef	u32		compat_uptr_t;
 
-static inline void *compat_ptr(compat_uptr_t uptr)
+static inline void __user *compat_ptr(compat_uptr_t uptr)
 {
-	return (void *)(unsigned long)uptr;
+	return (void __user *)(unsigned long)uptr;
 }
 
-static __inline__ void *compat_alloc_user_space(long len)
+static __inline__ void __user *compat_alloc_user_space(long len)
 {
 	struct pt_regs *regs = &current->thread.regs;
-	return (void *)regs->gr[30];
+	return (void __user *)regs->gr[30];
 }
 
 #endif /* _ASM_PARISC_COMPAT_H */
diff --git a/include/asm-parisc/dma-mapping.h b/include/asm-parisc/dma-mapping.h
--- a/include/asm-parisc/dma-mapping.h
+++ b/include/asm-parisc/dma-mapping.h
@@ -1,8 +1,8 @@
 #ifndef _PARISC_DMA_MAPPING_H
 #define _PARISC_DMA_MAPPING_H
 
-#include <linux/mm.h>
 #include <linux/config.h>
+#include <linux/mm.h>
 #include <asm/cacheflush.h>
 #include <asm/scatterlist.h>
 
diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h
--- a/include/asm-parisc/dma.h
+++ b/include/asm-parisc/dma.h
@@ -38,9 +38,11 @@
 ** won't compile :-(
 */
 #define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-#define DMA_AUTOINIT     0x10
+#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
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff --git a/include/asm-parisc/eisa_eeprom.h b/include/asm-parisc/eisa_eeprom.h
--- a/include/asm-parisc/eisa_eeprom.h
+++ b/include/asm-parisc/eisa_eeprom.h
@@ -13,6 +13,8 @@
 #ifndef ASM_EISA_EEPROM_H
 #define ASM_EISA_EEPROM_H
 
+extern void __iomem *eisa_eeprom_addr;
+
 #define HPEE_MAX_LENGTH       0x2000	/* maximum eeprom length */
 
 #define HPEE_SLOT_INFO(slot) (20+(48*slot))
diff --git a/include/asm-parisc/errno.h b/include/asm-parisc/errno.h
--- a/include/asm-parisc/errno.h
+++ b/include/asm-parisc/errno.h
@@ -115,5 +115,9 @@
 #define ENOTSUP		252	/* Function not implemented (POSIX.4 / HPUX) */
 #define ECANCELLED	253	/* aio request was canceled before complete (POSIX.4 / HPUX) */
 
+/* for robust mutexes */
+#define EOWNERDEAD	254	/* Owner died */
+#define ENOTRECOVERABLE	255	/* State not recoverable */
+
 
 #endif
diff --git a/include/asm-parisc/floppy.h b/include/asm-parisc/floppy.h
--- a/include/asm-parisc/floppy.h
+++ b/include/asm-parisc/floppy.h
@@ -235,7 +235,7 @@ static int hard_dma_setup(char *addr, un
 	return 0;
 }
 
-struct fd_routine_l {
+static 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);
diff --git a/include/asm-parisc/hardirq.h b/include/asm-parisc/hardirq.h
--- a/include/asm-parisc/hardirq.h
+++ b/include/asm-parisc/hardirq.h
@@ -15,9 +15,7 @@
 #ifndef _PARISC_HARDIRQ_H
 #define _PARISC_HARDIRQ_H
 
-#include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/cache.h>
 #include <linux/irq.h>
 
 typedef struct {
@@ -26,16 +24,6 @@ typedef struct {
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
-#define HARDIRQ_BITS	16
-
-/*
- * The hardirq mask has to be large enough to have space for potentially all
- * IRQ sources in the system nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
-
 void ack_bad_irq(unsigned int irq);
 
 #endif /* _PARISC_HARDIRQ_H */
diff --git a/include/asm-parisc/hardware.h b/include/asm-parisc/hardware.h
--- a/include/asm-parisc/hardware.h
+++ b/include/asm-parisc/hardware.h
@@ -122,6 +122,7 @@ extern char *print_pci_hwpath(struct pci
 extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
 extern void init_parisc_bus(void);
 extern struct device *hwpath_to_device(struct hardware_path *modpath);
+extern void device_to_hwpath(struct device *dev, struct hardware_path *path);
 
 
 /* inventory.c: */
diff --git a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
--- a/include/asm-parisc/ide.h
+++ b/include/asm-parisc/ide.h
@@ -13,8 +13,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
-
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	2
 #endif
@@ -34,7 +32,7 @@
 #define __ide_outsw	outsw
 #define __ide_outsl	outsl
 
-static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count)
+static __inline__ void __ide_mm_insw(void __iomem *port, void *addr, u32 count)
 {
 	while (count--) {
 		*(u16 *)addr = __raw_readw(port);
@@ -42,7 +40,7 @@ static __inline__ void __ide_mm_insw(uns
 	}
 }
 
-static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count)
+static __inline__ void __ide_mm_insl(void __iomem *port, void *addr, u32 count)
 {
 	while (count--) {
 		*(u32 *)addr = __raw_readl(port);
@@ -50,7 +48,7 @@ static __inline__ void __ide_mm_insl(uns
 	}
 }
 
-static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count)
+static __inline__ void __ide_mm_outsw(void __iomem *port, void *addr, u32 count)
 {
 	while (count--) {
 		__raw_writew(*(u16 *)addr, port);
@@ -58,7 +56,7 @@ static __inline__ void __ide_mm_outsw(un
 	}
 }
 
-static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count)
+static __inline__ void __ide_mm_outsl(void __iomem *port, void *addr, u32 count)
 {
 	while (count--) {
 		__raw_writel(*(u32 *)addr, port);
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -273,10 +273,11 @@ static inline void __raw_writeq(unsigned
 }
 #endif /* !USE_HPPA_IOREMAP */
 
+/* readb can never be const, so use __fswab instead of le*_to_cpu */
 #define readb(addr) __raw_readb(addr)
-#define readw(addr) le16_to_cpu(__raw_readw(addr))
-#define readl(addr) le32_to_cpu(__raw_readl(addr))
-#define readq(addr) le64_to_cpu(__raw_readq(addr))
+#define readw(addr) __fswab16(__raw_readw(addr))
+#define readl(addr) __fswab32(__raw_readl(addr))
+#define readq(addr) __fswab64(__raw_readq(addr))
 #define writeb(b, addr) __raw_writeb(b, addr)
 #define writew(b, addr) __raw_writew(cpu_to_le16(b), addr)
 #define writel(b, addr) __raw_writel(cpu_to_le32(b), addr)
@@ -403,4 +404,15 @@ extern void outsl (unsigned long port, c
 
 #include <asm-generic/iomap.h>
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -40,10 +40,12 @@ struct hw_interrupt_type;
 void no_ack_irq(unsigned int irq);
 void no_end_irq(unsigned int irq);
 
-extern int txn_alloc_irq(void);
+extern int txn_alloc_irq(unsigned int nbits);
 extern int txn_claim_irq(int);
-extern unsigned int txn_alloc_data(int, unsigned int);
-extern unsigned long txn_alloc_addr(int);
+extern unsigned int txn_alloc_data(unsigned int);
+extern unsigned long txn_alloc_addr(unsigned int);
+
+extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
 
 extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
 
diff --git a/include/asm-parisc/led.h b/include/asm-parisc/led.h
--- a/include/asm-parisc/led.h
+++ b/include/asm-parisc/led.h
@@ -21,19 +21,23 @@
 #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 */
+#define LED_CMD_REG_NONE 0		/* NULL == no addr for the cmd register */
 
 /* led tasklet struct */
 extern struct tasklet_struct led_tasklet;
 
 /* register_led_driver() */
-int __init register_led_driver( int model, char *cmd_reg, char *data_reg );
+int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg);
 
 /* registers the LED regions for procfs */
 void __init register_led_regions(void);
 
+#ifdef CONFIG_CHASSIS_LCD_LED
 /* writes a string to the LCD display (if possible on this h/w) */
 int lcd_print(char *str);
+#else
+#define lcd_print(str)
+#endif
 
 /* main LED initialization function (uses PDC) */ 
 int __init led_init(void);
diff --git a/include/asm-parisc/module.h b/include/asm-parisc/module.h
--- a/include/asm-parisc/module.h
+++ b/include/asm-parisc/module.h
@@ -17,12 +17,16 @@
 #define Elf_Rela Elf32_Rela
 #endif
 
+struct unwind_table;
+
 struct mod_arch_specific
 {
 	unsigned long got_offset, got_count, got_max;
 	unsigned long fdesc_offset, fdesc_count, fdesc_max;
 	unsigned long stub_offset, stub_count, stub_max;
 	unsigned long init_stub_offset, init_stub_count, init_stub_max;
+	int unwind_section;
+	struct unwind_table *unwind;
 };
 
 #endif /* _ASM_PARISC_MODULE_H */
diff --git a/include/asm-parisc/numnodes.h b/include/asm-parisc/numnodes.h
--- a/include/asm-parisc/numnodes.h
+++ b/include/asm-parisc/numnodes.h
@@ -1,8 +1,6 @@
 #ifndef _ASM_MAX_NUMNODES_H
 #define _ASM_MAX_NUMNODES_H
 
-#include <linux/config.h>
-
 /* Max 8 Nodes */
 #define NODES_SHIFT	3
 
diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h
--- a/include/asm-parisc/parisc-device.h
+++ b/include/asm-parisc/parisc-device.h
@@ -6,6 +6,7 @@ struct parisc_device {
 	struct parisc_driver *driver;	/* Driver for this device */
 	char		name[80];	/* The hardware description */
 	int		irq;
+	int		aux_irq;	/* Some devices have a second IRQ */
 
 	char		hw_path;        /* The module number on this bus */
 	unsigned int	num_addrs;	/* some devices have additional address ranges. */
diff --git a/include/asm-parisc/parport_gsc.h b/include/asm-parisc/parport_gsc.h
deleted file mode 100644
--- a/include/asm-parisc/parport_gsc.h
+++ /dev/null
@@ -1,193 +0,0 @@
-#ifndef __LINUX_PARPORT_GSC_H
-#define __LINUX_PARPORT_GSC_H
-
-#include <asm/io.h>
-#include <linux/delay.h>
-
-#undef	DEBUG_PARPORT	/* undefine for production */
-#define DELAY_TIME 	0
-
-#if DELAY_TIME == 0
-#define parport_readb	gsc_readb
-#define parport_writeb	gsc_writeb
-#else
-static __inline__ unsigned char parport_readb( unsigned long port )
-{
-    udelay(DELAY_TIME);
-    return gsc_readb(port);
-}
-
-static __inline__ void parport_writeb( unsigned char value, unsigned long port )
-{
-    gsc_writeb(value,port);
-    udelay(DELAY_TIME);
-}
-#endif
-
-/* --- register definitions ------------------------------- */
-
-#define EPPDATA(p)  ((p)->base    + 0x4)
-#define EPPADDR(p)  ((p)->base    + 0x3)
-#define CONTROL(p)  ((p)->base    + 0x2)
-#define STATUS(p)   ((p)->base    + 0x1)
-#define DATA(p)     ((p)->base    + 0x0)
-
-struct parport_gsc_private {
-	/* Contents of CTR. */
-	unsigned char ctr;
-
-	/* Bitmask of writable CTR bits. */
-	unsigned char ctr_writable;
-
-	/* Number of bytes per portword. */
-	int pword;
-
-	/* Not used yet. */
-	int readIntrThreshold;
-	int writeIntrThreshold;
-
-	/* buffer suitable for DMA, if DMA enabled */
-	char *dma_buf;
-	dma_addr_t dma_handle;
-	struct pci_dev *dev;
-};
-
-extern __inline__ void parport_gsc_write_data(struct parport *p, unsigned char d)
-{
-#ifdef DEBUG_PARPORT
-	printk (KERN_DEBUG "parport_gsc_write_data(%p,0x%02x)\n", p, d);
-#endif
-	parport_writeb(d, DATA(p));
-}
-
-extern __inline__ unsigned char parport_gsc_read_data(struct parport *p)
-{
-	unsigned char val = parport_readb (DATA (p));
-#ifdef DEBUG_PARPORT
-	printk (KERN_DEBUG "parport_gsc_read_data(%p) = 0x%02x\n",
-		p, val);
-#endif
-	return val;
-}
-
-/* __parport_gsc_frob_control differs from parport_gsc_frob_control in that
- * it doesn't do any extra masking. */
-static __inline__ unsigned char __parport_gsc_frob_control (struct parport *p,
-							   unsigned char mask,
-							   unsigned char val)
-{
-	struct parport_gsc_private *priv = p->physport->private_data;
-	unsigned char ctr = priv->ctr;
-#ifdef DEBUG_PARPORT
-	printk (KERN_DEBUG
-		"__parport_gsc_frob_control(%02x,%02x): %02x -> %02x\n",
-		mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
-#endif
-	ctr = (ctr & ~mask) ^ val;
-	ctr &= priv->ctr_writable; /* only write writable bits. */
-	parport_writeb (ctr, CONTROL (p));
-	priv->ctr = ctr;	/* Update soft copy */
-	return ctr;
-}
-
-extern __inline__ void parport_gsc_data_reverse (struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x20, 0x20);
-}
-
-extern __inline__ void parport_gsc_data_forward (struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x20, 0x00);
-}
-
-extern __inline__ void parport_gsc_write_control (struct parport *p,
-						 unsigned char d)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to newer interface. */
-	if (d & 0x20) {
-		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-			p->name, p->cad->name);
-		parport_gsc_data_reverse (p);
-	}
-
-	__parport_gsc_frob_control (p, wm, d & wm);
-}
-
-extern __inline__ unsigned char parport_gsc_read_control(struct parport *p)
-{
-	const unsigned char rm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-	const struct parport_gsc_private *priv = p->physport->private_data;
-	return priv->ctr & rm; /* Use soft copy */
-}
-
-extern __inline__ unsigned char parport_gsc_frob_control (struct parport *p,
-							 unsigned char mask,
-							 unsigned char val)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to newer interface. */
-	if (mask & 0x20) {
-		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
-			p->name, p->cad->name,
-			(val & 0x20) ? "reverse" : "forward");
-		if (val & 0x20)
-			parport_gsc_data_reverse (p);
-		else
-			parport_gsc_data_forward (p);
-	}
-
-	/* Restrict mask and val to control lines. */
-	mask &= wm;
-	val &= wm;
-
-	return __parport_gsc_frob_control (p, mask, val);
-}
-
-extern __inline__ unsigned char parport_gsc_read_status(struct parport *p)
-{
-	return parport_readb (STATUS(p));
-}
-
-
-extern __inline__ void parport_gsc_disable_irq(struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x10, 0x00);
-}
-
-extern __inline__ void parport_gsc_enable_irq(struct parport *p)
-{
-	__parport_gsc_frob_control (p, 0x10, 0x10);
-}
-
-extern void parport_gsc_release_resources(struct parport *p);
-
-extern int parport_gsc_claim_resources(struct parport *p);
-
-extern void parport_gsc_init_state(struct pardevice *, struct parport_state *s);
-
-extern void parport_gsc_save_state(struct parport *p, struct parport_state *s);
-
-extern void parport_gsc_restore_state(struct parport *p, struct parport_state *s);
-
-extern void parport_gsc_inc_use_count(void);
-
-extern void parport_gsc_dec_use_count(void);
-
-extern struct parport *parport_gsc_probe_port (unsigned long base,
-					      unsigned long base_hi,
-					      int irq, int dma,
-					      struct pci_dev *dev);
-
-#endif
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -28,7 +28,7 @@
 ** Data needed by pcibios layer belongs here.
 */
 struct pci_hba_data {
-	unsigned long	base_addr;	/* aka Host Physical Address */
+	void __iomem   *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" */
@@ -69,7 +69,7 @@ struct pci_hba_data {
 #define PCI_PORT_HBA(a)		((a) >> HBA_PORT_SPACE_BITS)
 #define PCI_PORT_ADDR(a)	((a) & (HBA_PORT_SPACE_SIZE - 1))
 
-#if CONFIG_PARISC64
+#if CONFIG_64BIT
 #define PCI_F_EXTEND		0xffffffff00000000UL
 #define PCI_IS_LMMIO(hba,a)	pci_is_lmmio(hba,a)
 
@@ -90,14 +90,14 @@ static __inline__  int pci_is_lmmio(stru
 		: (a))					/* GMMIO */
 #define PCI_HOST_ADDR(hba,a)	((a) + hba->lmmio_space_offset)
 
-#else	/* !CONFIG_PARISC64 */
+#else	/* !CONFIG_64BIT */
 
 #define PCI_BUS_ADDR(hba,a)	(a)
 #define PCI_HOST_ADDR(hba,a)	(a)
 #define PCI_F_EXTEND		0UL
 #define PCI_IS_LMMIO(hba,a)	(1)	/* 32-bit doesn't support GMMIO */
 
-#endif /* !CONFIG_PARISC64 */
+#endif /* !CONFIG_64BIT */
 
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
@@ -106,11 +106,28 @@ static __inline__  int pci_is_lmmio(stru
 struct pci_bus;
 struct pci_dev;
 
-/* The PCI address space does equal the physical memory
- * address space.  The networking and block device layers use
+/*
+ * If the PCI device's view of memory is the same as the CPU's view of memory,
+ * PCI_DMA_BUS_IS_PHYS is true.  The networking and block device layers use
  * this boolean for bounce buffer decisions.
  */
-#define PCI_DMA_BUS_IS_PHYS     (1)
+#ifdef CONFIG_PA20
+/* All PA-2.0 machines have an IOMMU. */
+#define PCI_DMA_BUS_IS_PHYS	0
+#define parisc_has_iommu()	do { } while (0)
+#else
+
+#if defined(CONFIG_IOMMU_CCIO) || defined(CONFIG_IOMMU_SBA)
+extern int parisc_bus_is_phys; 	/* in arch/parisc/kernel/setup.c */
+#define PCI_DMA_BUS_IS_PHYS	parisc_bus_is_phys
+#define parisc_has_iommu()	do { parisc_bus_is_phys = 0; } while (0)
+#else
+#define PCI_DMA_BUS_IS_PHYS	1
+#define parisc_has_iommu()	do { } while (0)
+#endif
+
+#endif	/* !CONFIG_PA20 */
+
 
 /*
 ** Most PCI devices (eg Tulip, NCR720) also export the same registers
@@ -182,16 +199,27 @@ extern inline void pcibios_register_hba(
 #endif
 
 /*
-** used by drivers/pci/pci.c:pci_do_scan_bus()
-**   0 == check if bridge is numbered before re-numbering.
-**   1 == pci_do_scan_bus() should automatically number all PCI-PCI bridges.
-**
-** REVISIT:
-**   To date, only alpha sets this to one. We'll need to set this
-**   to zero for legacy platforms and one for PAT platforms.
-*/
-#define pcibios_assign_all_busses()     (pdc_type == PDC_TYPE_PAT)
-#define pcibios_scan_all_fns(a, b)	0
+ * pcibios_assign_all_busses() is used in drivers/pci/pci.c:pci_do_scan_bus()
+ *   0 == check if bridge is numbered before re-numbering.
+ *   1 == pci_do_scan_bus() should automatically number all PCI-PCI bridges.
+ *
+ *   We *should* set this to zero for "legacy" platforms and one
+ *   for PAT platforms.
+ *
+ *   But legacy platforms also need to renumber the busses below a Host
+ *   Bus controller.  Adding a 4-port Tulip card on the first PCI root
+ *   bus of a C200 resulted in the secondary bus being numbered as 1.
+ *   The second PCI host bus controller's root bus had already been
+ *   assigned bus number 1 by firmware and sysfs complained.
+ *
+ *   Firmware isn't doing anything wrong here since each controller
+ *   is its own PCI domain.  It's simpler and easier for us to renumber
+ *   the busses rather than treat each Dino as a separate PCI domain.
+ *   Eventually, we may want to introduce PCI domains for Superdome or
+ *   rp7420/8420 boxes and then revisit this issue.
+ */
+#define pcibios_assign_all_busses()     (1)
+#define pcibios_scan_all_fns(a, b)	(0)
 
 #define PCIBIOS_MIN_IO          0x10
 #define PCIBIOS_MIN_MEM         0x1000 /* NBPG - but pci/setup-res.c dies */
diff --git a/include/asm-parisc/pdc_chassis.h b/include/asm-parisc/pdc_chassis.h
--- a/include/asm-parisc/pdc_chassis.h
+++ b/include/asm-parisc/pdc_chassis.h
@@ -1,8 +1,8 @@
 /*
- *		include/asm-parisc/pdc_chassis.h
+ *	include/asm-parisc/pdc_chassis.h
  *
- *		Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
- *		Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *	Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *	Copyright (C) 2002 Thibaut Varene <varenet@parisc-linux.org>
  *
  *
  *      This program is free software; you can redistribute it and/or modify
diff --git a/include/asm-parisc/pdcpat.h b/include/asm-parisc/pdcpat.h
--- a/include/asm-parisc/pdcpat.h
+++ b/include/asm-parisc/pdcpat.h
@@ -190,16 +190,16 @@
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
 
-#ifdef CONFIG_PARISC64
+#ifdef CONFIG_64BIT
 #define is_pdc_pat()	(PDC_TYPE_PAT == pdc_type)
 extern int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num);
 extern int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
-#else	/* ! CONFIG_PARISC64 */
+#else	/* ! CONFIG_64BIT */
 /* No PAT support for 32-bit kernels...sorry */
 #define is_pdc_pat()	(0)
 #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	/* ! CONFIG_PARISC64 */
+#endif	/* ! CONFIG_64BIT */
 
 
 struct pdc_pat_cell_num {
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
--- a/include/asm-parisc/pgalloc.h
+++ b/include/asm-parisc/pgalloc.h
@@ -7,7 +7,6 @@
 #include <asm/processor.h>
 #include <asm/fixmap.h>
 
-#include <asm/pgtable.h>
 #include <asm/cache.h>
 
 /* Allocate the top level pgd (page directory)
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -39,6 +39,7 @@
         do{                                                     \
                 *(pteptr) = (pteval);                           \
         } while(0)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 #endif /* !__ASSEMBLY__ */
 
@@ -119,7 +120,7 @@
  * pgd entries used up by user/kernel:
  */
 
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #ifndef __ASSEMBLY__
 extern  void *vmalloc_start;
@@ -263,7 +264,7 @@ extern unsigned long *empty_zero_page;
 
 #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_clear(mm,addr,xp)	do { pte_val(*(xp)) = 0; } while (0)
 
 #define pmd_flag(x)	(pmd_val(x) & PxD_FLAG_MASK)
 #define pmd_address(x)	((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
@@ -431,7 +432,7 @@ extern void update_mmu_cache(struct vm_a
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	if (!pte_young(*ptep))
@@ -441,12 +442,12 @@ static inline int ptep_test_and_clear_yo
 	pte_t pte = *ptep;
 	if (!pte_young(pte))
 		return 0;
-	set_pte(ptep, pte_mkold(pte));
+	set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte));
 	return 1;
 #endif
 }
 
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	if (!pte_dirty(*ptep))
@@ -456,14 +457,14 @@ static inline int ptep_test_and_clear_di
 	pte_t pte = *ptep;
 	if (!pte_dirty(pte))
 		return 0;
-	set_pte(ptep, pte_mkclean(pte));
+	set_pte_at(vma->vm_mm, addr, ptep, pte_mkclean(pte));
 	return 1;
 #endif
 }
 
 extern spinlock_t pa_dbit_lock;
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t old_pte;
 	pte_t pte;
@@ -472,13 +473,13 @@ static inline pte_t ptep_get_and_clear(p
 	pte = old_pte = *ptep;
 	pte_val(pte) &= ~_PAGE_PRESENT;
 	pte_val(pte) |= _PAGE_FLUSH;
-	set_pte(ptep,pte);
+	set_pte_at(mm,addr,ptep,pte);
 	spin_unlock(&pa_dbit_lock);
 
 	return old_pte;
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_SMP
 	unsigned long new, old;
@@ -489,17 +490,7 @@ static inline void ptep_set_wrprotect(pt
 	} 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), &pte_val(*ptep));
-#else
-	pte_t old_pte = *ptep;
-	set_pte(ptep, pte_mkdirty(old_pte));
+	set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 #endif
 }
 
@@ -510,6 +501,13 @@ static inline void ptep_mkdirty(pte_t *p
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /* We provide our own get_unmapped_area to provide cache coherency */
 
 #define HAVE_ARCH_UNMAPPED_AREA
@@ -518,7 +516,6 @@ static inline void ptep_mkdirty(pte_t *p
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
--- a/include/asm-parisc/serial.h
+++ b/include/asm-parisc/serial.h
@@ -2,8 +2,6 @@
  * include/asm-parisc/serial.h
  */
 
-#include <linux/config.h>
-
 /*
  * This assumes you have a 7.272727 MHz clock for your UART.
  * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
diff --git a/include/asm-parisc/signal.h b/include/asm-parisc/signal.h
--- a/include/asm-parisc/signal.h
+++ b/include/asm-parisc/signal.h
@@ -89,17 +89,6 @@
 #define _NSIG_BPW	BITS_PER_LONG
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
-/*
- * 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 /* __KERNEL__ */
 
 #define SIG_BLOCK          0	/* for blocking signals */
@@ -123,13 +112,14 @@ struct siginfo;
  * compiler doesn't support code which changes or tests the address of
  * the function in the little struct.  This is really ugly -PB
  */
-typedef __kernel_caddr_t __sighandler_t;
+typedef char __user *__sighandler_t;
 #else
-typedef void (*__sighandler_t)(int);
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
 #endif
 
 typedef struct sigaltstack {
-	void *ss_sp;
+	void __user *ss_sp;
 	int ss_flags;
 	size_t ss_size;
 } stack_t;
diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
--- a/include/asm-parisc/spinlock.h
+++ b/include/asm-parisc/spinlock.h
@@ -226,7 +226,7 @@ static  __inline__ void _raw_write_unloc
 }
 
 #ifdef CONFIG_DEBUG_RWLOCK
-extern void _dbg_write_trylock(rwlock_t * rw, const char *bfile, int bline);
+extern int _dbg_write_trylock(rwlock_t * rw, const char *bfile, int bline);
 #define _raw_write_trylock(rw) _dbg_write_trylock(rw, __FILE__, __LINE__)
 #else
 static  __inline__ int _raw_write_trylock(rwlock_t *rw)
diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h
--- a/include/asm-parisc/system.h
+++ b/include/asm-parisc/system.h
@@ -125,7 +125,7 @@ static inline void set_eiem(unsigned lon
 ** The __asm__ op below simple prevents gcc/ld from reordering
 ** instructions across the mb() "call".
 */
-#define mb()		__asm__ __volatile__("":::"memory");	/* barrier() */
+#define mb()		__asm__ __volatile__("":::"memory")	/* barrier() */
 #define rmb()		mb()
 #define wmb()		mb()
 #define smp_mb()	mb()
@@ -205,4 +205,6 @@ extern spinlock_t pa_tlb_lock;
 
 #endif
 
+#define arch_align_stack(x) (x)
+
 #endif
diff --git a/include/asm-parisc/thread_info.h b/include/asm-parisc/thread_info.h
--- a/include/asm-parisc/thread_info.h
+++ b/include/asm-parisc/thread_info.h
@@ -23,7 +23,7 @@ struct thread_info {
 	.flags		= 0,			\
 	.cpu		= 0,			\
 	.addr_limit	= KERNEL_DS,		\
-	.preempt_count	= 0,			\
+	.preempt_count	= 1,			\
   	.restart_block	= {			\
 		.fn = do_no_restart_syscall	\
 	}					\
@@ -52,7 +52,7 @@ struct thread_info {
 
 #endif /* !__ASSEMBLY */
 
-#define PREEMPT_ACTIVE          0x4000000
+#define PREEMPT_ACTIVE          0x10000000
 
 /*
  * thread information flags
diff --git a/include/asm-parisc/timex.h b/include/asm-parisc/timex.h
--- a/include/asm-parisc/timex.h
+++ b/include/asm-parisc/timex.h
@@ -12,8 +12,6 @@
 
 typedef unsigned long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles (void)
 {
 	return mfctl(16);
diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h
--- a/include/asm-parisc/uaccess.h
+++ b/include/asm-parisc/uaccess.h
@@ -24,7 +24,7 @@
 
 /*
  * Note that since kernel addresses are in a separate address space on
- * parisc, we don't need to do anything for access_ok() or verify_area().
+ * parisc, we don't need to do anything for access_ok().
  * We just let the page fault handler do the right thing. This also means
  * that put_user is the same as __put_user, etc.
  */
@@ -34,8 +34,15 @@ extern int __get_user_bad(void);
 extern int __put_kernel_bad(void);
 extern int __put_user_bad(void);
 
-#define access_ok(type,addr,size)   (1)
-#define verify_area(type,addr,size) (0)
+static inline long access_ok(int type, const void __user * addr,
+		unsigned long size)
+{
+	return 1;
+}
+
+#define verify_area(type,addr,size) (0)	/* FIXME: all users should go away soon,
+                                         * and use access_ok instead, then this
+                                         * should be removed. */
 
 #define put_user __put_user
 #define get_user __get_user
@@ -142,22 +149,23 @@ struct exception_data {
 #define __put_user(x,ptr)                                       \
 ({								\
 	register long __pu_err __asm__ ("r8") = 0;      	\
+        __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x);	\
 								\
 	if (segment_eq(get_fs(),KERNEL_DS)) {                   \
 	    switch (sizeof(*(ptr))) {                           \
-	    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: STD_KERNEL(x,ptr); break;			\
+	    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: STD_KERNEL(__x,ptr); break;			\
 	    default: __put_kernel_bad(); break;			\
 	    }                                                   \
 	}                                                       \
 	else {                                                  \
 	    switch (sizeof(*(ptr))) {                           \
-	    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: STD_USER(x,ptr); break;			\
+	    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: STD_USER(__x,ptr); break;			\
 	    default: __put_user_bad(); break;			\
 	    }                                                   \
 	}                                                       \
diff --git a/include/asm-parisc/unaligned.h b/include/asm-parisc/unaligned.h
--- a/include/asm-parisc/unaligned.h
+++ b/include/asm-parisc/unaligned.h
@@ -1,22 +1,7 @@
 #ifndef _ASM_PARISC_UNALIGNED_H_
 #define _ASM_PARISC_UNALIGNED_H_
 
-/* parisc can't handle unaligned accesses. */
-/* copied from asm-sparc/unaligned.h */
-
-#include <linux/string.h>
-
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
-
+#include <asm-generic/unaligned.h>
 
 #ifdef __KERNEL__
 struct pt_regs;
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
--- a/include/asm-parisc/unistd.h
+++ b/include/asm-parisc/unistd.h
@@ -1024,6 +1024,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _ASM_PARISC_UNISTD_H_ */
diff --git a/include/asm-parisc/unwind.h b/include/asm-parisc/unwind.h
--- a/include/asm-parisc/unwind.h
+++ b/include/asm-parisc/unwind.h
@@ -1,6 +1,8 @@
 #ifndef _UNWIND_H_
 #define _UNWIND_H_
 
+#include <linux/list.h>
+
 /* From ABI specifications */
 struct unwind_table_entry {
 	unsigned int region_start;
@@ -39,7 +41,7 @@ struct unwind_table_entry {
 };
 
 struct unwind_table {
-	struct unwind_table *next;
+	struct list_head list;
 	const char *name;
 	unsigned long gp;
 	unsigned long base_addr;
@@ -55,15 +57,18 @@ struct unwind_frame_info {
 	   available; but for now we only try to get the sp and ip for each
 	   frame */
 	/* struct pt_regs regs; */
-	unsigned long sp, ip, rp;
+	unsigned long sp, ip, rp, r31;
 	unsigned long prev_sp, prev_ip;
 };
 
-void * unwind_table_add(const char *name, unsigned long base_addr, 
-		 unsigned long gp,
-                 void *start, void *end);
+struct unwind_table *
+unwind_table_add(const char *name, unsigned long base_addr, 
+		 unsigned long gp, void *start, void *end);
+void
+unwind_table_remove(struct unwind_table *table);
+
 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
-		       unsigned long sp, unsigned long ip, unsigned long rp);
+		       struct pt_regs *regs);
 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t);
 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs);
 int unwind_once(struct unwind_frame_info *info);
diff --git a/include/asm-ppc/agp.h b/include/asm-ppc/agp.h
--- a/include/asm-ppc/agp.h
+++ b/include/asm-ppc/agp.h
@@ -10,4 +10,14 @@
 #define flush_agp_mappings()
 #define flush_agp_cache() mb()
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif
diff --git a/include/asm-ppc/bug.h b/include/asm-ppc/bug.h
--- a/include/asm-ppc/bug.h
+++ b/include/asm-ppc/bug.h
@@ -14,6 +14,7 @@ struct bug_entry {
  */
 #define BUG_WARNING_TRAP	0x1000000
 
+#ifdef CONFIG_BUG
 #define BUG() do {							 \
 	__asm__ __volatile__(						 \
 		"1:	twi 31,0,0\n"					 \
@@ -50,6 +51,8 @@ struct bug_entry {
 #define HAVE_ARCH_BUG
 #define HAVE_ARCH_BUG_ON
 #define HAVE_ARCH_WARN_ON
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
--- a/include/asm-ppc/cache.h
+++ b/include/asm-ppc/cache.h
@@ -50,12 +50,12 @@ extern void flush_dcache_all(void);
 /* Cache control on the MPC8xx is provided through some additional
  * special purpose registers.
  */
-#define IC_CST		560	/* Instruction cache control/status */
-#define IC_ADR		561	/* Address needed for some commands */
-#define IC_DAT		562	/* Read-only data register */
-#define DC_CST		568	/* Data cache control/status */
-#define DC_ADR		569	/* Address needed for some commands */
-#define DC_DAT		570	/* Read-only data register */
+#define SPRN_IC_CST	560	/* Instruction cache control/status */
+#define SPRN_IC_ADR	561	/* Address needed for some commands */
+#define SPRN_IC_DAT	562	/* Read-only data register */
+#define SPRN_DC_CST	568	/* Data cache control/status */
+#define SPRN_DC_ADR	569	/* Address needed for some commands */
+#define SPRN_DC_DAT	570	/* Read-only data register */
 
 /* Commands.  Only the first few are available to the instruction cache.
 */
diff --git a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h
--- a/include/asm-ppc/cacheflush.h
+++ b/include/asm-ppc/cacheflush.h
@@ -22,7 +22,7 @@
 #define flush_cache_all()		do { } while (0)
 #define flush_cache_mm(mm)		do { } while (0)
 #define flush_cache_range(vma, a, b)	do { } while (0)
-#define flush_cache_page(vma, p)	do { } while (0)
+#define flush_cache_page(vma, p, pfn)	do { } while (0)
 #define flush_icache_page(vma, page)	do { } while (0)
 #define flush_cache_vmap(start, end)	do { } while (0)
 #define flush_cache_vunmap(start, end)	do { } while (0)
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -69,6 +69,7 @@
 #define CPM_CR_INIT_TX		((ushort)0x0002)
 #define CPM_CR_HUNT_MODE	((ushort)0x0003)
 #define CPM_CR_STOP_TX		((ushort)0x0004)
+#define CPM_CR_GRA_STOP_TX      ((ushort)0x0005)
 #define CPM_CR_RESTART_TX	((ushort)0x0006)
 #define CPM_CR_SET_GADDR	((ushort)0x0008)
 #define CPM_CR_START_IDMA	((ushort)0x0009)
@@ -85,7 +86,7 @@
  */
 #define CPM_DATAONLY_BASE	((uint)128)
 #define CPM_DP_NOSPACE		((uint)0x7fffffff)
-#ifdef CONFIG_8272
+#if defined(CONFIG_8272) || defined(CONFIG_MPC8555)
 #define CPM_DATAONLY_SIZE	((uint)(8 * 1024) - CPM_DATAONLY_BASE)
 #define CPM_FCC_SPECIAL_BASE	((uint)0x00009000)
 #else
@@ -531,7 +532,7 @@ typedef struct scc_uart {
 #define SCU_PSMR_RPM		((ushort)0x000c)
 #define SCU_PSMR_REVP		((ushort)0x0008)
 #define SCU_PSMR_TPM		((ushort)0x0003)
-#define SCU_PSMR_TEVP		((ushort)0x0003)
+#define SCU_PSMR_TEVP		((ushort)0x0002)
 
 /* CPM Transparent mode SCC.
  */
@@ -1038,6 +1039,52 @@ typedef struct im_idma {
 #define CMXSCR_TS4CS_CLK7  0x00000006   /* SCC4 Tx Clock Source is CLK7 */
 #define CMXSCR_TS4CS_CLK8  0x00000007   /* SCC4 Tx Clock Source is CLK8 */
 
+/*-----------------------------------------------------------------------
+ * SIUMCR - SIU Module Configuration Register				 4-31
+ */
+#define SIUMCR_BBD	0x80000000	/* Bus Busy Disable		*/
+#define SIUMCR_ESE	0x40000000	/* External Snoop Enable	*/
+#define SIUMCR_PBSE	0x20000000	/* Parity Byte Select Enable	*/
+#define SIUMCR_CDIS	0x10000000	/* Core Disable			*/
+#define SIUMCR_DPPC00	0x00000000	/* Data Parity Pins Configuration*/
+#define SIUMCR_DPPC01	0x04000000	/* - " -			*/
+#define SIUMCR_DPPC10	0x08000000	/* - " -			*/
+#define SIUMCR_DPPC11	0x0c000000	/* - " -			*/
+#define SIUMCR_L2CPC00	0x00000000	/* L2 Cache Pins Configuration	*/
+#define SIUMCR_L2CPC01	0x01000000	/* - " -			*/
+#define SIUMCR_L2CPC10	0x02000000	/* - " -			*/
+#define SIUMCR_L2CPC11	0x03000000	/* - " -			*/
+#define SIUMCR_LBPC00	0x00000000	/* Local Bus Pins Configuration	*/
+#define SIUMCR_LBPC01	0x00400000	/* - " -			*/
+#define SIUMCR_LBPC10	0x00800000	/* - " -			*/
+#define SIUMCR_LBPC11	0x00c00000	/* - " -			*/
+#define SIUMCR_APPC00	0x00000000	/* Address Parity Pins Configuration*/
+#define SIUMCR_APPC01	0x00100000	/* - " -			*/
+#define SIUMCR_APPC10	0x00200000	/* - " -			*/
+#define SIUMCR_APPC11	0x00300000	/* - " -			*/
+#define SIUMCR_CS10PC00	0x00000000	/* CS10 Pin Configuration	*/
+#define SIUMCR_CS10PC01	0x00040000	/* - " -			*/
+#define SIUMCR_CS10PC10	0x00080000	/* - " -			*/
+#define SIUMCR_CS10PC11	0x000c0000	/* - " -			*/
+#define SIUMCR_BCTLC00	0x00000000	/* Buffer Control Configuration	*/
+#define SIUMCR_BCTLC01	0x00010000	/* - " -			*/
+#define SIUMCR_BCTLC10	0x00020000	/* - " -			*/
+#define SIUMCR_BCTLC11	0x00030000	/* - " -			*/
+#define SIUMCR_MMR00	0x00000000	/* Mask Masters Requests	*/
+#define SIUMCR_MMR01	0x00004000	/* - " -			*/
+#define SIUMCR_MMR10	0x00008000	/* - " -			*/
+#define SIUMCR_MMR11	0x0000c000	/* - " -			*/
+#define SIUMCR_LPBSE	0x00002000	/* LocalBus Parity Byte Select Enable*/
+
+/*-----------------------------------------------------------------------
+ * SCCR - System Clock Control Register					 9-8
+*/
+#define SCCR_PCI_MODE	0x00000100	/* PCI Mode	*/
+#define SCCR_PCI_MODCK	0x00000080	/* Value of PCI_MODCK pin	*/
+#define SCCR_PCIDF_MSK	0x00000078	/* PCI division factor	*/
+#define SCCR_PCIDF_SHIFT 3
+
+
 #endif /* __CPM2__ */
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h
--- a/include/asm-ppc/cputable.h
+++ b/include/asm-ppc/cputable.h
@@ -61,6 +61,11 @@ struct cpu_spec {
 extern struct cpu_spec		cpu_specs[];
 extern struct cpu_spec		*cur_cpu_spec[];
 
+static inline unsigned int cpu_has_feature(unsigned int feature)
+{
+	return cur_cpu_spec[0]->cpu_features & feature;
+}
+
 #endif /* __ASSEMBLY__ */
 
 /* CPU kernel features */
@@ -81,8 +86,9 @@ extern struct cpu_spec		*cur_cpu_spec[];
 #define CPU_FTR_DUAL_PLL_750FX		0x00004000
 #define CPU_FTR_NO_DPM			0x00008000
 #define CPU_FTR_HAS_HIGH_BATS		0x00010000
-#define CPU_FTR_NEED_COHERENT           0x00020000
+#define CPU_FTR_NEED_COHERENT		0x00020000
 #define CPU_FTR_NO_BTIC			0x00040000
+#define CPU_FTR_BIG_PHYS		0x00080000
 
 #ifdef __ASSEMBLY__
 
diff --git a/include/asm-ppc/dbdma.h b/include/asm-ppc/dbdma.h
--- a/include/asm-ppc/dbdma.h
+++ b/include/asm-ppc/dbdma.h
@@ -88,7 +88,7 @@ struct dbdma_cmd {
 #define WAIT_ALWAYS	3	/* always wait */
 
 /* Align an address for a DBDMA command structure */
-#define DBDMA_ALIGN(x)	(((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \
+#define DBDMA_ALIGN(x)	(((unsigned long)(x) + sizeof(struct dbdma_cmd) - 1) \
 			 & -sizeof(struct dbdma_cmd))
 
 /* Useful macros */
diff --git a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h
--- a/include/asm-ppc/dma.h
+++ b/include/asm-ppc/dma.h
@@ -25,7 +25,6 @@
  * with a grain of salt.
  */
 
-
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
@@ -192,9 +191,9 @@ static __inline__ void release_dma_lock(
 /* enable/disable a specific DMA channel */
 static __inline__ void enable_dma(unsigned int dmanr)
 {
-	unsigned char ucDmaCmd=0x00;
+	unsigned char ucDmaCmd = 0x00;
 
-	if (dmanr != 4)	{
+	if (dmanr != 4) {
 		dma_outb(0, DMA2_MASK_REG);	/* This may not be enabled */
 		dma_outb(ucDmaCmd, DMA2_CMD_REG);	/* Enable group */
 	}
@@ -244,60 +243,58 @@ static __inline__ void set_dma_mode(unsi
  */
 static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
 {
-	switch(dmanr) {
-		case 0:
-			dma_outb(pagenr, DMA_LO_PAGE_0);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_0);
-			break;
-		case 1:
-			dma_outb(pagenr, DMA_LO_PAGE_1);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_1);
-			break;
-		case 2:
-			dma_outb(pagenr, DMA_LO_PAGE_2);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_2);
-			break;
-		case 3:
-			dma_outb(pagenr, DMA_LO_PAGE_3);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
-			break;
-		case 5:
-			if (SND_DMA1 == 5 || SND_DMA2 == 5)
-				dma_outb(pagenr, DMA_LO_PAGE_5);
-			else
-				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
-			break;
-		case 6:
-			if (SND_DMA1 == 6 || SND_DMA2 == 6)
-				dma_outb(pagenr, DMA_LO_PAGE_6);
-			else
-				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
-			break;
-		case 7:
-			if (SND_DMA1 == 7 || SND_DMA2 == 7)
-				dma_outb(pagenr, DMA_LO_PAGE_7);
-			else
-				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
-			dma_outb(pagenr >> 8, DMA_HI_PAGE_7);
-			break;
+	switch (dmanr) {
+	case 0:
+		dma_outb(pagenr, DMA_LO_PAGE_0);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_0);
+		break;
+	case 1:
+		dma_outb(pagenr, DMA_LO_PAGE_1);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_1);
+		break;
+	case 2:
+		dma_outb(pagenr, DMA_LO_PAGE_2);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_2);
+		break;
+	case 3:
+		dma_outb(pagenr, DMA_LO_PAGE_3);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
+		break;
+	case 5:
+		if (SND_DMA1 == 5 || SND_DMA2 == 5)
+			dma_outb(pagenr, DMA_LO_PAGE_5);
+		else
+			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
+		break;
+	case 6:
+		if (SND_DMA1 == 6 || SND_DMA2 == 6)
+			dma_outb(pagenr, DMA_LO_PAGE_6);
+		else
+			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+		dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
+		break;
+	case 7:
+		if (SND_DMA1 == 7 || SND_DMA2 == 7)
+			dma_outb(pagenr, DMA_LO_PAGE_7);
+		else
+			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+		dma_outb(pagenr >> 8, DMA_HI_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 phys)
 {
 	if (dmanr <= 3) {
-		dma_outb(phys & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE );
+		dma_outb(phys & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE);
 		dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE);
 	} else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-		dma_outb(phys  & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE );
-		dma_outb((phys >> 8)  & 0xff, ((dmanr & 3) << 2) +
-				IO_DMA2_BASE);
+		dma_outb(phys & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
+		dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
 		dma_outb((dmanr & 3), DMA2_EXT_REG);
 	} else {
 		dma_outb((phys >> 1) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
@@ -306,7 +303,6 @@ static __inline__ void set_dma_addr(unsi
 	set_dma_page(dmanr, phys >> 16);
 }
 
-
 /* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
  * a specific DMA channel.
  * You must ensure the parameters are valid.
@@ -321,16 +317,16 @@ static __inline__ void set_dma_count(uns
 	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);
+			 IO_DMA1_BASE);
 	} else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-		dma_outb( count & 0xff, ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
-		dma_outb( (count >> 8) & 0xff, ((dmanr & 3) << 2) + 2 +
-				IO_DMA2_BASE);
+		dma_outb(count & 0xff, ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
+		dma_outb((count >> 8) & 0xff, ((dmanr & 3) << 2) + 2 +
+			 IO_DMA2_BASE);
 	} else {
 		dma_outb((count >> 1) & 0xff, ((dmanr & 3) << 2) + 2 +
-				IO_DMA2_BASE);
+			 IO_DMA2_BASE);
 		dma_outb((count >> 9) & 0xff, ((dmanr & 3) << 2) + 2 +
-				IO_DMA2_BASE);
+			 IO_DMA2_BASE);
 	}
 }
 
@@ -345,8 +341,8 @@ static __inline__ void set_dma_count(uns
 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;
+	    ((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;
@@ -355,14 +351,14 @@ static __inline__ int get_dma_residue(un
 	count += dma_inb(io_port) << 8;
 
 	return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2)
-		? count : (count<<1);
+	    ? count : (count << 1);
 
 }
 
 /* These are in kernel/dma.c: */
 
 /* reserve a DMA channel */
-extern int request_dma(unsigned int dmanr, const char * device_id);
+extern int request_dma(unsigned int dmanr, const char *device_id);
 /* release it again */
 extern void free_dma(unsigned int dmanr);
 
@@ -371,5 +367,5 @@ extern int isa_dma_bridge_buggy;
 #else
 #define isa_dma_bridge_buggy	(0)
 #endif
-#endif /* _ASM_DMA_H */
-#endif /* __KERNEL__ */
+#endif				/* _ASM_DMA_H */
+#endif				/* __KERNEL__ */
diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
--- a/include/asm-ppc/floppy.h
+++ b/include/asm-ppc/floppy.h
@@ -11,28 +11,149 @@
 #ifndef __ASM_PPC_FLOPPY_H
 #define __ASM_PPC_FLOPPY_H
 
-#define fd_inb(port)			inb_p(port)
-#define fd_outb(value,port)		outb_p(value,port)
+#define fd_inb(port)		inb_p(port)
+#define fd_outb(value,port)	outb_p(value,port)
 
-#define fd_enable_dma()         enable_dma(FLOPPY_DMA)
-#define fd_disable_dma()        disable_dma(FLOPPY_DMA)
-#define fd_request_dma()        request_dma(FLOPPY_DMA,"floppy")
-#define fd_free_dma()           free_dma(FLOPPY_DMA)
-#define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
-#define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
-#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,(unsigned int)virt_to_bus(addr))
-#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
+#define fd_disable_dma()	fd_ops->_disable_dma(FLOPPY_DMA)
+#define fd_free_dma()           fd_ops->_free_dma(FLOPPY_DMA)
+#define fd_get_dma_residue()    fd_ops->_get_dma_residue(FLOPPY_DMA)
+#define fd_dma_setup(addr, size, mode, io) fd_ops->_dma_setup(addr, size, mode, io)
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
-#define fd_cacheflush(addr,size) /* nothing */
-#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-				            "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
-__inline__ void virtual_dma_init(void)
+static int fd_request_dma(void);
+
+struct fd_dma_ops {
+	void (*_disable_dma)(unsigned int dmanr);
+	void (*_free_dma)(unsigned int dmanr);
+	int (*_get_dma_residue)(unsigned int dummy);
+	int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
+};
+
+static int virtual_dma_count;
+static int virtual_dma_residue;
+static char *virtual_dma_addr;
+static int virtual_dma_mode;
+static int doing_vdma;
+static struct fd_dma_ops *fd_ops;
+
+static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned char st;
+	int lcount;
+	char *lptr;
+
+	if (!doing_vdma)
+		return floppy_interrupt(irq, dev_id, regs);
+
+
+	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);
+
+	if (st == 0x20)
+		return IRQ_HANDLED;
+	if (!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+		doing_vdma = 0;
+		floppy_interrupt(irq, dev_id, regs);
+		return IRQ_HANDLED;
+	}
+	return IRQ_HANDLED;
+}
+
+static void vdma_disable_dma(unsigned int dummy)
+{
+	doing_vdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=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 int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_vdma = 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)
+{
+	/* actual, physical DMA */
+	doing_vdma = 0;
+	clear_dma_ff(FLOPPY_DMA);
+	set_dma_mode(FLOPPY_DMA,mode);
+	set_dma_addr(FLOPPY_DMA,(unsigned int)virt_to_bus(addr));
+	set_dma_count(FLOPPY_DMA,size);
+	enable_dma(FLOPPY_DMA);
+	return 0;
+}
+
+static struct fd_dma_ops real_dma_ops =
+{
+	._disable_dma = disable_dma,
+	._free_dma = free_dma,
+	._get_dma_residue = get_dma_residue,
+	._dma_setup = hard_dma_setup
+};
+
+static struct fd_dma_ops virt_dma_ops =
+{
+	._disable_dma = vdma_disable_dma,
+	._free_dma = vdma_nop,
+	._get_dma_residue = vdma_get_dma_residue,
+	._dma_setup = vdma_dma_setup
+};
+
+static int fd_request_dma()
 {
-	/* Nothing to do on PowerPC */
+	if (can_use_virtual_dma & 1) {
+		fd_ops = &virt_dma_ops;
+		return 0;
+	}
+	else {
+		fd_ops = &real_dma_ops;
+		return request_dma(FLOPPY_DMA, "floppy");
+	}
 }
 
 static int FDC1 = 0x3f0;
diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h
--- a/include/asm-ppc/highmem.h
+++ b/include/asm-ppc/highmem.h
@@ -35,8 +35,6 @@ extern pte_t *kmap_pte;
 extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
 
-extern void kmap_init(void) __init;
-
 /*
  * Right now we initialize only a single pte table. It can be extended
  * easily, subsequent pte tables have to be allocated in one physical
@@ -90,7 +88,7 @@ static inline void *kmap_atomic(struct p
 #ifdef HIGHMEM_DEBUG
 	BUG_ON(!pte_none(*(kmap_pte+idx)));
 #endif
-	set_pte(kmap_pte+idx, mk_pte(page, kmap_prot));
+	set_pte_at(&init_mm, vaddr, kmap_pte+idx, mk_pte(page, kmap_prot));
 	flush_tlb_page(NULL, vaddr);
 
 	return (void*) vaddr;
@@ -114,7 +112,7 @@ static inline void kunmap_atomic(void *k
 	 * force other mappings to Oops if they'll try to access
 	 * this pte without first remap it
 	 */
-	pte_clear(kmap_pte+idx);
+	pte_clear(&init_mm, vaddr, kmap_pte+idx);
 	flush_tlb_page(NULL, vaddr);
 #endif
 	dec_preempt_count();
diff --git a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h
--- a/include/asm-ppc/hydra.h
+++ b/include/asm-ppc/hydra.h
@@ -51,7 +51,7 @@ struct Hydra {
     char OpenPIC[0x40000];
 };
 
-extern volatile struct Hydra *Hydra;
+extern volatile struct Hydra __iomem *Hydra;
 
 
     /*
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -30,6 +30,8 @@
 #include <asm/mpc8xx.h>
 #elif defined(CONFIG_8260)
 #include <asm/mpc8260.h>
+#elif defined(CONFIG_83xx)
+#include <asm/mpc83xx.h>
 #elif defined(CONFIG_85xx)
 #include <asm/mpc85xx.h>
 #elif defined(CONFIG_APUS)
@@ -550,4 +552,15 @@ extern void pci_iounmap(struct pci_dev *
 #include <asm/mpc8260_pci9.h>
 #endif
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ipc.h b/include/asm-ppc/ipc.h
--- a/include/asm-ppc/ipc.h
+++ b/include/asm-ppc/ipc.h
@@ -1,29 +1 @@
-#ifndef __PPC_IPC_H__
-#define __PPC_IPC_H__
-
-/*
- * These are used to wrap system calls on PowerPC.
- *
- * See arch/ppc/kernel/syscalls.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#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 IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif /* __PPC_IPC_H__ */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-ppc/ipic.h b/include/asm-ppc/ipic.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc/ipic.h
@@ -0,0 +1,85 @@
+/*
+ * include/asm-ppc/ipic.h
+ *
+ * IPIC external definitions and structure.
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_IPIC_H__
+#define __ASM_IPIC_H__
+
+#include <linux/irq.h>
+
+/* Flags when we init the IPIC */
+#define IPIC_SPREADMODE_GRP_A	0x00000001
+#define IPIC_SPREADMODE_GRP_D	0x00000002
+#define IPIC_SPREADMODE_MIX_A	0x00000004
+#define IPIC_SPREADMODE_MIX_B	0x00000008
+#define IPIC_DISABLE_MCP_OUT	0x00000010
+#define IPIC_IRQ0_MCP		0x00000020
+
+/* IPIC registers offsets */
+#define IPIC_SICFR	0x00	/* System Global Interrupt Configuration Register */
+#define IPIC_SIVCR	0x04	/* System Global Interrupt Vector Register */
+#define IPIC_SIPNR_H	0x08	/* System Internal Interrupt Pending Register (HIGH) */
+#define IPIC_SIPNR_L	0x0C	/* System Internal Interrupt Pending Register (LOW) */
+#define IPIC_SIPRR_A	0x10	/* System Internal Interrupt group A Priority Register */
+#define IPIC_SIPRR_B	0x14	/* System Internal Interrupt group B Priority Register */
+#define IPIC_SIPRR_C	0x18	/* System Internal Interrupt group C Priority Register */
+#define IPIC_SIPRR_D	0x1C	/* System Internal Interrupt group D Priority Register */
+#define IPIC_SIMSR_H	0x20	/* System Internal Interrupt Mask Register (HIGH) */
+#define IPIC_SIMSR_L	0x24	/* System Internal Interrupt Mask Register (LOW) */
+#define IPIC_SICNR	0x28	/* System Internal Interrupt Control Register */
+#define IPIC_SEPNR	0x2C	/* System External Interrupt Pending Register */
+#define IPIC_SMPRR_A	0x30	/* System Mixed Interrupt group A Priority Register */
+#define IPIC_SMPRR_B	0x34	/* System Mixed Interrupt group B Priority Register */
+#define IPIC_SEMSR	0x38	/* System External Interrupt Mask Register */
+#define IPIC_SECNR	0x3C	/* System External Interrupt Control Register */
+#define IPIC_SERSR	0x40	/* System Error Status Register */
+#define IPIC_SERMR	0x44	/* System Error Mask Register */
+#define IPIC_SERCR	0x48	/* System Error Control Register */
+#define IPIC_SIFCR_H	0x50	/* System Internal Interrupt Force Register (HIGH) */
+#define IPIC_SIFCR_L	0x54	/* System Internal Interrupt Force Register (LOW) */
+#define IPIC_SEFCR	0x58	/* System External Interrupt Force Register */
+#define IPIC_SERFR	0x5C	/* System Error Force Register */
+#define IPIC_SCVCR	0x60	/* System Critical Interrupt Vector Register */
+#define IPIC_SMVCR	0x64	/* System Management Interrupt Vector Register */
+
+enum ipic_prio_grp {
+	IPIC_INT_GRP_A = IPIC_SIPRR_A,
+	IPIC_INT_GRP_D = IPIC_SIPRR_D,
+	IPIC_MIX_GRP_A = IPIC_SMPRR_A,
+	IPIC_MIX_GRP_B = IPIC_SMPRR_B,
+};
+
+enum ipic_mcp_irq {
+	IPIC_MCP_IRQ0 = 0,
+	IPIC_MCP_WDT  = 1,
+	IPIC_MCP_SBA  = 2,
+	IPIC_MCP_PCI1 = 5,
+	IPIC_MCP_PCI2 = 6,
+	IPIC_MCP_MU   = 7,
+};
+
+extern void ipic_init(phys_addr_t phys_addr, unsigned int flags,
+		unsigned int irq_offset,
+		unsigned char *senses, unsigned int senses_count);
+extern int ipic_set_priority(unsigned int irq, unsigned int priority);
+extern void ipic_set_highest_priority(unsigned int irq);
+extern void ipic_set_default_priority(void);
+extern void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq);
+extern void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq);
+extern u32 ipic_get_mcp_status(void);
+extern void ipic_clear_mcp_status(u32 mask);
+extern int ipic_get_irq(struct pt_regs *regs);
+
+#endif /* __ASM_IPIC_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
--- a/include/asm-ppc/irq.h
+++ b/include/asm-ppc/irq.h
@@ -161,7 +161,17 @@ static __inline__ int irq_canonicalize(i
 	return irq;
 }
 
-#elif defined(CONFIG_CPM2) && defined(CONFIG_85xx)
+#elif defined(CONFIG_83xx)
+#include <asm/mpc83xx.h>
+
+static __inline__ int irq_canonicalize(int irq)
+{
+	return irq;
+}
+
+#define	NR_IRQS	(NR_IPIC_INTS)
+
+#elif defined(CONFIG_85xx)
 /* Now include the board configuration specific associations.
 */
 #include <asm/mpc85xx.h>
@@ -176,7 +186,7 @@ static __inline__ int irq_canonicalize(i
 #define NR_CPM_INTS	64
 #define NR_EPIC_INTS	44
 #ifndef NR_8259_INTS
-#define NR_8259_INTS 0
+#define NR_8259_INTS	0
 #endif
 #define NUM_8259_INTERRUPTS NR_8259_INTS
 
@@ -186,13 +196,59 @@ static __inline__ int irq_canonicalize(i
 
 #define NR_IRQS	(NR_EPIC_INTS + NR_CPM_INTS + NR_8259_INTS)
 
-/* These values must be zero-based and map 1:1 with the EPIC configuration.
- * They are used throughout the 8560 I/O subsystem to generate
- * interrupt masks, flags, and other control patterns.  This is why the
- * current kernel assumption of the 8259 as the base controller is such
- * a pain in the butt.
- */
+/* Internal IRQs on MPC85xx OpenPIC */
+
+#ifndef MPC85xx_OPENPIC_IRQ_OFFSET
+#ifdef CONFIG_CPM2
+#define MPC85xx_OPENPIC_IRQ_OFFSET	(CPM_IRQ_OFFSET + NR_CPM_INTS)
+#else
+#define MPC85xx_OPENPIC_IRQ_OFFSET	0
+#endif
+#endif
+
+/* Not all of these exist on all MPC85xx implementations */
+#define MPC85xx_IRQ_L2CACHE	( 0 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_ECM		( 1 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DDR		( 2 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_LBIU	( 3 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA0	( 4 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA1	( 5 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA2	( 6 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA3	( 7 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI1	( 8 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI2	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_ERROR	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_BELL	(10 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_TX	(11 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_RX	(12 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_TX	(13 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_RX	(14 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_ERROR	(18 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_TX	(19 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_RX	(20 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_ERROR	(24 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_FEC		(25 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DUART	(26 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_IIC1	(27 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PERFMON	(28 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_SEC2	(29 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_CPM		(30 + MPC85xx_OPENPIC_IRQ_OFFSET)
+
+/* The 12 external interrupt lines */
+#define MPC85xx_IRQ_EXT0        (32 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT1        (33 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT2        (34 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT3        (35 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT4        (36 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT5        (37 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT6        (38 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT7        (39 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT8        (40 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT9        (41 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT10       (42 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT11       (43 + MPC85xx_OPENPIC_IRQ_OFFSET)
 
+/* CPM related interrupts */
 #define	SIU_INT_ERROR		((uint)0x00+CPM_IRQ_OFFSET)
 #define	SIU_INT_I2C		((uint)0x01+CPM_IRQ_OFFSET)
 #define	SIU_INT_SPI		((uint)0x02+CPM_IRQ_OFFSET)
@@ -257,57 +313,62 @@ static __inline__ int irq_canonicalize(i
  * (Document errata updates have fixed this...make sure you have up to
  * date processor documentation -- Dan).
  */
-#define NR_SIU_INTS	64
 
-#define	SIU_INT_ERROR		((uint)0x00)
-#define	SIU_INT_I2C		((uint)0x01)
-#define	SIU_INT_SPI		((uint)0x02)
-#define	SIU_INT_RISC		((uint)0x03)
-#define	SIU_INT_SMC1		((uint)0x04)
-#define	SIU_INT_SMC2		((uint)0x05)
-#define	SIU_INT_IDMA1		((uint)0x06)
-#define	SIU_INT_IDMA2		((uint)0x07)
-#define	SIU_INT_IDMA3		((uint)0x08)
-#define	SIU_INT_IDMA4		((uint)0x09)
-#define	SIU_INT_SDMA		((uint)0x0a)
-#define	SIU_INT_TIMER1		((uint)0x0c)
-#define	SIU_INT_TIMER2		((uint)0x0d)
-#define	SIU_INT_TIMER3		((uint)0x0e)
-#define	SIU_INT_TIMER4		((uint)0x0f)
-#define	SIU_INT_TMCNT		((uint)0x10)
-#define	SIU_INT_PIT		((uint)0x11)
-#define	SIU_INT_IRQ1		((uint)0x13)
-#define	SIU_INT_IRQ2		((uint)0x14)
-#define	SIU_INT_IRQ3		((uint)0x15)
-#define	SIU_INT_IRQ4		((uint)0x16)
-#define	SIU_INT_IRQ5		((uint)0x17)
-#define	SIU_INT_IRQ6		((uint)0x18)
-#define	SIU_INT_IRQ7		((uint)0x19)
-#define	SIU_INT_FCC1		((uint)0x20)
-#define	SIU_INT_FCC2		((uint)0x21)
-#define	SIU_INT_FCC3		((uint)0x22)
-#define	SIU_INT_MCC1		((uint)0x24)
-#define	SIU_INT_MCC2		((uint)0x25)
-#define	SIU_INT_SCC1		((uint)0x28)
-#define	SIU_INT_SCC2		((uint)0x29)
-#define	SIU_INT_SCC3		((uint)0x2a)
-#define	SIU_INT_SCC4		((uint)0x2b)
-#define	SIU_INT_PC15		((uint)0x30)
-#define	SIU_INT_PC14		((uint)0x31)
-#define	SIU_INT_PC13		((uint)0x32)
-#define	SIU_INT_PC12		((uint)0x33)
-#define	SIU_INT_PC11		((uint)0x34)
-#define	SIU_INT_PC10		((uint)0x35)
-#define	SIU_INT_PC9		((uint)0x36)
-#define	SIU_INT_PC8		((uint)0x37)
-#define	SIU_INT_PC7		((uint)0x38)
-#define	SIU_INT_PC6		((uint)0x39)
-#define	SIU_INT_PC5		((uint)0x3a)
-#define	SIU_INT_PC4		((uint)0x3b)
-#define	SIU_INT_PC3		((uint)0x3c)
-#define	SIU_INT_PC2		((uint)0x3d)
-#define	SIU_INT_PC1		((uint)0x3e)
-#define	SIU_INT_PC0		((uint)0x3f)
+#ifndef CPM_IRQ_OFFSET
+#define CPM_IRQ_OFFSET	0
+#endif
+
+#define NR_CPM_INTS	64
+
+#define	SIU_INT_ERROR		((uint)0x00 + CPM_IRQ_OFFSET)
+#define	SIU_INT_I2C		((uint)0x01 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SPI		((uint)0x02 + CPM_IRQ_OFFSET)
+#define	SIU_INT_RISC		((uint)0x03 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SMC1		((uint)0x04 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SMC2		((uint)0x05 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA1		((uint)0x06 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA2		((uint)0x07 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA3		((uint)0x08 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA4		((uint)0x09 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SDMA		((uint)0x0a + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER1		((uint)0x0c + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER2		((uint)0x0d + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER3		((uint)0x0e + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER4		((uint)0x0f + CPM_IRQ_OFFSET)
+#define	SIU_INT_TMCNT		((uint)0x10 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PIT		((uint)0x11 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ1		((uint)0x13 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ2		((uint)0x14 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ3		((uint)0x15 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ4		((uint)0x16 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ5		((uint)0x17 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ6		((uint)0x18 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ7		((uint)0x19 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC1		((uint)0x20 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC2		((uint)0x21 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC3		((uint)0x22 + CPM_IRQ_OFFSET)
+#define	SIU_INT_MCC1		((uint)0x24 + CPM_IRQ_OFFSET)
+#define	SIU_INT_MCC2		((uint)0x25 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC1		((uint)0x28 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC2		((uint)0x29 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC3		((uint)0x2a + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC4		((uint)0x2b + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC15		((uint)0x30 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC14		((uint)0x31 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC13		((uint)0x32 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC12		((uint)0x33 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC11		((uint)0x34 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC10		((uint)0x35 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC9		((uint)0x36 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC8		((uint)0x37 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC7		((uint)0x38 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC6		((uint)0x39 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC5		((uint)0x3a + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC4		((uint)0x3b + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC3		((uint)0x3c + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC2		((uint)0x3d + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC1		((uint)0x3e + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC0		((uint)0x3f + CPM_IRQ_OFFSET)
 
 #endif /* CONFIG_8260 */
 
diff --git a/include/asm-ppc/keylargo.h b/include/asm-ppc/keylargo.h
--- a/include/asm-ppc/keylargo.h
+++ b/include/asm-ppc/keylargo.h
@@ -228,6 +228,11 @@
 
 #define K2_FCR1_PCI1_BUS_RESET_N	0x00000010
 #define K2_FCR1_PCI1_SLEEP_RESET_EN	0x00000020
+#define K2_FCR1_I2S0_CELL_ENABLE	0x00000400
+#define K2_FCR1_I2S0_RESET		0x00000800
+#define K2_FCR1_I2S0_CLK_ENABLE_BIT	0x00001000
+#define K2_FCR1_I2S0_ENABLE    		0x00002000
+
 #define K2_FCR1_PCI1_CLK_ENABLE		0x00004000
 #define K2_FCR1_FW_CLK_ENABLE		0x00008000
 #define K2_FCR1_FW_RESET_N		0x00010000
diff --git a/include/asm-ppc/m8260_pci.h b/include/asm-ppc/m8260_pci.h
--- a/include/asm-ppc/m8260_pci.h
+++ b/include/asm-ppc/m8260_pci.h
@@ -19,6 +19,7 @@
  * Define the vendor/device ID for the MPC8265.
  */
 #define	PCI_DEVICE_ID_MPC8265	((0x18C0 << 16) | PCI_VENDOR_ID_MOTOROLA)
+#define	PCI_DEVICE_ID_MPC8272	((0x18C1 << 16) | PCI_VENDOR_ID_MOTOROLA)
 
 #define M8265_PCIBR0	0x101ac
 #define M8265_PCIBR1	0x101b0
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 
 #include <asm/setup.h>
+#include <asm/page.h>
 
 #ifdef CONFIG_APUS
 #include <asm-m68k/machdep.h>
@@ -15,6 +16,7 @@ struct pt_regs;
 struct pci_bus;	
 struct pci_dev;
 struct seq_file;
+struct file;
 
 /* We export this macro for external modules like Alsa to know if
  * ppc_md.feature_call is implemented or not
@@ -93,6 +95,12 @@ struct machdep_calls {
 	/* Called at then very end of pcibios_init() */
 	void (*pcibios_after_init)(void);
 
+	/* Get access protection for /dev/mem */
+	pgprot_t	(*phys_mem_access_prot)(struct file *file,
+						unsigned long offset,
+						unsigned long size,
+						pgprot_t vma_prot);
+
 	/* this is for modules, since _machine can be a define -- Cort */
 	int ppc_machine;
 
@@ -121,6 +129,7 @@ typedef enum sys_ctrler_kind {
 	SYS_CTRLER_UNKNOWN = 0,
 	SYS_CTRLER_CUDA = 1,
 	SYS_CTRLER_PMU = 2,
+	SYS_CTRLER_SMU = 3,
 } sys_ctrler_t;
 
 extern sys_ctrler_t sys_ctrler;
diff --git a/include/asm-ppc/macio.h b/include/asm-ppc/macio.h
--- a/include/asm-ppc/macio.h
+++ b/include/asm-ppc/macio.h
@@ -126,7 +126,7 @@ struct macio_driver
 	int	(*probe)(struct macio_dev* dev, const struct of_match *match);
 	int	(*remove)(struct macio_dev* dev);
 
-	int	(*suspend)(struct macio_dev* dev, u32 state);
+	int	(*suspend)(struct macio_dev* dev, pm_message_t state);
 	int	(*resume)(struct macio_dev* dev);
 	int	(*shutdown)(struct macio_dev* dev);
 
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -15,11 +15,13 @@
  * virtual/physical addressing like 32-bit virtual / 36-bit
  * physical need a larger than native word size type. -Matt
  */
-#ifndef CONFIG_PTE_64BIT
+#ifndef CONFIG_PHYS_64BIT
 typedef unsigned long phys_addr_t;
+#define PHYS_FMT	"%.8lx"
 #else
 typedef unsigned long long phys_addr_t;
 extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
+#define PHYS_FMT	"%16Lx"
 #endif
 
 /* Default "unsigned long" context */
@@ -152,7 +154,7 @@ typedef struct _P601_BAT {
  * is written, and the contents of several registers are used to
  * create the entry.
  */
-#define MI_CTR		784	/* Instruction TLB control register */
+#define SPRN_MI_CTR	784	/* Instruction TLB control register */
 #define MI_GPM		0x80000000	/* Set domain manager mode */
 #define MI_PPM		0x40000000	/* Set subpage protection */
 #define MI_CIDEF	0x20000000	/* Set cache inhibit when MMU dis */
@@ -164,7 +166,7 @@ typedef struct _P601_BAT {
 /* These are the Ks and Kp from the PowerPC books.  For proper operation,
  * Ks = 0, Kp = 1.
  */
-#define MI_AP		786
+#define SPRN_MI_AP	786
 #define MI_Ks		0x80000000	/* Should not be set */
 #define MI_Kp		0x40000000	/* Should always be set */
 
@@ -172,7 +174,7 @@ typedef struct _P601_BAT {
  * about the last instruction TLB miss.  When MI_RPN is written, bits in
  * this register are used to create the TLB entry.
  */
-#define MI_EPN		787
+#define SPRN_MI_EPN	787
 #define MI_EPNMASK	0xfffff000	/* Effective page number for entry */
 #define MI_EVALID	0x00000200	/* Entry is valid */
 #define MI_ASIDMASK	0x0000000f	/* ASID match value */
@@ -182,7 +184,7 @@ typedef struct _P601_BAT {
  * For the instruction TLB, it contains bits that get loaded into the
  * TLB entry when the MI_RPN is written.
  */
-#define MI_TWC		789
+#define SPRN_MI_TWC	789
 #define MI_APG		0x000001e0	/* Access protection group (0) */
 #define MI_GUARDED	0x00000010	/* Guarded storage */
 #define MI_PSMASK	0x0000000c	/* Mask of page size bits */
@@ -196,7 +198,7 @@ typedef struct _P601_BAT {
  * causes a TLB entry to be created for the instruction TLB, using
  * additional information from the MI_EPN, and MI_TWC registers.
  */
-#define MI_RPN		790
+#define SPRN_MI_RPN	790
 
 /* Define an RPN value for mapping kernel memory to large virtual
  * pages for boot initialization.  This has real page number of 0,
@@ -205,7 +207,7 @@ typedef struct _P601_BAT {
  */
 #define MI_BOOTINIT	0x000001fd
 
-#define MD_CTR		792	/* Data TLB control register */
+#define SPRN_MD_CTR	792	/* Data TLB control register */
 #define MD_GPM		0x80000000	/* Set domain manager mode */
 #define MD_PPM		0x40000000	/* Set subpage protection */
 #define MD_CIDEF	0x20000000	/* Set cache inhibit when MMU dis */
@@ -216,14 +218,14 @@ typedef struct _P601_BAT {
 #define MD_IDXMASK	0x00001f00	/* TLB index to be loaded */
 #define MD_RESETVAL	0x04000000	/* Value of register at reset */
 
-#define M_CASID		793	/* Address space ID (context) to match */
+#define SPRN_M_CASID	793	/* Address space ID (context) to match */
 #define MC_ASIDMASK	0x0000000f	/* Bits used for ASID value */
 
 
 /* These are the Ks and Kp from the PowerPC books.  For proper operation,
  * Ks = 0, Kp = 1.
  */
-#define MD_AP		794
+#define SPRN_MD_AP	794
 #define MD_Ks		0x80000000	/* Should not be set */
 #define MD_Kp		0x40000000	/* Should always be set */
 
@@ -231,7 +233,7 @@ typedef struct _P601_BAT {
  * about the last instruction TLB miss.  When MD_RPN is written, bits in
  * this register are used to create the TLB entry.
  */
-#define MD_EPN		795
+#define SPRN_MD_EPN	795
 #define MD_EPNMASK	0xfffff000	/* Effective page number for entry */
 #define MD_EVALID	0x00000200	/* Entry is valid */
 #define MD_ASIDMASK	0x0000000f	/* ASID match value */
@@ -241,7 +243,7 @@ typedef struct _P601_BAT {
  * During a software tablewalk, reading this register provides the address
  * of the entry associated with MD_EPN.
  */
-#define M_TWB		796
+#define SPRN_M_TWB	796
 #define	M_L1TB		0xfffff000	/* Level 1 table base address */
 #define M_L1INDX	0x00000ffc	/* Level 1 index, when read */
 					/* Reset value is undefined */
@@ -251,7 +253,7 @@ typedef struct _P601_BAT {
  * when the MD_RPN is written.  It is also provides the hardware assist
  * for finding the PTE address during software tablewalk.
  */
-#define MD_TWC		797
+#define SPRN_MD_TWC	797
 #define MD_L2TB		0xfffff000	/* Level 2 table base address */
 #define MD_L2INDX	0xfffffe00	/* Level 2 index (*pte), when read */
 #define MD_APG		0x000001e0	/* Access protection group (0) */
@@ -269,12 +271,12 @@ typedef struct _P601_BAT {
  * causes a TLB entry to be created for the data TLB, using
  * additional information from the MD_EPN, and MD_TWC registers.
  */
-#define MD_RPN		798
+#define SPRN_MD_RPN	798
 
 /* This is a temporary storage register that could be used to save
  * a processor working register during a tablewalk.
  */
-#define M_TW		799
+#define SPRN_M_TW	799
 
 /*
  * At present, all PowerPC 400-class processors share a similar TLB
diff --git a/include/asm-ppc/mpc10x.h b/include/asm-ppc/mpc10x.h
--- a/include/asm-ppc/mpc10x.h
+++ b/include/asm-ppc/mpc10x.h
@@ -115,8 +115,8 @@
 #define	MPC10X_CFG_MAPB_OPTIONS_CFAE	0x80	/* CPU_FD_ALIAS_EN */
 #define	MPC10X_CFG_MAPB_OPTIONS_PFAE	0x40	/* PCI_FD_ALIAS_EN */
 #define	MPC10X_CFG_MAPB_OPTIONS_DR	0x20	/* DLL_RESET */
-#define	MPC10X_CFG_MAPB_OPTIONS_PCICH	0x80	/* PCI_COMPATIBILITY_HOLE */
-#define	MPC10X_CFG_MAPB_OPTIONS_PROCCH	0x40	/* PROC_COMPATIBILITY_HOLE */
+#define	MPC10X_CFG_MAPB_OPTIONS_PCICH	0x08	/* PCI_COMPATIBILITY_HOLE */
+#define	MPC10X_CFG_MAPB_OPTIONS_PROCCH	0x04	/* PROC_COMPATIBILITY_HOLE */
 
 /* Define offsets for the memory controller registers in the config space */
 #define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
--- a/include/asm-ppc/mpc52xx.h
+++ b/include/asm-ppc/mpc52xx.h
@@ -10,7 +10,7 @@
  * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> 
  * for the 2.4 kernel.
  *
- * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
  * Copyright (C) 2003 MontaVista, Software, Inc.
  *
  * This file is licensed under the terms of the GNU General Public License
@@ -26,53 +26,73 @@
 #include <asm/types.h>
 
 struct pt_regs;
-struct ocp_def;
 #endif /* __ASSEMBLY__ */
 
 
 /* ======================================================================== */
+/* PPC Sys devices definition                                               */
+/* ======================================================================== */
+
+enum ppc_sys_devices {
+	MPC52xx_MSCAN1,
+	MPC52xx_MSCAN2,
+	MPC52xx_SPI,
+	MPC52xx_USB,
+	MPC52xx_BDLC,
+	MPC52xx_PSC1,
+	MPC52xx_PSC2,
+	MPC52xx_PSC3,
+	MPC52xx_PSC4,
+	MPC52xx_PSC5,
+	MPC52xx_PSC6,
+	MPC52xx_FEC,
+	MPC52xx_ATA,
+	MPC52xx_I2C1,
+	MPC52xx_I2C2,
+};
+
+
+/* ======================================================================== */
 /* Main registers/struct addresses                                          */
 /* ======================================================================== */
-/* Theses are PHYSICAL addresses !                                          */
-/* TODO : There should be no static mapping, but it's not yet the case, so  */
-/*        we require a 1:1 mapping                                          */
 
+/* MBAR position */
 #define MPC52xx_MBAR		0xf0000000	/* Phys address */
-#define MPC52xx_MBAR_SIZE	0x00010000
 #define MPC52xx_MBAR_VIRT	0xf0000000	/* Virt address */
+#define MPC52xx_MBAR_SIZE	0x00010000
+
+#define MPC52xx_PA(x)		((phys_addr_t)(MPC52xx_MBAR + (x)))
+#define MPC52xx_VA(x)		((void __iomem *)(MPC52xx_MBAR_VIRT + (x)))
 
-#define MPC52xx_MMAP_CTL	(MPC52xx_MBAR + 0x0000)
-#define MPC52xx_SDRAM		(MPC52xx_MBAR + 0x0100)
-#define MPC52xx_CDM		(MPC52xx_MBAR + 0x0200)
-#define MPC52xx_SFTRST		(MPC52xx_MBAR + 0x0220)
-#define MPC52xx_SFTRST_BIT	0x01000000
-#define MPC52xx_INTR		(MPC52xx_MBAR + 0x0500)
-#define MPC52xx_GPTx(x)		(MPC52xx_MBAR + 0x0600 + ((x)<<4))
-#define MPC52xx_RTC		(MPC52xx_MBAR + 0x0800)
-#define MPC52xx_MSCAN1		(MPC52xx_MBAR + 0x0900)
-#define MPC52xx_MSCAN2		(MPC52xx_MBAR + 0x0980)
-#define MPC52xx_GPIO		(MPC52xx_MBAR + 0x0b00)
-#define MPC52xx_GPIO_WKUP	(MPC52xx_MBAR + 0x0c00)
-#define MPC52xx_PCI		(MPC52xx_MBAR + 0x0d00)
-#define MPC52xx_USB_OHCI	(MPC52xx_MBAR + 0x1000)
-#define MPC52xx_SDMA		(MPC52xx_MBAR + 0x1200)
-#define MPC52xx_XLB		(MPC52xx_MBAR + 0x1f00)
-#define MPC52xx_PSCx(x)		(MPC52xx_MBAR + 0x2000 + ((x)<<9))
-#define MPC52xx_PSC1		(MPC52xx_MBAR + 0x2000)
-#define MPC52xx_PSC2		(MPC52xx_MBAR + 0x2200)
-#define MPC52xx_PSC3		(MPC52xx_MBAR + 0x2400)
-#define MPC52xx_PSC4		(MPC52xx_MBAR + 0x2600)
-#define MPC52xx_PSC5		(MPC52xx_MBAR + 0x2800)
-#define MPC52xx_PSC6		(MPC52xx_MBAR + 0x2C00)
-#define MPC52xx_FEC		(MPC52xx_MBAR + 0x3000)
-#define MPC52xx_ATA		(MPC52xx_MBAR + 0x3a00)
-#define MPC52xx_I2C1		(MPC52xx_MBAR + 0x3d00)
-#define MPC52xx_I2C_MICR	(MPC52xx_MBAR + 0x3d20)
-#define MPC52xx_I2C2		(MPC52xx_MBAR + 0x3d40)
+/* Registers zone offset/size  */
+#define MPC52xx_MMAP_CTL_OFFSET		0x0000
+#define MPC52xx_MMAP_CTL_SIZE		0x068
+#define MPC52xx_SDRAM_OFFSET		0x0100
+#define MPC52xx_SDRAM_SIZE		0x010
+#define MPC52xx_CDM_OFFSET		0x0200
+#define MPC52xx_CDM_SIZE		0x038
+#define MPC52xx_INTR_OFFSET		0x0500
+#define MPC52xx_INTR_SIZE		0x04c
+#define MPC52xx_GPTx_OFFSET(x)		(0x0600 + ((x)<<4))
+#define MPC52xx_GPT_SIZE		0x010
+#define MPC52xx_RTC_OFFSET		0x0800
+#define MPC52xx_RTC_SIZE		0x024
+#define MPC52xx_GPIO_OFFSET		0x0b00
+#define MPC52xx_GPIO_SIZE		0x040
+#define MPC52xx_GPIO_WKUP_OFFSET	0x0c00
+#define MPC52xx_GPIO_WKUP_SIZE		0x028
+#define MPC52xx_PCI_OFFSET		0x0d00
+#define MPC52xx_PCI_SIZE		0x100
+#define MPC52xx_SDMA_OFFSET		0x1200
+#define MPC52xx_SDMA_SIZE		0x100
+#define MPC52xx_XLB_OFFSET		0x1f00
+#define MPC52xx_XLB_SIZE		0x100
+#define MPC52xx_PSCx_OFFSET(x)		(((x)!=6)?(0x1e00+((x)<<9)):0x2c00)
+#define MPC52xx_PSC_SIZE		0x0a0
 
 /* SRAM used for SDMA */
-#define MPC52xx_SRAM		(MPC52xx_MBAR + 0x8000)
-#define MPC52xx_SRAM_SIZE	(16*1024)
+#define MPC52xx_SRAM_OFFSET		0x8000
+#define MPC52xx_SRAM_SIZE		0x4000
 
 
 /* ======================================================================== */
@@ -119,11 +139,12 @@ struct ocp_def;
 #define MPC52xx_SPI_SPIF_IRQ		(MPC52xx_PERP_IRQ_BASE + 14)
 #define MPC52xx_I2C1_IRQ		(MPC52xx_PERP_IRQ_BASE + 15)
 #define MPC52xx_I2C2_IRQ		(MPC52xx_PERP_IRQ_BASE + 16)
-#define MPC52xx_CAN1_IRQ		(MPC52xx_PERP_IRQ_BASE + 17)
-#define MPC52xx_CAN2_IRQ		(MPC52xx_PERP_IRQ_BASE + 18)
+#define MPC52xx_MSCAN1_IRQ		(MPC52xx_PERP_IRQ_BASE + 17)
+#define MPC52xx_MSCAN2_IRQ		(MPC52xx_PERP_IRQ_BASE + 18)
 #define MPC52xx_IR_RX_IRQ		(MPC52xx_PERP_IRQ_BASE + 19)
 #define MPC52xx_IR_TX_IRQ		(MPC52xx_PERP_IRQ_BASE + 20)
 #define MPC52xx_XLB_ARB_IRQ		(MPC52xx_PERP_IRQ_BASE + 21)
+#define MPC52xx_BDLC_IRQ		(MPC52xx_PERP_IRQ_BASE + 22)
 
 
 
@@ -163,7 +184,7 @@ struct mpc52xx_mmap_ctl {
 	u32	cs6_start;	/* MMAP_CTRL + 0x58 */
 	u32	cs6_stop;	/* MMAP_CTRL + 0x5c */
 	u32	cs7_start;	/* MMAP_CTRL + 0x60 */
-	u32	cs7_stop;	/* MMAP_CTRL + 0x60 */
+	u32	cs7_stop;	/* MMAP_CTRL + 0x64 */
 };
 
 /* SDRAM control */
@@ -209,7 +230,7 @@ struct mpc52xx_sdma {
 
 	u16	tcr[16];	/* SDMA + 0x1c .. 0x3a */
 
-	u8	ipr[32];	/* SDMA + 0x3c .. 5b */
+	u8	ipr[32];	/* SDMA + 0x3c .. 0x5b */
 
 	u32	cReqSelect;	/* SDMA + 0x5c */
 	u32	task_size0;	/* SDMA + 0x60 */
@@ -391,7 +412,19 @@ extern void mpc52xx_halt(void);
 extern void mpc52xx_power_off(void);
 extern void mpc52xx_progress(char *s, unsigned short hex);
 extern void mpc52xx_calibrate_decr(void);
-extern void mpc52xx_add_board_devices(struct ocp_def board_ocp[]);
+
+extern void mpc52xx_find_bridges(void);
+
+
+	/* Matching of PSC function */
+struct mpc52xx_psc_func {
+	int id;
+	char *func;
+};
+
+extern int mpc52xx_match_psc_function(int psc_idx, const char *func);
+extern struct  mpc52xx_psc_func mpc52xx_psc_functions[];
+	/* This array is to be defined in platform file */
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -41,7 +41,7 @@
 #endif
 
 #ifdef CONFIG_PCI_8260
-#include <syslib/m8260_pci.h>
+#include <syslib/m82xx_pci.h>
 #endif
 
 /* Make sure the memory translation stuff is there if PCI not used.
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc/mpc83xx.h
@@ -0,0 +1,114 @@
+/*
+ * include/asm-ppc/mpc83xx.h
+ *
+ * MPC83xx definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC83xx_H__
+#define __ASM_MPC83xx_H__
+
+#include <linux/config.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_83xx
+
+#ifdef CONFIG_MPC834x_SYS
+#include <platforms/83xx/mpc834x_sys.h>
+#endif
+
+#define _IO_BASE        isa_io_base
+#define _ISA_MEM_BASE   isa_mem_base
+#ifdef CONFIG_PCI
+#define PCI_DRAM_OFFSET pci_dram_offset
+#else
+#define PCI_DRAM_OFFSET 0
+#endif
+
+/*
+ * The "residual" board information structure the boot loader passes
+ * into the kernel.
+ */
+extern unsigned char __res[];
+
+/* Internal IRQs on MPC83xx OpenPIC */
+/* Not all of these exist on all MPC83xx implementations */
+
+#ifndef MPC83xx_IPIC_IRQ_OFFSET
+#define MPC83xx_IPIC_IRQ_OFFSET	0
+#endif
+
+#define NR_IPIC_INTS 128
+
+#define MPC83xx_IRQ_UART1	( 9 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_UART2	(10 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_SEC2	(11 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_IIC1	(14 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_IIC2	(15 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_SPI		(16 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT1	(17 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT2	(18 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT3	(19 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT4	(20 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT5	(21 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT6	(22 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT7	(23 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC1_TX	(32 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC1_RX	(33 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC1_ERROR	(34 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC2_TX	(35 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC2_RX	(36 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_TSEC2_ERROR	(37 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_USB2_DR	(38 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_USB2_MPH	(39 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_EXT0	(48 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_RTC_SEC	(64 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_PIT		(65 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_PCI1	(66 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_PCI2	(67 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_RTC_ALR	(68 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_MU		(69 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_SBA		(70 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_DMA		(71 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM4	(72 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM8	(73 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GPIO1	(74 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GPIO2	(75 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_DDR		(76 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_LBC		(77 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM2	(78 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM6	(79 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_PMC		(80 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM3	(84 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM7	(85 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM1	(90 + MPC83xx_IPIC_IRQ_OFFSET)
+#define MPC83xx_IRQ_GTM5	(91 + MPC83xx_IPIC_IRQ_OFFSET)
+
+#define MPC83xx_CCSRBAR_SIZE	(1024*1024)
+
+/* Let modules/drivers get at immrbar (physical) */
+extern phys_addr_t immrbar;
+
+enum ppc_sys_devices {
+	MPC83xx_TSEC1,
+	MPC83xx_TSEC2,
+	MPC83xx_IIC1,
+	MPC83xx_IIC2,
+	MPC83xx_DUART,
+	MPC83xx_SEC2,
+	MPC83xx_USB2_DR,
+	MPC83xx_USB2_MPH,
+};
+
+#endif /* CONFIG_83xx */
+#endif /* __ASM_MPC83xx_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -52,55 +52,6 @@
  */
 extern unsigned char __res[];
 
-/* Internal IRQs on MPC85xx OpenPIC */
-/* Not all of these exist on all MPC85xx implementations */
-
-#ifndef MPC85xx_OPENPIC_IRQ_OFFSET
-#define MPC85xx_OPENPIC_IRQ_OFFSET	64
-#endif
-
-/* The 32 internal sources */
-#define MPC85xx_IRQ_L2CACHE	( 0 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_ECM		( 1 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DDR		( 2 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_LBIU	( 3 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DMA0	( 4 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DMA1	( 5 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DMA2	( 6 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DMA3	( 7 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_PCI1	( 8 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_PCI2	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_RIO_ERROR	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_RIO_BELL	(10 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_RIO_TX	(11 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_RIO_RX	(12 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC1_TX	(13 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC1_RX	(14 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC1_ERROR	(18 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC2_TX	(19 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC2_RX	(20 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_TSEC2_ERROR	(24 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_FEC		(25 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_DUART	(26 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_IIC1	(27 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_PERFMON	(28 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_SEC2	(29 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_CPM		(30 + MPC85xx_OPENPIC_IRQ_OFFSET)
-
-/* The 12 external interrupt lines */
-#define MPC85xx_IRQ_EXT0        (32 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT1        (33 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT2        (34 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT3        (35 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT4        (36 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT5        (37 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT6        (38 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT7        (39 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT8        (40 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT9        (41 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT10       (42 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT11       (43 + MPC85xx_OPENPIC_IRQ_OFFSET)
-
 /* Offset from CCSRBAR */
 #define MPC85xx_CPM_OFFSET	(0x80000)
 #define MPC85xx_CPM_SIZE	(0x40000)
diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h
--- a/include/asm-ppc/mv64x60_defs.h
+++ b/include/asm-ppc/mv64x60_defs.h
@@ -36,6 +36,8 @@
 #define GT64260_WINDOW_SIZE_MIN			0x00100000
 #define MV64360_WINDOW_SIZE_MIN			0x00010000
 
+#define	MV64x60_TCLK_FREQ_MAX			133333333U
+
 /* IRQ's for embedded controllers */
 #define	MV64x60_IRQ_DEV				1
 #define	MV64x60_IRQ_CPU_ERR			3
@@ -43,6 +45,11 @@
 #define	MV64x60_IRQ_TIMER_2_3			9
 #define	MV64x60_IRQ_TIMER_4_5			10
 #define	MV64x60_IRQ_TIMER_6_7			11
+#define	MV64x60_IRQ_P1_GPP_0_7			24
+#define	MV64x60_IRQ_P1_GPP_8_15			25
+#define	MV64x60_IRQ_P1_GPP_16_23		26
+#define	MV64x60_IRQ_P1_GPP_24_31		27
+#define	MV64x60_IRQ_DOORBELL			28
 #define	MV64x60_IRQ_ETH_0			32
 #define	MV64x60_IRQ_ETH_1			33
 #define	MV64x60_IRQ_ETH_2			34
@@ -52,12 +59,49 @@
 #define	MV64x60_IRQ_MPSC_0			40
 #define	MV64x60_IRQ_MPSC_1			42
 #define	MV64x60_IRQ_COMM			43
+#define	MV64x60_IRQ_P0_GPP_0_7			56
+#define	MV64x60_IRQ_P0_GPP_8_15			57
+#define	MV64x60_IRQ_P0_GPP_16_23		58
+#define	MV64x60_IRQ_P0_GPP_24_31		59
 
 #define	MV64360_IRQ_PCI0			12
 #define	MV64360_IRQ_SRAM_PAR_ERR		13
 #define	MV64360_IRQ_PCI1			16
 #define	MV64360_IRQ_SDMA_1			38
 
+#define	MV64x60_IRQ_GPP0			64
+#define	MV64x60_IRQ_GPP1			65
+#define	MV64x60_IRQ_GPP2			66
+#define	MV64x60_IRQ_GPP3			67
+#define	MV64x60_IRQ_GPP4			68
+#define	MV64x60_IRQ_GPP5			69
+#define	MV64x60_IRQ_GPP6			70
+#define	MV64x60_IRQ_GPP7			71
+#define	MV64x60_IRQ_GPP8			72
+#define	MV64x60_IRQ_GPP9			73
+#define	MV64x60_IRQ_GPP10			74
+#define	MV64x60_IRQ_GPP11			75
+#define	MV64x60_IRQ_GPP12			76
+#define	MV64x60_IRQ_GPP13			77
+#define	MV64x60_IRQ_GPP14			78
+#define	MV64x60_IRQ_GPP15			79
+#define	MV64x60_IRQ_GPP16			80
+#define	MV64x60_IRQ_GPP17			81
+#define	MV64x60_IRQ_GPP18			82
+#define	MV64x60_IRQ_GPP19			83
+#define	MV64x60_IRQ_GPP20			84
+#define	MV64x60_IRQ_GPP21			85
+#define	MV64x60_IRQ_GPP22			86
+#define	MV64x60_IRQ_GPP23			87
+#define	MV64x60_IRQ_GPP24			88
+#define	MV64x60_IRQ_GPP25			89
+#define	MV64x60_IRQ_GPP26			90
+#define	MV64x60_IRQ_GPP27			91
+#define	MV64x60_IRQ_GPP28			92
+#define	MV64x60_IRQ_GPP29			93
+#define	MV64x60_IRQ_GPP30			94
+#define	MV64x60_IRQ_GPP31			95
+
 /* Offsets for register blocks */
 #define	GT64260_ENET_PHY_ADDR			0x2000
 #define	GT64260_ENET_ESMIR			0x2010
@@ -303,7 +347,7 @@
 #define	MV64360_SRAM_ERR_DATA_HI		0x03a0
 #define	MV64360_SRAM_ERR_PARITY			0x03a8
 
-#define	MV64360_SRAM_SIZE			0x00040000 /* 256 KB of SRAM */
+#define	MV64360_SRAM_SIZE			0x00040000 /* 2Mb/256KB SRAM */
 
 /*
  *****************************************************************************
diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
--- a/include/asm-ppc/ocp.h
+++ b/include/asm-ppc/ocp.h
@@ -119,7 +119,7 @@ struct ocp_driver {
 	const struct ocp_device_id *id_table;	/* NULL if wants all devices */
 	int  (*probe)  (struct ocp_device *dev);	/* New device inserted */
 	void (*remove) (struct ocp_device *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
-	int  (*suspend) (struct ocp_device *dev, u32 state);	/* Device suspended */
+	int  (*suspend) (struct ocp_device *dev, pm_message_t state);	/* Device suspended */
 	int  (*resume) (struct ocp_device *dev);	                /* Device woken up */
 	struct device_driver driver;
 };
diff --git a/include/asm-ppc/of_device.h b/include/asm-ppc/of_device.h
--- a/include/asm-ppc/of_device.h
+++ b/include/asm-ppc/of_device.h
@@ -55,7 +55,7 @@ struct of_platform_driver
 	int	(*probe)(struct of_device* dev, const struct of_match *match);
 	int	(*remove)(struct of_device* dev);
 
-	int	(*suspend)(struct of_device* dev, u32 state);
+	int	(*suspend)(struct of_device* dev, pm_message_t state);
 	int	(*resume)(struct of_device* dev);
 	int	(*shutdown)(struct of_device* dev);
 
diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
--- a/include/asm-ppc/open_pic.h
+++ b/include/asm-ppc/open_pic.h
@@ -56,6 +56,7 @@ extern void smp_openpic_message_pass(int
 				     int wait);
 extern void openpic_set_k2_cascade(int irq);
 extern void openpic_set_priority(u_int pri);
+extern u_int openpic_get_priority(void);
 
 extern inline int openpic_to_irq(int irq)
 {
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -137,6 +137,8 @@ static inline void* ___va(unsigned long 
 #define ___va(paddr) ((paddr)+PPC_MEMOFFSET)
 #endif
 
+extern int page_is_ram(unsigned long pfn);
+
 #define __pa(x) ___pa((unsigned long)(x))
 #define __va(x) ((void *)(___va((unsigned long)(x))))
 
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -12,7 +12,7 @@ struct pci_controller;
  * pci_io_base returns the memory address at which you can access
  * the I/O space for PCI bus number `bus' (or NULL on error).
  */
-extern void *pci_bus_io_base(unsigned int bus);
+extern void __iomem *pci_bus_io_base(unsigned int bus);
 extern unsigned long pci_bus_io_base_phys(unsigned int bus);
 extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
 
@@ -48,7 +48,7 @@ struct pci_controller {
 	int last_busno;
 	int bus_offset;
 
-	void *io_base_virt;
+	void __iomem *io_base_virt;
 	unsigned long io_base_phys;
 
 	/* Some machines (PReP) have a non 1:1 mapping of
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -79,9 +79,8 @@ extern unsigned long pci_bus_to_phys(uns
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
 /* Set the name of the bus as it appears in /proc/bus/pci */
-static inline int pci_name_bus(char *name, struct pci_bus *bus)
+static inline int pci_proc_domain(struct pci_bus *bus)
 {
-	sprintf(name, "%02x", bus->number);
 	return 0;
 }
 
@@ -98,6 +97,12 @@ pcibios_resource_to_bus(struct pci_dev *
 
 extern void pcibios_add_platform_entries(struct pci_dev *dev);
 
+struct file;
+extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
+					 unsigned long offset,
+					 unsigned long size,
+					 pgprot_t prot);
+
 #endif	/* __KERNEL__ */
 
 #endif /* __PPC_PCI_H */
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -96,7 +96,7 @@ extern unsigned long ioremap_bot, iorema
 #define PTRS_PER_PGD	(1 << (32 - PGDIR_SHIFT))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
 #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
@@ -225,8 +225,7 @@ extern unsigned long ioremap_bot, iorema
 /* ERPN in a PTE never gets cleared, ignore it */
 #define _PTE_NONE_MASK	0xffffffff00000000ULL
 
-#elif defined(CONFIG_E500)
-
+#elif defined(CONFIG_FSL_BOOKE)
 /*
    MMU Assist Register 3:
 
@@ -240,21 +239,29 @@ extern unsigned long ioremap_bot, iorema
      entries use the top 29 bits.
 */
 
-/* Definitions for e500 core */
-#define _PAGE_PRESENT	0x001	/* S: PTE contains a translation */
-#define _PAGE_USER	0x002	/* S: User page (maps to UR) */
-#define _PAGE_FILE	0x002	/* S: when !present: nonlinear file mapping */
-#define _PAGE_ACCESSED	0x004	/* S: Page referenced */
-#define _PAGE_HWWRITE	0x008	/* H: Dirty & RW, set in exception */
-#define _PAGE_RW	0x010	/* S: Write permission */
-#define _PAGE_HWEXEC	0x020	/* H: UX permission */
-
-#define _PAGE_ENDIAN	0x040	/* H: E bit */
-#define _PAGE_GUARDED	0x080	/* H: G bit */
-#define _PAGE_COHERENT	0x100	/* H: M bit */
-#define _PAGE_NO_CACHE	0x200	/* H: I bit */
-#define _PAGE_WRITETHRU	0x400	/* H: W bit */
-#define _PAGE_DIRTY	0x800	/* S: Page dirty */
+/* Definitions for FSL Book-E Cores */
+#define _PAGE_PRESENT	0x00001	/* S: PTE contains a translation */
+#define _PAGE_USER	0x00002	/* S: User page (maps to UR) */
+#define _PAGE_FILE	0x00002	/* S: when !present: nonlinear file mapping */
+#define _PAGE_ACCESSED	0x00004	/* S: Page referenced */
+#define _PAGE_HWWRITE	0x00008	/* H: Dirty & RW, set in exception */
+#define _PAGE_RW	0x00010	/* S: Write permission */
+#define _PAGE_HWEXEC	0x00020	/* H: UX permission */
+
+#define _PAGE_ENDIAN	0x00040	/* H: E bit */
+#define _PAGE_GUARDED	0x00080	/* H: G bit */
+#define _PAGE_COHERENT	0x00100	/* H: M bit */
+#define _PAGE_NO_CACHE	0x00200	/* H: I bit */
+#define _PAGE_WRITETHRU	0x00400	/* H: W bit */
+
+#ifdef CONFIG_PTE_64BIT
+#define _PAGE_DIRTY	0x08000	/* S: Page dirty */
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK	0xffffffffffff0000ULL
+#else
+#define _PAGE_DIRTY	0x00800	/* S: Page dirty */
+#endif
 
 #define _PMD_PRESENT	0
 #define _PMD_PRESENT_MASK (PAGE_MASK)
@@ -431,10 +438,19 @@ extern unsigned long bad_call_to_PMD_PAG
  * Conversions between PTE values and page frame numbers.
  */
 
-#define pte_pfn(x)		(pte_val(x) >> PAGE_SHIFT)
+/* in some case we want to additionaly adjust where the pfn is in the pte to
+ * allow room for more flags */
+#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
+#define PFN_SHIFT_OFFSET	(PAGE_SHIFT + 8)
+#else
+#define PFN_SHIFT_OFFSET	(PAGE_SHIFT)
+#endif
+
+#define pte_pfn(x)		(pte_val(x) >> PFN_SHIFT_OFFSET)
 #define pte_page(x)		pfn_to_page(pte_pfn(x))
 
-#define pfn_pte(pfn, prot)	__pte(((pte_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pte(pfn, prot)	__pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) |\
+					pgprot_val(prot))
 #define mk_pte(page, prot)	pfn_pte(page_to_pfn(page), prot)
 
 /*
@@ -448,7 +464,7 @@ extern unsigned long empty_zero_page[102
 
 #define pte_none(pte)		((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
 #define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
-#define pte_clear(ptep)		do { set_pte((ptep), __pte(0)); } while (0)
+#define pte_clear(mm,addr,ptep)	do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
 #define	pmd_bad(pmd)		(pmd_val(pmd) & _PMD_BAD)
@@ -512,13 +528,24 @@ static inline pte_t pte_modify(pte_t pte
 }
 
 /*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry.  flush_hash_pages is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_pages(unsigned context, unsigned long va,
+			    unsigned long pmdval, int count);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va,
+			  unsigned long pmdval);
+
+/*
  * Atomic PTE updates.
  *
  * pte_update clears and sets bit atomically, and returns
- * the old pte value.
- * The ((unsigned long)(p+1) - 4) hack is to get to the least-significant
- * 32 bits of the PTE regardless of whether PTEs are 32 or 64 bits.
+ * the old pte value.  In the 64-bit PTE case we lock around the
+ * low PTE word since we expect ALL flag bits to be there
  */
+#ifndef CONFIG_PTE_64BIT
 static inline unsigned long pte_update(pte_t *p, unsigned long clr,
 				       unsigned long set)
 {
@@ -532,17 +559,39 @@ static inline unsigned long pte_update(p
 "	stwcx.	%1,0,%3\n\
 	bne-	1b"
 	: "=&r" (old), "=&r" (tmp), "=m" (*p)
-	: "r" ((unsigned long)(p+1) - 4), "r" (clr), "r" (set), "m" (*p)
+	: "r" (p), "r" (clr), "r" (set), "m" (*p)
 	: "cc" );
 	return old;
 }
+#else
+static inline unsigned long long pte_update(pte_t *p, unsigned long clr,
+				       unsigned long set)
+{
+	unsigned long long old;
+	unsigned long tmp;
+
+	__asm__ __volatile__("\
+1:	lwarx	%L0,0,%4\n\
+	lwzx	%0,0,%3\n\
+	andc	%1,%L0,%5\n\
+	or	%1,%1,%6\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%1,0,%4\n\
+	bne-	1b"
+	: "=&r" (old), "=&r" (tmp), "=m" (*p)
+	: "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
+	: "cc" );
+	return old;
+}
+#endif
 
 /*
  * set_pte stores a linux PTE into the linux page table.
  * On machines which use an MMU hash table we avoid changing the
  * _PAGE_HASHPTE bit.
  */
-static inline void set_pte(pte_t *ptep, pte_t pte)
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pte)
 {
 #if _PAGE_HASHPTE != 0
 	pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
@@ -551,43 +600,47 @@ static inline void set_pte(pte_t *ptep, 
 #endif
 }
 
-extern void flush_hash_one_pte(pte_t *ptep);
-
 /*
  * 2.6 calles this without flushing the TLB entry, this is wrong
  * for our hash-based implementation, we fix that up here
  */
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep)
 {
 	unsigned long old;
 	old = pte_update(ptep, _PAGE_ACCESSED, 0);
 #if _PAGE_HASHPTE != 0
-	if (old & _PAGE_HASHPTE)
-		flush_hash_one_pte(ptep);
+	if (old & _PAGE_HASHPTE) {
+		unsigned long ptephys = __pa(ptep) & PAGE_MASK;
+		flush_hash_pages(context, addr, ptephys, 1);
+	}
 #endif
 	return (old & _PAGE_ACCESSED) != 0;
 }
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+	__ptep_test_and_clear_young((__vma)->vm_mm->context, __addr, __ptep)
 
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
+					    unsigned long addr, pte_t *ptep)
 {
 	return (pte_update(ptep, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
 }
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+				       pte_t *ptep)
 {
 	return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+				      pte_t *ptep)
 {
 	pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
 }
 
-static inline void ptep_mkdirty(pte_t *ptep)
-{
-	pte_update(ptep, 0, _PAGE_DIRTY);
-}
-
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
 {
@@ -607,6 +660,12 @@ static inline void __ptep_set_access_fla
  */
 #define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
 
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
 
 /*
@@ -659,17 +718,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD
 extern void paging_init(void);
 
 /*
- * When flushing the tlb entry for a page, we also need to flush the hash
- * table entry.  flush_hash_pages is assembler (for speed) in hashtable.S.
- */
-extern int flush_hash_pages(unsigned context, unsigned long va,
-			    unsigned long pmdval, int count);
-
-/* Add an HPTE to the hash table */
-extern void add_hash_page(unsigned context, unsigned long va,
-			  unsigned long pmdval);
-
-/*
  * Encode and decode a swap entry.
  * Note that the bits we use in a PTE for representing a swap entry
  * must not include the _PAGE_PRESENT bit, the _PAGE_FILE bit, or the
@@ -729,11 +777,27 @@ static inline int io_remap_page_range(st
 	phys_addr_t paddr64 = fixup_bigphys_addr(paddr, size);
 	return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
 }
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+					unsigned long vaddr,
+					unsigned long pfn,
+					unsigned long size,
+					pgprot_t prot)
+{
+	phys_addr_t paddr64 = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+	return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
+}
 #else
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /*
  * No page table caches to initialise
  */
@@ -741,15 +805,9 @@ static inline int io_remap_page_range(st
 
 extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
 
-#endif /* !__ASSEMBLY__ */
-
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
-#define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
+#endif /* !__ASSEMBLY__ */
+
 #endif /* _PPC_PGTABLE_H */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h
--- a/include/asm-ppc/pmac_feature.h
+++ b/include/asm-ppc/pmac_feature.h
@@ -112,9 +112,13 @@
  */
 #define PMAC_TYPE_UNKNOWN_INTREPID	0x11f	/* Generic */
 
-/* MacRISC4 / G5 machines
+/* MacRISC4 / G5 machines. We don't have per-machine selection here anymore,
+ * but rather machine families
  */
-#define PMAC_TYPE_POWERMAC_G5		0x150	/* First tower */
+#define PMAC_TYPE_POWERMAC_G5		0x150	/* U3 & U3H based */
+#define PMAC_TYPE_POWERMAC_G5_U3L	0x151	/* U3L based desktop */
+#define PMAC_TYPE_IMAC_G5		0x152	/* iMac G5 */
+#define PMAC_TYPE_XSERVE_G5		0x153	/* Xserve G5 */
 #define PMAC_TYPE_UNKNOWN_K2		0x19f	/* Any other K2 based */
 
 /*
@@ -301,6 +305,20 @@ extern void pmac_call_early_video_resume
 
 #define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
 
+/* The AGP driver registers itself here */
+extern void pmac_register_agp_pm(struct pci_dev *bridge,
+				 int (*suspend)(struct pci_dev *bridge),
+				 int (*resume)(struct pci_dev *bridge));
+
+/* Those are meant to be used by video drivers to deal with AGP
+ * suspend resume properly
+ */
+extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
+extern void pmac_resume_agp_for_card(struct pci_dev *dev);
+
+/* Used by the via-pmu driver for suspend/resume
+ */
+extern void pmac_tweak_clock_spreading(int enable);
 
 /*
  * The part below is for use by macio_asic.c only, do not rely
diff --git a/include/asm-ppc/ppc4xx_pic.h b/include/asm-ppc/ppc4xx_pic.h
--- a/include/asm-ppc/ppc4xx_pic.h
+++ b/include/asm-ppc/ppc4xx_pic.h
@@ -43,11 +43,11 @@
  *
  */
 struct ppc4xx_uic_settings {
-	u32 	polarity;
-	u32 	triggering;
-	u32	ext_irq_mask;
+	u32 polarity;
+	u32 triggering;
+	u32 ext_irq_mask;
 };
 
 extern void ppc4xx_pic_init(void);
 
-#endif	/* __PPC4XX_PIC_H__ */
+#endif				/* __PPC4XX_PIC_H__ */
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -21,8 +21,12 @@
 #include <linux/device.h>
 #include <linux/types.h>
 
-#if defined(CONFIG_85xx)
+#if defined(CONFIG_83xx)
+#include <asm/mpc83xx.h>
+#elif defined(CONFIG_85xx)
 #include <asm/mpc85xx.h>
+#elif defined(CONFIG_PPC_MPC52xx)
+#include <asm/mpc52xx.h>
 #else
 #error "need definition of ppc_sys_devices"
 #endif
diff --git a/include/asm-ppc/ppcboot.h b/include/asm-ppc/ppcboot.h
--- a/include/asm-ppc/ppcboot.h
+++ b/include/asm-ppc/ppcboot.h
@@ -38,7 +38,8 @@ typedef struct bd_info {
 	unsigned long	bi_flashoffset; /* reserved area for startup monitor */
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
-#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx)
+#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx) ||\
+	defined(CONFIG_83xx)
 	unsigned long	bi_immr_base;	/* base of IMMR register */
 #endif
 #if defined(CONFIG_PPC_MPC52xx)
@@ -72,7 +73,8 @@ typedef struct bd_info {
 #if defined(CONFIG_HYMOD)
 	hymod_conf_t	bi_hymod_conf;	/* hymod configuration information */
 #endif
-#if defined(CONFIG_EVB64260) || defined(CONFIG_44x) || defined(CONFIG_85xx)
+#if defined(CONFIG_EVB64260) || defined(CONFIG_44x) || defined(CONFIG_85xx) ||\
+	defined(CONFIG_83xx)
 	/* second onboard ethernet port */
 	unsigned char	bi_enet1addr[6];
 #endif
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -9,12 +9,10 @@
 #define _PPC_PROM_H
 
 #include <linux/config.h>
+#include <linux/types.h>
 
-typedef void *phandle;
-typedef void *ihandle;
-
-extern char *prom_display_paths[];
-extern unsigned int prom_num_displays;
+typedef u32 phandle;
+typedef u32 ihandle;
 
 struct address_range {
 	unsigned int space;
diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h
--- a/include/asm-ppc/reg.h
+++ b/include/asm-ppc/reg.h
@@ -181,6 +181,7 @@
 #define HID1_PC3	(1<<13)		/* 7450 PLL_CFG[3] */
 #define HID1_SYNCBE	(1<<11)		/* 7450 ABE for sync, eieio */
 #define HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */
+#define HID1_PS		(1<<16)		/* 750FX PLL selection */
 #define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */
 #define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
 #define SPRN_HID4	0x3F4		/* 970 HID4 */
@@ -335,91 +336,6 @@
 #define MMCR0_PMC2_LOADMISSTIME	0x5
 #define MMCR0_PMXE	(1 << 26)
 
-/* Short-hand versions for a number of the above SPRNs */
-#define CTR	SPRN_CTR	/* Counter Register */
-#define DAR	SPRN_DAR	/* Data Address Register */
-#define DABR	SPRN_DABR	/* Data Address Breakpoint Register */
-#define DBAT0L	SPRN_DBAT0L	/* Data BAT 0 Lower Register */
-#define DBAT0U	SPRN_DBAT0U	/* Data BAT 0 Upper Register */
-#define DBAT1L	SPRN_DBAT1L	/* Data BAT 1 Lower Register */
-#define DBAT1U	SPRN_DBAT1U	/* Data BAT 1 Upper Register */
-#define DBAT2L	SPRN_DBAT2L	/* Data BAT 2 Lower Register */
-#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 DEC	SPRN_DEC	/* Decrement Register */
-#define DMISS	SPRN_DMISS	/* Data TLB Miss Register */
-#define DSISR	SPRN_DSISR	/* Data Storage Interrupt Status Register */
-#define EAR	SPRN_EAR	/* External Address Register */
-#define HASH1	SPRN_HASH1	/* Primary Hash Address Register */
-#define HASH2	SPRN_HASH2	/* Secondary Hash Address Register */
-#define HID0	SPRN_HID0	/* Hardware Implementation Register 0 */
-#define HID1	SPRN_HID1	/* Hardware Implementation Register 1 */
-#define IABR	SPRN_IABR	/* Instruction Address Breakpoint Register */
-#define IBAT0L	SPRN_IBAT0L	/* Instruction BAT 0 Lower Register */
-#define IBAT0U	SPRN_IBAT0U	/* Instruction BAT 0 Upper Register */
-#define IBAT1L	SPRN_IBAT1L	/* Instruction BAT 1 Lower Register */
-#define IBAT1U	SPRN_IBAT1U	/* Instruction BAT 1 Upper Register */
-#define IBAT2L	SPRN_IBAT2L	/* Instruction BAT 2 Lower Register */
-#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 */
-#define L2CR	SPRN_L2CR	/* Classic PPC L2 cache control register */
-#define L3CR	SPRN_L3CR	/* PPC 745x L3 cache control register */
-//#define LR	SPRN_LR
-#define PVR	SPRN_PVR	/* Processor Version */
-//#define RPA	SPRN_RPA	/* Required Physical Address Register */
-#define SDR1	SPRN_SDR1	/* MMU hash base register */
-#define SPR0	SPRN_SPRG0	/* Supervisor Private Registers */
-#define SPR1	SPRN_SPRG1
-#define SPR2	SPRN_SPRG2
-#define SPR3	SPRN_SPRG3
-#define SPR4	SPRN_SPRG4
-#define SPR5	SPRN_SPRG5
-#define SPR6	SPRN_SPRG6
-#define SPR7	SPRN_SPRG7
-#define SPRG0	SPRN_SPRG0
-#define SPRG1	SPRN_SPRG1
-#define SPRG2	SPRN_SPRG2
-#define SPRG3	SPRN_SPRG3
-#define SPRG4	SPRN_SPRG4
-#define SPRG5	SPRN_SPRG5
-#define SPRG6	SPRN_SPRG6
-#define SPRG7	SPRN_SPRG7
-#define SRR0	SPRN_SRR0	/* Save and Restore Register 0 */
-#define SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
-#define SRR2	SPRN_SRR2	/* Save and Restore Register 2 */
-#define SRR3	SPRN_SRR3	/* Save and Restore Register 3 */
-#define SVR	SPRN_SVR	/* System Version Register */
-#define ICTC	SPRN_ICTC	/* Instruction Cache Throttling Control Reg */
-#define THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
-#define THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
-#define THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
-#define XER	SPRN_XER
-#define TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
-#define TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
-#define TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
-#define TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
-
 /* Processor Version Register */
 
 /* Processor Version Register (PVR) field extraction */
@@ -488,12 +404,6 @@
 #define PVR_8245	0x80811014
 #define PVR_8260	PVR_8240
 
-/* System Version Numbers */
-#define SVR_8540	0x80300000
-#define SVR_8541E	0x807A0000
-#define SVR_8555E	0x80790000
-#define SVR_8560	0x80700000
-
 #if 0
 /* Segment Registers */
 #define SR0	0
diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
--- a/include/asm-ppc/reg_booke.h
+++ b/include/asm-ppc/reg_booke.h
@@ -172,6 +172,7 @@ do {						\
 #define SPRN_MAS4	0x274	/* MMU Assist Register 4 */
 #define SPRN_MAS5	0x275	/* MMU Assist Register 5 */
 #define SPRN_MAS6	0x276	/* MMU Assist Register 6 */
+#define SPRN_MAS7	0x3b0	/* MMU Assist Register 7 */
 #define SPRN_PID1	0x279	/* Process ID Register 1 */
 #define SPRN_PID2	0x27A	/* Process ID Register 2 */
 #define SPRN_TLB0CFG	0x2B0	/* TLB 0 Config Register */
@@ -304,6 +305,7 @@ do {						\
 #define ESR_PIL		0x08000000	/* Program Exception - Illegal */
 #define ESR_PPR		0x04000000	/* Program Exception - Priveleged */
 #define ESR_PTR		0x02000000	/* Program Exception - Trap */
+#define ESR_FP		0x01000000	/* Floating Point Operation */
 #define ESR_DST		0x00800000	/* Storage Exception - Data miss */
 #define ESR_DIZ		0x00400000	/* Storage Exception - Zone fault */
 #define ESR_ST		0x00800000	/* Store Operation */
@@ -427,26 +429,6 @@ do {						\
 #define SPEFSCR_FOVFE	0x00000004	/* Embedded FP overflow enable */
 #define SPEFSCR_FRMC 	0x00000003	/* Embedded FP rounding mode control */
 
-/* Short-hand for various SPRs. */
-#ifdef CONFIG_BOOKE
-#define CSRR0	SPRN_CSRR0	/* Critical Save and Restore Register 0 */
-#define CSRR1	SPRN_CSRR1	/* Critical Save and Restore Register 1 */
-#else
-#define CSRR0	SPRN_SRR2	/* Logically and functionally equivalent. */
-#define CSRR1	SPRN_SRR3	/* Logically and functionally equivalent. */
-#endif
-#define MCSRR0	SPRN_MCSRR0	/* Machine Check Save and Restore Register 0 */
-#define MCSRR1	SPRN_MCSRR1	/* Machine Check Save and Restore Register 1 */
-#define DCMP	SPRN_DCMP	/* Data TLB Compare Register */
-#define SPRG4R	SPRN_SPRG4R	/* Supervisor Private Registers */
-#define SPRG5R	SPRN_SPRG5R
-#define SPRG6R	SPRN_SPRG6R
-#define SPRG7R	SPRN_SPRG7R
-#define SPRG4W	SPRN_SPRG4W
-#define SPRG5W	SPRN_SPRG5W
-#define SPRG6W	SPRN_SPRG6W
-#define SPRG7W	SPRN_SPRG7W
-
 /*
  * The IBM-403 is an even more odd special case, as it is much
  * older than the IBM-405 series.  We put these down here incase someone
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -22,6 +22,8 @@
 #include <platforms/mcpn765.h>
 #elif defined(CONFIG_MVME5100)
 #include <platforms/mvme5100.h>
+#elif defined(CONFIG_PAL4)
+#include <platforms/pal4_serial.h>
 #elif defined(CONFIG_PRPMC750)
 #include <platforms/prpmc750.h>
 #elif defined(CONFIG_PRPMC800)
@@ -32,8 +34,12 @@
 #include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ibm4xx.h>
+#elif defined(CONFIG_83xx)
+#include <asm/mpc83xx.h>
 #elif defined(CONFIG_85xx)
 #include <asm/mpc85xx.h>
+#elif defined(CONFIG_RADSTONE_PPC7D)
+#include <platforms/radstone_ppc7d.h>
 #else
 
 /*
diff --git a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h
--- a/include/asm-ppc/sigcontext.h
+++ b/include/asm-ppc/sigcontext.h
@@ -2,14 +2,14 @@
 #define _ASM_PPC_SIGCONTEXT_H
 
 #include <asm/ptrace.h>
-
+#include <linux/compiler.h>
 
 struct sigcontext {
 	unsigned long	_unused[4];
 	int		signal;
 	unsigned long	handler;
 	unsigned long	oldmask;
-	struct pt_regs 	*regs;
+	struct pt_regs 	__user *regs;
 };
 
 #endif
diff --git a/include/asm-ppc/signal.h b/include/asm-ppc/signal.h
--- a/include/asm-ppc/signal.h
+++ b/include/asm-ppc/signal.h
@@ -99,34 +99,8 @@ typedef struct {
 
 #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 /* __KERNEL__ */
 
-#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 __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 struct old_sigaction {
 	__sighandler_t sa_handler;
diff --git a/include/asm-ppc/suspend.h b/include/asm-ppc/suspend.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc/suspend.h
@@ -0,0 +1,12 @@
+static inline int arch_prepare_suspend(void)
+{
+	return 0;
+}
+
+static inline void save_processor_state(void)
+{
+}
+
+static inline void restore_processor_state(void)
+{
+}
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -152,9 +152,9 @@ extern inline void * xchg_ptr(void * m, 
 #define __HAVE_ARCH_CMPXCHG	1
 
 static __inline__ unsigned long
-__cmpxchg_u32(volatile int *p, int old, int new)
+__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
 {
-	int prev;
+	unsigned int prev;
 
 	__asm__ __volatile__ ("\n\
 1:	lwarx	%0,0,%2 \n\
@@ -201,5 +201,7 @@ __cmpxchg(volatile void *ptr, unsigned l
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 #endif /* __PPC_SYSTEM_H */
diff --git a/include/asm-ppc/timex.h b/include/asm-ppc/timex.h
--- a/include/asm-ppc/timex.h
+++ b/include/asm-ppc/timex.h
@@ -19,8 +19,6 @@ typedef unsigned long cycles_t;
  * Currently only used on SMP.
  */
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles(void)
 {
 	cycles_t ret = 0;
diff --git a/include/asm-ppc/todc.h b/include/asm-ppc/todc.h
--- a/include/asm-ppc/todc.h
+++ b/include/asm-ppc/todc.h
@@ -98,6 +98,7 @@ typedef struct {
 #define TODC_TYPE_PC97307		10	/* PC97307 internal RTC */
 #define TODC_TYPE_DS1557		11	/* Dallas DS1557 RTC */
 #define TODC_TYPE_DS17285		12	/* Dallas DS17285 RTC */
+#define TODC_TYPE_DS1553		13	/* Dallas DS1553 RTC */
 #define	TODC_TYPE_MC146818		100	/* Leave room for m48txx's */
 
 /*
@@ -208,6 +209,28 @@ typedef struct {
 #define	TODC_TYPE_DS1501_NVRAM_ADDR_REG	0x10
 #define	TODC_TYPE_DS1501_NVRAM_DATA_REG	0x13
 
+#define	TODC_TYPE_DS1553_NVRAM_SIZE		0x1ff0
+#define	TODC_TYPE_DS1553_SW_FLAGS		0
+#define	TODC_TYPE_DS1553_YEAR			0x1fff
+#define	TODC_TYPE_DS1553_MONTH			0x1ffe
+#define	TODC_TYPE_DS1553_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_DS1553_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_DS1553_HOURS			0x1ffb
+#define	TODC_TYPE_DS1553_MINUTES		0x1ffa
+#define	TODC_TYPE_DS1553_SECONDS		0x1ff9
+#define	TODC_TYPE_DS1553_CNTL_B			0x1ff9
+#define	TODC_TYPE_DS1553_CNTL_A			0x1ff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1553_WATCHDOG		0x1ff7
+#define	TODC_TYPE_DS1553_INTERRUPTS		0x1ff6
+#define	TODC_TYPE_DS1553_ALARM_DATE		0x1ff5
+#define	TODC_TYPE_DS1553_ALARM_HOUR		0x1ff4
+#define	TODC_TYPE_DS1553_ALARM_MINUTES		0x1ff3
+#define	TODC_TYPE_DS1553_ALARM_SECONDS		0x1ff2
+#define	TODC_TYPE_DS1553_CENTURY		0x1ff8
+#define	TODC_TYPE_DS1553_FLAGS			0x1ff0
+#define	TODC_TYPE_DS1553_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1553_NVRAM_DATA_REG		0
+
 #define	TODC_TYPE_DS1557_NVRAM_SIZE		0x7fff0
 #define	TODC_TYPE_DS1557_SW_FLAGS		0
 #define	TODC_TYPE_DS1557_YEAR			0x7ffff
diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
--- a/include/asm-ppc/uaccess.h
+++ b/include/asm-ppc/uaccess.h
@@ -37,7 +37,8 @@
 #define access_ok(type, addr, size) \
 	(__chk_user_ptr(addr),__access_ok((unsigned long)(addr),(size)))
 
-extern inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h
--- a/include/asm-ppc/uninorth.h
+++ b/include/asm-ppc/uninorth.h
@@ -27,13 +27,18 @@
 #define UNI_N_CFG_AGP_BASE		0x90
 #define UNI_N_CFG_GART_CTRL		0x94
 #define UNI_N_CFG_INTERNAL_STATUS	0x98
+#define UNI_N_CFG_GART_DUMMY_PAGE	0xa4
 
 /* UNI_N_CFG_GART_CTRL bits definitions */
-/* Not U3 */
 #define UNI_N_CFG_GART_INVAL		0x00000001
 #define UNI_N_CFG_GART_ENABLE		0x00000100
 #define UNI_N_CFG_GART_2xRESET		0x00010000
 #define UNI_N_CFG_GART_DISSBADET	0x00020000
+/* The following seems to only be used only on U3 <j.glisse@gmail.com> */
+#define U3_N_CFG_GART_SYNCMODE		0x00040000
+#define U3_N_CFG_GART_PERFRD		0x00080000
+#define U3_N_CFG_GART_B2BGNT		0x00200000
+#define U3_N_CFG_GART_FASTDDR		0x00400000
 
 /* My understanding of UniNorth AGP as of UniNorth rev 1.0x,
  * revision 1.5 (x4 AGP) may need further changes.
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -276,8 +276,9 @@
 #define __NR_add_key		269
 #define __NR_request_key	270
 #define __NR_keyctl		271
+#define __NR_waitid		272
 
-#define __NR_syscalls		272
+#define __NR_syscalls		273
 
 #define __NR(n)	#n
 
@@ -296,6 +297,7 @@
 		register unsigned long __sc_5  __asm__ ("r5");		\
 		register unsigned long __sc_6  __asm__ ("r6");		\
 		register unsigned long __sc_7  __asm__ ("r7");		\
+		register unsigned long __sc_8  __asm__ ("r8");		\
 									\
 		__sc_loadargs_##nr(name, args);				\
 		__asm__ __volatile__					\
@@ -304,10 +306,10 @@
 			: "=&r" (__sc_0),				\
 			  "=&r" (__sc_3),  "=&r" (__sc_4),		\
 			  "=&r" (__sc_5),  "=&r" (__sc_6),		\
-			  "=&r" (__sc_7)				\
+			  "=&r" (__sc_7),  "=&r" (__sc_8)		\
 			: __sc_asm_input_##nr				\
 			: "cr0", "ctr", "memory",			\
-			  "r8", "r9", "r10","r11", "r12");		\
+			  "r9", "r10","r11", "r12");			\
 		__sc_ret = __sc_3;					\
 		__sc_err = __sc_0;					\
 	}								\
@@ -335,6 +337,9 @@
 #define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5)		\
 	__sc_loadargs_4(name, arg1, arg2, arg3, arg4);			\
 	__sc_7 = (unsigned long) (arg5)
+#define __sc_loadargs_6(name, arg1, arg2, arg3, arg4, arg5, arg6)	\
+	__sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5);		\
+	__sc_8 = (unsigned long) (arg6)
 
 #define __sc_asm_input_0 "0" (__sc_0)
 #define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
@@ -342,6 +347,7 @@
 #define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
 #define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
 #define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
+#define __sc_asm_input_6 __sc_asm_input_5, "6" (__sc_8)
 
 #define _syscall0(type,name)						\
 type name(void)								\
@@ -379,6 +385,12 @@ type name(type1 arg1, type2 arg2, type3 
 	__syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);	\
 }
 
+#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) \
+{									\
+	__syscall_nr(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \
+}
+
 #ifdef __KERNEL__
 
 #define __NR__exit __NR_exit
@@ -468,7 +480,7 @@ long sys_rt_sigaction(int sig,
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc64/a.out.h b/include/asm-ppc64/a.out.h
--- a/include/asm-ppc64/a.out.h
+++ b/include/asm-ppc64/a.out.h
@@ -1,8 +1,6 @@
 #ifndef __PPC64_A_OUT_H__
 #define __PPC64_A_OUT_H__
 
-#include <asm/ppcdebug.h>
-
 /*
  * c 2001 PPC 64 Team, IBM Corp
  *
@@ -30,14 +28,11 @@ struct exec
 
 #ifdef __KERNEL__
 
-#define STACK_TOP_USER64 (TASK_SIZE_USER64)
-
-/* Give 32-bit user space a full 4G address space to live in. */
-#define STACK_TOP_USER32 (TASK_SIZE_USER32)
+#define STACK_TOP_USER64 TASK_SIZE_USER64
+#define STACK_TOP_USER32 TASK_SIZE_USER32
 
-#define STACK_TOP ((test_thread_flag(TIF_32BIT) || \
-		(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \
-		STACK_TOP_USER32 : STACK_TOP_USER64)
+#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
+		   STACK_TOP_USER32 : STACK_TOP_USER64)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ppc64/agp.h b/include/asm-ppc64/agp.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/agp.h
@@ -0,0 +1,23 @@
+#ifndef AGP_H
+#define AGP_H 1
+
+#include <asm/io.h>
+
+/* nothing much needed here */
+
+#define map_page_into_agp(page)
+#define unmap_page_from_agp(page)
+#define flush_agp_mappings()
+#define flush_agp_cache() mb()
+
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
+#endif
diff --git a/include/asm-ppc64/bug.h b/include/asm-ppc64/bug.h
--- a/include/asm-ppc64/bug.h
+++ b/include/asm-ppc64/bug.h
@@ -26,6 +26,8 @@ struct bug_entry *find_bug(unsigned long
  */
 #define BUG_WARNING_TRAP	0x1000000
 
+#ifdef CONFIG_BUG
+
 #define BUG() do {							 \
 	__asm__ __volatile__(						 \
 		"1:	twi 31,0,0\n"					 \
@@ -55,11 +57,12 @@ struct bug_entry *find_bug(unsigned long
 		    "i" (__FILE__), "i" (__FUNCTION__));	\
 } while (0)
 
-#endif
-
 #define HAVE_ARCH_BUG
 #define HAVE_ARCH_BUG_ON
 #define HAVE_ARCH_WARN_ON
+#endif
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-ppc64/cacheflush.h b/include/asm-ppc64/cacheflush.h
--- a/include/asm-ppc64/cacheflush.h
+++ b/include/asm-ppc64/cacheflush.h
@@ -12,7 +12,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_icache_page(vma, page)		do { } while (0)
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
@@ -28,6 +28,7 @@ extern void flush_icache_user_range(stru
 
 extern void flush_dcache_range(unsigned long start, unsigned long stop);
 extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
+extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 do { memcpy(dst, src, len); \
@@ -40,7 +41,7 @@ extern void __flush_dcache_icache(void *
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
-	if (!(cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE))
+	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
 		__flush_icache_range(start, stop);
 }
 
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -66,6 +66,11 @@ struct cpu_spec {
 extern struct cpu_spec		cpu_specs[];
 extern struct cpu_spec		*cur_cpu_spec;
 
+static inline unsigned long cpu_has_feature(unsigned long feature)
+{
+	return cur_cpu_spec->cpu_features & feature;
+}
+
 
 /* firmware feature bitmask values */
 #define FIRMWARE_MAX_FEATURES 63
diff --git a/include/asm-ppc64/dma-mapping.h b/include/asm-ppc64/dma-mapping.h
--- a/include/asm-ppc64/dma-mapping.h
+++ b/include/asm-ppc64/dma-mapping.h
@@ -19,7 +19,7 @@
 extern int dma_supported(struct device *dev, u64 mask);
 extern int dma_set_mask(struct device *dev, u64 dma_mask);
 extern void *dma_alloc_coherent(struct device *dev, size_t size,
-		dma_addr_t *dma_handle, int flag);
+		dma_addr_t *dma_handle, unsigned int __nocast flag);
 extern void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
 		dma_addr_t dma_handle);
 extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
@@ -113,4 +113,24 @@ dma_cache_sync(void *vaddr, size_t size,
 	/* nothing to do */
 }
 
+/*
+ * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
+ */
+struct dma_mapping_ops {
+	void *		(*alloc_coherent)(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, unsigned int __nocast flag);
+	void		(*free_coherent)(struct device *dev, size_t size,
+				void *vaddr, dma_addr_t dma_handle);
+	dma_addr_t	(*map_single)(struct device *dev, void *ptr,
+				size_t size, enum dma_data_direction direction);
+	void		(*unmap_single)(struct device *dev, dma_addr_t dma_addr,
+				size_t size, enum dma_data_direction direction);
+	int		(*map_sg)(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction);
+	void		(*unmap_sg)(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction);
+	int		(*dma_supported)(struct device *dev, u64 mask);
+	int		(*dac_dma_supported)(struct device *dev, u64 mask);
+};
+
 #endif	/* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h
--- a/include/asm-ppc64/eeh.h
+++ b/include/asm-ppc64/eeh.h
@@ -104,17 +104,30 @@ int eeh_unregister_notifier(struct notif
  */
 #define EEH_IO_ERROR_VALUE(size)	(~0U >> ((4 - (size)) * 8))
 
-#else
-#define eeh_init()
-#define eeh_check_failure(token, val) (val)
-#define eeh_dn_check_failure(dn, dev) (0)
-#define pci_addr_cache_build()
-#define eeh_add_device_early(dn)
-#define eeh_add_device_late(dev)
-#define eeh_remove_device(dev)
+#else /* !CONFIG_EEH */
+static inline void eeh_init(void) { }
+
+static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
+{
+	return val;
+}
+
+static inline int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
+{
+	return 0;
+}
+
+static inline void pci_addr_cache_build(void) { }
+
+static inline void eeh_add_device_early(struct device_node *dn) { }
+
+static inline void eeh_add_device_late(struct pci_dev *dev) { }
+
+static inline void eeh_remove_device(struct pci_dev *dev) { }
+
 #define EEH_POSSIBLE_ERROR(val, type) (0)
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
-#endif
+#endif /* CONFIG_EEH */
 
 /* 
  * MMIO read/write operations with EEH support.
diff --git a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h
--- a/include/asm-ppc64/elf.h
+++ b/include/asm-ppc64/elf.h
@@ -221,11 +221,20 @@ do {								\
 		set_thread_flag(TIF_ABI_PENDING);		\
 	else							\
 		clear_thread_flag(TIF_ABI_PENDING);		\
-	if (ibcs2)						\
-		set_personality(PER_SVR4);			\
-	else if (current->personality != PER_LINUX32)		\
+	if (personality(current->personality) != PER_LINUX32)	\
 		set_personality(PER_LINUX);			\
 } while (0)
+
+/*
+ * An executable for which elf_read_implies_exec() returns TRUE will
+ * have the READ_IMPLIES_EXEC personality flag set automatically. This
+ * is only required to work around bugs in old 32bit toolchains. Since
+ * the 64bit ABI has never had these issues dont enable the workaround
+ * even if we have an executable stack.
+ */
+#define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \
+		(exec_stk != EXSTACK_DISABLE_X) : 0)
+
 #endif
 
 /*
@@ -238,10 +247,20 @@ do {								\
 /* A special ignored type value for PPC, for glibc compatibility.  */
 #define AT_IGNOREPPC		22
 
+/* The vDSO location. We have to use the same value as x86 for glibc's
+ * sake :-)
+ */
+#define AT_SYSINFO_EHDR		33
+
 extern int dcache_bsize;
 extern int icache_bsize;
 extern int ucache_bsize;
 
+/* We do have an arch_setup_additional_pages for vDSO matters */
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack);
+
 /*
  * The requirements here are:
  * - keep the final alignment of sp (sp & 0xf)
@@ -260,6 +279,8 @@ do {									\
 	NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize);			\
 	NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize);			\
 	NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize);			\
+	/* vDSO base */							\
+	NEW_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base);       	\
  } while (0)
 
 /* PowerPC64 relocations defined by the ABIs */
diff --git a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h
--- a/include/asm-ppc64/hvcall.h
+++ b/include/asm-ppc64/hvcall.h
@@ -1,6 +1,8 @@
 #ifndef _PPC64_HVCALL_H
 #define _PPC64_HVCALL_H
 
+#define HVSC			.long 0x44000022
+
 #define H_Success	0
 #define H_Busy		1	/* Hardware busy -- retry later */
 #define H_Constrained	4	/* Resource request constrained to max allowed */
@@ -41,7 +43,7 @@
 
 /* Flags */
 #define H_LARGE_PAGE		(1UL<<(63-16))
-#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
+#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 */
@@ -54,8 +56,6 @@
 #define H_PP1			(1UL<<(63-62))
 #define H_PP2			(1UL<<(63-63))
 
-
-
 /* pSeries hypervisor opcodes */
 #define H_REMOVE		0x04
 #define H_ENTER			0x08
@@ -108,6 +108,8 @@
 #define H_FREE_VTERM		0x158
 #define H_POLL_PENDING	        0x1D8
 
+#ifndef __ASSEMBLY__
+
 /* plpar_hcall() -- Generic call interface using above opcodes
  *
  * The actual call interface is a hypervisor call instruction with
@@ -125,8 +127,6 @@ long plpar_hcall(unsigned long opcode,
 		 unsigned long *out2,
 		 unsigned long *out3);
 
-#define HVSC			".long 0x44000022\n"
-
 /* Same as plpar_hcall but for those opcodes that return no values
  * other than status.  Slightly more efficient.
  */
@@ -147,9 +147,6 @@ long plpar_hcall_8arg_2ret(unsigned long
 			   unsigned long arg7,
 			   unsigned long arg8,
 			   unsigned long *out1);
-
-
- 
  
 /* plpar_hcall_4out()
  *
@@ -166,4 +163,5 @@ long plpar_hcall_4out(unsigned long opco
 		      unsigned long *out3,
 		      unsigned long *out4);
 
+#endif /* __ASSEMBLY__ */
 #endif /* _PPC64_HVCALL_H */
diff --git a/include/asm-ppc64/iSeries/iSeries_fixup.h b/include/asm-ppc64/iSeries/iSeries_fixup.h
deleted file mode 100644
--- a/include/asm-ppc64/iSeries/iSeries_fixup.h
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#ifndef	__ISERIES_FIXUP_H__
-#define	__ISERIES_FIXUP_H__
-#include <linux/pci.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void iSeries_fixup (void);
-void iSeries_fixup_bus (struct pci_bus*);
-unsigned int iSeries_scan_slot (struct pci_dev*, u16, u8, u8);
-
-
-/* Need to store information related to the PHB bucc and make it accessible to the hose */
-struct iSeries_hose_arch_data {
-	u32 hvBusNumber;
-};
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __ISERIES_FIXUP_H__ */
diff --git a/include/asm-ppc64/iSeries/mf.h b/include/asm-ppc64/iSeries/mf.h
--- a/include/asm-ppc64/iSeries/mf.h
+++ b/include/asm-ppc64/iSeries/mf.h
@@ -52,6 +52,7 @@ extern void mf_clear_src(void);
 extern void mf_init(void);
 
 extern int mf_get_rtc(struct rtc_time *tm);
+extern int mf_get_boot_rtc(struct rtc_time *tm);
 extern int mf_set_rtc(struct rtc_time *tm);
 
 #endif /* _ASM_PPC64_ISERIES_MF_H */
diff --git a/include/asm-ppc64/imalloc.h b/include/asm-ppc64/imalloc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/imalloc.h
@@ -0,0 +1,24 @@
+#ifndef _PPC64_IMALLOC_H
+#define _PPC64_IMALLOC_H
+
+/*
+ * Define the address range of the imalloc VM area.
+ */
+#define PHBS_IO_BASE  	  IOREGIONBASE
+#define IMALLOC_BASE      (IOREGIONBASE + 0x80000000ul)	/* Reserve 2 gigs for PHBs */
+#define IMALLOC_END       (IOREGIONBASE + EADDR_MASK)
+
+
+/* imalloc region types */
+#define IM_REGION_UNUSED	0x1
+#define IM_REGION_SUBSET	0x2
+#define IM_REGION_EXISTS	0x4
+#define IM_REGION_OVERLAP	0x8
+#define IM_REGION_SUPERSET	0x10
+
+extern struct vm_struct * im_get_free_area(unsigned long size);
+extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
+			int region_type);
+unsigned long im_free(void *addr);
+
+#endif /* _PPC64_IMALLOC_H */
diff --git a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
--- a/include/asm-ppc64/io.h
+++ b/include/asm-ppc64/io.h
@@ -442,6 +442,17 @@ out:
 extern int check_legacy_ioport(unsigned long base_port);
 
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* _PPC64_IO_H */
diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h
--- a/include/asm-ppc64/iommu.h
+++ b/include/asm-ppc64/iommu.h
@@ -145,9 +145,9 @@ extern int iommu_map_sg(struct device *d
 extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 		int nelems, enum dma_data_direction direction);
 
-extern void *iommu_alloc_consistent(struct iommu_table *tbl, size_t size,
-		dma_addr_t *dma_handle);
-extern void iommu_free_consistent(struct iommu_table *tbl, size_t size,
+extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
+		dma_addr_t *dma_handle, unsigned int __nocast flag);
+extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 		void *vaddr, dma_addr_t dma_handle);
 extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
 		size_t size, enum dma_data_direction direction);
diff --git a/include/asm-ppc64/ipc.h b/include/asm-ppc64/ipc.h
--- a/include/asm-ppc64/ipc.h
+++ b/include/asm-ppc64/ipc.h
@@ -1,34 +1 @@
-#ifndef __PPC64_IPC_H__
-#define __PPC64_IPC_H__
-
-/* 
- * These are used to wrap system calls on PowerPC.
- *
- * See arch/ppc64/kernel/syscalls.c for ugly 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.
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#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 IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif /* __PPC64_IPC_H__ */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-ppc64/kprobes.h b/include/asm-ppc64/kprobes.h
--- a/include/asm-ppc64/kprobes.h
+++ b/include/asm-ppc64/kprobes.h
@@ -35,6 +35,11 @@ typedef unsigned int kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION	0x7fe00008	/* trap */
 #define MAX_INSN_SIZE 1
 
+#define IS_TW(instr)		(((instr) & 0xfc0007fe) == 0x7c000008)
+#define IS_TD(instr)		(((instr) & 0xfc0007fe) == 0x7c000088)
+#define IS_TDI(instr)		(((instr) & 0xfc000000) == 0x08000000)
+#define IS_TWI(instr)		(((instr) & 0xfc000000) == 0x0c000000)
+
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)((func_descr_t *)pentry)
 
 /* Architecture specific copy of original instruction */
diff --git a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h
--- a/include/asm-ppc64/lmb.h
+++ b/include/asm-ppc64/lmb.h
@@ -16,8 +16,6 @@
 #include <linux/init.h>
 #include <asm/prom.h>
 
-extern unsigned long reloc_offset(void);
-
 #define MAX_LMB_REGIONS 128
 
 #define LMB_ALLOC_ANYWHERE	0
@@ -53,6 +51,7 @@ extern unsigned long __init lmb_alloc_ba
 extern unsigned long __init lmb_phys_mem_size(void);
 extern unsigned long __init lmb_end_of_DRAM(void);
 extern unsigned long __init lmb_abs_to_phys(unsigned long);
+extern void __init lmb_enforce_memory_limit(void);
 
 extern void lmb_dump_all(void);
 
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -21,6 +21,7 @@ struct pci_bus;	
 struct device_node;
 struct iommu_table;
 struct rtc_time;
+struct file;
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
@@ -30,8 +31,10 @@ struct smp_ops_t {
 	void  (*setup_cpu)(int nr);
 	void  (*take_timebase)(void);
 	void  (*give_timebase)(void);
+	int   (*cpu_enable)(unsigned int nr);
 	int   (*cpu_disable)(void);
 	void  (*cpu_die)(unsigned int nr);
+	int   (*cpu_bootable)(unsigned int nr);
 };
 #endif
 
@@ -129,11 +132,34 @@ struct machdep_calls {
 	/* Get legacy PCI/IDE interrupt mapping */ 
 	int		(*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
 	
+	/* Get access protection for /dev/mem */
+	pgprot_t	(*phys_mem_access_prot)(struct file *file,
+						unsigned long offset,
+						unsigned long size,
+						pgprot_t vma_prot);
+
 };
 
 extern struct machdep_calls ppc_md;
 extern char cmd_line[COMMAND_LINE_SIZE];
 
+#ifdef CONFIG_PPC_PMAC
+/*
+ * Power macintoshes have either a CUDA, PMU or SMU controlling
+ * system reset, power, NVRAM, RTC.
+ */
+typedef enum sys_ctrler_kind {
+	SYS_CTRLER_UNKNOWN = 0,
+	SYS_CTRLER_CUDA = 1,
+	SYS_CTRLER_PMU = 2,
+	SYS_CTRLER_SMU = 3,
+} sys_ctrler_t;
+extern sys_ctrler_t sys_ctrler;
+
+#endif /* CONFIG_PPC_PMAC */
+
+
+
 /* 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),
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
--- a/include/asm-ppc64/mmu.h
+++ b/include/asm-ppc64/mmu.h
@@ -15,19 +15,10 @@
 
 #include <linux/config.h>
 #include <asm/page.h>
-#include <linux/stringify.h>
 
-#ifndef __ASSEMBLY__
-
-/* Time to allow for more things here */
-typedef unsigned long mm_context_id_t;
-typedef struct {
-	mm_context_id_t id;
-#ifdef CONFIG_HUGETLB_PAGE
-	pgd_t *huge_pgdir;
-	u16 htlb_segs; /* bitmask */
-#endif
-} mm_context_t;
+/*
+ * Segment table
+ */
 
 #define STE_ESID_V	0x80
 #define STE_ESID_KS	0x20
@@ -36,15 +27,48 @@ typedef struct {
 
 #define STE_VSID_SHIFT	12
 
-struct stab_entry {
-	unsigned long esid_data;
-	unsigned long vsid_data;
-};
+/* Location of cpu0's segment table */
+#define STAB0_PAGE	0x9
+#define STAB0_PHYS_ADDR	(STAB0_PAGE<<PAGE_SHIFT)
+#define STAB0_VIRT_ADDR	(KERNELBASE+STAB0_PHYS_ADDR)
+
+/*
+ * SLB
+ */
 
-/* Hardware Page Table Entry */
+#define SLB_NUM_BOLTED		3
+#define SLB_CACHE_ENTRIES	8
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_V		ASM_CONST(0x0000000008000000) /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT		12
+#define SLB_VSID_KS		ASM_CONST(0x0000000000000800)
+#define SLB_VSID_KP		ASM_CONST(0x0000000000000400)
+#define SLB_VSID_N		ASM_CONST(0x0000000000000200) /* no-execute */
+#define SLB_VSID_L		ASM_CONST(0x0000000000000100) /* largepage 16M */
+#define SLB_VSID_C		ASM_CONST(0x0000000000000080) /* class */
+
+#define SLB_VSID_KERNEL		(SLB_VSID_KP|SLB_VSID_C)
+#define SLB_VSID_USER		(SLB_VSID_KP|SLB_VSID_KS)
+
+/*
+ * Hash table
+ */
 
 #define HPTES_PER_GROUP 8
 
+/* Values for PP (assumes Ks=0, Kp=1) */
+/* pp0 will always be 0 for linux     */
+#define PP_RWXX	0	/* Supervisor read/write, User none */
+#define PP_RWRX 1	/* Supervisor read/write, User read */
+#define PP_RWRW 2	/* Supervisor read/write, User read/write */
+#define PP_RXRX 3	/* Supervisor read,       User read */
+
+#ifndef __ASSEMBLY__
+
+/* Hardware Page Table Entry */
 typedef struct {
 	unsigned long avpn:57; /* vsid | api == avpn  */
 	unsigned long :     2; /* Software use */
@@ -90,14 +114,6 @@ typedef struct {
 	} dw1;
 } HPTE; 
 
-/* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux     */
-#define PP_RWXX	0	/* Supervisor read/write, User none */
-#define PP_RWRX 1	/* Supervisor read/write, User read */
-#define PP_RWRW 2	/* Supervisor read/write, User read/write */
-#define PP_RXRX 3	/* Supervisor read,       User read */
-
-
 extern HPTE *		htab_address;
 extern unsigned long	htab_hash_mask;
 
@@ -174,31 +190,70 @@ extern int __hash_page(unsigned long ea,
 
 extern void htab_finish_init(void);
 
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
+extern void hpte_init_iSeries(void);
+
+extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
+				     unsigned long va, unsigned long prpn,
+				     int secondary, unsigned long hpteflags,
+				     int bolted, int large);
+extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
+			       unsigned long prpn, int secondary,
+			       unsigned long hpteflags, int bolted, int large);
+
 #endif /* __ASSEMBLY__ */
 
 /*
- * Location of cpu0's segment table
+ * VSID allocation
+ *
+ * We first generate a 36-bit "proto-VSID".  For kernel addresses this
+ * is equal to the ESID, for user addresses it is:
+ *	(context << 15) | (esid & 0x7fff)
+ *
+ * The two forms are distinguishable because the top bit is 0 for user
+ * addresses, whereas the top two bits are 1 for kernel addresses.
+ * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
+ * now.
+ *
+ * The proto-VSIDs are then scrambled into real VSIDs with the
+ * multiplicative hash:
+ *
+ *	VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
+ *	where	VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
+ *		VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
+ *
+ * This scramble is only well defined for proto-VSIDs below
+ * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
+ * reserved.  VSID_MULTIPLIER is prime, so in particular it is
+ * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
+ * Because the modulus is 2^n-1 we can compute it efficiently without
+ * a divide or extra multiply (see below).
+ *
+ * This scheme has several advantages over older methods:
+ *
+ * 	- We have VSIDs allocated for every kernel address
+ * (i.e. everything above 0xC000000000000000), except the very top
+ * segment, which simplifies several things.
+ *
+ * 	- We allow for 15 significant bits of ESID and 20 bits of
+ * context for user addresses.  i.e. 8T (43 bits) of address space for
+ * up to 1M contexts (although the page table structure and context
+ * allocation will need changes to take advantage of this).
+ *
+ * 	- The scramble function gives robust scattering in the hash
+ * table (at least based on some initial results).  The previous
+ * method was more susceptible to pathological cases giving excessive
+ * hash collisions.
+ */
+/*
+ * WARNING - If you change these you must make sure the asm
+ * implementations in slb_allocate (slb_low.S), do_stab_bolted
+ * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
+ *
+ * You'll also need to change the precomputed VSID values in head.S
+ * which are used by the iSeries firmware.
  */
-#define STAB0_PAGE	0x9
-#define STAB0_PHYS_ADDR	(STAB0_PAGE<<PAGE_SHIFT)
-#define STAB0_VIRT_ADDR	(KERNELBASE+STAB0_PHYS_ADDR)
-
-#define SLB_NUM_BOLTED		3
-#define SLB_CACHE_ENTRIES	8
-
-/* Bits in the SLB ESID word */
-#define SLB_ESID_V		0x0000000008000000	/* entry is valid */
-
-/* Bits in the SLB VSID word */
-#define SLB_VSID_SHIFT		12
-#define SLB_VSID_KS		0x0000000000000800
-#define SLB_VSID_KP		0x0000000000000400
-#define SLB_VSID_N		0x0000000000000200	/* no-execute */
-#define SLB_VSID_L		0x0000000000000100	/* largepage (4M) */
-#define SLB_VSID_C		0x0000000000000080	/* class */
-
-#define SLB_VSID_KERNEL		(SLB_VSID_KP|SLB_VSID_C)
-#define SLB_VSID_USER		(SLB_VSID_KP|SLB_VSID_KS)
 
 #define VSID_MULTIPLIER	ASM_CONST(200730139)	/* 28-bit prime */
 #define VSID_BITS	36
@@ -239,4 +294,50 @@ extern void htab_finish_init(void);
 	srdi	rx,rx,VSID_BITS;	/* extract 2^36 bit */		\
 	add	rt,rt,rx
 
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_context_id_t;
+
+typedef struct {
+	mm_context_id_t id;
+#ifdef CONFIG_HUGETLB_PAGE
+	pgd_t *huge_pgdir;
+	u16 htlb_segs; /* bitmask */
+#endif
+} mm_context_t;
+
+
+static inline unsigned long vsid_scramble(unsigned long protovsid)
+{
+#if 0
+	/* The code below is equivalent to this function for arguments
+	 * < 2^VSID_BITS, which is all this should ever be called
+	 * with.  However gcc is not clever enough to compute the
+	 * modulus (2^n-1) without a second multiply. */
+	return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
+#else /* 1 */
+	unsigned long x;
+
+	x = protovsid * VSID_MULTIPLIER;
+	x = (x >> VSID_BITS) + (x & VSID_MODULUS);
+	return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
+#endif /* 1 */
+}
+
+/* This is only valid for addresses >= KERNELBASE */
+static inline unsigned long get_kernel_vsid(unsigned long ea)
+{
+	return vsid_scramble(ea >> SID_SHIFT);
+}
+
+/* This is only valid for user addresses (which are below 2^41) */
+static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
+{
+	return vsid_scramble((context << USER_ESID_BITS)
+			     | (ea >> SID_SHIFT));
+}
+
+#endif /* __ASSEMBLY */
+
 #endif /* _PPC64_MMU_H_ */
diff --git a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h
--- a/include/asm-ppc64/mmu_context.h
+++ b/include/asm-ppc64/mmu_context.h
@@ -59,11 +59,11 @@ static inline void switch_mm(struct mm_s
 		return;
 
 #ifdef CONFIG_ALTIVEC
-	if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		asm volatile ("dssall");
 #endif /* CONFIG_ALTIVEC */
 
-	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
+	if (cpu_has_feature(CPU_FTR_SLB))
 		switch_slb(tsk, next);
 	else
 		switch_stab(tsk, next);
@@ -84,86 +84,4 @@ static inline void activate_mm(struct mm
 	local_irq_restore(flags);
 }
 
-/* VSID allocation
- * ===============
- *
- * We first generate a 36-bit "proto-VSID".  For kernel addresses this
- * is equal to the ESID, for user addresses it is:
- *	(context << 15) | (esid & 0x7fff)
- *
- * The two forms are distinguishable because the top bit is 0 for user
- * addresses, whereas the top two bits are 1 for kernel addresses.
- * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
- * now.
- *
- * The proto-VSIDs are then scrambled into real VSIDs with the
- * multiplicative hash:
- *
- *	VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
- *	where	VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
- *		VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
- *
- * This scramble is only well defined for proto-VSIDs below
- * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
- * reserved.  VSID_MULTIPLIER is prime, so in particular it is
- * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
- * Because the modulus is 2^n-1 we can compute it efficiently without
- * a divide or extra multiply (see below).
- *
- * This scheme has several advantages over older methods:
- *
- * 	- We have VSIDs allocated for every kernel address
- * (i.e. everything above 0xC000000000000000), except the very top
- * segment, which simplifies several things.
- *
- * 	- We allow for 15 significant bits of ESID and 20 bits of
- * context for user addresses.  i.e. 8T (43 bits) of address space for
- * up to 1M contexts (although the page table structure and context
- * allocation will need changes to take advantage of this).
- *
- * 	- The scramble function gives robust scattering in the hash
- * table (at least based on some initial results).  The previous
- * method was more susceptible to pathological cases giving excessive
- * hash collisions.
- */
-
-/*
- * WARNING - If you change these you must make sure the asm
- * implementations in slb_allocate(), do_stab_bolted and mmu.h
- * (ASM_VSID_SCRAMBLE macro) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
- */
-
-static inline unsigned long vsid_scramble(unsigned long protovsid)
-{
-#if 0
-	/* The code below is equivalent to this function for arguments
-	 * < 2^VSID_BITS, which is all this should ever be called
-	 * with.  However gcc is not clever enough to compute the
-	 * modulus (2^n-1) without a second multiply. */
-	return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
-#else /* 1 */
-	unsigned long x;
-
-	x = protovsid * VSID_MULTIPLIER;
-	x = (x >> VSID_BITS) + (x & VSID_MODULUS);
-	return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
-#endif /* 1 */
-}
-
-/* This is only valid for addresses >= KERNELBASE */
-static inline unsigned long get_kernel_vsid(unsigned long ea)
-{
-	return vsid_scramble(ea >> SID_SHIFT);
-}
-
-/* This is only valid for user addresses (which are below 2^41) */
-static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
-{
-	return vsid_scramble((context << USER_ESID_BITS)
-			     | (ea >> SID_SHIFT));
-}
-
 #endif /* __PPC64_MMU_CONTEXT_H */
diff --git a/include/asm-ppc64/pSeries_reconfig.h b/include/asm-ppc64/pSeries_reconfig.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/pSeries_reconfig.h
@@ -0,0 +1,25 @@
+#ifndef _PPC64_PSERIES_RECONFIG_H
+#define _PPC64_PSERIES_RECONFIG_H
+
+#include <linux/notifier.h>
+
+/*
+ * Use this API if your code needs to know about OF device nodes being
+ * added or removed on pSeries systems.
+ */
+
+#define PSERIES_RECONFIG_ADD    0x0001
+#define PSERIES_RECONFIG_REMOVE 0x0002
+
+#ifdef CONFIG_PPC_PSERIES
+extern int pSeries_reconfig_notifier_register(struct notifier_block *);
+extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
+#else /* !CONFIG_PPC_PSERIES */
+static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
+{
+	return 0;
+}
+static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
+#endif /* CONFIG_PPC_PSERIES */
+
+#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h
--- a/include/asm-ppc64/paca.h
+++ b/include/asm-ppc64/paca.h
@@ -22,7 +22,6 @@
 #include	<asm/iSeries/ItLpRegSave.h>
 #include	<asm/mmu.h>
 
-extern struct paca_struct paca[];
 register struct paca_struct *local_paca asm("r13");
 #define get_paca()	local_paca
 
@@ -115,4 +114,6 @@ struct paca_struct {
 #endif
 };
 
+extern struct paca_struct paca[];
+
 #endif /* _PPC64_PACA_H */
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h
+++ b/include/asm-ppc64/page.h
@@ -23,7 +23,6 @@
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(ASM_CONST(1) << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
-#define PAGE_OFFSET_MASK (PAGE_SIZE-1)
 
 #define SID_SHIFT       28
 #define SID_MASK        0xfffffffffUL
@@ -48,8 +47,8 @@
 #define ARCH_HAS_HUGEPAGE_ONLY_RANGE
 #define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
 
-#define touches_hugepage_low_range(addr, len) \
-	(LOW_ESID_MASK((addr), (len)) & current->mm->context.htlb_segs)
+#define touches_hugepage_low_range(mm, addr, len) \
+	(LOW_ESID_MASK((addr), (len)) & mm->context.htlb_segs)
 #define touches_hugepage_high_range(addr, len) \
 	(((addr) > (TASK_HPAGE_BASE-(len))) && ((addr) < TASK_HPAGE_END))
 
@@ -61,13 +60,13 @@
 #define within_hugepage_high_range(addr, len) (((addr) >= TASK_HPAGE_BASE) \
 	  && ((addr)+(len) <= TASK_HPAGE_END) && ((addr)+(len) >= (addr)))
 
-#define is_hugepage_only_range(addr, len) \
+#define is_hugepage_only_range(mm, addr, len) \
 	(touches_hugepage_high_range((addr), (len)) || \
-	  touches_hugepage_low_range((addr), (len)))
+	  touches_hugepage_low_range((mm), (addr), (len)))
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
 #define in_hugepage_area(context, addr) \
-	((cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) && \
+	(cpu_has_feature(CPU_FTR_16M_PAGE) && \
 	 ( (((addr) >= TASK_HPAGE_BASE) && ((addr) < TASK_HPAGE_END)) || \
 	   ( ((addr) < 0x100000000L) && \
 	     ((1 << GET_ESID(addr)) & (context).htlb_segs) ) ) )
@@ -85,9 +84,6 @@
 /* align addr on a size boundary - adjust address up if needed */
 #define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
 
-/* to align the pointer to the (next) double word boundary */
-#define DOUBLEWORD_ALIGN(addr)	_ALIGN(addr,sizeof(unsigned long))
-
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
 
@@ -100,7 +96,6 @@
 #define REGION_SIZE   4UL
 #define REGION_SHIFT  60UL
 #define REGION_MASK   (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
-#define REGION_STRIDE (1UL << REGION_SHIFT)
 
 static __inline__ void clear_page(void *addr)
 {
@@ -185,6 +180,9 @@ extern int page_is_ram(unsigned long pfn
 
 extern u64 ppc64_pft_size;		/* Log 2 of page table size */
 
+/* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */
+#define __HAVE_ARCH_GATE_AREA		1
+
 #endif /* __ASSEMBLY__ */
 
 #ifdef MODULE
@@ -206,13 +204,13 @@ extern u64 ppc64_pft_size;		/* Log 2 of 
 #define VMALLOCBASE     ASM_CONST(0xD000000000000000)
 #define IOREGIONBASE    ASM_CONST(0xE000000000000000)
 
-#define IO_REGION_ID       (IOREGIONBASE>>REGION_SHIFT)
-#define VMALLOC_REGION_ID  (VMALLOCBASE>>REGION_SHIFT)
-#define KERNEL_REGION_ID   (KERNELBASE>>REGION_SHIFT)
+#define IO_REGION_ID       (IOREGIONBASE >> REGION_SHIFT)
+#define VMALLOC_REGION_ID  (VMALLOCBASE >> REGION_SHIFT)
+#define KERNEL_REGION_ID   (KERNELBASE >> REGION_SHIFT)
 #define USER_REGION_ID     (0UL)
-#define REGION_ID(X)	   (((unsigned long)(X))>>REGION_SHIFT)
+#define REGION_ID(ea)	   (((unsigned long)(ea)) >> REGION_SHIFT)
 
-#define __bpn_to_ba(x) ((((unsigned long)(x))<<PAGE_SHIFT) + KERNELBASE)
+#define __bpn_to_ba(x) ((((unsigned long)(x)) << PAGE_SHIFT) + KERNELBASE)
 #define __ba_to_bpn(x) ((((unsigned long)(x)) & ~REGION_MASK) >> PAGE_SHIFT)
 
 #define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
@@ -232,8 +230,36 @@ extern u64 ppc64_pft_size;		/* Log 2 of 
 
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+/*
+ * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
+ * and needs to be executable.  This means the whole heap ends
+ * up being executable.
+ */
+#define VM_DATA_DEFAULT_FLAGS32	(VM_READ | VM_WRITE | VM_EXEC | \
+				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_DATA_DEFAULT_FLAGS64	(VM_READ | VM_WRITE | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#define VM_DATA_DEFAULT_FLAGS \
+	(test_thread_flag(TIF_32BIT) ? \
+	 VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
+
+/*
+ * This is the default if a program doesn't have a PT_GNU_STACK
+ * program header entry. The PPC64 ELF ABI has a non executable stack
+ * stack by default, so in the absense of a PT_GNU_STACK program header
+ * we turn execute permission off.
+ */
+#define VM_STACK_DEFAULT_FLAGS32	(VM_READ | VM_WRITE | VM_EXEC | \
+					 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_STACK_DEFAULT_FLAGS64	(VM_READ | VM_WRITE | \
+					 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_STACK_DEFAULT_FLAGS \
+	(test_thread_flag(TIF_32BIT) ? \
+	 VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
+
 #endif /* __KERNEL__ */
 #endif /* _PPC64_PAGE_H */
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -13,11 +13,14 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
+
 #include <asm/machdep.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 
+#include <asm-generic/pci-dma-compat.h>
+
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
@@ -63,135 +66,22 @@ static inline int pcibios_prep_mwi(struc
 
 extern unsigned int pcibios_assign_all_busses(void);
 
-/*
- * PCI DMA operations are abstracted for G5 vs. i/pSeries
- */
-struct pci_dma_ops {
-	void *		(*pci_alloc_consistent)(struct pci_dev *hwdev, size_t size,
-					dma_addr_t *dma_handle);
-	void		(*pci_free_consistent)(struct pci_dev *hwdev, size_t size,
-				       void *vaddr, dma_addr_t dma_handle);
-
-	dma_addr_t	(*pci_map_single)(struct pci_dev *hwdev, void *ptr,
-					  size_t size, enum dma_data_direction direction);
-	void		(*pci_unmap_single)(struct pci_dev *hwdev, dma_addr_t dma_addr,
-					    size_t size, enum dma_data_direction direction);
-	int		(*pci_map_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
-				      int nents, enum dma_data_direction direction);
-	void		(*pci_unmap_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
-					int nents, enum dma_data_direction direction);
-	int		(*pci_dma_supported)(struct pci_dev *hwdev, u64 mask);
-	int		(*pci_dac_dma_supported)(struct pci_dev *hwdev, u64 mask);
-};
-
-extern struct pci_dma_ops pci_dma_ops;
-
-static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-					 dma_addr_t *dma_handle)
-{
-	return pci_dma_ops.pci_alloc_consistent(hwdev, size, dma_handle);
-}
-
-static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-				       void *vaddr, dma_addr_t dma_handle)
-{
-	pci_dma_ops.pci_free_consistent(hwdev, size, vaddr, dma_handle);
-}
-
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size, int direction)
-{
-	return pci_dma_ops.pci_map_single(hwdev, ptr, size,
-			(enum dma_data_direction)direction);
-}
-
-static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-				    size_t size, int direction)
-{
-	pci_dma_ops.pci_unmap_single(hwdev, dma_addr, size,
-			(enum dma_data_direction)direction);
-}
-
-static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents, int direction)
-{
-	return pci_dma_ops.pci_map_sg(hwdev, sg, nents,
-			(enum dma_data_direction)direction);
-}
-
-static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents, int direction)
-{
-	pci_dma_ops.pci_unmap_sg(hwdev, sg, nents,
-			(enum dma_data_direction)direction);
-}
-
-static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
-					       dma_addr_t dma_handle,
-					       size_t size, int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* nothing to do */
-}
-
-static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
-						  dma_addr_t dma_handle,
-						  size_t size, int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* nothing to do */
-}
-
-static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
-					   struct scatterlist *sg,
-					   int nelems, int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* nothing to do */
-}
-
-static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
-					      struct scatterlist *sg,
-					      int nelems, int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* nothing to do */
-}
-
-/* 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.
- * We default to supporting only 32 bits DMA unless we have
- * an explicit override of this function in pci_dma_ops for
- * the platform
- */
-static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
-	if (pci_dma_ops.pci_dma_supported)
-		return pci_dma_ops.pci_dma_supported(hwdev, mask);
-	return (mask < 0x100000000ull);
-}
+extern struct dma_mapping_ops pci_dma_ops;
 
 /* For DAC DMA, we currently don't support it by default, but
  * we let the platform override this
  */
 static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
 {
-	if (pci_dma_ops.pci_dac_dma_supported)
-		return pci_dma_ops.pci_dac_dma_supported(hwdev, mask);
+	if (pci_dma_ops.dac_dma_supported)
+		return pci_dma_ops.dac_dma_supported(&hwdev->dev, mask);
 	return 0;
 }
 
-static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
-{
-	return dma_mapping_error(dma_addr);
-}
-
 extern int pci_domain_nr(struct pci_bus *bus);
 
-/* Set the name of the bus as it appears in /proc/bus/pci */
-extern int pci_name_bus(char *name, struct pci_bus *bus);
+/* Decide whether to display the domain number in /proc */
+extern int pci_proc_domain(struct pci_bus *bus);
 
 struct vm_area_struct;
 /* Map a range of PCI memory or I/O space for a device into user space */
@@ -201,10 +91,6 @@ int pci_mmap_page_range(struct pci_dev *
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP	1
 
-#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)
-
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
 	dma_addr_t ADDR_NAME;
@@ -244,6 +130,13 @@ extern int pci_read_irq_line(struct pci_
 
 extern void pcibios_add_platform_entries(struct pci_dev *dev);
 
+struct file;
+extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
+					 unsigned long offset,
+					 unsigned long size,
+					 pgprot_t prot);
+
+
 #endif	/* __KERNEL__ */
 
 #endif /* __PPC64_PCI_H */
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
--- a/include/asm-ppc64/pgalloc.h
+++ b/include/asm-ppc64/pgalloc.h
@@ -5,9 +5,6 @@
 #include <linux/slab.h>
 #include <linux/cpumask.h>
 #include <linux/percpu.h>
-#include <asm/processor.h>
-#include <asm/tlb.h>
-#include <asm/page.h>
 
 extern kmem_cache_t *zero_cache;
 
@@ -30,7 +27,7 @@ pgd_free(pgd_t *pgd)
 	kmem_cache_free(zero_cache, pgd);
 }
 
-#define pgd_populate(MM, PGD, PMD)	pgd_set(PGD, PMD)
+#define pud_populate(MM, PUD, PMD)	pud_set(PUD, PMD)
 
 static inline pmd_t *
 pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
@@ -48,42 +45,26 @@ pmd_free(pmd_t *pmd)
 #define pmd_populate(mm, pmd, pte_page) \
 	pmd_populate_kernel(mm, pmd, page_address(pte_page))
 
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-	pte_t *pte;
-	pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
-	if (pte) {
-		struct page *ptepage = virt_to_page(pte);
-		ptepage->mapping = (void *) mm;
-		ptepage->index = address & PMD_MASK;
-	}
-	return pte;
-}
-
-static inline struct page *
-pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-	pte_t *pte;
-	pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
-	if (pte) {
-		struct page *ptepage = virt_to_page(pte);
-		ptepage->mapping = (void *) mm;
-		ptepage->index = address & PMD_MASK;
-		return ptepage;
-	}
+	return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
+	if (pte)
+		return virt_to_page(pte);
 	return NULL;
 }
 		
 static inline void pte_free_kernel(pte_t *pte)
 {
-	virt_to_page(pte)->mapping = NULL;
 	kmem_cache_free(zero_cache, pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	ptepage->mapping = NULL;
 	kmem_cache_free(zero_cache, page_address(ptepage));
 }
 
diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
--- a/include/asm-ppc64/pgtable.h
+++ b/include/asm-ppc64/pgtable.h
@@ -1,8 +1,6 @@
 #ifndef _PPC64_PGTABLE_H
 #define _PPC64_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
-
 /*
  * This file contains the functions and defines necessary to modify and use
  * the ppc64 hashed page table.
@@ -17,15 +15,7 @@
 #include <asm/tlbflush.h>
 #endif /* __ASSEMBLY__ */
 
-/* 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)
-#define PMD_MASK	(~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT - 3) + (PAGE_SHIFT - 2))
-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+#include <asm-generic/pgtable-nopud.h>
 
 /*
  * Entries per page directory level.  The PTE level must use a 64b record
@@ -40,40 +30,30 @@
 #define PTRS_PER_PMD	(1 << PMD_INDEX_SIZE)
 #define PTRS_PER_PGD	(1 << PGD_INDEX_SIZE)
 
-#define USER_PTRS_PER_PGD	(1024)
-#define FIRST_USER_PGD_NR	0
+/* PMD_SHIFT determines what a second-level page table entry can map */
+#define PMD_SHIFT	(PAGE_SHIFT + PTE_INDEX_SIZE)
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
 
-#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
-                    PGD_INDEX_SIZE + PAGE_SHIFT) 
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	(PMD_SHIFT + PMD_INDEX_SIZE)
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+#define FIRST_USER_ADDRESS	0
 
 /*
  * Size of EA range mapped by our pagetables.
  */
-#define PGTABLE_EA_BITS	41
-#define PGTABLE_EA_MASK	((1UL<<PGTABLE_EA_BITS)-1)
+#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+                    PGD_INDEX_SIZE + PAGE_SHIFT)
+#define EADDR_MASK ((1UL << EADDR_SIZE) - 1)
 
 /*
  * Define the address range of the vmalloc VM area.
  */
 #define VMALLOC_START (0xD000000000000000ul)
-#define VMALLOC_END   (VMALLOC_START + PGTABLE_EA_MASK)
-
-/*
- * Define the address range of the imalloc VM area.
- * (used for ioremap)
- */
-#define IMALLOC_START     (ioremap_bot)
-#define IMALLOC_VMADDR(x) ((unsigned long)(x))
-#define PHBS_IO_BASE  	  (0xE000000000000000ul)	/* Reserve 2 gigs for PHBs */
-#define IMALLOC_BASE      (0xE000000080000000ul)  
-#define IMALLOC_END       (IMALLOC_BASE + PGTABLE_EA_MASK)
-
-/*
- * Define the user address range
- */
-#define USER_START (0UL)
-#define USER_END   (USER_START + PGTABLE_EA_MASK)
-
+#define VMALLOC_END   (VMALLOC_START + EADDR_MASK)
 
 /*
  * Bits in a linux-style PTE.  These match the bits in the
@@ -82,14 +62,14 @@
 #define _PAGE_PRESENT	0x0001 /* software: pte contains a translation */
 #define _PAGE_USER	0x0002 /* matches one of the PP bits */
 #define _PAGE_FILE	0x0002 /* (!present only) software: pte holds file offset */
-#define _PAGE_RW	0x0004 /* software: user write access allowed */
+#define _PAGE_EXEC	0x0004 /* No execute on POWER4 and newer (we invert) */
 #define _PAGE_GUARDED	0x0008
 #define _PAGE_COHERENT	0x0010 /* M: enforce memory coherence (SMP systems) */
 #define _PAGE_NO_CACHE	0x0020 /* I: cache inhibit */
 #define _PAGE_WRITETHRU	0x0040 /* W: cache write-through */
 #define _PAGE_DIRTY	0x0080 /* C: page changed */
 #define _PAGE_ACCESSED	0x0100 /* R: page referenced */
-#define _PAGE_EXEC	0x0200 /* software: i-cache coherence required */
+#define _PAGE_RW	0x0200 /* software: user write access allowed */
 #define _PAGE_HASHPTE	0x0400 /* software: pte has an associated HPTE */
 #define _PAGE_BUSY	0x0800 /* software: PTE & hash are busy */ 
 #define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
@@ -118,29 +98,41 @@
 #define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_WRENABLE)
 #define PAGE_KERNEL_CI	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
 			       _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
+
+#define PAGE_AGP	__pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
+#define HAVE_PAGE_AGP
+
+/*
+ * This bit in a hardware PTE indicates that the page is *not* executable.
+ */
+#define HW_NO_EXEC	_PAGE_EXEC
 
 /*
- * The PowerPC can only do execute protection on a segment (256MB) basis,
- * not on a page basis.  So we consider execute permission the same as read.
+ * POWER4 and newer have per page execute protection, older chips can only
+ * do this on a segment (256MB) basis.
+ *
  * Also, write permissions imply read permissions.
  * This is the closest we can get..
+ *
+ * Note due to the way vm flags are laid out, the bits are XWR
  */
 #define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY_X
+#define __P001	PAGE_READONLY
 #define __P010	PAGE_COPY
-#define __P011	PAGE_COPY_X
-#define __P100	PAGE_READONLY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY_X
 #define __P101	PAGE_READONLY_X
-#define __P110	PAGE_COPY
+#define __P110	PAGE_COPY_X
 #define __P111	PAGE_COPY_X
 
 #define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY_X
+#define __S001	PAGE_READONLY
 #define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED_X
-#define __S100	PAGE_READONLY
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY_X
 #define __S101	PAGE_READONLY_X
-#define __S110	PAGE_SHARED
+#define __S110	PAGE_SHARED_X
 #define __S111	PAGE_SHARED_X
 
 #ifndef __ASSEMBLY__
@@ -156,10 +148,6 @@ extern unsigned long empty_zero_page[PAG
 /* shift to put page number into pte */
 #define PTE_SHIFT (17)
 
-/* We allow 2^41 bytes of real memory, so we need 29 bits in the PMD
- * to give the PTE page number.  The bottom two bits are for flags. */
-#define PMD_TO_PTEPAGE_SHIFT (2)
-
 #ifdef CONFIG_HUGETLB_PAGE
 
 #ifndef __ASSEMBLY__
@@ -188,13 +176,14 @@ void hugetlb_mm_free_pgd(struct mm_struc
  */
 #define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 
-#define pfn_pte(pfn,pgprot)						\
-({									\
-	pte_t pte;							\
-	pte_val(pte) = ((unsigned long)(pfn) << PTE_SHIFT) |   		\
-                        pgprot_val(pgprot);				\
-	pte;								\
-})
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+	pte_t pte;
+
+
+	pte_val(pte) = (pfn << PTE_SHIFT) | pgprot_val(pgprot);
+	return pte;
+}
 
 #define pte_modify(_pte, newprot) \
   (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
@@ -208,20 +197,20 @@ void hugetlb_mm_free_pgd(struct mm_struc
 #define pte_page(x)		pfn_to_page(pte_pfn(x))
 
 #define pmd_set(pmdp, ptep) 	\
-	(pmd_val(*(pmdp)) = (__ba_to_bpn(ptep) << PMD_TO_PTEPAGE_SHIFT))
+	(pmd_val(*(pmdp)) = __ba_to_bpn(ptep))
 #define pmd_none(pmd)		(!pmd_val(pmd))
 #define	pmd_bad(pmd)		(pmd_val(pmd) == 0)
 #define	pmd_present(pmd)	(pmd_val(pmd) != 0)
 #define	pmd_clear(pmdp)		(pmd_val(*(pmdp)) = 0)
-#define pmd_page_kernel(pmd)	\
-	(__bpn_to_ba(pmd_val(pmd) >> PMD_TO_PTEPAGE_SHIFT))
+#define pmd_page_kernel(pmd)	(__bpn_to_ba(pmd_val(pmd)))
 #define pmd_page(pmd)		virt_to_page(pmd_page_kernel(pmd))
-#define pgd_set(pgdp, pmdp)	(pgd_val(*(pgdp)) = (__ba_to_bpn(pmdp)))
-#define pgd_none(pgd)		(!pgd_val(pgd))
-#define pgd_bad(pgd)		((pgd_val(pgd)) == 0)
-#define pgd_present(pgd)	(pgd_val(pgd) != 0UL)
-#define pgd_clear(pgdp)		(pgd_val(*(pgdp)) = 0UL)
-#define pgd_page(pgd)		(__bpn_to_ba(pgd_val(pgd))) 
+
+#define pud_set(pudp, pmdp)	(pud_val(*(pudp)) = (__ba_to_bpn(pmdp)))
+#define pud_none(pud)		(!pud_val(pud))
+#define pud_bad(pud)		((pud_val(pud)) == 0UL)
+#define pud_present(pud)	(pud_val(pud) != 0UL)
+#define pud_clear(pudp)		(pud_val(*(pudp)) = 0UL)
+#define pud_page(pud)		(__bpn_to_ba(pud_val(pud)))
 
 /* 
  * Find an entry in a page-table-directory.  We combine the address region 
@@ -233,12 +222,13 @@ void hugetlb_mm_free_pgd(struct mm_struc
 #define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(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)))
+#define pmd_offset(pudp,addr) \
+  ((pmd_t *) pud_page(*(pudp)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
 
 /* Find an entry in the third-level page table.. */
 #define pte_offset_kernel(dir,addr) \
-  ((pte_t *) pmd_page_kernel(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+  ((pte_t *) pmd_page_kernel(*(dir)) \
+ + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 
 #define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
 #define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir), (addr))
@@ -252,8 +242,6 @@ void hugetlb_mm_free_pgd(struct mm_struc
 /* to find an entry in the ioremap page-table-directory */
 #define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
 
-#define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
-
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -315,9 +303,10 @@ static inline unsigned long pte_update(p
  * batch, doesn't actually triggers the hash flush immediately,
  * you need to call flush_tlb_pending() to do that.
  */
-extern void hpte_update(pte_t *ptep, unsigned long pte, int wrprot);
+extern void hpte_update(struct mm_struct *mm, unsigned long addr, unsigned long pte,
+			int wrprot);
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int __ptep_test_and_clear_young(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long old;
 
@@ -325,18 +314,25 @@ static inline int ptep_test_and_clear_yo
 		return 0;
 	old = pte_update(ptep, _PAGE_ACCESSED);
 	if (old & _PAGE_HASHPTE) {
-		hpte_update(ptep, old, 0);
+		hpte_update(mm, addr, old, 0);
 		flush_tlb_pending();
 	}
 	return (old & _PAGE_ACCESSED) != 0;
 }
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(__vma, __addr, __ptep)		   \
+({									   \
+	int __r;							   \
+	__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
+	__r;								   \
+})
 
 /*
  * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
  * moment we always flush but we need to fix hpte_update and test if the
  * optimisation is worth it.
  */
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long old;
 
@@ -344,11 +340,19 @@ static inline int ptep_test_and_clear_di
 		return 0;
 	old = pte_update(ptep, _PAGE_DIRTY);
 	if (old & _PAGE_HASHPTE)
-		hpte_update(ptep, old, 0);
+		hpte_update(mm, addr, old, 0);
 	return (old & _PAGE_DIRTY) != 0;
 }
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define ptep_test_and_clear_dirty(__vma, __addr, __ptep)		   \
+({									   \
+	int __r;							   \
+	__r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
+	__r;								   \
+})
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long old;
 
@@ -356,7 +360,7 @@ static inline void ptep_set_wrprotect(pt
        		return;
 	old = pte_update(ptep, _PAGE_RW);
 	if (old & _PAGE_HASHPTE)
-		hpte_update(ptep, old, 0);
+		hpte_update(mm, addr, old, 0);
 }
 
 /*
@@ -370,45 +374,49 @@ static inline void ptep_set_wrprotect(pt
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
 #define ptep_clear_flush_young(__vma, __address, __ptep)		\
 ({									\
-	int __young = ptep_test_and_clear_young(__ptep);		\
+	int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
+						  __ptep);		\
 	__young;							\
 })
 
 #define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
 #define ptep_clear_flush_dirty(__vma, __address, __ptep)		\
 ({									\
-	int __dirty = ptep_test_and_clear_dirty(__ptep);		\
+	int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
+						  __ptep); 		\
 	flush_tlb_page(__vma, __address);				\
 	__dirty;							\
 })
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long old = pte_update(ptep, ~0UL);
 
 	if (old & _PAGE_HASHPTE)
-		hpte_update(ptep, old, 0);
+		hpte_update(mm, addr, old, 0);
 	return __pte(old);
 }
 
-static inline void pte_clear(pte_t * ptep)
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t * ptep)
 {
 	unsigned long old = pte_update(ptep, ~0UL);
 
 	if (old & _PAGE_HASHPTE)
-		hpte_update(ptep, old, 0);
+		hpte_update(mm, addr, old, 0);
 }
 
 /*
  * set_pte stores a linux PTE into the linux page table.
  */
-static inline void set_pte(pte_t *ptep, pte_t pte)
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pte)
 {
 	if (pte_present(*ptep)) {
-		pte_clear(ptep);
+		pte_clear(mm, addr, ptep);
 		flush_tlb_pending();
 	}
-	*ptep = __pte(pte_val(pte)) & ~_PAGE_HPTEFLAGS;
+	*ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
 }
 
 /* Set the dirty and/or accessed bits atomically in a linux PTE, this
@@ -418,7 +426,7 @@ static inline void set_pte(pte_t *ptep, 
 static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
 {
 	unsigned long bits = pte_val(entry) &
-		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
+		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
 	unsigned long old, tmp;
 
 	__asm__ __volatile__(
@@ -443,28 +451,35 @@ static inline void __ptep_set_access_fla
  */
 #define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
 
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
 
 extern unsigned long ioremap_bot, ioremap_base;
 
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#define pte_ERROR(e) \
-	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
 	printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
 	printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e))
 
-extern pgd_t swapper_pg_dir[1024];
-extern pgd_t ioremap_dir[1024];
+extern pgd_t swapper_pg_dir[];
+extern pgd_t ioremap_dir[];
 
 extern void paging_init(void);
 
-struct mmu_gather;
-void hugetlb_free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
-			   unsigned long start, unsigned long end);
+/*
+ * Because the huge pgtables are only 2 level, they can take
+ * at most around 4M, much less than one hugepage which the
+ * process is presumably entitled to use.  So we don't bother
+ * freeing up the pagetables on unmap, and wait until
+ * destroy_context() to clean up the lot.
+ */
+#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \
+						do { } while (0)
 
 /*
  * This gets called at the end of handling a page fault, when
@@ -494,36 +509,11 @@ extern void update_mmu_cache(struct vm_a
  */
 #define kern_addr_valid(addr)	(1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
-		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
 void pgtable_cache_init(void);
 
-extern void hpte_init_native(void);
-extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
-
-/* imalloc region types */
-#define IM_REGION_UNUSED	0x1
-#define IM_REGION_SUBSET	0x2
-#define IM_REGION_EXISTS	0x4
-#define IM_REGION_OVERLAP	0x8
-#define IM_REGION_SUPERSET	0x10
-
-extern struct vm_struct * im_get_free_area(unsigned long size);
-extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
-			int region_type);
-unsigned long im_free(void *addr);
-
-extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
-				     unsigned long va, unsigned long prpn,
-				     int secondary, unsigned long hpteflags,
-				     int bolted, int large);
-
-extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
-			       unsigned long prpn, int secondary,
-			       unsigned long hpteflags, int bolted, int large);
-
 /*
  * find_linux_pte returns the address of a linux pte for a given 
  * effective address and directory.  If not found, it returns zero.
@@ -531,33 +521,30 @@ extern long native_hpte_insert(unsigned 
 static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
 {
 	pgd_t *pg;
+	pud_t *pu;
 	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_present(*pm)) { 
-			pt = pte_offset_kernel(pm, ea);
-			pte = *pt;
-			if (!pte_present(pte))
-				pt = NULL;
+		pu = pud_offset(pg, ea);
+		if (!pud_none(*pu)) {
+			pm = pmd_offset(pu, ea);
+			if (pmd_present(*pm)) {
+				pt = pte_offset_kernel(pm, ea);
+				pte = *pt;
+				if (!pte_present(pte))
+					pt = NULL;
+			}
 		}
 	}
 
 	return pt;
 }
 
-#endif /* __ASSEMBLY__ */
-
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
-#define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
+#endif /* __ASSEMBLY__ */
+
 #endif /* _PPC64_PGTABLE_H */
diff --git a/include/asm-ppc64/pmc.h b/include/asm-ppc64/pmc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/pmc.h
@@ -0,0 +1,29 @@
+/*
+ * pmc.h
+ * Copyright (C) 2004  David Gibson, 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
+ */
+#ifndef _PPC64_PMC_H
+#define _PPC64_PMC_H
+
+#include <asm/ptrace.h>
+
+typedef void (*perf_irq_t)(struct pt_regs *);
+
+int reserve_pmc_hardware(perf_irq_t new_perf_irq);
+void release_pmc_hardware(void);
+
+#endif /* _PPC64_PMC_H */
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -120,98 +120,18 @@
 
 /* Special Purpose Registers (SPRNs)*/
 
-#define	SPRN_CDBCR	0x3D7	/* Cache Debug Control Register */
 #define	SPRN_CTR	0x009	/* Count Register */
 #define	SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
-#define	SPRN_DAC1	0x3F6	/* Data Address Compare 1 */
-#define	SPRN_DAC2	0x3F7	/* Data Address Compare 2 */
+#define   DABR_TRANSLATION	(1UL << 2)
 #define	SPRN_DAR	0x013	/* Data Address Register */
-#define	SPRN_DBCR	0x3F2	/* Debug Control Regsiter */
-#define	  DBCR_EDM	0x80000000
-#define	  DBCR_IDM	0x40000000
-#define	  DBCR_RST(x)	(((x) & 0x3) << 28)
-#define	    DBCR_RST_NONE       	0
-#define	    DBCR_RST_CORE       	1
-#define	    DBCR_RST_CHIP       	2
-#define	    DBCR_RST_SYSTEM		3
-#define	  DBCR_IC	0x08000000	/* Instruction Completion Debug Evnt */
-#define	  DBCR_BT	0x04000000	/* Branch Taken Debug Event */
-#define	  DBCR_EDE	0x02000000	/* Exception Debug Event */
-#define	  DBCR_TDE	0x01000000	/* TRAP Debug Event */
-#define	  DBCR_FER	0x00F80000	/* First Events Remaining Mask */
-#define	  DBCR_FT	0x00040000	/* Freeze Timers on Debug Event */
-#define	  DBCR_IA1	0x00020000	/* Instr. Addr. Compare 1 Enable */
-#define	  DBCR_IA2	0x00010000	/* Instr. Addr. Compare 2 Enable */
-#define	  DBCR_D1R	0x00008000	/* Data Addr. Compare 1 Read Enable */
-#define	  DBCR_D1W	0x00004000	/* Data Addr. Compare 1 Write Enable */
-#define	  DBCR_D1S(x)	(((x) & 0x3) << 12)	/* Data Adrr. Compare 1 Size */
-#define	    DAC_BYTE	0
-#define	    DAC_HALF	1
-#define	    DAC_WORD	2
-#define	    DAC_QUAD	3
-#define	  DBCR_D2R	0x00000800	/* Data Addr. Compare 2 Read Enable */
-#define	  DBCR_D2W	0x00000400	/* Data Addr. Compare 2 Write Enable */
-#define	  DBCR_D2S(x)	(((x) & 0x3) << 8)	/* Data Addr. Compare 2 Size */
-#define	  DBCR_SBT	0x00000040	/* Second Branch Taken Debug Event */
-#define	  DBCR_SED	0x00000020	/* Second Exception Debug Event */
-#define	  DBCR_STD	0x00000010	/* Second Trap Debug Event */
-#define	  DBCR_SIA	0x00000008	/* Second IAC Enable */
-#define	  DBCR_SDA	0x00000004	/* Second DAC Enable */
-#define	  DBCR_JOI	0x00000002	/* JTAG Serial Outbound Int. Enable */
-#define	  DBCR_JII	0x00000001	/* JTAG Serial Inbound Int. Enable */
-#define	SPRN_DBCR0	0x3F2	/* Debug Control Register 0 */
-#define	SPRN_DBCR1	0x3BD	/* Debug Control Register 1 */
-#define	SPRN_DBSR	0x3F0	/* Debug Status Register */
-#define	SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
-#define	  DCCR_NOCACHE		0	/* Noncacheable */
-#define	  DCCR_CACHE		1	/* Cacheable */
-#define	SPRN_DCMP	0x3D1	/* Data TLB Compare Register */
-#define	SPRN_DCWR	0x3BA	/* Data Cache Write-thru Register */
-#define	  DCWR_COPY		0	/* Copy-back */
-#define	  DCWR_WRITE		1	/* Write-through */
-#define	SPRN_DEAR	0x3D5	/* Data Error Address Register */
 #define	SPRN_DEC	0x016	/* Decrement Register */
-#define	SPRN_DMISS	0x3D0	/* Data TLB Miss Register */
 #define	SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
-#define	SPRN_EAR	0x11A	/* External Address Register */
-#define	SPRN_ESR	0x3D4	/* Exception Syndrome Register */
-#define	  ESR_IMCP	0x80000000	/* Instr. Machine Check - Protection */
-#define	  ESR_IMCN	0x40000000	/* Instr. Machine Check - Non-config */
-#define	  ESR_IMCB	0x20000000	/* Instr. Machine Check - Bus error */
-#define	  ESR_IMCT	0x10000000	/* Instr. Machine Check - Timeout */
-#define	  ESR_PIL	0x08000000	/* Program Exception - Illegal */
-#define	  ESR_PPR	0x04000000	/* Program Exception - Priveleged */
-#define	  ESR_PTR	0x02000000	/* Program Exception - Trap */
-#define	  ESR_DST	0x00800000	/* Storage Exception - Data miss */
-#define	  ESR_DIZ	0x00400000	/* Storage Exception - Zone fault */
-#define	SPRN_EVPR	0x3D6	/* Exception Vector Prefix Register */
-#define	SPRN_HASH1	0x3D2	/* Primary Hash Address Register */
-#define	SPRN_HASH2	0x3D3	/* Secondary Hash Address Resgister */
+#define   DSISR_NOHPTE		0x40000000	/* no translation found */
+#define   DSISR_PROTFAULT	0x08000000	/* protection fault */
+#define   DSISR_ISSTORE		0x02000000	/* access was a store */
+#define   DSISR_DABRMATCH	0x00400000	/* hit data breakpoint */
+#define   DSISR_NOSEGMENT	0x00200000	/* STAB/SLB miss */
 #define	SPRN_HID0	0x3F0	/* Hardware Implementation Register 0 */
-#define	  HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
-#define	  HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
-#define	  HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
-#define	  HID0_SBCLK	(1<<27)
-#define	  HID0_EICE	(1<<26)
-#define	  HID0_ECLK	(1<<25)
-#define	  HID0_PAR	(1<<24)
-#define	  HID0_DOZE	(1<<23)
-#define	  HID0_NAP	(1<<22)
-#define	  HID0_SLEEP	(1<<21)
-#define	  HID0_DPM	(1<<20)
-#define	  HID0_ICE	(1<<15)		/* Instruction Cache Enable */
-#define	  HID0_DCE	(1<<14)		/* Data Cache Enable */
-#define	  HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
-#define	  HID0_DLOCK	(1<<12)		/* Data Cache Lock */
-#define	  HID0_ICFI	(1<<11)		/* Instr. Cache Flash Invalidate */
-#define	  HID0_DCI	(1<<10)		/* Data Cache Invalidate */
-#define   HID0_SPD	(1<<9)		/* Speculative disable */
-#define   HID0_SGE	(1<<7)		/* Store Gathering Enable */
-#define	  HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
-#define   HID0_BTIC	(1<<5)		/* Branch Target Instruction Cache Enable */
-#define   HID0_ABE	(1<<3)		/* Address Broadcast Enable */
-#define	  HID0_BHTE	(1<<2)		/* Branch History Table Enable */
-#define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
 #define	SPRN_MSRDORM	0x3F1	/* Hardware Implementation Register 1 */
 #define SPRN_HID1	0x3F1	/* Hardware Implementation Register 1 */
 #define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
@@ -220,23 +140,8 @@
 #define SPRN_HID5	0x3F6	/* 970 HID5 */
 #define	SPRN_TSC 	0x3FD	/* Thread switch control */
 #define	SPRN_TST 	0x3FC	/* Thread switch timeout */
-#define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
-#define	SPRN_IAC2	0x3F5	/* Instruction Address Compare 2 */
-#define	SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
-#define	  ICCR_NOCACHE		0	/* Noncacheable */
-#define	  ICCR_CACHE		1	/* Cacheable */
-#define	SPRN_ICDBDR	0x3D3	/* Instruction Cache Debug Data Register */
-#define	SPRN_ICMP	0x3D5	/* Instruction TLB Compare Register */
-#define	SPRN_ICTC	0x3FB	/* Instruction Cache Throttling Control Reg */
-#define	SPRN_IMISS	0x3D4	/* Instruction TLB Miss Register */
-#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_PBL1	0x3FC	/* Protection Bound Lower 1 */
-#define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
-#define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
-#define	SPRN_PBU2	0x3FF	/* Protection Bound Upper 2 */
-#define	SPRN_PID	0x3B1	/* Process ID */
 #define	SPRN_PIR	0x3FF	/* Processor Identification Register */
 #define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
 #define	SPRN_PURR	0x135	/* Processor Utilization of Resources Register */
@@ -244,9 +149,6 @@
 #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 */
@@ -259,50 +161,12 @@
 #define	SPRN_TBWL	0x11C	/* Time Base Lower Register (super, W/O) */
 #define	SPRN_TBWU	0x11D	/* Time Base Write Upper Register (super, W/O) */
 #define SPRN_HIOR	0x137	/* 970 Hypervisor interrupt offset */
-#define	SPRN_TCR	0x3DA	/* Timer Control Register */
-#define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
-#define	    WP_2_17		0		/* 2^17 clocks */
-#define	    WP_2_21		1		/* 2^21 clocks */
-#define	    WP_2_25		2		/* 2^25 clocks */
-#define	    WP_2_29		3		/* 2^29 clocks */
-#define	  TCR_WRC(x)		(((x)&0x3)<<28)	/* WDT Reset Control */
-#define	    WRC_NONE		0		/* No reset will occur */
-#define	    WRC_CORE		1		/* Core reset will occur */
-#define	    WRC_CHIP		2		/* Chip reset will occur */
-#define	    WRC_SYSTEM		3		/* System reset will occur */
-#define	  TCR_WIE		0x08000000	/* WDT Interrupt Enable */
-#define	  TCR_PIE		0x04000000	/* PIT Interrupt Enable */
-#define	  TCR_FP(x)		(((x)&0x3)<<24)	/* FIT Period */
-#define	    FP_2_9		0		/* 2^9 clocks */
-#define	    FP_2_13		1		/* 2^13 clocks */
-#define	    FP_2_17		2		/* 2^17 clocks */
-#define	    FP_2_21		3		/* 2^21 clocks */
-#define	  TCR_FIE		0x00800000	/* FIT Interrupt Enable */
-#define	  TCR_ARE		0x00400000	/* Auto Reload Enable */
-#define	SPRN_THRM1	0x3FC	/* Thermal Management Register 1 */
-#define	  THRM1_TIN		(1<<0)
-#define	  THRM1_TIV		(1<<1)
-#define	  THRM1_THRES		(0x7f<<2)
-#define	  THRM1_TID		(1<<29)
-#define	  THRM1_TIE		(1<<30)
-#define	  THRM1_V		(1<<31)
-#define	SPRN_THRM2	0x3FD	/* Thermal Management Register 2 */
-#define	SPRN_THRM3	0x3FE	/* Thermal Management Register 3 */
-#define	  THRM3_E		(1<<31)
-#define	SPRN_TSR	0x3D8	/* Timer Status Register */
-#define	  TSR_ENW		0x80000000	/* Enable Next Watchdog */
-#define	  TSR_WIS		0x40000000	/* WDT Interrupt Status */
-#define	  TSR_WRS(x)		(((x)&0x3)<<28)	/* WDT Reset Status */
-#define	    WRS_NONE		0		/* No WDT reset occurred */
-#define	    WRS_CORE		1		/* WDT forced core reset */
-#define	    WRS_CHIP		2		/* WDT forced chip reset */
-#define	    WRS_SYSTEM		3		/* WDT forced system reset */
-#define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
-#define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
 #define	SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
 #define	SPRN_XER	0x001	/* Fixed Point Exception Register */
-#define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
 #define SPRN_VRSAVE     0x100   /* Vector save */
+#define SPRN_CTRLF	0x088
+#define SPRN_CTRLT	0x098
+#define   CTRL_RUNLATCH	0x1
 
 /* Performance monitor SPRs */
 #define SPRN_SIAR	780
@@ -347,28 +211,19 @@
 #define	CTR	SPRN_CTR	/* Counter Register */
 #define	DAR	SPRN_DAR	/* Data Address Register */
 #define	DABR	SPRN_DABR	/* Data Address Breakpoint Register */
-#define	DCMP	SPRN_DCMP      	/* Data TLB Compare Register */
 #define	DEC	SPRN_DEC       	/* Decrement Register */
-#define	DMISS	SPRN_DMISS     	/* Data TLB Miss Register */
 #define	DSISR	SPRN_DSISR	/* Data Storage Interrupt Status Register */
-#define	EAR	SPRN_EAR       	/* External Address Register */
-#define	HASH1	SPRN_HASH1	/* Primary Hash Address Register */
-#define	HASH2	SPRN_HASH2	/* Secondary Hash Address Register */
 #define	HID0	SPRN_HID0	/* Hardware Implementation Register 0 */
 #define	MSRDORM	SPRN_MSRDORM	/* MSR Dormant Register */
 #define	NIADORM	SPRN_NIADORM	/* NIA Dormant Register */
 #define	TSC    	SPRN_TSC 	/* Thread switch control */
 #define	TST    	SPRN_TST 	/* Thread switch timeout */
 #define	IABR	SPRN_IABR      	/* Instruction Address Breakpoint 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 */
 #define	L2CR	SPRN_L2CR    	/* PPC 750 L2 control register */
 #define	__LR	SPRN_LR
 #define	PVR	SPRN_PVR	/* Processor Version */
 #define	PIR	SPRN_PIR	/* Processor ID */
 #define	PURR	SPRN_PURR	/* Processor Utilization of Resource Register */
-//#define	RPA	SPRN_RPA	/* Required Physical Address Register */
 #define	SDR1	SPRN_SDR1      	/* MMU hash base register */
 #define	SPR0	SPRN_SPRG0	/* Supervisor Private Registers */
 #define	SPR1	SPRN_SPRG1
@@ -384,10 +239,6 @@
 #define	TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
 #define	TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
 #define	TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
-#define ICTC	1019
-#define	THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
-#define	THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
-#define	THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
 #define	XER	SPRN_XER
 
 /* Processor Version Register (PVR) field extraction */
@@ -431,12 +282,6 @@
 #define XGLUE(a,b) a##b
 #define GLUE(a,b) XGLUE(a,b)
 
-/* iSeries CTRL register (for runlatch) */
-
-#define CTRLT		0x098
-#define CTRLF		0x088
-#define RUNLATCH	0x0001
-
 #ifdef __ASSEMBLY__
 
 #define _GLOBAL(name) \
@@ -537,15 +382,11 @@ extern struct task_struct *last_task_use
 #define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
 		TASK_SIZE_USER32 : TASK_SIZE_USER64)
 
-/* We can't actually tell the TASK_SIZE given just the mm, but default
- * to the 64-bit case to make sure that enough gets cleaned up. */
-#define MM_VM_SIZE(mm)	TASK_SIZE_USER64
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(STACK_TOP_USER32 / 4))
-#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(STACK_TOP_USER64 / 4))
+#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4))
+#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4))
 
 #define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \
 		TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
@@ -562,7 +403,9 @@ struct thread_struct {
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr;		/* Floating point status (plus pad) */
 	unsigned long	fpexc_mode;	/* Floating-point exception mode */
-	unsigned long	pad[3];		/* was saved_msr, saved_softe */
+	unsigned long	start_tb;	/* Start purr when proc switched in */
+	unsigned long	accum_tb;	/* Total accumilated purr for process */
+	unsigned long	vdso_base;	/* base of the vDSO library */
 #ifdef CONFIG_ALTIVEC
 	/* Complete AltiVec register set */
 	vector128	vr[32] __attribute((aligned(16)));
@@ -635,11 +478,17 @@ static inline unsigned long __pack_fe01(
 
 static inline void prefetch(const void *x)
 {
+	if (unlikely(!x))
+		return;
+
 	__asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
 }
 
 static inline void prefetchw(const void *x)
 {
+	if (unlikely(!x))
+		return;
+
 	__asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
 }
 
@@ -647,6 +496,24 @@ static inline void prefetchw(const void 
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
+static inline void ppc64_runlatch_on(void)
+{
+	unsigned long ctrl;
+
+	ctrl = mfspr(SPRN_CTRLF);
+	ctrl |= CTRL_RUNLATCH;
+	mtspr(SPRN_CTRLT, ctrl);
+}
+
+static inline void ppc64_runlatch_off(void)
+{
+	unsigned long ctrl;
+
+	ctrl = mfspr(SPRN_CTRLF);
+	ctrl &= ~CTRL_RUNLATCH;
+	mtspr(SPRN_CTRLT, ctrl);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
--- a/include/asm-ppc64/prom.h
+++ b/include/asm-ppc64/prom.h
@@ -137,6 +137,7 @@ struct device_node {
 	int	devfn;			/* for pci devices */
 	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
 	int	eeh_config_addr;
+	int	pci_ext_config_space;	/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
 	struct	iommu_table *iommu_table;	/* for phb's or bridges */
 
@@ -146,9 +147,7 @@ struct device_node {
 	struct	device_node *sibling;
 	struct	device_node *next;	/* next device of same type */
 	struct	device_node *allnext;	/* next in list of all nodes */
-	struct  proc_dir_entry *pde;       /* this node's proc directory */
-	struct  proc_dir_entry *name_link; /* name symlink */
-	struct  proc_dir_entry *addr_link; /* addr symlink */
+	struct  proc_dir_entry *pde;	/* this node's proc directory */
 	struct  kref kref;
 	unsigned long _flags;
 };
@@ -173,15 +172,6 @@ static inline void set_node_proc_entry(s
 	dn->pde = de;
 }
 
-static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de)
-{
-	dn->name_link = de;
-}
-
-static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de)
-{
-	dn->addr_link = de;
-}
 
 /* OBSOLETE: Old stlye node lookup */
 extern struct device_node *find_devices(const char *name);
@@ -208,8 +198,8 @@ extern struct device_node *of_node_get(s
 extern void of_node_put(struct device_node *node);
 
 /* For updating the device tree at runtime */
-extern int of_add_node(const char *path, struct property *proplist);
-extern int of_remove_node(struct device_node *np);
+extern void of_attach_node(struct device_node *);
+extern void of_detach_node(const struct device_node *);
 
 /* Other Prototypes */
 extern unsigned long prom_init(unsigned long, unsigned long, unsigned long,
diff --git a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h
--- a/include/asm-ppc64/rtas.h
+++ b/include/asm-ppc64/rtas.h
@@ -24,12 +24,9 @@
 
 /* RTAS return status codes */
 #define RTAS_BUSY		-2    /* RTAS Busy */
-#define RTAS_NO_SUCH_INDICATOR	-3    /* No such indicator implemented */
 #define RTAS_EXTENDED_DELAY_MIN	9900
 #define RTAS_EXTENDED_DELAY_MAX	9905
 
-#define RTAS_UNKNOWN_OP		-1099 /* Unknown RTAS Token */
-
 /*
  * In general to call RTAS use rtas_token("string") to lookup
  * an RTAS token for the given string (e.g. "event-scan").
diff --git a/include/asm-ppc64/seccomp.h b/include/asm-ppc64/seccomp.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/seccomp.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h> /* already defines TIF_32BIT */
+
+#ifndef TIF_32BIT
+#error "unexpected TIF_32BIT on ppc64"
+#endif
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+
+#define __NR_seccomp_read_32 __NR_read
+#define __NR_seccomp_write_32 __NR_write
+#define __NR_seccomp_exit_32 __NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/include/asm-ppc64/sections.h b/include/asm-ppc64/sections.h
--- a/include/asm-ppc64/sections.h
+++ b/include/asm-ppc64/sections.h
@@ -17,4 +17,13 @@ extern char _end[];
 #define __openfirmware
 #define __openfirmwaredata
 
+
+static inline int in_kernel_text(unsigned long addr)
+{
+	if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end)
+		return 1;
+
+	return 0;
+}
+
 #endif
diff --git a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h
--- a/include/asm-ppc64/signal.h
+++ b/include/asm-ppc64/signal.h
@@ -96,47 +96,20 @@ typedef struct {
 
 #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 __sigfunction(int);
-typedef __sigfunction __user * __sighandler_t;
-
-/* Type of the restorer function */
-typedef void __sigrestorer(void);
-typedef __sigrestorer __user * __sigrestorer_t;
-
-#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 */
+#include <asm-generic/signal.h>
 
 struct old_sigaction {
 	__sighandler_t sa_handler;
 	old_sigset_t sa_mask;
 	unsigned long sa_flags;
-	__sigrestorer_t sa_restorer;
+	__sigrestore_t sa_restorer;
 };
 
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
-	__sigrestorer_t sa_restorer;
+	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
 
diff --git a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h
--- a/include/asm-ppc64/smp.h
+++ b/include/asm-ppc64/smp.h
@@ -29,7 +29,7 @@
 extern int boot_cpuid;
 extern int boot_cpuid_phys;
 
-extern void cpu_die(void) __attribute__((noreturn));
+extern void cpu_die(void);
 
 #ifdef CONFIG_SMP
 
@@ -37,6 +37,13 @@ extern void smp_send_debugger_break(int 
 struct pt_regs;
 extern void smp_message_recv(int, struct pt_regs *);
 
+#ifdef CONFIG_HOTPLUG_CPU
+extern void fixup_irqs(cpumask_t map);
+int generic_cpu_disable(void);
+int generic_cpu_enable(unsigned int cpu);
+void generic_cpu_die(unsigned int cpu);
+void generic_mach_cpu_die(void);
+#endif
 
 #define __smp_processor_id() (get_paca()->paca_index)
 #define hard_smp_processor_id() (get_paca()->hw_cpu_id)
diff --git a/include/asm-ppc64/smu.h b/include/asm-ppc64/smu.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/smu.h
@@ -0,0 +1,22 @@
+/*
+ * Definitions for talking to the SMU chip in newer G5 PowerMacs
+ */
+
+#include <linux/config.h>
+
+/*
+ * Basic routines for use by architecture. To be extended as
+ * we understand more of the chip
+ */
+extern int smu_init(void);
+extern int smu_present(void);
+extern void smu_shutdown(void);
+extern void smu_restart(void);
+extern int smu_get_rtc_time(struct rtc_time *time);
+extern int smu_set_rtc_time(struct rtc_time *time);
+
+/*
+ * SMU command buffer absolute address, exported by pmac_setup,
+ * this is allocated very early during boot.
+ */
+extern unsigned long smu_cmdbuf_abs;
diff --git a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h
--- a/include/asm-ppc64/spinlock.h
+++ b/include/asm-ppc64/spinlock.h
@@ -110,7 +110,7 @@ static void __inline__ _raw_spin_lock(sp
 			HMT_low();
 			if (SHARED_PROCESSOR)
 				__spin_yield(lock);
-		} while (likely(lock->lock != 0));
+		} while (unlikely(lock->lock != 0));
 		HMT_medium();
 	}
 }
@@ -128,7 +128,7 @@ static void __inline__ _raw_spin_lock_fl
 			HMT_low();
 			if (SHARED_PROCESSOR)
 				__spin_yield(lock);
-		} while (likely(lock->lock != 0));
+		} while (unlikely(lock->lock != 0));
 		HMT_medium();
 		local_irq_restore(flags_dis);
 	}
@@ -194,7 +194,7 @@ static void __inline__ _raw_read_lock(rw
 			HMT_low();
 			if (SHARED_PROCESSOR)
 				__rw_yield(rw);
-		} while (likely(rw->lock < 0));
+		} while (unlikely(rw->lock < 0));
 		HMT_medium();
 	}
 }
@@ -251,7 +251,7 @@ static void __inline__ _raw_write_lock(r
 			HMT_low();
 			if (SHARED_PROCESSOR)
 				__rw_yield(rw);
-		} while (likely(rw->lock != 0));
+		} while (unlikely(rw->lock != 0));
 		HMT_medium();
 	}
 }
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
--- a/include/asm-ppc64/system.h
+++ b/include/asm-ppc64/system.h
@@ -300,5 +300,7 @@ __cmpxchg(volatile void *ptr, unsigned l
  */
 #define NET_IP_ALIGN   0
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 #endif
diff --git a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h
--- a/include/asm-ppc64/systemcfg.h
+++ b/include/asm-ppc64/systemcfg.h
@@ -20,10 +20,14 @@
  * Minor version changes are a hint.
  */
 #define SYSTEMCFG_MAJOR 1
-#define SYSTEMCFG_MINOR 0
+#define SYSTEMCFG_MINOR 1
 
 #ifndef __ASSEMBLY__
 
+#include <linux/unistd.h>
+
+#define SYSCALL_MAP_SIZE      ((__NR_syscalls + 31) / 32)
+
 struct systemcfg {
 	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
 	struct {			/* Systemcfg version numbers	     */
@@ -47,7 +51,8 @@ struct systemcfg {
 	__u32 dcache_line_size;		/* L1 d-cache line size		0x64 */
 	__u32 icache_size;		/* L1 i-cache size		0x68 */
 	__u32 icache_line_size;		/* L1 i-cache line size		0x6C */
-	__u8  reserved0[3984];		/* Reserve rest of page		0x70 */
+   	__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of available syscalls 0x70 */
+   	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of available syscalls */
 };
 
 #ifdef __KERNEL__
@@ -56,8 +61,4 @@ extern struct systemcfg *systemcfg;
 
 #endif /* __ASSEMBLY__ */
 
-#define SYSTEMCFG_PAGE      0x5
-#define SYSTEMCFG_PHYS_ADDR (SYSTEMCFG_PAGE<<PAGE_SHIFT)
-#define SYSTEMCFG_VIRT_ADDR (KERNELBASE+SYSTEMCFG_PHYS_ADDR)
-
 #endif /* _SYSTEMCFG_H */
diff --git a/include/asm-ppc64/thread_info.h b/include/asm-ppc64/thread_info.h
--- a/include/asm-ppc64/thread_info.h
+++ b/include/asm-ppc64/thread_info.h
@@ -96,11 +96,12 @@ static inline struct thread_info *curren
 #define TIF_POLLING_NRFLAG	4	/* true if poll_idle() is polling
 					   TIF_NEED_RESCHED */
 #define TIF_32BIT		5	/* 32 bit binary */
-#define TIF_RUN_LIGHT		6	/* iSeries run light */
+/* #define SPARE		6 */
 #define TIF_ABI_PENDING		7	/* 32/64 bit switch needed */
 #define TIF_SYSCALL_AUDIT	8	/* syscall auditing active */
 #define TIF_SINGLESTEP		9	/* singlestepping active */
 #define TIF_MEMDIE		10
+#define TIF_SECCOMP		11	/* secure computing */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -109,11 +110,12 @@ static inline struct thread_info *curren
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_32BIT		(1<<TIF_32BIT)
-#define _TIF_RUN_LIGHT		(1<<TIF_RUN_LIGHT)
+/* #define _SPARE		(1<<SPARE) */
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
 				 _TIF_NEED_RESCHED)
diff --git a/include/asm-ppc64/time.h b/include/asm-ppc64/time.h
--- a/include/asm-ppc64/time.h
+++ b/include/asm-ppc64/time.h
@@ -43,10 +43,10 @@ extern time_t last_rtc_update;
 struct gettimeofday_vars {
 	unsigned long tb_to_xs;
 	unsigned long stamp_xsec;
+	unsigned long tb_orig_stamp;
 };
 
 struct gettimeofday_struct {
-	unsigned long tb_orig_stamp;
 	unsigned long tb_ticks_per_sec;
 	struct gettimeofday_vars vars[2];
 	struct gettimeofday_vars * volatile varp;
@@ -102,5 +102,14 @@ static inline unsigned long tb_ticks_sin
 unsigned mulhwu_scale_factor(unsigned, unsigned);
 void div128_by_32( unsigned long dividend_high, unsigned long dividend_low,
 		   unsigned divisor, struct div_result *dr );
+
+/* Used to store Processor Utilization register (purr) values */
+
+struct cpu_usage {
+        u64 current_tb;  /* Holds the current purr register values */
+};
+
+DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
+
 #endif /* __KERNEL__ */
 #endif /* __PPC64_TIME_H */
diff --git a/include/asm-ppc64/uaccess.h b/include/asm-ppc64/uaccess.h
--- a/include/asm-ppc64/uaccess.h
+++ b/include/asm-ppc64/uaccess.h
@@ -56,7 +56,8 @@
 #define access_ok(type,addr,size) \
 	__access_ok(((__force unsigned long)(addr)),(size),get_fs())
 
-static inline int verify_area(int type, const void __user *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -119,6 +120,7 @@ extern long __put_user_bad(void);
 #define __put_user_nocheck(x,ptr,size)				\
 ({								\
 	long __pu_err;						\
+	might_sleep();						\
 	__chk_user_ptr(ptr);					\
 	__put_user_size((x),(ptr),(size),__pu_err,-EFAULT);	\
 	__pu_err;						\
@@ -128,6 +130,7 @@ extern long __put_user_bad(void);
 ({									\
 	long __pu_err = -EFAULT;					\
 	void __user *__pu_addr = (ptr);					\
+	might_sleep();							\
 	if (access_ok(VERIFY_WRITE,__pu_addr,size))			\
 		__put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT);	\
 	__pu_err;							\
@@ -135,7 +138,6 @@ extern long __put_user_bad(void);
 
 #define __put_user_size(x,ptr,size,retval,errret)			\
 do {									\
-	might_sleep();							\
 	retval = 0;							\
 	switch (size) {							\
 	  case 1: __put_user_asm(x,ptr,retval,"stb",errret); break;	\
@@ -170,6 +172,7 @@ do {									\
 #define __get_user_nocheck(x,ptr,size)				\
 ({								\
 	long __gu_err, __gu_val;				\
+	might_sleep();						\
 	__get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
 	(x) = (__typeof__(*(ptr)))__gu_val;			\
 	__gu_err;						\
@@ -179,6 +182,7 @@ do {									\
 ({									\
 	long __gu_err = -EFAULT, __gu_val = 0;				\
 	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);		\
+	might_sleep();							\
 	if (access_ok(VERIFY_READ,__gu_addr,size))			\
 		__get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT);\
 	(x) = (__typeof__(*(ptr)))__gu_val;				\
@@ -189,7 +193,6 @@ extern long __get_user_bad(void);
 
 #define __get_user_size(x,ptr,size,retval,errret)			\
 do {									\
-	might_sleep();							\
 	retval = 0;							\
 	__chk_user_ptr(ptr);						\
 	switch (size) {							\
@@ -223,9 +226,8 @@ extern unsigned long __copy_tofrom_user(
 					unsigned long size);
 
 static inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
-	might_sleep();
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
@@ -248,9 +250,15 @@ __copy_from_user(void *to, const void __
 }
 
 static inline unsigned long
-__copy_to_user(void __user *to, const void *from, unsigned long n)
+__copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	might_sleep();
+	return __copy_from_user_inatomic(to, from, n);
+}
+
+static inline unsigned long
+__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
+{
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
@@ -272,6 +280,13 @@ __copy_to_user(void __user *to, const vo
 	return __copy_tofrom_user(to, (__force const void __user *) from, n);
 }
 
+static inline unsigned long
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	might_sleep();
+	return __copy_to_user_inatomic(to, from, n);
+}
+
 #define __copy_in_user(to, from, size) \
 	__copy_tofrom_user((to), (from), (size))
 
@@ -284,9 +299,6 @@ extern unsigned long copy_in_user(void _
 
 extern unsigned long __clear_user(void __user *addr, unsigned long size);
 
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
-
 static inline unsigned long
 clear_user(void __user *addr, unsigned long size)
 {
diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h
+++ b/include/asm-ppc64/unistd.h
@@ -282,8 +282,9 @@
 #define __NR_add_key		269
 #define __NR_request_key	270
 #define __NR_keyctl		271
+#define __NR_waitid		272
 
-#define __NR_syscalls		272
+#define __NR_syscalls		273
 #ifdef __KERNEL__
 #define NR_syscalls	__NR_syscalls
 #endif
@@ -472,7 +473,7 @@ long sys_rt_sigaction(int sig, const str
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall")
 
 #endif		/* __KERNEL__ */
 
diff --git a/include/asm-ppc64/vdso.h b/include/asm-ppc64/vdso.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc64/vdso.h
@@ -0,0 +1,83 @@
+#ifndef __PPC64_VDSO_H__
+#define __PPC64_VDSO_H__
+
+#ifdef __KERNEL__
+
+/* Default link addresses for the vDSOs */
+#define VDSO32_LBASE	0x100000
+#define VDSO64_LBASE	0x100000
+
+/* Default map addresses */
+#define VDSO32_MBASE	VDSO32_LBASE
+#define VDSO64_MBASE	VDSO64_LBASE
+
+#define VDSO_VERSION_STRING	LINUX_2.6.12
+
+/* Define if 64 bits VDSO has procedure descriptors */
+#undef VDS64_HAS_DESCRIPTORS
+
+#ifndef __ASSEMBLY__
+
+extern unsigned int vdso64_pages;
+extern unsigned int vdso32_pages;
+
+/* Offsets relative to thread->vdso_base */
+extern unsigned long vdso64_rt_sigtramp;
+extern unsigned long vdso32_sigtramp;
+extern unsigned long vdso32_rt_sigtramp;
+
+extern void vdso_init(void);
+
+#else /* __ASSEMBLY__ */
+
+#ifdef __VDSO64__
+#ifdef VDS64_HAS_DESCRIPTORS
+#define V_FUNCTION_BEGIN(name)		\
+	.globl name;			\
+        .section ".opd","a";		\
+        .align 3;			\
+	name:				\
+	.quad .name,.TOC.@tocbase,0;	\
+	.previous;			\
+	.globl .name;			\
+	.type .name,@function; 		\
+	.name:				\
+
+#define V_FUNCTION_END(name)		\
+	.size .name,.-.name;
+
+#define V_LOCAL_FUNC(name) (.name)
+
+#else /* VDS64_HAS_DESCRIPTORS */
+
+#define V_FUNCTION_BEGIN(name)		\
+	.globl name;			\
+	name:				\
+
+#define V_FUNCTION_END(name)		\
+	.size name,.-name;
+
+#define V_LOCAL_FUNC(name) (name)
+
+#endif /* VDS64_HAS_DESCRIPTORS */
+#endif /* __VDSO64__ */
+
+#ifdef __VDSO32__
+
+#define V_FUNCTION_BEGIN(name)		\
+	.globl name;			\
+	.type name,@function; 		\
+	name:				\
+
+#define V_FUNCTION_END(name)		\
+	.size name,.-name;
+
+#define V_LOCAL_FUNC(name) (name)
+
+#endif /* __VDSO32__ */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __PPC64_VDSO_H__ */
diff --git a/include/asm-ppc64/vio.h b/include/asm-ppc64/vio.h
--- a/include/asm-ppc64/vio.h
+++ b/include/asm-ppc64/vio.h
@@ -57,32 +57,7 @@ int vio_get_irq(struct vio_dev *dev);
 int vio_enable_interrupts(struct vio_dev *dev);
 int vio_disable_interrupts(struct vio_dev *dev);
 
-dma_addr_t vio_map_single(struct vio_dev *dev, void *vaddr, 
-			  size_t size, enum dma_data_direction direction);
-void vio_unmap_single(struct vio_dev *dev, dma_addr_t dma_handle, 
-		      size_t size, enum dma_data_direction direction);
-int vio_map_sg(struct vio_dev *vdev, struct scatterlist *sglist, 
-	       int nelems, enum dma_data_direction direction);
-void vio_unmap_sg(struct vio_dev *vdev, struct scatterlist *sglist, 
-		  int nelems, enum dma_data_direction direction);
-void *vio_alloc_consistent(struct vio_dev *dev, size_t size, 
-			   dma_addr_t *dma_handle);
-void vio_free_consistent(struct vio_dev *dev, size_t size, void *vaddr, 
-			 dma_addr_t dma_handle);
-
-static inline int vio_dma_supported(struct vio_dev *hwdev, u64 mask)
-{
-	return 1;
-}
-
-#define vio_map_page(dev, page, off, size, dir) \
-		vio_map_single(dev, (page_address(page) + (off)), size, dir)
-#define vio_unmap_page(dev,addr,sz,dir) vio_unmap_single(dev,addr,sz,dir)
-
-static inline int vio_set_dma_mask(struct vio_dev *dev, u64 mask)
-{
-	return -EIO;
-}
+extern struct dma_mapping_ops vio_dma_ops;
 
 extern struct bus_type vio_bus_type;
 
diff --git a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h
--- a/include/asm-ppc64/xics.h
+++ b/include/asm-ppc64/xics.h
@@ -30,7 +30,4 @@ struct xics_ipi_struct {
 
 extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
-extern unsigned int default_distrib_server;
-extern unsigned int interrupt_server_size;
-
 #endif /* _PPC64_KERNEL_XICS_H */
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
--- a/include/asm-s390/atomic.h
+++ b/include/asm-s390/atomic.h
@@ -61,6 +61,10 @@ static __inline__ void atomic_sub(int i,
 {
 	       __CS_LOOP(v, i, "sr");
 }
+static __inline__ int atomic_sub_return(int i, atomic_t * v)
+{
+	return __CS_LOOP(v, i, "sr");
+}
 static __inline__ void atomic_inc(volatile atomic_t * v)
 {
 	       __CS_LOOP(v, 1, "ar");
diff --git a/include/asm-s390/bug.h b/include/asm-s390/bug.h
--- a/include/asm-s390/bug.h
+++ b/include/asm-s390/bug.h
@@ -3,12 +3,15 @@
 
 #include <linux/kernel.h>
 
+#ifdef CONFIG_BUG
 #define BUG() do { \
         printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
         __asm__ __volatile__(".long 0"); \
 } while (0)
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-s390/cacheflush.h b/include/asm-s390/cacheflush.h
--- a/include/asm-s390/cacheflush.h
+++ b/include/asm-s390/cacheflush.h
@@ -8,7 +8,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -164,6 +164,8 @@ extern int ccw_device_clear(struct ccw_d
 
 extern int read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
 extern int read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
+extern int read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
+			      int *length, __u8 lpm);
 
 extern int ccw_device_set_online(struct ccw_device *cdev);
 extern int ccw_device_set_offline(struct ccw_device *cdev);
@@ -186,4 +188,5 @@ extern int _ccw_device_get_subchannel_nu
 extern struct device *s390_root_dev_register(const char *);
 extern void s390_root_dev_unregister(struct device *);
 
+extern void *ccw_device_get_chp_desc(struct ccw_device *, int);
 #endif /* _S390_CCWDEV_H_ */
diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h
--- a/include/asm-s390/cmb.h
+++ b/include/asm-s390/cmb.h
@@ -52,7 +52,7 @@ struct cmbdata {
 #define BIODASDREADALLCMB	_IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
 
 #ifdef __KERNEL__
-
+struct ccw_device;
 /**
  * enable_cmf() - switch on the channel measurement for a specific device
  *  @cdev:	The ccw device to be enabled
diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h
--- a/include/asm-s390/cputime.h
+++ b/include/asm-s390/cputime.h
@@ -9,6 +9,8 @@
 #ifndef _S390_CPUTIME_H
 #define _S390_CPUTIME_H
 
+#include <asm/div64.h>
+
 /* We want to use micro-second resolution. */
 
 typedef unsigned long long cputime_t;
@@ -40,6 +42,12 @@ __div(unsigned long long n, unsigned int
 #define cputime_max			((~0UL >> 1) - 1)
 #define cputime_add(__a, __b)		((__a) +  (__b))
 #define cputime_sub(__a, __b)		((__a) -  (__b))
+#define cputime_div(__a, __n) ({		\
+	unsigned long long __div = (__a);	\
+	do_div(__div,__n);			\
+	__div;					\
+})
+#define cputime_halve(__a)		((__a) >> 1)
 #define cputime_eq(__a, __b)		((__a) == (__b))
 #define cputime_gt(__a, __b)		((__a) >  (__b))
 #define cputime_ge(__a, __b)		((__a) >= (__b))
diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h
--- a/include/asm-s390/debug.h
+++ b/include/asm-s390/debug.h
@@ -43,7 +43,7 @@ struct __debug_entry{
 #define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
 #define DEBUG_FLUSH_ALL            -1 /* parameter to flush all areas */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
-#define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
+#define DEBUG_MAX_PROCF_LEN        64 /* max length for a proc file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -107,6 +107,17 @@ extern void iounmap(void *addr);
 
 #define mmiowb()
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/asm-s390/ipc.h b/include/asm-s390/ipc.h
--- a/include/asm-s390/ipc.h
+++ b/include/asm-s390/ipc.h
@@ -1,40 +1 @@
-/*
- *  include/asm-s390/ipc.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/ipc.h"
- */
-
-#ifndef __s390_IPC_H__
-#define __s390_IPC_H__
-
-/* 
- * These are used to wrap system calls on S390.
- *
- * See arch/s390/kernel/sys_s390.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -16,6 +16,8 @@
 #define PAGE_SHIFT      12
 #define PAGE_SIZE       (1UL << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
+#define PAGE_DEFAULT_ACC	0
+#define PAGE_DEFAULT_KEY	(PAGE_DEFAULT_ACC << 4)
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -14,7 +14,6 @@
 #define _S390_PGALLOC_H
 
 #include <linux/config.h>
-#include <asm/processor.h>
 #include <linux/threads.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
@@ -130,8 +129,10 @@ pte_alloc_one_kernel(struct mm_struct *m
 
 	pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
 	if (pte != NULL) {
-		for (i=0; i < PTRS_PER_PTE; i++)
-			pte_clear(pte+i);
+		for (i=0; i < PTRS_PER_PTE; i++) {
+			pte_clear(mm, vmaddr, pte+i);
+			vmaddr += PAGE_SIZE;
+		}
 	}
 	return pte;
 }
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -95,14 +95,14 @@ extern char empty_zero_page[PAGE_SIZE];
 # define USER_PTRS_PER_PGD  512
 # define USER_PGD_PTRS      512
 # define KERNEL_PGD_PTRS    512
-# define FIRST_USER_PGD_NR  0
 #else /* __s390x__ */
 # define USER_PTRS_PER_PGD  2048
 # define USER_PGD_PTRS      2048
 # define KERNEL_PGD_PTRS    2048
-# define FIRST_USER_PGD_NR  0
 #endif /* __s390x__ */
 
+#define FIRST_USER_ADDRESS  0
+
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e))
 #define pmd_ERROR(e) \
@@ -322,6 +322,7 @@ extern inline void set_pte(pte_t *pteptr
 {
 	*pteptr = pteval;
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 /*
  * pgd/pmd/pte query functions
@@ -457,7 +458,7 @@ extern inline void pmd_clear(pmd_t * pmd
 
 #endif /* __s390x__ */
 
-extern inline void pte_clear(pte_t *ptep)
+extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_val(*ptep) = _PAGE_INVALID_EMPTY;
 }
@@ -521,7 +522,7 @@ extern inline pte_t pte_mkyoung(pte_t pt
 	return pte;
 }
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	return 0;
 }
@@ -531,10 +532,10 @@ ptep_clear_flush_young(struct vm_area_st
 			unsigned long address, pte_t *ptep)
 {
 	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_young(ptep);
+	return ptep_test_and_clear_young(vma, address, ptep);
 }
 
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	return 0;
 }
@@ -544,13 +545,13 @@ ptep_clear_flush_dirty(struct vm_area_st
 			unsigned long address, pte_t *ptep)
 {
 	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_dirty(ptep);
+	return ptep_test_and_clear_dirty(vma, address, ptep);
 }
 
-static inline pte_t ptep_get_and_clear(pte_t *ptep)
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t pte = *ptep;
-	pte_clear(ptep);
+	pte_clear(mm, addr, ptep);
 	return pte;
 }
 
@@ -573,19 +574,14 @@ ptep_clear_flush(struct vm_area_struct *
 				      : "=m" (*ptep) : "m" (*ptep),
 				        "a" (ptep), "a" (address) );
 #endif /* __s390x__ */
-	pte_clear(ptep);
+	pte_val(*ptep) = _PAGE_INVALID_EMPTY;
 	return pte;
 }
 
-static inline void ptep_set_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_t old_pte = *ptep;
-	set_pte(ptep, pte_wrprotect(old_pte));
-}
-
-static inline void ptep_mkdirty(pte_t *ptep)
-{
-	pte_mkdirty(*ptep);
+	set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 }
 
 static inline void
@@ -756,11 +752,17 @@ extern inline pmd_t * pmd_offset(pgd_t *
  *  0000000000111111111122222222223333333333444444444455 5555 5 55566 66
  *  0123456789012345678901234567890123456789012345678901 2345 6 78901 23
  */
+#ifndef __s390x__
+#define __SWP_OFFSET_MASK (~0UL >> 12)
+#else
+#define __SWP_OFFSET_MASK (~0UL >> 11)
+#endif
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
 	pte_t pte;
+	offset &= __SWP_OFFSET_MASK;
 	pte_val(pte) = _PAGE_INVALID_SWAP | ((type & 0x1f) << 2) |
-		((offset & 1) << 7) | ((offset & 0xffffe) << 11);
+		((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
 	return pte;
 }
 
@@ -802,7 +804,6 @@ extern inline pte_t mk_swap_pte(unsigned
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
diff --git a/include/asm-s390/posix_types.h b/include/asm-s390/posix_types.h
--- a/include/asm-s390/posix_types.h
+++ b/include/asm-s390/posix_types.h
@@ -83,16 +83,16 @@ typedef struct {
 #endif
 
 #undef  __FD_SET
-#define __FD_SET(fd,fdsetp)  set_bit(fd,fdsetp->fds_bits)
+#define __FD_SET(fd,fdsetp)  set_bit((fd),(fdsetp)->fds_bits)
 
 #undef  __FD_CLR
-#define __FD_CLR(fd,fdsetp)  clear_bit(fd,fdsetp->fds_bits)
+#define __FD_CLR(fd,fdsetp)  clear_bit((fd),(fdsetp)->fds_bits)
 
 #undef  __FD_ISSET
-#define __FD_ISSET(fd,fdsetp)  test_bit(fd,fdsetp->fds_bits)
+#define __FD_ISSET(fd,fdsetp)  test_bit((fd),(fdsetp)->fds_bits)
 
 #undef  __FD_ZERO
-#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+#define __FD_ZERO(fdsetp) (memset ((fdsetp), 0, sizeof(*(fd_set *)(fdsetp))))
 
 #endif     /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)*/
 
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -74,8 +74,6 @@ extern struct task_struct *last_task_use
 
 #endif /* __s390x__ */
 
-#define MM_VM_SIZE(mm)		DEFAULT_TASK_SIZE
-
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
 typedef struct {
@@ -247,7 +245,7 @@ static inline void enabled_wait(void)
 	psw_t wait_psw;
 
 	wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
-		PSW_MASK_MCHECK | PSW_MASK_WAIT;
+		PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY;
 #ifndef __s390x__
 	asm volatile (
 		"    basr %0,0\n"
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -185,6 +185,7 @@
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <asm/setup.h>
+#include <asm/page.h>
 
 typedef union
 {
@@ -235,6 +236,7 @@ typedef struct 
 #define PSW_ADDR_INSN		0x7FFFFFFFUL
 
 #define PSW_BASE_BITS		0x00080000UL
+#define PSW_DEFAULT_KEY		(((unsigned long) PAGE_DEFAULT_ACC) << 20)
 
 #define PSW_ASC_PRIMARY		0x00000000UL
 #define PSW_ASC_ACCREG		0x00004000UL
@@ -260,6 +262,7 @@ typedef struct 
 
 #define PSW_BASE_BITS		0x0000000180000000UL
 #define PSW_BASE32_BITS		0x0000000080000000UL
+#define PSW_DEFAULT_KEY		(((unsigned long) PAGE_DEFAULT_ACC) << 52)
 
 #define PSW_ASC_PRIMARY		0x0000000000000000UL
 #define PSW_ASC_ACCREG		0x0000400000000000UL
@@ -268,14 +271,15 @@ typedef struct 
 
 #define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
 			 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-			 PSW_MASK_PSTATE)
+			 PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
 
 #endif /* __s390x__ */
 
-#define PSW_KERNEL_BITS	(PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY)
+#define PSW_KERNEL_BITS	(PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
+			 PSW_DEFAULT_KEY)
 #define PSW_USER_BITS	(PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
 			 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-			 PSW_MASK_PSTATE)
+			 PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
 
 /* This macro merges a NEW PSW mask specified by the user into
    the currently active PSW mask CURRENT, modifying only those
@@ -470,6 +474,12 @@ struct user_regs_struct
 extern void show_regs(struct pt_regs * regs);
 #endif
 
+static inline void
+psw_set_key(unsigned int key)
+{
+	asm volatile ( "spka 0(%0)" : : "d" (key) );
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _S390_PTRACE_H */
diff --git a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h
--- a/include/asm-s390/siginfo.h
+++ b/include/asm-s390/siginfo.h
@@ -13,12 +13,6 @@
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
-#ifdef CONFIG_ARCH_S390X
-#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-#else
-#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-#endif
-
 #include <asm-generic/siginfo.h>
 
 #endif
diff --git a/include/asm-s390/signal.h b/include/asm-s390/signal.h
--- a/include/asm-s390/signal.h
+++ b/include/asm-s390/signal.h
@@ -117,30 +117,7 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -18,6 +18,7 @@
 #if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
 
 #include <asm/lowcore.h>
+#include <asm/sigp.h>
 
 /*
   s390 specific smp.c headers
@@ -59,6 +60,30 @@ extern __inline__ __u16 hard_smp_process
         return cpu_address;
 }
 
+/*
+ * returns 1 if cpu is in stopped/check stopped state or not operational
+ * returns 0 otherwise
+ */
+static inline int
+smp_cpu_not_running(int cpu)
+{
+	__u32 status;
+
+	switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) {
+	case sigp_order_code_accepted:
+	case sigp_status_stored:
+		/* Check for stopped and check stop state */
+		if (status & 0x50)
+			return 1;
+		break;
+	case sigp_not_operational:
+		return 1;
+	default:
+		break;
+	}
+	return 0;
+}
+
 #define cpu_logical_map(cpu) (cpu)
 
 extern int __cpu_disable (void);
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -335,19 +335,23 @@ __cmpxchg(volatile void *ptr, unsigned l
         __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
 	__asm__ __volatile__ ( \
 		"   bras  1,0f\n" \
                 "   lctlg 0,0,0(%0)\n" \
 		"0: ex    %1,0(1)" \
-		: : "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
+		: : "a" (&array), "a" (((low)<<4)+(high)), \
+		    "m" (*(addrtype *)(array)) : "1" ); \
 	})
 
 #define __ctl_store(array, low, high) ({ \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
 	__asm__ __volatile__ ( \
 		"   bras  1,0f\n" \
 		"   stctg 0,0,0(%1)\n" \
 		"0: ex    %2,0(1)" \
-		: "=m" (array) : "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
+		: "=m" (*(addrtype *)(array)) \
+		: "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
 	})
 
 #define __ctl_set_bit(cr, bit) ({ \
@@ -390,19 +394,23 @@ __cmpxchg(volatile void *ptr, unsigned l
 	__asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
 	__asm__ __volatile__ ( \
 		"   bras  1,0f\n" \
                 "   lctl 0,0,0(%0)\n" \
 		"0: ex    %1,0(1)" \
-		: : "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
+		: : "a" (&array), "a" (((low)<<4)+(high)), \
+		    "m" (*(addrtype *)(array)) : "1" ); \
 	})
 
 #define __ctl_store(array, low, high) ({ \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
 	__asm__ __volatile__ ( \
 		"   bras  1,0f\n" \
 		"   stctl 0,0,0(%1)\n" \
 		"0: ex    %2,0(1)" \
-		: "=m" (array) : "a" (&array), "a" (((low)<<4)+(high)): "1" ); \
+		: "=m" (*(addrtype *)(array)) \
+		: "a" (&array), "a" (((low)<<4)+(high)): "1" ); \
 	})
 
 #define __ctl_set_bit(cr, bit) ({ \
@@ -461,6 +469,8 @@ extern void (*_machine_restart)(char *co
 extern void (*_machine_halt)(void);
 extern void (*_machine_power_off)(void);
 
+#define arch_align_stack(x) (x)
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h
--- a/include/asm-s390/timex.h
+++ b/include/asm-s390/timex.h
@@ -15,8 +15,6 @@
 
 typedef unsigned long long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles(void)
 {
 	cycles_t cycles;
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
--- a/include/asm-s390/uaccess.h
+++ b/include/asm-s390/uaccess.h
@@ -65,7 +65,8 @@
 
 #define access_ok(type,addr,size) __access_ok(addr,size)
 
-extern inline int verify_area(int type, const void __user *addr,
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user *addr,
 						unsigned long size)
 {
 	return access_ok(type, addr, size) ? 0 : -EFAULT;
@@ -161,7 +162,7 @@ struct exception_table_entry
 		__put_user_asm(__x, ptr, __pu_err);		\
 		break;						\
 	default:						\
-		__pu_err = __put_user_bad();			\
+		__put_user_bad();				\
 		break;						\
 	 }							\
 	__pu_err;						\
@@ -182,7 +183,7 @@ struct exception_table_entry
 })
 
 
-extern int __put_user_bad(void);
+extern int __put_user_bad(void) __attribute__((noreturn));
 
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
 #define __get_user_asm(x, ptr, err) \
@@ -225,8 +226,7 @@ extern int __put_user_bad(void);
 		__get_user_asm(__x, ptr, __gu_err);		\
 		break;						\
 	default:						\
-		__x = 0;					\
-		__gu_err = __get_user_bad();			\
+		__get_user_bad();				\
 		break;						\
 	}							\
 	(x) = __x;						\
@@ -248,7 +248,7 @@ extern int __put_user_bad(void);
 	__get_user(x, ptr);					\
 })
 
-extern int __get_user_bad(void);
+extern int __get_user_bad(void) __attribute__((noreturn));
 
 #define __put_user_unaligned __put_user
 #define __get_user_unaligned __get_user
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
--- a/include/asm-s390/unistd.h
+++ b/include/asm-s390/unistd.h
@@ -259,7 +259,7 @@
 #define __NR_fadvise64_64	264
 #define __NR_statfs64		265
 #define __NR_fstatfs64		266
-/* Number 267 is reserved for new sys_remap_file_pages */
+#define __NR_remap_file_pages	267
 /* Number 268 is reserved for new sys_mbind */
 /* Number 269 is reserved for new sys_get_mempolicy */
 /* Number 270 is reserved for new sys_set_mempolicy */
@@ -270,8 +270,12 @@
 #define __NR_mq_notify		275
 #define __NR_mq_getsetattr	276
 /* Number 277 is reserved for new sys_kexec_load */
+#define __NR_add_key		278
+#define __NR_request_key	279
+#define __NR_keyctl		280
+#define __NR_waitid		281
 
-#define NR_syscalls 278
+#define NR_syscalls 282
 
 /* 
  * There are some system calls that are not present on 64 bit, some
@@ -330,7 +334,6 @@
 #undef  __NR_setgid32
 #undef  __NR_setfsuid32
 #undef  __NR_setfsgid32
-#undef  __NR_getdents64
 #undef  __NR_fcntl64
 #undef  __NR_sendfile64
 #undef  __NR_fadvise64_64
@@ -597,6 +600,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _ASM_S390_UNISTD_H_ */
diff --git a/include/asm-s390/user.h b/include/asm-s390/user.h
--- a/include/asm-s390/user.h
+++ b/include/asm-s390/user.h
@@ -10,7 +10,7 @@
 #define _S390_USER_H
 
 #include <asm/page.h>
-#include <linux/ptrace.h>
+#include <asm/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 (under
    linux we use the 'trad-core' bfd).  There are quite a number of
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -262,9 +262,9 @@ found_middle:
 #define find_first_bit(addr, size) \
 	find_next_bit((addr), (size), 0)
 
-static __inline__ int find_next_zero_bit(void *addr, int size, int offset)
+static __inline__ int find_next_zero_bit(const unsigned long *addr, int size, int offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	const unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
 	unsigned long tmp;
 
@@ -325,7 +325,7 @@ found_middle:
  * bits is cleared.
  */
 
-static inline int sched_find_first_bit(unsigned long *b)
+static inline int sched_find_first_bit(const unsigned long *b)
 {
 	if (unlikely(b[0]))
 		return __ffs(b[0]);
diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
--- a/include/asm-sh/bug.h
+++ b/include/asm-sh/bug.h
@@ -3,15 +3,18 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BUG
 /*
  * Tell the user there is some problem.
  */
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-	asm volatile("nop"); \
+	*(volatile int *)0 = 0; \
 } while (0)
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-sh/bus-sh.h b/include/asm-sh/bus-sh.h
--- a/include/asm-sh/bus-sh.h
+++ b/include/asm-sh/bus-sh.h
@@ -34,7 +34,7 @@ struct sh_driver {
 	unsigned int		bus_id;
 	int (*probe)(struct sh_dev *);
 	int (*remove)(struct sh_dev *);
-	int (*suspend)(struct sh_dev *, u32);
+	int (*suspend)(struct sh_dev *, pm_message_t);
 	int (*resume)(struct sh_dev *);
 };
 
diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h
--- a/include/asm-sh/cacheflush.h
+++ b/include/asm-sh/cacheflush.h
@@ -1,5 +1,6 @@
 #ifndef __ASM_SH_CACHEFLUSH_H
 #define __ASM_SH_CACHEFLUSH_H
+#ifdef __KERNEL__
 
 #include <asm/cpu/cacheflush.h>
 
@@ -15,15 +16,16 @@ extern void __flush_invalidate_region(vo
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 	do {							\
-		flush_cache_page(vma, vaddr);			\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
 		memcpy(dst, src, len);				\
 		flush_icache_user_range(vma, page, vaddr, len);	\
 	} while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
 	do {							\
-		flush_cache_page(vma, vaddr);			\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
 		memcpy(dst, src, len);				\
 	} while (0)
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_CACHEFLUSH_H */
diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
--- a/include/asm-sh/checksum.h
+++ b/include/asm-sh/checksum.h
@@ -42,7 +42,7 @@ asmlinkage unsigned int csum_partial_cop
  *	passed in an incorrect kernel address to one of these functions. 
  *	
  *	If you use these functions directly please don't forget the 
- *	verify_area().
+ *	access_ok().
  */
 static __inline__
 unsigned int csum_partial_copy_nocheck (const unsigned char *src, unsigned char *dst,
diff --git a/include/asm-sh/cpu-sh2/cacheflush.h b/include/asm-sh/cpu-sh2/cacheflush.h
--- a/include/asm-sh/cpu-sh2/cacheflush.h
+++ b/include/asm-sh/cpu-sh2/cacheflush.h
@@ -15,7 +15,7 @@
  *
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
- *  - flush_cache_page(mm, vmaddr) flushes a single page
+ *  - flush_cache_page(mm, vmaddr, pfn) flushes a single page
  *  - flush_cache_range(vma, start, end) flushes a range of pages
  *
  *  - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
@@ -28,7 +28,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h
--- a/include/asm-sh/cpu-sh3/cacheflush.h
+++ b/include/asm-sh/cpu-sh3/cacheflush.h
@@ -15,7 +15,7 @@
  *
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
- *  - flush_cache_page(mm, vmaddr) flushes a single page
+ *  - flush_cache_page(mm, vmaddr, pfn) flushes a single page
  *  - flush_cache_range(vma, start, end) flushes a range of pages
  *
  *  - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
@@ -43,7 +43,7 @@ extern void flush_cache_all(void);
 extern void flush_cache_mm(struct mm_struct *mm);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                               unsigned long end);
-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
 extern void flush_dcache_page(struct page *pg);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
@@ -68,7 +68,7 @@ extern void flush_icache_page(struct vm_
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-sh/cpu-sh3/freq.h b/include/asm-sh/cpu-sh3/freq.h
--- a/include/asm-sh/cpu-sh3/freq.h
+++ b/include/asm-sh/cpu-sh3/freq.h
@@ -10,7 +10,11 @@
 #ifndef __ASM_CPU_SH3_FREQ_H
 #define __ASM_CPU_SH3_FREQ_H
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+#define FRQCR			0xa415ff80
+#else
 #define FRQCR			0xffffff80
+#endif
 #define MIN_DIVISOR_NR		0
 #define MAX_DIVISOR_NR		4
 
diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
new file mode 100644
--- /dev/null
+++ b/include/asm-sh/cpu-sh3/timer.h
@@ -0,0 +1,64 @@
+/*
+ * include/asm-sh/cpu-sh3/timer.h
+ *
+ * Copyright (C) 2004 Lineo Solutions, 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.
+ */
+#ifndef __ASM_CPU_SH3_TIMER_H
+#define __ASM_CPU_SH3_TIMER_H
+
+/*
+ * ---------------------------------------------------------------------------
+ * TMU Common definitions for SH3 processors
+ *	SH7706
+ *	SH7709S
+ *	SH7727
+ *	SH7729R
+ *	SH7710
+ *	SH7720
+ *	SH7300
+ * ---------------------------------------------------------------------------
+ */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+#define TMU_TSTR	0xa412fe92	/* Byte access */
+
+#define TMU0_TCOR	0xa412fe94	/* Long access */
+#define TMU0_TCNT	0xa412fe98	/* Long access */
+#define TMU0_TCR	0xa412fe9c	/* Word access */
+
+#define TMU1_TCOR	0xa412fea0	/* Long access */
+#define TMU1_TCNT	0xa412fea4	/* Long access */
+#define TMU1_TCR	0xa412fea8	/* Word access */
+
+#define TMU2_TCOR	0xa412feac	/* Long access */
+#define TMU2_TCNT	0xa412feb0	/* Long access */
+#define TMU2_TCR	0xa412feb4	/* Word access */
+
+#else
+#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#define TMU_TOCR	0xfffffe90	/* Byte access */
+#endif
+#define TMU_TSTR	0xfffffe92	/* Byte access */
+
+#define TMU0_TCOR	0xfffffe94	/* Long access */
+#define TMU0_TCNT	0xfffffe98	/* Long access */
+#define TMU0_TCR	0xfffffe9c	/* Word access */
+
+#define TMU1_TCOR	0xfffffea0	/* Long access */
+#define TMU1_TCNT	0xfffffea4	/* Long access */
+#define TMU1_TCR	0xfffffea8	/* Word access */
+
+#define TMU2_TCOR	0xfffffeac	/* Long access */
+#define TMU2_TCNT	0xfffffeb0	/* Long access */
+#define TMU2_TCR	0xfffffeb4	/* Word access */
+#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#define TMU2_TCPR2	0xfffffeb8	/* Long access */
+#endif
+#endif
+
+#endif /* __ASM_CPU_SH3_TIMER_H */
+
diff --git a/include/asm-sh/cpu-sh4/cacheflush.h b/include/asm-sh/cpu-sh4/cacheflush.h
--- a/include/asm-sh/cpu-sh4/cacheflush.h
+++ b/include/asm-sh/cpu-sh4/cacheflush.h
@@ -28,7 +28,7 @@ extern void flush_cache_all(void);
 extern void flush_cache_mm(struct mm_struct *mm);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
 extern void flush_dcache_page(struct page *pg);
 
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
diff --git a/include/asm-sh/cpu-sh4/timer.h b/include/asm-sh/cpu-sh4/timer.h
new file mode 100644
--- /dev/null
+++ b/include/asm-sh/cpu-sh4/timer.h
@@ -0,0 +1,51 @@
+/*
+ * include/asm-sh/cpu-sh4/timer.h
+ *
+ * Copyright (C) 2004 Lineo Solutions, 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.
+ */
+#ifndef __ASM_CPU_SH4_TIMER_H
+#define __ASM_CPU_SH4_TIMER_H
+
+/*
+ * ---------------------------------------------------------------------------
+ * TMU Common definitions for SH4 processors
+ *	SH7750S/SH7750R
+ *	SH7751/SH7751R
+ *	SH7760
+ * ---------------------------------------------------------------------------
+ */
+
+#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#define TMU_TOCR        0xffd80000      /* Byte access */
+#endif
+#define TMU_TSTR        0xffd80004      /* Byte access */
+
+#define TMU0_TCOR       0xffd80008      /* Long access */
+#define TMU0_TCNT       0xffd8000c      /* Long access */
+#define TMU0_TCR        0xffd80010      /* Word access */
+
+#define TMU1_TCOR       0xffd80014      /* Long access */
+#define TMU1_TCNT       0xffd80018      /* Long access */
+#define TMU1_TCR        0xffd8001c      /* Word access */
+
+#define TMU2_TCOR       0xffd80020      /* Long access */
+#define TMU2_TCNT       0xffd80024      /* Long access */
+#define TMU2_TCR        0xffd80028      /* Word access */
+#define TMU2_TCPR	0xffd8002c	/* Long access */
+
+#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#define TMU3_TCOR       0xfe100008      /* Long access */
+#define TMU3_TCNT       0xfe10000c      /* Long access */
+#define TMU3_TCR        0xfe100010      /* Word access */
+
+#define TMU4_TCOR       0xfe100014      /* Long access */
+#define TMU4_TCNT       0xfe100018      /* Long access */
+#define TMU4_TCR        0xfe10001c      /* Word access */
+#endif
+
+#endif /* __ASM_CPU_SH4_TIMER_H */
+
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -3,7 +3,6 @@
 
 #include <linux/config.h>
 #include <linux/mm.h>
-#include <linux/device.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 
diff --git a/include/asm-sh/floppy.h b/include/asm-sh/floppy.h
--- a/include/asm-sh/floppy.h
+++ b/include/asm-sh/floppy.h
@@ -227,7 +227,7 @@ static int hard_dma_setup(char *addr, un
 	return 0;
 }
 
-struct fd_routine_l {
+static 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);
diff --git a/include/asm-sh/hardirq.h b/include/asm-sh/hardirq.h
--- a/include/asm-sh/hardirq.h
+++ b/include/asm-sh/hardirq.h
@@ -12,15 +12,6 @@ typedef struct {
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
-#define HARDIRQ_BITS	8
-
-/*
- * The hardirq mask has to be large enough to have
- * space for potentially all IRQ sources in the system
- * nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
+extern void ack_bad_irq(unsigned int irq);
 
 #endif /* __ASM_SH_HARDIRQ_H */
diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h
--- a/include/asm-sh/io.h
+++ b/include/asm-sh/io.h
@@ -295,6 +295,17 @@ out:
 #define dma_cache_wback(_start,_size) \
     __flush_wback_region(_start,_size)
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_IO_H */
diff --git a/include/asm-sh/ipc.h b/include/asm-sh/ipc.h
--- a/include/asm-sh/ipc.h
+++ b/include/asm-sh/ipc.h
@@ -1,32 +1 @@
-#ifndef __ASM_SH_IPC_H
-#define __ASM_SH_IPC_H
-
-/* 
- * These are used to wrap system calls on x86.
- *
- * See arch/i386/kernel/sys_i386.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif /* __ASM_SH_IPC_H */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -17,7 +17,8 @@
 
 #if defined(CONFIG_SH_HP600) || \
     defined(CONFIG_SH_RTS7751R2D) || \
-    defined(CONFIG_SH_HS7751RVOIP)
+    defined(CONFIG_SH_HS7751RVOIP) || \
+    defined(CONFIG_SH_SH03)
 #include <asm/mach/ide.h>
 #endif
 
diff --git a/include/asm-sh/mc146818rtc.h b/include/asm-sh/mc146818rtc.h
--- a/include/asm-sh/mc146818rtc.h
+++ b/include/asm-sh/mc146818rtc.h
@@ -16,6 +16,7 @@
 
 /* FIXME:RTC Interrupt feature is not implemented yet. */
 #undef  RTC_IRQ
+#define RTC_IRQ		0
 
 #if defined(CONFIG_CPU_SH3)
 #define RTC_PORT(n)		(R64CNT+(n)*2)
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_SH_PGALLOC_H
 #define __ASM_SH_PGALLOC_H
 
-#include <asm/processor.h>
 #include <linux/threads.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
diff --git a/include/asm-sh/pgtable-2level.h b/include/asm-sh/pgtable-2level.h
--- a/include/asm-sh/pgtable-2level.h
+++ b/include/asm-sh/pgtable-2level.h
@@ -41,6 +41,8 @@ static inline void pgd_clear (pgd_t * pg
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
 /*
  * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -44,7 +44,7 @@ extern unsigned long empty_zero_page[102
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define PTE_PHYS_MASK	0x1ffff000
 
@@ -164,7 +164,7 @@ extern unsigned long empty_zero_page[102
 
 #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 pte_clear(mm,addr,xp)	do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
@@ -279,6 +279,13 @@ typedef pte_t *pte_addr_t;
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 /*
  * No page table caches to initialise
  */
@@ -290,7 +297,7 @@ extern unsigned int kobjsize(const void 
 
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-extern pte_t ptep_get_and_clear(pte_t *ptep);
+extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
 #endif
 
 #include <asm-generic/pgtable.h>
diff --git a/include/asm-sh/sh03/ide.h b/include/asm-sh/sh03/ide.h
new file mode 100644
--- /dev/null
+++ b/include/asm-sh/sh03/ide.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_SH_SH03_IDE_H
+#define __ASM_SH_SH03_IDE_H
+
+#define IRQ_CFCARD	8
+#define IRQ_PCMCIA	8
+
+#endif /* __ASM_SH_SH03_IDE_H */
diff --git a/include/asm-sh/signal.h b/include/asm-sh/signal.h
--- a/include/asm-sh/signal.h
+++ b/include/asm-sh/signal.h
@@ -108,30 +108,7 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -259,4 +259,6 @@ static __inline__ unsigned long __xchg(u
 void disable_hlt(void);
 void enable_hlt(void);
 
+#define arch_align_stack(x) (x)
+
 #endif
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -27,7 +27,7 @@ struct thread_info {
 
 #endif
 
-#define PREEMPT_ACTIVE		0x4000000
+#define PREEMPT_ACTIVE		0x10000000
 
 /*
  * macros/functions for gaining access to the thread information structure
diff --git a/include/asm-sh/timex.h b/include/asm-sh/timex.h
--- a/include/asm-sh/timex.h
+++ b/include/asm-sh/timex.h
@@ -10,8 +10,6 @@
 
 typedef unsigned long long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static __inline__ cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -146,7 +146,8 @@ static inline int access_ok(int type, co
 	return __access_ok(addr, size);
 }
 
-static inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-sh/unaligned.h b/include/asm-sh/unaligned.h
--- a/include/asm-sh/unaligned.h
+++ b/include/asm-sh/unaligned.h
@@ -2,18 +2,6 @@
 #define __ASM_SH_UNALIGNED_H
 
 /* SH can't handle unaligned accesses. */
-
-#include <linux/string.h>
-
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* __ASM_SH_UNALIGNED_H */
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -517,7 +517,7 @@ asmlinkage long sys_rt_sigaction(int sig
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* __ASM_SH_UNISTD_H */
diff --git a/include/asm-sh64/bug.h b/include/asm-sh64/bug.h
--- a/include/asm-sh64/bug.h
+++ b/include/asm-sh64/bug.h
@@ -1,7 +1,28 @@
 #ifndef __ASM_SH64_BUG_H
 #define __ASM_SH64_BUG_H
 
-#include <asm-sh/bug.h>
+#include <linux/config.h>
+
+/*
+ * Tell the user there is some problem, then force a segfault (in process
+ * context) or a panic (interrupt context).
+ */
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	*(volatile int *)0 = 0; \
+} while (0)
+
+#define BUG_ON(condition) do { \
+	if (unlikely((condition)!=0)) \
+		BUG(); \
+} while(0)
+
+#define WARN_ON(condition) do { \
+	if (unlikely((condition)!=0)) { \
+		printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+		dump_stack(); \
+	} \
+} while (0)
 
 #endif /* __ASM_SH64_BUG_H */
 
diff --git a/include/asm-sh64/cacheflush.h b/include/asm-sh64/cacheflush.h
--- a/include/asm-sh64/cacheflush.h
+++ b/include/asm-sh64/cacheflush.h
@@ -14,7 +14,7 @@ extern void flush_cache_mm(struct mm_str
 extern void flush_cache_sigtramp(unsigned long start, unsigned long end);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
 extern void flush_dcache_page(struct page *pg);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
@@ -31,14 +31,14 @@ extern void flush_icache_user_range(stru
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 	do {							\
-		flush_cache_page(vma, vaddr);			\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
 		memcpy(dst, src, len);				\
 		flush_icache_user_range(vma, page, vaddr, len);	\
 	} while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
 	do {							\
-		flush_cache_page(vma, vaddr);			\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
 		memcpy(dst, src, len);				\
 	} while (0)
 
diff --git a/include/asm-sh64/checksum.h b/include/asm-sh64/checksum.h
--- a/include/asm-sh64/checksum.h
+++ b/include/asm-sh64/checksum.h
@@ -34,7 +34,7 @@ asmlinkage unsigned int csum_partial(con
  *	passed in an incorrect kernel address to one of these functions.
  *
  *	If you use these functions directly please don't forget the
- *	verify_area().
+ *	access_ok().
  */
 
 
diff --git a/include/asm-sh64/elf.h b/include/asm-sh64/elf.h
--- a/include/asm-sh64/elf.h
+++ b/include/asm-sh64/elf.h
@@ -53,6 +53,12 @@ typedef struct user_fpu_struct elf_fpreg
 
 #define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
 
+#define	R_SH_DIR32		1
+#define	R_SH_REL32		2
+#define	R_SH_IMM_LOW16		246
+#define	R_SH_IMM_LOW16_PCREL	247
+#define	R_SH_IMM_MEDLOW16	248
+#define	R_SH_IMM_MEDLOW16_PCREL	249
 
 #define ELF_CORE_COPY_REGS(_dest,_regs)				\
 	memcpy((char *) &_dest, (char *) _regs,			\
diff --git a/include/asm-sh64/hardirq.h b/include/asm-sh64/hardirq.h
--- a/include/asm-sh64/hardirq.h
+++ b/include/asm-sh64/hardirq.h
@@ -1,7 +1,19 @@
 #ifndef __ASM_SH64_HARDIRQ_H
 #define __ASM_SH64_HARDIRQ_H
 
-#include <asm-sh/hardirq.h>
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+	unsigned int __softirq_pending;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+
+/* arch/sh64/kernel/irq.c */
+extern void ack_bad_irq(unsigned int irq);
 
 #endif /* __ASM_SH64_HARDIRQ_H */
 
diff --git a/include/asm-sh64/hardware.h b/include/asm-sh64/hardware.h
--- a/include/asm-sh64/hardware.h
+++ b/include/asm-sh64/hardware.h
@@ -17,29 +17,6 @@
 #define	PHYS_PERIPHERAL_BLOCK	0x09000000
 #define PHYS_DMAC_BLOCK		0x0e000000
 #define PHYS_PCI_BLOCK		0x60000000
-
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-#include <asm/io.h>
-
-struct vcr_info {
-	u8	perr_flags;	/* P-port Error flags */
-	u8	merr_flags;	/* Module Error flags */
-	u16	mod_vers;	/* Module Version */
-	u16	mod_id;		/* Module ID */
-	u8	bot_mb;		/* Bottom Memory block */
-	u8	top_mb;		/* Top Memory block */
-};
-
-static inline struct vcr_info sh64_get_vcr_info(unsigned long base)
-{
-	unsigned long long tmp;
-
-	tmp = sh64_in64(base);
-
-	return *((struct vcr_info *)&tmp);
-}
-
-#endif /* __ASSEMBLY__ */
+#define PHYS_EMI_BLOCK		0xff000000
 
 #endif /* __ASM_SH64_HARDWARE_H */
diff --git a/include/asm-sh64/ide.h b/include/asm-sh64/ide.h
--- a/include/asm-sh64/ide.h
+++ b/include/asm-sh64/ide.h
@@ -21,7 +21,12 @@
 #define MAX_HWIFS	CONFIG_IDE_MAX_HWIFS
 #endif
 
+/* Without this, the initialisation of PCI IDE cards end up calling
+ * ide_init_hwif_ports, which won't work. */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#define IDE_ARCH_OBSOLETE_INIT 1
 #define ide_default_io_ctl(base)	(0)
+#endif
 
 #include <asm-generic/ide_iops.h>
 
diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h
--- a/include/asm-sh64/io.h
+++ b/include/asm-sh64/io.h
@@ -25,9 +25,11 @@
  * onchip_remap();
  */
 
+#include <linux/compiler.h>
 #include <asm/cache.h>
 #include <asm/system.h>
 #include <asm/page.h>
+#include <asm-generic/iomap.h>
 
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
@@ -39,75 +41,90 @@
  * with an implicit size. The traditional read{b,w,l}/write{b,w,l}
  * mess is wrapped to this, as are the SH-specific ctrl_in/out routines.
  */
-static inline unsigned char sh64_in8(unsigned long addr)
+static inline unsigned char sh64_in8(const volatile void __iomem *addr)
 {
-	return *(volatile unsigned char *)addr;
+	return *(volatile unsigned char __force *)addr;
 }
 
-static inline unsigned short sh64_in16(unsigned long addr)
+static inline unsigned short sh64_in16(const volatile void __iomem *addr)
 {
-	return *(volatile unsigned short *)addr;
+	return *(volatile unsigned short __force *)addr;
 }
 
-static inline unsigned long sh64_in32(unsigned long addr)
+static inline unsigned int sh64_in32(const volatile void __iomem *addr)
 {
-	return *(volatile unsigned long *)addr;
+	return *(volatile unsigned int __force *)addr;
 }
 
-static inline unsigned long long sh64_in64(unsigned long addr)
+static inline unsigned long long sh64_in64(const volatile void __iomem *addr)
 {
-	return *(volatile unsigned long long *)addr;
+	return *(volatile unsigned long long __force *)addr;
 }
 
-static inline void sh64_out8(unsigned char b, unsigned long addr)
+static inline void sh64_out8(unsigned char b, volatile void __iomem *addr)
 {
-	*(volatile unsigned char *)addr = b;
+	*(volatile unsigned char __force *)addr = b;
 	wmb();
 }
 
-static inline void sh64_out16(unsigned short b, unsigned long addr)
+static inline void sh64_out16(unsigned short b, volatile void __iomem *addr)
 {
-	*(volatile unsigned short *)addr = b;
+	*(volatile unsigned short __force *)addr = b;
 	wmb();
 }
 
-static inline void sh64_out32(unsigned long b, unsigned long addr)
+static inline void sh64_out32(unsigned int b, volatile void __iomem *addr)
 {
-	*(volatile unsigned long *)addr = b;
+	*(volatile unsigned int __force *)addr = b;
 	wmb();
 }
 
-static inline void sh64_out64(unsigned long long b, unsigned long addr)
+static inline void sh64_out64(unsigned long long b, volatile void __iomem *addr)
 {
-	*(volatile unsigned long long *)addr = b;
+	*(volatile unsigned long long __force *)addr = b;
 	wmb();
 }
 
 #define readb(addr)		sh64_in8(addr)
 #define readw(addr)		sh64_in16(addr)
 #define readl(addr)		sh64_in32(addr)
-#define readb_relaxed(addr)		sh64_in8(addr)
-#define readw_relaxed(addr)		sh64_in16(addr)
-#define readl_relaxed(addr)		sh64_in32(addr)
+#define readb_relaxed(addr)	sh64_in8(addr)
+#define readw_relaxed(addr)	sh64_in16(addr)
+#define readl_relaxed(addr)	sh64_in32(addr)
 
 #define writeb(b, addr)		sh64_out8(b, addr)
 #define writew(b, addr)		sh64_out16(b, addr)
 #define writel(b, addr)		sh64_out32(b, addr)
 
-#define ctrl_inb(addr)		sh64_in8(addr)
-#define ctrl_inw(addr)		sh64_in16(addr)
-#define ctrl_inl(addr)		sh64_in32(addr)
-
-#define ctrl_outb(b, addr)	sh64_out8(b, addr)
-#define ctrl_outw(b, addr)	sh64_out16(b, addr)
-#define ctrl_outl(b, addr)	sh64_out32(b, addr)
-
-unsigned long inb(unsigned long port);
-unsigned long inw(unsigned long port);
-unsigned long inl(unsigned long port);
-void outb(unsigned long value, unsigned long port);
-void outw(unsigned long value, unsigned long port);
-void outl(unsigned long value, unsigned long port);
+#define ctrl_inb(addr)		sh64_in8(ioport_map(addr, 1))
+#define ctrl_inw(addr)		sh64_in16(ioport_map(addr, 2))
+#define ctrl_inl(addr)		sh64_in32(ioport_map(addr, 4))
+
+#define ctrl_outb(b, addr)	sh64_out8(b, ioport_map(addr, 1))
+#define ctrl_outw(b, addr)	sh64_out16(b, ioport_map(addr, 2))
+#define ctrl_outl(b, addr)	sh64_out32(b, ioport_map(addr, 4))
+
+#define ioread8(addr)		sh64_in8(addr)
+#define ioread16(addr)		sh64_in16(addr)
+#define ioread32(addr)		sh64_in32(addr)
+#define iowrite8(b, addr)	sh64_out8(b, addr)
+#define iowrite16(b, addr)	sh64_out16(b, addr)
+#define iowrite32(b, addr)	sh64_out32(b, addr)
+
+#define inb(addr)		ctrl_inb(addr)
+#define inw(addr)		ctrl_inw(addr)
+#define inl(addr)		ctrl_inl(addr)
+#define outb(b, addr)		ctrl_outb(b, addr)
+#define outw(b, addr)		ctrl_outw(b, addr)
+#define outl(b, addr)		ctrl_outl(b, addr)
+
+void outsw(unsigned long port, const void *addr, unsigned long count);
+void insw(unsigned long port, void *addr, unsigned long count);
+void outsl(unsigned long port, const void *addr, unsigned long count);
+void insl(unsigned long port, void *addr, unsigned long count);
+
+void memcpy_toio(void __iomem *to, const void *from, long count);
+void memcpy_fromio(void *to, void __iomem *from, long count);
 
 #define mmiowb()
 
@@ -154,7 +171,7 @@ extern void iounmap(void *addr);
 unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name);
 extern void onchip_unmap(unsigned long vaddr);
 
-static __inline__ int check_signature(unsigned long io_addr,
+static __inline__ int check_signature(volatile void __iomem *io_addr,
 			const unsigned char *signature, int length)
 {
 	int retval = 0;
@@ -218,5 +235,16 @@ static __inline__ void dma_cache_wback (
 		asm volatile ("ocbwb	%0, 0" : : "r" (s));
 }
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH64_IO_H */
diff --git a/include/asm-sh64/ioctls.h b/include/asm-sh64/ioctls.h
--- a/include/asm-sh64/ioctls.h
+++ b/include/asm-sh64/ioctls.h
@@ -9,103 +9,108 @@
  * include/asm-sh64/ioctls.h
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2004  Richard Curnow
  *
  */
 
 #include <asm/ioctl.h>
 
-#define FIOCLEX		_IO('f', 1)
-#define FIONCLEX	_IO('f', 2)
-#define FIOASYNC	_IOW('f', 125, int)
-#define FIONBIO		_IOW('f', 126, int)
-#define FIONREAD	_IOR('f', 127, int)
+#define FIOCLEX		0x6601		/* _IO('f', 1) */
+#define FIONCLEX	0x6602		/* _IO('f', 2) */
+#define FIOASYNC	0x4004667d	/* _IOW('f', 125, int) */
+#define FIONBIO		0x4004667e	/* _IOW('f', 126, int) */
+#define FIONREAD	0x8004667f	/* _IOW('f', 127, int) */
 #define TIOCINQ		FIONREAD
-#define FIOQSIZE	_IOR('f', 128, loff_t)
+#define FIOQSIZE	0x80086680	/* _IOR('f', 128, loff_t) */
 
 #define TCGETS		0x5401
 #define TCSETS		0x5402
 #define TCSETSW		0x5403
 #define TCSETSF		0x5404
 
-#define TCGETA		_IOR('t', 23, struct termio)
-#define TCSETA		_IOW('t', 24, struct termio)
-#define TCSETAW		_IOW('t', 25, struct termio)
-#define TCSETAF		_IOW('t', 28, struct termio)
-
-#define TCSBRK		_IO('t', 29)
-#define TCXONC		_IO('t', 30)
-#define TCFLSH		_IO('t', 31)
-
-#define TIOCSWINSZ	_IOW('t', 103, struct winsize)
-#define TIOCGWINSZ	_IOR('t', 104, struct winsize)
-#define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
-#define	TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
-#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
-
-#define TIOCSPGRP	_IOW('t', 118, int)
-#define TIOCGPGRP	_IOR('t', 119, int)
-
-#define TIOCEXCL	_IO('T', 12) /* 0x540C */
-#define TIOCNXCL	_IO('T', 13) /* 0x540D */
-#define TIOCSCTTY	_IO('T', 14) /* 0x540E */
-
-#define TIOCSTI		_IOW('T', 18, char) /* 0x5412 */
-#define TIOCMGET	_IOR('T', 21, unsigned int) /* 0x5415 */
-#define TIOCMBIS	_IOW('T', 22, unsigned int) /* 0x5416 */
-#define TIOCMBIC	_IOW('T', 23, unsigned int) /* 0x5417 */
-#define TIOCMSET	_IOW('T', 24, unsigned int) /* 0x5418 */
-# 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 TIOCGSOFTCAR	_IOR('T', 25, unsigned int) /* 0x5419 */
-#define TIOCSSOFTCAR	_IOW('T', 26, unsigned int) /* 0x541A */
-#define TIOCLINUX	_IOW('T', 28, char) /* 0x541C */
-#define TIOCCONS	_IO('T', 29) /* 0x541D */
-#define TIOCGSERIAL	_IOR('T', 30, struct serial_struct) /* 0x541E */
-#define TIOCSSERIAL	_IOW('T', 31, struct serial_struct) /* 0x541F */
-#define TIOCPKT		_IOW('T', 32, int) /* 0x5420 */
-# 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 TIOCNOTTY	_IO('T', 34) /* 0x5422 */
-#define TIOCSETD	_IOW('T', 35, int) /* 0x5423 */
-#define TIOCGETD	_IOR('T', 36, int) /* 0x5424 */
-#define TCSBRKP		_IOW('T', 37, int) /* 0x5425 */	/* Needed for POSIX tcsendbreak() */
-#define TIOCTTYGSTRUCT	_IOR('T', 38, struct tty_struct) /* 0x5426 */ /* For debugging only */
-#define TIOCSBRK	_IO('T', 39) /* 0x5427 */ /* BSD compatibility */
-#define TIOCCBRK	_IO('T', 40) /* 0x5428 */ /* BSD compatibility */
-#define TIOCGSID	_IOR('T', 41, pid_t) /* 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 TIOCSERCONFIG	_IO('T', 83) /* 0x5453 */
-#define TIOCSERGWILD	_IOR('T', 84,  int) /* 0x5454 */
-#define TIOCSERSWILD	_IOW('T', 85,  int) /* 0x5455 */
+#define TCGETA		0x80127417	/* _IOR('t', 23, struct termio) */
+#define TCSETA		0x40127418	/* _IOW('t', 24, struct termio) */
+#define TCSETAW		0x40127419	/* _IOW('t', 25, struct termio) */
+#define TCSETAF		0x4012741c	/* _IOW('t', 28, struct termio) */
+
+#define TCSBRK		0x741d		/* _IO('t', 29) */
+#define TCXONC		0x741e		/* _IO('t', 30) */
+#define TCFLSH		0x741f		/* _IO('t', 31) */
+
+#define TIOCSWINSZ	0x40087467	/* _IOW('t', 103, struct winsize) */
+#define TIOCGWINSZ	0x80087468	/* _IOR('t', 104, struct winsize) */
+#define	TIOCSTART	0x746e		/* _IO('t', 110)  start output, like ^Q */
+#define	TIOCSTOP	0x746f		/* _IO('t', 111)  stop output, like ^S */
+#define TIOCOUTQ        0x80047473	/* _IOR('t', 115, int) output queue size */
+
+#define TIOCSPGRP	0x40047476	/* _IOW('t', 118, int) */
+#define TIOCGPGRP	0x80047477	/* _IOR('t', 119, int) */
+
+#define TIOCEXCL	0x540c		/* _IO('T', 12) */
+#define TIOCNXCL	0x540d		/* _IO('T', 13) */
+#define TIOCSCTTY	0x540e		/* _IO('T', 14) */
+
+#define TIOCSTI		0x40015412	/* _IOW('T', 18, char) 0x5412 */
+#define TIOCMGET	0x80045415	/* _IOR('T', 21, unsigned int) 0x5415 */
+#define TIOCMBIS	0x40045416	/* _IOW('T', 22, unsigned int) 0x5416 */
+#define TIOCMBIC	0x40045417	/* _IOW('T', 23, unsigned int) 0x5417 */
+#define TIOCMSET	0x40045418	/* _IOW('T', 24, unsigned int) 0x5418 */
+
+#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 TIOCGSOFTCAR	0x80045419	/* _IOR('T', 25, unsigned int) 0x5419 */
+#define TIOCSSOFTCAR	0x4004541a	/* _IOW('T', 26, unsigned int) 0x541A */
+#define TIOCLINUX	0x4004541c	/* _IOW('T', 28, char) 0x541C */
+#define TIOCCONS	0x541d		/* _IO('T', 29) */
+#define TIOCGSERIAL	0x803c541e	/* _IOR('T', 30, struct serial_struct) 0x541E */
+#define TIOCSSERIAL	0x403c541f	/* _IOW('T', 31, struct serial_struct) 0x541F */
+#define TIOCPKT		0x40045420	/* _IOW('T', 32, int) 0x5420 */
+
+#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 TIOCNOTTY	0x5422		/* _IO('T', 34) */
+#define TIOCSETD	0x40045423	/* _IOW('T', 35, int) 0x5423 */
+#define TIOCGETD	0x80045424	/* _IOR('T', 36, int) 0x5424 */
+#define TCSBRKP		0x40045424	/* _IOW('T', 37, int) 0x5425 */	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x8c105426	/* _IOR('T', 38, struct tty_struct) 0x5426 */ /* For debugging only */
+#define TIOCSBRK	0x5427		/* _IO('T', 39) */ /* BSD compatibility */
+#define TIOCCBRK	0x5428		/* _IO('T', 40) */ /* BSD compatibility */
+#define TIOCGSID	0x80045429	/* _IOR('T', 41, pid_t) 0x5429 */ /* Return the session ID of FD */
+#define TIOCGPTN	0x80045430	/* _IOR('T',0x30, unsigned int) 0x5430 Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	0x40045431	/* _IOW('T',0x31, int) Lock/unlock Pty */
+
+#define TIOCSERCONFIG	0x5453		/* _IO('T', 83) */
+#define TIOCSERGWILD	0x80045454	/* _IOR('T', 84,  int) 0x5454 */
+#define TIOCSERSWILD	0x40045455	/* _IOW('T', 85,  int) 0x5455 */
 #define TIOCGLCKTRMIOS	0x5456
 #define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	_IOR('T', 88, struct async_struct) /* 0x5458 */ /* For debugging only */
-#define TIOCSERGETLSR   _IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line status register */
-  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-# define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
-#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* 0x545A */ /* Get multiport config  */
-#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* 0x545B */ /* Set multiport config */
+#define TIOCSERGSTRUCT	0x80d85458	/* _IOR('T', 88, struct async_struct) 0x5458 */ /* For debugging only */
+#define TIOCSERGETLSR   0x80045459	/* _IOR('T', 89, unsigned int) 0x5459 */ /* Get line status register */
 
-#define TIOCMIWAIT	_IO('T', 92) /* 0x545C */	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	_IOR('T', 93, struct async_icount) /* 0x545D */	/* read serial port inline interrupt counts */
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
+#define TIOCSERGETMULTI 0x80a8545a	/* _IOR('T', 90, struct serial_multiport_struct) 0x545A */ /* Get multiport config  */
+#define TIOCSERSETMULTI 0x40a8545b	/* _IOW('T', 91, struct serial_multiport_struct) 0x545B */ /* Set multiport config */
+
+#define TIOCMIWAIT	0x545c		/* _IO('T', 92) wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x802c545d	/* _IOR('T', 93, struct async_icount) 0x545D */	/* read serial port inline interrupt counts */
 
 #endif /* __ASM_SH64_IOCTLS_H */
diff --git a/include/asm-sh64/ipc.h b/include/asm-sh64/ipc.h
--- a/include/asm-sh64/ipc.h
+++ b/include/asm-sh64/ipc.h
@@ -1,6 +1 @@
-#ifndef __ASM_SH64_IPC_H
-#define __ASM_SH64_IPC_H
-
-#include <asm-sh/ipc.h>
-
-#endif /* __ASM_SH64_IPC_H */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-sh64/irq.h b/include/asm-sh64/irq.h
--- a/include/asm-sh64/irq.h
+++ b/include/asm-sh64/irq.h
@@ -83,11 +83,12 @@
 #define IRQ_P2INTC      (START_EXT_IRQS + (3*8) + 2)
 #define IRQ_P2INTD      (START_EXT_IRQS + (3*8) + 3)
 
-#define START_EXT_IRQS  64
-
 #define I8042_KBD_IRQ	(START_EXT_IRQS + 2)
 #define I8042_AUX_IRQ	(START_EXT_IRQS + 6)
 
+#define IRQ_CFCARD	(START_EXT_IRQS + 7)
+#define IRQ_PCMCIA	(0)
+
 #else
 #define NR_EXT_IRQS	0
 #endif
diff --git a/include/asm-sh64/module.h b/include/asm-sh64/module.h
--- a/include/asm-sh64/module.h
+++ b/include/asm-sh64/module.h
@@ -4,6 +4,14 @@
  * This file contains the SH architecture specific module code.
  */
 
+struct mod_arch_specific {
+	/* empty */
+};
+
+#define Elf_Shdr		Elf32_Shdr
+#define Elf_Sym			Elf32_Sym
+#define Elf_Ehdr		Elf32_Ehdr
+
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
diff --git a/include/asm-sh64/pgalloc.h b/include/asm-sh64/pgalloc.h
--- a/include/asm-sh64/pgalloc.h
+++ b/include/asm-sh64/pgalloc.h
@@ -14,7 +14,6 @@
  *
  */
 
-#include <asm/processor.h>
 #include <linux/threads.h>
 #include <linux/mm.h>
 
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -136,6 +136,7 @@ static __inline__ void set_pte(pte_t *pt
 	 */
 	*(xp) = (x & NPHYS_SIGN) ? (x | NPHYS_MASK) : x;
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep)
 {
@@ -237,7 +238,7 @@ static inline pmd_t * pmd_offset(pgd_t *
 
 /* Round it up ! */
 #define USER_PTRS_PER_PGD	((TASK_SIZE+PGDIR_SIZE-1)/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #ifndef __ASSEMBLY__
 #define VMALLOC_END	0xff000000
@@ -280,8 +281,6 @@ static inline pmd_t * pmd_offset(pgd_t *
 
 /* Mask which drops software flags */
 #define _PAGE_FLAGS_HARDWARE_MASK	0xfffffffffffff3dbLL
-/* Flags default: 4KB, Read, Not write, Not execute, Not user */
-#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x0000000000000040LL
 
 /*
  * HugeTLB support
@@ -383,7 +382,7 @@ extern void __handle_bad_pmd_kernel(pmd_
  */
 #define _PTE_EMPTY	0x0
 #define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
-#define pte_clear(xp)	(set_pte(xp, __pte(_PTE_EMPTY)))
+#define pte_clear(mm,addr,xp)	(set_pte_at(mm, addr, xp, __pte(_PTE_EMPTY)))
 #define pte_none(x)	(pte_val(x) == _PTE_EMPTY)
 
 /*
@@ -483,6 +482,14 @@ extern void update_mmu_cache(struct vm_a
 
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/include/asm-sh64/signal.h b/include/asm-sh64/signal.h
--- a/include/asm-sh64/signal.h
+++ b/include/asm-sh64/signal.h
@@ -107,30 +107,7 @@ typedef struct {
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	THREAD_SIZE
 
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h
--- a/include/asm-sh64/system.h
+++ b/include/asm-sh64/system.h
@@ -15,7 +15,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/kernel.h>
 #include <asm/registers.h>
 #include <asm/processor.h>
 
@@ -191,4 +190,6 @@ extern void print_seg(char *file,int lin
 
 #define PL() printk("@ <%s,%s:%d>\n",__FILE__,__FUNCTION__,__LINE__)
 
+#define arch_align_stack(x) (x)
+
 #endif /* __ASM_SH64_SYSTEM_H */
diff --git a/include/asm-sh64/thread_info.h b/include/asm-sh64/thread_info.h
--- a/include/asm-sh64/thread_info.h
+++ b/include/asm-sh64/thread_info.h
@@ -61,14 +61,19 @@ static inline struct thread_info *curren
 }
 
 /* thread information allocation */
-#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,2))
+
+
+
+#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
 #define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
 #define get_thread_info(ti) get_task_struct((ti)->task)
 #define put_thread_info(ti) put_task_struct((ti)->task)
 
 #endif /* __ASSEMBLY__ */
 
-#define PREEMPT_ACTIVE		0x4000000
+#define THREAD_SIZE  8192
+
+#define PREEMPT_ACTIVE		0x10000000
 
 /* thread information flags */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
@@ -76,7 +81,6 @@ static inline struct thread_info *curren
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_MEMDIE		4
 
-#define THREAD_SIZE	16384
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-sh64/timex.h b/include/asm-sh64/timex.h
--- a/include/asm-sh64/timex.h
+++ b/include/asm-sh64/timex.h
@@ -23,8 +23,6 @@
 
 typedef unsigned long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static __inline__ cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-sh64/uaccess.h b/include/asm-sh64/uaccess.h
--- a/include/asm-sh64/uaccess.h
+++ b/include/asm-sh64/uaccess.h
@@ -60,7 +60,8 @@
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 #define __access_ok(addr,size) (__range_ok(addr,size) == 0)
 
-extern inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -313,6 +314,12 @@ struct exception_table_entry
    sh64 at the moment). */
 #define ARCH_KMALLOC_MINALIGN 8
 
+/*
+ * We want 8-byte alignment for the slab caches as well, otherwise we have
+ * the same BYTES_PER_WORD (sizeof(void *)) min align in kmem_cache_create().
+ */
+#define ARCH_SLAB_MINALIGN 8
+
 /* Returns 0 if exception not found and fixup.unit otherwise.  */
 extern unsigned long search_exception_table(unsigned long addr);
 extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
diff --git a/include/asm-sh64/unaligned.h b/include/asm-sh64/unaligned.h
--- a/include/asm-sh64/unaligned.h
+++ b/include/asm-sh64/unaligned.h
@@ -12,17 +12,6 @@
  *
  */
 
-#include <linux/string.h>
-
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* __ASM_SH64_UNALIGNED_H */
diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
--- a/include/asm-sh64/unistd.h
+++ b/include/asm-sh64/unistd.h
@@ -333,8 +333,13 @@
 #define __NR_mq_timedreceive    (__NR_mq_open+3)
 #define __NR_mq_notify          (__NR_mq_open+4)
 #define __NR_mq_getsetattr      (__NR_mq_open+5)
+#define __NR_sys_kexec_load	311
+#define __NR_waitid		312
+#define __NR_add_key		313
+#define __NR_request_key	314
+#define __NR_keyctl		315
 
-#define NR_syscalls 311
+#define NR_syscalls 316
 
 /* user-visible error numbers are in the range -1 - -125: see <asm-sh64/errno.h> */
 
@@ -549,7 +554,7 @@ static inline pid_t wait(int * wait_stat
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
 #endif /* __ASM_SH64_UNISTD_H */
diff --git a/include/asm-sparc/bug.h b/include/asm-sparc/bug.h
--- a/include/asm-sparc/bug.h
+++ b/include/asm-sparc/bug.h
@@ -1,6 +1,7 @@
 #ifndef _SPARC_BUG_H
 #define _SPARC_BUG_H
 
+#ifdef CONFIG_BUG
 /* Only use the inline asm until a gcc release that can handle __builtin_trap
  * -rob 2003-06-25
  *
@@ -26,6 +27,8 @@ extern void do_BUG(const char *file, int
 #endif
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-sparc/cacheflush.h b/include/asm-sparc/cacheflush.h
--- a/include/asm-sparc/cacheflush.h
+++ b/include/asm-sparc/cacheflush.h
@@ -50,21 +50,21 @@ BTFIXUPDEF_CALL(void, flush_cache_page, 
 #define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
 #define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
 #define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end)
-#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr)
+#define flush_cache_page(vma,addr,pfn) BTFIXUP_CALL(flush_cache_page)(vma,addr)
 #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 copy_to_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
 	} while (0)
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+	do {							\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+		memcpy(dst, src, len);				\
 	} while (0)
 
 BTFIXUPDEF_CALL(void, __flush_page_to_ram, unsigned long)
diff --git a/include/asm-sparc/errno.h b/include/asm-sparc/errno.h
--- a/include/asm-sparc/errno.h
+++ b/include/asm-sparc/errno.h
@@ -107,4 +107,8 @@
 #define	EKEYREVOKED	130	/* Key has been revoked */
 #define	EKEYREJECTED	131	/* Key was rejected by service */
 
+/* for robust mutexes */
+#define	EOWNERDEAD	132	/* Owner died */
+#define	ENOTRECOVERABLE	133	/* State not recoverable */
+
 #endif
diff --git a/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h
--- a/include/asm-sparc/floppy.h
+++ b/include/asm-sparc/floppy.h
@@ -227,7 +227,7 @@ static __inline__ void sun_fd_disable_dm
 	doing_pdma = 0;
 	if (pdma_base) {
 		mmu_unlockarea(pdma_base, pdma_areasize);
-		pdma_base = 0;
+		pdma_base = NULL;
 	}
 }
 
diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h
--- a/include/asm-sparc/io.h
+++ b/include/asm-sparc/io.h
@@ -274,4 +274,17 @@ extern void sbus_iounmap(volatile void _
 
 #endif
 
+#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED		1
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* !(__SPARC_IO_H) */
diff --git a/include/asm-sparc/ipc.h b/include/asm-sparc/ipc.h
--- a/include/asm-sparc/ipc.h
+++ b/include/asm-sparc/ipc.h
@@ -1,32 +1 @@
-#ifndef __SPARC_IPC_H__
-#define __SPARC_IPC_H__
-
-/* 
- * These are used to wrap system calls on the sparc.
- *
- * See arch/sparc/kernel/sys_sparc.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf __user *msgp;
-	long msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-sparc/mostek.h b/include/asm-sparc/mostek.h
--- a/include/asm-sparc/mostek.h
+++ b/include/asm-sparc/mostek.h
@@ -128,7 +128,6 @@ struct mostek48t08 {
 	char offset[6*1024];         /* Magic things may be here, who knows? */
 	struct mostek48t02 regs;     /* Here is what we are interested in.   */
 };
-extern struct mostek48t08 *mstk48t08_regs;
 
 extern enum sparc_clock_type sp_clock_typ;
 
diff --git a/include/asm-sparc/mxcc.h b/include/asm-sparc/mxcc.h
--- a/include/asm-sparc/mxcc.h
+++ b/include/asm-sparc/mxcc.h
@@ -115,8 +115,8 @@ extern __inline__ unsigned long mxcc_get
 {
 	unsigned long mxcc_control;
 
-	__asm__ __volatile__("set -1, %%g2\n\t"
-			     "set -1, %%g3\n\t"
+	__asm__ __volatile__("set 0xffffffff, %%g2\n\t"
+			     "set 0xffffffff, %%g3\n\t"
 			     "stda %%g2, [%1] %2\n\t"
 			     "lda [%3] %2, %0\n\t" :
 			     "=r" (mxcc_control) :
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -63,7 +63,7 @@ BTFIXUPDEF_INT(page_kernel)
 #define PTRS_PER_PMD    	BTFIXUP_SIMM13(ptrs_per_pmd)
 #define PTRS_PER_PGD    	BTFIXUP_SIMM13(ptrs_per_pgd)
 #define USER_PTRS_PER_PGD	BTFIXUP_SIMM13(user_ptrs_per_pgd)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 #define PTE_SIZE		(PTRS_PER_PTE*4)
 
 #define PAGE_NONE      __pgprot(BTFIXUP_INT(page_none))
@@ -150,6 +150,7 @@ BTFIXUPDEF_CALL_CONST(unsigned long, pgd
 BTFIXUPDEF_SETHI(none_mask)
 BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t)
 BTFIXUPDEF_CALL(void, pte_clear, pte_t *)
+BTFIXUPDEF_CALL(int, pte_read, pte_t)
 
 extern __inline__ int pte_none(pte_t pte)
 {
@@ -157,7 +158,8 @@ extern __inline__ int pte_none(pte_t pte
 }
 
 #define pte_present(pte) BTFIXUP_CALL(pte_present)(pte)
-#define pte_clear(pte) BTFIXUP_CALL(pte_clear)(pte)
+#define pte_clear(mm,addr,pte) BTFIXUP_CALL(pte_clear)(pte)
+#define pte_read(pte) BTFIXUP_CALL(pte_read)(pte)
 
 BTFIXUPDEF_CALL_CONST(int, pmd_bad, pmd_t)
 BTFIXUPDEF_CALL_CONST(int, pmd_present, pmd_t)
@@ -186,31 +188,10 @@ BTFIXUPDEF_CALL(void, pgd_clear, pgd_t *
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-BTFIXUPDEF_HALF(pte_readi)
 BTFIXUPDEF_HALF(pte_writei)
 BTFIXUPDEF_HALF(pte_dirtyi)
 BTFIXUPDEF_HALF(pte_youngi)
 
-extern int pte_read(pte_t pte) __attribute_const__;
-extern __inline__ int pte_read(pte_t pte)
-{
-	switch (sparc_cpu_model){
-	case sun4:
-	case sun4c:
-		return pte_val(pte) & BTFIXUP_HALF(pte_readi);
-	case sun4d:
-	case sun4e:
-	case sun4m:
-		return !(pte_val(pte) & BTFIXUP_HALF(pte_readi));
-	/* pacify gcc warnings */
-	case sun4u:
-	case sun_unknown:
-	case ap1000:
-	default:
-		return 0;
-	}
-}
-
 extern int pte_write(pte_t pte) __attribute_const__;
 extern __inline__ int pte_write(pte_t pte)
 {
@@ -339,6 +320,7 @@ extern unsigned int pg_iobits;
 BTFIXUPDEF_CALL(void, set_pte, pte_t *, pte_t)
 
 #define set_pte(ptep,pteval) BTFIXUP_CALL(set_pte)(ptep,pteval)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 struct seq_file;
 BTFIXUPDEF_CALL(void, mmu_info, struct seq_file *)
@@ -453,8 +435,20 @@ extern unsigned long *sparc_valid_addr_b
 #define kern_addr_valid(addr) \
 	(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to,
+extern int io_remap_page_range(struct vm_area_struct *vma,
+			       unsigned long from, unsigned long to,
 			       unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma,
+			      unsigned long from, unsigned long pfn,
+			      unsigned long size, pgprot_t prot);
+
+/*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits.  These macros/functions put it there or get it from there.
+ */
+#define MK_IOSPACE_PFN(space, pfn)	(pfn | (space << (BITS_PER_LONG - 4)))
+#define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
+#define GET_PFN(pfn)			(pfn & 0x0fffffffUL)
 
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-sparc/resource.h b/include/asm-sparc/resource.h
--- a/include/asm-sparc/resource.h
+++ b/include/asm-sparc/resource.h
@@ -8,32 +8,18 @@
 #define _SPARC_RESOURCE_H
 
 /*
- * Resource limits
+ * These two resource limit IDs have a Sparc/Linux-specific ordering,
+ * the rest comes from the generic header:
  */
-
-#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_NOFILE	6		/* max number of open files */
-#define RLIMIT_NPROC	7		/* max number of processes */
-#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 RLIMIT_SIGPENDING 11		/* max number of pending signals */
-#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
-
-#define RLIM_NLIMITS	13
-#define __ARCH_RLIMIT_ORDER
+#define RLIMIT_NOFILE		6	/* max number of open files */
+#define RLIMIT_NPROC		7	/* max number of processes */
 
 /*
  * SuS says limits have to be unsigned.
  * We make this unsigned, but keep the
- * old value.
+ * old value for compatibility:
  */
-#define RLIM_INFINITY	0x7fffffff
+#define RLIM_INFINITY		0x7fffffff
 
 #include <asm-generic/resource.h>
 
diff --git a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h
--- a/include/asm-sparc/signal.h
+++ b/include/asm-sparc/signal.h
@@ -143,7 +143,6 @@ struct sigstack {
 #define SA_ONESHOT	_SV_RESET
 #define SA_INTERRUPT	0x10u
 #define SA_NOMASK	0x20u
-#define SA_SHIRQ	0x40u
 #define SA_NOCLDWAIT	0x100u
 #define SA_SIGINFO	0x200u
 
@@ -162,11 +161,6 @@ struct sigstack {
 
 #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.
- *
  * DJHR
  * SA_STATIC_ALLOC is used for the SPARC system to indicate that this
  * interrupt handler's irq structure should be statically allocated
@@ -177,21 +171,10 @@ struct sigstack {
  * statically allocated data.. which is NOT GOOD.
  *
  */
-#define SA_PROBE SA_ONESHOT
-#define SA_SAMPLE_RANDOM SA_RESTART
 #define SA_STATIC_ALLOC		0x80
 #endif
 
-/* Type of a signal handler.  */
-#ifdef __KERNEL__
-typedef void (*__sighandler_t)(int, int, struct sigcontext *, char *);
-#else
-typedef void (*__sighandler_t)(int);
-#endif
-
-#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 */
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 struct __new_sigaction {
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -257,4 +257,6 @@ extern void die_if_kernel(char *str, str
 
 #endif /* __ASSEMBLY__ */
 
+#define arch_align_stack(x) (x)
+
 #endif /* !(__SPARC_SYSTEM_H) */
diff --git a/include/asm-sparc/timex.h b/include/asm-sparc/timex.h
--- a/include/asm-sparc/timex.h
+++ b/include/asm-sparc/timex.h
@@ -10,7 +10,6 @@
 
 /* XXX Maybe do something better at some point... -DaveM */
 typedef unsigned long cycles_t;
-extern cycles_t cacheflush_time;
 #define get_cycles()	(0)
 
 #endif
diff --git a/include/asm-sparc/uaccess.h b/include/asm-sparc/uaccess.h
--- a/include/asm-sparc/uaccess.h
+++ b/include/asm-sparc/uaccess.h
@@ -18,7 +18,7 @@
 
 #ifndef __ASSEMBLY__
 
-/* Sparc is not segmented, however we need to be able to fool verify_area()
+/* Sparc is not segmented, however we need to be able to fool access_ok()
  * when doing system calls from kernel mode legitimately.
  *
  * "For historical reasons, these macros are grossly misnamed." -Linus
@@ -41,14 +41,16 @@
  * No one can read/write anything from userland in the kernel space by setting
  * large size and address near to PAGE_OFFSET - a fault will break his intentions.
  */
-#define __user_ok(addr,size) ((addr) < STACK_TOP)
+#define __user_ok(addr, size) ({ (void)(size); (addr) < STACK_TOP; })
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
 #define __access_ok(addr,size) (__user_ok((addr) & get_fs().seg,(size)))
-#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+#define access_ok(type, addr, size)					\
+	({ (void)(type); __access_ok((unsigned long)(addr), size); })
 
-static inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
-	return access_ok(type,addr,size)?0:-EFAULT;
+	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
 
 /*
diff --git a/include/asm-sparc/unaligned.h b/include/asm-sparc/unaligned.h
--- a/include/asm-sparc/unaligned.h
+++ b/include/asm-sparc/unaligned.h
@@ -1,19 +1,6 @@
 #ifndef _ASM_SPARC_UNALIGNED_H_
 #define _ASM_SPARC_UNALIGNED_H_
 
-/* Sparc can't handle unaligned accesses. */
-
-#include <linux/string.h>
-
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* _ASM_SPARC_UNALIGNED_H */
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -79,7 +79,7 @@
 #define __NR_umask               60 /* Common                                      */
 #define __NR_chroot              61 /* Common                                      */
 #define __NR_fstat               62 /* Common                                      */
-#define __NR_fstat64		 63 /* Linux sparc32 Specific			   */
+#define __NR_fstat64		 63 /* Linux Specific			           */
 #define __NR_getpagesize         64 /* Common                                      */
 #define __NR_msync               65 /* Common in newer 1.3.x revs...               */
 #define __NR_vfork               66 /* Common                                      */
@@ -148,14 +148,14 @@
 #define __NR_truncate           129 /* Common                                      */
 #define __NR_ftruncate          130 /* Common                                      */
 #define __NR_flock              131 /* Common                                      */
-#define __NR_lstat64		132 /* Linux sparc32 Specific			   */
+#define __NR_lstat64		132 /* Linux Specific			           */
 #define __NR_sendto             133 /* Common                                      */
 #define __NR_shutdown           134 /* Common                                      */
 #define __NR_socketpair         135 /* Common                                      */
 #define __NR_mkdir              136 /* Common                                      */
 #define __NR_rmdir              137 /* Common                                      */
 #define __NR_utimes             138 /* SunOS Specific                              */
-#define __NR_stat64		139 /* Linux sparc32 Specific			   */
+#define __NR_stat64		139 /* Linux Specific			           */
 #define __NR_sendfile64         140 /* adjtime under SunOS                         */
 #define __NR_getpeername        141 /* Common                                      */
 #define __NR_futex              142 /* gethostid under SunOS                       */
@@ -513,6 +513,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _SPARC_UNISTD_H */
diff --git a/include/asm-sparc64/agp.h b/include/asm-sparc64/agp.h
--- a/include/asm-sparc64/agp.h
+++ b/include/asm-sparc64/agp.h
@@ -8,4 +8,14 @@
 #define flush_agp_mappings() 
 #define flush_agp_cache() mb()
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif
diff --git a/include/asm-sparc64/bug.h b/include/asm-sparc64/bug.h
--- a/include/asm-sparc64/bug.h
+++ b/include/asm-sparc64/bug.h
@@ -1,6 +1,7 @@
 #ifndef _SPARC64_BUG_H
 #define _SPARC64_BUG_H
 
+#ifdef CONFIG_BUG
 #include <linux/compiler.h>
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
@@ -14,6 +15,8 @@ extern void do_BUG(const char *file, int
 #endif
 
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif
diff --git a/include/asm-sparc64/bugs.h b/include/asm-sparc64/bugs.h
--- a/include/asm-sparc64/bugs.h
+++ b/include/asm-sparc64/bugs.h
@@ -8,7 +8,7 @@
 
 extern unsigned long loops_per_jiffy;
 
-static void check_bugs(void)
+static void __init check_bugs(void)
 {
 #ifndef CONFIG_SMP
 	cpu_data(0).udelay_val = loops_per_jiffy;
diff --git a/include/asm-sparc64/cacheflush.h b/include/asm-sparc64/cacheflush.h
--- a/include/asm-sparc64/cacheflush.h
+++ b/include/asm-sparc64/cacheflush.h
@@ -2,6 +2,17 @@
 #define _SPARC64_CACHEFLUSH_H
 
 #include <linux/config.h>
+#include <asm/page.h>
+
+/* Flushing for D-cache alias handling is only needed if
+ * the page size is smaller than 16K.
+ */
+#if PAGE_SHIFT < 14
+#define DCACHE_ALIASING_POSSIBLE
+#endif
+
+#ifndef __ASSEMBLY__
+
 #include <linux/mm.h>
 
 /* Cache flush operations. */
@@ -11,7 +22,7 @@
 	do { if ((__mm) == current->mm) flushw_user(); } while(0)
 #define flush_cache_range(vma, start, end) \
 	flush_cache_mm((vma)->vm_mm)
-#define flush_cache_page(vma, page) \
+#define flush_cache_page(vma, page, pfn) \
 	flush_cache_mm((vma)->vm_mm)
 
 /* 
@@ -20,9 +31,9 @@
  * module load, so we need this.
  */
 extern void flush_icache_range(unsigned long start, unsigned long end);
+extern void __flush_icache_page(unsigned long);
 
 extern void __flush_dcache_page(void *addr, int flush_icache);
-extern void __flush_icache_page(unsigned long);
 extern void flush_dcache_page_impl(struct page *page);
 #ifdef CONFIG_SMP
 extern void smp_flush_dcache_page_impl(struct page *page, int cpu);
@@ -33,27 +44,35 @@ extern void flush_dcache_page_all(struct
 #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
+extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
 #define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+extern void flush_ptrace_access(struct vm_area_struct *, struct page *,
+				unsigned long uaddr, void *kaddr,
+				unsigned long len, int write);
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len)		\
+	do {								\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));	\
+		memcpy(dst, src, len);					\
+		flush_ptrace_access(vma, page, vaddr, src, len, 0);	\
 	} while (0)
 
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		flush_cache_page(vma, vaddr);	\
-		memcpy(dst, src, len);		\
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) 		\
+	do {								\
+		flush_cache_page(vma, vaddr, page_to_pfn(page));	\
+		memcpy(dst, src, len);					\
+		flush_ptrace_access(vma, page, vaddr, dst, len, 1);	\
 	} while (0)
 
-extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#endif /* !__ASSEMBLY__ */
+
 #endif /* _SPARC64_CACHEFLUSH_H */
diff --git a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h
--- a/include/asm-sparc64/checksum.h
+++ b/include/asm-sparc64/checksum.h
@@ -38,47 +38,44 @@ extern unsigned int csum_partial(const u
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern unsigned int csum_partial_copy_sparc64(const unsigned char *src, unsigned char *dst,
+extern unsigned int csum_partial_copy_nocheck(const unsigned char *src,
+					      unsigned char *dst,
 					      int len, unsigned int sum);
-			
-static inline unsigned int 
-csum_partial_copy_nocheck (const unsigned char *src, unsigned char *dst, int len,
-			   unsigned int sum)
-{
-	int ret;
-	unsigned char cur_ds = get_thread_current_ds();
-	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
-	ret = csum_partial_copy_sparc64(src, dst, len, sum);
-	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (cur_ds));
-	return ret;
-}
 
-static inline unsigned int 
-csum_partial_copy_from_user(const unsigned char __user *src, unsigned char *dst, int len,
+extern long __csum_partial_copy_from_user(const unsigned char __user *src,
+					  unsigned char *dst, int len,
+					  unsigned int sum);
+
+static inline unsigned int
+csum_partial_copy_from_user(const unsigned char __user *src,
+			    unsigned char *dst, int len,
 			    unsigned int sum, int *err)
 {
-	__asm__ __volatile__ ("stx	%0, [%%sp + 0x7ff + 128]"
-			      : : "r" (err));
-	return csum_partial_copy_sparc64((__force const char *) src,
-					 dst, len, sum);
+	long ret = __csum_partial_copy_from_user(src, dst, len, sum);
+	if (ret < 0)
+		*err = -EFAULT;
+	return (unsigned int) ret;
 }
 
 /* 
  *	Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-extern unsigned int csum_partial_copy_user_sparc64(const unsigned char *src, unsigned char __user *dst,
-						   int len, unsigned int sum);
-
-static inline unsigned int 
-csum_and_copy_to_user(const unsigned char *src, unsigned char __user *dst, int len,
+extern long __csum_partial_copy_to_user(const unsigned char *src,
+					unsigned char __user *dst, int len,
+					  unsigned int sum);
+
+static inline unsigned int
+csum_and_copy_to_user(const unsigned char *src,
+		      unsigned char __user *dst, int len,
 		      unsigned int sum, int *err)
 {
-	__asm__ __volatile__ ("stx	%0, [%%sp + 0x7ff + 128]"
-			      : : "r" (err));
-	return csum_partial_copy_user_sparc64(src, dst, len, sum);
+	long ret = __csum_partial_copy_to_user(src, dst, len, sum);
+	if (ret < 0)
+		*err = -EFAULT;
+	return (unsigned int) ret;
 }
-  
+
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  * the majority of the time.
  */
diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
--- a/include/asm-sparc64/compat.h
+++ b/include/asm-sparc64/compat.h
@@ -51,16 +51,50 @@ struct compat_stat {
 	compat_dev_t	st_rdev;
 	compat_off_t	st_size;
 	compat_time_t	st_atime;
-	u32		__unused1;
+	compat_ulong_t	st_atime_nsec;
 	compat_time_t	st_mtime;
-	u32		__unused2;
+	compat_ulong_t	st_mtime_nsec;
 	compat_time_t	st_ctime;
-	u32		__unused3;
+	compat_ulong_t	st_ctime_nsec;
 	compat_off_t	st_blksize;
 	compat_off_t	st_blocks;
 	u32		__unused4[2];
 };
 
+struct compat_stat64 {
+	unsigned long long	st_dev;
+
+	unsigned long long	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[8];
+
+	long long	st_size;
+	unsigned int	st_blksize;
+
+	unsigned char	__pad4[8];
+	unsigned int	st_blocks;
+
+	unsigned int	st_atime;
+	unsigned int	st_atime_nsec;
+
+	unsigned int	st_mtime;
+	unsigned int	st_mtime_nsec;
+
+	unsigned int	st_ctime;
+	unsigned int	st_ctime_nsec;
+
+	unsigned int	__unused4;
+	unsigned int	__unused5;
+};
+
 struct compat_flock {
 	short		l_type;
 	short		l_whence;
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -19,12 +19,13 @@ typedef struct {
 
 	/* Dcache line 2 */
 	unsigned int	pgcache_size;
-	unsigned int	pgdcache_size;
+	unsigned int	__pad1;
 	unsigned long	*pte_cache[2];
 	unsigned long	*pgd_cache;
 } cpuinfo_sparc;
 
 DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
-#define cpu_data(__cpu)	per_cpu(__cpu_data, (__cpu))
+#define cpu_data(__cpu)		per_cpu(__cpu_data, (__cpu))
+#define local_cpu_data()	__get_cpu_var(__cpu_data)
 
 #endif /* _SPARC64_CPUDATA_H */
diff --git a/include/asm-sparc64/errno.h b/include/asm-sparc64/errno.h
--- a/include/asm-sparc64/errno.h
+++ b/include/asm-sparc64/errno.h
@@ -107,4 +107,8 @@
 #define	EKEYREVOKED	130	/* Key has been revoked */
 #define	EKEYREJECTED	131	/* Key was rejected by service */
 
+/* for robust mutexes */
+#define	EOWNERDEAD	132	/* Owner died */
+#define	ENOTRECOVERABLE	133	/* State not recoverable */
+
 #endif /* !(_SPARC64_ERRNO_H) */
diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h
+++ b/include/asm-sparc64/ide.h
@@ -13,8 +13,8 @@
 #include <linux/config.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
-#include <asm/page.h>
 #include <asm/spitfire.h>
+#include <asm/cacheflush.h>
 
 #ifndef MAX_HWIFS
 # ifdef CONFIG_BLK_DEV_IDEPCI
@@ -51,7 +51,7 @@ static inline unsigned int inw_be(void _
 
 static inline void __ide_insw(void __iomem *port, void *dst, u32 count)
 {
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 	unsigned long end = (unsigned long)dst + (count << 1);
 #endif
 	u16 *ps = dst;
@@ -74,7 +74,7 @@ static inline void __ide_insw(void __iom
 	if(count)
 		*ps++ = inw_be(port);
 
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 	__flush_dcache_range((unsigned long)dst, end);
 #endif
 }
@@ -88,7 +88,7 @@ static inline void outw_be(unsigned shor
 
 static inline void __ide_outsw(void __iomem *port, void *src, u32 count)
 {
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 	unsigned long end = (unsigned long)src + (count << 1);
 #endif
 	const u16 *ps = src;
@@ -111,7 +111,7 @@ static inline void __ide_outsw(void __io
 	if(count)
 		outw_be(*ps, port);
 
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 	__flush_dcache_range((unsigned long)src, end);
 #endif
 }
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -485,6 +485,17 @@ extern void pci_iounmap(struct pci_dev *
 #define dma_cache_wback(_start,_size)		do { } while (0)
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif
 
 #endif /* !(__SPARC64_IO_H) */
diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h
--- a/include/asm-sparc64/iommu.h
+++ b/include/asm-sparc64/iommu.h
@@ -16,4 +16,6 @@
 #define IOPTE_CACHE   0x0000000000000010UL /* Cached (in UPA E-cache)         */
 #define IOPTE_WRITE   0x0000000000000002UL /* Writeable                       */
 
+#define IOMMU_NUM_CTXS	4096
+
 #endif /* !(_SPARC_IOMMU_H) */
diff --git a/include/asm-sparc64/ipc.h b/include/asm-sparc64/ipc.h
--- a/include/asm-sparc64/ipc.h
+++ b/include/asm-sparc64/ipc.h
@@ -1,33 +1 @@
-#ifndef __SPARC64_IPC_H__
-#define __SPARC64_IPC_H__
-
-/* 
- * These are used to wrap system calls on the sparc.
- *
- * See arch/sparc64/kernel/sys_sparc32.c for ugly details..
- */
-struct ipc_kludge {
-	u32 msgp;
-	s32 msgtyp;
-};
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define SEMTIMEDOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC            25
-
-/* We don't need to maintain backward compatibility on 64bit, we've started fresh */
-#define IPCCALL(version,op)	(op)
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-sparc64/mmu.h b/include/asm-sparc64/mmu.h
--- a/include/asm-sparc64/mmu.h
+++ b/include/asm-sparc64/mmu.h
@@ -1,7 +1,99 @@
 #ifndef __MMU_H
 #define __MMU_H
 
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+#include <linux/config.h>
+#include <asm/page.h>
+#include <asm/const.h>
 
+/*
+ * For the 8k pagesize kernel, use only 10 hw context bits to optimize some
+ * shifts in the fast tlbmiss handlers, instead of all 13 bits (specifically
+ * for vpte offset calculation). For other pagesizes, this optimization in
+ * the tlbhandlers can not be done; but still, all 13 bits can not be used
+ * because the tlb handlers use "andcc" instruction which sign extends 13
+ * bit arguments.
+ */
+#if PAGE_SHIFT == 13
+#define CTX_NR_BITS		10
+#else
+#define CTX_NR_BITS		12
 #endif
+
+#define TAG_CONTEXT_BITS	((_AC(1,UL) << CTX_NR_BITS) - _AC(1,UL))
+
+/* UltraSPARC-III+ and later have a feature whereby you can
+ * select what page size the various Data-TLB instances in the
+ * chip.  In order to gracefully support this, we put the version
+ * field in a spot outside of the areas of the context register
+ * where this parameter is specified.
+ */
+#define CTX_VERSION_SHIFT	22
+#define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
+
+#define CTX_PGSZ_8KB		_AC(0x0,UL)
+#define CTX_PGSZ_64KB		_AC(0x1,UL)
+#define CTX_PGSZ_512KB		_AC(0x2,UL)
+#define CTX_PGSZ_4MB		_AC(0x3,UL)
+#define CTX_PGSZ_BITS		_AC(0x7,UL)
+#define CTX_PGSZ0_NUC_SHIFT	61
+#define CTX_PGSZ1_NUC_SHIFT	58
+#define CTX_PGSZ0_SHIFT		16
+#define CTX_PGSZ1_SHIFT		19
+#define CTX_PGSZ_MASK		((CTX_PGSZ_BITS << CTX_PGSZ0_SHIFT) | \
+				 (CTX_PGSZ_BITS << CTX_PGSZ1_SHIFT))
+
+#if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
+#define CTX_PGSZ_BASE	CTX_PGSZ_8KB
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_64KB)
+#define CTX_PGSZ_BASE	CTX_PGSZ_64KB
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_512KB)
+#define CTX_PGSZ_BASE	CTX_PGSZ_512KB
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_4MB)
+#define CTX_PGSZ_BASE	CTX_PGSZ_4MB
+#else
+#error No page size specified in kernel configuration
+#endif
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
+#define CTX_PGSZ_HUGE		CTX_PGSZ_4MB
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+#define CTX_PGSZ_HUGE		CTX_PGSZ_512KB
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+#define CTX_PGSZ_HUGE		CTX_PGSZ_64KB
+#endif
+
+#define CTX_PGSZ_KERN	CTX_PGSZ_4MB
+
+/* Thus, when running on UltraSPARC-III+ and later, we use the following
+ * PRIMARY_CONTEXT register values for the kernel context.
+ */
+#define CTX_CHEETAH_PLUS_NUC \
+	((CTX_PGSZ_KERN << CTX_PGSZ0_NUC_SHIFT) | \
+	 (CTX_PGSZ_BASE << CTX_PGSZ1_NUC_SHIFT))
+
+#define CTX_CHEETAH_PLUS_CTX0 \
+	((CTX_PGSZ_KERN << CTX_PGSZ0_SHIFT) | \
+	 (CTX_PGSZ_BASE << CTX_PGSZ1_SHIFT))
+
+/* If you want "the TLB context number" use CTX_NR_MASK.  If you
+ * want "the bits I program into the context registers" use
+ * CTX_HW_MASK.
+ */
+#define CTX_NR_MASK		TAG_CONTEXT_BITS
+#define CTX_HW_MASK		(CTX_NR_MASK | CTX_PGSZ_MASK)
+
+#define CTX_FIRST_VERSION	((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL))
+#define CTX_VALID(__ctx)	\
+	 (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK))
+#define CTX_HWBITS(__ctx)	((__ctx.sparc64_ctx_val) & CTX_HW_MASK)
+#define CTX_NRBITS(__ctx)	((__ctx.sparc64_ctx_val) & CTX_NR_MASK)
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+	unsigned long	sparc64_ctx_val;
+} mm_context_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __MMU_H */
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -4,23 +4,6 @@
 
 /* Derived heavily from Linus's Alpha/AXP ASN code... */
 
-#include <asm/page.h>
-
-/*
- * For the 8k pagesize kernel, use only 10 hw context bits to optimize some shifts in
- * the fast tlbmiss handlers, instead of all 13 bits (specifically for vpte offset
- * calculation). For other pagesizes, this optimization in the tlbhandlers can not be 
- * done; but still, all 13 bits can not be used because the tlb handlers use "andcc"
- * instruction which sign extends 13 bit arguments.
- */
-#if PAGE_SHIFT == 13
-#define CTX_VERSION_SHIFT	10
-#define TAG_CONTEXT_BITS	0x3ff
-#else
-#define CTX_VERSION_SHIFT	12
-#define TAG_CONTEXT_BITS	0xfff
-#endif
-
 #ifndef __ASSEMBLY__
 
 #include <linux/spinlock.h>
@@ -35,19 +18,14 @@ extern spinlock_t ctx_alloc_lock;
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
-#define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
-#define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
-#define CTX_VALID(__ctx)	\
-	 (!(((__ctx) ^ tlb_context_cache) & CTX_VERSION_MASK))
-#define CTX_HWBITS(__ctx)	((__ctx) & ~CTX_VERSION_MASK)
-
 extern void get_new_mmu_context(struct mm_struct *mm);
 
 /* Initialize a new mmu context.  This is invoked when a new
  * address space instance (unique or shared) is instantiated.
  * This just needs to set mm->context to an invalid context.
  */
-#define init_new_context(__tsk, __mm)	(((__mm)->context = 0UL), 0)
+#define init_new_context(__tsk, __mm)	\
+	(((__mm)->context.sparc64_ctx_val = 0UL), 0)
 
 /* Destroy a dead context.  This occurs when mmput drops the
  * mm_users count to zero, the mmaps have been released, and
@@ -59,7 +37,7 @@ extern void get_new_mmu_context(struct m
 #define destroy_context(__mm)					\
 do {	spin_lock(&ctx_alloc_lock);				\
 	if (CTX_VALID((__mm)->context)) {			\
-		unsigned long nr = CTX_HWBITS((__mm)->context);	\
+		unsigned long nr = CTX_NRBITS((__mm)->context);	\
 		mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));	\
 	}							\
 	spin_unlock(&ctx_alloc_lock);				\
@@ -101,7 +79,7 @@ do { \
 			     "flush	%%g6" \
 			     : /* No outputs */ \
 			     : "r" (CTX_HWBITS((__mm)->context)), \
-			       "r" (0x10), "i" (ASI_DMMU))
+			       "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU))
 
 extern void __flush_tlb_mm(unsigned long, unsigned long);
 
@@ -135,7 +113,8 @@ static inline void switch_mm(struct mm_s
 		 */
 		if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
 			cpu_set(cpu, mm->cpu_vm_mask);
-			__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
+			__flush_tlb_mm(CTX_HWBITS(mm->context),
+				       SECONDARY_CONTEXT);
 		}
 	}
 	spin_unlock(&mm->page_table_lock);
diff --git a/include/asm-sparc64/mostek.h b/include/asm-sparc64/mostek.h
--- a/include/asm-sparc64/mostek.h
+++ b/include/asm-sparc64/mostek.h
@@ -38,7 +38,7 @@
  *
  * We now deal with physical addresses for I/O to the chip. -DaveM
  */
-static __inline__ u8 mostek_read(unsigned long addr)
+static __inline__ u8 mostek_read(void __iomem *addr)
 {
 	u8 ret;
 
@@ -48,7 +48,7 @@ static __inline__ u8 mostek_read(unsigne
 	return ret;
 }
 
-static __inline__ void mostek_write(unsigned long addr, u8 val)
+static __inline__ void mostek_write(void __iomem *addr, u8 val)
 {
 	__asm__ __volatile__("stba	%0, [%1] %2"
 			     : /* no outputs */
@@ -67,7 +67,7 @@ static __inline__ void mostek_write(unsi
 #define MOSTEK_YEAR		0x07ffUL
 
 extern spinlock_t mostek_lock;
-extern unsigned long mstk48t02_regs;
+extern void __iomem *mstk48t02_regs;
 
 /* Control register values. */
 #define	MSTK_CREG_WRITE	0x80	/* Must set this before placing values. */
@@ -134,13 +134,11 @@ do {	u8 __val = mostek_read(regs + MOSTE
  */
 #define MOSTEK_48T08_OFFSET	0x0000UL	/* Lower NVRAM portions */
 #define MOSTEK_48T08_48T02	0x1800UL	/* Offset to 48T02 chip */
-extern unsigned long mstk48t08_regs;
 
 /* SUN5 systems usually have 48t59 model clock chipsets.  But we keep the older
  * clock chip definitions around just in case.
  */
 #define MOSTEK_48T59_OFFSET	0x0000UL	/* Lower NVRAM portions */
 #define MOSTEK_48T59_48T02	0x1800UL	/* Offset to 48T02 chip */
-extern unsigned long mstk48t59_regs;
 
 #endif /* !(_SPARC64_MOSTEK_H) */
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -6,7 +6,18 @@
 #include <linux/config.h>
 #include <asm/const.h>
 
+#if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
 #define PAGE_SHIFT   13
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_64KB)
+#define PAGE_SHIFT   16
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_512KB)
+#define PAGE_SHIFT   19
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_4MB)
+#define PAGE_SHIFT   22
+#else
+#error No page size specified in kernel configuration
+#endif
+
 #define PAGE_SIZE    (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -13,6 +13,12 @@
 
 #define PARPORT_PC_MAX_PORTS	PARPORT_MAX
 
+/*
+ * While sparc64 doesn't have an ISA DMA API, we provide something that looks
+ * close enough to make parport_pc happy
+ */
+#define HAS_DMA
+
 static struct sparc_ebus_info {
 	struct ebus_dma_info info;
 	unsigned int addr;
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -15,6 +15,7 @@
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/oplib.h>
+#include <asm/iommu.h>
 
 /* The abstraction used here is that there are PCI controllers,
  * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
@@ -40,9 +41,6 @@ struct pci_iommu {
 	 */
 	spinlock_t	lock;
 
-	/* Context allocator. */
-	unsigned int	iommu_cur_ctx;
-
 	/* IOMMU page table, a linear array of ioptes. */
 	iopte_t		*page_table;		/* The page table itself. */
 	int		page_table_sz_bits;	/* log2 of ow many pages does it map? */
@@ -87,6 +85,10 @@ struct pci_iommu {
 		u16	flush;
 	} alloc_info[PBM_NCLUSTERS];
 
+	/* CTX allocation. */
+	unsigned long ctx_lowest_free;
+	unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)];
+
 	/* Here a PCI controller driver describes the areas of
 	 * PCI memory space where DMA to/from physical memory
 	 * are addressed.  Drivers interrogate the PCI layer
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -223,7 +223,10 @@ static inline int pci_dma_mapping_error(
 /* Return the index of the PCI controller for device PDEV. */
 
 extern int pci_domain_nr(struct pci_bus *bus);
-extern int pci_name_bus(char *name, struct pci_bus *bus);
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return 1;
+}
 
 /* Platform support for /proc/bus/pci/X/Y mmap()s. */
 
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -1,6 +1,49 @@
 #ifndef __ARCH_SPARC64_PERCPU__
 #define __ARCH_SPARC64_PERCPU__
 
-#include <asm-generic/percpu.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_SMP
+
+extern void setup_per_cpu_areas(void);
+
+extern unsigned long __per_cpu_base;
+extern unsigned long __per_cpu_shift;
+#define __per_cpu_offset(__cpu) \
+	(__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift))
+
+/* Separate out the type, so (int[3], foo) works. */
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+register unsigned long __local_per_cpu_offset asm("g5");
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
+#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
+
+/* A macro to avoid #include hell... */
+#define percpu_modcopy(pcpudst, src, size)			\
+do {								\
+	unsigned int __i;					\
+	for (__i = 0; __i < NR_CPUS; __i++)			\
+		if (cpu_possible(__i))				\
+			memcpy((pcpudst)+__per_cpu_offset(__i),	\
+			       (src), (size));			\
+} while (0)
+#else /* ! SMP */
+
+#define DEFINE_PER_CPU(type, name) \
+    __typeof__(type) per_cpu__##name
+
+#define per_cpu(var, cpu)			(*((void)cpu, &per_cpu__##var))
+#define __get_cpu_var(var)			per_cpu__##var
+
+#endif	/* SMP */
+
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+
+#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
+#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
 
 #endif /* __ARCH_SPARC64_PERCPU__ */
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -7,88 +7,25 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
-#include <asm/page.h>
 #include <asm/spitfire.h>
-#include <asm/pgtable.h>
 #include <asm/cpudata.h>
+#include <asm/cacheflush.h>
 
 /* Page table allocation/freeing. */
 #ifdef CONFIG_SMP
 /* Sliiiicck */
-#define pgt_quicklists	cpu_data(smp_processor_id())
+#define pgt_quicklists	local_cpu_data()
 #else
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
 	unsigned long *pte_cache[2];
 	unsigned int pgcache_size;
-	unsigned int pgdcache_size;
 } pgt_quicklists;
 #endif
 #define pgd_quicklist		(pgt_quicklists.pgd_cache)
 #define pmd_quicklist		((unsigned long *)0)
 #define pte_quicklist		(pgt_quicklists.pte_cache)
 #define pgtable_cache_size	(pgt_quicklists.pgcache_size)
-#define pgd_cache_size		(pgt_quicklists.pgdcache_size)
-
-#ifndef CONFIG_SMP
-
-static __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-	struct page *page = virt_to_page(pgd);
-
-	preempt_disable();
-	if (!page->lru.prev) {
-		page->lru.next = (void *) pgd_quicklist;
-		pgd_quicklist = (unsigned long *)page;
-	}
-	page->lru.prev = (void *)
-	  (((unsigned long)page->lru.prev) |
-	   (((unsigned long)pgd & (PAGE_SIZE / 2)) ? 2 : 1));
-	pgd_cache_size++;
-	preempt_enable();
-}
-
-static __inline__ pgd_t *get_pgd_fast(void)
-{
-        struct page *ret;
-
-	preempt_disable();
-        if ((ret = (struct page *)pgd_quicklist) != NULL) {
-                unsigned long mask = (unsigned long)ret->lru.prev;
-		unsigned long off = 0;
-
-		if (mask & 1)
-			mask &= ~1;
-		else {
-			off = PAGE_SIZE / 2;
-			mask &= ~2;
-		}
-		ret->lru.prev = (void *) mask;
-		if (!mask)
-			pgd_quicklist = (unsigned long *)ret->lru.next;
-                ret = (struct page *)(__page_address(ret) + off);
-                pgd_cache_size--;
-		preempt_enable();
-        } else {
-		struct page *page;
-
-		preempt_enable();
-		page = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
-		if (page) {
-			ret = (struct page *)page_address(page);
-			page->lru.prev = (void *) 2UL;
-
-			preempt_disable();
-			page->lru.next = (void *) pgd_quicklist;
-			pgd_quicklist = (unsigned long *)page;
-			pgd_cache_size++;
-			preempt_enable();
-		}
-        }
-        return (pgd_t *)ret;
-}
-
-#else /* CONFIG_SMP */
 
 static __inline__ void free_pgd_fast(pgd_t *pgd)
 {
@@ -123,9 +60,7 @@ static __inline__ void free_pgd_slow(pgd
 	free_page((unsigned long)pgd);
 }
 
-#endif /* CONFIG_SMP */
-
-#if (L1DCACHE_SIZE > PAGE_SIZE)			/* is there D$ aliasing problem */
+#ifdef DCACHE_ALIASING_POSSIBLE
 #define VPTE_COLOR(address)		(((address) >> (PAGE_SHIFT + 10)) & 1UL)
 #define DCACHE_COLOR(address)		(((address) >> PAGE_SHIFT) & 1UL)
 #else
@@ -187,29 +122,16 @@ static __inline__ void free_pmd_slow(pmd
 #define pmd_populate(MM,PMD,PTE_PAGE)		\
 	pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
 
-extern pte_t *__pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address);
-
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-	pte_t *pte = __pte_alloc_one_kernel(mm, address);
-	if (pte) {
-		struct page *page = virt_to_page(pte);
-		page->mapping = (void *) mm;
-		page->index = address & PMD_MASK;
-	}
-	return pte;
-}
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address);
 
 static inline struct page *
 pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	pte_t *pte = __pte_alloc_one_kernel(mm, addr);
-	if (pte) {
-		struct page *page = virt_to_page(pte);
-		page->mapping = (void *) mm;
-		page->index = addr & PMD_MASK;
-		return page;
-	}
+	pte_t *pte = pte_alloc_one_kernel(mm, addr);
+
+	if (pte)
+		return virt_to_page(pte);
+
 	return NULL;
 }
 
@@ -246,13 +168,11 @@ static __inline__ void free_pte_slow(pte
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-	virt_to_page(pte)->mapping = NULL;
 	free_pte_fast(pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	ptepage->mapping = NULL;
 	free_pte_fast(page_address(ptepage));
 }
 
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -15,6 +15,8 @@
 #include <asm-generic/pgtable-nopud.h>
 
 #include <linux/config.h>
+#include <linux/compiler.h>
+#include <asm/types.h>
 #include <asm/spitfire.h>
 #include <asm/asi.h>
 #include <asm/system.h>
@@ -58,45 +60,25 @@
 #define PMD_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3))
 #define PMD_SIZE	(1UL << PMD_SHIFT)
 #define PMD_MASK	(~(PMD_SIZE-1))
-#define PMD_BITS	11
+#define PMD_BITS	(PAGE_SHIFT - 2)
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
 #define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3) + PMD_BITS)
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
+#define PGDIR_BITS	(PAGE_SHIFT - 2)
 
 #ifndef __ASSEMBLY__
 
 #include <linux/sched.h>
 
 /* Entries per page directory level. */
-#define PTRS_PER_PTE		(1UL << (PAGE_SHIFT-3))
-
-/* We the first one in this file, what we export to the kernel
- * is different so we can optimize correctly for 32-bit tasks.
- */
-#define REAL_PTRS_PER_PMD	(1UL << PMD_BITS)
-
-/* This is gross, but unless we do this gcc retests the
- * thread flag every interation in pmd traversal loops.
- */
-extern unsigned long __ptrs_per_pmd(void) __attribute_const__;
-#define PTRS_PER_PMD		__ptrs_per_pmd()
-
-/*
- * We cannot use the top address range because VPTE table lives there. This
- * formula finds the total legal virtual space in the processor, subtracts the
- * vpte size, then aligns it to the number of bytes mapped by one pgde, and
- * thus calculates the number of pgdes needed.
- */
-#define PTRS_PER_PGD (((1UL << VA_BITS) - VPTE_SIZE + (1UL << (PAGE_SHIFT + \
-		      (PAGE_SHIFT-3) + PMD_BITS)) - 1) / (1UL << (PAGE_SHIFT + \
-		      (PAGE_SHIFT-3) + PMD_BITS)))
+#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PMD	(1UL << PMD_BITS)
+#define PTRS_PER_PGD	(1UL << PGDIR_BITS)
 
 /* Kernel has a separate 44bit address space. */
-#define USER_PTRS_PER_PGD	((const int)(test_thread_flag(TIF_32BIT)) ? \
-				 (1) : (PTRS_PER_PGD))
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #define pte_ERROR(e)	__builtin_trap()
 #define pmd_ERROR(e)	__builtin_trap()
@@ -234,8 +216,8 @@ extern struct page *mem_map_zero;
 
 /* PFNs are real physical page numbers.  However, mem_map only begins to record
  * per-page information starting at pfn_base.  This is to handle systems where
- * the first physical page in the machine is at some huge physical address, such
- * as 4GB.   This is common on a partitioned E10000, for example.
+ * the first physical page in the machine is at some huge physical address,
+ * such as 4GB.   This is common on a partitioned E10000, for example.
  */
 
 #define pfn_pte(pfn, prot)	\
@@ -306,7 +288,7 @@ static inline pte_t pte_modify(pte_t ori
 #define pte_mkdirty(pte)	(__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD))
+#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
 #define pgd_offset(mm, address)	((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
@@ -320,7 +302,7 @@ static inline pte_t pte_modify(pte_t ori
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(pudp, address)	\
 	((pmd_t *) pud_page(*(pudp)) + \
-	 (((address) >> PMD_SHIFT) & (REAL_PTRS_PER_PMD-1)))
+	 (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)))
 
 /* Find an entry in the third-level page table.. */
 #define pte_index(dir, address)	\
@@ -333,18 +315,23 @@ static inline pte_t pte_modify(pte_t ori
 #define pte_unmap_nested(pte)		do { } while (0)
 
 /* Actual page table PTE updates.  */
-extern void tlb_batch_add(pte_t *ptep, pte_t orig);
+extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
 
-static inline void set_pte(pte_t *ptep, pte_t pte)
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
 {
 	pte_t orig = *ptep;
 
 	*ptep = pte;
-	if (pte_present(orig))
-		tlb_batch_add(ptep, orig);
+
+	/* It is more efficient to let flush_tlb_kernel_range()
+	 * handle init_mm tlb flushes.
+	 */
+	if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
+		tlb_batch_add(mm, addr, ptep, orig);
 }
 
-#define pte_clear(ptep)		set_pte((ptep), __pte(0UL))
+#define pte_clear(mm,addr,ptep)		\
+	set_pte_at((mm), (addr), (ptep), __pte(0UL))
 
 extern pgd_t swapper_pg_dir[1];
 
@@ -425,6 +412,22 @@ extern unsigned long *sparc64_valid_addr
 extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
 			       unsigned long offset,
 			       unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+			       unsigned long pfn,
+			       unsigned long size, pgprot_t prot);
+
+/* Clear virtual and physical cachability, set side-effect bit.  */
+#define pgprot_noncached(prot) \
+	(__pgprot((pgprot_val(prot) & ~(_PAGE_CP | _PAGE_CV)) | \
+	 _PAGE_E))
+
+/*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits.  These macros/functions put it there or get it from there.
+ */
+#define MK_IOSPACE_PFN(space, pfn)	(pfn | (space << (BITS_PER_LONG - 4)))
+#define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
+#define GET_PFN(pfn)			(pfn & 0x0fffffffffffffffUL)
 
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-sparc64/resource.h b/include/asm-sparc64/resource.h
--- a/include/asm-sparc64/resource.h
+++ b/include/asm-sparc64/resource.h
@@ -8,25 +8,11 @@
 #define _SPARC64_RESOURCE_H
 
 /*
- * Resource limits
+ * These two resource limit IDs have a Sparc/Linux-specific ordering,
+ * the rest comes from the generic header:
  */
-
-#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_NOFILE	6		/* max number of open files */
-#define RLIMIT_NPROC	7		/* max number of processes */
-#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 RLIMIT_SIGPENDING 11		/* max number of pending signals */
-#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
-
-#define RLIM_NLIMITS	13
-#define __ARCH_RLIMIT_ORDER
+#define RLIMIT_NOFILE		6	/* max number of open files */
+#define RLIMIT_NPROC		7	/* max number of processes */
 
 #include <asm-generic/resource.h>
 
diff --git a/include/asm-sparc64/rwsem-const.h b/include/asm-sparc64/rwsem-const.h
new file mode 100644
--- /dev/null
+++ b/include/asm-sparc64/rwsem-const.h
@@ -0,0 +1,12 @@
+/* rwsem-const.h: RW semaphore counter constants.  */
+#ifndef _SPARC64_RWSEM_CONST_H
+#define _SPARC64_RWSEM_CONST_H
+
+#define RWSEM_UNLOCKED_VALUE		0x00000000
+#define RWSEM_ACTIVE_BIAS		0x00000001
+#define RWSEM_ACTIVE_MASK		0x0000ffff
+#define RWSEM_WAITING_BIAS		0xffff0000
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+#endif /* _SPARC64_RWSEM_CONST_H */
diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h
--- a/include/asm-sparc64/rwsem.h
+++ b/include/asm-sparc64/rwsem.h
@@ -15,17 +15,12 @@
 
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <asm/rwsem-const.h>
 
 struct rwsem_waiter;
 
 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		0xffff0000
-#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;
 };
@@ -56,16 +51,16 @@ static __inline__ int rwsem_atomic_updat
 	int tmp = delta;
 
 	__asm__ __volatile__(
-		"1:\tlduw	[%2], %%g5\n\t"
-		"add		%%g5, %1, %%g7\n\t"
-		"cas		[%2], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
+		"1:\tlduw	[%2], %%g1\n\t"
+		"add		%%g1, %1, %%g7\n\t"
+		"cas		[%2], %%g1, %%g7\n\t"
+		"cmp		%%g1, %%g7\n\t"
 		"bne,pn		%%icc, 1b\n\t"
 		" membar	#StoreLoad | #StoreStore\n\t"
 		"mov		%%g7, %0\n\t"
 		: "=&r" (tmp)
 		: "0" (tmp), "r" (sem)
-		: "g5", "g7", "memory", "cc");
+		: "g1", "g7", "memory", "cc");
 
 	return tmp + delta;
 }
diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h
--- a/include/asm-sparc64/siginfo.h
+++ b/include/asm-sparc64/siginfo.h
@@ -3,9 +3,6 @@
 
 #define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
 
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
 #define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
 #define __ARCH_SI_TRAPNO
 #define __ARCH_SI_BAND_T int
@@ -19,11 +16,6 @@
 
 #ifdef CONFIG_COMPAT
 
-typedef union sigval32 {
-	int sival_int;
-	u32 sival_ptr;
-} sigval_t32;
-
 struct compat_siginfo;
 
 #endif /* CONFIG_COMPAT */
@@ -38,26 +30,4 @@ struct compat_siginfo;
 #define EMT_TAGOVF	(__SI_FAULT|1)	/* tag overflow */
 #define NSIGEMT		1
 
-#ifdef __KERNEL__
-
-#ifdef CONFIG_COMPAT
-
-typedef struct sigevent32 {
-	sigval_t32 sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE32];
-
-		struct {
-			u32 _function;
-			u32 _attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t32;
-
-#endif /* CONFIG_COMPAT */
-
-#endif /* __KERNEL__ */
-
 #endif
diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h
--- a/include/asm-sparc64/signal.h
+++ b/include/asm-sparc64/signal.h
@@ -145,7 +145,6 @@ struct sigstack {
 #define SA_ONESHOT	_SV_RESET
 #define SA_INTERRUPT	0x10u
 #define SA_NOMASK	0x20u
-#define SA_SHIRQ	0x40u
 #define SA_NOCLDWAIT    0x100u
 #define SA_SIGINFO      0x200u
 
@@ -165,11 +164,6 @@ struct sigstack {
 
 #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.
- *
  * DJHR
  * SA_STATIC_ALLOC is used for the SPARC system to indicate that this
  * interrupt handler's irq structure should be statically allocated
@@ -180,26 +174,10 @@ struct sigstack {
  * statically allocated data.. which is NOT GOOD.
  *
  */
-#define SA_PROBE SA_ONESHOT
-#define SA_SAMPLE_RANDOM SA_RESTART
 #define SA_STATIC_ALLOC		0x80
 #endif
 
-/* Type of a signal handler.  */
-#ifdef __KERNEL__
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-#else
-typedef void (*__sighandler_t)(int);
-typedef void (*__sigrestore_t)(void);
-#endif
-
-#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 */
+#include <asm-generic/signal.h>
 
 struct __new_sigaction {
 	__sighandler_t		sa_handler;
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -30,8 +30,6 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-extern unsigned char boot_cpu_id;
-
 extern cpumask_t phys_cpu_present_map;
 #define cpu_possible_map phys_cpu_present_map
 
diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
--- a/include/asm-sparc64/spinlock.h
+++ b/include/asm-sparc64/spinlock.h
@@ -31,15 +31,20 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
+typedef struct {
+	volatile unsigned char lock;
+#ifdef CONFIG_PREEMPT
+	unsigned int break_lock;
+#endif
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0,}
 
-#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
-#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
+#define spin_lock_init(lp)	do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(lp)  ((lp)->lock != 0)
 
-#define spin_unlock_wait(lock)	\
+#define spin_unlock_wait(lp)	\
 do {	membar("#LoadLoad");	\
-} while(*((volatile unsigned char *)lock))
+} while((lp)->lock)
 
 static inline void _raw_spin_lock(spinlock_t *lock)
 {
@@ -109,20 +114,19 @@ static inline void _raw_spin_lock_flags(
 #else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
-	unsigned char lock;
+	volatile unsigned char lock;
 	unsigned int owner_pc, owner_cpu;
+#ifdef CONFIG_PREEMPT
+	unsigned int break_lock;
+#endif
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0xff }
-#define spin_lock_init(__lock)	\
-do {	(__lock)->lock = 0; \
-	(__lock)->owner_pc = 0; \
-	(__lock)->owner_cpu = 0xff; \
-} while(0)
-#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+#define spin_lock_init(lp)	do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(__lock)	((__lock)->lock != 0)
 #define spin_unlock_wait(__lock)	\
 do { \
 	membar("#LoadLoad"); \
-} while(*((volatile unsigned char *)(&((__lock)->lock))))
+} while((__lock)->lock)
 
 extern void _do_spin_lock (spinlock_t *lock, char *str);
 extern void _do_spin_unlock (spinlock_t *lock);
@@ -139,8 +143,13 @@ extern int _do_spin_trylock (spinlock_t 
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED	0
+typedef struct {
+	volatile unsigned int lock;
+#ifdef CONFIG_PREEMPT
+	unsigned int break_lock;
+#endif
+} rwlock_t;
+#define RW_LOCK_UNLOCKED	(rwlock_t) {0,}
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
 
 static void inline __read_lock(rwlock_t *lock)
@@ -251,9 +260,12 @@ static int inline __write_trylock(rwlock
 #else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
-	unsigned long lock;
+	volatile unsigned long lock;
 	unsigned int writer_pc, writer_cpu;
 	unsigned int reader_pc[NR_CPUS];
+#ifdef CONFIG_PREEMPT
+	unsigned int break_lock;
+#endif
 } rwlock_t;
 #define RW_LOCK_UNLOCKED	(rwlock_t) { 0, 0, 0xff, { } }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
@@ -304,6 +316,8 @@ do {	unsigned long flags; \
 #endif /* CONFIG_DEBUG_SPINLOCK */
 
 #define _raw_read_trylock(lock) generic_raw_read_trylock(lock)
+#define read_can_lock(rw)	(!((rw)->lock & 0x80000000UL))
+#define write_can_lock(rw)	(!(rw)->lock)
 
 #endif /* !(__ASSEMBLY__) */
 
diff --git a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h
--- a/include/asm-sparc64/spitfire.h
+++ b/include/asm-sparc64/spitfire.h
@@ -34,6 +34,9 @@
 #define PHYS_WATCHPOINT		0x0000000000000040
 
 #define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
+#define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
+
+#define L1DCACHE_SIZE		0x4000
 
 #ifndef __ASSEMBLY__
 
@@ -45,9 +48,8 @@ enum ultra_tlb_layout {
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
-
-#define L1DCACHE_SIZE		0x4000
+extern int cheetah_pcache_forced_on;
+extern void cheetah_enable_pcache(void);
 
 #define sparc64_highest_locked_tlbent()	\
 	(tlb_type == spitfire ? \
@@ -100,46 +102,6 @@ static __inline__ void spitfire_put_dsfs
 			     : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_DMMU));
 }
 
-static __inline__ unsigned long spitfire_get_primary_context(void)
-{
-	unsigned long ctx;
-
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
-			     : "=r" (ctx)
-			     : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-	return ctx;
-}
-
-static __inline__ void spitfire_set_primary_context(unsigned long ctx)
-{
-	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-			     "membar	#Sync"
-			     : /* No outputs */
-			     : "r" (ctx & 0x3ff),
-			       "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-	__asm__ __volatile__ ("membar #Sync" : : : "memory");
-}
-
-static __inline__ unsigned long spitfire_get_secondary_context(void)
-{
-	unsigned long ctx;
-
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
-			     : "=r" (ctx)
-			     : "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU));
-	return ctx;
-}
-
-static __inline__ void spitfire_set_secondary_context(unsigned long ctx)
-{
-	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-			     "membar	#Sync"
-			     : /* No outputs */
-			     : "r" (ctx & 0x3ff),
-			       "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU));
-	__asm__ __volatile__ ("membar #Sync" : : : "memory");
-}
-
 /* The data cache is write through, so this just invalidates the
  * specified line.
  */
diff --git a/include/asm-sparc64/stat.h b/include/asm-sparc64/stat.h
--- a/include/asm-sparc64/stat.h
+++ b/include/asm-sparc64/stat.h
@@ -21,43 +21,28 @@ struct stat {
 	unsigned long  __unused4[2];
 };
 
-#ifdef __KERNEL__
-/* This is sparc32 stat64 structure. */
-
 struct stat64 {
-	unsigned long long	st_dev;
-
-	unsigned long long	st_ino;
+	unsigned long	st_dev;
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
 
 	unsigned int	st_mode;
-	unsigned int	st_nlink;
-
 	unsigned int	st_uid;
 	unsigned int	st_gid;
+	unsigned int	__pad0;
 
-	unsigned long long	st_rdev;
-
-	unsigned char	__pad3[8];
-
-	long long	st_size;
-	unsigned int	st_blksize;
-
-	unsigned char	__pad4[8];
-	unsigned int	st_blocks;
-
-	unsigned int	st_atime;
-	unsigned int	st_atime_nsec;
-
-	unsigned int	st_mtime;
-	unsigned int	st_mtime_nsec;
-
-	unsigned int	st_ctime;
-	unsigned int	st_ctime_nsec;
-
-	unsigned int	__unused4;
-	unsigned int	__unused5;
+	unsigned long	st_rdev;
+	long		st_size;
+	long		st_blksize;
+	long		st_blocks;
+
+	unsigned long	st_atime;
+	unsigned long	st_atime_nsec;
+	unsigned long	st_mtime;
+	unsigned long	st_mtime_nsec;
+	unsigned long	st_ctime;
+	unsigned long	st_ctime_nsec;
+	long		__unused[3];
 };
 
 #endif
-
-#endif
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -182,7 +182,7 @@ do {	if (test_thread_flag(TIF_PERFCTR)) 
 	__asm__ __volatile__("wr %%g0, %0, %%asi"			\
 	: : "r" (__thread_flag_byte_ptr(next->thread_info)[TI_FLAG_BYTE_CURRENT_DS]));\
 	__asm__ __volatile__(						\
-	"mov	%%g4, %%g5\n\t"						\
+	"mov	%%g4, %%g7\n\t"						\
 	"wrpr	%%g0, 0x95, %%pstate\n\t"				\
 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"				\
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"				\
@@ -207,7 +207,7 @@ do {	if (test_thread_flag(TIF_PERFCTR)) 
 	"wrpr	%%g0, 0x96, %%pstate\n\t"				\
 	"andcc	%%o7, %6, %%g0\n\t"					\
 	"beq,pt %%icc, 1f\n\t"						\
-	" mov	%%g5, %0\n\t"						\
+	" mov	%%g7, %0\n\t"						\
 	"b,a ret_from_syscall\n\t"					\
 	"1:\n\t"							\
 	: "=&r" (last)							\
@@ -215,7 +215,7 @@ do {	if (test_thread_flag(TIF_PERFCTR)) 
 	  "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_FLAGS), "i" (TI_CWP),	\
 	  "i" (_TIF_NEWCHILD), "i" (TI_TASK)				\
 	: "cc",								\
-	        "g1", "g2", "g3",       "g5",       "g7",		\
+	        "g1", "g2", "g3",                   "g7",		\
 	              "l2", "l3", "l4", "l5", "l6", "l7",		\
 	  "i0", "i1", "i2", "i3", "i4", "i5",				\
 	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7" EXTRA_CLOBBER);\
@@ -226,37 +226,41 @@ do {	if (test_thread_flag(TIF_PERFCTR)) 
 	}								\
 } while(0)
 
-static __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
+static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
 {
+	unsigned long tmp1, tmp2;
+
 	__asm__ __volatile__(
 "	membar		#StoreLoad | #LoadLoad\n"
-"	mov		%0, %%g5\n"
-"1:	lduw		[%2], %%g7\n"
-"	cas		[%2], %%g7, %0\n"
-"	cmp		%%g7, %0\n"
+"	mov		%0, %1\n"
+"1:	lduw		[%4], %2\n"
+"	cas		[%4], %2, %0\n"
+"	cmp		%2, %0\n"
 "	bne,a,pn	%%icc, 1b\n"
-"	 mov		%%g5, %0\n"
+"	 mov		%1, %0\n"
 "	membar		#StoreLoad | #StoreStore\n"
-	: "=&r" (val)
+	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
 	: "0" (val), "r" (m)
-	: "g5", "g7", "cc", "memory");
+	: "cc", "memory");
 	return val;
 }
 
-static __inline__ unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
+static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
 {
+	unsigned long tmp1, tmp2;
+
 	__asm__ __volatile__(
 "	membar		#StoreLoad | #LoadLoad\n"
-"	mov		%0, %%g5\n"
-"1:	ldx		[%2], %%g7\n"
-"	casx		[%2], %%g7, %0\n"
-"	cmp		%%g7, %0\n"
+"	mov		%0, %1\n"
+"1:	ldx		[%4], %2\n"
+"	casx		[%4], %2, %0\n"
+"	cmp		%2, %0\n"
 "	bne,a,pn	%%xcc, 1b\n"
-"	 mov		%%g5, %0\n"
+"	 mov		%1, %0\n"
 "	membar		#StoreLoad | #StoreStore\n"
-	: "=&r" (val)
+	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
 	: "0" (val), "r" (m)
-	: "g5", "g7", "cc", "memory");
+	: "cc", "memory");
 	return val;
 }
 
@@ -341,4 +345,6 @@ __cmpxchg(volatile void *ptr, unsigned l
 
 #endif /* !(__ASSEMBLY__) */
 
+#define arch_align_stack(x) (x)
+
 #endif /* !(__SPARC64_SYSTEM_H) */
diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h
--- a/include/asm-sparc64/tlb.h
+++ b/include/asm-sparc64/tlb.h
@@ -44,7 +44,7 @@ extern void flush_tlb_pending(void);
 
 static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 {
-	struct mmu_gather *mp = &per_cpu(mmu_gathers, smp_processor_id());
+	struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
 
 	BUG_ON(mp->tlb_nr);
 
@@ -80,18 +80,16 @@ static inline void tlb_finish_mmu(struct
 {
 	unsigned long freed = mp->freed;
 	struct mm_struct *mm = mp->mm;
-	unsigned long rss = mm->rss;
+	unsigned long rss = get_mm_counter(mm, rss);
 
 	if (rss < freed)
 		freed = rss;
-	mm->rss = rss - freed;
+	add_mm_counter(mm, rss, -freed);
 
 	tlb_flush_mmu(mp);
 
 	if (mp->tlb_frozen) {
-		unsigned long context = mm->context;
-
-		if (CTX_VALID(context))
+		if (CTX_VALID(mm->context))
 			do_flush_tlb_mm(mm);
 		mp->tlb_frozen = 0;
 	} else
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h
--- a/include/asm-sparc64/uaccess.h
+++ b/include/asm-sparc64/uaccess.h
@@ -49,12 +49,18 @@ do {										\
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg));	\
 } while(0)
 
-#define __user_ok(addr,size) ((void)(addr), (void)(size), 1)
-#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
-#define __access_ok(addr,size) ((void)(addr), (void)(size), 1)
-#define access_ok(type,addr,size) ((void)(type), (void)(addr), (void)(size), 1)
+static inline int __access_ok(const void __user * addr, unsigned long size)
+{
+	return 1;
+}
+
+static inline int access_ok(int type, const void __user * addr, unsigned long size)
+{
+	return 1;
+}
 
-static inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return 0;
 }
diff --git a/include/asm-sparc64/unaligned.h b/include/asm-sparc64/unaligned.h
--- a/include/asm-sparc64/unaligned.h
+++ b/include/asm-sparc64/unaligned.h
@@ -1,19 +1,6 @@
 #ifndef _ASM_SPARC64_UNALIGNED_H_
 #define _ASM_SPARC64_UNALIGNED_H_
 
-/* Sparc can't handle unaligned accesses. */
-
-#include <linux/string.h>
-
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* _ASM_SPARC64_UNALIGNED_H */
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -79,7 +79,7 @@
 #define __NR_umask               60 /* Common                                      */
 #define __NR_chroot              61 /* Common                                      */
 #define __NR_fstat               62 /* Common                                      */
-/* #define __NR_fstat64          63    Linux sparc32 Specific                      */
+#define __NR_fstat64             63 /* Linux Specific                              */
 #define __NR_getpagesize         64 /* Common                                      */
 #define __NR_msync               65 /* Common in newer 1.3.x revs...               */
 #define __NR_vfork               66 /* Common                                      */
@@ -148,14 +148,14 @@
 #define __NR_truncate           129 /* Common                                      */
 #define __NR_ftruncate          130 /* Common                                      */
 #define __NR_flock              131 /* Common                                      */
-/* #define __NR_lstat64		132    Linux sparc32 Specific                      */
+#define __NR_lstat64		132 /* Linux Specific                              */
 #define __NR_sendto             133 /* Common                                      */
 #define __NR_shutdown           134 /* Common                                      */
 #define __NR_socketpair         135 /* Common                                      */
 #define __NR_mkdir              136 /* Common                                      */
 #define __NR_rmdir              137 /* Common                                      */
 #define __NR_utimes             138 /* SunOS Specific                              */
-/* #define __NR_stat64		139    Linux sparc32 Specific			   */
+#define __NR_stat64		139 /* Linux Specific			           */
 #define __NR_sendfile64         140 /* adjtime under SunOS                         */
 #define __NR_getpeername        141 /* Common                                      */
 #define __NR_futex              142 /* gethostid under SunOS                       */
@@ -509,6 +509,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif /* _SPARC64_UNISTD_H */
diff --git a/include/asm-um/arch-signal-i386.h b/include/asm-um/arch-signal-i386.h
deleted file mode 100644
--- a/include/asm-um/arch-signal-i386.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_ARCH_SIGNAL_I386_H
-#define __UM_ARCH_SIGNAL_I386_H
-
-struct arch_signal_context {
-	unsigned long extrasigs[_NSIG_WORDS];
-};
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
--- a/include/asm-um/archparam-i386.h
+++ b/include/asm-um/archparam-i386.h
@@ -6,143 +6,6 @@
 #ifndef __UM_ARCHPARAM_I386_H
 #define __UM_ARCHPARAM_I386_H
 
-/********* Bits for asm-um/elf.h ************/
-
-#include "user.h"
-
-extern char * elf_aux_platform;
-#define ELF_PLATFORM (elf_aux_platform)
-
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
-
-typedef struct user_i387_struct elf_fpregset_t;
-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];
-
-#define ELF_DATA        ELFDATA2LSB
-#define ELF_ARCH        EM_386
-
-#define ELF_PLAT_INIT(regs, load_addr) do { \
-	PT_REGS_EBX(regs) = 0; \
-	PT_REGS_ECX(regs) = 0; \
-	PT_REGS_EDX(regs) = 0; \
-	PT_REGS_ESI(regs) = 0; \
-	PT_REGS_EDI(regs) = 0; \
-	PT_REGS_EBP(regs) = 0; \
-	PT_REGS_EAX(regs) = 0; \
-} while(0)
-
-/* Shamelessly stolen from include/asm-i386/elf.h */
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs) do {	\
-	pr_reg[0] = PT_REGS_EBX(regs);		\
-	pr_reg[1] = PT_REGS_ECX(regs);		\
-	pr_reg[2] = PT_REGS_EDX(regs);		\
-	pr_reg[3] = PT_REGS_ESI(regs);		\
-	pr_reg[4] = PT_REGS_EDI(regs);		\
-	pr_reg[5] = PT_REGS_EBP(regs);		\
-	pr_reg[6] = PT_REGS_EAX(regs);		\
-	pr_reg[7] = PT_REGS_DS(regs);		\
-	pr_reg[8] = PT_REGS_ES(regs);		\
-	/* fake once used fs and gs selectors? */	\
-	pr_reg[9] = PT_REGS_DS(regs);		\
-	pr_reg[10] = PT_REGS_DS(regs);		\
-	pr_reg[11] = PT_REGS_SYSCALL_NR(regs);	\
-	pr_reg[12] = PT_REGS_IP(regs);		\
-	pr_reg[13] = PT_REGS_CS(regs);		\
-	pr_reg[14] = PT_REGS_EFLAGS(regs);	\
-	pr_reg[15] = PT_REGS_SP(regs);		\
-	pr_reg[16] = PT_REGS_SS(regs);		\
-} while(0);
-
-
-extern unsigned long vsyscall_ehdr;
-extern unsigned long vsyscall_end;
-extern unsigned long __kernel_vsyscall;
-
-#define VSYSCALL_BASE vsyscall_ehdr
-#define VSYSCALL_END vsyscall_end
-
-/*
- * This is the range that is readable by user mode, and things
- * acting like user mode such as get_user_pages.
- */
-#define FIXADDR_USER_START      VSYSCALL_BASE
-#define FIXADDR_USER_END        VSYSCALL_END
-
-/*
- * Architecture-neutral AT_ values in 0-17, leave some room
- * for more of them, start the x86-specific ones at 32.
- */
-#define AT_SYSINFO		32
-#define AT_SYSINFO_EHDR		33
-
-#define ARCH_DLINFO						\
-do {								\
-	if ( vsyscall_ehdr ) {					\
-		NEW_AUX_ENT(AT_SYSINFO,	__kernel_vsyscall);	\
-		NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr);	\
-	}							\
-} while (0)
-
-/*
- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
- * extra segments containing the vsyscall DSO contents.  Dumping its
- * contents makes post-mortem fully interpretable later without matching up
- * the same kernel and hardware config to see what PC values meant.
- * Dumping its extra ELF program headers includes all the other information
- * a debugger needs to easily find how the vsyscall DSO was being used.
- */
-#define ELF_CORE_EXTRA_PHDRS						      \
-	(vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0 )
-
-#define ELF_CORE_WRITE_EXTRA_PHDRS					      \
-if ( vsyscall_ehdr ) {							      \
-	const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr;    \
-	const struct elf_phdr *const phdrp =				      \
-		(const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff);   \
-	int i;								      \
-	Elf32_Off ofs = 0;						      \
-	for (i = 0; i < ehdrp->e_phnum; ++i) {				      \
-		struct elf_phdr phdr = phdrp[i];			      \
-		if (phdr.p_type == PT_LOAD) {				      \
-			ofs = phdr.p_offset = offset;			      \
-			offset += phdr.p_filesz;			      \
-		}							      \
-		else							      \
-			phdr.p_offset += ofs;				      \
-		phdr.p_paddr = 0; /* match other core phdrs */		      \
-		DUMP_WRITE(&phdr, sizeof(phdr));			      \
-	}								      \
-}
-#define ELF_CORE_WRITE_EXTRA_DATA					      \
-if ( vsyscall_ehdr ) {							      \
-	const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr;    \
-	const struct elf_phdr *const phdrp =				      \
-		(const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff);   \
-	int i;								      \
-	for (i = 0; i < ehdrp->e_phnum; ++i) {				      \
-		if (phdrp[i].p_type == PT_LOAD)				      \
-			DUMP_WRITE((void *) phdrp[i].p_vaddr,		      \
-				   phdrp[i].p_filesz);			      \
-	}								      \
-}
-
-#define R_386_NONE	0
-#define R_386_32	1
-#define R_386_PC32	2
-#define R_386_GOT32	3
-#define R_386_PLT32	4
-#define R_386_COPY	5
-#define R_386_GLOB_DAT	6
-#define R_386_JMP_SLOT	7
-#define R_386_RELATIVE	8
-#define R_386_GOTOFF	9
-#define R_386_GOTPC	10
-#define R_386_NUM	11
-
 /********* Nothing for asm-um/hardirq.h **********/
 
 /********* Nothing for asm-um/hw_irq.h **********/
diff --git a/include/asm-um/archparam-ppc.h b/include/asm-um/archparam-ppc.h
--- a/include/asm-um/archparam-ppc.h
+++ b/include/asm-um/archparam-ppc.h
@@ -1,26 +1,6 @@
 #ifndef __UM_ARCHPARAM_PPC_H
 #define __UM_ARCHPARAM_PPC_H
 
-/********* Bits for asm-um/elf.h ************/
-
-#define ELF_PLATFORM (0)
-
-#define ELF_ET_DYN_BASE (0x08000000)
-
-/* the following stolen from asm-ppc/elf.h */
-#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
-#define ELF_NFPREG	33	/* includes fpscr */
-/* General registers */
-typedef unsigned long elf_greg_t;
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-/* Floating point registers */
-typedef double elf_fpreg_t;
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-
-#define ELF_DATA        ELFDATA2MSB
-#define ELF_ARCH	EM_PPC
-
 /********* Bits for asm-um/hw_irq.h **********/
 
 struct hw_interrupt_type;
diff --git a/include/asm-um/archparam-x86_64.h b/include/asm-um/archparam-x86_64.h
--- a/include/asm-um/archparam-x86_64.h
+++ b/include/asm-um/archparam-x86_64.h
@@ -7,42 +7,6 @@
 #ifndef __UM_ARCHPARAM_X86_64_H
 #define __UM_ARCHPARAM_X86_64_H
 
-#include <asm/user.h>
-
-#define ELF_PLATFORM "x86_64"
-
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
-
-typedef unsigned long elf_greg_t;
-typedef struct { } elf_fpregset_t;
-
-#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-#define ELF_DATA        ELFDATA2LSB
-#define ELF_ARCH        EM_X86_64
-
-#define ELF_PLAT_INIT(regs, load_addr)    do { \
-	PT_REGS_RBX(regs) = 0; \
-	PT_REGS_RCX(regs) = 0; \
-	PT_REGS_RDX(regs) = 0; \
-	PT_REGS_RSI(regs) = 0; \
-	PT_REGS_RDI(regs) = 0; \
-	PT_REGS_RBP(regs) = 0; \
-	PT_REGS_RAX(regs) = 0; \
-	PT_REGS_R8(regs) = 0; \
-	PT_REGS_R9(regs) = 0; \
-	PT_REGS_R10(regs) = 0; \
-	PT_REGS_R11(regs) = 0; \
-	PT_REGS_R12(regs) = 0; \
-	PT_REGS_R13(regs) = 0; \
-	PT_REGS_R14(regs) = 0; \
-	PT_REGS_R15(regs) = 0; \
-} while (0)
-
-#ifdef TIF_IA32 /* XXX */
-        clear_thread_flag(TIF_IA32);
-#endif
 
 /* No user-accessible fixmap addresses, i.e. vsyscall */
 #define FIXADDR_USER_START	0
diff --git a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S
--- a/include/asm-um/common.lds.S
+++ b/include/asm-um/common.lds.S
@@ -8,11 +8,6 @@
   _sdata = .;
   PROVIDE (sdata = .);
 
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
   RODATA
 
   .unprotected : { *(.unprotected) }
@@ -20,6 +15,10 @@
   PROVIDE (_unprotected_end = .);
 
   . = ALIGN(4096);
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
   __uml_setup_start = .;
   .uml.setup.init : { *(.uml.setup.init) }
   __uml_setup_end = .;
diff --git a/include/asm-um/delay.h b/include/asm-um/delay.h
--- a/include/asm-um/delay.h
+++ b/include/asm-um/delay.h
@@ -4,4 +4,6 @@
 #include "asm/arch/delay.h"
 #include "asm/archparam.h"
 
+#define MILLION 1000000
+
 #endif
diff --git a/include/asm-um/elf-i386.h b/include/asm-um/elf-i386.h
new file mode 100644
--- /dev/null
+++ b/include/asm-um/elf-i386.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+#ifndef __UM_ELF_I386_H
+#define __UM_ELF_I386_H
+
+#include <asm/user.h>
+
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+
+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;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+	(((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
+
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define ELF_PLAT_INIT(regs, load_addr) do { \
+	PT_REGS_EBX(regs) = 0; \
+	PT_REGS_ECX(regs) = 0; \
+	PT_REGS_EDX(regs) = 0; \
+	PT_REGS_ESI(regs) = 0; \
+	PT_REGS_EDI(regs) = 0; \
+	PT_REGS_EBP(regs) = 0; \
+	PT_REGS_EAX(regs) = 0; \
+} while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+/* Shamelessly stolen from include/asm-i386/elf.h */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do {	\
+	pr_reg[0] = PT_REGS_EBX(regs);		\
+	pr_reg[1] = PT_REGS_ECX(regs);		\
+	pr_reg[2] = PT_REGS_EDX(regs);		\
+	pr_reg[3] = PT_REGS_ESI(regs);		\
+	pr_reg[4] = PT_REGS_EDI(regs);		\
+	pr_reg[5] = PT_REGS_EBP(regs);		\
+	pr_reg[6] = PT_REGS_EAX(regs);		\
+	pr_reg[7] = PT_REGS_DS(regs);		\
+	pr_reg[8] = PT_REGS_ES(regs);		\
+	/* fake once used fs and gs selectors? */	\
+	pr_reg[9] = PT_REGS_DS(regs);		\
+	pr_reg[10] = PT_REGS_DS(regs);		\
+	pr_reg[11] = PT_REGS_SYSCALL_NR(regs);	\
+	pr_reg[12] = PT_REGS_IP(regs);		\
+	pr_reg[13] = PT_REGS_CS(regs);		\
+	pr_reg[14] = PT_REGS_EFLAGS(regs);	\
+	pr_reg[15] = PT_REGS_SP(regs);		\
+	pr_reg[16] = PT_REGS_SS(regs);		\
+} while(0);
+
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
+
+extern char * elf_aux_platform;
+#define ELF_PLATFORM (elf_aux_platform)
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+extern unsigned long vsyscall_ehdr;
+extern unsigned long vsyscall_end;
+extern unsigned long __kernel_vsyscall;
+
+#define VSYSCALL_BASE vsyscall_ehdr
+#define VSYSCALL_END vsyscall_end
+
+/*
+ * This is the range that is readable by user mode, and things
+ * acting like user mode such as get_user_pages.
+ */
+#define FIXADDR_USER_START      VSYSCALL_BASE
+#define FIXADDR_USER_END        VSYSCALL_END
+
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them, start the x86-specific ones at 32.
+ */
+#define AT_SYSINFO		32
+#define AT_SYSINFO_EHDR		33
+
+#define ARCH_DLINFO						\
+do {								\
+	if ( vsyscall_ehdr ) {					\
+		NEW_AUX_ENT(AT_SYSINFO,	__kernel_vsyscall);	\
+		NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr);	\
+	}							\
+} while (0)
+
+/*
+ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
+ * extra segments containing the vsyscall DSO contents.  Dumping its
+ * contents makes post-mortem fully interpretable later without matching up
+ * the same kernel and hardware config to see what PC values meant.
+ * Dumping its extra ELF program headers includes all the other information
+ * a debugger needs to easily find how the vsyscall DSO was being used.
+ */
+#define ELF_CORE_EXTRA_PHDRS						      \
+	(vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0 )
+
+#define ELF_CORE_WRITE_EXTRA_PHDRS					      \
+if ( vsyscall_ehdr ) {							      \
+	const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr;    \
+	const struct elf_phdr *const phdrp =				      \
+		(const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff);   \
+	int i;								      \
+	Elf32_Off ofs = 0;						      \
+	for (i = 0; i < ehdrp->e_phnum; ++i) {				      \
+		struct elf_phdr phdr = phdrp[i];			      \
+		if (phdr.p_type == PT_LOAD) {				      \
+			ofs = phdr.p_offset = offset;			      \
+			offset += phdr.p_filesz;			      \
+		}							      \
+		else							      \
+			phdr.p_offset += ofs;				      \
+		phdr.p_paddr = 0; /* match other core phdrs */		      \
+		DUMP_WRITE(&phdr, sizeof(phdr));			      \
+	}								      \
+}
+#define ELF_CORE_WRITE_EXTRA_DATA					      \
+if ( vsyscall_ehdr ) {							      \
+	const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr;    \
+	const struct elf_phdr *const phdrp =				      \
+		(const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff);   \
+	int i;								      \
+	for (i = 0; i < ehdrp->e_phnum; ++i) {				      \
+		if (phdrp[i].p_type == PT_LOAD)				      \
+			DUMP_WRITE((void *) phdrp[i].p_vaddr,		      \
+				   phdrp[i].p_filesz);			      \
+	}								      \
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/include/asm-um/elf-ppc.h b/include/asm-um/elf-ppc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-um/elf-ppc.h
@@ -0,0 +1,54 @@
+#ifndef __UM_ELF_PPC_H
+#define __UM_ELF_PPC_H
+
+#include "linux/config.h"
+
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+#define ELF_EXEC_PAGESIZE 4096
+
+#define elf_check_arch(x) (1)
+
+#ifdef CONFIG_64_BIT
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#define USE_ELF_CORE_DUMP
+
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+
+#define ELF_PLATFORM (0)
+
+#define ELF_ET_DYN_BASE (0x08000000)
+
+/* the following stolen from asm-ppc/elf.h */
+#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
+#define ELF_NFPREG	33	/* includes fpscr */
+/* General registers */
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Floating point registers */
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_DATA        ELFDATA2MSB
+#define ELF_ARCH	EM_PPC
+
+#endif
diff --git a/include/asm-um/elf-x86_64.h b/include/asm-um/elf-x86_64.h
new file mode 100644
--- /dev/null
+++ b/include/asm-um/elf-x86_64.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2003 PathScale, Inc.
+ *
+ * Licensed under the GPL
+ */
+#ifndef __UM_ELF_X86_64_H
+#define __UM_ELF_X86_64_H
+
+#include <asm/user.h>
+
+/* x86-64 relocation types, taken from asm-x86_64/elf.h */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM		16
+
+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 { } elf_fpregset_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)
+
+#define ELF_CLASS	ELFCLASS64
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_X86_64
+
+#define ELF_PLAT_INIT(regs, load_addr)    do { \
+	PT_REGS_RBX(regs) = 0; \
+	PT_REGS_RCX(regs) = 0; \
+	PT_REGS_RDX(regs) = 0; \
+	PT_REGS_RSI(regs) = 0; \
+	PT_REGS_RDI(regs) = 0; \
+	PT_REGS_RBP(regs) = 0; \
+	PT_REGS_RAX(regs) = 0; \
+	PT_REGS_R8(regs) = 0; \
+	PT_REGS_R9(regs) = 0; \
+	PT_REGS_R10(regs) = 0; \
+	PT_REGS_R11(regs) = 0; \
+	PT_REGS_R12(regs) = 0; \
+	PT_REGS_R13(regs) = 0; \
+	PT_REGS_R14(regs) = 0; \
+	PT_REGS_R15(regs) = 0; \
+} while (0)
+
+#ifdef TIF_IA32 /* XXX */
+#error XXX, indeed
+        clear_thread_flag(TIF_IA32);
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
+
+#define ELF_PLATFORM "x86_64"
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h
deleted file mode 100644
--- a/include/asm-um/elf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __UM_ELF_H
-#define __UM_ELF_H
-
-#include "linux/config.h"
-#include "asm/archparam.h"
-
-extern long elf_aux_hwcap;
-#define ELF_HWCAP (elf_aux_hwcap)
-
-#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
-
-#define ELF_EXEC_PAGESIZE 4096
-
-#define elf_check_arch(x) (1)
-
-#ifdef CONFIG_64_BIT
-#define ELF_CLASS ELFCLASS64
-#else
-#define ELF_CLASS ELFCLASS32
-#endif
-
-#define USE_ELF_CORE_DUMP
-
-#define R_386_NONE	0
-#define R_386_32	1
-#define R_386_PC32	2
-#define R_386_GOT32	3
-#define R_386_PLT32	4
-#define R_386_COPY	5
-#define R_386_GLOB_DAT	6
-#define R_386_JMP_SLOT	7
-#define R_386_RELATIVE	8
-#define R_386_GOTOFF	9
-#define R_386_GOTPC	10
-#define R_386_NUM	11
-
-#endif
diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
--- a/include/asm-um/fixmap.h
+++ b/include/asm-um/fixmap.h
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <asm/kmap_types.h>
 #include <asm/archparam.h>
+#include <asm/elf.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
diff --git a/include/asm-um/io.h b/include/asm-um/io.h
--- a/include/asm-um/io.h
+++ b/include/asm-um/io.h
@@ -22,4 +22,15 @@ static inline void * phys_to_virt(unsign
 	return __va(address);
 }
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif
diff --git a/include/asm-um/ipc.h b/include/asm-um/ipc.h
--- a/include/asm-um/ipc.h
+++ b/include/asm-um/ipc.h
@@ -1,6 +1 @@
-#ifndef __UM_IPC_H
-#define __UM_IPC_H
-
-#include "asm/arch/ipc.h"
-
-#endif
+#include <asm-generic/ipc.h>
diff --git a/include/asm-um/linkage.h b/include/asm-um/linkage.h
--- a/include/asm-um/linkage.h
+++ b/include/asm-um/linkage.h
@@ -1,7 +1,6 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
+#ifndef __ASM_UM_LINKAGE_H
+#define __ASM_UM_LINKAGE_H
 
-#define FASTCALL(x)	x __attribute__((regparm(3)))
-#define fastcall        __attribute__((regparm(3)))
+#include "asm/arch/linkage.h"
 
 #endif
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -27,7 +27,7 @@ struct page;
 #define clear_user_page(page, vaddr, pg)	clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64_BIT)
+#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT)
 
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
 typedef struct { unsigned long long pmd; } pmd_t;
@@ -45,6 +45,9 @@ typedef struct { unsigned long pgd; } pg
 	({ (pte).pte_high = (phys) >> 32; \
 	   (pte).pte_low = (phys) | pgprot_val(prot); })
 
+#define pmd_val(x)	((x).pmd)
+#define __pmd(x) ((pmd_t) { (x) } )
+
 typedef unsigned long long pfn_t;
 typedef unsigned long long phys_t;
 
@@ -95,7 +98,13 @@ extern unsigned long uml_physmem;
 
 extern unsigned long to_phys(void *virt);
 extern void *to_virt(unsigned long phys);
-#define __pa(virt) to_phys((void *) virt)
+
+/* Cast to unsigned long before casting to void * to avoid a warning from
+ * mmap_kmem about cutting a long long down to a void *.  Not sure that
+ * casting is the right thing, but 32-bit UML can't have 64-bit virtual
+ * addresses
+ */
+#define __pa(virt) to_phys((void *) (unsigned long) virt)
 #define __va(phys) to_virt((unsigned long) phys)
 
 #define page_to_pfn(page) ((page) - mem_map)
diff --git a/include/asm-um/pgtable-2level.h b/include/asm-um/pgtable-2level.h
--- a/include/asm-um/pgtable-2level.h
+++ b/include/asm-um/pgtable-2level.h
@@ -21,10 +21,9 @@
  * we don't really have any PMD directory physically.
  */
 #define PTRS_PER_PTE	1024
-#define PTRS_PER_PMD	1
 #define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
 #define PTRS_PER_PGD	1024
-#define FIRST_USER_PGD_NR       0
+#define FIRST_USER_ADDRESS	0
 
 #define pte_ERROR(e) \
         printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), \
@@ -59,6 +58,7 @@ static inline void set_pte(pte_t *pteptr
 	*pteptr = pte_mknewpage(pteval);
 	if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
 
diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h
--- a/include/asm-um/pgtable-3level.h
+++ b/include/asm-um/pgtable-3level.h
@@ -31,7 +31,7 @@
 #define PTRS_PER_PMD 512
 #define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
 #define PTRS_PER_PGD 512
-#define FIRST_USER_PGD_NR       0
+#define FIRST_USER_ADDRESS	0
 
 #define pte_ERROR(e) \
         printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \
@@ -84,6 +84,7 @@ static inline void set_pte(pte_t *pteptr
 	*pteptr = pte_mknewpage(*pteptr);
 	if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
 }
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 #define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
 
@@ -144,11 +145,11 @@ static inline pmd_t pfn_pmd(pfn_t page_n
  */
 #define PTE_FILE_MAX_BITS	32
 
-#ifdef CONFIG_64_BIT
+#ifdef CONFIG_64BIT
 
 #define pte_to_pgoff(p) ((p).pte >> 32)
 
-#define pgoff_to_pte(off) ((pte_t) { ((off) < 32) | _PAGE_FILE })
+#define pgoff_to_pte(off) ((pte_t) { ((off) << 32) | _PAGE_FILE })
 
 #else
 
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -106,7 +106,7 @@ extern unsigned long end_iomem;
 /*
  * Define this if things work differently on an i386 and an i486:
  * it will (on an i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
+ * done without a 'access_ok(VERIFY_WRITE,..)'
  */
 #undef TEST_VERIFY_AREA
 
@@ -114,17 +114,9 @@ extern unsigned long end_iomem;
 extern unsigned long pg0[1024];
 
 /*
- * 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)
 
@@ -142,7 +134,7 @@ extern pte_t * __bad_pagetable(void);
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
-#define pte_clear(xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE))
+#define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE))
 
 #define pmd_none(x)	(!(pmd_val(x) & ~_PAGE_NEWPAGE))
 #define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -16,15 +16,14 @@ struct task_struct;
 
 struct mm_struct;
 
-#define cpu_relax()   barrier()
-
 struct thread_struct {
+	/* This flag is set to 1 before calling do_fork (and analyzed in
+	 * copy_thread) to mark that we are begin called from userspace (fork /
+	 * vfork / clone), and reset to 0 after. It is left to 0 when called
+	 * from kernelspace (i.e. kernel_thread() or fork_idle(), as of 2.6.11). */
 	int forking;
 	int nsyscalls;
 	struct pt_regs regs;
-	unsigned long cr2;
-	int err;
-	unsigned long trap_no;
 	int singlestep_syscall;
 	void *fault_addr;
 	void *fault_catcher;
@@ -72,8 +71,6 @@ struct thread_struct {
 	.forking		= 0, \
 	.nsyscalls		= 0, \
         .regs		   	= EMPTY_REGS, \
-	.cr2			= 0, \
-	.err			= 0, \
 	.fault_addr		= NULL, \
 	.prev_sched		= NULL, \
 	.temp_stack		= 0, \
@@ -91,7 +88,11 @@ extern struct task_struct *alloc_task_st
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 extern void dump_thread(struct pt_regs *regs, struct user *u);
-extern void prepare_to_copy(struct task_struct *tsk);
+
+static inline void prepare_to_copy(struct task_struct *tsk)
+{
+}
+
 
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -9,16 +9,29 @@
 extern int host_has_xmm;
 extern int host_has_cmov;
 
+/* include faultinfo structure */
+#include "sysdep/faultinfo.h"
+
 struct arch_thread {
 	unsigned long debugregs[8];
 	int debugregs_seq;
+	struct faultinfo faultinfo;
 };
 
 #define INIT_ARCH_THREAD { .debugregs  		= { [ 0 ... 7 ] = 0 }, \
-                           .debugregs_seq	= 0 }
+                           .debugregs_seq	= 0, \
+                           .faultinfo		= { 0, 0, 0 } }
 
 #include "asm/arch/user.h"
 
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+	__asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax()	rep_nop()
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter"). Stolen
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h
--- a/include/asm-um/processor-x86_64.h
+++ b/include/asm-um/processor-x86_64.h
@@ -7,12 +7,28 @@
 #ifndef __UM_PROCESSOR_X86_64_H
 #define __UM_PROCESSOR_X86_64_H
 
-#include "asm/arch/user.h"
+/* include faultinfo structure */
+#include "sysdep/faultinfo.h"
 
 struct arch_thread {
+        unsigned long debugregs[8];
+        int debugregs_seq;
+        struct faultinfo faultinfo;
 };
 
-#define INIT_ARCH_THREAD { }
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+extern inline void rep_nop(void)
+{
+	__asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax()   rep_nop()
+
+#define INIT_ARCH_THREAD { .debugregs  		= { [ 0 ... 7 ] = 0 }, \
+                           .debugregs_seq	= 0, \
+                           .faultinfo		= { 0, 0, 0 } }
+
+#include "asm/arch/user.h"
 
 #define current_text_addr() \
 	({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; })
diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
--- a/include/asm-um/ptrace-i386.h
+++ b/include/asm-um/ptrace-i386.h
@@ -6,6 +6,8 @@
 #ifndef __UM_PTRACE_I386_H
 #define __UM_PTRACE_I386_H
 
+#define HOST_AUDIT_ARCH AUDIT_ARCH_I386
+
 #include "sysdep/ptrace.h"
 #include "asm/ptrace-generic.h"
 
diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
--- a/include/asm-um/ptrace-x86_64.h
+++ b/include/asm-um/ptrace-x86_64.h
@@ -14,6 +14,8 @@
 #include "asm/ptrace-generic.h"
 #undef signal_fault
 
+#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
+
 void signal_fault(struct pt_regs_subarch *regs, void *frame, char *where);
 
 #define FS_BASE (21 * sizeof(unsigned long))
diff --git a/include/asm-um/setup.h b/include/asm-um/setup.h
--- a/include/asm-um/setup.h
+++ b/include/asm-um/setup.h
@@ -1,6 +1,10 @@
 #ifndef SETUP_H_INCLUDED
 #define SETUP_H_INCLUDED
 
-#define COMMAND_LINE_SIZE 512
+/* POSIX mandated with _POSIX_ARG_MAX that we can rely on 4096 chars in the
+ * command line, so this choice is ok.
+ */
+
+#define COMMAND_LINE_SIZE 4096
 
 #endif		/* SETUP_H_INCLUDED */
diff --git a/include/asm-um/signal.h b/include/asm-um/signal.h
--- a/include/asm-um/signal.h
+++ b/include/asm-um/signal.h
@@ -11,6 +11,9 @@
 #define do_signal do_signal_renamed
 #include "asm/arch/signal.h"
 #undef do_signal
+#undef ptrace_signal_deliver
+
+#define ptrace_signal_deliver(regs, cookie) do {} while(0)
 
 #endif
 
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -41,18 +41,17 @@ struct thread_info {
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
+#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
 	struct thread_info *ti;
-	unsigned long mask = PAGE_SIZE *
-		(1 << CONFIG_KERNEL_STACK_ORDER) - 1;
-        ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
+	unsigned long mask = THREAD_SIZE - 1;
+	ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
 	return ti;
 }
 
 /* thread information allocation */
-#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
 #define alloc_thread_info(tsk) \
 	((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL))
 #define free_thread_info(ti) kfree(ti)
@@ -62,7 +61,7 @@ static inline struct thread_info *curren
 
 #endif
 
-#define PREEMPT_ACTIVE		0x4000000
+#define PREEMPT_ACTIVE		0x10000000
 
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
@@ -72,12 +71,14 @@ static inline struct thread_info *curren
 					 */
 #define TIF_RESTART_BLOCK 	4
 #define TIF_MEMDIE	 	5
+#define TIF_SYSCALL_AUDIT	6
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
-#define _TIF_RESTART_BLOCK	(1 << TIF_RESTART_BLOCK)
+#define _TIF_MEMDIE		(1 << TIF_MEMDIE)
+#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 
 #endif
 
diff --git a/include/asm-um/timex.h b/include/asm-um/timex.h
--- a/include/asm-um/timex.h
+++ b/include/asm-um/timex.h
@@ -3,8 +3,6 @@
 
 typedef unsigned long cycles_t;
 
-#define cacheflush_time (0)
-
 static inline cycles_t get_cycles (void)
 {
 	return 0;
diff --git a/include/asm-v850/bug.h b/include/asm-v850/bug.h
--- a/include/asm-v850/bug.h
+++ b/include/asm-v850/bug.h
@@ -14,9 +14,12 @@
 #ifndef __V850_BUG_H__
 #define __V850_BUG_H__
 
+#ifdef CONFIG_BUG
 extern void __bug (void) __attribute__ ((noreturn));
 #define BUG()		__bug()
 #define HAVE_ARCH_BUG
+#endif
+
 #include <asm-generic/bug.h>
 
 #endif /* __V850_BUG_H__ */
diff --git a/include/asm-v850/cacheflush.h b/include/asm-v850/cacheflush.h
--- a/include/asm-v850/cacheflush.h
+++ b/include/asm-v850/cacheflush.h
@@ -25,7 +25,7 @@
 #define flush_cache_all()			((void)0)
 #define flush_cache_mm(mm)			((void)0)
 #define flush_cache_range(vma, start, end)	((void)0)
-#define flush_cache_page(vma, vmaddr)		((void)0)
+#define flush_cache_page(vma, vmaddr, pfn)	((void)0)
 #define flush_dcache_page(page)			((void)0)
 #define flush_dcache_mmap_lock(mapping)		((void)0)
 #define flush_dcache_mmap_unlock(mapping)	((void)0)
diff --git a/include/asm-v850/io.h b/include/asm-v850/io.h
--- a/include/asm-v850/io.h
+++ b/include/asm-v850/io.h
@@ -119,4 +119,15 @@ outsl (unsigned long port, const void *s
 #define memcpy_fromio(dst, src, len) memcpy (dst, (void *)src, len)
 #define memcpy_toio(dst, src, len) memcpy ((void *)dst, src, len)
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __V850_IO_H__ */
diff --git a/include/asm-v850/ipc.h b/include/asm-v850/ipc.h
--- a/include/asm-v850/ipc.h
+++ b/include/asm-v850/ipc.h
@@ -1,31 +1 @@
-#ifndef __V850_IPC_H__
-#define __V850_IPC_H__
-
-/* 
- * These are used to wrap system calls on v850.
- *
- * See arch/v850/kernel/syscalls.c for ugly details..
- */
-struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
-};
-
-#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
-
-/* Used by the DIPC package, try and avoid reusing it */
-#define DIPC		25
-
-#define IPCCALL(version,op)	((version)<<16 | (op))
-
-#endif /* __V850_IPC_H__ */
+#include <asm-generic/ipc.h>
diff --git a/include/asm-v850/signal.h b/include/asm-v850/signal.h
--- a/include/asm-v850/signal.h
+++ b/include/asm-v850/signal.h
@@ -110,32 +110,7 @@ typedef unsigned long sigset_t;
 #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 /* __KERNEL__ */
-
-
-#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 */
-
+#include <asm-generic/signal.h>
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h
--- a/include/asm-v850/system.h
+++ b/include/asm-v850/system.h
@@ -108,4 +108,6 @@ extern inline unsigned long __xchg (unsi
 	return tmp;
 }
 
+#define arch_align_stack(x) (x)
+
 #endif /* __V850_SYSTEM_H__ */
diff --git a/include/asm-v850/uaccess.h b/include/asm-v850/uaccess.h
--- a/include/asm-v850/uaccess.h
+++ b/include/asm-v850/uaccess.h
@@ -27,7 +27,8 @@ extern inline int access_ok (int type, c
 	return val >= (0x80 + NUM_CPU_IRQS*16) && val < 0xFFFFF000;
 }
 
-extern inline int verify_area (int type, const void *addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area (int type, const void *addr, unsigned long size)
 {
 	return access_ok (type, addr, size) ? 0 : -EFAULT;
 }
diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h
--- a/include/asm-v850/unistd.h
+++ b/include/asm-v850/unistd.h
@@ -466,7 +466,7 @@ asmlinkage long sys_rt_sigaction(int sig
  */
 #define cond_syscall(name)						      \
   asm (".weak\t" C_SYMBOL_STRING(name) ";"				      \
-       ".set\t" C_SYMBOL_STRING(name) "," C_SYMBOL_STRING(sys_ni_syscall));
+       ".set\t" C_SYMBOL_STRING(name) "," C_SYMBOL_STRING(sys_ni_syscall))
 #if 0
 /* This doesn't work if there's a function prototype for NAME visible,
    because the argument types probably won't match.  */
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -153,7 +153,6 @@ static inline int acpi_irq_balance_set(c
 
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
-extern int acpi_save_state_disk(void);
 extern void acpi_restore_state_mem(void);
 
 extern unsigned long acpi_wakeup_address;
diff --git a/include/asm-x86_64/agp.h b/include/asm-x86_64/agp.h
--- a/include/asm-x86_64/agp.h
+++ b/include/asm-x86_64/agp.h
@@ -19,4 +19,14 @@ int unmap_page_from_agp(struct page *pag
    worth it. Would need a page for it. */
 #define flush_agp_cache() asm volatile("wbinvd":::"memory")
 
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
 #endif
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -99,7 +99,6 @@ extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 extern void clustered_apic_check(void);
 
-extern int check_nmi_watchdog(void);
 extern void nmi_watchdog_default(void);
 extern int setup_nmi_watchdog(char *);
 
diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h
--- a/include/asm-x86_64/apicdef.h
+++ b/include/asm-x86_64/apicdef.h
@@ -112,7 +112,7 @@
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
-#define MAX_IO_APICS 32
+#define MAX_IO_APICS 128
 
 /*
  * All x86-64 systems are xAPIC compatible.
diff --git a/include/asm-x86_64/bootsetup.h b/include/asm-x86_64/bootsetup.h
--- a/include/asm-x86_64/bootsetup.h
+++ b/include/asm-x86_64/bootsetup.h
@@ -2,7 +2,8 @@
 #ifndef _X86_64_BOOTSETUP_H
 #define _X86_64_BOOTSETUP_H 1
 
-extern char x86_boot_params[2048];
+#define BOOT_PARAM_SIZE		4096
+extern char x86_boot_params[BOOT_PARAM_SIZE];
 
 /*
  * This is set up by the setup-routine at boot-time
diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h
--- a/include/asm-x86_64/bug.h
+++ b/include/asm-x86_64/bug.h
@@ -15,11 +15,15 @@ struct bug_frame {
 	unsigned short line;
 } __attribute__((packed));
 
+#ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
 #define BUG() \
 	asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \
-		     "i"(__LINE__), "i" (__stringify(KBUILD_BASENAME)))
+		     "i"(__LINE__), "i" (__stringify(__FILE__)))
 void out_of_line_bug(void);
-#include <asm-generic/bug.h>
+#else
+static inline void out_of_line_bug(void) { }
+#endif
 
+#include <asm-generic/bug.h>
 #endif
diff --git a/include/asm-x86_64/cacheflush.h b/include/asm-x86_64/cacheflush.h
--- a/include/asm-x86_64/cacheflush.h
+++ b/include/asm-x86_64/cacheflush.h
@@ -8,7 +8,7 @@
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -7,7 +7,7 @@
 #ifndef __ASM_X8664_CPUFEATURE_H
 #define __ASM_X8664_CPUFEATURE_H
 
-#define NCAPINTS	6
+#define NCAPINTS	7	/* N 32-bit words worth of info */
 
 /* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
 #define X86_FEATURE_FPU		(0*32+ 0) /* Onboard FPU */
@@ -62,6 +62,7 @@
 #define X86_FEATURE_CYRIX_ARR	(3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR	(3*32+ 3) /* Centaur MCRs (= MTRRs) */
 #define X86_FEATURE_K8_C	(3*32+ 4) /* C stepping K8 */
+#define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
@@ -73,9 +74,15 @@
 #define X86_FEATURE_CX16	(4*32+13) /* CMPXCHG16B */
 #define X86_FEATURE_XTPR	(4*32+14) /* Send Task Priority Messages */
 
-/* More extended AMD flags: CPUID level 0x80000001, ecx, word 5 */
-#define X86_FEATURE_LAHF_LM	(5*32+ 0) /* LAHF/SAHF in long mode */
-#define X86_FEATURE_CMP_LEGACY	(5*32+ 1) /* If yes HyperThreading not valid */
+/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
+#define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
+#define X86_FEATURE_XSTORE_EN	(5*32+ 3) /* on-CPU RNG enabled */
+#define X86_FEATURE_XCRYPT	(5*32+ 6) /* on-CPU crypto (xcrypt insn) */
+#define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* on-CPU crypto enabled */
+
+/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
+#define X86_FEATURE_LAHF_LM	(6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY	(6*32+ 1) /* If yes HyperThreading not valid */
 
 #define cpu_has(c, bit)                test_bit(bit, (c)->x86_capability)
 #define boot_cpu_has(bit)      test_bit(bit, boot_cpu_data.x86_capability)
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -14,7 +14,7 @@
 #include <linux/mmzone.h>
 
 #define E820MAP	0x2d0		/* our map */
-#define E820MAX	32		/* number of entries in E820MAP */
+#define E820MAX	128		/* number of entries in E820MAP */
 #define E820NR	0x1e8		/* # entries in E820MAP */
 
 #define E820_RAM	1
@@ -50,6 +50,7 @@ extern void e820_print_map(char *who);
 extern int e820_mapped(unsigned long start, unsigned long end, unsigned type);
 
 extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
+extern void e820_setup_gap(void);
 
 extern void __init parse_memopt(char *p, char **end);
 
diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h
--- a/include/asm-x86_64/floppy.h
+++ b/include/asm-x86_64/floppy.h
@@ -223,7 +223,7 @@ static int hard_dma_setup(char *addr, un
 	return 0;
 }
 
-struct fd_routine_l {
+static 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);
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -36,11 +36,7 @@
   *  - 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
@@ -329,6 +325,17 @@ out:
 extern int iommu_bio_merge;
 #define BIO_VMERGE_BOUNDARY iommu_bio_merge
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -202,7 +202,6 @@ extern int skip_ioapic_setup;
 #define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
 
 #ifdef CONFIG_ACPI_BOOT
-extern int io_apic_get_unique_id (int ioapic, int apic_id);
 extern int io_apic_get_version (int ioapic);
 extern int io_apic_get_redir_entries (int ioapic);
 extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
diff --git a/include/asm-x86_64/ioctl32.h b/include/asm-x86_64/ioctl32.h
deleted file mode 100644
--- a/include/asm-x86_64/ioctl32.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <linux/ioctl32.h>
diff --git a/include/asm-x86_64/ipc.h b/include/asm-x86_64/ipc.h
deleted file mode 100644
--- a/include/asm-x86_64/ipc.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __x8664_IPC_H__
-#define __x8664_IPC_H__
-
-/* dummy */
-
-#endif
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -23,7 +23,6 @@ enum die_val { 
 	DIE_OOPS = 1,
 	DIE_INT3,
 	DIE_DEBUG,
-	DIE_DEBUGSTEP,
 	DIE_PANIC,
 	DIE_NMI,
 	DIE_DIE,
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -45,7 +45,8 @@ static __inline__ void local_sub(unsigne
 		:"ir" (i), "m" (v->counter));
 }
 
-/* On x86, these are no better than the atomic variants. */
+/* On x86-64 these are better than the atomic variants on SMP kernels
+   because they dont use a lock prefix. */
 #define __local_inc(l)		local_inc(l)
 #define __local_dec(l)		local_dec(l)
 #define __local_add(i,l)	local_add((i),(l))
diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
--- a/include/asm-x86_64/mmu_context.h
+++ b/include/asm-x86_64/mmu_context.h
@@ -28,6 +28,11 @@ static inline void enter_lazy_tlb(struct
 }
 #endif
 
+static inline void load_cr3(pgd_t *pgd)
+{
+	asm volatile("movq %0,%%cr3" :: "r" (__pa(pgd)) : "memory");
+}
+
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
 			     struct task_struct *tsk)
 {
@@ -40,7 +45,8 @@ static inline void switch_mm(struct mm_s
 		write_pda(active_mm, next);
 #endif
 		set_bit(cpu, &next->cpu_vm_mask);
-		asm volatile("movq %0,%%cr3" :: "r" (__pa(next->pgd)) : "memory");
+		load_cr3(next->pgd);
+
 		if (unlikely(next->context.ldt != prev->context.ldt)) 
 			load_LDT_nolock(&next->context, cpu);
 	}
@@ -54,7 +60,7 @@ static inline void switch_mm(struct mm_s
 			 * tlb flush IPI delivery. We must reload CR3
 			 * to make sure to use no freed page tables.
 			 */
-			asm volatile("movq %0,%%cr3" :: "r" (__pa(next->pgd)) : "memory");
+			load_cr3(next->pgd);
 			load_LDT_nolock(&next->context, cpu);
 		}
 	}
diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
--- a/include/asm-x86_64/mpspec.h
+++ b/include/asm-x86_64/mpspec.h
@@ -156,7 +156,7 @@ struct mpc_config_lintsrc
  *	7	2 CPU MCA+PCI
  */
 
-#define MAX_MP_BUSSES 270
+#define MAX_MP_BUSSES 256
 #define MAX_IRQ_SOURCES 256
 enum mp_bustype {
 	MP_BUS_ISA = 1,
@@ -176,7 +176,6 @@ extern int apic_version [MAX_APICS];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
 extern int mpc_default_type;
-extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
 
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -28,8 +28,8 @@
 
 #define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) 
 
-/* wrmsrl with exception handling */
-#define checking_wrmsrl(msr,val) ({ int ret__;						\
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ int ret__;						\
 	asm volatile("2: wrmsr ; xorl %0,%0\n"						\
 		     "1:\n\t"								\
 		     ".section .fixup,\"ax\"\n\t"					\
@@ -40,9 +40,11 @@
 		     "   .quad 	2b,3b\n\t"						\
 		     ".previous"							\
 		     : "=a" (ret__)							\
-		     : "c" (msr), "0" ((__u32)val), "d" ((val)>>32), "i" (-EFAULT));\
+		     : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
 	ret__; })
 
+#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
+
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
 
@@ -78,6 +80,18 @@ extern inline void cpuid(int op, unsigne
 		: "0" (op));
 }
 
+/* Some CPUID calls want 'count' to be placed in ecx */
+static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+	       	int *edx)
+{
+	__asm__("cpuid"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op), "c" (count));
+}
+
 /*
  * CPUID functions returning a single datum
  */
@@ -149,6 +163,7 @@ extern inline unsigned int cpuid_edx(uns
 #define EFER_NX (1<<_EFER_NX)
 
 /* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_TSC		0x10
 #define MSR_IA32_PLATFORM_ID	0x17
 
 #define MSR_IA32_PERFCTR0      0xc1
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -53,5 +53,7 @@ extern void die_nmi(char *str, struct pt
 
 extern int panic_on_timeout;
 extern int unknown_nmi_panic;
+
+extern int check_nmi_watchdog(void);
  
 #endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -63,10 +63,6 @@ typedef struct { unsigned long pgprot; }
 #define __pgd(x) ((pgd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 
-extern unsigned long vm_stack_flags, vm_stack_flags32;
-extern unsigned long vm_data_default_flags, vm_data_default_flags32;
-extern unsigned long vm_force_exec32;
-
 #define __START_KERNEL		0xffffffff80100000UL
 #define __START_KERNEL_map	0xffffffff80000000UL
 #define __PAGE_OFFSET           0xffff810000000000UL
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -1,7 +1,6 @@
 #ifndef _X86_64_PGALLOC_H
 #define _X86_64_PGALLOC_H
 
-#include <asm/processor.h>
 #include <asm/fixmap.h>
 #include <asm/pda.h>
 #include <linux/threads.h>
@@ -99,7 +98,8 @@ extern inline void pte_free(struct page 
 } 
 
 #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
-#define __pmd_free_tlb(tlb,x)   pmd_free(x)
-#define __pud_free_tlb(tlb,x)   pud_free(x)
+
+#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
+#define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
 
 #endif /* _X86_64_PGALLOC_H */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -73,6 +73,7 @@ static inline void set_pte(pte_t *dst, p
 {
 	pte_val(*dst) = pte_val(val);
 } 
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 static inline void set_pmd(pmd_t *dst, pmd_t val)
 {
@@ -102,7 +103,7 @@ extern inline void pgd_clear (pgd_t * pg
 #define pud_page(pud) \
 ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
 
-#define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte, 0))
+#define ptep_get_and_clear(mm,addr,xp)	__pte(xchg(&(xp)->pte, 0))
 #define pte_same(a, b)		((a).pte == (b).pte)
 
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -113,7 +114,7 @@ extern inline void pgd_clear (pgd_t * pg
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR	0
+#define FIRST_USER_ADDRESS	0
 
 #ifndef __ASSEMBLY__
 #define MAXMEM		 0x3fffffffffffUL
@@ -224,7 +225,7 @@ static inline unsigned long pud_bad(pud_
 
 #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 pte_clear(mm,addr,xp)	do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))	/* FIXME: is this
 						   right? */
@@ -263,22 +264,26 @@ extern inline pte_t pte_mkdirty(pte_t pt
 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)
+struct vm_area_struct;
+
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	if (!pte_dirty(*ptep))
 		return 0;
 	return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
 }
 
-static inline int ptep_test_and_clear_young(pte_t *ptep)
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	if (!pte_young(*ptep))
 		return 0;
 	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); }
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+	clear_bit(_PAGE_BIT_RW, ptep);
+}
 
 /*
  * Macro to mark a page protection value as "uncacheable".
@@ -402,6 +407,13 @@ extern int kern_addr_valid(unsigned long
 #define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
 		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn)	(pfn)
+#define GET_IOSPACE(pfn)		0
+#define GET_PFN(pfn)			(pfn)
+
 #define HAVE_ARCH_UNMAPPED_AREA
 
 #define pgtable_cache_init()   do { } while (0)
@@ -419,7 +431,6 @@ extern int kern_addr_valid(unsigned long
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_MKDIRTY
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -62,9 +62,8 @@ struct cpuinfo_x86 {
 	int	x86_tlbsize;	/* number of 4K pages in DTLB/ITLB combined(in pages)*/
         __u8    x86_virt_bits, x86_phys_bits;
 	__u8	x86_num_cores;
-	__u8	x86_apicid;
         __u32   x86_power; 	
-	__u32   x86_cpuid_level;	/* Max CPUID function supported */
+	__u32   extended_cpuid_level;	/* Max extended CPUID function supported */
 	unsigned long loops_per_jiffy;
 } ____cacheline_aligned;
 
@@ -92,7 +91,6 @@ extern char ignore_irq13;
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
-extern void dodgy_tsc(void);
 
 /*
  * EFLAGS bits
@@ -160,9 +158,9 @@ static inline void clear_in_cr4 (unsigne
 
 
 /*
- * User space process size. 47bits.
+ * User space process size. 47bits minus one guard page.
  */
-#define TASK_SIZE	(0x800000000000UL)
+#define TASK_SIZE	(0x800000000000UL - 4096)
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -29,7 +29,12 @@ extern void config_acpi_tables(void);
 extern void ia32_syscall(void);
 extern void iommu_hole_init(void);
 
-extern void time_init_smp(void);
+extern void time_init_gtod(void);
+extern int pmtimer_mark_offset(void);
+extern unsigned int do_gettimeoffset_pm(void);
+extern u32 pmtmr_ioport;
+extern unsigned long long monotonic_base;
+extern int sysctl_vsyscall;
 
 extern void do_softirq_thunk(void);
 
@@ -69,8 +74,6 @@ extern void __die(const char * str, stru
 extern void __show_regs(struct pt_regs * regs);
 extern void show_regs(struct pt_regs * regs);
 
-extern int map_syscall32(struct mm_struct *mm, unsigned long address);
-extern int __map_syscall32(struct mm_struct *mm, unsigned long address);
 extern char *syscall32_page;
 extern void syscall32_cpu_init(void);
 
diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
--- a/include/asm-x86_64/ptrace.h
+++ b/include/asm-x86_64/ptrace.h
@@ -86,6 +86,11 @@ struct pt_regs {
 extern unsigned long profile_pc(struct pt_regs *regs);
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
+struct task_struct;
+
+extern unsigned long
+convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs);
+
 enum {
         EF_CF   = 0x00000001,
         EF_PF   = 0x00000004,
diff --git a/include/asm-x86_64/seccomp.h b/include/asm-x86_64/seccomp.h
new file mode 100644
--- /dev/null
+++ b/include/asm-x86_64/seccomp.h
@@ -0,0 +1,24 @@
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h>
+
+#ifdef TIF_32BIT
+#error "unexpected TIF_32BIT on x86_64"
+#else
+#define TIF_32BIT TIF_IA32
+#endif
+
+#include <linux/unistd.h>
+#include <asm/ia32_unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+
+#define __NR_seccomp_read_32 __NR_ia32_read
+#define __NR_seccomp_write_32 __NR_ia32_write
+#define __NR_seccomp_exit_32 __NR_ia32_exit
+#define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
--- a/include/asm-x86_64/segment.h
+++ b/include/asm-x86_64/segment.h
@@ -24,10 +24,9 @@
 
 #define GDT_ENTRY_TLS 1
 #define GDT_ENTRY_TSS 8	/* needs two entries */
-#define GDT_ENTRY_LDT 10
-#define GDT_ENTRY_TLS_MIN 11
-#define GDT_ENTRY_TLS_MAX 13
-/* 14 free */
+#define GDT_ENTRY_LDT 10 /* needs two entries */
+#define GDT_ENTRY_TLS_MIN 12
+#define GDT_ENTRY_TLS_MAX 14
 #define GDT_ENTRY_KERNELCS16 15
 
 #define GDT_ENTRY_TLS_ENTRIES 3
diff --git a/include/asm-x86_64/siginfo.h b/include/asm-x86_64/siginfo.h
--- a/include/asm-x86_64/siginfo.h
+++ b/include/asm-x86_64/siginfo.h
@@ -3,8 +3,6 @@
 
 #define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
 
-#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-
 #include <asm-generic/siginfo.h>
 
 #endif
diff --git a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h
--- a/include/asm-x86_64/signal.h
+++ b/include/asm-x86_64/signal.h
@@ -116,35 +116,9 @@ typedef unsigned long sigset_t;
 #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 */
+#include <asm-generic/signal.h>
 
 #ifndef __ASSEMBLY__
-/* Type of a signal handler.  */
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
-
-#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;
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -31,12 +31,16 @@ extern int disable_apic;
 
 struct pt_regs;
 
+extern cpumask_t cpu_present_mask;
+extern cpumask_t cpu_possible_map;
+extern cpumask_t cpu_online_map;
+extern cpumask_t cpu_callout_map;
+
 /*
  * Private routines/data
  */
  
 extern void smp_alloc_memory(void);
-extern cpumask_t cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
 extern int smp_num_siblings;
@@ -44,11 +48,12 @@ 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);
 void smp_stop_cpu(void);
 extern cpumask_t cpu_sibling_map[NR_CPUS];
+extern cpumask_t cpu_core_map[NR_CPUS];
 extern u8 phys_proc_id[NR_CPUS];
+extern u8 cpu_core_id[NR_CPUS];
 
 #define SMP_TRAMPOLINE_BASE 0x6000
 
@@ -58,10 +63,6 @@ extern u8 phys_proc_id[NR_CPUS];
  * compresses data structures.
  */
 
-extern cpumask_t cpu_callout_map;
-extern cpumask_t cpu_callin_map;
-#define cpu_possible_map cpu_callout_map
-
 static inline int num_booting_cpus(void)
 {
 	return cpus_weight(cpu_callout_map);
@@ -75,7 +76,7 @@ extern __inline int hard_smp_processor_i
 	return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
 }
 
-#define safe_smp_processor_id() (disable_apic ? 0 : x86_apicid_to_cpu(hard_smp_processor_id()))
+extern int safe_smp_processor_id(void);
 
 #endif /* !ASSEMBLY */
 
@@ -97,22 +98,6 @@ static inline unsigned int cpu_mask_to_a
 	return cpus_addr(cpumask)[0];
 }
 
-static inline int x86_apicid_to_cpu(u8 apicid)
-{
-	int i;
-
-	for (i = 0; i < NR_CPUS; ++i)
-		if (x86_cpu_to_apicid[i] == apicid)
-			return i;
-
-	/* No entries in x86_cpu_to_apicid?  Either no MPS|ACPI,
-	 * or called too early.  Either way, we must be CPU 0. */
-      	if (x86_cpu_to_apicid[0] == BAD_APICID)
-		return 0;
-
-	return -1;
-}
-
 static inline int cpu_present_to_apicid(int mps_cpu)
 {
 	if (mps_cpu < NR_CPUS)
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -55,5 +55,4 @@ extern unsigned long saved_edi;
 
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
-extern int acpi_save_state_disk(void);
 #endif
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -338,4 +338,6 @@ void enable_hlt(void);
 #define HAVE_EAT_KEY
 void eat_key(void);
 
+extern unsigned long arch_align_stack(unsigned long sp);
+
 #endif
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -102,6 +102,7 @@ static inline struct thread_info *stack_
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
 #define TIF_IRET		5	/* force IRET */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+#define TIF_SECCOMP		8	/* secure computing */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_IA32		17	/* 32bit process */ 
 #define TIF_FORK		18	/* ret_from_fork */
@@ -115,6 +116,7 @@ static inline struct thread_info *stack_
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_IA32		(1<<TIF_IA32)
 #define _TIF_FORK		(1<<TIF_FORK)
@@ -122,9 +124,9 @@ static inline struct thread_info *stack_
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
 /* work to do on any return to user space */
-#define _TIF_ALLWORK_MASK 0x0000FFFF	
+#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
 
 #define PREEMPT_ACTIVE     0x10000000
 
diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
--- a/include/asm-x86_64/timex.h
+++ b/include/asm-x86_64/timex.h
@@ -16,8 +16,6 @@
 
 typedef unsigned long long cycles_t;
 
-extern cycles_t cacheflush_time;
-
 static inline cycles_t get_cycles (void)
 {
 	unsigned long long ret;
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -35,8 +35,7 @@ static inline cpumask_t __pcibus_to_cpum
 	cpus_and(res, busmask, online);
 	return res;
 }
-/* broken generic file uses #ifndef later on this */
-#define pcibus_to_cpumask(bus) __pcibus_to_cpumask(bus)
+#define pcibus_to_cpumask(bus) __pcibus_to_cpumask(bus->number)
 
 #ifdef CONFIG_NUMA
 /* sched_domains SD_NODE_INIT for x86_64 machines */
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -49,7 +49,8 @@
 
 #define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
 
-extern inline int verify_area(int type, const void __user * addr, unsigned long size)
+/* this function will go away soon - use access_ok() instead */
+extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -73,6 +74,7 @@ struct exception_table_entry
 	unsigned long insn, fixup;
 };
 
+#define ARCH_HAS_SEARCH_EXTABLE
 
 /*
  * These are the main single-value transfer routines.  They automatically
@@ -89,16 +91,11 @@ struct exception_table_entry
  * 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")
+		:"c" (ptr) \
+		:"r8")
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 #define get_user(x,ptr)							\
@@ -120,14 +117,13 @@ 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")
+		:"c" (ptr),"d" (x)					\
+		:"r8")
 
 #define put_user(x,ptr)							\
   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
@@ -150,10 +146,15 @@ extern void __put_user_bad(void);
 
 #define __put_user_check(x,ptr,size)			\
 ({							\
-	int __pu_err = -EFAULT;				\
+	int __pu_err;					\
 	__typeof__(*(ptr)) __user *__pu_addr = (ptr);	\
-	if (likely(access_ok(VERIFY_WRITE,__pu_addr,size)))	\
-		__put_user_size((x),__pu_addr,(size),__pu_err);	\
+	switch (size) { 				\
+	case 1: __put_user_x(1,__pu_err,x,__pu_addr); break;	\
+	case 2: __put_user_x(2,__pu_err,x,__pu_addr); break;	\
+	case 4: __put_user_x(4,__pu_err,x,__pu_addr); break;	\
+	case 8: __put_user_x(8,__pu_err,x,__pu_addr); break;	\
+	default: __put_user_bad();			\
+	}						\
 	__pu_err;					\
 })
 
@@ -204,6 +205,10 @@ struct __large_struct { unsigned long bu
 	__gu_err;						\
 })
 
+extern int __get_user_1(void);
+extern int __get_user_2(void);
+extern int __get_user_4(void);
+extern int __get_user_8(void);
 extern int __get_user_bad(void);
 
 #define __get_user_size(x,ptr,size,retval)				\
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -76,7 +76,7 @@ __SYSCALL(__NR_madvise, sys_madvise)
 #define __NR_shmget                             29
 __SYSCALL(__NR_shmget, sys_shmget)
 #define __NR_shmat                              30
-__SYSCALL(__NR_shmat, wrap_sys_shmat)
+__SYSCALL(__NR_shmat, sys_shmat)
 #define __NR_shmctl                             31
 __SYSCALL(__NR_shmctl, sys_shmctl)
 
@@ -533,8 +533,6 @@ __SYSCALL(__NR_tgkill, sys_tgkill)
 __SYSCALL(__NR_utimes, sys_utimes)
 #define __NR_vserver		236
 __SYSCALL(__NR_vserver, sys_ni_syscall)
-#define __NR_vserver		236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
 #define __NR_mbind 		237
 __SYSCALL(__NR_mbind, sys_mbind)
 #define __NR_set_mempolicy 	238
@@ -774,7 +772,7 @@ asmlinkage long sys_pipe(int *fildes);
 
 asmlinkage long sys_ptrace(long request, long pid,
 				unsigned long addr, long data);
-asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs);
+asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs);
 asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
@@ -792,6 +790,6 @@ asmlinkage long sys_rt_sigaction(int sig
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
 #endif
diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
--- a/include/asm-x86_64/vsyscall.h
+++ b/include/asm-x86_64/vsyscall.h
@@ -25,6 +25,7 @@ enum vsyscall_num {
 
 #define VXTIME_TSC	1
 #define VXTIME_HPET	2
+#define VXTIME_PMTMR	3
 
 struct vxtime_data {
 	long hpet_address;	/* HPET base address */
@@ -54,6 +55,8 @@ extern struct timezone sys_tz;
 extern int sysctl_vsyscall;
 extern seqlock_t xtime_lock;
 
+extern int sysctl_vsyscall;
+
 #define ARCH_HAVE_XTIME_LOCK 1
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
--- a/include/linux/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -323,6 +323,7 @@ struct ac97_ops
 	
 #define AC97_DELUDED_MODEM	1	/* Audio codec reports its a modem */
 #define AC97_NO_PCM_VOLUME	2	/* Volume control is missing 	   */
+#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
 };
 
 extern int ac97_read_proc (char *page_out, char **start, off_t off,
diff --git a/include/linux/acct.h b/include/linux/acct.h
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -120,12 +120,12 @@ struct acct_v3
 struct super_block;
 extern void acct_auto_close(struct super_block *sb);
 extern void acct_process(long exitcode);
-extern void acct_update_integrals(void);
+extern void acct_update_integrals(struct task_struct *tsk);
 extern void acct_clear_integrals(struct task_struct *tsk);
 #else
 #define acct_auto_close(x)	do { } while (0)
 #define acct_process(x)		do { } while (0)
-#define acct_update_integrals()		do { } while (0)
+#define acct_update_integrals(x)		do { } while (0)
 #define acct_clear_integrals(task)	do { } while (0)
 #endif
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -25,6 +25,10 @@
 #ifndef _LINUX_ACPI_H
 #define _LINUX_ACPI_H
 
+#include <linux/config.h>
+
+#ifdef	CONFIG_ACPI
+
 #ifndef _LINUX
 #define _LINUX
 #endif
@@ -455,8 +459,6 @@ struct acpi_prt_list {
 	struct list_head	entries;
 };
 
-extern struct acpi_prt_list	acpi_prt;
-
 struct pci_dev;
 
 int acpi_pci_irq_enable (struct pci_dev *dev);
@@ -535,4 +537,5 @@ static inline int acpi_get_pxm(acpi_hand
 
 extern int pnpacpi_disabled;
 
-#endif /*_LINUX_ACPI_H*/
+#endif	/* CONFIG_ACPI */
+#endif	/*_LINUX_ACPI_H*/
diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h
--- a/include/linux/agp_backend.h
+++ b/include/linux/agp_backend.h
@@ -1,6 +1,7 @@
 /*
  * AGPGART backend specific includes. Not for userspace consumption.
  *
+ * Copyright (C) 2004 Silicon Graphics, Inc.
  * Copyright (C) 2002-2003 Dave Jones
  * Copyright (C) 1999 Jeff Hartmann
  * Copyright (C) 1999 Precision Insight, Inc.
@@ -63,21 +64,24 @@ struct agp_kern_info {
 	struct vm_operations_struct *vm_ops;
 };
 
-/* 
+/*
  * The agp_memory structure has information about the block of agp memory
  * allocated.  A caller may manipulate the next and prev pointers to link
  * each allocated item into a list.  These pointers are ignored by the backend.
  * Everything else should never be written to, but the caller may read any of
- * the items to detrimine the status of this block of agp memory. 
+ * the items to determine the status of this block of agp memory.
  */
 
+struct agp_bridge_data;
+
 struct agp_memory {
-	int key;
 	struct agp_memory *next;
 	struct agp_memory *prev;
+	struct agp_bridge_data *bridge;
+	unsigned long *memory;
 	size_t page_count;
+	int key;
 	int num_scratch_pages;
-	unsigned long *memory;
 	off_t pg_start;
 	u32 type;
 	u32 physical;
@@ -87,14 +91,19 @@ struct agp_memory {
 
 #define AGP_NORMAL_MEMORY 0
 
+extern struct agp_bridge_data *agp_bridge;
+extern struct list_head agp_bridges;
+
+extern struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *);
+
 extern void agp_free_memory(struct agp_memory *);
-extern struct agp_memory *agp_allocate_memory(size_t, u32);
-extern int agp_copy_info(struct agp_kern_info *);
+extern struct agp_memory *agp_allocate_memory(struct agp_bridge_data *, size_t, u32);
+extern int agp_copy_info(struct agp_bridge_data *, struct agp_kern_info *);
 extern int agp_bind_memory(struct agp_memory *, off_t);
 extern int agp_unbind_memory(struct agp_memory *);
-extern void agp_enable(u32);
-extern int agp_backend_acquire(void);
-extern void agp_backend_release(void);
+extern void agp_enable(struct agp_bridge_data *, u32);
+extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *);
+extern void agp_backend_release(struct agp_bridge_data *);
 
 #endif				/* __KERNEL__ */
 #endif				/* _AGP_BACKEND_H */
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -2,7 +2,7 @@
  *
  * Copyright 2000,2001,2002 Red Hat.
  *
- * Written by Benjamin LaHaise <bcrl@redhat.com>
+ * Written by Benjamin LaHaise <bcrl@kvack.org>
  *
  * Distribute under the terms of the GPLv2 (see ../../COPYING) or under 
  * the following terms.
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -1,5 +1,6 @@
 #ifndef __LINUX_ATALK_H__
 #define __LINUX_ATALK_H__
+
 /*
  * AppleTalk networking structures
  *
@@ -36,6 +37,10 @@ struct atalk_netrange {
 	__u16	nr_lastnet;
 };
 
+#ifdef __KERNEL__
+
+#include <net/sock.h>
+
 struct atalk_route {
 	struct net_device  *dev;
 	struct atalk_addr  target;
@@ -63,6 +68,8 @@ struct atalk_iface {
 };
 	
 struct atalk_sock {
+	/* struct sock has to be the first member of atalk_sock */
+	struct sock	sk;
 	unsigned short	dest_net;
 	unsigned short	src_net;
 	unsigned char	dest_node;
@@ -71,7 +78,10 @@ struct atalk_sock {
 	unsigned char	src_port;
 };
 
-#ifdef __KERNEL__
+static inline struct atalk_sock *at_sk(struct sock *sk)
+{
+	return (struct atalk_sock *)sk;
+}
 
 #include <asm/byteorder.h>
 
@@ -197,8 +207,6 @@ extern void		 aarp_proxy_remove(struct n
 
 extern void		aarp_cleanup_module(void);
 
-#define at_sk(__sk) ((struct atalk_sock *)(__sk)->sk_protinfo)
-
 extern struct hlist_head atalk_sockets;
 extern rwlock_t atalk_sockets_lock;
 
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -30,9 +30,6 @@
 #define ATM_DS3_PCR	(8000*12)
 			/* DS3: 12 cells in a 125 usec time slot */
 
-#define atm_sk(__sk) ((struct atm_vcc *)(__sk)->sk_protinfo)
-#define ATM_SD(s)	(atm_sk((s)->sk))
-
 
 #define __AAL_STAT_ITEMS \
     __HANDLE_ITEM(tx);			/* TX okay */ \
@@ -281,6 +278,8 @@ enum {
 #define ATM_ATMOPT_CLP	1	/* set CLP bit */
 
 struct atm_vcc {
+	/* struct sock has to be the first member of atm_vcc */
+	struct sock	sk;
 	unsigned long	flags;		/* VCC flags (ATM_VF_*) */
 	short		vpi;		/* VPI and VCI (types must be equal */
 					/* with sockaddr) */
@@ -297,7 +296,6 @@ struct atm_vcc {
 	void		*dev_data;	/* per-device data */
 	void		*proto_data;	/* per-protocol data */
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
-	struct sock	*sk;		/* socket backpointer */
 	/* SVC part --- may move later ------------------------------------- */
 	short		itf;		/* interface number */
 	struct sockaddr_atmsvc local;
@@ -310,6 +308,20 @@ struct atm_vcc {
 					/* by CLIP and sch_atm. */
 };
 
+static inline struct atm_vcc *atm_sk(struct sock *sk)
+{
+	return (struct atm_vcc *)sk;
+}
+
+static inline struct atm_vcc *ATM_SD(struct socket *sock)
+{
+	return atm_sk(sock->sk);
+}
+
+static inline struct sock *sk_atm(struct atm_vcc *vcc)
+{
+	return (struct sock *)vcc;
+}
 
 struct atm_dev_addr {
 	struct sockaddr_atmsvc addr;	/* ATM address */
@@ -410,20 +422,20 @@ static inline int atm_guess_pdu2truesize
 
 static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
 {
-	atomic_add(truesize, &vcc->sk->sk_rmem_alloc);
+	atomic_add(truesize, &sk_atm(vcc)->sk_rmem_alloc);
 }
 
 
 static inline void atm_return(struct atm_vcc *vcc,int truesize)
 {
-	atomic_sub(truesize, &vcc->sk->sk_rmem_alloc);
+	atomic_sub(truesize, &sk_atm(vcc)->sk_rmem_alloc);
 }
 
 
 static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
 {
-	return (size + atomic_read(&vcc->sk->sk_wmem_alloc)) <
-	       vcc->sk->sk_sndbuf;
+	return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
+	       sk_atm(vcc)->sk_sndbuf;
 }
 
 
diff --git a/include/linux/audit.h b/include/linux/audit.h
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -1,4 +1,4 @@
-/* audit.h -- Auditing support -*- linux-c -*-
+/* audit.h -- Auditing support
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
  * All Rights Reserved.
@@ -24,6 +24,9 @@
 #ifndef _LINUX_AUDIT_H_
 #define _LINUX_AUDIT_H_
 
+#include <linux/sched.h>
+#include <linux/elf.h>
+
 /* Request and reply types */
 #define AUDIT_GET      1000	/* Get status */
 #define AUDIT_SET      1001	/* Set status (enable/disable/auditd) */
@@ -67,6 +70,7 @@
 #define AUDIT_FSGID	8
 #define AUDIT_LOGINUID	9
 #define AUDIT_PERS	10
+#define AUDIT_ARCH	11
 
 				/* These are ONLY useful when checking
 				 * at syscall exit time (AUDIT_AT_EXIT). */
@@ -96,6 +100,38 @@
 #define AUDIT_FAIL_PRINTK	1
 #define AUDIT_FAIL_PANIC	2
 
+/* distinguish syscall tables */
+#define __AUDIT_ARCH_64BIT 0x80000000
+#define __AUDIT_ARCH_LE	   0x40000000
+#define AUDIT_ARCH_ALPHA	(EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_ARM		(EM_ARM|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_ARMEB	(EM_ARM)
+#define AUDIT_ARCH_CRIS		(EM_CRIS|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_FRV		(EM_FRV)
+#define AUDIT_ARCH_H8300	(EM_H8_300)
+#define AUDIT_ARCH_I386		(EM_386|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_IA64		(EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_M32R		(EM_M32R)
+#define AUDIT_ARCH_M68K		(EM_68K)
+#define AUDIT_ARCH_MIPS		(EM_MIPS)
+#define AUDIT_ARCH_MIPSEL	(EM_MIPS|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_MIPS64	(EM_MIPS|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_MIPSEL64	(EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_PARISC	(EM_PARISC)
+#define AUDIT_ARCH_PARISC64	(EM_PARISC|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_PPC		(EM_PPC)
+#define AUDIT_ARCH_PPC64	(EM_PPC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_S390		(EM_S390)
+#define AUDIT_ARCH_S390X	(EM_S390|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SH		(EM_SH)
+#define AUDIT_ARCH_SHEL		(EM_SH|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_SH64		(EM_SH|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SHEL64	(EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_SPARC	(EM_SPARC)
+#define AUDIT_ARCH_SPARC64	(EM_SPARC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_V850		(EM_V850|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_X86_64	(EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+
 #ifndef __KERNEL__
 struct audit_message {
 	struct nlmsghdr nlh;
@@ -125,40 +161,45 @@ struct audit_rule {		/* for AUDIT_LIST, 
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_AUDIT
 struct audit_buffer;
 struct audit_context;
-#endif
+struct inode;
 
+#define AUDITSC_INVALID 0
+#define AUDITSC_SUCCESS 1
+#define AUDITSC_FAILURE 2
+#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
 #ifdef CONFIG_AUDITSYSCALL
 /* These are defined in auditsc.c */
 				/* Public API */
 extern int  audit_alloc(struct task_struct *task);
 extern void audit_free(struct task_struct *task);
-extern void audit_syscall_entry(struct task_struct *task,
+extern void audit_syscall_entry(struct task_struct *task, int arch,
 				int major, unsigned long a0, unsigned long a1,
 				unsigned long a2, unsigned long a3);
-extern void audit_syscall_exit(struct task_struct *task, int return_code);
+extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
 extern void audit_getname(const char *name);
 extern void audit_putname(const char *name);
-extern void audit_inode(const char *name, unsigned long ino, dev_t rdev);
+extern void audit_inode(const char *name, const struct inode *inode);
 
 				/* Private API (for audit.c only) */
 extern int  audit_receive_filter(int type, int pid, int uid, int seq,
-				 void *data);
+				 void *data, uid_t loginuid);
 extern void audit_get_stamp(struct audit_context *ctx,
-			    struct timespec *t, int *serial);
-extern int  audit_set_loginuid(struct audit_context *ctx, uid_t loginuid);
+			    struct timespec *t, unsigned int *serial);
+extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
 extern uid_t audit_get_loginuid(struct audit_context *ctx);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
-#define audit_syscall_entry(t,a,b,c,d,e) do { ; } while (0)
-#define audit_syscall_exit(t,r) do { ; } while (0)
+#define audit_syscall_entry(t,ta,a,b,c,d,e) do { ; } while (0)
+#define audit_syscall_exit(t,f,r) do { ; } while (0)
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
-#define audit_inode(n,i,d) do { ; } while (0)
+#define audit_inode(n,i) do { ; } while (0)
 #define audit_get_loginuid(c) ({ -1; })
+#define audit_ipc_perms(q,u,g,m) ({ 0; })
 #endif
 
 #ifdef CONFIG_AUDIT
@@ -173,17 +214,15 @@ extern void		    audit_log_format(struct
 					     const char *fmt, ...)
 			    __attribute__((format(printf,2,3)));
 extern void		    audit_log_end(struct audit_buffer *ab);
-extern void		    audit_log_end_fast(struct audit_buffer *ab);
-extern void		    audit_log_end_irq(struct audit_buffer *ab);
+extern void		    audit_log_hex(struct audit_buffer *ab,
+					  const unsigned char *buf,
+					  size_t len);
+extern void		    audit_log_untrustedstring(struct audit_buffer *ab,
+						      const char *string);
 extern void		    audit_log_d_path(struct audit_buffer *ab,
 					     const char *prefix,
 					     struct dentry *dentry,
 					     struct vfsmount *vfsmnt);
-extern int		    audit_set_rate_limit(int limit);
-extern int		    audit_set_backlog_limit(int limit);
-extern int		    audit_set_enabled(int state);
-extern int		    audit_set_failure(int state);
-
 				/* Private API (for auditsc.c only) */
 extern void		    audit_send_reply(int pid, int seq, int type,
 					     int done, int multi,
@@ -195,13 +234,9 @@ extern void		    audit_log_lost(const ch
 #define audit_log_vformat(b,f,a) do { ; } while (0)
 #define audit_log_format(b,f,...) do { ; } while (0)
 #define audit_log_end(b) do { ; } while (0)
-#define audit_log_end_fast(b) do { ; } while (0)
-#define audit_log_end_irq(b) do { ; } while (0)
+#define audit_log_hex(a,b,l) do { ; } while (0)
+#define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b,p,d,v) do { ; } while (0)
-#define audit_set_rate_limit(l) do { ; } while (0)
-#define audit_set_backlog_limit(l) do { ; } while (0)
-#define audit_set_enabled(s) do { ; } while (0)
-#define audit_set_failure(s) do { ; } while (0)
 #endif
 #endif
 #endif
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -23,7 +23,7 @@
 #define AUTOFS_MIN_PROTO_VERSION	3
 #define AUTOFS_MAX_PROTO_VERSION	4
 
-#define AUTOFS_PROTO_SUBVERSION         5
+#define AUTOFS_PROTO_SUBVERSION		6
 
 /* Mask for expire behaviour */
 #define AUTOFS_EXP_IMMEDIATE		1
diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
--- a/include/linux/awe_voice.h
+++ b/include/linux/awe_voice.h
@@ -29,9 +29,9 @@
 #define SAMPLE_TYPE_AWE32	0x20
 #endif
 
-#ifndef _PATCHKEY
-#define _PATCHKEY(id) ((id<<8)|0xfd)
-#endif
+#define _LINUX_PATCHKEY_H_INDIRECT
+#include <linux/patchkey.h>
+#undef _LINUX_PATCHKEY_H_INDIRECT
 
 /*----------------------------------------------------------------
  * patch information record
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -25,13 +25,39 @@ typedef int (congested_fn)(void *, int);
 struct backing_dev_info {
 	unsigned long ra_pages;	/* max readahead in PAGE_CACHE_SIZE units */
 	unsigned long state;	/* Always use atomic bitops on this */
-	int memory_backed;	/* Cannot clean pages with writepage */
+	unsigned int capabilities; /* Device capabilities */
 	congested_fn *congested_fn; /* Function pointer if device is md/dm */
 	void *congested_data;	/* Pointer to aux data for congested func */
 	void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
 	void *unplug_io_data;
 };
 
+
+/*
+ * Flags in backing_dev_info::capability
+ * - The first two flags control whether dirty pages will contribute to the
+ *   VM's accounting and whether writepages() should be called for dirty pages
+ *   (something that would not, for example, be appropriate for ramfs)
+ * - These flags let !MMU mmap() govern direct device mapping vs immediate
+ *   copying more easily for MAP_PRIVATE, especially for ROM filesystems
+ */
+#define BDI_CAP_NO_ACCT_DIRTY	0x00000001	/* Dirty pages shouldn't contribute to accounting */
+#define BDI_CAP_NO_WRITEBACK	0x00000002	/* Don't write pages back */
+#define BDI_CAP_MAP_COPY	0x00000004	/* Copy can be mapped (MAP_PRIVATE) */
+#define BDI_CAP_MAP_DIRECT	0x00000008	/* Can be mapped directly (MAP_SHARED) */
+#define BDI_CAP_READ_MAP	0x00000010	/* Can be mapped for reading */
+#define BDI_CAP_WRITE_MAP	0x00000020	/* Can be mapped for writing */
+#define BDI_CAP_EXEC_MAP	0x00000040	/* Can be mapped for execution */
+#define BDI_CAP_VMFLAGS \
+	(BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
+
+#if defined(VM_MAYREAD) && \
+	(BDI_CAP_READ_MAP != VM_MAYREAD || \
+	 BDI_CAP_WRITE_MAP != VM_MAYWRITE || \
+	 BDI_CAP_EXEC_MAP != VM_MAYEXEC)
+#error please change backing_dev_info::capabilities flags
+#endif
+
 extern struct backing_dev_info default_backing_dev_info;
 void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page);
 
@@ -62,4 +88,17 @@ static inline int bdi_rw_congested(struc
 				  (1 << BDI_write_congested));
 }
 
+#define bdi_cap_writeback_dirty(bdi) \
+	(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
+
+#define bdi_cap_account_dirty(bdi) \
+	(!((bdi)->capabilities & BDI_CAP_NO_ACCT_DIRTY))
+
+#define mapping_cap_writeback_dirty(mapping) \
+	bdi_cap_writeback_dirty((mapping)->backing_dev_info)
+
+#define mapping_cap_account_dirty(mapping) \
+	bdi_cap_account_dirty((mapping)->backing_dev_info)
+
+
 #endif		/* _LINUX_BACKING_DEV_H */
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -77,7 +77,6 @@ extern int flush_old_exec(struct linux_b
 extern int setup_arg_pages(struct linux_binprm * bprm,
 			   unsigned long stack_top,
 			   int executable_stack);
-extern int copy_strings(int argc,char __user * __user * argv,struct linux_binprm *bprm); 
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
diff --git a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -59,6 +59,7 @@ struct bio_vec {
 	unsigned int	bv_offset;
 };
 
+struct bio_set;
 struct bio;
 typedef int (bio_end_io_t) (struct bio *, unsigned int, int);
 typedef void (bio_destructor_t) (struct bio *);
@@ -109,6 +110,7 @@ struct bio {
 	void			*bi_private;
 
 	bio_destructor_t	*bi_destructor;	/* destructor */
+	struct bio_set		*bi_set;	/* memory pools set */
 };
 
 /*
@@ -258,7 +260,11 @@ extern struct bio_pair *bio_split(struct
 extern mempool_t *bio_split_pool;
 extern void bio_pair_release(struct bio_pair *dbio);
 
-extern struct bio *bio_alloc(int, int);
+extern struct bio_set *bioset_create(int, int, int);
+extern void bioset_free(struct bio_set *);
+
+extern struct bio *bio_alloc(unsigned int __nocast, int);
+extern struct bio *bio_alloc_bioset(unsigned int __nocast, int, struct bio_set *);
 extern void bio_put(struct bio *);
 
 extern void bio_endio(struct bio *, unsigned int, int);
@@ -267,7 +273,7 @@ extern int bio_phys_segments(struct requ
 extern int bio_hw_segments(struct request_queue *, struct bio *);
 
 extern void __bio_clone(struct bio *, struct bio *);
-extern struct bio *bio_clone(struct bio *, int);
+extern struct bio *bio_clone(struct bio *, unsigned int __nocast);
 
 extern void bio_init(struct bio *);
 
@@ -280,6 +286,7 @@ extern void bio_set_pages_dirty(struct b
 extern void bio_check_pages_dirty(struct bio *bio);
 extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
 extern int bio_uncopy_user(struct bio *);
+void zero_fill_bio(struct bio *bio);
 
 #ifdef CONFIG_HIGHMEM
 /*
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -41,7 +41,9 @@
  * bitmap_shift_right(dst, src, n, nbits)	*dst = *src >> n
  * bitmap_shift_left(dst, src, n, nbits)	*dst = *src << n
  * bitmap_scnprintf(buf, len, src, nbits)	Print bitmap src to buf
- * bitmap_parse(ubuf, ulen, dst, nbits)		Parse bitmap dst from buf
+ * bitmap_parse(ubuf, ulen, dst, nbits)		Parse bitmap dst from user buf
+ * bitmap_scnlistprintf(buf, len, src, nbits)	Print bitmap src as list to buf
+ * bitmap_parselist(buf, dst, nbits)		Parse bitmap dst from list
  */
 
 /*
@@ -98,6 +100,10 @@ extern int bitmap_scnprintf(char *buf, u
 			const unsigned long *src, int nbits);
 extern int bitmap_parse(const char __user *ubuf, unsigned int ulen,
 			unsigned long *dst, int nbits);
+extern int bitmap_scnlistprintf(char *buf, unsigned int len,
+			const unsigned long *src, int nbits);
+extern int bitmap_parselist(const char *buf, unsigned long *maskp,
+			int nmaskbits);
 extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -134,4 +134,26 @@ static inline unsigned long hweight_long
 	return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w);
 }
 
+/*
+ * rol32 - rotate a 32-bit value left
+ *
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 rol32(__u32 word, unsigned int shift)
+{
+	return (word << shift) | (word >> (32 - shift));
+}
+
+/*
+ * ror32 - rotate a 32-bit value right
+ *
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 ror32(__u32 word, unsigned int shift)
+{
+	return (word >> shift) | (word << (32 - shift));
+}
+
 #endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -93,6 +93,9 @@ struct io_context *get_io_context(int gf
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
 
+struct request;
+typedef void (rq_end_io_fn)(struct request *);
+
 struct request_list {
 	int count[2];
 	int starved[2];
@@ -176,6 +179,12 @@ struct request {
 	 * For Power Management requests
 	 */
 	struct request_pm_state *pm;
+
+	/*
+	 * completion callback. end_io_data should be folded in with waiting
+	 */
+	rq_end_io_fn *end_io;
+	void *end_io_data;
 };
 
 /*
@@ -210,6 +219,7 @@ enum rq_flag_bits {
 	__REQ_PM_SHUTDOWN,	/* shutdown request */
 	__REQ_BAR_PREFLUSH,	/* barrier pre-flush done */
 	__REQ_BAR_POSTFLUSH,	/* barrier post-flush */
+	__REQ_BAR_FLUSH,	/* rq is the flush request */
 	__REQ_NR_BITS,		/* stops here */
 };
 
@@ -237,6 +247,7 @@ enum rq_flag_bits {
 #define REQ_PM_SHUTDOWN	(1 << __REQ_PM_SHUTDOWN)
 #define REQ_BAR_PREFLUSH	(1 << __REQ_BAR_PREFLUSH)
 #define REQ_BAR_POSTFLUSH	(1 << __REQ_BAR_POSTFLUSH)
+#define REQ_BAR_FLUSH	(1 << __REQ_BAR_FLUSH)
 
 /*
  * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
@@ -266,6 +277,8 @@ struct bio_vec;
 typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
 typedef void (activity_fn) (void *data, int rw);
 typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
+typedef int (prepare_flush_fn) (request_queue_t *, struct request *);
+typedef void (end_flush_fn) (request_queue_t *, struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -309,6 +322,8 @@ struct request_queue
 	merge_bvec_fn		*merge_bvec_fn;
 	activity_fn		*activity_fn;
 	issue_flush_fn		*issue_flush_fn;
+	prepare_flush_fn	*prepare_flush_fn;
+	end_flush_fn		*end_flush_fn;
 
 	/*
 	 * Auto-unplugging state
@@ -332,7 +347,7 @@ struct request_queue
 	 * queue needs bounce pages for pages above this limit
 	 */
 	unsigned long		bounce_pfn;
-	int			bounce_gfp;
+	unsigned int		bounce_gfp;
 
 	/*
 	 * various queue flags, see QUEUE_* below
@@ -340,8 +355,11 @@ struct request_queue
 	unsigned long		queue_flags;
 
 	/*
-	 * protects queue structures from reentrancy
+	 * protects queue structures from reentrancy. ->__queue_lock should
+	 * _never_ be used directly, it is queue private. always use
+	 * ->queue_lock.
 	 */
+	spinlock_t		__queue_lock;
 	spinlock_t		*queue_lock;
 
 	/*
@@ -380,6 +398,18 @@ struct request_queue
 	unsigned int		sg_reserved_size;
 
 	struct list_head	drain_list;
+
+	/*
+	 * reserved for flush operations
+	 */
+	struct request		*flush_rq;
+	unsigned char		ordered;
+};
+
+enum {
+	QUEUE_ORDERED_NONE,
+	QUEUE_ORDERED_TAG,
+	QUEUE_ORDERED_FLUSH,
 };
 
 #define RQ_INACTIVE		(-1)
@@ -396,12 +426,13 @@ struct request_queue
 #define QUEUE_FLAG_DEAD		5	/* queue being torn down */
 #define QUEUE_FLAG_REENTER	6	/* Re-entrancy avoidance */
 #define QUEUE_FLAG_PLUGGED	7	/* queue is plugged */
-#define QUEUE_FLAG_ORDERED	8	/* supports ordered writes */
-#define QUEUE_FLAG_DRAIN	9	/* draining queue for sched switch */
+#define QUEUE_FLAG_DRAIN	8	/* draining queue for sched switch */
+#define QUEUE_FLAG_FLUSH	9	/* doing barrier flush sequence */
 
 #define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_stopped(q)	test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
+#define blk_queue_flushing(q)	test_bit(QUEUE_FLAG_FLUSH, &(q)->queue_flags)
 
 #define blk_fs_request(rq)	((rq)->flags & REQ_CMD)
 #define blk_pc_request(rq)	((rq)->flags & REQ_BLOCK_PC)
@@ -509,10 +540,10 @@ extern void blk_unregister_queue(struct 
 extern void register_disk(struct gendisk *dev);
 extern void generic_make_request(struct bio *bio);
 extern void blk_put_request(struct request *);
+extern void blk_end_sync_rq(struct request *rq);
 extern void blk_attempt_remerge(request_queue_t *, struct request *);
 extern void __blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, int);
-extern void blk_put_request(struct request *);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *, int);
 extern void blk_requeue_request(request_queue_t *, struct request *);
 extern void blk_plug_device(request_queue_t *);
@@ -602,6 +633,9 @@ extern struct backing_dev_info *blk_get_
 extern void blk_queue_ordered(request_queue_t *, int);
 extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
 extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *);
+extern struct request *blk_start_pre_flush(request_queue_t *,struct request *);
+extern int blk_complete_barrier_rq(request_queue_t *, struct request *, int);
+extern int blk_complete_barrier_rq_locked(request_queue_t *, struct request *, int);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -169,7 +169,7 @@ void __brelse(struct buffer_head *);
 void __bforget(struct buffer_head *);
 void __breadahead(struct block_device *, sector_t block, int size);
 struct buffer_head *__bread(struct block_device *, sector_t block, int size);
-struct buffer_head *alloc_buffer_head(int gfp_flags);
+struct buffer_head *alloc_buffer_head(unsigned int __nocast gfp_flags);
 void free_buffer_head(struct buffer_head * bh);
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
 void FASTCALL(__lock_buffer(struct buffer_head *bh));
@@ -203,6 +203,9 @@ int file_fsync(struct file *, struct den
 int nobh_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 int nobh_commit_write(struct file *, struct page *, unsigned, unsigned);
 int nobh_truncate_page(struct address_space *, loff_t);
+int nobh_writepage(struct page *page, get_block_t *get_block,
+                        struct writeback_control *wbc);
+
 
 /*
  * inline definitions
diff --git a/include/linux/capability.h b/include/linux/capability.h
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -44,8 +44,6 @@ typedef struct __user_cap_data_struct {
 
 #include <linux/spinlock.h>
 
-extern spinlock_t task_capability_lock;
-
 /* #define STRICT_CAP_T_TYPECHECKS */
 
 #ifdef STRICT_CAP_T_TYPECHECKS
diff --git a/include/linux/compat.h b/include/linux/compat.h
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -83,6 +83,12 @@ struct compat_rusage {
 
 extern int put_compat_rusage(const struct rusage *, struct compat_rusage __user *);
 
+struct compat_siginfo;
+
+extern asmlinkage long compat_sys_waitid(int, compat_pid_t,
+		struct compat_siginfo __user *, int,
+		struct compat_rusage __user *);
+
 struct compat_dirent {
 	u32		d_ino;
 	compat_off_t	d_off;
@@ -95,12 +101,14 @@ typedef union compat_sigval {
 	compat_uptr_t	sival_ptr;
 } compat_sigval_t;
 
+#define COMPAT_SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
 typedef struct compat_sigevent {
 	compat_sigval_t sigev_value;
 	compat_int_t sigev_signo;
 	compat_int_t sigev_notify;
 	union {
-		compat_int_t _pad[SIGEV_PAD_SIZE];
+		compat_int_t _pad[COMPAT_SIGEV_PAD_SIZE];
 		compat_int_t _tid;
 
 		struct {
@@ -145,8 +153,10 @@ long compat_get_bitmap(unsigned long *ma
 		       unsigned long bitmap_size);
 long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
 		       unsigned long bitmap_size);
-struct compat_siginfo;
 int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from);
 int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from);
+int get_compat_sigevent(struct sigevent *event,
+		const struct compat_sigevent __user *u_event);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -16,6 +16,7 @@ COMPATIBLE_IOCTL(TCSETA)
 COMPATIBLE_IOCTL(TCSETAW)
 COMPATIBLE_IOCTL(TCSETAF)
 COMPATIBLE_IOCTL(TCSBRK)
+ULONG_IOCTL(TCSBRKP)
 COMPATIBLE_IOCTL(TCXONC)
 COMPATIBLE_IOCTL(TCFLSH)
 COMPATIBLE_IOCTL(TCGETS)
@@ -692,6 +693,9 @@ COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFA
 COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
 COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
 COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
 COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
 /* MTD */
 COMPATIBLE_IOCTL(MEMGETINFO)
diff --git a/include/linux/compiler-gcc+.h b/include/linux/compiler-gcc+.h
deleted file mode 100644
--- a/include/linux/compiler-gcc+.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Never include this file directly.  Include <linux/compiler.h> instead.  */
-
-/*
- * These definitions are for Ueber-GCC: always newer than the latest
- * version and hence sporting everything plus a kitchen-sink.
- */
-#include <linux/compiler-gcc.h>
-
-#define inline			inline		__attribute__((always_inline))
-#define __inline__		__inline__	__attribute__((always_inline))
-#define __inline		__inline	__attribute__((always_inline))
-#define __deprecated		__attribute__((deprecated))
-#define __attribute_used__	__attribute__((__used__))
-#define __attribute_pure__	__attribute__((pure))
-#define __attribute_const__	__attribute__((__const__))
-#define __must_check 		__attribute__((warn_unused_result))
diff --git a/include/linux/compiler-gcc2.h b/include/linux/compiler-gcc2.h
--- a/include/linux/compiler-gcc2.h
+++ b/include/linux/compiler-gcc2.h
@@ -22,3 +22,8 @@
 # define __attribute_pure__	__attribute__((pure))
 # define __attribute_const__	__attribute__((__const__))
 #endif
+
+/* GCC 2.95.x/2.96 recognize __va_copy, but not va_copy. Actually later GCC's
+ * define both va_copy and __va_copy, but the latter may go away, so limit this
+ * to this header */
+#define va_copy			__va_copy
diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
--- a/include/linux/compiler-gcc3.h
+++ b/include/linux/compiler-gcc3.h
@@ -10,7 +10,7 @@
 #endif
 
 #if __GNUC_MINOR__ > 0
-# define __deprecated	__attribute__((deprecated))
+# define __deprecated		__attribute__((deprecated))
 #endif
 
 #if __GNUC_MINOR__ >= 3
@@ -23,12 +23,10 @@
 #define __attribute_const__	__attribute__((__const__))
 
 #if __GNUC_MINOR__ >= 1
-#define  noinline __attribute__((noinline))
+#define  noinline		__attribute__((noinline))
 #endif
+
 #if __GNUC_MINOR__ >= 4
-#define __must_check __attribute__((warn_unused_result))
+#define __must_check		__attribute__((warn_unused_result))
 #endif
 
-#if __GNUC_MINOR__ >= 5
-#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
-#endif
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
new file mode 100644
--- /dev/null
+++ b/include/linux/compiler-gcc4.h
@@ -0,0 +1,16 @@
+/* Never include this file directly.  Include <linux/compiler.h> instead.  */
+
+/* These definitions are for GCC v4.x.  */
+#include <linux/compiler-gcc.h>
+
+#define inline			inline		__attribute__((always_inline))
+#define __inline__		__inline__	__attribute__((always_inline))
+#define __inline		__inline	__attribute__((always_inline))
+#define __deprecated		__attribute__((deprecated))
+#define __attribute_used__	__attribute__((__used__))
+#define __attribute_pure__	__attribute__((pure))
+#define __attribute_const__	__attribute__((__const__))
+#define  noinline		__attribute__((noinline))
+#define __must_check 		__attribute__((warn_unused_result))
+#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
+
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -8,6 +8,7 @@
 # define __kernel	/* default address space */
 # define __safe		__attribute__((safe))
 # define __force	__attribute__((force))
+# define __nocast	__attribute__((nocast))
 # define __iomem	__attribute__((noderef, address_space(2)))
 # define __acquires(x)	__attribute__((context(0,1)))
 # define __releases(x)	__attribute__((context(1,0)))
@@ -21,6 +22,7 @@ extern void __chk_io_ptr(void __iomem *)
 # define __kernel
 # define __safe
 # define __force
+# define __nocast
 # define __iomem
 # define __chk_user_ptr(x) (void)0
 # define __chk_io_ptr(x) (void)0
@@ -34,8 +36,10 @@ extern void __chk_io_ptr(void __iomem *)
 
 #ifdef __KERNEL__
 
-#if __GNUC__ > 3
-# include <linux/compiler-gcc+.h>	/* catch-all for GCC 4, 5, etc. */
+#if __GNUC__ > 4
+#error no compiler-gcc.h file for this gcc version
+#elif __GNUC__ == 4
+# include <linux/compiler-gcc4.h>
 #elif __GNUC__ == 3
 # include <linux/compiler-gcc3.h>
 #elif __GNUC__ == 2
@@ -72,10 +76,10 @@ extern void __chk_io_ptr(void __iomem *)
     (typeof(ptr)) (__ptr + (off)); })
 #endif
 
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
+#endif /* __ASSEMBLY__ */
+
 /*
  * Allow us to mark functions as 'deprecated' and have gcc emit a nice
  * warning for each use, in hopes of speeding the functions removal.
@@ -86,6 +90,12 @@ extern void __chk_io_ptr(void __iomem *)
 # define __deprecated		/* unimplemented */
 #endif
 
+#ifdef MODULE
+#define __deprecated_for_modules __deprecated
+#else
+#define __deprecated_for_modules
+#endif
+
 #ifndef __must_check
 #define __must_check
 #endif
diff --git a/include/linux/console.h b/include/linux/console.h
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -59,7 +59,6 @@ struct consw {
 extern const struct consw *conswitchp;
 
 extern const struct consw dummy_con;	/* dummy console buffer */
-extern const struct consw fb_con;	/* frame buffer based console */
 extern const struct consw vga_con;	/* VGA text console */
 extern const struct consw newport_con;	/* SGI Newport console  */
 extern const struct consw prom_con;	/* SPARC PROM console */
@@ -77,13 +76,17 @@ void give_up_console(const struct consw 
 #define CM_MOVE     (3)
 
 /*
- *	The interface for a console, or any other device that
- *	wants to capture console messages (printer driver?)
+ * The interface for a console, or any other device that wants to capture
+ * console messages (printer driver?)
+ *
+ * If a console driver is marked CON_BOOT then it will be auto-unregistered
+ * when the first real console is registered.  This is for early-printk drivers.
  */
 
 #define CON_PRINTBUFFER	(1)
 #define CON_CONSDEV	(2) /* Last on the command line */
 #define CON_ENABLED	(4)
+#define CON_BOOT	(8)
 
 struct console
 {
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -26,6 +26,7 @@ struct vc_data {
 	const struct consw *vc_sw;
 	unsigned short	*vc_screenbuf;		/* In-memory character/attribute buffer */
 	unsigned int	vc_screenbuf_size;
+	unsigned char	vc_mode;		/* KD_TEXT, ... */
 	/* attributes for all characters on screen */
 	unsigned char	vc_attr;		/* Current attributes */
 	unsigned char	vc_def_color;		/* Default colors */
@@ -48,6 +49,11 @@ struct vc_data {
 	unsigned int	vc_state;		/* Escape sequence parser state */
 	unsigned int	vc_npar,vc_par[NPAR];	/* Parameters of current escape sequence */
 	struct tty_struct *vc_tty;		/* TTY we are attached to */
+	/* data for manual vt switching */
+	struct vt_mode	vt_mode;
+	int		vt_pid;
+	int		vt_newvt;
+	wait_queue_head_t paste_wait;
 	/* mode flags */
 	unsigned int	vc_charset	: 1;	/* Character set G0 / G1 */
 	unsigned int	vc_s_charset	: 1;	/* Saved character set */
@@ -89,7 +95,6 @@ struct vc_data {
 	struct vc_data **vc_display_fg;		/* [!] Ptr to var holding fg console for this display */
 	unsigned long	vc_uni_pagedir;
 	unsigned long	*vc_uni_pagedir_loc;  /* [!] Location of uni_pagedir variable for this console */
-	struct vt_struct *vc_vt;
 	/* additional information is in vt_kern.h */
 };
 
diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h
--- a/include/linux/consolemap.h
+++ b/include/linux/consolemap.h
@@ -11,5 +11,5 @@
 struct vc_data;
 
 extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
-extern unsigned short *set_translate(int m,int currcons);
+extern unsigned short *set_translate(int m, struct vc_data *vc);
 extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -49,7 +49,7 @@ int cpufreq_unregister_notifier(struct n
 /* Frequency values here are CPU kHz so that hardware which doesn't run 
  * with some frequencies can complain without having to guess what per 
  * cent / per mille means. 
- * Maximum transition latency is in microseconds - if it's unknown,
+ * Maximum transition latency is in nanoseconds - if it's unknown,
  * CPUFREQ_ETERNAL shall be used.
  */
 
@@ -103,6 +103,7 @@ struct cpufreq_policy {
 #define CPUFREQ_PRECHANGE	(0)
 #define CPUFREQ_POSTCHANGE	(1)
 #define CPUFREQ_RESUMECHANGE	(8)
+#define CPUFREQ_SUSPENDCHANGE	(9)
 
 struct cpufreq_freqs {
 	unsigned int cpu;	/* cpu nr */
@@ -200,6 +201,7 @@ struct cpufreq_driver {
 
 	/* optional */
 	int	(*exit)		(struct cpufreq_policy *policy);
+	int	(*suspend)	(struct cpufreq_policy *policy, u32 state);
 	int	(*resume)	(struct cpufreq_policy *policy);
 	struct freq_attr	**attr;
 };
@@ -211,7 +213,8 @@ struct cpufreq_driver {
 #define CPUFREQ_CONST_LOOPS 	0x02	/* loops_per_jiffy or other kernel
 					 * "constants" aren't affected by
 					 * frequency transitions */
-
+#define CPUFREQ_PM_NO_WARN	0x04	/* don't warn on suspend/resume speed
+					 * mismatches */
 
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -10,6 +10,8 @@
  *
  * For details of cpumask_scnprintf() and cpumask_parse(),
  * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ * For details of cpulist_scnprintf() and cpulist_parse(), see
+ * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
  *
  * The available cpumask operations are:
  *
@@ -46,6 +48,8 @@
  *
  * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
  * int cpumask_parse(ubuf, ulen, mask)	Parse ascii string as cpumask
+ * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
+ * int cpulist_parse(buf, map)		Parse ascii string as cpulist
  *
  * for_each_cpu_mask(cpu, mask)		for-loop cpu over mask
  *
@@ -268,14 +272,28 @@ static inline int __cpumask_scnprintf(ch
 	return bitmap_scnprintf(buf, len, srcp->bits, nbits);
 }
 
-#define cpumask_parse(ubuf, ulen, src) \
-			__cpumask_parse((ubuf), (ulen), &(src), NR_CPUS)
+#define cpumask_parse(ubuf, ulen, dst) \
+			__cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS)
 static inline int __cpumask_parse(const char __user *buf, int len,
 					cpumask_t *dstp, int nbits)
 {
 	return bitmap_parse(buf, len, dstp->bits, nbits);
 }
 
+#define cpulist_scnprintf(buf, len, src) \
+			__cpulist_scnprintf((buf), (len), &(src), NR_CPUS)
+static inline int __cpulist_scnprintf(char *buf, int len,
+					const cpumask_t *srcp, int nbits)
+{
+	return bitmap_scnlistprintf(buf, len, srcp->bits, nbits);
+}
+
+#define cpulist_parse(buf, dst) __cpulist_parse((buf), &(dst), NR_CPUS)
+static inline int __cpulist_parse(const char *buf, cpumask_t *dstp, int nbits)
+{
+	return bitmap_parselist(buf, dstp->bits, nbits);
+}
+
 #if NR_CPUS > 1
 #define for_each_cpu_mask(cpu, mask)		\
 	for ((cpu) = first_cpu(mask);		\
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
new file mode 100644
--- /dev/null
+++ b/include/linux/cpuset.h
@@ -0,0 +1,64 @@
+#ifndef _LINUX_CPUSET_H
+#define _LINUX_CPUSET_H
+/*
+ *  cpuset interface
+ *
+ *  Copyright (C) 2003 BULL SA
+ *  Copyright (C) 2004 Silicon Graphics, Inc.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/nodemask.h>
+
+#ifdef CONFIG_CPUSETS
+
+extern int cpuset_init(void);
+extern void cpuset_init_smp(void);
+extern void cpuset_fork(struct task_struct *p);
+extern void cpuset_exit(struct task_struct *p);
+extern cpumask_t cpuset_cpus_allowed(const struct task_struct *p);
+void cpuset_init_current_mems_allowed(void);
+void cpuset_update_current_mems_allowed(void);
+void cpuset_restrict_to_mems_allowed(unsigned long *nodes);
+int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
+int cpuset_zone_allowed(struct zone *z);
+extern struct file_operations proc_cpuset_operations;
+extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
+
+#else /* !CONFIG_CPUSETS */
+
+static inline int cpuset_init(void) { return 0; }
+static inline void cpuset_init_smp(void) {}
+static inline void cpuset_fork(struct task_struct *p) {}
+static inline void cpuset_exit(struct task_struct *p) {}
+
+static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p)
+{
+	return cpu_possible_map;
+}
+
+static inline void cpuset_init_current_mems_allowed(void) {}
+static inline void cpuset_update_current_mems_allowed(void) {}
+static inline void cpuset_restrict_to_mems_allowed(unsigned long *nodes) {}
+
+static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
+{
+	return 1;
+}
+
+static inline int cpuset_zone_allowed(struct zone *z)
+{
+	return 1;
+}
+
+static inline char *cpuset_task_status_allowed(struct task_struct *task,
+							char *buffer)
+{
+	return buffer;
+}
+
+#endif /* !CONFIG_CPUSETS */
+
+#endif /* _LINUX_CPUSET_H */
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
new file mode 100644
--- /dev/null
+++ b/include/linux/cryptohash.h
@@ -0,0 +1,12 @@
+#ifndef __CRYPTOHASH_H
+#define __CRYPTOHASH_H
+
+#define SHA_DIGEST_WORDS 5
+#define SHA_WORKSPACE_WORDS 80
+
+void sha_init(__u32 *buf);
+void sha_transform(__u32 *digest, const char *data, __u32 *W);
+
+__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
+
+#endif
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -162,17 +162,16 @@ extern spinlock_t dcache_lock;
  * d_drop - drop a dentry
  * @dentry: dentry to drop
  *
- * d_drop() unhashes the entry from the parent
- * dentry hashes, so that it won't be found through
- * a VFS lookup any more. Note that this is different
- * from deleting the dentry - d_delete will try to
- * mark the dentry negative if possible, giving a
- * successful _negative_ lookup, while d_drop will
+ * d_drop() unhashes the entry from the parent dentry hashes, so that it won't
+ * be found through a VFS lookup any more. Note that this is different from
+ * deleting the dentry - d_delete will try to mark the dentry negative if
+ * possible, giving a successful _negative_ lookup, while d_drop will
  * just make the cache lookup fail.
  *
- * d_drop() is used mainly for stuff that wants
- * to invalidate a dentry for some reason (NFS
- * timeouts or autofs deletes).
+ * d_drop() is used mainly for stuff that wants to invalidate a dentry for some
+ * reason (NFS timeouts or autofs deletes).
+ *
+ * __d_drop requires dentry->d_lock.
  */
 
 static inline void __d_drop(struct dentry *dentry)
@@ -186,7 +185,9 @@ static inline void __d_drop(struct dentr
 static inline void d_drop(struct dentry *dentry)
 {
 	spin_lock(&dcache_lock);
+	spin_lock(&dentry->d_lock);
  	__d_drop(dentry);
+	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 }
 
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -15,6 +15,12 @@
 #ifndef _DEBUGFS_H_
 #define _DEBUGFS_H_
 
+#include <linux/fs.h>
+
+#include <linux/types.h>
+
+struct file_operations;
+
 #if defined(CONFIG_DEBUG_FS)
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
 				   struct dentry *parent, void *data,
@@ -34,6 +40,9 @@ struct dentry *debugfs_create_bool(const
 				  struct dentry *parent, u32 *value);
 
 #else
+
+#include <linux/err.h>
+
 /* 
  * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled
  * so users have a chance to detect if there was a real error or not.  We don't
@@ -66,21 +75,21 @@ static inline struct dentry *debugfs_cre
 
 static inline struct dentry *debugfs_create_u16(const char *name, mode_t mode,
 						struct dentry *parent,
-						u8 *value)
+						u16 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 						struct dentry *parent,
-						u8 *value)
+						u32 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 						 struct dentry *parent,
-						 u8 *value)
+						 u32 *value)
 {
 	return ERR_PTR(-ENODEV);
 }
diff --git a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -15,7 +15,6 @@
 #include <linux/ioport.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
-#include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pm.h>
@@ -102,7 +101,7 @@ struct device_driver {
 	char			* name;
 	struct bus_type		* bus;
 
-	struct semaphore	unload_sem;
+	struct completion	unloaded;
 	struct kobject		kobj;
 	struct list_head	devices;
 
@@ -111,7 +110,7 @@ struct device_driver {
 	int	(*probe)	(struct device * dev);
 	int 	(*remove)	(struct device * dev);
 	void	(*shutdown)	(struct device * dev);
-	int	(*suspend)	(struct device * dev, u32 state, u32 level);
+	int	(*suspend)	(struct device * dev, pm_message_t state, u32 level);
 	int	(*resume)	(struct device * dev, u32 level);
 };
 
@@ -148,6 +147,7 @@ struct class {
 	struct subsystem	subsys;
 	struct list_head	children;
 	struct list_head	interfaces;
+	struct semaphore	sem;	/* locks both the children and interfaces lists */
 
 	struct class_attribute		* class_attrs;
 	struct class_device_attribute	* class_dev_attrs;
@@ -184,6 +184,7 @@ struct class_device {
 
 	struct kobject		kobj;
 	struct class		* class;	/* required */
+	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
 	struct device		* dev;		/* not necessary, but nice to have */
 	void			* class_data;	/* class-specific data */
 
@@ -272,9 +273,6 @@ struct device {
 					   BIOS data relevant to device) */
 	struct dev_pm_info	power;
 
-	u32		detach_state;	/* State to enter when device is
-					   detached from its driver. */
-
 	u64		*dma_mask;	/* dma mask (if dma'able device) */
 	u64		coherent_dma_mask;/* Like dma_mask, but for
 					     alloc_coherent mappings as
diff --git a/include/linux/dp83840.h b/include/linux/dp83840.h
deleted file mode 100644
--- a/include/linux/dp83840.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/dp83840.h: definitions for DP83840 MII-compatible transceivers
- *
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
- */
-#ifndef __LINUX_DP83840_H
-#define __LINUX_DP83840_H
-
-#include <linux/mii.h>
-
-/*
- * Data sheets and programming docs for the DP83840 are available at
- * from http://www.national.com/
- *
- * The DP83840 is capable of both 10 and 100Mbps ethernet, in both
- * half and full duplex mode.  It also supports auto negotiation.
- *
- * But.... THIS THING IS A PAIN IN THE ASS TO PROGRAM!
- * Debugging eeprom burnt code is more fun than programming this chip!
- */
-
-/* First, the MII register numbers (actually DP83840 register numbers). */
-#define MII_CSCONFIG        0x17        /* CS configuration            */
-
-/* The Carrier Sense config register. */
-#define CSCONFIG_RESV1          0x0001  /* Unused...                   */
-#define CSCONFIG_LED4           0x0002  /* Pin for full-dplx LED4      */
-#define CSCONFIG_LED1           0x0004  /* Pin for conn-status LED1    */
-#define CSCONFIG_RESV2          0x0008  /* Unused...                   */
-#define CSCONFIG_TCVDISAB       0x0010  /* Turns off the transceiver   */
-#define CSCONFIG_DFBYPASS       0x0020  /* Bypass disconnect function  */
-#define CSCONFIG_GLFORCE        0x0040  /* Good link force for 100mbps */
-#define CSCONFIG_CLKTRISTATE    0x0080  /* Tristate 25m clock          */
-#define CSCONFIG_RESV3          0x0700  /* Unused...                   */
-#define CSCONFIG_ENCODE         0x0800  /* 1=MLT-3, 0=binary           */
-#define CSCONFIG_RENABLE        0x1000  /* Repeater mode enable        */
-#define CSCONFIG_TCDISABLE      0x2000  /* Disable timeout counter     */
-#define CSCONFIG_RESV4          0x4000  /* Unused...                   */
-#define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
-
-#endif /* __LINUX_DP83840_H */
diff --git a/include/linux/dqblk_xfs.h b/include/linux/dqblk_xfs.h
--- a/include/linux/dqblk_xfs.h
+++ b/include/linux/dqblk_xfs.h
@@ -28,6 +28,12 @@
  */
 
 #define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
+#define XQM_COMMAND(x)	(((x) & (0xff<<8)) == ('X'<<8))	/* test if for XFS */
+
+#define XQM_USRQUOTA	0	/* system call user quota type */
+#define XQM_GRPQUOTA	1	/* system call group quota type */
+#define XQM_MAXQUOTAS	2
+
 #define Q_XQUOTAON	XQM_CMD(1)	/* enable accounting/enforcement */
 #define Q_XQUOTAOFF	XQM_CMD(2)	/* disable accounting/enforcement */
 #define Q_XGETQUOTA	XQM_CMD(3)	/* get disk limits and usage */
diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
--- a/include/linux/dvb/audio.h
+++ b/include/linux/dvb/audio.h
@@ -1,9 +1,9 @@
-/* 
+/*
  * audio.h
  *
  * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
  *                  & Marcus Metzler <marcus@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Lesser Public License
@@ -32,35 +32,35 @@
 
 
 typedef enum {
-        AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ 
-	AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ 
+        AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */
+	AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */
 } audio_stream_source_t;
 
 
-typedef enum { 
-	AUDIO_STOPPED,      /* Device is stopped */ 
-        AUDIO_PLAYING,      /* Device is currently playing */ 
-	AUDIO_PAUSED        /* Device is paused */ 
+typedef enum {
+	AUDIO_STOPPED,      /* Device is stopped */
+        AUDIO_PLAYING,      /* Device is currently playing */
+	AUDIO_PAUSED        /* Device is paused */
 } audio_play_state_t;
 
 
 typedef enum {
         AUDIO_STEREO,
-        AUDIO_MONO_LEFT, 
-	AUDIO_MONO_RIGHT 
+        AUDIO_MONO_LEFT,
+	AUDIO_MONO_RIGHT
 } audio_channel_select_t;
 
 
-typedef struct audio_mixer { 
+typedef struct audio_mixer {
         unsigned int volume_left;
         unsigned int volume_right;
   // what else do we need? bass, pass-through, ...
 } audio_mixer_t;
 
 
-typedef struct audio_status { 
+typedef struct audio_status {
         int                    AV_sync_state;  /* sync audio and video? */
-        int                    mute_state;     /* audio is muted */ 
+        int                    mute_state;     /* audio is muted */
         audio_play_state_t     play_state;     /* current playback state */
         audio_stream_source_t  stream_source;  /* current stream source */
         audio_channel_select_t channel_select; /* currently selected channel */
@@ -88,7 +88,7 @@ typedef uint16_t audio_attributes_t;
 /*    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  */
 /*    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */
 /*    2- 0 number of audio channels (n+1 channels) */
- 
+
 
 /* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */
 #define AUDIO_CAP_DTS    1
@@ -101,7 +101,7 @@ typedef uint16_t audio_attributes_t;
 #define AUDIO_CAP_SDDS 128
 #define AUDIO_CAP_AC3  256
 
-#define AUDIO_STOP                 _IO('o', 1) 
+#define AUDIO_STOP                 _IO('o', 1)
 #define AUDIO_PLAY                 _IO('o', 2)
 #define AUDIO_PAUSE                _IO('o', 3)
 #define AUDIO_CONTINUE             _IO('o', 4)
@@ -122,4 +122,3 @@ typedef uint16_t audio_attributes_t;
 #define AUDIO_SET_KARAOKE          _IOW('o', 18, audio_karaoke_t)
 
 #endif /* _DVBAUDIO_H_ */
-
diff --git a/include/linux/dvb/ca.h b/include/linux/dvb/ca.h
--- a/include/linux/dvb/ca.h
+++ b/include/linux/dvb/ca.h
@@ -1,9 +1,9 @@
-/* 
+/*
  * ca.h
  *
  * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
  *                  & Marcus Metzler <marcus@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Lesser Public License
@@ -88,4 +88,3 @@ typedef struct ca_pid {
 #define CA_SET_PID        _IOW('o', 135, ca_pid_t)
 
 #endif
-
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
  *                  & Ralph  Metzler <ralph@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -31,6 +31,7 @@
 #include <time.h>
 #endif
 
+
 #define DMX_FILTER_SIZE 16
 
 typedef enum
@@ -111,10 +112,10 @@ typedef struct dmx_filter
 
 struct dmx_sct_filter_params
 {
-	__u16            pid;
-	dmx_filter_t        filter;
-	__u32            timeout;
-	__u32            flags;
+	__u16          pid;
+	dmx_filter_t   filter;
+	__u32          timeout;
+	__u32          flags;
 #define DMX_CHECK_CRC       1
 #define DMX_ONESHOT         2
 #define DMX_IMMEDIATE_START 4
@@ -124,11 +125,11 @@ struct dmx_sct_filter_params
 
 struct dmx_pes_filter_params
 {
-	__u16            pid;
-	dmx_input_t         input;
-	dmx_output_t        output;
-	dmx_pes_type_t      pes_type;
-	__u32            flags;
+	__u16          pid;
+	dmx_input_t    input;
+	dmx_output_t   output;
+	dmx_pes_type_t pes_type;
+	__u32          flags;
 };
 
 
@@ -144,7 +145,7 @@ struct dmx_event
 
 typedef struct dmx_caps {
 	__u32 caps;
-	int num_decoders; 
+	int num_decoders;
 } dmx_caps_t;
 
 typedef enum {
@@ -165,16 +166,15 @@ struct dmx_stc {
 };
 
 
-#define DMX_START                _IO('o',41) 
-#define DMX_STOP                 _IO('o',42)
-#define DMX_SET_FILTER           _IOW('o',43,struct dmx_sct_filter_params)
-#define DMX_SET_PES_FILTER       _IOW('o',44,struct dmx_pes_filter_params)
-#define DMX_SET_BUFFER_SIZE      _IO('o',45)
-#define DMX_GET_EVENT            _IOR('o',46,struct dmx_event)
+#define DMX_START                _IO('o', 41)
+#define DMX_STOP                 _IO('o', 42)
+#define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
+#define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
+#define DMX_SET_BUFFER_SIZE      _IO('o', 45)
+#define DMX_GET_EVENT            _IOR('o', 46, struct dmx_event)
 #define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
-#define DMX_GET_CAPS             _IOR('o',48,dmx_caps_t)
-#define DMX_SET_SOURCE           _IOW('o',49,dmx_source_t)
-#define DMX_GET_STC              _IOWR('o',50,struct dmx_stc)
+#define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
+#define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
+#define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
 
 #endif /*_DVBDMX_H_*/
-
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -2,10 +2,10 @@
  * frontend.h
  *
  * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
- *                    Ralph  Metzler <ralph@convergence.de>
- *                    Holger Waechtler <holger@convergence.de>
- *                    Andre Draszik <ad@convergence.de>
- *                    for convergence integrated media GmbH
+ *		    Ralph  Metzler <ralph@convergence.de>
+ *		    Holger Waechtler <holger@convergence.de>
+ *		    Andre Draszik <ad@convergence.de>
+ *		    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -30,54 +30,54 @@
 
 
 typedef enum fe_type {
-        FE_QPSK,
-        FE_QAM,
+	FE_QPSK,
+	FE_QAM,
 	FE_OFDM,
 	FE_ATSC
 } fe_type_t;
 
 
 typedef enum fe_caps {
-	FE_IS_STUPID                  = 0,
-	FE_CAN_INVERSION_AUTO         = 0x1,
-	FE_CAN_FEC_1_2                = 0x2,
-	FE_CAN_FEC_2_3                = 0x4,
-	FE_CAN_FEC_3_4                = 0x8,
-	FE_CAN_FEC_4_5                = 0x10,
-	FE_CAN_FEC_5_6                = 0x20,
-	FE_CAN_FEC_6_7                = 0x40,
-	FE_CAN_FEC_7_8                = 0x80,
-	FE_CAN_FEC_8_9                = 0x100,
-	FE_CAN_FEC_AUTO               = 0x200,
-	FE_CAN_QPSK                   = 0x400,
-	FE_CAN_QAM_16                 = 0x800,
-	FE_CAN_QAM_32                 = 0x1000,
-	FE_CAN_QAM_64                 = 0x2000,
-	FE_CAN_QAM_128                = 0x4000,
-	FE_CAN_QAM_256                = 0x8000,
-	FE_CAN_QAM_AUTO               = 0x10000,
-	FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000,
-	FE_CAN_BANDWIDTH_AUTO         = 0x40000,
-	FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
-	FE_CAN_HIERARCHY_AUTO         = 0x100000,
+	FE_IS_STUPID			= 0,
+	FE_CAN_INVERSION_AUTO		= 0x1,
+	FE_CAN_FEC_1_2			= 0x2,
+	FE_CAN_FEC_2_3			= 0x4,
+	FE_CAN_FEC_3_4			= 0x8,
+	FE_CAN_FEC_4_5			= 0x10,
+	FE_CAN_FEC_5_6			= 0x20,
+	FE_CAN_FEC_6_7			= 0x40,
+	FE_CAN_FEC_7_8			= 0x80,
+	FE_CAN_FEC_8_9			= 0x100,
+	FE_CAN_FEC_AUTO			= 0x200,
+	FE_CAN_QPSK			= 0x400,
+	FE_CAN_QAM_16			= 0x800,
+	FE_CAN_QAM_32			= 0x1000,
+	FE_CAN_QAM_64			= 0x2000,
+	FE_CAN_QAM_128			= 0x4000,
+	FE_CAN_QAM_256			= 0x8000,
+	FE_CAN_QAM_AUTO			= 0x10000,
+	FE_CAN_TRANSMISSION_MODE_AUTO	= 0x20000,
+	FE_CAN_BANDWIDTH_AUTO		= 0x40000,
+	FE_CAN_GUARD_INTERVAL_AUTO	= 0x80000,
+	FE_CAN_HIERARCHY_AUTO		= 0x100000,
 	FE_CAN_8VSB			= 0x200000,
 	FE_CAN_16VSB			= 0x400000,
 	FE_NEEDS_BENDING		= 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
-	FE_CAN_RECOVER                = 0x40000000, // frontend can recover from a cable unplug automatically
-	FE_CAN_MUTE_TS                = 0x80000000  // frontend can stop spurious TS data output
+	FE_CAN_RECOVER			= 0x40000000, // frontend can recover from a cable unplug automatically
+	FE_CAN_MUTE_TS			= 0x80000000  // frontend can stop spurious TS data output
 } fe_caps_t;
 
 
 struct dvb_frontend_info {
 	char       name[128];
-        fe_type_t  type;
-        __u32      frequency_min;
-        __u32      frequency_max;
+	fe_type_t  type;
+	__u32      frequency_min;
+	__u32      frequency_max;
 	__u32      frequency_stepsize;
 	__u32      frequency_tolerance;
 	__u32      symbol_rate_min;
-        __u32      symbol_rate_max;
-	__u32      symbol_rate_tolerance;     /* ppm */
+	__u32      symbol_rate_max;
+	__u32      symbol_rate_tolerance;	/* ppm */
 	__u32      notifier_delay;		/* DEPRECATED */
 	fe_caps_t  caps;
 };
@@ -88,76 +88,76 @@ struct dvb_frontend_info {
  *  the meaning of this struct...
  */
 struct dvb_diseqc_master_cmd {
-        __u8 msg [6];        /*  { framing, address, command, data [3] } */
-        __u8 msg_len;        /*  valid values are 3...6  */
+	__u8 msg [6];	/*  { framing, address, command, data [3] } */
+	__u8 msg_len;	/*  valid values are 3...6  */
 };
 
 
 struct dvb_diseqc_slave_reply {
-	__u8 msg [4];        /*  { framing, data [3] } */
-	__u8 msg_len;        /*  valid values are 0...4, 0 means no msg  */
-	int     timeout;        /*  return from ioctl after timeout ms with */
-};                              /*  errorcode when no message was received  */
+	__u8 msg [4];	/*  { framing, data [3] } */
+	__u8 msg_len;	/*  valid values are 0...4, 0 means no msg  */
+	int  timeout;	/*  return from ioctl after timeout ms with */
+};			/*  errorcode when no message was received  */
 
 
 typedef enum fe_sec_voltage {
-        SEC_VOLTAGE_13,
-        SEC_VOLTAGE_18,
+	SEC_VOLTAGE_13,
+	SEC_VOLTAGE_18,
 	SEC_VOLTAGE_OFF
 } fe_sec_voltage_t;
 
 
 typedef enum fe_sec_tone_mode {
-        SEC_TONE_ON,
-        SEC_TONE_OFF
+	SEC_TONE_ON,
+	SEC_TONE_OFF
 } fe_sec_tone_mode_t;
 
 
 typedef enum fe_sec_mini_cmd {
-        SEC_MINI_A,
-        SEC_MINI_B
+	SEC_MINI_A,
+	SEC_MINI_B
 } fe_sec_mini_cmd_t;
 
 
 typedef enum fe_status {
-	FE_HAS_SIGNAL     = 0x01,   /*  found something above the noise level */
-	FE_HAS_CARRIER    = 0x02,   /*  found a DVB signal  */
-	FE_HAS_VITERBI    = 0x04,   /*  FEC is stable  */
-	FE_HAS_SYNC       = 0x08,   /*  found sync bytes  */
-	FE_HAS_LOCK       = 0x10,   /*  everything's working... */
-	FE_TIMEDOUT       = 0x20,   /*  no lock within the last ~2 seconds */
-	FE_REINIT         = 0x40    /*  frontend was reinitialized,  */
-} fe_status_t;                      /*  application is recommended to reset */
-                                    /*  DiSEqC, tone and parameters */
+	FE_HAS_SIGNAL	= 0x01,   /*  found something above the noise level */
+	FE_HAS_CARRIER	= 0x02,   /*  found a DVB signal  */
+	FE_HAS_VITERBI	= 0x04,   /*  FEC is stable  */
+	FE_HAS_SYNC	= 0x08,   /*  found sync bytes  */
+	FE_HAS_LOCK	= 0x10,   /*  everything's working... */
+	FE_TIMEDOUT	= 0x20,   /*  no lock within the last ~2 seconds */
+	FE_REINIT	= 0x40    /*  frontend was reinitialized,  */
+} fe_status_t;			  /*  application is recommended to reset */
+				  /*  DiSEqC, tone and parameters */
 
 typedef enum fe_spectral_inversion {
-        INVERSION_OFF,
-        INVERSION_ON,
-        INVERSION_AUTO
+	INVERSION_OFF,
+	INVERSION_ON,
+	INVERSION_AUTO
 } fe_spectral_inversion_t;
 
 
 typedef enum fe_code_rate {
-        FEC_NONE = 0,
-        FEC_1_2,
-        FEC_2_3,
-        FEC_3_4,
-        FEC_4_5,
-        FEC_5_6,
-        FEC_6_7,
-        FEC_7_8,
-        FEC_8_9,
-        FEC_AUTO
+	FEC_NONE = 0,
+	FEC_1_2,
+	FEC_2_3,
+	FEC_3_4,
+	FEC_4_5,
+	FEC_5_6,
+	FEC_6_7,
+	FEC_7_8,
+	FEC_8_9,
+	FEC_AUTO
 } fe_code_rate_t;
 
 
 typedef enum fe_modulation {
-        QPSK,
-        QAM_16,
-        QAM_32,
-        QAM_64,
-        QAM_128,
-        QAM_256,
+	QPSK,
+	QAM_16,
+	QAM_32,
+	QAM_64,
+	QAM_128,
+	QAM_256,
 	QAM_AUTO,
 	VSB_8,
 	VSB_16
@@ -196,15 +196,14 @@ typedef enum fe_hierarchy {
 
 
 struct dvb_qpsk_parameters {
-        __u32           symbol_rate;  /* symbol rate in Symbols per second */
-        fe_code_rate_t  fec_inner;    /* forward error correction (see above) */
+	__u32		symbol_rate;  /* symbol rate in Symbols per second */
+	fe_code_rate_t	fec_inner;    /* forward error correction (see above) */
 };
 
-
 struct dvb_qam_parameters {
-        __u32            symbol_rate; /* symbol rate in Symbols per second */
-        fe_code_rate_t   fec_inner;   /* forward error correction (see above) */
-        fe_modulation_t  modulation;  /* modulation type (see above) */
+	__u32		symbol_rate; /* symbol rate in Symbols per second */
+	fe_code_rate_t	fec_inner;   /* forward error correction (see above) */
+	fe_modulation_t	modulation;  /* modulation type (see above) */
 };
 
 struct dvb_vsb_parameters {
@@ -212,19 +211,19 @@ struct dvb_vsb_parameters {
 };
 
 struct dvb_ofdm_parameters {
-        fe_bandwidth_t      bandwidth;
-        fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
-        fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
-        fe_modulation_t     constellation; /* modulation type (see above) */
-        fe_transmit_mode_t  transmission_mode;
-        fe_guard_interval_t guard_interval;
-        fe_hierarchy_t      hierarchy_information;
+	fe_bandwidth_t      bandwidth;
+	fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
+	fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
+	fe_modulation_t     constellation; /* modulation type (see above) */
+	fe_transmit_mode_t  transmission_mode;
+	fe_guard_interval_t guard_interval;
+	fe_hierarchy_t      hierarchy_information;
 };
 
 
 struct dvb_frontend_parameters {
 	__u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM/ATSC */
-                                  /* intermediate frequency in kHz for QPSK */
+			     /* intermediate frequency in kHz for QPSK */
 	fe_spectral_inversion_t inversion;
 	union {
 		struct dvb_qpsk_parameters qpsk;
@@ -242,29 +241,27 @@ struct dvb_frontend_event {
 
 
 
-#define FE_GET_INFO                _IOR('o', 61, struct dvb_frontend_info)
+#define FE_GET_INFO		   _IOR('o', 61, struct dvb_frontend_info)
 
 #define FE_DISEQC_RESET_OVERLOAD   _IO('o', 62)
 #define FE_DISEQC_SEND_MASTER_CMD  _IOW('o', 63, struct dvb_diseqc_master_cmd)
 #define FE_DISEQC_RECV_SLAVE_REPLY _IOR('o', 64, struct dvb_diseqc_slave_reply)
 #define FE_DISEQC_SEND_BURST       _IO('o', 65)  /* fe_sec_mini_cmd_t */
 
-#define FE_SET_TONE                _IO('o', 66)  /* fe_sec_tone_mode_t */
-#define FE_SET_VOLTAGE             _IO('o', 67)  /* fe_sec_voltage_t */
+#define FE_SET_TONE		   _IO('o', 66)  /* fe_sec_tone_mode_t */
+#define FE_SET_VOLTAGE		   _IO('o', 67)  /* fe_sec_voltage_t */
 #define FE_ENABLE_HIGH_LNB_VOLTAGE _IO('o', 68)  /* int */
 
-#define FE_READ_STATUS             _IOR('o', 69, fe_status_t)
-#define FE_READ_BER                _IOR('o', 70, __u32)
+#define FE_READ_STATUS		   _IOR('o', 69, fe_status_t)
+#define FE_READ_BER		   _IOR('o', 70, __u32)
 #define FE_READ_SIGNAL_STRENGTH    _IOR('o', 71, __u16)
-#define FE_READ_SNR                _IOR('o', 72, __u16)
+#define FE_READ_SNR		   _IOR('o', 72, __u16)
 #define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32)
 
-#define FE_SET_FRONTEND            _IOW('o', 76, struct dvb_frontend_parameters)
-#define FE_GET_FRONTEND            _IOR('o', 77, struct dvb_frontend_parameters)
-#define FE_GET_EVENT               _IOR('o', 78, struct dvb_frontend_event)
+#define FE_SET_FRONTEND		   _IOW('o', 76, struct dvb_frontend_parameters)
+#define FE_GET_FRONTEND		   _IOR('o', 77, struct dvb_frontend_parameters)
+#define FE_GET_EVENT		   _IOR('o', 78, struct dvb_frontend_event)
 
 #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
 
-
 #endif /*_DVBFRONTEND_H_*/
-
diff --git a/include/linux/dvb/net.h b/include/linux/dvb/net.h
--- a/include/linux/dvb/net.h
+++ b/include/linux/dvb/net.h
@@ -1,9 +1,9 @@
-/* 
+/*
  * net.h
  *
  * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
  *                  & Ralph  Metzler <ralph@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -30,15 +30,15 @@
 struct dvb_net_if {
 	__u16 pid;
 	__u16 if_num;
-	__u8 feedtype;
+	__u8  feedtype;
 #define DVB_NET_FEEDTYPE_MPE 0	/* multi protocol encapsulation */
 #define DVB_NET_FEEDTYPE_ULE 1	/* ultra lightweight encapsulation */
 };
 
 
-#define NET_ADD_IF                 _IOWR('o', 52, struct dvb_net_if)
-#define NET_REMOVE_IF              _IO('o', 53)
-#define NET_GET_IF                 _IOWR('o', 54, struct dvb_net_if)
+#define NET_ADD_IF    _IOWR('o', 52, struct dvb_net_if)
+#define NET_REMOVE_IF _IO('o', 53)
+#define NET_GET_IF    _IOWR('o', 54, struct dvb_net_if)
 
 
 /* binary compatibility cruft: */
diff --git a/include/linux/dvb/osd.h b/include/linux/dvb/osd.h
--- a/include/linux/dvb/osd.h
+++ b/include/linux/dvb/osd.h
@@ -1,9 +1,9 @@
-/* 
+/*
  * osd.h
  *
  * Copyright (C) 2001 Ralph  Metzler <ralph@convergence.de>
  *                  & Marcus Metzler <marcus@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Lesser Public License
@@ -93,7 +93,7 @@ typedef enum {
 // TODO: remove "test" in final version
   OSD_Text,       // (x0,y0,size,color,text)
   OSD_SetWindow, //  (x0) set window with number 0<x0<8 as current
-  OSD_MoveWindow, //  move current window to (x0, y0)  
+  OSD_MoveWindow, //  move current window to (x0, y0)
   OSD_OpenRaw,	// Open other types of OSD windows
 } OSD_Command;
 
@@ -138,8 +138,7 @@ typedef struct osd_cap_s {
 } osd_cap_t;
 
 
-#define OSD_SEND_CMD       _IOW('o', 160, osd_cmd_t)
+#define OSD_SEND_CMD            _IOW('o', 160, osd_cmd_t)
 #define OSD_GET_CAPABILITY      _IOR('o', 161, osd_cap_t)
 
 #endif
-
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -27,4 +27,3 @@
 #define DVB_API_VERSION_MINOR 1
 
 #endif /*_DVBVERSION_H_*/
-
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -1,9 +1,9 @@
-/* 
+/*
  * video.h
  *
  * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
  *                  & Ralph  Metzler <ralph@convergence.de>
-                      for convergence integrated media GmbH
+ *                    for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -35,25 +35,25 @@
 
 
 typedef enum {
-	VIDEO_FORMAT_4_3,     /* Select 4:3 format */ 
+	VIDEO_FORMAT_4_3,     /* Select 4:3 format */
         VIDEO_FORMAT_16_9,    /* Select 16:9 format. */
 	VIDEO_FORMAT_221_1    /* 2.21:1 */
 } video_format_t;
 
 
 typedef enum {
-	 VIDEO_SYSTEM_PAL, 
-	 VIDEO_SYSTEM_NTSC, 
-	 VIDEO_SYSTEM_PALN, 
-	 VIDEO_SYSTEM_PALNc, 
-	 VIDEO_SYSTEM_PALM, 
-	 VIDEO_SYSTEM_NTSC60, 
+	 VIDEO_SYSTEM_PAL,
+	 VIDEO_SYSTEM_NTSC,
+	 VIDEO_SYSTEM_PALN,
+	 VIDEO_SYSTEM_PALNc,
+	 VIDEO_SYSTEM_PALM,
+	 VIDEO_SYSTEM_NTSC60,
 	 VIDEO_SYSTEM_PAL60,
 	 VIDEO_SYSTEM_PALM60
 } video_system_t;
 
 
-typedef enum {   
+typedef enum {
         VIDEO_PAN_SCAN,       /* use pan and scan format */
 	VIDEO_LETTER_BOX,     /* use letterbox format */
 	VIDEO_CENTER_CUT_OUT  /* use center cut out format */
@@ -66,35 +66,35 @@ typedef struct {
 } video_size_t;
 
 typedef enum {
-        VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ 
-	VIDEO_SOURCE_MEMORY /* If this source is selected, the stream 
-			       comes from the user through the write 
-			       system call */ 
+        VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
+	VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
+			       comes from the user through the write
+			       system call */
 } video_stream_source_t;
 
 
 typedef enum {
-	VIDEO_STOPPED, /* Video is stopped */ 
-        VIDEO_PLAYING, /* Video is currently playing */ 
-	VIDEO_FREEZED  /* Video is freezed */ 
-} video_play_state_t; 
+	VIDEO_STOPPED, /* Video is stopped */
+        VIDEO_PLAYING, /* Video is currently playing */
+	VIDEO_FREEZED  /* Video is freezed */
+} video_play_state_t;
 
 
-struct video_event { 
-        int32_t type; 
-#define VIDEO_EVENT_SIZE_CHANGED 1
+struct video_event {
+        int32_t type;
+#define VIDEO_EVENT_SIZE_CHANGED	1
 #define VIDEO_EVENT_FRAME_RATE_CHANGED	2
         time_t timestamp;
-	union { 
+	union {
 	        video_size_t size;
 		unsigned int frame_rate;	/* in frames per 1000sec */
-	} u; 
+	} u;
 };
 
 
-struct video_status { 
+struct video_status {
         int                   video_blank;   /* blank video on freeze? */
-        video_play_state_t    play_state;    /* current state of playback */  
+        video_play_state_t    play_state;    /* current state of playback */
         video_stream_source_t stream_source; /* current source (demux/memory) */
         video_format_t        video_format;  /* current aspect ratio of stream*/
         video_displayformat_t display_format;/* selected cropping mode */
@@ -103,11 +103,11 @@ struct video_status { 
 
 struct video_still_picture {
         char __user *iFrame;        /* pointer to a single iframe in memory */
-        int32_t size; 
+        int32_t size;
 };
 
 
-typedef 
+typedef
 struct video_highlight {
 	int     active;      /*    1=show highlight, 0=hide highlight */
 	uint8_t contrast1;   /*    7- 4  Pattern pixel contrast */
@@ -118,7 +118,7 @@ struct video_highlight {
                              /*    3- 0  Background pixel color */
 	uint8_t color2;      /*    7- 4  Emphasis pixel-2 color */
                              /*    3- 0  Emphasis pixel-1 color */
- 	uint32_t ypos;       /*   23-22  auto action mode */
+	uint32_t ypos;       /*   23-22  auto action mode */
                              /*   21-12  start y */
                              /*    9- 0  end y */
 	uint32_t xpos;       /*   23-22  button color number */
@@ -160,21 +160,21 @@ typedef uint16_t video_attributes_t;
 
 /* bit definitions for capabilities: */
 /* can the hardware decode MPEG1 and/or MPEG2? */
-#define VIDEO_CAP_MPEG1   1 
+#define VIDEO_CAP_MPEG1   1
 #define VIDEO_CAP_MPEG2   2
 /* can you send a system and/or program stream to video device?
-   (you still have to open the video and the audio device but only 
+   (you still have to open the video and the audio device but only
     send the stream to the video device) */
 #define VIDEO_CAP_SYS     4
 #define VIDEO_CAP_PROG    8
-/* can the driver also handle SPU, NAVI and CSS encoded data? 
+/* can the driver also handle SPU, NAVI and CSS encoded data?
    (CSS API is not present yet) */
 #define VIDEO_CAP_SPU    16
 #define VIDEO_CAP_NAVI   32
 #define VIDEO_CAP_CSS    64
 
 
-#define VIDEO_STOP                 _IO('o', 21) 
+#define VIDEO_STOP                 _IO('o', 21)
 #define VIDEO_PLAY                 _IO('o', 22)
 #define VIDEO_FREEZE               _IO('o', 23)
 #define VIDEO_CONTINUE             _IO('o', 24)
@@ -201,4 +201,3 @@ typedef uint16_t video_attributes_t;
 #define VIDEO_GET_FRAME_RATE       _IOR('o', 56, unsigned int)
 
 #endif /*_DVBVIDEO_H_*/
-
diff --git a/include/linux/edd.h b/include/linux/edd.h
--- a/include/linux/edd.h
+++ b/include/linux/edd.h
@@ -32,7 +32,7 @@
 
 #define EDDNR 0x1e9		/* addr of number of edd_info structs at EDDBUF
 				   in boot_params - treat this as 1 byte  */
-#define EDDBUF	0x600		/* addr of edd_info structs in boot_params */
+#define EDDBUF	0xd00		/* addr of edd_info structs in boot_params */
 #define EDDMAXNR 6		/* number of edd_info structs starting at EDDBUF  */
 #define EDDEXTSIZE 8		/* change these if you muck with the structures */
 #define EDDPARMSIZE 74
diff --git a/include/linux/efi.h b/include/linux/efi.h
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -301,7 +301,6 @@ extern u64 efi_mem_attributes (unsigned 
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
 					struct resource *data_resource);
-extern efi_status_t phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc);
 extern unsigned long __init efi_get_time(void);
 extern int __init efi_set_rtc_mmss(unsigned long nowtime);
 extern struct efi_memory_map memmap;
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -20,6 +20,7 @@ typedef int (elevator_may_queue_fn) (req
 
 typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
 typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
+typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
 
 typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
 typedef void (elevator_exit_fn) (elevator_t *);
@@ -34,6 +35,7 @@ struct elevator_ops
 	elevator_add_req_fn *elevator_add_req_fn;
 	elevator_remove_req_fn *elevator_remove_req_fn;
 	elevator_requeue_req_fn *elevator_requeue_req_fn;
+	elevator_deactivate_req_fn *elevator_deactivate_req_fn;
 
 	elevator_queue_empty_fn *elevator_queue_empty_fn;
 	elevator_completed_req_fn *elevator_completed_req_fn;
@@ -87,6 +89,7 @@ extern void elv_merge_requests(request_q
 extern void elv_merged_request(request_queue_t *, struct request *);
 extern void elv_remove_request(request_queue_t *, struct request *);
 extern void elv_requeue_request(request_queue_t *, struct request *);
+extern void elv_deactivate_request(request_queue_t *, struct request *);
 extern int elv_queue_empty(request_queue_t *);
 extern struct request *elv_next_request(struct request_queue *q);
 extern struct request *elv_former_request(request_queue_t *, struct request *);
diff --git a/include/linux/err.h b/include/linux/err.h
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -13,6 +13,8 @@
  * This should be a per-architecture thing, to allow different
  * error and pointer decisions.
  */
+#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)
+
 static inline void *ERR_PTR(long error)
 {
 	return (void *) error;
@@ -25,7 +27,7 @@ static inline long PTR_ERR(const void *p
 
 static inline long IS_ERR(const void *ptr)
 {
-	return unlikely((unsigned long)ptr > (unsigned long)-1000L);
+	return IS_ERR_VALUE((unsigned long)ptr);
 }
 
 #endif /* _LINUX_ERR_H */
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)eth.h	1.0.4	05/13/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		Relocated to include/linux where it belongs by Alan Cox 
@@ -47,20 +47,41 @@ static inline void eth_copy_and_sum (str
 }
 
 /**
+ * is_zero_ether_addr - Determine if give Ethernet address is all
+ * zeros.
+ */
+static inline int is_zero_ether_addr(const u8 *addr)
+{
+	return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
+}
+
+/**
+ * is_multicast_ether_addr - Determine if the given Ethernet address is a
+ * multicast address.
+ *
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return true if the address is a multicast address.
+ */
+static inline int is_multicast_ether_addr(const u8 *addr)
+{
+	return addr[0] & 0x01;
+}
+
+/**
  * is_valid_ether_addr - Determine if the given Ethernet address is valid
  * @addr: Pointer to a six-byte array containing the Ethernet address
  *
  * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
- * a multicast address, and is not FF:FF:FF:FF:FF:FF.  The multicast
- * and FF:FF:... tests are combined into the single test "!(addr[0]&1)".
+ * a multicast address, and is not FF:FF:FF:FF:FF:FF.
  *
  * Return true if the address is valid.
  */
-static inline int is_valid_ether_addr( const u8 *addr )
+static inline int is_valid_ether_addr(const u8 *addr)
 {
-	const char zaddr[6] = {0,};
-
-	return !(addr[0]&1) && memcmp( addr, zaddr, 6);
+	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
+	 * explicitly check for it here. */
+	return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
 }
 
 /**
@@ -76,6 +97,6 @@ static inline void random_ether_addr(u8 
 	addr [0] &= 0xfe;	/* clear multicast bit */
 	addr [0] |= 0x02;	/* set local assignment bit (IEEE802) */
 }
-#endif
+#endif	/* __KERNEL__ */
 
 #endif	/* _LINUX_ETHERDEVICE_H */
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -256,6 +256,7 @@ struct net_device;
 u32 ethtool_op_get_link(struct net_device *dev);
 u32 ethtool_op_get_tx_csum(struct net_device *dev);
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
+int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
 u32 ethtool_op_get_sg(struct net_device *dev);
 int ethtool_op_set_sg(struct net_device *dev, u32 data);
 u32 ethtool_op_get_tso(struct net_device *dev);
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -357,6 +357,7 @@ struct ext3_inode {
 #define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
 #define EXT3_MOUNT_RESERVATION		0x10000	/* Preallocation */
 #define EXT3_MOUNT_BARRIER		0x20000 /* Use block barriers */
+#define EXT3_MOUNT_NOBH			0x40000 /* No bufferheads */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -724,6 +725,7 @@ extern struct ext3_group_desc * ext3_get
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
 extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
+extern void ext3_init_block_alloc_info(struct inode *);
 extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv);
 
 /* dir.c */
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -27,12 +27,31 @@ struct ext3_reserve_window {
 
 struct ext3_reserve_window_node {
 	struct rb_node	 	rsv_node;
-	atomic_t		rsv_goal_size;
-	atomic_t		rsv_alloc_hit;
-	seqlock_t		rsv_seqlock;
+	__u32			rsv_goal_size;
+	__u32			rsv_alloc_hit;
 	struct ext3_reserve_window	rsv_window;
 };
 
+struct ext3_block_alloc_info {
+	/* information about reservation window */
+	struct ext3_reserve_window_node	rsv_window_node;
+	/*
+	 * was i_next_alloc_block in ext3_inode_info
+	 * is the logical (file-relative) number of the
+	 * most-recently-allocated block in this file.
+	 * We use this for detecting linearly ascending allocation requests.
+	 */
+	__u32                   last_alloc_logical_block;
+	/*
+	 * Was i_next_alloc_goal in ext3_inode_info
+	 * is the *physical* companion to i_next_alloc_block.
+	 * it the the physical block number of the block which was most-recentl
+	 * allocated to this file.  This give us the goal (target) for the next
+	 * allocation when we detect linearly ascending requests.
+	 */
+	__u32                   last_alloc_physical_block;
+};
+
 #define rsv_start rsv_window._rsv_start
 #define rsv_end rsv_window._rsv_end
 
@@ -61,22 +80,8 @@ struct ext3_inode_info {
 	__u32	i_block_group;
 	__u32	i_state;		/* Dynamic state flags for ext3 */
 
-	/*
-	 * i_next_alloc_block is the logical (file-relative) number of the
-	 * most-recently-allocated block in this file.  Yes, it is misnamed.
-	 * We use this for detecting linearly ascending allocation requests.
-	 */
-	__u32	i_next_alloc_block;
-
-	/*
-	 * i_next_alloc_goal is the *physical* companion to i_next_alloc_block.
-	 * it the the physical block number of the block which was most-recently
-	 * allocated to this file.  This give us the goal (target) for the next
-	 * allocation when we detect linearly ascending requests.
-	 */
-	__u32	i_next_alloc_goal;
-	/* block reservation window */
-	struct ext3_reserve_window_node i_rsv_window;
+	/* block reservation info */
+	struct ext3_block_alloc_info *i_block_alloc_info;
 
 	__u32	i_dir_start_lookup;
 #ifdef CONFIG_EXT3_FS_XATTR
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -111,9 +111,9 @@ void ext3_journal_abort_handle(const cha
 
 static inline int
 __ext3_journal_get_undo_access(const char *where, handle_t *handle,
-				struct buffer_head *bh, int *credits)
+				struct buffer_head *bh)
 {
-	int err = journal_get_undo_access(handle, bh, credits);
+	int err = journal_get_undo_access(handle, bh);
 	if (err)
 		ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
 	return err;
@@ -121,19 +121,18 @@ __ext3_journal_get_undo_access(const cha
 
 static inline int
 __ext3_journal_get_write_access(const char *where, handle_t *handle,
-				struct buffer_head *bh, int *credits)
+				struct buffer_head *bh)
 {
-	int err = journal_get_write_access(handle, bh, credits);
+	int err = journal_get_write_access(handle, bh);
 	if (err)
 		ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
 	return err;
 }
 
 static inline void
-ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh,
-				int credits)
+ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
 {
-	journal_release_buffer(handle, bh, credits);
+	journal_release_buffer(handle, bh);
 }
 
 static inline int
@@ -176,12 +175,10 @@ __ext3_journal_dirty_metadata(const char
 }
 
 
-#define ext3_journal_get_undo_access(handle, bh, credits) \
-	__ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits))
+#define ext3_journal_get_undo_access(handle, bh) \
+	__ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
 #define ext3_journal_get_write_access(handle, bh) \
-	__ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL)
-#define ext3_journal_get_write_access_credits(handle, bh, credits) \
-	__ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits))
+	__ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
 #define ext3_journal_revoke(handle, blocknr, bh) \
 	__ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
 #define ext3_journal_get_create_access(handle, bh) \
diff --git a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -103,7 +103,10 @@
 #define FB_ACCEL_SIS_GLAMOUR_2  40	/* SiS 315, 650, 740		*/
 #define FB_ACCEL_SIS_XABRE      41	/* SiS 330 ("Xabre")		*/
 #define FB_ACCEL_I830           42      /* Intel 830M/845G/85x/865G     */
-
+#define FB_ACCEL_NV_10          43      /* nVidia Arch 10               */
+#define FB_ACCEL_NV_20          44      /* nVidia Arch 20               */
+#define FB_ACCEL_NV_30          45      /* nVidia Arch 30               */
+#define FB_ACCEL_NV_40          46      /* nVidia Arch 40               */
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92	/* NeoMagic NM2093              */
@@ -490,6 +493,8 @@ struct fb_cursor_user {
 #define FB_EVENT_SET_CONSOLE_MAP        0x07
 /*      A display blank is requested       */
 #define FB_EVENT_BLANK                  0x08
+/*      Private modelist is to be replaced */
+#define FB_EVENT_NEW_MODELIST           0x09
 
 struct fb_event {
 	struct fb_info *info;
@@ -558,6 +563,9 @@ struct fb_ops {
 	int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
 			    unsigned blue, unsigned transp, struct fb_info *info);
 
+	/* set color registers in batch */
+	int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
+
 	/* blank display */
 	int (*fb_blank)(int blank, struct fb_info *info);
 
@@ -585,7 +593,7 @@ struct fb_ops {
 			unsigned long arg, struct fb_info *info);
 
 	/* Handle 32bit compat ioctl (optional) */
-	int (*fb_compat_ioctl)(struct file *f, unsigned cmd, unsigned long arg,
+	long (*fb_compat_ioctl)(struct file *f, unsigned cmd, unsigned long arg,
 			       struct fb_info *info);
 
 	/* perform fb specific mmap */
@@ -697,9 +705,7 @@ struct fb_tile_ops {
 
 #define FBINFO_MISC_USEREVENT          0x10000 /* event request
 						  from userspace */
-#define FBINFO_MISC_MODESWITCH         0x20000 /* mode switch */
-#define FBINFO_MISC_MODESWITCHLATE     0x40000 /* init hardware later */
-#define FBINFO_MISC_TILEBLITTING       0x80000 /* use tile blitting */
+#define FBINFO_MISC_TILEBLITTING       0x20000 /* use tile blitting */
 
 struct fb_info {
 	int node;
@@ -712,8 +718,10 @@ struct fb_info {
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -821,8 +829,9 @@ extern void fb_sysmove_buf_aligned(struc
 				u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
 				u32 height);
 extern void fb_set_suspend(struct fb_info *info, int state);
-extern int fb_get_color_depth(struct fb_info *info);
+extern int fb_get_color_depth(struct fb_var_screeninfo *var);
 extern int fb_get_options(char *name, char **option);
+extern int fb_new_modelist(struct fb_info *info);
 
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
@@ -830,6 +839,8 @@ extern int num_registered_fb;
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0
@@ -854,10 +865,7 @@ extern int fb_get_mode(int flags, u32 va
 extern int fb_validate_mode(const struct fb_var_screeninfo *var,
 			    struct fb_info *info);
 extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var);
-extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
 extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs);
-extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
-extern struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize);
 extern void fb_destroy_modedb(struct fb_videomode *modedb);
 
 /* drivers/video/modedb.c */
@@ -875,6 +883,8 @@ extern struct fb_videomode *fb_match_mod
 					  struct list_head *head);
 extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
 					      struct list_head *head);
+extern struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+						 struct list_head *head);
 extern void fb_destroy_modelist(struct list_head *head);
 extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
 				     struct list_head *head);
diff --git a/include/linux/fcdevice.h b/include/linux/fcdevice.h
--- a/include/linux/fcdevice.h
+++ b/include/linux/fcdevice.h
@@ -27,8 +27,6 @@
 #include <linux/if_fc.h>
 
 #ifdef __KERNEL__
-extern unsigned short	fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
-
 extern struct net_device *alloc_fcdev(int sizeof_priv);
 #endif
 
diff --git a/include/linux/fddidevice.h b/include/linux/fddidevice.h
--- a/include/linux/fddidevice.h
+++ b/include/linux/fddidevice.h
@@ -10,7 +10,7 @@
  * Author:	Lawrence V. Stefani, <stefani@lkg.dec.com>
  *
  *		fddidevice.h is based on previous trdevice.h work by
- *			Ross Biro, <bir7@leland.Stanford.Edu>
+ *			Ross Biro
  *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *			Alan Cox, <gw4pts@gw4pts.ampr.org>
  *
diff --git a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -129,6 +129,7 @@ extern int dir_notify_enable;
 #define S_DIRSYNC	64	/* Directory modifications are synchronous */
 #define S_NOCMTIME	128	/* Do not update file c/mtime */
 #define S_SWAPFILE	256	/* Do not truncate: swapon got its bmaps */
+#define S_PRIVATE	512	/* Inode is fs-internal */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -162,6 +163,7 @@ extern int dir_notify_enable;
 #define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
 #define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
 #define IS_SWAPFILE(inode)	((inode)->i_flags & S_SWAPFILE)
+#define IS_PRIVATE(inode)	((inode)->i_flags & S_PRIVATE)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -210,7 +212,6 @@ extern int dir_notify_enable;
 #include <linux/list.h>
 #include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
-#include <linux/audit.h>
 #include <linux/init.h>
 
 #include <asm/atomic.h>
@@ -335,7 +336,7 @@ struct backing_dev_info;
 struct address_space {
 	struct inode		*host;		/* owner: inode, block_device */
 	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-	spinlock_t		tree_lock;	/* and spinlock protecting it */
+	rwlock_t		tree_lock;	/* and rwlock protecting it */
 	unsigned int		i_mmap_writable;/* count VM_SHARED mappings */
 	struct prio_tree_root	i_mmap;		/* tree of private and shared mappings */
 	struct list_head	i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
@@ -444,7 +445,6 @@ struct inode {
 	unsigned long		i_version;
 	unsigned long		i_blocks;
 	unsigned short          i_bytes;
-	unsigned char		i_sock;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct semaphore	i_sem;
 	struct rw_semaphore	i_alloc_sem;
@@ -647,6 +647,8 @@ struct lock_manager_operations {
 	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
 	void (*fl_release_private)(struct file_lock *);
 	void (*fl_break)(struct file_lock *);
+	int (*fl_mylease)(struct file_lock *, struct file_lock *);
+	int (*fl_change)(struct file_lock **, int);
 };
 
 /* that will die - we need it for nfs_lock_info */
@@ -713,7 +715,7 @@ extern int flock_lock_file_wait(struct f
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
 extern int setlease(struct file *, long, struct file_lock **);
-extern void remove_lease(struct file_lock *);
+extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
 extern void steal_locks(fl_owner_t from);
@@ -1051,83 +1053,87 @@ static inline void file_accessed(struct 
 int sync_inode(struct inode *inode, struct writeback_control *wbc);
 
 /**
- * &export_operations - for nfsd to communicate with file systems
- * decode_fh:      decode a file handle fragment and return a &struct dentry
- * encode_fh:      encode a file handle fragment from a dentry
- * get_name:       find the name for a given inode in a given directory
- * get_parent:     find the parent of a given directory
- * get_dentry:     find a dentry for the inode given a file handle sub-fragment
+ * struct export_operations - for nfsd to communicate with file systems
+ * @decode_fh:      decode a file handle fragment and return a &struct dentry
+ * @encode_fh:      encode a file handle fragment from a dentry
+ * @get_name:       find the name for a given inode in a given directory
+ * @get_parent:     find the parent of a given directory
+ * @get_dentry:     find a dentry for the inode given a file handle sub-fragment
  *
  * Description:
  *    The export_operations structure provides a means for nfsd to communicate
  *    with a particular exported file system  - particularly enabling nfsd and
  *    the filesystem to co-operate when dealing with file handles.
  *
- *    export_operations contains two basic operation for dealing with file handles,
- *    decode_fh() and encode_fh(), and allows for some other operations to be defined
- *    which standard helper routines use to get specific information from the
- *    filesystem.
+ *    export_operations contains two basic operation for dealing with file
+ *    handles, decode_fh() and encode_fh(), and allows for some other
+ *    operations to be defined which standard helper routines use to get
+ *    specific information from the filesystem.
  *
  *    nfsd encodes information use to determine which filesystem a filehandle
- *    applies to in the initial part of the file handle.  The remainder, termed a
- *    file handle fragment, is controlled completely by the filesystem.
- *    The standard helper routines assume that this fragment will contain one or two
- *    sub-fragments, one which identifies the file, and one which may be used to
- *    identify the (a) directory containing the file.
+ *    applies to in the initial part of the file handle.  The remainder, termed
+ *    a file handle fragment, is controlled completely by the filesystem.  The
+ *    standard helper routines assume that this fragment will contain one or
+ *    two sub-fragments, one which identifies the file, and one which may be
+ *    used to identify the (a) directory containing the file.
  *
  *    In some situations, nfsd needs to get a dentry which is connected into a
- *    specific part of the file tree.  To allow for this, it passes the function
- *    acceptable() together with a @context which can be used to see if the dentry
- *    is acceptable.  As there can be multiple dentrys for a given file, the filesystem
- *    should check each one for acceptability before looking for the next.  As soon
- *    as an acceptable one is found, it should be returned.
+ *    specific part of the file tree.  To allow for this, it passes the
+ *    function acceptable() together with a @context which can be used to see
+ *    if the dentry is acceptable.  As there can be multiple dentrys for a
+ *    given file, the filesystem should check each one for acceptability before
+ *    looking for the next.  As soon as an acceptable one is found, it should
+ *    be returned.
  *
  * decode_fh:
- *    @decode_fh is given a &struct super_block (@sb), a file handle fragment (@fh, @fh_len)
- *    and an acceptability testing function (@acceptable, @context).  It should return
- *    a &struct dentry which refers to the same file that the file handle fragment refers
- *    to,  and which passes the acceptability test.  If it cannot, it should return
- *    a %NULL pointer if the file was found but no acceptable &dentries were available, or
- *    a %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or %ENOMEM).
+ *    @decode_fh is given a &struct super_block (@sb), a file handle fragment
+ *    (@fh, @fh_len) and an acceptability testing function (@acceptable,
+ *    @context).  It should return a &struct dentry which refers to the same
+ *    file that the file handle fragment refers to,  and which passes the
+ *    acceptability test.  If it cannot, it should return a %NULL pointer if
+ *    the file was found but no acceptable &dentries were available, or a
+ *    %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or
+ *    %ENOMEM).
  *
  * encode_fh:
- *    @encode_fh should store in the file handle fragment @fh (using at most @max_len bytes)
- *    information that can be used by @decode_fh to recover the file refered to by the
- *    &struct dentry @de.  If the @connectable flag is set, the encode_fh() should store
- *    sufficient information so that a good attempt can be made to find not only
- *    the file but also it's place in the filesystem.   This typically means storing
- *    a reference to de->d_parent in the filehandle fragment.
- *    encode_fh() should return the number of bytes stored or a negative error code
- *    such as %-ENOSPC
+ *    @encode_fh should store in the file handle fragment @fh (using at most
+ *    @max_len bytes) information that can be used by @decode_fh to recover the
+ *    file refered to by the &struct dentry @de.  If the @connectable flag is
+ *    set, the encode_fh() should store sufficient information so that a good
+ *    attempt can be made to find not only the file but also it's place in the
+ *    filesystem.   This typically means storing a reference to de->d_parent in
+ *    the filehandle fragment.  encode_fh() should return the number of bytes
+ *    stored or a negative error code such as %-ENOSPC
  *
  * get_name:
- *    @get_name should find a name for the given @child in the given @parent directory.
- *    The name should be stored in the @name (with the understanding that it is already
- *    pointing to a a %NAME_MAX+1 sized buffer.   get_name() should return %0 on success,
- *    a negative error code or error.
- *    @get_name will be called without @parent->i_sem held.
+ *    @get_name should find a name for the given @child in the given @parent
+ *    directory.  The name should be stored in the @name (with the
+ *    understanding that it is already pointing to a a %NAME_MAX+1 sized
+ *    buffer.   get_name() should return %0 on success, a negative error code
+ *    or error.  @get_name will be called without @parent->i_sem held.
  *
  * get_parent:
- *    @get_parent should find the parent directory for the given @child which is also
- *    a directory.  In the event that it cannot be found, or storage space cannot be
- *    allocated, a %ERR_PTR should be returned.
+ *    @get_parent should find the parent directory for the given @child which
+ *    is also a directory.  In the event that it cannot be found, or storage
+ *    space cannot be allocated, a %ERR_PTR should be returned.
  *
  * get_dentry:
- *    Given a &super_block (@sb) and a pointer to a file-system specific inode identifier,
- *    possibly an inode number, (@inump) get_dentry() should find the identified inode and
- *    return a dentry for that inode.
- *    Any suitable dentry can be returned including, if necessary, a new dentry created
- *    with d_alloc_root.  The caller can then find any other extant dentrys by following the
- *    d_alias links.  If a new dentry was created using d_alloc_root, DCACHE_NFSD_DISCONNECTED
- *    should be set, and the dentry should be d_rehash()ed.
+ *    Given a &super_block (@sb) and a pointer to a file-system specific inode
+ *    identifier, possibly an inode number, (@inump) get_dentry() should find
+ *    the identified inode and return a dentry for that inode.  Any suitable
+ *    dentry can be returned including, if necessary, a new dentry created with
+ *    d_alloc_root.  The caller can then find any other extant dentrys by
+ *    following the d_alias links.  If a new dentry was created using
+ *    d_alloc_root, DCACHE_NFSD_DISCONNECTED should be set, and the dentry
+ *    should be d_rehash()ed.
  *
- *    If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code can be returned.
- *    The @inump will be whatever was passed to nfsd_find_fh_dentry() in either the
- *    @obj or @parent parameters.
+ *    If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code
+ *    can be returned.  The @inump will be whatever was passed to
+ *    nfsd_find_fh_dentry() in either the @obj or @parent parameters.
  *
  * Locking rules:
- *  get_parent is called with child->d_inode->i_sem down
- *  get_name is not (which is possibly inconsistent)
+ *    get_parent is called with child->d_inode->i_sem down
+ *    get_name is not (which is possibly inconsistent)
  */
 
 struct export_operations {
@@ -1268,13 +1274,7 @@ extern void __init vfs_caches_init(unsig
 #ifndef CONFIG_AUDITSYSCALL
 #define putname(name)   __putname(name)
 #else
-#define putname(name)							\
-	do {								\
-		if (unlikely(current->audit_context))			\
-			audit_putname(name);				\
-		else							\
-			__putname(name);				\
-	} while (0)
+extern void putname(const char *name);
 #endif
 
 extern int register_blkdev(unsigned int, const char *);
@@ -1341,7 +1341,7 @@ extern int fs_may_remount_ro(struct supe
 
 extern int check_disk_change(struct block_device *);
 extern int invalidate_inodes(struct super_block *);
-extern int __invalidate_device(struct block_device *, int);
+extern int __invalidate_device(struct block_device *);
 extern int invalidate_partition(struct gendisk *, int);
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
 					pgoff_t start, pgoff_t end);
@@ -1353,11 +1353,15 @@ static inline void invalidate_remote_ino
 		invalidate_inode_pages(inode->i_mapping);
 }
 extern int invalidate_inode_pages2(struct address_space *mapping);
+extern int invalidate_inode_pages2_range(struct address_space *mapping,
+					 pgoff_t start, pgoff_t end);
 extern int write_inode_now(struct inode *, int);
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_flush(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern int filemap_write_and_wait(struct address_space *mapping);
+extern int filemap_write_and_wait_range(struct address_space *mapping,
+				        loff_t lstart, loff_t lend);
 extern void sync_supers(void);
 extern void sync_filesystems(int wait);
 extern void emergency_sync(void);
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -10,19 +10,14 @@
  */
 
 #include <asm/io.h>
-#include <linux/input.h>
 #include <linux/list.h>
-
-struct gameport;
+#include <linux/device.h>
 
 struct gameport {
 
-	void *private;	/* Private pointer for joystick drivers */
-	void *driver;	/* Private pointer for gameport drivers */
-	char *name;
-	char *phys;
-
-	struct input_id id;
+	void *port_data;	/* Private pointer for gameport drivers */
+	char name[32];
+	char phys[32];
 
 	int io;
 	int speed;
@@ -35,36 +30,127 @@ struct gameport {
 	int (*open)(struct gameport *, int);
 	void (*close)(struct gameport *);
 
-	struct gameport_dev *dev;
+	struct timer_list poll_timer;
+	unsigned int poll_interval;	/* in msecs */
+	spinlock_t timer_lock;
+	unsigned int poll_cnt;
+	void (*poll_handler)(struct gameport *);
+
+	struct gameport *parent, *child;
+
+	struct gameport_driver *drv;
+	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
+
+	struct device dev;
+	unsigned int registered;	/* port has been fully registered with driver core */
 
 	struct list_head node;
 };
+#define to_gameport_port(d)	container_of(d, struct gameport, dev)
 
-struct gameport_dev {
+struct gameport_driver {
 
 	void *private;
-	char *name;
+	char *description;
 
-	void (*connect)(struct gameport *, struct gameport_dev *dev);
+	int (*connect)(struct gameport *, struct gameport_driver *drv);
+	int (*reconnect)(struct gameport *);
 	void (*disconnect)(struct gameport *);
 
-	struct list_head node;
+	struct device_driver driver;
+
+	unsigned int ignore;
 };
+#define to_gameport_driver(d)	container_of(d, struct gameport_driver, driver)
 
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode);
+int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode);
 void gameport_close(struct gameport *gameport);
 void gameport_rescan(struct gameport *gameport);
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
-void gameport_register_port(struct gameport *gameport);
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+
+void __gameport_register_port(struct gameport *gameport, struct module *owner);
+static inline void gameport_register_port(struct gameport *gameport)
+{
+	__gameport_register_port(gameport, THIS_MODULE);
+}
+
 void gameport_unregister_port(struct gameport *gameport);
+
+void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
 #else
-static inline void gameport_register_port(struct gameport *gameport) { return; }
-static inline void gameport_unregister_port(struct gameport *gameport) { return; }
+
+static inline void gameport_register_port(struct gameport *gameport)
+{
+	return;
+}
+
+static inline void gameport_unregister_port(struct gameport *gameport)
+{
+	return;
+}
+
+static inline void gameport_set_phys(struct gameport *gameport,
+				     const char *fmt, ...)
+{
+	return;
+}
+
 #endif
 
-void gameport_register_device(struct gameport_dev *dev);
-void gameport_unregister_device(struct gameport_dev *dev);
+static inline struct gameport *gameport_allocate_port(void)
+{
+	struct gameport *gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL);
+
+	return gameport;
+}
+
+static inline void gameport_free_port(struct gameport *gameport)
+{
+	kfree(gameport);
+}
+
+static inline void gameport_set_name(struct gameport *gameport, const char *name)
+{
+	strlcpy(gameport->name, name, sizeof(gameport->name));
+}
+
+/*
+ * Use the following fucntions to manipulate gameport's per-port
+ * driver-specific data.
+ */
+static inline void *gameport_get_drvdata(struct gameport *gameport)
+{
+	return dev_get_drvdata(&gameport->dev);
+}
+
+static inline void gameport_set_drvdata(struct gameport *gameport, void *data)
+{
+	dev_set_drvdata(&gameport->dev, data);
+}
+
+/*
+ * Use the following fucntions to pin gameport's driver in process context
+ */
+static inline int gameport_pin_driver(struct gameport *gameport)
+{
+	return down_interruptible(&gameport->drv_sem);
+}
+
+static inline void gameport_unpin_driver(struct gameport *gameport)
+{
+	up(&gameport->drv_sem);
+}
+
+void __gameport_register_driver(struct gameport_driver *drv, struct module *owner);
+static inline void gameport_register_driver(struct gameport_driver *drv)
+{
+	__gameport_register_driver(drv, THIS_MODULE);
+}
+
+void gameport_unregister_driver(struct gameport_driver *drv);
 
 #define GAMEPORT_MODE_DISABLED		0
 #define GAMEPORT_MODE_RAW		1
@@ -81,7 +167,7 @@ void gameport_unregister_device(struct g
 #define GAMEPORT_ID_VENDOR_GRAVIS	0x0009
 #define GAMEPORT_ID_VENDOR_GUILLEMOT	0x000a
 
-static __inline__ void gameport_trigger(struct gameport *gameport)
+static inline void gameport_trigger(struct gameport *gameport)
 {
 	if (gameport->trigger)
 		gameport->trigger(gameport);
@@ -89,7 +175,7 @@ static __inline__ void gameport_trigger(
 		outb(0xff, gameport->io);
 }
 
-static __inline__ unsigned char gameport_read(struct gameport *gameport)
+static inline unsigned char gameport_read(struct gameport *gameport)
 {
 	if (gameport->read)
 		return gameport->read(gameport);
@@ -97,7 +183,7 @@ static __inline__ unsigned char gameport
 		return inb(gameport->io);
 }
 
-static __inline__ int gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static inline int gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
 	if (gameport->cooked_read)
 		return gameport->cooked_read(gameport, axes, buttons);
@@ -105,7 +191,7 @@ static __inline__ int gameport_cooked_re
 		return -1;
 }
 
-static __inline__ int gameport_calibrate(struct gameport *gameport, int *axes, int *max)
+static inline int gameport_calibrate(struct gameport *gameport, int *axes, int *max)
 {
 	if (gameport->calibrate)
 		return gameport->calibrate(gameport, axes, max);
@@ -113,9 +199,22 @@ static __inline__ int gameport_calibrate
 		return -1;
 }
 
-static __inline__ int gameport_time(struct gameport *gameport, int time)
+static inline int gameport_time(struct gameport *gameport, int time)
 {
 	return (time * gameport->speed) / 1000;
 }
 
+static inline void gameport_set_poll_handler(struct gameport *gameport, void (*handler)(struct gameport *))
+{
+	gameport->poll_handler = handler;
+}
+
+static inline void gameport_set_poll_interval(struct gameport *gameport, unsigned int msecs)
+{
+	gameport->poll_interval = msecs;
+}
+
+void gameport_start_polling(struct gameport *gameport);
+void gameport_stop_polling(struct gameport *gameport);
+
 #endif
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -34,7 +34,7 @@ struct gs_port {
   int                     xmit_head;
   int                     xmit_tail;
   int                     xmit_cnt;
-  /*  struct semaphore        port_write_sem; */
+  struct semaphore        port_write_sem;
   int                     flags;
   wait_queue_head_t       open_wait;
   wait_queue_head_t       close_wait;
@@ -49,6 +49,7 @@ struct gs_port {
   int                     baud_base;
   int                     baud;
   int                     custom_divisor;
+  spinlock_t              driver_lock;
 };
 
 
@@ -70,6 +71,7 @@ struct gs_port {
 #define GS_DEBUG_STUFF   0x00000008
 #define GS_DEBUG_CLOSE   0x00000010
 #define GS_DEBUG_FLOW    0x00000020
+#define GS_DEBUG_WRITE   0x00000040
 
 
 void gs_put_char(struct tty_struct *tty, unsigned char ch);
@@ -91,6 +93,4 @@ int  gs_setserial(struct gs_port *port, 
 int  gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
 void gs_got_break(struct gs_port *port);
 
-extern int gs_debug;
-
 #endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -26,26 +26,28 @@ struct vm_area_struct;
  *
  * __GFP_NORETRY: The VM implementation must not retry indefinitely.
  */
-#define __GFP_WAIT	0x10	/* Can wait and reschedule? */
-#define __GFP_HIGH	0x20	/* Should access emergency pools? */
-#define __GFP_IO	0x40	/* Can start physical IO? */
-#define __GFP_FS	0x80	/* Can call down to low-level FS? */
-#define __GFP_COLD	0x100	/* Cache-cold page required */
-#define __GFP_NOWARN	0x200	/* Suppress page allocation failure warning */
-#define __GFP_REPEAT	0x400	/* Retry the allocation.  Might fail */
-#define __GFP_NOFAIL	0x800	/* Retry for ever.  Cannot fail */
-#define __GFP_NORETRY	0x1000	/* Do not retry.  Might fail */
-#define __GFP_NO_GROW	0x2000	/* Slab internal usage */
-#define __GFP_COMP	0x4000	/* Add compound page metadata */
-#define __GFP_ZERO	0x8000	/* Return zeroed page on success */
+#define __GFP_WAIT	0x10u	/* Can wait and reschedule? */
+#define __GFP_HIGH	0x20u	/* Should access emergency pools? */
+#define __GFP_IO	0x40u	/* Can start physical IO? */
+#define __GFP_FS	0x80u	/* Can call down to low-level FS? */
+#define __GFP_COLD	0x100u	/* Cache-cold page required */
+#define __GFP_NOWARN	0x200u	/* Suppress page allocation failure warning */
+#define __GFP_REPEAT	0x400u	/* Retry the allocation.  Might fail */
+#define __GFP_NOFAIL	0x800u	/* Retry for ever.  Cannot fail */
+#define __GFP_NORETRY	0x1000u	/* Do not retry.  Might fail */
+#define __GFP_NO_GROW	0x2000u	/* Slab internal usage */
+#define __GFP_COMP	0x4000u	/* Add compound page metadata */
+#define __GFP_ZERO	0x8000u	/* Return zeroed page on success */
+#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
 
-#define __GFP_BITS_SHIFT 16	/* Room for 16 __GFP_FOO bits */
+#define __GFP_BITS_SHIFT 20	/* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
 
 /* if you forget to add the bitmask here kernel will crash, period */
 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
 			__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
-			__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP)
+			__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
+			__GFP_NOMEMALLOC)
 
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_NOIO	(__GFP_WAIT)
@@ -82,7 +84,7 @@ static inline void arch_free_page(struct
 extern struct page *
 FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *));
 
-static inline struct page *alloc_pages_node(int nid, unsigned int gfp_mask,
+static inline struct page *alloc_pages_node(int nid, unsigned int __nocast gfp_mask,
 						unsigned int order)
 {
 	if (unlikely(order >= MAX_ORDER))
@@ -93,17 +95,17 @@ static inline struct page *alloc_pages_n
 }
 
 #ifdef CONFIG_NUMA
-extern struct page *alloc_pages_current(unsigned gfp_mask, unsigned order);
+extern struct page *alloc_pages_current(unsigned int __nocast gfp_mask, unsigned order);
 
 static inline struct page *
-alloc_pages(unsigned int gfp_mask, unsigned int order)
+alloc_pages(unsigned int __nocast gfp_mask, unsigned int order)
 {
 	if (unlikely(order >= MAX_ORDER))
 		return NULL;
 
 	return alloc_pages_current(gfp_mask, order);
 }
-extern struct page *alloc_page_vma(unsigned gfp_mask,
+extern struct page *alloc_page_vma(unsigned __nocast gfp_mask,
 			struct vm_area_struct *vma, unsigned long addr);
 #else
 #define alloc_pages(gfp_mask, order) \
@@ -112,8 +114,8 @@ extern struct page *alloc_page_vma(unsig
 #endif
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
 
-extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order));
-extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask));
+extern unsigned long FASTCALL(__get_free_pages(unsigned int __nocast gfp_mask, unsigned int order));
+extern unsigned long FASTCALL(get_zeroed_page(unsigned int __nocast gfp_mask));
 
 #define __get_free_page(gfp_mask) \
 		__get_free_pages((gfp_mask),0)
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -43,13 +43,17 @@
 #define __IRQ_MASK(x)	((1UL << (x))-1)
 
 #define PREEMPT_MASK	(__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
-#define HARDIRQ_MASK	(__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
 #define SOFTIRQ_MASK	(__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+#define HARDIRQ_MASK	(__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
 
 #define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
 #define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
 #define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
 
+#if PREEMPT_ACTIVE < (1 << (HARDIRQ_SHIFT + HARDIRQ_BITS))
+#error PREEMPT_ACTIVE is too low!
+#endif
+
 #define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
 #define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
 #define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h
--- a/include/linux/hayesesp.h
+++ b/include/linux/hayesesp.h
@@ -77,6 +77,7 @@ struct hayes_esp_config {
 
 struct esp_struct {
 	int			magic;
+	spinlock_t		lock;
 	int			port;
 	int			irq;
 	int			flags; 		/* defined in tty.h */
diff --git a/include/linux/hdpu_features.h b/include/linux/hdpu_features.h
new file mode 100644
--- /dev/null
+++ b/include/linux/hdpu_features.h
@@ -0,0 +1,26 @@
+#include <linux/spinlock.h>
+
+struct cpustate_t {
+	spinlock_t lock;
+	int excl;
+        int open_count;
+	unsigned char cached_val;
+	int inited;
+	unsigned long *set_addr;
+	unsigned long *clr_addr;
+};
+
+
+#define HDPU_CPUSTATE_NAME "hdpu cpustate"
+#define HDPU_NEXUS_NAME "hdpu nexus"
+
+#define CPUSTATE_KERNEL_MAJOR  0x10
+
+#define CPUSTATE_KERNEL_INIT_DRV   0 /* CPU State Driver Initialized */
+#define CPUSTATE_KERNEL_INIT_PCI   1 /* 64360 PCI Busses Init */
+#define CPUSTATE_KERNEL_INIT_REG   2 /* 64360 Bridge Init */
+#define CPUSTATE_KERNEL_CPU1_KICK  3 /* Boot cpu 1 */
+#define CPUSTATE_KERNEL_CPU1_OK    4  /* Cpu 1 has checked in */
+#define CPUSTATE_KERNEL_OK         5 /* Terminal state */
+#define CPUSTATE_KERNEL_RESET   14 /* Board reset via SW*/
+#define CPUSTATE_KERNEL_HALT   15 /* Board halted via SW*/
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -201,8 +201,8 @@ struct hiddev_usage_ref_multi {
  *		ioctl(fd, HIDIOCGUSAGE, &uref);
  *          }
  *	}
- *	uref.report_id |= HID_REPORT_ID_NEXT;
- *	ret = ioctl(fd, HIDIOCGREPORTINFO, &uref);
+ *	rinfo.report_id |= HID_REPORT_ID_NEXT;
+ *	ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
  *  }
  */
 
diff --git a/include/linux/hippidevice.h b/include/linux/hippidevice.h
--- a/include/linux/hippidevice.h
+++ b/include/linux/hippidevice.h
@@ -10,7 +10,7 @@
  * Author:	Jes Sorensen, <Jes.Sorensen@cern.ch>
  *
  *		hippidevice.h is based on previous fddidevice.h work by
- *			Ross Biro, <bir7@leland.Stanford.Edu>
+ *			Ross Biro
  *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *			Alan Cox, <gw4pts@gw4pts.ampr.org>
  *			Lawrence V. Stefani, <stefani@lkg.dec.com>
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -36,8 +36,9 @@ extern const unsigned long hugetlb_zero,
 extern int sysctl_hugetlb_shm_group;
 
 #ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define is_hugepage_only_range(addr, len)	0
-#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
+#define is_hugepage_only_range(mm, addr, len)	0
+#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \
+						do { } while (0)
 #endif
 
 #ifndef ARCH_HAS_PREPARE_HUGEPAGE_RANGE
@@ -71,8 +72,9 @@ static inline unsigned long hugetlb_tota
 #define is_aligned_hugepage_range(addr, len)	0
 #define prepare_hugepage_range(addr, len)	(-EINVAL)
 #define pmd_huge(x)	0
-#define is_hugepage_only_range(addr, len)	0
-#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
+#define is_hugepage_only_range(mm, addr, len)	0
+#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \
+						do { } while (0)
 #define alloc_huge_page()			({ NULL; })
 #define free_huge_page(p)			({ (void)(p); BUG(); })
 
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -20,8 +20,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */
 
-/* $Id: i2c-id.h,v 1.68 2003/02/25 02:55:18 mds Exp $ */
-
 #ifndef LINUX_I2C_ID_H
 #define LINUX_I2C_ID_H
 
@@ -196,11 +194,15 @@
 #define I2C_ALGO_OCP    0x120000	/* IBM or otherwise On-chip I2C algorithm */
 #define I2C_ALGO_BITHS	0x130000	/* enhanced bit style adapters	*/
 #define I2C_ALGO_IOP3XX	0x140000	/* XSCALE IOP3XX On-chip I2C alg */
-#define I2C_ALGO_PCA	0x150000	/* PCA 9564 style adapters	*/
-
 #define I2C_ALGO_SIBYTE 0x150000	/* Broadcom SiByte SOCs		*/
-#define I2C_ALGO_SGI	0x160000        /* SGI algorithm                */
-#define I2C_ALGO_AU1550	0x170000        /* Au1550 PSC algorithm		*/
+#define I2C_ALGO_SGI	0x160000	/* SGI algorithm		*/
+
+#define I2C_ALGO_USB	0x170000	/* USB algorithm		*/
+#define I2C_ALGO_VIRT	0x180000	/* Virtual bus adapter		*/
+
+#define I2C_ALGO_MV64XXX 0x190000	/* Marvell mv64xxx i2c ctlr	*/
+#define I2C_ALGO_PCA	0x1a0000	/* PCA 9564 style adapters	*/
+#define I2C_ALGO_AU1550	0x1b0000        /* Au1550 PSC algorithm		*/
 
 #define I2C_ALGO_EXP	0x800000	/* experimental			*/
 
@@ -240,6 +242,7 @@
 #define I2C_HW_B_IXP4XX 0x17	/* GPIO on IXP4XX systems		*/
 #define I2C_HW_B_S3VIA	0x18	/* S3Via ProSavage adapter		*/
 #define I2C_HW_B_ZR36067 0x19	/* Zoran-36057/36067 based boards	*/
+#define I2C_HW_B_PCILYNX 0x1a	/* TI PCILynx I2C adapter		*/
 #define I2C_HW_B_CX2388x 0x1b	/* connexant 2388x based tv cards	*/
 
 /* --- PCF 8584 based algorithms					*/
@@ -310,4 +313,7 @@
 /* --- MCP107 adapter */
 #define I2C_HW_MPC107 0x00
 
+/* --- Marvell mv64xxx i2c adapter */
+#define I2C_HW_MV64XXX 0x00
+
 #endif /* LINUX_I2C_ID_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -55,7 +55,7 @@ extern int i2c_master_recv(struct i2c_cl
 
 /* Transfer num messages.
  */
-extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
 
 /*
  * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. 
@@ -134,8 +134,6 @@ struct i2c_driver {
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
-extern struct bus_type i2c_bus_type;
-
 #define I2C_NAME_SIZE	50
 
 /*
@@ -144,7 +142,6 @@ extern struct bus_type i2c_bus_type;
  * function is mainly used for lookup & other admin. functions.
  */
 struct i2c_client {
-	int id;
 	unsigned int flags;		/* div., see below		*/
 	unsigned int addr;		/* chip address - NOTE: 7bit 	*/
 					/* addresses are stored in the	*/
@@ -190,11 +187,11 @@ struct i2c_algorithm {
 	char name[32];				/* textual description 	*/
 	unsigned int id;
 
-	/* If an adapter algorithm can't to I2C-level access, set master_xfer
+	/* If an adapter algorithm can't do I2C-level access, set master_xfer
 	   to NULL. If an adapter algorithm can do SMBus access, set 
 	   smbus_xfer. If set to NULL, the SMBus protocol is simulated
 	   using common I2C messages */
-	int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], 
+	int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, 
 	                   int num);
 	int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 
 	                   unsigned short flags, char read_write,
@@ -302,16 +299,13 @@ struct i2c_client_address_data {
 };
 
 /* Internal numbers to terminate lists */
-#define I2C_CLIENT_END		0xfffe
-#define I2C_CLIENT_ISA_END	0xfffefffe
+#define I2C_CLIENT_END		0xfffeU
+#define I2C_CLIENT_ISA_END	0xfffefffeU
 
 /* The numbers to use to set I2C bus address */
 #define ANY_I2C_BUS		0xffff
 #define ANY_I2C_ISA_BUS		9191
 
-/* The length of the option lists */
-#define I2C_CLIENT_MAX_OPTS 48
-
 
 /* ----- functions exported by i2c.o */
 
@@ -374,10 +368,16 @@ extern void i2c_put_adapter(struct i2c_a
 
 
 /* Return the functionality mask */
-extern u32 i2c_get_functionality (struct i2c_adapter *adap);
+static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
+{
+	return adap->algo->functionality(adap);
+}
 
 /* Return 1 if adapter supports everything we need, 0 if not. */
-extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func);
+static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
+{
+	return (func & i2c_get_functionality(adap)) == func;
+}
 
 /*
  * I2C Message - used for pure i2c transaction, also from /dev interface
@@ -423,22 +423,22 @@ struct i2c_msg {
 #define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC  0x40000000 /* SMBus 2.0 */
 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
 
-#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
-                            I2C_FUNC_SMBUS_WRITE_BYTE
-#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \
-                                 I2C_FUNC_SMBUS_WRITE_BYTE_DATA
-#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \
-                                 I2C_FUNC_SMBUS_WRITE_WORD_DATA
-#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
-                                  I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
-#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
-                                  I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
-                                   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
-#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
-                                      I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
-#define I2C_FUNC_SMBUS_WORD_DATA_PEC  I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
-                                      I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
+#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
+                             I2C_FUNC_SMBUS_WRITE_BYTE)
+#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
+                                  I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
+#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
+                                  I2C_FUNC_SMBUS_WRITE_WORD_DATA)
+#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
+                                   I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
+#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
+                                  I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
+#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
+                                    I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2)
+#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
+                                       I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC)
+#define I2C_FUNC_SMBUS_WORD_DATA_PEC  (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
+                                       I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC)
 
 #define I2C_FUNC_SMBUS_READ_BYTE_PEC		I2C_FUNC_SMBUS_READ_BYTE_DATA
 #define I2C_FUNC_SMBUS_WRITE_BYTE_PEC		I2C_FUNC_SMBUS_WRITE_BYTE_DATA
@@ -447,14 +447,14 @@ struct i2c_msg {
 #define I2C_FUNC_SMBUS_BYTE_PEC			I2C_FUNC_SMBUS_BYTE_DATA
 #define I2C_FUNC_SMBUS_BYTE_DATA_PEC		I2C_FUNC_SMBUS_WORD_DATA
 
-#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
-                            I2C_FUNC_SMBUS_BYTE | \
-                            I2C_FUNC_SMBUS_BYTE_DATA | \
-                            I2C_FUNC_SMBUS_WORD_DATA | \
-                            I2C_FUNC_SMBUS_PROC_CALL | \
-                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
-                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
-                            I2C_FUNC_SMBUS_I2C_BLOCK
+#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \
+                             I2C_FUNC_SMBUS_BYTE | \
+                             I2C_FUNC_SMBUS_BYTE_DATA | \
+                             I2C_FUNC_SMBUS_WORD_DATA | \
+                             I2C_FUNC_SMBUS_PROC_CALL | \
+                             I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
+                             I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
+                             I2C_FUNC_SMBUS_I2C_BLOCK)
 
 /* 
  * Data for SMBus Messages 
@@ -529,6 +529,9 @@ union i2c_smbus_data {
 #define I2C_MAJOR	89		/* Device major number		*/
 
 /* These defines are used for probing i2c client addresses */
+/* The length of the option lists */
+#define I2C_CLIENT_MAX_OPTS 48
+
 /* Default fill of many variables */
 #define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
@@ -547,19 +550,12 @@ union i2c_smbus_data {
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END}
 
-/* This is ugly. We need to evaluate I2C_CLIENT_MAX_OPTS before it is 
-   stringified */
-#define I2C_CLIENT_MODPARM_AUX1(x) "1-" #x "h"
-#define I2C_CLIENT_MODPARM_AUX(x) I2C_CLIENT_MODPARM_AUX1(x)
-#define I2C_CLIENT_MODPARM I2C_CLIENT_MODPARM_AUX(I2C_CLIENT_MAX_OPTS)
-
 /* I2C_CLIENT_MODULE_PARM creates a module parameter, and puts it in the
    module header */
 
 #define I2C_CLIENT_MODULE_PARM(var,desc) \
   static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; \
   static unsigned int var##_num; \
-  /*MODULE_PARM(var,I2C_CLIENT_MODPARM);*/ \
   module_param_array(var, short, &var##_num, 0); \
   MODULE_PARM_DESC(var,desc)
 
diff --git a/include/linux/ibmtr.h b/include/linux/ibmtr.h
--- a/include/linux/ibmtr.h
+++ b/include/linux/ibmtr.h
@@ -169,7 +169,7 @@ typedef enum {	CLOSED,	OPEN } open_state
 
 struct tok_info {
 	unsigned char irq;
-	void *mmio;
+	void __iomem *mmio;
 	unsigned char hw_address[32];
 	unsigned char adapter_type;
 	unsigned char data_rate;
@@ -192,12 +192,13 @@ struct tok_info {
 	/* Additions by Peter De Schrijver */
 	unsigned char page_mask;          /* mask to select RAM page to Map*/
 	unsigned char mapped_ram_size;    /* size of RAM page */
-	__u32 sram_virt;                  /* Shared memory base address */
-	__u32 init_srb;               /* Initial System Request Block address */
-	__u32 srb;                        /* System Request Block address */
-	__u32 ssb;                        /* System Status Block address */
-	__u32 arb;                        /* Adapter Request Block address */
-	__u32 asb;                        /* Adapter Status Block address */
+	__u32 sram_phys;          /* Shared memory base address */
+	void __iomem *sram_virt;          /* Shared memory base address */
+	void __iomem *init_srb;   /* Initial System Request Block address */
+	void __iomem *srb;                /* System Request Block address */
+	void __iomem *ssb;                /* System Status Block address */
+	void __iomem *arb;                /* Adapter Request Block address */
+	void __iomem *asb;                /* Adapter Status Block address */
         __u8  init_srb_page;
         __u8  srb_page;
         __u8  ssb_page;
diff --git a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -664,7 +664,6 @@ typedef struct ide_drive_s {
 
 	struct request		*rq;	/* current request */
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
-	struct ide_driver_s	*driver;/* (ide_driver_t *) */
 	void		*driver_data;	/* extra driver data */
 	struct hd_driveid	*id;	/* drive model identification info */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
@@ -718,6 +717,7 @@ typedef struct ide_drive_s {
 					 */
 	unsigned scsi		: 1;	/* 0=default, 1=ide-scsi emulation */
 	unsigned sleeping	: 1;	/* 1=sleeping & sleep field valid */
+	unsigned post_reset	: 1;
 
         u8	quirk_list;	/* considered quirky, set for a specific host */
         u8	init_speed;	/* transfer rate set at boot */
@@ -740,7 +740,6 @@ typedef struct ide_drive_s {
 	u8	sect;		/* "real" sectors per track */
 	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
 	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
-	u8	doing_barrier;	/* state, 1=currently doing flush */
 
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
@@ -756,9 +755,10 @@ typedef struct ide_drive_s {
 	struct list_head list;
 	struct device	gendev;
 	struct semaphore gendev_rel_sem;	/* to deal with device release() */
-	struct gendisk *disk;
 } ide_drive_t;
 
+#define to_ide_device(dev)container_of(dev, ide_drive_t, gendev)
+
 #define IDE_CHIPSET_PCI_MASK	\
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
@@ -1087,34 +1087,21 @@ enum {
  */
 typedef struct ide_driver_s {
 	struct module			*owner;
-	const char			*name;
 	const char			*version;
 	u8				media;
-	unsigned busy			: 1;
 	unsigned supports_dsc_overlap	: 1;
-	int		(*cleanup)(ide_drive_t *);
 	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, sector_t);
 	int		(*end_request)(ide_drive_t *, int, int);
 	ide_startstop_t	(*error)(ide_drive_t *, struct request *rq, u8, u8);
 	ide_startstop_t	(*abort)(ide_drive_t *, struct request *rq);
 	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-	void		(*pre_reset)(ide_drive_t *);
-	sector_t	(*capacity)(ide_drive_t *);
-	ide_startstop_t	(*special)(ide_drive_t *);
 	ide_proc_entry_t	*proc;
-	int		(*attach)(ide_drive_t *);
 	void		(*ata_prebuilder)(ide_drive_t *);
 	void		(*atapi_prebuilder)(ide_drive_t *);
-	ide_startstop_t	(*start_power_step)(ide_drive_t *, struct request *);
-	void		(*complete_power_step)(ide_drive_t *, struct request *, u8, u8);
 	struct device_driver	gen_driver;
-	struct list_head drives;
-	struct list_head drivers;
 } ide_driver_t;
 
-#define DRIVER(drive)		((drive)->driver)
-
-extern int generic_ide_ioctl(struct file *, struct block_device *, unsigned, unsigned long);
+int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
 
 /*
  * ide_hwifs[] is the master data structure used to keep track
@@ -1130,6 +1117,7 @@ extern	ide_hwif_t	ide_hwifs[];		/* maste
 extern int noautodma;
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
+extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
@@ -1331,9 +1319,7 @@ extern irqreturn_t ide_intr(int irq, voi
 extern void do_ide_request(request_queue_t *);
 extern void ide_init_subdrivers(void);
 
-extern struct block_device_operations ide_fops[];
-
-extern int ata_attach(ide_drive_t *);
+void ide_init_disk(struct gendisk *, ide_drive_t *);
 
 extern int ideprobe_init(void);
 
@@ -1347,11 +1333,8 @@ extern void default_hwif_iops(ide_hwif_t
 extern void default_hwif_mmiops(ide_hwif_t *);
 extern void default_hwif_transport(ide_hwif_t *);
 
-int ide_register_driver(ide_driver_t *driver);
-void ide_unregister_driver(ide_driver_t *driver);
-int ide_register_subdriver(ide_drive_t *, ide_driver_t *);
-int ide_unregister_subdriver (ide_drive_t *drive);
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+void ide_register_subdriver(ide_drive_t *, ide_driver_t *);
+void ide_unregister_subdriver(ide_drive_t *, ide_driver_t *);
 
 #define ON_BOARD		1
 #define NEVER_BOARD		0
@@ -1446,6 +1429,9 @@ extern int ide_hwif_request_regions(ide_
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
 extern void ide_unregister (unsigned int index);
 
+void ide_register_region(struct gendisk *);
+void ide_unregister_region(struct gendisk *);
+
 void ide_undecoded_slave(ide_hwif_t *);
 
 int probe_hwif_init_with_fixup(ide_hwif_t *, void (*)(ide_hwif_t *));
diff --git a/include/linux/if.h b/include/linux/if.h
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -8,7 +8,7 @@
  * Version:	@(#)if.h	1.0.2	04/18/93
  *
  * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
- *		Ross Biro, <bir7@leland.Stanford.Edu>
+ *		Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -9,7 +9,7 @@
  *
  * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
  *		Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
- *		Ross Biro, <bir7@leland.Stanford.Edu>
+ *		Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Florian La Roche,
  *		Jonathan Layes <layes@loran.com>
diff --git a/include/linux/if_ec.h b/include/linux/if_ec.h
--- a/include/linux/if_ec.h
+++ b/include/linux/if_ec.h
@@ -47,8 +47,9 @@ struct ec_framehdr 
   unsigned char port;
 };
 
-struct econet_opt
-{
+struct econet_sock {
+  /* struct sock has to be the first member of econet_sock */
+  struct sock	sk;
   unsigned char cb;
   unsigned char port;
   unsigned char station;
@@ -56,7 +57,10 @@ struct econet_opt
   unsigned short num;
 };
 
-#define ec_sk(__sk) ((struct econet_opt *)(__sk)->sk_protinfo)
+static inline struct econet_sock *ec_sk(const struct sock *sk)
+{
+	return (struct econet_sock *)sk;
+}
 
 struct ec_device
 {
diff --git a/include/linux/if_ltalk.h b/include/linux/if_ltalk.h
--- a/include/linux/if_ltalk.h
+++ b/include/linux/if_ltalk.h
@@ -6,7 +6,7 @@
 #define LTALK_ALEN		1
 
 #ifdef __KERNEL__
-extern void ltalk_setup(struct net_device *);
+extern struct net_device *alloc_ltalkdev(int sizeof_priv);
 #endif
 
 #endif
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -119,10 +119,13 @@ struct pppoe_opt {
 					     relayed to (PPPoE relaying) */
 };
 
-struct pppox_opt {
+#include <net/sock.h>
+
+struct pppox_sock {
+	/* struct sock must be the first member of pppox_sock */
+	struct sock		sk;
 	struct ppp_channel	chan;
-	struct sock		*sk;
-	struct pppox_opt	*next;	  /* for hash table */
+	struct pppox_sock	*next;	  /* for hash table */
 	union {
 		struct pppoe_opt pppoe;
 	} proto;
@@ -132,7 +135,15 @@ struct pppox_opt {
 #define pppoe_pa	proto.pppoe.pa
 #define pppoe_relay	proto.pppoe.relay
 
-#define pppox_sk(__sk) ((struct pppox_opt *)(__sk)->sk_protinfo)
+static inline struct pppox_sock *pppox_sk(struct sock *sk)
+{
+	return (struct pppox_sock *)sk;
+}
+
+static inline struct sock *sk_pppox(struct pppox_sock *po)
+{
+	return (struct sock *)po;
+}
 
 struct module;
 
diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h
--- a/include/linux/if_shaper.h
+++ b/include/linux/if_shaper.h
@@ -23,7 +23,7 @@ struct shaper
 	__u32 shapeclock;
 	unsigned long recovery;	/* Time we can next clock a packet out on
 				   an empty queue */
-        unsigned long locked;
+	struct semaphore sem;
         struct net_device_stats stats;
 	struct net_device *dev;
 	int  (*hard_start_xmit) (struct sk_buff *skb,
@@ -38,7 +38,6 @@ struct shaper
 	int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh);
 	void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char *  haddr);
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
-	wait_queue_head_t  wait_queue;
 	struct timer_list timer;
 };
 
diff --git a/include/linux/if_tr.h b/include/linux/if_tr.h
--- a/include/linux/if_tr.h
+++ b/include/linux/if_tr.h
@@ -9,7 +9,7 @@
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *    Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ *		Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -19,24 +19,18 @@
 #ifndef _LINUX_IF_TR_H
 #define _LINUX_IF_TR_H
 
+#include <asm/byteorder.h>	/* For __be16 */
 
 /* IEEE 802.5 Token-Ring magic constants.  The frame sizes omit the preamble
    and FCS/CRC (frame check sequence). */
-#define TR_ALEN	6		/* Octets in one ethernet addr	 */
-#define TR_HLEN   (sizeof(struct trh_hdr)+sizeof(struct trllc))
-#define AC			0x10
-#define LLC_FRAME 0x40
-#if 0
-#define ETH_HLEN	14		/* Total octets in header.	 */
-#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
-#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
-#endif
-
+#define TR_ALEN		6		/* Octets in one token-ring addr */
+#define TR_HLEN 	(sizeof(struct trh_hdr)+sizeof(struct trllc))
+#define AC		0x10
+#define LLC_FRAME 	0x40
 
 /* LLC and SNAP constants */
-#define EXTENDED_SAP 0xAA
-#define UI_CMD       0x03
+#define EXTENDED_SAP 	0xAA
+#define UI_CMD       	0x03
 
 /* This is an Token-Ring frame header. */
 struct trh_hdr {
@@ -44,8 +38,8 @@ struct trh_hdr {
 	__u8  fc;			/* frame control field */
 	__u8  daddr[TR_ALEN];		/* destination address */
 	__u8  saddr[TR_ALEN];		/* source address */
-	__u16 rcf;			/* route control field */
-	__u16 rseg[8];			/* routing registers */
+	__be16 rcf;			/* route control field */
+	__be16 rseg[8];			/* routing registers */
 };
 
 #ifdef __KERNEL__
@@ -63,7 +57,7 @@ struct trllc {
 	__u8  ssap;			/* source SAP */
 	__u8  llc;			/* LLC control field */
 	__u8  protid[3];		/* protocol id */
-	__u16 ethertype;		/* ether type field */
+	__be16 ethertype;		/* ether type field */
 };
 
 /* Token-Ring statistics collection data. */
@@ -96,14 +90,13 @@ struct tr_statistics {
 };
 
 /* source routing stuff */
-
-#define TR_RII 0x80
-#define TR_RCF_DIR_BIT 0x80
-#define TR_RCF_LEN_MASK 0x1f00
-#define TR_RCF_BROADCAST 0x8000         /* all-routes broadcast */
-#define TR_RCF_LIMITED_BROADCAST 0xC000 /* single-route broadcast */
-#define TR_RCF_FRAME2K 0x20
-#define TR_RCF_BROADCAST_MASK 0xC000
-#define TR_MAXRIFLEN 18
+#define TR_RII 			0x80
+#define TR_RCF_DIR_BIT 		0x80
+#define TR_RCF_LEN_MASK 	0x1f00
+#define TR_RCF_BROADCAST 	0x8000	/* all-routes broadcast */
+#define TR_RCF_LIMITED_BROADCAST 0xC000	/* single-route broadcast */
+#define TR_RCF_FRAME2K 		0x20
+#define TR_RCF_BROADCAST_MASK 	0xC000
+#define TR_MAXRIFLEN 		18
 
 #endif	/* _LINUX_IF_TR_H */
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -29,6 +29,7 @@ struct ipv4_devconf
 	int	no_xfrm;
 	int	no_policy;
 	int	force_igmp_version;
+	int	promote_secondaries;
 	void	*sysctl;
 };
 
@@ -71,6 +72,7 @@ struct in_device
 #define IN_DEV_SEC_REDIRECTS(in_dev)	(ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
 #define IN_DEV_IDTAG(in_dev)		((in_dev)->cnf.tag)
 #define IN_DEV_MEDIUM_ID(in_dev)	((in_dev)->cnf.medium_id)
+#define IN_DEV_PROMOTE_SECONDARIES(in_dev)	(ipv4_devconf.promote_secondaries || (in_dev)->cnf.promote_secondaries)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -51,6 +51,7 @@
 		.list = LIST_HEAD_INIT(sig.shared_pending.list),	\
 		.signal =  {{0}}}, \
 	.posix_timers	 = LIST_HEAD_INIT(sig.posix_timers),		\
+	.cpu_timers	= INIT_CPU_TIMERS(sig.cpu_timers),		\
 	.rlim		= INIT_RLIMITS,					\
 }
 
@@ -89,9 +90,6 @@ extern struct group_info init_groups;
 	.children	= LIST_HEAD_INIT(tsk.children),			\
 	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
 	.group_leader	= &tsk,						\
-	.real_timer	= {						\
-		.function	= it_real_fn				\
-	},								\
 	.group_info	= &init_groups,					\
 	.cap_effective	= CAP_INIT_EFF_SET,				\
 	.cap_inheritable = CAP_INIT_INH_SET,				\
@@ -112,8 +110,16 @@ extern struct group_info init_groups;
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
 }
 
 
+#define INIT_CPU_TIMERS(cpu_timers)					\
+{									\
+	LIST_HEAD_INIT(cpu_timers[0]),					\
+	LIST_HEAD_INIT(cpu_timers[1]),					\
+	LIST_HEAD_INIT(cpu_timers[2]),					\
+}
+
 
 #endif
diff --git a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -328,6 +328,11 @@ struct input_absinfo {
 #define KEY_BRIGHTNESSUP	225
 #define KEY_MEDIA		226
 
+#define KEY_SWITCHVIDEOMODE	227
+#define KEY_KBDILLUMTOGGLE	228
+#define KEY_KBDILLUMDOWN	229
+#define KEY_KBDILLUMUP		230
+
 #define KEY_UNKNOWN		240
 
 #define BTN_MISC		0x100
@@ -771,7 +776,7 @@ struct ff_effect {
 #include <linux/fs.h>
 #include <linux/timer.h>
 
-#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define NBITS(x) (((x)/BITS_PER_LONG)+1)
 #define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
diff --git a/include/linux/ioc4_common.h b/include/linux/ioc4_common.h
new file mode 100644
--- /dev/null
+++ b/include/linux/ioc4_common.h
@@ -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) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#ifndef _LINUX_IOC4_COMMON_H
+#define _LINUX_IOC4_COMMON_H
+
+/* prototypes */
+
+int ioc4_serial_init(void);
+
+int ioc4_serial_attach_one(struct pci_dev *pdev, const struct
+				pci_device_id *pci_id);
+int ioc4_ide_attach_one(struct pci_dev *pdev, const struct
+				pci_device_id *pci_id);
+
+#endif	/* _LINUX_IOC4_COMMON_H */
diff --git a/include/linux/ioctl32.h b/include/linux/ioctl32.h
--- a/include/linux/ioctl32.h
+++ b/include/linux/ioctl32.h
@@ -1,6 +1,8 @@
 #ifndef IOCTL32_H
 #define IOCTL32_H 1
 
+#include <linux/compiler.h>	/* for __deprecated */
+
 struct file;
 
 typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
@@ -23,9 +25,9 @@ struct ioctl_trans {
  */ 
 
 #ifdef CONFIG_COMPAT
-extern int register_ioctl32_conversion(unsigned int cmd,
+extern int __deprecated register_ioctl32_conversion(unsigned int cmd,
 				ioctl_trans_handler_t handler);
-extern int unregister_ioctl32_conversion(unsigned int cmd);
+extern int __deprecated unregister_ioctl32_conversion(unsigned int cmd);
 
 #else
 
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -91,8 +91,6 @@ struct resource_list {
 extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
-extern int get_resource_list(struct resource *, char *buf, int size);
-
 extern int request_resource(struct resource *root, struct resource *new);
 extern struct resource * ____request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
diff --git a/include/linux/ip.h b/include/linux/ip.h
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -121,18 +121,18 @@ struct inet_sock {
 	__u16			dport;		/* Destination port */
 	__u16			num;		/* Local port */
 	__u32			saddr;		/* Sending source */
-	int			uc_ttl;		/* Unicast TTL */
-	int			tos;		/* TOS */
-	unsigned	   	cmsg_flags;
+	__s16			uc_ttl;		/* Unicast TTL */
+	__u16			cmsg_flags;
 	struct ip_options	*opt;
 	__u16			sport;		/* Source port */
-	unsigned char		hdrincl;	/* Include headers ? */
+	__u16			id;		/* ID counter for DF pkts */
+	__u8			tos;		/* TOS */
 	__u8			mc_ttl;		/* Multicasting TTL */
-	__u8			mc_loop;	/* Loopback */
 	__u8			pmtudisc;
-	__u16			id;		/* ID counter for DF pkts */
 	unsigned		recverr : 1,
-				freebind : 1;
+				freebind : 1,
+				hdrincl : 1,
+				mc_loop : 1;
 	int			mc_index;	/* Multicast device index */
 	__u32			mc_addr;
 	struct ip_mc_socklist	*mc_list;	/* Group array */
@@ -152,6 +152,7 @@ struct inet_sock {
 };
 
 #define IPCORK_OPT	1	/* ip-options has been held in ipcork.opt */
+#define IPCORK_ALLFRAG	2	/* always fragment (for ipv6 for now) */
 
 static inline struct inet_sock *inet_sk(const struct sock *sk)
 {
@@ -163,7 +164,7 @@ static inline void __inet_sk_copy_descen
 					     const int ancestor_size)
 {
 	memcpy(inet_sk(sk_to) + 1, inet_sk(sk_from) + 1,
-	       sk_from->sk_prot->slab_obj_size - ancestor_size);
+	       sk_from->sk_prot->obj_size - ancestor_size);
 }
 #if !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE))
 static inline void inet_sk_copy_descendant(struct sock *sk_to,
diff --git a/include/linux/ip_mp_alg.h b/include/linux/ip_mp_alg.h
new file mode 100644
--- /dev/null
+++ b/include/linux/ip_mp_alg.h
@@ -0,0 +1,22 @@
+/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifndef _LINUX_IP_MP_ALG_H
+#define _LINUX_IP_MP_ALG_H
+
+enum ip_mp_alg {
+	IP_MP_ALG_NONE,
+	IP_MP_ALG_RR,
+	IP_MP_ALG_DRR,
+	IP_MP_ALG_RANDOM,
+	IP_MP_ALG_WRANDOM,
+	__IP_MP_ALG_MAX
+};
+
+#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
+
+#endif /* _LINUX_IP_MP_ALG_H */
+
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -104,13 +104,22 @@ struct ipmi_smi_handlers
 	/* Called to poll for work to do.  This is so upper layers can
 	   poll for operations during things like crash dumps. */
 	void (*poll)(void *send_info);
+
+	/* Tell the handler that we are using it/not using it.  The
+	   message handler get the modules that this handler belongs
+	   to; this function lets the SMI claim any modules that it
+	   uses.  These may be NULL if this is not required. */
+	int (*inc_usecount)(void *send_info);
+	void (*dec_usecount)(void *send_info);
 };
 
-/* Add a low-level interface to the IPMI driver. */
+/* Add a low-level interface to the IPMI driver.  Note that if the
+   interface doesn't know its slave address, it should pass in zero. */
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 		      void                     *send_info,
 		      unsigned char            version_major,
 		      unsigned char            version_minor,
+		      unsigned char            slave_addr,
 		      ipmi_smi_t               *intf);
 
 /*
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -209,8 +209,8 @@ struct ipv6_pinfo {
 
 	__u32			flow_label;
 	__u32			frag_size;
-	int			hop_limit;
-	int			mcast_hops;
+	__s16			hop_limit;
+	__s16			mcast_hops;
 	int			mcast_oif;
 
 	/* pktoption flags */
@@ -233,10 +233,11 @@ struct ipv6_pinfo {
 				pmtudisc:2,
 				ipv6only:1;
 
+	__u32			dst_cookie;
+
 	struct ipv6_mc_socklist	*ipv6_mc_list;
 	struct ipv6_ac_socklist	*ipv6_ac_list;
 	struct ipv6_fl_socklist *ipv6_fl_list;
-	__u32			dst_cookie;
 
 	struct ipv6_txoptions	*opt;
 	struct sk_buff		*pktoptions;
diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h
--- a/include/linux/isapnp.h
+++ b/include/linux/isapnp.h
@@ -100,16 +100,7 @@ int isapnp_present(void);
 int isapnp_cfg_begin(int csn, int device);
 int isapnp_cfg_end(void);
 unsigned char isapnp_read_byte(unsigned char idx);
-unsigned short isapnp_read_word(unsigned char idx);
-unsigned int isapnp_read_dword(unsigned char idx);
 void isapnp_write_byte(unsigned char idx, unsigned char val);
-void isapnp_write_word(unsigned char idx, unsigned short val);
-void isapnp_write_dword(unsigned char idx, unsigned int val);
-void isapnp_wake(unsigned char csn);
-void isapnp_device(unsigned char device);
-void isapnp_activate(unsigned char device);
-void isapnp_deactivate(unsigned char device);
-void *isapnp_alloc(long size);
 
 #ifdef CONFIG_PROC_FS
 int isapnp_proc_init(void);
@@ -119,9 +110,6 @@ static inline int isapnp_proc_init(void)
 static inline int isapnp_proc_done(void) { return 0; }
 #endif
 
-/* init/main.c */
-int isapnp_init(void);
-
 /* compat */
 struct pnp_card *pnp_find_card(unsigned short vendor,
 			       unsigned short device,
@@ -138,15 +126,7 @@ static inline int isapnp_present(void) {
 static inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
 static inline int isapnp_cfg_end(void) { return -ENODEV; }
 static inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
-static inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
-static inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
 static inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
-static inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
-static inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
-static inline void isapnp_wake(unsigned char csn) { ; }
-static inline void isapnp_device(unsigned char device) { ; }
-static inline void isapnp_activate(unsigned char device) { ; }
-static inline void isapnp_deactivate(unsigned char device) { ; }
 
 static inline struct pnp_card *pnp_find_card(unsigned short vendor,
 					     unsigned short device,
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -1,4 +1,3 @@
-
 #ifndef _ISOFS_FS_H
 #define _ISOFS_FS_H
 
@@ -163,150 +162,4 @@ struct iso_directory_record {
 
 #define ISOFS_SUPER_MAGIC 0x9660
 
-#ifdef __KERNEL__
-/* Number conversion inlines, named after the section in ISO 9660
-   they correspond to. */
-
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-#include <linux/iso_fs_i.h>
-#include <linux/iso_fs_sb.h>
-
-static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb)
-{
-	return sb->s_fs_info;
-}
-
-static inline struct iso_inode_info *ISOFS_I(struct inode *inode)
-{
-	return container_of(inode, struct iso_inode_info, vfs_inode);
-}
-
-static inline int isonum_711(char *p)
-{
-	return *(u8 *)p;
-}
-static inline int isonum_712(char *p)
-{
-	return *(s8 *)p;
-}
-static inline unsigned int isonum_721(char *p)
-{
-	return le16_to_cpu(get_unaligned((__le16 *)p));
-}
-static inline unsigned int isonum_722(char *p)
-{
-	return be16_to_cpu(get_unaligned((__le16 *)p));
-}
-static inline unsigned int isonum_723(char *p)
-{
-	/* Ignore bigendian datum due to broken mastering programs */
-	return le16_to_cpu(get_unaligned((__le16 *)p));
-}
-static inline unsigned int isonum_731(char *p)
-{
-	return le32_to_cpu(get_unaligned((__le32 *)p));
-}
-static inline unsigned int isonum_732(char *p)
-{
-	return be32_to_cpu(get_unaligned((__le32 *)p));
-}
-static inline unsigned int isonum_733(char *p)
-{
-	/* Ignore bigendian datum due to broken mastering programs */
-	return le32_to_cpu(get_unaligned((__le32 *)p));
-}
-extern int iso_date(char *, int);
-
-struct inode;		/* To make gcc happy */
-
-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
-extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
-extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
-
-int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
-int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
-
-extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *);
-extern struct buffer_head *isofs_bread(struct inode *, sector_t);
-extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
-
-extern struct inode *isofs_iget(struct super_block *sb,
-                                unsigned long block,
-                                unsigned long offset);
-
-/* Because the inode number is no longer relevant to finding the
- * underlying meta-data for an inode, we are free to choose a more
- * convenient 32-bit number as the inode number.  The inode numbering
- * scheme was recommended by Sergey Vlasov and Eric Lammerts. */
-static inline unsigned long isofs_get_ino(unsigned long block,
-					  unsigned long offset,
-					  unsigned long bufbits)
-{
-	return (block << (bufbits - 5)) | (offset >> 5);
-}
-
-/* Every directory can have many redundant directory entries scattered
- * throughout the directory tree.  First there is the directory entry
- * with the name of the directory stored in the parent directory.
- * Then, there is the "." directory entry stored in the directory
- * itself.  Finally, there are possibly many ".." directory entries
- * stored in all the subdirectories.
- *
- * In order for the NFS get_parent() method to work and for the
- * general consistency of the dcache, we need to make sure the
- * "i_iget5_block" and "i_iget5_offset" all point to exactly one of
- * the many redundant entries for each directory.  We normalize the
- * block and offset by always making them point to the "."  directory.
- *
- * Notice that we do not use the entry for the directory with the name
- * that is located in the parent directory.  Even though choosing this
- * first directory is more natural, it is much easier to find the "."
- * entry in the NFS get_parent() method because it is implicitly
- * encoded in the "extent + ext_attr_length" fields of _all_ the
- * redundant entries for the directory.  Thus, it can always be
- * reached regardless of which directory entry you have in hand.
- *
- * This works because the "." entry is simply the first directory
- * record when you start reading the file that holds all the directory
- * records, and this file starts at "extent + ext_attr_length" blocks.
- * Because the "." entry is always the first entry listed in the
- * directories file, the normalized "offset" value is always 0.
- *
- * You should pass the directory entry in "de".  On return, "block"
- * and "offset" will hold normalized values.  Only directories are
- * affected making it safe to call even for non-directory file
- * types. */
-static inline void
-isofs_normalize_block_and_offset(struct iso_directory_record* de,
-				 unsigned long *block,
-				 unsigned long *offset)
-{
-	/* Only directories are normalized. */
-	if (de->flags[0] & 2) {
-		*offset = 0;
-		*block = (unsigned long)isonum_733(de->extent)
-			+ (unsigned long)isonum_711(de->ext_attr_length);
-	}
-}
-
-extern struct inode_operations isofs_dir_inode_operations;
-extern struct file_operations isofs_dir_operations;
-extern struct address_space_operations isofs_symlink_aops;
-extern struct export_operations isofs_export_ops;
-
-/* The following macros are used to check for memory leaks. */
-#ifdef LEAK_CHECK
-#define free_s leak_check_free_s
-#define malloc leak_check_malloc
-#define sb_bread leak_check_bread
-#define brelse leak_check_brelse
-extern void * leak_check_malloc(unsigned int size);
-extern void leak_check_free_s(void * obj, int size);
-extern struct buffer_head * leak_check_bread(struct super_block *sb, int block);
-extern void leak_check_brelse(struct buffer_head * bh);
-#endif /* LEAK_CHECK */
-
-#endif /* __KERNEL__ */
-
 #endif
diff --git a/include/linux/iso_fs_i.h b/include/linux/iso_fs_i.h
deleted file mode 100644
--- a/include/linux/iso_fs_i.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _ISO_FS_I
-#define _ISO_FS_I
-
-#include <linux/fs.h>
-
-enum isofs_file_format {
-	isofs_file_normal = 0,
-	isofs_file_sparse = 1,
-	isofs_file_compressed = 2,
-};
-	
-/*
- * iso fs inode data in memory
- */
-struct iso_inode_info {
-	unsigned long i_iget5_block;
-	unsigned long i_iget5_offset;
-	unsigned int i_first_extent;
-	unsigned char i_file_format;
-	unsigned char i_format_parm[3];
-	unsigned long i_next_section_block;
-	unsigned long i_next_section_offset;
-	off_t i_section_size;
-	struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/iso_fs_sb.h b/include/linux/iso_fs_sb.h
deleted file mode 100644
--- a/include/linux/iso_fs_sb.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _ISOFS_FS_SB
-#define _ISOFS_FS_SB
-
-/*
- * iso9660 super-block data in memory
- */
-struct isofs_sb_info {
-	unsigned long s_ninodes;
-	unsigned long s_nzones;
-	unsigned long s_firstdatazone;
-	unsigned long s_log_zone_size;
-	unsigned long s_max_size;
-	
-	unsigned char s_high_sierra; /* A simple flag */
-	unsigned char s_mapping;
-	int           s_rock_offset; /* offset of SUSP fields within SU area */
-	unsigned char s_rock;
-	unsigned char s_joliet_level;
-	unsigned char s_utf8;
-	unsigned char s_cruft; /* Broken disks with high
-				  byte of length containing
-				  junk */
-	unsigned char s_unhide;
-	unsigned char s_nosuid;
-	unsigned char s_nodev;
-	unsigned char s_nocompress;
-
-	mode_t s_mode;
-	gid_t s_gid;
-	uid_t s_uid;
-	struct nls_table *s_nls_iocharset; /* Native language support table */
-};
-
-#endif
diff --git a/include/linux/ixjuser.h b/include/linux/ixjuser.h
--- a/include/linux/ixjuser.h
+++ b/include/linux/ixjuser.h
@@ -42,8 +42,6 @@
  *
  *****************************************************************************/
 
-static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 4.1 2001/08/05 00:17:37 craigs Exp $";
-
 #include <linux/telephony.h>
 
 
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -562,6 +562,7 @@ struct transaction_s 
  * @j_sb_buffer: First part of superblock buffer
  * @j_superblock: Second part of superblock buffer
  * @j_format_version: Version of the superblock format
+ * @j_state_lock: Protect the various scalars in the journal
  * @j_barrier_count:  Number of processes waiting to create a barrier lock
  * @j_barrier: The barrier lock itself
  * @j_running_transaction: The current running transaction..
@@ -589,6 +590,7 @@ struct transaction_s 
  * @j_fs_dev: Device which holds the client fs.  For internal journal this will
  *     be equal to j_dev
  * @j_maxlen: Total maximum capacity of the journal region on disk.
+ * @j_list_lock: Protects the buffer lists and internal buffer state.
  * @j_inode: Optional inode where we store the journal.  If present, all journal
  *     block numbers are mapped into this inode via bmap().
  * @j_tail_sequence:  Sequence number of the oldest transaction in the log 
@@ -604,8 +606,11 @@ struct transaction_s 
  * @j_commit_interval: What is the maximum transaction lifetime before we begin
  *  a commit?
  * @j_commit_timer:  The timer used to wakeup the commit thread
+ * @j_revoke_lock: Protect the revoke table
  * @j_revoke: The revoke table - maintains the list of revoked blocks in the
  *     current transaction.
+ * @j_revoke_table: alternate revoke tables for j_revoke
+ * @j_private: An opaque pointer to fs-private information.
  */
 
 struct journal_s
@@ -789,6 +794,12 @@ struct journal_s
 	struct jbd_revoke_table_s *j_revoke_table[2];
 
 	/*
+	 * array of bhs for journal_commit_transaction
+	 */
+	struct buffer_head	**j_wbuf;
+	int			j_wbufsize;
+
+	/*
 	 * An opaque pointer to fs-private information.  ext3 puts its
 	 * superblock pointer here
 	 */
@@ -811,6 +822,7 @@ struct journal_s
  */
 
 /* Filing buffers */
+extern void __journal_temp_unlink_buffer(struct journal_head *jh);
 extern void journal_unfile_buffer(journal_t *, struct journal_head *);
 extern void __journal_unfile_buffer(struct journal_head *);
 extern void __journal_refile_buffer(struct journal_head *);
@@ -867,15 +879,12 @@ static inline handle_t *journal_current_
 extern handle_t *journal_start(journal_t *, int nblocks);
 extern int	 journal_restart (handle_t *, int nblocks);
 extern int	 journal_extend (handle_t *, int nblocks);
-extern int	 journal_get_write_access(handle_t *, struct buffer_head *,
-						int *credits);
+extern int	 journal_get_write_access(handle_t *, struct buffer_head *);
 extern int	 journal_get_create_access (handle_t *, struct buffer_head *);
-extern int	 journal_get_undo_access(handle_t *, struct buffer_head *,
-						int *credits);
+extern int	 journal_get_undo_access(handle_t *, struct buffer_head *);
 extern int	 journal_dirty_data (handle_t *, struct buffer_head *);
 extern int	 journal_dirty_metadata (handle_t *, struct buffer_head *);
-extern void	 journal_release_buffer (handle_t *, struct buffer_head *,
-						int credits);
+extern void	 journal_release_buffer (handle_t *, struct buffer_head *);
 extern int	 journal_forget (handle_t *, struct buffer_head *);
 extern void	 journal_sync_buffer (struct buffer_head *);
 extern int	 journal_invalidatepage(journal_t *,
@@ -926,7 +935,7 @@ void journal_put_journal_head(struct jou
  */
 extern kmem_cache_t *jbd_handle_cache;
 
-static inline handle_t *jbd_alloc_handle(int gfp_flags)
+static inline handle_t *jbd_alloc_handle(unsigned int __nocast gfp_flags)
 {
 	return kmem_cache_alloc(jbd_handle_cache, gfp_flags);
 }
diff --git a/include/linux/jffs.h b/include/linux/jffs.h
--- a/include/linux/jffs.h
+++ b/include/linux/jffs.h
@@ -208,7 +208,6 @@ struct jffs_flash_status
 #define JFFS_MEMORY_DEBUG 0
 
 extern long no_jffs_node;
-extern long no_jffs_file;
 #if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG
 extern long no_jffs_control;
 extern long no_jffs_raw_inode;
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h
--- a/include/linux/journal-head.h
+++ b/include/linux/journal-head.h
@@ -32,6 +32,13 @@ struct journal_head {
 	unsigned b_jlist;
 
 	/*
+	 * This flag signals the buffer has been modified by
+	 * the currently running transaction
+	 * [jbd_lock_bh_state()]
+	 */
+	unsigned b_modified;
+
+	/*
 	 * Copy of the buffer data frozen for writing to the log.
 	 * [jbd_lock_bh_state()]
 	 */
diff --git a/include/linux/joystick.h b/include/linux/joystick.h
--- a/include/linux/joystick.h
+++ b/include/linux/joystick.h
@@ -66,10 +66,10 @@ struct js_event {
 #define JSIOCSCORR		_IOW('j', 0x21, struct js_corr)			/* set correction values */
 #define JSIOCGCORR		_IOR('j', 0x22, struct js_corr)			/* get correction values */
 
-#define JSIOCSAXMAP		_IOW('j', 0x31, __u8[ABS_MAX])			/* set axis mapping */
-#define JSIOCGAXMAP		_IOR('j', 0x32, __u8[ABS_MAX])			/* get axis mapping */
-#define JSIOCSBTNMAP		_IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC])	/* set button mapping */
-#define JSIOCGBTNMAP		_IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC])	/* get button mapping */
+#define JSIOCSAXMAP		_IOW('j', 0x31, __u8[ABS_MAX + 1])		/* set axis mapping */
+#define JSIOCGAXMAP		_IOR('j', 0x32, __u8[ABS_MAX + 1])		/* get axis mapping */
+#define JSIOCSBTNMAP		_IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC + 1])	/* set button mapping */
+#define JSIOCGBTNMAP		_IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC + 1])	/* get button mapping */
 
 /*
  * Types and constants for get/set correction
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -48,10 +48,20 @@ extern int console_printk[];
 
 struct completion;
 
+/**
+ * might_sleep - annotation for functions that can sleep
+ *
+ * this macro will print a stack trace if it is executed in an atomic
+ * context (spinlock, irq-handler, ...).
+ *
+ * This is a useful debugging help to be able to catch problems early and not
+ * be biten later when the calling function happens to sleep when it is not
+ * supposed to.
+ */
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
-void __might_sleep(char *file, int line);
 #define might_sleep() __might_sleep(__FILE__, __LINE__)
 #define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
+void __might_sleep(char *file, int line);
 #else
 #define might_sleep() do {} while(0)
 #define might_sleep_if(cond) do {} while (0)
@@ -81,17 +91,21 @@ extern unsigned long long simple_strtoul
 extern long long simple_strtoll(const char *,char **,unsigned int);
 extern int sprintf(char * buf, const char * fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
-extern int vsprintf(char *buf, const char *, va_list);
+extern int vsprintf(char *buf, const char *, va_list)
+	__attribute__ ((format (printf, 2, 0)));
 extern int snprintf(char * buf, size_t size, const char * fmt, ...)
 	__attribute__ ((format (printf, 3, 4)));
-extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+	__attribute__ ((format (printf, 3, 0)));
 extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
 	__attribute__ ((format (printf, 3, 4)));
-extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+	__attribute__ ((format (printf, 3, 0)));
 
 extern int sscanf(const char *, const char *, ...)
-	__attribute__ ((format (scanf,2,3)));
-extern int vsscanf(const char *, const char *, va_list);
+	__attribute__ ((format (scanf, 2, 3)));
+extern int vsscanf(const char *, const char *, va_list)
+	__attribute__ ((format (scanf, 2, 0)));
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
@@ -101,9 +115,19 @@ extern int __kernel_text_address(unsigne
 extern int kernel_text_address(unsigned long addr);
 extern int session_of_pgrp(int pgrp);
 
-asmlinkage int vprintk(const char *fmt, va_list args);
+#ifdef CONFIG_PRINTK
+asmlinkage int vprintk(const char *fmt, va_list args)
+	__attribute__ ((format (printf, 1, 0)));
 asmlinkage int printk(const char * fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
+#else
+static inline int vprintk(const char *s, va_list args)
+	__attribute__ ((format (printf, 1, 0)));
+static inline int vprintk(const char *s, va_list args) { return 0; }
+static inline int printk(const char *s, ...)
+	__attribute__ ((format (printf, 1, 2)));
+static inline int printk(const char *s, ...) { return 0; }
+#endif
 
 unsigned long int_sqrt(unsigned long);
 
@@ -278,6 +302,12 @@ struct sysinfo {
 extern void BUILD_BUG(void);
 #define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0)
 
+#ifdef CONFIG_SYSCTL
+extern int randomize_va_space;
+#else
+#define randomize_va_space 1
+#endif
+
 /* Trap pasters of __FUNCTION__ at compile-time */
 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 95
 #define __FUNCTION__ (__func__)
diff --git a/include/linux/key.h b/include/linux/key.h
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -58,6 +58,7 @@ struct key;
 
 struct seq_file;
 struct user_struct;
+struct signal_struct;
 
 struct key_type;
 struct key_owner;
@@ -258,7 +259,9 @@ extern struct key root_user_keyring, roo
 extern int alloc_uid_keyring(struct user_struct *user);
 extern void switch_uid_keyring(struct user_struct *new_user);
 extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
+extern int copy_thread_group_keys(struct task_struct *tsk);
 extern void exit_keys(struct task_struct *tsk);
+extern void exit_thread_group_keys(struct signal_struct *tg);
 extern int suid_keys(struct task_struct *tsk);
 extern int exec_keys(struct task_struct *tsk);
 extern void key_fsuid_changed(struct task_struct *tsk);
@@ -274,7 +277,9 @@ extern void key_init(void);
 #define alloc_uid_keyring(u)		0
 #define switch_uid_keyring(u)		do { } while(0)
 #define copy_keys(f,t)			0
+#define copy_thread_group_keys(t)	0
 #define exit_keys(t)			do { } while(0)
+#define exit_thread_group_keys(tg)	do { } while(0)
 #define suid_keys(t)			do { } while(0)
 #define exec_keys(t)			do { } while(0)
 #define key_fsuid_changed(t)		do { } while(0)
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -16,7 +16,7 @@
 
 #define NR_SHIFT	9
 
-#define NR_KEYS		255
+#define NR_KEYS		256
 #define MAX_NR_KEYMAPS	256
 /* This means 128Kb if all keymaps are allocated. Only the superuser
 	may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
@@ -27,7 +27,6 @@ extern const int NR_TYPES;
 extern const int max_vals[];
 extern unsigned short *key_maps[MAX_NR_KEYMAPS];
 extern unsigned short plain_map[NR_KEYS];
-extern unsigned char keyboard_type;
 #endif
 
 #define MAX_NR_FUNC	256	/* max nr of strings assigned to keys */
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
--- a/include/linux/kfifo.h
+++ b/include/linux/kfifo.h
@@ -35,8 +35,8 @@ struct kfifo {
 };
 
 extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
-				int gfp_mask, spinlock_t *lock);
-extern struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask,
+				unsigned int __nocast gfp_mask, spinlock_t *lock);
+extern struct kfifo *kfifo_alloc(unsigned int size, unsigned int __nocast gfp_mask,
 				 spinlock_t *lock);
 extern void kfifo_free(struct kfifo *fifo);
 extern unsigned int __kfifo_put(struct kfifo *fifo,
@@ -44,7 +44,7 @@ extern unsigned int __kfifo_put(struct k
 extern unsigned int __kfifo_get(struct kfifo *fifo,
 				unsigned char *buffer, unsigned int len);
 
-/*
+/**
  * __kfifo_reset - removes the entire FIFO contents, no locking version
  * @fifo: the fifo to be emptied.
  */
@@ -53,7 +53,7 @@ static inline void __kfifo_reset(struct 
 	fifo->in = fifo->out = 0;
 }
 
-/*
+/**
  * kfifo_reset - removes the entire FIFO contents
  * @fifo: the fifo to be emptied.
  */
@@ -68,7 +68,7 @@ static inline void kfifo_reset(struct kf
 	spin_unlock_irqrestore(fifo->lock, flags);
 }
 
-/*
+/**
  * kfifo_put - puts some data into the FIFO
  * @fifo: the fifo to be used.
  * @buffer: the data to be added.
@@ -93,7 +93,7 @@ static inline unsigned int kfifo_put(str
 	return ret;
 }
 
-/*
+/**
  * kfifo_get - gets some data from the FIFO
  * @fifo: the fifo to be used.
  * @buffer: where the data must be copied.
@@ -124,7 +124,7 @@ static inline unsigned int kfifo_get(str
 	return ret;
 }
 
-/*
+/**
  * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
  * @fifo: the fifo to be used.
  */
@@ -133,7 +133,7 @@ static inline unsigned int __kfifo_len(s
 	return fifo->in - fifo->out;
 }
 
-/*
+/**
  * kfifo_len - returns the number of bytes available in the FIFO
  * @fifo: the fifo to be used.
  */
diff --git a/include/linux/kobj_map.h b/include/linux/kobj_map.h
--- a/include/linux/kobj_map.h
+++ b/include/linux/kobj_map.h
@@ -7,6 +7,6 @@ int kobj_map(struct kobj_map *, dev_t, u
 	     kobj_probe_t *, int (*)(dev_t, void *), void *);
 void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
 struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
-struct kobj_map *kobj_map_init(kobj_probe_t *, struct subsystem *);
+struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
 
 #endif
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -20,6 +20,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/sysfs.h>
+#include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/kref.h>
 #include <linux/kobject_uevent.h>
@@ -102,6 +103,7 @@ struct kset {
 	struct subsystem	* subsys;
 	struct kobj_type	* ktype;
 	struct list_head	list;
+	spinlock_t		list_lock;
 	struct kobject		kobj;
 	struct kset_hotplug_ops	* hotplug_ops;
 };
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -43,6 +43,9 @@ typedef int (*kprobe_fault_handler_t) (s
 struct kprobe {
 	struct hlist_node hlist;
 
+	/* list of kprobes for multi-handler support */
+	struct list_head list;
+
 	/* location of the probe point */
 	kprobe_opcode_t *addr;
 
diff --git a/include/linux/kref.h b/include/linux/kref.h
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -26,7 +26,7 @@ struct kref {
 
 void kref_init(struct kref *kref);
 void kref_get(struct kref *kref);
-void kref_put(struct kref *kref, void (*release) (struct kref *kref));
+int kref_put(struct kref *kref, void (*release) (struct kref *kref));
 
 #endif /* __KERNEL__ */
 #endif /* _KREF_H_ */
diff --git a/include/linux/libata.h b/include/linux/libata.h
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -410,6 +410,7 @@ extern u8 ata_chk_err(struct ata_port *a
 extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
+extern void ata_host_stop (struct ata_host_set *host_set);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
 extern int ata_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -466,12 +467,34 @@ static inline u8 ata_chk_status(struct a
 	return ap->ops->check_status(ap);
 }
 
+
+/**
+ *	ata_pause - Flush writes and pause 400 nanoseconds.
+ *	@ap: Port to wait for.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
 static inline void ata_pause(struct ata_port *ap)
 {
 	ata_altstatus(ap);
 	ndelay(400);
 }
 
+
+/**
+ *	ata_busy_wait - Wait for a port status register
+ *	@ap: Port to wait for.
+ *
+ *	Waits up to max*10 microseconds for the selected bits in the port's
+ *	status register to be cleared.
+ *	Returns final value of status register.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
 static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
 			       unsigned int max)
 {
@@ -486,6 +509,18 @@ static inline u8 ata_busy_wait(struct at
 	return status;
 }
 
+
+/**
+ *	ata_wait_idle - Wait for a port to be idle.
+ *	@ap: Port to wait for.
+ *
+ *	Waits up to 10ms for port's BUSY and DRQ signals to clear.
+ *	Returns final value of status register.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
 static inline u8 ata_wait_idle(struct ata_port *ap)
 {
 	u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
@@ -524,6 +559,18 @@ static inline void ata_tf_init(struct at
 		tf->device = ATA_DEVICE_OBS | ATA_DEV1;
 }
 
+
+/**
+ *	ata_irq_on - Enable interrupts on a port.
+ *	@ap: Port on which interrupts are enabled.
+ *
+ *	Enable interrupts on a legacy IDE device using MMIO or PIO,
+ *	wait for idle, clear any pending interrupts.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
 static inline u8 ata_irq_on(struct ata_port *ap)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -543,6 +590,18 @@ static inline u8 ata_irq_on(struct ata_p
 	return tmp;
 }
 
+
+/**
+ *	ata_irq_ack - Acknowledge a device interrupt.
+ *	@ap: Port on which interrupts are enabled.
+ *
+ *	Wait up to 10 ms for legacy IDE device to become idle (BUSY
+ *	or BUSY+DRQ clear).  Obtain dma status and port status from
+ *	device.  Clear the interrupt.  Return port status.
+ *
+ *	LOCKING:
+ */
+
 static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
 {
 	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
@@ -584,6 +643,13 @@ static inline void scr_write(struct ata_
 	ap->ops->scr_write(ap, reg, val);
 }
 
+static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, 
+				   u32 val)
+{
+	ap->ops->scr_write(ap, reg, val);
+	(void) ap->ops->scr_read(ap, reg);
+}
+
 static inline unsigned int sata_dev_present(struct ata_port *ap)
 {
 	return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
diff --git a/include/linux/list.h b/include/linux/list.h
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -692,7 +692,7 @@ static inline void hlist_add_after(struc
  * @member:	the name of the hlist_node within the struct.
  *
  * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as hlist_add_rcu()
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
  */
 #define hlist_for_each_entry_rcu(tpos, pos, head, member)		 \
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -42,7 +42,6 @@ struct nlm_host {
 	struct rpc_clnt	*	h_rpcclnt;	/* RPC client to talk to peer */
 	char			h_name[20];	/* remote hostname */
 	u32			h_version;	/* interface version */
-	rpc_authflavor_t	h_authflavor;	/* RPC authentication type */
 	unsigned short		h_proto;	/* transport proto */
 	unsigned short		h_reclaiming : 1,
 				h_server     : 1, /* server side, not client side */
@@ -143,8 +142,6 @@ extern unsigned long		nlmsvc_timeout;
  * Lockd client functions
  */
 struct nlm_rqst * nlmclnt_alloc_call(void);
-int		  nlmclnt_call(struct nlm_rqst *, u32);
-int		  nlmclnt_async_call(struct nlm_rqst *, u32, rpc_action);
 int		  nlmclnt_block(struct nlm_host *, struct file_lock *, u32 *);
 int		  nlmclnt_cancel(struct nlm_host *, struct file_lock *);
 u32		  nlmclnt_grant(struct nlm_lock *);
diff --git a/include/linux/loop.h b/include/linux/loop.h
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -71,7 +71,10 @@ struct loop_device {
 /*
  * Loop flags
  */
-#define LO_FLAGS_READ_ONLY	1
+enum {
+	LO_FLAGS_READ_ONLY	= 1,
+	LO_FLAGS_USE_AOPS	= 2,
+};
 
 #include <asm/posix_types.h>	/* for __kernel_old_dev_t */
 #include <asm/types.h>		/* for __u64 */
diff --git a/include/linux/major.h b/include/linux/major.h
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -25,7 +25,6 @@
 #define MISC_MAJOR		10
 #define SCSI_CDROM_MAJOR	11
 #define MUX_MAJOR		11	/* PA-RISC only */
-#define QIC02_TAPE_MAJOR	12
 #define XT_DISK_MAJOR		13
 #define INPUT_MAJOR		13
 #define SOUND_MAJOR		14
diff --git a/include/linux/mempool.h b/include/linux/mempool.h
--- a/include/linux/mempool.h
+++ b/include/linux/mempool.h
@@ -6,7 +6,7 @@
 
 #include <linux/wait.h>
 
-typedef void * (mempool_alloc_t)(int gfp_mask, void *pool_data);
+typedef void * (mempool_alloc_t)(unsigned int __nocast gfp_mask, void *pool_data);
 typedef void (mempool_free_t)(void *element, void *pool_data);
 
 typedef struct mempool_s {
@@ -22,16 +22,16 @@ typedef struct mempool_s {
 } mempool_t;
 extern mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
 				 mempool_free_t *free_fn, void *pool_data);
-extern int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
+extern int mempool_resize(mempool_t *pool, int new_min_nr, unsigned int __nocast gfp_mask);
 extern void mempool_destroy(mempool_t *pool);
-extern void * mempool_alloc(mempool_t *pool, int gfp_mask);
+extern void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask);
 extern void mempool_free(void *element, mempool_t *pool);
 
 /*
  * A mempool_alloc_t and mempool_free_t that get the memory from
  * a slab that is passed in through pool_data.
  */
-void *mempool_alloc_slab(int gfp_mask, void *pool_data);
+void *mempool_alloc_slab(unsigned int __nocast gfp_mask, void *pool_data);
 void mempool_free_slab(void *element, void *pool_data);
 
 #endif /* _LINUX_MEMPOOL_H */
diff --git a/include/linux/mii.h b/include/linux/mii.h
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -20,6 +20,8 @@
 #define MII_ADVERTISE       0x04        /* Advertisement control reg   */
 #define MII_LPA             0x05        /* Link partner ability reg    */
 #define MII_EXPANSION       0x06        /* Expansion register          */
+#define MII_CTRL1000        0x09        /* 1000BASE-T control          */
+#define MII_STAT1000        0x0a        /* 1000BASE-T status           */
 #define MII_DCOUNTER        0x12        /* Disconnect counter          */
 #define MII_FCSCOUNTER      0x13        /* False carrier counter       */
 #define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
@@ -63,11 +65,17 @@
 #define ADVERTISE_SLCT          0x001f  /* Selector bits               */
 #define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
 #define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
 #define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
 #define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
 #define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
 #define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
-#define ADVERTISE_RESV          0x1c00  /* Unused...                   */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */
+#define ADVERTISE_RESV          0x1000  /* Unused...                   */
 #define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
 #define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
 #define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
@@ -80,11 +88,17 @@
 /* Link partner ability register. */
 #define LPA_SLCT                0x001f  /* Same as advertise selector  */
 #define LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
+#define LPA_1000XFULL           0x0020  /* Can do 1000BASE-X full-duplex */
 #define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
+#define LPA_1000XHALF           0x0040  /* Can do 1000BASE-X half-duplex */
 #define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
+#define LPA_1000XPAUSE          0x0080  /* Can do 1000BASE-X pause     */
 #define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
+#define LPA_1000XPAUSE_ASYM     0x0100  /* Can do 1000BASE-X pause asym*/
 #define LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
-#define LPA_RESV                0x1c00  /* Unused...                   */
+#define LPA_PAUSE_CAP           0x0400  /* Can pause                   */
+#define LPA_PAUSE_ASYM          0x0800  /* Can pause asymetrically     */
+#define LPA_RESV                0x1000  /* Unused...                   */
 #define LPA_RFAULT              0x2000  /* Link partner faulted        */
 #define LPA_LPACK               0x4000  /* Link partner acked us       */
 #define LPA_NPAGE               0x8000  /* Next page bit               */
@@ -105,6 +119,15 @@
 #define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
 #define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
 
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF      0x0100  /* Advertise 1000BASE-T half duplex */
+
+/* 1000BASE-T Status register */
+#define LPA_1000LOCALRXOK       0x2000  /* Link partner local receiver status */
+#define LPA_1000REMRXOK         0x1000  /* Link partner remote receiver status */
+#define LPA_1000FULL            0x0800  /* Link partner 1000BASE-T full duplex */
+#define LPA_1000HALF            0x0400  /* Link partner 1000BASE-T half duplex */
 
 struct mii_if_info {
 	int phy_id;
@@ -114,6 +137,7 @@ struct mii_if_info {
 
 	unsigned int full_duplex : 1;	/* is full duplex? */
 	unsigned int force_media : 1;	/* is autoneg. disabled? */
+	unsigned int supports_gmii : 1; /* are GMII registers supported? */
 
 	struct net_device *dev;
 	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
diff --git a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -37,10 +37,6 @@ extern int sysctl_legacy_va_layout;
 #include <asm/processor.h>
 #include <asm/atomic.h>
 
-#ifndef MM_VM_SIZE
-#define MM_VM_SIZE(mm)	((TASK_SIZE + PGDIR_SIZE - 1) & PGDIR_MASK)
-#endif
-
 #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n))
 
 /*
@@ -164,6 +160,7 @@ extern unsigned int kobjsize(const void 
 #define VM_ACCOUNT	0x00100000	/* Is a VM accounted object */
 #define VM_HUGETLB	0x00400000	/* Huge TLB Page VM */
 #define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
+#define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -581,17 +578,19 @@ struct zap_details {
 	pgoff_t	first_index;			/* Lowest page->index to unmap */
 	pgoff_t last_index;			/* Highest page->index to unmap */
 	spinlock_t *i_mmap_lock;		/* For unmap_mapping_range: */
-	unsigned long break_addr;		/* Where unmap_vmas stopped */
 	unsigned long truncate_count;		/* Compare vm_truncate_count */
 };
 
-void zap_page_range(struct vm_area_struct *vma, unsigned long address,
+unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *);
-int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm,
+unsigned long unmap_vmas(struct mmu_gather **tlb, struct mm_struct *mm,
 		struct vm_area_struct *start_vma, unsigned long start_addr,
 		unsigned long end_addr, unsigned long *nr_accounted,
 		struct zap_details *);
-void clear_page_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end);
+void free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
+		unsigned long end, unsigned long floor, unsigned long ceiling);
+void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma,
+		unsigned long floor, unsigned long ceiling);
 int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
 			struct vm_area_struct *vma);
 int zeromap_page_range(struct vm_area_struct *vma, unsigned long from,
@@ -638,9 +637,9 @@ extern unsigned long do_mremap(unsigned 
  * These functions are passed a count `nr_to_scan' and a gfpmask.  They should
  * scan `nr_to_scan' objects, attempting to free them.
  *
- * The callback must the number of objects which remain in the cache.
+ * The callback must return the number of objects which remain in the cache.
  *
- * The callback will be passes nr_to_scan == 0 when the VM is querying the
+ * The callback will be passed nr_to_scan == 0 when the VM is querying the
  * cache size, so a fastpath for that case is appropriate.
  */
 typedef int (*shrinker_t)(int nr_to_scan, unsigned int gfp_mask);
@@ -727,6 +726,7 @@ extern void __vma_link_rb(struct mm_stru
 extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
 	unsigned long addr, unsigned long len, pgoff_t pgoff);
 extern void exit_mmap(struct mm_struct *);
+extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
 
 extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
@@ -838,7 +838,7 @@ static inline void vm_stat_unaccount(str
 }
 
 /* update per process rss and vm hiwater data */
-extern void update_mem_hiwater(void);
+extern void update_mem_hiwater(struct task_struct *tsk);
 
 #ifndef CONFIG_DEBUG_PAGEALLOC
 static inline void
@@ -856,5 +856,8 @@ int in_gate_area_no_task(unsigned long a
 #define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);})
 #endif	/* __HAVE_ARCH_GATE_AREA */
 
+/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
+#define OOM_DISABLE -17
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -75,7 +75,7 @@ struct mmc_driver {
 	struct device_driver drv;
 	int (*probe)(struct mmc_card *);
 	void (*remove)(struct mmc_card *);
-	int (*suspend)(struct mmc_card *, u32);
+	int (*suspend)(struct mmc_card *, pm_message_t);
 	int (*resume)(struct mmc_card *);
 };
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -98,7 +98,7 @@ extern void mmc_free_host(struct mmc_hos
 #define mmc_priv(x)	((void *)((x) + 1))
 #define mmc_dev(x)	((x)->dev)
 
-extern int mmc_suspend_host(struct mmc_host *, u32);
+extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
 extern int mmc_resume_host(struct mmc_host *);
 
 extern void mmc_detect_change(struct mmc_host *);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -37,6 +37,7 @@ struct mmc_command {
 #define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
 #define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_SHORT)
+#define MMC_RSP_R6	(MMC_RSP_SHORT|MMC_RSP_CRC)
 
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -76,6 +76,16 @@
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
 
+/* SD commands                           type  argument     response */
+  /* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+
+  /* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
 /*
   MMC status in R1
   Type
@@ -113,7 +123,7 @@
 #define R1_STATUS(x)            (x & 0xFFFFE000)
 #define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 7)	/* sr, c */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
 /* These are unpacked versions of the actual responses */
 
@@ -185,6 +195,33 @@ struct _mmc_csd {
 #define MMC_VDD_35_36	0x00800000	/* VDD voltage 3.5 ~ 3.6 */
 #define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
 
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC		(1<<0)	/* (0) Basic protocol functions */
+					/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ		(1<<1)	/* (1) Stream read commands */
+					/* (CMD11) */
+#define CCC_BLOCK_READ		(1<<2)	/* (2) Block read commands */
+					/* (CMD16,17,18) */
+#define CCC_STREAM_WRITE	(1<<3)	/* (3) Stream write commands */
+					/* (CMD20) */
+#define CCC_BLOCK_WRITE		(1<<4)	/* (4) Block write commands */
+					/* (CMD16,24,25,26,27) */
+#define CCC_ERASE		(1<<5)	/* (5) Ability to erase blocks */
+					/* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT		(1<<6)	/* (6) Able to write protect blocks */
+					/* (CMD28,29,30) */
+#define CCC_LOCK_CARD		(1<<7)	/* (7) Able to lock down card */
+					/* (CMD16,CMD42) */
+#define CCC_APP_SPEC		(1<<8)	/* (8) Application specific */
+					/* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE		(1<<9)	/* (9) I/O mode */
+					/* (CMD5,39,40,52,53) */
+#define CCC_SWITCH		(1<<10)	/* (10) High speed switch */
+					/* (CMD6,34,35,36,37,50) */
+					/* (11) Reserved */
+					/* (CMD?) */
 
 /*
  * CSD field definitions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -11,6 +11,7 @@
 #include <linux/cache.h>
 #include <linux/threads.h>
 #include <linux/numa.h>
+#include <linux/init.h>
 #include <asm/atomic.h>
 
 /* Free memory management - zoned buddy allocator.  */
@@ -278,6 +279,16 @@ void wakeup_kswapd(struct zone *zone, in
 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
 		int alloc_type, int can_try_harder, int gfp_high);
 
+#ifdef CONFIG_HAVE_MEMORY_PRESENT
+void memory_present(int nid, unsigned long start, unsigned long end);
+#else
+static inline void memory_present(int nid, unsigned long start, unsigned long end) {}
+#endif
+
+#ifdef CONFIG_NEED_NODE_MEMMAP_SIZE
+unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
+#endif
+
 /*
  * zone_idx() returns 0 for the ZONE_DMA zone, 1 for the ZONE_NORMAL zone, etc.
  */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -165,4 +165,14 @@ struct pnp_card_device_id {
 };
 
 
+#define SERIO_ANY	0xff
+
+struct serio_device_id {
+	__u8 type;
+	__u8 extra;
+	__u8 id;
+	__u8 proto;
+};
+
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -77,24 +77,14 @@ void sort_main_extable(void);
 extern struct subsystem module_subsys;
 
 #ifdef MODULE
-#define ___module_cat(a,b) __mod_ ## a ## b
-#define __module_cat(a,b) ___module_cat(a,b)
-#define __MODULE_INFO(tag, name, info)					  \
-static const char __module_cat(name,__LINE__)[]				  \
-  __attribute_used__							  \
-  __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info
-
 #define MODULE_GENERIC_TABLE(gtype,name)			\
 extern const struct gtype##_id __mod_##gtype##_table		\
   __attribute__ ((unused, alias(__stringify(name))))
 
 extern struct module __this_module;
 #define THIS_MODULE (&__this_module)
-
 #else  /* !MODULE */
-
 #define MODULE_GENERIC_TABLE(gtype,name)
-#define __MODULE_INFO(tag, name, info)
 #define THIS_MODULE ((struct module *)0)
 #endif
 
@@ -560,7 +550,8 @@ static inline void MODULE_PARM_(void) { 
 /* DEPRECATED: Do not use. */
 #define MODULE_PARM(var,type)						    \
 struct obsolete_modparm __parm_##var __attribute__((section("__obsparm"))) = \
-{ __stringify(var), type, &MODULE_PARM_ };
+{ __stringify(var), type, &MODULE_PARM_ }; \
+__MODULE_PARM_TYPE(var, type);
 #else
 #define MODULE_PARM(var,type) static void __attribute__((__unused__)) *__parm_##var = &MODULE_PARM_;
 #endif
@@ -572,7 +563,6 @@ struct obsolete_modparm __parm_##var __a
 extern void __deprecated inter_module_register(const char *,
 		struct module *, const void *);
 extern void __deprecated inter_module_unregister(const char *);
-extern const void * __deprecated inter_module_get(const char *);
 extern const void * __deprecated inter_module_get_request(const char *,
 		const char *);
 extern void __deprecated inter_module_put(const char *);
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -13,6 +13,19 @@
 #define MODULE_PARAM_PREFIX __stringify(KBUILD_MODNAME) "."
 #endif
 
+#ifdef MODULE
+#define ___module_cat(a,b) __mod_ ## a ## b
+#define __module_cat(a,b) ___module_cat(a,b)
+#define __MODULE_INFO(tag, name, info)					  \
+static const char __module_cat(name,__LINE__)[]				  \
+  __attribute_used__							  \
+  __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info
+#else  /* !MODULE */
+#define __MODULE_INFO(tag, name, info)
+#endif
+#define __MODULE_PARM_TYPE(name, _type)					  \
+  __MODULE_INFO(parmtype, name##type, #name ":" _type)
+
 struct kernel_param;
 
 /* Returns 0, or -errno.  arg is in kp->arg. */
@@ -65,7 +78,7 @@ struct kparam_array
 #define module_param_named(name, value, type, perm)			   \
 	param_check_##type(name, &(value));				   \
 	module_param_call(name, param_set_##type, param_get_##type, &value, perm); \
-	__MODULE_INFO(parmtype, name##type, #name ":" #type)
+	__MODULE_PARM_TYPE(name, #type)
 
 #define module_param(name, type, perm)				\
 	module_param_named(name, name, type, perm)
@@ -76,7 +89,7 @@ struct kparam_array
 		= { len, string };					\
 	module_param_call(name, param_set_copystring, param_get_string,	\
 		   &__param_string_##name, perm);			\
-	__MODULE_INFO(parmtype, name##type, #name ":string")
+	__MODULE_PARM_TYPE(name, "string")
 
 /* Called on module insert or kernel boot */
 extern int parse_args(const char *name,
@@ -138,7 +151,7 @@ extern int param_get_invbool(char *buffe
 	    sizeof(array[0]), array };					\
 	module_param_call(name, param_array_set, param_array_get, 	\
 			  &__param_arr_##name, perm);			\
-	__MODULE_INFO(parmtype, name##type, #name ":array of " #type)
+	__MODULE_PARM_TYPE(name, "array of " #type)
 
 #define module_param_array(name, type, nump, perm)		\
 	module_param_array_named(name, name, type, nump, perm)
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -11,12 +11,15 @@
  */
 
 struct writeback_control;
+typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
 
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
 				unsigned nr_pages, get_block_t get_block);
 int mpage_readpage(struct page *page, get_block_t get_block);
 int mpage_writepages(struct address_space *mapping,
 		struct writeback_control *wbc, get_block_t get_block);
+int mpage_writepage(struct page *page, get_block_t *get_block,
+		struct writeback_control *wbc);
 
 static inline int
 generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -50,8 +50,6 @@
 #define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
 /* Convert attribute bits and a mask to the UNIX mode. */
 #define MSDOS_MKMODE(a, m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
-/* Convert the UNIX mode to MS-DOS attribute bits. */
-#define MSDOS_MKATTR(m)	((m & S_IWUGO) ? ATTR_NONE : ATTR_RO)
 
 #define MSDOS_NAME	11	/* maximum name length */
 #define MSDOS_LONGNAME	256	/* maximum name length */
@@ -78,15 +76,11 @@
 #define BAD_FAT12	0xFF7
 #define BAD_FAT16	0xFFF7
 #define BAD_FAT32	0x0FFFFFF7
-#define BAD_FAT(s)	(MSDOS_SB(s)->fat_bits == 32 ? BAD_FAT32 : \
-	MSDOS_SB(s)->fat_bits == 16 ? BAD_FAT16 : BAD_FAT12)
 
 /* standard EOF */
 #define EOF_FAT12	0xFFF
 #define EOF_FAT16	0xFFFF
 #define EOF_FAT32	0x0FFFFFFF
-#define EOF_FAT(s)	(MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
-	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
 #define FAT_ENT_FREE	(0)
 #define FAT_ENT_BAD	(BAD_FAT32)
@@ -100,8 +94,11 @@
 /*
  * ioctl commands
  */
-#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
-#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
+#define VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
+/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
+#define FAT_IOCTL_GET_ATTRIBUTES	_IOR('r', 0x10, __u32)
+#define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
 
 /*
  * vfat shortname flags
@@ -152,7 +149,7 @@ struct msdos_dir_entry {
 	__u8	name[8],ext[3];	/* name and extension */
 	__u8	attr;		/* attribute bits */
 	__u8    lcase;		/* Case for base and extension */
-	__u8	ctime_ms;	/* Creation time, milliseconds */
+	__u8	ctime_cs;	/* Creation time, centiseconds (0-199) */
 	__le16	ctime;		/* Creation time */
 	__le16	cdate;		/* Creation date */
 	__le16	adate;		/* Last access date */
@@ -173,10 +170,12 @@ struct msdos_dir_slot {
 	__u8    name11_12[4];	/* last 2 characters in name */
 };
 
-struct vfat_slot_info {
-	int long_slots;		/* number of long slots in filename */
-	loff_t longname_offset;	/* dir offset for longname start */
+struct fat_slot_info {
 	loff_t i_pos;		/* on-disk position of directory entry */
+	loff_t slot_off;	/* offset for slot or de start */
+	int nr_slots;		/* number of slots + 1(de) in filename */
+	struct msdos_dir_entry *de;
+	struct buffer_head *bh;
 };
 
 #ifdef __KERNEL__
@@ -228,8 +227,8 @@ struct msdos_sb_info {
 	unsigned long root_cluster;  /* first cluster of the root directory */
 	unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
 	struct semaphore fat_lock;
-	int prev_free;               /* previously allocated cluster number */
-	int free_clusters;           /* -1 if undefined */
+	unsigned int prev_free;      /* previously allocated cluster number */
+	unsigned int free_clusters;  /* -1 if undefined */
 	struct fat_mount_options options;
 	struct nls_table *nls_disk;  /* Codepage used on disk */
 	struct nls_table *nls_io;    /* Charset used for input and display */
@@ -237,6 +236,9 @@ struct msdos_sb_info {
 	int dir_per_block;	     /* dir entries per block */
 	int dir_per_block_bits;	     /* log2(dir_per_block) */
 
+	int fatent_shift;
+	struct fatent_operations *fatent_ops;
+
 	spinlock_t inode_hash_lock;
 	struct hlist_head inode_hashtable[FAT_HASH_SIZE];
 };
@@ -257,7 +259,6 @@ struct msdos_inode_info {
 	int i_start;		/* first cluster or 0 */
 	int i_logstart;		/* logical first cluster */
 	int i_attrs;		/* unused attribute bits */
-	int i_ctime_ms;		/* unused change time in milliseconds */
 	loff_t i_pos;		/* on-disk position of directory entry or 0 */
 	struct hlist_node i_fat_hash;	/* hash by i_location */
 	struct inode vfs_inode;
@@ -273,6 +274,14 @@ static inline struct msdos_inode_info *M
 	return container_of(inode, struct msdos_inode_info, vfs_inode);
 }
 
+/* Return the FAT attribute byte for this inode */
+static inline u8 fat_attr(struct inode *inode)
+{
+	return ((inode->i_mode & S_IWUGO) ? ATTR_NONE : ATTR_RO) |
+		(S_ISDIR(inode->i_mode) ? ATTR_DIR : ATTR_NONE) |
+		MSDOS_I(inode)->i_attrs;
+}
+
 static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus)
 {
 	return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus
@@ -307,7 +316,6 @@ static inline void fatwchar_to16(__u8 *d
 
 /* fat/cache.c */
 extern void fat_cache_inval_inode(struct inode *inode);
-extern int fat_access(struct super_block *sb, int nr, int new_value);
 extern int fat_get_cluster(struct inode *inode, int cluster,
 			   int *fclus, int *dclus);
 extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
@@ -315,19 +323,67 @@ extern int fat_bmap(struct inode *inode,
 /* fat/dir.c */
 extern struct file_operations fat_dir_operations;
 extern int fat_search_long(struct inode *inode, const unsigned char *name,
-			   int name_len, int anycase,
-			   loff_t *spos, loff_t *lpos);
-extern int fat_add_entries(struct inode *dir, int slots,
-			   struct buffer_head **bh,
-			   struct msdos_dir_entry **de, loff_t *i_pos);
-extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
+			   int name_len, struct fat_slot_info *sinfo);
 extern int fat_dir_empty(struct inode *dir);
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const unsigned char *name,
-		    struct buffer_head **res_bh,
-		    struct msdos_dir_entry **res_de, loff_t *i_pos);
+		    struct fat_slot_info *sinfo);
+extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+				struct msdos_dir_entry **de, loff_t *i_pos);
+extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
+extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+			   struct fat_slot_info *sinfo);
+extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
+
+/* fat/fatent.c */
+struct fat_entry {
+	int entry;
+	union {
+		u8 *ent12_p[2];
+		__le16 *ent16_p;
+		__le32 *ent32_p;
+	} u;
+	int nr_bhs;
+	struct buffer_head *bhs[2];
+};
+
+static inline void fatent_init(struct fat_entry *fatent)
+{
+	fatent->nr_bhs = 0;
+	fatent->entry = 0;
+	fatent->u.ent32_p = NULL;
+	fatent->bhs[0] = fatent->bhs[1] = NULL;
+}
+
+static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
+{
+	fatent->entry = entry;
+	fatent->u.ent32_p = NULL;
+}
+
+static inline void fatent_brelse(struct fat_entry *fatent)
+{
+	int i;
+	fatent->u.ent32_p = NULL;
+	for (i = 0; i < fatent->nr_bhs; i++)
+		brelse(fatent->bhs[i]);
+	fatent->nr_bhs = 0;
+	fatent->bhs[0] = fatent->bhs[1] = NULL;
+}
+
+extern void fat_ent_access_init(struct super_block *sb);
+extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
+			int entry);
+extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+			 int new, int wait);
+extern int fat_alloc_clusters(struct inode *inode, int *cluster,
+			      int nr_cluster);
+extern int fat_free_clusters(struct inode *inode, int cluster);
+extern int fat_count_free_clusters(struct super_block *sb);
 
 /* fat/file.c */
+extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
 extern struct file_operations fat_file_operations;
 extern struct inode_operations fat_file_inode_operations;
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
@@ -338,35 +394,18 @@ extern void fat_attach(struct inode *ino
 extern void fat_detach(struct inode *inode);
 extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
 extern struct inode *fat_build_inode(struct super_block *sb,
-			struct msdos_dir_entry *de, loff_t i_pos, int *res);
-int fat_fill_super(struct super_block *sb, void *data, int silent,
-		   struct inode_operations *fs_dir_inode_ops, int isvfat);
+			struct msdos_dir_entry *de, loff_t i_pos);
+extern int fat_sync_inode(struct inode *inode);
+extern int fat_fill_super(struct super_block *sb, void *data, int silent,
+			struct inode_operations *fs_dir_inode_ops, int isvfat);
 
 /* fat/misc.c */
 extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
-extern void lock_fat(struct super_block *sb);
-extern void unlock_fat(struct super_block *sb);
 extern void fat_clusters_flush(struct super_block *sb);
-extern int fat_add_cluster(struct inode *inode);
+extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
 extern int date_dos2unix(unsigned short time, unsigned short date);
 extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
-extern int fat__get_entry(struct inode *dir, loff_t *pos,
-			  struct buffer_head **bh,
-			  struct msdos_dir_entry **de, loff_t *i_pos);
-static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
-				    struct buffer_head **bh,
-				    struct msdos_dir_entry **de, loff_t *i_pos)
-{
-	/* Fast stuff first */
-	if (*bh && *de &&
-	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
-		*pos += sizeof(struct msdos_dir_entry);
-		(*de)++;
-		(*i_pos)++;
-		return 0;
-	}
-	return fat__get_entry(dir, pos, bh, de, i_pos);
-}
+extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/mtio.h b/include/linux/mtio.h
--- a/include/linux/mtio.h
+++ b/include/linux/mtio.h
@@ -150,34 +150,6 @@ struct	mtpos {
 };
 
 
-/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
- * as an interim solution for QIC-02 until DDI is fully implemented.
- */
-struct mtconfiginfo {
-	long	mt_type;	/* drive type */
-	long	ifc_type;	/* interface card type */
-	unsigned short	irqnr;	/* IRQ number to use */
-	unsigned short	dmanr;	/* DMA channel to use */
-	unsigned short	port;	/* IO port base address */
-
-	unsigned long	debug;	/* debugging flags */
-
-	unsigned	have_dens:1;
-	unsigned	have_bsf:1;
-	unsigned	have_fsr:1;
-	unsigned	have_bsr:1;
-	unsigned	have_eod:1;
-	unsigned	have_seek:1;
-	unsigned	have_tell:1;
-	unsigned	have_ras1:1;
-	unsigned	have_ras2:1;
-	unsigned	have_ras3:1;
-	unsigned	have_qfa:1;
-
-	unsigned	pad1:5;
-	char		reserved[10];
-};
-
 /*  structure for MTIOCVOLINFO, query information about the volume
  *  currently positioned at (zftape)
  */
diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h
--- a/include/linux/mv643xx.h
+++ b/include/linux/mv643xx.h
@@ -1,5 +1,5 @@
 /*
- * mv64340.h - MV-64340 Internal registers definition file.
+ * mv643xx.h - MV-643XX Internal registers definition file.
  *
  * Copyright 2002 Momentum Computer, Inc.
  * 	Author: Matthew Dharm <mdharm@momenco.com>
@@ -10,8 +10,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#ifndef __ASM_MV64340_H
-#define __ASM_MV64340_H
+#ifndef __ASM_MV643XX_H
+#define __ASM_MV643XX_H
 
 #ifdef __MIPS__
 #include <asm/addrspace.h>
@@ -662,116 +662,119 @@
 /*        Ethernet Unit Registers  		*/
 /****************************************/
 
-#define MV64340_ETH_PHY_ADDR_REG                                    0x2000
-#define MV64340_ETH_SMI_REG                                         0x2004
-#define MV64340_ETH_UNIT_DEFAULT_ADDR_REG                           0x2008
-#define MV64340_ETH_UNIT_DEFAULTID_REG                              0x200c
-#define MV64340_ETH_UNIT_INTERRUPT_CAUSE_REG                        0x2080
-#define MV64340_ETH_UNIT_INTERRUPT_MASK_REG                         0x2084
-#define MV64340_ETH_UNIT_INTERNAL_USE_REG                           0x24fc
-#define MV64340_ETH_UNIT_ERROR_ADDR_REG                             0x2094
-#define MV64340_ETH_BAR_0                                           0x2200
-#define MV64340_ETH_BAR_1                                           0x2208
-#define MV64340_ETH_BAR_2                                           0x2210
-#define MV64340_ETH_BAR_3                                           0x2218
-#define MV64340_ETH_BAR_4                                           0x2220
-#define MV64340_ETH_BAR_5                                           0x2228
-#define MV64340_ETH_SIZE_REG_0                                      0x2204
-#define MV64340_ETH_SIZE_REG_1                                      0x220c
-#define MV64340_ETH_SIZE_REG_2                                      0x2214
-#define MV64340_ETH_SIZE_REG_3                                      0x221c
-#define MV64340_ETH_SIZE_REG_4                                      0x2224
-#define MV64340_ETH_SIZE_REG_5                                      0x222c
-#define MV64340_ETH_HEADERS_RETARGET_BASE_REG                       0x2230
-#define MV64340_ETH_HEADERS_RETARGET_CONTROL_REG                    0x2234
-#define MV64340_ETH_HIGH_ADDR_REMAP_REG_0                           0x2280
-#define MV64340_ETH_HIGH_ADDR_REMAP_REG_1                           0x2284
-#define MV64340_ETH_HIGH_ADDR_REMAP_REG_2                           0x2288
-#define MV64340_ETH_HIGH_ADDR_REMAP_REG_3                           0x228c
-#define MV64340_ETH_BASE_ADDR_ENABLE_REG                            0x2290
-#define MV64340_ETH_ACCESS_PROTECTION_REG(port)                    (0x2294 + (port<<2))
-#define MV64340_ETH_MIB_COUNTERS_BASE(port)                        (0x3000 + (port<<7))
-#define MV64340_ETH_PORT_CONFIG_REG(port)                          (0x2400 + (port<<10))
-#define MV64340_ETH_PORT_CONFIG_EXTEND_REG(port)                   (0x2404 + (port<<10))
-#define MV64340_ETH_MII_SERIAL_PARAMETRS_REG(port)                 (0x2408 + (port<<10))
-#define MV64340_ETH_GMII_SERIAL_PARAMETRS_REG(port)                (0x240c + (port<<10))
-#define MV64340_ETH_VLAN_ETHERTYPE_REG(port)                       (0x2410 + (port<<10))
-#define MV64340_ETH_MAC_ADDR_LOW(port)                             (0x2414 + (port<<10))
-#define MV64340_ETH_MAC_ADDR_HIGH(port)                            (0x2418 + (port<<10))
-#define MV64340_ETH_SDMA_CONFIG_REG(port)                          (0x241c + (port<<10))
-#define MV64340_ETH_DSCP_0(port)                                   (0x2420 + (port<<10))
-#define MV64340_ETH_DSCP_1(port)                                   (0x2424 + (port<<10))
-#define MV64340_ETH_DSCP_2(port)                                   (0x2428 + (port<<10))
-#define MV64340_ETH_DSCP_3(port)                                   (0x242c + (port<<10))
-#define MV64340_ETH_DSCP_4(port)                                   (0x2430 + (port<<10))
-#define MV64340_ETH_DSCP_5(port)                                   (0x2434 + (port<<10))
-#define MV64340_ETH_DSCP_6(port)                                   (0x2438 + (port<<10))
-#define MV64340_ETH_PORT_SERIAL_CONTROL_REG(port)                  (0x243c + (port<<10))
-#define MV64340_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port)            (0x2440 + (port<<10))
-#define MV64340_ETH_PORT_STATUS_REG(port)                          (0x2444 + (port<<10))
-#define MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port)               (0x2448 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_FIXED_PRIORITY(port)                  (0x244c + (port<<10))
-#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port)         (0x2450 + (port<<10))
-#define MV64340_ETH_MAXIMUM_TRANSMIT_UNIT(port)                    (0x2458 + (port<<10))
-#define MV64340_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port)           (0x245c + (port<<10))
-#define MV64340_ETH_INTERRUPT_CAUSE_REG(port)                      (0x2460 + (port<<10))
-#define MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port)               (0x2464 + (port<<10))
-#define MV64340_ETH_INTERRUPT_MASK_REG(port)                       (0x2468 + (port<<10))
-#define MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port)                (0x246c + (port<<10))
-#define MV64340_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2470 + (port<<10))
-#define MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2474 + (port<<10))
-#define MV64340_ETH_RX_MINIMAL_FRAME_SIZE_REG(port)                (0x247c + (port<<10))
-#define MV64340_ETH_RX_DISCARDED_FRAMES_COUNTER(port)              (0x2484 + (port<<10)
-#define MV64340_ETH_PORT_DEBUG_0_REG(port)                         (0x248c + (port<<10))
-#define MV64340_ETH_PORT_DEBUG_1_REG(port)                         (0x2490 + (port<<10))
-#define MV64340_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port)             (0x2494 + (port<<10))
-#define MV64340_ETH_INTERNAL_USE_REG(port)                         (0x24fc + (port<<10))
-#define MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port)                (0x2680 + (port<<10))
-#define MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(port)               (0x2684 + (port<<10))      
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x260c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x261c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x262c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x263c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x264c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x265c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x266c + (port<<10))     
-#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x267c + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x26c0 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x26c4 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x26c8 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x26cc + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x26d0 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x26d4 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x26d8 + (port<<10))     
-#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x26dc + (port<<10))     
-#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port)            (0x2700 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port)            (0x2710 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port)            (0x2720 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port)            (0x2730 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port)            (0x2740 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port)            (0x2750 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port)            (0x2760 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port)            (0x2770 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port)           (0x2704 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port)           (0x2714 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port)           (0x2724 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port)           (0x2734 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port)           (0x2744 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port)           (0x2754 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port)           (0x2764 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port)           (0x2774 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_0_ARBITER_CONFIG(port)                (0x2708 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_1_ARBITER_CONFIG(port)                (0x2718 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_2_ARBITER_CONFIG(port)                (0x2728 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_3_ARBITER_CONFIG(port)                (0x2738 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_4_ARBITER_CONFIG(port)                (0x2748 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_5_ARBITER_CONFIG(port)                (0x2758 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_6_ARBITER_CONFIG(port)                (0x2768 + (port<<10))
-#define MV64340_ETH_TX_QUEUE_7_ARBITER_CONFIG(port)                (0x2778 + (port<<10))
-#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port)               (0x2780 + (port<<10))
-#define MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port)   (0x3400 + (port<<10))
-#define MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port)     (0x3500 + (port<<10))
-#define MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE(port)             (0x3600 + (port<<10))
+#define MV643XX_ETH_SHARED_REGS                                     0x2000
+#define MV643XX_ETH_SHARED_REGS_SIZE                                0x2000
+
+#define MV643XX_ETH_PHY_ADDR_REG                                    0x2000
+#define MV643XX_ETH_SMI_REG                                         0x2004
+#define MV643XX_ETH_UNIT_DEFAULT_ADDR_REG                           0x2008
+#define MV643XX_ETH_UNIT_DEFAULTID_REG                              0x200c
+#define MV643XX_ETH_UNIT_INTERRUPT_CAUSE_REG                        0x2080
+#define MV643XX_ETH_UNIT_INTERRUPT_MASK_REG                         0x2084
+#define MV643XX_ETH_UNIT_INTERNAL_USE_REG                           0x24fc
+#define MV643XX_ETH_UNIT_ERROR_ADDR_REG                             0x2094
+#define MV643XX_ETH_BAR_0                                           0x2200
+#define MV643XX_ETH_BAR_1                                           0x2208
+#define MV643XX_ETH_BAR_2                                           0x2210
+#define MV643XX_ETH_BAR_3                                           0x2218
+#define MV643XX_ETH_BAR_4                                           0x2220
+#define MV643XX_ETH_BAR_5                                           0x2228
+#define MV643XX_ETH_SIZE_REG_0                                      0x2204
+#define MV643XX_ETH_SIZE_REG_1                                      0x220c
+#define MV643XX_ETH_SIZE_REG_2                                      0x2214
+#define MV643XX_ETH_SIZE_REG_3                                      0x221c
+#define MV643XX_ETH_SIZE_REG_4                                      0x2224
+#define MV643XX_ETH_SIZE_REG_5                                      0x222c
+#define MV643XX_ETH_HEADERS_RETARGET_BASE_REG                       0x2230
+#define MV643XX_ETH_HEADERS_RETARGET_CONTROL_REG                    0x2234
+#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_0                           0x2280
+#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_1                           0x2284
+#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_2                           0x2288
+#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_3                           0x228c
+#define MV643XX_ETH_BASE_ADDR_ENABLE_REG                            0x2290
+#define MV643XX_ETH_ACCESS_PROTECTION_REG(port)                    (0x2294 + (port<<2))
+#define MV643XX_ETH_MIB_COUNTERS_BASE(port)                        (0x3000 + (port<<7))
+#define MV643XX_ETH_PORT_CONFIG_REG(port)                          (0x2400 + (port<<10))
+#define MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port)                   (0x2404 + (port<<10))
+#define MV643XX_ETH_MII_SERIAL_PARAMETRS_REG(port)                 (0x2408 + (port<<10))
+#define MV643XX_ETH_GMII_SERIAL_PARAMETRS_REG(port)                (0x240c + (port<<10))
+#define MV643XX_ETH_VLAN_ETHERTYPE_REG(port)                       (0x2410 + (port<<10))
+#define MV643XX_ETH_MAC_ADDR_LOW(port)                             (0x2414 + (port<<10))
+#define MV643XX_ETH_MAC_ADDR_HIGH(port)                            (0x2418 + (port<<10))
+#define MV643XX_ETH_SDMA_CONFIG_REG(port)                          (0x241c + (port<<10))
+#define MV643XX_ETH_DSCP_0(port)                                   (0x2420 + (port<<10))
+#define MV643XX_ETH_DSCP_1(port)                                   (0x2424 + (port<<10))
+#define MV643XX_ETH_DSCP_2(port)                                   (0x2428 + (port<<10))
+#define MV643XX_ETH_DSCP_3(port)                                   (0x242c + (port<<10))
+#define MV643XX_ETH_DSCP_4(port)                                   (0x2430 + (port<<10))
+#define MV643XX_ETH_DSCP_5(port)                                   (0x2434 + (port<<10))
+#define MV643XX_ETH_DSCP_6(port)                                   (0x2438 + (port<<10))
+#define MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port)                  (0x243c + (port<<10))
+#define MV643XX_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port)            (0x2440 + (port<<10))
+#define MV643XX_ETH_PORT_STATUS_REG(port)                          (0x2444 + (port<<10))
+#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port)               (0x2448 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_FIXED_PRIORITY(port)                  (0x244c + (port<<10))
+#define MV643XX_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port)         (0x2450 + (port<<10))
+#define MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port)                    (0x2458 + (port<<10))
+#define MV643XX_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port)           (0x245c + (port<<10))
+#define MV643XX_ETH_INTERRUPT_CAUSE_REG(port)                      (0x2460 + (port<<10))
+#define MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port)               (0x2464 + (port<<10))
+#define MV643XX_ETH_INTERRUPT_MASK_REG(port)                       (0x2468 + (port<<10))
+#define MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port)                (0x246c + (port<<10))
+#define MV643XX_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2470 + (port<<10))
+#define MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2474 + (port<<10))
+#define MV643XX_ETH_RX_MINIMAL_FRAME_SIZE_REG(port)                (0x247c + (port<<10))
+#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port)              (0x2484 + (port<<10)
+#define MV643XX_ETH_PORT_DEBUG_0_REG(port)                         (0x248c + (port<<10))
+#define MV643XX_ETH_PORT_DEBUG_1_REG(port)                         (0x2490 + (port<<10))
+#define MV643XX_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port)             (0x2494 + (port<<10))
+#define MV643XX_ETH_INTERNAL_USE_REG(port)                         (0x24fc + (port<<10))
+#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port)                (0x2680 + (port<<10))
+#define MV643XX_ETH_CURRENT_SERVED_TX_DESC_PTR(port)               (0x2684 + (port<<10))      
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x260c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x261c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x262c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x263c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x264c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x265c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x266c + (port<<10))     
+#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x267c + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x26c0 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x26c4 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x26c8 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x26cc + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x26d0 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x26d4 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x26d8 + (port<<10))     
+#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x26dc + (port<<10))     
+#define MV643XX_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port)            (0x2700 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port)            (0x2710 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port)            (0x2720 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port)            (0x2730 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port)            (0x2740 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port)            (0x2750 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port)            (0x2760 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port)            (0x2770 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port)           (0x2704 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port)           (0x2714 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port)           (0x2724 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port)           (0x2734 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port)           (0x2744 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port)           (0x2754 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port)           (0x2764 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port)           (0x2774 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_0_ARBITER_CONFIG(port)                (0x2708 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_1_ARBITER_CONFIG(port)                (0x2718 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_2_ARBITER_CONFIG(port)                (0x2728 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_3_ARBITER_CONFIG(port)                (0x2738 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_4_ARBITER_CONFIG(port)                (0x2748 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_5_ARBITER_CONFIG(port)                (0x2758 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_6_ARBITER_CONFIG(port)                (0x2768 + (port<<10))
+#define MV643XX_ETH_TX_QUEUE_7_ARBITER_CONFIG(port)                (0x2778 + (port<<10))
+#define MV643XX_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port)               (0x2780 + (port<<10))
+#define MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port)   (0x3400 + (port<<10))
+#define MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port)     (0x3500 + (port<<10))
+#define MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port)             (0x3600 + (port<<10))
 
 /*******************************************/
 /*          CUNIT  Registers               */
@@ -977,12 +980,9 @@
 /* I2C Registers                        */
 /****************************************/
 
-#define MV64340_I2C_SLAVE_ADDR                                      0xc000
-#define MV64340_I2C_EXTENDED_SLAVE_ADDR                             0xc010
-#define MV64340_I2C_DATA                                            0xc004
-#define MV64340_I2C_CONTROL                                         0xc008
-#define MV64340_I2C_STATUS_BAUDE_RATE                               0xc00C
-#define MV64340_I2C_SOFT_RESET                                      0xc01c
+#define MV64XXX_I2C_CTLR_NAME					"mv64xxx i2c"
+#define MV64XXX_I2C_OFFSET                                          0xc000
+#define MV64XXX_I2C_REG_BLOCK_SIZE                                  0x0020
 
 /****************************************/
 /* GPP Interface Registers              */
@@ -1085,4 +1085,229 @@ struct mpsc_pdata {
 	u32	brg_clk_freq;
 };
 
-#endif /* __ASM_MV64340_H */
+/* i2c Platform Device, Driver Data */
+struct mv64xxx_i2c_pdata {
+	u32	freq_m;
+	u32	freq_n;
+	u32	timeout;	/* In milliseconds */
+	u32	retries;
+};
+
+/* These macros describe Ethernet Port configuration reg (Px_cR) bits */
+#define MV643XX_ETH_UNICAST_NORMAL_MODE		0
+#define MV643XX_ETH_UNICAST_PROMISCUOUS_MODE	(1<<0)
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_0		0
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_1		(1<<1)
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_2		(1<<2)
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_3		((1<<2) | (1<<1))
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_4		(1<<3)
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_5		((1<<3) | (1<<1))
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_6		((1<<3) | (1<<2))
+#define MV643XX_ETH_DEFAULT_RX_QUEUE_7		((1<<3) | (1<<2) | (1<<1))
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_0	0
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_1	(1<<4)
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_2	(1<<5)
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_3	((1<<5) | (1<<4))
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_4	(1<<6)
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_5	((1<<6) | (1<<4))
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_6	((1<<6) | (1<<5))
+#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_7	((1<<6) | (1<<5) | (1<<4))
+#define MV643XX_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP	0
+#define MV643XX_ETH_REJECT_BC_IF_NOT_IP_OR_ARP	(1<<7)
+#define MV643XX_ETH_RECEIVE_BC_IF_IP		0
+#define MV643XX_ETH_REJECT_BC_IF_IP		(1<<8)
+#define MV643XX_ETH_RECEIVE_BC_IF_ARP		0
+#define MV643XX_ETH_REJECT_BC_IF_ARP		(1<<9)
+#define MV643XX_ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY (1<<12)
+#define MV643XX_ETH_CAPTURE_TCP_FRAMES_DIS	0
+#define MV643XX_ETH_CAPTURE_TCP_FRAMES_EN	(1<<14)
+#define MV643XX_ETH_CAPTURE_UDP_FRAMES_DIS	0
+#define MV643XX_ETH_CAPTURE_UDP_FRAMES_EN	(1<<15)
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_0	0
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_1	(1<<16)
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_2	(1<<17)
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_3	((1<<17) | (1<<16))
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_4	(1<<18)
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_5	((1<<18) | (1<<16))
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_6	((1<<18) | (1<<17))
+#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_7	((1<<18) | (1<<17) | (1<<16))
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_0	0
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_1	(1<<19)
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_2	(1<<20)
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_3	((1<<20) | (1<<19))
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4	((1<<21)
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_5	((1<<21) | (1<<19))
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_6	((1<<21) | (1<<20))
+#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_7	((1<<21) | (1<<20) | (1<<19))
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_0	0
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_1	(1<<22)
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_2	(1<<23)
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_3	((1<<23) | (1<<22))
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_4	(1<<24)
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_5	((1<<24) | (1<<22))
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_6	((1<<24) | (1<<23))
+#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_7	((1<<24) | (1<<23) | (1<<22))
+
+#define	MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE			\
+		MV643XX_ETH_UNICAST_NORMAL_MODE		|	\
+		MV643XX_ETH_DEFAULT_RX_QUEUE_0		|	\
+		MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_0	|	\
+		MV643XX_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP	|	\
+		MV643XX_ETH_RECEIVE_BC_IF_IP		|	\
+		MV643XX_ETH_RECEIVE_BC_IF_ARP		|	\
+		MV643XX_ETH_CAPTURE_TCP_FRAMES_DIS	|	\
+		MV643XX_ETH_CAPTURE_UDP_FRAMES_DIS	|	\
+		MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_0	|	\
+		MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_0	|	\
+		MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+/* These macros describe Ethernet Port configuration extend reg (Px_cXR) bits*/
+#define MV643XX_ETH_CLASSIFY_EN				(1<<0)
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL		0
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7	(1<<1)
+#define MV643XX_ETH_PARTITION_DISABLE			0
+#define MV643XX_ETH_PARTITION_ENABLE			(1<<2)
+
+#define	MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE		\
+		MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL	|	\
+		MV643XX_ETH_PARTITION_DISABLE
+
+/* These macros describe Ethernet Port Sdma configuration reg (SDCR) bits */
+#define MV643XX_ETH_RIFB			(1<<0)
+#define MV643XX_ETH_RX_BURST_SIZE_1_64BIT		0
+#define MV643XX_ETH_RX_BURST_SIZE_2_64BIT		(1<<1)
+#define MV643XX_ETH_RX_BURST_SIZE_4_64BIT		(1<<2)
+#define MV643XX_ETH_RX_BURST_SIZE_8_64BIT		((1<<2) | (1<<1))
+#define MV643XX_ETH_RX_BURST_SIZE_16_64BIT		(1<<3)
+#define MV643XX_ETH_BLM_RX_NO_SWAP			(1<<4)
+#define MV643XX_ETH_BLM_RX_BYTE_SWAP			0
+#define MV643XX_ETH_BLM_TX_NO_SWAP			(1<<5)
+#define MV643XX_ETH_BLM_TX_BYTE_SWAP			0
+#define MV643XX_ETH_DESCRIPTORS_BYTE_SWAP		(1<<6)
+#define MV643XX_ETH_DESCRIPTORS_NO_SWAP			0
+#define MV643XX_ETH_TX_BURST_SIZE_1_64BIT		0
+#define MV643XX_ETH_TX_BURST_SIZE_2_64BIT		(1<<22)
+#define MV643XX_ETH_TX_BURST_SIZE_4_64BIT		(1<<23)
+#define MV643XX_ETH_TX_BURST_SIZE_8_64BIT		((1<<23) | (1<<22))
+#define MV643XX_ETH_TX_BURST_SIZE_16_64BIT		(1<<24)
+
+#define	MV643XX_ETH_IPG_INT_RX(value) ((value & 0x3fff) << 8)
+
+#define	MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE		\
+		MV643XX_ETH_RX_BURST_SIZE_4_64BIT	|	\
+		MV643XX_ETH_IPG_INT_RX(0)		|	\
+		MV643XX_ETH_TX_BURST_SIZE_4_64BIT
+
+/* These macros describe Ethernet Port serial control reg (PSCR) bits */
+#define MV643XX_ETH_SERIAL_PORT_DISABLE			0
+#define MV643XX_ETH_SERIAL_PORT_ENABLE			(1<<0)
+#define MV643XX_ETH_FORCE_LINK_PASS			(1<<1)
+#define MV643XX_ETH_DO_NOT_FORCE_LINK_PASS		0
+#define MV643XX_ETH_ENABLE_AUTO_NEG_FOR_DUPLX		0
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX		(1<<2)
+#define MV643XX_ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL	0
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL	(1<<3)
+#define MV643XX_ETH_ADV_NO_FLOW_CTRL			0
+#define MV643XX_ETH_ADV_SYMMETRIC_FLOW_CTRL		(1<<4)
+#define MV643XX_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX	0
+#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS		(1<<5)
+#define MV643XX_ETH_FORCE_BP_MODE_NO_JAM		0
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX		(1<<7)
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR	(1<<8)
+#define MV643XX_ETH_FORCE_LINK_FAIL			0
+#define MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL		(1<<10)
+#define MV643XX_ETH_RETRANSMIT_16_ATTEMPTS		0
+#define MV643XX_ETH_RETRANSMIT_FOREVER			(1<<11)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII		(1<<13)
+#define MV643XX_ETH_ENABLE_AUTO_NEG_SPEED_GMII		0
+#define MV643XX_ETH_DTE_ADV_0				0
+#define MV643XX_ETH_DTE_ADV_1				(1<<14)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_BYPASS		0
+#define MV643XX_ETH_ENABLE_AUTO_NEG_BYPASS		(1<<15)
+#define MV643XX_ETH_AUTO_NEG_NO_CHANGE			0
+#define MV643XX_ETH_RESTART_AUTO_NEG			(1<<16)
+#define MV643XX_ETH_MAX_RX_PACKET_1518BYTE		0
+#define MV643XX_ETH_MAX_RX_PACKET_1522BYTE		(1<<17)
+#define MV643XX_ETH_MAX_RX_PACKET_1552BYTE		(1<<18)
+#define MV643XX_ETH_MAX_RX_PACKET_9022BYTE		((1<<18) | (1<<17))
+#define MV643XX_ETH_MAX_RX_PACKET_9192BYTE		(1<<19)
+#define MV643XX_ETH_MAX_RX_PACKET_9700BYTE		((1<<19) | (1<<17))
+#define MV643XX_ETH_SET_EXT_LOOPBACK			(1<<20)
+#define MV643XX_ETH_CLR_EXT_LOOPBACK			0
+#define MV643XX_ETH_SET_FULL_DUPLEX_MODE		(1<<21)
+#define MV643XX_ETH_SET_HALF_DUPLEX_MODE		0
+#define MV643XX_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1<<22)
+#define MV643XX_ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0
+#define MV643XX_ETH_SET_GMII_SPEED_TO_10_100		0
+#define MV643XX_ETH_SET_GMII_SPEED_TO_1000		(1<<23)
+#define MV643XX_ETH_SET_MII_SPEED_TO_10			0
+#define MV643XX_ETH_SET_MII_SPEED_TO_100		(1<<24)
+
+#define	MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE		\
+		MV643XX_ETH_DO_NOT_FORCE_LINK_PASS	|	\
+		MV643XX_ETH_ENABLE_AUTO_NEG_FOR_DUPLX	|	\
+		MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL |	\
+		MV643XX_ETH_ADV_SYMMETRIC_FLOW_CTRL	|	\
+		MV643XX_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX |	\
+		MV643XX_ETH_FORCE_BP_MODE_NO_JAM	|	\
+		(1<<9)	/* reserved */			|	\
+		MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL	|	\
+		MV643XX_ETH_RETRANSMIT_16_ATTEMPTS	|	\
+		MV643XX_ETH_ENABLE_AUTO_NEG_SPEED_GMII	|	\
+		MV643XX_ETH_DTE_ADV_0			|	\
+		MV643XX_ETH_DISABLE_AUTO_NEG_BYPASS	|	\
+		MV643XX_ETH_AUTO_NEG_NO_CHANGE		|	\
+		MV643XX_ETH_MAX_RX_PACKET_9700BYTE	|	\
+		MV643XX_ETH_CLR_EXT_LOOPBACK		|	\
+		MV643XX_ETH_SET_FULL_DUPLEX_MODE	|	\
+		MV643XX_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+/* These macros describe Ethernet Serial Status reg (PSR) bits */
+#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT		(1<<0)
+#define MV643XX_ETH_PORT_STATUS_LINK_UP			(1<<1)
+#define MV643XX_ETH_PORT_STATUS_FULL_DUPLEX		(1<<2)
+#define MV643XX_ETH_PORT_STATUS_FLOW_CONTROL		(1<<3)
+#define MV643XX_ETH_PORT_STATUS_GMII_1000		(1<<4)
+#define MV643XX_ETH_PORT_STATUS_MII_100			(1<<5)
+/* PSR bit 6 is undocumented */
+#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS		(1<<7)
+#define MV643XX_ETH_PORT_STATUS_AUTONEG_BYPASSED	(1<<8)
+#define MV643XX_ETH_PORT_STATUS_PARTITION		(1<<9)
+#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY		(1<<10)
+/* PSR bits 11-31 are reserved */
+
+#define	MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE	800
+#define	MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE	400
+
+#define MV643XX_ETH_DESC_SIZE				64
+
+#define MV643XX_ETH_SHARED_NAME	"mv643xx_eth_shared"
+#define MV643XX_ETH_NAME	"mv643xx_eth"
+
+struct mv643xx_eth_platform_data {
+	/* 
+	 * Non-values for mac_addr, phy_addr, port_config, etc.
+	 * override the default value.  Setting the corresponding
+	 * force_* field, causes the default value to be overridden
+	 * even when zero.
+	 */
+	unsigned int	force_phy_addr:1;
+	unsigned int	force_port_config:1;
+	unsigned int	force_port_config_extend:1;
+	unsigned int	force_port_sdma_config:1;
+	unsigned int	force_port_serial_control:1;
+	int		phy_addr;
+	char		*mac_addr;	/* pointer to mac address */
+	u32		port_config;
+	u32		port_config_extend;
+	u32		port_sdma_config;
+	u32		port_serial_control;
+	u32		tx_queue_size;
+	u32		rx_queue_size;
+	u32		tx_sram_addr;
+	u32		tx_sram_size;
+	u32		rx_sram_addr;
+	u32		rx_sram_size;
+};
+
+#endif /* __ASM_MV643XX_H */
diff --git a/include/linux/namei.h b/include/linux/namei.h
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -39,12 +39,14 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LA
  *  - ending slashes ok even for nonexistent files
  *  - internal "there are more path compnents" flag
  *  - locked when lookup done with dcache_lock held
+ *  - dentry cache is untrusted; force a real lookup
  */
 #define LOOKUP_FOLLOW		 1
 #define LOOKUP_DIRECTORY	 2
 #define LOOKUP_CONTINUE		 4
 #define LOOKUP_PARENT		16
 #define LOOKUP_NOALT		32
+#define LOOKUP_REVAL		64
 /*
  * Intent data
  */
diff --git a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -7,7 +7,7 @@
  * Version:	@(#)net.h	1.0.3	05/25/93
  *
  * Authors:	Orest Zborowski, <obz@Kodak.COM>
- *		Ross Biro, <bir7@leland.Stanford.Edu>
+ *		Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
@@ -61,21 +61,22 @@ typedef enum {
 #define SOCK_ASYNC_NOSPACE	0
 #define SOCK_ASYNC_WAITDATA	1
 #define SOCK_NOSPACE		2
+#define SOCK_PASSCRED		3
 
 #ifndef ARCH_HAS_SOCKET_TYPES
-/** sock_type - Socket types
- * 
+/**
+ * enum sock_type - Socket types
+ * @SOCK_STREAM: stream (connection) socket
+ * @SOCK_DGRAM: datagram (conn.less) socket
+ * @SOCK_RAW: raw socket
+ * @SOCK_RDM: reliably-delivered message
+ * @SOCK_SEQPACKET: sequential packet socket
+ * @SOCK_PACKET: linux specific way of getting packets at the dev level.
+ *		  For writing rarp and other similar things on the user level.
+ *
  * When adding some new socket type please
  * grep ARCH_HAS_SOCKET_TYPE include/asm-* /socket.h, at least MIPS
  * overrides this enum for binary compat reasons.
- * 
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket 
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- *		  For writing rarp and other similar things on the user level.
  */
 enum sock_type {
 	SOCK_STREAM	= 1,
@@ -92,15 +93,14 @@ enum sock_type {
 
 /**
  *  struct socket - general BSD socket
- *  @state - socket state (%SS_CONNECTED, etc)
- *  @flags - socket flags (%SOCK_ASYNC_NOSPACE, etc)
- *  @ops - protocol specific socket operations
- *  @fasync_list - Asynchronous wake up list
- *  @file - File back pointer for gc
- *  @sk - internal networking protocol agnostic socket representation
- *  @wait - wait queue for several uses
- *  @type - socket type (%SOCK_STREAM, etc)
- *  @passcred - credentials (used only in Unix Sockets (aka PF_LOCAL))
+ *  @state: socket state (%SS_CONNECTED, etc)
+ *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
+ *  @ops: protocol specific socket operations
+ *  @fasync_list: Asynchronous wake up list
+ *  @file: File back pointer for gc
+ *  @sk: internal networking protocol agnostic socket representation
+ *  @wait: wait queue for several uses
+ *  @type: socket type (%SOCK_STREAM, etc)
  */
 struct socket {
 	socket_state		state;
@@ -111,7 +111,6 @@ struct socket {
 	struct sock		*sk;
 	wait_queue_head_t	wait;
 	short			type;
-	unsigned char		passcred;
 };
 
 struct vm_area_struct;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)dev.h	1.0.10	08/12/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
  *		Donald J. Becker, <becker@cesdis.gsfc.nasa.gov>
@@ -41,7 +41,7 @@
 struct divert_blk;
 struct vlan_group;
 struct ethtool_ops;
-
+struct netpoll;
 					/* source back-compat hooks */
 #define SET_ETHTOOL_OPS(netdev,ops) \
 	( (netdev)->ethtool_ops = (ops) )
@@ -204,7 +204,7 @@ struct hh_cache
 	/* cached hardware header; allow for machine alignment needs.        */
 #define HH_DATA_MOD	16
 #define HH_DATA_OFF(__len) \
-	(HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
+	(HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1))
 #define HH_DATA_ALIGN(__len) \
 	(((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
 	unsigned long	hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
@@ -328,9 +328,7 @@ struct net_device
 	unsigned short		flags;	/* interface flags (a la BSD)	*/
 	unsigned short		gflags;
         unsigned short          priv_flags; /* Like 'flags' but invisible to userspace. */
-        unsigned short          unused_alignment_fixer; /* Because we need priv_flags,
-                                                         * and we want to be 32-bit aligned.
-                                                         */
+	unsigned short		padded;	/* How much padding added by alloc_netdev() */
 
 	unsigned		mtu;	/* interface MTU value		*/
 	unsigned short		type;	/* interface hardware type	*/
@@ -403,7 +401,7 @@ struct net_device
 	} reg_state;
 
 	/* Net device features */
-	int			features;
+	unsigned long		features;
 #define NETIF_F_SG		1	/* Scatter/gather IO. */
 #define NETIF_F_IP_CSUM		2	/* Can checksum only TCP/UDP over IPv4. */
 #define NETIF_F_NO_CSUM		4	/* Does not require checksum. F.e. loopack. */
@@ -469,9 +467,8 @@ struct net_device
 	int			(*hard_header_parse)(struct sk_buff *skb,
 						     unsigned char *haddr);
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
-	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
 #ifdef CONFIG_NETPOLL
-	int			netpoll_rx;
+	struct netpoll		*np;
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	void                    (*poll_controller)(struct net_device *dev);
@@ -487,8 +484,6 @@ struct net_device
 
 	/* class/net/name entry */
 	struct class_device	class_dev;
-	/* how much padding had been added by alloc_netdev() */
-	int padded;
 };
 
 #define	NETDEV_ALIGN		32
@@ -508,7 +503,7 @@ static inline void *netdev_priv(struct n
 #define SET_NETDEV_DEV(net, pdev)	((net)->class_dev.dev = (pdev))
 
 struct packet_type {
-	unsigned short		type;	/* This is really htons(ether_type).	*/
+	__be16			type;	/* This is really htons(ether_type).	*/
 	struct net_device		*dev;	/* NULL is wildcarded here		*/
 	int			(*func) (struct sk_buff *, struct net_device *,
 					 struct packet_type *);
@@ -678,6 +673,8 @@ extern unsigned		dev_get_flags(const str
 extern int		dev_change_flags(struct net_device *, unsigned);
 extern int		dev_change_name(struct net_device *, char *);
 extern int		dev_set_mtu(struct net_device *, int);
+extern int		dev_set_mac_address(struct net_device *,
+					    struct sockaddr *);
 extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 
 extern void		dev_init(void);
@@ -916,13 +913,12 @@ extern void		dev_mc_discard(struct net_d
 extern void		dev_set_promiscuity(struct net_device *dev, int inc);
 extern void		dev_set_allmulti(struct net_device *dev, int inc);
 extern void		netdev_state_change(struct net_device *dev);
+extern void		netdev_features_change(struct net_device *dev);
 /* Load a device via the kmod */
 extern void		dev_load(const char *name);
 extern void		dev_mcast_init(void);
 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);
 extern int skb_checksum_help(struct sk_buff *skb, int inward);
 /* rx skb timestamps */
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -18,7 +18,8 @@
 #define NF_STOLEN 2
 #define NF_QUEUE 3
 #define NF_REPEAT 4
-#define NF_MAX_VERDICT NF_REPEAT
+#define NF_STOP 5
+#define NF_MAX_VERDICT NF_STOP
 
 /* Generic cache responses from hook functions.
    <= 0x2000 is used for protocol-flags. */
@@ -138,21 +139,32 @@ void nf_log_packet(int pf,
 /* This is gross, but inline doesn't cut it for avoiding the function
    call in fast path: gcc doesn't inline (needs value tracking?). --RR */
 #ifdef CONFIG_NETFILTER_DEBUG
-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)			\
- nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)
-#define NF_HOOK_THRESH nf_hook_slow
+#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)			       \
+({int __ret;								       \
+if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
+	__ret = (okfn)(skb);						       \
+__ret;})
+#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)	       \
+({int __ret;								       \
+if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
+	__ret = (okfn)(skb);						       \
+__ret;})
 #else
-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)			\
-(list_empty(&nf_hooks[(pf)][(hook)])					\
- ? (okfn)(skb)								\
- : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN))
-#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)	\
-(list_empty(&nf_hooks[(pf)][(hook)])					\
- ? (okfn)(skb)								\
- : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), (thresh)))
+#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)			       \
+({int __ret;								       \
+if (list_empty(&nf_hooks[pf][hook]) ||					       \
+    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
+	__ret = (okfn)(skb);						       \
+__ret;})
+#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)	       \
+({int __ret;								       \
+if (list_empty(&nf_hooks[pf][hook]) ||					       \
+    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
+	__ret = (okfn)(skb);						       \
+__ret;})
 #endif
 
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
 		 struct net_device *indev, struct net_device *outdev,
 		 int (*okfn)(struct sk_buff *), int thresh);
 
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -154,7 +154,7 @@ struct arpt_entry
 #define ARPT_CONTINUE 0xFFFFFFFF
 
 /* For standard target */
-#define ARPT_RETURN (-NF_MAX_VERDICT - 1)
+#define ARPT_RETURN (-NF_REPEAT - 1)
 
 /* The argument to ARPT_SO_GET_INFO */
 struct arpt_getinfo
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -62,6 +62,9 @@ enum nf_ip_hook_priorities {
 	NF_IP_PRI_FILTER = 0,
 	NF_IP_PRI_NAT_SRC = 100,
 	NF_IP_PRI_SELINUX_LAST = 225,
+	NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2,
+	NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1,
+	NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
 	NF_IP_PRI_LAST = INT_MAX,
 };
 
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
@@ -23,13 +23,16 @@ enum tcp_conntrack {
 /* SACK is permitted by the sender */
 #define IP_CT_TCP_FLAG_SACK_PERM		0x02
 
+/* This sender sent FIN first */
+#define IP_CT_TCP_FLAG_CLOSE_INIT		0x03
+
 struct ip_ct_tcp_state {
 	u_int32_t	td_end;		/* max of seq + len */
 	u_int32_t	td_maxend;	/* max of ack + max(win, 1) */
 	u_int32_t	td_maxwin;	/* max(win) */
 	u_int8_t	td_scale;	/* window scale factor */
 	u_int8_t	loose;		/* used when connection picked up from the middle */
-	u_int8_t	flags;		/* per direction state flags */
+	u_int8_t	flags;		/* per direction options */
 };
 
 struct ip_ct_tcp
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -166,7 +166,7 @@ struct ipt_entry
 #define IPT_CONTINUE 0xFFFFFFFF
 
 /* For standard target */
-#define IPT_RETURN (-NF_MAX_VERDICT - 1)
+#define IPT_RETURN (-NF_REPEAT - 1)
 
 /* TCP matching stuff */
 struct ipt_tcp
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -166,7 +166,7 @@ struct ip6t_entry
 #define IP6T_CONTINUE 0xFFFFFFFF
 
 /* For standard target */
-#define IP6T_RETURN (-NF_MAX_VERDICT - 1)
+#define IP6T_RETURN (-NF_REPEAT - 1)
 
 /* TCP matching stuff */
 struct ip6t_tcp
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -110,6 +110,7 @@ struct netlink_skb_parms
 	__u32			dst_pid;
 	__u32			dst_groups;
 	kernel_cap_t		eff_cap;
+	__u32			loginuid;	/* Login (audit) uid */
 };
 
 #define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -16,11 +16,14 @@ struct netpoll;
 struct netpoll {
 	struct net_device *dev;
 	char dev_name[16], *name;
+	int rx_flags;
 	void (*rx_hook)(struct netpoll *, int, char *, int);
+	void (*drop)(struct sk_buff *skb);
 	u32 local_ip, remote_ip;
 	u16 local_port, remote_port;
 	unsigned char local_mac[6], remote_mac[6];
-	struct list_head rx_list;
+	spinlock_t poll_lock;
+	int poll_owner;
 };
 
 void netpoll_poll(struct netpoll *np);
@@ -30,7 +33,35 @@ int netpoll_setup(struct netpoll *np);
 int netpoll_trap(void);
 void netpoll_set_trap(int trap);
 void netpoll_cleanup(struct netpoll *np);
-int netpoll_rx(struct sk_buff *skb);
+int __netpoll_rx(struct sk_buff *skb);
+void netpoll_queue(struct sk_buff *skb);
 
+#ifdef CONFIG_NETPOLL
+static inline int netpoll_rx(struct sk_buff *skb)
+{
+	return skb->dev->np && skb->dev->np->rx_flags && __netpoll_rx(skb);
+}
+
+static inline void netpoll_poll_lock(struct net_device *dev)
+{
+	if (dev->np) {
+		spin_lock(&dev->np->poll_lock);
+		dev->np->poll_owner = smp_processor_id();
+	}
+}
+
+static inline void netpoll_poll_unlock(struct net_device *dev)
+{
+	if (dev->np) {
+		spin_unlock(&dev->np->poll_lock);
+		dev->np->poll_owner = -1;
+	}
+}
+
+#else
+#define netpoll_rx(a) 0
+#define netpoll_poll_lock(a)
+#define netpoll_poll_unlock(a)
+#endif
 
 #endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -345,17 +345,14 @@ extern struct inode_operations nfs_dir_i
 extern struct file_operations nfs_dir_operations;
 extern struct dentry_operations nfs_dentry_operations;
 
+extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+
 /*
  * linux/fs/nfs/symlink.c
  */
 extern struct inode_operations nfs_symlink_inode_operations;
 
 /*
- * linux/fs/nfs/locks.c
- */
-extern int nfs_lock(struct file *, int, struct file_lock *);
-
-/*
  * linux/fs/nfs/unlink.c
  */
 extern int  nfs_async_unlink(struct dentry *);
@@ -379,11 +376,8 @@ extern void nfs_commit_done(struct rpc_t
  * return value!)
  */
 extern int  nfs_sync_inode(struct inode *, unsigned long, unsigned int, int);
-extern int  nfs_flush_inode(struct inode *, unsigned long, unsigned int, int);
-extern int  nfs_flush_list(struct list_head *, int, int);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 extern int  nfs_commit_inode(struct inode *, unsigned long, unsigned int, int);
-extern int  nfs_commit_list(struct list_head *, int);
 #else
 static inline int
 nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how)
@@ -424,7 +418,6 @@ static inline int nfs_wb_page(struct ino
  * Allocate and free nfs_write_data structures
  */
 extern mempool_t *nfs_wdata_mempool;
-extern mempool_t *nfs_commit_mempool;
 
 static inline struct nfs_write_data *nfs_writedata_alloc(void)
 {
@@ -441,23 +434,6 @@ static inline void nfs_writedata_free(st
 	mempool_free(p, nfs_wdata_mempool);
 }
 
-extern void  nfs_writedata_release(struct rpc_task *task);
-
-static inline struct nfs_write_data *nfs_commit_alloc(void)
-{
-	struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
-	if (p) {
-		memset(p, 0, sizeof(*p));
-		INIT_LIST_HEAD(&p->pages);
-	}
-	return p;
-}
-
-static inline void nfs_commit_free(struct nfs_write_data *p)
-{
-	mempool_free(p, nfs_commit_mempool);
-}
-
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
@@ -469,7 +445,6 @@ static inline void nfs_commit_free(struc
 extern int  nfs_readpage(struct file *, struct page *);
 extern int  nfs_readpages(struct file *, struct address_space *,
 		struct list_head *, unsigned);
-extern int  nfs_pagein_list(struct list_head *, int);
 extern void nfs_readpage_result(struct rpc_task *);
 
 /*
@@ -610,6 +585,9 @@ struct nfs4_client {
 	wait_queue_head_t	cl_waitq;
 	struct rpc_wait_queue	cl_rpcwaitq;
 
+	/* used for the setclientid verifier */
+	struct timespec		cl_boot_time;
+
 	/* idmapper */
 	struct idmap *		cl_idmap;
 
@@ -617,6 +595,7 @@ struct nfs4_client {
 	 * This is used to generate the clientid, and the callback address.
 	 */
 	char			cl_ipaddr[16];
+	unsigned char		cl_id_uniquifier;
 };
 
 /*
@@ -696,21 +675,26 @@ struct nfs4_exception {
 	int retry;
 };
 
+struct nfs4_state_recovery_ops {
+	int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);
+	int (*recover_lock)(struct nfs4_state *, struct file_lock *);
+};
+
 extern struct dentry_operations nfs4_dentry_operations;
 extern struct inode_operations nfs4_dir_inode_operations;
 
 /* nfs4proc.c */
+extern int nfs4_map_errors(int err);
 extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
 extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
-extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
 extern int nfs4_proc_async_renew(struct nfs4_client *);
 extern int nfs4_proc_renew(struct nfs4_client *);
 extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode);
-extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *);
 extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);
-extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
-extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request);
+
+extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
+extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
 
 /* nfs4renewd.c */
 extern void nfs4_schedule_state_renewal(struct nfs4_client *);
@@ -728,6 +712,7 @@ extern u32 nfs4_alloc_lockowner_id(struc
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
+extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_close_state(struct nfs4_state *, mode_t);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -53,5 +53,6 @@ struct nfs_server {
 #define NFS_CAP_HARDLINKS	(1U << 1)
 #define NFS_CAP_SYMLINKS	(1U << 2)
 #define NFS_CAP_ACLS		(1U << 3)
+#define NFS_CAP_ATOMIC_OPEN	(1U << 4)
 
 #endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -563,6 +563,7 @@ struct nfs4_readdir_arg {
 	u32				count;
 	struct page **			pages;	/* zero-copy data */
 	unsigned int			pgbase;	/* zero-copy data */
+	const u32 *			bitmask;
 };
 
 struct nfs4_readdir_res {
@@ -681,7 +682,7 @@ struct nfs_rpc_ops {
 	int	(*read)    (struct nfs_read_data *);
 	int	(*write)   (struct nfs_write_data *);
 	int	(*commit)  (struct nfs_write_data *);
-	struct inode *	(*create)  (struct inode *, struct dentry *,
+	int	(*create)  (struct inode *, struct dentry *,
 			    struct iattr *, int);
 	int	(*remove)  (struct inode *, struct qstr *);
 	int	(*unlink_setup)  (struct rpc_message *,
@@ -693,13 +694,12 @@ struct nfs_rpc_ops {
 	int	(*symlink) (struct inode *, struct qstr *, struct qstr *,
 			    struct iattr *, struct nfs_fh *,
 			    struct nfs_fattr *);
-	int	(*mkdir)   (struct inode *, struct qstr *, struct iattr *,
-			    struct nfs_fh *, struct nfs_fattr *);
+	int	(*mkdir)   (struct inode *, struct dentry *, struct iattr *);
 	int	(*rmdir)   (struct inode *, struct qstr *);
 	int	(*readdir) (struct dentry *, struct rpc_cred *,
 			    u64, struct page *, unsigned int, int);
-	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
-			    dev_t, struct nfs_fh *, struct nfs_fattr *);
+	int	(*mknod)   (struct inode *, struct dentry *, struct iattr *,
+			    dev_t);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsstat *);
 	int	(*fsinfo)  (struct nfs_server *, struct nfs_fh *,
@@ -731,7 +731,5 @@ extern struct nfs_rpc_ops	nfs_v4_cliento
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
 extern struct rpc_version	nfs_version4;
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
 
 #endif
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -19,10 +19,9 @@
  * be hash_next and hash_prev.
  */
 struct svc_cacherep {
-	struct svc_cacherep *	c_hash_next;
-	struct svc_cacherep *	c_hash_prev;
-	struct svc_cacherep *	c_lru_next;
-	struct svc_cacherep *	c_lru_prev;
+	struct hlist_node	c_hash;
+	struct list_head	c_lru;
+
 	unsigned char		c_state,	/* unused, inprog, done */
 				c_type,		/* status, buffer */
 				c_secure : 1;	/* req came from port < 1024 */
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -96,9 +96,9 @@ int		nfsd_commit(struct svc_rqst *, stru
 int		nfsd_open(struct svc_rqst *, struct svc_fh *, int,
 				int, struct file **);
 void		nfsd_close(struct file *);
-int		nfsd_read(struct svc_rqst *, struct svc_fh *,
-				loff_t, struct kvec *,int, unsigned long *);
-int		nfsd_write(struct svc_rqst *, struct svc_fh *,
+int 		nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+				loff_t, struct kvec *, int, unsigned long *);
+int 		nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
 				loff_t, struct kvec *,int, unsigned long, int *);
 int		nfsd_readlink(struct svc_rqst *, struct svc_fh *,
 				char *, int *);
@@ -129,15 +129,15 @@ int		nfsd_permission(struct svc_export *
  * NFSv4 State
  */
 #ifdef CONFIG_NFSD_V4
-void nfs4_state_init(void);
+int nfs4_state_init(void);
 void nfs4_state_shutdown(void);
 time_t nfs4_lease_time(void);
 void nfs4_reset_lease(time_t leasetime);
 #else
-void static inline nfs4_state_init(void){}
-void static inline nfs4_state_shutdown(void){}
-time_t static inline nfs4_lease_time(void){return 0;}
-void static inline nfs4_reset_lease(time_t leasetime){}
+static inline int nfs4_state_init(void){return 0;}
+static inline void nfs4_state_shutdown(void){}
+static inline time_t nfs4_lease_time(void){return 0;}
+static inline void nfs4_reset_lease(time_t leasetime){}
 #endif
 
 /*
@@ -209,6 +209,7 @@ void		nfsd_lockd_shutdown(void);
 #define	nfserr_no_grace		__constant_htonl(NFSERR_NO_GRACE)
 #define	nfserr_reclaim_bad	__constant_htonl(NFSERR_RECLAIM_BAD)
 #define	nfserr_badname		__constant_htonl(NFSERR_BADNAME)
+#define	nfserr_cb_path_down	__constant_htonl(NFSERR_CB_PATH_DOWN)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -67,12 +67,6 @@ extern stateid_t onestateid;
 #define ZERO_STATEID(stateid)       (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)        (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
 
-/* Delegation recall states */
-#define NFS4_NO_RECALL			0x000
-#define NFS4_RECALL_IN_PROGRESS		0x001
-#define NFS4_RECALL_COMPLETE		0x002
-#define NFS4_REAP_DELEG			0x004
-
 struct nfs4_cb_recall {
 	u32			cbr_ident;
 	int			cbr_trunc;
@@ -86,13 +80,11 @@ struct nfs4_delegation {
 	struct list_head	dl_del_perfile; /* nfs4_file->fi_del_perfile */
 	struct list_head	dl_del_perclnt; /* nfs4_client->cl_del_perclnt*/
 	struct list_head	dl_recall_lru;  /* delegation recalled */
-	atomic_t		dl_recall_cnt;  /* resend cb_recall only once */
 	atomic_t		dl_count;       /* ref count */
-	atomic_t		dl_state;       /* recall state */
 	struct nfs4_client	*dl_client;
 	struct nfs4_file	*dl_file;
 	struct file_lock	*dl_flock;
-	struct nfs4_stateid	*dl_stp;
+	struct file		*dl_vfs_file;
 	u32			dl_type;
 	time_t			dl_time;
 	struct nfs4_cb_recall	dl_recall;
@@ -141,7 +133,6 @@ struct nfs4_client {
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
 	struct nfs4_callback	cl_callback;    /* callback info */
-	time_t			cl_first_state; /* first state aquisition*/
 	atomic_t		cl_count;	/* ref count */
 };
 
@@ -153,8 +144,6 @@ struct nfs4_client {
 struct nfs4_client_reclaim {
 	struct list_head	cr_strhash;	/* hash by cr_name */
 	struct xdr_netobj 	cr_name; 	/* id generated by client */
-	time_t			cr_first_state; /* first state aquisition */
-	u32			cr_expired;     /* boolean: lease expired? */
 };
 
 static inline void
@@ -258,7 +247,6 @@ struct nfs4_stateid {
 	struct nfs4_file            * st_file;
 	stateid_t                     st_stateid;
 	struct file                 * st_vfs_file;
-	int                           st_vfs_set;
 	unsigned long                 st_access_bmap;
 	unsigned long                 st_deny_bmap;
 };
@@ -282,7 +270,7 @@ struct nfs4_stateid {
 extern time_t nfs4_laundromat(void);
 extern int nfsd4_renew(clientid_t *clid);
 extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, 
-		stateid_t *stateid, int flags);
+		stateid_t *stateid, int flags, struct file **filp);
 extern int nfs4_share_conflict(struct svc_fh *current_fh, 
 		unsigned int deny_type);
 extern void nfs4_lock_state(void);
@@ -292,7 +280,8 @@ extern int nfs4_check_open_reclaim(clien
 extern void put_nfs4_client(struct nfs4_client *clp);
 extern void nfs4_free_stateowner(struct kref *kref);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
-extern int nfsd4_cb_recall(struct nfs4_delegation *dp);
+extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
+extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 
 static inline void
 nfs4_put_stateowner(struct nfs4_stateowner *so)
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -241,6 +241,7 @@ struct nfsd4_read {
 	u32		rd_length;          /* request */
 	struct kvec	rd_iov[RPCSVC_MAXPAGES];
 	int		rd_vlen;
+	struct file     *rd_filp;
 	
 	struct svc_rqst *rd_rqstp;          /* response */
 	struct svc_fh * rd_fhp;             /* response */
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -10,6 +10,8 @@
  *
  * For details of nodemask_scnprintf() and nodemask_parse(),
  * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ * For details of nodelist_scnprintf() and nodelist_parse(), see
+ * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
  *
  * The available nodemask operations are:
  *
@@ -48,6 +50,8 @@
  *
  * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
  * int nodemask_parse(ubuf, ulen, mask)	Parse ascii string as nodemask
+ * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
+ * int nodelist_parse(buf, map)		Parse ascii string as nodelist
  *
  * for_each_node_mask(node, mask)	for-loop node over mask
  *
@@ -281,14 +285,28 @@ static inline int __nodemask_scnprintf(c
 	return bitmap_scnprintf(buf, len, srcp->bits, nbits);
 }
 
-#define nodemask_parse(ubuf, ulen, src) \
-			__nodemask_parse((ubuf), (ulen), &(src), MAX_NUMNODES)
+#define nodemask_parse(ubuf, ulen, dst) \
+			__nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES)
 static inline int __nodemask_parse(const char __user *buf, int len,
 					nodemask_t *dstp, int nbits)
 {
 	return bitmap_parse(buf, len, dstp->bits, nbits);
 }
 
+#define nodelist_scnprintf(buf, len, src) \
+			__nodelist_scnprintf((buf), (len), &(src), MAX_NUMNODES)
+static inline int __nodelist_scnprintf(char *buf, int len,
+					const nodemask_t *srcp, int nbits)
+{
+	return bitmap_scnlistprintf(buf, len, srcp->bits, nbits);
+}
+
+#define nodelist_parse(buf, dst) __nodelist_parse((buf), &(dst), MAX_NUMNODES)
+static inline int __nodelist_parse(const char *buf, nodemask_t *dstp, int nbits)
+{
+	return bitmap_parselist(buf, dstp->bits, nbits);
+}
+
 #if MAX_NUMNODES > 1
 #define for_each_node_mask(node, mask)			\
 	for ((node) = first_node(mask);			\
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -56,6 +56,7 @@ extern int notifier_call_chain(struct no
 #define NETDEV_CHANGEADDR	0x0008
 #define NETDEV_GOING_DOWN	0x0009
 #define NETDEV_CHANGENAME	0x000A
+#define NETDEV_FEAT_CHANGE	0x000B
 
 #define SYS_DOWN	0x0001	/* Notify of system down */
 #define SYS_RESTART	SYS_DOWN
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -75,7 +75,7 @@
 #define PG_mappedtodisk		17	/* Has blocks allocated on-disk */
 #define PG_reclaim		18	/* To be reclaimed asap */
 #define PG_nosave_free		19	/* Free, should not be written */
-
+#define PG_uncached		20	/* Page has been mapped as uncached */
 
 /*
  * Global page accounting.  One instance per CPU.  Only unsigned longs are
@@ -131,6 +131,7 @@ struct page_state {
 	unsigned long allocstall;	/* direct reclaim calls */
 
 	unsigned long pgrotated;	/* pages rotated to tail of the LRU */
+	unsigned long nr_bounce;	/* pages for bounce buffers */
 };
 
 extern void get_page_state(struct page_state *ret);
@@ -301,10 +302,13 @@ extern void __mod_page_state(unsigned of
 #define PageSwapCache(page)	0
 #endif
 
+#define PageUncached(page)	test_bit(PG_uncached, &(page)->flags)
+#define SetPageUncached(page)	set_bit(PG_uncached, &(page)->flags)
+#define ClearPageUncached(page)	clear_bit(PG_uncached, &(page)->flags)
+
 struct page;	/* forward declaration */
 
 int test_clear_page_dirty(struct page *page);
-int __clear_page_dirty(struct page *page);
 int test_clear_page_writeback(struct page *page);
 int test_set_page_writeback(struct page *page);
 
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -19,7 +19,7 @@
 #define	AS_EIO		(__GFP_BITS_SHIFT + 0)	/* IO error on async write */
 #define AS_ENOSPC	(__GFP_BITS_SHIFT + 1)	/* ENOSPC on async write */
 
-static inline int mapping_gfp_mask(struct address_space * mapping)
+static inline unsigned int __nocast mapping_gfp_mask(struct address_space * mapping)
 {
 	return mapping->flags & __GFP_BITS_MASK;
 }
diff --git a/include/linux/parport.h b/include/linux/parport.h
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -105,8 +105,6 @@ typedef enum {
 #include <asm/ptrace.h>
 #include <asm/semaphore.h>
 
-#define PARPORT_NEED_GENERIC_OPS
-
 /* Define this later. */
 struct parport;
 struct pardevice;
@@ -520,9 +518,8 @@ extern int parport_device_proc_register(
 extern int parport_device_proc_unregister(struct pardevice *device);
 
 /* 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_NOT_PC)
 
-#undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
 #define parport_write_data(p,x)            parport_pc_write_data(p,x)
 #define parport_read_data(p)               parport_pc_read_data(p)
@@ -534,9 +531,9 @@ extern int parport_device_proc_unregiste
 #define parport_disable_irq(p)             parport_pc_disable_irq(p)
 #define parport_data_forward(p)            parport_pc_data_forward(p)
 #define parport_data_reverse(p)            parport_pc_data_reverse(p)
-#endif
 
-#ifdef PARPORT_NEED_GENERIC_OPS
+#else  /*  !CONFIG_PARPORT_NOT_PC  */
+
 /* Generic operations vector through the dispatch table. */
 #define parport_write_data(p,x)            (p)->ops->write_data(p,x)
 #define parport_read_data(p)               (p)->ops->read_data(p)
@@ -548,7 +545,8 @@ extern int parport_device_proc_unregiste
 #define parport_disable_irq(p)             (p)->ops->disable_irq(p)
 #define parport_data_forward(p)            (p)->ops->data_forward(p)
 #define parport_data_reverse(p)            (p)->ops->data_reverse(p)
-#endif
+
+#endif /*  !CONFIG_PARPORT_NOT_PC  */
 
 #endif /* __KERNEL__ */
 #endif /* _PARPORT_H_ */
diff --git a/include/linux/patchkey.h b/include/linux/patchkey.h
new file mode 100644
--- /dev/null
+++ b/include/linux/patchkey.h
@@ -0,0 +1,45 @@
+/*
+ * <linux/patchkey.h> -- definition of _PATCHKEY macro
+ *
+ * Copyright (C) 2005 Stuart Brady
+ *
+ * This exists because awe_voice.h defined its own _PATCHKEY and it wasn't
+ * clear whether removing this would break anything in userspace.
+ *
+ * Do not include this file directly.  Please use <sys/soundcard.h> instead.
+ * For kernel code, use <linux/soundcard.h>
+ */
+
+#ifndef _LINUX_PATCHKEY_H_INDIRECT
+#error "patchkey.h included directly"
+#endif
+
+#ifndef _LINUX_PATCHKEY_H
+#define _LINUX_PATCHKEY_H
+
+/* Endian macros. */
+#ifdef __KERNEL__
+#  include <asm/byteorder.h>
+#else
+#  include <endian.h>
+#endif
+
+#if defined(__KERNEL__)
+#  if defined(__BIG_ENDIAN)
+#    define _PATCHKEY(id) (0xfd00|id)
+#  elif defined(__LITTLE_ENDIAN)
+#    define _PATCHKEY(id) ((id<<8)|0x00fd)
+#  else
+#    error "could not determine byte order"
+#  endif
+#elif defined(__BYTE_ORDER)
+#  if __BYTE_ORDER == __BIG_ENDIAN
+#    define _PATCHKEY(id) (0xfd00|id)
+#  elif __BYTE_ORDER == __LITTLE_ENDIAN
+#    define _PATCHKEY(id) ((id<<8)|0x00fd)
+#  else
+#    error "could not determine byte order"
+#  endif
+#endif
+
+#endif /* _LINUX_PATCHKEY_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -501,6 +501,7 @@ typedef int __bitwise pci_power_t;
 #define PCI_D2	((pci_power_t __force) 2)
 #define PCI_D3hot	((pci_power_t __force) 3)
 #define PCI_D3cold	((pci_power_t __force) 4)
+#define PCI_POWER_ERROR	((pci_power_t __force) -1)
 
 /*
  * The pci_dev structure is used to describe PCI devices.
@@ -549,8 +550,6 @@ struct pci_dev {
 	unsigned int	irq;
 	struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
 
-	char *		slot_name;	/* pointer to dev.bus_id */
-
 	/* These fields are used by common fixups */
 	unsigned int	transparent:1;	/* Transparent PCI bridge */
 	unsigned int	multifunction:1;/* Part of multi-function device */
@@ -563,7 +562,7 @@ struct pci_dev {
 	int rom_attr_enabled;		/* has display of the rom attribute been enabled? */
 	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
 #ifdef CONFIG_PCI_NAMES
-#define PCI_NAME_SIZE	96
+#define PCI_NAME_SIZE	255
 #define PCI_NAME_HALF	__stringify(43)	/* less than half to handle slop */
 	char		pretty_name[PCI_NAME_SIZE];	/* pretty name for users to see */
 #endif
@@ -642,8 +641,10 @@ struct pci_ops {
 };
 
 struct pci_raw_ops {
-	int (*read)(int dom, int bus, int devfn, int reg, int len, u32 *val);
-	int (*write)(int dom, int bus, int devfn, int reg, int len, u32 val);
+	int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
+		    int reg, int len, u32 *val);
+	int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn,
+		     int reg, int len, u32 val);
 };
 
 extern struct pci_raw_ops *raw_pci_ops;
@@ -669,7 +670,8 @@ struct pci_driver {
 	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
 	int  (*suspend) (struct pci_dev *dev, pm_message_t state);	/* Device suspended */
 	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
-	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
+	int  (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);   /* Enable wake event */
+	void (*shutdown) (struct pci_dev *dev);
 
 	struct device_driver	driver;
 	struct pci_dynids dynids;
@@ -809,7 +811,6 @@ void pci_set_master(struct pci_dev *dev)
 int pci_set_mwi(struct pci_dev *dev);
 void pci_clear_mwi(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
-int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
@@ -940,7 +941,6 @@ static inline void pci_set_master(struct
 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_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
-static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
 static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
 static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
@@ -952,7 +952,7 @@ static inline const struct pci_device_id
 static inline int pci_save_state(struct pci_dev *dev) { return 0; }
 static inline int pci_restore_state(struct pci_dev *dev) { return 0; }
 static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { return 0; }
-static inline pci_power_t pci_choose_state(struct pci_dev *dev, u32 state) { return PCI_D0; }
+static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
 
 #define	isa_bridge	((struct pci_dev *)NULL)
@@ -966,9 +966,8 @@ static inline int pci_enable_wake(struct
  */
 #ifndef CONFIG_PCI_DOMAINS
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
-static inline int pci_name_bus(char *name, struct pci_bus *bus)
+static inline int pci_proc_domain(struct pci_bus *bus)
 {
-	sprintf(name, "%02x", bus->number);
 	return 0;
 }
 #endif
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -352,10 +352,21 @@
 #define PCI_DEVICE_ID_ATI_RS300_133	0x5831
 #define PCI_DEVICE_ID_ATI_RS300_166	0x5832
 #define PCI_DEVICE_ID_ATI_RS300_200	0x5833
+#define PCI_DEVICE_ID_ATI_RS350_100     0x7830
+#define PCI_DEVICE_ID_ATI_RS350_133     0x7831
+#define PCI_DEVICE_ID_ATI_RS350_166     0x7832
+#define PCI_DEVICE_ID_ATI_RS350_200     0x7833
+#define PCI_DEVICE_ID_ATI_RS400_100     0x5a30
+#define PCI_DEVICE_ID_ATI_RS400_133     0x5a31
+#define PCI_DEVICE_ID_ATI_RS400_166     0x5a32
+#define PCI_DEVICE_ID_ATI_RS400_200     0x5a33
+#define PCI_DEVICE_ID_ATI_RS480         0x5950
 /* ATI IXP Chipset */
 #define PCI_DEVICE_ID_ATI_IXP200_IDE	0x4349
 #define PCI_DEVICE_ID_ATI_IXP300_IDE	0x4369
+#define PCI_DEVICE_ID_ATI_IXP300_SATA   0x436e
 #define PCI_DEVICE_ID_ATI_IXP400_IDE	0x4376
+#define PCI_DEVICE_ID_ATI_IXP400_SATA   0x4379
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -386,6 +397,8 @@
 #define PCI_DEVICE_ID_NS_SCx200_VIDEO	0x0504
 #define PCI_DEVICE_ID_NS_SCx200_XBUS	0x0505
 #define PCI_DEVICE_ID_NS_SC1100_BRIDGE	0x0510
+#define PCI_DEVICE_ID_NS_SC1100_SMI	0x0511
+#define PCI_DEVICE_ID_NS_SC1100_XBUS	0x0515
 #define PCI_DEVICE_ID_NS_87410		0xd001
 
 #define PCI_VENDOR_ID_TSENG		0x100c
@@ -506,6 +519,7 @@
 #define PCI_DEVICE_ID_AMD_OPUS_7449	0x7449
 #	define PCI_DEVICE_ID_AMD_VIPER_7449	PCI_DEVICE_ID_AMD_OPUS_7449
 #define PCI_DEVICE_ID_AMD_8111_LAN	0x7462
+#define PCI_DEVICE_ID_AMD_8111_LPC	0x7468
 #define PCI_DEVICE_ID_AMD_8111_IDE	0x7469
 #define PCI_DEVICE_ID_AMD_8111_SMBUS2	0x746a
 #define PCI_DEVICE_ID_AMD_8111_SMBUS	0x746b
@@ -695,7 +709,10 @@
 #define PCI_DEVICE_ID_HP_SX1000_IOC	0x127c
 #define PCI_DEVICE_ID_HP_DIVA_EVEREST	0x1282
 #define PCI_DEVICE_ID_HP_DIVA_AUX	0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3	0x1301
 #define PCI_DEVICE_ID_HP_CISSA		0x3220
+#define PCI_DEVICE_ID_HP_CISSB		0x3230
+#define PCI_DEVICE_ID_HP_ZX2_IOC	0x4031
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
@@ -753,6 +770,7 @@
 #define PCI_DEVICE_ID_TI_1251B		0xac1f
 #define PCI_DEVICE_ID_TI_4410		0xac41
 #define PCI_DEVICE_ID_TI_4451		0xac42
+#define PCI_DEVICE_ID_TI_4510		0xac44
 #define PCI_DEVICE_ID_TI_4520		0xac46
 #define PCI_DEVICE_ID_TI_1410		0xac50
 #define PCI_DEVICE_ID_TI_1420		0xac51
@@ -792,6 +810,7 @@
 #define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
 #define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
 #define PCI_DEVICE_ID_MOTOROLA_HARRIER	0x480b
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200	0x5803
 
 #define PCI_VENDOR_ID_PROMISE		0x105a
 #define PCI_DEVICE_ID_PROMISE_20265	0x0d30
@@ -835,6 +854,7 @@
 #define PCI_DEVICE_ID_MYLEX_DAC960_LA	0x0020
 #define PCI_DEVICE_ID_MYLEX_DAC960_LP	0x0050
 #define PCI_DEVICE_ID_MYLEX_DAC960_BA	0xBA56
+#define PCI_DEVICE_ID_MYLEX_DAC960_GEM	0xB166
 
 #define PCI_VENDOR_ID_PICOP		0x1066
 #define PCI_DEVICE_ID_PICOP_PT86C52X	0x0001
@@ -854,6 +874,7 @@
 #define PCI_DEVICE_ID_APPLE_KL_USB_P	0x0026
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P	0x0027
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15	0x002d
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15	0x002e
 #define PCI_DEVICE_ID_APPLE_UNI_N_FW2	0x0030
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2	0x0032
 #define PCI_DEVIEC_ID_APPLE_UNI_N_ATA	0x0033
@@ -861,7 +882,13 @@
 #define PCI_DEVICE_ID_APPLE_IPID_ATA100	0x003b
 #define PCI_DEVICE_ID_APPLE_KEYLARGO_I	0x003e
 #define PCI_DEVICE_ID_APPLE_K2_ATA100	0x0043
+#define PCI_DEVICE_ID_APPLE_U3_AGP	0x004b
 #define PCI_DEVICE_ID_APPLE_K2_GMAC	0x004c
+#define PCI_DEVICE_ID_APPLE_SH_ATA      0x0050
+#define PCI_DEVICE_ID_APPLE_SH_SUNGEM   0x0051
+#define PCI_DEVICE_ID_APPLE_SH_FW       0x0052
+#define PCI_DEVICE_ID_APPLE_U3L_AGP	0x0058
+#define PCI_DEVICE_ID_APPLE_U3H_AGP	0x0059
 #define PCI_DEVICE_ID_APPLE_TIGON3	0x1645
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073
@@ -1091,6 +1118,7 @@
 #define PCI_DEVICE_ID_NVIDIA_TNT		0x0020
 #define PCI_DEVICE_ID_NVIDIA_TNT2		0x0028
 #define PCI_DEVICE_ID_NVIDIA_UTNT2		0x0029
+#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN        0x002a
 #define PCI_DEVICE_ID_NVIDIA_VTNT2		0x002C
 #define PCI_DEVICE_ID_NVIDIA_UVTNT2		0x002D
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE	0x0035
@@ -1098,6 +1126,12 @@
 #define PCI_DEVICE_ID_NVIDIA_NVENET_10		0x0037
 #define PCI_DEVICE_ID_NVIDIA_NVENET_11		0x0038
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2	0x003e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800       0x0041
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE    0x0042
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT    0x0045
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000     0x004E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS	0x0052
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE	0x0053
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA	0x0054
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2	0x0055
@@ -1114,6 +1148,12 @@
 #define PCI_DEVICE_ID_NVIDIA_NVENET_5		0x008c
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA	0x008e
 #define PCI_DEVICE_ID_NVIDIA_ITNT2		0x00A0
+#define PCI_DEVICE_ID_GEFORCE_6800A             0x00c1
+#define PCI_DEVICE_ID_GEFORCE_6800A_LE          0x00c2
+#define PCI_DEVICE_ID_GEFORCE_GO_6800           0x00c8
+#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA     0x00c9
+#define PCI_DEVICE_ID_QUADRO_FX_GO1400          0x00cc
+#define PCI_DEVICE_ID_QUADRO_FX_1400            0x00ce
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3		0x00d1
 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO		0x00da
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS	0x00d4
@@ -1134,21 +1174,43 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2	0x0111
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO	0x0112
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR	0x0113
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT	0x0140
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600	0x0141
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL	0x0145
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540	0x014E
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200	0x014F
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS	0x0150
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2	0x0151
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200    0x0164
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250    0x0166
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1  0x0167
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1  0x0168
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460	0x0170
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440	0x0171
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420	0x0172
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE	0x0173
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO	0x0174
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO	0x0175
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO    0x0177
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL	0x0178
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_200	0x017A
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL	0x017B
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL	0x017C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO    0x0186
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO    0x0187
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL    0x0188
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC    0x0189
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS    0x018A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL    0x018B
 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
 #define PCI_DEVICE_ID_NVIDIA_NFORCE		0x01a4
 #define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO		0x01b1
@@ -1160,13 +1222,67 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC		0x0203
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B      0x0211
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE   0x0212
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT   0x0215
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600	0x0250
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400	0x0251
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200	0x0253
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL	0x0258
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL	0x0259
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL	0x025B
-#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200	0x0329
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE	0x0265
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA	0x0266
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2	0x0267
+#define PCI_DEVICE_ID_NVIDIA_NVENET_12		0x0268
+#define PCI_DEVICE_ID_NVIDIA_NVENET_13		0x0269
+#define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO	0x026B
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800	0x0280
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X    0x0281
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE     0x0282
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO       0x0286
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL        0x0288
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL        0x0289
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL       0x028C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA  0x0301
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800        0x0302
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000         0x0308
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000         0x0309
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA  0x0311
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600        0x0312
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE      0x0314
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600      0x031A
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650      0x031B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700        0x031C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200        0x0320
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA  0x0321
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1      0x0322
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE      0x0323
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200      0x0324
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250      0x0325
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500        0x0326
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100        0x0327
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32   0x0328
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200	    0x0329
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI     0x032A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500          0x032B
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300      0x032C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100      0x032D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA  0x0330
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900        0x0331
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT      0x0332
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA  0x0333
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT      0x0334
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000         0x0338
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700          0x033F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA  0x0341
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700        0x0342
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE      0x0343
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE      0x0344
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1    0x0347
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
 
 #define PCI_VENDOR_ID_IMS		0x10e0
 #define PCI_DEVICE_ID_IMS_8849		0x8849
@@ -1418,6 +1534,10 @@
 #define PCI_DEVICE_ID_DIGI_DF_M_E	0x0071
 #define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A	0x0072
 #define PCI_DEVICE_ID_DIGI_DF_M_A	0x0073
+#define PCI_DEVICE_ID_NEO_2DB9          0x00C8
+#define PCI_DEVICE_ID_NEO_2DB9PRI       0x00C9
+#define PCI_DEVICE_ID_NEO_2RJ45         0x00CA
+#define PCI_DEVICE_ID_NEO_2RJ45PRI      0x00CB
 
 #define PCI_VENDOR_ID_MUTECH		0x1159
 #define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
@@ -1497,6 +1617,9 @@
 #define PCI_DEVICE_ID_ARTOP_AEC7612D	0x8040
 #define PCI_DEVICE_ID_ARTOP_AEC7612SUW	0x8050
 #define PCI_DEVICE_ID_ARTOP_8060	0x8060
+#define PCI_DEVICE_ID_ARTOP_AEC67160	0x8080
+#define PCI_DEVICE_ID_ARTOP_AEC67160_2	0x8081
+#define PCI_DEVICE_ID_ARTOP_AEC67162	0x808a
 
 #define PCI_VENDOR_ID_ZEITNET		0x1193
 #define PCI_DEVICE_ID_ZEITNET_1221	0x0001
@@ -1609,6 +1732,10 @@
 #define PCI_DEVICE_ID_PC300_TE_M_2	0x0320
 #define PCI_DEVICE_ID_PC300_TE_M_1	0x0321
 
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT    		0x1259
+#define PCI_SUBDEVICE_ID_AT_2701FX	0x2703
+
 #define PCI_VENDOR_ID_ESSENTIAL		0x120f
 #define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
 
@@ -1652,6 +1779,11 @@
 #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
 #define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT    		0x1259
+#define PCI_SUBDEVICE_ID_AT_2700FX	0x2701
+#define PCI_SUBDEVICE_ID_AT_2701FX	0x2703
+
 #define PCI_VENDOR_ID_ESS		0x125d
 #define PCI_DEVICE_ID_ESS_ESS1968	0x1968
 #define PCI_DEVICE_ID_ESS_AUDIOPCI	0x1969
@@ -1789,6 +1921,7 @@
 #define PCI_DEVICE_ID_SEALEVEL_UCOMM232	0x7202
 #define PCI_DEVICE_ID_SEALEVEL_COMM4	0x7401
 #define PCI_DEVICE_ID_SEALEVEL_COMM8	0x7801
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM8	0x7804
 
 #define PCI_VENDOR_ID_HYPERCOPE		0x1365
 #define PCI_DEVICE_ID_HYPERCOPE_PLX	0x9050
@@ -1905,6 +2038,8 @@
 #define PCI_DEVICE_ID_OXSEMI_16PCI954PP	0x9513
 #define PCI_DEVICE_ID_OXSEMI_16PCI952	0x9521
 
+#define PCI_VENDOR_ID_SAMSUNG		0x144d
+
 #define PCI_VENDOR_ID_AIRONET		0x14b9
 #define PCI_DEVICE_ID_AIRONET_4800_1	0x0001
 #define PCI_DEVICE_ID_AIRONET_4800	0x4500 // values switched?  see
@@ -1935,12 +2070,15 @@
 #define PCI_DEVICE_ID_AFAVLAB_P030	0x2182
 
 #define PCI_VENDOR_ID_BROADCOM		0x14e4
+#define PCI_DEVICE_ID_TIGON3_5752	0x1600
+#define PCI_DEVICE_ID_TIGON3_5752M	0x1601
 #define PCI_DEVICE_ID_TIGON3_5700	0x1644
 #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_5704S_2	0x1649
+#define PCI_DEVICE_ID_NX2_5706		0x164a
 #define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
 #define PCI_DEVICE_ID_TIGON3_5705	0x1653
 #define PCI_DEVICE_ID_TIGON3_5705_2	0x1654
@@ -1960,6 +2098,7 @@
 #define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
 #define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
 #define PCI_DEVICE_ID_TIGON3_5704S	0x16a8
+#define PCI_DEVICE_ID_NX2_5706S		0x16aa
 #define PCI_DEVICE_ID_TIGON3_5702A3	0x16c6
 #define PCI_DEVICE_ID_TIGON3_5703A3	0x16c7
 #define PCI_DEVICE_ID_TIGON3_5781	0x16dd
@@ -1995,6 +2134,8 @@
 #define PCI_DEVICE_ID_MELLANOX_TAVOR	0x5a44
 #define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
 #define PCI_DEVICE_ID_MELLANOX_ARBEL	0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI	0x6274
 
 #define PCI_VENDOR_ID_PDC		0x15e9
 #define PCI_DEVICE_ID_PDC_1841		0x1841
@@ -2032,13 +2173,15 @@
 #define PCI_VENDOR_ID_S2IO		0x17d5
 #define	PCI_DEVICE_ID_S2IO_WIN		0x5731
 #define	PCI_DEVICE_ID_S2IO_UNI		0x5831
+#define PCI_DEVICE_ID_HERC_WIN		0x5732
+#define PCI_DEVICE_ID_HERC_UNI		0x5832
 
 #define PCI_VENDOR_ID_INFINICON		0x1820
 
 #define PCI_VENDOR_ID_TOPSPIN		0x1867
 
-#define PCI_VENDOR_ID_ARC               0x192E
-#define PCI_DEVICE_ID_ARC_EHCI          0x0101
+#define PCI_VENDOR_ID_TDI               0x192E
+#define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
@@ -2240,6 +2383,8 @@
 #define PCI_DEVICE_ID_INTEL_82915G_IG	0x2582
 #define PCI_DEVICE_ID_INTEL_82915GM_HB	0x2590
 #define PCI_DEVICE_ID_INTEL_82915GM_IG	0x2592
+#define PCI_DEVICE_ID_INTEL_82945G_HB	0x2770
+#define PCI_DEVICE_ID_INTEL_82945G_IG	0x2772
 #define PCI_DEVICE_ID_INTEL_ICH6_0	0x2640
 #define PCI_DEVICE_ID_INTEL_ICH6_1	0x2641
 #define PCI_DEVICE_ID_INTEL_ICH6_2	0x2642
@@ -2260,11 +2405,31 @@
 #define PCI_DEVICE_ID_INTEL_ICH6_17	0x266d
 #define PCI_DEVICE_ID_INTEL_ICH6_18	0x266e
 #define PCI_DEVICE_ID_INTEL_ICH6_19	0x266f
+#define PCI_DEVICE_ID_INTEL_ESB2_0	0x2670
+#define PCI_DEVICE_ID_INTEL_ESB2_1	0x2680
+#define PCI_DEVICE_ID_INTEL_ESB2_2	0x2681
+#define PCI_DEVICE_ID_INTEL_ESB2_3	0x2682
+#define PCI_DEVICE_ID_INTEL_ESB2_4	0x2683
+#define PCI_DEVICE_ID_INTEL_ESB2_5	0x2688
+#define PCI_DEVICE_ID_INTEL_ESB2_6	0x2689
+#define PCI_DEVICE_ID_INTEL_ESB2_7	0x268a
+#define PCI_DEVICE_ID_INTEL_ESB2_8	0x268b
+#define PCI_DEVICE_ID_INTEL_ESB2_9	0x268c
+#define PCI_DEVICE_ID_INTEL_ESB2_10	0x2690
+#define PCI_DEVICE_ID_INTEL_ESB2_11	0x2692
+#define PCI_DEVICE_ID_INTEL_ESB2_12	0x2694
+#define PCI_DEVICE_ID_INTEL_ESB2_13	0x2696
+#define PCI_DEVICE_ID_INTEL_ESB2_14	0x2698
+#define PCI_DEVICE_ID_INTEL_ESB2_15	0x2699
+#define PCI_DEVICE_ID_INTEL_ESB2_16	0x269a
+#define PCI_DEVICE_ID_INTEL_ESB2_17	0x269b
+#define PCI_DEVICE_ID_INTEL_ESB2_18	0x269e
 #define PCI_DEVICE_ID_INTEL_ICH7_0	0x27b8
-#define PCI_DEVICE_ID_INTEL_ICH7_1	0x27b1
+#define PCI_DEVICE_ID_INTEL_ICH7_1	0x27b9
 #define PCI_DEVICE_ID_INTEL_ICH7_2	0x27c0
 #define PCI_DEVICE_ID_INTEL_ICH7_3	0x27c1
-#define PCI_DEVICE_ID_INTEL_ICH7_4	0x27c2
+#define PCI_DEVICE_ID_INTEL_ICH7_30	0x27b0
+#define PCI_DEVICE_ID_INTEL_ICH7_31	0x27bd
 #define PCI_DEVICE_ID_INTEL_ICH7_5	0x27c4
 #define PCI_DEVICE_ID_INTEL_ICH7_6	0x27c5
 #define PCI_DEVICE_ID_INTEL_ICH7_7	0x27c8
@@ -2285,6 +2450,18 @@
 #define PCI_DEVICE_ID_INTEL_ICH7_22	0x27e0
 #define PCI_DEVICE_ID_INTEL_ICH7_23	0x27e2
 #define PCI_DEVICE_ID_INTEL_82855PM_HB	0x3340
+#define PCI_DEVICE_ID_INTEL_ESB2_19	0x3500
+#define PCI_DEVICE_ID_INTEL_ESB2_20	0x3501
+#define PCI_DEVICE_ID_INTEL_ESB2_21	0x3504
+#define PCI_DEVICE_ID_INTEL_ESB2_22	0x3505
+#define PCI_DEVICE_ID_INTEL_ESB2_23	0x350c
+#define PCI_DEVICE_ID_INTEL_ESB2_24	0x350d
+#define PCI_DEVICE_ID_INTEL_ESB2_25	0x3510
+#define PCI_DEVICE_ID_INTEL_ESB2_26	0x3511
+#define PCI_DEVICE_ID_INTEL_ESB2_27	0x3514
+#define PCI_DEVICE_ID_INTEL_ESB2_28	0x3515
+#define PCI_DEVICE_ID_INTEL_ESB2_29	0x3518
+#define PCI_DEVICE_ID_INTEL_ESB2_30	0x3519
 #define PCI_DEVICE_ID_INTEL_82830_HB	0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC	0x3577
 #define PCI_DEVICE_ID_INTEL_82855GM_HB	0x3580
@@ -2396,6 +2573,7 @@
 #define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
 #define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
 #define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
+#define PCI_DEVICE_ID_ADAPTEC2_SCAMP	0x0503
 
 #define PCI_VENDOR_ID_ATRONICS		0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015	0x2015
@@ -2405,13 +2583,15 @@
 
 #define PCI_VENDOR_ID_NETMOS		0x9710
 #define PCI_DEVICE_ID_NETMOS_9705	0x9705
+#define PCI_DEVICE_ID_NETMOS_9715	0x9715
 #define PCI_DEVICE_ID_NETMOS_9735	0x9735
+#define PCI_DEVICE_ID_NETMOS_9745	0x9745
+#define PCI_DEVICE_ID_NETMOS_9755	0x9755
 #define PCI_DEVICE_ID_NETMOS_9805	0x9805
 #define PCI_DEVICE_ID_NETMOS_9815	0x9815
 #define PCI_DEVICE_ID_NETMOS_9835	0x9835
+#define PCI_DEVICE_ID_NETMOS_9845	0x9845
 #define PCI_DEVICE_ID_NETMOS_9855	0x9855
-#define PCI_DEVICE_ID_NETMOS_9755	0x9755
-#define PCI_DEVICE_ID_NETMOS_9715	0x9715
 
 #define PCI_SUBVENDOR_ID_EXSYS		0xd84d
 #define PCI_SUBDEVICE_ID_EXSYS_4014	0x4014
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -59,7 +59,7 @@ struct pcie_port_service_driver {
 	int (*probe) (struct pcie_device *dev, 
 		const struct pcie_port_service_id *id);
 	void (*remove) (struct pcie_device *dev);
-	int (*suspend) (struct pcie_device *dev, u32 state);
+	int (*suspend) (struct pcie_device *dev, pm_message_t state);
 	int (*resume) (struct pcie_device *dev);
 
 	const struct pcie_port_service_id *id_table;
diff --git a/include/linux/personality.h b/include/linux/personality.h
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -18,6 +18,7 @@ extern int		__set_personality(unsigned l
  * These occupy the top three bytes.
  */
 enum {
+	ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization of VA space */
 	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
 						 * (signal handling)
 						 */
@@ -35,7 +36,7 @@ enum {
  * Security-relevant compatibility flags that must be
  * cleared upon setuid or setgid exec:
  */
-#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC)
+#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE)
 
 /*
  * Personality types.
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -80,6 +80,7 @@ enum
 	TCA_ACT_KIND,
 	TCA_ACT_OPTIONS,
 	TCA_ACT_INDEX,
+	TCA_ACT_STATS,
 	__TCA_ACT_MAX
 };
 
@@ -221,14 +222,20 @@ struct tc_u32_sel
 	struct tc_u32_key	keys[0];
 };
 
-#ifdef CONFIG_CLS_U32_PERF
+struct tc_u32_mark
+{
+	__u32		val;
+	__u32		mask;
+	__u32		success;
+};
+
 struct tc_u32_pcnt
 {
 	__u64 rcnt;
 	__u64 rhit;
 	__u64 kcnts[0];
 };
-#endif
+
 /* Flags */
 
 #define TC_U32_TERMINAL		1
@@ -319,4 +326,101 @@ enum
 
 #define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
 
+/* Basic filter */
+
+enum
+{
+	TCA_BASIC_UNSPEC,
+	TCA_BASIC_CLASSID,
+	TCA_BASIC_EMATCHES,
+	TCA_BASIC_ACT,
+	TCA_BASIC_POLICE,
+	__TCA_BASIC_MAX
+};
+
+#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
+
+/* Extended Matches */
+
+struct tcf_ematch_tree_hdr
+{
+	__u16		nmatches;
+	__u16		progid;
+};
+
+enum
+{
+	TCA_EMATCH_TREE_UNSPEC,
+	TCA_EMATCH_TREE_HDR,
+	TCA_EMATCH_TREE_LIST,
+	__TCA_EMATCH_TREE_MAX
+};
+#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1)
+
+struct tcf_ematch_hdr
+{
+	__u16		matchid;
+	__u16		kind;
+	__u16		flags;
+	__u16		pad; /* currently unused */
+};
+
+/*  0                   1
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+ * +-----------------------+-+-+---+
+ * |         Unused        |S|I| R |
+ * +-----------------------+-+-+---+
+ *
+ * R(2) ::= relation to next ematch
+ *          where: 0 0 END (last ematch)
+ *                 0 1 AND
+ *                 1 0 OR
+ *                 1 1 Unused (invalid)
+ * I(1) ::= invert result
+ * S(1) ::= simple payload
+ */
+#define TCF_EM_REL_END	0
+#define TCF_EM_REL_AND	(1<<0)
+#define TCF_EM_REL_OR	(1<<1)
+#define TCF_EM_INVERT	(1<<2)
+#define TCF_EM_SIMPLE	(1<<3)
+
+#define TCF_EM_REL_MASK	3
+#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK)
+
+enum
+{
+	TCF_LAYER_LINK,
+	TCF_LAYER_NETWORK,
+	TCF_LAYER_TRANSPORT,
+	__TCF_LAYER_MAX
+};
+#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
+
+/* Ematch type assignments
+ *   1..32767		Reserved for ematches inside kernel tree
+ *   32768..65535	Free to use, not reliable
+ */
+enum
+{
+	TCF_EM_CONTAINER,
+	TCF_EM_CMP,
+	TCF_EM_NBYTE,
+	TCF_EM_U32,
+	TCF_EM_META,
+	__TCF_EM_MAX
+};
+
+enum
+{
+	TCF_EM_PROG_TC
+};
+
+enum
+{
+	TCF_EM_OPND_EQ,
+	TCF_EM_OPND_GT,
+	TCF_EM_OPND_LT
+};
+
 #endif
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -427,6 +427,7 @@ enum
 	TCA_NETEM_UNSPEC,
 	TCA_NETEM_CORR,
 	TCA_NETEM_DELAY_DIST,
+	TCA_NETEM_REORDER,
 	__TCA_NETEM_MAX,
 };
 
@@ -437,7 +438,7 @@ struct tc_netem_qopt
 	__u32	latency;	/* added delay (us) */
 	__u32   limit;		/* fifo limit (packets) */
 	__u32	loss;		/* random packet loss (0=none ~0=100%) */
-	__u32	gap;		/* re-ordering gap (0 for delay all) */
+	__u32	gap;		/* re-ordering gap (0 for none) */
 	__u32   duplicate;	/* random packet dup  (0=none ~0=100%) */
 	__u32	jitter;		/* random jitter in latency (us) */
 };
@@ -449,6 +450,12 @@ struct tc_netem_corr
 	__u32	dup_corr;	/* duplicate correlation  */
 };
 
+struct tc_netem_reorder
+{
+	__u32	probability;
+	__u32	correlation;
+};
+
 #define NETEM_DIST_SCALE	8192
 
 #endif
diff --git a/include/linux/pm.h b/include/linux/pm.h
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -116,11 +116,6 @@ void __deprecated pm_unregister(struct p
 void __deprecated pm_unregister_all(pm_callback callback);
 
 /*
- * Send a request to a single device
- */
-int __deprecated pm_send(struct pm_dev *dev, pm_request_t rqst, void *data);
-
-/*
  * Send a request to all devices
  */
 int __deprecated pm_send_all(pm_request_t rqst, void *data);
@@ -140,11 +135,6 @@ static inline void pm_unregister(struct 
 
 static inline void pm_unregister_all(pm_callback callback) {}
 
-static inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-	return 0;
-}
-
 static inline int pm_send_all(pm_request_t rqst, void *data)
 {
 	return 0;
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -378,7 +378,6 @@ int pnp_register_dma_resource(struct pnp
 int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data);
 int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data);
 void pnp_init_resource_table(struct pnp_resource_table *table);
-int pnp_assign_resources(struct pnp_dev *dev, int depnum);
 int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode);
 int pnp_auto_config_dev(struct pnp_dev *dev);
 int pnp_validate_config(struct pnp_dev *dev);
@@ -423,7 +422,6 @@ static inline int pnp_register_dma_resou
 static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; }
 static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; }
 static inline void pnp_init_resource_table(struct pnp_resource_table *table) { }
-static inline int pnp_assign_resources(struct pnp_dev *dev, int depnum) { return -ENODEV; }
 static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; }
 static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; }
diff --git a/include/linux/poll.h b/include/linux/poll.h
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -71,13 +71,9 @@ static inline
 int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset)
 {
 	nr = FDS_BYTES(nr);
-	if (ufdset) {
-		int error;
-		error = verify_area(VERIFY_WRITE, ufdset, nr);
-		if (!error && __copy_from_user(fdset, ufdset, nr))
-			error = -EFAULT;
-		return error;
-	}
+	if (ufdset)
+		return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0;
+
 	memset(fdset, 0, nr);
 	return 0;
 }
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -3,6 +3,36 @@
 
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/sched.h>
+
+union cpu_time_count {
+	cputime_t cpu;
+	unsigned long long sched;
+};
+
+struct cpu_timer_list {
+	struct list_head entry;
+	union cpu_time_count expires, incr;
+	struct task_struct *task;
+	int firing;
+};
+
+#define CPUCLOCK_PID(clock)		((pid_t) ~((clock) >> 3))
+#define CPUCLOCK_PERTHREAD(clock) \
+	(((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
+#define CPUCLOCK_PID_MASK	7
+#define CPUCLOCK_PERTHREAD_MASK	4
+#define CPUCLOCK_WHICH(clock)	((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK)
+#define CPUCLOCK_CLOCK_MASK	3
+#define CPUCLOCK_PROF		0
+#define CPUCLOCK_VIRT		1
+#define CPUCLOCK_SCHED		2
+#define CPUCLOCK_MAX		3
+
+#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
+	((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
+#define MAKE_THREAD_CPUCLOCK(tid, clock) \
+	MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK)
 
 /* POSIX.1b interval timer structure. */
 struct k_itimer {
@@ -13,15 +43,27 @@ struct k_itimer {
 	int it_overrun;			/* overrun on pending signal  */
 	int it_overrun_last;		/* overrun on last delivered signal */
 	int it_requeue_pending;         /* waiting to requeue this timer */
+#define REQUEUE_PENDING 1
 	int it_sigev_notify;		/* notify word of sigevent struct */
 	int it_sigev_signo;		/* signo word of sigevent struct */
 	sigval_t it_sigev_value;	/* value word of sigevent struct */
-	unsigned long it_incr;		/* interval specified in jiffies */
 	struct task_struct *it_process;	/* process to send signal to */
-	struct timer_list it_timer;
 	struct sigqueue *sigq;		/* signal queue entry. */
-	struct list_head abs_timer_entry; /* clock abs_timer_list */
-	struct timespec wall_to_prev;   /* wall_to_monotonic used when set */
+	union {
+		struct {
+			struct timer_list timer;
+			struct list_head abs_timer_entry; /* clock abs_timer_list */
+			struct timespec wall_to_prev;   /* wall_to_monotonic used when set */
+			unsigned long incr; /* interval in jiffies */
+		} real;
+		struct cpu_timer_list cpu;
+		struct {
+			unsigned int clock;
+			unsigned int node;
+			unsigned long incr;
+			unsigned long expires;
+		} mmtimer;
+	} it;
 };
 
 struct k_clock_abs {
@@ -30,26 +72,27 @@ struct k_clock_abs {
 };
 struct k_clock {
 	int res;		/* in nano seconds */
+	int (*clock_getres) (clockid_t which_clock, struct timespec *tp);
 	struct k_clock_abs *abs_struct;
-	int (*clock_set) (struct timespec * tp);
-	int (*clock_get) (struct timespec * tp);
+	int (*clock_set) (clockid_t which_clock, struct timespec * tp);
+	int (*clock_get) (clockid_t which_clock, struct timespec * tp);
 	int (*timer_create) (struct k_itimer *timer);
-	int (*nsleep) (int which_clock, int flags,
-		       struct timespec * t);
+	int (*nsleep) (clockid_t which_clock, int flags, struct timespec *);
 	int (*timer_set) (struct k_itimer * timr, int flags,
 			  struct itimerspec * new_setting,
 			  struct itimerspec * old_setting);
 	int (*timer_del) (struct k_itimer * timr);
+#define TIMER_RETRY 1
 	void (*timer_get) (struct k_itimer * timr,
 			   struct itimerspec * cur_setting);
 };
 
-void register_posix_clock(int clock_id, struct k_clock *new_clock);
+void register_posix_clock(clockid_t clock_id, struct k_clock *new_clock);
 
 /* Error handlers for timer_create, nanosleep and settime */
 int do_posix_clock_notimer_create(struct k_itimer *timer);
-int do_posix_clock_nonanosleep(int which_clock, int flags, struct timespec * t);
-int do_posix_clock_nosettime(struct timespec *tp);
+int do_posix_clock_nonanosleep(clockid_t, int flags, struct timespec *);
+int do_posix_clock_nosettime(clockid_t, struct timespec *tp);
 
 /* function to call to trigger timer event */
 int posix_timer_event(struct k_itimer *timr, int si_private);
@@ -65,12 +108,32 @@ struct now_struct {
 #define posix_bump_timer(timr, now)					\
          do {								\
               long delta, orun;						\
-	      delta = now.jiffies - (timr)->it_timer.expires;		\
+	      delta = now.jiffies - (timr)->it.real.timer.expires;	\
               if (delta >= 0) {						\
-	           orun = 1 + (delta / (timr)->it_incr);		\
-	          (timr)->it_timer.expires += orun * (timr)->it_incr;	\
+	           orun = 1 + (delta / (timr)->it.real.incr);		\
+	          (timr)->it.real.timer.expires +=			\
+			 orun * (timr)->it.real.incr;			\
                   (timr)->it_overrun += orun;				\
               }								\
             }while (0)
-#endif
 
+int posix_cpu_clock_getres(clockid_t which_clock, struct timespec *);
+int posix_cpu_clock_get(clockid_t which_clock, struct timespec *);
+int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp);
+int posix_cpu_timer_create(struct k_itimer *);
+int posix_cpu_nsleep(clockid_t, int, struct timespec *);
+int posix_cpu_timer_set(struct k_itimer *, int,
+			struct itimerspec *, struct itimerspec *);
+int posix_cpu_timer_del(struct k_itimer *);
+void posix_cpu_timer_get(struct k_itimer *, struct itimerspec *);
+
+void posix_cpu_timer_schedule(struct k_itimer *);
+
+void run_posix_cpu_timers(struct task_struct *);
+void posix_cpu_timers_exit(struct task_struct *);
+void posix_cpu_timers_exit_group(struct task_struct *);
+
+void set_process_cpu_timer(struct task_struct *, unsigned int,
+			   cputime_t *, cputime_t *);
+
+#endif
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -71,11 +71,11 @@ posix_acl_release(struct posix_acl *acl)
 
 /* posix_acl.c */
 
-extern struct posix_acl *posix_acl_alloc(int, int);
-extern struct posix_acl *posix_acl_clone(const struct posix_acl *, int);
+extern struct posix_acl *posix_acl_alloc(int, unsigned int __nocast);
+extern struct posix_acl *posix_acl_clone(const struct posix_acl *, unsigned int __nocast);
 extern int posix_acl_valid(const struct posix_acl *);
 extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
-extern struct posix_acl *posix_acl_from_mode(mode_t, int);
+extern struct posix_acl *posix_acl_from_mode(mode_t, unsigned int __nocast);
 extern int posix_acl_equiv_mode(const struct posix_acl *, mode_t *);
 extern int posix_acl_create_masq(struct posix_acl *, mode_t *);
 extern int posix_acl_chmod_masq(struct posix_acl *, mode_t);
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -114,7 +114,6 @@ extern struct dentry *qnx4_lookup(struct
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
-extern struct buffer_head *qnx4_getblk(struct inode *, int, int);
 extern struct buffer_head *qnx4_bread(struct inode *, int, int);
 
 extern struct inode_operations qnx4_file_inode_operations;
@@ -130,7 +129,6 @@ extern int qnx4_unlink(struct inode *dir
 extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
 extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int);
 extern int qnx4_sync_inode(struct inode *inode);
-extern int qnx4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create);
 
 static inline struct qnx4_sb_info *qnx4_sb(struct super_block *sb)
 {
diff --git a/include/linux/random.h b/include/linux/random.h
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -53,16 +53,10 @@ void generate_random_uuid(unsigned char 
 
 extern __u32 secure_ip_id(__u32 daddr);
 extern u32 secure_tcp_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport);
+extern u32 secure_tcpv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, 
+				       __u16 dport);
 extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 					__u16 sport, __u16 dport);
-extern __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
-				   __u16 sport, __u16 dport,
-				   __u32 sseq, __u32 count,
-				   __u32 data);
-extern __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr,
-				  __u32 daddr, __u16 sport,
-				  __u16 dport, __u32 sseq,
-				  __u32 count, __u32 maxdiff);
 extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
 					  __u16 sport, __u16 dport);
 
@@ -70,6 +64,9 @@ extern __u32 secure_tcpv6_sequence_numbe
 extern struct file_operations random_fops, urandom_fops;
 #endif
 
+unsigned int get_random_int(void);
+unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
+
 #endif /* __KERNEL___ */
 
 #endif /* _LINUX_RANDOM_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -157,9 +157,9 @@ static inline int rcu_pending(int cpu)
 /**
  * rcu_read_lock - mark the beginning of an RCU read-side critical section.
  *
- * When synchronize_kernel() is invoked on one CPU while other CPUs
+ * When synchronize_rcu() is invoked on one CPU while other CPUs
  * are within RCU read-side critical sections, then the
- * synchronize_kernel() is guaranteed to block until after all the other
+ * synchronize_rcu() is guaranteed to block until after all the other
  * CPUs exit their critical sections.  Similarly, if call_rcu() is invoked
  * on one CPU while other CPUs are within RCU read-side critical
  * sections, invocation of the corresponding RCU callback is deferred
@@ -256,6 +256,21 @@ static inline int rcu_pending(int cpu)
 						(p) = (v); \
 					})
 
+/**
+ * synchronize_sched - block until all CPUs have exited any non-preemptive
+ * kernel code sequences.
+ *
+ * This means that all preempt_disable code sequences, including NMI and
+ * hardware-interrupt handlers, in progress on entry will have completed
+ * before this primitive returns.  However, this does not guarantee that
+ * softirq handlers will have completed, since in some kernels
+ *
+ * This primitive provides the guarantees made by the (deprecated)
+ * synchronize_kernel() API.  In contrast, synchronize_rcu() only
+ * guarantees that rcu_read_lock() sections will have completed.
+ */
+#define synchronize_sched() synchronize_rcu()
+
 extern void rcu_init(void);
 extern void rcu_check_callbacks(int cpu, int user);
 extern void rcu_restart_cpu(int cpu);
@@ -265,7 +280,9 @@ extern void FASTCALL(call_rcu(struct rcu
 				void (*func)(struct rcu_head *head)));
 extern void FASTCALL(call_rcu_bh(struct rcu_head *head,
 				void (*func)(struct rcu_head *head)));
-extern void synchronize_kernel(void);
+extern __deprecated_for_modules void synchronize_kernel(void);
+extern void synchronize_rcu(void);
+void synchronize_idle(void);
 
 #endif /* __KERNEL__ */
 #endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/reboot_fixups.h b/include/linux/reboot_fixups.h
new file mode 100644
--- /dev/null
+++ b/include/linux/reboot_fixups.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_REBOOT_FIXUPS_H
+#define _LINUX_REBOOT_FIXUPS_H
+
+#ifdef CONFIG_X86_REBOOTFIXUPS
+extern void mach_reboot_fixups(void);
+#else
+#define mach_reboot_fixups() ((void)(0))
+#endif
+
+#endif /* _LINUX_REBOOT_FIXUPS_H */
diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
--- a/include/linux/reiserfs_acl.h
+++ b/include/linux/reiserfs_acl.h
@@ -5,18 +5,18 @@
 #define REISERFS_ACL_VERSION	0x0001
 
 typedef struct {
-	__u16		e_tag;
-	__u16		e_perm;
-	__u32		e_id;
+	__le16		e_tag;
+	__le16		e_perm;
+	__le32		e_id;
 } reiserfs_acl_entry;
 
 typedef struct {
-	__u16		e_tag;
-	__u16		e_perm;
+	__le16		e_tag;
+	__le16		e_perm;
 } reiserfs_acl_entry_short;
 
 typedef struct {
-	__u32		a_version;
+	__le32		a_version;
 } reiserfs_acl_header;
 
 static inline size_t reiserfs_acl_size(int count)
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -114,47 +114,47 @@ if( !( cond ) ) 								\
 
 
 struct journal_params {
-    __u32 jp_journal_1st_block;	      /* where does journal start from on its
+    __le32 jp_journal_1st_block;	      /* where does journal start from on its
 				       * device */
-    __u32 jp_journal_dev;	      /* journal device st_rdev */
-    __u32 jp_journal_size;	      /* size of the journal */
-    __u32 jp_journal_trans_max;	      /* max number of blocks in a transaction. */
-    __u32 jp_journal_magic; 	      /* random value made on fs creation (this
+    __le32 jp_journal_dev;	      /* journal device st_rdev */
+    __le32 jp_journal_size;	      /* size of the journal */
+    __le32 jp_journal_trans_max;	      /* max number of blocks in a transaction. */
+    __le32 jp_journal_magic; 	      /* random value made on fs creation (this
 				       * was sb_journal_block_count) */
-    __u32 jp_journal_max_batch;	      /* max number of blocks to batch into a
+    __le32 jp_journal_max_batch;	      /* max number of blocks to batch into a
 				       * trans */
-    __u32 jp_journal_max_commit_age;  /* in seconds, how old can an async
+    __le32 jp_journal_max_commit_age;  /* in seconds, how old can an async
 				       * commit be */
-    __u32 jp_journal_max_trans_age;   /* in seconds, how old can a transaction
+    __le32 jp_journal_max_trans_age;   /* in seconds, how old can a transaction
 				       * be */
 };
 
 /* this is the super from 3.5.X, where X >= 10 */
 struct reiserfs_super_block_v1
 {
-    __u32 s_block_count;	   /* blocks count         */
-    __u32 s_free_blocks;           /* free blocks count    */
-    __u32 s_root_block;            /* root block number    */
+    __le32 s_block_count;	   /* blocks count         */
+    __le32 s_free_blocks;           /* free blocks count    */
+    __le32 s_root_block;            /* root block number    */
     struct journal_params s_journal;
-    __u16 s_blocksize;             /* block size */
-    __u16 s_oid_maxsize;	   /* max size of object id array, see
+    __le16 s_blocksize;             /* block size */
+    __le16 s_oid_maxsize;	   /* max size of object id array, see
 				    * get_objectid() commentary  */
-    __u16 s_oid_cursize;	   /* current size of object id array */
-    __u16 s_umount_state;          /* this is set to 1 when filesystem was
+    __le16 s_oid_cursize;	   /* current size of object id array */
+    __le16 s_umount_state;          /* this is set to 1 when filesystem was
 				    * umounted, to 2 - when not */    
     char s_magic[10];              /* reiserfs magic string indicates that
 				    * file system is reiserfs:
 				    * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
-    __u16 s_fs_state;	           /* it is set to used by fsck to mark which
+    __le16 s_fs_state;	           /* it is set to used by fsck to mark which
 				    * phase of rebuilding is done */
-    __u32 s_hash_function_code;    /* indicate, what hash function is being use
+    __le32 s_hash_function_code;    /* indicate, what hash function is being use
 				    * to sort names in a directory*/
-    __u16 s_tree_height;           /* height of disk tree */
-    __u16 s_bmap_nr;               /* amount of bitmap blocks needed to address
+    __le16 s_tree_height;           /* height of disk tree */
+    __le16 s_bmap_nr;               /* amount of bitmap blocks needed to address
 				    * each block of file system */
-    __u16 s_version;               /* this field is only reliable on filesystem
+    __le16 s_version;               /* this field is only reliable on filesystem
 				    * with non-standard journal */
-    __u16 s_reserved_for_journal;  /* size in blocks of journal area on main
+    __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
 				    * device, we need to keep after
 				    * making fs with non-standard journal */	
 } __attribute__ ((__packed__));
@@ -165,8 +165,8 @@ struct reiserfs_super_block_v1
 struct reiserfs_super_block
 {
     struct reiserfs_super_block_v1 s_v1;
-    __u32 s_inode_generation;
-    __u32 s_flags;                  /* Right now used only by inode-attributes, if enabled */
+    __le32 s_inode_generation;
+    __le32 s_flags;                  /* Right now used only by inode-attributes, if enabled */
     unsigned char s_uuid[16];       /* filesystem unique identifier */
     unsigned char s_label[16];      /* filesystem volume label */
     char s_unused[88] ;             /* zero filled by mkreiserfs and
@@ -225,7 +225,7 @@ struct reiserfs_super_block
 #define SB_ONDISK_JOURNAL_DEVICE(s) \
          le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
 #define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
-         le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
 
 #define is_block_in_log_or_reserved_area(s, block) \
          block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
@@ -269,7 +269,7 @@ int is_reiserfs_jr (struct reiserfs_supe
 #define QUOTA_EXCEEDED -6
 
 typedef __u32 b_blocknr_t;
-typedef __u32 unp_t;
+typedef __le32 unp_t;
 
 struct unfm_nodeinfo {
     unp_t unfm_nodenum;
@@ -376,78 +376,57 @@ static inline struct reiserfs_sb_info *R
 // directories use this key as well as old files
 //
 struct offset_v1 {
-    __u32 k_offset;
-    __u32 k_uniqueness;
+    __le32 k_offset;
+    __le32 k_uniqueness;
 } __attribute__ ((__packed__));
 
 struct offset_v2 {
-#ifdef __LITTLE_ENDIAN
-	    /* little endian version */
-	    __u64 k_offset:60;
-	    __u64 k_type: 4;
-#else
-	    /* big endian version */
-	    __u64 k_type: 4;
-	    __u64 k_offset:60;
-#endif
+	__le64 v;
 } __attribute__ ((__packed__));
 
-#ifndef __LITTLE_ENDIAN
-typedef union {
-    struct offset_v2 offset_v2;
-    __u64 linear;
-} __attribute__ ((__packed__)) offset_v2_esafe_overlay;
-
 static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 )
 {
-    offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
-    tmp.linear = le64_to_cpu( tmp.linear );
-    return (tmp.offset_v2.k_type <= TYPE_MAXTYPE)?tmp.offset_v2.k_type:TYPE_ANY;
+	__u8 type = le64_to_cpu(v2->v) >> 60;
+	return (type <= TYPE_MAXTYPE)?type:TYPE_ANY;
 }
  
 static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type )
 {
-    offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
-    tmp->linear = le64_to_cpu(tmp->linear);
-    tmp->offset_v2.k_type = type;
-    tmp->linear = cpu_to_le64(tmp->linear);
+	v2->v = (v2->v & cpu_to_le64(~0ULL>>4)) | cpu_to_le64((__u64)type<<60);
 }
  
 static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 )
 {
-    offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
-    tmp.linear = le64_to_cpu( tmp.linear );
-    return tmp.offset_v2.k_offset;
+	return le64_to_cpu(v2->v) & (~0ULL>>4);
 }
 
 static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ){
-    offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
-    tmp->linear = le64_to_cpu(tmp->linear);
-    tmp->offset_v2.k_offset = offset;
-    tmp->linear = cpu_to_le64(tmp->linear);
+	offset &= (~0ULL>>4);
+	v2->v = (v2->v & cpu_to_le64(15ULL<<60)) | cpu_to_le64(offset);
 }
-#else
-# define offset_v2_k_type(v2)           ((v2)->k_type)
-# define set_offset_v2_k_type(v2,val)   (offset_v2_k_type(v2) = (val))
-# define offset_v2_k_offset(v2)         ((v2)->k_offset)
-# define set_offset_v2_k_offset(v2,val) (offset_v2_k_offset(v2) = (val))
-#endif
 
 /* Key of an item determines its location in the S+tree, and
    is composed of 4 components */
 struct reiserfs_key {
-    __u32 k_dir_id;    /* packing locality: by default parent
+    __le32 k_dir_id;    /* packing locality: by default parent
 			  directory object id */
-    __u32 k_objectid;  /* object identifier */
+    __le32 k_objectid;  /* object identifier */
     union {
 	struct offset_v1 k_offset_v1;
 	struct offset_v2 k_offset_v2;
     } __attribute__ ((__packed__)) u;
 } __attribute__ ((__packed__));
 
+struct in_core_key {
+    __u32 k_dir_id;    /* packing locality: by default parent
+			  directory object id */
+    __u32 k_objectid;  /* object identifier */
+    __u64 k_offset;
+    __u8 k_type;
+};
 
 struct cpu_key {
-    struct reiserfs_key on_disk_key;
+    struct in_core_key on_disk_key;
     int version;
     int key_length; /* 3 in all cases but direct2indirect and
 		       indirect2direct conversion */
@@ -508,15 +487,15 @@ struct item_head
 		   item. Note that the key, not this field, is used to
 		   determine the item type, and thus which field this
 		   union contains. */
-		__u16 ih_free_space_reserved; 
+		__le16 ih_free_space_reserved;
 		/* Iff this is a directory item, this field equals the
 		   number of directory entries in the directory item. */
-		__u16 ih_entry_count; 
+		__le16 ih_entry_count;
 	} __attribute__ ((__packed__)) u;
-	__u16 ih_item_len;           /* total size of the item body */
-	__u16 ih_item_location;      /* an offset to the item body
+	__le16 ih_item_len;           /* total size of the item body */
+	__le16 ih_item_location;      /* an offset to the item body
 				      * within the block */
-	__u16 ih_version;	     /* 0 for all old items, 2 for new
+	__le16 ih_version;	     /* 0 for all old items, 2 for new
 					ones. Highest bit is set by fsck
 					temporary, cleaned after all
 					done */
@@ -670,43 +649,29 @@ static inline void set_le_ih_k_type (str
 //
 static inline loff_t cpu_key_k_offset (const struct cpu_key * key)
 {
-    return (key->version == KEY_FORMAT_3_5) ?
-        key->on_disk_key.u.k_offset_v1.k_offset :
-	key->on_disk_key.u.k_offset_v2.k_offset;
+    return key->on_disk_key.k_offset;
 }
 
 static inline loff_t cpu_key_k_type (const struct cpu_key * key)
 {
-    return (key->version == KEY_FORMAT_3_5) ?
-        uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
-	key->on_disk_key.u.k_offset_v2.k_type;
+    return key->on_disk_key.k_type;
 }
 
 static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
 {
-    (key->version == KEY_FORMAT_3_5) ?
-        (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
-	(key->on_disk_key.u.k_offset_v2.k_offset = offset);
+	key->on_disk_key.k_offset = offset;
 }
 
-
 static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
 {
-    (key->version == KEY_FORMAT_3_5) ?
-        (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)):
-	(key->on_disk_key.u.k_offset_v2.k_type = type);
+	key->on_disk_key.k_type = type;
 }
 
-
 static inline void cpu_key_k_offset_dec (struct cpu_key * key)
 {
-    if (key->version == KEY_FORMAT_3_5)
-	key->on_disk_key.u.k_offset_v1.k_offset --;
-    else
-	key->on_disk_key.u.k_offset_v2.k_offset --;
+	key->on_disk_key.k_offset --;
 }
 
-
 #define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
 #define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
 #define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
@@ -752,10 +717,10 @@ extern struct reiserfs_key root_key;
 /* Header of a disk block.  More precisely, header of a formatted leaf
    or internal node, and not the header of an unformatted node. */
 struct block_head {       
-  __u16 blk_level;        /* Level of a block in the tree. */
-  __u16 blk_nr_item;      /* Number of keys/items in a block. */
-  __u16 blk_free_space;   /* Block free space in bytes. */
-  __u16 blk_reserved;
+  __le16 blk_level;        /* Level of a block in the tree. */
+  __le16 blk_nr_item;      /* Number of keys/items in a block. */
+  __le16 blk_free_space;   /* Block free space in bytes. */
+  __le16 blk_reserved;
 				/* dump this in v4/planA */
   struct reiserfs_key  blk_right_delim_key; /* kept only for compatibility */
 };
@@ -819,19 +784,19 @@ struct block_head {       
 //
 struct stat_data_v1
 {
-    __u16 sd_mode;	/* file type, permissions */
-    __u16 sd_nlink;	/* number of hard links */
-    __u16 sd_uid;		/* owner */
-    __u16 sd_gid;		/* group */
-    __u32 sd_size;	/* file size */
-    __u32 sd_atime;	/* time of last access */
-    __u32 sd_mtime;	/* time file was last modified  */
-    __u32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+    __le16 sd_mode;	/* file type, permissions */
+    __le16 sd_nlink;	/* number of hard links */
+    __le16 sd_uid;		/* owner */
+    __le16 sd_gid;		/* group */
+    __le32 sd_size;	/* file size */
+    __le32 sd_atime;	/* time of last access */
+    __le32 sd_mtime;	/* time file was last modified  */
+    __le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
     union {
-	__u32 sd_rdev;
-	__u32 sd_blocks;	/* number of blocks file uses */
+	__le32 sd_rdev;
+	__le32 sd_blocks;	/* number of blocks file uses */
     } __attribute__ ((__packed__)) u;
-    __u32 sd_first_direct_byte; /* first byte of file which is stored
+    __le32 sd_first_direct_byte; /* first byte of file which is stored
 				   in a direct item: except that if it
 				   equals 1 it is a symlink and if it
 				   equals ~(__u32)0 there is no
@@ -897,20 +862,20 @@ struct stat_data_v1
 /* Stat Data on disk (reiserfs version of UFS disk inode minus the
    address blocks) */
 struct stat_data {
-    __u16 sd_mode;	/* file type, permissions */
-    __u16 sd_attrs;     /* persistent inode flags */
-    __u32 sd_nlink;	/* number of hard links */
-    __u64 sd_size;	/* file size */
-    __u32 sd_uid;		/* owner */
-    __u32 sd_gid;		/* group */
-    __u32 sd_atime;	/* time of last access */
-    __u32 sd_mtime;	/* time file was last modified  */
-    __u32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
-    __u32 sd_blocks;
+    __le16 sd_mode;	/* file type, permissions */
+    __le16 sd_attrs;     /* persistent inode flags */
+    __le32 sd_nlink;	/* number of hard links */
+    __le64 sd_size;	/* file size */
+    __le32 sd_uid;		/* owner */
+    __le32 sd_gid;		/* group */
+    __le32 sd_atime;	/* time of last access */
+    __le32 sd_mtime;	/* time file was last modified  */
+    __le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+    __le32 sd_blocks;
     union {
-	__u32 sd_rdev;
-	__u32 sd_generation;
-      //__u32 sd_first_direct_byte; 
+	__le32 sd_rdev;
+	__le32 sd_generation;
+      //__le32 sd_first_direct_byte;
       /* first byte of file which is stored in a
 				       direct item: except that if it equals 1
 				       it is a symlink and if it equals
@@ -993,12 +958,12 @@ struct stat_data {
 
 struct reiserfs_de_head
 {
-  __u32 deh_offset;		/* third component of the directory entry key */
-  __u32 deh_dir_id;		/* objectid of the parent directory of the object, that is referenced
+  __le32 deh_offset;		/* third component of the directory entry key */
+  __le32 deh_dir_id;		/* objectid of the parent directory of the object, that is referenced
 					   by directory entry */
-  __u32 deh_objectid;		/* objectid of the object, that is referenced by directory entry */
-  __u16 deh_location;		/* offset of name in the whole item */
-  __u16 deh_state;		/* whether 1) entry contains stat data (for future), and 2) whether
+  __le32 deh_objectid;		/* objectid of the object, that is referenced by directory entry */
+  __le16 deh_location;		/* offset of name in the whole item */
+  __le16 deh_state;		/* whether 1) entry contains stat data (for future), and 2) whether
 					   entry is hidden (unlinked) */
 } __attribute__ ((__packed__));
 #define DEH_SIZE                  sizeof(struct reiserfs_de_head)
@@ -1058,10 +1023,10 @@ struct reiserfs_de_head
 #define de_visible(deh)	    	    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 #define de_hidden(deh)	    	    !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 
-extern void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
-				    __u32 par_dirid, __u32 par_objid);
-extern void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
-				 __u32 par_dirid, __u32 par_objid);
+extern void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid,
+				    __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
+				 __le32 par_dirid, __le32 par_objid);
 
 /* array of the entry headers */
  /* get item body */
@@ -1160,9 +1125,9 @@ struct reiserfs_dir_entry
 /* Disk child pointer: The pointer from an internal node of the tree
    to a node that is on disk. */
 struct disk_child {
-  __u32       dc_block_number;              /* Disk child's block number. */
-  __u16       dc_size;		            /* Disk child's used space.   */
-  __u16       dc_reserved;
+  __le32       dc_block_number;              /* Disk child's block number. */
+  __le16       dc_size;		            /* Disk child's used space.   */
+  __le16       dc_reserved;
 };
 
 #define DC_SIZE (sizeof(struct disk_child))
@@ -1476,7 +1441,7 @@ struct tree_balance
   int fs_gen;                  /* saved value of `reiserfs_generation' counter
 			          see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
-  struct reiserfs_key  key;	      /* key pointer, to pass to block allocator or
+  struct in_core_key  key;	      /* key pointer, to pass to block allocator or
 				 another low-level subsystem */
 #endif
 } ;
@@ -1630,10 +1595,10 @@ struct reiserfs_iget_args {
 
 /* first block written in a commit.  */
 struct reiserfs_journal_desc {
-  __u32 j_trans_id ;			/* id of commit */
-  __u32 j_len ;			/* length of commit. len +1 is the commit block */
-  __u32 j_mount_id ;				/* mount id of this trans*/
-  __u32 j_realblock[1] ; /* real locations for each block */
+  __le32 j_trans_id ;			/* id of commit */
+  __le32 j_len ;			/* length of commit. len +1 is the commit block */
+  __le32 j_mount_id ;				/* mount id of this trans*/
+  __le32 j_realblock[1] ; /* real locations for each block */
 } ;
 
 #define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
@@ -1646,9 +1611,9 @@ struct reiserfs_journal_desc {
 
 /* last block written in a commit */
 struct reiserfs_journal_commit {
-  __u32 j_trans_id ;			/* must match j_trans_id from the desc block */
-  __u32 j_len ;			/* ditto */
-  __u32 j_realblock[1] ; /* real locations for each block */
+  __le32 j_trans_id ;			/* must match j_trans_id from the desc block */
+  __le32 j_len ;			/* ditto */
+  __le32 j_realblock[1] ; /* real locations for each block */
 } ;
 
 #define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
@@ -1663,9 +1628,9 @@ struct reiserfs_journal_commit {
 ** and this transaction does not need to be replayed.
 */
 struct reiserfs_journal_header {
-  __u32 j_last_flush_trans_id ;		/* id of last fully flushed transaction */
-  __u32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
-  __u32 j_mount_id ;
+  __le32 j_last_flush_trans_id ;		/* id of last fully flushed transaction */
+  __le32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
+  __le32 j_mount_id ;
   /* 12 */ struct journal_params jh_journal;
 } ;
 
@@ -2117,7 +2082,7 @@ struct buffer_head * get_FEB (struct tre
  struct __reiserfs_blocknr_hint {
      struct inode * inode;		/* inode passed to allocator, if we allocate unf. nodes */
      long block;			/* file offset, in blocks */
-     struct reiserfs_key key;
+     struct in_core_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
@@ -2144,7 +2109,7 @@ void reiserfs_init_alloc_options (struct
  * to use for a new object underneat it.  The locality is returned
  * in disk byte order (le).
  */
-u32 reiserfs_choose_packing(struct inode *dir);
+__le32 reiserfs_choose_packing(struct inode *dir);
 
 int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
--- a/include/linux/reiserfs_fs_i.h
+++ b/include/linux/reiserfs_fs_i.h
@@ -23,9 +23,8 @@ typedef enum {
       space on crash with some files open, but unlinked. */
     i_link_saved_unlink_mask   =  0x0010,
     i_link_saved_truncate_mask =  0x0020,
-    i_priv_object              =  0x0080,
-    i_has_xattr_dir            =  0x0100,
-    i_data_log	               =  0x0200,
+    i_has_xattr_dir            =  0x0040,
+    i_data_log	               =  0x0080,
 } reiserfs_inode_flags;
 
 
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -10,8 +10,8 @@
 #define REISERFS_XATTR_MAGIC 0x52465841 /* "RFXA" */
 
 struct reiserfs_xattr_header {
-    __u32 h_magic;              /* magic number for identification */
-    __u32 h_hash;               /* hash of the value */
+    __le32 h_magic;              /* magic number for identification */
+    __le32 h_hash;               /* hash of the value */
 };
 
 #ifdef __KERNEL__
@@ -31,7 +31,7 @@ struct reiserfs_xattr_handler {
 
 
 #ifdef CONFIG_REISERFS_FS_XATTR
-#define is_reiserfs_priv_object(inode) (REISERFS_I(inode)->i_flags & i_priv_object)
+#define is_reiserfs_priv_object(inode) IS_PRIVATE(inode)
 #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
 ssize_t reiserfs_getxattr (struct dentry *dentry, const char *name,
 			   void *buffer, size_t size);
@@ -103,9 +103,16 @@ reiserfs_read_unlock_xattr_i(struct inod
     up_read (&REISERFS_I(inode)->xattr_sem);
 }
 
+static inline void
+reiserfs_mark_inode_private(struct inode *inode)
+{
+    inode->i_flags |= S_PRIVATE;
+}
+
 #else
 
 #define is_reiserfs_priv_object(inode) 0
+#define reiserfs_mark_inode_private(inode)
 #define reiserfs_getxattr NULL
 #define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -89,10 +89,14 @@ enum {
 	RTM_GETANYCAST	= 62,
 #define RTM_GETANYCAST	RTM_GETANYCAST
 
-	RTM_MAX,
-#define RTM_MAX		RTM_MAX
+	__RTM_MAX,
+#define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
 };
 
+#define RTM_NR_MSGTYPES	(RTM_MAX + 1 - RTM_BASE)
+#define RTM_NR_FAMILIES	(RTM_NR_MSGTYPES >> 2)
+#define RTM_FAM(cmd)	(((cmd) - RTM_BASE) >> 2)
+
 /* 
    Generic structure for encapsulation of optional route information.
    It is reminiscent of sockaddr, but with sa_family replaced
@@ -250,6 +254,7 @@ enum rtattr_type_t
 	RTA_FLOW,
 	RTA_CACHEINFO,
 	RTA_SESSION,
+	RTA_MP_ALGO,
 	__RTA_MAX
 };
 
@@ -346,6 +351,7 @@ enum
 #define RTAX_FEATURE_ECN	0x00000001
 #define RTAX_FEATURE_SACK	0x00000002
 #define RTAX_FEATURE_TIMESTAMP	0x00000004
+#define RTAX_FEATURE_ALLFRAG	0x00000008
 
 struct rta_session
 {
@@ -446,6 +452,7 @@ enum
 	NDA_DST,
 	NDA_LLADDR,
 	NDA_CACHEINFO,
+	NDA_PROBES,
 	__NDA_MAX
 };
 
@@ -699,7 +706,6 @@ enum
 	TCA_RATE,
 	TCA_FCNT,
 	TCA_STATS2,
-	TCA_ACT_STATS,
 	__TCA_MAX
 };
 
@@ -779,6 +785,11 @@ extern void __rta_fill(struct sk_buff *s
 		 goto rtattr_failure; \
    	__rta_fill(skb, attrtype, attrlen, data); }) 
 
+#define RTA_PUT_NOHDR(skb, attrlen, data) \
+({	if (unlikely(skb_tailroom(skb) < (int)(attrlen))) \
+		goto rtattr_failure; \
+	memcpy(skb_put(skb, RTA_ALIGN(attrlen)), data, attrlen); })
+		
 static inline struct rtattr *
 __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 {
diff --git a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -14,6 +14,7 @@
 #include <linux/thread_info.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
+#include <linux/nodemask.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -32,6 +33,7 @@
 #include <linux/pid.h>
 #include <linux/percpu.h>
 #include <linux/topology.h>
+#include <linux/seccomp.h>
 
 struct exec_domain;
 
@@ -173,7 +175,6 @@ extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
 extern void scheduler_tick(void);
-extern unsigned long cache_decay_ticks;
 
 /* Attach to any functions which should be ignored in wchan output. */
 #define __sched		__attribute__((__section__(".sched.text")))
@@ -203,6 +204,12 @@ arch_get_unmapped_area_topdown(struct fi
 extern void arch_unmap_area(struct vm_area_struct *area);
 extern void arch_unmap_area_topdown(struct vm_area_struct *area);
 
+#define set_mm_counter(mm, member, value) (mm)->_##member = (value)
+#define get_mm_counter(mm, member) ((mm)->_##member)
+#define add_mm_counter(mm, member, value) (mm)->_##member += (value)
+#define inc_mm_counter(mm, member) (mm)->_##member++
+#define dec_mm_counter(mm, member) (mm)->_##member--
+typedef unsigned long mm_counter_t;
 
 struct mm_struct {
 	struct vm_area_struct * mmap;		/* list of VMAs */
@@ -219,7 +226,7 @@ struct mm_struct {
 	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
 	int map_count;				/* number of VMAs */
 	struct rw_semaphore mmap_sem;
-	spinlock_t page_table_lock;		/* Protects page tables, mm->rss, mm->anon_rss */
+	spinlock_t page_table_lock;		/* Protects page tables and some counters */
 
 	struct list_head mmlist;		/* List of maybe swapped mm's.  These are globally strung
 						 * together off init_mm.mmlist, and are protected
@@ -229,9 +236,13 @@ struct mm_struct {
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
 	unsigned long arg_start, arg_end, env_start, env_end;
-	unsigned long rss, anon_rss, total_vm, locked_vm, shared_vm;
+	unsigned long total_vm, locked_vm, shared_vm;
 	unsigned long exec_vm, stack_vm, reserved_vm, def_flags, nr_ptes;
 
+	/* Special counters protected by the page_table_lock */
+	mm_counter_t _rss;
+	mm_counter_t _anon_rss;
+
 	unsigned long saved_auxv[42]; /* for /proc/PID/auxv */
 
 	unsigned dumpable:1;
@@ -300,6 +311,14 @@ struct signal_struct {
 	/* POSIX.1b Interval Timers */
 	struct list_head posix_timers;
 
+	/* ITIMER_REAL timer for the process */
+	struct timer_list real_timer;
+	unsigned long it_real_value, it_real_incr;
+
+	/* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */
+	cputime_t it_prof_expires, it_virt_expires;
+	cputime_t it_prof_incr, it_virt_incr;
+
 	/* job control IDs */
 	pid_t pgrp;
 	pid_t tty_old_pgrp;
@@ -320,6 +339,14 @@ struct signal_struct {
 	unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
 
 	/*
+	 * Cumulative ns of scheduled CPU time for dead threads in the
+	 * group, not including a zombie group leader.  (This only differs
+	 * from jiffies_to_ns(utime + stime) if sched_clock uses something
+	 * other than jiffies.)
+	 */
+	unsigned long long sched_time;
+
+	/*
 	 * We don't bother to synchronize most readers of this at all,
 	 * because there is no reader checking a limit that actually needs
 	 * to get both rlim_cur and rlim_max atomically, and either one
@@ -329,6 +356,15 @@ struct signal_struct {
 	 * have no need to disable irqs.
 	 */
 	struct rlimit rlim[RLIM_NLIMITS];
+
+	struct list_head cpu_timers[3];
+
+	/* keep the process-shared keyrings here so that they do the right
+	 * thing in threads created with CLONE_THREAD */
+#ifdef CONFIG_KEYS
+	struct key *session_keyring;	/* keyring inherited over fork */
+	struct key *process_keyring;	/* keyring private to this process */
+#endif
 };
 
 /*
@@ -462,17 +498,26 @@ struct sched_domain {
 	/* load_balance() stats */
 	unsigned long lb_cnt[MAX_IDLE_TYPES];
 	unsigned long lb_failed[MAX_IDLE_TYPES];
+	unsigned long lb_balanced[MAX_IDLE_TYPES];
 	unsigned long lb_imbalance[MAX_IDLE_TYPES];
+	unsigned long lb_gained[MAX_IDLE_TYPES];
+	unsigned long lb_hot_gained[MAX_IDLE_TYPES];
 	unsigned long lb_nobusyg[MAX_IDLE_TYPES];
 	unsigned long lb_nobusyq[MAX_IDLE_TYPES];
 
+	/* Active load balancing */
+	unsigned long alb_cnt;
+	unsigned long alb_failed;
+	unsigned long alb_pushed;
+
 	/* sched_balance_exec() stats */
 	unsigned long sbe_attempts;
 	unsigned long sbe_pushed;
 
 	/* try_to_wake_up() stats */
-	unsigned long ttwu_wake_affine;
-	unsigned long ttwu_wake_balance;
+	unsigned long ttwu_wake_remote;
+	unsigned long ttwu_move_affine;
+	unsigned long ttwu_move_balance;
 #endif
 };
 
@@ -488,6 +533,7 @@ extern void cpu_attach_domain(struct sch
 
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
+struct cpuset;
 
 #define NGROUPS_SMALL		32
 #define NGROUPS_PER_BLOCK	((int)(PAGE_SIZE / sizeof(gid_t)))
@@ -532,7 +578,7 @@ struct task_struct {
 	unsigned long flags;	/* per process flags, defined below */
 	unsigned long ptrace;
 
-	int lock_depth;		/* Lock depth */
+	int lock_depth;		/* BKL lock depth */
 
 	int prio, static_prio;
 	struct list_head run_list;
@@ -540,6 +586,7 @@ struct task_struct {
 
 	unsigned long sleep_avg;
 	unsigned long long timestamp, last_ran;
+	unsigned long long sched_time; /* sched_clock time spent running */
 	int activated;
 
 	unsigned long policy;
@@ -593,15 +640,16 @@ struct task_struct {
 	int __user *clear_child_tid;		/* CLONE_CHILD_CLEARTID */
 
 	unsigned long rt_priority;
-	unsigned long it_real_value, it_real_incr;
-	cputime_t it_virt_value, it_virt_incr;
-	cputime_t it_prof_value, it_prof_incr;
-	struct timer_list real_timer;
 	cputime_t utime, stime;
 	unsigned long nvcsw, nivcsw; /* context switch counts */
 	struct timespec start_time;
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
 	unsigned long min_flt, maj_flt;
+
+  	cputime_t it_prof_expires, it_virt_expires;
+	unsigned long long it_sched_expires;
+	struct list_head cpu_timers[3];
+
 /* process credentials */
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
@@ -610,12 +658,13 @@ struct task_struct {
 	unsigned keep_capabilities:1;
 	struct user_struct *user;
 #ifdef CONFIG_KEYS
-	struct key *session_keyring;	/* keyring inherited over fork */
-	struct key *process_keyring;	/* keyring private to this process (CLONE_THREAD) */
 	struct key *thread_keyring;	/* keyring private to this thread */
 #endif
 	int oomkilladj; /* OOM kill score adjustment (bit shift). */
-	char comm[TASK_COMM_LEN];
+	char comm[TASK_COMM_LEN]; /* executable name excluding path
+				     - access with [gs]et_task_comm (which lock
+				       it with task_lock())
+				     - initialized normally by flush_old_exec */
 /* file system info */
 	int link_count, total_link_count;
 /* ipc stuff */
@@ -643,6 +692,7 @@ struct task_struct {
 	
 	void *security;
 	struct audit_context *audit_context;
+	seccomp_t seccomp;
 
 /* Thread group tracking */
    	u32 parent_exec_id;
@@ -685,6 +735,11 @@ struct task_struct {
   	struct mempolicy *mempolicy;
 	short il_next;
 #endif
+#ifdef CONFIG_CPUSETS
+	struct cpuset *cpuset;
+	nodemask_t mems_allowed;
+	int cpuset_mems_generation;
+#endif
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
@@ -735,6 +790,7 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_LESS_THROTTLE 0x00100000	/* Throttle me less: I clean memory */
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
+#define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
@@ -773,6 +829,7 @@ static inline int set_cpus_allowed(task_
 #endif
 
 extern unsigned long long sched_clock(void);
+extern unsigned long long current_sched_time(const task_t *current_task);
 
 /* sched_exec is called by processes performing an exec */
 #ifdef CONFIG_SMP
@@ -791,6 +848,7 @@ extern void sched_idle_next(void);
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(const task_t *p);
 extern int task_nice(const task_t *p);
+extern int can_nice(const task_t *p, const int nice);
 extern int task_curr(const task_t *p);
 extern int idle_cpu(int cpu);
 extern int sched_setscheduler(struct task_struct *, int, struct sched_param *);
@@ -957,7 +1015,6 @@ extern int  copy_thread(int, unsigned lo
 extern void flush_thread(void);
 extern void exit_thread(void);
 
-extern void exit_mm(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_signal(struct task_struct *);
 extern void __exit_signal(struct task_struct *);
@@ -967,7 +1024,6 @@ extern void exit_itimers(struct signal_s
 
 extern NORET_TYPE void do_group_exit(int);
 
-extern void reparent_to_init(void);
 extern void daemonize(const char *, ...);
 extern int allow_signal(int);
 extern int disallow_signal(int);
diff --git a/include/linux/scx200.h b/include/linux/scx200.h
--- a/include/linux/scx200.h
+++ b/include/linux/scx200.h
@@ -7,6 +7,10 @@
 
 /* Interesting stuff for the National Semiconductor SCx200 CPU */
 
+extern unsigned scx200_cb_base;
+
+#define scx200_cb_present() (scx200_cb_base!=0)
+
 /* F0 PCI Header/Bridge Configuration Registers */
 #define SCx200_DOCCS_BASE 0x78	/* DOCCS Base Address Register */
 #define SCx200_DOCCS_CTRL 0x7c	/* DOCCS Control Register */
@@ -15,7 +19,7 @@
 #define SCx200_GPIO_SIZE 0x2c	/* Size of GPIO register block */
 
 /* General Configuration Block */
-#define SCx200_CB_BASE 0x9000	/* Base fixed at 0x9000 according to errata */
+#define SCx200_CB_BASE_FIXED 0x9000	/* Base fixed at 0x9000 according to errata? */
 
 /* Watchdog Timer */
 #define SCx200_WDT_OFFSET 0x00	/* offset within configuration block */
@@ -44,9 +48,7 @@
 #define SCx200_IID 0x3c		/* IA On a Chip Identification Number Reg */
 #define SCx200_REV 0x3d		/* Revision Register */
 #define SCx200_CBA 0x3e		/* Configuration Base Address Register */
-
-/* Verify that the configuration block really is there */
-#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+#define SCx200_CBA_SCRATCH 0x64	/* Configuration Base Address Scratchpad */
 
 /*
     Local variables:
diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h
--- a/include/linux/scx200_gpio.h
+++ b/include/linux/scx200_gpio.h
@@ -1,10 +1,8 @@
 #include <linux/spinlock.h>
 
 u32 scx200_gpio_configure(int index, u32 set, u32 clear);
-void scx200_gpio_dump(unsigned index);
 
 extern unsigned scx200_gpio_base;
-extern spinlock_t scx200_gpio_lock;
 extern long scx200_gpio_shadow[2];
 
 #define scx200_gpio_present() (scx200_gpio_base!=0)
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
new file mode 100644
--- /dev/null
+++ b/include/linux/seccomp.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_SECCOMP_H
+#define _LINUX_SECCOMP_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SECCOMP
+
+#define NR_SECCOMP_MODES 1
+
+#include <linux/thread_info.h>
+#include <asm/seccomp.h>
+
+typedef struct { int mode; } seccomp_t;
+
+extern void __secure_computing(int);
+static inline void secure_computing(int this_syscall)
+{
+	if (unlikely(test_thread_flag(TIF_SECCOMP)))
+		__secure_computing(this_syscall);
+}
+
+#else /* CONFIG_SECCOMP */
+
+#if (__GNUC__ > 2)
+  typedef struct { } seccomp_t;
+#else
+  typedef struct { int gcc_is_buggy; } seccomp_t;
+#endif
+
+#define secure_computing(x) do { } while (0)
+
+#endif /* CONFIG_SECCOMP */
+
+#endif /* _LINUX_SECCOMP_H */
diff --git a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -458,13 +458,15 @@ struct swap_info_struct;
  *	Check permissions for a mmap operation.  The @file may be NULL, e.g.
  *	if mapping anonymous memory.
  *	@file contains the file structure for file to map (may be NULL).
- *	@prot contains the requested permissions.
+ *	@reqprot contains the protection requested by the application.
+ *	@prot contains the protection that will be applied by the kernel.
  *	@flags contains the operational flags.
  *	Return 0 if permission is granted.
  * @file_mprotect:
  *	Check permissions before changing memory access permissions.
  *	@vma contains the memory region to modify.
- *	@prot contains the requested permissions.
+ *	@reqprot contains the protection requested by the application.
+ *	@prot contains the protection that will be applied by the kernel.
  *	Return 0 if permission is granted.
  * @file_lock:
  *	Check permission before performing file locking operations.
@@ -1129,8 +1131,11 @@ struct security_operations {
 	int (*file_ioctl) (struct file * file, unsigned int cmd,
 			   unsigned long arg);
 	int (*file_mmap) (struct file * file,
+			  unsigned long reqprot,
 			  unsigned long prot, unsigned long flags);
-	int (*file_mprotect) (struct vm_area_struct * vma, unsigned long prot);
+	int (*file_mprotect) (struct vm_area_struct * vma,
+			      unsigned long reqprot,
+			      unsigned long prot);
 	int (*file_lock) (struct file * file, unsigned int cmd);
 	int (*file_fcntl) (struct file * file, unsigned int cmd,
 			   unsigned long arg);
@@ -1426,11 +1431,15 @@ static inline void security_sb_post_pivo
 
 static inline int security_inode_alloc (struct inode *inode)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return 0;
 	return security_ops->inode_alloc_security (inode);
 }
 
 static inline void security_inode_free (struct inode *inode)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return;
 	security_ops->inode_free_security (inode);
 }
 	
@@ -1438,6 +1447,8 @@ static inline int security_inode_create 
 					 struct dentry *dentry,
 					 int mode)
 {
+	if (unlikely (IS_PRIVATE (dir)))
+		return 0;
 	return security_ops->inode_create (dir, dentry, mode);
 }
 
@@ -1445,6 +1456,8 @@ static inline void security_inode_post_c
 					       struct dentry *dentry,
 					       int mode)
 {
+	if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode)))
+		return;
 	security_ops->inode_post_create (dir, dentry, mode);
 }
 
@@ -1452,6 +1465,8 @@ static inline int security_inode_link (s
 				       struct inode *dir,
 				       struct dentry *new_dentry)
 {
+	if (unlikely (IS_PRIVATE (old_dentry->d_inode)))
+		return 0;
 	return security_ops->inode_link (old_dentry, dir, new_dentry);
 }
 
@@ -1459,12 +1474,16 @@ static inline void security_inode_post_l
 					     struct inode *dir,
 					     struct dentry *new_dentry)
 {
+	if (new_dentry->d_inode && unlikely (IS_PRIVATE (new_dentry->d_inode)))
+		return;
 	security_ops->inode_post_link (old_dentry, dir, new_dentry);
 }
 
 static inline int security_inode_unlink (struct inode *dir,
 					 struct dentry *dentry)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_unlink (dir, dentry);
 }
 
@@ -1472,6 +1491,8 @@ static inline int security_inode_symlink
 					  struct dentry *dentry,
 					  const char *old_name)
 {
+	if (unlikely (IS_PRIVATE (dir)))
+		return 0;
 	return security_ops->inode_symlink (dir, dentry, old_name);
 }
 
@@ -1479,6 +1500,8 @@ static inline void security_inode_post_s
 						struct dentry *dentry,
 						const char *old_name)
 {
+	if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode)))
+		return;
 	security_ops->inode_post_symlink (dir, dentry, old_name);
 }
 
@@ -1486,6 +1509,8 @@ static inline int security_inode_mkdir (
 					struct dentry *dentry,
 					int mode)
 {
+	if (unlikely (IS_PRIVATE (dir)))
+		return 0;
 	return security_ops->inode_mkdir (dir, dentry, mode);
 }
 
@@ -1493,12 +1518,16 @@ static inline void security_inode_post_m
 					      struct dentry *dentry,
 					      int mode)
 {
+	if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode)))
+		return;
 	security_ops->inode_post_mkdir (dir, dentry, mode);
 }
 
 static inline int security_inode_rmdir (struct inode *dir,
 					struct dentry *dentry)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_rmdir (dir, dentry);
 }
 
@@ -1506,6 +1535,8 @@ static inline int security_inode_mknod (
 					struct dentry *dentry,
 					int mode, dev_t dev)
 {
+	if (unlikely (IS_PRIVATE (dir)))
+		return 0;
 	return security_ops->inode_mknod (dir, dentry, mode, dev);
 }
 
@@ -1513,6 +1544,8 @@ static inline void security_inode_post_m
 					      struct dentry *dentry,
 					      int mode, dev_t dev)
 {
+	if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode)))
+		return;
 	security_ops->inode_post_mknod (dir, dentry, mode, dev);
 }
 
@@ -1521,6 +1554,9 @@ static inline int security_inode_rename 
 					 struct inode *new_dir,
 					 struct dentry *new_dentry)
 {
+        if (unlikely (IS_PRIVATE (old_dentry->d_inode) ||
+            (new_dentry->d_inode && IS_PRIVATE (new_dentry->d_inode))))
+		return 0;
 	return security_ops->inode_rename (old_dir, old_dentry,
 					   new_dir, new_dentry);
 }
@@ -1530,83 +1566,114 @@ static inline void security_inode_post_r
 					       struct inode *new_dir,
 					       struct dentry *new_dentry)
 {
+	if (unlikely (IS_PRIVATE (old_dentry->d_inode) ||
+	    (new_dentry->d_inode && IS_PRIVATE (new_dentry->d_inode))))
+		return;
 	security_ops->inode_post_rename (old_dir, old_dentry,
 						new_dir, new_dentry);
 }
 
 static inline int security_inode_readlink (struct dentry *dentry)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_readlink (dentry);
 }
 
 static inline int security_inode_follow_link (struct dentry *dentry,
 					      struct nameidata *nd)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_follow_link (dentry, nd);
 }
 
 static inline int security_inode_permission (struct inode *inode, int mask,
 					     struct nameidata *nd)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return 0;
 	return security_ops->inode_permission (inode, mask, nd);
 }
 
 static inline int security_inode_setattr (struct dentry *dentry,
 					  struct iattr *attr)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_setattr (dentry, attr);
 }
 
 static inline int security_inode_getattr (struct vfsmount *mnt,
 					  struct dentry *dentry)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_getattr (mnt, dentry);
 }
 
 static inline void security_inode_delete (struct inode *inode)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return;
 	security_ops->inode_delete (inode);
 }
 
 static inline int security_inode_setxattr (struct dentry *dentry, char *name,
 					   void *value, size_t size, int flags)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_setxattr (dentry, name, value, size, flags);
 }
 
 static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
 						void *value, size_t size, int flags)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return;
 	security_ops->inode_post_setxattr (dentry, name, value, size, flags);
 }
 
 static inline int security_inode_getxattr (struct dentry *dentry, char *name)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_getxattr (dentry, name);
 }
 
 static inline int security_inode_listxattr (struct dentry *dentry)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_listxattr (dentry);
 }
 
 static inline int security_inode_removexattr (struct dentry *dentry, char *name)
 {
+	if (unlikely (IS_PRIVATE (dentry->d_inode)))
+		return 0;
 	return security_ops->inode_removexattr (dentry, name);
 }
 
 static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return 0;
 	return security_ops->inode_getsecurity(inode, name, buffer, size);
 }
 
 static inline int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return 0;
 	return security_ops->inode_setsecurity(inode, name, value, size, flags);
 }
 
 static inline int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
 {
+	if (unlikely (IS_PRIVATE (inode)))
+		return 0;
 	return security_ops->inode_listsecurity(inode, buffer, buffer_size);
 }
 
@@ -1631,16 +1698,18 @@ static inline int security_file_ioctl (s
 	return security_ops->file_ioctl (file, cmd, arg);
 }
 
-static inline int security_file_mmap (struct file *file, unsigned long prot,
+static inline int security_file_mmap (struct file *file, unsigned long reqprot,
+				      unsigned long prot,
 				      unsigned long flags)
 {
-	return security_ops->file_mmap (file, prot, flags);
+	return security_ops->file_mmap (file, reqprot, prot, flags);
 }
 
 static inline int security_file_mprotect (struct vm_area_struct *vma,
+					  unsigned long reqprot,
 					  unsigned long prot)
 {
-	return security_ops->file_mprotect (vma, prot);
+	return security_ops->file_mprotect (vma, reqprot, prot);
 }
 
 static inline int security_file_lock (struct file *file, unsigned int cmd)
@@ -1883,6 +1952,8 @@ static inline int security_sem_semop (st
 
 static inline void security_d_instantiate (struct dentry *dentry, struct inode *inode)
 {
+	if (unlikely (inode && IS_PRIVATE (inode)))
+		return;
 	security_ops->d_instantiate (dentry, inode);
 }
 
@@ -2278,13 +2349,15 @@ static inline int security_file_ioctl (s
 	return 0;
 }
 
-static inline int security_file_mmap (struct file *file, unsigned long prot,
+static inline int security_file_mmap (struct file *file, unsigned long reqprot,
+				      unsigned long prot,
 				      unsigned long flags)
 {
 	return 0;
 }
 
 static inline int security_file_mprotect (struct vm_area_struct *vma,
+					  unsigned long reqprot,
 					  unsigned long prot)
 {
 	return 0;
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -18,6 +18,7 @@ struct seq_file {
 	size_t from;
 	size_t count;
 	loff_t index;
+	loff_t version;
 	struct semaphore sem;
 	struct seq_operations *op;
 	void *private;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -106,6 +106,19 @@
 /* TXX9 type number */
 #define PORT_TXX9       64
 
+/* NEC VR4100 series SIU/DSIU */
+#define PORT_VR41XX_SIU		65
+#define PORT_VR41XX_DSIU	66
+
+/* Samsung S3C2400 SoC */
+#define PORT_S3C2400	67
+
+/* M32R SIO */
+#define PORT_M32R_SIO	68
+
+/*Digi jsm */
+#define PORT_JSM        65
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>
@@ -350,6 +363,7 @@ void uart_unregister_port(struct uart_dr
 int uart_register_port(struct uart_driver *reg, struct uart_port *port);
 int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
+int uart_match_port(struct uart_port *port1, struct uart_port *port2);
 
 /*
  * Power Management
@@ -465,6 +479,25 @@ uart_handle_cts_change(struct uart_port 
 	}
 }
 
+#include <linux/tty_flip.h>
+
+static inline void
+uart_insert_char(struct uart_port *port, unsigned int status,
+		 unsigned int overrun, unsigned int ch, unsigned int flag)
+{
+	struct tty_struct *tty = port->info->tty;
+
+	if ((status & port->ignore_status_mask & ~overrun) == 0)
+		tty_insert_flip_char(tty, ch, flag);
+
+	/*
+	 * Overrun is special.  Since it's reported immediately,
+	 * it doesn't affect the current character.
+	 */
+	if (status & ~port->ignore_status_mask & overrun)
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+}
+
 /*
  *	UART_ENABLE_MS - determine if port should enable modem status irqs
  */
diff --git a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -10,18 +10,18 @@
  */
 
 #include <linux/ioctl.h>
-#include <linux/interrupt.h>
 
 #define SPIOCSTYPE	_IOW('q', 0x01, unsigned long)
 
 #ifdef __KERNEL__
 
+#include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
+#include <linux/mod_devicetable.h>
 
 struct serio {
-	void *private;
 	void *port_data;
 
 	char name[32];
@@ -29,19 +29,15 @@ struct serio {
 
 	unsigned int manual_bind;
 
-	unsigned short idbus;
-	unsigned short idvendor;
-	unsigned short idproduct;
-	unsigned short idversion;
-
-	unsigned long type;
-	unsigned long event;
+	struct serio_device_id id;
 
 	spinlock_t lock;		/* protects critical sections from port's interrupt handler */
 
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
 	void (*close)(struct serio *);
+	int (*start)(struct serio *);
+	void (*stop)(struct serio *);
 
 	struct serio *parent, *child;
 
@@ -49,6 +45,7 @@ struct serio {
 	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
 
 	struct device dev;
+	unsigned int registered;	/* port has been fully registered with driver core */
 
 	struct list_head node;
 };
@@ -58,19 +55,18 @@ struct serio_driver {
 	void *private;
 	char *description;
 
+	struct serio_device_id *id_table;
 	unsigned int manual_bind;
 
 	void (*write_wakeup)(struct serio *);
 	irqreturn_t (*interrupt)(struct serio *, unsigned char,
 			unsigned int, struct pt_regs *);
-	void (*connect)(struct serio *, struct serio_driver *drv);
+	int  (*connect)(struct serio *, struct serio_driver *drv);
 	int  (*reconnect)(struct serio *);
 	void (*disconnect)(struct serio *);
 	void (*cleanup)(struct serio *);
 
 	struct device_driver driver;
-
-	struct list_head node;
 };
 #define to_serio_driver(d)	container_of(d, struct serio_driver, driver)
 
@@ -80,15 +76,28 @@ void serio_rescan(struct serio *serio);
 void serio_reconnect(struct serio *serio);
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
-void serio_register_port(struct serio *serio);
-void serio_register_port_delayed(struct serio *serio);
+void __serio_register_port(struct serio *serio, struct module *owner);
+static inline void serio_register_port(struct serio *serio)
+{
+	__serio_register_port(serio, THIS_MODULE);
+}
+
 void serio_unregister_port(struct serio *serio);
-void serio_unregister_port_delayed(struct serio *serio);
+void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
+static inline void serio_unregister_port_delayed(struct serio *serio)
+{
+	__serio_unregister_port_delayed(serio, THIS_MODULE);
+}
+
+void __serio_register_driver(struct serio_driver *drv, struct module *owner);
+static inline void serio_register_driver(struct serio_driver *drv)
+{
+	__serio_register_driver(drv, THIS_MODULE);
+}
 
-void serio_register_driver(struct serio_driver *drv);
 void serio_unregister_driver(struct serio_driver *drv);
 
-static __inline__ int serio_write(struct serio *serio, unsigned char data)
+static inline int serio_write(struct serio *serio, unsigned char data)
 {
 	if (serio->write)
 		return serio->write(serio, data);
@@ -96,29 +105,42 @@ static __inline__ int serio_write(struct
 		return -1;
 }
 
-static __inline__ void serio_drv_write_wakeup(struct serio *serio)
+static inline void serio_drv_write_wakeup(struct serio *serio)
 {
 	if (serio->drv && serio->drv->write_wakeup)
 		serio->drv->write_wakeup(serio);
 }
 
-static __inline__ void serio_cleanup(struct serio *serio)
+static inline void serio_cleanup(struct serio *serio)
 {
 	if (serio->drv && serio->drv->cleanup)
 		serio->drv->cleanup(serio);
 }
 
+/*
+ * Use the following fucntions to manipulate serio's per-port
+ * driver-specific data.
+ */
+static inline void *serio_get_drvdata(struct serio *serio)
+{
+	return dev_get_drvdata(&serio->dev);
+}
+
+static inline void serio_set_drvdata(struct serio *serio, void *data)
+{
+	dev_set_drvdata(&serio->dev, data);
+}
 
 /*
  * Use the following fucntions to protect critical sections in
  * driver code from port's interrupt handler
  */
-static __inline__ void serio_pause_rx(struct serio *serio)
+static inline void serio_pause_rx(struct serio *serio)
 {
 	spin_lock_irq(&serio->lock);
 }
 
-static __inline__ void serio_continue_rx(struct serio *serio)
+static inline void serio_continue_rx(struct serio *serio)
 {
 	spin_unlock_irq(&serio->lock);
 }
@@ -126,12 +148,12 @@ static __inline__ void serio_continue_rx
 /*
  * Use the following fucntions to pin serio's driver in process context
  */
-static __inline__ int serio_pin_driver(struct serio *serio)
+static inline int serio_pin_driver(struct serio *serio)
 {
 	return down_interruptible(&serio->drv_sem);
 }
 
-static __inline__ void serio_unpin_driver(struct serio *serio)
+static inline void serio_unpin_driver(struct serio *serio)
 {
 	up(&serio->drv_sem);
 }
@@ -146,15 +168,20 @@ static __inline__ void serio_unpin_drive
 #define SERIO_PARITY	2
 #define SERIO_FRAME	4
 
-#define SERIO_TYPE	0xff000000UL
-#define SERIO_XT	0x00000000UL
-#define SERIO_8042	0x01000000UL
-#define SERIO_RS232	0x02000000UL
-#define SERIO_HIL_MLC	0x03000000UL
-#define SERIO_PS_PSTHRU	0x05000000UL
-#define SERIO_8042_XL	0x06000000UL
+/*
+ * Serio types
+ */
+#define SERIO_XT	0x00
+#define SERIO_8042	0x01
+#define SERIO_RS232	0x02
+#define SERIO_HIL_MLC	0x03
+#define SERIO_PS_PSTHRU	0x05
+#define SERIO_8042_XL	0x06
 
-#define SERIO_PROTO	0xFFUL
+/*
+ * Serio types
+ */
+#define SERIO_UNKNOWN	0x00
 #define SERIO_MSC	0x01
 #define SERIO_SUN	0x02
 #define SERIO_MS	0x03
@@ -181,8 +208,7 @@ static __inline__ void serio_unpin_drive
 #define SERIO_SNES232	0x26
 #define SERIO_SEMTECH	0x27
 #define SERIO_LKKBD	0x28
-
-#define SERIO_ID	0xff00UL
-#define SERIO_EXTRA	0xff0000UL
+#define SERIO_ELO	0x29
+#define SERIO_MICROTOUCH	0x30
 
 #endif
diff --git a/include/linux/signal.h b/include/linux/signal.h
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -8,7 +8,16 @@
 
 #ifdef __KERNEL__
 
-#define MAX_SIGPENDING	1024
+/*
+ * 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
 
 /*
  * Real Time signals may be queued.
@@ -211,14 +220,19 @@ static inline void init_sigpending(struc
 	INIT_LIST_HEAD(&sig->list);
 }
 
+/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
+static inline int valid_signal(unsigned long sig)
+{
+	return sig <= _NSIG ? 1 : 0;
+}
+
 extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
+extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
 
-#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
-#endif
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -83,12 +83,6 @@
  *	Any questions? No questions, good. 		--ANK
  */
 
-#ifdef __i386__
-#define NET_CALLER(arg) (*(((void **)&arg) - 1))
-#else
-#define NET_CALLER(arg) __builtin_return_address(0)
-#endif
-
 struct net_device;
 
 #ifdef CONFIG_NETFILTER
@@ -146,6 +140,20 @@ struct skb_shared_info {
 	skb_frag_t	frags[MAX_SKB_FRAGS];
 };
 
+/* We divide dataref into two halves.  The higher 16 bits hold references
+ * to the payload part of skb->data.  The lower 16 bits hold references to
+ * the entire skb->data.  It is up to the users of the skb to agree on
+ * where the payload starts.
+ *
+ * All users must obey the rule that the skb->data reference count must be
+ * greater than or equal to the payload reference count.
+ *
+ * Holding a reference to the payload part means that the user does not
+ * care about modifications to the header part of skb->data.
+ */
+#define SKB_DATAREF_SHIFT 16
+#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
+
 /** 
  *	struct sk_buff - socket buffer
  *	@next: Next buffer in list
@@ -159,14 +167,16 @@ struct skb_shared_info {
  *	@h: Transport layer header
  *	@nh: Network layer header
  *	@mac: Link layer header
- *	@dst: FIXME: Describe this field
+ *	@dst: destination entry
+ *	@sp: the security path, used for xfrm
  *	@cb: Control buffer. Free for use by every layer. Put private vars here
  *	@len: Length of actual data
  *	@data_len: Data length
  *	@mac_len: Length of link layer header
  *	@csum: Checksum
- *	@__unused: Dead field, may be reused
+ *	@local_df: allow local fragmentation
  *	@cloned: Head may be cloned (check refcnt to be sure)
+ *	@nohdr: Payload reference only, must not modify header
  *	@pkt_type: Packet class
  *	@ip_summed: Driver fed us an IP checksum
  *	@priority: Packet queueing priority
@@ -187,6 +197,8 @@ struct skb_shared_info {
  *	@nf_bridge: Saved data about a bridged frame - see br_netfilter.c
  *      @private: Data which is private to the HIPPI implementation
  *	@tc_index: Traffic control index
+ *	@tc_verd: traffic control verdict
+ *	@tc_classid: traffic control classid
  */
 
 struct sk_buff {
@@ -238,7 +250,8 @@ struct sk_buff {
 				mac_len,
 				csum;
 	unsigned char		local_df,
-				cloned,
+				cloned:1,
+				nohdr:1,
 				pkt_type,
 				ip_summed;
 	__u32			priority;
@@ -370,7 +383,42 @@ static inline void kfree_skb(struct sk_b
  */
 static inline int skb_cloned(const struct sk_buff *skb)
 {
-	return skb->cloned && atomic_read(&skb_shinfo(skb)->dataref) != 1;
+	return skb->cloned &&
+	       (atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1;
+}
+
+/**
+ *	skb_header_cloned - is the header a clone
+ *	@skb: buffer to check
+ *
+ *	Returns true if modifying the header part of the buffer requires
+ *	the data to be copied.
+ */
+static inline int skb_header_cloned(const struct sk_buff *skb)
+{
+	int dataref;
+
+	if (!skb->cloned)
+		return 0;
+
+	dataref = atomic_read(&skb_shinfo(skb)->dataref);
+	dataref = (dataref & SKB_DATAREF_MASK) - (dataref >> SKB_DATAREF_SHIFT);
+	return dataref != 1;
+}
+
+/**
+ *	skb_header_release - release reference to header
+ *	@skb: buffer to operate on
+ *
+ *	Drop a reference to the header part of the buffer.  This is done
+ *	by acquiring a payload reference.  You must not read from the header
+ *	part of skb->data after this.
+ */
+static inline void skb_header_release(struct sk_buff *skb)
+{
+	BUG_ON(skb->nohdr);
+	skb->nohdr = 1;
+	atomic_add(1 << SKB_DATAREF_SHIFT, &skb_shinfo(skb)->dataref);
 }
 
 /**
@@ -921,6 +969,7 @@ static inline void __skb_queue_purge(str
 		kfree_skb(skb);
 }
 
+#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB
 /**
  *	__dev_alloc_skb - allocate an skbuff for sending
  *	@length: length to allocate
@@ -933,7 +982,6 @@ static inline void __skb_queue_purge(str
  *
  *	%NULL is returned in there is no free memory.
  */
-#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB
 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
 					      int gfp_mask)
 {
@@ -1054,6 +1102,42 @@ static inline int skb_linearize(struct s
 	return __skb_linearize(skb, gfp);
 }
 
+/**
+ *	skb_postpull_rcsum - update checksum for received skb after pull
+ *	@skb: buffer to update
+ *	@start: start of data before pull
+ *	@len: length of data pulled
+ *
+ *	After doing a pull on a received packet, you need to call this to
+ *	update the CHECKSUM_HW checksum, or set ip_summed to CHECKSUM_NONE
+ *	so that it can be recomputed from scratch.
+ */
+
+static inline void skb_postpull_rcsum(struct sk_buff *skb,
+					 const void *start, int len)
+{
+	if (skb->ip_summed == CHECKSUM_HW)
+		skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0));
+}
+
+/**
+ *	pskb_trim_rcsum - trim received skb and update checksum
+ *	@skb: buffer to trim
+ *	@len: new length
+ *
+ *	This is exactly the same as pskb_trim except that it ensures the
+ *	checksum of received packets are still valid after the operation.
+ */
+
+static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
+{
+	if (len >= skb->len)
+		return 0;
+	if (skb->ip_summed == CHECKSUM_HW)
+		skb->ip_summed = CHECKSUM_NONE;
+	return __pskb_trim(skb, len);
+}
+
 static inline void *kmap_skb_frag(const skb_frag_t *frag)
 {
 #ifdef CONFIG_HIGHMEM
@@ -1094,6 +1178,8 @@ extern unsigned int    skb_checksum(cons
 				    int len, unsigned int csum);
 extern int	       skb_copy_bits(const struct sk_buff *skb, int offset,
 				     void *to, int len);
+extern int	       skb_store_bits(const struct sk_buff *skb, int offset,
+				      void *from, int len);
 extern unsigned int    skb_copy_and_csum_bits(const struct sk_buff *skb,
 					      int offset, u8 *to, int len,
 					      unsigned int csum);
@@ -1118,22 +1204,6 @@ static inline void *skb_header_pointer(c
 extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
 
-struct skb_iter {
-	/* Iteration functions set these */
-	unsigned char *data;
-	unsigned int len;
-
-	/* Private to iteration */
-	unsigned int nextfrag;
-	struct sk_buff *fraglist;
-};
-
-/* Keep iterating until skb_iter_next returns false. */
-extern void skb_iter_first(const struct sk_buff *skb, struct skb_iter *i);
-extern int skb_iter_next(const struct sk_buff *skb, struct skb_iter *i);
-/* Call this if aborting loop before !skb_iter_next */
-extern void skb_iter_abort(const struct sk_buff *skb, struct skb_iter *i);
-
 #ifdef CONFIG_NETFILTER
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
 {
diff --git a/include/linux/slab.h b/include/linux/slab.h
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -61,17 +61,10 @@ extern kmem_cache_t *kmem_cache_create(c
 				       void (*)(void *, kmem_cache_t *, unsigned long));
 extern int kmem_cache_destroy(kmem_cache_t *);
 extern int kmem_cache_shrink(kmem_cache_t *);
-extern void *kmem_cache_alloc(kmem_cache_t *, int);
-#ifdef CONFIG_NUMA
-extern void *kmem_cache_alloc_node(kmem_cache_t *, int);
-#else
-static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int node)
-{
-	return kmem_cache_alloc(cachep, GFP_KERNEL);
-}
-#endif
+extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast);
 extern void kmem_cache_free(kmem_cache_t *, void *);
 extern unsigned int kmem_cache_size(kmem_cache_t *);
+extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags);
 
 /* Size description struct for general caches. */
 struct cache_sizes {
@@ -80,9 +73,9 @@ struct cache_sizes {
 	kmem_cache_t	*cs_dmacachep;
 };
 extern struct cache_sizes malloc_sizes[];
-extern void *__kmalloc(size_t, int);
+extern void *__kmalloc(size_t, unsigned int __nocast);
 
-static inline void *kmalloc(size_t size, int flags)
+static inline void *kmalloc(size_t size, unsigned int __nocast flags)
 {
 	if (__builtin_constant_p(size)) {
 		int i = 0;
@@ -105,16 +98,29 @@ found:
 	return __kmalloc(size, flags);
 }
 
-extern void *kcalloc(size_t, size_t, int);
+extern void *kcalloc(size_t, size_t, unsigned int __nocast);
 extern void kfree(const void *);
 extern unsigned int ksize(const void *);
 
+#ifdef CONFIG_NUMA
+extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node);
+extern void *kmalloc_node(size_t size, int flags, int node);
+#else
+static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node)
+{
+	return kmem_cache_alloc(cachep, flags);
+}
+static inline void *kmalloc_node(size_t size, int flags, int node)
+{
+	return kmalloc(size, flags);
+}
+#endif
+
 extern int FASTCALL(kmem_cache_reap(int));
 extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr));
 
 /* System wide caches */
 extern kmem_cache_t	*vm_area_cachep;
-extern kmem_cache_t	*mm_cachep;
 extern kmem_cache_t	*names_cachep;
 extern kmem_cache_t	*files_cachep;
 extern kmem_cache_t	*filp_cachep;
diff --git a/include/linux/smp.h b/include/linux/smp.h
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -71,11 +71,6 @@ static inline int on_each_cpu(void (*fun
 	return ret;
 }
 
-/*
- * True once the per process idle is forked
- */
-extern int smp_threads_ready;
-
 #define MSG_ALL_BUT_SELF	0x8000	/* Assume <32768 CPU's */
 #define MSG_ALL			0x8001
 
@@ -102,7 +97,6 @@ void smp_prepare_boot_cpu(void);
 # define smp_processor_id()			0
 #endif
 #define hard_smp_processor_id()			0
-#define smp_threads_ready			1
 #define smp_call_function(func,info,retry,wait)	({ 0; })
 #define on_each_cpu(func,info,retry,wait)	({ func(info); 0; })
 static inline void smp_send_reschedule(int cpu) { }
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)sockios.h	1.0.2	03/09/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
diff --git a/include/linux/sort.h b/include/linux/sort.h
new file mode 100644
--- /dev/null
+++ b/include/linux/sort.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_SORT_H
+#define _LINUX_SORT_H
+
+#include <linux/types.h>
+
+void sort(void *base, size_t num, size_t size,
+	  int (*cmp)(const void *, const void *),
+	  void (*swap)(void *, void *, int));
+
+#endif
diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h
--- a/include/linux/soundcard.h
+++ b/include/linux/soundcard.h
@@ -39,6 +39,13 @@
 /* In Linux we need to be prepared for cross compiling */
 #include <linux/ioctl.h>
 
+/* Endian macros. */
+#ifdef __KERNEL__
+#  include <asm/byteorder.h>
+#else
+#  include <endian.h>
+#endif
+
 /*
  *	Supported card ID numbers (Should be somewhere else?)
  */
@@ -179,13 +186,26 @@ typedef struct seq_event_rec {
  * Some big endian/little endian handling macros
  */
 
-#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__sparc__) || defined(HPPA) || defined(PPC) || defined(__mc68000__)
-/* Big endian machines */
-#  define _PATCHKEY(id) (0xfd00|id)
-#  define AFMT_S16_NE AFMT_S16_BE
-#else
-#  define _PATCHKEY(id) ((id<<8)|0xfd)
-#  define AFMT_S16_NE AFMT_S16_LE
+#define _LINUX_PATCHKEY_H_INDIRECT
+#include <linux/patchkey.h>
+#undef _LINUX_PATCHKEY_H_INDIRECT
+
+#if defined(__KERNEL__)
+#  if defined(__BIG_ENDIAN)
+#    define AFMT_S16_NE AFMT_S16_BE
+#  elif defined(__LITTLE_ENDIAN)
+#    define AFMT_S16_NE AFMT_S16_LE
+#  else
+#    error "could not determine byte order"
+#  endif
+#elif defined(__BYTE_ORDER)
+#  if __BYTE_ORDER == __BIG_ENDIAN
+#    define AFMT_S16_NE AFMT_S16_BE
+#  elif __BYTE_ORDER == __LITTLE_ENDIAN
+#    define AFMT_S16_NE AFMT_S16_LE
+#  else
+#    error "could not determine byte order"
+#  endif
 #endif
 
 /*
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -248,7 +248,7 @@ typedef struct {
 
 #define _spin_trylock_bh(lock)	({preempt_disable(); local_bh_disable(); \
 				_raw_spin_trylock(lock) ? \
-				1 : ({preempt_enable(); local_bh_enable(); 0;});})
+				1 : ({preempt_enable_no_resched(); local_bh_enable(); 0;});})
 
 #define _spin_lock(lock)	\
 do { \
@@ -383,7 +383,7 @@ do { \
 #define _spin_unlock_bh(lock) \
 do { \
 	_raw_spin_unlock(lock); \
-	preempt_enable(); \
+	preempt_enable_no_resched(); \
 	local_bh_enable(); \
 	__release(lock); \
 } while (0)
@@ -391,7 +391,7 @@ do { \
 #define _write_unlock_bh(lock) \
 do { \
 	_raw_write_unlock(lock); \
-	preempt_enable(); \
+	preempt_enable_no_resched(); \
 	local_bh_enable(); \
 	__release(lock); \
 } while (0)
@@ -423,8 +423,8 @@ do { \
 #define _read_unlock_bh(lock)	\
 do { \
 	_raw_read_unlock(lock);	\
+	preempt_enable_no_resched();	\
 	local_bh_enable();	\
-	preempt_enable();	\
 	__release(lock); \
 } while (0)
 
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
--- a/include/linux/stallion.h
+++ b/include/linux/stallion.h
@@ -126,7 +126,7 @@ typedef struct stlbrd {
 	int		nrbnks;
 	int		irq;
 	int		irqtype;
-	void		(*isr)(struct stlbrd *brdp);
+	int		(*isr)(struct stlbrd *brdp);
 	unsigned int	ioaddr1;
 	unsigned int	ioaddr2;
 	unsigned int	iosize1;
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -8,7 +8,7 @@
 #include <linux/cpu.h>
 #include <asm/system.h>
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
 /**
  * stop_machine_run: freeze the machine on all CPUs and run this function
  * @fn: the function to run
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -35,8 +35,7 @@ struct auth_cred {
  * Client user credentials
  */
 struct rpc_cred {
-	struct list_head	cr_hash;	/* hash chain */
-	struct rpc_auth *	cr_auth;
+	struct hlist_node	cr_hash;	/* hash chain */
 	struct rpc_credops *	cr_ops;
 	unsigned long		cr_expire;	/* when to gc */
 	atomic_t		cr_count;	/* ref count */
@@ -59,10 +58,13 @@ struct rpc_cred {
  */
 #define RPC_CREDCACHE_NR	8
 #define RPC_CREDCACHE_MASK	(RPC_CREDCACHE_NR - 1)
+struct rpc_cred_cache {
+	struct hlist_head	hashtable[RPC_CREDCACHE_NR];
+	unsigned long		nextgc;		/* next garbage collection */
+	unsigned long		expire;		/* cache expiry interval */
+};
+
 struct rpc_auth {
-	struct list_head	au_credcache[RPC_CREDCACHE_NR];
-	unsigned long		au_expire;	/* cache expiry interval */
-	unsigned long		au_nextgc;	/* next garbage collection */
 	unsigned int		au_cslack;	/* call cred size estimate */
 	unsigned int		au_rslack;	/* reply verf size guess */
 	unsigned int		au_flags;	/* various flags */
@@ -73,6 +75,7 @@ struct rpc_auth {
 						 * case) */
 	atomic_t		au_count;	/* Reference counter */
 
+	struct rpc_cred_cache *	au_credcache;
 	/* per-flavor data */
 };
 #define RPC_AUTH_PROC_CREDS	0x0010		/* process creds (including
@@ -91,14 +94,16 @@ struct rpc_authops {
 	struct rpc_auth *	(*create)(struct rpc_clnt *, rpc_authflavor_t);
 	void			(*destroy)(struct rpc_auth *);
 
+	struct rpc_cred *	(*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
 	struct rpc_cred *	(*crcreate)(struct rpc_auth*, struct auth_cred *, int);
 };
 
 struct rpc_credops {
+	const char *		cr_name;	/* Name of the auth flavour */
 	void			(*crdestroy)(struct rpc_cred *);
 
 	int			(*crmatch)(struct auth_cred *, struct rpc_cred *, int);
-	u32 *			(*crmarshal)(struct rpc_task *, u32 *, int);
+	u32 *			(*crmarshal)(struct rpc_task *, u32 *);
 	int			(*crrefresh)(struct rpc_task *);
 	u32 *			(*crvalidate)(struct rpc_task *, u32 *);
 	int			(*crwrap_req)(struct rpc_task *, kxdrproc_t,
@@ -130,7 +135,7 @@ int			rpcauth_unwrap_resp(struct rpc_tas
 int			rpcauth_refreshcred(struct rpc_task *);
 void			rpcauth_invalcred(struct rpc_task *);
 int			rpcauth_uptodatecred(struct rpc_task *);
-void			rpcauth_init_credcache(struct rpc_auth *);
+int			rpcauth_init_credcache(struct rpc_auth *, unsigned long);
 void			rpcauth_free_credcache(struct rpc_auth *);
 
 static inline
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
--- a/include/linux/sunrpc/auth_gss.h
+++ b/include/linux/sunrpc/auth_gss.h
@@ -68,18 +68,21 @@ struct rpc_gss_init_res {
 
 struct gss_cl_ctx {
 	atomic_t		count;
-	u32			gc_proc;
+	enum rpc_gss_proc	gc_proc;
 	u32			gc_seq;
 	spinlock_t		gc_seq_lock;
 	struct gss_ctx		*gc_gss_ctx;
 	struct xdr_netobj	gc_wire_ctx;
 	u32			gc_win;
+	unsigned long		gc_expiry;
 };
 
+struct gss_upcall_msg;
 struct gss_cred {
 	struct rpc_cred		gc_base;
-	u32			gc_flavor;
+	enum rpc_gss_svc	gc_service;
 	struct gss_cl_ctx	*gc_ctx;
+	struct gss_upcall_msg	*gc_upcall;
 };
 
 #define gc_uid			gc_base.cr_uid
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -37,8 +37,7 @@
  * Entries have a ref count and a 'hashed' flag which counts the existance
  * in the hash table.
  * We only expire entries when refcount is zero.
- * Existance in the cache is not measured in refcount but rather in
- * CACHE_HASHED flag.
+ * Existance in the cache is counted  the refcount.
  */
 
 /* Every cache item has a common header that is used
@@ -57,7 +56,6 @@ struct cache_head {
 #define	CACHE_VALID	0	/* Entry contains valid data */
 #define	CACHE_NEGATIVE	1	/* Negative entry - there is no match for the key */
 #define	CACHE_PENDING	2	/* An upcall has been sent but no reply received yet*/
-#define	CACHE_HASHED	3	/* Entry is in a hash table */
 
 #define	CACHE_NEW_EXPIRY 120	/* keep new things pending confirmation for 120 seconds */
 
@@ -185,7 +183,6 @@ RTN *FNAME ARGS										\
 											\
 			if (new)							\
 				{INIT;}							\
-			cache_get(&tmp->MEMBER);					\
 			if (set) {							\
 				if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
 				{ /* need to swap in new */				\
@@ -194,8 +191,6 @@ RTN *FNAME ARGS										\
 					new->MEMBER.next = tmp->MEMBER.next;		\
 					*hp = &new->MEMBER;				\
 					tmp->MEMBER.next = NULL;			\
-					set_bit(CACHE_HASHED, &new->MEMBER.flags);	\
-					clear_bit(CACHE_HASHED, &tmp->MEMBER.flags);	\
 					t2 = tmp; tmp = new; new = t2;			\
 				}							\
 				if (test_bit(CACHE_NEGATIVE,  &item->MEMBER.flags))	\
@@ -205,6 +200,7 @@ RTN *FNAME ARGS										\
 					clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);	\
 				}							\
 			}								\
+			cache_get(&tmp->MEMBER);					\
 			if (set||new) write_unlock(&(DETAIL)->hash_lock);		\
 			else read_unlock(&(DETAIL)->hash_lock);				\
 			if (set)							\
@@ -220,7 +216,7 @@ RTN *FNAME ARGS										\
 		new->MEMBER.next = *head;						\
 		*head = &new->MEMBER;							\
 		(DETAIL)->entries ++;							\
-		set_bit(CACHE_HASHED, &new->MEMBER.flags);				\
+		cache_get(&new->MEMBER);						\
 		if (set) {								\
 			tmp = new;							\
 			if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags))		\
@@ -268,15 +264,10 @@ static inline struct cache_head  *cache_
 
 static inline int cache_put(struct cache_head *h, struct cache_detail *cd)
 {
-	atomic_dec(&h->refcnt);
-	if (!atomic_read(&h->refcnt) &&
+	if (atomic_read(&h->refcnt) <= 2 &&
 	    h->expiry_time < cd->nextcheck)
 		cd->nextcheck = h->expiry_time;
-	if (!test_bit(CACHE_HASHED, &h->flags) &&
-	    !atomic_read(&h->refcnt))
-		return 1;
-
-	return 0;
+	return atomic_dec_and_test(&h->refcnt);
 }
 
 extern void cache_init(struct cache_head *h);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -51,7 +51,6 @@ struct rpc_clnt {
 				cl_intr     : 1,/* interruptible */
 				cl_chatty   : 1,/* be verbose */
 				cl_autobind : 1,/* use getport() */
-				cl_droppriv : 1,/* enable NFS suid hack */
 				cl_oneshot  : 1,/* dispose after use */
 				cl_dead     : 1;/* abandoned */
 
@@ -129,6 +128,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);
+size_t		rpc_max_payload(struct rpc_clnt *);
 
 static __inline__
 int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -33,8 +33,9 @@ struct gss_ctx {
 
 /* gss-api prototypes; note that these are somewhat simplified versions of
  * the prototypes specified in RFC 2744. */
-u32 gss_import_sec_context(
-		struct xdr_netobj	*input_token,
+int gss_import_sec_context(
+		const void*		input_token,
+		size_t			bufsize,
 		struct gss_api_mech	*mech,
 		struct gss_ctx		**ctx_id);
 u32 gss_get_mic(
@@ -50,8 +51,6 @@ u32 gss_verify_mic(
 u32 gss_delete_sec_context(
 		struct gss_ctx		**ctx_id);
 
-struct gss_api_mech * gss_mech_get_by_name(char *name);
-struct gss_api_mech * gss_mech_get_by_pseudoflavor(u32 pseudoflavor);
 u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
 char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
 
@@ -80,8 +79,9 @@ struct gss_api_mech {
 
 /* and must provide the following operations: */
 struct gss_api_ops {
-	u32 (*gss_import_sec_context)(
-			struct xdr_netobj	*input_token,
+	int (*gss_import_sec_context)(
+			const void		*input_token,
+			size_t			bufsize,
 			struct gss_ctx		*ctx_id);
 	u32 (*gss_get_mic)(
 			struct gss_ctx		*ctx_id,
@@ -105,7 +105,7 @@ void gss_mech_unregister(struct gss_api_
 struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
 
 /* Returns a reference to a mechanism, given a name like "krb5" etc. */
-struct gss_api_mech *gss_mech_get_by_name(char *);
+struct gss_api_mech *gss_mech_get_by_name(const char *);
 
 /* Similar, but get by pseudoflavor. */
 struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -53,9 +53,8 @@ struct rpc_task {
 	struct rpc_message	tk_msg;		/* RPC call info */
 	__u32 *			tk_buffer;	/* XDR buffer */
 	size_t			tk_bufsize;
-	__u8			tk_garb_retry,
-				tk_cred_retry,
-				tk_suid_retry;
+	__u8			tk_garb_retry;
+	__u8			tk_cred_retry;
 
 	unsigned long		tk_cookie;	/* Cookie for batching tasks */
 
@@ -118,9 +117,7 @@ typedef void			(*rpc_action)(struct rpc_
  */
 #define RPC_TASK_ASYNC		0x0001		/* is an async task */
 #define RPC_TASK_SWAPPER	0x0002		/* is swapping in/out */
-#define RPC_TASK_SETUID		0x0004		/* is setuid process */
 #define RPC_TASK_CHILD		0x0008		/* is child of other task */
-#define RPC_CALL_REALUID	0x0010		/* try using real uid */
 #define RPC_CALL_MAJORSEEN	0x0020		/* major timeout seen */
 #define RPC_TASK_ROOTCREDS	0x0040		/* force root creds */
 #define RPC_TASK_DYNAMIC	0x0080		/* task was kmalloc'ed */
@@ -129,7 +126,6 @@ typedef void			(*rpc_action)(struct rpc_
 #define RPC_TASK_NOINTR		0x0400		/* uninterruptible task */
 
 #define RPC_IS_ASYNC(t)		((t)->tk_flags & RPC_TASK_ASYNC)
-#define RPC_IS_SETUID(t)	((t)->tk_flags & RPC_TASK_SETUID)
 #define RPC_IS_CHILD(t)		((t)->tk_flags & RPC_TASK_CHILD)
 #define RPC_IS_SWAPPER(t)	((t)->tk_flags & RPC_TASK_SWAPPER)
 #define RPC_DO_ROOTOVERRIDE(t)	((t)->tk_flags & RPC_TASK_ROOTCREDS)
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -251,8 +251,7 @@ struct svc_program {
 	char *			pg_name;	/* service name */
 	char *			pg_class;	/* class name: services sharing authentication */
 	struct svc_stat *	pg_stats;	/* rpc statistics */
-	/* Override authentication. NULL means use default */
-	int			(*pg_authenticate)(struct svc_rqst *, u32 *);
+	int			(*pg_authenticate)(struct svc_rqst *);
 };
 
 /*
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -26,21 +26,23 @@ struct svc_cred {
 struct svc_rqst;		/* forward decl */
 
 /* Authentication is done in the context of a domain.
- * For a server, a domain represents a group of clients using
+ *
+ * Currently, the nfs server uses the auth_domain to stand
+ * for the "client" listed in /etc/exports.
+ *
+ * More generally, a domain might represent a group of clients using
  * a common mechanism for authentication and having a common mapping
  * between local identity (uid) and network identity.  All clients
  * in a domain have similar general access rights.  Each domain can
  * contain multiple principals which will have different specific right
  * based on normal Discretionary Access Control.
  *
- * For a client, a domain represents a number of servers which all
- * use a common authentication mechanism and network identity name space.
- *
  * A domain is created by an authentication flavour module based on name
  * only.  Userspace then fills in detail on demand.
  *
- * The creation of a domain typically implies creation of one or
- * more caches for storing domain specific information.
+ * In the case of auth_unix and auth_null, the auth_domain is also
+ * associated with entries in another cache representing the mapping
+ * of ip addresses to the given client.
  */
 struct auth_domain {
 	struct	cache_head	h;
@@ -92,6 +94,7 @@ struct auth_ops {
 	int	(*accept)(struct svc_rqst *rq, u32 *authp);
 	int	(*release)(struct svc_rqst *rq);
 	void	(*domain_release)(struct auth_domain *);
+	int	(*set_client)(struct svc_rqst *rq);
 };
 
 #define	SVC_GARBAGE	1
@@ -107,6 +110,7 @@ struct auth_ops {
 
 extern int	svc_authenticate(struct svc_rqst *rqstp, u32 *authp);
 extern int	svc_authorise(struct svc_rqst *rqstp);
+extern int	svc_set_client(struct svc_rqst *rqstp);
 extern int	svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
 extern void	svc_auth_unregister(rpc_authflavor_t flavor);
 
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -140,6 +140,9 @@ struct rpc_xprt {
 	unsigned int		rcvsize,	/* socket receive buffer size */
 				sndsize;	/* socket send buffer size */
 
+	size_t			max_payload;	/* largest RPC payload size,
+						   in bytes */
+
 	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 */
diff --git a/include/linux/superhyway.h b/include/linux/superhyway.h
new file mode 100644
--- /dev/null
+++ b/include/linux/superhyway.h
@@ -0,0 +1,79 @@
+/*
+ * include/linux/superhyway.h
+ *
+ * SuperHyway Bus definitions
+ *
+ * Copyright (C) 2004, 2005  Paul Mundt <lethal@linux-sh.org>
+ *
+ * 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 __LINUX_SUPERHYWAY_H
+#define __LINUX_SUPERHYWAY_H
+
+#include <linux/device.h>
+
+/*
+ * SuperHyway IDs
+ */
+#define SUPERHYWAY_DEVICE_ID_SH5_DMAC	0x0183
+
+struct vcr_info {
+	u8	perr_flags;	/* P-port Error flags */
+	u8	merr_flags;	/* Module Error flags */
+	u16	mod_vers;	/* Module Version */
+	u16	mod_id;		/* Module ID */
+	u8	bot_mb;		/* Bottom Memory block */
+	u8	top_mb;		/* Top Memory block */
+};
+
+struct superhyway_device_id {
+	unsigned int id;
+	unsigned long driver_data;
+};
+
+struct superhyway_device;
+extern struct bus_type superhyway_bus_type;
+
+struct superhyway_driver {
+	char *name;
+
+	const struct superhyway_device_id *id_table;
+	struct device_driver drv;
+
+	int (*probe)(struct superhyway_device *dev, const struct superhyway_device_id *id);
+	void (*remove)(struct superhyway_device *dev);
+};
+
+#define to_superhyway_driver(d)	container_of((d), struct superhyway_driver, drv)
+
+struct superhyway_device {
+	char name[32];
+
+	struct device dev;
+
+	struct superhyway_device_id id;
+	struct superhyway_driver *drv;
+
+	struct resource resource;
+	struct vcr_info vcr;
+};
+
+#define to_superhyway_device(d)	container_of((d), struct superhyway_device, dev)
+
+#define superhyway_get_drvdata(d)	dev_get_drvdata(&(d)->dev)
+#define superhyway_set_drvdata(d,p)	dev_set_drvdata(&(d)->dev, (p))
+
+extern int superhyway_scan_bus(void);
+
+/* drivers/sh/superhyway/superhyway.c */
+int superhyway_register_driver(struct superhyway_driver *);
+void superhyway_unregister_driver(struct superhyway_driver *);
+int superhyway_add_device(unsigned int, unsigned long, unsigned long long);
+
+/* drivers/sh/superhyway/superhyway-sysfs.c */
+extern struct device_attribute superhyway_dev_attrs[];
+
+#endif /* __LINUX_SUPERHYWAY_H */
+
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -1,7 +1,7 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
-#if defined(CONFIG_X86) || defined(CONFIG_FRV)
+#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
 #include <asm/suspend.h>
 #endif
 #include <linux/swap.h>
@@ -15,15 +15,26 @@ typedef struct pbe {
 	unsigned long address;		/* address of the copy */
 	unsigned long orig_address;	/* original address of page */
 	swp_entry_t swap_address;	
-	swp_entry_t dummy;		/* we need scratch space at 
-					 * end of page (see link, diskpage)
-					 */
+
+	struct pbe *next;	/* also used as scratch space at
+				 * end of page (see link, diskpage)
+				 */
 } suspend_pagedir_t;
 
+#define for_each_pbe(pbe, pblist) \
+	for (pbe = pblist ; pbe ; pbe = pbe->next)
+
+#define PBES_PER_PAGE      (PAGE_SIZE/sizeof(struct pbe))
+#define PB_PAGE_SKIP       (PBES_PER_PAGE-1)
+
+#define for_each_pb_page(pbe, pblist) \
+	for (pbe = pblist ; pbe ; pbe = (pbe+PB_PAGE_SKIP)->next)
+
+
 #define SWAP_FILENAME_MAXLENGTH	32
 
 
-#define SUSPEND_PD_PAGES(x)     (((x)*sizeof(struct pbe))/PAGE_SIZE+1)
+extern dev_t swsusp_resume_device;
    
 /* mm/vmscan.c */
 extern int shrink_mem(void);
diff --git a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -148,7 +148,7 @@ struct swap_list_t {
 #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
 
 /* linux/mm/oom_kill.c */
-extern void out_of_memory(int gfp_mask);
+extern void out_of_memory(unsigned int __nocast gfp_mask);
 
 /* linux/mm/memory.c */
 extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -456,8 +456,7 @@ asmlinkage long sys_semctl(int semid, in
 asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
 				unsigned nsops,
 				const struct timespec __user *timeout);
-asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
-				int shmflg, unsigned long __user *addr);
+asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg);
 asmlinkage long sys_shmget(key_t key, size_t size, int flag);
 asmlinkage long sys_shmdt(char __user *shmaddr);
 asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -135,6 +135,7 @@ enum
 	KERN_HZ_TIMER=65,	/* int: hz timer on or off */
 	KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */
 	KERN_BOOTLOADER_TYPE=67, /* int: boot loader type */
+	KERN_RANDOMIZE=68, /* int: randomize virtual address space */
 };
 
 
@@ -345,6 +346,7 @@ enum
 	NET_TCP_MODERATE_RCVBUF=106,
 	NET_TCP_TSO_WIN_DIVISOR=107,
 	NET_TCP_BIC_BETA=108,
+	NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109,
 };
 
 enum {
@@ -398,6 +400,8 @@ enum
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 	NET_IPV4_CONF_ARP_IGNORE=19,
+	NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
+	__NET_IPV4_CONF_MAX
 };
 
 /* /proc/sys/net/ipv4/netfilter */
@@ -455,7 +459,8 @@ enum {
 	NET_IPV6_ROUTE_GC_INTERVAL=6,
 	NET_IPV6_ROUTE_GC_ELASTICITY=7,
 	NET_IPV6_ROUTE_MTU_EXPIRES=8,
-	NET_IPV6_ROUTE_MIN_ADVMSS=9
+	NET_IPV6_ROUTE_MIN_ADVMSS=9,
+	NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS=10
 };
 
 enum {
@@ -475,7 +480,8 @@ enum {
 	NET_IPV6_REGEN_MAX_RETRY=14,
 	NET_IPV6_MAX_DESYNC_FACTOR=15,
 	NET_IPV6_MAX_ADDRESSES=16,
-	NET_IPV6_FORCE_MLD_VERSION=17
+	NET_IPV6_FORCE_MLD_VERSION=17,
+	__NET_IPV6_MAX
 };
 
 /* /proc/sys/net/ipv6/icmp */
@@ -500,7 +506,10 @@ enum {
 	NET_NEIGH_GC_INTERVAL=13,
 	NET_NEIGH_GC_THRESH1=14,
 	NET_NEIGH_GC_THRESH2=15,
-	NET_NEIGH_GC_THRESH3=16
+	NET_NEIGH_GC_THRESH3=16,
+	NET_NEIGH_RETRANS_TIME_MS=17,
+	NET_NEIGH_REACHABLE_TIME_MS=18,
+	__NET_NEIGH_MAX
 };
 
 /* /proc/sys/net/ipx */
@@ -636,6 +645,7 @@ enum {
 	NET_SCTP_MAX_BURST               = 12,
 	NET_SCTP_ADDIP_ENABLE		 = 13,
 	NET_SCTP_PRSCTP_ENABLE		 = 14,
+	NET_SCTP_SNDBUF_POLICY		 = 15,
 };
 
 /* /proc/sys/net/bridge */
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -22,6 +22,7 @@
 #define _SYSDEV_H_
 
 #include <linux/kobject.h>
+#include <linux/pm.h>
 
 
 struct sys_device;
@@ -31,7 +32,7 @@ struct sysdev_class {
 
 	/* Default operations for these types of devices */
 	int	(*shutdown)(struct sys_device *);
-	int	(*suspend)(struct sys_device *, u32 state);
+	int	(*suspend)(struct sys_device *, pm_message_t state);
 	int	(*resume)(struct sys_device *);
 	struct kset		kset;
 };
@@ -50,7 +51,7 @@ struct sysdev_driver {
 	int	(*add)(struct sys_device *);
 	int	(*remove)(struct sys_device *);
 	int	(*shutdown)(struct sys_device *);
-	int	(*suspend)(struct sys_device *, u32 state);
+	int	(*suspend)(struct sys_device *, pm_message_t state);
 	int	(*resume)(struct sys_device *);
 };
 
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -99,6 +99,9 @@ sysfs_create_file(struct kobject *, cons
 extern int
 sysfs_update_file(struct kobject *, const struct attribute *);
 
+extern int
+sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
+
 extern void
 sysfs_remove_file(struct kobject *, const struct attribute *);
 
@@ -140,6 +143,10 @@ static inline int sysfs_update_file(stru
 {
 	return 0;
 }
+static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+{
+	return 0;
+}
 
 static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
 {
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -16,10 +16,22 @@
 struct pt_regs;
 struct tty_struct;
 
+/* Possible values of bitmask for enabling sysrq functions */
+/* 0x0001 is reserved for enable everything */
+#define SYSRQ_ENABLE_LOG	0x0002
+#define SYSRQ_ENABLE_KEYBOARD	0x0004
+#define SYSRQ_ENABLE_DUMP	0x0008
+#define SYSRQ_ENABLE_SYNC	0x0010
+#define SYSRQ_ENABLE_REMOUNT	0x0020
+#define SYSRQ_ENABLE_SIGNAL	0x0040
+#define SYSRQ_ENABLE_BOOT	0x0080
+#define SYSRQ_ENABLE_RTNICE	0x0100
+
 struct sysrq_key_op {
 	void (*handler)(int, struct pt_regs *, struct tty_struct *);
 	char *help_msg;
 	char *action_msg;
+	int enable_mask;
 };
 
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -30,7 +42,7 @@ struct sysrq_key_op {
  */
 
 void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
-void __handle_sysrq(int, struct pt_regs *, struct tty_struct *);
+void __handle_sysrq(int, struct pt_regs *, struct tty_struct *, int check_mask);
 int register_sysrq_key(int, struct sysrq_key_op *);
 int unregister_sysrq_key(int, struct sysrq_key_op *);
 struct sysrq_key_op *__sysrq_get_key_op(int key);
diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h
new file mode 100644
--- /dev/null
+++ b/include/linux/tc_act/tc_defact.h
@@ -0,0 +1,21 @@
+#ifndef __LINUX_TC_DEF_H
+#define __LINUX_TC_DEF_H
+
+#include <linux/pkt_cls.h>
+
+struct tc_defact
+{
+	tc_gen;
+};
+                                                                                
+enum
+{
+	TCA_DEF_UNSPEC,
+	TCA_DEF_TM,
+	TCA_DEF_PARMS,
+	TCA_DEF_DATA,
+	__TCA_DEF_MAX
+};
+#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
+
+#endif
diff --git a/include/linux/tc_ematch/tc_em_cmp.h b/include/linux/tc_ematch/tc_em_cmp.h
new file mode 100644
--- /dev/null
+++ b/include/linux/tc_ematch/tc_em_cmp.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_TC_EM_CMP_H
+#define __LINUX_TC_EM_CMP_H
+
+#include <linux/pkt_cls.h>
+
+struct tcf_em_cmp
+{
+	__u32		val;
+	__u32		mask;
+	__u16		off;
+	__u8		align:4;
+	__u8		flags:4;
+	__u8		layer:4;
+	__u8		opnd:4;
+};
+
+enum
+{
+	TCF_EM_ALIGN_U8  = 1,
+	TCF_EM_ALIGN_U16 = 2,
+	TCF_EM_ALIGN_U32 = 4
+};
+
+#define TCF_EM_CMP_TRANS	1
+
+#endif
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
new file mode 100644
--- /dev/null
+++ b/include/linux/tc_ematch/tc_em_meta.h
@@ -0,0 +1,99 @@
+#ifndef __LINUX_TC_EM_META_H
+#define __LINUX_TC_EM_META_H
+
+#include <linux/pkt_cls.h>
+
+enum
+{
+	TCA_EM_META_UNSPEC,
+	TCA_EM_META_HDR,
+	TCA_EM_META_LVALUE,
+	TCA_EM_META_RVALUE,
+	__TCA_EM_META_MAX
+};
+#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1)
+
+struct tcf_meta_val
+{
+	__u16			kind;
+	__u8			shift;
+	__u8			op;
+};
+
+#define TCF_META_TYPE_MASK	(0xf << 12)
+#define TCF_META_TYPE(kind)	(((kind) & TCF_META_TYPE_MASK) >> 12)
+#define TCF_META_ID_MASK	0x7ff
+#define TCF_META_ID(kind)	((kind) & TCF_META_ID_MASK)
+
+enum
+{
+	TCF_META_TYPE_VAR,
+	TCF_META_TYPE_INT,
+	__TCF_META_TYPE_MAX
+};
+#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1)
+
+enum
+{
+	TCF_META_ID_VALUE,
+	TCF_META_ID_RANDOM,
+	TCF_META_ID_LOADAVG_0,
+	TCF_META_ID_LOADAVG_1,
+	TCF_META_ID_LOADAVG_2,
+	TCF_META_ID_DEV,
+	TCF_META_ID_INDEV,
+	TCF_META_ID_REALDEV,
+	TCF_META_ID_PRIORITY,
+	TCF_META_ID_PROTOCOL,
+	TCF_META_ID_SECURITY,
+	TCF_META_ID_PKTTYPE,
+	TCF_META_ID_PKTLEN,
+	TCF_META_ID_DATALEN,
+	TCF_META_ID_MACLEN,
+	TCF_META_ID_NFMARK,
+	TCF_META_ID_TCINDEX,
+	TCF_META_ID_TCVERDICT,
+	TCF_META_ID_TCCLASSID,
+	TCF_META_ID_RTCLASSID,
+	TCF_META_ID_RTIIF,
+	TCF_META_ID_SK_FAMILY,
+	TCF_META_ID_SK_STATE,
+	TCF_META_ID_SK_REUSE,
+	TCF_META_ID_SK_BOUND_IF,
+	TCF_META_ID_SK_REFCNT,
+	TCF_META_ID_SK_SHUTDOWN,
+	TCF_META_ID_SK_PROTO,
+	TCF_META_ID_SK_TYPE,
+	TCF_META_ID_SK_RCVBUF,
+	TCF_META_ID_SK_RMEM_ALLOC,
+	TCF_META_ID_SK_WMEM_ALLOC,
+	TCF_META_ID_SK_OMEM_ALLOC,
+	TCF_META_ID_SK_WMEM_QUEUED,
+	TCF_META_ID_SK_RCV_QLEN,
+	TCF_META_ID_SK_SND_QLEN,
+ 	TCF_META_ID_SK_ERR_QLEN,
+	TCF_META_ID_SK_FORWARD_ALLOCS,
+	TCF_META_ID_SK_SNDBUF,
+ 	TCF_META_ID_SK_ALLOCS,
+ 	TCF_META_ID_SK_ROUTE_CAPS,
+ 	TCF_META_ID_SK_HASHENT,
+ 	TCF_META_ID_SK_LINGERTIME,
+ 	TCF_META_ID_SK_ACK_BACKLOG,
+ 	TCF_META_ID_SK_MAX_ACK_BACKLOG,
+ 	TCF_META_ID_SK_PRIO,
+ 	TCF_META_ID_SK_RCVLOWAT,
+ 	TCF_META_ID_SK_RCVTIMEO,
+ 	TCF_META_ID_SK_SNDTIMEO,
+ 	TCF_META_ID_SK_SENDMSG_OFF,
+ 	TCF_META_ID_SK_WRITE_PENDING,
+	__TCF_META_ID_MAX
+};
+#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
+
+struct tcf_meta_hdr
+{
+	struct tcf_meta_val	left;
+	struct tcf_meta_val	right;
+};
+
+#endif
diff --git a/include/linux/tc_ematch/tc_em_nbyte.h b/include/linux/tc_ematch/tc_em_nbyte.h
new file mode 100644
--- /dev/null
+++ b/include/linux/tc_ematch/tc_em_nbyte.h
@@ -0,0 +1,13 @@
+#ifndef __LINUX_TC_EM_NBYTE_H
+#define __LINUX_TC_EM_NBYTE_H
+
+#include <linux/pkt_cls.h>
+
+struct tcf_em_nbyte
+{
+	__u16		off;
+	__u16		len:12;
+	__u8		layer:4;
+};
+
+#endif
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -216,17 +216,16 @@ struct tcp_options_received {
 	__u32	ts_recent;	/* Time stamp to echo next		*/
 	__u32	rcv_tsval;	/* Time stamp value             	*/
 	__u32	rcv_tsecr;	/* Time stamp echo reply        	*/
-	char	saw_tstamp;	/* Saw TIMESTAMP on last packet		*/
-	char	tstamp_ok;	/* TIMESTAMP seen on SYN packet		*/
-	char	sack_ok;	/* SACK seen on SYN packet		*/
-	char	wscale_ok;	/* Wscale seen on SYN packet		*/
-	__u8	snd_wscale;	/* Window scaling received from sender	*/
-	__u8	rcv_wscale;	/* Window scaling to send to receiver	*/
+	__u16 	saw_tstamp : 1,	/* Saw TIMESTAMP on last packet		*/
+		tstamp_ok : 1,	/* TIMESTAMP seen on SYN packet		*/
+		dsack : 1,	/* D-SACK is scheduled			*/
+		wscale_ok : 1,	/* Wscale seen on SYN packet		*/
+		sack_ok : 4,	/* SACK seen on SYN packet		*/
+		snd_wscale : 4,	/* Window scaling received from sender	*/
+		rcv_wscale : 4;	/* Window scaling to send to receiver	*/
 /*	SACKs data	*/
-	__u8	dsack;		/* D-SACK is scheduled			*/
 	__u8	eff_sacks;	/* Size of SACK array to send with next packet */
 	__u8	num_sacks;	/* Number of SACK blocks		*/
-	__u8	__pad;
 	__u16	user_mss;  	/* mss requested by user in ioctl */
 	__u16	mss_clamp;	/* Maximal mss, negotiated at connection setup */
 };
@@ -284,10 +283,13 @@ struct tcp_sock {
 	__u32	mss_cache;	/* Cached effective mss, not including SACKS */
 	__u16	mss_cache_std;	/* Like mss_cache, but without TSO */
 	__u16	ext_header_len;	/* Network protocol overhead (IP/IPv6 options) */
-	__u16	ext2_header_len;/* Options depending on route */
 	__u8	ca_state;	/* State of fast-retransmit machine 	*/
 	__u8	retransmits;	/* Number of unrecovered RTO timeouts.	*/
 
+	__u16	advmss;		/* Advertised MSS			*/
+	__u32	window_clamp;	/* Maximal window to advertise		*/
+	__u32	rcv_ssthresh;	/* Current window clamp			*/
+
 	__u32	frto_highmark;	/* snd_nxt when RTO occurred */
 	__u8	reordering;	/* Packet reordering metric.		*/
 	__u8	frto_counter;	/* Number of new acks after RTO */
@@ -345,14 +347,9 @@ struct tcp_sock {
 	struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
 	struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
-	__u32	window_clamp;	/* Maximal window to advertise		*/
-	__u32	rcv_ssthresh;	/* Current window clamp			*/
-	__u16	advmss;		/* Advertised MSS			*/
-
 	__u8	syn_retries;	/* num of allowed syn retries */
 	__u8	ecn_flags;	/* ECN status bits.			*/
 	__u16	prior_ssthresh; /* ssthresh saved at recovery start	*/
-	__u16	__pad1;
 	__u32	lost_out;	/* Lost packets			*/
 	__u32	sacked_out;	/* SACK'd packets			*/
 	__u32	fackets_out;	/* FACK'd packets			*/
diff --git a/include/linux/threads.h b/include/linux/threads.h
--- a/include/linux/threads.h
+++ b/include/linux/threads.h
@@ -7,7 +7,7 @@
  * The default limit for the nr of threads is now in
  * /proc/sys/kernel/threads-max.
  */
- 
+
 /*
  * Maximum supported processors that can run under SMP.  This value is
  * set via configure setting.  The maximum is equal to the size of the
@@ -25,11 +25,12 @@
 /*
  * This controls the default maximum pid allocated to a process
  */
-#define PID_MAX_DEFAULT 0x8000
+#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)
 
 /*
  * A maximum of 4 million PIDs should be enough for a while:
  */
-#define PID_MAX_LIMIT (sizeof(long) > 4 ? 4*1024*1024 : PID_MAX_DEFAULT)
+#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
+	(sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
 
 #endif
diff --git a/include/linux/timex.h b/include/linux/timex.h
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -240,9 +240,7 @@ extern long time_precision;	/* clock pre
 extern long time_maxerror;	/* maximum error */
 extern long time_esterror;	/* estimated error */
 
-extern long time_phase;		/* phase offset (scaled us) */
 extern long time_freq;		/* frequency offset (scaled ppm) */
-extern long time_adj;		/* tick adjust (scaled 1 / HZ) */
 extern long time_reftime;	/* time at last adjustment (s) */
 
 extern long time_adjust;	/* The amount of adjtime left */
diff --git a/include/linux/topology.h b/include/linux/topology.h
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -31,9 +31,12 @@
 #include <linux/bitops.h>
 #include <linux/mmzone.h>
 #include <linux/smp.h>
-
 #include <asm/topology.h>
 
+#ifndef node_has_online_mem
+#define node_has_online_mem(nid) (1)
+#endif
+
 #ifndef nr_cpus_node
 #define nr_cpus_node(node)							\
 	({									\
diff --git a/include/linux/tpqic02.h b/include/linux/tpqic02.h
deleted file mode 100644
--- a/include/linux/tpqic02.h
+++ /dev/null
@@ -1,738 +0,0 @@
-/* $Id: tpqic02.h,v 1.5 1996/12/14 23:01:38 root Exp root $
- *
- * Include file for QIC-02 driver for Linux.
- *
- * Copyright (c) 1992--1995 by H. H. Bergman. All rights reserved.
- *
- * ******* USER CONFIG SECTION BELOW (Near line 70) *******
- */
-
-#ifndef _LINUX_TPQIC02_H
-#define _LINUX_TPQIC02_H
-
-#include <linux/config.h>
-
-#if defined(CONFIG_QIC02_TAPE) || defined(CONFIG_QIC02_TAPE_MODULE)
-
-/* need to have QIC02_TAPE_DRIVE and QIC02_TAPE_IFC expand to something */
-#include <linux/mtio.h>
-
-
-/* Make QIC02_TAPE_IFC expand to something.
- *
- * The only difference between WANGTEK and EVEREX is in the 
- * handling of the DMA channel 3.
- * Note that the driver maps EVEREX to WANGTEK internally for speed
- * reasons. Externally WANGTEK==1, EVEREX==2, ARCHIVE==3.
- * These must correspond to the values used in qic02config(1).
- *
- * Support for Mountain controllers was added by Erik Jacobson
- * and severely hacked by me.   -- hhb
- * 
- * Support for Emerald controllers by Alan Bain <afrb2@chiark.chu.cam.ac.uk>
- * with more hacks by me.   -- hhb
- */
-#define WANGTEK		1		   /* don't know about Wangtek QIC-36 */
-#define EVEREX		(WANGTEK+1)  /* I heard *some* of these are identical */
-#define EVEREX_811V	EVEREX			      /* With TEAC MT 2ST 45D */
-#define EVEREX_831V	EVEREX
-#define ARCHIVE		3
-#define ARCHIVE_SC400	ARCHIVE	       /* rumoured to be from the pre-SMD-age */
-#define ARCHIVE_SC402	ARCHIVE		       /* don't know much about SC400 */
-#define ARCHIVE_SC499	ARCHIVE       /* SC402 and SC499R should be identical */
-
-#define MOUNTAIN	5		       /* Mountain Computer Interface */
-#define EMERALD		6		       /* Emerald Interface card */
-
-
-
-#define QIC02_TAPE_PORT_RANGE 	8	 /* number of IO locations to reserve */
-
-
-/*********** START OF USER CONFIGURABLE SECTION ************/
-
-/* Tape configuration: Select DRIVE, IFC, PORT, IRQ and DMA below.
- * Runtime (re)configuration is not supported yet.
- *
- * Tape drive configuration:	(MT_IS* constants are defined in mtio.h)
- *
- * QIC02_TAPE_DRIVE = MT_ISWT5150
- *	- Wangtek 5150, format: up to QIC-150.
- * QIC02_TAPE_DRIVE = MT_ISQIC02_ALL_FEATURES
- *	- Enables some optional QIC02 commands that some drives may lack.
- *	  It is provided so you can check which are supported by your drive.
- *	  Refer to tpqic02.h for others.
- *
- * Supported interface cards: QIC02_TAPE_IFC =
- *	WANGTEK,
- *	ARCHIVE_SC402, ARCHIVE_SC499.	(both same programming interface)
- *
- * Make sure you have the I/O ports/DMA channels 
- * and IRQ stuff configured properly!
- * NOTE: There may be other device drivers using the same major
- *       number. This must be avoided. Check for timer.h conflicts too.
- *
- * If you have an EVEREX EV-831 card and you are using DMA channel 3,
- * you will probably have to ``#define QIC02_TAPE_DMA3_FIX'' below.
- */
-
-/* CONFIG_QIC02_DYNCONF can be defined in autoconf.h, by `make config' */
-
-/*** #undef CONFIG_QIC02_DYNCONF ***/
-
-#ifndef CONFIG_QIC02_DYNCONF
-
-#define QIC02_TAPE_DRIVE	MT_ISQIC02_ALL_FEATURES	 /* drive type */
-/* #define QIC02_TAPE_DRIVE	MT_ISWT5150 */
-/* #define QIC02_TAPE_DRIVE	MT_ISARCHIVE_5945L2 */
-/* #define QIC02_TAPE_DRIVE	MT_ISTEAC_MT2ST */
-/* #define QIC02_TAPE_DRIVE	MT_ISARCHIVE_2150L */
-/* #define QIC02_TAPE_DRIVE	MT_ISARCHIVESC499 */
-
-/* Either WANGTEK, ARCHIVE or MOUNTAIN. Not EVEREX. 
- * If you have an EVEREX, use WANGTEK and try the DMA3_FIX below.
- */
-#define QIC02_TAPE_IFC		WANGTEK	/* interface card type */
-/* #define QIC02_TAPE_IFC		ARCHIVE */
-/* #define QIC02_TAPE_IFC		MOUNTAIN */
-
-#define QIC02_TAPE_PORT 	0x300	/* controller port address */
-#define QIC02_TAPE_IRQ		5	/* For IRQ2, use 9 here, others normal. */
-#define QIC02_TAPE_DMA		1	/* either 1 or 3, because 2 is used by the floppy */
-
-/* If DMA3 doesn't work, but DMA1 does, and you have a 
- * Wangtek/Everex card, you can try #define-ing the flag
- * below. Note that you should also change the DACK jumper
- * for Wangtek/Everex cards when changing the DMA channel.
- */
-#undef QIC02_TAPE_DMA3_FIX
-
-/************ END OF USER CONFIGURABLE SECTION *************/
-
-/* I put the stuff above in config.in, but a few recompiles, to
- * verify different configurations, and several days later I decided
- * to change it back again.
- */
-
-
-
-/* NOTE: TP_HAVE_DENS should distinguish between available densities (?)
- * NOTE: Drive select is not implemented -- I have only one tape streamer,
- *	 so I'm unable and unmotivated to test and implement that. ;-) ;-)
- */
-#if QIC02_TAPE_DRIVE == MT_ISWT5150
-#define TP_HAVE_DENS	1
-#define TP_HAVE_BSF	0	/* nope */
-#define TP_HAVE_FSR	0	/* nope */
-#define TP_HAVE_BSR	0	/* nope */
-#define TP_HAVE_EOD	0	/* most of the time */
-#define TP_HAVE_SEEK	0
-#define TP_HAVE_TELL	0
-#define TP_HAVE_RAS1	1
-#define TP_HAVE_RAS2	1
-
-#elif QIC02_TAPE_DRIVE == MT_ISARCHIVESC499	/* Archive SC-499 QIC-36 controller */
-#define TP_HAVE_DENS	1	/* can do set density (QIC-11 / QIC-24) */
-#define TP_HAVE_BSF	0
-#define TP_HAVE_FSR	1	/* can skip one block forwards */
-#define TP_HAVE_BSR	1	/* can skip one block backwards */
-#define TP_HAVE_EOD	1	/* can seek to end of recorded data */
-#define TP_HAVE_SEEK	0
-#define TP_HAVE_TELL	0
-#define TP_HAVE_RAS1	1	/* can run selftest 1 */
-#define TP_HAVE_RAS2	1	/* can run selftest 2 */
-/* These last two selftests shouldn't be used yet! */
-
-#elif (QIC02_TAPE_DRIVE == MT_ISARCHIVE_2060L) || (QIC02_TAPE_DRIVE == MT_ISARCHIVE_2150L)
-#define TP_HAVE_DENS	1	/* can do set density (QIC-24 / QIC-120 / QIC-150) */
-#define TP_HAVE_BSF	0
-#define TP_HAVE_FSR	1	/* can skip one block forwards */
-#define TP_HAVE_BSR	1	/* can skip one block backwards */
-#define TP_HAVE_EOD	1	/* can seek to end of recorded data */
-#define TP_HAVE_TELL	1	/* can read current block address */
-#define TP_HAVE_SEEK	1	/* can seek to block */
-#define TP_HAVE_RAS1	1	/* can run selftest 1 */
-#define TP_HAVE_RAS2	1	/* can run selftest 2 */
-/* These last two selftests shouldn't be used yet! */
-
-#elif QIC02_TAPE_DRIVE == MT_ISARCHIVE_5945L2
-/* can anyone verify this entry?? */
-#define TP_HAVE_DENS	1	/* can do set density?? (QIC-24??) */
-#define TP_HAVE_BSF	0
-#define TP_HAVE_FSR	1	/* can skip one block forwards */
-#define TP_HAVE_BSR	1	/* can skip one block backwards */
-#define TP_HAVE_EOD	1	/* can seek to end of recorded data */
-#define TP_HAVE_TELL	1	/* can read current block address */
-#define TP_HAVE_SEEK	1	/* can seek to block */
-#define TP_HAVE_RAS1	1	/* can run selftest 1 */
-#define TP_HAVE_RAS2	1	/* can run selftest 2 */
-/* These last two selftests shouldn't be used yet! */
-
-#elif QIC02_TAPE_DRIVE == MT_ISTEAC_MT2ST
-/* can anyone verify this entry?? */
-#define TP_HAVE_DENS	0	/* cannot do set density?? (QIC-150?) */
-#define TP_HAVE_BSF	0
-#define TP_HAVE_FSR	1	/* can skip one block forwards */
-#define TP_HAVE_BSR	1	/* can skip one block backwards */
-#define TP_HAVE_EOD	1	/* can seek to end of recorded data */
-#define TP_HAVE_SEEK	1	/* can seek to block */
-#define TP_HAVE_TELL	1	/* can read current block address */
-#define TP_HAVE_RAS1	1	/* can run selftest 1 */
-#define TP_HAVE_RAS2	1	/* can run selftest 2 */
-/* These last two selftests shouldn't be used yet! */
-
-#elif QIC02_TAPE_DRIVE == MT_ISQIC02_ALL_FEATURES
-#define TP_HAVE_DENS	1	/* can do set density */
-#define TP_HAVE_BSF	1	/* can search filemark backwards */
-#define TP_HAVE_FSR	1	/* can skip one block forwards */
-#define TP_HAVE_BSR	1	/* can skip one block backwards */
-#define TP_HAVE_EOD	1	/* can seek to end of recorded data */
-#define TP_HAVE_SEEK	1	/* seek to block address */
-#define TP_HAVE_TELL	1	/* tell current block address */
-#define TP_HAVE_RAS1	1	/* can run selftest 1 */
-#define TP_HAVE_RAS2	1	/* can run selftest 2 */
-/* These last two selftests shouldn't be used yet! */
-
-
-#else
-#error No QIC-02 tape drive type defined!
-/* If your drive is not listed above, first try the 'ALL_FEATURES',
- * to see what commands are supported, then create your own entry in
- * the list above. You may want to mail it to me, so that I can include
- * it in the next release.
- */
-#endif
-
-#endif /* !CONFIG_QIC02_DYNCONF */
-
-
-/* WANGTEK interface card specifics */
-#define WT_QIC02_STAT_PORT	(QIC02_TAPE_PORT)
-#define WT_QIC02_CTL_PORT	(QIC02_TAPE_PORT)
-#define WT_QIC02_CMD_PORT	(QIC02_TAPE_PORT+1)
-#define WT_QIC02_DATA_PORT	(QIC02_TAPE_PORT+1)
-
-/* status register bits (Active LOW!) */
-#define WT_QIC02_STAT_POLARITY	0
-#define WT_QIC02_STAT_READY	0x01
-#define WT_QIC02_STAT_EXCEPTION	0x02
-#define WT_QIC02_STAT_MASK	(WT_QIC02_STAT_READY|WT_QIC02_STAT_EXCEPTION)
-
-#define WT_QIC02_STAT_RESETMASK	0x07
-#define WT_QIC02_STAT_RESETVAL	(WT_QIC02_STAT_RESETMASK & ~WT_QIC02_STAT_EXCEPTION)
-
-/* controller register (QIC02_CTL_PORT) bits */
-#define WT_QIC02_CTL_RESET	0x02
-#define WT_QIC02_CTL_REQUEST	0x04
-#define WT_CTL_ONLINE		0x01
-#define WT_CTL_CMDOFF		0xC0 
-
-#define WT_CTL_DMA3		0x10			  /* enable dma chan3 */
-#define WT_CTL_DMA1		0x08	         /* enable dma chan1 or chan2 */
-
-/* EMERALD interface card specifics
- * Much like Wangtek, only different polarity and bit locations
- */
-#define EMR_QIC02_STAT_PORT	(QIC02_TAPE_PORT)
-#define EMR_QIC02_CTL_PORT	(QIC02_TAPE_PORT)
-#define EMR_QIC02_CMD_PORT	(QIC02_TAPE_PORT+1)
-#define EMR_QIC02_DATA_PORT	(QIC02_TAPE_PORT+1)
-
-/* status register bits (Active High!) */
-#define EMR_QIC02_STAT_POLARITY		1
-#define EMR_QIC02_STAT_READY		0x01
-#define EMR_QIC02_STAT_EXCEPTION	0x02
-#define EMR_QIC02_STAT_MASK	(EMR_QIC02_STAT_READY|EMR_QIC02_STAT_EXCEPTION)
-
-#define EMR_QIC02_STAT_RESETMASK	0x07
-#define EMR_QIC02_STAT_RESETVAL	(EMR_QIC02_STAT_RESETMASK & ~EMR_QIC02_STAT_EXCEPTION)
-
-/* controller register (QIC02_CTL_PORT) bits */
-#define EMR_QIC02_CTL_RESET	0x02
-#define EMR_QIC02_CTL_REQUEST	0x04
-#define EMR_CTL_ONLINE		0x01
-#define EMR_CTL_CMDOFF		0xC0 
-
-#define EMR_CTL_DMA3		0x10			  /* enable dma chan3 */
-#define EMR_CTL_DMA1		0x08	         /* enable dma chan1 or chan2 */
-
-
-
-/* ARCHIVE interface card specifics */
-#define AR_QIC02_STAT_PORT	(QIC02_TAPE_PORT+1)
-#define AR_QIC02_CTL_PORT	(QIC02_TAPE_PORT+1)
-#define AR_QIC02_CMD_PORT	(QIC02_TAPE_PORT)
-#define AR_QIC02_DATA_PORT	(QIC02_TAPE_PORT)
-
-#define AR_START_DMA_PORT	(QIC02_TAPE_PORT+2)
-#define AR_RESET_DMA_PORT	(QIC02_TAPE_PORT+3)
-
-/* STAT port bits */
-#define AR_QIC02_STAT_POLARITY	0
-#define AR_STAT_IRQF		0x80	/* active high, interrupt request flag */
-#define AR_QIC02_STAT_READY	0x40	/* active low */
-#define AR_QIC02_STAT_EXCEPTION	0x20	/* active low */
-#define AR_QIC02_STAT_MASK	(AR_QIC02_STAT_READY|AR_QIC02_STAT_EXCEPTION)
-#define AR_STAT_DMADONE		0x10	/* active high, DMA done */
-#define AR_STAT_DIRC		0x08	/* active high, direction */
-
-#define AR_QIC02_STAT_RESETMASK	0x70	/* check RDY,EXC,DMADONE */
-#define AR_QIC02_STAT_RESETVAL	((AR_QIC02_STAT_RESETMASK & ~AR_STAT_IRQF & ~AR_QIC02_STAT_EXCEPTION) | AR_STAT_DMADONE)
-
-/* CTL port bits */
-#define AR_QIC02_CTL_RESET	0x80	/* drive reset */
-#define AR_QIC02_CTL_REQUEST	0x40	/* notify of new command */
-#define AR_CTL_IEN		0x20	/* interrupt enable */
-#define AR_CTL_DNIEN		0x10	/* done-interrupt enable */
-  /* Note: All of these bits are cleared automatically when writing to
-   * AR_RESET_DMA_PORT. So AR_CTL_IEN and AR_CTL_DNIEN must be
-   * reprogrammed before the write to AR_START_DMA_PORT.
-   */
-
-
-/* MOUNTAIN interface specifics */
-#define MTN_QIC02_STAT_PORT	(QIC02_TAPE_PORT+1)
-#define MTN_QIC02_CTL_PORT	(QIC02_TAPE_PORT+1)
-#define MTN_QIC02_CMD_PORT	(QIC02_TAPE_PORT)
-#define MTN_QIC02_DATA_PORT	(QIC02_TAPE_PORT)
-
-#define MTN_W_SELECT_DMA_PORT	(QIC02_TAPE_PORT+2)
-#define MTN_R_DESELECT_DMA_PORT	(QIC02_TAPE_PORT+2)
-#define MTN_W_DMA_WRITE_PORT	(QIC02_TAPE_PORT+3)
-
-/* STAT port bits */
-#define MTN_QIC02_STAT_POLARITY	 0
-#define MTN_QIC02_STAT_READY	 0x02	/* active low */
-#define MTN_QIC02_STAT_EXCEPTION 0x04	/* active low */
-#define MTN_QIC02_STAT_MASK	 (MTN_QIC02_STAT_READY|MTN_QIC02_STAT_EXCEPTION)
-#define MTN_STAT_DMADONE	 0x01	/* active high, DMA done */
-
-#define MTN_QIC02_STAT_RESETMASK 0x07	/* check RDY,EXC,DMADONE */
-#define MTN_QIC02_STAT_RESETVAL	 ((MTN_QIC02_STAT_RESETMASK & ~MTN_QIC02_STAT_EXCEPTION) | MTN_STAT_DMADONE)
-
-/* CTL port bits */
-#define MTN_QIC02_CTL_RESET_NOT	 0x80	/* drive reset, active low */
-#define MTN_QIC02_CTL_RESET	 0x80	/* Fodder #definition to keep gcc happy */
-
-#define MTN_QIC02_CTL_ONLINE	 0x40	/* Put drive on line  */
-#define MTN_QIC02_CTL_REQUEST	 0x20	/* notify of new command */
-#define MTN_QIC02_CTL_IRQ_DRIVER 0x10	/* Enable IRQ tristate driver */
-#define MTN_QIC02_CTL_DMA_DRIVER 0x08	/* Enable DMA tristate driver */
-#define MTN_CTL_EXC_IEN		 0x04	/* Exception interrupt enable */
-#define MTN_CTL_RDY_IEN		 0x02	/* Ready interrupt enable */
-#define MTN_CTL_DNIEN		 0x01	/* done-interrupt enable */
-
-#define MTN_CTL_ONLINE		(MTN_QIC02_CTL_RESET_NOT | MTN_QIC02_CTL_IRQ_DRIVER | MTN_QIC02_CTL_DMA_DRIVER)
-
-
-#ifndef CONFIG_QIC02_DYNCONF
-
-# define QIC02_TAPE_DEBUG	(qic02_tape_debug)
-
-# if QIC02_TAPE_IFC == WANGTEK	
-#  define QIC02_STAT_POLARITY	WT_QIC02_STAT_POLARITY
-#  define QIC02_STAT_PORT	WT_QIC02_STAT_PORT
-#  define QIC02_CTL_PORT	WT_QIC02_CTL_PORT
-#  define QIC02_CMD_PORT	WT_QIC02_CMD_PORT
-#  define QIC02_DATA_PORT	WT_QIC02_DATA_PORT
-
-#  define QIC02_STAT_READY	WT_QIC02_STAT_READY
-#  define QIC02_STAT_EXCEPTION	WT_QIC02_STAT_EXCEPTION
-#  define QIC02_STAT_MASK	WT_QIC02_STAT_MASK
-#  define QIC02_STAT_RESETMASK	WT_QIC02_STAT_RESETMASK
-#  define QIC02_STAT_RESETVAL	WT_QIC02_STAT_RESETVAL
-
-#  define QIC02_CTL_RESET	WT_QIC02_CTL_RESET
-#  define QIC02_CTL_REQUEST	WT_QIC02_CTL_REQUEST
-
-#  if QIC02_TAPE_DMA == 3
-#   ifdef QIC02_TAPE_DMA3_FIX
-#    define WT_CTL_DMA		WT_CTL_DMA1
-#   else
-#    define WT_CTL_DMA		WT_CTL_DMA3
-#   endif
-#  elif QIC02_TAPE_DMA == 1
-#    define WT_CTL_DMA		WT_CTL_DMA1
-#  else
-#   error Unsupported or incorrect DMA configuration.
-#  endif
-
-# elif QIC02_TAPE_IFC == EMERALD
-#  define QIC02_STAT_POLARITY	EMR_QIC02_STAT_POLARITY
-#  define QIC02_STAT_PORT	EMR_QIC02_STAT_PORT
-#  define QIC02_CTL_PORT	EMR_QIC02_CTL_PORT
-#  define QIC02_CMD_PORT	EMR_QIC02_CMD_PORT
-#  define QIC02_DATA_PORT	EMR_QIC02_DATA_PORT
-
-#  define QIC02_STAT_READY	EMR_QIC02_STAT_READY
-#  define QIC02_STAT_EXCEPTION	EMR_QIC02_STAT_EXCEPTION
-#  define QIC02_STAT_MASK	EMR_QIC02_STAT_MASK
-#  define QIC02_STAT_RESETMASK	EMR_QIC02_STAT_RESETMASK
-#  define QIC02_STAT_RESETVAL	EMR_QIC02_STAT_RESETVAL
-
-#  define QIC02_CTL_RESET	EMR_QIC02_CTL_RESET
-#  define QIC02_CTL_REQUEST	EMR_QIC02_CTL_REQUEST
-
-#  if QIC02_TAPE_DMA == 3
-#   ifdef QIC02_TAPE_DMA3_FIX
-#    define EMR_CTL_DMA		EMR_CTL_DMA1
-#   else
-#    define EMR_CTL_DMA		EMR_CTL_DMA3
-#   endif
-#  elif QIC02_TAPE_DMA == 1
-#    define EMR_CTL_DMA		EMR_CTL_DMA1
-#  else
-#   error Unsupported or incorrect DMA configuration.
-#  endif
-
-# elif QIC02_TAPE_IFC == ARCHIVE
-#  define QIC02_STAT_POLARITY	AR_QIC02_STAT_POLARITY
-#  define QIC02_STAT_PORT	AR_QIC02_STAT_PORT
-#  define QIC02_CTL_PORT	AR_QIC02_CTL_PORT
-#  define QIC02_CMD_PORT	AR_QIC02_CMD_PORT
-#  define QIC02_DATA_PORT	AR_QIC02_DATA_PORT
-
-#  define QIC02_STAT_READY	AR_QIC02_STAT_READY
-#  define QIC02_STAT_EXCEPTION	AR_QIC02_STAT_EXCEPTION
-#  define QIC02_STAT_MASK	AR_QIC02_STAT_MASK
-#  define QIC02_STAT_RESETMASK	AR_QIC02_STAT_RESETMASK
-#  define QIC02_STAT_RESETVAL	AR_QIC02_STAT_RESETVAL
-
-#  define QIC02_CTL_RESET	AR_QIC02_CTL_RESET
-#  define QIC02_CTL_REQUEST	AR_QIC02_CTL_REQUEST
-
-#  if QIC02_TAPE_DMA > 3	/* channel 2 is used by the floppy driver */
-#   error DMA channels other than 1 and 3 are not supported.
-#  endif
-
-# elif QIC02_TAPE_IFC == MOUNTAIN
-#  define QIC02_STAT_POLARITY	MTN_QIC02_STAT_POLARITY
-#  define QIC02_STAT_PORT	MTN_QIC02_STAT_PORT
-#  define QIC02_CTL_PORT	MTN_QIC02_CTL_PORT
-#  define QIC02_CMD_PORT	MTN_QIC02_CMD_PORT
-#  define QIC02_DATA_PORT	MTN_QIC02_DATA_PORT
-
-#  define QIC02_STAT_READY	MTN_QIC02_STAT_READY
-#  define QIC02_STAT_EXCEPTION	MTN_QIC02_STAT_EXCEPTION
-#  define QIC02_STAT_MASK	MTN_QIC02_STAT_MASK
-#  define QIC02_STAT_RESETMASK	MTN_QIC02_STAT_RESETMASK
-#  define QIC02_STAT_RESETVAL	MTN_QIC02_STAT_RESETVAL
-
-#  define QIC02_CTL_RESET	MTN_QIC02_CTL_RESET
-#  define QIC02_CTL_REQUEST	MTN_QIC02_CTL_REQUEST
-
-#  if QIC02_TAPE_DMA > 3	/* channel 2 is used by the floppy driver */
-#   error DMA channels other than 1 and 3 are not supported.
-#  endif
-
-# else
-#  error No valid interface card specified!
-# endif /* QIC02_TAPE_IFC */
-
-
-  /* An ugly hack to make sure WT_CTL_DMA is defined even for the
-   * static, non-Wangtek case. The alternative was even worse.
-   */ 
-# ifndef WT_CTL_DMA
-#  define WT_CTL_DMA		WT_CTL_DMA1
-# endif
-
-/*******************/
-
-#else /* !CONFIG_QIC02_DYNCONF */
-
-/* Now the runtime config version, using variables instead of constants.
- *
- * qic02_tape_dynconf is R/O for the kernel, set from userspace.
- * qic02_tape_ccb is private to the driver, R/W.
- */
-
-# define QIC02_TAPE_DRIVE	(qic02_tape_dynconf.mt_type)
-# define QIC02_TAPE_IFC		(qic02_tape_ccb.ifc_type)
-# define QIC02_TAPE_IRQ		(qic02_tape_dynconf.irqnr)
-# define QIC02_TAPE_DMA		(qic02_tape_dynconf.dmanr)
-# define QIC02_TAPE_PORT	(qic02_tape_dynconf.port)
-# define WT_CTL_DMA		(qic02_tape_ccb.dma_enable_value)
-# define QIC02_TAPE_DEBUG	(qic02_tape_dynconf.debug)
-
-# define QIC02_STAT_PORT	(qic02_tape_ccb.port_stat)
-# define QIC02_CTL_PORT 	(qic02_tape_ccb.port_ctl)
-# define QIC02_CMD_PORT 	(qic02_tape_ccb.port_cmd)
-# define QIC02_DATA_PORT 	(qic02_tape_ccb.port_data)
-
-# define QIC02_STAT_POLARITY	(qic02_tape_ccb.stat_polarity)
-# define QIC02_STAT_READY	(qic02_tape_ccb.stat_ready)
-# define QIC02_STAT_EXCEPTION	(qic02_tape_ccb.stat_exception)
-# define QIC02_STAT_MASK	(qic02_tape_ccb.stat_mask)
-
-# define QIC02_STAT_RESETMASK	(qic02_tape_ccb.stat_resetmask)
-# define QIC02_STAT_RESETVAL	(qic02_tape_ccb.stat_resetval)
-
-# define QIC02_CTL_RESET	(qic02_tape_ccb.ctl_reset)
-# define QIC02_CTL_REQUEST	(qic02_tape_ccb.ctl_request)
-
-# define TP_HAVE_DENS		(qic02_tape_dynconf.have_dens)
-# define TP_HAVE_BSF		(qic02_tape_dynconf.have_bsf)
-# define TP_HAVE_FSR		(qic02_tape_dynconf.have_fsr)
-# define TP_HAVE_BSR		(qic02_tape_dynconf.have_bsr)
-# define TP_HAVE_EOD		(qic02_tape_dynconf.have_eod)
-# define TP_HAVE_SEEK		(qic02_tape_dynconf.have_seek)
-# define TP_HAVE_TELL		(qic02_tape_dynconf.have_tell)
-# define TP_HAVE_RAS1		(qic02_tape_dynconf.have_ras1)
-# define TP_HAVE_RAS2		(qic02_tape_dynconf.have_ras2)
-
-#endif /* CONFIG_QIC02_DYNCONF */
-
-
-/* "Vendor Unique" codes */
-/* Archive seek & tell stuff */
-#define AR_QCMDV_TELL_BLK	0xAE	/* read current block address */
-#define AR_QCMDV_SEEK_BLK	0xAD	/* seek to specific block */
-#define AR_SEEK_BUF_SIZE	3	/* address is 3 bytes */
-
-
-
-/*
- * Misc common stuff
- */
-
-/* Standard QIC-02 commands -- rev F.  All QIC-02 drives must support these */
-#define QCMD_SEL_1	0x01		/* select drive 1 */
-#define QCMD_SEL_2	0x02		/* select drive 2 */
-#define QCMD_SEL_3	0x04		/* select drive 3 */
-#define QCMD_SEL_4	0x08		/* select drive 4 */
-#define	QCMD_REWIND	0x21		/* rewind tape */
-#define QCMD_ERASE	0x22		/* erase tape */
-#define QCMD_RETEN	0x24		/* retension tape */
-#define	QCMD_WRT_DATA	0x40		/* write data */
-#define	QCMD_WRT_FM	0x60		/* write file mark */
-#define	QCMD_RD_DATA	0x80		/* read data */
-#define	QCMD_RD_FM	0xA0		/* read file mark (forward direction) */
-#define	QCMD_RD_STAT	0xC0		/* read status */
-
-/* Other (optional/vendor unique) commands */
- /* Density commands are only valid when TP_BOM is set! */
-#define QCMD_DENS_11	0x26		/* QIC-11 */
-#define QCMD_DENS_24	0x27		/* QIC-24: 9 track 60MB */
-#define QCMD_DENS_120	0x28		/* QIC-120: 15 track 120MB */
-#define QCMD_DENS_150	0x29		/* QIC-150: 18 track 150MB */
-#define QCMD_DENS_300	0x2A		/* QIC-300/QIC-2100 */
-#define QCMD_DENS_600	0x2B		/* QIC-600/QIC-2200 */
-/* don't know about QIC-1000 and QIC-1350 */
-
-#define	QCMD_WRTNU_DATA	0x40		/* write data, no underruns, insert filler. */
-#define QCMD_SPACE_FWD	0x81		/* skip next block */
-#define QCMD_SPACE_BCK	0x89		/* move tape head one block back -- very useful! */
-#define QCMD_RD_FM_BCK	0xA8		/* read filemark (backwards) */
-#define QCMD_SEEK_EOD	0xA3		/* skip to EOD */
-#define	QCMD_RD_STAT_X1	0xC1		/* read extended status 1 */
-#define	QCMD_RD_STAT_X2	0xC4		/* read extended status 2 */
-#define	QCMD_RD_STAT_X3	0xE0		/* read extended status 3 */
-#define QCMD_SELF_TST1	0xC2		/* run self test 1 (nondestructive) */
-#define QCMD_SELF_TST2	0xCA		/* run self test 2 (destructive) */
-
-
-
-/* Optional, QFA (Quick File Access) commands.
- * Not all drives support this, but those that do could use these commands
- * to implement semi-non-sequential access. `mt fsf` would benefit from this.
- * QFA divides the tape into 2 partitions, a data and a directory partition,
- * causing some incompatibility problems wrt std QIC-02 data exchange.
- * It would be useful to cache the directory info, but that might be tricky
- * to do in kernel-space. [Size constraints.]
- * Refer to the QIC-02 specs, appendix A for more information.
- * I have no idea how other *nix variants implement QFA.
- * I have no idea which drives support QFA and which don't.
- */
-#define QFA_ENABLE	0x2D		/* enter QFA mode, give @ BOT only */
-#define QFA_DATA	0x20		/* select data partition */
-#define QFA_DIR		0x23		/* select directory partition */
-#define QFA_RD_POS	0xCF		/* read position+status bytes */
-#define QFA_SEEK_EOD	0xA1		/* seek EOD within current partition */
-#define QFA_SEEK_BLK	0xAF		/* seek to a block within current partition */
-
-
-
-
-/*
- * Debugging flags
- */
-#define TPQD_SENSE_TEXT	0x0001
-#define TPQD_SENSE_CNTS 0x0002
-#define TPQD_REWIND	0x0004
-#define TPQD_TERM_CYCLE	0x0008
-#define TPQD_IOCTLS	0x0010
-#define TPQD_DMAX	0x0020
-#define TPQD_BLKSZ	0x0040
-#define TPQD_MISC	0x0080
-
-#define TPQD_DEBUG	0x0100
-
-#define TPQD_DIAGS	0x1000
-
-#define TPQD_ALWAYS	0x8000
-
-#define TPQD_DEFAULT_FLAGS	0x00fc
-
-
-#define TPQDBG(f)	((QIC02_TAPE_DEBUG) & (TPQD_##f))
-
-
-/* Minor device codes for tapes:
- * |7|6|5|4|3|2|1|0|
- *  | \ | / \ | / |_____ 1=rewind on close, 0=no rewind on close
- *  |  \|/    |_________ Density: 000=none, 001=QIC-11, 010=24, 011=120,
- *  |   |                100=QIC-150, 101..111 reserved.
- *  |   |_______________ Reserved for unit numbers.
- *  |___________________ Reserved for diagnostics during debugging.
- */
-
-#define	TP_REWCLOSE(d)	((d)&1)	   		/* rewind bit */
-			   /* rewind is only done if data has been transferred */
-#define	TP_DENS(d)	(((d) >> 1) & 0x07) 	      /* tape density */
-#define TP_UNIT(d)	(((d) >> 4) & 0x07)	       /* unit number */
-
-/* print excessive diagnostics */
-#define TP_DIAGS(dev)	(QIC02_TAPE_DEBUG & TPQD_DIAGS)
-
-/* status codes returned by a WTS_RDSTAT call */
-struct tpstatus {	/* sizeof(short)==2), LSB first */
-	unsigned short	exs;	/* Drive exception flags */
-	unsigned short	dec;	/* data error count: nr of blocks rewritten/soft read errors */
-	unsigned short	urc;	/* underrun count: nr of times streaming was interrupted */
-};
-#define TPSTATSIZE	sizeof(struct tpstatus)
-
-
-/* defines for tpstatus.exs -- taken from 386BSD wt driver */
-#define	TP_POR		0x100	/* Power on or reset occurred */
-#define	TP_EOR		0x200	/* REServed for end of RECORDED media */
-#define	TP_PAR		0x400	/* REServed for bus parity */
-#define	TP_BOM		0x800	/* Beginning of media */
-#define	TP_MBD		0x1000	/* Marginal block detected */
-#define	TP_NDT		0x2000	/* No data detected */
-#define	TP_ILL		0x4000	/* Illegal command */
-#define	TP_ST1		0x8000	/* Status byte 1 flag */
-#define	TP_FIL		0x01	/* File mark detected */
-#define	TP_BNL		0x02	/* Bad block not located */
-#define	TP_UDA		0x04	/* Unrecoverable data error */
-#define	TP_EOM		0x08	/* End of media */
-#define	TP_WRP		0x10	/* Write protected cartridge */
-#define	TP_USL		0x20	/* Unselected drive */
-#define	TP_CNI		0x40	/* Cartridge not in place */
-#define	TP_ST0		0x80	/* Status byte 0 flag */
-
-#define REPORT_ERR0	(TP_CNI|TP_USL|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL)
-#define REPORT_ERR1	(TP_ILL|TP_NDT|TP_MBD|TP_PAR)
-
-
-/* exception numbers */
-#define EXC_UNKNOWN	0	/* (extra) Unknown exception code */
-#define EXC_NDRV	1	/* No drive */
-#define EXC_NCART	2	/* No cartridge */
-#define EXC_WP		3	/* Write protected */
-#define EXC_EOM		4	/* EOM */
-#define EXC_RWA		5	/* read/write abort */
-#define EXC_XBAD	6	/* read error, bad block transferred */
-#define EXC_XFILLER	7	/* read error, filler block transferred */
-#define EXC_NDT		8	/* read error, no data */
-#define EXC_NDTEOM	9	/* read error, no data & EOM */
-#define EXC_NDTBOM	10	/* read error, no data & BOM */
-#define EXC_FM		11	/* Read a filemark */
-#define EXC_ILL		12	/* Illegal command */
-#define EXC_POR		13	/* Power on/reset */
-#define EXC_MARGINAL	14	/* Marginal block detected */
-#define EXC_EOR		15	/* (extra, for SEEKEOD) End Of Recorded data reached */
-#define EXC_BOM		16	/* (extra) BOM reached */
-
-
-#define TAPE_NOTIFY_TIMEOUT	1000000
-
-/* internal function return codes */
-#define TE_OK	0		/* everything is fine */
-#define TE_EX	1		/* exception detected */
-#define TE_ERR	2		/* some error */
-#define TE_NS	3		/* can't read status */
-#define TE_TIM	4		/* timed out */
-#define TE_DEAD	5		/* tape drive doesn't respond */
-#define TE_END	6		/******** Archive hack *****/
-
-/* timeout timer values -- check these! */
-#define TIM_S	(4*HZ)		/* 4 seconds (normal cmds) */
-#define TIM_M	(30*HZ)		/* 30 seconds (write FM) */
-#define TIM_R	(8*60*HZ)	/* 8 minutes (retensioning) */
-#define TIM_F	(2*3600*HZ)	/* est. 1.2hr for full tape read/write+2 retens */
-
-#define TIMERON(t)	mod_timer(&tp_timer, jiffies + (t))
-#define TIMEROFF	del_timer_sync(&tp_timer);
-#define TIMERCONT	add_timer(&tp_timer);
-
-
-typedef char flag;
-#define NO	0	/* NO must be 0 */
-#define YES	1	/* YES must be != 0 */
-
-
-#ifdef TDEBUG
-# define TPQDEB(s)	s
-# define TPQPUTS(s)	tpqputs(s)
-#else
-# define TPQDEB(s)
-# define TPQPUTS(s)
-#endif
-
-
-/* NR_BLK_BUF is a `tuneable parameter'. If you're really low on
- * kernel space, you could decrease it to 1, or if you got a very
- * slow machine, you could increase it up to 127 blocks. Less kernel
- * buffer blocks result in more context-switching.
- */
-#define NR_BLK_BUF	20				    /* max 127 blocks */
-#define TAPE_BLKSIZE	512		  /* streamer tape block size (fixed) */
-#define TPQBUF_SIZE	(TAPE_BLKSIZE*NR_BLK_BUF)	       /* buffer size */
-
-
-#define BLOCKS_BEYOND_EW	2	/* nr of blocks after Early Warning hole */
-#define BOGUS_IRQ		32009
-
-
-/* This is internal data, filled in based on the ifc_type field given
- * by the user. Everex is mapped to Wangtek with a different
- * `dma_enable_value', if dmanr==3.
- */
-struct qic02_ccb {
-	long	ifc_type;
-
-	unsigned short	port_stat;	/* Status port address */
-	unsigned short	port_ctl;	/* Control port address */
-	unsigned short	port_cmd;	/* Command port address */
-	unsigned short	port_data;	/* Data port address */
-
-	/* status register bits */
-	unsigned short	stat_polarity;	/* invert status bits or not */
-	unsigned short	stat_ready;	/* drive ready */
-	unsigned short	stat_exception;	/* drive signals exception */
-	unsigned short	stat_mask;
-	unsigned short	stat_resetmask;
-	unsigned short	stat_resetval;
-
-	/* control register bits */
-	unsigned short	ctl_reset;	/* reset drive */
-	unsigned short	ctl_request;	/* latch command */
-	
-	/* This is used to change the DMA3 behaviour */
-	unsigned short	dma_enable_value;
-};
-
-#if MODULE
-static int qic02_tape_init(void);
-#else
-extern int qic02_tape_init(void);			  /* for mem.c */
-#endif
-
-
-
-#endif /* CONFIG_QIC02_TAPE */
-
-#endif /* _LINUX_TPQIC02_H */
-
diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h
--- a/include/linux/transport_class.h
+++ b/include/linux/transport_class.h
@@ -48,6 +48,14 @@ struct anon_transport_class cls = {				\
 #define class_to_transport_class(x) \
 	container_of(x, struct transport_class, class)
 
+struct transport_container {
+	struct attribute_container ac;
+	struct attribute_group *statistics;
+};
+
+#define attribute_container_to_transport_container(x) \
+	container_of(x, struct transport_container, ac)
+
 void transport_remove_device(struct device *);
 void transport_add_device(struct device *);
 void transport_setup_device(struct device *);
@@ -68,6 +76,16 @@ transport_unregister_device(struct devic
 	transport_destroy_device(dev);
 }
 
+static inline int transport_container_register(struct transport_container *tc)
+{
+	return attribute_container_register(&tc->ac);
+}
+
+static inline int transport_container_unregister(struct transport_container *tc)
+{
+	return attribute_container_unregister(&tc->ac);
+}
+
 int transport_class_register(struct transport_class *);
 int anon_transport_class_register(struct anon_transport_class *);
 void transport_class_unregister(struct transport_class *);
diff --git a/include/linux/trdevice.h b/include/linux/trdevice.h
--- a/include/linux/trdevice.h
+++ b/include/linux/trdevice.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)eth.h	1.0.4	05/13/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		Relocated to include/linux where it belongs by Alan Cox 
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -22,6 +22,9 @@
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
  * 
  * Changes/Revisions:
+ *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
+ *		- added force feedback support
+ *             - added UI_SET_PHYS
  *	0.1	20/06/2002
  *		- first public version
  */
@@ -29,10 +32,25 @@
 #define UINPUT_MINOR		223
 #define UINPUT_NAME		"uinput"
 #define UINPUT_BUFFER_SIZE	16
+#define UINPUT_NUM_REQUESTS	16
 
 /* state flags => bit index for {set|clear|test}_bit ops */
 #define UIST_CREATED		0
 
+struct uinput_request {
+	int			id;
+	int			code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
+
+	int			retval;
+	wait_queue_head_t	waitq;
+	int			completed;
+
+	union {
+		int		effect_id;
+		struct ff_effect* effect;
+	} u;
+};
+
 struct uinput_device {
 	struct input_dev	*dev;
 	unsigned long		state;
@@ -41,13 +59,30 @@ struct uinput_device {
 				head,
 				tail;
 	struct input_event	buff[UINPUT_BUFFER_SIZE];
+
+	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
+	wait_queue_head_t	requests_waitq;
+	struct semaphore	requests_sem;
 };
 #endif	/* __KERNEL__ */
 
+struct uinput_ff_upload {
+	int			request_id;
+	int			retval;
+	struct ff_effect	effect;
+};
+
+struct uinput_ff_erase {
+	int			request_id;
+	int			retval;
+	int			effect_id;
+};
+
 /* ioctl */
 #define UINPUT_IOCTL_BASE	'U'
 #define UI_DEV_CREATE		_IO(UINPUT_IOCTL_BASE, 1)
 #define UI_DEV_DESTROY		_IO(UINPUT_IOCTL_BASE, 2)
+
 #define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
 #define UI_SET_KEYBIT		_IOW(UINPUT_IOCTL_BASE, 101, int)
 #define UI_SET_RELBIT		_IOW(UINPUT_IOCTL_BASE, 102, int)
@@ -56,6 +91,63 @@ struct uinput_device {
 #define UI_SET_LEDBIT		_IOW(UINPUT_IOCTL_BASE, 105, int)
 #define UI_SET_SNDBIT		_IOW(UINPUT_IOCTL_BASE, 106, int)
 #define UI_SET_FFBIT		_IOW(UINPUT_IOCTL_BASE, 107, int)
+#define UI_SET_PHYS		_IOW(UINPUT_IOCTL_BASE, 108, char*)
+
+#define UI_BEGIN_FF_UPLOAD	_IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
+#define UI_END_FF_UPLOAD	_IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
+#define UI_BEGIN_FF_ERASE	_IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
+#define UI_END_FF_ERASE		_IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
+
+/* To write a force-feedback-capable driver, the upload_effect
+ * and erase_effect callbacks in input_dev must be implemented.
+ * The uinput driver will generate a fake input event when one of
+ * these callbacks are invoked. The userspace code then uses
+ * ioctls to retrieve additional parameters and send the return code.
+ * The callback blocks until this return code is sent.
+ *
+ * The described callback mechanism is only used if EV_FF is set.
+ * Otherwise, default implementations of upload_effect and erase_effect
+ * are used.
+ *
+ * To implement upload_effect():
+ *   1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD.
+ *      A request ID will be given in 'value'.
+ *   2. Allocate a uinput_ff_upload struct, fill in request_id with
+ *      the 'value' from the EV_UINPUT event.
+ *   3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
+ *      uinput_ff_upload struct. It will be filled in with the
+ *      ff_effect passed to upload_effect().
+ *   4. Perform the effect upload, and place the modified ff_effect
+ *      and a return code back into the uinput_ff_upload struct.
+ *   5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
+ *      uinput_ff_upload_effect struct. This will complete execution
+ *      of our upload_effect() handler.
+ *
+ * To implement erase_effect():
+ *   1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE.
+ *      A request ID will be given in 'value'.
+ *   2. Allocate a uinput_ff_erase struct, fill in request_id with
+ *      the 'value' from the EV_UINPUT event.
+ *   3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the
+ *      uinput_ff_erase struct. It will be filled in with the
+ *      effect ID passed to erase_effect().
+ *   4. Perform the effect erasure, and place a return code back
+ *      into the uinput_ff_erase struct.
+ *      and a return code back into the uinput_ff_erase struct.
+ *   5. Issue a UI_END_FF_ERASE ioctl, also giving it the
+ *      uinput_ff_erase_effect struct. This will complete execution
+ *      of our erase_effect() handler.
+ */
+
+/* This is the new event type, used only by uinput.
+ * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
+ * is the unique request ID. This number was picked
+ * arbitrarily, above EV_MAX (since the input system
+ * never sees it) but in the range of a 16-bit int.
+ */
+#define EV_UINPUT		0x0101
+#define UI_FF_UPLOAD		1
+#define UI_FF_ERASE		2
 
 #ifndef NBITS
 #define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
diff --git a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -70,6 +70,7 @@ struct usb_host_interface {
 	 */
 	struct usb_host_endpoint *endpoint;
 
+	char *string;		/* iInterface string, if present */
 	unsigned char *extra;   /* Extra descriptors */
 	int extralen;
 };
@@ -189,6 +190,8 @@ struct usb_interface_cache {
 /**
  * struct usb_host_config - representation of a device's configuration
  * @desc: the device's configuration descriptor.
+ * @string: pointer to the cached version of the iConfiguration string, if
+ *	present for this configuration.
  * @interface: array of pointers to usb_interface structures, one for each
  *	interface in the configuration.  The number of interfaces is stored
  *	in desc.bNumInterfaces.  These pointers are valid only while the
@@ -225,6 +228,7 @@ struct usb_interface_cache {
 struct usb_host_config {
 	struct usb_config_descriptor	desc;
 
+	char *string;
 	/* the interfaces associated with this configuration,
 	 * stored in no particular order */
 	struct usb_interface *interface[USB_MAXINTERFACES];
@@ -285,6 +289,10 @@ struct usb_bus {
 
 	struct class_device class_dev;	/* class device for this bus */
 	void (*release)(struct usb_bus *bus);	/* function to destroy this bus's memory */
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+	struct mon_bus *mon_bus;	/* non-null when associated */
+	int monitored;			/* non-zero when monitored */
+#endif
 };
 #define	to_usb_bus(d) container_of(d, struct usb_bus, class_dev)
 
@@ -338,6 +346,9 @@ struct usb_device {
 	int have_langid;		/* whether string_langid is valid yet */
 	int string_langid;		/* language ID for strings */
 
+	char *product;
+	char *manufacturer;
+	char *serial;			/* static strings from the device */
 	struct list_head filelist;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 
@@ -547,7 +558,7 @@ struct usb_driver {
 
 	int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
 
-	int (*suspend) (struct usb_interface *intf, u32 state);
+	int (*suspend) (struct usb_interface *intf, pm_message_t message);
 	int (*resume) (struct usb_interface *intf);
 
 	const struct usb_device_id *id_table;
@@ -785,6 +796,10 @@ typedef void (*usb_complete_t)(struct ur
  * of the iso_frame_desc array, and the number of errors is reported in
  * error_count.  Completion callbacks for ISO transfers will normally
  * (re)submit URBs to ensure a constant transfer rate.
+ *
+ * Note that even fields marked "public" should not be touched by the driver
+ * when the urb is owned by the hcd, that is, since the call to
+ * usb_submit_urb() till the entry into the completion routine.
  */
 struct urb
 {
@@ -792,12 +807,12 @@ struct urb
 	struct kref kref;		/* reference count of the URB */
 	spinlock_t lock;		/* lock for the URB */
 	void *hcpriv;			/* private data for host controller */
-	struct list_head urb_list;	/* list pointer to all active urbs */
 	int bandwidth;			/* bandwidth for INT/ISO request */
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
 
 	/* public, documented fields in the urb that can be used by drivers */
+	struct list_head urb_list;	/* list head for use by the urb owner */
 	struct usb_device *dev; 	/* (in) pointer to associated device */
 	unsigned int pipe;		/* (in) pipe information */
 	int status;			/* (return) non-ISO status */
@@ -938,11 +953,11 @@ void *usb_buffer_alloc (struct usb_devic
 void usb_buffer_free (struct usb_device *dev, size_t size,
 	void *addr, dma_addr_t dma);
 
-struct urb *usb_buffer_map (struct urb *urb);
 #if 0
+struct urb *usb_buffer_map (struct urb *urb);
 void usb_buffer_dmasync (struct urb *urb);
-#endif
 void usb_buffer_unmap (struct urb *urb);
+#endif
 
 struct scatterlist;
 int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
@@ -966,7 +981,7 @@ extern int usb_bulk_msg(struct usb_devic
 	int timeout);
 
 /* selective suspend/resume */
-extern int usb_suspend_device(struct usb_device *dev, u32 state);
+extern int usb_suspend_device(struct usb_device *dev, pm_message_t message);
 extern int usb_resume_device(struct usb_device *dev);
 
 
@@ -986,13 +1001,13 @@ extern int usb_reset_configuration(struc
 extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
 
 /*
- * timeouts, in seconds, used for sending/receiving control messages
+ * timeouts, in milliseconds, used for sending/receiving control messages
  * they typically complete within a few frames (msec) after they're issued
  * USB identifies 5 second timeouts, maybe more in a few cases, and a few
  * slow devices (like some MGE Ellipse UPSes) actually push that limit.
  */
-#define USB_CTRL_GET_TIMEOUT	5
-#define USB_CTRL_SET_TIMEOUT	5
+#define USB_CTRL_GET_TIMEOUT	5000
+#define USB_CTRL_SET_TIMEOUT	5000
 
 
 /**
diff --git a/include/linux/usb_cdc.h b/include/linux/usb_cdc.h
new file mode 100644
--- /dev/null
+++ b/include/linux/usb_cdc.h
@@ -0,0 +1,192 @@
+/*
+ * USB Communications Device Class (CDC) definitions
+ *
+ * CDC says how to talk to lots of different types of network adapters,
+ * notably ethernet adapters and various modems.  It's used mostly with
+ * firmware based USB peripherals.
+ */
+
+#define USB_CDC_SUBCLASS_ACM			0x02
+#define USB_CDC_SUBCLASS_ETHERNET		0x06
+#define USB_CDC_SUBCLASS_WHCM			0x08
+#define USB_CDC_SUBCLASS_DMM			0x09
+#define USB_CDC_SUBCLASS_MDLM			0x0a
+#define USB_CDC_SUBCLASS_OBEX			0x0b
+
+#define USB_CDC_PROTO_NONE			0
+
+#define USB_CDC_ACM_PROTO_AT_V25TER		1
+#define USB_CDC_ACM_PROTO_AT_PCCA101		2
+#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE	3
+#define USB_CDC_ACM_PROTO_AT_GSM		4
+#define USB_CDC_ACM_PROTO_AT_3G			5
+#define USB_CDC_ACM_PROTO_AT_CDMA		6
+#define USB_CDC_ACM_PROTO_VENDOR		0xff
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific descriptors ... there are a couple dozen of them
+ */
+
+#define USB_CDC_HEADER_TYPE		0x00		/* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE	0x01		/* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE		0x02		/* acm_descriptor */
+#define USB_CDC_UNION_TYPE		0x06		/* union_desc */
+#define USB_CDC_COUNTRY_TYPE		0x07
+#define USB_CDC_ETHERNET_TYPE		0x0f		/* ether_desc */
+#define USB_CDC_WHCM_TYPE		0x11
+#define USB_CDC_MDLM_TYPE		0x12		/* mdlm_desc */
+#define USB_CDC_MDLM_DETAIL_TYPE	0x13		/* mdlm_detail_desc */
+#define USB_CDC_DMM_TYPE		0x14
+#define USB_CDC_OBEX_TYPE		0x15
+
+/* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
+struct usb_cdc_header_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__le16	bcdCDC;
+} __attribute__ ((packed));
+
+/* "Call Management Descriptor" from CDC spec  5.2.3.2 */
+struct usb_cdc_call_mgmt_descriptor {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__u8	bmCapabilities;
+#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT		0x01
+#define USB_CDC_CALL_MGMT_CAP_DATA_INTF		0x02
+
+	__u8	bDataInterface;
+} __attribute__ ((packed));
+
+/* "Abstract Control Management Descriptor" from CDC spec  5.2.3.3 */
+struct usb_cdc_acm_descriptor {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__u8	bmCapabilities;
+} __attribute__ ((packed));
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
+struct usb_cdc_union_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__u8	bMasterInterface0;
+	__u8	bSlaveInterface0;
+	/* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct usb_cdc_ether_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__u8	iMACAddress;
+	__le32	bmEthernetStatistics;
+	__le16	wMaxSegmentSize;
+	__le16	wNumberMCFilters;
+	__u8	bNumberPowerFilters;
+} __attribute__ ((packed));
+
+/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */
+struct usb_cdc_mdlm_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__le16	bcdVersion;
+	__u8	bGUID[16];
+} __attribute__ ((packed));
+
+/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */
+struct usb_cdc_mdlm_detail_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	/* type is associated with mdlm_desc.bGUID */
+	__u8	bGuidDescriptorType;
+	__u8	bDetailData[0];
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Control Requests (6.2)
+ *
+ * section 3.6.2.1 table 4 has the ACM profile, for modems.
+ * section 3.8.2 table 10 has the ethernet profile.
+ *
+ * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
+ * heavily dependent on the encapsulated (proprietary) command mechanism.
+ */
+
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
+#define USB_CDC_REQ_SET_LINE_CODING		0x20
+#define USB_CDC_REQ_GET_LINE_CODING		0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
+#define USB_CDC_REQ_SEND_BREAK			0x23
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS	0x40
+#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER	0x41
+#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER	0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER	0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC		0x44
+
+/* Line Coding Structure from CDC spec 6.2.13 */
+struct usb_cdc_line_coding {
+	__le32	dwDTERate;
+	__u8	bCharFormat;
+#define USB_CDC_1_STOP_BITS			0
+#define USB_CDC_1_5_STOP_BITS			1
+#define USB_CDC_2_STOP_BITS			2
+
+	__u8	bParityType;
+#define USB_CDC_NO_PARITY			0
+#define USB_CDC_ODD_PARITY			1
+#define USB_CDC_EVEN_PARITY			2
+#define USB_CDC_MARK_PARITY			3
+#define USB_CDC_SPACE_PARITY			4
+
+	__u8	bDataBits;
+} __attribute__ ((packed));
+
+/* table 62; bits in multicast filter */
+#define	USB_CDC_PACKET_TYPE_PROMISCUOUS		(1 << 0)
+#define	USB_CDC_PACKET_TYPE_ALL_MULTICAST	(1 << 1) /* no filter */
+#define	USB_CDC_PACKET_TYPE_DIRECTED		(1 << 2)
+#define	USB_CDC_PACKET_TYPE_BROADCAST		(1 << 3)
+#define	USB_CDC_PACKET_TYPE_MULTICAST		(1 << 4) /* filtered */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Notifications (6.3) sent by interrupt transfers
+ *
+ * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
+ * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
+ * RNDIS also defines its own bit-incompatible notifications
+ */
+
+#define USB_CDC_NOTIFY_NETWORK_CONNECTION	0x00
+#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE	0x01
+#define USB_CDC_NOTIFY_SERIAL_STATE		0x20
+#define USB_CDC_NOTIFY_SPEED_CHANGE		0x2a
+
+struct usb_cdc_notification {
+	__u8	bmRequestType;
+	__u8	bNotificationType;
+	__le16	wValue;
+	__le16	wIndex;
+	__le16	wLength;
+} __attribute__ ((packed));
+
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -32,6 +32,7 @@
 #define _LINUX_USBDEVICE_FS_H
 
 #include <linux/types.h>
+#include <linux/compat.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -123,6 +124,24 @@ struct usbdevfs_hub_portinfo {
 	char port [127];	/* e.g. port 3 connects to device 27 */
 };
 
+#ifdef CONFIG_COMPAT
+struct usbdevfs_urb32 {
+	unsigned char type;
+	unsigned char endpoint;
+	compat_int_t status;
+	compat_uint_t flags;
+	compat_caddr_t buffer;
+	compat_int_t buffer_length;
+	compat_int_t actual_length;
+	compat_int_t start_frame;
+	compat_int_t number_of_packets;
+	compat_int_t error_count;
+	compat_uint_t signr;
+	compat_caddr_t usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+#endif
+
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
@@ -130,9 +149,12 @@ struct usbdevfs_hub_portinfo {
 #define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
 #define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
 #define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
 #define USBDEVFS_DISCARDURB        _IO('U', 11)
 #define USBDEVFS_REAPURB           _IOW('U', 12, void *)
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
 #define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
 #define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
 #define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
@@ -143,5 +165,4 @@ struct usbdevfs_hub_portinfo {
 #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
 #define USBDEVFS_DISCONNECT        _IO('U', 22)
 #define USBDEVFS_CONNECT           _IO('U', 23)
-
 #endif /* _LINUX_USBDEVICE_FS_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -268,64 +268,92 @@ struct v4l2_timecode
 /* The above is based on SMPTE timecodes */
 
 
+#if 1
 /*
- *	C O M P R E S S I O N   P A R A M E T E R S
+ *	M P E G   C O M P R E S S I O N   P A R A M E T E R S
+ *
+ *  ### WARNING: this is still work-in-progress right now, most likely
+ *  ###          there will be some incompatible changes.
+ *
  */
-#if 0
-/* ### generic compression settings don't work, there is too much
- * ### codec-specific stuff.  Maybe reuse that for MPEG codec settings
- * ### later ... */
-struct v4l2_compression
-{
-	__u32	quality;
-	__u32	keyframerate;
-	__u32	pframerate;
-	__u32	reserved[5];
-
-/*  what we'll need for MPEG, extracted from some postings on
-    the v4l list (Gert Vervoort, PlasmaJohn).
-
-system stream:
-  - type: elementary stream(ES), packatised elementary stream(s) (PES)
-    program stream(PS), transport stream(TS)
-  - system bitrate
-  - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes)
-  - TS video PID
-  - TS audio PID
-  - TS PCR PID
-  - TS system information tables (PAT, PMT, CAT, NIT and SIT)
-  - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported
-    by MPEG-1 systems)
-
-audio:
-  - type: MPEG (+Layer I,II,III), AC-3, LPCM
-  - bitrate
-  - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz)
-  - Trick Modes? (ff, rew)
-  - Copyright
-  - Inverse Telecine
-
-video:
-  - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set
-    through excisting V4L2 controls
-  - noise reduction, parameters encoder specific?
-  - MPEG video version: MPEG-1, MPEG-2
-  - GOP (Group Of Pictures) definition:
-    - N: number of frames per GOP
-    - M: distance between reference (I,P) frames
-    - open/closed GOP
-  - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes)
-  - quantiser scale: linear or logarithmic
-  - scanning: alternate or zigzag
-  - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate).
-  - target video bitrate for CBR
-  - target video bitrate for VBR
-  - maximum video bitrate for VBR - min. quantiser value for VBR
-  - max. quantiser value for VBR
-  - adaptive quantisation value
-  - return the number of bytes per GOP or bitrate for bitrate monitoring
 
-*/
+
+enum v4l2_bitrate_mode {
+	V4L2_BITRATE_NONE = 0,	/* not specified */
+	V4L2_BITRATE_CBR,	/* constant bitrate */
+	V4L2_BITRATE_VBR,	/* variable bitrate */
+};
+struct v4l2_bitrate {
+	/* rates are specified in kbit/sec */
+	enum v4l2_bitrate_mode	mode;
+	__u32			min;
+	__u32			target;  /* use this one for CBR */
+	__u32			max;
+};
+
+enum v4l2_mpeg_streamtype {
+	V4L2_MPEG_SS_1,		/* MPEG-1 system stream */
+	V4L2_MPEG_PS_2,		/* MPEG-2 program stream */
+	V4L2_MPEG_TS_2,		/* MPEG-2 transport stream */
+	V4L2_MPEG_PS_DVD,      	/* MPEG-2 program stream with DVD header fixups */
+};
+enum v4l2_mpeg_audiotype {
+	V4L2_MPEG_AU_2_I,	/* MPEG-2 layer 1 */
+	V4L2_MPEG_AU_2_II,	/* MPEG-2 layer 2 */
+	V4L2_MPEG_AU_2_III,	/* MPEG-2 layer 3 */
+	V4L2_MPEG_AC3,		/* AC3 */
+	V4L2_MPEG_LPCM,		/* LPCM */
+};
+enum v4l2_mpeg_videotype {
+	V4L2_MPEG_VI_1,		/* MPEG-1 */
+	V4L2_MPEG_VI_2,		/* MPEG-2 */
+};
+enum v4l2_mpeg_aspectratio {
+	V4L2_MPEG_ASPECT_SQUARE = 1,   /* square pixel */
+	V4L2_MPEG_ASPECT_4_3    = 2,   /*  4 : 3       */
+	V4L2_MPEG_ASPECT_16_9   = 3,   /* 16 : 9       */
+	V4L2_MPEG_ASPECT_1_221  = 4,   /*  1 : 2,21    */
+};
+
+struct v4l2_mpeg_compression {
+	/* general */
+	enum v4l2_mpeg_streamtype	st_type;
+	struct v4l2_bitrate		st_bitrate;
+
+	/* transport streams */
+	__u16				ts_pid_pmt;
+	__u16				ts_pid_audio;
+	__u16				ts_pid_video;
+	__u16				ts_pid_pcr;
+
+	/* program stream */
+	__u16				ps_size;
+	__u16				reserved_1;    /* align */
+
+	/* audio */
+	enum v4l2_mpeg_audiotype	au_type;
+	struct v4l2_bitrate		au_bitrate;
+	__u32				au_sample_rate;
+	__u8                            au_pesid;
+	__u8                            reserved_2[3]; /* align */
+
+	/* video */
+	enum v4l2_mpeg_videotype	vi_type;
+	enum v4l2_mpeg_aspectratio	vi_aspect_ratio;
+	struct v4l2_bitrate		vi_bitrate;
+	__u32				vi_frame_rate;
+	__u16				vi_frames_per_gop;
+	__u16				vi_bframes_count;
+	__u8                            vi_pesid;
+	__u8                            reserved_3[3]; /* align */
+
+	/* misc flags */
+	__u32                           closed_gops:1;
+	__u32                           pulldown:1;
+	__u32                           reserved_4:30; /* align */
+
+	/* I don't expect the above being perfect yet ;) */
+	__u32				reserved_5[8];
 };
 #endif
 
@@ -841,9 +869,9 @@ struct v4l2_streamparm
 #define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
 #define VIDIOC_G_FMT		_IOWR ('V',  4, struct v4l2_format)
 #define VIDIOC_S_FMT		_IOWR ('V',  5, struct v4l2_format)
-#if 0
-#define VIDIOC_G_COMP		_IOR  ('V',  6, struct v4l2_compression)
-#define VIDIOC_S_COMP		_IOW  ('V',  7, struct v4l2_compression)
+#if 1 /* experimental */
+#define VIDIOC_G_MPEGCOMP       _IOR  ('V',  6, struct v4l2_mpeg_compression)
+#define VIDIOC_S_MPEGCOMP     	_IOW  ('V',  7, struct v4l2_mpeg_compression)
 #endif
 #define VIDIOC_REQBUFS		_IOWR ('V',  8, struct v4l2_requestbuffers)
 #define VIDIOC_QUERYBUF		_IOWR ('V',  9, struct v4l2_buffer)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -26,7 +26,8 @@ struct vm_struct {
 extern void *vmalloc(unsigned long size);
 extern void *vmalloc_exec(unsigned long size);
 extern void *vmalloc_32(unsigned long size);
-extern void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot);
+extern void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask, pgprot_t prot);
+extern void *__vmalloc_area(struct vm_struct *area, unsigned int __nocast gfp_mask, pgprot_t prot);
 extern void vfree(void *addr);
 
 extern void *vmap(struct page **pages, unsigned int count,
@@ -40,6 +41,7 @@ extern struct vm_struct *get_vm_area(uns
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 					unsigned long start, unsigned long end);
 extern struct vm_struct *remove_vm_area(void *addr);
+extern struct vm_struct *__remove_vm_area(void *addr);
 extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
 			struct page ***pages);
 extern void unmap_vm_area(struct vm_struct *area);
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -25,15 +25,6 @@
 #define BROKEN_GRAPHICS_PROGRAMS 1
 #endif
 
-extern struct vt_struct {
-	int vc_num;				/* The console number */
-	unsigned char	vc_mode;		/* KD_TEXT, ... */
-	struct vt_mode	vt_mode;
-	int		vt_pid;
-	int		vt_newvt;
-	wait_queue_head_t paste_wait;
-} *vt_cons[MAX_NR_CONSOLES];
-
 extern void kd_mksound(unsigned int hz, unsigned int ticks);
 extern int kbd_rate(struct kbd_repeat *rep);
 
@@ -41,25 +32,20 @@ extern int kbd_rate(struct kbd_repeat *r
 
 int vc_allocate(unsigned int console);
 int vc_cons_allocated(unsigned int console);
-int vc_resize(int currcons, unsigned int cols, unsigned int lines);
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
 void vc_disallocate(unsigned int console);
-void reset_palette(int currcons);
-void set_palette(int currcons);
+void reset_palette(struct vc_data *vc);
 void do_blank_screen(int entering_gfx);
 void do_unblank_screen(int leaving_gfx);
 void unblank_screen(void);
 void poke_blanked_console(void);
-int con_font_op(int currcons, struct console_font_op *op);
-int con_font_set(int currcons, struct console_font_op *op);
-int con_font_get(int currcons, struct console_font_op *op);
-int con_font_default(int currcons, struct console_font_op *op);
-int con_font_copy(int currcons, struct console_font_op *op);
+int con_font_op(struct vc_data *vc, struct console_font_op *op);
 int con_set_cmap(unsigned char __user *cmap);
 int con_get_cmap(unsigned char __user *cmap);
-void scrollback(int);
-void scrollfront(int);
-void update_region(int currcons, unsigned long start, int count);
-void redraw_screen(int new_console, int is_switch);
+void scrollback(struct vc_data *vc, int lines);
+void scrollfront(struct vc_data *vc, int lines);
+void update_region(struct vc_data *vc, unsigned long start, int count);
+void redraw_screen(struct vc_data *vc, int is_switch);
 #define update_screen(x) redraw_screen(x, 0)
 #define switch_screen(x) redraw_screen(x, 1)
 
@@ -75,25 +61,25 @@ int con_set_trans_old(unsigned char __us
 int con_get_trans_old(unsigned char __user * table);
 int con_set_trans_new(unsigned short __user * table);
 int con_get_trans_new(unsigned short __user * table);
-int con_clear_unimap(int currcons, struct unimapinit *ui);
-int con_set_unimap(int currcons, ushort ct, struct unipair __user *list);
-int con_get_unimap(int currcons, ushort ct, ushort __user *uct, struct unipair __user *list);
-int con_set_default_unimap(int currcons);
-void con_free_unimap(int currcons);
-void con_protect_unimap(int currcons, int rdonly);
-int con_copy_unimap(int dstcons, int srccons);
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui);
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
+int con_set_default_unimap(struct vc_data *vc);
+void con_free_unimap(struct vc_data *vc);
+void con_protect_unimap(struct vc_data *vc, int rdonly);
+int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
 
 /* vt.c */
-void complete_change_console(unsigned int new_console);
 int vt_waitactive(int vt);
-void change_console(unsigned int);
-void reset_vc(unsigned int new_console);
+void change_console(struct vc_data *new_vc);
+void reset_vc(struct vc_data *vc);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
  * we can easily avoid touching user space while holding the console spinlock.
  */
-#define CON_BUF_SIZE	PAGE_SIZE
+
+#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
 extern char con_buf[CON_BUF_SIZE];
 extern struct semaphore con_buf_sem;
 
diff --git a/include/linux/wait.h b/include/linux/wait.h
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -79,7 +79,7 @@ typedef struct __wait_queue_head wait_qu
 
 static inline void init_waitqueue_head(wait_queue_head_t *q)
 {
-	q->lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&q->lock);
 	INIT_LIST_HEAD(&q->task_list);
 }
 
@@ -169,6 +169,18 @@ do {									\
 	finish_wait(&wq, &__wait);					\
 } while (0)
 
+/**
+ * wait_event - sleep until a condition gets true
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ */
 #define wait_event(wq, condition) 					\
 do {									\
 	if (condition)	 						\
@@ -191,6 +203,22 @@ do {									\
 	finish_wait(&wq, &__wait);					\
 } while (0)
 
+/**
+ * wait_event_timeout - sleep until a condition gets true or a timeout elapses
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * The function returns 0 if the @timeout elapsed, and the remaining
+ * jiffies if the condition evaluated to true before the timeout elapsed.
+ */
 #define wait_event_timeout(wq, condition, timeout)			\
 ({									\
 	long __ret = timeout;						\
@@ -217,6 +245,21 @@ do {									\
 	finish_wait(&wq, &__wait);					\
 } while (0)
 
+/**
+ * wait_event_interruptible - sleep until a condition gets true
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_INTERRUPTIBLE) until the
+ * @condition evaluates to true or a signal is received.
+ * The @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * The function will return -ERESTARTSYS if it was interrupted by a
+ * signal and 0 if @condition evaluated to true.
+ */
 #define wait_event_interruptible(wq, condition)				\
 ({									\
 	int __ret = 0;							\
@@ -245,6 +288,23 @@ do {									\
 	finish_wait(&wq, &__wait);					\
 } while (0)
 
+/**
+ * wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_INTERRUPTIBLE) until the
+ * @condition evaluates to true or a signal is received.
+ * The @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it
+ * was interrupted by a signal, and the remaining jiffies otherwise
+ * if the condition evaluated to true before the timeout elapsed.
+ */
 #define wait_event_interruptible_timeout(wq, condition, timeout)	\
 ({									\
 	long __ret = timeout;						\
@@ -326,9 +386,7 @@ int wake_bit_function(wait_queue_t *wait
 	wait_queue_t name = {						\
 		.task		= current,				\
 		.func		= autoremove_wake_function,		\
-		.task_list	= {	.next = &(name).task_list,	\
-					.prev = &(name).task_list,	\
-				},					\
+		.task_list	= LIST_HEAD_INIT((name).task_list),	\
 	}
 
 #define DEFINE_WAIT_BIT(name, word, bit)				\
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -70,6 +70,9 @@ extern int current_is_keventd(void);
 extern int keventd_up(void);
 
 extern void init_workqueues(void);
+void cancel_rearming_delayed_work(struct work_struct *work);
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *,
+				       struct work_struct *);
 
 /*
  * Kill off a pending schedule_delayed_work().  Note that the work callback
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -86,6 +86,7 @@ static inline void wait_on_inode(struct 
 int wakeup_bdflush(long nr_pages);
 void laptop_io_completion(void);
 void laptop_sync_completion(void);
+void throttle_vm_writeout(void);
 
 /* These are exported to sysctl. */
 extern int dirty_background_ratio;
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -140,8 +140,11 @@ enum {
 	XFRM_MSG_FLUSHPOLICY,
 #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
 
-	XFRM_MSG_MAX
+	__XFRM_MSG_MAX
 };
+#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
+
+#define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)
 
 struct xfrm_user_tmpl {
 	struct xfrm_id		id;
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -1,5 +1,5 @@
 /*
- * $Id: ir-common.h,v 1.6 2004/09/15 16:15:24 kraxel Exp $
+ * $Id: ir-common.h,v 1.8 2005/02/22 12:28:40 kraxel Exp $
  *
  * some common structs and functions to handle infrared remotes via
  * input layer ...
@@ -47,7 +47,9 @@ struct ir_input_state {
 };
 
 extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
 		   int ir_type, IR_KEYTAB_TYPE *ir_codes);
@@ -55,6 +57,8 @@ void ir_input_nokey(struct input_dev *de
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 		      u32 ir_key, u32 ir_raw);
 u32  ir_extract_bits(u32 data, u32 mask);
+int  ir_dump_samples(u32 *samples, int count);
+int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 
 /*
  * Local variables:
diff --git a/include/media/saa6752hs.h b/include/media/saa6752hs.h
--- a/include/media/saa6752hs.h
+++ b/include/media/saa6752hs.h
@@ -18,14 +18,14 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#ifndef _SAA6752HS_H
+#if 0 /* ndef _SAA6752HS_H */
 #define _SAA6752HS_H
 
-enum mpeg_bitrate_mode {
-	MPEG_BITRATE_MODE_VBR = 0, /* Variable bitrate */
-	MPEG_BITRATE_MODE_CBR = 1, /* Constant bitrate */
+enum mpeg_video_bitrate_mode {
+	MPEG_VIDEO_BITRATE_MODE_VBR = 0, /* Variable bitrate */
+	MPEG_VIDEO_BITRATE_MODE_CBR = 1, /* Constant bitrate */
 
-	MPEG_BITRATE_MODE_MAX
+	MPEG_VIDEO_BITRATE_MODE_MAX
 };
 
 enum mpeg_audio_bitrate {
@@ -35,16 +35,33 @@ enum mpeg_audio_bitrate {
 	MPEG_AUDIO_BITRATE_MAX
 };
 
+enum mpeg_video_format {
+	MPEG_VIDEO_FORMAT_D1 = 0,
+	MPEG_VIDEO_FORMAT_2_3_D1 = 1,
+	MPEG_VIDEO_FORMAT_1_2_D1 = 2,
+	MPEG_VIDEO_FORMAT_SIF = 3,
+
+	MPEG_VIDEO_FORMAT_MAX
+};
+
 #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000
 #define MPEG_TOTAL_BITRATE_MAX 27000
+#define MPEG_PID_MAX ((1 << 14) - 1)
 
 struct mpeg_params {
-	enum mpeg_bitrate_mode bitrate_mode;
+	enum mpeg_video_bitrate_mode video_bitrate_mode;
 	unsigned int video_target_bitrate;
 	unsigned int video_max_bitrate; // only used for VBR
 	enum mpeg_audio_bitrate audio_bitrate;
 	unsigned int total_bitrate;
+
+   	unsigned int pmt_pid;
+	unsigned int video_pid;
+	unsigned int audio_pid;
+	unsigned int pcr_pid;
+
+	enum mpeg_video_format video_format;
 };
 
 #define MPEG_SETPARAMS             _IOW('6',100,struct mpeg_params)
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -65,7 +65,7 @@ struct saa7146_vv;
 /* saa7146 page table */
 struct saa7146_pgtable {
 	unsigned int	size;
-	u32 		*cpu;
+	u32		*cpu;
 	dma_addr_t	dma;
 	/* used for offsets for u,v planes for planar capture modes */
 	unsigned long	offset;
@@ -93,20 +93,20 @@ struct saa7146_extension
 #define SAA7146_USE_I2C_IRQ	0x1
 #define SAA7146_I2C_SHORT_DELAY	0x2
 	int	flags;
-	
+
 	/* pairs of subvendor and subdevice ids for
 	   supported devices, last entry 0xffff, 0xfff */
 	struct module *module;
 	struct pci_driver driver;
 	struct pci_device_id *pci_tbl;
-	
+
 	/* extension functions */
 	int (*probe)(struct saa7146_dev *);
 	int (*attach)(struct saa7146_dev *, struct saa7146_pci_extension_data *);
 	int (*detach)(struct saa7146_dev*);
 
 	u32	irq_mask;	/* mask to indicate, which irq-events are handled by the extension */
-	void 	(*irq_func)(struct saa7146_dev*, u32* irq_mask);
+	void	(*irq_func)(struct saa7146_dev*, u32* irq_mask);
 };
 
 struct saa7146_dma
@@ -122,18 +122,18 @@ struct saa7146_dev
 	struct list_head		item;
 
 	/* different device locks */
-       	spinlock_t                 	slock;
-        struct semaphore           	lock;
+	spinlock_t			slock;
+        struct semaphore		lock;
 
-	unsigned char			__iomem *mem;	/* pointer to mapped IO memory */
+	unsigned char			__iomem *mem;		/* pointer to mapped IO memory */
 	int				revision;	/* chip revision; needed for bug-workarounds*/
 
 	/* pci-device & irq stuff*/
 	char				name[32];
 	struct pci_dev			*pci;
 	u32				int_todo;
-       	spinlock_t			int_slock;
-	
+	spinlock_t			int_slock;
+
 	/* extension handling */
 	struct saa7146_extension	*ext;		/* indicates if handled by extension */
 	void				*ext_priv;	/* pointer for extension private use (most likely some private data) */
@@ -149,7 +149,7 @@ struct saa7146_dev
 	struct saa7146_dma	d_i2c;	/* pointer to i2c memory */
 	wait_queue_head_t	i2c_wq;
 	int			i2c_op;
-	
+
 	/* memories */
 	struct saa7146_dma	d_rps0;
 	struct saa7146_dma	d_rps1;
@@ -157,7 +157,7 @@ struct saa7146_dev
 
 /* from saa7146_i2c.c */
 int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
-int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num,  int retries);
+int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries);
 
 /* from saa7146_core.c */
 extern struct list_head saa7146_devices;
@@ -178,8 +178,8 @@ int saa7146_wait_for_debi_done(struct sa
 
 /* some i2c constants */
 #define SAA7146_I2C_TIMEOUT	100	/* i2c-timeout-value in ms */
-#define SAA7146_I2C_RETRIES 	3	/* how many times shall we retry an i2c-operation? */
-#define SAA7146_I2C_DELAY 	5	/* time we wait after certain i2c-operations */
+#define SAA7146_I2C_RETRIES	3	/* how many times shall we retry an i2c-operation? */
+#define SAA7146_I2C_DELAY	5	/* time we wait after certain i2c-operations */
 
 /* unsorted defines */
 #define ME1    0x0000000800
@@ -272,7 +272,7 @@ int saa7146_wait_for_debi_done(struct sa
 #define MASK_W1   0xffff0000    /* Mask value for word 1 */
 
 #define MASK_PA   0xfffffffc    /* Mask value for physical address */
-#define MASK_PR   0xfffffffe 	/* Mask value for protection register */
+#define MASK_PR   0xfffffffe	/* Mask value for protection register */
 #define MASK_ER   0xffffffff    /* Mask value for the entire register */
 
 #define MASK_NONE 0x00000000    /* No mask */
@@ -295,7 +295,7 @@ int saa7146_wait_for_debi_done(struct sa
 #define BASE_ODD3         0x30  /* Video DMA 3 registers */
 #define BASE_EVEN3        0x34
 #define PROT_ADDR3        0x38
-#define PITCH3            0x3C         
+#define PITCH3            0x3C
 #define BASE_PAGE3        0x40  /* Video DMA 3 base page */
 #define NUM_LINE_BYTE3    0x44
 
@@ -323,15 +323,15 @@ int saa7146_wait_for_debi_done(struct sa
 #define DEBI_CONFIG       0x7C
 #define DEBI_COMMAND      0x80
 #define DEBI_PAGE         0x84
-#define DEBI_AD           0x88	
+#define DEBI_AD           0x88
 
-#define I2C_TRANSFER      0x8C	
-#define I2C_STATUS        0x90	
+#define I2C_TRANSFER      0x8C
+#define I2C_STATUS        0x90
 
 #define BASE_A1_IN        0x94	/* Audio 1 input DMA */
 #define PROT_A1_IN        0x98
 #define PAGE_A1_IN        0x9C
-  
+
 #define BASE_A1_OUT       0xA0  /* Audio 1 output DMA */
 #define PROT_A1_OUT       0xA4
 #define PAGE_A1_OUT       0xA8
@@ -371,12 +371,12 @@ int saa7146_wait_for_debi_done(struct sa
 #define RPS_ADDR0         0x104  /* RPS task 0 address register */
 #define RPS_ADDR1         0x108  /* RPS task 1 address register */
 
-#define ISR               0x10C  /* Interrupt status register */                                                             
+#define ISR               0x10C  /* Interrupt status register */
 #define PSR               0x110  /* Primary status register */
 #define SSR               0x114  /* Secondary status register */
 
 #define EC1R              0x118  /* Event counter set 1 register */
-#define EC2R              0x11C  /* Event counter set 2 register */         
+#define EC2R              0x11C  /* Event counter set 2 register */
 
 #define PCI_VDP1          0x120  /* Video DMA pointer of FIFO 1 */
 #define PCI_VDP2          0x124  /* Video DMA pointer of FIFO 2 */
@@ -450,4 +450,3 @@ int saa7146_wait_for_debi_done(struct sa
 #define SAA7146_I2C_BUS_BIT_RATE_60	(0x300)
 
 #endif
-
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -31,7 +31,7 @@ struct	saa7146_video_dma {
 
 struct saa7146_format {
 	char	*name;
-	u32   	pixelformat;
+	u32	pixelformat;
 	u32	trans;
 	u8	depth;
 	u8	flags;
@@ -45,10 +45,10 @@ struct saa7146_standard
 
 	int v_offset;	/* number of lines of vertical offset before processing */
 	int v_field;	/* number of lines in a field for HPS to process */
-	
+
 	int h_offset;	/* horizontal offset of processing window */
 	int h_pixels;	/* number of horizontal pixels to process */
-	
+
 	int v_max_out;
 	int h_max_out;
 };
@@ -90,7 +90,7 @@ struct saa7146_fh {
 
 	/* video overlay */
 	struct saa7146_overlay	ov;
-	
+
 	/* video capture */
 	struct videobuf_queue	video_q;
 	struct v4l2_pix_format	video_fmt;
@@ -139,11 +139,11 @@ struct saa7146_vv
 	   all opens? currently, we do the latter, like all other
 	   drivers do... */
 	struct saa7146_standard	*standard;
-	
+
 	int	vflip;
-	int 	hflip;
-	int 	current_hps_source;
-	int 	current_hps_sync;
+	int	hflip;
+	int	current_hps_source;
+	int	current_hps_sync;
 
 	struct saa7146_dma	d_clipping;	/* pointer to clipping memory */
 
@@ -157,7 +157,7 @@ struct saa7146_vv
 struct saa7146_extension_ioctls
 {
 	unsigned int	cmd;
-	int		flags;	
+	int		flags;
 };
 
 /* flags */
@@ -166,16 +166,16 @@ struct saa7146_extension_ioctls
 struct saa7146_ext_vv
 {
 	/* informations about the video capabilities of the device */
-	int	inputs;			
-	int	audios;			
+	int	inputs;
+	int	audios;
 	u32	capabilities;
-	int 	flags;
+	int	flags;
 
 	/* additionally supported transmission standards */
 	struct saa7146_standard *stds;
 	int num_stds;
 	int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
-		
+
 	struct saa7146_extension_ioctls *ioctls;
 	int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
 };
@@ -264,7 +264,7 @@ void saa7146_res_free(struct saa7146_fh 
 
 /* misc defines */
 #define SAA7146_NO_SWAP		(0x0)
-#define SAA7146_TWO_BYTE_SWAP 	(0x1)
+#define SAA7146_TWO_BYTE_SWAP	(0x1)
 #define SAA7146_FOUR_BYTE_SWAP	(0x2)
 
 #endif
diff --git a/include/media/tuner.h b/include/media/tuner.h
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -29,55 +29,74 @@
 #define TUNER_PHILIPS_PAL_I 1
 #define TUNER_PHILIPS_NTSC  2
 #define TUNER_PHILIPS_SECAM 3		/* you must actively select B/G, L, L` */
+
 #define TUNER_ABSENT        4
 #define TUNER_PHILIPS_PAL   5
 #define TUNER_TEMIC_NTSC    6        /* 4032 FY5 (3X 7004, 9498, 9789)  */
 #define TUNER_TEMIC_PAL_I   7        /* 4062 FY5 (3X 8501, 9957)        */
+
 #define TUNER_TEMIC_4036FY5_NTSC 8   /* 4036 FY5 (3X 1223, 1981, 7686)  */
 #define TUNER_ALPS_TSBH1_NTSC 	 9
 #define TUNER_ALPS_TSBE1_PAL 	10
 #define TUNER_ALPS_TSBB5_PAL_I 	11
+
 #define TUNER_ALPS_TSBE5_PAL 	12
 #define TUNER_ALPS_TSBC5_PAL 	13
 #define TUNER_TEMIC_4006FH5_PAL	14   /* 4006 FH5 (3X 9500, 9501, 7291)     */
 #define TUNER_ALPS_TSHC6_NTSC 	15
+
 #define TUNER_TEMIC_PAL_DK	16   /* 4016 FY5 (3X 1392, 1393)     */
 #define TUNER_PHILIPS_NTSC_M	17
 #define TUNER_TEMIC_4066FY5_PAL_I       18  /* 4066 FY5 (3X 7032, 7035) */
 #define TUNER_TEMIC_4006FN5_MULTI_PAL   19  /* B/G, I and D/K autodetected (3X 7595, 7606, 7657)*/
+
 #define TUNER_TEMIC_4009FR5_PAL         20  /* incl. FM radio (3X 7607, 7488, 7711)*/
 #define TUNER_TEMIC_4039FR5_NTSC        21  /* incl. FM radio (3X 7246, 7578, 7732)*/
 #define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  (3X 7804, 7806, 8103, 8104)*/
 #define TUNER_PHILIPS_PAL_DK		23
+
 #define TUNER_PHILIPS_FQ1216ME		24  /* you must actively select B/G/D/K, I, L, L` */
 #define TUNER_LG_PAL_I_FM	25
 #define TUNER_LG_PAL_I		26
 #define TUNER_LG_NTSC_FM	27
+
 #define TUNER_LG_PAL_FM		28
 #define TUNER_LG_PAL		29
 #define TUNER_TEMIC_4009FN5_MULTI_PAL_FM	30  /* B/G, I and D/K autodetected (3X 8155, 8160, 8163)*/
 #define TUNER_SHARP_2U5JF5540_NTSC  31
+
 #define TUNER_Samsung_PAL_TCPM9091PD27 32
 #define TUNER_MT2032 33
 #define TUNER_TEMIC_4106FH5 	34	/* 4106 FH5 (3X 7808, 7865)*/
 #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
+
 #define TUNER_HITACHI_NTSC       40
 #define TUNER_PHILIPS_PAL_MK     41
 #define TUNER_PHILIPS_ATSC       42
 #define TUNER_PHILIPS_FM1236_MK3 43
+
 #define TUNER_PHILIPS_4IN1       44	/* ATI TV Wonder Pro - Conexant */
 /* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
 #define TUNER_MICROTUNE_4049FM5  45
 #define TUNER_LG_NTSC_TAPE       47
+
 #define TUNER_TNF_8831BGFF       48
 #define TUNER_MICROTUNE_4042FI5  49	/* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */
 #define TUNER_TCL_2002N          50
 #define TUNER_PHILIPS_FM1256_IH3   51
+
 #define TUNER_THOMSON_DTT7610    52
+#define TUNER_PHILIPS_FQ1286     53
+#define TUNER_PHILIPS_TDA8290    54
+#define TUNER_LG_PAL_TAPE        55    /* Hauppauge PVR-150 PAL */
+
+#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */
+#define TUNER_PHILIPS_FQ1236A_MK4 57   /* Hauppauge PVR-500MCE NTSC */
 
 #define NOTUNER 0
 #define PAL     1	/* PAL_BG */
@@ -102,10 +121,6 @@
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
-#if 0 /* obsolete */
-# define TUNER_SET_RADIOFREQ         _IOW('t',3,int)    /* set radio freq */
-# define TUNER_SET_MODE              _IOW('t',4,int)    /* set tuner mode */
-#endif
 
 #define  TDA9887_SET_CONFIG          _IOW('t',5,int)
 /* tv card specific */
@@ -123,4 +138,62 @@
 # define TDA9887_DEEMPHASIS_75       (3<<16)
 # define TDA9887_AUTOMUTE            (1<<18)
 
+#ifdef __KERNEL__
+
+#define I2C_ADDR_TDA8290        0x4b
+#define I2C_ADDR_TDA8275        0x61
+
+struct tuner {
+	/* device */
+	struct i2c_client i2c;
+
+	/* state + config */
+	unsigned int initialized;
+	unsigned int type;            /* chip type */
+	unsigned int freq;            /* keep track of the current settings */
+	v4l2_std_id  std;
+	int          using_v4l2;
+
+	enum v4l2_tuner_type mode;
+	unsigned int input;
+
+	/* used by MT2032 */
+	unsigned int xogc;
+	unsigned int radio_if2;
+
+	/* used by tda8290 */
+	unsigned char i2c_easy_mode[2];
+	unsigned char i2c_set_freq[8];
+
+	/* function ptrs */
+	void (*tv_freq)(struct i2c_client *c, unsigned int freq);
+	void (*radio_freq)(struct i2c_client *c, unsigned int freq);
+	int  (*has_signal)(struct i2c_client *c);
+	int  (*is_stereo)(struct i2c_client *c);
+};
+
+extern unsigned int tuner_debug;
+extern unsigned const int tuner_count;
+
+extern int microtune_init(struct i2c_client *c);
+extern int tda8290_init(struct i2c_client *c);
+extern int default_tuner_init(struct i2c_client *c);
+
+#define tuner_warn(fmt, arg...) \
+	dev_printk(KERN_WARNING , &t->i2c.dev , fmt , ## arg)
+#define tuner_info(fmt, arg...) \
+	dev_printk(KERN_INFO , &t->i2c.dev , fmt , ## arg)
+#define tuner_dbg(fmt, arg...) \
+	if (tuner_debug) dev_printk(KERN_DEBUG , &t->i2c.dev , fmt , ## arg)
+
+#endif /* __KERNEL__ */
+
 #endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h
--- a/include/media/video-buf-dvb.h
+++ b/include/media/video-buf-dvb.h
@@ -16,7 +16,7 @@ struct videobuf_dvb {
 	int                        nfeeds;
 
 	/* videobuf_dvb_(un)register manges this */
-	struct dvb_adapter         *adapter;
+	struct dvb_adapter         adapter;
 	struct dvb_demux           demux;
 	struct dmxdev              dmxdev;
 	struct dmx_frontend        fe_hw;
diff --git a/include/net/act_api.h b/include/net/act_api.h
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -81,7 +81,7 @@ extern struct tc_action *tcf_action_init
 extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
 extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
-extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *);
+extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *, int);
 #endif /* CONFIG_NET_CLS_ACT */
 
 extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
diff --git a/include/net/act_generic.h b/include/net/act_generic.h
new file mode 100644
--- /dev/null
+++ b/include/net/act_generic.h
@@ -0,0 +1,142 @@
+/*
+ * include/net/act_generic.h
+ *
+*/
+#ifndef _NET_ACT_GENERIC_H
+#define _NET_ACT_GENERIC_H
+static inline int tcf_defact_release(struct tcf_defact *p, int bind)
+{
+	int ret = 0;
+	if (p) {
+		if (bind) {
+			p->bindcnt--;
+		}
+		p->refcnt--;
+		if (p->bindcnt <= 0 && p->refcnt <= 0) {
+			kfree(p->defdata);
+			tcf_hash_destroy(p);
+			ret = 1;
+		}
+	}
+	return ret;
+}
+
+static inline int
+alloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata)
+{
+	p->defdata = kmalloc(datalen, GFP_KERNEL);
+	if (p->defdata == NULL)
+		return -ENOMEM;
+	p->datalen = datalen;
+	memcpy(p->defdata, defdata, datalen);
+	return 0;
+}
+
+static inline int
+realloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata)
+{
+	/* safer to be just brute force for now */
+	kfree(p->defdata);
+	return alloc_defdata(p, datalen, defdata);
+}
+
+static inline int
+tcf_defact_init(struct rtattr *rta, struct rtattr *est,
+		struct tc_action *a, int ovr, int bind)
+{
+	struct rtattr *tb[TCA_DEF_MAX];
+	struct tc_defact *parm;
+	struct tcf_defact *p;
+	void *defdata;
+	u32 datalen = 0;
+	int ret = 0;
+
+	if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0)
+		return -EINVAL;
+
+	if (tb[TCA_DEF_PARMS - 1] == NULL || 
+	    RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm))
+		return -EINVAL;
+
+	parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]);
+	defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]);
+	if (defdata == NULL)
+		return -EINVAL;
+
+	datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]);
+	if (datalen <= 0)
+		return -EINVAL;
+
+	p = tcf_hash_check(parm->index, a, ovr, bind);
+	if (p == NULL) {
+		p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+		if (p == NULL)
+			return -ENOMEM;
+
+		ret = alloc_defdata(p, datalen, defdata);
+		if (ret < 0) {
+			kfree(p);
+			return ret;
+		}
+		ret = ACT_P_CREATED;
+	} else {
+		if (!ovr) {
+			tcf_defact_release(p, bind);
+			return -EEXIST;
+		}
+		realloc_defdata(p, datalen, defdata);
+	}
+
+	spin_lock_bh(&p->lock);
+	p->action = parm->action;
+	spin_unlock_bh(&p->lock);
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(p);
+	return ret;
+}
+
+static inline int tcf_defact_cleanup(struct tc_action *a, int bind)
+{
+	struct tcf_defact *p = PRIV(a, defact);
+
+	if (p != NULL)
+		return tcf_defact_release(p, bind);
+	return 0;
+}
+
+static inline int
+tcf_defact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+{
+	unsigned char *b = skb->tail;
+	struct tc_defact opt;
+	struct tcf_defact *p = PRIV(a, defact);
+	struct tcf_t t;
+
+	opt.index = p->index;
+	opt.refcnt = p->refcnt - ref;
+	opt.bindcnt = p->bindcnt - bind;
+	opt.action = p->action;
+	RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
+	RTA_PUT(skb, TCA_DEF_DATA, p->datalen, p->defdata);
+	t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+	t.expires = jiffies_to_clock_t(p->tm.expires);
+	RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t);
+	return skb->len;
+
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+#define tca_use_default_ops \
+	.dump           =       tcf_defact_dump, \
+	.cleanup        =       tcf_defact_cleanup, \
+	.init           =       tcf_defact_init, \
+	.walk           =       tcf_generic_walker, \
+
+#define tca_use_default_defines(name) \
+	static u32 idx_gen; \
+	static struct tcf_defact *tcf_##name_ht[MY_TAB_SIZE]; \
+	static DEFINE_RWLOCK(##name_lock);
+#endif /* _NET_ACT_GENERIC_H */
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -17,6 +17,8 @@
 
 #define IPV6_MAX_ADDRESSES		16
 
+#include <linux/in6.h>
+
 struct prefix_info {
 	__u8			type;
 	__u8			length;
@@ -43,13 +45,13 @@ struct prefix_info {
 
 #ifdef __KERNEL__
 
-#include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <net/if_inet6.h>
+#include <net/ipv6.h>
 
 #define IN6_ADDR_HSIZE		16
 
-extern void			addrconf_init(void);
+extern int			addrconf_init(void);
 extern void			addrconf_cleanup(void);
 
 extern int			addrconf_add_ifaddr(void __user *arg);
@@ -102,6 +104,8 @@ extern int ipv6_is_mld(struct sk_buff *s
 
 extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len);
 
+extern int ipv6_get_hoplimit(struct net_device *dev);
+
 /*
  *	anycast prototypes (anycast.c)
  */
diff --git a/include/net/ax25.h b/include/net/ax25.h
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -220,6 +220,14 @@ static __inline__ void ax25_cb_put(ax25_
 	}
 }
 
+static inline unsigned short ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	skb->dev      = dev;
+	skb->pkt_type = PACKET_HOST;
+	skb->mac.raw  = skb->data;
+	return htons(ETH_P_AX25);
+}
+
 /* af_ax25.c */
 extern struct hlist_head ax25_list;
 extern spinlock_t ax25_list_lock;
@@ -305,7 +313,7 @@ extern ax25_cb *ax25_send_frame(struct s
 extern void ax25_output(ax25_cb *, int, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
-extern void ax25_queue_xmit(struct sk_buff *);
+extern void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev);
 extern int  ax25_check_iframes_acked(ax25_cb *, unsigned short);
 
 /* ax25_route.c */
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -125,7 +125,6 @@ struct bt_sock_list {
 
 int  bt_sock_register(int proto, struct net_proto_family *ops);
 int  bt_sock_unregister(int proto);
-struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio);
 void bt_sock_link(struct bt_sock_list *l, struct sock *s);
 void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
 int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -217,7 +217,8 @@ void hci_inquiry_cache_update(struct hci
 /* ----- HCI Connections ----- */
 enum {
 	HCI_CONN_AUTH_PEND,
-	HCI_CONN_ENCRYPT_PEND
+	HCI_CONN_ENCRYPT_PEND,
+	HCI_CONN_RSWITCH_PEND
 };
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -290,6 +291,7 @@ struct hci_conn *hci_connect(struct hci_
 int hci_conn_auth(struct hci_conn *conn);
 int hci_conn_encrypt(struct hci_conn *conn);
 int hci_conn_change_link_key(struct hci_conn *conn);
+int hci_conn_switch_role(struct hci_conn *conn, uint8_t role);
 
 static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout)
 {
@@ -515,6 +517,8 @@ struct hci_cb {
 
 	void (*auth_cfm)	(struct hci_conn *conn, __u8 status);
 	void (*encrypt_cfm)	(struct hci_conn *conn, __u8 status, __u8 encrypt);
+	void (*key_change_cfm)	(struct hci_conn *conn, __u8 status);
+	void (*role_switch_cfm)	(struct hci_conn *conn, __u8 status, __u8 role);
 };
 
 static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
@@ -547,6 +551,32 @@ static inline void hci_encrypt_cfm(struc
 	read_unlock_bh(&hci_cb_list_lock);
 }
 
+static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
+{
+	struct list_head *p;
+
+	read_lock_bh(&hci_cb_list_lock);
+	list_for_each(p, &hci_cb_list) {
+		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+		if (cb->key_change_cfm)
+			cb->key_change_cfm(conn, status);
+	}
+	read_unlock_bh(&hci_cb_list_lock);
+}
+
+static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, __u8 role)
+{
+	struct list_head *p;
+
+	read_lock_bh(&hci_cb_list_lock);
+	list_for_each(p, &hci_cb_list) {
+		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+		if (cb->role_switch_cfm)
+			cb->role_switch_cfm(conn, status, role);
+	}
+	read_unlock_bh(&hci_cb_list_lock);
+}
+
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
@@ -565,8 +595,10 @@ void hci_si_event(struct hci_dev *hdev, 
 void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
 
 /* HCI info for socket */
-#define hci_pi(sk)	((struct hci_pinfo *)sk->sk_protinfo)
+#define hci_pi(sk) ((struct hci_pinfo *) sk)
+
 struct hci_pinfo {
+	struct bt_sock    bt;
 	struct hci_dev    *hdev;
 	struct hci_filter filter;
 	__u32             cmsg_mask;
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -201,9 +201,10 @@ struct l2cap_conn {
 };
 
 /* ----- L2CAP channel and socket info ----- */
-#define l2cap_pi(sk)   ((struct l2cap_pinfo *)sk->sk_protinfo)
+#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
 struct l2cap_pinfo {
+	struct bt_sock	bt;
 	__u16		psm;
 	__u16		dcid;
 	__u16		scid;
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -293,9 +293,10 @@ struct rfcomm_conninfo {
 #define RFCOMM_LM_RELIABLE	0x0010
 #define RFCOMM_LM_SECURE	0x0020
 
-#define rfcomm_pi(sk)   ((struct rfcomm_pinfo *)sk->sk_protinfo)
+#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk)
 
 struct rfcomm_pinfo {
+	struct bt_sock bt;
 	struct rfcomm_dlc   *dlc;
 	u8     channel;
 	u32    link_mode;
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -68,9 +68,10 @@ struct sco_conn {
 #define sco_conn_unlock(c)	spin_unlock(&c->lock);
 
 /* ----- SCO socket info ----- */
-#define sco_pi(sk)   ((struct sco_pinfo *)sk->sk_protinfo)
+#define sco_pi(sk) ((struct sco_pinfo *) sk)
 
 struct sco_pinfo {
+	struct bt_sock	bt;
 	__u32		flags;
 	struct sco_conn	*conn;
 };
diff --git a/include/net/checksum.h b/include/net/checksum.h
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -30,7 +30,7 @@ static inline
 unsigned int csum_and_copy_from_user (const unsigned char __user *src, unsigned char *dst,
 				      int len, int sum, int *err_ptr)
 {
-	if (verify_area(VERIFY_READ, src, len) == 0)
+	if (access_ok(VERIFY_READ, src, len))
 		return csum_partial_copy_from_user(src, dst, len, sum, err_ptr);
 
 	if (len)
diff --git a/include/net/dn.h b/include/net/dn.h
--- a/include/net/dn.h
+++ b/include/net/dn.h
@@ -2,6 +2,7 @@
 #define _NET_DN_H
 
 #include <linux/dn.h>
+#include <net/sock.h>
 #include <asm/byteorder.h>
 
 typedef unsigned short dn_address;
@@ -133,7 +134,10 @@ struct dn_scp                           
 
 };
 
-#define DN_SK(__sk) ((struct dn_scp *)(__sk)->sk_protinfo)
+static inline struct dn_scp *DN_SK(struct sock *sk)
+{
+	return (struct dn_scp *)(sk + 1);
+}
 
 /*
  * src,dst : Source and Destination DECnet addresses
diff --git a/include/net/dst.h b/include/net/dst.h
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -42,12 +42,14 @@ struct dst_entry
 	int			__use;
 	struct dst_entry	*child;
 	struct net_device       *dev;
-	int			obsolete;
+	short			error;
+	short			obsolete;
 	int			flags;
 #define DST_HOST		1
 #define DST_NOXFRM		2
 #define DST_NOPOLICY		4
 #define DST_NOHASH		8
+#define DST_BALANCED            0x10
 	unsigned long		lastuse;
 	unsigned long		expires;
 
@@ -60,8 +62,6 @@ struct dst_entry
 	unsigned long		rate_last;	/* rate limiting for ICMP */
 	unsigned long		rate_tokens;
 
-	int			error;
-
 	struct neighbour	*neighbour;
 	struct hh_cache		*hh;
 	struct xfrm_state	*xfrm;
@@ -109,19 +109,23 @@ dst_metric(const struct dst_entry *dst, 
 	return dst->metrics[metric-1];
 }
 
-static inline u32
-dst_path_metric(const struct dst_entry *dst, int metric)
+static inline u32 dst_mtu(const struct dst_entry *dst)
 {
-	return dst->path->metrics[metric-1];
+	u32 mtu = dst_metric(dst, RTAX_MTU);
+	/*
+	 * Alexey put it here, so ask him about it :)
+	 */
+	barrier();
+	return mtu;
 }
 
 static inline u32
-dst_pmtu(const struct dst_entry *dst)
+dst_allfrag(const struct dst_entry *dst)
 {
-	u32 mtu = dst_path_metric(dst, RTAX_MTU);
+	int ret = dst_metric(dst, RTAX_FEATURES) & RTAX_FEATURE_ALLFRAG;
 	/* Yes, _exactly_. This is paranoia. */
 	barrier();
-	return mtu;
+	return ret;
 }
 
 static inline int
@@ -249,6 +253,13 @@ static inline int dst_input(struct sk_bu
 	}
 }
 
+static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie)
+{
+	if (dst->obsolete)
+		dst = dst->ops->check(dst, cookie);
+	return dst;
+}
+
 extern void		dst_init(void);
 
 struct flowi;
diff --git a/include/net/flow.h b/include/net/flow.h
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -51,6 +51,7 @@ struct flowi {
 
 	__u8	proto;
 	__u8	flags;
+#define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
 	union {
 		struct {
 			__u16	sport;
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
--- a/include/net/gen_stats.h
+++ b/include/net/gen_stats.h
@@ -15,7 +15,8 @@ struct gnet_dump
 	/* Backward compatability */
 	int               compat_tc_stats;
 	int               compat_xstats;
-	struct rtattr *   xstats;
+	void *            xstats;
+	int               xstats_len;
 	struct tc_stats   tc_stats;
 };
 
diff --git a/include/net/icmp.h b/include/net/icmp.h
--- a/include/net/icmp.h
+++ b/include/net/icmp.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)icmp.h	1.0.4	05/13/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -19,9 +19,9 @@ struct inet_peer
 {
 	struct inet_peer	*avl_left, *avl_right;
 	struct inet_peer	*unused_next, **unused_prevp;
-	atomic_t		refcnt;
 	unsigned long		dtime;		/* the time of last use of not
 						 * referenced entries */
+	atomic_t		refcnt;
 	__u32			v4daddr;	/* peer's address */
 	__u16			avl_height;
 	__u16			ip_id_count;	/* IP ID for the next packet */
@@ -35,7 +35,6 @@ void			inet_initpeers(void) __init;
 struct inet_peer	*inet_getpeer(__u32 daddr, int create);
 
 extern spinlock_t inet_peer_unused_lock;
-extern struct inet_peer *inet_peer_unused_head;
 extern struct inet_peer **inet_peer_unused_tailp;
 /* can be called from BH context or outside */
 static inline void	inet_putpeer(struct inet_peer *p)
diff --git a/include/net/ip.h b/include/net/ip.h
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)ip.h	1.0.2	05/07/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox, <gw4pts@gw4pts.ampr.org>
  *
@@ -163,6 +163,7 @@ DECLARE_SNMP_STAT(struct linux_mib, net_
 
 extern int sysctl_local_port_range[2];
 extern int sysctl_ip_default_ttl;
+extern int sysctl_ip_nonlocal_bind;
 
 #ifdef CONFIG_INET
 /* The function in 2.2 was invalid, producing wrong result for
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -37,6 +37,7 @@ struct kern_rta {
 	u32		*rta_flow;
 	struct rta_cacheinfo *rta_ci;
 	struct rta_session *rta_sess;
+	u32		*rta_mp_alg;
 };
 
 struct fib_info;
@@ -81,6 +82,9 @@ struct fib_info {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 	int			fib_power;
 #endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	u32			fib_mp_alg;
+#endif
 	struct fib_nh		fib_nh[0];
 #define fib_dev		fib_nh[0].nh_dev
 };
@@ -95,6 +99,10 @@ struct fib_result {
 	unsigned char	nh_sel;
 	unsigned char	type;
 	unsigned char	scope;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	__u32           network;
+	__u32           netmask;
+#endif
 	struct fib_info *fi;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	struct fib_rule	*r;
@@ -119,6 +127,14 @@ struct fib_result {
 #define FIB_RES_DEV(res)		(FIB_RES_NH(res).nh_dev)
 #define FIB_RES_OIF(res)		(FIB_RES_NH(res).nh_oif)
 
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+#define FIB_RES_NETWORK(res)		((res).network)
+#define FIB_RES_NETMASK(res)	        ((res).netmask)
+#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+#define FIB_RES_NETWORK(res)		(0)
+#define FIB_RES_NETMASK(res)	        (0)
+#endif /* CONFIG_IP_ROUTE_MULTIPATH_WRANDOM */
+
 struct fib_table {
 	unsigned char	tb_id;
 	unsigned	tb_stamp;
diff --git a/include/net/ip_mp_alg.h b/include/net/ip_mp_alg.h
new file mode 100644
--- /dev/null
+++ b/include/net/ip_mp_alg.h
@@ -0,0 +1,99 @@
+/* ip_mp_alg.h: IPV4 multipath algorithm support.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifndef _NET_IP_MP_ALG_H
+#define _NET_IP_MP_ALG_H
+
+#include <linux/config.h>
+#include <linux/ip_mp_alg.h>
+#include <net/flow.h>
+#include <net/route.h>
+
+struct fib_nh;
+
+struct ip_mp_alg_ops {
+	void	(*mp_alg_select_route)(const struct flowi *flp,
+				       struct rtable *rth, struct rtable **rp);
+	void	(*mp_alg_flush)(void);
+	void	(*mp_alg_set_nhinfo)(__u32 network, __u32 netmask,
+				     unsigned char prefixlen,
+				     const struct fib_nh *nh);
+	void	(*mp_alg_remove)(struct rtable *rth);
+};
+
+extern int multipath_alg_register(struct ip_mp_alg_ops *, enum ip_mp_alg);
+extern void multipath_alg_unregister(struct ip_mp_alg_ops *, enum ip_mp_alg);
+
+extern struct ip_mp_alg_ops *ip_mp_alg_table[];
+
+static inline int multipath_select_route(const struct flowi *flp,
+					 struct rtable *rth,
+					 struct rtable **rp)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
+
+	/* mp_alg_select_route _MUST_ be implemented */
+	if (ops && (rth->u.dst.flags & DST_BALANCED)) {
+		ops->mp_alg_select_route(flp, rth, rp);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+static inline void multipath_flush(void)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	int i;
+
+	for (i = IP_MP_ALG_NONE; i <= IP_MP_ALG_MAX; i++) {
+		struct ip_mp_alg_ops *ops = ip_mp_alg_table[i];
+
+		if (ops && ops->mp_alg_flush)
+			ops->mp_alg_flush();
+	}
+#endif
+}
+
+static inline void multipath_set_nhinfo(struct rtable *rth,
+					__u32 network, __u32 netmask,
+					unsigned char prefixlen,
+					const struct fib_nh *nh)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
+
+	if (ops && ops->mp_alg_set_nhinfo)
+		ops->mp_alg_set_nhinfo(network, netmask, prefixlen, nh);
+#endif
+}
+
+static inline void multipath_remove(struct rtable *rth)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
+
+	if (ops && ops->mp_alg_remove &&
+	    (rth->u.dst.flags & DST_BALANCED))
+		ops->mp_alg_remove(rth);
+#endif
+}
+
+static inline int multipath_comparekeys(const struct flowi *flp1,
+					const struct flowi *flp2)
+{
+	return flp1->fl4_dst == flp2->fl4_dst &&
+		flp1->fl4_src == flp2->fl4_src &&
+		flp1->oif == flp2->oif &&
+#ifdef CONFIG_IP_ROUTE_FWMARK
+		flp1->fl4_fwmark == flp2->fl4_fwmark &&
+#endif
+		!((flp1->fl4_tos ^ flp2->fl4_tos) &
+		  (IPTOS_RT_MASK | RTO_ONLINK));
+}
+
+#endif /* _NET_IP_MP_ALG_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -305,6 +305,32 @@ static inline int ipv6_addr_equal(const 
 		a1->s6_addr32[3] == a2->s6_addr32[3]);
 }
 
+static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2,
+				      unsigned int prefixlen)
+{
+	unsigned pdw, pbi;
+
+	/* check complete u32 in prefix */
+	pdw = prefixlen >> 5;
+	if (pdw && memcmp(a1, a2, pdw << 2))
+		return 0;
+
+	/* check incomplete u32 in prefix */
+	pbi = prefixlen & 0x1f;
+	if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi))))
+		return 0;
+
+	return 1;
+}
+
+static inline int ipv6_prefix_equal(const struct in6_addr *a1,
+				    const struct in6_addr *a2,
+				    unsigned int prefixlen)
+{
+	return __ipv6_prefix_equal(a1->s6_addr32, a2->s6_addr32,
+				   prefixlen);
+}
+
 static inline int ipv6_addr_any(const struct in6_addr *a)
 {
 	return ((a->s6_addr32[0] | a->s6_addr32[1] | 
@@ -390,7 +416,7 @@ extern void			ipv6_push_frag_opts(struct
 						    u8 *proto);
 
 extern int			ipv6_skip_exthdr(const struct sk_buff *, int start,
-					         u8 *nexthdrp, int len);
+					         u8 *nexthdrp);
 
 extern int 			ipv6_ext_hdr(u8 nexthdr);
 
diff --git a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h
--- a/include/net/irda/af_irda.h
+++ b/include/net/irda/af_irda.h
@@ -33,9 +33,12 @@
 #include <net/irda/irlmp.h>		/* struct lsap_cb */
 #include <net/irda/irttp.h>		/* struct tsap_cb */
 #include <net/irda/discovery.h>		/* struct discovery_t */
+#include <net/sock.h>
 
 /* IrDA Socket */
 struct irda_sock {
+	/* struct sock has to be the first member of irda_sock */
+	struct sock sk;
 	__u32 saddr;          /* my local address */
 	__u32 daddr;          /* peer address */
 
@@ -69,7 +72,6 @@ struct irda_sock {
 
 	int errno;            /* status of the IAS query */
 
-	struct sock *sk;
 	wait_queue_head_t query_wait;	/* Wait for the answer to a query */
 	struct timer_list watchdog;	/* Timeout for discovery */
 
@@ -77,6 +79,9 @@ struct irda_sock {
 	LOCAL_FLOW rx_flow;
 };
 
-#define irda_sk(__sk) ((struct irda_sock *)(__sk)->sk_protinfo)
+static inline struct irda_sock *irda_sk(struct sock *sk)
+{
+	return (struct irda_sock *)sk;
+}
 
 #endif /* AF_IRDA_H */
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -66,22 +66,25 @@ extern unsigned int irda_debug;
 /* use 0 for production, 1 for verification, >2 for debug */
 #define IRDA_DEBUG_LEVEL 0
 
-#define IRDA_DEBUG(n, args...) (irda_debug >= (n)) ? (printk(KERN_DEBUG args)) : 0
-#define ASSERT(expr, func) \
-if(!(expr)) { \
-        printk( "Assertion failed! %s:%s:%d %s\n", \
-        __FILE__,__FUNCTION__,__LINE__,(#expr));  \
-        func }
+#define IRDA_DEBUG(n, args...) \
+do {	if (irda_debug >= (n)) \
+		printk(KERN_DEBUG args); \
+} while (0)
+#define IRDA_ASSERT(expr, func) \
+do { if(!(expr)) { \
+	printk( "Assertion failed! %s:%s:%d %s\n", \
+		__FILE__,__FUNCTION__,__LINE__,(#expr) ); \
+	func } } while (0)
+#define IRDA_ASSERT_LABEL(label)	label
 #else
-#define IRDA_DEBUG(n, args...)
-#define ASSERT(expr, func) \
-if(!(expr)) do { \
-        func } while (0)
+#define IRDA_DEBUG(n, args...) do { } while (0)
+#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0)
+#define IRDA_ASSERT_LABEL(label)
 #endif /* CONFIG_IRDA_DEBUG */
 
-#define WARNING(args...) printk(KERN_WARNING args)
-#define MESSAGE(args...) printk(KERN_INFO args)
-#define ERROR(args...)   printk(KERN_ERR args)
+#define IRDA_WARNING(args...) printk(KERN_WARNING args)
+#define IRDA_MESSAGE(args...) printk(KERN_INFO args)
+#define IRDA_ERROR(args...)   printk(KERN_ERR args)
 
 /*
  *  Magic numbers used by Linux-IrDA. Random numbers which must be unique to 
diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h
--- a/include/net/irda/irda_device.h
+++ b/include/net/irda/irda_device.h
@@ -235,9 +235,7 @@ int  irda_device_register_dongle(struct 
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type);
 int irda_device_dongle_cleanup(dongle_t *dongle);
 
-#ifdef CONFIG_ISA
 void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode);
-#endif
 
 void irda_task_delete(struct irda_task *task);
 struct irda_task *irda_task_execute(void *instance, 
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -13,6 +13,7 @@
  */
 #include <linux/timer.h>
 #include <net/llc_if.h>
+#include <net/sock.h>
 #include <linux/llc.h>
 
 #define LLC_EVENT                1
@@ -28,8 +29,9 @@ struct llc_timer {
 	u16		  expire;	/* timer expire time */
 };
 
-struct llc_opt {
-	struct sock	    *sk;		/* sock that has this llc_opt */
+struct llc_sock {
+	/* struct sock must be the first member of llc_sock */
+	struct sock	    sk;
 	struct sockaddr_llc addr;		/* address sock is bound to */
 	u8		    state;		/* state of connection */
 	struct llc_sap	    *sap;		/* pointer to parent SAP */
@@ -75,7 +77,10 @@ struct llc_opt {
 					      Used for resending FRMR */
 };
 
-#define llc_sk(__sk) ((struct llc_opt *)(__sk)->sk_protinfo)
+static inline struct llc_sock *llc_sk(const struct sock *sk)
+{
+	return (struct llc_sock *)sk;
+}
 
 static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type)
 {
@@ -87,7 +92,7 @@ static __inline__ char llc_backlog_type(
 	return skb->cb[sizeof(skb->cb) - 1];
 }
 
-extern struct sock *llc_sk_alloc(int family, int priority);
+extern struct sock *llc_sk_alloc(int family, int priority, struct proto *prot);
 extern void llc_sk_free(struct sock *sk);
 
 extern void llc_sk_reset(struct sock *sk);
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -15,11 +15,15 @@
  *	ndisc options
  */
 
-#define ND_OPT_SOURCE_LL_ADDR		1
-#define ND_OPT_TARGET_LL_ADDR		2
-#define ND_OPT_PREFIX_INFO		3
-#define ND_OPT_REDIRECT_HDR		4
-#define ND_OPT_MTU			5
+enum {
+	__ND_OPT_PREFIX_INFO_END = 0,
+	ND_OPT_SOURCE_LL_ADDR = 1,	/* RFC2461 */
+	ND_OPT_TARGET_LL_ADDR = 2,	/* RFC2461 */
+	ND_OPT_PREFIX_INFO = 3,		/* RFC2461 */
+	ND_OPT_REDIRECT_HDR = 4,	/* RFC2461 */
+	ND_OPT_MTU = 5,			/* RFC2461 */
+	__ND_OPT_MAX
+};
 
 #define MAX_RTR_SOLICITATION_DELAY	HZ
 
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -274,7 +274,8 @@ extern int			neigh_sysctl_register(struc
 						      struct neigh_parms *p,
 						      int p_id, int pdev_id,
 						      char *p_name,
-						      proc_handler *proc_handler);
+						      proc_handler *proc_handler,
+						      ctl_handler *strategy);
 extern void			neigh_sysctl_unregister(struct neigh_parms *p);
 
 static inline void __neigh_parms_put(struct neigh_parms *parms)
diff --git a/include/net/netrom.h b/include/net/netrom.h
--- a/include/net/netrom.h
+++ b/include/net/netrom.h
@@ -8,6 +8,7 @@
 #define _NETROM_H 
 #include <linux/netrom.h>
 #include <linux/list.h>
+#include <net/sock.h>
 
 #define	NR_NETWORK_LEN			15
 #define	NR_TRANSPORT_LEN		5
@@ -55,7 +56,8 @@ enum {
 #define NR_MAX_WINDOW_SIZE		127			/* Maximum Window Allowable - 127 */
 #define	NR_MAX_PACKET_SIZE		236			/* Maximum Packet Length - 236 */
 
-typedef struct {
+struct nr_sock {
+	struct sock		sock;
 	ax25_address		user_addr, source_addr, dest_addr;
 	struct net_device		*device;
 	unsigned char		my_index,   my_id;
@@ -72,10 +74,9 @@ typedef struct {
 	struct sk_buff_head	ack_queue;
 	struct sk_buff_head	reseq_queue;
 	struct sk_buff_head	frag_queue;
-	struct sock		*sk;		/* Backlink to socket */
-} nr_cb;
+};
 
-#define nr_sk(__sk) ((nr_cb *)(__sk)->sk_protinfo)
+#define nr_sk(sk) ((struct nr_sock *)(sk))
 
 struct nr_neigh {
 	struct hlist_node	neigh_node;
@@ -221,6 +222,7 @@ extern void nr_transmit_refusal(struct s
 extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
+extern void nr_init_timers(struct sock *sk);
 extern void nr_start_heartbeat(struct sock *);
 extern void nr_start_t1timer(struct sock *);
 extern void nr_start_t2timer(struct sock *);
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -148,6 +148,198 @@ extern int tcf_exts_dump(struct sk_buff 
 extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
 	                       struct tcf_ext_map *map);
 
+/**
+ * struct tcf_pkt_info - packet information
+ */
+struct tcf_pkt_info
+{
+	unsigned char *		ptr;
+	int			nexthdr;
+};
+
+#ifdef CONFIG_NET_EMATCH
+
+struct tcf_ematch_ops;
+
+/**
+ * struct tcf_ematch - extended match (ematch)
+ * 
+ * @matchid: identifier to allow userspace to reidentify a match
+ * @flags: flags specifying attributes and the relation to other matches
+ * @ops: the operations lookup table of the corresponding ematch module
+ * @datalen: length of the ematch specific configuration data
+ * @data: ematch specific data
+ */
+struct tcf_ematch
+{
+	struct tcf_ematch_ops * ops;
+	unsigned long		data;
+	unsigned int		datalen;
+	u16			matchid;
+	u16			flags;
+};
+
+static inline int tcf_em_is_container(struct tcf_ematch *em)
+{
+	return !em->ops;
+}
+
+static inline int tcf_em_is_simple(struct tcf_ematch *em)
+{
+	return em->flags & TCF_EM_SIMPLE;
+}
+
+static inline int tcf_em_is_inverted(struct tcf_ematch *em)
+{
+	return em->flags & TCF_EM_INVERT;
+}
+
+static inline int tcf_em_last_match(struct tcf_ematch *em)
+{
+	return (em->flags & TCF_EM_REL_MASK) == TCF_EM_REL_END;
+}
+
+static inline int tcf_em_early_end(struct tcf_ematch *em, int result)
+{
+	if (tcf_em_last_match(em))
+		return 1;
+
+	if (result == 0 && em->flags & TCF_EM_REL_AND)
+		return 1;
+
+	if (result != 0 && em->flags & TCF_EM_REL_OR)
+		return 1;
+
+	return 0;
+}
+	
+/**
+ * struct tcf_ematch_tree - ematch tree handle
+ *
+ * @hdr: ematch tree header supplied by userspace
+ * @matches: array of ematches
+ */
+struct tcf_ematch_tree
+{
+	struct tcf_ematch_tree_hdr hdr;
+	struct tcf_ematch *	matches;
+	
+};
+
+/**
+ * struct tcf_ematch_ops - ematch module operations
+ * 
+ * @kind: identifier (kind) of this ematch module
+ * @datalen: length of expected configuration data (optional)
+ * @change: called during validation (optional)
+ * @match: called during ematch tree evaluation, must return 1/0
+ * @destroy: called during destroyage (optional)
+ * @dump: called during dumping process (optional)
+ * @owner: owner, must be set to THIS_MODULE
+ * @link: link to previous/next ematch module (internal use)
+ */
+struct tcf_ematch_ops
+{
+	int			kind;
+	int			datalen;
+	int			(*change)(struct tcf_proto *, void *,
+					  int, struct tcf_ematch *);
+	int			(*match)(struct sk_buff *, struct tcf_ematch *,
+					 struct tcf_pkt_info *);
+	void			(*destroy)(struct tcf_proto *,
+					   struct tcf_ematch *);
+	int			(*dump)(struct sk_buff *, struct tcf_ematch *);
+	struct module		*owner;
+	struct list_head	link;
+};
+
+extern int tcf_em_register(struct tcf_ematch_ops *);
+extern int tcf_em_unregister(struct tcf_ematch_ops *);
+extern int tcf_em_tree_validate(struct tcf_proto *, struct rtattr *,
+				struct tcf_ematch_tree *);
+extern void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *);
+extern int tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int);
+extern int __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *,
+			       struct tcf_pkt_info *);
+
+/**
+ * tcf_em_tree_change - replace ematch tree of a running classifier
+ *
+ * @tp: classifier kind handle
+ * @dst: destination ematch tree variable
+ * @src: source ematch tree (temporary tree from tcf_em_tree_validate)
+ *
+ * This functions replaces the ematch tree in @dst with the ematch
+ * tree in @src. The classifier in charge of the ematch tree may be
+ * running.
+ */
+static inline void tcf_em_tree_change(struct tcf_proto *tp,
+				      struct tcf_ematch_tree *dst,
+				      struct tcf_ematch_tree *src)
+{
+	tcf_tree_lock(tp);
+	memcpy(dst, src, sizeof(*dst));
+	tcf_tree_unlock(tp);
+}
+
+/**
+ * tcf_em_tree_match - evaulate an ematch tree
+ *
+ * @skb: socket buffer of the packet in question
+ * @tree: ematch tree to be used for evaluation
+ * @info: packet information examined by classifier
+ *
+ * This function matches @skb against the ematch tree in @tree by going
+ * through all ematches respecting their logic relations returning
+ * as soon as the result is obvious.
+ *
+ * Returns 1 if the ematch tree as-one matches, no ematches are configured
+ * or ematch is not enabled in the kernel, otherwise 0 is returned.
+ */
+static inline int tcf_em_tree_match(struct sk_buff *skb,
+				    struct tcf_ematch_tree *tree,
+				    struct tcf_pkt_info *info)
+{
+	if (tree->hdr.nmatches)
+		return __tcf_em_tree_match(skb, tree, info);
+	else
+		return 1;
+}
+
+#else /* CONFIG_NET_EMATCH */
+
+struct tcf_ematch_tree
+{
+};
+
+#define tcf_em_tree_validate(tp, tb, t) ((void)(t), 0)
+#define tcf_em_tree_destroy(tp, t) do { (void)(t); } while(0)
+#define tcf_em_tree_dump(skb, t, tlv) (0)
+#define tcf_em_tree_change(tp, dst, src) do { } while(0)
+#define tcf_em_tree_match(skb, t, info) ((void)(info), 1)
+
+#endif /* CONFIG_NET_EMATCH */
+
+static inline unsigned char * tcf_get_base_ptr(struct sk_buff *skb, int layer)
+{
+	switch (layer) {
+		case TCF_LAYER_LINK:
+			return skb->data;
+		case TCF_LAYER_NETWORK:
+			return skb->nh.raw;
+		case TCF_LAYER_TRANSPORT:
+			return skb->h.raw;
+	}
+
+	return NULL;
+}
+
+static inline int tcf_valid_offset(struct sk_buff *skb, unsigned char *ptr,
+				   int len)
+{
+	return unlikely((ptr + len) < skb->tail && ptr > skb->head);
+}
+
 #ifdef CONFIG_NET_CLS_IND
 static inline int
 tcf_change_indev(struct tcf_proto *tp, char *indev, struct rtattr *indev_tlv)
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -140,7 +140,7 @@ psched_tod_diff(int delta_sec, int bound
 	if (bound <= 1000000 || delta_sec > (0x7FFFFFFF/1000000)-1)
 		return bound;
 	delta = delta_sec * 1000000;
-	if (delta > bound)
+	if (delta > bound || delta < 0)
 		delta = bound;
 	return delta;
 }
@@ -156,7 +156,9 @@ psched_tod_diff(int delta_sec, int bound
 		   __delta += 1000000; \
 	   case 1: \
 		   __delta += 1000000; \
-	   case 0: ; \
+	   case 0: \
+ 		   if (__delta > bound || __delta < 0) \
+ 			__delta = bound; \
 	   } \
 	   __delta; \
 })
diff --git a/include/net/rose.h b/include/net/rose.h
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -6,7 +6,9 @@
 
 #ifndef _ROSE_H
 #define _ROSE_H 
+
 #include <linux/rose.h>
+#include <net/sock.h>
 
 #define	ROSE_ADDR_LEN			5
 
@@ -114,7 +116,8 @@ struct rose_route {
 	unsigned int		rand;
 };
 
-typedef struct {
+struct rose_sock {
+	struct sock		sock;
 	rose_address		source_addr,   dest_addr;
 	ax25_address		source_call,   dest_call;
 	unsigned char		source_ndigis, dest_ndigis;
@@ -135,10 +138,9 @@ typedef struct {
 	struct rose_facilities_struct facilities;
 	struct timer_list	timer;
 	struct timer_list	idletimer;
-	struct sock		*sk;		/* Backlink to socket */
-} rose_cb;
+};
 
-#define rose_sk(__sk) ((rose_cb *)(__sk)->sk_protinfo)
+#define rose_sk(sk) ((struct rose_sock *)(sk))
 
 /* af_rose.c */
 extern ax25_address rose_callsign;
diff --git a/include/net/route.h b/include/net/route.h
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)route.h	1.0.4	05/27/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  * Fixes:
  *		Alan Cox	:	Reformatted. Added ip_rt_local()
@@ -44,8 +44,9 @@
 /* RTO_CONN is not used (being alias for 0), but preserved not to break
  * some modules referring to it. */
 
-#define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sk->sk_localroute)
+#define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))
 
+struct fib_nh;
 struct inet_peer;
 struct rtable
 {
@@ -58,7 +59,8 @@ struct rtable
 	struct in_device	*idev;
 	
 	unsigned		rt_flags;
-	unsigned		rt_type;
+	__u16			rt_type;
+	__u16			rt_multipath_alg;
 
 	__u32			rt_dst;	/* Path destination	*/
 	__u32			rt_src;	/* Path source		*/
diff --git a/include/net/scm.h b/include/net/scm.h
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -51,13 +51,13 @@ static __inline__ void scm_recv(struct s
 {
 	if (!msg->msg_control)
 	{
-		if (sock->passcred || scm->fp)
+		if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp)
 			msg->msg_flags |= MSG_CTRUNC;
 		scm_destroy(scm);
 		return;
 	}
 
-	if (sock->passcred)
+	if (test_bit(SOCK_PASSCRED, &sock->flags))
 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
 
 	if (!scm->fp)
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -407,32 +407,38 @@ sctp_vtag_verify(const struct sctp_chunk
 	return 0;
 }
 
-/* Check VTAG of the packet matches the sender's own tag OR its peer's
- * tag and the T bit is set in the Chunk Flags.
+/* Check VTAG of the packet matches the sender's own tag and the T bit is
+ * not set, OR its peer's tag and the T bit is set in the Chunk Flags.
  */
 static inline int
 sctp_vtag_verify_either(const struct sctp_chunk *chunk,
 			const struct sctp_association *asoc)
 {
-        /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2
+        /* RFC 2960 Section 8.5.1, sctpimpguide Section 2.41
 	 *
-	 * B) The receiver of a ABORT shall accept the packet if the
-	 * Verification Tag field of the packet matches its own tag OR it
-	 * is set to its peer's tag and the T bit is set in the Chunk
-	 * Flags. Otherwise, the receiver MUST silently discard the packet
-	 * and take no further action.
-	 *
-	 * (C) The receiver of a SHUTDOWN COMPLETE shall accept the
-	 * packet if the Verification Tag field of the packet
-	 * matches its own tag OR it is set to its peer's tag and
-	 * the T bit is set in the Chunk Flags.  Otherwise, the
-	 * receiver MUST silently discard the packet and take no
-	 * further action....
+	 * B) The receiver of a ABORT MUST accept the packet
+	 *    if the Verification Tag field of the packet matches its own tag
+	 *    and the T bit is not set
+	 *    OR
+	 *    it is set to its peer's tag and the T bit is set in the Chunk
+	 *    Flags.
+	 *    Otherwise, the receiver MUST silently discard the packet
+	 *    and take no further action.
 	 *
+	 * C) The receiver of a SHUTDOWN COMPLETE shall accept the packet
+	 *    if the Verification Tag field of the packet matches its own tag
+	 *    and the T bit is not set
+	 *    OR
+	 *    it is set to its peer's tag and the T bit is set in the Chunk
+	 *    Flags.
+	 *    Otherwise, the receiver MUST silently discard the packet
+	 *    and take no further action.  An endpoint MUST ignore the
+	 *    SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state.
 	 */
-        if ((ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag) ||
-	    (sctp_test_T_bit(chunk) && (ntohl(chunk->sctp_hdr->vtag)
-	    == asoc->c.peer_vtag))) {
+        if ((!sctp_test_T_bit(chunk) &&
+             (ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag)) ||
+	    (sctp_test_T_bit(chunk) &&
+	     (ntohl(chunk->sctp_hdr->vtag) == asoc->c.peer_vtag))) {
                 return 1;
 	}
 
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -154,6 +154,13 @@ extern struct sctp_globals {
 	int max_retrans_path;
 	int max_retrans_init;
 
+	/*
+	 * Policy for preforming sctp/socket accounting
+	 * 0   - do socket level accounting, all assocs share sk_sndbuf
+	 * 1   - do sctp accounting, each asoc may use sk_sndbuf bytes
+	 */
+	int sndbuf_policy;
+
 	/* HB.interval		    - 30 seconds  */
 	int hb_interval;
 
@@ -207,6 +214,7 @@ extern struct sctp_globals {
 #define sctp_valid_cookie_life		(sctp_globals.valid_cookie_life)
 #define sctp_cookie_preserve_enable	(sctp_globals.cookie_preserve_enable)
 #define sctp_max_retrans_association	(sctp_globals.max_retrans_association)
+#define sctp_sndbuf_policy	 	(sctp_globals.sndbuf_policy)
 #define sctp_max_retrans_path		(sctp_globals.max_retrans_path)
 #define sctp_max_retrans_init		(sctp_globals.max_retrans_init)
 #define sctp_hb_interval		(sctp_globals.hb_interval)
@@ -1212,7 +1220,8 @@ struct sctp_endpoint {
 	/* Default timeouts.  */
 	int timeouts[SCTP_NUM_TIMEOUT_TYPES];
 
-	/* Various thresholds.	*/
+	/* sendbuf acct. policy.	*/
+	__u32 sndbuf_policy;
 
 	/* Name for debugging output... */
 	char *debug_name;
diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h
--- a/include/net/slhc_vj.h
+++ b/include/net/slhc_vj.h
@@ -185,7 +185,4 @@ int slhc_remember __ARGS((struct slcompr
 			  int isize));
 int slhc_toss __ARGS((struct slcompress *comp));
 
-void slhc_i_status __ARGS((struct slcompress *comp));
-void slhc_o_status __ARGS((struct slcompress *comp));
-
 #endif	/* _SLHC_H */
diff --git a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)sock.h	1.0.4	05/13/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
  *		Florian La Roche <flla@stud.uni-sb.de>
@@ -61,10 +61,10 @@
  * the other protocols.
  */
 
-/* Define this to get the sk->sk_debug debugging facility. */
+/* Define this to get the SOCK_DBG debugging facility. */
 #define SOCK_DEBUGGING
 #ifdef SOCK_DEBUGGING
-#define SOCK_DEBUG(sk, msg...) do { if ((sk) && ((sk)->sk_debug)) \
+#define SOCK_DEBUG(sk, msg...) do { if ((sk) && sock_flag((sk), SOCK_DBG)) \
 					printk(KERN_DEBUG msg); } while (0)
 #else
 #define SOCK_DEBUG(sk, msg...) do { } while (0)
@@ -90,17 +90,17 @@ do {	spin_lock_init(&((__sk)->sk_lock.sl
 struct sock;
 
 /**
-  *	struct sock_common - minimal network layer representation of sockets
-  *	@skc_family - network address family
-  *	@skc_state - Connection state
-  *	@skc_reuse - %SO_REUSEADDR setting
-  *	@skc_bound_dev_if - bound device index if != 0
-  *	@skc_node - main hash linkage for various protocol lookup tables
-  *	@skc_bind_node - bind hash linkage for various protocol lookup tables
-  *	@skc_refcnt - reference count
-  *
-  *	This is the minimal network layer representation of sockets, the header
-  *	for struct sock and struct tcp_tw_bucket.
+ *	struct sock_common - minimal network layer representation of sockets
+ *	@skc_family: network address family
+ *	@skc_state: Connection state
+ *	@skc_reuse: %SO_REUSEADDR setting
+ *	@skc_bound_dev_if: bound device index if != 0
+ *	@skc_node: main hash linkage for various protocol lookup tables
+ *	@skc_bind_node: bind hash linkage for various protocol lookup tables
+ *	@skc_refcnt: reference count
+ *
+ *	This is the minimal network layer representation of sockets, the header
+ *	for struct sock and struct tcp_tw_bucket.
   */
 struct sock_common {
 	unsigned short		skc_family;
@@ -114,69 +114,62 @@ struct sock_common {
 
 /**
   *	struct sock - network layer representation of sockets
-  *	@__sk_common - shared layout with tcp_tw_bucket
-  *	@sk_zapped - ax25 & ipx means !linked
-  *	@sk_shutdown - mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
-  *	@sk_use_write_queue - wheter to call sk->sk_write_space in sock_wfree
-  *	@sk_userlocks - %SO_SNDBUF and %SO_RCVBUF settings
-  *	@sk_lock -	synchronizer
-  *	@sk_rcvbuf - size of receive buffer in bytes
-  *	@sk_sleep - sock wait queue
-  *	@sk_dst_cache - destination cache
-  *	@sk_dst_lock - destination cache lock
-  *	@sk_policy - flow policy
-  *	@sk_rmem_alloc - receive queue bytes committed
-  *	@sk_receive_queue - incoming packets
-  *	@sk_wmem_alloc - transmit queue bytes committed
-  *	@sk_write_queue - Packet sending queue
-  *	@sk_omem_alloc - "o" is "option" or "other"
-  *	@sk_wmem_queued - persistent queue size
-  *	@sk_forward_alloc - space allocated forward
-  *	@sk_allocation - allocation mode
-  *	@sk_sndbuf - size of send buffer in bytes
-  *	@sk_flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings
-  *	@sk_no_check - %SO_NO_CHECK setting, wether or not checkup packets
-  *	@sk_debug - %SO_DEBUG setting
-  *	@sk_rcvtstamp - %SO_TIMESTAMP setting
-  *	@sk_no_largesend - whether to sent large segments or not
-  *	@sk_route_caps - route capabilities (e.g. %NETIF_F_TSO)
-  *	@sk_lingertime - %SO_LINGER l_linger setting
-  *	@sk_hashent - hash entry in several tables (e.g. tcp_ehash)
-  *	@sk_backlog - always used with the per-socket spinlock held
-  *	@sk_callback_lock - used with the callbacks in the end of this struct
-  *	@sk_error_queue - rarely used
-  *	@sk_prot - protocol handlers inside a network family
-  *	@sk_err - last error
-  *	@sk_err_soft - errors that don't cause failure but are the cause of a persistent failure not just 'timed out'
-  *	@sk_ack_backlog - current listen backlog
-  *	@sk_max_ack_backlog - listen backlog set in listen()
-  *	@sk_priority - %SO_PRIORITY setting
-  *	@sk_type - socket type (%SOCK_STREAM, etc)
-  *	@sk_localroute - route locally only, %SO_DONTROUTE setting
-  *	@sk_protocol - which protocol this socket belongs in this network family
-  *	@sk_peercred - %SO_PEERCRED setting
-  *	@sk_rcvlowat - %SO_RCVLOWAT setting
-  *	@sk_rcvtimeo - %SO_RCVTIMEO setting
-  *	@sk_sndtimeo - %SO_SNDTIMEO setting
-  *	@sk_filter - socket filtering instructions
-  *	@sk_protinfo - private area, net family specific, when not using slab
-  *	@sk_slab - the slabcache this instance was allocated from
-  *	@sk_timer - sock cleanup timer
-  *	@sk_stamp - time stamp of last packet received
-  *	@sk_socket - Identd and reporting IO signals
-  *	@sk_user_data - RPC layer private data
-  *	@sk_owner - module that owns this socket
-  *	@sk_sndmsg_page - cached page for sendmsg
-  *	@sk_sndmsg_off - cached offset for sendmsg
-  *	@sk_send_head - front of stuff to transmit
-  *	@sk_write_pending - a write to stream socket waits to start
-  *	@sk_queue_shrunk - write queue has been shrunk recently
-  *	@sk_state_change - callback to indicate change in the state of the sock
-  *	@sk_data_ready - callback to indicate there is data to be processed
-  *	@sk_write_space - callback to indicate there is bf sending space available
-  *	@sk_error_report - callback to indicate errors (e.g. %MSG_ERRQUEUE)
-  *	@sk_backlog_rcv - callback to process the backlog
-  *	@sk_destruct - called at sock freeing time, i.e. when all refcnt == 0
+  *	@__sk_common: shared layout with tcp_tw_bucket
+  *	@sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
+  *	@sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings
+  *	@sk_lock:	synchronizer
+  *	@sk_rcvbuf: size of receive buffer in bytes
+  *	@sk_sleep: sock wait queue
+  *	@sk_dst_cache: destination cache
+  *	@sk_dst_lock: destination cache lock
+  *	@sk_policy: flow policy
+  *	@sk_rmem_alloc: receive queue bytes committed
+  *	@sk_receive_queue: incoming packets
+  *	@sk_wmem_alloc: transmit queue bytes committed
+  *	@sk_write_queue: Packet sending queue
+  *	@sk_omem_alloc: "o" is "option" or "other"
+  *	@sk_wmem_queued: persistent queue size
+  *	@sk_forward_alloc: space allocated forward
+  *	@sk_allocation: allocation mode
+  *	@sk_sndbuf: size of send buffer in bytes
+  *	@sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings
+  *	@sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
+  *	@sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
+  *	@sk_lingertime: %SO_LINGER l_linger setting
+  *	@sk_hashent: hash entry in several tables (e.g. tcp_ehash)
+  *	@sk_backlog: always used with the per-socket spinlock held
+  *	@sk_callback_lock: used with the callbacks in the end of this struct
+  *	@sk_error_queue: rarely used
+  *	@sk_prot: protocol handlers inside a network family
+  *	@sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, IPV6_ADDRFORM for instance)
+  *	@sk_err: last error
+  *	@sk_err_soft: errors that don't cause failure but are the cause of a persistent failure not just 'timed out'
+  *	@sk_ack_backlog: current listen backlog
+  *	@sk_max_ack_backlog: listen backlog set in listen()
+  *	@sk_priority: %SO_PRIORITY setting
+  *	@sk_type: socket type (%SOCK_STREAM, etc)
+  *	@sk_protocol: which protocol this socket belongs in this network family
+  *	@sk_peercred: %SO_PEERCRED setting
+  *	@sk_rcvlowat: %SO_RCVLOWAT setting
+  *	@sk_rcvtimeo: %SO_RCVTIMEO setting
+  *	@sk_sndtimeo: %SO_SNDTIMEO setting
+  *	@sk_filter: socket filtering instructions
+  *	@sk_protinfo: private area, net family specific, when not using slab
+  *	@sk_timer: sock cleanup timer
+  *	@sk_stamp: time stamp of last packet received
+  *	@sk_socket: Identd and reporting IO signals
+  *	@sk_user_data: RPC layer private data
+  *	@sk_sndmsg_page: cached page for sendmsg
+  *	@sk_sndmsg_off: cached offset for sendmsg
+  *	@sk_send_head: front of stuff to transmit
+  *	@sk_security: used by security modules
+  *	@sk_write_pending: a write to stream socket waits to start
+  *	@sk_state_change: callback to indicate change in the state of the sock
+  *	@sk_data_ready: callback to indicate there is data to be processed
+  *	@sk_write_space: callback to indicate there is bf sending space available
+  *	@sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE)
+  *	@sk_backlog_rcv: callback to process the backlog
+  *	@sk_destruct: called at sock freeing time, i.e. when all refcnt == 0
  */
 struct sock {
 	/*
@@ -191,33 +184,30 @@ struct sock {
 #define sk_node			__sk_common.skc_node
 #define sk_bind_node		__sk_common.skc_bind_node
 #define sk_refcnt		__sk_common.skc_refcnt
-	volatile unsigned char	sk_zapped;
-	unsigned char		sk_shutdown;
-	unsigned char		sk_use_write_queue;
-	unsigned char		sk_userlocks;
-	socket_lock_t		sk_lock;
+	unsigned char		sk_shutdown : 2,
+				sk_no_check : 2,
+				sk_userlocks : 4;
+	unsigned char		sk_protocol;
+	unsigned short		sk_type;
 	int			sk_rcvbuf;
+	socket_lock_t		sk_lock;
 	wait_queue_head_t	*sk_sleep;
 	struct dst_entry	*sk_dst_cache;
-	rwlock_t		sk_dst_lock;
 	struct xfrm_policy	*sk_policy[2];
+	rwlock_t		sk_dst_lock;
 	atomic_t		sk_rmem_alloc;
-	struct sk_buff_head	sk_receive_queue;
 	atomic_t		sk_wmem_alloc;
-	struct sk_buff_head	sk_write_queue;
 	atomic_t		sk_omem_alloc;
+	struct sk_buff_head	sk_receive_queue;
+	struct sk_buff_head	sk_write_queue;
 	int			sk_wmem_queued;
 	int			sk_forward_alloc;
 	unsigned int		sk_allocation;
 	int			sk_sndbuf;
-	unsigned long 		sk_flags;
-	char		 	sk_no_check;
-	unsigned char		sk_debug;
-	unsigned char		sk_rcvtstamp;
-	unsigned char		sk_no_largesend;
 	int			sk_route_caps;
-	unsigned long	        sk_lingertime;
 	int			sk_hashent;
+	unsigned long 		sk_flags;
+	unsigned long	        sk_lingertime;
 	/*
 	 * The backlog queue is special, it is always used with
 	 * the per-socket spinlock held and requires low latency
@@ -227,36 +217,30 @@ struct sock {
 		struct sk_buff *head;
 		struct sk_buff *tail;
 	} sk_backlog;
-	rwlock_t		sk_callback_lock;
 	struct sk_buff_head	sk_error_queue;
 	struct proto		*sk_prot;
+	struct proto		*sk_prot_creator;
+	rwlock_t		sk_callback_lock;
 	int			sk_err,
 				sk_err_soft;
 	unsigned short		sk_ack_backlog;
 	unsigned short		sk_max_ack_backlog;
 	__u32			sk_priority;
-	unsigned short		sk_type;
-	unsigned char		sk_localroute;
-	unsigned char		sk_protocol;
 	struct ucred		sk_peercred;
 	int			sk_rcvlowat;
 	long			sk_rcvtimeo;
 	long			sk_sndtimeo;
 	struct sk_filter      	*sk_filter;
 	void			*sk_protinfo;
-	kmem_cache_t		*sk_slab;
 	struct timer_list	sk_timer;
 	struct timeval		sk_stamp;
 	struct socket		*sk_socket;
 	void			*sk_user_data;
-	struct module		*sk_owner;
 	struct page		*sk_sndmsg_page;
-	__u32			sk_sndmsg_off;
 	struct sk_buff		*sk_send_head;
+	__u32			sk_sndmsg_off;
 	int			sk_write_pending;
 	void			*sk_security;
-	__u8			sk_queue_shrunk;
-	/* three bytes hole, try to pack */
 	void			(*sk_state_change)(struct sock *sk);
 	void			(*sk_data_ready)(struct sock *sk, int bytes);
 	void			(*sk_write_space)(struct sock *sk);
@@ -391,6 +375,13 @@ enum sock_flags {
 	SOCK_DESTROY,
 	SOCK_BROADCAST,
 	SOCK_TIMESTAMP,
+	SOCK_ZAPPED,
+	SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */
+	SOCK_DBG, /* %SO_DEBUG setting */
+	SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */
+	SOCK_NO_LARGESEND, /* whether to sent large segments or not */
+	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
+	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
 };
 
 static inline void sock_set_flag(struct sock *sk, enum sock_flags flag)
@@ -455,7 +446,7 @@ static inline void sk_stream_set_owner_r
 
 static inline void sk_stream_free_skb(struct sock *sk, struct sk_buff *skb)
 {
-	sk->sk_queue_shrunk   = 1;
+	sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
 	sk->sk_wmem_queued   -= skb->truesize;
 	sk->sk_forward_alloc += skb->truesize;
 	__kfree_skb(skb);
@@ -554,42 +545,22 @@ struct proto {
 	int			max_header;
 
 	kmem_cache_t		*slab;
-	int			slab_obj_size;
+	unsigned int		obj_size;
 
 	struct module		*owner;
 
 	char			name[32];
 
+	struct list_head	node;
+
 	struct {
 		int inuse;
 		u8  __pad[SMP_CACHE_BYTES - sizeof(int)];
 	} stats[NR_CPUS];
 };
 
-extern int sk_alloc_slab(struct proto *prot, char *name);
-extern void sk_free_slab(struct proto *prot);
-
-static inline void sk_alloc_slab_error(struct proto *proto)
-{
-	printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", proto->name);
-}
-
-static __inline__ void sk_set_owner(struct sock *sk, struct module *owner)
-{
-	/*
-	 * One should use sk_set_owner just once, after struct sock creation,
-	 * be it shortly after sk_alloc or after a function that returns a new
-	 * struct sock (and that down the call chain called sk_alloc), e.g. the
-	 * IPv4 and IPv6 modules share tcp_create_openreq_child, so if
-	 * tcp_create_openreq_child called sk_set_owner IPv6 would have to
-	 * change the ownership of this struct sock, with one not needed
-	 * transient sk_set_owner call.
-	 */
-	BUG_ON(sk->sk_owner != NULL);
-
-	sk->sk_owner = owner;
-	__module_get(owner);
-}
+extern int proto_register(struct proto *prot, int alloc_slab);
+extern void proto_unregister(struct proto *prot);
 
 /* Called with local bh disabled */
 static __inline__ void sock_prot_inc_use(struct proto *prot)
@@ -709,8 +680,8 @@ extern void FASTCALL(release_sock(struct
 #define bh_lock_sock(__sk)	spin_lock(&((__sk)->sk_lock.slock))
 #define bh_unlock_sock(__sk)	spin_unlock(&((__sk)->sk_lock.slock))
 
-extern struct sock *		sk_alloc(int family, int priority, int zero_it,
-					 kmem_cache_t *slab);
+extern struct sock		*sk_alloc(int family, int priority,
+					  struct proto *prot, int zero_it);
 extern void			sk_free(struct sock *sk);
 
 extern struct sk_buff		*sock_wmalloc(struct sock *sk,
@@ -983,6 +954,7 @@ __sk_dst_check(struct sock *sk, u32 cook
 
 	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
 		sk->sk_dst_cache = NULL;
+		dst_release(dst);
 		return NULL;
 	}
 
@@ -996,6 +968,7 @@ sk_dst_check(struct sock *sk, u32 cookie
 
 	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
 		sk_dst_reset(sk);
+		dst_release(dst);
 		return NULL;
 	}
 
@@ -1240,7 +1213,7 @@ static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
 	struct timeval *stamp = &skb->stamp;
-	if (sk->sk_rcvtstamp) { 
+	if (sock_flag(sk, SOCK_RCVTSTAMP)) {
 		/* Race occurred between timestamp enabling and packet
 		   receiving.  Fill in the current time for now. */
 		if (stamp->tv_sec == 0)
@@ -1253,8 +1226,8 @@ sock_recv_timestamp(struct msghdr *msg, 
 
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
- * @sk - socket to eat this skb from
- * @skb - socket buffer to eat
+ * @sk: socket to eat this skb from
+ * @skb: socket buffer to eat
  *
  * This routine must be called with interrupts disabled or with the socket
  * locked so that the sk_buff queue operation is ok.
diff --git a/include/net/tc_act/tc_defact.h b/include/net/tc_act/tc_defact.h
new file mode 100644
--- /dev/null
+++ b/include/net/tc_act/tc_defact.h
@@ -0,0 +1,13 @@
+#ifndef __NET_TC_DEF_H
+#define __NET_TC_DEF_H
+
+#include <net/act_api.h>
+
+struct tcf_defact
+{
+	tca_gen(defact);
+	u32     datalen;
+	void    *defdata;
+};
+
+#endif
diff --git a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)tcp.h	1.0.5	05/23/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
@@ -1039,6 +1039,7 @@ static inline void tcp_reset_xmit_timer(
 #ifdef TCP_DEBUG
 		printk(tcp_timer_bug_msg);
 #endif
+		return;
 	};
 }
 
@@ -1416,19 +1417,20 @@ tcp_nagle_check(const struct tcp_sock *t
 		  tcp_minshall_check(tp))));
 }
 
-extern void tcp_set_skb_tso_segs(struct sk_buff *, unsigned int);
+extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *);
 
 /* This checks if the data bearing packet SKB (usually sk->sk_send_head)
  * should be put on the wire right now.
  */
-static __inline__ int tcp_snd_test(const struct tcp_sock *tp, 
+static __inline__ int tcp_snd_test(struct sock *sk,
 				   struct sk_buff *skb,
 				   unsigned cur_mss, int nonagle)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	int pkts = tcp_skb_pcount(skb);
 
 	if (!pkts) {
-		tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
+		tcp_set_skb_tso_segs(sk, skb);
 		pkts = tcp_skb_pcount(skb);
 	}
 
@@ -1489,7 +1491,7 @@ static __inline__ void __tcp_push_pendin
 	if (skb) {
 		if (!tcp_skb_is_last(sk, skb))
 			nonagle = TCP_NAGLE_PUSH;
-		if (!tcp_snd_test(tp, skb, cur_mss, nonagle) ||
+		if (!tcp_snd_test(sk, skb, cur_mss, nonagle) ||
 		    tcp_write_xmit(sk, nonagle))
 			tcp_check_probe_timer(sk, tp);
 	}
@@ -1507,7 +1509,7 @@ static __inline__ int tcp_may_send_now(s
 	struct sk_buff *skb = sk->sk_send_head;
 
 	return (skb &&
-		tcp_snd_test(tp, skb, tcp_current_mss(sk, 1),
+		tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
 			     tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
 }
 
@@ -1914,7 +1916,7 @@ static inline void tcp_v4_setup_caps(str
 {
 	sk->sk_route_caps = dst->dev->features;
 	if (sk->sk_route_caps & NETIF_F_TSO) {
-		if (sk->sk_no_largesend || dst->header_len)
+		if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
 			sk->sk_route_caps &= ~NETIF_F_TSO;
 	}
 }
diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h
--- a/include/net/tcp_ecn.h
+++ b/include/net/tcp_ecn.h
@@ -33,7 +33,7 @@ static inline void TCP_ECN_send_syn(stru
 	if (sysctl_tcp_ecn && !(sk->sk_route_caps & NETIF_F_TSO)) {
 		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR;
 		tp->ecn_flags = TCP_ECN_OK;
-		sk->sk_no_largesend = 1;
+		sock_set_flag(sk, SOCK_NO_LARGESEND);
 	}
 }
 
diff --git a/include/net/udp.h b/include/net/udp.h
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)udp.h	1.0.2	05/07/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  * Fixes:
diff --git a/include/net/x25.h b/include/net/x25.h
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -10,6 +10,7 @@
 #ifndef _X25_H
 #define _X25_H 
 #include <linux/x25.h>
+#include <net/sock.h>
 
 #define	X25_ADDR_LEN			16
 
@@ -129,7 +130,8 @@ struct x25_neigh {
 	atomic_t		refcnt;
 };
 
-struct x25_opt {
+struct x25_sock {
+	struct sock		sk;
 	struct x25_address	source_addr, dest_addr;
 	struct x25_neigh	*neighbour;
 	unsigned int		lci;
@@ -141,7 +143,6 @@ struct x25_opt {
 	struct sk_buff_head	fragment_queue;
 	struct sk_buff_head	interrupt_in_queue;
 	struct sk_buff_head	interrupt_out_queue;
-	struct sock		*sk;		/* Backlink to socket */
 	struct timer_list	timer;
 	struct x25_causediag	causediag;
 	struct x25_facilities	facilities;
@@ -149,7 +150,10 @@ struct x25_opt {
 	unsigned long 		vc_facil_mask;	/* inc_call facilities mask */
 };
 
-#define x25_sk(__sk) ((struct x25_opt *)(__sk)->sk_protinfo)
+static inline struct x25_sock *x25_sk(const struct sock *sk)
+{
+	return (struct x25_sock *)sk;
+}
 
 /* af_x25.c */
 extern int  sysctl_x25_restart_request_timeout;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1,6 +1,7 @@
 #ifndef _NET_XFRM_H
 #define _NET_XFRM_H
 
+#include <linux/compiler.h>
 #include <linux/xfrm.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -212,7 +213,7 @@ struct xfrm_type
 	void			(*destructor)(struct xfrm_state *);
 	int			(*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
 	int			(*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
-	int			(*output)(struct sk_buff *pskb);
+	int			(*output)(struct xfrm_state *, struct sk_buff *pskb);
 	/* Estimate maximal size of result of transformation of a dgram */
 	u32			(*get_max_size)(struct xfrm_state *, int size);
 };
@@ -511,8 +512,22 @@ struct xfrm_dst
 		struct rtable		rt;
 		struct rt6_info		rt6;
 	} u;
+	struct dst_entry *route;
+	u32 route_mtu_cached;
+	u32 child_mtu_cached;
+	u32 route_cookie;
+	u32 path_cookie;
 };
 
+static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
+{
+	dst_release(xdst->route);
+	if (likely(xdst->u.dst.xfrm))
+		xfrm_state_put(xdst->u.dst.xfrm);
+}
+
+extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
+
 /* Decapsulation state, used by the input to store data during
  * decapsulation procedure, to be used later (during the policy
  * check
@@ -807,6 +822,7 @@ extern void xfrm_state_flush(u8 proto);
 extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
+extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
 extern int xfrm4_rcv(struct sk_buff *skb);
 extern int xfrm4_output(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
@@ -857,6 +873,8 @@ struct xfrm_state * xfrm_find_acq(u8 mod
 extern void xfrm_policy_flush(void);
 extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
 extern int xfrm_flush_bundles(void);
+extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family);
+extern void xfrm_init_pmtu(struct dst_entry *dst);
 
 extern wait_queue_head_t km_waitq;
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -169,6 +169,21 @@ struct pcmcia_device {
 		event_callback_args_t 	event_callback_args;
 	}			client;
 
+	/* information about this device */
+	u8			has_manf_id:1;
+	u8			has_card_id:1;
+	u8			has_func_id:1;
+	u8			reserved:5;
+
+	u8			func_id;
+	u16			manf_id;
+	u16			card_id;
+
+	char *			prod_id[4];
+
+	/* device driver wanted by cardmgr */
+	struct pcmcia_driver *	cardmgr;
+
 	struct device		dev;
 };
 
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -203,6 +203,17 @@ struct pcmcia_socket {
 	u_char				pci_irq;
 	struct pci_dev *		cb_dev;
 
+
+	/* socket setup is done so resources should be able to be allocated. Only
+	 * if set to 1, calls to find_{io,mem}_region are handled, and insertion
+	 * events are actually managed by the PCMCIA layer.*/
+	u8				resource_setup_done:1;
+
+	/* is set to one if resource setup is done using adjust_resource_info() */
+	u8				resource_setup_old:1;
+
+	u8				reserved:6;
+
 	/* socket operations */
 	struct pccard_operations *	ops;
 	struct pccard_resource_ops *	resource_ops;
@@ -248,7 +259,7 @@ extern void pcmcia_unregister_socket(str
 extern struct class pcmcia_socket_class;
 
 /* socket drivers are expected to use these callbacks in their .drv struct */
-extern int pcmcia_socket_dev_suspend(struct device *dev, u32 state);
+extern int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state);
 extern int pcmcia_socket_dev_resume(struct device *dev);
 
 #endif /* _LINUX_SS_H */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -169,8 +169,10 @@ static inline int scsi_status_is_good(in
 #define RESERVATION_CONFLICT 0x0c
 #define COMMAND_TERMINATED   0x11
 #define QUEUE_FULL           0x14
+#define ACA_ACTIVE           0x18
+#define TASK_ABORTED         0x20
 
-#define STATUS_MASK          0x3e
+#define STATUS_MASK          0xfe
 
 /*
  *  SENSE KEYS
@@ -293,6 +295,8 @@ struct scsi_lun {
 #define DID_PASSTHROUGH 0x0a	/* Force command past mid-layer            */
 #define DID_SOFT_ERROR  0x0b	/* The low level driver just wish a retry  */
 #define DID_IMM_RETRY   0x0c	/* Retry without decrementing retry count  */
+#define DID_REQUEUE	0x0d	/* Requeue command (no immediate retry) also
+				 * without decrementing the retry count	   */
 #define DRIVER_OK       0x00	/* Driver status                           */
 
 /*
@@ -348,7 +352,7 @@ struct scsi_lun {
  *      host_byte   = set by low-level driver to indicate status.
  *      driver_byte = set by mid-level.
  */
-#define status_byte(result) (((result) >> 1) & 0x1f)
+#define status_byte(result) (((result) >> 1) & 0x7f)
 #define msg_byte(result)    (((result) >> 8) & 0xff)
 #define host_byte(result)   (((result) >> 16) & 0xff)
 #define driver_byte(result) (((result) >> 24) & 0xff)
@@ -358,6 +362,15 @@ struct scsi_lun {
 #define sense_error(sense)  ((sense) & 0xf)
 #define sense_valid(sense)  ((sense) & 0x80);
 
+/*
+ * default timeouts
+*/
+#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT		(60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
+#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )
+
 
 #define IDENTIFY_BASE       0x80
 #define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -43,20 +43,17 @@ struct scsi_cmnd {
 	void (*done) (struct scsi_cmnd *);	/* Mid-level done function */
 
 	/*
-	 * A SCSI Command is assigned a nonzero serial_number when internal_cmnd
-	 * passes it to the driver's queue command function.  The serial_number
-	 * is cleared when scsi_done is entered indicating that the command has
-	 * been completed.  If a timeout occurs, the serial number at the moment
-	 * of timeout is copied into serial_number_at_timeout.  By subsequently
-	 * comparing the serial_number and serial_number_at_timeout fields
-	 * during abort or reset processing, we can detect whether the command
-	 * has already completed.  This also detects cases where the command has
-	 * completed and the SCSI Command structure has already being reused
-	 * for another command, so that we can avoid incorrectly aborting or
-	 * resetting the new command.
+	 * A SCSI Command is assigned a nonzero serial_number before passed
+	 * to the driver's queue command function.  The serial_number is
+	 * cleared when scsi_done is entered indicating that the command
+	 * has been completed.  It currently doesn't have much use other
+	 * than printk's.  Some lldd's use this number for other purposes.
+	 * It's almost certain that such usages are either incorrect or
+	 * meaningless.  Please kill all usages other than printk's.  Also,
+	 * as this number is always identical to ->pid, please convert
+	 * printk's to use ->pid, so that we can kill this field.
 	 */
 	unsigned long serial_number;
-	unsigned long serial_number_at_timeout;
 
 	int retries;
 	int allowed;
@@ -64,12 +61,6 @@ struct scsi_cmnd {
 	int timeout_total;
 	int timeout;
 
-	/*
-	 * We handle the timeout differently if it happens when a reset, 
-	 * abort, etc are in process. 
-	 */
-	unsigned volatile char internal_timeout;
-
 	unsigned char cmd_len;
 	unsigned char old_cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -139,7 +130,7 @@ struct scsi_cmnd {
 	int result;		/* Status code from lower level driver */
 
 	unsigned char tag;	/* SCSI-II queued command tag */
-	unsigned long pid;	/* Process ID, starts at 0 */
+	unsigned long pid;	/* Process ID, starts at 0. Unique per host. */
 };
 
 /*
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -43,8 +43,9 @@ struct scsi_device {
 	struct list_head    siblings;   /* list of all devices on this host */
 	struct list_head    same_target_siblings; /* just the devices sharing same target id */
 
-	volatile unsigned short device_busy;	/* commands actually active on low-level */
-	spinlock_t sdev_lock;           /* also the request queue_lock */
+	/* this is now protected by the request_queue->queue_lock */
+	unsigned int device_busy;	/* commands actually active on
+					 * low-level. protected by queue_lock. */
 	spinlock_t list_lock;
 	struct list_head cmd_list;	/* queue of in use SCSI Command structures */
 	struct list_head starved_entry;
@@ -112,12 +113,17 @@ struct scsi_device {
 	unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
 	unsigned select_no_atn:1;
 	unsigned fix_capacity:1;	/* READ_CAPACITY is too high by 1 */
+	unsigned retry_hwerror:1;	/* Retry HARDWARE_ERROR */
 
 	unsigned int device_blocked;	/* Device returned QUEUE_FULL. */
 
 	unsigned int max_device_blocked; /* what device_blocked counts down from  */
 #define SCSI_DEFAULT_DEVICE_BLOCKED	3
 
+	atomic_t iorequest_cnt;
+	atomic_t iodone_cnt;
+	atomic_t ioerr_cnt;
+
 	int timeout;
 
 	struct device		sdev_gendev;
@@ -140,7 +146,10 @@ struct scsi_device {
  */
 struct scsi_target {
 	struct scsi_device	*starget_sdev_user;
+	struct list_head	siblings;
+	struct list_head	devices;
 	struct device		dev;
+	unsigned int		reap_ref; /* protected by the host lock */
 	unsigned int		channel;
 	unsigned int		id; /* target id ... replace
 				     * scsi_device.id eventually */
@@ -169,6 +178,10 @@ extern struct scsi_device *scsi_device_l
 					      uint, uint, uint);
 extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
 						uint, uint, uint);
+extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
+							uint);
+extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
+							  uint);
 extern void starget_for_each_device(struct scsi_target *, void *,
 		     void (*fn)(struct scsi_device *, void *));
 
@@ -222,6 +235,12 @@ extern int scsi_device_quiesce(struct sc
 extern void scsi_device_resume(struct scsi_device *sdev);
 extern void scsi_target_quiesce(struct scsi_target *);
 extern void scsi_target_resume(struct scsi_target *);
+extern void scsi_scan_target(struct device *parent, unsigned int channel,
+			     unsigned int id, unsigned int lun, int rescan);
+extern void scsi_target_reap(struct scsi_target *);
+extern void scsi_target_block(struct device *);
+extern void scsi_target_unblock(struct device *);
+extern void scsi_remove_target(struct device *);
 extern const char *scsi_device_state_name(enum scsi_device_state);
 extern int scsi_is_sdev_device(const struct device *);
 extern int scsi_is_target_device(const struct device *);
diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h
--- a/include/scsi/scsi_devinfo.h
+++ b/include/scsi/scsi_devinfo.h
@@ -27,4 +27,5 @@
 #define BLIST_NOT_LOCKABLE	0x80000	/* don't use PREVENT-ALLOW commands */
 #define BLIST_NO_ULD_ATTACH	0x100000 /* device is actually for RAID config */
 #define BLIST_SELECT_NO_ATN	0x200000 /* select without ATN */
+#define BLIST_RETRY_HWERROR	0x400000 /* retry HARDWARE_ERROR */
 #endif
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -14,6 +14,8 @@ struct scsi_driver {
 	int (*init_command)(struct scsi_cmnd *);
 	void (*rescan)(struct device *);
 	int (*issue_flush)(struct device *, sector_t *);
+	int (*prepare_flush)(struct request_queue *, struct request *);
+	void (*end_flush)(struct request_queue *, struct request *);
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 struct block_device;
 struct module;
@@ -363,6 +364,12 @@ struct scsi_host_template {
 	unsigned skip_settle_delay:1;
 
 	/*
+	 * ordered write support
+	 */
+	unsigned ordered_flush:1;
+	unsigned ordered_tag:1;
+
+	/*
 	 * Countdown for host blocking with no commands outstanding
 	 */
 	unsigned int max_host_blocked;
@@ -416,6 +423,7 @@ struct Scsi_Host {
 	 * access this list directly from a driver.
 	 */
 	struct list_head	__devices;
+	struct list_head	__targets;
 	
 	struct scsi_host_cmd_pool *cmd_pool;
 	spinlock_t		free_list_lock;
@@ -440,8 +448,14 @@ struct Scsi_Host {
 	wait_queue_head_t       host_wait;
 	struct scsi_host_template *hostt;
 	struct scsi_transport_template *transportt;
-	volatile unsigned short host_busy;   /* commands actually active on low-level */
-	volatile unsigned short host_failed; /* commands that failed. */
+
+	/*
+	 * The following two fields are protected with host_lock;
+	 * however, eh routines can safely access during eh processing
+	 * without acquiring the lock.
+	 */
+	unsigned int host_busy;		   /* commands actually active on low-level */
+	unsigned int host_failed;	   /* commands that failed. */
     
 	unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
 	int resetting; /* if set, it means that last_reset is a valid value */
@@ -483,7 +497,12 @@ struct Scsi_Host {
 	short unsigned int sg_tablesize;
 	short unsigned int max_sectors;
 	unsigned long dma_boundary;
-
+	/* 
+	 * Used to assign serial numbers to the cmds.
+	 * Protected by the host lock.
+	 */
+	unsigned long cmd_serial_number, cmd_pid; 
+	
 	unsigned unchecked_isa_dma:1;
 	unsigned use_clustering:1;
 	unsigned use_blk_tcq:1;
@@ -502,6 +521,18 @@ struct Scsi_Host {
 	unsigned reverse_ordering:1;
 
 	/*
+	 * ordered write support
+	 */
+	unsigned ordered_flush:1;
+	unsigned ordered_tag:1;
+
+	/*
+	 * Optional work queue to be utilized by the transport
+	 */
+	char work_q_name[KOBJ_NAME_LEN];
+	struct workqueue_struct *work_q;
+
+	/*
 	 * Host has rejected a command because it was busy.
 	 */
 	unsigned int host_blocked;
@@ -548,11 +579,24 @@ struct Scsi_Host {
 	unsigned long hostdata[0]  /* Used for storage of host specific stuff */
 		__attribute__ ((aligned (sizeof(unsigned long))));
 };
-#define		dev_to_shost(d)		\
-	container_of(d, struct Scsi_Host, shost_gendev)
+
 #define		class_to_shost(d)	\
 	container_of(d, struct Scsi_Host, shost_classdev)
 
+int scsi_is_host_device(const struct device *);
+
+static inline struct Scsi_Host *dev_to_shost(struct device *dev)
+{
+	while (!scsi_is_host_device(dev)) {
+		if (!dev->parent)
+			return NULL;
+		dev = dev->parent;
+	}
+	return container_of(dev, struct Scsi_Host, shost_gendev);
+}
+
+extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
+extern void scsi_flush_work(struct Scsi_Host *);
 
 extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
 extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
@@ -596,8 +640,6 @@ struct class_container;
  */
 extern void scsi_free_host_dev(struct scsi_device *);
 extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
-int scsi_is_host_device(const struct device *);
-
 
 /* legacy interfaces */
 extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -23,13 +23,10 @@
 #include <linux/transport_class.h>
 
 struct scsi_transport_template {
-	/* The statistics attached to the host class only */
-	struct attribute_group *host_statistics;
-
 	/* the attribute containers */
-	struct attribute_container host_attrs;
-	struct attribute_container target_attrs;
-	struct attribute_container device_attrs;
+	struct transport_container host_attrs;
+	struct transport_container target_attrs;
+	struct transport_container device_attrs;
 
 	/* The size of the specific transport attribute structure (a
 	 * space of this size will be left at the end of the
@@ -37,6 +34,11 @@ struct scsi_transport_template {
 	int	device_size;
 	int	target_size;
 	int	host_size;
+
+	/*
+	 * True if the transport wants to use a host-based work-queue
+	 */
+	unsigned int create_work_queue : 1;
 };
 
 #define transport_class_to_shost(tc) \
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -16,6 +16,13 @@
  *  You 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) 2004-2005   James Smart, Emulex Corporation
+ *    Rewrite for host, target, device, and remote port attributes,
+ *    statistics, and service functions...
+ *
  */
 #ifndef SCSI_TRANSPORT_FC_H
 #define SCSI_TRANSPORT_FC_H
@@ -61,8 +68,10 @@ enum fc_port_type {
  */
 enum fc_port_state {
 	FC_PORTSTATE_UNKNOWN,
+	FC_PORTSTATE_NOTPRESENT,
 	FC_PORTSTATE_ONLINE,
 	FC_PORTSTATE_OFFLINE,		/* User has taken Port Offline */
+	FC_PORTSTATE_BLOCKED,
 	FC_PORTSTATE_BYPASSED,
 	FC_PORTSTATE_DIAGNOSTICS,
 	FC_PORTSTATE_LINKDOWN,
@@ -103,35 +112,134 @@ enum fc_port_state {
  * scsi_transport_fc.c (for the ascii descriptions).
  */
 enum fc_tgtid_binding_type  {
+	FC_TGTID_BIND_NONE,
 	FC_TGTID_BIND_BY_WWPN,
 	FC_TGTID_BIND_BY_WWNN,
 	FC_TGTID_BIND_BY_ID,
 };
 
+/*
+ * FC Remote Port Roles
+ * Note: values are not enumerated, as they can be "or'd" together
+ * for reporting (e.g. report roles). If you alter this list,
+ * you also need to alter scsi_transport_fc.c (for the ascii descriptions).
+ */
+#define FC_RPORT_ROLE_UNKNOWN			0x00
+#define FC_RPORT_ROLE_FCP_TARGET		0x01
+#define FC_RPORT_ROLE_FCP_INITIATOR		0x02
+#define FC_RPORT_ROLE_IP_PORT			0x04
+
+
+/*
+ * fc_rport_identifiers: This set of data contains all elements
+ * to uniquely identify a remote FC port. The driver uses this data
+ * to report the existence of a remote FC port in the topology. Internally,
+ * the transport uses this data for attributes and to manage consistent
+ * target id bindings.
+ */
+struct fc_rport_identifiers {
+	u64 node_name;
+	u64 port_name;
+	u32 port_id;
+	u32 roles;
+};
+
+/* Macro for use in defining Remote Port attributes */
+#define FC_RPORT_ATTR(_name,_mode,_show,_store)				\
+struct class_device_attribute class_device_attr_rport_##_name = 	\
+	__ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * FC Remote Port Attributes
+ *
+ * This structure exists for each remote FC port that a LLDD notifies
+ * the subsystem of.  A remote FC port may or may not be a SCSI Target,
+ * also be a SCSI initiator, IP endpoint, etc. As such, the remote
+ * port is considered a separate entity, independent of "role" (such
+ * as scsi target).
+ *
+ * --
+ *
+ * Attributes are based on HBAAPI V2.0 definitions. Only those
+ * attributes that are determinable by the local port (aka Host)
+ * are contained.
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after successfully calling
+ * fc_remote_port_add(). The transport fully manages all get functions
+ * w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+
+struct fc_rport {	/* aka fc_starget_attrs */
+	/* Fixed Attributes */
+	u32 maxframe_size;
+	u32 supported_classes;
+
+	/* Dynamic Attributes */
+	u32 dev_loss_tmo;	/* Remote Port loss timeout in seconds. */
+
+	/* Private (Transport-managed) Attributes */
+	u64 node_name;
+	u64 port_name;
+	u32 port_id;
+	u32 roles;
+	enum fc_port_state port_state;	/* Will only be ONLINE or UNKNOWN */
+	u32 scsi_target_id;
 
+	/* exported data */
+	void *dd_data;			/* Used for driver-specific storage */
+
+	/* internal data */
+	unsigned int channel;
+	u32 number;
+	struct list_head peers;
+	struct device dev;
+ 	struct work_struct dev_loss_work;
+ 	struct work_struct scan_work;
+} __attribute__((aligned(sizeof(unsigned long))));
+
+#define	dev_to_rport(d)				\
+	container_of(d, struct fc_rport, dev)
+#define transport_class_to_rport(classdev)	\
+	dev_to_rport(classdev->dev)
+#define rport_to_shost(r)			\
+	dev_to_shost(r->dev.parent)
 
 /*
- * FC Remote Port (Target) Attributes
+ * FC SCSI Target Attributes
+ *
+ * The SCSI Target is considered an extention of a remote port (as
+ * a remote port can be more than a SCSI Target). Within the scsi
+ * subsystem, we leave the Target as a separate entity. Doing so
+ * provides backward compatibility with prior FC transport api's,
+ * and lets remote ports be handled entirely within the FC transport
+ * and independently from the scsi subsystem. The drawback is that
+ * some data will be duplicated.
  */
 
 struct fc_starget_attrs {	/* aka fc_target_attrs */
-	int port_id;
+	/* Dynamic Attributes */
 	u64 node_name;
 	u64 port_name;
-	u32 dev_loss_tmo;	/* Remote Port loss timeout in seconds. */
-	struct work_struct dev_loss_work;
+	u32 port_id;
 };
 
-#define fc_starget_port_id(x) \
-	(((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
 #define fc_starget_node_name(x) \
 	(((struct fc_starget_attrs *)&(x)->starget_data)->node_name)
 #define fc_starget_port_name(x)	\
 	(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
-#define fc_starget_dev_loss_tmo(x) \
-	(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo)
-#define fc_starget_dev_loss_work(x) \
-	(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_work)
+#define fc_starget_port_id(x) \
+	(((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
+
+#define starget_to_rport(s)			\
+	scsi_is_fc_rport(s->dev.parent) ? dev_to_rport(s->dev.parent) : NULL
 
 
 /*
@@ -197,11 +305,7 @@ struct fc_host_attrs {
 	char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
 	u32 supported_speeds;
 	u32 maxframe_size;
-	char hardware_version[FC_VERSION_STRING_SIZE];
-	char firmware_version[FC_VERSION_STRING_SIZE];
 	char serial_number[FC_SERIAL_NUMBER_SIZE];
-	char opt_rom_version[FC_VERSION_STRING_SIZE];
-	char driver_version[FC_VERSION_STRING_SIZE];
 
 	/* Dynamic Attributes */
 	u32 port_id;
@@ -210,13 +314,15 @@ struct fc_host_attrs {
 	u8  active_fc4s[FC_FC4_LIST_SIZE];
 	u32 speed;
 	u64 fabric_name;
-	u32 link_down_tmo;	/* Link Down timeout in seconds. */
 
 	/* Private (Transport-managed) Attributes */
 	enum fc_tgtid_binding_type  tgtid_bind_type;
 
 	/* internal data */
-	struct work_struct link_down_work;
+	struct list_head rports;
+	struct list_head rport_bindings;
+	u32 next_rport_number;
+	u32 next_target_id;
 };
 
 #define fc_host_node_name(x) \
@@ -233,16 +339,8 @@ struct fc_host_attrs {
 	(((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
 #define fc_host_maxframe_size(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
-#define fc_host_hardware_version(x)	\
-	(((struct fc_host_attrs *)(x)->shost_data)->hardware_version)
-#define fc_host_firmware_version(x)	\
-	(((struct fc_host_attrs *)(x)->shost_data)->firmware_version)
 #define fc_host_serial_number(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
-#define fc_host_opt_rom_version(x)	\
-	(((struct fc_host_attrs *)(x)->shost_data)->opt_rom_version)
-#define fc_host_driver_version(x)	\
-	(((struct fc_host_attrs *)(x)->shost_data)->driver_version)
 #define fc_host_port_id(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->port_id)
 #define fc_host_port_type(x)	\
@@ -255,21 +353,26 @@ struct fc_host_attrs {
 	(((struct fc_host_attrs *)(x)->shost_data)->speed)
 #define fc_host_fabric_name(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->fabric_name)
-#define fc_host_link_down_tmo(x) \
-	(((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo)
 #define fc_host_tgtid_bind_type(x) \
 	(((struct fc_host_attrs *)(x)->shost_data)->tgtid_bind_type)
-#define fc_host_link_down_work(x) \
-	(((struct fc_host_attrs *)(x)->shost_data)->link_down_work)
+#define fc_host_rports(x) \
+	(((struct fc_host_attrs *)(x)->shost_data)->rports)
+#define fc_host_rport_bindings(x) \
+	(((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
+#define fc_host_next_rport_number(x) \
+	(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
+#define fc_host_next_target_id(x) \
+	(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
 
 
 /* The functions by which the transport class and the driver communicate */
 struct fc_function_template {
-	void 	(*get_starget_port_id)(struct scsi_target *);
+	void    (*get_rport_dev_loss_tmo)(struct fc_rport *);
+	void	(*set_rport_dev_loss_tmo)(struct fc_rport *, u32);
+
 	void	(*get_starget_node_name)(struct scsi_target *);
 	void	(*get_starget_port_name)(struct scsi_target *);
-	void    (*get_starget_dev_loss_tmo)(struct scsi_target *);
-	void	(*set_starget_dev_loss_tmo)(struct scsi_target *, u32);
+	void 	(*get_starget_port_id)(struct scsi_target *);
 
 	void 	(*get_host_port_id)(struct Scsi_Host *);
 	void	(*get_host_port_type)(struct Scsi_Host *);
@@ -277,22 +380,33 @@ struct fc_function_template {
 	void	(*get_host_active_fc4s)(struct Scsi_Host *);
 	void	(*get_host_speed)(struct Scsi_Host *);
 	void	(*get_host_fabric_name)(struct Scsi_Host *);
-	void    (*get_host_link_down_tmo)(struct Scsi_Host *);
-	void	(*set_host_link_down_tmo)(struct Scsi_Host *, u32);
 
 	struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
 	void	(*reset_fc_host_stats)(struct Scsi_Host *);
 
+	/* allocation lengths for host-specific data */
+	u32	 			dd_fcrport_size;
+
 	/* 
 	 * The driver sets these to tell the transport class it
 	 * wants the attributes displayed in sysfs.  If the show_ flag
 	 * is not set, the attribute will be private to the transport
 	 * class 
 	 */
-	unsigned long	show_starget_port_id:1;
+
+	/* remote port fixed attributes */
+	unsigned long	show_rport_maxframe_size:1;
+	unsigned long	show_rport_supported_classes:1;
+	unsigned long   show_rport_dev_loss_tmo:1;
+
+	/*
+	 * target dynamic attributes
+	 * These should all be "1" if the driver uses the remote port
+	 * add/delete functions (so attributes reflect rport values).
+	 */
 	unsigned long	show_starget_node_name:1;
 	unsigned long	show_starget_port_name:1;
-	unsigned long   show_starget_dev_loss_tmo:1;
+	unsigned long	show_starget_port_id:1;
 
 	/* host fixed attributes */
 	unsigned long	show_host_node_name:1;
@@ -302,11 +416,7 @@ struct fc_function_template {
 	unsigned long	show_host_symbolic_name:1;
 	unsigned long	show_host_supported_speeds:1;
 	unsigned long	show_host_maxframe_size:1;
-	unsigned long	show_host_hardware_version:1;
-	unsigned long	show_host_firmware_version:1;
 	unsigned long	show_host_serial_number:1;
-	unsigned long	show_host_opt_rom_version:1;
-	unsigned long	show_host_driver_version:1;
 	/* host dynamic attributes */
 	unsigned long	show_host_port_id:1;
 	unsigned long	show_host_port_type:1;
@@ -314,15 +424,19 @@ struct fc_function_template {
 	unsigned long	show_host_active_fc4s:1;
 	unsigned long	show_host_speed:1;
 	unsigned long	show_host_fabric_name:1;
-	unsigned long   show_host_link_down_tmo:1;
 };
 
 
-struct scsi_transport_template *fc_attach_transport(struct fc_function_template *);
+struct scsi_transport_template *fc_attach_transport(
+			struct fc_function_template *);
 void fc_release_transport(struct scsi_transport_template *);
-int fc_target_block(struct scsi_target *starget);
-void fc_target_unblock(struct scsi_target *starget);
-int fc_host_block(struct Scsi_Host *shost);
-void fc_host_unblock(struct Scsi_Host *shost);
+void fc_remove_host(struct Scsi_Host *);
+struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost,
+			int channel, struct fc_rport_identifiers  *ids);
+void fc_remote_port_delete(struct fc_rport  *rport);
+void fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles);
+int fc_remote_port_block(struct fc_rport *rport);
+void fc_remote_port_unblock(struct fc_rport *rport);
+int scsi_is_fc_rport(const struct device *);
 
 #endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
--- a/include/scsi/scsi_transport_spi.h
+++ b/include/scsi/scsi_transport_spi.h
@@ -27,8 +27,11 @@ struct scsi_transport_template;
 
 struct spi_transport_attrs {
 	int period;		/* value in the PPR/SDTR command */
+	int min_period;
 	int offset;
+	int max_offset;
 	unsigned int width:1;	/* 0 - narrow, 1 - wide */
+	unsigned int max_width:1;
 	unsigned int iu:1;	/* Information Units enabled */
 	unsigned int dt:1;	/* DT clocking enabled */
 	unsigned int qas:1;	/* Quick Arbitration and Selection enabled */
@@ -63,8 +66,11 @@ struct spi_host_attrs {
 
 /* accessor functions */
 #define spi_period(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->period)
+#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period)
 #define spi_offset(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->offset)
+#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset)
 #define spi_width(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->width)
+#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width)
 #define spi_iu(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->iu)
 #define spi_dt(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->dt)
 #define spi_qas(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->qas)
@@ -130,5 +136,6 @@ struct scsi_transport_template *spi_atta
 void spi_release_transport(struct scsi_transport_template *);
 void spi_schedule_dv_device(struct scsi_device *);
 void spi_dv_device(struct scsi_device *);
+void spi_display_xfer_agreement(struct scsi_target *);
 
 #endif /* SCSI_TRANSPORT_SPI_H */
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -356,6 +356,7 @@
 #define AC97_SCAP_INDEP_SDIN	(1<<6)	/* independent SDIN */
 #define AC97_SCAP_INV_EAPD	(1<<7)	/* inverted EAPD */
 #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
+#define AC97_SCAP_NO_SPDIF	(1<<9)	/* don't build SPDIF controls */
 
 /* ac97->flags */
 #define AC97_HAS_PC_BEEP	(1<<0)	/* force PC Speaker usage */
@@ -366,6 +367,13 @@
 #define AC97_DOUBLE_RATE	(1<<5)	/* supports double rate playback */
 #define AC97_HAS_NO_MASTER_VOL	(1<<6)	/* no Master volume */
 #define AC97_HAS_NO_PCM_VOL	(1<<7)	/* no PCM volume */
+#define AC97_DEFAULT_POWER_OFF	(1<<8)	/* no RESET write */
+#define AC97_MODEM_PATCH	(1<<9)	/* modem patch */
+#define AC97_HAS_NO_REC_GAIN	(1<<10) /* no Record gain */
+#define AC97_HAS_NO_PHONE	(1<<11) /* no PHONE volume */
+#define AC97_HAS_NO_PC_BEEP	(1<<12) /* no PC Beep volume */
+#define AC97_HAS_NO_VIDEO	(1<<13) /* no Video volume */
+#define AC97_HAS_NO_CD		(1<<14) /* no CD volume */
 
 /* rates indexes */
 #define AC97_RATES_FRONT_DAC	0
@@ -580,4 +588,11 @@ int snd_ac97_pcm_open(struct ac97_pcm *p
 int snd_ac97_pcm_close(struct ac97_pcm *pcm);
 int snd_ac97_pcm_double_rate_rules(snd_pcm_runtime_t *runtime);
 
+struct ac97_enum {
+	unsigned char reg;
+	unsigned char shift_l;
+	unsigned char shift_r;
+	unsigned short mask;
+	const char **texts;
+};
 #endif /* __SOUND_AC97_CODEC_H */
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
new file mode 100644
--- /dev/null
+++ b/include/sound/ak4114.h
@@ -0,0 +1,205 @@
+#ifndef __SOUND_AK4114_H
+#define __SOUND_AK4114_H
+
+/*
+ *  Routines for Asahi Kasei AK4114
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *
+ *
+ *   This program is free software; you can redistribute it 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
+ *
+ */
+
+/* AK4114 registers */
+#define AK4114_REG_PWRDN	0x00	/* power down */
+#define AK4114_REG_FORMAT	0x01	/* format control */
+#define AK4114_REG_IO0		0x02	/* input/output control */
+#define AK4114_REG_IO1		0x03	/* input/output control */
+#define AK4114_REG_INT0_MASK	0x04	/* interrupt0 mask */
+#define AK4114_REG_INT1_MASK	0x05	/* interrupt1 mask */
+#define AK4114_REG_RCS0		0x06	/* receiver status 0 */
+#define AK4114_REG_RCS1		0x07	/* receiver status 1 */
+#define AK4114_REG_RXCSB0	0x08	/* RX channel status byte 0 */
+#define AK4114_REG_RXCSB1	0x09	/* RX channel status byte 1 */
+#define AK4114_REG_RXCSB2	0x0a	/* RX channel status byte 2 */
+#define AK4114_REG_RXCSB3	0x0b	/* RX channel status byte 3 */
+#define AK4114_REG_RXCSB4	0x0c	/* RX channel status byte 4 */
+#define AK4114_REG_TXCSB0	0x0d	/* TX channel status byte 0 */
+#define AK4114_REG_TXCSB1	0x0e	/* TX channel status byte 1 */
+#define AK4114_REG_TXCSB2	0x0f	/* TX channel status byte 2 */
+#define AK4114_REG_TXCSB3	0x10	/* TX channel status byte 3 */
+#define AK4114_REG_TXCSB4	0x11	/* TX channel status byte 4 */
+#define AK4114_REG_Pc0		0x12	/* burst preamble Pc byte 0 */
+#define AK4114_REG_Pc1		0x13	/* burst preamble Pc byte 1 */
+#define AK4114_REG_Pd0		0x14	/* burst preamble Pd byte 0 */
+#define AK4114_REG_Pd1		0x15	/* burst preamble Pd byte 1 */
+#define AK4114_REG_QSUB_ADDR	0x16	/* Q-subcode address + control */
+#define AK4114_REG_QSUB_TRACK	0x17	/* Q-subcode track */
+#define AK4114_REG_QSUB_INDEX	0x18	/* Q-subcode index */
+#define AK4114_REG_QSUB_MINUTE	0x19	/* Q-subcode minute */
+#define AK4114_REG_QSUB_SECOND	0x1a	/* Q-subcode second */
+#define AK4114_REG_QSUB_FRAME	0x1b	/* Q-subcode frame */
+#define AK4114_REG_QSUB_ZERO	0x1c	/* Q-subcode zero */
+#define AK4114_REG_QSUB_ABSMIN	0x1d	/* Q-subcode absolute minute */
+#define AK4114_REG_QSUB_ABSSEC	0x1e	/* Q-subcode absolute second */
+#define AK4114_REG_QSUB_ABSFRM	0x1f	/* Q-subcode absolute frame */
+
+/* sizes */
+#define AK4114_REG_RXCSB_SIZE	((AK4114_REG_RXCSB4-AK4114_REG_RXCSB0)+1)
+#define AK4114_REG_TXCSB_SIZE	((AK4114_REG_TXCSB4-AK4114_REG_TXCSB0)+1)
+#define AK4114_REG_QSUB_SIZE	((AK4114_REG_QSUB_ABSFRM-AK4114_REG_QSUB_ADDR)+1)
+
+/* AK4117_REG_PWRDN bits */
+#define AK4114_CS12		(1<<7)	/* Channel Status Select */
+#define AK4114_BCU		(1<<6)	/* Block Start & C/U Output Mode */
+#define AK4114_CM1		(1<<5)	/* Master Clock Operation Select */
+#define AK4114_CM0		(1<<4)	/* Master Clock Operation Select */
+#define AK4114_OCKS1		(1<<3)	/* Master Clock Frequency Select */
+#define AK4114_OCKS0		(1<<2)	/* Master Clock Frequency Select */
+#define AK4114_PWN		(1<<1)	/* 0 = power down, 1 = normal operation */
+#define AK4114_RST		(1<<0)	/* 0 = reset & initialize (except this register), 1 = normal operation */
+
+/* AK4114_REQ_FORMAT bits */
+#define AK4114_MONO		(1<<7)	/* Double Sampling Frequency Mode: 0 = stereo, 1 = mono */
+#define AK4114_DIF2		(1<<5)	/* Audio Data Control */
+#define AK4114_DIF1		(1<<5)	/* Audio Data Control */
+#define AK4114_DIF0		(1<<4)	/* Audio Data Control */
+#define AK4114_DIF_16R		(0)				/* STDO: 16-bit, right justified */
+#define AK4114_DIF_18R		(AK4114_DIF0)			/* STDO: 18-bit, right justified */
+#define AK4114_DIF_20R		(AK4114_DIF1)			/* STDO: 20-bit, right justified */
+#define AK4114_DIF_24R		(AK4114_DIF1|AK4114_DIF0)	/* STDO: 24-bit, right justified */
+#define AK4114_DIF_24L		(AK4114_DIF2)			/* STDO: 24-bit, left justified */
+#define AK4114_DIF_24I2S	(AK4114_DIF2|AK4114_DIF0)	/* STDO: I2S */
+#define AK4114_DIF_I24L		(AK4114_DIF2|AK4114_DIF1)	/* STDO: 24-bit, left justified; LRCLK, BICK = Input */
+#define AK4114_DIF_I24I2S	(AK4114_DIF2|AK4114_DIF1|AK4114_DIF0) /* STDO: I2S;  LRCLK, BICK = Input */
+#define AK4114_DEAU		(1<<3)	/* Deemphasis Autodetect Enable (1 = enable) */
+#define AK4114_DEM1		(1<<2)	/* 32kHz-48kHz Deemphasis Control */
+#define AK4114_DEM0		(1<<1)	/* 32kHz-48kHz Deemphasis Control */
+#define AK4114_DEM_44KHZ	(0)
+#define AK4114_DEM_48KHZ	(AK4114_DEM1)
+#define AK4114_DEM_32KHZ	(AK4114_DEM0|AK4114_DEM1)
+#define AK4114_DEM_96KHZ	(AK4114_DEM1)	/* DFS must be set */
+#define AK4114_DFS		(1<<0)	/* 96kHz Deemphasis Control */
+
+/* AK4114_REG_IO0 */
+#define AK4114_TX1E		(1<<7)	/* TX1 Output Enable (1 = enable) */
+#define AK4114_OPS12		(1<<2)	/* Output Though Data Selector for TX1 pin */
+#define AK4114_OPS11		(1<<1)	/* Output Though Data Selector for TX1 pin */
+#define AK4114_OPS10		(1<<0)	/* Output Though Data Selector for TX1 pin */
+#define AK4114_TX0E		(1<<3)	/* TX0 Output Enable (1 = enable) */
+#define AK4114_OPS02		(1<<2)	/* Output Though Data Selector for TX0 pin */
+#define AK4114_OPS01		(1<<1)	/* Output Though Data Selector for TX0 pin */
+#define AK4114_OPS00		(1<<0)	/* Output Though Data Selector for TX0 pin */
+
+/* AK4114_REG_IO1 */
+#define AK4114_EFH1		(1<<7)	/* Interrupt 0 pin Hold */
+#define AK4114_EFH0		(1<<6)	/* Interrupt 0 pin Hold */
+#define AK4114_EFH_512		(0)
+#define AK4114_EFH_1024		(AK4114_EFH0)
+#define AK4114_EFH_2048		(AK4114_EFH1)
+#define AK4114_EFH_4096		(AK4114_EFH1|AK4114_EFH0)
+#define AK4114_UDIT		(1<<5)	/* U-bit Control for DIT (0 = fixed '0', 1 = recovered) */
+#define AK4114_TLR		(1<<4)	/* Double Sampling Frequency Select for DIT (0 = L channel, 1 = R channel) */
+#define AK4114_DIT		(1<<3)	/* TX1 out: 0 = Through Data (RX data), 1 = Transmit Data (DAUX data) */
+#define AK4114_IPS2		(1<<2)	/* Input Recovery Data Select */
+#define AK4114_IPS1		(1<<1)	/* Input Recovery Data Select */
+#define AK4114_IPS0		(1<<0)	/* Input Recovery Data Select */
+#define AK4114_IPS(x)		((x)&7)
+
+/* AK4114_REG_INT0_MASK && AK4114_REG_INT1_MASK*/
+#define AK4117_MQI              (1<<7)  /* mask enable for QINT bit */
+#define AK4117_MAT              (1<<6)  /* mask enable for AUTO bit */
+#define AK4117_MCI              (1<<5)  /* mask enable for CINT bit */
+#define AK4117_MUL              (1<<4)  /* mask enable for UNLOCK bit */
+#define AK4117_MDTS             (1<<3)  /* mask enable for DTSCD bit */
+#define AK4117_MPE              (1<<2)  /* mask enable for PEM bit */
+#define AK4117_MAN              (1<<1)  /* mask enable for AUDN bit */
+#define AK4117_MPR              (1<<0)  /* mask enable for PAR bit */
+
+/* AK4114_REG_RCS0 */
+#define AK4114_QINT		(1<<7)	/* Q-subcode buffer interrupt, 0 = no change, 1 = changed */
+#define AK4114_AUTO		(1<<6)	/* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */
+#define AK4114_CINT		(1<<5)	/* channel status buffer interrupt, 0 = no change, 1 = change */
+#define AK4114_UNLCK		(1<<4)	/* PLL lock status, 0 = lock, 1 = unlock */
+#define AK4114_DTSCD		(1<<3)	/* DTS-CD Detect, 0 = No detect, 1 = Detect */
+#define AK4114_PEM		(1<<2)	/* Pre-emphasis Detect, 0 = OFF, 1 = ON */
+#define AK4114_AUDION		(1<<1)	/* audio bit output, 0 = audio, 1 = non-audio */
+#define AK4114_PAR		(1<<0)	/* parity error or biphase error status, 0 = no error, 1 = error */
+
+/* AK4114_REG_RCS1 */
+#define AK4114_FS3		(1<<7)	/* sampling frequency detection */
+#define AK4114_FS2		(1<<6)
+#define AK4114_FS1		(1<<5)
+#define AK4114_FS0		(1<<4)
+#define AK4114_FS_44100HZ	(0)
+#define AK4114_FS_48000HZ	(AK4114_FS1)
+#define AK4114_FS_32000HZ	(AK4114_FS1|AK4114_FS0)
+#define AK4114_FS_88200HZ	(AK4114_FS3)
+#define AK4114_FS_96000HZ	(AK4114_FS3|AK4114_FS1)
+#define AK4114_FS_176400HZ	(AK4114_FS3|AK4114_FS2)
+#define AK4114_FS_192000HZ	(AK4114_FS3|AK4114_FS2|AK4114_FS1)
+#define AK4114_V		(1<<3)	/* Validity of Channel Status, 0 = Valid, 1 = Invalid */
+#define AK4114_QCRC		(1<<1)	/* CRC for Q-subcode, 0 = no error, 1 = error */
+#define AK4114_CCRC		(1<<0)	/* CRC for channel status, 0 = no error, 1 = error */
+
+/* flags for snd_ak4114_check_rate_and_errors() */
+#define AK4114_CHECK_NO_STAT	(1<<0)	/* no statistics */
+#define AK4114_CHECK_NO_RATE	(1<<1)	/* no rate check */
+
+#define AK4114_CONTROLS		14
+
+typedef void (ak4114_write_t)(void *private_data, unsigned char addr, unsigned char data);
+typedef unsigned char (ak4114_read_t)(void *private_data, unsigned char addr);
+
+typedef struct ak4114 ak4114_t;
+
+struct ak4114 {
+	snd_card_t * card;
+	ak4114_write_t * write;
+	ak4114_read_t * read;
+	void * private_data;
+	unsigned int init: 1;
+	spinlock_t lock;
+	unsigned char regmap[7];
+	unsigned char txcsb[5];
+	snd_kcontrol_t *kctls[AK4114_CONTROLS];
+	snd_pcm_substream_t *playback_substream;
+	snd_pcm_substream_t *capture_substream;
+	unsigned long parity_errors;
+	unsigned long v_bit_errors;
+	unsigned long qcrc_errors;
+	unsigned long ccrc_errors;
+	unsigned char rcs0;
+	unsigned char rcs1;
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+	void *change_callback_private;
+	void (*change_callback)(ak4114_t *ak4114, unsigned char c0, unsigned char c1);
+};
+
+int snd_ak4114_create(snd_card_t *card,
+		      ak4114_read_t *read, ak4114_write_t *write,
+		      unsigned char pgm[7], unsigned char txcsb[5],
+		      void *private_data, ak4114_t **r_ak4114);
+void snd_ak4114_reg_write(ak4114_t *ak4114, unsigned char reg, unsigned char mask, unsigned char val);
+void snd_ak4114_reinit(ak4114_t *ak4114);
+int snd_ak4114_build(ak4114_t *ak4114,
+		     snd_pcm_substream_t *playback_substream,
+                     snd_pcm_substream_t *capture_substream);
+int snd_ak4114_external_rate(ak4114_t *ak4114);
+int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags);
+
+#endif /* __SOUND_AK4114_H */
+
diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h
--- a/include/sound/ak4117.h
+++ b/include/sound/ak4117.h
@@ -106,7 +106,7 @@
 #define AK4117_DIF_24L		(AK4117_DIF2)			/* STDO: 24-bit, left justified */
 #define AK4117_DIF_24I2S	(AK4117_DIF2|AK4117_DIF0)	/* STDO: I2S */
 
-/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */
+/* AK4117_REG_INT0_MASK & AK4117_REG_INT1_MASK */
 #define AK4117_MULK		(1<<7)	/* mask enable for UNLOCK bit */
 #define AK4117_MPAR		(1<<6)	/* mask enable for PAR bit */
 #define AK4117_MAUTO		(1<<5)	/* mask enable for AUTO bit */
@@ -181,8 +181,8 @@ struct ak4117 {
 
 int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write,
 		      unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117);
-void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val);
-void snd_ak4117_reinit(ak4117_t *chip);
+void snd_ak4117_reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
+void snd_ak4117_reinit(ak4117_t *ak4117);
 int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream);
 int snd_ak4117_external_rate(ak4117_t *ak4117);
 int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags);
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -50,7 +50,8 @@ struct snd_akm4xxx {
 	/* template should fill the following fields */
 	unsigned int idx_offset;			/* control index offset */
 	enum {
-		SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381
+		SND_AK4524, SND_AK4528, SND_AK4529,
+		SND_AK4355, SND_AK4358, SND_AK4381
 	} type;
 	struct snd_ak4xxx_ops ops;
 };
diff --git a/include/sound/asound.h b/include/sound/asound.h
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -582,6 +582,7 @@ enum sndrv_timer_slave_class {
 /* global timers (device member) */
 #define SNDRV_TIMER_GLOBAL_SYSTEM	0
 #define SNDRV_TIMER_GLOBAL_RTC		1
+#define SNDRV_TIMER_GLOBAL_HPET		2
 
 /* info flags */
 #define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -185,7 +185,7 @@
 #define MIDI_CTL_LSB_GENERAL_PURPOSE4 	0x33
 #define MIDI_CTL_SUSTAIN              	0x40
 #define MIDI_CTL_PORTAMENTO           	0x41
-#define MIDI_CTL_SUSTENUTO            	0x42
+#define MIDI_CTL_SOSTENUTO            	0x42
 #define MIDI_CTL_SOFT_PEDAL           	0x43
 #define MIDI_CTL_LEGATO_FOOTSWITCH	0x44
 #define MIDI_CTL_HOLD2                	0x45
diff --git a/include/sound/control.h b/include/sound/control.h
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -119,6 +119,13 @@ int snd_ctl_create(snd_card_t *card);
 
 int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
 int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+#else
+#define snd_ctl_register_ioctl_compat(fcn)
+#define snd_ctl_unregister_ioctl_compat(fcn)
+#endif
 
 int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control);
 int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control);
diff --git a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -26,6 +26,7 @@
 #include <asm/semaphore.h>		/* struct semaphore */
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/workqueue.h>		/* struct workqueue_struct */
+#include <linux/pm.h>			/* pm_message_t */
 
 /* Typedef's */
 typedef struct timespec snd_timestamp_t;
@@ -167,13 +168,15 @@ struct _snd_card {
 	struct device *dev;
 
 #ifdef CONFIG_PM
-	int (*pm_suspend)(snd_card_t *card, unsigned int state);
-	int (*pm_resume)(snd_card_t *card, unsigned int state);
-	struct pm_dev *pm_dev;		/* for ISA */
+	int (*pm_suspend)(snd_card_t *card, pm_message_t state);
+	int (*pm_resume)(snd_card_t *card);
 	void *pm_private_data;
 	unsigned int power_state;	/* power state */
 	struct semaphore power_lock;	/* power lock */
 	wait_queue_head_t power_sleep;
+#ifdef CONFIG_SND_GENERIC_PM
+	struct snd_generic_device *pm_dev;	/* for ISA */
+#endif
 #endif
 
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
@@ -206,36 +209,34 @@ static inline void snd_power_change_stat
 	wake_up(&card->power_sleep);
 }
 int snd_card_set_pm_callback(snd_card_t *card,
-			     int (*suspend)(snd_card_t *, unsigned int),
-			     int (*resume)(snd_card_t *, unsigned int),
+			     int (*suspend)(snd_card_t *, pm_message_t),
+			     int (*resume)(snd_card_t *),
 			     void *private_data);
-int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
-				 int (*suspend)(snd_card_t *, unsigned int),
-				 int (*resume)(snd_card_t *, unsigned int),
-				 void *private_data);
+int snd_card_set_generic_pm_callback(snd_card_t *card,
+				     int (*suspend)(snd_card_t *, pm_message_t),
+				     int (*resume)(snd_card_t *),
+				     void *private_data);
 #define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
-	snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data)
-#ifdef CONFIG_PCI
-#ifndef SND_PCI_PM_CALLBACKS
-int snd_card_pci_suspend(struct pci_dev *dev, u32 state);
+	snd_card_set_generic_pm_callback(card, suspend, resume, data)
+struct pci_dev;
+int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state);
 int snd_card_pci_resume(struct pci_dev *dev);
 #define SND_PCI_PM_CALLBACKS \
 	.suspend = snd_card_pci_suspend,  .resume = snd_card_pci_resume
-#endif
-#endif
-#else
+
+#else /* ! CONFIG_PM */
+
 #define snd_power_lock(card)		do { (void)(card); } while (0)
 #define snd_power_unlock(card)		do { (void)(card); } while (0)
 static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; }
 #define snd_power_get_state(card)	SNDRV_CTL_POWER_D0
 #define snd_power_change_state(card, state)	do { (void)(card); } while (0)
 #define snd_card_set_pm_callback(card,suspend,resume,data)
-#define snd_card_set_dev_pm_callback(card,suspend,resume,data)
+#define snd_card_set_generic_pm_callback(card,suspend,resume,data)
 #define snd_card_set_isa_pm_callback(card,suspend,resume,data)
-#ifdef CONFIG_PCI
 #define SND_PCI_PM_CALLBACKS
-#endif
-#endif
+
+#endif /* CONFIG_PM */
 
 /* device.c */
 
@@ -489,4 +490,13 @@ static inline int snd_timestamp_null(str
 
 #define SNDRV_OSS_VERSION         ((3<<16)|(8<<8)|(1<<4)|(0))	/* 3.8.1a */
 
+/* for easier backward-porting */
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#ifndef gameport_set_dev_parent
+#define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev))
+#define gameport_set_port_data(gp,r) ((gp)->port_data = (r))
+#define gameport_get_port_data(gp) (gp)->port_data
+#endif
+#endif
+
 #endif /* __SOUND_CORE_H */
diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h
--- a/include/sound/cs46xx.h
+++ b/include/sound/cs46xx.h
@@ -1720,7 +1720,7 @@ struct _snd_cs46xx {
 	snd_kcontrol_t *eapd_switch; /* for amplifier hack */
 	int accept_valid;	/* accept mmap valid (for OSS) */
 
-	struct snd_cs46xx_gameport *gameport;
+	struct gameport *gameport;
 
 #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
 	int current_gpio;
@@ -1751,6 +1751,6 @@ int snd_cs46xx_pcm_center_lfe(cs46xx_t *
 int snd_cs46xx_mixer(cs46xx_t *chip);
 int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
 int snd_cs46xx_start_dsp(cs46xx_t *chip);
-void snd_cs46xx_gameport(cs46xx_t *chip);
+int snd_cs46xx_gameport(cs46xx_t *chip);
 
 #endif /* __SOUND_CS46XX_H */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -51,7 +51,9 @@
 #define NUM_MIDI        16
 #define NUM_G           64              /* use all channels */
 #define NUM_FXSENDS     4
+#define NUM_EFX_PLAYBACK    16
 
+/* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */
 #define EMU10K1_DMA_MASK	0x7fffffffUL	/* 31bit */
 #define AUDIGY_DMA_MASK		0xffffffffUL	/* 32bit */
 
@@ -82,10 +84,16 @@
 						/* Clear pending interrupts by writing a 1 to	*/
 						/* the relevant bits and zero to the other bits	*/
 
+#define IPR_GPIOMSG		0x20000000	/* GPIO message interrupt (RE'd, still not sure 
+						   which INTE bits enable it)			*/
+
 /* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1)			*/
 #define IPR_A_MIDITRANSBUFEMPTY2 0x10000000	/* MIDI UART transmit buffer empty		*/
 #define IPR_A_MIDIRECVBUFEMPTY2	0x08000000	/* MIDI UART receive buffer empty		*/
 
+#define IPR_SPDIFBUFFULL	0x04000000	/* SPDIF capture related, 10k2 only? (RE)	*/
+#define IPR_SPDIFBUFHALFFULL	0x02000000	/* SPDIF capture related? (RE)			*/
+
 #define IPR_SAMPLERATETRACKER	0x01000000	/* Sample rate tracker lock status change	*/
 #define IPR_FXDSP		0x00800000	/* Enable FX DSP interrupts			*/
 #define IPR_FORCEINT		0x00400000	/* Force Sound Blaster interrupt		*/
@@ -104,12 +112,12 @@
 #define IPR_INTERVALTIMER	0x00000200	/* Interval timer terminal count		*/
 #define IPR_MIDITRANSBUFEMPTY	0x00000100	/* MIDI UART transmit buffer empty		*/
 #define IPR_MIDIRECVBUFEMPTY	0x00000080	/* MIDI UART receive buffer empty		*/
-#define IPR_CHANNELLOOP		0x00000040	/* One or more channel loop interrupts pending	*/
+#define IPR_CHANNELLOOP		0x00000040	/* Channel (half) loop interrupt(s) pending	*/
 #define IPR_CHANNELNUMBERMASK	0x0000003f	/* When IPR_CHANNELLOOP is set, indicates the	*/
-						/* Highest set channel in CLIPL or CLIPH.  When	*/
-						/* IP is written with CL set, the bit in CLIPL	*/
-						/* or CLIPH corresponding to the CIN value 	*/
-						/* written will be cleared.			*/
+						/* highest set channel in CLIPL, CLIPH, HLIPL,  */
+						/* or HLIPH.  When IP is written with CL set,	*/
+						/* the bit in H/CLIPL or H/CLIPH corresponding	*/
+						/* to the CIN value written will be cleared.	*/
 
 #define INTE			0x0c		/* Interrupt enable register			*/
 #define INTE_VIRTUALSB_MASK	0xc0000000	/* Virtual Soundblaster I/O port capture	*/
@@ -236,9 +244,27 @@
 #define A_IOCFG			0x18		/* GPIO on Audigy card (16bits)			*/
 #define A_GPINPUT_MASK		0xff00
 #define A_GPOUTPUT_MASK		0x00ff
-#define A_IOCFG_GPOUT0		0x0044		/* analog/digital? */
-#define A_IOCFG_GPOUT1		0x0002		/* IR */
+
+// Audigy output/GPIO stuff taken from the kX drivers
+#define A_IOCFG_GPOUT0		0x0044		/* analog/digital				*/
+#define A_IOCFG_DISABLE_ANALOG	0x0040		/* = 'enable' for Audigy2 (chiprev=4)		*/
+#define A_IOCFG_ENABLE_DIGITAL	0x0004
+#define A_IOCFG_UNKNOWN_20      0x0020
+#define A_IOCFG_DISABLE_AC97_FRONT      0x0080  /* turn off ac97 front -> front (10k2.1)	*/
+#define A_IOCFG_GPOUT1		0x0002		/* IR? drive's internal bypass (?)		*/
 #define A_IOCFG_GPOUT2		0x0001		/* IR */
+#define A_IOCFG_MULTIPURPOSE_JACK	0x2000  /* center+lfe+rear_center (a2/a2ex)		*/
+                                                /* + digital for generic 10k2			*/
+#define A_IOCFG_DIGITAL_JACK    0x1000          /* digital for a2 platinum			*/
+#define A_IOCFG_FRONT_JACK      0x4000
+#define A_IOCFG_REAR_JACK       0x8000
+#define A_IOCFG_PHONES_JACK     0x0100          /* LiveDrive					*/
+
+/* outputs:
+ *	for audigy2 platinum:	0xa00
+ *	for a2 platinum ex:	0x1c00
+ *	for a1 platinum:	0x0
+ */
 
 #define TIMER			0x1a		/* Timer terminal count register		*/
 						/* NOTE: After the rate is changed, a maximum	*/
@@ -254,6 +280,46 @@
 #define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
 #define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
 
+/* Available on the Audigy 2 and Audigy 4 only. This is the P16V chip. */
+#define PTR2			0x20		/* Indexed register set pointer register	*/
+#define DATA2			0x24		/* Indexed register set data register		*/
+#define IPR2			0x28		/* P16V interrupt pending register		*/
+#define IPR2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define IPR2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define IPR2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define IPR2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Capture Channel 0 half loop                          */
+						/* 0x00000100 Playback. Only in once per period.
+						 * 0x00110000 Capture. Int on half buffer.
+						 */
+#define INTE2			0x2c		/* P16V Interrupt enable register. 	*/
+#define INTE2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define INTE2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define INTE2_PLAYBACK_CH_1_LOOP      0x00002000 /* Playback Channel 1 loop                               */
+#define INTE2_PLAYBACK_CH_1_HALF_LOOP 0x00000200 /* Playback Channel 1 half loop                          */
+#define INTE2_PLAYBACK_CH_2_LOOP      0x00004000 /* Playback Channel 2 loop                               */
+#define INTE2_PLAYBACK_CH_2_HALF_LOOP 0x00000400 /* Playback Channel 2 half loop                          */
+#define INTE2_PLAYBACK_CH_3_LOOP      0x00008000 /* Playback Channel 3 loop                               */
+#define INTE2_PLAYBACK_CH_3_HALF_LOOP 0x00000800 /* Playback Channel 3 half loop                          */
+#define INTE2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define INTE2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Caputre Channel 0 half loop                          */
+#define HCFG2			0x34		/* Defaults: 0, win2000 sets it to 00004201 */
+						/* 0x00000000 2-channel output. */
+						/* 0x00000200 8-channel output. */
+						/* 0x00000004 pauses stream/irq fail. */
+						/* Rest of bits no nothing to sound output */
+						/* bit 0: Enable P16V audio.
+						 * bit 1: Lock P16V record memory cache.
+						 * bit 2: Lock P16V playback memory cache.
+						 * bit 3: Dummy record insert zero samples.
+						 * bit 8: Record 8-channel in phase.
+						 * bit 9: Playback 8-channel in phase.
+						 * bit 11-12: Playback mixer attenuation: 0=0dB, 1=-6dB, 2=-12dB, 3=Mute.
+						 * bit 13: Playback mixer enable.
+						 * bit 14: Route SRC48 mixer output to fx engine.
+						 * bit 15: Enable IEEE 1394 chip.
+						 */
+#define IPR3			0x38		/* Cdif interrupt pending register		*/
+#define INTE3			0x3c		/* Cdif interrupt enable register. 	*/
 /************************************************************************************************/
 /* PCI function 1 registers, address = <val> + PCIBASE1						*/
 /************************************************************************************************/
@@ -464,6 +530,8 @@
 						/* NOTE: All channels contain internal variables; do	*/
 						/* not write to these locations.			*/
 
+/* 1f something */
+
 #define CD0			0x20		/* Cache data 0 register				*/
 #define CD1			0x21		/* Cache data 1 register				*/
 #define CD2			0x22		/* Cache data 2 register				*/
@@ -481,6 +549,8 @@
 #define CDE			0x2e		/* Cache data E register				*/
 #define CDF			0x2f		/* Cache data F register				*/
 
+/* 0x30-3f seem to be the same as 0x20-2f */
+
 #define PTB			0x40		/* Page table base register				*/
 #define PTB_MASK		0xfffff000	/* Physical address of the page table in host memory	*/
 
@@ -511,7 +581,11 @@
 
 #define FXWC			0x43		/* FX output write channels register			*/
 						/* When set, each bit enables the writing of the	*/
-						/* corresponding FX output channel into host memory	*/
+						/* corresponding FX output channel (internal registers  */
+						/* 0x20-0x3f) to host memory.  This mode of recording   */
+						/* is 16bit, 48KHz only. All 32 channels can be enabled */
+						/* simultaneously.					*/
+
 #define FXWC_DEFAULTROUTE_C     (1<<0)		/* left emu out? */
 #define FXWC_DEFAULTROUTE_B     (1<<1)		/* right emu out? */
 #define FXWC_DEFAULTROUTE_A     (1<<12)
@@ -546,12 +620,16 @@
 #define FXBA			0x47		/* FX Buffer Address */
 #define FXBA_MASK		0xfffff000	/* 20 bit base address					*/
 
+/* 0x48 something - word access, defaults to 3f */
+
 #define MICBS			0x49		/* Microphone buffer size register			*/
 
 #define ADCBS			0x4a		/* ADC buffer size register				*/
 
 #define FXBS			0x4b		/* FX buffer size register				*/
 
+/* register: 0x4c..4f: ffff-ffff current amounts, per-channel */
+
 /* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
 #define ADCBS_BUFSIZE_NONE	0x00000000
 #define ADCBS_BUFSIZE_384	0x00000001
@@ -602,6 +680,7 @@
 #define A_DBG_SATURATION_OCCURED 0x20000000
 #define A_DBG_SATURATION_ADDR	 0x0ffc0000
 
+// NOTE: 0x54,55,56: 64-bit
 #define SPCS0			0x54		/* SPDIF output Channel Status 0 register	*/
 
 #define SPCS1			0x55		/* SPDIF output Channel Status 1 register	*/
@@ -657,6 +736,7 @@
 #define AC97SLOT_CNTR		0x10            /* Center enable */
 #define AC97SLOT_LFE		0x20            /* LFE enable */
 
+// NOTE: 0x60,61,62: 64-bit
 #define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
 
 #define GPSRCS			0x61		/* General Purpose SPDIF sample rate cvt status */
@@ -693,6 +773,19 @@
 #define FXIDX_MASK		0x0000ffff	/* 16-bit value					*/
 #define FXIDX_IDX		0x10000065
 
+/* The 32-bit HLIx and HLIPx registers all have one bit per channel control/status      		*/
+#define HLIEL			0x66		/* Channel half loop interrupt enable low register	*/
+
+#define HLIEH			0x67		/* Channel half loop interrupt enable high register	*/
+
+#define HLIPL			0x68		/* Channel half loop interrupt pending low register	*/
+
+#define HLIPH			0x69		/* Channel half loop interrupt pending high register	*/
+
+// 0x6a,6b,6c used for some recording
+// 0x6d unused
+// 0x6e,6f - tanktable base / offset
+
 /* This is the MPU port on the card (via the game port)						*/
 #define A_MUDATA1		0x70
 #define A_MUCMD1		0x71
@@ -710,10 +803,14 @@
 #define A_FXWC2			0x75		/* Selects 0x9f-0x80 for FX recording           */
 
 #define A_SPDIF_SAMPLERATE	0x76		/* Set the sample rate of SPDIF output		*/
-#define A_SPDIF_48000		0x00000080
-#define A_SPDIF_44100		0x00000000
+#define A_SPDIF_RATE_MASK	0x000000c0
+#define A_SPDIF_48000		0x00000000
+#define A_SPDIF_44100		0x00000080
 #define A_SPDIF_96000		0x00000040
 
+/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell	*/
+/* 0x7a, 0x7b - lookup tables */
+
 #define A_FXRT2			0x7c
 #define A_FXRT_CHANNELE		0x0000003f	/* Effects send bus number for channel's effects send E	*/
 #define A_FXRT_CHANNELF		0x00003f00	/* Effects send bus number for channel's effects send F	*/
@@ -725,7 +822,8 @@
 #define A_FXSENDAMOUNT_F_MASK	0x00FF0000
 #define A_FXSENDAMOUNT_G_MASK	0x0000FF00
 #define A_FXSENDAMOUNT_H_MASK	0x000000FF
-
+/* 0x7c, 0x7e "high bit is used for filtering" */
+ 
 /* The send amounts for this one are the same as used with the emu10k1 */
 #define A_FXRT1			0x7e
 #define A_FXRT_CHANNELA		0x0000003f
@@ -782,6 +880,7 @@ typedef struct _snd_emu10k1_voice emu10k
 typedef struct _snd_emu10k1_pcm emu10k1_pcm_t;
 
 typedef enum {
+	EMU10K1_EFX,
 	EMU10K1_PCM,
 	EMU10K1_SYNTH,
 	EMU10K1_MIDI
@@ -790,8 +889,9 @@ typedef enum {
 struct _snd_emu10k1_voice {
 	emu10k1_t *emu;
 	int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
+	    efx: 1,
 	    synth: 1,
 	    midi: 1;
 	void (*interrupt)(emu10k1_t *emu, emu10k1_voice_t *pvoice);
@@ -801,6 +901,7 @@ struct _snd_emu10k1_voice {
 
 typedef enum {
 	PLAYBACK_EMUVOICE,
+	PLAYBACK_EFX,
 	CAPTURE_AC97ADC,
 	CAPTURE_AC97MIC,
 	CAPTURE_EFX
@@ -810,7 +911,7 @@ struct _snd_emu10k1_pcm {
 	emu10k1_t *emu;
 	snd_emu10k1_pcm_type_t type;
 	snd_pcm_substream_t *substream;
-	emu10k1_voice_t *voices[2];
+	emu10k1_voice_t *voices[NUM_EFX_PLAYBACK];
 	emu10k1_voice_t *extra;
 	unsigned short running;
 	unsigned short first_ptr;
@@ -934,15 +1035,33 @@ typedef struct {
 	void (*interrupt)(emu10k1_t *emu, unsigned int status);
 } emu10k1_midi_t;
 
+typedef struct {
+	u32 vendor;
+	u32 device;
+	u32 subsystem;
+	unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */
+	unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */
+	unsigned char ca0102_chip;  /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */
+	unsigned char ca0108_chip;  /* Audigy 2 Value */
+	unsigned char ca0151_chip;  /* P16V */
+	unsigned char spk71;        /* Has 7.1 speakers */
+	unsigned char spdif_bug;    /* Has Spdif phasing bug */
+	unsigned char ac97_chip;    /* Has an AC97 chip */
+	unsigned char ecard;        /* APS EEPROM */
+	char * driver;
+	char * name;
+} emu_chip_details_t;
+
 struct _snd_emu10k1 {
 	int irq;
 
 	unsigned long port;			/* I/O port number */
-	int APS: 1,				/* APS flag */
+	unsigned int APS: 1,			/* APS flag */
 	    no_ac97: 1,				/* no AC'97 */
 	    tos_link: 1,			/* tos link detected */
 	    rear_ac97: 1,			/* rear channels are on AC'97 */
 	    spk71:1;				/* 7.1 configuration (Audigy 2 ZS) */
+	const emu_chip_details_t *card_capabilities;	/* Contains profile of card capabilities */
 	unsigned int audigy;			/* is Audigy? */
 	unsigned int revision;			/* chip revision */
 	unsigned int serial;			/* serial number */
@@ -953,6 +1072,9 @@ struct _snd_emu10k1 {
 	int max_cache_pages;			/* max memory size / PAGE_SIZE */
 	struct snd_dma_buffer silent_page;	/* silent page */
 	struct snd_dma_buffer ptb_pages;	/* page table pages */
+	struct snd_dma_device p16v_dma_dev;
+	struct snd_dma_buffer p16v_buffer;
+
 	snd_util_memhdr_t *memhdr;		/* page allocation list */
 	emu10k1_memblk_t *reserved_page;	/* reserved page */
 
@@ -974,6 +1096,7 @@ struct _snd_emu10k1 {
 	snd_pcm_t *pcm;
 	snd_pcm_t *pcm_mic;
 	snd_pcm_t *pcm_efx;
+	snd_pcm_t *pcm_p16v;
 
 	spinlock_t synth_lock;
 	void *synth;
@@ -984,23 +1107,29 @@ struct _snd_emu10k1 {
 	spinlock_t voice_lock;
 	struct semaphore ptb_lock;
 
-	emu10k1_voice_t voices[64];
+	emu10k1_voice_t voices[NUM_G];
+	emu10k1_voice_t p16v_voices[4];
+	int p16v_device_offset;
 	emu10k1_pcm_mixer_t pcm_mixer[32];
+	emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK];
 	snd_kcontrol_t *ctl_send_routing;
 	snd_kcontrol_t *ctl_send_volume;
 	snd_kcontrol_t *ctl_attn;
+	snd_kcontrol_t *ctl_efx_send_routing;
+	snd_kcontrol_t *ctl_efx_send_volume;
+	snd_kcontrol_t *ctl_efx_attn;
 
 	void (*hwvol_interrupt)(emu10k1_t *emu, unsigned int status);
 	void (*capture_interrupt)(emu10k1_t *emu, unsigned int status);
 	void (*capture_mic_interrupt)(emu10k1_t *emu, unsigned int status);
 	void (*capture_efx_interrupt)(emu10k1_t *emu, unsigned int status);
-	void (*timer_interrupt)(emu10k1_t *emu);
 	void (*spdif_interrupt)(emu10k1_t *emu, unsigned int status);
 	void (*dsp_interrupt)(emu10k1_t *emu);
 
 	snd_pcm_substream_t *pcm_capture_substream;
 	snd_pcm_substream_t *pcm_capture_mic_substream;
 	snd_pcm_substream_t *pcm_capture_efx_substream;
+	snd_pcm_substream_t *pcm_playback_efx_substream;
 
 	snd_timer_t *timer;
 
@@ -1008,6 +1137,7 @@ struct _snd_emu10k1 {
 	emu10k1_midi_t midi2; /* for audigy */
 
 	unsigned int efx_voices_mask[2];
+	unsigned int next_free_voice;
 };
 
 int snd_emu10k1_create(snd_card_t * card,
@@ -1021,6 +1151,10 @@ int snd_emu10k1_create(snd_card_t * card
 int snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_pcm_mic(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
+int snd_p16v_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
+int snd_p16v_free(emu10k1_t * emu);
+int snd_p16v_mixer(emu10k1_t * emu);
+int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_mixer(emu10k1_t * emu);
 int snd_emu10k1_timer(emu10k1_t * emu, int device);
@@ -1037,12 +1171,17 @@ int snd_emu10k1_fx8010_tram_setup(emu10k
 /* I/O functions */
 unsigned int snd_emu10k1_ptr_read(emu10k1_t * emu, unsigned int reg, unsigned int chn);
 void snd_emu10k1_ptr_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data);
+unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu, unsigned int reg, unsigned int chn);
+void snd_emu10k1_ptr20_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data);
 unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb);
 void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb);
 void snd_emu10k1_voice_intr_enable(emu10k1_t *emu, unsigned int voicenum);
 void snd_emu10k1_voice_intr_disable(emu10k1_t *emu, unsigned int voicenum);
 void snd_emu10k1_voice_intr_ack(emu10k1_t *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_enable(emu10k1_t *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_disable(emu10k1_t *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_ack(emu10k1_t *emu, unsigned int voicenum);
 void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum);
 void snd_emu10k1_voice_clear_loop_stop(emu10k1_t *emu, unsigned int voicenum);
 void snd_emu10k1_wait(emu10k1_t *emu, unsigned int wait);
@@ -1112,7 +1251,10 @@ int snd_emu10k1_fx8010_unregister_irq_ha
 /* GPRs */
 #define FXBUS(x)	(0x00 + (x))	/* x = 0x00 - 0x0f */
 #define EXTIN(x)	(0x10 + (x))	/* x = 0x00 - 0x0f */
-#define EXTOUT(x)	(0x20 + (x))	/* x = 0x00 - 0x0f */
+#define EXTOUT(x)	(0x20 + (x))	/* x = 0x00 - 0x0f physical outs -> FXWC low 16 bits */
+#define FXBUS2(x)	(0x30 + (x))	/* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */
+					/* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */
+
 #define C_00000000	0x40
 #define C_00000001	0x41
 #define C_00000002	0x42
@@ -1154,9 +1296,13 @@ int snd_emu10k1_fx8010_unregister_irq_ha
 #define A_ITRAM_CTL(x)	(A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */
 #define A_ETRAM_CTL(x)	(A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */
 
-#define A_FXBUS(x)	(0x00 + (x))	/* x = 0x00 - 0x3f? */
-#define A_EXTIN(x)	(0x40 + (x))	/* x = 0x00 - 0x1f? */
-#define A_EXTOUT(x)	(0x60 + (x))	/* x = 0x00 - 0x1f? */
+#define A_FXBUS(x)	(0x00 + (x))	/* x = 0x00 - 0x3f FX buses */
+#define A_EXTIN(x)	(0x40 + (x))	/* x = 0x00 - 0x0f physical ins */
+#define A_P16VIN(x)	(0x50 + (x))	/* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */
+#define A_EXTOUT(x)	(0x60 + (x))	/* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown   */
+#define A_FXBUS2(x)	(0x80 + (x))	/* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */
+#define A_EMU32OUTH(x)	(0xa0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */
+#define A_EMU32OUTL(x)	(0xb0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */
 #define A_GPR(x)	(A_FXGPREGBASE + (x))
 
 /* cc_reg constants */
diff --git a/include/sound/gus.h b/include/sound/gus.h
--- a/include/sound/gus.h
+++ b/include/sound/gus.h
@@ -230,7 +230,7 @@ typedef struct {
 	int mode;		/* operation mode */
 	int client;		/* sequencer client number */
 	int port;		/* sequencer port number */
-	int midi_has_voices: 1;
+	unsigned int midi_has_voices: 1;
 } snd_gus_port_t;
 
 typedef struct _snd_gus_voice snd_gus_voice_t;
@@ -264,7 +264,7 @@ typedef enum {
 
 struct _snd_gus_voice {
 	int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
 	    synth:1,
 	    midi: 1;
diff --git a/include/sound/hwdep.h b/include/sound/hwdep.h
--- a/include/sound/hwdep.h
+++ b/include/sound/hwdep.h
@@ -38,6 +38,7 @@ typedef struct _snd_hwdep_ops {
 	int (*release) (snd_hwdep_t * hw, struct file * file);
 	unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
 	int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
+	int (*ioctl_compat) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
 	int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
 	int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
 	int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h
--- a/include/sound/mixer_oss.h
+++ b/include/sound/mixer_oss.h
@@ -38,7 +38,7 @@ typedef int (*snd_mixer_oss_put_recsrce_
 
 struct _snd_oss_mixer_slot {
 	int number;
-	int stereo: 1;
+	unsigned int stereo: 1;
 	snd_mixer_oss_get_volume_t get_volume;
 	snd_mixer_oss_put_volume_t put_volume;
 	snd_mixer_oss_get_recsrc_t get_recsrc;
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
--- a/include/sound/mpu401.h
+++ b/include/sound/mpu401.h
@@ -86,9 +86,6 @@ struct _snd_mpu401 {
 	spinlock_t output_lock;
 	spinlock_t timer_lock;
 	
-	atomic_t rx_loop;
-	atomic_t tx_loop;
-
 	struct timer_list timer;
 
 	void (*write) (mpu401_t * mpu, unsigned char data, unsigned long addr);
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -23,6 +23,7 @@
  */
 
 #include <sound/asound.h>
+#include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <asm/semaphore.h>
@@ -65,8 +66,7 @@ typedef struct _snd_rawmidi_global_ops {
 } snd_rawmidi_global_ops_t;
 
 struct _snd_rawmidi_runtime {
-	unsigned int trigger: 1, /* transfer is running */
-		     drain: 1,	/* drain stage */
+	unsigned int drain: 1,	/* drain stage */
 		     oss: 1;	/* OSS compatible mode */
 	/* midi stream buffer */
 	unsigned char *buffer;	/* buffer for MIDI data */
@@ -79,8 +79,10 @@ struct _snd_rawmidi_runtime {
 	/* misc */
 	spinlock_t lock;
 	wait_queue_head_t sleep;
-	/* event handler (room [output] or new bytes [input]) */
+	/* event handler (new bytes, input only) */
 	void (*event)(snd_rawmidi_substream_t *substream);
+	/* defers calls to event [input] or ops->trigger [output] */
+	struct tasklet_struct tasklet;
 	/* private data */
 	void *private_data;
 	void (*private_free)(snd_rawmidi_substream_t *substream);
diff --git a/include/sound/seq_midi_emul.h b/include/sound/seq_midi_emul.h
--- a/include/sound/seq_midi_emul.h
+++ b/include/sound/seq_midi_emul.h
@@ -136,7 +136,7 @@ typedef struct snd_seq_midi_op {
 #define gm_sustain	 	control[MIDI_CTL_SUSTAIN]
 #define gm_hold			gm_sustain
 #define gm_portamento		control[MIDI_CTL_PORTAMENTO]
-#define gm_sustenuto		control[MIDI_CTL_SUSTENUTO]
+#define gm_sostenuto		control[MIDI_CTL_SOSTENUTO]
 
 /*
  * These macros give the complete value of the controls that consist
@@ -166,7 +166,7 @@ typedef struct snd_seq_midi_op {
 #define SNDRV_MIDI_NOTE_OFF		0x00
 #define SNDRV_MIDI_NOTE_ON		0x01
 #define SNDRV_MIDI_NOTE_RELEASED		0x02
-#define SNDRV_MIDI_NOTE_SUSTENUTO		0x04
+#define SNDRV_MIDI_NOTE_SOSTENUTO		0x04
  
 #define SNDRV_MIDI_PARAM_TYPE_REGISTERED		0
 #define SNDRV_MIDI_PARAM_TYPE_NONREGISTERED	1
diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h
--- a/include/sound/seq_virmidi.h
+++ b/include/sound/seq_virmidi.h
@@ -38,7 +38,7 @@ typedef struct _snd_virmidi {
 	int seq_mode;
 	int client;
 	int port;
-	int trigger: 1;
+	unsigned int trigger: 1;
 	snd_midi_event_t *parser;
 	snd_seq_event_t event;
 	snd_virmidi_dev_t *rdev;
diff --git a/include/sound/trident.h b/include/sound/trident.h
--- a/include/sound/trident.h
+++ b/include/sound/trident.h
@@ -290,7 +290,7 @@ typedef struct {
 	int mode;		/* operation mode */
 	int client;		/* sequencer client number */
 	int port;		/* sequencer port number */
-	int midi_has_voices: 1;
+	unsigned int midi_has_voices: 1;
 } snd_trident_port_t;
 
 typedef struct snd_trident_memblk_arg {
@@ -308,7 +308,7 @@ typedef struct {
 
 struct _snd_trident_voice {
 	unsigned int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
 	    synth:1,
 	    midi: 1;
@@ -347,7 +347,7 @@ struct _snd_trident_voice {
 	trident_t *trident;
 	snd_pcm_substream_t *substream;
 	snd_trident_voice_t *extra;	/* extra PCM voice (acts as interrupt generator) */
-	int running: 1,
+	unsigned int running: 1,
             capture: 1,
             spdif: 1,
             foldback: 1,
@@ -448,7 +448,7 @@ struct _snd_trident {
 
 	spinlock_t reg_lock;
 
-	struct snd_trident_gameport *gameport;
+	struct gameport *gameport;
 };
 
 int snd_trident_create(snd_card_t * card,
@@ -457,7 +457,7 @@ int snd_trident_create(snd_card_t * card
 		       int pcm_spdif_device,
 		       int max_wavetable_size,
 		       trident_t ** rtrident);
-void snd_trident_gameport(trident_t *trident);
+int snd_trident_create_gameport(trident_t *trident);
 
 int snd_trident_pcm(trident_t * trident, int device, snd_pcm_t **rpcm);
 int snd_trident_foldback_pcm(trident_t * trident, int device, snd_pcm_t **rpcm);
diff --git a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.8"
-#define CONFIG_SND_DATE " (Thu Jan 13 09:39:32 2005 UTC)"
+#define CONFIG_SND_VERSION "1.0.9rc2"
+#define CONFIG_SND_DATE "  (Thu Mar 24 10:33:39 2005 UTC)"
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -198,6 +198,10 @@
 #define YMFPCI_LEGACY2_IMOD	(1 << 15)	/* legacy IRQ mode */
 /* SIEN:IMOD 0:0 = legacy irq, 0:1 = INTA, 1:0 = serialized IRQ */
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /*
  *
  */
@@ -262,7 +266,7 @@ typedef enum {
 struct _snd_ymfpci_voice {
 	ymfpci_t *chip;
 	int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
 	    synth: 1,
 	    midi: 1;
@@ -288,9 +292,9 @@ struct _snd_ymfpci_pcm {
 	snd_ymfpci_pcm_type_t type;
 	snd_pcm_substream_t *substream;
 	ymfpci_voice_t *voices[2];	/* playback only */
-	int running: 1;
-	int output_front: 1;
-	int output_rear: 1;
+	unsigned int running: 1;
+	unsigned int output_front: 1;
+	unsigned int output_rear: 1;
 	u32 period_size;		/* cached from runtime->period_size */
 	u32 buffer_size;		/* cached from runtime->buffer_size */
 	u32 period_pos;
@@ -311,9 +315,8 @@ struct _snd_ymfpci {
 	struct resource *mpu_res;
 
 	unsigned short old_legacy_ctrl;
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
-	struct resource *joystick_res;
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 
 	struct snd_dma_buffer work_ptr;
@@ -381,6 +384,7 @@ int snd_ymfpci_create(snd_card_t * card,
 		      struct pci_dev *pci,
 		      unsigned short old_legacy_ctrl,
 		      ymfpci_t ** rcodec);
+void snd_ymfpci_free_gameport(ymfpci_t *chip);
 
 int snd_ymfpci_pcm(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_pcm2(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
@@ -389,8 +393,4 @@ int snd_ymfpci_pcm_4ch(ymfpci_t *chip, i
 int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch);
 int snd_ymfpci_timer(ymfpci_t *chip, int device);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK
-#endif
-
 #endif /* __SOUND_YMFPCI_H */
diff --git a/include/sound/yss225.h b/include/sound/yss225.h
deleted file mode 100644
--- a/include/sound/yss225.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __SOUND_YSS225_H
-#define __SOUND_YSS225_H
-
-extern unsigned char page_zero[256];
-extern unsigned char page_one[256];
-extern unsigned char page_two[128];
-extern unsigned char page_three[128];
-extern unsigned char page_four[128];
-extern unsigned char page_six[192];
-extern unsigned char page_seven[256];
-extern unsigned char page_zero_v2[96];
-extern unsigned char page_one_v2[96];
-extern unsigned char page_two_v2[48];
-extern unsigned char page_three_v2[48];
-extern unsigned char page_four_v2[48];
-extern unsigned char page_seven_v2[96];
-extern unsigned char mod_v2[304];
-extern unsigned char coefficients[364];
-extern unsigned char coefficients2[56];
-extern unsigned char coefficients3[404];
-
-
-#endif /* __SOUND_YSS225_H  */
diff --git a/include/video/edid.h b/include/video/edid.h
--- a/include/video/edid.h
+++ b/include/video/edid.h
@@ -4,9 +4,6 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
-#ifdef CONFIG_PPC_OF
-#include <linux/pci.h>
-#endif
 
 #ifdef CONFIG_X86
 struct edid_info {
@@ -14,14 +11,8 @@ struct edid_info {
 };
 
 extern struct edid_info edid_info;
-extern char *get_EDID_from_BIOS(void *);
-
 #endif /* CONFIG_X86 */
 
-#ifdef CONFIG_PPC_OF
-extern char *get_EDID_from_OF(struct pci_dev *pdev);
-#endif
-
 #endif /* __KERNEL__ */
 
 #endif /* __linux_video_edid_h__ */
diff --git a/include/video/kyro.h b/include/video/kyro.h
--- a/include/video/kyro.h
+++ b/include/video/kyro.h
@@ -49,9 +49,7 @@ extern void *kyro_dev_virtual_regs_ptr(v
 extern unsigned int kyro_dev_fb_size(void);
 extern unsigned int kyro_dev_regs_size(void);
 
-extern int kyro_dev_overlay_create(u32 width, u32 height, int bLinear);
 extern u32 kyro_dev_overlay_offset(void);
-extern int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 width, u32 height);
 
 /*
  * benedict.gaster@superh.com
diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h
--- a/include/video/pm3fb.h
+++ b/include/video/pm3fb.h
@@ -1119,34 +1119,6 @@
 /* ***** pm3fb useful define and macro ***** */
 /* ***************************************** */
 
-/* kernel -specific definitions */
-/* what kernel is this ? */
-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)))
-#define KERNEL_2_5
-#endif
-
-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)))
-#define KERNEL_2_4
-#endif
-
-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))) 
-#define KERNEL_2_2
-/* pci_resource_start, available in 2.2.18 */
-#include <linux/kcomp.h>
-#ifdef CONFIG_FB_OF
-#define SUPPORT_FB_OF
-#endif
-#endif
-
-#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4)) && (!defined(KERNEL_2_5))
-#error "Only kernel 2.2.x, kernel 2.4.y and kernel 2.5.z might work"
-#endif
-
-/* not sure if/why it's needed. doesn't work without on my PowerMac... */
-#ifdef __BIG_ENDIAN
-#define MUST_BYTESWAP
-#endif
-
 /* permedia3 -specific definitions */
 #define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
 
@@ -1203,19 +1175,9 @@
 /* ******************************************** */
 /* ***** A bunch of register-access macro ***** */
 /* ******************************************** */
-#ifdef KERNEL_2_2
-#ifdef MUST_BYTESWAP /* we are writing big_endian to big_endian through a little_endian macro */
-#define PM3_READ_REG(r) __swab32(readl((l_fb_info->vIOBase + r)))
-#define PM3_WRITE_REG(r, v) writel(__swab32(v), (l_fb_info->vIOBase + r))
-#else /* MUST_BYTESWAP */
-#define PM3_WRITE_REG(r, v) writel(v, (l_fb_info->vIOBase + r))
-#define PM3_READ_REG(r) readl((l_fb_info->vIOBase + r))
-#endif /* MUST_BYTESWAP */
-#endif /* KERNEL_2_2 */
-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) /* native-endian access */
+
 #define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
 #define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
-#endif /* KERNEL_2_4 or KERNEL_2_5 */
 
 
 #define depth2bpp(d) ((d + 7L) & ~7L)
diff --git a/include/video/s1d13xxxfb.h b/include/video/s1d13xxxfb.h
new file mode 100644
--- /dev/null
+++ b/include/video/s1d13xxxfb.h
@@ -0,0 +1,166 @@
+/* drivers/video/s1d3xxxfb.h
+ *
+ * (c) 2004 Simtec Electronics
+ * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * Header file for Epson S1D13XXX driver code
+ *
+ * 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	S1D13XXXFB_H
+#define	S1D13XXXFB_H
+
+#define S1D_PALETTE_SIZE		256
+#define S1D_CHIP_REV			7	/* expected chip revision number for s1d13806 */
+#define S1D_FBID			"S1D13806"
+#define S1D_DEVICENAME			"s1d13806fb"
+
+/* register definitions (tested on s1d13896) */
+#define S1DREG_REV_CODE			0x0000	/* Revision Code Register */
+#define S1DREG_MISC			0x0001	/* Miscellaneous Register */
+#define S1DREG_GPIO_CNF0		0x0004	/* General IO Pins Configuration Register 0 */
+#define S1DREG_GPIO_CNF1		0x0005	/* General IO Pins Configuration Register 1 */
+#define S1DREG_GPIO_CTL0		0x0008	/* General IO Pins Control Register 0 */
+#define S1DREG_GPIO_CTL1		0x0009	/* General IO Pins Control Register 1 */
+#define S1DREG_CNF_STATUS		0x000C	/* Configuration Status Readback Register */
+#define S1DREG_CLK_CNF			0x0010	/* Memory Clock Configuration Register */
+#define S1DREG_LCD_CLK_CNF		0x0014	/* LCD Pixel Clock Configuration Register */
+#define S1DREG_CRT_CLK_CNF		0x0018	/* CRT/TV Pixel Clock Configuration Register */
+#define S1DREG_MPLUG_CLK_CNF		0x001C	/* MediaPlug Clock Configuration Register */
+#define S1DREG_CPU2MEM_WST_SEL		0x001E	/* CPU To Memory Wait State Select Register */
+#define S1DREG_MEM_CNF			0x0020	/* Memory Configuration Register */
+#define S1DREG_SDRAM_REF_RATE		0x0021	/* SDRAM Refresh Rate Register */
+#define S1DREG_SDRAM_TC0		0x002A	/* SDRAM Timing Control Register 0 */
+#define S1DREG_SDRAM_TC1		0x002B	/* SDRAM Timing Control Register 1 */
+#define S1DREG_PANEL_TYPE		0x0030	/* Panel Type Register */
+#define S1DREG_MOD_RATE			0x0031	/* MOD Rate Register */
+#define S1DREG_LCD_DISP_HWIDTH		0x0032	/* LCD Horizontal Display Width Register: ((val)+1)*8)=pix/line */
+#define S1DREG_LCD_NDISP_HPER		0x0034	/* LCD Horizontal Non-Display Period Register: ((val)+1)*8)=NDpix/line */
+#define S1DREG_TFT_FPLINE_START		0x0035	/* TFT FPLINE Start Position Register */
+#define S1DREG_TFT_FPLINE_PWIDTH	0x0036	/* TFT FPLINE Pulse Width Register. */
+#define S1DREG_LCD_DISP_VHEIGHT0	0x0038	/* LCD Vertical Display Height Register 0 */
+#define S1DREG_LCD_DISP_VHEIGHT1	0x0039	/* LCD Vertical Display Height Register 1 */
+#define S1DREG_LCD_NDISP_VPER		0x003A	/* LCD Vertical Non-Display Period Register: (val)+1=NDlines */
+#define S1DREG_TFT_FPFRAME_START	0x003B	/* TFT FPFRAME Start Position Register */
+#define S1DREG_TFT_FPFRAME_PWIDTH	0x003C	/* TFT FPFRAME Pulse Width Register */
+#define S1DREG_LCD_DISP_MODE		0x0040	/* LCD Display Mode Register */
+#define S1DREG_LCD_MISC			0x0041	/* LCD Miscellaneous Register */
+#define S1DREG_LCD_DISP_START0		0x0042	/* LCD Display Start Address Register 0 */
+#define S1DREG_LCD_DISP_START1		0x0043	/* LCD Display Start Address Register 1 */
+#define S1DREG_LCD_DISP_START2		0x0044	/* LCD Display Start Address Register 2 */
+#define S1DREG_LCD_MEM_OFF0		0x0046	/* LCD Memory Address Offset Register 0 */
+#define S1DREG_LCD_MEM_OFF1		0x0047	/* LCD Memory Address Offset Register 1 */
+#define S1DREG_LCD_PIX_PAN		0x0048	/* LCD Pixel Panning Register */
+#define S1DREG_LCD_DISP_FIFO_HTC	0x004A	/* LCD Display FIFO High Threshold Control Register */
+#define S1DREG_LCD_DISP_FIFO_LTC	0x004B	/* LCD Display FIFO Low Threshold Control Register */
+#define S1DREG_CRT_DISP_HWIDTH		0x0050	/* CRT/TV Horizontal Display Width Register: ((val)+1)*8)=pix/line */
+#define S1DREG_CRT_NDISP_HPER		0x0052	/* CRT/TV Horizontal Non-Display Period Register */
+#define S1DREG_CRT_HRTC_START		0x0053	/* CRT/TV HRTC Start Position Register */
+#define S1DREG_CRT_HRTC_PWIDTH		0x0054	/* CRT/TV HRTC Pulse Width Register */
+#define S1DREG_CRT_DISP_VHEIGHT0	0x0056	/* CRT/TV Vertical Display Height Register 0 */
+#define S1DREG_CRT_DISP_VHEIGHT1	0x0057	/* CRT/TV Vertical Display Height Register 1 */
+#define S1DREG_CRT_NDISP_VPER		0x0058	/* CRT/TV Vertical Non-Display Period Register */
+#define S1DREG_CRT_VRTC_START		0x0059	/* CRT/TV VRTC Start Position Register */
+#define S1DREG_CRT_VRTC_PWIDTH		0x005A	/* CRT/TV VRTC Pulse Width Register */
+#define S1DREG_TV_OUT_CTL		0x005B	/* TV Output Control Register */
+#define S1DREG_CRT_DISP_MODE		0x0060	/* CRT/TV Display Mode Register */
+#define S1DREG_CRT_DISP_START0		0x0062	/* CRT/TV Display Start Address Register 0 */
+#define S1DREG_CRT_DISP_START1		0x0063	/* CRT/TV Display Start Address Register 1 */
+#define S1DREG_CRT_DISP_START2		0x0064	/* CRT/TV Display Start Address Register 2 */
+#define S1DREG_CRT_MEM_OFF0		0x0066	/* CRT/TV Memory Address Offset Register 0 */
+#define S1DREG_CRT_MEM_OFF1		0x0067	/* CRT/TV Memory Address Offset Register 1 */
+#define S1DREG_CRT_PIX_PAN		0x0068	/* CRT/TV Pixel Panning Register */
+#define S1DREG_CRT_DISP_FIFO_HTC	0x006A	/* CRT/TV Display FIFO High Threshold Control Register */
+#define S1DREG_CRT_DISP_FIFO_LTC	0x006B	/* CRT/TV Display FIFO Low Threshold Control Register */
+#define S1DREG_LCD_CUR_CTL		0x0070	/* LCD Ink/Cursor Control Register */
+#define S1DREG_LCD_CUR_START		0x0071	/* LCD Ink/Cursor Start Address Register */
+#define S1DREG_LCD_CUR_XPOS0		0x0072	/* LCD Cursor X Position Register 0 */
+#define S1DREG_LCD_CUR_XPOS1		0x0073	/* LCD Cursor X Position Register 1 */
+#define S1DREG_LCD_CUR_YPOS0		0x0074	/* LCD Cursor Y Position Register 0 */
+#define S1DREG_LCD_CUR_YPOS1		0x0075	/* LCD Cursor Y Position Register 1 */
+#define S1DREG_LCD_CUR_BCTL0		0x0076	/* LCD Ink/Cursor Blue Color 0 Register */
+#define S1DREG_LCD_CUR_GCTL0		0x0077	/* LCD Ink/Cursor Green Color 0 Register */
+#define S1DREG_LCD_CUR_RCTL0		0x0078	/* LCD Ink/Cursor Red Color 0 Register */
+#define S1DREG_LCD_CUR_BCTL1		0x007A	/* LCD Ink/Cursor Blue Color 1 Register */
+#define S1DREG_LCD_CUR_GCTL1		0x007B	/* LCD Ink/Cursor Green Color 1 Register */
+#define S1DREG_LCD_CUR_RCTL1		0x007C	/* LCD Ink/Cursor Red Color 1 Register */
+#define S1DREG_LCD_CUR_FIFO_HTC		0x007E	/* LCD Ink/Cursor FIFO High Threshold Register */
+#define S1DREG_CRT_CUR_CTL		0x0080	/* CRT/TV Ink/Cursor Control Register */
+#define S1DREG_CRT_CUR_START		0x0081	/* CRT/TV Ink/Cursor Start Address Register */
+#define S1DREG_CRT_CUR_XPOS0		0x0082	/* CRT/TV Cursor X Position Register 0 */
+#define S1DREG_CRT_CUR_XPOS1		0x0083	/* CRT/TV Cursor X Position Register 1 */
+#define S1DREG_CRT_CUR_YPOS0		0x0084	/* CRT/TV Cursor Y Position Register 0 */
+#define S1DREG_CRT_CUR_YPOS1		0x0085	/* CRT/TV Cursor Y Position Register 1 */
+#define S1DREG_CRT_CUR_BCTL0		0x0086	/* CRT/TV Ink/Cursor Blue Color 0 Register */
+#define S1DREG_CRT_CUR_GCTL0		0x0087	/* CRT/TV Ink/Cursor Green Color 0 Register */
+#define S1DREG_CRT_CUR_RCTL0		0x0088	/* CRT/TV Ink/Cursor Red Color 0 Register */
+#define S1DREG_CRT_CUR_BCTL1		0x008A	/* CRT/TV Ink/Cursor Blue Color 1 Register */
+#define S1DREG_CRT_CUR_GCTL1		0x008B	/* CRT/TV Ink/Cursor Green Color 1 Register */
+#define S1DREG_CRT_CUR_RCTL1		0x008C	/* CRT/TV Ink/Cursor Red Color 1 Register */
+#define S1DREG_CRT_CUR_FIFO_HTC		0x008E	/* CRT/TV Ink/Cursor FIFO High Threshold Register */
+#define S1DREG_BBLT_CTL0		0x0100	/* BitBLT Control Register 0 */
+#define S1DREG_BBLT_CTL1		0x0101	/* BitBLT Control Register 1 */
+#define S1DREG_BBLT_CC_EXP		0x0102	/* BitBLT Code/Color Expansion Register */
+#define S1DREG_BBLT_OP			0x0103	/* BitBLT Operation Register */
+#define S1DREG_BBLT_SRC_START0		0x0104	/* BitBLT Source Start Address Register 0 */
+#define S1DREG_BBLT_SRC_START1		0x0105	/* BitBLT Source Start Address Register 1 */
+#define S1DREG_BBLT_SRC_START2		0x0106	/* BitBLT Source Start Address Register 2 */
+#define S1DREG_BBLT_DST_START0		0x0108	/* BitBLT Destination Start Address Register 0 */
+#define S1DREG_BBLT_DST_START1		0x0109	/* BitBLT Destination Start Address Register 1 */
+#define S1DREG_BBLT_DST_START2		0x010A	/* BitBLT Destination Start Address Register 2 */
+#define S1DREG_BBLT_MEM_OFF0		0x010C	/* BitBLT Memory Address Offset Register 0 */
+#define S1DREG_BBLT_MEM_OFF1		0x010D	/* BitBLT Memory Address Offset Register 1 */
+#define S1DREG_BBLT_WIDTH0		0x0110	/* BitBLT Width Register 0 */
+#define S1DREG_BBLT_WIDTH1		0x0111	/* BitBLT Width Register 1 */
+#define S1DREG_BBLT_HEIGHT0		0x0112	/* BitBLT Height Register 0 */
+#define S1DREG_BBLT_HEIGHT1		0x0113	/* BitBLT Height Register 1 */
+#define S1DREG_BBLT_BGC0		0x0114	/* BitBLT Background Color Register 0 */
+#define S1DREG_BBLT_BGC1		0x0115	/* BitBLT Background Color Register 1 */
+#define S1DREG_BBLT_FGC0		0x0118	/* BitBLT Foreground Color Register 0 */
+#define S1DREG_BBLT_FGC1		0x0119	/* BitBLT Foreground Color Register 1 */
+#define S1DREG_LKUP_MODE		0x01E0	/* Look-Up Table Mode Register */
+#define S1DREG_LKUP_ADDR		0x01E2	/* Look-Up Table Address Register */
+#define S1DREG_LKUP_DATA		0x01E4	/* Look-Up Table Data Register */
+#define S1DREG_PS_CNF			0x01F0	/* Power Save Configuration Register */
+#define S1DREG_PS_STATUS		0x01F1	/* Power Save Status Register */
+#define S1DREG_CPU2MEM_WDOGT		0x01F4	/* CPU-to-Memory Access Watchdog Timer Register */
+#define S1DREG_COM_DISP_MODE		0x01FC	/* Common Display Mode Register */
+
+#define S1DREG_DELAYOFF			0xFFFE
+#define S1DREG_DELAYON			0xFFFF
+
+/* Note: all above defines should go in separate header files
+   when implementing other S1D13xxx chip support. */
+
+struct s1d13xxxfb_regval {
+	u16	addr;
+	u8	value;
+};
+
+
+struct s1d13xxxfb_par {
+	void __iomem	*regs;
+	unsigned char	display;
+
+	unsigned int	pseudo_palette[16];
+#ifdef CONFIG_PM
+	void		*regs_save;	/* pm saves all registers here */
+	void		*disp_save;	/* pm saves entire screen here */
+#endif
+};
+
+struct s1d13xxxfb_pdata {
+	const struct s1d13xxxfb_regval	*initregs;
+	const unsigned int		initregssize;
+	void				(*platform_init_video)(void);
+#ifdef CONFIG_PM
+	int				(*platform_suspend_video)(void);
+	int				(*platform_resume_video)(void);
+#endif
+};
+
+#endif
+
diff --git a/include/video/tdfx.h b/include/video/tdfx.h
--- a/include/video/tdfx.h
+++ b/include/video/tdfx.h
@@ -99,6 +99,8 @@
 #define MISCINIT1_2DBLOCK_DIS           BIT(15)
 #define DRAMINIT0_SGRAM_NUM             BIT(26)
 #define DRAMINIT0_SGRAM_TYPE            BIT(27)
+#define DRAMINIT0_SGRAM_TYPE_MASK       (BIT(27)|BIT(28)|BIT(29))
+#define DRAMINIT0_SGRAM_TYPE_SHIFT      27
 #define DRAMINIT1_MEM_SDRAM             BIT(30)
 #define VGAINIT0_VGA_DISABLE            BIT(0)
 #define VGAINIT0_EXT_TIMING             BIT(1)
diff --git a/include/video/trident.h b/include/video/trident.h
--- a/include/video/trident.h
+++ b/include/video/trident.h
@@ -9,7 +9,7 @@
 #define debug(f,a...)
 #endif
 
-#define output(f, a...) printk("tridentfb: " f, ## a)
+#define output(f, a...) pr_info("tridentfb: " f, ## a)
 
 #define Kb	(1024)
 #define Mb	(Kb*Kb)
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -55,6 +55,14 @@ config LOCK_KERNEL
 	depends on SMP || PREEMPT
 	default y
 
+config INIT_ENV_ARG_LIMIT
+	int
+	default 32 if !USERMODE
+	default 128 if USERMODE
+	help
+	  This is the value of the two limits on the number of argument and of
+	  env.var passed to init from the kernel command line.
+
 endmenu
 
 menu "General setup"
@@ -157,7 +165,6 @@ config SYSCTL
 config AUDIT
 	bool "Auditing support"
 	default y if SECURITY_SELINUX
-	default n
 	help
 	  Enable auditing infrastructure that can be used with another
 	  kernel subsystem, such as SELinux (which requires this for
@@ -166,31 +173,13 @@ config AUDIT
 
 config AUDITSYSCALL
 	bool "Enable system-call auditing support"
-	depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64)
+	depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64 || UML)
 	default y if SECURITY_SELINUX
-	default n
 	help
 	  Enable low-overhead system-call auditing infrastructure that
 	  can be used independently or with another kernel subsystem,
 	  such as SELinux.
 
-config LOG_BUF_SHIFT
-	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
-	range 12 21
-	default 17 if ARCH_S390
-	default 16 if X86_NUMAQ || IA64
-	default 15 if SMP
-	default 14
-	help
-	  Select kernel log buffer size as a power of 2.
-	  Defaults and Examples:
-	  	     17 => 128 KB for S/390
-		     16 => 64 KB for x86 NUMAQ or IA-64
-	             15 => 32 KB for SMP
-	             14 => 16 KB for uniprocessor
-		     13 =>  8 KB
-		     12 =>  4 KB
-
 config HOTPLUG
 	bool "Support for hot-pluggable devices" if !ARCH_S390
 	default ARCH_S390
@@ -237,6 +226,16 @@ config IKCONFIG_PROC
 	  This option enables access to the kernel configuration file
 	  through /proc/config.gz.
 
+config CPUSETS
+	bool "Cpuset support"
+	depends on SMP
+	help
+	  This options will let you create and manage CPUSET's which
+	  allow dynamically partitioning a system into sets of CPUs and
+	  Memory Nodes and assigning tasks to run only within those sets.
+	  This is primarily useful on large SMP or NUMA systems.
+
+	  Say N if unsure.
 
 menuconfig EMBEDDED
 	bool "Configure standard kernel features (for small systems)"
@@ -276,6 +275,35 @@ config KALLSYMS_EXTRA_PASS
 	   reported.  KALLSYMS_EXTRA_PASS is only a temporary workaround while
 	   you wait for kallsyms to be fixed.
 
+
+config PRINTK
+	default y
+	bool "Enable support for printk" if EMBEDDED
+	help
+	  This option enables normal printk support. Removing it
+	  eliminates most of the message strings from the kernel image
+	  and makes the kernel more or less silent. As this makes it
+	  very difficult to diagnose system problems, saying N here is
+	  strongly discouraged.
+
+config BUG
+	bool "BUG() support" if EMBEDDED
+	default y
+	help
+          Disabling this option eliminates support for BUG and WARN, reducing
+          the size of your kernel image and potentially quietly ignoring
+          numerous fatal conditions. You should only consider disabling this
+          option for embedded systems with no facilities for reporting errors.
+          Just say Y.
+
+config BASE_FULL
+	default y
+	bool "Enable full-sized data structures for core" if EMBEDDED
+	help
+	  Disabling this option reduces the size of miscellaneous core
+	  kernel data structures. This saves memory on small machines,
+	  but may reduce performance.
+
 config FUTEX
 	bool "Enable futex support" if EMBEDDED
 	default y
@@ -294,7 +322,6 @@ config EPOLL
 config CC_OPTIMIZE_FOR_SIZE
 	bool "Optimize for size" if EMBEDDED
 	default y if ARM || H8300
-	default n
 	help
 	  Enabling this option will pass "-Os" instead of "-O2" to gcc
 	  resulting in a smaller kernel.
@@ -358,6 +385,11 @@ config TINY_SHMEM
 	default !SHMEM
 	bool
 
+config BASE_SMALL
+	int
+	default 0 if BASE_FULL
+	default 1 if !BASE_FULL
+
 menu "Loadable module support"
 
 config MODULES
@@ -410,7 +442,7 @@ config OBSOLETE_MODPARM
 
 config MODVERSIONS
 	bool "Module versioning support (EXPERIMENTAL)"
-	depends on MODULES && EXPERIMENTAL && !USERMODE
+	depends on MODULES && EXPERIMENTAL
 	help
 	  Usually, you have to use modules compiled with your kernel.
 	  Saying Y here makes it sometimes possible to use modules
diff --git a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -53,7 +53,7 @@ static int __init readwrite(char *str)
 __setup("ro", readonly);
 __setup("rw", readwrite);
 
-static dev_t __init try_name(char *name, int part)
+static dev_t try_name(char *name, int part)
 {
 	char path[64];
 	char buf[32];
@@ -135,7 +135,7 @@ fail:
  *	is mounted on rootfs /sys.
  */
 
-dev_t __init name_to_dev_t(char *name)
+dev_t name_to_dev_t(char *name)
 {
 	char s[32];
 	char *p;
diff --git a/init/main.c b/init/main.c
--- a/init/main.c
+++ b/init/main.c
@@ -41,6 +41,7 @@
 #include <linux/kallsyms.h>
 #include <linux/writeback.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/efi.h>
 #include <linux/unistd.h>
 #include <linux/rmap.h>
@@ -109,8 +110,8 @@ EXPORT_SYMBOL(system_state);
 /*
  * Boot command-line arguments
  */
-#define MAX_INIT_ARGS 32
-#define MAX_INIT_ENVS 32
+#define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT
+#define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT
 
 extern void time_init(void);
 /* Default late time init is NULL. archs can override this later. */
@@ -209,6 +210,14 @@ static int __init quiet_kernel(char *str
 __setup("debug", debug_kernel);
 __setup("quiet", quiet_kernel);
 
+static int __init loglevel(char *str)
+{
+	get_option(&str, &console_loglevel);
+	return 1;
+}
+
+__setup("loglevel=", loglevel);
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * failed parameters
@@ -347,12 +356,11 @@ static void __init smp_init(void)
 	}
 
 	/* Any cleanup work */
-	printk("Brought up %ld CPUs\n", (long)num_online_cpus());
+	printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus());
 	smp_cpus_done(max_cpus);
 #if 0
 	/* Get other processors into their bootup holding patterns. */
 
-	smp_threads_ready=1;
 	smp_commence();
 #endif
 }
@@ -423,6 +431,7 @@ asmlinkage void __init start_kernel(void
  */
 	lock_kernel();
 	page_address_init();
+	printk(KERN_NOTICE);
 	printk(linux_banner);
 	setup_arch(&command_line);
 	setup_per_cpu_areas();
@@ -446,7 +455,7 @@ asmlinkage void __init start_kernel(void
 	preempt_disable();
 	build_all_zonelists();
 	page_alloc_init();
-	printk("Kernel command line: %s\n", saved_command_line);
+	printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);
 	parse_early_param();
 	parse_args("Booting kernel", command_line, __start___param,
 		   __stop___param - __start___param,
@@ -497,6 +506,7 @@ asmlinkage void __init start_kernel(void
 	proc_caches_init();
 	buffer_init();
 	unnamed_dev_init();
+	key_init();
 	security_init();
 	vfs_caches_init(num_physpages);
 	radix_tree_init();
@@ -506,6 +516,8 @@ asmlinkage void __init start_kernel(void
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
+	cpuset_init();
+
 	check_bugs();
 
 	acpi_early_init(); /* before LAPIC and SMP init */
@@ -553,7 +565,7 @@ static void __init do_initcalls(void)
 			local_irq_enable();
 		}
 		if (msg) {
-			printk("error in initcall at 0x%p: "
+			printk(KERN_WARNING "error in initcall at 0x%p: "
 				"returned with %s\n", *call, msg);
 		}
 	}
@@ -574,7 +586,6 @@ static void __init do_basic_setup(void)
 	/* drivers will send hotplug events */
 	init_workqueues();
 	usermodehelper_init();
-	key_init();
 	driver_init();
 
 #ifdef CONFIG_SYSCTL
@@ -626,6 +637,10 @@ static int init(void * unused)
 {
 	lock_kernel();
 	/*
+	 * init can run on any cpu.
+	 */
+	set_cpus_allowed(current, CPU_MASK_ALL);
+	/*
 	 * Tell the world that we're going to be the grim
 	 * reaper of innocent orphaned children.
 	 *
@@ -644,6 +659,8 @@ static int init(void * unused)
 	smp_init();
 	sched_init_smp();
 
+	cpuset_init_smp();
+
 	/*
 	 * Do this before initcalls, because some drivers want to access
 	 * firmware files.
@@ -672,7 +689,7 @@ static int init(void * unused)
 	numa_default_policy();
 
 	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
-		printk("Warning: unable to open an initial console.\n");
+		printk(KERN_WARNING "Warning: unable to open an initial console.\n");
 
 	(void) sys_dup(0);
 	(void) sys_dup(0);
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -25,7 +25,7 @@ struct compat_mq_attr {
 static inline int get_compat_mq_attr(struct mq_attr *attr,
 			const struct compat_mq_attr __user *uattr)
 {
-	if (verify_area(VERIFY_READ, uattr, sizeof *uattr))
+	if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
 		return -EFAULT;
 
 	return __get_user(attr->mq_flags, &uattr->mq_flags)
@@ -102,20 +102,6 @@ asmlinkage ssize_t compat_sys_mq_timedre
 			u_msg_prio, u_ts);
 }
 
-static int get_compat_sigevent(struct sigevent *event,
-		const struct compat_sigevent __user *u_event)
-{
-	if (verify_area(VERIFY_READ, u_event, sizeof(*u_event)))
-		return -EFAULT;
-
-	return __get_user(event->sigev_value.sival_int,
-			  &u_event->sigev_value.sival_int)
-	     | __get_user(event->sigev_signo, &u_event->sigev_signo)
-	     | __get_user(event->sigev_notify, &u_event->sigev_notify)
-	     | __get_user(event->sigev_notify_thread_id,
-			  &u_event->sigev_notify_thread_id);
-}
-
 asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
 			const struct compat_sigevent __user *u_notification)
 {
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -23,6 +23,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/syscalls.h>
+#include <linux/signal.h>
 #include <net/sock.h>
 #include "util.h"
 
@@ -767,7 +768,7 @@ static inline void pipelined_send(struct
 	list_del(&receiver->list);
 	receiver->state = STATE_PENDING;
 	wake_up_process(receiver->task);
-	wmb();
+	smp_wmb();
 	receiver->state = STATE_READY;
 }
 
@@ -786,7 +787,7 @@ static inline void pipelined_receive(str
 	list_del(&sender->list);
 	sender->state = STATE_PENDING;
 	wake_up_process(sender->task);
-	wmb();
+	smp_wmb();
 	sender->state = STATE_READY;
 }
 
@@ -976,8 +977,7 @@ asmlinkage long sys_mq_notify(mqd_t mqde
 			     notification.sigev_notify != SIGEV_THREAD))
 			return -EINVAL;
 		if (notification.sigev_notify == SIGEV_SIGNAL &&
-			(notification.sigev_signo < 0 ||
-			 notification.sigev_signo > _NSIG)) {
+			!valid_signal(notification.sigev_signo)) {
 			return -EINVAL;
 		}
 		if (notification.sigev_notify == SIGEV_THREAD) {
diff --git a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -25,6 +25,7 @@
 #include <linux/security.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -425,6 +426,8 @@ asmlinkage long sys_msgctl (int msqid, i
 			return -EFAULT;
 		if (copy_msqid_from_user (&setbuf, buf, version))
 			return -EFAULT;
+		if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
+			return err;
 		break;
 	case IPC_RMID:
 		break;
diff --git a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -72,6 +72,7 @@
 #include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -803,6 +804,8 @@ static int semctl_down(int semid, int se
 	if(cmd == IPC_SET) {
 		if(copy_semid_from_user (&setbuf, arg.buf, version))
 			return -EFAULT;
+		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+			return err;
 	}
 	sma = sem_lock(semid);
 	if(sma==NULL)
diff --git a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -27,6 +27,9 @@
 #include <linux/shmem_fs.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
+#include <linux/ptrace.h>
+
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -600,6 +603,8 @@ asmlinkage long sys_shmctl (int shmid, i
 			err = -EFAULT;
 			goto out;
 		}
+		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+			return err;
 		down(&shm_ids.sem);
 		shp = shm_lock(shmid);
 		err=-EINVAL;
@@ -768,6 +773,18 @@ out:
 	return err;
 }
 
+asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
+{
+	unsigned long ret;
+	long err;
+
+	err = do_shmat(shmid, shmaddr, shmflg, &ret);
+	if (err)
+		return err;
+	force_successful_syscall_return();
+	return (long)ret;
+}
+
 /*
  * detach and kill segment if marked destroyed.
  * The work is done in shm_close.
diff --git a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -7,7 +7,7 @@ obj-y     = sched.o fork.o exec_domain.o
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
-	    kthread.o wait.o kfifo.o sys_ni.o
+	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
@@ -18,6 +18,7 @@ obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
@@ -26,8 +27,9 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
+obj-$(CONFIG_SECCOMP) += seccomp.o
 
-ifneq ($(CONFIG_IA64),y)
+ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
 # needed for x86 only.  Why this used to be enabled for all architectures is beyond
 # me.  I suspect most platforms don't need this, but until we know that for sure
@@ -45,7 +47,7 @@ $(obj)/config_data.gz: .config FORCE
 	$(call if_changed,gzip)
 
 quiet_cmd_ikconfiggz = IKCFG   $@
-      cmd_ikconfiggz = (echo "const char kernel_config_data[] = MAGIC_START"; cat $< | scripts/bin2c; echo "MAGIC_END;") > $@
+      cmd_ikconfiggz = (echo "static const char kernel_config_data[] = MAGIC_START"; cat $< | scripts/bin2c; echo "MAGIC_END;") > $@
 targets += config_data.h
 $(obj)/config_data.h: $(obj)/config_data.gz FORCE
 	$(call if_changed,ikconfiggz)
diff --git a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -170,7 +170,7 @@ out:
  *
  * NOTE: acct_globals.lock MUST be held on entry and exit.
  */
-void acct_file_reopen(struct file *file)
+static void acct_file_reopen(struct file *file)
 {
 	struct file *old_acct = NULL;
 
@@ -534,17 +534,15 @@ void acct_process(long exitcode)
  * acct_update_integrals
  *    -  update mm integral fields in task_struct
  */
-void acct_update_integrals(void)
+void acct_update_integrals(struct task_struct *tsk)
 {
-	struct task_struct *tsk = current;
-
 	if (likely(tsk->mm)) {
 		long delta = tsk->stime - tsk->acct_stimexpd;
 
 		if (delta == 0)
 			return;
 		tsk->acct_stimexpd = tsk->stime;
-		tsk->acct_rss_mem1 += delta * tsk->mm->rss;
+		tsk->acct_rss_mem1 += delta * get_mm_counter(tsk->mm, rss);
 		tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
 	}
 }
diff --git a/kernel/audit.c b/kernel/audit.c
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1,4 +1,4 @@
-/* audit.c -- Auditing support -*- linux-c -*-
+/* audit.c -- Auditing support
  * Gateway between the kernel (e.g., selinux) and the user-space audit daemon.
  * System-call specific features have moved to auditsc.c
  *
@@ -38,7 +38,7 @@
  *	  6) Support low-overhead kernel-based filtering to minimize the
  *	     information that must be passed to user-space.
  *
- * Example user-space utilities: http://people.redhat.com/faith/audit/
+ * Example user-space utilities: http://people.redhat.com/sgrubb/audit/
  */
 
 #include <linux/init.h>
@@ -142,7 +142,6 @@ struct audit_buffer {
 	int		     total;
 	int		     type;
 	int		     pid;
-	int		     count; /* Times requeued */
 };
 
 void audit_set_type(struct audit_buffer *ab, int type)
@@ -155,6 +154,9 @@ struct audit_entry {
 	struct audit_rule rule;
 };
 
+static void audit_log_end_irq(struct audit_buffer *ab);
+static void audit_log_end_fast(struct audit_buffer *ab);
+
 static void audit_panic(const char *message)
 {
 	switch (audit_failure)
@@ -236,36 +238,36 @@ void audit_log_lost(const char *message)
 
 }
 
-int audit_set_rate_limit(int limit)
+static int audit_set_rate_limit(int limit, uid_t loginuid)
 {
 	int old		 = audit_rate_limit;
 	audit_rate_limit = limit;
-	audit_log(current->audit_context, "audit_rate_limit=%d old=%d",
-		  audit_rate_limit, old);
+	audit_log(NULL, "audit_rate_limit=%d old=%d by auid %u",
+			audit_rate_limit, old, loginuid);
 	return old;
 }
 
-int audit_set_backlog_limit(int limit)
+static int audit_set_backlog_limit(int limit, uid_t loginuid)
 {
 	int old		 = audit_backlog_limit;
 	audit_backlog_limit = limit;
-	audit_log(current->audit_context, "audit_backlog_limit=%d old=%d",
-		  audit_backlog_limit, old);
+	audit_log(NULL, "audit_backlog_limit=%d old=%d by auid %u",
+			audit_backlog_limit, old, loginuid);
 	return old;
 }
 
-int audit_set_enabled(int state)
+static int audit_set_enabled(int state, uid_t loginuid)
 {
 	int old		 = audit_enabled;
 	if (state != 0 && state != 1)
 		return -EINVAL;
 	audit_enabled = state;
-	audit_log(current->audit_context, "audit_enabled=%d old=%d",
-		  audit_enabled, old);
+	audit_log(NULL, "audit_enabled=%d old=%d by auid %u",
+		  audit_enabled, old, loginuid);
 	return old;
 }
 
-int audit_set_failure(int state)
+static int audit_set_failure(int state, uid_t loginuid)
 {
 	int old		 = audit_failure;
 	if (state != AUDIT_FAIL_SILENT
@@ -273,8 +275,8 @@ int audit_set_failure(int state)
 	    && state != AUDIT_FAIL_PANIC)
 		return -EINVAL;
 	audit_failure = state;
-	audit_log(current->audit_context, "audit_failure=%d old=%d",
-		  audit_failure, old);
+	audit_log(NULL, "audit_failure=%d old=%d by auid %u",
+		  audit_failure, old, loginuid);
 	return old;
 }
 
@@ -341,6 +343,7 @@ static int audit_receive_msg(struct sk_b
 	int			err;
 	struct audit_buffer	*ab;
 	u16			msg_type = nlh->nlmsg_type;
+	uid_t			loginuid; /* loginuid of sender */
 
 	err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
 	if (err)
@@ -348,6 +351,7 @@ static int audit_receive_msg(struct sk_b
 
 	pid  = NETLINK_CREDS(skb)->pid;
 	uid  = NETLINK_CREDS(skb)->uid;
+	loginuid = NETLINK_CB(skb).loginuid;
 	seq  = nlh->nlmsg_seq;
 	data = NLMSG_DATA(nlh);
 
@@ -368,34 +372,36 @@ static int audit_receive_msg(struct sk_b
 			return -EINVAL;
 		status_get   = (struct audit_status *)data;
 		if (status_get->mask & AUDIT_STATUS_ENABLED) {
-			err = audit_set_enabled(status_get->enabled);
+			err = audit_set_enabled(status_get->enabled, loginuid);
 			if (err < 0) return err;
 		}
 		if (status_get->mask & AUDIT_STATUS_FAILURE) {
-			err = audit_set_failure(status_get->failure);
+			err = audit_set_failure(status_get->failure, loginuid);
 			if (err < 0) return err;
 		}
 		if (status_get->mask & AUDIT_STATUS_PID) {
 			int old   = audit_pid;
 			audit_pid = status_get->pid;
-			audit_log(current->audit_context,
-				  "audit_pid=%d old=%d", audit_pid, old);
+			audit_log(NULL, "audit_pid=%d old=%d by auid %u",
+				  audit_pid, old, loginuid);
 		}
 		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
-			audit_set_rate_limit(status_get->rate_limit);
+			audit_set_rate_limit(status_get->rate_limit, loginuid);
 		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
-			audit_set_backlog_limit(status_get->backlog_limit);
+			audit_set_backlog_limit(status_get->backlog_limit,
+							loginuid);
 		break;
 	case AUDIT_USER:
 		ab = audit_log_start(NULL);
 		if (!ab)
 			break;	/* audit_panic has been called */
 		audit_log_format(ab,
-				 "user pid=%d uid=%d length=%d msg='%.1024s'",
+				 "user pid=%d uid=%d length=%d loginuid=%u"
+				 " msg='%.1024s'",
 				 pid, uid,
 				 (int)(nlh->nlmsg_len
 				       - ((char *)data - (char *)nlh)),
-				 (char *)data);
+				 loginuid, (char *)data);
 		ab->type = AUDIT_USER;
 		ab->pid  = pid;
 		audit_log_end(ab);
@@ -408,7 +414,7 @@ static int audit_receive_msg(struct sk_b
 	case AUDIT_LIST:
 #ifdef CONFIG_AUDITSYSCALL
 		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
-					   uid, seq, data);
+					   uid, seq, data, loginuid);
 #else
 		err = -EOPNOTSUPP;
 #endif
@@ -424,7 +430,7 @@ static int audit_receive_msg(struct sk_b
 /* Get message from skb (based on rtnetlink_rcv_skb).  Each message is
  * processed by audit_receive_msg.  Malformed skbs with wrong length are
  * discarded silently.  */
-static int audit_receive_skb(struct sk_buff *skb)
+static void audit_receive_skb(struct sk_buff *skb)
 {
 	int		err;
 	struct nlmsghdr	*nlh;
@@ -433,7 +439,7 @@ static int audit_receive_skb(struct sk_b
 	while (skb->len >= NLMSG_SPACE(0)) {
 		nlh = (struct nlmsghdr *)skb->data;
 		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
-			return 0;
+			return;
 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
 		if (rlen > skb->len)
 			rlen = skb->len;
@@ -443,23 +449,20 @@ static int audit_receive_skb(struct sk_b
 			netlink_ack(skb, nlh, 0);
 		skb_pull(skb, rlen);
 	}
-	return 0;
 }
 
 /* Receive messages from netlink socket. */
 static void audit_receive(struct sock *sk, int length)
 {
 	struct sk_buff  *skb;
+	unsigned int qlen;
 
-	if (down_trylock(&audit_netlink_sem))
-		return;
+	down(&audit_netlink_sem);
 
-				/* FIXME: this must not cause starvation */
-	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
-		if (audit_receive_skb(skb) && skb->len)
-			skb_queue_head(&sk->sk_receive_queue, skb);
-		else
-			kfree_skb(skb);
+	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+		audit_receive_skb(skb);
+		kfree_skb(skb);
 	}
 	up(&audit_netlink_sem);
 }
@@ -480,7 +483,7 @@ static void audit_log_move(struct audit_
 	if (ab->len == 0)
 		return;
 
-	skb = skb_peek(&ab->sklist);
+	skb = skb_peek_tail(&ab->sklist);
 	if (!skb || skb_tailroom(skb) <= ab->len + extra) {
 		skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC);
 		if (!skb) {
@@ -519,9 +522,9 @@ static inline int audit_log_drain(struct
 			retval = netlink_unicast(audit_sock, skb, audit_pid,
 						 MSG_DONTWAIT);
 		}
-		if (retval == -EAGAIN && ab->count < 5) {
-			++ab->count;
-			skb_queue_tail(&ab->sklist, skb);
+		if (retval == -EAGAIN &&
+		    (atomic_read(&audit_backlog)) < audit_backlog_limit) {
+			skb_queue_head(&ab->sklist, skb);
 			audit_log_end_irq(ab);
 			return 1;
 		}
@@ -537,8 +540,8 @@ static inline int audit_log_drain(struct
 		if (!audit_pid) { /* No daemon */
 			int offset = ab->nlh ? NLMSG_SPACE(0) : 0;
 			int len    = skb->len - offset;
-			printk(KERN_ERR "%*.*s\n",
-			       len, len, skb->data + offset);
+			skb->data[offset + len] = '\0';
+			printk(KERN_ERR "%s\n", skb->data + offset);
 		}
 		kfree_skb(skb);
 		ab->nlh = NULL;
@@ -547,7 +550,7 @@ static inline int audit_log_drain(struct
 }
 
 /* Initialize audit support at boot time. */
-int __init audit_init(void)
+static int __init audit_init(void)
 {
 	printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
 	       audit_default ? "enabled" : "disabled");
@@ -617,7 +620,7 @@ struct audit_buffer *audit_log_start(str
 	struct audit_buffer	*ab	= NULL;
 	unsigned long		flags;
 	struct timespec		t;
-	int			serial	= 0;
+	unsigned int		serial;
 
 	if (!audit_initialized)
 		return NULL;
@@ -659,15 +662,16 @@ struct audit_buffer *audit_log_start(str
 	ab->total = 0;
 	ab->type  = AUDIT_KERNEL;
 	ab->pid   = 0;
-	ab->count = 0;
 
 #ifdef CONFIG_AUDITSYSCALL
 	if (ab->ctx)
 		audit_get_stamp(ab->ctx, &t, &serial);
 	else
 #endif
+	{
 		t = CURRENT_TIME;
-
+		serial = 0;
+	}
 	audit_log_format(ab, "audit(%lu.%03lu:%u): ",
 			 t.tv_sec, t.tv_nsec/1000000, serial);
 	return ab;
@@ -717,6 +721,29 @@ void audit_log_format(struct audit_buffe
 	va_end(args);
 }
 
+void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len)
+{
+	int i;
+
+	for (i=0; i<len; i++)
+		audit_log_format(ab, "%02x", buf[i]);
+}
+
+void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+{
+	const unsigned char *p = string;
+
+	while (*p) {
+		if (*p == '"' || *p == ' ' || *p < 0x20 || *p > 0x7f) {
+			audit_log_hex(ab, string, strlen(string));
+			return;
+		}
+		p++;
+	}
+	audit_log_format(ab, "\"%s\"", string);
+}
+
+
 /* This is a helper-function to print the d_path without using a static
  * buffer or allocating another buffer in addition to the one in
  * audit_buffer. */
@@ -768,7 +795,7 @@ static DECLARE_TASKLET(audit_tasklet, au
  * the audit buffer is places on a queue and a tasklet is scheduled to
  * remove them from the queue outside the irq context.  May be called in
  * any context. */
-void audit_log_end_irq(struct audit_buffer *ab)
+static void audit_log_end_irq(struct audit_buffer *ab)
 {
 	unsigned long flags;
 
@@ -783,7 +810,7 @@ void audit_log_end_irq(struct audit_buff
 
 /* Send the message in the audit buffer directly to user space.  May not
  * be called in an irq context. */
-void audit_log_end_fast(struct audit_buffer *ab)
+static void audit_log_end_fast(struct audit_buffer *ab)
 {
 	unsigned long flags;
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1,4 +1,4 @@
-/* auditsc.c -- System-call auditing support -*- linux-c -*-
+/* auditsc.c -- System-call auditing support
  * Handles all system-call specific auditing features.
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
@@ -89,9 +89,30 @@ enum audit_state {
 struct audit_names {
 	const char	*name;
 	unsigned long	ino;
+	dev_t		dev;
+	umode_t		mode;
+	uid_t		uid;
+	gid_t		gid;
 	dev_t		rdev;
 };
 
+struct audit_aux_data {
+	struct audit_aux_data	*next;
+	int			type;
+};
+
+#define AUDIT_AUX_IPCPERM	0
+
+struct audit_aux_data_ipcctl {
+	struct audit_aux_data	d;
+	struct ipc_perm		p;
+	unsigned long		qbytes;
+	uid_t			uid;
+	gid_t			gid;
+	mode_t			mode;
+};
+
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    in_syscall;	/* 1 if task is in a syscall */
@@ -102,17 +123,19 @@ struct audit_context {
 	int		    major;      /* syscall number */
 	unsigned long	    argv[4];    /* syscall arguments */
 	int		    return_valid; /* return code is valid */
-	int		    return_code;/* syscall return code */
+	long		    return_code;/* syscall return code */
 	int		    auditable;  /* 1 if record should be written */
 	int		    name_count;
 	struct audit_names  names[AUDIT_NAMES];
 	struct audit_context *previous; /* For nested syscalls */
+	struct audit_aux_data *aux;
 
 				/* Save things to print about task_struct */
 	pid_t		    pid;
 	uid_t		    uid, euid, suid, fsuid;
 	gid_t		    gid, egid, sgid, fsgid;
 	unsigned long	    personality;
+	int		    arch;
 
 #if AUDIT_DEBUG
 	int		    put_count;
@@ -228,7 +251,8 @@ static int audit_copy_rule(struct audit_
 	return 0;
 }
 
-int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
+int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
+							uid_t loginuid)
 {
 	u32		   flags;
 	struct audit_entry *entry;
@@ -263,6 +287,7 @@ int audit_receive_filter(int type, int p
 			err = audit_add_rule(entry, &audit_entlist);
 		if (!err && (flags & AUDIT_AT_EXIT))
 			err = audit_add_rule(entry, &audit_extlist);
+		audit_log(NULL, "auid %u added an audit rule\n", loginuid);
 		break;
 	case AUDIT_DEL:
 		flags =((struct audit_rule *)data)->flags;
@@ -272,6 +297,7 @@ int audit_receive_filter(int type, int p
 			err = audit_del_rule(data, &audit_entlist);
 		if (!err && (flags & AUDIT_AT_EXIT))
 			err = audit_del_rule(data, &audit_extlist);
+		audit_log(NULL, "auid %u removed an audit rule\n", loginuid);
 		break;
 	default:
 		return -EINVAL;
@@ -326,6 +352,10 @@ static int audit_filter_rules(struct tas
 		case AUDIT_PERS:
 			result = (tsk->personality == value);
 			break;
+		case AUDIT_ARCH:
+			if (ctx) 
+				result = (ctx->arch == value);
+			break;
 
 		case AUDIT_EXIT:
 			if (ctx && ctx->return_valid)
@@ -333,12 +363,12 @@ static int audit_filter_rules(struct tas
 			break;
 		case AUDIT_SUCCESS:
 			if (ctx && ctx->return_valid)
-				result = (ctx->return_code >= 0);
+				result = (ctx->return_valid == AUDITSC_SUCCESS);
 			break;
 		case AUDIT_DEVMAJOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MAJOR(ctx->names[j].rdev)==value) {
+					if (MAJOR(ctx->names[j].dev)==value) {
 						++result;
 						break;
 					}
@@ -348,7 +378,7 @@ static int audit_filter_rules(struct tas
 		case AUDIT_DEVMINOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MINOR(ctx->names[j].rdev)==value) {
+					if (MINOR(ctx->names[j].dev)==value) {
 						++result;
 						break;
 					}
@@ -504,6 +534,16 @@ static inline void audit_free_names(stru
 	context->name_count = 0;
 }
 
+static inline void audit_free_aux(struct audit_context *context)
+{
+	struct audit_aux_data *aux;
+
+	while ((aux = context->aux)) {
+		context->aux = aux->next;
+		kfree(aux);
+	}
+}
+
 static inline void audit_zero_context(struct audit_context *context,
 				      enum audit_state state)
 {
@@ -570,6 +610,7 @@ static inline void audit_free_context(st
 			       context->name_count, count);
 		}
 		audit_free_names(context);
+		audit_free_aux(context);
 		kfree(context);
 		context  = previous;
 	} while (context);
@@ -577,6 +618,33 @@ static inline void audit_free_context(st
 		printk(KERN_ERR "audit: freed %d contexts\n", count);
 }
 
+static void audit_log_task_info(struct audit_buffer *ab)
+{
+	char name[sizeof(current->comm)];
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+
+	get_task_comm(name, current);
+	audit_log_format(ab, " comm=%s", name);
+
+	if (!mm)
+		return;
+
+	down_read(&mm->mmap_sem);
+	vma = mm->mmap;
+	while (vma) {
+		if ((vma->vm_flags & VM_EXECUTABLE) &&
+		    vma->vm_file) {
+			audit_log_d_path(ab, "exe=",
+					 vma->vm_file->f_dentry,
+					 vma->vm_file->f_vfsmnt);
+			break;
+		}
+		vma = vma->vm_next;
+	}
+	up_read(&mm->mmap_sem);
+}
+
 static void audit_log_exit(struct audit_context *context)
 {
 	int i;
@@ -588,8 +656,11 @@ static void audit_log_exit(struct audit_
 	audit_log_format(ab, "syscall=%d", context->major);
 	if (context->personality != PER_LINUX)
 		audit_log_format(ab, " per=%lx", context->personality);
+	audit_log_format(ab, " arch=%x", context->arch);
 	if (context->return_valid)
-		audit_log_format(ab, " exit=%d", context->return_code);
+		audit_log_format(ab, " success=%s exit=%ld", 
+				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
+				 context->return_code);
 	audit_log_format(ab,
 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
 		  " pid=%d loginuid=%d uid=%d gid=%d"
@@ -606,22 +677,49 @@ static void audit_log_exit(struct audit_
 		  context->gid,
 		  context->euid, context->suid, context->fsuid,
 		  context->egid, context->sgid, context->fsgid);
+	audit_log_task_info(ab);
 	audit_log_end(ab);
+	while (context->aux) {
+		struct audit_aux_data *aux;
+
+		ab = audit_log_start(context);
+		if (!ab)
+			continue; /* audit_panic has been called */
+
+		aux = context->aux;
+		context->aux = aux->next;
+
+		audit_log_format(ab, "auxitem=%d", aux->type);
+		switch (aux->type) {
+		case AUDIT_AUX_IPCPERM: {
+			struct audit_aux_data_ipcctl *axi = (void *)aux;
+			audit_log_format(ab, 
+					 " qbytes=%lx uid=%d gid=%d mode=%x",
+					 axi->qbytes, axi->uid, axi->gid, axi->mode);
+			}
+		}
+		audit_log_end(ab);
+		kfree(aux);
+	}
+
 	for (i = 0; i < context->name_count; i++) {
 		ab = audit_log_start(context);
 		if (!ab)
 			continue; /* audit_panic has been called */
 		audit_log_format(ab, "item=%d", i);
-		if (context->names[i].name)
-			audit_log_format(ab, " name=%s",
-					 context->names[i].name);
+		if (context->names[i].name) {
+			audit_log_format(ab, " name=");
+			audit_log_untrustedstring(ab, context->names[i].name);
+		}
 		if (context->names[i].ino != (unsigned long)-1)
-			audit_log_format(ab, " inode=%lu",
-					 context->names[i].ino);
-		/* FIXME: should use format_dev_t, but ab structure is
-		 * opaque. */
-		if (context->names[i].rdev != -1)
-			audit_log_format(ab, " dev=%02x:%02x",
+			audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
+					     " uid=%d gid=%d rdev=%02x:%02x",
+					 context->names[i].ino,
+					 MAJOR(context->names[i].dev),
+					 MINOR(context->names[i].dev),
+					 context->names[i].mode,
+					 context->names[i].uid,
+					 context->names[i].gid,
 					 MAJOR(context->names[i].rdev),
 					 MINOR(context->names[i].rdev));
 		audit_log_end(ab);
@@ -686,7 +784,7 @@ static inline unsigned int audit_serial(
  * then the record will be written at syscall exit time (otherwise, it
  * will only be written if another part of the kernel requests that it
  * be written). */
-void audit_syscall_entry(struct task_struct *tsk, int major,
+void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
 			 unsigned long a1, unsigned long a2,
 			 unsigned long a3, unsigned long a4)
 {
@@ -740,6 +838,7 @@ void audit_syscall_entry(struct task_str
 	if (!audit_enabled)
 		return;
 
+	context->arch	    = arch;
 	context->major      = major;
 	context->argv[0]    = a1;
 	context->argv[1]    = a2;
@@ -763,13 +862,13 @@ void audit_syscall_entry(struct task_str
  * filtering, or because some other part of the kernel write an audit
  * message), then write out the syscall information.  In call cases,
  * free the names stored from getname(). */
-void audit_syscall_exit(struct task_struct *tsk, int return_code)
+void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
 {
 	struct audit_context *context;
 
 	get_task_struct(tsk);
 	task_lock(tsk);
-	context = audit_get_context(tsk, 1, return_code);
+	context = audit_get_context(tsk, valid, return_code);
 	task_unlock(tsk);
 
 	/* Not having a context here is ok, since the parent may have
@@ -782,6 +881,7 @@ void audit_syscall_exit(struct task_stru
 
 	context->in_syscall = 0;
 	context->auditable  = 0;
+
 	if (context->previous) {
 		struct audit_context *new_context = context->previous;
 		context->previous  = NULL;
@@ -789,6 +889,7 @@ void audit_syscall_exit(struct task_stru
 		tsk->audit_context = new_context;
 	} else {
 		audit_free_names(context);
+		audit_free_aux(context);
 		audit_zero_context(context, context->state);
 		tsk->audit_context = context;
 	}
@@ -800,7 +901,9 @@ void audit_getname(const char *name)
 {
 	struct audit_context *context = current->audit_context;
 
-	BUG_ON(!context);
+	if (!context || IS_ERR(name) || !name)
+		return;
+
 	if (!context->in_syscall) {
 #if AUDIT_DEBUG == 2
 		printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
@@ -812,7 +915,6 @@ void audit_getname(const char *name)
 	BUG_ON(context->name_count >= AUDIT_NAMES);
 	context->names[context->name_count].name = name;
 	context->names[context->name_count].ino  = (unsigned long)-1;
-	context->names[context->name_count].rdev = -1;
 	++context->name_count;
 }
 
@@ -855,11 +957,10 @@ void audit_putname(const char *name)
 	}
 #endif
 }
-EXPORT_SYMBOL(audit_putname);
 
 /* Store the inode and device from a lookup.  Called from
  * fs/namei.c:path_lookup(). */
-void audit_inode(const char *name, unsigned long ino, dev_t rdev)
+void audit_inode(const char *name, const struct inode *inode)
 {
 	int idx;
 	struct audit_context *context = current->audit_context;
@@ -885,12 +986,16 @@ void audit_inode(const char *name, unsig
 		++context->ino_count;
 #endif
 	}
-	context->names[idx].ino  = ino;
-	context->names[idx].rdev = rdev;
+	context->names[idx].ino  = inode->i_ino;
+	context->names[idx].dev	 = inode->i_sb->s_dev;
+	context->names[idx].mode = inode->i_mode;
+	context->names[idx].uid  = inode->i_uid;
+	context->names[idx].gid  = inode->i_gid;
+	context->names[idx].rdev = inode->i_rdev;
 }
 
 void audit_get_stamp(struct audit_context *ctx,
-		     struct timespec *t, int *serial)
+		     struct timespec *t, unsigned int *serial)
 {
 	if (ctx) {
 		t->tv_sec  = ctx->ctime.tv_sec;
@@ -905,20 +1010,21 @@ void audit_get_stamp(struct audit_contex
 
 extern int audit_set_type(struct audit_buffer *ab, int type);
 
-int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid)
+int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
-	if (ctx) {
+	if (task->audit_context) {
 		struct audit_buffer *ab;
 
 		ab = audit_log_start(NULL);
 		if (ab) {
 			audit_log_format(ab, "login pid=%d uid=%u "
 				"old loginuid=%u new loginuid=%u",
-				ctx->pid, ctx->uid, ctx->loginuid, loginuid);
+				task->pid, task->uid, 
+				task->audit_context->loginuid, loginuid);
 			audit_set_type(ab, AUDIT_LOGIN);
 			audit_log_end(ab);
 		}
-		ctx->loginuid = loginuid;
+		task->audit_context->loginuid = loginuid;
 	}
 	return 0;
 }
@@ -927,3 +1033,26 @@ uid_t audit_get_loginuid(struct audit_co
 {
 	return ctx ? ctx->loginuid : -1;
 }
+
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+{
+	struct audit_aux_data_ipcctl *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->qbytes = qbytes;
+	ax->uid = uid;
+	ax->gid = gid;
+	ax->mode = mode;
+
+	ax->d.type = AUDIT_AUX_IPCPERM;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
diff --git a/kernel/capability.c b/kernel/capability.c
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -20,10 +20,10 @@ EXPORT_SYMBOL(securebits);
 EXPORT_SYMBOL(cap_bset);
 
 /*
- * This global lock protects task->cap_* for all tasks including current.
+ * This lock protects task->cap_* for all tasks including current.
  * Locking rule: acquire this prior to tasklist_lock.
  */
-DEFINE_SPINLOCK(task_capability_lock);
+static DEFINE_SPINLOCK(task_capability_lock);
 
 /*
  * For sys_getproccap() and sys_setproccap(), any of the three
diff --git a/kernel/compat.c b/kernel/compat.c
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -23,17 +23,18 @@
 #include <linux/security.h>
 
 #include <asm/uaccess.h>
+#include <asm/bug.h>
 
 int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
 {
-	return (verify_area(VERIFY_READ, cts, sizeof(*cts)) ||
+	return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
 			__get_user(ts->tv_sec, &cts->tv_sec) ||
 			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
 
 int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
 {
-	return (verify_area(VERIFY_WRITE, cts, sizeof(*cts)) ||
+	return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
 			__put_user(ts->tv_sec, &cts->tv_sec) ||
 			__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
@@ -413,6 +414,36 @@ compat_sys_wait4(compat_pid_t pid, compa
 	}
 }
 
+asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
+		struct compat_siginfo __user *uinfo, int options,
+		struct compat_rusage __user *uru)
+{
+	siginfo_t info;
+	struct rusage ru;
+	long ret;
+	mm_segment_t old_fs = get_fs();
+
+	memset(&info, 0, sizeof(info));
+
+	set_fs(KERNEL_DS);
+	ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
+			 uru ? (struct rusage __user *)&ru : NULL);
+	set_fs(old_fs);
+
+	if ((ret < 0) || (info.si_signo == 0))
+		return ret;
+
+	if (uru) {
+		ret = put_compat_rusage(&ru, uru);
+		if (ret)
+			return ret;
+	}
+
+	BUG_ON(info.si_code & __SI_MASK);
+	info.si_code |= __SI_CHLD;
+	return copy_siginfo_to_user32(uinfo, &info);
+}
+
 static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
 				    unsigned len, cpumask_t *new_mask)
 {
@@ -599,6 +630,27 @@ long compat_sys_clock_nanosleep(clockid_
 	return err;	
 } 
 
+/*
+ * We currently only need the following fields from the sigevent
+ * structure: sigev_value, sigev_signo, sig_notify and (sometimes
+ * sigev_notify_thread_id).  The others are handled in user mode.
+ * We also assume that copying sigev_value.sival_int is sufficient
+ * to keep all the bits of sigev_value.sival_ptr intact.
+ */
+int get_compat_sigevent(struct sigevent *event,
+		const struct compat_sigevent __user *u_event)
+{
+	memset(event, 0, sizeof(*event));
+	return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) ||
+		__get_user(event->sigev_value.sival_int,
+			&u_event->sigev_value.sival_int) ||
+		__get_user(event->sigev_signo, &u_event->sigev_signo) ||
+		__get_user(event->sigev_notify, &u_event->sigev_notify) ||
+		__get_user(event->sigev_notify_thread_id,
+			&u_event->sigev_notify_thread_id))
+		? -EFAULT : 0;
+}
+
 /* timer_create is architecture specific because it needs sigevent conversion */
 
 long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
@@ -612,7 +664,7 @@ long compat_get_bitmap(unsigned long *ma
 	/* align bitmap up to nearest compat_long_t boundary */
 	bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
 
-	if (verify_area(VERIFY_READ, umask, bitmap_size / 8))
+	if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
 		return -EFAULT;
 
 	nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
@@ -653,7 +705,7 @@ long compat_put_bitmap(compat_ulong_t __
 	/* align bitmap up to nearest compat_long_t boundary */
 	bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
 
-	if (verify_area(VERIFY_WRITE, umask, bitmap_size / 8))
+	if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
 		return -EFAULT;
 
 	nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
new file mode 100644
--- /dev/null
+++ b/kernel/cpuset.c
@@ -0,0 +1,1578 @@
+/*
+ *  kernel/cpuset.c
+ *
+ *  Processor and Memory placement constraints for sets of tasks.
+ *
+ *  Copyright (C) 2003 BULL SA.
+ *  Copyright (C) 2004 Silicon Graphics, Inc.
+ *
+ *  Portions derived from Patrick Mochel's sysfs code.
+ *  sysfs is Copyright (c) 2001-3 Patrick Mochel
+ *  Portions Copyright (c) 2004 Silicon Graphics, Inc.
+ *
+ *  2003-10-10 Written by Simon Derr <simon.derr@bull.net>
+ *  2003-10-22 Updates by Stephen Hemminger.
+ *  2004 May-July Rework by Paul Jackson <pj@sgi.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/cpuset.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/backing-dev.h>
+#include <linux/sort.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+#define CPUSET_SUPER_MAGIC 		0x27e0eb
+
+struct cpuset {
+	unsigned long flags;		/* "unsigned long" so bitops work */
+	cpumask_t cpus_allowed;		/* CPUs allowed to tasks in cpuset */
+	nodemask_t mems_allowed;	/* Memory Nodes allowed to tasks */
+
+	atomic_t count;			/* count tasks using this cpuset */
+
+	/*
+	 * We link our 'sibling' struct into our parents 'children'.
+	 * Our children link their 'sibling' into our 'children'.
+	 */
+	struct list_head sibling;	/* my parents children */
+	struct list_head children;	/* my children */
+
+	struct cpuset *parent;		/* my parent */
+	struct dentry *dentry;		/* cpuset fs entry */
+
+	/*
+	 * Copy of global cpuset_mems_generation as of the most
+	 * recent time this cpuset changed its mems_allowed.
+	 */
+	 int mems_generation;
+};
+
+/* bits in struct cpuset flags field */
+typedef enum {
+	CS_CPU_EXCLUSIVE,
+	CS_MEM_EXCLUSIVE,
+	CS_REMOVED,
+	CS_NOTIFY_ON_RELEASE
+} cpuset_flagbits_t;
+
+/* convenient tests for these bits */
+static inline int is_cpu_exclusive(const struct cpuset *cs)
+{
+	return !!test_bit(CS_CPU_EXCLUSIVE, &cs->flags);
+}
+
+static inline int is_mem_exclusive(const struct cpuset *cs)
+{
+	return !!test_bit(CS_MEM_EXCLUSIVE, &cs->flags);
+}
+
+static inline int is_removed(const struct cpuset *cs)
+{
+	return !!test_bit(CS_REMOVED, &cs->flags);
+}
+
+static inline int notify_on_release(const struct cpuset *cs)
+{
+	return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
+}
+
+/*
+ * Increment this atomic integer everytime any cpuset changes its
+ * mems_allowed value.  Users of cpusets can track this generation
+ * number, and avoid having to lock and reload mems_allowed unless
+ * the cpuset they're using changes generation.
+ *
+ * A single, global generation is needed because attach_task() could
+ * reattach a task to a different cpuset, which must not have its
+ * generation numbers aliased with those of that tasks previous cpuset.
+ *
+ * Generations are needed for mems_allowed because one task cannot
+ * modify anothers memory placement.  So we must enable every task,
+ * on every visit to __alloc_pages(), to efficiently check whether
+ * its current->cpuset->mems_allowed has changed, requiring an update
+ * of its current->mems_allowed.
+ */
+static atomic_t cpuset_mems_generation = ATOMIC_INIT(1);
+
+static struct cpuset top_cpuset = {
+	.flags = ((1 << CS_CPU_EXCLUSIVE) | (1 << CS_MEM_EXCLUSIVE)),
+	.cpus_allowed = CPU_MASK_ALL,
+	.mems_allowed = NODE_MASK_ALL,
+	.count = ATOMIC_INIT(0),
+	.sibling = LIST_HEAD_INIT(top_cpuset.sibling),
+	.children = LIST_HEAD_INIT(top_cpuset.children),
+	.parent = NULL,
+	.dentry = NULL,
+	.mems_generation = 0,
+};
+
+static struct vfsmount *cpuset_mount;
+static struct super_block *cpuset_sb = NULL;
+
+/*
+ * cpuset_sem should be held by anyone who is depending on the children
+ * or sibling lists of any cpuset, or performing non-atomic operations
+ * on the flags or *_allowed values of a cpuset, such as raising the
+ * CS_REMOVED flag bit iff it is not already raised, or reading and
+ * conditionally modifying the *_allowed values.  One kernel global
+ * cpuset semaphore should be sufficient - these things don't change
+ * that much.
+ *
+ * The code that modifies cpusets holds cpuset_sem across the entire
+ * operation, from cpuset_common_file_write() down, single threading
+ * all cpuset modifications (except for counter manipulations from
+ * fork and exit) across the system.  This presumes that cpuset
+ * modifications are rare - better kept simple and safe, even if slow.
+ *
+ * The code that reads cpusets, such as in cpuset_common_file_read()
+ * and below, only holds cpuset_sem across small pieces of code, such
+ * as when reading out possibly multi-word cpumasks and nodemasks, as
+ * the risks are less, and the desire for performance a little greater.
+ * The proc_cpuset_show() routine needs to hold cpuset_sem to insure
+ * that no cs->dentry is NULL, as it walks up the cpuset tree to root.
+ *
+ * The hooks from fork and exit, cpuset_fork() and cpuset_exit(), don't
+ * (usually) grab cpuset_sem.  These are the two most performance
+ * critical pieces of code here.  The exception occurs on exit(),
+ * when a task in a notify_on_release cpuset exits.  Then cpuset_sem
+ * is taken, and if the cpuset count is zero, a usermode call made
+ * to /sbin/cpuset_release_agent with the name of the cpuset (path
+ * relative to the root of cpuset file system) as the argument.
+ *
+ * A cpuset can only be deleted if both its 'count' of using tasks is
+ * zero, and its list of 'children' cpusets is empty.  Since all tasks
+ * in the system use _some_ cpuset, and since there is always at least
+ * one task in the system (init, pid == 1), therefore, top_cpuset
+ * always has either children cpusets and/or using tasks.  So no need
+ * for any special hack to ensure that top_cpuset cannot be deleted.
+ */
+
+static DECLARE_MUTEX(cpuset_sem);
+
+/*
+ * A couple of forward declarations required, due to cyclic reference loop:
+ *  cpuset_mkdir -> cpuset_create -> cpuset_populate_dir -> cpuset_add_file
+ *  -> cpuset_create_file -> cpuset_dir_inode_operations -> cpuset_mkdir.
+ */
+
+static int cpuset_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry);
+
+static struct backing_dev_info cpuset_backing_dev_info = {
+	.ra_pages = 0,		/* No readahead */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+};
+
+static struct inode *cpuset_new_inode(mode_t mode)
+{
+	struct inode *inode = new_inode(cpuset_sb);
+
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		inode->i_mapping->backing_dev_info = &cpuset_backing_dev_info;
+	}
+	return inode;
+}
+
+static void cpuset_diput(struct dentry *dentry, struct inode *inode)
+{
+	/* is dentry a directory ? if so, kfree() associated cpuset */
+	if (S_ISDIR(inode->i_mode)) {
+		struct cpuset *cs = dentry->d_fsdata;
+		BUG_ON(!(is_removed(cs)));
+		kfree(cs);
+	}
+	iput(inode);
+}
+
+static struct dentry_operations cpuset_dops = {
+	.d_iput = cpuset_diput,
+};
+
+static struct dentry *cpuset_get_dentry(struct dentry *parent, const char *name)
+{
+	struct qstr qstr;
+	struct dentry *d;
+
+	qstr.name = name;
+	qstr.len = strlen(name);
+	qstr.hash = full_name_hash(name, qstr.len);
+	d = lookup_hash(&qstr, parent);
+	if (!IS_ERR(d))
+		d->d_op = &cpuset_dops;
+	return d;
+}
+
+static void remove_dir(struct dentry *d)
+{
+	struct dentry *parent = dget(d->d_parent);
+
+	d_delete(d);
+	simple_rmdir(parent->d_inode, d);
+	dput(parent);
+}
+
+/*
+ * NOTE : the dentry must have been dget()'ed
+ */
+static void cpuset_d_remove_dir(struct dentry *dentry)
+{
+	struct list_head *node;
+
+	spin_lock(&dcache_lock);
+	node = dentry->d_subdirs.next;
+	while (node != &dentry->d_subdirs) {
+		struct dentry *d = list_entry(node, struct dentry, d_child);
+		list_del_init(node);
+		if (d->d_inode) {
+			d = dget_locked(d);
+			spin_unlock(&dcache_lock);
+			d_delete(d);
+			simple_unlink(dentry->d_inode, d);
+			dput(d);
+			spin_lock(&dcache_lock);
+		}
+		node = dentry->d_subdirs.next;
+	}
+	list_del_init(&dentry->d_child);
+	spin_unlock(&dcache_lock);
+	remove_dir(dentry);
+}
+
+static struct super_operations cpuset_ops = {
+	.statfs = simple_statfs,
+	.drop_inode = generic_delete_inode,
+};
+
+static int cpuset_fill_super(struct super_block *sb, void *unused_data,
+							int unused_silent)
+{
+	struct inode *inode;
+	struct dentry *root;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = CPUSET_SUPER_MAGIC;
+	sb->s_op = &cpuset_ops;
+	cpuset_sb = sb;
+
+	inode = cpuset_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR);
+	if (inode) {
+		inode->i_op = &simple_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		/* directories start off with i_nlink == 2 (for "." entry) */
+		inode->i_nlink++;
+	} else {
+		return -ENOMEM;
+	}
+
+	root = d_alloc_root(inode);
+	if (!root) {
+		iput(inode);
+		return -ENOMEM;
+	}
+	sb->s_root = root;
+	return 0;
+}
+
+static struct super_block *cpuset_get_sb(struct file_system_type *fs_type,
+					int flags, const char *unused_dev_name,
+					void *data)
+{
+	return get_sb_single(fs_type, flags, data, cpuset_fill_super);
+}
+
+static struct file_system_type cpuset_fs_type = {
+	.name = "cpuset",
+	.get_sb = cpuset_get_sb,
+	.kill_sb = kill_litter_super,
+};
+
+/* struct cftype:
+ *
+ * The files in the cpuset filesystem mostly have a very simple read/write
+ * handling, some common function will take care of it. Nevertheless some cases
+ * (read tasks) are special and therefore I define this structure for every
+ * kind of file.
+ *
+ *
+ * When reading/writing to a file:
+ *	- the cpuset to use in file->f_dentry->d_parent->d_fsdata
+ *	- the 'cftype' of the file is file->f_dentry->d_fsdata
+ */
+
+struct cftype {
+	char *name;
+	int private;
+	int (*open) (struct inode *inode, struct file *file);
+	ssize_t (*read) (struct file *file, char __user *buf, size_t nbytes,
+							loff_t *ppos);
+	int (*write) (struct file *file, const char __user *buf, size_t nbytes,
+							loff_t *ppos);
+	int (*release) (struct inode *inode, struct file *file);
+};
+
+static inline struct cpuset *__d_cs(struct dentry *dentry)
+{
+	return dentry->d_fsdata;
+}
+
+static inline struct cftype *__d_cft(struct dentry *dentry)
+{
+	return dentry->d_fsdata;
+}
+
+/*
+ * Call with cpuset_sem held.  Writes path of cpuset into buf.
+ * Returns 0 on success, -errno on error.
+ */
+
+static int cpuset_path(const struct cpuset *cs, char *buf, int buflen)
+{
+	char *start;
+
+	start = buf + buflen;
+
+	*--start = '\0';
+	for (;;) {
+		int len = cs->dentry->d_name.len;
+		if ((start -= len) < buf)
+			return -ENAMETOOLONG;
+		memcpy(start, cs->dentry->d_name.name, len);
+		cs = cs->parent;
+		if (!cs)
+			break;
+		if (!cs->parent)
+			continue;
+		if (--start < buf)
+			return -ENAMETOOLONG;
+		*start = '/';
+	}
+	memmove(buf, start, buf + buflen - start);
+	return 0;
+}
+
+/*
+ * Notify userspace when a cpuset is released, by running
+ * /sbin/cpuset_release_agent with the name of the cpuset (path
+ * relative to the root of cpuset file system) as the argument.
+ *
+ * Most likely, this user command will try to rmdir this cpuset.
+ *
+ * This races with the possibility that some other task will be
+ * attached to this cpuset before it is removed, or that some other
+ * user task will 'mkdir' a child cpuset of this cpuset.  That's ok.
+ * The presumed 'rmdir' will fail quietly if this cpuset is no longer
+ * unused, and this cpuset will be reprieved from its death sentence,
+ * to continue to serve a useful existence.  Next time it's released,
+ * we will get notified again, if it still has 'notify_on_release' set.
+ *
+ * Note final arg to call_usermodehelper() is 0 - that means
+ * don't wait.  Since we are holding the global cpuset_sem here,
+ * and we are asking another thread (started from keventd) to rmdir a
+ * cpuset, we can't wait - or we'd deadlock with the removing thread
+ * on cpuset_sem.
+ */
+
+static int cpuset_release_agent(char *cpuset_str)
+{
+	char *argv[3], *envp[3];
+	int i;
+
+	i = 0;
+	argv[i++] = "/sbin/cpuset_release_agent";
+	argv[i++] = cpuset_str;
+	argv[i] = NULL;
+
+	i = 0;
+	/* minimal command environment */
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[i] = NULL;
+
+	return call_usermodehelper(argv[0], argv, envp, 0);
+}
+
+/*
+ * Either cs->count of using tasks transitioned to zero, or the
+ * cs->children list of child cpusets just became empty.  If this
+ * cs is notify_on_release() and now both the user count is zero and
+ * the list of children is empty, send notice to user land.
+ */
+
+static void check_for_release(struct cpuset *cs)
+{
+	if (notify_on_release(cs) && atomic_read(&cs->count) == 0 &&
+	    list_empty(&cs->children)) {
+		char *buf;
+
+		buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!buf)
+			return;
+		if (cpuset_path(cs, buf, PAGE_SIZE) < 0)
+			goto out;
+		cpuset_release_agent(buf);
+out:
+		kfree(buf);
+	}
+}
+
+/*
+ * Return in *pmask the portion of a cpusets's cpus_allowed that
+ * are online.  If none are online, walk up the cpuset hierarchy
+ * until we find one that does have some online cpus.  If we get
+ * all the way to the top and still haven't found any online cpus,
+ * return cpu_online_map.  Or if passed a NULL cs from an exit'ing
+ * task, return cpu_online_map.
+ *
+ * One way or another, we guarantee to return some non-empty subset
+ * of cpu_online_map.
+ *
+ * Call with cpuset_sem held.
+ */
+
+static void guarantee_online_cpus(const struct cpuset *cs, cpumask_t *pmask)
+{
+	while (cs && !cpus_intersects(cs->cpus_allowed, cpu_online_map))
+		cs = cs->parent;
+	if (cs)
+		cpus_and(*pmask, cs->cpus_allowed, cpu_online_map);
+	else
+		*pmask = cpu_online_map;
+	BUG_ON(!cpus_intersects(*pmask, cpu_online_map));
+}
+
+/*
+ * Return in *pmask the portion of a cpusets's mems_allowed that
+ * are online.  If none are online, walk up the cpuset hierarchy
+ * until we find one that does have some online mems.  If we get
+ * all the way to the top and still haven't found any online mems,
+ * return node_online_map.
+ *
+ * One way or another, we guarantee to return some non-empty subset
+ * of node_online_map.
+ *
+ * Call with cpuset_sem held.
+ */
+
+static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
+{
+	while (cs && !nodes_intersects(cs->mems_allowed, node_online_map))
+		cs = cs->parent;
+	if (cs)
+		nodes_and(*pmask, cs->mems_allowed, node_online_map);
+	else
+		*pmask = node_online_map;
+	BUG_ON(!nodes_intersects(*pmask, node_online_map));
+}
+
+/*
+ * Refresh current tasks mems_allowed and mems_generation from
+ * current tasks cpuset.  Call with cpuset_sem held.
+ *
+ * Be sure to call refresh_mems() on any cpuset operation which
+ * (1) holds cpuset_sem, and (2) might possibly alloc memory.
+ * Call after obtaining cpuset_sem lock, before any possible
+ * allocation.  Otherwise one risks trying to allocate memory
+ * while the task cpuset_mems_generation is not the same as
+ * the mems_generation in its cpuset, which would deadlock on
+ * cpuset_sem in cpuset_update_current_mems_allowed().
+ *
+ * Since we hold cpuset_sem, once refresh_mems() is called, the
+ * test (current->cpuset_mems_generation != cs->mems_generation)
+ * in cpuset_update_current_mems_allowed() will remain false,
+ * until we drop cpuset_sem.  Anyone else who would change our
+ * cpusets mems_generation needs to lock cpuset_sem first.
+ */
+
+static void refresh_mems(void)
+{
+	struct cpuset *cs = current->cpuset;
+
+	if (current->cpuset_mems_generation != cs->mems_generation) {
+		guarantee_online_mems(cs, &current->mems_allowed);
+		current->cpuset_mems_generation = cs->mems_generation;
+	}
+}
+
+/*
+ * is_cpuset_subset(p, q) - Is cpuset p a subset of cpuset q?
+ *
+ * One cpuset is a subset of another if all its allowed CPUs and
+ * Memory Nodes are a subset of the other, and its exclusive flags
+ * are only set if the other's are set.
+ */
+
+static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
+{
+	return	cpus_subset(p->cpus_allowed, q->cpus_allowed) &&
+		nodes_subset(p->mems_allowed, q->mems_allowed) &&
+		is_cpu_exclusive(p) <= is_cpu_exclusive(q) &&
+		is_mem_exclusive(p) <= is_mem_exclusive(q);
+}
+
+/*
+ * validate_change() - Used to validate that any proposed cpuset change
+ *		       follows the structural rules for cpusets.
+ *
+ * If we replaced the flag and mask values of the current cpuset
+ * (cur) with those values in the trial cpuset (trial), would
+ * our various subset and exclusive rules still be valid?  Presumes
+ * cpuset_sem held.
+ *
+ * 'cur' is the address of an actual, in-use cpuset.  Operations
+ * such as list traversal that depend on the actual address of the
+ * cpuset in the list must use cur below, not trial.
+ *
+ * 'trial' is the address of bulk structure copy of cur, with
+ * perhaps one or more of the fields cpus_allowed, mems_allowed,
+ * or flags changed to new, trial values.
+ *
+ * Return 0 if valid, -errno if not.
+ */
+
+static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
+{
+	struct cpuset *c, *par;
+
+	/* Each of our child cpusets must be a subset of us */
+	list_for_each_entry(c, &cur->children, sibling) {
+		if (!is_cpuset_subset(c, trial))
+			return -EBUSY;
+	}
+
+	/* Remaining checks don't apply to root cpuset */
+	if ((par = cur->parent) == NULL)
+		return 0;
+
+	/* We must be a subset of our parent cpuset */
+	if (!is_cpuset_subset(trial, par))
+		return -EACCES;
+
+	/* If either I or some sibling (!= me) is exclusive, we can't overlap */
+	list_for_each_entry(c, &par->children, sibling) {
+		if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
+		    c != cur &&
+		    cpus_intersects(trial->cpus_allowed, c->cpus_allowed))
+			return -EINVAL;
+		if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
+		    c != cur &&
+		    nodes_intersects(trial->mems_allowed, c->mems_allowed))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int update_cpumask(struct cpuset *cs, char *buf)
+{
+	struct cpuset trialcs;
+	int retval;
+
+	trialcs = *cs;
+	retval = cpulist_parse(buf, trialcs.cpus_allowed);
+	if (retval < 0)
+		return retval;
+	cpus_and(trialcs.cpus_allowed, trialcs.cpus_allowed, cpu_online_map);
+	if (cpus_empty(trialcs.cpus_allowed))
+		return -ENOSPC;
+	retval = validate_change(cs, &trialcs);
+	if (retval == 0)
+		cs->cpus_allowed = trialcs.cpus_allowed;
+	return retval;
+}
+
+static int update_nodemask(struct cpuset *cs, char *buf)
+{
+	struct cpuset trialcs;
+	int retval;
+
+	trialcs = *cs;
+	retval = nodelist_parse(buf, trialcs.mems_allowed);
+	if (retval < 0)
+		return retval;
+	nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map);
+	if (nodes_empty(trialcs.mems_allowed))
+		return -ENOSPC;
+	retval = validate_change(cs, &trialcs);
+	if (retval == 0) {
+		cs->mems_allowed = trialcs.mems_allowed;
+		atomic_inc(&cpuset_mems_generation);
+		cs->mems_generation = atomic_read(&cpuset_mems_generation);
+	}
+	return retval;
+}
+
+/*
+ * update_flag - read a 0 or a 1 in a file and update associated flag
+ * bit:	the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE,
+ *						CS_NOTIFY_ON_RELEASE)
+ * cs:	the cpuset to update
+ * buf:	the buffer where we read the 0 or 1
+ */
+
+static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
+{
+	int turning_on;
+	struct cpuset trialcs;
+	int err;
+
+	turning_on = (simple_strtoul(buf, NULL, 10) != 0);
+
+	trialcs = *cs;
+	if (turning_on)
+		set_bit(bit, &trialcs.flags);
+	else
+		clear_bit(bit, &trialcs.flags);
+
+	err = validate_change(cs, &trialcs);
+	if (err == 0) {
+		if (turning_on)
+			set_bit(bit, &cs->flags);
+		else
+			clear_bit(bit, &cs->flags);
+	}
+	return err;
+}
+
+static int attach_task(struct cpuset *cs, char *buf)
+{
+	pid_t pid;
+	struct task_struct *tsk;
+	struct cpuset *oldcs;
+	cpumask_t cpus;
+
+	if (sscanf(buf, "%d", &pid) != 1)
+		return -EIO;
+	if (cpus_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
+		return -ENOSPC;
+
+	if (pid) {
+		read_lock(&tasklist_lock);
+
+		tsk = find_task_by_pid(pid);
+		if (!tsk) {
+			read_unlock(&tasklist_lock);
+			return -ESRCH;
+		}
+
+		get_task_struct(tsk);
+		read_unlock(&tasklist_lock);
+
+		if ((current->euid) && (current->euid != tsk->uid)
+		    && (current->euid != tsk->suid)) {
+			put_task_struct(tsk);
+			return -EACCES;
+		}
+	} else {
+		tsk = current;
+		get_task_struct(tsk);
+	}
+
+	task_lock(tsk);
+	oldcs = tsk->cpuset;
+	if (!oldcs) {
+		task_unlock(tsk);
+		put_task_struct(tsk);
+		return -ESRCH;
+	}
+	atomic_inc(&cs->count);
+	tsk->cpuset = cs;
+	task_unlock(tsk);
+
+	guarantee_online_cpus(cs, &cpus);
+	set_cpus_allowed(tsk, cpus);
+
+	put_task_struct(tsk);
+	if (atomic_dec_and_test(&oldcs->count))
+		check_for_release(oldcs);
+	return 0;
+}
+
+/* The various types of files and directories in a cpuset file system */
+
+typedef enum {
+	FILE_ROOT,
+	FILE_DIR,
+	FILE_CPULIST,
+	FILE_MEMLIST,
+	FILE_CPU_EXCLUSIVE,
+	FILE_MEM_EXCLUSIVE,
+	FILE_NOTIFY_ON_RELEASE,
+	FILE_TASKLIST,
+} cpuset_filetype_t;
+
+static ssize_t cpuset_common_file_write(struct file *file, const char __user *userbuf,
+					size_t nbytes, loff_t *unused_ppos)
+{
+	struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+	struct cftype *cft = __d_cft(file->f_dentry);
+	cpuset_filetype_t type = cft->private;
+	char *buffer;
+	int retval = 0;
+
+	/* Crude upper limit on largest legitimate cpulist user might write. */
+	if (nbytes > 100 + 6 * NR_CPUS)
+		return -E2BIG;
+
+	/* +1 for nul-terminator */
+	if ((buffer = kmalloc(nbytes + 1, GFP_KERNEL)) == 0)
+		return -ENOMEM;
+
+	if (copy_from_user(buffer, userbuf, nbytes)) {
+		retval = -EFAULT;
+		goto out1;
+	}
+	buffer[nbytes] = 0;	/* nul-terminate */
+
+	down(&cpuset_sem);
+
+	if (is_removed(cs)) {
+		retval = -ENODEV;
+		goto out2;
+	}
+
+	switch (type) {
+	case FILE_CPULIST:
+		retval = update_cpumask(cs, buffer);
+		break;
+	case FILE_MEMLIST:
+		retval = update_nodemask(cs, buffer);
+		break;
+	case FILE_CPU_EXCLUSIVE:
+		retval = update_flag(CS_CPU_EXCLUSIVE, cs, buffer);
+		break;
+	case FILE_MEM_EXCLUSIVE:
+		retval = update_flag(CS_MEM_EXCLUSIVE, cs, buffer);
+		break;
+	case FILE_NOTIFY_ON_RELEASE:
+		retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer);
+		break;
+	case FILE_TASKLIST:
+		retval = attach_task(cs, buffer);
+		break;
+	default:
+		retval = -EINVAL;
+		goto out2;
+	}
+
+	if (retval == 0)
+		retval = nbytes;
+out2:
+	up(&cpuset_sem);
+out1:
+	kfree(buffer);
+	return retval;
+}
+
+static ssize_t cpuset_file_write(struct file *file, const char __user *buf,
+						size_t nbytes, loff_t *ppos)
+{
+	ssize_t retval = 0;
+	struct cftype *cft = __d_cft(file->f_dentry);
+	if (!cft)
+		return -ENODEV;
+
+	/* special function ? */
+	if (cft->write)
+		retval = cft->write(file, buf, nbytes, ppos);
+	else
+		retval = cpuset_common_file_write(file, buf, nbytes, ppos);
+
+	return retval;
+}
+
+/*
+ * These ascii lists should be read in a single call, by using a user
+ * buffer large enough to hold the entire map.  If read in smaller
+ * chunks, there is no guarantee of atomicity.  Since the display format
+ * used, list of ranges of sequential numbers, is variable length,
+ * and since these maps can change value dynamically, one could read
+ * gibberish by doing partial reads while a list was changing.
+ * A single large read to a buffer that crosses a page boundary is
+ * ok, because the result being copied to user land is not recomputed
+ * across a page fault.
+ */
+
+static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs)
+{
+	cpumask_t mask;
+
+	down(&cpuset_sem);
+	mask = cs->cpus_allowed;
+	up(&cpuset_sem);
+
+	return cpulist_scnprintf(page, PAGE_SIZE, mask);
+}
+
+static int cpuset_sprintf_memlist(char *page, struct cpuset *cs)
+{
+	nodemask_t mask;
+
+	down(&cpuset_sem);
+	mask = cs->mems_allowed;
+	up(&cpuset_sem);
+
+	return nodelist_scnprintf(page, PAGE_SIZE, mask);
+}
+
+static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,
+				size_t nbytes, loff_t *ppos)
+{
+	struct cftype *cft = __d_cft(file->f_dentry);
+	struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+	cpuset_filetype_t type = cft->private;
+	char *page;
+	ssize_t retval = 0;
+	char *s;
+	char *start;
+	size_t n;
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+
+	s = page;
+
+	switch (type) {
+	case FILE_CPULIST:
+		s += cpuset_sprintf_cpulist(s, cs);
+		break;
+	case FILE_MEMLIST:
+		s += cpuset_sprintf_memlist(s, cs);
+		break;
+	case FILE_CPU_EXCLUSIVE:
+		*s++ = is_cpu_exclusive(cs) ? '1' : '0';
+		break;
+	case FILE_MEM_EXCLUSIVE:
+		*s++ = is_mem_exclusive(cs) ? '1' : '0';
+		break;
+	case FILE_NOTIFY_ON_RELEASE:
+		*s++ = notify_on_release(cs) ? '1' : '0';
+		break;
+	default:
+		retval = -EINVAL;
+		goto out;
+	}
+	*s++ = '\n';
+	*s = '\0';
+
+	start = page + *ppos;
+	n = s - start;
+	retval = n - copy_to_user(buf, start, min(n, nbytes));
+	*ppos += retval;
+out:
+	free_page((unsigned long)page);
+	return retval;
+}
+
+static ssize_t cpuset_file_read(struct file *file, char __user *buf, size_t nbytes,
+								loff_t *ppos)
+{
+	ssize_t retval = 0;
+	struct cftype *cft = __d_cft(file->f_dentry);
+	if (!cft)
+		return -ENODEV;
+
+	/* special function ? */
+	if (cft->read)
+		retval = cft->read(file, buf, nbytes, ppos);
+	else
+		retval = cpuset_common_file_read(file, buf, nbytes, ppos);
+
+	return retval;
+}
+
+static int cpuset_file_open(struct inode *inode, struct file *file)
+{
+	int err;
+	struct cftype *cft;
+
+	err = generic_file_open(inode, file);
+	if (err)
+		return err;
+
+	cft = __d_cft(file->f_dentry);
+	if (!cft)
+		return -ENODEV;
+	if (cft->open)
+		err = cft->open(inode, file);
+	else
+		err = 0;
+
+	return err;
+}
+
+static int cpuset_file_release(struct inode *inode, struct file *file)
+{
+	struct cftype *cft = __d_cft(file->f_dentry);
+	if (cft->release)
+		return cft->release(inode, file);
+	return 0;
+}
+
+static struct file_operations cpuset_file_operations = {
+	.read = cpuset_file_read,
+	.write = cpuset_file_write,
+	.llseek = generic_file_llseek,
+	.open = cpuset_file_open,
+	.release = cpuset_file_release,
+};
+
+static struct inode_operations cpuset_dir_inode_operations = {
+	.lookup = simple_lookup,
+	.mkdir = cpuset_mkdir,
+	.rmdir = cpuset_rmdir,
+};
+
+static int cpuset_create_file(struct dentry *dentry, int mode)
+{
+	struct inode *inode;
+
+	if (!dentry)
+		return -ENOENT;
+	if (dentry->d_inode)
+		return -EEXIST;
+
+	inode = cpuset_new_inode(mode);
+	if (!inode)
+		return -ENOMEM;
+
+	if (S_ISDIR(mode)) {
+		inode->i_op = &cpuset_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+
+		/* start off with i_nlink == 2 (for "." entry) */
+		inode->i_nlink++;
+	} else if (S_ISREG(mode)) {
+		inode->i_size = 0;
+		inode->i_fop = &cpuset_file_operations;
+	}
+
+	d_instantiate(dentry, inode);
+	dget(dentry);	/* Extra count - pin the dentry in core */
+	return 0;
+}
+
+/*
+ *	cpuset_create_dir - create a directory for an object.
+ *	cs: 	the cpuset we create the directory for.
+ *		It must have a valid ->parent field
+ *		And we are going to fill its ->dentry field.
+ *	name:	The name to give to the cpuset directory. Will be copied.
+ *	mode:	mode to set on new directory.
+ */
+
+static int cpuset_create_dir(struct cpuset *cs, const char *name, int mode)
+{
+	struct dentry *dentry = NULL;
+	struct dentry *parent;
+	int error = 0;
+
+	parent = cs->parent->dentry;
+	dentry = cpuset_get_dentry(parent, name);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	error = cpuset_create_file(dentry, S_IFDIR | mode);
+	if (!error) {
+		dentry->d_fsdata = cs;
+		parent->d_inode->i_nlink++;
+		cs->dentry = dentry;
+	}
+	dput(dentry);
+
+	return error;
+}
+
+static int cpuset_add_file(struct dentry *dir, const struct cftype *cft)
+{
+	struct dentry *dentry;
+	int error;
+
+	down(&dir->d_inode->i_sem);
+	dentry = cpuset_get_dentry(dir, cft->name);
+	if (!IS_ERR(dentry)) {
+		error = cpuset_create_file(dentry, 0644 | S_IFREG);
+		if (!error)
+			dentry->d_fsdata = (void *)cft;
+		dput(dentry);
+	} else
+		error = PTR_ERR(dentry);
+	up(&dir->d_inode->i_sem);
+	return error;
+}
+
+/*
+ * Stuff for reading the 'tasks' file.
+ *
+ * Reading this file can return large amounts of data if a cpuset has
+ * *lots* of attached tasks. So it may need several calls to read(),
+ * but we cannot guarantee that the information we produce is correct
+ * unless we produce it entirely atomically.
+ *
+ * Upon tasks file open(), a struct ctr_struct is allocated, that
+ * will have a pointer to an array (also allocated here).  The struct
+ * ctr_struct * is stored in file->private_data.  Its resources will
+ * be freed by release() when the file is closed.  The array is used
+ * to sprintf the PIDs and then used by read().
+ */
+
+/* cpusets_tasks_read array */
+
+struct ctr_struct {
+	char *buf;
+	int bufsz;
+};
+
+/*
+ * Load into 'pidarray' up to 'npids' of the tasks using cpuset 'cs'.
+ * Return actual number of pids loaded.
+ */
+static inline int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
+{
+	int n = 0;
+	struct task_struct *g, *p;
+
+	read_lock(&tasklist_lock);
+
+	do_each_thread(g, p) {
+		if (p->cpuset == cs) {
+			pidarray[n++] = p->pid;
+			if (unlikely(n == npids))
+				goto array_full;
+		}
+	} while_each_thread(g, p);
+
+array_full:
+	read_unlock(&tasklist_lock);
+	return n;
+}
+
+static int cmppid(const void *a, const void *b)
+{
+	return *(pid_t *)a - *(pid_t *)b;
+}
+
+/*
+ * Convert array 'a' of 'npids' pid_t's to a string of newline separated
+ * decimal pids in 'buf'.  Don't write more than 'sz' chars, but return
+ * count 'cnt' of how many chars would be written if buf were large enough.
+ */
+static int pid_array_to_buf(char *buf, int sz, pid_t *a, int npids)
+{
+	int cnt = 0;
+	int i;
+
+	for (i = 0; i < npids; i++)
+		cnt += snprintf(buf + cnt, max(sz - cnt, 0), "%d\n", a[i]);
+	return cnt;
+}
+
+static int cpuset_tasks_open(struct inode *unused, struct file *file)
+{
+	struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+	struct ctr_struct *ctr;
+	pid_t *pidarray;
+	int npids;
+	char c;
+
+	if (!(file->f_mode & FMODE_READ))
+		return 0;
+
+	ctr = kmalloc(sizeof(*ctr), GFP_KERNEL);
+	if (!ctr)
+		goto err0;
+
+	/*
+	 * If cpuset gets more users after we read count, we won't have
+	 * enough space - tough.  This race is indistinguishable to the
+	 * caller from the case that the additional cpuset users didn't
+	 * show up until sometime later on.
+	 */
+	npids = atomic_read(&cs->count);
+	pidarray = kmalloc(npids * sizeof(pid_t), GFP_KERNEL);
+	if (!pidarray)
+		goto err1;
+
+	npids = pid_array_load(pidarray, npids, cs);
+	sort(pidarray, npids, sizeof(pid_t), cmppid, NULL);
+
+	/* Call pid_array_to_buf() twice, first just to get bufsz */
+	ctr->bufsz = pid_array_to_buf(&c, sizeof(c), pidarray, npids) + 1;
+	ctr->buf = kmalloc(ctr->bufsz, GFP_KERNEL);
+	if (!ctr->buf)
+		goto err2;
+	ctr->bufsz = pid_array_to_buf(ctr->buf, ctr->bufsz, pidarray, npids);
+
+	kfree(pidarray);
+	file->private_data = ctr;
+	return 0;
+
+err2:
+	kfree(pidarray);
+err1:
+	kfree(ctr);
+err0:
+	return -ENOMEM;
+}
+
+static ssize_t cpuset_tasks_read(struct file *file, char __user *buf,
+						size_t nbytes, loff_t *ppos)
+{
+	struct ctr_struct *ctr = file->private_data;
+
+	if (*ppos + nbytes > ctr->bufsz)
+		nbytes = ctr->bufsz - *ppos;
+	if (copy_to_user(buf, ctr->buf + *ppos, nbytes))
+		return -EFAULT;
+	*ppos += nbytes;
+	return nbytes;
+}
+
+static int cpuset_tasks_release(struct inode *unused_inode, struct file *file)
+{
+	struct ctr_struct *ctr;
+
+	if (file->f_mode & FMODE_READ) {
+		ctr = file->private_data;
+		kfree(ctr->buf);
+		kfree(ctr);
+	}
+	return 0;
+}
+
+/*
+ * for the common functions, 'private' gives the type of file
+ */
+
+static struct cftype cft_tasks = {
+	.name = "tasks",
+	.open = cpuset_tasks_open,
+	.read = cpuset_tasks_read,
+	.release = cpuset_tasks_release,
+	.private = FILE_TASKLIST,
+};
+
+static struct cftype cft_cpus = {
+	.name = "cpus",
+	.private = FILE_CPULIST,
+};
+
+static struct cftype cft_mems = {
+	.name = "mems",
+	.private = FILE_MEMLIST,
+};
+
+static struct cftype cft_cpu_exclusive = {
+	.name = "cpu_exclusive",
+	.private = FILE_CPU_EXCLUSIVE,
+};
+
+static struct cftype cft_mem_exclusive = {
+	.name = "mem_exclusive",
+	.private = FILE_MEM_EXCLUSIVE,
+};
+
+static struct cftype cft_notify_on_release = {
+	.name = "notify_on_release",
+	.private = FILE_NOTIFY_ON_RELEASE,
+};
+
+static int cpuset_populate_dir(struct dentry *cs_dentry)
+{
+	int err;
+
+	if ((err = cpuset_add_file(cs_dentry, &cft_cpus)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_mems)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_cpu_exclusive)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_mem_exclusive)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_notify_on_release)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0)
+		return err;
+	return 0;
+}
+
+/*
+ *	cpuset_create - create a cpuset
+ *	parent:	cpuset that will be parent of the new cpuset.
+ *	name:		name of the new cpuset. Will be strcpy'ed.
+ *	mode:		mode to set on new inode
+ *
+ *	Must be called with the semaphore on the parent inode held
+ */
+
+static long cpuset_create(struct cpuset *parent, const char *name, int mode)
+{
+	struct cpuset *cs;
+	int err;
+
+	cs = kmalloc(sizeof(*cs), GFP_KERNEL);
+	if (!cs)
+		return -ENOMEM;
+
+	down(&cpuset_sem);
+	refresh_mems();
+	cs->flags = 0;
+	if (notify_on_release(parent))
+		set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
+	cs->cpus_allowed = CPU_MASK_NONE;
+	cs->mems_allowed = NODE_MASK_NONE;
+	atomic_set(&cs->count, 0);
+	INIT_LIST_HEAD(&cs->sibling);
+	INIT_LIST_HEAD(&cs->children);
+	atomic_inc(&cpuset_mems_generation);
+	cs->mems_generation = atomic_read(&cpuset_mems_generation);
+
+	cs->parent = parent;
+
+	list_add(&cs->sibling, &cs->parent->children);
+
+	err = cpuset_create_dir(cs, name, mode);
+	if (err < 0)
+		goto err;
+
+	/*
+	 * Release cpuset_sem before cpuset_populate_dir() because it
+	 * will down() this new directory's i_sem and if we race with
+	 * another mkdir, we might deadlock.
+	 */
+	up(&cpuset_sem);
+
+	err = cpuset_populate_dir(cs->dentry);
+	/* If err < 0, we have a half-filled directory - oh well ;) */
+	return 0;
+err:
+	list_del(&cs->sibling);
+	up(&cpuset_sem);
+	kfree(cs);
+	return err;
+}
+
+static int cpuset_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct cpuset *c_parent = dentry->d_parent->d_fsdata;
+
+	/* the vfs holds inode->i_sem already */
+	return cpuset_create(c_parent, dentry->d_name.name, mode | S_IFDIR);
+}
+
+static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
+{
+	struct cpuset *cs = dentry->d_fsdata;
+	struct dentry *d;
+	struct cpuset *parent;
+
+	/* the vfs holds both inode->i_sem already */
+
+	down(&cpuset_sem);
+	refresh_mems();
+	if (atomic_read(&cs->count) > 0) {
+		up(&cpuset_sem);
+		return -EBUSY;
+	}
+	if (!list_empty(&cs->children)) {
+		up(&cpuset_sem);
+		return -EBUSY;
+	}
+	spin_lock(&cs->dentry->d_lock);
+	parent = cs->parent;
+	set_bit(CS_REMOVED, &cs->flags);
+	list_del(&cs->sibling);	/* delete my sibling from parent->children */
+	if (list_empty(&parent->children))
+		check_for_release(parent);
+	d = dget(cs->dentry);
+	cs->dentry = NULL;
+	spin_unlock(&d->d_lock);
+	cpuset_d_remove_dir(d);
+	dput(d);
+	up(&cpuset_sem);
+	return 0;
+}
+
+/**
+ * cpuset_init - initialize cpusets at system boot
+ *
+ * Description: Initialize top_cpuset and the cpuset internal file system,
+ **/
+
+int __init cpuset_init(void)
+{
+	struct dentry *root;
+	int err;
+
+	top_cpuset.cpus_allowed = CPU_MASK_ALL;
+	top_cpuset.mems_allowed = NODE_MASK_ALL;
+
+	atomic_inc(&cpuset_mems_generation);
+	top_cpuset.mems_generation = atomic_read(&cpuset_mems_generation);
+
+	init_task.cpuset = &top_cpuset;
+
+	err = register_filesystem(&cpuset_fs_type);
+	if (err < 0)
+		goto out;
+	cpuset_mount = kern_mount(&cpuset_fs_type);
+	if (IS_ERR(cpuset_mount)) {
+		printk(KERN_ERR "cpuset: could not mount!\n");
+		err = PTR_ERR(cpuset_mount);
+		cpuset_mount = NULL;
+		goto out;
+	}
+	root = cpuset_mount->mnt_sb->s_root;
+	root->d_fsdata = &top_cpuset;
+	root->d_inode->i_nlink++;
+	top_cpuset.dentry = root;
+	root->d_inode->i_op = &cpuset_dir_inode_operations;
+	err = cpuset_populate_dir(root);
+out:
+	return err;
+}
+
+/**
+ * cpuset_init_smp - initialize cpus_allowed
+ *
+ * Description: Finish top cpuset after cpu, node maps are initialized
+ **/
+
+void __init cpuset_init_smp(void)
+{
+	top_cpuset.cpus_allowed = cpu_online_map;
+	top_cpuset.mems_allowed = node_online_map;
+}
+
+/**
+ * cpuset_fork - attach newly forked task to its parents cpuset.
+ * @p: pointer to task_struct of forking parent process.
+ *
+ * Description: By default, on fork, a task inherits its
+ * parents cpuset.  The pointer to the shared cpuset is
+ * automatically copied in fork.c by dup_task_struct().
+ * This cpuset_fork() routine need only increment the usage
+ * counter in that cpuset.
+ **/
+
+void cpuset_fork(struct task_struct *tsk)
+{
+	atomic_inc(&tsk->cpuset->count);
+}
+
+/**
+ * cpuset_exit - detach cpuset from exiting task
+ * @tsk: pointer to task_struct of exiting process
+ *
+ * Description: Detach cpuset from @tsk and release it.
+ *
+ * Note that cpusets marked notify_on_release force every task
+ * in them to take the global cpuset_sem semaphore when exiting.
+ * This could impact scaling on very large systems.  Be reluctant
+ * to use notify_on_release cpusets where very high task exit
+ * scaling is required on large systems.
+ *
+ * Don't even think about derefencing 'cs' after the cpuset use
+ * count goes to zero, except inside a critical section guarded
+ * by the cpuset_sem semaphore.  If you don't hold cpuset_sem,
+ * then a zero cpuset use count is a license to any other task to
+ * nuke the cpuset immediately.
+ *
+ **/
+
+void cpuset_exit(struct task_struct *tsk)
+{
+	struct cpuset *cs;
+
+	task_lock(tsk);
+	cs = tsk->cpuset;
+	tsk->cpuset = NULL;
+	task_unlock(tsk);
+
+	if (notify_on_release(cs)) {
+		down(&cpuset_sem);
+		if (atomic_dec_and_test(&cs->count))
+			check_for_release(cs);
+		up(&cpuset_sem);
+	} else {
+		atomic_dec(&cs->count);
+	}
+}
+
+/**
+ * cpuset_cpus_allowed - return cpus_allowed mask from a tasks cpuset.
+ * @tsk: pointer to task_struct from which to obtain cpuset->cpus_allowed.
+ *
+ * Description: Returns the cpumask_t cpus_allowed of the cpuset
+ * attached to the specified @tsk.  Guaranteed to return some non-empty
+ * subset of cpu_online_map, even if this means going outside the
+ * tasks cpuset.
+ **/
+
+cpumask_t cpuset_cpus_allowed(const struct task_struct *tsk)
+{
+	cpumask_t mask;
+
+	down(&cpuset_sem);
+	task_lock((struct task_struct *)tsk);
+	guarantee_online_cpus(tsk->cpuset, &mask);
+	task_unlock((struct task_struct *)tsk);
+	up(&cpuset_sem);
+
+	return mask;
+}
+
+void cpuset_init_current_mems_allowed(void)
+{
+	current->mems_allowed = NODE_MASK_ALL;
+}
+
+/*
+ * If the current tasks cpusets mems_allowed changed behind our backs,
+ * update current->mems_allowed and mems_generation to the new value.
+ * Do not call this routine if in_interrupt().
+ */
+
+void cpuset_update_current_mems_allowed(void)
+{
+	struct cpuset *cs = current->cpuset;
+
+	if (!cs)
+		return;		/* task is exiting */
+	if (current->cpuset_mems_generation != cs->mems_generation) {
+		down(&cpuset_sem);
+		refresh_mems();
+		up(&cpuset_sem);
+	}
+}
+
+void cpuset_restrict_to_mems_allowed(unsigned long *nodes)
+{
+	bitmap_and(nodes, nodes, nodes_addr(current->mems_allowed),
+							MAX_NUMNODES);
+}
+
+/*
+ * Are any of the nodes on zonelist zl allowed in current->mems_allowed?
+ */
+int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
+{
+	int i;
+
+	for (i = 0; zl->zones[i]; i++) {
+		int nid = zl->zones[i]->zone_pgdat->node_id;
+
+		if (node_isset(nid, current->mems_allowed))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Is 'current' valid, and is zone z allowed in current->mems_allowed?
+ */
+int cpuset_zone_allowed(struct zone *z)
+{
+	return in_interrupt() ||
+		node_isset(z->zone_pgdat->node_id, current->mems_allowed);
+}
+
+/*
+ * proc_cpuset_show()
+ *  - Print tasks cpuset path into seq_file.
+ *  - Used for /proc/<pid>/cpuset.
+ */
+
+static int proc_cpuset_show(struct seq_file *m, void *v)
+{
+	struct cpuset *cs;
+	struct task_struct *tsk;
+	char *buf;
+	int retval = 0;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	tsk = m->private;
+	down(&cpuset_sem);
+	task_lock(tsk);
+	cs = tsk->cpuset;
+	task_unlock(tsk);
+	if (!cs) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	retval = cpuset_path(cs, buf, PAGE_SIZE);
+	if (retval < 0)
+		goto out;
+	seq_puts(m, buf);
+	seq_putc(m, '\n');
+out:
+	up(&cpuset_sem);
+	kfree(buf);
+	return retval;
+}
+
+static int cpuset_open(struct inode *inode, struct file *file)
+{
+	struct task_struct *tsk = PROC_I(inode)->task;
+	return single_open(file, proc_cpuset_show, tsk);
+}
+
+struct file_operations proc_cpuset_operations = {
+	.open		= cpuset_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/* Display task cpus_allowed, mems_allowed in /proc/<pid>/status file. */
+char *cpuset_task_status_allowed(struct task_struct *task, char *buffer)
+{
+	buffer += sprintf(buffer, "Cpus_allowed:\t");
+	buffer += cpumask_scnprintf(buffer, PAGE_SIZE, task->cpus_allowed);
+	buffer += sprintf(buffer, "\n");
+	buffer += sprintf(buffer, "Mems_allowed:\t");
+	buffer += nodemask_scnprintf(buffer, PAGE_SIZE, task->mems_allowed);
+	buffer += sprintf(buffer, "\n");
+	return buffer;
+}
diff --git a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -25,7 +25,9 @@
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
 #include <linux/mempolicy.h>
+#include <linux/cpuset.h>
 #include <linux/syscalls.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -37,6 +39,8 @@ extern struct task_struct *child_reaper;
 
 int getrusage(struct task_struct *, int, struct rusage __user *);
 
+static void exit_mm(struct task_struct * tsk);
+
 static void __unhash_process(struct task_struct *p)
 {
 	nr_threads--;
@@ -208,7 +212,7 @@ static inline int has_stopped_jobs(int p
 }
 
 /**
- * reparent_to_init() - Reparent the calling kernel thread to the init task.
+ * reparent_to_init - Reparent the calling kernel thread to the init task.
  *
  * If a kernel thread is launched as a result of a system call, or if
  * it ever exits, it should generally reparent itself to init so that
@@ -219,7 +223,7 @@ static inline int has_stopped_jobs(int p
  *
  * NOTE that reparent_to_init() gives the caller full capabilities.
  */
-void reparent_to_init(void)
+static inline void reparent_to_init(void)
 {
 	write_lock_irq(&tasklist_lock);
 
@@ -276,7 +280,7 @@ void set_special_pids(pid_t session, pid
  */
 int allow_signal(int sig)
 {
-	if (sig < 1 || sig > _NSIG)
+	if (!valid_signal(sig) || sig < 1)
 		return -EINVAL;
 
 	spin_lock_irq(&current->sighand->siglock);
@@ -297,7 +301,7 @@ EXPORT_SYMBOL(allow_signal);
 
 int disallow_signal(int sig)
 {
-	if (sig < 1 || sig > _NSIG)
+	if (!valid_signal(sig) || sig < 1)
 		return -EINVAL;
 
 	spin_lock_irq(&current->sighand->siglock);
@@ -472,7 +476,7 @@ EXPORT_SYMBOL_GPL(exit_fs);
  * Turn us into a lazy TLB process if we
  * aren't already..
  */
-void exit_mm(struct task_struct * tsk)
+static void exit_mm(struct task_struct * tsk)
 {
 	struct mm_struct *mm = tsk->mm;
 
@@ -516,8 +520,6 @@ static inline void choose_new_parent(tas
 	 */
 	BUG_ON(p == reaper || reaper->exit_state >= EXIT_ZOMBIE);
 	p->real_parent = reaper;
-	if (p->parent == p->real_parent)
-		BUG();
 }
 
 static inline void reparent_thread(task_t *p, task_t *father, int traced)
@@ -753,13 +755,6 @@ static void exit_notify(struct task_stru
 		state = EXIT_DEAD;
 	tsk->exit_state = state;
 
-	/*
-	 * Clear these here so that update_process_times() won't try to deliver
-	 * itimer, profile or rlimit signals to this task while it is in late exit.
-	 */
-	tsk->it_virt_value = cputime_zero;
-	tsk->it_prof_value = cputime_zero;
-
 	write_unlock_irq(&tasklist_lock);
 
 	list_for_each_safe(_p, _n, &ptrace_dead) {
@@ -799,15 +794,22 @@ fastcall NORET_TYPE void do_exit(long co
 	}
 
 	tsk->flags |= PF_EXITING;
-	del_timer_sync(&tsk->real_timer);
+
+	/*
+	 * Make sure we don't try to process any timer firings
+	 * while we are already exiting.
+	 */
+ 	tsk->it_virt_expires = cputime_zero;
+ 	tsk->it_prof_expires = cputime_zero;
+	tsk->it_sched_expires = 0;
 
 	if (unlikely(in_atomic()))
 		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
 				current->comm, current->pid,
 				preempt_count());
 
-	acct_update_integrals();
-	update_mem_hiwater();
+	acct_update_integrals(tsk);
+	update_mem_hiwater(tsk);
 	group_dead = atomic_dec_and_test(&tsk->signal->live);
 	if (group_dead)
 		acct_process(code);
@@ -818,6 +820,7 @@ fastcall NORET_TYPE void do_exit(long co
 	__exit_fs(tsk);
 	exit_namespace(tsk);
 	exit_thread();
+	cpuset_exit(tsk);
 	exit_keys(tsk);
 
 	if (group_dead && tsk->signal->leader)
@@ -841,6 +844,8 @@ fastcall NORET_TYPE void do_exit(long co
 	for (;;) ;
 }
 
+EXPORT_SYMBOL_GPL(do_exit);
+
 NORET_TYPE void complete_and_exit(struct completion *comp, long code)
 {
 	if (comp)
diff --git a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -29,6 +29,7 @@
 #include <linux/mman.h>
 #include <linux/fs.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/security.h>
 #include <linux/swap.h>
 #include <linux/syscalls.h>
@@ -79,6 +80,24 @@ int nr_processes(void)
 static kmem_cache_t *task_struct_cachep;
 #endif
 
+/* SLAB cache for signal_struct structures (tsk->signal) */
+kmem_cache_t *signal_cachep;
+
+/* SLAB cache for sighand_struct structures (tsk->sighand) */
+kmem_cache_t *sighand_cachep;
+
+/* SLAB cache for files_struct structures (tsk->files) */
+kmem_cache_t *files_cachep;
+
+/* SLAB cache for fs_struct structures (tsk->fs) */
+kmem_cache_t *fs_cachep;
+
+/* SLAB cache for vm_area_struct structures */
+kmem_cache_t *vm_area_cachep;
+
+/* SLAB cache for mm_struct structures (tsk->mm) */
+static kmem_cache_t *mm_cachep;
+
 void free_task(struct task_struct *tsk)
 {
 	free_thread_info(tsk->thread_info);
@@ -129,6 +148,8 @@ void __init fork_init(unsigned long memp
 
 	init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
 	init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
+	init_task.signal->rlim[RLIMIT_SIGPENDING] =
+		init_task.signal->rlim[RLIMIT_NPROC];
 }
 
 static struct task_struct *dup_task_struct(struct task_struct *orig)
@@ -174,8 +195,8 @@ static inline int dup_mmap(struct mm_str
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
 	mm->map_count = 0;
-	mm->rss = 0;
-	mm->anon_rss = 0;
+	set_mm_counter(mm, rss, 0);
+	set_mm_counter(mm, anon_rss, 0);
 	cpus_clear(mm->cpu_vm_mask);
 	mm->mm_rb = RB_ROOT;
 	rb_link = &mm->mm_rb.rb_node;
@@ -471,7 +492,7 @@ static int copy_mm(unsigned long clone_f
 	if (retval)
 		goto free_pt;
 
-	mm->hiwater_rss = mm->rss;
+	mm->hiwater_rss = get_mm_counter(mm,rss);
 	mm->hiwater_vm = mm->total_vm;
 
 good_mm:
@@ -719,6 +740,7 @@ static inline int copy_sighand(unsigned 
 static inline int copy_signal(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct signal_struct *sig;
+	int ret;
 
 	if (clone_flags & CLONE_THREAD) {
 		atomic_inc(&current->signal->count);
@@ -729,6 +751,13 @@ static inline int copy_signal(unsigned l
 	tsk->signal = sig;
 	if (!sig)
 		return -ENOMEM;
+
+	ret = copy_thread_group_keys(tsk);
+	if (ret < 0) {
+		kmem_cache_free(signal_cachep, sig);
+		return ret;
+	}
+
 	atomic_set(&sig->count, 1);
 	atomic_set(&sig->live, 1);
 	init_waitqueue_head(&sig->wait_chldexit);
@@ -740,6 +769,16 @@ static inline int copy_signal(unsigned l
 	init_sigpending(&sig->shared_pending);
 	INIT_LIST_HEAD(&sig->posix_timers);
 
+	sig->it_real_value = sig->it_real_incr = 0;
+	sig->real_timer.function = it_real_fn;
+	sig->real_timer.data = (unsigned long) tsk;
+	init_timer(&sig->real_timer);
+
+	sig->it_virt_expires = cputime_zero;
+	sig->it_virt_incr = cputime_zero;
+	sig->it_prof_expires = cputime_zero;
+	sig->it_prof_incr = cputime_zero;
+
 	sig->tty = current->signal->tty;
 	sig->pgrp = process_group(current);
 	sig->session = current->signal->session;
@@ -749,11 +788,24 @@ static inline int copy_signal(unsigned l
 	sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
 	sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
 	sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
+	sig->sched_time = 0;
+	INIT_LIST_HEAD(&sig->cpu_timers[0]);
+	INIT_LIST_HEAD(&sig->cpu_timers[1]);
+	INIT_LIST_HEAD(&sig->cpu_timers[2]);
 
 	task_lock(current->group_leader);
 	memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
 	task_unlock(current->group_leader);
 
+	if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
+		/*
+		 * New sole thread in the process gets an expiry time
+		 * of the whole CPU time limit.
+		 */
+		tsk->it_prof_expires =
+			secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
+	}
+
 	return 0;
 }
 
@@ -866,23 +918,22 @@ static task_t *copy_process(unsigned lon
 	clear_tsk_thread_flag(p, TIF_SIGPENDING);
 	init_sigpending(&p->pending);
 
-	p->it_real_value = 0;
-	p->it_real_incr = 0;
-	p->it_virt_value = cputime_zero;
-	p->it_virt_incr = cputime_zero;
-	p->it_prof_value = cputime_zero;
-	p->it_prof_incr = cputime_zero;
-	init_timer(&p->real_timer);
-	p->real_timer.data = (unsigned long) p;
-
 	p->utime = cputime_zero;
 	p->stime = cputime_zero;
+ 	p->sched_time = 0;
 	p->rchar = 0;		/* I/O counter: bytes read */
 	p->wchar = 0;		/* I/O counter: bytes written */
 	p->syscr = 0;		/* I/O counter: read syscalls */
 	p->syscw = 0;		/* I/O counter: write syscalls */
 	acct_clear_integrals(p);
 
+ 	p->it_virt_expires = cputime_zero;
+	p->it_prof_expires = cputime_zero;
+ 	p->it_sched_expires = 0;
+ 	INIT_LIST_HEAD(&p->cpu_timers[0]);
+ 	INIT_LIST_HEAD(&p->cpu_timers[1]);
+ 	INIT_LIST_HEAD(&p->cpu_timers[2]);
+
 	p->lock_depth = -1;		/* -1 = no lock */
 	do_posix_clock_monotonic_gettime(&p->start_time);
 	p->security = NULL;
@@ -1015,6 +1066,21 @@ static task_t *copy_process(unsigned lon
 			set_tsk_thread_flag(p, TIF_SIGPENDING);
 		}
 
+		if (!cputime_eq(current->signal->it_virt_expires,
+				cputime_zero) ||
+		    !cputime_eq(current->signal->it_prof_expires,
+				cputime_zero) ||
+		    current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY ||
+		    !list_empty(&current->signal->cpu_timers[0]) ||
+		    !list_empty(&current->signal->cpu_timers[1]) ||
+		    !list_empty(&current->signal->cpu_timers[2])) {
+			/*
+			 * Have child wake up on its first tick to check
+			 * for process CPU timers.
+			 */
+			p->it_prof_expires = jiffies_to_cputime(1);
+		}
+
 		spin_unlock(&current->sighand->siglock);
 	}
 
@@ -1022,6 +1088,8 @@ static task_t *copy_process(unsigned lon
 	if (unlikely(p->ptrace & PT_PTRACED))
 		__ptrace_link(p, current->parent);
 
+	cpuset_fork(p);
+
 	attach_pid(p, PIDTYPE_PID, p->pid);
 	attach_pid(p, PIDTYPE_TGID, p->tgid);
 	if (thread_group_leader(p)) {
@@ -1183,24 +1251,6 @@ long do_fork(unsigned long clone_flags,
 	return pid;
 }
 
-/* SLAB cache for signal_struct structures (tsk->signal) */
-kmem_cache_t *signal_cachep;
-
-/* SLAB cache for sighand_struct structures (tsk->sighand) */
-kmem_cache_t *sighand_cachep;
-
-/* SLAB cache for files_struct structures (tsk->files) */
-kmem_cache_t *files_cachep;
-
-/* SLAB cache for fs_struct structures (tsk->fs) */
-kmem_cache_t *fs_cachep;
-
-/* SLAB cache for vm_area_struct structures */
-kmem_cache_t *vm_area_cachep;
-
-/* SLAB cache for mm_struct structures (tsk->mm) */
-kmem_cache_t *mm_cachep;
-
 void __init proc_caches_init(void)
 {
 	sighand_cachep = kmem_cache_create("sighand_cache",
diff --git a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -39,8 +39,9 @@
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/syscalls.h>
+#include <linux/signal.h>
 
-#define FUTEX_HASHBITS 8
+#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
  * Futexes are matched on equal values of this key.
@@ -97,7 +98,6 @@ struct futex_q {
  */
 struct futex_hash_bucket {
        spinlock_t              lock;
-       unsigned int	    nqueued;
        struct list_head       chain;
 };
 
@@ -265,7 +265,6 @@ static inline int get_futex_value_locked
 	inc_preempt_count();
 	ret = __copy_from_user_inatomic(dest, from, sizeof(int));
 	dec_preempt_count();
-	preempt_check_resched();
 
 	return ret ? -EFAULT : 0;
 }
@@ -339,7 +338,6 @@ static int futex_requeue(unsigned long u
 	struct list_head *head1;
 	struct futex_q *this, *next;
 	int ret, drop_count = 0;
-	unsigned int nqueued;
 
  retry:
 	down_read(&current->mm->mmap_sem);
@@ -354,23 +352,22 @@ static int futex_requeue(unsigned long u
 	bh1 = hash_futex(&key1);
 	bh2 = hash_futex(&key2);
 
-	nqueued = bh1->nqueued;
+	if (bh1 < bh2)
+		spin_lock(&bh1->lock);
+	spin_lock(&bh2->lock);
+	if (bh1 > bh2)
+		spin_lock(&bh1->lock);
+
 	if (likely(valp != NULL)) {
 		int curval;
 
-		/* In order to avoid doing get_user while
-		   holding bh1->lock and bh2->lock, nqueued
-		   (monotonically increasing field) must be first
-		   read, then *uaddr1 fetched from userland and
-		   after acquiring lock nqueued field compared with
-		   the stored value.  The smp_mb () below
-		   makes sure that bh1->nqueued is read from memory
-		   before *uaddr1.  */
-		smp_mb();
-
 		ret = get_futex_value_locked(&curval, (int __user *)uaddr1);
 
 		if (unlikely(ret)) {
+			spin_unlock(&bh1->lock);
+			if (bh1 != bh2)
+				spin_unlock(&bh2->lock);
+
 			/* If we would have faulted, release mmap_sem, fault
 			 * it in and start all over again.
 			 */
@@ -385,21 +382,10 @@ static int futex_requeue(unsigned long u
 		}
 		if (curval != *valp) {
 			ret = -EAGAIN;
-			goto out;
+			goto out_unlock;
 		}
 	}
 
-	if (bh1 < bh2)
-		spin_lock(&bh1->lock);
-	spin_lock(&bh2->lock);
-	if (bh1 > bh2)
-		spin_lock(&bh1->lock);
-
-	if (unlikely(nqueued != bh1->nqueued && valp != NULL)) {
-		ret = -EAGAIN;
-		goto out_unlock;
-	}
-
 	head1 = &bh1->chain;
 	list_for_each_entry_safe(this, next, head1, list) {
 		if (!match_futex (&this->key, &key1))
@@ -435,13 +421,9 @@ out:
 	return ret;
 }
 
-/*
- * queue_me and unqueue_me must be called as a pair, each
- * exactly once.  They are called with the hashed spinlock held.
- */
-
 /* The key must be already stored in q->key. */
-static void queue_me(struct futex_q *q, int fd, struct file *filp)
+static inline struct futex_hash_bucket *
+queue_lock(struct futex_q *q, int fd, struct file *filp)
 {
 	struct futex_hash_bucket *bh;
 
@@ -455,11 +437,35 @@ static void queue_me(struct futex_q *q, 
 	q->lock_ptr = &bh->lock;
 
 	spin_lock(&bh->lock);
-	bh->nqueued++;
+	return bh;
+}
+
+static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *bh)
+{
 	list_add_tail(&q->list, &bh->chain);
 	spin_unlock(&bh->lock);
 }
 
+static inline void
+queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
+{
+	spin_unlock(&bh->lock);
+	drop_key_refs(&q->key);
+}
+
+/*
+ * queue_me and unqueue_me must be called as a pair, each
+ * exactly once.  They are called with the hashed spinlock held.
+ */
+
+/* The key must be already stored in q->key. */
+static void queue_me(struct futex_q *q, int fd, struct file *filp)
+{
+	struct futex_hash_bucket *bh;
+	bh = queue_lock(q, fd, filp);
+	__queue_me(q, bh);
+}
+
 /* Return 1 if we were still queued (ie. 0 means we were woken) */
 static int unqueue_me(struct futex_q *q)
 {
@@ -503,6 +509,7 @@ static int futex_wait(unsigned long uadd
 	DECLARE_WAITQUEUE(wait, current);
 	int ret, curval;
 	struct futex_q q;
+	struct futex_hash_bucket *bh;
 
  retry:
 	down_read(&current->mm->mmap_sem);
@@ -511,7 +518,7 @@ static int futex_wait(unsigned long uadd
 	if (unlikely(ret != 0))
 		goto out_release_sem;
 
-	queue_me(&q, -1, NULL);
+	bh = queue_lock(&q, -1, NULL);
 
 	/*
 	 * Access the page AFTER the futex is queued.
@@ -537,14 +544,13 @@ static int futex_wait(unsigned long uadd
 	ret = get_futex_value_locked(&curval, (int __user *)uaddr);
 
 	if (unlikely(ret)) {
+		queue_unlock(&q, bh);
+
 		/* If we would have faulted, release mmap_sem, fault it in and
 		 * start all over again.
 		 */
 		up_read(&current->mm->mmap_sem);
 
-		if (!unqueue_me(&q)) /* There's a chance we got woken already */
-			return 0;
-
 		ret = get_user(curval, (int __user *)uaddr);
 
 		if (!ret)
@@ -553,9 +559,13 @@ static int futex_wait(unsigned long uadd
 	}
 	if (curval != val) {
 		ret = -EWOULDBLOCK;
-		goto out_unqueue;
+		queue_unlock(&q, bh);
+		goto out_release_sem;
 	}
 
+	/* Only actually queue if *uaddr contained val.  */
+	__queue_me(&q, bh);
+
 	/*
 	 * Now the futex is queued and we have checked the data, we
 	 * don't want to hold mmap_sem while we sleep.
@@ -596,10 +606,6 @@ static int futex_wait(unsigned long uadd
 	 * have handled it for us already. */
 	return -EINTR;
 
- out_unqueue:
-	/* If we were woken (and unqueued), we succeeded, whatever. */
-	if (!unqueue_me(&q))
-		ret = 0;
  out_release_sem:
 	up_read(&current->mm->mmap_sem);
 	return ret;
@@ -649,7 +655,7 @@ static int futex_fd(unsigned long uaddr,
 	int ret, err;
 
 	ret = -EINVAL;
-	if (signal < 0 || signal > _NSIG)
+	if (!valid_signal(signal))
 		goto out;
 
 	ret = get_unused_fd();
diff --git a/kernel/intermodule.c b/kernel/intermodule.c
--- a/kernel/intermodule.c
+++ b/kernel/intermodule.c
@@ -113,7 +113,7 @@ void inter_module_unregister(const char 
  * Try to increment the use count on the owning module, if that fails
  * then return NULL.  Otherwise return the userdata.
  */
-const void *inter_module_get(const char *im_name)
+static const void *inter_module_get(const char *im_name)
 {
 	struct list_head *tmp;
 	struct inter_module_entry *ime;
@@ -178,6 +178,5 @@ void inter_module_put(const char *im_nam
 
 EXPORT_SYMBOL(inter_module_register);
 EXPORT_SYMBOL(inter_module_unregister);
-EXPORT_SYMBOL(inter_module_get);
 EXPORT_SYMBOL(inter_module_get_request);
 EXPORT_SYMBOL(inter_module_put);
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -30,6 +30,7 @@
  */
 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
 	[0 ... NR_IRQS-1] = {
+		.status = IRQ_DISABLED,
 		.handler = &no_irq_type,
 		.lock = SPIN_LOCK_UNLOCKED
 	}
@@ -118,8 +119,6 @@ fastcall unsigned int __do_IRQ(unsigned 
 		 */
 		desc->handler->ack(irq);
 		action_ret = handle_IRQ_event(irq, regs, desc->action);
-		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret);
 		desc->handler->end(irq);
 		return 1;
 	}
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -19,6 +19,13 @@ static struct proc_dir_entry *root_irq_d
  */
 static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
 
+void __attribute__((weak))
+proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+{
+	irq_affinity[irq] = mask_val;
+	irq_desc[irq].handler->set_affinity(irq, mask_val);
+}
+
 static int irq_affinity_read_proc(char *page, char **start, off_t off,
 				  int count, int *eof, void *data)
 {
@@ -53,8 +60,7 @@ static int irq_affinity_write_proc(struc
 	if (cpus_empty(tmp))
 		return -EINVAL;
 
-	irq_affinity[irq] = new_value;
-	irq_desc[irq].handler->set_affinity(irq, new_value);
+	proc_set_irq_affinity(irq, new_value);
 
 	return full_count;
 }
diff --git a/kernel/itimer.c b/kernel/itimer.c
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -11,36 +11,86 @@
 #include <linux/interrupt.h>
 #include <linux/syscalls.h>
 #include <linux/time.h>
+#include <linux/posix-timers.h>
 
 #include <asm/uaccess.h>
 
+static unsigned long it_real_value(struct signal_struct *sig)
+{
+	unsigned long val = 0;
+	if (timer_pending(&sig->real_timer)) {
+		val = sig->real_timer.expires - jiffies;
+
+		/* look out for negative/zero itimer.. */
+		if ((long) val <= 0)
+			val = 1;
+	}
+	return val;
+}
+
 int do_getitimer(int which, struct itimerval *value)
 {
-	register unsigned long val;
+	struct task_struct *tsk = current;
+	unsigned long interval, val;
+	cputime_t cinterval, cval;
 
 	switch (which) {
 	case ITIMER_REAL:
-		val = 0;
-		/* 
-		 * FIXME! This needs to be atomic, in case the kernel timer happens!
-		 */
-		if (timer_pending(&current->real_timer)) {
-			val = current->real_timer.expires - jiffies;
-
-			/* look out for negative/zero itimer.. */
-			if ((long) val <= 0)
-				val = 1;
-		}
+		spin_lock_irq(&tsk->sighand->siglock);
+		interval = tsk->signal->it_real_incr;
+		val = it_real_value(tsk->signal);
+		spin_unlock_irq(&tsk->sighand->siglock);
 		jiffies_to_timeval(val, &value->it_value);
-		jiffies_to_timeval(current->it_real_incr, &value->it_interval);
+		jiffies_to_timeval(interval, &value->it_interval);
 		break;
 	case ITIMER_VIRTUAL:
-		cputime_to_timeval(current->it_virt_value, &value->it_value);
-		cputime_to_timeval(current->it_virt_incr, &value->it_interval);
+		read_lock(&tasklist_lock);
+		spin_lock_irq(&tsk->sighand->siglock);
+		cval = tsk->signal->it_virt_expires;
+		cinterval = tsk->signal->it_virt_incr;
+		if (!cputime_eq(cval, cputime_zero)) {
+			struct task_struct *t = tsk;
+			cputime_t utime = tsk->signal->utime;
+			do {
+				utime = cputime_add(utime, t->utime);
+				t = next_thread(t);
+			} while (t != tsk);
+			if (cputime_le(cval, utime)) { /* about to fire */
+				cval = jiffies_to_cputime(1);
+			} else {
+				cval = cputime_sub(cval, utime);
+			}
+		}
+		spin_unlock_irq(&tsk->sighand->siglock);
+		read_unlock(&tasklist_lock);
+		cputime_to_timeval(cval, &value->it_value);
+		cputime_to_timeval(cinterval, &value->it_interval);
 		break;
 	case ITIMER_PROF:
-		cputime_to_timeval(current->it_prof_value, &value->it_value);
-		cputime_to_timeval(current->it_prof_incr, &value->it_interval);
+		read_lock(&tasklist_lock);
+		spin_lock_irq(&tsk->sighand->siglock);
+		cval = tsk->signal->it_prof_expires;
+		cinterval = tsk->signal->it_prof_incr;
+		if (!cputime_eq(cval, cputime_zero)) {
+			struct task_struct *t = tsk;
+			cputime_t ptime = cputime_add(tsk->signal->utime,
+						      tsk->signal->stime);
+			do {
+				ptime = cputime_add(ptime,
+						    cputime_add(t->utime,
+								t->stime));
+				t = next_thread(t);
+			} while (t != tsk);
+			if (cputime_le(cval, ptime)) { /* about to fire */
+				cval = jiffies_to_cputime(1);
+			} else {
+				cval = cputime_sub(cval, ptime);
+			}
+		}
+		spin_unlock_irq(&tsk->sighand->siglock);
+		read_unlock(&tasklist_lock);
+		cputime_to_timeval(cval, &value->it_value);
+		cputime_to_timeval(cinterval, &value->it_interval);
 		break;
 	default:
 		return(-EINVAL);
@@ -48,7 +98,6 @@ int do_getitimer(int which, struct itime
 	return 0;
 }
 
-/* SMP: Only we modify our itimer values. */
 asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
 {
 	int error = -EFAULT;
@@ -63,70 +112,116 @@ asmlinkage long sys_getitimer(int which,
 	return error;
 }
 
+/*
+ * Called with P->sighand->siglock held and P->signal->real_timer inactive.
+ * If interval is nonzero, arm the timer for interval ticks from now.
+ */
+static inline void it_real_arm(struct task_struct *p, unsigned long interval)
+{
+	p->signal->it_real_value = interval; /* XXX unnecessary field?? */
+	if (interval == 0)
+		return;
+	if (interval > (unsigned long) LONG_MAX)
+		interval = LONG_MAX;
+	/* the "+ 1" below makes sure that the timer doesn't go off before
+	 * the interval requested. This could happen if
+	 * time requested % (usecs per jiffy) is more than the usecs left
+	 * in the current jiffy */
+	p->signal->real_timer.expires = jiffies + interval + 1;
+	add_timer(&p->signal->real_timer);
+}
+
 void it_real_fn(unsigned long __data)
 {
 	struct task_struct * p = (struct task_struct *) __data;
-	unsigned long interval;
 
 	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
-	interval = p->it_real_incr;
-	if (interval) {
-		if (interval > (unsigned long) LONG_MAX)
-			interval = LONG_MAX;
-		p->real_timer.expires = jiffies + interval;
-		add_timer(&p->real_timer);
-	}
+
+	/*
+	 * Now restart the timer if necessary.  We don't need any locking
+	 * here because do_setitimer makes sure we have finished running
+	 * before it touches anything.
+	 */
+	it_real_arm(p, p->signal->it_real_incr);
 }
 
 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 {
-	unsigned long expire;
-	cputime_t cputime;
-	int k;
+	struct task_struct *tsk = current;
+ 	unsigned long val, interval;
+	cputime_t cval, cinterval, nval, ninterval;
 
-	if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
-		return k;
 	switch (which) {
-		case ITIMER_REAL:
-			del_timer_sync(&current->real_timer);
-			expire = timeval_to_jiffies(&value->it_value);
-			current->it_real_value = expire;
-			current->it_real_incr =
-				timeval_to_jiffies(&value->it_interval);
-			if (!expire)
-				break;
-			if (expire > (unsigned long) LONG_MAX)
-				expire = LONG_MAX;
-			current->real_timer.expires = jiffies + expire;
-			add_timer(&current->real_timer);
-			break;
-		case ITIMER_VIRTUAL:
-			cputime = timeval_to_cputime(&value->it_value);
-			if (cputime_gt(cputime, cputime_zero))
-				cputime = cputime_add(cputime,
-						      jiffies_to_cputime(1));
-			current->it_virt_value = cputime;
-			cputime = timeval_to_cputime(&value->it_interval);
-			current->it_virt_incr = cputime;
-			break;
-		case ITIMER_PROF:
-			cputime = timeval_to_cputime(&value->it_value);
-			if (cputime_gt(cputime, cputime_zero))
-				cputime = cputime_add(cputime,
-						      jiffies_to_cputime(1));
-			current->it_prof_value = cputime;
-			cputime = timeval_to_cputime(&value->it_interval);
-			current->it_prof_incr = cputime;
-			break;
-		default:
-			return -EINVAL;
+	case ITIMER_REAL:
+		spin_lock_irq(&tsk->sighand->siglock);
+		interval = tsk->signal->it_real_incr;
+		val = it_real_value(tsk->signal);
+		if (val)
+			del_timer_sync(&tsk->signal->real_timer);
+		tsk->signal->it_real_incr =
+			timeval_to_jiffies(&value->it_interval);
+		it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
+		spin_unlock_irq(&tsk->sighand->siglock);
+		if (ovalue) {
+			jiffies_to_timeval(val, &ovalue->it_value);
+			jiffies_to_timeval(interval,
+					   &ovalue->it_interval);
+		}
+		break;
+	case ITIMER_VIRTUAL:
+		nval = timeval_to_cputime(&value->it_value);
+		ninterval = timeval_to_cputime(&value->it_interval);
+		read_lock(&tasklist_lock);
+		spin_lock_irq(&tsk->sighand->siglock);
+		cval = tsk->signal->it_virt_expires;
+		cinterval = tsk->signal->it_virt_incr;
+		if (!cputime_eq(cval, cputime_zero) ||
+		    !cputime_eq(nval, cputime_zero)) {
+			if (cputime_gt(nval, cputime_zero))
+				nval = cputime_add(nval,
+						   jiffies_to_cputime(1));
+			set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
+					      &nval, &cval);
+		}
+		tsk->signal->it_virt_expires = nval;
+		tsk->signal->it_virt_incr = ninterval;
+		spin_unlock_irq(&tsk->sighand->siglock);
+		read_unlock(&tasklist_lock);
+		if (ovalue) {
+			cputime_to_timeval(cval, &ovalue->it_value);
+			cputime_to_timeval(cinterval, &ovalue->it_interval);
+		}
+		break;
+	case ITIMER_PROF:
+		nval = timeval_to_cputime(&value->it_value);
+		ninterval = timeval_to_cputime(&value->it_interval);
+		read_lock(&tasklist_lock);
+		spin_lock_irq(&tsk->sighand->siglock);
+		cval = tsk->signal->it_prof_expires;
+		cinterval = tsk->signal->it_prof_incr;
+		if (!cputime_eq(cval, cputime_zero) ||
+		    !cputime_eq(nval, cputime_zero)) {
+			if (cputime_gt(nval, cputime_zero))
+				nval = cputime_add(nval,
+						   jiffies_to_cputime(1));
+			set_process_cpu_timer(tsk, CPUCLOCK_PROF,
+					      &nval, &cval);
+		}
+		tsk->signal->it_prof_expires = nval;
+		tsk->signal->it_prof_incr = ninterval;
+		spin_unlock_irq(&tsk->sighand->siglock);
+		read_unlock(&tasklist_lock);
+		if (ovalue) {
+			cputime_to_timeval(cval, &ovalue->it_value);
+			cputime_to_timeval(cinterval, &ovalue->it_interval);
+		}
+		break;
+	default:
+		return -EINVAL;
 	}
 	return 0;
 }
 
-/* SMP: Again, only we play with our itimers, and signals are SMP safe
- *      now so that is not an issue at all anymore.
- */
 asmlinkage long sys_setitimer(int which,
 			      struct itimerval __user *value,
 			      struct itimerval __user *ovalue)
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -46,6 +46,14 @@ static inline int is_kernel_inittext(uns
 	return 0;
 }
 
+static inline int is_kernel_extratext(unsigned long addr)
+{
+	if (addr >= (unsigned long)_sextratext
+	    && addr <= (unsigned long)_eextratext)
+		return 1;
+	return 0;
+}
+
 static inline int is_kernel_text(unsigned long addr)
 {
 	if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
@@ -145,14 +153,22 @@ unsigned long kallsyms_lookup_name(const
 	}
 	return module_kallsyms_lookup_name(name);
 }
+EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
 
-/* Lookup an address.  modname is set to NULL if it's in the kernel. */
+/*
+ * Lookup an address
+ * - modname is set to NULL if it's in the kernel
+ * - we guarantee that the returned name is valid until we reschedule even if
+ *   it resides in a module
+ * - we also guarantee that modname will be valid until rescheduled
+ */
 const char *kallsyms_lookup(unsigned long addr,
 			    unsigned long *symbolsize,
 			    unsigned long *offset,
 			    char **modname, char *namebuf)
 {
 	unsigned long i, low, high, mid;
+	const char *msym;
 
 	/* This kernel should never had been booted. */
 	BUG_ON(!kallsyms_addresses);
@@ -161,8 +177,9 @@ const char *kallsyms_lookup(unsigned lon
 	namebuf[0] = 0;
 
 	if ((all_var && is_kernel(addr)) ||
-	    (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr)))) {
-		unsigned long symbol_end=0;
+	    (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
+				is_kernel_extratext(addr)))) {
+		unsigned long symbol_end = 0;
 
 		/* do a binary search on the sorted kallsyms_addresses array */
 		low = 0;
@@ -204,7 +221,12 @@ const char *kallsyms_lookup(unsigned lon
 		return namebuf;
 	}
 
-	return module_address_lookup(addr, symbolsize, offset, modname);
+	/* see if it's in a module */
+	msym = module_address_lookup(addr, symbolsize, offset, modname);
+	if (msym)
+		return strncpy(namebuf, msym, KSYM_NAME_LEN);
+
+	return NULL;
 }
 
 /* Replace "%s" in format with address, or returns -errno. */
@@ -342,7 +364,7 @@ static int s_show(struct seq_file *m, vo
 	return 0;
 }
 
-struct seq_operations kallsyms_op = {
+static struct seq_operations kallsyms_op = {
 	.start = s_start,
 	.next = s_next,
 	.stop = s_stop,
@@ -384,7 +406,7 @@ static struct file_operations kallsyms_o
 	.release = kallsyms_release,
 };
 
-int __init kallsyms_init(void)
+static int __init kallsyms_init(void)
 {
 	struct proc_dir_entry *entry;
 
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/kfifo.h>
 
-/*
+/**
  * kfifo_init - allocates a new FIFO using a preallocated buffer
  * @buffer: the preallocated buffer to be used.
  * @size: the size of the internal buffer, this have to be a power of 2.
@@ -36,7 +36,7 @@
  * struct kfifo with kfree().
  */
 struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
-			 int gfp_mask, spinlock_t *lock)
+			 unsigned int __nocast gfp_mask, spinlock_t *lock)
 {
 	struct kfifo *fifo;
 
@@ -56,7 +56,7 @@ struct kfifo *kfifo_init(unsigned char *
 }
 EXPORT_SYMBOL(kfifo_init);
 
-/*
+/**
  * kfifo_alloc - allocates a new FIFO and its internal buffer
  * @size: the size of the internal buffer to be allocated.
  * @gfp_mask: get_free_pages mask, passed to kmalloc()
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(kfifo_init);
  *
  * The size will be rounded-up to a power of 2.
  */
-struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask, spinlock_t *lock)
+struct kfifo *kfifo_alloc(unsigned int size, unsigned int __nocast gfp_mask, spinlock_t *lock)
 {
 	unsigned char *buffer;
 	struct kfifo *ret;
@@ -91,7 +91,7 @@ struct kfifo *kfifo_alloc(unsigned int s
 }
 EXPORT_SYMBOL(kfifo_alloc);
 
-/*
+/**
  * kfifo_free - frees the FIFO
  * @fifo: the fifo to be freed.
  */
@@ -102,7 +102,7 @@ void kfifo_free(struct kfifo *fifo)
 }
 EXPORT_SYMBOL(kfifo_free);
 
-/*
+/**
  * __kfifo_put - puts some data into the FIFO, no locking version
  * @fifo: the fifo to be used.
  * @buffer: the data to be added.
@@ -135,7 +135,7 @@ unsigned int __kfifo_put(struct kfifo *f
 }
 EXPORT_SYMBOL(__kfifo_put);
 
-/*
+/**
  * __kfifo_get - gets some data from the FIFO, no locking version
  * @fifo: the fifo to be used.
  * @buffer: where the data must be copied.
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -44,6 +44,7 @@ static struct hlist_head kprobe_table[KP
 
 unsigned int kprobe_cpu = NR_CPUS;
 static DEFINE_SPINLOCK(kprobe_lock);
+static struct kprobe *curr_kprobe;
 
 /* Locks kprobe: irqs must be disabled */
 void lock_kprobes(void)
@@ -73,22 +74,139 @@ struct kprobe *get_kprobe(void *addr)
 	return NULL;
 }
 
+/*
+ * Aggregate handlers for multiple kprobes support - these handlers
+ * take care of invoking the individual kprobe handlers on p->list
+ */
+int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe *kp;
+
+	list_for_each_entry(kp, &p->list, list) {
+		if (kp->pre_handler) {
+			curr_kprobe = kp;
+			kp->pre_handler(kp, regs);
+			curr_kprobe = NULL;
+		}
+	}
+	return 0;
+}
+
+void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
+		unsigned long flags)
+{
+	struct kprobe *kp;
+
+	list_for_each_entry(kp, &p->list, list) {
+		if (kp->post_handler) {
+			curr_kprobe = kp;
+			kp->post_handler(kp, regs, flags);
+			curr_kprobe = NULL;
+		}
+	}
+	return;
+}
+
+int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr)
+{
+	/*
+	 * if we faulted "during" the execution of a user specified
+	 * probe handler, invoke just that probe's fault handler
+	 */
+	if (curr_kprobe && curr_kprobe->fault_handler) {
+		if (curr_kprobe->fault_handler(curr_kprobe, regs, trapnr))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Fill in the required fields of the "manager kprobe". Replace the
+ * earlier kprobe in the hlist with the manager kprobe
+ */
+static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
+{
+	ap->addr = p->addr;
+	ap->opcode = p->opcode;
+	memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
+
+	ap->pre_handler = aggr_pre_handler;
+	ap->post_handler = aggr_post_handler;
+	ap->fault_handler = aggr_fault_handler;
+
+	INIT_LIST_HEAD(&ap->list);
+	list_add(&p->list, &ap->list);
+
+	INIT_HLIST_NODE(&ap->hlist);
+	hlist_del(&p->hlist);
+	hlist_add_head(&ap->hlist,
+		&kprobe_table[hash_ptr(ap->addr, KPROBE_HASH_BITS)]);
+}
+
+/*
+ * This is the second or subsequent kprobe at the address - handle
+ * the intricacies
+ * TODO: Move kcalloc outside the spinlock
+ */
+static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
+{
+	int ret = 0;
+	struct kprobe *ap;
+
+	if (old_p->break_handler || p->break_handler) {
+		ret = -EEXIST;	/* kprobe and jprobe can't (yet) coexist */
+	} else if (old_p->pre_handler == aggr_pre_handler) {
+		list_add(&p->list, &old_p->list);
+	} else {
+		ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
+		if (!ap)
+			return -ENOMEM;
+		add_aggr_kprobe(ap, old_p);
+		list_add(&p->list, &ap->list);
+	}
+	return ret;
+}
+
+/* kprobe removal house-keeping routines */
+static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags)
+{
+	*p->addr = p->opcode;
+	hlist_del(&p->hlist);
+	flush_icache_range((unsigned long) p->addr,
+		   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	spin_unlock_irqrestore(&kprobe_lock, flags);
+	arch_remove_kprobe(p);
+}
+
+static inline void cleanup_aggr_kprobe(struct kprobe *old_p,
+		struct kprobe *p, unsigned long flags)
+{
+	list_del(&p->list);
+	if (list_empty(&old_p->list)) {
+		cleanup_kprobe(old_p, flags);
+		kfree(old_p);
+	} else
+		spin_unlock_irqrestore(&kprobe_lock, flags);
+}
+
 int register_kprobe(struct kprobe *p)
 {
 	int ret = 0;
 	unsigned long flags = 0;
+	struct kprobe *old_p;
 
 	if ((ret = arch_prepare_kprobe(p)) != 0) {
-		goto out;
+		goto rm_kprobe;
 	}
 	spin_lock_irqsave(&kprobe_lock, flags);
-	INIT_HLIST_NODE(&p->hlist);
-	if (get_kprobe(p->addr)) {
-		ret = -EEXIST;
+	old_p = get_kprobe(p->addr);
+	if (old_p) {
+		ret = register_aggr_kprobe(old_p, p);
 		goto out;
 	}
-	arch_copy_kprobe(p);
 
+	arch_copy_kprobe(p);
+	INIT_HLIST_NODE(&p->hlist);
 	hlist_add_head(&p->hlist,
 		       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
@@ -96,8 +214,9 @@ int register_kprobe(struct kprobe *p)
 	*p->addr = BREAKPOINT_INSTRUCTION;
 	flush_icache_range((unsigned long) p->addr,
 			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
-      out:
+out:
 	spin_unlock_irqrestore(&kprobe_lock, flags);
+rm_kprobe:
 	if (ret == -EEXIST)
 		arch_remove_kprobe(p);
 	return ret;
@@ -106,13 +225,17 @@ int register_kprobe(struct kprobe *p)
 void unregister_kprobe(struct kprobe *p)
 {
 	unsigned long flags;
-	arch_remove_kprobe(p);
+	struct kprobe *old_p;
+
 	spin_lock_irqsave(&kprobe_lock, flags);
-	*p->addr = p->opcode;
-	hlist_del(&p->hlist);
-	flush_icache_range((unsigned long) p->addr,
-			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
-	spin_unlock_irqrestore(&kprobe_lock, flags);
+	old_p = get_kprobe(p->addr);
+	if (old_p) {
+		if (old_p->pre_handler == aggr_pre_handler)
+			cleanup_aggr_kprobe(old_p, p, flags);
+		else
+			cleanup_kprobe(p, flags);
+	} else
+		spin_unlock_irqrestore(&kprobe_lock, flags);
 }
 
 static struct notifier_block kprobe_exceptions_nb = {
diff --git a/kernel/kthread.c b/kernel/kthread.c
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -174,7 +174,7 @@ int kthread_stop(struct task_struct *k)
 
 	/* Must init completion *before* thread sees kthread_stop_info.k */
 	init_completion(&kthread_stop_info.done);
-	wmb();
+	smp_wmb();
 
 	/* Now set kthread_should_stop() to true, and wake it up. */
 	kthread_stop_info.k = k;
diff --git a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -472,7 +472,7 @@ struct stopref
 };
 
 /* Whole machine is stopped with interrupts off when this runs. */
-static inline int __try_stop_module(void *_sref)
+static int __try_stop_module(void *_sref)
 {
 	struct stopref *sref = _sref;
 
@@ -1072,14 +1072,22 @@ static void mod_kobject_remove(struct mo
 	kobject_unregister(&mod->mkobj.kobj);
 }
 
+/*
+ * unlink the module with the whole machine is stopped with interrupts off
+ * - this defends against kallsyms not taking locks
+ */
+static int __unlink_module(void *_mod)
+{
+	struct module *mod = _mod;
+	list_del(&mod->list);
+	return 0;
+}
+
 /* Free a module, remove from lists, etc (must hold module mutex). */
 static void free_module(struct module *mod)
 {
 	/* Delete from various lists */
-	spin_lock_irq(&modlist_lock);
-	list_del(&mod->list);
-	spin_unlock_irq(&modlist_lock);
-
+	stop_machine_run(__unlink_module, mod, NR_CPUS);
 	remove_sect_attrs(mod);
 	mod_kobject_remove(mod);
 
@@ -1732,6 +1740,17 @@ static struct module *load_module(void _
 	goto free_hdr;
 }
 
+/*
+ * link the module with the whole machine is stopped with interrupts off
+ * - this defends against kallsyms not taking locks
+ */
+static int __link_module(void *_mod)
+{
+	struct module *mod = _mod;
+	list_add(&mod->list, &modules);
+	return 0;
+}
+
 /* This is where the real work happens */
 asmlinkage long
 sys_init_module(void __user *umod,
@@ -1739,6 +1758,7 @@ sys_init_module(void __user *umod,
 		const char __user *uargs)
 {
 	struct module *mod;
+	mm_segment_t old_fs = get_fs();
 	int ret = 0;
 
 	/* Must have permission */
@@ -1756,6 +1776,9 @@ sys_init_module(void __user *umod,
 		return PTR_ERR(mod);
 	}
 
+	/* flush the icache in correct context */
+	set_fs(KERNEL_DS);
+
 	/* Flush the instruction cache, since we've played with text */
 	if (mod->module_init)
 		flush_icache_range((unsigned long)mod->module_init,
@@ -1764,11 +1787,11 @@ sys_init_module(void __user *umod,
 	flush_icache_range((unsigned long)mod->module_core,
 			   (unsigned long)mod->module_core + mod->core_size);
 
+	set_fs(old_fs);
+
 	/* Now sew it into the lists.  They won't access us, since
            strong_try_module_get() will fail. */
-	spin_lock_irq(&modlist_lock);
-	list_add(&mod->list, &modules);
-	spin_unlock_irq(&modlist_lock);
+	stop_machine_run(__link_module, mod, NR_CPUS);
 
 	/* Drop lock so they can recurse */
 	up(&module_mutex);
@@ -1784,7 +1807,7 @@ sys_init_module(void __user *umod,
 		/* Init routine failed: abort.  Try to protect us from
                    buggy refcounters. */
 		mod->state = MODULE_STATE_GOING;
-		synchronize_kernel();
+		synchronize_sched();
 		if (mod->unsafe)
 			printk(KERN_ERR "%s: module is now stuck!\n",
 			       mod->name);
diff --git a/kernel/panic.c b/kernel/panic.c
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -49,8 +49,7 @@ EXPORT_SYMBOL(panic_blink);
  *	panic - halt the system
  *	@fmt: The text string to print
  *
- *	Display a message, then perform cleanups. Functions in the panic
- *	notifier list are called after the filesystem cache is flushed (when possible).
+ *	Display a message, then perform cleanups.
  *
  *	This function never returns.
  */
@@ -103,9 +102,9 @@ NORET_TYPE void panic(const char * fmt, 
 #ifdef __sparc__
 	{
 		extern int stop_a_enabled;
-		/* Make sure the user can actually press L1-A */
+		/* Make sure the user can actually press Stop-A (L1-A) */
 		stop_a_enabled = 1;
-		printk(KERN_EMERG "Press L1-A to return to the boot prom\n");
+		printk(KERN_EMERG "Press Stop-A (L1-A) to return to the boot prom\n");
 	}
 #endif
 #if defined(CONFIG_ARCH_S390)
diff --git a/kernel/params.c b/kernel/params.c
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -314,9 +314,10 @@ int param_array(const char *name,
 int param_array_set(const char *val, struct kernel_param *kp)
 {
 	struct kparam_array *arr = kp->arg;
+	unsigned int temp_num;
 
 	return param_array(kp->name, val, 1, arr->max, arr->elem,
-			   arr->elemsize, arr->set, arr->num ?: &arr->max);
+			   arr->elemsize, arr->set, arr->num ?: &temp_num);
 }
 
 int param_array_get(char *buffer, struct kernel_param *kp)
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
new file mode 100644
--- /dev/null
+++ b/kernel/posix-cpu-timers.c
@@ -0,0 +1,1559 @@
+/*
+ * Implement CPU time clocks for the POSIX clock interface.
+ */
+
+#include <linux/sched.h>
+#include <linux/posix-timers.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+
+static int check_clock(clockid_t which_clock)
+{
+	int error = 0;
+	struct task_struct *p;
+	const pid_t pid = CPUCLOCK_PID(which_clock);
+
+	if (CPUCLOCK_WHICH(which_clock) >= CPUCLOCK_MAX)
+		return -EINVAL;
+
+	if (pid == 0)
+		return 0;
+
+	read_lock(&tasklist_lock);
+	p = find_task_by_pid(pid);
+	if (!p || (CPUCLOCK_PERTHREAD(which_clock) ?
+		   p->tgid != current->tgid : p->tgid != pid)) {
+		error = -EINVAL;
+	}
+	read_unlock(&tasklist_lock);
+
+	return error;
+}
+
+static inline union cpu_time_count
+timespec_to_sample(clockid_t which_clock, const struct timespec *tp)
+{
+	union cpu_time_count ret;
+	ret.sched = 0;		/* high half always zero when .cpu used */
+	if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+		ret.sched = tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec;
+	} else {
+		ret.cpu = timespec_to_cputime(tp);
+	}
+	return ret;
+}
+
+static void sample_to_timespec(clockid_t which_clock,
+			       union cpu_time_count cpu,
+			       struct timespec *tp)
+{
+	if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+		tp->tv_sec = div_long_long_rem(cpu.sched,
+					       NSEC_PER_SEC, &tp->tv_nsec);
+	} else {
+		cputime_to_timespec(cpu.cpu, tp);
+	}
+}
+
+static inline int cpu_time_before(clockid_t which_clock,
+				  union cpu_time_count now,
+				  union cpu_time_count then)
+{
+	if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+		return now.sched < then.sched;
+	}  else {
+		return cputime_lt(now.cpu, then.cpu);
+	}
+}
+static inline void cpu_time_add(clockid_t which_clock,
+				union cpu_time_count *acc,
+			        union cpu_time_count val)
+{
+	if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+		acc->sched += val.sched;
+	}  else {
+		acc->cpu = cputime_add(acc->cpu, val.cpu);
+	}
+}
+static inline union cpu_time_count cpu_time_sub(clockid_t which_clock,
+						union cpu_time_count a,
+						union cpu_time_count b)
+{
+	if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+		a.sched -= b.sched;
+	}  else {
+		a.cpu = cputime_sub(a.cpu, b.cpu);
+	}
+	return a;
+}
+
+/*
+ * Update expiry time from increment, and increase overrun count,
+ * given the current clock sample.
+ */
+static inline void bump_cpu_timer(struct k_itimer *timer,
+				  union cpu_time_count now)
+{
+	int i;
+
+	if (timer->it.cpu.incr.sched == 0)
+		return;
+
+	if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
+		unsigned long long delta, incr;
+
+		if (now.sched < timer->it.cpu.expires.sched)
+			return;
+		incr = timer->it.cpu.incr.sched;
+		delta = now.sched + incr - timer->it.cpu.expires.sched;
+		/* Don't use (incr*2 < delta), incr*2 might overflow. */
+		for (i = 0; incr < delta - incr; i++)
+			incr = incr << 1;
+		for (; i >= 0; incr >>= 1, i--) {
+			if (delta <= incr)
+				continue;
+			timer->it.cpu.expires.sched += incr;
+			timer->it_overrun += 1 << i;
+			delta -= incr;
+		}
+	} else {
+		cputime_t delta, incr;
+
+		if (cputime_lt(now.cpu, timer->it.cpu.expires.cpu))
+			return;
+		incr = timer->it.cpu.incr.cpu;
+		delta = cputime_sub(cputime_add(now.cpu, incr),
+				    timer->it.cpu.expires.cpu);
+		/* Don't use (incr*2 < delta), incr*2 might overflow. */
+		for (i = 0; cputime_lt(incr, cputime_sub(delta, incr)); i++)
+			     incr = cputime_add(incr, incr);
+		for (; i >= 0; incr = cputime_halve(incr), i--) {
+			if (cputime_le(delta, incr))
+				continue;
+			timer->it.cpu.expires.cpu =
+				cputime_add(timer->it.cpu.expires.cpu, incr);
+			timer->it_overrun += 1 << i;
+			delta = cputime_sub(delta, incr);
+		}
+	}
+}
+
+static inline cputime_t prof_ticks(struct task_struct *p)
+{
+	return cputime_add(p->utime, p->stime);
+}
+static inline cputime_t virt_ticks(struct task_struct *p)
+{
+	return p->utime;
+}
+static inline unsigned long long sched_ns(struct task_struct *p)
+{
+	return (p == current) ? current_sched_time(p) : p->sched_time;
+}
+
+int posix_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+{
+	int error = check_clock(which_clock);
+	if (!error) {
+		tp->tv_sec = 0;
+		tp->tv_nsec = ((NSEC_PER_SEC + HZ - 1) / HZ);
+		if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
+			/*
+			 * If sched_clock is using a cycle counter, we
+			 * don't have any idea of its true resolution
+			 * exported, but it is much more than 1s/HZ.
+			 */
+			tp->tv_nsec = 1;
+		}
+	}
+	return error;
+}
+
+int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp)
+{
+	/*
+	 * You can never reset a CPU clock, but we check for other errors
+	 * in the call before failing with EPERM.
+	 */
+	int error = check_clock(which_clock);
+	if (error == 0) {
+		error = -EPERM;
+	}
+	return error;
+}
+
+
+/*
+ * Sample a per-thread clock for the given task.
+ */
+static int cpu_clock_sample(clockid_t which_clock, struct task_struct *p,
+			    union cpu_time_count *cpu)
+{
+	switch (CPUCLOCK_WHICH(which_clock)) {
+	default:
+		return -EINVAL;
+	case CPUCLOCK_PROF:
+		cpu->cpu = prof_ticks(p);
+		break;
+	case CPUCLOCK_VIRT:
+		cpu->cpu = virt_ticks(p);
+		break;
+	case CPUCLOCK_SCHED:
+		cpu->sched = sched_ns(p);
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Sample a process (thread group) clock for the given group_leader task.
+ * Must be called with tasklist_lock held for reading.
+ * Must be called with tasklist_lock held for reading, and p->sighand->siglock.
+ */
+static int cpu_clock_sample_group_locked(unsigned int clock_idx,
+					 struct task_struct *p,
+					 union cpu_time_count *cpu)
+{
+	struct task_struct *t = p;
+ 	switch (clock_idx) {
+	default:
+		return -EINVAL;
+	case CPUCLOCK_PROF:
+		cpu->cpu = cputime_add(p->signal->utime, p->signal->stime);
+		do {
+			cpu->cpu = cputime_add(cpu->cpu, prof_ticks(t));
+			t = next_thread(t);
+		} while (t != p);
+		break;
+	case CPUCLOCK_VIRT:
+		cpu->cpu = p->signal->utime;
+		do {
+			cpu->cpu = cputime_add(cpu->cpu, virt_ticks(t));
+			t = next_thread(t);
+		} while (t != p);
+		break;
+	case CPUCLOCK_SCHED:
+		cpu->sched = p->signal->sched_time;
+		/* Add in each other live thread.  */
+		while ((t = next_thread(t)) != p) {
+			cpu->sched += t->sched_time;
+		}
+		if (p->tgid == current->tgid) {
+			/*
+			 * We're sampling ourselves, so include the
+			 * cycles not yet banked.  We still omit
+			 * other threads running on other CPUs,
+			 * so the total can always be behind as
+			 * much as max(nthreads-1,ncpus) * (NSEC_PER_SEC/HZ).
+			 */
+			cpu->sched += current_sched_time(current);
+		} else {
+			cpu->sched += p->sched_time;
+		}
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Sample a process (thread group) clock for the given group_leader task.
+ * Must be called with tasklist_lock held for reading.
+ */
+static int cpu_clock_sample_group(clockid_t which_clock,
+				  struct task_struct *p,
+				  union cpu_time_count *cpu)
+{
+	int ret;
+	unsigned long flags;
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	ret = cpu_clock_sample_group_locked(CPUCLOCK_WHICH(which_clock), p,
+					    cpu);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	return ret;
+}
+
+
+int posix_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+{
+	const pid_t pid = CPUCLOCK_PID(which_clock);
+	int error = -EINVAL;
+	union cpu_time_count rtn;
+
+	if (pid == 0) {
+		/*
+		 * Special case constant value for our own clocks.
+		 * We don't have to do any lookup to find ourselves.
+		 */
+		if (CPUCLOCK_PERTHREAD(which_clock)) {
+			/*
+			 * Sampling just ourselves we can do with no locking.
+			 */
+			error = cpu_clock_sample(which_clock,
+						 current, &rtn);
+		} else {
+			read_lock(&tasklist_lock);
+			error = cpu_clock_sample_group(which_clock,
+						       current, &rtn);
+			read_unlock(&tasklist_lock);
+		}
+	} else {
+		/*
+		 * Find the given PID, and validate that the caller
+		 * should be able to see it.
+		 */
+		struct task_struct *p;
+		read_lock(&tasklist_lock);
+		p = find_task_by_pid(pid);
+		if (p) {
+			if (CPUCLOCK_PERTHREAD(which_clock)) {
+				if (p->tgid == current->tgid) {
+					error = cpu_clock_sample(which_clock,
+								 p, &rtn);
+				}
+			} else if (p->tgid == pid && p->signal) {
+				error = cpu_clock_sample_group(which_clock,
+							       p, &rtn);
+			}
+		}
+		read_unlock(&tasklist_lock);
+	}
+
+	if (error)
+		return error;
+	sample_to_timespec(which_clock, rtn, tp);
+	return 0;
+}
+
+
+/*
+ * Validate the clockid_t for a new CPU-clock timer, and initialize the timer.
+ * This is called from sys_timer_create with the new timer already locked.
+ */
+int posix_cpu_timer_create(struct k_itimer *new_timer)
+{
+	int ret = 0;
+	const pid_t pid = CPUCLOCK_PID(new_timer->it_clock);
+	struct task_struct *p;
+
+	if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&new_timer->it.cpu.entry);
+	new_timer->it.cpu.incr.sched = 0;
+	new_timer->it.cpu.expires.sched = 0;
+
+	read_lock(&tasklist_lock);
+	if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) {
+		if (pid == 0) {
+			p = current;
+		} else {
+			p = find_task_by_pid(pid);
+			if (p && p->tgid != current->tgid)
+				p = NULL;
+		}
+	} else {
+		if (pid == 0) {
+			p = current->group_leader;
+		} else {
+			p = find_task_by_pid(pid);
+			if (p && p->tgid != pid)
+				p = NULL;
+		}
+	}
+	new_timer->it.cpu.task = p;
+	if (p) {
+		get_task_struct(p);
+	} else {
+		ret = -EINVAL;
+	}
+	read_unlock(&tasklist_lock);
+
+	return ret;
+}
+
+/*
+ * Clean up a CPU-clock timer that is about to be destroyed.
+ * This is called from timer deletion with the timer already locked.
+ * If we return TIMER_RETRY, it's necessary to release the timer's lock
+ * and try again.  (This happens when the timer is in the middle of firing.)
+ */
+int posix_cpu_timer_del(struct k_itimer *timer)
+{
+	struct task_struct *p = timer->it.cpu.task;
+
+	if (timer->it.cpu.firing)
+		return TIMER_RETRY;
+
+	if (unlikely(p == NULL))
+		return 0;
+
+	if (!list_empty(&timer->it.cpu.entry)) {
+		read_lock(&tasklist_lock);
+		if (unlikely(p->signal == NULL)) {
+			/*
+			 * We raced with the reaping of the task.
+			 * The deletion should have cleared us off the list.
+			 */
+			BUG_ON(!list_empty(&timer->it.cpu.entry));
+		} else {
+			/*
+			 * Take us off the task's timer list.
+			 */
+			spin_lock(&p->sighand->siglock);
+			list_del(&timer->it.cpu.entry);
+			spin_unlock(&p->sighand->siglock);
+		}
+		read_unlock(&tasklist_lock);
+	}
+	put_task_struct(p);
+
+	return 0;
+}
+
+/*
+ * Clean out CPU timers still ticking when a thread exited.  The task
+ * pointer is cleared, and the expiry time is replaced with the residual
+ * time for later timer_gettime calls to return.
+ * This must be called with the siglock held.
+ */
+static void cleanup_timers(struct list_head *head,
+			   cputime_t utime, cputime_t stime,
+			   unsigned long long sched_time)
+{
+	struct cpu_timer_list *timer, *next;
+	cputime_t ptime = cputime_add(utime, stime);
+
+	list_for_each_entry_safe(timer, next, head, entry) {
+		timer->task = NULL;
+		list_del_init(&timer->entry);
+		if (cputime_lt(timer->expires.cpu, ptime)) {
+			timer->expires.cpu = cputime_zero;
+		} else {
+			timer->expires.cpu = cputime_sub(timer->expires.cpu,
+							 ptime);
+		}
+	}
+
+	++head;
+	list_for_each_entry_safe(timer, next, head, entry) {
+		timer->task = NULL;
+		list_del_init(&timer->entry);
+		if (cputime_lt(timer->expires.cpu, utime)) {
+			timer->expires.cpu = cputime_zero;
+		} else {
+			timer->expires.cpu = cputime_sub(timer->expires.cpu,
+							 utime);
+		}
+	}
+
+	++head;
+	list_for_each_entry_safe(timer, next, head, entry) {
+		timer->task = NULL;
+		list_del_init(&timer->entry);
+		if (timer->expires.sched < sched_time) {
+			timer->expires.sched = 0;
+		} else {
+			timer->expires.sched -= sched_time;
+		}
+	}
+}
+
+/*
+ * These are both called with the siglock held, when the current thread
+ * is being reaped.  When the final (leader) thread in the group is reaped,
+ * posix_cpu_timers_exit_group will be called after posix_cpu_timers_exit.
+ */
+void posix_cpu_timers_exit(struct task_struct *tsk)
+{
+	cleanup_timers(tsk->cpu_timers,
+		       tsk->utime, tsk->stime, tsk->sched_time);
+
+}
+void posix_cpu_timers_exit_group(struct task_struct *tsk)
+{
+	cleanup_timers(tsk->signal->cpu_timers,
+		       cputime_add(tsk->utime, tsk->signal->utime),
+		       cputime_add(tsk->stime, tsk->signal->stime),
+		       tsk->sched_time + tsk->signal->sched_time);
+}
+
+
+/*
+ * Set the expiry times of all the threads in the process so one of them
+ * will go off before the process cumulative expiry total is reached.
+ */
+static void process_timer_rebalance(struct task_struct *p,
+				    unsigned int clock_idx,
+				    union cpu_time_count expires,
+				    union cpu_time_count val)
+{
+	cputime_t ticks, left;
+	unsigned long long ns, nsleft;
+ 	struct task_struct *t = p;
+	unsigned int nthreads = atomic_read(&p->signal->live);
+
+	switch (clock_idx) {
+	default:
+		BUG();
+		break;
+	case CPUCLOCK_PROF:
+		left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+				   nthreads);
+		do {
+			if (!unlikely(t->exit_state)) {
+				ticks = cputime_add(prof_ticks(t), left);
+				if (cputime_eq(t->it_prof_expires,
+					       cputime_zero) ||
+				    cputime_gt(t->it_prof_expires, ticks)) {
+					t->it_prof_expires = ticks;
+				}
+			}
+			t = next_thread(t);
+		} while (t != p);
+		break;
+	case CPUCLOCK_VIRT:
+		left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+				   nthreads);
+		do {
+			if (!unlikely(t->exit_state)) {
+				ticks = cputime_add(virt_ticks(t), left);
+				if (cputime_eq(t->it_virt_expires,
+					       cputime_zero) ||
+				    cputime_gt(t->it_virt_expires, ticks)) {
+					t->it_virt_expires = ticks;
+				}
+			}
+			t = next_thread(t);
+		} while (t != p);
+		break;
+	case CPUCLOCK_SCHED:
+		nsleft = expires.sched - val.sched;
+		do_div(nsleft, nthreads);
+		do {
+			if (!unlikely(t->exit_state)) {
+				ns = t->sched_time + nsleft;
+				if (t->it_sched_expires == 0 ||
+				    t->it_sched_expires > ns) {
+					t->it_sched_expires = ns;
+				}
+			}
+			t = next_thread(t);
+		} while (t != p);
+		break;
+	}
+}
+
+static void clear_dead_task(struct k_itimer *timer, union cpu_time_count now)
+{
+	/*
+	 * That's all for this thread or process.
+	 * We leave our residual in expires to be reported.
+	 */
+	put_task_struct(timer->it.cpu.task);
+	timer->it.cpu.task = NULL;
+	timer->it.cpu.expires = cpu_time_sub(timer->it_clock,
+					     timer->it.cpu.expires,
+					     now);
+}
+
+/*
+ * Insert the timer on the appropriate list before any timers that
+ * expire later.  This must be called with the tasklist_lock held
+ * for reading, and interrupts disabled.
+ */
+static void arm_timer(struct k_itimer *timer, union cpu_time_count now)
+{
+	struct task_struct *p = timer->it.cpu.task;
+	struct list_head *head, *listpos;
+	struct cpu_timer_list *const nt = &timer->it.cpu;
+	struct cpu_timer_list *next;
+	unsigned long i;
+
+	head = (CPUCLOCK_PERTHREAD(timer->it_clock) ?
+		p->cpu_timers : p->signal->cpu_timers);
+	head += CPUCLOCK_WHICH(timer->it_clock);
+
+	BUG_ON(!irqs_disabled());
+	spin_lock(&p->sighand->siglock);
+
+	listpos = head;
+	if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
+		list_for_each_entry(next, head, entry) {
+			if (next->expires.sched > nt->expires.sched) {
+				listpos = &next->entry;
+				break;
+			}
+		}
+	} else {
+		list_for_each_entry(next, head, entry) {
+			if (cputime_gt(next->expires.cpu, nt->expires.cpu)) {
+				listpos = &next->entry;
+				break;
+			}
+		}
+	}
+	list_add(&nt->entry, listpos);
+
+	if (listpos == head) {
+		/*
+		 * We are the new earliest-expiring timer.
+		 * If we are a thread timer, there can always
+		 * be a process timer telling us to stop earlier.
+		 */
+
+		if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+			switch (CPUCLOCK_WHICH(timer->it_clock)) {
+			default:
+				BUG();
+			case CPUCLOCK_PROF:
+				if (cputime_eq(p->it_prof_expires,
+					       cputime_zero) ||
+				    cputime_gt(p->it_prof_expires,
+					       nt->expires.cpu))
+					p->it_prof_expires = nt->expires.cpu;
+				break;
+			case CPUCLOCK_VIRT:
+				if (cputime_eq(p->it_virt_expires,
+					       cputime_zero) ||
+				    cputime_gt(p->it_virt_expires,
+					       nt->expires.cpu))
+					p->it_virt_expires = nt->expires.cpu;
+				break;
+			case CPUCLOCK_SCHED:
+				if (p->it_sched_expires == 0 ||
+				    p->it_sched_expires > nt->expires.sched)
+					p->it_sched_expires = nt->expires.sched;
+				break;
+			}
+		} else {
+			/*
+			 * For a process timer, we must balance
+			 * all the live threads' expirations.
+			 */
+			switch (CPUCLOCK_WHICH(timer->it_clock)) {
+			default:
+				BUG();
+			case CPUCLOCK_VIRT:
+				if (!cputime_eq(p->signal->it_virt_expires,
+						cputime_zero) &&
+				    cputime_lt(p->signal->it_virt_expires,
+					       timer->it.cpu.expires.cpu))
+					break;
+				goto rebalance;
+			case CPUCLOCK_PROF:
+				if (!cputime_eq(p->signal->it_prof_expires,
+						cputime_zero) &&
+				    cputime_lt(p->signal->it_prof_expires,
+					       timer->it.cpu.expires.cpu))
+					break;
+				i = p->signal->rlim[RLIMIT_CPU].rlim_cur;
+				if (i != RLIM_INFINITY &&
+				    i <= cputime_to_secs(timer->it.cpu.expires.cpu))
+					break;
+				goto rebalance;
+			case CPUCLOCK_SCHED:
+			rebalance:
+				process_timer_rebalance(
+					timer->it.cpu.task,
+					CPUCLOCK_WHICH(timer->it_clock),
+					timer->it.cpu.expires, now);
+				break;
+			}
+		}
+	}
+
+	spin_unlock(&p->sighand->siglock);
+}
+
+/*
+ * The timer is locked, fire it and arrange for its reload.
+ */
+static void cpu_timer_fire(struct k_itimer *timer)
+{
+	if (unlikely(timer->sigq == NULL)) {
+		/*
+		 * This a special case for clock_nanosleep,
+		 * not a normal timer from sys_timer_create.
+		 */
+		wake_up_process(timer->it_process);
+		timer->it.cpu.expires.sched = 0;
+	} else if (timer->it.cpu.incr.sched == 0) {
+		/*
+		 * One-shot timer.  Clear it as soon as it's fired.
+		 */
+		posix_timer_event(timer, 0);
+		timer->it.cpu.expires.sched = 0;
+	} else if (posix_timer_event(timer, ++timer->it_requeue_pending)) {
+		/*
+		 * The signal did not get queued because the signal
+		 * was ignored, so we won't get any callback to
+		 * reload the timer.  But we need to keep it
+		 * ticking in case the signal is deliverable next time.
+		 */
+		posix_cpu_timer_schedule(timer);
+	}
+}
+
+/*
+ * Guts of sys_timer_settime for CPU timers.
+ * This is called with the timer locked and interrupts disabled.
+ * If we return TIMER_RETRY, it's necessary to release the timer's lock
+ * and try again.  (This happens when the timer is in the middle of firing.)
+ */
+int posix_cpu_timer_set(struct k_itimer *timer, int flags,
+			struct itimerspec *new, struct itimerspec *old)
+{
+	struct task_struct *p = timer->it.cpu.task;
+	union cpu_time_count old_expires, new_expires, val;
+	int ret;
+
+	if (unlikely(p == NULL)) {
+		/*
+		 * Timer refers to a dead task's clock.
+		 */
+		return -ESRCH;
+	}
+
+	new_expires = timespec_to_sample(timer->it_clock, &new->it_value);
+
+	read_lock(&tasklist_lock);
+	/*
+	 * We need the tasklist_lock to protect against reaping that
+	 * clears p->signal.  If p has just been reaped, we can no
+	 * longer get any information about it at all.
+	 */
+	if (unlikely(p->signal == NULL)) {
+		read_unlock(&tasklist_lock);
+		put_task_struct(p);
+		timer->it.cpu.task = NULL;
+		return -ESRCH;
+	}
+
+	/*
+	 * Disarm any old timer after extracting its expiry time.
+	 */
+	BUG_ON(!irqs_disabled());
+	spin_lock(&p->sighand->siglock);
+	old_expires = timer->it.cpu.expires;
+	list_del_init(&timer->it.cpu.entry);
+	spin_unlock(&p->sighand->siglock);
+
+	/*
+	 * We need to sample the current value to convert the new
+	 * value from to relative and absolute, and to convert the
+	 * old value from absolute to relative.  To set a process
+	 * timer, we need a sample to balance the thread expiry
+	 * times (in arm_timer).  With an absolute time, we must
+	 * check if it's already passed.  In short, we need a sample.
+	 */
+	if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+		cpu_clock_sample(timer->it_clock, p, &val);
+	} else {
+		cpu_clock_sample_group(timer->it_clock, p, &val);
+	}
+
+	if (old) {
+		if (old_expires.sched == 0) {
+			old->it_value.tv_sec = 0;
+			old->it_value.tv_nsec = 0;
+		} else {
+			/*
+			 * Update the timer in case it has
+			 * overrun already.  If it has,
+			 * we'll report it as having overrun
+			 * and with the next reloaded timer
+			 * already ticking, though we are
+			 * swallowing that pending
+			 * notification here to install the
+			 * new setting.
+			 */
+			bump_cpu_timer(timer, val);
+			if (cpu_time_before(timer->it_clock, val,
+					    timer->it.cpu.expires)) {
+				old_expires = cpu_time_sub(
+					timer->it_clock,
+					timer->it.cpu.expires, val);
+				sample_to_timespec(timer->it_clock,
+						   old_expires,
+						   &old->it_value);
+			} else {
+				old->it_value.tv_nsec = 1;
+				old->it_value.tv_sec = 0;
+			}
+		}
+	}
+
+	if (unlikely(timer->it.cpu.firing)) {
+		/*
+		 * We are colliding with the timer actually firing.
+		 * Punt after filling in the timer's old value, and
+		 * disable this firing since we are already reporting
+		 * it as an overrun (thanks to bump_cpu_timer above).
+		 */
+		read_unlock(&tasklist_lock);
+		timer->it.cpu.firing = -1;
+		ret = TIMER_RETRY;
+		goto out;
+	}
+
+	if (new_expires.sched != 0 && !(flags & TIMER_ABSTIME)) {
+		cpu_time_add(timer->it_clock, &new_expires, val);
+	}
+
+	/*
+	 * Install the new expiry time (or zero).
+	 * For a timer with no notification action, we don't actually
+	 * arm the timer (we'll just fake it for timer_gettime).
+	 */
+	timer->it.cpu.expires = new_expires;
+	if (new_expires.sched != 0 &&
+	    (timer->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE &&
+	    cpu_time_before(timer->it_clock, val, new_expires)) {
+		arm_timer(timer, val);
+	}
+
+	read_unlock(&tasklist_lock);
+
+	/*
+	 * Install the new reload setting, and
+	 * set up the signal and overrun bookkeeping.
+	 */
+	timer->it.cpu.incr = timespec_to_sample(timer->it_clock,
+						&new->it_interval);
+
+	/*
+	 * This acts as a modification timestamp for the timer,
+	 * so any automatic reload attempt will punt on seeing
+	 * that we have reset the timer manually.
+	 */
+	timer->it_requeue_pending = (timer->it_requeue_pending + 2) &
+		~REQUEUE_PENDING;
+	timer->it_overrun_last = 0;
+	timer->it_overrun = -1;
+
+	if (new_expires.sched != 0 &&
+	    (timer->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE &&
+	    !cpu_time_before(timer->it_clock, val, new_expires)) {
+		/*
+		 * The designated time already passed, so we notify
+		 * immediately, even if the thread never runs to
+		 * accumulate more time on this clock.
+		 */
+		cpu_timer_fire(timer);
+	}
+
+	ret = 0;
+ out:
+	if (old) {
+		sample_to_timespec(timer->it_clock,
+				   timer->it.cpu.incr, &old->it_interval);
+	}
+	return ret;
+}
+
+void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
+{
+	union cpu_time_count now;
+	struct task_struct *p = timer->it.cpu.task;
+	int clear_dead;
+
+	/*
+	 * Easy part: convert the reload time.
+	 */
+	sample_to_timespec(timer->it_clock,
+			   timer->it.cpu.incr, &itp->it_interval);
+
+	if (timer->it.cpu.expires.sched == 0) {	/* Timer not armed at all.  */
+		itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
+		return;
+	}
+
+	if (unlikely(p == NULL)) {
+		/*
+		 * This task already died and the timer will never fire.
+		 * In this case, expires is actually the dead value.
+		 */
+	dead:
+		sample_to_timespec(timer->it_clock, timer->it.cpu.expires,
+				   &itp->it_value);
+		return;
+	}
+
+	/*
+	 * Sample the clock to take the difference with the expiry time.
+	 */
+	if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+		cpu_clock_sample(timer->it_clock, p, &now);
+		clear_dead = p->exit_state;
+	} else {
+		read_lock(&tasklist_lock);
+		if (unlikely(p->signal == NULL)) {
+			/*
+			 * The process has been reaped.
+			 * We can't even collect a sample any more.
+			 * Call the timer disarmed, nothing else to do.
+			 */
+			put_task_struct(p);
+			timer->it.cpu.task = NULL;
+			timer->it.cpu.expires.sched = 0;
+			read_unlock(&tasklist_lock);
+			goto dead;
+		} else {
+			cpu_clock_sample_group(timer->it_clock, p, &now);
+			clear_dead = (unlikely(p->exit_state) &&
+				      thread_group_empty(p));
+		}
+		read_unlock(&tasklist_lock);
+	}
+
+	if ((timer->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
+		if (timer->it.cpu.incr.sched == 0 &&
+		    cpu_time_before(timer->it_clock,
+				    timer->it.cpu.expires, now)) {
+			/*
+			 * Do-nothing timer expired and has no reload,
+			 * so it's as if it was never set.
+			 */
+			timer->it.cpu.expires.sched = 0;
+			itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
+			return;
+		}
+		/*
+		 * Account for any expirations and reloads that should
+		 * have happened.
+		 */
+		bump_cpu_timer(timer, now);
+	}
+
+	if (unlikely(clear_dead)) {
+		/*
+		 * We've noticed that the thread is dead, but
+		 * not yet reaped.  Take this opportunity to
+		 * drop our task ref.
+		 */
+		clear_dead_task(timer, now);
+		goto dead;
+	}
+
+	if (cpu_time_before(timer->it_clock, now, timer->it.cpu.expires)) {
+		sample_to_timespec(timer->it_clock,
+				   cpu_time_sub(timer->it_clock,
+						timer->it.cpu.expires, now),
+				   &itp->it_value);
+	} else {
+		/*
+		 * The timer should have expired already, but the firing
+		 * hasn't taken place yet.  Say it's just about to expire.
+		 */
+		itp->it_value.tv_nsec = 1;
+		itp->it_value.tv_sec = 0;
+	}
+}
+
+/*
+ * Check for any per-thread CPU timers that have fired and move them off
+ * the tsk->cpu_timers[N] list onto the firing list.  Here we update the
+ * tsk->it_*_expires values to reflect the remaining thread CPU timers.
+ */
+static void check_thread_timers(struct task_struct *tsk,
+				struct list_head *firing)
+{
+	struct list_head *timers = tsk->cpu_timers;
+
+	tsk->it_prof_expires = cputime_zero;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
+			tsk->it_prof_expires = t->expires.cpu;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+
+	++timers;
+	tsk->it_virt_expires = cputime_zero;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
+			tsk->it_virt_expires = t->expires.cpu;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+
+	++timers;
+	tsk->it_sched_expires = 0;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (tsk->sched_time < t->expires.sched) {
+			tsk->it_sched_expires = t->expires.sched;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+}
+
+/*
+ * Check for any per-thread CPU timers that have fired and move them
+ * off the tsk->*_timers list onto the firing list.  Per-thread timers
+ * have already been taken off.
+ */
+static void check_process_timers(struct task_struct *tsk,
+				 struct list_head *firing)
+{
+	struct signal_struct *const sig = tsk->signal;
+	cputime_t utime, stime, ptime, virt_expires, prof_expires;
+	unsigned long long sched_time, sched_expires;
+	struct task_struct *t;
+	struct list_head *timers = sig->cpu_timers;
+
+	/*
+	 * Don't sample the current process CPU clocks if there are no timers.
+	 */
+	if (list_empty(&timers[CPUCLOCK_PROF]) &&
+	    cputime_eq(sig->it_prof_expires, cputime_zero) &&
+	    sig->rlim[RLIMIT_CPU].rlim_cur == RLIM_INFINITY &&
+	    list_empty(&timers[CPUCLOCK_VIRT]) &&
+	    cputime_eq(sig->it_virt_expires, cputime_zero) &&
+	    list_empty(&timers[CPUCLOCK_SCHED]))
+		return;
+
+	/*
+	 * Collect the current process totals.
+	 */
+	utime = sig->utime;
+	stime = sig->stime;
+	sched_time = sig->sched_time;
+	t = tsk;
+	do {
+		utime = cputime_add(utime, t->utime);
+		stime = cputime_add(stime, t->stime);
+		sched_time += t->sched_time;
+		t = next_thread(t);
+	} while (t != tsk);
+	ptime = cputime_add(utime, stime);
+
+	prof_expires = cputime_zero;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (cputime_lt(ptime, t->expires.cpu)) {
+			prof_expires = t->expires.cpu;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+
+	++timers;
+	virt_expires = cputime_zero;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (cputime_lt(utime, t->expires.cpu)) {
+			virt_expires = t->expires.cpu;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+
+	++timers;
+	sched_expires = 0;
+	while (!list_empty(timers)) {
+		struct cpu_timer_list *t = list_entry(timers->next,
+						      struct cpu_timer_list,
+						      entry);
+		if (sched_time < t->expires.sched) {
+			sched_expires = t->expires.sched;
+			break;
+		}
+		t->firing = 1;
+		list_move_tail(&t->entry, firing);
+	}
+
+	/*
+	 * Check for the special case process timers.
+	 */
+	if (!cputime_eq(sig->it_prof_expires, cputime_zero)) {
+		if (cputime_ge(ptime, sig->it_prof_expires)) {
+			/* ITIMER_PROF fires and reloads.  */
+			sig->it_prof_expires = sig->it_prof_incr;
+			if (!cputime_eq(sig->it_prof_expires, cputime_zero)) {
+				sig->it_prof_expires = cputime_add(
+					sig->it_prof_expires, ptime);
+			}
+			__group_send_sig_info(SIGPROF, SEND_SIG_PRIV, tsk);
+		}
+		if (!cputime_eq(sig->it_prof_expires, cputime_zero) &&
+		    (cputime_eq(prof_expires, cputime_zero) ||
+		     cputime_lt(sig->it_prof_expires, prof_expires))) {
+			prof_expires = sig->it_prof_expires;
+		}
+	}
+	if (!cputime_eq(sig->it_virt_expires, cputime_zero)) {
+		if (cputime_ge(utime, sig->it_virt_expires)) {
+			/* ITIMER_VIRTUAL fires and reloads.  */
+			sig->it_virt_expires = sig->it_virt_incr;
+			if (!cputime_eq(sig->it_virt_expires, cputime_zero)) {
+				sig->it_virt_expires = cputime_add(
+					sig->it_virt_expires, utime);
+			}
+			__group_send_sig_info(SIGVTALRM, SEND_SIG_PRIV, tsk);
+		}
+		if (!cputime_eq(sig->it_virt_expires, cputime_zero) &&
+		    (cputime_eq(virt_expires, cputime_zero) ||
+		     cputime_lt(sig->it_virt_expires, virt_expires))) {
+			virt_expires = sig->it_virt_expires;
+		}
+	}
+	if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
+		unsigned long psecs = cputime_to_secs(ptime);
+		cputime_t x;
+		if (psecs >= sig->rlim[RLIMIT_CPU].rlim_max) {
+			/*
+			 * At the hard limit, we just die.
+			 * No need to calculate anything else now.
+			 */
+			__group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk);
+			return;
+		}
+		if (psecs >= sig->rlim[RLIMIT_CPU].rlim_cur) {
+			/*
+			 * At the soft limit, send a SIGXCPU every second.
+			 */
+			__group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
+			if (sig->rlim[RLIMIT_CPU].rlim_cur
+			    < sig->rlim[RLIMIT_CPU].rlim_max) {
+				sig->rlim[RLIMIT_CPU].rlim_cur++;
+			}
+		}
+		x = secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
+		if (cputime_eq(prof_expires, cputime_zero) ||
+		    cputime_lt(x, prof_expires)) {
+			prof_expires = x;
+		}
+	}
+
+	if (!cputime_eq(prof_expires, cputime_zero) ||
+	    !cputime_eq(virt_expires, cputime_zero) ||
+	    sched_expires != 0) {
+		/*
+		 * Rebalance the threads' expiry times for the remaining
+		 * process CPU timers.
+		 */
+
+		cputime_t prof_left, virt_left, ticks;
+		unsigned long long sched_left, sched;
+		const unsigned int nthreads = atomic_read(&sig->live);
+
+		prof_left = cputime_sub(prof_expires, utime);
+		prof_left = cputime_sub(prof_left, stime);
+		prof_left = cputime_div(prof_left, nthreads);
+		virt_left = cputime_sub(virt_expires, utime);
+		virt_left = cputime_div(virt_left, nthreads);
+		if (sched_expires) {
+			sched_left = sched_expires - sched_time;
+			do_div(sched_left, nthreads);
+		} else {
+			sched_left = 0;
+		}
+		t = tsk;
+		do {
+			ticks = cputime_add(cputime_add(t->utime, t->stime),
+					    prof_left);
+			if (!cputime_eq(prof_expires, cputime_zero) &&
+			    (cputime_eq(t->it_prof_expires, cputime_zero) ||
+			     cputime_gt(t->it_prof_expires, ticks))) {
+				t->it_prof_expires = ticks;
+			}
+
+			ticks = cputime_add(t->utime, virt_left);
+			if (!cputime_eq(virt_expires, cputime_zero) &&
+			    (cputime_eq(t->it_virt_expires, cputime_zero) ||
+			     cputime_gt(t->it_virt_expires, ticks))) {
+				t->it_virt_expires = ticks;
+			}
+
+			sched = t->sched_time + sched_left;
+			if (sched_expires && (t->it_sched_expires == 0 ||
+					      t->it_sched_expires > sched)) {
+				t->it_sched_expires = sched;
+			}
+
+			do {
+				t = next_thread(t);
+			} while (unlikely(t->exit_state));
+		} while (t != tsk);
+	}
+}
+
+/*
+ * This is called from the signal code (via do_schedule_next_timer)
+ * when the last timer signal was delivered and we have to reload the timer.
+ */
+void posix_cpu_timer_schedule(struct k_itimer *timer)
+{
+	struct task_struct *p = timer->it.cpu.task;
+	union cpu_time_count now;
+
+	if (unlikely(p == NULL))
+		/*
+		 * The task was cleaned up already, no future firings.
+		 */
+		return;
+
+	/*
+	 * Fetch the current sample and update the timer's expiry time.
+	 */
+	if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+		cpu_clock_sample(timer->it_clock, p, &now);
+		bump_cpu_timer(timer, now);
+		if (unlikely(p->exit_state)) {
+			clear_dead_task(timer, now);
+			return;
+		}
+		read_lock(&tasklist_lock); /* arm_timer needs it.  */
+	} else {
+		read_lock(&tasklist_lock);
+		if (unlikely(p->signal == NULL)) {
+			/*
+			 * The process has been reaped.
+			 * We can't even collect a sample any more.
+			 */
+			put_task_struct(p);
+			timer->it.cpu.task = p = NULL;
+			timer->it.cpu.expires.sched = 0;
+			read_unlock(&tasklist_lock);
+			return;
+		} else if (unlikely(p->exit_state) && thread_group_empty(p)) {
+			/*
+			 * We've noticed that the thread is dead, but
+			 * not yet reaped.  Take this opportunity to
+			 * drop our task ref.
+			 */
+			clear_dead_task(timer, now);
+			read_unlock(&tasklist_lock);
+			return;
+		}
+		cpu_clock_sample_group(timer->it_clock, p, &now);
+		bump_cpu_timer(timer, now);
+		/* Leave the tasklist_lock locked for the call below.  */
+	}
+
+	/*
+	 * Now re-arm for the new expiry time.
+	 */
+	arm_timer(timer, now);
+
+	read_unlock(&tasklist_lock);
+}
+
+/*
+ * This is called from the timer interrupt handler.  The irq handler has
+ * already updated our counts.  We need to check if any timers fire now.
+ * Interrupts are disabled.
+ */
+void run_posix_cpu_timers(struct task_struct *tsk)
+{
+	LIST_HEAD(firing);
+	struct k_itimer *timer, *next;
+
+	BUG_ON(!irqs_disabled());
+
+#define UNEXPIRED(clock) \
+		(cputime_eq(tsk->it_##clock##_expires, cputime_zero) || \
+		 cputime_lt(clock##_ticks(tsk), tsk->it_##clock##_expires))
+
+	if (UNEXPIRED(prof) && UNEXPIRED(virt) &&
+	    (tsk->it_sched_expires == 0 ||
+	     tsk->sched_time < tsk->it_sched_expires))
+		return;
+
+#undef	UNEXPIRED
+
+	BUG_ON(tsk->exit_state);
+
+	/*
+	 * Double-check with locks held.
+	 */
+	read_lock(&tasklist_lock);
+	spin_lock(&tsk->sighand->siglock);
+
+	/*
+	 * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N]
+	 * all the timers that are firing, and put them on the firing list.
+	 */
+	check_thread_timers(tsk, &firing);
+	check_process_timers(tsk, &firing);
+
+	/*
+	 * We must release these locks before taking any timer's lock.
+	 * There is a potential race with timer deletion here, as the
+	 * siglock now protects our private firing list.  We have set
+	 * the firing flag in each timer, so that a deletion attempt
+	 * that gets the timer lock before we do will give it up and
+	 * spin until we've taken care of that timer below.
+	 */
+	spin_unlock(&tsk->sighand->siglock);
+	read_unlock(&tasklist_lock);
+
+	/*
+	 * Now that all the timers on our list have the firing flag,
+	 * noone will touch their list entries but us.  We'll take
+	 * each timer's lock before clearing its firing flag, so no
+	 * timer call will interfere.
+	 */
+	list_for_each_entry_safe(timer, next, &firing, it.cpu.entry) {
+		int firing;
+		spin_lock(&timer->it_lock);
+		list_del_init(&timer->it.cpu.entry);
+		firing = timer->it.cpu.firing;
+		timer->it.cpu.firing = 0;
+		/*
+		 * The firing flag is -1 if we collided with a reset
+		 * of the timer, which already reported this
+		 * almost-firing as an overrun.  So don't generate an event.
+		 */
+		if (likely(firing >= 0)) {
+			cpu_timer_fire(timer);
+		}
+		spin_unlock(&timer->it_lock);
+	}
+}
+
+/*
+ * Set one of the process-wide special case CPU timers.
+ * The tasklist_lock and tsk->sighand->siglock must be held by the caller.
+ * The oldval argument is null for the RLIMIT_CPU timer, where *newval is
+ * absolute; non-null for ITIMER_*, where *newval is relative and we update
+ * it to be absolute, *oldval is absolute and we update it to be relative.
+ */
+void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
+			   cputime_t *newval, cputime_t *oldval)
+{
+	union cpu_time_count now;
+	struct list_head *head;
+
+	BUG_ON(clock_idx == CPUCLOCK_SCHED);
+	cpu_clock_sample_group_locked(clock_idx, tsk, &now);
+
+	if (oldval) {
+		if (!cputime_eq(*oldval, cputime_zero)) {
+			if (cputime_le(*oldval, now.cpu)) {
+				/* Just about to fire. */
+				*oldval = jiffies_to_cputime(1);
+			} else {
+				*oldval = cputime_sub(*oldval, now.cpu);
+			}
+		}
+
+		if (cputime_eq(*newval, cputime_zero))
+			return;
+		*newval = cputime_add(*newval, now.cpu);
+
+		/*
+		 * If the RLIMIT_CPU timer will expire before the
+		 * ITIMER_PROF timer, we have nothing else to do.
+		 */
+		if (tsk->signal->rlim[RLIMIT_CPU].rlim_cur
+		    < cputime_to_secs(*newval))
+			return;
+	}
+
+	/*
+	 * Check whether there are any process timers already set to fire
+	 * before this one.  If so, we don't have anything more to do.
+	 */
+	head = &tsk->signal->cpu_timers[clock_idx];
+	if (list_empty(head) ||
+	    cputime_ge(list_entry(head->next,
+				  struct cpu_timer_list, entry)->expires.cpu,
+		       *newval)) {
+		/*
+		 * Rejigger each thread's expiry time so that one will
+		 * notice before we hit the process-cumulative expiry time.
+		 */
+		union cpu_time_count expires = { .sched = 0 };
+		expires.cpu = *newval;
+		process_timer_rebalance(tsk, clock_idx, expires, now);
+	}
+}
+
+static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
+
+int posix_cpu_nsleep(clockid_t which_clock, int flags,
+		     struct timespec *rqtp)
+{
+	struct restart_block *restart_block =
+	    &current_thread_info()->restart_block;
+	struct k_itimer timer;
+	int error;
+
+	/*
+	 * Diagnose required errors first.
+	 */
+	if (CPUCLOCK_PERTHREAD(which_clock) &&
+	    (CPUCLOCK_PID(which_clock) == 0 ||
+	     CPUCLOCK_PID(which_clock) == current->pid))
+		return -EINVAL;
+
+	/*
+	 * Set up a temporary timer and then wait for it to go off.
+	 */
+	memset(&timer, 0, sizeof timer);
+	spin_lock_init(&timer.it_lock);
+	timer.it_clock = which_clock;
+	timer.it_overrun = -1;
+	error = posix_cpu_timer_create(&timer);
+	timer.it_process = current;
+	if (!error) {
+		struct timespec __user *rmtp;
+		static struct itimerspec zero_it;
+		struct itimerspec it = { .it_value = *rqtp,
+					 .it_interval = {} };
+
+		spin_lock_irq(&timer.it_lock);
+		error = posix_cpu_timer_set(&timer, flags, &it, NULL);
+		if (error) {
+			spin_unlock_irq(&timer.it_lock);
+			return error;
+		}
+
+		while (!signal_pending(current)) {
+			if (timer.it.cpu.expires.sched == 0) {
+				/*
+				 * Our timer fired and was reset.
+				 */
+				spin_unlock_irq(&timer.it_lock);
+				return 0;
+			}
+
+			/*
+			 * Block until cpu_timer_fire (or a signal) wakes us.
+			 */
+			__set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&timer.it_lock);
+			schedule();
+			spin_lock_irq(&timer.it_lock);
+		}
+
+		/*
+		 * We were interrupted by a signal.
+		 */
+		sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
+		posix_cpu_timer_set(&timer, 0, &zero_it, &it);
+		spin_unlock_irq(&timer.it_lock);
+
+		if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
+			/*
+			 * It actually did fire already.
+			 */
+			return 0;
+		}
+
+		/*
+		 * Report back to the user the time still remaining.
+		 */
+		rmtp = (struct timespec __user *) restart_block->arg1;
+		if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
+		    copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+			return -EFAULT;
+
+		restart_block->fn = posix_cpu_clock_nanosleep_restart;
+		/* Caller already set restart_block->arg1 */
+		restart_block->arg0 = which_clock;
+		restart_block->arg2 = rqtp->tv_sec;
+		restart_block->arg3 = rqtp->tv_nsec;
+
+		error = -ERESTART_RESTARTBLOCK;
+	}
+
+	return error;
+}
+
+static long
+posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
+{
+	clockid_t which_clock = restart_block->arg0;
+	struct timespec t = { .tv_sec = restart_block->arg2,
+			      .tv_nsec = restart_block->arg3 };
+	restart_block->fn = do_no_restart_syscall;
+	return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t);
+}
+
+
+#define PROCESS_CLOCK	MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
+#define THREAD_CLOCK	MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED)
+
+static int process_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+{
+	return posix_cpu_clock_getres(PROCESS_CLOCK, tp);
+}
+static int process_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+{
+	return posix_cpu_clock_get(PROCESS_CLOCK, tp);
+}
+static int process_cpu_timer_create(struct k_itimer *timer)
+{
+	timer->it_clock = PROCESS_CLOCK;
+	return posix_cpu_timer_create(timer);
+}
+static int process_cpu_nsleep(clockid_t which_clock, int flags,
+			      struct timespec *rqtp)
+{
+	return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
+}
+static int thread_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+{
+	return posix_cpu_clock_getres(THREAD_CLOCK, tp);
+}
+static int thread_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+{
+	return posix_cpu_clock_get(THREAD_CLOCK, tp);
+}
+static int thread_cpu_timer_create(struct k_itimer *timer)
+{
+	timer->it_clock = THREAD_CLOCK;
+	return posix_cpu_timer_create(timer);
+}
+static int thread_cpu_nsleep(clockid_t which_clock, int flags,
+			      struct timespec *rqtp)
+{
+	return -EINVAL;
+}
+
+static __init int init_posix_cpu_timers(void)
+{
+	struct k_clock process = {
+		.clock_getres = process_cpu_clock_getres,
+		.clock_get = process_cpu_clock_get,
+		.clock_set = do_posix_clock_nosettime,
+		.timer_create = process_cpu_timer_create,
+		.nsleep = process_cpu_nsleep,
+	};
+	struct k_clock thread = {
+		.clock_getres = thread_cpu_clock_getres,
+		.clock_get = thread_cpu_clock_get,
+		.clock_set = do_posix_clock_nosettime,
+		.timer_create = thread_cpu_timer_create,
+		.nsleep = thread_cpu_nsleep,
+	};
+
+	register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
+	register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
+
+	return 0;
+}
+__initcall(init_posix_cpu_timers);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -46,6 +46,7 @@
 #include <linux/syscalls.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/module.h>
 
 #ifndef div_long_long_rem
 #include <asm/div64.h>
@@ -92,14 +93,13 @@ static DEFINE_SPINLOCK(idr_lock);
  * inactive.  It could be in the "fire" routine getting a new expire time.
  */
 #define TIMER_INACTIVE 1
-#define TIMER_RETRY 1
 
 #ifdef CONFIG_SMP
 # define timer_active(tmr) \
-		((tmr)->it_timer.entry.prev != (void *)TIMER_INACTIVE)
+		((tmr)->it.real.timer.entry.prev != (void *)TIMER_INACTIVE)
 # define set_timer_inactive(tmr) \
 		do { \
-			(tmr)->it_timer.entry.prev = (void *)TIMER_INACTIVE; \
+			(tmr)->it.real.timer.entry.prev = (void *)TIMER_INACTIVE; \
 		} while (0)
 #else
 # define timer_active(tmr) BARFY	// error to use outside of SMP
@@ -115,7 +115,6 @@ static DEFINE_SPINLOCK(idr_lock);
 #endif
 
 
-#define REQUEUE_PENDING 1
 /*
  * The timer ID is turned into a timer address by idr_find().
  * Verifying a valid ID consists of:
@@ -173,22 +172,12 @@ static struct k_clock posix_clocks[MAX_C
 static struct k_clock_abs abs_list = {.list = LIST_HEAD_INIT(abs_list.list),
 				      .lock = SPIN_LOCK_UNLOCKED};
 
-#define if_clock_do(clock_fun,alt_fun,parms) \
-		(!clock_fun) ? alt_fun parms : clock_fun parms
-
-#define p_timer_get(clock,a,b) \
-	       	if_clock_do((clock)->timer_get,do_timer_gettime, (a,b))
-
-#define p_nsleep(clock,a,b,c) \
-		if_clock_do((clock)->nsleep, do_nsleep, (a,b,c))
-
-#define p_timer_del(clock,a) \
-		if_clock_do((clock)->timer_del, do_timer_delete, (a))
-
-static int do_posix_gettime(struct k_clock *clock, struct timespec *tp);
+static void posix_timer_fn(unsigned long);
 static u64 do_posix_clock_monotonic_gettime_parts(
 	struct timespec *tp, struct timespec *mo);
 int do_posix_clock_monotonic_gettime(struct timespec *tp);
+static int do_posix_clock_monotonic_get(clockid_t, struct timespec *tp);
+
 static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags);
 
 static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
@@ -197,6 +186,79 @@ static inline void unlock_timer(struct k
 }
 
 /*
+ * Call the k_clock hook function if non-null, or the default function.
+ */
+#define CLOCK_DISPATCH(clock, call, arglist) \
+ 	((clock) < 0 ? posix_cpu_##call arglist : \
+ 	 (posix_clocks[clock].call != NULL \
+ 	  ? (*posix_clocks[clock].call) arglist : common_##call arglist))
+
+/*
+ * Default clock hook functions when the struct k_clock passed
+ * to register_posix_clock leaves a function pointer null.
+ *
+ * The function common_CALL is the default implementation for
+ * the function pointer CALL in struct k_clock.
+ */
+
+static inline int common_clock_getres(clockid_t which_clock,
+				      struct timespec *tp)
+{
+	tp->tv_sec = 0;
+	tp->tv_nsec = posix_clocks[which_clock].res;
+	return 0;
+}
+
+static inline int common_clock_get(clockid_t which_clock, struct timespec *tp)
+{
+	getnstimeofday(tp);
+	return 0;
+}
+
+static inline int common_clock_set(clockid_t which_clock, struct timespec *tp)
+{
+	return do_sys_settimeofday(tp, NULL);
+}
+
+static inline int common_timer_create(struct k_itimer *new_timer)
+{
+	INIT_LIST_HEAD(&new_timer->it.real.abs_timer_entry);
+	init_timer(&new_timer->it.real.timer);
+	new_timer->it.real.timer.data = (unsigned long) new_timer;
+	new_timer->it.real.timer.function = posix_timer_fn;
+	set_timer_inactive(new_timer);
+	return 0;
+}
+
+/*
+ * These ones are defined below.
+ */
+static int common_nsleep(clockid_t, int flags, struct timespec *t);
+static void common_timer_get(struct k_itimer *, struct itimerspec *);
+static int common_timer_set(struct k_itimer *, int,
+			    struct itimerspec *, struct itimerspec *);
+static int common_timer_del(struct k_itimer *timer);
+
+/*
+ * Return nonzero iff we know a priori this clockid_t value is bogus.
+ */
+static inline int invalid_clockid(clockid_t which_clock)
+{
+	if (which_clock < 0)	/* CPU clock, posix_cpu_* will check it */
+		return 0;
+	if ((unsigned) which_clock >= MAX_CLOCKS)
+		return 1;
+	if (posix_clocks[which_clock].clock_getres != NULL)
+		return 0;
+#ifndef CLOCK_DISPATCH_DIRECT
+	if (posix_clocks[which_clock].res != 0)
+		return 0;
+#endif
+	return 1;
+}
+
+
+/*
  * Initialize everything, well, just everything in Posix clocks/timers ;)
  */
 static __init int init_posix_timers(void)
@@ -206,7 +268,7 @@ static __init int init_posix_timers(void
 	};
 	struct k_clock clock_monotonic = {.res = CLOCK_REALTIME_RES,
 		.abs_struct = NULL,
-		.clock_get = do_posix_clock_monotonic_gettime,
+		.clock_get = do_posix_clock_monotonic_get,
 		.clock_set = do_posix_clock_nosettime
 	};
 
@@ -263,9 +325,9 @@ static long add_clockset_delta(struct k_
 
 	set_normalized_timespec(&delta,
 				new_wall_to->tv_sec -
-				timr->wall_to_prev.tv_sec,
+				timr->it.real.wall_to_prev.tv_sec,
 				new_wall_to->tv_nsec -
-				timr->wall_to_prev.tv_nsec);
+				timr->it.real.wall_to_prev.tv_nsec);
 	if (likely(!(delta.tv_sec | delta.tv_nsec)))
 		return 0;
 	if (delta.tv_sec < 0) {
@@ -276,16 +338,16 @@ static long add_clockset_delta(struct k_
 		sign++;
 	}
 	tstojiffie(&delta, posix_clocks[timr->it_clock].res, &exp);
-	timr->wall_to_prev = *new_wall_to;
-	timr->it_timer.expires += (sign ? -exp : exp);
+	timr->it.real.wall_to_prev = *new_wall_to;
+	timr->it.real.timer.expires += (sign ? -exp : exp);
 	return 1;
 }
 
 static void remove_from_abslist(struct k_itimer *timr)
 {
-	if (!list_empty(&timr->abs_timer_entry)) {
+	if (!list_empty(&timr->it.real.abs_timer_entry)) {
 		spin_lock(&abs_list.lock);
-		list_del_init(&timr->abs_timer_entry);
+		list_del_init(&timr->it.real.abs_timer_entry);
 		spin_unlock(&abs_list.lock);
 	}
 }
@@ -299,7 +361,7 @@ static void schedule_next_timer(struct k
 	/*
 	 * Set up the timer for the next interval (if there is one).
 	 * Note: this code uses the abs_timer_lock to protect
-	 * wall_to_prev and must hold it until exp is set, not exactly
+	 * it.real.wall_to_prev and must hold it until exp is set, not exactly
 	 * obvious...
 
 	 * This function is used for CLOCK_REALTIME* and
@@ -309,7 +371,7 @@ static void schedule_next_timer(struct k
 	 * "other" CLOCKs "next timer" code (which, I suppose should
 	 * also be added to the k_clock structure).
 	 */
-	if (!timr->it_incr) 
+	if (!timr->it.real.incr)
 		return;
 
 	do {
@@ -318,7 +380,7 @@ static void schedule_next_timer(struct k
 		posix_get_now(&now);
 	} while (read_seqretry(&xtime_lock, seq));
 
-	if (!list_empty(&timr->abs_timer_entry)) {
+	if (!list_empty(&timr->it.real.abs_timer_entry)) {
 		spin_lock(&abs_list.lock);
 		add_clockset_delta(timr, &new_wall_to);
 
@@ -331,7 +393,7 @@ static void schedule_next_timer(struct k
 	timr->it_overrun_last = timr->it_overrun;
 	timr->it_overrun = -1;
 	++timr->it_requeue_pending;
-	add_timer(&timr->it_timer);
+	add_timer(&timr->it.real.timer);
 }
 
 /*
@@ -355,7 +417,10 @@ void do_schedule_next_timer(struct sigin
 	if (!timr || timr->it_requeue_pending != info->si_sys_private)
 		goto exit;
 
-	schedule_next_timer(timr);
+	if (timr->it_clock < 0)	/* CPU clock */
+		posix_cpu_timer_schedule(timr);
+	else
+		schedule_next_timer(timr);
 	info->si_overrun = timr->it_overrun_last;
 exit:
 	if (timr)
@@ -396,6 +461,7 @@ int posix_timer_event(struct k_itimer *t
 			timr->it_process);
 	}
 }
+EXPORT_SYMBOL_GPL(posix_timer_event);
 
 /*
  * This function gets called when a POSIX.1b interval timer expires.  It
@@ -415,7 +481,7 @@ static void posix_timer_fn(unsigned long
 
 	spin_lock_irqsave(&timr->it_lock, flags);
  	set_timer_inactive(timr);
-	if (!list_empty(&timr->abs_timer_entry)) {
+	if (!list_empty(&timr->it.real.abs_timer_entry)) {
 		spin_lock(&abs_list.lock);
 		do {
 			seq = read_seqbegin(&xtime_lock);
@@ -423,9 +489,9 @@ static void posix_timer_fn(unsigned long
 		} while (read_seqretry(&xtime_lock, seq));
 		set_normalized_timespec(&delta,
 					new_wall_to.tv_sec -
-					timr->wall_to_prev.tv_sec,
+					timr->it.real.wall_to_prev.tv_sec,
 					new_wall_to.tv_nsec -
-					timr->wall_to_prev.tv_nsec);
+					timr->it.real.wall_to_prev.tv_nsec);
 		if (likely((delta.tv_sec | delta.tv_nsec ) == 0)) {
 			/* do nothing, timer is on time */
 		} else if (delta.tv_sec < 0) {
@@ -435,9 +501,9 @@ static void posix_timer_fn(unsigned long
 			tstojiffie(&delta,
 				   posix_clocks[timr->it_clock].res,
 				   &exp);
-			timr->wall_to_prev = new_wall_to;
-			timr->it_timer.expires += exp;
-			add_timer(&timr->it_timer);
+			timr->it.real.wall_to_prev = new_wall_to;
+			timr->it.real.timer.expires += exp;
+			add_timer(&timr->it.real.timer);
 			do_notify = 0;
 		}
 		spin_unlock(&abs_list.lock);
@@ -446,7 +512,7 @@ static void posix_timer_fn(unsigned long
 	if (do_notify)  {
 		int si_private=0;
 
-		if (timr->it_incr)
+		if (timr->it.real.incr)
 			si_private = ++timr->it_requeue_pending;
 		else {
 			remove_from_abslist(timr);
@@ -481,15 +547,17 @@ static inline struct task_struct * good_
 	return rtn;
 }
 
-void register_posix_clock(int clock_id, struct k_clock *new_clock)
+void register_posix_clock(clockid_t clock_id, struct k_clock *new_clock)
 {
 	if ((unsigned) clock_id >= MAX_CLOCKS) {
 		printk("POSIX clock register failed for clock_id %d\n",
 		       clock_id);
 		return;
 	}
+
 	posix_clocks[clock_id] = *new_clock;
 }
+EXPORT_SYMBOL_GPL(register_posix_clock);
 
 static struct k_itimer * alloc_posix_timer(void)
 {
@@ -498,7 +566,6 @@ static struct k_itimer * alloc_posix_tim
 	if (!tmr)
 		return tmr;
 	memset(tmr, 0, sizeof (struct k_itimer));
-	INIT_LIST_HEAD(&tmr->abs_timer_entry);
 	if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
 		kmem_cache_free(posix_timers_cache, tmr);
 		tmr = NULL;
@@ -538,8 +605,7 @@ sys_timer_create(clockid_t which_clock,
 	sigevent_t event;
 	int it_id_set = IT_ID_NOT_SET;
 
-	if ((unsigned) which_clock >= MAX_CLOCKS ||
-				!posix_clocks[which_clock].res)
+	if (invalid_clockid(which_clock))
 		return -EINVAL;
 
 	new_timer = alloc_posix_timer();
@@ -571,19 +637,10 @@ sys_timer_create(clockid_t which_clock,
 	it_id_set = IT_ID_SET;
 	new_timer->it_id = (timer_t) new_timer_id;
 	new_timer->it_clock = which_clock;
-	new_timer->it_incr = 0;
 	new_timer->it_overrun = -1;
-	if (posix_clocks[which_clock].timer_create) {
-		error =  posix_clocks[which_clock].timer_create(new_timer);
-		if (error)
-			goto out;
-	} else {
-		init_timer(&new_timer->it_timer);
-		new_timer->it_timer.expires = 0;
-		new_timer->it_timer.data = (unsigned long) new_timer;
-		new_timer->it_timer.function = posix_timer_fn;
-		set_timer_inactive(new_timer);
-	}
+	error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
+	if (error)
+		goto out;
 
 	/*
 	 * return the timer_id now.  The next step is hard to
@@ -734,36 +791,36 @@ static struct k_itimer * lock_timer(time
  * report.
  */
 static void
-do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting)
+common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
 	unsigned long expires;
 	struct now_struct now;
 
 	do
-		expires = timr->it_timer.expires;
-	while ((volatile long) (timr->it_timer.expires) != expires);
+		expires = timr->it.real.timer.expires;
+	while ((volatile long) (timr->it.real.timer.expires) != expires);
 
 	posix_get_now(&now);
 
 	if (expires &&
 	    ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) &&
-	    !timr->it_incr &&
-	    posix_time_before(&timr->it_timer, &now))
-		timr->it_timer.expires = expires = 0;
+	    !timr->it.real.incr &&
+	    posix_time_before(&timr->it.real.timer, &now))
+		timr->it.real.timer.expires = expires = 0;
 	if (expires) {
 		if (timr->it_requeue_pending & REQUEUE_PENDING ||
 		    (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
 			posix_bump_timer(timr, now);
-			expires = timr->it_timer.expires;
+			expires = timr->it.real.timer.expires;
 		}
 		else
-			if (!timer_pending(&timr->it_timer))
+			if (!timer_pending(&timr->it.real.timer))
 				expires = 0;
 		if (expires)
 			expires -= now.jiffies;
 	}
 	jiffies_to_timespec(expires, &cur_setting->it_value);
-	jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval);
+	jiffies_to_timespec(timr->it.real.incr, &cur_setting->it_interval);
 
 	if (cur_setting->it_value.tv_sec < 0) {
 		cur_setting->it_value.tv_nsec = 1;
@@ -783,7 +840,7 @@ sys_timer_gettime(timer_t timer_id, stru
 	if (!timr)
 		return -EINVAL;
 
-	p_timer_get(&posix_clocks[timr->it_clock], timr, &cur_setting);
+	CLOCK_DISPATCH(timr->it_clock, timer_get, (timr, &cur_setting));
 
 	unlock_timer(timr, flags);
 
@@ -854,7 +911,7 @@ static int adjust_abs_time(struct k_cloc
 			/*
 			 * Not one of the basic clocks
 			 */
-			do_posix_gettime(clock, &now);	
+			clock->clock_get(clock - posix_clocks, &now);
 			jiffies_64_f = get_jiffies_64();
 		}
 		/*
@@ -881,6 +938,10 @@ static int adjust_abs_time(struct k_cloc
 	 */
 	if (oc.tv_sec < 0)
 		oc.tv_sec = oc.tv_nsec = 0;
+
+	if (oc.tv_sec | oc.tv_nsec)
+		set_normalized_timespec(&oc, oc.tv_sec,
+					oc.tv_nsec + clock->res);
 	tstojiffie(&oc, clock->res, exp);
 
 	/*
@@ -907,23 +968,23 @@ static int adjust_abs_time(struct k_cloc
 /* Set a POSIX.1b interval timer. */
 /* timr->it_lock is taken. */
 static inline int
-do_timer_settime(struct k_itimer *timr, int flags,
+common_timer_set(struct k_itimer *timr, int flags,
 		 struct itimerspec *new_setting, struct itimerspec *old_setting)
 {
 	struct k_clock *clock = &posix_clocks[timr->it_clock];
 	u64 expire_64;
 
 	if (old_setting)
-		do_timer_gettime(timr, old_setting);
+		common_timer_get(timr, old_setting);
 
 	/* disable the timer */
-	timr->it_incr = 0;
+	timr->it.real.incr = 0;
 	/*
 	 * careful here.  If smp we could be in the "fire" routine which will
 	 * be spinning as we hold the lock.  But this is ONLY an SMP issue.
 	 */
 #ifdef CONFIG_SMP
-	if (timer_active(timr) && !del_timer(&timr->it_timer))
+	if (timer_active(timr) && !del_timer(&timr->it.real.timer))
 		/*
 		 * It can only be active if on an other cpu.  Since
 		 * we have cleared the interval stuff above, it should
@@ -936,7 +997,7 @@ do_timer_settime(struct k_itimer *timr, 
 
 	set_timer_inactive(timr);
 #else
-	del_timer(&timr->it_timer);
+	del_timer(&timr->it.real.timer);
 #endif
 	remove_from_abslist(timr);
 
@@ -948,29 +1009,29 @@ do_timer_settime(struct k_itimer *timr, 
 	 *switch off the timer when it_value is zero
 	 */
 	if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) {
-		timr->it_timer.expires = 0;
+		timr->it.real.timer.expires = 0;
 		return 0;
 	}
 
 	if (adjust_abs_time(clock,
 			    &new_setting->it_value, flags & TIMER_ABSTIME, 
-			    &expire_64, &(timr->wall_to_prev))) {
+			    &expire_64, &(timr->it.real.wall_to_prev))) {
 		return -EINVAL;
 	}
-	timr->it_timer.expires = (unsigned long)expire_64;	
+	timr->it.real.timer.expires = (unsigned long)expire_64;
 	tstojiffie(&new_setting->it_interval, clock->res, &expire_64);
-	timr->it_incr = (unsigned long)expire_64;
+	timr->it.real.incr = (unsigned long)expire_64;
 
 	/*
 	 * We do not even queue SIGEV_NONE timers!  But we do put them
 	 * in the abs list so we can do that right.
 	 */
 	if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE))
-		add_timer(&timr->it_timer);
+		add_timer(&timr->it.real.timer);
 
 	if (flags & TIMER_ABSTIME && clock->abs_struct) {
 		spin_lock(&clock->abs_struct->lock);
-		list_add_tail(&(timr->abs_timer_entry),
+		list_add_tail(&(timr->it.real.abs_timer_entry),
 			      &(clock->abs_struct->list));
 		spin_unlock(&clock->abs_struct->lock);
 	}
@@ -1003,12 +1064,9 @@ retry:
 	if (!timr)
 		return -EINVAL;
 
-	if (!posix_clocks[timr->it_clock].timer_set)
-		error = do_timer_settime(timr, flags, &new_spec, rtn);
-	else
-	        error = posix_clocks[timr->it_clock].timer_set(timr,
-							       flags,
-							       &new_spec, rtn);
+	error = CLOCK_DISPATCH(timr->it_clock, timer_set,
+			       (timr, flags, &new_spec, rtn));
+
 	unlock_timer(timr, flag);
 	if (error == TIMER_RETRY) {
 		rtn = NULL;	// We already got the old time...
@@ -1022,11 +1080,11 @@ retry:
 	return error;
 }
 
-static inline int do_timer_delete(struct k_itimer *timer)
+static inline int common_timer_del(struct k_itimer *timer)
 {
-	timer->it_incr = 0;
+	timer->it.real.incr = 0;
 #ifdef CONFIG_SMP
-	if (timer_active(timer) && !del_timer(&timer->it_timer))
+	if (timer_active(timer) && !del_timer(&timer->it.real.timer))
 		/*
 		 * It can only be active if on an other cpu.  Since
 		 * we have cleared the interval stuff above, it should
@@ -1037,13 +1095,18 @@ static inline int do_timer_delete(struct
 		 */
 		return TIMER_RETRY;
 #else
-	del_timer(&timer->it_timer);
+	del_timer(&timer->it.real.timer);
 #endif
 	remove_from_abslist(timer);
 
 	return 0;
 }
 
+static inline int timer_delete_hook(struct k_itimer *timer)
+{
+	return CLOCK_DISPATCH(timer->it_clock, timer_del, (timer));
+}
+
 /* Delete a POSIX.1b interval timer. */
 asmlinkage long
 sys_timer_delete(timer_t timer_id)
@@ -1060,14 +1123,14 @@ retry_delete:
 		return -EINVAL;
 
 #ifdef CONFIG_SMP
-	error = p_timer_del(&posix_clocks[timer->it_clock], timer);
+	error = timer_delete_hook(timer);
 
 	if (error == TIMER_RETRY) {
 		unlock_timer(timer, flags);
 		goto retry_delete;
 	}
 #else
-	p_timer_del(&posix_clocks[timer->it_clock], timer);
+	timer_delete_hook(timer);
 #endif
 	spin_lock(&current->sighand->siglock);
 	list_del(&timer->list);
@@ -1099,14 +1162,14 @@ retry_delete:
 	spin_lock_irqsave(&timer->it_lock, flags);
 
 #ifdef CONFIG_SMP
-	error = p_timer_del(&posix_clocks[timer->it_clock], timer);
+	error = timer_delete_hook(timer);
 
 	if (error == TIMER_RETRY) {
 		unlock_timer(timer, flags);
 		goto retry_delete;
 	}
 #else
-	p_timer_del(&posix_clocks[timer->it_clock], timer);
+	timer_delete_hook(timer);
 #endif
 	list_del(&timer->list);
 	/*
@@ -1134,6 +1197,7 @@ void exit_itimers(struct signal_struct *
 		tmr = list_entry(sig->posix_timers.next, struct k_itimer, list);
 		itimer_delete(tmr);
 	}
+	del_timer_sync(&sig->real_timer);
 }
 
 /*
@@ -1143,14 +1207,6 @@ void exit_itimers(struct signal_struct *
  * spin_lock_irq() held and from clock calls with no locking.	They must
  * use the save flags versions of locks.
  */
-static int do_posix_gettime(struct k_clock *clock, struct timespec *tp)
-{
-	if (clock->clock_get)
-		return clock->clock_get(tp);
-
-	getnstimeofday(tp);
-	return 0;
-}
 
 /*
  * We do ticks here to avoid the irq lock ( they take sooo long).
@@ -1177,7 +1233,7 @@ static u64 do_posix_clock_monotonic_gett
 	return jiff;
 }
 
-int do_posix_clock_monotonic_gettime(struct timespec *tp)
+static int do_posix_clock_monotonic_get(clockid_t clock, struct timespec *tp)
 {
 	struct timespec wall_to_mono;
 
@@ -1193,17 +1249,24 @@ int do_posix_clock_monotonic_gettime(str
 	return 0;
 }
 
-int do_posix_clock_nosettime(struct timespec *tp)
+int do_posix_clock_monotonic_gettime(struct timespec *tp)
+{
+	return do_posix_clock_monotonic_get(CLOCK_MONOTONIC, tp);
+}
+
+int do_posix_clock_nosettime(clockid_t clockid, struct timespec *tp)
 {
 	return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(do_posix_clock_nosettime);
 
 int do_posix_clock_notimer_create(struct k_itimer *timer)
 {
 	return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create);
 
-int do_posix_clock_nonanosleep(int which_clock, int flags, struct timespec *t)
+int do_posix_clock_nonanosleep(clockid_t clock, int flags, struct timespec *t)
 {
 #ifndef ENOTSUP
 	return -EOPNOTSUPP;	/* aka ENOTSUP in userland for POSIX */
@@ -1211,30 +1274,19 @@ int do_posix_clock_nonanosleep(int which
 	return -ENOTSUP;
 #endif
 }
+EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep);
 
 asmlinkage long
 sys_clock_settime(clockid_t which_clock, const struct timespec __user *tp)
 {
 	struct timespec new_tp;
 
-	if ((unsigned) which_clock >= MAX_CLOCKS ||
-					!posix_clocks[which_clock].res)
+	if (invalid_clockid(which_clock))
 		return -EINVAL;
 	if (copy_from_user(&new_tp, tp, sizeof (*tp)))
 		return -EFAULT;
-	if (posix_clocks[which_clock].clock_set)
-		return posix_clocks[which_clock].clock_set(&new_tp);
-
-	return do_sys_settimeofday(&new_tp, NULL);
-}
 
-static int do_clock_gettime(clockid_t which_clock, struct timespec *tp)
-{
-	if ((unsigned) which_clock >= MAX_CLOCKS ||
-					!posix_clocks[which_clock].res)
-		return -EINVAL;
-
-	return do_posix_gettime(&posix_clocks[which_clock], tp);
+	return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp));
 }
 
 asmlinkage long
@@ -1243,7 +1295,10 @@ sys_clock_gettime(clockid_t which_clock,
 	struct timespec kernel_tp;
 	int error;
 
-	error = do_clock_gettime(which_clock, &kernel_tp);
+	if (invalid_clockid(which_clock))
+		return -EINVAL;
+	error = CLOCK_DISPATCH(which_clock, clock_get,
+			       (which_clock, &kernel_tp));
 	if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
 		error = -EFAULT;
 
@@ -1255,18 +1310,19 @@ asmlinkage long
 sys_clock_getres(clockid_t which_clock, struct timespec __user *tp)
 {
 	struct timespec rtn_tp;
+	int error;
 
-	if ((unsigned) which_clock >= MAX_CLOCKS ||
-					!posix_clocks[which_clock].res)
+	if (invalid_clockid(which_clock))
 		return -EINVAL;
 
-	rtn_tp.tv_sec = 0;
-	rtn_tp.tv_nsec = posix_clocks[which_clock].res;
-	if (tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp)))
-		return -EFAULT;
+	error = CLOCK_DISPATCH(which_clock, clock_getres,
+			       (which_clock, &rtn_tp));
 
-	return 0;
+	if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) {
+		error = -EFAULT;
+	}
 
+	return error;
 }
 
 static void nanosleep_wake_up(unsigned long __data)
@@ -1364,13 +1420,13 @@ void clock_was_set(void)
 			break;
 		}
 		timr = list_entry(cws_list.next, struct k_itimer,
-				   abs_timer_entry);
+				  it.real.abs_timer_entry);
 
-		list_del_init(&timr->abs_timer_entry);
+		list_del_init(&timr->it.real.abs_timer_entry);
 		if (add_clockset_delta(timr, &new_wall_to) &&
-		    del_timer(&timr->it_timer))  /* timer run yet? */
-			add_timer(&timr->it_timer);
-		list_add(&timr->abs_timer_entry, &abs_list.list);
+		    del_timer(&timr->it.real.timer))  /* timer run yet? */
+			add_timer(&timr->it.real.timer);
+		list_add(&timr->it.real.abs_timer_entry, &abs_list.list);
 		spin_unlock_irq(&abs_list.lock);
 	} while (1);
 
@@ -1379,9 +1435,6 @@ void clock_was_set(void)
 
 long clock_nanosleep_restart(struct restart_block *restart_block);
 
-extern long do_clock_nanosleep(clockid_t which_clock, int flags,
-			       struct timespec *t);
-
 asmlinkage long
 sys_clock_nanosleep(clockid_t which_clock, int flags,
 		    const struct timespec __user *rqtp,
@@ -1392,8 +1445,7 @@ sys_clock_nanosleep(clockid_t which_cloc
 	    &(current_thread_info()->restart_block);
 	int ret;
 
-	if ((unsigned) which_clock >= MAX_CLOCKS ||
-					!posix_clocks[which_clock].res)
+	if (invalid_clockid(which_clock))
 		return -EINVAL;
 
 	if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
@@ -1402,23 +1454,22 @@ sys_clock_nanosleep(clockid_t which_cloc
 	if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0)
 		return -EINVAL;
 
-	if (posix_clocks[which_clock].nsleep)
-		ret = posix_clocks[which_clock].nsleep(which_clock, flags, &t);
-	else
-		ret = do_clock_nanosleep(which_clock, flags, &t);
 	/*
-	 * Do this here as do_clock_nanosleep does not have the real address
+	 * Do this here as nsleep function does not have the real address.
 	 */
 	restart_block->arg1 = (unsigned long)rmtp;
 
+	ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t));
+
 	if ((ret == -ERESTART_RESTARTBLOCK) && rmtp &&
 					copy_to_user(rmtp, &t, sizeof (t)))
 		return -EFAULT;
 	return ret;
 }
 
-long
-do_clock_nanosleep(clockid_t which_clock, int flags, struct timespec *tsave)
+
+static int common_nsleep(clockid_t which_clock,
+			 int flags, struct timespec *tsave)
 {
 	struct timespec t, dum;
 	struct timer_list new_timer;
@@ -1461,7 +1512,6 @@ do_clock_nanosleep(clockid_t which_clock
 		if (abs || !rq_time) {
 			adjust_abs_time(&posix_clocks[which_clock], &t, abs,
 					&rq_time, &dum);
-			rq_time += (t.tv_sec || t.tv_nsec);
 		}
 
 		left = rq_time - get_jiffies_64();
@@ -1525,7 +1575,7 @@ long
 clock_nanosleep_restart(struct restart_block *restart_block)
 {
 	struct timespec t;
-	int ret = do_clock_nanosleep(restart_block->arg0, 0, &t);
+	int ret = common_nsleep(restart_block->arg0, 0, &t);
 
 	if ((ret == -ERESTART_RESTARTBLOCK) && restart_block->arg1 &&
 	    copy_to_user((struct timespec __user *)(restart_block->arg1), &t,
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -16,7 +16,6 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
-#include <linux/device.h>
 #include "power.h"
 
 
@@ -25,13 +24,16 @@ extern struct pm_ops * pm_ops;
 
 extern int swsusp_suspend(void);
 extern int swsusp_write(void);
+extern int swsusp_check(void);
 extern int swsusp_read(void);
+extern void swsusp_close(void);
 extern int swsusp_resume(void);
 extern int swsusp_free(void);
 
 
 static int noresume = 0;
 char resume_file[256] = CONFIG_PM_STD_PARTITION;
+dev_t swsusp_resume_device;
 
 /**
  *	power_down - Shut machine down for hibernate.
@@ -51,7 +53,7 @@ static void power_down(suspend_disk_meth
 	local_irq_save(flags);
 	switch(mode) {
 	case PM_DISK_PLATFORM:
- 		device_power_down(PMSG_SUSPEND);
+ 		device_shutdown();
 		error = pm_ops->enter(PM_SUSPEND_DISK);
 		break;
 	case PM_DISK_SHUTDOWN:
@@ -121,45 +123,54 @@ static void finish(void)
 }
 
 
-static int prepare(void)
+static int prepare_processes(void)
 {
 	int error;
 
 	pm_prepare_console();
 
 	sys_sync();
+
 	if (freeze_processes()) {
 		error = -EBUSY;
-		goto Thaw;
+		return error;
 	}
 
 	if (pm_disk_mode == PM_DISK_PLATFORM) {
 		if (pm_ops && pm_ops->prepare) {
 			if ((error = pm_ops->prepare(PM_SUSPEND_DISK)))
-				goto Thaw;
+				return error;
 		}
 	}
 
 	/* Free memory before shutting down devices. */
 	free_some_memory();
 
+	return 0;
+}
+
+static void unprepare_processes(void)
+{
+	enable_nonboot_cpus();
+	thaw_processes();
+	pm_restore_console();
+}
+
+static int prepare_devices(void)
+{
+	int error;
+
 	disable_nonboot_cpus();
 	if ((error = device_suspend(PMSG_FREEZE))) {
 		printk("Some devices failed to suspend\n");
-		goto Finish;
+		platform_finish();
+		enable_nonboot_cpus();
+		return error;
 	}
 
 	return 0;
- Finish:
-	platform_finish();
- Thaw:
-	enable_nonboot_cpus();
-	thaw_processes();
-	pm_restore_console();
-	return error;
 }
 
-
 /**
  *	pm_suspend_disk - The granpappy of power management.
  *
@@ -173,8 +184,15 @@ int pm_suspend_disk(void)
 {
 	int error;
 
-	if ((error = prepare()))
+	error = prepare_processes();
+	if (!error) {
+		error = prepare_devices();
+	}
+
+	if (error) {
+		unprepare_processes();
 		return error;
+	}
 
 	pr_debug("PM: Attempting to suspend to disk.\n");
 	if (pm_disk_mode == PM_DISK_FIRMWARE)
@@ -223,17 +241,28 @@ static int software_resume(void)
 		return 0;
 	}
 
+	pr_debug("PM: Checking swsusp image.\n");
+
+	if ((error = swsusp_check()))
+		goto Done;
+
+	pr_debug("PM: Preparing processes for restore.\n");
+
+	if ((error = prepare_processes())) {
+		swsusp_close();
+		goto Cleanup;
+	}
+
 	pr_debug("PM: Reading swsusp image.\n");
 
 	if ((error = swsusp_read()))
-		goto Done;
+		goto Cleanup;
 
-	pr_debug("PM: Preparing system for restore.\n");
+	pr_debug("PM: Preparing devices for restore.\n");
 
-	if ((error = prepare()))
+	if ((error = prepare_devices()))
 		goto Free;
 
-	barrier();
 	mb();
 
 	pr_debug("PM: Restoring saved image.\n");
@@ -242,6 +271,8 @@ static int software_resume(void)
 	finish();
  Free:
 	swsusp_free();
+ Cleanup:
+	unprepare_processes();
  Done:
 	pr_debug("PM: Resume from disk failed.\n");
 	return 0;
@@ -329,8 +360,41 @@ static ssize_t disk_store(struct subsyst
 
 power_attr(disk);
 
+static ssize_t resume_show(struct subsystem * subsys, char *buf)
+{
+	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
+		       MINOR(swsusp_resume_device));
+}
+
+static ssize_t resume_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+	int len;
+	char *p;
+	unsigned int maj, min;
+	int error = -EINVAL;
+	dev_t res;
+
+	p = memchr(buf, '\n', n);
+	len = p ? p - buf : n;
+
+	if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
+		res = MKDEV(maj,min);
+		if (maj == MAJOR(res) && min == MINOR(res)) {
+			swsusp_resume_device = res;
+			printk("Attempting manual resume\n");
+			noresume = 0;
+			software_resume();
+		}
+	}
+
+	return error >= 0 ? n : error;
+}
+
+power_attr(resume);
+
 static struct attribute * g[] = {
 	&disk_attr.attr,
+	&resume_attr.attr,
 	NULL,
 };
 
diff --git a/kernel/power/main.c b/kernel/power/main.c
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -65,8 +65,10 @@ static int suspend_prepare(suspend_state
 			goto Thaw;
 	}
 
-	if ((error = device_suspend(PMSG_SUSPEND)))
+	if ((error = device_suspend(PMSG_SUSPEND))) {
+		printk(KERN_ERR "Some devices failed to suspend\n");
 		goto Finish;
+	}
 	return 0;
  Finish:
 	if (pm_ops->finish)
@@ -85,8 +87,10 @@ static int suspend_enter(suspend_state_t
 
 	local_irq_save(flags);
 
-	if ((error = device_power_down(PMSG_SUSPEND)))
+	if ((error = device_power_down(PMSG_SUSPEND))) {
+		printk(KERN_ERR "Some devices failed to power down\n");
 		goto Done;
+	}
 	error = pm_ops->enter(state);
 	device_power_up();
  Done:
@@ -115,7 +119,7 @@ static void suspend_finish(suspend_state
 
 
 
-char * pm_states[] = {
+static char * pm_states[] = {
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
 	[PM_SUSPEND_DISK]	= "disk",
@@ -152,14 +156,14 @@ static int enter_state(suspend_state_t s
 		goto Unlock;
 	}
 
-	pr_debug("PM: Preparing system for suspend\n");
+	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
 	if ((error = suspend_prepare(state)))
 		goto Unlock;
 
-	pr_debug("PM: Entering state.\n");
+	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
 	error = suspend_enter(state);
 
-	pr_debug("PM: Finishing up.\n");
+	pr_debug("PM: Finishing wakeup.\n");
 	suspend_finish(state);
  Unlock:
 	up(&pm_sem);
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
--- a/kernel/power/pm.c
+++ b/kernel/power/pm.c
@@ -151,7 +151,7 @@ void pm_unregister_all(pm_callback callb
  *	execution and unload yourself.
  */
  
-int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
 	int status = 0;
 	unsigned long prev_state, next_state;
diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c
--- a/kernel/power/poweroff.c
+++ b/kernel/power/poweroff.c
@@ -32,7 +32,8 @@ static void handle_poweroff(int key, str
 static struct sysrq_key_op	sysrq_poweroff_op = {
 	.handler        = handle_poweroff,
 	.help_msg       = "powerOff",
-	.action_msg     = "Power Off"
+	.action_msg     = "Power Off",
+ 	.enable_mask	= SYSRQ_ENABLE_BOOT,
 };
 
 static int pm_sysrq_init(void)
diff --git a/kernel/power/smp.c b/kernel/power/smp.c
--- a/kernel/power/smp.c
+++ b/kernel/power/smp.c
@@ -42,17 +42,17 @@ static void smp_pause(void * data)
 	__restore_processor_state(&ctxt);
 }
 
-cpumask_t oldmask;
+static cpumask_t oldmask;
 
 void disable_nonboot_cpus(void)
 {
-	printk("Freezing CPUs (at %d)", smp_processor_id());
 	oldmask = current->cpus_allowed;
 	set_cpus_allowed(current, cpumask_of_cpu(0));
+	printk("Freezing CPUs (at %d)", _smp_processor_id());
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(HZ);
 	printk("...");
-	BUG_ON(smp_processor_id() != 0);
+	BUG_ON(_smp_processor_id() != 0);
 
 	/* FIXME: for this to work, all the CPUs must be running
 	 * "idle" thread (or we deadlock). Is that guaranteed? */
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -76,11 +76,10 @@
 extern const void __nosave_begin, __nosave_end;
 
 /* Variables to be preserved over suspend */
-static int pagedir_order_check;
 static int nr_copy_pages_check;
 
 extern char resume_file[];
-static dev_t resume_device;
+
 /* Local variables that should not be affected by save */
 unsigned int nr_copy_pages __nosavedata = 0;
 
@@ -99,7 +98,6 @@ unsigned int nr_copy_pages __nosavedata 
  */
 suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
 static suspend_pagedir_t *pagedir_save;
-static int pagedir_order __nosavedata = 0;
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
@@ -170,7 +168,7 @@ static int is_resume_device(const struct
 	struct inode *inode = file->f_dentry->d_inode;
 
 	return S_ISBLK(inode->i_mode) &&
-		resume_device == MKDEV(imajor(inode), iminor(inode));
+		swsusp_resume_device == MKDEV(imajor(inode), iminor(inode));
 }
 
 static int swsusp_swap_check(void) /* This is called before saving image */
@@ -225,8 +223,6 @@ static void lock_swapdevices(void)
 	swap_list_unlock();
 }
 
-
-
 /**
  *	write_swap_page - Write one page to a fresh swap location.
  *	@addr:	Address we're writing.
@@ -239,7 +235,6 @@ static void lock_swapdevices(void)
  *	This is a partial improvement, since we will at least return other
  *	errors, though we need to eventually fix the damn code.
  */
-
 static int write_page(unsigned long addr, swp_entry_t * loc)
 {
 	swp_entry_t entry;
@@ -259,14 +254,12 @@ static int write_page(unsigned long addr
 	return error;
 }
 
-
 /**
  *	data_free - Free the swap entries used by the saved image.
  *
  *	Walk the list of used swap entries and free each one. 
  *	This is only used for cleanup when suspend fails.
  */
-
 static void data_free(void)
 {
 	swp_entry_t entry;
@@ -282,28 +275,27 @@ static void data_free(void)
 	}
 }
 
-
 /**
  *	data_write - Write saved image to swap.
  *
  *	Walk the list of pages in the image and sync each one to swap.
  */
-
 static int data_write(void)
 {
-	int error = 0;
-	int i;
+	int error = 0, i = 0;
 	unsigned int mod = nr_copy_pages / 100;
+	struct pbe *p;
 
 	if (!mod)
 		mod = 1;
 
 	printk( "Writing data to swap (%d pages)...     ", nr_copy_pages );
-	for (i = 0; i < nr_copy_pages && !error; i++) {
+	for_each_pbe(p, pagedir_nosave) {
 		if (!(i%mod))
 			printk( "\b\b\b\b%3d%%", i / mod );
-		error = write_page((pagedir_nosave+i)->address,
-					  &((pagedir_nosave+i)->swap_address));
+		if ((error = write_page(p->address, &(p->swap_address))))
+			return error;
+		i++;
 	}
 	printk("\b\b\b\bdone\n");
 	return error;
@@ -326,15 +318,14 @@ static void dump_info(void)
 
 static void init_header(void)
 {
-	memset(&swsusp_info,0,sizeof(swsusp_info));
+	memset(&swsusp_info, 0, sizeof(swsusp_info));
 	swsusp_info.version_code = LINUX_VERSION_CODE;
 	swsusp_info.num_physpages = num_physpages;
-	memcpy(&swsusp_info.uts,&system_utsname,sizeof(system_utsname));
+	memcpy(&swsusp_info.uts, &system_utsname, sizeof(system_utsname));
 
 	swsusp_info.suspend_pagedir = pagedir_nosave;
 	swsusp_info.cpus = num_online_cpus();
 	swsusp_info.image_pages = nr_copy_pages;
-	dump_info();
 }
 
 static int close_swap(void)
@@ -342,7 +333,8 @@ static int close_swap(void)
 	swp_entry_t entry;
 	int error;
 
-	error = write_page((unsigned long)&swsusp_info,&entry);
+	dump_info();
+	error = write_page((unsigned long)&swsusp_info, &entry);
 	if (!error) { 
 		printk( "S" );
 		error = mark_swapfiles(entry);
@@ -373,15 +365,18 @@ static void free_pagedir_entries(void)
 
 static int write_pagedir(void)
 {
-	unsigned long addr = (unsigned long)pagedir_nosave;
 	int error = 0;
-	int n = SUSPEND_PD_PAGES(nr_copy_pages);
-	int i;
+	unsigned n = 0;
+	struct pbe * pbe;
+
+	printk( "Writing pagedir...");
+	for_each_pb_page(pbe, pagedir_nosave) {
+		if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++])))
+			return error;
+	}
 
 	swsusp_info.pagedir_pages = n;
-	printk( "Writing pagedir (%d pages)\n", n);
-	for (i = 0; i < n && !error; i++, addr += PAGE_SIZE)
-		error = write_page(addr, &swsusp_info.pagedir[i]);
+	printk("done (%u pages)\n", n);
 	return error;
 }
 
@@ -567,8 +562,8 @@ static void copy_data_pages(void)
 	struct zone *zone;
 	unsigned long zone_pfn;
 	struct pbe * pbe = pagedir_nosave;
-	int to_copy = nr_copy_pages;
 	
+	pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages);
 	for_each_zone(zone) {
 		if (is_highmem(zone))
 			continue;
@@ -577,78 +572,126 @@ static void copy_data_pages(void)
 			if (saveable(zone, &zone_pfn)) {
 				struct page * page;
 				page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
+				BUG_ON(!pbe);
 				pbe->orig_address = (long) page_address(page);
 				/* copy_page is not usable for copying task structs. */
 				memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE);
-				pbe++;
-				to_copy--;
+				pbe = pbe->next;
 			}
 		}
 	}
-	BUG_ON(to_copy);
+	BUG_ON(pbe);
 }
 
 
 /**
- *	calc_order - Determine the order of allocation needed for pagedir_save.
- *
- *	This looks tricky, but is just subtle. Please fix it some time.
- *	Since there are %nr_copy_pages worth of pages in the snapshot, we need
- *	to allocate enough contiguous space to hold 
- *		(%nr_copy_pages * sizeof(struct pbe)), 
- *	which has the saved/orig locations of the page.. 
- *
- *	SUSPEND_PD_PAGES() tells us how many pages we need to hold those 
- *	structures, then we call get_bitmask_order(), which will tell us the
- *	last bit set in the number, starting with 1. (If we need 30 pages, that
- *	is 0x0000001e in hex. The last bit is the 5th, which is the order we 
- *	would use to allocate 32 contiguous pages).
- *
- *	Since we also need to save those pages, we add the number of pages that
- *	we need to nr_copy_pages, and in case of an overflow, do the 
- *	calculation again to update the number of pages needed. 
- *
- *	With this model, we will tend to waste a lot of memory if we just cross
- *	an order boundary. Plus, the higher the order of allocation that we try
- *	to do, the more likely we are to fail in a low-memory situtation 
- *	(though	we're unlikely to get this far in such a case, since swsusp 
- *	requires half of memory to be free anyway).
+ *	calc_nr - Determine the number of pages needed for a pbe list.
  */
 
-
-static void calc_order(void)
+static int calc_nr(int nr_copy)
 {
-	int diff = 0;
-	int order = 0;
+	int extra = 0;
+	int mod = !!(nr_copy % PBES_PER_PAGE);
+	int diff = (nr_copy / PBES_PER_PAGE) + mod;
 
 	do {
-		diff = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages)) - order;
-		if (diff) {
-			order += diff;
-			nr_copy_pages += 1 << diff;
-		}
-	} while(diff);
-	pagedir_order = order;
+		extra += diff;
+		nr_copy += diff;
+		mod = !!(nr_copy % PBES_PER_PAGE);
+		diff = (nr_copy / PBES_PER_PAGE) + mod - extra;
+	} while (diff > 0);
+
+	return nr_copy;
 }
 
+/**
+ *	free_pagedir - free pages allocated with alloc_pagedir()
+ */
+
+static inline void free_pagedir(struct pbe *pblist)
+{
+	struct pbe *pbe;
+
+	while (pblist) {
+		pbe = (pblist + PB_PAGE_SKIP)->next;
+		free_page((unsigned long)pblist);
+		pblist = pbe;
+	}
+}
+
+/**
+ *	fill_pb_page - Create a list of PBEs on a given memory page
+ */
+
+static inline void fill_pb_page(struct pbe *pbpage)
+{
+	struct pbe *p;
+
+	p = pbpage;
+	pbpage += PB_PAGE_SKIP;
+	do
+		p->next = p + 1;
+	while (++p < pbpage);
+}
+
+/**
+ *	create_pbe_list - Create a list of PBEs on top of a given chain
+ *	of memory pages allocated with alloc_pagedir()
+ */
+
+static void create_pbe_list(struct pbe *pblist, unsigned nr_pages)
+{
+	struct pbe *pbpage, *p;
+	unsigned num = PBES_PER_PAGE;
+
+	for_each_pb_page (pbpage, pblist) {
+		if (num >= nr_pages)
+			break;
+
+		fill_pb_page(pbpage);
+		num += PBES_PER_PAGE;
+	}
+	if (pbpage) {
+		for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++)
+			p->next = p + 1;
+		p->next = NULL;
+	}
+	pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
+}
 
 /**
  *	alloc_pagedir - Allocate the page directory.
  *
- *	First, determine exactly how many contiguous pages we need and
+ *	First, determine exactly how many pages we need and
  *	allocate them.
+ *
+ *	We arrange the pages in a chain: each page is an array of PBES_PER_PAGE
+ *	struct pbe elements (pbes) and the last element in the page points
+ *	to the next page.
+ *
+ *	On each page we set up a list of struct_pbe elements.
  */
 
-static int alloc_pagedir(void)
+static struct pbe * alloc_pagedir(unsigned nr_pages)
 {
-	calc_order();
-	pagedir_save = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC | __GFP_COLD,
-							     pagedir_order);
-	if (!pagedir_save)
-		return -ENOMEM;
-	memset(pagedir_save, 0, (1 << pagedir_order) * PAGE_SIZE);
-	pagedir_nosave = pagedir_save;
-	return 0;
+	unsigned num;
+	struct pbe *pblist, *pbe;
+
+	if (!nr_pages)
+		return NULL;
+
+	pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
+	pblist = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+	for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
+        		pbe = pbe->next, num += PBES_PER_PAGE) {
+		pbe += PB_PAGE_SKIP;
+		pbe->next = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+	}
+	if (!pbe) { /* get_zeroed_page() failed */
+		free_pagedir(pblist);
+		pblist = NULL;
+        }
+	return pblist;
 }
 
 /**
@@ -658,10 +701,8 @@ static int alloc_pagedir(void)
 static void free_image_pages(void)
 {
 	struct pbe * p;
-	int i;
 
-	p = pagedir_save;
-	for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
+	for_each_pbe(p, pagedir_save) {
 		if (p->address) {
 			ClearPageNosave(virt_to_page(p->address));
 			free_page(p->address);
@@ -672,15 +713,13 @@ static void free_image_pages(void)
 
 /**
  *	alloc_image_pages - Allocate pages for the snapshot.
- *
  */
 
 static int alloc_image_pages(void)
 {
 	struct pbe * p;
-	int i;
 
-	for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
+	for_each_pbe(p, pagedir_save) {
 		p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
 		if (!p->address)
 			return -ENOMEM;
@@ -694,7 +733,7 @@ void swsusp_free(void)
 	BUG_ON(PageNosave(virt_to_page(pagedir_save)));
 	BUG_ON(PageNosaveFree(virt_to_page(pagedir_save)));
 	free_image_pages();
-	free_pages((unsigned long) pagedir_save, pagedir_order);
+	free_pagedir(pagedir_save);
 }
 
 
@@ -752,10 +791,14 @@ static int swsusp_alloc(void)
 	if (!enough_swap())
 		return -ENOSPC;
 
-	if ((error = alloc_pagedir())) {
+	nr_copy_pages = calc_nr(nr_copy_pages);
+
+	if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
 		printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
-		return error;
+		return -ENOMEM;
 	}
+	create_pbe_list(pagedir_save, nr_copy_pages);
+	pagedir_nosave = pagedir_save;
 	if ((error = alloc_image_pages())) {
 		printk(KERN_ERR "suspend: Allocating image pages failed.\n");
 		swsusp_free();
@@ -763,7 +806,6 @@ static int swsusp_alloc(void)
 	}
 
 	nr_copy_pages_check = nr_copy_pages;
-	pagedir_order_check = pagedir_order;
 	return 0;
 }
 
@@ -780,7 +822,7 @@ static int suspend_prepare_image(void)
 
 	drain_local_pages();
 	count_data_pages();
-	printk("swsusp: Need to copy %u pages\n",nr_copy_pages);
+	printk("swsusp: Need to copy %u pages\n", nr_copy_pages);
 
 	error = swsusp_alloc();
 	if (error)
@@ -850,35 +892,29 @@ int swsusp_suspend(void)
 	 * at resume time, and evil weirdness ensues.
 	 */
 	if ((error = device_power_down(PMSG_FREEZE))) {
+		printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
 		local_irq_enable();
+		swsusp_free();
 		return error;
 	}
 	save_processor_state();
-	error = swsusp_arch_suspend();
+	if ((error = swsusp_arch_suspend()))
+		swsusp_free();
 	/* Restore control flow magically appears here */
 	restore_processor_state();
+	BUG_ON (nr_copy_pages_check != nr_copy_pages);
 	restore_highmem();
 	device_power_up();
 	local_irq_enable();
 	return error;
 }
 
-
-asmlinkage int swsusp_restore(void)
-{
-	BUG_ON (nr_copy_pages_check != nr_copy_pages);
-	BUG_ON (pagedir_order_check != pagedir_order);
-	
-	/* Even mappings of "global" things (vmalloc) need to be fixed */
-	__flush_tlb_global();
-	return 0;
-}
-
 int swsusp_resume(void)
 {
 	int error;
 	local_irq_disable();
-	device_power_down(PMSG_FREEZE);
+	if (device_power_down(PMSG_FREEZE))
+		printk(KERN_ERR "Some devices failed to power down, very bad\n");
 	/* We'll ignore saved state, but this gets preempt count (etc) right */
 	save_processor_state();
 	error = swsusp_arch_resume();
@@ -898,7 +934,7 @@ int swsusp_resume(void)
 /*
  * Returns true if given address/order collides with any orig_address 
  */
-static int __init does_collide_order(unsigned long addr, int order)
+static int does_collide_order(unsigned long addr, int order)
 {
 	int i;
 	
@@ -908,44 +944,104 @@ static int __init does_collide_order(uns
 	return 0;
 }
 
-/*
- * We check here that pagedir & pages it points to won't collide with pages
- * where we're going to restore from the loaded pages later
+/**
+ *	On resume, for storing the PBE list and the image,
+ *	we can only use memory pages that do not conflict with the pages
+ *	which had been used before suspend.
+ *
+ *	We don't know which pages are usable until we allocate them.
+ *
+ *	Allocated but unusable (ie eaten) memory pages are linked together
+ *	to create a list, so that we can free them easily
+ *
+ *	We could have used a type other than (void *)
+ *	for this purpose, but ...
  */
-static int __init check_pagedir(void)
+static void **eaten_memory = NULL;
+
+static inline void eat_page(void *page)
 {
-	int i;
+	void **c;
 
-	for(i=0; i < nr_copy_pages; i++) {
-		unsigned long addr;
+	c = eaten_memory;
+	eaten_memory = page;
+	*eaten_memory = c;
+}
 
-		do {
-			addr = get_zeroed_page(GFP_ATOMIC);
-			if(!addr)
-				return -ENOMEM;
-		} while (does_collide_order(addr, 0));
+static unsigned long get_usable_page(unsigned gfp_mask)
+{
+	unsigned long m;
 
-		(pagedir_nosave+i)->address = addr;
+	m = get_zeroed_page(gfp_mask);
+	while (does_collide_order(m, 0)) {
+		eat_page((void *)m);
+		m = get_zeroed_page(gfp_mask);
+		if (!m)
+			break;
 	}
-	return 0;
+	return m;
 }
 
-static int __init swsusp_pagedir_relocate(void)
+static void free_eaten_memory(void)
 {
-	/*
-	 * We have to avoid recursion (not to overflow kernel stack),
-	 * and that's why code looks pretty cryptic 
+	unsigned long m;
+	void **c;
+	int i = 0;
+
+	c = eaten_memory;
+	while (c) {
+		m = (unsigned long)c;
+		c = *c;
+		free_page(m);
+		i++;
+	}
+	eaten_memory = NULL;
+	pr_debug("swsusp: %d unused pages freed\n", i);
+}
+
+/**
+ *	check_pagedir - We ensure here that pages that the PBEs point to
+ *	won't collide with pages where we're going to restore from the loaded
+ *	pages later
+ */
+
+static int check_pagedir(struct pbe *pblist)
+{
+	struct pbe *p;
+
+	/* This is necessary, so that we can free allocated pages
+	 * in case of failure
 	 */
-	suspend_pagedir_t *old_pagedir = pagedir_nosave;
-	void **eaten_memory = NULL;
-	void **c = eaten_memory, *m, *f;
-	int ret = 0;
+	for_each_pbe (p, pblist)
+		p->address = 0UL;
+
+	for_each_pbe (p, pblist) {
+		p->address = get_usable_page(GFP_ATOMIC);
+		if (!p->address)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/**
+ *	swsusp_pagedir_relocate - It is possible, that some memory pages
+ *	occupied by the list of PBEs collide with pages where we're going to
+ *	restore from the loaded pages later.  We relocate them here.
+ */
+
+static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
+{
 	struct zone *zone;
-	int i;
-	struct pbe *p;
 	unsigned long zone_pfn;
+	struct pbe *pbpage, *tail, *p;
+	void *m;
+	int rel = 0, error = 0;
+
+	if (!pblist) /* a sanity check */
+		return NULL;
 
-	printk("Relocating pagedir ");
+	pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
+			swsusp_info.pagedir_pages);
 
 	/* Set page flags */
 
@@ -955,48 +1051,55 @@ static int __init swsusp_pagedir_relocat
 					zone->zone_start_pfn));
 	}
 
-	/* Clear orig address */
+	/* Clear orig addresses */
 
-	for(i = 0, p = pagedir_nosave; i < nr_copy_pages; i++, p++) {
+	for_each_pbe (p, pblist)
 		ClearPageNosaveFree(virt_to_page(p->orig_address));
-	}
 
-	if (!does_collide_order((unsigned long)old_pagedir, pagedir_order)) {
-		printk("not necessary\n");
-		return check_pagedir();
-	}
+	tail = pblist + PB_PAGE_SKIP;
 
-	while ((m = (void *) __get_free_pages(GFP_ATOMIC, pagedir_order)) != NULL) {
-		if (!does_collide_order((unsigned long)m, pagedir_order))
-			break;
-		eaten_memory = m;
-		printk( "." ); 
-		*eaten_memory = c;
-		c = eaten_memory;
-	}
+	/* Relocate colliding pages */
 
-	if (!m) {
-		printk("out of memory\n");
-		ret = -ENOMEM;
-	} else {
-		pagedir_nosave =
-			memcpy(m, old_pagedir, PAGE_SIZE << pagedir_order);
+	for_each_pb_page (pbpage, pblist) {
+		if (does_collide_order((unsigned long)pbpage, 0)) {
+			m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD);
+			if (!m) {
+				error = -ENOMEM;
+				break;
+			}
+			memcpy(m, (void *)pbpage, PAGE_SIZE);
+			if (pbpage == pblist)
+				pblist = (struct pbe *)m;
+			else
+				tail->next = (struct pbe *)m;
+
+			eat_page((void *)pbpage);
+			pbpage = (struct pbe *)m;
+
+			/* We have to link the PBEs again */
+
+			for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
+				if (p->next) /* needed to save the end */
+					p->next = p + 1;
+
+			rel++;
+		}
+		tail = pbpage + PB_PAGE_SKIP;
 	}
 
-	c = eaten_memory;
-	while (c) {
-		printk(":");
-		f = c;
-		c = *c;
-		free_pages((unsigned long)f, pagedir_order);
+	if (error) {
+		printk("\nswsusp: Out of memory\n\n");
+		free_pagedir(pblist);
+		free_eaten_memory();
+		pblist = NULL;
 	}
-	if (ret)
-		return ret;
-	printk("|\n");
-	return check_pagedir();
+	else
+		printk("swsusp: Relocated %d pages\n", rel);
+
+	return pblist;
 }
 
-/**
+/*
  *	Using bio to read from swap.
  *	This code requires a bit more work than just using buffer heads
  *	but, it is the recommended way for 2.5/2.6.
@@ -1075,7 +1178,7 @@ static int bio_write_page(pgoff_t page_o
  * I really don't think that it's foolproof but more than nothing..
  */
 
-static const char * __init sanity_check(void)
+static const char * sanity_check(void)
 {
 	dump_info();
 	if(swsusp_info.version_code != LINUX_VERSION_CODE)
@@ -1096,7 +1199,7 @@ static const char * __init sanity_check(
 }
 
 
-static int __init check_header(void)
+static int check_header(void)
 {
 	const char * reason = NULL;
 	int error;
@@ -1110,11 +1213,10 @@ static int __init check_header(void)
 		return -EPERM;
 	}
 	nr_copy_pages = swsusp_info.image_pages;
-	pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
 	return error;
 }
 
-static int __init check_sig(void)
+static int check_sig(void)
 {
 	int error;
 
@@ -1129,7 +1231,7 @@ static int __init check_sig(void)
 		 */
 		error = bio_write_page(0, &swsusp_header);
 	} else { 
-		pr_debug(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
+		printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
 		return -EINVAL;
 	}
 	if (!error)
@@ -1138,104 +1240,194 @@ static int __init check_sig(void)
 }
 
 /**
- *	swsusp_read_data - Read image pages from swap.
+ *	data_read - Read image pages from swap.
  *
  *	You do not need to check for overlaps, check_pagedir()
  *	already did that.
  */
 
-static int __init data_read(void)
+static int data_read(struct pbe *pblist)
 {
 	struct pbe * p;
-	int error;
-	int i;
-	int mod = nr_copy_pages / 100;
+	int error = 0;
+	int i = 0;
+	int mod = swsusp_info.image_pages / 100;
 
 	if (!mod)
 		mod = 1;
 
-	if ((error = swsusp_pagedir_relocate()))
-		return error;
+	printk("swsusp: Reading image data (%lu pages):     ",
+			swsusp_info.image_pages);
+
+	for_each_pbe (p, pblist) {
+		if (!(i % mod))
+			printk("\b\b\b\b%3d%%", i / mod);
 
-	printk( "Reading image data (%d pages):     ", nr_copy_pages );
-	for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
-		if (!(i%mod))
-			printk( "\b\b\b\b%3d%%", i / mod );
 		error = bio_read_page(swp_offset(p->swap_address),
 				  (void *)p->address);
+		if (error)
+			return error;
+
+		i++;
 	}
-	printk(" %d done.\n",i);
+	printk("\b\b\b\bdone\n");
 	return error;
-
 }
 
-extern dev_t __init name_to_dev_t(const char *line);
+extern dev_t name_to_dev_t(const char *line);
 
-static int __init read_pagedir(void)
+/**
+ *	read_pagedir - Read page backup list pages from swap
+ */
+
+static int read_pagedir(struct pbe *pblist)
 {
-	unsigned long addr;
-	int i, n = swsusp_info.pagedir_pages;
-	int error = 0;
+	struct pbe *pbpage, *p;
+	unsigned i = 0;
+	int error;
 
-	addr = __get_free_pages(GFP_ATOMIC, pagedir_order);
-	if (!addr)
-		return -ENOMEM;
-	pagedir_nosave = (struct pbe *)addr;
+	if (!pblist)
+		return -EFAULT;
 
-	pr_debug("swsusp: Reading pagedir (%d Pages)\n",n);
+	printk("swsusp: Reading pagedir (%lu pages)\n",
+			swsusp_info.pagedir_pages);
 
-	for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) {
-		unsigned long offset = swp_offset(swsusp_info.pagedir[i]);
-		if (offset)
-			error = bio_read_page(offset, (void *)addr);
-		else
-			error = -EFAULT;
+	for_each_pb_page (pbpage, pblist) {
+		unsigned long offset = swp_offset(swsusp_info.pagedir[i++]);
+
+		error = -EFAULT;
+		if (offset) {
+			p = (pbpage + PB_PAGE_SKIP)->next;
+			error = bio_read_page(offset, (void *)pbpage);
+			(pbpage + PB_PAGE_SKIP)->next = p;
+		}
+		if (error)
+			break;
 	}
+
 	if (error)
-		free_pages((unsigned long)pagedir_nosave, pagedir_order);
+		free_page((unsigned long)pblist);
+
+	BUG_ON(i != swsusp_info.pagedir_pages);
+
 	return error;
 }
 
-static int __init read_suspend_image(void)
+
+static int check_suspend_image(void)
 {
 	int error = 0;
 
 	if ((error = check_sig()))
 		return error;
+
 	if ((error = check_header()))
 		return error;
-	if ((error = read_pagedir()))
+
+	return 0;
+}
+
+static int read_suspend_image(void)
+{
+	int error = 0;
+	struct pbe *p;
+
+	if (!(p = alloc_pagedir(nr_copy_pages)))
+		return -ENOMEM;
+
+	if ((error = read_pagedir(p)))
 		return error;
-	if ((error = data_read()))
-		free_pages((unsigned long)pagedir_nosave, pagedir_order);
+
+	create_pbe_list(p, nr_copy_pages);
+
+	if (!(pagedir_nosave = swsusp_pagedir_relocate(p)))
+		return -ENOMEM;
+
+	/* Allocate memory for the image and read the data from swap */
+
+	error = check_pagedir(pagedir_nosave);
+	free_eaten_memory();
+	if (!error)
+		error = data_read(pagedir_nosave);
+
+	if (error) { /* We fail cleanly */
+		for_each_pbe (p, pagedir_nosave)
+			if (p->address) {
+				free_page(p->address);
+				p->address = 0UL;
+			}
+		free_pagedir(pagedir_nosave);
+	}
 	return error;
 }
 
 /**
- *	swsusp_read - Read saved image from swap.
+ *      swsusp_check - Check for saved image in swap
  */
 
-int __init swsusp_read(void)
+int swsusp_check(void)
 {
 	int error;
 
-	if (!strlen(resume_file))
-		return -ENOENT;
-
-	resume_device = name_to_dev_t(resume_file);
-	pr_debug("swsusp: Resume From Partition: %s\n", resume_file);
+	if (!swsusp_resume_device) {
+		if (!strlen(resume_file))
+			return -ENOENT;
+		swsusp_resume_device = name_to_dev_t(resume_file);
+		pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+	} else {
+		pr_debug("swsusp: Resume From Partition %d:%d\n",
+			 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+	}
 
-	resume_bdev = open_by_devnum(resume_device, FMODE_READ);
+	resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
 	if (!IS_ERR(resume_bdev)) {
 		set_blocksize(resume_bdev, PAGE_SIZE);
-		error = read_suspend_image();
-		blkdev_put(resume_bdev);
+		error = check_suspend_image();
+		if (error)
+		    blkdev_put(resume_bdev);
 	} else
 		error = PTR_ERR(resume_bdev);
 
 	if (!error)
-		pr_debug("Reading resume file was successful\n");
+		pr_debug("swsusp: resume file found\n");
+	else
+		pr_debug("swsusp: Error %d check for resume file\n", error);
+	return error;
+}
+
+/**
+ *	swsusp_read - Read saved image from swap.
+ */
+
+int swsusp_read(void)
+{
+	int error;
+
+	if (IS_ERR(resume_bdev)) {
+		pr_debug("swsusp: block device not initialised\n");
+		return PTR_ERR(resume_bdev);
+	}
+
+	error = read_suspend_image();
+	blkdev_put(resume_bdev);
+
+	if (!error)
+		pr_debug("swsusp: Reading resume file was successful\n");
 	else
 		pr_debug("swsusp: Error %d resuming\n", error);
 	return error;
 }
+
+/**
+ *	swsusp_close - close swap device.
+ */
+
+void swsusp_close(void)
+{
+	if (IS_ERR(resume_bdev)) {
+		pr_debug("swsusp: block device not initialised\n");
+		return;
+	}
+
+	blkdev_put(resume_bdev);
+}
diff --git a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -54,7 +54,12 @@ int console_printk[4] = {
 
 EXPORT_SYMBOL(console_printk);
 
+/*
+ * Low lever drivers may need that to know if they can schedule in
+ * their unblank() callback or not. So let's export it.
+ */
 int oops_in_progress;
+EXPORT_SYMBOL(oops_in_progress);
 
 /*
  * console_sem protects the console_drivers list, and also
@@ -80,10 +85,6 @@ static int console_locked;
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
-static char __log_buf[__LOG_BUF_LEN];
-static char *log_buf = __log_buf;
-static int log_buf_len = __LOG_BUF_LEN;
-
 #define LOG_BUF_MASK	(log_buf_len-1)
 #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
 
@@ -94,7 +95,6 @@ static int log_buf_len = __LOG_BUF_LEN;
 static unsigned long log_start;	/* Index into log_buf: next char to be read by syslog() */
 static unsigned long con_start;	/* Index into log_buf: next char to be sent to consoles */
 static unsigned long log_end;	/* Index into log_buf: most-recently-written-char + 1 */
-static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
 
 /*
  *	Array of consoles built from command line options (console=)
@@ -115,6 +115,13 @@ static int preferred_console = -1;
 /* Flag: console code may call schedule() */
 static int console_may_schedule;
 
+#ifdef CONFIG_PRINTK
+
+static char __log_buf[__LOG_BUF_LEN];
+static char *log_buf = __log_buf;
+static int log_buf_len = __LOG_BUF_LEN;
+static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+
 /*
  *	Setup a list of consoles. Called from init/main.c
  */
@@ -153,42 +160,6 @@ static int __init console_setup(char *st
 
 __setup("console=", console_setup);
 
-/**
- * add_preferred_console - add a device to the list of preferred consoles.
- *
- * The last preferred console added will be used for kernel messages
- * and stdin/out/err for init.  Normally this is used by console_setup
- * above to handle user-supplied console arguments; however it can also
- * be used by arch-specific code either to override the user or more
- * commonly to provide a default console (ie from PROM variables) when
- * the user has not supplied one.
- */
-int __init add_preferred_console(char *name, int idx, char *options)
-{
-	struct console_cmdline *c;
-	int i;
-
-	/*
-	 *	See if this tty is not yet registered, and
-	 *	if we have a slot free.
-	 */
-	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-		if (strcmp(console_cmdline[i].name, name) == 0 &&
-			  console_cmdline[i].index == idx) {
-				selected_console = i;
-				return 0;
-		}
-	if (i == MAX_CMDLINECONSOLES)
-		return -E2BIG;
-	selected_console = i;
-	c = &console_cmdline[i];
-	memcpy(c->name, name, sizeof(c->name));
-	c->name[sizeof(c->name) - 1] = 0;
-	c->options = options;
-	c->index = idx;
-	return 0;
-}
-
 static int __init log_buf_len_setup(char *str)
 {
 	unsigned long size = memparse(str, &str);
@@ -269,9 +240,10 @@ int do_syslog(int type, char __user * bu
 		error = 0;
 		if (!len)
 			goto out;
-		error = verify_area(VERIFY_WRITE,buf,len);
-		if (error)
+		if (!access_ok(VERIFY_WRITE, buf, len)) {
+			error = -EFAULT;
 			goto out;
+		}
 		error = wait_event_interruptible(log_wait, (log_start - log_end));
 		if (error)
 			goto out;
@@ -301,9 +273,10 @@ int do_syslog(int type, char __user * bu
 		error = 0;
 		if (!len)
 			goto out;
-		error = verify_area(VERIFY_WRITE,buf,len);
-		if (error)
+		if (!access_ok(VERIFY_WRITE, buf, len)) {
+			error = -EFAULT;
 			goto out;
+		}
 		count = len;
 		if (count > log_buf_len)
 			count = log_buf_len;
@@ -499,6 +472,22 @@ static void zap_locks(void)
 	init_MUTEX(&console_sem);
 }
 
+#if defined(CONFIG_PRINTK_TIME)
+static int printk_time = 1;
+#else
+static int printk_time = 0;
+#endif
+
+static int __init printk_time_setup(char *str)
+{
+	if (*str)
+		return 0;
+	printk_time = 1;
+	return 1;
+}
+
+__setup("time", printk_time_setup);
+
 /*
  * This is printk.  It can be called from any context.  We want it to work.
  * 
@@ -512,6 +501,7 @@ static void zap_locks(void)
  * then changes console_loglevel may break. This is because console_loglevel
  * is inspected when the actual printing occurs.
  */
+
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
@@ -547,12 +537,51 @@ asmlinkage int vprintk(const char *fmt, 
 	 */
 	for (p = printk_buf; *p; p++) {
 		if (log_level_unknown) {
-			if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
-				emit_log_char('<');
-				emit_log_char(default_message_loglevel + '0');
-				emit_log_char('>');
+                        /* log_level_unknown signals the start of a new line */
+			if (printk_time) {
+				int loglev_char;
+				char tbuf[50], *tp;
+				unsigned tlen;
+				unsigned long long t;
+				unsigned long nanosec_rem;
+
+				/*
+				 * force the log level token to be
+				 * before the time output.
+				 */
+				if (p[0] == '<' && p[1] >='0' &&
+				   p[1] <= '7' && p[2] == '>') {
+					loglev_char = p[1];
+					p += 3;
+					printed_len += 3;
+				} else {
+					loglev_char = default_message_loglevel
+						+ '0';
+				}
+				t = sched_clock();
+				nanosec_rem = do_div(t, 1000000000);
+				tlen = sprintf(tbuf,
+						"<%c>[%5lu.%06lu] ",
+						loglev_char,
+						(unsigned long)t,
+						nanosec_rem/1000);
+
+				for (tp = tbuf; tp < tbuf + tlen; tp++)
+					emit_log_char(*tp);
+				printed_len += tlen - 3;
+			} else {
+				if (p[0] != '<' || p[1] < '0' ||
+				   p[1] > '7' || p[2] != '>') {
+					emit_log_char('<');
+					emit_log_char(default_message_loglevel
+						+ '0');
+					emit_log_char('>');
+				}
+				printed_len += 3;
 			}
 			log_level_unknown = 0;
+			if (!*p)
+				break;
 		}
 		emit_log_char(*p);
 		if (*p == '\n')
@@ -593,6 +622,54 @@ out:
 EXPORT_SYMBOL(printk);
 EXPORT_SYMBOL(vprintk);
 
+#else
+
+asmlinkage long sys_syslog(int type, char __user * buf, int len)
+{
+	return 0;
+}
+
+int do_syslog(int type, char __user * buf, int len) { return 0; }
+static void call_console_drivers(unsigned long start, unsigned long end) {}
+
+#endif
+
+/**
+ * add_preferred_console - add a device to the list of preferred consoles.
+ *
+ * The last preferred console added will be used for kernel messages
+ * and stdin/out/err for init.  Normally this is used by console_setup
+ * above to handle user-supplied console arguments; however it can also
+ * be used by arch-specific code either to override the user or more
+ * commonly to provide a default console (ie from PROM variables) when
+ * the user has not supplied one.
+ */
+int __init add_preferred_console(char *name, int idx, char *options)
+{
+	struct console_cmdline *c;
+	int i;
+
+	/*
+	 *	See if this tty is not yet registered, and
+	 *	if we have a slot free.
+	 */
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+		if (strcmp(console_cmdline[i].name, name) == 0 &&
+			  console_cmdline[i].index == idx) {
+				selected_console = i;
+				return 0;
+		}
+	if (i == MAX_CMDLINECONSOLES)
+		return -E2BIG;
+	selected_console = i;
+	c = &console_cmdline[i];
+	memcpy(c->name, name, sizeof(c->name));
+	c->name[sizeof(c->name) - 1] = 0;
+	c->options = options;
+	c->index = idx;
+	return 0;
+}
+
 /**
  * acquire_console_sem - lock the console system for exclusive use.
  *
@@ -694,12 +771,15 @@ void console_unblank(void)
 	struct console *c;
 
 	/*
-	 * Try to get the console semaphore. If someone else owns it
-	 * we have to return without unblanking because console_unblank
-	 * may be called in interrupt context.
+	 * console_unblank can no longer be called in interrupt context unless
+	 * oops_in_progress is set to 1..
 	 */
-	if (down_trylock(&console_sem) != 0)
-		return;
+	if (oops_in_progress) {
+		if (down_trylock(&console_sem) != 0)
+			return;
+	} else
+		acquire_console_sem();
+
 	console_locked = 1;
 	console_may_schedule = 0;
 	for (c = console_drivers; c != NULL; c = c->next)
@@ -804,6 +884,11 @@ void register_console(struct console * c
 	if (!(console->flags & CON_ENABLED))
 		return;
 
+	if (console_drivers && (console_drivers->flags & CON_BOOT)) {
+		unregister_console(console_drivers);
+		console->flags &= ~CON_PRINTBUFFER;
+	}
+
 	/*
 	 *	Put this console in the list - keep the
 	 *	preferred driver at the head of the list.
@@ -861,7 +946,7 @@ int unregister_console(struct console * 
 	return res;
 }
 EXPORT_SYMBOL(unregister_console);
-	
+
 /**
  * tty_write_message - write a message to a certain tty, not just the console.
  *
diff --git a/kernel/profile.c b/kernel/profile.c
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -49,15 +49,19 @@ static DECLARE_MUTEX(profile_flip_mutex)
 
 static int __init profile_setup(char * str)
 {
+	static char __initdata schedstr[] = "schedule";
 	int par;
 
-	if (!strncmp(str, "schedule", 8)) {
+	if (!strncmp(str, schedstr, strlen(schedstr))) {
 		prof_on = SCHED_PROFILING;
-		printk(KERN_INFO "kernel schedule profiling enabled\n");
-		if (str[7] == ',')
-			str += 8;
-	}
-	if (get_option(&str,&par)) {
+		if (str[strlen(schedstr)] == ',')
+			str += strlen(schedstr) + 1;
+		if (get_option(&str, &par))
+			prof_shift = par;
+		printk(KERN_INFO
+			"kernel schedule profiling enabled (shift: %ld)\n",
+			prof_shift);
+	} else if (get_option(&str, &par)) {
 		prof_shift = par;
 		prof_on = CPU_PROFILING;
 		printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n",
@@ -184,7 +188,7 @@ void unregister_timer_hook(int (*hook)(s
 	WARN_ON(hook != timer_hook);
 	timer_hook = NULL;
 	/* make sure all CPUs see the NULL hook */
-	synchronize_kernel();
+	synchronize_sched();  /* Allow ongoing interrupts to complete. */
 }
 
 EXPORT_SYMBOL_GPL(register_timer_hook);
@@ -522,7 +526,7 @@ static int __init create_hash_tables(voi
 	return 0;
 out_cleanup:
 	prof_on = 0;
-	mb();
+	smp_mb();
 	on_each_cpu(profile_nop, NULL, 0, 1);
 	for_each_online_cpu(cpu) {
 		struct page *page;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -16,6 +16,7 @@
 #include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -135,7 +136,7 @@ int ptrace_attach(struct task_struct *ta
  	    (current->gid != task->sgid) ||
  	    (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
 		goto bad;
-	rmb();
+	smp_rmb();
 	if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
 		goto bad;
 	/* the same process cannot be attached many times */
@@ -166,7 +167,7 @@ bad:
 
 int ptrace_detach(struct task_struct *child, unsigned int data)
 {
-	if ((unsigned long) data > _NSIG)
+	if (!valid_signal(data))
 		return	-EIO;
 
 	/* Architecture-specific hardware disable .. */
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -444,15 +444,18 @@ static void wakeme_after_rcu(struct rcu_
 }
 
 /**
- * synchronize_kernel - wait until a grace period has elapsed.
+ * synchronize_rcu - wait until a grace period has elapsed.
  *
  * Control will return to the caller some time after a full grace
  * period has elapsed, in other words after all currently executing RCU
  * read-side critical sections have completed.  RCU read-side critical
  * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
  * and may be nested.
+ *
+ * If your read-side code is not protected by rcu_read_lock(), do -not-
+ * use synchronize_rcu().
  */
-void synchronize_kernel(void)
+void synchronize_rcu(void)
 {
 	struct rcu_synchronize rcu;
 
@@ -464,7 +467,16 @@ void synchronize_kernel(void)
 	wait_for_completion(&rcu.completion);
 }
 
+/*
+ * Deprecated, use synchronize_rcu() or synchronize_sched() instead.
+ */
+void synchronize_kernel(void)
+{
+	synchronize_rcu();
+}
+
 module_param(maxbatch, int, 0);
-EXPORT_SYMBOL(call_rcu);
-EXPORT_SYMBOL(call_rcu_bh);
-EXPORT_SYMBOL(synchronize_kernel);
+EXPORT_SYMBOL(call_rcu);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL(call_rcu_bh);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL(synchronize_rcu);
+EXPORT_SYMBOL(synchronize_kernel);  /* WARNING: GPL-only in April 2006. */
diff --git a/kernel/resource.c b/kernel/resource.c
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -91,7 +91,7 @@ static int r_show(struct seq_file *m, vo
 	return 0;
 }
 
-struct seq_operations resource_op = {
+static struct seq_operations resource_op = {
 	.start	= r_start,
 	.next	= r_next,
 	.stop	= r_stop,
@@ -266,7 +266,7 @@ static int find_resource(struct resource
 		new->start = (new->start + align - 1) & ~(align - 1);
 		if (alignf)
 			alignf(alignf_data, new, size, align);
-		if (new->start < new->end && new->end - new->start + 1 >= size) {
+		if (new->start < new->end && new->end - new->start >= size - 1) {
 			new->end = new->start + size - 1;
 			return 0;
 		}
diff --git a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -40,11 +40,13 @@
 #include <linux/timer.h>
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/percpu.h>
 #include <linux/kthread.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/times.h>
+#include <linux/acct.h>
 #include <asm/tlb.h>
 
 #include <asm/unistd.h>
@@ -164,7 +166,7 @@
 #define SCALE_PRIO(x, prio) \
 	max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
 
-static unsigned int task_timeslice(task_t *p)
+static inline unsigned int task_timeslice(task_t *p)
 {
 	if (p->static_prio < NICE_TO_PRIO(0))
 		return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
@@ -246,35 +248,13 @@ struct runqueue {
 	unsigned long yld_cnt;
 
 	/* schedule() stats */
-	unsigned long sched_noswitch;
 	unsigned long sched_switch;
 	unsigned long sched_cnt;
 	unsigned long sched_goidle;
 
-	/* pull_task() stats */
-	unsigned long pt_gained[MAX_IDLE_TYPES];
-	unsigned long pt_lost[MAX_IDLE_TYPES];
-
-	/* active_load_balance() stats */
-	unsigned long alb_cnt;
-	unsigned long alb_lost;
-	unsigned long alb_gained;
-	unsigned long alb_failed;
-
 	/* try_to_wake_up() stats */
 	unsigned long ttwu_cnt;
-	unsigned long ttwu_attempts;
-	unsigned long ttwu_moved;
-
-	/* wake_up_new_task() stats */
-	unsigned long wunt_cnt;
-	unsigned long wunt_moved;
-
-	/* sched_migrate_task() stats */
-	unsigned long smt_cnt;
-
-	/* sched_balance_exec() stats */
-	unsigned long sbe_cnt;
+	unsigned long ttwu_local;
 #endif
 };
 
@@ -302,7 +282,7 @@ static DEFINE_PER_CPU(struct runqueue, r
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
  * explicitly disabling preemption.
  */
-static runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
+static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
 	__acquires(rq->lock)
 {
 	struct runqueue *rq;
@@ -329,12 +309,11 @@ static inline void task_rq_unlock(runque
  * bump this up when changing the output format or the meaning of an existing
  * format, so that tools can adapt (or abort)
  */
-#define SCHEDSTAT_VERSION 10
+#define SCHEDSTAT_VERSION 11
 
 static int show_schedstat(struct seq_file *seq, void *v)
 {
 	int cpu;
-	enum idle_type itype;
 
 	seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
 	seq_printf(seq, "timestamp %lu\n", jiffies);
@@ -347,43 +326,40 @@ static int show_schedstat(struct seq_fil
 
 		/* runqueue-specific stats */
 		seq_printf(seq,
-		    "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
-		    "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+		    "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 		    cpu, rq->yld_both_empty,
-		    rq->yld_act_empty, rq->yld_exp_empty,
-		    rq->yld_cnt, rq->sched_noswitch,
+		    rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt,
 		    rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
-		    rq->alb_cnt, rq->alb_gained, rq->alb_lost,
-		    rq->alb_failed,
-		    rq->ttwu_cnt, rq->ttwu_moved, rq->ttwu_attempts,
-		    rq->wunt_cnt, rq->wunt_moved,
-		    rq->smt_cnt, rq->sbe_cnt, rq->rq_sched_info.cpu_time,
+		    rq->ttwu_cnt, rq->ttwu_local,
+		    rq->rq_sched_info.cpu_time,
 		    rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
 
-		for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES; itype++)
-			seq_printf(seq, " %lu %lu", rq->pt_gained[itype],
-						    rq->pt_lost[itype]);
 		seq_printf(seq, "\n");
 
 #ifdef CONFIG_SMP
 		/* domain-specific stats */
 		for_each_domain(cpu, sd) {
+			enum idle_type itype;
 			char mask_str[NR_CPUS];
 
 			cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
 			seq_printf(seq, "domain%d %s", dcnt++, mask_str);
 			for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES;
-						itype++) {
-				seq_printf(seq, " %lu %lu %lu %lu %lu",
+					itype++) {
+				seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu",
 				    sd->lb_cnt[itype],
+				    sd->lb_balanced[itype],
 				    sd->lb_failed[itype],
 				    sd->lb_imbalance[itype],
+				    sd->lb_gained[itype],
+				    sd->lb_hot_gained[itype],
 				    sd->lb_nobusyq[itype],
 				    sd->lb_nobusyg[itype]);
 			}
-			seq_printf(seq, " %lu %lu %lu %lu\n",
+			seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu\n",
+			    sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
 			    sd->sbe_pushed, sd->sbe_attempts,
-			    sd->ttwu_wake_affine, sd->ttwu_wake_balance);
+			    sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance);
 		}
 #endif
 	}
@@ -426,7 +402,7 @@ struct file_operations proc_schedstat_op
 /*
  * rq_lock - lock a given runqueue and disable interrupts.
  */
-static runqueue_t *this_rq_lock(void)
+static inline runqueue_t *this_rq_lock(void)
 	__acquires(rq->lock)
 {
 	runqueue_t *rq;
@@ -648,6 +624,7 @@ static inline void __activate_idle_task(
 
 static void recalc_task_prio(task_t *p, unsigned long long now)
 {
+	/* Caller must always ensure 'now >= p->timestamp' */
 	unsigned long long __sleep_time = now - p->timestamp;
 	unsigned long sleep_time;
 
@@ -995,7 +972,6 @@ static int try_to_wake_up(task_t * p, un
 #endif
 
 	rq = task_rq_lock(p, &flags);
-	schedstat_inc(rq, ttwu_cnt);
 	old_state = p->state;
 	if (!(old_state & state))
 		goto out;
@@ -1010,8 +986,21 @@ static int try_to_wake_up(task_t * p, un
 	if (unlikely(task_running(rq, p)))
 		goto out_activate;
 
-	new_cpu = cpu;
+#ifdef CONFIG_SCHEDSTATS
+	schedstat_inc(rq, ttwu_cnt);
+	if (cpu == this_cpu) {
+		schedstat_inc(rq, ttwu_local);
+	} else {
+		for_each_domain(this_cpu, sd) {
+			if (cpu_isset(cpu, sd->span)) {
+				schedstat_inc(sd, ttwu_wake_remote);
+				break;
+			}
+		}
+	}
+#endif
 
+	new_cpu = cpu;
 	if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
 		goto out_set_cpu;
 
@@ -1050,7 +1039,7 @@ static int try_to_wake_up(task_t * p, un
 			 * in this domain.
 			 */
 			if (cpu_isset(cpu, sd->span)) {
-				schedstat_inc(sd, ttwu_wake_affine);
+				schedstat_inc(sd, ttwu_move_affine);
 				goto out_set_cpu;
 			}
 		} else if ((sd->flags & SD_WAKE_BALANCE) &&
@@ -1060,7 +1049,7 @@ static int try_to_wake_up(task_t * p, un
 			 * an imbalance.
 			 */
 			if (cpu_isset(cpu, sd->span)) {
-				schedstat_inc(sd, ttwu_wake_balance);
+				schedstat_inc(sd, ttwu_move_balance);
 				goto out_set_cpu;
 			}
 		}
@@ -1068,10 +1057,8 @@ static int try_to_wake_up(task_t * p, un
 
 	new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */
 out_set_cpu:
-	schedstat_inc(rq, ttwu_attempts);
 	new_cpu = wake_idle(new_cpu, p);
 	if (new_cpu != cpu) {
-		schedstat_inc(rq, ttwu_moved);
 		set_task_cpu(p, new_cpu);
 		task_rq_unlock(rq, &flags);
 		/* might preempt at this point */
@@ -1214,7 +1201,6 @@ void fastcall wake_up_new_task(task_t * 
 
 	BUG_ON(p->state != TASK_RUNNING);
 
-	schedstat_inc(rq, wunt_cnt);
 	/*
 	 * We decrease the sleep average of forking parents
 	 * and children as well, to keep max-interactive tasks
@@ -1266,7 +1252,6 @@ void fastcall wake_up_new_task(task_t * 
 		if (TASK_PREEMPTS_CURR(p, rq))
 			resched_task(rq->curr);
 
-		schedstat_inc(rq, wunt_moved);
 		/*
 		 * Parent and child are on different CPUs, now get the
 		 * parent runqueue to update the parent's ->sleep_avg:
@@ -1323,7 +1308,7 @@ void fastcall sched_exit(task_t * p)
  * with the lock held can cause deadlocks; see schedule() for
  * details.)
  */
-static void finish_task_switch(task_t *prev)
+static inline void finish_task_switch(task_t *prev)
 	__releases(rq->lock)
 {
 	runqueue_t *rq = this_rq();
@@ -1570,7 +1555,6 @@ static void sched_migrate_task(task_t *p
 	    || unlikely(cpu_is_offline(dest_cpu)))
 		goto out;
 
-	schedstat_inc(rq, smt_cnt);
 	/* force the process onto the specified CPU */
 	if (migrate_task(p, dest_cpu, &req)) {
 		/* Need to wait for migration thread (might exit: take ref). */
@@ -1598,7 +1582,6 @@ void sched_exec(void)
 	struct sched_domain *tmp, *sd = NULL;
 	int new_cpu, this_cpu = get_cpu();
 
-	schedstat_inc(this_rq(), sbe_cnt);
 	/* Prefer the current CPU if there's only this task running */
 	if (this_rq()->nr_running <= 1)
 		goto out;
@@ -1741,13 +1724,10 @@ skip_queue:
 		goto skip_bitmap;
 	}
 
-	/*
-	 * Right now, this is the only place pull_task() is called,
-	 * so we can safely collect pull_task() stats here rather than
-	 * inside pull_task().
-	 */
-	schedstat_inc(this_rq, pt_gained[idle]);
-	schedstat_inc(busiest, pt_lost[idle]);
+#ifdef CONFIG_SCHEDSTATS
+	if (task_hot(tmp, busiest->timestamp_last_tick, sd))
+		schedstat_inc(sd, lb_hot_gained[idle]);
+#endif
 
 	pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
 	pulled++;
@@ -1760,6 +1740,12 @@ skip_queue:
 		goto skip_bitmap;
 	}
 out:
+	/*
+	 * Right now, this is the only place pull_task() is called,
+	 * so we can safely collect pull_task() stats here rather than
+	 * inside pull_task().
+	 */
+	schedstat_add(sd, lb_gained[idle], pulled);
 	return pulled;
 }
 
@@ -1780,7 +1766,7 @@ find_busiest_group(struct sched_domain *
 	do {
 		unsigned long load;
 		int local_group;
-		int i, nr_cpus = 0;
+		int i;
 
 		local_group = cpu_isset(this_cpu, group->cpumask);
 
@@ -1794,13 +1780,9 @@ find_busiest_group(struct sched_domain *
 			else
 				load = source_load(i);
 
-			nr_cpus++;
 			avg_load += load;
 		}
 
-		if (!nr_cpus)
-			goto nextgroup;
-
 		total_load += avg_load;
 		total_pwr += group->cpu_power;
 
@@ -1839,13 +1821,12 @@ nextgroup:
 	 * by pulling tasks to us.  Be careful of negative numbers as they'll
 	 * appear as very large values with unsigned longs.
 	 */
-	*imbalance = min(max_load - avg_load, avg_load - this_load);
-
 	/* How much load to actually move to equalise the imbalance */
-	*imbalance = (*imbalance * min(busiest->cpu_power, this->cpu_power))
-				/ SCHED_LOAD_SCALE;
+	*imbalance = min((max_load - avg_load) * busiest->cpu_power,
+				(avg_load - this_load) * this->cpu_power)
+			/ SCHED_LOAD_SCALE;
 
-	if (*imbalance < SCHED_LOAD_SCALE - 1) {
+	if (*imbalance < SCHED_LOAD_SCALE) {
 		unsigned long pwr_now = 0, pwr_move = 0;
 		unsigned long tmp;
 
@@ -1871,14 +1852,16 @@ nextgroup:
 							max_load - tmp);
 
 		/* Amount of load we'd add */
-		tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;
-		if (max_load < tmp)
-			tmp = max_load;
+		if (max_load*busiest->cpu_power <
+				SCHED_LOAD_SCALE*SCHED_LOAD_SCALE)
+			tmp = max_load*busiest->cpu_power/this->cpu_power;
+		else
+			tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;
 		pwr_move += this->cpu_power*min(SCHED_LOAD_SCALE, this_load + tmp);
 		pwr_move /= SCHED_LOAD_SCALE;
 
-		/* Move if we gain another 8th of a CPU worth of throughput */
-		if (pwr_move < pwr_now + SCHED_LOAD_SCALE / 8)
+		/* Move if we gain throughput */
+		if (pwr_move <= pwr_now)
 			goto out_balanced;
 
 		*imbalance = 1;
@@ -1886,7 +1869,7 @@ nextgroup:
 	}
 
 	/* Get rid of the scaling factor, rounding down as we divide */
-	*imbalance = (*imbalance + 1) / SCHED_LOAD_SCALE;
+	*imbalance = *imbalance / SCHED_LOAD_SCALE;
 
 	return busiest;
 
@@ -2020,6 +2003,8 @@ static int load_balance(int this_cpu, ru
 out_balanced:
 	spin_unlock(&this_rq->lock);
 
+	schedstat_inc(sd, lb_balanced[idle]);
+
 	/* tune up the balancing interval */
 	if (sd->balance_interval < sd->max_interval)
 		sd->balance_interval *= 2;
@@ -2045,12 +2030,14 @@ static int load_balance_newidle(int this
 	schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
 	group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
 	if (!group) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
 		goto out;
 	}
 
 	busiest = find_busiest_queue(group);
 	if (!busiest || busiest == this_rq) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
 		goto out;
 	}
@@ -2104,7 +2091,6 @@ static void active_load_balance(runqueue
 	cpumask_t visited_cpus;
 	int cpu;
 
-	schedstat_inc(busiest_rq, alb_cnt);
 	/*
 	 * Search for suitable CPUs to push tasks to in successively higher
 	 * domains with SD_LOAD_BALANCE set.
@@ -2115,6 +2101,8 @@ static void active_load_balance(runqueue
 			/* no more domains to search */
 			break;
 
+		schedstat_inc(sd, alb_cnt);
+
 		cpu_group = sd->groups;
 		do {
 			for_each_cpu_mask(cpu, cpu_group->cpumask) {
@@ -2139,10 +2127,9 @@ static void active_load_balance(runqueue
 				double_lock_balance(busiest_rq, target_rq);
 				if (move_tasks(target_rq, cpu, busiest_rq,
 						1, sd, SCHED_IDLE)) {
-					schedstat_inc(busiest_rq, alb_lost);
-					schedstat_inc(target_rq, alb_gained);
+					schedstat_inc(sd, alb_pushed);
 				} else {
-					schedstat_inc(busiest_rq, alb_failed);
+					schedstat_inc(sd, alb_failed);
 				}
 				spin_unlock(&target_rq->lock);
 			}
@@ -2241,6 +2228,32 @@ DEFINE_PER_CPU(struct kernel_stat, kstat
 EXPORT_PER_CPU_SYMBOL(kstat);
 
 /*
+ * This is called on clock ticks and on context switches.
+ * Bank in p->sched_time the ns elapsed since the last tick or switch.
+ */
+static inline void update_cpu_clock(task_t *p, runqueue_t *rq,
+				    unsigned long long now)
+{
+	unsigned long long last = max(p->timestamp, rq->timestamp_last_tick);
+	p->sched_time += now - last;
+}
+
+/*
+ * Return current->sched_time plus any more ns on the sched_clock
+ * that have not yet been banked.
+ */
+unsigned long long current_sched_time(const task_t *tsk)
+{
+	unsigned long long ns;
+	unsigned long flags;
+	local_irq_save(flags);
+	ns = max(tsk->timestamp, task_rq(tsk)->timestamp_last_tick);
+	ns = tsk->sched_time + (sched_clock() - ns);
+	local_irq_restore(flags);
+	return ns;
+}
+
+/*
  * We place interactive tasks back into the active array, if possible.
  *
  * To guarantee that this does not starve expired tasks we ignore the
@@ -2257,70 +2270,6 @@ EXPORT_PER_CPU_SYMBOL(kstat);
 			((rq)->curr->static_prio > (rq)->best_expired_prio))
 
 /*
- * Do the virtual cpu time signal calculations.
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in user space since the last update
- */
-static inline void account_it_virt(struct task_struct * p, cputime_t cputime)
-{
-	cputime_t it_virt = p->it_virt_value;
-
-	if (cputime_gt(it_virt, cputime_zero) &&
-	    cputime_gt(cputime, cputime_zero)) {
-		if (cputime_ge(cputime, it_virt)) {
-			it_virt = cputime_add(it_virt, p->it_virt_incr);
-			send_sig(SIGVTALRM, p, 1);
-		}
-		it_virt = cputime_sub(it_virt, cputime);
-		p->it_virt_value = it_virt;
-	}
-}
-
-/*
- * Do the virtual profiling signal calculations.
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in user and kernel space since the last update
- */
-static void account_it_prof(struct task_struct *p, cputime_t cputime)
-{
-	cputime_t it_prof = p->it_prof_value;
-
-	if (cputime_gt(it_prof, cputime_zero) &&
-	    cputime_gt(cputime, cputime_zero)) {
-		if (cputime_ge(cputime, it_prof)) {
-			it_prof = cputime_add(it_prof, p->it_prof_incr);
-			send_sig(SIGPROF, p, 1);
-		}
-		it_prof = cputime_sub(it_prof, cputime);
-		p->it_prof_value = it_prof;
-	}
-}
-
-/*
- * Check if the process went over its cputime resource limit after
- * some cpu time got added to utime/stime.
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in user and kernel space since the last update
- */
-static void check_rlimit(struct task_struct *p, cputime_t cputime)
-{
-	cputime_t total, tmp;
-	unsigned long secs;
-
-	total = cputime_add(p->utime, p->stime);
-	secs = cputime_to_secs(total);
-	if (unlikely(secs >= p->signal->rlim[RLIMIT_CPU].rlim_cur)) {
-		/* Send SIGXCPU every second. */
-		tmp = cputime_sub(total, cputime);
-		if (cputime_to_secs(tmp) < secs)
-			send_sig(SIGXCPU, p, 1);
-		/* and SIGKILL when we go over max.. */
-		if (secs >= p->signal->rlim[RLIMIT_CPU].rlim_max)
-			send_sig(SIGKILL, p, 1);
-	}
-}
-
-/*
  * Account user cpu time to a process.
  * @p: the process that the cpu time gets accounted to
  * @hardirq_offset: the offset to subtract from hardirq_count()
@@ -2333,11 +2282,6 @@ void account_user_time(struct task_struc
 
 	p->utime = cputime_add(p->utime, cputime);
 
-	/* Check for signals (SIGVTALRM, SIGPROF, SIGXCPU & SIGKILL). */
-	check_rlimit(p, cputime);
-	account_it_virt(p, cputime);
-	account_it_prof(p, cputime);
-
 	/* Add user time to cpustat. */
 	tmp = cputime_to_cputime64(cputime);
 	if (TASK_NICE(p) > 0)
@@ -2361,12 +2305,6 @@ void account_system_time(struct task_str
 
 	p->stime = cputime_add(p->stime, cputime);
 
-	/* Check for signals (SIGPROF, SIGXCPU & SIGKILL). */
-	if (likely(p->signal && p->exit_state < EXIT_ZOMBIE)) {
-		check_rlimit(p, cputime);
-		account_it_prof(p, cputime);
-	}
-
 	/* Add system time to cpustat. */
 	tmp = cputime_to_cputime64(cputime);
 	if (hardirq_count() - hardirq_offset)
@@ -2379,6 +2317,10 @@ void account_system_time(struct task_str
 		cpustat->iowait = cputime64_add(cpustat->iowait, tmp);
 	else
 		cpustat->idle = cputime64_add(cpustat->idle, tmp);
+	/* Account for system time used */
+	acct_update_integrals(p);
+	/* Update rss highwater mark */
+	update_mem_hiwater(p);
 }
 
 /*
@@ -2414,8 +2356,11 @@ void scheduler_tick(void)
 	int cpu = smp_processor_id();
 	runqueue_t *rq = this_rq();
 	task_t *p = current;
+	unsigned long long now = sched_clock();
+
+	update_cpu_clock(p, rq, now);
 
-	rq->timestamp_last_tick = sched_clock();
+	rq->timestamp_last_tick = now;
 
 	if (p == rq->idle) {
 		if (wake_priority_sleeper(rq))
@@ -2703,9 +2648,11 @@ need_resched_nonpreemptible:
 
 	schedstat_inc(rq, sched_cnt);
 	now = sched_clock();
-	if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG))
+	if (likely((long long)(now - prev->timestamp) < NS_MAX_SLEEP_AVG)) {
 		run_time = now - prev->timestamp;
-	else
+		if (unlikely((long long)(now - prev->timestamp) < 0))
+			run_time = 0;
+	} else
 		run_time = NS_MAX_SLEEP_AVG;
 
 	/*
@@ -2773,8 +2720,7 @@ go_idle:
 		array = rq->active;
 		rq->expired_timestamp = 0;
 		rq->best_expired_prio = MAX_PRIO;
-	} else
-		schedstat_inc(rq, sched_noswitch);
+	}
 
 	idx = sched_find_first_bit(array->bitmap);
 	queue = array->queue + idx;
@@ -2782,6 +2728,8 @@ go_idle:
 
 	if (!rt_task(next) && next->activated > 0) {
 		unsigned long long delta = now - next->timestamp;
+		if (unlikely((long long)(now - next->timestamp) < 0))
+			delta = 0;
 
 		if (next->activated == 1)
 			delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
@@ -2799,6 +2747,8 @@ switch_tasks:
 	clear_tsk_need_resched(prev);
 	rcu_qsctr_inc(task_cpu(prev));
 
+	update_cpu_clock(prev, rq, now);
+
 	prev->sleep_avg -= run_time;
 	if ((long)prev->sleep_avg <= 0)
 		prev->sleep_avg = 0;
@@ -2956,6 +2906,7 @@ static void __wake_up_common(wait_queue_
  * @q: the waitqueue
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: is directly passed to the wakeup function
  */
 void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,
 				int nr_exclusive, void *key)
@@ -2978,7 +2929,7 @@ void fastcall __wake_up_locked(wait_queu
 }
 
 /**
- * __wake_up - sync- wake up threads blocked on a waitqueue.
+ * __wake_up_sync - wake up threads blocked on a waitqueue.
  * @q: the waitqueue
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
@@ -3273,6 +3224,19 @@ out_unlock:
 
 EXPORT_SYMBOL(set_user_nice);
 
+/*
+ * can_nice - check if a task can reduce its nice value
+ * @p: task
+ * @nice: nice value
+ */
+int can_nice(const task_t *p, const int nice)
+{
+	/* convert nice value [19,-20] to rlimit style value [0,39] */
+	int nice_rlim = 19 - nice;
+	return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur ||
+		capable(CAP_SYS_NICE));
+}
+
 #ifdef __ARCH_WANT_SYS_NICE
 
 /*
@@ -3292,12 +3256,8 @@ asmlinkage long sys_nice(int increment)
 	 * We don't have to worry. Conceptually one call occurs first
 	 * and we have a single winner.
 	 */
-	if (increment < 0) {
-		if (!capable(CAP_SYS_NICE))
-			return -EPERM;
-		if (increment < -40)
-			increment = -40;
-	}
+	if (increment < -40)
+		increment = -40;
 	if (increment > 40)
 		increment = 40;
 
@@ -3307,6 +3267,9 @@ asmlinkage long sys_nice(int increment)
 	if (nice > 19)
 		nice = 19;
 
+	if (increment < 0 && !can_nice(current, nice))
+		return -EPERM;
+
 	retval = security_task_setnice(current, nice);
 	if (retval)
 		return retval;
@@ -3422,6 +3385,7 @@ recheck:
 		return -EINVAL;
 
 	if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
+	    param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur &&
 	    !capable(CAP_SYS_NICE))
 		return -EPERM;
 	if ((current->euid != p->euid) && (current->euid != p->uid) &&
@@ -3578,6 +3542,7 @@ long sched_setaffinity(pid_t pid, cpumas
 {
 	task_t *p;
 	int retval;
+	cpumask_t cpus_allowed;
 
 	lock_cpu_hotplug();
 	read_lock(&tasklist_lock);
@@ -3602,6 +3567,8 @@ long sched_setaffinity(pid_t pid, cpumas
 			!capable(CAP_SYS_NICE))
 		goto out_unlock;
 
+	cpus_allowed = cpuset_cpus_allowed(p);
+	cpus_and(new_mask, new_mask, cpus_allowed);
 	retval = set_cpus_allowed(p, new_mask);
 
 out_unlock:
@@ -3788,22 +3755,22 @@ EXPORT_SYMBOL(cond_resched);
  */
 int cond_resched_lock(spinlock_t * lock)
 {
-#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
-	if (lock->break_lock) {
-		lock->break_lock = 0;
+	int ret = 0;
+
+	if (need_lockbreak(lock)) {
 		spin_unlock(lock);
 		cpu_relax();
+		ret = 1;
 		spin_lock(lock);
 	}
-#endif
 	if (need_resched()) {
 		_raw_spin_unlock(lock);
 		preempt_enable_no_resched();
 		__cond_resched();
+		ret = 1;
 		spin_lock(lock);
-		return 1;
 	}
-	return 0;
+	return ret;
 }
 
 EXPORT_SYMBOL(cond_resched_lock);
@@ -4058,6 +4025,7 @@ void __devinit init_idle(task_t *idle, i
 	idle->array = NULL;
 	idle->prio = MAX_PRIO;
 	idle->state = TASK_RUNNING;
+	idle->cpus_allowed = cpumask_of_cpu(cpu);
 	set_task_cpu(idle, cpu);
 
 	spin_lock_irqsave(&rq->lock, flags);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
new file mode 100644
--- /dev/null
+++ b/kernel/seccomp.c
@@ -0,0 +1,56 @@
+/*
+ * linux/kernel/seccomp.c
+ *
+ * Copyright 2004-2005  Andrea Arcangeli <andrea@cpushare.com>
+ *
+ * This defines a simple but solid secure-computing mode.
+ */
+
+#include <linux/seccomp.h>
+#include <linux/sched.h>
+
+/* #define SECCOMP_DEBUG 1 */
+
+/*
+ * Secure computing mode 1 allows only read/write/exit/sigreturn.
+ * To be fully secure this must be combined with rlimit
+ * to limit the stack allocations too.
+ */
+static int mode1_syscalls[] = {
+	__NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
+	0, /* null terminated */
+};
+
+#ifdef TIF_32BIT
+static int mode1_syscalls_32[] = {
+	__NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32,
+	0, /* null terminated */
+};
+#endif
+
+void __secure_computing(int this_syscall)
+{
+	int mode = current->seccomp.mode;
+	int * syscall;
+
+	switch (mode) {
+	case 1:
+		syscall = mode1_syscalls;
+#ifdef TIF_32BIT
+		if (test_thread_flag(TIF_32BIT))
+			syscall = mode1_syscalls_32;
+#endif
+		do {
+			if (*syscall == this_syscall)
+				return;
+		} while (*++syscall);
+		break;
+	default:
+		BUG();
+	}
+
+#ifdef SECCOMP_DEBUG
+	dump_stack();
+#endif
+	do_exit(SIGKILL);
+}
diff --git a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -22,13 +22,13 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/ptrace.h>
+#include <linux/posix-timers.h>
+#include <linux/signal.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/siginfo.h>
 
-extern void k_getrusage(struct task_struct *, int, struct rusage *);
-
 /*
  * SLAB caches for signal bits.
  */
@@ -260,19 +260,23 @@ next_signal(struct sigpending *pending, 
 	return sig;
 }
 
-static struct sigqueue *__sigqueue_alloc(struct task_struct *t, int flags)
+static struct sigqueue *__sigqueue_alloc(struct task_struct *t, unsigned int __nocast flags,
+					 int override_rlimit)
 {
 	struct sigqueue *q = NULL;
 
-	if (atomic_read(&t->user->sigpending) <
+	atomic_inc(&t->user->sigpending);
+	if (override_rlimit ||
+	    atomic_read(&t->user->sigpending) <=
 			t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
 		q = kmem_cache_alloc(sigqueue_cachep, flags);
-	if (q) {
+	if (unlikely(q == NULL)) {
+		atomic_dec(&t->user->sigpending);
+	} else {
 		INIT_LIST_HEAD(&q->list);
 		q->flags = 0;
 		q->lock = NULL;
 		q->user = get_uid(t->user);
-		atomic_inc(&q->user->sigpending);
 	}
 	return(q);
 }
@@ -347,7 +351,9 @@ void __exit_signal(struct task_struct *t
 	if (!atomic_read(&sig->count))
 		BUG();
 	spin_lock(&sighand->siglock);
+	posix_cpu_timers_exit(tsk);
 	if (atomic_dec_and_test(&sig->count)) {
+		posix_cpu_timers_exit_group(tsk);
 		if (tsk == sig->curr_target)
 			sig->curr_target = next_thread(tsk);
 		tsk->signal = NULL;
@@ -381,6 +387,7 @@ void __exit_signal(struct task_struct *t
 		sig->maj_flt += tsk->maj_flt;
 		sig->nvcsw += tsk->nvcsw;
 		sig->nivcsw += tsk->nivcsw;
+		sig->sched_time += tsk->sched_time;
 		spin_unlock(&sighand->siglock);
 		sig = NULL;	/* Marker for below.  */
 	}
@@ -402,6 +409,7 @@ void __exit_signal(struct task_struct *t
 		 * signals are constrained to threads inside the group.
 		 */
 		exit_itimers(sig);
+		exit_thread_group_keys(sig);
 		kmem_cache_free(signal_cachep, sig);
 	}
 }
@@ -514,7 +522,16 @@ static int __dequeue_signal(struct sigpe
 {
 	int sig = 0;
 
-	sig = next_signal(pending, mask);
+	/* SIGKILL must have priority, otherwise it is quite easy
+	 * to create an unkillable process, sending sig < SIGKILL
+	 * to self */
+	if (unlikely(sigismember(&pending->signal, SIGKILL))) {
+		if (!sigismember(mask, SIGKILL))
+			sig = SIGKILL;
+	}
+
+	if (likely(!sig))
+		sig = next_signal(pending, mask);
 	if (sig) {
 		if (current->notifier) {
 			if (sigismember(current->notifier_mask, sig)) {
@@ -564,7 +581,15 @@ int dequeue_signal(struct task_struct *t
 	if ( signr &&
 	     ((info->si_code & __SI_MASK) == __SI_TIMER) &&
 	     info->si_sys_private){
+		/*
+		 * Release the siglock to ensure proper locking order
+		 * of timer locks outside of siglocks.  Note, we leave
+		 * irqs disabled here, since the posix-timers code is
+		 * about to disable them again anyway.
+		 */
+		spin_unlock(&tsk->sighand->siglock);
 		do_schedule_next_timer(info);
+		spin_lock(&tsk->sighand->siglock);
 	}
 	return signr;
 }
@@ -631,7 +656,7 @@ static int check_kill_permission(int sig
 				 struct task_struct *t)
 {
 	int error = -EINVAL;
-	if (sig < 0 || sig > _NSIG)
+	if (!valid_signal(sig))
 		return error;
 	error = -EPERM;
 	if ((!info || ((unsigned long)info != 1 &&
@@ -793,7 +818,9 @@ static int send_signal(int sig, struct s
 	   make sure at least one signal gets delivered and don't
 	   pass on the info struct.  */
 
-	q = __sigqueue_alloc(t, GFP_ATOMIC);
+	q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
+					     ((unsigned long) info < 2 ||
+					      info->si_code >= 0)));
 	if (q) {
 		list_add_tail(&q->list, &signals->list);
 		switch ((unsigned long) info) {
@@ -1036,7 +1063,7 @@ __group_complete_signal(int sig, struct 
 	return;
 }
 
-static int
+int
 __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	int ret = 0;
@@ -1228,7 +1255,7 @@ send_sig_info(int sig, struct siginfo *i
 	 * Make sure legacy kernel users don't send in bad values
 	 * (normal paths check this in check_kill_permission).
 	 */
-	if (sig < 0 || sig > _NSIG)
+	if (!valid_signal(sig))
 		return -EINVAL;
 
 	/*
@@ -1316,7 +1343,7 @@ struct sigqueue *sigqueue_alloc(void)
 {
 	struct sigqueue *q;
 
-	if ((q = __sigqueue_alloc(current, GFP_KERNEL)))
+	if ((q = __sigqueue_alloc(current, GFP_KERNEL, 0)))
 		q->flags |= SIGQUEUE_PREALLOC;
 	return(q);
 }
@@ -1503,7 +1530,7 @@ void do_notify_parent(struct task_struct
 		if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
 			sig = 0;
 	}
-	if (sig > 0 && sig <= _NSIG)
+	if (valid_signal(sig) && sig > 0)
 		__group_send_sig_info(sig, &info, tsk->parent);
 	__wake_up_parent(tsk, tsk->parent);
 	spin_unlock_irqrestore(&psig->siglock, flags);
@@ -1632,8 +1659,6 @@ void ptrace_notify(int exit_code)
 	spin_unlock_irq(&current->sighand->siglock);
 }
 
-#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
-
 static void
 finish_stop(int stop_count)
 {
@@ -1728,6 +1753,7 @@ do_signal_stop(int signr)
 			 * with another processor delivering a stop signal,
 			 * then the SIGCONT that wakes us up should clear it.
 			 */
+			read_unlock(&tasklist_lock);
 			return 0;
 		}
 
@@ -1944,8 +1970,6 @@ relock:
 	return signr;
 }
 
-#endif
-
 EXPORT_SYMBOL(recalc_sigpending);
 EXPORT_SYMBOL_GPL(dequeue_signal);
 EXPORT_SYMBOL(flush_signals);
@@ -2201,6 +2225,8 @@ sys_rt_sigtimedwait(const sigset_t __use
 			current->state = TASK_INTERRUPTIBLE;
 			timeout = schedule_timeout(timeout);
 
+			if (current->flags & PF_FREEZE)
+				refrigerator(PF_FREEZE);
 			spin_lock_irq(&current->sighand->siglock);
 			sig = dequeue_signal(current, &these, &info);
 			current->blocked = current->real_blocked;
@@ -2348,7 +2374,7 @@ do_sigaction(int sig, const struct k_sig
 {
 	struct k_sigaction *k;
 
-	if (sig < 1 || sig > _NSIG || (act && sig_kernel_only(sig)))
+	if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
 		return -EINVAL;
 
 	k = &current->sighand->action[sig-1];
@@ -2432,7 +2458,7 @@ do_sigaltstack (const stack_t __user *us
 		int ss_flags;
 
 		error = -EFAULT;
-		if (verify_area(VERIFY_READ, uss, sizeof(*uss))
+		if (!access_ok(VERIFY_READ, uss, sizeof(*uss))
 		    || __get_user(ss_sp, &uss->ss_sp)
 		    || __get_user(ss_flags, &uss->ss_flags)
 		    || __get_user(ss_size, &uss->ss_size))
diff --git a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -355,8 +355,12 @@ static int ksoftirqd(void * __bind_cpu)
 	set_current_state(TASK_INTERRUPTIBLE);
 
 	while (!kthread_should_stop()) {
-		if (!local_softirq_pending())
+		preempt_disable();
+		if (!local_softirq_pending()) {
+			preempt_enable_no_resched();
 			schedule();
+			preempt_disable();
+		}
 
 		__set_current_state(TASK_RUNNING);
 
@@ -364,14 +368,14 @@ static int ksoftirqd(void * __bind_cpu)
 			/* Preempt disable stops cpu going offline.
 			   If already offline, we'll be on wrong CPU:
 			   don't process */
-			preempt_disable();
 			if (cpu_is_offline((long)__bind_cpu))
 				goto wait_to_die;
 			do_softirq();
-			preempt_enable();
+			preempt_enable_no_resched();
 			cond_resched();
+			preempt_disable();
 		}
-
+		preempt_enable();
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 	__set_current_state(TASK_RUNNING);
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -187,6 +187,7 @@ void __lockfunc _##op##_lock(locktype##_
 			cpu_relax();					\
 		preempt_disable();					\
 	}								\
+	(lock)->break_lock = 0;						\
 }									\
 									\
 EXPORT_SYMBOL(_##op##_lock);						\
@@ -209,6 +210,7 @@ unsigned long __lockfunc _##op##_lock_ir
 			cpu_relax();					\
 		preempt_disable();					\
 	}								\
+	(lock)->break_lock = 0;						\
 	return flags;							\
 }									\
 									\
@@ -292,7 +294,7 @@ EXPORT_SYMBOL(_spin_unlock_irq);
 void __lockfunc _spin_unlock_bh(spinlock_t *lock)
 {
 	_raw_spin_unlock(lock);
-	preempt_enable();
+	preempt_enable_no_resched();
 	local_bh_enable();
 }
 EXPORT_SYMBOL(_spin_unlock_bh);
@@ -316,7 +318,7 @@ EXPORT_SYMBOL(_read_unlock_irq);
 void __lockfunc _read_unlock_bh(rwlock_t *lock)
 {
 	_raw_read_unlock(lock);
-	preempt_enable();
+	preempt_enable_no_resched();
 	local_bh_enable();
 }
 EXPORT_SYMBOL(_read_unlock_bh);
@@ -340,7 +342,7 @@ EXPORT_SYMBOL(_write_unlock_irq);
 void __lockfunc _write_unlock_bh(rwlock_t *lock)
 {
 	_raw_write_unlock(lock);
-	preempt_enable();
+	preempt_enable_no_resched();
 	local_bh_enable();
 }
 EXPORT_SYMBOL(_write_unlock_bh);
@@ -352,7 +354,7 @@ int __lockfunc _spin_trylock_bh(spinlock
 	if (_raw_spin_trylock(lock))
 		return 1;
 
-	preempt_enable();
+	preempt_enable_no_resched();
 	local_bh_enable();
 	return 0;
 }
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -6,6 +6,7 @@
 #include <linux/syscalls.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
+#include <asm/uaccess.h>
 
 /* Since we effect priority and affinity (both of which are visible
  * to, and settable by outside processes) we do indirection via a
@@ -32,7 +33,7 @@ static int stopmachine(void *cpu)
 	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
 
 	/* Ack: we are alive */
-	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
+	smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
 	atomic_inc(&stopmachine_thread_ack);
 
 	/* Simple state machine */
@@ -42,14 +43,14 @@ static int stopmachine(void *cpu)
 			local_irq_disable();
 			irqs_disabled = 1;
 			/* Ack: irqs disabled. */
-			mb(); /* Must read state first. */
+			smp_mb(); /* Must read state first. */
 			atomic_inc(&stopmachine_thread_ack);
 		} else if (stopmachine_state == STOPMACHINE_PREPARE
 			   && !prepared) {
 			/* Everyone is in place, hold CPU. */
 			preempt_disable();
 			prepared = 1;
-			mb(); /* Must read state first. */
+			smp_mb(); /* Must read state first. */
 			atomic_inc(&stopmachine_thread_ack);
 		}
 		/* Yield in first stage: migration threads need to
@@ -61,7 +62,7 @@ static int stopmachine(void *cpu)
 	}
 
 	/* Ack: we are exiting. */
-	mb(); /* Must read state first. */
+	smp_mb(); /* Must read state first. */
 	atomic_inc(&stopmachine_thread_ack);
 
 	if (irqs_disabled)
@@ -76,7 +77,7 @@ static int stopmachine(void *cpu)
 static void stopmachine_set_state(enum stopmachine_state state)
 {
 	atomic_set(&stopmachine_thread_ack, 0);
-	wmb();
+	smp_wmb();
 	stopmachine_state = state;
 	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)
 		cpu_relax();
@@ -86,9 +87,13 @@ static int stop_machine(void)
 {
 	int i, ret = 0;
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+	mm_segment_t old_fs = get_fs();
 
 	/* One high-prio thread per cpu.  We'll do this one. */
-	sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
+	set_fs(KERNEL_DS);
+	sys_sched_setscheduler(current->pid, SCHED_FIFO,
+				(struct sched_param __user *)&param);
+	set_fs(old_fs);
 
 	atomic_set(&stopmachine_thread_ack, 0);
 	stopmachine_num_threads = 0;
diff --git a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -20,10 +20,12 @@
 #include <linux/device.h>
 #include <linux/key.h>
 #include <linux/times.h>
+#include <linux/posix-timers.h>
 #include <linux/security.h>
 #include <linux/dcookies.h>
 #include <linux/suspend.h>
 #include <linux/tty.h>
+#include <linux/signal.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -89,7 +91,7 @@ int cad_pid = 1;
  */
 
 static struct notifier_block *reboot_notifier_list;
-DEFINE_RWLOCK(notifier_lock);
+static DEFINE_RWLOCK(notifier_lock);
 
 /**
  *	notifier_chain_register	- Add notifier to a notifier chain
@@ -216,16 +218,17 @@ int unregister_reboot_notifier(struct no
 }
 
 EXPORT_SYMBOL(unregister_reboot_notifier);
+
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
 	int no_nice;
 
 	if (p->uid != current->euid &&
-		p->uid != current->uid && !capable(CAP_SYS_NICE)) {
+		p->euid != current->euid && !capable(CAP_SYS_NICE)) {
 		error = -EPERM;
 		goto out;
 	}
-	if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) {
+	if (niceval < task_nice(p) && !can_nice(p, niceval)) {
 		error = -EACCES;
 		goto out;
 	}
@@ -523,7 +526,7 @@ asmlinkage long sys_setregid(gid_t rgid,
 	if (new_egid != old_egid)
 	{
 		current->mm->dumpable = 0;
-		wmb();
+		smp_wmb();
 	}
 	if (rgid != (gid_t) -1 ||
 	    (egid != (gid_t) -1 && egid != old_rgid))
@@ -554,7 +557,7 @@ asmlinkage long sys_setgid(gid_t gid)
 		if(old_egid != gid)
 		{
 			current->mm->dumpable=0;
-			wmb();
+			smp_wmb();
 		}
 		current->gid = current->egid = current->sgid = current->fsgid = gid;
 	}
@@ -563,7 +566,7 @@ asmlinkage long sys_setgid(gid_t gid)
 		if(old_egid != gid)
 		{
 			current->mm->dumpable=0;
-			wmb();
+			smp_wmb();
 		}
 		current->egid = current->fsgid = gid;
 	}
@@ -594,7 +597,7 @@ static int set_user(uid_t new_ruid, int 
 	if(dumpclear)
 	{
 		current->mm->dumpable = 0;
-		wmb();
+		smp_wmb();
 	}
 	current->uid = new_ruid;
 	return 0;
@@ -651,7 +654,7 @@ asmlinkage long sys_setreuid(uid_t ruid,
 	if (new_euid != old_euid)
 	{
 		current->mm->dumpable=0;
-		wmb();
+		smp_wmb();
 	}
 	current->fsuid = current->euid = new_euid;
 	if (ruid != (uid_t) -1 ||
@@ -701,7 +704,7 @@ asmlinkage long sys_setuid(uid_t uid)
 	if (old_euid != uid)
 	{
 		current->mm->dumpable = 0;
-		wmb();
+		smp_wmb();
 	}
 	current->fsuid = current->euid = uid;
 	current->suid = new_suid;
@@ -746,7 +749,7 @@ asmlinkage long sys_setresuid(uid_t ruid
 		if (euid != current->euid)
 		{
 			current->mm->dumpable = 0;
-			wmb();
+			smp_wmb();
 		}
 		current->euid = euid;
 	}
@@ -796,7 +799,7 @@ asmlinkage long sys_setresgid(gid_t rgid
 		if (egid != current->egid)
 		{
 			current->mm->dumpable = 0;
-			wmb();
+			smp_wmb();
 		}
 		current->egid = egid;
 	}
@@ -843,7 +846,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
 		if (uid != old_fsuid)
 		{
 			current->mm->dumpable = 0;
-			wmb();
+			smp_wmb();
 		}
 		current->fsuid = uid;
 	}
@@ -873,7 +876,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
 		if (gid != old_fsgid)
 		{
 			current->mm->dumpable = 0;
-			wmb();
+			smp_wmb();
 		}
 		current->fsgid = gid;
 		key_fsgid_changed(current);
@@ -1192,7 +1195,7 @@ static int groups_from_user(struct group
 	return 0;
 }
 
-/* a simple shell-metzner sort */
+/* a simple Shell sort */
 static void groups_sort(struct group_info *group_info)
 {
 	int base, max, stride;
@@ -1501,6 +1504,20 @@ asmlinkage long sys_setrlimit(unsigned i
 	task_lock(current->group_leader);
 	*old_rlim = new_rlim;
 	task_unlock(current->group_leader);
+
+	if (resource == RLIMIT_CPU && new_rlim.rlim_cur != RLIM_INFINITY &&
+	    (cputime_eq(current->signal->it_prof_expires, cputime_zero) ||
+	     new_rlim.rlim_cur <= cputime_to_secs(
+		     current->signal->it_prof_expires))) {
+		cputime_t cputime = secs_to_cputime(new_rlim.rlim_cur);
+		read_lock(&tasklist_lock);
+		spin_lock_irq(&current->sighand->siglock);
+		set_process_cpu_timer(current, CPUCLOCK_PROF,
+				      &cputime, NULL);
+		spin_unlock_irq(&current->sighand->siglock);
+		read_unlock(&tasklist_lock);
+	}
+
 	return 0;
 }
 
@@ -1524,7 +1541,7 @@ asmlinkage long sys_setrlimit(unsigned i
  * given child after it's reaped, or none so this sample is before reaping.
  */
 
-void k_getrusage(struct task_struct *p, int who, struct rusage *r)
+static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
 {
 	struct task_struct *t;
 	unsigned long flags;
@@ -1621,7 +1638,7 @@ asmlinkage long sys_prctl(int option, un
 	switch (option) {
 		case PR_SET_PDEATHSIG:
 			sig = arg2;
-			if (sig < 0 || sig > _NSIG) {
+			if (!valid_signal(sig)) {
 				error = -EINVAL;
 				break;
 			}
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -12,74 +12,76 @@ asmlinkage long sys_ni_syscall(void)
 	return -ENOSYS;
 }
 
-cond_syscall(sys_nfsservctl)
-cond_syscall(sys_quotactl)
-cond_syscall(sys_acct)
-cond_syscall(sys_lookup_dcookie)
-cond_syscall(sys_swapon)
-cond_syscall(sys_swapoff)
-cond_syscall(sys_init_module)
-cond_syscall(sys_delete_module)
-cond_syscall(sys_socketpair)
-cond_syscall(sys_bind)
-cond_syscall(sys_listen)
-cond_syscall(sys_accept)
-cond_syscall(sys_connect)
-cond_syscall(sys_getsockname)
-cond_syscall(sys_getpeername)
-cond_syscall(sys_sendto)
-cond_syscall(sys_send)
-cond_syscall(sys_recvfrom)
-cond_syscall(sys_recv)
-cond_syscall(sys_socket)
-cond_syscall(sys_setsockopt)
-cond_syscall(sys_getsockopt)
-cond_syscall(sys_shutdown)
-cond_syscall(sys_sendmsg)
-cond_syscall(sys_recvmsg)
-cond_syscall(sys_socketcall)
-cond_syscall(sys_futex)
-cond_syscall(compat_sys_futex)
-cond_syscall(sys_epoll_create)
-cond_syscall(sys_epoll_ctl)
-cond_syscall(sys_epoll_wait)
-cond_syscall(sys_semget)
-cond_syscall(sys_semop)
-cond_syscall(sys_semtimedop)
-cond_syscall(sys_semctl)
-cond_syscall(sys_msgget)
-cond_syscall(sys_msgsnd)
-cond_syscall(sys_msgrcv)
-cond_syscall(sys_msgctl)
-cond_syscall(sys_shmget)
-cond_syscall(sys_shmdt)
-cond_syscall(sys_shmctl)
-cond_syscall(sys_mq_open)
-cond_syscall(sys_mq_unlink)
-cond_syscall(sys_mq_timedsend)
-cond_syscall(sys_mq_timedreceive)
-cond_syscall(sys_mq_notify)
-cond_syscall(sys_mq_getsetattr)
-cond_syscall(compat_sys_mq_open)
-cond_syscall(compat_sys_mq_timedsend)
-cond_syscall(compat_sys_mq_timedreceive)
-cond_syscall(compat_sys_mq_notify)
-cond_syscall(compat_sys_mq_getsetattr)
-cond_syscall(sys_mbind)
-cond_syscall(sys_get_mempolicy)
-cond_syscall(sys_set_mempolicy)
-cond_syscall(compat_sys_mbind)
-cond_syscall(compat_sys_get_mempolicy)
-cond_syscall(compat_sys_set_mempolicy)
-cond_syscall(sys_add_key)
-cond_syscall(sys_request_key)
-cond_syscall(sys_keyctl)
-cond_syscall(compat_sys_keyctl)
-cond_syscall(compat_sys_socketcall)
+cond_syscall(sys_nfsservctl);
+cond_syscall(sys_quotactl);
+cond_syscall(sys_acct);
+cond_syscall(sys_lookup_dcookie);
+cond_syscall(sys_swapon);
+cond_syscall(sys_swapoff);
+cond_syscall(sys_init_module);
+cond_syscall(sys_delete_module);
+cond_syscall(sys_socketpair);
+cond_syscall(sys_bind);
+cond_syscall(sys_listen);
+cond_syscall(sys_accept);
+cond_syscall(sys_connect);
+cond_syscall(sys_getsockname);
+cond_syscall(sys_getpeername);
+cond_syscall(sys_sendto);
+cond_syscall(sys_send);
+cond_syscall(sys_recvfrom);
+cond_syscall(sys_recv);
+cond_syscall(sys_socket);
+cond_syscall(sys_setsockopt);
+cond_syscall(sys_getsockopt);
+cond_syscall(sys_shutdown);
+cond_syscall(sys_sendmsg);
+cond_syscall(sys_recvmsg);
+cond_syscall(sys_socketcall);
+cond_syscall(sys_futex);
+cond_syscall(compat_sys_futex);
+cond_syscall(sys_epoll_create);
+cond_syscall(sys_epoll_ctl);
+cond_syscall(sys_epoll_wait);
+cond_syscall(sys_semget);
+cond_syscall(sys_semop);
+cond_syscall(sys_semtimedop);
+cond_syscall(sys_semctl);
+cond_syscall(sys_msgget);
+cond_syscall(sys_msgsnd);
+cond_syscall(sys_msgrcv);
+cond_syscall(sys_msgctl);
+cond_syscall(sys_shmget);
+cond_syscall(sys_shmat);
+cond_syscall(sys_shmdt);
+cond_syscall(sys_shmctl);
+cond_syscall(sys_mq_open);
+cond_syscall(sys_mq_unlink);
+cond_syscall(sys_mq_timedsend);
+cond_syscall(sys_mq_timedreceive);
+cond_syscall(sys_mq_notify);
+cond_syscall(sys_mq_getsetattr);
+cond_syscall(compat_sys_mq_open);
+cond_syscall(compat_sys_mq_timedsend);
+cond_syscall(compat_sys_mq_timedreceive);
+cond_syscall(compat_sys_mq_notify);
+cond_syscall(compat_sys_mq_getsetattr);
+cond_syscall(sys_mbind);
+cond_syscall(sys_get_mempolicy);
+cond_syscall(sys_set_mempolicy);
+cond_syscall(compat_sys_mbind);
+cond_syscall(compat_sys_get_mempolicy);
+cond_syscall(compat_sys_set_mempolicy);
+cond_syscall(sys_add_key);
+cond_syscall(sys_request_key);
+cond_syscall(sys_keyctl);
+cond_syscall(compat_sys_keyctl);
+cond_syscall(compat_sys_socketcall);
 
 /* arch-specific weak syscall entries */
-cond_syscall(sys_pciconfig_read)
-cond_syscall(sys_pciconfig_write)
-cond_syscall(sys_pciconfig_iobase)
-cond_syscall(sys32_ipc)
-cond_syscall(sys32_sysctl)
+cond_syscall(sys_pciconfig_read);
+cond_syscall(sys_pciconfig_write);
+cond_syscall(sys_pciconfig_iobase);
+cond_syscall(sys32_ipc);
+cond_syscall(sys32_sysctl);
+cond_syscall(ppc_rtas);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -121,6 +121,8 @@ extern int sysctl_hz_timer;
 extern int acct_parm[];
 #endif
 
+int randomize_va_space = 1;
+
 static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
 		       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
@@ -632,6 +634,15 @@ static ctl_table kern_table[] = {
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+	{
+		.ctl_name	= KERN_RANDOMIZE,
+		.procname	= "randomize_va_space",
+		.data		= &randomize_va_space,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+
 	{ .ctl_name = 0 }
 };
 
@@ -1366,6 +1377,7 @@ static ssize_t proc_writesys(struct file
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes a string from/to the user buffer. If the kernel
  * buffer provided is not large enough to hold the string, the
@@ -1582,6 +1594,7 @@ static int do_proc_dointvec(ctl_table *t
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
  * values from/to the user buffer, treated as an ASCII string. 
@@ -1686,6 +1699,7 @@ static int do_proc_dointvec_minmax_conv(
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
  * values from/to the user buffer, treated as an ASCII string.
@@ -1818,6 +1832,7 @@ static int do_proc_doulongvec_minmax(ctl
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
  * values from/to the user buffer, treated as an ASCII string.
@@ -1840,6 +1855,7 @@ int proc_doulongvec_minmax(ctl_table *ta
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
  * values from/to the user buffer, treated as an ASCII string. The values
@@ -1930,6 +1946,7 @@ static int do_proc_dointvec_ms_jiffies_c
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
  * values from/to the user buffer, treated as an ASCII string. 
@@ -1974,6 +1991,8 @@ int proc_dointvec_userhz_jiffies(ctl_tab
  * @filp: the file structure
  * @buffer: the user buffer
  * @lenp: the size of the user buffer
+ * @ppos: file position
+ * @ppos: the current position in the file
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
  * values from/to the user buffer, treated as an ASCII string. 
diff --git a/kernel/time.c b/kernel/time.c
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -34,6 +34,7 @@
 #include <linux/syscalls.h>
 #include <linux/security.h>
 #include <linux/fs.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -215,6 +216,14 @@ long pps_stbcnt;		/* stability limit exc
 /* hook for a loadable hardpps kernel module */
 void (*hardpps_ptr)(struct timeval *);
 
+/* we call this to notify the arch when the clock is being
+ * controlled.  If no such arch routine, do nothing.
+ */
+void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+{
+	return;
+}
+
 /* adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
  */
@@ -398,6 +407,7 @@ leave:	if ((time_status & (STA_UNSYNC|ST
 	txc->stbcnt	   = pps_stbcnt;
 	write_sequnlock_irq(&xtime_lock);
 	do_gettimeofday(&txc->time);
+	notify_arch_cmos_timer();
 	return(result);
 }
 
@@ -494,6 +504,7 @@ void getnstimeofday (struct timespec *tv
 	tv->tv_sec = sec;
 	tv->tv_nsec = nsec;
 }
+EXPORT_SYMBOL_GPL(getnstimeofday);
 
 int do_settimeofday (struct timespec *tv)
 {
@@ -505,14 +516,6 @@ int do_settimeofday (struct timespec *tv
 
 	write_seqlock_irq(&xtime_lock);
 	{
-		/*
-		 * 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!
-		 */
-		nsec -= time_interpolator_get_offset();
-
 		wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
 		wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
 
diff --git a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -30,6 +30,7 @@
 #include <linux/thread_info.h>
 #include <linux/time.h>
 #include <linux/jiffies.h>
+#include <linux/posix-timers.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
 
@@ -48,8 +49,9 @@ static void time_interpolator_update(lon
 /*
  * per-CPU timer vector definitions:
  */
-#define TVN_BITS 6
-#define TVR_BITS 8
+
+#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
+#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
 #define TVN_SIZE (1 << TVN_BITS)
 #define TVR_SIZE (1 << TVR_BITS)
 #define TVN_MASK (TVN_SIZE - 1)
@@ -587,10 +589,10 @@ long time_tolerance = MAXFREQ;		/* frequ
 long time_precision = 1;		/* clock precision (us)		*/
 long time_maxerror = NTP_PHASE_LIMIT;	/* maximum error (us)		*/
 long time_esterror = NTP_PHASE_LIMIT;	/* estimated error (us)		*/
-long time_phase;			/* phase offset (scaled us)	*/
+static long time_phase;			/* phase offset (scaled us)	*/
 long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC;
 					/* frequency offset (scaled ppm)*/
-long time_adj;				/* tick adjust (scaled 1 / HZ)	*/
+static long time_adj;			/* tick adjust (scaled 1 / HZ)	*/
 long time_reftime;			/* time at last adjustment (s)	*/
 long time_adjust;
 long time_next_adjust;
@@ -824,6 +826,7 @@ void update_process_times(int user_tick)
 	if (rcu_pending(cpu))
 		rcu_check_callbacks(cpu, user_tick);
 	scheduler_tick();
+ 	run_posix_cpu_timers(p);
 }
 
 /*
@@ -844,6 +847,8 @@ static unsigned long count_active_tasks(
  */
 unsigned long avenrun[3];
 
+EXPORT_SYMBOL(avenrun);
+
 /*
  * calc_load - given tick count, update the avenrun load estimates.
  * This is called while holding a write_lock on xtime_lock.
@@ -1002,7 +1007,7 @@ asmlinkage long sys_getppid(void)
 		 * Make sure we read the pid before re-reading the
 		 * parent pointer:
 		 */
-		rmb();
+		smp_rmb();
 		parent = me->group_leader->real_parent;
 		if (old != parent)
 			continue;
diff --git a/kernel/user.c b/kernel/user.c
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -18,7 +18,8 @@
  * UID task count cache, to get fast user lookup in "alloc_uid"
  * when changing user ID's (ie setuid() and friends).
  */
-#define UIDHASH_BITS		8
+
+#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8)
 #define UIDHASH_SZ		(1 << UIDHASH_BITS)
 #define UIDHASH_MASK		(UIDHASH_SZ - 1)
 #define __uidhashfn(uid)	(((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -423,6 +423,31 @@ void flush_scheduled_work(void)
 	flush_workqueue(keventd_wq);
 }
 
+/**
+ * cancel_rearming_delayed_workqueue - reliably kill off a delayed
+ *			work whose handler rearms the delayed work.
+ * @wq:   the controlling workqueue structure
+ * @work: the delayed work struct
+ */
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+				       struct work_struct *work)
+{
+	while (!cancel_delayed_work(work))
+		flush_workqueue(wq);
+}
+EXPORT_SYMBOL(cancel_rearming_delayed_workqueue);
+
+/**
+ * cancel_rearming_delayed_work - reliably kill off a delayed keventd
+ *			work whose handler rearms the delayed work.
+ * @work: the delayed work struct
+ */
+void cancel_rearming_delayed_work(struct work_struct *work)
+{
+	cancel_rearming_delayed_workqueue(keventd_wq, work);
+}
+EXPORT_SYMBOL(cancel_rearming_delayed_work);
+
 int keventd_up(void)
 {
 	return keventd_wq != NULL;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1,14 +1,23 @@
 
+config PRINTK_TIME
+	bool "Show timing information on printks"
+	help
+	  Selecting this option causes timing information to be
+	  included in printk output.  This allows you to measure
+	  the interval between kernel operations, including bootup
+	  operations.  This is useful for identifying long delays
+	  in kernel startup.
+
+
 config DEBUG_KERNEL
 	bool "Kernel debugging"
-	depends on (ALPHA || ARM || CRIS || H8300 || X86 || IA64 || M32R || M68K || M68KNOMMU || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SUPERH || SUPERH64 || SPARC32 || SPARC64 || USERMODE || V850 || X86_64)
 	help
 	  Say Y here if you are developing drivers or trying to debug and
 	  identify kernel problems.
 
 config MAGIC_SYSRQ
 	bool "Magic SysRq key"
-	depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SUPERH || SUPERH64 || SPARC32 || SPARC64 || X86_64 || USERMODE)
+	depends on DEBUG_KERNEL && !UML
 	help
 	  If you say Y here, you will have some control over the system even
 	  if the system crashes for example during kernel debugging (e.g., you
@@ -20,12 +29,22 @@ config MAGIC_SYSRQ
 	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
 	  unless you really know what this hack does.
 
-config MAGIC_SYSRQ
-	bool "Magic SysRq key"
-	depends on DEBUG_KERNEL && (H8300 || M68KNOMMU || V850)
-	help
-	  Enables console device to interpret special characters as
-	  commands to dump state information.
+config LOG_BUF_SHIFT
+	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
+	range 12 21
+	default 17 if ARCH_S390
+	default 16 if X86_NUMAQ || IA64
+	default 15 if SMP
+	default 14
+	help
+	  Select kernel log buffer size as a power of 2.
+	  Defaults and Examples:
+	  	     17 => 128 KB for S/390
+		     16 => 64 KB for x86 NUMAQ or IA-64
+	             15 => 32 KB for SMP
+	             14 => 16 KB for uniprocessor
+		     13 =>  8 KB
+		     12 =>  4 KB
 
 config SCHEDSTATS
 	bool "Collect scheduler statistics"
@@ -41,7 +60,7 @@ config SCHEDSTATS
 
 config DEBUG_SLAB
 	bool "Debug memory allocations"
-	depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64 || USERMODE || X86_64)
+	depends on DEBUG_KERNEL
 	help
 	  Say Y here to have the kernel do limited verification on memory
 	  allocation as well as poisoning memory on free to catch use of freed
@@ -49,7 +68,7 @@ config DEBUG_SLAB
 
 config DEBUG_PREEMPT
 	bool "Debug preemptible kernel"
-	depends on PREEMPT
+	depends on DEBUG_KERNEL && PREEMPT
 	default y
 	help
 	  If you say Y here then the kernel will use a debug variant of the
@@ -59,7 +78,7 @@ config DEBUG_PREEMPT
 
 config DEBUG_SPINLOCK
 	bool "Spinlock debugging"
-	depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || MIPS || PARISC || PPC32 || (SUPERH && !SUPERH64) || SPARC32 || SPARC64 || USERMODE || X86_64)
+	depends on DEBUG_KERNEL
 	help
 	  Say Y here and build SMP to catch missing spinlock initialization
 	  and certain other kinds of spinlock errors commonly made.  This is
@@ -68,7 +87,7 @@ config DEBUG_SPINLOCK
 
 config DEBUG_SPINLOCK_SLEEP
 	bool "Sleep-inside-spinlock checking"
-	depends on DEBUG_KERNEL && (X86 || IA64 || M32R || MIPS || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64 || USERMODE)
+	depends on DEBUG_KERNEL
 	help
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.
@@ -82,14 +101,15 @@ config DEBUG_KOBJECT
 
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
-	depends on DEBUG_KERNEL && HIGHMEM && (X86 || PPC32 || MIPS || SPARC32)
+	depends on DEBUG_KERNEL && HIGHMEM
 	help
 	  This options enables addition error checking for high memory systems.
 	  Disable for production systems.
 
 config DEBUG_BUGVERBOSE
 	bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
-	depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || (X86 && !X86_64)
+	depends on BUG
+	depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || (X86 && !X86_64) || FRV
 	default !EMBEDDED
 	help
 	  Say Y here to make BUG() panics output the file name and line number
@@ -98,24 +118,13 @@ config DEBUG_BUGVERBOSE
 
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
-	depends on DEBUG_KERNEL && (ALPHA || CRIS || X86 || IA64 || M32R || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || (SUPERH && !SUPERH64) || SPARC64 || V850 || X86_64)
+	depends on DEBUG_KERNEL
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
-	  Say Y here only if you plan to use gdb to debug the kernel.
-	  If you don't debug the kernel, you can say N.
+	  Say Y here only if you plan to debug the kernel.
 
-config DEBUG_INFO
-	bool "Enable kernel debugging symbols"
-	depends on DEBUG_KERNEL && USERMODE
-	help
-        When this is enabled, the User-Mode Linux binary will include
-        debugging symbols.  This enlarges the binary by a few megabytes,
-        but aids in tracking down kernel problems in UML.  It is required
-        if you intend to do any kernel development.
-
-        If you're truly short on disk space or don't expect to report any
-        bugs back to the UML developers, say N, otherwise say Y.
+	  If unsure, say N.
 
 config DEBUG_IOREMAP
 	bool "Enable ioremap() debugging"
@@ -140,13 +149,13 @@ config DEBUG_FS
 
 	  If unsure, say N.
 
-if !X86_64
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
-	depends on X86 || CRIS || M68KNOMMU
+	depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML)
+	default y if DEBUG_INFO && UML
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
 	  and slower, but it will give very useful debugging information.
 	  If you don't debug the kernel, you can say N, but we may not be able
 	  to solve problems without frame pointers.
-endif
+
diff --git a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,8 +4,11 @@
 
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
 	 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
-	 kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
-	 bitmap.o extable.o kobject_uevent.o prio_tree.o
+	 kobject.o kref.o idr.o div64.o int_sqrt.o \
+	 bitmap.o extable.o kobject_uevent.o prio_tree.o sha1.o \
+	 halfmd4.o
+
+obj-y += sort.o parser.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/bitmap.c b/lib/bitmap.c
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -291,6 +291,7 @@ EXPORT_SYMBOL(__bitmap_weight);
 #define nbits_to_hold_value(val)	fls(val)
 #define roundup_power2(val,modulus)	(((val) + (modulus) - 1) & ~((modulus) - 1))
 #define unhex(c)			(isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
+#define BASEDEC 10		/* fancier cpuset lists input in decimal */
 
 /**
  * bitmap_scnprintf - convert bitmap to an ASCII hex string.
@@ -409,6 +410,108 @@ int bitmap_parse(const char __user *ubuf
 }
 EXPORT_SYMBOL(bitmap_parse);
 
+/*
+ * bscnl_emit(buf, buflen, rbot, rtop, bp)
+ *
+ * Helper routine for bitmap_scnlistprintf().  Write decimal number
+ * or range to buf, suppressing output past buf+buflen, with optional
+ * comma-prefix.  Return len of what would be written to buf, if it
+ * all fit.
+ */
+static inline int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len)
+{
+	if (len > 0)
+		len += scnprintf(buf + len, buflen - len, ",");
+	if (rbot == rtop)
+		len += scnprintf(buf + len, buflen - len, "%d", rbot);
+	else
+		len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop);
+	return len;
+}
+
+/**
+ * bitmap_scnlistprintf - convert bitmap to list format ASCII string
+ * @buf: byte buffer into which string is placed
+ * @buflen: reserved size of @buf, in bytes
+ * @maskp: pointer to bitmap to convert
+ * @nmaskbits: size of bitmap, in bits
+ *
+ * Output format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.  Output format is compatible with the format
+ * accepted as input by bitmap_parselist().
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing '\0', as
+ * per ISO C99.
+ */
+int bitmap_scnlistprintf(char *buf, unsigned int buflen,
+	const unsigned long *maskp, int nmaskbits)
+{
+	int len = 0;
+	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
+	int cur, rbot, rtop;
+
+	rbot = cur = find_first_bit(maskp, nmaskbits);
+	while (cur < nmaskbits) {
+		rtop = cur;
+		cur = find_next_bit(maskp, nmaskbits, cur+1);
+		if (cur >= nmaskbits || cur > rtop + 1) {
+			len = bscnl_emit(buf, buflen, rbot, rtop, len);
+			rbot = cur;
+		}
+	}
+	return len;
+}
+EXPORT_SYMBOL(bitmap_scnlistprintf);
+
+/**
+ * bitmap_parselist - convert list format ASCII string to bitmap
+ * @buf: read nul-terminated user string from this buffer
+ * @mask: write resulting mask here
+ * @nmaskbits: number of bits in mask to be written
+ *
+ * Input format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.
+ *
+ * Returns 0 on success, -errno on invalid input strings:
+ *    -EINVAL:   second number in range smaller than first
+ *    -EINVAL:   invalid character in string
+ *    -ERANGE:   bit number specified too large for mask
+ */
+int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+{
+	unsigned a, b;
+
+	bitmap_zero(maskp, nmaskbits);
+	do {
+		if (!isdigit(*bp))
+			return -EINVAL;
+		b = a = simple_strtoul(bp, (char **)&bp, BASEDEC);
+		if (*bp == '-') {
+			bp++;
+			if (!isdigit(*bp))
+				return -EINVAL;
+			b = simple_strtoul(bp, (char **)&bp, BASEDEC);
+		}
+		if (!(a <= b))
+			return -EINVAL;
+		if (b >= nmaskbits)
+			return -ERANGE;
+		while (a <= b) {
+			set_bit(a, maskp);
+			a++;
+		}
+		if (*bp == ',')
+			bp++;
+	} while (*bp != '\0' && *bp != '\n');
+	return 0;
+}
+EXPORT_SYMBOL(bitmap_parselist);
+
 /**
  *	bitmap_find_free_region - find a contiguous aligned mem region
  *	@bitmap: an array of unsigned longs corresponding to the bitmap
diff --git a/lib/extable.c b/lib/extable.c
--- a/lib/extable.c
+++ b/lib/extable.c
@@ -13,6 +13,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sort.h>
 #include <asm/uaccess.h>
 
 extern struct exception_table_entry __start___ex_table[];
@@ -25,26 +26,23 @@ extern struct exception_table_entry __st
  * This is used both for the kernel exception table and for
  * the exception tables of modules that get loaded.
  */
+static int cmp_ex(const void *a, const void *b)
+{
+	const struct exception_table_entry *x = a, *y = b;
+
+	/* avoid overflow */
+	if (x->insn > y->insn)
+		return 1;
+	if (x->insn < y->insn)
+		return -1;
+	return 0;
+}
+
 void sort_extable(struct exception_table_entry *start,
 		  struct exception_table_entry *finish)
 {
-	struct exception_table_entry el, *p, *q;
-
-	/* insertion sort */
-	for (p = start + 1; p < finish; ++p) {
-		/* start .. p-1 is sorted */
-		if (p[0].insn < p[-1].insn) {
-			/* move element p down to its right place */
-			el = *p;
-			q = p;
-			do {
-				/* el comes before q[-1], move q[-1] up one */
-				q[0] = q[-1];
-				--q;
-			} while (q > start && el.insn < q[-1].insn);
-			*q = el;
-		}
-	}
+	sort(start, finish - start, sizeof(struct exception_table_entry),
+	     cmp_ex, NULL);
 }
 #endif
 
diff --git a/lib/halfmd4.c b/lib/halfmd4.c
new file mode 100644
--- /dev/null
+++ b/lib/halfmd4.c
@@ -0,0 +1,66 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cryptohash.h>
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function.  The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s)	\
+	(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
+ */
+__u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
+{
+	__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[0] + K1,  3);
+	ROUND(F, d, a, b, c, in[1] + K1,  7);
+	ROUND(F, c, d, a, b, in[2] + K1, 11);
+	ROUND(F, b, c, d, a, in[3] + K1, 19);
+	ROUND(F, a, b, c, d, in[4] + K1,  3);
+	ROUND(F, d, a, b, c, in[5] + K1,  7);
+	ROUND(F, c, d, a, b, in[6] + K1, 11);
+	ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[1] + K2,  3);
+	ROUND(G, d, a, b, c, in[3] + K2,  5);
+	ROUND(G, c, d, a, b, in[5] + K2,  9);
+	ROUND(G, b, c, d, a, in[7] + K2, 13);
+	ROUND(G, a, b, c, d, in[0] + K2,  3);
+	ROUND(G, d, a, b, c, in[2] + K2,  5);
+	ROUND(G, c, d, a, b, in[4] + K2,  9);
+	ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[3] + K3,  3);
+	ROUND(H, d, a, b, c, in[7] + K3,  9);
+	ROUND(H, c, d, a, b, in[2] + K3, 11);
+	ROUND(H, b, c, d, a, in[6] + K3, 15);
+	ROUND(H, a, b, c, d, in[1] + K3,  3);
+	ROUND(H, d, a, b, c, in[5] + K3,  9);
+	ROUND(H, c, d, a, b, in[0] + K3, 11);
+	ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+
+	return buf[1]; /* "most hashed" word */
+}
+EXPORT_SYMBOL(half_md4_transform);
diff --git a/lib/iomap.c b/lib/iomap.c
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -58,13 +58,23 @@ unsigned int fastcall ioread16(void __io
 {
 	IO_COND(addr, return inw(port), return readw(addr));
 }
+unsigned int fastcall ioread16be(void __iomem *addr)
+{
+	IO_COND(addr, return inw(port), return be16_to_cpu(__raw_readw(addr)));
+}
 unsigned int fastcall ioread32(void __iomem *addr)
 {
 	IO_COND(addr, return inl(port), return readl(addr));
 }
+unsigned int fastcall ioread32be(void __iomem *addr)
+{
+	IO_COND(addr, return inl(port), return be32_to_cpu(__raw_readl(addr)));
+}
 EXPORT_SYMBOL(ioread8);
 EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread16be);
 EXPORT_SYMBOL(ioread32);
+EXPORT_SYMBOL(ioread32be);
 
 void fastcall iowrite8(u8 val, void __iomem *addr)
 {
@@ -74,13 +84,23 @@ void fastcall iowrite16(u16 val, void __
 {
 	IO_COND(addr, outw(val,port), writew(val, addr));
 }
+void fastcall iowrite16be(u16 val, void __iomem *addr)
+{
+	IO_COND(addr, outw(val,port), __raw_writew(cpu_to_be16(val), addr));
+}
 void fastcall iowrite32(u32 val, void __iomem *addr)
 {
 	IO_COND(addr, outl(val,port), writel(val, addr));
 }
+void fastcall iowrite32be(u32 val, void __iomem *addr)
+{
+	IO_COND(addr, outl(val,port), __raw_writel(cpu_to_be32(val), addr));
+}
 EXPORT_SYMBOL(iowrite8);
 EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite16be);
 EXPORT_SYMBOL(iowrite32);
+EXPORT_SYMBOL(iowrite32be);
 
 /*
  * These are the "repeat MMIO read/write" functions.
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
--- a/lib/kernel_lock.c
+++ b/lib/kernel_lock.c
@@ -79,7 +79,7 @@ EXPORT_SYMBOL(smp_processor_id);
  *
  * Don't use in new code.
  */
-DECLARE_MUTEX(kernel_sem);
+static DECLARE_MUTEX(kernel_sem);
 
 /*
  * Re-acquire the kernel semaphore.
diff --git a/lib/kobject.c b/lib/kobject.c
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -140,9 +140,9 @@ void kobject_init(struct kobject * kobj)
 static void unlink(struct kobject * kobj)
 {
 	if (kobj->kset) {
-		down_write(&kobj->kset->subsys->rwsem);
+		spin_lock(&kobj->kset->list_lock);
 		list_del_init(&kobj->entry);
-		up_write(&kobj->kset->subsys->rwsem);
+		spin_unlock(&kobj->kset->list_lock);
 	}
 	kobject_put(kobj);
 }
@@ -168,13 +168,13 @@ int kobject_add(struct kobject * kobj)
 		 kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
 
 	if (kobj->kset) {
-		down_write(&kobj->kset->subsys->rwsem);
+		spin_lock(&kobj->kset->list_lock);
 
 		if (!parent)
 			parent = kobject_get(&kobj->kset->kobj);
 
 		list_add_tail(&kobj->entry,&kobj->kset->list);
-		up_write(&kobj->kset->subsys->rwsem);
+		spin_unlock(&kobj->kset->list_lock);
 	}
 	kobj->parent = parent;
 
@@ -184,8 +184,6 @@ int kobject_add(struct kobject * kobj)
 		unlink(kobj);
 		if (parent)
 			kobject_put(parent);
-	} else {
-		kobject_hotplug(kobj, KOBJ_ADD);
 	}
 
 	return error;
@@ -207,7 +205,8 @@ int kobject_register(struct kobject * ko
 			printk("kobject_register failed for %s (%d)\n",
 			       kobject_name(kobj),error);
 			dump_stack();
-		}
+		} else
+			kobject_hotplug(kobj, KOBJ_ADD);
 	} else
 		error = -EINVAL;
 	return error;
@@ -217,13 +216,12 @@ int kobject_register(struct kobject * ko
 /**
  *	kobject_set_name - Set the name of an object
  *	@kobj:	object.
- *	@name:	name. 
+ *	@fmt:	format string used to build the name
  *
  *	If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated
  *	string that @kobj->k_name points to. Otherwise, use the static 
  *	@kobj->name array.
  */
-
 int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
 {
 	int error = 0;
@@ -301,7 +299,6 @@ int kobject_rename(struct kobject * kobj
 
 void kobject_del(struct kobject * kobj)
 {
-	kobject_hotplug(kobj, KOBJ_REMOVE);
 	sysfs_remove_dir(kobj);
 	unlink(kobj);
 }
@@ -314,6 +311,7 @@ void kobject_del(struct kobject * kobj)
 void kobject_unregister(struct kobject * kobj)
 {
 	pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
+	kobject_hotplug(kobj, KOBJ_REMOVE);
 	kobject_del(kobj);
 	kobject_put(kobj);
 }
@@ -380,6 +378,7 @@ void kset_init(struct kset * k)
 {
 	kobject_init(&k->kobj);
 	INIT_LIST_HEAD(&k->list);
+	spin_lock_init(&k->list_lock);
 }
 
 
@@ -444,7 +443,7 @@ struct kobject * kset_find_obj(struct ks
 	struct list_head * entry;
 	struct kobject * ret = NULL;
 
-	down_read(&kset->subsys->rwsem);
+	spin_lock(&kset->list_lock);
 	list_for_each(entry,&kset->list) {
 		struct kobject * k = to_kobj(entry);
 		if (kobject_name(k) && !strcmp(kobject_name(k),name)) {
@@ -452,7 +451,7 @@ struct kobject * kset_find_obj(struct ks
 			break;
 		}
 	}
-	up_read(&kset->subsys->rwsem);
+	spin_unlock(&kset->list_lock);
 	return ret;
 }
 
@@ -524,7 +523,6 @@ void subsys_remove_file(struct subsystem
 	}
 }
 
-EXPORT_SYMBOL(kobject_get_path);
 EXPORT_SYMBOL(kobject_init);
 EXPORT_SYMBOL(kobject_register);
 EXPORT_SYMBOL(kobject_unregister);
@@ -532,7 +530,6 @@ EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
 EXPORT_SYMBOL(kobject_add);
 EXPORT_SYMBOL(kobject_del);
-EXPORT_SYMBOL(kobject_rename);
 
 EXPORT_SYMBOL(kset_register);
 EXPORT_SYMBOL(kset_unregister);
diff --git a/lib/kref.c b/lib/kref.c
--- a/lib/kref.c
+++ b/lib/kref.c
@@ -42,14 +42,21 @@ void kref_get(struct kref *kref)
  *	     in as this function.
  *
  * Decrement the refcount, and if 0, call release().
+ * Return 1 if the object was removed, otherwise return 0.  Beware, if this
+ * function returns 0, you still can not count on the kref from remaining in
+ * memory.  Only use the return value if you want to see if the kref is now
+ * gone, not present.
  */
-void kref_put(struct kref *kref, void (*release) (struct kref *kref))
+int kref_put(struct kref *kref, void (*release)(struct kref *kref))
 {
 	WARN_ON(release == NULL);
 	WARN_ON(release == (void (*)(struct kref *))kfree);
 
-	if (atomic_dec_and_test(&kref->refcount))
+	if (atomic_dec_and_test(&kref->refcount)) {
 		release(kref);
+		return 1;
+	}
+	return 0;
 }
 
 EXPORT_SYMBOL(kref_init);
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
--- a/lib/rwsem-spinlock.c
+++ b/lib/rwsem-spinlock.c
@@ -76,7 +76,7 @@ __rwsem_do_wake(struct rw_semaphore *sem
 		list_del(&waiter->list);
 		tsk = waiter->task;
 		/* Don't touch waiter after ->task has been NULLed */
-		mb();
+		smp_mb();
 		waiter->task = NULL;
 		wake_up_process(tsk);
 		put_task_struct(tsk);
@@ -91,7 +91,7 @@ __rwsem_do_wake(struct rw_semaphore *sem
 
 		list_del(&waiter->list);
 		tsk = waiter->task;
-		mb();
+		smp_mb();
 		waiter->task = NULL;
 		wake_up_process(tsk);
 		put_task_struct(tsk);
@@ -123,7 +123,7 @@ __rwsem_wake_one_writer(struct rw_semaph
 	list_del(&waiter->list);
 
 	tsk = waiter->task;
-	mb();
+	smp_mb();
 	waiter->task = NULL;
 	wake_up_process(tsk);
 	put_task_struct(tsk);
@@ -140,12 +140,12 @@ void fastcall __sched __down_read(struct
 
 	rwsemtrace(sem, "Entering __down_read");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irq(&sem->wait_lock);
 
 	if (sem->activity >= 0 && list_empty(&sem->wait_list)) {
 		/* granted */
 		sem->activity++;
-		spin_unlock(&sem->wait_lock);
+		spin_unlock_irq(&sem->wait_lock);
 		goto out;
 	}
 
@@ -160,7 +160,7 @@ void fastcall __sched __down_read(struct
 	list_add_tail(&waiter.list, &sem->wait_list);
 
 	/* we don't need to touch the semaphore struct anymore */
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irq(&sem->wait_lock);
 
 	/* wait to be given the lock */
 	for (;;) {
@@ -181,10 +181,12 @@ void fastcall __sched __down_read(struct
  */
 int fastcall __down_read_trylock(struct rw_semaphore *sem)
 {
+	unsigned long flags;
 	int ret = 0;
+
 	rwsemtrace(sem, "Entering __down_read_trylock");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	if (sem->activity >= 0 && list_empty(&sem->wait_list)) {
 		/* granted */
@@ -192,7 +194,7 @@ int fastcall __down_read_trylock(struct 
 		ret = 1;
 	}
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving __down_read_trylock");
 	return ret;
@@ -209,12 +211,12 @@ void fastcall __sched __down_write(struc
 
 	rwsemtrace(sem, "Entering __down_write");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irq(&sem->wait_lock);
 
 	if (sem->activity == 0 && list_empty(&sem->wait_list)) {
 		/* granted */
 		sem->activity = -1;
-		spin_unlock(&sem->wait_lock);
+		spin_unlock_irq(&sem->wait_lock);
 		goto out;
 	}
 
@@ -229,7 +231,7 @@ void fastcall __sched __down_write(struc
 	list_add_tail(&waiter.list, &sem->wait_list);
 
 	/* we don't need to touch the semaphore struct anymore */
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irq(&sem->wait_lock);
 
 	/* wait to be given the lock */
 	for (;;) {
@@ -250,10 +252,12 @@ void fastcall __sched __down_write(struc
  */
 int fastcall __down_write_trylock(struct rw_semaphore *sem)
 {
+	unsigned long flags;
 	int ret = 0;
+
 	rwsemtrace(sem, "Entering __down_write_trylock");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	if (sem->activity == 0 && list_empty(&sem->wait_list)) {
 		/* granted */
@@ -261,7 +265,7 @@ int fastcall __down_write_trylock(struct
 		ret = 1;
 	}
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving __down_write_trylock");
 	return ret;
@@ -272,14 +276,16 @@ int fastcall __down_write_trylock(struct
  */
 void fastcall __up_read(struct rw_semaphore *sem)
 {
+	unsigned long flags;
+
 	rwsemtrace(sem, "Entering __up_read");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	if (--sem->activity == 0 && !list_empty(&sem->wait_list))
 		sem = __rwsem_wake_one_writer(sem);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving __up_read");
 }
@@ -289,15 +295,17 @@ void fastcall __up_read(struct rw_semaph
  */
 void fastcall __up_write(struct rw_semaphore *sem)
 {
+	unsigned long flags;
+
 	rwsemtrace(sem, "Entering __up_write");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	sem->activity = 0;
 	if (!list_empty(&sem->wait_list))
 		sem = __rwsem_do_wake(sem, 1);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving __up_write");
 }
@@ -308,15 +316,17 @@ void fastcall __up_write(struct rw_semap
  */
 void fastcall __downgrade_write(struct rw_semaphore *sem)
 {
+	unsigned long flags;
+
 	rwsemtrace(sem, "Entering __downgrade_write");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	sem->activity = 1;
 	if (!list_empty(&sem->wait_list))
 		sem = __rwsem_do_wake(sem, 0);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving __downgrade_write");
 }
diff --git a/lib/rwsem.c b/lib/rwsem.c
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -74,7 +74,7 @@ __rwsem_do_wake(struct rw_semaphore *sem
 	 */
 	list_del(&waiter->list);
 	tsk = waiter->task;
-	mb();
+	smp_mb();
 	waiter->task = NULL;
 	wake_up_process(tsk);
 	put_task_struct(tsk);
@@ -117,7 +117,7 @@ __rwsem_do_wake(struct rw_semaphore *sem
 		waiter = list_entry(next, struct rwsem_waiter, list);
 		next = waiter->list.next;
 		tsk = waiter->task;
-		mb();
+		smp_mb();
 		waiter->task = NULL;
 		wake_up_process(tsk);
 		put_task_struct(tsk);
@@ -150,7 +150,7 @@ rwsem_down_failed_common(struct rw_semap
 	set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 
 	/* set up my own style of waitqueue */
-	spin_lock(&sem->wait_lock);
+	spin_lock_irq(&sem->wait_lock);
 	waiter->task = tsk;
 	get_task_struct(tsk);
 
@@ -163,7 +163,7 @@ rwsem_down_failed_common(struct rw_semap
 	if (!(count & RWSEM_ACTIVE_MASK))
 		sem = __rwsem_do_wake(sem, 0);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irq(&sem->wait_lock);
 
 	/* wait to be given the lock */
 	for (;;) {
@@ -219,15 +219,17 @@ rwsem_down_write_failed(struct rw_semaph
  */
 struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem)
 {
+	unsigned long flags;
+
 	rwsemtrace(sem, "Entering rwsem_wake");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	/* do nothing if list empty */
 	if (!list_empty(&sem->wait_list))
 		sem = __rwsem_do_wake(sem, 0);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving rwsem_wake");
 
@@ -241,15 +243,17 @@ struct rw_semaphore fastcall *rwsem_wake
  */
 struct rw_semaphore fastcall *rwsem_downgrade_wake(struct rw_semaphore *sem)
 {
+	unsigned long flags;
+
 	rwsemtrace(sem, "Entering rwsem_downgrade_wake");
 
-	spin_lock(&sem->wait_lock);
+	spin_lock_irqsave(&sem->wait_lock, flags);
 
 	/* do nothing if list empty */
 	if (!list_empty(&sem->wait_list))
 		sem = __rwsem_do_wake(sem, 1);
 
-	spin_unlock(&sem->wait_lock);
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
 
 	rwsemtrace(sem, "Leaving rwsem_downgrade_wake");
 	return sem;
diff --git a/lib/sha1.c b/lib/sha1.c
new file mode 100644
--- /dev/null
+++ b/lib/sha1.c
@@ -0,0 +1,96 @@
+/*
+ * SHA transform algorithm, originally taken from code written by
+ * Peter Gutmann, and placed in the public domain.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cryptohash.h>
+
+/* The SHA f()-functions.  */
+
+#define f1(x,y,z)   (z ^ (x & (y ^ z)))		/* x ? y : z */
+#define f2(x,y,z)   (x ^ y ^ z)			/* XOR */
+#define f3(x,y,z)   ((x & y) + (z & (x ^ y)))	/* majority */
+
+/* The SHA Mysterious Constants */
+
+#define K1  0x5A827999L			/* Rounds  0-19: sqrt(2) * 2^30 */
+#define K2  0x6ED9EBA1L			/* Rounds 20-39: sqrt(3) * 2^30 */
+#define K3  0x8F1BBCDCL			/* Rounds 40-59: sqrt(5) * 2^30 */
+#define K4  0xCA62C1D6L			/* Rounds 60-79: sqrt(10) * 2^30 */
+
+/*
+ * sha_transform: single block SHA1 transform
+ *
+ * @digest: 160 bit digest to update
+ * @data:   512 bits of data to hash
+ * @W:      80 words of workspace (see note)
+ *
+ * This function generates a SHA1 digest for a single 512-bit block.
+ * Be warned, it does not handle padding and message digest, do not
+ * confuse it with the full FIPS 180-1 digest algorithm for variable
+ * length messages.
+ *
+ * Note: If the hash is security sensitive, the caller should be sure
+ * to clear the workspace. This is left to the caller to avoid
+ * unnecessary clears between chained hashing operations.
+ */
+void sha_transform(__u32 *digest, const char *in, __u32 *W)
+{
+	__u32 a, b, c, d, e, t, i;
+
+	for (i = 0; i < 16; i++)
+		W[i] = be32_to_cpu(((const __u32 *)in)[i]);
+
+	for (i = 0; i < 64; i++)
+		W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
+
+	a = digest[0];
+	b = digest[1];
+	c = digest[2];
+	d = digest[3];
+	e = digest[4];
+
+	for (i = 0; i < 20; i++) {
+		t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 40; i ++) {
+		t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 60; i ++) {
+		t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 80; i ++) {
+		t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	digest[0] += a;
+	digest[1] += b;
+	digest[2] += c;
+	digest[3] += d;
+	digest[4] += e;
+}
+EXPORT_SYMBOL(sha_transform);
+
+/*
+ * sha_init: initialize the vectors for a SHA1 digest
+ *
+ * @buf: vector to initialize
+ */
+void sha_init(__u32 *buf)
+{
+	buf[0] = 0x67452301;
+	buf[1] = 0xefcdab89;
+	buf[2] = 0x98badcfe;
+	buf[3] = 0x10325476;
+	buf[4] = 0xc3d2e1f0;
+}
+
diff --git a/lib/sort.c b/lib/sort.c
new file mode 100644
--- /dev/null
+++ b/lib/sort.c
@@ -0,0 +1,119 @@
+/*
+ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
+ *
+ * Jan 23 2005  Matt Mackall <mpm@selenic.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+void u32_swap(void *a, void *b, int size)
+{
+	u32 t = *(u32 *)a;
+	*(u32 *)a = *(u32 *)b;
+	*(u32 *)b = t;
+}
+
+void generic_swap(void *a, void *b, int size)
+{
+	char t;
+
+	do {
+		t = *(char *)a;
+		*(char *)a++ = *(char *)b;
+		*(char *)b++ = t;
+	} while (--size > 0);
+}
+
+/*
+ * sort - sort an array of elements
+ * @base: pointer to data to sort
+ * @num: number of elements
+ * @size: size of each element
+ * @cmp: pointer to comparison function
+ * @swap: pointer to swap function or NULL
+ *
+ * This function does a heapsort on the given array. You may provide a
+ * swap function optimized to your element type.
+ *
+ * Sorting time is O(n log n) both on average and worst-case. While
+ * qsort is about 20% faster on average, it suffers from exploitable
+ * O(n*n) worst-case behavior and extra memory requirements that make
+ * it less suitable for kernel use.
+ */
+
+void sort(void *base, size_t num, size_t size,
+	  int (*cmp)(const void *, const void *),
+	  void (*swap)(void *, void *, int size))
+{
+	/* pre-scale counters for performance */
+	int i = (num/2) * size, n = num * size, c, r;
+
+	if (!swap)
+		swap = (size == 4 ? u32_swap : generic_swap);
+
+	/* heapify */
+	for ( ; i >= 0; i -= size) {
+		for (r = i; r * 2 < n; r  = c) {
+			c = r * 2;
+			if (c < n - size && cmp(base + c, base + c + size) < 0)
+				c += size;
+			if (cmp(base + r, base + c) >= 0)
+				break;
+			swap(base + r, base + c, size);
+		}
+	}
+
+	/* sort */
+	for (i = n - size; i >= 0; i -= size) {
+		swap(base, base + i, size);
+		for (r = 0; r * 2 < i; r = c) {
+			c = r * 2;
+			if (c < i - size && cmp(base + c, base + c + size) < 0)
+				c += size;
+			if (cmp(base + r, base + c) >= 0)
+				break;
+			swap(base + r, base + c, size);
+		}
+	}
+}
+
+EXPORT_SYMBOL(sort);
+
+#if 0
+/* a simple boot-time regression test */
+
+int cmpint(const void *a, const void *b)
+{
+	return *(int *)a - *(int *)b;
+}
+
+static int sort_test(void)
+{
+	int *a, i, r = 1;
+
+	a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
+	BUG_ON(!a);
+
+	printk("testing sort()\n");
+
+	for (i = 0; i < 1000; i++) {
+		r = (r * 725861) % 6599;
+		a[i] = r;
+	}
+
+	sort(a, 1000, sizeof(int), cmpint, NULL);
+
+	for (i = 0; i < 999; i++)
+		if (a[i] > a[i+1]) {
+			printk("sort() failed!\n");
+			break;
+		}
+
+	kfree(a);
+
+	return 0;
+}
+
+module_init(sort_test);
+#endif
diff --git a/lib/string.c b/lib/string.c
--- a/lib/string.c
+++ b/lib/string.c
@@ -65,6 +65,7 @@ EXPORT_SYMBOL(strnicmp);
  * @dest: Where to copy the string to
  * @src: Where to copy the string from
  */
+#undef strcpy
 char * strcpy(char * dest,const char *src)
 {
 	char *tmp = dest;
@@ -85,6 +86,10 @@ EXPORT_SYMBOL(strcpy);
  *
  * The result is not %NUL-terminated if the source exceeds
  * @count bytes.
+ *
+ * In the case where the length of @src is less than  that  of
+ * count, the remainder of @dest will be padded with %NUL.
+ *
  */
 char * strncpy(char * dest,const char *src,size_t count)
 {
@@ -132,6 +137,7 @@ EXPORT_SYMBOL(strlcpy);
  * @dest: The string to be appended to
  * @src: The string to append to it
  */
+#undef strcat
 char * strcat(char * dest, const char * src)
 {
 	char *tmp = dest;
@@ -209,6 +215,7 @@ EXPORT_SYMBOL(strlcat);
  * @cs: One string
  * @ct: Another string
  */
+#undef strcmp
 int strcmp(const char * cs,const char * ct)
 {
 	register signed char __res;
@@ -514,6 +521,7 @@ EXPORT_SYMBOL(memmove);
  * @ct: Another area of memory
  * @count: The size of the area.
  */
+#undef memcmp
 int memcmp(const void * cs,const void * ct,size_t count)
 {
 	const unsigned char *su1, *su2;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -580,7 +580,7 @@ EXPORT_SYMBOL(scnprintf);
  */
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
-	return vsnprintf(buf, (~0U)>>1, fmt, args);
+	return vsnprintf(buf, INT_MAX, fmt, args);
 }
 
 EXPORT_SYMBOL(vsprintf);
@@ -601,7 +601,7 @@ int sprintf(char * buf, const char *fmt,
 	int i;
 
 	va_start(args, fmt);
-	i=vsprintf(buf,fmt,args);
+	i=vsnprintf(buf, INT_MAX, fmt, args);
 	va_end(args);
 	return i;
 }
diff --git a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -29,11 +29,6 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 /*
- * This is needed for the following functions:
- *  - try_to_release_page
- *  - block_invalidatepage
- *  - generic_osync_inode
- *
  * FIXME: remove all knowledge of the buffer layer from the core VM
  */
 #include <linux/buffer_head.h> /* for generic_osync_inode */
@@ -123,12 +118,11 @@ void remove_from_page_cache(struct page 
 {
 	struct address_space *mapping = page->mapping;
 
-	if (unlikely(!PageLocked(page)))
-		PAGE_BUG(page);
+	BUG_ON(!PageLocked(page));
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 }
 
 static int sync_page(void *word)
@@ -139,7 +133,25 @@ static int sync_page(void *word)
 	page = container_of((page_flags_t *)word, struct page, flags);
 
 	/*
-	 * FIXME, fercrissake.  What is this barrier here for?
+	 * page_mapping() is being called without PG_locked held.
+	 * Some knowledge of the state and use of the page is used to
+	 * reduce the requirements down to a memory barrier.
+	 * The danger here is of a stale page_mapping() return value
+	 * indicating a struct address_space different from the one it's
+	 * associated with when it is associated with one.
+	 * After smp_mb(), it's either the correct page_mapping() for
+	 * the page, or an old page_mapping() and the page's own
+	 * page_mapping() has gone NULL.
+	 * The ->sync_page() address_space operation must tolerate
+	 * page_mapping() going NULL. By an amazing coincidence,
+	 * this comes about because none of the users of the page
+	 * in the ->sync_page() methods make essential use of the
+	 * page_mapping(), merely passing the page down to the backing
+	 * device's unplug functions when it's non-NULL, which in turn
+	 * ignore it for all cases but swap, where only page->private is
+	 * of interest. When page_mapping() does go NULL, the entire
+	 * call stack gracefully ignores the page and returns.
+	 * -- wli
 	 */
 	smp_mb();
 	mapping = page_mapping(page);
@@ -152,9 +164,10 @@ static int sync_page(void *word)
 /**
  * filemap_fdatawrite_range - start writeback against all of a mapping's
  * dirty pages that lie within the byte offsets <start, end>
- * @mapping: address space structure to write
- * @start: offset in bytes where the range starts
- * @end : offset in bytes where the range ends
+ * @mapping:	address space structure to write
+ * @start:	offset in bytes where the range starts
+ * @end:	offset in bytes where the range ends
+ * @sync_mode:	enable synchronous operation
  *
  * If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
  * opposed to a regular memory * cleansing writeback.  The difference between
@@ -172,7 +185,7 @@ static int __filemap_fdatawrite_range(st
 		.end = end,
 	};
 
-	if (mapping->backing_dev_info->memory_backed)
+	if (!mapping_cap_writeback_dirty(mapping))
 		return 0;
 
 	ret = do_writepages(mapping, &wbc);
@@ -269,7 +282,7 @@ int sync_page_range(struct inode *inode,
 	pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
 	int ret;
 
-	if (mapping->backing_dev_info->memory_backed || !count)
+	if (!mapping_cap_writeback_dirty(mapping) || !count)
 		return 0;
 	ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1);
 	if (ret == 0) {
@@ -295,7 +308,7 @@ int sync_page_range_nolock(struct inode 
 	pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
 	int ret;
 
-	if (mapping->backing_dev_info->memory_backed || !count)
+	if (!mapping_cap_writeback_dirty(mapping) || !count)
 		return 0;
 	ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1);
 	if (ret == 0)
@@ -336,6 +349,22 @@ int filemap_write_and_wait(struct addres
 	return retval;
 }
 
+int filemap_write_and_wait_range(struct address_space *mapping,
+				 loff_t lstart, loff_t lend)
+{
+	int retval = 0;
+
+	if (mapping->nrpages) {
+		retval = __filemap_fdatawrite_range(mapping, lstart, lend,
+						    WB_SYNC_ALL);
+		if (retval == 0)
+			retval = wait_on_page_writeback_range(mapping,
+						    lstart >> PAGE_CACHE_SHIFT,
+						    lend >> PAGE_CACHE_SHIFT);
+	}
+	return retval;
+}
+
 /*
  * This function is used to add newly allocated pagecache pages:
  * the page is new, so we can just run SetPageLocked() against it.
@@ -349,7 +378,7 @@ int add_to_page_cache(struct page *page,
 	int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 
 	if (error == 0) {
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 		error = radix_tree_insert(&mapping->page_tree, offset, page);
 		if (!error) {
 			page_cache_get(page);
@@ -359,7 +388,7 @@ int add_to_page_cache(struct page *page,
 			mapping->nrpages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -472,11 +501,11 @@ struct page * find_get_page(struct addre
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page)
 		page_cache_get(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -489,11 +518,11 @@ struct page *find_trylock_page(struct ad
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page && TestSetPageLocked(page))
 		page = NULL;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -502,8 +531,8 @@ EXPORT_SYMBOL(find_trylock_page);
 /**
  * find_lock_page - locate, pin and lock a pagecache page
  *
- * @mapping - the address_space to search
- * @offset - the page index
+ * @mapping: the address_space to search
+ * @offset: the page index
  *
  * Locates the desired pagecache page, locks it, increments its reference
  * count and returns its address.
@@ -515,15 +544,15 @@ struct page *find_lock_page(struct addre
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 repeat:
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page) {
 		page_cache_get(page);
 		if (TestSetPageLocked(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			read_unlock_irq(&mapping->tree_lock);
 			lock_page(page);
-			spin_lock_irq(&mapping->tree_lock);
+			read_lock_irq(&mapping->tree_lock);
 
 			/* Has the page been truncated while we slept? */
 			if (page->mapping != mapping || page->index != offset) {
@@ -533,7 +562,7 @@ repeat:
 			}
 		}
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -542,9 +571,9 @@ EXPORT_SYMBOL(find_lock_page);
 /**
  * find_or_create_page - locate or add a pagecache page
  *
- * @mapping - the page's address_space
- * @index - the page's index into the mapping
- * @gfp_mask - page allocation mode
+ * @mapping: the page's address_space
+ * @index: the page's index into the mapping
+ * @gfp_mask: page allocation mode
  *
  * Locates a page in the pagecache.  If the page is not present, a new page
  * is allocated using @gfp_mask and is added to the pagecache and to the VM's
@@ -607,12 +636,12 @@ unsigned find_get_pages(struct address_s
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup(&mapping->page_tree,
 				(void **)pages, start, nr_pages);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -626,14 +655,14 @@ unsigned find_get_pages_tag(struct addre
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
 				(void **)pages, *index, nr_pages, tag);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
 	if (ret)
 		*index = pages[ret - 1]->index + 1;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -650,7 +679,7 @@ struct page *
 grab_cache_page_nowait(struct address_space *mapping, unsigned long index)
 {
 	struct page *page = find_get_page(mapping, index);
-	int gfp_mask;
+	unsigned int gfp_mask;
 
 	if (page) {
 		if (!TestSetPageLocked(page))
@@ -691,7 +720,7 @@ void do_generic_mapping_read(struct addr
 	unsigned long index;
 	unsigned long end_index;
 	unsigned long offset;
-	unsigned long req_size;
+	unsigned long last_index;
 	unsigned long next_index;
 	unsigned long prev_index;
 	loff_t isize;
@@ -703,7 +732,7 @@ void do_generic_mapping_read(struct addr
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	next_index = index;
 	prev_index = ra.prev_page;
-	req_size = (desc->count + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
 	offset = *ppos & ~PAGE_CACHE_MASK;
 
 	isize = i_size_read(inode);
@@ -713,7 +742,7 @@ void do_generic_mapping_read(struct addr
 	end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
 	for (;;) {
 		struct page *page;
-		unsigned long ret_size, nr, ret;
+		unsigned long nr, ret;
 
 		/* nr is the maximum number of bytes to copy from this page */
 		nr = PAGE_CACHE_SIZE;
@@ -728,12 +757,9 @@ void do_generic_mapping_read(struct addr
 		nr = nr - offset;
 
 		cond_resched();
-		if (index == next_index && req_size) {
-			ret_size = page_cache_readahead(mapping, &ra,
-					filp, index, req_size);
-			next_index += ret_size;
-			req_size -= ret_size;
-		}
+		if (index == next_index)
+			next_index = page_cache_readahead(mapping, &ra, filp,
+					index, last_index - index);
 
 find_page:
 		page = find_get_page(mapping, index);
@@ -978,7 +1004,7 @@ __generic_file_aio_read(struct kiocb *io
 		if (pos < size) {
 			retval = generic_file_direct_IO(READ, iocb,
 						iov, pos, nr_segs);
-			if (retval >= 0 && !is_sync_kiocb(iocb))
+			if (retval > 0 && !is_sync_kiocb(iocb))
 				retval = -EIOCBQUEUED;
 			if (retval > 0)
 				*ppos = pos + retval;
@@ -1154,7 +1180,8 @@ static int fastcall page_cache_read(stru
  * it in the page cache, and handles the special cases reasonably without
  * having a lot of duplicated code.
  */
-struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address, int *type)
+struct page *filemap_nopage(struct vm_area_struct *area,
+				unsigned long address, int *type)
 {
 	int error;
 	struct file *file = area->vm_file;
@@ -1162,11 +1189,10 @@ struct page * filemap_nopage(struct vm_a
 	struct file_ra_state *ra = &file->f_ra;
 	struct inode *inode = mapping->host;
 	struct page *page;
-	unsigned long size, pgoff, endoff;
+	unsigned long size, pgoff;
 	int did_readaround = 0, majmin = VM_FAULT_MINOR;
 
-	pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
-	endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+	pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
 
 retry_all:
 	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -1178,13 +1204,6 @@ retry_all:
 		goto no_cached_page;
 
 	/*
-	 * The "size" of the file, as far as mmap is concerned, isn't bigger
-	 * than the mapping
-	 */
-	if (size > endoff)
-		size = endoff;
-
-	/*
 	 * The readahead code wants to be told about each and every page
 	 * so it can build and shrink its windows appropriately
 	 *
@@ -1373,8 +1392,13 @@ retry_find:
 	 * Ok, found a page in the page cache, now we need to check
 	 * that it's up-to-date.
 	 */
-	if (!PageUptodate(page))
+	if (!PageUptodate(page)) {
+		if (nonblock) {
+			page_cache_release(page);
+			return NULL;
+		}
 		goto page_not_uptodate;
+	}
 
 success:
 	/*
@@ -1938,12 +1962,13 @@ generic_file_buffered_write(struct kiocb
 		buf = iov->iov_base + written;
 	else {
 		filemap_set_next_iovec(&cur_iov, &iov_base, written);
-		buf = iov->iov_base + iov_base;
+		buf = cur_iov->iov_base + iov_base;
 	}
 
 	do {
 		unsigned long index;
 		unsigned long offset;
+		unsigned long maxlen;
 		size_t copied;
 
 		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
@@ -1958,7 +1983,10 @@ generic_file_buffered_write(struct kiocb
 		 * same page as we're writing to, without it being marked
 		 * up-to-date.
 		 */
-		fault_in_pages_readable(buf, bytes);
+		maxlen = cur_iov->iov_len - iov_base;
+		if (maxlen > bytes)
+			maxlen = bytes;
+		fault_in_pages_readable(buf, maxlen);
 
 		page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
 		if (!page) {
@@ -1996,9 +2024,13 @@ generic_file_buffered_write(struct kiocb
 				count -= status;
 				pos += status;
 				buf += status;
-				if (unlikely(nr_segs > 1))
+				if (unlikely(nr_segs > 1)) {
 					filemap_set_next_iovec(&cur_iov,
 							&iov_base, status);
+					buf = cur_iov->iov_base + iov_base;
+				} else {
+					iov_base += status;
+				}
 			}
 		}
 		if (unlikely(copied != bytes))
@@ -2269,21 +2301,28 @@ generic_file_direct_IO(int rw, struct ki
 	struct file *file = iocb->ki_filp;
 	struct address_space *mapping = file->f_mapping;
 	ssize_t retval;
+	size_t write_len = 0;
 
 	/*
 	 * If it's a write, unmap all mmappings of the file up-front.  This
 	 * will cause any pte dirty bits to be propagated into the pageframes
 	 * for the subsequent filemap_write_and_wait().
 	 */
-	if (rw == WRITE && mapping_mapped(mapping))
-		unmap_mapping_range(mapping, 0, -1, 0);
+	if (rw == WRITE) {
+		write_len = iov_length(iov, nr_segs);
+	       	if (mapping_mapped(mapping))
+			unmap_mapping_range(mapping, offset, write_len, 0);
+	}
 
 	retval = filemap_write_and_wait(mapping);
 	if (retval == 0) {
 		retval = mapping->a_ops->direct_IO(rw, iocb, iov,
 						offset, nr_segs);
 		if (rw == WRITE && mapping->nrpages) {
-			int err = invalidate_inode_pages2(mapping);
+			pgoff_t end = (offset + write_len - 1)
+						>> PAGE_CACHE_SHIFT;
+			int err = invalidate_inode_pages2_range(mapping,
+					offset >> PAGE_CACHE_SHIFT, end);
 			if (err)
 				retval = err;
 		}
diff --git a/mm/fremap.c b/mm/fremap.c
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -30,7 +30,7 @@ static inline void zap_pte(struct mm_str
 	if (pte_present(pte)) {
 		unsigned long pfn = pte_pfn(pte);
 
-		flush_cache_page(vma, addr);
+		flush_cache_page(vma, addr, pfn);
 		pte = ptep_clear_flush(vma, addr, ptep);
 		if (pfn_valid(pfn)) {
 			struct page *page = pfn_to_page(pfn);
@@ -39,13 +39,13 @@ static inline void zap_pte(struct mm_str
 					set_page_dirty(page);
 				page_remove_rmap(page);
 				page_cache_release(page);
-				mm->rss--;
+				dec_mm_counter(mm, rss);
 			}
 		}
 	} else {
 		if (!pte_file(pte))
 			free_swap_and_cache(pte_to_swp_entry(pte));
-		pte_clear(ptep);
+		pte_clear(mm, addr, ptep);
 	}
 }
 
@@ -92,9 +92,9 @@ int install_page(struct mm_struct *mm, s
 
 	zap_pte(mm, vma, addr, pte);
 
-	mm->rss++;
+	inc_mm_counter(mm,rss);
 	flush_icache_page(vma, page);
-	set_pte(pte, mk_pte(page, prot));
+	set_pte_at(mm, addr, pte, mk_pte(page, prot));
 	page_add_file_rmap(page);
 	pte_val = *pte;
 	pte_unmap(pte);
@@ -139,7 +139,7 @@ int install_file_pte(struct mm_struct *m
 
 	zap_pte(mm, vma, addr, pte);
 
-	set_pte(pte, pgoff_to_pte(pgoff));
+	set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
 	pte_val = *pte;
 	pte_unmap(pte);
 	update_mmu_cache(vma, addr, pte_val);
diff --git a/mm/highmem.c b/mm/highmem.c
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -30,9 +30,9 @@
 
 static mempool_t *page_pool, *isa_page_pool;
 
-static void *page_pool_alloc(int gfp_mask, void *data)
+static void *page_pool_alloc(unsigned int __nocast gfp_mask, void *data)
 {
-	int gfp = gfp_mask | (int) (long) data;
+	unsigned int gfp = gfp_mask | (unsigned int) (long) data;
 
 	return alloc_page(gfp);
 }
@@ -90,7 +90,8 @@ static void flush_all_zero_pkmaps(void)
 		 * So no dangers, even with speculative execution.
 		 */
 		page = pte_page(pkmap_page_table[i]);
-		pte_clear(&pkmap_page_table[i]);
+		pte_clear(&init_mm, (unsigned long)page_address(page),
+			  &pkmap_page_table[i]);
 
 		set_page_address(page, NULL);
 	}
@@ -138,7 +139,8 @@ start:
 		}
 	}
 	vaddr = PKMAP_ADDR(last_pkmap_nr);
-	set_pte(&(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));
+	set_pte_at(&init_mm, vaddr,
+		   &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));
 
 	pkmap_count[last_pkmap_nr] = 1;
 	set_page_address(page, (void *)vaddr);
@@ -323,6 +325,7 @@ static void bounce_end_io(struct bio *bi
 			continue;
 
 		mempool_free(bvec->bv_page, pool);	
+		dec_page_state(nr_bounce);
 	}
 
 	bio_endio(bio_orig, bio_orig->bi_size, err);
@@ -403,6 +406,7 @@ static void __blk_queue_bounce(request_q
 		to->bv_page = mempool_alloc(pool, q->bounce_gfp);
 		to->bv_len = from->bv_len;
 		to->bv_offset = from->bv_offset;
+		inc_page_state(nr_bounce);
 
 		if (rw == WRITE) {
 			char *vto, *vfrom;
diff --git a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -46,7 +46,6 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/rmap.h>
-#include <linux/acct.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
@@ -84,116 +83,205 @@ EXPORT_SYMBOL(high_memory);
 EXPORT_SYMBOL(vmalloc_earlyreserve);
 
 /*
- * Note: this doesn't free the actual pages themselves. That
- * has been handled earlier when unmapping all the memory regions.
+ * If a p?d_bad entry is found while walking page tables, report
+ * the error, before resetting entry to p?d_none.  Usually (but
+ * very seldom) called out from the p?d_none_or_clear_bad macros.
  */
-static inline void clear_pmd_range(struct mmu_gather *tlb, pmd_t *pmd, unsigned long start, unsigned long end)
+
+void pgd_clear_bad(pgd_t *pgd)
 {
-	struct page *page;
+	pgd_ERROR(*pgd);
+	pgd_clear(pgd);
+}
 
-	if (pmd_none(*pmd))
-		return;
-	if (unlikely(pmd_bad(*pmd))) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	if (!((start | end) & ~PMD_MASK)) {
-		/* Only clear full, aligned ranges */
-		page = pmd_page(*pmd);
-		pmd_clear(pmd);
-		dec_page_state(nr_page_table_pages);
-		tlb->mm->nr_ptes--;
-		pte_free_tlb(tlb, page);
-	}
+void pud_clear_bad(pud_t *pud)
+{
+	pud_ERROR(*pud);
+	pud_clear(pud);
 }
 
-static inline void clear_pud_range(struct mmu_gather *tlb, pud_t *pud, unsigned long start, unsigned long end)
+void pmd_clear_bad(pmd_t *pmd)
 {
-	unsigned long addr = start, next;
-	pmd_t *pmd, *__pmd;
+	pmd_ERROR(*pmd);
+	pmd_clear(pmd);
+}
 
-	if (pud_none(*pud))
-		return;
-	if (unlikely(pud_bad(*pud))) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return;
-	}
+/*
+ * Note: this doesn't free the actual pages themselves. That
+ * has been handled earlier when unmapping all the memory regions.
+ */
+static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd)
+{
+	struct page *page = pmd_page(*pmd);
+	pmd_clear(pmd);
+	pte_free_tlb(tlb, page);
+	dec_page_state(nr_page_table_pages);
+	tlb->mm->nr_ptes--;
+}
+
+static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
+				unsigned long addr, unsigned long end,
+				unsigned long floor, unsigned long ceiling)
+{
+	pmd_t *pmd;
+	unsigned long next;
+	unsigned long start;
 
-	pmd = __pmd = pmd_offset(pud, start);
+	start = addr;
+	pmd = pmd_offset(pud, addr);
 	do {
-		next = (addr + PMD_SIZE) & PMD_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		
-		clear_pmd_range(tlb, pmd, addr, next);
-		pmd++;
-		addr = next;
-	} while (addr && (addr < end));
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		free_pte_range(tlb, pmd);
+	} while (pmd++, addr = next, addr != end);
 
-	if (!((start | end) & ~PUD_MASK)) {
-		/* Only clear full, aligned ranges */
-		pud_clear(pud);
-		pmd_free_tlb(tlb, __pmd);
+	start &= PUD_MASK;
+	if (start < floor)
+		return;
+	if (ceiling) {
+		ceiling &= PUD_MASK;
+		if (!ceiling)
+			return;
 	}
-}
+	if (end - 1 > ceiling - 1)
+		return;
 
+	pmd = pmd_offset(pud, start);
+	pud_clear(pud);
+	pmd_free_tlb(tlb, pmd);
+}
 
-static inline void clear_pgd_range(struct mmu_gather *tlb, pgd_t *pgd, unsigned long start, unsigned long end)
+static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
+				unsigned long addr, unsigned long end,
+				unsigned long floor, unsigned long ceiling)
 {
-	unsigned long addr = start, next;
-	pud_t *pud, *__pud;
-
-	if (pgd_none(*pgd))
-		return;
-	if (unlikely(pgd_bad(*pgd))) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return;
-	}
+	pud_t *pud;
+	unsigned long next;
+	unsigned long start;
 
-	pud = __pud = pud_offset(pgd, start);
+	start = addr;
+	pud = pud_offset(pgd, addr);
 	do {
-		next = (addr + PUD_SIZE) & PUD_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		
-		clear_pud_range(tlb, pud, addr, next);
-		pud++;
-		addr = next;
-	} while (addr && (addr < end));
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		free_pmd_range(tlb, pud, addr, next, floor, ceiling);
+	} while (pud++, addr = next, addr != end);
 
-	if (!((start | end) & ~PGDIR_MASK)) {
-		/* Only clear full, aligned ranges */
-		pgd_clear(pgd);
-		pud_free_tlb(tlb, __pud);
+	start &= PGDIR_MASK;
+	if (start < floor)
+		return;
+	if (ceiling) {
+		ceiling &= PGDIR_MASK;
+		if (!ceiling)
+			return;
 	}
+	if (end - 1 > ceiling - 1)
+		return;
+
+	pud = pud_offset(pgd, start);
+	pgd_clear(pgd);
+	pud_free_tlb(tlb, pud);
 }
 
 /*
- * This function clears user-level page tables of a process.
+ * This function frees user-level page tables of a process.
  *
  * Must be called with pagetable lock held.
  */
-void clear_page_range(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+void free_pgd_range(struct mmu_gather **tlb,
+			unsigned long addr, unsigned long end,
+			unsigned long floor, unsigned long ceiling)
 {
-	unsigned long addr = start, next;
-	pgd_t * pgd = pgd_offset(tlb->mm, start);
-	unsigned long i;
-
-	for (i = pgd_index(start); i <= pgd_index(end-1); i++) {
-		next = (addr + PGDIR_SIZE) & PGDIR_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		
-		clear_pgd_range(tlb, pgd, addr, next);
-		pgd++;
-		addr = next;
+	pgd_t *pgd;
+	unsigned long next;
+	unsigned long start;
+
+	/*
+	 * The next few lines have given us lots of grief...
+	 *
+	 * Why are we testing PMD* at this top level?  Because often
+	 * there will be no work to do at all, and we'd prefer not to
+	 * go all the way down to the bottom just to discover that.
+	 *
+	 * Why all these "- 1"s?  Because 0 represents both the bottom
+	 * of the address space and the top of it (using -1 for the
+	 * top wouldn't help much: the masks would do the wrong thing).
+	 * The rule is that addr 0 and floor 0 refer to the bottom of
+	 * the address space, but end 0 and ceiling 0 refer to the top
+	 * Comparisons need to use "end - 1" and "ceiling - 1" (though
+	 * that end 0 case should be mythical).
+	 *
+	 * Wherever addr is brought up or ceiling brought down, we must
+	 * be careful to reject "the opposite 0" before it confuses the
+	 * subsequent tests.  But what about where end is brought down
+	 * by PMD_SIZE below? no, end can't go down to 0 there.
+	 *
+	 * Whereas we round start (addr) and ceiling down, by different
+	 * masks at different levels, in order to test whether a table
+	 * now has no other vmas using it, so can be freed, we don't
+	 * bother to round floor or end up - the tests don't need that.
+	 */
+
+	addr &= PMD_MASK;
+	if (addr < floor) {
+		addr += PMD_SIZE;
+		if (!addr)
+			return;
+	}
+	if (ceiling) {
+		ceiling &= PMD_MASK;
+		if (!ceiling)
+			return;
+	}
+	if (end - 1 > ceiling - 1)
+		end -= PMD_SIZE;
+	if (addr > end - 1)
+		return;
+
+	start = addr;
+	pgd = pgd_offset((*tlb)->mm, addr);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		free_pud_range(*tlb, pgd, addr, next, floor, ceiling);
+	} while (pgd++, addr = next, addr != end);
+
+	if (!tlb_is_full_mm(*tlb))
+		flush_tlb_pgtables((*tlb)->mm, start, end);
+}
+
+void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *vma,
+		unsigned long floor, unsigned long ceiling)
+{
+	while (vma) {
+		struct vm_area_struct *next = vma->vm_next;
+		unsigned long addr = vma->vm_start;
+
+		if (is_hugepage_only_range(vma->vm_mm, addr, HPAGE_SIZE)) {
+			hugetlb_free_pgd_range(tlb, addr, vma->vm_end,
+				floor, next? next->vm_start: ceiling);
+		} else {
+			/*
+			 * Optimization: gather nearby vmas into one call down
+			 */
+			while (next && next->vm_start <= vma->vm_end + PMD_SIZE
+			  && !is_hugepage_only_range(vma->vm_mm, next->vm_start,
+							HPAGE_SIZE)) {
+				vma = next;
+				next = vma->vm_next;
+			}
+			free_pgd_range(tlb, addr, vma->vm_end,
+				floor, next? next->vm_start: ceiling);
+		}
+		vma = next;
 	}
 }
 
-pte_t fastcall * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+pte_t fastcall *pte_alloc_map(struct mm_struct *mm, pmd_t *pmd,
+				unsigned long address)
 {
 	if (!pmd_present(*pmd)) {
 		struct page *new;
@@ -254,20 +342,7 @@ out:
  */
 
 static inline void
-copy_swap_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, pte_t pte)
-{
-	if (pte_file(pte))
-		return;
-	swap_duplicate(pte_to_swp_entry(pte));
-	if (list_empty(&dst_mm->mmlist)) {
-		spin_lock(&mmlist_lock);
-		list_add(&dst_mm->mmlist, &src_mm->mmlist);
-		spin_unlock(&mmlist_lock);
-	}
-}
-
-static inline void
-copy_one_pte(struct mm_struct *dst_mm,  struct mm_struct *src_mm,
+copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pte_t *dst_pte, pte_t *src_pte, unsigned long vm_flags,
 		unsigned long addr)
 {
@@ -275,12 +350,21 @@ copy_one_pte(struct mm_struct *dst_mm,  
 	struct page *page;
 	unsigned long pfn;
 
-	/* pte contains position in swap, so copy. */
-	if (!pte_present(pte)) {
-		copy_swap_pte(dst_mm, src_mm, pte);
-		set_pte(dst_pte, pte);
+	/* pte contains position in swap or file, so copy. */
+	if (unlikely(!pte_present(pte))) {
+		if (!pte_file(pte)) {
+			swap_duplicate(pte_to_swp_entry(pte));
+			/* make sure dst_mm is on swapoff's mmlist. */
+			if (unlikely(list_empty(&dst_mm->mmlist))) {
+				spin_lock(&mmlist_lock);
+				list_add(&dst_mm->mmlist, &src_mm->mmlist);
+				spin_unlock(&mmlist_lock);
+			}
+		}
+		set_pte_at(dst_mm, addr, dst_pte, pte);
 		return;
 	}
+
 	pfn = pte_pfn(pte);
 	/* the pte points outside of valid memory, the
 	 * mapping is assumed to be good, meaningful
@@ -292,7 +376,7 @@ copy_one_pte(struct mm_struct *dst_mm,  
 		page = pfn_to_page(pfn);
 
 	if (!page || PageReserved(page)) {
-		set_pte(dst_pte, pte);
+		set_pte_at(dst_mm, addr, dst_pte, pte);
 		return;
 	}
 
@@ -301,7 +385,7 @@ copy_one_pte(struct mm_struct *dst_mm,  
 	 * in the parent and the child
 	 */
 	if ((vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE) {
-		ptep_set_wrprotect(src_pte);
+		ptep_set_wrprotect(src_mm, addr, src_pte);
 		pte = *src_pte;
 	}
 
@@ -313,172 +397,137 @@ copy_one_pte(struct mm_struct *dst_mm,  
 		pte = pte_mkclean(pte);
 	pte = pte_mkold(pte);
 	get_page(page);
-	dst_mm->rss++;
+	inc_mm_counter(dst_mm, rss);
 	if (PageAnon(page))
-		dst_mm->anon_rss++;
-	set_pte(dst_pte, pte);
+		inc_mm_counter(dst_mm, anon_rss);
+	set_pte_at(dst_mm, addr, dst_pte, pte);
 	page_dup_rmap(page);
 }
 
-static int copy_pte_range(struct mm_struct *dst_mm,  struct mm_struct *src_mm,
+static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma,
 		unsigned long addr, unsigned long end)
 {
 	pte_t *src_pte, *dst_pte;
-	pte_t *s, *d;
 	unsigned long vm_flags = vma->vm_flags;
+	int progress;
 
-	d = dst_pte = pte_alloc_map(dst_mm, dst_pmd, addr);
+again:
+	dst_pte = pte_alloc_map(dst_mm, dst_pmd, addr);
 	if (!dst_pte)
 		return -ENOMEM;
+	src_pte = pte_offset_map_nested(src_pmd, addr);
 
+	progress = 0;
 	spin_lock(&src_mm->page_table_lock);
-	s = src_pte = pte_offset_map_nested(src_pmd, addr);
-	for (; addr < end; addr += PAGE_SIZE, s++, d++) {
-		if (pte_none(*s))
+	do {
+		/*
+		 * We are holding two locks at this point - either of them
+		 * could generate latencies in another task on another CPU.
+		 */
+		if (progress >= 32 && (need_resched() ||
+		    need_lockbreak(&src_mm->page_table_lock) ||
+		    need_lockbreak(&dst_mm->page_table_lock)))
+			break;
+		if (pte_none(*src_pte)) {
+			progress++;
 			continue;
-		copy_one_pte(dst_mm, src_mm, d, s, vm_flags, addr);
-	}
-	pte_unmap_nested(src_pte);
-	pte_unmap(dst_pte);
+		}
+		copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vm_flags, addr);
+		progress += 8;
+	} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 	spin_unlock(&src_mm->page_table_lock);
+
+	pte_unmap_nested(src_pte - 1);
+	pte_unmap(dst_pte - 1);
 	cond_resched_lock(&dst_mm->page_table_lock);
+	if (addr != end)
+		goto again;
 	return 0;
 }
 
-static int copy_pmd_range(struct mm_struct *dst_mm,  struct mm_struct *src_mm,
+static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pud_t *dst_pud, pud_t *src_pud, struct vm_area_struct *vma,
 		unsigned long addr, unsigned long end)
 {
 	pmd_t *src_pmd, *dst_pmd;
-	int err = 0;
 	unsigned long next;
 
-	src_pmd = pmd_offset(src_pud, addr);
 	dst_pmd = pmd_alloc(dst_mm, dst_pud, addr);
 	if (!dst_pmd)
 		return -ENOMEM;
-
-	for (; addr < end; addr = next, src_pmd++, dst_pmd++) {
-		next = (addr + PMD_SIZE) & PMD_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		if (pmd_none(*src_pmd))
-			continue;
-		if (pmd_bad(*src_pmd)) {
-			pmd_ERROR(*src_pmd);
-			pmd_clear(src_pmd);
+	src_pmd = pmd_offset(src_pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(src_pmd))
 			continue;
-		}
-		err = copy_pte_range(dst_mm, src_mm, dst_pmd, src_pmd,
-							vma, addr, next);
-		if (err)
-			break;
-	}
-	return err;
+		if (copy_pte_range(dst_mm, src_mm, dst_pmd, src_pmd,
+						vma, addr, next))
+			return -ENOMEM;
+	} while (dst_pmd++, src_pmd++, addr = next, addr != end);
+	return 0;
 }
 
-static int copy_pud_range(struct mm_struct *dst_mm,  struct mm_struct *src_mm,
+static inline int copy_pud_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pgd_t *dst_pgd, pgd_t *src_pgd, struct vm_area_struct *vma,
 		unsigned long addr, unsigned long end)
 {
 	pud_t *src_pud, *dst_pud;
-	int err = 0;
 	unsigned long next;
 
-	src_pud = pud_offset(src_pgd, addr);
 	dst_pud = pud_alloc(dst_mm, dst_pgd, addr);
 	if (!dst_pud)
 		return -ENOMEM;
-
-	for (; addr < end; addr = next, src_pud++, dst_pud++) {
-		next = (addr + PUD_SIZE) & PUD_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		if (pud_none(*src_pud))
-			continue;
-		if (pud_bad(*src_pud)) {
-			pud_ERROR(*src_pud);
-			pud_clear(src_pud);
+	src_pud = pud_offset(src_pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(src_pud))
 			continue;
-		}
-		err = copy_pmd_range(dst_mm, src_mm, dst_pud, src_pud,
-							vma, addr, next);
-		if (err)
-			break;
-	}
-	return err;
+		if (copy_pmd_range(dst_mm, src_mm, dst_pud, src_pud,
+						vma, addr, next))
+			return -ENOMEM;
+	} while (dst_pud++, src_pud++, addr = next, addr != end);
+	return 0;
 }
 
-int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
+int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		struct vm_area_struct *vma)
 {
 	pgd_t *src_pgd, *dst_pgd;
-	unsigned long addr, start, end, next;
-	int err = 0;
+	unsigned long next;
+	unsigned long addr = vma->vm_start;
+	unsigned long end = vma->vm_end;
 
 	if (is_vm_hugetlb_page(vma))
-		return copy_hugetlb_page_range(dst, src, vma);
-
-	start = vma->vm_start;
-	src_pgd = pgd_offset(src, start);
-	dst_pgd = pgd_offset(dst, start);
-
-	end = vma->vm_end;
-	addr = start;
-	while (addr && (addr < end-1)) {
-		next = (addr + PGDIR_SIZE) & PGDIR_MASK;
-		if (next > end || next <= addr)
-			next = end;
-		if (pgd_none(*src_pgd))
-			goto next_pgd;
-		if (pgd_bad(*src_pgd)) {
-			pgd_ERROR(*src_pgd);
-			pgd_clear(src_pgd);
-			goto next_pgd;
-		}
-		err = copy_pud_range(dst, src, dst_pgd, src_pgd,
-							vma, addr, next);
-		if (err)
-			break;
-
-next_pgd:
-		src_pgd++;
-		dst_pgd++;
-		addr = next;
-	}
+		return copy_hugetlb_page_range(dst_mm, src_mm, vma);
 
-	return err;
+	dst_pgd = pgd_offset(dst_mm, addr);
+	src_pgd = pgd_offset(src_mm, addr);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(src_pgd))
+			continue;
+		if (copy_pud_range(dst_mm, src_mm, dst_pgd, src_pgd,
+						vma, addr, next))
+			return -ENOMEM;
+	} while (dst_pgd++, src_pgd++, addr = next, addr != end);
+	return 0;
 }
 
-static void zap_pte_range(struct mmu_gather *tlb,
-		pmd_t *pmd, unsigned long address,
-		unsigned long size, struct zap_details *details)
+static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
+				unsigned long addr, unsigned long end,
+				struct zap_details *details)
 {
-	unsigned long offset;
-	pte_t *ptep;
+	pte_t *pte;
 
-	if (pmd_none(*pmd))
-		return;
-	if (unlikely(pmd_bad(*pmd))) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	ptep = pte_offset_map(pmd, address);
-	offset = address & ~PMD_MASK;
-	if (offset + size > PMD_SIZE)
-		size = PMD_SIZE - offset;
-	size &= PAGE_MASK;
-	if (details && !details->check_mapping && !details->nonlinear_vma)
-		details = NULL;
-	for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
-		pte_t pte = *ptep;
-		if (pte_none(pte))
+	pte = pte_offset_map(pmd, addr);
+	do {
+		pte_t ptent = *pte;
+		if (pte_none(ptent))
 			continue;
-		if (pte_present(pte)) {
+		if (pte_present(ptent)) {
 			struct page *page = NULL;
-			unsigned long pfn = pte_pfn(pte);
+			unsigned long pfn = pte_pfn(ptent);
 			if (pfn_valid(pfn)) {
 				page = pfn_to_page(pfn);
 				if (PageReserved(page))
@@ -502,19 +551,20 @@ static void zap_pte_range(struct mmu_gat
 				     page->index > details->last_index))
 					continue;
 			}
-			pte = ptep_get_and_clear(ptep);
-			tlb_remove_tlb_entry(tlb, ptep, address+offset);
+			ptent = ptep_get_and_clear(tlb->mm, addr, pte);
+			tlb_remove_tlb_entry(tlb, pte, addr);
 			if (unlikely(!page))
 				continue;
 			if (unlikely(details) && details->nonlinear_vma
 			    && linear_page_index(details->nonlinear_vma,
-					address+offset) != page->index)
-				set_pte(ptep, pgoff_to_pte(page->index));
-			if (pte_dirty(pte))
+						addr) != page->index)
+				set_pte_at(tlb->mm, addr, pte,
+					   pgoff_to_pte(page->index));
+			if (pte_dirty(ptent))
 				set_page_dirty(page);
 			if (PageAnon(page))
-				tlb->mm->anon_rss--;
-			else if (pte_young(pte))
+				dec_mm_counter(tlb->mm, anon_rss);
+			else if (pte_young(ptent))
 				mark_page_accessed(page);
 			tlb->freed++;
 			page_remove_rmap(page);
@@ -527,78 +577,64 @@ static void zap_pte_range(struct mmu_gat
 		 */
 		if (unlikely(details))
 			continue;
-		if (!pte_file(pte))
-			free_swap_and_cache(pte_to_swp_entry(pte));
-		pte_clear(ptep);
-	}
-	pte_unmap(ptep-1);
+		if (!pte_file(ptent))
+			free_swap_and_cache(pte_to_swp_entry(ptent));
+		pte_clear(tlb->mm, addr, pte);
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+	pte_unmap(pte - 1);
 }
 
-static void zap_pmd_range(struct mmu_gather *tlb,
-		pud_t *pud, unsigned long address,
-		unsigned long size, struct zap_details *details)
+static inline void zap_pmd_range(struct mmu_gather *tlb, pud_t *pud,
+				unsigned long addr, unsigned long end,
+				struct zap_details *details)
 {
-	pmd_t * pmd;
-	unsigned long end;
+	pmd_t *pmd;
+	unsigned long next;
 
-	if (pud_none(*pud))
-		return;
-	if (unlikely(pud_bad(*pud))) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return;
-	}
-	pmd = pmd_offset(pud, address);
-	end = address + size;
-	if (end > ((address + PUD_SIZE) & PUD_MASK))
-		end = ((address + PUD_SIZE) & PUD_MASK);
+	pmd = pmd_offset(pud, addr);
 	do {
-		zap_pte_range(tlb, pmd, address, end - address, details);
-		address = (address + PMD_SIZE) & PMD_MASK; 
-		pmd++;
-	} while (address && (address < end));
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		zap_pte_range(tlb, pmd, addr, next, details);
+	} while (pmd++, addr = next, addr != end);
 }
 
-static void zap_pud_range(struct mmu_gather *tlb,
-		pgd_t * pgd, unsigned long address,
-		unsigned long end, struct zap_details *details)
+static inline void zap_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
+				unsigned long addr, unsigned long end,
+				struct zap_details *details)
 {
-	pud_t * pud;
+	pud_t *pud;
+	unsigned long next;
 
-	if (pgd_none(*pgd))
-		return;
-	if (unlikely(pgd_bad(*pgd))) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return;
-	}
-	pud = pud_offset(pgd, address);
+	pud = pud_offset(pgd, addr);
 	do {
-		zap_pmd_range(tlb, pud, address, end - address, details);
-		address = (address + PUD_SIZE) & PUD_MASK; 
-		pud++;
-	} while (address && (address < end));
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		zap_pmd_range(tlb, pud, addr, next, details);
+	} while (pud++, addr = next, addr != end);
 }
 
-static void unmap_page_range(struct mmu_gather *tlb,
-		struct vm_area_struct *vma, unsigned long address,
-		unsigned long end, struct zap_details *details)
+static void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+				unsigned long addr, unsigned long end,
+				struct zap_details *details)
 {
-	unsigned long next;
 	pgd_t *pgd;
-	int i;
+	unsigned long next;
 
-	BUG_ON(address >= end);
-	pgd = pgd_offset(vma->vm_mm, address);
+	if (details && !details->check_mapping && !details->nonlinear_vma)
+		details = NULL;
+
+	BUG_ON(addr >= end);
 	tlb_start_vma(tlb, vma);
-	for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next <= address || next > end)
-			next = end;
-		zap_pud_range(tlb, pgd, address, next, details);
-		address = next;
-		pgd++;
-	}
+	pgd = pgd_offset(vma->vm_mm, addr);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		zap_pud_range(tlb, pgd, addr, next, details);
+	} while (pgd++, addr = next, addr != end);
 	tlb_end_vma(tlb, vma);
 }
 
@@ -619,7 +655,7 @@ static void unmap_page_range(struct mmu_
  * @nr_accounted: Place number of unmapped pages in vm-accountable vma's here
  * @details: details of nonlinear truncation or shared cache invalidation
  *
- * Returns the number of vma's which were covered by the unmapping.
+ * Returns the end address of the unmapping (restart addr if interrupted).
  *
  * Unmap all pages in the vma list.  Called under page_table_lock.
  *
@@ -636,7 +672,7 @@ static void unmap_page_range(struct mmu_
  * ensure that any thus-far unmapped pages are flushed before unmap_vmas()
  * drops the lock and schedules.
  */
-int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm,
+unsigned long unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm,
 		struct vm_area_struct *vma, unsigned long start_addr,
 		unsigned long end_addr, unsigned long *nr_accounted,
 		struct zap_details *details)
@@ -644,12 +680,11 @@ int unmap_vmas(struct mmu_gather **tlbp,
 	unsigned long zap_bytes = ZAP_BLOCK_SIZE;
 	unsigned long tlb_start = 0;	/* For tlb_finish_mmu */
 	int tlb_start_valid = 0;
-	int ret = 0;
+	unsigned long start = start_addr;
 	spinlock_t *i_mmap_lock = details? details->i_mmap_lock: NULL;
 	int fullmm = tlb_is_full_mm(*tlbp);
 
 	for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) {
-		unsigned long start;
 		unsigned long end;
 
 		start = max(vma->vm_start, start_addr);
@@ -662,7 +697,6 @@ int unmap_vmas(struct mmu_gather **tlbp,
 		if (vma->vm_flags & VM_ACCOUNT)
 			*nr_accounted += (end - start) >> PAGE_SHIFT;
 
-		ret++;
 		while (start != end) {
 			unsigned long block;
 
@@ -693,7 +727,6 @@ int unmap_vmas(struct mmu_gather **tlbp,
 				if (i_mmap_lock) {
 					/* must reset count of rss freed */
 					*tlbp = tlb_gather_mmu(mm, fullmm);
-					details->break_addr = start;
 					goto out;
 				}
 				spin_unlock(&mm->page_table_lock);
@@ -707,7 +740,7 @@ int unmap_vmas(struct mmu_gather **tlbp,
 		}
 	}
 out:
-	return ret;
+	return start;	/* which is now the end (or restart) address */
 }
 
 /**
@@ -717,7 +750,7 @@ out:
  * @size: number of bytes to zap
  * @details: details of nonlinear truncation or shared cache invalidation
  */
-void zap_page_range(struct vm_area_struct *vma, unsigned long address,
+unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *details)
 {
 	struct mm_struct *mm = vma->vm_mm;
@@ -727,16 +760,16 @@ void zap_page_range(struct vm_area_struc
 
 	if (is_vm_hugetlb_page(vma)) {
 		zap_hugepage_range(vma, address, size);
-		return;
+		return end;
 	}
 
 	lru_add_drain();
 	spin_lock(&mm->page_table_lock);
 	tlb = tlb_gather_mmu(mm, 0);
-	unmap_vmas(&tlb, mm, vma, address, end, &nr_accounted, details);
+	end = unmap_vmas(&tlb, mm, vma, address, end, &nr_accounted, details);
 	tlb_finish_mmu(tlb, address, end);
-	acct_update_integrals();
 	spin_unlock(&mm->page_table_lock);
+	return end;
 }
 
 /*
@@ -987,111 +1020,78 @@ out:
 
 EXPORT_SYMBOL(get_user_pages);
 
-static void zeromap_pte_range(pte_t * pte, unsigned long address,
-                                     unsigned long size, pgprot_t prot)
+static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
+			unsigned long addr, unsigned long end, pgprot_t prot)
 {
-	unsigned long end;
+	pte_t *pte;
 
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
+	pte = pte_alloc_map(mm, pmd, addr);
+	if (!pte)
+		return -ENOMEM;
 	do {
-		pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address), prot));
+		pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(addr), prot));
 		BUG_ON(!pte_none(*pte));
-		set_pte(pte, zero_pte);
-		address += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
-}
-
-static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd,
-		unsigned long address, unsigned long size, pgprot_t prot)
-{
-	unsigned long base, end;
-
-	base = address & PUD_MASK;
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
+		set_pte_at(mm, addr, pte, zero_pte);
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+	pte_unmap(pte - 1);
+	return 0;
+}
+
+static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
+			unsigned long addr, unsigned long end, pgprot_t prot)
+{
+	pmd_t *pmd;
+	unsigned long next;
+
+	pmd = pmd_alloc(mm, pud, addr);
+	if (!pmd)
+		return -ENOMEM;
 	do {
-		pte_t * pte = pte_alloc_map(mm, pmd, base + address);
-		if (!pte)
+		next = pmd_addr_end(addr, end);
+		if (zeromap_pte_range(mm, pmd, addr, next, prot))
 			return -ENOMEM;
-		zeromap_pte_range(pte, base + address, end - address, prot);
-		pte_unmap(pte);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
+	} while (pmd++, addr = next, addr != end);
 	return 0;
 }
 
-static inline int zeromap_pud_range(struct mm_struct *mm, pud_t * pud,
-				    unsigned long address,
-                                    unsigned long size, pgprot_t prot)
-{
-	unsigned long base, end;
-	int error = 0;
-
-	base = address & PGDIR_MASK;
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
+static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
+			unsigned long addr, unsigned long end, pgprot_t prot)
+{
+	pud_t *pud;
+	unsigned long next;
+
+	pud = pud_alloc(mm, pgd, addr);
+	if (!pud)
+		return -ENOMEM;
 	do {
-		pmd_t * pmd = pmd_alloc(mm, pud, base + address);
-		error = -ENOMEM;
-		if (!pmd)
-			break;
-		error = zeromap_pmd_range(mm, pmd, base + address,
-					  end - address, prot);
-		if (error)
-			break;
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && (address < end));
+		next = pud_addr_end(addr, end);
+		if (zeromap_pmd_range(mm, pud, addr, next, prot))
+			return -ENOMEM;
+	} while (pud++, addr = next, addr != end);
 	return 0;
 }
 
-int zeromap_page_range(struct vm_area_struct *vma, unsigned long address,
-					unsigned long size, pgprot_t prot)
+int zeromap_page_range(struct vm_area_struct *vma,
+			unsigned long addr, unsigned long size, pgprot_t prot)
 {
-	int i;
-	int error = 0;
-	pgd_t * pgd;
-	unsigned long beg = address;
-	unsigned long end = address + size;
+	pgd_t *pgd;
 	unsigned long next;
+	unsigned long end = addr + size;
 	struct mm_struct *mm = vma->vm_mm;
+	int err;
 
-	pgd = pgd_offset(mm, address);
-	flush_cache_range(vma, beg, end);
-	BUG_ON(address >= end);
-	BUG_ON(end > vma->vm_end);
-
+	BUG_ON(addr >= end);
+	pgd = pgd_offset(mm, addr);
+	flush_cache_range(vma, addr, end);
 	spin_lock(&mm->page_table_lock);
-	for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
-		pud_t *pud = pud_alloc(mm, pgd, address);
-		error = -ENOMEM;
-		if (!pud)
-			break;
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next <= beg || next > end)
-			next = end;
-		error = zeromap_pud_range(mm, pud, address,
-						next - address, prot);
-		if (error)
+	do {
+		next = pgd_addr_end(addr, end);
+		err = zeromap_pud_range(mm, pgd, addr, next, prot);
+		if (err)
 			break;
-		address = next;
-		pgd++;
-	}
-	/*
-	 * Why flush? zeromap_pte_range has a BUG_ON for !pte_none()
-	 */
-	flush_tlb_range(vma, beg, end);
+	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&mm->page_table_lock);
-	return error;
+	return err;
 }
 
 /*
@@ -1099,95 +1099,74 @@ int zeromap_page_range(struct vm_area_st
  * mappings are removed. any references to nonexistent pages results
  * in null mappings (currently treated as "copy-on-access")
  */
-static inline void
-remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
-		unsigned long pfn, pgprot_t prot)
+static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
+			unsigned long addr, unsigned long end,
+			unsigned long pfn, pgprot_t prot)
 {
-	unsigned long end;
+	pte_t *pte;
 
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
+	pte = pte_alloc_map(mm, pmd, addr);
+	if (!pte)
+		return -ENOMEM;
 	do {
 		BUG_ON(!pte_none(*pte));
 		if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn)))
- 			set_pte(pte, pfn_pte(pfn, prot));
-		address += PAGE_SIZE;
+			set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
 		pfn++;
-		pte++;
-	} while (address && (address < end));
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+	pte_unmap(pte - 1);
+	return 0;
 }
 
-static inline int
-remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address,
-		unsigned long size, unsigned long pfn, pgprot_t prot)
+static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
+			unsigned long addr, unsigned long end,
+			unsigned long pfn, pgprot_t prot)
 {
-	unsigned long base, end;
+	pmd_t *pmd;
+	unsigned long next;
 
-	base = address & PUD_MASK;
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
-	pfn -= (address >> PAGE_SHIFT);
+	pfn -= addr >> PAGE_SHIFT;
+	pmd = pmd_alloc(mm, pud, addr);
+	if (!pmd)
+		return -ENOMEM;
 	do {
-		pte_t * pte = pte_alloc_map(mm, pmd, base + address);
-		if (!pte)
+		next = pmd_addr_end(addr, end);
+		if (remap_pte_range(mm, pmd, addr, next,
+				pfn + (addr >> PAGE_SHIFT), prot))
 			return -ENOMEM;
-		remap_pte_range(pte, base + address, end - address,
-				(address >> PAGE_SHIFT) + pfn, prot);
-		pte_unmap(pte);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
+	} while (pmd++, addr = next, addr != end);
 	return 0;
 }
 
-static inline int remap_pud_range(struct mm_struct *mm, pud_t * pud,
-				  unsigned long address, unsigned long size,
-				  unsigned long pfn, pgprot_t prot)
-{
-	unsigned long base, end;
-	int error;
-
-	base = address & PGDIR_MASK;
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	pfn -= address >> PAGE_SHIFT;
+static inline int remap_pud_range(struct mm_struct *mm, pgd_t *pgd,
+			unsigned long addr, unsigned long end,
+			unsigned long pfn, pgprot_t prot)
+{
+	pud_t *pud;
+	unsigned long next;
+
+	pfn -= addr >> PAGE_SHIFT;
+	pud = pud_alloc(mm, pgd, addr);
+	if (!pud)
+		return -ENOMEM;
 	do {
-		pmd_t *pmd = pmd_alloc(mm, pud, base+address);
-		error = -ENOMEM;
-		if (!pmd)
-			break;
-		error = remap_pmd_range(mm, pmd, base + address, end - address,
-				(address >> PAGE_SHIFT) + pfn, prot);
-		if (error)
-			break;
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && (address < end));
-	return error;
+		next = pud_addr_end(addr, end);
+		if (remap_pmd_range(mm, pud, addr, next,
+				pfn + (addr >> PAGE_SHIFT), prot))
+			return -ENOMEM;
+	} while (pud++, addr = next, addr != end);
+	return 0;
 }
 
 /*  Note: this is only safe if the mm semaphore is held when called. */
-int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 		    unsigned long pfn, unsigned long size, pgprot_t prot)
 {
-	int error = 0;
 	pgd_t *pgd;
-	unsigned long beg = from;
-	unsigned long end = from + size;
 	unsigned long next;
+	unsigned long end = addr + size;
 	struct mm_struct *mm = vma->vm_mm;
-	int i;
-
-	pfn -= from >> PAGE_SHIFT;
-	pgd = pgd_offset(mm, from);
-	flush_cache_range(vma, beg, end);
-	BUG_ON(from >= end);
+	int err;
 
 	/*
 	 * Physically remapped pages are special. Tell the
@@ -1199,31 +1178,21 @@ int remap_pfn_range(struct vm_area_struc
 	 */
 	vma->vm_flags |= VM_IO | VM_RESERVED;
 
+	BUG_ON(addr >= end);
+	pfn -= addr >> PAGE_SHIFT;
+	pgd = pgd_offset(mm, addr);
+	flush_cache_range(vma, addr, end);
 	spin_lock(&mm->page_table_lock);
-	for (i = pgd_index(beg); i <= pgd_index(end-1); i++) {
-		pud_t *pud = pud_alloc(mm, pgd, from);
-		error = -ENOMEM;
-		if (!pud)
-			break;
-		next = (from + PGDIR_SIZE) & PGDIR_MASK;
-		if (next > end || next <= from)
-			next = end;
-		error = remap_pud_range(mm, pud, from, end - from,
-					pfn + (from >> PAGE_SHIFT), prot);
-		if (error)
+	do {
+		next = pgd_addr_end(addr, end);
+		err = remap_pud_range(mm, pgd, addr, next,
+				pfn + (addr >> PAGE_SHIFT), prot);
+		if (err)
 			break;
-		from = next;
-		pgd++;
-	}
-	/*
-	 * Why flush? remap_pte_range has a BUG_ON for !pte_none()
-	 */
-	flush_tlb_range(vma, beg, end);
+	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&mm->page_table_lock);
-
-	return error;
+	return err;
 }
-
 EXPORT_SYMBOL(remap_pfn_range);
 
 /*
@@ -1247,11 +1216,11 @@ static inline void break_cow(struct vm_a
 {
 	pte_t entry;
 
-	flush_cache_page(vma, address);
 	entry = maybe_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)),
 			      vma);
 	ptep_establish(vma, address, page_table, entry);
 	update_mmu_cache(vma, address, entry);
+	lazy_mmu_prot_update(entry);
 }
 
 /*
@@ -1299,11 +1268,12 @@ static int do_wp_page(struct mm_struct *
 		int reuse = can_share_swap_page(old_page);
 		unlock_page(old_page);
 		if (reuse) {
-			flush_cache_page(vma, address);
+			flush_cache_page(vma, address, pfn);
 			entry = maybe_mkwrite(pte_mkyoung(pte_mkdirty(pte)),
 					      vma);
 			ptep_set_access_flags(vma, address, page_table, entry, 1);
 			update_mmu_cache(vma, address, entry);
+			lazy_mmu_prot_update(entry);
 			pte_unmap(page_table);
 			spin_unlock(&mm->page_table_lock);
 			return VM_FAULT_MINOR;
@@ -1337,13 +1307,12 @@ static int do_wp_page(struct mm_struct *
 	page_table = pte_offset_map(pmd, address);
 	if (likely(pte_same(*page_table, pte))) {
 		if (PageAnon(old_page))
-			mm->anon_rss--;
-		if (PageReserved(old_page)) {
-			++mm->rss;
-			acct_update_integrals();
-			update_mem_hiwater();
-		} else
+			dec_mm_counter(mm, anon_rss);
+		if (PageReserved(old_page))
+			inc_mm_counter(mm, rss);
+		else
 			page_remove_rmap(old_page);
+		flush_cache_page(vma, address, pfn);
 		break_cow(vma, new_page, address, page_table);
 		lru_cache_add_active(new_page);
 		page_add_anon_rmap(new_page, vma, address);
@@ -1387,7 +1356,7 @@ no_new_page:
  * i_mmap_lock.
  *
  * In order to make forward progress despite repeatedly restarting some
- * large vma, note the break_addr set by unmap_vmas when it breaks out:
+ * large vma, note the restart_addr from unmap_vmas when it breaks out:
  * and restart from that address when we reach that vma again.  It might
  * have been split or merged, shrunk or extended, but never shifted: so
  * restart_addr remains valid so long as it remains in the vma's range.
@@ -1425,8 +1394,8 @@ again:
 		}
 	}
 
-	details->break_addr = end_addr;
-	zap_page_range(vma, start_addr, end_addr - start_addr, details);
+	restart_addr = zap_page_range(vma, start_addr,
+					end_addr - start_addr, details);
 
 	/*
 	 * We cannot rely on the break test in unmap_vmas:
@@ -1437,14 +1406,14 @@ again:
 	need_break = need_resched() ||
 			need_lockbreak(details->i_mmap_lock);
 
-	if (details->break_addr >= end_addr) {
+	if (restart_addr >= end_addr) {
 		/* We have now completed this vma: mark it so */
 		vma->vm_truncate_count = details->truncate_count;
 		if (!need_break)
 			return 0;
 	} else {
 		/* Note restart_addr in vma's truncate_count field */
-		vma->vm_truncate_count = details->break_addr;
+		vma->vm_truncate_count = restart_addr;
 		if (!need_break)
 			goto again;
 	}
@@ -1732,12 +1701,13 @@ static int do_swap_page(struct mm_struct
 	spin_lock(&mm->page_table_lock);
 	page_table = pte_offset_map(pmd, address);
 	if (unlikely(!pte_same(*page_table, orig_pte))) {
-		pte_unmap(page_table);
-		spin_unlock(&mm->page_table_lock);
-		unlock_page(page);
-		page_cache_release(page);
 		ret = VM_FAULT_MINOR;
-		goto out;
+		goto out_nomap;
+	}
+
+	if (unlikely(!PageUptodate(page))) {
+		ret = VM_FAULT_SIGBUS;
+		goto out_nomap;
 	}
 
 	/* The page isn't present yet, go ahead with the fault. */
@@ -1746,10 +1716,7 @@ static int do_swap_page(struct mm_struct
 	if (vm_swap_full())
 		remove_exclusive_swap_page(page);
 
-	mm->rss++;
-	acct_update_integrals();
-	update_mem_hiwater();
-
+	inc_mm_counter(mm, rss);
 	pte = mk_pte(page, vma->vm_page_prot);
 	if (write_access && can_share_swap_page(page)) {
 		pte = maybe_mkwrite(pte_mkdirty(pte), vma);
@@ -1758,7 +1725,7 @@ static int do_swap_page(struct mm_struct
 	unlock_page(page);
 
 	flush_icache_page(vma, page);
-	set_pte(page_table, pte);
+	set_pte_at(mm, address, page_table, pte);
 	page_add_anon_rmap(page, vma, address);
 
 	if (write_access) {
@@ -1770,10 +1737,17 @@ static int do_swap_page(struct mm_struct
 
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, address, pte);
+	lazy_mmu_prot_update(pte);
 	pte_unmap(page_table);
 	spin_unlock(&mm->page_table_lock);
 out:
 	return ret;
+out_nomap:
+	pte_unmap(page_table);
+	spin_unlock(&mm->page_table_lock);
+	unlock_page(page);
+	page_cache_release(page);
+	goto out;
 }
 
 /*
@@ -1813,9 +1787,7 @@ do_anonymous_page(struct mm_struct *mm, 
 			spin_unlock(&mm->page_table_lock);
 			goto out;
 		}
-		mm->rss++;
-		acct_update_integrals();
-		update_mem_hiwater();
+		inc_mm_counter(mm, rss);
 		entry = maybe_mkwrite(pte_mkdirty(mk_pte(page,
 							 vma->vm_page_prot)),
 				      vma);
@@ -1824,11 +1796,12 @@ do_anonymous_page(struct mm_struct *mm, 
 		page_add_anon_rmap(page, vma, addr);
 	}
 
-	set_pte(page_table, entry);
+	set_pte_at(mm, addr, page_table, entry);
 	pte_unmap(page_table);
 
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
+	lazy_mmu_prot_update(entry);
 	spin_unlock(&mm->page_table_lock);
 out:
 	return VM_FAULT_MINOR;
@@ -1931,15 +1904,13 @@ retry:
 	/* Only go through if we didn't race with anybody else... */
 	if (pte_none(*page_table)) {
 		if (!PageReserved(new_page))
-			++mm->rss;
-		acct_update_integrals();
-		update_mem_hiwater();
+			inc_mm_counter(mm, rss);
 
 		flush_icache_page(vma, new_page);
 		entry = mk_pte(new_page, vma->vm_page_prot);
 		if (write_access)
 			entry = maybe_mkwrite(pte_mkdirty(entry), vma);
-		set_pte(page_table, entry);
+		set_pte_at(mm, address, page_table, entry);
 		if (anon) {
 			lru_cache_add_active(new_page);
 			page_add_anon_rmap(new_page, vma, address);
@@ -1956,6 +1927,7 @@ retry:
 
 	/* no need to invalidate: a not-present page shouldn't be cached */
 	update_mmu_cache(vma, address, entry);
+	lazy_mmu_prot_update(entry);
 	spin_unlock(&mm->page_table_lock);
 out:
 	return ret;
@@ -1983,7 +1955,7 @@ static int do_file_page(struct mm_struct
 	 */
 	if (!vma->vm_ops || !vma->vm_ops->populate || 
 			(write_access && !(vma->vm_flags & VM_SHARED))) {
-		pte_clear(pte);
+		pte_clear(mm, address, pte);
 		return do_no_page(mm, vma, address, write_access, pte, pmd);
 	}
 
@@ -2050,6 +2022,7 @@ static inline int handle_pte_fault(struc
 	entry = pte_mkyoung(entry);
 	ptep_set_access_flags(vma, address, pte, entry, write_access);
 	update_mmu_cache(vma, address, entry);
+	lazy_mmu_prot_update(entry);
 	pte_unmap(pte);
 	spin_unlock(&mm->page_table_lock);
 	return VM_FAULT_MINOR;
@@ -2099,15 +2072,12 @@ int handle_mm_fault(struct mm_struct *mm
 	return VM_FAULT_OOM;
 }
 
-#ifndef __ARCH_HAS_4LEVEL_HACK
+#ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.
  *
  * We've already handled the fast-path in-line, and we own the
  * page table lock.
- *
- * On a two-level or three-level page table, this ends up actually being
- * entirely optimized away.
  */
 pud_t fastcall *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
 {
@@ -2131,15 +2101,14 @@ pud_t fastcall *__pud_alloc(struct mm_st
  out:
 	return pud_offset(pgd, address);
 }
+#endif /* __PAGETABLE_PUD_FOLDED */
 
+#ifndef __PAGETABLE_PMD_FOLDED
 /*
  * Allocate page middle directory.
  *
  * We've already handled the fast-path in-line, and we own the
  * page table lock.
- *
- * On a two-level page table, this ends up actually being entirely
- * optimized away.
  */
 pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
 {
@@ -2155,38 +2124,24 @@ pmd_t fastcall *__pmd_alloc(struct mm_st
 	 * Because we dropped the lock, we should re-check the
 	 * entry, as somebody else could have populated it..
 	 */
+#ifndef __ARCH_HAS_4LEVEL_HACK
 	if (pud_present(*pud)) {
 		pmd_free(new);
 		goto out;
 	}
 	pud_populate(mm, pud, new);
- out:
-	return pmd_offset(pud, address);
-}
 #else
-pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
-{
-	pmd_t *new;
-
-	spin_unlock(&mm->page_table_lock);
-	new = pmd_alloc_one(mm, address);
-	spin_lock(&mm->page_table_lock);
-	if (!new)
-		return NULL;
-
-	/*
-	 * Because we dropped the lock, we should re-check the
-	 * entry, as somebody else could have populated it..
-	 */
 	if (pgd_present(*pud)) {
 		pmd_free(new);
 		goto out;
 	}
 	pgd_populate(mm, pud, new);
-out:
+#endif /* __ARCH_HAS_4LEVEL_HACK */
+
+ out:
 	return pmd_offset(pud, address);
 }
-#endif
+#endif /* __PAGETABLE_PMD_FOLDED */
 
 int make_pages_present(unsigned long addr, unsigned long end)
 {
@@ -2253,13 +2208,13 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
  * update_mem_hiwater
  *	- update per process rss and vm high water data
  */
-void update_mem_hiwater(void)
+void update_mem_hiwater(struct task_struct *tsk)
 {
-	struct task_struct *tsk = current;
-
 	if (tsk->mm) {
-		if (tsk->mm->hiwater_rss < tsk->mm->rss)
-			tsk->mm->hiwater_rss = tsk->mm->rss;
+		unsigned long rss = get_mm_counter(tsk->mm, rss);
+
+		if (tsk->mm->hiwater_rss < rss)
+			tsk->mm->hiwater_rss = rss;
 		if (tsk->mm->hiwater_vm < tsk->mm->total_vm)
 			tsk->mm->hiwater_vm = tsk->mm->total_vm;
 	}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -67,6 +67,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/nodemask.h>
+#include <linux/cpuset.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -167,6 +168,10 @@ static int get_nodes(unsigned long *node
 	if (copy_from_user(nodes, nmask, nlongs*sizeof(unsigned long)))
 		return -EFAULT;
 	nodes[nlongs-1] &= endmask;
+	/* Update current mems_allowed */
+	cpuset_update_current_mems_allowed();
+	/* Ignore nodes not set in current->mems_allowed */
+	cpuset_restrict_to_mems_allowed(nodes);
 	return mpol_check_policy(mode, nodes);
 }
 
@@ -643,7 +648,7 @@ get_vma_policy(struct vm_area_struct *vm
 }
 
 /* Return a zonelist representing a mempolicy */
-static struct zonelist *zonelist_policy(unsigned gfp, struct mempolicy *policy)
+static struct zonelist *zonelist_policy(unsigned int __nocast gfp, struct mempolicy *policy)
 {
 	int nd;
 
@@ -655,8 +660,10 @@ static struct zonelist *zonelist_policy(
 		break;
 	case MPOL_BIND:
 		/* Lower zones don't get a policy applied */
-		if (gfp >= policy_zone)
-			return policy->v.zonelist;
+		/* Careful: current->mems_allowed might have moved */
+		if ((gfp & GFP_ZONEMASK) >= policy_zone)
+			if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist))
+				return policy->v.zonelist;
 		/*FALL THROUGH*/
 	case MPOL_INTERLEAVE: /* should not happen */
 	case MPOL_DEFAULT:
@@ -705,7 +712,7 @@ static unsigned offset_il_node(struct me
 
 /* Allocate a page in interleaved policy.
    Own path because it needs to do special accounting. */
-static struct page *alloc_page_interleave(unsigned gfp, unsigned order, unsigned nid)
+static struct page *alloc_page_interleave(unsigned int __nocast gfp, unsigned order, unsigned nid)
 {
 	struct zonelist *zl;
 	struct page *page;
@@ -743,10 +750,12 @@ static struct page *alloc_page_interleav
  *	Should be called with the mm_sem of the vma hold.
  */
 struct page *
-alloc_page_vma(unsigned gfp, struct vm_area_struct *vma, unsigned long addr)
+alloc_page_vma(unsigned int __nocast gfp, struct vm_area_struct *vma, unsigned long addr)
 {
 	struct mempolicy *pol = get_vma_policy(vma, addr);
 
+	cpuset_update_current_mems_allowed();
+
 	if (unlikely(pol->policy == MPOL_INTERLEAVE)) {
 		unsigned nid;
 		if (vma) {
@@ -779,11 +788,17 @@ alloc_page_vma(unsigned gfp, struct vm_a
  *	Allocate a page from the kernel page pool.  When not in
  *	interrupt context and apply the current process NUMA policy.
  *	Returns NULL when no page can be allocated.
+ *
+ *	Don't call cpuset_update_current_mems_allowed() unless
+ *	1) it's ok to take cpuset_sem (can WAIT), and
+ *	2) allocating for current task (not interrupt).
  */
-struct page *alloc_pages_current(unsigned gfp, unsigned order)
+struct page *alloc_pages_current(unsigned int __nocast gfp, unsigned order)
 {
 	struct mempolicy *pol = current->mempolicy;
 
+	if ((gfp & __GFP_WAIT) && !in_interrupt())
+		cpuset_update_current_mems_allowed();
 	if (!pol || in_interrupt())
 		pol = &default_policy;
 	if (pol->policy == MPOL_INTERLEAVE)
diff --git a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -105,7 +105,7 @@ EXPORT_SYMBOL(mempool_create);
  * while this function is running. mempool_alloc() & mempool_free()
  * might be called (eg. from IRQ contexts) while this function executes.
  */
-int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
+int mempool_resize(mempool_t *pool, int new_min_nr, unsigned int __nocast gfp_mask)
 {
 	void *element;
 	void **new_elements;
@@ -114,8 +114,8 @@ int mempool_resize(mempool_t *pool, int 
 	BUG_ON(new_min_nr <= 0);
 
 	spin_lock_irqsave(&pool->lock, flags);
-	if (new_min_nr < pool->min_nr) {
-		while (pool->curr_nr > new_min_nr) {
+	if (new_min_nr <= pool->min_nr) {
+		while (new_min_nr < pool->curr_nr) {
 			element = remove_element(pool);
 			spin_unlock_irqrestore(&pool->lock, flags);
 			pool->free(element, pool->pool_data);
@@ -132,6 +132,12 @@ int mempool_resize(mempool_t *pool, int 
 		return -ENOMEM;
 
 	spin_lock_irqsave(&pool->lock, flags);
+	if (unlikely(new_min_nr <= pool->min_nr)) {
+		/* Raced, other resize will do our work */
+		spin_unlock_irqrestore(&pool->lock, flags);
+		kfree(new_elements);
+		goto out;
+	}
 	memcpy(new_elements, pool->elements,
 			pool->curr_nr * sizeof(*new_elements));
 	kfree(pool->elements);
@@ -149,7 +155,7 @@ int mempool_resize(mempool_t *pool, int 
 		} else {
 			spin_unlock_irqrestore(&pool->lock, flags);
 			pool->free(element, pool->pool_data);	/* Raced */
-			spin_lock_irqsave(&pool->lock, flags);
+			goto out;
 		}
 	}
 out_unlock:
@@ -187,36 +193,27 @@ EXPORT_SYMBOL(mempool_destroy);
  * *never* fails when called from process contexts. (it might
  * fail if called from an IRQ context.)
  */
-void * mempool_alloc(mempool_t *pool, int gfp_mask)
+void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask)
 {
 	void *element;
 	unsigned long flags;
 	DEFINE_WAIT(wait);
-	int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+	int gfp_temp;
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
+
+	gfp_mask |= __GFP_NOMEMALLOC;	/* don't allocate emergency reserves */
+	gfp_mask |= __GFP_NORETRY;	/* don't loop in __alloc_pages */
+	gfp_mask |= __GFP_NOWARN;	/* failures are OK */
+
+	gfp_temp = gfp_mask & ~(__GFP_WAIT|__GFP_IO);
+
 repeat_alloc:
-	element = pool->alloc(gfp_nowait|__GFP_NOWARN, pool->pool_data);
+
+	element = pool->alloc(gfp_temp, pool->pool_data);
 	if (likely(element != NULL))
 		return element;
 
-	/*
-	 * If the pool is less than 50% full and we can perform effective
-	 * page reclaim then try harder to allocate an element.
-	 */
-	mb();
-	if ((gfp_mask & __GFP_FS) && (gfp_mask != gfp_nowait) &&
-				(pool->curr_nr <= pool->min_nr/2)) {
-		element = pool->alloc(gfp_mask, pool->pool_data);
-		if (likely(element != NULL))
-			return element;
-	}
-
-	/*
-	 * Kick the VM at this point.
-	 */
-	wakeup_bdflush(0);
-
 	spin_lock_irqsave(&pool->lock, flags);
 	if (likely(pool->curr_nr)) {
 		element = remove_element(pool);
@@ -229,8 +226,10 @@ repeat_alloc:
 	if (!(gfp_mask & __GFP_WAIT))
 		return NULL;
 
+	/* Now start performing page reclaim */
+	gfp_temp = gfp_mask;
 	prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
-	mb();
+	smp_mb();
 	if (!pool->curr_nr)
 		io_schedule();
 	finish_wait(&pool->wait, &wait);
@@ -251,7 +250,7 @@ void mempool_free(void *element, mempool
 {
 	unsigned long flags;
 
-	mb();
+	smp_mb();
 	if (pool->curr_nr < pool->min_nr) {
 		spin_lock_irqsave(&pool->lock, flags);
 		if (pool->curr_nr < pool->min_nr) {
@@ -269,7 +268,7 @@ EXPORT_SYMBOL(mempool_free);
 /*
  * A commonly used alloc and free fn.
  */
-void *mempool_alloc_slab(int gfp_mask, void *pool_data)
+void *mempool_alloc_slab(unsigned int __nocast gfp_mask, void *pool_data)
 {
 	kmem_cache_t *mem = (kmem_cache_t *) pool_data;
 	return kmem_cache_alloc(mem, gfp_mask);
diff --git a/mm/mincore.c b/mm/mincore.c
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -97,8 +97,7 @@ static long mincore_vma(struct vm_area_s
  * return values:
  *  zero    - success
  *  -EFAULT - vec points to an illegal address
- *  -EINVAL - addr is not a multiple of PAGE_CACHE_SIZE,
- *		or len has a nonpositive value
+ *  -EINVAL - addr is not a multiple of PAGE_CACHE_SIZE
  *  -ENOMEM - Addresses in the range [addr, addr + len] are
  *		invalid for the address space of this process, or
  *		specify one or more pages which are not currently
@@ -119,17 +118,17 @@ asmlinkage long sys_mincore(unsigned lon
  	if (start & ~PAGE_CACHE_MASK)
 		goto einval;
 
-	if (start < FIRST_USER_PGD_NR * PGDIR_SIZE)
-		goto enomem;
-
 	limit = TASK_SIZE;
 	if (start >= limit)
 		goto enomem;
 
+	if (!len)
+		return 0;
+
 	max = limit - start;
 	len = PAGE_CACHE_ALIGN(len);
-	if (len > max)
-		goto einval;
+	if (len > max || !len)
+		goto enomem;
 
 	end = start + len;
 
diff --git a/mm/mlock.c b/mm/mlock.c
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -7,18 +7,32 @@
 
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/mempolicy.h>
 #include <linux/syscalls.h>
 
 
-static int mlock_fixup(struct vm_area_struct * vma, 
+static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
 	unsigned long start, unsigned long end, unsigned int newflags)
 {
 	struct mm_struct * mm = vma->vm_mm;
+	pgoff_t pgoff;
 	int pages;
 	int ret = 0;
 
-	if (newflags == vma->vm_flags)
+	if (newflags == vma->vm_flags) {
+		*prev = vma;
 		goto out;
+	}
+
+	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+	*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
+			  vma->vm_file, pgoff, vma_policy(vma));
+	if (*prev) {
+		vma = *prev;
+		goto success;
+	}
+
+	*prev = vma;
 
 	if (start != vma->vm_start) {
 		ret = split_vma(mm, vma, start, 1);
@@ -32,6 +46,7 @@ static int mlock_fixup(struct vm_area_st
 			goto out;
 	}
 
+success:
 	/*
 	 * vm_flags is protected by the mmap_sem held in write mode.
 	 * It's okay if try_to_unmap_one unmaps a page just after we
@@ -59,7 +74,7 @@ out:
 static int do_mlock(unsigned long start, size_t len, int on)
 {
 	unsigned long nstart, end, tmp;
-	struct vm_area_struct * vma, * next;
+	struct vm_area_struct * vma, * prev;
 	int error;
 
 	len = PAGE_ALIGN(len);
@@ -68,10 +83,13 @@ static int do_mlock(unsigned long start,
 		return -EINVAL;
 	if (end == start)
 		return 0;
-	vma = find_vma(current->mm, start);
+	vma = find_vma_prev(current->mm, start, &prev);
 	if (!vma || vma->vm_start > start)
 		return -ENOMEM;
 
+	if (start > vma->vm_start)
+		prev = vma;
+
 	for (nstart = start ; ; ) {
 		unsigned int newflags;
 
@@ -81,18 +99,19 @@ static int do_mlock(unsigned long start,
 		if (!on)
 			newflags &= ~VM_LOCKED;
 
-		if (vma->vm_end >= end) {
-			error = mlock_fixup(vma, nstart, end, newflags);
-			break;
-		}
-
 		tmp = vma->vm_end;
-		next = vma->vm_next;
-		error = mlock_fixup(vma, nstart, tmp, newflags);
+		if (tmp > end)
+			tmp = end;
+		error = mlock_fixup(vma, &prev, nstart, tmp, newflags);
 		if (error)
 			break;
 		nstart = tmp;
-		vma = next;
+		if (nstart < prev->vm_end)
+			nstart = prev->vm_end;
+		if (nstart >= end)
+			break;
+
+		vma = prev->vm_next;
 		if (!vma || vma->vm_start != nstart) {
 			error = -ENOMEM;
 			break;
@@ -141,7 +160,7 @@ asmlinkage long sys_munlock(unsigned lon
 
 static int do_mlockall(int flags)
 {
-	struct vm_area_struct * vma;
+	struct vm_area_struct * vma, * prev = NULL;
 	unsigned int def_flags = 0;
 
 	if (flags & MCL_FUTURE)
@@ -150,7 +169,7 @@ static int do_mlockall(int flags)
 	if (flags == MCL_FUTURE)
 		goto out;
 
-	for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
+	for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
 		unsigned int newflags;
 
 		newflags = vma->vm_flags | VM_LOCKED;
@@ -158,7 +177,7 @@ static int do_mlockall(int flags)
 			newflags &= ~VM_LOCKED;
 
 		/* Ignore errors */
-		mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
+		mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
 	}
 out:
 	return 0;
diff --git a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -21,7 +21,6 @@
 #include <linux/hugetlb.h>
 #include <linux/profile.h>
 #include <linux/module.h>
-#include <linux/acct.h>
 #include <linux/mount.h>
 #include <linux/mempolicy.h>
 #include <linux/rmap.h>
@@ -30,6 +29,10 @@
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
 
+static void unmap_region(struct mm_struct *mm,
+		struct vm_area_struct *vma, struct vm_area_struct *prev,
+		unsigned long start, unsigned long end);
+
 /*
  * WARNING: the debugging will use recursive algorithms so never enable this
  * unless you know what you are doing.
@@ -873,7 +876,7 @@ unsigned long do_mmap_pgoff(struct file 
 	int error;
 	struct rb_node ** rb_link, * rb_parent;
 	int accountable = 1;
-	unsigned long charged = 0;
+	unsigned long charged = 0, reqprot = prot;
 
 	if (file) {
 		if (is_file_hugepages(file))
@@ -897,16 +900,16 @@ unsigned long do_mmap_pgoff(struct file 
 			prot |= PROT_EXEC;
 
 	if (!len)
-		return addr;
+		return -EINVAL;
 
 	/* Careful about overflows.. */
 	len = PAGE_ALIGN(len);
 	if (!len || len > TASK_SIZE)
-		return -EINVAL;
+		return -ENOMEM;
 
 	/* offset overflow? */
 	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
-		return -EINVAL;
+               return -EOVERFLOW;
 
 	/* Too many mappings? */
 	if (mm->map_count > sysctl_max_map_count)
@@ -934,9 +937,10 @@ unsigned long do_mmap_pgoff(struct file 
 	/* mlock MCL_FUTURE? */
 	if (vm_flags & VM_LOCKED) {
 		unsigned long locked, lock_limit;
-		locked = mm->locked_vm << PAGE_SHIFT;
+		locked = len >> PAGE_SHIFT;
+		locked += mm->locked_vm;
 		lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
-		locked += len;
+		lock_limit >>= PAGE_SHIFT;
 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			return -EAGAIN;
 	}
@@ -991,7 +995,7 @@ unsigned long do_mmap_pgoff(struct file 
 		}
 	}
 
-	error = security_file_mmap(file, prot, flags);
+	error = security_file_mmap(file, reqprot, prot, flags);
 	if (error)
 		return error;
 		
@@ -1006,8 +1010,7 @@ munmap_back:
 	}
 
 	/* Check against address space limit. */
-	if ((mm->total_vm << PAGE_SHIFT) + len
-	    > current->signal->rlim[RLIMIT_AS].rlim_cur)
+	if (!may_expand_vm(mm, len >> PAGE_SHIFT))
 		return -ENOMEM;
 
 	if (accountable && (!(flags & MAP_NORESERVE) ||
@@ -1121,8 +1124,6 @@ out:	
 					pgoff, flags & MAP_NONBLOCK);
 		down_write(&mm->mmap_sem);
 	}
-	acct_update_integrals();
-	update_mem_hiwater();
 	return addr;
 
 unmap_and_free_vma:
@@ -1132,7 +1133,8 @@ unmap_and_free_vma:
 	fput(file);
 
 	/* Undo any partial mapping done by a device driver. */
-	zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
+	unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
+	charged = 0;
 free_vma:
 	kmem_cache_free(vm_area_cachep, vma);
 unacct_error:
@@ -1221,19 +1223,14 @@ arch_get_unmapped_area_topdown(struct fi
 			  const unsigned long len, const unsigned long pgoff,
 			  const unsigned long flags)
 {
-	struct vm_area_struct *vma, *prev_vma;
+	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
-	unsigned long base = mm->mmap_base, addr = addr0;
-	int first_time = 1;
+	unsigned long addr = addr0;
 
 	/* requested length too big for entire address space */
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
-	/* dont allow allocations above current base */
-	if (mm->free_area_cache > base)
-		mm->free_area_cache = base;
-
 	/* requesting a specific address */
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
@@ -1243,48 +1240,34 @@ arch_get_unmapped_area_topdown(struct fi
 			return addr;
 	}
 
-try_again:
+	/* either no address requested or can't fit in requested address hole */
+	addr = mm->free_area_cache;
+
 	/* make sure it can fit in the remaining address space */
-	if (mm->free_area_cache < len)
-		goto fail;
+	if (addr > len) {
+		vma = find_vma(mm, addr-len);
+		if (!vma || addr <= vma->vm_start)
+			/* remember the address as a hint for next time */
+			return (mm->free_area_cache = addr-len);
+	}
+
+	addr = mm->mmap_base-len;
 
-	/* either no address requested or cant fit in requested address hole */
-	addr = (mm->free_area_cache - len) & PAGE_MASK;
 	do {
 		/*
 		 * Lookup failure means no vma is above this address,
-		 * i.e. return with success:
+		 * else if new region fits below vma->vm_start,
+		 * return with success:
 		 */
- 	 	if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
-			return addr;
-
-		/*
-		 * new region fits between prev_vma->vm_end and
-		 * vma->vm_start, use it:
-		 */
-		if (addr+len <= vma->vm_start &&
-				(!prev_vma || (addr >= prev_vma->vm_end)))
+		vma = find_vma(mm, addr);
+		if (!vma || addr+len <= vma->vm_start)
 			/* remember the address as a hint for next time */
 			return (mm->free_area_cache = addr);
-		else
-			/* pull free_area_cache down to the first hole */
-			if (mm->free_area_cache == vma->vm_end)
-				mm->free_area_cache = vma->vm_start;
 
 		/* try just below the current vma->vm_start */
 		addr = vma->vm_start-len;
-	} while (len <= vma->vm_start);
+	} while (len < vma->vm_start);
 
-fail:
-	/*
-	 * if hint left us with no space for the requested
-	 * mapping then try again:
-	 */
-	if (first_time) {
-		mm->free_area_cache = base;
-		first_time = 0;
-		goto try_again;
-	}
 	/*
 	 * A failed mmap() very likely causes application failure,
 	 * so fall back to the bottom-up function here. This scenario
@@ -1296,7 +1279,7 @@ fail:
 	/*
 	 * Restore the topdown base:
 	 */
-	mm->free_area_cache = base;
+	mm->free_area_cache = mm->mmap_base;
 
 	return addr;
 }
@@ -1309,43 +1292,50 @@ void arch_unmap_area_topdown(struct vm_a
 	 */
 	if (area->vm_end > area->vm_mm->free_area_cache)
 		area->vm_mm->free_area_cache = area->vm_end;
+
+	/* dont allow allocations above current base */
+	if (area->vm_mm->free_area_cache > area->vm_mm->mmap_base)
+		area->vm_mm->free_area_cache = area->vm_mm->mmap_base;
 }
 
 unsigned long
 get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
 		unsigned long pgoff, unsigned long flags)
 {
-	if (flags & MAP_FIXED) {
-		unsigned long ret;
+	unsigned long ret;
 
-		if (addr > TASK_SIZE - len)
-			return -ENOMEM;
-		if (addr & ~PAGE_MASK)
-			return -EINVAL;
-		if (file && is_file_hugepages(file))  {
-			/*
-			 * Check if the given range is hugepage aligned, and
-			 * can be made suitable for hugepages.
-			 */
-			ret = prepare_hugepage_range(addr, len);
-		} else {
-			/*
-			 * Ensure that a normal request is not falling in a
-			 * reserved hugepage range.  For some archs like IA-64,
-			 * there is a separate region for hugepages.
-			 */
-			ret = is_hugepage_only_range(addr, len);
-		}
-		if (ret)
-			return -EINVAL;
-		return addr;
-	}
+	if (!(flags & MAP_FIXED)) {
+		unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
-	if (file && file->f_op && file->f_op->get_unmapped_area)
-		return file->f_op->get_unmapped_area(file, addr, len,
-						pgoff, flags);
+		get_area = current->mm->get_unmapped_area;
+		if (file && file->f_op && file->f_op->get_unmapped_area)
+			get_area = file->f_op->get_unmapped_area;
+		addr = get_area(file, addr, len, pgoff, flags);
+		if (IS_ERR_VALUE(addr))
+			return addr;
+	}
 
-	return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
+	if (addr > TASK_SIZE - len)
+		return -ENOMEM;
+	if (addr & ~PAGE_MASK)
+		return -EINVAL;
+	if (file && is_file_hugepages(file))  {
+		/*
+		 * Check if the given range is hugepage aligned, and
+		 * can be made suitable for hugepages.
+		 */
+		ret = prepare_hugepage_range(addr, len);
+	} else {
+		/*
+		 * Ensure that a normal request is not falling in a
+		 * reserved hugepage range.  For some archs like IA-64,
+		 * there is a separate region for hugepages.
+		 */
+		ret = is_hugepage_only_range(current->mm, addr, len);
+	}
+	if (ret)
+		return -EINVAL;
+	return addr;
 }
 
 EXPORT_SYMBOL(get_unmapped_area);
@@ -1434,7 +1424,7 @@ static int acct_stack_growth(struct vm_a
 	struct rlimit *rlim = current->signal->rlim;
 
 	/* address space limit tests */
-	if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT)
+	if (!may_expand_vm(mm, grow))
 		return -ENOMEM;
 
 	/* Stack limit test */
@@ -1463,8 +1453,6 @@ static int acct_stack_growth(struct vm_a
 	if (vma->vm_flags & VM_LOCKED)
 		mm->locked_vm += grow;
 	__vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow);
-	acct_update_integrals();
-	update_mem_hiwater();
 	return 0;
 }
 
@@ -1592,66 +1580,6 @@ find_extend_vma(struct mm_struct * mm, u
 }
 #endif
 
-/*
- * Try to free as many page directory entries as we can,
- * without having to work very hard at actually scanning
- * the page tables themselves.
- *
- * Right now we try to free page tables if we have a nice
- * PGDIR-aligned area that got free'd up. We could be more
- * granular if we want to, but this is fast and simple,
- * and covers the bad cases.
- *
- * "prev", if it exists, points to a vma before the one
- * we just free'd - but there's no telling how much before.
- */
-static void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
-	unsigned long start, unsigned long end)
-{
-	unsigned long first = start & PGDIR_MASK;
-	unsigned long last = end + PGDIR_SIZE - 1;
-	struct mm_struct *mm = tlb->mm;
-
-	if (last > MM_VM_SIZE(mm) || last < end)
-		last = MM_VM_SIZE(mm);
-
-	if (!prev) {
-		prev = mm->mmap;
-		if (!prev)
-			goto no_mmaps;
-		if (prev->vm_end > start) {
-			if (last > prev->vm_start)
-				last = prev->vm_start;
-			goto no_mmaps;
-		}
-	}
-	for (;;) {
-		struct vm_area_struct *next = prev->vm_next;
-
-		if (next) {
-			if (next->vm_start < start) {
-				prev = next;
-				continue;
-			}
-			if (last > next->vm_start)
-				last = next->vm_start;
-		}
-		if (prev->vm_end > first)
-			first = prev->vm_end;
-		break;
-	}
-no_mmaps:
-	if (last < first)	/* for arches with discontiguous pgd indices */
-		return;
-	if (first < FIRST_USER_PGD_NR * PGDIR_SIZE)
-		first = FIRST_USER_PGD_NR * PGDIR_SIZE;
-	/* No point trying to free anything if we're in the same pte page */
-	if ((first & PMD_MASK) < (last & PMD_MASK)) {
-		clear_page_range(tlb, first, last);
-		flush_tlb_pgtables(mm, first, last);
-	}
-}
-
 /* Normal function to fix up a mapping
  * This function is the default for when an area has no specific
  * function.  This may be used as part of a more specific routine.
@@ -1677,14 +1605,13 @@ static void unmap_vma(struct mm_struct *
  * Ok - we have the memory areas we should free on the 'free' list,
  * so release them, and do the vma updates.
  */
-static void unmap_vma_list(struct mm_struct *mm,
-	struct vm_area_struct *mpnt)
+static void unmap_vma_list(struct mm_struct *mm, struct vm_area_struct *vma)
 {
 	do {
-		struct vm_area_struct *next = mpnt->vm_next;
-		unmap_vma(mm, mpnt);
-		mpnt = next;
-	} while (mpnt != NULL);
+		struct vm_area_struct *next = vma->vm_next;
+		unmap_vma(mm, vma);
+		vma = next;
+	} while (vma);
 	validate_mm(mm);
 }
 
@@ -1694,24 +1621,22 @@ static void unmap_vma_list(struct mm_str
  * Called with the page table lock held.
  */
 static void unmap_region(struct mm_struct *mm,
-	struct vm_area_struct *vma,
-	struct vm_area_struct *prev,
-	unsigned long start,
-	unsigned long end)
+		struct vm_area_struct *vma, struct vm_area_struct *prev,
+		unsigned long start, unsigned long end)
 {
+	struct vm_area_struct *next = prev? prev->vm_next: mm->mmap;
 	struct mmu_gather *tlb;
 	unsigned long nr_accounted = 0;
 
 	lru_add_drain();
+	spin_lock(&mm->page_table_lock);
 	tlb = tlb_gather_mmu(mm, 0);
 	unmap_vmas(&tlb, mm, vma, start, end, &nr_accounted, NULL);
 	vm_unacct_memory(nr_accounted);
-
-	if (is_hugepage_only_range(start, end - start))
-		hugetlb_free_pgtables(tlb, prev, start, end);
-	else
-		free_pgtables(tlb, prev, start, end);
+	free_pgtables(&tlb, vma, prev? prev->vm_end: FIRST_USER_ADDRESS,
+				 next? next->vm_start: 0);
 	tlb_finish_mmu(tlb, start, end);
+	spin_unlock(&mm->page_table_lock);
 }
 
 /*
@@ -1797,7 +1722,7 @@ int split_vma(struct mm_struct * mm, str
 int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
 {
 	unsigned long end;
-	struct vm_area_struct *mpnt, *prev, *last;
+	struct vm_area_struct *vma, *prev, *last;
 
 	if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE-start)
 		return -EINVAL;
@@ -1806,14 +1731,14 @@ int do_munmap(struct mm_struct *mm, unsi
 		return -EINVAL;
 
 	/* Find the first overlapping VMA */
-	mpnt = find_vma_prev(mm, start, &prev);
-	if (!mpnt)
+	vma = find_vma_prev(mm, start, &prev);
+	if (!vma)
 		return 0;
-	/* we have  start < mpnt->vm_end  */
+	/* we have  start < vma->vm_end  */
 
 	/* if it doesn't overlap, we have nothing.. */
 	end = start + len;
-	if (mpnt->vm_start >= end)
+	if (vma->vm_start >= end)
 		return 0;
 
 	/*
@@ -1823,11 +1748,11 @@ int do_munmap(struct mm_struct *mm, unsi
 	 * unmapped vm_area_struct will remain in use: so lower split_vma
 	 * places tmp vma above, and higher split_vma places tmp vma below.
 	 */
-	if (start > mpnt->vm_start) {
-		int error = split_vma(mm, mpnt, start, 0);
+	if (start > vma->vm_start) {
+		int error = split_vma(mm, vma, start, 0);
 		if (error)
 			return error;
-		prev = mpnt;
+		prev = vma;
 	}
 
 	/* Does it split the last one? */
@@ -1837,18 +1762,16 @@ int do_munmap(struct mm_struct *mm, unsi
 		if (error)
 			return error;
 	}
-	mpnt = prev? prev->vm_next: mm->mmap;
+	vma = prev? prev->vm_next: mm->mmap;
 
 	/*
 	 * Remove the vma's, and unmap the actual pages
 	 */
-	detach_vmas_to_be_unmapped(mm, mpnt, prev, end);
-	spin_lock(&mm->page_table_lock);
-	unmap_region(mm, mpnt, prev, start, end);
-	spin_unlock(&mm->page_table_lock);
+	detach_vmas_to_be_unmapped(mm, vma, prev, end);
+	unmap_region(mm, vma, prev, start, end);
 
 	/* Fix up all other VM information */
-	unmap_vma_list(mm, mpnt);
+	unmap_vma_list(mm, vma);
 
 	return 0;
 }
@@ -1903,9 +1826,10 @@ unsigned long do_brk(unsigned long addr,
 	 */
 	if (mm->def_flags & VM_LOCKED) {
 		unsigned long locked, lock_limit;
-		locked = mm->locked_vm << PAGE_SHIFT;
+		locked = len >> PAGE_SHIFT;
+		locked += mm->locked_vm;
 		lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
-		locked += len;
+		lock_limit >>= PAGE_SHIFT;
 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			return -EAGAIN;
 	}
@@ -1928,8 +1852,7 @@ unsigned long do_brk(unsigned long addr,
 	}
 
 	/* Check against address space limits *after* clearing old maps... */
-	if ((mm->total_vm << PAGE_SHIFT) + len
-	    > current->signal->rlim[RLIMIT_AS].rlim_cur)
+	if (!may_expand_vm(mm, len >> PAGE_SHIFT))
 		return -ENOMEM;
 
 	if (mm->map_count > sysctl_max_map_count)
@@ -1968,8 +1891,6 @@ out:
 		mm->locked_vm += len >> PAGE_SHIFT;
 		make_pages_present(addr, addr + len);
 	}
-	acct_update_integrals();
-	update_mem_hiwater();
 	return addr;
 }
 
@@ -1979,28 +1900,25 @@ EXPORT_SYMBOL(do_brk);
 void exit_mmap(struct mm_struct *mm)
 {
 	struct mmu_gather *tlb;
-	struct vm_area_struct *vma;
+	struct vm_area_struct *vma = mm->mmap;
 	unsigned long nr_accounted = 0;
+	unsigned long end;
 
 	lru_add_drain();
 
 	spin_lock(&mm->page_table_lock);
 
-	tlb = tlb_gather_mmu(mm, 1);
 	flush_cache_mm(mm);
-	/* Use ~0UL here to ensure all VMAs in the mm are unmapped */
-	mm->map_count -= unmap_vmas(&tlb, mm, mm->mmap, 0,
-					~0UL, &nr_accounted, NULL);
+	tlb = tlb_gather_mmu(mm, 1);
+	/* Use -1 here to ensure all VMAs in the mm are unmapped */
+	end = unmap_vmas(&tlb, mm, vma, 0, -1, &nr_accounted, NULL);
 	vm_unacct_memory(nr_accounted);
-	BUG_ON(mm->map_count);	/* This is just debugging */
-	clear_page_range(tlb, FIRST_USER_PGD_NR * PGDIR_SIZE, MM_VM_SIZE(mm));
-	
-	tlb_finish_mmu(tlb, 0, MM_VM_SIZE(mm));
+	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
+	tlb_finish_mmu(tlb, 0, end);
 
-	vma = mm->mmap;
 	mm->mmap = mm->mmap_cache = NULL;
 	mm->mm_rb = RB_ROOT;
-	mm->rss = 0;
+	set_mm_counter(mm, rss, 0);
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
 
@@ -2015,6 +1933,8 @@ void exit_mmap(struct mm_struct *mm)
 		remove_vm_struct(vma);
 		vma = next;
 	}
+
+	BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
 }
 
 /* Insert vm structure into process list sorted by address
@@ -2102,3 +2022,19 @@ struct vm_area_struct *copy_vma(struct v
 	}
 	return new_vma;
 }
+
+/*
+ * Return true if the calling process may expand its vm space by the passed
+ * number of pages
+ */
+int may_expand_vm(struct mm_struct *mm, unsigned long npages)
+{
+	unsigned long cur = mm->total_vm;	/* pages */
+	unsigned long lim;
+
+	lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+
+	if (cur + npages > lim)
+		return 0;
+	return 1;
+}
diff --git a/mm/mprotect.c b/mm/mprotect.c
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -25,116 +25,77 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static inline void
-change_pte_range(pmd_t *pmd, unsigned long address,
-		unsigned long size, pgprot_t newprot)
+static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
+		unsigned long addr, unsigned long end, pgprot_t newprot)
 {
-	pte_t * pte;
-	unsigned long end;
+	pte_t *pte;
 
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	pte = pte_offset_map(pmd, address);
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
+	pte = pte_offset_map(pmd, addr);
 	do {
 		if (pte_present(*pte)) {
-			pte_t entry;
+			pte_t ptent;
 
 			/* Avoid an SMP race with hardware updated dirty/clean
 			 * bits by wiping the pte and then setting the new pte
 			 * into place.
 			 */
-			entry = ptep_get_and_clear(pte);
-			set_pte(pte, pte_modify(entry, newprot));
+			ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot);
+			set_pte_at(mm, addr, pte, ptent);
+			lazy_mmu_prot_update(ptent);
 		}
-		address += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
+	} while (pte++, addr += PAGE_SIZE, addr != end);
 	pte_unmap(pte - 1);
 }
 
-static inline void
-change_pmd_range(pud_t *pud, unsigned long address,
-		unsigned long size, pgprot_t newprot)
+static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud,
+		unsigned long addr, unsigned long end, pgprot_t newprot)
 {
-	pmd_t * pmd;
-	unsigned long end;
+	pmd_t *pmd;
+	unsigned long next;
 
-	if (pud_none(*pud))
-		return;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return;
-	}
-	pmd = pmd_offset(pud, address);
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
+	pmd = pmd_offset(pud, addr);
 	do {
-		change_pte_range(pmd, address, end - address, newprot);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		change_pte_range(mm, pmd, addr, next, newprot);
+	} while (pmd++, addr = next, addr != end);
 }
 
-static inline void
-change_pud_range(pgd_t *pgd, unsigned long address,
-		unsigned long size, pgprot_t newprot)
+static inline void change_pud_range(struct mm_struct *mm, pgd_t *pgd,
+		unsigned long addr, unsigned long end, pgprot_t newprot)
 {
-	pud_t * pud;
-	unsigned long end;
+	pud_t *pud;
+	unsigned long next;
 
-	if (pgd_none(*pgd))
-		return;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return;
-	}
-	pud = pud_offset(pgd, address);
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
+	pud = pud_offset(pgd, addr);
 	do {
-		change_pmd_range(pud, address, end - address, newprot);
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && (address < end));
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		change_pmd_range(mm, pud, addr, next, newprot);
+	} while (pud++, addr = next, addr != end);
 }
 
-static void
-change_protection(struct vm_area_struct *vma, unsigned long start,
-		unsigned long end, pgprot_t newprot)
+static void change_protection(struct vm_area_struct *vma,
+		unsigned long addr, unsigned long end, pgprot_t newprot)
 {
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 	pgd_t *pgd;
-	unsigned long beg = start, next;
-	int i;
+	unsigned long next;
+	unsigned long start = addr;
 
-	pgd = pgd_offset(mm, start);
-	flush_cache_range(vma, beg, end);
-	BUG_ON(start >= end);
+	BUG_ON(addr >= end);
+	pgd = pgd_offset(mm, addr);
+	flush_cache_range(vma, addr, end);
 	spin_lock(&mm->page_table_lock);
-	for (i = pgd_index(start); i <= pgd_index(end-1); i++) {
-		next = (start + PGDIR_SIZE) & PGDIR_MASK;
-		if (next <= start || next > end)
-			next = end;
-		change_pud_range(pgd, start, next - start, newprot);
-		start = next;
-		pgd++;
-	}
-	flush_tlb_range(vma, beg, end);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		change_pud_range(mm, pgd, addr, next, newprot);
+	} while (pgd++, addr = next, addr != end);
+	flush_tlb_range(vma, start, end);
 	spin_unlock(&mm->page_table_lock);
 }
 
@@ -142,7 +103,7 @@ static int
 mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
 	unsigned long start, unsigned long end, unsigned long newflags)
 {
-	struct mm_struct * mm = vma->vm_mm;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long oldflags = vma->vm_flags;
 	long nrpages = (end - start) >> PAGE_SHIFT;
 	unsigned long charged = 0;
@@ -185,16 +146,13 @@ mprotect_fixup(struct vm_area_struct *vm
 		goto success;
 	}
 
+	*pprev = vma;
+
 	if (start != vma->vm_start) {
 		error = split_vma(mm, vma, start, 1);
 		if (error)
 			goto fail;
 	}
-	/*
-	 * Unless it returns an error, this function always sets *pprev to
-	 * the first vma for which vma->vm_end >= end.
-	 */
-	*pprev = vma;
 
 	if (end != vma->vm_end) {
 		error = split_vma(mm, vma, end, 0);
@@ -222,7 +180,7 @@ fail:
 asmlinkage long
 sys_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
-	unsigned long vm_flags, nstart, end, tmp;
+	unsigned long vm_flags, nstart, end, tmp, reqprot;
 	struct vm_area_struct *vma, *prev;
 	int error = -EINVAL;
 	const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
@@ -232,14 +190,16 @@ sys_mprotect(unsigned long start, size_t
 
 	if (start & ~PAGE_MASK)
 		return -EINVAL;
+	if (!len)
+		return 0;
 	len = PAGE_ALIGN(len);
 	end = start + len;
-	if (end < start)
+	if (end <= start)
 		return -ENOMEM;
 	if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM))
 		return -EINVAL;
-	if (end == start)
-		return 0;
+
+	reqprot = prot;
 	/*
 	 * Does the application expect PROT_READ to imply PROT_EXEC:
 	 */
@@ -293,7 +253,7 @@ sys_mprotect(unsigned long start, size_t
 			goto out;
 		}
 
-		error = security_file_mprotect(vma, prot);
+		error = security_file_mprotect(vma, reqprot, prot);
 		if (error)
 			goto out;
 
diff --git a/mm/mremap.c b/mm/mremap.c
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -16,7 +16,6 @@
 #include <linux/fs.h>
 #include <linux/highmem.h>
 #include <linux/security.h>
-#include <linux/acct.h>
 #include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
@@ -31,26 +30,16 @@ static pte_t *get_one_pte_map_nested(str
 	pte_t *pte = NULL;
 
 	pgd = pgd_offset(mm, addr);
-	if (pgd_none(*pgd))
+	if (pgd_none_or_clear_bad(pgd))
 		goto end;
 
 	pud = pud_offset(pgd, addr);
-	if (pud_none(*pud))
+	if (pud_none_or_clear_bad(pud))
 		goto end;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		goto end;
-	}
 
 	pmd = pmd_offset(pud, addr);
-	if (pmd_none(*pmd))
+	if (pmd_none_or_clear_bad(pmd))
 		goto end;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		goto end;
-	}
 
 	pte = pte_offset_map_nested(pmd, addr);
 	if (pte_none(*pte)) {
@@ -68,15 +57,17 @@ static pte_t *get_one_pte_map(struct mm_
 	pmd_t *pmd;
 
 	pgd = pgd_offset(mm, addr);
-	if (pgd_none(*pgd))
+	if (pgd_none_or_clear_bad(pgd))
 		return NULL;
 
 	pud = pud_offset(pgd, addr);
-	if (pud_none(*pud))
+	if (pud_none_or_clear_bad(pud))
 		return NULL;
+
 	pmd = pmd_offset(pud, addr);
-	if (!pmd_present(*pmd))
+	if (pmd_none_or_clear_bad(pmd))
 		return NULL;
+
 	return pte_offset_map(pmd, addr);
 }
 
@@ -150,7 +141,7 @@ move_one_page(struct vm_area_struct *vma
 			if (dst) {
 				pte_t pte;
 				pte = ptep_clear_flush(vma, old_addr, src);
-				set_pte(dst, pte);
+				set_pte_at(mm, new_addr, dst, pte);
 			} else
 				error = -ENOMEM;
 			pte_unmap_nested(src);
@@ -233,6 +224,12 @@ static unsigned long move_vma(struct vm_
 			split = 1;
 	}
 
+	/*
+	 * if we failed to move page tables we still do total_vm increment
+	 * since do_munmap() will decrement it by old_len == new_len
+	 */
+	mm->total_vm += new_len >> PAGE_SHIFT;
+
 	if (do_munmap(mm, old_addr, old_len) < 0) {
 		/* OOM: unable to split vma, just get accounts right */
 		vm_unacct_memory(excess >> PAGE_SHIFT);
@@ -246,7 +243,6 @@ static unsigned long move_vma(struct vm_
 			vma->vm_next->vm_flags |= VM_ACCOUNT;
 	}
 
-	mm->total_vm += new_len >> PAGE_SHIFT;
 	__vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT);
 	if (vm_flags & VM_LOCKED) {
 		mm->locked_vm += new_len >> PAGE_SHIFT;
@@ -255,9 +251,6 @@ static unsigned long move_vma(struct vm_
 					   new_addr + new_len);
 	}
 
-	acct_update_integrals();
-	update_mem_hiwater();
-
 	return new_addr;
 }
 
@@ -359,10 +352,10 @@ unsigned long do_mremap(unsigned long ad
 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			goto out;
 	}
-	ret = -ENOMEM;
-	if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
-	    > current->signal->rlim[RLIMIT_AS].rlim_cur)
+	if (!may_expand_vm(current->mm, (new_len - old_len) >> PAGE_SHIFT)) {
+		ret = -ENOMEM;
 		goto out;
+	}
 
 	if (vma->vm_flags & VM_ACCOUNT) {
 		charged = (new_len - old_len) >> PAGE_SHIFT;
@@ -394,8 +387,6 @@ unsigned long do_mremap(unsigned long ad
 				make_pages_present(addr + old_len,
 						   addr + new_len);
 			}
-			acct_update_integrals();
-			update_mem_hiwater();
 			ret = addr;
 			goto out;
 		}
diff --git a/mm/msync.c b/mm/msync.c
--- a/mm/msync.c
+++ b/mm/msync.c
@@ -21,170 +21,109 @@
  * Called with mm->page_table_lock held to protect against other
  * threads/the swapper from ripping pte's out from under us.
  */
-static int filemap_sync_pte(pte_t *ptep, struct vm_area_struct *vma,
-	unsigned long address, unsigned int flags)
-{
-	pte_t pte = *ptep;
-	unsigned long pfn = pte_pfn(pte);
-	struct page *page;
-
-	if (pte_present(pte) && pfn_valid(pfn)) {
-		page = pfn_to_page(pfn);
-		if (!PageReserved(page) &&
-		    (ptep_clear_flush_dirty(vma, address, ptep) ||
-		     page_test_and_clear_dirty(page)))
-			set_page_dirty(page);
-	}
-	return 0;
-}
 
-static int filemap_sync_pte_range(pmd_t * pmd,
-	unsigned long address, unsigned long end, 
-	struct vm_area_struct *vma, unsigned int flags)
+static void sync_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+				unsigned long addr, unsigned long end)
 {
 	pte_t *pte;
-	int error;
 
-	if (pmd_none(*pmd))
-		return 0;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return 0;
-	}
-	pte = pte_offset_map(pmd, address);
-	if ((address & PMD_MASK) != (end & PMD_MASK))
-		end = (address & PMD_MASK) + PMD_SIZE;
-	error = 0;
+	pte = pte_offset_map(pmd, addr);
 	do {
-		error |= filemap_sync_pte(pte, vma, address, flags);
-		address += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
+		unsigned long pfn;
+		struct page *page;
 
-	pte_unmap(pte - 1);
+		if (!pte_present(*pte))
+			continue;
+		pfn = pte_pfn(*pte);
+		if (!pfn_valid(pfn))
+			continue;
+		page = pfn_to_page(pfn);
+		if (PageReserved(page))
+			continue;
 
-	return error;
+		if (ptep_clear_flush_dirty(vma, addr, pte) ||
+		    page_test_and_clear_dirty(page))
+			set_page_dirty(page);
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+	pte_unmap(pte - 1);
 }
 
-static inline int filemap_sync_pmd_range(pud_t * pud,
-	unsigned long address, unsigned long end, 
-	struct vm_area_struct *vma, unsigned int flags)
+static inline void sync_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+				unsigned long addr, unsigned long end)
 {
-	pmd_t * pmd;
-	int error;
+	pmd_t *pmd;
+	unsigned long next;
 
-	if (pud_none(*pud))
-		return 0;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return 0;
-	}
-	pmd = pmd_offset(pud, address);
-	if ((address & PUD_MASK) != (end & PUD_MASK))
-		end = (address & PUD_MASK) + PUD_SIZE;
-	error = 0;
+	pmd = pmd_offset(pud, addr);
 	do {
-		error |= filemap_sync_pte_range(pmd, address, end, vma, flags);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
-	return error;
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		sync_pte_range(vma, pmd, addr, next);
+	} while (pmd++, addr = next, addr != end);
 }
 
-static inline int filemap_sync_pud_range(pgd_t *pgd,
-	unsigned long address, unsigned long end,
-	struct vm_area_struct *vma, unsigned int flags)
+static inline void sync_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+				unsigned long addr, unsigned long end)
 {
 	pud_t *pud;
-	int error;
+	unsigned long next;
 
-	if (pgd_none(*pgd))
-		return 0;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return 0;
-	}
-	pud = pud_offset(pgd, address);
-	if ((address & PGDIR_MASK) != (end & PGDIR_MASK))
-		end = (address & PGDIR_MASK) + PGDIR_SIZE;
-	error = 0;
+	pud = pud_offset(pgd, addr);
 	do {
-		error |= filemap_sync_pmd_range(pud, address, end, vma, flags);
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && (address < end));
-	return error;
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		sync_pmd_range(vma, pud, addr, next);
+	} while (pud++, addr = next, addr != end);
 }
 
-static int __filemap_sync(struct vm_area_struct *vma, unsigned long address,
-			size_t size, unsigned int flags)
+static void sync_page_range(struct vm_area_struct *vma,
+				unsigned long addr, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	pgd_t *pgd;
-	unsigned long end = address + size;
 	unsigned long next;
-	int i;
-	int error = 0;
-
-	/* Aquire the lock early; it may be possible to avoid dropping
-	 * and reaquiring it repeatedly.
-	 */
-	spin_lock(&vma->vm_mm->page_table_lock);
-
-	pgd = pgd_offset(vma->vm_mm, address);
-	flush_cache_range(vma, address, end);
 
 	/* For hugepages we can't go walking the page table normally,
 	 * but that's ok, hugetlbfs is memory based, so we don't need
 	 * to do anything more on an msync() */
 	if (is_vm_hugetlb_page(vma))
-		goto out;
+		return;
 
-	if (address >= end)
-		BUG();
-	for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next <= address || next > end)
-			next = end;
-		error |= filemap_sync_pud_range(pgd, address, next, vma, flags);
-		address = next;
-		pgd++;
-	}
-	/*
-	 * Why flush ? filemap_sync_pte already flushed the tlbs with the
-	 * dirty bits.
-	 */
-	flush_tlb_range(vma, end - size, end);
- out:
-	spin_unlock(&vma->vm_mm->page_table_lock);
-
-	return error;
+	BUG_ON(addr >= end);
+	pgd = pgd_offset(mm, addr);
+	flush_cache_range(vma, addr, end);
+	spin_lock(&mm->page_table_lock);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		sync_pud_range(vma, pgd, addr, next);
+	} while (pgd++, addr = next, addr != end);
+	spin_unlock(&mm->page_table_lock);
 }
 
 #ifdef CONFIG_PREEMPT
-static int filemap_sync(struct vm_area_struct *vma, unsigned long address,
-			size_t size, unsigned int flags)
+static inline void filemap_sync(struct vm_area_struct *vma,
+				unsigned long addr, unsigned long end)
 {
 	const size_t chunk = 64 * 1024;	/* bytes */
-	int error = 0;
-
-	while (size) {
-		size_t sz = min(size, chunk);
+	unsigned long next;
 
-		error |= __filemap_sync(vma, address, sz, flags);
+	do {
+		next = addr + chunk;
+		if (next > end || next < addr)
+			next = end;
+		sync_page_range(vma, addr, next);
 		cond_resched();
-		address += sz;
-		size -= sz;
-	}
-	return error;
+	} while (addr = next, addr != end);
 }
 #else
-static int filemap_sync(struct vm_area_struct *vma, unsigned long address,
-			size_t size, unsigned int flags)
+static inline void filemap_sync(struct vm_area_struct *vma,
+				unsigned long addr, unsigned long end)
 {
-	return __filemap_sync(vma, address, size, flags);
+	sync_page_range(vma, addr, end);
 }
 #endif
 
@@ -199,19 +138,19 @@ static int filemap_sync(struct vm_area_s
  * So my _not_ starting I/O in MS_ASYNC we provide complete flexibility to
  * applications.
  */
-static int msync_interval(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, int flags)
+static int msync_interval(struct vm_area_struct *vma,
+			unsigned long addr, unsigned long end, int flags)
 {
 	int ret = 0;
-	struct file * file = vma->vm_file;
+	struct file *file = vma->vm_file;
 
 	if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED))
 		return -EBUSY;
 
 	if (file && (vma->vm_flags & VM_SHARED)) {
-		ret = filemap_sync(vma, start, end-start, flags);
+		filemap_sync(vma, addr, end);
 
-		if (!ret && (flags & MS_SYNC)) {
+		if (flags & MS_SYNC) {
 			struct address_space *mapping = file->f_mapping;
 			int err;
 
@@ -236,7 +175,7 @@ static int msync_interval(struct vm_area
 asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
 {
 	unsigned long end;
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma;
 	int unmapped_error, error = -EINVAL;
 
 	if (flags & MS_SYNC)
diff --git a/mm/nommu.c b/mm/nommu.c
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -150,7 +150,8 @@ void vfree(void *addr)
 	kfree(addr);
 }
 
-void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot)
+void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask,
+			pgprot_t prot)
 {
 	/*
 	 * kmalloc doesn't like __GFP_HIGHMEM for some reason
@@ -256,29 +257,6 @@ asmlinkage unsigned long sys_brk(unsigne
 	return mm->brk = brk;
 }
 
-/*
- * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
- * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
- * into "VM_xxx".
- */
-static inline unsigned long calc_vm_flags(unsigned long prot, unsigned long flags)
-{
-#define _trans(x,bit1,bit2) \
-((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
-
-	unsigned long prot_bits, flag_bits;
-	prot_bits =
-		_trans(prot, PROT_READ, VM_READ) |
-		_trans(prot, PROT_WRITE, VM_WRITE) |
-		_trans(prot, PROT_EXEC, VM_EXEC);
-	flag_bits =
-		_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) |
-		_trans(flags, MAP_DENYWRITE, VM_DENYWRITE) |
-		_trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);
-	return prot_bits | flag_bits;
-#undef _trans
-}
-
 #ifdef DEBUG
 static void show_process_blocks(void)
 {
@@ -381,29 +359,33 @@ static void delete_nommu_vma(struct vm_a
 }
 
 /*
- * handle mapping creation for uClinux
+ * determine whether a mapping should be permitted and, if so, what sort of
+ * mapping we're capable of supporting
  */
-unsigned long do_mmap_pgoff(struct file *file,
-			    unsigned long addr,
-			    unsigned long len,
-			    unsigned long prot,
-			    unsigned long flags,
-			    unsigned long pgoff)
+static int validate_mmap_request(struct file *file,
+				 unsigned long addr,
+				 unsigned long len,
+				 unsigned long prot,
+				 unsigned long flags,
+				 unsigned long pgoff,
+				 unsigned long *_capabilities)
 {
-	struct vm_list_struct *vml = NULL;
-	struct vm_area_struct *vma = NULL;
-	struct rb_node *rb;
-	unsigned int vm_flags;
-	void *result;
-	int ret, membacked;
+	unsigned long capabilities;
+	unsigned long reqprot = prot;
+	int ret;
 
 	/* do the simple checks first */
 	if (flags & MAP_FIXED || addr) {
-		printk(KERN_DEBUG "%d: Can't do fixed-address/overlay mmap of RAM\n",
+		printk(KERN_DEBUG
+		       "%d: Can't do fixed-address/overlay mmap of RAM\n",
 		       current->pid);
 		return -EINVAL;
 	}
 
+	if ((flags & MAP_TYPE) != MAP_PRIVATE &&
+	    (flags & MAP_TYPE) != MAP_SHARED)
+		return -EINVAL;
+
 	if (PAGE_ALIGN(len) == 0)
 		return addr;
 
@@ -414,35 +396,58 @@ unsigned long do_mmap_pgoff(struct file 
 	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
 		return -EINVAL;
 
-	/* validate file mapping requests */
-	membacked = 0;
 	if (file) {
+		/* validate file mapping requests */
+		struct address_space *mapping;
+
 		/* files must support mmap */
 		if (!file->f_op || !file->f_op->mmap)
 			return -ENODEV;
 
-		if ((prot & PROT_EXEC) &&
-		    (file->f_vfsmnt->mnt_flags & MNT_NOEXEC))
-			return -EPERM;
-
 		/* work out if what we've got could possibly be shared
 		 * - we support chardevs that provide their own "memory"
 		 * - we support files/blockdevs that are memory backed
 		 */
-		if (S_ISCHR(file->f_dentry->d_inode->i_mode)) {
-			membacked = 1;
-		}
-		else {
-			struct address_space *mapping = file->f_mapping;
-			if (!mapping)
-				mapping = file->f_dentry->d_inode->i_mapping;
-			if (mapping && mapping->backing_dev_info)
-				membacked = mapping->backing_dev_info->memory_backed;
+		mapping = file->f_mapping;
+		if (!mapping)
+			mapping = file->f_dentry->d_inode->i_mapping;
+
+		capabilities = 0;
+		if (mapping && mapping->backing_dev_info)
+			capabilities = mapping->backing_dev_info->capabilities;
+
+		if (!capabilities) {
+			/* no explicit capabilities set, so assume some
+			 * defaults */
+			switch (file->f_dentry->d_inode->i_mode & S_IFMT) {
+			case S_IFREG:
+			case S_IFBLK:
+				capabilities = BDI_CAP_MAP_COPY;
+				break;
+
+			case S_IFCHR:
+				capabilities =
+					BDI_CAP_MAP_DIRECT |
+					BDI_CAP_READ_MAP |
+					BDI_CAP_WRITE_MAP;
+				break;
+
+			default:
+				return -EINVAL;
+			}
 		}
 
+		/* eliminate any capabilities that we can't support on this
+		 * device */
+		if (!file->f_op->get_unmapped_area)
+			capabilities &= ~BDI_CAP_MAP_DIRECT;
+		if (!file->f_op->read)
+			capabilities &= ~BDI_CAP_MAP_COPY;
+
 		if (flags & MAP_SHARED) {
 			/* do checks for writing, appending and locking */
-			if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE))
+			if ((prot & PROT_WRITE) &&
+			    !(file->f_mode & FMODE_WRITE))
 				return -EACCES;
 
 			if (IS_APPEND(file->f_dentry->d_inode) &&
@@ -452,64 +457,243 @@ unsigned long do_mmap_pgoff(struct file 
 			if (locks_verify_locked(file->f_dentry->d_inode))
 				return -EAGAIN;
 
-			if (!membacked) {
+			if (!(capabilities & BDI_CAP_MAP_DIRECT))
+				return -ENODEV;
+
+			if (((prot & PROT_READ)  && !(capabilities & BDI_CAP_READ_MAP))  ||
+			    ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) ||
+			    ((prot & PROT_EXEC)  && !(capabilities & BDI_CAP_EXEC_MAP))
+			    ) {
 				printk("MAP_SHARED not completely supported on !MMU\n");
 				return -EINVAL;
 			}
 
-			/* we require greater support from the driver or
-			 * filesystem - we ask it to tell us what memory to
-			 * use */
-			if (!file->f_op->get_unmapped_area)
-				return -ENODEV;
+			/* we mustn't privatise shared mappings */
+			capabilities &= ~BDI_CAP_MAP_COPY;
 		}
 		else {
-			/* we read private files into memory we allocate */
-			if (!file->f_op->read)
+			/* we're going to read the file into private memory we
+			 * allocate */
+			if (!(capabilities & BDI_CAP_MAP_COPY))
 				return -ENODEV;
+
+			/* we don't permit a private writable mapping to be
+			 * shared with the backing device */
+			if (prot & PROT_WRITE)
+				capabilities &= ~BDI_CAP_MAP_DIRECT;
+		}
+
+		/* handle executable mappings and implied executable
+		 * mappings */
+		if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+			if (prot & PROT_EXEC)
+				return -EPERM;
+		}
+		else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) {
+			/* handle implication of PROT_EXEC by PROT_READ */
+			if (current->personality & READ_IMPLIES_EXEC) {
+				if (capabilities & BDI_CAP_EXEC_MAP)
+					prot |= PROT_EXEC;
+			}
+		}
+		else if ((prot & PROT_READ) &&
+			 (prot & PROT_EXEC) &&
+			 !(capabilities & BDI_CAP_EXEC_MAP)
+			 ) {
+			/* backing file is not executable, try to copy */
+			capabilities &= ~BDI_CAP_MAP_DIRECT;
 		}
 	}
+	else {
+		/* anonymous mappings are always memory backed and can be
+		 * privately mapped
+		 */
+		capabilities = BDI_CAP_MAP_COPY;
 
-	/* handle PROT_EXEC implication by PROT_READ */
-	if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
-		if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
+		/* handle PROT_EXEC implication by PROT_READ */
+		if ((prot & PROT_READ) &&
+		    (current->personality & READ_IMPLIES_EXEC))
 			prot |= PROT_EXEC;
+	}
 
-	/* do simple checking here so the lower-level routines won't have
-	 * to. we assume access permissions have been handled by the open
-	 * of the memory object, so we don't do any here.
-	 */
-	vm_flags = calc_vm_flags(prot,flags) /* | mm->def_flags */
-		| VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+	/* allow the security API to have its say */
+	ret = security_file_mmap(file, reqprot, prot, flags);
+	if (ret < 0)
+		return ret;
 
-	if (!membacked) {
-		/* share any file segment that's mapped read-only */
-		if (((flags & MAP_PRIVATE) && !(prot & PROT_WRITE) && file) ||
-		    ((flags & MAP_SHARED) && !(prot & PROT_WRITE) && file))
-			vm_flags |= VM_MAYSHARE;
+	/* looks okay */
+	*_capabilities = capabilities;
+	return 0;
+}
 
-		/* refuse to let anyone share files with this process if it's being traced -
-		 * otherwise breakpoints set in it may interfere with another untraced process
-		 */
-		if (current->ptrace & PT_PTRACED)
-			vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
+/*
+ * we've determined that we can make the mapping, now translate what we
+ * now know into VMA flags
+ */
+static unsigned long determine_vm_flags(struct file *file,
+					unsigned long prot,
+					unsigned long flags,
+					unsigned long capabilities)
+{
+	unsigned long vm_flags;
+
+	vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags);
+	vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+	/* vm_flags |= mm->def_flags; */
+
+	if (!(capabilities & BDI_CAP_MAP_DIRECT)) {
+		/* attempt to share read-only copies of mapped file chunks */
+		if (file && !(prot & PROT_WRITE))
+			vm_flags |= VM_MAYSHARE;
 	}
 	else {
-		/* permit sharing of character devices and ramfs files at any time for
-		 * anything other than a privately writable mapping
-		 */
-		if (!(flags & MAP_PRIVATE) || !(prot & PROT_WRITE)) {
+		/* overlay a shareable mapping on the backing device or inode
+		 * if possible - used for chardevs, ramfs/tmpfs/shmfs and
+		 * romfs/cramfs */
+		if (flags & MAP_SHARED)
+			vm_flags |= VM_MAYSHARE | VM_SHARED;
+		else if ((((vm_flags & capabilities) ^ vm_flags) & BDI_CAP_VMFLAGS) == 0)
 			vm_flags |= VM_MAYSHARE;
-			if (flags & MAP_SHARED)
-				vm_flags |= VM_SHARED;
+	}
+
+	/* refuse to let anyone share private mappings with this process if
+	 * it's being traced - otherwise breakpoints set in it may interfere
+	 * with another untraced process
+	 */
+	if ((flags & MAP_PRIVATE) && (current->ptrace & PT_PTRACED))
+		vm_flags &= ~VM_MAYSHARE;
+
+	return vm_flags;
+}
+
+/*
+ * set up a shared mapping on a file
+ */
+static int do_mmap_shared_file(struct vm_area_struct *vma, unsigned long len)
+{
+	int ret;
+
+	ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+	if (ret != -ENOSYS)
+		return ret;
+
+	/* getting an ENOSYS error indicates that direct mmap isn't
+	 * possible (as opposed to tried but failed) so we'll fall
+	 * through to making a private copy of the data and mapping
+	 * that if we can */
+	return -ENODEV;
+}
+
+/*
+ * set up a private mapping or an anonymous shared mapping
+ */
+static int do_mmap_private(struct vm_area_struct *vma, unsigned long len)
+{
+	void *base;
+	int ret;
+
+	/* invoke the file's mapping function so that it can keep track of
+	 * shared mappings on devices or memory
+	 * - VM_MAYSHARE will be set if it may attempt to share
+	 */
+	if (vma->vm_file) {
+		ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+		if (ret != -ENOSYS) {
+			/* shouldn't return success if we're not sharing */
+			BUG_ON(ret == 0 && !(vma->vm_flags & VM_MAYSHARE));
+			return ret; /* success or a real error */
 		}
+
+		/* getting an ENOSYS error indicates that direct mmap isn't
+		 * possible (as opposed to tried but failed) so we'll try to
+		 * make a private copy of the data and map that instead */
 	}
 
-	/* allow the security API to have its say */
-	ret = security_file_mmap(file, prot, flags);
-	if (ret)
+	/* allocate some memory to hold the mapping
+	 * - note that this may not return a page-aligned address if the object
+	 *   we're allocating is smaller than a page
+	 */
+	base = kmalloc(len, GFP_KERNEL);
+	if (!base)
+		goto enomem;
+
+	vma->vm_start = (unsigned long) base;
+	vma->vm_end = vma->vm_start + len;
+	vma->vm_flags |= VM_MAPPED_COPY;
+
+#ifdef WARN_ON_SLACK
+	if (len + WARN_ON_SLACK <= kobjsize(result))
+		printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n",
+		       len, current->pid, kobjsize(result) - len);
+#endif
+
+	if (vma->vm_file) {
+		/* read the contents of a file into the copy */
+		mm_segment_t old_fs;
+		loff_t fpos;
+
+		fpos = vma->vm_pgoff;
+		fpos <<= PAGE_SHIFT;
+
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos);
+		set_fs(old_fs);
+
+		if (ret < 0)
+			goto error_free;
+
+		/* clear the last little bit */
+		if (ret < len)
+			memset(base + ret, 0, len - ret);
+
+	} else {
+		/* if it's an anonymous mapping, then just clear it */
+		memset(base, 0, len);
+	}
+
+	return 0;
+
+error_free:
+	kfree(base);
+	vma->vm_start = 0;
+	return ret;
+
+enomem:
+	printk("Allocation of length %lu from process %d failed\n",
+	       len, current->pid);
+	show_free_areas();
+	return -ENOMEM;
+}
+
+/*
+ * handle mapping creation for uClinux
+ */
+unsigned long do_mmap_pgoff(struct file *file,
+			    unsigned long addr,
+			    unsigned long len,
+			    unsigned long prot,
+			    unsigned long flags,
+			    unsigned long pgoff)
+{
+	struct vm_list_struct *vml = NULL;
+	struct vm_area_struct *vma = NULL;
+	struct rb_node *rb;
+	unsigned long capabilities, vm_flags;
+	void *result;
+	int ret;
+
+	/* decide whether we should attempt the mapping, and if so what sort of
+	 * mapping */
+	ret = validate_mmap_request(file, addr, len, prot, flags, pgoff,
+				    &capabilities);
+	if (ret < 0)
 		return ret;
 
+	/* we've determined that we can make the mapping, now translate what we
+	 * now know into VMA flags */
+	vm_flags = determine_vm_flags(file, prot, flags, capabilities);
+
 	/* we're going to need to record the mapping if it works */
 	vml = kmalloc(sizeof(struct vm_list_struct), GFP_KERNEL);
 	if (!vml)
@@ -518,8 +702,8 @@ unsigned long do_mmap_pgoff(struct file 
 
 	down_write(&nommu_vma_sem);
 
-	/* if we want to share, we need to search for VMAs created by another
-	 * mmap() call that overlap with our proposed mapping
+	/* if we want to share, we need to check for VMAs created by other
+	 * mmap() calls that overlap with our proposed mapping
 	 * - we can only share with an exact match on most regular files
 	 * - shared mappings on character devices and memory backed files are
 	 *   permitted to overlap inexactly as far as we are concerned for in
@@ -543,13 +727,14 @@ unsigned long do_mmap_pgoff(struct file 
 			if (vma->vm_pgoff >= pgoff + pglen)
 				continue;
 
-			vmpglen = (vma->vm_end - vma->vm_start + PAGE_SIZE - 1) >> PAGE_SHIFT;
+			vmpglen = vma->vm_end - vma->vm_start + PAGE_SIZE - 1;
+			vmpglen >>= PAGE_SHIFT;
 			if (pgoff >= vma->vm_pgoff + vmpglen)
 				continue;
 
-			/* handle inexact matches between mappings */
-			if (vmpglen != pglen || vma->vm_pgoff != pgoff) {
-				if (!membacked)
+			/* handle inexactly overlapping matches between mappings */
+			if (vma->vm_pgoff != pgoff || vmpglen != pglen) {
+				if (!(capabilities & BDI_CAP_MAP_DIRECT))
 					goto sharing_violation;
 				continue;
 			}
@@ -561,21 +746,30 @@ unsigned long do_mmap_pgoff(struct file 
 			result = (void *) vma->vm_start;
 			goto shared;
 		}
-	}
 
-	vma = NULL;
+		vma = NULL;
 
-	/* obtain the address to map to. we verify (or select) it and ensure
-	 * that it represents a valid section of the address space
-	 * - this is the hook for quasi-memory character devices
-	 */
-	if (file && file->f_op->get_unmapped_area) {
-		addr = file->f_op->get_unmapped_area(file, addr, len, pgoff, flags);
-		if (IS_ERR((void *) addr)) {
-			ret = addr;
-			if (ret == (unsigned long) -ENOSYS)
+		/* obtain the address at which to make a shared mapping
+		 * - this is the hook for quasi-memory character devices to
+		 *   tell us the location of a shared mapping
+		 */
+		if (file && file->f_op->get_unmapped_area) {
+			addr = file->f_op->get_unmapped_area(file, addr, len,
+							     pgoff, flags);
+			if (IS_ERR((void *) addr)) {
+				ret = addr;
+				if (ret != (unsigned long) -ENOSYS)
+					goto error;
+
+				/* the driver refused to tell us where to site
+				 * the mapping so we'll have to attempt to copy
+				 * it */
 				ret = (unsigned long) -ENODEV;
-			goto error;
+				if (!(capabilities & BDI_CAP_MAP_COPY))
+					goto error;
+
+				capabilities &= ~BDI_CAP_MAP_DIRECT;
+			}
 		}
 	}
 
@@ -597,96 +791,18 @@ unsigned long do_mmap_pgoff(struct file 
 
 	vml->vma = vma;
 
-	/* determine the object being mapped and call the appropriate specific
-	 * mapper.
-	 */
-	if (file) {
-#ifdef MAGIC_ROM_PTR
-		/* First, try simpler routine designed to give us a ROM pointer. */
-		if (file->f_op->romptr && !(prot & PROT_WRITE)) {
-			ret = file->f_op->romptr(file, vma);
-#ifdef DEBUG
-			printk("romptr mmap returned %d (st=%lx)\n",
-			       ret, vma->vm_start);
-#endif
-			result = (void *) vma->vm_start;
-			if (!ret)
-				goto done;
-			else if (ret != -ENOSYS)
-				goto error;
-		} else
-#endif /* MAGIC_ROM_PTR */
-		/* Then try full mmap routine, which might return a RAM
-		 * pointer, or do something truly complicated
-		 */
-		if (file->f_op->mmap) {
-			ret = file->f_op->mmap(file, vma);
-
-#ifdef DEBUG
-			printk("f_op->mmap() returned %d (st=%lx)\n",
-			       ret, vma->vm_start);
-#endif
-			result = (void *) vma->vm_start;
-			if (!ret)
-				goto done;
-			else if (ret != -ENOSYS)
-				goto error;
-		} else {
-			ret = -ENODEV; /* No mapping operations defined */
-			goto error;
-		}
-
-		/* An ENOSYS error indicates that mmap isn't possible (as
-		 * opposed to tried but failed) so we'll fall through to the
-		 * copy. */
-	}
-
-	/* allocate some memory to hold the mapping
-	 * - note that this may not return a page-aligned address if the object
-	 *   we're allocating is smaller than a page
-	 */
-	ret = -ENOMEM;
-	result = kmalloc(len, GFP_KERNEL);
-	if (!result) {
-		printk("Allocation of length %lu from process %d failed\n",
-		       len, current->pid);
-		show_free_areas();
+	/* set up the mapping */
+	if (file && vma->vm_flags & VM_SHARED)
+		ret = do_mmap_shared_file(vma, len);
+	else
+		ret = do_mmap_private(vma, len);
+	if (ret < 0)
 		goto error;
-	}
 
-	vma->vm_start = (unsigned long) result;
-	vma->vm_end = vma->vm_start + len;
+	/* okay... we have a mapping; now we have to register it */
+	result = (void *) vma->vm_start;
 
-#ifdef WARN_ON_SLACK
-	if (len + WARN_ON_SLACK <= kobjsize(result))
-		printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n",
-		       len, current->pid, kobjsize(result) - len);
-#endif
-
-	if (file) {
-		mm_segment_t old_fs = get_fs();
-		loff_t fpos;
-
-		fpos = pgoff;
-		fpos <<= PAGE_SHIFT;
-
-		set_fs(KERNEL_DS);
-		ret = file->f_op->read(file, (char *) result, len, &fpos);
-		set_fs(old_fs);
-
-		if (ret < 0)
-			goto error2;
-		if (ret < len)
-			memset(result + ret, 0, len - ret);
-	} else {
-		memset(result, 0, len);
-	}
-
-	if (prot & PROT_EXEC)
-		flush_icache_range((unsigned long) result, (unsigned long) result + len);
-
- done:
-	if (!(vma->vm_flags & VM_SHARED)) {
+	if (vma->vm_flags & VM_MAPPED_COPY) {
 		realalloc += kobjsize(result);
 		askedalloc += len;
 	}
@@ -697,6 +813,7 @@ unsigned long do_mmap_pgoff(struct file 
 	current->mm->total_vm += len >> PAGE_SHIFT;
 
 	add_nommu_vma(vma);
+
  shared:
 	realalloc += kobjsize(vml);
 	askedalloc += sizeof(*vml);
@@ -706,6 +823,10 @@ unsigned long do_mmap_pgoff(struct file 
 
 	up_write(&nommu_vma_sem);
 
+	if (prot & PROT_EXEC)
+		flush_icache_range((unsigned long) result,
+				   (unsigned long) result + len);
+
 #ifdef DEBUG
 	printk("do_mmap:\n");
 	show_process_blocks();
@@ -713,8 +834,6 @@ unsigned long do_mmap_pgoff(struct file 
 
 	return (unsigned long) result;
 
- error2:
-	kfree(result);
  error:
 	up_write(&nommu_vma_sem);
 	kfree(vml);
@@ -761,7 +880,7 @@ static void put_vma(struct vm_area_struc
 
 			/* IO memory and memory shared directly out of the pagecache from
 			 * ramfs/tmpfs mustn't be released here */
-			if (!(vma->vm_flags & (VM_IO | VM_SHARED)) && vma->vm_start) {
+			if (vma->vm_flags & VM_MAPPED_COPY) {
 				realalloc -= kobjsize((void *) vma->vm_start);
 				askedalloc -= vma->vm_end - vma->vm_start;
 				kfree((void *) vma->vm_start);
@@ -784,13 +903,6 @@ int do_munmap(struct mm_struct *mm, unsi
 	struct vm_list_struct *vml, **parent;
 	unsigned long end = addr + len;
 
-#ifdef MAGIC_ROM_PTR
-	/* For efficiency's sake, if the pointer is obviously in ROM,
-	   don't bother walking the lists to free it */
-	if (is_in_rom(addr))
-		return 0;
-#endif
-
 #ifdef DEBUG
 	printk("do_munmap:\n");
 #endif
@@ -959,13 +1071,13 @@ void arch_unmap_area(struct vm_area_stru
 {
 }
 
-void update_mem_hiwater(void)
+void update_mem_hiwater(struct task_struct *tsk)
 {
-	struct task_struct *tsk = current;
+	unsigned long rss = get_mm_counter(tsk->mm, rss);
 
 	if (likely(tsk->mm)) {
-		if (tsk->mm->hiwater_rss < tsk->mm->rss)
-			tsk->mm->hiwater_rss = tsk->mm->rss;
+		if (tsk->mm->hiwater_rss < rss)
+			tsk->mm->hiwater_rss = rss;
 		if (tsk->mm->hiwater_vm < tsk->mm->total_vm)
 			tsk->mm->hiwater_vm = tsk->mm->total_vm;
 	}
@@ -1063,3 +1175,7 @@ int __vm_enough_memory(long pages, int c
 	return -ENOMEM;
 }
 
+int in_gate_area_no_task(unsigned long addr)
+{
+	return 0;
+}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -145,7 +145,7 @@ static struct task_struct * select_bad_p
 	do_posix_clock_monotonic_gettime(&uptime);
 	do_each_thread(g, p)
 		/* skip the init task with pid == 1 */
-		if (p->pid > 1) {
+		if (p->pid > 1 && p->oomkilladj != OOM_DISABLE) {
 			unsigned long points;
 
 			/*
@@ -253,7 +253,7 @@ static struct mm_struct *oom_kill_proces
  * OR try to be smart about which process to kill. Note that we
  * don't have to be perfect here, we just have to be good.
  */
-void out_of_memory(int gfp_mask)
+void out_of_memory(unsigned int __nocast gfp_mask)
 {
 	struct mm_struct *mm = NULL;
 	task_t * p;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -255,7 +255,7 @@ static void balance_dirty_pages(struct a
 
 /**
  * balance_dirty_pages_ratelimited - balance dirty memory state
- * @mapping - address_space which was dirtied
+ * @mapping: address_space which was dirtied
  *
  * Processes which are dirtying memory should call in here once for each page
  * which was newly dirtied.  The function will periodically check the system's
@@ -289,6 +289,28 @@ void balance_dirty_pages_ratelimited(str
 }
 EXPORT_SYMBOL(balance_dirty_pages_ratelimited);
 
+void throttle_vm_writeout(void)
+{
+	struct writeback_state wbs;
+	long background_thresh;
+	long dirty_thresh;
+
+        for ( ; ; ) {
+		get_dirty_limits(&wbs, &background_thresh, &dirty_thresh, NULL);
+
+                /*
+                 * Boost the allowable dirty threshold a bit for page
+                 * allocators so they don't get DoS'ed by heavy writers
+                 */
+                dirty_thresh += dirty_thresh / 10;      /* wheeee... */
+
+                if (wbs.nr_unstable + wbs.nr_writeback <= dirty_thresh)
+                        break;
+                blk_congestion_wait(WRITE, HZ/10);
+        }
+}
+
+
 /*
  * writeback at least _min_pages, and keep writing until the amount of dirty
  * memory is less than the background threshold, or until we're all clean.
@@ -540,8 +562,8 @@ int do_writepages(struct address_space *
 /**
  * write_one_page - write out a single page and optionally wait on I/O
  *
- * @page - the page to write
- * @wait - if true, wait on writeout
+ * @page: the page to write
+ * @wait: if true, wait on writeout
  *
  * The page must be locked by the caller and will be unlocked upon return.
  *
@@ -601,16 +623,16 @@ int __set_page_dirty_nobuffers(struct pa
 		struct address_space *mapping2;
 
 		if (mapping) {
-			spin_lock_irq(&mapping->tree_lock);
+			write_lock_irq(&mapping->tree_lock);
 			mapping2 = page_mapping(page);
 			if (mapping2) { /* Race with truncate? */
 				BUG_ON(mapping2 != mapping);
-				if (!mapping->backing_dev_info->memory_backed)
+				if (mapping_cap_account_dirty(mapping))
 					inc_page_state(nr_dirty);
 				radix_tree_tag_set(&mapping->page_tree,
 					page_index(page), PAGECACHE_TAG_DIRTY);
 			}
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			if (mapping->host) {
 				/* !PageAnon && !swapper_space */
 				__mark_inode_dirty(mapping->host,
@@ -685,17 +707,17 @@ int test_clear_page_dirty(struct page *p
 	unsigned long flags;
 
 	if (mapping) {
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		write_lock_irqsave(&mapping->tree_lock, flags);
 		if (TestClearPageDirty(page)) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
-			if (!mapping->backing_dev_info->memory_backed)
+			write_unlock_irqrestore(&mapping->tree_lock, flags);
+			if (mapping_cap_account_dirty(mapping))
 				dec_page_state(nr_dirty);
 			return 1;
 		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		write_unlock_irqrestore(&mapping->tree_lock, flags);
 		return 0;
 	}
 	return TestClearPageDirty(page);
@@ -722,7 +744,7 @@ int clear_page_dirty_for_io(struct page 
 
 	if (mapping) {
 		if (TestClearPageDirty(page)) {
-			if (!mapping->backing_dev_info->memory_backed)
+			if (mapping_cap_account_dirty(mapping))
 				dec_page_state(nr_dirty);
 			return 1;
 		}
@@ -732,30 +754,6 @@ int clear_page_dirty_for_io(struct page 
 }
 EXPORT_SYMBOL(clear_page_dirty_for_io);
 
-/*
- * Clear a page's dirty flag while ignoring dirty memory accounting
- */
-int __clear_page_dirty(struct page *page)
-{
-	struct address_space *mapping = page_mapping(page);
-
-	if (mapping) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&mapping->tree_lock, flags);
-		if (TestClearPageDirty(page)) {
-			radix_tree_tag_clear(&mapping->page_tree,
-						page_index(page),
-						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
-			return 1;
-		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
-		return 0;
-	}
-	return TestClearPageDirty(page);
-}
-
 int test_clear_page_writeback(struct page *page)
 {
 	struct address_space *mapping = page_mapping(page);
@@ -764,13 +762,13 @@ int test_clear_page_writeback(struct pag
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		write_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestClearPageWriteback(page);
 		if (ret)
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_WRITEBACK);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		write_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestClearPageWriteback(page);
 	}
@@ -785,7 +783,7 @@ int test_set_page_writeback(struct page 
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		write_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestSetPageWriteback(page);
 		if (!ret)
 			radix_tree_tag_set(&mapping->page_tree,
@@ -795,7 +793,7 @@ int test_set_page_writeback(struct page 
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		write_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestSetPageWriteback(page);
 	}
@@ -813,9 +811,9 @@ int mapping_tagged(struct address_space 
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&mapping->tree_lock, flags);
+	read_lock_irqsave(&mapping->tree_lock, flags);
 	ret = radix_tree_tagged(&mapping->page_tree, tag);
-	spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	read_unlock_irqrestore(&mapping->tree_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(mapping_tagged);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -31,19 +31,26 @@
 #include <linux/topology.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/nodemask.h>
 #include <linux/vmalloc.h>
 
 #include <asm/tlbflush.h>
 #include "internal.h"
 
-/* MCD - HACK: Find somewhere to initialize this EARLY, or make this initializer cleaner */
+/*
+ * MCD - HACK: Find somewhere to initialize this EARLY, or make this
+ * initializer cleaner
+ */
 nodemask_t node_online_map = { { [0] = 1UL } };
+EXPORT_SYMBOL(node_online_map);
 nodemask_t node_possible_map = NODE_MASK_ALL;
+EXPORT_SYMBOL(node_possible_map);
 struct pglist_data *pgdat_list;
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
 long nr_swap_pages;
+
 /*
  * results with 256, 32 in the lowmem_reserve sysctl:
  *	1G machine -> (16M dma, 800M-16M normal, 1G-800M high)
@@ -191,6 +198,37 @@ static inline void rmv_page_order(struct
 }
 
 /*
+ * Locate the struct page for both the matching buddy in our
+ * pair (buddy1) and the combined O(n+1) page they form (page).
+ *
+ * 1) Any buddy B1 will have an order O twin B2 which satisfies
+ * the following equation:
+ *     B2 = B1 ^ (1 << O)
+ * For example, if the starting buddy (buddy2) is #8 its order
+ * 1 buddy is #10:
+ *     B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
+ *
+ * 2) Any buddy B will have an order O+1 parent P which
+ * satisfies the following equation:
+ *     P = B & ~(1 << O)
+ *
+ * Assumption: *_mem_map is contigious at least up to MAX_ORDER
+ */
+static inline struct page *
+__page_find_buddy(struct page *page, unsigned long page_idx, unsigned int order)
+{
+	unsigned long buddy_idx = page_idx ^ (1 << order);
+
+	return page + (buddy_idx - page_idx);
+}
+
+static inline unsigned long
+__find_combined_index(unsigned long page_idx, unsigned int order)
+{
+	return (page_idx & ~(1 << order));
+}
+
+/*
  * This function checks whether a page is free && is the buddy
  * we can do coalesce a page and its buddy if
  * (a) the buddy is free &&
@@ -233,50 +271,49 @@ static inline int page_is_buddy(struct p
  * -- wli
  */
 
-static inline void __free_pages_bulk (struct page *page, struct page *base,
+static inline void __free_pages_bulk (struct page *page,
 		struct zone *zone, unsigned int order)
 {
 	unsigned long page_idx;
-	struct page *coalesced;
 	int order_size = 1 << order;
 
 	if (unlikely(order))
 		destroy_compound_page(page, order);
 
-	page_idx = page - base;
+	page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
 
 	BUG_ON(page_idx & (order_size - 1));
 	BUG_ON(bad_range(zone, page));
 
 	zone->free_pages += order_size;
 	while (order < MAX_ORDER-1) {
+		unsigned long combined_idx;
 		struct free_area *area;
 		struct page *buddy;
-		int buddy_idx;
 
-		buddy_idx = (page_idx ^ (1 << order));
-		buddy = base + buddy_idx;
+		combined_idx = __find_combined_index(page_idx, order);
+		buddy = __page_find_buddy(page, page_idx, order);
+
 		if (bad_range(zone, buddy))
 			break;
 		if (!page_is_buddy(buddy, order))
-			break;
-		/* Move the buddy up one level. */
+			break;		/* Move the buddy up one level. */
 		list_del(&buddy->lru);
 		area = zone->free_area + order;
 		area->nr_free--;
 		rmv_page_order(buddy);
-		page_idx &= buddy_idx;
+		page = page + (combined_idx - page_idx);
+		page_idx = combined_idx;
 		order++;
 	}
-	coalesced = base + page_idx;
-	set_page_order(coalesced, order);
-	list_add(&coalesced->lru, &zone->free_area[order].free_list);
+	set_page_order(page, order);
+	list_add(&page->lru, &zone->free_area[order].free_list);
 	zone->free_area[order].nr_free++;
 }
 
 static inline void free_pages_check(const char *function, struct page *page)
 {
-	if (	page_mapped(page) ||
+	if (	page_mapcount(page) ||
 		page->mapping != NULL ||
 		page_count(page) != 0 ||
 		(page->flags & (
@@ -309,10 +346,9 @@ free_pages_bulk(struct zone *zone, int c
 		struct list_head *list, unsigned int order)
 {
 	unsigned long flags;
-	struct page *base, *page = NULL;
+	struct page *page = NULL;
 	int ret = 0;
 
-	base = zone->zone_mem_map;
 	spin_lock_irqsave(&zone->lock, flags);
 	zone->all_unreclaimable = 0;
 	zone->pages_scanned = 0;
@@ -320,7 +356,7 @@ free_pages_bulk(struct zone *zone, int c
 		page = list_entry(list->prev, struct page, lru);
 		/* have to delete it as __free_pages_bulk list manipulates */
 		list_del(&page->lru);
-		__free_pages_bulk(page, base, zone, order);
+		__free_pages_bulk(page, zone, order);
 		ret++;
 	}
 	spin_unlock_irqrestore(&zone->lock, flags);
@@ -404,7 +440,7 @@ void set_page_refs(struct page *page, in
  */
 static void prep_new_page(struct page *page, int order)
 {
-	if (page->mapping || page_mapped(page) ||
+	if (page->mapping || page_mapcount(page) ||
 	    (page->flags & (
 			1 << PG_private	|
 			1 << PG_locked	|
@@ -599,7 +635,7 @@ void fastcall free_cold_page(struct page
 	free_hot_cold_page(page, 1);
 }
 
-static inline void prep_zero_page(struct page *page, int order, int gfp_flags)
+static inline void prep_zero_page(struct page *page, int order, unsigned int __nocast gfp_flags)
 {
 	int i;
 
@@ -614,7 +650,7 @@ static inline void prep_zero_page(struct
  * or two.
  */
 static struct page *
-buffered_rmqueue(struct zone *zone, int order, int gfp_flags)
+buffered_rmqueue(struct zone *zone, int order, unsigned int __nocast gfp_flags)
 {
 	unsigned long flags;
 	struct page *page = NULL;
@@ -692,7 +728,7 @@ int zone_watermark_ok(struct zone *z, in
  * This is the 'heart' of the zoned buddy allocator.
  */
 struct page * fastcall
-__alloc_pages(unsigned int gfp_mask, unsigned int order,
+__alloc_pages(unsigned int __nocast gfp_mask, unsigned int order,
 		struct zonelist *zonelist)
 {
 	const int wait = gfp_mask & __GFP_WAIT;
@@ -732,6 +768,9 @@ __alloc_pages(unsigned int gfp_mask, uns
 				       classzone_idx, 0, 0))
 			continue;
 
+		if (!cpuset_zone_allowed(z))
+			continue;
+
 		page = buffered_rmqueue(z, order, gfp_mask);
 		if (page)
 			goto got_pg;
@@ -743,6 +782,9 @@ __alloc_pages(unsigned int gfp_mask, uns
 	/*
 	 * Go through the zonelist again. Let __GFP_HIGH and allocations
 	 * coming from realtime tasks to go deeper into reserves
+	 *
+	 * This is the last chance, in general, before the goto nopage.
+	 * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
 	 */
 	for (i = 0; (z = zones[i]) != NULL; i++) {
 		if (!zone_watermark_ok(z, order, z->pages_min,
@@ -750,18 +792,27 @@ __alloc_pages(unsigned int gfp_mask, uns
 				       gfp_mask & __GFP_HIGH))
 			continue;
 
+		if (wait && !cpuset_zone_allowed(z))
+			continue;
+
 		page = buffered_rmqueue(z, order, gfp_mask);
 		if (page)
 			goto got_pg;
 	}
 
 	/* This allocation should allow future memory freeing. */
-	if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) && !in_interrupt()) {
-		/* go through the zonelist yet again, ignoring mins */
-		for (i = 0; (z = zones[i]) != NULL; i++) {
-			page = buffered_rmqueue(z, order, gfp_mask);
-			if (page)
-				goto got_pg;
+
+	if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))
+			&& !in_interrupt()) {
+		if (!(gfp_mask & __GFP_NOMEMALLOC)) {
+			/* go through the zonelist yet again, ignoring mins */
+			for (i = 0; (z = zones[i]) != NULL; i++) {
+				if (!cpuset_zone_allowed(z))
+					continue;
+				page = buffered_rmqueue(z, order, gfp_mask);
+				if (page)
+					goto got_pg;
+			}
 		}
 		goto nopage;
 	}
@@ -798,6 +849,9 @@ rebalance:
 					       gfp_mask & __GFP_HIGH))
 				continue;
 
+			if (!cpuset_zone_allowed(z))
+				continue;
+
 			page = buffered_rmqueue(z, order, gfp_mask);
 			if (page)
 				goto got_pg;
@@ -814,6 +868,9 @@ rebalance:
 					       classzone_idx, 0, 0))
 				continue;
 
+			if (!cpuset_zone_allowed(z))
+				continue;
+
 			page = buffered_rmqueue(z, order, gfp_mask);
 			if (page)
 				goto got_pg;
@@ -860,7 +917,7 @@ EXPORT_SYMBOL(__alloc_pages);
 /*
  * Common helper functions.
  */
-fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
+fastcall unsigned long __get_free_pages(unsigned int __nocast gfp_mask, unsigned int order)
 {
 	struct page * page;
 	page = alloc_pages(gfp_mask, order);
@@ -871,7 +928,7 @@ fastcall unsigned long __get_free_pages(
 
 EXPORT_SYMBOL(__get_free_pages);
 
-fastcall unsigned long get_zeroed_page(unsigned int gfp_mask)
+fastcall unsigned long get_zeroed_page(unsigned int __nocast gfp_mask)
 {
 	struct page * page;
 
@@ -1300,8 +1357,7 @@ static int __init build_zonelists_node(p
 #define MAX_NODE_LOAD (num_online_nodes())
 static int __initdata node_load[MAX_NUMNODES];
 /**
- * find_next_best_node - find the next node that should appear in a given
- *    node's fallback list
+ * find_next_best_node - find the next node that should appear in a given node's fallback list
  * @node: node whose fallback list we're appending
  * @used_node_mask: nodemask_t of already used nodes
  *
@@ -1370,7 +1426,6 @@ static void __init build_zonelists(pg_da
 	/* initialize zonelists */
 	for (i = 0; i < GFP_ZONETYPES; i++) {
 		zonelist = pgdat->node_zonelists + i;
-		memset(zonelist, 0, sizeof(*zonelist));
 		zonelist->zones[0] = NULL;
 	}
 
@@ -1417,7 +1472,6 @@ static void __init build_zonelists(pg_da
 		struct zonelist *zonelist;
 
 		zonelist = pgdat->node_zonelists + i;
-		memset(zonelist, 0, sizeof(*zonelist));
 
 		j = 0;
 		k = ZONE_NORMAL;
@@ -1459,6 +1513,7 @@ void __init build_all_zonelists(void)
 	for_each_online_node(i)
 		build_zonelists(NODE_DATA(i));
 	printk("Built %i zonelists\n", num_online_nodes());
+	cpuset_init_current_mems_allowed();
 }
 
 /*
@@ -1621,6 +1676,18 @@ static void __init free_area_init_core(s
 		if (batch < 1)
 			batch = 1;
 
+		/*
+		 * Clamp the batch to a 2^n - 1 value. Having a power
+		 * of 2 value was found to be more likely to have
+		 * suboptimal cache aliasing properties in some cases.
+		 *
+		 * For example if 2 tasks are alternately allocating
+		 * batches of pages, one task can end up with a lot
+		 * of pages of one half of the possible page colors
+		 * and the other with pages of the other colors.
+		 */
+		batch = (1 << fls(batch + batch/2)) - 1;
+
 		for (cpu = 0; cpu < NR_CPUS; cpu++) {
 			struct per_cpu_pages *pcp;
 
@@ -1679,14 +1746,25 @@ static void __init free_area_init_core(s
 	}
 }
 
-void __init node_alloc_mem_map(struct pglist_data *pgdat)
+static void __init alloc_node_mem_map(struct pglist_data *pgdat)
 {
 	unsigned long size;
 
-	size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
-	pgdat->node_mem_map = alloc_bootmem_node(pgdat, size);
+	/* Skip empty nodes */
+	if (!pgdat->node_spanned_pages)
+		return;
+
+	/* ia64 gets its own node_mem_map, before this, without bootmem */
+	if (!pgdat->node_mem_map) {
+		size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
+		pgdat->node_mem_map = alloc_bootmem_node(pgdat, size);
+	}
 #ifndef CONFIG_DISCONTIGMEM
-	mem_map = contig_page_data.node_mem_map;
+	/*
+	 * With no DISCONTIG, the global mem_map is just set as node 0's
+	 */
+	if (pgdat == NODE_DATA(0))
+		mem_map = NODE_DATA(0)->node_mem_map;
 #endif
 }
 
@@ -1698,8 +1776,7 @@ void __init free_area_init_node(int nid,
 	pgdat->node_start_pfn = node_start_pfn;
 	calculate_zone_totalpages(pgdat, zones_size, zholes_size);
 
-	if (!pfn_to_page(node_start_pfn))
-		node_alloc_mem_map(pgdat);
+	alloc_node_mem_map(pgdat);
 
 	free_area_init_core(pgdat, zones_size, zholes_size);
 }
@@ -1821,6 +1898,7 @@ static char *vmstat_text[] = {
 	"allocstall",
 
 	"pgrotated",
+	"nr_bounce",
 };
 
 static void *vmstat_start(struct seq_file *m, loff_t *pos)
@@ -1924,15 +2002,20 @@ static void setup_per_zone_lowmem_reserv
 
 	for_each_pgdat(pgdat) {
 		for (j = 0; j < MAX_NR_ZONES; j++) {
-			struct zone * zone = pgdat->node_zones + j;
+			struct zone *zone = pgdat->node_zones + j;
 			unsigned long present_pages = zone->present_pages;
 
 			zone->lowmem_reserve[j] = 0;
 
 			for (idx = j-1; idx >= 0; idx--) {
-				struct zone * lower_zone = pgdat->node_zones + idx;
+				struct zone *lower_zone;
+
+				if (sysctl_lowmem_reserve_ratio[idx] < 1)
+					sysctl_lowmem_reserve_ratio[idx] = 1;
 
-				lower_zone->lowmem_reserve[j] = present_pages / sysctl_lowmem_reserve_ratio[idx];
+				lower_zone = pgdat->node_zones + idx;
+				lower_zone->lowmem_reserve[j] = present_pages /
+					sysctl_lowmem_reserve_ratio[idx];
 				present_pages += lower_zone->present_pages;
 			}
 		}
@@ -2039,7 +2122,7 @@ module_init(init_per_zone_pages_min)
  *	changes.
  */
 int min_free_kbytes_sysctl_handler(ctl_table *table, int write, 
-		struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+	struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
 	proc_dointvec(table, write, file, buffer, length, ppos);
 	setup_per_zone_pages_min();
@@ -2056,7 +2139,7 @@ int min_free_kbytes_sysctl_handler(ctl_t
  * if in function of the boot time zone sizes.
  */
 int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
-		 struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+	struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
 	proc_dointvec_minmax(table, write, file, buffer, length, ppos);
 	setup_per_zone_lowmem_reserve();
diff --git a/mm/page_io.c b/mm/page_io.c
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -19,7 +19,7 @@
 #include <linux/writeback.h>
 #include <asm/pgtable.h>
 
-static struct bio *get_swap_bio(int gfp_flags, pgoff_t index,
+static struct bio *get_swap_bio(unsigned int __nocast gfp_flags, pgoff_t index,
 				struct page *page, bio_end_io_t end_io)
 {
 	struct bio *bio;
diff --git a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -23,6 +23,7 @@ EXPORT_SYMBOL(default_unplug_io_fn);
 struct backing_dev_info default_backing_dev_info = {
 	.ra_pages	= (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
 	.state		= 0,
+	.capabilities	= BDI_CAP_MAP_COPY,
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 EXPORT_SYMBOL_GPL(default_backing_dev_info);
@@ -55,7 +56,7 @@ static inline void ra_off(struct file_ra
 {
 	ra->start = 0;
 	ra->flags = 0;
-	ra->size = -1;
+	ra->size = 0;
 	ra->ahead_start = 0;
 	ra->ahead_size = 0;
 	return;
@@ -85,14 +86,16 @@ static unsigned long get_init_ra_size(un
  * not for each call to readahead.  If a cache miss occured, reduce next I/O
  * size, else increase depending on how close to max we are.
  */
-static unsigned long get_next_ra_size(unsigned long cur, unsigned long max,
-				unsigned long min, unsigned long * flags)
+static inline unsigned long get_next_ra_size(struct file_ra_state *ra)
 {
+	unsigned long max = get_max_readahead(ra);
+	unsigned long min = get_min_readahead(ra);
+	unsigned long cur = ra->size;
 	unsigned long newsize;
 
-	if (*flags & RA_FLAG_MISS) {
+	if (ra->flags & RA_FLAG_MISS) {
+		ra->flags &= ~RA_FLAG_MISS;
 		newsize = max((cur - 2), min);
-		*flags &= ~RA_FLAG_MISS;
 	} else if (cur < max / 16) {
 		newsize = 4 * cur;
 	} else {
@@ -190,18 +193,16 @@ out:
  * size:	Number of pages in that read
  *              Together, these form the "current window".
  *              Together, start and size represent the `readahead window'.
- * next_size:   The number of pages to read on the next readahead miss.
- *              Has the magical value -1UL if readahead has been disabled.
  * prev_page:   The page which the readahead algorithm most-recently inspected.
- *              prev_page is mainly an optimisation: if page_cache_readahead
- *		sees that it is again being called for a page which it just
- *		looked at, it can return immediately without making any state
- *		changes.
+ *              It is mainly used to detect sequential file reading.
+ *              If page_cache_readahead sees that it is again being called for
+ *              a page which it just looked at, it can return immediately without
+ *              making any state changes.
  * ahead_start,
  * ahead_size:  Together, these form the "ahead window".
  * ra_pages:	The externally controlled max readahead for this fd.
  *
- * When readahead is in the off state (size == -1UL), readahead is disabled.
+ * When readahead is in the off state (size == 0), readahead is disabled.
  * In this state, prev_page is used to detect the resumption of sequential I/O.
  *
  * The readahead code manages two windows - the "current" and the "ahead"
@@ -222,7 +223,7 @@ out:
  *           ahead window.
  *
  * A `readahead hit' occurs when a read request is made against a page which is
- * the next sequential page. Ahead windowe calculations are done only when it
+ * the next sequential page. Ahead window calculations are done only when it
  * is time to submit a new IO.  The code ramps up the size agressively at first,
  * but slow down as it approaches max_readhead.
  *
@@ -233,12 +234,9 @@ out:
  * read happens to be the first page of the file, it is assumed that a linear
  * read is about to happen and the window is immediately set to the initial size
  * based on I/O request size and the max_readahead.
- * 
- * A page request at (start + size) is not a miss at all - it's just a part of
- * sequential file reading.
  *
  * This function is to be called for every read request, rather than when
- * it is time to perform readahead.  It is called only oce for the entire I/O
+ * it is time to perform readahead.  It is called only once for the entire I/O
  * regardless of size unless readahead is unable to start enough I/O to satisfy
  * the request (I/O request > max_readahead).
  */
@@ -274,7 +272,7 @@ __do_page_cache_readahead(struct address
 	/*
 	 * Preallocate as many pages as we will need.
 	 */
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
 		unsigned long page_offset = offset + page_idx;
 		
@@ -285,16 +283,16 @@ __do_page_cache_readahead(struct address
 		if (page)
 			continue;
 
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (!page)
 			break;
 		page->index = page_offset;
 		list_add(&page->lru, &page_pool);
 		ret++;
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 
 	/*
 	 * Now start the IO.  We ignore I/O errors - if the page is not
@@ -346,8 +344,8 @@ int force_page_cache_readahead(struct ad
  * readahead isn't helping.
  *
  */
-int check_ra_success(struct file_ra_state *ra, unsigned long nr_to_read,
-				 unsigned long actual)
+static inline int check_ra_success(struct file_ra_state *ra,
+			unsigned long nr_to_read, unsigned long actual)
 {
 	if (actual == 0) {
 		ra->cache_hit += nr_to_read;
@@ -392,18 +390,46 @@ blockable_page_cache_readahead(struct ad
 {
 	int actual;
 
-	if (block) {
-		actual = __do_page_cache_readahead(mapping, filp,
-						offset, nr_to_read);
-	} else {
-		actual = do_page_cache_readahead(mapping, filp,
-						offset, nr_to_read);
-		if (actual == -1)
-			return 0;
-	}
+	if (!block && bdi_read_congested(mapping->backing_dev_info))
+		return 0;
+
+	actual = __do_page_cache_readahead(mapping, filp, offset, nr_to_read);
+
 	return check_ra_success(ra, nr_to_read, actual);
 }
 
+static int make_ahead_window(struct address_space *mapping, struct file *filp,
+				struct file_ra_state *ra, int force)
+{
+	int block, ret;
+
+	ra->ahead_size = get_next_ra_size(ra);
+	ra->ahead_start = ra->start + ra->size;
+
+	block = force || (ra->prev_page >= ra->ahead_start);
+	ret = blockable_page_cache_readahead(mapping, filp,
+			ra->ahead_start, ra->ahead_size, ra, block);
+
+	if (!ret && !force) {
+		/* A read failure in blocking mode, implies pages are
+		 * all cached. So we can safely assume we have taken
+		 * care of all the pages requested in this call.
+		 * A read failure in non-blocking mode, implies we are
+		 * reading more pages than requested in this call.  So
+		 * we safely assume we have taken care of all the pages
+		 * requested in this call.
+		 *
+		 * Just reset the ahead window in case we failed due to
+		 * congestion.  The ahead window will any way be closed
+		 * in case we failed due to excessive page cache hits.
+		 */
+		ra->ahead_start = 0;
+		ra->ahead_size = 0;
+	}
+
+	return ret;
+}
+
 /*
  * page_cache_readahead is the main function.  If performs the adaptive
  * readahead window size management and submits the readahead I/O.
@@ -413,37 +439,35 @@ page_cache_readahead(struct address_spac
 		     struct file *filp, unsigned long offset,
 		     unsigned long req_size)
 {
-	unsigned long max, min;
-	unsigned long newsize = req_size;
-	unsigned long block;
+	unsigned long max, newsize;
+	int sequential;
 
 	/*
-	 * Here we detect the case where the application is performing
-	 * sub-page sized reads.  We avoid doing extra work and bogusly
-	 * perturbing the readahead window expansion logic.
-	 * If size is zero, there is no read ahead window so we need one
+	 * We avoid doing extra work and bogusly perturbing the readahead
+	 * window expansion logic.
 	 */
-	if (offset == ra->prev_page && req_size == 1 && ra->size != 0)
-		goto out;
+	if (offset == ra->prev_page && --req_size)
+		++offset;
+
+	/* Note that prev_page == -1 if it is a first read */
+	sequential = (offset == ra->prev_page + 1);
+	ra->prev_page = offset;
 
 	max = get_max_readahead(ra);
-	min = get_min_readahead(ra);
 	newsize = min(req_size, max);
 
-	if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE)) {
-		newsize = 1;
-		ra->prev_page = offset;
-		goto out;	/* No readahead or file already in cache */
-	}
+	/* No readahead or sub-page sized read or file already in cache */
+	if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE))
+		goto out;
+
+	ra->prev_page += newsize - 1;
+
 	/*
-	 * Special case - first read.  We'll assume it's a whole-file read if
-	 * at start of file, and grow the window fast.  Or detect first
+	 * Special case - first read at start of file. We'll assume it's
+	 * a whole-file read and grow the window fast.  Or detect first
 	 * sequential access
 	 */
-	if ((ra->size == 0 && offset == 0)	/* first io and start of file */
-	    || (ra->size == -1 && ra->prev_page == offset - 1)) {
-		/* First sequential */
-		ra->prev_page  = offset + newsize - 1;
+	if (sequential && ra->size == 0) {
 		ra->size = get_init_ra_size(newsize, max);
 		ra->start = offset;
 		if (!blockable_page_cache_readahead(mapping, filp, offset,
@@ -458,13 +482,9 @@ page_cache_readahead(struct address_spac
 		 * IOs,* thus preventing stalls. so issue the ahead window
 		 * immediately.
 		 */
-		if (req_size >= max) {
-			ra->ahead_size = get_next_ra_size(ra->size, max, min,
-							  &ra->flags);
-			ra->ahead_start = ra->start + ra->size;
-			blockable_page_cache_readahead(mapping, filp,
-				 ra->ahead_start, ra->ahead_size, ra, 1);
-		}
+		if (req_size >= max)
+			make_ahead_window(mapping, filp, ra, 1);
+
 		goto out;
 	}
 
@@ -473,9 +493,8 @@ page_cache_readahead(struct address_spac
 	 * partial page reads and first access were handled above,
 	 * so this must be the next page otherwise it is random
 	 */
-	if ((offset != (ra->prev_page+1) || (ra->size == 0))) {
+	if (!sequential) {
 		ra_off(ra);
-		ra->prev_page  = offset + newsize - 1;
 		blockable_page_cache_readahead(mapping, filp, offset,
 				 newsize, ra, 1);
 		goto out;
@@ -487,28 +506,8 @@ page_cache_readahead(struct address_spac
 	 */
 
 	if (ra->ahead_start == 0) {	 /* no ahead window yet */
-		ra->ahead_size = get_next_ra_size(ra->size, max, min,
-						  &ra->flags);
-		ra->ahead_start = ra->start + ra->size;
-		block = ((offset + newsize -1) >= ra->ahead_start);
-		if (!blockable_page_cache_readahead(mapping, filp,
-		    ra->ahead_start, ra->ahead_size, ra, block)) {
-			/* A read failure in blocking mode, implies pages are
-			 * all cached. So we can safely assume we have taken
-			 * care of all the pages requested in this call. A read
-			 * failure in non-blocking mode, implies we are reading
-			 * more pages than requested in this call.  So we safely
-			 * assume we have taken care of all the pages requested
-			 * in this call.
-			 *
-			 * Just reset the ahead window in case we failed due to
-			 * congestion.  The ahead window will any way be closed
-			 * in case we failed due to exessive page cache hits.
-			 */
-			ra->ahead_start = 0;
-			ra->ahead_size = 0;
+		if (!make_ahead_window(mapping, filp, ra, 0))
 			goto out;
-		}
 	}
 	/*
 	 * Already have an ahead window, check if we crossed into it.
@@ -517,35 +516,14 @@ page_cache_readahead(struct address_spac
 	 * we get called back on the first page of the ahead window which
 	 * will allow us to submit more IO.
 	 */
-	if ((offset + newsize - 1) >= ra->ahead_start) {
+	if (ra->prev_page >= ra->ahead_start) {
 		ra->start = ra->ahead_start;
 		ra->size = ra->ahead_size;
-		ra->ahead_start = ra->ahead_start + ra->ahead_size;
-		ra->ahead_size = get_next_ra_size(ra->ahead_size,
-						  max, min, &ra->flags);
-		block = ((offset + newsize - 1) >= ra->ahead_start);
-		if (!blockable_page_cache_readahead(mapping, filp,
-			ra->ahead_start, ra->ahead_size, ra, block)) {
-			/* A read failure in blocking mode, implies pages are
-			 * all cached. So we can safely assume we have taken
-			 * care of all the pages requested in this call.
-			 * A read failure in non-blocking mode, implies we are
-			 * reading more pages than requested in this call.  So
-			 * we safely assume we have taken care of all the pages
-			 * requested in this call.
-			 *
-			 * Just reset the ahead window in case we failed due to
-			 * congestion.  The ahead window will any way be closed
-			 * in case we failed due to excessive page cache hits.
-			 */
-			ra->ahead_start = 0;
-			ra->ahead_size = 0;
-		}
+		make_ahead_window(mapping, filp, ra, 0);
 	}
 
 out:
-	ra->prev_page = offset + newsize - 1;
-	return(newsize);
+	return ra->prev_page + 1;
 }
 
 /*
diff --git a/mm/rmap.c b/mm/rmap.c
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -51,7 +51,6 @@
 #include <linux/swapops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/acct.h>
 #include <linux/rmap.h>
 #include <linux/rcupdate.h>
 
@@ -244,6 +243,42 @@ unsigned long page_address_in_vma(struct
 }
 
 /*
+ * Check that @page is mapped at @address into @mm.
+ *
+ * On success returns with mapped pte and locked mm->page_table_lock.
+ */
+static pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+					unsigned long address)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	/*
+	 * We need the page_table_lock to protect us from page faults,
+	 * munmap, fork, etc...
+	 */
+	spin_lock(&mm->page_table_lock);
+	pgd = pgd_offset(mm, address);
+	if (likely(pgd_present(*pgd))) {
+		pud = pud_offset(pgd, address);
+		if (likely(pud_present(*pud))) {
+			pmd = pmd_offset(pud, address);
+			if (likely(pmd_present(*pmd))) {
+				pte = pte_offset_map(pmd, address);
+				if (likely(pte_present(*pte) &&
+					   page_to_pfn(page) == pte_pfn(*pte)))
+					return pte;
+				pte_unmap(pte);
+			}
+		}
+	}
+	spin_unlock(&mm->page_table_lock);
+	return ERR_PTR(-ENOENT);
+}
+
+/*
  * Subfunctions of page_referenced: page_referenced_one called
  * repeatedly from either page_referenced_anon or page_referenced_file.
  */
@@ -252,51 +287,27 @@ static int page_referenced_one(struct pa
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long address;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
 	pte_t *pte;
 	int referenced = 0;
 
-	if (!mm->rss)
+	if (!get_mm_counter(mm, rss))
 		goto out;
 	address = vma_address(page, vma);
 	if (address == -EFAULT)
 		goto out;
 
-	spin_lock(&mm->page_table_lock);
-
-	pgd = pgd_offset(mm, address);
-	if (!pgd_present(*pgd))
-		goto out_unlock;
-
-	pud = pud_offset(pgd, address);
-	if (!pud_present(*pud))
-		goto out_unlock;
-
-	pmd = pmd_offset(pud, address);
-	if (!pmd_present(*pmd))
-		goto out_unlock;
-
-	pte = pte_offset_map(pmd, address);
-	if (!pte_present(*pte))
-		goto out_unmap;
-
-	if (page_to_pfn(page) != pte_pfn(*pte))
-		goto out_unmap;
-
-	if (ptep_clear_flush_young(vma, address, pte))
-		referenced++;
-
-	if (mm != current->mm && !ignore_token && has_swap_token(mm))
-		referenced++;
+	pte = page_check_address(page, mm, address);
+	if (!IS_ERR(pte)) {
+		if (ptep_clear_flush_young(vma, address, pte))
+			referenced++;
 
-	(*mapcount)--;
+		if (mm != current->mm && !ignore_token && has_swap_token(mm))
+			referenced++;
 
-out_unmap:
-	pte_unmap(pte);
-out_unlock:
-	spin_unlock(&mm->page_table_lock);
+		(*mapcount)--;
+		pte_unmap(pte);
+		spin_unlock(&mm->page_table_lock);
+	}
 out:
 	return referenced;
 }
@@ -437,7 +448,7 @@ void page_add_anon_rmap(struct page *pag
 	BUG_ON(PageReserved(page));
 	BUG_ON(!anon_vma);
 
-	vma->vm_mm->anon_rss++;
+	inc_mm_counter(vma->vm_mm, anon_rss);
 
 	anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
 	index = (address - vma->vm_start) >> PAGE_SHIFT;
@@ -503,43 +514,19 @@ static int try_to_unmap_one(struct page 
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long address;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
 	pte_t *pte;
 	pte_t pteval;
 	int ret = SWAP_AGAIN;
 
-	if (!mm->rss)
+	if (!get_mm_counter(mm, rss))
 		goto out;
 	address = vma_address(page, vma);
 	if (address == -EFAULT)
 		goto out;
 
-	/*
-	 * We need the page_table_lock to protect us from page faults,
-	 * munmap, fork, etc...
-	 */
-	spin_lock(&mm->page_table_lock);
-
-	pgd = pgd_offset(mm, address);
-	if (!pgd_present(*pgd))
-		goto out_unlock;
-
-	pud = pud_offset(pgd, address);
-	if (!pud_present(*pud))
-		goto out_unlock;
-
-	pmd = pmd_offset(pud, address);
-	if (!pmd_present(*pmd))
-		goto out_unlock;
-
-	pte = pte_offset_map(pmd, address);
-	if (!pte_present(*pte))
-		goto out_unmap;
-
-	if (page_to_pfn(page) != pte_pfn(*pte))
-		goto out_unmap;
+	pte = page_check_address(page, mm, address);
+	if (IS_ERR(pte))
+		goto out;
 
 	/*
 	 * If the page is mlock()d, we cannot swap it out.
@@ -574,7 +561,7 @@ static int try_to_unmap_one(struct page 
 	}
 
 	/* Nuke the page table entry. */
-	flush_cache_page(vma, address);
+	flush_cache_page(vma, address, page_to_pfn(page));
 	pteval = ptep_clear_flush(vma, address, pte);
 
 	/* Move the dirty bit to the physical page now the pte is gone. */
@@ -594,19 +581,17 @@ static int try_to_unmap_one(struct page 
 			list_add(&mm->mmlist, &init_mm.mmlist);
 			spin_unlock(&mmlist_lock);
 		}
-		set_pte(pte, swp_entry_to_pte(entry));
+		set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
 		BUG_ON(pte_file(*pte));
-		mm->anon_rss--;
+		dec_mm_counter(mm, anon_rss);
 	}
 
-	mm->rss--;
-	acct_update_integrals();
+	dec_mm_counter(mm, rss);
 	page_remove_rmap(page);
 	page_cache_release(page);
 
 out_unmap:
 	pte_unmap(pte);
-out_unlock:
 	spin_unlock(&mm->page_table_lock);
 out:
 	return ret;
@@ -641,7 +626,7 @@ static void try_to_unmap_cluster(unsigne
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
-	pte_t *pte;
+	pte_t *pte, *original_pte;
 	pte_t pteval;
 	struct page *page;
 	unsigned long address;
@@ -673,7 +658,7 @@ static void try_to_unmap_cluster(unsigne
 	if (!pmd_present(*pmd))
 		goto out_unlock;
 
-	for (pte = pte_offset_map(pmd, address);
+	for (original_pte = pte = pte_offset_map(pmd, address);
 			address < end; pte++, address += PAGE_SIZE) {
 
 		if (!pte_present(*pte))
@@ -692,12 +677,12 @@ static void try_to_unmap_cluster(unsigne
 			continue;
 
 		/* Nuke the page table entry. */
-		flush_cache_page(vma, address);
+		flush_cache_page(vma, address, pfn);
 		pteval = ptep_clear_flush(vma, address, pte);
 
 		/* If nonlinear, store the file page offset in the pte. */
 		if (page->index != linear_page_index(vma, address))
-			set_pte(pte, pgoff_to_pte(page->index));
+			set_pte_at(mm, address, pte, pgoff_to_pte(page->index));
 
 		/* Move the dirty bit to the physical page now the pte is gone. */
 		if (pte_dirty(pteval))
@@ -705,13 +690,11 @@ static void try_to_unmap_cluster(unsigne
 
 		page_remove_rmap(page);
 		page_cache_release(page);
-		acct_update_integrals();
-		mm->rss--;
+		dec_mm_counter(mm, rss);
 		(*mapcount)--;
 	}
 
-	pte_unmap(pte);
-
+	pte_unmap(original_pte);
 out_unlock:
 	spin_unlock(&mm->page_table_lock);
 }
@@ -805,7 +788,7 @@ static int try_to_unmap_file(struct page
 			if (vma->vm_flags & (VM_LOCKED|VM_RESERVED))
 				continue;
 			cursor = (unsigned long) vma->vm_private_data;
-			while (vma->vm_mm->rss &&
+			while (get_mm_counter(vma->vm_mm, rss) &&
 				cursor < max_nl_cursor &&
 				cursor < vma->vm_end - vma->vm_start) {
 				try_to_unmap_cluster(cursor, &mapcount, vma);
@@ -863,3 +846,4 @@ int try_to_unmap(struct page *page)
 		ret = SWAP_SUCCESS;
 	return ret;
 }
+
diff --git a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -184,8 +184,8 @@ static struct vm_operations_struct shmem
 
 static struct backing_dev_info shmem_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
-	.unplug_io_fn = default_unplug_io_fn,
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+	.unplug_io_fn	= default_unplug_io_fn,
 };
 
 static LIST_HEAD(shmem_swaplist);
@@ -922,7 +922,7 @@ shmem_swapin(struct shmem_inode_info *in
 }
 
 static inline struct page *
-shmem_alloc_page(unsigned long gfp,struct shmem_inode_info *info,
+shmem_alloc_page(unsigned int __nocast gfp,struct shmem_inode_info *info,
 				 unsigned long idx)
 {
 	return alloc_page(gfp | __GFP_ZERO);
@@ -2172,7 +2172,7 @@ static int shmem_xattr_security_set(stru
 	return security_inode_setsecurity(inode, name, value, size, flags);
 }
 
-struct xattr_handler shmem_xattr_security_handler = {
+static struct xattr_handler shmem_xattr_security_handler = {
 	.prefix	= XATTR_SECURITY_PREFIX,
 	.list	= shmem_xattr_security_list,
 	.get	= shmem_xattr_security_get,
diff --git a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -507,10 +507,9 @@ static int slab_break_gfp_order = BREAK_
 struct cache_sizes malloc_sizes[] = {
 #define CACHE(x) { .cs_size = (x) },
 #include <linux/kmalloc_sizes.h>
-	{ 0, }
+	CACHE(ULONG_MAX)
 #undef CACHE
 };
-
 EXPORT_SYMBOL(malloc_sizes);
 
 /* Must match cache_sizes above. Out of line to keep cache footprint low. */
@@ -574,7 +573,7 @@ static void free_block(kmem_cache_t* cac
 static void enable_cpucache (kmem_cache_t *cachep);
 static void cache_reap (void *unused);
 
-static inline void ** ac_entry(struct array_cache *ac)
+static inline void **ac_entry(struct array_cache *ac)
 {
 	return (void**)(ac+1);
 }
@@ -584,24 +583,38 @@ static inline struct array_cache *ac_dat
 	return cachep->array[smp_processor_id()];
 }
 
-static kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags)
+static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
 {
 	struct cache_sizes *csizep = malloc_sizes;
 
-	/* This function could be moved to the header file, and
-	 * made inline so consumers can quickly determine what
-	 * cache pointer they require.
+#if DEBUG
+	/* This happens if someone tries to call
+ 	* kmem_cache_create(), or __kmalloc(), before
+ 	* the generic caches are initialized.
+ 	*/
+	BUG_ON(csizep->cs_cachep == NULL);
+#endif
+	while (size > csizep->cs_size)
+		csizep++;
+
+	/*
+	 * Really subtile: The last entry with cs->cs_size==ULONG_MAX
+	 * has cs_{dma,}cachep==NULL. Thus no special case
+	 * for large kmalloc calls required.
 	 */
-	for ( ; csizep->cs_size; csizep++) {
-		if (size > csizep->cs_size)
-			continue;
-		break;
-	}
-	return (gfpflags & GFP_DMA) ? csizep->cs_dmacachep : csizep->cs_cachep;
+	if (unlikely(gfpflags & GFP_DMA))
+		return csizep->cs_dmacachep;
+	return csizep->cs_cachep;
+}
+
+kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags)
+{
+	return __find_general_cachep(size, gfpflags);
 }
+EXPORT_SYMBOL(kmem_find_general_cachep);
 
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
-static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
+static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
 		 int flags, size_t *left_over, unsigned int *num)
 {
 	int i;
@@ -659,17 +672,17 @@ static void __devinit start_cpu_timer(in
 	}
 }
 
-static struct array_cache *alloc_arraycache(int cpu, int entries, int batchcount)
+static struct array_cache *alloc_arraycache(int cpu, int entries,
+						int batchcount)
 {
 	int memsize = sizeof(void*)*entries+sizeof(struct array_cache);
 	struct array_cache *nc = NULL;
 
-	if (cpu != -1) {
-		nc = kmem_cache_alloc_node(kmem_find_general_cachep(memsize,
-					GFP_KERNEL), cpu_to_node(cpu));
-	}
-	if (!nc)
+	if (cpu == -1)
 		nc = kmalloc(memsize, GFP_KERNEL);
+	else
+		nc = kmalloc_node(memsize, GFP_KERNEL, cpu_to_node(cpu));
+
 	if (nc) {
 		nc->avail = 0;
 		nc->limit = entries;
@@ -680,8 +693,7 @@ static struct array_cache *alloc_arrayca
 }
 
 static int __devinit cpuup_callback(struct notifier_block *nfb,
-				  unsigned long action,
-				  void *hcpu)
+				  unsigned long action, void *hcpu)
 {
 	long cpu = (long)hcpu;
 	kmem_cache_t* cachep;
@@ -794,7 +806,7 @@ void __init kmem_cache_init(void)
 	sizes = malloc_sizes;
 	names = cache_names;
 
-	while (sizes->cs_size) {
+	while (sizes->cs_size != ULONG_MAX) {
 		/* For performance, all the general caches are L1 aligned.
 		 * This should be particularly beneficial on SMP boxes, as it
 		 * eliminates "false sharing".
@@ -886,7 +898,7 @@ __initcall(cpucache_init);
  * did not request dmaable memory, we might get it, but that
  * would be relatively rare and ignorable.
  */
-static void *kmem_getpages(kmem_cache_t *cachep, int flags, int nodeid)
+static void *kmem_getpages(kmem_cache_t *cachep, unsigned int __nocast flags, int nodeid)
 {
 	struct page *page;
 	void *addr;
@@ -948,7 +960,8 @@ static void kmem_rcu_free(struct rcu_hea
 #if DEBUG
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
-static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, unsigned long caller)
+static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr,
+				unsigned long caller)
 {
 	int size = obj_reallen(cachep);
 
@@ -1606,7 +1619,6 @@ int kmem_cache_shrink(kmem_cache_t *cach
 
 	return __cache_shrink(cachep);
 }
-
 EXPORT_SYMBOL(kmem_cache_shrink);
 
 /**
@@ -1626,7 +1638,7 @@ EXPORT_SYMBOL(kmem_cache_shrink);
  * The caller must guarantee that noone will allocate memory from the cache
  * during the kmem_cache_destroy().
  */
-int kmem_cache_destroy (kmem_cache_t * cachep)
+int kmem_cache_destroy(kmem_cache_t * cachep)
 {
 	int i;
 
@@ -1654,7 +1666,7 @@ int kmem_cache_destroy (kmem_cache_t * c
 	}
 
 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-		synchronize_kernel();
+		synchronize_rcu();
 
 	/* no cpu_online check required here since we clear the percpu
 	 * array on cpu offline and set this to NULL.
@@ -1671,12 +1683,11 @@ int kmem_cache_destroy (kmem_cache_t * c
 
 	return 0;
 }
-
 EXPORT_SYMBOL(kmem_cache_destroy);
 
 /* Get the memory for a slab management obj. */
-static struct slab* alloc_slabmgmt (kmem_cache_t *cachep,
-			void *objp, int colour_off, int local_flags)
+static struct slab* alloc_slabmgmt(kmem_cache_t *cachep,
+			void *objp, int colour_off, unsigned int __nocast local_flags)
 {
 	struct slab *slabp;
 	
@@ -1701,8 +1712,8 @@ static inline kmem_bufctl_t *slab_bufctl
 	return (kmem_bufctl_t *)(slabp+1);
 }
 
-static void cache_init_objs (kmem_cache_t * cachep,
-			struct slab * slabp, unsigned long ctor_flags)
+static void cache_init_objs(kmem_cache_t *cachep,
+			struct slab *slabp, unsigned long ctor_flags)
 {
 	int i;
 
@@ -1747,7 +1758,7 @@ static void cache_init_objs (kmem_cache_
 	slabp->free = 0;
 }
 
-static void kmem_flagcheck(kmem_cache_t *cachep, int flags)
+static void kmem_flagcheck(kmem_cache_t *cachep, unsigned int flags)
 {
 	if (flags & SLAB_DMA) {
 		if (!(cachep->gfpflags & GFP_DMA))
@@ -1777,12 +1788,12 @@ static void set_slab_attr(kmem_cache_t *
  * Grow (by 1) the number of slabs within a cache.  This is called by
  * kmem_cache_alloc() when there are no active objs left in a cache.
  */
-static int cache_grow (kmem_cache_t * cachep, int flags, int nodeid)
+static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nodeid)
 {
 	struct slab	*slabp;
 	void		*objp;
 	size_t		 offset;
-	int		 local_flags;
+	unsigned int	 local_flags;
 	unsigned long	 ctor_flags;
 
 	/* Be lazy and only check for valid flags here,
@@ -1882,7 +1893,8 @@ static void kfree_debugcheck(const void 
 	}
 }
 
-static void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp, void *caller)
+static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
+					void *caller)
 {
 	struct page *page;
 	unsigned int objnr;
@@ -1950,18 +1962,17 @@ static void *cache_free_debugcheck (kmem
 
 static void check_slabp(kmem_cache_t *cachep, struct slab *slabp)
 {
-	int i;
+	kmem_bufctl_t i;
 	int entries = 0;
 	
 	check_spinlock_acquired(cachep);
 	/* Check slab's freelist to see if this obj is there. */
 	for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) {
 		entries++;
-		if (entries > cachep->num || i < 0 || i >= cachep->num)
+		if (entries > cachep->num || i >= cachep->num)
 			goto bad;
 	}
 	if (entries != cachep->num - slabp->inuse) {
-		int i;
 bad:
 		printk(KERN_ERR "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n",
 				cachep->name, cachep->num, slabp, slabp->inuse);
@@ -1980,7 +1991,7 @@ bad:
 #define check_slabp(x,y) do { } while(0)
 #endif
 
-static void* cache_alloc_refill(kmem_cache_t* cachep, int flags)
+static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flags)
 {
 	int batchcount;
 	struct kmem_list3 *l3;
@@ -2077,7 +2088,7 @@ alloc_done:
 }
 
 static inline void
-cache_alloc_debugcheck_before(kmem_cache_t *cachep, int flags)
+cache_alloc_debugcheck_before(kmem_cache_t *cachep, unsigned int __nocast flags)
 {
 	might_sleep_if(flags & __GFP_WAIT);
 #if DEBUG
@@ -2132,7 +2143,7 @@ cache_alloc_debugcheck_after(kmem_cache_
 #endif
 
 
-static inline void * __cache_alloc (kmem_cache_t *cachep, int flags)
+static inline void *__cache_alloc(kmem_cache_t *cachep, unsigned int __nocast flags)
 {
 	unsigned long save_flags;
 	void* objp;
@@ -2211,7 +2222,7 @@ static void free_block(kmem_cache_t *cac
 	}
 }
 
-static void cache_flusharray (kmem_cache_t* cachep, struct array_cache *ac)
+static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac)
 {
 	int batchcount;
 
@@ -2268,7 +2279,7 @@ free_done:
  *
  * Called with disabled ints.
  */
-static inline void __cache_free (kmem_cache_t *cachep, void* objp)
+static inline void __cache_free(kmem_cache_t *cachep, void *objp)
 {
 	struct array_cache *ac = ac_data(cachep);
 
@@ -2294,11 +2305,10 @@ static inline void __cache_free (kmem_ca
  * Allocate an object from this cache.  The flags are only relevant
  * if the cache has no available objects.
  */
-void * kmem_cache_alloc (kmem_cache_t *cachep, int flags)
+void *kmem_cache_alloc(kmem_cache_t *cachep, unsigned int __nocast flags)
 {
 	return __cache_alloc(cachep, flags);
 }
-
 EXPORT_SYMBOL(kmem_cache_alloc);
 
 /**
@@ -2354,7 +2364,7 @@ out:
  * and can sleep. And it will allocate memory on the given node, which
  * can improve the performance for cpu bound structures.
  */
-void *kmem_cache_alloc_node(kmem_cache_t *cachep, int nodeid)
+void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid)
 {
 	int loop;
 	void *objp;
@@ -2386,7 +2396,7 @@ void *kmem_cache_alloc_node(kmem_cache_t
 		spin_unlock_irq(&cachep->spinlock);
 
 		local_irq_disable();
-		if (!cache_grow(cachep, GFP_KERNEL, nodeid)) {
+		if (!cache_grow(cachep, flags, nodeid)) {
 			local_irq_enable();
 			return NULL;
 		}
@@ -2428,6 +2438,16 @@ got_slabp:
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 
+void *kmalloc_node(size_t size, int flags, int node)
+{
+	kmem_cache_t *cachep;
+
+	cachep = kmem_find_general_cachep(size, flags);
+	if (unlikely(cachep == NULL))
+		return NULL;
+	return kmem_cache_alloc_node(cachep, flags, node);
+}
+EXPORT_SYMBOL(kmalloc_node);
 #endif
 
 /**
@@ -2451,26 +2471,20 @@ EXPORT_SYMBOL(kmem_cache_alloc_node);
  * platforms.  For example, on i386, it means that the memory must come
  * from the first 16MB.
  */
-void * __kmalloc (size_t size, int flags)
+void *__kmalloc(size_t size, unsigned int __nocast flags)
 {
-	struct cache_sizes *csizep = malloc_sizes;
+	kmem_cache_t *cachep;
 
-	for (; csizep->cs_size; csizep++) {
-		if (size > csizep->cs_size)
-			continue;
-#if DEBUG
-		/* This happens if someone tries to call
-		 * kmem_cache_create(), or kmalloc(), before
-		 * the generic caches are initialized.
-		 */
-		BUG_ON(csizep->cs_cachep == NULL);
-#endif
-		return __cache_alloc(flags & GFP_DMA ?
-			 csizep->cs_dmacachep : csizep->cs_cachep, flags);
-	}
-	return NULL;
+	/* If you want to save a few bytes .text space: replace
+	 * __ with kmem_.
+	 * Then kmalloc uses the uninlined functions instead of the inline
+	 * functions.
+	 */
+	cachep = __find_general_cachep(size, flags);
+	if (unlikely(cachep == NULL))
+		return NULL;
+	return __cache_alloc(cachep, flags);
 }
-
 EXPORT_SYMBOL(__kmalloc);
 
 #ifdef CONFIG_SMP
@@ -2493,9 +2507,8 @@ void *__alloc_percpu(size_t size, size_t
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_possible(i))
 			continue;
-		pdata->ptrs[i] = kmem_cache_alloc_node(
-				kmem_find_general_cachep(size, GFP_KERNEL),
-				cpu_to_node(i));
+		pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL,
+						cpu_to_node(i));
 
 		if (!pdata->ptrs[i])
 			goto unwind_oom;
@@ -2514,7 +2527,6 @@ unwind_oom:
 	kfree(pdata);
 	return NULL;
 }
-
 EXPORT_SYMBOL(__alloc_percpu);
 #endif
 
@@ -2526,7 +2538,7 @@ EXPORT_SYMBOL(__alloc_percpu);
  * Free an object which was previously allocated from this
  * cache.
  */
-void kmem_cache_free (kmem_cache_t *cachep, void *objp)
+void kmem_cache_free(kmem_cache_t *cachep, void *objp)
 {
 	unsigned long flags;
 
@@ -2534,7 +2546,6 @@ void kmem_cache_free (kmem_cache_t *cach
 	__cache_free(cachep, objp);
 	local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(kmem_cache_free);
 
 /**
@@ -2543,7 +2554,7 @@ EXPORT_SYMBOL(kmem_cache_free);
  * @size: element size.
  * @flags: the type of memory to allocate.
  */
-void *kcalloc(size_t n, size_t size, int flags)
+void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
 {
 	void *ret = NULL;
 
@@ -2555,7 +2566,6 @@ void *kcalloc(size_t n, size_t size, int
 		memset(ret, 0, n * size);
 	return ret;
 }
-
 EXPORT_SYMBOL(kcalloc);
 
 /**
@@ -2565,12 +2575,12 @@ EXPORT_SYMBOL(kcalloc);
  * Don't free memory not originally allocated by kmalloc()
  * or you will run into trouble.
  */
-void kfree (const void *objp)
+void kfree(const void *objp)
 {
 	kmem_cache_t *c;
 	unsigned long flags;
 
-	if (!objp)
+	if (unlikely(!objp))
 		return;
 	local_irq_save(flags);
 	kfree_debugcheck(objp);
@@ -2578,7 +2588,6 @@ void kfree (const void *objp)
 	__cache_free(c, (void*)objp);
 	local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(kfree);
 
 #ifdef CONFIG_SMP
@@ -2602,7 +2611,6 @@ free_percpu(const void *objp)
 	}
 	kfree(p);
 }
-
 EXPORT_SYMBOL(free_percpu);
 #endif
 
@@ -2610,7 +2618,6 @@ unsigned int kmem_cache_size(kmem_cache_
 {
 	return obj_reallen(cachep);
 }
-
 EXPORT_SYMBOL(kmem_cache_size);
 
 struct ccupdate_struct {
@@ -2631,7 +2638,8 @@ static void do_ccupdate_local(void *info
 }
 
 
-static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount, int shared)
+static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount,
+				int shared)
 {
 	struct ccupdate_struct new;
 	struct array_cache *new_shared;
@@ -2686,7 +2694,7 @@ static int do_tune_cpucache (kmem_cache_
 }
 
 
-static void enable_cpucache (kmem_cache_t *cachep)
+static void enable_cpucache(kmem_cache_t *cachep)
 {
 	int err;
 	int limit, shared;
diff --git a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -29,13 +29,13 @@ static struct address_space_operations s
 };
 
 static struct backing_dev_info swap_backing_dev_info = {
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 	.unplug_io_fn	= swap_unplug_io_fn,
 };
 
 struct address_space swapper_space = {
 	.page_tree	= RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),
-	.tree_lock	= SPIN_LOCK_UNLOCKED,
+	.tree_lock	= RW_LOCK_UNLOCKED,
 	.a_ops		= &swap_aops,
 	.i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear),
 	.backing_dev_info = &swap_backing_dev_info,
@@ -76,7 +76,7 @@ static int __add_to_swap_cache(struct pa
 	BUG_ON(PagePrivate(page));
 	error = radix_tree_preload(gfp_mask);
 	if (!error) {
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		error = radix_tree_insert(&swapper_space.page_tree,
 						entry.val, page);
 		if (!error) {
@@ -87,7 +87,7 @@ static int __add_to_swap_cache(struct pa
 			total_swapcache_pages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -143,7 +143,6 @@ void __delete_from_swap_cache(struct pag
 int add_to_swap(struct page * page)
 {
 	swp_entry_t entry;
-	int pf_flags;
 	int err;
 
 	if (!PageLocked(page))
@@ -154,29 +153,19 @@ int add_to_swap(struct page * page)
 		if (!entry.val)
 			return 0;
 
-		/* Radix-tree node allocations are performing
-		 * GFP_ATOMIC allocations under PF_MEMALLOC.  
-		 * They can completely exhaust the page allocator.  
-		 *
-		 * So PF_MEMALLOC is dropped here.  This causes the slab 
-		 * allocations to fail earlier, so radix-tree nodes will 
-		 * then be allocated from the mempool reserves.
+		/*
+		 * Radix-tree node allocations from PF_MEMALLOC contexts could
+		 * completely exhaust the page allocator. __GFP_NOMEMALLOC
+		 * stops emergency reserves from being allocated.
 		 *
-		 * We're still using __GFP_HIGH for radix-tree node
-		 * allocations, so some of the emergency pools are available,
-		 * just not all of them.
+		 * TODO: this could cause a theoretical memory reclaim
+		 * deadlock in the swap out path.
 		 */
-
-		pf_flags = current->flags;
-		current->flags &= ~PF_MEMALLOC;
-
 		/*
 		 * Add it to the swap cache and mark it dirty
 		 */
-		err = __add_to_swap_cache(page, entry, GFP_ATOMIC|__GFP_NOWARN);
-
-		if (pf_flags & PF_MEMALLOC)
-			current->flags |= PF_MEMALLOC;
+		err = __add_to_swap_cache(page, entry,
+				GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN);
 
 		switch (err) {
 		case 0:				/* Success */
@@ -214,9 +203,9 @@ void delete_from_swap_cache(struct page 
   
 	entry.val = page->private;
 
-	spin_lock_irq(&swapper_space.tree_lock);
+	write_lock_irq(&swapper_space.tree_lock);
 	__delete_from_swap_cache(page);
-	spin_unlock_irq(&swapper_space.tree_lock);
+	write_unlock_irq(&swapper_space.tree_lock);
 
 	swap_free(entry);
 	page_cache_release(page);
@@ -315,13 +304,11 @@ struct page * lookup_swap_cache(swp_entr
 {
 	struct page *page;
 
-	spin_lock_irq(&swapper_space.tree_lock);
-	page = radix_tree_lookup(&swapper_space.page_tree, entry.val);
-	if (page) {
-		page_cache_get(page);
+	page = find_get_page(&swapper_space, entry.val);
+
+	if (page)
 		INC_CACHE_INFO(find_success);
-	}
-	spin_unlock_irq(&swapper_space.tree_lock);
+
 	INC_CACHE_INFO(find_total);
 	return page;
 }
@@ -344,12 +331,7 @@ struct page *read_swap_cache_async(swp_e
 		 * called after lookup_swap_cache() failed, re-calling
 		 * that would confuse statistics.
 		 */
-		spin_lock_irq(&swapper_space.tree_lock);
-		found_page = radix_tree_lookup(&swapper_space.page_tree,
-						entry.val);
-		if (found_page)
-			page_cache_get(found_page);
-		spin_unlock_irq(&swapper_space.tree_lock);
+		found_page = find_get_page(&swapper_space, entry.val);
 		if (found_page)
 			break;
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/rmap.h>
 #include <linux/security.h>
-#include <linux/acct.h>
 #include <linux/backing-dev.h>
 #include <linux/syscalls.h>
 
@@ -80,7 +79,7 @@ void swap_unplug_io_fn(struct backing_de
 		WARN_ON(page_count(page) <= 1);
 
 		bdi = bdev->bd_inode->i_mapping->backing_dev_info;
-		bdi->unplug_io_fn(bdi, page);
+		blk_run_backing_dev(bdi, page);
 	}
 	up_read(&swap_unplug_sem);
 }
@@ -292,10 +291,10 @@ static int exclusive_swap_page(struct pa
 		/* Is the only swap cache user the cache itself? */
 		if (p->swap_map[swp_offset(entry)] == 1) {
 			/* Recheck the page count with the swapcache lock held.. */
-			spin_lock_irq(&swapper_space.tree_lock);
+			write_lock_irq(&swapper_space.tree_lock);
 			if (page_count(page) == 2)
 				retval = 1;
-			spin_unlock_irq(&swapper_space.tree_lock);
+			write_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
@@ -363,13 +362,13 @@ int remove_exclusive_swap_page(struct pa
 	retval = 0;
 	if (p->swap_map[swp_offset(entry)] == 1) {
 		/* Recheck the page count with the swapcache lock held.. */
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		if ((page_count(page) == 2) && !PageWriteback(page)) {
 			__delete_from_swap_cache(page);
 			SetPageDirty(page);
 			retval = 1;
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 	}
 	swap_info_put(p);
 
@@ -392,14 +391,8 @@ void free_swap_and_cache(swp_entry_t ent
 
 	p = swap_info_get(entry);
 	if (p) {
-		if (swap_entry_free(p, swp_offset(entry)) == 1) {
-			spin_lock_irq(&swapper_space.tree_lock);
-			page = radix_tree_lookup(&swapper_space.page_tree,
-				entry.val);
-			if (page && TestSetPageLocked(page))
-				page = NULL;
-			spin_unlock_irq(&swapper_space.tree_lock);
-		}
+		if (swap_entry_free(p, swp_offset(entry)) == 1)
+			page = find_trylock_page(&swapper_space, entry.val);
 		swap_info_put(p);
 	}
 	if (page) {
@@ -419,170 +412,121 @@ void free_swap_and_cache(swp_entry_t ent
 }
 
 /*
- * The swap entry has been read in advance, and we return 1 to indicate
- * that the page has been used or is no longer needed.
- *
  * Always set the resulting pte to be nowrite (the same as COW pages
  * after one process has exited).  We don't know just how many PTEs will
  * share this swap entry, so be cautious and let do_wp_page work out
  * what to do if a write is requested later.
+ *
+ * vma->vm_mm->page_table_lock is held.
  */
-/* vma->vm_mm->page_table_lock is held */
-static void
-unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir,
-	swp_entry_t entry, struct page *page)
+static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
+		unsigned long addr, swp_entry_t entry, struct page *page)
 {
-	vma->vm_mm->rss++;
+	inc_mm_counter(vma->vm_mm, rss);
 	get_page(page);
-	set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
-	page_add_anon_rmap(page, vma, address);
+	set_pte_at(vma->vm_mm, addr, pte,
+		   pte_mkold(mk_pte(page, vma->vm_page_prot)));
+	page_add_anon_rmap(page, vma, addr);
 	swap_free(entry);
-	acct_update_integrals();
-	update_mem_hiwater();
+	/*
+	 * Move the page to the active list so it is not
+	 * immediately swapped out again after swapon.
+	 */
+	activate_page(page);
 }
 
-/* vma->vm_mm->page_table_lock is held */
-static unsigned long unuse_pmd(struct vm_area_struct *vma, pmd_t *dir,
-	unsigned long address, unsigned long end,
-	swp_entry_t entry, struct page *page)
+static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+				unsigned long addr, unsigned long end,
+				swp_entry_t entry, struct page *page)
 {
 	pte_t *pte;
 	pte_t swp_pte = swp_entry_to_pte(entry);
 
-	if (pmd_none(*dir))
-		return 0;
-	if (pmd_bad(*dir)) {
-		pmd_ERROR(*dir);
-		pmd_clear(dir);
-		return 0;
-	}
-	pte = pte_offset_map(dir, address);
+	pte = pte_offset_map(pmd, addr);
 	do {
 		/*
 		 * swapoff spends a _lot_ of time in this loop!
 		 * Test inline before going to call unuse_pte.
 		 */
 		if (unlikely(pte_same(*pte, swp_pte))) {
-			unuse_pte(vma, address, pte, entry, page);
+			unuse_pte(vma, pte, addr, entry, page);
 			pte_unmap(pte);
-
-			/*
-			 * Move the page to the active list so it is not
-			 * immediately swapped out again after swapon.
-			 */
-			activate_page(page);
-
-			/* add 1 since address may be 0 */
-			return 1 + address;
+			return 1;
 		}
-		address += PAGE_SIZE;
-		pte++;
-	} while (address < end);
+	} while (pte++, addr += PAGE_SIZE, addr != end);
 	pte_unmap(pte - 1);
 	return 0;
 }
 
-/* vma->vm_mm->page_table_lock is held */
-static unsigned long unuse_pud(struct vm_area_struct *vma, pud_t *pud,
-        unsigned long address, unsigned long end,
-	swp_entry_t entry, struct page *page)
+static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+				unsigned long addr, unsigned long end,
+				swp_entry_t entry, struct page *page)
 {
 	pmd_t *pmd;
 	unsigned long next;
-	unsigned long foundaddr;
 
-	if (pud_none(*pud))
-		return 0;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return 0;
-	}
-	pmd = pmd_offset(pud, address);
+	pmd = pmd_offset(pud, addr);
 	do {
-		next = (address + PMD_SIZE) & PMD_MASK;
-		if (next > end || !next)
-			next = end;
-		foundaddr = unuse_pmd(vma, pmd, address, next, entry, page);
-		if (foundaddr)
-			return foundaddr;
-		address = next;
-		pmd++;
-	} while (address < end);
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		if (unuse_pte_range(vma, pmd, addr, next, entry, page))
+			return 1;
+	} while (pmd++, addr = next, addr != end);
 	return 0;
 }
 
-/* vma->vm_mm->page_table_lock is held */
-static unsigned long unuse_pgd(struct vm_area_struct *vma, pgd_t *pgd,
-	unsigned long address, unsigned long end,
-	swp_entry_t entry, struct page *page)
+static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+				unsigned long addr, unsigned long end,
+				swp_entry_t entry, struct page *page)
 {
 	pud_t *pud;
 	unsigned long next;
-	unsigned long foundaddr;
 
-	if (pgd_none(*pgd))
-		return 0;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return 0;
-	}
-	pud = pud_offset(pgd, address);
+	pud = pud_offset(pgd, addr);
 	do {
-		next = (address + PUD_SIZE) & PUD_MASK;
-		if (next > end || !next)
-			next = end;
-		foundaddr = unuse_pud(vma, pud, address, next, entry, page);
-		if (foundaddr)
-			return foundaddr;
-		address = next;
-		pud++;
-	} while (address < end);
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		if (unuse_pmd_range(vma, pud, addr, next, entry, page))
+			return 1;
+	} while (pud++, addr = next, addr != end);
 	return 0;
 }
 
-/* vma->vm_mm->page_table_lock is held */
-static unsigned long unuse_vma(struct vm_area_struct *vma,
-	swp_entry_t entry, struct page *page)
+static int unuse_vma(struct vm_area_struct *vma,
+				swp_entry_t entry, struct page *page)
 {
 	pgd_t *pgd;
-	unsigned long address, next, end;
-	unsigned long foundaddr;
+	unsigned long addr, end, next;
 
 	if (page->mapping) {
-		address = page_address_in_vma(page, vma);
-		if (address == -EFAULT)
+		addr = page_address_in_vma(page, vma);
+		if (addr == -EFAULT)
 			return 0;
 		else
-			end = address + PAGE_SIZE;
+			end = addr + PAGE_SIZE;
 	} else {
-		address = vma->vm_start;
+		addr = vma->vm_start;
 		end = vma->vm_end;
 	}
-	pgd = pgd_offset(vma->vm_mm, address);
+
+	pgd = pgd_offset(vma->vm_mm, addr);
 	do {
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next > end || !next)
-			next = end;
-		foundaddr = unuse_pgd(vma, pgd, address, next, entry, page);
-		if (foundaddr)
-			return foundaddr;
-		address = next;
-		pgd++;
-	} while (address < end);
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		if (unuse_pud_range(vma, pgd, addr, next, entry, page))
+			return 1;
+	} while (pgd++, addr = next, addr != end);
 	return 0;
 }
 
-static int unuse_process(struct mm_struct * mm,
-			swp_entry_t entry, struct page* page)
+static int unuse_mm(struct mm_struct *mm,
+				swp_entry_t entry, struct page *page)
 {
-	struct vm_area_struct* vma;
-	unsigned long foundaddr = 0;
+	struct vm_area_struct *vma;
 
-	/*
-	 * Go through process' page directory.
-	 */
 	if (!down_read_trylock(&mm->mmap_sem)) {
 		/*
 		 * Our reference to the page stops try_to_unmap_one from
@@ -594,16 +538,13 @@ static int unuse_process(struct mm_struc
 	}
 	spin_lock(&mm->page_table_lock);
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		if (vma->anon_vma) {
-			foundaddr = unuse_vma(vma, entry, page);
-			if (foundaddr)
-				break;
-		}
+		if (vma->anon_vma && unuse_vma(vma, entry, page))
+			break;
 	}
 	spin_unlock(&mm->page_table_lock);
 	up_read(&mm->mmap_sem);
 	/*
-	 * Currently unuse_process cannot fail, but leave error handling
+	 * Currently unuse_mm cannot fail, but leave error handling
 	 * at call sites for now, since we change it from time to time.
 	 */
 	return 0;
@@ -747,7 +688,7 @@ static int try_to_unuse(unsigned int typ
 			if (start_mm == &init_mm)
 				shmem = shmem_unuse(entry, page);
 			else
-				retval = unuse_process(start_mm, entry, page);
+				retval = unuse_mm(start_mm, entry, page);
 		}
 		if (*swap_map > 1) {
 			int set_start_mm = (*swap_map >= swcount);
@@ -779,7 +720,7 @@ static int try_to_unuse(unsigned int typ
 					set_start_mm = 1;
 					shmem = shmem_unuse(entry, page);
 				} else
-					retval = unuse_process(mm, entry, page);
+					retval = unuse_mm(mm, entry, page);
 				if (set_start_mm && *swap_map < swcount) {
 					mmput(new_start_mm);
 					atomic_inc(&mm->mm_users);
diff --git a/mm/thrash.c b/mm/thrash.c
--- a/mm/thrash.c
+++ b/mm/thrash.c
@@ -15,7 +15,7 @@
 
 static DEFINE_SPINLOCK(swap_token_lock);
 static unsigned long swap_token_timeout;
-unsigned long swap_token_check;
+static unsigned long swap_token_check;
 struct mm_struct * swap_token_mm = &init_mm;
 
 #define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2)
diff --git a/mm/truncate.c b/mm/truncate.c
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -76,15 +76,15 @@ invalidate_complete_page(struct address_
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		return 0;
 	}
 
 	BUG_ON(PagePrivate(page));
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 	ClearPageUptodate(page);
 	page_cache_release(page);	/* pagecache ref */
 	return 1;
@@ -241,54 +241,68 @@ unsigned long invalidate_inode_pages(str
 EXPORT_SYMBOL(invalidate_inode_pages);
 
 /**
- * invalidate_inode_pages2 - remove all pages from an address_space
- * @mapping - the address_space
+ * invalidate_inode_pages2_range - remove range of pages from an address_space
+ * @mapping: the address_space
+ * @start: the page offset 'from' which to invalidate
+ * @end: the page offset 'to' which to invalidate (inclusive)
  *
  * Any pages which are found to be mapped into pagetables are unmapped prior to
  * invalidation.
  *
  * Returns -EIO if any pages could not be invalidated.
  */
-int invalidate_inode_pages2(struct address_space *mapping)
+int invalidate_inode_pages2_range(struct address_space *mapping,
+				  pgoff_t start, pgoff_t end)
 {
 	struct pagevec pvec;
-	pgoff_t next = 0;
+	pgoff_t next;
 	int i;
 	int ret = 0;
-	int did_full_unmap = 0;
+	int did_range_unmap = 0;
+	int wrapped = 0;
 
 	pagevec_init(&pvec, 0);
-	while (!ret && pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+	next = start;
+	while (next <= end && !ret && !wrapped &&
+		pagevec_lookup(&pvec, mapping, next,
+			min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
 		for (i = 0; !ret && i < pagevec_count(&pvec); i++) {
 			struct page *page = pvec.pages[i];
+			pgoff_t page_index;
 			int was_dirty;
 
 			lock_page(page);
-			if (page->mapping != mapping) {	/* truncate race? */
+			if (page->mapping != mapping) {
 				unlock_page(page);
 				continue;
 			}
+			page_index = page->index;
+			next = page_index + 1;
+			if (next == 0)
+				wrapped = 1;
+			if (page_index > end) {
+				unlock_page(page);
+				break;
+			}
 			wait_on_page_writeback(page);
-			next = page->index + 1;
 			while (page_mapped(page)) {
-				if (!did_full_unmap) {
+				if (!did_range_unmap) {
 					/*
 					 * Zap the rest of the file in one hit.
-					 * FIXME: invalidate_inode_pages2()
-					 * should take start/end offsets.
 					 */
 					unmap_mapping_range(mapping,
-						page->index << PAGE_CACHE_SHIFT,
-					  	-1, 0);
-					did_full_unmap = 1;
+					    page_index << PAGE_CACHE_SHIFT,
+					    (end - page_index + 1)
+							<< PAGE_CACHE_SHIFT,
+					    0);
+					did_range_unmap = 1;
 				} else {
 					/*
 					 * Just zap this page
 					 */
 					unmap_mapping_range(mapping,
-					  page->index << PAGE_CACHE_SHIFT,
-					  (page->index << PAGE_CACHE_SHIFT)+1,
-					  0);
+					  page_index << PAGE_CACHE_SHIFT,
+					  PAGE_CACHE_SIZE, 0);
 				}
 			}
 			was_dirty = test_clear_page_dirty(page);
@@ -304,4 +318,19 @@ int invalidate_inode_pages2(struct addre
 	}
 	return ret;
 }
+EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
+
+/**
+ * invalidate_inode_pages2 - remove all pages from an address_space
+ * @mapping: the address_space
+ *
+ * Any pages which are found to be mapped into pagetables are unmapped prior to
+ * invalidation.
+ *
+ * Returns -EIO if any pages could not be invalidated.
+ */
+int invalidate_inode_pages2(struct address_space *mapping)
+{
+	return invalidate_inode_pages2_range(mapping, 0, -1);
+}
 EXPORT_SYMBOL_GPL(invalidate_inode_pages2);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -23,210 +23,136 @@
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
-static void unmap_area_pte(pmd_t *pmd, unsigned long address,
-				  unsigned long size)
+static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
 {
-	unsigned long end;
 	pte_t *pte;
 
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-
-	pte = pte_offset_kernel(pmd, address);
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-
+	pte = pte_offset_kernel(pmd, addr);
 	do {
-		pte_t page;
-		page = ptep_get_and_clear(pte);
-		address += PAGE_SIZE;
-		pte++;
-		if (pte_none(page))
-			continue;
-		if (pte_present(page))
-			continue;
-		printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
-	} while (address < end);
+		pte_t ptent = ptep_get_and_clear(&init_mm, addr, pte);
+		WARN_ON(!pte_none(ptent) && !pte_present(ptent));
+	} while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
-static void unmap_area_pmd(pud_t *pud, unsigned long address,
-				  unsigned long size)
+static inline void vunmap_pmd_range(pud_t *pud, unsigned long addr,
+						unsigned long end)
 {
-	unsigned long end;
 	pmd_t *pmd;
+	unsigned long next;
 
-	if (pud_none(*pud))
-		return;
-	if (pud_bad(*pud)) {
-		pud_ERROR(*pud);
-		pud_clear(pud);
-		return;
-	}
-
-	pmd = pmd_offset(pud, address);
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
-
+	pmd = pmd_offset(pud, addr);
 	do {
-		unmap_area_pte(pmd, address, end - address);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
+		next = pmd_addr_end(addr, end);
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		vunmap_pte_range(pmd, addr, next);
+	} while (pmd++, addr = next, addr != end);
 }
 
-static void unmap_area_pud(pgd_t *pgd, unsigned long address,
-			   unsigned long size)
+static inline void vunmap_pud_range(pgd_t *pgd, unsigned long addr,
+						unsigned long end)
 {
 	pud_t *pud;
-	unsigned long end;
+	unsigned long next;
 
-	if (pgd_none(*pgd))
-		return;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return;
-	}
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		vunmap_pmd_range(pud, addr, next);
+	} while (pud++, addr = next, addr != end);
+}
 
-	pud = pud_offset(pgd, address);
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
+void unmap_vm_area(struct vm_struct *area)
+{
+	pgd_t *pgd;
+	unsigned long next;
+	unsigned long addr = (unsigned long) area->addr;
+	unsigned long end = addr + area->size;
 
+	BUG_ON(addr >= end);
+	pgd = pgd_offset_k(addr);
+	flush_cache_vunmap(addr, end);
 	do {
-		unmap_area_pmd(pud, address, end - address);
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && (address < end));
-}
-
-static int map_area_pte(pte_t *pte, unsigned long address,
-			       unsigned long size, pgprot_t prot,
-			       struct page ***pages)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		vunmap_pud_range(pgd, addr, next);
+	} while (pgd++, addr = next, addr != end);
+	flush_tlb_kernel_range((unsigned long) area->addr, end);
+}
 
+static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
+			unsigned long end, pgprot_t prot, struct page ***pages)
+{
+	pte_t *pte;
+
+	pte = pte_alloc_kernel(&init_mm, pmd, addr);
+	if (!pte)
+		return -ENOMEM;
 	do {
 		struct page *page = **pages;
 		WARN_ON(!pte_none(*pte));
 		if (!page)
 			return -ENOMEM;
-
-		set_pte(pte, mk_pte(page, prot));
-		address += PAGE_SIZE;
-		pte++;
+		set_pte_at(&init_mm, addr, pte, mk_pte(page, prot));
 		(*pages)++;
-	} while (address < end);
+	} while (pte++, addr += PAGE_SIZE, addr != end);
 	return 0;
 }
 
-static int map_area_pmd(pmd_t *pmd, unsigned long address,
-			       unsigned long size, pgprot_t prot,
-			       struct page ***pages)
-{
-	unsigned long base, end;
-
-	base = address & PUD_MASK;
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
+static inline int vmap_pmd_range(pud_t *pud, unsigned long addr,
+			unsigned long end, pgprot_t prot, struct page ***pages)
+{
+	pmd_t *pmd;
+	unsigned long next;
 
+	pmd = pmd_alloc(&init_mm, pud, addr);
+	if (!pmd)
+		return -ENOMEM;
 	do {
-		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, base + address);
-		if (!pte)
+		next = pmd_addr_end(addr, end);
+		if (vmap_pte_range(pmd, addr, next, prot, pages))
 			return -ENOMEM;
-		if (map_area_pte(pte, address, end - address, prot, pages))
-			return -ENOMEM;
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-
+	} while (pmd++, addr = next, addr != end);
 	return 0;
 }
 
-static int map_area_pud(pud_t *pud, unsigned long address,
-			       unsigned long end, pgprot_t prot,
-			       struct page ***pages)
+static inline int vmap_pud_range(pgd_t *pgd, unsigned long addr,
+			unsigned long end, pgprot_t prot, struct page ***pages)
 {
+	pud_t *pud;
+	unsigned long next;
+
+	pud = pud_alloc(&init_mm, pgd, addr);
+	if (!pud)
+		return -ENOMEM;
 	do {
-		pmd_t *pmd = pmd_alloc(&init_mm, pud, address);
-		if (!pmd)
-			return -ENOMEM;
-		if (map_area_pmd(pmd, address, end - address, prot, pages))
+		next = pud_addr_end(addr, end);
+		if (vmap_pmd_range(pud, addr, next, prot, pages))
 			return -ENOMEM;
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address && address < end);
-
+	} while (pud++, addr = next, addr != end);
 	return 0;
 }
 
-void unmap_vm_area(struct vm_struct *area)
-{
-	unsigned long address = (unsigned long) area->addr;
-	unsigned long end = (address + area->size);
-	unsigned long next;
-	pgd_t *pgd;
-	int i;
-
-	pgd = pgd_offset_k(address);
-	flush_cache_vunmap(address, end);
-	for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next <= address || next > end)
-			next = end;
-		unmap_area_pud(pgd, address, next - address);
-		address = next;
-	        pgd++;
-	}
-	flush_tlb_kernel_range((unsigned long) area->addr, end);
-}
-
 int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
 {
-	unsigned long address = (unsigned long) area->addr;
-	unsigned long end = address + (area->size-PAGE_SIZE);
-	unsigned long next;
 	pgd_t *pgd;
-	int err = 0;
-	int i;
+	unsigned long next;
+	unsigned long addr = (unsigned long) area->addr;
+	unsigned long end = addr + area->size - PAGE_SIZE;
+	int err;
 
-	pgd = pgd_offset_k(address);
+	BUG_ON(addr >= end);
+	pgd = pgd_offset_k(addr);
 	spin_lock(&init_mm.page_table_lock);
-	for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
-		pud_t *pud = pud_alloc(&init_mm, pgd, address);
-		if (!pud) {
-			err = -ENOMEM;
-			break;
-		}
-		next = (address + PGDIR_SIZE) & PGDIR_MASK;
-		if (next < address || next > end)
-			next = end;
-		if (map_area_pud(pud, address, next, prot, pages)) {
-			err = -ENOMEM;
+	do {
+		next = pgd_addr_end(addr, end);
+		err = vmap_pud_range(pgd, addr, next, prot, pages);
+		if (err)
 			break;
-		}
-
-		address = next;
-		pgd++;
-	}
-
+	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_cache_vmap((unsigned long) area->addr, end);
 	return err;
@@ -252,20 +178,22 @@ struct vm_struct *__get_vm_area(unsigned
 		align = 1ul << bit;
 	}
 	addr = ALIGN(start, align);
+	size = PAGE_ALIGN(size);
 
 	area = kmalloc(sizeof(*area), GFP_KERNEL);
 	if (unlikely(!area))
 		return NULL;
 
-	/*
-	 * We always allocate a guard page.
-	 */
-	size += PAGE_SIZE;
 	if (unlikely(!size)) {
 		kfree (area);
 		return NULL;
 	}
 
+	/*
+	 * We always allocate a guard page.
+	 */
+	size += PAGE_SIZE;
+
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) {
 		if ((unsigned long)tmp->addr < addr) {
@@ -320,34 +248,46 @@ struct vm_struct *get_vm_area(unsigned l
 	return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
 }
 
-/**
- *	remove_vm_area  -  find and remove a contingous kernel virtual area
- *
- *	@addr:		base address
- *
- *	Search for the kernel VM area starting at @addr, and remove it.
- *	This function returns the found VM area, but using it is NOT safe
- *	on SMP machines.
- */
-struct vm_struct *remove_vm_area(void *addr)
+/* Caller must hold vmlist_lock */
+struct vm_struct *__remove_vm_area(void *addr)
 {
 	struct vm_struct **p, *tmp;
 
-	write_lock(&vmlist_lock);
 	for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) {
 		 if (tmp->addr == addr)
 			 goto found;
 	}
-	write_unlock(&vmlist_lock);
 	return NULL;
 
 found:
 	unmap_vm_area(tmp);
 	*p = tmp->next;
-	write_unlock(&vmlist_lock);
+
+	/*
+	 * Remove the guard page.
+	 */
+	tmp->size -= PAGE_SIZE;
 	return tmp;
 }
 
+/**
+ *	remove_vm_area  -  find and remove a contingous kernel virtual area
+ *
+ *	@addr:		base address
+ *
+ *	Search for the kernel VM area starting at @addr, and remove it.
+ *	This function returns the found VM area, but using it is NOT safe
+ *	on SMP machines, except for its size or flags.
+ */
+struct vm_struct *remove_vm_area(void *addr)
+{
+	struct vm_struct *v;
+	write_lock(&vmlist_lock);
+	v = __remove_vm_area(addr);
+	write_unlock(&vmlist_lock);
+	return v;
+}
+
 void __vunmap(void *addr, int deallocate_pages)
 {
 	struct vm_struct *area;
@@ -368,7 +308,7 @@ void __vunmap(void *addr, int deallocate
 		WARN_ON(1);
 		return;
 	}
-	
+
 	if (deallocate_pages) {
 		int i;
 
@@ -456,32 +396,12 @@ void *vmap(struct page **pages, unsigned
 
 EXPORT_SYMBOL(vmap);
 
-/**
- *	__vmalloc  -  allocate virtually contiguous memory
- *
- *	@size:		allocation size
- *	@gfp_mask:	flags for the page level allocator
- *	@prot:		protection mask for the allocated pages
- *
- *	Allocate enough pages to cover @size from the page level
- *	allocator with @gfp_mask flags.  Map them into contiguous
- *	kernel virtual space, using a pagetable protection of @prot.
- */
-void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot)
+void *__vmalloc_area(struct vm_struct *area, unsigned int __nocast gfp_mask, pgprot_t prot)
 {
-	struct vm_struct *area;
 	struct page **pages;
 	unsigned int nr_pages, array_size, i;
 
-	size = PAGE_ALIGN(size);
-	if (!size || (size >> PAGE_SHIFT) > num_physpages)
-		return NULL;
-
-	area = get_vm_area(size, VM_ALLOC);
-	if (!area)
-		return NULL;
-
-	nr_pages = size >> PAGE_SHIFT;
+	nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
 	array_size = (nr_pages * sizeof(struct page *));
 
 	area->nr_pages = nr_pages;
@@ -506,7 +426,7 @@ void *__vmalloc(unsigned long size, int 
 			goto fail;
 		}
 	}
-	
+
 	if (map_vm_area(area, prot, &pages))
 		goto fail;
 	return area->addr;
@@ -516,6 +436,32 @@ fail:
 	return NULL;
 }
 
+/**
+ *	__vmalloc  -  allocate virtually contiguous memory
+ *
+ *	@size:		allocation size
+ *	@gfp_mask:	flags for the page level allocator
+ *	@prot:		protection mask for the allocated pages
+ *
+ *	Allocate enough pages to cover @size from the page level
+ *	allocator with @gfp_mask flags.  Map them into contiguous
+ *	kernel virtual space, using a pagetable protection of @prot.
+ */
+void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask, pgprot_t prot)
+{
+	struct vm_struct *area;
+
+	size = PAGE_ALIGN(size);
+	if (!size || (size >> PAGE_SHIFT) > num_physpages)
+		return NULL;
+
+	area = get_vm_area(size, VM_ALLOC);
+	if (!area)
+		return NULL;
+
+	return __vmalloc_area(area, gfp_mask, prot);
+}
+
 EXPORT_SYMBOL(__vmalloc);
 
 /**
@@ -536,6 +482,10 @@ void *vmalloc(unsigned long size)
 
 EXPORT_SYMBOL(vmalloc);
 
+#ifndef PAGE_KERNEL_EXEC
+# define PAGE_KERNEL_EXEC PAGE_KERNEL
+#endif
+
 /**
  *	vmalloc_exec  -  allocate virtually contiguous, executable memory
  *
@@ -549,10 +499,6 @@ EXPORT_SYMBOL(vmalloc);
  *	use __vmalloc() instead.
  */
 
-#ifndef PAGE_KERNEL_EXEC
-# define PAGE_KERNEL_EXEC PAGE_KERNEL
-#endif
-
 void *vmalloc_exec(unsigned long size)
 {
 	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
diff --git a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -30,6 +30,7 @@
 #include <linux/rmap.h>
 #include <linux/topology.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
 
@@ -72,6 +73,12 @@ struct scan_control {
 	unsigned int gfp_mask;
 
 	int may_writepage;
+
+	/* This context's SWAP_CLUSTER_MAX. If freeing memory for
+	 * suspend, we effectively ignore SWAP_CLUSTER_MAX.
+	 * In this context, it doesn't matter that we scan the
+	 * whole list at once. */
+	int swap_cluster_max;
 };
 
 /*
@@ -137,7 +144,7 @@ struct shrinker *set_shrinker(int seeks,
 	        shrinker->seeks = seeks;
 	        shrinker->nr = 0;
 	        down_write(&shrinker_rwsem);
-	        list_add(&shrinker->list, &shrinker_list);
+	        list_add_tail(&shrinker->list, &shrinker_list);
 	        up_write(&shrinker_rwsem);
 	}
 	return shrinker;
@@ -306,8 +313,20 @@ static pageout_t pageout(struct page *pa
 	 */
 	if (!is_page_cache_freeable(page))
 		return PAGE_KEEP;
-	if (!mapping)
+	if (!mapping) {
+		/*
+		 * Some data journaling orphaned pages can have
+		 * page->mapping == NULL while being dirty with clean buffers.
+		 */
+		if (PagePrivate(page)) {
+			if (try_to_free_buffers(page)) {
+				ClearPageDirty(page);
+				printk("%s: orphaned page\n", __FUNCTION__);
+				return PAGE_CLEAN;
+			}
+		}
 		return PAGE_KEEP;
+	}
 	if (mapping->a_ops->writepage == NULL)
 		return PAGE_ACTIVATE;
 	if (!may_write_to_queue(mapping->backing_dev_info))
@@ -475,7 +494,7 @@ static int shrink_list(struct list_head 
 		if (!mapping)
 			goto keep_locked;	/* truncate got there first */
 
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 
 		/*
 		 * The non-racy check for busy page.  It is critical to check
@@ -483,7 +502,7 @@ static int shrink_list(struct list_head 
 		 * not in use by anybody. 	(pagecache + us == 2)
 		 */
 		if (page_count(page) != 2 || PageDirty(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			goto keep_locked;
 		}
 
@@ -491,7 +510,7 @@ static int shrink_list(struct list_head 
 		if (PageSwapCache(page)) {
 			swp_entry_t swap = { .val = page->private };
 			__delete_from_swap_cache(page);
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			swap_free(swap);
 			__put_page(page);	/* The pagecache ref */
 			goto free_it;
@@ -499,7 +518,7 @@ static int shrink_list(struct list_head 
 #endif /* CONFIG_SWAP */
 
 		__remove_from_page_cache(page);
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		__put_page(page);
 
 free_it:
@@ -527,14 +546,56 @@ keep:
 }
 
 /*
- * zone->lru_lock is heavily contented.  We relieve it by quickly privatising
- * a batch of pages and working on them outside the lock.  Any pages which were
- * not freed will be added back to the LRU.
+ * zone->lru_lock is heavily contended.  Some of the functions that
+ * shrink the lists perform better by taking out a batch of pages
+ * and working on them outside the LRU lock.
  *
- * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
+ * For pagecache intensive workloads, this function is the hottest
+ * spot in the kernel (apart from copy_*_user functions).
  *
- * For pagecache intensive workloads, the first loop here is the hottest spot
- * in the kernel (apart from the copy_*_user functions).
+ * Appropriate locks must be held before calling this function.
+ *
+ * @nr_to_scan:	The number of pages to look through on the list.
+ * @src:	The LRU list to pull pages off.
+ * @dst:	The temp list to put pages on to.
+ * @scanned:	The number of pages that were scanned.
+ *
+ * returns how many pages were moved onto *@dst.
+ */
+static int isolate_lru_pages(int nr_to_scan, struct list_head *src,
+			     struct list_head *dst, int *scanned)
+{
+	int nr_taken = 0;
+	struct page *page;
+	int scan = 0;
+
+	while (scan++ < nr_to_scan && !list_empty(src)) {
+		page = lru_to_page(src);
+		prefetchw_prev_lru_page(page, src, flags);
+
+		if (!TestClearPageLRU(page))
+			BUG();
+		list_del(&page->lru);
+		if (get_page_testone(page)) {
+			/*
+			 * It is being freed elsewhere
+			 */
+			__put_page(page);
+			SetPageLRU(page);
+			list_add(&page->lru, src);
+			continue;
+		} else {
+			list_add(&page->lru, dst);
+			nr_taken++;
+		}
+	}
+
+	*scanned = scan;
+	return nr_taken;
+}
+
+/*
+ * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
  */
 static void shrink_cache(struct zone *zone, struct scan_control *sc)
 {
@@ -548,32 +609,13 @@ static void shrink_cache(struct zone *zo
 	spin_lock_irq(&zone->lru_lock);
 	while (max_scan > 0) {
 		struct page *page;
-		int nr_taken = 0;
-		int nr_scan = 0;
+		int nr_taken;
+		int nr_scan;
 		int nr_freed;
 
-		while (nr_scan++ < SWAP_CLUSTER_MAX &&
-				!list_empty(&zone->inactive_list)) {
-			page = lru_to_page(&zone->inactive_list);
-
-			prefetchw_prev_lru_page(page,
-						&zone->inactive_list, flags);
-
-			if (!TestClearPageLRU(page))
-				BUG();
-			list_del(&page->lru);
-			if (get_page_testone(page)) {
-				/*
-				 * It is being freed elsewhere
-				 */
-				__put_page(page);
-				SetPageLRU(page);
-				list_add(&page->lru, &zone->inactive_list);
-				continue;
-			}
-			list_add(&page->lru, &page_list);
-			nr_taken++;
-		}
+		nr_taken = isolate_lru_pages(sc->swap_cluster_max,
+					     &zone->inactive_list,
+					     &page_list, &nr_scan);
 		zone->nr_inactive -= nr_taken;
 		zone->pages_scanned += nr_scan;
 		spin_unlock_irq(&zone->lru_lock);
@@ -639,7 +681,7 @@ refill_inactive_zone(struct zone *zone, 
 {
 	int pgmoved;
 	int pgdeactivate = 0;
-	int pgscanned = 0;
+	int pgscanned;
 	int nr_pages = sc->nr_to_scan;
 	LIST_HEAD(l_hold);	/* The pages which were snipped off */
 	LIST_HEAD(l_inactive);	/* Pages to go onto the inactive_list */
@@ -652,30 +694,9 @@ refill_inactive_zone(struct zone *zone, 
 	long swap_tendency;
 
 	lru_add_drain();
-	pgmoved = 0;
 	spin_lock_irq(&zone->lru_lock);
-	while (pgscanned < nr_pages && !list_empty(&zone->active_list)) {
-		page = lru_to_page(&zone->active_list);
-		prefetchw_prev_lru_page(page, &zone->active_list, flags);
-		if (!TestClearPageLRU(page))
-			BUG();
-		list_del(&page->lru);
-		if (get_page_testone(page)) {
-			/*
-			 * It was already free!  release_pages() or put_page()
-			 * are about to remove it from the LRU and free it. So
-			 * put the refcount back and put the page back on the
-			 * LRU
-			 */
-			__put_page(page);
-			SetPageLRU(page);
-			list_add(&page->lru, &zone->active_list);
-		} else {
-			list_add(&page->lru, &l_hold);
-			pgmoved++;
-		}
-		pgscanned++;
-	}
+	pgmoved = isolate_lru_pages(nr_pages, &zone->active_list,
+				    &l_hold, &pgscanned);
 	zone->pages_scanned += pgscanned;
 	zone->nr_active -= pgmoved;
 	spin_unlock_irq(&zone->lru_lock);
@@ -797,37 +818,39 @@ shrink_zone(struct zone *zone, struct sc
 	 */
 	zone->nr_scan_active += (zone->nr_active >> sc->priority) + 1;
 	nr_active = zone->nr_scan_active;
-	if (nr_active >= SWAP_CLUSTER_MAX)
+	if (nr_active >= sc->swap_cluster_max)
 		zone->nr_scan_active = 0;
 	else
 		nr_active = 0;
 
 	zone->nr_scan_inactive += (zone->nr_inactive >> sc->priority) + 1;
 	nr_inactive = zone->nr_scan_inactive;
-	if (nr_inactive >= SWAP_CLUSTER_MAX)
+	if (nr_inactive >= sc->swap_cluster_max)
 		zone->nr_scan_inactive = 0;
 	else
 		nr_inactive = 0;
 
-	sc->nr_to_reclaim = SWAP_CLUSTER_MAX;
+	sc->nr_to_reclaim = sc->swap_cluster_max;
 
 	while (nr_active || nr_inactive) {
 		if (nr_active) {
 			sc->nr_to_scan = min(nr_active,
-					(unsigned long)SWAP_CLUSTER_MAX);
+					(unsigned long)sc->swap_cluster_max);
 			nr_active -= sc->nr_to_scan;
 			refill_inactive_zone(zone, sc);
 		}
 
 		if (nr_inactive) {
 			sc->nr_to_scan = min(nr_inactive,
-					(unsigned long)SWAP_CLUSTER_MAX);
+					(unsigned long)sc->swap_cluster_max);
 			nr_inactive -= sc->nr_to_scan;
 			shrink_cache(zone, sc);
 			if (sc->nr_to_reclaim <= 0)
 				break;
 		}
 	}
+
+	throttle_vm_writeout();
 }
 
 /*
@@ -857,6 +880,9 @@ shrink_caches(struct zone **zones, struc
 		if (zone->present_pages == 0)
 			continue;
 
+		if (!cpuset_zone_allowed(zone))
+			continue;
+
 		zone->temp_priority = sc->priority;
 		if (zone->prev_priority > sc->priority)
 			zone->prev_priority = sc->priority;
@@ -900,6 +926,9 @@ int try_to_free_pages(struct zone **zone
 	for (i = 0; zones[i] != NULL; i++) {
 		struct zone *zone = zones[i];
 
+		if (!cpuset_zone_allowed(zone))
+			continue;
+
 		zone->temp_priority = DEF_PRIORITY;
 		lru_pages += zone->nr_active + zone->nr_inactive;
 	}
@@ -909,18 +938,19 @@ int try_to_free_pages(struct zone **zone
 		sc.nr_scanned = 0;
 		sc.nr_reclaimed = 0;
 		sc.priority = priority;
+		sc.swap_cluster_max = SWAP_CLUSTER_MAX;
 		shrink_caches(zones, &sc);
 		shrink_slab(sc.nr_scanned, gfp_mask, lru_pages);
 		if (reclaim_state) {
 			sc.nr_reclaimed += reclaim_state->reclaimed_slab;
 			reclaim_state->reclaimed_slab = 0;
 		}
-		if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX) {
+		total_scanned += sc.nr_scanned;
+		total_reclaimed += sc.nr_reclaimed;
+		if (total_reclaimed >= sc.swap_cluster_max) {
 			ret = 1;
 			goto out;
 		}
-		total_scanned += sc.nr_scanned;
-		total_reclaimed += sc.nr_reclaimed;
 
 		/*
 		 * Try to write back as many pages as we just scanned.  This
@@ -929,7 +959,7 @@ int try_to_free_pages(struct zone **zone
 		 * that's undesirable in laptop mode, where we *want* lumpy
 		 * writeout.  So in laptop mode, write out the whole world.
 		 */
-		if (total_scanned > SWAP_CLUSTER_MAX + SWAP_CLUSTER_MAX/2) {
+		if (total_scanned > sc.swap_cluster_max + sc.swap_cluster_max/2) {
 			wakeup_bdflush(laptop_mode ? 0 : total_scanned);
 			sc.may_writepage = 1;
 		}
@@ -939,8 +969,14 @@ int try_to_free_pages(struct zone **zone
 			blk_congestion_wait(WRITE, HZ/10);
 	}
 out:
-	for (i = 0; zones[i] != 0; i++)
-		zones[i]->prev_priority = zones[i]->temp_priority;
+	for (i = 0; zones[i] != 0; i++) {
+		struct zone *zone = zones[i];
+
+		if (!cpuset_zone_allowed(zone))
+			continue;
+
+		zone->prev_priority = zone->temp_priority;
+	}
 	return ret;
 }
 
@@ -1061,6 +1097,7 @@ scan:
 			sc.nr_scanned = 0;
 			sc.nr_reclaimed = 0;
 			sc.priority = priority;
+			sc.swap_cluster_max = nr_pages? nr_pages : SWAP_CLUSTER_MAX;
 			shrink_zone(zone, &sc);
 			reclaim_state->reclaimed_slab = 0;
 			shrink_slab(sc.nr_scanned, GFP_KERNEL, lru_pages);
@@ -1098,7 +1135,7 @@ scan:
 		 * matches the direct reclaim path behaviour in terms of impact
 		 * on zone->*_priority.
 		 */
-		if (total_reclaimed >= SWAP_CLUSTER_MAX)
+		if ((total_reclaimed >= SWAP_CLUSTER_MAX) && (!nr_pages))
 			break;
 	}
 out:
@@ -1200,6 +1237,8 @@ void wakeup_kswapd(struct zone *zone, in
 		return;
 	if (pgdat->kswapd_max_order < order)
 		pgdat->kswapd_max_order = order;
+	if (!cpuset_zone_allowed(zone))
+		return;
 	if (!waitqueue_active(&zone->zone_pgdat->kswapd_wait))
 		return;
 	wake_up_interruptible(&zone->zone_pgdat->kswapd_wait);
diff --git a/net/802/fc.c b/net/802/fc.c
--- a/net/802/fc.c
+++ b/net/802/fc.c
@@ -97,40 +97,6 @@ static int fc_rebuild_header(struct sk_b
 #endif
 }
 
-unsigned short
-fc_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-	struct fch_hdr *fch = (struct fch_hdr *)skb->data;
-	struct fcllc *fcllc;
-
-	skb->mac.raw = skb->data;
-	fcllc = (struct fcllc *)(skb->data + sizeof (struct fch_hdr) + 2);
-	skb_pull(skb, sizeof (struct fch_hdr) + 2);
-
-	if (*fch->daddr & 1) {
-		if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN))
-			skb->pkt_type = PACKET_BROADCAST;
-		else
-			skb->pkt_type = PACKET_MULTICAST;
-	} else if (dev->flags & IFF_PROMISC) {
-		if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN))
-			skb->pkt_type = PACKET_OTHERHOST;
-	}
-
-	/*
-	 * Strip the SNAP header from ARP packets since we don't pass
-	 * them through to the 802.2/SNAP layers.
-	 */
-	if (fcllc->dsap == EXTENDED_SAP &&
-	    (fcllc->ethertype == ntohs(ETH_P_IP) ||
-	     fcllc->ethertype == ntohs(ETH_P_ARP))) {
-		skb_pull(skb, sizeof (struct fcllc));
-		return fcllc->ethertype;
-	}
-
-	return ntohs(ETH_P_802_2);
-}
-
 static void fc_setup(struct net_device *dev)
 {
 	dev->hard_header	= fc_header;
diff --git a/net/802/fddi.c b/net/802/fddi.c
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -10,7 +10,7 @@
  * Authors:	Lawrence V. Stefani, <stefani@lkg.dec.com>
  *
  *		fddi.c is based on previous eth.c and tr.c work by
- *			Ross Biro, <bir7@leland.Stanford.Edu>
+ *			Ross Biro
  *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *			Mark Evans, <evansmp@uhura.aston.ac.uk>
  *			Florian La Roche, <rzsfl@rz.uni-sb.de>
diff --git a/net/802/hippi.c b/net/802/hippi.c
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)hippi.c	1.0.0	05/29/97
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Florian  La Roche, <rzsfl@rz.uni-sb.de>
diff --git a/net/802/tr.c b/net/802/tr.c
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -47,12 +47,12 @@ static void rif_check_expire(unsigned lo
  *	Each RIF entry we learn is kept this way
  */
  
-struct rif_cache_s {	
+struct rif_cache {
 	unsigned char addr[TR_ALEN];
 	int iface;
-	__u16 rcf;
-	__u16 rseg[8];
-	struct rif_cache_s *next;
+	__be16 rcf;
+	__be16 rseg[8];
+	struct rif_cache *next;
 	unsigned long last_used;
 	unsigned char local_ring;
 };
@@ -64,7 +64,7 @@ struct rif_cache_s {	
  *	up a lot.
  */
  
-static struct rif_cache_s *rif_table[RIF_TABLE_SIZE];
+static struct rif_cache *rif_table[RIF_TABLE_SIZE];
 
 static DEFINE_SPINLOCK(rif_lock);
 
@@ -249,7 +249,7 @@ void tr_source_route(struct sk_buff *skb
 {
 	int slack;
 	unsigned int hash;
-	struct rif_cache_s *entry;
+	struct rif_cache *entry;
 	unsigned char *olddata;
 	static const unsigned char mcast_func_addr[] 
 		= {0xC0,0x00,0x00,0x04,0x00,0x00};
@@ -337,7 +337,7 @@ printk("source routing for %02X:%02X:%02
 static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev)
 {
 	unsigned int hash, rii_p = 0;
-	struct rif_cache_s *entry;
+	struct rif_cache *entry;
 
 
 	spin_lock_bh(&rif_lock);
@@ -373,7 +373,7 @@ printk("adding rif_entry: addr:%02X:%02X
 		 *	FIXME: We ought to keep some kind of cache size
 		 *	limiting and adjust the timers to suit.
 		 */
-		entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC);
+		entry=kmalloc(sizeof(struct rif_cache),GFP_ATOMIC);
 
 		if(!entry) 
 		{
@@ -435,7 +435,7 @@ static void rif_check_expire(unsigned lo
 	spin_lock_bh(&rif_lock);
 	
 	for(i =0; i < RIF_TABLE_SIZE; i++) {
-		struct rif_cache_s *entry, **pentry;
+		struct rif_cache *entry, **pentry;
 		
 		pentry = rif_table+i;
 		while((entry=*pentry) != NULL) {
@@ -467,10 +467,10 @@ static void rif_check_expire(unsigned lo
  
 #ifdef CONFIG_PROC_FS
 
-static struct rif_cache_s *rif_get_idx(loff_t pos)
+static struct rif_cache *rif_get_idx(loff_t pos)
 {
 	int i;
-	struct rif_cache_s *entry;
+	struct rif_cache *entry;
 	loff_t off = 0;
 
 	for(i = 0; i < RIF_TABLE_SIZE; i++) 
@@ -493,7 +493,7 @@ static void *rif_seq_start(struct seq_fi
 static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	int i;
-	struct rif_cache_s *ent = v;
+	struct rif_cache *ent = v;
 
 	++*pos;
 
@@ -522,7 +522,7 @@ static void rif_seq_stop(struct seq_file
 static int rif_seq_show(struct seq_file *seq, void *v)
 {
 	int j, rcf_len, segment, brdgnmb;
-	struct rif_cache_s *entry = v;
+	struct rif_cache *entry = v;
 
 	if (v == SEQ_START_TOKEN)
 		seq_puts(seq,
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -23,7 +23,7 @@
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
 #include <linux/slab.h>		/* kmalloc(), kfree() */
-#include <linux/mm.h>		/* verify_area(), etc. */
+#include <linux/mm.h>
 #include <linux/string.h>	/* inline mem*, str* functions */
 #include <linux/init.h>		/* __initfunc et al. */
 #include <asm/byteorder.h>	/* htons(), etc. */
diff --git a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -45,15 +45,6 @@ config PACKET_MMAP
 
 	  If unsure, say N.
 
-config NETLINK_DEV
-	tristate "Netlink device emulation"
-	help
-	  This option will be removed soon. Any programs that want to use
-	  character special nodes like /dev/tap0 or /dev/route (all with major
-	  number 36) need this option, and need to be rewritten soon to use
-	  the real netlink socket.
-	  This is a backward compatibility option, choose Y for now.
-
 config UNIX
 	tristate "Unix domain sockets"
 	---help---
@@ -107,28 +98,24 @@ source "net/ipv4/Kconfig"
 
 #   IPv6 as module will cause a CRASH if you try to unload it
 config IPV6
-	tristate "The IPv6 protocol (EXPERIMENTAL)"
-	depends on INET && EXPERIMENTAL
+	tristate "The IPv6 protocol"
+	depends on INET
+	default m
 	select CRYPTO if IPV6_PRIVACY
 	select CRYPTO_MD5 if IPV6_PRIVACY
 	---help---
-	  This is experimental support for the IP version 6 (formerly called
-	  IPng "IP next generation").  You will still be able to do
-	  regular IPv4 networking as well.
-
-	  Features of this new protocol include: expanded address space,
-	  authentication and privacy, and seamless interoperability with the
-	  current version of IP (IP version 4). For general information about
-	  IPv6, see <http://playground.sun.com/pub/ipng/html/ipng-main.html>;
-	  for specific information about IPv6 under Linux read the HOWTO at
-	  <http://www.bieringer.de/linux/IPv6/> and the file net/ipv6/README
-	  in the kernel source.
+	  This is complemental support for the IP version 6.
+	  You will still be able to do traditional IPv4 networking as well.
+
+	  For general information about IPv6, see
+	  <http://playground.sun.com/pub/ipng/html/ipng-main.html>.
+	  For Linux IPv6 development information, see <http://www.linux-ipv6.org>.
+	  For specific information about IPv6 under Linux, read the HOWTO at
+	  <http://www.bieringer.de/linux/IPv6/>.
 
 	  To compile this protocol support as a module, choose M here: the 
 	  module will be called ipv6.
 
-	  It is safe to say N here for now.
-
 source "net/ipv6/Kconfig"
 
 menuconfig NETFILTER
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -573,6 +573,7 @@ static int atrtr_create(struct rtentry *
 
 	/* Fill in the routing entry */
 	rt->target  = ta->sat_addr;
+	dev_hold(devhint);
 	rt->dev     = devhint;
 	rt->flags   = r->rt_flags;
 	rt->gateway = ga->sat_addr;
@@ -1015,6 +1016,12 @@ static unsigned short atalk_checksum(con
 	return sum ? htons((unsigned short)sum) : 0xFFFF;
 }
 
+static struct proto ddp_proto = {
+	.name	  = "DDP",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct atalk_sock),
+};
+
 /*
  * Create a socket. Initialise the socket, blank the addresses
  * set the state.
@@ -1022,7 +1029,6 @@ static unsigned short atalk_checksum(con
 static int atalk_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct atalk_sock *at;
 	int rc = -ESOCKTNOSUPPORT;
 
 	/*
@@ -1032,25 +1038,17 @@ static int atalk_create(struct socket *s
 	if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
 		goto out;
 	rc = -ENOMEM;
-	sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1);
 	if (!sk)
 		goto out;
-	at = sk->sk_protinfo = kmalloc(sizeof(*at), GFP_KERNEL);
-	if (!at)
-		goto outsk;
-	memset(at, 0, sizeof(*at));
 	rc = 0;
 	sock->ops = &atalk_dgram_ops;
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	/* Checksums on by default */
-	sk->sk_zapped = 1;
+	sock_set_flag(sk, SOCK_ZAPPED);
 out:
 	return rc;
-outsk:
-	sk_free(sk);
-	goto out;
 }
 
 /* Free a socket. No work needed */
@@ -1127,7 +1125,7 @@ static int atalk_autobind(struct sock *s
 
 	n = atalk_pick_and_bind_port(sk, &sat);
 	if (!n)
-		sk->sk_zapped = 0;
+		sock_reset_flag(sk, SOCK_ZAPPED);
 out:
 	return n;
 }
@@ -1139,7 +1137,8 @@ static int atalk_bind(struct socket *soc
 	struct sock *sk = sock->sk;
 	struct atalk_sock *at = at_sk(sk);
 
-	if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_at))
+	if (!sock_flag(sk, SOCK_ZAPPED) ||
+	    addr_len != sizeof(struct sockaddr_at))
 		return -EINVAL;
 
 	if (addr->sat_family != AF_APPLETALK)
@@ -1174,7 +1173,7 @@ static int atalk_bind(struct socket *soc
 			return -EADDRINUSE;
 	}
 
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	return 0;
 }
 
@@ -1209,7 +1208,7 @@ static int atalk_connect(struct socket *
 #endif			
 	}
 
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		if (atalk_autobind(sk) < 0)
 			return -EBUSY;
 
@@ -1236,7 +1235,7 @@ static int atalk_getname(struct socket *
 	struct sock *sk = sock->sk;
 	struct atalk_sock *at = at_sk(sk);
 
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		if (atalk_autobind(sk) < 0)
 			return -ENOBUFS;
 
@@ -1558,7 +1557,7 @@ static int atalk_sendmsg(struct kiocb *i
 		return -EMSGSIZE;
 
 	if (usat) {
-		if (sk->sk_zapped)
+		if (sock_flag(sk, SOCK_ZAPPED))
 			if (atalk_autobind(sk) < 0)
 				return -EBUSY;
 
@@ -1880,6 +1879,11 @@ static char atalk_err_snap[] __initdata 
 /* Called by proto.c on kernel start up */
 static int __init atalk_init(void)
 {
+	int rc = proto_register(&ddp_proto, 0);
+
+	if (rc != 0)
+		goto out;
+
 	(void)sock_register(&atalk_family_ops);
 	ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
 	if (!ddp_dl)
@@ -1892,7 +1896,8 @@ static int __init atalk_init(void)
 	aarp_proto_init();
 	atalk_proc_init();
 	atalk_register_sysctl();
-	return 0;
+out:
+	return rc;
 }
 module_init(atalk_init);
 
@@ -1917,6 +1922,7 @@ static void __exit atalk_exit(void)
 	dev_remove_pack(&ppptalk_packet_type);
 	unregister_snap_client(ddp_dl);
 	sock_unregister(PF_APPLETALK);
+	proto_unregister(&ddp_proto);
 }
 module_exit(atalk_exit);
 
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c
--- a/net/appletalk/dev.c
+++ b/net/appletalk/dev.c
@@ -19,7 +19,7 @@ static int ltalk_mac_addr(struct net_dev
 	return -EINVAL;
 }
 
-void ltalk_setup(struct net_device *dev)
+static void ltalk_setup(struct net_device *dev)
 {
 	/* Fill in the fields of the device structure with localtalk-generic values. */
 	
@@ -40,4 +40,22 @@ void ltalk_setup(struct net_device *dev)
 
 	dev->flags		= IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
 }
-EXPORT_SYMBOL(ltalk_setup);
+
+/**
+ * alloc_ltalkdev - Allocates and sets up an localtalk device
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ *	for this localtalk device
+ *
+ * Fill in the fields of the device structure with localtalk-generic
+ * values. Basically does everything except registering the device.
+ *
+ * Constructs a new net device, complete with a private data area of
+ * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
+ * this private data area.
+ */
+
+struct net_device *alloc_ltalkdev(int sizeof_priv)
+{
+	return alloc_netdev(sizeof_priv, "lt%d", ltalk_setup);
+}
+EXPORT_SYMBOL(alloc_ltalkdev);
diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c
+++ b/net/atm/atm_misc.c
@@ -16,7 +16,7 @@
 int atm_charge(struct atm_vcc *vcc,int truesize)
 {
 	atm_force_charge(vcc,truesize);
-	if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf)
+	if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf)
 		return 1;
 	atm_return(vcc,truesize);
 	atomic_inc(&vcc->stats->rx_drop);
@@ -27,15 +27,16 @@ int atm_charge(struct atm_vcc *vcc,int t
 struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
     int gfp_flags)
 {
+	struct sock *sk = sk_atm(vcc);
 	int guess = atm_guess_pdu2truesize(pdu_size);
 
 	atm_force_charge(vcc,guess);
-	if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf) {
+	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
 		struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
 
 		if (skb) {
 			atomic_add(skb->truesize-guess,
-				   &vcc->sk->sk_rmem_alloc);
+				   &sk->sk_rmem_alloc);
 			return skb;
 		}
 	}
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -190,7 +190,7 @@ static int br2684_xmit_vcc(struct sk_buf
 		dev_kfree_skb(skb);
 		return 0;
 		}
-	atomic_add(skb->truesize, &atmvcc->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
 	ATM_SKB(skb)->atm_options = atmvcc->atm_options;
 	brdev->stats.tx_packets++;
 	brdev->stats.tx_bytes += skb->len;
@@ -557,7 +557,7 @@ Note: we do not have explicit unassign, 
 	barrier();
 	atmvcc->push = br2684_push;
 	skb_queue_head_init(&copy);
-	skb_migrate(&atmvcc->sk->sk_receive_queue, &copy);
+	skb_migrate(&sk_atm(atmvcc)->sk_receive_queue, &copy);
 	while ((skb = skb_dequeue(&copy)) != NULL) {
 		BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
 		BRPRIV(skb->dev)->stats.rx_packets--;
diff --git a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -58,6 +58,7 @@ static int start_timer = 1;
 
 static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
 {
+	struct sock *sk;
 	struct atmarp_ctrl *ctrl;
 	struct sk_buff *skb;
 
@@ -70,8 +71,10 @@ static int to_atmarpd(enum atmarp_ctrl_t
 	ctrl->itf_num = itf;
 	ctrl->ip = ip;
 	atm_force_charge(atmarpd,skb->truesize);
-	skb_queue_tail(&atmarpd->sk->sk_receive_queue, skb);
-	atmarpd->sk->sk_data_ready(atmarpd->sk, skb->len);
+
+	sk = sk_atm(atmarpd);
+	skb_queue_tail(&sk->sk_receive_queue, skb);
+	sk->sk_data_ready(sk, skb->len);
 	return 0;
 }
 
@@ -434,7 +437,7 @@ static int clip_start_xmit(struct sk_buf
 		memcpy(here,llc_oui,sizeof(llc_oui));
 		((u16 *) here)[3] = skb->protocol;
 	}
-	atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 	ATM_SKB(skb)->atm_options = vcc->atm_options;
 	entry->vccs->last_use = jiffies;
 	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
@@ -493,7 +496,7 @@ static int clip_mkip(struct atm_vcc *vcc
 	vcc->push = clip_push;
 	vcc->pop = clip_pop;
 	skb_queue_head_init(&copy);
-	skb_migrate(&vcc->sk->sk_receive_queue, &copy);
+	skb_migrate(&sk_atm(vcc)->sk_receive_queue, &copy);
 	/* re-process everything received between connection setup and MKIP */
 	while ((skb = skb_dequeue(&copy)) != NULL)
 		if (!clip_devs) {
@@ -686,10 +689,10 @@ static void atmarpd_close(struct atm_vcc
 	barrier();
 	unregister_inetaddr_notifier(&clip_inet_notifier);
 	unregister_netdevice_notifier(&clip_dev_notifier);
-	if (skb_peek(&vcc->sk->sk_receive_queue))
+	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
 		printk(KERN_ERR "atmarpd_close: closing with requests "
 		    "pending\n");
-	skb_queue_purge(&vcc->sk->sk_receive_queue);
+	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
 	DPRINTK("(done)\n");
 	module_put(THIS_MODULE);
 }
@@ -723,7 +726,7 @@ static int atm_init_atmarp(struct atm_vc
 	set_bit(ATM_VF_READY,&vcc->flags);
 	    /* allow replies and avoid getting closed if signaling dies */
 	vcc->dev = &atmarpd_dev;
-	vcc_insert_socket(vcc->sk);
+	vcc_insert_socket(sk_atm(vcc));
 	vcc->push = NULL;
 	vcc->pop = NULL; /* crash */
 	vcc->push_oam = NULL; /* crash */
@@ -822,7 +825,7 @@ static void atmarp_info(struct seq_file 
 	int svc, llc, off;
 
 	svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
-	       (clip_vcc->vcc->sk->sk_family == AF_ATMSVC));
+	       (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC));
 
 	llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
 	       clip_vcc->encap);
diff --git a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -12,7 +12,7 @@
 #include <linux/socket.h>	/* SOL_SOCKET */
 #include <linux/errno.h>	/* error codes */
 #include <linux/capability.h>
-#include <linux/mm.h>		/* verify_area */
+#include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/time.h>		/* struct timeval */
 #include <linux/skbuff.h>
@@ -41,7 +41,7 @@
 struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
 DEFINE_RWLOCK(vcc_sklist_lock);
 
-void __vcc_insert_socket(struct sock *sk)
+static void __vcc_insert_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
 	struct hlist_head *head = &vcc_hash[vcc->vci &
@@ -68,17 +68,18 @@ static void vcc_remove_socket(struct soc
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
 	struct sk_buff *skb;
+	struct sock *sk = sk_atm(vcc);
 
-	if (atomic_read(&vcc->sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) {
+	if (atomic_read(&sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) {
 		DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
-			atomic_read(&vcc->sk->sk_wmem_alloc), size,
-			vcc->sk->sk_sndbuf);
+			atomic_read(&sk->sk_wmem_alloc), size,
+			sk->sk_sndbuf);
 		return NULL;
 	}
 	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
-	DPRINTK("AlTx %d += %d\n", atomic_read(&vcc->sk->sk_wmem_alloc),
+	DPRINTK("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc),
 		skb->truesize);
-	atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk->sk_wmem_alloc);
 	return skb;
 }
 
@@ -89,15 +90,11 @@ EXPORT_SYMBOL(vcc_insert_socket);
 
 static void vcc_sock_destruct(struct sock *sk)
 {
-	struct atm_vcc *vcc = atm_sk(sk);
-
-	if (atomic_read(&vcc->sk->sk_rmem_alloc))
+	if (atomic_read(&sk->sk_rmem_alloc))
 		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
 
-	if (atomic_read(&vcc->sk->sk_wmem_alloc))
+	if (atomic_read(&sk->sk_wmem_alloc))
 		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
-
-	kfree(sk->sk_protinfo);
 }
 
 static void vcc_def_wakeup(struct sock *sk)
@@ -130,6 +127,11 @@ static void vcc_write_space(struct sock 
 	read_unlock(&sk->sk_callback_lock);
 }
 
+static struct proto vcc_proto = {
+	.name	  = "VCC",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct atm_vcc),
+};
  
 int vcc_create(struct socket *sock, int protocol, int family)
 {
@@ -139,35 +141,26 @@ int vcc_create(struct socket *sock, int 
 	sock->sk = NULL;
 	if (sock->type == SOCK_STREAM)
 		return -EINVAL;
-	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(family, GFP_KERNEL, &vcc_proto, 1);
 	if (!sk)
 		return -ENOMEM;
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 	sk->sk_state_change = vcc_def_wakeup;
 	sk->sk_write_space = vcc_write_space;
 
-	vcc = sk->sk_protinfo = kmalloc(sizeof(*vcc), GFP_KERNEL);
-	if (!vcc) {
-		sk_free(sk);
-		return -ENOMEM;
-	}
-
-	memset(vcc, 0, sizeof(*vcc));
-	vcc->sk = sk;
+	vcc = atm_sk(sk);
 	vcc->dev = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
 	vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
-	atomic_set(&vcc->sk->sk_wmem_alloc, 0);
-	atomic_set(&vcc->sk->sk_rmem_alloc, 0);
+	atomic_set(&sk->sk_wmem_alloc, 0);
+	atomic_set(&sk->sk_rmem_alloc, 0);
 	vcc->push = NULL;
 	vcc->pop = NULL;
 	vcc->push_oam = NULL;
 	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
 	vcc->atm_options = vcc->aal_options = 0;
 	sk->sk_destruct = vcc_sock_destruct;
-	sock->sk = sk;
 	return 0;
 }
 
@@ -187,7 +180,7 @@ static void vcc_destroy_socket(struct so
 
 		vcc_remove_socket(sk);	/* no more receive */
 
-		while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue)) != NULL) {
+		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
@@ -215,11 +208,13 @@ int vcc_release(struct socket *sock)
 
 void vcc_release_async(struct atm_vcc *vcc, int reply)
 {
+	struct sock *sk = sk_atm(vcc);
+
 	set_bit(ATM_VF_CLOSE, &vcc->flags);
-	vcc->sk->sk_shutdown |= RCV_SHUTDOWN;
-	vcc->sk->sk_err = -reply;
+	sk->sk_shutdown |= RCV_SHUTDOWN;
+	sk->sk_err = -reply;
 	clear_bit(ATM_VF_WAITING, &vcc->flags);
-	vcc->sk->sk_state_change(vcc->sk);
+	sk->sk_state_change(sk);
 }
 
 
@@ -328,6 +323,7 @@ static int find_ci(struct atm_vcc *vcc, 
 static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
 			 int vci)
 {
+	struct sock *sk = sk_atm(vcc);
 	int error;
 
 	if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
@@ -347,7 +343,7 @@ static int __vcc_connect(struct atm_vcc 
 	}
 	vcc->vpi = vpi;
 	vcc->vci = vci;
-	__vcc_insert_socket(vcc->sk);
+	__vcc_insert_socket(sk);
 	write_unlock_irq(&vcc_sklist_lock);
 	switch (vcc->qos.aal) {
 		case ATM_AAL0:
@@ -386,7 +382,7 @@ static int __vcc_connect(struct atm_vcc 
 	return 0;
 
 fail:
-	vcc_remove_socket(vcc->sk);
+	vcc_remove_socket(sk);
 fail_module_put:
 	module_put(dev->ops->owner);
 	/* ensure we get dev module ref count correct */
@@ -495,7 +491,7 @@ int vcc_recvmsg(struct kiocb *iocb, stru
         if (error)
                 return error;
         sock_recv_timestamp(msg, sk, skb);
-        DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->rmem_alloc), skb->truesize);
+        DPRINTK("RcvM %d -= %d\n", atomic_read(&sk->rmem_alloc), skb->truesize);
         atm_return(vcc, skb->truesize);
         skb_free_datagram(sk, skb);
         return copied;
@@ -544,7 +540,7 @@ int vcc_sendmsg(struct kiocb *iocb, stru
 		error = -EMSGSIZE;
 		goto out;
 	}
-	/* verify_area is done by net/socket.c */
+
 	eff = (size+3) & ~3; /* align to word boundary */
 	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 	error = 0;
@@ -615,7 +611,7 @@ unsigned int vcc_poll(struct file *file,
 		return mask;
 
 	if (vcc->qos.txtp.traffic_class != ATM_NONE &&
-	    vcc_writable(vcc->sk))
+	    vcc_writable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 
 	return mask;
@@ -638,7 +634,7 @@ static int atm_change_qos(struct atm_vcc
 	if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
 	if (error) return error;
 	if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
-	if (vcc->sk->sk_family == AF_ATMPVC)
+	if (sk_atm(vcc)->sk_family == AF_ATMPVC)
 		return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
 	return svc_change_qos(vcc,qos);
 }
@@ -762,43 +758,34 @@ int vcc_getsockopt(struct socket *sock, 
 	return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
 }
 
-
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-struct net_bridge;
-struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
-						unsigned char *addr) = NULL;
-void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL;
-#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE)
-EXPORT_SYMBOL(br_fdb_get_hook);
-EXPORT_SYMBOL(br_fdb_put_hook);
-#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
-#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
-#endif /* defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) */
-
-
 static int __init atm_init(void)
 {
 	int error;
 
+	if ((error = proto_register(&vcc_proto, 0)) < 0)
+		goto out;
+
 	if ((error = atmpvc_init()) < 0) {
 		printk(KERN_ERR "atmpvc_init() failed with %d\n", error);
-		goto failure;
+		goto out_unregister_vcc_proto;
 	}
 	if ((error = atmsvc_init()) < 0) {
 		printk(KERN_ERR "atmsvc_init() failed with %d\n", error);
-		goto failure;
+		goto out_atmpvc_exit;
 	}
         if ((error = atm_proc_init()) < 0) {
 		printk(KERN_ERR "atm_proc_init() failed with %d\n",error);
-		goto failure;
+		goto out_atmsvc_exit;
 	}
-	return 0;
-
-failure:
-	atmsvc_exit();
-	atmpvc_exit();
+out:
 	return error;
+out_atmsvc_exit:
+	atmsvc_exit();
+out_atmpvc_exit:
+	atmsvc_exit();
+out_unregister_vcc_proto:
+	proto_unregister(&vcc_proto);
+	goto out;
 }
 
 static void __exit atm_exit(void)
@@ -806,6 +793,7 @@ static void __exit atm_exit(void)
 	atm_proc_exit();
 	atmsvc_exit();
 	atmpvc_exit();
+	proto_unregister(&vcc_proto);
 }
 
 module_init(atm_init);
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(deregister_atm_ioctl);
 
 int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
 	int error;
 	struct list_head * pos;
@@ -59,8 +60,8 @@ int vcc_ioctl(struct socket *sock, unsig
 				error =  -EINVAL;
 				goto done;
 			}
-			error = put_user(vcc->sk->sk_sndbuf -
-					 atomic_read(&vcc->sk->sk_wmem_alloc),
+			error = put_user(sk->sk_sndbuf -
+					 atomic_read(&sk->sk_wmem_alloc),
 					 (int __user *) argp) ? -EFAULT : 0;
 			goto done;
 		case SIOCINQ:
@@ -71,13 +72,13 @@ int vcc_ioctl(struct socket *sock, unsig
 					error = -EINVAL;
 					goto done;
 				}
-				skb = skb_peek(&vcc->sk->sk_receive_queue);
+				skb = skb_peek(&sk->sk_receive_queue);
 				error = put_user(skb ? skb->len : 0,
 					 	 (int __user *)argp) ? -EFAULT : 0;
 				goto done;
 			}
 		case SIOCGSTAMP: /* borrowed from IP */
-			error = sock_get_timestamp(vcc->sk, argp);
+			error = sock_get_timestamp(sk, argp);
 			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
diff --git a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -37,11 +37,8 @@
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #include <linux/if_bridge.h>
 #include "../bridge/br_private.h"
-static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 
-extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
-       unsigned char *addr);
-extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 #endif
 
 /* Modular too */
@@ -83,6 +80,29 @@ static int lane2_resolve(struct net_devi
 static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
                          u8 *tlvs, u32 sizeoftlvs);
 
+static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, 
+			   unsigned long permanent);
+static void lec_arp_check_empties(struct lec_priv *priv,
+				  struct atm_vcc *vcc, struct sk_buff *skb);
+static void lec_arp_destroy(struct lec_priv *priv);
+static void lec_arp_init(struct lec_priv *priv);
+static struct atm_vcc* lec_arp_resolve(struct lec_priv *priv,
+				       unsigned char *mac_to_find,
+				       int is_rdesc,
+				       struct lec_arp_table **ret_entry);
+static void lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
+			   unsigned char *atm_addr, unsigned long remoteflag,
+			   unsigned int targetless_le_arp);
+static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
+static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
+static void lec_set_flush_tran_id(struct lec_priv *priv,
+				  unsigned char *atm_addr,
+				  unsigned long tran_id);
+static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
+			  struct atm_vcc *vcc,
+			  void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb));
+static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
+
 static struct lane2_ops lane2_ops = {
 	lane2_resolve,         /* resolve,             spec 3.1.3 */
 	lane2_associate_req,   /* associate_req,       spec 3.1.4 */
@@ -94,21 +114,6 @@ static unsigned char bus_mac[ETH_ALEN] =
 /* Device structures */
 static struct net_device *dev_lec[MAX_LEC_ITF];
 
-/* This will be called from proc.c via function pointer */
-struct net_device *get_dev_lec(int itf)
-{
-	struct net_device *dev;
-
-	if (itf >= MAX_LEC_ITF)
-		return NULL;
-	rtnl_lock();
-	dev = dev_lec[itf];
-	if (dev)
-		dev_hold(dev);
-	rtnl_unlock();
-	return dev;
-}
-
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
 {
@@ -122,6 +127,7 @@ static void lec_handle_bridge(struct sk_
         eth = (struct ethhdr *)skb->data;
         buff = skb->data + skb->dev->hard_header_len;
         if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
+		struct sock *sk;
                 struct sk_buff *skb2;
                 struct atmlec_msg *mesg;
 
@@ -135,8 +141,9 @@ static void lec_handle_bridge(struct sk_
 
                 priv = (struct lec_priv *)dev->priv;
                 atm_force_charge(priv->lecd, skb2->truesize);
-                skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2);
-                priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb2->len);
+		sk = sk_atm(priv->lecd);
+                skb_queue_tail(&sk->sk_receive_queue, skb2);
+                sk->sk_data_ready(sk, skb2->len);
         }
 
         return;
@@ -153,7 +160,7 @@ static void lec_handle_bridge(struct sk_
  * and returns NULL.
  */
 #ifdef CONFIG_TR
-unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
+static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
 {
         struct trh_hdr *trh;
         int riflen, num_rdsc;
@@ -214,7 +221,7 @@ lec_send(struct atm_vcc *vcc, struct sk_
 	ATM_SKB(skb)->vcc = vcc;
 	ATM_SKB(skb)->atm_options = vcc->atm_options;
 
-	atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 	if (vcc->send(vcc, skb) < 0) {
 		priv->stats.tx_dropped++;
 		return;
@@ -430,7 +437,7 @@ lec_atm_send(struct atm_vcc *vcc, struct
         int i;
         char *tmp; /* FIXME */
 
-	atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
         mesg = (struct atmlec_msg *)skb->data;
         tmp = skb->data;
         tmp += sizeof(struct atmlec_msg);
@@ -528,6 +535,7 @@ lec_atm_send(struct atm_vcc *vcc, struct
                     f->dst->state == BR_STATE_FORWARDING) {
                                 /* hit from bridge table, send LE_ARP_RESPONSE */
                         struct sk_buff *skb2;
+			struct sock *sk;
 
                         DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
                         skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
@@ -538,8 +546,9 @@ lec_atm_send(struct atm_vcc *vcc, struct
                         skb2->len = sizeof(struct atmlec_msg);
                         memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
                         atm_force_charge(priv->lecd, skb2->truesize);
-                        skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2);
-                        priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb2->len);
+			sk = sk_atm(priv->lecd);
+                        skb_queue_tail(&sk->sk_receive_queue, skb2);
+                        sk->sk_data_ready(sk, skb2->len);
                 }
                 if (f != NULL) br_fdb_put_hook(f);
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
@@ -567,10 +576,10 @@ lec_atm_close(struct atm_vcc *vcc)
         netif_stop_queue(dev);
         lec_arp_destroy(priv);
 
-        if (skb_peek(&vcc->sk->sk_receive_queue))
+        if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
 		printk("%s lec_atm_close: closing with messages pending\n",
                        dev->name);
-        while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue)) != NULL) {
+        while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
                 atm_return(vcc, skb->truesize);
 		dev_kfree_skb(skb);
         }
@@ -595,11 +604,12 @@ static struct atm_dev lecatm_dev = {
  * LANE2: new argument struct sk_buff *data contains
  * the LE_ARP based TLVs introduced in the LANE2 spec
  */
-int 
+static int 
 send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, 
              unsigned char *mac_addr, unsigned char *atm_addr,
              struct sk_buff *data)
 {
+	struct sock *sk;
 	struct sk_buff *skb;
 	struct atmlec_msg *mesg;
 
@@ -623,14 +633,15 @@ send_to_lecd(struct lec_priv *priv, atml
 		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
 
         atm_force_charge(priv->lecd, skb->truesize);
-	skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb);
-        priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb->len);
+	sk = sk_atm(priv->lecd);
+	skb_queue_tail(&sk->sk_receive_queue, skb);
+        sk->sk_data_ready(sk, skb->len);
 
         if (data != NULL) {
                 DPRINTK("lec: about to send %d bytes of data\n", data->len);
                 atm_force_charge(priv->lecd, data->truesize);
-                skb_queue_tail(&priv->lecd->sk->sk_receive_queue, data);
-                priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb->len);
+                skb_queue_tail(&sk->sk_receive_queue, data);
+                sk->sk_data_ready(sk, skb->len);
         }
 
         return 0;
@@ -675,7 +686,7 @@ static unsigned char lec_ctrl_magic[] = 
         0x01,
         0x01 };
 
-void 
+static void 
 lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
 {
         struct net_device *dev = (struct net_device *)vcc->proto_data;
@@ -711,9 +722,11 @@ lec_push(struct atm_vcc *vcc, struct sk_
                 printk("%s...\n",buf);
 #endif /* DUMP_PACKETS > 0 */
         if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
+		struct sock *sk = sk_atm(vcc);
+
                 DPRINTK("%s: To daemon\n",dev->name);
-                skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-                vcc->sk->sk_data_ready(vcc->sk, skb->len);
+                skb_queue_tail(&sk->sk_receive_queue, skb);
+                sk->sk_data_ready(sk, skb->len);
         } else { /* Data frame, queue to protocol handlers */
                 unsigned char *dst;
 
@@ -756,7 +769,7 @@ lec_push(struct atm_vcc *vcc, struct sk_
         }
 }
 
-void
+static void
 lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 {
 	struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
@@ -776,7 +789,7 @@ lec_pop(struct atm_vcc *vcc, struct sk_b
 	}
 }
 
-int 
+static int 
 lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 {
 	struct lec_vcc_priv *vpriv;
@@ -805,7 +818,7 @@ lec_vcc_attach(struct atm_vcc *vcc, void
         return 0;
 }
 
-int 
+static int 
 lec_mcast_attach(struct atm_vcc *vcc, int arg)
 {
         if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
@@ -815,7 +828,7 @@ lec_mcast_attach(struct atm_vcc *vcc, in
 }
 
 /* Initialize device. */
-int 
+static int 
 lecd_attach(struct atm_vcc *vcc, int arg)
 {  
         int i;
@@ -866,7 +879,7 @@ lecd_attach(struct atm_vcc *vcc, int arg
 	priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
         vcc->dev = &lecatm_dev;
-        vcc_insert_socket(vcc->sk);
+        vcc_insert_socket(sk_atm(vcc));
         
         vcc->proto_data = dev_lec[i];
 	set_bit(ATM_VF_META,&vcc->flags);
@@ -1375,7 +1388,6 @@ static void lane2_associate_ind (struct 
 
 static void lec_arp_check_expire(unsigned long data);
 static void lec_arp_expire_arp(unsigned long data);
-void dump_arp_table(struct lec_priv *priv);
 
 /* 
  * Arp table funcs
@@ -1386,7 +1398,7 @@ void dump_arp_table(struct lec_priv *pri
 /*
  * Initialization of arp-cache
  */
-void 
+static void 
 lec_arp_init(struct lec_priv *priv)
 {
         unsigned short i;
@@ -1402,7 +1414,7 @@ lec_arp_init(struct lec_priv *priv)
         add_timer(&priv->lec_arp_timer);
 }
 
-void
+static void
 lec_arp_clear_vccs(struct lec_arp_table *entry)
 {
         if (entry->vcc) {
@@ -1531,7 +1543,7 @@ get_status_string(unsigned char st)
 }
 #endif
 
-void
+static void
 dump_arp_table(struct lec_priv *priv)
 {
 #if DEBUG_ARP_TABLE
@@ -1683,7 +1695,7 @@ dump_arp_table(struct lec_priv *priv)
 /*
  * Destruction of arp-cache
  */
-void
+static void
 lec_arp_destroy(struct lec_priv *priv)
 {
 	unsigned long flags;
@@ -1945,9 +1957,9 @@ lec_arp_check_expire(unsigned long data)
  * Try to find vcc where mac_address is attached.
  * 
  */
-struct atm_vcc*
-lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
-                struct lec_arp_table **ret_entry)
+static struct atm_vcc*
+lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
+		int is_rdesc, struct lec_arp_table **ret_entry)
 {
 	unsigned long flags;
         struct lec_arp_table *entry;
@@ -2026,7 +2038,7 @@ out:
 	return found;
 }
 
-int
+static int
 lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, 
                 unsigned long permanent)
 {
@@ -2056,7 +2068,7 @@ lec_addr_delete(struct lec_priv *priv, u
 /*
  * Notifies:  Response to arp_request (atm_addr != NULL) 
  */
-void
+static void
 lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
                unsigned char *atm_addr, unsigned long remoteflag,
                unsigned int targetless_le_arp)
@@ -2168,7 +2180,7 @@ out:
 /*
  * Notifies: Vcc setup ready 
  */
-void
+static void
 lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
               struct atm_vcc *vcc,
               void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb))
@@ -2312,7 +2324,7 @@ out:
 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
-void
+static void
 lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
 {
 	unsigned long flags;
@@ -2338,7 +2350,7 @@ lec_flush_complete(struct lec_priv *priv
         dump_arp_table(priv);
 }
 
-void
+static void
 lec_set_flush_tran_id(struct lec_priv *priv,
                       unsigned char *atm_addr, unsigned long tran_id)
 {
@@ -2356,7 +2368,7 @@ lec_set_flush_tran_id(struct lec_priv *p
 	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
-int 
+static int 
 lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
 {
 	unsigned long flags;
@@ -2393,7 +2405,7 @@ out:
         return err;
 }
 
-void
+static void
 lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
 {
 	unsigned long flags;
@@ -2468,7 +2480,7 @@ lec_vcc_close(struct lec_priv *priv, str
 	dump_arp_table(priv);
 }
 
-void
+static void
 lec_arp_check_empties(struct lec_priv *priv,
                       struct atm_vcc *vcc, struct sk_buff *skb)
 {
diff --git a/net/atm/lec.h b/net/atm/lec.h
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -14,14 +14,6 @@
 #include <linux/netdevice.h>
 #include <linux/atmlec.h>
 
-#if defined (CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-#include <linux/if_bridge.h>
-struct net_bridge;
-extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
-                                                unsigned char *addr);
-extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
-#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
-
 #define LEC_HEADER_LEN 16
 
 struct lecdatahdr_8023 {
@@ -146,14 +138,5 @@ struct lec_vcc_priv {
 
 #define LEC_VCC_PRIV(vcc)	((struct lec_vcc_priv *)((vcc)->user_back))
 
-int lecd_attach(struct atm_vcc *vcc, int arg);
-int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg);
-int lec_mcast_attach(struct atm_vcc *vcc, int arg);
-struct net_device *get_dev_lec(int itf);
-int send_to_lecd(struct lec_priv *priv,
-                 atmlec_msg_type type, unsigned char *mac_addr,
-                 unsigned char *atm_addr, struct sk_buff *data);
-void lec_push(struct atm_vcc *vcc, struct sk_buff *skb);
-
 #endif /* _LEC_H_ */
 
diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h
--- a/net/atm/lec_arpc.h
+++ b/net/atm/lec_arpc.h
@@ -89,28 +89,4 @@ struct tlv {                   /* LANE2:
 #define LEC_REMOTE_FLAG      0x0001
 #define LEC_PERMANENT_FLAG   0x0002
 
-/* Protos */
-void lec_arp_init(struct lec_priv *priv);
-int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
-void lec_arp_destroy(struct lec_priv *priv);
-void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
-
-struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
-                                unsigned char *mac_to_addr,
-                                int is_rdesc,
-                                struct lec_arp_table **ret_entry);
-void lec_vcc_added(struct lec_priv *dev,
-                   struct atmlec_ioc *ioc_data, struct atm_vcc *vcc,
-                   void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb));
-void lec_arp_check_empties(struct lec_priv *priv,
-                           struct atm_vcc *vcc, struct sk_buff *skb);
-int lec_addr_delete(struct lec_priv *priv,
-                    unsigned char *mac_addr, unsigned long permanent);
-void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
-void lec_arp_update(struct lec_priv *priv,
-                    unsigned char *mac_addr, unsigned char *atm_addr,
-                    unsigned long remoteflag, unsigned int targetless_le_arp);
-void lec_set_flush_tran_id(struct lec_priv *priv,
-                           unsigned char *mac_addr, unsigned long tran_id);
-
 #endif
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -522,7 +522,7 @@ static int send_via_shortcut(struct sk_b
 		memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
 	}
 
-	atomic_add(skb->truesize, &entry->shortcut->sk->sk_wmem_alloc);
+	atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
 	ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
 	entry->shortcut->send(entry->shortcut, skb);
 	entry->packets_fwded++;
@@ -564,7 +564,7 @@ static int mpc_send_packet(struct sk_buf
 	return retval;
 }
 
-int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 {
 	int bytes_left;
 	struct mpoa_client *mpc;
@@ -665,10 +665,12 @@ static void mpc_push(struct atm_vcc *vcc
 	
 	skb->dev = dev;
 	if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
+		struct sock *sk = sk_atm(vcc);
+
 		dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
 		/* Pass control packets to daemon */
-		skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-		vcc->sk->sk_data_ready(vcc->sk, skb->len);
+		skb_queue_tail(&sk->sk_receive_queue, skb);
+		sk->sk_data_ready(sk, skb->len);
 		return;
 	}
 
@@ -751,7 +753,7 @@ static struct atm_dev mpc_dev = {
 	/* members not explicitly initialised will be 0 */
 };
 
-int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
+static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
 {
 	struct mpoa_client *mpc;
 	struct lec_priv *priv;
@@ -794,7 +796,7 @@ int atm_mpoa_mpoad_attach (struct atm_vc
 
 	mpc->mpoad_vcc = vcc;
 	vcc->dev = &mpc_dev;
-	vcc_insert_socket(vcc->sk);
+	vcc_insert_socket(sk_atm(vcc));
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
@@ -853,7 +855,7 @@ static void mpoad_close(struct atm_vcc *
 	mpc->in_ops->destroy_cache(mpc);
 	mpc->eg_ops->destroy_cache(mpc);
 
-	while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
+	while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
 		atm_return(vcc, skb->truesize);
 		kfree_skb(skb);
 	}
@@ -873,7 +875,7 @@ static int msg_from_mpoad(struct atm_vcc
 	
 	struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
 	struct k_message *mesg = (struct k_message*)skb->data;
-	atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 	
 	if (mpc == NULL) {
 		printk("mpoa: msg_from_mpoad: no mpc found\n");
@@ -938,6 +940,7 @@ static int msg_from_mpoad(struct atm_vcc
 int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
 {
 	struct sk_buff *skb;
+	struct sock *sk;
 
 	if (mpc == NULL || !mpc->mpoad_vcc) {
 		printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type);
@@ -950,8 +953,10 @@ int msg_to_mpoad(struct k_message *mesg,
 	skb_put(skb, sizeof(struct k_message));
 	memcpy(skb->data, mesg, sizeof(struct k_message));
 	atm_force_charge(mpc->mpoad_vcc, skb->truesize);
-	skb_queue_tail(&mpc->mpoad_vcc->sk->sk_receive_queue, skb);
-	mpc->mpoad_vcc->sk->sk_data_ready(mpc->mpoad_vcc->sk, skb->len);
+	
+	sk = sk_atm(mpc->mpoad_vcc);
+	skb_queue_tail(&sk->sk_receive_queue, skb);
+	sk->sk_data_ready(sk, skb->len);
 
 	return 0;
 }
@@ -1206,6 +1211,7 @@ static void egress_purge_rcvd(struct k_m
 
 static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
 {
+	struct sock *sk;
 	struct k_message *purge_msg;
 	struct sk_buff *skb;
 
@@ -1229,8 +1235,10 @@ static void purge_egress_shortcut(struct
 		purge_msg->content.eg_info = entry->ctrl_info;
 
 	atm_force_charge(vcc, skb->truesize);
-	skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-	vcc->sk->sk_data_ready(vcc->sk, skb->len);
+
+	sk = sk_atm(vcc);
+	skb_queue_tail(&sk->sk_receive_queue, skb);
+	sk->sk_data_ready(sk, skb->len);
 	dprintk("mpoa: purge_egress_shortcut: exiting:\n");
 
 	return;
@@ -1452,7 +1460,7 @@ static __init int atm_mpoa_init(void)
 	return 0;
 }
 
-void __exit atm_mpoa_cleanup(void)
+static void __exit atm_mpoa_cleanup(void)
 {
 	struct mpoa_client *mpc, *tmp;
 	struct atm_mpoa_qos *qos, *nextqos;
diff --git a/net/atm/mpc.h b/net/atm/mpc.h
--- a/net/atm/mpc.h
+++ b/net/atm/mpc.h
@@ -11,10 +11,6 @@
 /* kernel -> mpc-daemon */
 int msg_to_mpoad(struct k_message *msg, struct mpoa_client *mpc);
 
-/* Functions for ioctl(ATMMPC_*) operations */
-int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg);
-int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg);
-
 struct mpoa_client {
         struct mpoa_client *next;
         struct net_device *dev;      /* lec in question                     */
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -233,7 +233,8 @@ static int pppoatm_send(struct ppp_chann
 		kfree_skb(skb);
 		return 1;
 	}
-	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->sk_wmem_alloc);
+
+	atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
 	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
 	DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
 	    pvcc->chan.unit, skb, ATM_SKB(skb)->vcc,
@@ -344,7 +345,7 @@ static int pppoatm_ioctl(struct socket *
 	return -ENOIOCTLCMD;
 }
 
-struct atm_ioctl pppoatm_ioctl_ops = {
+static struct atm_ioctl pppoatm_ioctl_ops = {
 	.owner	= THIS_MODULE,
 	.ioctl	= pppoatm_ioctl,
 };
diff --git a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -71,9 +71,7 @@ struct vcc_state {
 
 static inline int compare_family(struct sock *sk, int family)
 {
-	struct atm_vcc *vcc = atm_sk(sk);
-
-	return !family || (vcc->sk->sk_family == family);
+	return !family || (sk->sk_family == family);
 }
 
 static int __vcc_walk(struct sock **sock, int family, int *bucket, loff_t l)
@@ -203,13 +201,15 @@ static const char *vcc_state(struct atm_
 
 static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
+	struct sock *sk = sk_atm(vcc);
+
 	seq_printf(seq, "%p ", vcc);
 	if (!vcc->dev)
 		seq_printf(seq, "Unassigned    ");
 	else 
 		seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi,
 			vcc->vci);
-	switch (vcc->sk->sk_family) {
+	switch (sk->sk_family) {
 		case AF_ATMPVC:
 			seq_printf(seq, "PVC");
 			break;
@@ -217,12 +217,12 @@ static void vcc_info(struct seq_file *se
 			seq_printf(seq, "SVC");
 			break;
 		default:
-			seq_printf(seq, "%3d", vcc->sk->sk_family);
+			seq_printf(seq, "%3d", sk->sk_family);
 	}
-	seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, vcc->sk->sk_err,
-		atomic_read(&vcc->sk->sk_wmem_alloc),vcc->sk->sk_sndbuf,
-		atomic_read(&vcc->sk->sk_rmem_alloc),vcc->sk->sk_rcvbuf,
-		atomic_read(&vcc->sk->sk_refcnt));
+	seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err,
+		  atomic_read(&sk->sk_wmem_alloc), sk->sk_sndbuf,
+		  atomic_read(&sk->sk_rmem_alloc), sk->sk_rcvbuf,
+		  atomic_read(&sk->sk_refcnt));
 }
 
 static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
diff --git a/net/atm/protocols.h b/net/atm/protocols.h
--- a/net/atm/protocols.h
+++ b/net/atm/protocols.h
@@ -6,8 +6,6 @@
 #ifndef NET_ATM_PROTOCOLS_H
 #define NET_ATM_PROTOCOLS_H
 
-void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb);
-
 int atm_init_aal0(struct atm_vcc *vcc);	/* "raw" AAL0 */
 int atm_init_aal34(struct atm_vcc *vcc);/* "raw" AAL3/4 transport */
 int atm_init_aal5(struct atm_vcc *vcc);	/* "raw" AAL5 transport */
diff --git a/net/atm/raw.c b/net/atm/raw.c
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -25,22 +25,26 @@
  * SKB == NULL indicates that the link is being closed
  */
 
-void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
+static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	if (skb) {
-		skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-		vcc->sk->sk_data_ready(vcc->sk, skb->len);
+		struct sock *sk = sk_atm(vcc);
+
+		skb_queue_tail(&sk->sk_receive_queue, skb);
+		sk->sk_data_ready(sk, skb->len);
 	}
 }
 
 
 static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	DPRINTK("APopR (%d) %d -= %d\n", vcc->vci, vcc->sk->sk_wmem_alloc,
+	struct sock *sk = sk_atm(vcc);
+
+	DPRINTK("APopR (%d) %d -= %d\n", vcc->vci, sk->sk_wmem_alloc,
 		skb->truesize);
-	atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
 	dev_kfree_skb_any(skb);
-	vcc->sk->sk_write_space(vcc->sk);
+	sk->sk_write_space(sk);
 }
 
 
diff --git a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -44,11 +44,6 @@ static struct atm_dev *__alloc_atm_dev(c
 	return dev;
 }
 
-static void __free_atm_dev(struct atm_dev *dev)
-{
-	kfree(dev);
-}
-
 static struct atm_dev *__atm_dev_lookup(int number)
 {
 	struct atm_dev *dev;
@@ -90,7 +85,7 @@ struct atm_dev *atm_dev_register(const c
 		if ((inuse = __atm_dev_lookup(number))) {
 			atm_dev_put(inuse);
 			spin_unlock(&atm_dev_lock);
-			__free_atm_dev(dev);
+			kfree(dev);
 			return NULL;
 		}
 		dev->number = number;
@@ -119,7 +114,7 @@ struct atm_dev *atm_dev_register(const c
 		spin_lock(&atm_dev_lock);
 		list_del(&dev->dev_list);
 		spin_unlock(&atm_dev_lock);
-		__free_atm_dev(dev);
+		kfree(dev);
 		return NULL;
 	}
 
@@ -148,7 +143,7 @@ void atm_dev_deregister(struct atm_dev *
                 }
         }
 
-	__free_atm_dev(dev);
+	kfree(dev);
 }
 
 void shutdown_atm_dev(struct atm_dev *dev)
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -62,8 +62,8 @@ static void sigd_put_skb(struct sk_buff 
 	}
 #endif
 	atm_force_charge(sigd,skb->truesize);
-	skb_queue_tail(&sigd->sk->sk_receive_queue,skb);
-	sigd->sk->sk_data_ready(sigd->sk, skb->len);
+	skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb);
+	sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len);
 }
 
 
@@ -97,15 +97,18 @@ static int sigd_send(struct atm_vcc *vcc
 {
 	struct atmsvc_msg *msg;
 	struct atm_vcc *session_vcc;
+	struct sock *sk;
 
 	msg = (struct atmsvc_msg *) skb->data;
-	atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc);
+	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 	DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
 	  (unsigned long) msg->vcc);
 	vcc = *(struct atm_vcc **) &msg->vcc;
+	sk = sk_atm(vcc);
+
 	switch (msg->type) {
 		case as_okay:
-			vcc->sk->sk_err = -msg->reply;
+			sk->sk_err = -msg->reply;
 			clear_bit(ATM_VF_WAITING, &vcc->flags);
 			if (!*vcc->local.sas_addr.prv &&
 			    !*vcc->local.sas_addr.pub) {
@@ -126,25 +129,25 @@ static int sigd_send(struct atm_vcc *vcc
 		case as_error:
 			clear_bit(ATM_VF_REGIS,&vcc->flags);
 			clear_bit(ATM_VF_READY,&vcc->flags);
-			vcc->sk->sk_err = -msg->reply;
+			sk->sk_err = -msg->reply;
 			clear_bit(ATM_VF_WAITING, &vcc->flags);
 			break;
 		case as_indicate:
 			vcc = *(struct atm_vcc **) &msg->listen_vcc;
+			sk = sk_atm(vcc);
 			DPRINTK("as_indicate!!!\n");
-			lock_sock(vcc->sk);
-			if (vcc->sk->sk_ack_backlog ==
-			    vcc->sk->sk_max_ack_backlog) {
+			lock_sock(sk);
+			if (sk_acceptq_is_full(sk)) {
 				sigd_enq(NULL,as_reject,vcc,NULL,NULL);
 				dev_kfree_skb(skb);
 				goto as_indicate_complete;
 			}
-			vcc->sk->sk_ack_backlog++;
-			skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-			DPRINTK("waking vcc->sk->sk_sleep 0x%p\n", vcc->sk->sk_sleep);
-			vcc->sk->sk_state_change(vcc->sk);
+			sk->sk_ack_backlog++;
+			skb_queue_tail(&sk->sk_receive_queue, skb);
+			DPRINTK("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
+			sk->sk_state_change(sk);
 as_indicate_complete:
-			release_sock(vcc->sk);
+			release_sock(sk);
 			return 0;
 		case as_close:
 			set_bit(ATM_VF_RELEASED,&vcc->flags);
@@ -155,7 +158,7 @@ as_indicate_complete:
 			break;
 		case as_addparty:
 		case as_dropparty:
-			vcc->sk->sk_err_soft = msg->reply;	/* < 0 failure, otherwise ep_ref */
+			sk->sk_err_soft = msg->reply;	/* < 0 failure, otherwise ep_ref */
 			clear_bit(ATM_VF_WAITING, &vcc->flags);
 			break;
 		default:
@@ -163,7 +166,7 @@ as_indicate_complete:
 			    (int) msg->type);
 			return -EINVAL;
 	}
-	vcc->sk->sk_state_change(vcc->sk);
+	sk->sk_state_change(sk);
 out:
 	dev_kfree_skb(skb);
 	return 0;
@@ -213,7 +216,7 @@ void sigd_enq(struct atm_vcc *vcc,enum a
 
 static void purge_vcc(struct atm_vcc *vcc)
 {
-	if (vcc->sk->sk_family == PF_ATMSVC &&
+	if (sk_atm(vcc)->sk_family == PF_ATMSVC &&
 	    !test_bit(ATM_VF_META,&vcc->flags)) {
 		set_bit(ATM_VF_RELEASED,&vcc->flags);
 		vcc_release_async(vcc, -EUNATCH);
@@ -229,9 +232,9 @@ static void sigd_close(struct atm_vcc *v
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
-	if (skb_peek(&vcc->sk->sk_receive_queue))
+	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
-	skb_queue_purge(&vcc->sk->sk_receive_queue);
+	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
 
 	read_lock(&vcc_sklist_lock);
 	for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
@@ -268,7 +271,7 @@ int sigd_attach(struct atm_vcc *vcc)
 	DPRINTK("sigd_attach\n");
 	sigd = vcc;
 	vcc->dev = &sigd_dev;
-	vcc_insert_socket(vcc->sk);
+	vcc_insert_socket(sk_atm(vcc));
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 #ifdef WAIT_FOR_DEMON
diff --git a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -53,20 +53,21 @@ static void svc_disconnect(struct atm_vc
 {
 	DEFINE_WAIT(wait);
 	struct sk_buff *skb;
+	struct sock *sk = sk_atm(vcc);
 
 	DPRINTK("svc_disconnect %p\n",vcc);
 	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
-		prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 		sigd_enq(vcc,as_close,NULL,NULL,NULL);
 		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
 			schedule();
-			prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+			prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 		}
-		finish_wait(vcc->sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
 	}
 	/* beware - socket is still in use by atmsigd until the last
 	   as_indicate has been answered */
-	while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue)) != NULL) {
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 		atm_return(vcc, skb->truesize);
 		DPRINTK("LISTEN REL\n");
 		sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
@@ -318,8 +319,7 @@ static int svc_listen(struct socket *soc
 		goto out;
 	}
 	set_bit(ATM_VF_LISTEN,&vcc->flags);
-	vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog :
-						    ATM_BACKLOG_DEFAULT;
+	sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
 	error = -sk->sk_err;
 out:
 	release_sock(sk);
@@ -348,8 +348,8 @@ static int svc_accept(struct socket *soc
 	while (1) {
 		DEFINE_WAIT(wait);
 
-		prepare_to_wait(old_vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
-		while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) &&
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+		while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
 		       sigd) {
 			if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
 			if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
@@ -367,9 +367,9 @@ static int svc_accept(struct socket *soc
 				error = -ERESTARTSYS;
 				break;
 			}
-			prepare_to_wait(old_vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+			prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 		}
-		finish_wait(old_vcc->sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
 		if (error)
 			goto out;
 		if (!skb) {
@@ -385,7 +385,7 @@ static int svc_accept(struct socket *soc
 		error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
 				    msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci);
 		dev_kfree_skb(skb);
-		old_vcc->sk->sk_ack_backlog--;
+		sk->sk_ack_backlog--;
 		if (error) {
 			sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
 			    &old_vcc->qos,error);
@@ -394,23 +394,23 @@ static int svc_accept(struct socket *soc
 		}
 		/* wait should be short, so we ignore the non-blocking flag */
 		set_bit(ATM_VF_WAITING, &new_vcc->flags);
-		prepare_to_wait(new_vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+		prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) {
 			release_sock(sk);
 			schedule();
 			lock_sock(sk);
-			prepare_to_wait(new_vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+			prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 		}
-		finish_wait(new_vcc->sk->sk_sleep, &wait);
+		finish_wait(sk_atm(new_vcc)->sk_sleep, &wait);
 		if (!sigd) {
 			error = -EUNATCH;
 			goto out;
 		}
-		if (!new_vcc->sk->sk_err)
+		if (!sk_atm(new_vcc)->sk_err)
 			break;
-		if (new_vcc->sk->sk_err != ERESTARTSYS) {
-			error = -new_vcc->sk->sk_err;
+		if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
+			error = -sk_atm(new_vcc)->sk_err;
 			goto out;
 		}
 	}
@@ -436,19 +436,20 @@ static int svc_getname(struct socket *so
 
 int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
 {
+	struct sock *sk = sk_atm(vcc);
 	DEFINE_WAIT(wait);
 
 	set_bit(ATM_VF_WAITING, &vcc->flags);
-	prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+	prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
 	while (test_bit(ATM_VF_WAITING, &vcc->flags) &&
 	       !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
 		schedule();
-		prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
 	}
-	finish_wait(vcc->sk->sk_sleep, &wait);
+	finish_wait(sk->sk_sleep, &wait);
 	if (!sigd) return -EUNATCH;
-	return -vcc->sk->sk_err;
+	return -sk->sk_err;
 }
 
 
@@ -533,28 +534,29 @@ static int svc_addparty(struct socket *s
 			int sockaddr_len, int flags)
 {
 	DEFINE_WAIT(wait);
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc = ATM_SD(sock);
 	int error;
 
-	lock_sock(vcc->sk);
+	lock_sock(sk);
 	set_bit(ATM_VF_WAITING, &vcc->flags);
-	prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 	sigd_enq(vcc, as_addparty, NULL, NULL,
 	         (struct sockaddr_atmsvc *) sockaddr);
 	if (flags & O_NONBLOCK) {
-		finish_wait(vcc->sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
 		error = -EINPROGRESS;
 		goto out;
 	}
 	DPRINTK("svc_addparty added wait queue\n");
 	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
 		schedule();
-		prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 	}
-	finish_wait(vcc->sk->sk_sleep, &wait);
-	error = xchg(&vcc->sk->sk_err_soft, 0);
+	finish_wait(sk->sk_sleep, &wait);
+	error = xchg(&sk->sk_err_soft, 0);
 out:
-	release_sock(vcc->sk);
+	release_sock(sk);
 	return error;
 }
 
@@ -562,25 +564,26 @@ out:
 static int svc_dropparty(struct socket *sock, int ep_ref)
 {
 	DEFINE_WAIT(wait);
+	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc = ATM_SD(sock);
 	int error;
 
-	lock_sock(vcc->sk);
+	lock_sock(sk);
 	set_bit(ATM_VF_WAITING, &vcc->flags);
-	prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 	sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
 	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
 		schedule();
-		prepare_to_wait(vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 	}
-	finish_wait(vcc->sk->sk_sleep, &wait);
+	finish_wait(sk->sk_sleep, &wait);
 	if (!sigd) {
 		error = -EUNATCH;
 		goto out;
 	}
-	error = xchg(&vcc->sk->sk_err_soft, 0);
+	error = xchg(&sk->sk_err_soft, 0);
 out:
-	release_sock(vcc->sk);
+	release_sock(sk);
 	return error;
 }
 
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -180,8 +180,7 @@ struct sock *ax25_get_socket(ax25_addres
 		    !ax25cmp(&s->dest_addr, dest_addr) &&
 		    s->sk->sk_type == type) {
 			sk = s->sk;
-			/* XXX Sleeps with spinlock held, use refcounts instead. XXX */
-			lock_sock(sk);
+			sock_hold(sk);
 			break;
 		}
 	}
@@ -307,9 +306,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
 
 			kfree_skb(skb);
 		}
-		while ((skb = skb_dequeue(&ax25->sk->sk_write_queue)) != NULL) {
-			kfree_skb(skb);
-		}
+		skb_queue_purge(&ax25->sk->sk_write_queue);
 	}
 
 	if (ax25->sk != NULL) {
@@ -763,6 +760,16 @@ out:
 	return res;
 }
 
+/*
+ * XXX: when creating ax25_sock we should update the .obj_size setting
+ * below.
+ */
+static struct proto ax25_proto = {
+	.name	  = "AX25",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct sock),
+};
+
 static int ax25_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -813,7 +820,7 @@ static int ax25_create(struct socket *so
 		return -ESOCKTNOSUPPORT;
 	}
 
-	if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL)
+	if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL)
 		return -ENOMEM;
 
 	ax25 = sk->sk_protinfo = ax25_create_cb();
@@ -823,7 +830,6 @@ static int ax25_create(struct socket *so
 	}
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sk->sk_destruct = ax25_free_sock;
 	sock->ops    = &ax25_proto_ops;
@@ -839,7 +845,7 @@ struct sock *ax25_make_new(struct sock *
 	struct sock *sk;
 	ax25_cb *ax25, *oax25;
 
-	if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL)
+	if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL)
 		return NULL;
 
 	if ((ax25 = ax25_create_cb()) == NULL) {
@@ -859,7 +865,6 @@ struct sock *ax25_make_new(struct sock *
 	}
 
 	sock_init_data(NULL, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sk->sk_destruct = ax25_free_sock;
 	sk->sk_type     = osk->sk_type;
@@ -868,10 +873,14 @@ struct sock *ax25_make_new(struct sock *
 	sk->sk_protocol = osk->sk_protocol;
 	sk->sk_rcvbuf   = osk->sk_rcvbuf;
 	sk->sk_sndbuf   = osk->sk_sndbuf;
-	sk->sk_debug    = osk->sk_debug;
 	sk->sk_state    = TCP_ESTABLISHED;
 	sk->sk_sleep    = osk->sk_sleep;
-	sk->sk_zapped   = osk->sk_zapped;
+
+	if (sock_flag(osk, SOCK_DBG))
+		sock_set_flag(sk, SOCK_DBG);
+
+	if (sock_flag(osk, SOCK_ZAPPED))
+		sock_set_flag(sk, SOCK_ZAPPED);
 
 	oax25 = ax25_sk(osk);
 
@@ -1025,7 +1034,7 @@ static int ax25_bind(struct socket *sock
 	lock_sock(sk);
 
 	ax25 = ax25_sk(sk);
-	if (!sk->sk_zapped) {
+	if (!sock_flag(sk, SOCK_ZAPPED)) {
 		err = -EINVAL;
 		goto out;
 	}
@@ -1059,7 +1068,7 @@ static int ax25_bind(struct socket *sock
 
 done:
 	ax25_cb_add(ax25);
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 
 out:
 	release_sock(sk);
@@ -1172,7 +1181,7 @@ static int ax25_connect(struct socket *s
 	 *	the socket is already bound, check to see if the device has
 	 *	been filled in, error if it hasn't.
 	 */
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		/* check if we can remove this feature. It is broken. */
 		printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
 			current->comm);
@@ -1420,7 +1429,7 @@ static int ax25_sendmsg(struct kiocb *io
 	lock_sock(sk);
 	ax25 = ax25_sk(sk);
 
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		err = -EADDRNOTAVAIL;
 		goto out;
 	}
@@ -1578,9 +1587,7 @@ static int ax25_sendmsg(struct kiocb *io
 	*asmptr = AX25_UI;
 
 	/* Datagram frames go straight out of the door as UI */
-	skb->dev = ax25->ax25_dev->dev;
-
-	ax25_queue_xmit(skb);
+	ax25_queue_xmit(skb, ax25->ax25_dev->dev);
 
 	err = len;
 
@@ -1997,6 +2004,11 @@ EXPORT_SYMBOL(ax25_display_timer);
 
 static int __init ax25_init(void)
 {
+	int rc = proto_register(&ax25_proto, 0);
+
+	if (rc != 0)
+		goto out;
+
 	sock_register(&ax25_family_ops);
 	dev_add_pack(&ax25_packet_type);
 	register_netdevice_notifier(&ax25_dev_notifier);
@@ -2005,8 +2017,8 @@ static int __init ax25_init(void)
 	proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops);
 	proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops);
 	proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops);
-
-	return 0;
+out:
+	return rc;
 }
 module_init(ax25_init);
 
@@ -2031,5 +2043,6 @@ static void __exit ax25_exit(void)
 	dev_remove_pack(&ax25_packet_type);
 
 	sock_unregister(PF_AX25);
+	proto_unregister(&ax25_proto);
 }
 module_exit(ax25_exit);
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
--- a/net/ax25/ax25_ds_subr.c
+++ b/net/ax25/ax25_ds_subr.c
@@ -143,8 +143,7 @@ static void ax25_kiss_cmd(ax25_dev *ax25
 	*p++ = cmd;
 	*p++ = param;
 
-	skb->dev      = ax25_dev->dev;
-	skb->protocol = htons(ETH_P_AX25);
+	skb->protocol = ax25_type_trans(skb, ax25_dev->dev);
 
 	dev_queue_xmit(skb);
 }
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -275,6 +275,7 @@ static int ax25_rcv(struct sk_buff *skb,
 			/* Now find a suitable dgram socket */
 			sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
 			if (sk != NULL) {
+				bh_lock_sock(sk);
 				if (atomic_read(&sk->sk_rmem_alloc) >=
 				    sk->sk_rcvbuf) {
 					kfree_skb(skb);
@@ -286,7 +287,8 @@ static int ax25_rcv(struct sk_buff *skb,
 					if (sock_queue_rcv_skb(sk, skb) != 0)
 						kfree_skb(skb);
 				}
-				release_sock(sk);
+				bh_unlock_sock(sk);
+				sock_put(sk);
 			} else {
 				kfree_skb(skb);
 			}
@@ -356,7 +358,7 @@ static int ax25_rcv(struct sk_buff *skb,
 
 	if (sk != NULL) {
 		bh_lock_sock(sk);
-		if (sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
+		if (sk_acceptq_is_full(sk) ||
 		    (make = ax25_make_new(sk, ax25_dev)) == NULL) {
 			if (mine)
 				ax25_return_dm(dev, &src, &dest, &dp);
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -199,9 +199,7 @@ int ax25_rebuild_header(struct sk_buff *
 		skb = ourskb;
 	}
 
-	skb->dev      = dev;
-
-	ax25_queue_xmit(skb);
+	ax25_queue_xmit(skb, dev);
 
 put:
 	ax25_put_route(route);
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -340,21 +340,18 @@ void ax25_transmit_buffer(ax25_cb *ax25,
 
 	ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-	skb->dev = ax25->ax25_dev->dev;
-
-	ax25_queue_xmit(skb);
+	ax25_queue_xmit(skb, ax25->ax25_dev->dev);
 }
 
 /*
  *	A small shim to dev_queue_xmit to add the KISS control byte, and do
  *	any packet forwarding in operation.
  */
-void ax25_queue_xmit(struct sk_buff *skb)
+void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned char *ptr;
 
-	skb->protocol = htons(ETH_P_AX25);
-	skb->dev      = ax25_fwd_dev(skb->dev);
+	skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev));
 
 	ptr  = skb_push(skb, 1);
 	*ptr = 0x00;			/* KISS */
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -455,7 +455,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25
 
 	if (ax25->sk != NULL) {
 		bh_lock_sock(ax25->sk);
-		ax25->sk->sk_zapped = 0;
+		sock_reset_flag(ax25->sk, SOCK_ZAPPED);
 		bh_unlock_sock(ax25->sk);
 	}
 
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -220,9 +220,7 @@ void ax25_return_dm(struct net_device *d
 	dptr  = skb_push(skb, ax25_addr_size(digi));
 	dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
 
-	skb->dev      = dev;
-
-	ax25_queue_xmit(skb);
+	ax25_queue_xmit(skb, dev);
 }
 
 /*
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -31,7 +31,6 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
@@ -60,11 +59,9 @@ EXPORT_SYMBOL(proc_bt);
 #define BT_MAX_PROTO	8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
 
-static kmem_cache_t *bt_sock_cache;
-
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
-	if (proto >= BT_MAX_PROTO)
+	if (proto < 0 || proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
 	if (bt_proto[proto])
@@ -77,7 +74,7 @@ EXPORT_SYMBOL(bt_sock_register);
 
 int bt_sock_unregister(int proto)
 {
-	if (proto >= BT_MAX_PROTO)
+	if (proto < 0 || proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
 	if (!bt_proto[proto])
@@ -92,7 +89,7 @@ static int bt_sock_create(struct socket 
 {
 	int err = 0;
 
-	if (proto >= BT_MAX_PROTO)
+	if (proto < 0 || proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
 #if defined(CONFIG_KMOD)
@@ -108,36 +105,6 @@ static int bt_sock_create(struct socket 
 	return err; 
 }
 
-struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio)
-{
-	struct sock *sk;
-	void *pi;
-
-	sk = sk_alloc(PF_BLUETOOTH, prio, sizeof(struct bt_sock), bt_sock_cache);
-	if (!sk)
-		return NULL;
-
-	if (pi_size) {
-		pi = kmalloc(pi_size, prio);
-		if (!pi) {
-			sk_free(sk);
-			return NULL;
-		}
-		memset(pi, 0, pi_size);
-		sk->sk_protinfo = pi;
-	}
-
-	sock_init_data(sock, sk);
-	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
-	sk->sk_zapped   = 0;
-	sk->sk_protocol = proto;
-	sk->sk_state    = BT_OPEN;
-
-	return sk;
-}
-EXPORT_SYMBOL(bt_sock_alloc);
-
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
 {
 	write_lock_bh(&l->lock);
@@ -355,16 +322,6 @@ static int __init bt_init(void)
 	if (proc_bt)
 		proc_bt->owner = THIS_MODULE;
 
-	/* Init socket cache */
-	bt_sock_cache = kmem_cache_create("bt_sock",
-			sizeof(struct bt_sock), 0,
-			SLAB_HWCACHE_ALIGN, NULL, NULL);
-
-	if (!bt_sock_cache) {
-		BT_ERR("Socket cache creation failed");
-		return -ENOMEM;
-	}
-
 	sock_register(&bt_sock_family_ops);
 
 	BT_INFO("HCI device and connection manager initialized");
@@ -383,7 +340,6 @@ static void __exit bt_exit(void)
 	bt_sysfs_cleanup();
 
 	sock_unregister(PF_BLUETOOTH);
-	kmem_cache_destroy(bt_sock_cache);
 
 	remove_proc_entry("bluetooth", NULL);
 }
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -34,7 +34,6 @@
 #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>
@@ -167,6 +166,12 @@ static struct proto_ops bnep_sock_ops = 
 	.mmap       = sock_no_mmap
 };
 
+static struct proto bnep_proto = {
+	.name		= "BNEP",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct bt_sock)
+};
+
 static int bnep_sock_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -176,17 +181,21 @@ static int bnep_sock_create(struct socke
 	if (sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
-	if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
+	sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1);
+	if (!sk)
 		return -ENOMEM;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
 	sock->ops = &bnep_sock_ops;
 
-	sock->state  = SS_UNCONNECTED;
+	sock->state = SS_UNCONNECTED;
+
+	sock_reset_flag(sk, SOCK_ZAPPED);
 
-	sk->sk_destruct = NULL;
 	sk->sk_protocol = protocol;
+	sk->sk_state	= BT_OPEN;
+
 	return 0;
 }
 
@@ -198,13 +207,30 @@ static struct net_proto_family bnep_sock
 
 int __init bnep_sock_init(void)
 {
-	bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
+	int err;
+
+	err = proto_register(&bnep_proto, 0);
+	if (err < 0)
+		return err;
+
+	err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
+	if (err < 0)
+		goto error;
+
 	return 0;
+
+error:
+	BT_ERR("Can't register BNEP socket");
+	proto_unregister(&bnep_proto);
+	return err;
 }
 
 int __exit bnep_sock_cleanup(void)
 {
-	if (bt_sock_unregister(BTPROTO_BNEP))
+	if (bt_sock_unregister(BTPROTO_BNEP) < 0)
 		BT_ERR("Can't unregister BNEP socket");
+
+	proto_unregister(&bnep_proto);
+
 	return 0;
 }
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -26,7 +26,6 @@
 #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>
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -26,7 +26,6 @@
 #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>
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -26,7 +26,6 @@
 #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>
@@ -158,6 +157,12 @@ static struct proto_ops cmtp_sock_ops = 
 	.mmap		= sock_no_mmap
 };
 
+static struct proto cmtp_proto = {
+	.name		= "CMTP",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct bt_sock)
+};
+
 static int cmtp_sock_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -167,17 +172,20 @@ static int cmtp_sock_create(struct socke
 	if (sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
-	if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
+	sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1);
+	if (!sk)
 		return -ENOMEM;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
 	sock->ops = &cmtp_sock_ops;
 
 	sock->state = SS_UNCONNECTED;
 
-	sk->sk_destruct = NULL;
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
 	sk->sk_protocol = protocol;
+	sk->sk_state    = BT_OPEN;
 
 	return 0;
 }
@@ -190,13 +198,28 @@ static struct net_proto_family cmtp_sock
 
 int cmtp_init_sockets(void)
 {
-	bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
+	int err;
+
+	err = proto_register(&cmtp_proto, 0);
+	if (err < 0)
+		return err;
+
+	err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
+	if (err < 0)
+		goto error;
 
 	return 0;
+
+error:
+	BT_ERR("Can't register CMTP socket");
+	proto_unregister(&cmtp_proto);
+	return err;
 }
 
 void cmtp_cleanup_sockets(void)
 {
-	if (bt_sock_unregister(BTPROTO_CMTP))
+	if (bt_sock_unregister(BTPROTO_CMTP) < 0)
 		BT_ERR("Can't unregister CMTP socket");
+
+	proto_unregister(&cmtp_proto);
 }
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -30,7 +30,6 @@
 #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>
@@ -348,6 +347,24 @@ int hci_conn_change_link_key(struct hci_
 }
 EXPORT_SYMBOL(hci_conn_change_link_key);
 
+/* Switch role */
+int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
+{
+	BT_DBG("conn %p", conn);
+
+	if (!role && conn->link_mode & HCI_LM_MASTER)
+		return 1;
+
+	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
+		struct hci_cp_switch_role cp;
+		bacpy(&cp.bdaddr, &conn->dst);
+		cp.role = role;
+		hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(hci_conn_switch_role);
+
 /* Drop all connection on the device */
 void hci_conn_hash_flush(struct hci_dev *hdev)
 {
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -31,7 +31,6 @@
 #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>
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -30,7 +30,6 @@
 #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>
@@ -718,17 +717,20 @@ static inline void hci_role_change_evt(s
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
 
-	if (ev->status)
-		return;
-
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (conn) {
-		if (ev->role)
-			conn->link_mode &= ~HCI_LM_MASTER;
-		else
-			conn->link_mode |= HCI_LM_MASTER;
+		if (!ev->status) {
+			if (ev->role)
+				conn->link_mode &= ~HCI_LM_MASTER;
+			else
+				conn->link_mode |= HCI_LM_MASTER;
+		}
+
+		clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+
+		hci_role_switch_cfm(conn, ev->status, ev->role);
 	}
 
 	hci_dev_unlock(hdev);
@@ -749,6 +751,7 @@ static inline void hci_auth_complete_evt
 	if (conn) {
 		if (!ev->status)
 			conn->link_mode |= HCI_LM_AUTH;
+
 		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 
 		hci_auth_cfm(conn, ev->status);
@@ -790,6 +793,7 @@ static inline void hci_encrypt_change_ev
 			else
 				conn->link_mode &= ~HCI_LM_ENCRYPT;
 		}
+
 		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
 
 		hci_encrypt_cfm(conn, ev->status, ev->encrypt);
@@ -801,6 +805,25 @@ static inline void hci_encrypt_change_ev
 /* Change Connection Link Key Complete */
 static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+	struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+	__u16 handle = __le16_to_cpu(ev->handle);
+
+	BT_DBG("%s status %d", hdev->name, ev->status);
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, handle);
+	if (conn) {
+		if (!ev->status)
+			conn->link_mode |= HCI_LM_SECURE;
+
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+		hci_key_change_cfm(conn, ev->status);
+	}
+
+	hci_dev_unlock(hdev);
 }
 
 /* Pin Code Request*/
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -30,7 +30,6 @@
 #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>
@@ -590,6 +589,12 @@ static struct proto_ops hci_sock_ops = {
 	.mmap		= sock_no_mmap
 };
 
+static struct proto hci_sk_proto = {
+	.name		= "HCI",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct hci_pinfo)
+};
+
 static int hci_sock_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -601,11 +606,15 @@ static int hci_sock_create(struct socket
 
 	sock->ops = &hci_sock_ops;
 
-	sk = bt_sock_alloc(sock, protocol, sizeof(struct hci_pinfo), GFP_KERNEL);
+	sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
 	if (!sk)
 		return -ENOMEM;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
+
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
+	sk->sk_protocol = protocol;
 
 	sock->state = SS_UNCONNECTED;
 	sk->sk_state = BT_OPEN;
@@ -662,23 +671,36 @@ static struct notifier_block hci_sock_nb
 
 int __init hci_sock_init(void)
 {
-	if (bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
-		BT_ERR("HCI socket registration failed");
-		return -EPROTO;
-	}
+	int err;
+
+	err = proto_register(&hci_sk_proto, 0);
+	if (err < 0)
+		return err;
+
+	err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
+	if (err < 0)
+		goto error;
 
 	hci_register_notifier(&hci_sock_nblock);
 
 	BT_INFO("HCI socket layer initialized");
 
 	return 0;
+
+error:
+	BT_ERR("HCI socket registration failed");
+	proto_unregister(&hci_sk_proto);
+	return err;
 }
 
 int __exit hci_sock_cleanup(void)
 {
-	if (bt_sock_unregister(BTPROTO_HCI))
+	if (bt_sock_unregister(BTPROTO_HCI) < 0)
 		BT_ERR("HCI socket unregistration failed");
 
 	hci_unregister_notifier(&hci_sock_nblock);
+
+	proto_unregister(&hci_sk_proto);
+
 	return 0;
 }
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -55,7 +55,7 @@ static ssize_t show_inquiry_cache(struct
 				batostr(&bdaddr),
 				data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode,
 				data->dev_class[2], data->dev_class[1], data->dev_class[0],
-				data->clock_offset, data->rssi, e->timestamp);
+				__le16_to_cpu(data->clock_offset), data->rssi, e->timestamp);
 	}
 
 	hci_dev_unlock_bh(hdev);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -26,7 +26,6 @@
 #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>
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -26,7 +26,6 @@
 #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>
@@ -164,6 +163,12 @@ static struct proto_ops hidp_sock_ops = 
 	.mmap		= sock_no_mmap
 };
 
+static struct proto hidp_proto = {
+	.name		= "HIDP",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct bt_sock)
+};
+
 static int hidp_sock_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -173,17 +178,20 @@ static int hidp_sock_create(struct socke
 	if (sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
-	if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
+	sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
+	if (!sk)
 		return -ENOMEM;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
 	sock->ops = &hidp_sock_ops;
 
 	sock->state = SS_UNCONNECTED;
 
-	sk->sk_destruct = NULL;
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
 	sk->sk_protocol = protocol;
+	sk->sk_state	= BT_OPEN;
 
 	return 0;
 }
@@ -198,10 +206,19 @@ int __init hidp_init_sockets(void)
 {
 	int err;
 
+	err = proto_register(&hidp_proto, 0);
+	if (err < 0)
+		return err;
+
 	err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
 	if (err < 0)
-		BT_ERR("Can't register HIDP socket");
+		goto error;
 
+	return 0;
+
+error:
+	BT_ERR("Can't register HIDP socket");
+	proto_unregister(&hidp_proto);
 	return err;
 }
 
@@ -209,4 +226,6 @@ void __exit hidp_cleanup_sockets(void)
 {
 	if (bt_sock_unregister(BTPROTO_HIDP) < 0)
 		BT_ERR("Can't unregister HIDP socket");
+
+	proto_unregister(&hidp_proto);
 }
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -30,7 +30,6 @@
 #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>
@@ -264,9 +263,6 @@ static void l2cap_sock_destruct(struct s
 
 	skb_queue_purge(&sk->sk_receive_queue);
 	skb_queue_purge(&sk->sk_write_queue);
-
-	if (sk->sk_protinfo)
-		kfree(sk->sk_protinfo);
 }
 
 static void l2cap_sock_cleanup_listen(struct sock *parent)
@@ -280,7 +276,7 @@ static void l2cap_sock_cleanup_listen(st
 		l2cap_sock_close(sk);
 
 	parent->sk_state  = BT_CLOSED;
-	parent->sk_zapped = 1;
+	sock_set_flag(parent, SOCK_ZAPPED);
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -288,7 +284,7 @@ static void l2cap_sock_cleanup_listen(st
  */
 static void l2cap_sock_kill(struct sock *sk)
 {
-	if (!sk->sk_zapped || sk->sk_socket)
+	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
 		return;
 
 	BT_DBG("sk %p state %d", sk, sk->sk_state);
@@ -333,7 +329,7 @@ static void __l2cap_sock_close(struct so
 		break;
 
 	default:
-		sk->sk_zapped = 1;
+		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
 	}
 }
@@ -370,19 +366,28 @@ static void l2cap_sock_init(struct sock 
 	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 }
 
+static struct proto l2cap_proto = {
+	.name		= "L2CAP",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct l2cap_pinfo)
+};
+
 static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
 {
 	struct sock *sk;
 
-	sk = bt_sock_alloc(sock, proto, sizeof(struct l2cap_pinfo), prio);
+	sk = sk_alloc(PF_BLUETOOTH, prio, &l2cap_proto, 1);
 	if (!sk)
 		return NULL;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
 	sk->sk_destruct = l2cap_sock_destruct;
 	sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
 
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
 	sk->sk_protocol = proto;
 	sk->sk_state    = BT_OPEN;
 
@@ -1062,7 +1067,7 @@ static void l2cap_chan_del(struct sock *
 	}
 
 	sk->sk_state  = BT_CLOSED;
-	sk->sk_zapped = 1;
+	sock_set_flag(sk, SOCK_ZAPPED);
 
 	if (err)
 		sk->sk_err = err;
@@ -1410,7 +1415,7 @@ static inline int l2cap_connect_req(stru
 	result = L2CAP_CR_NO_MEM;
 
 	/* Check for backlog size */
-	if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) {
+	if (sk_acceptq_is_full(parent)) {
 		BT_DBG("backlog full %d", parent->sk_ack_backlog); 
 		goto response;
 	}
@@ -1424,7 +1429,7 @@ static inline int l2cap_connect_req(stru
 	/* Check if we already have channel with that dcid */
 	if (__l2cap_get_chan_by_dcid(list, scid)) {
 		write_unlock(&list->lock);
-		sk->sk_zapped = 1;
+		sock_set_flag(sk, SOCK_ZAPPED);
 		l2cap_sock_kill(sk);
 		goto response;
 	}
@@ -2261,15 +2266,22 @@ static struct hci_proto l2cap_hci_proto 
 static int __init l2cap_init(void)
 {
 	int err;
+	
+	err = proto_register(&l2cap_proto, 0);
+	if (err < 0)
+		return err;
 
-	if ((err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
+	err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
+	if (err < 0) {
 		BT_ERR("L2CAP socket registration failed");
-		return err;
+		goto error;
 	}
 
-	if ((err = hci_register_proto(&l2cap_hci_proto))) {
+	err = hci_register_proto(&l2cap_hci_proto);
+	if (err < 0) {
 		BT_ERR("L2CAP protocol registration failed");
-		return err;
+		bt_sock_unregister(BTPROTO_L2CAP);
+		goto error;
 	}
 
 	l2cap_proc_init();
@@ -2278,18 +2290,23 @@ static int __init l2cap_init(void)
 	BT_INFO("L2CAP socket layer initialized");
 
 	return 0;
+
+error:
+	proto_unregister(&l2cap_proto);
+	return err;
 }
 
 static void __exit l2cap_exit(void)
 {
 	l2cap_proc_cleanup();
 
-	/* Unregister socket and protocol */
-	if (bt_sock_unregister(BTPROTO_L2CAP))
+	if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
 		BT_ERR("L2CAP socket unregistration failed");
 
-	if (hci_unregister_proto(&l2cap_hci_proto))
+	if (hci_unregister_proto(&l2cap_hci_proto) < 0)
 		BT_ERR("L2CAP protocol unregistration failed");
+
+	proto_unregister(&l2cap_proto);
 }
 
 void l2cap_load(void)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -68,7 +68,7 @@ static DECLARE_MUTEX(rfcomm_sem);
 #define rfcomm_lock()	down(&rfcomm_sem);
 #define rfcomm_unlock()	up(&rfcomm_sem);
 
-unsigned long rfcomm_event;
+static unsigned long rfcomm_event;
 
 static LIST_HEAD(session_list);
 static atomic_t terminate, running;
@@ -389,6 +389,8 @@ static int __rfcomm_dlc_close(struct rfc
 		rfcomm_dlc_unlock(d);
 
 		skb_queue_purge(&d->tx_queue);
+		rfcomm_session_put(s);
+
 		rfcomm_dlc_unlink(d);
 	}
 
@@ -598,6 +600,8 @@ static struct rfcomm_session *rfcomm_ses
 		goto failed;
 	}
 
+	rfcomm_session_hold(s);
+
 	s->initiator = 1;
 
 	bacpy(&addr.l2_bdaddr, dst);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -33,7 +33,6 @@
 #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>
@@ -105,7 +104,7 @@ static void rfcomm_sk_state_change(struc
 	parent = bt_sk(sk)->parent;
 	if (parent) {
 		if (d->state == BT_CLOSED) {
-			sk->sk_zapped = 1;
+			sock_set_flag(sk, SOCK_ZAPPED);
 			bt_accept_unlink(sk);
 		}
 		parent->sk_data_ready(parent, 0);
@@ -117,7 +116,7 @@ static void rfcomm_sk_state_change(struc
 
 	bh_unlock_sock(sk);
 
-	if (parent && sk->sk_zapped) {
+	if (parent && sock_flag(sk, SOCK_ZAPPED)) {
 		/* We have to drop DLC lock here, otherwise
 		 * rfcomm_sock_destruct() will dead lock. */
 		rfcomm_dlc_unlock(d);
@@ -196,9 +195,6 @@ static void rfcomm_sock_destruct(struct 
 	rfcomm_dlc_unlock(d);
 
 	rfcomm_dlc_put(d);
-
-	if (sk->sk_protinfo)
-		kfree(sk->sk_protinfo);
 }
 
 static void rfcomm_sock_cleanup_listen(struct sock *parent)
@@ -214,7 +210,7 @@ static void rfcomm_sock_cleanup_listen(s
 	}
 
 	parent->sk_state  = BT_CLOSED;
-	parent->sk_zapped = 1;
+	sock_set_flag(parent, SOCK_ZAPPED);
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -222,7 +218,7 @@ static void rfcomm_sock_cleanup_listen(s
  */
 static void rfcomm_sock_kill(struct sock *sk)
 {
-	if (!sk->sk_zapped || sk->sk_socket)
+	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
 		return;
 
 	BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
@@ -251,7 +247,7 @@ static void __rfcomm_sock_close(struct s
 		rfcomm_dlc_close(d, 0);
 
 	default:
-		sk->sk_zapped = 1;
+		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
 	}
 }
@@ -282,22 +278,30 @@ static void rfcomm_sock_init(struct sock
 	pi->dlc->link_mode = pi->link_mode;
 }
 
+static struct proto rfcomm_proto = {
+	.name		= "RFCOMM",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct rfcomm_pinfo)
+};
+
 static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
 {
 	struct rfcomm_dlc *d;
 	struct sock *sk;
 
-	sk = bt_sock_alloc(sock, BTPROTO_RFCOMM, sizeof(struct rfcomm_pinfo), prio);
+	sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1);
 	if (!sk)
 		return NULL;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
 	d = rfcomm_dlc_alloc(prio);
 	if (!d) {
 		sk_free(sk);
 		return NULL;
 	}
+
 	d->data_ready   = rfcomm_sk_data_ready;
 	d->state_change = rfcomm_sk_state_change;
 
@@ -310,8 +314,10 @@ static struct sock *rfcomm_sock_alloc(st
 	sk->sk_sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
 	sk->sk_rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
 
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
 	sk->sk_protocol = proto;
-	sk->sk_state    = BT_OPEN;
+	sk->sk_state	= BT_OPEN;
 
 	bt_sock_link(&rfcomm_sk_list, sk);
 
@@ -832,7 +838,7 @@ int rfcomm_connect_ind(struct rfcomm_ses
 		return 0;
 
 	/* Check for backlog size */
-	if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) {
+	if (sk_acceptq_is_full(parent)) {
 		BT_DBG("backlog full %d", parent->sk_ack_backlog); 
 		goto done;
 	}
@@ -972,24 +978,32 @@ int  __init rfcomm_init_sockets(void)
 {
 	int err;
 
-	if ((err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
-		BT_ERR("RFCOMM socket layer registration failed. %d", err);
+	err = proto_register(&rfcomm_proto, 0);
+	if (err < 0)
 		return err;
-	}
+
+	err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
+	if (err < 0)
+		goto error;
 
 	rfcomm_sock_proc_init();
 
 	BT_INFO("RFCOMM socket layer initialized");
+
 	return 0;
+
+error:
+	BT_ERR("RFCOMM socket layer registration failed");
+	proto_unregister(&rfcomm_proto);
+	return err;
 }
 
 void __exit rfcomm_cleanup_sockets(void)
 {
-	int err;
-
 	rfcomm_sock_proc_cleanup();
 
-	/* Unregister socket, protocol and notifier */
-	if ((err = bt_sock_unregister(BTPROTO_RFCOMM)))
-		BT_ERR("RFCOMM socket layer unregistration failed. %d", err);
+	if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
+		BT_ERR("RFCOMM socket layer unregistration failed");
+
+	proto_unregister(&rfcomm_proto);
 }
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -30,7 +30,6 @@
 #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>
@@ -334,9 +333,6 @@ static void sco_sock_destruct(struct soc
 
 	skb_queue_purge(&sk->sk_receive_queue);
 	skb_queue_purge(&sk->sk_write_queue);
-
-	if (sk->sk_protinfo)
-		kfree(sk->sk_protinfo);
 }
 
 static void sco_sock_cleanup_listen(struct sock *parent)
@@ -352,7 +348,7 @@ static void sco_sock_cleanup_listen(stru
 	}
 
 	parent->sk_state  = BT_CLOSED;
-	parent->sk_zapped = 1;
+	sock_set_flag(parent, SOCK_ZAPPED);
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -360,7 +356,7 @@ static void sco_sock_cleanup_listen(stru
  */
 static void sco_sock_kill(struct sock *sk)
 {
-	if (!sk->sk_zapped || sk->sk_socket)
+	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
 		return;
 
 	BT_DBG("sk %p state %d", sk, sk->sk_state);
@@ -399,7 +395,7 @@ static void sco_sock_close(struct sock *
 		break;
 
 	default:
-		sk->sk_zapped = 1;
+		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
 	};
 
@@ -416,18 +412,29 @@ static void sco_sock_init(struct sock *s
 		sk->sk_type = parent->sk_type;
 }
 
+static struct proto sco_proto = {
+	.name		= "SCO",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct sco_pinfo)
+};
+
 static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
 {
 	struct sock *sk;
 
-	sk = bt_sock_alloc(sock, proto, sizeof(struct sco_pinfo), prio);
+	sk = sk_alloc(PF_BLUETOOTH, prio, &sco_proto, 1);
 	if (!sk)
 		return NULL;
 
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
 	sk->sk_destruct = sco_sock_destruct;
 	sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
+
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
+	sk->sk_protocol = proto;
 	sk->sk_state    = BT_OPEN;
 
 	sco_sock_init_timer(sk);
@@ -778,7 +785,7 @@ static void sco_chan_del(struct sock *sk
 	sk->sk_err   = err;
 	sk->sk_state_change(sk);
 
-	sk->sk_zapped = 1;
+	sock_set_flag(sk, SOCK_ZAPPED);
 }
 
 static void sco_conn_ready(struct sco_conn *conn)
@@ -1011,14 +1018,21 @@ static int __init sco_init(void)
 {
 	int err;
 
-	if ((err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
-		BT_ERR("SCO socket registration failed");
+	err = proto_register(&sco_proto, 0);
+	if (err < 0)
 		return err;
+
+	err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
+	if (err < 0) {
+		BT_ERR("SCO socket registration failed");
+		goto error;
 	}
 
-	if ((err = hci_register_proto(&sco_hci_proto))) {
+	err = hci_register_proto(&sco_hci_proto);
+	if (err < 0) {
 		BT_ERR("SCO protocol registration failed");
-		return err;
+		bt_sock_unregister(BTPROTO_SCO);
+		goto error;
 	}
 
 	sco_proc_init();
@@ -1027,20 +1041,23 @@ static int __init sco_init(void)
 	BT_INFO("SCO socket layer initialized");
 
 	return 0;
+
+error:
+	proto_unregister(&sco_proto);
+	return err;
 }
 
 static void __exit sco_exit(void)
 {
-	int err;
-
 	sco_proc_cleanup();
 
-	/* Unregister socket, protocol and notifier */
-	if ((err = bt_sock_unregister(BTPROTO_SCO)))
-		BT_ERR("SCO socket unregistration failed. %d", err);
+	if (bt_sock_unregister(BTPROTO_SCO) < 0)
+		BT_ERR("SCO socket unregistration failed");
+
+	if (hci_unregister_proto(&sco_hci_proto) < 0)
+		BT_ERR("SCO protocol unregistration failed");
 
-	if ((err = hci_unregister_proto(&sco_hci_proto)))
-		BT_ERR("SCO protocol unregistration failed. %d", err);
+	proto_unregister(&sco_proto);
 }
 
 module_init(sco_init);
diff --git a/net/bridge/br.c b/net/bridge/br.c
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -16,17 +16,12 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/miscdevice.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 
 #include "br_private.h"
 
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-#include "../atm/lec.h"
-#endif
-
 int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
 
 static int __init br_init(void)
@@ -40,10 +35,9 @@ static int __init br_init(void)
 	brioctl_set(br_ioctl_deviceless_stub);
 	br_handle_frame_hook = br_handle_frame;
 
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_get_hook = br_fdb_get;
 	br_fdb_put_hook = br_fdb_put;
-#endif
+
 	register_netdevice_notifier(&br_device_notifier);
 
 	return 0;
@@ -61,10 +55,8 @@ static void __exit br_deinit(void)
 
 	synchronize_net();
 
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_get_hook = NULL;
 	br_fdb_put_hook = NULL;
-#endif
 
 	br_handle_frame_hook = NULL;
 	br_fdb_fini();
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -21,10 +21,7 @@
 
 static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
 {
-	struct net_bridge *br;
-
-	br = dev->priv;
-
+	struct net_bridge *br = netdev_priv(dev);
 	return &br->statistics;
 }
 
@@ -54,9 +51,11 @@ int br_dev_xmit(struct sk_buff *skb, str
 
 static int br_dev_open(struct net_device *dev)
 {
-	netif_start_queue(dev);
+	struct net_bridge *br = netdev_priv(dev);
 
-	br_stp_enable_bridge(dev->priv);
+	br_features_recompute(br);
+	netif_start_queue(dev);
+	br_stp_enable_bridge(br);
 
 	return 0;
 }
@@ -67,7 +66,7 @@ static void br_dev_set_multicast_list(st
 
 static int br_dev_stop(struct net_device *dev)
 {
-	br_stp_disable_bridge(dev->priv);
+	br_stp_disable_bridge(netdev_priv(dev));
 
 	netif_stop_queue(dev);
 
@@ -76,18 +75,13 @@ static int br_dev_stop(struct net_device
 
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
-	if ((new_mtu < 68) || new_mtu > br_min_mtu(dev->priv))
+	if (new_mtu < 68 || new_mtu > br_min_mtu(netdev_priv(dev)))
 		return -EINVAL;
 
 	dev->mtu = new_mtu;
 	return 0;
 }
 
-static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
-{
-	return -1;
-}
-
 void br_dev_setup(struct net_device *dev)
 {
 	memset(dev->dev_addr, 0, ETH_ALEN);
@@ -103,7 +97,6 @@ void br_dev_setup(struct net_device *dev
 	dev->destructor = free_netdev;
 	SET_MODULE_OWNER(dev);
 	dev->stop = br_dev_stop;
-	dev->accept_fastpath = br_dev_accept_fastpath;
 	dev->tx_queue_len = 0;
 	dev->set_mac_address = NULL;
 	dev->priv_flags = IFF_EBRIDGE;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -19,12 +19,13 @@
 #include <linux/times.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/jhash.h>
 #include <asm/atomic.h>
 #include "br_private.h"
 
 static kmem_cache_t *br_fdb_cache;
 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
-		      const unsigned char *addr, int is_local);
+		      const unsigned char *addr);
 
 void __init br_fdb_init(void)
 {
@@ -57,26 +58,12 @@ static __inline__ int has_expired(const 
 
 static __inline__ int br_mac_hash(const unsigned char *mac)
 {
-	unsigned long x;
-
-	x = mac[0];
-	x = (x << 2) ^ mac[1];
-	x = (x << 2) ^ mac[2];
-	x = (x << 2) ^ mac[3];
-	x = (x << 2) ^ mac[4];
-	x = (x << 2) ^ mac[5];
-
-	x ^= x >> 8;
-
-	return x & (BR_HASH_SIZE - 1);
+	return jhash(mac, ETH_ALEN, 0) & (BR_HASH_SIZE - 1);
 }
 
 static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)
 {
 	hlist_del_rcu(&f->hlist);
-	if (!f->is_static)
-		list_del(&f->u.age_list);
-
 	br_fdb_put(f);
 }
 
@@ -114,8 +101,7 @@ void br_fdb_changeaddr(struct net_bridge
 	}
  insert:
 	/* insert new address,  may fail if invalid address or dup. */
-	fdb_insert(br, p, newaddr, 1);
-
+	fdb_insert(br, p, newaddr);
 
 	spin_unlock_bh(&br->hash_lock);
 }
@@ -123,30 +109,23 @@ void br_fdb_changeaddr(struct net_bridge
 void br_fdb_cleanup(unsigned long _data)
 {
 	struct net_bridge *br = (struct net_bridge *)_data;
-	struct list_head *l, *n;
-	unsigned long delay;
+	unsigned long delay = hold_time(br);
+	int i;
 
 	spin_lock_bh(&br->hash_lock);
-	delay = hold_time(br);
-
-	list_for_each_safe(l, n, &br->age_list) {
+	for (i = 0; i < BR_HASH_SIZE; i++) {
 		struct net_bridge_fdb_entry *f;
-		unsigned long expires;
-
-		f = list_entry(l, struct net_bridge_fdb_entry, u.age_list);
-		expires = f->ageing_timer + delay;
+		struct hlist_node *h, *n;
 
-		if (time_before_eq(expires, jiffies)) {
-			WARN_ON(f->is_static);
-			pr_debug("expire age %lu jiffies %lu\n",
-				 f->ageing_timer, jiffies);
-			fdb_delete(f);
-		} else {
-			mod_timer(&br->gc_timer, expires);
-			break;
+		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
+			if (!f->is_static && 
+			    time_before_eq(f->ageing_timer + delay, jiffies)) 
+				fdb_delete(f);
 		}
 	}
 	spin_unlock_bh(&br->hash_lock);
+
+	mod_timer(&br->gc_timer, jiffies + HZ/10);
 }
 
 void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
@@ -222,7 +201,7 @@ struct net_bridge_fdb_entry *br_fdb_get(
 static void fdb_rcu_free(struct rcu_head *head)
 {
 	struct net_bridge_fdb_entry *ent
-		= container_of(head, struct net_bridge_fdb_entry, u.rcu);
+		= container_of(head, struct net_bridge_fdb_entry, rcu);
 	kmem_cache_free(br_fdb_cache, ent);
 }
 
@@ -230,7 +209,7 @@ static void fdb_rcu_free(struct rcu_head
 void br_fdb_put(struct net_bridge_fdb_entry *ent)
 {
 	if (atomic_dec_and_test(&ent->use_count))
-		call_rcu(&ent->u.rcu, fdb_rcu_free);
+		call_rcu(&ent->rcu, fdb_rcu_free);
 }
 
 /*
@@ -278,80 +257,112 @@ int br_fdb_fillbuf(struct net_bridge *br
 	return num;
 }
 
-static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
-		  const unsigned char *addr, int is_local)
+static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
+						    const unsigned char *addr)
 {
 	struct hlist_node *h;
 	struct net_bridge_fdb_entry *fdb;
-	int hash = br_mac_hash(addr);
-
-	if (!is_valid_ether_addr(addr))
-		return -EADDRNOTAVAIL;
-
-	hlist_for_each_entry(fdb, h, &br->hash[hash], hlist) {
-		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
-			/* attempt to update an entry for a local interface */
-			if (fdb->is_local) {
-				/* it is okay to have multiple ports with same 
-				 * address, just don't allow to be spoofed.
-				 */
-				if (is_local) 
-					return 0;
-
-				if (net_ratelimit()) 
-					printk(KERN_WARNING "%s: received packet with "
-					       " own address as source address\n",
-					       source->dev->name);
-				return -EEXIST;
-			}
 
-			if (is_local) {
-				printk(KERN_WARNING "%s adding interface with same address "
-				       "as a received packet\n",
-				       source->dev->name);
-				goto update;
-			}
+	hlist_for_each_entry_rcu(fdb, h, head, hlist) {
+		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN))
+			return fdb;
+	}
+	return NULL;
+}
 
-			if (fdb->is_static)
-				return 0;
+static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
+					       struct net_bridge_port *source,
+					       const unsigned char *addr, 
+					       int is_local)
+{
+	struct net_bridge_fdb_entry *fdb;
 
-			/* move to end of age list */
-			list_del(&fdb->u.age_list);
-			goto update;
-		}
+	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
+	if (fdb) {
+		memcpy(fdb->addr.addr, addr, ETH_ALEN);
+		atomic_set(&fdb->use_count, 1);
+		hlist_add_head_rcu(&fdb->hlist, head);
+
+		fdb->dst = source;
+		fdb->is_local = is_local;
+		fdb->is_static = is_local;
+		fdb->ageing_timer = jiffies;
 	}
+	return fdb;
+}
 
-	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
-	if (!fdb)
-		return ENOMEM;
+static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
+		  const unsigned char *addr)
+{
+	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+	struct net_bridge_fdb_entry *fdb;
 
-	memcpy(fdb->addr.addr, addr, ETH_ALEN);
-	atomic_set(&fdb->use_count, 1);
-	hlist_add_head_rcu(&fdb->hlist, &br->hash[hash]);
-
-	if (!timer_pending(&br->gc_timer)) {
-		br->gc_timer.expires = jiffies + hold_time(br);
-		add_timer(&br->gc_timer);
-	}
+	if (!is_valid_ether_addr(addr))
+		return -EINVAL;
+
+	fdb = fdb_find(head, addr);
+	if (fdb) {
+		/* it is okay to have multiple ports with same 
+		 * address, just use the first one.
+		 */
+		if (fdb->is_local) 
+			return 0;
+
+		printk(KERN_WARNING "%s adding interface with same address "
+		       "as a received packet\n",
+		       source->dev->name);
+		fdb_delete(fdb);
+ 	}
 
- update:
-	fdb->dst = source;
-	fdb->is_local = is_local;
-	fdb->is_static = is_local;
-	fdb->ageing_timer = jiffies;
-	if (!is_local) 
-		list_add_tail(&fdb->u.age_list, &br->age_list);
+	if (!fdb_create(head, source, addr, 1))
+		return -ENOMEM;
 
 	return 0;
 }
 
 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
-		  const unsigned char *addr, int is_local)
+		  const unsigned char *addr)
 {
 	int ret;
 
 	spin_lock_bh(&br->hash_lock);
-	ret = fdb_insert(br, source, addr, is_local);
+	ret = fdb_insert(br, source, addr);
 	spin_unlock_bh(&br->hash_lock);
 	return ret;
 }
+
+void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
+		   const unsigned char *addr)
+{
+	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+	struct net_bridge_fdb_entry *fdb;
+
+	/* some users want to always flood. */
+	if (hold_time(br) == 0)
+		return;
+
+	rcu_read_lock();
+	fdb = fdb_find(head, addr);
+	if (likely(fdb)) {
+		/* attempt to update an entry for a local interface */
+		if (unlikely(fdb->is_local)) {
+			if (net_ratelimit()) 
+				printk(KERN_WARNING "%s: received packet with "
+				       " own address as source address\n",
+				       source->dev->name);
+		} else {
+			/* fastpath: update of existing entry */
+			fdb->dst = source;
+			fdb->ageing_timer = jiffies;
+		}
+	} else {
+		spin_lock_bh(&br->hash_lock);
+		if (!fdb_find(head, addr))
+			fdb_create(head, source, addr, 0);
+		/* else  we lose race and someone else inserts
+		 * it first, don't bother updating
+		 */
+		spin_unlock_bh(&br->hash_lock);
+	}
+	rcu_read_unlock();
+}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -314,6 +314,28 @@ int br_min_mtu(const struct net_bridge *
 	return mtu;
 }
 
+/*
+ * Recomputes features using slave's features
+ */
+void br_features_recompute(struct net_bridge *br)
+{
+	struct net_bridge_port *p;
+	unsigned long features, checksum;
+
+	features = NETIF_F_SG | NETIF_F_FRAGLIST 
+		| NETIF_F_HIGHDMA | NETIF_F_TSO;
+	checksum = NETIF_F_IP_CSUM;	/* least commmon subset */
+
+	list_for_each_entry(p, &br->port_list, list) {
+		if (!(p->dev->features 
+		      & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)))
+			checksum = 0;
+		features &= p->dev->features;
+	}
+
+	br->dev->features = features | checksum | NETIF_F_LLTX;
+}
+
 /* called with RTNL */
 int br_add_if(struct net_bridge *br, struct net_device *dev)
 {
@@ -332,7 +354,7 @@ int br_add_if(struct net_bridge *br, str
 	if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev))))
 		return PTR_ERR(p);
 
- 	if ((err = br_fdb_insert(br, p, dev->dev_addr, 1)))
+ 	if ((err = br_fdb_insert(br, p, dev->dev_addr)))
 		destroy_nbp(p);
  
 	else if ((err = br_sysfs_addif(p)))
@@ -368,6 +390,7 @@ int br_del_if(struct net_bridge *br, str
 
 	spin_lock_bh(&br->lock);
 	br_stp_recalculate_bridge_id(br);
+	br_features_recompute(br);
 	spin_unlock_bh(&br->lock);
 
 	return 0;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -26,7 +26,7 @@ static int br_pass_frame_up_finish(struc
 #ifdef CONFIG_NETFILTER_DEBUG
 	skb->nf_debug = 0;
 #endif
-	netif_rx(skb);
+	netif_receive_skb(skb);
 
 	return 0;
 }
@@ -54,6 +54,9 @@ int br_handle_frame_finish(struct sk_buf
 	struct net_bridge_fdb_entry *dst;
 	int passedup = 0;
 
+	/* insert into forwarding database after filtering to avoid spoofing */
+	br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+
 	if (br->dev->flags & IFF_PROMISC) {
 		struct sk_buff *skb2;
 
@@ -105,12 +108,11 @@ int br_handle_frame(struct net_bridge_po
 	if (p->state == BR_STATE_DISABLED)
 		goto err;
 
-	if (eth_hdr(skb)->h_source[0] & 1)
+	if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
 		goto err;
 
-	if (p->state == BR_STATE_LEARNING ||
-	    p->state == BR_STATE_FORWARDING)
-		br_fdb_insert(p->br, p, eth_hdr(skb)->h_source, 0);
+	if (p->state == BR_STATE_LEARNING)
+		br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
 
 	if (p->br->stp_enabled &&
 	    !memcmp(dest, bridge_ula, 5) &&
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -324,6 +324,8 @@ static int old_deviceless(void __user *u
 		int *indices;
 		int ret = 0;
 
+		if (args[2] >= 2048)
+			return -ENOMEM;
 		indices = kmalloc(args[2]*sizeof(int), GFP_KERNEL);
 		if (indices == NULL)
 			return -ENOMEM;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -829,8 +829,7 @@ static unsigned int ip_sabotage_in(unsig
 {
 	if ((*pskb)->nf_bridge &&
 	    !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
-		okfn(*pskb);
-		return NF_STOLEN;
+		return NF_STOP;
 	}
 
 	return NF_ACCEPT;
@@ -891,8 +890,7 @@ static unsigned int ip_sabotage_out(unsi
 		if (out->priv_flags & IFF_802_1Q_VLAN)
 			nf_bridge->netoutdev = (struct net_device *)out;
 #endif
-		okfn(skb);
-		return NF_STOLEN;
+		return NF_STOP;
 	}
 
 	return NF_ACCEPT;
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -65,6 +65,15 @@ static int br_device_event(struct notifi
 		}
 		break;
 
+	case NETDEV_FEAT_CHANGE:
+		if (br->dev->flags & IFF_UP) 
+			br_features_recompute(br);
+
+		/* could do recursive feature change notification
+		 * but who would care?? 
+		 */
+		break;
+
 	case NETDEV_DOWN:
 		if (br->dev->flags & IFF_UP)
 			br_stp_disable_port(p);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -46,10 +46,8 @@ struct net_bridge_fdb_entry
 {
 	struct hlist_node		hlist;
 	struct net_bridge_port		*dst;
-	union {
-		struct list_head	age_list;
-		struct rcu_head		rcu;
-	} u;
+
+	struct rcu_head			rcu;
 	atomic_t			use_count;
 	unsigned long			ageing_timer;
 	mac_addr			addr;
@@ -148,8 +146,10 @@ extern int br_fdb_fillbuf(struct net_bri
 			  unsigned long count, unsigned long off);
 extern int br_fdb_insert(struct net_bridge *br,
 			 struct net_bridge_port *source,
-			 const unsigned char *addr,
-			 int is_local);
+			 const unsigned char *addr);
+extern void br_fdb_update(struct net_bridge *br,
+			  struct net_bridge_port *source,
+			  const unsigned char *addr);
 
 /* br_forward.c */
 extern void br_deliver(const struct net_bridge_port *to,
@@ -174,6 +174,7 @@ extern int br_add_if(struct net_bridge *
 extern int br_del_if(struct net_bridge *br,
 	      struct net_device *dev);
 extern int br_min_mtu(const struct net_bridge *br);
+extern void br_features_recompute(struct net_bridge *br);
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
@@ -216,6 +217,12 @@ extern void br_stp_timer_init(struct net
 extern void br_stp_port_timer_init(struct net_bridge_port *p);
 extern unsigned long br_timer_value(const struct timer_list *timer);
 
+/* br.c */
+extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+						       unsigned char *addr);
+extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+
+
 #ifdef CONFIG_SYSFS
 /* br_sysfs_if.c */
 extern int br_sysfs_addif(struct net_bridge_port *p);
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -140,6 +140,9 @@ int br_stp_handle_bpdu(struct sk_buff *s
 	struct net_bridge *br = p->br;
 	unsigned char *buf;
 
+	/* insert into forwarding database after filtering to avoid spoofing */
+	br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+
 	/* need at least the 802 and STP headers */
 	if (!pskb_may_pull(skb, sizeof(header)+1) ||
 	    memcmp(skb->data, header, sizeof(header)))
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -49,6 +49,8 @@ void br_stp_enable_bridge(struct net_bri
 
 	spin_lock_bh(&br->lock);
 	mod_timer(&br->hello_timer, jiffies + br->hello_time);
+	mod_timer(&br->gc_timer, jiffies + HZ/10);
+	
 	br_config_bpdu_generation(br);
 
 	list_for_each_entry(p, &br->port_list, list) {
@@ -78,6 +80,7 @@ void br_stp_disable_bridge(struct net_br
 	del_timer_sync(&br->hello_timer);
 	del_timer_sync(&br->topology_change_timer);
 	del_timer_sync(&br->tcn_timer);
+	del_timer_sync(&br->gc_timer);
 }
 
 /* called under bridge lock */
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -248,6 +248,7 @@ int br_sysfs_addif(struct net_bridge_por
 	if (err)
 		goto out2;
 
+	kobject_hotplug(&p->kobj, KOBJ_ADD);
 	return 0;
  out2:
 	kobject_del(&p->kobj);
@@ -259,6 +260,7 @@ void br_sysfs_removeif(struct net_bridge
 {
 	pr_debug("br_sysfs_removeif\n");
 	sysfs_remove_link(&p->br->ifobj, p->dev->name);
+	kobject_hotplug(&p->kobj, KOBJ_REMOVE);
 	kobject_del(&p->kobj);
 }
 
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -179,9 +179,10 @@ unsigned int ebt_do_table (unsigned int 
 	struct ebt_chainstack *cs;
 	struct ebt_entries *chaininfo;
 	char *base;
-	struct ebt_table_info *private = table->private;
+	struct ebt_table_info *private;
 
 	read_lock_bh(&table->lock);
+	private = table->private;
 	cb_base = COUNTER_BASE(private->counters, private->nentries,
 	   smp_processor_id());
 	if (private->chainstack)
@@ -822,10 +823,10 @@ static int translate_table(struct ebt_re
 		/* this will get free'd in do_replace()/ebt_register_table()
 		   if an error occurs */
 		newinfo->chainstack = (struct ebt_chainstack **)
-		   vmalloc(NR_CPUS * sizeof(struct ebt_chainstack));
+		   vmalloc(num_possible_cpus() * sizeof(struct ebt_chainstack));
 		if (!newinfo->chainstack)
 			return -ENOMEM;
-		for (i = 0; i < NR_CPUS; i++) {
+		for (i = 0; i < num_possible_cpus(); i++) {
 			newinfo->chainstack[i] =
 			   vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
 			if (!newinfo->chainstack[i]) {
@@ -898,7 +899,7 @@ static void get_counters(struct ebt_coun
 	memcpy(counters, oldcounters,
 	   sizeof(struct ebt_counter) * nentries);
 	/* add other counters to those of cpu 0 */
-	for (cpu = 1; cpu < NR_CPUS; cpu++) {
+	for (cpu = 1; cpu < num_possible_cpus(); cpu++) {
 		counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
 		for (i = 0; i < nentries; i++) {
 			counters[i].pcnt += counter_base[i].pcnt;
@@ -930,7 +931,7 @@ static int do_replace(void __user *user,
 		BUGPRINT("Entries_size never zero\n");
 		return -EINVAL;
 	}
-	countersize = COUNTER_OFFSET(tmp.nentries) * NR_CPUS;
+	countersize = COUNTER_OFFSET(tmp.nentries) * num_possible_cpus();
 	newinfo = (struct ebt_table_info *)
 	   vmalloc(sizeof(struct ebt_table_info) + countersize);
 	if (!newinfo)
@@ -1023,7 +1024,7 @@ static int do_replace(void __user *user,
 
 	vfree(table->entries);
 	if (table->chainstack) {
-		for (i = 0; i < NR_CPUS; i++)
+		for (i = 0; i < num_possible_cpus(); i++)
 			vfree(table->chainstack[i]);
 		vfree(table->chainstack);
 	}
@@ -1043,7 +1044,7 @@ free_counterstmp:
 		vfree(counterstmp);
 	/* can be initialized in translate_table() */
 	if (newinfo->chainstack) {
-		for (i = 0; i < NR_CPUS; i++)
+		for (i = 0; i < num_possible_cpus(); i++)
 			vfree(newinfo->chainstack[i]);
 		vfree(newinfo->chainstack);
 	}
@@ -1137,7 +1138,7 @@ int ebt_register_table(struct ebt_table 
 		return -EINVAL;
 	}
 
-	countersize = COUNTER_OFFSET(table->table->nentries) * NR_CPUS;
+	countersize = COUNTER_OFFSET(table->table->nentries) * num_possible_cpus();
 	newinfo = (struct ebt_table_info *)
 	   vmalloc(sizeof(struct ebt_table_info) + countersize);
 	ret = -ENOMEM;
@@ -1191,7 +1192,7 @@ free_unlock:
 	up(&ebt_mutex);
 free_chainstack:
 	if (newinfo->chainstack) {
-		for (i = 0; i < NR_CPUS; i++)
+		for (i = 0; i < num_possible_cpus(); i++)
 			vfree(newinfo->chainstack[i]);
 		vfree(newinfo->chainstack);
 	}
@@ -1215,7 +1216,7 @@ void ebt_unregister_table(struct ebt_tab
 	if (table->private->entries)
 		vfree(table->private->entries);
 	if (table->private->chainstack) {
-		for (i = 0; i < NR_CPUS; i++)
+		for (i = 0; i < num_possible_cpus(); i++)
 			vfree(table->private->chainstack[i]);
 		vfree(table->private->chainstack);
 	}
diff --git a/net/core/datagram.c b/net/core/datagram.c
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -115,10 +115,10 @@ out_noerr:
 
 /**
  *	skb_recv_datagram - Receive a datagram skbuff
- *	@sk - socket
- *	@flags - MSG_ flags
- *	@noblock - blocking operation?
- *	@err - error code returned
+ *	@sk: socket
+ *	@flags: MSG_ flags
+ *	@noblock: blocking operation?
+ *	@err: error code returned
  *
  *	Get a datagram skbuff, understands the peeking, nonblocking wakeups
  *	and possible races. This replaces identical code in packet, raw and
@@ -201,10 +201,10 @@ void skb_free_datagram(struct sock *sk, 
 
 /**
  *	skb_copy_datagram_iovec - Copy a datagram to an iovec.
- *	@skb - buffer to copy
- *	@offset - offset in the buffer to start copying from
- *	@iovec - io vector to copy to
- *	@len - amount of data to copy from buffer to iovec
+ *	@skb: buffer to copy
+ *	@offset: offset in the buffer to start copying from
+ *	@to: io vector to copy to
+ *	@len: amount of data to copy from buffer to iovec
  *
  *	Note: the iovec is modified during the copy.
  */
@@ -377,9 +377,9 @@ fault:
 
 /**
  *	skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
- *	@skb - skbuff
- *	@hlen - hardware length
- *	@iovec - io vector
+ *	@skb: skbuff
+ *	@hlen: hardware length
+ *	@iov: io vector
  * 
  *	Caller _must_ check that skb will fit to this iovec.
  *
@@ -425,9 +425,9 @@ fault:
 
 /**
  * 	datagram_poll - generic datagram poll
- *	@file - file struct
- *	@sock - socket
- *	@wait - poll table
+ *	@file: file struct
+ *	@sock: socket
+ *	@wait: poll table
  *
  *	Datagram poll: Again totally generic. This also handles
  *	sequenced packet sockets providing the socket receive queue
diff --git a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7,7 +7,7 @@
  *		2 of the License, or (at your option) any later version.
  *
  *	Derived from the non IP parts of dev.c 1.0.19
- * 		Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * 		Authors:	Ross Biro
  *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *				Mark Evans, <evansmp@uhura.aston.ac.uk>
  *
@@ -761,6 +761,18 @@ int dev_change_name(struct net_device *d
 }
 
 /**
+ *	netdev_features_change - device changes fatures
+ *	@dev: device to cause notification
+ *
+ *	Called to indicate a device has changed features.
+ */
+void netdev_features_change(struct net_device *dev)
+{
+	notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+}
+EXPORT_SYMBOL(netdev_features_change);
+
+/**
  *	netdev_state_change - device changes state
  *	@dev: device to cause notification
  *
@@ -1214,6 +1226,19 @@ int __skb_linearize(struct sk_buff *skb,
  *	A negative errno code is returned on a failure. A success does not
  *	guarantee the frame will be transmitted as it may be dropped due
  *	to congestion or traffic shaping.
+ *
+ * -----------------------------------------------------------------------------------
+ *      I notice this method can also return errors from the queue disciplines,
+ *      including NET_XMIT_DROP, which is a positive value.  So, errors can also
+ *      be positive.
+ *
+ *      Regardless of the return value, the skb is consumed, so it is currently
+ *      difficult to retry a send to this method.  (You can bump the ref count
+ *      before sending to hold a reference for retry if you are careful.)
+ *
+ *      When calling this method, interrupts MUST be enabled.  This is because
+ *      the BH enable code must have IRQs enabled so that it will not deadlock.
+ *          --BLG
  */
 
 int dev_queue_xmit(struct sk_buff *skb)
@@ -1427,13 +1452,10 @@ int netif_rx(struct sk_buff *skb)
 	struct softnet_data *queue;
 	unsigned long flags;
 
-#ifdef CONFIG_NETPOLL
-	if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
-		kfree_skb(skb);
+	/* if netpoll wants it, pretend we never saw it */
+	if (netpoll_rx(skb))
 		return NET_RX_DROP;
-	}
-#endif
-	
+
 	if (!skb->stamp.tv_sec)
 		net_timestamp(&skb->stamp);
 
@@ -1561,6 +1583,10 @@ static __inline__ int deliver_skb(struct
 
 #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
 int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
+struct net_bridge;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+						unsigned char *addr);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
 
 static __inline__ int handle_bridge(struct sk_buff **pskb,
 				    struct packet_type **pt_prev, int *ret)
@@ -1629,12 +1655,9 @@ int netif_receive_skb(struct sk_buff *sk
 	int ret = NET_RX_DROP;
 	unsigned short type;
 
-#ifdef CONFIG_NETPOLL
-	if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
-		kfree_skb(skb);
+	/* if we've gotten here through NAPI, check netpoll */
+	if (skb->dev->poll && netpoll_rx(skb))
 		return NET_RX_DROP;
-	}
-#endif
 
 	if (!skb->stamp.tv_sec)
 		net_timestamp(&skb->stamp);
@@ -1721,6 +1744,7 @@ static int process_backlog(struct net_de
 	struct softnet_data *queue = &__get_cpu_var(softnet_data);
 	unsigned long start_time = jiffies;
 
+	backlog_dev->weight = weight_p;
 	for (;;) {
 		struct sk_buff *skb;
 		struct net_device *dev;
@@ -1781,8 +1805,10 @@ static void net_rx_action(struct softirq
 
 		dev = list_entry(queue->poll_list.next,
 				 struct net_device, poll_list);
+		netpoll_poll_lock(dev);
 
 		if (dev->quota <= 0 || dev->poll(dev, &budget)) {
+			netpoll_poll_unlock(dev);
 			local_irq_disable();
 			list_del(&dev->poll_list);
 			list_add_tail(&dev->poll_list, &queue->poll_list);
@@ -1791,6 +1817,7 @@ static void net_rx_action(struct softirq
 			else
 				dev->quota = dev->weight;
 		} else {
+			netpoll_poll_unlock(dev);
 			dev_put(dev);
 			local_irq_disable();
 		}
@@ -2300,6 +2327,21 @@ int dev_set_mtu(struct net_device *dev, 
 	return err;
 }
 
+int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
+{
+	int err;
+
+	if (!dev->set_mac_address)
+		return -EOPNOTSUPP;
+	if (sa->sa_family != dev->type)
+		return -EINVAL;
+	if (!netif_device_present(dev))
+		return -ENODEV;
+	err = dev->set_mac_address(dev, sa);
+	if (!err)
+		notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+	return err;
+}
 
 /*
  *	Perform the SIOCxIFxxx calls.
@@ -2346,17 +2388,7 @@ static int dev_ifsioc(struct ifreq *ifr,
 			return 0;
 
 		case SIOCSIFHWADDR:
-			if (!dev->set_mac_address)
-				return -EOPNOTSUPP;
-			if (ifr->ifr_hwaddr.sa_family != dev->type)
-				return -EINVAL;
-			if (!netif_device_present(dev))
-				return -ENODEV;
-			err = dev->set_mac_address(dev, &ifr->ifr_hwaddr);
-			if (!err)
-				notifier_call_chain(&netdev_chain,
-						    NETDEV_CHANGEADDR, dev);
-			return err;
+			return dev_set_mac_address(dev, &ifr->ifr_hwaddr);
 
 		case SIOCSIFHWBROADCAST:
 			if (ifr->ifr_hwaddr.sa_family != dev->type)
@@ -3072,7 +3104,7 @@ void free_netdev(struct net_device *dev)
 void synchronize_net(void) 
 {
 	might_sleep();
-	synchronize_kernel();
+	synchronize_rcu();
 }
 
 /**
@@ -3322,6 +3354,7 @@ EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
 EXPORT_SYMBOL(dev_change_flags);
 EXPORT_SYMBOL(dev_set_mtu);
+EXPORT_SYMBOL(dev_set_mac_address);
 EXPORT_SYMBOL(free_netdev);
 EXPORT_SYMBOL(netdev_boot_setup_check);
 EXPORT_SYMBOL(netdev_set_master);
@@ -3337,9 +3370,12 @@ EXPORT_SYMBOL(unregister_netdevice);
 EXPORT_SYMBOL(unregister_netdevice_notifier);
 EXPORT_SYMBOL(net_enable_timestamp);
 EXPORT_SYMBOL(net_disable_timestamp);
+EXPORT_SYMBOL(dev_get_flags);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);
+EXPORT_SYMBOL(br_fdb_get_hook);
+EXPORT_SYMBOL(br_fdb_put_hook);
 #endif
 
 #ifdef CONFIG_KMOD
diff --git a/net/core/dst.c b/net/core/dst.c
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -198,13 +198,15 @@ again:
 
 	dst = child;
 	if (dst) {
+		int nohash = dst->flags & DST_NOHASH;
+
 		if (atomic_dec_and_test(&dst->__refcnt)) {
 			/* We were real parent of this dst, so kill child. */
-			if (dst->flags&DST_NOHASH)
+			if (nohash)
 				goto again;
 		} else {
 			/* Child is still referenced, return it for freeing. */
-			if (dst->flags&DST_NOHASH)
+			if (nohash)
 				return dst;
 			/* Child is still in his hash table */
 		}
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -29,7 +29,7 @@ u32 ethtool_op_get_link(struct net_devic
 
 u32 ethtool_op_get_tx_csum(struct net_device *dev)
 {
-	return (dev->features & NETIF_F_IP_CSUM) != 0;
+	return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
 }
 
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
@@ -42,6 +42,15 @@ int ethtool_op_set_tx_csum(struct net_de
 	return 0;
 }
 
+int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= NETIF_F_HW_CSUM;
+	else
+		dev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
 u32 ethtool_op_get_sg(struct net_device *dev)
 {
 	return (dev->features & NETIF_F_SG) != 0;
@@ -347,7 +356,7 @@ static int ethtool_set_coalesce(struct n
 {
 	struct ethtool_coalesce coalesce;
 
-	if (!dev->ethtool_ops->get_coalesce)
+	if (!dev->ethtool_ops->set_coalesce)
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
@@ -682,6 +691,7 @@ int dev_ethtool(struct ifreq *ifr)
 	void __user *useraddr = ifr->ifr_data;
 	u32 ethcmd;
 	int rc;
+	unsigned long old_features;
 
 	/*
 	 * XXX: This can be pushed down into the ethtool_* handlers that
@@ -703,6 +713,8 @@ int dev_ethtool(struct ifreq *ifr)
 		if ((rc = dev->ethtool_ops->begin(dev)) < 0)
 			return rc;
 
+	old_features = dev->features;
+
 	switch (ethcmd) {
 	case ETHTOOL_GSET:
 		rc = ethtool_get_settings(dev, useraddr);
@@ -712,7 +724,6 @@ int dev_ethtool(struct ifreq *ifr)
 		break;
 	case ETHTOOL_GDRVINFO:
 		rc = ethtool_get_drvinfo(dev, useraddr);
-
 		break;
 	case ETHTOOL_GREGS:
 		rc = ethtool_get_regs(dev, useraddr);
@@ -801,6 +812,10 @@ int dev_ethtool(struct ifreq *ifr)
 	
 	if(dev->ethtool_ops->complete)
 		dev->ethtool_ops->complete(dev);
+
+	if (old_features != dev->features)
+		netdev_features_change(dev);
+
 	return rc;
 
  ioctl:
@@ -817,3 +832,4 @@ EXPORT_SYMBOL(ethtool_op_get_tx_csum);
 EXPORT_SYMBOL(ethtool_op_set_sg);
 EXPORT_SYMBOL(ethtool_op_set_tso);
 EXPORT_SYMBOL(ethtool_op_set_tx_csum);
+EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -56,18 +56,20 @@ int
 gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
 	int xstats_type, spinlock_t *lock, struct gnet_dump *d)
 {
+	memset(d, 0, sizeof(*d));
+	
 	spin_lock_bh(lock);
 	d->lock = lock;
-	d->tail = (struct rtattr *) skb->tail;
+	if (type)
+		d->tail = (struct rtattr *) skb->tail;
 	d->skb = skb;
 	d->compat_tc_stats = tc_stats_type;
 	d->compat_xstats = xstats_type;
-	d->xstats = NULL;
 
-	if (d->compat_tc_stats)
-		memset(&d->tc_stats, 0, sizeof(d->tc_stats));
+	if (d->tail)
+		return gnet_stats_copy(d, type, NULL, 0);
 
-	return gnet_stats_copy(d, type, NULL, 0);
+	return 0;
 }
 
 /**
@@ -108,8 +110,11 @@ gnet_stats_copy_basic(struct gnet_dump *
 		d->tc_stats.bytes = b->bytes;
 		d->tc_stats.packets = b->packets;
 	}
-	
-	return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
+
+	if (d->tail)
+		return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
+
+	return 0;
 }
 
 /**
@@ -131,7 +136,10 @@ gnet_stats_copy_rate_est(struct gnet_dum
 		d->tc_stats.pps = r->pps;
 	}
 
-	return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));
+	if (d->tail)
+		return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));
+
+	return 0;
 }
 
 /**
@@ -154,8 +162,11 @@ gnet_stats_copy_queue(struct gnet_dump *
 		d->tc_stats.backlog = q->backlog;
 		d->tc_stats.overlimits = q->overlimits;
 	}
-		
-	return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
+
+	if (d->tail)
+		return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
+
+	return 0;
 }
 
 /**
@@ -174,9 +185,15 @@ gnet_stats_copy_queue(struct gnet_dump *
 int
 gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
 {
-	if (d->compat_xstats)
-		d->xstats = (struct rtattr *) d->skb->tail;
-	return gnet_stats_copy(d, TCA_STATS_APP, st, len);
+	if (d->compat_xstats) {
+		d->xstats = st;
+		d->xstats_len = len;
+	}
+
+	if (d->tail)
+		return gnet_stats_copy(d, TCA_STATS_APP, st, len);
+
+	return 0;
 }
 
 /**
@@ -194,7 +211,8 @@ gnet_stats_copy_app(struct gnet_dump *d,
 int
 gnet_stats_finish_copy(struct gnet_dump *d)
 {
-	d->tail->rta_len = d->skb->tail - (u8 *) d->tail;
+	if (d->tail)
+		d->tail->rta_len = d->skb->tail - (u8 *) d->tail;
 
 	if (d->compat_tc_stats)
 		if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
@@ -202,8 +220,8 @@ gnet_stats_finish_copy(struct gnet_dump 
 			return -1;
 
 	if (d->compat_xstats && d->xstats) {
-		if (gnet_stats_copy(d, d->compat_xstats, RTA_DATA(d->xstats),
-			RTA_PAYLOAD(d->xstats)) < 0)
+		if (gnet_stats_copy(d, d->compat_xstats, d->xstats,
+			d->xstats_len) < 0)
 			return -1;
 	}
 
diff --git a/net/core/iovec.c b/net/core/iovec.c
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -33,7 +33,7 @@
  *	Verify iovec. The caller must ensure that the iovec is big enough
  *	to hold the message iovec.
  *
- *	Save time not doing verify_area. copy_*_user will make this work
+ *	Save time not doing access_ok. copy_*_user will make this work
  *	in any case.
  */
 
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -16,6 +16,7 @@
 #include <linux/netdevice.h>
 #include <linux/if.h>
 #include <net/sock.h>
+#include <net/pkt_sched.h>
 #include <linux/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
@@ -74,6 +75,12 @@ void linkwatch_run_queue(void)
 		clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
 
 		if (dev->flags & IFF_UP) {
+			if (netif_carrier_ok(dev)) {
+				WARN_ON(dev->qdisc_sleeping == &noop_qdisc);
+				dev_activate(dev);
+			} else
+				dev_deactivate(dev);
+
 			netdev_state_change(dev);
 		}
 
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1430,6 +1430,7 @@ int neigh_delete(struct sk_buff *skb, st
 
 	read_lock(&neigh_tbl_lock);
 	for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+		struct rtattr *dst_attr = nda[NDA_DST - 1];
 		struct neighbour *n;
 
 		if (tbl->family != ndm->ndm_family)
@@ -1437,20 +1438,18 @@ int neigh_delete(struct sk_buff *skb, st
 		read_unlock(&neigh_tbl_lock);
 
 		err = -EINVAL;
-		if (!nda[NDA_DST - 1] ||
-		    nda[NDA_DST - 1]->rta_len != RTA_LENGTH(tbl->key_len))
+		if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
 			goto out_dev_put;
 
 		if (ndm->ndm_flags & NTF_PROXY) {
-			err = pneigh_delete(tbl,
-					    RTA_DATA(nda[NDA_DST - 1]), dev);
+			err = pneigh_delete(tbl, RTA_DATA(dst_attr), dev);
 			goto out_dev_put;
 		}
 
 		if (!dev)
 			goto out;
 
-		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST - 1]), dev);
+		n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev);
 		if (n) {
 			err = neigh_update(n, NULL, NUD_FAILED, 
 					   NEIGH_UPDATE_F_OVERRIDE|
@@ -1482,6 +1481,8 @@ int neigh_add(struct sk_buff *skb, struc
 
 	read_lock(&neigh_tbl_lock);
 	for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+		struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1];
+		struct rtattr *dst_attr = nda[NDA_DST - 1];
 		int override = 1;
 		struct neighbour *n;
 
@@ -1490,48 +1491,49 @@ int neigh_add(struct sk_buff *skb, struc
 		read_unlock(&neigh_tbl_lock);
 
 		err = -EINVAL;
-		if (!nda[NDA_DST - 1] ||
-		    nda[NDA_DST - 1]->rta_len != RTA_LENGTH(tbl->key_len))
+		if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
 			goto out_dev_put;
+
 		if (ndm->ndm_flags & NTF_PROXY) {
 			err = -ENOBUFS;
-			if (pneigh_lookup(tbl,
-					  RTA_DATA(nda[NDA_DST - 1]), dev, 1))
+			if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1))
 				err = 0;
 			goto out_dev_put;
 		}
+
 		err = -EINVAL;
 		if (!dev)
 			goto out;
-		if (nda[NDA_LLADDR - 1] &&
-		    nda[NDA_LLADDR - 1]->rta_len != RTA_LENGTH(dev->addr_len))
+		if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len)
 			goto out_dev_put;
-		err = 0;
-		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST - 1]), dev);
+	
+		n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev);
 		if (n) {
-			if (nlh->nlmsg_flags & NLM_F_EXCL)
+			if (nlh->nlmsg_flags & NLM_F_EXCL) {
 				err = -EEXIST;
+				neigh_release(n);
+				goto out_dev_put;
+			}
+			
 			override = nlh->nlmsg_flags & NLM_F_REPLACE;
-		} else if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+		} else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
 			err = -ENOENT;
-		else {
-			n = __neigh_lookup_errno(tbl, RTA_DATA(nda[NDA_DST - 1]),
-						 dev);
+			goto out_dev_put;
+		} else {
+			n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev);
 			if (IS_ERR(n)) {
 				err = PTR_ERR(n);
-				n = NULL;
+				goto out_dev_put;
 			}
 		}
-		if (!err) {
-			err = neigh_update(n, nda[NDA_LLADDR - 1] ?
-						RTA_DATA(nda[NDA_LLADDR - 1]) :
-						NULL,
-					   ndm->ndm_state,
-					   (override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
-					   NEIGH_UPDATE_F_ADMIN);
-		}
-		if (n)
-			neigh_release(n);
+
+		err = neigh_update(n,
+				   lladdr_attr ? RTA_DATA(lladdr_attr) : NULL,
+				   ndm->ndm_state,
+				   (override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
+				   NEIGH_UPDATE_F_ADMIN);
+
+		neigh_release(n);
 		goto out_dev_put;
 	}
 
@@ -1552,6 +1554,7 @@ static int neigh_fill_info(struct sk_buf
 	unsigned char *b = skb->tail;
 	struct nda_cacheinfo ci;
 	int locked = 0;
+	u32 probes;
 	struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq, event,
 					 sizeof(struct ndmsg));
 	struct ndmsg *ndm = NLMSG_DATA(nlh);
@@ -1571,9 +1574,11 @@ static int neigh_fill_info(struct sk_buf
 	ci.ndm_confirmed = now - n->confirmed;
 	ci.ndm_updated	 = now - n->updated;
 	ci.ndm_refcnt	 = atomic_read(&n->refcnt) - 1;
+	probes = atomic_read(&n->probes);
 	read_unlock_bh(&n->lock);
 	locked		 = 0;
 	RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
+	RTA_PUT(skb, NDA_PROBES, sizeof(probes), &probes);
 	nlh->nlmsg_len	 = skb->tail - b;
 	return skb->len;
 
@@ -1948,7 +1953,7 @@ static int neigh_stat_seq_show(struct se
 	struct neigh_statistics *st = v;
 
 	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n");
+		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs\n");
 		return 0;
 	}
 
@@ -2047,7 +2052,7 @@ static void neigh_app_notify(struct neig
 
 static struct neigh_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		neigh_vars[17];
+	ctl_table		neigh_vars[__NET_NEIGH_MAX];
 	ctl_table		neigh_dev[2];
 	ctl_table		neigh_neigh_dir[2];
 	ctl_table		neigh_proto_dir[2];
@@ -2170,6 +2175,22 @@ static struct neigh_sysctl_table {
 			.mode		= 0644,
 			.proc_handler	= &proc_dointvec,
 		},
+		{
+			.ctl_name	= NET_NEIGH_RETRANS_TIME_MS,
+			.procname	= "retrans_time_ms",
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec_ms_jiffies,
+			.strategy	= &sysctl_ms_jiffies,
+		},
+		{
+			.ctl_name	= NET_NEIGH_REACHABLE_TIME_MS,
+			.procname	= "base_reachable_time_ms",
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec_ms_jiffies,
+			.strategy	= &sysctl_ms_jiffies,
+		},
 	},
 	.neigh_dev = {
 		{
@@ -2200,7 +2221,7 @@ static struct neigh_sysctl_table {
 
 int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 			  int p_id, int pdev_id, char *p_name, 
-			  proc_handler *handler)
+			  proc_handler *handler, ctl_handler *strategy)
 {
 	struct neigh_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
 	const char *dev_name_source = NULL;
@@ -2214,10 +2235,6 @@ int neigh_sysctl_register(struct net_dev
 	t->neigh_vars[1].data  = &p->ucast_probes;
 	t->neigh_vars[2].data  = &p->app_probes;
 	t->neigh_vars[3].data  = &p->retrans_time;
-	if (handler) {
-		t->neigh_vars[3].proc_handler = handler;
-		t->neigh_vars[3].extra1 = dev;
-	}
 	t->neigh_vars[4].data  = &p->base_reachable_time;
 	t->neigh_vars[5].data  = &p->delay_probe_time;
 	t->neigh_vars[6].data  = &p->gc_staletime;
@@ -2227,18 +2244,43 @@ int neigh_sysctl_register(struct net_dev
 	t->neigh_vars[10].data = &p->proxy_delay;
 	t->neigh_vars[11].data = &p->locktime;
 
- 	dev_name_source = t->neigh_dev[0].procname;
 	if (dev) {
 		dev_name_source = dev->name;
 		t->neigh_dev[0].ctl_name = dev->ifindex;
-		memset(&t->neigh_vars[12], 0, sizeof(ctl_table));
+		t->neigh_vars[12].procname = NULL;
+		t->neigh_vars[13].procname = NULL;
+		t->neigh_vars[14].procname = NULL;
+		t->neigh_vars[15].procname = NULL;
 	} else {
+ 		dev_name_source = t->neigh_dev[0].procname;
 		t->neigh_vars[12].data = (int *)(p + 1);
 		t->neigh_vars[13].data = (int *)(p + 1) + 1;
 		t->neigh_vars[14].data = (int *)(p + 1) + 2;
 		t->neigh_vars[15].data = (int *)(p + 1) + 3;
 	}
 
+	t->neigh_vars[16].data  = &p->retrans_time;
+	t->neigh_vars[17].data  = &p->base_reachable_time;
+
+	if (handler || strategy) {
+		/* RetransTime */
+		t->neigh_vars[3].proc_handler = handler;
+		t->neigh_vars[3].strategy = strategy;
+		t->neigh_vars[3].extra1 = dev;
+		/* ReachableTime */
+		t->neigh_vars[4].proc_handler = handler;
+		t->neigh_vars[4].strategy = strategy;
+		t->neigh_vars[4].extra1 = dev;
+		/* RetransTime (in milliseconds)*/
+		t->neigh_vars[16].proc_handler = handler;
+		t->neigh_vars[16].strategy = strategy;
+		t->neigh_vars[16].extra1 = dev;
+		/* ReachableTime (in milliseconds) */
+		t->neigh_vars[17].proc_handler = handler;
+		t->neigh_vars[17].strategy = strategy;
+		t->neigh_vars[17].extra1 = dev;
+	}
+
 	dev_name = net_sysctl_strdup(dev_name_source);
 	if (!dev_name) {
 		err = -ENOBUFS;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -21,6 +21,7 @@
 #define to_net_dev(class) container_of(class, struct net_device, class_dev)
 
 static const char fmt_hex[] = "%#x\n";
+static const char fmt_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
 static const char fmt_ulong[] = "%lu\n";
 
@@ -91,7 +92,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO,
 NETDEVICE_ATTR(addr_len, fmt_dec);
 NETDEVICE_ATTR(iflink, fmt_dec);
 NETDEVICE_ATTR(ifindex, fmt_dec);
-NETDEVICE_ATTR(features, fmt_hex);
+NETDEVICE_ATTR(features, fmt_long_hex);
 NETDEVICE_ATTR(type, fmt_dec);
 
 /* use same locking rules as GIFHWADDR ioctl's */
@@ -184,6 +185,22 @@ static ssize_t store_tx_queue_len(struct
 static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 
 			 store_tx_queue_len);
 
+NETDEVICE_SHOW(weight, fmt_dec);
+
+static int change_weight(struct net_device *net, unsigned long new_weight)
+{
+	net->weight = new_weight;
+	return 0;
+}
+
+static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len)
+{
+	return netdev_store(dev, buf, len, change_weight);
+}
+
+static CLASS_DEVICE_ATTR(weight, S_IRUGO | S_IWUSR, show_weight, 
+			 store_weight);
+
 
 static struct class_device_attribute *net_class_attributes[] = {
 	&class_device_attr_ifindex,
@@ -193,6 +210,7 @@ static struct class_device_attribute *ne
 	&class_device_attr_features,
 	&class_device_attr_mtu,
 	&class_device_attr_flags,
+	&class_device_attr_weight,
 	&class_device_attr_type,
 	&class_device_attr_address,
 	&class_device_attr_broadcast,
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -217,21 +217,10 @@ void nf_debug_ip_local_deliver(struct sk
 	 * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING.  */
 	if (!skb->dev) {
 		printk("ip_local_deliver: skb->dev is NULL.\n");
-	}
-	else if (strcmp(skb->dev->name, "lo") == 0) {
-		if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
-				      | (1 << NF_IP_POST_ROUTING)
-				      | (1 << NF_IP_PRE_ROUTING)
-				      | (1 << NF_IP_LOCAL_IN))) {
-			printk("ip_local_deliver: bad loopback skb: ");
-			debug_print_hooks_ip(skb->nf_debug);
-			nf_dump_skb(PF_INET, skb);
-		}
-	}
-	else {
+	} else {
 		if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
 				      | (1<<NF_IP_LOCAL_IN))) {
-			printk("ip_local_deliver: bad non-lo skb: ");
+			printk("ip_local_deliver: bad skb: ");
 			debug_print_hooks_ip(skb->nf_debug);
 			nf_dump_skb(PF_INET, skb);
 		}
@@ -247,8 +236,6 @@ void nf_debug_ip_loopback_xmit(struct sk
 		debug_print_hooks_ip(newskb->nf_debug);
 		nf_dump_skb(PF_INET, newskb);
 	}
-	/* Clear to avoid confusing input check */
-	newskb->nf_debug = 0;
 }
 
 void nf_debug_ip_finish_output2(struct sk_buff *skb)
@@ -349,6 +336,8 @@ static unsigned int nf_iterate(struct li
 			       int (*okfn)(struct sk_buff *),
 			       int hook_thresh)
 {
+	unsigned int verdict;
+
 	/*
 	 * The caller must not block between calls to this
 	 * function because of risk of continuing from deleted element.
@@ -361,28 +350,18 @@ static unsigned int nf_iterate(struct li
 
 		/* Optimization: we don't need to hold module
                    reference here, since function can't sleep. --RR */
-		switch (elem->hook(hook, skb, indev, outdev, okfn)) {
-		case NF_QUEUE:
-			return NF_QUEUE;
-
-		case NF_STOLEN:
-			return NF_STOLEN;
-
-		case NF_DROP:
-			return NF_DROP;
-
-		case NF_REPEAT:
-			*i = (*i)->prev;
-			break;
-
+		verdict = elem->hook(hook, skb, indev, outdev, okfn);
+		if (verdict != NF_ACCEPT) {
 #ifdef CONFIG_NETFILTER_DEBUG
-		case NF_ACCEPT:
-			break;
-
-		default:
-			NFDEBUG("Evil return from %p(%u).\n", 
-				elem->hook, hook);
+			if (unlikely(verdict > NF_MAX_VERDICT)) {
+				NFDEBUG("Evil return from %p(%u).\n",
+				        elem->hook, hook);
+				continue;
+			}
 #endif
+			if (verdict != NF_REPEAT)
+				return verdict;
+			*i = (*i)->prev;
 		}
 	}
 	return NF_ACCEPT;
@@ -494,7 +473,9 @@ static int nf_queue(struct sk_buff *skb,
 	return 1;
 }
 
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+/* Returns 1 if okfn() needs to be executed by the caller,
+ * -EPERM for NF_DROP, 0 otherwise. */
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
 		 struct net_device *indev,
 		 struct net_device *outdev,
 		 int (*okfn)(struct sk_buff *),
@@ -508,34 +489,29 @@ int nf_hook_slow(int pf, unsigned int ho
 	rcu_read_lock();
 
 #ifdef CONFIG_NETFILTER_DEBUG
-	if (skb->nf_debug & (1 << hook)) {
+	if (unlikely((*pskb)->nf_debug & (1 << hook))) {
 		printk("nf_hook: hook %i already set.\n", hook);
-		nf_dump_skb(pf, skb);
+		nf_dump_skb(pf, *pskb);
 	}
-	skb->nf_debug |= (1 << hook);
+	(*pskb)->nf_debug |= (1 << hook);
 #endif
 
 	elem = &nf_hooks[pf][hook];
- next_hook:
-	verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
+next_hook:
+	verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
 			     outdev, &elem, okfn, hook_thresh);
-	if (verdict == NF_QUEUE) {
+	if (verdict == NF_ACCEPT || verdict == NF_STOP) {
+		ret = 1;
+		goto unlock;
+	} else if (verdict == NF_DROP) {
+		kfree_skb(*pskb);
+		ret = -EPERM;
+	} else if (verdict == NF_QUEUE) {
 		NFDEBUG("nf_hook: Verdict = QUEUE.\n");
-		if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
+		if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn))
 			goto next_hook;
 	}
-
-	switch (verdict) {
-	case NF_ACCEPT:
-		ret = okfn(skb);
-		break;
-
-	case NF_DROP:
-		kfree_skb(skb);
-		ret = -EPERM;
-		break;
-	}
-
+unlock:
 	rcu_read_unlock();
 	return ret;
 }
@@ -678,7 +654,6 @@ EXPORT_SYMBOL(ip_route_me_harder);
 int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
 {
 	struct sk_buff *nskb;
-	unsigned int iplen;
 
 	if (writable_len > (*pskb)->len)
 		return 0;
@@ -687,35 +662,7 @@ int skb_ip_make_writable(struct sk_buff 
 	if (skb_shared(*pskb) || skb_cloned(*pskb))
 		goto copy_skb;
 
-	/* Alexey says IP hdr is always modifiable and linear, so ok. */
-	if (writable_len <= (*pskb)->nh.iph->ihl*4)
-		return 1;
-
-	iplen = writable_len - (*pskb)->nh.iph->ihl*4;
-
-	/* DaveM says protocol headers are also modifiable. */
-	switch ((*pskb)->nh.iph->protocol) {
-	case IPPROTO_TCP: {
-		struct tcphdr _hdr, *hp;
-		hp = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
-					sizeof(_hdr), &_hdr);
-		if (hp == NULL)
-			goto copy_skb;
-		if (writable_len <= (*pskb)->nh.iph->ihl*4 + hp->doff*4)
-			goto pull_skb;
-		goto copy_skb;
-	}
-	case IPPROTO_UDP:
-		if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
-			goto pull_skb;
-		goto copy_skb;
-	case IPPROTO_ICMP:
-		if (writable_len
-		    <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
-			goto pull_skb;
-		goto copy_skb;
-	/* Insert other cases here as desired */
-	}
+	return pskb_may_pull(*pskb, writable_len);
 
 copy_skb:
 	nskb = skb_copy(*pskb, GFP_ATOMIC);
@@ -730,9 +677,6 @@ copy_skb:
 	kfree_skb(*pskb);
 	*pskb = nskb;
 	return 1;
-
-pull_skb:
-	return pskb_may_pull(*pskb, writable_len);
 }
 EXPORT_SYMBOL(skb_ip_make_writable);
 #endif /*CONFIG_INET*/
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -18,7 +18,9 @@
 #include <linux/interrupt.h>
 #include <linux/netpoll.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/rcupdate.h>
+#include <linux/workqueue.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <asm/unaligned.h>
@@ -28,18 +30,19 @@
  * message gets out even in extreme OOM situations.
  */
 
-#define MAX_SKBS 32
 #define MAX_UDP_CHUNK 1460
+#define MAX_SKBS 32
+#define MAX_QUEUE_DEPTH (MAX_SKBS / 2)
 
 static DEFINE_SPINLOCK(skb_list_lock);
 static int nr_skbs;
 static struct sk_buff *skbs;
 
-static DEFINE_SPINLOCK(rx_list_lock);
-static LIST_HEAD(rx_list);
+static DEFINE_SPINLOCK(queue_lock);
+static int queue_depth;
+static struct sk_buff *queue_head, *queue_tail;
 
 static atomic_t trapped;
-static DEFINE_SPINLOCK(netpoll_poll_lock);
 
 #define NETPOLL_RX_ENABLED  1
 #define NETPOLL_RX_DROP     2
@@ -50,6 +53,50 @@ static DEFINE_SPINLOCK(netpoll_poll_lock
 
 static void zap_completion_queue(void);
 
+static void queue_process(void *p)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	while (queue_head) {
+		spin_lock_irqsave(&queue_lock, flags);
+
+		skb = queue_head;
+		queue_head = skb->next;
+		if (skb == queue_tail)
+			queue_head = NULL;
+
+		queue_depth--;
+
+		spin_unlock_irqrestore(&queue_lock, flags);
+
+		dev_queue_xmit(skb);
+	}
+}
+
+static DECLARE_WORK(send_queue, queue_process, NULL);
+
+void netpoll_queue(struct sk_buff *skb)
+{
+	unsigned long flags;
+
+	if (queue_depth == MAX_QUEUE_DEPTH) {
+		__kfree_skb(skb);
+		return;
+	}
+
+	spin_lock_irqsave(&queue_lock, flags);
+	if (!queue_head)
+		queue_head = skb;
+	else
+		queue_tail->next = skb;
+	queue_tail = skb;
+	queue_depth++;
+	spin_unlock_irqrestore(&queue_lock, flags);
+
+	schedule_work(&send_queue);
+}
+
 static int checksum_udp(struct sk_buff *skb, struct udphdr *uh,
 			     unsigned short ulen, u32 saddr, u32 daddr)
 {
@@ -66,8 +113,15 @@ static int checksum_udp(struct sk_buff *
 }
 
 /*
- * Check whether delayed processing was scheduled for our current CPU,
- * and then manually invoke NAPI polling to pump data off the card.
+ * Check whether delayed processing was scheduled for our NIC. If so,
+ * we attempt to grab the poll lock and use ->poll() to pump the card.
+ * If this fails, either we've recursed in ->poll() or it's already
+ * running on another CPU.
+ *
+ * Note: we don't mask interrupts with this lock because we're using
+ * trylock here and interrupts are already disabled in the softirq
+ * case. Further, we test the poll_owner to avoid recursion on UP
+ * systems where the lock doesn't exist.
  *
  * In cases where there is bi-directional communications, reading only
  * one message at a time can lead to packets being dropped by the
@@ -77,22 +131,19 @@ static int checksum_udp(struct sk_buff *
 static void poll_napi(struct netpoll *np)
 {
 	int budget = 16;
-	unsigned long flags;
-	struct softnet_data *queue;
 
-	spin_lock_irqsave(&netpoll_poll_lock, flags);
-	queue = &__get_cpu_var(softnet_data);
 	if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) &&
-	    !list_empty(&queue->poll_list)) {
-		np->dev->netpoll_rx |= NETPOLL_RX_DROP;
+	    np->poll_owner != smp_processor_id() &&
+	    spin_trylock(&np->poll_lock)) {
+		np->rx_flags |= NETPOLL_RX_DROP;
 		atomic_inc(&trapped);
 
 		np->dev->poll(np->dev, &budget);
 
 		atomic_dec(&trapped);
-		np->dev->netpoll_rx &= ~NETPOLL_RX_DROP;
+		np->rx_flags &= ~NETPOLL_RX_DROP;
+		spin_unlock(&np->poll_lock);
 	}
-	spin_unlock_irqrestore(&netpoll_poll_lock, flags);
 }
 
 void netpoll_poll(struct netpoll *np)
@@ -142,7 +193,10 @@ static void zap_completion_queue(void)
 		while (clist != NULL) {
 			struct sk_buff *skb = clist;
 			clist = clist->next;
-			__kfree_skb(skb);
+			if(skb->destructor)
+				dev_kfree_skb_any(skb); /* put this one back */
+			else
+				__kfree_skb(skb);
 		}
 	}
 
@@ -165,10 +219,11 @@ repeat:
 	if (!skb) {
 		spin_lock_irqsave(&skb_list_lock, flags);
 		skb = skbs;
-		if (skb)
+		if (skb) {
 			skbs = skb->next;
-		skb->next = NULL;
-		nr_skbs--;
+			skb->next = NULL;
+			nr_skbs--;
+		}
 		spin_unlock_irqrestore(&skb_list_lock, flags);
 	}
 
@@ -197,6 +252,16 @@ repeat:
 		return;
 	}
 
+	/* avoid recursion */
+	if(np->poll_owner == smp_processor_id() ||
+	   np->dev->xmit_lock_owner == smp_processor_id()) {
+		if (np->drop)
+			np->drop(skb);
+		else
+			__kfree_skb(skb);
+		return;
+	}
+
 	spin_lock(&np->dev->xmit_lock);
 	np->dev->xmit_lock_owner = smp_processor_id();
 
@@ -233,7 +298,7 @@ void netpoll_send_udp(struct netpoll *np
 
 	udp_len = len + sizeof(*udph);
 	ip_len = eth_len = udp_len + sizeof(*iph);
-	total_len = eth_len + ETH_HLEN;
+	total_len = eth_len + ETH_HLEN + NET_IP_ALIGN;
 
 	skb = find_skb(np, total_len, total_len - len);
 	if (!skb)
@@ -269,6 +334,8 @@ void netpoll_send_udp(struct netpoll *np
 	memcpy(eth->h_source, np->local_mac, 6);
 	memcpy(eth->h_dest, np->remote_mac, 6);
 
+	skb->dev = np->dev;
+
 	netpoll_send_skb(np, skb);
 }
 
@@ -279,18 +346,7 @@ static void arp_reply(struct sk_buff *sk
 	int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
 	u32 sip, tip;
 	struct sk_buff *send_skb;
-	unsigned long flags;
-	struct list_head *p;
-	struct netpoll *np = NULL;
-
-	spin_lock_irqsave(&rx_list_lock, flags);
-	list_for_each(p, &rx_list) {
-		np = list_entry(p, struct netpoll, rx_list);
-		if ( np->dev == skb->dev )
-			break;
-		np = NULL;
-	}
-	spin_unlock_irqrestore(&rx_list_lock, flags);
+	struct netpoll *np = skb->dev->np;
 
 	if (!np) return;
 
@@ -368,15 +424,15 @@ static void arp_reply(struct sk_buff *sk
 	netpoll_send_skb(np, send_skb);
 }
 
-int netpoll_rx(struct sk_buff *skb)
+int __netpoll_rx(struct sk_buff *skb)
 {
 	int proto, len, ulen;
 	struct iphdr *iph;
 	struct udphdr *uh;
-	struct netpoll *np;
-	struct list_head *p;
-	unsigned long flags;
+	struct netpoll *np = skb->dev->np;
 
+	if (!np->rx_hook)
+		goto out;
 	if (skb->dev->type != ARPHRD_ETHER)
 		goto out;
 
@@ -420,32 +476,27 @@ int netpoll_rx(struct sk_buff *skb)
 		goto out;
 	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0)
 		goto out;
+	if (np->local_ip && np->local_ip != ntohl(iph->daddr))
+		goto out;
+	if (np->remote_ip && np->remote_ip != ntohl(iph->saddr))
+		goto out;
+	if (np->local_port && np->local_port != ntohs(uh->dest))
+		goto out;
+
+	np->rx_hook(np, ntohs(uh->source),
+		    (char *)(uh+1),
+		    ulen - sizeof(struct udphdr));
 
-	spin_lock_irqsave(&rx_list_lock, flags);
-	list_for_each(p, &rx_list) {
-		np = list_entry(p, struct netpoll, rx_list);
-		if (np->dev && np->dev != skb->dev)
-			continue;
-		if (np->local_ip && np->local_ip != ntohl(iph->daddr))
-			continue;
-		if (np->remote_ip && np->remote_ip != ntohl(iph->saddr))
-			continue;
-		if (np->local_port && np->local_port != ntohs(uh->dest))
-			continue;
-
-		spin_unlock_irqrestore(&rx_list_lock, flags);
-
-		if (np->rx_hook)
-			np->rx_hook(np, ntohs(uh->source),
-				    (char *)(uh+1),
-				    ulen - sizeof(struct udphdr));
+	kfree_skb(skb);
+	return 1;
 
+out:
+	if (atomic_read(&trapped)) {
+		kfree_skb(skb);
 		return 1;
 	}
-	spin_unlock_irqrestore(&rx_list_lock, flags);
 
-out:
-	return atomic_read(&trapped);
+	return 0;
 }
 
 int netpoll_parse_options(struct netpoll *np, char *opt)
@@ -561,6 +612,9 @@ int netpoll_setup(struct netpoll *np)
 	struct net_device *ndev = NULL;
 	struct in_device *in_dev;
 
+	np->poll_lock = SPIN_LOCK_UNLOCKED;
+	np->poll_owner = -1;
+
 	if (np->dev_name)
 		ndev = dev_get_by_name(np->dev_name);
 	if (!ndev) {
@@ -568,6 +622,10 @@ int netpoll_setup(struct netpoll *np)
 		       np->name, np->dev_name);
 		return -1;
 	}
+
+	np->dev = ndev;
+	ndev->np = np;
+
 	if (!ndev->poll_controller) {
 		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
 		       np->name, np->dev_name);
@@ -575,16 +633,13 @@ int netpoll_setup(struct netpoll *np)
 	}
 
 	if (!netif_running(ndev)) {
-		unsigned short oflags;
 		unsigned long atmost, atleast;
 
 		printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
 		       np->name, np->dev_name);
 
-		oflags = ndev->flags;
-
 		rtnl_shlock();
-		if (dev_change_flags(ndev, oflags | IFF_UP) < 0) {
+		if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) {
 			printk(KERN_ERR "%s: failed to open %s\n",
 			       np->name, np->dev_name);
 			rtnl_shunlock();
@@ -593,7 +648,7 @@ int netpoll_setup(struct netpoll *np)
 		rtnl_shunlock();
 
 		atleast = jiffies + HZ/10;
- 		atmost = jiffies + 10*HZ;
+ 		atmost = jiffies + 4*HZ;
 		while (!netif_carrier_ok(ndev)) {
 			if (time_after(jiffies, atmost)) {
 				printk(KERN_NOTICE
@@ -604,12 +659,16 @@ int netpoll_setup(struct netpoll *np)
 			cond_resched();
 		}
 
+		/* If carrier appears to come up instantly, we don't
+		 * trust it and pause so that we don't pump all our
+		 * queued console messages into the bitbucket.
+		 */
+
 		if (time_before(jiffies, atleast)) {
-			printk(KERN_NOTICE "%s: carrier detect appears flaky,"
-			       " waiting 10 seconds\n",
+			printk(KERN_NOTICE "%s: carrier detect appears"
+			       " untrustworthy, waiting 4 seconds\n",
 			       np->name);
-			while (time_before(jiffies, atmost))
-				cond_resched();
+			msleep(4000);
 		}
 	}
 
@@ -633,36 +692,22 @@ int netpoll_setup(struct netpoll *np)
 		       np->name, HIPQUAD(np->local_ip));
 	}
 
-	np->dev = ndev;
-
-	if(np->rx_hook) {
-		unsigned long flags;
-
-		np->dev->netpoll_rx = NETPOLL_RX_ENABLED;
-
-		spin_lock_irqsave(&rx_list_lock, flags);
-		list_add(&np->rx_list, &rx_list);
-		spin_unlock_irqrestore(&rx_list_lock, flags);
-	}
+	if(np->rx_hook)
+		np->rx_flags = NETPOLL_RX_ENABLED;
 
 	return 0;
+
  release:
+	ndev->np = NULL;
+	np->dev = NULL;
 	dev_put(ndev);
 	return -1;
 }
 
 void netpoll_cleanup(struct netpoll *np)
 {
-	if (np->rx_hook) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&rx_list_lock, flags);
-		list_del(&np->rx_list);
-		spin_unlock_irqrestore(&rx_list_lock, flags);
-	}
-
 	if (np->dev)
-		np->dev->netpoll_rx = 0;
+		np->dev->np = NULL;
 	dev_put(np->dev);
 	np->dev = NULL;
 }
@@ -687,3 +732,4 @@ EXPORT_SYMBOL(netpoll_setup);
 EXPORT_SYMBOL(netpoll_cleanup);
 EXPORT_SYMBOL(netpoll_send_udp);
 EXPORT_SYMBOL(netpoll_poll);
+EXPORT_SYMBOL(netpoll_queue);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -151,7 +151,7 @@
 #include <asm/timex.h>
 
 
-#define VERSION  "pktgen v2.58: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.61: Packet Generator for packet performance testing.\n"
 
 /* #define PG_DEBUG(a) a */
 #define PG_DEBUG(a) 
@@ -1419,7 +1419,6 @@ static int proc_thread_write(struct file
 	if (debug) 
 		printk("pktgen: t=%s, count=%lu\n", name, count);
         
-	thread_lock();
 
         t = (struct pktgen_thread*)(data);
 	if(!t) {
@@ -1441,14 +1440,18 @@ static int proc_thread_write(struct file
 		if( copy_from_user(f, &user_buffer[i], len) )
 			return -EFAULT;
 		i += len;
+		thread_lock();
                 pktgen_add_device(t, f);
+		thread_unlock();
                 ret = count;
                 sprintf(pg_result, "OK: add_device=%s", f);
 		goto out;
 	}
 
         if (!strcmp(name, "rem_device_all")) {
+		thread_lock();
 		t->control |= T_REMDEV;
+		thread_unlock();
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(HZ/8);  /* Propagate thread->control  */
 		ret = count;
@@ -1456,10 +1459,11 @@ static int proc_thread_write(struct file
 		goto out;
 	}
 
-
         if (!strcmp(name, "max_before_softirq")) {
                 len = num_arg(&user_buffer[i], 10, &value);
+		thread_lock();
                 t->max_before_softirq = value;
+		thread_unlock();
                 ret = count;
                 sprintf(pg_result, "OK: max_before_softirq=%lu", value);
 		goto out;
@@ -1467,7 +1471,6 @@ static int proc_thread_write(struct file
 
 	ret = -EINVAL;
  out:
-	thread_unlock();
 
 	return ret;
 }
@@ -1682,7 +1685,7 @@ static void pktgen_setup_inject(struct p
 					pkt_dev->saddr_min = in_dev->ifa_list->ifa_address;
 					pkt_dev->saddr_max = pkt_dev->saddr_min;
 				}
-				in_dev_put(in_dev);	
+				__in_dev_put(in_dev);	
 			}
 			rcu_read_unlock();
 		}
@@ -2587,7 +2590,7 @@ static void pktgen_rem_thread(struct pkt
         thread_unlock();
 }
 
-__inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
+static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
 	struct net_device *odev = NULL;
 	__u64 idle_start = 0;
@@ -2651,7 +2654,6 @@ __inline__ void pktgen_xmit(struct pktge
 	
 	spin_lock_bh(&odev->xmit_lock);
 	if (!netif_queue_stopped(odev)) {
-		u64 now;
 
 		atomic_inc(&(pkt_dev->skb->users));
 retry_now:
@@ -2675,24 +2677,18 @@ retry_now:
 			
 			pkt_dev->errors++;
 			pkt_dev->last_ok = 0;
-			pkt_dev->next_tx_us = getCurUs(); /* TODO */
-			pkt_dev->next_tx_ns = 0;
 		}
 
+		pkt_dev->next_tx_us = getCurUs();
+		pkt_dev->next_tx_ns = 0;
+
 		pkt_dev->next_tx_us += pkt_dev->delay_us;
 		pkt_dev->next_tx_ns += pkt_dev->delay_ns;
+
 		if (pkt_dev->next_tx_ns > 1000) {
 			pkt_dev->next_tx_us++;
 			pkt_dev->next_tx_ns -= 1000;
 		}
-
-		now = getCurUs();
-		if (now > pkt_dev->next_tx_us) {
-			/* TODO: this code is slightly wonky.  */
-			pkt_dev->errors++;
-			pkt_dev->next_tx_us = now - pkt_dev->delay_us;
-			pkt_dev->next_tx_ns = 0;
-		}
 	} 
 
 	else {  /* Retry it next time */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
@@ -87,30 +86,33 @@ struct sock *rtnl;
 
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
-static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rtm_min[RTM_NR_FAMILIES] =
 {
-	NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-	NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
-	NLMSG_LENGTH(sizeof(struct rtmsg)),
-	NLMSG_LENGTH(sizeof(struct ndmsg)),
-	NLMSG_LENGTH(sizeof(struct rtmsg)),
-	NLMSG_LENGTH(sizeof(struct tcmsg)),
-	NLMSG_LENGTH(sizeof(struct tcmsg)),
-	NLMSG_LENGTH(sizeof(struct tcmsg)),
-	NLMSG_LENGTH(sizeof(struct tcamsg))
+	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+	[RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+	[RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)),
+	[RTM_FAM(RTM_NEWNEIGH)]     = NLMSG_LENGTH(sizeof(struct ndmsg)),
+	[RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct rtmsg)),
+	[RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)),
+	[RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)),
+	[RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)),
+	[RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)),
+	[RTM_FAM(RTM_NEWPREFIX)]    = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+	[RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+	[RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
 };
 
-static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rta_max[RTM_NR_FAMILIES] =
 {
-	IFLA_MAX,
-	IFA_MAX,
-	RTA_MAX,
-	NDA_MAX,
-	RTA_MAX,
-	TCA_MAX,
-	TCA_MAX,
-	TCA_MAX,
-	TCAA_MAX
+	[RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX,
+	[RTM_FAM(RTM_NEWADDR)]      = IFA_MAX,
+	[RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX,
+	[RTM_FAM(RTM_NEWNEIGH)]     = NDA_MAX,
+	[RTM_FAM(RTM_NEWRULE)]      = RTA_MAX,
+	[RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX,
+	[RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX,
+	[RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX,
+	[RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,
 };
 
 void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
@@ -607,27 +609,33 @@ static inline int rtnetlink_rcv_skb(stru
 
 /*
  *  rtnetlink input queue processing routine:
- *	- try to acquire shared lock. If it is failed, defer processing.
+ *	- process as much as there was in the queue upon entry.
  *	- feed skbs to rtnetlink_rcv_skb, until it refuse a message,
- *	  that will occur, when a dump started and/or acquisition of
- *	  exclusive lock failed.
+ *	  that will occur, when a dump started.
  */
 
 static void rtnetlink_rcv(struct sock *sk, int len)
 {
+	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
-			return;
+		rtnl_lock();
+
+		if (qlen > skb_queue_len(&sk->sk_receive_queue))
+			qlen = skb_queue_len(&sk->sk_receive_queue);
 
-		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+		for (; qlen; qlen--) {
+			skb = skb_dequeue(&sk->sk_receive_queue);
 			if (rtnetlink_rcv_skb(skb)) {
 				if (skb->len)
 					skb_queue_head(&sk->sk_receive_queue,
 						       skb);
-				else
+				else {
 					kfree_skb(skb);
+					qlen--;
+				}
 				break;
 			}
 			kfree_skb(skb);
@@ -636,10 +644,10 @@ static void rtnetlink_rcv(struct sock *s
 		up(&rtnl_sem);
 
 		netdev_run_todo();
-	} while (rtnl && rtnl->sk_receive_queue.qlen);
+	} while (qlen);
 }
 
-static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
 {
 	[RTM_GETLINK  - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
 	[RTM_SETLINK  - RTM_BASE] = { .doit   = do_setlink	      },
@@ -647,7 +655,8 @@ static struct rtnetlink_link link_rtnetl
 	[RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
 	[RTM_NEWNEIGH - RTM_BASE] = { .doit   = neigh_add	      },
 	[RTM_DELNEIGH - RTM_BASE] = { .doit   = neigh_delete	      },
-	[RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info	      }
+	[RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info	      },
+	[RTM_GETRULE  - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
 };
 
 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
diff --git a/net/core/scm.c b/net/core/scm.c
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -15,7 +15,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/socket.h>
 #include <linux/file.h>
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -86,8 +86,10 @@ static kmem_cache_t *skbuff_head_cache;
  */
 void skb_over_panic(struct sk_buff *skb, int sz, void *here)
 {
-	printk(KERN_INFO "skput:over: %p:%d put:%d dev:%s",
-		here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+	printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "
+	                  "data:%p tail:%p end:%p dev:%s\n",
+	       here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end,
+	       skb->dev ? skb->dev->name : "<NULL>");
 	BUG();
 }
 
@@ -102,8 +104,10 @@ void skb_over_panic(struct sk_buff *skb,
 
 void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
-	printk(KERN_INFO "skput:under: %p:%d put:%d dev:%s",
-               here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+	printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "
+	                  "data:%p tail:%p end:%p dev:%s\n",
+	       here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end,
+	       skb->dev ? skb->dev->name : "<NULL>");
 	BUG();
 }
 
@@ -241,7 +245,8 @@ static void skb_clone_fraglist(struct sk
 void skb_release_data(struct sk_buff *skb)
 {
 	if (!skb->cloned ||
-	    atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) {
+	    !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,
+			       &skb_shinfo(skb)->dataref)) {
 		if (skb_shinfo(skb)->nr_frags) {
 			int i;
 			for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
@@ -275,20 +280,14 @@ void kfree_skbmem(struct sk_buff *skb)
 
 void __kfree_skb(struct sk_buff *skb)
 {
-	if (skb->list) {
-	 	printk(KERN_WARNING "Warning: kfree_skb passed an skb still "
-		       "on a list (from %p).\n", NET_CALLER(skb));
-		BUG();
-	}
+	BUG_ON(skb->list != NULL);
 
 	dst_release(skb->dst);
 #ifdef CONFIG_XFRM
 	secpath_put(skb->sp);
 #endif
-	if(skb->destructor) {
-		if (in_irq())
-			printk(KERN_WARNING "Warning: kfree_skb on "
-					    "hard IRQ %p\n", NET_CALLER(skb));
+	if (skb->destructor) {
+		WARN_ON(in_irq());
 		skb->destructor(skb);
 	}
 #ifdef CONFIG_NETFILTER
@@ -353,6 +352,7 @@ struct sk_buff *skb_clone(struct sk_buff
 	C(csum);
 	C(local_df);
 	n->cloned = 1;
+	n->nohdr = 0;
 	C(pkt_type);
 	C(ip_summed);
 	C(priority);
@@ -604,6 +604,7 @@ int pskb_expand_head(struct sk_buff *skb
 	skb->h.raw   += off;
 	skb->nh.raw  += off;
 	skb->cloned   = 0;
+	skb->nohdr    = 0;
 	atomic_set(&skb_shinfo(skb)->dataref, 1);
 	return 0;
 
@@ -982,70 +983,94 @@ fault:
 	return -EFAULT;
 }
 
-/* Keep iterating until skb_iter_next returns false. */
-void skb_iter_first(const struct sk_buff *skb, struct skb_iter *i)
+/**
+ *	skb_store_bits - store bits from kernel buffer to skb
+ *	@skb: destination buffer
+ *	@offset: offset in destination
+ *	@from: source buffer
+ *	@len: number of bytes to copy
+ *
+ *	Copy the specified number of bytes from the source buffer to the
+ *	destination skb.  This function handles all the messy bits of
+ *	traversing fragment lists and such.
+ */
+
+int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len)
 {
-	i->len = skb_headlen(skb);
-	i->data = (unsigned char *)skb->data;
-	i->nextfrag = 0;
-	i->fraglist = NULL;
-}
-
-int skb_iter_next(const struct sk_buff *skb, struct skb_iter *i)
-{
-	/* Unmap previous, if not head fragment. */
-	if (i->nextfrag)
-		kunmap_skb_frag(i->data);
-
-	if (i->fraglist) {
-	fraglist:
-		/* We're iterating through fraglist. */
-		if (i->nextfrag < skb_shinfo(i->fraglist)->nr_frags) {
-			i->data = kmap_skb_frag(&skb_shinfo(i->fraglist)
-						->frags[i->nextfrag]);
-			i->len = skb_shinfo(i->fraglist)->frags[i->nextfrag]
-				.size;
-			i->nextfrag++;
-			return 1;
+	int i, copy;
+	int start = skb_headlen(skb);
+
+	if (offset > (int)skb->len - len)
+		goto fault;
+
+	if ((copy = start - offset) > 0) {
+		if (copy > len)
+			copy = len;
+		memcpy(skb->data + offset, from, copy);
+		if ((len -= copy) == 0)
+			return 0;
+		offset += copy;
+		from += copy;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+		int end;
+
+		BUG_TRAP(start <= offset + len);
+
+		end = start + frag->size;
+		if ((copy = end - offset) > 0) {
+			u8 *vaddr;
+
+			if (copy > len)
+				copy = len;
+
+			vaddr = kmap_skb_frag(frag);
+			memcpy(vaddr + frag->page_offset + offset - start,
+			       from, copy);
+			kunmap_skb_frag(vaddr);
+
+			if ((len -= copy) == 0)
+				return 0;
+			offset += copy;
+			from += copy;
 		}
-		/* Fragments with fragments?  Too hard! */
-		BUG_ON(skb_shinfo(i->fraglist)->frag_list);
-		i->fraglist = i->fraglist->next;
-		if (!i->fraglist)
-			goto end;
-
-		i->len = skb_headlen(i->fraglist);
-		i->data = i->fraglist->data;
-		i->nextfrag = 0;
-		return 1;
-	}
-
-	if (i->nextfrag < skb_shinfo(skb)->nr_frags) {
-		i->data = kmap_skb_frag(&skb_shinfo(skb)->frags[i->nextfrag]);
-		i->len = skb_shinfo(skb)->frags[i->nextfrag].size;
-		i->nextfrag++;
-		return 1;
-	}
-
-	i->fraglist = skb_shinfo(skb)->frag_list;
-	if (i->fraglist)
-		goto fraglist;
-
-end:
-	/* Bug trap for callers */
-	i->data = NULL;
-	return 0;
-}
+		start = end;
+	}
 
-void skb_iter_abort(const struct sk_buff *skb, struct skb_iter *i)
-{
-	/* Unmap previous, if not head fragment. */
-	if (i->data && i->nextfrag)
-		kunmap_skb_frag(i->data);
-	/* Bug trap for callers */
-	i->data = NULL;
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+		for (; list; list = list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
+			if ((copy = end - offset) > 0) {
+				if (copy > len)
+					copy = len;
+				if (skb_store_bits(list, offset - start,
+						   from, copy))
+					goto fault;
+				if ((len -= copy) == 0)
+					return 0;
+				offset += copy;
+				from += copy;
+			}
+			start = end;
+		}
+	}
+	if (!len)
+		return 0;
+
+fault:
+	return -EFAULT;
 }
 
+EXPORT_SYMBOL(skb_store_bits);
+
 /* Checksum skb data. */
 
 unsigned int skb_checksum(const struct sk_buff *skb, int offset,
@@ -1444,7 +1469,7 @@ static inline void skb_split_no_header(s
 
 			if (pos < len) {
 				/* Split frag.
-				 * We have to variants in this case:
+				 * We have two variants in this case:
 				 * 1. Move all the frag to the second
 				 *    part, if it is possible. F.e.
 				 *    this approach is mandatory for TUX,
@@ -1467,6 +1492,9 @@ static inline void skb_split_no_header(s
 
 /**
  * skb_split - Split fragmented skb to two parts at length len.
+ * @skb: the buffer to split
+ * @skb1: the buffer to receive the second part
+ * @len: new length for skb
  */
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
 {
@@ -1516,6 +1544,3 @@ EXPORT_SYMBOL(skb_queue_tail);
 EXPORT_SYMBOL(skb_unlink);
 EXPORT_SYMBOL(skb_append);
 EXPORT_SYMBOL(skb_split);
-EXPORT_SYMBOL(skb_iter_first);
-EXPORT_SYMBOL(skb_iter_next);
-EXPORT_SYMBOL(skb_iter_abort);
diff --git a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -9,7 +9,7 @@
  *
  * Version:	$Id: sock.c,v 1.117 2002/02/01 22:01:03 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Florian La Roche, <flla@stud.uni-sb.de>
  *		Alan Cox, <A.Cox@swansea.ac.uk>
@@ -97,8 +97,9 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
@@ -228,8 +229,10 @@ int sock_setsockopt(struct socket *sock,
 			{
 				ret = -EACCES;
 			}
+			else if (valbool)
+				sock_set_flag(sk, SOCK_DBG);
 			else
-				sk->sk_debug = valbool;
+				sock_reset_flag(sk, SOCK_DBG);
 			break;
 		case SO_REUSEADDR:
 			sk->sk_reuse = valbool;
@@ -239,7 +242,10 @@ int sock_setsockopt(struct socket *sock,
 			ret = -ENOPROTOOPT;
 		  	break;
 		case SO_DONTROUTE:
-			sk->sk_localroute = valbool;
+			if (valbool)
+				sock_set_flag(sk, SOCK_LOCALROUTE);
+			else
+				sock_reset_flag(sk, SOCK_LOCALROUTE);
 			break;
 		case SO_BROADCAST:
 			sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
@@ -333,13 +339,18 @@ int sock_setsockopt(struct socket *sock,
 			break;
 
 		case SO_PASSCRED:
-			sock->passcred = valbool;
+			if (valbool)
+				set_bit(SOCK_PASSCRED, &sock->flags);
+			else
+				clear_bit(SOCK_PASSCRED, &sock->flags);
 			break;
 
 		case SO_TIMESTAMP:
-			sk->sk_rcvtstamp = valbool;
-			if (valbool) 
+			if (valbool)  {
+				sock_set_flag(sk, SOCK_RCVTSTAMP);
 				sock_enable_timestamp(sk);
+			} else
+				sock_reset_flag(sk, SOCK_RCVTSTAMP);
 			break;
 
 		case SO_RCVLOWAT:
@@ -463,11 +474,11 @@ int sock_getsockopt(struct socket *sock,
   	switch(optname) 
   	{
 		case SO_DEBUG:		
-			v.val = sk->sk_debug;
+			v.val = sock_flag(sk, SOCK_DBG);
 			break;
 		
 		case SO_DONTROUTE:
-			v.val = sk->sk_localroute;
+			v.val = sock_flag(sk, SOCK_LOCALROUTE);
 			break;
 		
 		case SO_BROADCAST:
@@ -523,7 +534,7 @@ int sock_getsockopt(struct socket *sock,
 			break;
 
 		case SO_TIMESTAMP:
-			v.val = sk->sk_rcvtstamp;
+			v.val = sock_flag(sk, SOCK_RCVTSTAMP);
 			break;
 
 		case SO_RCVTIMEO:
@@ -557,7 +568,7 @@ int sock_getsockopt(struct socket *sock,
 			break; 
 
 		case SO_PASSCRED:
-			v.val = sock->passcred;
+			v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
 			break;
 
 		case SO_PEERCRED:
@@ -603,40 +614,43 @@ lenout:
   	return 0;
 }
 
-static kmem_cache_t *sk_cachep;
-
 /**
  *	sk_alloc - All socket objects are allocated here
- *	@family - protocol family
- *	@priority - for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
- *	@zero_it - zeroes the allocated sock
- *	@slab - alternate slab
- *
- *	All socket objects are allocated here. If @zero_it is non-zero
- *	it should have the size of the are to be zeroed, because the
- *	private slabcaches have different sizes of the generic struct sock.
- *	1 has been kept as a way to say sizeof(struct sock).
+ *	@family: protocol family
+ *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ *	@prot: struct proto associated with this new sock instance
+ *	@zero_it: if we should zero the newly allocated sock
  */
-struct sock *sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab)
+struct sock *sk_alloc(int family, int priority, struct proto *prot, int zero_it)
 {
 	struct sock *sk = NULL;
+	kmem_cache_t *slab = prot->slab;
+
+	if (slab != NULL)
+		sk = kmem_cache_alloc(slab, priority);
+	else
+		sk = kmalloc(prot->obj_size, priority);
 
-	if (!slab)
-		slab = sk_cachep;
-	sk = kmem_cache_alloc(slab, priority);
 	if (sk) {
 		if (zero_it) {
-			memset(sk, 0,
-			       zero_it == 1 ? sizeof(struct sock) : zero_it);
+			memset(sk, 0, prot->obj_size);
 			sk->sk_family = family;
+			/*
+			 * See comment in struct sock definition to understand
+			 * why we need sk_prot_creator -acme
+			 */
+			sk->sk_prot = sk->sk_prot_creator = prot;
 			sock_lock_init(sk);
 		}
-		sk->sk_slab = slab;
 		
 		if (security_sk_alloc(sk, family, priority)) {
-			kmem_cache_free(slab, sk);
+			if (slab != NULL)
+				kmem_cache_free(slab, sk);
+			else
+				kfree(sk);
 			sk = NULL;
-		}
+		} else
+			__module_get(prot->owner);
 	}
 	return sk;
 }
@@ -644,7 +658,7 @@ struct sock *sk_alloc(int family, int pr
 void sk_free(struct sock *sk)
 {
 	struct sk_filter *filter;
-	struct module *owner = sk->sk_owner;
+	struct module *owner = sk->sk_prot_creator->owner;
 
 	if (sk->sk_destruct)
 		sk->sk_destruct(sk);
@@ -662,17 +676,15 @@ void sk_free(struct sock *sk)
 		       __FUNCTION__, atomic_read(&sk->sk_omem_alloc));
 
 	security_sk_free(sk);
-	kmem_cache_free(sk->sk_slab, sk);
+	if (sk->sk_prot_creator->slab != NULL)
+		kmem_cache_free(sk->sk_prot_creator->slab, sk);
+	else
+		kfree(sk);
 	module_put(owner);
 }
 
 void __init sk_init(void)
 {
-	sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
-				      SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!sk_cachep)
-		printk(KERN_CRIT "sk_init: Cannot create sock SLAB cache!");
-
 	if (num_physpages <= 4096) {
 		sysctl_wmem_max = 32767;
 		sysctl_rmem_max = 32767;
@@ -698,7 +710,7 @@ void sock_wfree(struct sk_buff *skb)
 
 	/* In case it might be waiting for more memory. */
 	atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
-	if (!sk->sk_use_write_queue)
+	if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
 		sk->sk_write_space(sk);
 	sock_put(sk);
 }
@@ -962,8 +974,8 @@ static void __release_sock(struct sock *
 
 /**
  * sk_wait_data - wait for data to arrive at sk_receive_queue
- * sk - sock to wait on
- * timeo - for how long
+ * @sk:    sock to wait on
+ * @timeo: for how long
  *
  * Now socket state including sk->sk_err is changed only under lock,
  * hence we may omit checks after joining wait queue.
@@ -1175,9 +1187,10 @@ void sock_init_data(struct socket *sock,
 	sk->sk_rcvbuf		=	sysctl_rmem_default;
 	sk->sk_sndbuf		=	sysctl_wmem_default;
 	sk->sk_state		=	TCP_CLOSE;
-	sk->sk_zapped		=	1;
 	sk->sk_socket		=	sock;
 
+	sock_set_flag(sk, SOCK_ZAPPED);
+
 	if(sock)
 	{
 		sk->sk_type	=	sock->type;
@@ -1205,7 +1218,6 @@ void sock_init_data(struct socket *sock,
 	sk->sk_rcvlowat		=	1;
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
-	sk->sk_owner		=	NULL;
 
 	sk->sk_stamp.tv_sec     = -1L;
 	sk->sk_stamp.tv_usec    = -1L;
@@ -1346,26 +1358,182 @@ void sk_common_release(struct sock *sk)
 
 EXPORT_SYMBOL(sk_common_release);
 
-int sk_alloc_slab(struct proto *prot, char *name)
+static DEFINE_RWLOCK(proto_list_lock);
+static LIST_HEAD(proto_list);
+
+int proto_register(struct proto *prot, int alloc_slab)
 {
-	prot->slab = kmem_cache_create(name,
-				       prot->slab_obj_size, 0,
-				       SLAB_HWCACHE_ALIGN, NULL, NULL);
+	int rc = -ENOBUFS;
+
+	if (alloc_slab) {
+		prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
+					       SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+		if (prot->slab == NULL) {
+			printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
+			       prot->name);
+			goto out;
+		}
+	}
 
-	return prot->slab != NULL ? 0 : -ENOBUFS;
+	write_lock(&proto_list_lock);
+	list_add(&prot->node, &proto_list);
+	write_unlock(&proto_list_lock);
+	rc = 0;
+out:
+	return rc;
 }
 
-EXPORT_SYMBOL(sk_alloc_slab);
+EXPORT_SYMBOL(proto_register);
 
-void sk_free_slab(struct proto *prot)
+void proto_unregister(struct proto *prot)
 {
+	write_lock(&proto_list_lock);
+
 	if (prot->slab != NULL) {
 		kmem_cache_destroy(prot->slab);
 		prot->slab = NULL;
 	}
+
+	list_del(&prot->node);
+	write_unlock(&proto_list_lock);
+}
+
+EXPORT_SYMBOL(proto_unregister);
+
+#ifdef CONFIG_PROC_FS
+static inline struct proto *__proto_head(void)
+{
+	return list_entry(proto_list.next, struct proto, node);
+}
+
+static inline struct proto *proto_head(void)
+{
+	return list_empty(&proto_list) ? NULL : __proto_head();
+}
+
+static inline struct proto *proto_next(struct proto *proto)
+{
+	return proto->node.next == &proto_list ? NULL :
+		list_entry(proto->node.next, struct proto, node);
+}
+
+static inline struct proto *proto_get_idx(loff_t pos)
+{
+	struct proto *proto;
+	loff_t i = 0;
+
+	list_for_each_entry(proto, &proto_list, node)
+		if (i++ == pos)
+			goto out;
+
+	proto = NULL;
+out:
+	return proto;
+}
+
+static void *proto_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	read_lock(&proto_list_lock);
+	return *pos ? proto_get_idx(*pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+	return v == SEQ_START_TOKEN ? proto_head() : proto_next(v);
+}
+
+static void proto_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&proto_list_lock);
 }
 
-EXPORT_SYMBOL(sk_free_slab);
+static char proto_method_implemented(const void *method)
+{
+	return method == NULL ? 'n' : 'y';
+}
+
+static void proto_seq_printf(struct seq_file *seq, struct proto *proto)
+{
+	seq_printf(seq, "%-9s %4u %6d  %6d   %-3s %6u   %-3s  %-10s "
+			"%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n",
+		   proto->name,
+		   proto->obj_size,
+		   proto->sockets_allocated != NULL ? atomic_read(proto->sockets_allocated) : -1,
+		   proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1,
+		   proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI",
+		   proto->max_header,
+		   proto->slab == NULL ? "no" : "yes",
+		   module_name(proto->owner),
+		   proto_method_implemented(proto->close),
+		   proto_method_implemented(proto->connect),
+		   proto_method_implemented(proto->disconnect),
+		   proto_method_implemented(proto->accept),
+		   proto_method_implemented(proto->ioctl),
+		   proto_method_implemented(proto->init),
+		   proto_method_implemented(proto->destroy),
+		   proto_method_implemented(proto->shutdown),
+		   proto_method_implemented(proto->setsockopt),
+		   proto_method_implemented(proto->getsockopt),
+		   proto_method_implemented(proto->sendmsg),
+		   proto_method_implemented(proto->recvmsg),
+		   proto_method_implemented(proto->sendpage),
+		   proto_method_implemented(proto->bind),
+		   proto_method_implemented(proto->backlog_rcv),
+		   proto_method_implemented(proto->hash),
+		   proto_method_implemented(proto->unhash),
+		   proto_method_implemented(proto->get_port),
+		   proto_method_implemented(proto->enter_memory_pressure));
+}
+
+static int proto_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN)
+		seq_printf(seq, "%-9s %-4s %-8s %-6s %-5s %-7s %-4s %-10s %s",
+			   "protocol",
+			   "size",
+			   "sockets",
+			   "memory",
+			   "press",
+			   "maxhdr",
+			   "slab",
+			   "module",
+			   "cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n");
+	else
+		proto_seq_printf(seq, v);
+	return 0;
+}
+
+static struct seq_operations proto_seq_ops = {
+	.start  = proto_seq_start,
+	.next   = proto_seq_next,
+	.stop   = proto_seq_stop,
+	.show   = proto_seq_show,
+};
+
+static int proto_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &proto_seq_ops);
+}
+
+static struct file_operations proto_seq_fops = {
+	.owner		= THIS_MODULE,
+	.open		= proto_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int __init proto_init(void)
+{
+	/* register /proc/net/protocols */
+	return proc_net_fops_create("protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0;
+}
+
+subsys_initcall(proto_init);
+
+#endif /* PROC_FS */
 
 EXPORT_SYMBOL(sk_alloc);
 EXPORT_SYMBOL(sk_free);
diff --git a/net/core/stream.c b/net/core/stream.c
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -21,7 +21,7 @@
 
 /**
  * sk_stream_write_space - stream socket write_space callback.
- * sk - socket
+ * @sk: socket
  *
  * FIXME: write proper description
  */
@@ -43,8 +43,8 @@ EXPORT_SYMBOL(sk_stream_write_space);
 
 /**
  * sk_stream_wait_connect - Wait for a socket to get into the connected state
- * @sk - sock to wait on
- * @timeo_p - for how long to wait
+ * @sk: sock to wait on
+ * @timeo_p: for how long to wait
  *
  * Must be called with the socket locked.
  */
@@ -79,7 +79,7 @@ EXPORT_SYMBOL(sk_stream_wait_connect);
 
 /**
  * sk_stream_closing - Return 1 if we still have things to send in our buffers.
- * @sk - socket to verify
+ * @sk: socket to verify
  */
 static inline int sk_stream_closing(struct sock *sk)
 {
@@ -107,8 +107,8 @@ EXPORT_SYMBOL(sk_stream_wait_close);
 
 /**
  * sk_stream_wait_memory - Wait for more memory for a socket
- * @sk - socket to wait for memory
- * @timeo_p - for how long
+ * @sk: socket to wait for memory
+ * @timeo_p: for how long
  */
 int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
 {
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -149,7 +149,6 @@ static void dn_keepalive(struct sock *sk
 #define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
 
 
-static kmem_cache_t *dn_sk_cachep;
 static struct proto_ops dn_proto_ops;
 static DEFINE_RWLOCK(dn_hash_lock);
 static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
@@ -447,21 +446,23 @@ static void dn_destruct(struct sock *sk)
 	dst_release(xchg(&sk->sk_dst_cache, NULL));
 }
 
+static struct proto dn_proto = {
+	.name	  = "DECNET",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct dn_sock),
+};
+
 static struct sock *dn_alloc_sock(struct socket *sock, int gfp)
 {
 	struct dn_scp *scp;
-	struct sock *sk = sk_alloc(PF_DECnet, gfp, sizeof(struct dn_sock),
-				   dn_sk_cachep);
+	struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1);
 
 	if  (!sk)
 		goto out;
 
-	sk->sk_protinfo = scp = (struct dn_scp *)(sk + 1);
-
 	if (sock)
 		sock->ops = &dn_proto_ops;
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sk->sk_backlog_rcv = dn_nsp_backlog_rcv;
 	sk->sk_destruct    = dn_destruct;
@@ -471,6 +472,7 @@ static struct sock *dn_alloc_sock(struct
 	sk->sk_allocation  = gfp;
 
 	/* Initialization of DECnet Session Control Port		*/
+	scp = DN_SK(sk);
 	scp->state	= DN_O;		/* Open			*/
 	scp->numdat	= 1;		/* Next data seg to tx	*/
 	scp->numoth	= 1;		/* Next oth data to tx  */
@@ -751,14 +753,13 @@ static int dn_bind(struct socket *sock, 
 
 	rv = -EINVAL;
 	lock_sock(sk);
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		memcpy(&scp->addr, saddr, addr_len);
-		sk->sk_zapped = 0;
+		sock_reset_flag(sk, SOCK_ZAPPED);
 
 		rv = dn_hash_sock(sk);
-		if (rv) {
-			sk->sk_zapped = 1;
-		}
+		if (rv)
+			sock_set_flag(sk, SOCK_ZAPPED);
 	}
 	release_sock(sk);
 
@@ -772,7 +773,7 @@ static int dn_auto_bind(struct socket *s
 	struct dn_scp *scp = DN_SK(sk);
 	int rv;
 
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 
 	scp->addr.sdn_flags  = 0;
 	scp->addr.sdn_objnum = 0;
@@ -796,9 +797,8 @@ static int dn_auto_bind(struct socket *s
 	rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
 	if (rv == 0) {
 		rv = dn_hash_sock(sk);
-		if (rv) {
-			sk->sk_zapped = 1;
-		}
+		if (rv)
+			sock_set_flag(sk, SOCK_ZAPPED);
 	}
 
 	return rv;
@@ -814,7 +814,7 @@ static int dn_confirm_accept(struct sock
 		return -EINVAL;
 
 	scp->state = DN_CC;
-	scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS);
+	scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS);
 	dn_send_conn_conf(sk, allocation);
 
 	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
@@ -923,7 +923,7 @@ static int __dn_connect(struct sock *sk,
 	if (addr->sdn_flags & SDF_WILD)
 		goto out;
 
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		err = dn_auto_bind(sk->sk_socket);
 		if (err)
 			goto out;
@@ -943,7 +943,7 @@ static int __dn_connect(struct sock *sk,
 	sk->sk_route_caps = sk->sk_dst_cache->dev->features;
 	sock->state = SS_CONNECTING;
 	scp->state = DN_CI;
-	scp->segsize_loc = dst_path_metric(sk->sk_dst_cache, RTAX_ADVMSS);
+	scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS);
 
 	dn_nsp_send_conninit(sk, NSP_CI);
 	err = -EINPROGRESS;
@@ -1142,7 +1142,7 @@ static int dn_accept(struct socket *sock
 	lock_sock(newsk);
 	err = dn_hash_sock(newsk);
 	if (err == 0) {
-		newsk->sk_zapped = 0;
+		sock_reset_flag(newsk, SOCK_ZAPPED);
 		dn_send_conn_ack(newsk);
 
 		/*
@@ -1260,7 +1260,7 @@ static int dn_listen(struct socket *sock
 
 	lock_sock(sk);
 
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 
 	if ((DN_SK(sk)->state != DN_O) || (sk->sk_state == TCP_LISTEN))
@@ -1672,7 +1672,7 @@ static int dn_recvmsg(struct kiocb *iocb
 
 	lock_sock(sk);
 
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		rv = -EADDRNOTAVAIL;
 		goto out;
 	}
@@ -1869,7 +1869,7 @@ static inline unsigned int dn_current_ms
 
 	/* This works out the maximum size of segment we can send out */
 	if (dst) {
-		u32 mtu = dst_pmtu(dst);
+		u32 mtu = dst_mtu(dst);
 		mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now);
 	}
 
@@ -2352,14 +2352,13 @@ static char banner[] __initdata = KERN_I
 
 static int __init decnet_init(void)
 {
+	int rc;
+
         printk(banner);
 
-	dn_sk_cachep = kmem_cache_create("decnet_socket_cache",
-					 sizeof(struct dn_sock),
-					 0, SLAB_HWCACHE_ALIGN,
-					 NULL, NULL);
-	if (!dn_sk_cachep)
-		return -ENOMEM;
+	rc = proto_register(&dn_proto, 1);
+	if (rc != 0)
+		goto out;
 
 	dn_neigh_init();
 	dn_dev_init();
@@ -2372,8 +2371,8 @@ static int __init decnet_init(void)
 
 	proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
 	dn_register_sysctl();
-
-	return 0;
+out:
+	return rc;
 
 }
 module_init(decnet_init);
@@ -2400,7 +2399,7 @@ static void __exit decnet_exit(void)
 
 	proc_net_remove("decnet");
 
-	kmem_cache_destroy(dn_sk_cachep);
+	proto_unregister(&dn_proto);
 }
 module_exit(decnet_exit);
 #endif
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -1411,21 +1411,22 @@ static struct file_operations dn_dev_seq
 
 #endif /* CONFIG_PROC_FS */
 
-static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
+static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =
 {
-	 [4] = { .doit   = dn_dev_rtm_newaddr,	},
-	 [5] = { .doit   = dn_dev_rtm_deladdr,	},
-	 [6] = { .dumpit = dn_dev_dump_ifaddr,	},
-
+	[RTM_NEWADDR  - RTM_BASE] = { .doit	= dn_dev_rtm_newaddr,	},
+	[RTM_DELADDR  - RTM_BASE] = { .doit	= dn_dev_rtm_deladdr,	},
+	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= dn_dev_dump_ifaddr,	},
 #ifdef CONFIG_DECNET_ROUTER
-	 [8] = { .doit   = dn_fib_rtm_newroute,	},
-	 [9] = { .doit   = dn_fib_rtm_delroute,	},
-	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_fib_dump, },
-	[16] = { .doit   = dn_fib_rtm_newrule, },
-	[17] = { .doit   = dn_fib_rtm_delrule, },
-	[18] = { .dumpit = dn_fib_dump_rules,  },
+	[RTM_NEWROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_newroute,	},
+	[RTM_DELROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_delroute,	},
+	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute,
+				      .dumpit	= dn_fib_dump,		},
+	[RTM_NEWRULE  - RTM_BASE] = { .doit	= dn_fib_rtm_newrule,	},
+	[RTM_DELRULE  - RTM_BASE] = { .doit	= dn_fib_rtm_delrule,	},
+	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= dn_fib_dump_rules,	},
 #else
-	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_cache_dump, },
+	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute,
+				      .dumpit	= dn_cache_dump,	},
 #endif
 
 };
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -324,7 +324,7 @@ err_out:
 
 static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb)
 {
-	if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) {
+	if (sk_acceptq_is_full(sk)) {
 		kfree_skb(skb);
 		return;
 	}
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -253,7 +253,6 @@ static void dn_dst_update_pmtu(struct ds
  */
 static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
 {
-	dst_release(dst);
 	return NULL;
 }
 
@@ -818,7 +817,7 @@ static int dn_rt_set_next_hop(struct dn_
 	if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || 
             rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu)
 		rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
-	mss = dn_mss_from_pmtu(dev, dst_pmtu(&rt->u.dst));
+	mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
 	if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 ||
 	    rt->u.dst.metrics[RTAX_ADVMSS-1] > mss)
 		rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -119,8 +119,9 @@ static inline void dnrmg_receive_user_sk
 static void dnrmg_receive_user_sk(struct sock *sk, int len)
 {
 	struct sk_buff *skb;
+	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
 
-	while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+	for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) {
 		dnrmg_receive_user_skb(skb);
 		kfree_skb(skb);
 	}
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -184,7 +184,7 @@ static int econet_bind(struct socket *so
 {
 	struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
 	struct sock *sk=sock->sk;
-	struct econet_opt *eo = ec_sk(sk);
+	struct econet_sock *eo = ec_sk(sk);
 	
 	/*
 	 *	Check legality
@@ -284,7 +284,7 @@ static int econet_sendmsg(struct kiocb *
 	 */
 	 
 	if (saddr == NULL) {
-		struct econet_opt *eo = ec_sk(sk);
+		struct econet_sock *eo = ec_sk(sk);
 
 		addr.station = eo->station;
 		addr.net     = eo->net;
@@ -437,8 +437,8 @@ static int econet_sendmsg(struct kiocb *
 		void __user *base = msg->msg_iov[i].iov_base;
 		size_t len = msg->msg_iov[i].iov_len;
 		/* Check it now since we switch to KERNEL_DS later. */
-		if ((err = verify_area(VERIFY_READ, base, len)) < 0)
-			return err;
+		if (!access_ok(VERIFY_READ, base, len))
+			return -EFAULT;
 		iov[i+1].iov_base = base;
 		iov[i+1].iov_len = len;
 		size += len;
@@ -485,7 +485,7 @@ static int econet_getname(struct socket 
 			  int *uaddr_len, int peer)
 {
 	struct sock *sk = sock->sk;
-	struct econet_opt *eo = ec_sk(sk);
+	struct econet_sock *eo = ec_sk(sk);
 	struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
 
 	if (peer)
@@ -555,6 +555,12 @@ static int econet_release(struct socket 
 	return 0;
 }
 
+static struct proto econet_proto = {
+	.name	  = "ECONET",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct econet_sock),
+};
+
 /*
  *	Create an Econet socket
  */
@@ -562,7 +568,7 @@ static int econet_release(struct socket 
 static int econet_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct econet_opt *eo;
+	struct econet_sock *eo;
 	int err;
 
 	/* Econet only provides datagram services. */
@@ -572,28 +578,21 @@ static int econet_create(struct socket *
 	sock->state = SS_UNCONNECTED;
 
 	err = -ENOBUFS;
-	sk = sk_alloc(PF_ECONET, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_ECONET, GFP_KERNEL, &econet_proto, 1);
 	if (sk == NULL)
 		goto out;
 
 	sk->sk_reuse = 1;
 	sock->ops = &econet_ops;
-	sock_init_data(sock,sk);
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
-	eo = sk->sk_protinfo = kmalloc(sizeof(*eo), GFP_KERNEL);
-	if (!eo)
-		goto out_free;
-	memset(eo, 0, sizeof(*eo));
-	sk->sk_zapped = 0;
+	eo = ec_sk(sk);
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	sk->sk_family = PF_ECONET;
 	eo->num = protocol;
 
 	econet_insert_socket(&econet_sklist, sk);
 	return(0);
-
-out_free:
-	sk_free(sk);
 out:
 	return err;
 }
@@ -735,7 +734,7 @@ static struct sock *ec_listening_socket(
 	struct hlist_node *node;
 
 	sk_for_each(sk, node, &econet_sklist) {
-		struct econet_opt *opt = ec_sk(sk);
+		struct econet_sock *opt = ec_sk(sk);
 		if ((opt->port == port || opt->port == 0) && 
 		    (opt->station == station || opt->station == 0) &&
 		    (opt->net == net || opt->net == 0))
@@ -1101,10 +1100,15 @@ static void __exit econet_proto_exit(voi
 #endif
 	unregister_netdevice_notifier(&econet_netdev_notifier);
 	sock_unregister(econet_family_ops.family);
+	proto_unregister(&econet_proto);
 }
 
 static int __init econet_proto_init(void)
 {
+	int err = proto_register(&econet_proto, 0);
+
+	if (err != 0)
+		goto out;
 	sock_register(&econet_family_ops);
 #ifdef CONFIG_ECONET_AUNUDP
 	spin_lock_init(&aun_queue_lock);
@@ -1114,7 +1118,8 @@ static int __init econet_proto_init(void
 	econet_hw_initialise();
 #endif
 	register_netdevice_notifier(&econet_netdev_notifier);
-	return 0;
+out:
+	return err;
 }
 
 module_init(econet_proto_init);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -7,7 +7,7 @@
  *
  * Version:	@(#)eth.c	1.0.7	05/25/93
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Florian  La Roche, <rzsfl@rz.uni-sb.de>
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -90,6 +90,48 @@ config IP_ROUTE_MULTIPATH
 	  equal "cost" and chooses one of them in a non-deterministic fashion
 	  if a matching packet arrives.
 
+config IP_ROUTE_MULTIPATH_CACHED
+	bool "IP: equal cost multipath with caching support (EXPERIMENTAL)"
+	depends on: IP_ROUTE_MULTIPATH
+	help
+	  Normally, equal cost multipath routing is not supported by the
+	  routing cache. If you say Y here, alternative routes are cached
+	  and on cache lookup a route is chosen in a configurable fashion.
+
+	  If unsure, say N.
+
+config IP_ROUTE_MULTIPATH_RR
+	tristate "MULTIPATH: round robin algorithm"
+	depends on IP_ROUTE_MULTIPATH_CACHED
+	help
+	  Mulitpath routes are chosen according to Round Robin
+
+config IP_ROUTE_MULTIPATH_RANDOM
+	tristate "MULTIPATH: random algorithm"
+	depends on IP_ROUTE_MULTIPATH_CACHED
+	help
+	  Multipath routes are chosen in a random fashion. Actually,
+	  there is no weight for a route. The advantage of this policy
+	  is that it is implemented stateless and therefore introduces only
+	  a very small delay.
+
+config IP_ROUTE_MULTIPATH_WRANDOM
+	tristate "MULTIPATH: weighted random algorithm"
+	depends on IP_ROUTE_MULTIPATH_CACHED
+	help
+	  Multipath routes are chosen in a weighted random fashion. 
+	  The per route weights are the weights visible via ip route 2. As the
+	  corresponding state management introduces some overhead routing delay
+	  is increased.
+
+config IP_ROUTE_MULTIPATH_DRR
+	tristate "MULTIPATH: interface round robin algorithm"
+	depends on IP_ROUTE_MULTIPATH_CACHED
+	help
+	  Connections are distributed in a round robin fashion over the
+	  available interfaces. This policy makes sense if the connections 
+	  should be primarily distributed on interfaces and not on routes. 
+
 config IP_ROUTE_VERBOSE
 	bool "IP: verbose route monitoring"
 	depends on IP_ADVANCED_ROUTER
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -20,9 +20,14 @@ obj-$(CONFIG_INET_ESP) += esp4.o
 obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
 obj-$(CONFIG_INET_TUNNEL) += xfrm4_tunnel.o 
 obj-$(CONFIG_IP_PNP) += ipconfig.o
+obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
+obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
+obj-$(CONFIG_IP_ROUTE_MULTIPATH_WRANDOM) += multipath_wrandom.o
+obj-$(CONFIG_IP_ROUTE_MULTIPATH_DRR) += multipath_drr.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 obj-$(CONFIG_IP_VS) += ipvs/
 obj-$(CONFIG_IP_TCPDIAG) += tcp_diag.o 
+obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
 		      xfrm4_output.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: af_inet.c,v 1.137 2002/02/01 22:01:03 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Florian La Roche, <flla@stud.uni-sb.de>
  *		Alan Cox, <A.Cox@swansea.ac.uk>
@@ -73,7 +73,6 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -281,14 +280,11 @@ static int inet_create(struct socket *so
 	BUG_TRAP(answer_prot->slab != NULL);
 
 	err = -ENOBUFS;
-	sk = sk_alloc(PF_INET, GFP_KERNEL,
-		      answer_prot->slab_obj_size,
-		      answer_prot->slab);
+	sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1);
 	if (sk == NULL)
 		goto out;
 
 	err = 0;
-	sk->sk_prot = answer_prot;
 	sk->sk_no_check = answer_no_check;
 	if (INET_PROTOSW_REUSE & answer_flags)
 		sk->sk_reuse = 1;
@@ -309,7 +305,6 @@ static int inet_create(struct socket *so
 	inet->id = 0;
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, sk->sk_prot->owner);
 
 	sk->sk_destruct	   = inet_sock_destruct;
 	sk->sk_family	   = PF_INET;
@@ -1026,21 +1021,17 @@ static int __init inet_init(void)
 		goto out;
 	}
 
-	rc = sk_alloc_slab(&tcp_prot, "tcp_sock");
-	if (rc) {
-		sk_alloc_slab_error(&tcp_prot);
+	rc = proto_register(&tcp_prot, 1);
+	if (rc)
 		goto out;
-	}
-	rc = sk_alloc_slab(&udp_prot, "udp_sock");
-	if (rc) {
-		sk_alloc_slab_error(&udp_prot);
-		goto out_tcp_free_slab;
-	}
-	rc = sk_alloc_slab(&raw_prot, "raw_sock");
-	if (rc) {
-		sk_alloc_slab_error(&raw_prot);
-		goto out_udp_free_slab;
-	}
+
+	rc = proto_register(&udp_prot, 1);
+	if (rc)
+		goto out_unregister_tcp_proto;
+
+	rc = proto_register(&raw_prot, 1);
+	if (rc)
+		goto out_unregister_udp_proto;
 
 	/*
 	 *	Tell SOCKET that we are alive... 
@@ -1114,10 +1105,10 @@ static int __init inet_init(void)
 	rc = 0;
 out:
 	return rc;
-out_tcp_free_slab:
-	sk_free_slab(&tcp_prot);
-out_udp_free_slab:
-	sk_free_slab(&udp_prot);
+out_unregister_tcp_proto:
+	proto_unregister(&tcp_prot);
+out_unregister_udp_proto:
+	proto_unregister(&udp_prot);
 	goto out;
 }
 
@@ -1190,6 +1181,7 @@ EXPORT_SYMBOL(inet_stream_connect);
 EXPORT_SYMBOL(inet_stream_ops);
 EXPORT_SYMBOL(inet_unregister_protosw);
 EXPORT_SYMBOL(net_statistics);
+EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
 
 #ifdef INET_REFCNT_DEBUG
 EXPORT_SYMBOL(inet_sock_nr);
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -53,11 +53,9 @@ static int ip_clear_mutable_options(stru
 	return 0;
 }
 
-static int ah_output(struct sk_buff *skb)
+static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x  = dst->xfrm;
 	struct iphdr *iph, *top_iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1243,7 +1243,7 @@ void __init arp_init(void)
 	arp_proc_init();
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
-			      NET_IPV4_NEIGH, "ipv4", NULL);
+			      NET_IPV4_NEIGH, "ipv4", NULL, NULL);
 #endif
 	register_netdevice_notifier(&arp_netdev_notifier);
 }
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -9,7 +9,7 @@
  *		2 of the License, or (at your option) any later version.
  *
  *	Derived from the IP parts of dev.c 1.0.19
- * 		Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * 		Authors:	Ross Biro
  *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *				Mark Evans, <evansmp@uhura.aston.ac.uk>
  *
@@ -153,7 +153,7 @@ struct in_device *inetdev_init(struct ne
 	dev_hold(dev);
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
-			      NET_IPV4_NEIGH, "ipv4", NULL);
+			      NET_IPV4_NEIGH, "ipv4", NULL, NULL);
 #endif
 
 	/* Account for reference dev->ip_ptr */
@@ -187,6 +187,10 @@ static void inetdev_destroy(struct in_de
 
 	ASSERT_RTNL();
 
+	dev = in_dev->dev;
+	if (dev == &loopback_dev)
+		return;
+
 	in_dev->dead = 1;
 
 	ip_mc_destroy_dev(in_dev);
@@ -200,7 +204,6 @@ static void inetdev_destroy(struct in_de
 	devinet_sysctl_unregister(&in_dev->cnf);
 #endif
 
-	dev = in_dev->dev;
 	dev->ip_ptr = NULL;
 
 #ifdef CONFIG_SYSCTL
@@ -230,11 +233,14 @@ int inet_addr_onlink(struct in_device *i
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 			 int destroy)
 {
+	struct in_ifaddr *promote = NULL;
 	struct in_ifaddr *ifa1 = *ifap;
 
 	ASSERT_RTNL();
 
-	/* 1. Deleting primary ifaddr forces deletion all secondaries */
+	/* 1. Deleting primary ifaddr forces deletion all secondaries 
+	 * unless alias promotion is set
+	 **/
 
 	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
 		struct in_ifaddr *ifa;
@@ -248,11 +254,16 @@ static void inet_del_ifa(struct in_devic
 				continue;
 			}
 
-			*ifap1 = ifa->ifa_next;
+			if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
+				*ifap1 = ifa->ifa_next;
 
-			rtmsg_ifa(RTM_DELADDR, ifa);
-			notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
-			inet_free_ifa(ifa);
+				rtmsg_ifa(RTM_DELADDR, ifa);
+				notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
+				inet_free_ifa(ifa);
+			} else {
+				promote = ifa;
+				break;
+			}
 		}
 	}
 
@@ -278,6 +289,13 @@ static void inet_del_ifa(struct in_devic
 		if (!in_dev->ifa_list)
 			inetdev_destroy(in_dev);
 	}
+
+	if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
+		/* not sure if we should send a delete notify first? */
+		promote->ifa_flags &= ~IFA_F_SECONDARY;
+		rtmsg_ifa(RTM_NEWADDR, promote);
+		notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
+	}
 }
 
 static int inet_insert_ifa(struct in_ifaddr *ifa)
@@ -943,8 +961,16 @@ static int inetdev_event(struct notifier
 
 	ASSERT_RTNL();
 
-	if (!in_dev)
+	if (!in_dev) {
+		if (event == NETDEV_REGISTER && dev == &loopback_dev) {
+			in_dev = inetdev_init(dev);
+			if (!in_dev)
+				panic("devinet: Failed to create loopback\n");
+			in_dev->cnf.no_xfrm = 1;
+			in_dev->cnf.no_policy = 1;
+		}
 		goto out;
+	}
 
 	switch (event) {
 	case NETDEV_REGISTER:
@@ -967,8 +993,6 @@ static int inetdev_event(struct notifier
 				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 				inet_insert_ifa(ifa);
 			}
-			in_dev->cnf.no_xfrm = 1;
-			in_dev->cnf.no_policy = 1;
 		}
 		ip_mc_up(in_dev);
 		break;
@@ -992,7 +1016,7 @@ static int inetdev_event(struct notifier
 		devinet_sysctl_unregister(&in_dev->cnf);
 		neigh_sysctl_unregister(in_dev->arp_parms);
 		neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
-				      NET_IPV4_NEIGH, "ipv4", NULL);
+				      NET_IPV4_NEIGH, "ipv4", NULL, NULL);
 		devinet_sysctl_register(in_dev, &in_dev->cnf);
 #endif
 		break;
@@ -1098,17 +1122,18 @@ static void rtmsg_ifa(int event, struct 
 	}
 }
 
-static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
-	 [4] = { .doit	 = inet_rtm_newaddr,  },
-	 [5] = { .doit	 = inet_rtm_deladdr,  },
-	 [6] = { .dumpit = inet_dump_ifaddr,  },
-	 [8] = { .doit	 = inet_rtm_newroute, },
-	 [9] = { .doit	 = inet_rtm_delroute, },
-	[10] = { .doit	 = inet_rtm_getroute, .dumpit = inet_dump_fib, },
+static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
+	[RTM_NEWADDR  - RTM_BASE] = { .doit	= inet_rtm_newaddr,	},
+	[RTM_DELADDR  - RTM_BASE] = { .doit	= inet_rtm_deladdr,	},
+	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= inet_dump_ifaddr,	},
+	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet_rtm_newroute,	},
+	[RTM_DELROUTE - RTM_BASE] = { .doit	= inet_rtm_delroute,	},
+	[RTM_GETROUTE - RTM_BASE] = { .doit	= inet_rtm_getroute,
+				      .dumpit	= inet_dump_fib,	},
 #ifdef CONFIG_IP_MULTIPLE_TABLES
-	[16] = { .doit	 = inet_rtm_newrule, },
-	[17] = { .doit	 = inet_rtm_delrule, },
-	[18] = { .dumpit = inet_dump_rules,  },
+	[RTM_NEWRULE  - RTM_BASE] = { .doit	= inet_rtm_newrule,	},
+	[RTM_DELRULE  - RTM_BASE] = { .doit	= inet_rtm_delrule,	},
+	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= inet_dump_rules,	},
 #endif
 };
 
@@ -1212,7 +1237,7 @@ int ipv4_doint_and_flush_strategy(ctl_ta
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[20];
+	ctl_table		devinet_vars[__NET_IPV4_CONF_MAX];
 	ctl_table		devinet_dev[2];
 	ctl_table		devinet_conf_dir[2];
 	ctl_table		devinet_proto_dir[2];
@@ -1374,6 +1399,15 @@ static struct devinet_sysctl_table {
 			.proc_handler	= &ipv4_doint_and_flush,
 			.strategy	= &ipv4_doint_and_flush_strategy,
 		},
+		{
+			.ctl_name	= NET_IPV4_CONF_PROMOTE_SECONDARIES,
+			.procname	= "promote_secondaries",
+			.data		= &ipv4_devconf.promote_secondaries,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &ipv4_doint_and_flush,
+			.strategy	= &ipv4_doint_and_flush_strategy,
+		},
 	},
 	.devinet_dev = {
 		{
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -17,11 +17,9 @@ struct esp_decap_data {
 	__u8		proto;
 };
 
-static int esp_output(struct sk_buff *skb)
+static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x  = dst->xfrm;
 	struct iphdr *top_iph;
 	struct ip_esp_hdr *esph;
 	struct crypto_tfm *tfm;
@@ -480,7 +478,7 @@ static int __init esp4_init(void)
 {
 	struct xfrm_decap_state decap;
 
-	if (sizeof(struct esp_decap_data)  <
+	if (sizeof(struct esp_decap_data)  >
 	    sizeof(decap.decap_data)) {
 		extern void decap_data_too_small(void);
 
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -93,6 +93,7 @@ static inline u32 fz_key(u32 dst, struct
 }
 
 static DEFINE_RWLOCK(fib_hash_lock);
+static unsigned int fib_hash_genid;
 
 #define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct hlist_head))
 
@@ -181,6 +182,7 @@ static void fn_rehash_zone(struct fn_zon
 		fz->fz_hashmask = new_hashmask;
 		fz->fz_divisor = new_divisor;
 		fn_rebuild_zone(fz, old_ht, old_divisor);
+		fib_hash_genid++;
 		write_unlock_bh(&fib_hash_lock);
 
 		fz_hash_free(old_ht, old_divisor);
@@ -236,6 +238,7 @@ fn_new_zone(struct fn_hash *table, int z
 		table->fn_zones[i]->fz_next = fz;
 	}
 	table->fn_zones[z] = fz;
+	fib_hash_genid++;
 	write_unlock_bh(&fib_hash_lock);
 	return fz;
 }
@@ -261,6 +264,7 @@ fn_hash_lookup(struct fib_table *tb, con
 
 			err = fib_semantic_match(&f->fn_alias,
 						 flp, res,
+						 f->fn_key, fz->fz_mask,
 						 fz->fz_order);
 			if (err <= 0)
 				goto out;
@@ -451,6 +455,7 @@ fn_hash_insert(struct fib_table *tb, str
 			fa->fa_scope = r->rtm_scope;
 			state = fa->fa_state;
 			fa->fa_state &= ~FA_S_ACCESSED;
+			fib_hash_genid++;
 			write_unlock_bh(&fib_hash_lock);
 
 			fib_release_info(fi_drop);
@@ -515,6 +520,7 @@ fn_hash_insert(struct fib_table *tb, str
 		fib_insert_node(fz, new_f);
 	list_add_tail(&new_fa->fa_list,
 		 (fa ? &fa->fa_list : &f->fn_alias));
+	fib_hash_genid++;
 	write_unlock_bh(&fib_hash_lock);
 
 	if (new_f)
@@ -600,6 +606,7 @@ fn_hash_delete(struct fib_table *tb, str
 			hlist_del(&f->fn_hash);
 			kill_fn = 1;
 		}
+		fib_hash_genid++;
 		write_unlock_bh(&fib_hash_lock);
 
 		if (fa->fa_state & FA_S_ACCESSED)
@@ -637,6 +644,7 @@ static int fn_flush_list(struct fn_zone 
 					hlist_del(&f->fn_hash);
 					kill_f = 1;
 				}
+				fib_hash_genid++;
 				write_unlock_bh(&fib_hash_lock);
 
 				fn_free_alias(fa);
@@ -801,6 +809,9 @@ struct fib_iter_state {
 	struct hlist_head *hash_head;
 	struct fib_node *fn;
 	struct fib_alias *fa;
+	loff_t pos;
+	unsigned int genid;
+	int valid;
 };
 
 static struct fib_alias *fib_get_first(struct seq_file *seq)
@@ -812,6 +823,9 @@ static struct fib_alias *fib_get_first(s
 	iter->hash_head = NULL;
 	iter->fn        = NULL;
 	iter->fa        = NULL;
+	iter->pos	= 0;
+	iter->genid	= fib_hash_genid;
+	iter->valid	= 1;
 
 	for (iter->zone = table->fn_zone_list; iter->zone;
 	     iter->zone = iter->zone->fz_next) {
@@ -916,16 +930,34 @@ static struct fib_alias *fib_get_next(st
 		}
 	}
 out:
+	iter->pos++;
 	return fa;
 }
 
+static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct fib_iter_state *iter = seq->private;
+	struct fib_alias *fa;
+	
+	if (iter->valid && pos >= iter->pos && iter->genid == fib_hash_genid) {
+		fa   = iter->fa;
+		pos -= iter->pos;
+	} else
+		fa = fib_get_first(seq);
+
+	if (fa)
+		while (pos && (fa = fib_get_next(seq)))
+			--pos;
+	return pos ? NULL : fa;
+}
+
 static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	void *v = NULL;
 
 	read_lock(&fib_hash_lock);
 	if (ip_fib_main_table)
-		v = *pos ? fib_get_next(seq) : SEQ_START_TOKEN;
+		v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 	return v;
 }
 
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
--- a/net/ipv4/fib_lookup.h
+++ b/net/ipv4/fib_lookup.h
@@ -19,7 +19,8 @@ struct fib_alias {
 /* Exported by fib_semantics.c */
 extern int fib_semantic_match(struct list_head *head,
 			      const struct flowi *flp,
-			      struct fib_result *res, int prefixlen);
+			      struct fib_result *res, __u32 zone, __u32 mask,
+				int prefixlen);
 extern void fib_release_info(struct fib_info *);
 extern struct fib_info *fib_create_info(const struct rtmsg *r,
 					struct kern_rta *rta,
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -42,6 +42,7 @@
 #include <net/tcp.h>
 #include <net/sock.h>
 #include <net/ip_fib.h>
+#include <net/ip_mp_alg.h>
 
 #include "fib_lookup.h"
 
@@ -649,6 +650,9 @@ fib_create_info(const struct rtmsg *r, s
 #else
 	const int nhs = 1;
 #endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	u32 mp_alg = IP_MP_ALG_NONE;
+#endif
 
 	/* Fast check to catch the most weird cases */
 	if (fib_props[r->rtm_type].scope > r->rtm_scope)
@@ -661,6 +665,15 @@ fib_create_info(const struct rtmsg *r, s
 			goto err_inval;
 	}
 #endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	if (rta->rta_mp_alg) {
+		mp_alg = *rta->rta_mp_alg;
+
+		if (mp_alg < IP_MP_ALG_NONE ||
+		    mp_alg > IP_MP_ALG_MAX)
+			goto err_inval;
+	}
+#endif
 
 	err = -ENOBUFS;
 	if (fib_info_cnt >= fib_hash_size) {
@@ -752,6 +765,10 @@ fib_create_info(const struct rtmsg *r, s
 #endif
 	}
 
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	fi->fib_mp_alg = mp_alg;
+#endif
+
 	if (fib_props[r->rtm_type].error) {
 		if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
 			goto err_inval;
@@ -831,7 +848,8 @@ failure:
 }
 
 int fib_semantic_match(struct list_head *head, const struct flowi *flp,
-		       struct fib_result *res, int prefixlen)
+		       struct fib_result *res, __u32 zone, __u32 mask, 
+			int prefixlen)
 {
 	struct fib_alias *fa;
 	int nh_sel = 0;
@@ -895,6 +913,11 @@ out_fill_res:
 	res->type = fa->fa_type;
 	res->scope = fa->fa_scope;
 	res->fi = fa->fa_info;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	res->netmask = mask;
+	res->network = zone &
+		(0xFFFFFFFF >> (32 - prefixlen));
+#endif
 	atomic_inc(&res->fi->fib_clntref);
 	return 0;
 }
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -207,6 +207,7 @@ int sysctl_icmp_ignore_bogus_error_respo
 
 int sysctl_icmp_ratelimit = 1 * HZ;
 int sysctl_icmp_ratemask = 0x1818;
+int sysctl_icmp_errors_use_inbound_ifaddr;
 
 /*
  *	ICMP control array. This specifies what to do with each ICMP.
@@ -511,21 +512,17 @@ void icmp_send(struct sk_buff *skb_in, i
 	 */
 
 	saddr = iph->daddr;
-	if (!(rt->rt_flags & RTCF_LOCAL))
-		saddr = 0;
+	if (!(rt->rt_flags & RTCF_LOCAL)) {
+		if (sysctl_icmp_errors_use_inbound_ifaddr)
+			saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
+		else
+			saddr = 0;
+	}
 
 	tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
 					   IPTOS_PREC_INTERNETCONTROL) :
 					  iph->tos;
 
-	{
-		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
-							 .saddr = saddr,
-							 .tos = RT_TOS(tos) } },
-				    .proto = IPPROTO_ICMP };
-		if (ip_route_output_key(&rt, &fl))
-		    goto out_unlock;
-	}
 	if (ip_options_echo(&icmp_param.replyopts, skb_in))
 		goto ende;
 
@@ -544,13 +541,26 @@ void icmp_send(struct sk_buff *skb_in, i
 	inet_sk(icmp_socket->sk)->tos = tos;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
-	if (icmp_param.replyopts.srr) {
-		struct flowi fl = { .nl_u = { .ip4_u =
-					      { .daddr = icmp_param.replyopts.faddr,
-						.saddr = saddr,
-						.tos = RT_TOS(tos) } },
-				    .proto = IPPROTO_ICMP };
-		ip_rt_put(rt);
+
+	{
+		struct flowi fl = {
+			.nl_u = {
+				.ip4_u = {
+					.daddr = icmp_param.replyopts.srr ?
+						icmp_param.replyopts.faddr :
+						iph->saddr,
+					.saddr = saddr,
+					.tos = RT_TOS(tos)
+				}
+			},
+			.proto = IPPROTO_ICMP,
+			.uli_u = {
+				.icmpt = {
+					.type = type,
+					.code = code
+				}
+			}
+		};
 		if (ip_route_output_key(&rt, &fl))
 			goto out_unlock;
 	}
@@ -560,7 +570,7 @@ void icmp_send(struct sk_buff *skb_in, i
 
 	/* RFC says return as much as we can without exceeding 576 bytes. */
 
-	room = dst_pmtu(&rt->u.dst);
+	room = dst_mtu(&rt->u.dst);
 	if (room > 576)
 		room = 576;
 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -92,9 +92,9 @@ int inet_peer_threshold = 65536 + 128;	/
 int inet_peer_minttl = 120 * HZ;	/* TTL under high load: 120 sec */
 int inet_peer_maxttl = 10 * 60 * HZ;	/* usual time to live: 10 min */
 
+static struct inet_peer *inet_peer_unused_head;
 /* Exported for inet_putpeer inline function.  */
-struct inet_peer *inet_peer_unused_head,
-		**inet_peer_unused_tailp = &inet_peer_unused_head;
+struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
 DEFINE_SPINLOCK(inet_peer_unused_lock);
 #define PEER_MAX_CLEANUP_WORK 30
 
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -511,7 +511,7 @@ out:
 
 	/* change mtu on this route */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-		if (rel_info > dst_pmtu(skb2->dst)) {
+		if (rel_info > dst_mtu(skb2->dst)) {
 			kfree_skb(skb2);
 			return;
 		}
@@ -618,10 +618,8 @@ static int ipgre_rcv(struct sk_buff *skb
 
 		skb->mac.raw = skb->nh.raw;
 		skb->nh.raw = __pskb_pull(skb, offset);
+		skb_postpull_rcsum(skb, skb->mac.raw, offset);
 		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-		if (skb->ip_summed == CHECKSUM_HW)
-			skb->csum = csum_sub(skb->csum,
-					     csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0));
 		skb->pkt_type = PACKET_HOST;
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 		if (MULTICAST(iph->daddr)) {
@@ -766,9 +764,9 @@ static int ipgre_tunnel_xmit(struct sk_b
 
 	df = tiph->frag_off;
 	if (df)
-		mtu = dst_pmtu(&rt->u.dst) - tunnel->hlen;
+		mtu = dst_mtu(&rt->u.dst) - tunnel->hlen;
 	else
-		mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
+		mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
 	if (skb->dst)
 		skb->dst->ops->update_pmtu(skb->dst, mtu);
@@ -787,7 +785,7 @@ static int ipgre_tunnel_xmit(struct sk_b
 	else if (skb->protocol == htons(ETH_P_IPV6)) {
 		struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
 
-		if (rt6 && mtu < dst_pmtu(skb->dst) && mtu >= IPV6_MIN_MTU) {
+		if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) {
 			if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) ||
 			    rt6->rt6i_dst.plen == 128) {
 				rt6->rt6i_flags |= RTF_MODIFIED;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
  *		Alan Cox, <Alan.Cox@linux.org>
@@ -410,10 +410,9 @@ int ip_rcv(struct sk_buff *skb, struct n
 		 * is IP we can trim to the true length of the frame.
 		 * Note this now means skb->len holds ntohs(iph->tot_len).
 		 */
-		if (skb->len > len) {
-			__pskb_trim(skb, len);
-			if (skb->ip_summed == CHECKSUM_HW)
-				skb->ip_summed = CHECKSUM_NONE;
+		if (pskb_trim_rcsum(skb, len)) {
+			IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+			goto drop;
 		}
 	}
 
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: ip_output.c,v 1.100 2002/02/01 22:01:03 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
  *		Alan Cox, <Alan.Cox@linux.org>
@@ -111,6 +111,7 @@ static int ip_dev_loopback_xmit(struct s
 #ifdef CONFIG_NETFILTER_DEBUG
 	nf_debug_ip_loopback_xmit(newskb);
 #endif
+	nf_reset(newskb);
 	netif_rx(newskb);
 	return 0;
 }
@@ -195,6 +196,8 @@ static inline int ip_finish_output2(stru
 	nf_debug_ip_finish_output2(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
+	nf_reset(skb);
+
 	if (hh) {
 		int hh_alen;
 
@@ -278,7 +281,7 @@ int ip_mc_output(struct sk_buff *skb)
 				newskb->dev, ip_dev_loopback_xmit);
 	}
 
-	if (skb->len > dst_pmtu(&rt->u.dst))
+	if (skb->len > dst_mtu(&rt->u.dst))
 		return ip_fragment(skb, ip_finish_output);
 	else
 		return ip_finish_output(skb);
@@ -288,7 +291,7 @@ int ip_output(struct sk_buff *skb)
 {
 	IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
 
-	if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size)
+	if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->tso_size)
 		return ip_fragment(skb, ip_finish_output);
 	else
 		return ip_finish_output(skb);
@@ -448,7 +451,7 @@ int ip_fragment(struct sk_buff *skb, int
 
 	if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-			  htonl(dst_pmtu(&rt->u.dst)));
+			  htonl(dst_mtu(&rt->u.dst)));
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
@@ -458,7 +461,7 @@ int ip_fragment(struct sk_buff *skb, int
 	 */
 
 	hlen = iph->ihl * 4;
-	mtu = dst_pmtu(&rt->u.dst) - hlen;	/* Size of data space */
+	mtu = dst_mtu(&rt->u.dst) - hlen;	/* Size of data space */
 
 	/* When frag_list is given, use it. First, check its validity:
 	 * some transformers could create wrong frag_list or break existing
@@ -487,6 +490,14 @@ int ip_fragment(struct sk_buff *skb, int
 			/* Partially cloned skb? */
 			if (skb_shared(frag))
 				goto slow_path;
+
+			BUG_ON(frag->sk);
+			if (skb->sk) {
+				sock_hold(skb->sk);
+				frag->sk = skb->sk;
+				frag->destructor = sock_wfree;
+				skb->truesize -= frag->truesize;
+			}
 		}
 
 		/* Everything is OK. Generate! */
@@ -498,7 +509,7 @@ int ip_fragment(struct sk_buff *skb, int
 		skb->data_len = first_len - skb_headlen(skb);
 		skb->len = first_len;
 		iph->tot_len = htons(first_len);
-		iph->frag_off |= htons(IP_MF);
+		iph->frag_off = htons(IP_MF);
 		ip_send_check(iph);
 
 		for (;;) {
@@ -746,7 +757,7 @@ int ip_append_data(struct sock *sk,
 			inet->cork.addr = ipc->addr;
 		}
 		dst_hold(&rt->u.dst);
-		inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+		inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
 		inet->cork.rt = rt;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
@@ -1152,7 +1163,8 @@ int ip_push_pending_frames(struct sock *
 	 * If local_df is set too, we still allow to fragment this frame
 	 * locally. */
 	if (inet->pmtudisc == IP_PMTUDISC_DO ||
-	    (!skb_shinfo(skb)->frag_list && ip_dont_fragment(sk, &rt->u.dst)))
+	    (skb->len <= dst_mtu(&rt->u.dst) &&
+	     ip_dont_fragment(sk, &rt->u.dst)))
 		df = htons(IP_DF);
 
 	if (inet->cork.flags & IPCORK_OPT)
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -955,7 +955,7 @@ int ip_getsockopt(struct sock *sk, int l
 			val = 0;
 			dst = sk_dst_get(sk);
 			if (dst) {
-				val = dst_pmtu(dst) - dst->header_len;
+				val = dst_mtu(dst);
 				dst_release(dst);
 			}
 			if (!val) {
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -154,11 +154,9 @@ out:	
 	return err;
 }
 
-static int ipcomp_output(struct sk_buff *skb)
+static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x = dst->xfrm;
 	struct iphdr *iph;
 	struct ip_comp_hdr *ipch;
 	struct ipcomp_data *ipcd = x->data;
@@ -169,32 +167,22 @@ static int ipcomp_output(struct sk_buff 
 	hdr_len = iph->ihl * 4;
 	if ((skb->len - hdr_len) < ipcd->threshold) {
 		/* Don't bother compressing */
-		if (x->props.mode) {
-			ip_send_check(iph);
-		}
 		goto out_ok;
 	}
 
 	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 	    skb_linearize(skb, GFP_ATOMIC) != 0) {
-	    	err = -ENOMEM;
-	    	goto error;
+		goto out_ok;
 	}
 	
 	err = ipcomp_compress(x, skb);
+	iph = skb->nh.iph;
+
 	if (err) {
-		if (err == -EMSGSIZE) {
-			if (x->props.mode) {
-				iph = skb->nh.iph;
-				ip_send_check(iph);
-			}
-			goto out_ok;
-		}
-		goto error;
+		goto out_ok;
 	}
 
 	/* Install ipcomp header, convert into ipcomp datagram. */
-	iph = skb->nh.iph;
 	iph->tot_len = htons(skb->len);
 	ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4);
 	ipch->nexthdr = iph->protocol;
@@ -202,12 +190,12 @@ static int ipcomp_output(struct sk_buff 
 	ipch->cpi = htons((u16 )ntohl(x->id.spi));
 	iph->protocol = IPPROTO_COMP;
 	ip_send_check(iph);
+	return 0;
 
 out_ok:
-	err = 0;
-
-error:
-	return err;
+	if (x->props.mode)
+		ip_send_check(iph);
+	return 0;
 }
 
 static void ipcomp4_err(struct sk_buff *skb, u32 info)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -436,7 +436,7 @@ out:
 
 	/* change mtu on this route */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-		if (rel_info > dst_pmtu(skb2->dst)) {
+		if (rel_info > dst_mtu(skb2->dst)) {
 			kfree_skb(skb2);
 			return;
 		}
@@ -569,9 +569,9 @@ static int ipip_tunnel_xmit(struct sk_bu
 	}
 
 	if (tiph->frag_off)
-		mtu = dst_pmtu(&rt->u.dst) - sizeof(struct iphdr);
+		mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
 	else
-		mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
+		mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1171,7 +1171,7 @@ static void ipmr_queue_xmit(struct sk_bu
 
 	dev = rt->u.dst.dev;
 
-	if (skb->len+encap > dst_pmtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
+	if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
 		/* Do not fragment multicasts. Alas, IPv4 does not
 		   allow to send ICMP, so that packets will disappear
 		   to blackhole.
diff --git a/net/ipv4/ipvs/Makefile b/net/ipv4/ipvs/Makefile
--- a/net/ipv4/ipvs/Makefile
+++ b/net/ipv4/ipvs/Makefile
@@ -11,7 +11,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH
 
 ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o	   \
 		ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o	   		   \
-		ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o		   \
+		ip_vs_est.o ip_vs_proto.o 				   \
 		$(ip_vs_proto-objs-y)
 
 
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -1003,7 +1003,7 @@ ip_vs_in(unsigned int hooknum, struct sk
 
 	/* Check the server status */
 	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
-		/* the destination server is not availabe */
+		/* the destination server is not available */
 
 		if (sysctl_ip_vs_expire_nodest_conn) {
 			/* try to expire the connection immediately */
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -26,7 +26,7 @@
 #include <linux/fs.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
-#include <linux/timer.h>
+#include <linux/workqueue.h>
 #include <linux/swap.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -90,7 +90,7 @@ int ip_vs_get_debug_level(void)
 #endif
 
 /*
- *	update_defense_level is called from timer bh and from sysctl.
+ *	update_defense_level is called from keventd and from sysctl.
  */
 static void update_defense_level(void)
 {
@@ -212,19 +212,19 @@ static void update_defense_level(void)
 /*
  *	Timer for checking the defense
  */
-static struct timer_list defense_timer;
 #define DEFENSE_TIMER_PERIOD	1*HZ
+static void defense_work_handler(void *data);
+static DECLARE_WORK(defense_work, defense_work_handler, NULL);
 
-static void defense_timer_handler(unsigned long data)
+static void defense_work_handler(void *data)
 {
 	update_defense_level();
 	if (atomic_read(&ip_vs_dropentry))
 		ip_vs_random_dropentry();
 
-	mod_timer(&defense_timer, jiffies + DEFENSE_TIMER_PERIOD);
+	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
 }
 
-
 int
 ip_vs_use_count_inc(void)
 {
@@ -2370,10 +2370,7 @@ int ip_vs_control_init(void)
 	ip_vs_new_estimator(&ip_vs_stats);
 
 	/* Hook the defense timer */
-	init_timer(&defense_timer);
-	defense_timer.function = defense_timer_handler;
-	defense_timer.expires = jiffies + DEFENSE_TIMER_PERIOD;
-	add_timer(&defense_timer);
+	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
 
 	LeaveFunction(2);
 	return 0;
@@ -2384,7 +2381,7 @@ void ip_vs_control_cleanup(void)
 {
 	EnterFunction(2);
 	ip_vs_trash_cleanup();
-	del_timer_sync(&defense_timer);
+	cancel_rearming_delayed_work(&defense_work);
 	ip_vs_kill_estimator(&ip_vs_stats);
 	unregister_sysctl_table(sysctl_header);
 	proc_net_remove("ip_vs_stats");
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -216,9 +216,6 @@ int ip_vs_protocol_init(void)
 #ifdef CONFIG_IP_VS_PROTO_UDP
 	REGISTER_PROTOCOL(&ip_vs_protocol_udp);
 #endif
-#ifdef CONFIG_IP_VS_PROTO_ICMP
-	REGISTER_PROTOCOL(&ip_vs_protocol_icmp);
-#endif
 #ifdef CONFIG_IP_VS_PROTO_AH
 	REGISTER_PROTOCOL(&ip_vs_protocol_ah);
 #endif
diff --git a/net/ipv4/ipvs/ip_vs_proto_icmp.c b/net/ipv4/ipvs/ip_vs_proto_icmp.c
deleted file mode 100644
--- a/net/ipv4/ipvs/ip_vs_proto_icmp.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * ip_vs_proto_icmp.c:	ICMP load balancing support for IP Virtual Server
- *
- * Authors:	Julian Anastasov <ja@ssi.bg>, March 2002
- *
- *		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/module.h>
-#include <linux/kernel.h>
-#include <linux/icmp.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-static int icmp_timeouts[1] =		{ 1*60*HZ };
-
-static char * icmp_state_name_table[1] = { "ICMP" };
-
-static struct ip_vs_conn *
-icmp_conn_in_get(const struct sk_buff *skb,
-		 struct ip_vs_protocol *pp,
-		 const struct iphdr *iph,
-		 unsigned int proto_off,
-		 int inverse)
-{
-#if 0
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(iph->protocol,
-			iph->saddr, 0,
-			iph->daddr, 0);
-	} else {
-		cp = ip_vs_conn_in_get(iph->protocol,
-			iph->daddr, 0,
-			iph->saddr, 0);
-	}
-
-	return cp;
-
-#else
-	return NULL;
-#endif
-}
-
-static struct ip_vs_conn *
-icmp_conn_out_get(const struct sk_buff *skb,
-		  struct ip_vs_protocol *pp,
-		  const struct iphdr *iph,
-		  unsigned int proto_off,
-		  int inverse)
-{
-#if 0
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(iph->protocol,
-			iph->saddr, 0,
-			iph->daddr, 0);
-	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-			iph->daddr, 0,
-			iph->saddr, 0);
-	}
-
-	return cp;
-#else
-	return NULL;
-#endif
-}
-
-static int
-icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		   int *verdict, struct ip_vs_conn **cpp)
-{
-	*verdict = NF_ACCEPT;
-	return 0;
-}
-
-static int
-icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
-{
-	if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) {
-		if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
-			if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) {
-				IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for");
-				return 0;
-			}
-		}
-	}
-	return 1;
-}
-
-static void
-icmp_debug_packet(struct ip_vs_protocol *pp,
-		  const struct sk_buff *skb,
-		  int offset,
-		  const char *msg)
-{
-	char buf[256];
-	struct iphdr _iph, *ih;
-
-	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
-	if (ih == NULL)
-		sprintf(buf, "%s TRUNCATED", pp->name);
-	else if (ih->frag_off & __constant_htons(IP_OFFSET))
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
-	else {
-		struct icmphdr _icmph, *ic;
-
-		ic = skb_header_pointer(skb, offset + ih->ihl*4,
-					sizeof(_icmph), &_icmph);
-		if (ic == NULL)
-			sprintf(buf, "%s TRUNCATED to %u bytes\n",
-				pp->name, skb->len - offset);
-		else
-			sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
-				pp->name, NIPQUAD(ih->saddr),
-				NIPQUAD(ih->daddr),
-				ic->type, ic->code);
-	}
-	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
-}
-
-static int
-icmp_state_transition(struct ip_vs_conn *cp, int direction,
-		      const struct sk_buff *skb,
-		      struct ip_vs_protocol *pp)
-{
-	cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL];
-	return 1;
-}
-
-static int
-icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
-{
-	int num;
-	char **names;
-
-	num = IP_VS_ICMP_S_LAST;
-	names = icmp_state_name_table;
-	return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to);
-}
-
-
-static void icmp_init(struct ip_vs_protocol *pp)
-{
-	pp->timeout_table = icmp_timeouts;
-}
-
-static void icmp_exit(struct ip_vs_protocol *pp)
-{
-}
-
-struct ip_vs_protocol ip_vs_protocol_icmp = {
-	.name =			"ICMP",
-	.protocol =		IPPROTO_ICMP,
-	.dont_defrag =		0,
-	.init =			icmp_init,
-	.exit =			icmp_exit,
-	.conn_schedule =	icmp_conn_schedule,
-	.conn_in_get =		icmp_conn_in_get,
-	.conn_out_get =		icmp_conn_out_get,
-	.snat_handler =		NULL,
-	.dnat_handler =		NULL,
-	.csum_check =		icmp_csum_check,
-	.state_transition =	icmp_state_transition,
-	.register_app =		NULL,
-	.unregister_app =	NULL,
-	.app_conn_bind =	NULL,
-	.debug_packet =		icmp_debug_packet,
-	.timeout_change =	NULL,
-	.set_state_timeout =	icmp_set_state_timeout,
-};
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -126,6 +126,8 @@ static int ip_vs_wrr_update_svc(struct i
 	mark->cl = &svc->destinations;
 	mark->mw = ip_vs_wrr_max_weight(svc);
 	mark->di = ip_vs_wrr_gcd_weight(svc);
+	if (mark->cw > mark->mw)
+		mark->cw = 0;
 	return 0;
 }
 
@@ -163,7 +165,7 @@ ip_vs_wrr_schedule(struct ip_vs_service 
 			if (mark->cw <= 0) {
 				mark->cw = mark->mw;
 				/*
-				 * Still zero, which means no availabe servers.
+				 * Still zero, which means no available servers.
 				 */
 				if (mark->cw == 0) {
 					mark->cl = &svc->destinations;
@@ -186,7 +188,7 @@ ip_vs_wrr_schedule(struct ip_vs_service 
 			}
 		}
 
-		if (mark->cl == p) {
+		if (mark->cl == p && mark->cw == mark->di) {
 			/* back to the start, and no dest is found.
 			   It is only possible when all dests are OVERLOADED */
 			dest = NULL;
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -52,6 +52,7 @@ __ip_vs_dst_check(struct ip_vs_dest *des
 	if ((dst->obsolete || rtos != dest->dst_rtos) &&
 	    dst->ops->check(dst, cookie) == NULL) {
 		dest->dst_cache = NULL;
+		dst_release(dst);
 		return NULL;
 	}
 	dst_hold(dst);
@@ -177,7 +178,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, s
 	}
 
 	/* MTU checking */
-	mtu = dst_pmtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->u.dst);
 	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -244,7 +245,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, stru
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_pmtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->u.dst);
 	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -341,7 +342,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, s
 
 	tdev = rt->u.dst.dev;
 
-	mtu = dst_pmtu(&rt->u.dst) - sizeof(struct iphdr);
+	mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
 	if (mtu < 68) {
 		ip_rt_put(rt);
 		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n");
@@ -444,7 +445,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struc
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_pmtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->u.dst);
 	if ((iph->frag_off&__constant_htons(IP_DF)) && skb->len > mtu) {
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		ip_rt_put(rt);
@@ -507,7 +508,6 @@ ip_vs_icmp_xmit(struct sk_buff *skb, str
 			rc = NF_ACCEPT;
 		/* do not touch skb anymore */
 		atomic_inc(&cp->in_pkts);
-		__ip_vs_conn_put(cp);
 		goto out;
 	}
 
@@ -519,7 +519,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, str
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_pmtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->u.dst);
 	if ((skb->len > mtu) && (skb->nh.iph->frag_off&__constant_htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
diff --git a/net/ipv4/multipath.c b/net/ipv4/multipath.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/multipath.c
@@ -0,0 +1,55 @@
+/* multipath.c: IPV4 multipath algorithm support.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+#include <net/ip_mp_alg.h>
+
+static DEFINE_SPINLOCK(alg_table_lock);
+struct ip_mp_alg_ops *ip_mp_alg_table[IP_MP_ALG_MAX + 1];
+
+int multipath_alg_register(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
+{
+	struct ip_mp_alg_ops **slot;
+	int err;
+
+	if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX ||
+	    !ops->mp_alg_select_route)
+		return -EINVAL;
+
+	spin_lock(&alg_table_lock);
+	slot = &ip_mp_alg_table[n];
+	if (*slot != NULL) {
+		err = -EBUSY;
+	} else {
+		*slot = ops;
+		err = 0;
+	}
+	spin_unlock(&alg_table_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(multipath_alg_register);
+
+void multipath_alg_unregister(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
+{
+	struct ip_mp_alg_ops **slot;
+
+	if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX)
+		return;
+
+	spin_lock(&alg_table_lock);
+	slot = &ip_mp_alg_table[n];
+	if (*slot == ops)
+		*slot = NULL;
+	spin_unlock(&alg_table_lock);
+
+	synchronize_net();
+}
+EXPORT_SYMBOL(multipath_alg_unregister);
diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/multipath_drr.c
@@ -0,0 +1,251 @@
+/*
+ *              Device round robin policy for multipath.
+ *
+ *
+ * Version:	$Id: multipath_drr.c,v 1.1.2.1 2004/09/16 07:42:34 elueck Exp $
+ *
+ * Authors:	Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.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 <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+#include <net/ip_mp_alg.h>
+
+struct multipath_device {
+	int		ifi; /* interface index of device */
+	atomic_t	usecount;
+	int 		allocated;
+};
+
+#define MULTIPATH_MAX_DEVICECANDIDATES 10
+
+static struct multipath_device state[MULTIPATH_MAX_DEVICECANDIDATES];
+static DEFINE_SPINLOCK(state_lock);
+
+static int inline __multipath_findslot(void)
+{
+	int i;
+
+	for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++) {
+		if (state[i].allocated == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int inline __multipath_finddev(int ifindex)
+{
+	int i;
+
+	for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++) {
+		if (state[i].allocated != 0 &&
+		    state[i].ifi == ifindex)
+			return i;
+	}
+	return -1;
+}
+
+static int drr_dev_event(struct notifier_block *this,
+			 unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+	int devidx;
+
+	switch (event) {
+	case NETDEV_UNREGISTER:
+	case NETDEV_DOWN:
+		spin_lock_bh(&state_lock);
+
+		devidx = __multipath_finddev(dev->ifindex);
+		if (devidx != -1) {
+			state[devidx].allocated = 0;
+			state[devidx].ifi = 0;
+			atomic_set(&state[devidx].usecount, 0);
+		}
+
+		spin_unlock_bh(&state_lock);
+		break;
+	};
+
+	return NOTIFY_DONE;
+}
+
+struct notifier_block drr_dev_notifier = {
+	.notifier_call	= drr_dev_event,
+};
+
+
+static void drr_safe_inc(atomic_t *usecount)
+{
+	int n;
+
+	atomic_inc(usecount);
+
+	n = atomic_read(usecount);
+	if (n <= 0) {
+		int i;
+
+		spin_lock_bh(&state_lock);
+
+		for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++)
+			atomic_set(&state[i].usecount, 0);
+
+		spin_unlock_bh(&state_lock);
+	}
+}
+
+static void drr_select_route(const struct flowi *flp,
+			     struct rtable *first, struct rtable **rp)
+{
+	struct rtable *nh, *result, *cur_min;
+	int min_usecount = -1; 
+	int devidx = -1;
+	int cur_min_devidx = -1;
+
+	/* 1. make sure all alt. nexthops have the same GC related data */
+	/* 2. determine the new candidate to be returned */
+	result = NULL;
+	cur_min = NULL;
+	for (nh = rcu_dereference(first); nh;
+	     nh = rcu_dereference(nh->u.rt_next)) {
+		if ((nh->u.dst.flags & DST_BALANCED) != 0 &&
+		    multipath_comparekeys(&nh->fl, flp)) {
+			int nh_ifidx = nh->u.dst.dev->ifindex;
+
+			nh->u.dst.lastuse = jiffies;
+			nh->u.dst.__use++;
+			if (result != NULL)
+				continue;
+
+			/* search for the output interface */
+
+			/* this is not SMP safe, only add/remove are
+			 * SMP safe as wrong usecount updates have no big
+			 * impact
+			 */
+			devidx = __multipath_finddev(nh_ifidx);
+			if (devidx == -1) {
+				/* add the interface to the array 
+				 * SMP safe
+				 */
+				spin_lock_bh(&state_lock);
+
+				/* due to SMP: search again */
+				devidx = __multipath_finddev(nh_ifidx);
+				if (devidx == -1) {
+					/* add entry for device */
+					devidx = __multipath_findslot();
+					if (devidx == -1) {
+						/* unlikely but possible */
+						continue;
+					}
+
+					state[devidx].allocated = 1;
+					state[devidx].ifi = nh_ifidx;
+					atomic_set(&state[devidx].usecount, 0);
+					min_usecount = 0;
+				}
+
+				spin_unlock_bh(&state_lock);
+			}
+
+			if (min_usecount == 0) {
+				/* if the device has not been used it is
+				 * the primary target
+				 */
+				drr_safe_inc(&state[devidx].usecount);
+				result = nh;
+			} else {
+				int count =
+					atomic_read(&state[devidx].usecount);
+
+				if (min_usecount == -1 ||
+				    count < min_usecount) {
+					cur_min = nh;
+					cur_min_devidx = devidx;
+					min_usecount = count;
+				}
+			}
+		}
+	}
+
+	if (!result) {
+		if (cur_min) {
+			drr_safe_inc(&state[cur_min_devidx].usecount);
+			result = cur_min;
+		} else {
+			result = first;
+		}
+	}
+
+	*rp = result;
+}
+
+static struct ip_mp_alg_ops drr_ops = {
+	.mp_alg_select_route	=	drr_select_route,
+};
+
+static int __init drr_init(void)
+{
+	int err = register_netdevice_notifier(&drr_dev_notifier);
+
+	if (err)
+		return err;
+
+	err = multipath_alg_register(&drr_ops, IP_MP_ALG_DRR);
+	if (err)
+		goto fail;
+
+	return 0;
+
+fail:
+	unregister_netdevice_notifier(&drr_dev_notifier);
+	return err;
+}
+
+static void __exit drr_exit(void)
+{
+	unregister_netdevice_notifier(&drr_dev_notifier);
+	multipath_alg_unregister(&drr_ops, IP_MP_ALG_DRR);
+}
+
+module_init(drr_init);
+module_exit(drr_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_random.c b/net/ipv4/multipath_random.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/multipath_random.c
@@ -0,0 +1,130 @@
+/*
+ *              Random policy for multipath.
+ *
+ *
+ * Version:	$Id: multipath_random.c,v 1.1.2.3 2004/09/21 08:42:11 elueck Exp $
+ *
+ * Authors:	Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.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 <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+#include <net/ip_mp_alg.h>
+
+#define MULTIPATH_MAX_CANDIDATES 40
+
+/* interface to random number generation */
+static unsigned int RANDOM_SEED = 93186752;
+
+static inline unsigned int random(unsigned int ubound)
+{
+	static unsigned int a = 1588635695,
+		q = 2,
+		r = 1117695901;
+
+	RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q);
+
+	return RANDOM_SEED % ubound;
+}
+
+
+static void random_select_route(const struct flowi *flp,
+				struct rtable *first,
+				struct rtable **rp)
+{
+	struct rtable *rt;
+	struct rtable *decision;
+	unsigned char candidate_count = 0;
+
+	/* count all candidate */
+	for (rt = rcu_dereference(first); rt;
+	     rt = rcu_dereference(rt->u.rt_next)) {
+		if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
+		    multipath_comparekeys(&rt->fl, flp))
+			++candidate_count;
+	}
+
+	/* choose a random candidate */
+	decision = first;
+	if (candidate_count > 1) {
+		unsigned char i = 0;
+		unsigned char candidate_no = (unsigned char)
+			random(candidate_count);
+
+		/* find chosen candidate and adjust GC data for all candidates
+		 * to ensure they stay in cache
+		 */
+		for (rt = first; rt; rt = rt->u.rt_next) {
+			if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
+			    multipath_comparekeys(&rt->fl, flp)) {
+				rt->u.dst.lastuse = jiffies;
+
+				if (i == candidate_no)
+					decision = rt;
+
+				if (i >= candidate_count)
+					break;
+
+				i++;
+			}
+		}
+	}
+
+	decision->u.dst.__use++;
+	*rp = decision;
+}
+
+static struct ip_mp_alg_ops random_ops = {
+	.mp_alg_select_route	=	random_select_route,
+};
+
+static int __init random_init(void)
+{
+	return multipath_alg_register(&random_ops, IP_MP_ALG_RANDOM);
+}
+
+static void __exit random_exit(void)
+{
+	multipath_alg_unregister(&random_ops, IP_MP_ALG_RANDOM);
+}
+
+module_init(random_init);
+module_exit(random_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_rr.c b/net/ipv4/multipath_rr.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/multipath_rr.c
@@ -0,0 +1,97 @@
+/*
+ *              Round robin policy for multipath.
+ *
+ *
+ * Version:	$Id: multipath_rr.c,v 1.1.2.2 2004/09/16 07:42:34 elueck Exp $
+ *
+ * Authors:	Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.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 <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+#include <net/ip_mp_alg.h>
+
+static void rr_select_route(const struct flowi *flp,
+			    struct rtable *first, struct rtable **rp)
+{
+	struct rtable *nh, *result, *min_use_cand = NULL;
+	int min_use = -1;
+
+	/* 1. make sure all alt. nexthops have the same GC related data
+	 * 2. determine the new candidate to be returned
+	 */
+	result = NULL;
+	for (nh = rcu_dereference(first); nh;
+ 	     nh = rcu_dereference(nh->u.rt_next)) {
+		if ((nh->u.dst.flags & DST_BALANCED) != 0 &&
+		    multipath_comparekeys(&nh->fl, flp)) {
+			nh->u.dst.lastuse = jiffies;
+
+			if (min_use == -1 || nh->u.dst.__use < min_use) {
+				min_use = nh->u.dst.__use;
+				min_use_cand = nh;
+			}
+		}
+	}
+	result = min_use_cand;
+	if (!result)
+		result = first;
+
+	result->u.dst.__use++;
+	*rp = result;
+}
+
+static struct ip_mp_alg_ops rr_ops = {
+	.mp_alg_select_route	=	rr_select_route,
+};
+
+static int __init rr_init(void)
+{
+	return multipath_alg_register(&rr_ops, IP_MP_ALG_RR);
+}
+
+static void __exit rr_exit(void)
+{
+	multipath_alg_unregister(&rr_ops, IP_MP_ALG_RR);
+}
+
+module_init(rr_init);
+module_exit(rr_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/multipath_wrandom.c
@@ -0,0 +1,346 @@
+/*
+ *              Weighted random policy for multipath.
+ *
+ *
+ * Version:	$Id: multipath_wrandom.c,v 1.1.2.3 2004/09/22 07:51:40 elueck Exp $
+ *
+ * Authors:	Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.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 <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+#include <net/ip_fib.h>
+#include <net/ip_mp_alg.h>
+
+#define MULTIPATH_STATE_SIZE 15
+
+struct multipath_candidate {
+	struct multipath_candidate	*next;
+	int				power;
+	struct rtable			*rt;
+};
+
+struct multipath_dest {
+	struct list_head	list;
+
+	const struct fib_nh	*nh_info;
+	__u32			netmask;
+	__u32			network;
+	unsigned char		prefixlen;
+
+	struct rcu_head		rcu;
+};
+
+struct multipath_bucket {
+	struct list_head	head;
+	spinlock_t		lock;
+};
+
+struct multipath_route {
+	struct list_head	list;
+
+	int			oif;
+	__u32			gw;
+	struct list_head	dests;
+
+	struct rcu_head		rcu;
+};
+
+/* state: primarily weight per route information */
+static struct multipath_bucket state[MULTIPATH_STATE_SIZE];
+
+/* interface to random number generation */
+static unsigned int RANDOM_SEED = 93186752;
+
+static inline unsigned int random(unsigned int ubound)
+{
+	static unsigned int a = 1588635695,
+		q = 2,
+		r = 1117695901;
+	RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q);
+	return RANDOM_SEED % ubound;
+}
+
+static unsigned char __multipath_lookup_weight(const struct flowi *fl,
+					       const struct rtable *rt)
+{
+	const int state_idx = rt->idev->dev->ifindex % MULTIPATH_STATE_SIZE;
+	struct multipath_route *r;
+	struct multipath_route *target_route = NULL;
+	struct multipath_dest *d;
+	int weight = 1;
+
+	/* lookup the weight information for a certain route */
+	rcu_read_lock();
+
+	/* find state entry for gateway or add one if necessary */
+	list_for_each_entry_rcu(r, &state[state_idx].head, list) {
+		if (r->gw == rt->rt_gateway &&
+		    r->oif == rt->idev->dev->ifindex) {
+			target_route = r;
+			break;
+		}
+	}
+
+	if (!target_route) {
+		/* this should not happen... but we are prepared */
+		printk( KERN_CRIT"%s: missing state for gateway: %u and " \
+			"device %d\n", __FUNCTION__, rt->rt_gateway,
+			rt->idev->dev->ifindex);
+		goto out;
+	}
+
+	/* find state entry for destination */
+	list_for_each_entry_rcu(d, &target_route->dests, list) {
+		__u32 targetnetwork = fl->fl4_dst & 
+			(0xFFFFFFFF >> (32 - d->prefixlen));
+
+		if ((targetnetwork & d->netmask) == d->network) {
+			weight = d->nh_info->nh_weight;
+			goto out;
+		}
+	}
+
+out:
+	rcu_read_unlock();
+	return weight;
+}
+
+static void wrandom_init_state(void) 
+{
+	int i;
+
+	for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
+		INIT_LIST_HEAD(&state[i].head);
+		spin_lock_init(&state[i].lock);
+	}
+}
+
+static void wrandom_select_route(const struct flowi *flp,
+				 struct rtable *first,
+				 struct rtable **rp)
+{
+	struct rtable *rt;
+	struct rtable *decision;
+	struct multipath_candidate *first_mpc = NULL;
+	struct multipath_candidate *mpc, *last_mpc = NULL;
+	int power = 0;
+	int last_power;
+	int selector;
+	const size_t size_mpc = sizeof(struct multipath_candidate);
+
+	/* collect all candidates and identify their weights */
+	for (rt = rcu_dereference(first); rt;
+	     rt = rcu_dereference(rt->u.rt_next)) {
+		if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
+		    multipath_comparekeys(&rt->fl, flp)) {
+			struct multipath_candidate* mpc =
+				(struct multipath_candidate*)
+				kmalloc(size_mpc, GFP_ATOMIC);
+
+			if (!mpc)
+				return;
+
+			power += __multipath_lookup_weight(flp, rt) * 10000;
+
+			mpc->power = power;
+			mpc->rt = rt;
+			mpc->next = NULL;
+
+			if (!first_mpc)
+				first_mpc = mpc;
+			else
+				last_mpc->next = mpc;
+
+			last_mpc = mpc;
+		}
+	}
+
+	/* choose a weighted random candidate */
+	decision = first;
+	selector = random(power);
+	last_power = 0;
+
+	/* select candidate, adjust GC data and cleanup local state */
+	decision = first;
+	last_mpc = NULL;
+	for (mpc = first_mpc; mpc; mpc = mpc->next) {
+		mpc->rt->u.dst.lastuse = jiffies;
+		if (last_power <= selector && selector < mpc->power)
+			decision = mpc->rt;
+
+		last_power = mpc->power;
+		if (last_mpc)
+			kfree(last_mpc);
+
+		last_mpc = mpc;
+	}
+
+	if (last_mpc) {
+		/* concurrent __multipath_flush may lead to !last_mpc */
+		kfree(last_mpc);
+	}
+
+	decision->u.dst.__use++;
+	*rp = decision;
+}
+
+static void wrandom_set_nhinfo(__u32 network,
+			       __u32 netmask,
+			       unsigned char prefixlen,
+			       const struct fib_nh *nh)
+{
+	const int state_idx = nh->nh_oif % MULTIPATH_STATE_SIZE;
+	struct multipath_route *r, *target_route = NULL;
+	struct multipath_dest *d, *target_dest = NULL;
+
+	/* store the weight information for a certain route */
+	spin_lock(&state[state_idx].lock);
+
+	/* find state entry for gateway or add one if necessary */
+	list_for_each_entry_rcu(r, &state[state_idx].head, list) {
+		if (r->gw == nh->nh_gw && r->oif == nh->nh_oif) {
+			target_route = r;
+			break;
+		}
+	}
+
+	if (!target_route) {
+		const size_t size_rt = sizeof(struct multipath_route);
+		target_route = (struct multipath_route *)
+			kmalloc(size_rt, GFP_ATOMIC);
+
+		target_route->gw = nh->nh_gw;
+		target_route->oif = nh->nh_oif;
+		memset(&target_route->rcu, 0, sizeof(struct rcu_head));
+		INIT_LIST_HEAD(&target_route->dests);
+
+		list_add_rcu(&target_route->list, &state[state_idx].head);
+	}
+
+	/* find state entry for destination or add one if necessary */
+	list_for_each_entry_rcu(d, &target_route->dests, list) {
+		if (d->nh_info == nh) {
+			target_dest = d;
+			break;
+		}
+	}
+
+	if (!target_dest) {
+		const size_t size_dst = sizeof(struct multipath_dest);
+		target_dest = (struct multipath_dest*)
+			kmalloc(size_dst, GFP_ATOMIC);
+
+		target_dest->nh_info = nh;
+		target_dest->network = network;
+		target_dest->netmask = netmask;
+		target_dest->prefixlen = prefixlen;
+		memset(&target_dest->rcu, 0, sizeof(struct rcu_head));
+
+		list_add_rcu(&target_dest->list, &target_route->dests);
+	}
+	/* else: we already stored this info for another destination =>
+	 * we are finished
+	 */
+
+	spin_unlock(&state[state_idx].lock);
+}
+
+static void __multipath_free(struct rcu_head *head)
+{
+	struct multipath_route *rt = container_of(head, struct multipath_route,
+						  rcu);
+	kfree(rt);
+}
+
+static void __multipath_free_dst(struct rcu_head *head)
+{
+  	struct multipath_dest *dst = container_of(head,
+						  struct multipath_dest,
+						  rcu);
+	kfree(dst);
+}
+
+static void wrandom_flush(void)
+{
+	int i;
+
+	/* defere delete to all entries */
+	for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
+		struct multipath_route *r;
+
+		spin_lock(&state[i].lock);
+		list_for_each_entry_rcu(r, &state[i].head, list) {
+			struct multipath_dest *d;
+			list_for_each_entry_rcu(d, &r->dests, list) {
+				list_del_rcu(&d->list);
+				call_rcu(&d->rcu,
+					 __multipath_free_dst);
+			}
+			list_del_rcu(&r->list);
+			call_rcu(&r->rcu,
+				 __multipath_free);
+		}
+
+		spin_unlock(&state[i].lock);
+	}
+}
+
+static struct ip_mp_alg_ops wrandom_ops = {
+	.mp_alg_select_route	=	wrandom_select_route,
+	.mp_alg_flush		=	wrandom_flush,
+	.mp_alg_set_nhinfo	=	wrandom_set_nhinfo,
+};
+
+static int __init wrandom_init(void)
+{
+	wrandom_init_state();
+
+	return multipath_alg_register(&wrandom_ops, IP_MP_ALG_WRANDOM);
+}
+
+static void __exit wrandom_exit(void)
+{
+	multipath_alg_unregister(&wrandom_ops, IP_MP_ALG_WRANDOM);
+}
+
+module_init(wrandom_init);
+module_exit(wrandom_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -717,7 +717,7 @@ static int translate_table(const char *n
 	}
 
 	/* And one copy for every other CPU */
-	for (i = 1; i < NR_CPUS; i++) {
+	for (i = 1; i < num_possible_cpus(); i++) {
 		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
 		       newinfo->entries,
 		       SMP_ALIGN(newinfo->size));
@@ -768,7 +768,7 @@ static void get_counters(const struct ar
 	unsigned int cpu;
 	unsigned int i;
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+	for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
 		i = 0;
 		ARPT_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
 				   t->size,
@@ -886,7 +886,7 @@ static int do_replace(void __user *user,
 		return -ENOMEM;
 
 	newinfo = vmalloc(sizeof(struct arpt_table_info)
-			  + SMP_ALIGN(tmp.size) * NR_CPUS);
+			  + SMP_ALIGN(tmp.size) * num_possible_cpus());
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1159,7 +1159,7 @@ int arpt_register_table(struct arpt_tabl
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	newinfo = vmalloc(sizeof(struct arpt_table_info)
-			  + SMP_ALIGN(repl->size) * NR_CPUS);
+			  + SMP_ALIGN(repl->size) * num_possible_cpus());
 	if (!newinfo) {
 		ret = -ENOMEM;
 		return ret;
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -940,37 +940,25 @@ void ip_ct_refresh_acct(struct ip_conntr
 struct sk_buff *
 ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
 {
-	struct sock *sk = skb->sk;
 #ifdef CONFIG_NETFILTER_DEBUG
 	unsigned int olddebug = skb->nf_debug;
 #endif
 
-	if (sk) {
-		sock_hold(sk);
-		skb_orphan(skb);
-	}
+	skb_orphan(skb);
 
 	local_bh_disable(); 
 	skb = ip_defrag(skb, user);
 	local_bh_enable();
 
-	if (!skb) {
-		if (sk)
-			sock_put(sk);
-		return skb;
-	}
-
-	if (sk) {
-		skb_set_owner_w(skb, sk);
-		sock_put(sk);
-	}
-
-	ip_send_check(skb->nh.iph);
-	skb->nfcache |= NFC_ALTERED;
+	if (skb) {
+		ip_send_check(skb->nh.iph);
+		skb->nfcache |= NFC_ALTERED;
 #ifdef CONFIG_NETFILTER_DEBUG
-	/* Packet path as if nothing had happened. */
-	skb->nf_debug = olddebug;
+		/* Packet path as if nothing had happened. */
+		skb->nf_debug = olddebug;
 #endif
+	}
+
 	return skb;
 }
 
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -252,7 +252,7 @@ static int find_pattern(const char *data
 }
 
 /* Look up to see if we're just after a \n. */
-static int find_nl_seq(u16 seq, const struct ip_ct_ftp_master *info, int dir)
+static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
 {
 	unsigned int i;
 
@@ -263,7 +263,7 @@ static int find_nl_seq(u16 seq, const st
 }
 
 /* We don't update if it's older than what we have. */
-static void update_nl_seq(u16 nl_seq, struct ip_ct_ftp_master *info, int dir)
+static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir)
 {
 	unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
 
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -400,8 +400,8 @@ static int sctp_packet(struct ip_conntra
 					return -1;
 			}
 			DEBUGP("Setting vtag %x for dir %d\n", 
-					ih->init_tag, CTINFO2DIR(ctinfo));
-			conntrack->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = ih->init_tag;
+					ih->init_tag, !CTINFO2DIR(ctinfo));
+			conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag;
 		}
 
 		conntrack->proto.sctp.state = newconntrack;
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -254,7 +254,7 @@ static enum tcp_conntrack tcp_conntracks
  *	sSS -> sSR	Standard open.
  *	sSR -> sSR	Retransmitted SYN/ACK.
  *	sES -> sIG	Late retransmitted SYN/ACK?
- *	sFW -> sIG
+ *	sFW -> sIG	Might be SYN/ACK answering ignored SYN
  *	sCW -> sIG
  *	sLA -> sIG
  *	sTW -> sIG
@@ -273,10 +273,10 @@ static enum tcp_conntrack tcp_conntracks
  *	sCL -> sCL
  */
 /* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*ack*/	   { sIV, sIG, sIV, sES, sCW, sCW, sTW, sTW, sCL, sIV },
+/*ack*/	   { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV },
 /*
- *	sSS -> sIG	Might be a half-open connection.
- *	sSR -> sIV	Simultaneous open.
+ *	sSS -> sIV	Might be a half-open connection.
+ *	sSR -> sSR	Might answer late resent SYN.
  *	sES -> sES	:-)
  *	sFW -> sCW	Normal close request answered by ACK.
  *	sCW -> sCW
@@ -352,14 +352,19 @@ static unsigned int get_conntrack_index(
    http://www.nluug.nl/events/sane2000/papers.html
    http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
    
-   The boundaries and the conditions are slightly changed:
-   
+   The boundaries and the conditions are changed according to RFC793:
+   the packet must intersect the window (i.e. segments may be
+   after the right or before the left edge) and thus receivers may ACK
+   segments after the right edge of the window.
+
    	td_maxend = max(sack + max(win,1)) seen in reply packets
 	td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
+	td_maxwin += seq + len - sender.td_maxend
+			if seq + len > sender.td_maxend
 	td_end    = max(seq + len) seen in sent packets
    
-   I. 	Upper bound for valid data:	seq + len <= sender.td_maxend
-   II. 	Lower bound for valid data:	seq >= sender.td_end - receiver.td_maxwin
+   I.   Upper bound for valid data:	seq <= sender.td_maxend
+   II.  Lower bound for valid data:	seq + len >= sender.td_end - receiver.td_maxwin
    III.	Upper bound for valid ack:      sack <= receiver.td_end
    IV.	Lower bound for valid ack:	ack >= receiver.td_end - MAXACKWINDOW
    	
@@ -373,7 +378,7 @@ static inline __u32 segment_seq_plus_len
 					 size_t len,
 					 struct iphdr *iph,
 					 struct tcphdr *tcph)
-  {
+{
 	return (seq + len - (iph->ihl + tcph->doff)*4
 		+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
 }
@@ -444,22 +449,33 @@ static void tcp_options(const struct sk_
 	}
 }
 
-static void tcp_sack(struct tcphdr *tcph, __u32 *sack)
+static void tcp_sack(const struct sk_buff *skb,
+		     struct iphdr *iph,
+		     struct tcphdr *tcph,
+		     __u32 *sack)
 {
-	__u32 tmp;
+	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
 	unsigned char *ptr;
 	int length = (tcph->doff*4) - sizeof(struct tcphdr);
-	
+	__u32 tmp;
+
+	if (!length)
+		return;
+
+	ptr = skb_header_pointer(skb,
+				 (iph->ihl * 4) + sizeof(struct tcphdr),
+				 length, buff);
+	BUG_ON(ptr == NULL);
+
 	/* Fast path for timestamp-only option */
 	if (length == TCPOLEN_TSTAMP_ALIGNED*4
-	    && *(__u32 *)(tcph + 1) ==
+	    && *(__u32 *)ptr ==
 	        __constant_ntohl((TCPOPT_NOP << 24) 
 	        		 | (TCPOPT_NOP << 16)
 	        		 | (TCPOPT_TIMESTAMP << 8)
 	        		 | TCPOLEN_TIMESTAMP))
 		return;
 		
-	ptr = (unsigned char *)(tcph + 1);
 	while (length > 0) {
 		int opcode=*ptr++;
 		int opsize, i;
@@ -500,7 +516,7 @@ static void tcp_sack(struct tcphdr *tcph
 
 static int tcp_in_window(struct ip_ct_tcp *state, 
                          enum ip_conntrack_dir dir,
-                         unsigned int *index,
+                         unsigned int index,
                          const struct sk_buff *skb,
                          struct iphdr *iph,
                          struct tcphdr *tcph)
@@ -519,7 +535,7 @@ static int tcp_in_window(struct ip_ct_tc
 	end = segment_seq_plus_len(seq, skb->len, iph, tcph);
 	
 	if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
-		tcp_sack(tcph, &sack);
+		tcp_sack(skb, iph, tcph, &sack);
 		
 	DEBUGP("tcp_in_window: START\n");
 	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
@@ -598,20 +614,23 @@ static int tcp_in_window(struct ip_ct_tc
 		ack = sack = receiver->td_end;
 	}
 
-	if (seq == end)
+	if (seq == end
+	    && (!tcph->rst 
+	        || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT)))
 		/*
 		 * Packets contains no data: we assume it is valid
 		 * and check the ack value only.
+		 * However RST segments are always validated by their
+		 * SEQ number, except when seq == 0 (reset sent answering
+		 * SYN.
 		 */
 		seq = end = sender->td_end;
 		
 	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
-	       "seq=%u ack=%u sack =%u win=%u end=%u trim=%u\n",
+	       "seq=%u ack=%u sack =%u win=%u end=%u\n",
 		NIPQUAD(iph->saddr), ntohs(tcph->source),
 		NIPQUAD(iph->daddr), ntohs(tcph->dest),
-		seq, ack, sack, win, end, 
-		after(end, sender->td_maxend) && before(seq, sender->td_maxend)
-		? sender->td_maxend : end);
+		seq, ack, sack, win, end);
 	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
 	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
 		sender->td_end, sender->td_maxend, sender->td_maxwin,
@@ -619,24 +638,15 @@ static int tcp_in_window(struct ip_ct_tc
 		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
 		receiver->td_scale);
 	
-	/* Ignore data over the right edge of the receiver's window. */
-	if (after(end, sender->td_maxend) &&
-	    before(seq, sender->td_maxend)) {
-		end = sender->td_maxend;
-		if (*index == TCP_FIN_SET)
-			*index = TCP_ACK_SET;
-	}
 	DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
-		before(end, sender->td_maxend + 1) 
-		    || before(seq, sender->td_maxend + 1),
-	    	after(seq, sender->td_end - receiver->td_maxwin - 1) 
-	    	    || after(end, sender->td_end - receiver->td_maxwin - 1),
+		before(seq, sender->td_maxend + 1),
+	    	after(end, sender->td_end - receiver->td_maxwin - 1),
 	    	before(sack, receiver->td_end + 1),
 	    	after(ack, receiver->td_end - MAXACKWINDOW(sender)));
 	
 	if (sender->loose || receiver->loose ||
-	    (before(end, sender->td_maxend + 1) &&
-	     after(seq, sender->td_end - receiver->td_maxwin - 1) &&
+	    (before(seq, sender->td_maxend + 1) &&
+	     after(end, sender->td_end - receiver->td_maxwin - 1) &&
 	     before(sack, receiver->td_end + 1) &&
 	     after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
 	    	/*
@@ -653,6 +663,11 @@ static int tcp_in_window(struct ip_ct_tc
 			sender->td_maxwin = swin;
 		if (after(end, sender->td_end))
 			sender->td_end = end;
+		/*
+		 * Update receiver data.
+		 */
+		if (after(end, sender->td_maxend))
+			receiver->td_maxwin += end - sender->td_maxend;
 		if (after(sack + win, receiver->td_maxend - 1)) {
 			receiver->td_maxend = sack + win;
 			if (win == 0)
@@ -662,7 +677,7 @@ static int tcp_in_window(struct ip_ct_tc
 		/* 
 		 * Check retransmissions.
 		 */
-		if (*index == TCP_ACK_SET) {
+		if (index == TCP_ACK_SET) {
 			if (state->last_dir == dir
 			    && state->last_seq == seq
 			    && state->last_ack == ack
@@ -687,16 +702,16 @@ static int tcp_in_window(struct ip_ct_tc
 		if (LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL,
 			"ip_ct_tcp: %s ",
-			before(end, sender->td_maxend + 1) ?
-			after(seq, sender->td_end - receiver->td_maxwin - 1) ?
+			before(seq, sender->td_maxend + 1) ?
+			after(end, sender->td_end - receiver->td_maxwin - 1) ?
 			before(sack, receiver->td_end + 1) ?
 			after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
-			: "ACK is under the lower bound (possibly overly delayed ACK)"
-			: "ACK is over the upper bound (ACKed data has never seen yet)"
-			: "SEQ is under the lower bound (retransmitted already ACKed data)"
+			: "ACK is under the lower bound (possible overly delayed ACK)"
+			: "ACK is over the upper bound (ACKed data not seen yet)"
+			: "SEQ is under the lower bound (already ACKed data retransmitted)"
 			: "SEQ is over the upper bound (over the window of the receiver)");
 
-		res = ip_ct_tcp_be_liberal && !tcph->rst;
+		res = ip_ct_tcp_be_liberal;
   	}
   
 	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -755,6 +770,7 @@ static u8 tcp_valid_flags[(TH_FIN|TH_SYN
 {
 	[TH_SYN]			= 1,
 	[TH_SYN|TH_ACK]			= 1,
+	[TH_SYN|TH_ACK|TH_PUSH]		= 1,
 	[TH_RST]			= 1,
 	[TH_RST|TH_ACK]			= 1,
 	[TH_RST|TH_ACK|TH_PUSH]		= 1,
@@ -803,6 +819,7 @@ static int tcp_error(struct sk_buff *skb
 	 */
 	/* FIXME: Source route IP option packets --RR */
 	if (hooknum == NF_IP_PRE_ROUTING
+	    && skb->ip_summed != CHECKSUM_UNNECESSARY
 	    && csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP,
 			         skb->ip_summed == CHECKSUM_HW ? skb->csum
 			      	 : skb_checksum(skb, iph->ihl*4, tcplen, 0))) {
@@ -849,13 +866,12 @@ static int tcp_packet(struct ip_conntrac
 	switch (new_state) {
 	case TCP_CONNTRACK_IGNORE:
 		/* Either SYN in ORIGINAL
-		 * or SYN/ACK in REPLY
-		 * or ACK in REPLY direction (half-open connection). */
+		 * or SYN/ACK in REPLY. */
 		if (index == TCP_SYNACK_SET
 		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
 		    && conntrack->proto.tcp.last_dir != dir
-		    && after(ntohl(th->ack_seq),
-		    	     conntrack->proto.tcp.last_seq)) {
+		    && ntohl(th->ack_seq) ==
+		    	     conntrack->proto.tcp.last_end) {
 			/* This SYN/ACK acknowledges a SYN that we earlier 
 			 * ignored as invalid. This means that the client and
 			 * the server are both in sync, while the firewall is
@@ -875,6 +891,8 @@ static int tcp_packet(struct ip_conntrac
 		conntrack->proto.tcp.last_index = index;
 		conntrack->proto.tcp.last_dir = dir;
 		conntrack->proto.tcp.last_seq = ntohl(th->seq);
+		conntrack->proto.tcp.last_end = 
+		    segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th);
 		
 		WRITE_UNLOCK(&tcp_lock);
 		if (LOG_INVALID(IPPROTO_TCP))
@@ -892,7 +910,12 @@ static int tcp_packet(struct ip_conntrac
 				  "ip_ct_tcp: invalid state ");
 		return -NF_ACCEPT;
 	case TCP_CONNTRACK_SYN_SENT:
-		if (old_state >= TCP_CONNTRACK_TIME_WAIT) {	
+		if (old_state < TCP_CONNTRACK_TIME_WAIT)
+			break;
+		if ((conntrack->proto.tcp.seen[dir].flags &
+		         IP_CT_TCP_FLAG_CLOSE_INIT)
+		    || after(ntohl(th->seq),
+		    	     conntrack->proto.tcp.seen[dir].td_end)) {	
 		    	/* Attempt to reopen a closed connection.
 		    	* Delete this connection and look up again. */
 		    	WRITE_UNLOCK(&tcp_lock);
@@ -900,23 +923,23 @@ static int tcp_packet(struct ip_conntrac
 		    		conntrack->timeout.function((unsigned long)
 		    					    conntrack);
 		    	return -NF_REPEAT;
+		} else {
+			WRITE_UNLOCK(&tcp_lock);
+			if (LOG_INVALID(IPPROTO_TCP))
+				nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+				              "ip_ct_tcp: invalid SYN");
+			return -NF_ACCEPT;
 		}
-		break;
 	case TCP_CONNTRACK_CLOSE:
 		if (index == TCP_RST_SET
-		    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
-		         && conntrack->proto.tcp.last_index <= TCP_SYNACK_SET)
-		        || (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
-			 && conntrack->proto.tcp.last_index == TCP_ACK_SET))
-		    && after(ntohl(th->ack_seq),
-		    	     conntrack->proto.tcp.last_seq)) {
-			/* Ignore RST closing down invalid SYN or ACK
-			   we had let trough. */ 
-		    	WRITE_UNLOCK(&tcp_lock);
-			if (LOG_INVALID(IPPROTO_TCP))
-				nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
-					  "ip_ct_tcp: invalid RST (ignored) ");
-			return NF_ACCEPT;
+		    && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
+		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
+		    && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
+			/* RST sent to invalid SYN we had let trough
+			 * SYN was in window then, tear down connection.
+			 * We skip window checking, because packet might ACK
+			 * segments we ignored in the SYN. */
+			goto in_window;
 		}
 		/* Just fall trough */
 	default:
@@ -924,16 +947,14 @@ static int tcp_packet(struct ip_conntrac
 		break;
 	}
 
-	if (!tcp_in_window(&conntrack->proto.tcp, dir, &index, 
+	if (!tcp_in_window(&conntrack->proto.tcp, dir, index, 
 			   skb, iph, th)) {
 		WRITE_UNLOCK(&tcp_lock);
 		return -NF_ACCEPT;
 	}
-	/* From now on we have got in-window packets */
-	
-	/* If FIN was trimmed off, we don't change state. */
+    in_window:
+	/* From now on we have got in-window packets */	
 	conntrack->proto.tcp.last_index = index;
-	new_state = tcp_conntracks[dir][index][old_state];
 
 	DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
 	       "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
@@ -944,6 +965,10 @@ static int tcp_packet(struct ip_conntrac
 		old_state, new_state);
 
 	conntrack->proto.tcp.state = new_state;
+	if (old_state != new_state 
+	    && (new_state == TCP_CONNTRACK_FIN_WAIT
+	    	|| new_state == TCP_CONNTRACK_CLOSE))
+		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 	timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans
 		  && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans
 		  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
@@ -974,7 +999,7 @@ static int tcp_packet(struct ip_conntrac
 	return NF_ACCEPT;
 }
  
-  /* Called when a new connection for this protocol found. */
+/* Called when a new connection for this protocol found. */
 static int tcp_new(struct ip_conntrack *conntrack,
 		   const struct sk_buff *skb)
 {
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -77,34 +77,70 @@ seq_print_counters(struct seq_file *s,
 #define seq_print_counters(x, y)	0
 #endif
 
-static void *ct_seq_start(struct seq_file *s, loff_t *pos)
+struct ct_iter_state {
+	unsigned int bucket;
+};
+
+static struct list_head *ct_get_first(struct seq_file *seq)
 {
-	if (*pos >= ip_conntrack_htable_size)
-		return NULL;
-	return &ip_conntrack_hash[*pos];
+	struct ct_iter_state *st = seq->private;
+
+	for (st->bucket = 0;
+	     st->bucket < ip_conntrack_htable_size;
+	     st->bucket++) {
+		if (!list_empty(&ip_conntrack_hash[st->bucket]))
+			return ip_conntrack_hash[st->bucket].next;
+	}
+	return NULL;
 }
-  
-static void ct_seq_stop(struct seq_file *s, void *v)
+
+static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
+{
+	struct ct_iter_state *st = seq->private;
+
+	head = head->next;
+	while (head == &ip_conntrack_hash[st->bucket]) {
+		if (++st->bucket >= ip_conntrack_htable_size)
+			return NULL;
+		head = ip_conntrack_hash[st->bucket].next;
+	}
+	return head;
+}
+
+static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct list_head *head = ct_get_first(seq);
+
+	if (head)
+		while (pos && (head = ct_get_next(seq, head)))
+			pos--;
+	return pos ? NULL : head;
+}
+
+static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	READ_LOCK(&ip_conntrack_lock);
+	return ct_get_idx(seq, *pos);
 }
 
 static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
 	(*pos)++;
-	if (*pos >= ip_conntrack_htable_size)
-		return NULL;
-	return &ip_conntrack_hash[*pos];
+	return ct_get_next(s, v);
 }
   
-/* return 0 on success, 1 in case of error */
-static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
-			    struct seq_file *s)
+static void ct_seq_stop(struct seq_file *s, void *v)
+{
+	READ_UNLOCK(&ip_conntrack_lock);
+}
+ 
+static int ct_seq_show(struct seq_file *s, void *v)
 {
+	const struct ip_conntrack_tuple_hash *hash = v;
 	const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
 	struct ip_conntrack_protocol *proto;
 
 	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-
 	IP_NF_ASSERT(conntrack);
 
 	/* we only want to print DIR_ORIGINAL */
@@ -115,63 +151,50 @@ static int ct_seq_real_show(const struct
 			       .tuple.dst.protonum);
 	IP_NF_ASSERT(proto);
 
-	if (seq_printf(s, "%-8s %u %lu ",
+	if (seq_printf(s, "%-8s %u %ld ",
 		      proto->name,
 		      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
 		      timer_pending(&conntrack->timeout)
-		      ? (conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
-		return 1;
+		      ? (long)(conntrack->timeout.expires - jiffies)/HZ
+		      : 0) != 0)
+		return -ENOSPC;
 
 	if (proto->print_conntrack(s, conntrack))
-		return 1;
+		return -ENOSPC;
   
 	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
 			proto))
-		return 1;
+		return -ENOSPC;
 
  	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
-		return 1;
+		return -ENOSPC;
 
 	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
 		if (seq_printf(s, "[UNREPLIED] "))
-			return 1;
+			return -ENOSPC;
 
 	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
 			proto))
-		return 1;
+		return -ENOSPC;
 
  	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
-		return 1;
+		return -ENOSPC;
 
 	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
 		if (seq_printf(s, "[ASSURED] "))
-			return 1;
+			return -ENOSPC;
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-	if (seq_printf(s, "mark=%ld ", conntrack->mark))
-		return 1;
+	if (seq_printf(s, "mark=%lu ", conntrack->mark))
+		return -ENOSPC;
 #endif
 
 	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
-		return 1;
+		return -ENOSPC;
 
 	return 0;
 }
 
-static int ct_seq_show(struct seq_file *s, void *v)
-{
-	struct list_head *list = v;
-	int ret = 0;
-
-	/* FIXME: Simply truncates if hash chain too long. */
-	READ_LOCK(&ip_conntrack_lock);
-	if (LIST_FIND(list, ct_seq_real_show,
-		      struct ip_conntrack_tuple_hash *, s))
-		ret = -ENOSPC;
-	READ_UNLOCK(&ip_conntrack_lock);
-	return ret;
-}
-	
 static struct seq_operations ct_seq_ops = {
 	.start = ct_seq_start,
 	.next  = ct_seq_next,
@@ -181,7 +204,23 @@ static struct seq_operations ct_seq_ops 
   
 static int ct_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &ct_seq_ops);
+	struct seq_file *seq;
+	struct ct_iter_state *st;
+	int ret;
+
+	st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+	if (st == NULL)
+		return -ENOMEM;
+	ret = seq_open(file, &ct_seq_ops);
+	if (ret)
+		goto out_free;
+	seq          = file->private_data;
+	seq->private = st;
+	memset(st, 0, sizeof(struct ct_iter_state));
+	return ret;
+out_free:
+	kfree(st);
+	return ret;
 }
 
 static struct file_operations ct_file_ops = {
@@ -189,7 +228,7 @@ static struct file_operations ct_file_op
 	.open    = ct_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release
+	.release = seq_release_private,
 };
   
 /* expects */
@@ -217,6 +256,7 @@ static void *exp_seq_next(struct seq_fil
 {
  	struct list_head *e = v;
 
+	++*pos;
 	e = e->next;
 
 	if (e == &ip_conntrack_expect_list)
@@ -235,8 +275,8 @@ static int exp_seq_show(struct seq_file 
 	struct ip_conntrack_expect *expect = v;
 
 	if (expect->timeout.function)
-		seq_printf(s, "%lu ", timer_pending(&expect->timeout)
-			   ? (expect->timeout.expires - jiffies)/HZ : 0);
+		seq_printf(s, "%ld ", timer_pending(&expect->timeout)
+			   ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
 	else
 		seq_printf(s, "- ");
 
@@ -362,6 +402,16 @@ static unsigned int ip_confirm(unsigned 
 			       const struct net_device *out,
 			       int (*okfn)(struct sk_buff *))
 {
+	/* We've seen it coming out the other side: confirm it */
+	return ip_conntrack_confirm(pskb);
+}
+
+static unsigned int ip_conntrack_help(unsigned int hooknum,
+				      struct sk_buff **pskb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 
@@ -373,9 +423,7 @@ static unsigned int ip_confirm(unsigned 
 		if (ret != NF_ACCEPT)
 			return ret;
 	}
-
-	/* We've seen it coming out the other side: confirm it */
-	return ip_conntrack_confirm(pskb);
+	return NF_ACCEPT;
 }
 
 static unsigned int ip_conntrack_defrag(unsigned int hooknum,
@@ -384,13 +432,6 @@ static unsigned int ip_conntrack_defrag(
 				        const struct net_device *out,
 				        int (*okfn)(struct sk_buff *))
 {
-#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
-	/* Previously seen (loopback)?  Ignore.  Do this before
-           fragment check. */
-	if ((*pskb)->nfct)
-		return NF_ACCEPT;
-#endif
-
 	/* Gather fragments. */
 	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 		*pskb = ip_ct_gather_frags(*pskb,
@@ -418,7 +459,7 @@ static unsigned int ip_refrag(unsigned i
 	/* Local packets are never produced too large for their
 	   interface.  We degfragment them at LOCAL_OUT, however,
 	   so we have to refragment them here. */
-	if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
+	if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
 	    !skb_shinfo(*pskb)->tso_size) {
 		/* No hook can be after us, so this should be OK. */
 		ip_fragment(*pskb, okfn);
@@ -477,13 +518,30 @@ static struct nf_hook_ops ip_conntrack_l
 	.priority	= NF_IP_PRI_CONNTRACK,
 };
 
+/* helpers */
+static struct nf_hook_ops ip_conntrack_helper_out_ops = {
+	.hook		= ip_conntrack_help,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_POST_ROUTING,
+	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+};
+
+static struct nf_hook_ops ip_conntrack_helper_in_ops = {
+	.hook		= ip_conntrack_help,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_IN,
+	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+};
+
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops = {
 	.hook		= ip_refrag,
 	.owner		= THIS_MODULE,
 	.pf		= PF_INET,
 	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_LAST,
+	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 static struct nf_hook_ops ip_conntrack_local_in_ops = {
@@ -491,7 +549,7 @@ static struct nf_hook_ops ip_conntrack_l
 	.owner		= THIS_MODULE,
 	.pf		= PF_INET,
 	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_LAST-1,
+	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 /* Sysctl support */
@@ -792,10 +850,20 @@ static int init_or_cleanup(int init)
 		printk("ip_conntrack: can't register local out hook.\n");
 		goto cleanup_inops;
 	}
+	ret = nf_register_hook(&ip_conntrack_helper_in_ops);
+	if (ret < 0) {
+		printk("ip_conntrack: can't register local in helper hook.\n");
+		goto cleanup_inandlocalops;
+	}
+	ret = nf_register_hook(&ip_conntrack_helper_out_ops);
+	if (ret < 0) {
+		printk("ip_conntrack: can't register postrouting helper hook.\n");
+		goto cleanup_helperinops;
+	}
 	ret = nf_register_hook(&ip_conntrack_out_ops);
 	if (ret < 0) {
 		printk("ip_conntrack: can't register post-routing hook.\n");
-		goto cleanup_inandlocalops;
+		goto cleanup_helperoutops;
 	}
 	ret = nf_register_hook(&ip_conntrack_local_in_ops);
 	if (ret < 0) {
@@ -821,6 +889,10 @@ static int init_or_cleanup(int init)
 	nf_unregister_hook(&ip_conntrack_local_in_ops);
  cleanup_inoutandlocalops:
 	nf_unregister_hook(&ip_conntrack_out_ops);
+ cleanup_helperoutops:
+	nf_unregister_hook(&ip_conntrack_helper_out_ops);
+ cleanup_helperinops:
+	nf_unregister_hook(&ip_conntrack_helper_in_ops);
  cleanup_inandlocalops:
 	nf_unregister_hook(&ip_conntrack_local_out_ops);
  cleanup_inops:
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -356,15 +356,6 @@ unsigned int nat_packet(struct ip_conntr
 	unsigned long statusbit;
 	enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
 
-	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)
-	    && (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. */
-		if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
-			return NF_DROP;
-	}
-
 	if (mtype == IP_NAT_MANIP_SRC)
 		statusbit = IPS_SRC_NAT;
 	else
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -170,5 +170,14 @@ static int __init init(void)
 	return 0;
 }
 
+/* Prior to 2.6.11, we had a ports param.  No longer, but don't break users. */
+static int warn_set(const char *val, struct kernel_param *kp)
+{
+	printk(KERN_INFO __stringify(KBUILD_MODNAME)
+	       ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
+	return 0;
+}
+module_param_call(ports, warn_set, NULL, NULL, 0);
+
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c
--- a/net/ipv4/netfilter/ip_nat_irc.c
+++ b/net/ipv4/netfilter/ip_nat_irc.c
@@ -112,5 +112,14 @@ static int __init init(void)
 	return 0;
 }
 
+/* Prior to 2.6.11, we had a ports param.  No longer, but don't break users. */
+static int warn_set(const char *val, struct kernel_param *kp)
+{
+	printk(KERN_INFO __stringify(KBUILD_MODNAME)
+	       ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
+	return 0;
+}
+module_param_call(ports, warn_set, NULL, NULL, 0);
+
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -230,6 +230,25 @@ ip_nat_local_fn(unsigned int hooknum,
 	return ret;
 }
 
+static unsigned int
+ip_nat_adjust(unsigned int hooknum,
+	      struct sk_buff **pskb,
+	      const struct net_device *in,
+	      const struct net_device *out,
+	      int (*okfn)(struct sk_buff *))
+{
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+
+	ct = ip_conntrack_get(*pskb, &ctinfo);
+	if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
+	        DEBUGP("ip_nat_standalone: adjusting sequence number\n");
+	        if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
+	                return NF_DROP;
+	}
+	return NF_ACCEPT;
+}
+
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
@@ -250,6 +269,15 @@ static struct nf_hook_ops ip_nat_out_ops
 	.priority	= NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_out_ops = {
+	.hook		= ip_nat_adjust,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_POST_ROUTING,
+	.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops = {
 	.hook		= ip_nat_local_fn,
@@ -268,6 +296,16 @@ static struct nf_hook_ops ip_nat_local_i
 	.priority	= NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_in_ops = {
+	.hook		= ip_nat_adjust,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_IN,
+	.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
+
 static int init_or_cleanup(int init)
 {
 	int ret = 0;
@@ -296,10 +334,20 @@ static int init_or_cleanup(int init)
 		printk("ip_nat_init: can't register out hook.\n");
 		goto cleanup_inops;
 	}
+	ret = nf_register_hook(&ip_nat_adjust_in_ops);
+	if (ret < 0) {
+		printk("ip_nat_init: can't register adjust in hook.\n");
+		goto cleanup_outops;
+	}
+	ret = nf_register_hook(&ip_nat_adjust_out_ops);
+	if (ret < 0) {
+		printk("ip_nat_init: can't register adjust out hook.\n");
+		goto cleanup_adjustin_ops;
+	}
 	ret = nf_register_hook(&ip_nat_local_out_ops);
 	if (ret < 0) {
 		printk("ip_nat_init: can't register local out hook.\n");
-		goto cleanup_outops;
+		goto cleanup_adjustout_ops;;
 	}
 	ret = nf_register_hook(&ip_nat_local_in_ops);
 	if (ret < 0) {
@@ -312,6 +360,10 @@ static int init_or_cleanup(int init)
 	nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
 	nf_unregister_hook(&ip_nat_local_out_ops);
+ cleanup_adjustout_ops:
+	nf_unregister_hook(&ip_nat_adjust_out_ops);
+ cleanup_adjustin_ops:
+	nf_unregister_hook(&ip_nat_adjust_in_ops);
  cleanup_outops:
 	nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops:
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -3,6 +3,7 @@
  * communicating with userspace via netlink.
  *
  * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
+ * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.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
@@ -14,6 +15,10 @@
  *             Zander).
  * 2000-08-01: Added Nick Williams' MAC support.
  * 2002-06-25: Code cleanup.
+ * 2005-01-10: Added /proc counter for dropped packets; fixed so
+ *             packets aren't delivered to user space if they're going 
+ *             to be dropped. 
+ * 2005-05-26: local_bh_{disable,enable} around nf_reinject (Harald Welte)
  *
  */
 #include <linux/module.h>
@@ -59,6 +64,8 @@ static DEFINE_RWLOCK(queue_lock);
 static int peer_pid;
 static unsigned int copy_range;
 static unsigned int queue_total;
+static unsigned int queue_dropped = 0;
+static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
 static DECLARE_MUTEX(ipqnl_sem);
@@ -66,22 +73,23 @@ static DECLARE_MUTEX(ipqnl_sem);
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
 {
+	/* TCP input path (and probably other bits) assume to be called
+	 * from softirq context, not from syscall, like ipq_issue_verdict is
+	 * called.  TCP input path deadlocks with locks taken from timer
+	 * softirq, e.g.  We therefore emulate this by local_bh_disable() */
+
+	local_bh_disable();
 	nf_reinject(entry->skb, entry->info, verdict);
+	local_bh_enable();
+
 	kfree(entry);
 }
 
-static inline int
+static inline void
 __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;
 }
 
 /*
@@ -308,14 +316,24 @@ ipq_enqueue_packet(struct sk_buff *skb, 
 	if (!peer_pid)
 		goto err_out_free_nskb; 
 
+	if (queue_total >= queue_maxlen) {
+                queue_dropped++;
+		status = -ENOSPC;
+		if (net_ratelimit())
+		          printk (KERN_WARNING "ip_queue: full at %d entries, "
+				  "dropping packets(s). Dropped: %d\n", queue_total,
+				  queue_dropped);
+		goto err_out_free_nskb;
+	}
+
  	/* netlink_unicast will either free the nskb or attach it to a socket */ 
 	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
-	if (status < 0)
-		goto err_out_unlock;
-	
-	status = __ipq_enqueue_entry(entry);
-	if (status < 0)
+	if (status < 0) {
+	        queue_user_dropped++;
 		goto err_out_unlock;
+	}
+
+	__ipq_enqueue_entry(entry);
 
 	write_unlock_bh(&queue_lock);
 	return status;
@@ -538,20 +556,18 @@ ipq_rcv_skb(struct sk_buff *skb)
 static void
 ipq_rcv_sk(struct sock *sk, int len)
 {
-	do {
-		struct sk_buff *skb;
+	struct sk_buff *skb;
+	unsigned int qlen;
 
-		if (down_trylock(&ipqnl_sem))
-			return;
+	down(&ipqnl_sem);
 			
-		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-			ipq_rcv_skb(skb);
-			kfree_skb(skb);
-		}
+	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+		ipq_rcv_skb(skb);
+		kfree_skb(skb);
+	}
 		
-		up(&ipqnl_sem);
-
-	} while (ipqnl && ipqnl->sk_receive_queue.qlen);
+	up(&ipqnl_sem);
 }
 
 static int
@@ -637,12 +653,16 @@ ipq_get_info(char *buffer, char **start,
 	              "Copy mode         : %hu\n"
 	              "Copy range        : %u\n"
 	              "Queue length      : %u\n"
-	              "Queue max. length : %u\n",
+	              "Queue max. length : %u\n"
+		      "Queue dropped     : %u\n"
+		      "Netlink dropped   : %u\n",
 	              peer_pid,
 	              copy_mode,
 	              copy_range,
 	              queue_total,
-	              queue_maxlen);
+	              queue_maxlen,
+		      queue_dropped,
+		      queue_user_dropped);
 
 	read_unlock_bh(&queue_lock);
 	
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -923,7 +923,7 @@ translate_table(const char *name,
 	}
 
 	/* And one copy for every other CPU */
-	for (i = 1; i < NR_CPUS; i++) {
+	for (i = 1; i < num_possible_cpus(); i++) {
 		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
 		       newinfo->entries,
 		       SMP_ALIGN(newinfo->size));
@@ -945,7 +945,7 @@ replace_table(struct ipt_table *table,
 		struct ipt_entry *table_base;
 		unsigned int i;
 
-		for (i = 0; i < NR_CPUS; i++) {
+		for (i = 0; i < num_possible_cpus(); i++) {
 			table_base =
 				(void *)newinfo->entries
 				+ TABLE_OFFSET(newinfo, i);
@@ -992,7 +992,7 @@ get_counters(const struct ipt_table_info
 	unsigned int cpu;
 	unsigned int i;
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+	for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
 		i = 0;
 		IPT_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
 				  t->size,
@@ -1130,7 +1130,7 @@ do_replace(void __user *user, unsigned i
 		return -ENOMEM;
 
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
-			  + SMP_ALIGN(tmp.size) * NR_CPUS);
+			  + SMP_ALIGN(tmp.size) * num_possible_cpus());
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1460,7 +1460,7 @@ int ipt_register_table(struct ipt_table 
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
-			  + SMP_ALIGN(repl->size) * NR_CPUS);
+			  + SMP_ALIGN(repl->size) * num_possible_cpus());
 	if (!newinfo)
 		return -ENOMEM;
 
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -198,16 +198,16 @@ static void dump_packet(const struct ipt
 		static size_t required_len[NR_ICMP_TYPES+1]
 			= { [ICMP_ECHOREPLY] = 4,
 			    [ICMP_DEST_UNREACH]
-			    = 8 + sizeof(struct iphdr) + 8,
+			    = 8 + sizeof(struct iphdr),
 			    [ICMP_SOURCE_QUENCH]
-			    = 8 + sizeof(struct iphdr) + 8,
+			    = 8 + sizeof(struct iphdr),
 			    [ICMP_REDIRECT]
-			    = 8 + sizeof(struct iphdr) + 8,
+			    = 8 + sizeof(struct iphdr),
 			    [ICMP_ECHO] = 4,
 			    [ICMP_TIME_EXCEEDED]
-			    = 8 + sizeof(struct iphdr) + 8,
+			    = 8 + sizeof(struct iphdr),
 			    [ICMP_PARAMETERPROB]
-			    = 8 + sizeof(struct iphdr) + 8,
+			    = 8 + sizeof(struct iphdr),
 			    [ICMP_TIMESTAMP] = 20,
 			    [ICMP_TIMESTAMPREPLY] = 20,
 			    [ICMP_ADDRESS] = 12,
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -207,163 +207,22 @@ static void send_reset(struct sk_buff *o
 					   nskb->nh.iph->ihl);
 
 	/* "Never happens" */
-	if (nskb->len > dst_pmtu(nskb->dst))
+	if (nskb->len > dst_mtu(nskb->dst))
 		goto free_nskb;
 
 	nf_ct_attach(nskb, oldskb);
 
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-		ip_finish_output);
+		dst_output);
 	return;
 
  free_nskb:
 	kfree_skb(nskb);
 }
 
-static void send_unreach(struct sk_buff *skb_in, int code)
+static inline void send_unreach(struct sk_buff *skb_in, int code)
 {
-	struct iphdr *iph;
-	struct icmphdr *icmph;
-	struct sk_buff *nskb;
-	u32 saddr;
-	u8 tos;
-	int hh_len, length;
-	struct rtable *rt = (struct rtable*)skb_in->dst;
-	unsigned char *data;
-
-	if (!rt)
-		return;
-
-	/* FIXME: Use sysctl number. --RR */
-	if (!xrlim_allow(&rt->u.dst, 1*HZ))
-		return;
-
-	iph = skb_in->nh.iph;
-
-	/* No replies to physical multicast/broadcast */
-	if (skb_in->pkt_type!=PACKET_HOST)
-		return;
-
-	/* Now check at the protocol level */
-	if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
-		return;
-
-	/* Only reply to fragment 0. */
-	if (iph->frag_off&htons(IP_OFFSET))
-		return;
-
-	/* Ensure we have at least 8 bytes of proto header. */
-	if (skb_in->len < skb_in->nh.iph->ihl*4 + 8)
-		return;
-
-	/* If we send an ICMP error to an ICMP error a mess would result.. */
-	if (iph->protocol == IPPROTO_ICMP) {
-		struct icmphdr ihdr;
-
-		icmph = skb_header_pointer(skb_in, skb_in->nh.iph->ihl*4,
-					   sizeof(ihdr), &ihdr);
-		if (!icmph)
-			return;
-
-		/* Between echo-reply (0) and timestamp (13),
-		   everything except echo-request (8) is an error.
-		   Also, anything greater than NR_ICMP_TYPES is
-		   unknown, and hence should be treated as an error... */
-		if ((icmph->type < ICMP_TIMESTAMP
-		     && icmph->type != ICMP_ECHOREPLY
-		     && icmph->type != ICMP_ECHO)
-		    || icmph->type > NR_ICMP_TYPES)
-			return;
-	}
-
-	saddr = iph->daddr;
-	if (!(rt->rt_flags & RTCF_LOCAL))
-		saddr = 0;
-
-	tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
-
-	{
-		struct flowi fl = {
-			.nl_u = {
-				.ip4_u = {
-					.daddr = skb_in->nh.iph->saddr,
-					.saddr = saddr,
-					.tos = RT_TOS(tos)
-				}
-			},
-			.proto = IPPROTO_ICMP,
-			.uli_u = {
-				.icmpt = {
-					.type = ICMP_DEST_UNREACH,
-					.code = code
-				}
-			}
-		};
-
-		if (ip_route_output_key(&rt, &fl))
-			return;
-	}
-	/* RFC says return as much as we can without exceeding 576 bytes. */
-	length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
-
-	if (length > dst_pmtu(&rt->u.dst))
-		length = dst_pmtu(&rt->u.dst);
-	if (length > 576)
-		length = 576;
-
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
-	nskb = alloc_skb(hh_len + length, GFP_ATOMIC);
-	if (!nskb) {
-		ip_rt_put(rt);
-		return;
-	}
-
-	nskb->priority = 0;
-	nskb->dst = &rt->u.dst;
-	skb_reserve(nskb, hh_len);
-
-	/* Set up IP header */
-	iph = nskb->nh.iph
-		= (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
-	iph->version=4;
-	iph->ihl=5;
-	iph->tos=tos;
-	iph->tot_len = htons(length);
-
-	/* PMTU discovery never applies to ICMP packets. */
-	iph->frag_off = 0;
-
-	iph->ttl = MAXTTL;
-	ip_select_ident(iph, &rt->u.dst, NULL);
-	iph->protocol=IPPROTO_ICMP;
-	iph->saddr=rt->rt_src;
-	iph->daddr=rt->rt_dst;
-	iph->check=0;
-	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-	/* Set up ICMP header. */
-	icmph = nskb->h.icmph
-		= (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
-	icmph->type = ICMP_DEST_UNREACH;
-	icmph->code = code;	
-	icmph->un.gateway = 0;
-	icmph->checksum = 0;
-	
-	/* Copy as much of original packet as will fit */
-	data = skb_put(nskb,
-		       length - sizeof(struct iphdr) - sizeof(struct icmphdr));
-
-	skb_copy_bits(skb_in, 0, data,
-		      length - sizeof(struct iphdr) - sizeof(struct icmphdr));
-
-	icmph->checksum = ip_compute_csum((unsigned char *)icmph,
-					  length - sizeof(struct iphdr));
-
-	nf_ct_attach(nskb, skb_in);
-
-	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-		ip_finish_output);
+	icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
 }	
 
 static unsigned int reject(struct sk_buff **pskb,
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c
@@ -87,14 +87,14 @@ ipt_tcpmss_target(struct sk_buff **pskb,
 			return NF_DROP; /* or IPT_CONTINUE ?? */
 		}
 
-		if(dst_pmtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
+		if(dst_mtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
 			if (net_ratelimit())
 				printk(KERN_ERR
-		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_pmtu((*pskb)->dst));
+		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_mtu((*pskb)->dst));
 			return NF_DROP; /* or IPT_CONTINUE ?? */
 		}
 
-		newmss = dst_pmtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr);
+		newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr);
 	} else
 		newmss = tcpmssinfo->mss;
 
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -33,20 +33,15 @@
 #include <linux/sctp.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-
-#define ASSERT_READ_LOCK(x) 
-#define ASSERT_WRITE_LOCK(x) 
-#include <linux/netfilter_ipv4/lockhelp.h>
-#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/list.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_hashlimit.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
 
 /* FIXME: this is just for IP_NF_ASSERRT */
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 
-#define MS2JIFFIES(x) ((x*HZ)/1000)
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
@@ -67,7 +62,7 @@ struct dsthash_dst {
 
 struct dsthash_ent {
 	/* static / read-only parts in the beginning */
-	struct list_head list;
+	struct hlist_node node;
 	struct dsthash_dst dst;
 
 	/* modified structure members in the end */
@@ -80,7 +75,7 @@ struct dsthash_ent {
 };
 
 struct ipt_hashlimit_htable {
-	struct list_head list;		/* global list of all htables */
+	struct hlist_node node;		/* global list of all htables */
 	atomic_t use;
 
 	struct hashlimit_cfg cfg;	/* config */
@@ -94,12 +89,12 @@ struct ipt_hashlimit_htable {
 	/* seq_file stuff */
 	struct proc_dir_entry *pde;
 
-	struct list_head hash[0];	/* hashtable itself */
+	struct hlist_head hash[0];	/* hashtable itself */
 };
 
-static DECLARE_RWLOCK(hashlimit_lock);	/* protects htables list */
+static DECLARE_LOCK(hashlimit_lock);	/* protects htables list */
 static DECLARE_MUTEX(hlimit_mutex);	/* additional checkentry protection */
-static LIST_HEAD(hashlimit_htables);
+static HLIST_HEAD(hashlimit_htables);
 static kmem_cache_t *hashlimit_cachep;
 
 static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
@@ -113,7 +108,7 @@ static inline int dst_cmp(const struct d
 static inline u_int32_t
 hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
 {
-	return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 & dst->src_port), 
+	return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port), 
 			     dst->src_ip, ht->rnd) % ht->cfg.size);
 }
 
@@ -121,9 +116,17 @@ static inline struct dsthash_ent *
 __dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
 {
 	struct dsthash_ent *ent;
+	struct hlist_node *pos;
 	u_int32_t hash = hash_dst(ht, dst);
-	ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
-	return ent;
+
+	if (!hlist_empty(&ht->hash[hash]))
+		hlist_for_each_entry(ent, pos, &ht->hash[hash], node) {
+			if (dst_cmp(ent, dst)) {
+				return ent;
+			}
+		}
+	
+	return NULL;
 }
 
 /* allocate dsthash_ent, initialize dst, put in htable and lock it */
@@ -162,7 +165,7 @@ __dsthash_alloc_init(struct ipt_hashlimi
 	ent->dst.src_ip = dst->src_ip;
 	ent->dst.src_port = dst->src_port;
 
-	list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
+	hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]);
 
 	return ent;
 }
@@ -170,7 +173,7 @@ __dsthash_alloc_init(struct ipt_hashlimi
 static inline void 
 __dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent)
 {
-	list_del(&ent->list);
+	hlist_del(&ent->node);
 	kmem_cache_free(hashlimit_cachep, ent);
 	atomic_dec(&ht->count);
 }
@@ -210,7 +213,7 @@ static int htable_create(struct ipt_hash
 		hinfo->cfg.max = hinfo->cfg.size;
 
 	for (i = 0; i < hinfo->cfg.size; i++)
-		INIT_LIST_HEAD(&hinfo->hash[i]);
+		INIT_HLIST_HEAD(&hinfo->hash[i]);
 
 	atomic_set(&hinfo->count, 0);
 	atomic_set(&hinfo->use, 1);
@@ -225,14 +228,14 @@ static int htable_create(struct ipt_hash
 	hinfo->pde->data = hinfo;
 
 	init_timer(&hinfo->timer);
-	hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
+	hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
 	hinfo->timer.data = (unsigned long )hinfo;
 	hinfo->timer.function = htable_gc;
 	add_timer(&hinfo->timer);
 
-	WRITE_LOCK(&hashlimit_lock);
-	list_add(&hinfo->list, &hashlimit_htables);
-	WRITE_UNLOCK(&hashlimit_lock);
+	LOCK_BH(&hashlimit_lock);
+	hlist_add_head(&hinfo->node, &hashlimit_htables);
+	UNLOCK_BH(&hashlimit_lock);
 
 	return 0;
 }
@@ -258,8 +261,9 @@ static void htable_selective_cleanup(str
 	/* lock hash table and iterate over it */
 	spin_lock_bh(&ht->lock);
 	for (i = 0; i < ht->cfg.size; i++) {
-		struct dsthash_ent *dh, *n;
-		list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
+		struct dsthash_ent *dh;
+		struct hlist_node *pos, *n;
+		hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) {
 			if ((*select)(ht, dh))
 				__dsthash_free(ht, dh);
 		}
@@ -275,7 +279,7 @@ static void htable_gc(unsigned long htlo
 	htable_selective_cleanup(ht, select_gc);
 
 	/* re-add the timer accordingly */
-	ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
+	ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval);
 	add_timer(&ht->timer);
 }
 
@@ -295,16 +299,17 @@ static void htable_destroy(struct ipt_ha
 static struct ipt_hashlimit_htable *htable_find_get(char *name)
 {
 	struct ipt_hashlimit_htable *hinfo;
+	struct hlist_node *pos;
 
-	READ_LOCK(&hashlimit_lock);
-	list_for_each_entry(hinfo, &hashlimit_htables, list) {
+	LOCK_BH(&hashlimit_lock);
+	hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) {
 		if (!strcmp(name, hinfo->pde->name)) {
 			atomic_inc(&hinfo->use);
-			READ_UNLOCK(&hashlimit_lock);
+			UNLOCK_BH(&hashlimit_lock);
 			return hinfo;
 		}
 	}
-	READ_UNLOCK(&hashlimit_lock);
+	UNLOCK_BH(&hashlimit_lock);
 
 	return NULL;
 }
@@ -312,9 +317,9 @@ static struct ipt_hashlimit_htable *htab
 static void htable_put(struct ipt_hashlimit_htable *hinfo)
 {
 	if (atomic_dec_and_test(&hinfo->use)) {
-		WRITE_LOCK(&hashlimit_lock);
-		list_del(&hinfo->list);
-		WRITE_UNLOCK(&hashlimit_lock);
+		LOCK_BH(&hashlimit_lock);
+		hlist_del(&hinfo->node);
+		UNLOCK_BH(&hashlimit_lock);
 		htable_destroy(hinfo);
 	}
 }
@@ -468,7 +473,7 @@ hashlimit_match(const struct sk_buff *sk
 			return 0;
 		}
 
-		dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
+		dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
 
 		dh->rateinfo.prev = jiffies;
 		dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
@@ -482,7 +487,7 @@ hashlimit_match(const struct sk_buff *sk
 	}
 
 	/* update expiration timeout */
-	dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
+	dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
 
 	rateinfo_recalc(dh, now);
 	if (dh->rateinfo.credit >= dh->rateinfo.cost) {
@@ -619,7 +624,7 @@ static inline int dl_seq_real_show(struc
 	rateinfo_recalc(ent, jiffies);
 
 	return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n",
-			(ent->expires - jiffies)/HZ,
+			(long)(ent->expires - jiffies)/HZ,
 			NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port),
 			NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port),
 			ent->rateinfo.credit, ent->rateinfo.credit_cap,
@@ -631,12 +636,17 @@ static int dl_seq_show(struct seq_file *
 	struct proc_dir_entry *pde = s->private;
 	struct ipt_hashlimit_htable *htable = pde->data;
 	unsigned int *bucket = (unsigned int *)v;
+	struct dsthash_ent *ent;
+	struct hlist_node *pos;
 
-	if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
-		      struct dsthash_ent *, s)) {
-		/* buffer was filled and unable to print that tuple */
-		return 1;
-	}
+	if (!hlist_empty(&htable->hash[*bucket]))
+		hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) {
+			if (dl_seq_real_show(ent, s)) {
+				/* buffer was filled and unable to print that tuple */
+				return 1;
+			}
+		}
+	
 	return 0;
 }
 
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -223,7 +223,7 @@ static int ip_recent_ctrl(struct file *f
 			curr_table->table[count].last_seen = 0;
 			curr_table->table[count].addr = 0;
 			curr_table->table[count].ttl = 0;
-			memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+			memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
 			curr_table->table[count].oldest_pkt = 0;
 			curr_table->table[count].time_pos = 0;
 			curr_table->time_info[count].position = count;
@@ -502,7 +502,7 @@ match(const struct sk_buff *skb,
 		location = time_info[curr_table->time_pos].position;
 		hash_table[r_list[location].hash_entry] = -1;
 		hash_table[hash_result] = location;
-		memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+		memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
 		r_list[location].time_pos = curr_table->time_pos;
 		r_list[location].addr = addr;
 		r_list[location].ttl = ttl;
@@ -631,7 +631,7 @@ match(const struct sk_buff *skb,
 			r_list[location].last_seen = 0;
 			r_list[location].addr = 0;
 			r_list[location].ttl = 0;
-			memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+			memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
 			r_list[location].oldest_pkt = 0;
 			ans = !info->invert;
 		}
@@ -734,10 +734,10 @@ checkentry(const char *tablename,
 	memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot);
 #ifdef DEBUG
 	if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n",
-			sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
+			sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
 #endif
 
-	hold = vmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
+	hold = vmalloc(sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
 #ifdef DEBUG
 	if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n");
 #endif
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -103,13 +103,15 @@ static struct nf_hook_ops ipt_ops[] = {
 	  .hook = ipt_hook, 
 	  .pf = PF_INET, 
 	  .hooknum = NF_IP_PRE_ROUTING, 
-	  .priority = NF_IP_PRI_RAW
+	  .priority = NF_IP_PRI_RAW,
+	  .owner = THIS_MODULE,
 	},
 	{
 	  .hook = ipt_hook, 
 	  .pf = PF_INET, 
 	  .hooknum = NF_IP_LOCAL_OUT, 
-	  .priority = NF_IP_PRI_RAW
+	  .priority = NF_IP_PRI_RAW,
+	  .owner = THIS_MODULE,
 	},
 };
 
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: protocol.c,v 1.14 2001/05/18 02:25:49 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  * Fixes:
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: raw.c,v 1.64 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  * Fixes:
@@ -457,7 +457,7 @@ static int raw_sendmsg(struct kiocb *ioc
 			daddr = ipc.opt->faddr;
 		}
 	}
-	tos = RT_TOS(inet->tos) | sk->sk_localroute;
+	tos = RT_CONN_FLAGS(sk);
 	if (msg->msg_flags & MSG_DONTROUTE)
 		tos |= RTO_ONLINK;
 
@@ -724,7 +724,7 @@ struct proto raw_prot = {
 	.backlog_rcv =	raw_rcv_skb,
 	.hash =		raw_v4_hash,
 	.unhash =	raw_v4_unhash,
-	.slab_obj_size = sizeof(struct raw_sock),
+	.obj_size =	sizeof(struct raw_sock),
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox, <gw4pts@gw4pts.ampr.org>
  *		Linus Torvalds, <Linus.Torvalds@helsinki.fi>
@@ -100,10 +100,14 @@
 #include <net/tcp.h>
 #include <net/icmp.h>
 #include <net/xfrm.h>
+#include <net/ip_mp_alg.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
 
+#define RT_FL_TOS(oldflp) \
+    ((u32)(oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK)))
+
 #define IP_MAX_MTU	0xFFF0
 
 #define RT_GC_TIMEOUT (300*HZ)
@@ -393,7 +397,7 @@ static int rt_cpu_seq_show(struct seq_fi
 	struct rt_cache_stat *st = v;
 
 	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "entries  in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n");
+		seq_printf(seq, "entries  in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n");
 		return 0;
 	}
 	
@@ -447,11 +451,13 @@ static struct file_operations rt_cpu_seq
   
 static __inline__ void rt_free(struct rtable *rt)
 {
+	multipath_remove(rt);
 	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
 }
 
 static __inline__ void rt_drop(struct rtable *rt)
 {
+	multipath_remove(rt);
 	ip_rt_put(rt);
 	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
 }
@@ -513,6 +519,59 @@ static inline u32 rt_score(struct rtable
 	return score;
 }
 
+static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
+{
+	return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 &&
+	       fl1->oif     == fl2->oif &&
+	       fl1->iif     == fl2->iif;
+}
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+static struct rtable **rt_remove_balanced_route(struct rtable **chain_head,
+						struct rtable *expentry,
+						int *removed_count)
+{
+	int passedexpired = 0;
+	struct rtable **nextstep = NULL;
+	struct rtable **rthp = chain_head;
+	struct rtable *rth;
+
+	if (removed_count)
+		*removed_count = 0;
+
+	while ((rth = *rthp) != NULL) {
+		if (rth == expentry)
+			passedexpired = 1;
+
+		if (((*rthp)->u.dst.flags & DST_BALANCED) != 0  &&
+		    compare_keys(&(*rthp)->fl, &expentry->fl)) {
+			if (*rthp == expentry) {
+				*rthp = rth->u.rt_next;
+				continue;
+			} else {
+				*rthp = rth->u.rt_next;
+				rt_free(rth);
+				if (removed_count)
+					++(*removed_count);
+			}
+		} else {
+			if (!((*rthp)->u.dst.flags & DST_BALANCED) &&
+			    passedexpired && !nextstep)
+				nextstep = &rth->u.rt_next;
+
+			rthp = &rth->u.rt_next;
+		}
+	}
+
+	rt_free(expentry);
+	if (removed_count)
+		++(*removed_count);
+
+	return nextstep;
+}
+#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+
+
 /* This runs via a timer and thus is always in BH context. */
 static void rt_check_expire(unsigned long dummy)
 {
@@ -544,8 +603,22 @@ static void rt_check_expire(unsigned lon
 			}
 
 			/* Cleanup aged off entries. */
-			*rthp = rth->u.rt_next;
-			rt_free(rth);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+			/* remove all related balanced entries if necessary */
+			if (rth->u.dst.flags & DST_BALANCED) {
+				rthp = rt_remove_balanced_route(
+					&rt_hash_table[i].chain,
+					rth, NULL);
+				if (!rthp)
+					break;
+			} else {
+				*rthp = rth->u.rt_next;
+				rt_free(rth);
+			}
+#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+ 			*rthp = rth->u.rt_next;
+ 			rt_free(rth);
+#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
 		}
 		spin_unlock(&rt_hash_table[i].lock);
 
@@ -593,6 +666,9 @@ void rt_cache_flush(int delay)
 	if (delay < 0)
 		delay = ip_rt_min_delay;
 
+	/* flush existing multipath state*/
+	multipath_flush();
+
 	spin_lock_bh(&rt_flush_lock);
 
 	if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
@@ -711,9 +787,30 @@ static int rt_garbage_collect(void)
 					rthp = &rth->u.rt_next;
 					continue;
 				}
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+				/* remove all related balanced entries
+				 * if necessary
+				 */
+				if (rth->u.dst.flags & DST_BALANCED) {
+					int r;
+
+					rthp = rt_remove_balanced_route(
+						&rt_hash_table[i].chain,
+						rth,
+						&r);
+					goal -= r;
+					if (!rthp)
+						break;
+				} else {
+					*rthp = rth->u.rt_next;
+					rt_free(rth);
+					goal--;
+				}
+#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
 				*rthp = rth->u.rt_next;
 				rt_free(rth);
 				goal--;
+#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
 			}
 			spin_unlock_bh(&rt_hash_table[k].lock);
 			if (goal <= 0)
@@ -767,13 +864,6 @@ work_done:
 out:	return 0;
 }
 
-static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
-{
-	return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 &&
-	       fl1->oif     == fl2->oif &&
-	       fl1->iif     == fl2->iif;
-}
-
 static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
 {
 	struct rtable	*rth, **rthp;
@@ -794,7 +884,12 @@ restart:
 
 	spin_lock_bh(&rt_hash_table[hash].lock);
 	while ((rth = *rthp) != NULL) {
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+		if (!(rth->u.dst.flags & DST_BALANCED) &&
+		    compare_keys(&rth->fl, &rt->fl)) {
+#else
 		if (compare_keys(&rth->fl, &rt->fl)) {
+#endif
 			/* Put it first */
 			*rthp = rth->u.rt_next;
 			/*
@@ -953,7 +1048,8 @@ void __ip_select_ident(struct iphdr *iph
 			return;
 		}
 	} else
-		printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", NET_CALLER(iph));
+		printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", 
+		       __builtin_return_address(0));
 
 	ip_select_fb_ident(iph);
 }
@@ -1322,7 +1418,6 @@ static void ip_rt_update_pmtu(struct dst
 
 static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 {
-	dst_release(dst);
 	return NULL;
 }
 
@@ -1535,6 +1630,223 @@ e_inval:
 	return -EINVAL;
 }
 
+
+static void ip_handle_martian_source(struct net_device *dev,
+				     struct in_device *in_dev,
+				     struct sk_buff *skb,
+				     u32 daddr,
+				     u32 saddr) 
+{
+	RT_CACHE_STAT_INC(in_martian_src);
+#ifdef CONFIG_IP_ROUTE_VERBOSE
+	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {
+		/*
+		 *	RFC1812 recommendation, if source is martian,
+		 *	the only hint is MAC header.
+		 */
+		printk(KERN_WARNING "martian source %u.%u.%u.%u from "
+			"%u.%u.%u.%u, on dev %s\n",
+			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
+		if (dev->hard_header_len) {
+			int i;
+			unsigned char *p = skb->mac.raw;
+			printk(KERN_WARNING "ll header: ");
+			for (i = 0; i < dev->hard_header_len; i++, p++) {
+				printk("%02x", *p);
+				if (i < (dev->hard_header_len - 1))
+					printk(":");
+			}
+			printk("\n");
+		}
+	}
+#endif
+}
+
+static inline int __mkroute_input(struct sk_buff *skb, 
+				  struct fib_result* res, 
+				  struct in_device *in_dev, 
+				  u32 daddr, u32 saddr, u32 tos, 
+				  struct rtable **result) 
+{
+
+	struct rtable *rth;
+	int err;
+	struct in_device *out_dev;
+	unsigned flags = 0;
+	u32 spec_dst, itag;
+
+	/* get a working reference to the output device */
+	out_dev = in_dev_get(FIB_RES_DEV(*res));
+	if (out_dev == NULL) {
+		if (net_ratelimit())
+			printk(KERN_CRIT "Bug in ip_route_input" \
+			       "_slow(). Please, report\n");
+		return -EINVAL;
+	}
+
+
+	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), 
+				  in_dev->dev, &spec_dst, &itag);
+	if (err < 0) {
+		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, 
+					 saddr);
+		
+		err = -EINVAL;
+		goto cleanup;
+	}
+
+	if (err)
+		flags |= RTCF_DIRECTSRC;
+
+	if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
+	    (IN_DEV_SHARED_MEDIA(out_dev) ||
+	     inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
+		flags |= RTCF_DOREDIRECT;
+
+	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.
+		 */
+		if (out_dev == in_dev && !(flags & RTCF_DNAT)) {
+			err = -EINVAL;
+			goto cleanup;
+		}
+	}
+
+
+	rth = dst_alloc(&ipv4_dst_ops);
+	if (!rth) {
+		err = -ENOBUFS;
+		goto cleanup;
+	}
+
+	rth->u.dst.flags= DST_HOST;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	if (res->fi->fib_nhs > 1)
+		rth->u.dst.flags |= DST_BALANCED;
+#endif
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
+	if (in_dev->cnf.no_xfrm)
+		rth->u.dst.flags |= DST_NOXFRM;
+	rth->fl.fl4_dst	= daddr;
+	rth->rt_dst	= daddr;
+	rth->fl.fl4_tos	= tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+	rth->fl.fl4_fwmark= skb->nfmark;
+#endif
+	rth->fl.fl4_src	= saddr;
+	rth->rt_src	= saddr;
+	rth->rt_gateway	= daddr;
+	rth->rt_iif 	=
+		rth->fl.iif	= in_dev->dev->ifindex;
+	rth->u.dst.dev	= (out_dev)->dev;
+	dev_hold(rth->u.dst.dev);
+	rth->idev	= in_dev_get(rth->u.dst.dev);
+	rth->fl.oif 	= 0;
+	rth->rt_spec_dst= spec_dst;
+
+	rth->u.dst.input = ip_forward;
+	rth->u.dst.output = ip_output;
+
+	rt_set_nexthop(rth, res, itag);
+
+	rth->rt_flags = flags;
+
+	*result = rth;
+	err = 0;
+ cleanup:
+	/* release the working reference to the output device */
+	in_dev_put(out_dev);
+	return err;
+}						
+
+static inline int ip_mkroute_input_def(struct sk_buff *skb, 
+				       struct fib_result* res, 
+				       const struct flowi *fl,
+				       struct in_device *in_dev,
+				       u32 daddr, u32 saddr, u32 tos)
+{
+	struct rtable* rth;
+	int err;
+	unsigned hash;
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+	if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
+		fib_select_multipath(fl, res);
+#endif
+
+	/* create a routing cache entry */
+	err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
+	if (err)
+		return err;
+	atomic_set(&rth->u.dst.__refcnt, 1);
+
+	/* put it into the cache */
+	hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+	return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);	
+}
+
+static inline int ip_mkroute_input(struct sk_buff *skb, 
+				   struct fib_result* res, 
+				   const struct flowi *fl,
+				   struct in_device *in_dev,
+				   u32 daddr, u32 saddr, u32 tos)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	struct rtable* rth;
+	unsigned char hop, hopcount, lasthop;
+	int err = -EINVAL;
+	unsigned int hash;
+
+	if (res->fi)
+		hopcount = res->fi->fib_nhs;
+	else
+		hopcount = 1;
+
+	lasthop = hopcount - 1;
+
+	/* distinguish between multipath and singlepath */
+	if (hopcount < 2)
+		return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
+					    saddr, tos);
+	
+	/* add all alternatives to the routing cache */
+	for (hop = 0; hop < hopcount; hop++) {
+		res->nh_sel = hop;
+
+		/* create a routing cache entry */
+		err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
+				      &rth);
+		if (err)
+			return err;
+
+		/* put it into the cache */
+		hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+		err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+		if (err)
+			return err;
+
+		/* forward hop information to multipath impl. */
+		multipath_set_nhinfo(rth,
+				     FIB_RES_NETWORK(*res),
+				     FIB_RES_NETMASK(*res),
+				     res->prefixlen,
+				     &FIB_RES_NH(*res));
+
+		/* only for the last hop the reference count is handled
+		 * outside
+		 */
+		if (hop == lasthop)
+			atomic_set(&(skb->dst->__refcnt), 1);
+	}
+	return err;
+#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
+	return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
+#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
+}
+
+
 /*
  *	NOTE. We drop all the packets that has local source
  *	addresses, because every properly looped back packet
@@ -1546,11 +1858,10 @@ e_inval:
  */
 
 static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
-			u8 tos, struct net_device *dev)
+			       u8 tos, struct net_device *dev)
 {
 	struct fib_result res;
 	struct in_device *in_dev = in_dev_get(dev);
-	struct in_device *out_dev = NULL;
 	struct flowi fl = { .nl_u = { .ip4_u =
 				      { .daddr = daddr,
 					.saddr = saddr,
@@ -1574,8 +1885,6 @@ static int ip_route_input_slow(struct sk
 	if (!in_dev)
 		goto out;
 
-	hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
-
 	/* Check for the most weird martians, which can be not detected
 	   by fib_lookup.
 	 */
@@ -1628,79 +1937,14 @@ static int ip_route_input_slow(struct sk
 	if (res.type != RTN_UNICAST)
 		goto martian_destination;
 
-#ifdef CONFIG_IP_ROUTE_MULTIPATH
-	if (res.fi->fib_nhs > 1 && fl.oif == 0)
-		fib_select_multipath(&fl, &res);
-#endif
-	out_dev = in_dev_get(FIB_RES_DEV(res));
-	if (out_dev == NULL) {
-		if (net_ratelimit())
-			printk(KERN_CRIT "Bug in ip_route_input_slow(). "
-					 "Please, report\n");
-		goto e_inval;
-	}
-
-	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev,
-				  &spec_dst, &itag);
-	if (err < 0)
-		goto martian_source;
-
-	if (err)
-		flags |= RTCF_DIRECTSRC;
-
-	if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
-	    (IN_DEV_SHARED_MEDIA(out_dev) ||
-	     inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
-		flags |= RTCF_DOREDIRECT;
-
-	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.
-		 */
-		if (out_dev == in_dev && !(flags & RTCF_DNAT))
-			goto e_inval;
-	}
-
-	rth = dst_alloc(&ipv4_dst_ops);
-	if (!rth)
+	err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
+	if (err == -ENOBUFS)
 		goto e_nobufs;
-
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
-	if (in_dev->cnf.no_policy)
-		rth->u.dst.flags |= DST_NOPOLICY;
-	if (in_dev->cnf.no_xfrm)
-		rth->u.dst.flags |= DST_NOXFRM;
-	rth->fl.fl4_dst	= daddr;
-	rth->rt_dst	= daddr;
-	rth->fl.fl4_tos	= tos;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->fl.fl4_fwmark= skb->nfmark;
-#endif
-	rth->fl.fl4_src	= saddr;
-	rth->rt_src	= saddr;
-	rth->rt_gateway	= daddr;
-	rth->rt_iif 	=
-	rth->fl.iif	= dev->ifindex;
-	rth->u.dst.dev	= out_dev->dev;
-	dev_hold(rth->u.dst.dev);
-	rth->idev	= in_dev_get(rth->u.dst.dev);
-	rth->fl.oif 	= 0;
-	rth->rt_spec_dst= spec_dst;
-
-	rth->u.dst.input = ip_forward;
-	rth->u.dst.output = ip_output;
-
-	rt_set_nexthop(rth, &res, itag);
-
-	rth->rt_flags = flags;
-
-intern:
-	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+	if (err == -EINVAL)
+		goto e_inval;
+	
 done:
 	in_dev_put(in_dev);
-	if (out_dev)
-		in_dev_put(out_dev);
 	if (free_res)
 		fib_res_put(&res);
 out:	return err;
@@ -1760,7 +2004,9 @@ local_input:
 		rth->rt_flags 	&= ~RTCF_LOCAL;
 	}
 	rth->rt_type	= res.type;
-	goto intern;
+	hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
+	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+	goto done;
 
 no_route:
 	RT_CACHE_STAT_INC(in_no_route);
@@ -1788,30 +2034,7 @@ e_nobufs:
 	goto done;
 
 martian_source:
-
-	RT_CACHE_STAT_INC(in_martian_src);
-#ifdef CONFIG_IP_ROUTE_VERBOSE
-	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {
-		/*
-		 *	RFC1812 recommendation, if source is martian,
-		 *	the only hint is MAC header.
-		 */
-		printk(KERN_WARNING "martian source %u.%u.%u.%u from "
-			"%u.%u.%u.%u, on dev %s\n",
-			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
-		if (dev->hard_header_len) {
-			int i;
-			unsigned char *p = skb->mac.raw;
-			printk(KERN_WARNING "ll header: ");
-			for (i = 0; i < dev->hard_header_len; i++, p++) {
-				printk("%02x", *p);
-				if (i < (dev->hard_header_len - 1))
-					printk(":");
-			}
-			printk("\n");
-		}
-	}
-#endif
+	ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
 	goto e_inval;
 }
 
@@ -1882,13 +2105,224 @@ int ip_route_input(struct sk_buff *skb, 
 	return ip_route_input_slow(skb, daddr, saddr, tos, dev);
 }
 
+static inline int __mkroute_output(struct rtable **result,
+				   struct fib_result* res, 
+				   const struct flowi *fl,
+				   const struct flowi *oldflp, 
+				   struct net_device *dev_out, 
+				   unsigned flags) 
+{
+	struct rtable *rth;
+	struct in_device *in_dev;
+	u32 tos = RT_FL_TOS(oldflp);
+	int err = 0;
+
+	if (LOOPBACK(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
+		return -EINVAL;
+
+	if (fl->fl4_dst == 0xFFFFFFFF)
+		res->type = RTN_BROADCAST;
+	else if (MULTICAST(fl->fl4_dst))
+		res->type = RTN_MULTICAST;
+	else if (BADCLASS(fl->fl4_dst) || ZERONET(fl->fl4_dst))
+		return -EINVAL;
+
+	if (dev_out->flags & IFF_LOOPBACK)
+		flags |= RTCF_LOCAL;
+
+	/* get work reference to inet device */
+	in_dev = in_dev_get(dev_out);
+	if (!in_dev)
+		return -EINVAL;
+
+	if (res->type == RTN_BROADCAST) {
+		flags |= RTCF_BROADCAST | RTCF_LOCAL;
+		if (res->fi) {
+			fib_info_put(res->fi);
+			res->fi = NULL;
+		}
+	} else if (res->type == RTN_MULTICAST) {
+		flags |= RTCF_MULTICAST|RTCF_LOCAL;
+		if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, 
+				 oldflp->proto))
+			flags &= ~RTCF_LOCAL;
+		/* If multicast route do not exist use
+		   default one, but do not gateway in this case.
+		   Yes, it is hack.
+		 */
+		if (res->fi && res->prefixlen < 4) {
+			fib_info_put(res->fi);
+			res->fi = NULL;
+		}
+	}
+
+
+	rth = dst_alloc(&ipv4_dst_ops);
+	if (!rth) {
+		err = -ENOBUFS;
+		goto cleanup;
+	}		
+
+	rth->u.dst.flags= DST_HOST;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	if (res->fi) {
+		rth->rt_multipath_alg = res->fi->fib_mp_alg;
+		if (res->fi->fib_nhs > 1)
+			rth->u.dst.flags |= DST_BALANCED;
+	}
+#endif
+	if (in_dev->cnf.no_xfrm)
+		rth->u.dst.flags |= DST_NOXFRM;
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
+
+	rth->fl.fl4_dst	= oldflp->fl4_dst;
+	rth->fl.fl4_tos	= tos;
+	rth->fl.fl4_src	= oldflp->fl4_src;
+	rth->fl.oif	= oldflp->oif;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+	rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
+#endif
+	rth->rt_dst	= fl->fl4_dst;
+	rth->rt_src	= fl->fl4_src;
+	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;
+	/* get references to the devices that are to be hold by the routing 
+	   cache entry */
+	rth->u.dst.dev	= dev_out;
+	dev_hold(dev_out);
+	rth->idev	= in_dev_get(dev_out);
+	rth->rt_gateway = fl->fl4_dst;
+	rth->rt_spec_dst= fl->fl4_src;
+
+	rth->u.dst.output=ip_output;
+
+	RT_CACHE_STAT_INC(out_slow_tot);
+
+	if (flags & RTCF_LOCAL) {
+		rth->u.dst.input = ip_local_deliver;
+		rth->rt_spec_dst = fl->fl4_dst;
+	}
+	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
+		rth->rt_spec_dst = fl->fl4_src;
+		if (flags & RTCF_LOCAL && 
+		    !(dev_out->flags & IFF_LOOPBACK)) {
+			rth->u.dst.output = ip_mc_output;
+			RT_CACHE_STAT_INC(out_slow_mc);
+		}
+#ifdef CONFIG_IP_MROUTE
+		if (res->type == RTN_MULTICAST) {
+			if (IN_DEV_MFORWARD(in_dev) &&
+			    !LOCAL_MCAST(oldflp->fl4_dst)) {
+				rth->u.dst.input = ip_mr_input;
+				rth->u.dst.output = ip_mc_output;
+			}
+		}
+#endif
+	}
+
+	rt_set_nexthop(rth, res, 0);
+
+	rth->rt_flags = flags;
+
+	*result = rth;
+ cleanup:
+	/* release work reference to inet device */
+	in_dev_put(in_dev);
+
+	return err;
+}
+
+static inline int ip_mkroute_output_def(struct rtable **rp,
+					struct fib_result* res,
+					const struct flowi *fl,
+					const struct flowi *oldflp,
+					struct net_device *dev_out,
+					unsigned flags)
+{
+	struct rtable *rth;
+	int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
+	unsigned hash;
+	if (err == 0) {
+		u32 tos = RT_FL_TOS(oldflp);
+
+		atomic_set(&rth->u.dst.__refcnt, 1);
+		
+		hash = rt_hash_code(oldflp->fl4_dst, 
+				    oldflp->fl4_src ^ (oldflp->oif << 5), tos);
+		err = rt_intern_hash(hash, rth, rp);
+	}
+	
+	return err;
+}
+
+static inline int ip_mkroute_output(struct rtable** rp,
+				    struct fib_result* res,
+				    const struct flowi *fl,
+				    const struct flowi *oldflp,
+				    struct net_device *dev_out,
+				    unsigned flags)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	u32 tos = RT_FL_TOS(oldflp);
+	unsigned char hop;
+	unsigned hash;
+	int err = -EINVAL;
+	struct rtable *rth;
+
+	if (res->fi && res->fi->fib_nhs > 1) {
+		unsigned char hopcount = res->fi->fib_nhs;
+
+		for (hop = 0; hop < hopcount; hop++) {
+			struct net_device *dev2nexthop;
+
+			res->nh_sel = hop;
+
+			/* hold a work reference to the output device */
+			dev2nexthop = FIB_RES_DEV(*res);
+			dev_hold(dev2nexthop);
+
+			err = __mkroute_output(&rth, res, fl, oldflp,
+					       dev2nexthop, flags);
+
+			if (err != 0)
+				goto cleanup;
+
+			hash = rt_hash_code(oldflp->fl4_dst, 
+					    oldflp->fl4_src ^
+					    (oldflp->oif << 5), tos);
+			err = rt_intern_hash(hash, rth, rp);
+
+			/* forward hop information to multipath impl. */
+			multipath_set_nhinfo(rth,
+					     FIB_RES_NETWORK(*res),
+					     FIB_RES_NETMASK(*res),
+					     res->prefixlen,
+					     &FIB_RES_NH(*res));
+		cleanup:
+			/* release work reference to output device */
+			dev_put(dev2nexthop);
+
+			if (err != 0)
+				return err;
+		}
+		atomic_set(&(*rp)->u.dst.__refcnt, 1);
+		return err;
+	} else {
+		return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
+					     flags);
+	}
+#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+	return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out, flags);
+#endif
+}
+
 /*
  * Major route resolver routine.
  */
 
 static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
 {
-	u32 tos	= oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK);
+	u32 tos	= RT_FL_TOS(oldflp);
 	struct flowi fl = { .nl_u = { .ip4_u =
 				      { .daddr = oldflp->fl4_dst,
 					.saddr = oldflp->fl4_src,
@@ -1904,13 +2338,11 @@ static int ip_route_output_slow(struct r
 			    .oif = oldflp->oif };
 	struct fib_result res;
 	unsigned flags = 0;
-	struct rtable *rth;
 	struct net_device *dev_out = NULL;
-	struct in_device *in_dev = NULL;
-	unsigned hash;
 	int free_res = 0;
 	int err;
 
+
 	res.fi		= NULL;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	res.r		= NULL;
@@ -1960,6 +2392,8 @@ static int ip_route_output_slow(struct r
 			dev_put(dev_out);
 		dev_out = NULL;
 	}
+
+
 	if (oldflp->oif) {
 		dev_out = dev_get_by_index(oldflp->oif);
 		err = -ENODEV;
@@ -2066,117 +2500,16 @@ static int ip_route_output_slow(struct r
 	dev_hold(dev_out);
 	fl.oif = dev_out->ifindex;
 
-make_route:
-	if (LOOPBACK(fl.fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
-		goto e_inval;
 
-	if (fl.fl4_dst == 0xFFFFFFFF)
-		res.type = RTN_BROADCAST;
-	else if (MULTICAST(fl.fl4_dst))
-		res.type = RTN_MULTICAST;
-	else if (BADCLASS(fl.fl4_dst) || ZERONET(fl.fl4_dst))
-		goto e_inval;
-
-	if (dev_out->flags & IFF_LOOPBACK)
-		flags |= RTCF_LOCAL;
-
-	in_dev = in_dev_get(dev_out);
-	if (!in_dev)
-		goto e_inval;
-
-	if (res.type == RTN_BROADCAST) {
-		flags |= RTCF_BROADCAST | RTCF_LOCAL;
-		if (res.fi) {
-			fib_info_put(res.fi);
-			res.fi = NULL;
-		}
-	} else if (res.type == RTN_MULTICAST) {
-		flags |= RTCF_MULTICAST|RTCF_LOCAL;
-		if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, oldflp->proto))
-			flags &= ~RTCF_LOCAL;
-		/* If multicast route do not exist use
-		   default one, but do not gateway in this case.
-		   Yes, it is hack.
-		 */
-		if (res.fi && res.prefixlen < 4) {
-			fib_info_put(res.fi);
-			res.fi = NULL;
-		}
-	}
-
-	rth = dst_alloc(&ipv4_dst_ops);
-	if (!rth)
-		goto e_nobufs;
-
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
-	if (in_dev->cnf.no_xfrm)
-		rth->u.dst.flags |= DST_NOXFRM;
-	if (in_dev->cnf.no_policy)
-		rth->u.dst.flags |= DST_NOPOLICY;
-	rth->fl.fl4_dst	= oldflp->fl4_dst;
-	rth->fl.fl4_tos	= tos;
-	rth->fl.fl4_src	= oldflp->fl4_src;
-	rth->fl.oif	= oldflp->oif;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
-#endif
-	rth->rt_dst	= fl.fl4_dst;
-	rth->rt_src	= fl.fl4_src;
-	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;
-	rth->u.dst.dev	= dev_out;
-	dev_hold(dev_out);
-	rth->idev	= in_dev_get(dev_out);
-	rth->rt_gateway = fl.fl4_dst;
-	rth->rt_spec_dst= fl.fl4_src;
-
-	rth->u.dst.output=ip_output;
-
-	RT_CACHE_STAT_INC(out_slow_tot);
-
-	if (flags & RTCF_LOCAL) {
-		rth->u.dst.input = ip_local_deliver;
-		rth->rt_spec_dst = fl.fl4_dst;
-	}
-	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
-		rth->rt_spec_dst = fl.fl4_src;
-		if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) {
-			rth->u.dst.output = ip_mc_output;
-			RT_CACHE_STAT_INC(out_slow_mc);
-		}
-#ifdef CONFIG_IP_MROUTE
-		if (res.type == RTN_MULTICAST) {
-			if (IN_DEV_MFORWARD(in_dev) &&
-			    !LOCAL_MCAST(oldflp->fl4_dst)) {
-				rth->u.dst.input = ip_mr_input;
-				rth->u.dst.output = ip_mc_output;
-			}
-		}
-#endif
-	}
-
-	rt_set_nexthop(rth, &res, 0);
-	
+make_route:
+	err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);
 
-	rth->rt_flags = flags;
 
-	hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos);
-	err = rt_intern_hash(hash, rth, rp);
-done:
 	if (free_res)
 		fib_res_put(&res);
 	if (dev_out)
 		dev_put(dev_out);
-	if (in_dev)
-		in_dev_put(in_dev);
 out:	return err;
-
-e_inval:
-	err = -EINVAL;
-	goto done;
-e_nobufs:
-	err = -ENOBUFS;
-	goto done;
 }
 
 int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
@@ -2198,6 +2531,17 @@ int __ip_route_output_key(struct rtable 
 #endif
 		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
 			    (IPTOS_RT_MASK | RTO_ONLINK))) {
+
+			/* check for multipath routes and choose one if
+			 * necessary
+			 */
+			if (multipath_select_route(flp, rth, rp)) {
+				dst_hold(&(*rp)->u.dst);
+				RT_CACHE_STAT_INC(out_hit);
+				rcu_read_unlock_bh();
+				return 0;
+			}
+
 			rth->u.dst.lastuse = jiffies;
 			dst_hold(&rth->u.dst);
 			rth->u.dst.__use++;
@@ -2272,6 +2616,13 @@ static int rt_fill_info(struct sk_buff *
 	if (rt->u.dst.tclassid)
 		RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
 #endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+	if (rt->rt_multipath_alg != IP_MP_ALG_NONE) {
+		__u32 alg = rt->rt_multipath_alg;
+
+		RTA_PUT(skb, RTA_MP_ALGO, 4, &alg);
+	}
+#endif
 	if (rt->fl.iif)
 		RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
 	else if (rt->rt_src != rt->fl.fl4_src)
@@ -2492,7 +2843,7 @@ ctl_table ipv4_route_table[] = {
 		.procname	= "flush",
 		.data		= &flush_delay,
 		.maxlen		= sizeof(int),
-		.mode		= 0644,
+		.mode		= 0200,
 		.proc_handler	= &ipv4_sysctl_rtcache_flush,
 		.strategy	= &ipv4_sysctl_rtcache_flush_strategy,
 	},
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -17,11 +17,88 @@
 #include <linux/tcp.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/cryptohash.h>
 #include <linux/kernel.h>
 #include <net/tcp.h>
 
 extern int sysctl_tcp_syncookies;
 
+static __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+
+static __init int init_syncookies(void)
+{
+	get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
+	return 0;
+}
+module_init(init_syncookies);
+
+#define COOKIEBITS 24	/* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport,
+		       u32 count, int c)
+{
+	__u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS];
+
+	memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c]));
+	tmp[0] = saddr;
+	tmp[1] = daddr;
+	tmp[2] = (sport << 16) + dport;
+	tmp[3] = count;
+	sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
+
+	return tmp[17];
+}
+
+static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
+				   __u16 dport, __u32 sseq, __u32 count,
+				   __u32 data)
+{
+	/*
+	 * Compute the secure sequence number.
+	 * The output should be:
+   	 *   HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24)
+	 *      + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
+	 * Where sseq is their sequence number and count increases every
+	 * minute by 1.
+	 * As an extra hack, we add a small "data" value that encodes the
+	 * MSS into the second hash value.
+	 */
+
+	return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
+		sseq + (count << COOKIEBITS) +
+		((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
+		 & COOKIEMASK));
+}
+
+/*
+ * This retrieves the small "data" value from the syncookie.
+ * If the syncookie is bad, the data returned will be out of
+ * range.  This must be checked by the caller.
+ *
+ * The count value used to generate the cookie must be within
+ * "maxdiff" if the current (passed-in) "count".  The return value
+ * is (__u32)-1 if this test fails.
+ */
+static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr,
+				  __u16 sport, __u16 dport, __u32 sseq,
+				  __u32 count, __u32 maxdiff)
+{
+	__u32 diff;
+
+	/* Strip away the layers from the cookie */
+	cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq;
+
+	/* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
+	diff = (count - (cookie >> COOKIEBITS)) & ((__u32) - 1 >> COOKIEBITS);
+	if (diff >= maxdiff)
+		return (__u32)-1;
+
+	return (cookie -
+		cookie_hash(saddr, daddr, sport, dport, count - diff, 1))
+		& COOKIEMASK;	/* Leaving the data behind */
+}
+
 /* 
  * This table has to be sorted and terminated with (__u16)-1.
  * XXX generate a better table.
@@ -102,10 +179,9 @@ static inline struct sock *get_cookie_so
 	struct sock *child;
 
 	child = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
-	if (child) {
-		sk_set_owner(child, sk->sk_owner);
+	if (child)
 		tcp_acceptq_queue(sk, req, child);
-	} else
+	else
 		tcp_openreq_free(req);
 
 	return child;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -23,6 +23,7 @@ extern int sysctl_ip_nonlocal_bind;
 extern int sysctl_icmp_echo_ignore_all;
 extern int sysctl_icmp_echo_ignore_broadcasts;
 extern int sysctl_icmp_ignore_bogus_error_responses;
+extern int sysctl_icmp_errors_use_inbound_ifaddr;
 
 /* From ip_fragment.c */
 extern int sysctl_ipfrag_low_thresh;
@@ -396,6 +397,14 @@ ctl_table ipv4_table[] = {
 		.proc_handler	= &proc_dointvec
 	},
 	{
+		.ctl_name	= NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
+		.procname	= "icmp_errors_use_inbound_ifaddr",
+		.data		= &sysctl_icmp_errors_use_inbound_ifaddr,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
 		.ctl_name	= NET_IPV4_ROUTE,
 		.procname	= "route",
 		.maxlen		= 0,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
@@ -598,6 +598,7 @@ static inline void skb_entail(struct soc
 	TCP_SKB_CB(skb)->end_seq = tp->write_seq;
 	TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
 	TCP_SKB_CB(skb)->sacked = 0;
+	skb_header_release(skb);
 	__skb_queue_tail(&sk->sk_write_queue, skb);
 	sk_charge_skb(sk, skb);
 	if (!sk->sk_send_head)
@@ -2337,7 +2338,7 @@ void __init tcp_init(void)
 			(tcp_bhash_size * sizeof(struct tcp_bind_hashbucket));
 			order++)
 		;
-	if (order > 4) {
+	if (order >= 4) {
 		sysctl_local_port_range[0] = 32768;
 		sysctl_local_port_range[1] = 61000;
 		sysctl_tcp_max_tw_buckets = 180000;
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -777,8 +777,9 @@ static inline void tcpdiag_rcv_skb(struc
 static void tcpdiag_rcv(struct sock *sk, int len)
 {
 	struct sk_buff *skb;
+	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
 
-	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+	while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
 		tcpdiag_rcv_skb(skb);
 		kfree_skb(skb);
 	}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: tcp_input.c,v 1.243 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
@@ -71,6 +71,7 @@
 #include <net/tcp.h>
 #include <net/inet_common.h>
 #include <linux/ipsec.h>
+#include <asm/unaligned.h>
 
 int sysctl_tcp_timestamps = 1;
 int sysctl_tcp_window_scaling = 1;
@@ -977,7 +978,7 @@ tcp_sacktag_write_queue(struct sock *sk,
 	 * Not good, but alternative is to resegment the queue. */
 	if (sk->sk_route_caps & NETIF_F_TSO) {
 		sk->sk_route_caps &= ~NETIF_F_TSO;
-		sk->sk_no_largesend = 1;
+		sock_set_flag(sk, SOCK_NO_LARGESEND);
 		tp->mss_cache = tp->mss_cache_std;
 	}
 
@@ -1653,7 +1654,10 @@ static void DBGUNDO(struct sock *sk, str
 static void tcp_undo_cwr(struct tcp_sock *tp, int undo)
 {
 	if (tp->prior_ssthresh) {
-		tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1);
+		if (tcp_is_bic(tp))
+			tp->snd_cwnd = max(tp->snd_cwnd, tp->bictcp.last_max_cwnd);
+		else
+			tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1);
 
 		if (undo && tp->prior_ssthresh > tp->snd_ssthresh) {
 			tp->snd_ssthresh = tp->prior_ssthresh;
@@ -3007,7 +3011,7 @@ void tcp_parse_options(struct sk_buff *s
 	  			switch(opcode) {
 				case TCPOPT_MSS:
 					if(opsize==TCPOLEN_MSS && th->syn && !estab) {
-						u16 in_mss = ntohs(*(__u16 *)ptr);
+						u16 in_mss = ntohs(get_unaligned((__u16 *)ptr));
 						if (in_mss) {
 							if (opt_rx->user_mss && opt_rx->user_mss < in_mss)
 								in_mss = opt_rx->user_mss;
@@ -3018,15 +3022,16 @@ void tcp_parse_options(struct sk_buff *s
 				case TCPOPT_WINDOW:
 					if(opsize==TCPOLEN_WINDOW && th->syn && !estab)
 						if (sysctl_tcp_window_scaling) {
+							__u8 snd_wscale = *(__u8 *) ptr;
 							opt_rx->wscale_ok = 1;
-							opt_rx->snd_wscale = *(__u8 *)ptr;
-							if(opt_rx->snd_wscale > 14) {
+							if (snd_wscale > 14) {
 								if(net_ratelimit())
 									printk(KERN_INFO "tcp_parse_options: Illegal window "
 									       "scaling value %d >14 received.\n",
-									       opt_rx->snd_wscale);
-								opt_rx->snd_wscale = 14;
+									       snd_wscale);
+								snd_wscale = 14;
 							}
+							opt_rx->snd_wscale = snd_wscale;
 						}
 					break;
 				case TCPOPT_TIMESTAMP:
@@ -3034,8 +3039,8 @@ void tcp_parse_options(struct sk_buff *s
 						if ((estab && opt_rx->tstamp_ok) ||
 						    (!estab && sysctl_tcp_timestamps)) {
 							opt_rx->saw_tstamp = 1;
-							opt_rx->rcv_tsval = ntohl(*(__u32 *)ptr);
-							opt_rx->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
+							opt_rx->rcv_tsval = ntohl(get_unaligned((__u32 *)ptr));
+							opt_rx->rcv_tsecr = ntohl(get_unaligned((__u32 *)(ptr+4)));
 						}
 					}
 					break;
@@ -3512,7 +3517,6 @@ static void tcp_data_queue(struct sock *
 	if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
 		goto drop;
 
-	th = skb->h.th;
 	__skb_pull(skb, th->doff*4);
 
 	TCP_ECN_accept_cwr(tp, skb);
@@ -3935,7 +3939,7 @@ void tcp_cwnd_application_limited(struct
 
 
 /* When incoming ACK allowed to free some skb from write_queue,
- * we remember this event in flag sk->sk_queue_shrunk and wake up socket
+ * we remember this event in flag SOCK_QUEUE_SHRUNK and wake up socket
  * on the exit from tcp input handler.
  *
  * PROBLEM: sndbuf expansion does not work well with largesend.
@@ -3963,8 +3967,8 @@ static void tcp_new_space(struct sock *s
 
 static inline void tcp_check_space(struct sock *sk)
 {
-	if (sk->sk_queue_shrunk) {
-		sk->sk_queue_shrunk = 0;
+	if (sock_flag(sk, SOCK_QUEUE_SHRUNK)) {
+		sock_reset_flag(sk, SOCK_QUEUE_SHRUNK);
 		if (sk->sk_socket &&
 		    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
 			tcp_new_space(sk);
@@ -4351,16 +4355,7 @@ int tcp_rcv_established(struct sock *sk,
 					goto no_ack;
 			}
 
-			if (eaten) {
-				if (tcp_in_quickack_mode(tp)) {
-					tcp_send_ack(sk);
-				} else {
-					tcp_send_delayed_ack(sk);
-				}
-			} else {
-				__tcp_ack_snd_check(sk, 0);
-			}
-
+			__tcp_ack_snd_check(sk, 0);
 no_ack:
 			if (eaten)
 				__kfree_skb(skb);
@@ -4507,7 +4502,7 @@ static int tcp_rcv_synsent_state_process
 
 		TCP_ECN_rcv_synack(tp, th);
 		if (tp->ecn_flags&TCP_ECN_OK)
-			sk->sk_no_largesend = 1;
+			sock_set_flag(sk, SOCK_NO_LARGESEND);
 
 		tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
 		tcp_ack(sk, skb, FLAG_SLOWPATH);
@@ -4645,7 +4640,7 @@ discard:
 
 		TCP_ECN_rcv_syn(tp, th);
 		if (tp->ecn_flags&TCP_ECN_OK)
-			sk->sk_no_largesend = 1;
+			sock_set_flag(sk, SOCK_NO_LARGESEND);
 
 		tcp_sync_mss(sk, tp->pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -222,10 +222,13 @@ static int tcp_v4_get_port(struct sock *
 		int rover;
 
 		spin_lock(&tcp_portalloc_lock);
-		rover = tcp_port_rover;
+		if (tcp_port_rover < low)
+			rover = low;
+		else
+			rover = tcp_port_rover;
 		do {
 			rover++;
-			if (rover < low || rover > high)
+			if (rover > high)
 				rover = low;
 			head = &tcp_bhash[tcp_bhashfn(rover)];
 			spin_lock(&head->lock);
@@ -831,7 +834,6 @@ int tcp_v4_connect(struct sock *sk, stru
 	/* OK, now commit destination to socket.  */
 	__sk_dst_set(sk, &rt->u.dst);
 	tcp_v4_setup_caps(sk, &rt->u.dst);
-	tp->ext2_header_len = rt->u.dst.header_len;
 
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcp_sequence_number(inet->saddr,
@@ -941,10 +943,10 @@ static inline void do_pmtu_discovery(str
 	/* Something is about to be wrong... Remember soft error
 	 * for the case, if this connection will not able to recover.
 	 */
-	if (mtu < dst_pmtu(dst) && ip_dont_fragment(sk, dst))
+	if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst))
 		sk->sk_err_soft = EMSGSIZE;
 
-	mtu = dst_pmtu(dst);
+	mtu = dst_mtu(dst);
 
 	if (inet->pmtudisc != IP_PMTUDISC_DONT &&
 	    tp->pmtu_cookie > mtu) {
@@ -1578,10 +1580,9 @@ struct sock *tcp_v4_syn_recv_sock(struct
 	newtp->ext_header_len = 0;
 	if (newinet->opt)
 		newtp->ext_header_len = newinet->opt->optlen;
-	newtp->ext2_header_len = dst->header_len;
 	newinet->id = newtp->write_seq ^ jiffies;
 
-	tcp_sync_mss(newsk, dst_pmtu(dst));
+	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
 	tcp_initialize_rcv_mss(newsk);
 
@@ -1868,7 +1869,7 @@ static int tcp_v4_reselect_saddr(struct 
 
 	/* Query new route. */
 	err = ip_route_connect(&rt, daddr, 0,
-			       RT_TOS(inet->tos) | sk->sk_localroute,
+			       RT_CONN_FLAGS(sk),
 			       sk->sk_bound_dev_if,
 			       IPPROTO_TCP,
 			       inet->sport, inet->dport, sk);
@@ -1877,7 +1878,6 @@ static int tcp_v4_reselect_saddr(struct 
 
 	__sk_dst_set(sk, &rt->u.dst);
 	tcp_v4_setup_caps(sk, &rt->u.dst);
-	tcp_sk(sk)->ext2_header_len = rt->u.dst.header_len;
 
 	new_saddr = rt->rt_src;
 
@@ -1937,7 +1937,6 @@ int tcp_v4_rebuild_header(struct sock *s
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
 		tcp_v4_setup_caps(sk, &rt->u.dst);
-		tcp_sk(sk)->ext2_header_len = rt->u.dst.header_len;
 		return 0;
 	}
 
@@ -2068,7 +2067,7 @@ static int tcp_v4_init_sock(struct sock 
 	sk->sk_state = TCP_CLOSE;
 
 	sk->sk_write_space = sk_stream_write_space;
-	sk->sk_use_write_queue = 1;
+	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
 	tp->af_specific = &ipv4_specific;
 
@@ -2618,7 +2617,7 @@ struct proto tcp_prot = {
 	.sysctl_wmem		= sysctl_tcp_wmem,
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
-	.slab_obj_size		= sizeof(struct tcp_sock),
+	.obj_size		= sizeof(struct tcp_sock),
 };
 
 
@@ -2663,4 +2662,5 @@ EXPORT_SYMBOL(tcp_proc_unregister);
 EXPORT_SYMBOL(sysctl_local_port_range);
 EXPORT_SYMBOL(sysctl_max_syn_backlog);
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
+EXPORT_SYMBOL(sysctl_tcp_tw_reuse);
 
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: tcp_minisocks.c,v 1.15 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
@@ -688,8 +688,8 @@ struct sock *tcp_create_openreq_child(st
 {
 	/* allocate the newsk from the same slab of the master sock,
 	 * if not, at sk_free time we'll try to free it from the wrong
-	 * slabcache (i.e. is it TCPv4 or v6?) -acme */
-	struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0, sk->sk_prot->slab);
+	 * slabcache (i.e. is it TCPv4 or v6?), this is handled thru sk->sk_prot -acme */
+	struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, sk->sk_prot, 0);
 
 	if(newsk != NULL) {
 		struct tcp_sock *newtp;
@@ -807,7 +807,6 @@ struct sock *tcp_create_openreq_child(st
 						  keepalive_time_when(newtp));
 		newsk->sk_socket = NULL;
 		newsk->sk_sleep = NULL;
-		newsk->sk_owner = NULL;
 
 		newtp->rx_opt.tstamp_ok = req->tstamp_ok;
 		if((newtp->rx_opt.sack_ok = req->sack_ok) != 0) {
@@ -841,7 +840,7 @@ struct sock *tcp_create_openreq_child(st
 		newtp->rx_opt.mss_clamp = req->mss;
 		TCP_ECN_openreq_child(newtp, req);
 		if (newtp->ecn_flags&TCP_ECN_OK)
-			newsk->sk_no_largesend = 1;
+			sock_set_flag(newsk, SOCK_NO_LARGESEND);
 
 		tcp_ca_init(newtp);
 
@@ -1019,7 +1018,6 @@ struct sock *tcp_check_req(struct sock *
 		if (child == NULL)
 			goto listen_overflow;
 
-		sk_set_owner(child, sk->sk_owner);
 		tcp_synq_unlink(tp, req, prev);
 		tcp_synq_removed(sk, req);
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: tcp_output.c,v 1.146 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
@@ -400,6 +400,7 @@ static void tcp_queue_skb(struct sock *s
 
 	/* Advance write_seq and place onto the write_queue. */
 	tp->write_seq = TCP_SKB_CB(skb)->end_seq;
+	skb_header_release(skb);
 	__skb_queue_tail(&sk->sk_write_queue, skb);
 	sk_charge_skb(sk, skb);
 
@@ -426,7 +427,7 @@ void tcp_push_one(struct sock *sk, unsig
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb = sk->sk_send_head;
 
-	if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) {
+	if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) {
 		/* Send it out now. */
 		TCP_SKB_CB(skb)->when = tcp_time_stamp;
 		tcp_tso_set_push(skb);
@@ -439,9 +440,12 @@ void tcp_push_one(struct sock *sk, unsig
 	}
 }
 
-void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std)
+void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
 {
-	if (skb->len <= mss_std) {
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (skb->len <= tp->mss_cache_std ||
+	    !(sk->sk_route_caps & NETIF_F_TSO)) {
 		/* Avoid the costly divide in the normal
 		 * non-TSO case.
 		 */
@@ -450,10 +454,10 @@ void tcp_set_skb_tso_segs(struct sk_buff
 	} else {
 		unsigned int factor;
 
-		factor = skb->len + (mss_std - 1);
-		factor /= mss_std;
+		factor = skb->len + (tp->mss_cache_std - 1);
+		factor /= tp->mss_cache_std;
 		skb_shinfo(skb)->tso_segs = factor;
-		skb_shinfo(skb)->tso_size = mss_std;
+		skb_shinfo(skb)->tso_size = tp->mss_cache_std;
 	}
 }
 
@@ -524,8 +528,8 @@ static int tcp_fragment(struct sock *sk,
 	}
 
 	/* Fix up tso_factor for both original and new SKB.  */
-	tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
-	tcp_set_skb_tso_segs(buff, tp->mss_cache_std);
+	tcp_set_skb_tso_segs(sk, skb);
+	tcp_set_skb_tso_segs(sk, buff);
 
 	if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
 		tp->lost_out += tcp_skb_pcount(skb);
@@ -592,15 +596,15 @@ int tcp_trim_head(struct sock *sk, struc
 	skb->ip_summed = CHECKSUM_HW;
 
 	skb->truesize	     -= len;
-	sk->sk_queue_shrunk   = 1;
 	sk->sk_wmem_queued   -= len;
 	sk->sk_forward_alloc += len;
+	sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
 
 	/* Any change of skb->len requires recalculation of tso
 	 * factor and mss.
 	 */
 	if (tcp_skb_pcount(skb) > 1)
-		tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb));
+		tcp_set_skb_tso_segs(sk, skb);
 
 	return 0;
 }
@@ -631,12 +635,8 @@ int tcp_trim_head(struct sock *sk, struc
 unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct dst_entry *dst = __sk_dst_get(sk);
 	int mss_now;
 
-	if (dst && dst->ops->get_mss)
-		pmtu = dst->ops->get_mss(dst, pmtu);
-
 	/* Calculate base mss without TCP options:
 	   It is MMS_S - sizeof(tcphdr) of rfc1122
 	 */
@@ -647,7 +647,7 @@ unsigned int tcp_sync_mss(struct sock *s
 		mss_now = tp->rx_opt.mss_clamp;
 
 	/* Now subtract optional transport overhead */
-	mss_now -= tp->ext_header_len + tp->ext2_header_len;
+	mss_now -= tp->ext_header_len;
 
 	/* Then reserve room for full set of TCP options and 8 bytes of data */
 	if (mss_now < 48)
@@ -683,9 +683,8 @@ unsigned int tcp_current_mss(struct sock
 
 	mss_now = tp->mss_cache_std;
 	if (dst) {
-		u32 mtu = dst_pmtu(dst);
-		if (mtu != tp->pmtu_cookie ||
-		    tp->ext2_header_len != dst->header_len)
+		u32 mtu = dst_mtu(dst);
+		if (mtu != tp->pmtu_cookie)
 			mss_now = tcp_sync_mss(sk, mtu);
 	}
 
@@ -697,8 +696,7 @@ unsigned int tcp_current_mss(struct sock
 		unsigned int large_mss, factor, limit;
 
 		large_mss = 65535 - tp->af_specific->net_header_len -
-			tp->ext_header_len - tp->ext2_header_len -
-			tp->tcp_header_len;
+			tp->ext_header_len - tp->tcp_header_len;
 
 		if (tp->max_window && large_mss > (tp->max_window>>1))
 			large_mss = max((tp->max_window>>1),
@@ -757,7 +755,7 @@ int tcp_write_xmit(struct sock *sk, int 
 		mss_now = tcp_current_mss(sk, 1);
 
 		while ((skb = sk->sk_send_head) &&
-		       tcp_snd_test(tp, skb, mss_now,
+		       tcp_snd_test(sk, skb, mss_now,
 			       	    tcp_skb_is_last(sk, skb) ? nonagle :
 				    			       TCP_NAGLE_PUSH)) {
 			if (skb->len > mss_now) {
@@ -1045,7 +1043,7 @@ int tcp_retransmit_skb(struct sock *sk, 
 
 		if (sk->sk_route_caps & NETIF_F_TSO) {
 			sk->sk_route_caps &= ~NETIF_F_TSO;
-			sk->sk_no_largesend = 1;
+			sock_set_flag(sk, SOCK_NO_LARGESEND);
 			tp->mss_cache = tp->mss_cache_std;
 		}
 
@@ -1340,6 +1338,7 @@ int tcp_send_synack(struct sock *sk)
 			if (nskb == NULL)
 				return -ENOMEM;
 			__skb_unlink(skb, &sk->sk_write_queue);
+			skb_header_release(nskb);
 			__skb_queue_head(&sk->sk_write_queue, nskb);
 			sk_stream_free_skb(sk, skb);
 			sk_charge_skb(sk, nskb);
@@ -1431,6 +1430,7 @@ static inline void tcp_connect_init(stru
 {
 	struct dst_entry *dst = __sk_dst_get(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
+	__u8 rcv_wscale;
 
 	/* We'll fix this up when we get a response from the other end.
 	 * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
@@ -1442,7 +1442,7 @@ static inline void tcp_connect_init(stru
 	if (tp->rx_opt.user_mss)
 		tp->rx_opt.mss_clamp = tp->rx_opt.user_mss;
 	tp->max_window = 0;
-	tcp_sync_mss(sk, dst_pmtu(dst));
+	tcp_sync_mss(sk, dst_mtu(dst));
 
 	if (!tp->window_clamp)
 		tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
@@ -1455,8 +1455,9 @@ static inline void tcp_connect_init(stru
 				  &tp->rcv_wnd,
 				  &tp->window_clamp,
 				  sysctl_tcp_window_scaling,
-				  &tp->rx_opt.rcv_wscale);
+				  &rcv_wscale);
 
+	tp->rx_opt.rcv_wscale = rcv_wscale;
 	tp->rcv_ssthresh = tp->rcv_wnd;
 
 	sk->sk_err = 0;
@@ -1506,6 +1507,7 @@ int tcp_connect(struct sock *sk)
 	/* Send it off. */
 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
 	tp->retrans_stamp = TCP_SKB_CB(buff)->when;
+	skb_header_release(buff);
 	__skb_queue_tail(&sk->sk_write_queue, buff);
 	sk_charge_skb(sk, buff);
 	tp->packets_out += tcp_skb_pcount(buff);
@@ -1672,12 +1674,12 @@ int tcp_write_wakeup(struct sock *sk)
 				/* SWS override triggered forced fragmentation.
 				 * Disable TSO, the connection is too sick. */
 				if (sk->sk_route_caps & NETIF_F_TSO) {
-					sk->sk_no_largesend = 1;
+					sock_set_flag(sk, SOCK_NO_LARGESEND);
 					sk->sk_route_caps &= ~NETIF_F_TSO;
 					tp->mss_cache = tp->mss_cache_std;
 				}
 			} else if (!tcp_skb_pcount(skb))
-				tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
+				tcp_set_skb_tso_segs(sk, skb);
 
 			TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
 			TCP_SKB_CB(skb)->when = tcp_time_stamp;
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: tcp_timer.c,v 1.88 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Mark Evans, <evansmp@uhura.aston.ac.uk>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
@@ -38,6 +38,7 @@ static void tcp_keepalive_timer (unsigne
 
 #ifdef TCP_DEBUG
 const char tcp_timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+EXPORT_SYMBOL(tcp_timer_bug_msg);
 #endif
 
 /*
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: udp.c,v 1.102 2002/02/01 22:01:04 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
  *		Alan Cox, <Alan.Cox@linux.org>
@@ -574,7 +574,8 @@ int udp_sendmsg(struct kiocb *iocb, stru
 		connected = 0;
 	}
 	tos = RT_TOS(inet->tos);
-	if (sk->sk_localroute || (msg->msg_flags & MSG_DONTROUTE) || 
+	if (sock_flag(sk, SOCK_LOCALROUTE) ||
+	    (msg->msg_flags & MSG_DONTROUTE) || 
 	    (ipc.opt && ipc.opt->is_strictroute)) {
 		tos |= RTO_ONLINK;
 		connected = 0;
@@ -737,7 +738,7 @@ int udp_ioctl(struct sock *sk, int cmd, 
 			unsigned long amount;
 
 			amount = 0;
-			spin_lock_irq(&sk->sk_receive_queue.lock);
+			spin_lock_bh(&sk->sk_receive_queue.lock);
 			skb = skb_peek(&sk->sk_receive_queue);
 			if (skb != NULL) {
 				/*
@@ -747,7 +748,7 @@ int udp_ioctl(struct sock *sk, int cmd, 
 				 */
 				amount = skb->len - sizeof(struct udphdr);
 			}
-			spin_unlock_irq(&sk->sk_receive_queue.lock);
+			spin_unlock_bh(&sk->sk_receive_queue.lock);
 			return put_user(amount, (int __user *)arg);
 		}
 
@@ -847,12 +848,12 @@ csum_copy_err:
 	/* Clear queue. */
 	if (flags&MSG_PEEK) {
 		int clear = 0;
-		spin_lock_irq(&sk->sk_receive_queue.lock);
+		spin_lock_bh(&sk->sk_receive_queue.lock);
 		if (skb == skb_peek(&sk->sk_receive_queue)) {
 			__skb_unlink(skb, &sk->sk_receive_queue);
 			clear = 1;
 		}
-		spin_unlock_irq(&sk->sk_receive_queue.lock);
+		spin_unlock_bh(&sk->sk_receive_queue.lock);
 		if (clear)
 			kfree_skb(skb);
 	}
@@ -954,6 +955,8 @@ static int udp_encap_rcv(struct sock * s
 	 * header and optional ESP marker bytes) and then modify the
 	 * protocol to ESP, and then call into the transform receiver.
 	 */
+	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+		return 0;
 
 	/* Now we can update and verify the packet length... */
 	iph = skb->nh.iph;
@@ -1331,7 +1334,7 @@ unsigned int udp_poll(struct file *file,
 		struct sk_buff_head *rcvq = &sk->sk_receive_queue;
 		struct sk_buff *skb;
 
-		spin_lock_irq(&rcvq->lock);
+		spin_lock_bh(&rcvq->lock);
 		while ((skb = skb_peek(rcvq)) != NULL) {
 			if (udp_checksum_complete(skb)) {
 				UDP_INC_STATS_BH(UDP_MIB_INERRORS);
@@ -1342,7 +1345,7 @@ unsigned int udp_poll(struct file *file,
 				break;
 			}
 		}
-		spin_unlock_irq(&rcvq->lock);
+		spin_unlock_bh(&rcvq->lock);
 
 		/* nothing to see, move along */
 		if (skb == NULL)
@@ -1370,7 +1373,7 @@ struct proto udp_prot = {
 	.hash =		udp_v4_hash,
 	.unhash =	udp_v4_unhash,
 	.get_port =	udp_v4_get_port,
-	.slab_obj_size = sizeof(struct udp_sock),
+	.obj_size =	sizeof(struct udp_sock),
 };
 
 /* ------------------------------------------------------------------------ */
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -58,7 +58,7 @@ static void xfrm4_encap(struct sk_buff *
 	if (!top_iph->frag_off)
 		__ip_select_ident(top_iph, dst, 0);
 
-	top_iph->ttl = dst_path_metric(dst, RTAX_HOPLIMIT);
+	top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
 
 	top_iph->saddr = x->props.saddr.a4;
 	top_iph->daddr = x->id.daddr.a4;
@@ -78,11 +78,11 @@ static int xfrm4_tunnel_check_size(struc
 
 	IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
 	
-	if (!(iph->frag_off & htons(IP_DF)))
+	if (!(iph->frag_off & htons(IP_DF)) || skb->local_df)
 		goto out;
 
 	dst = skb->dst;
-	mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
+	mtu = dst_mtu(dst);
 	if (skb->len > mtu) {
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 		ret = -EMSGSIZE;
@@ -103,20 +103,20 @@ int xfrm4_output(struct sk_buff *skb)
 			goto error_nolock;
 	}
 
-	spin_lock_bh(&x->lock);
-	err = xfrm_state_check(x, skb);
-	if (err)
-		goto error;
-
 	if (x->props.mode) {
 		err = xfrm4_tunnel_check_size(skb);
 		if (err)
-			goto error;
+			goto error_nolock;
 	}
 
+	spin_lock_bh(&x->lock);
+	err = xfrm_state_check(x, skb);
+	if (err)
+		goto error;
+
 	xfrm4_encap(skb);
 
-	err = x->type->output(skb);
+	err = x->type->output(x, skb);
 	if (err)
 		goto error;
 
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -8,7 +8,10 @@
  * 	
  */
 
+#include <asm/bug.h>
+#include <linux/compiler.h>
 #include <linux/config.h>
+#include <linux/inetdevice.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 
@@ -22,26 +25,6 @@ static int xfrm4_dst_lookup(struct xfrm_
 	return __ip_route_output_key((struct rtable**)dst, fl);
 }
 
-/* Check that the bundle accepts the flow and its components are
- * still valid.
- */
-
-static int __xfrm4_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl)
-{
-	do {
-		if (xdst->u.dst.ops != &xfrm4_dst_ops)
-			return 1;
-
-		if (!xfrm_selector_match(&xdst->u.dst.xfrm->sel, fl, AF_INET))
-			return 0;
-		if (xdst->u.dst.xfrm->km.state != XFRM_STATE_VALID ||
-		    xdst->u.dst.path->obsolete > 0)
-			return 0;
-		xdst = (struct xfrm_dst*)xdst->u.dst.child;
-	} while (xdst);
-	return 0;
-}
-
 static struct dst_entry *
 __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 {
@@ -53,7 +36,7 @@ __xfrm4_find_bundle(struct flowi *fl, st
 		if (xdst->u.rt.fl.oif == fl->oif &&	/*XXX*/
 		    xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
 	    	    xdst->u.rt.fl.fl4_src == fl->fl4_src &&
-		    __xfrm4_bundle_ok(xdst, fl)) {
+		    xfrm_bundle_ok(xdst, fl, AF_INET)) {
 			dst_clone(dst);
 			break;
 		}
@@ -75,18 +58,30 @@ __xfrm4_bundle_create(struct xfrm_policy
 	struct rtable *rt = rt0;
 	u32 remote = fl->fl4_dst;
 	u32 local  = fl->fl4_src;
+	struct flowi fl_tunnel = {
+		.nl_u = {
+			.ip4_u = {
+				.saddr = local,
+				.daddr = remote
+			}
+		}
+	};
 	int i;
 	int err;
 	int header_len = 0;
 	int trailer_len = 0;
 
 	dst = dst_prev = NULL;
+	dst_hold(&rt->u.dst);
 
 	for (i = 0; i < nx; i++) {
 		struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
+		struct xfrm_dst *xdst;
+		int tunnel = 0;
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
+			dst_release(&rt->u.dst);
 			goto error;
 		}
 
@@ -97,30 +92,40 @@ __xfrm4_bundle_create(struct xfrm_policy
 			dst1->flags |= DST_NOHASH;
 			dst_clone(dst1);
 		}
+
+		xdst = (struct xfrm_dst *)dst1;
+		xdst->route = &rt->u.dst;
+
+		dst1->next = dst_prev;
 		dst_prev = dst1;
 		if (xfrm[i]->props.mode) {
 			remote = xfrm[i]->id.daddr.a4;
 			local  = xfrm[i]->props.saddr.a4;
+			tunnel = 1;
 		}
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
-	}
 
-	if (remote != fl->fl4_dst) {
-		struct flowi fl_tunnel = { .nl_u = { .ip4_u =
-						     { .daddr = remote,
-						       .saddr = local }
-					           }
-				         };
-		err = xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET);
-		if (err)
-			goto error;
-	} else {
-		dst_hold(&rt->u.dst);
+		if (tunnel) {
+			fl_tunnel.fl4_src = local;
+			fl_tunnel.fl4_dst = remote;
+			err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
+					      &fl_tunnel, AF_INET);
+			if (err)
+				goto error;
+		} else
+			dst_hold(&rt->u.dst);
 	}
+
 	dst_prev->child = &rt->u.dst;
+	dst->path = &rt->u.dst;
+
+	*dst_p = dst;
+	dst = dst_prev;
+
+	dst_prev = *dst_p;
 	i = 0;
-	for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
+	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
 		x->u.rt.fl = *fl;
 
@@ -133,8 +138,7 @@ __xfrm4_bundle_create(struct xfrm_policy
 		dst_prev->lastuse	= jiffies;
 		dst_prev->header_len	= header_len;
 		dst_prev->trailer_len	= trailer_len;
-		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
-		dst_prev->path		= &rt->u.dst;
+		memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
 
 		/* Copy neighbout for reachability confirmation */
 		dst_prev->neighbour	= neigh_clone(rt->u.dst.neighbour);
@@ -151,10 +155,13 @@ __xfrm4_bundle_create(struct xfrm_policy
 		x->u.rt.rt_dst = rt0->rt_dst;
 		x->u.rt.rt_gateway = rt->rt_gateway;
 		x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
+		x->u.rt.idev = rt0->idev;
+		in_dev_hold(rt0->idev);
 		header_len -= x->u.dst.xfrm->props.header_len;
 		trailer_len -= x->u.dst.xfrm->props.trailer_len;
 	}
-	*dst_p = dst;
+
+	xfrm_init_pmtu(dst);
 	return 0;
 
 error:
@@ -235,12 +242,45 @@ static inline int xfrm4_garbage_collect(
 
 static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
-	struct dst_entry *path = dst->path;
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+	struct dst_entry *path = xdst->route;
+
+	path->ops->update_pmtu(path, mtu);
+}
+
+static void xfrm4_dst_destroy(struct dst_entry *dst)
+{
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 
-	if (mtu < 68 + dst->header_len)
+	if (likely(xdst->u.rt.idev))
+		in_dev_put(xdst->u.rt.idev);
+	xfrm_dst_destroy(xdst);
+}
+
+static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+			     int unregister)
+{
+	struct xfrm_dst *xdst;
+
+	if (!unregister)
 		return;
 
-	path->ops->update_pmtu(path, mtu);
+	xdst = (struct xfrm_dst *)dst;
+	if (xdst->u.rt.idev->dev == dev) {
+		struct in_device *loopback_idev = in_dev_get(&loopback_dev);
+		BUG_ON(!loopback_idev);
+
+		do {
+			in_dev_put(xdst->u.rt.idev);
+			xdst->u.rt.idev = loopback_idev;
+			in_dev_hold(loopback_idev);
+			xdst = (struct xfrm_dst *)xdst->u.dst.child;
+		} while (xdst->u.dst.xfrm);
+
+		__in_dev_put(loopback_idev);
+	}
+
+	xfrm_dst_ifdown(dst, dev);
 }
 
 static struct dst_ops xfrm4_dst_ops = {
@@ -248,6 +288,8 @@ static struct dst_ops xfrm4_dst_ops = {
 	.protocol =		__constant_htons(ETH_P_IP),
 	.gc =			xfrm4_garbage_collect,
 	.update_pmtu =		xfrm4_update_pmtu,
+	.destroy =		xfrm4_dst_destroy,
+	.ifdown =		xfrm4_dst_ifdown,
 	.gc_thresh =		1024,
 	.entry_size =		sizeof(struct xfrm_dst),
 };
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -20,9 +20,9 @@ __xfrm4_init_tempsel(struct xfrm_state *
 {
 	x->sel.daddr.a4 = fl->fl4_dst;
 	x->sel.saddr.a4 = fl->fl4_src;
-	x->sel.dport = fl->fl_ip_dport;
+	x->sel.dport = xfrm_flowi_dport(fl);
 	x->sel.dport_mask = ~0;
-	x->sel.sport = fl->fl_ip_sport;
+	x->sel.sport = xfrm_flowi_sport(fl);
 	x->sel.sport_mask = ~0;
 	x->sel.prefixlen_d = 32;
 	x->sel.prefixlen_s = 32;
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -9,7 +9,7 @@
 #include <net/ip.h>
 #include <net/protocol.h>
 
-static int ipip_output(struct sk_buff *skb)
+static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct iphdr *iph;
 	
diff --git a/net/ipv6/README b/net/ipv6/README
deleted file mode 100644
--- a/net/ipv6/README
+++ /dev/null
@@ -1,8 +0,0 @@
-To join in the work on Linux IPv6 send mail to:
-
-        majordomo@oss.sgi.com
-
-and in the body of the message include:
-
-subscribe netdev
-
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -372,6 +372,7 @@ static struct inet6_dev * ipv6_add_dev(s
 		ndev->regen_timer.data = (unsigned long) ndev;
 		if ((dev->flags&IFF_LOOPBACK) ||
 		    dev->type == ARPHRD_TUNNEL ||
+		    dev->type == ARPHRD_NONE ||
 		    dev->type == ARPHRD_SIT) {
 			printk(KERN_INFO
 				"Disabled Privacy Extensions on device %p(%s)\n",
@@ -391,7 +392,9 @@ static struct inet6_dev * ipv6_add_dev(s
 		ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
 		neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, 
-			NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change);
+				      NET_IPV6_NEIGH, "ipv6",
+				      &ndisc_ifinfo_sysctl_change,
+				      NULL);
 		addrconf_sysctl_register(ndev, &ndev->cnf);
 #endif
 	}
@@ -569,7 +572,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
 out2:
 	read_unlock_bh(&addrconf_lock);
 
-	if (unlikely(err == 0))
+	if (likely(err == 0))
 		notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
 	else {
 		kfree(ifa);
@@ -589,6 +592,8 @@ static void ipv6_del_addr(struct inet6_i
 	struct inet6_ifaddr *ifa, **ifap;
 	struct inet6_dev *idev = ifp->idev;
 	int hash;
+	int deleted = 0, onlink = 0;
+	unsigned long expires = jiffies;
 
 	hash = ipv6_addr_hash(&ifp->addr);
 
@@ -631,7 +636,31 @@ static void ipv6_del_addr(struct inet6_i
 			*ifap = ifa->if_next;
 			__in6_ifa_put(ifp);
 			ifa->if_next = NULL;
-			break;
+			if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
+				break;
+			deleted = 1;
+		} else if (ifp->flags & IFA_F_PERMANENT) {
+			if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
+					      ifp->prefix_len)) {
+				if (ifa->flags & IFA_F_PERMANENT) {
+					onlink = 1;
+					if (deleted)
+						break;
+				} else {
+					unsigned long lifetime;
+
+					if (!onlink)
+						onlink = -1;
+
+					spin_lock(&ifa->lock);
+					lifetime = min_t(unsigned long,
+							 ifa->valid_lft, 0x7fffffffUL/HZ);
+					if (time_before(expires,
+							ifa->tstamp + lifetime * HZ))
+						expires = ifa->tstamp + lifetime * HZ;
+					spin_unlock(&ifa->lock);
+				}
+			}
 		}
 	}
 	write_unlock_bh(&idev->lock);
@@ -642,6 +671,40 @@ static void ipv6_del_addr(struct inet6_i
 
 	addrconf_del_timer(ifp);
 
+	/*
+	 * Purge or update corresponding prefix
+	 *
+	 * 1) we don't purge prefix here if address was not permanent.
+	 *    prefix is managed by its own lifetime.
+	 * 2) if there're no addresses, delete prefix.
+	 * 3) if there're still other permanent address(es),
+	 *    corresponding prefix is still permanent.
+	 * 4) otherwise, update prefix lifetime to the
+	 *    longest valid lifetime among the corresponding
+	 *    addresses on the device.
+	 *    Note: subsequent RA will update lifetime.
+	 *
+	 * --yoshfuji
+	 */
+	if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
+		struct in6_addr prefix;
+		struct rt6_info *rt;
+
+		ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
+		rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1);
+
+		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+			if (onlink == 0) {
+				ip6_del_rt(rt, NULL, NULL);
+				rt = NULL;
+			} else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
+				rt->rt6i_expires = expires;
+				rt->rt6i_flags |= RTF_EXPIRES;
+			}
+		}
+		dst_release(&rt->u.dst);
+	}
+
 	in6_ifa_put(ifp);
 }
 
@@ -880,7 +943,7 @@ out:
 int ipv6_get_saddr(struct dst_entry *dst,
 		   struct in6_addr *daddr, struct in6_addr *saddr)
 {
-	return ipv6_dev_get_saddr(dst ? dst->dev : NULL, daddr, saddr);
+	return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_idev->dev : NULL, daddr, saddr);
 }
 
 
@@ -1982,7 +2045,10 @@ static int addrconf_notify(struct notifi
 		if (idev) {
 			addrconf_sysctl_unregister(&idev->cnf);
 			neigh_sysctl_unregister(idev->nd_parms);
-			neigh_sysctl_register(dev, idev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change);
+			neigh_sysctl_register(dev, idev->nd_parms,
+					      NET_IPV6, NET_IPV6_NEIGH, "ipv6",
+					      &ndisc_ifinfo_sysctl_change,
+					      NULL);
 			addrconf_sysctl_register(idev, &idev->cnf);
 		}
 #endif
@@ -2008,6 +2074,9 @@ static int addrconf_ifdown(struct net_de
 
 	ASSERT_RTNL();
 
+	if (dev == &loopback_dev && how == 1)
+		how = 0;
+
 	rt6_ifdown(dev);
 	neigh_ifdown(&nd_tbl, dev);
 
@@ -2855,12 +2924,8 @@ static int inet6_fill_ifinfo(struct sk_b
 	r->ifi_family = AF_INET6;
 	r->ifi_type = dev->type;
 	r->ifi_index = dev->ifindex;
-	r->ifi_flags = dev->flags;
+	r->ifi_flags = dev_get_flags(dev);
 	r->ifi_change = 0;
-	if (!netif_running(dev) || !netif_carrier_ok(dev))
-		r->ifi_flags &= ~IFF_RUNNING;
-	else
-		r->ifi_flags |= IFF_RUNNING;
 
 	RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
 
@@ -3012,7 +3077,7 @@ static void inet6_prefix_notify(int even
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_PREFIX, GFP_ATOMIC);
 }
 
-static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
+static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
 	[RTM_GETLINK - RTM_BASE] = { .dumpit	= inet6_dump_ifinfo, },
 	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },
 	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, },
@@ -3147,7 +3212,7 @@ static int addrconf_sysctl_forward_strat
 static struct addrconf_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table addrconf_vars[18];
+	ctl_table addrconf_vars[__NET_IPV6_MAX];
 	ctl_table addrconf_dev[2];
 	ctl_table addrconf_conf_dir[2];
 	ctl_table addrconf_proto_dir[2];
@@ -3438,8 +3503,10 @@ int unregister_inet6addr_notifier(struct
  *	Init / cleanup code
  */
 
-void __init addrconf_init(void)
+int __init addrconf_init(void)
 {
+	int err = 0;
+
 	/* The addrconf netdev notifier requires that loopback_dev
 	 * has it's ipv6 private information allocated and setup
 	 * before it can bring up and give link-local addresses
@@ -3453,15 +3520,17 @@ void __init addrconf_init(void)
 	 * first, then loopback_dev, which cases all the non-loopback_dev
 	 * devices to fail to get a link-local address.
 	 *
-	 * So, as a temporary fix, register loopback_dev first by hand.
+	 * So, as a temporary fix, allocate the ipv6 structure for
+	 * loopback_dev first by hand.
 	 * Longer term, all of the dependencies ipv6 has upon the loopback
 	 * device and it being up should be removed.
 	 */
 	rtnl_lock();
-	addrconf_notify(&ipv6_dev_notf, NETDEV_REGISTER, &loopback_dev);
-	if (loopback_dev.flags & IFF_UP)
-		addrconf_notify(&ipv6_dev_notf, NETDEV_UP, &loopback_dev);
+	if (!ipv6_add_dev(&loopback_dev))
+		err = -ENOMEM;
 	rtnl_unlock();
+	if (err)
+		return err;
 
 	register_netdevice_notifier(&ipv6_dev_notf);
 
@@ -3479,6 +3548,8 @@ void __init addrconf_init(void)
 		register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
 	addrconf_sysctl_register(NULL, &ipv6_devconf_dflt);
 #endif
+
+	return 0;
 }
 
 void __exit addrconf_cleanup(void)
@@ -3507,6 +3578,7 @@ void __exit addrconf_cleanup(void)
 			continue;
 		addrconf_ifdown(dev, 1);
 	}
+	addrconf_ifdown(&loopback_dev, 2);
 
 	/*
 	 *	Check hash table.
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -28,7 +28,6 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
@@ -88,6 +87,7 @@ int sysctl_ipv6_bindv6only;
 
 #ifdef INET_REFCNT_DEBUG
 atomic_t inet6_sock_nr;
+EXPORT_SYMBOL(inet6_sock_nr);
 #endif
 
 /* The inetsw table contains everything that inet_create needs to
@@ -107,7 +107,7 @@ static void inet6_sock_destruct(struct s
 
 static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 {
-	const int offset = sk->sk_prot->slab_obj_size - sizeof(struct ipv6_pinfo);
+	const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo);
 
 	return (struct ipv6_pinfo *)(((u8 *)sk) + offset);
 }
@@ -166,15 +166,11 @@ static int inet6_create(struct socket *s
 	BUG_TRAP(answer_prot->slab != NULL);
 
 	rc = -ENOBUFS;
-	sk = sk_alloc(PF_INET6, GFP_KERNEL,
-		      answer_prot->slab_obj_size,
-		      answer_prot->slab);
+	sk = sk_alloc(PF_INET6, GFP_KERNEL, answer_prot, 1);
 	if (sk == NULL)
 		goto out;
 
 	sock_init_data(sock, sk);
-	sk->sk_prot = answer_prot;
-	sk_set_owner(sk, sk->sk_prot->owner);
 
 	rc = 0;
 	sk->sk_no_check = answer_no_check;
@@ -710,21 +706,18 @@ static int __init inet6_init(void)
 		return -EINVAL;
 	}
 
-	err = sk_alloc_slab(&tcpv6_prot, "tcpv6_sock");
-	if (err) {
-		sk_alloc_slab_error(&tcpv6_prot);
+	err = proto_register(&tcpv6_prot, 1);
+	if (err)
 		goto out;
-	}
-	err = sk_alloc_slab(&udpv6_prot, "udpv6_sock");
-	if (err) {
-		sk_alloc_slab_error(&udpv6_prot);
-		goto out_tcp_free_slab;
-	}
-	err = sk_alloc_slab(&rawv6_prot, "rawv6_sock");
-	if (err) {
-		sk_alloc_slab_error(&rawv6_prot);
-		goto out_udp_free_slab;
-	}
+
+	err = proto_register(&udpv6_prot, 1);
+	if (err)
+		goto out_unregister_tcp_proto;
+
+	err = proto_register(&rawv6_prot, 1);
+	if (err)
+		goto out_unregister_udp_proto;
+
 
 	/* Register the socket-side information for inet6_create.  */
 	for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
@@ -743,7 +736,7 @@ static int __init inet6_init(void)
 	/* Initialise ipv6 mibs */
 	err = init_ipv6_mibs();
 	if (err)
-		goto out_raw_free_slab;
+		goto out_unregister_raw_proto;
 	
 	/*
 	 *	ipngwg API draft makes clear that the correct semantics
@@ -784,7 +777,9 @@ static int __init inet6_init(void)
 	ipv6_packet_init();
 	ip6_route_init();
 	ip6_flowlabel_init();
-	addrconf_init();
+	err = addrconf_init();
+	if (err)
+		goto addrconf_fail;
 	sit_init();
 
 	/* Init v6 extension headers. */
@@ -800,7 +795,12 @@ static int __init inet6_init(void)
 out:
 	return err;
 
+addrconf_fail:
+	ip6_flowlabel_cleanup();
+	ip6_route_cleanup();
+	ipv6_packet_cleanup();
 #ifdef CONFIG_PROC_FS
+	if6_proc_exit();
 proc_if6_fail:
 	ac6_proc_exit();
 proc_anycast6_fail:
@@ -812,8 +812,8 @@ proc_udp6_fail:
 proc_tcp6_fail:
 	raw6_proc_exit();
 proc_raw6_fail:
-	igmp6_cleanup();
 #endif
+	igmp6_cleanup();
 igmp_fail:
 	ndisc_cleanup();
 ndisc_fail:
@@ -823,12 +823,12 @@ icmp_fail:
 	ipv6_sysctl_unregister();
 #endif
 	cleanup_ipv6_mibs();
-out_raw_free_slab:
-	sk_free_slab(&rawv6_prot);
-out_udp_free_slab:
-	sk_free_slab(&udpv6_prot);
-out_tcp_free_slab:
-	sk_free_slab(&tcpv6_prot);
+out_unregister_raw_proto:
+	proto_unregister(&rawv6_prot);
+out_unregister_udp_proto:
+	proto_unregister(&udpv6_prot);
+out_unregister_tcp_proto:
+	proto_unregister(&tcpv6_prot);
 	goto out;
 }
 module_init(inet6_init);
@@ -858,9 +858,9 @@ static void __exit inet6_exit(void)
 	ipv6_sysctl_unregister();	
 #endif
 	cleanup_ipv6_mibs();
-	sk_free_slab(&rawv6_prot);
-	sk_free_slab(&udpv6_prot);
-	sk_free_slab(&tcpv6_prot);
+	proto_unregister(&rawv6_prot);
+	proto_unregister(&udpv6_prot);
+	proto_unregister(&tcpv6_prot);
 }
 module_exit(inet6_exit);
 
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -154,12 +154,10 @@ static int ipv6_clear_mutable_options(st
 	return 0;
 }
 
-static int ah6_output(struct sk_buff *skb)
+static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
 	int extlen;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x  = dst->xfrm;
 	struct ipv6hdr *top_iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -48,32 +48,6 @@ static int ipv6_dev_ac_dec(struct net_de
 /* Big ac list lock for all the sockets */
 static DEFINE_RWLOCK(ipv6_sk_ac_lock);
 
-/* XXX ip6_addr_match() and ip6_onlink() really belong in net/core.c */
-
-static int
-ip6_addr_match(struct in6_addr *addr1, struct in6_addr *addr2, int prefix)
-{
-	__u32	mask;
-	int	i;
-
-	if (prefix > 128 || prefix < 0)
-		return 0;
-	if (prefix == 0)
-		return 1;
-	for (i=0; i<4; ++i) {
-		if (prefix >= 32)
-			mask = ~0;
-		else
-			mask = htonl(~0 << (32 - prefix));
-		if ((addr1->s6_addr32[i] ^ addr2->s6_addr32[i]) & mask)
-			return 0;
-		prefix -= 32;
-		if (prefix <= 0)
-			break;
-	}
-	return 1;
-}
-
 static int
 ip6_onlink(struct in6_addr *addr, struct net_device *dev)
 {
@@ -87,8 +61,8 @@ ip6_onlink(struct in6_addr *addr, struct
 	if (idev) {
 		read_lock_bh(&idev->lock);
 		for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
-			onlink = ip6_addr_match(addr, &ifa->addr,
-					ifa->prefix_len);
+			onlink = ipv6_prefix_equal(addr, &ifa->addr,
+						   ifa->prefix_len);
 			if (onlink)
 				break;
 		}
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -37,12 +37,10 @@
 #include <net/ipv6.h>
 #include <linux/icmpv6.h>
 
-static int esp6_output(struct sk_buff *skb)
+static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
 	int hdr_len;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x  = dst->xfrm;
 	struct ipv6hdr *top_iph;
 	struct ipv6_esp_hdr *esph;
 	struct crypto_tfm *tfm;
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -41,8 +41,8 @@ int ipv6_ext_hdr(u8 nexthdr)
  * when Linux implements ESP (and maybe AUTH) headers.
  * --AK
  *
- * This function parses (probably truncated) exthdr set "hdr"
- * of length "len". "nexthdrp" initially points to some place,
+ * This function parses (probably truncated) exthdr set "hdr".
+ * "nexthdrp" initially points to some place,
  * where type of the first header can be found.
  *
  * It skips all well-known exthdrs, and returns pointer to the start
@@ -63,7 +63,7 @@ int ipv6_ext_hdr(u8 nexthdr)
  * --ANK (980726)
  */
 
-int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len)
+int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)
 {
 	u8 nexthdr = *nexthdrp;
 
@@ -71,13 +71,11 @@ int ipv6_skip_exthdr(const struct sk_buf
 		struct ipv6_opt_hdr _hdr, *hp;
 		int hdrlen;
 
-		if (len < (int)sizeof(struct ipv6_opt_hdr))
-			return -1;
 		if (nexthdr == NEXTHDR_NONE)
 			return -1;
 		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
 		if (hp == NULL)
-			BUG();
+			return -1;
 		if (nexthdr == NEXTHDR_FRAGMENT) {
 			unsigned short _frag_off, *fp;
 			fp = skb_header_pointer(skb,
@@ -97,7 +95,6 @@ int ipv6_skip_exthdr(const struct sk_buf
 			hdrlen = ipv6_optlen(hp); 
 
 		nexthdr = hp->nexthdr;
-		len -= hdrlen;
 		start += hdrlen;
 	}
 
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -135,7 +135,7 @@ static int is_ineligible(struct sk_buff 
 	if (len < 0)
 		return 1;
 
-	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
+	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr);
 	if (ptr < 0)
 		return 0;
 	if (nexthdr == IPPROTO_ICMPV6) {
@@ -277,8 +277,8 @@ void icmpv6_send(struct sk_buff *skb, in
 {
 	struct inet6_dev *idev = NULL;
 	struct ipv6hdr *hdr = skb->nh.ipv6h;
-	struct sock *sk = icmpv6_socket->sk;
-	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct sock *sk;
+	struct ipv6_pinfo *np;
 	struct in6_addr *saddr = NULL;
 	struct dst_entry *dst;
 	struct icmp6hdr tmp_hdr;
@@ -358,6 +358,9 @@ void icmpv6_send(struct sk_buff *skb, in
 	if (icmpv6_xmit_lock())
 		return;
 
+	sk = icmpv6_socket->sk;
+	np = inet6_sk(sk);
+
 	if (!icmpv6_xrlim_allow(sk, type, &fl))
 		goto out;
 
@@ -381,6 +384,8 @@ void icmpv6_send(struct sk_buff *skb, in
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
 		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	if (hlimit < 0)
+		hlimit = ipv6_get_hoplimit(dst->dev);
 
 	msg.skb = skb;
 	msg.offset = skb->nh.raw - skb->data;
@@ -421,9 +426,9 @@ out:
 
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
-	struct sock *sk = icmpv6_socket->sk;
+	struct sock *sk;
 	struct inet6_dev *idev;
-	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6_pinfo *np;
 	struct in6_addr *saddr = NULL;
 	struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
 	struct icmp6hdr tmp_hdr;
@@ -452,6 +457,9 @@ static void icmpv6_echo_reply(struct sk_
 	if (icmpv6_xmit_lock())
 		return;
 
+	sk = icmpv6_socket->sk;
+	np = inet6_sk(sk);
+
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
@@ -467,6 +475,8 @@ static void icmpv6_echo_reply(struct sk_
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
 		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	if (hlimit < 0)
+		hlimit = ipv6_get_hoplimit(dst->dev);
 
 	idev = in6_dev_get(skb->dev);
 
@@ -510,7 +520,7 @@ static void icmpv6_notify(struct sk_buff
 	nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
 	if (ipv6_ext_hdr(nexthdr)) {
 		/* now skip over extension headers */
-		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr));
+		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
 		if (inner_offset<0)
 			return;
 	} else {
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -117,36 +117,6 @@ static __inline__ u32 fib6_new_sernum(vo
  */
 
 /*
- *	compare "prefix length" bits of an address
- */
-
-static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
-{
-	__u32 *a1 = token1;
-	__u32 *a2 = token2;
-	int pdw;
-	int pbi;
-
-	pdw = prefixlen >> 5;	  /* num of whole __u32 in prefix */
-	pbi = prefixlen &  0x1f;  /* num of bits in incomplete u32 in prefix */
-
-	if (pdw)
-		if (memcmp(a1, a2, pdw << 2))
-			return 0;
-
-	if (pbi) {
-		__u32 mask;
-
-		mask = htonl((0xffffffff) << (32 - pbi));
-
-		if ((a1[pdw] ^ a2[pdw]) & mask)
-			return 0;
-	}
-
-	return 1;
-}
-
-/*
  *	test bit
  */
 
@@ -261,7 +231,7 @@ static struct fib6_node * fib6_add_1(str
 		 *	Prefix match
 		 */
 		if (plen < fn->fn_bit ||
-		    !addr_match(&key->addr, addr, fn->fn_bit))
+		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
 			goto insert_above;
 		
 		/*
@@ -667,7 +637,7 @@ static struct fib6_node * fib6_lookup_1(
 			key = (struct rt6key *) ((u8 *) fn->leaf +
 						 args->offset);
 
-			if (addr_match(&key->addr, args->addr, key->plen))
+			if (ipv6_prefix_equal(&key->addr, args->addr, key->plen))
 				return fn;
 		}
 
@@ -718,7 +688,7 @@ static struct fib6_node * fib6_locate_1(
 		 *	Prefix match
 		 */
 		if (plen < fn->fn_bit ||
-		    !addr_match(&key->addr, addr, fn->fn_bit))
+		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
 			return NULL;
 
 		if (plen == fn->fn_bit)
@@ -1211,7 +1181,7 @@ void fib6_run_gc(unsigned long dummy)
 {
 	if (dummy != ~0UL) {
 		spin_lock_bh(&fib6_gc_lock);
-		gc_args.timeout = (int)dummy;
+		gc_args.timeout = dummy ? (int)dummy : ip6_rt_gc_interval;
 	} else {
 		local_bh_disable();
 		if (!spin_trylock(&fib6_gc_lock)) {
@@ -1248,7 +1218,7 @@ void __init fib6_init(void)
 		panic("cannot create fib6_nodes cache");
 }
 
-void __exit fib6_gc_cleanup(void)
+void fib6_gc_cleanup(void)
 {
 	del_timer(&ip6_fib_timer);
 	kmem_cache_destroy(fib6_node_kmem);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -87,7 +87,7 @@ static struct ip6_flowlabel * fl_lookup(
 
 static void fl_free(struct ip6_flowlabel *fl)
 {
-	if (fl->opt)
+	if (fl)
 		kfree(fl->opt);
 	kfree(fl);
 }
@@ -351,8 +351,7 @@ fl_create(struct in6_flowlabel_req *freq
 	return fl;
 
 done:
-	if (fl)
-		fl_free(fl);
+	fl_free(fl);
 	*err_p = err;
 	return NULL;
 }
@@ -536,10 +535,12 @@ release:
 		if (err)
 			goto done;
 
-		/* Do not check for fault */
-		if (!freq.flr_label)
-			copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label,
-				     &fl->label, sizeof(fl->label));
+		if (!freq.flr_label) {
+			if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label,
+					 &fl->label, sizeof(fl->label))) {
+				/* Intentionally ignore fault. */
+			}
+		}
 
 		sfl1->fl = fl;
 		sfl1->next = np->ipv6_fl_list;
@@ -551,10 +552,8 @@ release:
 	}
 
 done:
-	if (fl)
-		fl_free(fl);
-	if (sfl1)
-		kfree(sfl1);
+	fl_free(fl);
+	kfree(sfl1);
 	return err;
 }
 
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -71,10 +71,18 @@ int ipv6_rcv(struct sk_buff *skb, struct
 		goto out;
 	}
 
-	/* Store incoming device index. When the packet will
-	   be queued, we cannot refer to skb->dev anymore.
+	/*
+	 * Store incoming device index. When the packet will
+	 * be queued, we cannot refer to skb->dev anymore.
+	 *
+	 * BTW, when we send a packet for our own local address on a
+	 * non-loopback interface (e.g. ethX), it is being delivered
+	 * via the loopback interface (lo) here; skb->dev = &loopback_dev.
+	 * It, however, should be considered as if it is being
+	 * arrived via the sending interface (ethX), because of the
+	 * nature of scoping architecture. --yoshfuji
 	 */
-	IP6CB(skb)->iif = dev->ifindex;
+	IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex;
 
 	if (skb->len < sizeof(struct ipv6hdr))
 		goto err;
@@ -95,15 +103,11 @@ int ipv6_rcv(struct sk_buff *skb, struct
 	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
 		if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
 			goto truncated;
-		if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
-			if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr))){
-				IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
-				goto drop;
-			}
-			hdr = skb->nh.ipv6h;
-			if (skb->ip_summed == CHECKSUM_HW)
-				skb->ip_summed = CHECKSUM_NONE;
+		if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
+			IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+			goto drop;
 		}
+		hdr = skb->nh.ipv6h;
 	}
 
 	if (hdr->nexthdr == NEXTHDR_HOP) {
@@ -138,7 +142,6 @@ static inline int ip6_input_finish(struc
 	unsigned int nhoff;
 	int nexthdr;
 	u8 hash;
-	int cksum_sub = 0;
 
 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
 
@@ -173,11 +176,8 @@ resubmit:
 		if (ipprot->flags & INET6_PROTO_FINAL) {
 			struct ipv6hdr *hdr;	
 
-			if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
-				skb->csum = csum_sub(skb->csum,
-						     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
-				cksum_sub++;
-			}
+			skb_postpull_rcsum(skb, skb->nh.raw,
+					   skb->h.raw - skb->nh.raw);
 			hdr = skb->nh.ipv6h;
 			if (ipv6_addr_is_multicast(&hdr->daddr) &&
 			    !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
 
 int ip6_output(struct sk_buff *skb)
 {
-	if (skb->len > dst_pmtu(skb->dst))
+	if (skb->len > dst_mtu(skb->dst) || dst_allfrag(skb->dst))
 		return ip6_fragment(skb, ip6_output2);
 	else
 		return ip6_output2(skb);
@@ -253,6 +253,8 @@ int ip6_xmit(struct sock *sk, struct sk_
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
 		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	if (hlimit < 0)
+		hlimit = ipv6_get_hoplimit(dst->dev);
 
 	hdr->payload_len = htons(seg_len);
 	hdr->nexthdr = proto;
@@ -261,7 +263,7 @@ int ip6_xmit(struct sock *sk, struct sk_
 	ipv6_addr_copy(&hdr->saddr, &fl->fl6_src);
 	ipv6_addr_copy(&hdr->daddr, first_hop);
 
-	mtu = dst_pmtu(dst);
+	mtu = dst_mtu(dst);
 	if ((skb->len <= mtu) || ipfragok) {
 		IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
 		return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
@@ -395,6 +397,7 @@ int ip6_forward(struct sk_buff *skb)
 		IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
 		goto drop;
 	}
+	dst = skb->dst;
 
 	/* IPv6 specs say nothing about it, but it is clear that we cannot
 	   send redirects to source routed frames.
@@ -426,10 +429,10 @@ int ip6_forward(struct sk_buff *skb)
 		goto error;
 	}
 
-	if (skb->len > dst_pmtu(dst)) {
+	if (skb->len > dst_mtu(dst)) {
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
-		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_pmtu(dst), skb->dev);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
 		IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS);
 		IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS);
 		kfree_skb(skb);
@@ -532,7 +535,7 @@ static int ip6_fragment(struct sk_buff *
 	hlen = ip6_find_1stfragopt(skb, &prevhdr);
 	nexthdr = *prevhdr;
 
-	mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr);
+	mtu = dst_mtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr);
 
 	if (skb_shinfo(skb)->frag_list) {
 		int first_len = skb_pagelen(skb);
@@ -549,13 +552,17 @@ static int ip6_fragment(struct sk_buff *
 			    skb_headroom(frag) < hlen)
 			    goto slow_path;
 
-			/* Correct socket ownership. */
-			if (frag->sk == NULL)
-				goto slow_path;
-
 			/* Partially cloned skb? */
 			if (skb_shared(frag))
 				goto slow_path;
+
+			BUG_ON(frag->sk);
+			if (skb->sk) {
+				sock_hold(skb->sk);
+				frag->sk = skb->sk;
+				frag->destructor = sock_wfree;
+				skb->truesize -= frag->truesize;
+			}
 		}
 
 		err = 0;
@@ -847,7 +854,9 @@ int ip6_append_data(struct sock *sk, int
 		np->cork.rt = rt;
 		inet->cork.fl = *fl;
 		np->cork.hop_limit = hlimit;
-		inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+		inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
+		if (dst_allfrag(rt->u.dst.path))
+			inet->cork.flags |= IPCORK_ALLFRAG;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
 		sk->sk_sndmsg_off = 0;
@@ -899,7 +908,7 @@ int ip6_append_data(struct sock *sk, int
 
 	while (length > 0) {
 		/* Check if the remaining data fits into current packet. */
-		copy = mtu - skb->len;
+		copy = (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
 		if (copy < length)
 			copy = maxfraglen - skb->len;
 
@@ -924,7 +933,7 @@ alloc_new_skb:
 			 * we know we need more fragment(s).
 			 */
 			datalen = length + fraggap;
-			if (datalen > mtu - fragheaderlen)
+			if (datalen > (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
 				datalen = maxfraglen - fragheaderlen;
 
 			fraglen = datalen + fragheaderlen;
@@ -1111,12 +1120,10 @@ int ip6_push_pending_frames(struct sock 
 		tail_skb = &(tmp_skb->next);
 		skb->len += tmp_skb->len;
 		skb->data_len += tmp_skb->len;
-#if 0 /* Logically correct, but useless work, ip_fragment() will have to undo */
 		skb->truesize += tmp_skb->truesize;
 		__sock_put(tmp_skb->sk);
 		tmp_skb->destructor = NULL;
 		tmp_skb->sk = NULL;
-#endif
 	}
 
 	ipv6_addr_copy(final_dst, &fl->fl6_dst);
@@ -1144,7 +1151,7 @@ int ip6_push_pending_frames(struct sock 
 	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
 	if (err) {
 		if (err > 0)
-			err = inet->recverr ? net_xmit_errno(err) : 0;
+			err = np->recverr ? net_xmit_errno(err) : 0;
 		if (err)
 			goto error;
 	}
@@ -1158,6 +1165,7 @@ out:
 	if (np->cork.rt) {
 		dst_release(&np->cork.rt->u.dst);
 		np->cork.rt = NULL;
+		inet->cork.flags &= ~IPCORK_ALLFRAG;
 	}
 	memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
 	return err;
@@ -1185,6 +1193,7 @@ void ip6_flush_pending_frames(struct soc
 	if (np->cork.rt) {
 		dst_release(&np->cork.rt->u.dst);
 		np->cork.rt = NULL;
+		inet->cork.flags &= ~IPCORK_ALLFRAG;
 	}
 	memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
 }
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -94,6 +94,7 @@ static inline struct dst_entry *ip6_tnl_
 	if (dst && dst->obsolete && 
 	    dst->ops->check(dst, t->dst_cookie) == NULL) {
 		t->dst_cache = NULL;
+		dst_release(dst);
 		return NULL;
 	}
 
@@ -688,14 +689,14 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
 			       t->parms.name);
 		goto tx_err_dst_release;
 	}
-	mtu = dst_pmtu(dst) - sizeof (*ipv6h);
+	mtu = dst_mtu(dst) - sizeof (*ipv6h);
 	if (opt) {
 		max_headroom += 8;
 		mtu -= 8;
 	}
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
-	if (skb->dst && mtu < dst_pmtu(skb->dst)) {
+	if (skb->dst && mtu < dst_mtu(skb->dst)) {
 		struct rt6_info *rt = (struct rt6_info *) skb->dst;
 		rt->rt6i_flags |= RTF_MODIFIED;
 		rt->u.dst.metrics[RTAX_MTU-1] = mtu;
@@ -881,6 +882,7 @@ ip6ip6_tnl_change(struct ip6_tnl *t, str
 	t->parms.hop_limit = p->hop_limit;
 	t->parms.encap_limit = p->encap_limit;
 	t->parms.flowinfo = p->flowinfo;
+	t->parms.link = p->link;
 	ip6ip6_tnl_link_config(t);
 	return 0;
 }
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -139,11 +139,9 @@ error_out:
 	return err;
 }
 
-static int ipcomp6_output(struct sk_buff *skb)
+static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	struct dst_entry *dst = skb->dst;
-	struct xfrm_state *x = dst->xfrm;
 	struct ipv6hdr *top_iph;
 	int hdr_len;
 	struct ipv6_comp_hdr *ipch;
@@ -162,8 +160,7 @@ static int ipcomp6_output(struct sk_buff
 
 	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 		skb_linearize(skb, GFP_ATOMIC) != 0) {
-		err = -ENOMEM;
-		goto error;
+		goto out_ok;
 	}
 
 	/* compression */
@@ -176,11 +173,7 @@ static int ipcomp6_output(struct sk_buff
 	tfm = *per_cpu_ptr(ipcd->tfms, cpu);
 
 	err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
-	if (err) {
-		put_cpu();
-		goto error;
-	}
-	if ((dlen + sizeof(struct ipv6_comp_hdr)) >= plen) {
+	if (err || (dlen + sizeof(struct ipv6_comp_hdr)) >= plen) {
 		put_cpu();
 		goto out_ok;
 	}
@@ -200,10 +193,7 @@ static int ipcomp6_output(struct sk_buff
 	*skb->nh.raw = IPPROTO_COMP;
 
 out_ok:
-	err = 0;
-
-error:
-	return err;
+	return 0;
 }
 
 static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -607,7 +607,7 @@ int ipv6_getsockopt(struct sock *sk, int
 		lock_sock(sk);
 		dst = sk_dst_get(sk);
 		if (dst) {
-			val = dst_pmtu(dst) - dst->header_len;
+			val = dst_mtu(dst);
 			dst_release(dst);
 		}
 		release_sock(sk);
@@ -698,7 +698,7 @@ void __init ipv6_packet_init(void)
 	dev_add_pack(&ipv6_packet_type);
 }
 
-void __exit ipv6_packet_cleanup(void)
+void ipv6_packet_cleanup(void)
 {
 	dev_remove_pack(&ipv6_packet_type);
 }
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
--- a/net/ipv6/ipv6_syms.c
+++ b/net/ipv6/ipv6_syms.c
@@ -37,5 +37,4 @@ EXPORT_SYMBOL(in6_dev_finish_destroy);
 EXPORT_SYMBOL(xfrm6_rcv);
 #endif
 EXPORT_SYMBOL(rt6_lookup);
-EXPORT_SYMBOL(fl6_sock_lookup);
 EXPORT_SYMBOL(ipv6_push_nfrag_opts);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -156,14 +156,13 @@ struct neigh_table nd_tbl = {
 
 /* ND options */
 struct ndisc_options {
-	struct nd_opt_hdr *nd_opt_array[7];
-	struct nd_opt_hdr *nd_opt_piend;
+	struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX];
 };
 
 #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_pi_end		nd_opt_array[__ND_OPT_PREFIX_INFO_END]
 #define nd_opts_rh		nd_opt_array[ND_OPT_REDIRECT_HDR]
 #define nd_opts_mtu		nd_opt_array[ND_OPT_MTU]
 
@@ -183,6 +182,11 @@ static int ndisc_addr_option_pad(unsigne
 	}
 }
 
+static inline int ndisc_opt_addr_space(struct net_device *dev)
+{
+	return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
+}
+
 static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
 				  unsigned short addr_type)
 {
@@ -267,6 +271,17 @@ static struct ndisc_options *ndisc_parse
 	return ndopts;
 }
 
+static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
+				      struct net_device *dev)
+{
+	u8 *lladdr = (u8 *)(p + 1);
+	int lladdrlen = p->nd_opt_len << 3;
+	int prepad = ndisc_addr_option_pad(dev->type);
+	if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
+		return NULL;
+	return (lladdr + prepad);
+}
+
 int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
 {
 	switch (dev->type) {
@@ -439,7 +454,7 @@ static void ndisc_send_na(struct net_dev
 
 	if (inc_opt) {
 		if (dev->addr_len)
-			len += NDISC_OPT_SPACE(dev->addr_len);
+			len += ndisc_opt_addr_space(dev);
 		else
 			inc_opt = 0;
 	}
@@ -532,7 +547,7 @@ void ndisc_send_ns(struct net_device *de
 	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 	send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
 	if (send_llinfo)
-		len += NDISC_OPT_SPACE(dev->addr_len);
+		len += ndisc_opt_addr_space(dev);
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
 				  1, &err);
@@ -608,7 +623,7 @@ void ndisc_send_rs(struct net_device *de
 
 	len = sizeof(struct icmp6hdr);
 	if (dev->addr_len)
-		len += NDISC_OPT_SPACE(dev->addr_len);
+		len += ndisc_opt_addr_space(dev);
 
         skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
 				  1, &err);
@@ -704,7 +719,6 @@ static void ndisc_recv_ns(struct sk_buff
 	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
 	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 	u8 *lladdr = NULL;
-	int lladdrlen = 0;
 	u32 ndoptlen = skb->tail - msg->opt;
 	struct ndisc_options ndopts;
 	struct net_device *dev = skb->dev;
@@ -741,10 +755,8 @@ static void ndisc_recv_ns(struct sk_buff
 	}
 
 	if (ndopts.nd_opts_src_lladdr) {
-		lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1) +
-			ndisc_addr_option_pad(dev->type);
-		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
-		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
+		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
+		if (!lladdr) {
 			ND_PRINTK2(KERN_WARNING
 				   "ICMPv6 NS: invalid link-layer address length\n");
 			return;
@@ -867,7 +879,6 @@ static void ndisc_recv_na(struct sk_buff
 	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
 	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 	u8 *lladdr = NULL;
-	int lladdrlen = 0;
 	u32 ndoptlen = skb->tail - msg->opt;
 	struct ndisc_options ndopts;
 	struct net_device *dev = skb->dev;
@@ -899,10 +910,8 @@ static void ndisc_recv_na(struct sk_buff
 		return;
 	}
 	if (ndopts.nd_opts_tgt_lladdr) {
-		lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1) +
-			ndisc_addr_option_pad(dev->type);
-		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
-		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
+		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
+		if (!lladdr) {
 			ND_PRINTK2(KERN_WARNING
 				   "ICMPv6 NA: invalid link-layer address length\n");
 			return;
@@ -963,7 +972,6 @@ static void ndisc_recv_rs(struct sk_buff
 	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
 	struct ndisc_options ndopts;
 	u8 *lladdr = NULL;
-	int lladdrlen = 0;
 
 	if (skb->len < sizeof(*rs_msg))
 		return;
@@ -994,10 +1002,9 @@ static void ndisc_recv_rs(struct sk_buff
 	}
 
 	if (ndopts.nd_opts_src_lladdr) {
-		lladdr = (u8 *)(ndopts.nd_opts_src_lladdr + 1) +
-			ndisc_addr_option_pad(skb->dev->type);
-		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
-		if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len))
+		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
+					     skb->dev);
+		if (!lladdr)
 			goto out;
 	}
 
@@ -1121,8 +1128,11 @@ static void ndisc_router_discovery(struc
 	if (rt)
 		rt->rt6i_expires = jiffies + (HZ * lifetime);
 
-	if (ra_msg->icmph.icmp6_hop_limit)
+	if (ra_msg->icmph.icmp6_hop_limit) {
 		in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+		if (rt)
+			rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
+	}
 
 	/*
 	 *	Update Reachable Time and Retrans Timer
@@ -1166,12 +1176,10 @@ static void ndisc_router_discovery(struc
 				       skb->dev, 1);
 	if (neigh) {
 		u8 *lladdr = NULL;
-		int lladdrlen;
 		if (ndopts.nd_opts_src_lladdr) {
-			lladdr = (u8*)((ndopts.nd_opts_src_lladdr)+1) +
-				ndisc_addr_option_pad(skb->dev->type);
-			lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
-			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+			lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
+						     skb->dev);
+			if (!lladdr) {
 				ND_PRINTK2(KERN_WARNING
 					   "ICMPv6 RA: invalid link-layer address length\n");
 				goto out;
@@ -1236,7 +1244,6 @@ static void ndisc_redirect_rcv(struct sk
 	struct ndisc_options ndopts;
 	int optlen;
 	u8 *lladdr = NULL;
-	int lladdrlen;
 
 	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
 		ND_PRINTK2(KERN_WARNING
@@ -1291,10 +1298,9 @@ static void ndisc_redirect_rcv(struct sk
 		return;
 	}
 	if (ndopts.nd_opts_tgt_lladdr) {
-		lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1) +
-			ndisc_addr_option_pad(skb->dev->type);
-		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
-		if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
+					     skb->dev);
+		if (!lladdr) {
 			ND_PRINTK2(KERN_WARNING
 				   "ICMPv6 Redirect: invalid link-layer address length\n");
 			in6_dev_put(in6_dev);
@@ -1329,6 +1335,7 @@ void ndisc_send_redirect(struct sk_buff 
 	int rd_len;
 	int err;
 	int hlen;
+	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
 
 	dev = skb->dev;
 
@@ -1341,10 +1348,9 @@ void ndisc_send_redirect(struct sk_buff 
 
 	ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr);
 
-	rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
-	if (rt == NULL)
+	dst = ip6_route_output(NULL, &fl);
+	if (dst == NULL)
 		return;
-	dst = &rt->u.dst;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
 	if (err) {
@@ -1366,16 +1372,14 @@ void ndisc_send_redirect(struct sk_buff 
 	}
 
 	if (dev->addr_len) {
-		if (neigh->nud_state&NUD_VALID) {
-			len  += NDISC_OPT_SPACE(dev->addr_len);
-		} else {
-			/* If nexthop is not valid, do not redirect!
-			   We will make it later, when will be sure,
-			   that it is alive.
-			 */
-			dst_release(dst);
-			return;
-		}
+		read_lock_bh(&neigh->lock);
+		if (neigh->nud_state & NUD_VALID) {
+			memcpy(ha_buf, neigh->ha, dev->addr_len);
+			read_unlock_bh(&neigh->lock);
+			ha = ha_buf;
+			len += ndisc_opt_addr_space(dev);
+		} else
+			read_unlock_bh(&neigh->lock);
 	}
 
 	rd_len = min_t(unsigned int,
@@ -1420,8 +1424,8 @@ void ndisc_send_redirect(struct sk_buff 
 	 *	include target_address option
 	 */
 
-	if (dev->addr_len)
-		opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, neigh->ha,
+	if (ha)
+		opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
 					     dev->addr_len, dev->type);
 
 	/*
@@ -1515,11 +1519,11 @@ static int ndisc_netdev_event(struct not
 	switch (event) {
 	case NETDEV_CHANGEADDR:
 		neigh_changeaddr(&nd_tbl, dev);
-		fib6_run_gc(0);
+		fib6_run_gc(~0UL);
 		break;
 	case NETDEV_DOWN:
 		neigh_ifdown(&nd_tbl, dev);
-		fib6_run_gc(0);
+		fib6_run_gc(~0UL);
 		break;
 	default:
 		break;
@@ -1533,18 +1537,106 @@ static struct notifier_block ndisc_netde
 };
 
 #ifdef CONFIG_SYSCTL
+static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
+					 const char *func, const char *dev_name)
+{
+	static char warncomm[TASK_COMM_LEN];
+	static int warned;
+	if (strcmp(warncomm, current->comm) && warned < 5) {
+		strcpy(warncomm, current->comm);
+		printk(KERN_WARNING
+			"process `%s' is using deprecated sysctl (%s) "
+			"net.ipv6.neigh.%s.%s; "
+			"Use net.ipv6.neigh.%s.%s_ms "
+			"instead.\n",
+			warncomm, func,
+			dev_name, ctl->procname,
+			dev_name, ctl->procname);
+		warned++;
+	}
+}
+
 int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos)
 {
 	struct net_device *dev = ctl->extra1;
 	struct inet6_dev *idev;
+	int ret;
 
-	if (write && dev && (idev = in6_dev_get(dev)) != NULL) {
+	if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
+	    ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
+		ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
+
+	switch (ctl->ctl_name) {
+	case NET_NEIGH_RETRANS_TIME:
+		ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+		break;
+	case NET_NEIGH_REACHABLE_TIME:
+		ret = proc_dointvec_jiffies(ctl, write,
+					    filp, buffer, lenp, ppos);
+		break;
+	case NET_NEIGH_RETRANS_TIME_MS:
+	case NET_NEIGH_REACHABLE_TIME_MS:
+		ret = proc_dointvec_ms_jiffies(ctl, write,
+					       filp, buffer, lenp, ppos);
+		break;
+	default:
+		ret = -1;
+	}
+
+	if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
+		if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
+		    ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
+			idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
 		idev->tstamp = jiffies;
 		inet6_ifinfo_notify(RTM_NEWLINK, idev);
 		in6_dev_put(idev);
 	}
-	return proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+	return ret;
 }
+
+static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
+					int nlen, void __user *oldval,
+					size_t __user *oldlenp,
+					void __user *newval, size_t newlen,
+					void **context)
+{
+	struct net_device *dev = ctl->extra1;
+	struct inet6_dev *idev;
+	int ret;
+
+	if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
+	    ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
+		ndisc_warn_deprecated_sysctl(ctl, "procfs", dev ? dev->name : "default");
+
+	switch (ctl->ctl_name) {
+	case NET_NEIGH_REACHABLE_TIME:
+		ret = sysctl_jiffies(ctl, name, nlen,
+				     oldval, oldlenp, newval, newlen,
+				     context);
+		break;
+	case NET_NEIGH_RETRANS_TIME_MS:
+	case NET_NEIGH_REACHABLE_TIME_MS:
+		 ret = sysctl_ms_jiffies(ctl, name, nlen,
+					 oldval, oldlenp, newval, newlen,
+					 context);
+		 break;
+	default:
+		ret = 0;
+	}
+
+	if (newval && newlen && ret > 0 &&
+	    dev && (idev = in6_dev_get(dev)) != NULL) {
+		if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
+		    ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
+			idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
+		idev->tstamp = jiffies;
+		inet6_ifinfo_notify(RTM_NEWLINK, idev);
+		in6_dev_put(idev);
+	}
+
+	return ret;
+}
+
 #endif
 
 int __init ndisc_init(struct net_proto_family *ops)
@@ -1578,7 +1670,9 @@ int __init ndisc_init(struct net_proto_f
 
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, 
-			      "ipv6", &ndisc_ifinfo_sysctl_change);
+			      "ipv6",
+			      &ndisc_ifinfo_sysctl_change,
+			      &ndisc_ifinfo_sysctl_strategy);
 #endif
 
 	register_netdevice_notifier(&ndisc_netdev_notifier);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -2,8 +2,8 @@
 # IP netfilter configuration
 #
 
-menu "IPv6: Netfilter Configuration"
-	depends on INET && IPV6 && NETFILTER
+menu "IPv6: Netfilter Configuration (EXPERIMENTAL)"
+	depends on INET && IPV6 && NETFILTER && EXPERIMENTAL
 
 #tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP6_NF_CONNTRACK
 #if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -20,6 +20,9 @@
  *             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]
+ * 2005-02-04: Added /proc counter for dropped packets; fixed so
+ *             packets aren't delivered to user space if they're going
+ *             to be dropped.
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -64,6 +67,8 @@ static DEFINE_RWLOCK(queue_lock);
 static int peer_pid;
 static unsigned int copy_range;
 static unsigned int queue_total;
+static unsigned int queue_dropped = 0;
+static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
 static DECLARE_MUTEX(ipqnl_sem);
@@ -75,18 +80,11 @@ ipq_issue_verdict(struct ipq_queue_entry
 	kfree(entry);
 }
 
-static inline int
+static inline void
 __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;
 }
 
 /*
@@ -312,14 +310,24 @@ ipq_enqueue_packet(struct sk_buff *skb, 
 	if (!peer_pid)
 		goto err_out_free_nskb; 
 
+	if (queue_total >= queue_maxlen) {
+                queue_dropped++;
+		status = -ENOSPC;
+		if (net_ratelimit())
+		        printk (KERN_WARNING "ip6_queue: fill at %d entries, "
+				"dropping packet(s).  Dropped: %d\n", queue_total,
+				queue_dropped);
+		goto err_out_free_nskb;
+	}
+
  	/* netlink_unicast will either free the nskb or attach it to a socket */ 
 	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
-	if (status < 0)
+	if (status < 0) {
+ 	        queue_user_dropped++;
 		goto err_out_unlock;
+	}
 	
-	status = __ipq_enqueue_entry(entry);
-	if (status < 0)
-		goto err_out_unlock;
+	__ipq_enqueue_entry(entry);
 
 	write_unlock_bh(&queue_lock);
 	return status;
@@ -541,20 +549,18 @@ ipq_rcv_skb(struct sk_buff *skb)
 static void
 ipq_rcv_sk(struct sock *sk, int len)
 {
-	do {
-		struct sk_buff *skb;
+	struct sk_buff *skb;
+	unsigned int qlen;
 
-		if (down_trylock(&ipqnl_sem))
-			return;
+	down(&ipqnl_sem);
 			
-		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-			ipq_rcv_skb(skb);
-			kfree_skb(skb);
-		}
+	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+		ipq_rcv_skb(skb);
+		kfree_skb(skb);
+	}
 		
-		up(&ipqnl_sem);
-
-	} while (ipqnl && ipqnl->sk_receive_queue.qlen);
+	up(&ipqnl_sem);
 }
 
 static int
@@ -639,12 +645,16 @@ ipq_get_info(char *buffer, char **start,
 	              "Copy mode         : %hu\n"
 	              "Copy range        : %u\n"
 	              "Queue length      : %u\n"
-	              "Queue max. length : %u\n",
+	              "Queue max. length : %u\n"
+		      "Queue dropped     : %u\n"
+		      "Netfilter dropped : %u\n",
 	              peer_pid,
 	              copy_mode,
 	              copy_range,
 	              queue_total,
-	              queue_maxlen);
+	              queue_maxlen,
+		      queue_dropped,
+		      queue_user_dropped);
 
 	read_unlock_bh(&queue_lock);
 	
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -952,7 +952,7 @@ translate_table(const char *name,
 	}
 
 	/* And one copy for every other CPU */
-	for (i = 1; i < NR_CPUS; i++) {
+	for (i = 1; i < num_possible_cpus(); i++) {
 		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
 		       newinfo->entries,
 		       SMP_ALIGN(newinfo->size));
@@ -974,7 +974,7 @@ replace_table(struct ip6t_table *table,
 		struct ip6t_entry *table_base;
 		unsigned int i;
 
-		for (i = 0; i < NR_CPUS; i++) {
+		for (i = 0; i < num_possible_cpus(); i++) {
 			table_base =
 				(void *)newinfo->entries
 				+ TABLE_OFFSET(newinfo, i);
@@ -1021,7 +1021,7 @@ get_counters(const struct ip6t_table_inf
 	unsigned int cpu;
 	unsigned int i;
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+	for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
 		i = 0;
 		IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
 				  t->size,
@@ -1155,7 +1155,7 @@ do_replace(void __user *user, unsigned i
 		return -ENOMEM;
 
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
-			  + SMP_ALIGN(tmp.size) * NR_CPUS);
+			  + SMP_ALIGN(tmp.size) * num_possible_cpus());
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1469,7 +1469,7 @@ int ip6t_register_table(struct ip6t_tabl
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
-			  + SMP_ALIGN(repl->size) * NR_CPUS);
+			  + SMP_ALIGN(repl->size) * num_possible_cpus());
 	if (!newinfo)
 		return -ENOMEM;
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -34,6 +34,7 @@
 #include <linux/netfilter_ipv6.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
+#include <asm/bug.h>
 
 #include <net/ip.h>
 #include <net/sock.h>
@@ -452,12 +453,15 @@ csum_copy_err:
 }
 
 static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
-				     struct raw6_sock *rp, int len)
+				     struct raw6_sock *rp)
 {
 	struct sk_buff *skb;
 	int err = 0;
-	u16 *csum;
+	int offset;
+	int len;
+	int total_len;
 	u32 tmp_csum;
+	u16 csum;
 
 	if (!rp->checksum)
 		goto send;
@@ -465,10 +469,11 @@ static int rawv6_push_pending_frames(str
 	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
 		goto out;
 
-	if (rp->offset + 1 < len)
-		csum = (u16 *)(skb->h.raw + rp->offset);
-	else {
+	offset = rp->offset;
+	total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data);
+	if (offset >= total_len - 1) {
 		err = -EINVAL;
+		ip6_flush_pending_frames(sk);
 		goto out;
 	}
 
@@ -479,23 +484,46 @@ static int rawv6_push_pending_frames(str
 		 */
 		tmp_csum = skb->csum;
 	} else {
+		struct sk_buff *csum_skb = NULL;
 		tmp_csum = 0;
 
 		skb_queue_walk(&sk->sk_write_queue, skb) {
 			tmp_csum = csum_add(tmp_csum, skb->csum);
+
+			if (csum_skb)
+				continue;
+
+			len = skb->len - (skb->h.raw - skb->data);
+			if (offset >= len) {
+				offset -= len;
+				continue;
+			}
+
+			csum_skb = skb;
 		}
+
+		skb = csum_skb;
 	}
 
+	offset += skb->h.raw - skb->data;
+	if (skb_copy_bits(skb, offset, &csum, 2))
+		BUG();
+
 	/* in case cksum was not initialized */
-	if (unlikely(*csum))
-		tmp_csum = csum_sub(tmp_csum, *csum);
+	if (unlikely(csum))
+		tmp_csum = csum_sub(tmp_csum, csum);
 
-	*csum = csum_ipv6_magic(&fl->fl6_src,
-				&fl->fl6_dst,
-				len, fl->proto, tmp_csum);
+	tmp_csum = csum_ipv6_magic(&fl->fl6_src,
+				   &fl->fl6_dst,
+				   total_len, fl->proto, tmp_csum);
+
+	if (tmp_csum == 0)
+		tmp_csum = -1;
+
+	csum = tmp_csum;
+	if (skb_store_bits(skb, offset, &csum, 2))
+		BUG();
 
-	if (*csum == 0)
-		*csum = -1;
 send:
 	err = ip6_push_pending_frames(sk);
 out:
@@ -506,7 +534,7 @@ static int rawv6_send_hdrinc(struct sock
 			struct flowi *fl, struct rt6_info *rt, 
 			unsigned int flags)
 {
-	struct inet_sock *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6hdr *iph;
 	struct sk_buff *skb;
 	unsigned int hh_len;
@@ -543,7 +571,7 @@ static int rawv6_send_hdrinc(struct sock
 	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		      dst_output);
 	if (err > 0)
-		err = inet->recverr ? net_xmit_errno(err) : 0;
+		err = np->recverr ? net_xmit_errno(err) : 0;
 	if (err)
 		goto error;
 out:
@@ -756,6 +784,8 @@ static int rawv6_sendmsg(struct kiocb *i
 			hlimit = np->hop_limit;
 		if (hlimit < 0)
 			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+		if (hlimit < 0)
+			hlimit = ipv6_get_hoplimit(dst->dev);
 	}
 
 	if (msg->msg_flags&MSG_CONFIRM)
@@ -772,14 +802,12 @@ back_from_confirm:
 		if (err)
 			ip6_flush_pending_frames(sk);
 		else if (!(msg->msg_flags & MSG_MORE))
-			err = rawv6_push_pending_frames(sk, &fl, rp, len);
+			err = rawv6_push_pending_frames(sk, &fl, rp);
 	}
 done:
 	ip6_dst_store(sk, dst,
 		      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
 		      &np->daddr : NULL);
-	if (err > 0)
-		err = np->recverr ? net_xmit_errno(err) : 0;
 
 	release_sock(sk);
 out:	
@@ -975,7 +1003,7 @@ static int rawv6_init_sk(struct sock *sk
 }
 
 struct proto rawv6_prot = {
-	.name =		"RAW",
+	.name =		"RAWv6",
 	.owner =	THIS_MODULE,
 	.close =	rawv6_close,
 	.connect =	ip6_datagram_connect,
@@ -991,7 +1019,7 @@ struct proto rawv6_prot = {
 	.backlog_rcv =	rawv6_rcv_skb,
 	.hash =		raw_v6_hash,
 	.unhash =	raw_v6_unhash,
-	.slab_obj_size = sizeof(struct raw6_sock),
+	.obj_size =	sizeof(struct raw6_sock),
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -589,7 +589,6 @@ static struct dst_entry *ip6_dst_check(s
 	if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
 		return dst;
 
-	dst_release(dst);
 	return NULL;
 }
 
@@ -626,10 +625,12 @@ static void ip6_rt_update_pmtu(struct ds
 {
 	struct rt6_info *rt6 = (struct rt6_info*)dst;
 
-	if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen == 128) {
+	if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
 		rt6->rt6i_flags |= RTF_MODIFIED;
-		if (mtu < IPV6_MIN_MTU)
+		if (mtu < IPV6_MIN_MTU) {
 			mtu = IPV6_MIN_MTU;
+			dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+		}
 		dst->metrics[RTAX_MTU-1] = mtu;
 	}
 }
@@ -685,7 +686,7 @@ struct dst_entry *ndisc_dst_alloc(struct
 	atomic_set(&rt->u.dst.__refcnt, 1);
 	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
 	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
+	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
 	rt->u.dst.output  = output;
 
 #if 0	/* there's no chance to use these for ndisc */
@@ -769,7 +770,7 @@ static int ipv6_get_mtu(struct net_devic
 	return mtu;
 }
 
-static int ipv6_get_hoplimit(struct net_device *dev)
+int ipv6_get_hoplimit(struct net_device *dev)
 {
 	int hoplimit = ipv6_devconf.hop_limit;
 	struct inet6_dev *idev;
@@ -965,19 +966,12 @@ install_route:
 		}
 	}
 
-	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) {
-		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
-			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
-				IPV6_DEFAULT_MCASTHOPS;
-		else
-			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
-				ipv6_get_hoplimit(dev);
-	}
-
+	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)
+		rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
 	if (!rt->u.dst.metrics[RTAX_MTU-1])
 		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
 	if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
+		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
 	rt->u.dst.dev = dev;
 	rt->rt6i_idev = idev;
 	return ip6_ins_rt(rt, nlh, _rtattr);
@@ -1140,7 +1134,7 @@ source_ok:
 	nrt->rt6i_nexthop = neigh_clone(neigh);
 	/* Reset pmtu, it may be better */
 	nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
-	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&nrt->u.dst));
+	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst));
 
 	if (ip6_ins_rt(nrt, NULL, NULL))
 		goto out;
@@ -1164,26 +1158,26 @@ void rt6_pmtu_discovery(struct in6_addr 
 			struct net_device *dev, u32 pmtu)
 {
 	struct rt6_info *rt, *nrt;
-
-	if (pmtu < IPV6_MIN_MTU) {
-		if (net_ratelimit())
-			printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
-			       pmtu);
-		/* 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;
-	}
+	int allfrag = 0;
 
 	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
-
 	if (rt == NULL)
 		return;
 
-	if (pmtu >= dst_pmtu(&rt->u.dst))
+	if (pmtu >= dst_mtu(&rt->u.dst))
 		goto out;
 
+	if (pmtu < IPV6_MIN_MTU) {
+		/*
+		 * According to RFC2460, PMTU is set to the IPv6 Minimum Link 
+		 * MTU (1280) and a fragment header should always be included
+		 * after a node receiving Too Big message reporting PMTU is
+		 * less than the IPv6 Minimum Link MTU.
+		 */
+		pmtu = IPV6_MIN_MTU;
+		allfrag = 1;
+	}
+
 	/* New mtu received -> path was valid.
 	   They are sent only in response to data packets,
 	   so that this nexthop apparently is reachable. --ANK
@@ -1197,6 +1191,8 @@ void rt6_pmtu_discovery(struct in6_addr 
 	 */
 	if (rt->rt6i_flags & RTF_CACHE) {
 		rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+		if (allfrag)
+			rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
 		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
 		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
 		goto out;
@@ -1211,6 +1207,8 @@ void rt6_pmtu_discovery(struct in6_addr 
 		nrt = rt6_cow(rt, daddr, saddr);
 		if (!nrt->u.dst.error) {
 			nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+			if (allfrag)
+				nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
 			/* 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
@@ -1232,6 +1230,8 @@ void rt6_pmtu_discovery(struct in6_addr 
 		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
 		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+		if (allfrag)
+			nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
 		ip6_ins_rt(nrt, NULL, NULL);
 	}
 
@@ -1405,8 +1405,8 @@ struct rt6_info *addrconf_dst_alloc(stru
 	rt->rt6i_dev = &loopback_dev;
 	rt->rt6i_idev = idev;
 	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
-	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev);
+	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
 	rt->u.dst.obsolete = -1;
 
 	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
@@ -1480,9 +1480,9 @@ static int rt6_mtu_change_route(struct r
 	 */
 	if (rt->rt6i_dev == arg->dev &&
 	    !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
-            (dst_pmtu(&rt->u.dst) > arg->mtu ||
-             (dst_pmtu(&rt->u.dst) < arg->mtu &&
-	      dst_pmtu(&rt->u.dst) == idev->cnf.mtu6)))
+            (dst_mtu(&rt->u.dst) > arg->mtu ||
+             (dst_mtu(&rt->u.dst) < arg->mtu &&
+	      dst_mtu(&rt->u.dst) == idev->cnf.mtu6)))
 		rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
 	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu);
 	return 0;
@@ -1993,9 +1993,7 @@ int ipv6_sysctl_rtcache_flush(ctl_table 
 {
 	if (write) {
 		proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
-		if (flush_delay < 0)
-			flush_delay = 0;
-		fib6_run_gc((unsigned long)flush_delay);
+		fib6_run_gc(flush_delay <= 0 ? ~0UL : (unsigned long)flush_delay);
 		return 0;
 	} else
 		return -EINVAL;
@@ -2007,7 +2005,7 @@ ctl_table ipv6_route_table[] = {
 		.procname	=	"flush",
          	.data		=	&flush_delay,
 		.maxlen		=	sizeof(int),
-		.mode		=	0644,
+		.mode		=	0200,
          	.proc_handler	=	&ipv6_sysctl_rtcache_flush
 	},
 	{
@@ -2080,6 +2078,15 @@ ctl_table ipv6_route_table[] = {
          	.proc_handler	=	&proc_dointvec_jiffies,
 		.strategy	=	&sysctl_jiffies,
 	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,
+		.procname	=	"gc_min_interval_ms",
+         	.data		=	&ip6_rt_gc_min_interval,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_ms_jiffies,
+		.strategy	=	&sysctl_ms_jiffies,
+	},
 	{ .ctl_name = 0 }
 };
 
@@ -2109,7 +2116,7 @@ void __init ip6_route_init(void)
 #endif
 }
 
-void __exit ip6_route_cleanup(void)
+void ip6_route_cleanup(void)
 {
 #ifdef CONFIG_PROC_FS
 	proc_net_remove("ipv6_route");
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -500,9 +500,9 @@ static int ipip6_tunnel_xmit(struct sk_b
 	}
 
 	if (tiph->frag_off)
-		mtu = dst_pmtu(&rt->u.dst) - sizeof(struct iphdr);
+		mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
 	else
-		mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
+		mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -139,9 +139,12 @@ static int tcp_v6_get_port(struct sock *
 		int rover;
 
 		spin_lock(&tcp_portalloc_lock);
-		rover = tcp_port_rover;
+		if (tcp_port_rover < low)
+			rover = low;
+		else
+			rover = tcp_port_rover;
 		do {	rover++;
-			if ((rover < low) || (rover > high))
+			if (rover > high)
 				rover = low;
 			head = &tcp_bhash[tcp_bhashfn(rover)];
 			spin_lock(&head->lock);
@@ -441,21 +444,22 @@ static __u32 tcp_v6_init_sequence(struct
 	}
 }
 
-static int tcp_v6_check_established(struct sock *sk)
+static int __tcp_v6_check_established(struct sock *sk, __u16 lport,
+				      struct tcp_tw_bucket **twp)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct in6_addr *daddr = &np->rcv_saddr;
 	struct in6_addr *saddr = &np->daddr;
 	int dif = sk->sk_bound_dev_if;
-	u32 ports = TCP_COMBINED_PORTS(inet->dport, inet->num);
+	u32 ports = TCP_COMBINED_PORTS(inet->dport, lport);
 	int hash = tcp_v6_hashfn(daddr, inet->num, saddr, inet->dport);
 	struct tcp_ehash_bucket *head = &tcp_ehash[hash];
 	struct sock *sk2;
 	struct hlist_node *node;
 	struct tcp_tw_bucket *tw;
 
-	write_lock_bh(&head->lock);
+	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
 	sk_for_each(sk2, node, &(head + tcp_ehash_size)->chain) {
@@ -468,7 +472,10 @@ static int tcp_v6_check_established(stru
 		   sk2->sk_bound_dev_if == sk->sk_bound_dev_if) {
 			struct tcp_sock *tp = tcp_sk(sk);
 
-			if (tw->tw_ts_recent_stamp) {
+			if (tw->tw_ts_recent_stamp &&
+			    (!twp || (sysctl_tcp_tw_reuse &&
+				      xtime.tv_sec - 
+				      tw->tw_ts_recent_stamp > 1))) {
 				/* See comment in tcp_ipv4.c */
 				tp->write_seq = tw->tw_snd_nxt + 65535 + 2;
 				if (!tp->write_seq)
@@ -494,40 +501,113 @@ unique:
 	__sk_add_node(sk, &head->chain);
 	sk->sk_hashent = hash;
 	sock_prot_inc_use(sk->sk_prot);
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 
-	if (tw) {
+	if (twp) {
+		*twp = tw;
+		NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
+	} else if (tw) {
 		/* Silly. Should hash-dance instead... */
-		local_bh_disable();
 		tcp_tw_deschedule(tw);
 		NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
-		local_bh_enable();
 
 		tcp_tw_put(tw);
 	}
 	return 0;
 
 not_unique:
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 	return -EADDRNOTAVAIL;
 }
 
+static inline u32 tcpv6_port_offset(const struct sock *sk)
+{
+	const struct inet_sock *inet = inet_sk(sk);
+	const struct ipv6_pinfo *np = inet6_sk(sk);
+
+	return secure_tcpv6_port_ephemeral(np->rcv_saddr.s6_addr32,
+					   np->daddr.s6_addr32,
+					   inet->dport);
+}
+
 static int tcp_v6_hash_connect(struct sock *sk)
 {
-	struct tcp_bind_hashbucket *head;
-	struct tcp_bind_bucket *tb;
+	unsigned short snum = inet_sk(sk)->num;
+ 	struct tcp_bind_hashbucket *head;
+ 	struct tcp_bind_bucket *tb;
+	int ret;
 
-	/* XXX */
-	if (inet_sk(sk)->num == 0) { 
-		int err = tcp_v6_get_port(sk, inet_sk(sk)->num);
-		if (err)
-			return err;
-		inet_sk(sk)->sport = htons(inet_sk(sk)->num);
-	}
+ 	if (!snum) {
+ 		int low = sysctl_local_port_range[0];
+ 		int high = sysctl_local_port_range[1];
+		int range = high - low;
+ 		int i;
+		int port;
+		static u32 hint;
+		u32 offset = hint + tcpv6_port_offset(sk);
+		struct hlist_node *node;
+ 		struct tcp_tw_bucket *tw = NULL;
+
+ 		local_bh_disable();
+		for (i = 1; i <= range; i++) {
+			port = low + (i + offset) % range;
+ 			head = &tcp_bhash[tcp_bhashfn(port)];
+ 			spin_lock(&head->lock);
+
+ 			/* Does not bother with rcv_saddr checks,
+ 			 * because the established check is already
+ 			 * unique enough.
+ 			 */
+			tb_for_each(tb, node, &head->chain) {
+ 				if (tb->port == port) {
+ 					BUG_TRAP(!hlist_empty(&tb->owners));
+ 					if (tb->fastreuse >= 0)
+ 						goto next_port;
+ 					if (!__tcp_v6_check_established(sk,
+									port,
+									&tw))
+ 						goto ok;
+ 					goto next_port;
+ 				}
+ 			}
+
+ 			tb = tcp_bucket_create(head, port);
+ 			if (!tb) {
+ 				spin_unlock(&head->lock);
+ 				break;
+ 			}
+ 			tb->fastreuse = -1;
+ 			goto ok;
+
+ 		next_port:
+ 			spin_unlock(&head->lock);
+ 		}
+ 		local_bh_enable();
+
+ 		return -EADDRNOTAVAIL;
+
+ok:
+		hint += i;
+
+ 		/* Head lock still held and bh's disabled */
+ 		tcp_bind_hash(sk, tb, port);
+		if (sk_unhashed(sk)) {
+ 			inet_sk(sk)->sport = htons(port);
+ 			__tcp_v6_hash(sk);
+ 		}
+ 		spin_unlock(&head->lock);
+
+ 		if (tw) {
+ 			tcp_tw_deschedule(tw);
+ 			tcp_tw_put(tw);
+ 		}
 
-	head = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)];
-	tb = tb_head(head);
+		ret = 0;
+		goto out;
+ 	}
 
+ 	head  = &tcp_bhash[tcp_bhashfn(snum)];
+ 	tb  = tcp_sk(sk)->bind_hash;
 	spin_lock_bh(&head->lock);
 
 	if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
@@ -535,8 +615,12 @@ static int tcp_v6_hash_connect(struct so
 		spin_unlock_bh(&head->lock);
 		return 0;
 	} else {
-		spin_unlock_bh(&head->lock);
-		return tcp_v6_check_established(sk);
+		spin_unlock(&head->lock);
+		/* No definite answer... Walk to established hash table */
+		ret = __tcp_v6_check_established(sk, snum, NULL);
+out:
+		local_bh_enable();
+		return ret;
 	}
 }
 
@@ -701,7 +785,6 @@ static int tcp_v6_connect(struct sock *s
 	tp->ext_header_len = 0;
 	if (np->opt)
 		tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
-	tp->ext2_header_len = dst->header_len;
 
 	tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
@@ -813,8 +896,8 @@ static void tcp_v6_err(struct sk_buff *s
 		} else
 			dst_hold(dst);
 
-		if (tp->pmtu_cookie > dst_pmtu(dst)) {
-			tcp_sync_mss(sk, dst_pmtu(dst));
+		if (tp->pmtu_cookie > dst_mtu(dst)) {
+			tcp_sync_mss(sk, dst_mtu(dst));
 			tcp_simple_retransmit(sk);
 		} /* else let the usual retransmit timer handle it */
 		dst_release(dst);
@@ -1443,9 +1526,8 @@ static struct sock * tcp_v6_syn_recv_soc
 	if (newnp->opt)
 		newtp->ext_header_len = newnp->opt->opt_nflen +
 					newnp->opt->opt_flen;
-	newtp->ext2_header_len = dst->header_len;
 
-	tcp_sync_mss(newsk, dst_pmtu(dst));
+	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
 	tcp_initialize_rcv_mss(newsk);
 
@@ -1792,7 +1874,6 @@ static int tcp_v6_rebuild_header(struct 
 		ip6_dst_store(sk, dst, NULL);
 		sk->sk_route_caps = dst->dev->features &
 			~(NETIF_F_IP_CSUM | NETIF_F_TSO);
-		tcp_sk(sk)->ext2_header_len = dst->header_len;
 	}
 
 	return 0;
@@ -1846,7 +1927,6 @@ static int tcp_v6_xmit(struct sk_buff *s
 		ip6_dst_store(sk, dst, NULL);
 		sk->sk_route_caps = dst->dev->features &
 			~(NETIF_F_IP_CSUM | NETIF_F_TSO);
-		tcp_sk(sk)->ext2_header_len = dst->header_len;
 	}
 
 	skb->dst = dst_clone(dst);
@@ -1950,7 +2030,7 @@ static int tcp_v6_init_sock(struct sock 
 	tp->af_specific = &ipv6_specific;
 
 	sk->sk_write_space = sk_stream_write_space;
-	sk->sk_use_write_queue = 1;
+	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
 	sk->sk_sndbuf = sysctl_tcp_wmem[1];
 	sk->sk_rcvbuf = sysctl_tcp_rmem[1];
@@ -2158,7 +2238,7 @@ struct proto tcpv6_prot = {
 	.sysctl_wmem		= sysctl_tcp_wmem,
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
-	.slab_obj_size		= sizeof(struct tcp6_sock),
+	.obj_size		= sizeof(struct tcp6_sock),
 };
 
 static struct inet6_protocol tcpv6_protocol = {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -811,6 +811,8 @@ do_udp_sendmsg:
 			hlimit = np->hop_limit;
 		if (hlimit < 0)
 			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+		if (hlimit < 0)
+			hlimit = ipv6_get_hoplimit(dst->dev);
 	}
 
 	if (msg->msg_flags&MSG_CONFIRM)
@@ -1034,7 +1036,7 @@ void udp6_proc_exit(void) {
 /* ------------------------------------------------------------------------ */
 
 struct proto udpv6_prot = {
-	.name =		"UDP",
+	.name =		"UDPv6",
 	.owner =	THIS_MODULE,
 	.close =	udpv6_close,
 	.connect =	ip6_datagram_connect,
@@ -1049,7 +1051,7 @@ struct proto udpv6_prot = {
 	.hash =		udp_v6_hash,
 	.unhash =	udp_v6_unhash,
 	.get_port =	udp_v6_get_port,
-	.slab_obj_size = sizeof(struct udp6_sock),
+	.obj_size =	sizeof(struct udp6_sock),
 };
 
 extern struct proto_ops inet6_dgram_ops;
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -69,7 +69,7 @@ static void xfrm6_encap(struct sk_buff *
 		dsfield &= ~INET_ECN_MASK;
 	ipv6_change_dsfield(top_iph, 0, dsfield);
 	top_iph->nexthdr = IPPROTO_IPV6; 
-	top_iph->hop_limit = dst_path_metric(dst, RTAX_HOPLIMIT);
+	top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
 	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
 	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
 }
@@ -79,11 +79,12 @@ static int xfrm6_tunnel_check_size(struc
 	int mtu, ret = 0;
 	struct dst_entry *dst = skb->dst;
 
-	mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
+	mtu = dst_mtu(dst);
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
 
 	if (skb->len > mtu) {
+		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
 		ret = -EMSGSIZE;
 	}
@@ -103,20 +104,20 @@ int xfrm6_output(struct sk_buff *skb)
 			goto error_nolock;
 	}
 
-	spin_lock_bh(&x->lock);
-	err = xfrm_state_check(x, skb);
-	if (err)
-		goto error;
-
 	if (x->props.mode) {
 		err = xfrm6_tunnel_check_size(skb);
 		if (err)
-			goto error;
+			goto error_nolock;
 	}
 
+	spin_lock_bh(&x->lock);
+	err = xfrm_state_check(x, skb);
+	if (err)
+		goto error;
+
 	xfrm6_encap(skb);
 
-	err = x->type->output(skb);
+	err = x->type->output(x, skb);
 	if (err)
 		goto error;
 
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -11,7 +11,11 @@
  * 
  */
 
+#include <asm/bug.h>
+#include <linux/compiler.h>
 #include <linux/config.h>
+#include <linux/netdevice.h>
+#include <net/addrconf.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -31,26 +35,6 @@ static int xfrm6_dst_lookup(struct xfrm_
 	return err;
 }
 
-/* Check that the bundle accepts the flow and its components are
- * still valid.
- */
-
-static int __xfrm6_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl)
-{
-	do {
-		if (xdst->u.dst.ops != &xfrm6_dst_ops)
-			return 1;
-
-		if (!xfrm_selector_match(&xdst->u.dst.xfrm->sel, fl, AF_INET6))
-			return 0;
-		if (xdst->u.dst.xfrm->km.state != XFRM_STATE_VALID ||
-		    xdst->u.dst.path->obsolete > 0)
-			return 0;
-		xdst = (struct xfrm_dst*)xdst->u.dst.child;
-	} while (xdst);
-	return 0;
-}
-
 static struct dst_entry *
 __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 {
@@ -70,7 +54,7 @@ __xfrm6_find_bundle(struct flowi *fl, st
 				 xdst->u.rt6.rt6i_src.plen);
 		if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
 		    ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
-		    __xfrm6_bundle_ok(xdst, fl)) {
+		    xfrm_bundle_ok(xdst, fl, AF_INET6)) {
 			dst_clone(dst);
 			break;
 		}
@@ -92,18 +76,30 @@ __xfrm6_bundle_create(struct xfrm_policy
 	struct rt6_info *rt  = rt0;
 	struct in6_addr *remote = &fl->fl6_dst;
 	struct in6_addr *local  = &fl->fl6_src;
+	struct flowi fl_tunnel = {
+		.nl_u = {
+			.ip6_u = {
+				.saddr = *local,
+				.daddr = *remote
+			}
+		}
+	};
 	int i;
 	int err = 0;
 	int header_len = 0;
 	int trailer_len = 0;
 
 	dst = dst_prev = NULL;
+	dst_hold(&rt->u.dst);
 
 	for (i = 0; i < nx; i++) {
 		struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
+		struct xfrm_dst *xdst;
+		int tunnel = 0;
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
+			dst_release(&rt->u.dst);
 			goto error;
 		}
 
@@ -114,32 +110,44 @@ __xfrm6_bundle_create(struct xfrm_policy
 			dst1->flags |= DST_NOHASH;
 			dst_clone(dst1);
 		}
+
+		xdst = (struct xfrm_dst *)dst1;
+		xdst->route = &rt->u.dst;
+		if (rt->rt6i_node)
+			xdst->route_cookie = rt->rt6i_node->fn_sernum;
+
+		dst1->next = dst_prev;
 		dst_prev = dst1;
 		if (xfrm[i]->props.mode) {
 			remote = (struct in6_addr*)&xfrm[i]->id.daddr;
 			local  = (struct in6_addr*)&xfrm[i]->props.saddr;
+			tunnel = 1;
 		}
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
-	}
-
-	if (!ipv6_addr_equal(remote, &fl->fl6_dst)) {
-		struct flowi fl_tunnel;
 
-		memset(&fl_tunnel, 0, sizeof(fl_tunnel));
-		ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
-		ipv6_addr_copy(&fl_tunnel.fl6_src, local);
-
-		err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
-				      &fl_tunnel, AF_INET6);
-		if (err)
-			goto error;
-	} else {
-		dst_hold(&rt->u.dst);
+		if (tunnel) {
+			ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
+			ipv6_addr_copy(&fl_tunnel.fl6_src, local);
+			err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
+					      &fl_tunnel, AF_INET6);
+			if (err)
+				goto error;
+		} else
+			dst_hold(&rt->u.dst);
 	}
+
 	dst_prev->child = &rt->u.dst;
+	dst->path = &rt->u.dst;
+	if (rt->rt6i_node)
+		((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
+
+	*dst_p = dst;
+	dst = dst_prev;
+
+	dst_prev = *dst_p;
 	i = 0;
-	for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
+	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
 
 		dst_prev->xfrm = xfrm[i++];
@@ -151,8 +159,7 @@ __xfrm6_bundle_create(struct xfrm_policy
 		dst_prev->lastuse	= jiffies;
 		dst_prev->header_len	= header_len;
 		dst_prev->trailer_len	= trailer_len;
-		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
-		dst_prev->path		= &rt->u.dst;
+		memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
 
 		/* Copy neighbour for reachability confirmation */
 		dst_prev->neighbour	= neigh_clone(rt->u.dst.neighbour);
@@ -167,10 +174,13 @@ __xfrm6_bundle_create(struct xfrm_policy
 		memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); 
 		x->u.rt6.rt6i_dst      = rt0->rt6i_dst;
 		x->u.rt6.rt6i_src      = rt0->rt6i_src;	
+		x->u.rt6.rt6i_idev     = rt0->rt6i_idev;
+		in6_dev_hold(rt0->rt6i_idev);
 		header_len -= x->u.dst.xfrm->props.header_len;
 		trailer_len -= x->u.dst.xfrm->props.trailer_len;
 	}
-	*dst_p = dst;
+
+	xfrm_init_pmtu(dst);
 	return 0;
 
 error:
@@ -245,12 +255,45 @@ static inline int xfrm6_garbage_collect(
 
 static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
-	struct dst_entry *path = dst->path;
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+	struct dst_entry *path = xdst->route;
+
+	path->ops->update_pmtu(path, mtu);
+}
+
+static void xfrm6_dst_destroy(struct dst_entry *dst)
+{
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+
+	if (likely(xdst->u.rt6.rt6i_idev))
+		in6_dev_put(xdst->u.rt6.rt6i_idev);
+	xfrm_dst_destroy(xdst);
+}
+
+static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+			     int unregister)
+{
+	struct xfrm_dst *xdst;
+
+	if (!unregister)
+		return;
+
+	xdst = (struct xfrm_dst *)dst;
+	if (xdst->u.rt6.rt6i_idev->dev == dev) {
+		struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev);
+		BUG_ON(!loopback_idev);
+
+		do {
+			in6_dev_put(xdst->u.rt6.rt6i_idev);
+			xdst->u.rt6.rt6i_idev = loopback_idev;
+			in6_dev_hold(loopback_idev);
+			xdst = (struct xfrm_dst *)xdst->u.dst.child;
+		} while (xdst->u.dst.xfrm);
+
+		__in6_dev_put(loopback_idev);
+	}
 
-	if (mtu >= IPV6_MIN_MTU && mtu < dst_pmtu(dst))
-		path->ops->update_pmtu(path, mtu);
-	
-	return;
+	xfrm_dst_ifdown(dst, dev);
 }
 
 static struct dst_ops xfrm6_dst_ops = {
@@ -258,6 +301,8 @@ static struct dst_ops xfrm6_dst_ops = {
 	.protocol =		__constant_htons(ETH_P_IPV6),
 	.gc =			xfrm6_garbage_collect,
 	.update_pmtu =		xfrm6_update_pmtu,
+	.destroy =		xfrm6_dst_destroy,
+	.ifdown =		xfrm6_dst_ifdown,
 	.gc_thresh =		1024,
 	.entry_size =		sizeof(struct xfrm_dst),
 };
@@ -278,7 +323,7 @@ static void __init xfrm6_policy_init(voi
 	xfrm_policy_register_afinfo(&xfrm6_policy_afinfo);
 }
 
-static void __exit xfrm6_policy_fini(void)
+static void xfrm6_policy_fini(void)
 {
 	xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
 }
@@ -289,7 +334,7 @@ void __init xfrm6_init(void)
 	xfrm6_state_init();
 }
 
-void __exit xfrm6_fini(void)
+void xfrm6_fini(void)
 {
 	//xfrm6_input_fini();
 	xfrm6_policy_fini();
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -27,9 +27,9 @@ __xfrm6_init_tempsel(struct xfrm_state *
 	 * to current session. */
 	ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
 	ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
-	x->sel.dport = fl->fl_ip_dport;
+	x->sel.dport = xfrm_flowi_dport(fl);
 	x->sel.dport_mask = ~0;
-	x->sel.sport = fl->fl_ip_sport;
+	x->sel.sport = xfrm_flowi_sport(fl);
 	x->sel.sport_mask = ~0;
 	x->sel.prefixlen_d = 128;
 	x->sel.prefixlen_s = 128;
@@ -129,7 +129,7 @@ void __init xfrm6_state_init(void)
 	xfrm_state_register_afinfo(&xfrm6_state_afinfo);
 }
 
-void __exit xfrm6_state_fini(void)
+void xfrm6_state_fini(void)
 {
 	xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
 }
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -343,7 +343,7 @@ void xfrm6_tunnel_free_spi(xfrm_address_
 
 EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
 
-static int xfrm6_tunnel_output(struct sk_buff *skb)
+static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct ipv6hdr *top_iph;
 
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -80,8 +80,6 @@ static struct proto_ops ipx_dgram_ops;
 LIST_HEAD(ipx_interfaces);
 DEFINE_SPINLOCK(ipx_interfaces_lock);
 
-static kmem_cache_t *ipx_sk_slab;
-
 struct ipx_interface *ipx_primary_net;
 struct ipx_interface *ipx_internal_net;
 
@@ -310,7 +308,7 @@ static void __ipxitf_down(struct ipx_int
 		s->sk_error_report(s);
 		ipxs->intrfc = NULL;
 		ipxs->port   = 0;
-		s->sk_zapped = 1;	/* Indicates it is no longer bound */
+		sock_set_flag(s, SOCK_ZAPPED); /* Indicates it is no longer bound */
 		sk_del_node_init(s);
 	}
 	INIT_HLIST_HEAD(&intrfc->if_sklist);
@@ -1347,6 +1345,12 @@ out:
 	return rc;
 }
 
+static struct proto ipx_proto = {
+	.name	  = "IPX",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct ipx_sock),
+};
+
 static int ipx_create(struct socket *sock, int protocol)
 {
 	int rc = -ESOCKTNOSUPPORT;
@@ -1361,8 +1365,8 @@ static int ipx_create(struct socket *soc
 	if (sock->type != SOCK_DGRAM)
 		goto out;
 
-	sk = sk_alloc(PF_IPX, GFP_KERNEL, sizeof(struct ipx_sock), ipx_sk_slab);
        	rc = -ENOMEM;
+	sk = sk_alloc(PF_IPX, GFP_KERNEL, &ipx_proto, 1);
 	if (!sk)
 		goto out;
 #ifdef IPX_REFCNT_DEBUG
@@ -1371,7 +1375,6 @@ static int ipx_create(struct socket *soc
 			atomic_read(&ipx_sock_nr));
 #endif
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 	sk->sk_no_check = 1;		/* Checksum off by default */
 	sock->ops = &ipx_dgram_ops;
 	rc = 0;
@@ -1427,7 +1430,7 @@ static int ipx_bind(struct socket *sock,
 	struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
 	int rc = -EINVAL;
 
-	if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_ipx))
+	if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx))
 		goto out;
 
 	intrfc = ipxitf_find_using_net(addr->sipx_network);
@@ -1505,7 +1508,7 @@ static int ipx_bind(struct socket *sock,
 #endif	/* CONFIG_IPX_INTERN */
 
 	ipxitf_insert_socket(intrfc, sk);
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 
 	rc = 0;
 out_put:
@@ -1774,7 +1777,7 @@ static int ipx_recvmsg(struct kiocb *ioc
 	}
 	
 	rc = -ENOTCONN;
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 
 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
@@ -1954,12 +1957,10 @@ static char ipx_snap_err_msg[] __initdat
 
 static int __init ipx_init(void)
 {
-	ipx_sk_slab = kmem_cache_create("ipx_sock",
-					sizeof(struct ipx_sock), 0,
-					SLAB_HWCACHE_ALIGN, NULL, NULL);
+	int rc = proto_register(&ipx_proto, 1);
 
-	if (ipx_sk_slab == NULL)
-		return -ENOMEM;
+	if (rc != 0)
+		goto out;
 
 	sock_register(&ipx_family_ops);
 
@@ -1986,7 +1987,8 @@ static int __init ipx_init(void)
 	register_netdevice_notifier(&ipx_dev_notifier);
 	ipx_register_sysctl();
 	ipx_proc_init();
-	return 0;
+out:
+	return rc;
 }
 
 static void __exit ipx_proto_finito(void)
@@ -2012,11 +2014,7 @@ static void __exit ipx_proto_finito(void
 	destroy_EII_client(pEII_datalink);
 	pEII_datalink = NULL;
 
-	if (ipx_sk_slab != NULL) {
-		kmem_cache_destroy(ipx_sk_slab);
-		ipx_sk_slab = NULL;
-	}
-
+	proto_unregister(&ipx_proto);
 	sock_unregister(ipx_family_ops.family);
 }
 
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -87,11 +87,9 @@ static int irda_data_indication(void *in
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	self = (struct irda_sock *) instance;
-	ASSERT(self != NULL, return -1;);
-
-	sk = self->sk;
-	ASSERT(sk != NULL, return -1;);
+	self = instance;
+	sk = instance;
+	IRDA_ASSERT(sk != NULL, return -1;);
 
 	err = sock_queue_rcv_skb(sk, skb);
 	if (err) {
@@ -117,7 +115,7 @@ static void irda_disconnect_indication(v
 	struct irda_sock *self;
 	struct sock *sk;
 
-	self = (struct irda_sock *) instance;
+	self = instance;
 
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
@@ -125,7 +123,7 @@ static void irda_disconnect_indication(v
 	if(skb)
 		dev_kfree_skb(skb);
 
-	sk = self->sk;
+	sk = instance;
 	if (sk == NULL) {
 		IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n",
 			   __FUNCTION__, self);
@@ -183,11 +181,11 @@ static void irda_connect_confirm(void *i
 	struct irda_sock *self;
 	struct sock *sk;
 
-	self = (struct irda_sock *) instance;
+	self = instance;
 
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
-	sk = self->sk;
+	sk = instance;
 	if (sk == NULL) {
 		dev_kfree_skb(skb);
 		return;
@@ -206,14 +204,16 @@ static void irda_connect_confirm(void *i
 	switch (sk->sk_type) {
 	case SOCK_STREAM:
 		if (max_sdu_size != 0) {
-			ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__);
+			IRDA_ERROR("%s: max_sdu_size must be 0\n",
+				   __FUNCTION__);
 			return;
 		}
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
 		break;
 	case SOCK_SEQPACKET:
 		if (max_sdu_size == 0) {
-			ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__);
+			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
+				   __FUNCTION__);
 			return;
 		}
 		self->max_data_size = max_sdu_size;
@@ -245,11 +245,11 @@ static void irda_connect_indication(void
 	struct irda_sock *self;
 	struct sock *sk;
 
-	self = (struct irda_sock *) instance;
+	self = instance;
 
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
-	sk = self->sk;
+	sk = instance;
 	if (sk == NULL) {
 		dev_kfree_skb(skb);
 		return;
@@ -265,7 +265,8 @@ static void irda_connect_indication(void
 	switch (sk->sk_type) {
 	case SOCK_STREAM:
 		if (max_sdu_size != 0) {
-			ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__);
+			IRDA_ERROR("%s: max_sdu_size must be 0\n",
+				   __FUNCTION__);
 			kfree_skb(skb);
 			return;
 		}
@@ -273,7 +274,8 @@ static void irda_connect_indication(void
 		break;
 	case SOCK_SEQPACKET:
 		if (max_sdu_size == 0) {
-			ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__);
+			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
+				   __FUNCTION__);
 			kfree_skb(skb);
 			return;
 		}
@@ -304,7 +306,7 @@ static void irda_connect_response(struct
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
@@ -332,11 +334,9 @@ static void irda_flow_indication(void *i
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	self = (struct irda_sock *) instance;
-	ASSERT(self != NULL, return;);
-
-	sk = self->sk;
-	ASSERT(sk != NULL, return;);
+	self = instance;
+	sk = instance;
+	IRDA_ASSERT(sk != NULL, return;);
 
 	switch (flow) {
 	case FLOW_STOP:
@@ -373,7 +373,7 @@ static void irda_getvalue_confirm(int re
 
 	self = (struct irda_sock *) priv;
 	if (!self) {
-		WARNING("%s: lost myself!\n", __FUNCTION__);
+		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
 		return;
 	}
 
@@ -422,7 +422,7 @@ static void irda_selective_discovery_ind
 
 	self = (struct irda_sock *) priv;
 	if (!self) {
-		WARNING("%s: lost myself!\n", __FUNCTION__);
+		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
 		return;
 	}
 
@@ -448,7 +448,7 @@ static void irda_discovery_timeout(u_lon
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	self = (struct irda_sock *) priv;
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	/* Nothing for the caller */
 	self->cachelog = NULL;
@@ -470,7 +470,7 @@ static int irda_open_tsap(struct irda_so
 	notify_t notify;
 
 	if (self->tsap) {
-		WARNING("%s: busy!\n", __FUNCTION__);
+		IRDA_WARNING("%s: busy!\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -510,7 +510,7 @@ static int irda_open_lsap(struct irda_so
 	notify_t notify;
 
 	if (self->lsap) {
-		WARNING("%s(), busy!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), busy!\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -545,10 +545,11 @@ static int irda_find_lsap_sel(struct ird
 {
 	IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	if (self->iriap) {
-		WARNING("%s(): busy with a previous query\n", __FUNCTION__);
+		IRDA_WARNING("%s(): busy with a previous query\n",
+			     __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -633,7 +634,7 @@ static int irda_discover_daddr_and_lsap_
 
 	IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Ask lmp for the current discovery log
 	 * Note : we have to use irlmp_get_discoveries(), as opposed
@@ -782,7 +783,7 @@ static int irda_bind(struct socket *sock
 	struct irda_sock *self = irda_sk(sk);
 	int err;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
@@ -839,7 +840,7 @@ static int irda_accept(struct socket *so
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	err = irda_create(newsock, sk->sk_protocol);
 	if (err)
@@ -908,7 +909,7 @@ static int irda_accept(struct socket *so
 	newsk->sk_state = TCP_ESTABLISHED;
 
 	new = irda_sk(newsk);
-	ASSERT(new != NULL, return -1;);
+	IRDA_ASSERT(new != NULL, return -1;);
 
 	/* Now attach up the new socket */
 	new->tsap = irttp_dup(self->tsap, new);
@@ -1012,11 +1013,23 @@ static int irda_connect(struct socket *s
 		self->daddr = addr->sir_addr;
 		IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr);
 
-		/* Query remote LM-IAS */
-		err = irda_find_lsap_sel(self, addr->sir_name);
-		if (err) {
-			IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
-			return err;
+		/* If we don't have a valid service name, we assume the
+		 * user want to connect on a specific LSAP. Prevent
+		 * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */
+		if((addr->sir_name[0] != '\0') ||
+		   (addr->sir_lsap_sel >= 0x70)) {
+			/* Query remote LM-IAS using service name */
+			err = irda_find_lsap_sel(self, addr->sir_name);
+			if (err) {
+				IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+				return err;
+			}
+		} else {
+			/* Directly connect to the remote LSAP
+			 * specified by the sir_lsap field.
+			 * Please use with caution, in IrDA LSAPs are
+			 * dynamic and there is no "well-known" LSAP. */
+			self->dtsap_sel = addr->sir_lsap_sel;
 		}
 	}
 
@@ -1058,6 +1071,12 @@ static int irda_connect(struct socket *s
 	return 0;
 }
 
+static struct proto irda_proto = {
+	.name	  = "IRDA",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct irda_sock),
+};
+
 /*
  * Function irda_create (sock, protocol)
  *
@@ -1082,28 +1101,19 @@ static int irda_create(struct socket *so
 	}
 
 	/* Allocate networking socket */
-	if ((sk = sk_alloc(PF_IRDA, GFP_ATOMIC, 1, NULL)) == NULL)
+	sk = sk_alloc(PF_IRDA, GFP_ATOMIC, &irda_proto, 1);
+	if (sk == NULL)
 		return -ENOMEM;
 
-	/* Allocate IrDA socket */
-	self = sk->sk_protinfo = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC);
-	if (self == NULL) {
-		sk_free(sk);
-		return -ENOMEM;
-	}
-	memset(self, 0, sizeof(struct irda_sock));
-
+	self = irda_sk(sk);
 	IRDA_DEBUG(2, "%s() : self is %p\n", __FUNCTION__, self);
 
 	init_waitqueue_head(&self->query_wait);
 
 	/* Initialise networking socket struct */
 	sock_init_data(sock, sk);	/* Note : set sk->sk_refcnt to 1 */
-	sk_set_owner(sk, THIS_MODULE);
 	sk->sk_family = PF_IRDA;
 	sk->sk_protocol = protocol;
-	/* Link networking socket and IrDA socket structs together */
-	self->sk = sk;
 
 	switch (sock->type) {
 	case SOCK_STREAM:
@@ -1131,7 +1141,8 @@ static int irda_create(struct socket *so
 			self->max_sdu_size_rx = TTP_SAR_UNBOUND;
 			break;
 		default:
-			ERROR("%s: protocol not supported!\n", __FUNCTION__);
+			IRDA_ERROR("%s: protocol not supported!\n",
+				   __FUNCTION__);
 			return -ESOCKTNOSUPPORT;
 		}
 		break;
@@ -1159,7 +1170,7 @@ static void irda_destroy_socket(struct i
 {
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	/* Unregister with IrLMP */
 	irlmp_unregister_client(self->ckey);
@@ -1187,7 +1198,6 @@ static void irda_destroy_socket(struct i
 		self->lsap = NULL;
 	}
 #endif /* CONFIG_IRDA_ULTRA */
-	kfree(self);
 }
 
 /*
@@ -1208,8 +1218,6 @@ static int irda_release(struct socket *s
 
 	/* Destroy IrDA socket */
 	irda_destroy_socket(irda_sk(sk));
-	/* Prevent sock_def_destruct() to create havoc */
-	sk->sk_protinfo = NULL;
 
 	sock_orphan(sk);
 	sock->sk   = NULL;
@@ -1281,7 +1289,7 @@ static int irda_sendmsg(struct kiocb *io
 		return -ENOTCONN;
 
 	self = irda_sk(sk);
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Check if IrTTP is wants us to slow down */
 
@@ -1344,7 +1352,7 @@ static int irda_recvmsg_dgram(struct kio
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 				flags & MSG_DONTWAIT, &err);
@@ -1396,7 +1404,7 @@ static int irda_recvmsg_stream(struct ki
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	if (sock->flags & __SO_ACCEPTCON)
 		return(-EINVAL);
@@ -1533,7 +1541,7 @@ static int irda_sendmsg_dgram(struct kio
 		return -ENOTCONN;
 
 	self = irda_sk(sk);
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/*
 	 * Check that we don't send out to big frames. This is an unreliable
@@ -1602,7 +1610,7 @@ static int irda_sendmsg_ultra(struct kio
 	}
 
 	self = irda_sk(sk);
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Check if an address was specified with sendto. Jean II */
 	if (msg->msg_name) {
@@ -1675,7 +1683,7 @@ static int irda_shutdown(struct socket *
 	struct sock *sk = sock->sk;
 	struct irda_sock *self = irda_sk(sk);
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self);
 
@@ -1836,7 +1844,7 @@ static int irda_setsockopt(struct socket
 	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int opt;
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
@@ -2021,8 +2029,8 @@ static int irda_setsockopt(struct socket
 				   __FUNCTION__, opt);
 			self->max_sdu_size_rx = opt;
 		} else {
-			WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
+				     __FUNCTION__);
 			return -ENOPROTOOPT;
 		}
 		break;
@@ -2296,8 +2304,8 @@ bed:
 
 		/* Check that we can proceed with IAP */
 		if (self->iriap) {
-			WARNING("%s: busy with a previous query\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: busy with a previous query\n",
+				     __FUNCTION__);
 			kfree(ias_opt);
 			return -EBUSY;
 		}
@@ -2557,9 +2565,12 @@ SOCKOPS_WRAP(irda_ultra, PF_IRDA);
  */
 int __init irsock_init(void)
 {
-	sock_register(&irda_family_ops);
+	int rc = proto_register(&irda_proto, 0);
 
-	return 0;
+	if (rc == 0)
+		rc = sock_register(&irda_family_ops);
+
+	return rc;
 }
 
 /*
@@ -2571,6 +2582,5 @@ int __init irsock_init(void)
 void __exit irsock_cleanup(void)
 {
 	sock_unregister(PF_IRDA);
-
-        return;
+	proto_unregister(&irda_proto);
 }
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -155,7 +155,7 @@ void irlmp_expire_discoveries(hashbin_t 
 	int			n;		/* Size of the full log */
 	int			i = 0;		/* How many we expired */
 
-	ASSERT(log != NULL, return;);
+	IRDA_ASSERT(log != NULL, return;);
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	spin_lock_irqsave(&log->hb_spinlock, flags);
@@ -226,7 +226,7 @@ void irlmp_dump_discoveries(hashbin_t *l
 {
 	discovery_t *discovery;
 
-	ASSERT(log != NULL, return;);
+	IRDA_ASSERT(log != NULL, return;);
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
@@ -270,8 +270,8 @@ struct irda_device_info *irlmp_copy_disc
 	int			n;		/* Size of the full log */
 	int			i = 0;		/* How many we picked */
 
-	ASSERT(pn != NULL, return NULL;);
-	ASSERT(log != NULL, return NULL;);
+	IRDA_ASSERT(pn != NULL, return NULL;);
+	IRDA_ASSERT(log != NULL, return NULL;);
 
 	/* Save spin lock */
 	spin_lock_irqsave(&log->hb_spinlock, flags);
@@ -404,7 +404,7 @@ static struct seq_operations discovery_s
 
 static int discovery_seq_open(struct inode *inode, struct file *file)
 {
-	ASSERT(irlmp != NULL, return -EINVAL;);
+	IRDA_ASSERT(irlmp != NULL, return -EINVAL;);
 
 	return seq_open(file, &discovery_seq_ops);
 }
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -72,7 +72,7 @@ static int __init ircomm_init(void)
 {
 	ircomm = hashbin_new(HB_LOCK); 
 	if (ircomm == NULL) {
-		ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	
@@ -84,7 +84,7 @@ static int __init ircomm_init(void)
 	}
 #endif /* CONFIG_PROC_FS */
 	
-	MESSAGE("IrCOMM protocol (Dag Brattli)\n");
+	IRDA_MESSAGE("IrCOMM protocol (Dag Brattli)\n");
 		
 	return 0;
 }
@@ -114,7 +114,7 @@ struct ircomm_cb *ircomm_open(notify_t *
 	IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __FUNCTION__ ,
 		   service_type);
 
-	ASSERT(ircomm != NULL, return NULL;);
+	IRDA_ASSERT(ircomm != NULL, return NULL;);
 
 	self = kmalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
 	if (self == NULL)
@@ -190,14 +190,14 @@ int ircomm_close(struct ircomm_cb *self)
 {
 	struct ircomm_cb *entry;
 
-	ASSERT(self != NULL, return -EIO;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
+	IRDA_ASSERT(self != NULL, return -EIO;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
 	entry = hashbin_remove(ircomm, self->line, NULL);
 
-	ASSERT(entry == self, return -1;);
+	IRDA_ASSERT(entry == self, return -1;);
 	
         return __ircomm_close(self);
 }
@@ -220,8 +220,8 @@ int ircomm_connect_request(struct ircomm
 
 	IRDA_DEBUG(2 , "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 
 	self->service_type= service_type;
 
@@ -277,8 +277,8 @@ int ircomm_connect_response(struct ircom
 {
 	int ret;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
@@ -322,9 +322,9 @@ int ircomm_data_request(struct ircomm_cb
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -EFAULT;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
-	ASSERT(skb != NULL, return -EFAULT;);
+	IRDA_ASSERT(self != NULL, return -EFAULT;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
+	IRDA_ASSERT(skb != NULL, return -EFAULT;);
 	
 	ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
 
@@ -343,7 +343,7 @@ void ircomm_data_indication(struct ircom
 {	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(skb->len > 0, return;);
+	IRDA_ASSERT(skb->len > 0, return;);
 
 	if (self->notify.data_indication)
 		self->notify.data_indication(self->notify.instance, self, skb);
@@ -362,7 +362,7 @@ void ircomm_process_data(struct ircomm_c
 {
 	int clen;
 
-	ASSERT(skb->len > 0, return;);
+	IRDA_ASSERT(skb->len > 0, return;);
 
 	clen = skb->data[0];
 
@@ -397,9 +397,9 @@ int ircomm_control_request(struct ircomm
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -EFAULT;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
-	ASSERT(skb != NULL, return -EFAULT;);
+	IRDA_ASSERT(self != NULL, return -EFAULT;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
+	IRDA_ASSERT(skb != NULL, return -EFAULT;);
 	
 	ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
 
@@ -455,8 +455,8 @@ int ircomm_disconnect_request(struct irc
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 
 	ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, 
 			      &info);
@@ -476,7 +476,7 @@ void ircomm_disconnect_indication(struct
 {
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
        
-	ASSERT(info != NULL, return;);
+	IRDA_ASSERT(info != NULL, return;);
 
 	if (self->notify.disconnect_indication) {
 		self->notify.disconnect_indication(self->notify.instance, self,
@@ -496,8 +496,8 @@ void ircomm_flow_request(struct ircomm_c
 {
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 
 	if (self->service_type == IRCOMM_3_WIRE_RAW)
 		return;
@@ -541,7 +541,7 @@ static int ircomm_seq_show(struct seq_fi
 { 	
 	const struct ircomm_cb *self = v;
 
-	ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; );
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; );
 
 	if(self->line < 0x10)
 		seq_printf(seq, "ircomm%d", self->line);
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
--- a/net/irda/ircomm/ircomm_lmp.c
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -92,7 +92,8 @@ static int ircomm_lmp_connect_response(s
 		 *  Check that the client has reserved enough space for 
 		 *  headers
 		 */
-		ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, return -1;);
+		IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER,
+			    return -1;);
 
 		/* Don't forget to refcount it - should be NULL anyway */
 		skb_get(userdata);
@@ -144,7 +145,7 @@ static void ircomm_lmp_flow_control(stru
 	struct ircomm_cb *self;
 	int line;
 
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	cb = (struct irda_skb_cb *) skb->cb;
 
@@ -158,8 +159,8 @@ static void ircomm_lmp_flow_control(stru
                 return;
 	}
 
-        ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+        IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 
 	self->pkt_count--;
 
@@ -185,7 +186,7 @@ static int ircomm_lmp_data_request(struc
 	struct irda_skb_cb *cb;
 	int ret;
 
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	cb = (struct irda_skb_cb *) skb->cb;
 	
@@ -207,7 +208,7 @@ static int ircomm_lmp_data_request(struc
         }
 	ret = irlmp_data_request(self->lsap, skb);
 	if (ret) {
-		ERROR("%s(), failed\n", __FUNCTION__);
+		IRDA_ERROR("%s(), failed\n", __FUNCTION__);
 		/* irlmp_data_request already free the packet */
 	}
 
@@ -227,9 +228,9 @@ static int ircomm_lmp_data_indication(vo
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 	
 	ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
 
@@ -257,10 +258,10 @@ static void ircomm_lmp_connect_confirm(v
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(qos != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(qos != NULL, return;);
 
 	info.max_data_size = max_seg_size;
 	info.max_header_size = max_header_size;
@@ -290,10 +291,10 @@ static void ircomm_lmp_connect_indicatio
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(qos != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(qos != NULL, return;);
 
 	info.max_data_size = max_seg_size;
 	info.max_header_size = max_header_size;
@@ -320,8 +321,8 @@ static void ircomm_lmp_disconnect_indica
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 
 	info.reason = reason;
 
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -106,8 +106,8 @@ int ircomm_param_request(struct ircomm_t
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	tty = self->tty;
 	if (!tty)
@@ -137,7 +137,7 @@ int ircomm_param_request(struct ircomm_t
 	count = irda_param_insert(self, pi, skb->tail, skb_tailroom(skb),
 				  &ircomm_param_info);
 	if (count < 0) {
-		WARNING("%s(), no room for parameter!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
 		spin_unlock_irqrestore(&self->spinlock, flags);
 		return -1;
 	}
@@ -168,8 +168,8 @@ static int ircomm_param_service_type(voi
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	__u8 service_type = (__u8) param->pv.i;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get) {
 		param->pv.i = self->settings.service_type;
@@ -233,8 +233,8 @@ static int ircomm_param_port_type(void *
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = IRCOMM_SERIAL;
@@ -257,8 +257,8 @@ static int ircomm_param_port_name(void *
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get) {
 		IRDA_DEBUG(0, "%s(), not imp!\n", __FUNCTION__ );
@@ -280,8 +280,8 @@ static int ircomm_param_data_rate(void *
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get)
 		param->pv.i = self->settings.data_rate;
@@ -304,8 +304,8 @@ static int ircomm_param_data_format(void
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get)
 		param->pv.i = self->settings.data_format;
@@ -326,8 +326,8 @@ static int ircomm_param_flow_control(voi
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->settings.flow_control;
@@ -349,8 +349,8 @@ static int ircomm_param_xon_xoff(void *i
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	
 	if (get) {
 		param->pv.i = self->settings.xonxoff[0];
@@ -376,8 +376,8 @@ static int ircomm_param_enq_ack(void *in
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	
 	if (get) {
 		param->pv.i = self->settings.enqack[0];
@@ -418,8 +418,8 @@ static int ircomm_param_dte(void *instan
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	__u8 dte;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get)
 		param->pv.i = self->settings.dte;
@@ -467,8 +467,8 @@ static int ircomm_param_dce(void *instan
 
 	dce = (__u8) param->pv.i;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	self->settings.dce = dce;
 
@@ -494,8 +494,8 @@ static int ircomm_param_poll(void *insta
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Poll parameters are always of lenght 0 (just a signal) */
 	if (!get) {
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c
--- a/net/irda/ircomm/ircomm_ttp.c
+++ b/net/irda/ircomm/ircomm_ttp.c
@@ -172,7 +172,7 @@ static int ircomm_ttp_data_request(struc
 {
 	int ret;
 
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen);
 
@@ -180,7 +180,7 @@ static int ircomm_ttp_data_request(struc
 	 * Insert clen field, currently we either send data only, or control
 	 * only frames, to make things easier and avoid queueing
 	 */
-	ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
+	IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
 
 	/* Don't forget to refcount it - see ircomm_tty_do_softint() */
 	skb_get(skb);
@@ -191,7 +191,7 @@ static int ircomm_ttp_data_request(struc
 
 	ret = irttp_data_request(self->tsap, skb);
 	if (ret) {
-		ERROR("%s(), failed\n", __FUNCTION__);
+		IRDA_ERROR("%s(), failed\n", __FUNCTION__);
 		/* irttp_data_request already free the packet */
 	}
 
@@ -211,9 +211,9 @@ static int ircomm_ttp_data_indication(vo
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
 
@@ -234,13 +234,14 @@ static void ircomm_ttp_connect_confirm(v
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(qos != NULL, goto out;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(qos != NULL, goto out;);
 
 	if (max_sdu_size != TTP_SAR_DISABLE) {
-		ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
+			   __FUNCTION__);
 		goto out;
 	}
 
@@ -274,13 +275,14 @@ static void ircomm_ttp_connect_indicatio
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(qos != NULL, goto out;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(qos != NULL, goto out;);
 
 	if (max_sdu_size != TTP_SAR_DISABLE) {
-		ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
+			   __FUNCTION__);
 		goto out;
 	}
 
@@ -332,8 +334,8 @@ static void ircomm_ttp_disconnect_indica
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 
 	info.reason = reason;
 
@@ -357,8 +359,8 @@ static void ircomm_ttp_flow_indication(v
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 	
 	if (self->notify.flow_indication)
 		self->notify.flow_indication(self->notify.instance, self, cmd);
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -116,7 +116,7 @@ static int __init ircomm_tty_init(void)
 		return -ENOMEM;
 	ircomm_tty = hashbin_new(HB_LOCK); 
 	if (ircomm_tty == NULL) {
-		ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
 		put_tty_driver(driver);
 		return -ENOMEM;
 	}
@@ -134,7 +134,8 @@ static int __init ircomm_tty_init(void)
 	driver->flags           = TTY_DRIVER_REAL_RAW;
 	tty_set_operations(driver, &ops);
 	if (tty_register_driver(driver)) {
-		ERROR("%s(): Couldn't register serial driver\n", __FUNCTION__);
+		IRDA_ERROR("%s(): Couldn't register serial driver\n",
+			   __FUNCTION__);
 		put_tty_driver(driver);
 		return -1;
 	}
@@ -145,8 +146,8 @@ static void __exit __ircomm_tty_cleanup(
 {
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	ircomm_tty_shutdown(self);
 
@@ -168,7 +169,8 @@ static void __exit ircomm_tty_cleanup(vo
 
 	ret = tty_unregister_driver(driver);
         if (ret) {
-                ERROR("%s(), failed to unregister driver\n", __FUNCTION__);
+                IRDA_ERROR("%s(), failed to unregister driver\n",
+			   __FUNCTION__);
 		return;
 	}
 
@@ -189,8 +191,8 @@ static int ircomm_tty_startup(struct irc
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Check if already open */
 	if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
@@ -224,7 +226,7 @@ static int ircomm_tty_startup(struct irc
 	/* Connect IrCOMM link with remote device */
 	ret = ircomm_tty_attach_cable(self);
 	if (ret < 0) {
-		ERROR("%s(), error attaching cable!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), error attaching cable!\n", __FUNCTION__);
 		goto err;
 	}
 
@@ -381,7 +383,7 @@ static int ircomm_tty_open(struct tty_st
 		/* No, so make new instance */
 		self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
 		if (self == NULL) {
-			ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
+			IRDA_ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
 			return -ENOMEM;
 		}
 		memset(self, 0, sizeof(struct ircomm_tty_cb));
@@ -442,8 +444,8 @@ static int ircomm_tty_open(struct tty_st
 		 */
 
 		if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
-			WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
-				__FUNCTION__);
+			IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
+				     __FUNCTION__);
 			return -ERESTARTSYS;
 		}
 
@@ -499,8 +501,8 @@ static void ircomm_tty_close(struct tty_
 	if (!tty)
 		return;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	spin_lock_irqsave(&self->spinlock, flags);
 
@@ -526,8 +528,8 @@ static void ircomm_tty_close(struct tty_
 	}
 
 	if (--self->open_count < 0) {
-		ERROR("%s(), bad serial port count for ttys%d: %d\n",
-		      __FUNCTION__, self->line, self->open_count);
+		IRDA_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) {
@@ -586,8 +588,8 @@ static void ircomm_tty_flush_buffer(stru
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	/* 
 	 * Let do_softint() do this to avoid race condition with 
@@ -671,10 +673,9 @@ static void ircomm_tty_do_softint(void *
  *    accepted for writing. This routine is mandatory.
  */
 static int ircomm_tty_write(struct tty_struct *tty,
-			    const unsigned char *ubuf, int count)
+			    const unsigned char *buf, int count)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-	unsigned char *kbuf;		/* Buffer in kernel space */
 	unsigned long flags;
 	struct sk_buff *skb;
 	int tailroom = 0;
@@ -684,8 +685,8 @@ static int ircomm_tty_write(struct tty_s
 	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;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* We may receive packets from the TTY even before we have finished
 	 * our setup. Not cool.
@@ -714,9 +715,6 @@ static int ircomm_tty_write(struct tty_s
 	if (count < 1)
 		return 0;
 
-	/* The buffer is already in kernel space */
-	kbuf = (unsigned char *) ubuf;
-
 	/* Protect our manipulation of self->tx_skb and related */
 	spin_lock_irqsave(&self->spinlock, flags);
 
@@ -779,7 +777,7 @@ static int ircomm_tty_write(struct tty_s
 		}
 
 		/* Copy data */
-		memcpy(skb_put(skb,size), kbuf + len, size);
+		memcpy(skb_put(skb,size), buf + len, size);
 
 		count -= size;
 		len += size;
@@ -812,8 +810,8 @@ static int ircomm_tty_write_room(struct 
 	unsigned long flags;
 	int ret;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 #ifdef IRCOMM_NO_TX_BEFORE_INIT
 	/* max_header_size tells us if the channel is initialised or not. */
@@ -854,8 +852,8 @@ static void ircomm_tty_wait_until_sent(s
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	orig_jiffies = jiffies;
 
@@ -890,8 +888,8 @@ static void ircomm_tty_throttle(struct t
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	/* Software flow control? */
 	if (I_IXOFF(tty))
@@ -921,8 +919,8 @@ static void ircomm_tty_unthrottle(struct
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	/* Using software flow control? */
 	if (I_IXOFF(tty)) {
@@ -951,8 +949,8 @@ static int ircomm_tty_chars_in_buffer(st
 	unsigned long flags;
 	int len = 0;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	spin_lock_irqsave(&self->spinlock, flags);
 
@@ -968,8 +966,8 @@ static void ircomm_tty_shutdown(struct i
 {
 	unsigned long flags;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
@@ -1016,8 +1014,8 @@ static void ircomm_tty_hangup(struct tty
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	if (!tty)
 		return;
@@ -1069,8 +1067,8 @@ static void ircomm_tty_stop(struct tty_s
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	ircomm_flow_request(self->ircomm, FLOW_STOP);
 }
@@ -1089,8 +1087,8 @@ void ircomm_tty_check_modem_status(struc
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	tty = self->tty;
 
@@ -1152,9 +1150,9 @@ static int ircomm_tty_data_indication(vo
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	if (!self->tty) {
 		IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
@@ -1202,9 +1200,9 @@ static int ircomm_tty_control_indication
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	clen = skb->data[0];
 
@@ -1229,8 +1227,8 @@ static void ircomm_tty_flow_indication(v
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	struct tty_struct *tty;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	tty = self->tty;
 
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -132,8 +132,8 @@ int ircomm_tty_attach_cable(struct ircom
 {
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
        	/* Check if somebody has already connected to us */
 	if (ircomm_is_connected(self->ircomm)) {
@@ -161,8 +161,8 @@ void ircomm_tty_detach_cable(struct irco
 {
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	del_timer(&self->watchdog_timer);
 
@@ -210,8 +210,8 @@ static void ircomm_tty_ias_register(stru
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 	
 	/* Compute hint bits based on service */
 	hints = irlmp_service_to_hint(S_COMM);
@@ -299,8 +299,8 @@ static void ircomm_tty_ias_unregister(st
  */
 int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (self->service_type & IRCOMM_3_WIRE_RAW) 
 		return 0;
@@ -387,7 +387,7 @@ static void ircomm_tty_discovery_indicat
 	 * need to ensure that "line" is unique. - Jean II */
 	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
 	while (self != NULL) {
-		ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+		IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 		
 		ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, 
 				    NULL, &info);
@@ -410,8 +410,8 @@ void ircomm_tty_disconnect_indication(vo
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	if (!self->tty)
 		return;
@@ -440,8 +440,8 @@ static void ircomm_tty_getvalue_confirm(
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	/* We probably don't need to make any more queries */
 	iriap_close(self->iriap);
@@ -501,8 +501,8 @@ void ircomm_tty_connect_confirm(void *in
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	self->client = TRUE;
 	self->max_data_size = max_data_size;
@@ -532,8 +532,8 @@ void ircomm_tty_connect_indication(void 
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	self->client = FALSE;
 	self->max_data_size = max_data_size;
@@ -561,8 +561,8 @@ void ircomm_tty_link_established(struct 
 {
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	if (!self->tty)
 		return;
@@ -600,8 +600,8 @@ void ircomm_tty_link_established(struct 
 static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
 					    int timeout)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
 			 ircomm_tty_watchdog_timer_expired);
@@ -619,8 +619,8 @@ static void ircomm_tty_watchdog_timer_ex
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
 }
@@ -635,8 +635,8 @@ static void ircomm_tty_watchdog_timer_ex
 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
 			struct sk_buff *skb, struct ircomm_tty_info *info) 
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
@@ -653,8 +653,8 @@ int ircomm_tty_do_event(struct ircomm_tt
 static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
 {
 	/*
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
 	IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
 		   ircomm_tty_state[self->state], self->service_type);
@@ -690,7 +690,8 @@ static int ircomm_tty_state_idle(struct 
 		self->saddr = info->saddr;
 
 		if (self->iriap) {
-			WARNING("%s(), busy with a previous query\n", __FUNCTION__);
+			IRDA_WARNING("%s(), busy with a previous query\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 
@@ -747,7 +748,8 @@ static int ircomm_tty_state_search(struc
 		self->saddr = info->saddr;
 
 		if (self->iriap) {
-			WARNING("%s(), busy with a previous query\n", __FUNCTION__);
+			IRDA_WARNING("%s(), busy with a previous query\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 		
@@ -816,7 +818,8 @@ static int ircomm_tty_state_query_parame
 	switch (event) {
 	case IRCOMM_TTY_GOT_PARAMETERS:
 		if (self->iriap) {
-			WARNING("%s(), busy with a previous query\n", __FUNCTION__);
+			IRDA_WARNING("%s(), busy with a previous query\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 		
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -95,7 +95,7 @@ static void ircomm_tty_change_speed(stru
 		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
 		/* This got me. Bummer. Jean II */
 		if (self->service_type == IRCOMM_3_WIRE_RAW)
-			WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
+			IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
 	} else {
 		self->flags &= ~ASYNC_CTS_FLOW;
 		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
@@ -230,8 +230,8 @@ int ircomm_tty_tiocmset(struct tty_struc
 	if (tty->flags & (1 << TTY_IO_ERROR))
 		return -EIO;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (set & TIOCM_RTS)
 		self->settings.dte |= IRCOMM_RTS;
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -77,14 +77,14 @@ int __init irda_device_init( void)
 {
 	dongles = hashbin_new(HB_NOLOCK);
 	if (dongles == NULL) {
-		printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n");
+		IRDA_WARNING("IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 	spin_lock_init(&dongles->hb_spinlock);
 
 	tasks = hashbin_new(HB_LOCK);
 	if (tasks == NULL) {
-		printk(KERN_WARNING "IrDA: Can't allocate tasks hashbin!\n");
+		IRDA_WARNING("IrDA: Can't allocate tasks hashbin!\n");
 		hashbin_delete(dongles, NULL);
 		return -ENOMEM;
 	}
@@ -98,8 +98,8 @@ int __init irda_device_init( void)
 static void __exit leftover_dongle(void *arg)
 {
 	struct dongle_reg *reg = arg;
-	printk(KERN_WARNING "IrDA: Dongle type %x not unregistered\n",
-	       reg->type);
+	IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
+		     reg->type);
 }
 
 void __exit irda_device_cleanup(void)
@@ -125,8 +125,15 @@ void irda_device_set_media_busy(struct n
 
 	self = (struct irlap_cb *) dev->atalk_ptr;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	/* Some drivers may enable the receive interrupt before calling
+	 * irlap_open(), or they may disable the receive interrupt
+	 * after calling irlap_close().
+	 * The IrDA stack is protected from this in irlap_driver_rcv().
+	 * However, the driver calls directly the wrapper, that calls
+	 * us directly. Make sure we protect ourselves.
+	 * Jean II */
+	if (!self || self->magic != LAP_MAGIC)
+		return;
 
 	if (status) {
 		self->media_busy = TRUE;
@@ -157,8 +164,8 @@ int irda_device_is_receiving(struct net_
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	if (!dev->do_ioctl) {
-		ERROR("%s: do_ioctl not impl. by device driver\n",
-				__FUNCTION__);
+		IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
+			   __FUNCTION__);
 		return -1;
 	}
 
@@ -209,21 +216,22 @@ static int irda_task_kick(struct irda_ta
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(task != NULL, return -1;);
-	ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
+	IRDA_ASSERT(task != NULL, return -1;);
+	IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
 
 	/* Execute task until it's finished, or askes for a timeout */
 	do {
 		timeout = task->function(task);
 		if (count++ > 100) {
-			ERROR("%s: error in task handler!\n", __FUNCTION__);
+			IRDA_ERROR("%s: error in task handler!\n",
+				   __FUNCTION__);
 			irda_task_delete(task);
 			return TRUE;
 		}
 	} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
 
 	if (timeout < 0) {
-		ERROR("%s: Error executing task!\n", __FUNCTION__);
+		IRDA_ERROR("%s: Error executing task!\n", __FUNCTION__);
 		irda_task_delete(task);
 		return TRUE;
 	}
@@ -387,7 +395,8 @@ dongle_t *irda_device_dongle_init(struct
 #endif
 
 	if (!reg || !try_module_get(reg->owner) ) {
-		ERROR("IrDA: Unable to find requested dongle type %x\n", type);
+		IRDA_ERROR("IrDA: Unable to find requested dongle type %x\n",
+			   type);
 		goto out;
 	}
 
@@ -413,7 +422,7 @@ EXPORT_SYMBOL(irda_device_dongle_init);
  */
 int irda_device_dongle_cleanup(dongle_t *dongle)
 {
-	ASSERT(dongle != NULL, return -1;);
+	IRDA_ASSERT(dongle != NULL, return -1;);
 
 	dongle->issue->close(dongle);
 	module_put(dongle->issue->owner);
@@ -431,8 +440,8 @@ int irda_device_register_dongle(struct d
 	spin_lock(&dongles->hb_spinlock);
 	/* Check if this dongle has been registered before */
 	if (hashbin_find(dongles, new->type, NULL)) {
-		MESSAGE("%s: Dongle type %x already registered\n", 
-			__FUNCTION__, new->type);
+		IRDA_MESSAGE("%s: Dongle type %x already registered\n", 
+			     __FUNCTION__, new->type);
         } else {
 		/* Insert IrDA dongle into hashbin */
 		hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
@@ -456,16 +465,16 @@ void irda_device_unregister_dongle(struc
 	spin_lock(&dongles->hb_spinlock);
 	node = hashbin_remove(dongles, dongle->type, NULL);
 	if (!node) 
-		ERROR("%s: dongle not found!\n", __FUNCTION__);
+		IRDA_ERROR("%s: dongle not found!\n", __FUNCTION__);
 	spin_unlock(&dongles->hb_spinlock);
 }
 EXPORT_SYMBOL(irda_device_unregister_dongle);
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_ISA_DMA_API
 /*
  * Function setup_dma (idev, buffer, count, mode)
  *
- *    Setup the DMA channel. Commonly used by ISA FIR drivers
+ *    Setup the DMA channel. Commonly used by LPC FIR drivers
  *
  */
 void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode)
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -107,8 +107,8 @@ int __init iriap_init(void)
 	/* Object repository - defined in irias_object.c */
 	irias_objects = hashbin_new(HB_LOCK);
 	if (!irias_objects) {
-		WARNING("%s: Can't allocate irias_objects hashbin!\n",
-			__FUNCTION__);
+		IRDA_WARNING("%s: Can't allocate irias_objects hashbin!\n",
+			     __FUNCTION__);
 		hashbin_delete(iriap, NULL);
 		return -ENOMEM;
 	}
@@ -175,7 +175,7 @@ struct iriap_cb *iriap_open(__u8 slsap_s
 
 	self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
 	if (!self) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -220,8 +220,8 @@ static void __iriap_close(struct iriap_c
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	del_timer(&self->watchdog_timer);
 
@@ -244,8 +244,8 @@ void iriap_close(struct iriap_cb *self)
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	if (self->lsap) {
 		irlmp_close_lsap(self->lsap);
@@ -253,7 +253,7 @@ void iriap_close(struct iriap_cb *self)
 	}
 
 	entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL);
-	ASSERT(entry == self, return;);
+	IRDA_ASSERT(entry == self, return;);
 
 	__iriap_close(self);
 }
@@ -278,7 +278,7 @@ static int iriap_register_lsap(struct ir
 
 	self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
 	if (self->lsap == NULL) {
-		ERROR("%s: Unable to allocated LSAP!\n", __FUNCTION__);
+		IRDA_ERROR("%s: Unable to allocated LSAP!\n", __FUNCTION__);
 		return -1;
 	}
 	self->slsap_sel = self->lsap->slsap_sel;
@@ -302,10 +302,10 @@ static void iriap_disconnect_indication(
 
 	self = (struct iriap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
-	ASSERT(iriap != NULL, return;);
+	IRDA_ASSERT(iriap != NULL, return;);
 
 	del_timer(&self->watchdog_timer);
 
@@ -343,8 +343,8 @@ static void iriap_disconnect_request(str
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	tx_skb = dev_alloc_skb(64);
 	if (tx_skb == NULL) {
@@ -375,8 +375,8 @@ int iriap_getvaluebyclass_request(struct
 	int name_len, attr_len, skb_len;
 	__u8 *frame;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IAS_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;);
 
 	/* Client must supply the destination device address */
 	if (!daddr)
@@ -442,9 +442,9 @@ static void iriap_getvaluebyclass_confir
 	__u8 *fp;
 	int n;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Initialize variables */
 	fp = skb->data;
@@ -549,10 +549,10 @@ static void iriap_getvaluebyclass_respon
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
-	ASSERT(value != NULL, return;);
-	ASSERT(value->len <= 1024, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(value != NULL, return;);
+	IRDA_ASSERT(value->len <= 1024, return;);
 
 	/* Initialize variables */
 	n = 0;
@@ -642,9 +642,9 @@ static void iriap_getvaluebyclass_indica
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	fp = skb->data;
 	n = 1;
@@ -697,8 +697,8 @@ void iriap_send_ack(struct iriap_cb *sel
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -719,8 +719,8 @@ void iriap_connect_request(struct iriap_
 {
 	int ret;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	ret = irlmp_connect_request(self->lsap, LSAP_IAS,
 				    self->saddr, self->daddr,
@@ -746,9 +746,9 @@ static void iriap_connect_confirm(void *
 
 	self = (struct iriap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	self->max_data_size = max_seg_size;
 	self->max_header_size = max_header_size;
@@ -778,9 +778,9 @@ static void iriap_connect_indication(voi
 
 	self = (struct iriap_cb *) instance;
 
-	ASSERT(skb != NULL, return;);
-	ASSERT(self != NULL, goto out;);
-	ASSERT(self->magic == IAS_MAGIC, goto out;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, goto out;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
 
 	/* Start new server */
 	new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
@@ -826,9 +826,9 @@ static int iriap_data_indication(void *i
 
 	self = (struct iriap_cb *) instance;
 
-	ASSERT(skb != NULL, return 0;);
-	ASSERT(self != NULL, goto out;);
-	ASSERT(self->magic == IAS_MAGIC, goto out;);
+	IRDA_ASSERT(skb != NULL, return 0;);
+	IRDA_ASSERT(self != NULL, goto out;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
 
 	frame = skb->data;
 
@@ -840,8 +840,9 @@ static int iriap_data_indication(void *i
 	}
 	opcode = frame[0];
 	if (~opcode & IAP_LST) {
-		WARNING("%s:, IrIAS multiframe commands or "
-			"results is not implemented yet!\n", __FUNCTION__);
+		IRDA_WARNING("%s:, IrIAS multiframe commands or "
+			     "results is not implemented yet!\n",
+			     __FUNCTION__);
 		goto out;
 	}
 
@@ -917,24 +918,24 @@ void iriap_call_indication(struct iriap_
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	fp = skb->data;
 
 	opcode = fp[0];
 	if (~opcode & 0x80) {
-		WARNING("%s: IrIAS multiframe commands or results"
-			"is not implemented yet!\n", __FUNCTION__);
+		IRDA_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("%s: GetInfoBaseDetails not implemented yet!\n",
-				__FUNCTION__);
+		IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n",
+			     __FUNCTION__);
 		break;
 	case GET_VALUE_BY_CLASS:
 		iriap_getvaluebyclass_indication(self, skb);
@@ -953,8 +954,8 @@ static void iriap_watchdog_timer_expired
 {
 	struct iriap_cb *self = (struct iriap_cb *) data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	/* iriap_close(self); */
 }
@@ -1010,7 +1011,7 @@ static int irias_seq_show(struct seq_fil
 		struct ias_object *obj = v;
 		struct ias_attrib *attrib;
 
-		ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;);
+		IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;);
 
 		seq_printf(seq, "name: %s, id=%d\n",
 			   obj->name, obj->id);
@@ -1025,7 +1026,8 @@ static int irias_seq_show(struct seq_fil
 		     attrib != NULL;
 		     attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) {
 		     
-			ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, break; );
+			IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC,
+				    goto outloop; );
 
 			seq_printf(seq, " - Attribute name: \"%s\", ",
 				   attrib->name);
@@ -1055,6 +1057,7 @@ static int irias_seq_show(struct seq_fil
 			seq_putc(seq, '\n');
 
 		}
+	IRDA_ASSERT_LABEL(outloop:)
 		spin_unlock(&obj->attribs->hb_spinlock);
 	}
 
@@ -1070,7 +1073,7 @@ static struct seq_operations irias_seq_o
 
 static int irias_seq_open(struct inode *inode, struct file *file)
 {
-	ASSERT( irias_objects != NULL, return -EINVAL;);
+	IRDA_ASSERT( irias_objects != NULL, return -EINVAL;);
 
 	return seq_open(file, &irias_seq_ops);
 }
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -93,32 +93,32 @@ static void (*iriap_state[])(struct iria
 
 void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	self->client_state = state;
 }
 
 void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	self->call_state = state;
 }
 
 void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	self->server_state = state;
 }
 
 void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	self->r_connect_state = state;
 }
@@ -126,8 +126,8 @@ void iriap_next_r_connect_state(struct i
 void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event,
 			   struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	(*iriap_state[ self->client_state]) (self, event, skb);
 }
@@ -135,8 +135,8 @@ void iriap_do_client_event(struct iriap_
 void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event,
 			 struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	(*iriap_state[ self->call_state]) (self, event, skb);
 }
@@ -144,8 +144,8 @@ void iriap_do_call_event(struct iriap_cb
 void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event,
 			   struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	(*iriap_state[ self->server_state]) (self, event, skb);
 }
@@ -153,8 +153,8 @@ void iriap_do_server_event(struct iriap_
 void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event,
 			      struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	(*iriap_state[ self->r_connect_state]) (self, event, skb);
 }
@@ -169,13 +169,13 @@ void iriap_do_r_connect_event(struct iri
 static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
 			       struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	switch (event) {
 	case IAP_CALL_REQUEST_GVBC:
 		iriap_next_client_state(self, S_CONNECTING);
-		ASSERT(self->request_skb == NULL, return;);
+		IRDA_ASSERT(self->request_skb == NULL, return;);
 		/* Don't forget to refcount it -
 		 * see iriap_getvaluebyclass_request(). */
 		skb_get(skb);
@@ -199,8 +199,8 @@ static void state_s_disconnect(struct ir
 static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event,
 			       struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	switch (event) {
 	case IAP_LM_CONNECT_CONFIRM:
@@ -232,7 +232,7 @@ static void state_s_connecting(struct ir
 static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event,
 			 struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	switch (event) {
 	case IAP_LM_DISCONNECT_INDICATION:
@@ -257,7 +257,7 @@ static void state_s_make_call(struct iri
 {
 	struct sk_buff *tx_skb;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	switch (event) {
 	case IAP_CALL_REQUEST:
@@ -295,7 +295,7 @@ static void state_s_calling(struct iriap
 static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
 				struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	switch (event) {
 	case IAP_RECV_F_LST:
@@ -367,7 +367,7 @@ static void state_r_disconnect(struct ir
 	case IAP_LM_CONNECT_INDICATION:
 		tx_skb = dev_alloc_skb(64);
 		if (tx_skb == NULL) {
-			WARNING("%s: unable to malloc!\n", __FUNCTION__);
+			IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
 			return;
 		}
 
@@ -464,9 +464,9 @@ static void state_r_execute(struct iriap
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(skb != NULL, return;);
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IAS_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 
 	switch (event) {
 	case IAP_CALL_RESPONSE:
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -59,7 +59,7 @@ static char *strndup(char *str, int max)
 	/* Allocate new string */
         new_str = kmalloc(len + 1, GFP_ATOMIC);
         if (new_str == NULL) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -85,8 +85,8 @@ struct ias_object *irias_new_object( cha
 	obj = (struct ias_object *) kmalloc(sizeof(struct ias_object),
 					    GFP_ATOMIC);
 	if (obj == NULL) {
-		WARNING("%s(), Unable to allocate object!\n",
-			__FUNCTION__);
+		IRDA_WARNING("%s(), Unable to allocate object!\n",
+			     __FUNCTION__);
 		return NULL;
 	}
 	memset(obj, 0, sizeof( struct ias_object));
@@ -101,7 +101,8 @@ struct ias_object *irias_new_object( cha
 	obj->attribs = hashbin_new(HB_LOCK);
 
 	if (obj->attribs == NULL) {
-		WARNING("%s(), Unable to allocate attribs!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), Unable to allocate attribs!\n",
+			     __FUNCTION__);
 		kfree(obj);
 		return NULL;
 	}
@@ -118,8 +119,8 @@ EXPORT_SYMBOL(irias_new_object);
  */
 static void __irias_delete_attrib(struct ias_attrib *attrib)
 {
-	ASSERT(attrib != NULL, return;);
-	ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
+	IRDA_ASSERT(attrib != NULL, return;);
+	IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
 	if (attrib->name)
 		kfree(attrib->name);
@@ -132,8 +133,8 @@ static void __irias_delete_attrib(struct
 
 void __irias_delete_object(struct ias_object *obj)
 {
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
 	if (obj->name)
 		kfree(obj->name);
@@ -156,8 +157,8 @@ int irias_delete_object(struct ias_objec
 {
 	struct ias_object *node;
 
-	ASSERT(obj != NULL, return -1;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
+	IRDA_ASSERT(obj != NULL, return -1;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
 
 	/* Remove from list */
 	node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
@@ -184,9 +185,9 @@ int irias_delete_attrib(struct ias_objec
 {
 	struct ias_attrib *node;
 
-	ASSERT(obj != NULL, return -1;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
-	ASSERT(attrib != NULL, return -1;);
+	IRDA_ASSERT(obj != NULL, return -1;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
+	IRDA_ASSERT(attrib != NULL, return -1;);
 
 	/* Remove attribute from object */
 	node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib);
@@ -216,8 +217,8 @@ int irias_delete_attrib(struct ias_objec
  */
 void irias_insert_object(struct ias_object *obj)
 {
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
 	hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name);
 }
@@ -231,7 +232,7 @@ EXPORT_SYMBOL(irias_insert_object);
  */
 struct ias_object *irias_find_object(char *name)
 {
-	ASSERT(name != NULL, return NULL;);
+	IRDA_ASSERT(name != NULL, return NULL;);
 
 	/* Unsafe (locking), object might change */
 	return hashbin_lock_find(irias_objects, 0, name);
@@ -248,9 +249,9 @@ struct ias_attrib *irias_find_attrib(str
 {
 	struct ias_attrib *attrib;
 
-	ASSERT(obj != NULL, return NULL;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;);
-	ASSERT(name != NULL, return NULL;);
+	IRDA_ASSERT(obj != NULL, return NULL;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;);
+	IRDA_ASSERT(name != NULL, return NULL;);
 
 	attrib = hashbin_lock_find(obj->attribs, 0, name);
 	if (attrib == NULL)
@@ -270,11 +271,11 @@ EXPORT_SYMBOL(irias_find_attrib);
 static void irias_add_attrib(struct ias_object *obj, struct ias_attrib *attrib,
 			     int owner)
 {
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-	ASSERT(attrib != NULL, return;);
-	ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
+	IRDA_ASSERT(attrib != NULL, return;);
+	IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
 	/* Set if attrib is owned by kernel or user space */
 	attrib->value->owner = owner;
@@ -298,8 +299,8 @@ int irias_object_change_attribute(char *
 	/* Find object */
 	obj = hashbin_lock_find(irias_objects, 0, obj_name);
 	if (obj == NULL) {
-		WARNING("%s: Unable to find object: %s\n", __FUNCTION__,
-			obj_name);
+		IRDA_WARNING("%s: Unable to find object: %s\n", __FUNCTION__,
+			     obj_name);
 		return -1;
 	}
 
@@ -309,8 +310,8 @@ int irias_object_change_attribute(char *
 	/* Find attribute */
 	attrib = hashbin_find(obj->attribs, 0, attrib_name);
 	if (attrib == NULL) {
-		WARNING("%s: Unable to find attribute: %s\n", __FUNCTION__,
-			attrib_name);
+		IRDA_WARNING("%s: Unable to find attribute: %s\n",
+			     __FUNCTION__, attrib_name);
 		spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 		return -1;
 	}
@@ -345,14 +346,15 @@ void irias_add_integer_attrib(struct ias
 {
 	struct ias_attrib *attrib;
 
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-	ASSERT(name != NULL, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(name != NULL, return;);
 
 	attrib = (struct ias_attrib *) kmalloc(sizeof(struct ias_attrib),
 					       GFP_ATOMIC);
 	if (attrib == NULL) {
-		WARNING("%s: Unable to allocate attribute!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
 		return;
 	}
 	memset(attrib, 0, sizeof( struct ias_attrib));
@@ -379,16 +381,17 @@ void irias_add_octseq_attrib(struct ias_
 {
 	struct ias_attrib *attrib;
 
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-	ASSERT(name != NULL, return;);
-	ASSERT(octets != NULL, return;);
+	IRDA_ASSERT(name != NULL, return;);
+	IRDA_ASSERT(octets != NULL, return;);
 
 	attrib = (struct ias_attrib *) kmalloc(sizeof(struct ias_attrib),
 					       GFP_ATOMIC);
 	if (attrib == NULL) {
-		WARNING("%s: Unable to allocate attribute!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
 		return;
 	}
 	memset(attrib, 0, sizeof( struct ias_attrib));
@@ -413,16 +416,17 @@ void irias_add_string_attrib(struct ias_
 {
 	struct ias_attrib *attrib;
 
-	ASSERT(obj != NULL, return;);
-	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	IRDA_ASSERT(obj != NULL, return;);
+	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-	ASSERT(name != NULL, return;);
-	ASSERT(value != NULL, return;);
+	IRDA_ASSERT(name != NULL, return;);
+	IRDA_ASSERT(value != NULL, return;);
 
 	attrib = (struct ias_attrib *) kmalloc(sizeof( struct ias_attrib),
 					       GFP_ATOMIC);
 	if (attrib == NULL) {
-		WARNING("%s: Unable to allocate attribute!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
 		return;
 	}
 	memset(attrib, 0, sizeof( struct ias_attrib));
@@ -448,7 +452,7 @@ struct ias_value *irias_new_integer_valu
 
 	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(value, 0, sizeof(struct ias_value));
@@ -474,7 +478,7 @@ struct ias_value *irias_new_string_value
 
 	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset( value, 0, sizeof( struct ias_value));
@@ -501,7 +505,7 @@ struct ias_value *irias_new_octseq_value
 
 	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(value, 0, sizeof(struct ias_value));
@@ -514,7 +518,7 @@ struct ias_value *irias_new_octseq_value
 
 	value->t.oct_seq = kmalloc(len, GFP_ATOMIC);
 	if (value->t.oct_seq == NULL){
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		kfree(value);
 		return NULL;
 	}
@@ -529,7 +533,7 @@ struct ias_value *irias_new_missing_valu
 
 	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(value, 0, sizeof(struct ias_value));
@@ -550,7 +554,7 @@ void irias_delete_value(struct ias_value
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(value != NULL, return;);
+	IRDA_ASSERT(value != NULL, return;);
 
 	switch (value->type) {
 	case IAS_INTEGER: /* Fallthrough */
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -74,8 +74,8 @@ static void irlan_client_kick_timer_expi
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	/*  
 	 * If we are in peer mode, the client may not have got the discovery
@@ -107,8 +107,8 @@ void irlan_client_wakeup(struct irlan_cb
 {
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* 
 	 * Check if we are already awake, or if we are a provider in direct
@@ -155,7 +155,7 @@ void irlan_client_discovery_indication(d
 	
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
 
-	ASSERT(discovery != NULL, return;);
+	IRDA_ASSERT(discovery != NULL, return;);
 
 	/*
 	 * I didn't check it, but I bet that IrLAN suffer from the same
@@ -173,7 +173,7 @@ void irlan_client_discovery_indication(d
 	rcu_read_lock();
 	self = irlan_get_any();
 	if (self) {
-		ASSERT(self->magic == IRLAN_MAGIC, return;);
+		IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 		IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ ,
 		      daddr);
@@ -198,9 +198,9 @@ static int irlan_client_ctrl_data_indica
 	
 	self = (struct irlan_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 	
 	irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); 
 
@@ -227,12 +227,12 @@ static void irlan_client_ctrl_disconnect
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);	
-	ASSERT(tsap != NULL, return;);
-	ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);	
+	IRDA_ASSERT(tsap != NULL, return;);
+	IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
 	
-	ASSERT(tsap == self->client.tsap_ctrl, return;);
+	IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;);
 
        	/* Remove frames queued on the control channel */
 	while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
@@ -256,8 +256,8 @@ static void irlan_client_open_ctrl_tsap(
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if already open */
 	if (self->client.tsap_ctrl)
@@ -298,8 +298,8 @@ static void irlan_client_ctrl_connect_co
 
 	self = (struct irlan_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->client.max_sdu_size = max_sdu_size;
 	self->client.max_header_size = max_header_size;
@@ -322,34 +322,34 @@ static void print_ret_code(__u8 code) 
 		printk(KERN_INFO "Success\n");
 		break;
 	case 1:
-		WARNING("IrLAN: Insufficient resources\n");
+		IRDA_WARNING("IrLAN: Insufficient resources\n");
 		break;
 	case 2:
-		WARNING("IrLAN: Invalid command format\n");
+		IRDA_WARNING("IrLAN: Invalid command format\n");
 		break;
 	case 3:
-		WARNING("IrLAN: Command not supported\n");
+		IRDA_WARNING("IrLAN: Command not supported\n");
 		break;
 	case 4:
-		WARNING("IrLAN: Parameter not supported\n");
+		IRDA_WARNING("IrLAN: Parameter not supported\n");
 		break;
 	case 5:
-		WARNING("IrLAN: Value not supported\n");
+		IRDA_WARNING("IrLAN: Value not supported\n");
 		break;
 	case 6:
-		WARNING("IrLAN: Not open\n");
+		IRDA_WARNING("IrLAN: Not open\n");
 		break;
 	case 7:
-		WARNING("IrLAN: Authentication required\n");
+		IRDA_WARNING("IrLAN: Authentication required\n");
 		break;
 	case 8:
-		WARNING("IrLAN: Invalid password\n");
+		IRDA_WARNING("IrLAN: Invalid password\n");
 		break;
 	case 9:
-		WARNING("IrLAN: Protocol error\n");
+		IRDA_WARNING("IrLAN: Protocol error\n");
 		break;
 	case 255:
-		WARNING("IrLAN: Asynchronous status\n");
+		IRDA_WARNING("IrLAN: Asynchronous status\n");
 		break;
 	}
 }
@@ -371,15 +371,15 @@ void irlan_client_parse_response(struct 
         char *name;
         char *value;
 
-	ASSERT(skb != NULL, return;);	
+	IRDA_ASSERT(skb != NULL, return;);	
 	
 	IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len);
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	if (!skb) {
-		ERROR("%s(), Got NULL skb!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__);
 		return;
 	}
 	frame = skb->data;
@@ -438,8 +438,8 @@ static void irlan_check_response_param(s
 
 	IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Media type */
 	if (strcmp(param, "MEDIA") == 0) {
@@ -540,10 +540,10 @@ void irlan_client_get_value_confirm(int 
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(priv != NULL, return;);
+	IRDA_ASSERT(priv != NULL, return;);
 
 	self = (struct irlan_cb *) priv;
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* We probably don't need to make any more queries */
 	iriap_close(self->client.iriap);
diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c
--- a/net/irda/irlan/irlan_client_event.c
+++ b/net/irda/irlan/irlan_client_event.c
@@ -77,8 +77,8 @@ static int (*state[])(struct irlan_cb *,
 void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, 
 			   struct sk_buff *skb) 
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	(*state[ self->client.state]) (self, event, skb);
 }
@@ -94,13 +94,14 @@ static int irlan_client_state_idle(struc
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 	
 	switch (event) {
 	case IRLAN_DISCOVERY_INDICATION:
 		if (self->client.iriap) {
-			WARNING("%s(), busy with a previous query\n", __FUNCTION__);
+			IRDA_WARNING("%s(), busy with a previous query\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 		
@@ -137,12 +138,12 @@ static int irlan_client_state_query(stru
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 	
 	switch(event) {
 	case IRLAN_IAS_PROVIDER_AVAIL:
-		ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
+		IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
 
 		self->client.open_retries = 0;
 		
@@ -190,7 +191,7 @@ static int irlan_client_state_conn(struc
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	
 	switch (event) {
 	case IRLAN_CONNECT_COMPLETE:
@@ -225,11 +226,11 @@ static int irlan_client_state_info(struc
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	
 	switch (event) {
 	case IRLAN_DATA_INDICATION:
-		ASSERT(skb != NULL, return -1;);
+		IRDA_ASSERT(skb != NULL, return -1;);
 	
 		irlan_client_parse_response(self, skb);
 		
@@ -267,7 +268,7 @@ static int irlan_client_state_media(stru
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
@@ -306,7 +307,7 @@ static int irlan_client_state_open(struc
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
@@ -316,7 +317,7 @@ static int irlan_client_state_open(struc
 		 *  Check if we have got the remote TSAP for data 
 		 *  communications
 		 */
-	  	ASSERT(self->dtsap_sel_data != 0, return -1;);
+	  	IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
 
 		/* Check which access type we are dealing with */
 		switch (self->client.access_type) {
@@ -377,7 +378,7 @@ static int irlan_client_state_wait(struc
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	
 	switch(event) {
 	case IRLAN_PROVIDER_SIGNAL:
@@ -408,7 +409,7 @@ static int irlan_client_state_arb(struct
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	
 	switch(event) {
 	case IRLAN_CHECK_CON_ARB:
@@ -463,8 +464,8 @@ static int irlan_client_state_data(struc
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -261,8 +261,8 @@ static void __irlan_close(struct irlan_c
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 	
 	ASSERT_RTNL();
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	del_timer_sync(&self->watchdog_timer);
 	del_timer_sync(&self->client.kick_timer);
@@ -311,9 +311,9 @@ static void irlan_connect_indication(voi
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
-	ASSERT(tsap == self->tsap_data,return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(tsap == self->tsap_data,return;);
 
 	self->max_sdu_size = max_sdu_size;
 	self->max_header_size = max_header_size;
@@ -354,8 +354,8 @@ static void irlan_connect_confirm(void *
 
 	self = (struct irlan_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->max_sdu_size = max_sdu_size;
 	self->max_header_size = max_header_size;
@@ -403,12 +403,12 @@ static void irlan_disconnect_indication(
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);	
-	ASSERT(tsap != NULL, return;);
-	ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);	
+	IRDA_ASSERT(tsap != NULL, return;);
+	IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
 	
-	ASSERT(tsap == self->tsap_data, return;);
+	IRDA_ASSERT(tsap == self->tsap_data, return;);
 
 	IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
 
@@ -432,7 +432,7 @@ static void irlan_disconnect_indication(
 		IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ );
 		break;
 	default:
-		ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__);
+		IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__);
 		break;
 	}
 	
@@ -456,8 +456,8 @@ void irlan_open_data_tsap(struct irlan_c
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if already open */
 	if (self->tsap_data)
@@ -492,8 +492,8 @@ void irlan_close_tsaps(struct irlan_cb *
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Disconnect and close all open TSAP connections */
 	if (self->tsap_data) {
@@ -527,8 +527,8 @@ void irlan_ias_register(struct irlan_cb 
 	struct ias_object *obj;
 	struct ias_value *new_value;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	/* 
 	 * Check if object has already been registered by a previous provider.
@@ -634,8 +634,8 @@ void irlan_get_provider_info(struct irla
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	skb = dev_alloc_skb(64);
 	if (!skb)
@@ -666,8 +666,8 @@ void irlan_open_data_channel(struct irla
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	skb = dev_alloc_skb(64);
 	if (!skb)
@@ -698,8 +698,8 @@ void irlan_close_data_channel(struct irl
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if the TSAP is still there */
 	if (self->client.tsap_ctrl == NULL)
@@ -737,8 +737,8 @@ static void irlan_open_unicast_addr(stru
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);	
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);	
 	
 	skb = dev_alloc_skb(128);
 	if (!skb)
@@ -775,8 +775,8 @@ void irlan_set_broadcast_filter(struct i
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
  	skb = dev_alloc_skb(128);
 	if (!skb)
@@ -814,8 +814,8 @@ void irlan_set_multicast_filter(struct i
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
  	skb = dev_alloc_skb(128);
 	if (!skb)
@@ -854,8 +854,8 @@ static void irlan_get_unicast_addr(struc
 		
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	skb = dev_alloc_skb(128);
 	if (!skb)
@@ -889,8 +889,8 @@ void irlan_get_media_char(struct irlan_c
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	skb = dev_alloc_skb(64);
 	if (!skb)
@@ -985,8 +985,8 @@ static int __irlan_insert_param(struct s
 		value_len = 2;
 		break;
 	case IRLAN_ARRAY:
-		ASSERT(value_array != NULL, return 0;);
-		ASSERT(value_len > 0, return 0;);
+		IRDA_ASSERT(value_array != NULL, return 0;);
+		IRDA_ASSERT(value_len > 0, return 0;);
 		break;
 	default:
 		IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ );
@@ -1029,7 +1029,7 @@ static int __irlan_insert_param(struct s
 	default:
 		break;
 	}
-	ASSERT(n == (param_len+value_len+3), return 0;);
+	IRDA_ASSERT(n == (param_len+value_len+3), return 0;);
 
 	return param_len+value_len+3;
 }
@@ -1142,8 +1142,8 @@ static int irlan_seq_show(struct seq_fil
 	else {
 		struct irlan_cb *self = v;
 		
-		ASSERT(self != NULL, return -1;);
-		ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+		IRDA_ASSERT(self != NULL, return -1;);
+		IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
 		seq_printf(seq,"ifname: %s,\n",
 			       self->dev->name);
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -222,7 +222,13 @@ int irlan_eth_receive(void *instance, vo
 		++self->stats.rx_dropped; 
 		return 0;
 	}
-	ASSERT(skb->len > 1, return 0;);
+	if (skb->len < ETH_HLEN) {
+		IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
+			   __FUNCTION__, skb->len);
+		++self->stats.rx_dropped; 
+		dev_kfree_skb(skb);
+		return 0;
+	}
 		
 	/* 
 	 * Adopt this frame! Important to set all these fields since they 
@@ -261,12 +267,12 @@ void irlan_eth_flow_indication(void *ins
 
 	self = (struct irlan_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	dev = self->dev;
 
-	ASSERT(dev != NULL, return;);
+	IRDA_ASSERT(dev != NULL, return;);
 	
 	IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__,
 		   flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
@@ -340,7 +346,7 @@ static void irlan_eth_set_multicast_list
 
 	if (dev->flags & IFF_PROMISC) {
 		/* Enable promiscuous mode */
-		WARNING("Promiscous mode not implemented by IrLAN!\n");
+		IRDA_WARNING("Promiscous mode not implemented by IrLAN!\n");
 	} 
 	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
 		/* Disable promiscuous mode, use normal mode. */
diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c
--- a/net/irda/irlan/irlan_event.c
+++ b/net/irda/irlan/irlan_event.c
@@ -42,8 +42,8 @@ void irlan_next_client_state(struct irla
 {
 	IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->client.state = state;
 }
@@ -52,8 +52,8 @@ void irlan_next_provider_state(struct ir
 {
 	IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->provider.state = state;
 }
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
--- a/net/irda/irlan/irlan_filter.c
+++ b/net/irda/irlan/irlan_filter.c
@@ -36,8 +36,8 @@
  */
 void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	if ((self->provider.filter_type == IRLAN_DIRECTED) && 
 	    (self->provider.filter_operation == DYNAMIC))
@@ -148,8 +148,8 @@ void irlan_check_command_param(struct ir
 
 	bytes = value;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	IRDA_DEBUG(4, "%s, %s\n", param, value);
 
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
--- a/net/irda/irlan/irlan_provider.c
+++ b/net/irda/irlan/irlan_provider.c
@@ -74,10 +74,10 @@ static int irlan_provider_data_indicatio
 	
 	self = (struct irlan_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	code = skb->data[0];
 	switch(code) {
@@ -134,11 +134,11 @@ static void irlan_provider_connect_indic
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
-	ASSERT(tsap == self->provider.tsap_ctrl,return;);
-	ASSERT(self->provider.state == IRLAN_IDLE, return;);
+	IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;);
+	IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;);
 
 	daddr = irttp_get_daddr(tsap);
 	saddr = irttp_get_saddr(tsap);
@@ -168,8 +168,8 @@ static void irlan_provider_connect_indic
 void irlan_provider_connect_response(struct irlan_cb *self,
 				     struct tsap_cb *tsap)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Just accept */
 	irttp_connect_response(tsap, IRLAN_MTU, NULL);
@@ -187,12 +187,12 @@ static void irlan_provider_disconnect_in
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);	
-	ASSERT(tsap != NULL, return;);
-	ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);	
+	IRDA_ASSERT(tsap != NULL, return;);
+	IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
 	
-	ASSERT(tsap == self->provider.tsap_ctrl, return;);
+	IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;);
 	
 	irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
 }
@@ -234,12 +234,12 @@ int irlan_provider_parse_command(struct 
         char *value;
 	int ret = RSP_SUCCESS;
 	
-	ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
+	IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
 	
 	IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len);
 
-	ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
+	IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
 	
 	if (!skb)
 		return -RSP_PROTOCOL_ERROR;
@@ -293,8 +293,8 @@ void irlan_provider_send_reply(struct ir
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	skb = dev_alloc_skb(128);
 	if (!skb)
@@ -381,8 +381,8 @@ int irlan_provider_open_ctrl_tsap(struct
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
 	/* Check if already open */
 	if (self->provider.tsap_ctrl)
diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c
--- a/net/irda/irlan/irlan_provider_event.c
+++ b/net/irda/irlan/irlan_provider_event.c
@@ -58,7 +58,7 @@ static int (*state[])(struct irlan_cb *s
 void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, 
 			     struct sk_buff *skb) 
 {
-	ASSERT(*state[ self->provider.state] != NULL, return;);
+	IRDA_ASSERT(*state[ self->provider.state] != NULL, return;);
 
 	(*state[self->provider.state]) (self, event, skb);
 }
@@ -74,7 +74,7 @@ static int irlan_provider_state_idle(str
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 	
 	switch(event) {
 	case IRLAN_CONNECT_INDICATION:
@@ -103,7 +103,7 @@ static int irlan_provider_state_info(str
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 	
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	switch(event) {
 	case IRLAN_GET_INFO_CMD:
@@ -168,7 +168,7 @@ static int irlan_provider_state_open(str
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
 
 	switch(event) {
 	case IRLAN_FILTER_CONFIG_CMD:
@@ -207,8 +207,8 @@ static int irlan_provider_state_data(str
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
 	switch(event) {
 	case IRLAN_FILTER_CONFIG_CMD:
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -80,15 +80,16 @@ int __init irlap_init(void)
 {
 	/* Check if the compiler did its job properly.
 	 * May happen on some ARM configuration, check with Russell King. */
-	ASSERT(sizeof(struct xid_frame) == 14, ;);
-	ASSERT(sizeof(struct test_frame) == 10, ;);
-	ASSERT(sizeof(struct ua_frame) == 10, ;);
-	ASSERT(sizeof(struct snrm_frame) == 11, ;);
+	IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;);
+	IRDA_ASSERT(sizeof(struct test_frame) == 10, ;);
+	IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;);
+	IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;);
 
 	/* Allocate master array */
 	irlap = hashbin_new(HB_LOCK);
 	if (irlap == NULL) {
-	        ERROR("%s: can't allocate irlap hashbin!\n", __FUNCTION__);
+	        IRDA_ERROR("%s: can't allocate irlap hashbin!\n",
+			   __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -97,7 +98,7 @@ int __init irlap_init(void)
 
 void __exit irlap_cleanup(void)
 {
-	ASSERT(irlap != NULL, return;);
+	IRDA_ASSERT(irlap != NULL, return;);
 
 	hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
 }
@@ -186,8 +187,8 @@ EXPORT_SYMBOL(irlap_open);
  */
 static void __irlap_close(struct irlap_cb *self)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Stop timers */
 	del_timer(&self->slot_timer);
@@ -218,8 +219,8 @@ void irlap_close(struct irlap_cb *self)
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* We used to send a LAP_DISC_INDICATION here, but this was
 	 * racy. This has been move within irlmp_unregister_link()
@@ -249,8 +250,8 @@ void irlap_connect_indication(struct irl
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlap_init_qos_capabilities(self, NULL); /* No user QoS! */
 
@@ -283,8 +284,8 @@ void irlap_connect_request(struct irlap_
 {
 	IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	self->daddr = daddr;
 
@@ -310,8 +311,8 @@ void irlap_connect_confirm(struct irlap_
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
 }
@@ -342,13 +343,13 @@ void irlap_data_indication(struct irlap_
 void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
 			int unreliable)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
-	       return;);
+	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
+		    return;);
 	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
 	/*
@@ -389,12 +390,12 @@ void irlap_data_request(struct irlap_cb 
 #ifdef CONFIG_IRDA_ULTRA
 void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
+	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
 	       return;);
 	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
@@ -420,9 +421,9 @@ void irlap_unitdata_indication(struct ir
 {
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Hide LAP header from IrLMP layer */
 	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
@@ -440,8 +441,8 @@ void irlap_disconnect_request(struct irl
 {
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Don't disconnect until all data frames are successfully sent */
 	if (skb_queue_len(&self->txq) > 0) {
@@ -476,8 +477,8 @@ void irlap_disconnect_indication(struct 
 {
 	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Flush queues */
 	irlap_flush_all_queues(self);
@@ -495,7 +496,7 @@ void irlap_disconnect_indication(struct 
 						 reason, NULL);
 		break;
 	default:
-		ERROR("%s: Unknown reason %d\n", __FUNCTION__, reason);
+		IRDA_ERROR("%s: Unknown reason %d\n", __FUNCTION__, reason);
 	}
 }
 
@@ -509,15 +510,15 @@ void irlap_discovery_request(struct irla
 {
 	struct irlap_info info;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(discovery != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(discovery != NULL, return;);
 
 	IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots);
 
-	ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
-	       (discovery->nslots == 8) || (discovery->nslots == 16),
-	       return;);
+	IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
+		    (discovery->nslots == 8) || (discovery->nslots == 16),
+		    return;);
 
 	/* Discovery is only possible in NDM mode */
 	if (self->state != LAP_NDM) {
@@ -544,8 +545,8 @@ void irlap_discovery_request(struct irla
 	self->discovery_log = hashbin_new(HB_NOLOCK);
 
 	if (self->discovery_log == NULL) {
-		WARNING("%s(), Unable to allocate discovery log!\n",
-			__FUNCTION__);
+		IRDA_WARNING("%s(), Unable to allocate discovery log!\n",
+			     __FUNCTION__);
 		return;
 	}
 
@@ -569,10 +570,10 @@ void irlap_discovery_request(struct irla
  */
 void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
-	ASSERT(self->notify.instance != NULL, return;);
+	IRDA_ASSERT(self->notify.instance != NULL, return;);
 
 	/*
 	 * Check for successful discovery, since we are then allowed to clear
@@ -602,11 +603,11 @@ void irlap_discovery_indication(struct i
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(discovery != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(discovery != NULL, return;);
 
-	ASSERT(self->notify.instance != NULL, return;);
+	IRDA_ASSERT(self->notify.instance != NULL, return;);
 
 	/* A device is very likely to connect immediately after it performs
 	 * a successful discovery. This means that in our case, we are much
@@ -629,10 +630,10 @@ void irlap_status_indication(struct irla
 {
 	switch (quality_of_link) {
 	case STATUS_NO_ACTIVITY:
-		MESSAGE("IrLAP, no activity on link!\n");
+		IRDA_MESSAGE("IrLAP, no activity on link!\n");
 		break;
 	case STATUS_NOISY:
-		MESSAGE("IrLAP, noisy link!\n");
+		IRDA_MESSAGE("IrLAP, noisy link!\n");
 		break;
 	default:
 		break;
@@ -648,8 +649,8 @@ void irlap_reset_indication(struct irlap
 {
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	if (self->state == LAP_RESET_WAIT)
 		irlap_do_event(self, RESET_REQUEST, NULL, NULL);
@@ -677,7 +678,7 @@ int irlap_generate_rand_time_slot(int S,
 	static int rand;
 	int slot;
 
-	ASSERT((S - s) > 0, return 0;);
+	IRDA_ASSERT((S - s) > 0, return 0;);
 
 	rand += jiffies;
 	rand ^= (rand << 12);
@@ -685,7 +686,7 @@ int irlap_generate_rand_time_slot(int S,
 
 	slot = s + rand % (S-s);
 
-	ASSERT((slot >= s) || (slot < S), return 0;);
+	IRDA_ASSERT((slot >= s) || (slot < S), return 0;);
 
 	return slot;
 }
@@ -792,8 +793,8 @@ void irlap_initiate_connection_state(str
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Next to send and next to receive */
 	self->vs = self->vr = 0;
@@ -848,8 +849,8 @@ void irlap_flush_all_queues(struct irlap
 {
 	struct sk_buff* skb;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Free transmission queue */
 	while ((skb = skb_dequeue(&self->txq)) != NULL)
@@ -875,8 +876,8 @@ static void irlap_change_speed(struct ir
 
 	IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	self->speed = speed;
 
@@ -899,9 +900,9 @@ static void irlap_change_speed(struct ir
 static void irlap_init_qos_capabilities(struct irlap_cb *self,
 					struct qos_info *qos_user)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(self->netdev != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self->netdev != NULL, return;);
 
 	/* Start out with the maximum QoS support possible */
 	irda_init_max_qos_capabilies(&self->qos_rx);
@@ -947,8 +948,8 @@ void irlap_apply_default_connection_para
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* xbofs : Default value in NDM */
 	self->next_bofs   = 12;
@@ -1010,8 +1011,8 @@ void irlap_apply_connection_parameters(s
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Set the negotiated xbofs value */
 	self->next_bofs   = self->qos_tx.additional_bofs.value;
@@ -1040,8 +1041,8 @@ void irlap_apply_connection_parameters(s
 	 *  Initialize timeout values, some of the rules are listed on
 	 *  page 92 in IrLAP.
 	 */
-	ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
-	ASSERT(self->qos_rx.max_turn_time.value != 0, return;);
+	IRDA_ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
+	IRDA_ASSERT(self->qos_rx.max_turn_time.value != 0, return;);
 	/* The poll timeout applies only to the primary station.
 	 * It defines the maximum time the primary stay in XMIT mode
 	 * before timeout and turning the link around (sending a RR).
@@ -1139,7 +1140,7 @@ static int irlap_seq_show(struct seq_fil
 	const struct irlap_iter_state *iter = seq->private;
 	const struct irlap_cb *self = v;
 	
-	ASSERT(self->magic == LAP_MAGIC, return -EINVAL;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EINVAL;);
 
 	seq_printf(seq, "irlap%d ", iter->id);
 	seq_printf(seq, "state: %s\n",
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -169,8 +169,8 @@ static void irlap_poll_timer_expired(voi
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 }
@@ -183,8 +183,8 @@ static void irlap_poll_timer_expired(voi
  */
 static void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 #ifdef CONFIG_IRDA_FAST_RR
 	/*
@@ -346,12 +346,12 @@ static int irlap_state_ndm(struct irlap_
 	discovery_t *discovery_rsp;
 	int ret = 0;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case CONNECT_REQUEST:
-		ASSERT(self->netdev != NULL, return -1;);
+		IRDA_ASSERT(self->netdev != NULL, return -1;);
 
 		if (self->media_busy) {
 			/* Note : this will never happen, because we test
@@ -389,10 +389,11 @@ static int irlap_state_ndm(struct irlap_
 		}
 		break;
 	case DISCOVERY_REQUEST:
-		ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
 
 		if (self->media_busy) {
-			IRDA_DEBUG(0, "%s(), media busy!\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n",
+				   __FUNCTION__);
 			/* irlap->log.condition = MEDIA_BUSY; */
 
 			/* This will make IrLMP try again */
@@ -414,7 +415,7 @@ static int irlap_state_ndm(struct irlap_
 		irlap_next_state(self, LAP_QUERY);
 		break;
 	case RECV_DISCOVERY_XID_CMD:
-		ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
 
 		/* Assert that this is not the final slot */
 		if (info->s <= info->S) {
@@ -576,21 +577,21 @@ static int irlap_state_query(struct irla
 {
 	int ret = 0;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case RECV_DISCOVERY_XID_RSP:
-		ASSERT(info != NULL, return -1;);
-		ASSERT(info->discovery != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info->discovery != NULL, return -1;);
 
 		IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
 			   info->discovery->data.daddr);
 
 		if (!self->discovery_log) {
-			WARNING("%s: discovery log is gone! "
-				"maybe the discovery timeout has been set to "
-				"short?\n", __FUNCTION__);
+			IRDA_WARNING("%s: discovery log is gone! "
+				     "maybe the discovery timeout has been set"
+				     " to short?\n", __FUNCTION__);
 			break;
 		}
 		hashbin_insert(self->discovery_log,
@@ -613,7 +614,7 @@ static int irlap_state_query(struct irla
 		 * Jean II
 		 */
 
-		ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
 
 		IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __FUNCTION__, info->s);
 
@@ -690,8 +691,8 @@ static int irlap_state_reply(struct irla
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case QUERY_TIMER_EXPIRED:
@@ -700,7 +701,7 @@ static int irlap_state_reply(struct irla
 		irlap_next_state(self, LAP_NDM);
 		break;
 	case RECV_DISCOVERY_XID_CMD:
-		ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
 		/* Last frame? */
 		if (info->s == 0xff) {
 			del_timer(&self->query_timer);
@@ -757,14 +758,14 @@ static int irlap_state_conn(struct irlap
 
 	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case CONNECT_RESPONSE:
 		skb_pull(skb, sizeof(struct snrm_frame));
 
-		ASSERT(self->netdev != NULL, return -1;);
+		IRDA_ASSERT(self->netdev != NULL, return -1;);
 
 		irlap_qos_negotiate(self, skb);
 
@@ -851,8 +852,8 @@ static int irlap_state_setup(struct irla
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case FINAL_TIMER_EXPIRED:
@@ -880,8 +881,8 @@ static int irlap_state_setup(struct irla
 	case RECV_SNRM_CMD:
 		IRDA_DEBUG(4, "%s(), SNRM battle!\n", __FUNCTION__);
 
-		ASSERT(skb != NULL, return 0;);
-		ASSERT(info != NULL, return 0;);
+		IRDA_ASSERT(skb != NULL, return 0;);
+		IRDA_ASSERT(info != NULL, return 0;);
 
 		/*
 		 *  The device with the largest device address wins the battle
@@ -891,7 +892,7 @@ static int irlap_state_setup(struct irla
 			del_timer(&self->final_timer);
 			irlap_initiate_connection_state(self);
 
-			ASSERT(self->netdev != NULL, return -1;);
+			IRDA_ASSERT(self->netdev != NULL, return -1;);
 
 			skb_pull(skb, sizeof(struct snrm_frame));
 
@@ -923,11 +924,11 @@ static int irlap_state_setup(struct irla
 		irlap_initiate_connection_state(self);
 
 		/* Negotiate connection parameters */
-		ASSERT(skb->len > 10, return -1;);
+		IRDA_ASSERT(skb->len > 10, return -1;);
 
 		skb_pull(skb, sizeof(struct ua_frame));
 
-		ASSERT(self->netdev != NULL, return -1;);
+		IRDA_ASSERT(self->netdev != NULL, return -1;);
 
 		irlap_qos_negotiate(self, skb);
 
@@ -1158,8 +1159,8 @@ static int irlap_state_pclose(struct irl
 
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case RECV_UA_RSP: /* FALLTHROUGH */
@@ -1226,7 +1227,7 @@ static int irlap_state_nrm_p(struct irla
 		 */
 		self->fast_RR = FALSE;
 #endif /* CONFIG_IRDA_FAST_RR */
-		ASSERT( info != NULL, return -1;);
+		IRDA_ASSERT( info != NULL, return -1;);
 
 		ns_status = irlap_validate_ns_received(self, info->ns);
 		nr_status = irlap_validate_nr_received(self, info->nr);
@@ -1460,7 +1461,7 @@ static int irlap_state_nrm_p(struct irla
 			/* Start poll timer */
 			irlap_start_poll_timer(self, self->poll_timeout);
 		} else if (ret == NR_UNEXPECTED) {
-			ASSERT(info != NULL, return -1;);
+			IRDA_ASSERT(info != NULL, return -1;);
 			/*
 			 *  Unexpected nr!
 			 */
@@ -1491,7 +1492,7 @@ static int irlap_state_nrm_p(struct irla
 		}
 		break;
 	case RECV_RNR_RSP:
-		ASSERT(info != NULL, return -1;);
+		IRDA_ASSERT(info != NULL, return -1;);
 
 		/* Stop final timer */
 		del_timer(&self->final_timer);
@@ -1612,8 +1613,8 @@ static int irlap_state_reset_wait(struct
 
 	IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case RESET_REQUEST:
@@ -1659,8 +1660,8 @@ static int irlap_state_reset(struct irla
 
 	IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case RECV_DISC_CMD:
@@ -1693,7 +1694,7 @@ static int irlap_state_reset(struct irla
 		if (self->retry_count < 3) {
 			irlap_wait_min_turn_around(self, &self->qos_tx);
 
-			ASSERT(self->netdev != NULL, return -1;);
+			IRDA_ASSERT(self->netdev != NULL, return -1;);
 			irlap_send_snrm_frame(self, self->qos_dev);
 
 			self->retry_count++; /* Experimental!! */
@@ -1752,8 +1753,8 @@ static int irlap_state_xmit_s(struct irl
 
 	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
 
-	ASSERT(self != NULL, return -ENODEV;);
-	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+	IRDA_ASSERT(self != NULL, return -ENODEV;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
 	switch (event) {
 	case SEND_I_CMD:
@@ -1874,8 +1875,8 @@ static int irlap_state_nrm_s(struct irla
 
 	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case RECV_I_CMD: /* Optimize for the common case */
@@ -2231,8 +2232,8 @@ static int irlap_state_sclose(struct irl
 
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -ENODEV;);
-	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+	IRDA_ASSERT(self != NULL, return -ENODEV;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
 	switch (event) {
 	case RECV_DISC_CMD:
@@ -2304,8 +2305,8 @@ static int irlap_state_reset_check( stru
 
 	IRDA_DEBUG(1, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
 
-	ASSERT(self != NULL, return -ENODEV;);
-	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+	IRDA_ASSERT(self != NULL, return -ENODEV;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
 	switch (event) {
 	case RESET_RESPONSE:
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -113,8 +113,8 @@ void irlap_send_snrm_frame(struct irlap_
 	struct snrm_frame *frame;
 	int ret;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Allocate frame */
 	tx_skb = dev_alloc_skb(64);
@@ -206,8 +206,8 @@ void irlap_send_ua_response_frame(struct
 
 	IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Allocate frame */
 	tx_skb = dev_alloc_skb(64);
@@ -247,8 +247,8 @@ void irlap_send_dm_frame( struct irlap_c
 	struct sk_buff *tx_skb = NULL;
 	__u8 *frame;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	tx_skb = dev_alloc_skb(32);
 	if (!tx_skb)
@@ -279,8 +279,8 @@ void irlap_send_disc_frame(struct irlap_
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	tx_skb = dev_alloc_skb(16);
 	if (!tx_skb)
@@ -311,9 +311,9 @@ void irlap_send_discovery_xid_frame(stru
 	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__,
 		   s, S, command);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(discovery != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(discovery != NULL, return;);
 
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -402,11 +402,11 @@ static void irlap_recv_discovery_xid_rsp
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
 		return;
 	}
 		
@@ -423,7 +423,7 @@ static void irlap_recv_discovery_xid_rsp
 	}
 
 	if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
-		WARNING("%s: kmalloc failed!\n", __FUNCTION__);
+		IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__);
 		return;
 	}
 	memset(discovery, 0, sizeof(discovery_t));
@@ -478,7 +478,7 @@ static void irlap_recv_discovery_xid_cmd
 	char *text;
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
 		return;
 	}
 	
@@ -522,7 +522,8 @@ static void irlap_recv_discovery_xid_cmd
 		/* Check if things are sane at this point... */
 		if((discovery_info == NULL) || 
 		   !pskb_may_pull(skb, 3)) {
-			ERROR("%s: discovery frame to short!\n", __FUNCTION__);
+			IRDA_ERROR("%s: discovery frame to short!\n",
+				   __FUNCTION__);
 			return;
 		}
 
@@ -531,7 +532,7 @@ static void irlap_recv_discovery_xid_cmd
 		 */
 		discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
 		if (!discovery) {
-			WARNING("%s: unable to malloc!\n", __FUNCTION__);
+			IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
 			return;
 		}
 
@@ -861,9 +862,9 @@ void irlap_send_data_secondary_final(str
 {
 	struct sk_buff *tx_skb = NULL;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Is this reliable or unreliable data? */
 	if (skb->data[1] == I_FRAME) {
@@ -967,8 +968,8 @@ void irlap_resend_rejected_frames(struct
 	struct sk_buff *skb;
 	int count;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Initialize variables */
 	count = skb_queue_len(&self->wx_list);
@@ -1023,7 +1024,7 @@ void irlap_resend_rejected_frames(struct
 		if ((skb_queue_len( &self->txq) > 0) &&
 		    (self->window > 0)) {
 			skb = skb_dequeue( &self->txq);
-			ASSERT(skb != NULL, return;);
+			IRDA_ASSERT(skb != NULL, return;);
 
 			/*
 			 *  If send window > 1 then send frame with pf
@@ -1047,8 +1048,8 @@ void irlap_resend_rejected_frame(struct 
 	struct sk_buff *tx_skb;
 	struct sk_buff *skb;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/*  Resend unacknowledged frame(s) */
 	skb = skb_peek(&self->wx_list);
@@ -1089,9 +1090,9 @@ void irlap_send_ui_frame(struct irlap_cb
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Insert connection address */
 	skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
@@ -1168,13 +1169,13 @@ static void irlap_recv_frmr_frame(struct
 
 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(info != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(info != NULL, return;);
 
 	if (!pskb_may_pull(skb, 4)) {
-		ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
 		return;
 	}
 
@@ -1263,7 +1264,7 @@ static void irlap_recv_test_frame(struct
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	if (!pskb_may_pull(skb, sizeof(*frame))) {
-		ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
 		return;
 	}
 	frame = (struct test_frame *) skb->data;
@@ -1330,14 +1331,14 @@ int irlap_driver_rcv(struct sk_buff *skb
 	 * share and non linear skbs. This should never happen, so
 	 * we don't need to be clever about it. Jean II */
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-		ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
+		IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 		return -1;
 	}
 
 	/* Check if frame is large enough for parsing */
 	if (!pskb_may_pull(skb, 2)) {
-		ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 		return -1;
 	}
@@ -1387,7 +1388,7 @@ int irlap_driver_rcv(struct sk_buff *skb
 			irlap_recv_srej_frame(self, skb, &info, command);
 			break;
 		default:
-			WARNING("%s: Unknown S-frame %02x received!\n",
+			IRDA_WARNING("%s: Unknown S-frame %02x received!\n",
 				__FUNCTION__, info.control);
 			break;
 		}
@@ -1425,7 +1426,7 @@ int irlap_driver_rcv(struct sk_buff *skb
 		irlap_recv_ui_frame(self, skb, &info);
 		break;
 	default:
-		WARNING("%s: Unknown frame %02x received!\n",
+		IRDA_WARNING("%s: Unknown frame %02x received!\n",
 				__FUNCTION__, info.control);
 		break;
 	}
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -121,8 +121,8 @@ int __init irlmp_init(void)
 void __exit irlmp_cleanup(void) 
 {
 	/* Check for main structure */
-	ASSERT(irlmp != NULL, return;);
-	ASSERT(irlmp->magic == LMP_MAGIC, return;);
+	IRDA_ASSERT(irlmp != NULL, return;);
+	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
 
 	del_timer(&irlmp->discovery_timer);
 
@@ -147,10 +147,10 @@ struct lsap_cb *irlmp_open_lsap(__u8 sls
 {
 	struct lsap_cb *self;
 
-	ASSERT(notify != NULL, return NULL;);
-	ASSERT(irlmp != NULL, return NULL;);
-	ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
-	ASSERT(notify->instance != NULL, return NULL;);
+	IRDA_ASSERT(notify != NULL, return NULL;);
+	IRDA_ASSERT(irlmp != NULL, return NULL;);
+	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
+	IRDA_ASSERT(notify->instance != NULL, return NULL;);
 
 	/*  Does the client care which Source LSAP selector it gets?  */
 	if (slsap_sel == LSAP_ANY) {
@@ -163,7 +163,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 sls
 	/* Allocate new instance of a LSAP connection */
 	self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		ERROR("%s: can't allocate memory\n", __FUNCTION__);
+		IRDA_ERROR("%s: can't allocate memory\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct lsap_cb));
@@ -204,8 +204,8 @@ static void __irlmp_close_lsap(struct ls
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
 	/*
 	 *  Set some of the variables to preset values
@@ -230,8 +230,8 @@ void irlmp_close_lsap(struct lsap_cb *se
 	struct lap_cb *lap;
 	struct lsap_cb *lsap = NULL;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
 	/*
 	 *  Find out if we should remove this LSAP from a link or from the
@@ -239,7 +239,7 @@ void irlmp_close_lsap(struct lsap_cb *se
 	 */
 	lap = self->lap;
 	if (lap) {
-		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 		/* We might close a LSAP before it has completed the
 		 * connection setup. In those case, higher layers won't
 		 * send a proper disconnect request. Harmless, except
@@ -282,16 +282,16 @@ void irlmp_register_link(struct irlap_cb
 {
 	struct lap_cb *lap;
 
-	ASSERT(irlmp != NULL, return;);
-	ASSERT(irlmp->magic == LMP_MAGIC, return;);
-	ASSERT(notify != NULL, return;);
+	IRDA_ASSERT(irlmp != NULL, return;);
+	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
+	IRDA_ASSERT(notify != NULL, return;);
 
 	/*
 	 *  Allocate new instance of a LSAP connection
 	 */
 	lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL);
 	if (lap == NULL) {
-		ERROR("%s: unable to kmalloc\n", __FUNCTION__);
+		IRDA_ERROR("%s: unable to kmalloc\n", __FUNCTION__);
 		return;
 	}
 	memset(lap, 0, sizeof(struct lap_cb));
@@ -305,7 +305,7 @@ void irlmp_register_link(struct irlap_cb
 #endif
 	lap->lsaps = hashbin_new(HB_LOCK);
 	if (lap->lsaps == NULL) {
-		WARNING("%s(), unable to kmalloc lsaps\n", __FUNCTION__);
+		IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __FUNCTION__);
 		kfree(lap);
 		return;
 	}
@@ -344,7 +344,7 @@ void irlmp_unregister_link(__u32 saddr)
 	 * will be triggered anymore. Jean II */
 	link = hashbin_remove(irlmp->links, saddr, NULL);
 	if (link) {
-		ASSERT(link->magic == LMP_LAP_MAGIC, return;);
+		IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;);
 
 		/* Kill all the LSAPs on this link. Jean II */
 		link->reason = LAP_DISC_INDICATION;
@@ -376,8 +376,8 @@ int irlmp_connect_request(struct lsap_cb
 	struct lsap_cb *lsap;
 	int ret;
 
-	ASSERT(self != NULL, return -EBADR;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
+	IRDA_ASSERT(self != NULL, return -EBADR;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
 
 	IRDA_DEBUG(2,
 	      "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
@@ -404,7 +404,7 @@ int irlmp_connect_request(struct lsap_cb
 	}
 
 	/* Make room for MUX control header (3 bytes) */
-	ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
+	IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
 	skb_push(tx_skb, LMP_CONTROL_HEADER);
 
 	self->dlsap_sel = dlsap_sel;
@@ -473,10 +473,10 @@ int irlmp_connect_request(struct lsap_cb
 	 */
 	lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL);
 
-	ASSERT(lsap != NULL, return -1;);
-	ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(lsap->lap != NULL, return -1;);
-	ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
+	IRDA_ASSERT(lsap != NULL, return -1;);
+	IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(lsap->lap != NULL, return -1;);
+	IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
 
 	hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self,
 		       NULL);
@@ -516,10 +516,10 @@ void irlmp_connect_indication(struct lsa
 	int lap_header_size;
 	int max_header_size;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(self->lap != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self->lap != NULL, return;);
 
 	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
 		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
@@ -555,9 +555,9 @@ void irlmp_connect_indication(struct lsa
  */
 int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(userdata != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(userdata != NULL, return -1;);
 
 	/* We set the connected bit and move the lsap to the connected list
 	 * in the state machine itself. Jean II */
@@ -566,7 +566,7 @@ int irlmp_connect_response(struct lsap_c
 		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
 
 	/* Make room for MUX control header (3 bytes) */
-	ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
+	IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
 	skb_push(userdata, LMP_CONTROL_HEADER);
 
 	irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
@@ -591,10 +591,10 @@ void irlmp_connect_confirm(struct lsap_c
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(skb != NULL, return;);
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(self->lap != NULL, return;);
+	IRDA_ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(self->lap != NULL, return;);
 
 	self->qos = *self->lap->qos;
 
@@ -687,9 +687,9 @@ int irlmp_disconnect_request(struct lsap
 {
 	struct lsap_cb *lsap;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(userdata != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(userdata != NULL, return -1;);
 
 	/* Already disconnected ?
 	 * There is a race condition between irlmp_disconnect_indication()
@@ -716,18 +716,18 @@ int irlmp_disconnect_request(struct lsap
 	 *  Remove LSAP from list of connected LSAPs for the particular link
 	 *  and insert it into the list of unconnected LSAPs
 	 */
-	ASSERT(self->lap != NULL, return -1;);
-	ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
-	ASSERT(self->lap->lsaps != NULL, return -1;);
+	IRDA_ASSERT(self->lap != NULL, return -1;);
+	IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
 
 	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	self->lap->cache.valid = FALSE;
 #endif
 
-	ASSERT(lsap != NULL, return -1;);
-	ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(lsap == self, return -1;);
+	IRDA_ASSERT(lsap != NULL, return -1;);
+	IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(lsap == self, return -1;);
 
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
 		       (long) self, NULL);
@@ -751,8 +751,8 @@ void irlmp_disconnect_indication(struct 
 	struct lsap_cb *lsap;
 
 	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
 	IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
 		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
@@ -769,16 +769,16 @@ void irlmp_disconnect_indication(struct 
 	/*
 	 *  Remove association between this LSAP and the link it used
 	 */
-	ASSERT(self->lap != NULL, return;);
-	ASSERT(self->lap->lsaps != NULL, return;);
+	IRDA_ASSERT(self->lap != NULL, return;);
+	IRDA_ASSERT(self->lap->lsaps != NULL, return;);
 
 	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	self->lap->cache.valid = FALSE;
 #endif
 
-	ASSERT(lsap != NULL, return;);
-	ASSERT(lsap == self, return;);
+	IRDA_ASSERT(lsap != NULL, return;);
+	IRDA_ASSERT(lsap == self, return;);
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap,
 		       (long) lsap, NULL);
 
@@ -822,7 +822,7 @@ void irlmp_do_expiry(void)
 	 */
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
-		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 
 		if (lap->lap_state == LAP_STANDBY) {
 			/* Expire discoveries discovered on this link */
@@ -846,8 +846,8 @@ void irlmp_do_discovery(int nslots)
 
 	/* Make sure the value is sane */
 	if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
-		WARNING("%s: invalid value for number of slots!\n",
-				__FUNCTION__);
+		IRDA_WARNING("%s: invalid value for number of slots!\n",
+			     __FUNCTION__);
 		nslots = sysctl_discovery_slots = 8;
 	}
 
@@ -870,7 +870,7 @@ void irlmp_do_discovery(int nslots)
 	 */
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
-		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 
 		if (lap->lap_state == LAP_STANDBY) {
 			/* Try to discover */
@@ -1017,7 +1017,7 @@ void irlmp_discovery_confirm(hashbin_t *
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(log != NULL, return;);
+	IRDA_ASSERT(log != NULL, return;);
 
 	if (!(HASHBIN_GET_SIZE(log)))
 		return;
@@ -1052,7 +1052,7 @@ void irlmp_discovery_expiry(discinfo_t *
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	ASSERT(expiries != NULL, return;);
+	IRDA_ASSERT(expiries != NULL, return;);
 
 	/* For each client - notify callback may touch client list */
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
@@ -1085,7 +1085,7 @@ discovery_t *irlmp_get_discovery_respons
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(irlmp != NULL, return NULL;);
+	IRDA_ASSERT(irlmp != NULL, return NULL;);
 
 	u16ho(irlmp->discovery_rsp.data.hints) = irlmp->hints.word;
 
@@ -1120,11 +1120,11 @@ int irlmp_data_request(struct lsap_cb *s
 {
 	int	ret;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	/* Make room for MUX header */
-	ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
+	IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
 	skb_push(userdata, LMP_HEADER);
 
 	ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata);
@@ -1163,10 +1163,10 @@ int irlmp_udata_request(struct lsap_cb *
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(userdata != NULL, return -1;);
+	IRDA_ASSERT(userdata != NULL, return -1;);
 
 	/* Make room for MUX header */
-	ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
+	IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
 	skb_push(userdata, LMP_HEADER);
 
 	ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata);
@@ -1187,9 +1187,9 @@ void irlmp_udata_indication(struct lsap_
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Hide LMP header from layer above */
 	skb_pull(skb, LMP_HEADER);
@@ -1214,11 +1214,11 @@ int irlmp_connless_data_request(struct l
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(userdata != NULL, return -1;);
+	IRDA_ASSERT(userdata != NULL, return -1;);
 
 	/* Make room for MUX and PID header */
-	ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
-	       return -1;);
+	IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
+		    return -1;);
 
 	/* Insert protocol identifier */
 	skb_push(userdata, LMP_PID_HEADER);
@@ -1234,7 +1234,7 @@ int irlmp_connless_data_request(struct l
 	/* Try to send Connectionless  packets out on all links */
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
-		ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
+		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
 
 		clone_skb = skb_clone(userdata, GFP_ATOMIC);
 		if (!clone_skb) {
@@ -1265,9 +1265,9 @@ void irlmp_connless_data_indication(stru
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/* Hide LMP and PID header from layer above */
 	skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
@@ -1298,7 +1298,7 @@ void irlmp_status_indication(struct lap_
 	curr = (struct lsap_cb *) hashbin_get_first( self->lsaps);
 	while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL,
 					 (void *) &next) ) {
-		ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
+		IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
 		/*
 		 *  Inform service user if he has requested it
 		 */
@@ -1328,8 +1328,8 @@ void irlmp_flow_indication(struct lap_cb
 	struct lsap_cb *curr;
 	int	lsap_todo;
 
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT(flow == FLOW_START, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(flow == FLOW_START, return;);
 
 	/* Get the number of lsap. That's the only safe way to know
 	 * that we have looped around... - Jean II */
@@ -1559,7 +1559,7 @@ void *irlmp_register_client(__u16 hint_m
 	irlmp_client_t *client;
 
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
-	ASSERT(irlmp != NULL, return NULL;);
+	IRDA_ASSERT(irlmp != NULL, return NULL;);
 
 	/* Make a new registration */
 	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
@@ -1660,9 +1660,9 @@ static int irlmp_slsap_inuse(__u8 slsap_
 	struct lap_cb *lap;
 	unsigned long flags;
 
-	ASSERT(irlmp != NULL, return TRUE;);
-	ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
-	ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
+	IRDA_ASSERT(irlmp != NULL, return TRUE;);
+	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
+	IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
@@ -1684,7 +1684,7 @@ static int irlmp_slsap_inuse(__u8 slsap_
 	spin_lock_irqsave(&irlmp->links->hb_spinlock, flags);
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
-		ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;);
+		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;);
 
 		/* Careful for priority inversions here !
 		 * irlmp->links is never taken while another IrDA
@@ -1694,7 +1694,8 @@ static int irlmp_slsap_inuse(__u8 slsap_
 		/* For this IrLAP, check all the LSAPs */
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, goto errlsap;);
+			IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
+				    goto errlsap;);
 
 			if ((self->slsap_sel == slsap_sel)) {
 				IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n",
@@ -1720,7 +1721,7 @@ static int irlmp_slsap_inuse(__u8 slsap_
 
 	self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
 	while (self != NULL) {
-		ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;);
+		IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;);
 		if ((self->slsap_sel == slsap_sel)) {
 			IRDA_DEBUG(4, "Source LSAP selector=%02x in use (unconnected)\n",
 				   self->slsap_sel);
@@ -1737,7 +1738,7 @@ static int irlmp_slsap_inuse(__u8 slsap_
 	 * Jean II */
 errlsap:
 	spin_unlock(&lap->lsaps->hb_spinlock);
-errlap:
+IRDA_ASSERT_LABEL(errlap:)
 	spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
 	return TRUE;
 
@@ -1759,8 +1760,8 @@ static __u8 irlmp_find_free_slsap(void)
 	__u8 lsap_sel;
 	int wrapped = 0;
 
-	ASSERT(irlmp != NULL, return -1;);
-	ASSERT(irlmp->magic == LMP_MAGIC, return -1;);
+	IRDA_ASSERT(irlmp != NULL, return -1;);
+	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;);
 
 	/* Most users don't really care which LSAPs they are given,
 	 * and therefore we automatically give them a free LSAP.
@@ -1788,8 +1789,8 @@ static __u8 irlmp_find_free_slsap(void)
 
 			/* Make sure we terminate the loop */
 			if (wrapped++) {
-				ERROR("%s: no more free LSAPs !\n",
-				      __FUNCTION__);
+				IRDA_ERROR("%s: no more free LSAPs !\n",
+					   __FUNCTION__);
 				return 0;
 			}
 		}
@@ -1948,7 +1949,7 @@ static int irlmp_seq_show(struct seq_fil
 		seq_puts(seq, "\nRegistered Link Layers:\n");
 	else if (iter->hashbin == irlmp->unconnected_lsaps) {
 		self = v;
-		ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; );
+		IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; );
 		seq_printf(seq, "lsap state: %s, ",
 			   irlsap_state[ self->lsap_state]);
 		seq_printf(seq,
@@ -1977,7 +1978,8 @@ static int irlmp_seq_show(struct seq_fil
 		for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		     self != NULL;
 		     self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
+			IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
+				    goto outloop;);
 			seq_printf(seq, "  lsap state: %s, ",
 				   irlsap_state[ self->lsap_state]);
 			seq_printf(seq,
@@ -1987,6 +1989,7 @@ static int irlmp_seq_show(struct seq_fil
 			seq_putc(seq, '\n');
 
 		}
+	IRDA_ASSERT_LABEL(outloop:)
 		spin_unlock(&lap->lsaps->hb_spinlock);
 		seq_putc(seq, '\n');
 	} else
@@ -2008,7 +2011,7 @@ static int irlmp_seq_open(struct inode *
 	int rc = -ENOMEM;
 	struct irlmp_iter_state *s;
 
-	ASSERT(irlmp != NULL, return -EINVAL;);
+	IRDA_ASSERT(irlmp != NULL, return -EINVAL;);
 
 	s = kmalloc(sizeof(*s), GFP_KERNEL);
 	if (!s)
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -130,7 +130,7 @@ static inline void irlmp_next_lsap_state
 					 LSAP_STATE state)
 {
 	/*
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 	IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]);
 	*/
 	self->lsap_state = state;
@@ -140,8 +140,8 @@ static inline void irlmp_next_lsap_state
 int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
 			struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
 		__FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]);
@@ -158,8 +158,8 @@ int irlmp_do_lsap_event(struct lsap_cb *
 void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
 			struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
 	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __FUNCTION__,
 		   irlmp_event[event],
@@ -189,8 +189,8 @@ void irlmp_watchdog_timer_expired(void *
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
 	irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);
 }
@@ -201,8 +201,8 @@ void irlmp_idle_timer_expired(void *data
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
 	irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);
 }
@@ -260,7 +260,7 @@ static void irlmp_state_standby(struct l
 				struct sk_buff *skb)
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
-	ASSERT(self->irlap != NULL, return;);
+	IRDA_ASSERT(self->irlap != NULL, return;);
 
 	switch (event) {
 	case LM_LAP_DISCOVERY_REQUEST:
@@ -495,8 +495,8 @@ static int irlmp_state_disconnected(stru
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	switch (event) {
 #ifdef CONFIG_IRDA_ULTRA
@@ -511,8 +511,8 @@ static int irlmp_state_disconnected(stru
 		IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __FUNCTION__);
 
 		if (self->conn_skb) {
-			WARNING("%s: busy with another request!\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: busy with another request!\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 		/* Don't forget to refcount it (see irlmp_connect_request()) */
@@ -528,8 +528,8 @@ static int irlmp_state_disconnected(stru
 		break;
 	case LM_CONNECT_INDICATION:
 		if (self->conn_skb) {
-			WARNING("%s: busy with another request!\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: busy with another request!\n",
+				     __FUNCTION__);
 			return -EBUSY;
 		}
 		/* Don't forget to refcount it (see irlap_driver_rcv()) */
@@ -575,8 +575,8 @@ static int irlmp_state_connect(struct ls
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	switch (event) {
 	case LM_CONNECT_RESPONSE:
@@ -587,9 +587,9 @@ static int irlmp_state_connect(struct ls
 		lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
 				      NULL);
 
-		ASSERT(lsap == self, return -1;);
-		ASSERT(self->lap != NULL, return -1;);
-		ASSERT(self->lap->lsaps != NULL, return -1;);
+		IRDA_ASSERT(lsap == self, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
 
 		hashbin_insert(self->lap->lsaps, (irda_queue_t *) self,
 			       (long) self, NULL);
@@ -637,8 +637,8 @@ static int irlmp_state_connect_pend(stru
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	switch (event) {
 	case LM_CONNECT_REQUEST:
@@ -703,9 +703,9 @@ static int irlmp_state_dtr(struct lsap_c
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-	ASSERT(self->lap != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self->lap != NULL, return -1;);
 
 	switch (event) {
 	case LM_DATA_REQUEST: /* Optimize for the common case */
@@ -716,7 +716,7 @@ static int irlmp_state_dtr(struct lsap_c
 		irlmp_data_indication(self, skb);
 		break;
 	case LM_UDATA_REQUEST:
-		ASSERT(skb != NULL, return -1;);
+		IRDA_ASSERT(skb != NULL, return -1;);
 		irlmp_send_data_pdu(self->lap, self->dlsap_sel,
 				    self->slsap_sel, TRUE, skb);
 		break;
@@ -759,11 +759,11 @@ static int irlmp_state_dtr(struct lsap_c
 	case LM_DISCONNECT_INDICATION:
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
-		ASSERT(self->lap != NULL, return -1;);
-		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 
-		ASSERT(skb != NULL, return -1;);
-		ASSERT(skb->len > 3, return -1;);
+		IRDA_ASSERT(skb != NULL, return -1;);
+		IRDA_ASSERT(skb->len > 3, return -1;);
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
@@ -793,8 +793,8 @@ static int irlmp_state_setup(struct lsap
 	LM_REASON reason;
 	int ret = 0;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
@@ -809,11 +809,11 @@ static int irlmp_state_setup(struct lsap
 	case LM_DISCONNECT_INDICATION:
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
-		ASSERT(self->lap != NULL, return -1;);
-		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 
-		ASSERT(skb != NULL, return -1;);
-		ASSERT(skb->len > 3, return -1;);
+		IRDA_ASSERT(skb != NULL, return -1;);
+		IRDA_ASSERT(skb->len > 3, return -1;);
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
@@ -827,8 +827,8 @@ static int irlmp_state_setup(struct lsap
 
 		del_timer(&self->watchdog_timer);
 
-		ASSERT(self->lap != NULL, return -1;);
-		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 
 		reason = irlmp_convert_lap_reason(self->lap->reason);
 
@@ -837,7 +837,7 @@ static int irlmp_state_setup(struct lsap
 	case LM_WATCHDOG_TIMEOUT:
 		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__);
 
-		ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
@@ -868,12 +868,12 @@ static int irlmp_state_setup_pend(struct
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(irlmp != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(irlmp != NULL, return -1;);
 
 	switch (event) {
 	case LM_LAP_CONNECT_CONFIRM:
-		ASSERT(self->conn_skb != NULL, return -1;);
+		IRDA_ASSERT(self->conn_skb != NULL, return -1;);
 
 		tx_skb = self->conn_skb;
 		self->conn_skb = NULL;
@@ -888,7 +888,7 @@ static int irlmp_state_setup_pend(struct
 	case LM_WATCHDOG_TIMEOUT:
 		IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n",  __FUNCTION__);
 
-		ASSERT(self->lap != NULL, return -1;);
+		IRDA_ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -63,9 +63,9 @@ void irlmp_send_lcf_pdu(struct lap_cb *s
 	
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 	
 	frame = skb->data;
 	
@@ -98,9 +98,9 @@ void irlmp_link_data_indication(struct l
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT(skb->len > 2, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(skb->len > 2, return;);
 
 	fp = skb->data;
 
@@ -209,9 +209,9 @@ void irlmp_link_unitdata_indication(stru
 	
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT(skb->len > 2, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(skb->len > 2, return;);
 
 	fp = skb->data;
 
@@ -273,8 +273,8 @@ void irlmp_link_disconnect_indication(st
 {
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(lap != NULL, return;);
-	ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(lap != NULL, return;);
+	IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 
 	lap->reason = reason;
 	lap->daddr = DEV_ADDR_ANY;
@@ -304,7 +304,7 @@ void irlmp_link_connect_indication(struc
 
 	/* Update destination device address */
 	self->daddr = daddr;
-	ASSERT(self->saddr == saddr, return;);
+	IRDA_ASSERT(self->saddr == saddr, return;);
 
 	irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
 }
@@ -320,9 +320,9 @@ void irlmp_link_connect_confirm(struct l
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT(qos != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(qos != NULL, return;);
 
 	/* Don't need use the skb for now */
 
@@ -363,8 +363,8 @@ void irlmp_link_connect_confirm(struct l
 void irlmp_link_discovery_indication(struct lap_cb *self, 
 				     discovery_t *discovery)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
 	/* Add to main log, cleanup */
 	irlmp_add_discovery(irlmp->cachelog, discovery);
@@ -386,8 +386,8 @@ void irlmp_link_discovery_confirm(struct
 {
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	
 	/* Add to main log, cleanup */
 	irlmp_add_discovery_log(irlmp->cachelog, log);
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -632,7 +632,7 @@ irda_irnet_destroy(irnet_socket *	self)
       self->iriap = NULL;
     }
 
-  /* Cleanup eventual discoveries from connection attempt */
+  /* Cleanup eventual discoveries from connection attempt or control channel */
   if(self->discoveries != NULL)
     {
       /* Cleanup our copy of the discovery log */
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -171,18 +171,44 @@ irnet_ctrl_write(irnet_socket *	ap,
 #ifdef INITIAL_DISCOVERY
 /*------------------------------------------------------------------*/
 /*
- * Function irnet_read_discovery_log (self)
+ * Function irnet_get_discovery_log (self)
+ *
+ *    Query the content on the discovery log if not done
+ *
+ * This function query the current content of the discovery log
+ * at the startup of the event channel and save it in the internal struct.
+ */
+static void
+irnet_get_discovery_log(irnet_socket *	ap)
+{
+  __u16		mask = irlmp_service_to_hint(S_LAN);
+
+  /* Ask IrLMP for the current discovery log */
+  ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask,
+					  DISCOVERY_DEFAULT_SLOTS);
+
+  /* Check if the we got some results */
+  if(ap->discoveries == NULL)
+    ap->disco_number = -1;
+
+  DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n",
+	ap->discoveries, ap->disco_number);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_read_discovery_log (self, event)
  *
  *    Read the content on the discovery log
  *
  * This function dump the current content of the discovery log
  * at the startup of the event channel.
- * Return 1 if written on the control channel...
+ * Return 1 if wrote an event on the control channel...
  *
  * State of the ap->disco_XXX variables :
- *	at socket creation :	disco_index = 0 ; disco_number = 0
- *	while reading :		disco_index = X ; disco_number = Y
- *	After reading :		disco_index = Y ; disco_number = -1
+ * Socket creation :  discoveries = NULL ; disco_index = 0 ; disco_number = 0
+ * While reading :    discoveries = ptr  ; disco_index = X ; disco_number = Y
+ * After reading :    discoveries = NULL ; disco_index = Y ; disco_number = -1
  */
 static inline int
 irnet_read_discovery_log(irnet_socket *	ap,
@@ -201,19 +227,8 @@ irnet_read_discovery_log(irnet_socket *	
     }
 
   /* Test if it's the first time and therefore we need to get the log */
-  if(ap->disco_index == 0)
-    {
-      __u16		mask = irlmp_service_to_hint(S_LAN);
-
-      /* Ask IrLMP for the current discovery log */
-      ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask,
-					      DISCOVERY_DEFAULT_SLOTS);
-      /* Check if the we got some results */
-      if(ap->discoveries == NULL)
-	ap->disco_number = -1;
-      DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n",
-	    ap->discoveries, ap->disco_number);
-    }
+  if(ap->discoveries == NULL)
+    irnet_get_discovery_log(ap);
 
   /* Check if we have more item to dump */
   if(ap->disco_index < ap->disco_number)
@@ -417,7 +432,14 @@ irnet_ctrl_poll(irnet_socket *	ap,
     mask |= POLLIN | POLLRDNORM;
 #ifdef INITIAL_DISCOVERY
   if(ap->disco_number != -1)
-    mask |= POLLIN | POLLRDNORM;
+    {
+      /* Test if it's the first time and therefore we need to get the log */
+      if(ap->discoveries == NULL)
+	irnet_get_discovery_log(ap);
+      /* Recheck */
+      if(ap->disco_number != -1)
+	mask |= POLLIN | POLLRDNORM;
+    }
 #endif /* INITIAL_DISCOVERY */
 
   DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask);
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -391,8 +391,8 @@ int hashbin_delete( hashbin_t* hashbin, 
 	unsigned long flags = 0;
 	int i;
 
-	ASSERT(hashbin != NULL, return -1;);
-	ASSERT(hashbin->magic == HB_MAGIC, return -1;);
+	IRDA_ASSERT(hashbin != NULL, return -1;);
+	IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;);
 	
 	/* Synchronize */
 	if ( hashbin->hb_type & HB_LOCK ) {
@@ -447,8 +447,8 @@ void hashbin_insert(hashbin_t* hashbin, 
 
 	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
 
-	ASSERT( hashbin != NULL, return;);
-	ASSERT( hashbin->magic == HB_MAGIC, return;);
+	IRDA_ASSERT( hashbin != NULL, return;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;);
 
 	/*
 	 * Locate hashbin
@@ -560,8 +560,8 @@ void* hashbin_remove( hashbin_t* hashbin
 
 	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
 
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	IRDA_ASSERT( hashbin != NULL, return NULL;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
 	
 	/*
 	 * Locate hashbin
@@ -653,9 +653,9 @@ void* hashbin_remove_this( hashbin_t* ha
 
 	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
 
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
-	ASSERT( entry != NULL, return NULL;);
+	IRDA_ASSERT( hashbin != NULL, return NULL;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	IRDA_ASSERT( entry != NULL, return NULL;);
 	
 	/* Synchronize */
 	if ( hashbin->hb_type & HB_LOCK ) {
@@ -714,8 +714,8 @@ void* hashbin_find( hashbin_t* hashbin, 
 
 	IRDA_DEBUG( 4, "hashbin_find()\n");
 
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	IRDA_ASSERT( hashbin != NULL, return NULL;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
 
 	/*
 	 * Locate hashbin
@@ -836,8 +836,8 @@ irda_queue_t *hashbin_get_first( hashbin
 	irda_queue_t *entry;
 	int i;
 
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	IRDA_ASSERT( hashbin != NULL, return NULL;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
 
 	if ( hashbin == NULL)
 		return NULL;
@@ -872,11 +872,11 @@ irda_queue_t *hashbin_get_next( hashbin_
 	int bin;
 	int i;
 
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	IRDA_ASSERT( hashbin != NULL, return NULL;);
+	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
 
 	if ( hashbin->hb_current == NULL) {
-		ASSERT( hashbin->hb_current != NULL, return NULL;);
+		IRDA_ASSERT( hashbin->hb_current != NULL, return NULL;);
 		return NULL;
 	}	
 	entry = hashbin->hb_current->q_next;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -98,7 +98,8 @@ int __init irttp_init(void)
 
 	irttp->tsaps = hashbin_new(HB_LOCK);
 	if (!irttp->tsaps) {
-		ERROR("%s: can't allocate IrTTP hashbin!\n", __FUNCTION__);
+		IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n",
+			   __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -114,8 +115,8 @@ int __init irttp_init(void)
 void __exit irttp_cleanup(void) 
 {
 	/* Check for main structure */
-	ASSERT(irttp != NULL, return;);
-	ASSERT(irttp->magic == TTP_MAGIC, return;);
+	IRDA_ASSERT(irttp != NULL, return;);
+	IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
 
 	/*
 	 *  Delete hashbin and close all TSAP instances in it
@@ -210,8 +211,8 @@ void irttp_flush_queues(struct tsap_cb *
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	/* Deallocate frames waiting to be sent */
 	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
@@ -238,8 +239,8 @@ static struct sk_buff *irttp_reassemble_
 	struct sk_buff *skb, *frag;
 	int n = 0;  /* Fragment index */
 
-	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
+	IRDA_ASSERT(self != NULL, return NULL;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
 
 	IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __FUNCTION__,
 		   self->rx_sdu_size);
@@ -274,7 +275,7 @@ static struct sk_buff *irttp_reassemble_
 	 * droped the last fragment (when self->rx_sdu_size exceed
 	 * self->rx_max_sdu_size), where n < self->rx_sdu_size.
 	 * Jean II */
-	ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);
+	IRDA_ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);
 
 	/* Set the new length */
 	skb_trim(skb, n);
@@ -298,9 +299,9 @@ static inline void irttp_fragment_skb(st
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	/*
 	 *  Split frame into a number of segments
@@ -353,8 +354,8 @@ static int irttp_param_max_sdu_size(void
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	if (get)
 		param->pv.i = self->tx_max_sdu_size;
@@ -381,8 +382,8 @@ struct tsap_cb *irttp_open_tsap(__u8 sts
 	struct lsap_cb *lsap;
 	notify_t ttp_notify;
 
-	ASSERT(irttp != NULL, return NULL;);
-	ASSERT(irttp->magic == TTP_MAGIC, return NULL;);
+	IRDA_ASSERT(irttp != NULL, return NULL;);
+	IRDA_ASSERT(irttp->magic == TTP_MAGIC, return NULL;);
 
 	/* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to
 	 * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well.
@@ -430,7 +431,7 @@ struct tsap_cb *irttp_open_tsap(__u8 sts
 	 */
 	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
 	if (lsap == NULL) {
-		WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__);
+		IRDA_WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -466,8 +467,8 @@ EXPORT_SYMBOL(irttp_open_tsap);
 static void __irttp_close_tsap(struct tsap_cb *self)
 {
 	/* First make sure we're connected. */
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	irttp_flush_queues(self);
 
@@ -500,14 +501,15 @@ int irttp_close_tsap(struct tsap_cb *sel
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	/* Make sure tsap has been disconnected */
 	if (self->connected) {
 		/* Check if disconnect is not pending */
 		if (!test_bit(0, &self->disconnect_pend)) {
-			WARNING("%s: TSAP still connected!\n", __FUNCTION__);
+			IRDA_WARNING("%s: TSAP still connected!\n",
+				     __FUNCTION__);
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
@@ -518,7 +520,7 @@ int irttp_close_tsap(struct tsap_cb *sel
 
 	tsap = hashbin_remove(irttp->tsaps, (long) self, NULL);
 
-	ASSERT(tsap == self, return -1;);
+	IRDA_ASSERT(tsap == self, return -1;);
 
 	/* Close corresponding LSAP */
 	if (self->lsap) {
@@ -540,9 +542,9 @@ EXPORT_SYMBOL(irttp_close_tsap);
  */
 int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
@@ -582,16 +584,16 @@ int irttp_data_request(struct tsap_cb *s
 	__u8 *frame;
 	int ret;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
 		   skb_queue_len(&self->tx_queue));
 
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		WARNING("%s: No data, or not connected\n", __FUNCTION__);
+		IRDA_WARNING("%s: No data, or not connected\n", __FUNCTION__);
 		ret = -ENOTCONN;
 		goto err;
 	}
@@ -601,8 +603,8 @@ int irttp_data_request(struct tsap_cb *s
 	 *  inside an IrLAP frame
 	 */
 	if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
-		ERROR("%s: SAR disabled, and data is to large for IrLAP!\n",
-				__FUNCTION__);
+		IRDA_ERROR("%s: SAR disabled, and data is to large for IrLAP!\n",
+			   __FUNCTION__);
 		ret = -EMSGSIZE;
 		goto err;
 	}
@@ -615,8 +617,8 @@ int irttp_data_request(struct tsap_cb *s
 	    (self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&
 	    (skb->len > self->tx_max_sdu_size))
 	{
-		ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
-		      __FUNCTION__);
+		IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
+			   __FUNCTION__);
 		ret = -EMSGSIZE;
 		goto err;
 	}
@@ -638,7 +640,7 @@ int irttp_data_request(struct tsap_cb *s
 	/* Queue frame, or queue frame segments */
 	if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) {
 		/* Queue frame */
-		ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);
+		IRDA_ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);
 		frame = skb_push(skb, TTP_HEADER);
 		frame[0] = 0x00; /* Clear more bit */
 
@@ -800,8 +802,8 @@ static inline void irttp_give_credit(str
 	unsigned long flags;
 	int n;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n",
 		   __FUNCTION__,
@@ -857,9 +859,9 @@ static int irttp_udata_indication(void *
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(skb != NULL, return -1;);
 
 	self->stats.rx_packets++;
 
@@ -974,8 +976,8 @@ static void irttp_status_indication(void
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	/* Check if client has already closed the TSAP and gone away */
 	if (self->close_pend)
@@ -1003,8 +1005,8 @@ static void irttp_flow_indication(void *
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);
 
@@ -1046,8 +1048,8 @@ void irttp_flow_request(struct tsap_cb *
 {
 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	switch (flow) {
 	case FLOW_STOP:
@@ -1086,8 +1088,8 @@ int irttp_connect_request(struct tsap_cb
 
 	IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __FUNCTION__, max_sdu_size);
 
-	ASSERT(self != NULL, return -EBADR;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
+	IRDA_ASSERT(self != NULL, return -EBADR;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
 
 	if (self->connected) {
 		if(userdata)
@@ -1109,8 +1111,8 @@ int irttp_connect_request(struct tsap_cb
 		 *  Check that the client has reserved enough space for
 		 *  headers
 		 */
-		ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
-		       { dev_kfree_skb(userdata); return -1; } );
+		IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
+			{ dev_kfree_skb(userdata); return -1; } );
 	}
 
 	/* Initialize connection parameters */
@@ -1138,8 +1140,8 @@ int irttp_connect_request(struct tsap_cb
 
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
-		ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
-		       { dev_kfree_skb(tx_skb); return -1; } );
+		IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
+			{ dev_kfree_skb(tx_skb); return -1; } );
 
 		/* Insert SAR parameters */
 		frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
@@ -1185,9 +1187,9 @@ static void irttp_connect_confirm(void *
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	self->max_seg_size = max_seg_size - TTP_HEADER;
 	self->max_header_size = max_header_size + TTP_HEADER;
@@ -1213,7 +1215,7 @@ static void irttp_connect_confirm(void *
 
 	parameters = skb->data[0] & 0x80;
 
-	ASSERT(skb->len >= TTP_HEADER, return;);
+	IRDA_ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
 
 	if (parameters) {
@@ -1225,8 +1227,8 @@ static void irttp_connect_confirm(void *
 
 		/* Any errors in the parameter list? */
 		if (ret < 0) {
-			WARNING("%s: error extracting parameters\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: error extracting parameters\n",
+				     __FUNCTION__);
 			dev_kfree_skb(skb);
 
 			/* Do not accept this connection attempt */
@@ -1269,9 +1271,9 @@ void irttp_connect_indication(void *inst
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(skb != NULL, return;);
 
 	lsap = (struct lsap_cb *) sap;
 
@@ -1290,7 +1292,7 @@ void irttp_connect_indication(void *inst
 
 	parameters = skb->data[0] & 0x80;
 
-	ASSERT(skb->len >= TTP_HEADER, return;);
+	IRDA_ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
 
 	if (parameters) {
@@ -1302,8 +1304,8 @@ void irttp_connect_indication(void *inst
 
 		/* Any errors in the parameter list? */
 		if (ret < 0) {
-			WARNING("%s: error extracting parameters\n",
-					__FUNCTION__);
+			IRDA_WARNING("%s: error extracting parameters\n",
+				     __FUNCTION__);
 			dev_kfree_skb(skb);
 
 			/* Do not accept this connection attempt */
@@ -1337,8 +1339,8 @@ int irttp_connect_response(struct tsap_c
 	int ret;
 	__u8 n;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __FUNCTION__,
 		   self->stsap_sel);
@@ -1357,8 +1359,8 @@ int irttp_connect_response(struct tsap_c
 		 *  Check that the client has reserved enough space for
 		 *  headers
 		 */
-		ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
-		       { dev_kfree_skb(userdata); return -1; } );
+		IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
+			{ dev_kfree_skb(userdata); return -1; } );
 	}
 
 	self->avail_credit = 0;
@@ -1380,8 +1382,8 @@ int irttp_connect_response(struct tsap_c
 
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
-		ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
-		       { dev_kfree_skb(tx_skb); return -1; } );
+		IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
+			{ dev_kfree_skb(tx_skb); return -1; } );
 
 		/* Insert TTP header with SAR parameters */
 		frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
@@ -1481,8 +1483,8 @@ int irttp_disconnect_request(struct tsap
 {
 	int ret;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	/* Already disconnected? */
 	if (!self->connected) {
@@ -1579,8 +1581,8 @@ void irttp_disconnect_indication(void *i
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	/* Prevent higher layer to send more data */
 	self->connected = FALSE;
@@ -1879,7 +1881,7 @@ static int irttp_seq_open(struct inode *
 	int rc = -ENOMEM;
 	struct irttp_iter_state *s;
        
-	ASSERT(irttp != NULL, return -EINVAL;);
+	IRDA_ASSERT(irttp != NULL, return -EINVAL;);
 
 	s = kmalloc(sizeof(*s), GFP_KERNEL);
 	if (!s)
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -160,7 +160,8 @@ static int irda_insert_integer(void *sel
 	}
 	/* Check if buffer is long enough for insertion */
 	if (len < (2+p.pl)) {
-		WARNING("%s: buffer to short for insertion!\n", __FUNCTION__);
+		IRDA_WARNING("%s: buffer to short for insertion!\n",
+			     __FUNCTION__);
 		return -1;
 	}
 	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
@@ -185,7 +186,8 @@ static int irda_insert_integer(void *sel
 
 		break;
 	default:
-		WARNING("%s: length %d not supported\n", __FUNCTION__, p.pl);
+		IRDA_WARNING("%s: length %d not supported\n",
+			     __FUNCTION__, p.pl);
 		/* Skip parameter */
 		return -1;
 	}
@@ -214,9 +216,9 @@ static int irda_extract_integer(void *se
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		WARNING("%s: buffer to short for parsing! "
-			"Need %d bytes, but len is only %d\n",
-			__FUNCTION__, p.pl, len);
+		IRDA_WARNING("%s: buffer to short for parsing! "
+			     "Need %d bytes, but len is only %d\n",
+			     __FUNCTION__, p.pl, len);
 		return -1;
 	}
 
@@ -226,9 +228,9 @@ static int irda_extract_integer(void *se
 	 * PV_INTEGER means that the handler is flexible.
 	 */
 	if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
-		ERROR("%s: invalid parameter length! "
-		      "Expected %d bytes, but value had %d bytes!\n",
-		      __FUNCTION__, type & PV_MASK, p.pl);
+		IRDA_ERROR("%s: invalid parameter length! "
+			   "Expected %d bytes, but value had %d bytes!\n",
+			   __FUNCTION__, type & PV_MASK, p.pl);
 
 		/* Most parameters are bit/byte fields or little endian,
 		 * so it's ok to only extract a subset of it (the subset
@@ -265,7 +267,8 @@ static int irda_extract_integer(void *se
 			le32_to_cpus(&p.pv.i);
 		break;
 	default:
-		WARNING("%s: length %d not supported\n", __FUNCTION__, p.pl);
+		IRDA_WARNING("%s: length %d not supported\n",
+			     __FUNCTION__, p.pl);
 
 		/* Skip parameter */
 		return p.pl+2;
@@ -301,9 +304,9 @@ static int irda_extract_string(void *sel
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		WARNING("%s: buffer to short for parsing! "
-			"Need %d bytes, but len is only %d\n",
-			__FUNCTION__, p.pl, len);
+		IRDA_WARNING("%s: buffer to short for parsing! "
+			     "Need %d bytes, but len is only %d\n",
+			     __FUNCTION__, p.pl, len);
 		return -1;
 	}
 
@@ -340,9 +343,9 @@ static int irda_extract_octseq(void *sel
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		WARNING("%s: buffer to short for parsing! "
-			"Need %d bytes, but len is only %d\n",
-			__FUNCTION__, p.pl, len);
+		IRDA_WARNING("%s: buffer to short for parsing! "
+			     "Need %d bytes, but len is only %d\n",
+			     __FUNCTION__, p.pl, len);
 		return -1;
 	}
 
@@ -459,8 +462,8 @@ int irda_param_insert(void *self, __u8 p
 	int ret = -1;
 	int n = 0;
 
-	ASSERT(buf != NULL, return ret;);
-	ASSERT(info != 0, return ret;);
+	IRDA_ASSERT(buf != NULL, return ret;);
+	IRDA_ASSERT(info != 0, return ret;);
 
 	pi_minor = pi & info->pi_mask;
 	pi_major = pi >> info->pi_major_offset;
@@ -484,7 +487,7 @@ int irda_param_insert(void *self, __u8 p
 
 	/*  Check if handler has been implemented */
 	if (!pi_minor_info->func) {
-		MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi);
+		IRDA_MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi);
 		/* Skip this parameter */
 		return -1;
 	}
@@ -513,8 +516,8 @@ static int irda_param_extract(void *self
 	int ret = -1;
 	int n = 0;
 
-	ASSERT(buf != NULL, return ret;);
-	ASSERT(info != 0, return ret;);
+	IRDA_ASSERT(buf != NULL, return ret;);
+	IRDA_ASSERT(info != 0, return ret;);
 
 	pi_minor = buf[n] & info->pi_mask;
 	pi_major = buf[n] >> info->pi_major_offset;
@@ -541,7 +544,8 @@ static int irda_param_extract(void *self
 
 	/*  Check if handler has been implemented */
 	if (!pi_minor_info->func) {
-		MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, buf[n]);
+		IRDA_MESSAGE("%s: no handler for pi=%#x\n",
+			     __FUNCTION__, buf[n]);
 		/* Skip this parameter */
 		return 2 + buf[n + 1]; /* Continue */
 	}
@@ -565,8 +569,8 @@ int irda_param_extract_all(void *self, _
 	int ret = -1;
 	int n = 0;
 
-	ASSERT(buf != NULL, return ret;);
-	ASSERT(info != 0, return ret;);
+	IRDA_ASSERT(buf != NULL, return ret;);
+	IRDA_ASSERT(info != 0, return ret;);
 
 	/*
 	 * Parse all parameters. Each parameter must be at least two bytes
diff --git a/net/irda/qos.c b/net/irda/qos.c
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -200,7 +200,7 @@ static int msb_index (__u16 word) 
 	 * able to check precisely what's going on. If a end user sees this,
 	 * it's very likely the peer. - Jean II */
 	if (word == 0) {
-		WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
+		IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
 			 __FUNCTION__);
 		/* The only safe choice (we don't know the array size) */
 		word = 0x1;
@@ -278,8 +278,8 @@ static inline int value_highest_bit(__u3
  */
 void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
 {
-	ASSERT(qos != NULL, return;);
-	ASSERT(new != NULL, return;);
+	IRDA_ASSERT(qos != NULL, return;);
+	IRDA_ASSERT(new != NULL, return;);
 
 	/* Apply */
 	qos->baud_rate.bits       &= new->baud_rate.bits;
@@ -351,7 +351,7 @@ static void irlap_adjust_qos_settings(st
 	if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
 		int i;
 
-		WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
+		IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
 			 __FUNCTION__, sysctl_min_tx_turn_time);
 
 		/* We don't really need bits, but easier this way */
@@ -390,7 +390,7 @@ static void irlap_adjust_qos_settings(st
 	}
 #else /* Use method described in section 6.6.11 of IrLAP */
 	while (irlap_requested_line_capacity(qos) > line_capacity) {
-		ASSERT(index != 0, return;);
+		IRDA_ASSERT(index != 0, return;);
 
 		/* Must be able to send at least one frame */
 		if (qos->window_size.value > 1) {
@@ -402,8 +402,8 @@ static void irlap_adjust_qos_settings(st
 			IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
 				   __FUNCTION__, qos->data_size.value);
 		} else {
-			WARNING("%s(), nothing more we can do!\n",
-				__FUNCTION__);
+			IRDA_WARNING("%s(), nothing more we can do!\n",
+				     __FUNCTION__);
 		}
 	}
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
@@ -532,8 +532,8 @@ static int irlap_param_baud_rate(void *i
 
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	if (get) {
 		param->pv.i = self->qos_rx.baud_rate.bits;
@@ -568,8 +568,8 @@ static int irlap_param_link_disconnect(v
 	
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.link_disc_time.bits;
@@ -600,8 +600,8 @@ static int irlap_param_max_turn_time(voi
 {
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.max_turn_time.bits;
@@ -622,8 +622,8 @@ static int irlap_param_data_size(void *i
 {
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.data_size.bits;
@@ -645,8 +645,8 @@ static int irlap_param_window_size(void 
 {
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.window_size.bits;
@@ -666,8 +666,8 @@ static int irlap_param_additional_bofs(v
 {
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.additional_bofs.bits;
@@ -688,8 +688,8 @@ static int irlap_param_min_turn_time(voi
 {
 	struct irlap_cb *self = (struct irlap_cb *) instance;
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	IRDA_ASSERT(self != NULL, return -1;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
 	if (get)
 		param->pv.i = self->qos_rx.min_turn_time.bits;
@@ -716,8 +716,8 @@ __u32 irlap_max_line_capacity(__u32 spee
 	i = value_index(speed, baud_rates, 10);
 	j = value_index(max_turn_time, max_turn_times, 4);
 
-	ASSERT(((i >=0) && (i <10)), return 0;);
-	ASSERT(((j >=0) && (j <4)), return 0;);
+	IRDA_ASSERT(((i >=0) && (i <10)), return 0;);
+	IRDA_ASSERT(((j >=0) && (j <4)), return 0;);
 
 	line_capacity = max_line_capacities[i][j];
 
@@ -748,7 +748,7 @@ void irda_qos_bits_to_value(struct qos_i
 {
 	int index;
 
-	ASSERT(qos != NULL, return;);
+	IRDA_ASSERT(qos != NULL, return;);
 	
 	index = msb_index(qos->baud_rate.bits);
 	qos->baud_rate.value = baud_rates[index];
diff --git a/net/irda/timer.c b/net/irda/timer.c
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -144,8 +144,8 @@ static void irlap_slot_timer_expired(voi
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlap_do_event(self, SLOT_TIMER_EXPIRED, NULL, NULL);
 } 
@@ -160,8 +160,8 @@ static void irlap_query_timer_expired(vo
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlap_do_event(self, QUERY_TIMER_EXPIRED, NULL, NULL);
 } 
@@ -176,8 +176,8 @@ static void irlap_final_timer_expired(vo
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	irlap_do_event(self, FINAL_TIMER_EXPIRED, NULL, NULL);
 }
@@ -192,8 +192,8 @@ static void irlap_wd_timer_expired(void 
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 	
 	irlap_do_event(self, WD_TIMER_EXPIRED, NULL, NULL);
 }
@@ -208,8 +208,8 @@ static void irlap_backoff_timer_expired(
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
+	IRDA_ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 	
 	irlap_do_event(self, BACKOFF_TIMER_EXPIRED, NULL, NULL);
 }
@@ -224,7 +224,7 @@ void irlap_media_busy_expired(void* data
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	ASSERT(self != NULL, return;);
+	IRDA_ASSERT(self != NULL, return;);
 
 	irda_device_set_media_busy(self->netdev, FALSE);
 	/* Note : the LAP event will be send in irlap_stop_mbusy_timer(),
diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c
--- a/net/irda/wrapper.c
+++ b/net/irda/wrapper.c
@@ -133,7 +133,11 @@ int async_wrap_skb(struct sk_buff *skb, 
 		 *  bufsize-5 since the maximum number of bytes that can be
 		 *  transmitted after this point is 5.
 		 */
-		ASSERT(n < (buffsize-5), return n;);
+		if(n >= (buffsize-5)) {
+			IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n",
+				   __FUNCTION__, n);
+			return n;
+		}
 
 		n += stuff_byte(skb->data[i], tx_buff+n);
 		fcs.value = irda_fcs(fcs.value, skb->data[i]);
@@ -381,7 +385,7 @@ async_unwrap_ce(struct net_device *dev,
 		break;
 
 	case LINK_ESCAPE:
-		WARNING("%s: state not defined\n", __FUNCTION__);
+		IRDA_WARNING("%s: state not defined\n", __FUNCTION__);
 		break;
 
 	case BEGIN_FRAME:
diff --git a/net/key/af_key.c b/net/key/af_key.c
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -42,11 +42,17 @@ static atomic_t pfkey_table_users = ATOM
 
 static atomic_t pfkey_socks_nr = ATOMIC_INIT(0);
 
-struct pfkey_opt {
-	int	registered;
-	int	promisc;
+struct pfkey_sock {
+	/* struct sock must be the first member of struct pfkey_sock */
+	struct sock	sk;
+	int		registered;
+	int		promisc;
 };
-#define pfkey_sk(__sk) ((struct pfkey_opt *)(__sk)->sk_protinfo)
+
+static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
+{
+	return (struct pfkey_sock *)sk;
+}
 
 static void pfkey_sock_destruct(struct sock *sk)
 {
@@ -60,8 +66,6 @@ static void pfkey_sock_destruct(struct s
 	BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
 	BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
 
-	kfree(pfkey_sk(sk));
-
 	atomic_dec(&pfkey_socks_nr);
 }
 
@@ -125,10 +129,15 @@ static void pfkey_remove(struct sock *sk
 	pfkey_table_ungrab();
 }
 
+static struct proto key_proto = {
+	.name	  = "KEY",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct pfkey_sock),
+};
+
 static int pfkey_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct pfkey_opt *pfk;
 	int err;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -139,21 +148,12 @@ static int pfkey_create(struct socket *s
 		return -EPROTONOSUPPORT;
 
 	err = -ENOMEM;
-	sk = sk_alloc(PF_KEY, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1);
 	if (sk == NULL)
 		goto out;
 	
 	sock->ops = &pfkey_ops;
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
-
-	err = -ENOMEM;
-	pfk = sk->sk_protinfo = kmalloc(sizeof(*pfk), GFP_KERNEL);
-	if (!pfk) {
-		sk_free(sk);
-		goto out;
-	}
-	memset(pfk, 0, sizeof(*pfk));
 
 	sk->sk_family = PF_KEY;
 	sk->sk_destruct = pfkey_sock_destruct;
@@ -233,7 +233,7 @@ static int pfkey_broadcast(struct sk_buf
 
 	pfkey_lock_table();
 	sk_for_each(sk, node, &pfkey_table) {
-		struct pfkey_opt *pfk = pfkey_sk(sk);
+		struct pfkey_sock *pfk = pfkey_sk(sk);
 		int err2;
 
 		/* Yes, it means that if you are meant to receive this
@@ -598,7 +598,7 @@ static struct sk_buff * pfkey_xfrm_state
 	/* address family check */
 	sockaddr_size = pfkey_sockaddr_size(x->props.family);
 	if (!sockaddr_size)
-		ERR_PTR(-EINVAL);
+		return ERR_PTR(-EINVAL);
 
 	/* base, SA, (lifetime (HSC),) address(SD), (address(P),)
 	   key(AE), (identity(SD),) (sensitivity)> */
@@ -1418,7 +1418,7 @@ out_put_algs:
 
 static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
-	struct pfkey_opt *pfk = pfkey_sk(sk);
+	struct pfkey_sock *pfk = pfkey_sk(sk);
 	struct sk_buff *supp_skb;
 
 	if (hdr->sadb_msg_satype > SADB_SATYPE_MAX)
@@ -1514,7 +1514,7 @@ static int pfkey_dump(struct sock *sk, s
 
 static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
-	struct pfkey_opt *pfk = pfkey_sk(sk);
+	struct pfkey_sock *pfk = pfkey_sk(sk);
 	int satype = hdr->sadb_msg_satype;
 
 	if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) {
@@ -2863,16 +2863,38 @@ static void __exit ipsec_pfkey_exit(void
 	xfrm_unregister_km(&pfkeyv2_mgr);
 	remove_proc_entry("net/pfkey", NULL);
 	sock_unregister(PF_KEY);
+	proto_unregister(&key_proto);
 }
 
 static int __init ipsec_pfkey_init(void)
 {
-	sock_register(&pfkey_family_ops);
+	int err = proto_register(&key_proto, 0);
+
+	if (err != 0)
+		goto out;
+
+	err = sock_register(&pfkey_family_ops);
+	if (err != 0)
+		goto out_unregister_key_proto;
 #ifdef CONFIG_PROC_FS
-	create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL);
+	err = -ENOMEM;
+	if (create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL) == NULL)
+		goto out_sock_unregister;
 #endif
-	xfrm_register_km(&pfkeyv2_mgr);
-	return 0;
+	err = xfrm_register_km(&pfkeyv2_mgr);
+	if (err != 0)
+		goto out_remove_proc_entry;
+out:
+	return err;
+out_remove_proc_entry:
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("net/pfkey", NULL);
+out_sock_unregister:
+#endif
+	sock_unregister(PF_KEY);
+out_unregister_key_proto:
+	proto_unregister(&key_proto);
+	goto out;
 }
 
 module_init(ipsec_pfkey_init);
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -113,7 +113,7 @@ static __inline__ u8 llc_ui_header_len(s
  */
 static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
 {
-	struct llc_opt* llc = llc_sk(sk);
+	struct llc_sock* llc = llc_sk(sk);
 	int rc = 0;
 
 	if (llc_data_accept_state(llc->state) || llc->p_flag) {
@@ -135,6 +135,12 @@ static void llc_ui_sk_init(struct socket
 	sock->ops	= &llc_ui_ops;
 }
 
+static struct proto llc_proto = {
+	.name	  = "DDP",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct llc_sock),
+};
+
 /**
  *	llc_ui_create - alloc and init a new llc_ui socket
  *	@sock: Socket to initialize and attach allocated sk to.
@@ -151,7 +157,7 @@ static int llc_ui_create(struct socket *
 
 	if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
 		rc = -ENOMEM;
-		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
+		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto);
 		if (sk) {
 			rc = 0;
 			llc_ui_sk_init(sock, sk);
@@ -169,7 +175,7 @@ static int llc_ui_create(struct socket *
 static int llc_ui_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc;
+	struct llc_sock *llc;
 
 	if (!sk)
 		goto out;
@@ -180,7 +186,7 @@ static int llc_ui_release(struct socket 
 		llc->laddr.lsap, llc->daddr.lsap);
 	if (!llc_send_disc(sk))
 		llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
-	if (!sk->sk_zapped)
+	if (!sock_flag(sk, SOCK_ZAPPED))
 		llc_sap_remove_socket(llc->sap, sk);
 	release_sock(sk);
 	if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) {
@@ -244,11 +250,11 @@ out:
 static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap;
 	int rc = -EINVAL;
 
-	if (!sk->sk_zapped)
+	if (!sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 	rc = -ENODEV;
 	llc->dev = dev_getfirstbyhwtype(addr->sllc_arphrd);
@@ -266,7 +272,8 @@ static int llc_ui_autobind(struct socket
 	memcpy(&llc->addr, addr, sizeof(llc->addr));
 	/* assign new connection to its SAP */
 	llc_sap_add_socket(sap, sk);
-	rc = sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
+	rc = 0;
 out:
 	return rc;
 }
@@ -293,12 +300,12 @@ static int llc_ui_bind(struct socket *so
 {
 	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap;
 	int rc = -EINVAL;
 
 	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap);
-	if (!sk->sk_zapped || addrlen != sizeof(*addr))
+	if (!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr))
 		goto out;
 	rc = -EAFNOSUPPORT;
 	if (addr->sllc_family != AF_LLC)
@@ -339,7 +346,8 @@ static int llc_ui_bind(struct socket *so
 	memcpy(&llc->addr, addr, sizeof(llc->addr));
 	/* assign new connection to its SAP */
 	llc_sap_add_socket(sap, sk);
-	rc = sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
+	rc = 0;
 out:
 	return rc;
 }
@@ -394,7 +402,7 @@ static int llc_ui_connect(struct socket 
 			  int addrlen, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
 	struct net_device *dev;
 	int rc = -EINVAL;
@@ -406,7 +414,7 @@ static int llc_ui_connect(struct socket 
 	if (addr->sllc_family != AF_LLC)
 		goto out;
 	/* bind connection to sap if user hasn't done it. */
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		/* bind to sap with null dev, exclusive */
 		rc = llc_ui_autobind(sock, addr);
 		if (rc)
@@ -459,7 +467,7 @@ static int llc_ui_listen(struct socket *
 	if (sk->sk_type != SOCK_STREAM)
 		goto out;
 	rc = -EAGAIN;
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 	rc = 0;
 	if (!(unsigned)backlog)	/* BSDism */
@@ -571,7 +579,7 @@ static int llc_ui_wait_for_data(struct s
 static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int rc;
 
 	add_wait_queue_exclusive(sk->sk_sleep, &wait);
@@ -612,7 +620,7 @@ static int llc_ui_wait_for_busy_core(str
 static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	struct sock *sk = sock->sk, *newsk;
-	struct llc_opt *llc, *newllc;
+	struct llc_sock *llc, *newllc;
 	struct sk_buff *skb;
 	int rc = -EOPNOTSUPP;
 
@@ -638,7 +646,7 @@ static int llc_ui_accept(struct socket *
 	newsk = skb->sk;
 	/* attach connection to a new socket. */
 	llc_ui_sk_init(newsock, newsk);
-	newsk->sk_zapped	= 0;
+	sock_reset_flag(newsk, SOCK_ZAPPED);
 	newsk->sk_state		= TCP_ESTABLISHED;
 	newsock->state		= SS_CONNECTED;
 	llc			= llc_sk(sk);
@@ -728,7 +736,7 @@ static int llc_ui_sendmsg(struct kiocb *
 			  struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
 	int flags = msg->msg_flags;
 	int noblock = flags & MSG_DONTWAIT;
@@ -749,7 +757,7 @@ static int llc_ui_sendmsg(struct kiocb *
 		addr = &llc->addr;
 	}
 	/* must bind connection to sap if user hasn't done it. */
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		/* bind to sap with null dev, exclusive. */
 		rc = llc_ui_autobind(sock, addr);
 		if (rc)
@@ -819,11 +827,11 @@ static int llc_ui_getname(struct socket 
 {
 	struct sockaddr_llc sllc;
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int rc = 0;
 
 	lock_sock(sk);
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 	*uaddrlen = sizeof(sllc);
 	memset(uaddr, 0, *uaddrlen);
@@ -883,7 +891,7 @@ static int llc_ui_setsockopt(struct sock
 			     char __user *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int rc = -EINVAL, opt;
 
 	lock_sock(sk);
@@ -958,7 +966,7 @@ static int llc_ui_getsockopt(struct sock
 			     char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int val = 0, len = 0, rc = -EINVAL;
 
 	lock_sock(sk);
@@ -1031,18 +1039,25 @@ extern void llc_conn_handler(struct llc_
 
 static int __init llc2_init(void)
 {
-	int rc;
+	int rc = proto_register(&llc_proto, 0);
+
+	if (rc != 0)
+		goto out;
 
 	llc_build_offset_table();
 	llc_station_init();
 	llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
 	rc = llc_proc_init();
-	if (!rc) {
-		sock_register(&llc_ui_family_ops);
-		llc_add_pack(LLC_DEST_SAP, llc_sap_handler);
-		llc_add_pack(LLC_DEST_CONN, llc_conn_handler);
-	}
+	if (rc != 0)
+		goto out_unregister_llc_proto;
+	sock_register(&llc_ui_family_ops);
+	llc_add_pack(LLC_DEST_SAP, llc_sap_handler);
+	llc_add_pack(LLC_DEST_CONN, llc_conn_handler);
+out:
 	return rc;
+out_unregister_llc_proto:
+	proto_unregister(&llc_proto);
+	goto out;
 }
 
 static void __exit llc2_exit(void)
@@ -1052,6 +1067,7 @@ static void __exit llc2_exit(void)
 	llc_remove_pack(LLC_DEST_CONN);
 	sock_unregister(PF_LLC);
 	llc_proc_exit();
+	proto_unregister(&llc_proto);
 }
 
 module_init(llc2_init);
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -44,7 +44,7 @@ static int llc_conn_ac_set_p_flag_1(stru
 
 int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc->remote_busy_flag) {
 		u8 nr;
@@ -68,7 +68,7 @@ int llc_conn_ac_conn_ind(struct sock *sk
 	sap = llc_sap_find(dsap);
 	if (sap) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 
 		llc_pdu_decode_sa(skb, llc->daddr.mac);
 		llc_pdu_decode_da(skb, llc->laddr.mac);
@@ -146,7 +146,7 @@ int llc_conn_ac_rst_ind(struct sock *sk,
 	int rc = 1;
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	switch (ev->type) {
 	case LLC_CONN_EV_TYPE_PDU:
@@ -207,7 +207,7 @@ int llc_conn_ac_clear_remote_busy_if_f_e
 int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
 					       struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc->data_flag == 2)
 		del_timer(&llc->rej_sent_timer.timer);
@@ -220,7 +220,7 @@ int llc_conn_ac_send_disc_cmd_p_set_x(st
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -246,7 +246,7 @@ int llc_conn_ac_send_dm_rsp_f_set_p(stru
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit;
 
@@ -273,7 +273,7 @@ int llc_conn_ac_send_dm_rsp_f_set_1(stru
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
@@ -299,7 +299,7 @@ int llc_conn_ac_send_frmr_rsp_f_set_x(st
 	int rc = -ENOBUFS;
 	struct sk_buff *nskb;
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc->rx_pdu_hdr = *((u32 *)pdu);
 	if (LLC_PDU_IS_CMD(pdu))
@@ -334,7 +334,7 @@ int llc_conn_ac_resend_frmr_rsp_f_set_0(
 
 	if (nskb) {
 		u8 f_bit = 0;
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)&llc->rx_pdu_hdr;
 
@@ -364,7 +364,7 @@ int llc_conn_ac_resend_frmr_rsp_f_set_p(
 	llc_pdu_decode_pf_bit(skb, &f_bit);
 	nskb = llc_alloc_frame();
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -388,7 +388,7 @@ free:
 int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
 {
 	int rc;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
@@ -405,7 +405,7 @@ int llc_conn_ac_send_i_cmd_p_set_1(struc
 static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
@@ -422,7 +422,7 @@ static int llc_conn_ac_send_i_cmd_p_set_
 int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
 {
 	int rc;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
@@ -454,7 +454,7 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -490,7 +490,7 @@ int llc_conn_ac_send_rej_cmd_p_set_1(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -516,7 +516,7 @@ int llc_conn_ac_send_rej_rsp_f_set_1(str
 
 	if (nskb) {
 		u8 f_bit = 1;
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -541,7 +541,7 @@ int llc_conn_ac_send_rej_xxx_x_set_0(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 0;
 
@@ -567,7 +567,7 @@ int llc_conn_ac_send_rnr_cmd_p_set_1(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -592,7 +592,7 @@ int llc_conn_ac_send_rnr_rsp_f_set_1(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
@@ -619,7 +619,7 @@ int llc_conn_ac_send_rnr_xxx_x_set_0(str
 
 	if (nskb) {
 		u8 f_bit = 0;
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -640,7 +640,7 @@ free:
 
 int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (!llc->remote_busy_flag) {
 		llc->remote_busy_flag = 1;
@@ -656,7 +656,7 @@ int llc_conn_ac_opt_send_rnr_xxx_x_set_0
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -681,7 +681,7 @@ int llc_conn_ac_send_rr_cmd_p_set_1(stru
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -706,7 +706,7 @@ int llc_conn_ac_send_rr_rsp_f_set_1(stru
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
@@ -732,7 +732,7 @@ int llc_conn_ac_send_ack_rsp_f_set_1(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 		u8 f_bit = 1;
 
@@ -758,7 +758,7 @@ int llc_conn_ac_send_rr_xxx_x_set_0(stru
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -783,7 +783,7 @@ int llc_conn_ac_send_ack_xxx_x_set_0(str
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -816,7 +816,7 @@ int llc_conn_ac_send_sabme_cmd_p_set_x(s
 {
 	int rc = -ENOBUFS;
 	struct sk_buff *nskb = llc_alloc_frame();
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (nskb) {
 		struct llc_sap *sap = llc->sap;
@@ -849,7 +849,7 @@ int llc_conn_ac_send_ua_rsp_f_set_p(stru
 
 	llc_pdu_decode_pf_bit(skb, &f_bit);
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -882,7 +882,7 @@ int llc_conn_ac_set_s_flag_1(struct sock
 
 int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc_conn_set_p_flag(sk, 1);
 	mod_timer(&llc->pf_cycle_timer.timer,
@@ -903,7 +903,7 @@ int llc_conn_ac_start_p_timer(struct soc
 int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb)
 {
 	u8 pf_bit;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc_pdu_decode_pf_bit(skb, &pf_bit);
 	llc->ack_pf |= pf_bit & 1;
@@ -950,7 +950,7 @@ static int llc_conn_ac_send_i_rsp_f_set_
 					      struct sk_buff *skb)
 {
 	int rc;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_sap *sap = llc->sap;
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
@@ -976,7 +976,7 @@ static int llc_conn_ac_send_i_rsp_f_set_
  */
 int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc->ack_must_be_send) {
 		llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
@@ -1004,7 +1004,7 @@ static int llc_conn_ac_send_rr_rsp_f_set
 	struct sk_buff *nskb = llc_alloc_frame();
 
 	if (nskb) {
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		nskb->dev = llc->dev;
@@ -1035,7 +1035,7 @@ free:
  */
 static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (!llc->inc_cntr) {
 		llc->dec_step = 0;
@@ -1058,7 +1058,7 @@ static int llc_conn_ac_inc_npta_value(st
  */
 int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (!llc->connect_step && !llc->remote_busy_flag) {
 		if (!llc->dec_step) {
@@ -1084,7 +1084,7 @@ int llc_conn_ac_adjust_npta_by_rr(struct
  */
 int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc->remote_busy_flag)
 		if (!llc->dec_step) {
@@ -1109,7 +1109,7 @@ int llc_conn_ac_adjust_npta_by_rnr(struc
  */
 int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
 
 	llc->k -= unacked_pdu;
@@ -1128,7 +1128,7 @@ int llc_conn_ac_dec_tx_win_size(struct s
  */
 int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc->k += 1;
 	if (llc->k > 128)
@@ -1138,7 +1138,7 @@ int llc_conn_ac_inc_tx_win_size(struct s
 
 int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	del_timer(&llc->pf_cycle_timer.timer);
 	del_timer(&llc->ack_timer.timer);
@@ -1151,7 +1151,7 @@ int llc_conn_ac_stop_all_timers(struct s
 
 int llc_conn_ac_stop_other_timers(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	del_timer(&llc->rej_sent_timer.timer);
 	del_timer(&llc->pf_cycle_timer.timer);
@@ -1163,7 +1163,7 @@ int llc_conn_ac_stop_other_timers(struct
 
 int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire * HZ);
 	return 0;
@@ -1171,7 +1171,7 @@ int llc_conn_ac_start_ack_timer(struct s
 
 int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	mod_timer(&llc->rej_sent_timer.timer,
 		  jiffies + llc->rej_sent_timer.expire * HZ);
@@ -1181,7 +1181,7 @@ int llc_conn_ac_start_rej_timer(struct s
 int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
 					     struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (!timer_pending(&llc->ack_timer.timer))
 		mod_timer(&llc->ack_timer.timer,
@@ -1197,7 +1197,7 @@ int llc_conn_ac_stop_ack_timer(struct so
 
 int llc_conn_ac_stop_p_timer(struct sock *sk, struct sk_buff *skb)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	del_timer(&llc->pf_cycle_timer.timer);
 	llc_conn_set_p_flag(sk, 0);
@@ -1215,7 +1215,7 @@ int llc_conn_ac_upd_nr_received(struct s
 	int acked;
 	u16 unacked = 0;
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc->last_nr = PDU_SUPV_GET_Nr(pdu);
 	acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked);
diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
--- a/net/llc/llc_c_ev.c
+++ b/net/llc/llc_c_ev.c
@@ -78,7 +78,7 @@ static u16 llc_util_nr_inside_tx_window(
 	u8 nr1, nr2;
 	struct sk_buff *skb;
 	struct llc_pdu_sn *pdu;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int rc = 0;
 
 	if (llc->dev->flags & IFF_LOOPBACK)
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -53,7 +53,7 @@ static int llc_offset_table[NBR_CONN_STA
 int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 {
 	int rc;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
 	/*
@@ -221,7 +221,7 @@ void llc_conn_resend_i_pdu_as_cmd(struct
 	struct sk_buff *skb;
 	struct llc_pdu_sn *pdu;
 	u16 nbr_unack_pdus;
-	struct llc_opt *llc;
+	struct llc_sock *llc;
 	u8 howmany_resend = 0;
 
 	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
@@ -263,7 +263,7 @@ void llc_conn_resend_i_pdu_as_rsp(struct
 {
 	struct sk_buff *skb;
 	u16 nbr_unack_pdus;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	u8 howmany_resend = 0;
 
 	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
@@ -305,7 +305,7 @@ int llc_conn_remove_acked_pdus(struct so
 	struct sk_buff *skb;
 	struct llc_pdu_sn *pdu;
 	int nbr_acked = 0;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	int q_len = skb_queue_len(&llc->pdu_unack_q);
 
 	if (!q_len)
@@ -366,7 +366,7 @@ static void llc_conn_send_pdus(struct so
 static int llc_conn_service(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 1;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_conn_state_trans *trans;
 
 	if (llc->state > NBR_CONN_STATES)
@@ -399,7 +399,7 @@ static struct llc_conn_state_trans *llc_
 	struct llc_conn_state_trans **next_trans;
 	llc_conn_ev_qfyr_t *next_qualifier;
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct llc_conn_state *curr_state =
 					&llc_conn_state_table[llc->state - 1];
 
@@ -478,7 +478,7 @@ struct sock *llc_lookup_established(stru
 
 	read_lock_bh(&sap->sk_list.lock);
 	sk_for_each(rc, node, &sap->sk_list.list) {
-		struct llc_opt *llc = llc_sk(rc);
+		struct llc_sock *llc = llc_sk(rc);
 
 		if (llc->laddr.lsap == laddr->lsap &&
 		    llc->daddr.lsap == daddr->lsap &&
@@ -511,7 +511,7 @@ static struct sock *llc_lookup_listener(
 
 	read_lock_bh(&sap->sk_list.lock);
 	sk_for_each(rc, node, &sap->sk_list.list) {
-		struct llc_opt *llc = llc_sk(rc);
+		struct llc_sock *llc = llc_sk(rc);
 
 		if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
 		    llc->laddr.lsap == laddr->lsap &&
@@ -650,7 +650,7 @@ void llc_sap_remove_socket(struct llc_sa
 static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (!llc->dev)
 		llc->dev = skb->dev;
@@ -675,7 +675,7 @@ void llc_conn_handler(struct llc_sap *sa
 		 * Didn't find an active connection; verify if there
 		 * is a listening socket for this llc addr
 		 */
-		struct llc_opt *llc;
+		struct llc_sock *llc;
 		struct sock *parent = llc_lookup_listener(sap, &daddr);
 
 		if (!parent) {
@@ -683,7 +683,7 @@ void llc_conn_handler(struct llc_sap *sa
 			goto drop;
 		}
 
-		sk = llc_sk_alloc(parent->sk_family, GFP_ATOMIC);
+		sk = llc_sk_alloc(parent->sk_family, GFP_ATOMIC, parent->sk_prot);
 		if (!sk) {
 			sock_put(parent);
 			goto drop;
@@ -756,7 +756,7 @@ int llc_release_sockets(struct llc_sap *
 static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	int rc = 0;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc_backlog_type(skb) == LLC_PACKET) {
 		if (llc->state > 1) /* not closed */
@@ -786,17 +786,10 @@ out_kfree_skb:
  *
  *     Initializes a socket with default llc values.
  */
-static int llc_sk_init(struct sock* sk)
+static void llc_sk_init(struct sock* sk)
 {
-	struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
-	int rc = -ENOMEM;
+	struct llc_sock *llc = llc_sk(sk);
 
-	if (!llc)
-		goto out;
-	memset(llc, 0, sizeof(*llc));
-	rc = 0;
-
-	llc->sk	      = sk;
 	llc->state    = LLC_CONN_STATE_ADM;
 	llc->inc_cntr = llc->dec_cntr = 2;
 	llc->dec_step = llc->connect_step = 1;
@@ -827,9 +820,6 @@ static int llc_sk_init(struct sock* sk)
 		        * tx_win of remote LLC) */
 	skb_queue_head_init(&llc->pdu_unack_q);
 	sk->sk_backlog_rcv = llc_backlog_rcv;
-	sk->sk_protinfo = llc;
-out:
-	return rc;
 }
 
 /**
@@ -840,16 +830,14 @@ out:
  *	Allocates a LLC sock and initializes it. Returns the new LLC sock
  *	or %NULL if there's no memory available for one
  */
-struct sock *llc_sk_alloc(int family, int priority)
+struct sock *llc_sk_alloc(int family, int priority, struct proto *prot)
 {
-	struct sock *sk = sk_alloc(family, priority, 1, NULL);
+	struct sock *sk = sk_alloc(family, priority, prot, 1);
 
 	if (!sk)
 		goto out;
-	if (llc_sk_init(sk))
-		goto outsk;
+	llc_sk_init(sk);
 	sock_init_data(NULL, sk);
-	sk_set_owner(sk, THIS_MODULE);
 #ifdef LLC_REFCNT_DEBUG
 	atomic_inc(&llc_sock_nr);
 	printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
@@ -857,10 +845,6 @@ struct sock *llc_sk_alloc(int family, in
 #endif
 out:
 	return sk;
-outsk:
-	sk_free(sk);
-	sk = NULL;
-	goto out;
 }
 
 /**
@@ -871,7 +855,7 @@ outsk:
  */
 void llc_sk_free(struct sock *sk)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc->state = LLC_CONN_OUT_OF_SVC;
 	/* Stop all (possibly) running timers */
@@ -908,7 +892,7 @@ void llc_sk_free(struct sock *sk)
  */
 void llc_sk_reset(struct sock *sk)
 {
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	llc_conn_ac_stop_all_timers(sk, NULL);
 	skb_queue_purge(&sk->sk_write_queue);
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -45,7 +45,7 @@ int llc_build_and_send_pkt(struct sock *
 {
 	struct llc_conn_state_ev *ev;
 	int rc = -ECONNABORTED;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 
 	if (llc->state == LLC_CONN_STATE_ADM)
 		goto out;
@@ -86,7 +86,7 @@ int llc_establish_connection(struct sock
 	int rc = -EISCONN;
 	struct llc_addr laddr, daddr;
 	struct sk_buff *skb;
-	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sock *llc = llc_sk(sk);
 	struct sock *existing;
 
 	laddr.lsap = llc->sap->laddr.lsap;
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -65,7 +65,7 @@ static void *llc_seq_start(struct seq_fi
 static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct sock* sk, *next;
-	struct llc_opt *llc;
+	struct llc_sock *llc;
 	struct llc_sap *sap;
 
 	++*pos;
@@ -102,7 +102,7 @@ static void llc_seq_stop(struct seq_file
 {
 	if (v && v != SEQ_START_TOKEN) {
 		struct sock *sk = v;
-		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sock *llc = llc_sk(sk);
 		struct llc_sap *sap = llc->sap;
 
 		read_unlock_bh(&sap->sk_list.lock);
@@ -113,7 +113,7 @@ static void llc_seq_stop(struct seq_file
 static int llc_seq_socket_show(struct seq_file *seq, void *v)
 {
 	struct sock* sk;
-	struct llc_opt *llc;
+	struct llc_sock *llc;
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq, "SKt Mc local_mac_sap        remote_mac_sap   "
@@ -160,7 +160,7 @@ static char *llc_conn_state_names[] = {
 static int llc_seq_core_show(struct seq_file *seq, void *v)
 {
 	struct sock* sk;
-	struct llc_opt *llc;
+	struct llc_sock *llc;
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq, "Connection list:\n"
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -283,7 +283,7 @@ static struct sock *llc_lookup_dgram(str
 
 	read_lock_bh(&sap->sk_list.lock);
 	sk_for_each(rc, node, &sap->sk_list.list) {
-		struct llc_opt *llc = llc_sk(rc);
+		struct llc_sock *llc = llc_sk(rc);
 
 		if (rc->sk_type == SOCK_DGRAM &&
 		    llc->laddr.lsap == laddr->lsap &&
diff --git a/net/netlink/Makefile b/net/netlink/Makefile
--- a/net/netlink/Makefile
+++ b/net/netlink/Makefile
@@ -3,4 +3,3 @@
 #
 
 obj-y  				:= af_netlink.o
-obj-$(CONFIG_NETLINK_DEV)	+= netlink_dev.o
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -21,7 +21,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/major.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -50,30 +49,31 @@
 #include <linux/bitops.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/audit.h>
+
 #include <net/sock.h>
 #include <net/scm.h>
 
 #define Nprintk(a...)
 
-#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
-#define NL_EMULATE_DEV
-#endif
-
-struct netlink_opt
-{
+struct netlink_sock {
+	/* struct sock has to be the first member of netlink_sock */
+	struct sock		sk;
 	u32			pid;
 	unsigned int		groups;
 	u32			dst_pid;
 	unsigned int		dst_groups;
 	unsigned long		state;
-	int			(*handler)(int unit, struct sk_buff *skb);
 	wait_queue_head_t	wait;
 	struct netlink_callback	*cb;
 	spinlock_t		cb_lock;
 	void			(*data_ready)(struct sock *sk, int bytes);
 };
 
-#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo)
+static inline struct netlink_sock *nlk_sk(struct sock *sk)
+{
+	return (struct netlink_sock *)sk;
+}
 
 struct nl_pid_hash {
 	struct hlist_head *table;
@@ -122,8 +122,6 @@ static void netlink_sock_destruct(struct
 	BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
 	BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
 	BUG_TRAP(!nlk_sk(sk)->cb);
-
-	kfree(nlk_sk(sk));
 }
 
 /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP.
@@ -324,10 +322,16 @@ static void netlink_remove(struct sock *
 	netlink_table_ungrab();
 }
 
+static struct proto netlink_proto = {
+	.name	  = "NETLINK",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct netlink_sock),
+};
+
 static int netlink_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 
 	sock->state = SS_UNCONNECTED;
 
@@ -339,19 +343,13 @@ static int netlink_create(struct socket 
 
 	sock->ops = &netlink_ops;
 
-	sk = sk_alloc(PF_NETLINK, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
 	if (!sk)
 		return -ENOMEM;
 
-	sock_init_data(sock,sk);
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
-	nlk = sk->sk_protinfo = kmalloc(sizeof(*nlk), GFP_KERNEL);
-	if (!nlk) {
-		sk_free(sk);
-		return -ENOMEM;
-	}
-	memset(nlk, 0, sizeof(*nlk));
+	nlk = nlk_sk(sk);
 
 	spin_lock_init(&nlk->cb_lock);
 	init_waitqueue_head(&nlk->wait);
@@ -364,7 +362,7 @@ static int netlink_create(struct socket 
 static int netlink_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 
 	if (!sk)
 		return 0;
@@ -377,7 +375,6 @@ static int netlink_release(struct socket
 		nlk->cb->done(nlk->cb);
 		netlink_destroy_callback(nlk->cb);
 		nlk->cb = NULL;
-		__sock_put(sk);
 	}
 	spin_unlock(&nlk->cb_lock);
 
@@ -432,7 +429,6 @@ retry:
 	err = netlink_insert(sk, pid);
 	if (err == -EADDRINUSE)
 		goto retry;
-	nlk_sk(sk)->groups = 0;
 	return 0;
 }
 
@@ -445,7 +441,7 @@ static inline int netlink_capable(struct
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
 	int err;
 	
@@ -486,7 +482,7 @@ static int netlink_connect(struct socket
 {
 	int err = 0;
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	struct sockaddr_nl *nladdr=(struct sockaddr_nl*)addr;
 
 	if (addr->sa_family == AF_UNSPEC) {
@@ -517,7 +513,7 @@ static int netlink_connect(struct socket
 static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
 {
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	struct sockaddr_nl *nladdr=(struct sockaddr_nl *)addr;
 	
 	nladdr->nl_family = AF_NETLINK;
@@ -546,7 +542,7 @@ static struct sock *netlink_getsockbypid
 {
 	int protocol = ssk->sk_protocol;
 	struct sock *sock;
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 
 	sock = netlink_lookup(protocol, pid);
 	if (!sock)
@@ -566,13 +562,12 @@ static struct sock *netlink_getsockbypid
 struct sock *netlink_getsockbyfilp(struct file *filp)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct socket *socket;
 	struct sock *sock;
 
-	if (!inode->i_sock || !(socket = SOCKET_I(inode)))
+	if (!S_ISSOCK(inode->i_mode))
 		return ERR_PTR(-ENOTSOCK);
 
-	sock = socket->sk;
+	sock = SOCKET_I(inode)->sk;
 	if (sock->sk_family != AF_NETLINK)
 		return ERR_PTR(-EINVAL);
 
@@ -592,14 +587,10 @@ struct sock *netlink_getsockbyfilp(struc
  */
 int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo)
 {
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 
 	nlk = nlk_sk(sk);
 
-#ifdef NL_EMULATE_DEV
-	if (nlk->handler)
-		return 0;
-#endif
 	if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
 	    test_bit(0, &nlk->state)) {
 		DECLARE_WAITQUEUE(wait, current);
@@ -635,18 +626,10 @@ int netlink_attachskb(struct sock *sk, s
 
 int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol)
 {
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 	int len = skb->len;
 
 	nlk = nlk_sk(sk);
-#ifdef NL_EMULATE_DEV
-	if (nlk->handler) {
-		skb_orphan(skb);
-		len = nlk->handler(protocol, skb);
-		sock_put(sk);
-		return len;
-	}
-#endif
 
 	skb_queue_tail(&sk->sk_receive_queue, skb);
 	sk->sk_data_ready(sk, len);
@@ -710,13 +693,8 @@ retry:
 
 static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
-#ifdef NL_EMULATE_DEV
-	if (nlk->handler) {
-		nlk->handler(sk->sk_protocol, skb);
-		return 0;
-	} else
-#endif
+	struct netlink_sock *nlk = nlk_sk(sk);
+
 	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
 	    !test_bit(0, &nlk->state)) {
 		skb_set_owner_r(skb, sk);
@@ -741,7 +719,7 @@ struct netlink_broadcast_data {
 static inline int do_one_broadcast(struct sock *sk,
 				   struct netlink_broadcast_data *p)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	int val;
 
 	if (p->exclude_sk == sk)
@@ -757,11 +735,15 @@ static inline int do_one_broadcast(struc
 
 	sock_hold(sk);
 	if (p->skb2 == NULL) {
-		if (atomic_read(&p->skb->users) != 1) {
+		if (skb_shared(p->skb)) {
 			p->skb2 = skb_clone(p->skb, p->allocation);
 		} else {
-			p->skb2 = p->skb;
-			atomic_inc(&p->skb->users);
+			p->skb2 = skb_get(p->skb);
+			/*
+			 * skb ownership may have been set when
+			 * delivered to a previous socket.
+			 */
+			skb_orphan(p->skb2);
 		}
 	}
 	if (p->skb2 == NULL) {
@@ -807,11 +789,12 @@ int netlink_broadcast(struct sock *ssk, 
 	sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
 		do_one_broadcast(sk, &info);
 
+	kfree_skb(skb);
+
 	netlink_unlock_table();
 
 	if (info.skb2)
 		kfree_skb(info.skb2);
-	kfree_skb(skb);
 
 	if (info.delivered) {
 		if (info.congested && (allocation & __GFP_WAIT))
@@ -833,7 +816,7 @@ struct netlink_set_err_data {
 static inline int do_one_set_err(struct sock *sk,
 				 struct netlink_set_err_data *p)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 
 	if (sk == p->exclude_sk)
 		goto out;
@@ -868,7 +851,7 @@ void netlink_set_err(struct sock *ssk, u
 
 static inline void netlink_rcv_wake(struct sock *sk)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 
 	if (!skb_queue_len(&sk->sk_receive_queue))
 		clear_bit(0, &nlk->state);
@@ -881,7 +864,7 @@ static int netlink_sendmsg(struct kiocb 
 {
 	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	struct sockaddr_nl *addr=msg->msg_name;
 	u32 dst_pid;
 	u32 dst_groups;
@@ -928,6 +911,7 @@ static int netlink_sendmsg(struct kiocb 
 	NETLINK_CB(skb).groups	= nlk->groups;
 	NETLINK_CB(skb).dst_pid = dst_pid;
 	NETLINK_CB(skb).dst_groups = dst_groups;
+	NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
 	memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
 	/* What can I do? Netlink is asynchronous, so that
@@ -965,7 +949,7 @@ static int netlink_recvmsg(struct kiocb 
 	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
 	struct scm_cookie scm;
 	struct sock *sk = sock->sk;
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	int noblock = flags&MSG_DONTWAIT;
 	size_t copied;
 	struct sk_buff *skb;
@@ -1019,7 +1003,7 @@ out:
 
 static void netlink_data_ready(struct sock *sk, int len)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 
 	if (nlk->data_ready)
 		nlk->data_ready(sk, len);
@@ -1083,7 +1067,7 @@ static void netlink_destroy_callback(str
 
 static int netlink_dump(struct sock *sk)
 {
-	struct netlink_opt *nlk = nlk_sk(sk);
+	struct netlink_sock *nlk = nlk_sk(sk);
 	struct netlink_callback *cb;
 	struct sk_buff *skb;
 	struct nlmsghdr *nlh;
@@ -1122,7 +1106,6 @@ static int netlink_dump(struct sock *sk)
 	spin_unlock(&nlk->cb_lock);
 
 	netlink_destroy_callback(cb);
-	sock_put(sk);
 	return 0;
 }
 
@@ -1133,7 +1116,7 @@ int netlink_dump_start(struct sock *ssk,
 {
 	struct netlink_callback *cb;
 	struct sock *sk;
-	struct netlink_opt *nlk;
+	struct netlink_sock *nlk;
 
 	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
 	if (cb == NULL)
@@ -1164,6 +1147,7 @@ int netlink_dump_start(struct sock *ssk,
 	spin_unlock(&nlk->cb_lock);
 
 	netlink_dump(sk);
+	sock_put(sk);
 	return 0;
 }
 
@@ -1290,7 +1274,7 @@ static int netlink_seq_show(struct seq_f
 			 "Rmem     Wmem     Dump     Locks\n");
 	else {
 		struct sock *s = v;
-		struct netlink_opt *nlk = nlk_sk(s);
+		struct netlink_sock *nlk = nlk_sk(s);
 
 		seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %d\n",
 			   s,
@@ -1392,6 +1376,10 @@ static int __init netlink_proto_init(voi
 	int i;
 	unsigned long max;
 	unsigned int order;
+	int err = proto_register(&netlink_proto, 0);
+
+	if (err != 0)
+		goto out;
 
 	if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb))
 		netlink_skb_parms_too_large();
@@ -1438,15 +1426,17 @@ enomem:
 #endif
 	/* The netlink device handler may be needed early. */ 
 	rtnetlink_init();
-	return 0;
+out:
+	return err;
 }
 
 static void __exit netlink_proto_exit(void)
 {
-       sock_unregister(PF_NETLINK);
-       proc_net_remove("netlink");
-       kfree(nl_table);
-       nl_table = NULL;
+	sock_unregister(PF_NETLINK);
+	proc_net_remove("netlink");
+	kfree(nl_table);
+	nl_table = NULL;
+	proto_unregister(&netlink_proto);
 }
 
 core_initcall(netlink_proto_init);
diff --git a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
deleted file mode 100644
--- a/net/netlink/netlink_dev.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * NETLINK	An implementation of a loadable kernel mode driver providing
- *		multiple kernel/user space bidirectional communications links.
- *
- * 		Author: 	Alan Cox <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
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- * 
- *	Now netlink devices are emulated on the top of netlink sockets
- *	by compatibility reasons. Remove this file after a period. --ANK
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-static long open_map;
-static struct socket *netlink_user[MAX_LINKS];
-static struct class_simple *netlink_class;
-
-/*
- *	Device operations
- */
- 
-static unsigned int netlink_poll(struct file *file, poll_table * wait)
-{
-	struct socket *sock = netlink_user[iminor(file->f_dentry->d_inode)];
-
-	if (sock->ops->poll==NULL)
-		return 0;
-	return sock->ops->poll(file, sock, wait);
-}
-
-/*
- *	Write a message to the kernel side of a communication link
- */
- 
-static ssize_t netlink_write(struct file * file, const char __user * buf,
-			     size_t count, loff_t *pos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct socket *sock = netlink_user[iminor(inode)];
-	struct msghdr msg;
-	struct iovec iov;
-
-	iov.iov_base = (void __user*)buf;
-	iov.iov_len = count;
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_controllen=0;
-	msg.msg_flags=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-
-	return sock_sendmsg(sock, &msg, count);
-}
-
-/*
- *	Read a message from the kernel side of the communication link
- */
-
-static ssize_t netlink_read(struct file * file, char __user * buf,
-			    size_t count, loff_t *pos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct socket *sock = netlink_user[iminor(inode)];
-	struct msghdr msg;
-	struct iovec iov;
-
-	iov.iov_base = buf;
-	iov.iov_len = count;
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_controllen=0;
-	msg.msg_flags=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	if (file->f_flags&O_NONBLOCK)
-		msg.msg_flags=MSG_DONTWAIT;
-
-	return sock_recvmsg(sock, &msg, count, msg.msg_flags);
-}
-
-static int netlink_open(struct inode * inode, struct file * file)
-{
-	unsigned int minor = iminor(inode);
-	struct socket *sock;
-	struct sockaddr_nl nladdr;
-	int err;
-
-	if (minor>=MAX_LINKS)
-		return -ENODEV;
-	if (test_and_set_bit(minor, &open_map))
-		return -EBUSY;
-
-	err = sock_create_kern(PF_NETLINK, SOCK_RAW, minor, &sock);
-	if (err < 0)
-		goto out;
-
-	memset(&nladdr, 0, sizeof(nladdr));
-	nladdr.nl_family = AF_NETLINK;
-	nladdr.nl_groups = ~0;
-	if ((err = sock->ops->bind(sock, (struct sockaddr*)&nladdr, sizeof(nladdr))) < 0) {
-		sock_release(sock);
-		goto out;
-	}
-
-	netlink_user[minor] = sock;
-	return 0;
-
-out:
-	clear_bit(minor, &open_map);
-	return err;
-}
-
-static int netlink_release(struct inode * inode, struct file * file)
-{
-	unsigned int minor = iminor(inode);
-	struct socket *sock;
-
-	sock = netlink_user[minor];
-	netlink_user[minor] = NULL;
-	clear_bit(minor, &open_map);
-	sock_release(sock);
-	return 0;
-}
-
-
-static int netlink_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor = iminor(inode);
-	int retval = 0;
-
-	if (minor >= MAX_LINKS)
-		return -ENODEV;
-	switch ( cmd ) {
-		default:
-			retval = -EINVAL;
-	}
-	return retval;
-}
-
-
-static struct file_operations netlink_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.read =		netlink_read,
-	.write =	netlink_write,
-	.poll =		netlink_poll,
-	.ioctl =	netlink_ioctl,
-	.open =		netlink_open,
-	.release =	netlink_release,
-};
-
-static struct {
-	char *name;
-	int minor;
-} entries[] = {
-	{
-		.name	= "route",
-		.minor	= NETLINK_ROUTE,
-	},
-	{
-		.name	= "skip",
-		.minor	= NETLINK_SKIP,
-	},
-	{
-		.name	= "usersock",
-		.minor	= NETLINK_USERSOCK,
-	},
-	{
-		.name	= "fwmonitor",
-		.minor	= NETLINK_FIREWALL,
-	},
-	{
-		.name	= "tcpdiag",
-		.minor	= NETLINK_TCPDIAG,
-	},
-	{
-		.name	= "nflog",
-		.minor	= NETLINK_NFLOG,
-	},
-	{
-		.name	= "xfrm",
-		.minor	= NETLINK_XFRM,
-	},
-	{
-		.name	= "arpd",
-		.minor	= NETLINK_ARPD,
-	},
-	{
-		.name	= "route6",
-		.minor	= NETLINK_ROUTE6,
-	},
-	{
-		.name	= "ip6_fw",
-		.minor	= NETLINK_IP6_FW,
-	},
-	{
-		.name	= "dnrtmsg",
-		.minor	= NETLINK_DNRTMSG,
-	},
-};
-
-static int __init init_netlink(void)
-{
-	int i;
-
-	if (register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
-		printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
-		return -EIO;
-	}
-
-	netlink_class = class_simple_create(THIS_MODULE, "netlink");
-	if (IS_ERR(netlink_class)) {
-		printk (KERN_ERR "Error creating netlink class.\n");
-		unregister_chrdev(NETLINK_MAJOR, "netlink");
-		return PTR_ERR(netlink_class);
-	}
-
-	devfs_mk_dir("netlink");
-
-	/*  Someone tell me the official names for the uppercase ones  */
-	for (i = 0; i < ARRAY_SIZE(entries); i++) {
-		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, entries[i].minor),
-			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/%s", entries[i].name);
-		class_simple_device_add(netlink_class, MKDEV(NETLINK_MAJOR, entries[i].minor), NULL, "%s", entries[i].name);
-	}
-
-	for (i = 0; i < 16; i++) {
-		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, i + 16),
-			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/tap%d", i);
-		class_simple_device_add(netlink_class, MKDEV(NETLINK_MAJOR, i + 16), NULL, "tap%d", i);
-	}
-
-	return 0;
-}
-
-static void __exit cleanup_netlink(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(entries); i++) {
-		devfs_remove("netlink/%s", entries[i].name);
-		class_simple_device_remove(MKDEV(NETLINK_MAJOR, entries[i].minor));
-	}
-	for (i = 0; i < 16; i++) {
-		devfs_remove("netlink/tap%d", i);
-		class_simple_device_remove(MKDEV(NETLINK_MAJOR, i + 16));
-	}
-	devfs_remove("netlink");
-	class_simple_destroy(netlink_class);
-	unregister_chrdev(NETLINK_MAJOR, "netlink");
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_netlink);
-module_exit(cleanup_netlink);
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -63,29 +63,6 @@ static HLIST_HEAD(nr_list);
 static DEFINE_SPINLOCK(nr_list_lock);
 
 static struct proto_ops nr_proto_ops;
-void nr_init_timers(struct sock *sk);
-
-static struct sock *nr_alloc_sock(void)
-{
-	nr_cb *nr;
-	struct sock *sk = sk_alloc(PF_NETROM, GFP_ATOMIC, 1, NULL);
-
-	if (!sk)
-		goto out;
-
-	nr = sk->sk_protinfo = kmalloc(sizeof(*nr), GFP_ATOMIC);
-	if (!nr)
-		goto frees;
-
-	memset(nr, 0x00, sizeof(*nr));
-	nr->sk = sk;
-out:
-	return sk;
-frees:
-	sk_free(sk);
-	sk = NULL;
-	goto out;
-}
 
 /*
  *	Socket removal during an interrupt is now safe.
@@ -170,7 +147,7 @@ static struct sock *nr_find_socket(unsig
 
 	spin_lock_bh(&nr_list_lock);
 	sk_for_each(s, node, &nr_list) {
-		nr_cb *nr = nr_sk(s);
+		struct nr_sock *nr = nr_sk(s);
 		
 		if (nr->my_index == index && nr->my_id == id) {
 			bh_lock_sock(s);
@@ -194,7 +171,7 @@ static struct sock *nr_find_peer(unsigne
 
 	spin_lock_bh(&nr_list_lock);
 	sk_for_each(s, node, &nr_list) {
-		nr_cb *nr = nr_sk(s);
+		struct nr_sock *nr = nr_sk(s);
 		
 		if (nr->your_index == index && nr->your_id == id &&
 		    !ax25cmp(&nr->dest_addr, dest)) {
@@ -301,7 +278,7 @@ static int nr_setsockopt(struct socket *
 	char __user *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	int opt;
 
 	if (level != SOL_NETROM)
@@ -353,7 +330,7 @@ static int nr_getsockopt(struct socket *
 	char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	int val = 0;
 	int len; 
 
@@ -416,21 +393,26 @@ static int nr_listen(struct socket *sock
 	return -EOPNOTSUPP;
 }
 
+static struct proto nr_proto = {
+	.name	  = "NETROM",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct nr_sock),
+};
+
 static int nr_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	nr_cb *nr;
+	struct nr_sock *nr;
 
 	if (sock->type != SOCK_SEQPACKET || protocol != 0)
 		return -ESOCKTNOSUPPORT;
 
-	if ((sk = nr_alloc_sock()) == NULL)
+	if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL)
 		return -ENOMEM;
 
 	nr = nr_sk(sk);
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sock->ops    = &nr_proto_ops;
 	sk->sk_protocol = protocol;
@@ -457,18 +439,17 @@ static int nr_create(struct socket *sock
 static struct sock *nr_make_new(struct sock *osk)
 {
 	struct sock *sk;
-	nr_cb *nr, *onr;
+	struct nr_sock *nr, *onr;
 
 	if (osk->sk_type != SOCK_SEQPACKET)
 		return NULL;
 
-	if ((sk = nr_alloc_sock()) == NULL)
+	if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL)
 		return NULL;
 
 	nr = nr_sk(sk);
 
 	sock_init_data(NULL, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sk->sk_type     = osk->sk_type;
 	sk->sk_socket   = osk->sk_socket;
@@ -476,10 +457,14 @@ static struct sock *nr_make_new(struct s
 	sk->sk_protocol = osk->sk_protocol;
 	sk->sk_rcvbuf   = osk->sk_rcvbuf;
 	sk->sk_sndbuf   = osk->sk_sndbuf;
-	sk->sk_debug    = osk->sk_debug;
 	sk->sk_state    = TCP_ESTABLISHED;
 	sk->sk_sleep    = osk->sk_sleep;
-	sk->sk_zapped   = osk->sk_zapped;
+
+	if (sock_flag(osk, SOCK_ZAPPED))
+		sock_set_flag(sk, SOCK_ZAPPED);
+
+	if (sock_flag(osk, SOCK_DBG))
+		sock_set_flag(sk, SOCK_DBG);
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
@@ -505,7 +490,7 @@ static struct sock *nr_make_new(struct s
 static int nr_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr;
+	struct nr_sock *nr;
 
 	if (sk == NULL) return 0;
 
@@ -553,13 +538,13 @@ static int nr_release(struct socket *soc
 static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
 	struct net_device *dev;
 	ax25_address *user, *source;
 
 	lock_sock(sk);
-	if (!sk->sk_zapped) {
+	if (!sock_flag(sk, SOCK_ZAPPED)) {
 		release_sock(sk);
 		return -EINVAL;
 	}
@@ -611,7 +596,7 @@ static int nr_bind(struct socket *sock, 
 	nr->device = dev;
 	nr_insert_socket(sk);
 
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	dev_put(dev);
 	release_sock(sk);
 	SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
@@ -622,7 +607,7 @@ static int nr_connect(struct socket *soc
 	int addr_len, int flags)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
 	ax25_address *user, *source = NULL;
 	struct net_device *dev;
@@ -656,8 +641,8 @@ static int nr_connect(struct socket *soc
 		release_sock(sk);
 		return -EINVAL;
 	}
-	if (sk->sk_zapped) {	/* Must bind first - autobinding in this may or may not work */
-		sk->sk_zapped = 0;
+	if (sock_flag(sk, SOCK_ZAPPED)) {	/* Must bind first - autobinding in this may or may not work */
+		sock_reset_flag(sk, SOCK_ZAPPED);
 
 		if ((dev = nr_dev_first()) == NULL) {
 			release_sock(sk);
@@ -819,7 +804,7 @@ static int nr_getname(struct socket *soc
 {
 	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	lock_sock(sk);
 	if (peer != 0) {
@@ -847,7 +832,7 @@ int nr_rx_frame(struct sk_buff *skb, str
 {
 	struct sock *sk;
 	struct sock *make;	
-	nr_cb *nr_make;
+	struct nr_sock *nr_make;
 	ax25_address *src, *dest, *user;
 	unsigned short circuit_index, circuit_id;
 	unsigned short peer_circuit_index, peer_circuit_id;
@@ -939,7 +924,7 @@ int nr_rx_frame(struct sk_buff *skb, str
 
 	user = (ax25_address *)(skb->data + 21);
 
-	if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
+	if (sk == NULL || sk_acceptq_is_full(sk) ||
 	    (make = nr_make_new(sk)) == NULL) {
 		nr_transmit_refusal(skb, 0);
 		if (sk)
@@ -1012,7 +997,7 @@ static int nr_sendmsg(struct kiocb *iocb
 		      struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
 	int err;
 	struct sockaddr_ax25 sax;
@@ -1024,7 +1009,7 @@ static int nr_sendmsg(struct kiocb *iocb
 		return -EINVAL;
 
 	lock_sock(sk);
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		err = -EADDRNOTAVAIL;
 		goto out;
 	}
@@ -1272,7 +1257,7 @@ static int nr_info_show(struct seq_file 
 {
 	struct sock *s = v;
 	struct net_device *dev;
-	nr_cb *nr;
+	struct nr_sock *nr;
 	const char *devname;
 
 	if (v == SEQ_START_TOKEN)
@@ -1382,6 +1367,10 @@ static char banner[] __initdata = KERN_I
 static int __init nr_proto_init(void)
 {
 	int i;
+	int rc = proto_register(&nr_proto, 0);
+
+	if (rc != 0)
+		goto out;
 
 	if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) {
 		printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n");
@@ -1437,15 +1426,17 @@ static int __init nr_proto_init(void)
 	proc_net_fops_create("nr", S_IRUGO, &nr_info_fops);
 	proc_net_fops_create("nr_neigh", S_IRUGO, &nr_neigh_fops);
 	proc_net_fops_create("nr_nodes", S_IRUGO, &nr_nodes_fops);
-	return 0;
-
- fail:
+out:
+	return rc;
+fail:
 	while (--i >= 0) {
 		unregister_netdev(dev_nr[i]);
 		free_netdev(dev_nr[i]);
 	}
 	kfree(dev_nr);
-	return -1;
+	proto_unregister(&nr_proto);
+	rc = -1;
+	goto out;
 }
 
 module_init(nr_proto_init);
@@ -1489,5 +1480,6 @@ static void __exit nr_exit(void)
 	}
 
 	kfree(dev_nr);
+	proto_unregister(&nr_proto);
 }
 module_exit(nr_exit);
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -34,7 +34,7 @@
 static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 {
 	struct sk_buff *skbo, *skbn = skb;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
@@ -74,10 +74,9 @@ static int nr_queue_rx_frame(struct sock
 static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
 	int frametype)
 {
-	bh_lock_sock(sk);
 	switch (frametype) {
 	case NR_CONNACK: {
-		nr_cb *nr = nr_sk(sk);
+		struct nr_sock *nr = nr_sk(sk);
 
 		nr_stop_t1timer(sk);
 		nr_start_idletimer(sk);
@@ -103,8 +102,6 @@ static int nr_state1_machine(struct sock
 	default:
 		break;
 	}
-	bh_unlock_sock(sk);
-
 	return 0;
 }
 
@@ -116,7 +113,6 @@ static int nr_state1_machine(struct sock
 static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
 	int frametype)
 {
-	bh_lock_sock(sk);
 	switch (frametype) {
 	case NR_CONNACK | NR_CHOKE_FLAG:
 		nr_disconnect(sk, ECONNRESET);
@@ -132,8 +128,6 @@ static int nr_state2_machine(struct sock
 	default:
 		break;
 	}
-	bh_unlock_sock(sk);
-
 	return 0;
 }
 
@@ -144,7 +138,7 @@ static int nr_state2_machine(struct sock
  */
 static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
-	nr_cb *nrom = nr_sk(sk);
+	struct nr_sock *nrom = nr_sk(sk);
 	struct sk_buff_head temp_queue;
 	struct sk_buff *skbn;
 	unsigned short save_vr;
@@ -154,7 +148,6 @@ static int nr_state3_machine(struct sock
 	nr = skb->data[18];
 	ns = skb->data[17];
 
-	bh_lock_sock(sk);
 	switch (frametype) {
 	case NR_CONNREQ:
 		nr_write_internal(sk, NR_CONNACK);
@@ -265,15 +258,13 @@ static int nr_state3_machine(struct sock
 	default:
 		break;
 	}
-	bh_unlock_sock(sk);
-
 	return queued;
 }
 
-/* Higher level upcall for a LAPB frame */
+/* Higher level upcall for a LAPB frame - called with sk locked */
 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	int queued = 0, frametype;
 
 	if (nr->state == NR_STATE_0)
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
--- a/net/netrom/nr_out.c
+++ b/net/netrom/nr_out.c
@@ -82,7 +82,7 @@ void nr_output(struct sock *sk, struct s
  */
 static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	if (skb == NULL)
 		return;
@@ -101,7 +101,7 @@ static void nr_send_iframe(struct sock *
 void nr_send_nak_frame(struct sock *sk)
 {
 	struct sk_buff *skb, *skbn;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	if ((skb = skb_peek(&nr->ack_queue)) == NULL)
 		return;
@@ -125,7 +125,7 @@ void nr_send_nak_frame(struct sock *sk)
 
 void nr_kick(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	struct sk_buff *skb, *skbn;
 	unsigned short start, end;
 
@@ -188,7 +188,7 @@ void nr_kick(struct sock *sk)
 
 void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	unsigned char *dptr;
 
 	/*
@@ -223,7 +223,7 @@ void nr_transmit_buffer(struct sock *sk,
 
 void nr_establish_data_link(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	nr->condition = 0x00;
 	nr->n2count   = 0;
@@ -241,7 +241,7 @@ void nr_establish_data_link(struct sock 
  */
 void nr_enquiry_response(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	int frametype = NR_INFOACK;
 
 	if (nr->condition & NR_COND_OWN_RX_BUSY) {
@@ -259,7 +259,7 @@ void nr_enquiry_response(struct sock *sk
 
 void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
 {
-	nr_cb *nrom = nr_sk(sk);
+	struct nr_sock *nrom = nr_sk(sk);
 
 	if (nrom->vs == nr) {
 		nr_frames_acked(sk, nr);
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -34,7 +34,7 @@
  */
 void nr_clear_queues(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	skb_queue_purge(&sk->sk_write_queue);
 	skb_queue_purge(&nr->ack_queue);
@@ -49,7 +49,7 @@ void nr_clear_queues(struct sock *sk)
  */
 void nr_frames_acked(struct sock *sk, unsigned short nr)
 {
-	nr_cb *nrom = nr_sk(sk);
+	struct nr_sock *nrom = nr_sk(sk);
 	struct sk_buff *skb;
 
 	/*
@@ -88,7 +88,7 @@ void nr_requeue_frames(struct sock *sk)
  */
 int nr_validate_nr(struct sock *sk, unsigned short nr)
 {
-	nr_cb *nrom = nr_sk(sk);
+	struct nr_sock *nrom = nr_sk(sk);
 	unsigned short vc = nrom->va;
 
 	while (vc != nrom->vs) {
@@ -104,7 +104,7 @@ int nr_validate_nr(struct sock *sk, unsi
  */
 int nr_in_rx_window(struct sock *sk, unsigned short ns)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	unsigned short vc = nr->vr;
 	unsigned short vt = (nr->vl + nr->window) % NR_MODULUS;
 
@@ -122,7 +122,7 @@ int nr_in_rx_window(struct sock *sk, uns
  */
 void nr_write_internal(struct sock *sk, int frametype)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	int len, timeout;
diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
--- a/net/netrom/nr_timer.c
+++ b/net/netrom/nr_timer.c
@@ -38,7 +38,7 @@ static void nr_idletimer_expiry(unsigned
 
 void nr_init_timers(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	init_timer(&nr->t1timer);
 	nr->t1timer.data     = (unsigned long)sk;
@@ -63,28 +63,28 @@ void nr_init_timers(struct sock *sk)
 
 void nr_start_t1timer(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	mod_timer(&nr->t1timer, jiffies + nr->t1);
 }
 
 void nr_start_t2timer(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	mod_timer(&nr->t2timer, jiffies + nr->t2);
 }
 
 void nr_start_t4timer(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	mod_timer(&nr->t4timer, jiffies + nr->t4);
 }
 
 void nr_start_idletimer(struct sock *sk)
 {
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	if (nr->idle > 0)
 		mod_timer(&nr->idletimer, jiffies + nr->idle);
@@ -128,7 +128,7 @@ int nr_t1timer_running(struct sock *sk)
 static void nr_heartbeat_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	bh_lock_sock(sk);
 	switch (nr->state) {
@@ -167,7 +167,7 @@ static void nr_heartbeat_expiry(unsigned
 static void nr_t2timer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	bh_lock_sock(sk);
 	if (nr->condition & NR_COND_ACK_PENDING) {
@@ -189,7 +189,7 @@ static void nr_t4timer_expiry(unsigned l
 static void nr_idletimer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	bh_lock_sock(sk);
 
@@ -217,7 +217,7 @@ static void nr_idletimer_expiry(unsigned
 static void nr_t1timer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	nr_cb *nr = nr_sk(sk);
+	struct nr_sock *nr = nr_sk(sk);
 
 	bh_lock_sock(sk);
 	switch (nr->state) {
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox, <gw4pts@gw4pts.ampr.org>
  *
@@ -170,8 +170,9 @@ static int packet_set_ring(struct sock *
 
 static void packet_flush_mclist(struct sock *sk);
 
-struct packet_opt
-{
+struct packet_sock {
+	/* struct sock has to be the first member of packet_sock */
+	struct sock		sk;
 	struct tpacket_stats	stats;
 #ifdef CONFIG_PACKET_MMAP
 	char *			*pg_vec;
@@ -199,7 +200,7 @@ struct packet_opt
 
 #ifdef CONFIG_PACKET_MMAP
 
-static inline char *packet_lookup_frame(struct packet_opt *po, unsigned int position)
+static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
 {
 	unsigned int pg_vec_pos, frame_offset;
 	char *frame;
@@ -213,7 +214,10 @@ static inline char *packet_lookup_frame(
 }
 #endif
 
-#define pkt_sk(__sk) ((struct packet_opt *)(__sk)->sk_protinfo)
+static inline struct packet_sock *pkt_sk(struct sock *sk)
+{
+	return (struct packet_sock *)sk;
+}
 
 static void packet_sock_destruct(struct sock *sk)
 {
@@ -225,8 +229,6 @@ static void packet_sock_destruct(struct 
 		return;
 	}
 
-	if (pkt_sk(sk))
-		kfree(pkt_sk(sk));
 	atomic_dec(&packet_socks_nr);
 #ifdef PACKET_REFCNT_DEBUG
 	printk(KERN_DEBUG "PACKET socket %p is free, %d are alive\n", sk, atomic_read(&packet_socks_nr));
@@ -440,7 +442,7 @@ static int packet_rcv(struct sk_buff *sk
 {
 	struct sock *sk;
 	struct sockaddr_ll *sll;
-	struct packet_opt *po;
+	struct packet_sock *po;
 	u8 * skb_head = skb->data;
 	int skb_len = skb->len;
 	unsigned snaplen;
@@ -541,7 +543,7 @@ drop:
 static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt)
 {
 	struct sock *sk;
-	struct packet_opt *po;
+	struct packet_sock *po;
 	struct sockaddr_ll *sll;
 	struct tpacket_hdr *h;
 	u8 * skb_head = skb->data;
@@ -699,7 +701,7 @@ static int packet_sendmsg(struct kiocb *
 	 */
 	 
 	if (saddr == NULL) {
-		struct packet_opt *po = pkt_sk(sk);
+		struct packet_sock *po = pkt_sk(sk);
 
 		ifindex	= po->ifindex;
 		proto	= po->num;
@@ -786,7 +788,7 @@ out:
 static int packet_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct packet_opt *po;
+	struct packet_sock *po;
 
 	if (!sk)
 		return 0;
@@ -844,7 +846,7 @@ static int packet_release(struct socket 
 
 static int packet_do_bind(struct sock *sk, struct net_device *dev, int protocol)
 {
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	/*
 	 *	Detach an existing hook if present.
 	 */
@@ -953,6 +955,11 @@ out:
 	return err;
 }
 
+static struct proto packet_proto = {
+	.name	  = "PACKET",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct packet_sock),
+};
 
 /*
  *	Create a packet of type SOCK_PACKET. 
@@ -961,7 +968,7 @@ out:
 static int packet_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct packet_opt *po;
+	struct packet_sock *po;
 	int err;
 
 	if (!capable(CAP_NET_RAW))
@@ -976,7 +983,7 @@ static int packet_create(struct socket *
 	sock->state = SS_UNCONNECTED;
 
 	err = -ENOBUFS;
-	sk = sk_alloc(PF_PACKET, GFP_KERNEL, 1, NULL);
+	sk = sk_alloc(PF_PACKET, GFP_KERNEL, &packet_proto, 1);
 	if (sk == NULL)
 		goto out;
 
@@ -985,13 +992,9 @@ static int packet_create(struct socket *
 	if (sock->type == SOCK_PACKET)
 		sock->ops = &packet_ops_spkt;
 #endif
-	sock_init_data(sock,sk);
-	sk_set_owner(sk, THIS_MODULE);
+	sock_init_data(sock, sk);
 
-	po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL);
-	if (!po)
-		goto out_free;
-	memset(po, 0, sizeof(*po));
+	po = pkt_sk(sk);
 	sk->sk_family = PF_PACKET;
 	po->num = protocol;
 
@@ -1021,9 +1024,6 @@ static int packet_create(struct socket *
 	sk_add_node(sk, &packet_sklist);
 	write_unlock_bh(&packet_sklist_lock);
 	return(0);
-
-out_free:
-	sk_free(sk);
 out:
 	return err;
 }
@@ -1141,7 +1141,7 @@ static int packet_getname(struct socket 
 {
 	struct net_device *dev;
 	struct sock *sk = sock->sk;
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;
 
 	if (peer)
@@ -1195,7 +1195,7 @@ static void packet_dev_mclist(struct net
 
 static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
 {
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	struct packet_mclist *ml, *i;
 	struct net_device *dev;
 	int err;
@@ -1274,7 +1274,7 @@ static int packet_mc_drop(struct sock *s
 
 static void packet_flush_mclist(struct sock *sk)
 {
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	struct packet_mclist *ml;
 
 	if (!po->mclist)
@@ -1355,7 +1355,7 @@ static int packet_getsockopt(struct sock
 {
 	int len;
 	struct sock *sk = sock->sk;
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 
 	if (level != SOL_PACKET)
 		return -ENOPROTOOPT;
@@ -1401,7 +1401,7 @@ static int packet_notifier(struct notifi
 
 	read_lock(&packet_sklist_lock);
 	sk_for_each(sk, node, &packet_sklist) {
-		struct packet_opt *po = pkt_sk(sk);
+		struct packet_sock *po = pkt_sk(sk);
 
 		switch (msg) {
 		case NETDEV_UNREGISTER:
@@ -1504,7 +1504,7 @@ static unsigned int packet_poll(struct f
 				poll_table *wait)
 {
 	struct sock *sk = sock->sk;
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	unsigned int mask = datagram_poll(file, sock, wait);
 
 	spin_lock_bh(&sk->sk_receive_queue.lock);
@@ -1579,7 +1579,7 @@ static void free_pg_vec(char **pg_vec, u
 static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
 {
 	char **pg_vec = NULL;
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	int was_running, num, order = 0;
 	int err = 0;
 	
@@ -1709,7 +1709,7 @@ out:
 static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma)
 {
 	struct sock *sk = sock->sk;
-	struct packet_opt *po = pkt_sk(sk);
+	struct packet_sock *po = pkt_sk(sk);
 	unsigned long size;
 	unsigned long start;
 	int err = -EINVAL;
@@ -1839,7 +1839,7 @@ static int packet_seq_show(struct seq_fi
 		seq_puts(seq, "sk       RefCnt Type Proto  Iface R Rmem   User   Inode\n");
 	else {
 		struct sock *s = v;
-		const struct packet_opt *po = pkt_sk(s);
+		const struct packet_sock *po = pkt_sk(s);
 
 		seq_printf(seq,
 			   "%p %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
@@ -1884,16 +1884,21 @@ static void __exit packet_exit(void)
 	proc_net_remove("packet");
 	unregister_netdevice_notifier(&packet_netdev_notifier);
 	sock_unregister(PF_PACKET);
-	return;
+	proto_unregister(&packet_proto);
 }
 
 static int __init packet_init(void)
 {
+	int rc = proto_register(&packet_proto, 0);
+
+	if (rc != 0)
+		goto out;
+
 	sock_register(&packet_family_ops);
 	register_netdevice_notifier(&packet_netdev_notifier);
 	proc_net_fops_create("packet", 0, &packet_seq_fops);
-
-	return 0;
+out:
+	return rc;
 }
 
 module_init(packet_init);
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -126,28 +126,6 @@ int rosecmpm(rose_address *addr1, rose_a
 	return 0;
 }
 
-static struct sock *rose_alloc_sock(void)
-{
-	rose_cb *rose;
-	struct sock *sk = sk_alloc(PF_ROSE, GFP_ATOMIC, 1, NULL);
-
-	if (!sk)
-		goto out;
-
-	rose = sk->sk_protinfo = kmalloc(sizeof(*rose), GFP_ATOMIC);
-	if (!rose)
-		goto frees;
-
-	memset(rose, 0x00, sizeof(*rose));
-	rose->sk = sk;
-out:
-	return sk;
-frees:
-	sk_free(sk);
-	sk = NULL;
-	goto out;
-}
-
 /*
  *	Socket removal during an interrupt is now safe.
  */
@@ -169,7 +147,7 @@ void rose_kill_by_neigh(struct rose_neig
 
 	spin_lock_bh(&rose_list_lock);
 	sk_for_each(s, node, &rose_list) {
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 
 		if (rose->neighbour == neigh) {
 			rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
@@ -190,7 +168,7 @@ static void rose_kill_by_device(struct n
 
 	spin_lock_bh(&rose_list_lock);
 	sk_for_each(s, node, &rose_list) {
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 
 		if (rose->device == dev) {
 			rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
@@ -247,7 +225,7 @@ static struct sock *rose_find_listener(r
 
 	spin_lock_bh(&rose_list_lock);
 	sk_for_each(s, node, &rose_list) {
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 
 		if (!rosecmp(&rose->source_addr, addr) &&
 		    !ax25cmp(&rose->source_call, call) &&
@@ -256,7 +234,7 @@ static struct sock *rose_find_listener(r
 	}
 
 	sk_for_each(s, node, &rose_list) {
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 
 		if (!rosecmp(&rose->source_addr, addr) &&
 		    !ax25cmp(&rose->source_call, &null_ax25_address) &&
@@ -279,7 +257,7 @@ struct sock *rose_find_socket(unsigned i
 
 	spin_lock_bh(&rose_list_lock);
 	sk_for_each(s, node, &rose_list) {
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 
 		if (rose->lci == lci && rose->neighbour == neigh)
 			goto found;
@@ -372,7 +350,7 @@ static int rose_setsockopt(struct socket
 	char __user *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	int opt;
 
 	if (level != SOL_ROSE)
@@ -432,7 +410,7 @@ static int rose_getsockopt(struct socket
 	char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	int val = 0;
 	int len;
 
@@ -491,7 +469,7 @@ static int rose_listen(struct socket *so
 	struct sock *sk = sock->sk;
 
 	if (sk->sk_state != TCP_LISTEN) {
-		rose_cb *rose = rose_sk(sk);
+		struct rose_sock *rose = rose_sk(sk);
 
 		rose->dest_ndigis = 0;
 		memset(&rose->dest_addr, 0, ROSE_ADDR_LEN);
@@ -505,21 +483,26 @@ static int rose_listen(struct socket *so
 	return -EOPNOTSUPP;
 }
 
+static struct proto rose_proto = {
+	.name	  = "ROSE",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct rose_sock),
+};
+
 static int rose_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	rose_cb *rose;
+	struct rose_sock *rose;
 
 	if (sock->type != SOCK_SEQPACKET || protocol != 0)
 		return -ESOCKTNOSUPPORT;
 
-	if ((sk = rose_alloc_sock()) == NULL)
+	if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL)
 		return -ENOMEM;
 
 	rose = rose_sk(sk);
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	skb_queue_head_init(&rose->ack_queue);
 #ifdef M_BIT
@@ -547,18 +530,17 @@ static int rose_create(struct socket *so
 static struct sock *rose_make_new(struct sock *osk)
 {
 	struct sock *sk;
-	rose_cb *rose, *orose;
+	struct rose_sock *rose, *orose;
 
 	if (osk->sk_type != SOCK_SEQPACKET)
 		return NULL;
 
-	if ((sk = rose_alloc_sock()) == NULL)
+	if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL)
 		return NULL;
 
 	rose = rose_sk(sk);
 
 	sock_init_data(NULL, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	skb_queue_head_init(&rose->ack_queue);
 #ifdef M_BIT
@@ -572,10 +554,14 @@ static struct sock *rose_make_new(struct
 	sk->sk_protocol = osk->sk_protocol;
 	sk->sk_rcvbuf   = osk->sk_rcvbuf;
 	sk->sk_sndbuf   = osk->sk_sndbuf;
-	sk->sk_debug    = osk->sk_debug;
 	sk->sk_state    = TCP_ESTABLISHED;
 	sk->sk_sleep    = osk->sk_sleep;
-	sk->sk_zapped   = osk->sk_zapped;
+
+	if (sock_flag(osk, SOCK_ZAPPED))
+		sock_set_flag(sk, SOCK_ZAPPED);
+
+	if (sock_flag(osk, SOCK_DBG))
+		sock_set_flag(sk, SOCK_DBG);
 
 	init_timer(&rose->timer);
 	init_timer(&rose->idletimer);
@@ -596,7 +582,7 @@ static struct sock *rose_make_new(struct
 static int rose_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose;
+	struct rose_sock *rose;
 
 	if (sk == NULL) return 0;
 
@@ -642,13 +628,13 @@ static int rose_release(struct socket *s
 static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
 	struct net_device *dev;
 	ax25_address *user, *source;
 	int n;
 
-	if (!sk->sk_zapped)
+	if (!sock_flag(sk, SOCK_ZAPPED))
 		return -EINVAL;
 
 	if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
@@ -693,7 +679,7 @@ static int rose_bind(struct socket *sock
 
 	rose_insert_socket(sk);
 
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	SOCK_DEBUG(sk, "ROSE: socket is bound\n");
 	return 0;
 }
@@ -701,7 +687,7 @@ static int rose_bind(struct socket *sock
 static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
 	unsigned char cause, diagnostic;
 	ax25_address *user;
@@ -749,8 +735,8 @@ static int rose_connect(struct socket *s
 	if (!rose->lci)
 		return -ENETUNREACH;
 
-	if (sk->sk_zapped) {	/* Must bind first - autobinding in this may or may not work */
-		sk->sk_zapped = 0;
+	if (sock_flag(sk, SOCK_ZAPPED)) {	/* Must bind first - autobinding in this may or may not work */
+		sock_reset_flag(sk, SOCK_ZAPPED);
 
 		if ((dev = rose_dev_first()) == NULL)
 			return -ENETUNREACH;
@@ -902,7 +888,7 @@ static int rose_getname(struct socket *s
 {
 	struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr;
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	int n;
 
 	if (peer != 0) {
@@ -931,7 +917,7 @@ int rose_rx_call_request(struct sk_buff 
 {
 	struct sock *sk;
 	struct sock *make;
-	rose_cb *make_rose;
+	struct rose_sock *make_rose;
 	struct rose_facilities_struct facilities;
 	int n, len;
 
@@ -954,7 +940,7 @@ int rose_rx_call_request(struct sk_buff 
 	/*
 	 * We can't accept the Call Request.
 	 */
-	if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
+	if (sk == NULL || sk_acceptq_is_full(sk) ||
 	    (make = rose_make_new(sk)) == NULL) {
 		rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120);
 		return 0;
@@ -1012,7 +998,7 @@ static int rose_sendmsg(struct kiocb *io
 			struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name;
 	int err;
 	struct full_sockaddr_rose srose;
@@ -1023,7 +1009,7 @@ static int rose_sendmsg(struct kiocb *io
 	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
 		return -EINVAL;
 
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		return -EADDRNOTAVAIL;
 
 	if (sk->sk_shutdown & SEND_SHUTDOWN) {
@@ -1182,7 +1168,7 @@ static int rose_recvmsg(struct kiocb *io
 			struct msghdr *msg, size_t size, int flags)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;
 	size_t copied;
 	unsigned char *asmptr;
@@ -1247,7 +1233,7 @@ static int rose_recvmsg(struct kiocb *io
 static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	void __user *argp = (void __user *)arg;
 
 	switch (cmd) {
@@ -1382,7 +1368,7 @@ static int rose_info_show(struct seq_fil
 
 	else {
 		struct sock *s = v;
-		rose_cb *rose = rose_sk(s);
+		struct rose_sock *rose = rose_sk(s);
 		const char *devname, *callsign;
 		const struct net_device *dev = rose->device;
 
@@ -1485,6 +1471,10 @@ static const char banner[] = KERN_INFO "
 static int __init rose_proto_init(void)
 {
 	int i;
+	int rc = proto_register(&rose_proto, 0);
+
+	if (rc != 0)
+		goto out;
 
 	rose_callsign = null_ax25_address;
 
@@ -1537,14 +1527,15 @@ static int __init rose_proto_init(void)
 	proc_net_fops_create("rose_neigh", S_IRUGO, &rose_neigh_fops);
 	proc_net_fops_create("rose_nodes", S_IRUGO, &rose_nodes_fops);
 	proc_net_fops_create("rose_routes", S_IRUGO, &rose_routes_fops);
-
-	return 0;
+out:
+	return rc;
 fail:
 	while (--i >= 0) {
 		unregister_netdev(dev_rose[i]);
 		free_netdev(dev_rose[i]);
 	}
 	kfree(dev_rose);
+	proto_unregister(&rose_proto);
 	return -ENOMEM;
 }
 module_init(rose_proto_init);
@@ -1592,6 +1583,7 @@ static void __exit rose_exit(void)
 	}
 
 	kfree(dev_rose);
+	proto_unregister(&rose_proto);
 }
 
 module_exit(rose_exit);
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -41,7 +41,7 @@
  */
 static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	switch (frametype) {
 	case ROSE_CALL_ACCEPTED:
@@ -78,7 +78,7 @@ static int rose_state1_machine(struct so
  */
 static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	switch (frametype) {
 	case ROSE_CLEAR_REQUEST:
@@ -106,7 +106,7 @@ static int rose_state2_machine(struct so
  */
 static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	int queued = 0;
 
 	switch (frametype) {
@@ -216,7 +216,7 @@ static int rose_state3_machine(struct so
  */
 static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	switch (frametype) {
 	case ROSE_RESET_REQUEST:
@@ -265,7 +265,7 @@ static int rose_state5_machine(struct so
 /* Higher level upcall for a LAPB frame */
 int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	int queued = 0, frametype, ns, nr, q, d, m;
 
 	if (rose->state == ROSE_STATE_0)
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
--- a/net/rose/rose_out.c
+++ b/net/rose/rose_out.c
@@ -33,7 +33,7 @@
  */
 static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	if (skb == NULL)
 		return;
@@ -48,7 +48,7 @@ static void rose_send_iframe(struct sock
 
 void rose_kick(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sk_buff *skb, *skbn;
 	unsigned short start, end;
 
@@ -112,7 +112,7 @@ void rose_kick(struct sock *sk)
 
 void rose_enquiry_response(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	if (rose->condition & ROSE_COND_OWN_RX_BUSY)
 		rose_write_internal(sk, ROSE_RNR);
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -727,7 +727,8 @@ int rose_rt_ioctl(unsigned int cmd, void
 		}
 		if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
 			return -EINVAL;
-
+		if (rose_route.ndigis > 8) /* No more than 8 digipeats */
+			return -EINVAL;
 		err = rose_add_node(&rose_route, dev);
 		dev_put(dev);
 		return err;
@@ -898,7 +899,8 @@ int rose_route_frame(struct sk_buff *skb
 	 */
 	if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
 		if (frametype == ROSE_CALL_REQUEST) {
-			rose_cb *rose = rose_sk(sk);
+			struct rose_sock *rose = rose_sk(sk);
+
 			/* Remove an existing unused socket */
 			rose_clear_queues(sk);
 			rose->cause	 = ROSE_NETWORK_CONGESTION;
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -28,7 +28,7 @@
 #include <linux/interrupt.h>
 #include <net/rose.h>
 
-static int rose_create_facilities(unsigned char *buffer, rose_cb *rose);
+static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose);
 
 /*
  *	This routine purges all of the queues of frames.
@@ -47,7 +47,7 @@ void rose_clear_queues(struct sock *sk)
 void rose_frames_acked(struct sock *sk, unsigned short nr)
 {
 	struct sk_buff *skb;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	/*
 	 * Remove all the ack-ed frames from the ack queue.
@@ -85,7 +85,7 @@ void rose_requeue_frames(struct sock *sk
  */
 int rose_validate_nr(struct sock *sk, unsigned short nr)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	unsigned short vc = rose->va;
 
 	while (vc != rose->vs) {
@@ -102,7 +102,7 @@ int rose_validate_nr(struct sock *sk, un
  */
 void rose_write_internal(struct sock *sk, int frametype)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	unsigned char  lci1, lci2;
@@ -396,7 +396,7 @@ int rose_parse_facilities(unsigned char 
 	return 1;
 }
 
-static int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
+static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
 {
 	unsigned char *p = buffer + 1;
 	char *callsign;
@@ -492,7 +492,7 @@ static int rose_create_facilities(unsign
 
 void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	rose_stop_timer(sk);
 	rose_stop_idletimer(sk);
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
--- a/net/rose/rose_timer.c
+++ b/net/rose/rose_timer.c
@@ -46,7 +46,7 @@ void rose_start_heartbeat(struct sock *s
 
 void rose_start_t1timer(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	del_timer(&rose->timer);
 
@@ -59,7 +59,7 @@ void rose_start_t1timer(struct sock *sk)
 
 void rose_start_t2timer(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	del_timer(&rose->timer);
 
@@ -72,7 +72,7 @@ void rose_start_t2timer(struct sock *sk)
 
 void rose_start_t3timer(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	del_timer(&rose->timer);
 
@@ -85,7 +85,7 @@ void rose_start_t3timer(struct sock *sk)
 
 void rose_start_hbtimer(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	del_timer(&rose->timer);
 
@@ -98,7 +98,7 @@ void rose_start_hbtimer(struct sock *sk)
 
 void rose_start_idletimer(struct sock *sk)
 {
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	del_timer(&rose->idletimer);
 
@@ -129,7 +129,7 @@ void rose_stop_idletimer(struct sock *sk
 static void rose_heartbeat_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	bh_lock_sock(sk);
 	switch (rose->state) {
@@ -166,7 +166,7 @@ static void rose_heartbeat_expiry(unsign
 static void rose_timer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
-	rose_cb *rose = rose_sk(sk);
+	struct rose_sock *rose = rose_sk(sk);
 
 	bh_lock_sock(sk);
 	switch (rose->state) {
diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c
--- a/net/rxrpc/krxiod.c
+++ b/net/rxrpc/krxiod.c
@@ -138,6 +138,8 @@ static int rxrpc_krxiod(void *arg)
 
 		_debug("### End Work");
 
+		try_to_freeze(PF_FREEZE);
+
                 /* discard pending signals */
 		rxrpc_discard_my_signals();
 
diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
--- a/net/rxrpc/krxsecd.c
+++ b/net/rxrpc/krxsecd.c
@@ -107,6 +107,8 @@ static int rxrpc_krxsecd(void *arg)
 
 		_debug("### End Inbound Calls");
 
+		try_to_freeze(PF_FREEZE);
+
                 /* discard pending signals */
 		rxrpc_discard_my_signals();
 
diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c
--- a/net/rxrpc/krxtimod.c
+++ b/net/rxrpc/krxtimod.c
@@ -90,6 +90,8 @@ static int krxtimod(void *arg)
 			complete_and_exit(&krxtimod_dead, 0);
 		}
 
+		try_to_freeze(PF_FREEZE);
+
 		/* discard pending signals */
 		rxrpc_discard_my_signals();
 
diff --git a/net/rxrpc/main.c b/net/rxrpc/main.c
--- a/net/rxrpc/main.c
+++ b/net/rxrpc/main.c
@@ -22,12 +22,6 @@
 #include <rxrpc/message.h>
 #include "internal.h"
 
-static int rxrpc_initialise(void);
-static void rxrpc_cleanup(void);
-
-module_init(rxrpc_initialise);
-module_exit(rxrpc_cleanup);
-
 MODULE_DESCRIPTION("Rx RPC implementation");
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
@@ -38,7 +32,7 @@ __be32 rxrpc_epoch;
 /*
  * initialise the Rx module
  */
-static int rxrpc_initialise(void)
+static int __init rxrpc_initialise(void)
 {
 	int ret;
 
@@ -93,6 +87,8 @@ static int rxrpc_initialise(void)
 	return ret;
 } /* end rxrpc_initialise() */
 
+module_init(rxrpc_initialise);
+
 /*****************************************************************************/
 /*
  * clean up the Rx module
@@ -136,6 +132,8 @@ static void __exit rxrpc_cleanup(void)
 	kleave("");
 } /* end rxrpc_cleanup() */
 
+module_exit(rxrpc_cleanup);
+
 /*****************************************************************************/
 /*
  * clear the dead space between task_struct and kernel stack
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -185,7 +185,7 @@ config NET_SCH_GRED
 	depends on NET_SCHED
 	help
 	  Say Y here if you want to use the Generic Random Early Detection
-	  (RED) packet scheduling algorithm for some of your network devices
+	  (GRED) packet scheduling algorithm for some of your network devices
 	  (see the top of <file:net/sched/sch_red.c> for details and
 	  references about the algorithm).
 
@@ -269,6 +269,16 @@ config NET_CLS
 	  Documentation and software is at
 	  <http://diffserv.sourceforge.net/>.
 
+config NET_CLS_BASIC
+	tristate "Basic classifier"
+	depends on NET_CLS
+	---help---
+	  Say Y here if you want to be able to classify packets using
+	  only extended matches and actions.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called cls_basic.
+
 config NET_CLS_TCINDEX
 	tristate "TC index classifier"
 	depends on NET_CLS
@@ -375,6 +385,70 @@ config NET_CLS_RSVP6
 	  To compile this code as a module, choose M here: the
 	  module will be called cls_rsvp6.
 
+config NET_EMATCH
+	bool "Extended Matches"
+	depends on NET_CLS
+	---help---
+	  Say Y here if you want to use extended matches on top of classifiers
+	  and select the extended matches below.
+
+	  Extended matches are small classification helpers not worth writing
+	  a separate classifier.
+
+	  You must have a recent version of the iproute2 tools in order to use
+	  extended matches.
+
+config NET_EMATCH_STACK
+	int "Stack size"
+	depends on NET_EMATCH
+	default "32"
+	---help---
+	  Size of the local stack variable used while evaluating the tree of
+	  ematches. Limits the depth of the tree, i.e. the number of
+	  encapsulated precedences. Every level requires 4 bytes of additional
+	  stack space.
+
+config NET_EMATCH_CMP
+	tristate "Simple packet data comparison"
+	depends on NET_EMATCH
+	---help---
+	  Say Y here if you want to be able to classify packets based on
+	  simple packet data comparisons for 8, 16, and 32bit values.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called em_cmp.
+
+config NET_EMATCH_NBYTE
+	tristate "Multi byte comparison"
+	depends on NET_EMATCH
+	---help---
+	  Say Y here if you want to be able to classify packets based on
+	  multiple byte comparisons mainly useful for IPv6 address comparisons.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called em_nbyte.
+
+config NET_EMATCH_U32
+	tristate "U32 hashing key"
+	depends on NET_EMATCH
+	---help---
+	  Say Y here if you want to be able to classify packets using
+	  the famous u32 key in combination with logic relations.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called em_u32.
+
+config NET_EMATCH_META
+	tristate "Metadata"
+	depends on NET_EMATCH
+	---help---
+	  Say Y here if you want to be ablt to classify packets based on
+	  metadata such as load average, netfilter attributes, socket
+	  attributes and routing decisions.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called em_meta.
+
 config NET_CLS_ACT
 	bool "Packet ACTION"
 	depends on EXPERIMENTAL && NET_CLS && NET_QOS
@@ -432,3 +506,13 @@ config NET_CLS_POLICE
 	  Say Y to support traffic policing (bandwidth limits).  Needed for
 	  ingress and egress rate limiting.
 
+config NET_ACT_SIMP
+        tristate "Simple action"
+        depends on NET_CLS_ACT
+        ---help---
+        You must have new iproute2 to use this feature.
+        This adds a very simple action for demonstration purposes
+	The idea is to give action authors a basic example to look at.
+	All this action will do is print on the console the configured
+	policy string followed by _ then packet count.
+
diff --git a/net/sched/Makefile b/net/sched/Makefile
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -6,13 +6,14 @@ obj-y	:= sch_generic.o
 
 obj-$(CONFIG_NET_SCHED)		+= sch_api.o sch_fifo.o
 obj-$(CONFIG_NET_CLS)		+= cls_api.o
-obj-$(CONFIG_NET_CLS_ACT)       += act_api.o
+obj-$(CONFIG_NET_CLS_ACT)	+= act_api.o
 obj-$(CONFIG_NET_ACT_POLICE)	+= police.o
 obj-$(CONFIG_NET_CLS_POLICE)	+= police.o
-obj-$(CONFIG_NET_ACT_GACT)      += gact.o
-obj-$(CONFIG_NET_ACT_MIRRED)    += mirred.o
-obj-$(CONFIG_NET_ACT_IPT)       += ipt.o
-obj-$(CONFIG_NET_ACT_PEDIT)     += pedit.o
+obj-$(CONFIG_NET_ACT_GACT)	+= gact.o
+obj-$(CONFIG_NET_ACT_MIRRED)	+= mirred.o
+obj-$(CONFIG_NET_ACT_IPT)	+= ipt.o
+obj-$(CONFIG_NET_ACT_PEDIT)	+= pedit.o
+obj-$(CONFIG_NET_ACT_SIMP)	+= simple.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
 obj-$(CONFIG_NET_SCH_HPFQ)	+= sch_hpfq.o
@@ -33,3 +34,9 @@ obj-$(CONFIG_NET_CLS_FW)	+= cls_fw.o
 obj-$(CONFIG_NET_CLS_RSVP)	+= cls_rsvp.o
 obj-$(CONFIG_NET_CLS_TCINDEX)	+= cls_tcindex.o
 obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o
+obj-$(CONFIG_NET_CLS_BASIC)	+= cls_basic.o
+obj-$(CONFIG_NET_EMATCH)	+= ematch.o
+obj-$(CONFIG_NET_EMATCH_CMP)	+= em_cmp.o
+obj-$(CONFIG_NET_EMATCH_NBYTE)	+= em_nbyte.o
+obj-$(CONFIG_NET_EMATCH_U32)	+= em_u32.o
+obj-$(CONFIG_NET_EMATCH_META)	+= em_meta.o
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -171,10 +171,10 @@ repeat:
 				skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
 				skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd);
 			}
-			if (ret != TC_ACT_PIPE)
-				goto exec_done;
 			if (ret == TC_ACT_REPEAT)
 				goto repeat;	/* we need a ttl - JHS */
+			if (ret != TC_ACT_PIPE)
+				goto exec_done;
 		}
 		act = a->next;
 	}
@@ -228,7 +228,7 @@ tcf_action_dump_1(struct sk_buff *skb, s
 		return err;
 
 	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind);
-	if (tcf_action_copy_stats(skb, a))
+	if (tcf_action_copy_stats(skb, a, 0))
 		goto rtattr_failure;
 	r = (struct rtattr*) skb->tail;
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
@@ -380,19 +380,26 @@ err:
 	return NULL;
 }
 
-int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a)
+int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
+			  int compat_mode)
 {
-	int err;
+	int err = 0;
 	struct gnet_dump d;
 	struct tcf_act_hdr *h = a->priv;
 	
 	if (h == NULL)
 		goto errout;
 
-	if (a->type == TCA_OLD_COMPAT)
-		err = gnet_stats_start_copy_compat(skb, TCA_ACT_STATS,
-			TCA_STATS, TCA_XSTATS, h->stats_lock, &d);
-	else
+	/* compat_mode being true specifies a call that is supposed
+	 * to add additional backward compatiblity statistic TLVs.
+	 */
+	if (compat_mode) {
+		if (a->type == TCA_OLD_COMPAT)
+			err = gnet_stats_start_copy_compat(skb, 0,
+				TCA_STATS, TCA_XSTATS, h->stats_lock, &d);
+		else
+			return 0;
+	} else
 		err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
 			h->stats_lock, &d);
 
@@ -874,7 +881,7 @@ static int __init tc_action_init(void)
 		link_p[RTM_GETACTION-RTM_BASE].dumpit = tc_dump_action;
 	}
 
-	printk("TC classifier action (bugs to netdev@oss.sgi.com cc "
+	printk("TC classifier action (bugs to netdev@vger.kernel.org cc "
 	       "hadi@cyberus.ca)\n");
 	return 0;
 }
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -602,7 +602,7 @@ tcf_exts_dump_stats(struct sk_buff *skb,
 {
 #ifdef CONFIG_NET_CLS_ACT
 	if (exts->action)
-		if (tcf_action_copy_stats(skb, exts->action) < 0)
+		if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
 			goto rtattr_failure;
 #elif defined CONFIG_NET_CLS_POLICE
 	if (exts->police)
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
new file mode 100644
--- /dev/null
+++ b/net/sched/cls_basic.c
@@ -0,0 +1,306 @@
+/*
+ * net/sched/cls_basic.c	Basic Packet Classifier.
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <net/act_api.h>
+#include <net/pkt_cls.h>
+
+struct basic_head
+{
+	u32			hgenerator;
+	struct list_head	flist;
+};
+
+struct basic_filter
+{
+	u32			handle;
+	struct tcf_exts		exts;
+	struct tcf_ematch_tree	ematches;
+	struct tcf_result	res;
+	struct list_head	link;
+};
+
+static struct tcf_ext_map basic_ext_map = {
+	.action = TCA_BASIC_ACT,
+	.police = TCA_BASIC_POLICE
+};
+
+static int basic_classify(struct sk_buff *skb, struct tcf_proto *tp,
+			  struct tcf_result *res)
+{
+	int r;
+	struct basic_head *head = (struct basic_head *) tp->root;
+	struct basic_filter *f;
+
+	list_for_each_entry(f, &head->flist, link) {
+		if (!tcf_em_tree_match(skb, &f->ematches, NULL))
+			continue;
+		*res = f->res;
+		r = tcf_exts_exec(skb, &f->exts, res);
+		if (r < 0)
+			continue;
+		return r;
+	}
+	return -1;
+}
+
+static unsigned long basic_get(struct tcf_proto *tp, u32 handle)
+{
+	unsigned long l = 0UL;
+	struct basic_head *head = (struct basic_head *) tp->root;
+	struct basic_filter *f;
+
+	if (head == NULL)
+		return 0UL;
+
+	list_for_each_entry(f, &head->flist, link)
+		if (f->handle == handle)
+			l = (unsigned long) f;
+
+	return l;
+}
+
+static void basic_put(struct tcf_proto *tp, unsigned long f)
+{
+}
+
+static int basic_init(struct tcf_proto *tp)
+{
+	return 0;
+}
+
+static inline void basic_delete_filter(struct tcf_proto *tp,
+				       struct basic_filter *f)
+{
+	tcf_unbind_filter(tp, &f->res);
+	tcf_exts_destroy(tp, &f->exts);
+	tcf_em_tree_destroy(tp, &f->ematches);
+	kfree(f);
+}
+
+static void basic_destroy(struct tcf_proto *tp)
+{
+	struct basic_head *head = (struct basic_head *) xchg(&tp->root, NULL);
+	struct basic_filter *f, *n;
+	
+	list_for_each_entry_safe(f, n, &head->flist, link) {
+		list_del(&f->link);
+		basic_delete_filter(tp, f);
+	}
+}
+
+static int basic_delete(struct tcf_proto *tp, unsigned long arg)
+{
+	struct basic_head *head = (struct basic_head *) tp->root;
+	struct basic_filter *t, *f = (struct basic_filter *) arg;
+
+	list_for_each_entry(t, &head->flist, link)
+		if (t == f) {
+			tcf_tree_lock(tp);
+			list_del(&t->link);
+			tcf_tree_unlock(tp);
+			basic_delete_filter(tp, t);
+			return 0;
+		}
+
+	return -ENOENT;
+}
+
+static inline int basic_set_parms(struct tcf_proto *tp, struct basic_filter *f,
+				  unsigned long base, struct rtattr **tb,
+				  struct rtattr *est)
+{
+	int err = -EINVAL;
+	struct tcf_exts e;
+	struct tcf_ematch_tree t;
+
+	if (tb[TCA_BASIC_CLASSID-1])
+		if (RTA_PAYLOAD(tb[TCA_BASIC_CLASSID-1]) < sizeof(u32))
+			return err;
+
+	err = tcf_exts_validate(tp, tb, est, &e, &basic_ext_map);
+	if (err < 0)
+		return err;
+
+	err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES-1], &t);
+	if (err < 0)
+		goto errout;
+
+	if (tb[TCA_BASIC_CLASSID-1]) {
+		f->res.classid = *(u32*)RTA_DATA(tb[TCA_BASIC_CLASSID-1]);
+		tcf_bind_filter(tp, &f->res, base);
+	}
+
+	tcf_exts_change(tp, &f->exts, &e);
+	tcf_em_tree_change(tp, &f->ematches, &t);
+
+	return 0;
+errout:
+	tcf_exts_destroy(tp, &e);
+	return err;
+}
+
+static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle,
+		        struct rtattr **tca, unsigned long *arg)
+{
+	int err = -EINVAL;
+	struct basic_head *head = (struct basic_head *) tp->root;
+	struct rtattr *tb[TCA_BASIC_MAX];
+	struct basic_filter *f = (struct basic_filter *) *arg;
+
+	if (tca[TCA_OPTIONS-1] == NULL)
+		return -EINVAL;
+
+	if (rtattr_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS-1]) < 0)
+		return -EINVAL;
+
+	if (f != NULL) {
+		if (handle && f->handle != handle)
+			return -EINVAL;
+		return basic_set_parms(tp, f, base, tb, tca[TCA_RATE-1]);
+	}
+
+	err = -ENOBUFS;
+	if (head == NULL) {
+		head = kmalloc(sizeof(*head), GFP_KERNEL);
+		if (head == NULL)
+			goto errout;
+
+		memset(head, 0, sizeof(*head));
+		INIT_LIST_HEAD(&head->flist);
+		tp->root = head;
+	}
+
+	f = kmalloc(sizeof(*f), GFP_KERNEL);
+	if (f == NULL)
+		goto errout;
+	memset(f, 0, sizeof(*f));
+
+	err = -EINVAL;
+	if (handle)
+		f->handle = handle;
+	else {
+		int i = 0x80000000;
+		do {
+			if (++head->hgenerator == 0x7FFFFFFF)
+				head->hgenerator = 1;
+		} while (--i > 0 && basic_get(tp, head->hgenerator));
+
+		if (i <= 0) {
+			printk(KERN_ERR "Insufficient number of handles\n");
+			goto errout;
+		}
+
+		f->handle = head->hgenerator;
+	}
+
+	err = basic_set_parms(tp, f, base, tb, tca[TCA_RATE-1]);
+	if (err < 0)
+		goto errout;
+
+	tcf_tree_lock(tp);
+	list_add(&f->link, &head->flist);
+	tcf_tree_unlock(tp);
+	*arg = (unsigned long) f;
+
+	return 0;
+errout:
+	if (*arg == 0UL && f)
+		kfree(f);
+
+	return err;
+}
+
+static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+{
+	struct basic_head *head = (struct basic_head *) tp->root;
+	struct basic_filter *f;
+
+	list_for_each_entry(f, &head->flist, link) {
+		if (arg->count < arg->skip)
+			goto skip;
+
+		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
+			arg->stop = 1;
+			break;
+		}
+skip:
+		arg->count++;
+	}
+}
+
+static int basic_dump(struct tcf_proto *tp, unsigned long fh,
+		      struct sk_buff *skb, struct tcmsg *t)
+{
+	struct basic_filter *f = (struct basic_filter *) fh;
+	unsigned char *b = skb->tail;
+	struct rtattr *rta;
+
+	if (f == NULL)
+		return skb->len;
+
+	t->tcm_handle = f->handle;
+
+	rta = (struct rtattr *) b;
+	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+
+	if (f->res.classid)
+		RTA_PUT(skb, TCA_BASIC_CLASSID, sizeof(u32), &f->res.classid);
+
+	if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 ||
+	    tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
+		goto rtattr_failure;
+
+	rta->rta_len = (skb->tail - b);
+	return skb->len;
+
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static struct tcf_proto_ops cls_basic_ops = {
+	.kind		=	"basic",
+	.classify	=	basic_classify,
+	.init		=	basic_init,
+	.destroy	=	basic_destroy,
+	.get		=	basic_get,
+	.put		=	basic_put,
+	.change		=	basic_change,
+	.delete		=	basic_delete,
+	.walk		=	basic_walk,
+	.dump		=	basic_dump,
+	.owner		=	THIS_MODULE,
+};
+
+static int __init init_basic(void)
+{
+	return register_tcf_proto_ops(&cls_basic_ops);
+}
+
+static void __exit exit_basic(void) 
+{
+	unregister_tcf_proto_ops(&cls_basic_ops);
+}
+
+module_init(init_basic)
+module_exit(exit_basic)
+MODULE_LICENSE("GPL");
+
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -46,9 +46,11 @@
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
 
+#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *))
+
 struct fw_head
 {
-	struct fw_filter *ht[256];
+	struct fw_filter *ht[HTSIZE];
 };
 
 struct fw_filter
@@ -69,7 +71,28 @@ static struct tcf_ext_map fw_ext_map = {
 
 static __inline__ int fw_hash(u32 handle)
 {
-	return handle&0xFF;
+	if (HTSIZE == 4096)
+		return ((handle >> 24) & 0xFFF) ^
+		       ((handle >> 12) & 0xFFF) ^
+		       (handle & 0xFFF);
+	else if (HTSIZE == 2048)
+		return ((handle >> 22) & 0x7FF) ^
+		       ((handle >> 11) & 0x7FF) ^
+		       (handle & 0x7FF);
+	else if (HTSIZE == 1024)
+		return ((handle >> 20) & 0x3FF) ^
+		       ((handle >> 10) & 0x3FF) ^
+		       (handle & 0x3FF);
+	else if (HTSIZE == 512)
+		return (handle >> 27) ^
+		       ((handle >> 18) & 0x1FF) ^
+		       ((handle >> 9) & 0x1FF) ^
+		       (handle & 0x1FF);
+	else if (HTSIZE == 256) {
+		u8 *t = (u8 *) &handle;
+		return t[0] ^ t[1] ^ t[2] ^ t[3];
+	} else 
+		return handle & (HTSIZE - 1);
 }
 
 static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
@@ -152,7 +175,7 @@ static void fw_destroy(struct tcf_proto 
 	if (head == NULL)
 		return;
 
-	for (h=0; h<256; h++) {
+	for (h=0; h<HTSIZE; h++) {
 		while ((f=head->ht[h]) != NULL) {
 			head->ht[h] = f->next;
 			fw_delete_filter(tp, f);
@@ -291,7 +314,7 @@ static void fw_walk(struct tcf_proto *tp
 	if (arg->stop)
 		return;
 
-	for (h = 0; h < 256; h++) {
+	for (h = 0; h < HTSIZE; h++) {
 		struct fw_filter *f;
 
 		for (f = head->ht[h]; f; f = f->next) {
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -58,14 +58,6 @@
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
 
-
-struct tc_u32_mark
-{
-	u32		val;
-	u32		mask;
-	u32		success;
-};
-
 struct tc_u_knode
 {
 	struct tc_u_knode	*next;
diff --git a/net/sched/em_cmp.c b/net/sched/em_cmp.c
new file mode 100644
--- /dev/null
+++ b/net/sched/em_cmp.c
@@ -0,0 +1,101 @@
+/*
+ * net/sched/em_cmp.c	Simple packet data comparison ematch
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+#include <net/pkt_cls.h>
+
+static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
+{
+	return unlikely(cmp->flags & TCF_EM_CMP_TRANS);
+}
+
+static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
+			struct tcf_pkt_info *info)
+{
+	struct tcf_em_cmp *cmp = (struct tcf_em_cmp *) em->data;
+	unsigned char *ptr = tcf_get_base_ptr(skb, cmp->layer) + cmp->off;
+	u32 val = 0;
+
+	if (!tcf_valid_offset(skb, ptr, cmp->align))
+		return 0;
+
+	switch (cmp->align) {
+		case TCF_EM_ALIGN_U8:
+			val = *ptr;
+			break;
+
+		case TCF_EM_ALIGN_U16:
+			val = *ptr << 8;
+			val |= *(ptr+1);
+
+			if (cmp_needs_transformation(cmp))
+				val = be16_to_cpu(val);
+			break;
+
+		case TCF_EM_ALIGN_U32:
+			/* Worth checking boundries? The branching seems
+			 * to get worse. Visit again. */
+			val = *ptr << 24;
+			val |= *(ptr+1) << 16;
+			val |= *(ptr+2) << 8;
+			val |= *(ptr+3);
+
+			if (cmp_needs_transformation(cmp))
+				val = be32_to_cpu(val);
+			break;
+
+		default:
+			return 0;
+	}
+
+	if (cmp->mask)
+		val &= cmp->mask;
+
+	switch (cmp->opnd) {
+		case TCF_EM_OPND_EQ:
+			return val == cmp->val;
+		case TCF_EM_OPND_LT:
+			return val < cmp->val;
+		case TCF_EM_OPND_GT:
+			return val > cmp->val;
+	}
+
+	return 0;
+}
+
+static struct tcf_ematch_ops em_cmp_ops = {
+	.kind	  = TCF_EM_CMP,
+	.datalen  = sizeof(struct tcf_em_cmp),
+	.match	  = em_cmp_match,
+	.owner	  = THIS_MODULE,
+	.link	  = LIST_HEAD_INIT(em_cmp_ops.link)
+};
+
+static int __init init_em_cmp(void)
+{
+	return tcf_em_register(&em_cmp_ops);
+}
+
+static void __exit exit_em_cmp(void) 
+{
+	tcf_em_unregister(&em_cmp_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_cmp);
+module_exit(exit_em_cmp);
+
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
new file mode 100644
--- /dev/null
+++ b/net/sched/em_meta.c
@@ -0,0 +1,904 @@
+/*
+ * net/sched/em_meta.c	Metadata ematch
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ * 
+ * 	The metadata ematch compares two meta objects where each object
+ * 	represents either a meta value stored in the kernel or a static
+ * 	value provided by userspace. The objects are not provided by
+ * 	userspace itself but rather a definition providing the information
+ * 	to build them. Every object is of a certain type which must be
+ * 	equal to the object it is being compared to.
+ *
+ * 	The definition of a objects conists of the type (meta type), a
+ * 	identifier (meta id) and additional type specific information.
+ * 	The meta id is either TCF_META_TYPE_VALUE for values provided by
+ * 	userspace or a index to the meta operations table consisting of
+ * 	function pointers to type specific meta data collectors returning
+ * 	the value of the requested meta value.
+ *
+ * 	         lvalue                                   rvalue
+ * 	      +-----------+                           +-----------+
+ * 	      | type: INT |                           | type: INT |
+ * 	 def  | id: INDEV |                           | id: VALUE |
+ * 	      | data:     |                           | data: 3   |
+ * 	      +-----------+                           +-----------+
+ * 	            |                                       |
+ * 	            ---> meta_ops[INT][INDEV](...)          |
+ *	                      |                             |
+ * 	            -----------                             |
+ * 	            V                                       V
+ * 	      +-----------+                           +-----------+
+ * 	      | type: INT |                           | type: INT |
+ * 	 obj  | id: INDEV |                           | id: VALUE |
+ * 	      | data: 2   |<--data got filled out     | data: 3   |
+ * 	      +-----------+                           +-----------+
+ * 	            |                                         |
+ * 	            --------------> 2  equals 3 <--------------
+ *
+ * 	This is a simplified schema, the complexity varies depending
+ * 	on the meta type. Obviously, the length of the data must also
+ * 	be provided for non-numeric types.
+ *
+ * 	Additionaly, type dependant modifiers such as shift operators
+ * 	or mask may be applied to extend the functionaliy. As of now,
+ * 	the variable length type supports shifting the byte string to
+ * 	the right, eating up any number of octets and thus supporting
+ * 	wildcard interface name comparisons such as "ppp%" matching
+ * 	ppp0..9.
+ *
+ * 	NOTE: Certain meta values depend on other subsystems and are
+ * 	      only available if that subsytem is enabled in the kernel.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/tc_ematch/tc_em_meta.h>
+#include <net/dst.h>
+#include <net/route.h>
+#include <net/pkt_cls.h>
+#include <net/sock.h>
+
+struct meta_obj
+{
+	unsigned long		value;
+	unsigned int		len;
+};
+
+struct meta_value
+{
+	struct tcf_meta_val	hdr;
+	unsigned long		val;
+	unsigned int		len;
+};
+
+struct meta_match
+{
+	struct meta_value	lvalue;
+	struct meta_value	rvalue;
+};
+
+static inline int meta_id(struct meta_value *v)
+{
+	return TCF_META_ID(v->hdr.kind);
+}
+
+static inline int meta_type(struct meta_value *v)
+{
+	return TCF_META_TYPE(v->hdr.kind);
+}
+
+#define META_COLLECTOR(FUNC) static void meta_##FUNC(struct sk_buff *skb, \
+	struct tcf_pkt_info *info, struct meta_value *v, \
+	struct meta_obj *dst, int *err)
+
+/**************************************************************************
+ * System status & misc
+ **************************************************************************/
+
+META_COLLECTOR(int_random)
+{
+	get_random_bytes(&dst->value, sizeof(dst->value));
+}
+
+static inline unsigned long fixed_loadavg(int load)
+{
+	int rnd_load = load + (FIXED_1/200);
+	int rnd_frac = ((rnd_load & (FIXED_1-1)) * 100) >> FSHIFT;
+
+	return ((rnd_load >> FSHIFT) * 100) + rnd_frac;
+}
+
+META_COLLECTOR(int_loadavg_0)
+{
+	dst->value = fixed_loadavg(avenrun[0]);
+}
+
+META_COLLECTOR(int_loadavg_1)
+{
+	dst->value = fixed_loadavg(avenrun[1]);
+}
+
+META_COLLECTOR(int_loadavg_2)
+{
+	dst->value = fixed_loadavg(avenrun[2]);
+}
+
+/**************************************************************************
+ * Device names & indices
+ **************************************************************************/
+
+static inline int int_dev(struct net_device *dev, struct meta_obj *dst)
+{
+	if (unlikely(dev == NULL))
+		return -1;
+
+	dst->value = dev->ifindex;
+	return 0;
+}
+
+static inline int var_dev(struct net_device *dev, struct meta_obj *dst)
+{
+	if (unlikely(dev == NULL))
+		return -1;
+
+	dst->value = (unsigned long) dev->name;
+	dst->len = strlen(dev->name);
+	return 0;
+}
+
+META_COLLECTOR(int_dev)
+{
+	*err = int_dev(skb->dev, dst);
+}
+
+META_COLLECTOR(var_dev)
+{
+	*err = var_dev(skb->dev, dst);
+}
+
+META_COLLECTOR(int_indev)
+{
+	*err = int_dev(skb->input_dev, dst);
+}
+
+META_COLLECTOR(var_indev)
+{
+	*err = var_dev(skb->input_dev, dst);
+}
+
+META_COLLECTOR(int_realdev)
+{
+	*err = int_dev(skb->real_dev, dst);
+}
+
+META_COLLECTOR(var_realdev)
+{
+	*err = var_dev(skb->real_dev, dst);
+}
+
+/**************************************************************************
+ * skb attributes
+ **************************************************************************/
+
+META_COLLECTOR(int_priority)
+{
+	dst->value = skb->priority;
+}
+
+META_COLLECTOR(int_protocol)
+{
+	/* Let userspace take care of the byte ordering */
+	dst->value = skb->protocol;
+}
+
+META_COLLECTOR(int_security)
+{
+	dst->value = skb->security;
+}
+
+META_COLLECTOR(int_pkttype)
+{
+	dst->value = skb->pkt_type;
+}
+
+META_COLLECTOR(int_pktlen)
+{
+	dst->value = skb->len;
+}
+
+META_COLLECTOR(int_datalen)
+{
+	dst->value = skb->data_len;
+}
+
+META_COLLECTOR(int_maclen)
+{
+	dst->value = skb->mac_len;
+}
+
+/**************************************************************************
+ * Netfilter
+ **************************************************************************/
+
+#ifdef CONFIG_NETFILTER
+META_COLLECTOR(int_nfmark)
+{
+	dst->value = skb->nfmark;
+}
+#endif
+
+/**************************************************************************
+ * Traffic Control
+ **************************************************************************/
+
+META_COLLECTOR(int_tcindex)
+{
+	dst->value = skb->tc_index;
+}
+
+#ifdef CONFIG_NET_CLS_ACT
+META_COLLECTOR(int_tcverd)
+{
+	dst->value = skb->tc_verd;
+}
+
+META_COLLECTOR(int_tcclassid)
+{
+	dst->value = skb->tc_classid;
+}
+#endif
+
+/**************************************************************************
+ * Routing
+ **************************************************************************/
+
+#ifdef CONFIG_NET_CLS_ROUTE
+META_COLLECTOR(int_rtclassid)
+{
+	if (unlikely(skb->dst == NULL))
+		*err = -1;
+	else
+		dst->value = skb->dst->tclassid;
+}
+#endif
+
+META_COLLECTOR(int_rtiif)
+{
+	if (unlikely(skb->dst == NULL))
+		*err = -1;
+	else
+		dst->value = ((struct rtable*) skb->dst)->fl.iif;
+}
+
+/**************************************************************************
+ * Socket Attributes
+ **************************************************************************/
+
+#define SKIP_NONLOCAL(skb)			\
+	if (unlikely(skb->sk == NULL)) {	\
+		*err = -1;			\
+		return;				\
+	}
+
+META_COLLECTOR(int_sk_family)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_family;
+}
+
+META_COLLECTOR(int_sk_state)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_state;
+}
+
+META_COLLECTOR(int_sk_reuse)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_reuse;
+}
+
+META_COLLECTOR(int_sk_bound_if)
+{
+	SKIP_NONLOCAL(skb);
+	/* No error if bound_dev_if is 0, legal userspace check */
+	dst->value = skb->sk->sk_bound_dev_if;
+}
+
+META_COLLECTOR(var_sk_bound_if)
+{
+	SKIP_NONLOCAL(skb);
+
+	 if (skb->sk->sk_bound_dev_if == 0) {
+		dst->value = (unsigned long) "any";
+		dst->len = 3;
+	 } else  {
+		struct net_device *dev;
+		
+		dev = dev_get_by_index(skb->sk->sk_bound_dev_if);
+		*err = var_dev(dev, dst);
+		if (dev)
+			dev_put(dev);
+	 }
+}
+
+META_COLLECTOR(int_sk_refcnt)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = atomic_read(&skb->sk->sk_refcnt);
+}
+
+META_COLLECTOR(int_sk_rcvbuf)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_rcvbuf;
+}
+
+META_COLLECTOR(int_sk_shutdown)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_shutdown;
+}
+
+META_COLLECTOR(int_sk_proto)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_protocol;
+}
+
+META_COLLECTOR(int_sk_type)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_type;
+}
+
+META_COLLECTOR(int_sk_rmem_alloc)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = atomic_read(&skb->sk->sk_rmem_alloc);
+}
+
+META_COLLECTOR(int_sk_wmem_alloc)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = atomic_read(&skb->sk->sk_wmem_alloc);
+}
+
+META_COLLECTOR(int_sk_omem_alloc)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = atomic_read(&skb->sk->sk_omem_alloc);
+}
+
+META_COLLECTOR(int_sk_rcv_qlen)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_receive_queue.qlen;
+}
+
+META_COLLECTOR(int_sk_snd_qlen)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_write_queue.qlen;
+}
+
+META_COLLECTOR(int_sk_wmem_queued)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_wmem_queued;
+}
+
+META_COLLECTOR(int_sk_fwd_alloc)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_forward_alloc;
+}
+
+META_COLLECTOR(int_sk_sndbuf)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_sndbuf;
+}
+
+META_COLLECTOR(int_sk_alloc)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_allocation;
+}
+
+META_COLLECTOR(int_sk_route_caps)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_route_caps;
+}
+
+META_COLLECTOR(int_sk_hashent)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_hashent;
+}
+
+META_COLLECTOR(int_sk_lingertime)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_lingertime / HZ;
+}
+
+META_COLLECTOR(int_sk_err_qlen)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_error_queue.qlen;
+}
+
+META_COLLECTOR(int_sk_ack_bl)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_ack_backlog;
+}
+
+META_COLLECTOR(int_sk_max_ack_bl)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_max_ack_backlog;
+}
+
+META_COLLECTOR(int_sk_prio)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_priority;
+}
+
+META_COLLECTOR(int_sk_rcvlowat)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_rcvlowat;
+}
+
+META_COLLECTOR(int_sk_rcvtimeo)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_rcvtimeo / HZ;
+}
+
+META_COLLECTOR(int_sk_sndtimeo)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_sndtimeo / HZ;
+}
+
+META_COLLECTOR(int_sk_sendmsg_off)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_sndmsg_off;
+}
+
+META_COLLECTOR(int_sk_write_pend)
+{
+	SKIP_NONLOCAL(skb);
+	dst->value = skb->sk->sk_write_pending;
+}
+
+/**************************************************************************
+ * Meta value collectors assignment table
+ **************************************************************************/
+
+struct meta_ops
+{
+	void		(*get)(struct sk_buff *, struct tcf_pkt_info *,
+			       struct meta_value *, struct meta_obj *, int *);
+};
+
+#define META_ID(name) TCF_META_ID_##name
+#define META_FUNC(name) { .get = meta_##name }
+
+/* Meta value operations table listing all meta value collectors and
+ * assigns them to a type and meta id. */
+static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
+	[TCF_META_TYPE_VAR] = {
+		[META_ID(DEV)]			= META_FUNC(var_dev),
+		[META_ID(INDEV)]		= META_FUNC(var_indev),
+		[META_ID(REALDEV)]		= META_FUNC(var_realdev),
+		[META_ID(SK_BOUND_IF)] 		= META_FUNC(var_sk_bound_if),
+	},
+	[TCF_META_TYPE_INT] = {
+		[META_ID(RANDOM)]		= META_FUNC(int_random),
+		[META_ID(LOADAVG_0)]		= META_FUNC(int_loadavg_0),
+		[META_ID(LOADAVG_1)]		= META_FUNC(int_loadavg_1),
+		[META_ID(LOADAVG_2)]		= META_FUNC(int_loadavg_2),
+		[META_ID(DEV)]			= META_FUNC(int_dev),
+		[META_ID(INDEV)]		= META_FUNC(int_indev),
+		[META_ID(REALDEV)]		= META_FUNC(int_realdev),
+		[META_ID(PRIORITY)]		= META_FUNC(int_priority),
+		[META_ID(PROTOCOL)]		= META_FUNC(int_protocol),
+		[META_ID(SECURITY)]		= META_FUNC(int_security),
+		[META_ID(PKTTYPE)]		= META_FUNC(int_pkttype),
+		[META_ID(PKTLEN)]		= META_FUNC(int_pktlen),
+		[META_ID(DATALEN)]		= META_FUNC(int_datalen),
+		[META_ID(MACLEN)]		= META_FUNC(int_maclen),
+#ifdef CONFIG_NETFILTER
+		[META_ID(NFMARK)]		= META_FUNC(int_nfmark),
+#endif
+		[META_ID(TCINDEX)]		= META_FUNC(int_tcindex),
+#ifdef CONFIG_NET_CLS_ACT
+		[META_ID(TCVERDICT)]		= META_FUNC(int_tcverd),
+		[META_ID(TCCLASSID)]		= META_FUNC(int_tcclassid),
+#endif
+#ifdef CONFIG_NET_CLS_ROUTE
+		[META_ID(RTCLASSID)]		= META_FUNC(int_rtclassid),
+#endif
+		[META_ID(RTIIF)]		= META_FUNC(int_rtiif),
+		[META_ID(SK_FAMILY)]		= META_FUNC(int_sk_family),
+		[META_ID(SK_STATE)]		= META_FUNC(int_sk_state),
+		[META_ID(SK_REUSE)]		= META_FUNC(int_sk_reuse),
+		[META_ID(SK_BOUND_IF)]		= META_FUNC(int_sk_bound_if),
+		[META_ID(SK_REFCNT)]		= META_FUNC(int_sk_refcnt),
+		[META_ID(SK_RCVBUF)]		= META_FUNC(int_sk_rcvbuf),
+		[META_ID(SK_SNDBUF)]		= META_FUNC(int_sk_sndbuf),
+		[META_ID(SK_SHUTDOWN)]		= META_FUNC(int_sk_shutdown),
+		[META_ID(SK_PROTO)]		= META_FUNC(int_sk_proto),
+		[META_ID(SK_TYPE)]		= META_FUNC(int_sk_type),
+		[META_ID(SK_RMEM_ALLOC)]	= META_FUNC(int_sk_rmem_alloc),
+		[META_ID(SK_WMEM_ALLOC)]	= META_FUNC(int_sk_wmem_alloc),
+		[META_ID(SK_OMEM_ALLOC)]	= META_FUNC(int_sk_omem_alloc),
+		[META_ID(SK_WMEM_QUEUED)]	= META_FUNC(int_sk_wmem_queued),
+		[META_ID(SK_RCV_QLEN)]		= META_FUNC(int_sk_rcv_qlen),
+		[META_ID(SK_SND_QLEN)]		= META_FUNC(int_sk_snd_qlen),
+		[META_ID(SK_ERR_QLEN)]		= META_FUNC(int_sk_err_qlen),
+		[META_ID(SK_FORWARD_ALLOCS)]	= META_FUNC(int_sk_fwd_alloc),
+		[META_ID(SK_ALLOCS)]		= META_FUNC(int_sk_alloc),
+		[META_ID(SK_ROUTE_CAPS)]	= META_FUNC(int_sk_route_caps),
+		[META_ID(SK_HASHENT)]		= META_FUNC(int_sk_hashent),
+		[META_ID(SK_LINGERTIME)]	= META_FUNC(int_sk_lingertime),
+		[META_ID(SK_ACK_BACKLOG)]	= META_FUNC(int_sk_ack_bl),
+		[META_ID(SK_MAX_ACK_BACKLOG)]	= META_FUNC(int_sk_max_ack_bl),
+		[META_ID(SK_PRIO)]		= META_FUNC(int_sk_prio),
+		[META_ID(SK_RCVLOWAT)]		= META_FUNC(int_sk_rcvlowat),
+		[META_ID(SK_RCVTIMEO)]		= META_FUNC(int_sk_rcvtimeo),
+		[META_ID(SK_SNDTIMEO)]		= META_FUNC(int_sk_sndtimeo),
+		[META_ID(SK_SENDMSG_OFF)]	= META_FUNC(int_sk_sendmsg_off),
+		[META_ID(SK_WRITE_PENDING)]	= META_FUNC(int_sk_write_pend),
+	}
+};
+
+static inline struct meta_ops * meta_ops(struct meta_value *val)
+{
+	return &__meta_ops[meta_type(val)][meta_id(val)];
+}
+
+/**************************************************************************
+ * Type specific operations for TCF_META_TYPE_VAR
+ **************************************************************************/
+
+static int meta_var_compare(struct meta_obj *a, struct meta_obj *b)
+{
+	int r = a->len - b->len;
+
+	if (r == 0)
+		r = memcmp((void *) a->value, (void *) b->value, a->len);
+
+	return r;
+}
+
+static int meta_var_change(struct meta_value *dst, struct rtattr *rta)
+{
+	int len = RTA_PAYLOAD(rta);
+
+	dst->val = (unsigned long) kmalloc(len, GFP_KERNEL);
+	if (dst->val == 0UL)
+		return -ENOMEM;
+	memcpy((void *) dst->val, RTA_DATA(rta), len);
+	dst->len = len;
+	return 0;
+}
+
+static void meta_var_destroy(struct meta_value *v)
+{
+	if (v->val)
+		kfree((void *) v->val);
+}
+
+static void meta_var_apply_extras(struct meta_value *v,
+				  struct meta_obj *dst)
+{
+	int shift = v->hdr.shift;
+
+	if (shift && shift < dst->len)
+		dst->len -= shift;
+}
+
+static int meta_var_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
+{
+	if (v->val && v->len)
+		RTA_PUT(skb, tlv, v->len, (void *) v->val);
+	return 0;
+
+rtattr_failure:
+	return -1;
+}
+
+/**************************************************************************
+ * Type specific operations for TCF_META_TYPE_INT
+ **************************************************************************/
+
+static int meta_int_compare(struct meta_obj *a, struct meta_obj *b)
+{
+	/* Let gcc optimize it, the unlikely is not really based on
+	 * some numbers but jump free code for mismatches seems
+	 * more logical. */
+	if (unlikely(a->value == b->value))
+		return 0;
+	else if (a->value < b->value)
+		return -1;
+	else
+		return 1;
+}
+
+static int meta_int_change(struct meta_value *dst, struct rtattr *rta)
+{
+	if (RTA_PAYLOAD(rta) >= sizeof(unsigned long)) {
+		dst->val = *(unsigned long *) RTA_DATA(rta);
+		dst->len = sizeof(unsigned long);
+	} else if (RTA_PAYLOAD(rta) == sizeof(u32)) {
+		dst->val = *(u32 *) RTA_DATA(rta);
+		dst->len = sizeof(u32);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void meta_int_apply_extras(struct meta_value *v,
+				  struct meta_obj *dst)
+{
+	if (v->hdr.shift)
+		dst->value >>= v->hdr.shift;
+
+	if (v->val)
+		dst->value &= v->val;
+}
+
+static int meta_int_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
+{
+	if (v->len == sizeof(unsigned long))
+		RTA_PUT(skb, tlv, sizeof(unsigned long), &v->val);
+	else if (v->len == sizeof(u32)) {
+		u32 d = v->val;
+		RTA_PUT(skb, tlv, sizeof(d), &d);
+	}
+
+	return 0;
+
+rtattr_failure:
+	return -1;
+}
+
+/**************************************************************************
+ * Type specific operations table
+ **************************************************************************/
+
+struct meta_type_ops
+{
+	void	(*destroy)(struct meta_value *);
+	int	(*compare)(struct meta_obj *, struct meta_obj *);
+	int	(*change)(struct meta_value *, struct rtattr *);
+	void	(*apply_extras)(struct meta_value *, struct meta_obj *);
+	int	(*dump)(struct sk_buff *, struct meta_value *, int);
+};
+
+static struct meta_type_ops __meta_type_ops[TCF_META_TYPE_MAX+1] = {
+	[TCF_META_TYPE_VAR] = {
+		.destroy = meta_var_destroy,
+		.compare = meta_var_compare,
+		.change = meta_var_change,
+		.apply_extras = meta_var_apply_extras,
+		.dump = meta_var_dump
+	},
+	[TCF_META_TYPE_INT] = {
+		.compare = meta_int_compare,
+		.change = meta_int_change,
+		.apply_extras = meta_int_apply_extras,
+		.dump = meta_int_dump
+	}
+};
+
+static inline struct meta_type_ops * meta_type_ops(struct meta_value *v)
+{
+	return &__meta_type_ops[meta_type(v)];
+}
+
+/**************************************************************************
+ * Core
+ **************************************************************************/
+
+static inline int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info, 
+			   struct meta_value *v, struct meta_obj *dst)
+{
+	int err = 0;
+
+	if (meta_id(v) == TCF_META_ID_VALUE) {
+		dst->value = v->val;
+		dst->len = v->len;
+		return 0;
+	}
+
+	meta_ops(v)->get(skb, info, v, dst, &err);
+	if (err < 0)
+		return err;
+
+	if (meta_type_ops(v)->apply_extras)
+	    meta_type_ops(v)->apply_extras(v, dst);
+
+	return 0;
+}
+
+static int em_meta_match(struct sk_buff *skb, struct tcf_ematch *m,
+			 struct tcf_pkt_info *info)
+{
+	int r;
+	struct meta_match *meta = (struct meta_match *) m->data;
+	struct meta_obj l_value, r_value;
+
+	if (meta_get(skb, info, &meta->lvalue, &l_value) < 0 ||
+	    meta_get(skb, info, &meta->rvalue, &r_value) < 0)
+		return 0;
+
+	r = meta_type_ops(&meta->lvalue)->compare(&l_value, &r_value);
+
+	switch (meta->lvalue.hdr.op) {
+		case TCF_EM_OPND_EQ:
+			return !r;
+		case TCF_EM_OPND_LT:
+			return r < 0;
+		case TCF_EM_OPND_GT:
+			return r > 0;
+	}
+
+	return 0;
+}
+
+static inline void meta_delete(struct meta_match *meta)
+{
+	struct meta_type_ops *ops = meta_type_ops(&meta->lvalue);
+
+	if (ops && ops->destroy) {
+		ops->destroy(&meta->lvalue);
+		ops->destroy(&meta->rvalue);
+	}
+
+	kfree(meta);
+}
+
+static inline int meta_change_data(struct meta_value *dst, struct rtattr *rta)
+{
+	if (rta) {
+		if (RTA_PAYLOAD(rta) == 0)
+			return -EINVAL;
+
+		return meta_type_ops(dst)->change(dst, rta);
+	}
+
+	return 0;
+}
+
+static inline int meta_is_supported(struct meta_value *val)
+{
+	return (!meta_id(val) || meta_ops(val)->get);
+}
+
+static int em_meta_change(struct tcf_proto *tp, void *data, int len,
+			  struct tcf_ematch *m)
+{
+	int err = -EINVAL;
+	struct rtattr *tb[TCA_EM_META_MAX];
+	struct tcf_meta_hdr *hdr;
+	struct meta_match *meta = NULL;
+	
+	if (rtattr_parse(tb, TCA_EM_META_MAX, data, len) < 0)
+		goto errout;
+
+	if (tb[TCA_EM_META_HDR-1] == NULL ||
+	    RTA_PAYLOAD(tb[TCA_EM_META_HDR-1]) < sizeof(*hdr))
+		goto errout;
+	hdr = RTA_DATA(tb[TCA_EM_META_HDR-1]);
+
+	if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) ||
+	    TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX ||
+	    TCF_META_ID(hdr->left.kind) > TCF_META_ID_MAX ||
+	    TCF_META_ID(hdr->right.kind) > TCF_META_ID_MAX)
+		goto errout;
+
+	meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+	if (meta == NULL)
+		goto errout;
+	memset(meta, 0, sizeof(*meta));
+
+	memcpy(&meta->lvalue.hdr, &hdr->left, sizeof(hdr->left));
+	memcpy(&meta->rvalue.hdr, &hdr->right, sizeof(hdr->right));
+
+	if (!meta_is_supported(&meta->lvalue) ||
+	    !meta_is_supported(&meta->rvalue)) {
+		err = -EOPNOTSUPP;
+		goto errout;
+	}
+
+	if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE-1]) < 0 ||
+	    meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE-1]) < 0)
+		goto errout;
+
+	m->datalen = sizeof(*meta);
+	m->data = (unsigned long) meta;
+
+	err = 0;
+errout:
+	if (err && meta)
+		meta_delete(meta);
+	return err;
+}
+
+static void em_meta_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
+{
+	if (m)
+		meta_delete((struct meta_match *) m->data);
+}
+
+static int em_meta_dump(struct sk_buff *skb, struct tcf_ematch *em)
+{
+	struct meta_match *meta = (struct meta_match *) em->data;
+	struct tcf_meta_hdr hdr;
+	struct meta_type_ops *ops;
+
+	memset(&hdr, 0, sizeof(hdr));
+	memcpy(&hdr.left, &meta->lvalue.hdr, sizeof(hdr.left));
+	memcpy(&hdr.right, &meta->rvalue.hdr, sizeof(hdr.right));
+
+	RTA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+
+	ops = meta_type_ops(&meta->lvalue);
+	if (ops->dump(skb, &meta->lvalue, TCA_EM_META_LVALUE) < 0 ||
+	    ops->dump(skb, &meta->rvalue, TCA_EM_META_RVALUE) < 0)
+		goto rtattr_failure;
+
+	return 0;
+
+rtattr_failure:
+	return -1;
+}		
+
+static struct tcf_ematch_ops em_meta_ops = {
+	.kind	  = TCF_EM_META,
+	.change	  = em_meta_change,
+	.match	  = em_meta_match,
+	.destroy  = em_meta_destroy,
+	.dump	  = em_meta_dump,
+	.owner	  = THIS_MODULE,
+	.link	  = LIST_HEAD_INIT(em_meta_ops.link)
+};
+
+static int __init init_em_meta(void)
+{
+	return tcf_em_register(&em_meta_ops);
+}
+
+static void __exit exit_em_meta(void) 
+{
+	tcf_em_unregister(&em_meta_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_meta);
+module_exit(exit_em_meta);
diff --git a/net/sched/em_nbyte.c b/net/sched/em_nbyte.c
new file mode 100644
--- /dev/null
+++ b/net/sched/em_nbyte.c
@@ -0,0 +1,82 @@
+/*
+ * net/sched/em_nbyte.c	N-Byte ematch
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/tc_ematch/tc_em_nbyte.h>
+#include <net/pkt_cls.h>
+
+struct nbyte_data
+{
+	struct tcf_em_nbyte	hdr;
+	char			pattern[0];
+};
+	
+static int em_nbyte_change(struct tcf_proto *tp, void *data, int data_len,
+			   struct tcf_ematch *em)
+{
+	struct tcf_em_nbyte *nbyte = data;
+
+	if (data_len < sizeof(*nbyte) ||
+	    data_len < (sizeof(*nbyte) + nbyte->len))
+		return -EINVAL;
+
+	em->datalen = sizeof(*nbyte) + nbyte->len;
+	em->data = (unsigned long) kmalloc(em->datalen, GFP_KERNEL);
+	if (em->data == 0UL)
+		return -ENOBUFS;
+
+	memcpy((void *) em->data, data, em->datalen);
+
+	return 0;
+}
+
+static int em_nbyte_match(struct sk_buff *skb, struct tcf_ematch *em,
+			  struct tcf_pkt_info *info)
+{
+	struct nbyte_data *nbyte = (struct nbyte_data *) em->data;
+	unsigned char *ptr = tcf_get_base_ptr(skb, nbyte->hdr.layer);
+
+	ptr += nbyte->hdr.off;
+
+	if (!tcf_valid_offset(skb, ptr, nbyte->hdr.len))
+		return 0;
+
+	return !memcmp(ptr + nbyte->hdr.off, nbyte->pattern, nbyte->hdr.len);
+}
+
+static struct tcf_ematch_ops em_nbyte_ops = {
+	.kind	  = TCF_EM_NBYTE,
+	.change	  = em_nbyte_change,
+	.match	  = em_nbyte_match,
+	.owner	  = THIS_MODULE,
+	.link	  = LIST_HEAD_INIT(em_nbyte_ops.link)
+};
+
+static int __init init_em_nbyte(void)
+{
+	return tcf_em_register(&em_nbyte_ops);
+}
+
+static void __exit exit_em_nbyte(void) 
+{
+	tcf_em_unregister(&em_nbyte_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_nbyte);
+module_exit(exit_em_nbyte);
diff --git a/net/sched/em_u32.c b/net/sched/em_u32.c
new file mode 100644
--- /dev/null
+++ b/net/sched/em_u32.c
@@ -0,0 +1,63 @@
+/*
+ * net/sched/em_u32.c	U32 Ematch
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Based on net/sched/cls_u32.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <net/pkt_cls.h>
+
+static int em_u32_match(struct sk_buff *skb, struct tcf_ematch *em,
+			struct tcf_pkt_info *info)
+{
+	struct tc_u32_key *key = (struct tc_u32_key *) em->data;
+	unsigned char *ptr = skb->nh.raw;
+	
+	if (info) {
+		if (info->ptr)
+			ptr = info->ptr;
+		ptr += (info->nexthdr & key->offmask);
+	}
+
+	ptr += key->off;
+
+	if (!tcf_valid_offset(skb, ptr, sizeof(u32)))
+		return 0;
+	
+	return !(((*(u32*) ptr)  ^ key->val) & key->mask);
+}
+
+static struct tcf_ematch_ops em_u32_ops = {
+	.kind	  = TCF_EM_U32,
+	.datalen  = sizeof(struct tc_u32_key),
+	.match	  = em_u32_match,
+	.owner	  = THIS_MODULE,
+	.link	  = LIST_HEAD_INIT(em_u32_ops.link)
+};
+
+static int __init init_em_u32(void)
+{
+	return tcf_em_register(&em_u32_ops);
+}
+
+static void __exit exit_em_u32(void) 
+{
+	tcf_em_unregister(&em_u32_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_u32);
+module_exit(exit_em_u32);
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
new file mode 100644
--- /dev/null
+++ b/net/sched/ematch.c
@@ -0,0 +1,524 @@
+/*
+ * net/sched/ematch.c		Extended Match API
+ *
+ *		This program is free software; you can redistribute it 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:	Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ *
+ * An extended match (ematch) is a small classification tool not worth
+ * writing a full classifier for. Ematches can be interconnected to form
+ * a logic expression and get attached to classifiers to extend their
+ * functionatlity.
+ *
+ * The userspace part transforms the logic expressions into an array
+ * consisting of multiple sequences of interconnected ematches separated
+ * by markers. Precedence is implemented by a special ematch kind
+ * referencing a sequence beyond the marker of the current sequence
+ * causing the current position in the sequence to be pushed onto a stack
+ * to allow the current position to be overwritten by the position referenced
+ * in the special ematch. Matching continues in the new sequence until a
+ * marker is reached causing the position to be restored from the stack.
+ *
+ * Example:
+ *          A AND (B1 OR B2) AND C AND D
+ *
+ *              ------->-PUSH-------
+ *    -->--    /         -->--      \   -->--
+ *   /     \  /         /     \      \ /     \
+ * +-------+-------+-------+-------+-------+--------+
+ * | A AND | B AND | C AND | D END | B1 OR | B2 END |
+ * +-------+-------+-------+-------+-------+--------+
+ *                    \                      /
+ *                     --------<-POP---------
+ *
+ * where B is a virtual ematch referencing to sequence starting with B1.
+ * 
+ * ==========================================================================
+ *
+ * How to write an ematch in 60 seconds
+ * ------------------------------------
+ * 
+ *   1) Provide a matcher function:
+ *      static int my_match(struct sk_buff *skb, struct tcf_ematch *m,
+ *                          struct tcf_pkt_info *info)
+ *      {
+ *      	struct mydata *d = (struct mydata *) m->data;
+ *
+ *      	if (...matching goes here...)
+ *      		return 1;
+ *      	else
+ *      		return 0;
+ *      }
+ *
+ *   2) Fill out a struct tcf_ematch_ops:
+ *      static struct tcf_ematch_ops my_ops = {
+ *      	.kind = unique id,
+ *      	.datalen = sizeof(struct mydata),
+ *      	.match = my_match,
+ *      	.owner = THIS_MODULE,
+ *      };
+ *
+ *   3) Register/Unregister your ematch:
+ *      static int __init init_my_ematch(void)
+ *      {
+ *      	return tcf_em_register(&my_ops);
+ *      }
+ *
+ *      static void __exit exit_my_ematch(void)
+ *      {
+ *      	return tcf_em_unregister(&my_ops);
+ *      }
+ *
+ *      module_init(init_my_ematch);
+ *      module_exit(exit_my_ematch);
+ *
+ *   4) By now you should have two more seconds left, barely enough to
+ *      open up a beer to watch the compilation going.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <net/pkt_cls.h>
+#include <config/net/ematch/stack.h>
+
+static LIST_HEAD(ematch_ops);
+static DEFINE_RWLOCK(ematch_mod_lock);
+
+static inline struct tcf_ematch_ops * tcf_em_lookup(u16 kind)
+{
+	struct tcf_ematch_ops *e = NULL;
+
+	read_lock(&ematch_mod_lock);
+	list_for_each_entry(e, &ematch_ops, link) {
+		if (kind == e->kind) {
+			if (!try_module_get(e->owner))
+				e = NULL;
+			read_unlock(&ematch_mod_lock);
+			return e;
+		}
+	}
+	read_unlock(&ematch_mod_lock);
+
+	return NULL;
+}
+
+/**
+ * tcf_em_register - register an extended match
+ * 
+ * @ops: ematch operations lookup table
+ *
+ * This function must be called by ematches to announce their presence.
+ * The given @ops must have kind set to a unique identifier and the
+ * callback match() must be implemented. All other callbacks are optional
+ * and a fallback implementation is used instead.
+ *
+ * Returns -EEXISTS if an ematch of the same kind has already registered.
+ */
+int tcf_em_register(struct tcf_ematch_ops *ops)
+{
+	int err = -EEXIST;
+	struct tcf_ematch_ops *e;
+
+	if (ops->match == NULL)
+		return -EINVAL;
+
+	write_lock(&ematch_mod_lock);
+	list_for_each_entry(e, &ematch_ops, link)
+		if (ops->kind == e->kind)
+			goto errout;
+
+	list_add_tail(&ops->link, &ematch_ops);
+	err = 0;
+errout:
+	write_unlock(&ematch_mod_lock);
+	return err;
+}
+
+/**
+ * tcf_em_unregister - unregster and extended match
+ *
+ * @ops: ematch operations lookup table
+ *
+ * This function must be called by ematches to announce their disappearance
+ * for examples when the module gets unloaded. The @ops parameter must be
+ * the same as the one used for registration.
+ *
+ * Returns -ENOENT if no matching ematch was found.
+ */
+int tcf_em_unregister(struct tcf_ematch_ops *ops)
+{
+	int err = 0;
+	struct tcf_ematch_ops *e;
+
+	write_lock(&ematch_mod_lock);
+	list_for_each_entry(e, &ematch_ops, link) {
+		if (e == ops) {
+			list_del(&e->link);
+			goto out;
+		}
+	}
+
+	err = -ENOENT;
+out:
+	write_unlock(&ematch_mod_lock);
+	return err;
+}
+
+static inline struct tcf_ematch * tcf_em_get_match(struct tcf_ematch_tree *tree,
+						   int index)
+{
+	return &tree->matches[index];
+}
+
+
+static int tcf_em_validate(struct tcf_proto *tp,
+			   struct tcf_ematch_tree_hdr *tree_hdr,
+			   struct tcf_ematch *em, struct rtattr *rta, int idx)
+{
+	int err = -EINVAL;
+	struct tcf_ematch_hdr *em_hdr = RTA_DATA(rta);
+	int data_len = RTA_PAYLOAD(rta) - sizeof(*em_hdr);
+	void *data = (void *) em_hdr + sizeof(*em_hdr);
+
+	if (!TCF_EM_REL_VALID(em_hdr->flags))
+		goto errout;
+
+	if (em_hdr->kind == TCF_EM_CONTAINER) {
+		/* Special ematch called "container", carries an index
+		 * referencing an external ematch sequence. */
+		u32 ref;
+
+		if (data_len < sizeof(ref))
+			goto errout;
+		ref = *(u32 *) data;
+
+		if (ref >= tree_hdr->nmatches)
+			goto errout;
+
+		/* We do not allow backward jumps to avoid loops and jumps
+		 * to our own position are of course illegal. */
+		if (ref <= idx)
+			goto errout;
+
+		
+		em->data = ref;
+	} else {
+		/* Note: This lookup will increase the module refcnt
+		 * of the ematch module referenced. In case of a failure,
+		 * a destroy function is called by the underlying layer
+		 * which automatically releases the reference again, therefore
+		 * the module MUST not be given back under any circumstances
+		 * here. Be aware, the destroy function assumes that the
+		 * module is held if the ops field is non zero. */
+		em->ops = tcf_em_lookup(em_hdr->kind);
+
+		if (em->ops == NULL) {
+			err = -ENOENT;
+			goto errout;
+		}
+
+		/* ematch module provides expected length of data, so we
+		 * can do a basic sanity check. */
+		if (em->ops->datalen && data_len < em->ops->datalen)
+			goto errout;
+
+		if (em->ops->change) {
+			err = em->ops->change(tp, data, data_len, em);
+			if (err < 0)
+				goto errout;
+		} else if (data_len > 0) {
+			/* ematch module doesn't provide an own change
+			 * procedure and expects us to allocate and copy
+			 * the ematch data.
+			 *
+			 * TCF_EM_SIMPLE may be specified stating that the
+			 * data only consists of a u32 integer and the module
+			 * does not expected a memory reference but rather
+			 * the value carried. */
+			if (em_hdr->flags & TCF_EM_SIMPLE) {
+				if (data_len < sizeof(u32))
+					goto errout;
+				em->data = *(u32 *) data;
+			} else {
+				void *v = kmalloc(data_len, GFP_KERNEL);
+				if (v == NULL) {
+					err = -ENOBUFS;
+					goto errout;
+				}
+				memcpy(v, data, data_len);
+				em->data = (unsigned long) v;
+			}
+		}
+	}
+
+	em->matchid = em_hdr->matchid;
+	em->flags = em_hdr->flags;
+	em->datalen = data_len;
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * tcf_em_tree_validate - validate ematch config TLV and build ematch tree
+ *
+ * @tp: classifier kind handle
+ * @rta: ematch tree configuration TLV
+ * @tree: destination ematch tree variable to store the resulting
+ *        ematch tree.
+ *
+ * This function validates the given configuration TLV @rta and builds an
+ * ematch tree in @tree. The resulting tree must later be copied into
+ * the private classifier data using tcf_em_tree_change(). You MUST NOT
+ * provide the ematch tree variable of the private classifier data directly,
+ * the changes would not be locked properly.
+ *
+ * Returns a negative error code if the configuration TLV contains errors.
+ */
+int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta,
+			 struct tcf_ematch_tree *tree)
+{
+	int idx, list_len, matches_len, err = -EINVAL;
+	struct rtattr *tb[TCA_EMATCH_TREE_MAX];
+	struct rtattr *rt_match, *rt_hdr, *rt_list;
+	struct tcf_ematch_tree_hdr *tree_hdr;
+	struct tcf_ematch *em;
+
+	if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
+		goto errout;
+
+	rt_hdr = tb[TCA_EMATCH_TREE_HDR-1];
+	rt_list = tb[TCA_EMATCH_TREE_LIST-1];
+
+	if (rt_hdr == NULL || rt_list == NULL)
+		goto errout;
+
+	if (RTA_PAYLOAD(rt_hdr) < sizeof(*tree_hdr) ||
+	    RTA_PAYLOAD(rt_list) < sizeof(*rt_match))
+		goto errout;
+
+	tree_hdr = RTA_DATA(rt_hdr);
+	memcpy(&tree->hdr, tree_hdr, sizeof(*tree_hdr));
+
+	rt_match = RTA_DATA(rt_list);
+	list_len = RTA_PAYLOAD(rt_list);
+	matches_len = tree_hdr->nmatches * sizeof(*em);
+
+	tree->matches = kmalloc(matches_len, GFP_KERNEL);
+	if (tree->matches == NULL)
+		goto errout;
+	memset(tree->matches, 0, matches_len);
+
+	/* We do not use rtattr_parse_nested here because the maximum
+	 * number of attributes is unknown. This saves us the allocation
+	 * for a tb buffer which would serve no purpose at all.
+	 * 
+	 * The array of rt attributes is parsed in the order as they are
+	 * provided, their type must be incremental from 1 to n. Even
+	 * if it does not serve any real purpose, a failure of sticking
+	 * to this policy will result in parsing failure. */
+	for (idx = 0; RTA_OK(rt_match, list_len); idx++) {
+		err = -EINVAL;
+
+		if (rt_match->rta_type != (idx + 1))
+			goto errout_abort;
+
+		if (idx >= tree_hdr->nmatches)
+			goto errout_abort;
+
+		if (RTA_PAYLOAD(rt_match) < sizeof(struct tcf_ematch_hdr))
+			goto errout_abort;
+
+		em = tcf_em_get_match(tree, idx);
+
+		err = tcf_em_validate(tp, tree_hdr, em, rt_match, idx);
+		if (err < 0)
+			goto errout_abort;
+
+		rt_match = RTA_NEXT(rt_match, list_len);
+	}
+
+	/* Check if the number of matches provided by userspace actually
+	 * complies with the array of matches. The number was used for
+	 * the validation of references and a mismatch could lead to
+	 * undefined references during the matching process. */
+	if (idx != tree_hdr->nmatches) {
+		err = -EINVAL;
+		goto errout_abort;
+	}
+
+	err = 0;
+errout:
+	return err;
+
+errout_abort:
+	tcf_em_tree_destroy(tp, tree);
+	return err;
+}
+
+/**
+ * tcf_em_tree_destroy - destroy an ematch tree
+ *
+ * @tp: classifier kind handle
+ * @tree: ematch tree to be deleted
+ *
+ * This functions destroys an ematch tree previously created by
+ * tcf_em_tree_validate()/tcf_em_tree_change(). You must ensure that
+ * the ematch tree is not in use before calling this function.
+ */
+void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree)
+{
+	int i;
+
+	if (tree->matches == NULL)
+		return;
+
+	for (i = 0; i < tree->hdr.nmatches; i++) {
+		struct tcf_ematch *em = tcf_em_get_match(tree, i);
+
+		if (em->ops) {
+			if (em->ops->destroy)
+				em->ops->destroy(tp, em);
+			else if (!tcf_em_is_simple(em) && em->data)
+				kfree((void *) em->data);
+			module_put(em->ops->owner);
+		}
+	}
+	
+	tree->hdr.nmatches = 0;
+	kfree(tree->matches);
+}
+
+/**
+ * tcf_em_tree_dump - dump ematch tree into a rtnl message
+ *
+ * @skb: skb holding the rtnl message
+ * @t: ematch tree to be dumped
+ * @tlv: TLV type to be used to encapsulate the tree
+ *
+ * This function dumps a ematch tree into a rtnl message. It is valid to
+ * call this function while the ematch tree is in use.
+ *
+ * Returns -1 if the skb tailroom is insufficient.
+ */
+int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
+{
+	int i;
+	struct rtattr * top_start = (struct rtattr*) skb->tail;
+	struct rtattr * list_start;
+
+	RTA_PUT(skb, tlv, 0, NULL);
+	RTA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr);
+
+	list_start = (struct rtattr *) skb->tail;
+	RTA_PUT(skb, TCA_EMATCH_TREE_LIST, 0, NULL);
+
+	for (i = 0; i < tree->hdr.nmatches; i++) {
+		struct rtattr *match_start = (struct rtattr*) skb->tail;
+		struct tcf_ematch *em = tcf_em_get_match(tree, i);
+		struct tcf_ematch_hdr em_hdr = {
+			.kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER,
+			.matchid = em->matchid,
+			.flags = em->flags
+		};
+
+		RTA_PUT(skb, i+1, sizeof(em_hdr), &em_hdr);
+
+		if (em->ops && em->ops->dump) {
+			if (em->ops->dump(skb, em) < 0)
+				goto rtattr_failure;
+		} else if (tcf_em_is_container(em) || tcf_em_is_simple(em)) {
+			u32 u = em->data;
+			RTA_PUT_NOHDR(skb, sizeof(u), &u);
+		} else if (em->datalen > 0)
+			RTA_PUT_NOHDR(skb, em->datalen, (void *) em->data);
+
+		match_start->rta_len = skb->tail - (u8*) match_start;
+	}
+
+	list_start->rta_len = skb->tail - (u8 *) list_start;
+	top_start->rta_len = skb->tail - (u8 *) top_start;
+
+	return 0;
+
+rtattr_failure:
+	return -1;
+}
+
+static inline int tcf_em_match(struct sk_buff *skb, struct tcf_ematch *em,
+			       struct tcf_pkt_info *info)
+{
+	int r = em->ops->match(skb, em, info);
+	return tcf_em_is_inverted(em) ? !r : r;
+}
+
+/* Do not use this function directly, use tcf_em_tree_match instead */
+int __tcf_em_tree_match(struct sk_buff *skb, struct tcf_ematch_tree *tree,
+			struct tcf_pkt_info *info)
+{
+	int stackp = 0, match_idx = 0, res = 0;
+	struct tcf_ematch *cur_match;
+	int stack[CONFIG_NET_EMATCH_STACK];
+
+proceed:
+	while (match_idx < tree->hdr.nmatches) {
+		cur_match = tcf_em_get_match(tree, match_idx);
+
+		if (tcf_em_is_container(cur_match)) {
+			if (unlikely(stackp >= CONFIG_NET_EMATCH_STACK))
+				goto stack_overflow;
+
+			stack[stackp++] = match_idx;
+			match_idx = cur_match->data;
+			goto proceed;
+		}
+
+		res = tcf_em_match(skb, cur_match, info);
+
+		if (tcf_em_early_end(cur_match, res))
+			break;
+
+		match_idx++;
+	}
+
+pop_stack:
+	if (stackp > 0) {
+		match_idx = stack[--stackp];
+		cur_match = tcf_em_get_match(tree, match_idx);
+
+		if (tcf_em_early_end(cur_match, res))
+			goto pop_stack;
+		else {
+			match_idx++;
+			goto proceed;
+		}
+	}
+
+	return res;
+
+stack_overflow:
+	if (net_ratelimit())
+		printk("Local stack overflow, increase NET_EMATCH_STACK\n");
+	return -1;
+}
+
+EXPORT_SYMBOL(tcf_em_register);
+EXPORT_SYMBOL(tcf_em_unregister);
+EXPORT_SYMBOL(tcf_em_tree_validate);
+EXPORT_SYMBOL(tcf_em_tree_destroy);
+EXPORT_SYMBOL(tcf_em_tree_dump);
+EXPORT_SYMBOL(__tcf_em_tree_match);
diff --git a/net/sched/ipt.c b/net/sched/ipt.c
--- a/net/sched/ipt.c
+++ b/net/sched/ipt.c
@@ -284,10 +284,12 @@ tcf_ipt_dump(struct sk_buff *skb, struct
 	tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
 	tm.expires = jiffies_to_clock_t(p->tm.expires);
 	RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
+	kfree(t);
 	return skb->len;
 
       rtattr_failure:
 	skb_trim(skb, b - skb->data);
+	kfree(t);
 	return -1;
 }
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -406,11 +406,29 @@ qdisc_create(struct net_device *dev, u32
 
 	ops = qdisc_lookup_ops(kind);
 #ifdef CONFIG_KMOD
-	if (ops==NULL && tca[TCA_KIND-1] != NULL) {
+	if (ops == NULL && kind != NULL) {
 		char name[IFNAMSIZ];
 		if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
+			/* We dropped the RTNL semaphore in order to
+			 * perform the module load.  So, even if we
+			 * succeeded in loading the module we have to
+			 * tell the caller to replay the request.  We
+			 * indicate this using -EAGAIN.
+			 * We replay the request because the device may
+			 * go away in the mean time.
+			 */
+			rtnl_unlock();
 			request_module("sch_%s", name);
+			rtnl_lock();
 			ops = qdisc_lookup_ops(kind);
+			if (ops != NULL) {
+				/* We will try again qdisc_lookup_ops,
+				 * so don't keep a reference.
+				 */
+				module_put(ops->owner);
+				err = -EAGAIN;
+				goto err_out;
+			}
 		}
 	}
 #endif
@@ -606,14 +624,20 @@ static int tc_get_qdisc(struct sk_buff *
 
 static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct tcmsg *tcm = NLMSG_DATA(n);
-	struct rtattr **tca = arg;
+	struct tcmsg *tcm;
+	struct rtattr **tca;
 	struct net_device *dev;
-	u32 clid = tcm->tcm_parent;
-	struct Qdisc *q = NULL;
-	struct Qdisc *p = NULL;
+	u32 clid;
+	struct Qdisc *q, *p;
 	int err;
 
+replay:
+	/* Reinit, just in case something touches this. */
+	tcm = NLMSG_DATA(n);
+	tca = arg;
+	clid = tcm->tcm_parent;
+	q = p = NULL;
+
 	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)
 		return -ENODEV;
 
@@ -707,8 +731,11 @@ create_n_graft:
 		q = qdisc_create(dev, tcm->tcm_parent, tca, &err);
         else
 		q = qdisc_create(dev, tcm->tcm_handle, tca, &err);
-	if (q == NULL)
+	if (q == NULL) {
+		if (err == -EAGAIN)
+			goto replay;
 		return err;
+	}
 
 graft:
 	if (1) {
@@ -1262,6 +1289,7 @@ static int __init pktsched_init(void)
 
 subsys_initcall(pktsched_init);
 
+EXPORT_SYMBOL(qdisc_lookup);
 EXPORT_SYMBOL(qdisc_get_rtab);
 EXPORT_SYMBOL(qdisc_put_rtab);
 EXPORT_SYMBOL(register_qdisc);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -519,7 +519,7 @@ static void sch_atm_dequeue(unsigned lon
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
 			    flow->hdr_len);
 			atomic_add(skb->truesize,
-				   &flow->vcc->sk->sk_wmem_alloc);
+				   &sk_atm(flow->vcc)->sk_wmem_alloc);
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			(void) flow->vcc->send(flow->vcc,skb);
 		}
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -18,7 +18,7 @@
 #include <asm/byteorder.h>
 
 
-#if 1 /* control */
+#if 0 /* control */
 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
 #else
 #define DPRINTK(format,args...)
@@ -73,8 +73,13 @@ static int dsmark_graft(struct Qdisc *sc
 
 	DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new,
 	    old);
-	if (!new)
-		new = &noop_qdisc;
+
+	if (new == NULL) {
+		new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+		if (new == NULL)
+			new = &noop_qdisc;
+	}
+
 	sch_tree_lock(sch);
 	*old = xchg(&p->q,new);
 	if (*old)
@@ -163,14 +168,15 @@ static void dsmark_walk(struct Qdisc *sc
 		return;
 	for (i = 0; i < p->indices; i++) {
 		if (p->mask[i] == 0xff && !p->value[i])
-			continue;
+			goto ignore;
 		if (walker->count >= walker->skip) {
 			if (walker->fn(sch, i+1, walker) < 0) {
 				walker->stop = 1;
 				break;
 			}
 		}
-                walker->count++;
+ignore:		
+		walker->count++;
         }
 }
 
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -179,6 +179,7 @@ requeue:
 		netif_schedule(dev);
 		return 1;
 	}
+	BUG_ON((int) q->q.qlen < 0);
 	return q->q.qlen;
 }
 
@@ -539,6 +540,10 @@ void dev_activate(struct net_device *dev
 		write_unlock_bh(&qdisc_tree_lock);
 	}
 
+	if (!netif_carrier_ok(dev))
+		/* Delay activation until next carrier-on event */
+		return;
+
 	spin_lock_bh(&dev->queue_lock);
 	rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);
 	if (dev->qdisc != &noqueue_qdisc) {
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -717,6 +717,10 @@ static int htb_enqueue(struct sk_buff *s
 	if (q->direct_queue.qlen < q->direct_qlen) {
 	    __skb_queue_tail(&q->direct_queue, skb);
 	    q->direct_pkts++;
+	} else {
+	    kfree_skb(skb);
+	    sch->qstats.drops++;
+	    return NET_XMIT_DROP;
 	}
 #ifdef CONFIG_NET_CLS_ACT
     } else if (!cl) {
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -53,7 +53,6 @@
 
 struct netem_sched_data {
 	struct Qdisc	*qdisc;
-	struct sk_buff_head delayed;
 	struct timer_list timer;
 
 	u32 latency;
@@ -63,11 +62,12 @@ struct netem_sched_data {
 	u32 gap;
 	u32 jitter;
 	u32 duplicate;
+	u32 reorder;
 
 	struct crndstate {
 		unsigned long last;
 		unsigned long rho;
-	} delay_cor, loss_cor, dup_cor;
+	} delay_cor, loss_cor, dup_cor, reorder_cor;
 
 	struct disttable {
 		u32  size;
@@ -137,81 +137,79 @@ static long tabledist(unsigned long mu, 
 	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
 }
 
-/* Put skb in the private delayed queue. */
-static int delay_skb(struct Qdisc *sch, struct sk_buff *skb)
+/*
+ * Insert one skb into qdisc.
+ * Note: parent depends on return value to account for queue length.
+ * 	NET_XMIT_DROP: queue length didn't change.
+ *      NET_XMIT_SUCCESS: one skb was queued.
+ */
+static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 	struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
-	psched_tdiff_t td;
-	psched_time_t now;
-	
-	PSCHED_GET_TIME(now);
-	td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist);
-	PSCHED_TADD2(now, td, cb->time_to_send);
-	
-	/* Always queue at tail to keep packets in order */
-	if (likely(q->delayed.qlen < q->limit)) {
-		__skb_queue_tail(&q->delayed, skb);
-		sch->bstats.bytes += skb->len;
-		sch->bstats.packets++;
-
-		if (!timer_pending(&q->timer)) {
-			q->timer.expires = jiffies + PSCHED_US2JIFFIE(td);
-			add_timer(&q->timer);
-		}
-		return NET_XMIT_SUCCESS;
-	}
+	struct sk_buff *skb2;
+	int ret;
+	int count = 1;
 
-	sch->qstats.drops++;
-	kfree_skb(skb);
-	return NET_XMIT_DROP;
-}
+	pr_debug("netem_enqueue skb=%p\n", skb);
 
-static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies);
+	/* Random duplication */
+	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
+		++count;
 
 	/* Random packet drop 0 => none, ~0 => all */
-	if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
-		pr_debug("netem_enqueue: random loss\n");
+	if (q->loss && q->loss >= get_crandom(&q->loss_cor))
+		--count;
+
+	if (count == 0) {
 		sch->qstats.drops++;
 		kfree_skb(skb);
-		return 0;	/* lie about loss so TCP doesn't know */
+		return NET_XMIT_DROP;
 	}
 
-	/* Random duplication */
-	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) {
-		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-
-		pr_debug("netem_enqueue: dup %p\n", skb2);
-		if (skb2)
-			delay_skb(sch, skb2);
-	}
-
-	/* If doing simple delay then gap == 0 so all packets
-	 * go into the delayed holding queue
-	 * otherwise if doing out of order only "1 out of gap"
-	 * packets will be delayed.
+	/*
+	 * If we need to duplicate packet, then re-insert at top of the
+	 * qdisc tree, since parent queuer expects that only one
+	 * skb will be queued.
 	 */
-	if (q->counter < q->gap) {
-		int ret;
-
+	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
+		struct Qdisc *rootq = sch->dev->qdisc;
+		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
+		q->duplicate = 0;
+
+		rootq->enqueue(skb2, rootq);
+		q->duplicate = dupsave;
+	}
+
+	if (q->gap == 0 		/* not doing reordering */
+	    || q->counter < q->gap 	/* inside last reordering gap */
+	    || q->reorder < get_crandom(&q->reorder_cor)) {
+		psched_time_t now;
+		PSCHED_GET_TIME(now);
+		PSCHED_TADD2(now, tabledist(q->latency, q->jitter, 
+					    &q->delay_cor, q->delay_dist),
+			     cb->time_to_send);
 		++q->counter;
 		ret = q->qdisc->enqueue(skb, q->qdisc);
-		if (likely(ret == NET_XMIT_SUCCESS)) {
-			sch->q.qlen++;
-			sch->bstats.bytes += skb->len;
-			sch->bstats.packets++;
-		} else
-			sch->qstats.drops++;
-		return ret;
+	} else {
+		/* 
+		 * Do re-ordering by putting one out of N packets at the front
+		 * of the queue.
+		 */
+		PSCHED_GET_TIME(cb->time_to_send);
+		q->counter = 0;
+		ret = q->qdisc->ops->requeue(skb, q->qdisc);
 	}
-	
-	q->counter = 0;
 
-	return delay_skb(sch, skb);
+	if (likely(ret == NET_XMIT_SUCCESS)) {
+		sch->q.qlen++;
+		sch->bstats.bytes += skb->len;
+		sch->bstats.packets++;
+	} else
+		sch->qstats.drops++;
+
+	pr_debug("netem: enqueue ret %d\n", ret);
+	return ret;
 }
 
 /* Requeue packets but don't change time stamp */
@@ -240,56 +238,46 @@ static unsigned int netem_drop(struct Qd
 	return len;
 }
 
-/* Dequeue packet.
- *  Move all packets that are ready to send from the delay holding
- *  list to the underlying qdisc, then just call dequeue
- */
 static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
 	skb = q->qdisc->dequeue(q->qdisc);
-	if (skb) 
-		sch->q.qlen--;
-	return skb;
-}
-
-static void netem_watchdog(unsigned long arg)
-{
-	struct Qdisc *sch = (struct Qdisc *)arg;
-	struct netem_sched_data *q = qdisc_priv(sch);
-	struct net_device *dev = sch->dev;
-	struct sk_buff *skb;
-	psched_time_t now;
-
-	pr_debug("netem_watchdog: fired @%lu\n", jiffies);
-
-	spin_lock_bh(&dev->queue_lock);
-	PSCHED_GET_TIME(now);
-
-	while ((skb = skb_peek(&q->delayed)) != NULL) {
+	if (skb) {
 		const struct netem_skb_cb *cb
 			= (const struct netem_skb_cb *)skb->cb;
-		long delay 
-			= PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
-		pr_debug("netem_watchdog: skb %p@%lu %ld\n",
-			 skb, jiffies, delay);
+		psched_time_t now;
+		long delay;
 
 		/* if more time remaining? */
-		if (delay > 0) {
-			mod_timer(&q->timer, jiffies + delay);
-			break;
+		PSCHED_GET_TIME(now);
+		delay = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
+		pr_debug("netem_run: skb=%p delay=%ld\n", skb, delay);
+		if (delay <= 0) {
+			pr_debug("netem_dequeue: return skb=%p\n", skb);
+			sch->q.qlen--;
+			sch->flags &= ~TCQ_F_THROTTLED;
+			return skb;
 		}
-		__skb_unlink(skb, &q->delayed);
 
-		if (q->qdisc->enqueue(skb, q->qdisc))
+		mod_timer(&q->timer, jiffies + delay);
+		sch->flags |= TCQ_F_THROTTLED;
+
+		if (q->qdisc->ops->requeue(skb, q->qdisc) != 0)
 			sch->qstats.drops++;
-		else
-			sch->q.qlen++;
 	}
-	qdisc_run(dev);
-	spin_unlock_bh(&dev->queue_lock);
+
+	return NULL;
+}
+
+static void netem_watchdog(unsigned long arg)
+{
+	struct Qdisc *sch = (struct Qdisc *)arg;
+
+	pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen);
+	sch->flags &= ~TCQ_F_THROTTLED;
+	netif_schedule(sch->dev);
 }
 
 static void netem_reset(struct Qdisc *sch)
@@ -297,9 +285,8 @@ static void netem_reset(struct Qdisc *sc
 	struct netem_sched_data *q = qdisc_priv(sch);
 
 	qdisc_reset(q->qdisc);
-	skb_queue_purge(&q->delayed);
-
 	sch->q.qlen = 0;
+	sch->flags &= ~TCQ_F_THROTTLED;
 	del_timer_sync(&q->timer);
 }
 
@@ -365,6 +352,19 @@ static int get_correlation(struct Qdisc 
 	return 0;
 }
 
+static int get_reorder(struct Qdisc *sch, const struct rtattr *attr)
+{
+	struct netem_sched_data *q = qdisc_priv(sch);
+	const struct tc_netem_reorder *r = RTA_DATA(attr);
+
+	if (RTA_PAYLOAD(attr) != sizeof(*r))
+		return -EINVAL;
+
+	q->reorder = r->probability;
+	init_crandom(&q->reorder_cor, r->correlation);
+	return 0;
+}
+
 static int netem_change(struct Qdisc *sch, struct rtattr *opt)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
@@ -385,9 +385,15 @@ static int netem_change(struct Qdisc *sc
 	q->jitter = qopt->jitter;
 	q->limit = qopt->limit;
 	q->gap = qopt->gap;
+	q->counter = 0;
 	q->loss = qopt->loss;
 	q->duplicate = qopt->duplicate;
 
+	/* for compatiablity with earlier versions.
+	 * if gap is set, need to assume 100% probablity
+	 */
+	q->reorder = ~0;
+
 	/* Handle nested options after initial queue options.
 	 * Should have put all options in nested format but too late now.
 	 */ 
@@ -409,6 +415,11 @@ static int netem_change(struct Qdisc *sc
 			if (ret)
 				return ret;
 		}
+		if (tb[TCA_NETEM_REORDER-1]) {
+			ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]);
+			if (ret)
+				return ret;
+		}
 	}
 
 
@@ -423,11 +434,9 @@ static int netem_init(struct Qdisc *sch,
 	if (!opt)
 		return -EINVAL;
 
-	skb_queue_head_init(&q->delayed);
 	init_timer(&q->timer);
 	q->timer.function = netem_watchdog;
 	q->timer.data = (unsigned long) sch;
-	q->counter = 0;
 
 	q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
 	if (!q->qdisc) {
@@ -459,6 +468,7 @@ static int netem_dump(struct Qdisc *sch,
 	struct rtattr *rta = (struct rtattr *) b;
 	struct tc_netem_qopt qopt;
 	struct tc_netem_corr cor;
+	struct tc_netem_reorder reorder;
 
 	qopt.latency = q->latency;
 	qopt.jitter = q->jitter;
@@ -472,6 +482,11 @@ static int netem_dump(struct Qdisc *sch,
 	cor.loss_corr = q->loss_cor.rho;
 	cor.dup_corr = q->dup_cor.rho;
 	RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
+
+	reorder.probability = q->reorder;
+	reorder.correlation = q->reorder_cor.rho;
+	RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
+
 	rta->rta_len = skb->tail - b;
 
 	return skb->len;
diff --git a/net/sched/simple.c b/net/sched/simple.c
new file mode 100644
--- /dev/null
+++ b/net/sched/simple.c
@@ -0,0 +1,93 @@
+/*
+ * net/sched/simp.c	Simple example of an action
+ *
+ *		This program is free software; you can redistribute it 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:	Jamal Hadi Salim (2005)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <net/pkt_sched.h>
+
+#define TCA_ACT_SIMP 22
+
+/* XXX: Hide all these common elements under some macro 
+ * probably
+*/
+#include <linux/tc_act/tc_defact.h>
+#include <net/tc_act/tc_defact.h>
+
+/* use generic hash table with 8 buckets */
+#define MY_TAB_SIZE     8
+#define MY_TAB_MASK     (MY_TAB_SIZE - 1)
+static u32 idx_gen;
+static struct tcf_defact *tcf_simp_ht[MY_TAB_SIZE];
+static DEFINE_RWLOCK(simp_lock);
+
+/* override the defaults */
+#define tcf_st		tcf_defact
+#define tc_st		tc_defact
+#define tcf_t_lock	simp_lock
+#define tcf_ht		tcf_simp_ht
+
+#define CONFIG_NET_ACT_INIT 1
+#include <net/pkt_act.h>
+#include <net/act_generic.h>
+
+static int tcf_simp(struct sk_buff **pskb, struct tc_action *a)
+{
+	struct sk_buff *skb = *pskb;
+	struct tcf_defact *p = PRIV(a, defact);
+
+	spin_lock(&p->lock);
+	p->tm.lastuse = jiffies;
+	p->bstats.bytes += skb->len;
+	p->bstats.packets++;
+
+	/* print policy string followed by _ then packet count 
+	 * Example if this was the 3rd packet and the string was "hello" 
+	 * then it would look like "hello_3" (without quotes) 
+	 **/
+	printk("simple: %s_%d\n", (char *)p->defdata, p->bstats.packets);
+	spin_unlock(&p->lock);
+	return p->action;
+}
+
+static struct tc_action_ops act_simp_ops = {
+	.kind = "simple",
+	.type = TCA_ACT_SIMP,
+	.capab = TCA_CAP_NONE,
+	.owner = THIS_MODULE,
+	.act = tcf_simp,
+	tca_use_default_ops
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2005)");
+MODULE_DESCRIPTION("Simple example action");
+MODULE_LICENSE("GPL");
+
+static int __init simp_init_module(void)
+{
+	int ret = tcf_register_action(&act_simp_ops);
+	if (!ret)
+		printk("Simple TC action Loaded\n");
+	return ret;
+}
+
+static void __exit simp_cleanup_module(void)
+{
+	tcf_unregister_action(&act_simp_ops);
+}
+
+module_init(simp_init_module);
+module_exit(simp_cleanup_module);
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -125,8 +125,9 @@ static struct sctp_endpoint *sctp_endpoi
 		sp->autoclose * HZ;
 
 	/* Use SCTP specific send buffer space queues.  */
+	ep->sndbuf_policy = sctp_sndbuf_policy;
 	sk->sk_write_space = sctp_write_space;
-	sk->sk_use_write_queue = 1;
+	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
 	/* Initialize the secret key used with cookie. */
 	get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
diff --git a/net/sctp/input.c b/net/sctp/input.c
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -100,6 +100,21 @@ static inline int sctp_rcv_checksum(stru
 	return 0;
 }
 
+/* The free routine for skbuffs that sctp receives */
+static void sctp_rfree(struct sk_buff *skb)
+{
+	atomic_sub(sizeof(struct sctp_chunk),&skb->sk->sk_rmem_alloc);
+	sock_rfree(skb);
+}
+
+/* The ownership wrapper routine to do receive buffer accounting */
+static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
+{
+	skb_set_owner_r(skb,sk);
+	skb->destructor = sctp_rfree;
+	atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
+}
+
 /*
  * This is the routine which IP calls when receiving an SCTP packet.
  */
@@ -163,6 +178,37 @@ int sctp_rcv(struct sk_buff *skb)
 
 	asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport);
 
+	if (!asoc)
+		ep = __sctp_rcv_lookup_endpoint(&dest);
+
+	/* Retrieve the common input handling substructure. */
+	rcvr = asoc ? &asoc->base : &ep->base;
+	sk = rcvr->sk;
+
+	/*
+	 * If a frame arrives on an interface and the receiving socket is
+	 * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB
+	 */
+	if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb)))
+	{
+		sock_put(sk);
+		if (asoc) {
+			sctp_association_put(asoc);
+			asoc = NULL;
+		} else {
+			sctp_endpoint_put(ep);
+			ep = NULL;
+		}
+		sk = sctp_get_ctl_sock();
+		ep = sctp_sk(sk)->ep;
+		sctp_endpoint_hold(ep);
+		sock_hold(sk);
+		rcvr = &ep->base;
+	}
+
+	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
+		goto discard_release;
+
 	/*
 	 * RFC 2960, 8.4 - Handle "Out of the blue" Packets.
 	 * An SCTP packet is called an "out of the blue" (OOTB)
@@ -172,17 +218,12 @@ int sctp_rcv(struct sk_buff *skb)
 	 * packet belongs.
 	 */
 	if (!asoc) {
-		ep = __sctp_rcv_lookup_endpoint(&dest);
 		if (sctp_rcv_ootb(skb)) {
 			SCTP_INC_STATS_BH(SCTP_MIB_OUTOFBLUES);
 			goto discard_release;
 		}
 	}
 
-	/* Retrieve the common input handling substructure. */
-	rcvr = asoc ? &asoc->base : &ep->base;
-	sk = rcvr->sk;
-
 	/* SCTP seems to always need a timestamp right now (FIXME) */
 	if (skb->stamp.tv_sec == 0) {
 		do_gettimeofday(&skb->stamp);
@@ -203,6 +244,8 @@ int sctp_rcv(struct sk_buff *skb)
 		goto discard_release;
 	}
 
+	sctp_rcv_set_owner_r(skb,sk);
+
 	/* Remember what endpoint is to handle this packet. */
 	chunk->rcvr = rcvr;
 
@@ -243,13 +286,11 @@ discard_it:
 
 discard_release:
 	/* Release any structures we may be holding. */
-	if (asoc) {
-		sock_put(asoc->base.sk);
+	sock_put(sk);
+	if (asoc)
 		sctp_association_put(asoc);
-	} else {
-		sock_put(ep->base.sk);
+	else
 		sctp_endpoint_put(ep);
-	}
 
 	goto discard_it;
 }
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -496,9 +496,7 @@ static void sctp_v6_inaddr_any(union sct
 /* Is this a wildcard address? */
 static int sctp_v6_is_any(const union sctp_addr *addr)
 {
-	int type;
-	type = ipv6_addr_type((struct in6_addr *)&addr->v6.sin6_addr);
-	return IPV6_ADDR_ANY == type;
+	return ipv6_addr_any(&addr->v6.sin6_addr);
 }
 
 /* Should this be available for binding?   */
@@ -594,13 +592,11 @@ static struct sock *sctp_v6_create_accep
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
 	struct sctp6_sock *newsctp6sk;
 
-	newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot->slab_obj_size,
-			 sk->sk_prot->slab);
+	newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot, 1);
 	if (!newsk)
 		goto out;
 
 	sock_init_data(NULL, newsk);
-	sk_set_owner(newsk, THIS_MODULE);
 
 	newsk->sk_type = SOCK_STREAM;
 
@@ -609,11 +605,11 @@ static struct sock *sctp_v6_create_accep
 	newsk->sk_reuse = sk->sk_reuse;
 
 	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
 	newsk->sk_family = PF_INET6;
 	newsk->sk_protocol = IPPROTO_SCTP;
 	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
 	newsk->sk_shutdown = sk->sk_shutdown;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 
 	newsctp6sk = (struct sctp6_sock *)newsk;
 	inet_sk(newsk)->pinet6 = &newsctp6sk->inet6;
@@ -816,26 +812,23 @@ static int sctp_inet6_bind_verify(struct
 	if (addr->sa.sa_family != AF_INET6)
 		af = sctp_get_af_specific(addr->sa.sa_family);
 	else {
-		struct sock *sk;
 		int type = ipv6_addr_type(&addr->v6.sin6_addr);
-		sk = sctp_opt2sk(opt);
+		struct net_device *dev;
+
 		if (type & IPV6_ADDR_LINKLOCAL) {
-			/* Note: Behavior similar to af_inet6.c:
-			 *  1) Overrides previous bound_dev_if
-			 *  2) Destructive even if bind isn't successful.
-			 */
-
-			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+			if (!addr->v6.sin6_scope_id)
+				return 0;
+			dev = dev_get_by_index(addr->v6.sin6_scope_id);
+			if (!dev)
 				return 0;
+			dev_put(dev);
 		}
 		af = opt->pf->af;
 	}
 	return af->available(addr, opt);
 }
 
-/* Verify that the provided sockaddr looks bindable.   Common verification,
+/* Verify that the provided sockaddr looks sendable.   Common verification,
  * has already been taken care of.
  */
 static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
@@ -846,19 +839,16 @@ static int sctp_inet6_send_verify(struct
 	if (addr->sa.sa_family != AF_INET6)
 		af = sctp_get_af_specific(addr->sa.sa_family);
 	else {
-		struct sock *sk;
 		int type = ipv6_addr_type(&addr->v6.sin6_addr);
-		sk = sctp_opt2sk(opt);
+		struct net_device *dev;
+
 		if (type & IPV6_ADDR_LINKLOCAL) {
-			/* Note: Behavior similar to af_inet6.c:
-			 *  1) Overrides previous bound_dev_if
-			 *  2) Destructive even if bind isn't successful.
-			 */
-
-			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+			if (!addr->v6.sin6_scope_id)
+				return 0;
+			dev = dev_get_by_index(addr->v6.sin6_scope_id);
+			if (!dev)
 				return 0;
+			dev_put(dev);
 		}
 		af = opt->pf->af;
 	}
@@ -974,14 +964,14 @@ static struct sctp_pf sctp_pf_inet6_spec
 /* Initialize IPv6 support and register with inet6 stack.  */
 int sctp_v6_init(void)
 {
-	int rc = sk_alloc_slab(&sctpv6_prot, "sctpv6_sock");
+	int rc = proto_register(&sctpv6_prot, 1);
 
 	if (rc)
 		goto out;
 	/* Register inet6 protocol. */
 	rc = -EAGAIN;
 	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
-		goto out_sctp_free_slab;
+		goto out_unregister_sctp_proto;
 
 	/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
 	inet6_register_protosw(&sctpv6_seqpacket_protosw);
@@ -998,8 +988,8 @@ int sctp_v6_init(void)
 	rc = 0;
 out:
 	return rc;
-out_sctp_free_slab:
-	sk_free_slab(&sctpv6_prot);
+out_unregister_sctp_proto:
+	proto_unregister(&sctpv6_prot);
 	goto out;
 }
 
@@ -1011,5 +1001,5 @@ void sctp_v6_exit(void)
 	inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
 	inet6_unregister_protosw(&sctpv6_stream_protosw);
 	unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
-	sk_free_slab(&sctpv6_prot);
+	proto_unregister(&sctpv6_prot);
 }
diff --git a/net/sctp/output.c b/net/sctp/output.c
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -313,12 +313,12 @@ int sctp_packet_transmit(struct sctp_pac
 	sk = chunk->skb->sk;
 
 	/* Allocate the new skb.  */
-	nskb = dev_alloc_skb(packet->size);
+	nskb = alloc_skb(packet->size + LL_MAX_HEADER, GFP_ATOMIC);
 	if (!nskb)
 		goto nomem;
 
 	/* Make sure the outbound skb has enough header room reserved. */
-	skb_reserve(nskb, packet->overhead);
+	skb_reserve(nskb, packet->overhead + LL_MAX_HEADER);
 
 	/* Set the owning socket so that we know where to get the
 	 * destination IP address.
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -132,14 +132,25 @@ void sctp_snmp_proc_exit(void)
 static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
 {
 	struct list_head *pos;
+	struct sctp_association *asoc;
 	struct sctp_sockaddr_entry *laddr;
-	union sctp_addr *addr;
+	struct sctp_transport *peer;
+	union sctp_addr *addr, *primary = NULL;
 	struct sctp_af *af;
 
+	if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
+	    asoc = sctp_assoc(epb);
+	    peer = asoc->peer.primary_path;
+	    primary = &peer->saddr;
+	}
+
 	list_for_each(pos, &epb->bind_addr.address_list) {
 		laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
 		addr = (union sctp_addr *)&laddr->a;
 		af = sctp_get_af_specific(addr->sa.sa_family);
+		if (primary && af->cmp_addr(addr, primary)) {
+			seq_printf(seq, "*");
+		}
 		af->seq_dump_addr(seq, addr);
 	}
 }
@@ -149,17 +160,54 @@ static void sctp_seq_dump_remote_addrs(s
 {
 	struct list_head *pos;
 	struct sctp_transport *transport;
-	union sctp_addr *addr;
+	union sctp_addr *addr, *primary;
 	struct sctp_af *af;
 
+	primary = &(assoc->peer.primary_addr);
 	list_for_each(pos, &assoc->peer.transport_addr_list) {
 		transport = list_entry(pos, struct sctp_transport, transports);
 		addr = (union sctp_addr *)&transport->ipaddr;
 		af = sctp_get_af_specific(addr->sa.sa_family);
+		if (af->cmp_addr(addr, primary)) {
+			seq_printf(seq, "*");
+		}
 		af->seq_dump_addr(seq, addr);
 	}
 }
 
+static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos > sctp_ep_hashsize)
+		return NULL;
+
+	if (*pos < 0)
+		*pos = 0;
+
+	if (*pos == 0)
+		seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");
+
+	++*pos;
+
+	return (void *)pos;
+}
+
+static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
+{
+	return;
+}
+
+
+static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	if (*pos > sctp_ep_hashsize)
+		return NULL;
+
+	++*pos;
+
+	return pos;
+}
+
+
 /* Display sctp endpoints (/proc/net/sctp/eps). */
 static int sctp_eps_seq_show(struct seq_file *seq, void *v)
 {
@@ -167,38 +215,50 @@ static int sctp_eps_seq_show(struct seq_
 	struct sctp_ep_common *epb;
 	struct sctp_endpoint *ep;
 	struct sock *sk;
-	int hash;
+	int    hash = *(int *)v;
 
-	seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT LADDRS\n");
-	for (hash = 0; hash < sctp_ep_hashsize; hash++) {
-		head = &sctp_ep_hashtable[hash];
-		read_lock(&head->lock);
-		for (epb = head->chain; epb; epb = epb->next) {
-			ep = sctp_ep(epb);
-			sk = epb->sk;
-			seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
-				   sctp_sk(sk)->type, sk->sk_state, hash,
-				   epb->bind_addr.port);
-			sctp_seq_dump_local_addrs(seq, epb);
-			seq_printf(seq, "\n");
-		}
-		read_unlock(&head->lock);
+	if (hash > sctp_ep_hashsize)
+		return -ENOMEM;
+
+	head = &sctp_ep_hashtable[hash-1];
+	sctp_local_bh_disable();
+	read_lock(&head->lock);
+	for (epb = head->chain; epb; epb = epb->next) {
+		ep = sctp_ep(epb);
+		sk = epb->sk;
+		seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
+			   sctp_sk(sk)->type, sk->sk_state, hash-1,
+			   epb->bind_addr.port,
+			   sock_i_uid(sk), sock_i_ino(sk));
+
+		sctp_seq_dump_local_addrs(seq, epb);
+		seq_printf(seq, "\n");
 	}
+	read_unlock(&head->lock);
+	sctp_local_bh_enable();
 
 	return 0;
 }
 
+static struct seq_operations sctp_eps_ops = {
+	.start = sctp_eps_seq_start,
+	.next  = sctp_eps_seq_next,
+	.stop  = sctp_eps_seq_stop,
+	.show  = sctp_eps_seq_show,
+};
+
+
 /* Initialize the seq file operations for 'eps' object. */
 static int sctp_eps_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, sctp_eps_seq_show, NULL);
+	return seq_open(file, &sctp_eps_ops);
 }
 
 static struct file_operations sctp_eps_seq_fops = {
 	.open	 = sctp_eps_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = seq_release,
 };
 
 /* Set up the proc fs entry for 'eps' object. */
@@ -221,6 +281,40 @@ void sctp_eps_proc_exit(void)
 	remove_proc_entry("eps", proc_net_sctp);
 }
 
+
+static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos > sctp_assoc_hashsize)
+		return NULL;
+
+	if (*pos < 0)
+		*pos = 0;
+
+	if (*pos == 0)
+		seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
+				"RPORT LADDRS <-> RADDRS\n");
+
+	++*pos;
+
+	return (void *)pos;
+}
+
+static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
+{
+	return;
+}
+
+
+static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	if (*pos > sctp_assoc_hashsize)
+		return NULL;
+
+	++*pos;
+
+	return pos;
+}
+
 /* Display sctp associations (/proc/net/sctp/assocs). */
 static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
 {
@@ -228,43 +322,57 @@ static int sctp_assocs_seq_show(struct s
 	struct sctp_ep_common *epb;
 	struct sctp_association *assoc;
 	struct sock *sk;
-	int hash;
+	int    hash = *(int *)v;
 
-	seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT LPORT RPORT "
-			"LADDRS <-> RADDRS\n");
-	for (hash = 0; hash < sctp_assoc_hashsize; hash++) {
-		head = &sctp_assoc_hashtable[hash];
-		read_lock(&head->lock);
-		for (epb = head->chain; epb; epb = epb->next) {
-			assoc = sctp_assoc(epb);
-			sk = epb->sk;
-			seq_printf(seq,
-				   "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
-				   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
-				   assoc->state, hash, epb->bind_addr.port,
-				   assoc->peer.port);
-			sctp_seq_dump_local_addrs(seq, epb);
-			seq_printf(seq, "<-> ");
-			sctp_seq_dump_remote_addrs(seq, assoc);
-			seq_printf(seq, "\n");
-		}
-		read_unlock(&head->lock);
+	if (hash > sctp_assoc_hashsize)
+		return -ENOMEM;
+
+	head = &sctp_assoc_hashtable[hash-1];
+	sctp_local_bh_disable();
+	read_lock(&head->lock);
+	for (epb = head->chain; epb; epb = epb->next) {
+		assoc = sctp_assoc(epb);
+		sk = epb->sk;
+		seq_printf(seq,
+			   "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
+			   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
+			   assoc->state, hash-1, assoc->assoc_id,
+			   (sk->sk_rcvbuf - assoc->rwnd),
+			   assoc->sndbuf_used,
+			   sock_i_uid(sk), sock_i_ino(sk),
+			   epb->bind_addr.port,
+			   assoc->peer.port);
+
+		seq_printf(seq, " ");
+		sctp_seq_dump_local_addrs(seq, epb);
+		seq_printf(seq, "<-> ");
+		sctp_seq_dump_remote_addrs(seq, assoc);
+		seq_printf(seq, "\n");
 	}
+	read_unlock(&head->lock);
+	sctp_local_bh_enable();
 
 	return 0;
 }
 
+static struct seq_operations sctp_assoc_ops = {
+	.start = sctp_assocs_seq_start,
+	.next  = sctp_assocs_seq_next,
+	.stop  = sctp_assocs_seq_stop,
+	.show  = sctp_assocs_seq_show,
+};
+
 /* Initialize the seq file operations for 'assocs' object. */
 static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, sctp_assocs_seq_show, NULL);
+	return seq_open(file, &sctp_assoc_ops);
 }
 
 static struct file_operations sctp_assocs_seq_fops = {
 	.open	 = sctp_assocs_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = seq_release,
 };
 
 /* Set up the proc fs entry for 'assocs' object. */
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -378,10 +378,13 @@ static int sctp_v4_available(union sctp_
 {
 	int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
 
-	/* FIXME: ip_nonlocal_bind sysctl support. */
 
-	if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL)
+	if (addr->v4.sin_addr.s_addr != INADDR_ANY &&
+	   ret != RTN_LOCAL &&
+	   !sp->inet.freebind &&
+	   !sysctl_ip_nonlocal_bind)
 		return 0;
+
 	return 1;
 }
 
@@ -550,30 +553,26 @@ static int sctp_v4_is_ce(const struct sk
 static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
 					     struct sctp_association *asoc)
 {
-	struct sock *newsk;
 	struct inet_sock *inet = inet_sk(sk);
 	struct inet_sock *newinet;
+	struct sock *newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot, 1);
 
-	newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot->slab_obj_size,
-			 sk->sk_prot->slab);
 	if (!newsk)
 		goto out;
 
 	sock_init_data(NULL, newsk);
-	sk_set_owner(newsk, THIS_MODULE);
 
 	newsk->sk_type = SOCK_STREAM;
 
-	newsk->sk_prot = sk->sk_prot;
 	newsk->sk_no_check = sk->sk_no_check;
 	newsk->sk_reuse = sk->sk_reuse;
 	newsk->sk_shutdown = sk->sk_shutdown;
 
 	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
 	newsk->sk_family = PF_INET;
 	newsk->sk_protocol = IPPROTO_SCTP;
 	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+	sock_reset_flag(newsk, SOCK_ZAPPED);
 
 	newinet = inet_sk(newsk);
 
@@ -970,7 +969,7 @@ SCTP_STATIC __init int sctp_init(void)
 	if (!sctp_sanity_check())
 		goto out;
 
-	status = sk_alloc_slab(&sctp_prot, "sctp_sock");
+	status = proto_register(&sctp_prot, 1);
 	if (status)
 		goto out;
 
@@ -1047,6 +1046,9 @@ SCTP_STATIC __init int sctp_init(void)
 	sctp_max_retrans_path		= 5;
 	sctp_max_retrans_init		= 8;
 
+	/* Sendbuffer growth	    - do per-socket accounting */
+	sctp_sndbuf_policy		= 0;
+
 	/* HB.interval              - 30 seconds */
 	sctp_hb_interval		= 30 * HZ;
 
@@ -1163,8 +1165,6 @@ SCTP_STATIC __init int sctp_init(void)
 	status = 0;
 out:
 	return status;
-err_add_protocol:
-	sk_free_slab(&sctp_prot);
 err_ctl_sock_init:
 	sctp_v6_exit();
 err_v6_init:
@@ -1192,6 +1192,8 @@ err_bucket_cachep:
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_seqpacket_protosw);
 	inet_unregister_protosw(&sctp_stream_protosw);
+err_add_protocol:
+	proto_unregister(&sctp_prot);
 	goto out;
 }
 
@@ -1233,7 +1235,7 @@ SCTP_STATIC __exit void sctp_exit(void)
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_seqpacket_protosw);
 	inet_unregister_protosw(&sctp_stream_protosw);
-	sk_free_slab(&sctp_prot);
+	proto_unregister(&sctp_prot);
 }
 
 module_init(sctp_init);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -710,7 +710,9 @@ struct sctp_chunk *sctp_make_shutdown_co
 	struct sctp_chunk *retval;
 	__u8 flags = 0;
 
-	/* Maybe set the T-bit if we have no association. */
+	/* Set the T-bit if we have no association (vtag will be
+	 * reflected)
+	 */
 	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
 
 	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);
@@ -732,7 +734,7 @@ struct sctp_chunk *sctp_make_shutdown_co
 }
 
 /* Create an ABORT.  Note that we set the T bit if we have no
- * association.
+ * association, except when responding to an INIT (sctpimpguide 2.41).
  */
 struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
 			      const struct sctp_chunk *chunk,
@@ -741,8 +743,16 @@ struct sctp_chunk *sctp_make_abort(const
 	struct sctp_chunk *retval;
 	__u8 flags = 0;
 
-	/* Maybe set the T-bit if we have no association.  */
-	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
+	/* Set the T-bit if we have no association and 'chunk' is not
+	 * an INIT (vtag will be reflected).
+	 */
+	if (!asoc) {
+		if (chunk && chunk->chunk_hdr &&
+		    chunk->chunk_hdr->type == SCTP_CID_INIT)
+			flags = 0;
+		else
+			flags = SCTP_CHUNK_FLAG_T;
+	}
 
 	retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint);
 
@@ -2744,7 +2754,6 @@ struct sctp_chunk *sctp_make_fwdtsn(cons
 
 	hint = (nstreams + 1) * sizeof(__u32);
 
-	/* Maybe set the T-bit if we have no association.  */
 	retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint);
 
 	if (!retval)
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -126,15 +126,18 @@ sctp_chunk_length_valid(struct sctp_chun
  * should stop the T2-shutdown timer and remove all knowledge of the
  * association (and thus the association enters the CLOSED state).
  *
- * Verification Tag: 8.5.1(C)
+ * Verification Tag: 8.5.1(C), sctpimpguide 2.41.
  * C) Rules for packet carrying SHUTDOWN COMPLETE:
  * ...
- * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
- *   Verification Tag field of the packet matches its own tag OR it is
- *   set to its peer's tag and the T bit is set in the Chunk Flags.
- *   Otherwise, the receiver MUST silently discard the packet and take
- *   no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if
- *   it is not in the SHUTDOWN-ACK-SENT state.
+ * - The receiver of a SHUTDOWN COMPLETE shall accept the packet
+ *   if the Verification Tag field of the packet matches its own tag and
+ *   the T bit is not set
+ *   OR
+ *   it is set to its peer's tag and the T bit is set in the Chunk
+ *   Flags.
+ *   Otherwise, the receiver MUST silently discard the packet
+ *   and take no further action.  An endpoint MUST ignore the
+ *   SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state.
  *
  * Inputs
  * (endpoint, asoc, chunk)
@@ -268,7 +271,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(
 	 */
 	if (!sctp_sstate(sk, LISTENING) ||
 	    (sctp_style(sk, TCP) &&
-	     (sk->sk_ack_backlog >= sk->sk_max_ack_backlog)))
+	     sk_acceptq_is_full(sk)))
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
@@ -2858,16 +2861,16 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(
 /*
  * Generate an ABORT in response to a packet.
  *
- * Section: 8.4 Handle "Out of the blue" Packets
+ * Section: 8.4 Handle "Out of the blue" Packets, sctpimpguide 2.41
  *
- * 8) The receiver should respond to the sender of the OOTB packet
- *    with an ABORT.  When sending the ABORT, the receiver of the
- *    OOTB packet MUST fill in the Verification Tag field of the
- *    outbound packet with the value found in the Verification Tag
- *    field of the OOTB packet and set the T-bit in the Chunk Flags
- *    to indicate that no TCB was found.  After sending this ABORT,
- *    the receiver of the OOTB packet shall discard the OOTB packet
- *    and take no further action.
+ * 8) The receiver should respond to the sender of the OOTB packet with
+ *    an ABORT.  When sending the ABORT, the receiver of the OOTB packet
+ *    MUST fill in the Verification Tag field of the outbound packet
+ *    with the value found in the Verification Tag field of the OOTB
+ *    packet and set the T-bit in the Chunk Flags to indicate that the
+ *    Verification Tag is reflected.  After sending this ABORT, the
+ *    receiver of the OOTB packet shall discard the OOTB packet and take
+ *    no further action.
  *
  * Verification Tag:
  *
@@ -2895,6 +2898,10 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(
 			return SCTP_DISPOSITION_NOMEM;
 		}
 
+		/* Reflect vtag if T-Bit is set */
+		if (sctp_test_T_bit(abort))
+			packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+
 		/* Set the skb to the belonging sock for accounting.  */
 		abort->skb->sk = ep->base.sk;
 
@@ -3026,22 +3033,24 @@ nomem:
 }
 
 /*
- * RFC 2960, 8.4 - Handle "Out of the blue" Packets
+ * RFC 2960, 8.4 - Handle "Out of the blue" Packets, sctpimpguide 2.41.
+ *
  * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should
  *    respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.
  *    When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
  *    packet must fill in the Verification Tag field of the outbound
  *    packet with the Verification Tag received in the SHUTDOWN ACK and
- *    set the T-bit in the Chunk Flags to indicate that no TCB was
- *    found. Otherwise,
+ *    set the T-bit in the Chunk Flags to indicate that the Verification
+ *    Tag is reflected.
  *
  * 8) The receiver should respond to the sender of the OOTB packet with
  *    an ABORT.  When sending the ABORT, the receiver of the OOTB packet
  *    MUST fill in the Verification Tag field of the outbound packet
  *    with the value found in the Verification Tag field of the OOTB
- *    packet and set the T-bit in the Chunk Flags to indicate that no
- *    TCB was found.  After sending this ABORT, the receiver of the OOTB
- *    packet shall discard the OOTB packet and take no further action.
+ *    packet and set the T-bit in the Chunk Flags to indicate that the
+ *    Verification Tag is reflected.  After sending this ABORT, the
+ *    receiver of the OOTB packet shall discard the OOTB packet and take
+ *    no further action.
  */
 sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
 				const struct sctp_association *asoc,
@@ -3090,13 +3099,15 @@ sctp_disposition_t sctp_sf_ootb(const st
 /*
  * Handle an "Out of the blue" SHUTDOWN ACK.
  *
- * Section: 8.4 5)
+ * Section: 8.4 5, sctpimpguide 2.41.
+ *
  * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should
- *   respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.
- *   When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet
- *   must fill in the Verification Tag field of the outbound packet with
- *   the Verification Tag received in the SHUTDOWN ACK and set the
- *   T-bit in the Chunk Flags to indicate that no TCB was found.
+ *    respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.
+ *    When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
+ *    packet must fill in the Verification Tag field of the outbound
+ *    packet with the Verification Tag received in the SHUTDOWN ACK and
+ *    set the T-bit in the Chunk Flags to indicate that the Verification
+ *    Tag is reflected.
  *
  * Inputs
  * (endpoint, asoc, type, arg, commands)
@@ -3128,6 +3139,10 @@ static sctp_disposition_t sctp_sf_shut_8
 			return SCTP_DISPOSITION_NOMEM;
 		}
 
+		/* Reflect vtag if T-Bit is set */
+		if (sctp_test_T_bit(shut))
+			packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+
 		/* Set the skb to the belonging sock for accounting.  */
 		shut->skb->sk = ep->base.sk;
 
@@ -3591,7 +3606,6 @@ sctp_disposition_t sctp_sf_discard_chunk
  *
  * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST
  *    silently discard the OOTB packet and take no further action.
- *    Otherwise,
  *
  * Verification Tag: No verification necessary
  *
@@ -4961,6 +4975,11 @@ static struct sctp_packet *sctp_abort_pk
 			sctp_ootb_pkt_free(packet);
 			return NULL;
 		}
+
+		/* Reflect vtag if T-Bit is set */
+		if (sctp_test_T_bit(abort))
+			packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+
 		/* Add specified error causes, i.e., payload, to the
 		 * end of the chunk.
 		 */
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sct
 	struct sock *sk = asoc->base.sk;
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	if (asoc->ep->sndbuf_policy) {
+		/* make sure that no association uses more than sk_sndbuf */
+		amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	} else {
+		/* do socket level accounting */
+		amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+	}
+
 	if (amt < 0)
 		amt = 0;
+
 	return amt;
 }
 
@@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(stru
 	/* The sndbuf space is tracked per association.  */
 	sctp_association_hold(asoc);
 
+	skb_set_owner_w(chunk->skb, sk);
+
 	chunk->skb->destructor = sctp_wfree;
 	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
 	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
 
-	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
+	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
 }
 
 /* Verify that this is a valid address. */
@@ -3473,7 +3490,7 @@ static int sctp_getsockopt_associnfo(str
 		return -EINVAL;
 
 	/* Values correspoinding to the specific association */
-	if (assocparams.sasoc_assoc_id != 0) {
+	if (asoc) {
 		assocparams.sasoc_asocmaxrxt = asoc->max_retrans;
 		assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;
 		assocparams.sasoc_local_rwnd = asoc->a_rwnd;
@@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *s
 	chunk = *((struct sctp_chunk **)(skb->cb));
 	asoc = chunk->asoc;
 	sk = asoc->base.sk;
-	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
+	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+
+	sock_wfree(skb);
 	__sctp_write_space(asoc);
 
 	sctp_association_put(asoc);
@@ -4660,6 +4686,7 @@ static void sctp_sock_migrate(struct soc
 	struct sctp_endpoint *newep = newsp->ep;
 	struct sk_buff *skb, *tmp;
 	struct sctp_ulpevent *event;
+	int flags = 0;
 
 	/* Migrate socket buffer sizes and all the socket level options to the
 	 * new socket.
@@ -4681,6 +4708,17 @@ static void sctp_sock_migrate(struct soc
 	sctp_sk(newsk)->bind_hash = pp;
 	inet_sk(newsk)->num = inet_sk(oldsk)->num;
 
+	/* Copy the bind_addr list from the original endpoint to the new
+	 * endpoint so that we can handle restarts properly
+	 */
+	if (assoc->peer.ipv4_address)
+		flags |= SCTP_ADDR4_PEERSUPP;
+	if (assoc->peer.ipv6_address)
+		flags |= SCTP_ADDR6_PEERSUPP;
+	sctp_bind_addr_copy(&newsp->ep->base.bind_addr,
+			     &oldsp->ep->base.bind_addr,
+			     SCTP_SCOPE_GLOBAL, GFP_KERNEL, flags);
+
 	/* Move any messages in the old socket's receive queue that are for the
 	 * peeled off association to the new socket's receive queue.
 	 */
@@ -4768,7 +4806,7 @@ struct proto sctp_prot = {
 	.hash        =	sctp_hash,
 	.unhash      =	sctp_unhash,
 	.get_port    =	sctp_get_port,
-	.slab_obj_size = sizeof(struct sctp_sock),
+	.obj_size    =  sizeof(struct sctp_sock),
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -4792,6 +4830,6 @@ struct proto sctpv6_prot = {
 	.hash		= sctp_hash,
 	.unhash		= sctp_unhash,
 	.get_port	= sctp_get_port,
-	.slab_obj_size	= sizeof(struct sctp6_sock),
+	.obj_size	= sizeof(struct sctp6_sock),
 };
 #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -110,6 +110,14 @@ static ctl_table sctp_table[] = {
 		.proc_handler	= &proc_dointvec
 	},
 	{
+		.ctl_name	= NET_SCTP_SNDBUF_POLICY,
+		.procname	= "sndbuf_policy",
+		.data		= &sctp_sndbuf_policy,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
 		.ctl_name	= NET_SCTP_PATH_MAX_RETRANS,
 		.procname	= "path_max_retrans",
 		.data		= &sctp_max_retrans_path,
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -227,7 +227,7 @@ void sctp_transport_pmtu(struct sctp_tra
 	dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL);
 
 	if (dst) {
-		transport->pmtu = dst_pmtu(dst);
+		transport->pmtu = dst_mtu(dst);
 		dst_release(dst);
 	} else
 		transport->pmtu = SCTP_DEFAULT_MAXSEGMENT;
@@ -253,7 +253,7 @@ void sctp_transport_route(struct sctp_tr
 
 	transport->dst = dst;
 	if (dst) {
-		transport->pmtu = dst_pmtu(dst);
+		transport->pmtu = dst_mtu(dst);
 
 		/* Initialize sk->sk_rcv_saddr, if the transport is the
 		 * association's active path for getsockname().
diff --git a/net/socket.c b/net/socket.c
--- a/net/socket.c
+++ b/net/socket.c
@@ -4,7 +4,7 @@
  * Version:	@(#)socket.c	1.1.93	18/02/95
  *
  * Authors:	Orest Zborowski, <obz@Kodak.COM>
- *		Ross Biro, <bir7@leland.Stanford.Edu>
+ *		Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  * Fixes:
@@ -287,7 +287,7 @@ static struct inode *sock_alloc_inode(st
 	ei->socket.ops = NULL;
 	ei->socket.sk = NULL;
 	ei->socket.file = NULL;
-	ei->socket.passcred = 0;
+	ei->socket.flags = 0;
 
 	return &ei->vfs_inode;
 }
@@ -437,13 +437,13 @@ struct socket *sockfd_lookup(int fd, int
 	}
 
 	inode = file->f_dentry->d_inode;
-	if (!inode->i_sock || !(sock = SOCKET_I(inode)))
-	{
+	if (!S_ISSOCK(inode->i_mode)) {
 		*err = -ENOTSOCK;
 		fput(file);
 		return NULL;
 	}
 
+	sock = SOCKET_I(inode);
 	if (sock->file != file) {
 		printk(KERN_ERR "socki_lookup: socket file changed!\n");
 		sock->file = file;
@@ -471,7 +471,6 @@ static struct socket *sock_alloc(void)
 	sock = SOCKET_I(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
-	inode->i_sock = 1;
 	inode->i_uid = current->fsuid;
 	inode->i_gid = current->fsgid;
 
@@ -993,8 +992,7 @@ static int sock_fasync(int fd, struct fi
 	sock = SOCKET_I(filp->f_dentry->d_inode);
 
 	if ((sk=sock->sk) == NULL) {
-		if (fna)
-			kfree(fna);
+		kfree(fna);
 		return -EINVAL;
 	}
 
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -67,12 +67,9 @@ rpcauth_create(rpc_authflavor_t pseudofl
 
 	if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor]))
 		return NULL;
-	if (!try_module_get(ops->owner))
-		return NULL;
 	auth = ops->create(clnt, pseudoflavor);
 	if (!auth)
 		return NULL;
-	atomic_set(&auth->au_count, 1);
 	if (clnt->cl_auth)
 		rpcauth_destroy(clnt->cl_auth);
 	clnt->cl_auth = auth;
@@ -85,8 +82,6 @@ rpcauth_destroy(struct rpc_auth *auth)
 	if (!atomic_dec_and_test(&auth->au_count))
 		return;
 	auth->au_ops->destroy(auth);
-	module_put(auth->au_ops->owner);
-	kfree(auth);
 }
 
 static DEFINE_SPINLOCK(rpc_credcache_lock);
@@ -94,42 +89,35 @@ static DEFINE_SPINLOCK(rpc_credcache_loc
 /*
  * Initialize RPC credential cache
  */
-void
-rpcauth_init_credcache(struct rpc_auth *auth)
+int
+rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
 {
+	struct rpc_cred_cache *new;
 	int i;
-	for (i = 0; i < RPC_CREDCACHE_NR; i++)
-		INIT_LIST_HEAD(&auth->au_credcache[i]);
-	auth->au_nextgc = jiffies + (auth->au_expire >> 1);
-}
 
-/*
- * Destroy an unreferenced credential
- */
-static inline void
-rpcauth_crdestroy(struct rpc_cred *cred)
-{
-#ifdef RPC_DEBUG
-	BUG_ON(cred->cr_magic != RPCAUTH_CRED_MAGIC ||
-			atomic_read(&cred->cr_count) ||
-			!list_empty(&cred->cr_hash));
-	cred->cr_magic = 0;
-#endif
-	cred->cr_ops->crdestroy(cred);
+	new = (struct rpc_cred_cache *)kmalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return -ENOMEM;
+	for (i = 0; i < RPC_CREDCACHE_NR; i++)
+		INIT_HLIST_HEAD(&new->hashtable[i]);
+	new->expire = expire;
+	new->nextgc = jiffies + (expire >> 1);
+	auth->au_credcache = new;
+	return 0;
 }
 
 /*
  * Destroy a list of credentials
  */
 static inline
-void rpcauth_destroy_credlist(struct list_head *head)
+void rpcauth_destroy_credlist(struct hlist_head *head)
 {
 	struct rpc_cred *cred;
 
-	while (!list_empty(head)) {
-		cred = list_entry(head->next, struct rpc_cred, cr_hash);
-		list_del_init(&cred->cr_hash);
-		rpcauth_crdestroy(cred);
+	while (!hlist_empty(head)) {
+		cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
+		hlist_del_init(&cred->cr_hash);
+		put_rpccred(cred);
 	}
 }
 
@@ -140,56 +128,56 @@ void rpcauth_destroy_credlist(struct lis
 void
 rpcauth_free_credcache(struct rpc_auth *auth)
 {
-	LIST_HEAD(free);
-	struct list_head *pos, *next;
+	struct rpc_cred_cache *cache = auth->au_credcache;
+	HLIST_HEAD(free);
+	struct hlist_node *pos, *next;
 	struct rpc_cred	*cred;
 	int		i;
 
 	spin_lock(&rpc_credcache_lock);
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
-		list_for_each_safe(pos, next, &auth->au_credcache[i]) {
-			cred = list_entry(pos, struct rpc_cred, cr_hash);
-			cred->cr_auth = NULL;
-			list_del_init(&cred->cr_hash);
-			if (atomic_read(&cred->cr_count) == 0)
-				list_add(&cred->cr_hash, &free);
+		hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
+			cred = hlist_entry(pos, struct rpc_cred, cr_hash);
+			__hlist_del(&cred->cr_hash);
+			hlist_add_head(&cred->cr_hash, &free);
 		}
 	}
 	spin_unlock(&rpc_credcache_lock);
 	rpcauth_destroy_credlist(&free);
 }
 
-static inline int
-rpcauth_prune_expired(struct rpc_cred *cred, struct list_head *free)
+static void
+rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free)
 {
-	if (atomic_read(&cred->cr_count) != 0)
-	       return 0;
-	if (time_before(jiffies, cred->cr_expire))
-		return 0;
-	cred->cr_auth = NULL;
-	list_del(&cred->cr_hash);
-	list_add(&cred->cr_hash, free);
-	return 1;
+	if (atomic_read(&cred->cr_count) != 1)
+	       return;
+	if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire))
+		cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+	if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) {
+		__hlist_del(&cred->cr_hash);
+		hlist_add_head(&cred->cr_hash, free);
+	}
 }
 
 /*
  * Remove stale credentials. Avoid sleeping inside the loop.
  */
 static void
-rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free)
+rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
 {
-	struct list_head *pos, *next;
+	struct rpc_cred_cache *cache = auth->au_credcache;
+	struct hlist_node *pos, *next;
 	struct rpc_cred	*cred;
 	int		i;
 
 	dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
-		list_for_each_safe(pos, next, &auth->au_credcache[i]) {
-			cred = list_entry(pos, struct rpc_cred, cr_hash);
-			rpcauth_prune_expired(cred, free);
+		hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
+			cred = hlist_entry(pos, struct rpc_cred, cr_hash);
+			rpcauth_prune_expired(auth, cred, free);
 		}
 	}
-	auth->au_nextgc = jiffies + auth->au_expire;
+	cache->nextgc = jiffies + cache->expire;
 }
 
 /*
@@ -199,8 +187,9 @@ struct rpc_cred *
 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
 		int taskflags)
 {
-	LIST_HEAD(free);
-	struct list_head *pos, *next;
+	struct rpc_cred_cache *cache = auth->au_credcache;
+	HLIST_HEAD(free);
+	struct hlist_node *pos, *next;
 	struct rpc_cred	*new = NULL,
 			*cred = NULL;
 	int		nr = 0;
@@ -209,28 +198,26 @@ rpcauth_lookup_credcache(struct rpc_auth
 		nr = acred->uid & RPC_CREDCACHE_MASK;
 retry:
 	spin_lock(&rpc_credcache_lock);
-	if (time_before(auth->au_nextgc, jiffies))
+	if (time_before(cache->nextgc, jiffies))
 		rpcauth_gc_credcache(auth, &free);
-	list_for_each_safe(pos, next, &auth->au_credcache[nr]) {
+	hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
 		struct rpc_cred *entry;
-	       	entry = list_entry(pos, struct rpc_cred, cr_hash);
-		if (rpcauth_prune_expired(entry, &free))
-			continue;
+	       	entry = hlist_entry(pos, struct rpc_cred, cr_hash);
 		if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
-			list_del(&entry->cr_hash);
+			hlist_del(&entry->cr_hash);
 			cred = entry;
 			break;
 		}
+		rpcauth_prune_expired(auth, entry, &free);
 	}
 	if (new) {
 		if (cred)
-			list_add(&new->cr_hash, &free);
+			hlist_add_head(&new->cr_hash, &free);
 		else
 			cred = new;
 	}
 	if (cred) {
-		list_add(&cred->cr_hash, &auth->au_credcache[nr]);
-		cred->cr_auth = auth;
+		hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]);
 		get_rpccred(cred);
 	}
 	spin_unlock(&rpc_credcache_lock);
@@ -239,12 +226,13 @@ retry:
 
 	if (!cred) {
 		new = auth->au_ops->crcreate(auth, acred, taskflags);
-		if (new) {
+		if (!IS_ERR(new)) {
 #ifdef RPC_DEBUG
 			new->cr_magic = RPCAUTH_CRED_MAGIC;
 #endif
 			goto retry;
-		}
+		} else
+			cred = new;
 	}
 
 	return (struct rpc_cred *) cred;
@@ -253,18 +241,18 @@ retry:
 struct rpc_cred *
 rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
 {
-	struct auth_cred acred;
+	struct auth_cred acred = {
+		.uid = current->fsuid,
+		.gid = current->fsgid,
+		.group_info = current->group_info,
+	};
 	struct rpc_cred *ret;
 
-	get_group_info(current->group_info);
-	acred.uid = current->fsuid;
-	acred.gid = current->fsgid;
-	acred.group_info = current->group_info;
-
 	dprintk("RPC:     looking up %s cred\n",
 		auth->au_ops->au_name);
-	ret = rpcauth_lookup_credcache(auth, &acred, taskflags);
-	put_group_info(current->group_info);
+	get_group_info(acred.group_info);
+	ret = auth->au_ops->lookup_cred(auth, &acred, taskflags);
+	put_group_info(acred.group_info);
 	return ret;
 }
 
@@ -272,21 +260,22 @@ struct rpc_cred *
 rpcauth_bindcred(struct rpc_task *task)
 {
 	struct rpc_auth *auth = task->tk_auth;
-	struct auth_cred acred;
+	struct auth_cred acred = {
+		.uid = current->fsuid,
+		.gid = current->fsgid,
+		.group_info = current->group_info,
+	};
 	struct rpc_cred *ret;
 
-	get_group_info(current->group_info);
-	acred.uid = current->fsuid;
-	acred.gid = current->fsgid;
-	acred.group_info = current->group_info;
-
 	dprintk("RPC: %4d looking up %s cred\n",
 		task->tk_pid, task->tk_auth->au_ops->au_name);
-	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags);
-	if (task->tk_msg.rpc_cred == 0)
-		task->tk_status = -ENOMEM;
-	ret = task->tk_msg.rpc_cred;
-	put_group_info(current->group_info);
+	get_group_info(acred.group_info);
+	ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags);
+	if (!IS_ERR(ret))
+		task->tk_msg.rpc_cred = ret;
+	else
+		task->tk_status = PTR_ERR(ret);
+	put_group_info(acred.group_info);
 	return ret;
 }
 
@@ -302,16 +291,10 @@ rpcauth_holdcred(struct rpc_task *task)
 void
 put_rpccred(struct rpc_cred *cred)
 {
-	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
+	cred->cr_expire = jiffies;
+	if (!atomic_dec_and_test(&cred->cr_count))
 		return;
-
-	if (list_empty(&cred->cr_hash)) {
-		spin_unlock(&rpc_credcache_lock);
-		rpcauth_crdestroy(cred);
-		return;
-	}
-	cred->cr_expire = jiffies + cred->cr_auth->au_expire;
-	spin_unlock(&rpc_credcache_lock);
+	cred->cr_ops->crdestroy(cred);
 }
 
 void
@@ -335,8 +318,7 @@ rpcauth_marshcred(struct rpc_task *task,
 
 	dprintk("RPC: %4d marshaling %s cred %p\n",
 		task->tk_pid, auth->au_ops->au_name, cred);
-	return cred->cr_ops->crmarshal(task, p,
-				task->tk_flags & RPC_CALL_REALUID);
+	return cred->cr_ops->crmarshal(task, p);
 }
 
 u32 *
@@ -357,7 +339,7 @@ rpcauth_wrap_req(struct rpc_task *task, 
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
 	dprintk("RPC: %4d using %s cred %p to wrap rpc data\n",
-			task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
+			task->tk_pid, cred->cr_ops->cr_name, cred);
 	if (cred->cr_ops->crwrap_req)
 		return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
 	/* By default, we encode the arguments normally. */
@@ -371,7 +353,7 @@ rpcauth_unwrap_resp(struct rpc_task *tas
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
 	dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n",
-			task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
+			task->tk_pid, cred->cr_ops->cr_name, cred);
 	if (cred->cr_ops->crunwrap_resp)
 		return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
 						   data, obj);
@@ -384,11 +366,14 @@ rpcauth_refreshcred(struct rpc_task *tas
 {
 	struct rpc_auth	*auth = task->tk_auth;
 	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
+	int err;
 
 	dprintk("RPC: %4d refreshing %s cred %p\n",
 		task->tk_pid, auth->au_ops->au_name, cred);
-	task->tk_status = cred->cr_ops->crrefresh(task);
-	return task->tk_status;
+	err = cred->cr_ops->crrefresh(task);
+	if (err < 0)
+		task->tk_status = err;
+	return err;
 }
 
 void
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -85,7 +85,9 @@ static DEFINE_RWLOCK(gss_ctx_lock);
 struct gss_auth {
 	struct rpc_auth rpc_auth;
 	struct gss_api_mech *mech;
+	enum rpc_gss_svc service;
 	struct list_head upcalls;
+	struct rpc_clnt *client;
 	struct dentry *dentry;
 	char path[48];
 	spinlock_t lock;
@@ -175,42 +177,34 @@ gss_cred_is_uptodate_ctx(struct rpc_cred
 	return res;
 }
 
-static inline int
-simple_get_bytes(char **ptr, const char *end, void *res, int len)
+static const void *
+simple_get_bytes(const void *p, const void *end, void *res, size_t len)
 {
-	char *p, *q;
-	p = *ptr;
-	q = p + len;
-	if (q > end || q < p)
-		return -1;
+	const void *q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
 	memcpy(res, p, len);
-	*ptr = q;
-	return 0;
+	return q;
 }
 
-static inline int
-simple_get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
+static inline const void *
+simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
 {
-	char *p, *q;
-	p = *ptr;
-	if (simple_get_bytes(&p, end, &res->len, sizeof(res->len)))
-		return -1;
-	q = p + res->len;
-	if (q > end || q < p)
-		return -1;
-	res->data = p;
-	*ptr = q;
-	return 0;
-}
+	const void *q;
+	unsigned int len;
 
-static int
-dup_netobj(struct xdr_netobj *source, struct xdr_netobj *dest)
-{
-	dest->len = source->len;
-	if (!(dest->data = kmalloc(dest->len, GFP_KERNEL)))
-		return -1;
-	memcpy(dest->data, source->data, dest->len);
-	return 0;
+	p = simple_get_bytes(p, end, &len, sizeof(len));
+	if (IS_ERR(p))
+		return p;
+	q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
+	dest->data = kmalloc(len, GFP_KERNEL);
+	if (unlikely(dest->data == NULL))
+		return ERR_PTR(-ENOMEM);
+	dest->len = len;
+	memcpy(dest->data, p, len);
+	return q;
 }
 
 static struct gss_cl_ctx *
@@ -226,74 +220,84 @@ gss_cred_get_ctx(struct rpc_cred *cred)
 	return ctx;
 }
 
-static int
-gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
-		struct gss_cl_ctx **gc, uid_t *uid, int *gss_err)
+static struct gss_cl_ctx *
+gss_alloc_context(void)
 {
-	char *end = buf->data + buf->len;
-	char *p = buf->data;
 	struct gss_cl_ctx *ctx;
-	struct xdr_netobj tmp_buf;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (ctx != NULL) {
+		memset(ctx, 0, sizeof(*ctx));
+		ctx->gc_proc = RPC_GSS_PROC_DATA;
+		ctx->gc_seq = 1;	/* NetApp 6.4R1 doesn't accept seq. no. 0 */
+		spin_lock_init(&ctx->gc_seq_lock);
+		atomic_set(&ctx->count,1);
+	}
+	return ctx;
+}
+
+#define GSSD_MIN_TIMEOUT (60 * 60)
+static const void *
+gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm)
+{
+	const void *q;
+	unsigned int seclen;
 	unsigned int timeout;
-	int err = -EIO;
+	u32 window_size;
+	int ret;
 
-	if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL))) {
-		err = -ENOMEM;
+	/* First unsigned int gives the lifetime (in seconds) of the cred */
+	p = simple_get_bytes(p, end, &timeout, sizeof(timeout));
+	if (IS_ERR(p))
 		goto err;
-	}
-	ctx->gc_proc = RPC_GSS_PROC_DATA;
-	ctx->gc_seq = 1;	/* NetApp 6.4R1 doesn't accept seq. no. 0 */
-	spin_lock_init(&ctx->gc_seq_lock);
-	atomic_set(&ctx->count,1);
-
-	if (simple_get_bytes(&p, end, uid, sizeof(*uid)))
-		goto err_free_ctx;
-	/* FIXME: discarded timeout for now */
-	if (simple_get_bytes(&p, end, &timeout, sizeof(timeout)))
-		goto err_free_ctx;
-	*gss_err = 0;
-	if (simple_get_bytes(&p, end, &ctx->gc_win, sizeof(ctx->gc_win)))
-		goto err_free_ctx;
+	if (timeout == 0)
+		timeout = GSSD_MIN_TIMEOUT;
+	ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4;
+	/* Sequence number window. Determines the maximum number of simultaneous requests */
+	p = simple_get_bytes(p, end, &window_size, sizeof(window_size));
+	if (IS_ERR(p))
+		goto err;
+	ctx->gc_win = window_size;
 	/* gssd signals an error by passing ctx->gc_win = 0: */
-	if (!ctx->gc_win) {
-		/* in which case the next int is an error code: */
-		if (simple_get_bytes(&p, end, gss_err, sizeof(*gss_err)))
-			goto err_free_ctx;
-		err = 0;
-		goto err_free_ctx;
-	}
-	if (simple_get_netobj(&p, end, &tmp_buf))
-		goto err_free_ctx;
-	if (dup_netobj(&tmp_buf, &ctx->gc_wire_ctx)) {
-		err = -ENOMEM;
-		goto err_free_ctx;
-	}
-	if (simple_get_netobj(&p, end, &tmp_buf))
-		goto err_free_wire_ctx;
-	if (p != end)
-		goto err_free_wire_ctx;
-	if (gss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx))
-		goto err_free_wire_ctx;
-	*gc = ctx;
-	return 0;
-err_free_wire_ctx:
-	kfree(ctx->gc_wire_ctx.data);
-err_free_ctx:
-	kfree(ctx);
+	if (ctx->gc_win == 0) {
+		/* in which case, p points to  an error code which we ignore */
+		p = ERR_PTR(-EACCES);
+		goto err;
+	}
+	/* copy the opaque wire context */
+	p = simple_get_netobj(p, end, &ctx->gc_wire_ctx);
+	if (IS_ERR(p))
+		goto err;
+	/* import the opaque security context */
+	p  = simple_get_bytes(p, end, &seclen, sizeof(seclen));
+	if (IS_ERR(p))
+		goto err;
+	q = (const void *)((const char *)p + seclen);
+	if (unlikely(q > end || q < p)) {
+		p = ERR_PTR(-EFAULT);
+		goto err;
+	}
+	ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx);
+	if (ret < 0) {
+		p = ERR_PTR(ret);
+		goto err;
+	}
+	return q;
 err:
-	*gc = NULL;
-	dprintk("RPC:      gss_parse_init_downcall returning %d\n", err);
-	return err;
+	dprintk("RPC:      gss_fill_context returning %ld\n", -PTR_ERR(p));
+	return p;
 }
 
 
 struct gss_upcall_msg {
+	atomic_t count;
+	uid_t	uid;
 	struct rpc_pipe_msg msg;
 	struct list_head list;
 	struct gss_auth *auth;
-	struct rpc_wait_queue waitq;
-	uid_t	uid;
-	atomic_t count;
+	struct rpc_wait_queue rpc_waitqueue;
+	wait_queue_head_t waitqueue;
+	struct gss_cl_ctx *ctx;
 };
 
 static void
@@ -302,6 +306,8 @@ gss_release_msg(struct gss_upcall_msg *g
 	if (!atomic_dec_and_test(&gss_msg->count))
 		return;
 	BUG_ON(!list_empty(&gss_msg->list));
+	if (gss_msg->ctx != NULL)
+		gss_put_ctx(gss_msg->ctx);
 	kfree(gss_msg);
 }
 
@@ -320,16 +326,34 @@ __gss_find_upcall(struct gss_auth *gss_a
 	return NULL;
 }
 
+/* Try to add a upcall to the pipefs queue.
+ * If an upcall owned by our uid already exists, then we return a reference
+ * to that upcall instead of adding the new upcall.
+ */
+static inline struct gss_upcall_msg *
+gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg)
+{
+	struct gss_upcall_msg *old;
+
+	spin_lock(&gss_auth->lock);
+	old = __gss_find_upcall(gss_auth, gss_msg->uid);
+	if (old == NULL) {
+		atomic_inc(&gss_msg->count);
+		list_add(&gss_msg->list, &gss_auth->upcalls);
+	} else
+		gss_msg = old;
+	spin_unlock(&gss_auth->lock);
+	return gss_msg;
+}
+
 static void
 __gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
 	if (list_empty(&gss_msg->list))
 		return;
 	list_del_init(&gss_msg->list);
-	if (gss_msg->msg.errno < 0)
-		rpc_wake_up_status(&gss_msg->waitq, gss_msg->msg.errno);
-	else
-		rpc_wake_up(&gss_msg->waitq);
+	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+	wake_up_all(&gss_msg->waitqueue);
 	atomic_dec(&gss_msg->count);
 }
 
@@ -343,76 +367,139 @@ gss_unhash_msg(struct gss_upcall_msg *gs
 	spin_unlock(&gss_auth->lock);
 }
 
-static int
-gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred)
+static void
+gss_upcall_callback(struct rpc_task *task)
 {
-	struct gss_auth *gss_auth = container_of(clnt->cl_auth,
-			struct gss_auth, rpc_auth);
-	struct gss_upcall_msg *gss_msg, *gss_new = NULL;
-	struct rpc_pipe_msg *msg;
-	struct dentry *dentry = gss_auth->dentry;
-	uid_t uid = cred->cr_uid;
-	int res = 0;
+	struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
+			struct gss_cred, gc_base);
+	struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
+
+	BUG_ON(gss_msg == NULL);
+	if (gss_msg->ctx)
+		gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+	else
+		task->tk_status = gss_msg->msg.errno;
+	spin_lock(&gss_msg->auth->lock);
+	gss_cred->gc_upcall = NULL;
+	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+	spin_unlock(&gss_msg->auth->lock);
+	gss_release_msg(gss_msg);
+}
 
-	dprintk("RPC: %4u gss_upcall for uid %u\n", task->tk_pid, uid);
+static inline struct gss_upcall_msg *
+gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
+{
+	struct gss_upcall_msg *gss_msg;
 
-retry:
-	spin_lock(&gss_auth->lock);
-	gss_msg = __gss_find_upcall(gss_auth, uid);
-	if (gss_msg)
-		goto out_sleep;
-	if (gss_new == NULL) {
-		spin_unlock(&gss_auth->lock);
-		gss_new = kmalloc(sizeof(*gss_new), GFP_KERNEL);
-		if (!gss_new) {
-			dprintk("RPC: %4u gss_upcall -ENOMEM\n", task->tk_pid);
-			return -ENOMEM;
+	gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL);
+	if (gss_msg != NULL) {
+		memset(gss_msg, 0, sizeof(*gss_msg));
+		INIT_LIST_HEAD(&gss_msg->list);
+		rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
+		init_waitqueue_head(&gss_msg->waitqueue);
+		atomic_set(&gss_msg->count, 1);
+		gss_msg->msg.data = &gss_msg->uid;
+		gss_msg->msg.len = sizeof(gss_msg->uid);
+		gss_msg->uid = uid;
+		gss_msg->auth = gss_auth;
+	}
+	return gss_msg;
+}
+
+static struct gss_upcall_msg *
+gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
+{
+	struct gss_upcall_msg *gss_new, *gss_msg;
+
+	gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+	if (gss_new == NULL)
+		return ERR_PTR(-ENOMEM);
+	gss_msg = gss_add_msg(gss_auth, gss_new);
+	if (gss_msg == gss_new) {
+		int res = rpc_queue_upcall(gss_auth->dentry->d_inode, &gss_new->msg);
+		if (res) {
+			gss_unhash_msg(gss_new);
+			gss_msg = ERR_PTR(res);
 		}
-		goto retry;
+	} else
+		gss_release_msg(gss_new);
+	return gss_msg;
+}
+
+static inline int
+gss_refresh_upcall(struct rpc_task *task)
+{
+	struct rpc_cred *cred = task->tk_msg.rpc_cred;
+	struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth,
+			struct gss_auth, rpc_auth);
+	struct gss_cred *gss_cred = container_of(cred,
+			struct gss_cred, gc_base);
+	struct gss_upcall_msg *gss_msg;
+	int err = 0;
+
+	dprintk("RPC: %4u gss_refresh_upcall for uid %u\n", task->tk_pid, cred->cr_uid);
+	gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
+	if (IS_ERR(gss_msg)) {
+		err = PTR_ERR(gss_msg);
+		goto out;
 	}
-	gss_msg = gss_new;
-	memset(gss_new, 0, sizeof(*gss_new));
-	INIT_LIST_HEAD(&gss_new->list);
-	rpc_init_wait_queue(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
-	atomic_set(&gss_new->count, 2);
-	msg = &gss_new->msg;
-	msg->data = &gss_new->uid;
-	msg->len = sizeof(gss_new->uid);
-	gss_new->uid = uid;
-	gss_new->auth = gss_auth;
-	list_add(&gss_new->list, &gss_auth->upcalls);
-	gss_new = NULL;
-	/* Has someone updated the credential behind our back? */
-	if (!gss_cred_is_uptodate_ctx(cred)) {
-		/* No, so do upcall and sleep */
+	spin_lock(&gss_auth->lock);
+	if (gss_cred->gc_upcall != NULL)
+		rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
+	else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
 		task->tk_timeout = 0;
-		rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL);
-		spin_unlock(&gss_auth->lock);
-		res = rpc_queue_upcall(dentry->d_inode, msg);
-		if (res)
-			gss_unhash_msg(gss_msg);
-	} else {
-		/* Yes, so cancel upcall */
-		__gss_unhash_msg(gss_msg);
+		gss_cred->gc_upcall = gss_msg;
+		/* gss_upcall_callback will release the reference to gss_upcall_msg */
+		atomic_inc(&gss_msg->count);
+		rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+	} else
+		err = gss_msg->msg.errno;
+	spin_unlock(&gss_auth->lock);
+	gss_release_msg(gss_msg);
+out:
+	dprintk("RPC: %4u gss_refresh_upcall for uid %u result %d\n", task->tk_pid,
+			cred->cr_uid, err);
+	return err;
+}
+
+static inline int
+gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
+{
+	struct rpc_cred *cred = &gss_cred->gc_base;
+	struct gss_upcall_msg *gss_msg;
+	DEFINE_WAIT(wait);
+	int err = 0;
+
+	dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid);
+	gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
+	if (IS_ERR(gss_msg)) {
+		err = PTR_ERR(gss_msg);
+		goto out;
+	}
+	for (;;) {
+		prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
+		spin_lock(&gss_auth->lock);
+		if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
+			spin_unlock(&gss_auth->lock);
+			break;
+		}
 		spin_unlock(&gss_auth->lock);
+		if (signalled()) {
+			err = -ERESTARTSYS;
+			goto out_intr;
+		}
+		schedule();
 	}
+	if (gss_msg->ctx)
+		gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+	else
+		err = gss_msg->msg.errno;
+out_intr:
+	finish_wait(&gss_msg->waitqueue, &wait);
 	gss_release_msg(gss_msg);
-	dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid,
-			uid, res);
-	return res;
-out_sleep:
-	task->tk_timeout = 0;
-	rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL);
-	spin_unlock(&gss_auth->lock);
-	dprintk("RPC: %4u gss_upcall  sleeping\n", task->tk_pid);
-	if (gss_new)
-		kfree(gss_new);
-	/* Note: we drop the reference here: we are automatically removed
-	 * from the queue when we're woken up, and we should in any case
-	 * have no further responsabilities w.r.t. the upcall.
-	 */
-	gss_release_msg(gss_msg);
-	return 0;
+out:
+	dprintk("RPC: gss_create_upcall for uid %u result %d\n", cred->cr_uid, err);
+	return err;
 }
 
 static ssize_t
@@ -441,68 +528,75 @@ gss_pipe_upcall(struct file *filp, struc
 static ssize_t
 gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 {
-	struct xdr_netobj obj = {
-		.len	= mlen,
-	};
-	struct inode *inode = filp->f_dentry->d_inode;
-	struct rpc_inode *rpci = RPC_I(inode);
+	const void *p, *end;
+	void *buf;
 	struct rpc_clnt *clnt;
-	struct rpc_auth *auth;
 	struct gss_auth *gss_auth;
-	struct gss_api_mech *mech;
-	struct auth_cred acred = { 0 };
 	struct rpc_cred *cred;
 	struct gss_upcall_msg *gss_msg;
-	struct gss_cl_ctx *ctx = NULL;
-	ssize_t left;
-	int err;
-	int gss_err;
+	struct gss_cl_ctx *ctx;
+	uid_t uid;
+	int err = -EFBIG;
 
 	if (mlen > MSG_BUF_MAXSIZE)
-		return -EFBIG;
-	obj.data = kmalloc(mlen, GFP_KERNEL);
-	if (!obj.data)
-		return -ENOMEM;
-	left = copy_from_user(obj.data, src, mlen);
-	if (left) {
-		err = -EFAULT;
 		goto out;
-	}
-	clnt = rpci->private;
-	atomic_inc(&clnt->cl_users);
-	auth = clnt->cl_auth;
-	gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-	mech = gss_auth->mech;
-	err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid, &gss_err);
-	if (err)
+	err = -ENOMEM;
+	buf = kmalloc(mlen, GFP_KERNEL);
+	if (!buf)
+		goto out;
+
+	clnt = RPC_I(filp->f_dentry->d_inode)->private;
+	err = -EFAULT;
+	if (copy_from_user(buf, src, mlen))
 		goto err;
-	cred = rpcauth_lookup_credcache(auth, &acred, 0);
-	if (!cred)
+
+	end = (const void *)((char *)buf + mlen);
+	p = simple_get_bytes(buf, end, &uid, sizeof(uid));
+	if (IS_ERR(p)) {
+		err = PTR_ERR(p);
 		goto err;
-	if (gss_err)
-		cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
-	else
-		gss_cred_set_ctx(cred, ctx);
+	}
+
+	err = -ENOMEM;
+	ctx = gss_alloc_context();
+	if (ctx == NULL)
+		goto err;
+	err = 0;
+	gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth);
+	p = gss_fill_context(p, end, ctx, gss_auth->mech);
+	if (IS_ERR(p)) {
+		err = PTR_ERR(p);
+		if (err != -EACCES)
+			goto err_put_ctx;
+	}
 	spin_lock(&gss_auth->lock);
-	gss_msg = __gss_find_upcall(gss_auth, acred.uid);
+	gss_msg = __gss_find_upcall(gss_auth, uid);
 	if (gss_msg) {
-		if (gss_err)
-			gss_msg->msg.errno = -EACCES;
+		if (err == 0 && gss_msg->ctx == NULL)
+			gss_msg->ctx = gss_get_ctx(ctx);
+		gss_msg->msg.errno = err;
 		__gss_unhash_msg(gss_msg);
 		spin_unlock(&gss_auth->lock);
 		gss_release_msg(gss_msg);
-	} else
+	} else {
+		struct auth_cred acred = { .uid = uid };
 		spin_unlock(&gss_auth->lock);
-	rpc_release_client(clnt);
-	kfree(obj.data);
+		cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
+		if (IS_ERR(cred)) {
+			err = PTR_ERR(cred);
+			goto err_put_ctx;
+		}
+		gss_cred_set_ctx(cred, gss_get_ctx(ctx));
+	}
+	gss_put_ctx(ctx);
+	kfree(buf);
 	dprintk("RPC:      gss_pipe_downcall returning length %Zu\n", mlen);
 	return mlen;
+err_put_ctx:
+	gss_put_ctx(ctx);
 err:
-	if (ctx)
-		gss_destroy_ctx(ctx);
-	rpc_release_client(clnt);
+	kfree(buf);
 out:
-	kfree(obj.data);
 	dprintk("RPC:      gss_pipe_downcall returning %d\n", err);
 	return err;
 }
@@ -569,24 +663,32 @@ gss_create(struct rpc_clnt *clnt, rpc_au
 
 	dprintk("RPC:      creating GSS authenticator for client %p\n",clnt);
 
+	if (!try_module_get(THIS_MODULE))
+		return NULL;
 	if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
 		goto out_dec;
+	gss_auth->client = clnt;
 	gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
 	if (!gss_auth->mech) {
 		printk(KERN_WARNING "%s: Pseudoflavor %d not found!",
 				__FUNCTION__, flavor);
 		goto err_free;
 	}
+	gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
+	/* FIXME: Will go away once privacy support is merged in */
+	if (gss_auth->service == RPC_GSS_SVC_PRIVACY)
+		gss_auth->service = RPC_GSS_SVC_INTEGRITY;
 	INIT_LIST_HEAD(&gss_auth->upcalls);
 	spin_lock_init(&gss_auth->lock);
 	auth = &gss_auth->rpc_auth;
 	auth->au_cslack = GSS_CRED_SLACK >> 2;
 	auth->au_rslack = GSS_VERF_SLACK >> 2;
-	auth->au_expire = GSS_CRED_EXPIRE;
 	auth->au_ops = &authgss_ops;
 	auth->au_flavor = flavor;
+	atomic_set(&auth->au_count, 1);
 
-	rpcauth_init_credcache(auth);
+	if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0)
+		goto err_put_mech;
 
 	snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
 			clnt->cl_pathname,
@@ -601,6 +703,7 @@ err_put_mech:
 err_free:
 	kfree(gss_auth);
 out_dec:
+	module_put(THIS_MODULE);
 	return NULL;
 }
 
@@ -617,6 +720,8 @@ gss_destroy(struct rpc_auth *auth)
 	gss_mech_put(gss_auth->mech);
 
 	rpcauth_free_credcache(auth);
+	kfree(gss_auth);
+	module_put(THIS_MODULE);
 }
 
 /* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure
@@ -630,19 +735,14 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx)
 	if (ctx->gc_gss_ctx)
 		gss_delete_sec_context(&ctx->gc_gss_ctx);
 
-	if (ctx->gc_wire_ctx.len > 0) {
-		kfree(ctx->gc_wire_ctx.data);
-		ctx->gc_wire_ctx.len = 0;
-	}
-
+	kfree(ctx->gc_wire_ctx.data);
 	kfree(ctx);
-
 }
 
 static void
 gss_destroy_cred(struct rpc_cred *rc)
 {
-	struct gss_cred *cred = (struct gss_cred *)rc;
+	struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base);
 
 	dprintk("RPC:      gss_destroy_cred \n");
 
@@ -651,10 +751,21 @@ gss_destroy_cred(struct rpc_cred *rc)
 	kfree(cred);
 }
 
+/*
+ * Lookup RPCSEC_GSS cred for the current process
+ */
+static struct rpc_cred *
+gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+{
+	return rpcauth_lookup_credcache(auth, acred, taskflags);
+}
+
 static struct rpc_cred *
 gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
 {
+	struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
 	struct gss_cred	*cred = NULL;
+	int err = -ENOMEM;
 
 	dprintk("RPC:      gss_create_cred for uid %d, flavor %d\n",
 		acred->uid, auth->au_flavor);
@@ -663,7 +774,7 @@ gss_create_cred(struct rpc_auth *auth, s
 		goto out_err;
 
 	memset(cred, 0, sizeof(*cred));
-	atomic_set(&cred->gc_count, 0);
+	atomic_set(&cred->gc_count, 1);
 	cred->gc_uid = acred->uid;
 	/*
 	 * Note: in order to force a call to call_refresh(), we deliberately
@@ -671,19 +782,27 @@ gss_create_cred(struct rpc_auth *auth, s
 	 */
 	cred->gc_flags = 0;
 	cred->gc_base.cr_ops = &gss_credops;
-	cred->gc_flavor = auth->au_flavor;
+	cred->gc_service = gss_auth->service;
+	err = gss_create_upcall(gss_auth, cred);
+	if (err < 0)
+		goto out_err;
 
-	return (struct rpc_cred *) cred;
+	return &cred->gc_base;
 
 out_err:
-	dprintk("RPC:      gss_create_cred failed\n");
-	if (cred) gss_destroy_cred((struct rpc_cred *)cred);
-	return NULL;
+	dprintk("RPC:      gss_create_cred failed with error %d\n", err);
+	if (cred) gss_destroy_cred(&cred->gc_base);
+	return ERR_PTR(err);
 }
 
 static int
 gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
 {
+	struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+
+	/* Don't match with creds that have expired. */
+	if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+		return 0;
 	return (rc->cr_uid == acred->uid);
 }
 
@@ -692,7 +811,7 @@ gss_match(struct auth_cred *acred, struc
 * Maybe we should keep a cached credential for performance reasons.
 */
 static u32 *
-gss_marshal(struct rpc_task *task, u32 *p, int ruid)
+gss_marshal(struct rpc_task *task, u32 *p)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
@@ -704,20 +823,12 @@ gss_marshal(struct rpc_task *task, u32 *
 	struct xdr_netobj mic;
 	struct kvec	iov;
 	struct xdr_buf	verf_buf;
-	u32		service;
 
 	dprintk("RPC: %4u gss_marshal\n", task->tk_pid);
 
 	*p++ = htonl(RPC_AUTH_GSS);
 	cred_len = p++;
 
-	service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
-						gss_cred->gc_flavor);
-	if (service == 0) {
-		dprintk("RPC: %4u Bad pseudoflavor %d in gss_marshal\n",
-			task->tk_pid, gss_cred->gc_flavor);
-		goto out_put_ctx;
-	}
 	spin_lock(&ctx->gc_seq_lock);
 	req->rq_seqno = ctx->gc_seq++;
 	spin_unlock(&ctx->gc_seq_lock);
@@ -725,7 +836,7 @@ gss_marshal(struct rpc_task *task, u32 *
 	*p++ = htonl((u32) RPC_GSS_VERSION);
 	*p++ = htonl((u32) ctx->gc_proc);
 	*p++ = htonl((u32) req->rq_seqno);
-	*p++ = htonl((u32) service);
+	*p++ = htonl((u32) gss_cred->gc_service);
 	p = xdr_encode_netobj(p, &ctx->gc_wire_ctx);
 	*cred_len = htonl((p - (cred_len + 1)) << 2);
 
@@ -765,11 +876,9 @@ out_put_ctx:
 static int
 gss_refresh(struct rpc_task *task)
 {
-	struct rpc_clnt *clnt = task->tk_client;
-	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
-	if (!gss_cred_is_uptodate_ctx(cred))
-		return gss_upcall(clnt, task, cred);
+	if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
+		return gss_refresh_upcall(task);
 	return 0;
 }
 
@@ -785,7 +894,6 @@ gss_validate(struct rpc_task *task, u32 
 	struct xdr_buf	verf_buf;
 	struct xdr_netobj mic;
 	u32		flav,len;
-	u32		service;
 	u32		maj_stat;
 
 	dprintk("RPC: %4u gss_validate\n", task->tk_pid);
@@ -807,9 +915,7 @@ gss_validate(struct rpc_task *task, u32 
 		cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
 	if (maj_stat)
 		goto out_bad;
-       service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
-					gss_cred->gc_flavor);
-       switch (service) {
+       switch (gss_cred->gc_service) {
        case RPC_GSS_SVC_NONE:
 	       /* verifier data, flavor, length: */
 	       task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2;
@@ -818,7 +924,7 @@ gss_validate(struct rpc_task *task, u32 
 	       /* verifier data, flavor, length, length, sequence number: */
 	       task->tk_auth->au_rslack = XDR_QUADLEN(len) + 4;
 	       break;
-       default:
+       case RPC_GSS_SVC_PRIVACY:
 	       goto out_bad;
        }
 	gss_put_ctx(ctx);
@@ -889,7 +995,6 @@ gss_wrap_req(struct rpc_task *task,
 			gc_base);
 	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
 	int             status = -EIO;
-	u32		service;
 
 	dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid);
 	if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
@@ -899,19 +1004,16 @@ gss_wrap_req(struct rpc_task *task,
 		status = encode(rqstp, p, obj);
 		goto out;
 	}
-	service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
-						gss_cred->gc_flavor);
-	switch (service) {
+	switch (gss_cred->gc_service) {
 		case RPC_GSS_SVC_NONE:
 			status = encode(rqstp, p, obj);
-			goto out;
+			break;
 		case RPC_GSS_SVC_INTEGRITY:
 			status = gss_wrap_req_integ(cred, ctx, encode,
 								rqstp, p, obj);
-			goto out;
-		case RPC_GSS_SVC_PRIVACY:
-		default:
-			goto out;
+			break;
+       		case RPC_GSS_SVC_PRIVACY:
+			break;
 	}
 out:
 	gss_put_ctx(ctx);
@@ -966,23 +1068,19 @@ gss_unwrap_resp(struct rpc_task *task,
 			gc_base);
 	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
 	int             status = -EIO;
-	u32		service;
 
 	if (ctx->gc_proc != RPC_GSS_PROC_DATA)
 		goto out_decode;
-	service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
-						gss_cred->gc_flavor);
-	switch (service) {
+	switch (gss_cred->gc_service) {
 		case RPC_GSS_SVC_NONE:
-			goto out_decode;
+			break;
 		case RPC_GSS_SVC_INTEGRITY:
 			status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p);
 			if (status)
 				goto out;
 			break;
-		case RPC_GSS_SVC_PRIVACY:
-		default:
-			goto out;
+       		case RPC_GSS_SVC_PRIVACY:
+			break;
 	}
 out_decode:
 	status = decode(rqstp, p, obj);
@@ -1001,10 +1099,12 @@ static struct rpc_authops authgss_ops = 
 #endif
 	.create		= gss_create,
 	.destroy	= gss_destroy,
+	.lookup_cred	= gss_lookup_cred,
 	.crcreate	= gss_create_cred
 };
 
 static struct rpc_credops gss_credops = {
+	.cr_name	= "AUTH_GSS",
 	.crdestroy	= gss_destroy_cred,
 	.crmatch	= gss_match,
 	.crmarshal	= gss_marshal,
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -48,46 +48,48 @@
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
-static inline int
-get_bytes(char **ptr, const char *end, void *res, int len)
+static const void *
+simple_get_bytes(const void *p, const void *end, void *res, int len)
 {
-	char *p, *q;
-	p = *ptr;
-	q = p + len;
-	if (q > end || q < p)
-		return -1;
+	const void *q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
 	memcpy(res, p, len);
-	*ptr = q;
-	return 0;
+	return q;
 }
 
-static inline int
-get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
+static const void *
+simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
 {
-	char *p, *q;
-	p = *ptr;
-	if (get_bytes(&p, end, &res->len, sizeof(res->len)))
-		return -1;
-	q = p + res->len;
-	if (q > end || q < p)
-		return -1;
-	if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
-		return -1;
-	memcpy(res->data, p, res->len);
-	*ptr = q;
-	return 0;
+	const void *q;
+	unsigned int len;
+
+	p = simple_get_bytes(p, end, &len, sizeof(len));
+	if (IS_ERR(p))
+		return p;
+	q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
+	res->data = kmalloc(len, GFP_KERNEL);
+	if (unlikely(res->data == NULL))
+		return ERR_PTR(-ENOMEM);
+	memcpy(res->data, p, len);
+	res->len = len;
+	return q;
 }
 
-static inline int
-get_key(char **p, char *end, struct crypto_tfm **res)
+static inline const void *
+get_key(const void *p, const void *end, struct crypto_tfm **res)
 {
 	struct xdr_netobj	key;
 	int			alg, alg_mode;
 	char			*alg_name;
 
-	if (get_bytes(p, end, &alg, sizeof(alg)))
+	p = simple_get_bytes(p, end, &alg, sizeof(alg));
+	if (IS_ERR(p))
 		goto out_err;
-	if ((get_netobj(p, end, &key)))
+	p = simple_get_netobj(p, end, &key);
+	if (IS_ERR(p))
 		goto out_err;
 
 	switch (alg) {
@@ -105,50 +107,63 @@ get_key(char **p, char *end, struct cryp
 		goto out_err_free_tfm;
 
 	kfree(key.data);
-	return 0;
+	return p;
 
 out_err_free_tfm:
 	crypto_free_tfm(*res);
 out_err_free_key:
 	kfree(key.data);
+	p = ERR_PTR(-EINVAL);
 out_err:
-	return -1;
+	return p;
 }
 
-static u32
-gss_import_sec_context_kerberos(struct xdr_netobj *inbuf,
+static int
+gss_import_sec_context_kerberos(const void *p,
+				size_t len,
 				struct gss_ctx *ctx_id)
 {
-	char	*p = inbuf->data;
-	char	*end = inbuf->data + inbuf->len;
+	const void *end = (const void *)((const char *)p + len);
 	struct	krb5_ctx *ctx;
 
 	if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
 		goto out_err;
 	memset(ctx, 0, sizeof(*ctx));
 
-	if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate)))
+	p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init)))
+	p = simple_get_bytes(p, end, &ctx->seed_init, sizeof(ctx->seed_init));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed)))
+	p = simple_get_bytes(p, end, ctx->seed, sizeof(ctx->seed));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg)))
+	p = simple_get_bytes(p, end, &ctx->signalg, sizeof(ctx->signalg));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg)))
+	p = simple_get_bytes(p, end, &ctx->sealalg, sizeof(ctx->sealalg));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime)))
+	p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send)))
+	p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send));
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_netobj(&p, end, &ctx->mech_used))
+	p = simple_get_netobj(p, end, &ctx->mech_used);
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
-	if (get_key(&p, end, &ctx->enc))
+	p = get_key(p, end, &ctx->enc);
+	if (IS_ERR(p))
 		goto out_err_free_mech;
-	if (get_key(&p, end, &ctx->seq))
+	p = get_key(p, end, &ctx->seq);
+	if (IS_ERR(p))
 		goto out_err_free_key1;
-	if (p != end)
+	if (p != end) {
+		p = ERR_PTR(-EFAULT);
 		goto out_err_free_key2;
+	}
 
 	ctx_id->internal_ctx_id = ctx;
 	dprintk("RPC:      Succesfully imported new context.\n");
@@ -163,7 +178,7 @@ out_err_free_mech:
 out_err_free_ctx:
 	kfree(ctx);
 out_err:
-	return GSS_S_FAILURE;
+	return PTR_ERR(p);
 }
 
 static void
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -143,7 +143,7 @@ gss_mech_get(struct gss_api_mech *gm)
 EXPORT_SYMBOL(gss_mech_get);
 
 struct gss_api_mech *
-gss_mech_get_by_name(char *name)
+gss_mech_get_by_name(const char *name)
 {
 	struct gss_api_mech	*pos, *gm = NULL;
 
@@ -233,8 +233,8 @@ EXPORT_SYMBOL(gss_mech_put);
 
 /* The mech could probably be determined from the token instead, but it's just
  * as easy for now to pass it in. */
-u32
-gss_import_sec_context(struct xdr_netobj	*input_token,
+int
+gss_import_sec_context(const void *input_token, size_t bufsize,
 		       struct gss_api_mech	*mech,
 		       struct gss_ctx		**ctx_id)
 {
@@ -244,7 +244,7 @@ gss_import_sec_context(struct xdr_netobj
 	(*ctx_id)->mech_type = gss_mech_get(mech);
 
 	return mech->gm_ops
-		->gss_import_sec_context(input_token, *ctx_id);
+		->gss_import_sec_context(input_token, bufsize, *ctx_id);
 }
 
 /* gss_get_mic: compute a mic over message and return mic_token. */
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -49,52 +49,51 @@
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
-static inline int
-get_bytes(char **ptr, const char *end, void *res, int len)
+static const void *
+simple_get_bytes(const void *p, const void *end, void *res, int len)
 {
-	char *p, *q;
-	p = *ptr;
-	q = p + len;
-	if (q > end || q < p)
-		return -1;
+	const void *q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
 	memcpy(res, p, len);
-	*ptr = q;
-	return 0;
+	return q;
 }
 
-static inline int
-get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
+static const void *
+simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
 {
-	char *p, *q;
-	p = *ptr;
-	if (get_bytes(&p, end, &res->len, sizeof(res->len)))
-		return -1;
-	q = p + res->len;
-	if(res->len == 0)
-		goto out_nocopy;
-	if (q > end || q < p)
-		return -1;
-	if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
-		return -1;
-	memcpy(res->data, p, res->len);
-out_nocopy:
-	*ptr = q;
-	return 0;
+	const void *q;
+	unsigned int len;
+	p = simple_get_bytes(p, end, &len, sizeof(len));
+	if (IS_ERR(p))
+		return p;
+	res->len = len;
+	if (len == 0) {
+		res->data = NULL;
+		return p;
+	}
+	q = (const void *)((const char *)p + len);
+	if (unlikely(q > end || q < p))
+		return ERR_PTR(-EFAULT);
+	res->data = kmalloc(len, GFP_KERNEL);
+	if (unlikely(res->data == NULL))
+		return ERR_PTR(-ENOMEM);
+	memcpy(res->data, p, len);
+	return q;
 }
 
-static inline int
-get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
+static inline const void *
+get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
 {
-	struct xdr_netobj	key = {
-		.len = 0,
-		.data = NULL,
-	};
+	struct xdr_netobj	key = { 0 };
 	int			alg_mode,setkey = 0;
 	char			*alg_name;
 
-	if (get_bytes(p, end, resalg, sizeof(int)))
+	p = simple_get_bytes(p, end, resalg, sizeof(*resalg));
+	if (IS_ERR(p))
 		goto out_err;
-	if ((get_netobj(p, end, &key)))
+	p = simple_get_netobj(p, end, &key);
+	if (IS_ERR(p))
 		goto out_err;
 
 	switch (*resalg) {
@@ -111,10 +110,6 @@ get_key(char **p, char *end, struct cryp
 			alg_mode = 0;
 			setkey = 0;
 			break;
-		case NID_cast5_cbc:
-			dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
-			goto out_err;
-			break;
 		default:
 			dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
 			goto out_err_free_key;
@@ -128,69 +123,81 @@ get_key(char **p, char *end, struct cryp
 
 	if(key.len > 0)
 		kfree(key.data);
-	return 0;
+	return p;
 
 out_err_free_tfm:
 	crypto_free_tfm(*res);
 out_err_free_key:
 	if(key.len > 0)
 		kfree(key.data);
+	p = ERR_PTR(-EINVAL);
 out_err:
-	return -1;
+	return p;
 }
 
-static u32
-gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
+static int
+gss_import_sec_context_spkm3(const void *p, size_t len,
 				struct gss_ctx *ctx_id)
 {
-	char	*p = inbuf->data;
-	char	*end = inbuf->data + inbuf->len;
+	const void *end = (const void *)((const char *)p + len);
 	struct	spkm3_ctx *ctx;
 
 	if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
 		goto out_err;
 	memset(ctx, 0, sizeof(*ctx));
 
-	if (get_netobj(&p, end, &ctx->ctx_id))
+	p = simple_get_netobj(p, end, &ctx->ctx_id);
+	if (IS_ERR(p))
 		goto out_err_free_ctx;
 
-	if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
+	p = simple_get_bytes(p, end, &ctx->qop, sizeof(ctx->qop));
+	if (IS_ERR(p))
 		goto out_err_free_ctx_id;
 
-	if (get_netobj(&p, end, &ctx->mech_used))
+	p = simple_get_netobj(p, end, &ctx->mech_used);
+	if (IS_ERR(p))
 		goto out_err_free_mech;
 
-	if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
+	p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags));
+	if (IS_ERR(p))
 		goto out_err_free_mech;
 
-	if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
+	p = simple_get_bytes(p, end, &ctx->req_flags, sizeof(ctx->req_flags));
+	if (IS_ERR(p))
 		goto out_err_free_mech;
 
-	if (get_netobj(&p, end, &ctx->share_key))
+	p = simple_get_netobj(p, end, &ctx->share_key);
+	if (IS_ERR(p))
 		goto out_err_free_s_key;
 
-	if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
-		dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
-	}
-
-	if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
-		dprintk("RPC: SPKM3 integrity key will be NULL\n");
-	}
-
-	if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
+	p = get_key(p, end, &ctx->derived_conf_key, &ctx->conf_alg);
+	if (IS_ERR(p))
 		goto out_err_free_s_key;
 
-	if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
-		goto out_err_free_s_key;
+	p = get_key(p, end, &ctx->derived_integ_key, &ctx->intg_alg);
+	if (IS_ERR(p))
+		goto out_err_free_key1;
+
+	p = simple_get_bytes(p, end, &ctx->keyestb_alg, sizeof(ctx->keyestb_alg));
+	if (IS_ERR(p))
+		goto out_err_free_key2;
+
+	p = simple_get_bytes(p, end, &ctx->owf_alg, sizeof(ctx->owf_alg));
+	if (IS_ERR(p))
+		goto out_err_free_key2;
 
 	if (p != end)
-		goto out_err_free_s_key;
+		goto out_err_free_key2;
 
 	ctx_id->internal_ctx_id = ctx;
 
 	dprintk("Succesfully imported new spkm context.\n");
 	return 0;
 
+out_err_free_key2:
+	crypto_free_tfm(ctx->derived_integ_key);
+out_err_free_key1:
+	crypto_free_tfm(ctx->derived_conf_key);
 out_err_free_s_key:
 	kfree(ctx->share_key.data);
 out_err_free_mech:
@@ -200,7 +207,7 @@ out_err_free_ctx_id:
 out_err_free_ctx:
 	kfree(ctx);
 out_err:
-	return GSS_S_FAILURE;
+	return PTR_ERR(p);
 }
 
 static void
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -381,7 +381,6 @@ static int rsc_parse(struct cache_detail
 	else {
 		int N, i;
 		struct gss_api_mech *gm;
-		struct xdr_netobj tmp_buf;
 
 		/* gid */
 		if (get_int(&mesg, &rsci.cred.cr_gid))
@@ -420,9 +419,7 @@ static int rsc_parse(struct cache_detail
 			gss_mech_put(gm);
 			goto out;
 		}
-		tmp_buf.len = len;
-		tmp_buf.data = buf;
-		if (gss_import_sec_context(&tmp_buf, gm, &rsci.mechctx)) {
+		if (gss_import_sec_context(buf, len, gm, &rsci.mechctx)) {
 			gss_mech_put(gm);
 			goto out;
 		}
@@ -730,6 +727,19 @@ struct gss_svc_data {
 	struct rsc			*rsci;
 };
 
+static int
+svcauth_gss_set_client(struct svc_rqst *rqstp)
+{
+	struct gss_svc_data *svcdata = rqstp->rq_auth_data;
+	struct rsc *rsci = svcdata->rsci;
+	struct rpc_gss_wire_cred *gc = &svcdata->clcred;
+
+	rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
+	if (rqstp->rq_client == NULL)
+		return SVC_DENIED;
+	return SVC_OK;
+}
+
 /*
  * Accept an rpcsec packet.
  * If context establishment, punt to user space
@@ -893,11 +903,6 @@ svcauth_gss_accept(struct svc_rqst *rqst
 		svc_putu32(resv, rpc_success);
 		goto complete;
 	case RPC_GSS_PROC_DATA:
-		*authp = rpc_autherr_badcred;
-		rqstp->rq_client =
-			find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
-		if (rqstp->rq_client == NULL)
-			goto auth_err;
 		*authp = rpcsec_gsserr_ctxproblem;
 		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
 			goto auth_err;
@@ -911,8 +916,6 @@ svcauth_gss_accept(struct svc_rqst *rqst
 			if (unwrap_integ_data(&rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
 				goto auth_err;
-			svcdata->rsci = rsci;
-			cache_get(&rsci->h);
 			/* placeholders for length and seq. number: */
 			svcdata->body_start = resv->iov_base + resv->iov_len;
 			svc_putu32(resv, 0);
@@ -923,6 +926,8 @@ svcauth_gss_accept(struct svc_rqst *rqst
 		default:
 			goto auth_err;
 		}
+		svcdata->rsci = rsci;
+		cache_get(&rsci->h);
 		ret = SVC_OK;
 		goto out;
 	}
@@ -1052,6 +1057,7 @@ static struct auth_ops svcauthops_gss = 
 	.accept		= svcauth_gss_accept,
 	.release	= svcauth_gss_release,
 	.domain_release = svcauth_gss_domain_release,
+	.set_client	= svcauth_gss_set_client,
 };
 
 int
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -18,48 +18,28 @@
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
-static struct rpc_credops	null_credops;
+static struct rpc_auth null_auth;
+static struct rpc_cred null_cred;
 
 static struct rpc_auth *
 nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 {
-	struct rpc_auth	*auth;
-
-	dprintk("RPC: creating NULL authenticator for client %p\n", clnt);
-	if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth),GFP_KERNEL)))
-		return NULL;
-	auth->au_cslack = 4;
-	auth->au_rslack = 2;
-	auth->au_ops = &authnull_ops;
-	auth->au_expire = 1800 * HZ;
-	rpcauth_init_credcache(auth);
-
-	return (struct rpc_auth *) auth;
+	atomic_inc(&null_auth.au_count);
+	return &null_auth;
 }
 
 static void
 nul_destroy(struct rpc_auth *auth)
 {
-	dprintk("RPC: destroying NULL authenticator %p\n", auth);
-	rpcauth_free_credcache(auth);
 }
 
 /*
- * Create NULL creds for current process
+ * Lookup NULL creds for current process
  */
 static struct rpc_cred *
-nul_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
+nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
-	struct rpc_cred	*cred;
-
-	if (!(cred = (struct rpc_cred *) kmalloc(sizeof(*cred),GFP_KERNEL)))
-		return NULL;
-	atomic_set(&cred->cr_count, 0);
-	cred->cr_flags = RPCAUTH_CRED_UPTODATE;
-	cred->cr_uid = acred->uid;
-	cred->cr_ops = &null_credops;
-
-	return cred;
+	return get_rpccred(&null_cred);
 }
 
 /*
@@ -68,7 +48,6 @@ nul_create_cred(struct rpc_auth *auth, s
 static void
 nul_destroy_cred(struct rpc_cred *cred)
 {
-	kfree(cred);
 }
 
 /*
@@ -84,7 +63,7 @@ nul_match(struct auth_cred *acred, struc
  * Marshal credential.
  */
 static u32 *
-nul_marshal(struct rpc_task *task, u32 *p, int ruid)
+nul_marshal(struct rpc_task *task, u32 *p)
 {
 	*p++ = htonl(RPC_AUTH_NULL);
 	*p++ = 0;
@@ -125,7 +104,7 @@ nul_validate(struct rpc_task *task, u32 
 	return p;
 }
 
-struct rpc_authops	authnull_ops = {
+struct rpc_authops authnull_ops = {
 	.owner		= THIS_MODULE,
 	.au_flavor	= RPC_AUTH_NULL,
 #ifdef RPC_DEBUG
@@ -133,14 +112,32 @@ struct rpc_authops	authnull_ops = {
 #endif
 	.create		= nul_create,
 	.destroy	= nul_destroy,
-	.crcreate	= nul_create_cred,
+	.lookup_cred	= nul_lookup_cred,
+};
+
+static
+struct rpc_auth null_auth = {
+	.au_cslack	= 4,
+	.au_rslack	= 2,
+	.au_ops		= &authnull_ops,
 };
 
 static
 struct rpc_credops	null_credops = {
+	.cr_name	= "AUTH_NULL",
 	.crdestroy	= nul_destroy_cred,
 	.crmatch	= nul_match,
 	.crmarshal	= nul_marshal,
 	.crrefresh	= nul_refresh,
 	.crvalidate	= nul_validate,
 };
+
+static
+struct rpc_cred null_cred = {
+	.cr_ops		= &null_credops,
+	.cr_count	= ATOMIC_INIT(1),
+	.cr_flags	= RPCAUTH_CRED_UPTODATE,
+#ifdef RPC_DEBUG
+	.cr_magic	= RPCAUTH_CRED_MAGIC,
+#endif
+};
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -19,8 +19,6 @@
 struct unx_cred {
 	struct rpc_cred		uc_base;
 	gid_t			uc_gid;
-	uid_t			uc_puid;		/* process uid */
-	gid_t			uc_pgid;		/* process gid */
 	gid_t			uc_gids[NFS_NGROUPS];
 };
 #define uc_uid			uc_base.cr_uid
@@ -36,24 +34,17 @@ struct unx_cred {
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
+static struct rpc_auth		unix_auth;
+static struct rpc_cred_cache	unix_cred_cache;
 static struct rpc_credops	unix_credops;
 
 static struct rpc_auth *
 unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 {
-	struct rpc_auth	*auth;
-
 	dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
-	if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL)))
-		return NULL;
-	auth->au_cslack = UNX_WRITESLACK;
-	auth->au_rslack = 2;	/* assume AUTH_NULL verf */
-	auth->au_expire = UNX_CRED_EXPIRE;
-	auth->au_ops = &authunix_ops;
-
-	rpcauth_init_credcache(auth);
-
-	return auth;
+	if (atomic_inc_return(&unix_auth.au_count) == 0)
+		unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1);
+	return &unix_auth;
 }
 
 static void
@@ -63,6 +54,15 @@ unx_destroy(struct rpc_auth *auth)
 	rpcauth_free_credcache(auth);
 }
 
+/*
+ * Lookup AUTH_UNIX creds for current process
+ */
+static struct rpc_cred *
+unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
+{
+	return rpcauth_lookup_credcache(auth, acred, flags);
+}
+
 static struct rpc_cred *
 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
@@ -73,13 +73,13 @@ unx_create_cred(struct rpc_auth *auth, s
 				acred->uid, acred->gid);
 
 	if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
-	atomic_set(&cred->uc_count, 0);
+	atomic_set(&cred->uc_count, 1);
 	cred->uc_flags = RPCAUTH_CRED_UPTODATE;
 	if (flags & RPC_TASK_ROOTCREDS) {
-		cred->uc_uid = cred->uc_puid = 0;
-		cred->uc_gid = cred->uc_pgid = 0;
+		cred->uc_uid = 0;
+		cred->uc_gid = 0;
 		cred->uc_gids[0] = NOGROUP;
 	} else {
 		int groups = acred->group_info->ngroups;
@@ -88,8 +88,6 @@ unx_create_cred(struct rpc_auth *auth, s
 
 		cred->uc_uid = acred->uid;
 		cred->uc_gid = acred->gid;
-		cred->uc_puid = current->uid;
-		cred->uc_pgid = current->gid;
 		for (i = 0; i < groups; i++)
 			cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
 		if (i < NFS_NGROUPS)
@@ -121,9 +119,7 @@ unx_match(struct auth_cred *acred, struc
 		int groups;
 
 		if (cred->uc_uid != acred->uid
-		 || cred->uc_gid != acred->gid
-		 || cred->uc_puid != current->uid
-		 || cred->uc_pgid != current->gid)
+		 || cred->uc_gid != acred->gid)
 			return 0;
 
 		groups = acred->group_info->ngroups;
@@ -134,8 +130,8 @@ unx_match(struct auth_cred *acred, struc
 				return 0;
 		return 1;
 	}
-	return (cred->uc_uid == 0 && cred->uc_puid == 0
-	     && cred->uc_gid == 0 && cred->uc_pgid == 0
+	return (cred->uc_uid == 0
+	     && cred->uc_gid == 0
 	     && cred->uc_gids[0] == (gid_t) NOGROUP);
 }
 
@@ -144,7 +140,7 @@ unx_match(struct auth_cred *acred, struc
  * Maybe we should keep a cached credential for performance reasons.
  */
 static u32 *
-unx_marshal(struct rpc_task *task, u32 *p, int ruid)
+unx_marshal(struct rpc_task *task, u32 *p)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct unx_cred	*cred = (struct unx_cred *) task->tk_msg.rpc_cred;
@@ -160,14 +156,8 @@ unx_marshal(struct rpc_task *task, u32 *
 	 */
 	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
 
-	/* Note: we don't use real uid if it involves raising privilege */
-	if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
-		*p++ = htonl((u32) cred->uc_puid);
-		*p++ = htonl((u32) cred->uc_pgid);
-	} else {
-		*p++ = htonl((u32) cred->uc_uid);
-		*p++ = htonl((u32) cred->uc_gid);
-	}
+	*p++ = htonl((u32) cred->uc_uid);
+	*p++ = htonl((u32) cred->uc_gid);
 	hold = p++;
 	for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
 		*p++ = htonl((u32) cred->uc_gids[i]);
@@ -223,11 +213,27 @@ struct rpc_authops	authunix_ops = {
 #endif
 	.create		= unx_create,
 	.destroy	= unx_destroy,
+	.lookup_cred	= unx_lookup_cred,
 	.crcreate	= unx_create_cred,
 };
 
 static
+struct rpc_cred_cache	unix_cred_cache = {
+	.expire		= UNX_CRED_EXPIRE,
+};
+
+static
+struct rpc_auth		unix_auth = {
+	.au_cslack	= UNX_WRITESLACK,
+	.au_rslack	= 2,			/* assume AUTH_NULL verf */
+	.au_ops		= &authunix_ops,
+	.au_count	= ATOMIC_INIT(0),
+	.au_credcache	= &unix_cred_cache,
+};
+
+static
 struct rpc_credops	unix_credops = {
+	.cr_name	= "AUTH_UNIX",
 	.crdestroy	= unx_destroy_cred,
 	.crmatch	= unx_match,
 	.crmarshal	= unx_marshal,
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -321,12 +321,10 @@ static int cache_clean(void)
 			if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
 				queue_loose(current_detail, ch);
 
-			if (!atomic_read(&ch->refcnt))
+			if (atomic_read(&ch->refcnt) == 1)
 				break;
 		}
 		if (ch) {
-			cache_get(ch);
-			clear_bit(CACHE_HASHED, &ch->flags);
 			*cp = ch->next;
 			ch->next = NULL;
 			current_detail->entries--;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -23,6 +23,7 @@
 
 #include <asm/system.h>
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
@@ -406,12 +407,11 @@ rpc_call_async(struct rpc_clnt *clnt, st
 	rpc_call_setup(task, msg, 0);
 
 	/* Set up the call info struct and execute the task */
-	if (task->tk_status == 0)
-		status = rpc_execute(task);
-	else {
-		status = task->tk_status;
+	status = task->tk_status;
+	if (status == 0)
+		rpc_execute(task);
+	else
 		rpc_release_task(task);
-	}
 
 out:
 	rpc_clnt_sigunmask(clnt, &oldset);		
@@ -426,9 +426,9 @@ rpc_call_setup(struct rpc_task *task, st
 	task->tk_msg   = *msg;
 	task->tk_flags |= flags;
 	/* Bind the user cred */
-	if (task->tk_msg.rpc_cred != NULL) {
+	if (task->tk_msg.rpc_cred != NULL)
 		rpcauth_holdcred(task);
-	} else
+	else
 		rpcauth_bindcred(task);
 
 	if (task->tk_status == 0)
@@ -453,6 +453,20 @@ rpc_setbufsize(struct rpc_clnt *clnt, un
 }
 
 /*
+ * Return size of largest payload RPC client can support, in bytes
+ *
+ * For stream transports, this is one RPC record fragment (see RFC
+ * 1831), as we don't support multi-record requests yet.  For datagram
+ * transports, this is the size of an IP packet minus the IP, UDP, and
+ * RPC header sizes.
+ */
+size_t rpc_max_payload(struct rpc_clnt *clnt)
+{
+	return clnt->cl_xprt->max_payload;
+}
+EXPORT_SYMBOL(rpc_max_payload);
+
+/*
  * Restart an (async) RPC call. Usually called from within the
  * exit handler.
  */
@@ -871,21 +885,6 @@ call_decode(struct rpc_task *task)
 		goto out_retry;
 	}
 
-	/*
-	 * The following is an NFS-specific hack to cater for setuid
-	 * processes whose uid is mapped to nobody on the server.
-	 */
-	if (task->tk_client->cl_droppriv && 
-            (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
-		if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
-			dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
-			task->tk_flags ^= RPC_CALL_REALUID;
-			task->tk_action = call_bind;
-			task->tk_suid_retry--;
-			goto out_retry;
-		}
-	}
-
 	task->tk_action = NULL;
 
 	if (decode)
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -3,9 +3,6 @@
  *
  * Portmapper client.
  *
- * FIXME: In a secure environment, we may want to use an authentication
- * flavor other than AUTH_NULL.
- *
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
@@ -212,7 +209,7 @@ pmap_create(char *hostname, struct socka
 	/* printk("pmap: create clnt\n"); */
 	clnt = rpc_create_client(xprt, hostname,
 				&pmap_program, RPC_PMAP_VERSION,
-				RPC_AUTH_NULL);
+				RPC_AUTH_UNIX);
 	if (IS_ERR(clnt)) {
 		xprt_destroy(xprt);
 	} else {
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -132,9 +132,11 @@ __rpc_add_timer(struct rpc_task *task, r
  * Delete any timer for the current task. Because we use del_timer_sync(),
  * this function should never be called while holding queue->lock.
  */
-static inline void
+static void
 rpc_delete_timer(struct rpc_task *task)
 {
+	if (RPC_IS_QUEUED(task))
+		return;
 	if (test_and_clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate)) {
 		del_singleshot_timer_sync(&task->tk_timer);
 		dprintk("RPC: %4d deleting timer\n", task->tk_pid);
@@ -747,13 +749,10 @@ void rpc_init_task(struct rpc_task *task
 	task->tk_client = clnt;
 	task->tk_flags  = flags;
 	task->tk_exit   = callback;
-	if (current->uid != current->fsuid || current->gid != current->fsgid)
-		task->tk_flags |= RPC_TASK_SETUID;
 
 	/* Initialize retry counters */
 	task->tk_garb_retry = 2;
 	task->tk_cred_retry = 2;
-	task->tk_suid_retry = 1;
 
 	task->tk_priority = RPC_PRIORITY_NORMAL;
 	task->tk_cookie = (unsigned long)current;
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -90,6 +90,7 @@ EXPORT_SYMBOL(svc_reserve);
 EXPORT_SYMBOL(svc_auth_register);
 EXPORT_SYMBOL(auth_domain_lookup);
 EXPORT_SYMBOL(svc_authenticate);
+EXPORT_SYMBOL(svc_set_client);
 
 /* RPC statistics */
 #ifdef CONFIG_PROC_FS
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -264,6 +264,7 @@ svc_process(struct svc_serv *serv, struc
 	u32			dir, prog, vers, proc,
 				auth_stat, rpc_stat;
 	int			auth_res;
+	u32			*accept_statp;
 
 	rpc_stat = rpc_success;
 
@@ -299,6 +300,9 @@ svc_process(struct svc_serv *serv, struc
 	if (vers != 2)		/* RPC version number */
 		goto err_bad_rpc;
 
+	/* Save position in case we later decide to reject: */
+	accept_statp = resv->iov_base + resv->iov_len;
+
 	svc_putu32(resv, xdr_zero);		/* ACCEPT */
 
 	rqstp->rq_prog = prog = ntohl(svc_getu32(argv));	/* program number */
@@ -311,10 +315,12 @@ svc_process(struct svc_serv *serv, struc
 	 * We do this before anything else in order to get a decent
 	 * auth verifier.
 	 */
-	if (progp->pg_authenticate != NULL)
-		auth_res = progp->pg_authenticate(rqstp, &auth_stat);
-	else
-		auth_res = svc_authenticate(rqstp, &auth_stat);
+	auth_res = svc_authenticate(rqstp, &auth_stat);
+	/* Also give the program a chance to reject this call: */
+	if (auth_res == SVC_OK) {
+		auth_stat = rpc_autherr_badcred;
+		auth_res = progp->pg_authenticate(rqstp);
+	}
 	switch (auth_res) {
 	case SVC_OK:
 		break;
@@ -437,7 +443,8 @@ err_bad_rpc:
 err_bad_auth:
 	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
 	serv->sv_stats->rpcbadauth++;
-	resv->iov_len -= 4;
+	/* Restore write pointer to location of accept status: */
+	xdr_ressize_check(rqstp, accept_statp);
 	svc_putu32(resv, xdr_one);	/* REJECT */
 	svc_putu32(resv, xdr_one);	/* AUTH_ERROR */
 	svc_putu32(resv, auth_stat);	/* status */
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -59,6 +59,11 @@ svc_authenticate(struct svc_rqst *rqstp,
 	return aops->accept(rqstp, authp);
 }
 
+int svc_set_client(struct svc_rqst *rqstp)
+{
+	return rqstp->rq_authop->set_client(rqstp);
+}
+
 /* A request, which was authenticated, has now executed.
  * Time to finalise the the credentials and verifier
  * and release and resources
@@ -173,12 +178,12 @@ auth_domain_lookup(struct auth_domain *i
 		tmp = container_of(*hp, struct auth_domain, h);
 		if (!auth_domain_match(tmp, item))
 			continue;
-		cache_get(&tmp->h);
-		if (!set)
+		if (!set) {
+			cache_get(&tmp->h);
 			goto out_noset;
+		}
 		*hp = tmp->h.next;
 		tmp->h.next = NULL;
-		clear_bit(CACHE_HASHED, &tmp->h.flags);
 		auth_domain_drop(&tmp->h, &auth_domain_cache);
 		goto out_set;
 	}
@@ -187,9 +192,9 @@ auth_domain_lookup(struct auth_domain *i
 		goto out_nada;
 	auth_domain_cache.entries++;
 out_set:
-	set_bit(CACHE_HASHED, &item->h.flags);
 	item->h.next = *head;
 	*head = &item->h;
+	cache_get(&item->h);
 	write_unlock(&auth_domain_cache.hash_lock);
 	cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
 	cache_get(&item->h);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -368,7 +368,6 @@ svcauth_null_accept(struct svc_rqst *rqs
 	struct kvec	*argv = &rqstp->rq_arg.head[0];
 	struct kvec	*resv = &rqstp->rq_res.head[0];
 	struct svc_cred	*cred = &rqstp->rq_cred;
-	int		rv=0;
 
 	cred->cr_group_info = NULL;
 	rqstp->rq_client = NULL;
@@ -394,19 +393,11 @@ svcauth_null_accept(struct svc_rqst *rqs
 	if (cred->cr_group_info == NULL)
 		return SVC_DROP; /* kmalloc failure - client must retry */
 
-	rv = svcauth_unix_set_client(rqstp);
-	if (rv == SVC_DENIED)
-		goto badcred;
-
 	/* Put NULL verifier */
 	svc_putu32(resv, RPC_AUTH_NULL);
 	svc_putu32(resv, 0);
 
-	return rv;
-
-badcred:
-	*authp = rpc_autherr_badcred;
-	return SVC_DENIED;
+	return SVC_OK;
 }
 
 static int
@@ -429,6 +420,7 @@ struct auth_ops svcauth_null = {
 	.flavour	= RPC_AUTH_NULL,
 	.accept 	= svcauth_null_accept,
 	.release	= svcauth_null_release,
+	.set_client	= svcauth_unix_set_client,
 };
 
 
@@ -440,7 +432,6 @@ svcauth_unix_accept(struct svc_rqst *rqs
 	struct svc_cred	*cred = &rqstp->rq_cred;
 	u32		slen, i;
 	int		len   = argv->iov_len;
-	int		rv=0;
 
 	cred->cr_group_info = NULL;
 	rqstp->rq_client = NULL;
@@ -472,15 +463,11 @@ svcauth_unix_accept(struct svc_rqst *rqs
 		return SVC_DENIED;
 	}
 
-	rv = svcauth_unix_set_client(rqstp);
-	if (rv == SVC_DENIED)
-		goto badcred;
-
 	/* Put NULL verifier */
 	svc_putu32(resv, RPC_AUTH_NULL);
 	svc_putu32(resv, 0);
 
-	return rv;
+	return SVC_OK;
 
 badcred:
 	*authp = rpc_autherr_badcred;
@@ -510,5 +497,6 @@ struct auth_ops svcauth_unix = {
 	.accept 	= svcauth_unix_accept,
 	.release	= svcauth_unix_release,
 	.domain_release	= svcauth_unix_domain_release,
+	.set_client	= svcauth_unix_set_client,
 };
 
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1186,6 +1186,7 @@ svc_recv(struct svc_serv *serv, struct s
 	arg->len = (pages-1)*PAGE_SIZE;
 	arg->tail[0].iov_len = 0;
 	
+	try_to_freeze(PF_FREEZE);
 	if (signalled())
 		return -EINTR;
 
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -46,9 +46,9 @@ xdr_decode_netobj(u32 *p, struct xdr_net
 
 /**
  * xdr_encode_opaque_fixed - Encode fixed length opaque data
- * @p - pointer to current position in XDR buffer.
- * @ptr - pointer to data to encode (or NULL)
- * @nbytes - size of data.
+ * @p: pointer to current position in XDR buffer.
+ * @ptr: pointer to data to encode (or NULL)
+ * @nbytes: size of data.
  *
  * Copy the array of data of length nbytes at ptr to the XDR buffer
  * at position p, then align to the next 32-bit boundary by padding
@@ -76,9 +76,9 @@ EXPORT_SYMBOL(xdr_encode_opaque_fixed);
 
 /**
  * xdr_encode_opaque - Encode variable length opaque data
- * @p - pointer to current position in XDR buffer.
- * @ptr - pointer to data to encode (or NULL)
- * @nbytes - size of data.
+ * @p: pointer to current position in XDR buffer.
+ * @ptr: pointer to data to encode (or NULL)
+ * @nbytes: size of data.
  *
  * Returns the updated current XDR buffer position
  */
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1044,7 +1044,8 @@ tcp_state_change(struct sock *sk)
 	dprintk("RPC:      tcp_state_change client %p...\n", xprt);
 	dprintk("RPC:      state %x conn %d dead %d zapped %d\n",
 				sk->sk_state, xprt_connected(xprt),
-				sock_flag(sk, SOCK_DEAD), sk->sk_zapped);
+				sock_flag(sk, SOCK_DEAD),
+				sock_flag(sk, SOCK_ZAPPED));
 
 	switch (sk->sk_state) {
 	case TCP_ESTABLISHED:
@@ -1460,8 +1461,11 @@ xprt_setup(int proto, struct sockaddr_in
 	if (xprt->stream) {
 		xprt->cwnd = RPC_MAXCWND(xprt);
 		xprt->nocong = 1;
-	} else
+		xprt->max_payload = (1U << 31) - 1;
+	} else {
 		xprt->cwnd = RPC_INITCWND;
+		xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
+	}
 	spin_lock_init(&xprt->sock_lock);
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -85,7 +85,6 @@
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -121,8 +120,6 @@
 
 int sysctl_unix_max_dgram_qlen = 10;
 
-static kmem_cache_t *unix_sk_cachep;
-
 struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
 DEFINE_RWLOCK(unix_table_lock);
 static atomic_t unix_nr_socks = ATOMIC_INIT(0);
@@ -188,6 +185,13 @@ static int unix_mkname(struct sockaddr_u
 	if (!sunaddr || sunaddr->sun_family != AF_UNIX)
 		return -EINVAL;
 	if (sunaddr->sun_path[0]) {
+		/*
+		 * 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 exist.  However in kernel space
+		 * we are guaranteed that it is a valid memory location in our
+		 * kernel address buffer.
+		 */
 		((char *)sunaddr)[len]=0;
 		len = strlen(sunaddr->sun_path)+1+sizeof(short);
 		return len;
@@ -532,6 +536,12 @@ static struct proto_ops unix_seqpacket_o
 	.sendpage =	sock_no_sendpage,
 };
 
+static struct proto unix_proto = {
+	.name	  = "UNIX",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct unix_sock),
+};
+
 static struct sock * unix_create1(struct socket *sock)
 {
 	struct sock *sk = NULL;
@@ -540,15 +550,13 @@ static struct sock * unix_create1(struct
 	if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files)
 		goto out;
 
-	sk = sk_alloc(PF_UNIX, GFP_KERNEL, sizeof(struct unix_sock),
-		      unix_sk_cachep);
+	sk = sk_alloc(PF_UNIX, GFP_KERNEL, &unix_proto, 1);
 	if (!sk)
 		goto out;
 
 	atomic_inc(&unix_nr_socks);
 
 	sock_init_data(sock,sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	sk->sk_write_space	= unix_write_space;
 	sk->sk_max_ack_backlog	= sysctl_unix_max_dgram_qlen;
@@ -762,33 +770,12 @@ static int unix_bind(struct socket *sock
 		err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
 		if (err)
 			goto out_mknod_parent;
-		/*
-		 * Yucky last component or no last component at all?
-		 * (foo/., foo/.., /////)
-		 */
-		err = -EEXIST;
-		if (nd.last_type != LAST_NORM)
-			goto out_mknod;
-		/*
-		 * Lock the directory.
-		 */
-		down(&nd.dentry->d_inode->i_sem);
-		/*
-		 * Do the final lookup.
-		 */
-		dentry = lookup_hash(&nd.last, nd.dentry);
+
+		dentry = lookup_create(&nd, 0);
 		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto out_mknod_unlock;
-		err = -ENOENT;
-		/*
-		 * Special case - lookup gave negative, but... we had foo/bar/
-		 * From the vfs_mknod() POV we just have a negative dentry -
-		 * all is fine. Let's be bastards - you had / on the end, you've
-		 * been asking for (non-existent) directory. -ENOENT for you.
-		 */
-		if (nd.last.name[nd.last.len] && !dentry->d_inode)
-			goto out_mknod_dput;
+
 		/*
 		 * All right, let's create it.
 		 */
@@ -837,7 +824,6 @@ out_mknod_dput:
 	dput(dentry);
 out_mknod_unlock:
 	up(&nd.dentry->d_inode->i_sem);
-out_mknod:
 	path_release(&nd);
 out_mknod_parent:
 	if (err==-EEXIST)
@@ -861,8 +847,8 @@ static int unix_dgram_connect(struct soc
 			goto out;
 		alen = err;
 
-		if (sock->passcred && !unix_sk(sk)->addr &&
-		    (err = unix_autobind(sock)) != 0)
+		if (test_bit(SOCK_PASSCRED, &sock->flags) &&
+		    !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0)
 			goto out;
 
 		other=unix_find_other(sunaddr, alen, sock->type, hash, &err);
@@ -952,7 +938,8 @@ static int unix_stream_connect(struct so
 		goto out;
 	addr_len = err;
 
-	if (sock->passcred && !u->addr && (err = unix_autobind(sock)) != 0)
+	if (test_bit(SOCK_PASSCRED, &sock->flags)
+		&& !u->addr && (err = unix_autobind(sock)) != 0)
 		goto out;
 
 	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
@@ -1286,7 +1273,8 @@ static int unix_dgram_sendmsg(struct kio
 			goto out;
 	}
 
-	if (sock->passcred && !u->addr && (err = unix_autobind(sock)) != 0)
+	if (test_bit(SOCK_PASSCRED, &sock->flags)
+		&& !u->addr && (err = unix_autobind(sock)) != 0)
 		goto out;
 
 	err = -EMSGSIZE;
@@ -2048,26 +2036,28 @@ static inline void unix_sysctl_unregiste
 
 static int __init af_unix_init(void)
 {
+	int rc = -1;
 	struct sk_buff *dummy_skb;
 
 	if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) {
 		printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
-		return -1;
+		goto out;
+	}
+
+	rc = proto_register(&unix_proto, 1);
+        if (rc != 0) {
+                printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n",
+		       __FUNCTION__);
+		goto out;
 	}
-        /* allocate our sock slab cache */
-        unix_sk_cachep = kmem_cache_create("unix_sock",
-					   sizeof(struct unix_sock), 0,
-					   SLAB_HWCACHE_ALIGN, NULL, NULL);
-        if (!unix_sk_cachep)
-                printk(KERN_CRIT
-                        "af_unix_init: Cannot create unix_sock SLAB cache!\n");
 
 	sock_register(&unix_family_ops);
 #ifdef CONFIG_PROC_FS
 	proc_net_fops_create("unix", 0, &unix_seq_fops);
 #endif
 	unix_sysctl_register();
-	return 0;
+out:
+	return rc;
 }
 
 static void __exit af_unix_exit(void)
@@ -2075,7 +2065,7 @@ static void __exit af_unix_exit(void)
 	sock_unregister(PF_UNIX);
 	unix_sysctl_unregister();
 	proc_net_remove("unix");
-	kmem_cache_destroy(unix_sk_cachep);
+	proto_unregister(&unix_proto);
 }
 
 module_init(af_unix_init);
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -100,7 +100,7 @@ static struct sock *unix_get_socket(stru
 	/*
 	 *	Socket ?
 	 */
-	if (inode->i_sock) {
+	if (S_ISSOCK(inode->i_mode)) {
 		struct socket * sock = SOCKET_I(inode);
 		struct sock * s = sock->sk;
 
diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
--- a/net/wanrouter/af_wanpipe.c
+++ b/net/wanrouter/af_wanpipe.c
@@ -394,7 +394,7 @@ static int wanpipe_listen_rcv (struct sk
 	chan->lcn = mbox_ptr->cmd.lcn;
 	card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev;
 
-	newsk->sk_zapped = 0;
+	sock_reset_flag(newsk, SOCK_ZAPPED);
 	newwp->num = htons(X25_PROT);
 
 	if (wanpipe_do_bind(newsk, dev, newwp->num)) {
@@ -468,13 +468,26 @@ static struct sock *wanpipe_make_new(str
 	wp_sk(sk)->num	= wp_sk(osk)->num;
 	sk->sk_rcvbuf	= osk->sk_rcvbuf;
 	sk->sk_sndbuf	= osk->sk_sndbuf;
-	sk->sk_debug	= osk->sk_debug;
 	sk->sk_state	= WANSOCK_CONNECTING;
 	sk->sk_sleep	= osk->sk_sleep;
 
+	if (sock_flag(osk, SOCK_DBG))
+		sock_set_flag(sk, SOCK_DBG);
+
 	return sk;
 }
 
+/* 
+ * FIXME: wanpipe_opt has to include a sock in its definition and stop using
+ * sk_protinfo, but this code is not even compilable now, so lets leave it for
+ * later.
+ */
+static struct proto wanpipe_proto = {
+	.name	  = "WANPIPE",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct sock),
+};
+
 /*============================================================
  * wanpipe_make_new
  *
@@ -493,7 +506,7 @@ static struct sock *wanpipe_alloc_socket
 	struct sock *sk;
 	struct wanpipe_opt *wan_opt;
 
-	if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1, NULL)) == NULL)
+	if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, &wanpipe_proto, 1)) == NULL)
 		return NULL;
 
 	if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) {
@@ -546,7 +559,7 @@ static int wanpipe_sendmsg(struct kiocb 
 	int ifindex, err, reserve = 0;
 
 	
-	if (!sk->sk_zapped)
+	if (!sock_flag(sk, SOCK_ZAPPED))
 		return -ENETDOWN;
 
 	if (sk->sk_state != WANSOCK_CONNECTED)
@@ -672,7 +685,7 @@ static void wanpipe_delayed_transmit (un
 		return;
 	}
 	
-	if (sk->sk_state != WANSOCK_CONNECTED || !sk->sk_zapped) {
+	if (sk->sk_state != WANSOCK_CONNECTED || !sock_flag(sk, SOCK_ZAPPED)) {
 		clear_bit(0, &wp->timer);
 		DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n");
 		return;
@@ -865,7 +878,7 @@ static void wanpipe_unlink_driver (struc
 	struct net_device *dev;
 	wanpipe_common_t *chan=NULL;
 
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	sk->sk_state = WANSOCK_DISCONNECTED;
 	wp_sk(sk)->dev = NULL;
 
@@ -914,7 +927,7 @@ static void wanpipe_link_driver(struct n
 	chan->mbox = wp->mbox;
 	chan->tx_timer = &wp->tx_timer;
 	wp->dev = dev;
-	sk->sk_zapped = 1;
+	sock_set_flag(sk, SOCK_ZAPPED);
 	clear_bit(0,&chan->common_critical);
 }
 
@@ -964,7 +977,7 @@ static int wanpipe_release(struct socket
 	 */
 
 	if (wp->num == htons(X25_PROT) &&
-	    sk->sk_state != WANSOCK_DISCONNECTED && sk->sk_zapped) {
+	    sk->sk_state != WANSOCK_DISCONNECTED && sock_flag(sk, SOCK_ZAPPED)) {
 		struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if);
 		wanpipe_common_t *chan;
 		if (dev){
@@ -1075,15 +1088,15 @@ static void release_driver(struct sock *
 			}
 			kfree_skb(skb);
 		}
-		if (sk->sk_zapped)
+		if (sock_flag(sk, SOCK_ZAPPED))
 			wanpipe_unlink_card(sk);
 	}else{
-		if (sk->sk_zapped)
+		if (sock_flag(sk, SOCK_ZAPPED))
 			wanpipe_unlink_driver(sk);
 	}
 	sk->sk_state	    = WANSOCK_DISCONNECTED;
 	sk->sk_bound_dev_if = 0;
-	sk->sk_zapped	    = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	wp = wp_sk(sk);
 
 	if (wp && wp->mbox) {
@@ -1261,7 +1274,7 @@ static int wanpipe_do_bind(struct sock *
 	wanpipe_common_t *chan=NULL;
 	int err=0;
 
-	if (sk->sk_zapped) {
+	if (sock_flag(sk, SOCK_ZAPPED)) {
 		err = -EALREADY;
 		goto bind_unlock_exit;
 	}
@@ -1515,7 +1528,7 @@ static int wanpipe_create(struct socket 
 	sock->ops = &wanpipe_ops;
 	sock_init_data(sock,sk);
 
-	sk->sk_zapped	    = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	sk->sk_family	    = PF_WANPIPE;
 	wp_sk(sk)->num	    = protocol;
 	sk->sk_state	    = WANSOCK_DISCONNECTED;
@@ -1721,7 +1734,7 @@ static int wanpipe_notifier(struct notif
 		case NETDEV_UNREGISTER:
 			if (dev->ifindex == sk->sk_bound_dev_if) {
 				printk(KERN_INFO "wansock: Device down %s\n",dev->name);
-				if (sk->sk_zapped) {
+				if (sock_flag(sk, SOCK_ZAPPED)) {
 					wanpipe_unlink_driver(sk);
 					sk->sk_err = ENETDOWN;
 					sk->sk_error_report(sk);
@@ -1737,7 +1750,7 @@ static int wanpipe_notifier(struct notif
 			break;
 		case NETDEV_UP:
 			if (dev->ifindex == sk->sk_bound_dev_if &&
-			    po->num && !sk->sk_zapped) {
+			    po->num && !sock_flag(sk, SOCK_ZAPPED)) {
 				printk(KERN_INFO "wansock: Registering Device: %s\n",
 						dev->name);
 				wanpipe_link_driver(dev,sk);
@@ -2160,7 +2173,7 @@ static int wanpipe_link_card (struct soc
 
 	card->sk=sk;
 	card->func=wanpipe_listen_rcv;
-	sk->sk_zapped = 1;
+	sock_set_flag(sk, SOCK_ZAPPED);
  
 	return 0;
 }
@@ -2504,7 +2517,7 @@ static int wanpipe_connect(struct socket
 
 	dev_put(dev);
 	
-	if (!sk->sk_zapped) /* Must bind first - autobinding does not work */
+	if (!sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
 		return -EINVAL;
 
 	sock->state   = SS_CONNECTING;
@@ -2575,17 +2588,23 @@ void cleanup_module(void)
 	printk(KERN_INFO "wansock: Cleaning up \n");
 	unregister_netdevice_notifier(&wanpipe_netdev_notifier);
 	sock_unregister(PF_WANPIPE);
-	return;
+	proto_unregister(&wanpipe_proto);
 }
 
-
 int init_module(void)
 {
+	int rc;
 
 	printk(KERN_INFO "wansock: Registering Socket \n");
+
+	rc = proto_register(&wanpipe_proto, 0);
+	if (rc != 0)
+		goto out;
+
 	sock_register(&wanpipe_family_ops);
 	register_netdevice_notifier(&wanpipe_netdev_notifier);
-	return 0;
+out:
+	return rc;
 }
 #endif
 MODULE_LICENSE("GPL");
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -48,8 +48,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>	/* support for loadable modules */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
-#include <linux/mm.h>		/* verify_area(), etc. */
+#include <linux/slab.h>		/* kmalloc(), kfree() */
+#include <linux/mm.h>
 #include <linux/string.h>	/* inline mem*, str* functions */
 
 #include <asm/byteorder.h>	/* htons(), etc. */
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -442,35 +442,29 @@ static int x25_listen(struct socket *soc
 	return rc;
 }
 
+static struct proto x25_proto = {
+	.name	  = "X25",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct x25_sock),
+};
+
 static struct sock *x25_alloc_socket(void)
 {
-	struct x25_opt *x25;
-	struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, 1, NULL);
+	struct x25_sock *x25;
+	struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, &x25_proto, 1);
 
 	if (!sk)
 		goto out;
 
-	x25 = sk->sk_protinfo = kmalloc(sizeof(*x25), GFP_ATOMIC);
-	if (!x25)
-		goto frees;
-
-	memset(x25, 0, sizeof(*x25));
-
-	x25->sk = sk;
-
 	sock_init_data(NULL, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
+	x25 = x25_sk(sk);
 	skb_queue_head_init(&x25->ack_queue);
 	skb_queue_head_init(&x25->fragment_queue);
 	skb_queue_head_init(&x25->interrupt_in_queue);
 	skb_queue_head_init(&x25->interrupt_out_queue);
 out:
 	return sk;
-frees:
-	sk_free(sk);
-	sk = NULL;
-	goto out;
 }
 
 void x25_init_timers(struct sock *sk);
@@ -478,7 +472,7 @@ void x25_init_timers(struct sock *sk);
 static int x25_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct x25_opt *x25;
+	struct x25_sock *x25;
 	int rc = -ESOCKTNOSUPPORT;
 
 	if (sock->type != SOCK_SEQPACKET || protocol)
@@ -491,7 +485,6 @@ static int x25_create(struct socket *soc
 	x25 = x25_sk(sk);
 
 	sock_init_data(sock, sk);
-	sk_set_owner(sk, THIS_MODULE);
 
 	x25_init_timers(sk);
 
@@ -519,7 +512,7 @@ out:
 static struct sock *x25_make_new(struct sock *osk)
 {
 	struct sock *sk = NULL;
-	struct x25_opt *x25, *ox25;
+	struct x25_sock *x25, *ox25;
 
 	if (osk->sk_type != SOCK_SEQPACKET)
 		goto out;
@@ -535,12 +528,16 @@ static struct sock *x25_make_new(struct 
 	sk->sk_protocol    = osk->sk_protocol;
 	sk->sk_rcvbuf      = osk->sk_rcvbuf;
 	sk->sk_sndbuf      = osk->sk_sndbuf;
-	sk->sk_debug       = osk->sk_debug;
 	sk->sk_state       = TCP_ESTABLISHED;
 	sk->sk_sleep       = osk->sk_sleep;
-	sk->sk_zapped      = osk->sk_zapped;
 	sk->sk_backlog_rcv = osk->sk_backlog_rcv;
 
+	if (sock_flag(osk, SOCK_ZAPPED))
+		sock_set_flag(sk, SOCK_ZAPPED);
+	
+	if (sock_flag(osk, SOCK_DBG))
+		sock_set_flag(sk, SOCK_DBG);
+
 	ox25 = x25_sk(osk);
 	x25->t21        = ox25->t21;
 	x25->t22        = ox25->t22;
@@ -557,7 +554,7 @@ out:
 static int x25_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25;
+	struct x25_sock *x25;
 
 	if (!sk)
 		goto out;
@@ -598,14 +595,14 @@ static int x25_bind(struct socket *sock,
 	struct sock *sk = sock->sk;
 	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
 
-	if (!sk->sk_zapped ||
+	if (!sock_flag(sk, SOCK_ZAPPED) ||
 	    addr_len != sizeof(struct sockaddr_x25) ||
 	    addr->sx25_family != AF_X25)
 		return -EINVAL;
 
 	x25_sk(sk)->source_addr = addr->sx25_addr;
 	x25_insert_socket(sk);
-	sk->sk_zapped = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
 	SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
 
 	return 0;
@@ -644,7 +641,7 @@ static int x25_connect(struct socket *so
 		       int addr_len, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
 	struct x25_route *rt;
 	int rc = 0;
@@ -689,7 +686,7 @@ static int x25_connect(struct socket *so
 		goto out_put_neigh;
 
 	rc = -EINVAL;
-	if (sk->sk_zapped) /* Must bind first - autobinding does not work */
+	if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
 		goto out_put_neigh;
 
 	if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
@@ -802,7 +799,7 @@ static int x25_getname(struct socket *so
 {
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (peer) {
 		if (sk->sk_state != TCP_ESTABLISHED)
@@ -822,7 +819,7 @@ int x25_rx_call_request(struct sk_buff *
 {
 	struct sock *sk;
 	struct sock *make;
-	struct x25_opt *makex25;
+	struct x25_sock *makex25;
 	struct x25_address source_addr, dest_addr;
 	struct x25_facilities facilities;
 	struct x25_calluserdata calluserdata;
@@ -865,7 +862,7 @@ int x25_rx_call_request(struct sk_buff *
 	/*
 	 *	We can't accept the Call Request.
 	 */
-	if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog)
+	if (sk == NULL || sk_acceptq_is_full(sk))
 		goto out_clear_request;
 
 	/*
@@ -935,7 +932,7 @@ static int x25_sendmsg(struct kiocb *ioc
 		       struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
 	struct sockaddr_x25 sx25;
 	struct sk_buff *skb;
@@ -952,7 +949,7 @@ static int x25_sendmsg(struct kiocb *ioc
 		goto out;
 
 	rc = -EADDRNOTAVAIL;
-	if (sk->sk_zapped)
+	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
 
 	rc = -EPIPE;
@@ -1112,7 +1109,7 @@ static int x25_recvmsg(struct kiocb *ioc
 		       int flags)
 {
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
 	size_t copied;
 	int qbit;
@@ -1201,7 +1198,7 @@ out:
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	void __user *argp = (void __user *)arg;
 	int rc;
 
@@ -1391,6 +1388,11 @@ void x25_kill_by_neigh(struct x25_neigh 
 
 static int __init x25_init(void)
 {
+	int rc = proto_register(&x25_proto, 0);
+
+	if (rc != 0)
+		goto out;
+
 	sock_register(&x25_family_ops);
 
 	dev_add_pack(&x25_packet_type);
@@ -1403,7 +1405,8 @@ static int __init x25_init(void)
 	x25_register_sysctl();
 #endif
 	x25_proc_init();
-	return 0;
+out:
+	return rc;
 }
 module_init(x25_init);
 
@@ -1422,6 +1425,7 @@ static void __exit x25_exit(void)
 	dev_remove_pack(&x25_packet_type);
 
 	sock_unregister(AF_X25);
+	proto_unregister(&x25_proto);
 }
 module_exit(x25_exit);
 
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -158,7 +158,7 @@ int x25_create_facilities(unsigned char 
 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
 			     struct x25_facilities *new)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	struct x25_facilities *ours = &x25->facilities;
 	struct x25_facilities theirs;
 	int len;
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -34,7 +34,7 @@
 static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 {
 	struct sk_buff *skbo, *skbn = skb;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (more) {
 		x25->fraglen += skb->len;
@@ -89,7 +89,7 @@ static int x25_state1_machine(struct soc
 
 	switch (frametype) {
 		case X25_CALL_ACCEPTED: {
-			struct x25_opt *x25 = x25_sk(sk);
+			struct x25_sock *x25 = x25_sk(sk);
 
 			x25_stop_timer(sk);
 			x25->condition = 0x00;
@@ -165,7 +165,7 @@ static int x25_state3_machine(struct soc
 {
 	int queued = 0;
 	int modulus;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	
 	modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
 
@@ -295,7 +295,7 @@ static int x25_state4_machine(struct soc
 		case X25_RESET_REQUEST:
 			x25_write_internal(sk, X25_RESET_CONFIRMATION);
 		case X25_RESET_CONFIRMATION: {
-			struct x25_opt *x25 = x25_sk(sk);
+			struct x25_sock *x25 = x25_sk(sk);
 
 			x25_stop_timer(sk);
 			x25->condition = 0x00;
@@ -322,7 +322,7 @@ static int x25_state4_machine(struct soc
 /* Higher level upcall for a LAPB frame */
 int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	int queued = 0, frametype, ns, nr, q, d, m;
 
 	if (x25->state == X25_STATE_0)
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -54,7 +54,7 @@ int x25_output(struct sock *sk, struct s
 	unsigned char header[X25_EXT_MIN_LEN];
 	int err, frontlen, len;
 	int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	int header_len = x25->neighbour->extended ? X25_EXT_MIN_LEN :
 						    X25_STD_MIN_LEN;
 	int max_len = x25_pacsize_to_bytes(x25->facilities.pacsize_out);
@@ -116,7 +116,7 @@ int x25_output(struct sock *sk, struct s
  */
 static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (!skb)
 		return;
@@ -139,7 +139,7 @@ void x25_kick(struct sock *sk)
 	struct sk_buff *skb, *skbn;
 	unsigned short start, end;
 	int modulus;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (x25->state != X25_STATE_3)
 		return;
@@ -212,7 +212,7 @@ void x25_kick(struct sock *sk)
 
 void x25_enquiry_response(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (x25->condition & X25_COND_OWN_RX_BUSY)
 		x25_write_internal(sk, X25_RNR);
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -134,7 +134,7 @@ static void x25_seq_socket_stop(struct s
 static int x25_seq_socket_show(struct seq_file *seq, void *v)
 {
 	struct sock *s;
-	struct x25_opt *x25;
+	struct x25_sock *x25;
 	struct net_device *dev;
 	const char *devname;
 
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -33,7 +33,7 @@
  */
 void x25_clear_queues(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	skb_queue_purge(&sk->sk_write_queue);
 	skb_queue_purge(&x25->ack_queue);
@@ -51,7 +51,7 @@ void x25_clear_queues(struct sock *sk)
 void x25_frames_acked(struct sock *sk, unsigned short nr)
 {
 	struct sk_buff *skb;
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
 
 	/*
@@ -89,7 +89,7 @@ void x25_requeue_frames(struct sock *sk)
  */
 int x25_validate_nr(struct sock *sk, unsigned short nr)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	unsigned short vc = x25->va;
 	int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
 
@@ -108,7 +108,7 @@ int x25_validate_nr(struct sock *sk, uns
  */
 void x25_write_internal(struct sock *sk, int frametype)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	unsigned char  facilities[X25_MAX_FAC_LEN];
@@ -248,7 +248,7 @@ void x25_write_internal(struct sock *sk,
 int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
 	       int *d, int *m)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 	unsigned char *frame = skb->data;
 
 	*ns = *nr = *q = *d = *m = 0;
@@ -315,7 +315,7 @@ int x25_decode(struct sock *sk, struct s
 void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
 		    unsigned char diagnostic)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	x25_clear_queues(sk);
 	x25_stop_timer(sk);
@@ -342,7 +342,7 @@ void x25_disconnect(struct sock *sk, int
  */
 void x25_check_rbuf(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) &&
 	    (x25->condition & X25_COND_OWN_RX_BUSY)) {
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c
--- a/net/x25/x25_timer.c
+++ b/net/x25/x25_timer.c
@@ -31,7 +31,7 @@ static void x25_timer_expiry(unsigned lo
 
 void x25_init_timers(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	init_timer(&x25->timer);
 	x25->timer.data     = (unsigned long)sk;
@@ -54,28 +54,28 @@ void x25_stop_heartbeat(struct sock *sk)
 
 void x25_start_t2timer(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	mod_timer(&x25->timer, jiffies + x25->t2);
 }
 
 void x25_start_t21timer(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	mod_timer(&x25->timer, jiffies + x25->t21);
 }
 
 void x25_start_t22timer(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	mod_timer(&x25->timer, jiffies + x25->t22);
 }
 
 void x25_start_t23timer(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	mod_timer(&x25->timer, jiffies + x25->t23);
 }
@@ -87,7 +87,7 @@ void x25_stop_timer(struct sock *sk)
 
 unsigned long x25_display_timer(struct sock *sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	if (!timer_pending(&x25->timer))
 		return 0;
@@ -138,7 +138,7 @@ unlock:
  */
 static inline void x25_do_timer_expiry(struct sock * sk)
 {
-	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_sock *x25 = x25_sk(sk);
 
 	switch (x25->state) {
 
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -698,7 +698,7 @@ int skb_cow_data(struct sk_buff *skb, in
 				return -ENOMEM;
 
 			if (skb1->sk)
-				skb_set_owner_w(skb, skb1->sk);
+				skb_set_owner_w(skb2, skb1->sk);
 
 			/* Looking around. Are we still alive?
 			 * OK, link new skb, drop old one */
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -13,6 +13,7 @@
  * 	
  */
 
+#include <asm/bug.h>
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -300,19 +301,23 @@ static void xfrm_policy_gc_task(void *da
 
 static void xfrm_policy_kill(struct xfrm_policy *policy)
 {
-	write_lock_bh(&policy->lock);
-	if (policy->dead)
-		goto out;
+	int dead;
 
+	write_lock_bh(&policy->lock);
+	dead = policy->dead;
 	policy->dead = 1;
+	write_unlock_bh(&policy->lock);
+
+	if (unlikely(dead)) {
+		WARN_ON(1);
+		return;
+	}
 
 	spin_lock(&xfrm_policy_gc_lock);
 	list_add(&policy->list, &xfrm_policy_gc_list);
 	spin_unlock(&xfrm_policy_gc_lock);
-	schedule_work(&xfrm_policy_gc_work);
 
-out:
-	write_unlock_bh(&policy->lock);
+	schedule_work(&xfrm_policy_gc_work);
 }
 
 /* Generate new index... KAME seems to generate them ordered by cost
@@ -1015,46 +1020,23 @@ static struct dst_entry *xfrm_dst_check(
 	if (!stale_bundle(dst))
 		return dst;
 
-	dst_release(dst);
 	return NULL;
 }
 
 static int stale_bundle(struct dst_entry *dst)
 {
-	struct dst_entry *child = dst;
-
-	while (child) {
-		if (child->obsolete > 0 ||
-		    (child->dev && !netif_running(child->dev)) ||
-		    (child->xfrm && child->xfrm->km.state != XFRM_STATE_VALID)) {
-			return 1;
-		}
-		child = child->child;
-	}
-
-	return 0;
-}
-
-static void xfrm_dst_destroy(struct dst_entry *dst)
-{
-	if (!dst->xfrm)
-		return;
-	xfrm_state_put(dst->xfrm);
-	dst->xfrm = NULL;
+	return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC);
 }
 
-static void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
-			    int unregister)
+void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
 {
-	if (!unregister)
-		return;
-
 	while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
 		dst->dev = &loopback_dev;
 		dev_hold(&loopback_dev);
 		dev_put(dev);
 	}
 }
+EXPORT_SYMBOL(xfrm_dst_ifdown);
 
 static void xfrm_link_failure(struct sk_buff *skb)
 {
@@ -1121,6 +1103,94 @@ int xfrm_flush_bundles(void)
 	return 0;
 }
 
+void xfrm_init_pmtu(struct dst_entry *dst)
+{
+	do {
+		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+		u32 pmtu, route_mtu_cached;
+
+		pmtu = dst_mtu(dst->child);
+		xdst->child_mtu_cached = pmtu;
+
+		pmtu = xfrm_state_mtu(dst->xfrm, pmtu);
+
+		route_mtu_cached = dst_mtu(xdst->route);
+		xdst->route_mtu_cached = route_mtu_cached;
+
+		if (pmtu > route_mtu_cached)
+			pmtu = route_mtu_cached;
+
+		dst->metrics[RTAX_MTU-1] = pmtu;
+	} while ((dst = dst->next));
+}
+
+EXPORT_SYMBOL(xfrm_init_pmtu);
+
+/* Check that the bundle accepts the flow and its components are
+ * still valid.
+ */
+
+int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family)
+{
+	struct dst_entry *dst = &first->u.dst;
+	struct xfrm_dst *last;
+	u32 mtu;
+
+	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
+	    (dst->dev && !netif_running(dst->dev)))
+		return 0;
+
+	last = NULL;
+
+	do {
+		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+
+		if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
+			return 0;
+		if (dst->xfrm->km.state != XFRM_STATE_VALID)
+			return 0;
+
+		mtu = dst_mtu(dst->child);
+		if (xdst->child_mtu_cached != mtu) {
+			last = xdst;
+			xdst->child_mtu_cached = mtu;
+		}
+
+		if (!dst_check(xdst->route, xdst->route_cookie))
+			return 0;
+		mtu = dst_mtu(xdst->route);
+		if (xdst->route_mtu_cached != mtu) {
+			last = xdst;
+			xdst->route_mtu_cached = mtu;
+		}
+
+		dst = dst->child;
+	} while (dst->xfrm);
+
+	if (likely(!last))
+		return 1;
+
+	mtu = last->child_mtu_cached;
+	for (;;) {
+		dst = &last->u.dst;
+
+		mtu = xfrm_state_mtu(dst->xfrm, mtu);
+		if (mtu > last->route_mtu_cached)
+			mtu = last->route_mtu_cached;
+		dst->metrics[RTAX_MTU-1] = mtu;
+
+		if (last == first)
+			break;
+
+		last = last->u.next;
+		last->child_mtu_cached = mtu;
+	}
+
+	return 1;
+}
+
+EXPORT_SYMBOL(xfrm_bundle_ok);
+
 /* Well... that's _TASK_. We need to scan through transformation
  * list and figure out what mss tcp should generate in order to
  * final datagram fit to mtu. Mama mia... :-)
@@ -1177,10 +1247,6 @@ int xfrm_policy_register_afinfo(struct x
 			dst_ops->kmem_cachep = xfrm_dst_cache;
 		if (likely(dst_ops->check == NULL))
 			dst_ops->check = xfrm_dst_check;
-		if (likely(dst_ops->destroy == NULL))
-			dst_ops->destroy = xfrm_dst_destroy;
-		if (likely(dst_ops->ifdown == NULL))
-			dst_ops->ifdown = xfrm_dst_ifdown;
 		if (likely(dst_ops->negative_advice == NULL))
 			dst_ops->negative_advice = xfrm_negative_advice;
 		if (likely(dst_ops->link_failure == NULL))
@@ -1212,8 +1278,6 @@ int xfrm_policy_unregister_afinfo(struct
 			xfrm_policy_afinfo[afinfo->family] = NULL;
 			dst_ops->kmem_cachep = NULL;
 			dst_ops->check = NULL;
-			dst_ops->destroy = NULL;
-			dst_ops->ifdown = NULL;
 			dst_ops->negative_advice = NULL;
 			dst_ops->link_failure = NULL;
 			dst_ops->get_mss = NULL;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -48,6 +48,8 @@ static struct work_struct xfrm_state_gc_
 static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
 static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 
+static int xfrm_state_gc_flush_bundles;
+
 static void __xfrm_state_delete(struct xfrm_state *x);
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
@@ -81,6 +83,11 @@ static void xfrm_state_gc_task(void *dat
 	struct list_head *entry, *tmp;
 	struct list_head gc_list = LIST_HEAD_INIT(gc_list);
 
+	if (xfrm_state_gc_flush_bundles) {
+		xfrm_state_gc_flush_bundles = 0;
+		xfrm_flush_bundles();
+	}
+
 	spin_lock_bh(&xfrm_state_gc_lock);
 	list_splice_init(&xfrm_state_gc_list, &gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
@@ -228,8 +235,10 @@ static void __xfrm_state_delete(struct x
 		 * our caller holds.  A larger value means that
 		 * there are DSTs attached to this xfrm_state.
 		 */
-		if (atomic_read(&x->refcnt) > 2)
-			xfrm_flush_bundles();
+		if (atomic_read(&x->refcnt) > 2) {
+			xfrm_state_gc_flush_bundles = 1;
+			schedule_work(&xfrm_state_gc_work);
+		}
 
 		/* All xfrm_state objects are created by xfrm_state_alloc.
 		 * The xfrm_state_alloc call gives a reference, and that
@@ -295,10 +304,17 @@ xfrm_state_find(xfrm_address_t *daddr, x
 		unsigned short family)
 {
 	unsigned h = xfrm_dst_hash(daddr, family);
-	struct xfrm_state *x;
+	struct xfrm_state *x, *x0;
 	int acquire_in_progress = 0;
 	int error = 0;
 	struct xfrm_state *best = NULL;
+	struct xfrm_state_afinfo *afinfo;
+	
+	afinfo = xfrm_state_get_afinfo(family);
+	if (afinfo == NULL) {
+		*err = -EAFNOSUPPORT;
+		return NULL;
+	}
 
 	spin_lock_bh(&xfrm_state_lock);
 	list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
@@ -306,7 +322,8 @@ xfrm_state_find(xfrm_address_t *daddr, x
 		    x->props.reqid == tmpl->reqid &&
 		    xfrm_state_addr_check(x, daddr, saddr, family) &&
 		    tmpl->mode == x->props.mode &&
-		    tmpl->id.proto == x->id.proto) {
+		    tmpl->id.proto == x->id.proto &&
+		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
 			/* Resolution logic:
 			   1. There is a valid state with matching selector.
 			      Done.
@@ -333,14 +350,25 @@ xfrm_state_find(xfrm_address_t *daddr, x
 			} else if (x->km.state == XFRM_STATE_ERROR ||
 				   x->km.state == XFRM_STATE_EXPIRED) {
 				if (xfrm_selector_match(&x->sel, fl, family))
-					error = 1;
+					error = -ESRCH;
 			}
 		}
 	}
 
 	x = best;
-	if (!x && !error && !acquire_in_progress &&
-	    ((x = xfrm_state_alloc()) != NULL)) {
+	if (!x && !error && !acquire_in_progress) {
+		if (tmpl->id.spi &&
+		    (x0 = afinfo->state_lookup(daddr, tmpl->id.spi,
+		                               tmpl->id.proto)) != NULL) {
+			xfrm_state_put(x0);
+			error = -EEXIST;
+			goto out;
+		}
+		x = xfrm_state_alloc();
+		if (x == NULL) {
+			error = -ENOMEM;
+			goto out;
+		}
 		/* Initialize temporary selector matching only
 		 * to current session. */
 		xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
@@ -362,15 +390,16 @@ xfrm_state_find(xfrm_address_t *daddr, x
 			x->km.state = XFRM_STATE_DEAD;
 			xfrm_state_put(x);
 			x = NULL;
-			error = 1;
+			error = -ESRCH;
 		}
 	}
+out:
 	if (x)
 		xfrm_state_hold(x);
 	else
-		*err = acquire_in_progress ? -EAGAIN :
-			(error ? -ESRCH : -ENOMEM);
+		*err = acquire_in_progress ? -EAGAIN : error;
 	spin_unlock_bh(&xfrm_state_lock);
+	xfrm_state_put_afinfo(afinfo);
 	return x;
 }
 
@@ -609,7 +638,7 @@ static struct xfrm_state *__xfrm_find_ac
 
 	for (i = 0; i < XFRM_DST_HSIZE; i++) {
 		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
-			if (x->km.seq == seq) {
+			if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) {
 				xfrm_state_hold(x);
 				return x;
 			}
@@ -966,6 +995,36 @@ void xfrm_state_delete_tunnel(struct xfr
 }
 EXPORT_SYMBOL(xfrm_state_delete_tunnel);
 
+int xfrm_state_mtu(struct xfrm_state *x, int mtu)
+{
+	int res = mtu;
+
+	res -= x->props.header_len;
+
+	for (;;) {
+		int m = res;
+
+		if (m < 68)
+			return 68;
+
+		spin_lock_bh(&x->lock);
+		if (x->km.state == XFRM_STATE_VALID &&
+		    x->type && x->type->get_max_size)
+			m = x->type->get_max_size(x, m);
+		else
+			m += x->props.header_len;
+		spin_unlock_bh(&x->lock);
+
+		if (m <= mtu)
+			break;
+		res -= (m - mtu);
+	}
+
+	return res;
+}
+
+EXPORT_SYMBOL(xfrm_state_mtu);
+ 
 void __init xfrm_state_init(void)
 {
 	int i;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -34,14 +34,21 @@ static int verify_one_alg(struct rtattr 
 {
 	struct rtattr *rt = xfrma[type - 1];
 	struct xfrm_algo *algp;
+	int len;
 
 	if (!rt)
 		return 0;
 
-	if ((rt->rta_len - sizeof(*rt)) < sizeof(*algp))
+	len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp);
+	if (len < 0)
 		return -EINVAL;
 
 	algp = RTA_DATA(rt);
+
+	len -= (algp->alg_key_len + 7U) / 8; 
+	if (len < 0)
+		return -EINVAL;
+
 	switch (type) {
 	case XFRMA_ALG_AUTH:
 		if (!algp->alg_key_len &&
@@ -162,6 +169,7 @@ static int attach_one_algo(struct xfrm_a
 	struct rtattr *rta = u_arg;
 	struct xfrm_algo *p, *ualg;
 	struct xfrm_algo_desc *algo;
+	int len;
 
 	if (!rta)
 		return 0;
@@ -173,11 +181,12 @@ static int attach_one_algo(struct xfrm_a
 		return -ENOSYS;
 	*props = algo->desc.sadb_alg_id;
 
-	p = kmalloc(sizeof(*ualg) + ualg->alg_key_len, GFP_KERNEL);
+	len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8;
+	p = kmalloc(len, GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
-	memcpy(p, ualg, sizeof(*ualg) + ualg->alg_key_len);
+	memcpy(p, ualg, len);
 	*algpp = p;
 	return 0;
 }
@@ -855,47 +864,44 @@ static int xfrm_flush_policy(struct sk_b
 	return 0;
 }
 
-static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = {
-	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* NEW SA */
-	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* DEL SA */
-	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* GET SA */
-	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* NEW POLICY */
-	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* DEL POLICY */
-	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* GET POLICY */
-	NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)),	/* ALLOC SPI */
-	NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)),	/* ACQUIRE */
-	NLMSG_LENGTH(sizeof(struct xfrm_user_expire)),	/* EXPIRE */
-	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */
-	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* UPD SA */
-	NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */
-	NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)),	/* FLUSH SA */
-	NLMSG_LENGTH(0),				/* FLUSH POLICY */
+#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
+
+static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
+	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
+	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
+	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
+	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
+	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
+	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
+	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info),
+	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
+	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
+	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
+	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
+	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
+	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
+	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
 };
 
+#undef XMSGSIZE
+
 static struct xfrm_link {
 	int (*doit)(struct sk_buff *, struct nlmsghdr *, void **);
 	int (*dump)(struct sk_buff *, struct netlink_callback *);
-} xfrm_dispatch[] = {
-	{	.doit	=	xfrm_add_sa, 		},
-	{	.doit	=	xfrm_del_sa, 		},
-	{
-		.doit	=	xfrm_get_sa,
-		.dump	=	xfrm_dump_sa,
-	},
-	{	.doit	=	xfrm_add_policy 	},
-	{	.doit	=	xfrm_get_policy 	},
-	{
-		.doit	=	xfrm_get_policy,
-		.dump	=	xfrm_dump_policy,
-	},
-	{	.doit	=	xfrm_alloc_userspi	},
-	{},
-	{},
-	{	.doit	=	xfrm_add_policy 	},
-	{	.doit	=	xfrm_add_sa, 		},
-	{},
-	{	.doit	=	xfrm_flush_sa		},
-	{	.doit	=	xfrm_flush_policy	},
+} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
+	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
+	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },
+	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
+						   .dump = xfrm_dump_sa       },
+	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
+	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    },
+	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
+						   .dump = xfrm_dump_policy   },
+	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
+	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
+	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
+	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
+	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
 };
 
 static int xfrm_done(struct netlink_callback *cb)
@@ -931,7 +937,9 @@ static int xfrm_user_rcv_msg(struct sk_b
 		return -1;
 	}
 
-	if ((type == 2 || type == 5) && (nlh->nlmsg_flags & NLM_F_DUMP)) {
+	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
+	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
+	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
 		u32 rlen;
 
 		if (link->dump == NULL)
@@ -1009,18 +1017,26 @@ static int xfrm_user_rcv_skb(struct sk_b
 
 static void xfrm_netlink_rcv(struct sock *sk, int len)
 {
+	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+
 	do {
 		struct sk_buff *skb;
 
 		down(&xfrm_cfg_sem);
 
-		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+		if (qlen > skb_queue_len(&sk->sk_receive_queue))
+			qlen = skb_queue_len(&sk->sk_receive_queue);
+
+		for (; qlen; qlen--) {
+			skb = skb_dequeue(&sk->sk_receive_queue);
 			if (xfrm_user_rcv_skb(skb)) {
 				if (skb->len)
 					skb_queue_head(&sk->sk_receive_queue,
 						       skb);
-				else
+				else {
 					kfree_skb(skb);
+					qlen--;
+				}
 				break;
 			}
 			kfree_skb(skb);
@@ -1028,7 +1044,7 @@ static void xfrm_netlink_rcv(struct sock
 
 		up(&xfrm_cfg_sem);
 
-	} while (xfrm_nl && xfrm_nl->sk_receive_queue.qlen);
+	} while (qlen);
 }
 
 static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -183,15 +183,24 @@ cmd_gzip = gzip -f -9 < $< > $@
 # Generic stuff
 # ===========================================================================
 
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result in empty string if equal
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
+
+endif
+
+# echo command. Short version is $(quiet) equals quiet, otherwise full command
+echo-cmd = $(if $($(quiet)cmd_$(1)), \
+	echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';)
+
 # function to only execute the passed command if necessary
 # >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
 # note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
-
-if_changed = $(if $(strip $? \
-		          $(filter-out $(cmd_$(1)),$(cmd_$@))\
-			  $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+# 
+if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
 	@set -e; \
-	$(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';) \
+	$(echo-cmd) \
 	$(cmd_$(1)); \
 	echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
 
@@ -200,10 +209,9 @@ if_changed = $(if $(strip $? \
 # file
 
 if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
-		          $(filter-out $(cmd_$(1)),$(cmd_$@))\
-			  $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+	$(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),                  \
 	@set -e; \
-	$(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';) \
+	$(echo-cmd) \
 	$(cmd_$(1)); \
 	scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
@@ -213,9 +221,7 @@ if_changed_dep = $(if $(strip $? $(filte
 # will check if $(cmd_foo) changed, or any of the prequisites changed,
 # and if so will execute $(rule_foo)
 
-if_changed_rule = $(if $(strip $? \
-		               $(filter-out $(cmd_$(1)),$(cmd_$@))\
-			       $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
 			@set -e; \
 			$(rule_$(1)))
 
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -21,8 +21,9 @@ quiet_cmd_modules_install = INSTALL $@
 
 # Modules built outside the kernel source tree go into extra by default
 INSTALL_MOD_DIR ?= extra
+ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(KBUILD_EXTMOD),,$(@D))
 
-modinst_dir = $(MODLIB)/$(if $(filter ../% /%,$@),$(INSTALL_MOD_DIR)/,kernel/$(@D))
+modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
 
 $(modules):
-	$(call cmd,modules_install,$(modinst_dir))
+	$(call cmd,modules_install,$(MODLIB)/$(modinst_dir))
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -9,6 +9,7 @@
 #	Mips port by Juan Quintela <quintela@mandrakesoft.com>
 #	IA64 port via Andreas Dilger
 #	Arm port by Holger Schurig
+#	sh64 port by Paul Mundt
 #	Random bits by Matt Mackall <mpm@selenic.com>
 #	M68k port by Geert Uytterhoeven and Andreas Schwab
 #
@@ -64,6 +65,12 @@ my (@stack, $re, $x, $xs);
 	} elsif ($arch =~ /^s390x?$/) {
 		#   11160:       a7 fb ff 60             aghi   %r15,-160
 		$re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} elsif ($arch =~ /^sh64$/) {
+		#XXX: we only check for the immediate case presently,
+		#     though we will want to check for the movi/sub
+		#     pair for larger users. -- PFM.
+		#a00048e0:       d4fc40f0        addi.l  r15,-240,r15
+		$re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
 	} else {
 		print("wrong or unknown architecture\n");
 		exit
@@ -72,8 +79,8 @@ my (@stack, $re, $x, $xs);
 
 sub bysize($) {
 	my ($asize, $bsize);
-	($asize = $a) =~ s/.*	+(.*)$/$1/;
-	($bsize = $b) =~ s/.*	+(.*)$/$1/;
+	($asize = $a) =~ s/.*:	*(.*)$/$1/;
+	($bsize = $b) =~ s/.*:	*(.*)$/$1/;
 	$bsize <=> $asize
 }
 
@@ -90,11 +97,12 @@ while (my $line = <STDIN>) {
 		my $size = $1;
 		$size = hex($size) if ($size =~ /^0x/);
 
-		if ($size > 0x80000000) {
+		if ($size > 0xf0000000) {
 			$size = - $size;
 			$size += 0x80000000;
 			$size += 0x80000000;
 		}
+		next if ($size > 0x10000000);
 
 		next if $line !~ m/^($xs*)/;
 		my $addr = $1;
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -25,7 +25,6 @@
 #define MODUTILS_GENKSYMS_H 1
 
 #include <stdio.h>
-#include <assert.h>
 
 
 enum symbol_type
@@ -89,8 +88,17 @@ void error_with_pos(const char *, ...);
 
 #define MODUTILS_VERSION "<in-kernel>"
 
-#define xmalloc(size) ({ void *__ptr = malloc(size); assert(__ptr || size == 0); __ptr; })
-#define xstrdup(str)  ({ char *__str = strdup(str); assert(__str); __str; })
-
+#define xmalloc(size) ({ void *__ptr = malloc(size);		\
+	if(!__ptr && size != 0) {				\
+		fprintf(stderr, "out of memory\n");		\
+		exit(1);					\
+	}							\
+	__ptr; })
+#define xstrdup(str)  ({ char *__str = strdup(str);		\
+	if (!__str) {						\
+		fprintf(stderr, "out of memory\n");		\
+		exit(1);					\
+	}							\
+	__str; })
 
 #endif /* genksyms.h */
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -67,8 +67,9 @@ struct sym_entry {
 
 static struct sym_entry *table;
 static int size, cnt;
-static unsigned long long _stext, _etext, _sinittext, _einittext;
+static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
 static int all_symbols = 0;
+static char symbol_prefix_char = '\0';
 
 struct token {
 	unsigned char data[MAX_TOK_SIZE];
@@ -93,7 +94,7 @@ unsigned char best_table_len[256];
 static void
 usage(void)
 {
-	fprintf(stderr, "Usage: kallsyms [--all-symbols] < in.map > out.S\n");
+	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
 	exit(1);
 }
 
@@ -112,6 +113,7 @@ static int
 read_symbol(FILE *in, struct sym_entry *s)
 {
 	char str[500];
+	char *sym;
 	int rc;
 
 	rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
@@ -123,27 +125,36 @@ read_symbol(FILE *in, struct sym_entry *
 		return -1;
 	}
 
+	sym = str;
+	/* skip prefix char */
+	if (symbol_prefix_char && str[0] == symbol_prefix_char)
+		sym++;
+
 	/* Ignore most absolute/undefined (?) symbols. */
-	if (strcmp(str, "_stext") == 0)
+	if (strcmp(sym, "_stext") == 0)
 		_stext = s->addr;
-	else if (strcmp(str, "_etext") == 0)
+	else if (strcmp(sym, "_etext") == 0)
 		_etext = s->addr;
-	else if (strcmp(str, "_sinittext") == 0)
+	else if (strcmp(sym, "_sinittext") == 0)
 		_sinittext = s->addr;
-	else if (strcmp(str, "_einittext") == 0)
+	else if (strcmp(sym, "_einittext") == 0)
 		_einittext = s->addr;
+	else if (strcmp(sym, "_sextratext") == 0)
+		_sextratext = s->addr;
+	else if (strcmp(sym, "_eextratext") == 0)
+		_eextratext = s->addr;
 	else if (toupper(s->type) == 'A')
 	{
 		/* Keep these useful absolute symbols */
-		if (strcmp(str, "__kernel_syscall_via_break") &&
-		    strcmp(str, "__kernel_syscall_via_epc") &&
-		    strcmp(str, "__kernel_sigtramp") &&
-		    strcmp(str, "__gp"))
+		if (strcmp(sym, "__kernel_syscall_via_break") &&
+		    strcmp(sym, "__kernel_syscall_via_epc") &&
+		    strcmp(sym, "__kernel_sigtramp") &&
+		    strcmp(sym, "__gp"))
 			return -1;
 
 	}
 	else if (toupper(s->type) == 'U' ||
-		 is_arm_mapping_symbol(str))
+		 is_arm_mapping_symbol(sym))
 		return -1;
 
 	/* include the type field in the symbol name, so that it gets
@@ -177,30 +188,37 @@ symbol_valid(struct sym_entry *s)
 		"_SDA2_BASE_",		/* ppc */
 		NULL };
 	int i;
+	int offset = 1;
+
+	/* skip prefix char */
+	if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
+		offset++;
 
 	/* if --all-symbols is not specified, then symbols outside the text
 	 * and inittext sections are discarded */
 	if (!all_symbols) {
 		if ((s->addr < _stext || s->addr > _etext)
-		    && (s->addr < _sinittext || s->addr > _einittext))
+		    && (s->addr < _sinittext || s->addr > _einittext)
+		    && (s->addr < _sextratext || s->addr > _eextratext))
 			return 0;
 		/* Corner case.  Discard any symbols with the same value as
-		 * _etext or _einittext, they can move between pass 1 and 2
-		 * when the kallsyms data is added.  If these symbols move then
-		 * they may get dropped in pass 2, which breaks the kallsyms
-		 * rules.
+		 * _etext _einittext or _eextratext; they can move between pass
+		 * 1 and 2 when the kallsyms data are added.  If these symbols
+		 * move then they may get dropped in pass 2, which breaks the
+		 * kallsyms rules.
 		 */
-		if ((s->addr == _etext && strcmp(s->sym + 1, "_etext")) ||
-		    (s->addr == _einittext && strcmp(s->sym + 1, "_einittext")))
+		if ((s->addr == _etext && strcmp(s->sym + offset, "_etext")) ||
+		    (s->addr == _einittext && strcmp(s->sym + offset, "_einittext")) ||
+		    (s->addr == _eextratext && strcmp(s->sym + offset, "_eextratext")))
 			return 0;
 	}
 
 	/* Exclude symbols which vary between passes. */
-	if (strstr(s->sym + 1, "_compiled."))
+	if (strstr(s->sym + offset, "_compiled."))
 		return 0;
 
 	for (i = 0; special_symbols[i]; i++)
-		if( strcmp(s->sym + 1, special_symbols[i]) == 0 )
+		if( strcmp(s->sym + offset, special_symbols[i]) == 0 )
 			return 0;
 
 	return 1;
@@ -225,9 +243,15 @@ read_map(FILE *in)
 
 static void output_label(char *label)
 {
-	printf(".globl %s\n",label);
+	if (symbol_prefix_char)
+		printf(".globl %c%s\n", symbol_prefix_char, label);
+	else
+		printf(".globl %s\n", label);
 	printf("\tALGN\n");
-	printf("%s:\n",label);
+	if (symbol_prefix_char)
+		printf("%c%s:\n", symbol_prefix_char, label);
+	else
+		printf("%s:\n", label);
 }
 
 /* uncompress a compressed symbol. When this function is called, the best table
@@ -665,6 +689,13 @@ static void optimize_token_table(void)
 
 	insert_real_symbols_in_table();
 
+	/* When valid symbol is not registered, exit to error */
+	if (good_head.left == good_head.right &&
+	    bad_head.left == bad_head.right) {
+		fprintf(stderr, "No valid symbol.\n");
+		exit(1);
+	}
+
 	optimize_result();
 }
 
@@ -672,9 +703,21 @@ static void optimize_token_table(void)
 int
 main(int argc, char **argv)
 {
-	if (argc == 2 && strcmp(argv[1], "--all-symbols") == 0)
-		all_symbols = 1;
-	else if (argc != 1)
+	if (argc >= 2) {
+		int i;
+		for (i = 1; i < argc; i++) {
+			if(strcmp(argv[i], "--all-symbols") == 0)
+				all_symbols = 1;
+			else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
+				char *p = &argv[i][16];
+				/* skip quote */
+				if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
+					p++;
+				symbol_prefix_char = *p;
+			} else
+				usage();
+		}
+	} else if (argc != 1)
 		usage();
 
 	read_map(stdin);
@@ -683,4 +726,3 @@ main(int argc, char **argv)
 
 	return 0;
 }
-
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -2,7 +2,7 @@
 # Kernel configuration targets
 # These targets are used from top-level makefile
 
-.PHONY: oldconfig xconfig gconfig menuconfig config silentoldconfig
+.PHONY: oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
 
 xconfig: $(obj)/qconf
 	$< arch/$(ARCH)/Kconfig
@@ -23,6 +23,13 @@ oldconfig: $(obj)/conf
 silentoldconfig: $(obj)/conf
 	$< -s arch/$(ARCH)/Kconfig
 
+update-po-config: $(obj)/kxgettext
+	xgettext --default-domain=linux \
+          --add-comments --keyword=_ --keyword=N_ \
+          --files-from=scripts/kconfig/POTFILES.in \
+	-o scripts/kconfig/linux.pot
+	scripts/kconfig/kxgettext arch/$(ARCH)/Kconfig >> scripts/kconfig/linux.pot
+
 .PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig
 
 randconfig: $(obj)/conf
@@ -50,10 +57,12 @@ endif
 
 # Help text used by make help
 help:
-	@echo  '  oldconfig	  - Update current config utilising a line-oriented program'
+	@echo  '  config	  - Update current config utilising a line-oriented program'
 	@echo  '  menuconfig	  - Update current config utilising a menu based program'
 	@echo  '  xconfig	  - Update current config utilising a QT based front-end'
 	@echo  '  gconfig	  - Update current config utilising a GTK based front-end'
+	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
+	@echo  '  randconfig	  - New config with random answer to all options'
 	@echo  '  defconfig	  - New config with default answer to all options'
 	@echo  '  allmodconfig	  - New config selecting modules when possible'
 	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
@@ -70,9 +79,10 @@ help:
 #         Based on GTK which needs to be installed to compile it
 # object files used by all kconfig flavours
 
-hostprogs-y	:= conf mconf qconf gconf
+hostprogs-y	:= conf mconf qconf gconf kxgettext
 conf-objs	:= conf.o  zconf.tab.o
 mconf-objs	:= mconf.o zconf.tab.o
+kxgettext-objs	:= kxgettext.o zconf.tab.o
 
 ifeq ($(MAKECMDGOALS),xconfig)
 	qconf-target := 1
@@ -105,7 +115,11 @@ HOSTLOADLIBES_gconf	= `pkg-config gtk+-2
 HOSTCFLAGS_gconf.o	= `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --cflags` \
                           -D LKC_DIRECT_LINK
 
-$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o: $(obj)/zconf.tab.h
+$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o $(obj)/kxgettext: $(obj)/zconf.tab.h
+
+$(obj)/zconf.tab.h: $(src)/zconf.tab.h_shipped
+$(obj)/zconf.tab.c: $(src)/zconf.tab.c_shipped
+$(obj)/lex.zconf.c: $(src)/lex.zconf.c_shipped
 
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 
diff --git a/scripts/kconfig/POTFILES.in b/scripts/kconfig/POTFILES.in
new file mode 100644
--- /dev/null
+++ b/scripts/kconfig/POTFILES.in
@@ -0,0 +1,5 @@
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/qconf.cc
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -34,7 +34,7 @@ static int conf_cnt;
 static signed char line[128];
 static struct menu *rootEntry;
 
-static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
+static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
 
 static void strip(signed char *str)
 {
@@ -56,9 +56,9 @@ static void strip(signed char *str)
 static void check_stdin(void)
 {
 	if (!valid_stdin && input_mode == ask_silent) {
-		printf("aborted!\n\n");
-		printf("Console input/output is redirected. ");
-		printf("Run 'make oldconfig' to update configuration.\n\n");
+		printf(_("aborted!\n\n"));
+		printf(_("Console input/output is redirected. "));
+		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
 		exit(1);
 	}
 }
@@ -470,7 +470,7 @@ static void check_conf(struct menu *menu
 	if (sym) {
 		if (sym_is_changable(sym) && !sym_has_value(sym)) {
 			if (!conf_cnt++)
-				printf("*\n* Restart config...\n*\n");
+				printf(_("*\n* Restart config...\n*\n"));
 			rootEntry = menu_get_parent_menu(menu);
 			conf(rootEntry);
 		}
@@ -504,7 +504,7 @@ int main(int ac, char **av)
 			input_mode = set_default;
 			defconfig_file = av[i++];
 			if (!defconfig_file) {
-				printf("%s: No default config file specified\n",
+				printf(_("%s: No default config file specified\n"),
 					av[0]);
 				exit(1);
 			}
@@ -530,7 +530,7 @@ int main(int ac, char **av)
 	}
   	name = av[i];
 	if (!name) {
-		printf("%s: Kconfig file missing\n", av[0]);
+		printf(_("%s: Kconfig file missing\n"), av[0]);
 	}
 	conf_parse(name);
 	//zconfdump(stdout);
@@ -547,12 +547,12 @@ int main(int ac, char **av)
 		break;
 	case ask_silent:
 		if (stat(".config", &tmpstat)) {
-			printf("***\n"
+			printf(_("***\n"
 				"*** You have not yet configured your kernel!\n"
 				"***\n"
 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 				"*** \"make menuconfig\" or \"make xconfig\").\n"
-				"***\n");
+				"***\n"));
 			exit(1);
 		}
 	case ask_all:
@@ -576,7 +576,7 @@ int main(int ac, char **av)
 		check_conf(&rootmenu);
 	} while (conf_cnt);
 	if (conf_write(NULL)) {
-		fprintf(stderr, "\n*** Error during writing of the kernel configuration.\n\n");
+		fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
 		return 1;
 	}
 	return 0;
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -88,9 +88,9 @@ int conf_read(const char *name)
 			name = conf_expand_value(name);
 			in = zconf_fopen(name);
 			if (in) {
-				printf("#\n"
-				       "# using defaults found in %s\n"
-				       "#\n", name);
+				printf(_("#\n"
+				         "# using defaults found in %s\n"
+				         "#\n"), name);
 				break;
 			}
 		}
@@ -312,11 +312,11 @@ int conf_write(const char *name)
 	if (env && *env)
 		use_timestamp = 0;
 
-	fprintf(out, "#\n"
-		     "# Automatically generated make config: don't edit\n"
-		     "# Linux kernel version: %s\n"
-		     "%s%s"
-		     "#\n",
+	fprintf(out, _("#\n"
+		       "# Automatically generated make config: don't edit\n"
+		       "# Linux kernel version: %s\n"
+		       "%s%s"
+		       "#\n"),
 		     sym_get_string_value(sym),
 		     use_timestamp ? "# " : "",
 		     use_timestamp ? ctime(&now) : "");
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -41,7 +41,7 @@ static gboolean resizeable = FALSE;
 static gboolean config_changed = FALSE;
 
 static char nohelp_text[] =
-    "Sorry, no help available for this option yet.\n";
+    N_("Sorry, no help available for this option yet.\n");
 
 GtkWidget *main_wnd = NULL;
 GtkWidget *tree1_w = NULL;	// left  frame
@@ -187,11 +187,13 @@ void init_main_window(const gchar * glad
 	GtkWidget *widget;
 	GtkTextBuffer *txtbuf;
 	char title[256];
+	GdkPixmap *pixmap;
+	GdkBitmap *mask;
 	GtkStyle *style;
 
 	xml = glade_xml_new(glade_file, "window1", NULL);
 	if (!xml)
-		g_error("GUI loading failed !\n");
+		g_error(_("GUI loading failed !\n"));
 	glade_xml_signal_autoconnect(xml);
 
 	main_wnd = glade_xml_get_widget(xml, "window1");
@@ -219,18 +221,48 @@ void init_main_window(const gchar * glad
 	style = gtk_widget_get_style(main_wnd);
 	widget = glade_xml_get_widget(xml, "toolbar1");
 
+	pixmap = gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+					      &style->bg[GTK_STATE_NORMAL],
+					      (gchar **) xpm_single_view);
+	gtk_image_set_from_pixmap(GTK_IMAGE
+				  (((GtkToolbarChild
+				     *) (g_list_nth(GTK_TOOLBAR(widget)->
+						    children,
+						    5)->data))->icon),
+				  pixmap, mask);
+	pixmap =
+	    gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+					 &style->bg[GTK_STATE_NORMAL],
+					 (gchar **) xpm_split_view);
+	gtk_image_set_from_pixmap(GTK_IMAGE
+				  (((GtkToolbarChild
+				     *) (g_list_nth(GTK_TOOLBAR(widget)->
+						    children,
+						    6)->data))->icon),
+				  pixmap, mask);
+	pixmap =
+	    gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+					 &style->bg[GTK_STATE_NORMAL],
+					 (gchar **) xpm_tree_view);
+	gtk_image_set_from_pixmap(GTK_IMAGE
+				  (((GtkToolbarChild
+				     *) (g_list_nth(GTK_TOOLBAR(widget)->
+						    children,
+						    7)->data))->icon),
+				  pixmap, mask);
+
 	switch (view_mode) {
 	case SINGLE_VIEW:
 		widget = glade_xml_get_widget(xml, "button4");
-		gtk_button_clicked(GTK_BUTTON(widget));
+		g_signal_emit_by_name(widget, "clicked");
 		break;
 	case SPLIT_VIEW:
 		widget = glade_xml_get_widget(xml, "button5");
-		gtk_button_clicked(GTK_BUTTON(widget));
+		g_signal_emit_by_name(widget, "clicked");
 		break;
 	case FULL_VIEW:
 		widget = glade_xml_get_widget(xml, "button6");
-		gtk_button_clicked(GTK_BUTTON(widget));
+		g_signal_emit_by_name(widget, "clicked");
 		break;
 	}
 
@@ -243,7 +275,7 @@ void init_main_window(const gchar * glad
 					  /*"style", PANGO_STYLE_OBLIQUE, */
 					  NULL);
 
-	sprintf(title, "Linux Kernel v%s Configuration",
+	sprintf(title, _("Linux Kernel v%s Configuration"),
 		getenv("KERNELRELEASE"));
 	gtk_window_set_title(GTK_WINDOW(main_wnd), title);
 
@@ -293,7 +325,7 @@ void init_left_tree(void)
 	
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(view, column);
-	gtk_tree_view_column_set_title(column, "Options");
+	gtk_tree_view_column_set_title(column, _("Options"));
 
 	renderer = gtk_cell_renderer_toggle_new();
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
@@ -338,7 +370,7 @@ void init_right_tree(void)
 
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(view, column);
-	gtk_tree_view_column_set_title(column, "Options");
+	gtk_tree_view_column_set_title(column, _("Options"));
 
 	renderer = gtk_cell_renderer_pixbuf_new();
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
@@ -369,7 +401,7 @@ void init_right_tree(void)
 
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_insert_column_with_attributes(view, -1,
-						    "Name", renderer,
+						    _("Name"), renderer,
 						    "text", COL_NAME,
 						    "foreground-gdk",
 						    COL_COLOR, NULL);
@@ -393,7 +425,7 @@ void init_right_tree(void)
 						    COL_COLOR, NULL);
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_insert_column_with_attributes(view, -1,
-						    "Value", renderer,
+						    _("Value"), renderer,
 						    "text", COL_VALUE,
 						    "editable",
 						    COL_EDIT,
@@ -434,15 +466,15 @@ static void text_insert_help(struct menu
 	GtkTextIter start, end;
 	const char *prompt = menu_get_prompt(menu);
 	gchar *name;
-	const char *help = nohelp_text;
+	const char *help = _(nohelp_text);
 
 	if (!menu->sym)
 		help = "";
 	else if (menu->sym->help)
-		help = menu->sym->help;
+		help = _(menu->sym->help);
 
 	if (menu->sym && menu->sym->name)
-		name = g_strdup_printf(menu->sym->name);
+		name = g_strdup_printf(_(menu->sym->name));
 	else
 		name = g_strdup("");
 
@@ -498,7 +530,7 @@ gboolean on_window1_delete_event(GtkWidg
 	if (config_changed == FALSE)
 		return FALSE;
 
-	dialog = gtk_dialog_new_with_buttons("Warning !",
+	dialog = gtk_dialog_new_with_buttons(_("Warning !"),
 					     GTK_WINDOW(main_wnd),
 					     (GtkDialogFlags)
 					     (GTK_DIALOG_MODAL |
@@ -512,7 +544,7 @@ gboolean on_window1_delete_event(GtkWidg
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
 					GTK_RESPONSE_CANCEL);
 
-	label = gtk_label_new("\nSave configuration ?\n");
+	label = gtk_label_new(_("\nSave configuration ?\n"));
 	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
 	gtk_widget_show(label);
 
@@ -572,7 +604,7 @@ load_filename(GtkFileSelection * file_se
 					     (user_data));
 
 	if (conf_read(fn))
-		text_insert_msg("Error", "Unable to load configuration !");
+		text_insert_msg(_("Error"), _("Unable to load configuration !"));
 	else
 		display_tree(&rootmenu);
 }
@@ -581,7 +613,7 @@ void on_load1_activate(GtkMenuItem * men
 {
 	GtkWidget *fs;
 
-	fs = gtk_file_selection_new("Load file...");
+	fs = gtk_file_selection_new(_("Load file..."));
 	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
 			 "clicked",
 			 G_CALLBACK(load_filename), (gpointer) fs);
@@ -600,7 +632,7 @@ void on_load1_activate(GtkMenuItem * men
 void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
 {
 	if (conf_write(NULL))
-		text_insert_msg("Error", "Unable to save configuration !");
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
 
 	config_changed = FALSE;
 }
@@ -615,7 +647,7 @@ store_filename(GtkFileSelection * file_s
 					     (user_data));
 
 	if (conf_write(fn))
-		text_insert_msg("Error", "Unable to save configuration !");
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
 
 	gtk_widget_destroy(GTK_WIDGET(user_data));
 }
@@ -624,7 +656,7 @@ void on_save_as1_activate(GtkMenuItem * 
 {
 	GtkWidget *fs;
 
-	fs = gtk_file_selection_new("Save file as...");
+	fs = gtk_file_selection_new(_("Save file as..."));
 	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
 			 "clicked",
 			 G_CALLBACK(store_filename), (gpointer) fs);
@@ -708,7 +740,7 @@ on_show_debug_info1_activate(GtkMenuItem
 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 {
 	GtkWidget *dialog;
-	const gchar *intro_text =
+	const gchar *intro_text = _(
 	    "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
 	    "for Linux.\n"
 	    "For each option, a blank box indicates the feature is disabled, a\n"
@@ -724,7 +756,7 @@ void on_introduction1_activate(GtkMenuIt
 	    "option.\n"
 	    "\n"
 	    "Toggling Show Debug Info under the Options menu will show \n"
-	    "the dependencies, which you can then match by examining other options.";
+	    "the dependencies, which you can then match by examining other options.");
 
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -741,8 +773,8 @@ void on_about1_activate(GtkMenuItem * me
 {
 	GtkWidget *dialog;
 	const gchar *about_text =
-	    "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
-	    "Based on the source code from Roman Zippel.\n";
+	    _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+	      "Based on the source code from Roman Zippel.\n");
 
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -759,9 +791,9 @@ void on_license1_activate(GtkMenuItem * 
 {
 	GtkWidget *dialog;
 	const gchar *license_text =
-	    "gkc is released under the terms of the GNU GPL v2.\n"
-	    "For more information, please see the source code or\n"
-	    "visit http://www.fsf.org/licenses/licenses.html\n";
+	    _("gkc is released under the terms of the GNU GPL v2.\n"
+	      "For more information, please see the source code or\n"
+	      "visit http://www.fsf.org/licenses/licenses.html\n");
 
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1140,9 +1172,6 @@ on_treeview1_button_press_event(GtkWidge
 }
 
 
-/* Conf management */
-
-
 /* Fill a row of strings */
 static gchar **fill_row(struct menu *menu)
 {
@@ -1550,6 +1579,10 @@ int main(int ac, char *av[])
 	kconfig_load();
 #endif
 
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset(PACKAGE, "UTF-8");
+	textdomain(PACKAGE);
+
 	/* GTK stuffs */
 	gtk_set_locale();
 	gtk_init(&ac, &av);
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
--- a/scripts/kconfig/gconf.glade
+++ b/scripts/kconfig/gconf.glade
@@ -310,13 +310,13 @@
 	      <property name="tooltips">True</property>
 
 	      <child>
-		<widget class="GtkToolButton" id="button1">
+		<widget class="button" id="button1">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
 		  <property name="label" translatable="yes">Back</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-undo</property>
-		  <signal name="clicked" handler="on_back_pressed"/>
+		  <property name="stock_pixmap">gtk-undo</property>
+		  <signal name="pressed" handler="on_back_pressed"/>
 		</widget>
 	      </child>
 
@@ -327,24 +327,24 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button2">
+		<widget class="button" id="button2">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Load a config file</property>
 		  <property name="label" translatable="yes">Load</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-open</property>
-		  <signal name="clicked" handler="on_load_pressed"/>
+		  <property name="stock_pixmap">gtk-open</property>
+		  <signal name="pressed" handler="on_load_pressed"/>
 		</widget>
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button3">
+		<widget class="button" id="button3">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Save a config file</property>
 		  <property name="label" translatable="yes">Save</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-save</property>
-		  <signal name="clicked" handler="on_save_pressed"/>
+		  <property name="stock_pixmap">gtk-save</property>
+		  <signal name="pressed" handler="on_save_pressed"/>
 		</widget>
 	      </child>
 
@@ -355,34 +355,34 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button4">
+		<widget class="button" id="button4">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Single view</property>
 		  <property name="label" translatable="yes">Single</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-indent</property>
+		  <property name="stock_pixmap">gtk-missing-image</property>
 		  <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
 		</widget>
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button5">
+		<widget class="button" id="button5">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Split view</property>
 		  <property name="label" translatable="yes">Split</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-copy</property>
+		  <property name="stock_pixmap">gtk-missing-image</property>
 		  <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
 		</widget>
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button6">
+		<widget class="button" id="button6">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Full view</property>
 		  <property name="label" translatable="yes">Full</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-justify-left</property>
+		  <property name="stock_pixmap">gtk-missing-image</property>
 		  <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
 		</widget>
 	      </child>
@@ -394,24 +394,22 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button7">
+		<widget class="button" id="button7">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
 		  <property name="label" translatable="yes">Collapse</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-zoom-out</property>
-		  <signal name="clicked" handler="on_collapse_pressed"/>
+		  <signal name="pressed" handler="on_collapse_pressed"/>
 		</widget>
 	      </child>
 
 	      <child>
-		<widget class="GtkToolButton" id="button8">
+		<widget class="button" id="button8">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
 		  <property name="label" translatable="yes">Expand</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock-id">gtk-zoom-in</property>
-		  <signal name="clicked" handler="on_expand_pressed"/>
+		  <signal name="pressed" handler="on_expand_pressed"/>
 		</widget>
 	      </child>
 	    </widget>
diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c
new file mode 100644
--- /dev/null
+++ b/scripts/kconfig/kxgettext.c
@@ -0,0 +1,221 @@
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+	char *bfp = bf;
+	int multiline = strchr(text, '\n') != NULL;
+
+	*bfp++ = '"';
+	--len;
+
+	if (multiline) {
+		*bfp++ = '"';
+		*bfp++ = '\n';
+		*bfp++ = '"';
+		len -= 3;
+	}
+
+	while (*text != '\0' && len > 1) {
+		if (*text == '"')
+			*bfp++ = '\\';
+		else if (*text == '\n') {
+			*bfp++ = '\\';
+			*bfp++ = 'n';
+			*bfp++ = '"';
+			*bfp++ = '\n';
+			*bfp++ = '"';
+			len -= 5;
+			++text;
+			goto next;
+		}
+		*bfp++ = *text++;
+next:
+		--len;
+	}
+
+	if (multiline)
+		bfp -= 3;
+
+	*bfp++ = '"';
+	*bfp = '\0';
+
+	return bf;
+}
+
+struct file_line {
+	struct file_line *next;
+	char*		 file;
+	int		 lineno;
+};
+
+static struct file_line *file_line__new(char *file, int lineno)
+{
+	struct file_line *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->file   = file;
+	self->lineno = lineno;
+	self->next   = NULL;
+out:
+	return self;
+}
+
+struct message {
+	const char	 *msg;
+	const char	 *option;
+	struct message	 *next;
+	struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+{
+	struct message *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->files = file_line__new(file, lineno);
+	if (self->files == NULL)
+		goto out_fail;
+
+	self->msg = strdup(msg);
+	if (self->msg == NULL)
+		goto out_fail_msg;
+
+	self->option = option;
+	self->next = NULL;
+out:
+	return self;
+out_fail_msg:
+	free(self->files);
+out_fail:
+	free(self);
+	self = NULL;
+	goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		if (strcmp(m->msg, msg) == 0)
+			break;
+		m = m->next;
+	}
+
+	return m;
+}
+
+static int message__add_file_line(struct message *self, char *file, int lineno)
+{
+	int rc = -1;
+	struct file_line *fl = file_line__new(file, lineno);
+
+	if (fl == NULL)
+		goto out;
+
+	fl->next    = self->files;
+	self->files = fl;
+	rc = 0;
+out:
+	return rc;
+}
+
+static int message__add(const char *msg, char *option, char *file, int lineno)
+{
+	int rc = 0;
+	char bf[16384];
+	char *escaped = escape(msg, bf, sizeof(bf));
+	struct message *m = mesage__find(escaped);
+
+	if (m != NULL)
+		rc = message__add_file_line(m, file, lineno);
+	else {
+		m = message__new(escaped, option, file, lineno);
+
+		if (m != NULL) {
+			m->next	      = message__list;
+			message__list = m;
+		} else
+			rc = -1;
+	}
+	return rc;
+}
+
+void menu_build_message_list(struct menu *menu)
+{
+	struct menu *child;
+
+	message__add(menu_get_prompt(menu), NULL,
+		     menu->file == NULL ? "Root Menu" : menu->file->name,
+		     menu->lineno);
+
+	if (menu->sym != NULL && menu->sym->help != NULL)
+		message__add(menu->sym->help, menu->sym->name,
+			     menu->file == NULL ? "Root Menu" : menu->file->name,
+			     menu->lineno);
+
+	for (child = menu->list; child != NULL; child = child->next)
+		if (child->prompt != NULL)
+			menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+	struct file_line *fl = self->files;
+
+	printf("\n#: %s:%d", fl->file, fl->lineno);
+	fl = fl->next;
+
+	while (fl != NULL) {
+		printf(", %s:%d", fl->file, fl->lineno);
+		fl = fl->next;
+	}
+
+	if (self->option != NULL)
+		printf(", %s:00000", self->option);
+
+	putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+	message__print_file_lineno(self);
+
+	printf("msgid %s\n"
+	       "msgstr \"\"\n", self->msg);
+}
+
+void menu__xgettext(void)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		message__print_gettext_msgid_msgstr(m);
+		m = m->next;
+	}
+}
+
+int main(int ac, char **av)
+{
+	conf_parse(av[1]);
+
+	menu_build_message_list(menu_get_root_menu(NULL));
+	menu__xgettext();
+	return 0;
+}
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -8,6 +8,8 @@
 
 #include "expr.h"
 
+#include <libintl.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -23,6 +25,12 @@ extern "C" {
 
 #define SRCTREE "srctree"
 
+#define PACKAGE "linux"
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
 int zconfparse(void);
 void zconfdump(FILE *out);
 
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -4,6 +4,8 @@
  *
  * Introduced single menu mode (show all sub-menus in one large tree).
  * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  */
 
 #include <sys/ioctl.h>
@@ -23,7 +25,7 @@
 #include "lkc.h"
 
 static char menu_backtitle[128];
-static const char mconf_readme[] =
+static const char mconf_readme[] = N_(
 "Overview\n"
 "--------\n"
 "Some kernel features may be built directly into the kernel.\n"
@@ -156,39 +158,39 @@ static const char mconf_readme[] =
 "\n"
 "Note that this mode can eventually be a little more CPU expensive\n"
 "(especially with a larger number of unrolled categories) than the\n"
-"default mode.\n",
-menu_instructions[] =
+"default mode.\n"),
+menu_instructions[] = N_(
 	"Arrow keys navigate the menu.  "
 	"<Enter> selects submenus --->.  "
 	"Highlighted letters are hotkeys.  "
 	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
 	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
-	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
-radiolist_instructions[] =
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
 	"Use the arrow keys to navigate this window or "
 	"press the hotkey of the item you wish to select "
 	"followed by the <SPACE BAR>. "
-	"Press <?> for additional information about this option.",
-inputbox_instructions_int[] =
+	"Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
 	"Please enter a decimal value. "
 	"Fractions will not be accepted.  "
-	"Use the <TAB> key to move from the input field to the buttons below it.",
-inputbox_instructions_hex[] =
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
 	"Please enter a hexadecimal value. "
-	"Use the <TAB> key to move from the input field to the buttons below it.",
-inputbox_instructions_string[] =
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
 	"Please enter a string value. "
-	"Use the <TAB> key to move from the input field to the buttons below it.",
-setmod_text[] =
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
 	"This feature depends on another which has been configured as a module.\n"
-	"As a result, this feature will be built as a module.",
-nohelp_text[] =
-	"There is no help available for this kernel option.\n",
-load_config_text[] =
+	"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+	"There is no help available for this kernel option.\n"),
+load_config_text[] = N_(
 	"Enter the name of the configuration file you wish to load.  "
 	"Accept the name shown to restore the configuration you "
-	"last retrieved.  Leave blank to abort.",
-load_config_help[] =
+	"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
 	"\n"
 	"For various reasons, one may wish to keep several different kernel\n"
 	"configurations available on a single machine.\n"
@@ -198,11 +200,11 @@ load_config_help[] =
 	"to modify that configuration.\n"
 	"\n"
 	"If you are uncertain, then you have probably never used alternate\n"
-	"configuration files.  You should therefor leave this blank to abort.\n",
-save_config_text[] =
+	"configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
 	"Enter a filename to which this configuration should be saved "
-	"as an alternate.  Leave blank to abort.",
-save_config_help[] =
+	"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
 	"\n"
 	"For various reasons, one may wish to keep different kernel\n"
 	"configurations available on a single machine.\n"
@@ -212,8 +214,8 @@ save_config_help[] =
 	"configuration options you have selected at that time.\n"
 	"\n"
 	"If you are uncertain what all this means then you should probably\n"
-	"leave this blank.\n",
-search_help[] =
+	"leave this blank.\n"),
+search_help[] = N_(
 	"\n"
 	"Search for CONFIG_ symbols and display their relations.\n"
 	"Example: search for \"^FOO\"\n"
@@ -250,7 +252,7 @@ search_help[] =
 	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
 	"          ^USB => find all CONFIG_ symbols starting with USB\n"
 	"          USB$ => find all CONFIG_ symbols ending with USB\n"
-	"\n";
+	"\n");
 
 static signed char buf[4096], *bufptr = buf;
 static signed char input_buf[4096];
@@ -305,8 +307,8 @@ static void init_wsize(void)
 	}
 
 	if (rows < 19 || cols < 80) {
-		fprintf(stderr, "Your display is too small to run Menuconfig!\n");
-		fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
 		exit(1);
 	}
 
@@ -526,9 +528,9 @@ static void search_conf(void)
 again:
 	cprint_init();
 	cprint("--title");
-	cprint("Search Configuration Parameter");
+	cprint(_("Search Configuration Parameter"));
 	cprint("--inputbox");
-	cprint("Enter Keyword");
+	cprint(_("Enter Keyword"));
 	cprint("10");
 	cprint("75");
 	cprint("");
@@ -539,7 +541,7 @@ again:
 	case 0:
 		break;
 	case 1:
-		show_helptext("Search Configuration", search_help);
+		show_helptext(_("Search Configuration"), search_help);
 		goto again;
 	default:
 		return;
@@ -548,7 +550,7 @@ again:
 	sym_arr = sym_re_search(input_buf);
 	res = get_relations_str(sym_arr);
 	free(sym_arr);
-	show_textbox("Search Results", str_get(&res), 0, 0);
+	show_textbox(_("Search Results"), str_get(&res), 0, 0);
 	str_free(&res);
 }
 
@@ -721,9 +723,9 @@ static void conf(struct menu *menu)
 	while (1) {
 		cprint_init();
 		cprint("--title");
-		cprint("%s", prompt ? prompt : "Main Menu");
+		cprint("%s", prompt ? prompt : _("Main Menu"));
 		cprint("--menu");
-		cprint(menu_instructions);
+		cprint(_(menu_instructions));
 		cprint("%d", rows);
 		cprint("%d", cols);
 		cprint("%d", rows - 10);
@@ -736,9 +738,9 @@ static void conf(struct menu *menu)
 			cprint(":");
 			cprint("--- ");
 			cprint("L");
-			cprint("    Load an Alternate Configuration File");
+			cprint(_("    Load an Alternate Configuration File"));
 			cprint("S");
-			cprint("    Save Configuration to an Alternate File");
+			cprint(_("    Save Configuration to an Alternate File"));
 		}
 		stat = exec_conf();
 		if (stat < 0)
@@ -793,7 +795,7 @@ static void conf(struct menu *menu)
 			if (sym)
 				show_help(submenu);
 			else
-				show_helptext("README", mconf_readme);
+				show_helptext("README", _(mconf_readme));
 			break;
 		case 3:
 			if (type == 't') {
@@ -849,7 +851,7 @@ static void show_help(struct menu *menu)
 	{
 		if (sym->name) {
 			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
-			str_append(&help, sym->help);
+			str_append(&help, _(sym->help));
 			str_append(&help, "\n");
 		}
 	} else {
@@ -886,9 +888,9 @@ static void conf_choice(struct menu *men
 	while (1) {
 		cprint_init();
 		cprint("--title");
-		cprint("%s", prompt ? prompt : "Main Menu");
+		cprint("%s", prompt ? prompt : _("Main Menu"));
 		cprint("--radiolist");
-		cprint(radiolist_instructions);
+		cprint(_(radiolist_instructions));
 		cprint("15");
 		cprint("70");
 		cprint("6");
@@ -935,17 +937,17 @@ static void conf_string(struct menu *men
 	while (1) {
 		cprint_init();
 		cprint("--title");
-		cprint("%s", prompt ? prompt : "Main Menu");
+		cprint("%s", prompt ? prompt : _("Main Menu"));
 		cprint("--inputbox");
 		switch (sym_get_type(menu->sym)) {
 		case S_INT:
-			cprint(inputbox_instructions_int);
+			cprint(_(inputbox_instructions_int));
 			break;
 		case S_HEX:
-			cprint(inputbox_instructions_hex);
+			cprint(_(inputbox_instructions_hex));
 			break;
 		case S_STRING:
-			cprint(inputbox_instructions_string);
+			cprint(_(inputbox_instructions_string));
 			break;
 		default:
 			/* panic? */;
@@ -958,7 +960,7 @@ static void conf_string(struct menu *men
 		case 0:
 			if (sym_set_string_value(menu->sym, input_buf))
 				return;
-			show_textbox(NULL, "You have made an invalid entry.", 5, 43);
+			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
 			break;
 		case 1:
 			show_help(menu);
@@ -987,10 +989,10 @@ static void conf_load(void)
 				return;
 			if (!conf_read(input_buf))
 				return;
-			show_textbox(NULL, "File does not exist!", 5, 38);
+			show_textbox(NULL, _("File does not exist!"), 5, 38);
 			break;
 		case 1:
-			show_helptext("Load Alternate Configuration", load_config_help);
+			show_helptext(_("Load Alternate Configuration"), load_config_help);
 			break;
 		case 255:
 			return;
@@ -1016,10 +1018,10 @@ static void conf_save(void)
 				return;
 			if (!conf_write(input_buf))
 				return;
-			show_textbox(NULL, "Can't create file!  Probably a nonexistent directory.", 5, 60);
+			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 			break;
 		case 1:
-			show_helptext("Save Alternate Configuration", save_config_help);
+			show_helptext(_("Save Alternate Configuration"), save_config_help);
 			break;
 		case 255:
 			return;
@@ -1040,12 +1042,16 @@ int main(int ac, char **av)
 	char *mode;
 	int stat;
 
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
 	conf_parse(av[1]);
 	conf_read(NULL);
 
 	sym = sym_lookup("KERNELRELEASE", 0);
 	sym_calc_value(sym);
-	sprintf(menu_backtitle, "Linux Kernel v%s Configuration",
+	sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
 		sym_get_string_value(sym));
 
 	mode = getenv("MENUCONFIG_MODE");
@@ -1062,7 +1068,7 @@ int main(int ac, char **av)
 	do {
 		cprint_init();
 		cprint("--yesno");
-		cprint("Do you wish to save your new kernel configuration?");
+		cprint(_("Do you wish to save your new kernel configuration?"));
 		cprint("5");
 		cprint("60");
 		stat = exec_conf();
@@ -1070,20 +1076,20 @@ int main(int ac, char **av)
 
 	if (stat == 0) {
 		if (conf_write(NULL)) {
-			fprintf(stderr, "\n\n"
+			fprintf(stderr, _("\n\n"
 				"Error during writing of the kernel configuration.\n"
 				"Your kernel configuration changes were NOT saved."
-				"\n\n");
+				"\n\n"));
 			return 1;
 		}
-		printf("\n\n"
+		printf(_("\n\n"
 			"*** End of Linux kernel configuration.\n"
 			"*** Execute 'make' to build the kernel or try 'make help'."
-			"\n\n");
+			"\n\n"));
 	} else {
-		fprintf(stderr, "\n\n"
+		fprintf(stderr, _("\n\n"
 			"Your kernel configuration changes were NOT saved."
-			"\n\n");
+			"\n\n"));
 	}
 
 	return 0;
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -365,9 +365,9 @@ bool menu_is_visible(struct menu *menu)
 const char *menu_get_prompt(struct menu *menu)
 {
 	if (menu->prompt)
-		return menu->prompt->text;
+		return _(menu->prompt->text);
 	else if (menu->sym)
-		return menu->sym->name;
+		return _(menu->sym->name);
 	return NULL;
 }
 
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -26,8 +26,23 @@
 #include "qconf.moc"
 #include "images.c"
 
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
 static QApplication *configApp;
 
+static inline QString qgettext(const char* str)
+{
+  return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+  return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
 ConfigSettings::ConfigSettings()
 	: showAll(false), showName(false), showRange(false), showData(false)
 {
@@ -177,7 +192,7 @@ void ConfigItem::updateMenu(void)
 
 	sym = menu->sym;
 	prop = menu->prompt;
-	prompt = menu_get_prompt(menu);
+	prompt = QString::fromLocal8Bit(menu_get_prompt(menu));
 
 	if (prop) switch (prop->type) {
 	case P_MENU:
@@ -203,7 +218,7 @@ void ConfigItem::updateMenu(void)
 	if (!sym)
 		goto set_prompt;
 
-	setText(nameColIdx, sym->name);
+	setText(nameColIdx, QString::fromLocal8Bit(sym->name));
 
 	type = sym_get_type(sym);
 	switch (type) {
@@ -213,9 +228,9 @@ void ConfigItem::updateMenu(void)
 
 		if (!sym_is_changable(sym) && !list->showAll) {
 			setPixmap(promptColIdx, 0);
-			setText(noColIdx, 0);
-			setText(modColIdx, 0);
-			setText(yesColIdx, 0);
+			setText(noColIdx, QString::null);
+			setText(modColIdx, QString::null);
+			setText(yesColIdx, QString::null);
 			break;
 		}
 		expr = sym_get_tristate_value(sym);
@@ -257,6 +272,7 @@ void ConfigItem::updateMenu(void)
 		const char* data;
 
 		data = sym_get_string_value(sym);
+
 #if QT_VERSION >= 300
 		int i = list->mapIdx(dataColIdx);
 		if (i >= 0)
@@ -264,9 +280,9 @@ void ConfigItem::updateMenu(void)
 #endif
 		setText(dataColIdx, data);
 		if (type == S_STRING)
-			prompt.sprintf("%s: %s", prompt.latin1(), data);
+			prompt = QString("%1: %2").arg(prompt).arg(data);
 		else
-			prompt.sprintf("(%s) %s", data, prompt.latin1());
+			prompt = QString("(%2) %1").arg(prompt).arg(data);
 		break;
 	}
 	if (!sym_has_value(sym) && visible)
@@ -343,9 +359,9 @@ void ConfigLineEdit::show(ConfigItem* i)
 {
 	item = i;
 	if (sym_get_string_value(item->menu->sym))
-		setText(sym_get_string_value(item->menu->sym));
+		setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
 	else
-		setText(0);
+		setText(QString::null);
 	Parent::show();
 	setFocus();
 }
@@ -961,7 +977,7 @@ ConfigMainWindow::ConfigMainWindow(void)
 	delete configSettings;
 }
 
-static QString print_filter(const char *str)
+static QString print_filter(const QString &str)
 {
 	QRegExp re("[<>&\"\\n]");
 	QString res = str;
@@ -994,7 +1010,7 @@ static QString print_filter(const char *
 
 static void expr_print_help(void *data, const char *str)
 {
-	((QString*)data)->append(print_filter(str));
+	reinterpret_cast<QString*>(data)->append(print_filter(str));
 }
 
 /*
@@ -1009,7 +1025,7 @@ void ConfigMainWindow::setHelp(QListView
 	if (item)
 		menu = ((ConfigItem*)item)->menu;
 	if (!menu) {
-		helpText->setText(NULL);
+		helpText->setText(QString::null);
 		return;
 	}
 
@@ -1019,16 +1035,16 @@ void ConfigMainWindow::setHelp(QListView
 	if (sym) {
 		if (menu->prompt) {
 			head += "<big><b>";
-			head += print_filter(menu->prompt->text);
+			head += print_filter(_(menu->prompt->text));
 			head += "</b></big>";
 			if (sym->name) {
 				head += " (";
-				head += print_filter(sym->name);
+				head += print_filter(_(sym->name));
 				head += ")";
 			}
 		} else if (sym->name) {
 			head += "<big><b>";
-			head += print_filter(sym->name);
+			head += print_filter(_(sym->name));
 			head += "</b></big>";
 		}
 		head += "<br><br>";
@@ -1049,7 +1065,7 @@ void ConfigMainWindow::setHelp(QListView
 				case P_PROMPT:
 				case P_MENU:
 					debug += "prompt: ";
-					debug += print_filter(prop->text);
+					debug += print_filter(_(prop->text));
 					debug += "<br>";
 					break;
 				case P_DEFAULT:
@@ -1088,10 +1104,10 @@ void ConfigMainWindow::setHelp(QListView
 			debug += "<br>";
 		}
 
-		help = print_filter(sym->help);
+		help = print_filter(_(sym->help));
 	} else if (menu->prompt) {
 		head += "<big><b>";
-		head += print_filter(menu->prompt->text);
+		head += print_filter(_(menu->prompt->text));
 		head += "</b></big><br><br>";
 		if (showDebug) {
 			if (menu->prompt->visible.expr) {
@@ -1111,7 +1127,7 @@ void ConfigMainWindow::loadConfig(void)
 	QString s = QFileDialog::getOpenFileName(".config", NULL, this);
 	if (s.isNull())
 		return;
-	if (conf_read(s.latin1()))
+	if (conf_read(QFile::encodeName(s)))
 		QMessageBox::information(this, "qconf", "Unable to load configuration!");
 	ConfigView::updateListAll();
 }
@@ -1127,7 +1143,7 @@ void ConfigMainWindow::saveConfigAs(void
 	QString s = QFileDialog::getSaveFileName(".config", NULL, this);
 	if (s.isNull())
 		return;
-	if (conf_write(s.latin1()))
+	if (conf_write(QFile::encodeName(s)))
 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
 }
 
@@ -1372,6 +1388,9 @@ int main(int ac, char** av)
 	ConfigMainWindow* v;
 	const char *name;
 
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
 #ifndef LKC_DIRECT_LINK
 	kconfig_load();
 #endif
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -170,14 +170,14 @@ my %highlights_html = ( $type_constant, 
 			$type_param, "<tt><b>\$1</b></tt>" );
 my $blankline_html = "<p>";
 
-# sgml, docbook format
-my %highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+# XML, docbook format
+my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
 			$type_constant, "<constant>\$1</constant>",
 			$type_func, "<function>\$1</function>",
 			$type_struct, "<structname>\$1</structname>",
 			$type_env, "<envar>\$1</envar>",
 			$type_param, "<parameter>\$1</parameter>" );
-my $blankline_sgml = "</para><para>\n";
+my $blankline_xml = "</para><para>\n";
 
 # gnome, docbook format
 my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
@@ -297,14 +297,14 @@ while ($ARGV[0] =~ m/^-(.*)/) {
 	%highlights = %highlights_text;
 	$blankline = $blankline_text;
     } elsif ($cmd eq "-docbook") {
-	$output_mode = "sgml";
-	%highlights = %highlights_sgml;
-	$blankline = $blankline_sgml;
+	$output_mode = "xml";
+	%highlights = %highlights_xml;
+	$blankline = $blankline_xml;
     } elsif ($cmd eq "-gnome") {
 	$output_mode = "gnome";
 	%highlights = %highlights_gnome;
 	$blankline = $blankline_gnome;
-    } elsif ($cmd eq "-module") { # not needed for sgml, inherits from calling document
+    } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
 	$modulename = shift @ARGV;
     } elsif ($cmd eq "-function") { # to only output specific functions
 	$function_only = 1;
@@ -547,26 +547,31 @@ sub output_intro_html(%) {
     print "<hr>\n";
 }
 
-sub output_section_sgml(%) {
+sub output_section_xml(%) {
     my %args = %{$_[0]};
     my $section;    
     # print out each section
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
-	print "<refsect1>\n <title>$section</title>\n <para>\n";
+	print "<refsect1>\n";
+	print "<title>$section</title>\n";
 	if ($section =~ m/EXAMPLE/i) {
-	    print "<example><para>\n";
+	    print "<informalexample><programlisting>\n";
+	} else {
+	    print "<para>\n";
 	}
 	output_highlight($args{'sections'}{$section});
 	if ($section =~ m/EXAMPLE/i) {
-	    print "</para></example>\n";
+	    print "</programlisting></informalexample>\n";
+	} else {
+	    print "</para>\n";
 	}
-	print " </para>\n</refsect1>\n";
+	print "</refsect1>\n";
     }
 }
 
-# output function in sgml DocBook
-sub output_function_sgml(%) {
+# output function in XML DocBook
+sub output_function_xml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -576,8 +581,14 @@ sub output_function_sgml(%) {
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry>\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>Kernel Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print "<refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'function'}."</refname>\n";
@@ -607,7 +618,7 @@ sub output_function_sgml(%) {
 	    }
 	}
     } else {
-	print "  <void>\n";
+	print "  <void/>\n";
     }
     print "  </funcprototype></funcsynopsis>\n";
     print "</refsynopsisdiv>\n";
@@ -632,12 +643,12 @@ sub output_function_sgml(%) {
     }
     print "</refsect1>\n";
 
-    output_section_sgml(@_);
+    output_section_xml(@_);
     print "</refentry>\n\n";
 }
 
-# output struct in sgml DocBook
-sub output_struct_sgml(%) {
+# output struct in XML DocBook
+sub output_struct_xml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $id;
@@ -646,8 +657,14 @@ sub output_struct_sgml(%) {
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry>\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>Kernel Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print "<refentrytitle><phrase id=\"$id\">".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase id=\"$id\">".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
@@ -708,13 +725,13 @@ sub output_struct_sgml(%) {
     print "  </variablelist>\n";
     print " </refsect1>\n";
 
-    output_section_sgml(@_);
+    output_section_xml(@_);
 
     print "</refentry>\n\n";
 }
 
-# output enum in sgml DocBook
-sub output_enum_sgml(%) {
+# output enum in XML DocBook
+sub output_enum_xml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -724,8 +741,14 @@ sub output_enum_sgml(%) {
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry>\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>Kernel Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print "<refentrytitle><phrase id=\"$id\">enum ".$args{'enum'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase id=\"$id\">enum ".$args{'enum'}."</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>enum ".$args{'enum'}."</refname>\n";
@@ -769,13 +792,13 @@ sub output_enum_sgml(%) {
     print "  </variablelist>\n";
     print "</refsect1>\n";
 
-    output_section_sgml(@_);
+    output_section_xml(@_);
 
     print "</refentry>\n\n";
 }
 
-# output typedef in sgml DocBook
-sub output_typedef_sgml(%) {
+# output typedef in XML DocBook
+sub output_typedef_xml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $id;
@@ -784,8 +807,14 @@ sub output_typedef_sgml(%) {
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry>\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>Kernel Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print "<refentrytitle><phrase id=\"$id\">typedef ".$args{'typedef'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase id=\"$id\">typedef ".$args{'typedef'}."</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>typedef ".$args{'typedef'}."</refname>\n";
@@ -800,13 +829,13 @@ sub output_typedef_sgml(%) {
     print "  <synopsis>typedef ".$args{'typedef'}.";</synopsis>\n";
     print "</refsynopsisdiv>\n";
 
-    output_section_sgml(@_);
+    output_section_xml(@_);
 
     print "</refentry>\n\n";
 }
 
-# output in sgml DocBook
-sub output_intro_sgml(%) {
+# output in XML DocBook
+sub output_intro_xml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -831,7 +860,7 @@ sub output_intro_sgml(%) {
     print "\n\n";
 }
 
-# output in sgml DocBook
+# output in XML DocBook
 sub output_function_gnome {
     my %args = %{$_[0]};
     my ($parameter, $section);
@@ -1465,6 +1494,8 @@ sub dump_function($$) {
 
     $prototype =~ s/^static +//;
     $prototype =~ s/^extern +//;
+    $prototype =~ s/^fastcall +//;
+    $prototype =~ s/^asmlinkage +//;
     $prototype =~ s/^inline +//;
     $prototype =~ s/^__inline__ +//;
     $prototype =~ s/^#define +//; #ak added
@@ -1578,13 +1609,13 @@ sub process_state3_function($$) { 
     my $x = shift;
     my $file = shift;
 
-    if ($x =~ m#\s*/\*\s+MACDOC\s*#io) {
+    if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) {
 	# do nothing
     }
     elsif ($x =~ /([^\{]*)/) {
         $prototype .= $1;
     }
-    if (($x =~ /\{/) || ($x =~ /\#/) || ($x =~ /;/)) {
+    if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) {
         $prototype =~ s@/\*.*?\*/@@gos;	# strip comments.
 	$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
 	$prototype =~ s@^\s+@@gos; # strip leading spaces
@@ -1624,6 +1655,15 @@ sub process_state3_type($$) { 
     }
 }
 
+# replace <, >, and &
+sub xml_escape($) {
+	my $text = shift;
+	$text =~ s/\&/\\\\\\amp;/g;
+	$text =~ s/\</\\\\\\lt;/g;
+	$text =~ s/\>/\\\\\\gt;/g;
+	return $text;
+}
+
 sub process_file($) {
     my ($file) = "$ENV{'SRCTREE'}@_";
     my $identifier;
@@ -1664,7 +1704,7 @@ sub process_file($) {
 
 		$state = 2;
 		if (/-(.*)/) {
-		    $declaration_purpose = $1;
+		    $declaration_purpose = xml_escape($1);
 		} else {
 		    $declaration_purpose = "";
 		}
@@ -1695,10 +1735,7 @@ sub process_file($) {
 		$newcontents = $2;
 
 		if ($contents ne "") {
-		    $contents =~ s/\&/\\\\\\amp;/g;
-		    $contents =~ s/\</\\\\\\lt;/g;
-		    $contents =~ s/\>/\\\\\\gt;/g;
-		    dump_section($section, $contents);
+		    dump_section($section, xml_escape($contents));
 		    $section = $section_default;
 		}
 
@@ -1710,10 +1747,7 @@ sub process_file($) {
 	    } elsif (/$doc_end/) {
 
 		if ($contents ne "") {
-		    $contents =~ s/\&/\\\\\\amp;/g;
-		    $contents =~ s/\</\\\\\\lt;/g;
-		    $contents =~ s/\>/\\\\\\gt;/g;
-		    dump_section($section, $contents);
+		    dump_section($section, xml_escape($contents));
 		    $section = $section_default;
 		    $contents = "";
 		}
@@ -1727,10 +1761,7 @@ sub process_file($) {
 		# @parameter line to signify start of description
 		if ($1 eq "" && 
 			($section =~ m/^@/ || $section eq $section_context)) {
-		    $contents =~ s/\&/\\\\\\amp;/g;
-		    $contents =~ s/\</\\\\\\lt;/g;
-		    $contents =~ s/\>/\\\\\\gt;/g;
-		    dump_section($section, $contents);
+		    dump_section($section, xml_escape($contents));
 		    $section = $section_default;
 		    $contents = "";
 		} else {
@@ -1799,7 +1830,7 @@ sub process_file($) {
     }
     if ($initial_section_counter == $section_counter) {
 	print STDERR "Warning(${file}): no structured comments found\n";
-	if ($output_mode eq "sgml") {
+	if ($output_mode eq "xml") {
 	    # The template wants at least one RefEntry here; make one.
 	    print "<refentry>\n";
 	    print " <refnamediv>\n";
diff --git a/scripts/lxdialog/checklist.c b/scripts/lxdialog/checklist.c
--- a/scripts/lxdialog/checklist.c
+++ b/scripts/lxdialog/checklist.c
@@ -269,7 +269,7 @@ dialog_checklist (const char *title, con
 				    status[scroll + max_choice - 1],
 				    max_choice - 1, FALSE);
 			scrollok (list, TRUE);
-			scroll (list);
+			wscrl (list, 1);
 			scrollok (list, FALSE);
 		    }
 		    scroll++;
diff --git a/scripts/lxdialog/colors.h b/scripts/lxdialog/colors.h
--- a/scripts/lxdialog/colors.h
+++ b/scripts/lxdialog/colors.h
@@ -152,10 +152,4 @@
  * Global variables
  */
 
-typedef struct {
-    char name[COLOR_NAME_LEN];
-    int value;
-} color_names_st;
-
-extern color_names_st color_names[];
 extern int color_table[][3];
diff --git a/scripts/lxdialog/lxdialog.c b/scripts/lxdialog/lxdialog.c
--- a/scripts/lxdialog/lxdialog.c
+++ b/scripts/lxdialog/lxdialog.c
@@ -56,7 +56,7 @@ static struct Mode *modePtr;
 int
 main (int argc, const char * const * argv)
 {
-    int offset = 0, clear_screen = 0, end_common_opts = 0, retval;
+    int offset = 0, opt_clear = 0, end_common_opts = 0, retval;
     const char *title = NULL;
 
 #ifdef LOCALE
@@ -89,7 +89,7 @@ main (int argc, const char * const * arg
                 offset += 2;
             }
 	} else if (!strcmp (argv[offset + 1], "--clear")) {
-	    if (clear_screen) {	/* Hey, "--clear" can't appear twice! */
+	    if (opt_clear) {		/* Hey, "--clear" can't appear twice! */
 		Usage (argv[0]);
 		exit (-1);
 	    } else if (argc == 2) {	/* we only want to clear the screen */
@@ -98,7 +98,7 @@ main (int argc, const char * const * arg
 		end_dialog ();
 		return 0;
 	    } else {
-		clear_screen = 1;
+		opt_clear = 1;
 		offset++;
 	    }
 	} else			/* no more common options */
@@ -127,7 +127,7 @@ main (int argc, const char * const * arg
     init_dialog ();
     retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
 
-    if (clear_screen) {		/* clear screen before exit */
+    if (opt_clear) {		/* clear screen before exit */
 	attr_clear (stdscr, LINES, COLS, screen_attr);
 	refresh ();
     }
diff --git a/scripts/lxdialog/menubox.c b/scripts/lxdialog/menubox.c
--- a/scripts/lxdialog/menubox.c
+++ b/scripts/lxdialog/menubox.c
@@ -327,7 +327,7 @@ dialog_menu (const char *title, const ch
                    ) {
 		    /* Scroll menu up */
 		    scrollok (menu, TRUE);
-                    scroll (menu);
+		    wscrl (menu, 1);
                     scrollok (menu, FALSE);
 
                     scroll++;
@@ -357,7 +357,7 @@ dialog_menu (const char *title, const ch
                 for (i=0; (i < max_choice); i++) {
                     if (scroll+max_choice < item_no) {
 			scrollok (menu, TRUE);
-			scroll(menu);
+			wscrl (menu, 1);
 			scrollok (menu, FALSE);
                 	scroll++;
                 	print_item (menu, items[(scroll+max_choice-1)*2+1],
diff --git a/scripts/makeman b/scripts/makeman
deleted file mode 100755
--- a/scripts/makeman
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-## Copyright (C) Michael Still (mikal@stillhq.com)
-## Released under the terms of the GNU GPL
-##
-## A script to make or install the manpages extracted by split-man
-##
-## Arguements: $1 -- the word "convert" or "install"
-##             $2 -- the directory containing the SGML files for the manpages
-##             $3 -- the filename which contained the sgmldoc output
-##                     (I need this so I know which manpages to convert)
-
-my($LISTING, $GENERATED, $INPUT, $OUTPUT, $front, $mode, $filename, $tmpdir);
-
-if($ARGV[0] eq ""){
-  die "Usage: makeman [convert | install] <dir> <file>\n";
-}
-
-if( ! -d "$ARGV[1]" ){
-  die "Output directory \"$ARGV[1]\" does not exist\n";
-}
-
-if($ENV{"TMPDIR"} ne ""){
-  $tmpdir = $ENV{"TMPDIR"};
-}
-else{
-  $tmpdir = "/tmp";
-}
-
-if($ARGV[0] eq "convert"){
-  open LISTING, "grep \"<refentrytitle>\" $ARGV[2] |";
-  while(<LISTING>){
-    s/<\/.*$//;
-    s/^.*>//;
-    s/\.sgml//;
-    s/struct //;
-    s/typedef //;
-
-    chomp;
-    $filename = $_;
-    print "Processing $filename\n";
-
-    # Open the input file to extract the front matter, generate the man page,
-    # and open it, and the rearrange everything until it is happy
-    open INPUT, "< $ARGV[1]/$filename.sgml";
-    $front = "";
-    $mode = 0;
-
-    # The modes used here are:
-    #                                                         mode = 0
-    # <!-- BEGINFRONTTAG -->
-    # <!-- <bookinfo>                                         mode = 1
-    # <!--   <legalnotice>                                    mode = 2
-    # <!--     ...GPL or whatever...
-    # <!--   </legalnotice>                                   mode = 4
-    # <!-- </bookinfo>                                        mode = 3
-    # <!-- ENDFRONTTAG -->
-    #
-    # ...doco...
-
-    # I know that some of the if statements in this while loop are in a funny
-    # order, but that is deliberate...
-    while(<INPUT>){
-      if($mode > 0){
-	s/<!-- //;
-	s/ -->//;
-	s/<docinfo>//i;
-	s<\/docinfo>//i;
-	s/^[ \t]*//i;
-      }
-
-      if($mode == 2){
-	if(/<para>/i){
-	}
-	elsif(/<\/para>/i){
-	  $front = "$front.\\\" \n";
-	}
-	elsif(/<\/legalnotice>/i){
-	  $mode = 4;
-	}
-	elsif(/^[ \t]*$/){
-	}
-	else{
-	  $front = "$front.\\\"     $_";
-	}
-      }
-
-      if($mode == 1){
-	if(/<title>(.*)<\/title>/i){
-	  $front = "$front.\\\" This documentation was generated from the book titled \"$1\", which is part of the Linux kernel source.\n.\\\" \n";
-	}
-	elsif(/<legalnotice>/i){
-	  $front = "$front.\\\" This documentation comes with the following legal notice:\n.\\\" \n";
-	  $mode = 2;
-	}
-
-	elsif(/<author>/i){
-	  $front = "$front.\\\" Documentation by: ";
-	}
-	elsif(/<firstname>(.*)<\/firstname>/i){
-	  $front = "$front$1 ";
-	}
-	elsif(/<surname>(.*)<\/surname>/i){
-	  $front = "$front$1 ";
-	}
-	elsif(/<email>(.*)<\/email>/i){
-	  $front = "$front($1)";
-	}
-	elsif(/\/author>/i){
-	  $front = "$front\n";
-	}
-
-	elsif(/<copyright>/i){
-	  $front = "$front.\\\" Documentation copyright: ";
-	}
-	elsif(/<holder>(.*)<\/holder>/i){
-	  $front = "$front$1 ";
-	}
-	elsif(/<year>(.*)<\/year>/i){
-	  $front = "$front$1 ";
-	}
-	elsif(/\/copyright>/i){
-	  $front = "$front\n";
-	}
-
-	elsif(/^[ \t]*$/
-	      || /<affiliation>/i
-	      || /<\/affiliation>/i
-	      || /<address>/i
-	      || /<\/address>/i
-	      || /<authorgroup>/i
-	      || /<\/authorgroup>/i
-	      || /<\/legalnotice>/i
-              || /<date>/i
-              || /<\/date>/i
-              || /<edition>/i
-              || /<\/edition>/i
-	      || /<pubdate>/i
-	      || /<\/pubdate>/i){
-	}
-	else{
-	  print "Unknown tag in manpage conversion: $_";
-	  }
-      }
-
-      if($mode == 0){
-	if(/<bookinfo>/i){
-	  $mode = 1;
-	}
-      }
-
-      if($mode == 4){
-	if(/<\/bookinfo>/i){
-	  $mode = 3;
-	}
-      }
-    }
-    close INPUT;
-
-    system("cd $ARGV[1]; docbook2man $filename.sgml; mv $filename.9 $tmpdir/$$.9\n");
-    open GENERATED, "< $tmpdir/$$.9";
-    open OUTPUT, "> $ARGV[1]/$filename.9";
-
-    print OUTPUT "$front";
-    print OUTPUT ".\\\" For comments on the formatting of this manpage, please contact Michael Still <mikal\@stillhq.com>\n\n";
-    while(<GENERATED>){
-      print OUTPUT "$_";
-    }
-    close OUTPUT;
-    close GENERATED;
-
-    system("gzip -f $ARGV[1]/$filename.9\n");
-    unlink("$tmpdir/$$.9");
-  }
-}
-elsif($ARGV[0] eq "install"){
-  system("mkdir -p /usr/local/man/man9/; install $ARGV[1]/*.9.gz /usr/local/man/man9/");
-}
-else{
-  die "Usage: makeman [convert | install] <dir> <file>\n";
-}
-
-print "Done\n";
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -4,7 +4,7 @@
  *
  * Copyright 2002-2003  Rusty Russell, IBM Corporation
  *           2003       Kai Germaschewski
- *           
+ *
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -47,32 +47,31 @@ do {                                    
                 sprintf(str + strlen(str), "*");                \
 } while(0)
 
-/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */
-static int do_usb_entry(const char *filename,
-			struct usb_device_id *id, char *alias)
+/* USB is special because the bcdDevice can be matched against a numeric range */
+/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
+static void do_usb_entry(struct usb_device_id *id,
+			 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
+			 unsigned char range_lo, unsigned char range_hi,
+			 struct module *mod)
 {
-	id->match_flags = TO_NATIVE(id->match_flags);
-	id->idVendor = TO_NATIVE(id->idVendor);
-	id->idProduct = TO_NATIVE(id->idProduct);
-	id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
-	id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
-
-	/*
-	 * Some modules (visor) have empty slots as placeholder for
-	 * run-time specification that results in catch-all alias
-	 */
-	if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
-		return 1;
-
+	char alias[500];
 	strcpy(alias, "usb:");
 	ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
 	    id->idVendor);
 	ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
 	    id->idProduct);
-	ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
-	    id->bcdDevice_lo);
-	ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
-	    id->bcdDevice_hi);
+
+	strcat(alias, "d");
+	if (bcdDevice_initial_digits)
+		sprintf(alias + strlen(alias), "%0*X",
+			bcdDevice_initial_digits, bcdDevice_initial);
+	if (range_lo == range_hi)
+		sprintf(alias + strlen(alias), "%u", range_lo);
+	else if (range_lo > 0 || range_hi < 9)
+		sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi);
+	if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1))
+		strcat(alias, "*");
+
 	ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
 	    id->bDeviceClass);
 	ADD(alias, "dsc",
@@ -90,7 +89,73 @@ static int do_usb_entry(const char *file
 	ADD(alias, "ip",
 	    id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
 	    id->bInterfaceProtocol);
-	return 1;
+
+	/* Always end in a wildcard, for future extension */
+	if (alias[strlen(alias)-1] != '*')
+		strcat(alias, "*");
+	buf_printf(&mod->dev_table_buf,
+		   "MODULE_ALIAS(\"%s\");\n", alias);
+}
+
+static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
+{
+	unsigned int devlo, devhi;
+	unsigned char chi, clo;
+	int ndigits;
+
+	id->match_flags = TO_NATIVE(id->match_flags);
+	id->idVendor = TO_NATIVE(id->idVendor);
+	id->idProduct = TO_NATIVE(id->idProduct);
+
+	devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ?
+		TO_NATIVE(id->bcdDevice_lo) : 0x0U;
+	devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
+		TO_NATIVE(id->bcdDevice_hi) : ~0x0U;
+
+	/*
+	 * Some modules (visor) have empty slots as placeholder for
+	 * run-time specification that results in catch-all alias
+	 */
+	if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
+		return;
+
+	/* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
+	for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {
+		clo = devlo & 0xf;
+		chi = devhi & 0xf;
+		if (chi > 9)	/* it's bcd not hex */
+			chi = 9;
+		devlo >>= 4;
+		devhi >>= 4;
+
+		if (devlo == devhi || !ndigits) {
+			do_usb_entry(id, devlo, ndigits, clo, chi, mod);
+			break;
+		}
+
+		if (clo > 0)
+			do_usb_entry(id, devlo++, ndigits, clo, 9, mod);
+
+		if (chi < 9)
+			do_usb_entry(id, devhi--, ndigits, 0, chi, mod);
+	}
+}
+
+static void do_usb_table(void *symval, unsigned long size,
+			 struct module *mod)
+{
+	unsigned int i;
+	const unsigned long id_size = sizeof(struct usb_device_id);
+
+	if (size % id_size || size < id_size) {
+		fprintf(stderr, "*** Warning: %s ids %lu bad size "
+			"(each on %lu)\n", mod->name, size, id_size);
+	}
+	/* Leave last one: it's the terminator. */
+	size -= id_size;
+
+	for (i = 0; i < size; i += id_size)
+		do_usb_entry_multi(symval + i, mod);
 }
 
 /* Looks like: ieee1394:venNmoNspNverN */
@@ -181,6 +246,24 @@ static int do_ccw_entry(const char *file
 	return 1;
 }
 
+/* Looks like: "serio:tyNprNidNexN" */
+static int do_serio_entry(const char *filename,
+			  struct serio_device_id *id, char *alias)
+{
+	id->type = TO_NATIVE(id->type);
+	id->proto = TO_NATIVE(id->proto);
+	id->id = TO_NATIVE(id->id);
+	id->extra = TO_NATIVE(id->extra);
+
+	strcpy(alias, "serio:");
+	ADD(alias, "ty", id->type != SERIO_ANY, id->type);
+	ADD(alias, "pr", id->proto != SERIO_ANY, id->proto);
+	ADD(alias, "id", id->id != SERIO_ANY, id->id);
+	ADD(alias, "ex", id->extra != SERIO_ANY, id->extra);
+
+	return 1;
+}
+
 /* looks like: "pnp:dD" */
 static int do_pnp_entry(const char *filename,
 			struct pnp_device_id *id, char *alias)
@@ -262,14 +345,17 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size, sizeof(struct pci_device_id),
 			 do_pci_entry, mod);
 	else if (sym_is(symname, "__mod_usb_device_table"))
-		do_table(symval, sym->st_size, sizeof(struct usb_device_id),
-			 do_usb_entry, mod);
+		/* special case to handle bcdDevice ranges */
+		do_usb_table(symval, sym->st_size, mod);
 	else if (sym_is(symname, "__mod_ieee1394_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct ieee1394_device_id),
 			 do_ieee1394_entry, mod);
 	else if (sym_is(symname, "__mod_ccw_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct ccw_device_id),
 			 do_ccw_entry, mod);
+	else if (sym_is(symname, "__mod_serio_device_table"))
+		do_table(symval, sym->st_size, sizeof(struct serio_device_id),
+			 do_serio_entry, mod);
 	else if (sym_is(symname, "__mod_pnp_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct pnp_device_id),
 			 do_pnp_entry, mod);
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -47,11 +47,10 @@ warn(const char *fmt, ...)
 	va_end(arglist);
 }
 
-void *do_nofail(void *ptr, const char *file, int line, const char *expr)
+void *do_nofail(void *ptr, const char *expr)
 {
 	if (!ptr) {
-		fatal("Memory allocation failure %s line %d: %s.\n",
-		      file, line, expr);
+		fatal("modpost: Memory allocation failure: %s.\n", expr);
 	}
 	return ptr;
 }
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -53,8 +53,8 @@ static inline void __endian(const void *
 
 #endif
 
-#define NOFAIL(ptr)   do_nofail((ptr), __FILE__, __LINE__, #ptr)
-void *do_nofail(void *ptr, const char *file, int line, const char *expr);
+#define NOFAIL(ptr)   do_nofail((ptr), #ptr)
+void *do_nofail(void *ptr, const char *expr);
 
 struct buffer {
 	char *p;
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -419,7 +419,9 @@ void get_src_version(const char *modname
 	*end = '\0';
 
 	md4_init(&md);
-	for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " ")) {
+	while ((fname = strsep(&sources, " ")) != NULL) {
+		if (!*fname)
+			continue;
 		if (!parse_source_files(fname, &md))
 			goto release;
 	}
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
--- a/scripts/namespace.pl
+++ b/scripts/namespace.pl
@@ -406,6 +406,11 @@ sub resolve_external_references
 					&& $name !~ /^__.*per_cpu_end/
 					&& $name !~ /^__alt_instructions/
 					&& $name !~ /^__setup_/
+					&& $name !~ /^jiffies/
+					&& $name !~ /^__mod_timer/
+					&& $name !~ /^__mod_page_state/
+					&& $name !~ /^init_module/
+					&& $name !~ /^cleanup_module/
 				) {
 					printf "Cannot resolve ";
 					printf "weak " if ($type eq "w");
diff --git a/scripts/patch-kernel b/scripts/patch-kernel
--- a/scripts/patch-kernel
+++ b/scripts/patch-kernel
@@ -46,6 +46,19 @@
 # fix some whitespace damage;
 # be smarter about stopping when current version is larger than requested;
 #	Randy Dunlap <rddunlap@osdl.org>, 2004-AUG-18.
+#
+# Add better support for (non-incremental) 2.6.x.y patches;
+# If an ending version number if not specified, the script automatically
+# increments the SUBLEVEL (x in 2.6.x.y) until no more patch files are found;
+# however, EXTRAVERSION (y in 2.6.x.y) is never automatically incremented
+# but must be specified fully.
+#
+# patch-kernel does not normally support reverse patching, but does so when
+# applying EXTRAVERSION (x.y) patches, so that moving from 2.6.11.y to 2.6.11.z
+# is easy and handled by the script (reverse 2.6.11.y and apply 2.6.11.z).
+#	Randy Dunlap <rddunlap@osdl.org>, 2005-APR-08.
+
+PNAME=patch-kernel
 
 # Set directories from arguments, or use defaults.
 sourcedir=${1-/usr/src/linux}
@@ -54,7 +67,7 @@ stopvers=${3-default}
 
 if [ "$1" == -h -o "$1" == --help -o ! -r "$sourcedir/Makefile" ]; then
 cat << USAGE
-usage: patch-kernel [-h] [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
+usage: $PNAME [-h] [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
   source directory defaults to /usr/src/linux,
   patch directory defaults to the current directory,
   stopversion defaults to <all in patchdir>.
@@ -73,6 +86,19 @@ do
 done
 
 # ---------------------------------------------------------------------------
+# arg1 is filename
+noFile () {
+	echo "cannot find patch file: ${patch}"
+	exit 1
+}
+
+# ---------------------------------------------------------------------------
+backwards () {
+	echo "$PNAME does not support reverse patching"
+	exit 1
+}
+
+# ---------------------------------------------------------------------------
 # Find a file, first parameter is basename of file
 # it tries many compression mechanisms and sets variables to say how to get it
 findFile () {
@@ -133,6 +159,28 @@ applyPatch () {
   return 0;
 }
 
+# ---------------------------------------------------------------------------
+# arg1 is patch filename
+reversePatch () {
+	echo -n "Reversing $1 (${name}) ... "
+	if $uncomp ${patchdir}/"$1"${ext} | patch -p1 -Rs -N -E -d $sourcedir
+	then
+		echo "done."
+	else
+		echo "failed.  Clean it up."
+		exit 1
+	fi
+	if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ]
+	then
+		echo "Aborting.  Reject files found."
+		return 1
+	fi
+	# Remove backup files
+	find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
+
+	return 0
+}
+
 # set current VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION
 TMPFILE=`mktemp .tmpver.XXXXXX` || { echo "cannot make temp file" ; exit 1; }
 grep -E "^(VERSION|PATCHLEVEL|SUBLEVEL|EXTRAVERSION)" $sourcedir/Makefile > $TMPFILE
@@ -160,53 +208,57 @@ then
 		EXTRAVER=$EXTRAVERSION
 	fi
 	EXTRAVER=${EXTRAVER%%[[:punct:]]*}
-	#echo "patch-kernel: changing EXTRAVERSION from $EXTRAVERSION to $EXTRAVER"
+	#echo "$PNAME: changing EXTRAVERSION from $EXTRAVERSION to $EXTRAVER"
 fi
 
 #echo "stopvers=$stopvers"
 if [ $stopvers != "default" ]; then
 	STOPSUBLEVEL=`echo $stopvers | cut -d. -f3`
 	STOPEXTRA=`echo $stopvers | cut -d. -f4`
-	#echo "STOPSUBLEVEL=$STOPSUBLEVEL, STOPEXTRA=$STOPEXTRA"
+	#echo "#___STOPSUBLEVEL=/$STOPSUBLEVEL/, STOPEXTRA=/$STOPEXTRA/"
 else
 	STOPSUBLEVEL=9999
 	STOPEXTRA=9999
 fi
 
-while :				# incrementing SUBLEVEL (s in v.p.s)
-do
-    if [ x$EXTRAVER != "x" ]; then
+# This all assumes a 2.6.x[.y] kernel tree.
+# Don't allow backwards/reverse patching.
+if [ $STOPSUBLEVEL -lt $SUBLEVEL ]; then
+	backwards
+fi
+
+if [ x$EXTRAVER != "x" ]; then
 	CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL.$EXTRAVER"
-    else
+else
 	CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
-    fi
+fi
+
+if [ x$EXTRAVER != "x" ]; then
+	echo "backing up to: $VERSION.$PATCHLEVEL.$SUBLEVEL"
+	patch="patch-${CURRENTFULLVERSION}"
+	findFile $patchdir/${patch} || noFile ${patch}
+	reversePatch ${patch} || exit 1
+fi
+
+# now current is 2.6.x, with no EXTRA applied,
+# so update to target SUBLEVEL (2.6.SUBLEVEL)
+# and then to target EXTRAVER (2.6.SUB.EXTRAVER) if requested.
+# If not ending sublevel is specified, it is incremented until
+# no further sublevels are found.
 
+if [ $STOPSUBLEVEL -gt $SUBLEVEL ]; then
+while :				# incrementing SUBLEVEL (s in v.p.s)
+do
+    CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
+    EXTRAVER=
     if [ $stopvers == $CURRENTFULLVERSION ]; then
         echo "Stopping at $CURRENTFULLVERSION base as requested."
         break
     fi
 
-    while :			# incrementing EXTRAVER (x in v.p.s.x)
-    do
-	EXTRAVER=$((EXTRAVER + 1))
-	FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL.$EXTRAVER"
-	#echo "... trying $FULLVERSION ..."
-
-	patch=patch-$FULLVERSION
-
-	# See if the file exists and find extension
-	findFile $patchdir/${patch} || break
-
-	# Apply the patch and check all is OK
-	applyPatch $patch || break
-
-	continue 2
-    done
-
-    EXTRAVER=
     SUBLEVEL=$((SUBLEVEL + 1))
     FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
-    #echo "___ trying $FULLVERSION ___"
+    #echo "#___ trying $FULLVERSION ___"
 
     if [ $((SUBLEVEL)) -gt $((STOPSUBLEVEL)) ]; then
 	echo "Stopping since sublevel ($SUBLEVEL) is beyond stop-sublevel ($STOPSUBLEVEL)"
@@ -214,14 +266,33 @@ do
     fi
 
     patch=patch-$FULLVERSION
-
     # See if the file exists and find extension
-    findFile $patchdir/${patch} || break
+    findFile $patchdir/${patch} || noFile ${patch}
 
     # Apply the patch and check all is OK
     applyPatch $patch || break
 done
-#echo "base all done"
+#echo "#___sublevel all done"
+fi
+
+# There is no incremental searching for extraversion...
+if [ "$STOPEXTRA" != "" ]; then
+while :				# just to allow break
+do
+# apply STOPEXTRA directly (not incrementally) (x in v.p.s.x)
+	FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL.$STOPEXTRA"
+	#echo "#... trying $FULLVERSION ..."
+	patch=patch-$FULLVERSION
+
+	# See if the file exists and find extension
+	findFile $patchdir/${patch} || noFile ${patch}
+
+	# Apply the patch and check all is OK
+	applyPatch $patch || break
+	#echo "#___extraver all done"
+	break
+done
+fi
 
 if [ x$gotac != x ]; then
   # Out great user wants the -ac patches
diff --git a/scripts/show_delta b/scripts/show_delta
new file mode 100644
--- /dev/null
+++ b/scripts/show_delta
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+#
+# show_deltas: Read list of printk messages instrumented with
+# time data, and format with time deltas.
+#
+# Also, you can show the times relative to a fixed point.
+#
+# Copyright 2003 Sony Corporation
+#
+# GPL 2.0 applies.
+
+import sys
+import string
+
+def usage():
+	print """usage: show_delta [<options>] <filename>
+
+This program parses the output from a set of printk message lines which
+have time data prefixed because the CONFIG_PRINTK_TIME option is set, or
+the kernel command line option "time" is specified. When run with no
+options, the time information is converted to show the time delta between
+each printk line and the next.  When run with the '-b' option, all times
+are relative to a single (base) point in time.
+
+Options:
+  -h            Show this usage help.
+  -b <base>	Specify a base for time references.
+		<base> can be a number or a string.
+		If it is a string, the first message line
+		which matches (at the beginning of the
+		line) is used as the time reference.
+
+ex: $ dmesg >timefile
+    $ show_delta -b NET4 timefile
+
+will show times relative to the line in the kernel output
+starting with "NET4".
+"""
+	sys.exit(1)
+
+# returns a tuple containing the seconds and text for each message line
+# seconds is returned as a float
+# raise an exception if no timing data was found
+def get_time(line):
+	if line[0]!="[":
+		raise ValueError
+
+	# split on closing bracket
+	(time_str, rest) = string.split(line[1:],']',1)
+	time = string.atof(time_str)
+
+	#print "time=", time
+	return (time, rest)
+
+
+# average line looks like:
+# [    0.084282] VFS: Mounted root (romfs filesystem) readonly
+# time data is expressed in seconds.useconds,
+# convert_line adds a delta for each line
+last_time = 0.0
+def convert_line(line, base_time):
+	global last_time
+
+	try:
+		(time, rest) = get_time(line)
+	except:
+		# if any problem parsing time, don't convert anything
+		return line
+
+	if base_time:
+		# show time from base
+		delta = time - base_time
+	else:
+		# just show time from last line
+		delta = time - last_time
+		last_time = time
+
+	return ("[%5.6f < %5.6f >]" % (time, delta)) + rest
+
+def main():
+	base_str = ""
+	filein = ""
+	for arg in sys.argv[1:]:
+		if arg=="-b":
+			base_str = sys.argv[sys.argv.index("-b")+1]
+		elif arg=="-h":
+			usage()
+		else:
+			filein = arg
+
+	if not filein:
+		usage()
+
+	try:
+		lines = open(filein,"r").readlines()
+	except:
+		print "Problem opening file: %s" % filein
+		sys.exit(1)
+
+	if base_str:
+		print 'base= "%s"' % base_str
+		# assume a numeric base.  If that fails, try searching
+		# for a matching line.
+		try:
+			base_time = float(base_str)
+		except:
+			# search for line matching <base> string
+			found = 0
+			for line in lines:
+				try:
+					(time, rest) = get_time(line)
+				except:
+					continue
+				if string.find(rest, base_str)==1:
+					base_time = time
+					found = 1
+					# stop at first match
+					break
+			if not found:
+				print 'Couldn\'t find line matching base pattern "%s"' % base_str
+				sys.exit(1)
+	else:
+		base_time = 0.0
+
+	for line in lines:
+		print convert_line(line, base_time),
+
+main()
+
diff --git a/scripts/split-man b/scripts/split-man
deleted file mode 100755
--- a/scripts/split-man
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-## Copyright (C) Michael Still (mikal@stillhq.com)
-## Released under the terms of the GNU GPL
-##
-## Hoon through the specified DocBook SGML file, and split out the
-## man pages. These can then be processed into groff format, and
-## installed if desired...
-##
-## Arguements: $1 -- the name of the sgml file
-##             $2 -- the directory to put the generated SGML files in
-##             $3 -- kernel version
-
-my($SGML, $REF, $front, $refdata, $mode, $filename);
-
-if(($ARGV[0] eq "") || ($ARGV[1] eq "") || ($ARGV[2] eq "")){
-  die "Usage: split-man <sgml file> <output dir> <kernel version>\n";
-}
-
-open SGML, "< $ARGV[0]" or die "Could not open input file \"$ARGV[0]\"\n";
-if( ! -d "$ARGV[1]" ){
-  die "Output directory \"$ARGV[1]\" does not exist\n";
-}
-
-# Possible modes:
-#   0: Looking for input I care about
-#   1: Inside book front matter
-#   2: Inside a refentry
-#   3: Inside a refentry, and we know the filename
-
-$mode = 0;
-$refdata = "";
-$front = "";
-while(<SGML>){
-  # Starting modes
-  if(/<bookinfo>/ || /<docinfo>/){
-    $mode = 1;
-  }
-  elsif(/<refentry>/){
-    $mode = 2;
-  }
-  elsif(/<refentrytitle><phrase[^>]*>([^<]*)<.*$/){
-    $mode = 3;
-    $filename = $1;
-
-    $filename =~ s/struct //;
-    $filename =~ s/typedef //;
-
-    print "Found manpage for $filename\n";
-    open REF, "> $ARGV[1]/$filename.sgml" or
-      die "Couldn't open output file \"$ARGV[1]/$filename.sgml\": $!\n";
-    print REF <<EOF;
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<!-- BEGINFRONTTAG: The following is front matter for the parent book -->
-$front
-<!-- ENDFRONTTAG: End front matter -->
-
-$refdata
-EOF
-    $refdata = "";
-  }
-
-  # Extraction
-  if($mode == 1){
-    chomp $_;
-    $front = "$front<!-- $_ -->\n";
-  }
-  elsif($mode == 2){
-    $refdata = "$refdata$_";
-  }
-  elsif($mode == 3){
-    # There are some fixups which need to be applied
-    if(/<\/refmeta>/){
-      print REF "<manvolnum>9</manvolnum>\n";
-    }
-    if(/<\/refentry>/){
-      print REF <<EOF;
-<refsect1><title>About this document</title>
-<para>
-This documentation was generated with kernel version $ARGV[2].
-</para>
-</refsect1>
-EOF
-    }
-
-    # For some reason, we title the synopsis twice in the main DocBook
-    if(! /<title>Synopsis<\/title>/){
-      if(/<refentrytitle>/){
-	s/struct //;
-	s/typedef //;
-      }
-
-      print REF "$_";
-    }
-  }
-
-  # Ending modes
-  if(/<\/bookinfo>/ || /<\/docinfo>/){
-    $mode = 0;
-  }
-  elsif(/<\/refentry>/){
-    $mode = 0;
-    close REF;
-  }
-}
-
-# And make sure we don't process this unnessesarily
-$ARGV[0] =~ s/\.sgml/.9/;
-`touch $ARGV[0]`;
diff --git a/scripts/ver_linux b/scripts/ver_linux
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -87,7 +87,7 @@ loadkeys -V 2>&1 | awk \
 
 expr --v 2>&1 | awk 'NR==1{print "Sh-utils              ", $NF}'
 
-udevinfo -V | awk '{print "udev                  ", $3}'
+udevinfo -V 2>&1 | grep version | awk '{print "udev                  ", $3}'
 
 if [ -e /proc/modules ]; then
     X=`cat /proc/modules | sed -e "s/ .*$//"`
diff --git a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -446,13 +446,16 @@ static int dummy_file_ioctl (struct file
 	return 0;
 }
 
-static int dummy_file_mmap (struct file *file, unsigned long prot,
+static int dummy_file_mmap (struct file *file, unsigned long reqprot,
+			    unsigned long prot,
 			    unsigned long flags)
 {
 	return 0;
 }
 
-static int dummy_file_mprotect (struct vm_area_struct *vma, unsigned long prot)
+static int dummy_file_mprotect (struct vm_area_struct *vma,
+				unsigned long reqprot,
+				unsigned long prot)
 {
 	return 0;
 }
diff --git a/security/keys/key.c b/security/keys/key.c
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -57,9 +57,10 @@ struct key_user *key_user_lookup(uid_t u
 {
 	struct key_user *candidate = NULL, *user;
 	struct rb_node *parent = NULL;
-	struct rb_node **p = &key_user_tree.rb_node;
+	struct rb_node **p;
 
  try_again:
+	p = &key_user_tree.rb_node;
 	spin_lock(&key_user_lock);
 
 	/* search the tree for a user record with a matching UID */
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -165,30 +165,36 @@ int install_thread_keyring(struct task_s
 
 /*****************************************************************************/
 /*
- * install a fresh process keyring, discarding the old one
+ * make sure a process keyring is installed
  */
 static int install_process_keyring(struct task_struct *tsk)
 {
-	struct key *keyring, *old;
+	unsigned long flags;
+	struct key *keyring;
 	char buf[20];
 	int ret;
 
-	sprintf(buf, "_pid.%u", tsk->tgid);
+	if (!tsk->signal->process_keyring) {
+		sprintf(buf, "_pid.%u", tsk->tgid);
 
-	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
-		goto error;
-	}
+		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+		if (IS_ERR(keyring)) {
+			ret = PTR_ERR(keyring);
+			goto error;
+		}
 
-	task_lock(tsk);
-	old = tsk->process_keyring;
-	tsk->process_keyring = keyring;
-	task_unlock(tsk);
+		/* attach or swap keyrings */
+		spin_lock_irqsave(&tsk->sighand->siglock, flags);
+		if (!tsk->signal->process_keyring) {
+			tsk->signal->process_keyring = keyring;
+			keyring = NULL;
+		}
+		spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
-	ret = 0;
+		key_put(keyring);
+	}
 
-	key_put(old);
+	ret = 0;
  error:
 	return ret;
 
@@ -202,6 +208,7 @@ static int install_process_keyring(struc
 static int install_session_keyring(struct task_struct *tsk,
 				   struct key *keyring)
 {
+	unsigned long flags;
 	struct key *old;
 	char buf[20];
 	int ret;
@@ -221,10 +228,10 @@ static int install_session_keyring(struc
 	}
 
 	/* install the keyring */
-	task_lock(tsk);
-	old = tsk->session_keyring;
-	tsk->session_keyring = keyring;
-	task_unlock(tsk);
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	old = tsk->signal->session_keyring;
+	tsk->signal->session_keyring = keyring;
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
 	ret = 0;
 
@@ -236,42 +243,59 @@ static int install_session_keyring(struc
 
 /*****************************************************************************/
 /*
- * copy the keys for fork
+ * copy the keys in a thread group for fork without CLONE_THREAD
  */
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+int copy_thread_group_keys(struct task_struct *tsk)
 {
-	int ret = 0;
+	unsigned long flags;
 
-	key_check(tsk->session_keyring);
-	key_check(tsk->process_keyring);
-	key_check(tsk->thread_keyring);
+	key_check(current->thread_group->session_keyring);
+	key_check(current->thread_group->process_keyring);
 
-	if (tsk->session_keyring)
-		atomic_inc(&tsk->session_keyring->usage);
+	/* no process keyring yet */
+	tsk->signal->process_keyring = NULL;
 
-	if (tsk->process_keyring) {
-		if (clone_flags & CLONE_THREAD) {
-			atomic_inc(&tsk->process_keyring->usage);
-		}
-		else {
-			tsk->process_keyring = NULL;
-			ret = install_process_keyring(tsk);
-		}
-	}
+	/* same session keyring */
+	spin_lock_irqsave(&current->sighand->siglock, flags);
+	tsk->signal->session_keyring =
+		key_get(current->signal->session_keyring);
+	spin_unlock_irqrestore(&current->sighand->siglock, flags);
+
+	return 0;
+
+} /* end copy_thread_group_keys() */
 
+/*****************************************************************************/
+/*
+ * copy the keys for fork
+ */
+int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+{
+	key_check(tsk->thread_keyring);
+
+	/* no thread keyring yet */
 	tsk->thread_keyring = NULL;
-	return ret;
+	return 0;
 
 } /* end copy_keys() */
 
 /*****************************************************************************/
 /*
- * dispose of keys upon exit
+ * dispose of thread group keys upon thread group destruction
+ */
+void exit_thread_group_keys(struct signal_struct *tg)
+{
+	key_put(tg->session_keyring);
+	key_put(tg->process_keyring);
+
+} /* end exit_thread_group_keys() */
+
+/*****************************************************************************/
+/*
+ * dispose of keys upon thread exit
  */
 void exit_keys(struct task_struct *tsk)
 {
-	key_put(tsk->session_keyring);
-	key_put(tsk->process_keyring);
 	key_put(tsk->thread_keyring);
 
 } /* end exit_keys() */
@@ -282,6 +306,7 @@ void exit_keys(struct task_struct *tsk)
  */
 int exec_keys(struct task_struct *tsk)
 {
+	unsigned long flags;
 	struct key *old;
 
 	/* newly exec'd tasks don't get a thread keyring */
@@ -292,8 +317,15 @@ int exec_keys(struct task_struct *tsk)
 
 	key_put(old);
 
-	/* newly exec'd tasks get a fresh process keyring */
-	return install_process_keyring(tsk);
+	/* discard the process keyring from a newly exec'd task */
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	old = tsk->signal->process_keyring;
+	tsk->signal->process_keyring = NULL;
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+	key_put(old);
+
+	return 0;
 
 } /* end exec_keys() */
 
@@ -314,15 +346,6 @@ int suid_keys(struct task_struct *tsk)
  */
 void key_fsuid_changed(struct task_struct *tsk)
 {
-	/* update the ownership of the process keyring */
-	if (tsk->process_keyring) {
-		down_write(&tsk->process_keyring->sem);
-		write_lock(&tsk->process_keyring->lock);
-		tsk->process_keyring->uid = tsk->fsuid;
-		write_unlock(&tsk->process_keyring->lock);
-		up_write(&tsk->process_keyring->sem);
-	}
-
 	/* update the ownership of the thread keyring */
 	if (tsk->thread_keyring) {
 		down_write(&tsk->thread_keyring->sem);
@@ -340,15 +363,6 @@ void key_fsuid_changed(struct task_struc
  */
 void key_fsgid_changed(struct task_struct *tsk)
 {
-	/* update the ownership of the process keyring */
-	if (tsk->process_keyring) {
-		down_write(&tsk->process_keyring->sem);
-		write_lock(&tsk->process_keyring->lock);
-		tsk->process_keyring->gid = tsk->fsgid;
-		write_unlock(&tsk->process_keyring->lock);
-		up_write(&tsk->process_keyring->sem);
-	}
-
 	/* update the ownership of the thread keyring */
 	if (tsk->thread_keyring) {
 		down_write(&tsk->thread_keyring->sem);
@@ -373,7 +387,8 @@ struct key *search_process_keyrings_aux(
 					key_match_func_t match)
 {
 	struct task_struct *tsk = current;
-	struct key *key, *ret, *err, *session;
+	unsigned long flags;
+	struct key *key, *ret, *err, *tmp;
 
 	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
 	 * searchable, but we failed to find a key or we found a negative key;
@@ -407,9 +422,9 @@ struct key *search_process_keyrings_aux(
 	}
 
 	/* search the process keyring second */
-	if (tsk->process_keyring) {
-		key = keyring_search_aux(tsk->process_keyring, type,
-					 description, match);
+	if (tsk->signal->process_keyring) {
+		key = keyring_search_aux(tsk->signal->process_keyring,
+					 type, description, match);
 		if (!IS_ERR(key))
 			goto found;
 
@@ -427,12 +442,17 @@ struct key *search_process_keyrings_aux(
 	}
 
 	/* search the session keyring last */
-	session = tsk->session_keyring;
-	if (!session)
-		session = tsk->user->session_keyring;
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
 
-	key = keyring_search_aux(session, type,
-				 description, match);
+	tmp = tsk->signal->session_keyring;
+	if (!tmp)
+		tmp = tsk->user->session_keyring;
+	atomic_inc(&tmp->usage);
+
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+	key = keyring_search_aux(tmp, type, description, match);
+	key_put(tmp);
 	if (!IS_ERR(key))
 		goto found;
 
@@ -479,6 +499,7 @@ struct key *lookup_user_key(key_serial_t
 			    key_perm_t perm)
 {
 	struct task_struct *tsk = current;
+	unsigned long flags;
 	struct key *key;
 	int ret;
 
@@ -502,7 +523,7 @@ struct key *lookup_user_key(key_serial_t
 		break;
 
 	case KEY_SPEC_PROCESS_KEYRING:
-		if (!tsk->process_keyring) {
+		if (!tsk->signal->process_keyring) {
 			if (!create)
 				goto error;
 
@@ -513,12 +534,12 @@ struct key *lookup_user_key(key_serial_t
 			}
 		}
 
-		key = tsk->process_keyring;
+		key = tsk->signal->process_keyring;
 		atomic_inc(&key->usage);
 		break;
 
 	case KEY_SPEC_SESSION_KEYRING:
-		if (!tsk->session_keyring) {
+		if (!tsk->signal->session_keyring) {
 			/* always install a session keyring upon access if one
 			 * doesn't exist yet */
 			ret = install_session_keyring(
@@ -527,8 +548,10 @@ struct key *lookup_user_key(key_serial_t
 				goto error;
 		}
 
-		key = tsk->session_keyring;
+		spin_lock_irqsave(&tsk->sighand->siglock, flags);
+		key = tsk->signal->session_keyring;
 		atomic_inc(&key->usage);
+		spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 		break;
 
 	case KEY_SPEC_USER_KEYRING:
@@ -592,6 +615,7 @@ struct key *lookup_user_key(key_serial_t
 long join_session_keyring(const char *name)
 {
 	struct task_struct *tsk = current;
+	unsigned long flags;
 	struct key *keyring;
 	long ret;
 
@@ -601,7 +625,9 @@ long join_session_keyring(const char *na
 		if (ret < 0)
 			goto error;
 
-		ret = tsk->session_keyring->serial;
+		spin_lock_irqsave(&tsk->sighand->siglock, flags);
+		ret = tsk->signal->session_keyring->serial;
+		spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 		goto error;
 	}
 
@@ -628,10 +654,9 @@ long join_session_keyring(const char *na
 	if (ret < 0)
 		goto error2;
 
+	ret = keyring->serial;
 	key_put(keyring);
 
-	ret = tsk->session_keyring->serial;
-
  error2:
 	up(&key_session_sem);
  error:
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -34,6 +34,8 @@ static int call_request_key(struct key *
 			    const char *callout_info)
 {
 	struct task_struct *tsk = current;
+	unsigned long flags;
+	key_serial_t prkey, sskey;
 	char *argv[10], *envp[3], uid_str[12], gid_str[12];
 	char key_str[12], keyring_str[3][12];
 	int i;
@@ -46,16 +48,25 @@ static int call_request_key(struct key *
 	sprintf(key_str, "%d", key->serial);
 
 	/* we specify the process's default keyrings */
-	task_lock(current);
 	sprintf(keyring_str[0], "%d",
 		tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
-	sprintf(keyring_str[1], "%d",
-		tsk->process_keyring ? tsk->process_keyring->serial : 0);
-	sprintf(keyring_str[2], "%d",
-		(tsk->session_keyring ?
-		 tsk->session_keyring->serial :
-		 tsk->user->session_keyring->serial));
-	task_unlock(tsk);
+
+	prkey = 0;
+	if (tsk->signal->process_keyring)
+		prkey = tsk->signal->process_keyring->serial;
+
+	sskey = 0;
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	if (tsk->signal->session_keyring)
+		sskey = tsk->signal->session_keyring->serial;
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+
+	if (!sskey)
+		sskey = tsk->user->session_keyring->serial;
+
+	sprintf(keyring_str[1], "%d", prkey);
+	sprintf(keyring_str[2], "%d", sskey);
 
 	/* set up a minimal environment */
 	i = 0;
@@ -166,8 +177,19 @@ static struct key *__request_key_constru
 	now = current_kernel_time();
 	key->expiry = now.tv_sec + key_negative_timeout;
 
-	if (current->session_keyring)
-		key_link(current->session_keyring, key);
+	if (current->signal->session_keyring) {
+		unsigned long flags;
+		struct key *keyring;
+
+		spin_lock_irqsave(&current->sighand->siglock, flags);
+		keyring = current->signal->session_keyring;
+		atomic_inc(&keyring->usage);
+		spin_unlock_irqrestore(&current->sighand->siglock, flags);
+
+		key_link(keyring, key);
+		key_put(keyring);
+	}
+
 	key_put(key);
 
 	/* notify anyone who was waiting */
@@ -274,8 +296,8 @@ struct key *request_key(struct key_type 
 
 		/* - get hold of the user's construction queue */
 		user = key_user_lookup(current->fsuid);
-		if (IS_ERR(user)) {
-			key = ERR_PTR(PTR_ERR(user));
+		if (!user) {
+			key = ERR_PTR(-ENOMEM);
 			goto error;
 		}
 
diff --git a/security/seclvl.c b/security/seclvl.c
--- a/security/seclvl.c
+++ b/security/seclvl.c
@@ -170,7 +170,7 @@ seclvl_attr_show(struct kobject *kobj, s
 /**
  * Callback function pointers for show and store
  */
-struct sysfs_ops seclvlfs_sysfs_ops = {
+static struct sysfs_ops seclvlfs_sysfs_ops = {
 	.show = seclvl_attr_show,
 	.store = seclvl_attr_store,
 };
@@ -275,7 +275,7 @@ seclvl_write_file(struct seclvl_obj *obj
 }
 
 /* Generate sysfs_attr_seclvl */
-struct seclvl_attribute sysfs_attr_seclvl =
+static struct seclvl_attribute sysfs_attr_seclvl =
 __ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
        seclvl_write_file);
 
@@ -386,7 +386,7 @@ seclvl_write_passwd(struct seclvl_obj *o
 }
 
 /* Generate sysfs_attr_passwd */
-struct seclvl_attribute sysfs_attr_passwd =
+static struct seclvl_attribute sysfs_attr_passwd =
 __ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
        seclvl_write_passwd);
 
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -1,6 +1,6 @@
 config SECURITY_SELINUX
 	bool "NSA SELinux Support"
-	depends on SECURITY && NET
+	depends on SECURITY && NET && INET
 	default n
 	help
 	  This selects NSA Security-Enhanced Linux (SELinux).
@@ -76,12 +76,22 @@ config SECURITY_SELINUX_AVC_STATS
 	  /selinux/avc/cache_stats, which may be monitored via
 	  tools such as avcstat.
 
-config SECURITY_SELINUX_MLS
-	bool "NSA SELinux MLS policy (EXPERIMENTAL)"
-	depends on SECURITY_SELINUX && EXPERIMENTAL
-	default n
+config SECURITY_SELINUX_CHECKREQPROT_VALUE
+	int "NSA SELinux checkreqprot default value"
+	depends on SECURITY_SELINUX
+	range 0 1
+	default 1
 	help
-	  This enables the NSA SELinux Multi-Level Security (MLS) policy in
-	  addition to the default RBAC/TE policy.  This policy is
-	  experimental and has not been configured for use.  Unless you
-	  specifically want to experiment with MLS, say N.
+	  This option sets the default value for the 'checkreqprot' flag
+	  that determines whether SELinux checks the protection requested
+	  by the application or the protection that will be applied by the
+	  kernel (including any implied execute for read-implies-exec) for
+	  mmap and mprotect calls.  If this option is set to 0 (zero),
+	  SELinux will default to checking the protection that will be applied
+	  by the kernel.  If this option is set to 1 (one), SELinux will
+	  default to checking the protection requested by the application.
+	  The checkreqprot flag may be changed from the default via the
+	  'checkreqprot=' boot parameter.  It may also be changed at runtime
+	  via /selinux/checkreqprot if authorized by policy.
+
+	  If you are unsure how to answer this question, answer 1.
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -139,7 +139,7 @@ static inline int avc_hash(u32 ssid, u32
  * @tclass: target security class
  * @av: access vector
  */
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
@@ -199,7 +199,7 @@ void avc_dump_av(struct audit_buffer *ab
  * @tsid: target security identifier
  * @tclass: target security class
  */
-void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
+static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
 {
 	int rc;
 	char *scontext;
@@ -532,7 +532,6 @@ void avc_audit(u32 ssid, u32 tsid,
                u16 tclass, u32 requested,
                struct av_decision *avd, int result, struct avc_audit_data *a)
 {
-	struct task_struct *tsk = current;
 	struct inode *inode = NULL;
 	u32 denied, audited;
 	struct audit_buffer *ab;
@@ -556,39 +555,6 @@ void avc_audit(u32 ssid, u32 tsid,
 	audit_log_format(ab, "avc:  %s ", denied ? "denied" : "granted");
 	avc_dump_av(ab, tclass,audited);
 	audit_log_format(ab, " for ");
-	if (a && a->tsk)
-		tsk = a->tsk;
-	if (tsk && tsk->pid) {
-		struct mm_struct *mm;
-		struct vm_area_struct *vma;
-		audit_log_format(ab, " pid=%d", tsk->pid);
-		if (tsk == current)
-			mm = current->mm;
-		else
-			mm = get_task_mm(tsk);
-		if (mm) {
-			if (down_read_trylock(&mm->mmap_sem)) {
-				vma = mm->mmap;
-				while (vma) {
-					if ((vma->vm_flags & VM_EXECUTABLE) &&
-					    vma->vm_file) {
-						audit_log_d_path(ab, "exe=",
-							vma->vm_file->f_dentry,
-							vma->vm_file->f_vfsmnt);
-						break;
-					}
-					vma = vma->vm_next;
-				}
-				up_read(&mm->mmap_sem);
-			} else {
-				audit_log_format(ab, " comm=%s", tsk->comm);
-			}
-			if (tsk != current)
-				mmput(mm);
-		} else {
-			audit_log_format(ab, " comm=%s", tsk->comm);
-		}
-	}
 	if (a) {
 		switch (a->type) {
 		case AVC_AUDIT_DATA_IPC:
@@ -828,136 +794,6 @@ out:
 	return rc;
 }
 
-static int avc_update_cache(u32 event, u32 ssid, u32 tsid,
-                            u16 tclass, u32 perms)
-{
-	struct avc_node *node;
-	int i;
-
-	rcu_read_lock();
-
-	if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
-		/* apply to all matching nodes */
-		for (i = 0; i < AVC_CACHE_SLOTS; i++) {
-			list_for_each_entry_rcu(node, &avc_cache.slots[i], list) {
-				if (avc_sidcmp(ssid, node->ae.ssid) &&
-				    avc_sidcmp(tsid, node->ae.tsid) &&
-				    tclass == node->ae.tclass ) {
-					avc_update_node(event, perms, node->ae.ssid,
-							node->ae.tsid, node->ae.tclass);
-				}
-			}
-		}
-	} else {
-		/* apply to one node */
-		avc_update_node(event, perms, ssid, tsid, tclass);
-	}
-
-	rcu_read_unlock();
-
-	return 0;
-}
-
-static int avc_control(u32 event, u32 ssid, u32 tsid,
-                       u16 tclass, u32 perms,
-                       u32 seqno, u32 *out_retained)
-{
-	struct avc_callback_node *c;
-	u32 tretained = 0, cretained = 0;
-	int rc = 0;
-
-	/*
-	 * try_revoke only removes permissions from the cache
-	 * state if they are not retained by the object manager.
-	 * Hence, try_revoke must wait until after the callbacks have
-	 * been invoked to update the cache state.
-	 */
-	if (event != AVC_CALLBACK_TRY_REVOKE)
-		avc_update_cache(event,ssid,tsid,tclass,perms);
-
-	for (c = avc_callbacks; c; c = c->next)
-	{
-		if ((c->events & event) &&
-		    avc_sidcmp(c->ssid, ssid) &&
-		    avc_sidcmp(c->tsid, tsid) &&
-		    c->tclass == tclass &&
-		    (c->perms & perms)) {
-			cretained = 0;
-			rc = c->callback(event, ssid, tsid, tclass,
-					 (c->perms & perms),
-					 &cretained);
-			if (rc)
-				goto out;
-			tretained |= cretained;
-		}
-	}
-
-	if (event == AVC_CALLBACK_TRY_REVOKE) {
-		/* revoke any unretained permissions */
-		perms &= ~tretained;
-		avc_update_cache(event,ssid,tsid,tclass,perms);
-		*out_retained = tretained;
-	}
-
-	avc_latest_notif_update(seqno, 0);
-
-out:
-	return rc;
-}
-
-/**
- * avc_ss_grant - Grant previously denied permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- */
-int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass,
-                 u32 perms, u32 seqno)
-{
-	return avc_control(AVC_CALLBACK_GRANT,
-			   ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
- * avc_ss_try_revoke - Try to revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @out_retained: subset of @perms that are retained
- *
- * Try to revoke previously granted permissions, but
- * only if they are not retained as migrated permissions.
- * Return the subset of permissions that are retained via @out_retained.
- */
-int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass,
-                      u32 perms, u32 seqno, u32 *out_retained)
-{
-	return avc_control(AVC_CALLBACK_TRY_REVOKE,
-			   ssid, tsid, tclass, perms, seqno, out_retained);
-}
-
-/**
- * avc_ss_revoke - Revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- *
- * Revoke previously granted permissions, even if
- * they are retained as migrated permissions.
- */
-int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass,
-                  u32 perms, u32 seqno)
-{
-	return avc_control(AVC_CALLBACK_REVOKE,
-			   ssid, tsid, tclass, perms, seqno, NULL);
-}
-
 /**
  * avc_ss_reset - Flush the cache and revalidate migrated permissions.
  * @seqno: policy sequence number
@@ -991,46 +827,6 @@ out:
 }
 
 /**
- * avc_ss_set_auditallow - Enable or disable auditing of granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @enable: enable flag.
- */
-int avc_ss_set_auditallow(u32 ssid, u32 tsid, u16 tclass,
-                          u32 perms, u32 seqno, u32 enable)
-{
-	if (enable)
-		return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE,
-				   ssid, tsid, tclass, perms, seqno, NULL);
-	else
-		return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE,
-				   ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
- * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @enable: enable flag.
- */
-int avc_ss_set_auditdeny(u32 ssid, u32 tsid, u16 tclass,
-                         u32 perms, u32 seqno, u32 enable)
-{
-	if (enable)
-		return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE,
-				   ssid, tsid, tclass, perms, seqno, NULL);
-	else
-		return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE,
-				   ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
  * avc_has_perm_noaudit - Check permissions but perform no auditing.
  * @ssid: source security identifier
  * @tsid: target security identifier
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -10,6 +10,8 @@
  *
  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
  *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *                          <dgoeddel@trustedcs.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,
@@ -65,6 +67,7 @@
 #include <linux/hugetlb.h>
 #include <linux/personality.h>
 #include <linux/sysctl.h>
+#include <linux/audit.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -589,7 +592,8 @@ next_inode:
 		spin_unlock(&sbsec->isec_lock);
 		inode = igrab(inode);
 		if (inode) {
-			inode_doinit(inode);
+			if (!IS_PRIVATE (inode))
+				inode_doinit(inode);
 			iput(inode);
 		}
 		spin_lock(&sbsec->isec_lock);
@@ -668,6 +672,8 @@ static inline u16 socket_type_to_securit
 			return SECCLASS_NETLINK_IP6FW_SOCKET;
 		case NETLINK_DNRTMSG:
 			return SECCLASS_NETLINK_DNRT_SOCKET;
+		case NETLINK_KOBJECT_UEVENT:
+			return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
 		default:
 			return SECCLASS_NETLINK_SOCKET;
 		}
@@ -826,7 +832,9 @@ static int inode_doinit_with_dentry(stru
 				       __FUNCTION__, context, -rc,
 				       inode->i_sb->s_id, inode->i_ino);
 				kfree(context);
-				goto out;
+				/* Leave with the unlabeled SID */
+				rc = 0;
+				break;
 			}
 		}
 		kfree(context);
@@ -871,18 +879,8 @@ static int inode_doinit_with_dentry(stru
 	isec->initialized = 1;
 
 out:
-	if (inode->i_sock) {
-		struct socket *sock = SOCKET_I(inode);
-		if (sock->sk) {
-			isec->sclass = socket_type_to_security_class(sock->sk->sk_family,
-			                                             sock->sk->sk_type,
-			                                             sock->sk->sk_protocol);
-		} else {
-			isec->sclass = SECCLASS_SOCKET;
-		}
-	} else {
+	if (isec->sclass == SECCLASS_FILE)
 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
-	}
 
 	if (hold_sem)
 		up(&isec->sem);
@@ -918,9 +916,9 @@ static inline u32 signal_to_av(int sig)
 
 /* Check permission betweeen a pair of tasks, e.g. signal checks,
    fork check, ptrace check, etc. */
-int task_has_perm(struct task_struct *tsk1,
-		  struct task_struct *tsk2,
-		  u32 perms)
+static int task_has_perm(struct task_struct *tsk1,
+			 struct task_struct *tsk2,
+			 u32 perms)
 {
 	struct task_security_struct *tsec1, *tsec2;
 
@@ -931,8 +929,8 @@ int task_has_perm(struct task_struct *ts
 }
 
 /* Check whether a task is allowed to use a capability. */
-int task_has_capability(struct task_struct *tsk,
-			int cap)
+static int task_has_capability(struct task_struct *tsk,
+			       int cap)
 {
 	struct task_security_struct *tsec;
 	struct avc_audit_data ad;
@@ -948,8 +946,8 @@ int task_has_capability(struct task_stru
 }
 
 /* Check whether a task is allowed to use a system operation. */
-int task_has_system(struct task_struct *tsk,
-		    u32 perms)
+static int task_has_system(struct task_struct *tsk,
+			   u32 perms)
 {
 	struct task_security_struct *tsec;
 
@@ -962,10 +960,10 @@ int task_has_system(struct task_struct *
 /* Check whether a task has a particular permission to an inode.
    The 'adp' parameter is optional and allows other audit
    data to be passed (e.g. the dentry). */
-int inode_has_perm(struct task_struct *tsk,
-		   struct inode *inode,
-		   u32 perms,
-		   struct avc_audit_data *adp)
+static int inode_has_perm(struct task_struct *tsk,
+			  struct inode *inode,
+			  u32 perms,
+			  struct avc_audit_data *adp)
 {
 	struct task_security_struct *tsec;
 	struct inode_security_struct *isec;
@@ -1187,10 +1185,10 @@ static inline int may_rename(struct inod
 }
 
 /* Check whether a task can perform a filesystem operation. */
-int superblock_has_perm(struct task_struct *tsk,
-			struct super_block *sb,
-			u32 perms,
-			struct avc_audit_data *ad)
+static int superblock_has_perm(struct task_struct *tsk,
+			       struct super_block *sb,
+			       u32 perms,
+			       struct avc_audit_data *ad)
 {
 	struct task_security_struct *tsec;
 	struct superblock_security_struct *sbsec;
@@ -1247,7 +1245,7 @@ static inline u32 file_to_av(struct file
 }
 
 /* Set an inode's SID to a specified value. */
-int inode_security_set_sid(struct inode *inode, u32 sid)
+static int inode_security_set_sid(struct inode *inode, u32 sid)
 {
 	struct inode_security_struct *isec = inode->i_security;
 	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
@@ -1855,6 +1853,13 @@ static void selinux_bprm_post_apply_cred
 			initrlim = init_task.signal->rlim+i;
 			rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur);
 		}
+		if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
+			/*
+			 * This will cause RLIMIT_CPU calculations
+			 * to be refigured.
+			 */
+			current->it_prof_expires = jiffies_to_cputime(1);
+		}
 	}
 
 	/* Wake up the parent if it is waiting so that it can
@@ -2203,6 +2208,11 @@ static int selinux_inode_setxattr(struct
 	if (rc)
 		return rc;
 
+	rc = security_validate_transition(isec->sid, newsid, tsec->sid,
+	                                  isec->sclass);
+	if (rc)
+		return rc;
+
 	return avc_has_perm(newsid,
 			    sbsec->sid,
 			    SECCLASS_FILESYSTEM,
@@ -2407,6 +2417,7 @@ static int selinux_file_ioctl(struct fil
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+#ifndef CONFIG_PPC32
 	if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
 		/*
 		 * We are making executable an anonymous mapping or a
@@ -2417,6 +2428,7 @@ static int file_map_prot_check(struct fi
 		if (rc)
 			return rc;
 	}
+#endif
 
 	if (file) {
 		/* read access is always possible with a mapping */
@@ -2434,27 +2446,36 @@ static int file_map_prot_check(struct fi
 	return 0;
 }
 
-static int selinux_file_mmap(struct file *file, unsigned long prot, unsigned long flags)
+static int selinux_file_mmap(struct file *file, unsigned long reqprot,
+			     unsigned long prot, unsigned long flags)
 {
 	int rc;
 
-	rc = secondary_ops->file_mmap(file, prot, flags);
+	rc = secondary_ops->file_mmap(file, reqprot, prot, flags);
 	if (rc)
 		return rc;
 
+	if (selinux_checkreqprot)
+		prot = reqprot;
+
 	return file_map_prot_check(file, prot,
 				   (flags & MAP_TYPE) == MAP_SHARED);
 }
 
 static int selinux_file_mprotect(struct vm_area_struct *vma,
+				 unsigned long reqprot,
 				 unsigned long prot)
 {
 	int rc;
 
-	rc = secondary_ops->file_mprotect(vma, prot);
+	rc = secondary_ops->file_mprotect(vma, reqprot, prot);
 	if (rc)
 		return rc;
 
+	if (selinux_checkreqprot)
+		prot = reqprot;
+
+#ifndef CONFIG_PPC32
 	if (vma->vm_file != NULL && vma->anon_vma != NULL && (prot & PROT_EXEC)) {
 		/*
 		 * We are making executable a file mapping that has
@@ -2466,6 +2487,7 @@ static int selinux_file_mprotect(struct 
 		if (rc)
 			return rc;
 	}
+#endif
 
 	return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
 }
@@ -2833,8 +2855,7 @@ static int selinux_parse_skb_ipv6(struct
 
 	nexthdr = ip6->nexthdr;
 	offset += sizeof(_ipv6h);
-	offset = ipv6_skip_exthdr(skb, offset, &nexthdr,
-				  skb->tail - skb->head - offset);
+	offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
 	if (offset < 0)
 		goto out;
 
@@ -2949,18 +2970,15 @@ out:
 static void selinux_socket_post_create(struct socket *sock, int family,
 				       int type, int protocol, int kern)
 {
-	int err;
 	struct inode_security_struct *isec;
 	struct task_security_struct *tsec;
 
-	err = inode_doinit(SOCK_INODE(sock));
-	if (err < 0)
-		return;
 	isec = SOCK_INODE(sock)->i_security;
 
 	tsec = current->security;
 	isec->sclass = socket_type_to_security_class(family, type, protocol);
 	isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
+	isec->initialized = 1;
 
 	return;
 }
@@ -3064,7 +3082,53 @@ out:
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
-	return socket_has_perm(current, sock, SOCKET__CONNECT);
+	struct inode_security_struct *isec;
+	int err;
+
+	err = socket_has_perm(current, sock, SOCKET__CONNECT);
+	if (err)
+		return err;
+
+	/*
+	 * If a TCP socket, check name_connect permission for the port.
+	 */
+	isec = SOCK_INODE(sock)->i_security;
+	if (isec->sclass == SECCLASS_TCP_SOCKET) {
+		struct sock *sk = sock->sk;
+		struct avc_audit_data ad;
+		struct sockaddr_in *addr4 = NULL;
+		struct sockaddr_in6 *addr6 = NULL;
+		unsigned short snum;
+		u32 sid;
+
+		if (sk->sk_family == PF_INET) {
+			addr4 = (struct sockaddr_in *)address;
+			if (addrlen != sizeof(struct sockaddr_in))
+				return -EINVAL;
+			snum = ntohs(addr4->sin_port);
+		} else {
+			addr6 = (struct sockaddr_in6 *)address;
+			if (addrlen != sizeof(struct sockaddr_in6))
+				return -EINVAL;
+			snum = ntohs(addr6->sin6_port);
+		}
+
+		err = security_port_sid(sk->sk_family, sk->sk_type,
+					sk->sk_protocol, snum, &sid);
+		if (err)
+			goto out;
+
+		AVC_AUDIT_DATA_INIT(&ad,NET);
+		ad.u.net.dport = htons(snum);
+		ad.u.net.family = sk->sk_family;
+		err = avc_has_perm(isec->sid, sid, isec->sclass,
+				   TCP_SOCKET__NAME_CONNECT, &ad);
+		if (err)
+			goto out;
+	}
+
+out:
+	return err;
 }
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
@@ -3082,14 +3146,12 @@ static int selinux_socket_accept(struct 
 	if (err)
 		return err;
 
-	err = inode_doinit(SOCK_INODE(newsock));
-	if (err < 0)
-		return err;
 	newisec = SOCK_INODE(newsock)->i_security;
 
 	isec = SOCK_INODE(sock)->i_security;
 	newisec->sclass = isec->sclass;
 	newisec->sid = isec->sid;
+	newisec->initialized = 1;
 
 	return 0;
 }
@@ -3356,6 +3418,15 @@ static int selinux_nlmsg_perm(struct soc
 	
 	err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
 	if (err) {
+		if (err == -EINVAL) {
+			audit_log(current->audit_context,
+				  "SELinux:  unrecognized netlink message"
+				  " type=%hu for sclass=%hu\n",
+				  nlh->nlmsg_type, isec->sclass);
+			if (!selinux_enforcing)
+				err = 0;
+		}
+
 		/* Ignore */
 		if (err == -ENOENT)
 			err = 0;
@@ -3596,7 +3667,7 @@ static void msg_msg_free_security(struct
 }
 
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
-			u16 sclass, u32 perms)
+			u32 perms)
 {
 	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
@@ -3608,7 +3679,7 @@ static int ipc_has_perm(struct kern_ipc_
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = ipc_perms->key;
 
-	return avc_has_perm(tsec->sid, isec->sid, sclass, perms, &ad);
+	return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -3693,7 +3764,7 @@ static int selinux_msg_queue_msgctl(stru
 		return 0;
 	}
 
-	err = ipc_has_perm(&msq->q_perm, SECCLASS_MSGQ, perms);
+	err = ipc_has_perm(&msq->q_perm, perms);
 	return err;
 }
 
@@ -3845,7 +3916,7 @@ static int selinux_shm_shmctl(struct shm
 		return 0;
 	}
 
-	err = ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms);
+	err = ipc_has_perm(&shp->shm_perm, perms);
 	return err;
 }
 
@@ -3864,7 +3935,7 @@ static int selinux_shm_shmat(struct shmi
 	else
 		perms = SHM__READ | SHM__WRITE;
 
-	return ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms);
+	return ipc_has_perm(&shp->shm_perm, perms);
 }
 
 /* Semaphore security operations */
@@ -3953,7 +4024,7 @@ static int selinux_sem_semctl(struct sem
 		return 0;
 	}
 
-	err = ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms);
+	err = ipc_has_perm(&sma->sem_perm, perms);
 	return err;
 }
 
@@ -3967,18 +4038,13 @@ static int selinux_sem_semop(struct sem_
 	else
 		perms = SEM__READ;
 
-	return ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms);
+	return ipc_has_perm(&sma->sem_perm, perms);
 }
 
 static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 {
-	struct ipc_security_struct *isec = ipcp->security;
-	u16 sclass = SECCLASS_IPC;
 	u32 av = 0;
 
-	if (isec && isec->magic == SELINUX_MAGIC)
-		sclass = isec->sclass;
-
 	av = 0;
 	if (flag & S_IRUGO)
 		av |= IPC__UNIX_READ;
@@ -3988,11 +4054,11 @@ static int selinux_ipc_permission(struct
 	if (av == 0)
 		return 0;
 
-	return ipc_has_perm(ipcp, sclass, av);
+	return ipc_has_perm(ipcp, av);
 }
 
 /* module stacking operations */
-int selinux_register_security (const char *name, struct security_operations *ops)
+static int selinux_register_security (const char *name, struct security_operations *ops)
 {
 	if (secondary_ops != original_ops) {
 		printk(KERN_INFO "%s:  There is already a secondary security "
@@ -4009,7 +4075,7 @@ int selinux_register_security (const cha
 	return 0;
 }
 
-int selinux_unregister_security (const char *name, struct security_operations *ops)
+static int selinux_unregister_security (const char *name, struct security_operations *ops)
 {
 	if (ops != secondary_ops) {
 		printk (KERN_INFO "%s:  trying to unregister a security module "
@@ -4079,6 +4145,7 @@ static int selinux_setprocattr(struct ta
 	struct task_security_struct *tsec;
 	u32 sid = 0;
 	int error;
+	char *str = value;
 
 	if (current != p) {
 		/* SELinux only allows a process to change its own
@@ -4103,8 +4170,11 @@ static int selinux_setprocattr(struct ta
 		return error;
 
 	/* Obtain a SID for the context, if one was specified. */
-	if (size) {
-		int error;
+	if (size && str[1] && str[1] != '\n') {
+		if (str[size-1] == '\n') {
+			str[size-1] = 0;
+			size--;
+		}
 		error = security_context_to_sid(value, size, &sid);
 		if (error)
 			return error;
@@ -4172,7 +4242,7 @@ static int selinux_setprocattr(struct ta
 	return size;
 }
 
-struct security_operations selinux_ops = {
+static struct security_operations selinux_ops = {
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
@@ -4321,7 +4391,7 @@ struct security_operations selinux_ops =
 #endif
 };
 
-__init int selinux_init(void)
+static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h
--- a/security/selinux/include/av_inherit.h
+++ b/security/selinux/include/av_inherit.h
@@ -28,3 +28,4 @@
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL)
+   S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL)
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -25,6 +25,7 @@
    S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn")
    S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom")
    S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind")
+   S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NAME_CONNECT, "name_connect")
    S_(SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind")
    S_(SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind")
    S_(SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv")
@@ -83,6 +84,7 @@
    S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
    S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
    S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
+   S_(SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, "setcheckreqprot")
    S_(SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
@@ -116,6 +118,8 @@
    S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_TTY_CONFIG, "sys_tty_config")
    S_(SECCLASS_CAPABILITY, CAPABILITY__MKNOD, "mknod")
    S_(SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease")
+   S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_WRITE, "audit_write")
+   S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_CONTROL, "audit_control")
    S_(SECCLASS_PASSWD, PASSWD__PASSWD, "passwd")
    S_(SECCLASS_PASSWD, PASSWD__CHFN, "chfn")
    S_(SECCLASS_PASSWD, PASSWD__CHSH, "chsh")
@@ -216,6 +220,8 @@
    S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_WRITE, "nlmsg_write")
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READ, "nlmsg_read")
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write")
+   S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay")
+   S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write")
    S_(SECCLASS_DBUS, DBUS__ACQUIRE_SVC, "acquire_svc")
@@ -228,3 +234,5 @@
    S_(SECCLASS_NSCD, NSCD__SHMEMPWD, "shmempwd")
    S_(SECCLASS_NSCD, NSCD__SHMEMGRP, "shmemgrp")
    S_(SECCLASS_NSCD, NSCD__SHMEMHOST, "shmemhost")
+   S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
+   S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -253,6 +253,7 @@
 #define TCP_SOCKET__NEWCONN                       0x00800000UL
 #define TCP_SOCKET__ACCEPTFROM                    0x01000000UL
 #define TCP_SOCKET__NODE_BIND                     0x02000000UL
+#define TCP_SOCKET__NAME_CONNECT                  0x04000000UL
 
 #define UDP_SOCKET__IOCTL                         0x00000001UL
 #define UDP_SOCKET__READ                          0x00000002UL
@@ -522,6 +523,7 @@
 #define SECURITY__SETENFORCE                      0x00000080UL
 #define SECURITY__SETBOOL                         0x00000100UL
 #define SECURITY__SETSECPARAM                     0x00000200UL
+#define SECURITY__SETCHECKREQPROT                 0x00000400UL
 
 #define SYSTEM__IPC_INFO                          0x00000001UL
 #define SYSTEM__SYSLOG_READ                       0x00000002UL
@@ -557,6 +559,8 @@
 #define CAPABILITY__SYS_TTY_CONFIG                0x04000000UL
 #define CAPABILITY__MKNOD                         0x08000000UL
 #define CAPABILITY__LEASE                         0x10000000UL
+#define CAPABILITY__AUDIT_WRITE                   0x20000000UL
+#define CAPABILITY__AUDIT_CONTROL                 0x40000000UL
 
 #define PASSWD__PASSWD                            0x00000001UL
 #define PASSWD__CHFN                              0x00000002UL
@@ -836,6 +840,8 @@
 
 #define NETLINK_AUDIT_SOCKET__NLMSG_READ          0x00400000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_WRITE         0x00800000UL
+#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY         0x01000000UL
+#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV      0x02000000UL
 
 #define NETLINK_IP6FW_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_IP6FW_SOCKET__READ                0x00000002UL
@@ -898,3 +904,29 @@
 #define NSCD__SHMEMGRP                            0x00000040UL
 #define NSCD__SHMEMHOST                           0x00000080UL
 
+#define ASSOCIATION__SENDTO                       0x00000001UL
+#define ASSOCIATION__RECVFROM                     0x00000002UL
+
+#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL      0x00000001UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__READ       0x00000002UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__WRITE      0x00000004UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__CREATE     0x00000008UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__GETATTR    0x00000010UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__SETATTR    0x00000020UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__LOCK       0x00000040UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELFROM 0x00000080UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELTO  0x00000100UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__APPEND     0x00000200UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__BIND       0x00000400UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__CONNECT    0x00000800UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__LISTEN     0x00001000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__ACCEPT     0x00002000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__GETOPT     0x00004000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__SETOPT     0x00008000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__SHUTDOWN   0x00010000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__RECVFROM   0x00020000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__SENDTO     0x00040000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__RECV_MSG   0x00080000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG   0x00100000UL
+#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND  0x00200000UL
+
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -93,13 +93,6 @@ struct avc_cache_stats
 };
 
 /*
- * AVC display support
- */
-struct audit_buffer;
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
-void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass);
-
-/*
  * AVC operations
  */
 
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -8,20 +8,7 @@
 
 #include "flask.h"
 
-int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
-
-int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno,
-		      u32 *out_retained);
-
-int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
-
 int avc_ss_reset(u32 seqno);
 
-int avc_ss_set_auditallow(u32 ssid, u32 tsid, u16 tclass, u32 perms,
-			  u32 seqno, u32 enable);
-
-int avc_ss_set_auditdeny(u32 ssid, u32 tsid, u16 tclass, u32 perms,
-			 u32 seqno, u32 enable);
-
 #endif /* _SELINUX_AVC_SS_H_ */
 
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -56,3 +56,5 @@
     S_("netlink_dnrt_socket")
     S_("dbus")
     S_("nscd")
+    S_("association")
+    S_("netlink_kobject_uevent_socket")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -58,6 +58,8 @@
 #define SECCLASS_NETLINK_DNRT_SOCKET                     51
 #define SECCLASS_DBUS                                    52
 #define SECCLASS_NSCD                                    53
+#define SECCLASS_ASSOCIATION                             54
+#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET           55
 
 /*
  * Security identifier indices for initial entities
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -107,6 +107,6 @@ struct sk_security_struct {
 	u32 peer_sid;			/* SID of peer */
 };
 
-extern int inode_security_set_sid(struct inode *inode, u32 sid);
+extern unsigned int selinux_checkreqprot;
 
 #endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -21,10 +21,12 @@
 #define POLICYDB_VERSION_BOOL		16
 #define POLICYDB_VERSION_IPV6		17
 #define POLICYDB_VERSION_NLCLASS	18
+#define POLICYDB_VERSION_VALIDATETRANS	19
+#define POLICYDB_VERSION_MLS		19
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_NLCLASS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_MLS
 
 #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
 extern int selinux_enabled;
@@ -32,11 +34,7 @@ extern int selinux_enabled;
 #define selinux_enabled 1
 #endif
 
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-#define selinux_mls_enabled 1
-#else
-#define selinux_mls_enabled 0
-#endif
+extern int selinux_mls_enabled;
 
 int security_load_policy(void * data, size_t len);
 
@@ -79,6 +77,9 @@ int security_netif_sid(char *name, u32 *
 int security_node_sid(u16 domain, void *addr, u32 addrlen,
 	u32 *out_sid);
 
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                 u16 tclass);
+
 #define SECURITY_FS_USE_XATTR		1 /* use xattr */
 #define SECURITY_FS_USE_TRANS		2 /* use transition SIDs, e.g. devpts/tmpfs */
 #define SECURITY_FS_USE_TASK		3 /* use task SIDs, e.g. pipefs/sockfs */
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -91,13 +91,12 @@ static struct nlmsg_perm nlmsg_xfrm_perm
 
 static struct nlmsg_perm nlmsg_audit_perms[] =
 {
-	{ AUDIT_GET,		NETLINK_AUDIT_SOCKET__NLMSG_READ  },
-	{ AUDIT_SET,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
-	{ AUDIT_LIST,		NETLINK_AUDIT_SOCKET__NLMSG_READ  },
-	{ AUDIT_ADD,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
-	{ AUDIT_DEL,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
-	{ AUDIT_USER,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
-	{ AUDIT_LOGIN,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+	{ AUDIT_GET,		NETLINK_AUDIT_SOCKET__NLMSG_READ     },
+	{ AUDIT_SET,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_LIST,		NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+	{ AUDIT_ADD,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_DEL,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_USER,		NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
 };
 
 
@@ -126,7 +125,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16
 		break;
 
 	case SECCLASS_NETLINK_FIREWALL_SOCKET:
-	case NETLINK_IP6_FW:
+	case SECCLASS_NETLINK_IP6FW_SOCKET:
 		err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms,
 				 sizeof(nlmsg_firewall_perms));
 		break;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -34,6 +34,16 @@
 #include "objsec.h"
 #include "conditional.h"
 
+unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
+
+static int __init checkreqprot_setup(char *str)
+{
+	selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0;
+	return 1;
+}
+__setup("checkreqprot=", checkreqprot_setup);
+
+
 static DECLARE_MUTEX(sel_sem);
 
 /* global data for booleans */
@@ -44,8 +54,8 @@ static int *bool_pending_values = NULL;
 extern void selnl_notify_setenforce(int val);
 
 /* Check whether a task is allowed to use a security operation. */
-int task_has_security(struct task_struct *tsk,
-		      u32 perms)
+static int task_has_security(struct task_struct *tsk,
+			     u32 perms)
 {
 	struct task_security_struct *tsec;
 
@@ -72,6 +82,7 @@ enum sel_inos {
 	SEL_DISABLE,	/* disable SELinux until next reboot */
 	SEL_AVC,	/* AVC management directory */
 	SEL_MEMBER,	/* compute polyinstantiation membership decision */
+	SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
 };
 
 #define TMPBUFLEN	12
@@ -300,6 +311,54 @@ static struct file_operations sel_contex
 	.write		= sel_write_context,
 };
 
+static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
+				     size_t count, loff_t *ppos)
+{
+	char tmpbuf[TMPBUFLEN];
+	ssize_t length;
+
+	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_checkreqprot);
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+static ssize_t sel_write_checkreqprot(struct file * file, const char __user * buf,
+				      size_t count, loff_t *ppos)
+{
+	char *page;
+	ssize_t length;
+	unsigned int new_value;
+
+	length = task_has_security(current, SECURITY__SETCHECKREQPROT);
+	if (length)
+		return length;
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		/* No partial writes. */
+		return -EINVAL;
+	}
+	page = (char*)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	length = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+
+	length = -EINVAL;
+	if (sscanf(page, "%u", &new_value) != 1)
+		goto out;
+
+	selinux_checkreqprot = new_value ? 1 : 0;
+	length = count;
+out:
+	free_page((unsigned long) page);
+	return length;
+}
+static struct file_operations sel_checkreqprot_ops = {
+	.read		= sel_read_checkreqprot,
+	.write		= sel_write_checkreqprot,
+};
 
 /*
  * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
@@ -1182,6 +1241,7 @@ static int sel_fill_super(struct super_b
 		[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
 		[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
 		[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
+		[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
 		/* last one */ {""}
 	};
 	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile
--- a/security/selinux/ss/Makefile
+++ b/security/selinux/ss/Makefile
@@ -5,7 +5,5 @@
 EXTRA_CFLAGS += -Isecurity/selinux/include
 obj-y := ss.o
 
-ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o
-
-ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o
+ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
 
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -31,7 +31,8 @@
 static kmem_cache_t *avtab_node_cachep;
 
 static struct avtab_node*
-avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
+avtab_insert_node(struct avtab *h, int hvalue,
+		  struct avtab_node * prev, struct avtab_node * cur,
 		  struct avtab_key *key, struct avtab_datum *datum)
 {
 	struct avtab_node * newnode;
@@ -53,7 +54,7 @@ avtab_insert_node(struct avtab *h, int h
 	return newnode;
 }
 
-int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
+static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
 {
 	int hvalue;
 	struct avtab_node *prev, *cur, *newnode;
@@ -237,30 +238,6 @@ void avtab_destroy(struct avtab *h)
 }
 
 
-int avtab_map(struct avtab *h,
-	      int (*apply) (struct avtab_key *k,
-			    struct avtab_datum *d,
-			    void *args),
-	      void *args)
-{
-	int i, ret;
-	struct avtab_node *cur;
-
-	if (!h)
-		return 0;
-
-	for (i = 0; i < AVTAB_SIZE; i++) {
-		cur = h->htable[i];
-		while (cur != NULL) {
-			ret = apply(&cur->key, &cur->datum, args);
-			if (ret)
-				return ret;
-			cur = cur->next;
-		}
-	}
-	return 0;
-}
-
 int avtab_init(struct avtab *h)
 {
 	int i;
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -58,14 +58,8 @@ struct avtab {
 };
 
 int avtab_init(struct avtab *);
-int avtab_insert(struct avtab *h, struct avtab_key *k, struct avtab_datum *d);
 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
 void avtab_destroy(struct avtab *h);
-int avtab_map(struct avtab *h,
-	      int (*apply) (struct avtab_key *k,
-			    struct avtab_datum *d,
-			    void *args),
-	      void *args);
 void avtab_hash_eval(struct avtab *h, char *tag);
 
 int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -208,7 +208,7 @@ int cond_index_bool(void *key, void *dat
 	return 0;
 }
 
-int bool_isvalid(struct cond_bool_datum *b)
+static int bool_isvalid(struct cond_bool_datum *b)
 {
 	if (!(b->state == 0 || b->state == 1))
 		return 0;
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h
--- a/security/selinux/ss/constraint.h
+++ b/security/selinux/ss/constraint.h
@@ -31,6 +31,13 @@ struct constraint_expr {
 #define CEXPR_ROLE 2		/* role */
 #define CEXPR_TYPE 4		/* type */
 #define CEXPR_TARGET 8		/* target if set, source otherwise */
+#define CEXPR_XTARGET 16	/* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32		/* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64		/* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128		/* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256		/* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512		/* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024		/* low level 2 vs. high level 2 */
 	u32 attr;		/* attribute */
 
 #define CEXPR_EQ     1		/* == or eq */
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -17,6 +17,7 @@
 
 #include "ebitmap.h"
 #include "mls_types.h"
+#include "security.h"
 
 /*
  * A security context consists of an authenticated user
@@ -26,13 +27,9 @@ struct context {
 	u32 user;
 	u32 role;
 	u32 type;
-#ifdef CONFIG_SECURITY_SELINUX_MLS
 	struct mls_range range;
-#endif
 };
 
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-
 static inline void mls_context_init(struct context *c)
 {
 	memset(&c->range, 0, sizeof(c->range));
@@ -42,6 +39,9 @@ static inline int mls_context_cpy(struct
 {
 	int rc;
 
+	if (!selinux_mls_enabled)
+		return 0;
+
 	dst->range.level[0].sens = src->range.level[0].sens;
 	rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
 	if (rc)
@@ -57,6 +57,9 @@ out:
 
 static inline int mls_context_cmp(struct context *c1, struct context *c2)
 {
+	if (!selinux_mls_enabled)
+		return 1;
+
 	return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
 		ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
 		(c1->range.level[1].sens == c2->range.level[1].sens) &&
@@ -65,27 +68,14 @@ static inline int mls_context_cmp(struct
 
 static inline void mls_context_destroy(struct context *c)
 {
+	if (!selinux_mls_enabled)
+		return;
+
 	ebitmap_destroy(&c->range.level[0].cat);
 	ebitmap_destroy(&c->range.level[1].cat);
 	mls_context_init(c);
 }
 
-#else
-
-static inline void mls_context_init(struct context *c)
-{ }
-
-static inline int mls_context_cpy(struct context *dst, struct context *src)
-{ return 0; }
-
-static inline int mls_context_cmp(struct context *c1, struct context *c2)
-{ return 1; }
-
-static inline void mls_context_destroy(struct context *c)
-{ }
-
-#endif
-
 static inline void context_init(struct context *c)
 {
 	memset(c, 0, sizeof(*c));
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -9,49 +9,6 @@
 #include "ebitmap.h"
 #include "policydb.h"
 
-int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
-{
-	struct ebitmap_node *n1, *n2, *new, *prev;
-
-	ebitmap_init(dst);
-
-	n1 = e1->node;
-	n2 = e2->node;
-	prev = NULL;
-	while (n1 || n2) {
-		new = kmalloc(sizeof(*new), GFP_ATOMIC);
-		if (!new) {
-			ebitmap_destroy(dst);
-			return -ENOMEM;
-		}
-		memset(new, 0, sizeof(*new));
-		if (n1 && n2 && n1->startbit == n2->startbit) {
-			new->startbit = n1->startbit;
-			new->map = n1->map | n2->map;
-			n1 = n1->next;
-			n2 = n2->next;
-		} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
-			new->startbit = n1->startbit;
-			new->map = n1->map;
-			n1 = n1->next;
-		} else {
-			new->startbit = n2->startbit;
-			new->map = n2->map;
-			n2 = n2->next;
-		}
-
-		new->next = NULL;
-		if (prev)
-			prev->next = new;
-		else
-			dst->node = new;
-		prev = new;
-	}
-
-	dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
-	return 0;
-}
-
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
 {
 	struct ebitmap_node *n1, *n2;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -38,7 +38,6 @@ static inline void ebitmap_init(struct e
 }
 
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
-int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -73,81 +73,6 @@ int hashtab_insert(struct hashtab *h, vo
 	return 0;
 }
 
-int hashtab_remove(struct hashtab *h, void *key,
-		   void (*destroy)(void *k, void *d, void *args),
-		   void *args)
-{
-	u32 hvalue;
-	struct hashtab_node *cur, *last;
-
-	if (!h)
-		return -EINVAL;
-
-	hvalue = h->hash_value(h, key);
-	last = NULL;
-	cur = h->htable[hvalue];
-	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
-		last = cur;
-		cur = cur->next;
-	}
-
-	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
-		return -ENOENT;
-
-	if (last == NULL)
-		h->htable[hvalue] = cur->next;
-	else
-		last->next = cur->next;
-
-	if (destroy)
-		destroy(cur->key, cur->datum, args);
-	kfree(cur);
-	h->nel--;
-	return 0;
-}
-
-int hashtab_replace(struct hashtab *h, void *key, void *datum,
-		    void (*destroy)(void *k, void *d, void *args),
-		    void *args)
-{
-	u32 hvalue;
-	struct hashtab_node *prev, *cur, *newnode;
-
-	if (!h)
-		return -EINVAL;
-
-	hvalue = h->hash_value(h, key);
-	prev = NULL;
-	cur = h->htable[hvalue];
-	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
-		prev = cur;
-		cur = cur->next;
-	}
-
-	if (cur && (h->keycmp(h, key, cur->key) == 0)) {
-		if (destroy)
-			destroy(cur->key, cur->datum, args);
-		cur->key = key;
-		cur->datum = datum;
-	} else {
-		newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
-		if (newnode == NULL)
-			return -ENOMEM;
-		memset(newnode, 0, sizeof(*newnode));
-		newnode->key = key;
-		newnode->datum = datum;
-		if (prev) {
-			newnode->next = prev->next;
-			prev->next = newnode;
-		} else {
-			newnode->next = h->htable[hvalue];
-			h->htable[hvalue] = newnode;
-		}
-	}
-
-	return 0;
-}
-
 void *hashtab_search(struct hashtab *h, void *key)
 {
 	u32 hvalue;
@@ -215,44 +140,6 @@ int hashtab_map(struct hashtab *h,
 }
 
 
-void hashtab_map_remove_on_error(struct hashtab *h,
-                                 int (*apply)(void *k, void *d, void *args),
-                                 void (*destroy)(void *k, void *d, void *args),
-                                 void *args)
-{
-	u32 i;
-	int ret;
-	struct hashtab_node *last, *cur, *temp;
-
-	if (!h)
-		return;
-
-	for (i = 0; i < h->size; i++) {
-		last = NULL;
-		cur = h->htable[i];
-		while (cur != NULL) {
-			ret = apply(cur->key, cur->datum, args);
-			if (ret) {
-				if (last)
-					last->next = cur->next;
-				else
-					h->htable[i] = cur->next;
-
-				temp = cur;
-				cur = cur->next;
-				if (destroy)
-					destroy(temp->key, temp->datum, args);
-				kfree(temp);
-				h->nel--;
-			} else {
-				last = cur;
-				cur = cur->next;
-			}
-		}
-	}
-	return;
-}
-
 void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
 {
 	u32 i, chain_len, slots_used, max_chain_len;
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h
--- a/security/selinux/ss/hashtab.h
+++ b/security/selinux/ss/hashtab.h
@@ -54,33 +54,6 @@ struct hashtab *hashtab_create(u32 (*has
 int hashtab_insert(struct hashtab *h, void *k, void *d);
 
 /*
- * Removes the entry with the specified key from the hash table.
- * Applies the specified destroy function to (key,datum,args) for
- * the entry.
- *
- * Returns -ENOENT if no entry has the specified key,
- * -EINVAL for general errors or
- *0 otherwise.
- */
-int hashtab_remove(struct hashtab *h, void *k,
-		   void (*destroy)(void *k, void *d, void *args),
-		   void *args);
-
-/*
- * Insert or replace the specified (key, datum) pair in the specified
- * hash table.  If an entry for the specified key already exists,
- * then the specified destroy function is applied to (key,datum,args)
- * for the entry prior to replacing the entry's contents.
- *
- * Returns -ENOMEM if insufficient space is available,
- * -EINVAL for general errors or
- * 0 otherwise.
- */
-int hashtab_replace(struct hashtab *h, void *k, void *d,
-		    void (*destroy)(void *k, void *d, void *args),
-		    void *args);
-
-/*
  * Searches for the entry with the specified key in the hash table.
  *
  * Returns NULL if no entry has the specified key or
@@ -108,17 +81,6 @@ int hashtab_map(struct hashtab *h,
 		int (*apply)(void *k, void *d, void *args),
 		void *args);
 
-/*
- * Same as hashtab_map, except that if apply returns a non-zero status,
- * then the (key,datum) pair will be removed from the hashtab and the
- * destroy function will be applied to (key,datum,args).
- */
-void hashtab_map_remove_on_error(struct hashtab *h,
-                                 int (*apply)(void *k, void *d, void *args),
-                                 void (*destroy)(void *k, void *d, void *args),
-                                 void *args);
-
-
 /* Fill info with some hash table statistics */
 void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
 
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -3,6 +3,14 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -12,79 +20,47 @@
 #include "services.h"
 
 /*
- * Remove any permissions from `allowed' that are
- * denied by the MLS policy.
- */
-void mls_compute_av(struct context *scontext,
-		    struct context *tcontext,
-		    struct class_datum *tclass,
-		    u32 *allowed)
-{
-	unsigned int rel[2];
-	int l;
-
-	for (l = 0; l < 2; l++)
-		rel[l] = mls_level_relation(scontext->range.level[l],
-					    tcontext->range.level[l]);
-
-	if (rel[1] != MLS_RELATION_EQ) {
-		if (rel[1] != MLS_RELATION_DOM &&
-		    !ebitmap_get_bit(&policydb.trustedreaders, scontext->type - 1) &&
-		    !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
-			/* read(s,t) = (s.high >= t.high) = False */
-			*allowed = (*allowed) & ~(tclass->mlsperms.read);
-		}
-		if (rel[1] != MLS_RELATION_DOMBY &&
-		    !ebitmap_get_bit(&policydb.trustedreaders, tcontext->type - 1) &&
-		    !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
-			/* readby(s,t) = read(t,s) = False */
-			*allowed = (*allowed) & ~(tclass->mlsperms.readby);
-		}
-	}
-	if (((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) ||
-	    ((!mls_level_eq(tcontext->range.level[0],
-			    tcontext->range.level[1])) &&
-	     (rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ))) &&
-	    !ebitmap_get_bit(&policydb.trustedwriters, scontext->type - 1) &&
-	    !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
-		/*
-		 * write(s,t) = ((s.low <= t.low = t.high) or (s.low
-		 * <= t.low <= t.high <= s.high)) = False
-		 */
-		*allowed = (*allowed) & ~(tclass->mlsperms.write);
-	}
-
-	if (((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) ||
-	    ((!mls_level_eq(scontext->range.level[0],
-			    scontext->range.level[1])) &&
-	     (rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ))) &&
-	    !ebitmap_get_bit(&policydb.trustedwriters, tcontext->type - 1) &&
-	    !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
-		/* writeby(s,t) = write(t,s) = False */
-		*allowed = (*allowed) & ~(tclass->mlsperms.writeby);
-	}
-}
-
-/*
  * Return the length in bytes for the MLS fields of the
  * security context string representation of `context'.
  */
 int mls_compute_context_len(struct context * context)
 {
-	int i, l, len;
+	int i, l, len, range;
 
+	if (!selinux_mls_enabled)
+		return 0;
 
-	len = 0;
+	len = 1; /* for the beginning ":" */
 	for (l = 0; l < 2; l++) {
-		len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1;
+		range = 0;
+		len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
 
-		for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
-			if (ebitmap_get_bit(&context->range.level[l].cat, i - 1))
-				len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+		for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
+			if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+				if (range) {
+					range++;
+					continue;
+				}
 
-		if (mls_level_relation(context->range.level[0], context->range.level[1])
-				== MLS_RELATION_EQ)
-			break;
+				len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+				range++;
+			} else {
+				if (range > 1)
+					len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+				range = 0;
+			}
+		}
+		/* Handle case where last category is the end of range */
+		if (range > 1)
+			len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+
+		if (l == 0) {
+			if (mls_level_eq(&context->range.level[0],
+			                 &context->range.level[1]))
+				break;
+			else
+				len++;
+		}
 	}
 
 	return len;
@@ -95,40 +71,81 @@ int mls_compute_context_len(struct conte
  * the MLS fields of `context' into the string `*scontext'.
  * Update `*scontext' to point to the end of the MLS fields.
  */
-int mls_sid_to_context(struct context *context,
-		       char **scontext)
+void mls_sid_to_context(struct context *context,
+                        char **scontext)
 {
 	char *scontextp;
-	int i, l;
+	int i, l, range, wrote_sep;
+
+	if (!selinux_mls_enabled)
+		return;
 
 	scontextp = *scontext;
 
+	*scontextp = ':';
+	scontextp++;
+
 	for (l = 0; l < 2; l++) {
+		range = 0;
+		wrote_sep = 0;
 		strcpy(scontextp,
 		       policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
 		scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-		*scontextp = ':';
-		scontextp++;
-		for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
+
+		/* categories */
+		for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
 			if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+				if (range) {
+					range++;
+					continue;
+				}
+
+				if (!wrote_sep) {
+					*scontextp++ = ':';
+					wrote_sep = 1;
+				} else
+					*scontextp++ = ',';
 				strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
 				scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-				*scontextp = ',';
-				scontextp++;
+				range++;
+			} else {
+				if (range > 1) {
+					if (range > 2)
+						*scontextp++ = '.';
+					else
+						*scontextp++ = ',';
+
+					strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
+					scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+				}
+				range = 0;
 			}
-		if (mls_level_relation(context->range.level[0], context->range.level[1])
-				!= MLS_RELATION_EQ) {
-			scontextp--;
-			sprintf(scontextp, "-");
-			scontextp++;
+		}
 
-		} else {
-			break;
+		/* Handle case where last category is the end of range */
+		if (range > 1) {
+			if (range > 2)
+				*scontextp++ = '.';
+			else
+				*scontextp++ = ',';
+
+			strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
+			scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+		}
+
+		if (l == 0) {
+			if (mls_level_eq(&context->range.level[0],
+			                 &context->range.level[1]))
+				break;
+			else {
+				*scontextp = '-';
+				scontextp++;
+			}
 		}
 	}
 
 	*scontext = scontextp;
-	return 0;
+	return;
 }
 
 /*
@@ -137,20 +154,19 @@ int mls_sid_to_context(struct context *c
  */
 int mls_context_isvalid(struct policydb *p, struct context *c)
 {
-	unsigned int relation;
 	struct level_datum *levdatum;
 	struct user_datum *usrdatum;
-	struct mls_range_list *rnode;
 	int i, l;
 
+	if (!selinux_mls_enabled)
+		return 1;
+
 	/*
 	 * MLS range validity checks: high must dominate low, low level must
 	 * be valid (category set <-> sensitivity check), and high level must
 	 * be valid (category set <-> sensitivity check)
 	 */
-	relation = mls_level_relation(c->range.level[1],
-				      c->range.level[0]);
-	if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ)))
+	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
 		/* High does not dominate low. */
 		return 0;
 
@@ -185,18 +201,12 @@ int mls_context_isvalid(struct policydb 
 	if (!c->user || c->user > p->p_users.nprim)
 		return 0;
 	usrdatum = p->user_val_to_struct[c->user - 1];
-	for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) {
-		if (mls_range_contains(rnode->range, c->range))
-			break;
-	}
-	if (!rnode)
-		/* user may not be associated with range */
-		return 0;
+	if (!mls_range_contains(usrdatum->range, c->range))
+		return 0; /* user may not be associated with range */
 
 	return 1;
 }
 
-
 /*
  * Set the MLS fields in the security context structure
  * `context' based on the string representation in
@@ -213,23 +223,17 @@ int mls_context_to_sid(char oldc,
 {
 
 	char delim;
-	char *scontextp, *p;
+	char *scontextp, *p, *rngptr;
 	struct level_datum *levdatum;
-	struct cat_datum *catdatum;
+	struct cat_datum *catdatum, *rngdatum;
 	int l, rc = -EINVAL;
 
-	if (!oldc) {
-		/* No MLS component to the security context.  Try
-		   to use a default 'unclassified' value. */
-		levdatum = hashtab_search(policydb.p_levels.table,
-		                          "unclassified");
-		if (!levdatum)
-			goto out;
-		context->range.level[0].sens = levdatum->level->sens;
-		context->range.level[1].sens = context->range.level[0].sens;
-		rc = 0;
+	if (!selinux_mls_enabled)
+		return 0;
+
+	/* No MLS component to the security context. */
+	if (!oldc)
 		goto out;
-	}
 
 	/* Extract low sensitivity. */
 	scontextp = p = *scontext;
@@ -242,13 +246,15 @@ int mls_context_to_sid(char oldc,
 
 	for (l = 0; l < 2; l++) {
 		levdatum = hashtab_search(policydb.p_levels.table, scontextp);
-		if (!levdatum)
+		if (!levdatum) {
+			rc = -EINVAL;
 			goto out;
+		}
 
 		context->range.level[l].sens = levdatum->level->sens;
 
 		if (delim == ':') {
-			/* Extract low category set. */
+			/* Extract category set. */
 			while (1) {
 				scontextp = p;
 				while (*p && *p != ',' && *p != '-')
@@ -257,15 +263,46 @@ int mls_context_to_sid(char oldc,
 				if (delim != 0)
 					*p++ = 0;
 
+				/* Separate into range if exists */
+				if ((rngptr = strchr(scontextp, '.')) != NULL) {
+					/* Remove '.' */
+					*rngptr++ = 0;
+				}
+
 				catdatum = hashtab_search(policydb.p_cats.table,
 				                          scontextp);
-				if (!catdatum)
+				if (!catdatum) {
+					rc = -EINVAL;
 					goto out;
+				}
 
 				rc = ebitmap_set_bit(&context->range.level[l].cat,
 				                     catdatum->value - 1, 1);
 				if (rc)
 					goto out;
+
+				/* If range, set all categories in range */
+				if (rngptr) {
+					int i;
+
+					rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
+					if (!rngdatum) {
+						rc = -EINVAL;
+						goto out;
+					}
+
+					if (catdatum->value >= rngdatum->value) {
+						rc = -EINVAL;
+						goto out;
+					}
+
+					for (i = catdatum->value; i < rngdatum->value; i++) {
+						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
+						if (rc)
+							goto out;
+					}
+				}
+
 				if (delim != ',')
 					break;
 			}
@@ -306,7 +343,6 @@ static inline int mls_copy_context(struc
 
 	/* Copy the MLS range from the source context */
 	for (l = 0; l < 2; l++) {
-
 		dst->range.level[l].sens = src->range.level[l].sens;
 		rc = ebitmap_cpy(&dst->range.level[l].cat,
 				 &src->range.level[l].cat);
@@ -318,6 +354,84 @@ static inline int mls_copy_context(struc
 }
 
 /*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(struct context *dst,
+                                    struct context *src)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range from the source context */
+	for (l = 0; l < 2; l++) {
+		dst->range.level[l].sens = src->range.level[0].sens;
+		rc = ebitmap_cpy(&dst->range.level[l].cat,
+				 &src->range.level[0].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(struct context *context,
+                                struct mls_range *range)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range into the  context */
+	for (l = 0; l < 2; l++) {
+		context->range.level[l].sens = range->level[l].sens;
+		rc = ebitmap_cpy(&context->range.level[l].cat,
+				 &range->level[l].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                         struct context *usercon)
+{
+	if (selinux_mls_enabled) {
+		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
+		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
+		struct mls_level *user_low = &(user->range.level[0]);
+		struct mls_level *user_clr = &(user->range.level[1]);
+		struct mls_level *user_def = &(user->dfltlevel);
+		struct mls_level *usercon_sen = &(usercon->range.level[0]);
+		struct mls_level *usercon_clr = &(usercon->range.level[1]);
+
+		/* Honor the user's default level if we can */
+		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+			*usercon_sen = *user_def;
+		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+			*usercon_sen = *fromcon_sen;
+		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+			*usercon_sen = *user_low;
+		} else
+			return -EINVAL;
+
+		/* Lower the clearance of available contexts
+		   if the clearance of "fromcon" is lower than
+		   that of the user's default clearance (but
+		   only if the "fromcon" clearance dominates
+		   the user's computed sensitivity level) */
+		if (mls_level_dom(user_clr, fromcon_clr)) {
+			*usercon_clr = *fromcon_clr;
+		} else if (mls_level_dom(fromcon_clr, user_clr)) {
+			*usercon_clr = *user_clr;
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
  * Convert the MLS fields in the security context
  * structure `c' from the values specified in the
  * policy `oldp' to the values specified in the policy `newp'.
@@ -331,6 +445,9 @@ int mls_convert_context(struct policydb 
 	struct ebitmap bitmap;
 	int l, i;
 
+	if (!selinux_mls_enabled)
+		return 0;
+
 	for (l = 0; l < 2; l++) {
 		levdatum = hashtab_search(newp->p_levels.table,
 			oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
@@ -366,17 +483,38 @@ int mls_compute_sid(struct context *scon
 		    u32 specified,
 		    struct context *newcontext)
 {
+	if (!selinux_mls_enabled)
+		return 0;
+
 	switch (specified) {
 	case AVTAB_TRANSITION:
+		if (tclass == SECCLASS_PROCESS) {
+			struct range_trans *rangetr;
+			/* Look for a range transition rule. */
+			for (rangetr = policydb.range_tr; rangetr;
+			     rangetr = rangetr->next) {
+				if (rangetr->dom == scontext->type &&
+				    rangetr->type == tcontext->type) {
+					/* Set the range from the rule */
+					return mls_range_set(newcontext,
+					                     &rangetr->range);
+				}
+			}
+		}
+		/* Fallthrough */
 	case AVTAB_CHANGE:
-		/* Use the process MLS attributes. */
-		return mls_copy_context(newcontext, scontext);
+		if (tclass == SECCLASS_PROCESS)
+			/* Use the process MLS attributes. */
+			return mls_copy_context(newcontext, scontext);
+		else
+			/* Use the process effective MLS attributes. */
+			return mls_scopy_context(newcontext, scontext);
 	case AVTAB_MEMBER:
 		/* Only polyinstantiate the MLS attributes if
 		   the type is being polyinstantiated */
 		if (newcontext->type != tcontext->type) {
-			/* Use the process MLS attributes. */
-			return mls_copy_context(newcontext, scontext);
+			/* Use the process effective MLS attributes. */
+			return mls_scopy_context(newcontext, scontext);
 		} else {
 			/* Use the related object MLS attributes. */
 			return mls_copy_context(newcontext, tcontext);
@@ -387,365 +525,3 @@ int mls_compute_sid(struct context *scon
 	return -EINVAL;
 }
 
-void mls_user_destroy(struct user_datum *usrdatum)
-{
-	struct mls_range_list *rnode, *rtmp;
-	rnode = usrdatum->ranges;
-	while (rnode) {
-		rtmp = rnode;
-		rnode = rnode->next;
-		ebitmap_destroy(&rtmp->range.level[0].cat);
-		ebitmap_destroy(&rtmp->range.level[1].cat);
-		kfree(rtmp);
-	}
-}
-
-int mls_read_perm(struct perm_datum *perdatum, void *fp)
-{
-	u32 buf[1];
-	int rc;
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		return -EINVAL;
-	perdatum->base_perms = le32_to_cpu(buf[0]);
-	return 0;
-}
-
-/*
- * Read a MLS level structure from a policydb binary
- * representation file.
- */
-struct mls_level *mls_read_level(void *fp)
-{
-	struct mls_level *l;
-	u32 buf[1];
-	int rc;
-
-	l = kmalloc(sizeof(*l), GFP_ATOMIC);
-	if (!l) {
-		printk(KERN_ERR "security: mls: out of memory\n");
-		return NULL;
-	}
-	memset(l, 0, sizeof(*l));
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0) {
-		printk(KERN_ERR "security: mls: truncated level\n");
-		goto bad;
-	}
-	l->sens = cpu_to_le32(buf[0]);
-
-	if (ebitmap_read(&l->cat, fp)) {
-		printk(KERN_ERR "security: mls:  error reading level "
-		       "categories\n");
-		goto bad;
-	}
-	return l;
-
-bad:
-	kfree(l);
-	return NULL;
-}
-
-
-/*
- * Read a MLS range structure from a policydb binary
- * representation file.
- */
-static int mls_read_range_helper(struct mls_range *r, void *fp)
-{
-	u32 buf[2], items;
-	int rc;
-
-	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
-		goto out;
-
-	items = le32_to_cpu(buf[0]);
-	if (items > ARRAY_SIZE(buf)) {
-		printk(KERN_ERR "security: mls:  range overflow\n");
-		rc = -EINVAL;
-		goto out;
-	}
-	rc = next_entry(buf, fp, sizeof(u32) * items);
-	if (rc < 0) {
-		printk(KERN_ERR "security: mls:  truncated range\n");
-		goto out;
-	}
-	r->level[0].sens = le32_to_cpu(buf[0]);
-	if (items > 1) {
-		r->level[1].sens = le32_to_cpu(buf[1]);
-	} else {
-		r->level[1].sens = r->level[0].sens;
-	}
-
-	rc = ebitmap_read(&r->level[0].cat, fp);
-	if (rc) {
-		printk(KERN_ERR "security: mls:  error reading low "
-		       "categories\n");
-		goto out;
-	}
-	if (items > 1) {
-		rc = ebitmap_read(&r->level[1].cat, fp);
-		if (rc) {
-			printk(KERN_ERR "security: mls:  error reading high "
-			       "categories\n");
-			goto bad_high;
-		}
-	} else {
-		rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
-		if (rc) {
-			printk(KERN_ERR "security: mls:  out of memory\n");
-			goto bad_high;
-		}
-	}
-
-	rc = 0;
-out:
-	return rc;
-bad_high:
-	ebitmap_destroy(&r->level[0].cat);
-	goto out;
-}
-
-int mls_read_range(struct context *c, void *fp)
-{
-	return mls_read_range_helper(&c->range, fp);
-}
-
-
-/*
- * Read a MLS perms structure from a policydb binary
- * representation file.
- */
-int mls_read_class(struct class_datum *cladatum, void *fp)
-{
-	struct mls_perms *p = &cladatum->mlsperms;
-	u32 buf[4];
-	int rc;
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0) {
-		printk(KERN_ERR "security: mls:  truncated mls permissions\n");
-		return -EINVAL;
-	}
-	p->read = le32_to_cpu(buf[0]);
-	p->readby = le32_to_cpu(buf[1]);
-	p->write = le32_to_cpu(buf[2]);
-	p->writeby = le32_to_cpu(buf[3]);
-	return 0;
-}
-
-int mls_read_user(struct user_datum *usrdatum, void *fp)
-{
-	struct mls_range_list *r, *l;
-	int rc;
-	u32 nel, i;
-	u32 buf[1];
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		goto out;
-	nel = le32_to_cpu(buf[0]);
-	l = NULL;
-	for (i = 0; i < nel; i++) {
-		r = kmalloc(sizeof(*r), GFP_ATOMIC);
-		if (!r) {
-			rc = -ENOMEM;
-			goto out;
-		}
-		memset(r, 0, sizeof(*r));
-
-		rc = mls_read_range_helper(&r->range, fp);
-		if (rc) {
-			kfree(r);
-			goto out;
-		}
-
-		if (l)
-			l->next = r;
-		else
-			usrdatum->ranges = r;
-		l = r;
-	}
-out:
-	return rc;
-}
-
-int mls_read_nlevels(struct policydb *p, void *fp)
-{
-	u32 buf[1];
-	int rc;
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		return -EINVAL;
-	p->nlevels = le32_to_cpu(buf[0]);
-	return 0;
-}
-
-int mls_read_trusted(struct policydb *p, void *fp)
-{
-	int rc = 0;
-
-	rc = ebitmap_read(&p->trustedreaders, fp);
-	if (rc)
-		goto out;
-	rc = ebitmap_read(&p->trustedwriters, fp);
-	if (rc)
-		goto bad;
-	rc = ebitmap_read(&p->trustedobjects, fp);
-	if (rc)
-		goto bad2;
-out:
-	return rc;
-bad2:
-	ebitmap_destroy(&p->trustedwriters);
-bad:
-	ebitmap_destroy(&p->trustedreaders);
-	goto out;
-}
-
-int sens_index(void *key, void *datum, void *datap)
-{
-	struct policydb *p;
-	struct level_datum *levdatum;
-
-
-	levdatum = datum;
-	p = datap;
-
-	if (!levdatum->isalias)
-		p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
-
-	return 0;
-}
-
-int cat_index(void *key, void *datum, void *datap)
-{
-	struct policydb *p;
-	struct cat_datum *catdatum;
-
-
-	catdatum = datum;
-	p = datap;
-
-
-	if (!catdatum->isalias)
-		p->p_cat_val_to_name[catdatum->value - 1] = key;
-
-	return 0;
-}
-
-int sens_destroy(void *key, void *datum, void *p)
-{
-	struct level_datum *levdatum;
-
-	kfree(key);
-	levdatum = datum;
-	if (!levdatum->isalias) {
-		ebitmap_destroy(&levdatum->level->cat);
-		kfree(levdatum->level);
-	}
-	kfree(datum);
-	return 0;
-}
-
-int cat_destroy(void *key, void *datum, void *p)
-{
-	kfree(key);
-	kfree(datum);
-	return 0;
-}
-
-int sens_read(struct policydb *p, struct hashtab *h, void *fp)
-{
-	char *key = NULL;
-	struct level_datum *levdatum;
-	int rc;
-	u32 buf[2], len;
-
-	levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
-	if (!levdatum) {
-		rc = -ENOMEM;
-		goto out;
-	}
-	memset(levdatum, 0, sizeof(*levdatum));
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		goto bad;
-
-	len = le32_to_cpu(buf[0]);
-	levdatum->isalias = le32_to_cpu(buf[1]);
-
-	key = kmalloc(len + 1,GFP_ATOMIC);
-	if (!key) {
-		rc = -ENOMEM;
-		goto bad;
-	}
-	rc = next_entry(key, fp, len);
-	if (rc < 0)
-		goto bad;
-	key[len] = 0;
-
-	levdatum->level = mls_read_level(fp);
-	if (!levdatum->level) {
-		rc = -EINVAL;
-		goto bad;
-	}
-
-	rc = hashtab_insert(h, key, levdatum);
-	if (rc)
-		goto bad;
-out:
-	return rc;
-bad:
-	sens_destroy(key, levdatum, NULL);
-	goto out;
-}
-
-
-int cat_read(struct policydb *p, struct hashtab *h, void *fp)
-{
-	char *key = NULL;
-	struct cat_datum *catdatum;
-	int rc;
-	u32 buf[3], len;
-
-	catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
-	if (!catdatum) {
-		rc = -ENOMEM;
-		goto out;
-	}
-	memset(catdatum, 0, sizeof(*catdatum));
-
-	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		goto bad;
-
-	len = le32_to_cpu(buf[0]);
-	catdatum->value = le32_to_cpu(buf[1]);
-	catdatum->isalias = le32_to_cpu(buf[2]);
-
-	key = kmalloc(len + 1,GFP_ATOMIC);
-	if (!key) {
-		rc = -ENOMEM;
-		goto bad;
-	}
-	rc = next_entry(key, fp, len);
-	if (rc < 0)
-		goto bad;
-	key[len] = 0;
-
-	rc = hashtab_insert(h, key, catdatum);
-	if (rc)
-		goto bad;
-out:
-	return rc;
-
-bad:
-	cat_destroy(key, catdatum, NULL);
-	goto out;
-}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -3,21 +3,22 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
 #ifndef _SS_MLS_H_
 #define _SS_MLS_H_
 
 #include "context.h"
 #include "policydb.h"
 
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-
-void mls_compute_av(struct context *scontext,
-		    struct context *tcontext,
-		    struct class_datum *tclass,
-		    u32 *allowed);
-
 int mls_compute_context_len(struct context *context);
-int mls_sid_to_context(struct context *context, char **scontext);
+void mls_sid_to_context(struct context *context, char **scontext);
 int mls_context_isvalid(struct policydb *p, struct context *c);
 
 int mls_context_to_sid(char oldc,
@@ -34,66 +35,8 @@ int mls_compute_sid(struct context *scon
 		    u32 specified,
 		    struct context *newcontext);
 
-int sens_index(void *key, void *datum, void *datap);
-int cat_index(void *key, void *datum, void *datap);
-int sens_destroy(void *key, void *datum, void *p);
-int cat_destroy(void *key, void *datum, void *p);
-int sens_read(struct policydb *p, struct hashtab *h, void *fp);
-int cat_read(struct policydb *p, struct hashtab *h, void *fp);
-
-#define mls_for_user_ranges(user, usercon) { \
-struct mls_range_list *__ranges; \
-for (__ranges = user->ranges; __ranges; __ranges = __ranges->next) { \
-usercon.range = __ranges->range;
-
-#define mls_end_user_ranges } }
-
-#define mls_symtab_names  "levels", "categories",
-#define mls_symtab_sizes  16, 16,
-#define mls_index_f sens_index, cat_index,
-#define mls_destroy_f sens_destroy, cat_destroy,
-#define mls_read_f sens_read, cat_read,
-#define mls_write_f sens_write, cat_write,
-#define mls_policydb_index_others(p) printk(", %d levels", p->nlevels);
-
-#define mls_set_config(config) config |= POLICYDB_CONFIG_MLS
-
-void mls_user_destroy(struct user_datum *usrdatum);
-int mls_read_range(struct context *c, void *fp);
-int mls_read_perm(struct perm_datum *perdatum, void *fp);
-int mls_read_class(struct class_datum *cladatum,  void *fp);
-int mls_read_user(struct user_datum *usrdatum, void *fp);
-int mls_read_nlevels(struct policydb *p, void *fp);
-int mls_read_trusted(struct policydb *p, void *fp);
-
-#else
-
-#define	mls_compute_av(scontext, tcontext, tclass_datum, allowed)
-#define mls_compute_context_len(context) 0
-#define	mls_sid_to_context(context, scontextpp)
-#define mls_context_isvalid(p, c) 1
-#define	mls_context_to_sid(oldc, context_str, context) 0
-#define mls_convert_context(oldp, newp, c) 0
-#define mls_compute_sid(scontext, tcontext, tclass, specified, newcontextp) 0
-#define mls_for_user_ranges(user, usercon)
-#define mls_end_user_ranges
-#define mls_symtab_names
-#define mls_symtab_sizes
-#define mls_index_f
-#define mls_destroy_f
-#define mls_read_f
-#define mls_write_f
-#define mls_policydb_index_others(p)
-#define mls_set_config(config)
-#define mls_user_destroy(usrdatum)
-#define mls_read_range(c, fp) 0
-#define mls_read_perm(p, fp) 0
-#define mls_read_class(c, fp) 0
-#define mls_read_user(u, fp) 0
-#define mls_read_nlevels(p, fp) 0
-#define mls_read_trusted(p, fp) 0
-
-#endif
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                         struct context *usercon);
 
 #endif	/* _SS_MLS_H */
 
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
--- a/security/selinux/ss/mls_types.h
+++ b/security/selinux/ss/mls_types.h
@@ -3,9 +3,19 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
 #ifndef _SS_MLS_TYPES_H_
 #define _SS_MLS_TYPES_H_
 
+#include "security.h"
+
 struct mls_level {
 	u32 sens;		/* sensitivity */
 	struct ebitmap cat;	/* category set */
@@ -15,44 +25,32 @@ struct mls_range {
 	struct mls_level level[2]; /* low == level[0], high == level[1] */
 };
 
-struct mls_range_list {
-	struct mls_range range;
-	struct mls_range_list *next;
-};
-
-#define MLS_RELATION_DOM	1 /* source dominates */
-#define MLS_RELATION_DOMBY	2 /* target dominates */
-#define MLS_RELATION_EQ		4 /* source and target are equivalent */
-#define MLS_RELATION_INCOMP	8 /* source and target are incomparable */
-
-#define mls_level_eq(l1,l2) \
-(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat))
-
-#define mls_level_relation(l1,l2) ( \
-(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat)) ? \
-				    MLS_RELATION_EQ : \
-(((l1).sens >= (l2).sens) && ebitmap_contains(&(l1).cat, &(l2).cat)) ? \
-				    MLS_RELATION_DOM : \
-(((l2).sens >= (l1).sens) && ebitmap_contains(&(l2).cat, &(l1).cat)) ? \
-				    MLS_RELATION_DOMBY : \
-				    MLS_RELATION_INCOMP )
-
-#define mls_range_contains(r1,r2) \
-((mls_level_relation((r1).level[0], (r2).level[0]) & \
-	  (MLS_RELATION_EQ | MLS_RELATION_DOMBY)) && \
-	 (mls_level_relation((r1).level[1], (r2).level[1]) & \
-	  (MLS_RELATION_EQ | MLS_RELATION_DOM)))
-
-/*
- * Every access vector permission is mapped to a set of MLS base
- * permissions, based on the flow properties of the corresponding
- * operation.
- */
-struct mls_perms {
-	u32 read;     /* permissions that map to `read' */
-	u32 readby;   /* permissions that map to `readby' */
-	u32 write;    /* permissions that map to `write' */
-	u32 writeby;  /* permissions that map to `writeby' */
-};
+static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
+{
+	if (!selinux_mls_enabled)
+		return 1;
+
+	return ((l1->sens == l2->sens) &&
+	        ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
+{
+	if (!selinux_mls_enabled)
+		return 1;
+
+	return ((l1->sens >= l2->sens) &&
+	        ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
 
 #endif	/* _SS_MLS_TYPES_H_ */
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -4,10 +4,16 @@
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
 
-/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
  *
  * 	Added conditional policy language extensions
  *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  *	This 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,19 +39,23 @@ static char *symtab_name[SYM_NUM] = {
 	"roles",
 	"types",
 	"users",
-	mls_symtab_names
-	"bools"
+	"bools",
+	"levels",
+	"categories",
 };
 #endif
 
+int selinux_mls_enabled = 0;
+
 static unsigned int symtab_sizes[SYM_NUM] = {
 	2,
 	32,
 	16,
 	512,
 	128,
-	mls_symtab_sizes
-	16
+	16,
+	16,
+	16,
 };
 
 struct policydb_compat_info {
@@ -58,21 +68,26 @@ struct policydb_compat_info {
 static struct policydb_compat_info policydb_compat[] = {
 	{
 		.version        = POLICYDB_VERSION_BASE,
-		.sym_num        = SYM_NUM - 1,
+		.sym_num        = SYM_NUM - 3,
 		.ocon_num       = OCON_NUM - 1,
 	},
 	{
 		.version        = POLICYDB_VERSION_BOOL,
-		.sym_num        = SYM_NUM,
+		.sym_num        = SYM_NUM - 2,
 		.ocon_num       = OCON_NUM - 1,
 	},
 	{
 		.version        = POLICYDB_VERSION_IPV6,
-		.sym_num        = SYM_NUM,
+		.sym_num        = SYM_NUM - 2,
 		.ocon_num       = OCON_NUM,
 	},
 	{
 		.version        = POLICYDB_VERSION_NLCLASS,
+		.sym_num        = SYM_NUM - 2,
+		.ocon_num       = OCON_NUM,
+	},
+	{
+		.version        = POLICYDB_VERSION_MLS,
 		.sym_num        = SYM_NUM,
 		.ocon_num       = OCON_NUM,
 	},
@@ -95,7 +110,7 @@ static struct policydb_compat_info *poli
 /*
  * Initialize the role table.
  */
-int roles_init(struct policydb *p)
+static int roles_init(struct policydb *p)
 {
 	char *key = NULL;
 	int rc;
@@ -134,7 +149,7 @@ out_free_role:
 /*
  * Initialize a policy database structure.
  */
-int policydb_init(struct policydb *p)
+static int policydb_init(struct policydb *p)
 {
 	int i, rc;
 
@@ -252,6 +267,41 @@ static int user_index(void *key, void *d
 	return 0;
 }
 
+static int sens_index(void *key, void *datum, void *datap)
+{
+	struct policydb *p;
+	struct level_datum *levdatum;
+
+	levdatum = datum;
+	p = datap;
+
+	if (!levdatum->isalias) {
+		if (!levdatum->level->sens ||
+		    levdatum->level->sens > p->p_levels.nprim)
+			return -EINVAL;
+		p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+	}
+
+	return 0;
+}
+
+static int cat_index(void *key, void *datum, void *datap)
+{
+	struct policydb *p;
+	struct cat_datum *catdatum;
+
+	catdatum = datum;
+	p = datap;
+
+	if (!catdatum->isalias) {
+		if (!catdatum->value || catdatum->value > p->p_cats.nprim)
+			return -EINVAL;
+		p->p_cat_val_to_name[catdatum->value - 1] = key;
+	}
+
+	return 0;
+}
+
 static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
 {
 	common_index,
@@ -259,8 +309,9 @@ static int (*index_f[SYM_NUM]) (void *ke
 	role_index,
 	type_index,
 	user_index,
-	mls_index_f
-	cond_index_bool
+	cond_index_bool,
+	sens_index,
+	cat_index,
 };
 
 /*
@@ -270,7 +321,7 @@ static int (*index_f[SYM_NUM]) (void *ke
  *
  * Caller must clean up upon failure.
  */
-int policydb_index_classes(struct policydb *p)
+static int policydb_index_classes(struct policydb *p)
 {
 	int rc;
 
@@ -327,13 +378,15 @@ static void symtab_hash_eval(struct symt
  *
  * Caller must clean up on failure.
  */
-int policydb_index_others(struct policydb *p)
+static int policydb_index_others(struct policydb *p)
 {
 	int i, rc = 0;
 
 	printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
 	       p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
-	mls_policydb_index_others(p);
+	if (selinux_mls_enabled)
+		printk(", %d sens, %d cats", p->p_levels.nprim,
+		       p->p_cats.nprim);
 	printk("\n");
 
 	printk(KERN_INFO "security:  %d classes, %d rules\n",
@@ -429,6 +482,21 @@ static int class_destroy(void *key, void
 		constraint = constraint->next;
 		kfree(ctemp);
 	}
+
+	constraint = cladatum->validatetrans;
+	while (constraint) {
+		e = constraint->expr;
+		while (e) {
+			ebitmap_destroy(&e->names);
+			etmp = e;
+			e = e->next;
+			kfree(etmp);
+		}
+		ctemp = constraint;
+		constraint = constraint->next;
+		kfree(ctemp);
+	}
+
 	kfree(cladatum->comkey);
 	kfree(datum);
 	return 0;
@@ -460,7 +528,28 @@ static int user_destroy(void *key, void 
 	kfree(key);
 	usrdatum = datum;
 	ebitmap_destroy(&usrdatum->roles);
-	mls_user_destroy(usrdatum);
+	ebitmap_destroy(&usrdatum->range.level[0].cat);
+	ebitmap_destroy(&usrdatum->range.level[1].cat);
+	ebitmap_destroy(&usrdatum->dfltlevel.cat);
+	kfree(datum);
+	return 0;
+}
+
+static int sens_destroy(void *key, void *datum, void *p)
+{
+	struct level_datum *levdatum;
+
+	kfree(key);
+	levdatum = datum;
+	ebitmap_destroy(&levdatum->level->cat);
+	kfree(levdatum->level);
+	kfree(datum);
+	return 0;
+}
+
+static int cat_destroy(void *key, void *datum, void *p)
+{
+	kfree(key);
 	kfree(datum);
 	return 0;
 }
@@ -472,11 +561,12 @@ static int (*destroy_f[SYM_NUM]) (void *
 	role_destroy,
 	type_destroy,
 	user_destroy,
-	mls_destroy_f
-	cond_destroy_bool
+	cond_destroy_bool,
+	sens_destroy,
+	cat_destroy,
 };
 
-void ocontext_destroy(struct ocontext *c, int i)
+static void ocontext_destroy(struct ocontext *c, int i)
 {
 	context_destroy(&c->context[0]);
 	context_destroy(&c->context[1]);
@@ -624,6 +714,65 @@ int policydb_context_isvalid(struct poli
 }
 
 /*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(struct mls_range *r, void *fp)
+{
+	u32 buf[2], items;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc < 0)
+		goto out;
+
+	items = le32_to_cpu(buf[0]);
+	if (items > ARRAY_SIZE(buf)) {
+		printk(KERN_ERR "security: mls:  range overflow\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = next_entry(buf, fp, sizeof(u32) * items);
+	if (rc < 0) {
+		printk(KERN_ERR "security: mls:  truncated range\n");
+		goto out;
+	}
+	r->level[0].sens = le32_to_cpu(buf[0]);
+	if (items > 1)
+		r->level[1].sens = le32_to_cpu(buf[1]);
+	else
+		r->level[1].sens = r->level[0].sens;
+
+	rc = ebitmap_read(&r->level[0].cat, fp);
+	if (rc) {
+		printk(KERN_ERR "security: mls:  error reading low "
+		       "categories\n");
+		goto out;
+	}
+	if (items > 1) {
+		rc = ebitmap_read(&r->level[1].cat, fp);
+		if (rc) {
+			printk(KERN_ERR "security: mls:  error reading high "
+			       "categories\n");
+			goto bad_high;
+		}
+	} else {
+		rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+		if (rc) {
+			printk(KERN_ERR "security: mls:  out of memory\n");
+			goto bad_high;
+		}
+	}
+
+	rc = 0;
+out:
+	return rc;
+bad_high:
+	ebitmap_destroy(&r->level[0].cat);
+	goto out;
+}
+
+/*
  * Read and validate a security context structure
  * from a policydb binary representation file.
  */
@@ -642,11 +791,13 @@ static int context_read_and_validate(str
 	c->user = le32_to_cpu(buf[0]);
 	c->role = le32_to_cpu(buf[1]);
 	c->type = le32_to_cpu(buf[2]);
-	if (mls_read_range(c, fp)) {
-		printk(KERN_ERR "security: error reading MLS range of "
-		       "context\n");
-		rc = -EINVAL;
-		goto out;
+	if (p->policyvers >= POLICYDB_VERSION_MLS) {
+		if (mls_read_range_helper(&c->range, fp)) {
+			printk(KERN_ERR "security: error reading MLS range of "
+			       "context\n");
+			rc = -EINVAL;
+			goto out;
+		}
 	}
 
 	if (!policydb_context_isvalid(p, c)) {
@@ -684,9 +835,6 @@ static int perm_read(struct policydb *p,
 
 	len = le32_to_cpu(buf[0]);
 	perdatum->value = le32_to_cpu(buf[1]);
-	rc = mls_read_perm(perdatum, fp);
-	if (rc)
-		goto bad;
 
 	key = kmalloc(len + 1,GFP_KERNEL);
 	if (!key) {
@@ -761,14 +909,97 @@ bad:
 	goto out;
 }
 
+static int read_cons_helper(struct constraint_node **nodep, int ncons,
+                            int allowxtarget, void *fp)
+{
+	struct constraint_node *c, *lc;
+	struct constraint_expr *e, *le;
+	u32 buf[3], nexpr;
+	int rc, i, j, depth;
+
+	lc = NULL;
+	for (i = 0; i < ncons; i++) {
+		c = kmalloc(sizeof(*c), GFP_KERNEL);
+		if (!c)
+			return -ENOMEM;
+		memset(c, 0, sizeof(*c));
+
+		if (lc) {
+			lc->next = c;
+		} else {
+			*nodep = c;
+		}
+
+		rc = next_entry(buf, fp, (sizeof(u32) * 2));
+		if (rc < 0)
+			return rc;
+		c->permissions = le32_to_cpu(buf[0]);
+		nexpr = le32_to_cpu(buf[1]);
+		le = NULL;
+		depth = -1;
+		for (j = 0; j < nexpr; j++) {
+			e = kmalloc(sizeof(*e), GFP_KERNEL);
+			if (!e)
+				return -ENOMEM;
+			memset(e, 0, sizeof(*e));
+
+			if (le) {
+				le->next = e;
+			} else {
+				c->expr = e;
+			}
+
+			rc = next_entry(buf, fp, (sizeof(u32) * 3));
+			if (rc < 0)
+				return rc;
+			e->expr_type = le32_to_cpu(buf[0]);
+			e->attr = le32_to_cpu(buf[1]);
+			e->op = le32_to_cpu(buf[2]);
+
+			switch (e->expr_type) {
+			case CEXPR_NOT:
+				if (depth < 0)
+					return -EINVAL;
+				break;
+			case CEXPR_AND:
+			case CEXPR_OR:
+				if (depth < 1)
+					return -EINVAL;
+				depth--;
+				break;
+			case CEXPR_ATTR:
+				if (depth == (CEXPR_MAXDEPTH - 1))
+					return -EINVAL;
+				depth++;
+				break;
+			case CEXPR_NAMES:
+				if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+					return -EINVAL;
+				if (depth == (CEXPR_MAXDEPTH - 1))
+					return -EINVAL;
+				depth++;
+				if (ebitmap_read(&e->names, fp))
+					return -EINVAL;
+				break;
+			default:
+				return -EINVAL;
+			}
+			le = e;
+		}
+		if (depth != 0)
+			return -EINVAL;
+		lc = c;
+	}
+
+	return 0;
+}
+
 static int class_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct class_datum *cladatum;
-	struct constraint_node *c, *lc;
-	struct constraint_expr *e, *le;
-	u32 buf[6], len, len2, ncons, nexpr, nel;
-	int i, j, depth, rc;
+	u32 buf[6], len, len2, ncons, nel;
+	int i, rc;
 
 	cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL);
 	if (!cladatum) {
@@ -829,87 +1060,21 @@ static int class_read(struct policydb *p
 			goto bad;
 	}
 
-	lc = NULL;
-	for (i = 0; i < ncons; i++) {
-		c = kmalloc(sizeof(*c), GFP_KERNEL);
-		if (!c) {
-			rc = -ENOMEM;
-			goto bad;
-		}
-		memset(c, 0, sizeof(*c));
-
-		if (lc) {
-			lc->next = c;
-		} else {
-			cladatum->constraints = c;
-		}
+	rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+	if (rc)
+		goto bad;
 
-		rc = next_entry(buf, fp, sizeof(u32)*2);
+	if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
+		/* grab the validatetrans rules */
+		rc = next_entry(buf, fp, sizeof(u32));
 		if (rc < 0)
 			goto bad;
-		c->permissions = le32_to_cpu(buf[0]);
-		nexpr = le32_to_cpu(buf[1]);
-		le = NULL;
-		depth = -1;
-		for (j = 0; j < nexpr; j++) {
-			e = kmalloc(sizeof(*e), GFP_KERNEL);
-			if (!e) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			memset(e, 0, sizeof(*e));
-
-			if (le) {
-				le->next = e;
-			} else {
-				c->expr = e;
-			}
-
-			rc = next_entry(buf, fp, sizeof(u32)*3);
-			if (rc < 0)
-				goto bad;
-			e->expr_type = le32_to_cpu(buf[0]);
-			e->attr = le32_to_cpu(buf[1]);
-			e->op = le32_to_cpu(buf[2]);
-
-			rc = -EINVAL;
-			switch (e->expr_type) {
-			case CEXPR_NOT:
-				if (depth < 0)
-					goto bad;
-				break;
-			case CEXPR_AND:
-			case CEXPR_OR:
-				if (depth < 1)
-					goto bad;
-				depth--;
-				break;
-			case CEXPR_ATTR:
-				if (depth == (CEXPR_MAXDEPTH-1))
-					goto bad;
-				depth++;
-				break;
-			case CEXPR_NAMES:
-				if (depth == (CEXPR_MAXDEPTH-1))
-					goto bad;
-				depth++;
-				if (ebitmap_read(&e->names, fp))
-					goto bad;
-				break;
-			default:
-				goto bad;
-			}
-			le = e;
-		}
-		if (depth != 0)
+		ncons = le32_to_cpu(buf[0]);
+		rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+		if (rc)
 			goto bad;
-		lc = c;
 	}
 
-	rc = mls_read_class(cladatum, fp);
-	if (rc)
-		goto bad;
-
 	rc = hashtab_insert(h, key, cladatum);
 	if (rc)
 		goto bad;
@@ -1024,6 +1189,36 @@ bad:
 	goto out;
 }
 
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(struct mls_level *lp, void *fp)
+{
+	u32 buf[1];
+	int rc;
+
+	memset(lp, 0, sizeof(*lp));
+
+	rc = next_entry(buf, fp, sizeof buf);
+	if (rc < 0) {
+		printk(KERN_ERR "security: mls: truncated level\n");
+		goto bad;
+	}
+	lp->sens = le32_to_cpu(buf[0]);
+
+	if (ebitmap_read(&lp->cat, fp)) {
+		printk(KERN_ERR "security: mls:  error reading level "
+		       "categories\n");
+		goto bad;
+	}
+	return 0;
+
+bad:
+	return -EINVAL;
+}
+
 static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
@@ -1031,7 +1226,6 @@ static int user_read(struct policydb *p,
 	int rc;
 	u32 buf[2], len;
 
-
 	usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL);
 	if (!usrdatum) {
 		rc = -ENOMEM;
@@ -1060,9 +1254,14 @@ static int user_read(struct policydb *p,
 	if (rc)
 		goto bad;
 
-	rc = mls_read_user(usrdatum, fp);
-	if (rc)
-		goto bad;
+	if (p->policyvers >= POLICYDB_VERSION_MLS) {
+		rc = mls_read_range_helper(&usrdatum->range, fp);
+		if (rc)
+			goto bad;
+		rc = mls_read_level(&usrdatum->dfltlevel, fp);
+		if (rc)
+			goto bad;
+	}
 
 	rc = hashtab_insert(h, key, usrdatum);
 	if (rc)
@@ -1074,6 +1273,100 @@ bad:
 	goto out;
 }
 
+static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+	char *key = NULL;
+	struct level_datum *levdatum;
+	int rc;
+	u32 buf[2], len;
+
+	levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
+	if (!levdatum) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(levdatum, 0, sizeof(*levdatum));
+
+	rc = next_entry(buf, fp, sizeof buf);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	levdatum->isalias = le32_to_cpu(buf[1]);
+
+	key = kmalloc(len + 1,GFP_ATOMIC);
+	if (!key) {
+		rc = -ENOMEM;
+		goto bad;
+	}
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
+	if (!levdatum->level) {
+		rc = -ENOMEM;
+		goto bad;
+	}
+	if (mls_read_level(levdatum->level, fp)) {
+		rc = -EINVAL;
+		goto bad;
+	}
+
+	rc = hashtab_insert(h, key, levdatum);
+	if (rc)
+		goto bad;
+out:
+	return rc;
+bad:
+	sens_destroy(key, levdatum, NULL);
+	goto out;
+}
+
+static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+	char *key = NULL;
+	struct cat_datum *catdatum;
+	int rc;
+	u32 buf[3], len;
+
+	catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
+	if (!catdatum) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(catdatum, 0, sizeof(*catdatum));
+
+	rc = next_entry(buf, fp, sizeof buf);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	catdatum->value = le32_to_cpu(buf[1]);
+	catdatum->isalias = le32_to_cpu(buf[2]);
+
+	key = kmalloc(len + 1,GFP_ATOMIC);
+	if (!key) {
+		rc = -ENOMEM;
+		goto bad;
+	}
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	rc = hashtab_insert(h, key, catdatum);
+	if (rc)
+		goto bad;
+out:
+	return rc;
+
+bad:
+	cat_destroy(key, catdatum, NULL);
+	goto out;
+}
+
 static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
 {
 	common_read,
@@ -1081,12 +1374,12 @@ static int (*read_f[SYM_NUM]) (struct po
 	role_read,
 	type_read,
 	user_read,
-	mls_read_f
-	cond_read_bool
+	cond_read_bool,
+	sens_read,
+	cat_read,
 };
 
-#define mls_config(x) \
-       ((x) & POLICYDB_CONFIG_MLS) ? "mls" : "no_mls"
+extern int ss_initialized;
 
 /*
  * Read the configuration data from a policy database binary
@@ -1102,9 +1395,9 @@ int policydb_read(struct policydb *p, vo
 	u32 buf[8], len, len2, config, nprim, nel, nel2;
 	char *policydb_str;
 	struct policydb_compat_info *info;
+	struct range_trans *rt, *lrt;
 
 	config = 0;
-	mls_set_config(config);
 
 	rc = policydb_init(p);
 	if (rc)
@@ -1172,14 +1465,27 @@ int policydb_read(struct policydb *p, vo
 	    	goto bad;
 	}
 
-	if (buf[1] != config) {
-		printk(KERN_ERR "security:  policydb configuration (%s) does "
-		       "not match my configuration (%s)\n",
-		       mls_config(buf[1]),
-		       mls_config(config));
-		goto bad;
-	}
+	if ((buf[1] & POLICYDB_CONFIG_MLS)) {
+		if (ss_initialized && !selinux_mls_enabled) {
+			printk(KERN_ERR "Cannot switch between non-MLS and MLS "
+			       "policies\n");
+			goto bad;
+		}
+		selinux_mls_enabled = 1;
+		config |= POLICYDB_CONFIG_MLS;
 
+		if (p->policyvers < POLICYDB_VERSION_MLS) {
+			printk(KERN_ERR "security policydb version %d (MLS) "
+			       "not backwards compatible\n", p->policyvers);
+			goto bad;
+		}
+	} else {
+		if (ss_initialized && selinux_mls_enabled) {
+			printk(KERN_ERR "Cannot switch between MLS and non-MLS "
+			       "policies\n");
+			goto bad;
+		}
+	}
 
 	info = policydb_lookup_compat(p->policyvers);
 	if (!info) {
@@ -1195,10 +1501,6 @@ int policydb_read(struct policydb *p, vo
 		goto bad;
 	}
 
-	rc = mls_read_nlevels(p, fp);
-	if (rc)
-		goto bad;
-
 	for (i = 0; i < info->sym_num; i++) {
 		rc = next_entry(buf, fp, sizeof(u32)*2);
 		if (rc < 0)
@@ -1499,9 +1801,34 @@ int policydb_read(struct policydb *p, vo
 		}
 	}
 
-	rc = mls_read_trusted(p, fp);
-	if (rc)
-		goto bad;
+	if (p->policyvers >= POLICYDB_VERSION_MLS) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc < 0)
+			goto bad;
+		nel = le32_to_cpu(buf[0]);
+		lrt = NULL;
+		for (i = 0; i < nel; i++) {
+			rt = kmalloc(sizeof(*rt), GFP_KERNEL);
+			if (!rt) {
+				rc = -ENOMEM;
+				goto bad;
+			}
+			memset(rt, 0, sizeof(*rt));
+			if (lrt)
+				lrt->next = rt;
+			else
+				p->range_tr = rt;
+			rc = next_entry(buf, fp, (sizeof(u32) * 2));
+			if (rc < 0)
+				goto bad;
+			rt->dom = le32_to_cpu(buf[0]);
+			rt->type = le32_to_cpu(buf[1]);
+			rc = mls_read_range_helper(&rt->range, fp);
+			if (rc)
+				goto bad;
+			lrt = rt;
+		}
+	}
 
 	rc = 0;
 out:
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -5,10 +5,16 @@
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
 
-/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
  *
  * 	Added conditional policy language extensions
  *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  *	This program is free software; you can redistribute it and/or modify
  *  	it under the terms of the GNU General Public License as published by
@@ -34,13 +40,6 @@
 /* Permission attributes */
 struct perm_datum {
 	u32 value;		/* permission bit + 1 */
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-#define MLS_BASE_READ    1	/* MLS base permission `read' */
-#define MLS_BASE_WRITE   2	/* MLS base permission `write' */
-#define MLS_BASE_READBY  4	/* MLS base permission `readby' */
-#define MLS_BASE_WRITEBY 8	/* MLS base permission `writeby' */
-	u32 base_perms;		/* MLS base permission mask */
-#endif
 };
 
 /* Attributes of a common prefix for access vectors */
@@ -56,9 +55,7 @@ struct class_datum {
 	struct common_datum *comdatum;	/* common datum */
 	struct symtab permissions;	/* class-specific permission symbol table */
 	struct constraint_node *constraints;	/* constraints on class permissions */
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-	struct mls_perms mlsperms;	/* MLS base permission masks */
-#endif
+	struct constraint_node *validatetrans;	/* special transition rules */
 };
 
 /* Role attributes */
@@ -91,13 +88,11 @@ struct type_datum {
 struct user_datum {
 	u32 value;			/* internal user value */
 	struct ebitmap roles;		/* set of authorized roles for user */
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-	struct mls_range_list *ranges;	/* list of authorized MLS ranges for user */
-#endif
+	struct mls_range range;		/* MLS range (min - max) for user */
+	struct mls_level dfltlevel;	/* default login MLS level for user */
 };
 
 
-#ifdef CONFIG_SECURITY_SELINUX_MLS
 /* Sensitivity attributes */
 struct level_datum {
 	struct mls_level *level;	/* sensitivity and associated categories */
@@ -109,7 +104,13 @@ struct cat_datum {
 	u32 value;		/* internal category bit + 1 */
 	unsigned char isalias;  /* is this category an alias for another? */
 };
-#endif
+
+struct range_trans {
+	u32 dom;			/* current process domain */
+	u32 type;			/* program executable type */
+	struct mls_range range;		/* new range */
+	struct range_trans *next;
+};
 
 /* Boolean data type */
 struct cond_bool_datum {
@@ -164,15 +165,10 @@ struct genfs {
 #define SYM_ROLES   2
 #define SYM_TYPES   3
 #define SYM_USERS   4
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-#define SYM_LEVELS  5
-#define SYM_CATS    6
-#define SYM_BOOLS   7
-#define SYM_NUM     8
-#else
 #define SYM_BOOLS   5
-#define SYM_NUM     6
-#endif
+#define SYM_LEVELS  6
+#define SYM_CATS    7
+#define SYM_NUM     8
 
 /* object context array indices */
 #define OCON_ISID  0	/* initial SIDs */
@@ -193,9 +189,9 @@ struct policydb {
 #define p_roles symtab[SYM_ROLES]
 #define p_types symtab[SYM_TYPES]
 #define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
 #define p_levels symtab[SYM_LEVELS]
 #define p_cats symtab[SYM_CATS]
-#define p_bools symtab[SYM_BOOLS]
 
 	/* symbol names indexed by (value - 1) */
 	char **sym_val_to_name[SYM_NUM];
@@ -204,9 +200,9 @@ struct policydb {
 #define p_role_val_to_name sym_val_to_name[SYM_ROLES]
 #define p_type_val_to_name sym_val_to_name[SYM_TYPES]
 #define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
 #define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
 #define p_cat_val_to_name sym_val_to_name[SYM_CATS]
-#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
 
 	/* class, role, and user attributes indexed by (value - 1) */
 	struct class_datum **class_val_to_struct;
@@ -238,21 +234,12 @@ struct policydb {
 	   fixed labeling behavior. */
   	struct genfs *genfs;
 
-#ifdef CONFIG_SECURITY_SELINUX_MLS
-	/* number of legitimate MLS levels */
-	u32 nlevels;
-
-	struct ebitmap trustedreaders;
-	struct ebitmap trustedwriters;
-	struct ebitmap trustedobjects;
-#endif
+	/* range transitions */
+	struct range_trans *range_tr;
 
 	unsigned int policyvers;
 };
 
-extern int policydb_init(struct policydb *p);
-extern int policydb_index_classes(struct policydb *p);
-extern int policydb_index_others(struct policydb *p);
 extern void policydb_destroy(struct policydb *p);
 extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
 extern int policydb_context_isvalid(struct policydb *p, struct context *c);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -4,17 +4,17 @@
  * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
  *           James Morris <jmorris@redhat.com>
  *
- *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.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.
+ *	Support for enhanced MLS infrastructure.
  *
  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
  *
  * 	Added conditional policy language extensions
  *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.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, version 2.
@@ -52,7 +52,7 @@ static DECLARE_MUTEX(load_sem);
 #define LOAD_LOCK down(&load_sem)
 #define LOAD_UNLOCK up(&load_sem)
 
-struct sidtab sidtab;
+static struct sidtab sidtab;
 struct policydb policydb;
 int ss_initialized = 0;
 
@@ -64,18 +64,30 @@ int ss_initialized = 0;
  */
 static u32 latest_granting = 0;
 
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+				    u32 *scontext_len);
+
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
  * security contexts.
+ *
+ * xcontext is a special beast...  It is used by the validatetrans rules
+ * only.  For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition.  All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
  */
 static int constraint_expr_eval(struct context *scontext,
 				struct context *tcontext,
+				struct context *xcontext,
 				struct constraint_expr *cexpr)
 {
 	u32 val1, val2;
 	struct context *c;
 	struct role_datum *r1, *r2;
+	struct mls_level *l1, *l2;
 	struct constraint_expr *e;
 	int s[CEXPR_MAXDEPTH];
 	int sp = -1;
@@ -132,6 +144,52 @@ static int constraint_expr_eval(struct c
 					break;
 				}
 				break;
+			case CEXPR_L1L2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[0]);
+				goto mls_ops;
+			case CEXPR_L1H2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_H1L2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[0]);
+				goto mls_ops;
+			case CEXPR_H1H2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_L1H1:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(scontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_L2H2:
+				l1 = &(tcontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+mls_ops:
+			switch (e->op) {
+			case CEXPR_EQ:
+				s[++sp] = mls_level_eq(l1, l2);
+				continue;
+			case CEXPR_NEQ:
+				s[++sp] = !mls_level_eq(l1, l2);
+				continue;
+			case CEXPR_DOM:
+				s[++sp] = mls_level_dom(l1, l2);
+				continue;
+			case CEXPR_DOMBY:
+				s[++sp] = mls_level_dom(l2, l1);
+				continue;
+			case CEXPR_INCOMP:
+				s[++sp] = mls_level_incomp(l2, l1);
+				continue;
+			default:
+				BUG();
+				return 0;
+			}
+			break;
 			default:
 				BUG();
 				return 0;
@@ -155,6 +213,13 @@ static int constraint_expr_eval(struct c
 			c = scontext;
 			if (e->attr & CEXPR_TARGET)
 				c = tcontext;
+			else if (e->attr & CEXPR_XTARGET) {
+				c = xcontext;
+				if (!c) {
+					BUG();
+					return 0;
+				}
+			}
 			if (e->attr & CEXPR_USER)
 				val1 = c->user;
 			else if (e->attr & CEXPR_ROLE)
@@ -252,17 +317,13 @@ static int context_struct_compute_av(str
 	cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
 
 	/*
-	 * Remove any permissions prohibited by the MLS policy.
-	 */
-	mls_compute_av(scontext, tcontext, tclass_datum, &avd->allowed);
-
-	/*
-	 * Remove any permissions prohibited by a constraint.
+	 * Remove any permissions prohibited by a constraint (this includes
+	 * the MLS policy).
 	 */
 	constraint = tclass_datum->constraints;
 	while (constraint) {
 		if ((constraint->permissions & (avd->allowed)) &&
-		    !constraint_expr_eval(scontext, tcontext,
+		    !constraint_expr_eval(scontext, tcontext, NULL,
 					  constraint->expr)) {
 			avd->allowed = (avd->allowed) & ~(constraint->permissions);
 		}
@@ -290,6 +351,108 @@ static int context_struct_compute_av(str
 	return 0;
 }
 
+static int security_validtrans_handle_fail(struct context *ocontext,
+                                           struct context *ncontext,
+                                           struct context *tcontext,
+                                           u16 tclass)
+{
+	char *o = NULL, *n = NULL, *t = NULL;
+	u32 olen, nlen, tlen;
+
+	if (context_struct_to_string(ocontext, &o, &olen) < 0)
+		goto out;
+	if (context_struct_to_string(ncontext, &n, &nlen) < 0)
+		goto out;
+	if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+		goto out;
+	audit_log(current->audit_context,
+	          "security_validate_transition:  denied for"
+	          " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
+	          o, n, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+	kfree(o);
+	kfree(n);
+	kfree(t);
+
+	if (!selinux_enforcing)
+		return 0;
+	return -EPERM;
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                 u16 tclass)
+{
+	struct context *ocontext;
+	struct context *ncontext;
+	struct context *tcontext;
+	struct class_datum *tclass_datum;
+	struct constraint_node *constraint;
+	int rc = 0;
+
+	if (!ss_initialized)
+		return 0;
+
+	POLICY_RDLOCK;
+
+	/*
+	 * Remap extended Netlink classes for old policy versions.
+	 * Do this here rather than socket_type_to_security_class()
+	 * in case a newer policy version is loaded, allowing sockets
+	 * to remain in the correct class.
+	 */
+	if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
+		if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
+		    tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
+			tclass = SECCLASS_NETLINK_SOCKET;
+
+	if (!tclass || tclass > policydb.p_classes.nprim) {
+		printk(KERN_ERR "security_validate_transition:  "
+		       "unrecognized class %d\n", tclass);
+		rc = -EINVAL;
+		goto out;
+	}
+	tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+	ocontext = sidtab_search(&sidtab, oldsid);
+	if (!ocontext) {
+		printk(KERN_ERR "security_validate_transition: "
+		       " unrecognized SID %d\n", oldsid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	ncontext = sidtab_search(&sidtab, newsid);
+	if (!ncontext) {
+		printk(KERN_ERR "security_validate_transition: "
+		       " unrecognized SID %d\n", newsid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	tcontext = sidtab_search(&sidtab, tasksid);
+	if (!tcontext) {
+		printk(KERN_ERR "security_validate_transition: "
+		       " unrecognized SID %d\n", tasksid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	constraint = tclass_datum->validatetrans;
+	while (constraint) {
+		if (!constraint_expr_eval(ocontext, ncontext, tcontext,
+		                          constraint->expr)) {
+			rc = security_validtrans_handle_fail(ocontext, ncontext,
+			                                     tcontext, tclass);
+			goto out;
+		}
+		constraint = constraint->next;
+	}
+
+out:
+	POLICY_RDUNLOCK;
+	return rc;
+}
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
@@ -313,8 +476,8 @@ int security_compute_av(u32 ssid,
 	int rc = 0;
 
 	if (!ss_initialized) {
-		avd->allowed = requested;
-		avd->decided = requested;
+		avd->allowed = 0xffffffff;
+		avd->decided = 0xffffffff;
 		avd->auditallow = 0;
 		avd->auditdeny = 0xffffffff;
 		avd->seqno = latest_granting;
@@ -352,7 +515,7 @@ out:
  * to point to this string and set `*scontext_len' to
  * the length of the string.
  */
-int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
 {
 	char *scontextp;
 
@@ -366,7 +529,7 @@ int context_struct_to_string(struct cont
 	*scontext_len += mls_compute_context_len(context);
 
 	/* Allocate space for the context; caller must free this space. */
-	scontextp = kmalloc(*scontext_len+1,GFP_ATOMIC);
+	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
 	if (!scontextp) {
 		return -ENOMEM;
 	}
@@ -375,17 +538,16 @@ int context_struct_to_string(struct cont
 	/*
 	 * Copy the user name, role name and type name into the context.
 	 */
-	sprintf(scontextp, "%s:%s:%s:",
+	sprintf(scontextp, "%s:%s:%s",
 		policydb.p_user_val_to_name[context->user - 1],
 		policydb.p_role_val_to_name[context->role - 1],
 		policydb.p_type_val_to_name[context->type - 1]);
 	scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
 	             1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
-	             1 + strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+	             1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
 
 	mls_sid_to_context(context, &scontextp);
 
-	scontextp--;
 	*scontextp = 0;
 
 	return 0;
@@ -715,23 +877,8 @@ static int security_compute_sid(u32 ssid
 				}
 			}
 		}
-
-		if (!type_change && !roletr) {
-			/* No change in process role or type. */
-			*out_sid = ssid;
-			goto out_unlock;
-
-		}
 		break;
 	default:
-		if (!type_change &&
-		    (newcontext.user == tcontext->user) &&
-		    mls_context_cmp(scontext, tcontext)) {
-                        /* No change in object type, owner,
-			   or MLS attributes. */
-			*out_sid = tsid;
-			goto out_unlock;
-		}
 		break;
 	}
 
@@ -1049,9 +1196,11 @@ int security_load_policy(void *data, siz
 		}
 		policydb_loaded_version = policydb.policyvers;
 		ss_initialized = 1;
-
+		seqno = ++latest_granting;
 		LOAD_UNLOCK;
 		selinux_complete_init();
+		avc_ss_reset(seqno);
+		selnl_notify_policyload(seqno);
 		return 0;
 	}
 
@@ -1363,36 +1512,37 @@ int security_get_user_sids(u32 fromsid,
 			if (!ebitmap_get_bit(&role->types, j))
 				continue;
 			usercon.type = j+1;
-			mls_for_user_ranges(user,usercon) {
-				rc = context_struct_compute_av(fromcon, &usercon,
-							       SECCLASS_PROCESS,
-							       PROCESS__TRANSITION,
-							       &avd);
-				if (rc ||  !(avd.allowed & PROCESS__TRANSITION))
-					continue;
-				rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
-				if (rc) {
+
+			if (mls_setup_user_range(fromcon, user, &usercon))
+				continue;
+
+			rc = context_struct_compute_av(fromcon, &usercon,
+						       SECCLASS_PROCESS,
+						       PROCESS__TRANSITION,
+						       &avd);
+			if (rc ||  !(avd.allowed & PROCESS__TRANSITION))
+				continue;
+			rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
+			if (rc) {
+				kfree(mysids);
+				goto out_unlock;
+			}
+			if (mynel < maxnel) {
+				mysids[mynel++] = sid;
+			} else {
+				maxnel += SIDS_NEL;
+				mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC);
+				if (!mysids2) {
+					rc = -ENOMEM;
 					kfree(mysids);
 					goto out_unlock;
 				}
-				if (mynel < maxnel) {
-					mysids[mynel++] = sid;
-				} else {
-					maxnel += SIDS_NEL;
-					mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC);
-					if (!mysids2) {
-						rc = -ENOMEM;
-						kfree(mysids);
-						goto out_unlock;
-					}
-					memset(mysids2, 0, maxnel*sizeof(*mysids2));
-					memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
-					kfree(mysids);
-					mysids = mysids2;
-					mysids[mynel++] = sid;
-				}
+				memset(mysids2, 0, maxnel*sizeof(*mysids2));
+				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
+				kfree(mysids);
+				mysids = mysids2;
+				mysids[mynel++] = sid;
 			}
-			mls_end_user_ranges;
 		}
 	}
 
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -9,12 +9,6 @@
 #include "policydb.h"
 #include "sidtab.h"
 
-/*
- * The security server uses two global data structures
- * when providing its services:  the SID table (sidtab)
- * and the policy database (policydb).
- */
-extern struct sidtab sidtab;
 extern struct policydb policydb;
 
 #endif	/* _SS_SERVICES_H_ */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -87,42 +87,6 @@ out:
 	return rc;
 }
 
-int sidtab_remove(struct sidtab *s, u32 sid)
-{
-	int hvalue, rc = 0;
-	struct sidtab_node *cur, *last;
-
-	if (!s) {
-		rc = -ENOENT;
-		goto out;
-	}
-
-	hvalue = SIDTAB_HASH(sid);
-	last = NULL;
-	cur = s->htable[hvalue];
-	while (cur != NULL && sid > cur->sid) {
-		last = cur;
-		cur = cur->next;
-	}
-
-	if (cur == NULL || sid != cur->sid) {
-		rc = -ENOENT;
-		goto out;
-	}
-
-	if (last == NULL)
-		s->htable[hvalue] = cur->next;
-	else
-		last->next = cur->next;
-
-	context_destroy(&cur->context);
-
-	kfree(cur);
-	s->nel--;
-out:
-	return rc;
-}
-
 struct context *sidtab_search(struct sidtab *s, u32 sid)
 {
 	int hvalue;
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
--- a/sound/arm/sa11xx-uda1341.c
+++ b/sound/arm/sa11xx-uda1341.c
@@ -21,7 +21,7 @@
  *                              merged HAL layer (patches from Brian)
  */
 
-/* $Id: sa11xx-uda1341.c,v 1.19 2004/12/15 15:26:10 tiwai Exp $ */
+/* $Id: sa11xx-uda1341.c,v 1.21 2005/01/28 19:34:04 tiwai Exp $ */
 
 /***************************************************************************************************
 *
@@ -862,7 +862,7 @@ static int __init snd_card_sa11xx_uda134
 
 #ifdef CONFIG_PM
 
-static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state)
+static int snd_sa11xx_uda1341_suspend(snd_card_t *card, pm_message_t state)
 {
 	sa11xx_uda1341_t *chip = card->pm_private_data;
 
@@ -878,7 +878,7 @@ static int snd_sa11xx_uda1341_suspend(sn
 	return 0;
 }
 
-static int snd_sa11xx_uda1341_resume(snd_card_t *card, unsigned int state)
+static int snd_sa11xx_uda1341_resume(snd_card_t *card)
 {
 	sa11xx_uda1341_t *chip = card->pm_private_data;
 
@@ -938,7 +938,7 @@ static int __init sa11xx_uda1341_init(vo
 	if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0)) < 0)
 		goto nodev;
         
-	snd_card_set_dev_pm_callback(card, PM_SYS_DEV,
+	snd_card_set_generic_pm_callback(card,
 				     snd_sa11xx_uda1341_suspend, snd_sa11_uda1341_resume,
 				     sa11xx_uda1341);
 
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -1,16 +1,20 @@
 # ALSA soundcard-configuration
 config SND_TIMER
 	tristate
+	depends on SND
 
 config SND_PCM
 	tristate
 	select SND_TIMER
+	depends on SND
 
 config SND_HWDEP
 	tristate
+	depends on SND
 
 config SND_RAWMIDI
 	tristate
+	depends on SND
 
 config SND_SEQUENCER
 	tristate "Sequencer support"
@@ -40,6 +44,7 @@ config SND_SEQ_DUMMY
 
 config SND_OSSEMUL
 	bool
+	depends on SND
 
 config SND_MIXER_OSS
 	tristate "OSS Mixer API"
@@ -70,7 +75,7 @@ config SND_PCM_OSS
 
 config SND_SEQUENCER_OSS
 	bool "OSS Sequencer API"
-	depends on SND_SEQUENCER
+	depends on SND && SND_SEQUENCER
 	select SND_OSSEMUL
 	help
 	  Say Y here to enable OSS sequencer emulation (both
@@ -81,20 +86,6 @@ config SND_SEQUENCER_OSS
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-seq-oss.
 
-config SND_BIT32_EMUL
-	tristate "Emulation for 32-bit applications"
-	depends on SND && COMPAT
-	select SND_PCM
-	select SND_RAWMIDI
-	select SND_TIMER
-	select SND_HWDEP
-	help
-	  Say Y here to enable the emulation for 32-bit ALSA-native
-	  applications.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-ioctl32.
-
 config SND_RTCTIMER
 	tristate "RTC Timer support"
 	depends on SND && RTC
@@ -137,3 +128,6 @@ config SND_DEBUG_DETECT
 	  Say Y here to enable extra-verbose log messages printed when
 	  detecting devices.
 
+config SND_GENERIC_PM
+	bool
+	depends on SND
diff --git a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -31,4 +31,3 @@ obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi
 
 obj-$(CONFIG_SND_OSSEMUL)	+= oss/
 obj-$(CONFIG_SND_SEQUENCER)	+= seq/
-obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
diff --git a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -43,6 +43,9 @@ typedef struct _snd_kctl_ioctl {
 
 static DECLARE_RWSEM(snd_ioctl_rwsem);
 static LIST_HEAD(snd_control_ioctls);
+#ifdef CONFIG_COMPAT
+static LIST_HEAD(snd_control_compat_ioctls);
+#endif
 
 static int snd_ctl_open(struct inode *inode, struct file *file)
 {
@@ -516,20 +519,25 @@ snd_kcontrol_t *snd_ctl_find_id(snd_card
 static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
 			     unsigned int cmd, void __user *arg)
 {
-	snd_ctl_card_info_t info;
+	snd_ctl_card_info_t *info;
 
-	memset(&info, 0, sizeof(info));
+	info = kcalloc(1, sizeof(*info), GFP_KERNEL);
+	if (! info)
+		return -ENOMEM;
 	down_read(&snd_ioctl_rwsem);
-	info.card = card->number;
-	strlcpy(info.id, card->id, sizeof(info.id));
-	strlcpy(info.driver, card->driver, sizeof(info.driver));
-	strlcpy(info.name, card->shortname, sizeof(info.name));
-	strlcpy(info.longname, card->longname, sizeof(info.longname));
-	strlcpy(info.mixername, card->mixername, sizeof(info.mixername));
-	strlcpy(info.components, card->components, sizeof(info.components));
+	info->card = card->number;
+	strlcpy(info->id, card->id, sizeof(info->id));
+	strlcpy(info->driver, card->driver, sizeof(info->driver));
+	strlcpy(info->name, card->shortname, sizeof(info->name));
+	strlcpy(info->longname, card->longname, sizeof(info->longname));
+	strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
+	strlcpy(info->components, card->components, sizeof(info->components));
 	up_read(&snd_ioctl_rwsem);
-	if (copy_to_user(arg, &info, sizeof(snd_ctl_card_info_t)))
+	if (copy_to_user(arg, info, sizeof(snd_ctl_card_info_t))) {
+		kfree(info);
 		return -EFAULT;
+	}
+	kfree(info);
 	return 0;
 }
 
@@ -595,43 +603,51 @@ static int snd_ctl_elem_list(snd_card_t 
 	return 0;
 }
 
-static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
+static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
 {
 	snd_card_t *card = ctl->card;
-	snd_ctl_elem_info_t info;
 	snd_kcontrol_t *kctl;
 	snd_kcontrol_volatile_t *vd;
 	unsigned int index_offset;
 	int result;
 	
-	if (copy_from_user(&info, _info, sizeof(info)))
-		return -EFAULT;
 	down_read(&card->controls_rwsem);
-	kctl = snd_ctl_find_id(card, &info.id);
+	kctl = snd_ctl_find_id(card, &info->id);
 	if (kctl == NULL) {
 		up_read(&card->controls_rwsem);
 		return -ENOENT;
 	}
 #ifdef CONFIG_SND_DEBUG
-	info.access = 0;
+	info->access = 0;
 #endif
-	result = kctl->info(kctl, &info);
+	result = kctl->info(kctl, info);
 	if (result >= 0) {
-		snd_assert(info.access == 0, );
-		index_offset = snd_ctl_get_ioff(kctl, &info.id);
+		snd_assert(info->access == 0, );
+		index_offset = snd_ctl_get_ioff(kctl, &info->id);
 		vd = &kctl->vd[index_offset];
-		snd_ctl_build_ioff(&info.id, kctl, index_offset);
-		info.access = vd->access;
+		snd_ctl_build_ioff(&info->id, kctl, index_offset);
+		info->access = vd->access;
 		if (vd->owner) {
-			info.access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
+			info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
 			if (vd->owner == ctl)
-				info.access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
-			info.owner = vd->owner_pid;
+				info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
+			info->owner = vd->owner_pid;
 		} else {
-			info.owner = -1;
+			info->owner = -1;
 		}
 	}
 	up_read(&card->controls_rwsem);
+	return result;
+}
+
+static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
+{
+	snd_ctl_elem_info_t info;
+	int result;
+
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	result = snd_ctl_elem_info(ctl, &info);
 	if (result >= 0)
 		if (copy_to_user(_info, &info, sizeof(info)))
 			return -EFAULT;
@@ -816,14 +832,6 @@ static int snd_ctl_elem_user_info(snd_kc
 	struct user_element *ue = kcontrol->private_data;
 
 	*uinfo = ue->info;
-	if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
-		uinfo->value.enumerated.items = ue->info.value.enumerated.items;
-		if (uinfo->value.enumerated.item >= ue->info.value.enumerated.items)
-			uinfo->value.enumerated.item = 0;
-		strlcpy(uinfo->value.enumerated.name,
-			(char *)ue->priv_data + uinfo->value.enumerated.item * 64,
-			64);
-	}
 	return 0;
 }
 
@@ -851,28 +859,25 @@ static void snd_ctl_elem_user_free(snd_k
 	kfree(kcontrol->private_data);
 }
 
-static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
+static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace)
 {
 	snd_card_t *card = file->card;
-	snd_ctl_elem_info_t info;
 	snd_kcontrol_t kctl, *_kctl;
 	unsigned int access;
-	long private_size, extra_size;
+	long private_size;
 	struct user_element *ue;
 	int idx, err;
 	
 	if (card->user_ctl_count >= MAX_USER_CONTROLS)
 		return -ENOMEM;
-	if (copy_from_user(&info, _info, sizeof(info)))
-		return -EFAULT;
-	if (info.count > 1024)
+	if (info->count > 1024)
 		return -EINVAL;
-	access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-		(info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
-	info.id.numid = 0;
+	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+		(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
+	info->id.numid = 0;
 	memset(&kctl, 0, sizeof(kctl));
 	down_write(&card->controls_rwsem);
-	_kctl = snd_ctl_find_id(card, &info.id);
+	_kctl = snd_ctl_find_id(card, &info->id);
 	err = 0;
 	if (_kctl) {
 		if (replace)
@@ -886,67 +891,50 @@ static int snd_ctl_elem_add(snd_ctl_file
 	up_write(&card->controls_rwsem);
 	if (err < 0)
 		return err;
-	memcpy(&kctl.id, &info.id, sizeof(info.id));
-	kctl.count = info.owner ? info.owner : 1;
+	memcpy(&kctl.id, &info->id, sizeof(info->id));
+	kctl.count = info->owner ? info->owner : 1;
 	access |= SNDRV_CTL_ELEM_ACCESS_USER;
 	kctl.info = snd_ctl_elem_user_info;
 	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
 		kctl.get = snd_ctl_elem_user_get;
 	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
 		kctl.put = snd_ctl_elem_user_put;
-	extra_size = 0;
-	switch (info.type) {
+	switch (info->type) {
 	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 		private_size = sizeof(char);
-		if (info.count > 128)
+		if (info->count > 128)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_INTEGER:
 		private_size = sizeof(long);
-		if (info.count > 128)
+		if (info->count > 128)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 		private_size = sizeof(long long);
-		if (info.count > 64)
+		if (info->count > 64)
 			return -EINVAL;
 		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		private_size = sizeof(unsigned int);
-		if (info.count > 128)
-			return -EINVAL;
-		if (info.value.enumerated.items > 128)
-			return -EINVAL;
-		extra_size = info.value.enumerated.items * 64;
-		break;
 	case SNDRV_CTL_ELEM_TYPE_BYTES:
 		private_size = sizeof(unsigned char);
-		if (info.count > 512)
+		if (info->count > 512)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_IEC958:
 		private_size = sizeof(struct sndrv_aes_iec958);
-		if (info.count != 1)
+		if (info->count != 1)
 			return -EINVAL;
 		break;
 	default:
 		return -EINVAL;
 	}
-	private_size *= info.count;
-	ue = kcalloc(1, sizeof(struct user_element) + private_size + extra_size, GFP_KERNEL);
+	private_size *= info->count;
+	ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL);
 	if (ue == NULL)
 		return -ENOMEM;
-	ue->info = info;
-	ue->elem_data = (char *)ue + sizeof(ue);
+	ue->info = *info;
+	ue->elem_data = (char *)ue + sizeof(*ue);
 	ue->elem_data_size = private_size;
-	if (extra_size) {
-		ue->priv_data = (char *)ue + sizeof(ue) + private_size;
-		ue->priv_data_size = extra_size;
-		if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
-			if (copy_from_user(ue->priv_data, *(char __user **)info.value.enumerated.name, extra_size))
-				return -EFAULT;
-		}
-	}
 	kctl.private_free = snd_ctl_elem_user_free;
 	_kctl = snd_ctl_new(&kctl, access);
 	if (_kctl == NULL) {
@@ -969,6 +957,14 @@ static int snd_ctl_elem_add(snd_ctl_file
 	return 0;
 }
 
+static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
+{
+	snd_ctl_elem_info_t info;
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	return snd_ctl_elem_add(file, &info, replace);
+}
+
 static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
 {
 	snd_ctl_elem_id_t id;
@@ -1016,15 +1012,13 @@ static int snd_ctl_set_power_state(snd_c
 	switch (power_state) {
 	case SNDRV_CTL_POWER_D0:
 		if (card->power_state != power_state) {
-			/* FIXME: pass the correct state value */
-			card->pm_resume(card, 0);
+			card->pm_resume(card);
 			snd_power_change_state(card, power_state);
 		}
 		break;
 	case SNDRV_CTL_POWER_D3hot:
 		if (card->power_state != power_state) {
-			/* FIXME: pass the correct state value */
-			card->pm_suspend(card, 0);
+			card->pm_suspend(card, PMSG_SUSPEND);
 			snd_power_change_state(card, power_state);
 		}
 		break;
@@ -1039,8 +1033,7 @@ static int snd_ctl_set_power_state(snd_c
 }
 #endif
 
-static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, unsigned long arg)
+static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_ctl_file_t *ctl;
 	snd_card_t *card;
@@ -1061,7 +1054,7 @@ static inline int _snd_ctl_ioctl(struct 
 	case SNDRV_CTL_IOCTL_ELEM_LIST:
 		return snd_ctl_elem_list(ctl->card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_INFO:
-		return snd_ctl_elem_info(ctl, argp);
+		return snd_ctl_elem_info_user(ctl, argp);
 	case SNDRV_CTL_IOCTL_ELEM_READ:
 		return snd_ctl_elem_read_user(ctl->card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_WRITE:
@@ -1071,9 +1064,9 @@ static inline int _snd_ctl_ioctl(struct 
 	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
 		return snd_ctl_elem_unlock(ctl, argp);
 	case SNDRV_CTL_IOCTL_ELEM_ADD:
-		return snd_ctl_elem_add(ctl, argp, 0);
+		return snd_ctl_elem_add_user(ctl, argp, 0);
 	case SNDRV_CTL_IOCTL_ELEM_REPLACE:
-		return snd_ctl_elem_add(ctl, argp, 1);
+		return snd_ctl_elem_add_user(ctl, argp, 1);
 	case SNDRV_CTL_IOCTL_ELEM_REMOVE:
 		return snd_ctl_elem_remove(ctl, argp);
 	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
@@ -1113,17 +1106,6 @@ static inline int _snd_ctl_ioctl(struct 
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_ctl_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_ctl_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
 {
 	snd_ctl_file_t *ctl;
@@ -1199,7 +1181,7 @@ static unsigned int snd_ctl_poll(struct 
  * register the device-specific control-ioctls.
  * called from each device manager like pcm.c, hwdep.c, etc.
  */
-int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
+static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
 {
 	snd_kctl_ioctl_t *pn;
 
@@ -1208,22 +1190,34 @@ int snd_ctl_register_ioctl(snd_kctl_ioct
 		return -ENOMEM;
 	pn->fioctl = fcn;
 	down_write(&snd_ioctl_rwsem);
-	list_add_tail(&pn->list, &snd_control_ioctls);
+	list_add_tail(&pn->list, lists);
 	up_write(&snd_ioctl_rwsem);
 	return 0;
 }
 
+int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
+}
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
+}
+#endif
+
 /*
  * de-register the device-specific control-ioctls.
  */
-int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
+static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
 {
 	struct list_head *list;
 	snd_kctl_ioctl_t *p;
 
 	snd_runtime_check(fcn != NULL, return -EINVAL);
 	down_write(&snd_ioctl_rwsem);
-	list_for_each(list, &snd_control_ioctls) {
+	list_for_each(list, lists) {
 		p = list_entry(list, snd_kctl_ioctl_t, list);
 		if (p->fioctl == fcn) {
 			list_del(&p->list);
@@ -1237,6 +1231,19 @@ int snd_ctl_unregister_ioctl(snd_kctl_io
 	return -EINVAL;
 }
 
+int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
+}
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
+}
+
+#endif
+
 static int snd_ctl_fasync(int fd, struct file * file, int on)
 {
 	snd_ctl_file_t *ctl;
@@ -1249,6 +1256,15 @@ static int snd_ctl_fasync(int fd, struct
 }
 
 /*
+ * ioctl32 compat
+ */
+#ifdef CONFIG_COMPAT
+#include "control_compat.c"
+#else
+#define snd_ctl_ioctl_compat	NULL
+#endif
+
+/*
  *  INIT PART
  */
 
@@ -1259,7 +1275,8 @@ static struct file_operations snd_ctl_f_
 	.open =		snd_ctl_open,
 	.release =	snd_ctl_release,
 	.poll =		snd_ctl_poll,
-	.ioctl =	snd_ctl_ioctl,
+	.unlocked_ioctl =	snd_ctl_ioctl,
+	.compat_ioctl =	snd_ctl_ioctl_compat,
 	.fasync =	snd_ctl_fasync,
 };
 
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/control_compat.c
@@ -0,0 +1,412 @@
+/*
+ * compat ioctls for control API
+ *
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* this file included from control.c */
+
+#include <linux/compat.h>
+
+struct sndrv_ctl_elem_list32 {
+	u32 offset;
+	u32 space;
+	u32 used;
+	u32 count;
+	u32 pids;
+	unsigned char reserved[50];
+} /* don't set packed attribute here */;
+
+static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32)
+{
+	struct sndrv_ctl_elem_list __user *data;
+	compat_caddr_t ptr;
+	int err;
+
+	data = compat_alloc_user_space(sizeof(*data));
+
+	/* offset, space, used, count */
+	if (copy_in_user(data, data32, 4 * sizeof(u32)))
+		return -EFAULT;
+	/* pids */
+	if (get_user(ptr, &data32->pids) ||
+	    put_user(compat_ptr(ptr), &data->pids))
+		return -EFAULT;
+	err = snd_ctl_elem_list(card, data);
+	if (err < 0)
+		return err;
+	/* copy the result */
+	if (copy_in_user(data32, data, 4 * sizeof(u32)))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * control element info
+ * it uses union, so the things are not easy..
+ */
+
+struct sndrv_ctl_elem_info32 {
+	struct sndrv_ctl_elem_id id; // the size of struct is same
+	s32 type;
+	u32 access;
+	u32 count;
+	s32 owner;
+	union {
+		struct {
+			s32 min;
+			s32 max;
+			s32 step;
+		} integer;
+		struct {
+			u64 min;
+			u64 max;
+			u64 step;
+		} integer64;
+		struct {
+			u32 items;
+			u32 item;
+			char name[64];
+		} enumerated;
+		unsigned char reserved[128];
+	} value;
+	unsigned char reserved[64];
+} __attribute__((packed));
+
+static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32)
+{
+	struct sndrv_ctl_elem_info *data;
+	int err;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	/* copy id */
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
+		goto error;
+	/* we need to copy the item index.
+	 * hope this doesn't break anything..
+	 */
+	if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
+		goto error;
+	err = snd_ctl_elem_info(ctl, data);
+	if (err < 0)
+		goto error;
+	/* restore info to 32bit */
+	err = -EFAULT;
+	/* id, type, access, count */
+	if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
+	    copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
+		goto error;
+	if (put_user(data->owner, &data32->owner))
+		goto error;
+	switch (data->type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		if (put_user(data->value.integer.min, &data32->value.integer.min) ||
+		    put_user(data->value.integer.max, &data32->value.integer.max) ||
+		    put_user(data->value.integer.step, &data32->value.integer.step))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		if (copy_to_user(&data32->value.integer64,
+				 &data->value.integer64,
+				 sizeof(data->value.integer64)))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		if (copy_to_user(&data32->value.enumerated,
+				 &data->value.enumerated,
+				 sizeof(data->value.enumerated)))
+			goto error;
+		break;
+	default:
+		break;
+	}
+	err = 0;
+ error:
+	kfree(data);
+	return err;
+}
+
+/* read / write */
+struct sndrv_ctl_elem_value32 {
+	struct sndrv_ctl_elem_id id;
+	unsigned int indirect;	/* bit-field causes misalignment */
+        union {
+		s32 integer[128];
+		unsigned char data[512];
+#ifndef CONFIG_X86_64
+		s64 integer64[64];
+#endif
+        } value;
+        unsigned char reserved[128];
+};
+
+
+/* get the value type and count of the control */
+static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp)
+{
+	snd_kcontrol_t *kctl;
+	snd_ctl_elem_info_t info;
+	int err;
+
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, id);
+	if (! kctl) {
+		up_read(&card->controls_rwsem);
+		return -ENXIO;
+	}
+	info.id = *id;
+	err = kctl->info(kctl, &info);
+	up_read(&card->controls_rwsem);
+	if (err >= 0) {
+		err = info.type;
+		*countp = info.count;
+	}
+	return err;
+}
+
+static int get_elem_size(int type, int count)
+{
+	switch (type) {
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		return sizeof(s64) * count;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		return sizeof(int) * count;
+	case SNDRV_CTL_ELEM_TYPE_BYTES:
+		return 512;
+	case SNDRV_CTL_ELEM_TYPE_IEC958:
+		return sizeof(struct sndrv_aes_iec958);
+	default:
+		return -1;
+	}
+}
+
+static int copy_ctl_value_from_user(snd_card_t *card,
+				    struct sndrv_ctl_elem_value *data,
+				    struct sndrv_ctl_elem_value32 __user *data32,
+				    int *typep, int *countp)
+{
+	int i, type, count, size;
+	unsigned int indirect;
+
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
+		return -EFAULT;
+	if (get_user(indirect, &data32->indirect))
+		return -EFAULT;
+	if (indirect)
+		return -EINVAL;
+	type = get_ctl_type(card, &data->id, &count);
+	if (type < 0)
+		return type;
+
+	if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+		for (i = 0; i < count; i++) {
+			int val;
+			if (get_user(val, &data32->value.integer[i]))
+				return -EFAULT;
+			data->value.integer.value[i] = val;
+		}
+	} else {
+		size = get_elem_size(type, count);
+		if (size < 0) {
+			printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
+			return -EINVAL;
+		}
+		if (copy_from_user(data->value.bytes.data,
+				   data32->value.data, size))
+			return -EFAULT;
+	}
+
+	*typep = type;
+	*countp = count;
+	return 0;
+}
+
+/* restore the value to 32bit */
+static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32,
+				  struct sndrv_ctl_elem_value *data,
+				  int type, int count)
+{
+	int i, size;
+
+	if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+		for (i = 0; i < count; i++) {
+			int val;
+			val = data->value.integer.value[i];
+			if (put_user(val, &data32->value.integer[i]))
+				return -EFAULT;
+		}
+	} else {
+		size = get_elem_size(type, count);
+		if (copy_to_user(data32->value.data,
+				 data->value.bytes.data, size))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int snd_ctl_elem_read_user_compat(snd_card_t *card, 
+					 struct sndrv_ctl_elem_value32 __user *data32)
+{
+	struct sndrv_ctl_elem_value *data;
+	int err, type, count;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
+		goto error;
+	if ((err = snd_ctl_elem_read(card, data)) < 0)
+		goto error;
+	err = copy_ctl_value_to_user(data32, data, type, count);
+ error:
+	kfree(data);
+	return err;
+}
+
+static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file,
+					  struct sndrv_ctl_elem_value32 __user *data32)
+{
+	struct sndrv_ctl_elem_value *data;
+	int err, type, count;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0)
+		goto error;
+	if ((err = snd_ctl_elem_write(file->card, file, data)) < 0)
+		goto error;
+	err = copy_ctl_value_to_user(data32, data, type, count);
+ error:
+	kfree(data);
+	return err;
+}
+
+/* add or replace a user control */
+static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
+				   struct sndrv_ctl_elem_info32 __user *data32,
+				   int replace)
+{
+	struct sndrv_ctl_elem_info *data;
+	int err;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	/* id, type, access, count */ \
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
+	    copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
+		goto error;
+	if (get_user(data->owner, &data32->owner) ||
+	    get_user(data->type, &data32->type))
+		goto error;
+	switch (data->type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		if (get_user(data->value.integer.min, &data32->value.integer.min) ||
+		    get_user(data->value.integer.max, &data32->value.integer.max) ||
+		    get_user(data->value.integer.step, &data32->value.integer.step))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		if (copy_from_user(&data->value.integer64,
+				   &data32->value.integer64,
+				   sizeof(data->value.integer64)))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		if (copy_from_user(&data->value.enumerated,
+				   &data32->value.enumerated,
+				   sizeof(data->value.enumerated)))
+			goto error;
+		break;
+	default:
+		break;
+	}
+	err = snd_ctl_elem_add(file, data, replace);
+ error:
+	kfree(data);
+	return err;
+}  
+
+enum {
+	SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
+	SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
+	SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
+	SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
+	SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32),
+	SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32),
+};
+
+static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_ctl_file_t *ctl;
+	struct list_head *list;
+	void __user *argp = compat_ptr(arg);
+	int err;
+
+	ctl = file->private_data;
+	snd_assert(ctl && ctl->card, return -ENXIO);
+
+	switch (cmd) {
+	case SNDRV_CTL_IOCTL_PVERSION:
+	case SNDRV_CTL_IOCTL_CARD_INFO:
+	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+	case SNDRV_CTL_IOCTL_POWER:
+	case SNDRV_CTL_IOCTL_POWER_STATE:
+	case SNDRV_CTL_IOCTL_ELEM_LOCK:
+	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
+		return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_CTL_IOCTL_ELEM_LIST32:
+		return snd_ctl_elem_list_compat(ctl->card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_INFO32:
+		return snd_ctl_elem_info_compat(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_READ32:
+		return snd_ctl_elem_read_user_compat(ctl->card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_WRITE32:
+		return snd_ctl_elem_write_user_compat(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_ADD32:
+		return snd_ctl_elem_add_compat(ctl, argp, 0);
+	case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
+		return snd_ctl_elem_add_compat(ctl, argp, 1);
+	}
+
+	down_read(&snd_ioctl_rwsem);
+	list_for_each(list, &snd_control_compat_ioctls) {
+		snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list);
+		if (p->fioctl) {
+			err = p->fioctl(ctl->card, ctl, cmd, arg);
+			if (err != -ENOIOCTLCMD) {
+				up_read(&snd_ioctl_rwsem);
+				return err;
+			}
+		}
+	}
+	up_read(&snd_ioctl_rwsem);
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -223,7 +223,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_
 	/* check whether the dsp was already loaded */
 	if (hw->dsp_loaded & (1 << info.index))
 		return -EBUSY;
-	if (verify_area(VERIFY_READ, info.image, info.length))
+	if (!access_ok(VERIFY_READ, info.image, info.length))
 		return -EFAULT;
 	err = hw->ops.dsp_load(hw, &info);
 	if (err < 0)
@@ -232,8 +232,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_
 	return 0;
 }
 
-static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file,
-				   unsigned int cmd, unsigned long arg)
+static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
 {
 	snd_hwdep_t *hw = file->private_data;
 	void __user *argp = (void __user *)arg;
@@ -252,17 +251,6 @@ static inline int _snd_hwdep_ioctl(struc
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
-			   unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_hwdep_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	snd_hwdep_t *hw = file->private_data;
@@ -315,6 +303,12 @@ static int snd_hwdep_control_ioctl(snd_c
 	return -ENOIOCTLCMD;
 }
 
+#ifdef CONFIG_COMPAT
+#include "hwdep_compat.c"
+#else
+#define snd_hwdep_ioctl_compat	NULL
+#endif
+
 /*
 
  */
@@ -328,7 +322,8 @@ static struct file_operations snd_hwdep_
 	.open =		snd_hwdep_open,
 	.release =	snd_hwdep_release,
 	.poll =		snd_hwdep_poll,
-	.ioctl =	snd_hwdep_ioctl,
+	.unlocked_ioctl =	snd_hwdep_ioctl,
+	.compat_ioctl =	snd_hwdep_ioctl_compat,
 	.mmap =		snd_hwdep_mmap,
 };
 
@@ -509,12 +504,14 @@ static int __init alsa_hwdep_init(void)
 	}
 	snd_hwdep_proc_entry = entry;
 	snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
 	return 0;
 }
 
 static void __exit alsa_hwdep_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
 	if (snd_hwdep_proc_entry) {
 		snd_info_unregister(snd_hwdep_proc_entry);
 		snd_hwdep_proc_entry = NULL;
diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/hwdep_compat.c
@@ -0,0 +1,77 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for hwdep API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* This file is included from hwdep.c */
+
+#include <linux/compat.h>
+
+struct sndrv_hwdep_dsp_image32 {
+	u32 index;
+	unsigned char name[64];
+	u32 image;	/* pointer */
+	u32 length;
+	u32 driver_data;
+} /* don't set packed attribute here */;
+
+static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
+				     struct sndrv_hwdep_dsp_image32 __user *src)
+{
+	struct sndrv_hwdep_dsp_image *dst;
+	compat_caddr_t ptr;
+	u32 val;
+
+	dst = compat_alloc_user_space(sizeof(*dst));
+
+	/* index and name */
+	if (copy_in_user(dst, src, 4 + 64))
+		return -EFAULT;
+	if (get_user(ptr, &src->image) ||
+	    put_user(compat_ptr(ptr), &dst->image))
+		return -EFAULT;
+	if (get_user(val, &src->length) ||
+	    put_user(val, &dst->length))
+		return -EFAULT;
+	if (get_user(val, &src->driver_data) ||
+	    put_user(val, &dst->driver_data))
+		return -EFAULT;
+
+	return snd_hwdep_dsp_load(hw, dst);
+}
+
+enum {
+	SNDRV_HWDEP_IOCTL_DSP_LOAD32   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
+};
+
+static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
+{
+	snd_hwdep_t *hw = file->private_data;
+	void __user *argp = compat_ptr(arg);
+	switch (cmd) {
+	case SNDRV_HWDEP_IOCTL_PVERSION:
+	case SNDRV_HWDEP_IOCTL_INFO:
+	case SNDRV_HWDEP_IOCTL_DSP_STATUS:
+		return snd_hwdep_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_HWDEP_IOCTL_DSP_LOAD32:
+		return snd_hwdep_dsp_load_compat(hw, argp);
+	}
+	if (hw->ops.ioctl_compat)
+		return hw->ops.ioctl_compat(hw, file, cmd, arg);
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/core/info.c b/sound/core/info.c
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -92,19 +92,18 @@ static int snd_info_version_done(void);
 int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...)
 {
 	va_list args;
-	int res;
-	char sbuffer[512];
+	int len, res;
 
 	if (buffer->stop || buffer->error)
 		return 0;
+	len = buffer->len - buffer->size;
 	va_start(args, fmt);
-	res = vscnprintf(sbuffer, sizeof(sbuffer), fmt, args);
+	res = vsnprintf(buffer->curr, len, fmt, args);
 	va_end(args);
-	if (buffer->size + res >= buffer->len) {
+	if (res >= len) {
 		buffer->stop = 1;
 		return 0;
 	}
-	strcpy(buffer->curr, sbuffer);
 	buffer->curr += res;
 	buffer->size += res;
 	return res;
diff --git a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -39,7 +39,7 @@ struct snd_shutdown_f_ops {
 
 unsigned int snd_cards_lock = 0;	/* locked for registering/using */
 snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
-rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(snd_card_rwlock);
 
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
@@ -84,16 +84,13 @@ snd_card_t *snd_card_new(int idx, const 
 	write_lock(&snd_card_rwlock);
 	if (idx < 0) {
 		int idx2;
-		for (idx2 = 0; idx2 < snd_ecards_limit; idx2++)
-			if (!(snd_cards_lock & (1 << idx2))) {
+		for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+			if (~snd_cards_lock & idx & 1<<idx2) {
 				idx = idx2;
+				if (idx >= snd_ecards_limit)
+					snd_ecards_limit = idx + 1;
 				break;
 			}
-		if (idx < 0 && snd_ecards_limit < SNDRV_CARDS)
-			/* for dynamically additional devices like hotplug:
-			 * increment the limit if still free slot exists.
-			 */
-			idx = snd_ecards_limit++;
 	} else if (idx < snd_ecards_limit) {
 		if (snd_cards_lock & (1 << idx))
 			err = -ENODEV;	/* invalid */
@@ -229,6 +226,10 @@ int snd_card_disconnect(snd_card_t * car
 	return 0;	
 }
 
+#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
+static void snd_generic_device_unregister(struct snd_generic_device *dev);
+#endif
+
 /**
  *  snd_card_free - frees given soundcard structure
  *  @card: soundcard structure
@@ -252,9 +253,9 @@ int snd_card_free(snd_card_t * card)
 
 #ifdef CONFIG_PM
 	wake_up(&card->power_sleep);
-#ifdef CONFIG_ISA
+#ifdef CONFIG_SND_GENERIC_PM
 	if (card->pm_dev) {
-		pm_unregister(card->pm_dev);
+		snd_generic_device_unregister(card->pm_dev);
 		card->pm_dev = NULL;
 	}
 #endif
@@ -374,7 +375,7 @@ static void choose_default_id(snd_card_t
 
 	while (1) {
 	      	if (loops-- == 0) {
-      			snd_printk(KERN_ERR "unable to choose default card id (%s)", id);
+      			snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
       			strcpy(card->id, card->proc_root->name);
       			return;
       		}
@@ -719,8 +720,8 @@ int snd_power_wait(snd_card_t *card, uns
  * handler and from the control API.
  */
 int snd_card_set_pm_callback(snd_card_t *card,
-			     int (*suspend)(snd_card_t *, unsigned int),
-			     int (*resume)(snd_card_t *, unsigned int),
+			     int (*suspend)(snd_card_t *, pm_message_t),
+			     int (*resume)(snd_card_t *),
 			     void *private_data)
 {
 	card->pm_suspend = suspend;
@@ -729,56 +730,132 @@ int snd_card_set_pm_callback(snd_card_t 
 	return 0;
 }
 
-static int snd_generic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+#ifdef CONFIG_SND_GENERIC_PM
+/*
+ * use platform_device for generic power-management without a proper bus
+ * (e.g. ISA)
+ */
+struct snd_generic_device {
+	struct platform_device pdev;
+	snd_card_t *card;
+};
+
+#define get_snd_generic_card(dev)	container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card
+
+#define SND_GENERIC_NAME	"snd_generic_pm"
+
+static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level);
+static int snd_generic_resume(struct device *dev, u32 level);
+
+static struct device_driver snd_generic_driver = {
+	.name		= SND_GENERIC_NAME,
+	.bus		= &platform_bus_type,
+	.suspend	= snd_generic_suspend,
+	.resume		= snd_generic_resume,
+};
+
+static int generic_driver_registered;
+
+static void generic_driver_unregister(void)
+{
+	if (generic_driver_registered) {
+		generic_driver_registered--;
+		if (! generic_driver_registered)
+			driver_unregister(&snd_generic_driver);
+	}
+}
+
+static struct snd_generic_device *snd_generic_device_register(snd_card_t *card)
 {
-	snd_card_t *card = dev->data;
+	struct snd_generic_device *dev;
 
-	switch (rqst) {
-	case PM_SUSPEND:
-		if (card->power_state == SNDRV_CTL_POWER_D3hot)
-			break;
-		/* FIXME: the correct state value? */
-		card->pm_suspend(card, 0);
-		snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-		break;
-	case PM_RESUME:
-		if (card->power_state == SNDRV_CTL_POWER_D0)
-			break;
-		/* FIXME: the correct state value? */
-		card->pm_resume(card, 0);
-		snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-		break;
+	if (! generic_driver_registered) {
+		if (driver_register(&snd_generic_driver) < 0)
+			return NULL;
+	}
+	generic_driver_registered++;
+
+	dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
+	if (! dev) {
+		generic_driver_unregister();
+		return NULL;
+	}
+
+	dev->pdev.name = SND_GENERIC_NAME;
+	dev->pdev.id = card->number;
+	dev->card = card;
+	if (platform_device_register(&dev->pdev) < 0) {
+		kfree(dev);
+		generic_driver_unregister();
+		return NULL;
 	}
+	return dev;
+}
+
+static void snd_generic_device_unregister(struct snd_generic_device *dev)
+{
+	platform_device_unregister(&dev->pdev);
+	kfree(dev);
+	generic_driver_unregister();
+}
+
+/* suspend/resume callbacks for snd_generic platform device */
+static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+	snd_card_t *card;
+
+	if (level != SUSPEND_DISABLE)
+		return 0;
+
+	card = get_snd_generic_card(dev);
+	if (card->power_state == SNDRV_CTL_POWER_D3hot)
+		return 0;
+	card->pm_suspend(card, PMSG_SUSPEND);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
+}
+
+static int snd_generic_resume(struct device *dev, u32 level)
+{
+	snd_card_t *card;
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	card = get_snd_generic_card(dev);
+	if (card->power_state == SNDRV_CTL_POWER_D0)
+		return 0;
+	card->pm_resume(card);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
 
 /**
- * snd_card_set_dev_pm_callback - set the generic power-management callbacks
+ * snd_card_set_generic_pm_callback - set the generic power-management callbacks
  * @card: soundcard structure
- * @type: PM device type (PM_XXX)
  * @suspend: suspend callback function
  * @resume: resume callback function
  * @private_data: private data to pass to the callback functions
  *
  * Registers the power-management and sets the lowlevel callbacks for
- * the given card with the given PM type.  These callbacks are called
- * from the ALSA's common PM handler and from the control API.
+ * the given card.  These callbacks are called from the ALSA's common
+ * PM handler and from the control API.
  */
-int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
-				 int (*suspend)(snd_card_t *, unsigned int),
-				 int (*resume)(snd_card_t *, unsigned int),
+int snd_card_set_generic_pm_callback(snd_card_t *card,
+				 int (*suspend)(snd_card_t *, pm_message_t),
+				 int (*resume)(snd_card_t *),
 				 void *private_data)
 {
-	card->pm_dev = pm_register(type, 0, snd_generic_pm_callback);
+	card->pm_dev = snd_generic_device_register(card);
 	if (! card->pm_dev)
 		return -ENOMEM;
-	card->pm_dev->data = card;
 	snd_card_set_pm_callback(card, suspend, resume, private_data);
 	return 0;
 }
+#endif /* CONFIG_SND_GENERIC_PM */
 
 #ifdef CONFIG_PCI
-int snd_card_pci_suspend(struct pci_dev *dev, u32 state)
+int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
 {
 	snd_card_t *card = pci_get_drvdata(dev);
 	int err;
@@ -786,8 +863,7 @@ int snd_card_pci_suspend(struct pci_dev 
 		return 0;
 	if (card->power_state == SNDRV_CTL_POWER_D3hot)
 		return 0;
-	/* FIXME: correct state value? */
-	err = card->pm_suspend(card, 0);
+	err = card->pm_suspend(card, PMSG_SUSPEND);
 	pci_save_state(dev);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	return err;
@@ -802,8 +878,7 @@ int snd_card_pci_resume(struct pci_dev *
 		return 0;
 	/* restore the PCI config space */
 	pci_restore_state(dev);
-	/* FIXME: correct state value? */
-	card->pm_resume(card, 0);
+	card->pm_resume(card);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
diff --git a/sound/core/ioctl32/Makefile b/sound/core/ioctl32/Makefile
deleted file mode 100644
--- a/sound/core/ioctl32/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
-#
-
-snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
-ifneq ($(CONFIG_SND_SEQUENCER),n)
-  snd-ioctl32-objs += seq32.o
-endif
-
-obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
diff --git a/sound/core/ioctl32/hwdep32.c b/sound/core/ioctl32/hwdep32.c
deleted file mode 100644
--- a/sound/core/ioctl32/hwdep32.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for hwdep API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/hwdep.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_hwdep_dsp_image32 {
-	u32 index;
-	unsigned char name[64];
-	u32 image;	/* pointer */
-	u32 length;
-	u32 driver_data;
-} /* don't set packed attribute here */;
-
-static inline int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_hwdep_dsp_image __user *data, *dst;
-	struct sndrv_hwdep_dsp_image32 __user *data32, *src;
-	compat_caddr_t ptr;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* index and name */
-	if (copy_in_user(data, data32, 4 + 64))
-		return -EFAULT;
-	if (__get_user(ptr, &data32->image) ||
-	    __put_user(compat_ptr(ptr), &data->image))
-		return -EFAULT;
-	src = data32;
-	dst = data;
-	COPY_CVT(length);
-	COPY_CVT(driver_data);
-	return file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_HWDEP_IOCTL_DSP_LOAD32   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
-};
-
-struct ioctl32_mapper hwdep_mappers[] = {
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
-	{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
-	{ 0 },
-};
diff --git a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
deleted file mode 100644
--- a/sound/core/ioctl32/ioctl32.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for control API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/minors.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-
-/*
- * register/unregister mappers
- * exported for other modules
- */
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
-MODULE_LICENSE("GPL");
-
-int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
-int unregister_ioctl32_conversion(unsigned int cmd);
-
-
-int snd_ioctl32_register(struct ioctl32_mapper *mappers)
-{
-	int err;
-	struct ioctl32_mapper *m;
-
-	for (m = mappers; m->cmd; m++) {
-		err = register_ioctl32_conversion(m->cmd, m->handler);
-		if (err >= 0)
-			m->registered++;
-	}
-	return 0;
-}
-
-void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
-{
-	struct ioctl32_mapper *m;
-
-	for (m = mappers; m->cmd; m++) {
-		if (m->registered) {
-			unregister_ioctl32_conversion(m->cmd);
-			m->registered = 0;
-		}
-	}
-}
-
-
-/*
- * compatible wrapper
- */
-int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
-{
-	if (! filp->f_op || ! filp->f_op->ioctl)
-		return -ENOTTY;
-	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-}
-
-
-/*
- * Controls
- */
-
-struct sndrv_ctl_elem_list32 {
-	u32 offset;
-	u32 space;
-	u32 used;
-	u32 count;
-	u32 pids;
-	unsigned char reserved[50];
-} /* don't set packed attribute here */;
-
-static inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_list32 __user *data32;
-	struct sndrv_ctl_elem_list __user *data;
-	compat_caddr_t ptr;
-	int err;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* offset, space, used, count */
-	if (copy_in_user(data, data32, 4 * sizeof(u32)))
-		return -EFAULT;
-	/* pids */
-	if (__get_user(ptr, &data32->pids) ||
-	    __put_user(compat_ptr(ptr), &data->pids))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* copy the result */
-	if (copy_in_user(data32, data, 4 * sizeof(u32)))
-		return -EFAULT;
-	return 0;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
-
-/*
- * control element info
- * it uses union, so the things are not easy..
- */
-
-struct sndrv_ctl_elem_info32 {
-	struct sndrv_ctl_elem_id id; // the size of struct is same
-	s32 type;
-	u32 access;
-	u32 count;
-	s32 owner;
-	union {
-		struct {
-			s32 min;
-			s32 max;
-			s32 step;
-		} integer;
-		struct {
-			u64 min;
-			u64 max;
-			u64 step;
-		} integer64;
-		struct {
-			u32 items;
-			u32 item;
-			char name[64];
-		} enumerated;
-		unsigned char reserved[128];
-	} value;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-static inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_info __user *data, *src;
-	struct sndrv_ctl_elem_info32 __user *data32, *dst;
-	unsigned int type;
-	int err;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* copy id */
-	if (copy_in_user(&data->id, &data32->id, sizeof(data->id)))
-		return -EFAULT;
-	/* we need to copy the item index.
-	 * hope this doesn't break anything..
-	 */
-	if (copy_in_user(&data->value.enumerated.item,
-			 &data32->value.enumerated.item,
-			 sizeof(data->value.enumerated.item)))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* restore info to 32bit */
-	/* for COPY_CVT macro */
-	src = data;
-	dst = data32;
-	/* id, type, access, count */
-	if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) ||
-	    copy_in_user(&data32->type, &data->type, 3 * sizeof(u32)))
-		return -EFAULT;
-	COPY_CVT(owner);
-	__get_user(type, &data->type);
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		COPY_CVT(value.integer.min);
-		COPY_CVT(value.integer.max);
-		COPY_CVT(value.integer.step);
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-		if (copy_in_user(&data32->value.integer64,
-				 &data->value.integer64,
-				 sizeof(data->value.integer64)))
-			return -EFAULT;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		if (copy_in_user(&data32->value.enumerated,
-				 &data->value.enumerated,
-				 sizeof(data->value.enumerated)))
-			return -EFAULT;
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
-
-struct sndrv_ctl_elem_value32 {
-	struct sndrv_ctl_elem_id id;
-	unsigned int indirect;	/* bit-field causes misalignment */
-        union {
-		s32 integer[128];	/* integer and boolean need conversion */
-#ifndef CONFIG_X86_64
-		s64 integer64[64];	/* for alignment */
-#endif
-		unsigned char data[512];	/* others should be compatible */
-        } value;
-        unsigned char reserved[128];	/* not used */
-};
-
-
-/* hmm, it's so hard to retrieve the value type from the control id.. */
-static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id)
-{
-	snd_kcontrol_t *kctl;
-	snd_ctl_elem_info_t info;
-	int err;
-
-	down_read(&card->controls_rwsem);
-	kctl = snd_ctl_find_id(card, id);
-	if (! kctl) {
-		up_read(&card->controls_rwsem);
-		return -ENXIO;
-	}
-	info.id = *id;
-	err = kctl->info(kctl, &info);
-	up_read(&card->controls_rwsem);
-	if (err >= 0)
-		err = info.type;
-	return err;
-}
-
-extern int snd_major;
-
-static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_value *data;
-	struct sndrv_ctl_elem_value32 __user *data32;
-	snd_ctl_file_t *ctl;
-	int err, i, indirect;
-	int type;
-
-	/* sanity check */
-	if (imajor(file->f_dentry->d_inode) != snd_major ||
-	    SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL)
-		return -ENOTTY;
-
-	if ((ctl = file->private_data) == NULL)
-		return -ENOTTY;
-
-	data32 = compat_ptr(arg);
-	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) {
-		err = -EFAULT;
-		goto __end;
-	}
-	if (__get_user(indirect, &data32->indirect)) {
-		err = -EFAULT;
-		goto __end;
-	}
-	/* FIXME: indirect access is not supported */
-	if (indirect) {
-		err = -EINVAL;
-		goto __end;
-	}
-	type = get_ctl_type(ctl->card, &data->id);
-	if (type < 0) {
-		err = type;
-		goto __end;
-	}
-
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		for (i = 0; i < 128; i++) {
-			int val;
-			if (__get_user(val, &data32->value.integer[i])) {
-				err = -EFAULT;
-				goto __end;
-			}
-			data->value.integer.value[i] = val;
-		}
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-	case SNDRV_CTL_ELEM_TYPE_BYTES:
-	case SNDRV_CTL_ELEM_TYPE_IEC958:
-		if (__copy_from_user(data->value.bytes.data,
-				     data32->value.data,
-				     sizeof(data32->value.data))) {
-			err = -EFAULT;
-			goto __end;
-		}
-		break;
-	default:
-		printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
-		err = -EINVAL;
-		goto __end;
-	}
-
-	if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ)
-		err = snd_ctl_elem_read(ctl->card, data);
-	else
-		err = snd_ctl_elem_write(ctl->card, ctl, data);
-	if (err < 0)
-		goto __end;
-	/* restore info to 32bit */
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		for (i = 0; i < 128; i++) {
-			int val;
-			val = data->value.integer.value[i];
-			if (__put_user(val, &data32->value.integer[i])) {
-				err = -EFAULT;
-				goto __end;
-			}
-		}
-		break;
-	default:
-		if (__copy_to_user(data32->value.data,
-				   data->value.bytes.data,
-				   sizeof(data32->value.data))) {
-			err = -EFAULT;
-			goto __end;
-		}
-		break;
-		break;
-	}
-	err = 0;
-      __end:
-	kfree(data);
-	return err;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);
-
-/*
- */
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
-	SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
-	SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
-	SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
-};
-
-static struct ioctl32_mapper control_mappers[] = {
-	/* controls (without rawmidi, hwdep, timer releated ones) */
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO),
-	{ SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },
-	{ SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },
-	{ SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },
-	{ SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },
-	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE),
-	{ 0 }
-};
-
-
-/*
- */
-
-extern struct ioctl32_mapper pcm_mappers[];
-extern struct ioctl32_mapper rawmidi_mappers[];
-extern struct ioctl32_mapper timer_mappers[];
-extern struct ioctl32_mapper hwdep_mappers[];
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-extern struct ioctl32_mapper seq_mappers[];
-#endif
-
-static void snd_ioctl32_done(void)
-{
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-	snd_ioctl32_unregister(seq_mappers);
-#endif
-	snd_ioctl32_unregister(hwdep_mappers);
-	snd_ioctl32_unregister(timer_mappers);
-	snd_ioctl32_unregister(rawmidi_mappers);
-	snd_ioctl32_unregister(pcm_mappers);
-	snd_ioctl32_unregister(control_mappers);
-}
-
-static int __init snd_ioctl32_init(void)
-{
-	snd_ioctl32_register(control_mappers);
-	snd_ioctl32_register(pcm_mappers);
-	snd_ioctl32_register(rawmidi_mappers);
-	snd_ioctl32_register(timer_mappers);
-	snd_ioctl32_register(hwdep_mappers);
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-	snd_ioctl32_register(seq_mappers);
-#endif
-	return 0;
-}
-
-module_init(snd_ioctl32_init)
-module_exit(snd_ioctl32_done)
diff --git a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
deleted file mode 100644
--- a/sound/core/ioctl32/ioctl32.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *   32bit -> 64bit ioctl helpers
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- *
- * This file registers the converters from 32-bit ioctls to 64-bit ones.
- * The converter assumes that a 32-bit user-pointer can be casted by compat_ptr(x)
- * macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
- *
- */
-
-#ifndef __ALSA_IOCTL32_H
-#define __ALSA_IOCTL32_H
-
-#include <linux/compat.h>
-
-#define COPY(x) \
-	do { \
-		if (copy_in_user(&dst->x, &src->x, sizeof(dst->x))) \
-			return -EFAULT; \
-	} while (0)
-
-#define COPY_ARRAY(x) \
-	do { \
-		if (copy_in_user(dst->x, src->x, sizeof(dst->x))) \
-			return -EFAULT; \
-	} while (0)
-
-#define COPY_CVT(x) \
-	do { \
-		__typeof__(src->x) __val_tmp; \
-		if (get_user(__val_tmp, &src->x) || \
-		    put_user(__val_tmp, &dst->x))\
-			return -EFAULT; \
-	} while (0)
-
-#define convert_from_32(type, dstp, srcp)\
-{\
-	struct sndrv_##type __user *dst = dstp;\
-	struct sndrv_##type##32 __user *src = srcp;\
-	CVT_##sndrv_##type();\
-}
-
-#define convert_to_32(type, dstp, srcp)\
-{\
-	struct sndrv_##type __user *src = srcp;\
-	struct sndrv_##type##32 __user *dst = dstp;\
-	CVT_##sndrv_##type();\
-}
-
-
-#define DEFINE_ALSA_IOCTL(type) \
-static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\
-{\
-	struct sndrv_##type##32 __user *data32;\
-	struct sndrv_##type __user *data;\
-	int err;\
-	data32 = compat_ptr(arg);\
-	data = compat_alloc_user_space(sizeof(*data));\
-	convert_from_32(type, data, data32);\
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\
-	if (err < 0) \
-		return err;\
-	if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
-		convert_to_32(type, data32, data);\
-	}\
-	return 0;\
-}
-
-#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
-static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\
-	return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\
-}
-
-#define MAP_COMPAT(ctl) { ctl, snd_ioctl32_compat }
-
-struct ioctl32_mapper {
-	unsigned int cmd;
-	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
-	int registered;
-};
-
-int snd_ioctl32_compat(unsigned int, unsigned int, unsigned long, struct file *);
-
-int snd_ioctl32_register(struct ioctl32_mapper *mappers);
-void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
-
-#endif /* __ALSA_IOCTL32_H */
diff --git a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
deleted file mode 100644
--- a/sound/core/ioctl32/pcm32.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for PCM API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/time.h>
-#include <linux/slab.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/minors.h>
-#include "ioctl32.h"
-
-
-/* wrapper for sndrv_pcm_[us]frames */
-struct sndrv_pcm_sframes_str {
-	sndrv_pcm_sframes_t val;
-};
-struct sndrv_pcm_sframes_str32 {
-	s32 val;
-};
-struct sndrv_pcm_uframes_str {
-	sndrv_pcm_uframes_t val;
-};
-struct sndrv_pcm_uframes_str32 {
-	u32 val;
-};
-
-#define CVT_sndrv_pcm_sframes_str() { COPY_CVT(val); }
-#define CVT_sndrv_pcm_uframes_str() { COPY_CVT(val); }
-
-
-struct sndrv_pcm_hw_params32 {
-	u32 flags;
-	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
-	struct sndrv_mask mres[5];	/* reserved masks */
-	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
-	struct sndrv_interval ires[9];	/* reserved intervals */
-	u32 rmask;
-	u32 cmask;
-	u32 info;
-	u32 msbits;
-	u32 rate_num;
-	u32 rate_den;
-	u32 fifo_size;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-struct sndrv_pcm_sw_params32 {
-	s32 tstamp_mode;
-	u32 period_step;
-	u32 sleep_min;
-	u32 avail_min;
-	u32 xfer_align;
-	u32 start_threshold;
-	u32 stop_threshold;
-	u32 silence_threshold;
-	u32 silence_size;
-	u32 boundary;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_sw_params()\
-{\
-	COPY(tstamp_mode);\
-	COPY(period_step);\
-	COPY(sleep_min);\
-	COPY_CVT(avail_min);\
-	COPY_CVT(xfer_align);\
-	COPY_CVT(start_threshold);\
-	COPY_CVT(stop_threshold);\
-	COPY_CVT(silence_threshold);\
-	COPY_CVT(silence_size);\
-	COPY_CVT(boundary);\
-}
-
-struct sndrv_pcm_channel_info32 {
-	u32 channel;
-	u32 offset;
-	u32 first;
-	u32 step;
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_channel_info()\
-{\
-	COPY(channel);\
-	COPY_CVT(offset);\
-	COPY(first);\
-	COPY(step);\
-}
-
-struct sndrv_pcm_status32 {
-	s32 state;
-	struct compat_timespec trigger_tstamp;
-	struct compat_timespec tstamp;
-	u32 appl_ptr;
-	u32 hw_ptr;
-	s32 delay;
-	u32 avail;
-	u32 avail_max;
-	u32 overrange;
-	s32 suspended_state;
-	unsigned char reserved[60];
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_status()\
-{\
-	COPY(state);\
-	COPY_CVT(trigger_tstamp.tv_sec);\
-	COPY_CVT(trigger_tstamp.tv_nsec);\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY_CVT(appl_ptr);\
-	COPY_CVT(hw_ptr);\
-	COPY_CVT(delay);\
-	COPY_CVT(avail);\
-	COPY_CVT(avail_max);\
-	COPY_CVT(overrange);\
-	COPY(suspended_state);\
-}
-
-DEFINE_ALSA_IOCTL(pcm_uframes_str);
-DEFINE_ALSA_IOCTL(pcm_sframes_str);
-DEFINE_ALSA_IOCTL(pcm_sw_params);
-DEFINE_ALSA_IOCTL(pcm_channel_info);
-DEFINE_ALSA_IOCTL(pcm_status);
-
-/* sanity device check */
-extern int snd_major;
-static int sanity_check_pcm(struct file *file)
-{
-	unsigned short minor;
-	if (imajor(file->f_dentry->d_inode) != snd_major)
-		return -ENOTTY;
-	minor = iminor(file->f_dentry->d_inode);
-	if (minor >= 256 || 
-	    minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK)
-		return -ENOTTY;
-	return 0;
-}
-
-/* recalcuate the boundary within 32bit */
-static void recalculate_boundary(snd_pcm_runtime_t *runtime)
-{
-	if (! runtime->buffer_size)
-		return;
-	runtime->boundary = runtime->buffer_size;
-	while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
-		runtime->boundary *= 2;
-}
-
-/* both for HW_PARAMS and HW_REFINE */
-static int _snd_ioctl32_pcm_hw_params(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_pcm_hw_params32 __user *data32;
-	struct sndrv_pcm_hw_params *data;
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	snd_pcm_runtime_t *runtime;
-	int err;
-
-	if (sanity_check_pcm(file))
-		return -ENOTTY;
-	if (! (pcm_file = file->private_data))
-		return -ENOTTY;
-	if (! (substream = pcm_file->substream))
-		return -ENOTTY;
-	if (! (runtime = substream->runtime))
-		return -ENOTTY;
-
-	data32 = compat_ptr(arg);
-	data = kmalloc(sizeof(*data), GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-	if (copy_from_user(data, data32, sizeof(*data32))) {
-		err = -EFAULT;
-		goto error;
-	}
-	if (native_ctl == SNDRV_PCM_IOCTL_HW_REFINE)
-		err = snd_pcm_hw_refine(substream, data);
-	else
-		err = snd_pcm_hw_params(substream, data);
-	if (err < 0)
-		goto error;
-	if (copy_to_user(data32, data, sizeof(*data32)) ||
-	    __put_user((u32)data->fifo_size, &data32->fifo_size)) {
-		err = -EFAULT;
-		goto error;
-	}
-
-	if (native_ctl == SNDRV_PCM_IOCTL_HW_PARAMS)
-		recalculate_boundary(runtime);
- error:
-	kfree(data);
-	return err;
-}
-
-
-/*
- */
-struct sndrv_xferi32 {
-	s32 result;
-	u32 buf;
-	u32 frames;
-} __attribute__((packed));
-
-static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_xferi32 data32;
-	struct sndrv_xferi __user *data;
-	snd_pcm_sframes_t result;
-	int err;
-
-	if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
-		return -EFAULT;
-	data = compat_alloc_user_space(sizeof(*data));
-	if (put_user((snd_pcm_sframes_t)data32.result, &data->result) ||
-	    __put_user(compat_ptr(data32.buf), &data->buf) ||
-	    __put_user((snd_pcm_uframes_t)data32.frames, &data->frames))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* copy the result */
-	if (__get_user(result, &data->result))
-		return -EFAULT;
-	data32.result = result;
-	if (copy_to_user((void __user *)arg, &data32, sizeof(data32)))
-		return -EFAULT;
-	return 0;
-}
-
-
-/* snd_xfern needs remapping of bufs */
-struct sndrv_xfern32 {
-	s32 result;
-	u32 bufs;  /* this is void **; */
-	u32 frames;
-} __attribute__((packed));
-
-/*
- * xfern ioctl nees to copy (up to) 128 pointers on stack.
- * although we may pass the copied pointers through f_op->ioctl, but the ioctl
- * handler there expands again the same 128 pointers on stack, so it is better
- * to handle the function (calling pcm_readv/writev) directly in this handler.
- */
-static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	struct sndrv_xfern32 __user *srcptr = compat_ptr(arg);
-	struct sndrv_xfern32 data32;
-	void __user **bufs;
-	int err = 0, ch, i;
-	u32 __user *bufptr;
-
-	if (sanity_check_pcm(file))
-		return -ENOTTY;
-	if (! (pcm_file = file->private_data))
-		return -ENOTTY;
-	if (! (substream = pcm_file->substream))
-		return -ENOTTY;
-	if (! substream->runtime)
-		return -ENOTTY;
-
-	/* check validty of the command */
-	switch (native_ctl) {
-	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
-			return -EINVAL;
-		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
-			return -EBADFD;
-		break;
-	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
-			return -EINVAL;
-		break;
-	}
-	if ((ch = substream->runtime->channels) > 128)
-		return -EINVAL;
-	if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
-		return -EFAULT;
-	bufptr = compat_ptr(data32.bufs);
-	bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
-	if (bufs == NULL)
-		return -ENOMEM;
-	for (i = 0; i < ch; i++) {
-		u32 ptr;
-		if (get_user(ptr, bufptr)) {
-			kfree(bufs);
-			return -EFAULT;
-		}
-		bufs[ch] = compat_ptr(ptr);
-		bufptr++;
-	}
-	switch (native_ctl) {
-	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		err = snd_pcm_lib_writev(substream, bufs, data32.frames);
-		break;
-	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		err = snd_pcm_lib_readv(substream, bufs, data32.frames);
-		break;
-	}
-	if (err >= 0) {
-		if (put_user(err, &srcptr->result))
-			err = -EFAULT;
-	}
-	kfree(bufs);
-	return err;
-}
-
-
-struct sndrv_pcm_mmap_status32 {
-	s32 state;
-	s32 pad1;
-	u32 hw_ptr;
-	struct compat_timespec tstamp;
-	s32 suspended_state;
-} __attribute__((packed));
-
-struct sndrv_pcm_mmap_control32 {
-	u32 appl_ptr;
-	u32 avail_min;
-} __attribute__((packed));
-
-struct sndrv_pcm_sync_ptr32 {
-	u32 flags;
-	union {
-		struct sndrv_pcm_mmap_status32 status;
-		unsigned char reserved[64];
-	} s;
-	union {
-		struct sndrv_pcm_mmap_control32 control;
-		unsigned char reserved[64];
-	} c;
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_sync_ptr()\
-{\
-	COPY(flags);\
-	COPY(s.status.state);\
-	COPY(s.status.pad1);\
-	COPY_CVT(s.status.hw_ptr);\
-	COPY_CVT(s.status.tstamp.tv_sec);\
-	COPY_CVT(s.status.tstamp.tv_nsec);\
-	COPY(s.status.suspended_state);\
-	COPY_CVT(c.control.appl_ptr);\
-	COPY_CVT(c.control.avail_min);\
-}
-
-DEFINE_ALSA_IOCTL(pcm_sync_ptr);
-
-/*
- */
-
-DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_rewind, pcm_uframes_str, SNDRV_PCM_IOCTL_REWIND);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_forward, pcm_uframes_str, SNDRV_PCM_IOCTL_FORWARD);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_readi, xferi, SNDRV_PCM_IOCTL_READI_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_writei, xferi, SNDRV_PCM_IOCTL_WRITEI_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_readn, xfern, SNDRV_PCM_IOCTL_READN_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_writen, xfern, SNDRV_PCM_IOCTL_WRITEN_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_sync_ptr, pcm_sync_ptr, SNDRV_PCM_IOCTL_SYNC_PTR);
-
-
-/*
- * When PCM is used on 32bit mode, we need to disable
- * mmap of PCM status/control records because of the size
- * incompatibility.
- * 
- * Since INFO ioctl is always called at first, we mark the
- * mmap-disabling in this ioctl wrapper.
- */
-static int snd_pcm_info_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
-{
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	if (! filp->f_op || ! filp->f_op->ioctl)
-		return -ENOTTY;
-	pcm_file = filp->private_data;
-	if (! pcm_file)
-		return -ENOTTY;
-	substream = pcm_file->substream;
-	if (! substream)
-		return -ENOTTY;
-	substream->no_mmap_ctrl = 1;
-	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-}
-
-/*
- */
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
-	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
-	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
-	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
-	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
-	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
-	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
-	SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
-	SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
-	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
-	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
-	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
-	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
-
-};
-
-struct ioctl32_mapper pcm_mappers[] = {
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PVERSION),
-	/* MAP_COMPAT(SNDRV_PCM_IOCTL_INFO), */
-	{ SNDRV_PCM_IOCTL_INFO, snd_pcm_info_ioctl32 },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_TSTAMP),
-	{ SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) },
-	{ SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_HW_FREE),
-	{ SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) },
-	{ SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) },
-	{ SNDRV_PCM_IOCTL_DELAY32, AP(pcm_delay) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_HWSYNC),
-	{ SNDRV_PCM_IOCTL_SYNC_PTR32, AP(pcm_sync_ptr) },
-	{ SNDRV_PCM_IOCTL_CHANNEL_INFO32, AP(pcm_channel_info) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PREPARE),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_RESET),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_START),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_DROP),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_DRAIN),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PAUSE),
-	{ SNDRV_PCM_IOCTL_REWIND32, AP(pcm_rewind) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_RESUME),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_XRUN),
-	{ SNDRV_PCM_IOCTL_FORWARD32, AP(pcm_forward) },
-	{ SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(pcm_writei) },
-	{ SNDRV_PCM_IOCTL_READI_FRAMES32, AP(pcm_readi) },
-	{ SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(pcm_writen) },
-	{ SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_LINK),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_UNLINK),
-
-	{ 0 },
-};
diff --git a/sound/core/ioctl32/rawmidi32.c b/sound/core/ioctl32/rawmidi32.c
deleted file mode 100644
--- a/sound/core/ioctl32/rawmidi32.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for raw MIDI API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_rawmidi_params32 {
-	s32 stream;
-	u32 buffer_size;
-	u32 avail_min;
-	unsigned int no_active_sensing; /* avoid bit-field */
-	unsigned char reserved[16];
-} __attribute__((packed));
-
-#define CVT_sndrv_rawmidi_params()\
-{\
-	COPY(stream);\
-	COPY_CVT(buffer_size);\
-	COPY_CVT(avail_min);\
-	if (copy_in_user(((size_t __user *)&dst->avail_min + 1),\
-			 ((size_t __user *)&src->avail_min + 1), 4)) \
-		return -EFAULT;\
-}
-
-struct sndrv_rawmidi_status32 {
-	s32 stream;
-	struct compat_timespec tstamp;
-	u32 avail;
-	u32 xruns;
-	unsigned char reserved[16];
-} __attribute__((packed));
-
-#define CVT_sndrv_rawmidi_status()\
-{\
-	COPY(stream);\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY_CVT(avail);\
-	COPY_CVT(xruns);\
-}
-
-DEFINE_ALSA_IOCTL(rawmidi_params);
-DEFINE_ALSA_IOCTL(rawmidi_status);
-
-DEFINE_ALSA_IOCTL_ENTRY(rawmidi_params, rawmidi_params, SNDRV_RAWMIDI_IOCTL_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(rawmidi_status, rawmidi_status, SNDRV_RAWMIDI_IOCTL_STATUS);
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
-	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
-};
-
-struct ioctl32_mapper rawmidi_mappers[] = {
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_INFO),
-	{ SNDRV_RAWMIDI_IOCTL_PARAMS32, AP(rawmidi_params) },
-	{ SNDRV_RAWMIDI_IOCTL_STATUS32, AP(rawmidi_status) },
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DROP),
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DRAIN),
-
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE),
-
-	{ 0 },
-};
diff --git a/sound/core/ioctl32/seq32.c b/sound/core/ioctl32/seq32.c
deleted file mode 100644
--- a/sound/core/ioctl32/seq32.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for sequencer API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/timer.h>
-#include <asm/uaccess.h>
-#include <sound/asequencer.h>
-#include "ioctl32.h"
-
-struct sndrv_seq_port_info32 {
-	struct sndrv_seq_addr addr;	/* client/port numbers */
-	char name[64];			/* port name */
-
-	u32 capability;	/* port capability bits */
-	u32 type;		/* port type bits */
-	s32 midi_channels;		/* channels per MIDI port */
-	s32 midi_voices;		/* voices per MIDI port */
-	s32 synth_voices;		/* voices per SYNTH port */
-
-	s32 read_use;			/* R/O: subscribers for output (from this port) */
-	s32 write_use;			/* R/O: subscribers for input (to this port) */
-
-	u32 kernel;			/* reserved for kernel use (must be NULL) */
-	u32 flags;		/* misc. conditioning */
-	unsigned char time_queue;	/* queue # for timestamping */
-	char reserved[59];		/* for future use */
-};
-
-#define CVT_sndrv_seq_port_info()\
-{\
-	COPY(addr);\
-	COPY_ARRAY(name);\
-	COPY(capability);\
-	COPY(type);\
-	COPY(midi_channels);\
-	COPY(midi_voices);\
-	COPY(synth_voices);\
-	COPY(read_use);\
-	COPY(write_use);\
-	COPY(flags);\
-	COPY(time_queue);\
-}
-
-DEFINE_ALSA_IOCTL(seq_port_info);
-DEFINE_ALSA_IOCTL_ENTRY(create_port, seq_port_info, SNDRV_SEQ_IOCTL_CREATE_PORT);
-DEFINE_ALSA_IOCTL_ENTRY(delete_port, seq_port_info, SNDRV_SEQ_IOCTL_DELETE_PORT);
-DEFINE_ALSA_IOCTL_ENTRY(get_port_info, seq_port_info, SNDRV_SEQ_IOCTL_GET_PORT_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(set_port_info, seq_port_info, SNDRV_SEQ_IOCTL_SET_PORT_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(query_next_port, seq_port_info, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT);
-
-/*
- */
-#define AP(x) snd_ioctl32_##x
-
-enum {
-  SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
-};
-
-struct ioctl32_mapper seq_mappers[] = {
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_CLIENT_ID),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SYSTEM_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO),
-	{ SNDRV_SEQ_IOCTL_CREATE_PORT32, AP(create_port) },
-	{ SNDRV_SEQ_IOCTL_DELETE_PORT32, AP(delete_port) },
-	{ SNDRV_SEQ_IOCTL_GET_PORT_INFO32, AP(get_port_info) },
-	{ SNDRV_SEQ_IOCTL_SET_PORT_INFO32, AP(set_port_info) },
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_CREATE_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_DELETE_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_POOL),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_POOL),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_REMOVE_EVENTS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_SUBS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT),
-	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32, AP(query_next_port) },
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_RUNNING_MODE),
-	{ 0 },
-};
diff --git a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
deleted file mode 100644
--- a/sound/core/ioctl32/timer32.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for timer API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
- *
- *   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 <sound/driver.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/timer.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_timer_info32 {
-	u32 flags;
-	s32 card;
-	unsigned char id[64];
-	unsigned char name[80];
-	u32 reserved0;
-	u32 resolution;
-	unsigned char reserved[64];
-};
-
-#define CVT_sndrv_timer_info()\
-{\
-	COPY(flags);\
-	COPY(card);\
-	COPY_ARRAY(id);\
-	COPY_ARRAY(name);\
-	COPY_CVT(resolution);\
-}
-
-struct sndrv_timer_status32 {
-	struct compat_timespec tstamp;
-	u32 resolution;
-	u32 lost;
-	u32 overrun;
-	u32 queue;
-	unsigned char reserved[64];
-};
-
-#define CVT_sndrv_timer_status()\
-{\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY(resolution);\
-	COPY(lost);\
-	COPY(overrun);\
-	COPY(queue);\
-}
-
-DEFINE_ALSA_IOCTL(timer_info);
-DEFINE_ALSA_IOCTL(timer_status);
-
-DEFINE_ALSA_IOCTL_ENTRY(timer_info, timer_info, SNDRV_TIMER_IOCTL_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(timer_status, timer_status, SNDRV_TIMER_IOCTL_STATUS);
-
-/*
- */
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
-	SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
-};
-
-struct ioctl32_mapper timer_mappers[] = {
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_SELECT),
-	{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
-	{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) },
-#if 0
-	/* ** FIXME **
-	 * The following four entries are disabled because they conflict
-	 * with the TCOC* definitions.
-	 * Unfortunately, the current ioctl32 wrapper uses a single
-	 * hash table for all devices.  Once when the wrapper is fixed
-	 * with the table based on devices, they'll be back again.
-	 */
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_START),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
-#endif
-	{ 0 },
-};
diff --git a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -50,8 +50,8 @@ static long snd_alloc_kmalloc;
 static long snd_alloc_vmalloc;
 static LIST_HEAD(snd_alloc_kmalloc_list);
 static LIST_HEAD(snd_alloc_vmalloc_list);
-static spinlock_t snd_alloc_kmalloc_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t snd_alloc_vmalloc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock);
+static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
 #define KMALLOC_MAGIC 0x87654321
 #define VMALLOC_MAGIC 0x87654320
 static snd_info_entry_t *snd_memory_info_entry;
diff --git a/sound/core/misc.c b/sound/core/misc.c
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -40,7 +40,6 @@ int snd_task_name(struct task_struct *ta
 void snd_verbose_printk(const char *file, int line, const char *format, ...)
 {
 	va_list args;
-	char tmpbuf[512];
 	
 	if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
 		char tmp[] = "<0>";
@@ -51,9 +50,8 @@ void snd_verbose_printk(const char *file
 		printk("ALSA %s:%d: ", file, line);
 	}
 	va_start(args, format);
-	vsnprintf(tmpbuf, sizeof(tmpbuf), format, args);
+	vprintk(format, args);
 	va_end(args);
-	printk(tmpbuf);
 }
 #endif
 
@@ -61,7 +59,6 @@ void snd_verbose_printk(const char *file
 void snd_verbose_printd(const char *file, int line, const char *format, ...)
 {
 	va_list args;
-	char tmpbuf[512];
 	
 	if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
 		char tmp[] = "<0>";
@@ -72,9 +69,8 @@ void snd_verbose_printd(const char *file
 		printk(KERN_DEBUG "ALSA %s:%d: ", file, line);
 	}
 	va_start(args, format);
-	vsnprintf(tmpbuf, sizeof(tmpbuf), format, args);
+	vprintk(format, args);
 	va_end(args);
-	printk(tmpbuf);
 
 }
 #endif
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -359,16 +359,9 @@ static int snd_mixer_oss_ioctl1(snd_mixe
 	return -ENXIO;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_mixer_oss_ioctl(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg)
+static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	int err;
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
-	lock_kernel();
-	return err;
+	return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
 }
 
 int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg)
@@ -384,6 +377,13 @@ int snd_mixer_oss_ioctl_card(snd_card_t 
 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+/* all compatible */
+#define snd_mixer_oss_ioctl_compat	snd_mixer_oss_ioctl
+#else
+#define snd_mixer_oss_ioctl_compat	NULL
+#endif
+
 /*
  *  REGISTRATION PART
  */
@@ -393,7 +393,8 @@ static struct file_operations snd_mixer_
 	.owner =	THIS_MODULE,
 	.open =		snd_mixer_oss_open,
 	.release =	snd_mixer_oss_release,
-	.ioctl =	snd_mixer_oss_ioctl,
+	.unlocked_ioctl =	snd_mixer_oss_ioctl,
+	.compat_ioctl =	snd_mixer_oss_ioctl_compat,
 };
 
 static snd_minor_t snd_mixer_oss_reg =
@@ -521,7 +522,7 @@ static void snd_mixer_oss_get_volume1_vo
 		goto __unalloc;
 	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
 	snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
-	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, return);
+	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
 	*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
 	if (uinfo->count > 1)
 		*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
@@ -615,7 +616,7 @@ static void snd_mixer_oss_put_volume1_vo
 	if (uinfo == NULL || uctl == NULL)
 		goto __unalloc;
 	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
-	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, return);
+	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
 	uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
 	if (uinfo->count > 1)
 		uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
@@ -856,7 +857,7 @@ struct snd_mixer_oss_assign_table {
 
 static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, const char *name, int index, int item)
 {
-	snd_ctl_elem_info_t info;
+	snd_ctl_elem_info_t *info;
 	snd_kcontrol_t *kcontrol;
 	snd_card_t *card = mixer->card;
 	int err;
@@ -867,15 +868,22 @@ static int snd_mixer_oss_build_test(snd_
 		up_read(&card->controls_rwsem);
 		return 0;
 	}
-	if ((err = kcontrol->info(kcontrol, &info)) < 0) {
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (! info) {
 		up_read(&card->controls_rwsem);
+		return -ENOMEM;
+	}
+	if ((err = kcontrol->info(kcontrol, info)) < 0) {
+		up_read(&card->controls_rwsem);
+		kfree(info);
 		return err;
 	}
 	slot->numid[item] = kcontrol->id.numid;
 	up_read(&card->controls_rwsem);
-	if (info.count > slot->channels)
-		slot->channels = info.count;
+	if (info->count > slot->channels)
+		slot->channels = info->count;
 	slot->present |= 1 << item;
+	kfree(info);
 	return 0;
 }
 
@@ -960,10 +968,16 @@ static int snd_mixer_oss_build_input(snd
 		return 0;
 	down_read(&mixer->card->controls_rwsem);
 	if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
-		snd_ctl_elem_info_t uinfo;
+		snd_ctl_elem_info_t *uinfo;
 
-		memset(&uinfo, 0, sizeof(uinfo));
-		if (kctl->info(kctl, &uinfo)) {
+		uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+		if (! uinfo) {
+			up_read(&mixer->card->controls_rwsem);
+			return -ENOMEM;
+		}
+			
+		memset(uinfo, 0, sizeof(*uinfo));
+		if (kctl->info(kctl, uinfo)) {
 			up_read(&mixer->card->controls_rwsem);
 			return 0;
 		}
@@ -973,21 +987,22 @@ static int snd_mixer_oss_build_input(snd
 		if (!strcmp(str, "Master Mono"))
 			strcpy(str, "Mix Mono");
 		slot.capture_item = 0;
-		if (!strcmp(uinfo.value.enumerated.name, str)) {
+		if (!strcmp(uinfo->value.enumerated.name, str)) {
 			slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
 		} else {
-			for (slot.capture_item = 1; slot.capture_item < uinfo.value.enumerated.items; slot.capture_item++) {
-				uinfo.value.enumerated.item = slot.capture_item;
-				if (kctl->info(kctl, &uinfo)) {
+			for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
+				uinfo->value.enumerated.item = slot.capture_item;
+				if (kctl->info(kctl, uinfo)) {
 					up_read(&mixer->card->controls_rwsem);
 					return 0;
 				}
-				if (!strcmp(uinfo.value.enumerated.name, str)) {
+				if (!strcmp(uinfo->value.enumerated.name, str)) {
 					slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
 					break;
 				}
 			}
 		}
+		kfree(uinfo);
 	}
 	up_read(&mixer->card->controls_rwsem);
 	if (slot.present != 0) {
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -636,10 +636,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
-			ret = snd_pcm_lib_write(substream, ptr, frames);
+			ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
 			snd_leave_user(fs);
 		} else {
-			ret = snd_pcm_lib_write(substream, ptr, frames);
+			ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
 		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
@@ -679,10 +679,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
-			ret = snd_pcm_lib_read(substream, ptr, frames);
+			ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
 			snd_leave_user(fs);
 		} else {
-			ret = snd_pcm_lib_read(substream, ptr, frames);
+			ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
 		}
 		if (ret == -EPIPE) {
 			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
@@ -718,10 +718,10 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(sn
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
-			ret = snd_pcm_lib_writev(substream, bufs, frames);
+			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
 			snd_leave_user(fs);
 		} else {
-			ret = snd_pcm_lib_writev(substream, bufs, frames);
+			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
 		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
@@ -758,10 +758,10 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
-			ret = snd_pcm_lib_readv(substream, bufs, frames);
+			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
 			snd_leave_user(fs);
 		} else {
-			ret = snd_pcm_lib_readv(substream, bufs, frames);
+			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
 		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
@@ -777,7 +777,7 @@ static ssize_t snd_pcm_oss_write2(snd_pc
 		snd_pcm_plugin_channel_t *channels;
 		size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
 		if (!in_kernel) {
-			if (copy_from_user(runtime->oss.buffer, buf, bytes))
+			if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
 				return -EFAULT;
 			buf = runtime->oss.buffer;
 		}
@@ -839,7 +839,7 @@ static ssize_t snd_pcm_oss_write1(snd_pc
 					return xfer > 0 ? xfer : -EAGAIN;
 			}
 		} else {
-			tmp = snd_pcm_oss_write2(substream, (char *)buf, runtime->oss.period_bytes, 0);
+			tmp = snd_pcm_oss_write2(substream, (const char *)buf, runtime->oss.period_bytes, 0);
 			if (tmp <= 0)
 				return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 			runtime->oss.bytes += tmp;
@@ -858,7 +858,7 @@ static ssize_t snd_pcm_oss_read2(snd_pcm
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_pcm_sframes_t frames, frames1;
-	char *final_dst = buf;
+	char __user *final_dst = (char __user *)buf;
 	if (runtime->oss.plugin_first) {
 		snd_pcm_plugin_channel_t *channels;
 		size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
@@ -1058,6 +1058,7 @@ static int snd_pcm_oss_sync(snd_pcm_oss_
 			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
 				size = (runtime->frame_bits * size) / 8;
 				while (size > 0) {
+					mm_segment_t fs;
 					size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
 					size -= size1;
 					size1 *= 8;
@@ -1065,7 +1066,9 @@ static int snd_pcm_oss_sync(snd_pcm_oss_
 					snd_pcm_format_set_silence(runtime->format,
 								   runtime->oss.buffer,
 								   size1);
-					snd_pcm_lib_write(substream, runtime->oss.buffer, size1);
+					fs = snd_enter_user();
+					snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
+					snd_leave_user(fs);
 				}
 			} else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
 				void __user *buffers[runtime->channels];
@@ -1913,8 +1916,7 @@ static int snd_pcm_oss_release(struct in
 	return 0;
 }
 
-static inline int _snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
-				     unsigned int cmd, unsigned long arg)
+static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_oss_file_t *pcm_oss_file;
 	int __user *p = (int __user *)arg;
@@ -2073,16 +2075,12 @@ static inline int _snd_pcm_oss_ioctl(str
 	return -EINVAL;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_pcm_oss_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
+#ifdef CONFIG_COMPAT
+/* all compatible */
+#define snd_pcm_oss_ioctl_compat	snd_pcm_oss_ioctl
+#else
+#define snd_pcm_oss_ioctl_compat	NULL
+#endif
 
 static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
@@ -2296,7 +2294,7 @@ static void snd_pcm_oss_proc_write(snd_i
 				   snd_info_buffer_t * buffer)
 {
 	snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
-	char line[256], str[32], task_name[32], *ptr;
+	char line[128], str[32], task_name[32], *ptr;
 	int idx1;
 	snd_pcm_oss_setup_t *setup, *setup1, template;
 
@@ -2410,7 +2408,8 @@ static struct file_operations snd_pcm_os
 	.open =		snd_pcm_oss_open,
 	.release =	snd_pcm_oss_release,
 	.poll =		snd_pcm_oss_poll,
-	.ioctl =	snd_pcm_oss_ioctl,
+	.unlocked_ioctl =	snd_pcm_oss_ioctl,
+	.compat_ioctl =	snd_pcm_oss_ioctl_compat,
 	.mmap =		snd_pcm_oss_mmap,
 };
 
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -270,25 +270,35 @@ static const char *snd_pcm_oss_format_na
 #ifdef CONFIG_PROC_FS
 static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buffer_t *buffer)
 {
-	snd_pcm_info_t info;
+	snd_pcm_info_t *info;
 	int err;
+
 	snd_runtime_check(substream, return);
-	err = snd_pcm_info(substream, &info);
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (! info) {
+		printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n");
+		return;
+	}
+
+	err = snd_pcm_info(substream, info);
 	if (err < 0) {
 		snd_iprintf(buffer, "error %d\n", err);
+		kfree(info);
 		return;
 	}
-	snd_iprintf(buffer, "card: %d\n", info.card);
-	snd_iprintf(buffer, "device: %d\n", info.device);
-	snd_iprintf(buffer, "subdevice: %d\n", info.subdevice);
-	snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info.stream));
-	snd_iprintf(buffer, "id: %s\n", info.id);
-	snd_iprintf(buffer, "name: %s\n", info.name);
-	snd_iprintf(buffer, "subname: %s\n", info.subname);
-	snd_iprintf(buffer, "class: %d\n", info.dev_class);
-	snd_iprintf(buffer, "subclass: %d\n", info.dev_subclass);
-	snd_iprintf(buffer, "subdevices_count: %d\n", info.subdevices_count);
-	snd_iprintf(buffer, "subdevices_avail: %d\n", info.subdevices_avail);
+	snd_iprintf(buffer, "card: %d\n", info->card);
+	snd_iprintf(buffer, "device: %d\n", info->device);
+	snd_iprintf(buffer, "subdevice: %d\n", info->subdevice);
+	snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info->stream));
+	snd_iprintf(buffer, "id: %s\n", info->id);
+	snd_iprintf(buffer, "name: %s\n", info->name);
+	snd_iprintf(buffer, "subname: %s\n", info->subname);
+	snd_iprintf(buffer, "class: %d\n", info->dev_class);
+	snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
+	snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
+	snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
+	kfree(info);
 }
 
 static void snd_pcm_stream_proc_info_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
@@ -1004,6 +1014,7 @@ static int __init alsa_pcm_init(void)
 	snd_info_entry_t *entry;
 
 	snd_ctl_register_ioctl(snd_pcm_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
 	if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
 		snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read);
 		if (snd_info_register(entry) < 0) {
@@ -1018,6 +1029,7 @@ static int __init alsa_pcm_init(void)
 static void __exit alsa_pcm_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
 	if (snd_pcm_proc_entry) {
 		snd_info_unregister(snd_pcm_proc_entry);
 		snd_pcm_proc_entry = NULL;
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/pcm_compat.c
@@ -0,0 +1,513 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for PCM API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* This file included from pcm_native.c */
+
+#include <linux/compat.h>
+
+static int snd_pcm_ioctl_delay_compat(snd_pcm_substream_t *substream,
+				      s32 __user *src)
+{
+	snd_pcm_sframes_t delay;
+	mm_segment_t fs;
+	int err;
+
+	fs = snd_enter_user();
+	err = snd_pcm_delay(substream, &delay);
+	snd_leave_user(fs);
+	if (err < 0)
+		return err;
+	if (put_user(delay, src))
+		return -EFAULT;
+	return err;
+}
+
+static int snd_pcm_ioctl_rewind_compat(snd_pcm_substream_t *substream,
+				       u32 __user *src)
+{
+	snd_pcm_uframes_t frames;
+	int err;
+
+	if (get_user(frames, src))
+		return -EFAULT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_playback_rewind(substream, frames);
+	else
+		err = snd_pcm_capture_rewind(substream, frames);
+	if (put_user(err, src))
+		return -EFAULT;
+	return err < 0 ? err : 0;
+}
+
+static int snd_pcm_ioctl_forward_compat(snd_pcm_substream_t *substream,
+				       u32 __user *src)
+{
+	snd_pcm_uframes_t frames;
+	int err;
+
+	if (get_user(frames, src))
+		return -EFAULT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_playback_forward(substream, frames);
+	else
+		err = snd_pcm_capture_forward(substream, frames);
+	if (put_user(err, src))
+		return -EFAULT;
+	return err < 0 ? err : 0;
+}
+
+struct sndrv_pcm_hw_params32 {
+	u32 flags;
+	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
+	struct sndrv_mask mres[5];	/* reserved masks */
+	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	struct sndrv_interval ires[9];	/* reserved intervals */
+	u32 rmask;
+	u32 cmask;
+	u32 info;
+	u32 msbits;
+	u32 rate_num;
+	u32 rate_den;
+	u32 fifo_size;
+	unsigned char reserved[64];
+};
+
+struct sndrv_pcm_sw_params32 {
+	s32 tstamp_mode;
+	u32 period_step;
+	u32 sleep_min;
+	u32 avail_min;
+	u32 xfer_align;
+	u32 start_threshold;
+	u32 stop_threshold;
+	u32 silence_threshold;
+	u32 silence_size;
+	u32 boundary;
+	unsigned char reserved[64];
+};
+
+static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
+					  struct sndrv_pcm_sw_params32 __user *src)
+{
+	snd_pcm_sw_params_t params;
+	int err;
+
+	memset(&params, 0, sizeof(params));
+	if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
+	    get_user(params.period_step, &src->period_step) ||
+	    get_user(params.sleep_min, &src->sleep_min) ||
+	    get_user(params.avail_min, &src->avail_min) ||
+	    get_user(params.xfer_align, &src->xfer_align) ||
+	    get_user(params.start_threshold, &src->start_threshold) ||
+	    get_user(params.stop_threshold, &src->stop_threshold) ||
+	    get_user(params.silence_threshold, &src->silence_threshold) ||
+	    get_user(params.silence_size, &src->silence_size))
+		return -EFAULT;
+	err = snd_pcm_sw_params(substream, &params);
+	if (err < 0)
+		return err;
+	if (put_user(params.boundary, &src->boundary))
+		return -EFAULT;
+	return err;
+}
+
+struct sndrv_pcm_channel_info32 {
+	u32 channel;
+	u32 offset;
+	u32 first;
+	u32 step;
+};
+
+static int snd_pcm_ioctl_channel_info_compat(snd_pcm_substream_t *substream,
+					     struct sndrv_pcm_channel_info32 __user *src)
+{
+	snd_pcm_channel_info_t info;
+	int err;
+
+	if (get_user(info.channel, &src->channel) ||
+	    get_user(info.offset, &src->offset) ||
+	    get_user(info.first, &src->first) ||
+	    get_user(info.step, &src->step))
+		return -EFAULT;
+	err = snd_pcm_channel_info(substream, &info);
+	if (err < 0)
+		return err;
+	if (put_user(info.channel, &src->channel) ||
+	    put_user(info.offset, &src->offset) ||
+	    put_user(info.first, &src->first) ||
+	    put_user(info.step, &src->step))
+		return -EFAULT;
+	return err;
+}
+
+struct sndrv_pcm_status32 {
+	s32 state;
+	struct compat_timespec trigger_tstamp;
+	struct compat_timespec tstamp;
+	u32 appl_ptr;
+	u32 hw_ptr;
+	s32 delay;
+	u32 avail;
+	u32 avail_max;
+	u32 overrange;
+	s32 suspended_state;
+	unsigned char reserved[60];
+} __attribute__((packed));
+
+
+static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
+				      struct sndrv_pcm_status32 __user *src)
+{
+	snd_pcm_status_t status;
+	int err;
+
+	err = snd_pcm_status(substream, &status);
+	if (err < 0)
+		return err;
+
+	if (put_user(status.state, &src->state) ||
+	    put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) ||
+	    put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) ||
+	    put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
+	    put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+	    put_user(status.appl_ptr, &src->appl_ptr) ||
+	    put_user(status.hw_ptr, &src->hw_ptr) ||
+	    put_user(status.delay, &src->delay) ||
+	    put_user(status.avail, &src->avail) ||
+	    put_user(status.avail_max, &src->avail_max) ||
+	    put_user(status.overrange, &src->overrange) ||
+	    put_user(status.suspended_state, &src->suspended_state))
+		return -EFAULT;
+
+	return err;
+}
+
+/* recalcuate the boundary within 32bit */
+static void recalculate_boundary(snd_pcm_runtime_t *runtime)
+{
+	if (! runtime->buffer_size)
+		return;
+	runtime->boundary = runtime->buffer_size;
+	while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
+		runtime->boundary *= 2;
+}
+
+/* both for HW_PARAMS and HW_REFINE */
+static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
+					  int refine, 
+					  struct sndrv_pcm_hw_params32 __user *data32)
+{
+	struct sndrv_pcm_hw_params *data;
+	snd_pcm_runtime_t *runtime;
+	int err;
+
+	if (! (runtime = substream->runtime))
+		return -ENOTTY;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+	/* only fifo_size is different, so just copy all */
+	if (copy_from_user(data, data32, sizeof(*data32))) {
+		err = -EFAULT;
+		goto error;
+	}
+	if (refine)
+		err = snd_pcm_hw_refine(substream, data);
+	else
+		err = snd_pcm_hw_params(substream, data);
+	if (err < 0)
+		goto error;
+	if (copy_to_user(data32, data, sizeof(*data32)) ||
+	    put_user(data->fifo_size, &data32->fifo_size)) {
+		err = -EFAULT;
+		goto error;
+	}
+
+	if (! refine)
+		recalculate_boundary(runtime);
+ error:
+	kfree(data);
+	return err;
+}
+
+
+/*
+ */
+struct sndrv_xferi32 {
+	s32 result;
+	u32 buf;
+	u32 frames;
+};
+
+static int snd_pcm_ioctl_xferi_compat(snd_pcm_substream_t *substream,
+				      int dir, struct sndrv_xferi32 __user *data32)
+{
+	compat_caddr_t buf;
+	u32 frames;
+	int err;
+
+	if (! substream->runtime)
+		return -ENOTTY;
+	if (substream->stream != dir)
+		return -EINVAL;
+	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
+		return -EBADFD;
+
+	if (get_user(buf, &data32->buf) ||
+	    get_user(frames, &data32->frames))
+		return -EFAULT;
+
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
+	else
+		err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
+	if (err < 0)
+		return err;
+	/* copy the result */
+	if (put_user(err, &data32->result))
+		return -EFAULT;
+	return 0;
+}
+
+
+/* snd_xfern needs remapping of bufs */
+struct sndrv_xfern32 {
+	s32 result;
+	u32 bufs;  /* this is void **; */
+	u32 frames;
+};
+
+/*
+ * xfern ioctl nees to copy (up to) 128 pointers on stack.
+ * although we may pass the copied pointers through f_op->ioctl, but the ioctl
+ * handler there expands again the same 128 pointers on stack, so it is better
+ * to handle the function (calling pcm_readv/writev) directly in this handler.
+ */
+static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
+				      int dir, struct sndrv_xfern32 __user *data32)
+{
+	compat_caddr_t buf;
+	compat_caddr_t __user *bufptr;
+	u32 frames;
+	void __user **bufs;
+	int err, ch, i;
+
+	if (! substream->runtime)
+		return -ENOTTY;
+	if (substream->stream != dir)
+		return -EINVAL;
+
+	if ((ch = substream->runtime->channels) > 128)
+		return -EINVAL;
+	if (get_user(buf, &data32->bufs) ||
+	    get_user(frames, &data32->frames))
+		return -EFAULT;
+	bufptr = compat_ptr(buf);
+	bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
+	if (bufs == NULL)
+		return -ENOMEM;
+	for (i = 0; i < ch; i++) {
+		u32 ptr;
+		if (get_user(ptr, bufptr)) {
+			kfree(bufs);
+			return -EFAULT;
+		}
+		bufs[ch] = compat_ptr(ptr);
+		bufptr++;
+	}
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_lib_writev(substream, bufs, frames);
+	else
+		err = snd_pcm_lib_readv(substream, bufs, frames);
+	if (err >= 0) {
+		if (put_user(err, &data32->result))
+			err = -EFAULT;
+	}
+	kfree(bufs);
+	return err;
+}
+
+
+struct sndrv_pcm_mmap_status32 {
+	s32 state;
+	s32 pad1;
+	u32 hw_ptr;
+	struct compat_timespec tstamp;
+	s32 suspended_state;
+} __attribute__((packed));
+
+struct sndrv_pcm_mmap_control32 {
+	u32 appl_ptr;
+	u32 avail_min;
+};
+
+struct sndrv_pcm_sync_ptr32 {
+	u32 flags;
+	union {
+		struct sndrv_pcm_mmap_status32 status;
+		unsigned char reserved[64];
+	} s;
+	union {
+		struct sndrv_pcm_mmap_control32 control;
+		unsigned char reserved[64];
+	} c;
+} __attribute__((packed));
+
+static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
+					 struct sndrv_pcm_sync_ptr32 __user *src)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	volatile struct sndrv_pcm_mmap_status *status;
+	volatile struct sndrv_pcm_mmap_control *control;
+	u32 sflags;
+	struct sndrv_pcm_mmap_control scontrol;
+	struct sndrv_pcm_mmap_status sstatus;
+	int err;
+
+	snd_assert(runtime, return -EINVAL);
+
+	if (get_user(sflags, &src->flags) ||
+	    get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+	    get_user(scontrol.avail_min, &src->c.control.avail_min))
+		return -EFAULT;
+	if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
+		err = snd_pcm_hwsync(substream);
+		if (err < 0)
+			return err;
+	}
+	status = runtime->status;
+	control = runtime->control;
+	snd_pcm_stream_lock_irq(substream);
+	if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
+		control->appl_ptr = scontrol.appl_ptr;
+	else
+		scontrol.appl_ptr = control->appl_ptr;
+	if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+		control->avail_min = scontrol.avail_min;
+	else
+		scontrol.avail_min = control->avail_min;
+	sstatus.state = status->state;
+	sstatus.hw_ptr = status->hw_ptr;
+	sstatus.tstamp = status->tstamp;
+	sstatus.suspended_state = status->suspended_state;
+	snd_pcm_stream_unlock_irq(substream);
+	if (put_user(sstatus.state, &src->s.status.state) ||
+	    put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
+	    put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) ||
+	    put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) ||
+	    put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
+	    put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+	    put_user(scontrol.avail_min, &src->c.control.avail_min))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+/*
+ */
+enum {
+	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
+	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
+	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
+	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
+	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
+	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
+	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
+	SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
+	SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
+	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
+	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
+	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
+	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
+
+};
+
+static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_pcm_file_t *pcm_file;
+	snd_pcm_substream_t *substream;
+	void __user *argp = compat_ptr(arg);
+
+	pcm_file = file->private_data;
+	if (! pcm_file)
+		return -ENOTTY;
+	substream = pcm_file->substream;
+	if (! substream)
+		return -ENOTTY;
+
+	/*
+	 * When PCM is used on 32bit mode, we need to disable
+	 * mmap of PCM status/control records because of the size
+	 * incompatibility.
+	 */
+	substream->no_mmap_ctrl = 1;
+
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL_PVERSION:
+	case SNDRV_PCM_IOCTL_INFO:
+	case SNDRV_PCM_IOCTL_TSTAMP:
+	case SNDRV_PCM_IOCTL_HWSYNC:
+	case SNDRV_PCM_IOCTL_PREPARE:
+	case SNDRV_PCM_IOCTL_RESET:
+	case SNDRV_PCM_IOCTL_START:
+	case SNDRV_PCM_IOCTL_DROP:
+	case SNDRV_PCM_IOCTL_DRAIN:
+	case SNDRV_PCM_IOCTL_PAUSE:
+	case SNDRV_PCM_IOCTL_HW_FREE:
+	case SNDRV_PCM_IOCTL_RESUME:
+	case SNDRV_PCM_IOCTL_XRUN:
+	case SNDRV_PCM_IOCTL_LINK:
+	case SNDRV_PCM_IOCTL_UNLINK:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			return snd_pcm_playback_ioctl1(substream, cmd, argp);
+		else
+			return snd_pcm_capture_ioctl1(substream, cmd, argp);
+	case SNDRV_PCM_IOCTL_HW_REFINE32:
+		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
+	case SNDRV_PCM_IOCTL_HW_PARAMS32:
+		return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
+	case SNDRV_PCM_IOCTL_SW_PARAMS32:
+		return snd_pcm_ioctl_sw_params_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_STATUS32:
+		return snd_pcm_status_user_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_SYNC_PTR32:
+		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
+		return snd_pcm_ioctl_channel_info_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
+		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
+	case SNDRV_PCM_IOCTL_READI_FRAMES32:
+		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
+	case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
+		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
+	case SNDRV_PCM_IOCTL_READN_FRAMES32:
+		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
+	case SNDRV_PCM_IOCTL_DELAY32:
+		return snd_pcm_ioctl_delay_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_REWIND32:
+		return snd_pcm_ioctl_rewind_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_FORWARD32:
+		return snd_pcm_ioctl_forward_compat(substream, argp);
+	}
+
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1863,9 +1863,8 @@ static void snd_pcm_system_tick_set(snd_
 	if (ticks == 0)
 		del_timer(&runtime->tick_timer);
 	else {
+		ticks += (1000000 / HZ) - 1;
 		ticks /= (1000000 / HZ);
-		if (ticks % (1000000 / HZ))
-			ticks++;
 		mod_timer(&runtime->tick_timer, jiffies + ticks);
 	}
 }
@@ -2142,11 +2141,9 @@ static snd_pcm_sframes_t snd_pcm_lib_wri
 			break;
 		}
 		appl_ptr += frames;
-		if (appl_ptr >= runtime->boundary) {
-			runtime->control->appl_ptr = 0;
-		} else {
-			runtime->control->appl_ptr = appl_ptr;
-		}
+		if (appl_ptr >= runtime->boundary)
+			appl_ptr -= runtime->boundary;
+		runtime->control->appl_ptr = appl_ptr;
 		if (substream->ops->ack)
 			substream->ops->ack(substream);
 
@@ -2441,11 +2438,9 @@ static snd_pcm_sframes_t snd_pcm_lib_rea
 			break;
 		}
 		appl_ptr += frames;
-		if (appl_ptr >= runtime->boundary) {
-			runtime->control->appl_ptr = 0;
-		} else {
-			runtime->control->appl_ptr = appl_ptr;
-		}
+		if (appl_ptr >= runtime->boundary)
+			appl_ptr -= runtime->boundary;
+		runtime->control->appl_ptr = appl_ptr;
 		if (substream->ops->ack)
 			substream->ops->ack(substream);
 
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -291,7 +291,7 @@ struct page *snd_pcm_sgbuf_ops_page(snd_
  * @substream: the substream to allocate the DMA buffer to
  * @size: the requested buffer size in bytes
  *
- * Allocates the DMA buffer on the BUS type given by
+ * Allocates the DMA buffer on the BUS type given earlier to
  * snd_pcm_lib_preallocate_xxx_pages().
  *
  * Returns 1 if the buffer is changed, 0 if not changed, or a negative
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -65,7 +65,7 @@ static int snd_pcm_hw_params_old_user(sn
  *
  */
 
-rwlock_t snd_pcm_link_rwlock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
 
@@ -113,10 +113,18 @@ int snd_pcm_info(snd_pcm_substream_t * s
 
 int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _info)
 {
-	snd_pcm_info_t info;
-	int err = snd_pcm_info(substream, &info);
-	if (copy_to_user(_info, &info, sizeof(info)))
-		return -EFAULT;
+	snd_pcm_info_t *info;
+	int err;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (! info)
+		return -ENOMEM;
+	err = snd_pcm_info(substream, info);
+	if (err >= 0) {
+		if (copy_to_user(_info, info, sizeof(*info)))
+			err = -EFAULT;
+	}
+	kfree(info);
 	return err;
 }
 
@@ -602,17 +610,13 @@ static int snd_pcm_status_user(snd_pcm_s
 	return 0;
 }
 
-static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
+static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * info)
 {
-	snd_pcm_channel_info_t info;
 	snd_pcm_runtime_t *runtime;
-	int res;
 	unsigned int channel;
 	
 	snd_assert(substream != NULL, return -ENXIO);
-	if (copy_from_user(&info, _info, sizeof(info)))
-		return -EFAULT;
-	channel = info.channel;
+	channel = info->channel;
 	runtime = substream->runtime;
 	snd_pcm_stream_lock_irq(substream);
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
@@ -622,9 +626,19 @@ static int snd_pcm_channel_info(snd_pcm_
 	snd_pcm_stream_unlock_irq(substream);
 	if (channel >= runtime->channels)
 		return -EINVAL;
-	memset(&info, 0, sizeof(info));
-	info.channel = channel;
-	res = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, &info);
+	memset(info, 0, sizeof(*info));
+	info->channel = channel;
+	return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
+}
+
+static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
+{
+	snd_pcm_channel_info_t info;
+	int res;
+	
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	res = snd_pcm_channel_info(substream, &info);
 	if (res < 0)
 		return res;
 	if (copy_to_user(_info, &info, sizeof(info)))
@@ -1032,7 +1046,13 @@ static struct action_ops snd_pcm_action_
  */
 int snd_pcm_suspend(snd_pcm_substream_t *substream)
 {
-	return snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
+	int err;
+	unsigned long flags;
+
+	snd_pcm_stream_lock_irqsave(substream, flags);
+	err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
+	snd_pcm_stream_unlock_irqrestore(substream, flags);
+	return err;
 }
 
 /**
@@ -1051,11 +1071,8 @@ int snd_pcm_suspend_all(snd_pcm_t *pcm)
 			/* FIXME: the open/close code should lock this as well */
 			if (substream->runtime == NULL)
 				continue;
-			snd_pcm_stream_lock(substream);
-			if (substream->runtime->status->state != SNDRV_PCM_STATE_SUSPENDED)
-				err = snd_pcm_suspend(substream);
-			snd_pcm_stream_unlock(substream);
-			if (err < 0)
+			err = snd_pcm_suspend(substream);
+			if (err < 0 && err != -EBUSY)
 				return err;
 		}
 	}
@@ -2440,7 +2457,7 @@ static int snd_pcm_common_ioctl1(snd_pcm
 	case SNDRV_PCM_IOCTL_STATUS:
 		return snd_pcm_status_user(substream, arg);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
-		return snd_pcm_channel_info(substream, arg);
+		return snd_pcm_channel_info_user(substream, arg);
 	case SNDRV_PCM_IOCTL_PREPARE:
 		return snd_pcm_prepare(substream);
 	case SNDRV_PCM_IOCTL_RESET:
@@ -2640,40 +2657,28 @@ static int snd_pcm_capture_ioctl1(snd_pc
 	return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
 
-static int snd_pcm_playback_ioctl(struct inode *inode, struct file *file,
-				  unsigned int cmd, unsigned long arg)
+static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_file_t *pcm_file;
-	int err;
 
 	pcm_file = file->private_data;
 
 	if (((cmd >> 8) & 0xff) != 'A')
 		return -ENOTTY;
 
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
-	lock_kernel();
-	return err;
+	return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
 }
 
-static int snd_pcm_capture_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, unsigned long arg)
+static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_file_t *pcm_file;
-	int err;
 
 	pcm_file = file->private_data;
 
 	if (((cmd >> 8) & 0xff) != 'A')
 		return -ENOTTY;
 
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
-	lock_kernel();
-	return err;
+	return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
 }
 
 int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream,
@@ -2683,7 +2688,7 @@ int snd_pcm_kernel_playback_ioctl(snd_pc
 	int result;
 	
 	fs = snd_enter_user();
-	result = snd_pcm_playback_ioctl1(substream, cmd, arg);
+	result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg);
 	snd_leave_user(fs);
 	return result;
 }
@@ -2695,7 +2700,7 @@ int snd_pcm_kernel_capture_ioctl(snd_pcm
 	int result;
 	
 	fs = snd_enter_user();
-	result = snd_pcm_capture_ioctl1(substream, cmd, arg);
+	result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg);
 	snd_leave_user(fs);
 	return result;
 }
@@ -3103,8 +3108,8 @@ int snd_pcm_lib_mmap_iomem(snd_pcm_subst
 	area->vm_flags |= VM_IO;
 	size = area->vm_end - area->vm_start;
 	offset = area->vm_pgoff << PAGE_SHIFT;
-	if (io_remap_page_range(area, area->vm_start,
-				substream->runtime->dma_addr + offset,
+	if (io_remap_pfn_range(area, area->vm_start,
+				(substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
 				size, area->vm_page_prot))
 		return -EAGAIN;
 	atomic_inc(&substream->runtime->mmap_count);
@@ -3198,6 +3203,15 @@ static int snd_pcm_fasync(int fd, struct
 }
 
 /*
+ * ioctl32 compat
+ */
+#ifdef CONFIG_COMPAT
+#include "pcm_compat.c"
+#else
+#define snd_pcm_ioctl_compat	NULL
+#endif
+
+/*
  *  To be removed helpers to keep binary compatibility
  */
 
@@ -3318,7 +3332,8 @@ static struct file_operations snd_pcm_f_
 	.open =		snd_pcm_open,
 	.release =	snd_pcm_release,
 	.poll =		snd_pcm_playback_poll,
-	.ioctl =	snd_pcm_playback_ioctl,
+	.unlocked_ioctl =	snd_pcm_playback_ioctl,
+	.compat_ioctl = snd_pcm_ioctl_compat,
 	.mmap =		snd_pcm_mmap,
 	.fasync =	snd_pcm_fasync,
 };
@@ -3330,7 +3345,8 @@ static struct file_operations snd_pcm_f_
 	.open =		snd_pcm_open,
 	.release =	snd_pcm_release,
 	.poll =		snd_pcm_capture_poll,
-	.ioctl =	snd_pcm_capture_ioctl,
+	.unlocked_ioctl =	snd_pcm_capture_ioctl,
+	.compat_ioctl = snd_pcm_ioctl_compat,
 	.mmap =		snd_pcm_mmap,
 	.fasync =	snd_pcm_fasync,
 };
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -29,6 +29,8 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
 #include <sound/rawmidi.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -83,11 +85,34 @@ static inline int snd_rawmidi_ready_appe
 	       (!substream->append || runtime->avail >= count);
 }
 
-static int snd_rawmidi_init(snd_rawmidi_substream_t *substream)
+static void snd_rawmidi_input_event_tasklet(unsigned long data)
 {
-	snd_rawmidi_runtime_t *runtime = substream->runtime;
+	snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
+	substream->runtime->event(substream);
+}
+
+static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
+{
+	snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
+	substream->ops->trigger(substream, 1);
+}
+
+static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream)
+{
+	snd_rawmidi_runtime_t *runtime;
+
+	if ((runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
 	spin_lock_init(&runtime->lock);
 	init_waitqueue_head(&runtime->sleep);
+	if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
+		tasklet_init(&runtime->tasklet,
+			     snd_rawmidi_input_event_tasklet,
+			     (unsigned long)substream);
+	else
+		tasklet_init(&runtime->tasklet,
+			     snd_rawmidi_output_trigger_tasklet,
+			     (unsigned long)substream);
 	runtime->event = NULL;
 	runtime->buffer_size = PAGE_SIZE;
 	runtime->avail_min = 1;
@@ -95,32 +120,53 @@ static int snd_rawmidi_init(snd_rawmidi_
 		runtime->avail = 0;
 	else
 		runtime->avail = runtime->buffer_size;
-	if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL)
+	if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) {
+		kfree(runtime);
 		return -ENOMEM;
+	}
 	runtime->appl_ptr = runtime->hw_ptr = 0;
+	substream->runtime = runtime;
 	return 0;
 }
 
-static int snd_rawmidi_done_buffer(snd_rawmidi_runtime_t *runtime)
+static int snd_rawmidi_runtime_free(snd_rawmidi_substream_t * substream)
 {
-	if (runtime->buffer) {
-		kfree(runtime->buffer);
-		runtime->buffer = NULL;
-	}
+	snd_rawmidi_runtime_t *runtime = substream->runtime;
+
+	kfree(runtime->buffer);
+	kfree(runtime);
+	substream->runtime = NULL;
 	return 0;
 }
 
+static inline void snd_rawmidi_output_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+	if (up) {
+		tasklet_hi_schedule(&substream->runtime->tasklet);
+	} else {
+		tasklet_kill(&substream->runtime->tasklet);
+		substream->ops->trigger(substream, 0);
+	}
+}
+
+static void snd_rawmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+	substream->ops->trigger(substream, up);
+	if (!up && substream->runtime->event)
+		tasklet_kill(&substream->runtime->tasklet);
+}
+
 int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream)
 {
+	unsigned long flags;
 	snd_rawmidi_runtime_t *runtime = substream->runtime;
 
-	substream->ops->trigger(substream, 0);
-	runtime->trigger = 0;
+	snd_rawmidi_output_trigger(substream, 0);
 	runtime->drain = 0;
-	/* interrupts are not enabled at this moment,
-	   so spinlock is not required */
+	spin_lock_irqsave(&runtime->lock, flags);
 	runtime->appl_ptr = runtime->hw_ptr = 0;
 	runtime->avail = runtime->buffer_size;
+	spin_unlock_irqrestore(&runtime->lock, flags);
 	return 0;
 }
 
@@ -132,27 +178,22 @@ int snd_rawmidi_drain_output(snd_rawmidi
 
 	err = 0;
 	runtime->drain = 1;
-	while (runtime->avail < runtime->buffer_size) {
-		timeout = interruptible_sleep_on_timeout(&runtime->sleep, 10 * HZ);
-		if (signal_pending(current)) {
-			err = -ERESTARTSYS;
-			break;
-		}
-		if (runtime->avail < runtime->buffer_size && !timeout) {
-			snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
-			err = -EIO;
-			break;
-		}
+	timeout = wait_event_interruptible_timeout(runtime->sleep,
+				(runtime->avail >= runtime->buffer_size),
+				10*HZ);
+	if (signal_pending(current))
+		err = -ERESTARTSYS;
+	if (runtime->avail < runtime->buffer_size && !timeout) {
+		snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
+		err = -EIO;
 	}
 	runtime->drain = 0;
 	if (err != -ERESTARTSYS) {
 		/* we need wait a while to make sure that Tx FIFOs are empty */
 		if (substream->ops->drain)
 			substream->ops->drain(substream);
-		else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 20);
-		}
+		else
+			msleep(50);
 		snd_rawmidi_drop_output(substream);
 	}
 	return err;
@@ -160,14 +201,15 @@ int snd_rawmidi_drain_output(snd_rawmidi
 
 int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream)
 {
+	unsigned long flags;
 	snd_rawmidi_runtime_t *runtime = substream->runtime;
 
-	substream->ops->trigger(substream, 0);
-	runtime->trigger = 0;
+	snd_rawmidi_input_trigger(substream, 0);
 	runtime->drain = 0;
-	/* interrupts aren't enabled at this moment, so spinlock isn't needed */
+	spin_lock_irqsave(&runtime->lock, flags);
 	runtime->appl_ptr = runtime->hw_ptr = 0;
 	runtime->avail = 0;
+	spin_unlock_irqrestore(&runtime->lock, flags);
 	return 0;
 }
 
@@ -176,7 +218,7 @@ int snd_rawmidi_kernel_open(int cardnum,
 {
 	snd_rawmidi_t *rmidi;
 	struct list_head *list1, *list2;
-	snd_rawmidi_substream_t *sinput, *soutput;
+	snd_rawmidi_substream_t *sinput = NULL, *soutput = NULL;
 	snd_rawmidi_runtime_t *input = NULL, *output = NULL;
 	int err;
 
@@ -267,20 +309,11 @@ int snd_rawmidi_kernel_open(int cardnum,
 		list2 = list2->next;
 	}
 	if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
-		input = kcalloc(1, sizeof(*input), GFP_KERNEL);
-		if (input == NULL) {
-			err = -ENOMEM;
-			goto __error;
-		}
-		sinput->runtime = input;
-		if (snd_rawmidi_init(sinput) < 0) {
-			err = -ENOMEM;
+		if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
 			goto __error;
-		}
-		if ((err = sinput->ops->open(sinput)) < 0) {
-			sinput->runtime = NULL;
+		input = sinput->runtime;
+		if ((err = sinput->ops->open(sinput)) < 0)
 			goto __error;
-		}
 		sinput->opened = 1;
 		rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
 	} else {
@@ -289,26 +322,15 @@ int snd_rawmidi_kernel_open(int cardnum,
 	if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
 		if (soutput->opened)
 			goto __skip_output;
-		output = kcalloc(1, sizeof(*output), GFP_KERNEL);
-		if (output == NULL) {
-			err = -ENOMEM;
-			goto __error;
-		}
-		soutput->runtime = output;
-		if (snd_rawmidi_init(soutput) < 0) {
-			if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
+		if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
+			if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
 				sinput->ops->close(sinput);
-				sinput->runtime = NULL;
-			}
-			err = -ENOMEM;
 			goto __error;
 		}
+		output = soutput->runtime;
 		if ((err = soutput->ops->open(soutput)) < 0) {
-			if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
+			if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
 				sinput->ops->close(sinput);
-				sinput->runtime = NULL;
-			}
-			soutput->runtime = NULL;
 			goto __error;
 		}
 	      __skip_output:
@@ -331,14 +353,10 @@ int snd_rawmidi_kernel_open(int cardnum,
 	return 0;
 
       __error:
-	if (input != NULL) {
-		snd_rawmidi_done_buffer(input);
-		kfree(input);
-	}
-	if (output != NULL) {
-		snd_rawmidi_done_buffer(output);
-		kfree(output);
-	}
+	if (input != NULL)
+		snd_rawmidi_runtime_free(sinput);
+	if (output != NULL)
+		snd_rawmidi_runtime_free(soutput);
 	module_put(rmidi->card->module);
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
 		up(&rmidi->open_mutex);
@@ -465,14 +483,11 @@ int snd_rawmidi_kernel_release(snd_rawmi
 		substream = rfile->input;
 		rfile->input = NULL;
 		runtime = substream->runtime;
-		runtime->trigger = 0;
-		substream->ops->trigger(substream, 0);
+		snd_rawmidi_input_trigger(substream, 0);
 		substream->ops->close(substream);
-		snd_rawmidi_done_buffer(runtime);
 		if (runtime->private_free != NULL)
 			runtime->private_free(substream);
-		kfree(runtime);
-		substream->runtime = NULL;
+		snd_rawmidi_runtime_free(substream);
 		substream->opened = 0;
 		rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
 	}
@@ -487,13 +502,11 @@ int snd_rawmidi_kernel_release(snd_rawmi
 				snd_rawmidi_kernel_write(substream, &buf, 1);
 			}
 			if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
-				substream->ops->trigger(substream, 0);
+				snd_rawmidi_output_trigger(substream, 0);
 			substream->ops->close(substream);
-			snd_rawmidi_done_buffer(runtime);
 			if (runtime->private_free != NULL)
 				runtime->private_free(substream);
-			kfree(runtime);
-			substream->runtime = NULL;
+			snd_rawmidi_runtime_free(substream);
 			substream->opened = 0;
 			substream->append = 0;
 		}
@@ -673,8 +686,7 @@ static int snd_rawmidi_input_status(snd_
 	return 0;
 }
 
-static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
-				     unsigned int cmd, unsigned long arg)
+static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_rawmidi_file_t *rfile;
 	void __user *argp = (void __user *)arg;
@@ -784,17 +796,6 @@ static inline int _snd_rawmidi_ioctl(str
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_rawmidi_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_rawmidi_control_ioctl(snd_card_t * card,
 				     snd_ctl_file_t * control,
 				     unsigned int cmd,
@@ -887,7 +888,7 @@ int snd_rawmidi_receive(snd_rawmidi_subs
 			count1 = count;
 			if (count1 > (int)(runtime->buffer_size - runtime->avail)) {
 				count1 = runtime->buffer_size - runtime->avail;
-				runtime->xruns = count - count1;
+				runtime->xruns += count - count1;
 			}
 			if (count1 > 0) {
 				memcpy(runtime->buffer, buffer, count1);
@@ -897,13 +898,13 @@ int snd_rawmidi_receive(snd_rawmidi_subs
 			}
 		}
 	}
-	if (result > 0 && runtime->event == NULL) {
-		if (snd_rawmidi_ready(substream))
+	if (result > 0) {
+		if (runtime->event)
+			tasklet_hi_schedule(&runtime->tasklet);
+		else if (snd_rawmidi_ready(substream))
 			wake_up(&runtime->sleep);
 	}
 	spin_unlock_irqrestore(&runtime->lock, flags);
-	if (result > 0 && runtime->event)
-		runtime->event(substream);
 	return result;
 }
 
@@ -925,7 +926,8 @@ static long snd_rawmidi_kernel_read1(snd
 			memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1);
 		} else {
 			spin_unlock_irqrestore(&runtime->lock, flags);
-			if (copy_to_user(buf + result, runtime->buffer + runtime->appl_ptr, count1)) {
+			if (copy_to_user((char __user *)buf + result,
+					 runtime->buffer + runtime->appl_ptr, count1)) {
 				return result > 0 ? result : -EFAULT;
 			}
 			spin_lock_irqsave(&runtime->lock, flags);
@@ -942,8 +944,7 @@ static long snd_rawmidi_kernel_read1(snd
 
 long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *buf, long count)
 {
-	substream->runtime->trigger = 1;
-	substream->ops->trigger(substream, 1);
+	snd_rawmidi_input_trigger(substream, 1);
 	return snd_rawmidi_kernel_read1(substream, buf, count, 1);
 }
 
@@ -960,8 +961,7 @@ static ssize_t snd_rawmidi_read(struct f
 	if (substream == NULL)
 		return -EIO;
 	runtime = substream->runtime;
-	runtime->trigger = 1;
-	substream->ops->trigger(substream, 1);
+	snd_rawmidi_input_trigger(substream, 1);
 	result = 0;
 	while (count > 0) {
 		spin_lock_irq(&runtime->lock);
@@ -984,7 +984,7 @@ static ssize_t snd_rawmidi_read(struct f
 			spin_lock_irq(&runtime->lock);
 		}
 		spin_unlock_irq(&runtime->lock);
-		count1 = snd_rawmidi_kernel_read1(substream, buf, count, 0);
+		count1 = snd_rawmidi_kernel_read1(substream, (unsigned char *)buf, count, 0);
 		if (count1 < 0)
 			return result > 0 ? result : count1;
 		result += count1;
@@ -1012,8 +1012,6 @@ int snd_rawmidi_transmit_empty(snd_rawmi
 	}
 	spin_lock_irqsave(&runtime->lock, flags);
 	result = runtime->avail >= runtime->buffer_size;
-	if (result)
-		runtime->trigger = 1;
 	spin_unlock_irqrestore(&runtime->lock, flags);
 	return result;		
 }
@@ -1046,7 +1044,6 @@ int snd_rawmidi_transmit_peek(snd_rawmid
 	spin_lock_irqsave(&runtime->lock, flags);
 	if (runtime->avail >= runtime->buffer_size) {
 		/* warning: lowlevel layer MUST trigger down the hardware */
-		runtime->trigger = 0;
 		goto __skip;
 	}
 	if (count == 1) {	/* special case, faster code */
@@ -1061,8 +1058,12 @@ int snd_rawmidi_transmit_peek(snd_rawmid
 		memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1);
 		count -= count1;
 		result += count1;
-		if (count > 0)
+		if (count > 0) {
+			if (count > (int)(runtime->buffer_size - runtime->avail - count1))
+				count = runtime->buffer_size - runtime->avail - count1;
 			memcpy(buffer + count1, runtime->buffer, count);
+			result += count;
+		}
 	}
       __skip:
 	spin_unlock_irqrestore(&runtime->lock, flags);
@@ -1095,15 +1096,11 @@ int snd_rawmidi_transmit_ack(snd_rawmidi
 	runtime->hw_ptr %= runtime->buffer_size;
 	runtime->avail += count;
 	substream->bytes += count;
-	if (runtime->drain)
-		wake_up(&runtime->sleep);
-	else
-		if (count > 0 && runtime->event == NULL)
-			if (snd_rawmidi_ready(substream))
-				wake_up(&runtime->sleep);
+	if (count > 0) {
+		if (runtime->drain || snd_rawmidi_ready(substream))
+			wake_up(&runtime->sleep);
+	}
 	spin_unlock_irqrestore(&runtime->lock, flags);
-	if (count > 0 && runtime->event)
-		runtime->event(substream);
 	return count;
 }
 
@@ -1152,7 +1149,8 @@ static long snd_rawmidi_kernel_write1(sn
 			memcpy(runtime->buffer + runtime->appl_ptr, buf, count1);
 		} else {
 			spin_unlock_irqrestore(&runtime->lock, flags);
-			if (copy_from_user(runtime->buffer + runtime->appl_ptr, buf, count1)) {
+			if (copy_from_user(runtime->buffer + runtime->appl_ptr,
+					   (char __user *)buf, count1)) {
 				spin_lock_irqsave(&runtime->lock, flags);
 				result = result > 0 ? result : -EFAULT;
 				goto __end;
@@ -1167,12 +1165,10 @@ static long snd_rawmidi_kernel_write1(sn
 		count -= count1;
 	}
       __end:
-	if (result > 0)
-		runtime->trigger = 1;
 	count1 = runtime->avail < runtime->buffer_size;
 	spin_unlock_irqrestore(&runtime->lock, flags);
 	if (count1)
-		substream->ops->trigger(substream, 1);
+		snd_rawmidi_output_trigger(substream, 1);
 	return result;
 }
 
@@ -1217,7 +1213,7 @@ static ssize_t snd_rawmidi_write(struct 
 			spin_lock_irq(&runtime->lock);
 		}
 		spin_unlock_irq(&runtime->lock);
-		count1 = snd_rawmidi_kernel_write1(substream, buf, count, 0);
+		count1 = snd_rawmidi_kernel_write1(substream, (unsigned char *)buf, count, 0);
 		if (count1 < 0)
 			return result > 0 ? result : count1;
 		result += count1;
@@ -1257,8 +1253,7 @@ static unsigned int snd_rawmidi_poll(str
 	rfile = file->private_data;
 	if (rfile->input != NULL) {
 		runtime = rfile->input->runtime;
-		runtime->trigger = 1;
-		rfile->input->ops->trigger(rfile->input, 1);
+		snd_rawmidi_input_trigger(rfile->input, 1);
 		poll_wait(file, &runtime->sleep, wait);
 	}
 	if (rfile->output != NULL) {
@@ -1278,6 +1273,14 @@ static unsigned int snd_rawmidi_poll(str
 }
 
 /*
+ */
+#ifdef CONFIG_COMPAT
+#include "rawmidi_compat.c"
+#else
+#define snd_rawmidi_ioctl_compat	NULL
+#endif
+
+/*
 
  */
 
@@ -1347,7 +1350,8 @@ static struct file_operations snd_rawmid
 	.open =		snd_rawmidi_open,
 	.release =	snd_rawmidi_release,
 	.poll =		snd_rawmidi_poll,
-	.ioctl =	snd_rawmidi_ioctl,
+	.unlocked_ioctl =	snd_rawmidi_ioctl,
+	.compat_ioctl =	snd_rawmidi_ioctl_compat,
 };
 
 static snd_minor_t snd_rawmidi_reg =
@@ -1628,6 +1632,7 @@ static int __init alsa_rawmidi_init(void
 {
 
 	snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
 #ifdef CONFIG_SND_OSSEMUL
 	{ int i;
 	/* check device map table */
@@ -1649,6 +1654,7 @@ static int __init alsa_rawmidi_init(void
 static void __exit alsa_rawmidi_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
 }
 
 module_init(alsa_rawmidi_init)
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/rawmidi_compat.c
@@ -0,0 +1,120 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for raw MIDI API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* This file included from rawmidi.c */
+
+#include <linux/compat.h>
+
+struct sndrv_rawmidi_params32 {
+	s32 stream;
+	u32 buffer_size;
+	u32 avail_min;
+	unsigned int no_active_sensing; /* avoid bit-field */
+	unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
+					   struct sndrv_rawmidi_params32 __user *src)
+{
+	snd_rawmidi_params_t params;
+	unsigned int val;
+
+	if (rfile->output == NULL)
+		return -EINVAL;
+	if (get_user(params.stream, &src->stream) ||
+	    get_user(params.buffer_size, &src->buffer_size) ||
+	    get_user(params.avail_min, &src->avail_min) ||
+	    get_user(val, &src->no_active_sensing))
+		return -EFAULT;
+	params.no_active_sensing = val;
+	switch (params.stream) {
+	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		return snd_rawmidi_output_params(rfile->output, &params);
+	case SNDRV_RAWMIDI_STREAM_INPUT:
+		return snd_rawmidi_input_params(rfile->input, &params);
+	}
+	return -EINVAL;
+}
+
+struct sndrv_rawmidi_status32 {
+	s32 stream;
+	struct compat_timespec tstamp;
+	u32 avail;
+	u32 xruns;
+	unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
+					   struct sndrv_rawmidi_status32 __user *src)
+{
+	int err;
+	snd_rawmidi_status_t status;
+
+	if (rfile->output == NULL)
+		return -EINVAL;
+	if (get_user(status.stream, &src->stream))
+		return -EFAULT;
+
+	switch (status.stream) {
+	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		err = snd_rawmidi_output_status(rfile->output, &status);
+		break;
+	case SNDRV_RAWMIDI_STREAM_INPUT:
+		err = snd_rawmidi_input_status(rfile->input, &status);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (err < 0)
+		return err;
+
+	if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
+	    put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+	    put_user(status.avail, &src->avail) ||
+	    put_user(status.xruns, &src->xruns))
+		return -EFAULT;
+
+	return 0;
+}
+
+enum {
+	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
+	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
+};
+
+static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_rawmidi_file_t *rfile;
+	void __user *argp = compat_ptr(arg);
+
+	rfile = file->private_data;
+	switch (cmd) {
+	case SNDRV_RAWMIDI_IOCTL_PVERSION:
+	case SNDRV_RAWMIDI_IOCTL_INFO:
+	case SNDRV_RAWMIDI_IOCTL_DROP:
+	case SNDRV_RAWMIDI_IOCTL_DRAIN:
+		return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_RAWMIDI_IOCTL_PARAMS32:
+		return snd_rawmidi_ioctl_params_compat(rfile, argp);
+	case SNDRV_RAWMIDI_IOCTL_STATUS32:
+		return snd_rawmidi_ioctl_status_compat(rfile, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -183,4 +183,6 @@ MODULE_PARM_DESC(rtctimer_freq, "timer f
 
 MODULE_LICENSE("GPL");
 
+MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
+
 #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -59,7 +59,7 @@ static int odev_open(struct inode *inode
 static int odev_release(struct inode *inode, struct file *file);
 static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
 static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
-static int odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static unsigned int odev_poll(struct file *file, poll_table * wait);
 #ifdef CONFIG_PROC_FS
 static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
@@ -177,20 +177,20 @@ odev_write(struct file *file, const char
 	return snd_seq_oss_write(dp, buf, count, file);
 }
 
-static int
-odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long
+odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	seq_oss_devinfo_t *dp;
-	int err;
 	dp = file->private_data;
 	snd_assert(dp != NULL, return -EIO);
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_seq_oss_ioctl(dp, cmd, arg);
-	lock_kernel();
-	return err;
+	return snd_seq_oss_ioctl(dp, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+#define odev_ioctl_compat	odev_ioctl
+#else
+#define odev_ioctl_compat	NULL
+#endif
 
 static unsigned int
 odev_poll(struct file *file, poll_table * wait)
@@ -213,7 +213,8 @@ static struct file_operations seq_oss_f_
 	.open =		odev_open,
 	.release =	odev_release,
 	.poll =		odev_poll,
-	.ioctl =	odev_ioctl,
+	.unlocked_ioctl =	odev_ioctl,
+	.compat_ioctl =	odev_ioctl_compat,
 };
 
 static snd_minor_t seq_oss_reg = {
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -66,10 +66,17 @@ snd_seq_oss_create_client(void)
 {
 	int rc;
 	snd_seq_client_callback_t callback;
-	snd_seq_client_info_t info;
-	snd_seq_port_info_t port;
+	snd_seq_client_info_t *info;
+	snd_seq_port_info_t *port;
 	snd_seq_port_callback_t port_callback;
 
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	port = kmalloc(sizeof(*port), GFP_KERNEL);
+	if (!info || !port) {
+		rc = -ENOMEM;
+		goto __error;
+	}
+
 	/* create ALSA client */
 	memset(&callback, 0, sizeof(callback));
 
@@ -79,38 +86,38 @@ snd_seq_oss_create_client(void)
 
 	rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, &callback);
 	if (rc < 0)
-		return rc;
+		goto __error;
 
 	system_client = rc;
 	debug_printk(("new client = %d\n", rc));
 
 	/* set client information */
-	memset(&info, 0, sizeof(info));
-	info.client = system_client;
-	info.type = KERNEL_CLIENT;
-	strcpy(info.name, "OSS sequencer");
+	memset(info, 0, sizeof(*info));
+	info->client = system_client;
+	info->type = KERNEL_CLIENT;
+	strcpy(info->name, "OSS sequencer");
 
-	rc = call_ctl(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info);
+	rc = call_ctl(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info);
 
 	/* look up midi devices */
 	snd_seq_oss_midi_lookup_ports(system_client);
 
 	/* create annoucement receiver port */
-	memset(&port, 0, sizeof(port));
-	strcpy(port.name, "Receiver");
-	port.addr.client = system_client;
-	port.capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
-	port.type = 0;
+	memset(port, 0, sizeof(*port));
+	strcpy(port->name, "Receiver");
+	port->addr.client = system_client;
+	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
+	port->type = 0;
 
 	memset(&port_callback, 0, sizeof(port_callback));
 	/* don't set port_callback.owner here. otherwise the module counter
 	 * is incremented and we can no longer release the module..
 	 */
 	port_callback.event_input = receive_announce;
-	port.kernel = &port_callback;
+	port->kernel = &port_callback;
 	
-	call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
-	if ((system_port = port.addr.port) >= 0) {
+	call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+	if ((system_port = port->addr.port) >= 0) {
 		snd_seq_port_subscribe_t subs;
 
 		memset(&subs, 0, sizeof(subs));
@@ -120,9 +127,12 @@ snd_seq_oss_create_client(void)
 		subs.dest.port = system_port;
 		call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
 	}
+	rc = 0;
 
-
-	return 0;
+ __error:
+	kfree(port);
+	kfree(info);
+	return rc;
 }
 
 
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -56,7 +56,7 @@ struct seq_oss_midi_t {
 static int max_midi_devs;
 static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
 
-static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(register_lock);
 
 /*
  * prototypes
@@ -73,26 +73,27 @@ static int send_midi_event(seq_oss_devin
 int __init
 snd_seq_oss_midi_lookup_ports(int client)
 {
-	snd_seq_system_info_t sysinfo;
-	snd_seq_client_info_t clinfo;
-	snd_seq_port_info_t pinfo;
-	int rc;
+	snd_seq_client_info_t *clinfo;
+	snd_seq_port_info_t *pinfo;
 
-	rc = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SYSTEM_INFO, &sysinfo);
-	if (rc < 0)
-		return rc;
-	
-	memset(&clinfo, 0, sizeof(clinfo));
-	memset(&pinfo, 0, sizeof(pinfo));
-	clinfo.client = -1;
-	while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, &clinfo) == 0) {
-		if (clinfo.client == client)
+	clinfo = kcalloc(1, sizeof(*clinfo), GFP_KERNEL);
+	pinfo = kcalloc(1, sizeof(*pinfo), GFP_KERNEL);
+	if (! clinfo || ! pinfo) {
+		kfree(clinfo);
+		kfree(pinfo);
+		return -ENOMEM;
+	}
+	clinfo->client = -1;
+	while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
+		if (clinfo->client == client)
 			continue; /* ignore myself */
-		pinfo.addr.client = clinfo.client;
-		pinfo.addr.port = -1;
-		while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, &pinfo) == 0)
-			snd_seq_oss_midi_check_new_port(&pinfo);
+		pinfo->addr.client = clinfo->client;
+		pinfo->addr.port = -1;
+		while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
+			snd_seq_oss_midi_check_new_port(pinfo);
 	}
+	kfree(clinfo);
+	kfree(pinfo);
 	return 0;
 }
 
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -24,6 +24,7 @@
 #include "seq_oss_event.h"
 #include <sound/seq_oss_legacy.h>
 #include "../seq_lock.h"
+#include <linux/wait.h>
 
 /*
  * constants
@@ -165,7 +166,9 @@ snd_seq_oss_readq_pick(seq_oss_readq_t *
 void
 snd_seq_oss_readq_wait(seq_oss_readq_t *q)
 {
-	interruptible_sleep_on_timeout(&q->midi_sleep, q->pre_event_timeout);
+	wait_event_interruptible_timeout(q->midi_sleep,
+					 (q->qlen > 0 || q->head == q->tail),
+					 q->pre_event_timeout);
 }
 
 /*
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -75,7 +75,7 @@ static seq_oss_synth_t midi_synth_dev = 
 	"MIDI", /* name */
 };
 
-static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(register_lock);
 
 /*
  * prototypes
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -26,6 +26,7 @@
 #include <sound/seq_oss_legacy.h>
 #include "../seq_lock.h"
 #include "../seq_clientmgr.h"
+#include <linux/wait.h>
 
 
 /*
@@ -91,7 +92,6 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t
 {
 	seq_oss_devinfo_t *dp = q->dp;
 	abstime_t time;
-	unsigned long flags;
 
 	time = snd_seq_oss_timer_cur_tick(dp->timer);
 	if (q->sync_time >= time)
@@ -115,27 +115,13 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t
 		snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
 	}
 
-	spin_lock_irqsave(&q->sync_lock, flags);
-	if (! q->sync_event_put) { /* echoback event has been received */
-		spin_unlock_irqrestore(&q->sync_lock, flags);
-		return 0;
-	}
-		
-	/* wait for echo event */
-	spin_unlock(&q->sync_lock);
-	interruptible_sleep_on_timeout(&q->sync_sleep, HZ);
-	spin_lock(&q->sync_lock);
-	if (signal_pending(current)) {
+	wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
+	if (signal_pending(current))
 		/* interrupted - return 0 to finish sync */
 		q->sync_event_put = 0;
-		spin_unlock_irqrestore(&q->sync_lock, flags);
-		return 0;
-	}
-	spin_unlock_irqrestore(&q->sync_lock, flags);
-	if (q->sync_time >= time)
+	if (! q->sync_event_put || q->sync_time >= time)
 		return 0;
-	else
-		return 1;
+	return 1;
 }
 
 /*
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -37,8 +37,8 @@
 #include "seq_info.h"
 #include "seq_system.h"
 #include <sound/seq_device.h>
-#if defined(CONFIG_SND_BIT32_EMUL) || defined(CONFIG_SND_BIT32_EMUL_MODULE)
-#include "../ioctl32/ioctl32.h"
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
 #endif
 
 /* Client Manager
@@ -51,7 +51,7 @@
 #define SNDRV_SEQ_LFLG_OUTPUT	0x0002
 #define SNDRV_SEQ_LFLG_OPEN	(SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
 
-static spinlock_t clients_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clients_lock);
 static DECLARE_MUTEX(register_mutex);
 
 /*
@@ -375,7 +375,7 @@ static ssize_t snd_seq_read(struct file 
 	if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT))
 		return -ENXIO;
 
-	if (verify_area(VERIFY_WRITE, buf, count))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
 
 	/* check client structures are in place */
@@ -413,7 +413,7 @@ static ssize_t snd_seq_read(struct file 
 			}
 			count -= sizeof(snd_seq_event_t);
 			buf += sizeof(snd_seq_event_t);
-			err = snd_seq_expand_var_event(&cell->event, count, buf, 0, sizeof(snd_seq_event_t));
+			err = snd_seq_expand_var_event(&cell->event, count, (char *)buf, 0, sizeof(snd_seq_event_t));
 			if (err < 0)
 				break;
 			result += err;
@@ -1012,7 +1012,7 @@ static ssize_t snd_seq_write(struct file
 			event.data.ext.ptr = (char*)buf + sizeof(snd_seq_event_t);
 			len += extlen; /* increment data length */
 		} else {
-#if defined(CONFIG_SND_BIT32_EMUL) || defined(CONFIG_SND_BIT32_EMUL_MODULE)
+#ifdef CONFIG_COMPAT
 			if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
 				void *ptr = compat_ptr(event.data.raw32.d[1]);
 				event.data.ext.ptr = ptr;
@@ -2131,21 +2131,20 @@ static int snd_seq_do_ioctl(client_t *cl
 }
 
 
-static int snd_seq_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
+static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	client_t *client = (client_t *) file->private_data;
-	int err;
 
 	snd_assert(client != NULL, return -ENXIO);
 		
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
-	lock_kernel();
-	return err;
+	return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
 
+#ifdef CONFIG_COMPAT
+#include "seq_compat.c"
+#else
+#define snd_seq_ioctl_compat	NULL
+#endif
 
 /* -------------------------------------------------------- */
 
@@ -2321,7 +2320,7 @@ int snd_seq_kernel_client_ctl(int client
 	if (client == NULL)
 		return -ENXIO;
 	fs = snd_enter_user();
-	result = snd_seq_do_ioctl(client, cmd, arg);
+	result = snd_seq_do_ioctl(client, cmd, (void __user *)arg);
 	snd_leave_user(fs);
 	return result;
 }
@@ -2462,7 +2461,8 @@ static struct file_operations snd_seq_f_
 	.open =		snd_seq_open,
 	.release =	snd_seq_release,
 	.poll =		snd_seq_poll,
-	.ioctl =	snd_seq_ioctl,
+	.unlocked_ioctl =	snd_seq_ioctl,
+	.compat_ioctl =	snd_seq_ioctl_compat,
 };
 
 static snd_minor_t snd_seq_reg =
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/seq/seq_compat.c
@@ -0,0 +1,137 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for sequencer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* This file included from seq.c */
+
+#include <linux/compat.h>
+
+struct sndrv_seq_port_info32 {
+	struct sndrv_seq_addr addr;	/* client/port numbers */
+	char name[64];			/* port name */
+
+	u32 capability;	/* port capability bits */
+	u32 type;		/* port type bits */
+	s32 midi_channels;		/* channels per MIDI port */
+	s32 midi_voices;		/* voices per MIDI port */
+	s32 synth_voices;		/* voices per SYNTH port */
+
+	s32 read_use;			/* R/O: subscribers for output (from this port) */
+	s32 write_use;			/* R/O: subscribers for input (to this port) */
+
+	u32 kernel;			/* reserved for kernel use (must be NULL) */
+	u32 flags;		/* misc. conditioning */
+	unsigned char time_queue;	/* queue # for timestamping */
+	char reserved[59];		/* for future use */
+};
+
+static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
+					struct sndrv_seq_port_info32 __user *data32)
+{
+	int err = -EFAULT;
+	snd_seq_port_info_t *data;
+	mm_segment_t fs;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	if (copy_from_user(data, data32, sizeof(*data32)) ||
+	    get_user(data->flags, &data32->flags) ||
+	    get_user(data->time_queue, &data32->time_queue))
+		goto error;
+	data->kernel = NULL;
+
+	fs = snd_enter_user();
+	err = snd_seq_do_ioctl(client, cmd, data);
+	snd_leave_user(fs);
+	if (err < 0)
+		goto error;
+
+	if (copy_to_user(data32, data, sizeof(*data32)) ||
+	    put_user(data->flags, &data32->flags) ||
+	    put_user(data->time_queue, &data32->time_queue))
+		err = -EFAULT;
+
+ error:
+	kfree(data);
+	return err;
+}
+
+
+
+/*
+ */
+
+enum {
+	SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
+};
+
+static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	client_t *client = (client_t *) file->private_data;
+	void __user *argp = compat_ptr(arg);
+
+	snd_assert(client != NULL, return -ENXIO);
+
+	switch (cmd) {
+	case SNDRV_SEQ_IOCTL_PVERSION:
+	case SNDRV_SEQ_IOCTL_CLIENT_ID:
+	case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
+	case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
+	case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
+	case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
+	case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
+	case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
+	case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
+	case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
+	case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
+	case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
+	case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
+	case SNDRV_SEQ_IOCTL_QUERY_SUBS:
+	case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
+	case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
+	case SNDRV_SEQ_IOCTL_RUNNING_MODE:
+		return snd_seq_do_ioctl(client, cmd, argp);
+	case SNDRV_SEQ_IOCTL_CREATE_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
+	case SNDRV_SEQ_IOCTL_DELETE_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
+	case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
+	case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
+	case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -63,6 +63,7 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA sequencer MIDI-through client");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
 
 static int ports = 1;
 static int duplex = 0;
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
--- a/sound/core/seq/seq_instr.c
+++ b/sound/core/seq/seq_instr.c
@@ -430,7 +430,7 @@ static int instr_put(snd_seq_kinstr_ops_
 
 	if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
 		goto __return;
-	if (copy_from_user(&put, ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
+	if (copy_from_user(&put, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
 		result = -EFAULT;
 		goto __return;
 	}
@@ -466,7 +466,7 @@ static int instr_put(snd_seq_kinstr_ops_
 	if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) {
 		result = ops->put(ops->private_data,
 				  instr,
-				  ev->data.ext.ptr + sizeof(snd_seq_instr_header_t),
+				  (void __user *)ev->data.ext.ptr + sizeof(snd_seq_instr_header_t),
 				  ev->data.ext.len - sizeof(snd_seq_instr_header_t),
 				  atomic,
 				  put.cmd);
@@ -513,7 +513,7 @@ static int instr_free(snd_seq_kinstr_ops
 
 	if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
 		goto __return;
-	if (copy_from_user(&ifree, ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
+	if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
 		result = -EFAULT;
 		goto __return;
 	}
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -90,7 +90,7 @@ int snd_seq_dump_var_event(const snd_seq
 
 	if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
 		char buf[32];
-		char __user *curptr = event->data.ext.ptr;
+		char __user *curptr = (char __user *)event->data.ext.ptr;
 		while (len > 0) {
 			int size = sizeof(buf);
 			if (len < size)
@@ -134,7 +134,7 @@ static int seq_copy_in_kernel(char **buf
 	return 0;
 }
 
-static int seq_copy_in_user(char **bufptr, const void *src, int size)
+static int seq_copy_in_user(char __user **bufptr, const void *src, int size)
 {
 	if (copy_to_user(*bufptr, src, size))
 		return -EFAULT;
@@ -158,7 +158,7 @@ int snd_seq_expand_var_event(const snd_s
 	if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
 		if (! in_kernel)
 			return -EINVAL;
-		if (copy_from_user(buf, event->data.ext.ptr, len))
+		if (copy_from_user(buf, (void __user *)event->data.ext.ptr, len))
 			return -EFAULT;
 		return newlen;
 	}
@@ -336,7 +336,7 @@ int snd_seq_event_dup(pool_t *pool, snd_
 				tmp->event = src->event;
 				src = src->next;
 			} else if (is_usrptr) {
-				if (copy_from_user(&tmp->event, buf, size)) {
+				if (copy_from_user(&tmp->event, (char __user *)buf, size)) {
 					err = -EFAULT;
 					goto __error;
 				}
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -289,8 +289,8 @@ snd_seq_midisynth_register_port(snd_seq_
 {
 	seq_midisynth_client_t *client;
 	seq_midisynth_t *msynth, *ms;
-	snd_seq_port_info_t port;
-	snd_rawmidi_info_t info;
+	snd_seq_port_info_t *port;
+	snd_rawmidi_info_t *info;
 	int newclient = 0;
 	unsigned int p, ports;
 	snd_seq_client_callback_t callbacks;
@@ -300,20 +300,25 @@ snd_seq_midisynth_register_port(snd_seq_
 	unsigned int input_count = 0, output_count = 0;
 
 	snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
-	info.device = device;
-	info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
-	info.subdevice = 0;
-	if (snd_rawmidi_info_select(card, &info) >= 0)
-		output_count = info.subdevices_count;
-	info.stream = SNDRV_RAWMIDI_STREAM_INPUT;
-	if (snd_rawmidi_info_select(card, &info) >= 0) {
-		input_count = info.subdevices_count;
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (! info)
+		return -ENOMEM;
+	info->device = device;
+	info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
+	info->subdevice = 0;
+	if (snd_rawmidi_info_select(card, info) >= 0)
+		output_count = info->subdevices_count;
+	info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
+	if (snd_rawmidi_info_select(card, info) >= 0) {
+		input_count = info->subdevices_count;
 	}
 	ports = output_count;
 	if (ports < input_count)
 		ports = input_count;
-	if (ports == 0)
+	if (ports == 0) {
+		kfree(info);
 		return -ENODEV;
+	}
 	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
 		ports = 256 / SNDRV_RAWMIDI_DEVICES;
 
@@ -324,6 +329,7 @@ snd_seq_midisynth_register_port(snd_seq_
 		client = kcalloc(1, sizeof(*client), GFP_KERNEL);
 		if (client == NULL) {
 			up(&register_mutex);
+			kfree(info);
 			return -ENOMEM;
 		}
 		memset(&callbacks, 0, sizeof(callbacks));
@@ -333,14 +339,16 @@ snd_seq_midisynth_register_port(snd_seq_
 		if (client->seq_client < 0) {
 			kfree(client);
 			up(&register_mutex);
+			kfree(info);
 			return -ENOMEM;
 		}
-		set_client_name(client, card, &info);
+		set_client_name(client, card, info);
 	} else if (device == 0)
-		set_client_name(client, card, &info); /* use the first device's name */
+		set_client_name(client, card, info); /* use the first device's name */
 
 	msynth = kcalloc(ports, sizeof(seq_midisynth_t), GFP_KERNEL);
-	if (msynth == NULL)
+	port = kmalloc(sizeof(*port), GFP_KERNEL);
+	if (msynth == NULL || port == NULL)
 		goto __nomem;
 
 	for (p = 0; p < ports; p++) {
@@ -350,42 +358,42 @@ snd_seq_midisynth_register_port(snd_seq_
 			goto __nomem;
 
 		/* declare port */
-		memset(&port, 0, sizeof(port));
-		port.addr.client = client->seq_client;
-		port.addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
-		port.flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
-		memset(&info, 0, sizeof(info));
-		info.device = device;
+		memset(port, 0, sizeof(*port));
+		port->addr.client = client->seq_client;
+		port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
+		port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
+		memset(info, 0, sizeof(*info));
+		info->device = device;
 		if (p < output_count)
-			info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
+			info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
 		else
-			info.stream = SNDRV_RAWMIDI_STREAM_INPUT;
-		info.subdevice = p;
-		if (snd_rawmidi_info_select(card, &info) >= 0)
-			strcpy(port.name, info.subname);
-		if (! port.name[0]) {
-			if (info.name[0]) {
+			info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
+		info->subdevice = p;
+		if (snd_rawmidi_info_select(card, info) >= 0)
+			strcpy(port->name, info->subname);
+		if (! port->name[0]) {
+			if (info->name[0]) {
 				if (ports > 1)
-					snprintf(port.name, sizeof(port.name), "%s-%d", info.name, p);
+					snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
 				else
-					snprintf(port.name, sizeof(port.name), "%s", info.name);
+					snprintf(port->name, sizeof(port->name), "%s", info->name);
 			} else {
 				/* last resort */
 				if (ports > 1)
-					sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
+					sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
 				else
-					sprintf(port.name, "MIDI %d-%d", card->number, device);
+					sprintf(port->name, "MIDI %d-%d", card->number, device);
 			}
 		}
-		if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
-			port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
-		if ((info.flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
-			port.capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
-		if ((port.capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
-		    info.flags & SNDRV_RAWMIDI_INFO_DUPLEX)
-			port.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-		port.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
-		port.midi_channels = 16;
+		if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
+			port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+		if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
+			port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
+		if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
+		    info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
+			port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+		port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+		port->midi_channels = 16;
 		memset(&pcallbacks, 0, sizeof(pcallbacks));
 		pcallbacks.owner = THIS_MODULE;
 		pcallbacks.private_data = ms;
@@ -394,11 +402,11 @@ snd_seq_midisynth_register_port(snd_seq_
 		pcallbacks.use = midisynth_use;
 		pcallbacks.unuse = midisynth_unuse;
 		pcallbacks.event_input = event_process_midi;
-		port.kernel = &pcallbacks;
-		if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &port)<0)
+		port->kernel = &pcallbacks;
+		if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
 			goto __nomem;
 		ms->seq_client = client->seq_client;
-		ms->seq_port = port.addr.port;
+		ms->seq_port = port->addr.port;
 	}
 	client->ports_per_device[device] = ports;
 	client->ports[device] = msynth;
@@ -418,6 +426,8 @@ snd_seq_midisynth_register_port(snd_seq_
 		snd_seq_delete_kernel_client(client->seq_client);
 		kfree(client);
 	}
+	kfree(info);
+	kfree(port);
 	up(&register_mutex);
 	return -ENOMEM;
 }
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -244,8 +244,8 @@ note_off(snd_midi_op_t *ops, void *drv, 
 	if (chan->gm_hold) {
 		/* Hold this note until pedal is turned off */
 		chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED;
-	} else if (chan->note[note] & SNDRV_MIDI_NOTE_SUSTENUTO) {
-		/* Mark this note as release; it will be turned off when sustenuto
+	} else if (chan->note[note] & SNDRV_MIDI_NOTE_SOSTENUTO) {
+		/* Mark this note as release; it will be turned off when sostenuto
 		 * is turned off */
 		chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED;
 	} else {
@@ -287,18 +287,18 @@ do_control(snd_midi_op_t *ops, void *drv
 		break;
 	case MIDI_CTL_PORTAMENTO:
 		break;
-	case MIDI_CTL_SUSTENUTO:
+	case MIDI_CTL_SOSTENUTO:
 		if (value) {
 			/* Mark each note that is currently held down */
 			for (i = 0; i < 128; i++) {
 				if (chan->note[i] & SNDRV_MIDI_NOTE_ON)
-					chan->note[i] |= SNDRV_MIDI_NOTE_SUSTENUTO;
+					chan->note[i] |= SNDRV_MIDI_NOTE_SOSTENUTO;
 			}
 		} else {
 			/* release all notes that were held */
 			for (i = 0; i < 128; i++) {
-				if (chan->note[i] & SNDRV_MIDI_NOTE_SUSTENUTO) {
-					chan->note[i] &= ~SNDRV_MIDI_NOTE_SUSTENUTO;
+				if (chan->note[i] & SNDRV_MIDI_NOTE_SOSTENUTO) {
+					chan->note[i] &= ~SNDRV_MIDI_NOTE_SOSTENUTO;
 					if (chan->note[i] & SNDRV_MIDI_NOTE_RELEASED) {
 						chan->note[i] = SNDRV_MIDI_NOTE_OFF;
 						if (ops->note_off)
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -525,3 +525,15 @@ EXPORT_SYMBOL(snd_midi_event_no_status);
 EXPORT_SYMBOL(snd_midi_event_encode);
 EXPORT_SYMBOL(snd_midi_event_encode_byte);
 EXPORT_SYMBOL(snd_midi_event_decode);
+
+static int __init alsa_seq_midi_event_init(void)
+{
+	return 0;
+}
+
+static void __exit alsa_seq_midi_event_exit(void)
+{
+}
+
+module_init(alsa_seq_midi_event_init)
+module_exit(alsa_seq_midi_event_exit)
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -49,7 +49,7 @@
 
 /* list of allocated queues */
 static queue_t *queue_list[SNDRV_SEQ_MAX_QUEUES];
-static spinlock_t queue_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(queue_list_lock);
 /* number of queues allocated */
 static int num_queues;
 
@@ -650,7 +650,7 @@ void snd_seq_queue_remove_cells(int clie
 /*
  * send events to all subscribed ports
  */
-static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int from_timer_port, int atomic, int hop)
+static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
 {
 	snd_seq_event_t sev;
 
@@ -661,60 +661,58 @@ static void queue_broadcast_event(queue_
 	sev.queue = q->queue;
 	sev.data.queue.queue = q->queue;
 
-	if (from_timer_port) {
-		/* broadcast events from Timer port */
-		sev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
-		sev.source.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
-		sev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
-		snd_seq_kernel_client_dispatch(SNDRV_SEQ_CLIENT_SYSTEM, &sev, atomic, hop);
-	}
+	/* broadcast events from Timer port */
+	sev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
+	sev.source.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
+	sev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
+	snd_seq_kernel_client_dispatch(SNDRV_SEQ_CLIENT_SYSTEM, &sev, atomic, hop);
 }
 
 /*
  * process a received queue-control event.
  * this function is exported for seq_sync.c.
  */
-void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int from_timer_port, int atomic, int hop)
+void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
 {
 	switch (ev->type) {
 	case SNDRV_SEQ_EVENT_START:
 		snd_seq_prioq_leave(q->tickq, ev->source.client, 1);
 		snd_seq_prioq_leave(q->timeq, ev->source.client, 1);
 		if (! snd_seq_timer_start(q->timer))
-			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+			queue_broadcast_event(q, ev, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_CONTINUE:
 		if (! snd_seq_timer_continue(q->timer))
-			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+			queue_broadcast_event(q, ev, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_STOP:
 		snd_seq_timer_stop(q->timer);
-		queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+		queue_broadcast_event(q, ev, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_TEMPO:
 		snd_seq_timer_set_tempo(q->timer, ev->data.queue.param.value);
-		queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+		queue_broadcast_event(q, ev, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_SETPOS_TICK:
 		if (snd_seq_timer_set_position_tick(q->timer, ev->data.queue.param.time.tick) == 0) {
-			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+			queue_broadcast_event(q, ev, atomic, hop);
 		}
 		break;
 
 	case SNDRV_SEQ_EVENT_SETPOS_TIME:
 		if (snd_seq_timer_set_position_time(q->timer, ev->data.queue.param.time.time) == 0) {
-			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+			queue_broadcast_event(q, ev, atomic, hop);
 		}
 		break;
 	case SNDRV_SEQ_EVENT_QUEUE_SKEW:
 		if (snd_seq_timer_set_skew(q->timer,
 					   ev->data.queue.param.skew.value,
 					   ev->data.queue.param.skew.base) == 0) {
-			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+			queue_broadcast_event(q, ev, atomic, hop);
 		}
 		break;
 	}
@@ -740,7 +738,7 @@ int snd_seq_control_queue(snd_seq_event_
 		return -EPERM;
 	}
 
-	snd_seq_queue_process_event(q, ev, 1, atomic, hop);
+	snd_seq_queue_process_event(q, ev, atomic, hop);
 
 	queue_access_unlock(q);
 	queuefree(q);
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -111,7 +111,7 @@ int snd_seq_queue_use(int queueid, int c
 int snd_seq_queue_is_used(int queueid, int client);
 
 int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop);
-void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int from_timer_port, int atomic, int hop);
+void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop);
 
 /*
  * 64bit division - for sync stuff..
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
--- a/sound/core/seq/seq_system.c
+++ b/sound/core/seq/seq_system.c
@@ -123,13 +123,19 @@ int __init snd_seq_system_client_init(vo
 
 	snd_seq_client_callback_t callbacks;
 	snd_seq_port_callback_t pcallbacks;
-	snd_seq_client_info_t inf;
-	snd_seq_port_info_t port;
+	snd_seq_client_info_t *inf;
+	snd_seq_port_info_t *port;
+
+	inf = kcalloc(1, sizeof(*inf), GFP_KERNEL);
+	port = kcalloc(1, sizeof(*port), GFP_KERNEL);
+	if (! inf || ! port) {
+		kfree(inf);
+		kfree(port);
+		return -ENOMEM;
+	}
 
 	memset(&callbacks, 0, sizeof(callbacks));
 	memset(&pcallbacks, 0, sizeof(pcallbacks));
-	memset(&inf, 0, sizeof(inf));
-	memset(&port, 0, sizeof(port));
 	pcallbacks.owner = THIS_MODULE;
 	pcallbacks.event_input = event_input_timer;
 
@@ -138,33 +144,35 @@ int __init snd_seq_system_client_init(vo
 	sysclient = snd_seq_create_kernel_client(NULL, 0, &callbacks);
 
 	/* set our name */
-	inf.client = 0;
-	inf.type = KERNEL_CLIENT;
-	strcpy(inf.name, "System");
-	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &inf);
+	inf->client = 0;
+	inf->type = KERNEL_CLIENT;
+	strcpy(inf->name, "System");
+	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, inf);
 
 	/* register timer */
-	strcpy(port.name, "Timer");
-	port.capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
-	port.capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
-	port.kernel = &pcallbacks;
-	port.type = 0;
-	port.flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
-	port.addr.client = sysclient;
-	port.addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
-	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
+	strcpy(port->name, "Timer");
+	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
+	port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
+	port->kernel = &pcallbacks;
+	port->type = 0;
+	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
+	port->addr.client = sysclient;
+	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
+	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
 
 	/* register announcement port */
-	strcpy(port.name, "Announce");
-	port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
-	port.kernel = NULL;
-	port.type = 0;
-	port.flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
-	port.addr.client = sysclient;
-	port.addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
-	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
-	announce_port = port.addr.port;
+	strcpy(port->name, "Announce");
+	port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
+	port->kernel = NULL;
+	port->type = 0;
+	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
+	port->addr.client = sysclient;
+	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
+	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+	announce_port = port->addr.port;
 
+	kfree(inf);
+	kfree(port);
 	return 0;
 }
 
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -354,39 +354,48 @@ static int snd_virmidi_dev_attach_seq(sn
 	int client;
 	snd_seq_client_callback_t callbacks;
 	snd_seq_port_callback_t pcallbacks;
-	snd_seq_client_info_t info;
-	snd_seq_port_info_t pinfo;
+	snd_seq_client_info_t *info;
+	snd_seq_port_info_t *pinfo;
 	int err;
 
 	if (rdev->client >= 0)
 		return 0;
 
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
+	if (! info || ! pinfo) {
+		err = -ENOMEM;
+		goto __error;
+	}
+
 	memset(&callbacks, 0, sizeof(callbacks));
 	callbacks.private_data = rdev;
 	callbacks.allow_input = 1;
 	callbacks.allow_output = 1;
 	client = snd_seq_create_kernel_client(rdev->card, rdev->device, &callbacks);
-	if (client < 0)
-		return client;
+	if (client < 0) {
+		err = client;
+		goto __error;
+	}
 	rdev->client = client;
 
 	/* set client name */
-	memset(&info, 0, sizeof(info));
-	info.client = client;
-	info.type = KERNEL_CLIENT;
-	sprintf(info.name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device);
+	memset(info, 0, sizeof(*info));
+	info->client = client;
+	info->type = KERNEL_CLIENT;
+	sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device);
 	snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info);
 
 	/* create a port */
-	memset(&pinfo, 0, sizeof(pinfo));
-	pinfo.addr.client = client;
-	sprintf(pinfo.name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
+	memset(pinfo, 0, sizeof(*pinfo));
+	pinfo->addr.client = client;
+	sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
 	/* set all capabilities */
-	pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
-	pinfo.capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
-	pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-	pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
-	pinfo.midi_channels = 16;
+	pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+	pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
+	pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+	pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+	pinfo->midi_channels = 16;
 	memset(&pcallbacks, 0, sizeof(pcallbacks));
 	pcallbacks.owner = THIS_MODULE;
 	pcallbacks.private_data = rdev;
@@ -395,16 +404,21 @@ static int snd_virmidi_dev_attach_seq(sn
 	pcallbacks.use = snd_virmidi_use;
 	pcallbacks.unuse = snd_virmidi_unuse;
 	pcallbacks.event_input = snd_virmidi_event_input;
-	pinfo.kernel = &pcallbacks;
+	pinfo->kernel = &pcallbacks;
 	err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo);
 	if (err < 0) {
 		snd_seq_delete_kernel_client(client);
 		rdev->client = -1;
-		return err;
+		goto __error;
 	}
 
-	rdev->port = pinfo.addr.port;
-	return 0;	/* success */
+	rdev->port = pinfo->addr.port;
+	err = 0; /* success */
+
+ __error:
+	kfree(info);
+	kfree(pinfo);
+	return err;
 }
 
 
diff --git a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -48,7 +48,6 @@ module_param(major, int, 0444);
 MODULE_PARM_DESC(major, "Major # for sound driver.");
 module_param(cards_limit, int, 0444);
 MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
-MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
 #ifdef CONFIG_DEVFS_FS
 module_param(device_mode, int, 0444);
 MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs.");
@@ -420,7 +419,9 @@ EXPORT_SYMBOL(snd_card_file_remove);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL(snd_power_wait);
 EXPORT_SYMBOL(snd_card_set_pm_callback);
-EXPORT_SYMBOL(snd_card_set_dev_pm_callback);
+#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
+EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
+#endif
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(snd_card_pci_suspend);
 EXPORT_SYMBOL(snd_card_pci_resume);
@@ -467,6 +468,10 @@ EXPORT_SYMBOL(snd_ctl_find_id);
 EXPORT_SYMBOL(snd_ctl_notify);
 EXPORT_SYMBOL(snd_ctl_register_ioctl);
 EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+#ifdef CONFIG_COMPAT
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
+#endif
 EXPORT_SYMBOL(snd_ctl_elem_read);
 EXPORT_SYMBOL(snd_ctl_elem_write);
   /* misc.c */
diff --git a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -37,10 +37,12 @@
 #include <linux/kerneld.h>
 #endif
 
-#if !defined(CONFIG_SND_RTCTIMER) && !defined(CONFIG_SND_RTCTIMER_MODULE)
-#define DEFAULT_TIMER_LIMIT 1
-#else
+#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
+#define DEFAULT_TIMER_LIMIT 3
+#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
 #define DEFAULT_TIMER_LIMIT 2
+#else
+#define DEFAULT_TIMER_LIMIT 1
 #endif
 
 static int timer_limit = DEFAULT_TIMER_LIMIT;
@@ -76,7 +78,7 @@ static LIST_HEAD(snd_timer_list);
 static LIST_HEAD(snd_timer_slave_list);
 
 /* lock for slave active lists */
-static spinlock_t slave_active_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(slave_active_lock);
 
 static DECLARE_MUTEX(register_mutex);
 
@@ -1117,7 +1119,8 @@ static void snd_timer_user_append_to_tqu
 	if (tu->qused >= tu->queue_size) {
 		tu->overrun++;
 	} else {
-		memcpy(&tu->queue[tu->qtail++], tread, sizeof(*tread));
+		memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread));
+		tu->qtail %= tu->queue_size;
 		tu->qused++;
 	}
 }
@@ -1140,6 +1143,8 @@ static void snd_timer_user_ccallback(snd
 	spin_lock(&tu->qlock);
 	snd_timer_user_append_to_tqueue(tu, &r1);
 	spin_unlock(&tu->qlock);
+	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+	wake_up(&tu->qchange_sleep);
 }
 
 static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
@@ -1342,39 +1347,45 @@ static int snd_timer_user_next_device(sn
 
 static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo)
 {
-	snd_timer_ginfo_t ginfo;
+	snd_timer_ginfo_t *ginfo;
 	snd_timer_id_t tid;
 	snd_timer_t *t;
 	struct list_head *p;
 	int err = 0;
 
-	if (copy_from_user(&ginfo, _ginfo, sizeof(ginfo)))
+	ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL);
+	if (! ginfo)
+		return -ENOMEM;
+	if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) {
+		kfree(ginfo);
 		return -EFAULT;
-	tid = ginfo.tid;
-	memset(&ginfo, 0, sizeof(ginfo));
-	ginfo.tid = tid;
+	}
+	tid = ginfo->tid;
+	memset(ginfo, 0, sizeof(*ginfo));
+	ginfo->tid = tid;
 	down(&register_mutex);
 	t = snd_timer_find(&tid);
 	if (t != NULL) {
-		ginfo.card = t->card ? t->card->number : -1;
+		ginfo->card = t->card ? t->card->number : -1;
 		if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
-			ginfo.flags |= SNDRV_TIMER_FLG_SLAVE;
-		strlcpy(ginfo.id, t->id, sizeof(ginfo.id));
-		strlcpy(ginfo.name, t->name, sizeof(ginfo.name));
-		ginfo.resolution = t->hw.resolution;
+			ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
+		strlcpy(ginfo->id, t->id, sizeof(ginfo->id));
+		strlcpy(ginfo->name, t->name, sizeof(ginfo->name));
+		ginfo->resolution = t->hw.resolution;
 		if (t->hw.resolution_min > 0) {
-			ginfo.resolution_min = t->hw.resolution_min;
-			ginfo.resolution_max = t->hw.resolution_max;
+			ginfo->resolution_min = t->hw.resolution_min;
+			ginfo->resolution_max = t->hw.resolution_max;
 		}
 		list_for_each(p, &t->open_list_head) {
-			ginfo.clients++;
+			ginfo->clients++;
 		}
 	} else {
 		err = -ENODEV;
 	}
 	up(&register_mutex);
-	if (err >= 0 && copy_to_user(_ginfo, &ginfo, sizeof(ginfo)))
+	if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
 		err = -EFAULT;
+	kfree(ginfo);
 	return err;
 }
 
@@ -1488,23 +1499,28 @@ static int snd_timer_user_tselect(struct
 static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
 {
 	snd_timer_user_t *tu;
-	snd_timer_info_t info;
+	snd_timer_info_t *info;
 	snd_timer_t *t;
+	int err = 0;
 
 	tu = file->private_data;
 	snd_assert(tu->timeri != NULL, return -ENXIO);
 	t = tu->timeri->timer;
 	snd_assert(t != NULL, return -ENXIO);
-	memset(&info, 0, sizeof(info));
-	info.card = t->card ? t->card->number : -1;
+
+	info = kcalloc(1, sizeof(*info), GFP_KERNEL);
+	if (! info)
+		return -ENOMEM;
+	info->card = t->card ? t->card->number : -1;
 	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
-		info.flags |= SNDRV_TIMER_FLG_SLAVE;
-	strlcpy(info.id, t->id, sizeof(info.id));
-	strlcpy(info.name, t->name, sizeof(info.name));
-	info.resolution = t->hw.resolution;
-	if (copy_to_user(_info, &info, sizeof(*_info)))
-		return -EFAULT;
-	return 0;
+		info->flags |= SNDRV_TIMER_FLG_SLAVE;
+	strlcpy(info->id, t->id, sizeof(info->id));
+	strlcpy(info->name, t->name, sizeof(info->name));
+	info->resolution = t->hw.resolution;
+	if (copy_to_user(_info, info, sizeof(*_info)))
+		err = -EFAULT;
+	kfree(info);
+	return err;
 }
 
 static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params)
@@ -1653,8 +1669,7 @@ static int snd_timer_user_continue(struc
 	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
 
-static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
-					unsigned int cmd, unsigned long arg)
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_timer_user_t *tu;
 	void __user *argp = (void __user *)arg;
@@ -1701,17 +1716,6 @@ static inline int _snd_timer_user_ioctl(
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
-				unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_timer_user_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 {
 	snd_timer_user_t *tu;
@@ -1803,6 +1807,12 @@ static unsigned int snd_timer_user_poll(
 	return mask;
 }
 
+#ifdef CONFIG_COMPAT
+#include "timer_compat.c"
+#else
+#define snd_timer_user_ioctl_compat	NULL
+#endif
+
 static struct file_operations snd_timer_f_ops =
 {
 	.owner =	THIS_MODULE,
@@ -1810,7 +1820,8 @@ static struct file_operations snd_timer_
 	.open =		snd_timer_user_open,
 	.release =	snd_timer_user_release,
 	.poll =		snd_timer_user_poll,
-	.ioctl =	snd_timer_user_ioctl,
+	.unlocked_ioctl =	snd_timer_user_ioctl,
+	.compat_ioctl =	snd_timer_user_ioctl_compat,
 	.fasync = 	snd_timer_user_fasync,
 };
 
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
new file mode 100644
--- /dev/null
+++ b/sound/core/timer_compat.c
@@ -0,0 +1,119 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for timer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* This file included from timer.c */
+
+#include <linux/compat.h>
+
+struct sndrv_timer_info32 {
+	u32 flags;
+	s32 card;
+	unsigned char id[64];
+	unsigned char name[80];
+	u32 reserved0;
+	u32 resolution;
+	unsigned char reserved[64];
+};
+
+static int snd_timer_user_info_compat(struct file *file,
+				      struct sndrv_timer_info32 __user *_info)
+{
+	snd_timer_user_t *tu;
+	struct sndrv_timer_info32 info;
+	snd_timer_t *t;
+
+	tu = file->private_data;
+	snd_assert(tu->timeri != NULL, return -ENXIO);
+	t = tu->timeri->timer;
+	snd_assert(t != NULL, return -ENXIO);
+	memset(&info, 0, sizeof(info));
+	info.card = t->card ? t->card->number : -1;
+	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+		info.flags |= SNDRV_TIMER_FLG_SLAVE;
+	strlcpy(info.id, t->id, sizeof(info.id));
+	strlcpy(info.name, t->name, sizeof(info.name));
+	info.resolution = t->hw.resolution;
+	if (copy_to_user(_info, &info, sizeof(*_info)))
+		return -EFAULT;
+	return 0;
+}
+
+struct sndrv_timer_status32 {
+	struct compat_timespec tstamp;
+	u32 resolution;
+	u32 lost;
+	u32 overrun;
+	u32 queue;
+	unsigned char reserved[64];
+};
+
+static int snd_timer_user_status_compat(struct file *file,
+					struct sndrv_timer_status32 __user *_status)
+{
+	snd_timer_user_t *tu;
+	snd_timer_status_t status;
+	
+	tu = file->private_data;
+	snd_assert(tu->timeri != NULL, return -ENXIO);
+	memset(&status, 0, sizeof(status));
+	status.tstamp = tu->tstamp;
+	status.resolution = snd_timer_resolution(tu->timeri);
+	status.lost = tu->timeri->lost;
+	status.overrun = tu->overrun;
+	spin_lock_irq(&tu->qlock);
+	status.queue = tu->qused;
+	spin_unlock_irq(&tu->qlock);
+	if (copy_to_user(_status, &status, sizeof(status)))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ */
+
+enum {
+	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
+	SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
+};
+
+static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = compat_ptr(arg);
+
+	switch (cmd) {
+	case SNDRV_TIMER_IOCTL_PVERSION:
+	case SNDRV_TIMER_IOCTL_TREAD:
+	case SNDRV_TIMER_IOCTL_GINFO:
+	case SNDRV_TIMER_IOCTL_GPARAMS:
+	case SNDRV_TIMER_IOCTL_GSTATUS:
+	case SNDRV_TIMER_IOCTL_SELECT:
+	case SNDRV_TIMER_IOCTL_PARAMS:
+	case SNDRV_TIMER_IOCTL_START:
+	case SNDRV_TIMER_IOCTL_STOP:
+	case SNDRV_TIMER_IOCTL_CONTINUE:
+	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
+		return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_TIMER_IOCTL_INFO32:
+		return snd_timer_user_info_compat(file, argp);
+	case SNDRV_TIMER_IOCTL_STATUS32:
+		return snd_timer_user_status_compat(file, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -1,12 +1,7 @@
 /*
  *  Driver for generic MPU-401 boards (UART mode only)
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- *  ACPI PnP Copyright (c) 2004 by Clemens Ladisch <clemens@ladisch.de>
- *  based on 8250_acpi.c
- *  Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
- *  Copyright (C) 2004 Hewlett-Packard Co
- *       Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *  Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr>
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -27,27 +22,21 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#ifdef CONFIG_ACPI_BUS
-#include <linux/acpi.h>
-#endif
+#include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
-#ifdef CONFIG_ACPI_BUS
-#define USE_ACPI_PNP
-#endif
-
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("MPU-401 UART");
 MODULE_LICENSE("GPL");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
-#ifdef USE_ACPI_PNP
-static int acpipnp[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
+#ifdef CONFIG_PNP
+static int pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* MPU-401 port number */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* MPU-401 IRQ */
@@ -58,115 +47,36 @@ module_param_array(id, charp, NULL, 0444
 MODULE_PARM_DESC(id, "ID string for MPU-401 device.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
-#ifdef USE_ACPI_PNP
-module_param_array(acpipnp, bool, NULL, 0444);
-MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device.");
+#ifdef CONFIG_PNP
+module_param_array(pnp, bool, NULL, 0444);
+MODULE_PARM_DESC(pnp, "PnP detection for MPU-401 device.");
 #endif
 module_param_array(port, long, NULL, 0444);
 MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
 module_param_array(irq, int, NULL, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
 
-#ifndef CONFIG_ACPI_BUS
-struct acpi_device;
-#endif
-
 static snd_card_t *snd_mpu401_legacy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-static int cards;
-
-#ifdef USE_ACPI_PNP
-
-static int acpi_driver_registered;
-
-struct mpu401_resources {
-	unsigned long port;
-	int irq;
-};
+static int pnp_registered = 0;
 
-static acpi_status __devinit snd_mpu401_acpi_resource(struct acpi_resource *res,
-						      void *data)
-{
-	struct mpu401_resources *resources = (struct mpu401_resources *)data;
-
-	if (res->id == ACPI_RSTYPE_IRQ) {
-		if (res->data.irq.number_of_interrupts > 0) {
-			resources->irq = acpi_register_gsi(res->data.irq.interrupts[0],
-							   res->data.irq.edge_level,
-							   res->data.irq.active_high_low);
-		}
-	} else if (res->id == ACPI_RSTYPE_IO) {
-		if (res->data.io.range_length >= 2) {
-			resources->port = res->data.io.min_base_address;
-		}
-	}
-	return AE_OK;
-}
-
-static int __devinit snd_mpu401_acpi_pnp(int dev, struct acpi_device *device)
-{
-	struct mpu401_resources res;
-	acpi_status status;
-
-	res.port = SNDRV_AUTO_PORT;
-	res.irq = SNDRV_AUTO_IRQ;
-	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-				     snd_mpu401_acpi_resource, &res);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-	if (res.port == SNDRV_AUTO_PORT || res.irq == SNDRV_AUTO_IRQ) {
-		snd_printk(KERN_ERR "no port or irq in %s _CRS\n",
-			   acpi_device_bid(device));
-		return -ENODEV;
-	}
-	port[dev] = res.port;
-	irq[dev] = res.irq;
-	return 0;
-}
-
-#endif /* USE_ACPI_PNP */
-
-static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
+static int snd_mpu401_create(int dev, snd_card_t **rcard)
 {
 	snd_card_t *card;
 	int err;
 
-#ifdef USE_ACPI_PNP
-	if (!device) {
-#endif
-		if (port[dev] == SNDRV_AUTO_PORT) {
-			snd_printk(KERN_ERR "specify port\n");
-			return -EINVAL;
-		}
-		if (irq[dev] == SNDRV_AUTO_IRQ) {
-			snd_printk(KERN_ERR "specify or disable IRQ port\n");
-			return -EINVAL;
-		}
-#ifdef USE_ACPI_PNP
-	}
-#endif
-
-#ifdef USE_ACPI_PNP
-	if (device && (err = snd_mpu401_acpi_pnp(dev, device)) < 0)
-		return err;
-#endif
-
+	*rcard = NULL;
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
 	if (card == NULL)
 		return -ENOMEM;
 	strcpy(card->driver, "MPU-401 UART");
 	strcpy(card->shortname, card->driver);
-	sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
+	sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
 	if (irq[dev] >= 0) {
-		sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
+		sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]);
 	} else {
 		strcat(card->longname, "polled");
 	}
-#ifdef USE_ACPI_PNP
-	if (device) {
-		strcat(card->longname, ", ACPI id ");
-		strlcat(card->longname, acpi_device_bid(device), sizeof(card->longname));
-	}
-#endif
+
 	if (snd_mpu401_uart_new(card, 0,
 				MPU401_HW_MPU401,
 				port[dev], 0,
@@ -179,89 +89,127 @@ static int __devinit snd_card_mpu401_pro
 		snd_card_free(card);
 		return err;
 	}
-#ifdef USE_ACPI_PNP
-	if (device)
-		acpi_driver_data(device) = card;
-	else
-#endif
-		snd_mpu401_legacy_cards[dev] = card;
-	++cards;
+	*rcard = card;
 	return 0;
 }
 
-#ifdef USE_ACPI_PNP
+static int __devinit snd_mpu401_probe(int dev)
+{
+	if (port[dev] == SNDRV_AUTO_PORT) {
+		snd_printk(KERN_ERR "specify port\n");
+		return -EINVAL;
+	}
+	if (irq[dev] == SNDRV_AUTO_IRQ) {
+		snd_printk(KERN_ERR "specify or disable IRQ\n");
+		return -EINVAL;
+	}
+	return snd_mpu401_create(dev, &snd_mpu401_legacy_cards[dev]);
+}
+
+#ifdef CONFIG_PNP
+
+#define IO_EXTENT 2
+
+static struct pnp_device_id snd_mpu401_pnpids[] = {
+	{ .id = "PNPb006" },
+	{ .id = "" }
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids);
+
+static int __init snd_mpu401_pnp(int dev, struct pnp_dev *device,
+				 const struct pnp_device_id *id)
+{
+	if (!pnp_port_valid(device, 0) ||
+	    pnp_port_flags(device, 0) & IORESOURCE_DISABLED) {
+		snd_printk(KERN_ERR "no PnP port\n");
+		return -ENODEV;
+	}
+	if (pnp_port_len(device, 0) < IO_EXTENT) {
+		snd_printk(KERN_ERR "PnP port length is %ld, expected %d\n",
+			   pnp_port_len(device, 0), IO_EXTENT);
+		return -ENODEV;
+	}
+	port[dev] = pnp_port_start(device, 0);
+
+	if (!pnp_irq_valid(device, 0) ||
+	    pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) {
+		snd_printk(KERN_WARNING "no PnP irq, using polling\n");
+		irq[dev] = -1;
+	} else {
+		irq[dev] = pnp_irq(device, 0);
+	}
+	return 0;
+}
 
-static int __devinit snd_mpu401_acpi_add(struct acpi_device *device)
+static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
+					  const struct pnp_device_id *id)
 {
 	static int dev;
+	snd_card_t *card;
 	int err;
 
 	for ( ; dev < SNDRV_CARDS; ++dev) {
-		if (!enable[dev] || !acpipnp[dev])
+		if (!enable[dev] || !pnp[dev])
 			continue;
-		err = snd_card_mpu401_probe(dev, device);
+		err = snd_mpu401_pnp(dev, pnp_dev, id);
+		if (err < 0)
+			return err;
+		err = snd_mpu401_create(dev, &card);
 		if (err < 0)
 			return err;
+		snd_card_set_dev(card, &pnp_dev->dev);
+		pnp_set_drvdata(pnp_dev, card);
 		++dev;
 		return 0;
 	}
 	return -ENODEV;
 }
 
-static int __devexit snd_mpu401_acpi_remove(struct acpi_device *device,
-					    int type)
+static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev)
 {
-	snd_card_t *card;
-
-	if (!device)
-		return -EINVAL;
-	card = (snd_card_t *)acpi_driver_data(device);
-	if (!card)
-		return -EINVAL;
+	snd_card_t *card = (snd_card_t *) pnp_get_drvdata(dev);
 
 	snd_card_disconnect(card);
 	snd_card_free_in_thread(card);
-	acpi_driver_data(device) = NULL;
-	return 0;
 }
 
-static struct acpi_driver snd_mpu401_acpi_driver = {
-	.name = "MPU-401 Driver",
-	.class = "mpu401",
-	.ids = "PNPB006",
-	.ops = {
-		.add = snd_mpu401_acpi_add,
-		.remove = __devexit_p(snd_mpu401_acpi_remove),
-	},
+static struct pnp_driver snd_mpu401_pnp_driver = {
+	.name = "mpu401",
+	.id_table = snd_mpu401_pnpids,
+	.probe = snd_mpu401_pnp_probe,
+	.remove = __devexit_p(snd_mpu401_pnp_remove),
 };
-
-#endif /* USE_ACPI_PNP */
+#else
+static struct pnp_driver snd_mpu401_pnp_driver;
+#endif
 
 static int __init alsa_card_mpu401_init(void)
 {
-	int dev;
+	int dev, devices = 0;
+	int err;
 
-#ifdef USE_ACPI_PNP
-	if (acpi_bus_register_driver(&snd_mpu401_acpi_driver) >= 0)
-		acpi_driver_registered = 1;
-#endif
 	for (dev = 0; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev])
 			continue;
-#ifdef USE_ACPI_PNP
-		if (acpipnp[dev] && acpi_driver_registered)
+#ifdef CONFIG_PNP
+		if (pnp[dev])
 			continue;
 #endif
-		snd_card_mpu401_probe(dev, NULL);
+		if (snd_mpu401_probe(dev) >= 0)
+			devices++;
 	}
-	if (!cards) {
+	if ((err = pnp_register_driver(&snd_mpu401_pnp_driver)) >= 0) {
+		pnp_registered = 1;
+		devices += err;
+	}
+
+	if (!devices) {
 #ifdef MODULE
 		printk(KERN_ERR "MPU-401 device not found or device busy\n");
 #endif
-#ifdef USE_ACPI_PNP
-		if (acpi_driver_registered)
-			acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
-#endif
+		if (pnp_registered)
+			pnp_unregister_driver(&snd_mpu401_pnp_driver);
 		return -ENODEV;
 	}
 	return 0;
@@ -271,10 +219,8 @@ static void __exit alsa_card_mpu401_exit
 {
 	int idx;
 
-#ifdef USE_ACPI_PNP
-	if (acpi_driver_registered)
-		acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
-#endif
+	if (pnp_registered)
+		pnp_unregister_driver(&snd_mpu401_pnp_driver);
 	for (idx = 0; idx < SNDRV_CARDS; idx++)
 		snd_card_free(snd_mpu401_legacy_cards[idx]);
 }
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -94,9 +94,7 @@ static void _snd_mpu401_uart_interrupt(m
 {
 	spin_lock(&mpu->input_lock);
 	if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
-		atomic_dec(&mpu->rx_loop);
 		snd_mpu401_uart_input_read(mpu);
-		atomic_inc(&mpu->rx_loop);
 	} else {
 		snd_mpu401_uart_clear_rx(mpu);
 	}
@@ -104,12 +102,9 @@ static void _snd_mpu401_uart_interrupt(m
  	/* ok. for better Tx performance try do some output when input is done */
 	if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
 	    test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
-		if (spin_trylock(&mpu->output_lock)) {
-			atomic_dec(&mpu->tx_loop);
-			snd_mpu401_uart_output_write(mpu);
-			atomic_inc(&mpu->tx_loop);
-			spin_unlock(&mpu->output_lock);
-		}
+		spin_lock(&mpu->output_lock);
+		snd_mpu401_uart_output_write(mpu);
+		spin_unlock(&mpu->output_lock);
 	}
 }
 
@@ -243,7 +238,6 @@ static int snd_mpu401_uart_input_open(sn
 		snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1);
 	}
 	mpu->substream_input = substream;
-	atomic_set(&mpu->rx_loop, 1);
 	set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
 	return 0;
 }
@@ -261,7 +255,6 @@ static int snd_mpu401_uart_output_open(s
 		snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1);
 	}
 	mpu->substream_output = substream;
-	atomic_set(&mpu->tx_loop, 1);
 	set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
 	return 0;
 }
@@ -314,16 +307,9 @@ static void snd_mpu401_uart_input_trigge
 		}
 		
 		/* read data in advance */
-		/* prevent double enter via rawmidi->event callback */
-		if (atomic_dec_and_test(&mpu->rx_loop)) {
-			local_irq_save(flags);
-			if (spin_trylock(&mpu->input_lock)) {
-				snd_mpu401_uart_input_read(mpu);
-				spin_unlock(&mpu->input_lock);
-			}
-			local_irq_restore(flags);
-		}
-		atomic_inc(&mpu->rx_loop);
+		spin_lock_irqsave(&mpu->input_lock, flags);
+		snd_mpu401_uart_input_read(mpu);
+		spin_unlock_irqrestore(&mpu->input_lock, flags);
 	} else {
 		if (mpu->irq < 0)
 			snd_mpu401_uart_remove_timer(mpu, 1);
@@ -405,16 +391,9 @@ static void snd_mpu401_uart_output_trigg
 		snd_mpu401_uart_add_timer(mpu, 0);
 
 		/* output pending data */
-		/* prevent double enter via rawmidi->event callback */
-		if (atomic_dec_and_test(&mpu->tx_loop)) {
-			local_irq_save(flags);
-			if (spin_trylock(&mpu->output_lock)) {
-				snd_mpu401_uart_output_write(mpu);
-				spin_unlock(&mpu->output_lock);
-			}
-			local_irq_restore(flags);
-		}
-		atomic_inc(&mpu->tx_loop);
+		spin_lock_irqsave(&mpu->output_lock, flags);
+		snd_mpu401_uart_output_write(mpu);
+		spin_unlock_irqrestore(&mpu->output_lock, flags);
 	} else {
 		snd_mpu401_uart_remove_timer(mpu, 0);
 		clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -413,10 +413,11 @@ static void snd_mtpav_input_trigger(snd_
 
 static void snd_mtpav_output_timer(unsigned long data)
 {
+	unsigned long flags;
 	mtpav_t *chip = (mtpav_t *)data;
 	int p;
 
-	spin_lock(&chip->spinlock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	/* reprogram timer */
 	chip->timer.expires = 1 + jiffies;
 	add_timer(&chip->timer);
@@ -426,7 +427,7 @@ static void snd_mtpav_output_timer(unsig
 		if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output)
 			snd_mtpav_output_port_write(portp, portp->output);
 	}
-	spin_unlock(&chip->spinlock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 /* spinlock held! */
@@ -514,9 +515,7 @@ static void snd_mtpav_inmidi_process(mtp
 
 	portp = &mcrd->ports[mcrd->inmidiport];
 	if (portp->mode & MTPAV_MODE_INPUT_TRIGGERED) {
-		spin_unlock(&mcrd->spinlock);
 		snd_rawmidi_receive(portp->input, &inbyte, 1);
-		spin_lock(&mcrd->spinlock);
 	}
 }
 
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -232,7 +232,7 @@ static void snd_uart16550_io_loop(snd_ua
 			}
 			else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
 				snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
-		}
+			}
 		} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
 			snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
 		}
@@ -309,13 +309,14 @@ static irqreturn_t snd_uart16550_interru
 /* When the polling mode, this function calls snd_uart16550_io_loop. */
 static void snd_uart16550_buffer_timer(unsigned long data)
 {
+	unsigned long flags;
 	snd_uart16550_t *uart;
 
 	uart = (snd_uart16550_t *)data;
-	spin_lock(&uart->open_lock);
+	spin_lock_irqsave(&uart->open_lock, flags);
 	snd_uart16550_del_timer(uart);
 	snd_uart16550_io_loop(uart);
-	spin_unlock(&uart->open_lock);
+	spin_unlock_irqrestore(&uart->open_lock, flags);
 }
 
 /*
@@ -840,6 +841,16 @@ static int __init snd_uart16550_create(s
 	return 0;
 }
 
+static void __init snd_uart16550_substreams(snd_rawmidi_str_t *stream)
+{
+	struct list_head *list;
+
+	list_for_each(list, &stream->substreams) {
+		snd_rawmidi_substream_t *substream = list_entry(list, snd_rawmidi_substream_t, list);
+		sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
+	}
+}
+
 static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, snd_rawmidi_t **rmidi)
 {
 	snd_rawmidi_t *rrawmidi;
@@ -849,7 +860,9 @@ static int __init snd_uart16550_rmidi(sn
 		return err;
 	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
 	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
-	sprintf(rrawmidi->name, "uart16550 MIDI #%d", device);
+	strcpy(rrawmidi->name, "Serial MIDI");
+	snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
+	snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
 	rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
 			       SNDRV_RAWMIDI_INFO_INPUT |
 			       SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -906,7 +919,7 @@ static int __init snd_serial_probe(int d
 		return -ENOMEM;
 
 	strcpy(card->driver, "Serial");
-	strcpy(card->shortname, "Serial midi (uart16550A)");
+	strcpy(card->shortname, "Serial MIDI (UART16550A)");
 
 	if ((err = snd_uart16550_create(card,
 					port[dev],
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -45,12 +46,10 @@ MODULE_LICENSE("GPL");
  */
 void snd_vx_delay(vx_core_t *chip, int xmsec)
 {
-	if (! in_interrupt() && xmsec >= 1000 / HZ) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((xmsec * HZ + 999) / 1000);
-	} else {
+	if (! in_interrupt() && xmsec >= 1000 / HZ)
+		msleep(xmsec);
+	else
 		mdelay(xmsec);
-	}
 }
 
 /*
@@ -610,6 +609,10 @@ static void vx_proc_read(snd_info_entry_
 	static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
 	
 	snd_iprintf(buffer, "%s\n", chip->card->longname);
+	snd_iprintf(buffer, "Xilinx Firmware: %s\n",
+		    chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No");
+	snd_iprintf(buffer, "Device Initialized: %s\n",
+		    chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No");
 	snd_iprintf(buffer, "DSP audio info:");
 	if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME)
 		snd_iprintf(buffer, " realtime");
@@ -718,7 +721,7 @@ int snd_vx_dsp_load(vx_core_t *chip, con
 /*
  * suspend
  */
-static int snd_vx_suspend(snd_card_t *card, unsigned int state)
+static int snd_vx_suspend(snd_card_t *card, pm_message_t state)
 {
 	vx_core_t *chip = card->pm_private_data;
 	unsigned int i;
@@ -735,7 +738,7 @@ static int snd_vx_suspend(snd_card_t *ca
 /*
  * resume
  */
-static int snd_vx_resume(snd_card_t *card, unsigned int state)
+static int snd_vx_resume(snd_card_t *card)
 {
 	vx_core_t *chip = card->pm_private_data;
 	int i, err;
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -21,6 +21,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -3,6 +3,7 @@
 # Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
 #
 
+snd-ak4114-objs := ak4114.o
 snd-ak4117-objs := ak4117.o
 snd-ak4xxx-adda-objs := ak4xxx-adda.o
 snd-tea575x-tuner-objs := tea575x-tuner.o
@@ -11,4 +12,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
+obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
 obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
new file mode 100644
--- /dev/null
+++ b/sound/i2c/other/ak4114.c
@@ -0,0 +1,580 @@
+/*
+ *  Routines for control of the AK4114 via I2C and 4-wire serial interface
+ *  IEC958 (S/PDIF) receiver by Asahi Kasei
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   This program is free software; you can redistribute it 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 <sound/driver.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/ak4114.h>
+#include <sound/asoundef.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("AK4114 IEC958 (S/PDIF) receiver by Asahi Kasei");
+MODULE_LICENSE("GPL");
+
+#define AK4114_ADDR			0x00 /* fixed address */
+
+static void ak4114_stats(void *);
+
+static void reg_write(ak4114_t *ak4114, unsigned char reg, unsigned char val)
+{
+	ak4114->write(ak4114->private_data, reg, val);
+	if (reg <= AK4114_REG_INT1_MASK)
+		ak4114->regmap[reg] = val;
+	else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4)
+		ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val;
+}
+
+static inline unsigned char reg_read(ak4114_t *ak4114, unsigned char reg)
+{
+	return ak4114->read(ak4114->private_data, reg);
+}
+
+#if 0
+static void reg_dump(ak4114_t *ak4114)
+{
+	int i;
+
+	printk("AK4114 REG DUMP:\n");
+	for (i = 0; i < 0x20; i++)
+		printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < sizeof(ak4114->regmap) ? ak4114->regmap[i] : 0);
+}
+#endif
+
+static void snd_ak4114_free(ak4114_t *chip)
+{
+	chip->init = 1;	/* don't schedule new work */
+	mb();
+	if (chip->workqueue != NULL) {
+		flush_workqueue(chip->workqueue);
+		destroy_workqueue(chip->workqueue);
+	}
+	kfree(chip);
+}
+
+static int snd_ak4114_dev_free(snd_device_t *device)
+{
+	ak4114_t *chip = device->device_data;
+	snd_ak4114_free(chip);
+	return 0;
+}
+
+int snd_ak4114_create(snd_card_t *card,
+		      ak4114_read_t *read, ak4114_write_t *write,
+		      unsigned char pgm[7], unsigned char txcsb[5],
+		      void *private_data, ak4114_t **r_ak4114)
+{
+	ak4114_t *chip;
+	int err = 0;
+	unsigned char reg;
+	static snd_device_ops_t ops = {
+		.dev_free =     snd_ak4114_dev_free,
+	};
+
+	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->read = read;
+	chip->write = write;
+	chip->private_data = private_data;
+
+	for (reg = 0; reg < 7; reg++)
+		chip->regmap[reg] = pgm[reg];
+	for (reg = 0; reg < 5; reg++)
+		chip->txcsb[reg] = txcsb[reg];
+
+	chip->workqueue = create_workqueue("snd-ak4114");
+	if (chip->workqueue == NULL) {
+		kfree(chip);
+		return -ENOMEM;
+	}
+
+	snd_ak4114_reinit(chip);
+
+	chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
+	chip->rcs1 = reg_read(chip, AK4114_REG_RCS1);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
+		goto __fail;
+
+	if (r_ak4114)
+		*r_ak4114 = chip;
+	return 0;
+
+      __fail:
+	snd_ak4114_free(chip);
+	return err < 0 ? err : -EIO;
+}
+
+void snd_ak4114_reg_write(ak4114_t *chip, unsigned char reg, unsigned char mask, unsigned char val)
+{
+	if (reg <= AK4114_REG_INT1_MASK)
+		reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
+	else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
+		reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val);
+}
+
+void snd_ak4114_reinit(ak4114_t *chip)
+{
+	unsigned char old = chip->regmap[AK4114_REG_PWRDN], reg;
+
+	chip->init = 1;
+	mb();
+	flush_workqueue(chip->workqueue);
+	/* bring the chip to reset state and powerdown state */
+	reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN));
+	udelay(200);
+	/* release reset, but leave powerdown */
+	reg_write(chip, AK4114_REG_PWRDN, (old | AK4114_RST) & ~AK4114_PWN);
+	udelay(200);
+	for (reg = 1; reg < 7; reg++)
+		reg_write(chip, reg, chip->regmap[reg]);
+	for (reg = 0; reg < 5; reg++)
+		reg_write(chip, reg + AK4114_REG_TXCSB0, chip->txcsb[reg]);
+	/* release powerdown, everything is initialized now */
+	reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN);
+	/* bring up statistics / event queing */
+	chip->init = 0;
+	INIT_WORK(&chip->work, ak4114_stats, chip);
+	queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+}
+
+static unsigned int external_rate(unsigned char rcs1)
+{
+	switch (rcs1 & (AK4114_FS0|AK4114_FS1|AK4114_FS2|AK4114_FS3)) {
+	case AK4114_FS_32000HZ: return 32000;
+	case AK4114_FS_44100HZ: return 44100;
+	case AK4114_FS_48000HZ: return 48000;
+	case AK4114_FS_88200HZ: return 88200;
+	case AK4114_FS_96000HZ: return 96000;
+	case AK4114_FS_176400HZ: return 176400;
+	case AK4114_FS_192000HZ: return 192000;
+	default:		return 0;
+	}
+}
+
+static int snd_ak4114_in_error_info(snd_kcontrol_t *kcontrol,
+				    snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = LONG_MAX;
+	return 0;
+}
+
+static int snd_ak4114_in_error_get(snd_kcontrol_t *kcontrol,
+				   snd_ctl_elem_value_t *ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	long *ptr;
+
+	spin_lock_irq(&chip->lock);
+	ptr = (long *)(((char *)chip) + kcontrol->private_value);
+	ucontrol->value.integer.value[0] = *ptr;
+	*ptr = 0;
+	spin_unlock_irq(&chip->lock);
+	return 0;
+}
+
+static int snd_ak4114_in_bit_info(snd_kcontrol_t *kcontrol,
+				  snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ak4114_in_bit_get(snd_kcontrol_t *kcontrol,
+				 snd_ctl_elem_value_t *ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned char reg = kcontrol->private_value & 0xff;
+	unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
+	unsigned char inv = (kcontrol->private_value >> 31) & 1;
+
+	ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
+	return 0;
+}
+
+static int snd_ak4114_rate_info(snd_kcontrol_t *kcontrol,
+				snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 192000;
+	return 0;
+}
+
+static int snd_ak4114_rate_get(snd_kcontrol_t *kcontrol,
+			       snd_ctl_elem_value_t *ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4114_REG_RCS1));
+	return 0;
+}
+
+static int snd_ak4114_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ak4114_spdif_get(snd_kcontrol_t * kcontrol,
+				snd_ctl_elem_value_t * ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4114_REG_RXCSB_SIZE; i++)
+		ucontrol->value.iec958.status[i] = reg_read(chip, AK4114_REG_RXCSB0 + i);
+	return 0;
+}
+
+static int snd_ak4114_spdif_playback_get(snd_kcontrol_t * kcontrol,
+					 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++)
+		ucontrol->value.iec958.status[i] = chip->txcsb[i];
+	return 0;
+}
+
+static int snd_ak4114_spdif_playback_put(snd_kcontrol_t * kcontrol,
+					 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++)
+		reg_write(chip, AK4114_REG_TXCSB0 + i, ucontrol->value.iec958.status[i]);
+	return 0;
+}
+
+static int snd_ak4114_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ak4114_spdif_mask_get(snd_kcontrol_t * kcontrol,
+				      snd_ctl_elem_value_t * ucontrol)
+{
+	memset(ucontrol->value.iec958.status, 0xff, AK4114_REG_RXCSB_SIZE);
+	return 0;
+}
+
+static int snd_ak4114_spdif_pinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xffff;
+	uinfo->count = 4;
+	return 0;
+}
+
+static int snd_ak4114_spdif_pget(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned short tmp;
+
+	ucontrol->value.integer.value[0] = 0xf8f2;
+	ucontrol->value.integer.value[1] = 0x4e1f;
+	tmp = reg_read(chip, AK4114_REG_Pc0) | (reg_read(chip, AK4114_REG_Pc1) << 8);
+	ucontrol->value.integer.value[2] = tmp;
+	tmp = reg_read(chip, AK4114_REG_Pd0) | (reg_read(chip, AK4114_REG_Pd1) << 8);
+	ucontrol->value.integer.value[3] = tmp;
+	return 0;
+}
+
+static int snd_ak4114_spdif_qinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = AK4114_REG_QSUB_SIZE;
+	return 0;
+}
+
+static int snd_ak4114_spdif_qget(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4114_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4114_REG_QSUB_SIZE; i++)
+		ucontrol->value.bytes.data[i] = reg_read(chip, AK4114_REG_QSUB_ADDR + i);
+	return 0;
+}
+
+/* Don't forget to change AK4114_CONTROLS define!!! */
+static snd_kcontrol_new_t snd_ak4114_iec958_controls[] = {
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Parity Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_error_info,
+	.get =		snd_ak4114_in_error_get,
+	.private_value = offsetof(ak4114_t, parity_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 V-Bit Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_error_info,
+	.get =		snd_ak4114_in_error_get,
+	.private_value = offsetof(ak4114_t, v_bit_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 C-CRC Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_error_info,
+	.get =		snd_ak4114_in_error_get,
+	.private_value = offsetof(ak4114_t, ccrc_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Q-CRC Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_error_info,
+	.get =		snd_ak4114_in_error_get,
+	.private_value = offsetof(ak4114_t, qcrc_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 External Rate",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_rate_info,
+	.get =		snd_ak4114_rate_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.info =		snd_ak4114_spdif_mask_info,
+	.get =		snd_ak4114_spdif_mask_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_spdif_info,
+	.get =		snd_ak4114_spdif_playback_get,
+	.put =		snd_ak4114_spdif_playback_put,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.info =		snd_ak4114_spdif_mask_info,
+	.get =		snd_ak4114_spdif_mask_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_spdif_info,
+	.get =		snd_ak4114_spdif_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Preample Capture Default",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_spdif_pinfo,
+	.get =		snd_ak4114_spdif_pget,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Q-subcode Capture Default",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_spdif_qinfo,
+	.get =		snd_ak4114_spdif_qget,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Audio",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_bit_info,
+	.get =		snd_ak4114_in_bit_get,
+	.private_value = (1<<31) | (1<<8) | AK4114_REG_RCS0,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Non-PCM Bitstream",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_bit_info,
+	.get =		snd_ak4114_in_bit_get,
+	.private_value = (6<<8) | AK4114_REG_RCS1,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 DTS Bitstream",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4114_in_bit_info,
+	.get =		snd_ak4114_in_bit_get,
+	.private_value = (3<<8) | AK4114_REG_RCS1,
+}
+};
+
+int snd_ak4114_build(ak4114_t *ak4114,
+		     snd_pcm_substream_t *ply_substream,
+		     snd_pcm_substream_t *cap_substream)
+{
+	snd_kcontrol_t *kctl;
+	unsigned int idx;
+	int err;
+
+	snd_assert(cap_substream, return -EINVAL);
+	ak4114->playback_substream = ply_substream;
+	ak4114->capture_substream = cap_substream;
+	for (idx = 0; idx < AK4114_CONTROLS; idx++) {
+		kctl = snd_ctl_new1(&snd_ak4114_iec958_controls[idx], ak4114);
+		if (kctl == NULL)
+			return -ENOMEM;
+		if (!strstr(kctl->id.name, "Playback")) {
+			if (ply_substream == NULL) {
+				snd_ctl_free_one(kctl);
+				ak4114->kctls[idx] = NULL;
+				continue;
+			}
+			kctl->id.device = ply_substream->pcm->device;
+			kctl->id.subdevice = ply_substream->number;
+		} else {
+			kctl->id.device = cap_substream->pcm->device;
+			kctl->id.subdevice = cap_substream->number;
+		}
+		err = snd_ctl_add(ak4114->card, kctl);
+		if (err < 0)
+			return err;
+		ak4114->kctls[idx] = kctl;
+	}
+	return 0;
+}
+
+int snd_ak4114_external_rate(ak4114_t *ak4114)
+{
+	unsigned char rcs1;
+
+	rcs1 = reg_read(ak4114, AK4114_REG_RCS1);
+	return external_rate(rcs1);
+}
+
+int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags)
+{
+	snd_pcm_runtime_t *runtime = ak4114->capture_substream ? ak4114->capture_substream->runtime : NULL;
+	unsigned long _flags;
+	int res = 0;
+	unsigned char rcs0, rcs1;
+	unsigned char c0, c1;
+
+	rcs1 = reg_read(ak4114, AK4114_REG_RCS1);
+	if (flags & AK4114_CHECK_NO_STAT)
+		goto __rate;
+	rcs0 = reg_read(ak4114, AK4114_REG_RCS0);
+	spin_lock_irqsave(&ak4114->lock, _flags);
+	if (rcs0 & AK4114_PAR)
+		ak4114->parity_errors++;
+	if (rcs1 & AK4114_V)
+		ak4114->v_bit_errors++;
+	if (rcs1 & AK4114_CCRC)
+		ak4114->ccrc_errors++;
+	if (rcs1 & AK4114_QCRC)
+		ak4114->qcrc_errors++;
+	c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^
+                     (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK));
+	c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0);
+	ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT);
+	ak4114->rcs1 = rcs1;
+	spin_unlock_irqrestore(&ak4114->lock, _flags);
+
+	if (rcs0 & AK4114_PAR)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[0]->id);
+	if (rcs0 & AK4114_V)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[1]->id);
+	if (rcs1 & AK4114_CCRC)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[2]->id);
+	if (rcs1 & AK4114_QCRC)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[3]->id);
+
+	/* rate change */
+	if (c1 & 0xf0)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[4]->id);
+
+	if ((c0 & AK4114_PEM) | (c0 & AK4114_CINT))
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[9]->id);
+	if (c0 & AK4114_QINT)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[10]->id);
+
+	if (c0 & AK4114_AUDION)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[11]->id);
+	if (c0 & AK4114_AUTO)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[12]->id);
+	if (c0 & AK4114_DTSCD)
+		snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[13]->id);
+
+	if (ak4114->change_callback && (c0 | c1) != 0)
+		ak4114->change_callback(ak4114, c0, c1);
+
+      __rate:
+	/* compare rate */
+	res = external_rate(rcs1);
+	if (!(flags & AK4114_CHECK_NO_RATE) && runtime && runtime->rate != res) {
+		snd_pcm_stream_lock_irqsave(ak4114->capture_substream, _flags);
+		if (snd_pcm_running(ak4114->capture_substream)) {
+			// printk("rate changed (%i <- %i)\n", runtime->rate, res);
+			snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING);
+			wake_up(&runtime->sleep);
+			res = 1;
+		}
+		snd_pcm_stream_unlock_irqrestore(ak4114->capture_substream, _flags);
+	}
+	return res;
+}
+
+static void ak4114_stats(void *data)
+{
+	ak4114_t *chip = (ak4114_t *)data;
+
+	if (chip->init)
+		return;
+	snd_ak4114_check_rate_and_errors(chip, 0);
+	queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+}
+
+EXPORT_SYMBOL(snd_ak4114_create);
+EXPORT_SYMBOL(snd_ak4114_reg_write);
+EXPORT_SYMBOL(snd_ak4114_reinit);
+EXPORT_SYMBOL(snd_ak4114_build);
+EXPORT_SYMBOL(snd_ak4114_external_rate);
+EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -1,8 +1,8 @@
 /*
- *   ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381
+ *   ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
  *   AD and DA converters
  *
- *	Copyright (c) 2000-2003 Jaroslav Kysela <perex@suse.cz>,
+ *	Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>,
  *				Takashi Iwai <tiwai@suse.de>
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -84,6 +84,7 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, in
 		/* FIXME: needed for ak4529? */
 		break;
 	case SND_AK4355:
+	case SND_AK4358:
 		if (state) {
 			snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
 			return;
@@ -166,6 +167,24 @@ void snd_akm4xxx_init(akm4xxx_t *ak)
 		0x01, 0x01, /* 1: un-reset, unmute */
 		0xff, 0xff
 	};
+	static unsigned char inits_ak4358[] = {
+		0x01, 0x02, /* 1: reset and soft-mute */
+		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+		0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
+		// 0x02, 0x2e, /* quad speed */
+		0x03, 0x01, /* 3: de-emphasis off */
+		0x04, 0x00, /* 4: LOUT1 volume muted */
+		0x05, 0x00, /* 5: ROUT1 volume muted */
+		0x06, 0x00, /* 6: LOUT2 volume muted */
+		0x07, 0x00, /* 7: ROUT2 volume muted */
+		0x08, 0x00, /* 8: LOUT3 volume muted */
+		0x09, 0x00, /* 9: ROUT3 volume muted */
+		0x0b, 0x00, /* b: LOUT4 volume muted */
+		0x0c, 0x00, /* c: ROUT4 volume muted */
+		0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
+		0x01, 0x01, /* 1: un-reset, unmute */
+		0xff, 0xff
+	};
 	static unsigned char inits_ak4381[] = {
 		0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
 		0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
@@ -197,6 +216,10 @@ void snd_akm4xxx_init(akm4xxx_t *ak)
 		inits = inits_ak4355;
 		num_chips = 1;
 		break;
+	case SND_AK4358:
+		inits = inits_ak4358;
+		num_chips = 1;
+		break;
 	case SND_AK4381:
 		inits = inits_ak4381;
 		num_chips = ak->num_dacs / 2;
@@ -343,106 +366,121 @@ static int snd_akm4xxx_deemphasis_put(sn
 int snd_akm4xxx_build_controls(akm4xxx_t *ak)
 {
 	unsigned int idx, num_emphs;
+	snd_kcontrol_t *ctl;
 	int err;
 
+	ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
+	if (! ctl)
+		return -ENOMEM;
+
 	for (idx = 0; idx < ak->num_dacs; ++idx) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "DAC Volume");
-		ctl.id.index = idx + ak->idx_offset * 2;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.count = 1;
-		ctl.info = snd_akm4xxx_volume_info;
-		ctl.get = snd_akm4xxx_volume_get;
-		ctl.put = snd_akm4xxx_volume_put;
+		memset(ctl, 0, sizeof(*ctl));
+		strcpy(ctl->id.name, "DAC Volume");
+		ctl->id.index = idx + ak->idx_offset * 2;
+		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl->count = 1;
+		ctl->info = snd_akm4xxx_volume_info;
+		ctl->get = snd_akm4xxx_volume_get;
+		ctl->put = snd_akm4xxx_volume_put;
 		switch (ak->type) {
 		case SND_AK4524:
-			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
+			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
 			break;
 		case SND_AK4528:
-			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
 			break;
 		case SND_AK4529: {
 			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
-			ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+			ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
 			break;
 		}
 		case SND_AK4355:
-			ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+			ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+			break;
+		case SND_AK4358:
+			if (idx >= 6)
+				ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
+			else
+				ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
 			break;
 		case SND_AK4381:
-			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
+			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
 			break;
 		default:
-			return -EINVAL;
-			}
-		ctl.private_data = ak;
-		if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
-			return err;
+			err = -EINVAL;
+			goto __error;
+		}
+		ctl->private_data = ak;
+		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+			goto __error;
 	}
 	for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "ADC Volume");
-		ctl.id.index = idx + ak->idx_offset * 2;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.count = 1;
-		ctl.info = snd_akm4xxx_volume_info;
-		ctl.get = snd_akm4xxx_volume_get;
-		ctl.put = snd_akm4xxx_volume_put;
-		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
-		ctl.private_data = ak;
-		if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
-			return err;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "IPGA Analog Capture Volume");
-		ctl.id.index = idx + ak->idx_offset * 2;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.count = 1;
-		ctl.info = snd_akm4xxx_ipga_gain_info;
-		ctl.get = snd_akm4xxx_ipga_gain_get;
-		ctl.put = snd_akm4xxx_ipga_gain_put;
-		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
-		ctl.private_data = ak;
-		if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
-			return err;
+		memset(ctl, 0, sizeof(*ctl));
+		strcpy(ctl->id.name, "ADC Volume");
+		ctl->id.index = idx + ak->idx_offset * 2;
+		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl->count = 1;
+		ctl->info = snd_akm4xxx_volume_info;
+		ctl->get = snd_akm4xxx_volume_get;
+		ctl->put = snd_akm4xxx_volume_put;
+		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+		ctl->private_data = ak;
+		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+			goto __error;
+
+		memset(ctl, 0, sizeof(*ctl));
+		strcpy(ctl->id.name, "IPGA Analog Capture Volume");
+		ctl->id.index = idx + ak->idx_offset * 2;
+		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl->count = 1;
+		ctl->info = snd_akm4xxx_ipga_gain_info;
+		ctl->get = snd_akm4xxx_ipga_gain_get;
+		ctl->put = snd_akm4xxx_ipga_gain_put;
+		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
+		ctl->private_data = ak;
+		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+			goto __error;
 	}
-	if (ak->type == SND_AK4355)
+	if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
 		num_emphs = 1;
 	else
 		num_emphs = ak->num_dacs / 2;
 	for (idx = 0; idx < num_emphs; idx++) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "Deemphasis");
-		ctl.id.index = idx + ak->idx_offset;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.count = 1;
-		ctl.info = snd_akm4xxx_deemphasis_info;
-		ctl.get = snd_akm4xxx_deemphasis_get;
-		ctl.put = snd_akm4xxx_deemphasis_put;
+		memset(ctl, 0, sizeof(*ctl));
+		strcpy(ctl->id.name, "Deemphasis");
+		ctl->id.index = idx + ak->idx_offset;
+		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl->count = 1;
+		ctl->info = snd_akm4xxx_deemphasis_info;
+		ctl->get = snd_akm4xxx_deemphasis_get;
+		ctl->put = snd_akm4xxx_deemphasis_put;
 		switch (ak->type) {
 		case SND_AK4524:
 		case SND_AK4528:
-			ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
+			ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
 			break;
 		case SND_AK4529: {
 			int shift = idx == 3 ? 6 : (2 - idx) * 2;
-			ctl.private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
+			ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
 			break;
 		}
 		case SND_AK4355:
-			ctl.private_value = AK_COMPOSE(idx, 3, 0, 0);
+		case SND_AK4358:
+			ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
 			break;
 		case SND_AK4381:
-			ctl.private_value = AK_COMPOSE(idx, 1, 1, 0);
+			ctl->private_value = AK_COMPOSE(idx, 1, 1, 0);
 			break;
 		}
-		ctl.private_data = ak;
-		if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
-			return err;
+		ctl->private_data = ak;
+		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+			goto __error;
 	}
-	return 0;
+	err = 0;
+
+ __error:
+	kfree(ctl);
+	return err;
 }
 
 static int __init alsa_akm4xxx_module_init(void)
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -168,6 +168,10 @@ static int snd_tea575x_ioctl(struct inod
 	}
 }
 
+static void snd_tea575x_release(struct video_device *vfd)
+{
+}
+
 /*
  * initialize all the tea575x chips
  */
@@ -186,6 +190,7 @@ void snd_tea575x_init(tea575x_t *tea)
 	strcpy(tea->vd.name, tea->tea5759 ? "TEA5759 radio" : "TEA5757 radio");
 	tea->vd.type = VID_TYPE_TUNER;
 	tea->vd.hardware = VID_HARDWARE_RTRACK;	/* FIXME: assign new number */
+	tea->vd.release = snd_tea575x_release;
 	video_set_drvdata(&tea->vd, tea);
 	tea->vd.fops = &tea->fops;
 	tea->fops.owner = tea->card->module;
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -3,6 +3,16 @@
 menu "ISA devices"
 	depends on SND!=n && ISA
 
+config SND_AD1848_LIB
+        tristate
+        select SND_PCM
+	select SND_GENERIC_PM
+
+config SND_CS4231_LIB
+        tristate
+        select SND_PCM
+	select SND_GENERIC_PM
+
 config SND_AD1816A
 	tristate "Analog Devices SoundPort AD1816A"
 	depends on SND && ISAPNP
@@ -19,7 +29,7 @@ config SND_AD1816A
 config SND_AD1848
 	tristate "Generic AD1848/CS4248 driver"
 	depends on SND
-	select SND_PCM
+	select SND_AD1848_LIB
 	help
 	  Say Y here to include support for AD1848 (Analog Devices) or
 	  CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
@@ -34,7 +44,7 @@ config SND_CS4231
 	tristate "Generic Cirrus Logic CS4231 driver"
 	depends on SND
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for CS4231 chips from Cirrus
 	  Logic - Crystal Semiconductors.
@@ -47,7 +57,7 @@ config SND_CS4232
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for CS4232 chips from Cirrus
 	  Logic - Crystal Semiconductors.
@@ -60,7 +70,7 @@ config SND_CS4236
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
 	  CS4239 chips from Cirrus Logic - Crystal Semiconductors.
@@ -98,6 +108,7 @@ config SND_ES18XX
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_PCM
+	select SND_GENERIC_PM
 	help
 	  Say Y here to include support for ESS AudioDrive ES18xx chips.
 
@@ -138,7 +149,7 @@ config SND_GUSMAX
 	tristate "Gravis UltraSound MAX"
 	depends on SND
 	select SND_RAWMIDI
-	select SND_PCM
+	select SND_CS4231_LIB
 	select SND_GUS_SYNTH
 	help
 	  Say Y here to include support for Gravis UltraSound MAX
@@ -151,8 +162,9 @@ config SND_INTERWAVE
 	tristate "AMD InterWave, Gravis UltraSound PnP"
 	depends on SND
 	select SND_RAWMIDI
-	select SND_PCM
+	select SND_CS4231_LIB
 	select SND_GUS_SYNTH
+	select ISAPNP
 	help
 	  Say Y here to include support for AMD InterWave based
 	  soundcards (Gravis UltraSound Plug & Play, STB SoundRage32,
@@ -165,7 +177,7 @@ config SND_INTERWAVE_STB
 	tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
 	depends on SND
 	select SND_RAWMIDI
-	select SND_PCM
+	select SND_CS4231_LIB
 	select SND_GUS_SYNTH
 	help
 	  Say Y here to include support for AMD InterWave based
@@ -181,7 +193,7 @@ config SND_OPTI92X_AD1848
 	select SND_OPL3_LIB
 	select SND_OPL4_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_AD1848_LIB
 	help
 	  Say Y here to include support for soundcards based on Opti
 	  82C92x or OTI-601 chips and using an AD1848 codec.
@@ -195,7 +207,7 @@ config SND_OPTI92X_CS4231
 	select SND_OPL3_LIB
 	select SND_OPL4_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for soundcards based on Opti
 	  82C92x chips and using a CS4231 codec.
@@ -268,7 +280,7 @@ config SND_WAVEFRONT
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for Turtle Beach Maui, Tropez
 	  and Tropez+ soundcards based on the Wavefront chip.
@@ -294,7 +306,7 @@ config SND_AZT2320
 	depends on SND && ISAPNP
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for soundcards based on the
 	  Aztech Systems AZT2320 chip.
@@ -305,7 +317,7 @@ config SND_AZT2320
 config SND_CMI8330
 	tristate "C-Media CMI8330"
 	depends on SND
-	select SND_PCM
+	select SND_AD1848_LIB
 	help
 	  Say Y here to include support for soundcards based on the
 	  C-Media CMI8330 chip.
@@ -331,7 +343,7 @@ config SND_OPL3SA2
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3
 	  chips.
@@ -342,7 +354,7 @@ config SND_OPL3SA2
 config SND_SGALAXY
 	tristate "Aztech Sound Galaxy"
 	depends on SND
-	select SND_PCM
+	select SND_AD1848_LIB
 	help
 	  Say Y here to include support for Aztech Sound Galaxy
 	  soundcards.
@@ -355,7 +367,7 @@ config SND_SSCAPE
 	depends on SND
 	select SND_HWDEP
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_CS4231_LIB
 	help
 	  Say Y here to include support for Ensoniq SoundScape PnP
 	  soundcards.
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -644,7 +644,7 @@ static void snd_ad1848_thinkpad_twiddle(
 }
 
 #ifdef CONFIG_PM
-static int snd_ad1848_suspend(snd_card_t *card, unsigned int state)
+static int snd_ad1848_suspend(snd_card_t *card, pm_message_t state)
 {
 	ad1848_t *chip = card->pm_private_data;
 
@@ -657,7 +657,7 @@ static int snd_ad1848_suspend(snd_card_t
 	return 0;
 }
 
-static int snd_ad1848_resume(snd_card_t *card, unsigned int state)
+static int snd_ad1848_resume(snd_card_t *card)
 {
 	ad1848_t *chip = card->pm_private_data;
 
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -121,7 +121,7 @@ static int __devinit snd_card_als100_pnp
 		return -ENODEV;
 	}
 	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
-	acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->devmpu);
+	acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
 
 	pdev = acard->dev;
 
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
--- a/sound/isa/cs423x/cs4231_lib.c
+++ b/sound/isa/cs423x/cs4231_lib.c
@@ -1394,7 +1394,7 @@ static void snd_cs4231_resume(cs4231_t *
 #endif
 }
 
-static int snd_cs4231_pm_suspend(snd_card_t *card, unsigned int state)
+static int snd_cs4231_pm_suspend(snd_card_t *card, pm_message_t state)
 {
 	cs4231_t *chip = card->pm_private_data;
 	if (chip->suspend)
@@ -1402,7 +1402,7 @@ static int snd_cs4231_pm_suspend(snd_car
 	return 0;
 }
 
-static int snd_cs4231_pm_resume(snd_card_t *card, unsigned int state)
+static int snd_cs4231_pm_resume(snd_card_t *card)
 {
 	cs4231_t *chip = card->pm_private_data;
 	if (chip->resume)
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -1612,7 +1612,7 @@ static int __devinit snd_es18xx_pcm(es18
 
 /* Power Management support functions */
 #ifdef CONFIG_PM
-static int snd_es18xx_suspend(snd_card_t *card, unsigned int state)
+static int snd_es18xx_suspend(snd_card_t *card, pm_message_t state)
 {
 	es18xx_t *chip = card->pm_private_data;
 
@@ -1627,7 +1627,7 @@ static int snd_es18xx_suspend(snd_card_t
 	return 0;
 }
 
-static int snd_es18xx_resume(snd_card_t *card, unsigned int state)
+static int snd_es18xx_resume(snd_card_t *card)
 {
 	es18xx_t *chip = card->pm_private_data;
 
diff --git a/sound/isa/gus/gus_lfo.c b/sound/isa/gus/gus_lfo.c
deleted file mode 100644
--- a/sound/isa/gus/gus_lfo.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *  Routines for control of LFO generators (tremolo & vibrato) for
- *  GF1/InterWave chips...
- *
- *
- *   This program is free software; you can redistribute it 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 <sound/driver.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *  called by engine routines
- */
-
-static signed char snd_gf1_lfo_compute_value(snd_gus_card_t * gus,
-					     unsigned char *ptr)
-{
-	unsigned int twaveinc, depth_delta;
-	signed int result;
-	unsigned short control, twave, depth, depth_final;
-	unsigned char *ptr1;
-
-	control = *(unsigned short *) (ptr + 0x00);
-	ptr1 = ptr + ((control & 0x4000) >> 12);
-	/* 1. add TWAVEINC to TWAVE and write the result back */
-	/* LFO update rate is 689Hz, effect timer is in ms */
-	if (gus->gf1.timer_slave)
-		twaveinc = (689 * gus->gf1.timer_master_gus->gf1.effect_timer) / 1000;
-	else
-		twaveinc = (689 * gus->gf1.effect_timer) / 1000;
-	if (!twaveinc)
-		twaveinc++;
-#if 0
-	printk("twaveinc = 0x%x, effect_timer = %i\n", twaveinc, gus->gf1.effect_timer);
-#endif
-
-	depth = *(unsigned short *) (ptr1 + 0x0a);
-	depth_final = *(unsigned char *) (ptr + 0x02) << 5;
-	if (depth != depth_final) {
-		depth_delta = ((twaveinc * *(ptr + 0x03)) + *(unsigned short *) (ptr + 0x04));
-		*(unsigned short *) (ptr + 0x04) = depth_delta % 8000;
-		depth_delta /= 8000;
-		if (depth < depth_final) {
-			if (depth + depth_delta > depth_final)
-				depth = depth_final;
-			else
-				depth += depth_delta;
-		}
-		if (depth > depth_final) {
-			if (depth - depth_delta < depth_final)
-				depth = depth_final;
-			else
-				depth -= depth_delta;
-		}
-		*(unsigned short *) (ptr1 + 0x0a) = depth;
-	}
-	twaveinc *= (unsigned int) control & 0x7ff;
-	twaveinc += *(unsigned short *) (ptr + 0x06);
-	*(unsigned short *) (ptr + 0x06) = twaveinc % 1000;
-
-	twave = *(unsigned short *) (ptr1 + 0x08);
-	twave += (unsigned short) (twaveinc / (unsigned int) 1000);
-	*(unsigned short *) (ptr1 + 0x08) = twave;
-
-	if (!(control & 0x2000)) {
-		/* 2. if shift is low */
-		if (twave & 0x4000) {	/* bit 14 high -> invert TWAVE 13-0 */
-			twave ^= 0x3fff;
-			twave &= ~0x4000;
-		}
-		/* TWAVE bit 15 is exclusive or'd with the invert bit (12) */
-		twave ^= (control & 0x1000) << 3;
-	} else {
-		/* 2. if shift is high */
-		if (twave & 0x8000)	/* bit 15 high -> invert TWAVE 14-0 */
-			twave ^= 0x7fff;
-		/* the invert bit (12) is used as sign bit */
-		if (control & 0x1000)
-			twave |= 0x8000;
-		else
-			twave &= ~0x8000;
-	}
-	/* 3. multiply the 14-bit LFO waveform magnitude by 13-bit DEPTH */
-#if 0
-	printk("c=0x%x,tw=0x%x,to=0x%x,d=0x%x,df=0x%x,di=0x%x,r=0x%x,r1=%i\n",
-	       control, twave,
-	       *(unsigned short *) (ptr1 + 0x08),
-	       depth, depth_final, *(ptr + 0x03),
-	     (twave & 0x7fff) * depth, ((twave & 0x7fff) * depth) >> 21);
-#endif
-	result = (twave & 0x7fff) * depth;
-	if (result) {
-		/* shift */
-		result >>= 21;
-		result &= 0x3f;
-	}
-	/* add sign */
-	if (twave & 0x8000)
-		result = -result;
-#if 0
-	printk("lfo final value = %i\n", result);
-#endif
-	return result;
-}
-
-static void snd_gf1_lfo_register_setup(snd_gus_card_t * gus,
-				       snd_gf1_voice_t * voice,
-				       int lfo_type)
-{
-	unsigned long flags;
-
-	if (gus->gf1.enh_mode) {
-		CLI(&flags);
-		gf1_select_voice(gus, voice->number);
-		if (lfo_type & 1) {
-			snd_gf1_write8(gus, GF1_VB_FREQUENCY_LFO, voice->lfo_fc);
-			voice->lfo_fc = 0;
-		}
-		if (lfo_type & 2) {
-			snd_gf1_write8(gus, GF1_VB_VOLUME_LFO, voice->lfo_volume);
-			voice->lfo_volume = 0;
-		}
-		STI(&flags);
-	} else {
-		/*
-		 * ok.. with old GF1 chip can be only vibrato emulated...
-		 * volume register can be in volume ramp state, so tremolo isn't simple..
-		 */
-		if (!(lfo_type & 1))
-			return;
-#if 0
-		if (voice->lfo_fc)
-			printk("setup - %i = %i\n", voice->number, voice->lfo_fc);
-#endif
-		CLI(&flags);
-		gf1_select_voice(gus, voice->number);
-		snd_gf1_write16(gus, GF1_VW_FREQUENCY, voice->fc_register + voice->lfo_fc);
-		STI(&flags);
-	}
-}
-
-void snd_gf1_lfo_effect_interrupt(snd_gus_card_t * gus, snd_gf1_voice_t * voice)
-{
-	unsigned char *ptr;
-
-#if 0
-	if (voice->number != 0)
-		return;
-#endif
-	ptr = gus->gf1.lfos + ((voice->number) << 5);
-	/* 1. vibrato */
-	if (*(unsigned short *) (ptr + 0x00) & 0x8000)
-		voice->lfo_fc = snd_gf1_lfo_compute_value(gus, ptr);
-	/* 2. tremolo */
-	ptr += 16;
-	if (*(unsigned short *) (ptr + 0x00) & 0x8000)
-		voice->lfo_volume = snd_gf1_lfo_compute_value(gus, ptr);
-	/* 3. register setup */
-	snd_gf1_lfo_register_setup(gus, voice, 3);
-}
-
-/*
-
- */
-
-void snd_gf1_lfo_init(snd_gus_card_t * gus)
-{
-	if (gus->gf1.hw_lfo) {
-		snd_gf1_i_write16(gus, GF1_GW_LFO_BASE, 0x0000);
-		snd_gf1_dram_setmem(gus, 0, 0x0000, 1024);
-		/* now enable LFO */
-		snd_gf1_i_write8(gus, GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, GF1_GB_GLOBAL_MODE) | 0x02);
-	}
-	if (gus->gf1.sw_lfo) {
-#if 1
-		gus->gf1.lfos = snd_calloc(1024);
-		if (!gus->gf1.lfos)
-#endif
-			gus->gf1.sw_lfo = 0;
-	}
-}
-
-void snd_gf1_lfo_done(snd_gus_card_t * gus)
-{
-	if (gus->gf1.sw_lfo) {
-		if (gus->gf1.lfos) {
-			snd_gf1_free(gus->gf1.lfos, 1024);
-			gus->gf1.lfos = NULL;
-		}
-	}
-}
-
-void snd_gf1_lfo_program(snd_gus_card_t * gus, int voice, int lfo_type,
-                         struct ULTRA_STRU_IW_LFO_PROGRAM *program)
-{
-	unsigned int lfo_addr, wave_select;
-
-	wave_select = (program->freq_and_control & 0x4000) >> 12;
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	if (gus->gf1.hw_lfo) {
-#if 0
-		printk("LMCI = 0x%x\n", snd_gf1_i_look8(gus, 0x53));
-		printk("lfo_program: lfo_addr=0x%x,wave_sel=0x%x,fac=0x%x,df=0x%x,di=0x%x,twave=0x%x,depth=0x%x\n",
-		       lfo_addr, wave_select,
-		       program->freq_and_control,
-		       program->depth_final,
-		       program->depth_inc,
-		       program->twave,
-		       program->depth);
-#endif
-		snd_gf1_poke(gus, lfo_addr + 0x02, program->depth_final);
-		snd_gf1_poke(gus, lfo_addr + 0x03, program->depth_inc);
-		snd_gf1_pokew(gus, lfo_addr + 0x08 + wave_select, program->twave);
-		snd_gf1_pokew(gus, lfo_addr + 0x0a + wave_select, program->depth);
-		snd_gf1_pokew(gus, lfo_addr + 0x00, program->freq_and_control);
-#if 0
-		{
-			int i = 0;
-			for (i = 0; i < 16; i++)
-				printk("%02x:", snd_gf1_peek(gus, lfo_addr + i));
-			printk("\n");
-		}
-#endif
-	}
-	if (gus->gf1.sw_lfo) {
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-
-		*(ptr + 0x02) = program->depth_final;
-		*(ptr + 0x03) = program->depth_inc;
-		*(unsigned short *) (ptr + 0x08 + wave_select) = program->twave;
-		*(unsigned short *) (ptr + 0x0a + wave_select) = program->depth;
-		*(unsigned short *) (ptr + 0x00) = program->freq_and_control;
-	}
-}
-
-void snd_gf1_lfo_enable(snd_gus_card_t * gus, int voice, int lfo_type)
-{
-	unsigned int lfo_addr;
-
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	if (gus->gf1.hw_lfo)
-		snd_gf1_pokew(gus, lfo_addr + 0x00, snd_gf1_peekw(gus, lfo_addr + 0x00) | 0x8000);
-	if (gus->gf1.sw_lfo) {
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-
-		*(unsigned short *) (ptr + 0x00) |= 0x8000;
-	}
-}
-
-void snd_gf1_lfo_disable(snd_gus_card_t * gus, int voice, int lfo_type)
-{
-	unsigned int lfo_addr;
-
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	if (gus->gf1.hw_lfo)
-		snd_gf1_pokew(gus, lfo_addr + 0x00,
-				snd_gf1_peekw(gus, lfo_addr + 0x00) & ~0x8000);
-	if (gus->gf1.sw_lfo) {
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-
-		*(unsigned short *) (ptr + 0x00) &= ~0x8000;
-	}
-}
-
-void snd_gf1_lfo_change_freq(snd_gus_card_t * gus, int voice,
-		             int lfo_type, int freq)
-{
-	unsigned int lfo_addr;
-
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	if (gus->gf1.hw_lfo)
-		snd_gf1_pokew(gus, lfo_addr + 0x00,
-				(snd_gf1_peekw(gus, lfo_addr + 0x00) & ~0x7ff) | (freq & 0x7ff));
-	if (gus->gf1.sw_lfo) {
-		unsigned long flags;
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-
-		CLI(&flags);
-		*(unsigned short *) (ptr + 0x00) &= ~0x7ff;
-		*(unsigned short *) (ptr + 0x00) |= freq & 0x7ff;
-		STI(&flags);
-	}
-}
-
-void snd_gf1_lfo_change_depth(snd_gus_card_t * gus, int voice,
-			      int lfo_type, int depth)
-{
-	unsigned long flags;
-	unsigned int lfo_addr;
-	unsigned short control = 0;
-	unsigned char *ptr;
-
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	ptr = gus->gf1.lfos + lfo_addr;
-	if (gus->gf1.hw_lfo)
-		control = snd_gf1_peekw(gus, lfo_addr + 0x00);
-	if (gus->gf1.sw_lfo)
-		control = *(unsigned short *) (ptr + 0x00);
-	if (depth < 0) {
-		control |= 0x1000;
-		depth = -depth;
-	} else
-		control &= ~0x1000;
-	if (gus->gf1.hw_lfo) {
-		CLI(&flags);
-		snd_gf1_poke(gus, lfo_addr + 0x02, (unsigned char) depth);
-		snd_gf1_pokew(gus, lfo_addr + 0x0a + ((control & 0x4000) >> 12), depth << 5);
-		snd_gf1_pokew(gus, lfo_addr + 0x00, control);
-		STI(&flags);
-	}
-	if (gus->gf1.sw_lfo) {
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-
-		CLI(&flags);
-		*(ptr + 0x02) = (unsigned char) depth;
-		*(unsigned short *) (ptr + 0x0a + ((control & 0x4000) >> 12)) = depth << 5;
-		*(unsigned short *) (ptr + 0x00) = control;
-		STI(&flags);
-	}
-}
-
-void snd_gf1_lfo_setup(snd_gus_card_t * gus, int voice, int lfo_type,
-		       int freq, int current_depth, int depth, int sweep,
-		       int shape)
-{
-	struct ULTRA_STRU_IW_LFO_PROGRAM program;
-
-	program.freq_and_control = 0x8000 | (freq & 0x7ff);
-	if (shape & ULTRA_STRU_IW_LFO_SHAPE_POSTRIANGLE)
-		program.freq_and_control |= 0x2000;
-	if (depth < 0) {
-		program.freq_and_control |= 0x1000;
-		depth = -depth;
-	}
-	program.twave = 0;
-	program.depth = current_depth;
-	program.depth_final = depth;
-	if (sweep) {
-		program.depth_inc = (unsigned char) (((int) ((depth << 5) - current_depth) << 9) / (sweep * 4410L));
-		if (!program.depth_inc)
-			program.depth_inc++;
-	} else
-		program.depth = (unsigned short) (depth << 5);
-	snd_gf1_lfo_program(gus, voice, lfo_type, &program);
-}
-
-void snd_gf1_lfo_shutdown(snd_gus_card_t * gus, int voice, int lfo_type)
-{
-	unsigned long flags;
-	unsigned int lfo_addr;
-
-	lfo_addr = (voice << 5) | (lfo_type << 4);
-	if (gus->gf1.hw_lfo) {
-		snd_gf1_pokew(gus, lfo_addr + 0x00, 0x0000);
-		CLI(&flags);
-		gf1_select_voice(gus, voice);
-		snd_gf1_write8(gus, lfo_type == ULTRA_LFO_VIBRATO ? GF1_VB_FREQUENCY_LFO : GF1_VB_VOLUME_LFO, 0);
-		STI(&flags);
-	}
-	if (gus->gf1.sw_lfo) {
-		unsigned char *ptr = gus->gf1.lfos + lfo_addr;
-		snd_gf1_voice_t *pvoice;
-
-		*(unsigned short *) (ptr + 0x00) = 0;
-		*(unsigned short *) (ptr + 0x04) = 0;
-		*(unsigned short *) (ptr + 0x06) = 0;
-		if (gus->gf1.syn_voices) {
-			pvoice = gus->gf1.syn_voices + voice;
-			if (lfo_type == ULTRA_LFO_VIBRATO)
-				pvoice->lfo_fc = 0;
-			else
-				pvoice->lfo_volume = 0;
-			snd_gf1_lfo_register_setup(gus, pvoice, lfo_type == ULTRA_LFO_VIBRATO ? 1 : 2);
-		} else if (gus->gf1.enh_mode) {
-			CLI(&flags);
-			gf1_select_voice(gus, voice);
-			snd_gf1_write8(gus, lfo_type == ULTRA_LFO_VIBRATO ? GF1_VB_FREQUENCY_LFO : GF1_VB_VOLUME_LFO, 0);
-			STI(&flags);
-		}
-	}
-}
-
-void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char *data)
-{
-	int lfo_type;
-	int lfo_command;
-	int temp1, temp2;
-
-	lfo_type = *data >> 7;
-	lfo_command = *data & 0x7f;
-	switch (lfo_command) {
-	case ULTRA_LFO_SETUP:	/* setup */
-		temp1 = snd_gf1_get_word(data, 2);
-		temp2 = snd_gf1_get_word(data, 4);
-		snd_gf1_lfo_setup(gus, voice, lfo_type, temp1 & 0x7ff, 0, temp2 > 255 ? 255 : temp2, snd_gf1_get_byte(data, 1), (temp1 & 0x2000) >> 13);
-		break;
-	case ULTRA_LFO_FREQ:	/* freq */
-		snd_gf1_lfo_change_depth(gus, voice, lfo_type, snd_gf1_get_word(data, 2));
-		break;
-	case ULTRA_LFO_DEPTH:	/* depth */
-		snd_gf1_lfo_change_freq(gus, voice, lfo_type, snd_gf1_get_word(data, 2));
-		break;
-	case ULTRA_LFO_ENABLE:	/* enable */
-		snd_gf1_lfo_enable(gus, voice, lfo_type);
-		break;
-	case ULTRA_LFO_DISABLE:	/* disable */
-		snd_gf1_lfo_disable(gus, voice, lfo_type);
-		break;
-	case ULTRA_LFO_SHUTDOWN:	/* shutdown */
-		snd_gf1_lfo_shutdown(gus, voice, lfo_type);
-		break;
-	}
-}
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -333,6 +333,7 @@ static int snd_gf1_pcm_poke_block(snd_gu
 			}
 		}
 		if (count > 0 && !in_interrupt()) {
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(1);
 			if (signal_pending(current))
 				return -EAGAIN;
@@ -696,16 +697,10 @@ static int snd_gf1_pcm_playback_close(sn
 	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	gus_pcm_private_t *pcmp = runtime->private_data;
-	unsigned long jiffies_old;
+	
+	if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ))
+		snd_printk("gf1 pcm - serious DMA problem\n");
 
-	jiffies_old = jiffies;
-	while (atomic_read(&pcmp->dma_count) > 0) {
-		interruptible_sleep_on_timeout(&pcmp->sleep, 1);
-		if ((signed long)(jiffies - jiffies_old) > 2*HZ) {
-			snd_printk("gf1 pcm - serious DMA problem\n");
-			break;
-		}
-	}
 	snd_gf1_dma_done(gus);	
 	return 0;
 }
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
--- a/sound/isa/gus/gus_reset.c
+++ b/sound/isa/gus/gus_reset.c
@@ -207,7 +207,6 @@ void snd_gf1_stop_voices(snd_gus_card_t 
 	unsigned long flags;
 	short i, ramp_ok;
 	unsigned short ramp_end;
-	long time;
 
 	if (!in_interrupt()) {	/* this can't be done in interrupt */
 		for (i = v_min, ramp_ok = 0; i <= v_max; i++) {
@@ -227,11 +226,7 @@ void snd_gf1_stop_voices(snd_gus_card_t 
 			}
 			spin_unlock_irqrestore(&gus->reg_lock, flags);
 		}
-		time = HZ / 20;
-		while (time > 0 && !signal_pending(current)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			time = schedule_timeout(time);
-		}
+		msleep_interruptible(50);
 	}
 	snd_gf1_clear_voices(gus, v_min, v_max);
 }
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
--- a/sound/isa/gus/gus_synth.c
+++ b/sound/isa/gus/gus_synth.c
@@ -214,7 +214,7 @@ static int snd_gus_synth_new_device(snd_
 	snd_gus_card_t *gus;
 	int client, i;
 	snd_seq_client_callback_t callbacks;
-	snd_seq_client_info_t cinfo;
+	snd_seq_client_info_t *cinfo;
 	snd_seq_port_subscribe_t sub;
 	snd_iwffff_ops_t *iwops;
 	snd_gf1_ops_t *gf1ops;
@@ -227,21 +227,28 @@ static int snd_gus_synth_new_device(snd_
 	init_MUTEX(&gus->register_mutex);
 	gus->gf1.seq_client = -1;
 	
+	cinfo = kmalloc(sizeof(*cinfo), GFP_KERNEL);
+	if (! cinfo)
+		return -ENOMEM;
+
 	/* allocate new client */
 	memset(&callbacks, 0, sizeof(callbacks));
 	callbacks.private_data = gus;
 	callbacks.allow_output = callbacks.allow_input = 1;
 	client = gus->gf1.seq_client =
 			snd_seq_create_kernel_client(gus->card, 1, &callbacks);
-	if (client < 0)
+	if (client < 0) {
+		kfree(cinfo);
 		return client;
+	}
 
 	/* change name of client */
-	memset(&cinfo, 0, sizeof(cinfo));
-	cinfo.client = client;
-	cinfo.type = KERNEL_CLIENT;
-	sprintf(cinfo.name, gus->interwave ? "AMD InterWave" : "GF1");
-	snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
+	memset(cinfo, 0, sizeof(*cinfo));
+	cinfo->client = client;
+	cinfo->type = KERNEL_CLIENT;
+	sprintf(cinfo->name, gus->interwave ? "AMD InterWave" : "GF1");
+	snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, cinfo);
+	kfree(cinfo);
 
 	for (i = 0; i < 4; i++)
 		snd_gus_synth_create_port(gus, i);
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -79,8 +79,10 @@ module_param_array(id, charp, NULL, 0444
 MODULE_PARM_DESC(id, "ID string for InterWave soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable InterWave soundcard.");
+#ifdef CONFIG_PNP
 module_param_array(isapnp, bool, NULL, 0444);
 MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
+#endif
 module_param_array(port, long, NULL, 0444);
 MODULE_PARM_DESC(port, "Port # for InterWave driver.");
 #ifdef SNDRV_STB
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -529,7 +529,7 @@ static int __init snd_opl3sa2_mixer(opl3
 
 /* Power Management support functions */
 #ifdef CONFIG_PM
-static int snd_opl3sa2_suspend(snd_card_t *card, unsigned int state)
+static int snd_opl3sa2_suspend(snd_card_t *card, pm_message_t state)
 {
 	opl3sa2_t *chip = card->pm_private_data;
 
@@ -542,7 +542,7 @@ static int snd_opl3sa2_suspend(snd_card_
 	return 0;
 }
 
-static int snd_opl3sa2_resume(snd_card_t *card, unsigned int state)
+static int snd_opl3sa2_resume(snd_card_t *card)
 {
 	opl3sa2_t *chip = card->pm_private_data;
 	int i;
@@ -787,7 +787,7 @@ static int __devinit snd_opl3sa2_pnp_det
         int res;
 
         for ( ; dev < SNDRV_CARDS; dev++) {
-                if (!enable[dev] && !isapnp[dev])
+                if (!enable[dev] || !isapnp[dev])
                         continue;
                 res = snd_opl3sa2_probe(dev, card, id);
                 if (res < 0)
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -25,6 +25,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/emu8000.h>
 #include <sound/emu8000_reg.h>
@@ -355,8 +356,7 @@ init_arrays(emu8000_t *emu)
 {
 	send_array(emu, init1, ARRAY_SIZE(init1)/4);
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout((HZ * (44099 + 1024)) / 44100); /* wait for 1024 clocks */
+	msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
 	send_array(emu, init2, ARRAY_SIZE(init2)/4);
 	send_array(emu, init3, ARRAY_SIZE(init3)/4);
 
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -183,10 +183,10 @@ snd_emu8000_sample_new(snd_emux_t *rec, 
 	}
 
 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
-		if (verify_area(VERIFY_READ, data, sp->v.size))
+		if (!access_ok(VERIFY_READ, data, sp->v.size))
 			return -EFAULT;
 	} else {
-		if (verify_area(VERIFY_READ, data, sp->v.size * 2))
+		if (!access_ok(VERIFY_READ, data, sp->v.size * 2))
 			return -EFAULT;
 	}
 
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -46,20 +46,16 @@ irqreturn_t snd_sb8dsp_midi_interrupt(sb
 		inb(SBP(chip, DATA_AVAIL));	/* ack interrupt */
 		return IRQ_NONE;
 	}
+	spin_lock(&chip->midi_input_lock);
 	while (max-- > 0) {
-		spin_lock(&chip->midi_input_lock);
 		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
 			byte = inb(SBP(chip, READ));
 			if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {
-				spin_unlock(&chip->midi_input_lock);
 				snd_rawmidi_receive(chip->midi_substream_input, &byte, 1);
-			} else {
-				spin_unlock(&chip->midi_input_lock);
 			}
-		} else {
-			spin_unlock(&chip->midi_input_lock);
 		}
 	}
+	spin_unlock(&chip->midi_input_lock);
 	return IRQ_HANDLED;
 }
 
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -413,8 +413,8 @@ snd_wavefront_midi_interrupt (snd_wavefr
 		return;
 	}
 
+	spin_lock_irqsave (&midi->virtual, flags);
 	while (--max) {
-		spin_lock_irqsave (&midi->virtual, flags);
 
 		if (input_avail (midi)) {
 			byte = read_data (midi);
@@ -433,21 +433,17 @@ snd_wavefront_midi_interrupt (snd_wavefr
 			}
 
 			if (substream == NULL) {
-				spin_unlock_irqrestore (&midi->virtual, flags);
 				continue;
 			}
 
 			if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
-				spin_unlock_irqrestore (&midi->virtual, flags);
 				snd_rawmidi_receive(substream, &byte, 1);
-			} else {
-				spin_unlock_irqrestore (&midi->virtual, flags);
 			}
 		} else {
-			spin_unlock_irqrestore (&midi->virtual, flags);
 			break;
 		}
 	} 
+	spin_unlock_irqrestore (&midi->virtual, flags);
 
 	snd_wavefront_midi_output_write(card);
 }
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1201,7 +1201,11 @@ wavefront_send_multisample (snd_wavefron
 {
 	int i;
 	int num_samples;
-	unsigned char msample_hdr[WF_MSAMPLE_BYTES];
+	unsigned char *msample_hdr;
+
+	msample_hdr = kmalloc(sizeof(WF_MSAMPLE_BYTES), GFP_KERNEL);
+	if (! msample_hdr)
+		return -ENOMEM;
 
 	munge_int32 (header->number, &msample_hdr[0], 2);
 
@@ -1234,11 +1238,13 @@ wavefront_send_multisample (snd_wavefron
 			   (unsigned char *) (long) ((num_samples*2)+3),
 			   msample_hdr)) {
 		snd_printk ("download of multisample failed.\n");
+		kfree(msample_hdr);
 		return -(EIO);
 	}
 
 	dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
 
+	kfree(msample_hdr);
 	return (0);
 }
 
@@ -1356,78 +1362,103 @@ wavefront_find_free_patch (snd_wavefront
 
 static int
 wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr)
-
 {
-	wavefront_patch_info header;
+	wavefront_patch_info *header;
+	int err;
 	
-	if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
+	header = kmalloc(sizeof(*header), GFP_KERNEL);
+	if (! header)
+		return -ENOMEM;
+
+	if (copy_from_user (header, addr, sizeof(wavefront_patch_info) -
 			    sizeof(wavefront_any))) {
 		snd_printk ("bad address for load patch.\n");
-		return -(EFAULT);
+		err = -EFAULT;
+		goto __error;
 	}
 
 	DPRINT (WF_DEBUG_LOAD_PATCH, "download "
 				      "Sample type: %d "
 				      "Sample number: %d "
 				      "Sample size: %d\n",
-				      header.subkey,
-				      header.number,
-				      header.size);
+				      header->subkey,
+				      header->number,
+				      header->size);
 
-	switch (header.subkey) {
+	switch (header->subkey) {
 	case WF_ST_SAMPLE:  /* sample or sample_header, based on patch->size */
 
-		if (copy_from_user (&header.hdr.s, header.hdrptr,
-				    sizeof (wavefront_sample)))
-			return -EFAULT;
+		if (copy_from_user (&header->hdr.s, header->hdrptr,
+				    sizeof (wavefront_sample))) {
+			err = -EFAULT;
+			break;
+		}
 
-		return wavefront_send_sample (dev, &header, header.dataptr, 0);
+		err = wavefront_send_sample (dev, header, header->dataptr, 0);
+		break;
 
 	case WF_ST_MULTISAMPLE:
 
-		if (copy_from_user (&header.hdr.s, header.hdrptr,
-				    sizeof (wavefront_multisample)))
-			return -EFAULT;
-
-		return wavefront_send_multisample (dev, &header);
+		if (copy_from_user (&header->hdr.s, header->hdrptr,
+				    sizeof (wavefront_multisample))) {
+			err = -EFAULT;
+			break;
+		}
 
+		err = wavefront_send_multisample (dev, header);
+		break;
 
 	case WF_ST_ALIAS:
 
-		if (copy_from_user (&header.hdr.a, header.hdrptr,
-				    sizeof (wavefront_alias)))
-			return -EFAULT;
+		if (copy_from_user (&header->hdr.a, header->hdrptr,
+				    sizeof (wavefront_alias))) {
+			err = -EFAULT;
+			break;
+		}
 
-		return wavefront_send_alias (dev, &header);
+		err = wavefront_send_alias (dev, header);
+		break;
 
 	case WF_ST_DRUM:
-		if (copy_from_user (&header.hdr.d, header.hdrptr,
-				    sizeof (wavefront_drum)))
-			return -EFAULT;
+		if (copy_from_user (&header->hdr.d, header->hdrptr,
+				    sizeof (wavefront_drum))) {
+			err = -EFAULT;
+			break;
+		}
 
-		return wavefront_send_drum (dev, &header);
+		err = wavefront_send_drum (dev, header);
+		break;
 
 	case WF_ST_PATCH:
-		if (copy_from_user (&header.hdr.p, header.hdrptr,
-				    sizeof (wavefront_patch)))
-			return -EFAULT;
-
-		return wavefront_send_patch (dev, &header);
+		if (copy_from_user (&header->hdr.p, header->hdrptr,
+				    sizeof (wavefront_patch))) {
+			err = -EFAULT;
+			break;
+		}
+		
+		err = wavefront_send_patch (dev, header);
+		break;
 
 	case WF_ST_PROGRAM:
-		if (copy_from_user (&header.hdr.pr, header.hdrptr,
-				    sizeof (wavefront_program)))
-			return -EFAULT;
+		if (copy_from_user (&header->hdr.pr, header->hdrptr,
+				    sizeof (wavefront_program))) {
+			err = -EFAULT;
+			break;
+		}
 
-		return wavefront_send_program (dev, &header);
+		err = wavefront_send_program (dev, header);
+		break;
 
 	default:
 		snd_printk ("unknown patch type %d.\n",
-			    header.subkey);
-		return -(EINVAL);
+			    header->subkey);
+		err = -EINVAL;
+		break;
 	}
 
-	return 0;
+ __error:
+	kfree(header);
+	return err;
 }
 
 /***********************************************************************
@@ -1620,8 +1651,9 @@ snd_wavefront_synth_ioctl (snd_hwdep_t *
 	snd_card_t *card;
 	snd_wavefront_t *dev;
 	snd_wavefront_card_t *acard;
-	wavefront_control wc;
+	wavefront_control *wc;
 	void __user *argp = (void __user *)arg;
+	int err;
 
 	card = (snd_card_t *) hw->card;
 
@@ -1640,14 +1672,19 @@ snd_wavefront_synth_ioctl (snd_hwdep_t *
 		break;
 
 	case WFCTL_WFCMD:
-		if (copy_from_user (&wc, argp, sizeof (wc)))
-			return -EFAULT;
-		if (wavefront_synth_control (acard, &wc) < 0) {
-			return -EIO;
-		}
-		if (copy_to_user (argp, &wc, sizeof (wc)))
-			return -EFAULT;
-		break;
+		wc = kmalloc(sizeof(*wc), GFP_KERNEL);
+		if (! wc)
+			return -ENOMEM;
+		if (copy_from_user (wc, argp, sizeof (*wc)))
+			err = -EFAULT;
+		else if (wavefront_synth_control (acard, wc) < 0)
+			err = -EIO;
+		else if (copy_to_user (argp, wc, sizeof (*wc)))
+			err = -EFAULT;
+		else
+			err = 0;
+		kfree(wc);
+		return err;
 
 	default:
 		return -EINVAL;
@@ -1751,6 +1788,7 @@ wavefront_should_cause_interrupt (snd_wa
 	outb (val,port);
 	spin_unlock_irq(&dev->irq_lock);
 	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if ((timeout = schedule_timeout(timeout)) == 0)
 			return;
 		if (dev->irq_ok)
@@ -1942,7 +1980,7 @@ wavefront_download_firmware (snd_wavefro
 	fs = get_fs();
 	set_fs (get_ds());
 
-	if ((fd = sys_open (path, 0, 0)) < 0) {
+	if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) {
 		snd_printk ("Unable to load \"%s\".\n",
 			path);
 		return 1;
@@ -1951,7 +1989,7 @@ wavefront_download_firmware (snd_wavefro
 	while (1) {
 		int x;
 
-		if ((x = sys_read (fd, &section_length, sizeof (section_length))) !=
+		if ((x = sys_read (fd, (char __user *) &section_length, sizeof (section_length))) !=
 		    sizeof (section_length)) {
 			snd_printk ("firmware read error.\n");
 			goto failure;
@@ -1967,7 +2005,7 @@ wavefront_download_firmware (snd_wavefro
 			goto failure;
 		}
 
-		if (sys_read (fd, section, section_length) != section_length) {
+		if (sys_read (fd, (char __user *) section, section_length) != section_length) {
 			snd_printk ("firmware section "
 				"read error.\n");
 			goto failure;
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A
 
 config SOUND_ES1370
 	tristate "Ensoniq AudioPCI (ES1370)"
-	depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT
+	depends on SOUND_PRIME!=n && SOUND && PCI
 	help
 	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
 	  ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
@@ -125,7 +125,7 @@ config SOUND_ES1370
 
 config SOUND_ES1371
 	tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-	depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT
+	depends on SOUND_PRIME!=n && SOUND && PCI
 	help
 	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
 	  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -138,7 +138,7 @@ config SOUND_ES1371
 
 config SOUND_ESSSOLO1
 	tristate "ESS Technology Solo1" 
-	depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT && PCI
+	depends on SOUND_PRIME!=n && SOUND && PCI
 	help
 	  Say Y or M if you have a PCI sound card utilizing the ESS Technology
 	  Solo1 chip. To find out if your sound card uses a
@@ -179,7 +179,7 @@ config SOUND_HARMONY
 
 config SOUND_SONICVIBES
 	tristate "S3 SonicVibes"
-	depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT
+	depends on SOUND_PRIME!=n && SOUND
 	help
 	  Say Y or M if you have a PCI sound card utilizing the S3
 	  SonicVibes chipset. To find out if your sound card uses a
@@ -226,7 +226,7 @@ config SOUND_AU1550_AC97
 
 config SOUND_TRIDENT
 	tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
-	depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT
+	depends on SOUND_PRIME!=n && SOUND
 	---help---
 	  Say Y or M if you have a PCI sound card utilizing the Trident
 	  4DWave-DX/NX chipset or your mother board chipset has SiS 7018
@@ -556,7 +556,7 @@ config SOUND_AD1816
 
 config SOUND_AD1889
 	tristate "AD1889 based cards (AD1819 codec) (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && SOUND_OSS
+	depends on EXPERIMENTAL && SOUND_OSS && PCI
 	help
 	  Say M here if you have a sound card based on the Analog Devices
 	  AD1889 chip.
@@ -739,7 +739,7 @@ config SOUND_NM256
 
 config SOUND_MAD16
 	tristate "OPTi MAD16 and/or Mozart based cards"
-	depends on SOUND_OSS && SOUND_GAMEPORT
+	depends on SOUND_OSS
 	---help---
 	  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
 	  82C928 or 82C929 or 82C931) audio interface chip. These chips are
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -71,6 +71,7 @@ static int wolfson_init03(struct ac97_co
 static int wolfson_init04(struct ac97_codec * codec);
 static int wolfson_init05(struct ac97_codec * codec);
 static int wolfson_init11(struct ac97_codec * codec);
+static int wolfson_init13(struct ac97_codec * codec);
 static int tritech_init(struct ac97_codec * codec);
 static int tritech_maestro_init(struct ac97_codec * codec);
 static int sigmatel_9708_init(struct ac97_codec *codec);
@@ -107,6 +108,7 @@ static struct ac97_ops wolfson_ops03 = {
 static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
 static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
 static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
+static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
 static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
 static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
 static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
@@ -153,6 +155,7 @@ static const struct {
 	{0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
 	{0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
 	{0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
+	{0x43585430, "CXT48",			&default_ops,		AC97_DELUDED_MODEM },
 	{0x43585442, "CXT66",			&default_ops,		AC97_DELUDED_MODEM },
 	{0x44543031, "Diamond Technology DT0893", &default_ops},
 	{0x45838308, "ESS Allegro ES1988",	&null_ops},
@@ -171,6 +174,7 @@ static const struct {
 	{0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
 	{0x574D4C09, "Wolfson WM9709",		&null_ops},
 	{0x574D4C12, "Wolfson WM9711/9712",	&wolfson_ops11},
+	{0x574D4C13, "Wolfson WM9713",	&wolfson_ops13, AC97_DEFAULT_POWER_OFF},
 	{0x83847600, "SigmaTel STAC????",	&null_ops},
 	{0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
 	{0x83847605, "SigmaTel STAC9704",	&null_ops},
@@ -798,6 +802,9 @@ EXPORT_SYMBOL(ac97_release_codec);
  *	Currently codec_wait is used to wait for AC97 codec
  *	reset to complete. 
  *
+ *     Some codecs will power down when a register reset is
+ *     performed. We now check for such codecs.
+ *
  *	Returns 1 (true) on success, or 0 (false) on failure.
  */
  
@@ -811,34 +818,17 @@ int ac97_probe_codec(struct ac97_codec *
 	struct list_head *l;
 	struct ac97_driver *d;
 	
-	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
-	 * be read zero.
-	 *
-	 * FIXME: is the following comment outdated?  -jgarzik 
-	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-	 */
-	codec->codec_write(codec, AC97_RESET, 0L);
-
-	/* also according to spec, we wait for codec-ready state */	
+	/* wait for codec-ready state */
 	if (codec->codec_wait)
 		codec->codec_wait(codec);
 	else
 		udelay(10);
 
-	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
-		       : (codec->id&1 ? "Secondary":  "Primary"));
-		return 0;
-	}
-
-	/* probe for Modem Codec */
-	codec->modem = ac97_check_modem(codec);
-	codec->name = NULL;
-	codec->codec_ops = &default_ops;
-
+	/* will the codec power down if register reset ? */
 	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+	codec->name = NULL;
+	codec->codec_ops = &null_ops;
 	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
 		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
 			codec->type = ac97_codec_ids[i].id;
@@ -850,9 +840,34 @@ int ac97_probe_codec(struct ac97_codec *
 	}
 
 	codec->model = (id1 << 16) | id2;
+	if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
+		/* reset codec and wait for the ready bit before we continue */
+		codec->codec_write(codec, AC97_RESET, 0L);
+		if (codec->codec_wait)
+			codec->codec_wait(codec);
+		else
+			udelay(10);
+	}
+
+	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
+	 * be read zero.
+	 *
+	 * FIXME: is the following comment outdated?  -jgarzik
+	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
+	 */
+	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
+		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
+		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
+		       : (codec->id&1 ? "Secondary":  "Primary"));
+		return 0;
+	}
 	
+	/* probe for Modem Codec */
+	codec->modem = ac97_check_modem(codec);
+
+	/* enable SPDIF */
 	f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if(f & 4)
+	if((codec->codec_ops == &null_ops) && (f & 4))
 		codec->codec_ops = &default_digital_ops;
 	
 	/* A device which thinks its a modem but isnt */
@@ -921,11 +936,6 @@ static int ac97_init_mixer(struct ac97_c
 	codec->recmask_io = ac97_recmask_io;
 	codec->mixer_ioctl = ac97_mixer_ioctl;
 
-	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
-	if (codec->codec_ops->init != NULL) {
-		codec->codec_ops->init(codec);
-	}
-
 	/* initialize mixer channel volumes */
 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
 		struct mixer_defaults *md = &mixer_defaults[i];
@@ -936,6 +946,11 @@ static int ac97_init_mixer(struct ac97_c
 		ac97_set_mixer(codec, md->mixer, md->value);
 	}
 
+	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
+	if (codec->codec_ops->init != NULL) {
+		codec->codec_ops->init(codec);
+	}
+
 	/*
 	 *	Volume is MUTE only on this device. We have to initialise
 	 *	it but its useless beyond that.
@@ -1091,6 +1106,19 @@ static int wolfson_init11(struct ac97_co
 	return 0;
 }
 
+/* WM9713 */
+static int wolfson_init13(struct ac97_codec * codec)
+{
+	codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
+	codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
+	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
+	codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
+	codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
+	codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
+
+	return 0;
+}
+
 static int tritech_init(struct ac97_codec * codec)
 {
 	codec->codec_write(codec, 0x26, 0x0300);
diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
--- a/sound/oss/ali5455.c
+++ b/sound/oss/ali5455.c
@@ -3528,7 +3528,7 @@ static void __devexit ali_remove(struct 
 }
 
 #ifdef CONFIG_PM
-static int ali_pm_suspend(struct pci_dev *dev, u32 pm_state)
+static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
 {
 	struct ali_card *card = pci_get_drvdata(dev);
 	struct ali_state *state;
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -558,7 +558,7 @@ static ssize_t btaudio_dsp_read(struct f
 			__s16 __user *dst = (__s16 __user *)(buffer + ret);
 			__s16 avg;
 			int n = ndst>>1;
-			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {
+			if (!access_ok(VERIFY_WRITE, dst, ndst)) {
 				if (0 == ret)
 					ret = -EFAULT;
 				break;
@@ -574,7 +574,7 @@ static ssize_t btaudio_dsp_read(struct f
 			__u8 *src = bta->buf_cpu + bta->read_offset;
 			__u8 __user *dst = buffer + ret;
 			int n = ndst;
-			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {
+			if (!access_ok(VERIFY_WRITE, dst, ndst)) {
 				if (0 == ret)
 					ret = -EFAULT;
 				break;
@@ -587,7 +587,7 @@ static ssize_t btaudio_dsp_read(struct f
 			__u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
 			__u16 __user *dst = (__u16 __user *)(buffer + ret);
 			int n = ndst>>1;
-			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {
+			if (!access_ok(VERIFY_WRITE,dst,ndst)) {
 				if (0 == ret)
 					ret = -EFAULT;
 				break;
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
--- a/sound/oss/cmpci.c
+++ b/sound/oss/cmpci.c
@@ -426,7 +426,7 @@ struct cm_state {
 	struct address_info mpu_data;
 #endif
 #ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	struct gameport gameport;
+	struct gameport *gameport;
 #endif
 
 	int	chip_version;
@@ -468,17 +468,17 @@ struct cm_state {
 
 static LIST_HEAD(devs);
 
-static	int	mpuio = 0;
-static	int	fmio = 0;
-static	int	joystick = 0;
-static	int	spdif_inverse = 0;
-static	int	spdif_loop = 0;
-static	int	spdif_out = 0;
-static	int	use_line_as_rear = 0;
-static	int	use_line_as_bass = 0;
-static	int	use_mic_as_bass = 0;
-static	int	mic_boost = 0;
-static	int	hw_copy = 0;
+static	int	mpuio;
+static	int	fmio;
+static	int	joystick;
+static	int	spdif_inverse;
+static	int	spdif_loop;
+static	int	spdif_out;
+static	int	use_line_as_rear;
+static	int	use_line_as_bass;
+static	int	use_mic_as_bass;
+static	int	mic_boost;
+static	int	hw_copy;
 module_param(mpuio, int, 0);
 module_param(fmio, int, 0);
 module_param(joystick, bool, 0);
@@ -2925,7 +2925,7 @@ static /*const*/ struct file_operations 
 static struct initvol {
 	int mixch;
 	int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
 	{ SOUND_MIXER_WRITE_CD, 0x4f4f },
 	{ SOUND_MIXER_WRITE_LINE, 0x4f4f },
 	{ SOUND_MIXER_WRITE_MIC, 0x4f4f },
@@ -2984,6 +2984,51 @@ static int query_chip(struct cm_state *s
 	return ChipVersion;
 }
 
+#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
+		printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
+		return -EBUSY;
+	}
+
+	if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
+		release_region(io_port, CM_EXTENT_GAME);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "C-Media GP");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	/* enable joystick */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void __devexit cm_free_gameport(struct cm_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+
+		gameport_unregister_port(s->gameport);
+		s->gameport = NULL;
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+		release_region(gpio, CM_EXTENT_GAME);
+	}
+}
+#else
+static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
+static inline void cm_free_gameport(struct cm_state *s) { }
+#endif
+
 #define	echo_option(x)\
 if (x) strcat(options, "" #x " ")
 
@@ -3229,22 +3274,11 @@ static int __devinit cm_probe(struct pci
 	}
 skip_mpu:
 #endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	/* enable joystick */
-	if (joystick) {
-		s->gameport.io = 0x200;
-		if (!request_region(s->gameport.io, CM_EXTENT_GAME, "cmpci GAME")) {
-			printk(KERN_ERR "cmpci: gameport io ports in use\n");
-			s->gameport.io = 0;
-	       	} else {
-			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-			gameport_register_port(&s->gameport);
-		}
-	} else {
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-		s->gameport.io = 0;
-	}
-#endif
+	/* disable joystick port */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+	if (joystick)
+		cm_create_gameport(s, 0x200);
+
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -3278,13 +3312,9 @@ static void __devexit cm_remove(struct p
 
 	if (!s)
 		return;
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, CM_EXTENT_GAME);
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-	}
-#endif
+
+	cm_free_gameport(s);
+
 #ifdef CONFIG_SOUND_CMPCI_FM
 	if (s->iosynth) {
 		/* disable FM */
diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c
--- a/sound/oss/cs4281/cs4281_wrapper-24.c
+++ b/sound/oss/cs4281/cs4281_wrapper-24.c
@@ -27,7 +27,7 @@
 #include <linux/spinlock.h>
 
 static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; }
-static int cs4281_suspend_null(struct pci_dev *pcidev, u32 state) { return 0; }
+static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; }
 
 #define free_dmabuf(state, dmabuf) \
 	pci_free_consistent(state->pcidev, \
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
--- a/sound/oss/cs4281/cs4281m.c
+++ b/sound/oss/cs4281/cs4281m.c
@@ -4096,7 +4096,7 @@ static /*const */ struct file_operations
 static struct initvol {
 	int mixch;
 	int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
 
 	{
 	SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -388,7 +388,7 @@ static int cs_hardware_init(struct cs_ca
 static int cs46xx_powerup(struct cs_card *card, unsigned int type);
 static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
 static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state);
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
 static int cs46xx_resume_tbl(struct pci_dev *pcidev);
 
 #ifndef CS46XX_ACPI_SUPPORT
@@ -3640,7 +3640,7 @@ static int cs46xx_restart_part(struct cs
 
 static void cs461x_reset(struct cs_card *card);
 static void cs461x_proc_stop(struct cs_card *card);
-static int cs46xx_suspend(struct cs_card *card, u32 state)
+static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
 {
 	unsigned int tmp;
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
@@ -5774,7 +5774,7 @@ static int cs46xx_pm_callback(struct pm_
 #endif
 
 #if CS46XX_ACPI_SUPPORT
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state)
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
 {
 	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
diff --git a/sound/oss/cs46xxpm-24.h b/sound/oss/cs46xxpm-24.h
--- a/sound/oss/cs46xxpm-24.h
+++ b/sound/oss/cs46xxpm-24.h
@@ -36,7 +36,7 @@
 * for now (12/22/00) only enable the pm_register PM support.
 * allow these table entries to be null.
 */
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state);
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
 static int cs46xx_resume_tbl(struct pci_dev *pcidev);
 #define cs_pm_register(a, b, c)  NULL
 #define cs_pm_unregister_all(a) 
diff --git a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c
--- a/sound/oss/dmasound/dac3550a.c
+++ b/sound/oss/dmasound/dac3550a.c
@@ -40,9 +40,6 @@ static int daca_attach_adapter(struct i2
 static int daca_detect_client(struct i2c_adapter *adapter, int address);
 static int daca_detach_client(struct i2c_client *client);
 
-/* Unique ID allocation */
-static int daca_id;
-
 struct i2c_driver daca_driver = {  
 	.owner			= THIS_MODULE,
 	.name			= "DAC3550A driver  V " DACA_VERSION,
@@ -176,7 +173,6 @@ static int daca_detect_client(struct i2c
 	new_client->driver = &daca_driver;
 	new_client->flags = 0;
 	strcpy(new_client->name, client_name);
-	new_client->id = daca_id++; /* racy... */
 
 	if (daca_init_client(new_client))
 		goto bail;
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -2987,10 +2987,13 @@ printk("dmasound_pmac: Awacs/Screamer Co
 
 	set_hw_byteswap(io) ; /* figure out if the h/w can do it */
 
-	/* get default volume from nvram
-	 * vol = (~nvram_read_byte(0x1308) & 7) << 1;
-	*/
+#ifdef CONFIG_NVRAM
+	/* get default volume from nvram */
 	vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
+#else
+	vol = 0;
+#endif
+
 	/* set up tracking values */
 	spk_vol = vol * 100 ;
 	spk_vol /= 7 ; /* get set value to a percentage */
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
--- a/sound/oss/es1370.c
+++ b/sound/oss/es1370.c
@@ -384,7 +384,7 @@ struct es1370_state {
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct semaphore sem;
 };
 
@@ -2540,7 +2540,7 @@ MODULE_LICENSE("GPL");
 static struct initvol {
 	int mixch;
 	int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
 	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
 	{ SOUND_MIXER_WRITE_PCM, 0x4040 },
 	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
@@ -2556,6 +2556,7 @@ static struct initvol {
 static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1370_state *s;
+	struct gameport *gp = NULL;
 	mm_segment_t fs;
 	int i, val, ret;
 
@@ -2604,12 +2605,17 @@ static int __devinit es1370_probe(struct
 	/* note: setting CTRL_SERR_DIS is reported to break
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
 	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-	s->gameport.io = 0;
-	if (!request_region(0x200, JOY_EXTENT, "es1370"))
+	if (!request_region(0x200, JOY_EXTENT, "es1370")) {
 		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-	else {
+	} else if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
+		release_region(0x200, JOY_EXTENT);
+	} else {
+		gameport_set_name(gp, "ESS1370");
+		gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+		gp->dev.parent = &s->dev->dev;
+		gp->io = 0x200;
 		s->ctrl |= CTRL_JYSTK_EN;
-		s->gameport.io = 0x200;
 	}
 	if (lineout[devindex])
 		s->ctrl |= CTRL_XCTL0;
@@ -2665,9 +2671,10 @@ static int __devinit es1370_probe(struct
 		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
 	}
 	set_fs(fs);
+
 	/* register gameport */
-	if (s->gameport.io)
-		gameport_register_port(&s->gameport);
+	if (gp)
+		gameport_register_port(gp);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
@@ -2689,8 +2696,10 @@ static int __devinit es1370_probe(struct
  err_dev1:
 	printk(KERN_ERR "es1370: cannot register misc device\n");
 	free_irq(s->irq, s);
-	if (s->gameport.io)
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		release_region(s->gameport->io, JOY_EXTENT);
+		gameport_free_port(s->gameport);
+	}
  err_irq:
 	release_region(s->io, ES1370_EXTENT);
  err_region:
@@ -2709,9 +2718,10 @@ static void __devexit es1370_remove(stru
 	outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
 	}
 	release_region(s->io, ES1370_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -453,7 +453,7 @@ struct es1371_state {
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct semaphore sem;
 };
 
@@ -2786,12 +2786,12 @@ static struct
 	{ PCI_ANY_ID, PCI_ANY_ID }
 };
 
-
 static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1371_state *s;
+	struct gameport *gp;
 	mm_segment_t fs;
-	int i, val, res = -1;
+	int i, gpio, val, res = -1;
 	int idx;
 	unsigned long tmo;
 	signed long tmo2;
@@ -2849,8 +2849,8 @@ static int __devinit es1371_probe(struct
 		printk(KERN_ERR PFX "irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u joystick %#x\n",
-	       s->rev, s->io, s->irq, s->gameport.io);
+	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n",
+	       s->rev, s->io, s->irq);
 	/* register devices */
 	if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1)))<0)
 		goto err_dev1;
@@ -2881,16 +2881,23 @@ static int __devinit es1371_probe(struct
                     	printk(KERN_INFO PFX "Enabling internal amplifier.\n");
 		}
 	}
-	s->gameport.io = 0;
-	for (i = 0x218; i >= 0x200; i -= 0x08) {
-		if (request_region(i, JOY_EXTENT, "es1371")) {
-			s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-			s->gameport.io = i;
+
+	for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
+		if (request_region(gpio, JOY_EXTENT, "es1371"))
 			break;
-		}
-	}
-	if (!s->gameport.io)
+
+	if (gpio < 0x200) {
 		printk(KERN_ERR PFX "no free joystick address found\n");
+	} else if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR PFX "can not allocate memory for gameport\n");
+		release_region(gpio, JOY_EXTENT);
+	} else {
+		gameport_set_name(gp, "ESS1371 Gameport");
+		gameport_set_phys(gp, "isa%04x/gameport0", gpio);
+		gp->dev.parent = &s->dev->dev;
+		gp->io = gpio;
+		s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+	}
 
 	s->sctrl = 0;
 	cssr = 0;
@@ -2960,9 +2967,11 @@ static int __devinit es1371_probe(struct
 	set_fs(fs);
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
+
 	/* register gameport */
-	if (s->gameport.io)
-		gameport_register_port(&s->gameport);
+	if (s->gameport)
+		gameport_register_port(s->gameport);
+
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2973,8 +2982,10 @@ static int __devinit es1371_probe(struct
        	return 0;
 
  err_gp:
-	if (s->gameport.io)
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		release_region(s->gameport->io, JOY_EXTENT);
+		gameport_free_port(s->gameport);
+	}
 #ifdef ES1371_DEBUG
 	if (s->ps)
 		remove_proc_entry("es1371", NULL);
@@ -3013,9 +3024,10 @@ static void __devexit es1371_remove(stru
 	outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
 	}
 	release_region(s->io, ES1371_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -226,7 +226,7 @@ struct solo1_state {
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -2193,7 +2193,7 @@ static /*const*/ struct file_operations 
 static struct initvol {
 	int mixch;
 	int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
 	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
 	{ SOUND_MIXER_WRITE_PCM, 0x4040 },
 	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
@@ -2257,7 +2257,7 @@ static int setup_solo1(struct solo1_stat
 }
 
 static int
-solo1_suspend(struct pci_dev *pci_dev, u32 state) {
+solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
 	struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
 	if (!s)
 		return 1;
@@ -2280,9 +2280,36 @@ solo1_resume(struct pci_dev *pci_dev) {
 	return 0;
 }
 
+static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
+		printk(KERN_ERR "solo1: gameport io ports are in use\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
+		release_region(io_port, GAMEPORT_EXTENT);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ESS Solo1 Gameport");
+	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct solo1_state *s;
+	int gpio;
 	int ret;
 
  	if ((ret=pci_enable_device(pcidev)))
@@ -2323,7 +2350,7 @@ static int __devinit solo1_probe(struct 
 	s->vcbase = pci_resource_start(pcidev, 2);
 	s->ddmabase = s->vcbase + DDMABASE_OFFSET;
 	s->mpubase = pci_resource_start(pcidev, 3);
-	s->gameport.io = pci_resource_start(pcidev, 4);
+	gpio = pci_resource_start(pcidev, 4);
 	s->irq = pcidev->irq;
 	ret = -EBUSY;
 	if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
@@ -2342,15 +2369,10 @@ static int __devinit solo1_probe(struct 
 		printk(KERN_ERR "solo1: io ports in use\n");
 		goto err_region4;
 	}
-	if (s->gameport.io && !request_region(s->gameport.io, GAMEPORT_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: gameport io ports in use\n");
-		s->gameport.io = 0;
-	}
 	if ((ret=request_irq(s->irq,solo1_interrupt,SA_SHIRQ,"ESS Solo1",s))) {
 		printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1);
 	/* register devices */
 	if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
 		ret = s->dev_audio;
@@ -2373,7 +2395,7 @@ static int __devinit solo1_probe(struct 
 		goto err;
 	}
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	solo1_register_gameport(s, gpio);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	return 0;
@@ -2390,8 +2412,6 @@ static int __devinit solo1_probe(struct 
 	printk(KERN_ERR "solo1: initialisation error\n");
 	free_irq(s->irq, s);
  err_irq:
-	if (s->gameport.io)
-		release_region(s->gameport.io, GAMEPORT_EXTENT);
 	release_region(s->mpubase, MPUBASE_EXTENT);
  err_region4:
 	release_region(s->ddmabase, DDMABASE_EXTENT);
@@ -2417,9 +2437,10 @@ static void __devexit solo1_remove(struc
 	synchronize_irq(s->irq);
 	pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, GAMEPORT_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, GAMEPORT_EXTENT);
 	}
 	release_region(s->iobase, IOBASE_EXTENT);
 	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
--- a/sound/oss/gus_wave.c
+++ b/sound/oss/gus_wave.c
@@ -3126,8 +3126,7 @@ void __exit gus_wave_unload(struct addre
 	if (hw_config->slots[5] != -1)
 		sound_unload_mixerdev(hw_config->slots[5]);
 	
-	if(samples)
-		vfree(samples);
+	vfree(samples);
 	samples=NULL;
 }
 /* called in interrupt context */
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
--- a/sound/oss/harmony.c
+++ b/sound/oss/harmony.c
@@ -310,7 +310,7 @@ static int harmony_detect_rate(int *freq
 	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 5512:	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; 
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
--- a/sound/oss/i810_audio.c
+++ b/sound/oss/i810_audio.c
@@ -3470,7 +3470,7 @@ static void __devexit i810_remove(struct
 }
 
 #ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, u32 pm_state)
+static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
 {
         struct i810_card *card = pci_get_drvdata(dev);
         struct i810_state *state;
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
--- a/sound/oss/mad16.c
+++ b/sound/oss/mad16.c
@@ -52,7 +52,7 @@
 
 static int      mad16_conf;
 static int      mad16_cdsel;
-static struct gameport gameport;
+static struct gameport *gameport;
 static DEFINE_SPINLOCK(lock);
 
 #define C928	1
@@ -902,7 +902,30 @@ static int __initdata irq_map[16] =
 	-1, -1, -1, -1
 };
 
-static int __init init_mad16(void)
+static int __devinit mad16_register_gameport(int io_port)
+{
+	if (!request_region(io_port, 1, "mad16 gameport")) {
+		printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
+		return -EBUSY;
+	}
+
+	gameport = gameport_allocate_port();
+	if (!gameport) {
+		printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
+		release_region(io_port, 1);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gameport, "MAD16 Gameport");
+	gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
+	gameport->io = io_port;
+
+	gameport_register_port(gameport);
+
+	return 0;
+}
+
+static int __devinit init_mad16(void)
 {
 	int dmatype = 0;
 
@@ -1027,17 +1050,9 @@ static int __init init_mad16(void)
 
 	found_mpu = probe_mad16_mpu(&cfg_mpu);
 
-	if (joystick == 1) {
-		/* register gameport */
-		if (!request_region(0x201, 1, "mad16 gameport"))
-			printk(KERN_ERR "mad16: gameport address 0x201 already in use\n");
-		else {
-			printk(KERN_ERR "mad16: gameport enabled at 0x201\n");
-			gameport.io = 0x201;
-			gameport_register_port(&gameport);
-		}
-	}
-	else printk(KERN_ERR "mad16: gameport disabled.\n");
+	if (joystick)
+		mad16_register_gameport(0x201);
+
 	return 0;
 }
 
@@ -1045,10 +1060,10 @@ static void __exit cleanup_mad16(void)
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
-	if (gameport.io) {
+	if (gameport) {
 		/* the gameport was initialized so we must free it up */
-		gameport_unregister_port(&gameport);
-		gameport.io = 0;
+		gameport_unregister_port(gameport);
+		gameport = NULL;
 		release_region(0x201, 1);
 	}
 	unload_mad16(&cfg);
diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
--- a/sound/oss/maestro3.c
+++ b/sound/oss/maestro3.c
@@ -375,7 +375,7 @@ static struct m3_card *devs;
  * I'm not very good at laying out functions in a file :)
  */
 static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static int m3_suspend(struct pci_dev *pci_dev, u32 state);
+static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state);
 static void check_suspend(struct m3_card *card);
 
 static struct notifier_block m3_reboot_nb = {
@@ -2777,12 +2777,12 @@ static int m3_notifier(struct notifier_b
 
     for(card = devs; card != NULL; card = card->next) {
         if(!card->in_suspend)
-            m3_suspend(card->pcidev, 3); /* XXX legal? */
+            m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */
     }
     return 0;
 }
 
-static int m3_suspend(struct pci_dev *pci_dev, u32 state)
+static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
     unsigned long flags;
     int i;
diff --git a/sound/oss/maestro_tables.h b/sound/oss/maestro_tables.h
deleted file mode 100644
--- a/sound/oss/maestro_tables.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/* 
- *	Set up data block for the ESS soundblaster emulation. This is like
- *	the example code from ftp.esstech.com.tw  (104T31.ZIP)
- */
-
-u16 asp_block_0[]= {
-	0x7980, 0x003a, 0x7980, 0x007d, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 
-	0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 
-	0x7980, 0x0be6, 0x7980, 0x0069, 0xbe3a, 0x8b00, 0x8048, 0x6945, 
-	0xb801, 0x9045, 0x6941, 0xe388, 0x0031, 0x6944, 0xba50, 0xe38c, 
-	0x0031, 0x8b88, 0x6942, 0x304a, 0xe308, 0x0028, 0x6949, 0x9042, 
-	0x0042, 0xafa0, 0x8000, 0xafa0, 0x8000, 0x8042, 0x6944, 0xb801, 
-	0x9044, 0x0048, 0xbe3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0xbe41, 0xbf80, 0x0101, 0x8806, 0x8804, 0xb912, 
-	0x8807, 0xbc26, 0xbe40, 0xb92f, 0x9001, 0x9002, 0x003b, 0x0122, 
-	0x7a88, 0x0055, 0x003a, 0x013c, 0x7a88, 0x0055, 0x4902, 0xe100, 
-	0x0800, 0x0c02, 0xa000, 0x7980, 0x004e, 0xb908, 0x8809, 0xbec6, 
-	0x0067, 0x4a80, 0xe200, 0x0065, 0x4880, 0xe200, 0x0063, 0xb97f, 
-	0x6e80, 0x7980, 0x0066, 0x1089, 0x9088, 0xb900, 0x90a9, 0x8ba8, 
-	0xef00, 0x803d, 0x0003, 0x1007, 0x881f, 0x8b88, 0xbb0f, 0xada0, 
-	0x0810, 0x9003, 0x4903, 0xe200, 0x007b, 0x9002, 0x6a05, 0x6d04, 
-	0x9803, 0x9804, 0x9005, 0x003d, 0xbe3a, 0xaf06, 0x0000, 0x803d, 
-	0x8b88, 0x6906, 0x8810, 0xaf06, 0x0001, 0xbfb0, 0x00ff, 0xbaf5, 
-	0xe3cc, 0x009a, 0x5e06, 0x003f, 0xbf80, 0x0080, 0x4a06, 0xe200, 
-	0x0095, 0x6e80, 0x6d06, 0x7980, 0x009b, 0x9080, 0x0810, 0xba46, 
-	0x8810, 0x8b00, 0x1006, 0x9080, 0x003d, 0xbe3a, 0x1024, 0x2009, 
-	0x8810, 0x8b88, 0x8b00, 0x1089, 0xbfb0, 0x000e, 0xbe0a, 0x880d, 
-	0x903e, 0x1038, 0x2008, 0x8810, 0x1037, 0x2008, 0x8811, 0x5f3e, 
-	0x0000, 0x8b00, 0xf500, 0x5e80, 0xfffe, 0x1039, 0x2008, 0x8815, 
-	0x8b8d, 0x0231, 0x0333, 0x108a, 0x90ad, 0x1025, 0x200a, 0x8815, 
-	0x0605, 0xb91f, 0x8809, 0x4f16, 0x1080, 0xf600, 0xbfb0, 
-	0x0003, 0xbfb0, 0x0007, 0x9089, 0xbe47, 0xbe43, 0xbec6, 
-	0x00f6, 0x4f8b, 0x14a8, 0xe500, 0x6380, 0x8b89, 0x4e8a, 
-	0xbfe3, 0xe500, 0x2480, 0xbe46, 0x8b9d, 0xbfe7, 0xbfb0, 
-	0x00ff, 0x288c, 0x2026, 0x8814, 0xbe47, 0x8b00, 0x738f, 
-	0x54aa, 0xbe03, 0xbe0a, 0x2fa8, 0x988a, 0x8da9, 0xbe03, 
-	0x4d8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe03, 
-	0x4c8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe42, 
-	0x1039, 0x2008, 0x8815, 0x8b8d, 0x8b00, 0x8d8a, 0x7980, 
-	0x0bcf};
-
-u16 asp_block_1[]={
-	0x0005, 0xb900, 0x9008, 0x9009, 0x900a, 0xbb3f, 0x90a0,
-	0x001a, 0x011b, 0x021c, 0x0323, 0x1089, 0x9015, 0x108a,
-	0x9016, 0x108b, 0x9017, 0x1088, 0x9018, 0x0137, 0x0524, 
-	0x8b8d, 0x4f16, 0xe200, 0x0827, 0x4f15, 0xe200, 0x0827, 
-	0x7a80, 0x08e6, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb900, 
-	0x90a0, 0x908d, 0x7980, 0x0833, 0x7a80, 0x0913, 0x7803, 
-	0x7a80, 0x0913, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb903, 
-	0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 0x0845, 0x4e15, 
-	0xe200, 0x0845, 0x7a80, 0x08e6, 0x102c, 0xb806, 0x8813, 
-	0x8b8b, 0xb901, 0x90a0, 0x908d, 0x7980, 0x0851, 0x7a80, 
-	0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb806, 0x8813, 
-	0x8b8b, 0xb904, 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 
-	0x0863, 0x4d15, 0xe200, 0x0863, 0x7a80, 0x08e6, 0x102c, 
-	0xb80a, 0x8813, 0x8b8b, 0xb902, 0x90a0, 0x908d, 0x7980, 
-	0x086f, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 
-	0xb80a, 0x8813, 0x8b8b, 0xb905, 0x90a0, 0x908d, 0x7801, 
-	0x7a80, 0x0913, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, 
-	0x0913, 0x1024, 0xbf90, 0x0100, 0x8815, 0x4f16, 0xe200, 
-	0x088e, 0x4c15, 0xe200, 0x088e, 0x7a80, 0x08e6, 0x102c, 
-	0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0100, 0x90a0, 0x908d, 
-	0x7980, 0x089b, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 
-	0x102c, 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0103, 0x90a0, 
-	0x908d, 0x7c02, 0x4f16, 0xe200, 0x08ae, 0x4b15, 0xe200, 
-	0x08ae, 0x7a80, 0x08e6, 0x102c, 0xb818, 0x8813, 0x8b8b, 
-	0xbf80, 0x0101, 0x90a0, 0x908d, 0x7980, 0x08bb, 0x7a80, 
-	0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb818, 0x8813, 
-	0x8b8b, 0xbf80, 0x0104, 0x90a0, 0x908d, 0x7c02, 0x4f16, 
-	0xe200, 0x08ce, 0x4a15, 0xe200, 0x08ce, 0x7a80, 0x08e6, 
-	0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0102, 0x90a0, 
-	0x908d, 0x7980, 0x08db, 0x7a80, 0x0913, 0x7803, 0x7a80, 
-	0x0913, 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0105, 
-	0x90a0, 0x908d, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, 
-	0x0913, 0x7801, 0x7a80, 0x0913, 0x7980, 0x0920, 0x4f80, 
-	0x7803, 0xe100, 0x08fe, 0x4f89, 0xe100, 0x08f5, 0xb901, 
-	0x90a0, 0xb902, 0x90a0, 0x90a0, 0xb906, 0x90ad, 0xef00, 
-	0xb901, 0x90a0, 0xb906, 0x90a0, 0xb900, 0x90a0, 0xb906, 
-	0x90ad, 0xef00, 0x4f89, 0xe100, 0x090a, 0xb905, 0x90a0, 
-	0xb900, 0x90a0, 0xb902, 0x90a0, 0xb906, 0x90ad, 0xef00, 
-	0xb905, 0x90a0, 0xb900, 0x90a0, 0xb906, 0x90a0, 0xb904, 
-	0x90ad, 0xef00, 0x4f89, 0xe100, 0x091b, 0xb901, 0x90a0, 
-	0xb906, 0x90ad, 0xef00, 0xb905, 0x90a0, 0xb904, 0x90ad, 
-	0xef00, 0xb91f, 0x8809, 0x0034, 0x8b88, 0xbec6, 0x0932, 
-	0x1313, 0xbe1e, 0x1014, 0xbe1a, 0xbe01, 0xbfe8, 0xbe17, 
-	0x6a13, 0x6214, 0xbe14, 0x9813, 0x9014, 0x98a0, 0xbe47, 
-	0x5f0f, 0x002e, 0xe200, 0x093d, 0xbf80, 0xffd2, 0x900f, 
-	0x7980, 0x0940, 0x100f, 0xb801, 0x900f, 0x400f, 0x8b00, 
-	0xe500, 0xbe01, 0xbe09, 0x9010, 0xbe46, 0x5f11, 0x003f, 
-	0xe200, 0x094f, 0xb900, 0x9011, 0x7980, 0x0952, 0x1011, 
-	0xb801, 0x9011, 0x1001, 0xe388, 0x0bcf, 0x1021, 0x2009, 
-	0x8813, 0x8b8b, 0x8b00, 0x1080, 0xbfe6, 0x7810, 0x8b00, 
-	0x8b00, 0x2180, 0xbfb0, 0x0007, 0x4c11, 0x8b00, 0xe100, 
-	0x096c, 0x4b11, 0x8b00, 0xe600, 0xb900, 0x7980, 0x096d, 
-	0xbe0a, 0x4a11, 0x8b00, 0xe500, 0xbe01, 0x9012, 0x1037, 
-	0x2008, 0x8811, 0x102e, 0x2008, 0x8812, 0x4a89, 0xb901, 
-	0xe500, 0x9019, 0xe100, 0x09c9, 0xb900, 0x9019, 0x4a18, 
-	0xe200, 0x09c9, 0x5f0a, 0x0010, 0xe200, 0x098d, 0x4b18, 
-	0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0013, 
-	0xe200, 0x0997, 0x4b18, 0xb901, 0xe500, 0x9019, 0x7980, 
-	0x09c9, 0x5f0a, 0x0011, 0xe200, 0x09a4, 0x4f18, 0xb905, 
-	0xe500, 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 
-	0x5f0a, 0x0014, 0xe200, 0x09b1, 0x4c18, 0xb904, 0xe500, 
-	0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 
-	0x0012, 0xe200, 0x09be, 0x4d18, 0xb905, 0xe500, 0x9080, 
-	0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0015, 
-	0xe200, 0x09c9, 0x4e18, 0xb904, 0xe500, 0x9080, 0xb901, 
-	0xe500, 0x9019, 0x8b8a, 0x4f19, 0xe200, 0x09d4, 0x4b80, 
-	0xe200, 0x09d6, 0x5d80, 0x0020, 0x7980, 0x09d9, 0x5d80, 
-	0x0010, 0x4a80, 0xe200, 0x0bca, 0x1001, 0xba01, 0x9001, 
-	0x1024, 0x2009, 0x8815, 0x8b89, 0x4d8d, 0xe200, 0x09f8, 
-	0x4f16, 0xe100, 0x09ed, 0x8b89, 0x1080, 0xbfc0, 0x000c, 
-	0x908c, 0x7980, 0x09f8, 0x4b89, 0x108d, 0xf600, 0xbfb0, 
-	0x0003, 0x4a89, 0x8b00, 0xf500, 0xbfc0, 0x0008, 0x908c, 
-	0x1022, 0x2009, 0x8811, 0x102e, 0x2008, 0x8812, 0x102f, 
-	0x2008, 0x8813, 0x1020, 0x200a, 0x8814, 0x101d, 0x200a, 
-	0x8815, 0x8b8a, 0x4f19, 0xe100, 0x0a11, 0x5e80, 0x0020, 
-	0x5d80, 0x0018, 0x7980, 0x0a3e, 0x4f80, 0xe200, 0x0a1e, 
-	0x8b8b, 0x108a, 0xbfa0, 0x7fc0, 0x8b00, 0xf704, 0x5c80, 
-	0x0003, 0x7980, 0x0a3e, 0x4e80, 0xe200, 0x0a36, 0x8b8c, 
-	0x178b, 0xbe01, 0xbfb7, 0x00f0, 0x308a, 0xe344, 0x0a3e, 
-	0x8b8d, 0x4a8a, 0x8b00, 0xe200, 0x0a32, 0x5c80, 0x0006, 
-	0x7980, 0x0a3e, 0x5c80, 0x000a, 0x7980, 0x0a3e, 0x4c80,
-	0xe200, 0x0a3e, 0x4b80, 0x8b00, 0xf500, 0x5c80, 0x0019, 
-	0x4f80, 0xe200, 0x0a4d, 0x101f, 0x200a, 0x8816, 0x8b00, 
-	0x8b00, 0x8b8e, 0x1780, 0xbfb7, 0x00f0, 0x900b, 0x7980, 
-	0x0a64, 0x4e80, 0xe200, 0x0a5c, 0x101f, 0x200a, 0x8816, 
-	0x8b00, 0x8b00, 0x8b8e, 0x1b80, 0xbfbb, 0x000f, 0x900b, 
-	0x7980, 0x0a64, 0x4c80, 0xe200, 0x0a64, 0x8b8c, 0x1b80, 
-	0xbfbb, 0x000f, 0x900b, 0x8b89, 0x1880, 0xbfb8, 0x001c, 
-	0x4917, 0xe100, 0x0a6e, 0x4f80, 0x7980, 0x0a70, 0x4e80, 
-	0x8b00, 0xf500, 0xbf98, 0x0002, 0x8b8d, 0x4b89, 0x8b00, 
-	0xe600, 0xbfe1, 0x903e, 0xbe43, 0x6a0b, 0x613e, 0xbfe8, 
-	0x980c, 0xbe42, 0x7c10, 0x1080, 0xbfe5, 0xbe1e, 0x7810, 
-	0x1280, 0xbfb2, 0x001f, 0xbe11, 0x2027, 0x8811, 0x101e, 
-	0x200a, 0x8816, 0x8b00, 0x128e, 0x4980, 0xe100, 0x0a9b, 
-	0x4880, 0xe100, 0x0a98, 0xb900, 0x7980, 0x0a9f, 0xbe0a, 
-	0x7980, 0x0a9f, 0x4880, 0xe200, 0x0a9f, 0xbe09, 0xbe1e, 
-	0x158d, 0xbfb5, 0x003f, 0xbe11, 0x4889, 0xe200, 0x0aae, 
-	0xbe1e, 0x1010, 0x4818, 0x8b00, 0xe600, 0xbfe1, 0xbe11, 
-	0xbfe1, 0x8811, 0xbe1e, 0xb9ff, 0x8819, 0x8b00, 0x8b00, 
-	0xbf46, 0x8b00, 0xe600, 0xbe1f, 0xbe01, 0xbfb0, 0x00ff, 
-	0x202a, 0x8811, 0x8b00, 0x8b00, 0x108a, 0x900d, 0xb91f, 
-	0x8809, 0x0732, 0x730d, 0x4f80, 0xe200, 0x0ad8, 0x1028, 
-	0x200c, 0x8815, 0xbe43, 0x8b8b, 0x6a8d, 0xbec6, 0x0ad4, 
-	0x618b, 0x9880, 0x548f, 0x8dad, 0xbe42, 0x7980, 0x0b24, 
-	0x4e80, 0xe200, 0x0af9, 0x8b8c, 0x178b, 0xbe01, 0xbfb7, 
-	0x00f0, 0x903e, 0x1029, 0x200c, 0x8815, 0x108d, 0xbec6, 
-	0x0af6, 0x308b, 0xbe1e, 0x303e, 0x903f, 0x403f, 0xbe1f, 
-	0xe500, 0x103e, 0x9080, 0xbfe6, 0x202a, 0x8811, 0x8b00, 
-	0x1089, 0x548f, 0x8dad, 0x7980, 0x0b24, 0x4c8b, 0xe200, 
-	0x0b1b, 0x1029, 0x200c, 0x8815, 0xbf80, 0x007f, 0x903e, 
-	0x108d, 0xbec6, 0x0b14, 0x308b, 0xbe1e, 0x303e, 0x903f, 
-	0x403f, 0xbe1f, 0xe500, 0xb900, 0x9080, 0xbfe6, 0x202a, 
-	0x8811, 0x8b00, 0x1089, 0x548f, 0x8dad, 0x8b8a, 0xf500, 
-	0x5e80, 0xffdf, 0x7980, 0x0b24, 0x1089, 0xbfe6, 0x202a, 
-	0x8811, 0x8b00, 0x8b00, 0x548f, 0xbb1f, 0x8da0, 0x8b8f, 
-	0x0732, 0x1021, 0x2009, 0x8811, 0x8b89, 0x101d, 0x200a, 
-	0x8812, 0x1080, 0x7810, 0x8b00, 0xbe47, 0x288a, 0xbfb0, 
-	0x03ff, 0x4989, 0xe200, 0x0b3e, 0xbe1e, 0x1012, 0x4918, 
-	0x8b00, 0xe600, 0xbe0a, 0xbe11, 0x900e, 0xbe46, 0x108a, 
-	0xbfb0, 0x001c, 0xbfe1, 0x880d, 0x8b00, 0x6b0e, 0xbe0a, 
-	0x880c, 0x108c, 0xbfb0, 0x000f, 0x202d, 0x8814, 0x8b00, 
-	0x8b00, 0x5589, 0xbf03, 0x8c0e, 0xbf00, 0x1030, 0x2008, 
-	0x8811, 0xb91f, 0x8809, 0x108b, 0x0333, 0xbec6, 0x0b5f, 
-	0x200e, 0x90a0, 0x8b00, 0x8b89, 0x9080, 0x4a18, 0xe200, 
-	0x0b7a, 0x5f0a, 0x0011, 0xe200, 0x0b6c, 0x4f18, 0xe900, 
-	0x0b7c, 0x5f0a, 0x0014, 0xe200, 0x0b73, 0x4c18, 0xe900, 
-	0x0b9b, 0x5f0a, 0x0015, 0xe200, 0x0b7a, 0x4e18, 0xe900, 
-	0x0bb2, 0x7980, 0x009e, 0x0034, 0xb91f, 0x8809, 0x0333, 
-	0x8b8b, 0xbec6, 0x0b99, 0x1280, 0x6c80, 0xbfea, 0xbe1e, 
-	0x1580, 0x6c88, 0xbfec, 0xbe13, 0x903e, 0x6cab, 0x903f, 
-	0x4f3e, 0xb900, 0xf500, 0xbf80, 0x8000, 0x4f3f, 0xbf90, 
-	0x0d00, 0xf500, 0xbf90, 0x2700, 0x90a0, 0xef00, 0x0034, 
-	0xb91f, 0x8809, 0x0333, 0x8b88, 0xbec6, 0x0bb0, 0x1eab, 
-	0x6c80, 0xbfed, 0x903e, 0x4180, 0xb900, 0xf500, 0xbf80, 
-	0x8000, 0x4f3e, 0x8b00, 0xf500, 0xbf90, 0x4000, 0x90a8, 
-	0xef00, 0x0034, 0xb91f, 0x8809, 0x0333, 0x8b8b, 0xbec6, 
-	0x0bc8, 0x1280, 0x6c8b, 0xbfea, 0xbe1e, 0x1580, 0x6c80, 
-	0xbfec, 0xbe13, 0x903e, 0x4f3e, 0xbf80, 0x4000, 0xf500, 
-	0xbf90, 0x8000, 0x90a0, 0xef00, 0x0231, 0x8b8a, 0xb900, 
-	0xbb20, 0x90a0, 0x5f08, 0x0023, 0xe100, 0x0043, 0x1008, 
-	0xb801, 0x9008, 0x102b, 0x2008, 0x8812, 0x8b00, 0x8b00, 
-	0x1080, 0x900a, 0x102c, 0x2008, 0x8812, 0x8b00, 0x8b00, 
-	0x1080, 0x9009, 0x7980, 0x0952, 0x8148, 0x6946, 0xb801, 
-	0x9046, 0xb901, 0x9041, 0x6944, 0xba08, 0xe344, 0x0bfe, 
-	0x9044, 0x8b89, 0x0143, 0x694b, 0x881f, 0xbb0f, 0xada0, 
-	0x8143, 0x0811, 0x304a, 0xe308, 0x0bfe, 0x6949, 0x9043,
-	0x0148, 0xbe3a 
-}; 
-	
-u16 asp_block_2[]={ 
-	0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, 
-	0x0004, 0x0004, 0x0002, 0x0002, 0x0005, 0x0005, 
-	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 
-	0x0100, 0x0100, 0x0103, 0x0103, 0x0101, 0x0101, 
-	0x0104, 0x0104, 0x0102, 0x0102, 0x0105, 0x0105, 
-	0x0106, 0x0106, 0x0107, 0x0107, 0x0108, 0x0108
-};
-
-u16 asp_block_3[]={ 
-	0x0000, 0x0000, 0x0000, 0x1200, 0x1200, 0x1280, 0x0000, 0x05d0, 
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0000, 0x1104, 0x1105, 0x1008, 0x1020, 0x1040, 0x1060, 
-	0x1080, 0x10a0, 0x10b0, 0x100d, 0x1010, 0x10e0, 0x2000, 0x2980, 
-	0x2b00, 0x2b40, 0x2a00, 0x2b90, 0x13dc, 0x2b80, 0x11bc, 0x134c, 
-	0x1370, 0x12e0, 0x1240, 0x1260, 0x12c0, 0x009e, 0x0045, 0x10bc, 
-	0x1394, 0x13b8, 0x11f6, 0x10f6, 0x11b0, 0x0000, 0x0000, 0x0000, 
-	0x0000, 0x0815, 0x0956, 0x09df, 0x0be5, 0x0a19, 0x0a48, 0x0b37,
-	0x0b5d, 0x0a8b, 0x0aae, 0x0ad2 }; 
-
-
-u16 asp_block_4[] = {
-	0x0192, 0x04b6, 0x07d9, 0x0afb, 0x0e1c, 0x113a, 0x1455, 0x176e,
-	0x1a83, 0x1d93, 0x209f, 0x23a7, 0x26a8, 0x29a4, 0x2c99, 0x2f87,
-	0x326e, 0x354e, 0x3825, 0x3af3, 0x3db8, 0x4074, 0x4326, 0x45cd,
-	0x486a, 0x4afb, 0x4d81, 0x4ffb, 0x5269, 0x54ca, 0x571e, 0x5964,
-	0x5b9d, 0x5dc8, 0x5fe4, 0x61f1, 0x63ef, 0x65de, 0x67bd, 0x698c,
-	0x6b4b, 0x6cf9, 0x6e97, 0x7023, 0x719e, 0x7308, 0x7460, 0x75a6,
-	0x76d9, 0x77fb, 0x790a, 0x7a06, 0x7aef, 0x7bc6, 0x7c89, 0x7d3a,
-	0x7dd6, 0x7e60, 0x7ed6, 0x7f38, 0x7f87, 0x7fc2, 0x7fea, 0x7ffe,
-	0x7ffe, 0x7fea, 0x7fc2, 0x7f87, 0x7f38, 0x7ed6, 0x7e60, 0x7dd6,
-	0x7d3a, 0x7c89, 0x7bc6, 0x7aef, 0x7a06, 0x790a, 0x77fb, 0x76d9,
-	0x75a6, 0x7460, 0x7308, 0x719e, 0x7023, 0x6e97, 0x6cf9, 0x6b4b,
-	0x698c, 0x67bd, 0x65de, 0x63ef, 0x61f1, 0x5fe4, 0x5dc8, 0x5b9d,
-	0x5964, 0x571e, 0x54ca, 0x5269, 0x4ffb, 0x4d81, 0x4afb, 0x486a,
-	0x45cd, 0x4326, 0x4074, 0x3db8, 0x3af3, 0x3825, 0x354e, 0x326e,
-	0x2f87, 0x2c99, 0x29a4, 0x26a8, 0x23a7, 0x209f, 0x1d93, 0x1a83,
-	0x176e, 0x1455, 0x113a, 0x0e1c, 0x0afb, 0x07d9, 0x04b6, 0x0192,
-	0xfe6f, 0xfb4b, 0xf828, 0xf506, 0xf1e5, 0xeec7, 0xebac, 0xe893,
-	0xe57e, 0xe26e, 0xdf62, 0xdc5a, 0xd959, 0xd65d, 0xd368, 0xd07a,
-	0xcd93, 0xcab3, 0xc7dc, 0xc50e, 0xc249, 0xbf8d, 0xbcdb, 0xba34,
-	0xb797, 0xb506, 0xb280, 0xb006, 0xad98, 0xab37, 0xa8e3, 0xa69d,
-	0xa464, 0xa239, 0xa01d, 0x9e10, 0x9c12, 0x9a23, 0x9844, 0x9675,
-	0x94b6, 0x9308, 0x916a, 0x8fde, 0x8e63, 0x8cf9, 0x8ba1, 0x8a5b,
-	0x8928, 0x8806, 0x86f7, 0x85fb, 0x8512, 0x843b, 0x8378, 0x82c7,
-	0x822b, 0x81a1, 0x812b, 0x80c9, 0x807a, 0x803f, 0x8017, 0x8003,
-	0x8003, 0x8017, 0x803f, 0x807a, 0x80c9, 0x812b, 0x81a1, 0x822b,
-	0x82c7, 0x8378, 0x843b, 0x8512, 0x85fb, 0x86f7, 0x8806, 0x8928,
-	0x8a5b, 0x8ba1, 0x8cf9, 0x8e63, 0x8fde, 0x916a, 0x9308, 0x94b6,
-	0x9675, 0x9844, 0x9a23, 0x9c12, 0x9e10, 0xa01d, 0xa239, 0xa464,
-	0xa69d, 0xa8e3, 0xab37, 0xad98, 0xb006, 0xb280, 0xb506, 0xb797,
-	0xba34, 0xbcdb, 0xbf8d, 0xc249, 0xc50e, 0xc7dc, 0xcab3, 0xcd93,
-	0xd07a, 0xd368, 0xd65d, 0xd959, 0xdc5a, 0xdf62, 0xe26e, 0xe57e,
-	0xe893, 0xebac, 0xeec7, 0xf1e5, 0xf506, 0xf828, 0xfb4b, 0xfe6f,
-	0x7cc3, 0x725e, 0x68d5, 0x6017, 0x5813, 0x50b9, 0x49fb, 0x43cd,
-	0x3e22, 0x38ef, 0x342b, 0x2fcc, 0x2bc9, 0x281c, 0x24be, 0x21a6,
-	0x1ed1, 0x1c37, 0x19d5, 0x17a6, 0x15a5, 0x13ce, 0x121f, 0x1093,
-	0x0f28, 0x0ddc, 0x0cab, 0x0b93, 0x0a92, 0x09a7, 0x08cf, 0x080a,
-	0x0754, 0x06ae, 0x0615, 0x0589, 0x0509, 0x0494, 0x0428, 0x03c5,
-	0x036a, 0x0317, 0x02cb, 0x0285, 0x0245, 0x020a, 0x01d4, 0x01a2,
-	0x0175, 0x014b, 0x0125, 0x0102, 0x00e2, 0x00c5, 0x00aa, 0x0091,
-	0x007b, 0x0066, 0x0053, 0x0041, 0x0031, 0x0022, 0x0015, 0x0009,
-	0xfffe, 0xfff2, 0xffe5, 0xffd7, 0xffc8, 0xffb7, 0xffa5, 0xff91,
-	0xff7b, 0xff64, 0xff4a, 0xff2e, 0xff0f, 0xfeee, 0xfec9, 0xfea1,
-	0xfe76, 0xfe46, 0xfe13, 0xfdda, 0xfd9d, 0xfd5a, 0xfd11, 0xfcc1,
-	0xfc6b, 0xfc0c, 0xfba5, 0xfb34, 0xfab9, 0xfa33, 0xf9a1, 0xf902,
-	0xf854, 0xf797, 0xf6c8, 0xf5e7, 0xf4f1, 0xf3e5, 0xf2c1, 0xf183,
-	0xf027, 0xeeac, 0xed0f, 0xeb4d, 0xe961, 0xe74a, 0xe501, 0xe284,
-	0xdfcd, 0xdcd8, 0xd99d, 0xd618, 0xd242, 0xce12, 0xc982, 0xc487,
-	0xbf1a, 0xb92e, 0xb2ba, 0xabaf, 0xa402, 0x9ba3, 0x9282, 0x888d,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x000a, 0x000e,
-	0x0010, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, 0x0020,
-	0x0000, 0x0000, 0x0000, 0x000a, 0x0010, 0x0016, 0x001a, 0x001e,
-	0x0020, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030,
-	0x0000, 0x0000, 0x0010, 0x001a, 0x0020, 0x0026, 0x002a, 0x002e,
-	0x0030, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e, 0x0040,
-	0x0000, 0x0010, 0x0020, 0x002a, 0x0030, 0x0036, 0x003a, 0x003e,
-	0x0040, 0x0044, 0x0046, 0x0048, 0x004a, 0x004c, 0x004e, 0x0050,
-	0x0000, 0x0020, 0x0030, 0x003a, 0x0040, 0x0046, 0x004a, 0x004e,
-	0x0050, 0x0054, 0x0056, 0x0058, 0x005a, 0x005c, 0x005e, 0x0060,
-	0x0000, 0x0030, 0x0040, 0x004a, 0x0050, 0x0056, 0x005a, 0x005e,
-	0x0060, 0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070,
-	0x0008, 0x0021, 0x0042, 0x0064, 0x0086, 0x00a8, 0x00cb, 0x00ee,
-	0x0111, 0x0135, 0x0158, 0x017d, 0x01a1, 0x01c6, 0x01eb, 0x0211,
-	0x0236, 0x025d, 0x0283, 0x02aa, 0x02d1, 0x02f9, 0x0321, 0x0349,
-	0x0372, 0x039b, 0x03c4, 0x03ee, 0x0418, 0x0442, 0x046d, 0x0499,
-	0x04c4, 0x04f0, 0x051d, 0x054a, 0x0577, 0x05a5, 0x05d3, 0x0601,
-	0x0630, 0x0660, 0x0690, 0x06c0, 0x06f1, 0x0722, 0x0753, 0x0785,
-	0x07b8, 0x07eb, 0x081e, 0x0852, 0x0886, 0x08bb, 0x08f0, 0x0926,
-	0x095c, 0x0993, 0x09ca, 0x0a02, 0x0a3a, 0x0a73, 0x0aac, 0x0ae6,
-	0x0b20, 0x0b5b, 0x0b96, 0x0bd2, 0x0c0e, 0x0c4b, 0x0c89, 0x0cc7,
-	0x0d05, 0x0d44, 0x0d84, 0x0dc5, 0x0e05, 0x0e47, 0x0e89, 0x0ecc,
-	0x0f0f, 0x0f53, 0x0f97, 0x0fdd, 0x1022, 0x1069, 0x10b0, 0x10f7,
-	0x1140, 0x1189, 0x11d2, 0x121c, 0x1267, 0x12b3, 0x12ff, 0x134c,
-	0x139a, 0x13e8, 0x1438, 0x1487, 0x14d8, 0x1529, 0x157b, 0x15ce,
-	0x1621, 0x1676, 0x16cb, 0x1720, 0x1777, 0x17ce, 0x1826, 0x187f,
-	0x18d9, 0x1934, 0x198f, 0x19eb, 0x1a48, 0x1aa6, 0x1b05, 0x1b64,
-	0x1bc5, 0x1c26, 0x1c88, 0x1ceb, 0x1d4f, 0x1db4, 0x1e1a, 0x1e80,
-	0x1ee8, 0x1f51, 0x1fba, 0x2025, 0x2090, 0x20fc, 0x216a, 0x21d8,
-	0x2247, 0x22b8, 0x2329, 0x239b, 0x240f, 0x2483, 0x24f9, 0x256f,
-	0x25e7, 0x2660, 0x26da, 0x2755, 0x27d1, 0x284e, 0x28cc, 0x294b,
-	0x29cc, 0x2a4e, 0x2ad1, 0x2b55, 0x2bda, 0x2c61, 0x2ce8, 0x2d71,
-	0x2dfb, 0x2e87, 0x2f13, 0x2fa1, 0x3031, 0x30c1, 0x3153, 0x31e6,
-	0x327b, 0x3310, 0x33a8, 0x3440, 0x34da, 0x3575, 0x3612, 0x36b0,
-	0x3750, 0x37f1, 0x3893, 0x3937, 0x39dc, 0x3a83, 0x3b2c, 0x3bd6,
-	0x3c81, 0x3d2e, 0x3ddd, 0x3e8d, 0x3f3f, 0x3ff2, 0x40a7, 0x415d,
-	0x4216, 0x42d0, 0x438b, 0x4448, 0x4507, 0x45c8, 0x468b, 0x474f,
-	0x4815, 0x48dd, 0x49a6, 0x4a72, 0x4b3f, 0x4c0e, 0x4cdf, 0x4db2,
-	0x4e87, 0x4f5d, 0x5036, 0x5111, 0x51ed, 0x52cc, 0x53ac, 0x548f,
-	0x5573, 0x565a, 0x5743, 0x582e, 0x591b, 0x5a0a, 0x5afb, 0x5bef,
-	0x5ce4, 0x5ddc, 0x5ed7, 0x5fd3, 0x60d2, 0x61d3, 0x62d6, 0x63dc,
-	0x64e4, 0x65ee, 0x66fb, 0x680a, 0x691c, 0x6a30, 0x6b47, 0x6c60,
-	0x6d7c, 0x6e9a, 0x6fbb, 0x70de, 0x7204, 0x732d, 0x7459, 0x7587,
-	0x76b8, 0x77eb, 0x7922, 0x7a5b, 0x7b97, 0x7cd6, 0x7e18, 0x7f5d,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0002, 0x0002, 0x0003,
-	0x0003, 0x0004, 0x0004, 0x0005, 0x0006, 0x0008, 0x0009, 0x000a,
-	0x000c, 0x0010, 0x0012, 0x0015, 0x0019, 0x0022, 0x0024, 0x002a,
-	0x0031, 0x003e, 0x0049, 0x0055, 0x0062, 0x007c, 0x0092, 0x00a9,
-	0x00c4, 0x00fc, 0x0125, 0x0152, 0x0187, 0x01f2, 0x024a, 0x02a4,
-	0x030d, 0x03e3, 0x0492, 0x0547, 0x061b, 0x07c7, 0x0923, 0x0a8d,
-	0x0c19, 0x0eb3, 0x1228, 0x14c1, 0x17fb, 0x1d17, 0x22f2, 0x2835,
-	0x2dd4, 0x3cd0, 0x4cf5, 0x51cc, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
-	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001,
-	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002,
-	0x0002, 0x0003, 0x0004, 0x0005, 0x0005, 0x0007, 0x0008, 0x000a,
-	0x000b, 0x000e, 0x0011, 0x0014, 0x0017, 0x001c, 0x0022, 0x0028,
-	0x002e, 0x0039, 0x0045, 0x0050, 0x005c, 0x0073, 0x008a, 0x00a0,
-	0x00b9, 0x00e7, 0x0114, 0x0141, 0x0172, 0x01ce, 0x0228, 0x0283,
-	0x02e3, 0x039b, 0x0454, 0x0501, 0x05bf, 0x072a, 0x0899, 0x0a18,
-	0x0b7e, 0x0e55, 0x10d3, 0x1404, 0x16c3, 0x16c3, 0x16c3, 0x16c3,
-	0x0012, 0x0024, 0x0048, 0x006c, 0x0090, 0x00b4, 0x00d8, 0x00fc,
-	0x0120, 0x0144, 0x0168, 0x0168, 0x01b0, 0x01b0, 0x021c, 0x021c,
-	0x0000, 0x0003, 0x0008, 0x000b, 0x0001, 0x0004, 0x0009, 0x000c,
-	0x0002, 0x0005, 0x000a, 0x000d, 0x0010, 0x0013, 0x0011, 0x0014,
-	0x0012, 0x0015, 0x0100, 0x0103, 0x0108, 0x010b, 0x0101, 0x0104,
-	0x0109, 0x010c, 0x0102, 0x0105, 0x010a, 0x010d, 0x0110, 0x0113,
-	0x0111, 0x0114, 0x0112, 0x0115 };
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -892,7 +892,7 @@ static __inline__ int pack_DAPF_to_DAPQ(
 static int dsp_read(char __user *buf, size_t len)
 {
 	int count = len;
-	char *page = (char *)__get_free_page(PAGE_SIZE);
+	char *page = (char *)__get_free_page(GFP_KERNEL);
 
 	if (!page)
 		return -ENOMEM;
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
--- a/sound/oss/nm256_audio.c
+++ b/sound/oss/nm256_audio.c
@@ -1047,7 +1047,7 @@ nm256_peek_for_sig (struct nm256_info *c
  * VERSTR is a human-readable version string.
  */
 
-static int __init
+static int __devinit
 nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
 {
     struct nm256_info *card;
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
--- a/sound/oss/opl3sa2.c
+++ b/sound/oss/opl3sa2.c
@@ -199,7 +199,7 @@ module_param(mpu_io, int, 0);
 MODULE_PARM_DESC(mpu_io, "Set MIDI I/O base (0x330 or other. Address must be even and must be from 0x300 to 0x334)");
 
 module_param(irq, int, 0);
-MODULE_PARM_DESC(mss_irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)");
+MODULE_PARM_DESC(irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)");
 
 module_param(dma, int, 0);
 MODULE_PARM_DESC(dma, "Set MSS (audio) first DMA channel (0, 1, 3)");
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -1149,7 +1149,7 @@ static int mss_irq __initdata	= -1;
 static int mss_dma __initdata	= -1;
 static int mpu_io __initdata	= -1;
 static int mpu_irq __initdata	= -1;
-static int pss_no_sound __initdata = 0;	/* Just configure non-sound components */
+static int pss_no_sound = 0;	/* Just configure non-sound components */
 static int pss_keep_settings  = 1;	/* Keep hardware settings at module exit */
 static char *pss_firmware = "/etc/sound/pss_synth";
 
diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c
--- a/sound/oss/sb_card.c
+++ b/sound/oss/sb_card.c
@@ -26,9 +26,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif /* CONFIG_MCA */
 #include "sound_config.h"
 #include "sb_mixer.h"
 #include "sb.h"
@@ -289,6 +286,7 @@ static struct pnp_card_driver sb_pnp_dri
 	.probe         = sb_pnp_probe,
 	.remove        = sb_pnp_remove,
 };
+MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table);
 #endif /* CONFIG_PNP */
 
 static int __init sb_init(void)
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
--- a/sound/oss/sonicvibes.c
+++ b/sound/oss/sonicvibes.c
@@ -365,7 +365,7 @@ struct sv_state {
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -1149,7 +1149,7 @@ static int mixer_ioctl(struct sv_state *
 			if (mixtable[i].rec)
 				break;
 		}
-		if (!mixtable[i].rec)
+		if (i == SOUND_MIXER_NRDEVICES)
 			return 0;
 		spin_lock_irqsave(&s->lock, flags);
 		frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5);
@@ -2485,12 +2485,39 @@ static struct initvol {
 #define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
 				 (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
 
+static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
+		printk(KERN_ERR "sv: gameport io ports are in use\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "sv: can not allocate memory for gameport\n");
+		release_region(io_port, SV_EXTENT_GAME);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "S3 SonicVibes Gameport");
+	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
        	struct sv_state *s;
 	mm_segment_t fs;
 	int i, val, ret;
+	int gpio;
 	char *ddmaname;
 	unsigned ddmanamelen;
 
@@ -2546,11 +2573,11 @@ static int __devinit sv_probe(struct pci
 	s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
 	s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
 	s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
-	s->gameport.io = pci_resource_start(pcidev, RESOURCE_GAME);
+	gpio = pci_resource_start(pcidev, RESOURCE_GAME);
 	pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
 	pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
 	printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
-	       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->gameport.io, s->iodmaa, s->iodmac);
+	       s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
 	s->irq = pcidev->irq;
 	
 	/* hack */
@@ -2577,10 +2604,7 @@ static int __devinit sv_probe(struct pci
 		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
 		goto err_region1;
 	}
-	if (s->gameport.io && !request_region(s->gameport.io, SV_EXTENT_GAME, "ESS Solo1")) {
-		printk(KERN_ERR "sv: gameport io ports in use\n");
-		s->gameport.io = 0;
-	}
+
 	/* initialize codec registers */
 	outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
 	udelay(50);
@@ -2639,7 +2663,7 @@ static int __devinit sv_probe(struct pci
 	}
 	set_fs(fs);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	sv_register_gameport(s, gpio);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2659,8 +2683,6 @@ static int __devinit sv_probe(struct pci
 	printk(KERN_ERR "sv: cannot register misc device\n");
 	free_irq(s->irq, s);
  err_irq:
-	if (s->gameport.io)
-		release_region(s->gameport.io, SV_EXTENT_GAME);
 	release_region(s->iosynth, SV_EXTENT_SYNTH);
  err_region1:
 	release_region(s->iomidi, SV_EXTENT_MIDI);
@@ -2689,9 +2711,10 @@ static void __devexit sv_remove(struct p
 	/*outb(0, s->iodmaa + SV_DMA_RESET);*/
 	/*outb(0, s->iodmac + SV_DMA_RESET);*/
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, SV_EXTENT_GAME);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, SV_EXTENT_GAME);
 	}
 	release_region(s->iodmac, SV_EXTENT_DMA);
 	release_region(s->iodmaa, SV_EXTENT_DMA);
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -329,7 +329,7 @@ static int sound_mixer_ioctl(int mixdev,
 static int sound_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-	int err, len = 0, dtype;
+	int len = 0, dtype;
 	int dev = iminor(inode);
 	void __user *p = (void __user *)arg;
 
@@ -341,11 +341,11 @@ static int sound_ioctl(struct inode *ino
 		if (len < 1 || len > 65536 || !p)
 			return -EFAULT;
 		if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-			if ((err = verify_area(VERIFY_READ, p, len)) < 0)
-				return err;
+			if (!access_ok(VERIFY_READ, p, len))
+				return -EFAULT;
 		if (_SIOC_DIR(cmd) & _SIOC_READ)
-			if ((err = verify_area(VERIFY_WRITE, p, len)) < 0)
-				return err;
+			if (!access_ok(VERIFY_WRITE, p, len))
+				return -EFAULT;
 	}
 	DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 	if (cmd == OSS_GETVERSION)
diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
--- a/sound/oss/sscape.c
+++ b/sound/oss/sscape.c
@@ -1393,7 +1393,7 @@ static struct address_info cfg;
 static struct address_info cfg_mpu;
 
 static int __initdata spea = -1;
-static int __initdata mss = 0;
+static int mss = 0;
 static int __initdata dma = -1;
 static int __initdata irq = -1;
 static int __initdata io = -1;
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -441,7 +441,7 @@ struct trident_card {
 	struct timer_list timer;
 
 	/* Game port support */
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 enum dmabuf_mode {
@@ -487,7 +487,7 @@ static struct trident_channel *ali_alloc
 static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
 static void ali_restore_regs(struct trident_card *card);
 static void ali_save_regs(struct trident_card *card);
-static int trident_suspend(struct pci_dev *dev, u32 unused);
+static int trident_suspend(struct pci_dev *dev, pm_message_t unused);
 static int trident_resume(struct pci_dev *dev);
 static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
 static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
@@ -3723,7 +3723,7 @@ ali_restore_regs(struct trident_card *ca
 }
 
 static int
-trident_suspend(struct pci_dev *dev, u32 unused)
+trident_suspend(struct pci_dev *dev, pm_message_t unused)
 {
 	struct trident_card *card = pci_get_drvdata(dev);
 
@@ -4257,21 +4257,21 @@ trident_ac97_init(struct trident_card *c
 static unsigned char
 trident_game_read(struct gameport *gameport)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	return inb(TRID_REG(card, T4D_GAME_LEG));
 }
 
 static void
 trident_game_trigger(struct gameport *gameport)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	outb(0xff, TRID_REG(card, T4D_GAME_LEG));
 }
 
 static int
 trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	int i;
 
 	*buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
@@ -4288,7 +4288,7 @@ trident_game_cooked_read(struct gameport
 static int
 trident_game_open(struct gameport *gameport, int mode)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 
 	switch (mode) {
 	case GAMEPORT_MODE_COOKED:
@@ -4305,6 +4305,31 @@ trident_game_open(struct gameport *gamep
 	return 0;
 }
 
+static int __devinit
+trident_register_gameport(struct trident_card *card)
+{
+	struct gameport *gp;
+
+	card->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "trident: can not allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "Trident 4DWave");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(card->pci_dev));
+	gp->read = trident_game_read;
+	gp->trigger = trident_game_trigger;
+	gp->cooked_read = trident_game_cooked_read;
+	gp->open = trident_game_open;
+	gp->fuzz = 64;
+	gp->port_data = card;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 /* 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) */
@@ -4368,13 +4393,6 @@ trident_probe(struct pci_dev *pci_dev, c
 	card->banks[BANK_B].addresses = &bank_b_addrs;
 	card->banks[BANK_B].bitmap = 0UL;
 
-	card->gameport.driver = card;
-	card->gameport.fuzz = 64;
-	card->gameport.read = trident_game_read;
-	card->gameport.trigger = trident_game_trigger;
-	card->gameport.cooked_read = trident_game_cooked_read;
-	card->gameport.open = trident_game_open;
-
 	init_MUTEX(&card->open_sem);
 	spin_lock_init(&card->lock);
 	init_timer(&card->timer);
@@ -4508,7 +4526,7 @@ trident_probe(struct pci_dev *pci_dev, c
 	trident_enable_loop_interrupts(card);
 
 	/* Register gameport */
-	gameport_register_port(&card->gameport);
+	trident_register_gameport(card);
 
 out:
 	return rc;
@@ -4551,7 +4569,8 @@ trident_remove(struct pci_dev *pci_dev)
 	}
 
 	/* Unregister gameport */
-	gameport_unregister_port(&card->gameport);
+	if (card->gameport)
+		gameport_unregister_port(card->gameport);
 
 	/* Kill interrupts, and SP/DIF */
 	trident_disable_loop_interrupts(card);
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
--- a/sound/oss/wavfront.c
+++ b/sound/oss/wavfront.c
@@ -1518,45 +1518,56 @@ wavefront_load_gus_patch (int devno, int
 			  int offs, int count, int pmgr_flag)
 {
 	struct patch_info guspatch;
-	wavefront_patch_info samp, pat, prog;
+	wavefront_patch_info *samp, *pat, *prog;
 	wavefront_patch *patp;
 	wavefront_sample *sampp;
 	wavefront_program *progp;
 
 	int i,base_note;
 	long sizeof_patch;
+	int rc = -ENOMEM;
+
+	samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL);
+	if (!samp)
+		goto free_fail;
+	pat = samp + 1;
+	prog = pat + 1;
 
 	/* Copy in the header of the GUS patch */
 
 	sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; 
 	if (copy_from_user(&((char *) &guspatch)[offs],
-			   &(addr)[offs], sizeof_patch - offs))
-		return -EFAULT;
+			   &(addr)[offs], sizeof_patch - offs)) {
+		rc = -EFAULT;
+		goto free_fail;
+	}
 
 	if ((i = wavefront_find_free_patch ()) == -1) {
-		return -EBUSY;
+		rc = -EBUSY;
+		goto free_fail;
 	}
-	pat.number = i;
-	pat.subkey = WF_ST_PATCH;
-	patp = &pat.hdr.p;
+	pat->number = i;
+	pat->subkey = WF_ST_PATCH;
+	patp = &pat->hdr.p;
 
 	if ((i = wavefront_find_free_sample ()) == -1) {
-		return -EBUSY;
+		rc = -EBUSY;
+		goto free_fail;
 	}
-	samp.number = i;
-	samp.subkey = WF_ST_SAMPLE;
-	samp.size = guspatch.len;
-	sampp = &samp.hdr.s;
+	samp->number = i;
+	samp->subkey = WF_ST_SAMPLE;
+	samp->size = guspatch.len;
+	sampp = &samp->hdr.s;
 
-	prog.number = guspatch.instr_no;
-	progp = &prog.hdr.pr;
+	prog->number = guspatch.instr_no;
+	progp = &prog->hdr.pr;
 
 	/* Setup the patch structure */
 
 	patp->amplitude_bias=guspatch.volume;
 	patp->portamento=0;
-	patp->sample_number= samp.number & 0xff;
-	patp->sample_msb= samp.number>>8;
+	patp->sample_number= samp->number & 0xff;
+	patp->sample_msb= samp->number >> 8;
 	patp->pitch_bend= /*12*/ 0;
 	patp->mono=1;
 	patp->retrigger=1;
@@ -1589,7 +1600,7 @@ wavefront_load_gus_patch (int devno, int
 
 	/* Program for this patch */
 
-	progp->layer[0].patch_number= pat.number; /* XXX is this right ? */
+	progp->layer[0].patch_number= pat->number; /* XXX is this right ? */
 	progp->layer[0].mute=1;
 	progp->layer[0].pan_or_mod=1;
 	progp->layer[0].pan=7;
@@ -1637,11 +1648,11 @@ wavefront_load_gus_patch (int devno, int
 
 	/* Now ship it down */
 
-	wavefront_send_sample (&samp, 
+	wavefront_send_sample (samp,
 			       (unsigned short __user *) &(addr)[sizeof_patch],
 			       (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
-	wavefront_send_patch (&pat);
-	wavefront_send_program (&prog);
+	wavefront_send_patch (pat);
+	wavefront_send_program (prog);
 
 	/* Now pan as best we can ... use the slave/internal MIDI device
 	   number if it exists (since it talks to the WaveFront), or the
@@ -1653,8 +1664,11 @@ wavefront_load_gus_patch (int devno, int
 				       ((guspatch.panning << 4) > 127) ?
 				       127 : (guspatch.panning << 4));
 	}
+	rc = 0;
 
-	return(0);
+free_fail:
+	kfree(samp);
+	return rc;
 }
 
 static int
diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
--- a/sound/oss/ymfpci.c
+++ b/sound/oss/ymfpci.c
@@ -2074,7 +2074,7 @@ static /*const*/ struct file_operations 
 /*
  */
 
-static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
+static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused)
 {
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
diff --git a/sound/parisc/Kconfig b/sound/parisc/Kconfig
--- a/sound/parisc/Kconfig
+++ b/sound/parisc/Kconfig
@@ -1,6 +1,6 @@
 # ALSA PA-RISC drivers
 
-menu "ALSA GSC devices"
+menu "GSC devices"
 	depends on SND!=n && GSC
 
 config SND_HARMONY
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -1,264 +1,88 @@
-/*
- *  Harmony chipset driver
+/* Hewlett-Packard Harmony audio driver
  *
- *	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.
+ *   This is a driver for the Harmony audio chipset found
+ *   on the LASI ASIC of various early HP PA-RISC workstations.
  *
- *	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 Vivace are supported by this driver.
+ *   Copyright (C) 2004, Kyle McMartin <kyle@{debian.org,parisc-linux.org}>
  *
- *  this ALSA driver is based on OSS driver by:
- *	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>
+ *     Based on the previous Harmony incarnations by,
+ *       Copyright 2000 (c) Linuxcare Canada, Alex deVries
+ *       Copyright 2000-2003 (c) Helge Deller
+ *       Copyright 2001 (c) Matthieu Delahaye
+ *       Copyright 2001 (c) Jean-Christophe Vaugeois
+ *       Copyright 2003 (c) Laurent Canet
+ *       Copyright 2004 (c) Stuart Brady
  *
- * TODO:
- * - use generic DMA interface and ioremap()/iounmap()
- * - capture is still untested (and probaby non-working)
- * - spin locks
- * - implement non-consistent DMA pages
- * - implement gain meter
- * - module parameters
- * - correct cleaning sequence
- * - better error checking
- * - try to have a better quality.
- *   
- */
-
-/*
- * Harmony chipset 'modus operandi'.
- * - This chipset is found in some HP 32bit workstations, like 712, or B132 class.
- * most of controls are done through registers. Register are found at a fixed offset
- * from the hard physical adress, given in struct dev by register_parisc_driver.
+ *   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.
  *
- * Playback and recording use 4kb pages (dma or not, depending on the machine).
+ *   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.
  *
- * Most of PCM playback & capture is done through interrupt. When harmony needs
- * a new buffer to put recorded data or read played PCM, it sends an interrupt.
- * Bits 2 and 10 of DSTATUS register are '1' when harmony needs respectively
- * a new page for recording and playing. 
- * Interrupt are disabled/enabled by writing to bit 32 of DSTATUS. 
- * Adresses of next page to be played is put in PNXTADD register, next page
- * to be recorded is put in RNXTADD. There is 2 read-only registers, PCURADD and 
- * RCURADD that provides adress of current page.
- * 
- * Harmony has no way to control full duplex or half duplex mode. It means
- * that we always need to provide adresses of playback and capture data, even
- * when this is not needed. That's why we statically alloc one graveyard
- * buffer (to put recorded data in play-only mode) and a silence buffer.
- * 
- * Bitrate, number of channels and data format are controlled with
- * the CNTL register.
+ *   You 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.
  *
- * Mixer work is done through one register (GAINCTL). Only input gain,
- * output attenuation and general attenuation control is provided. There is
- * also controls for enabling/disabling internal speaker and line
- * input.
+ * Notes:
+ *   - graveyard and silence buffers last for lifetime of
+ *     the driver. playback and capture buffers are allocated
+ *     per _open()/_close().
+ * 
+ * TODO:
  *
- * Buffers used by this driver are all DMA consistent.
  */
 
-#include <linux/delay.h>
-#include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
 #include <sound/core.h>
-#include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/control.h>
 #include <sound/rawmidi.h>
 #include <sound/initval.h>
 #include <sound/info.h>
-#include <asm/hardware.h>
+
 #include <asm/io.h>
+#include <asm/hardware.h>
 #include <asm/parisc-device.h>
 
-MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>");
-MODULE_DESCRIPTION("ALSA Harmony sound driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALSA,Harmony soundcard}}");
-
-#undef DEBUG
-#ifdef DEBUG
-# define DPRINTK printk 
-#else
-# define DPRINTK(x,...)
-#endif
-
-#define PFX	"harmony: "
-
-#define MAX_PCM_DEVICES		1
-#define MAX_PCM_SUBSTREAMS	4
-#define MAX_MIDI_DEVICES	0
-
-#define HARMONY_BUF_SIZE	4096
-#define MAX_BUFS		10
-#define MAX_BUFFER_SIZE		(MAX_BUFS * HARMONY_BUF_SIZE)
-
-/* number of silence & graveyard buffers */
-#define GRAVEYARD_BUFS		3
-#define SILENCE_BUFS		3
-
-#define HARMONY_CNTL_C		0x80000000
-
-#define HARMONY_DSTATUS_PN	0x00000200
-#define HARMONY_DSTATUS_RN	0x00000002
-#define HARMONY_DSTATUS_IE	0x80000000
-
-#define HARMONY_DF_16BIT_LINEAR	0x00000000
-#define HARMONY_DF_8BIT_ULAW	0x00000001
-#define HARMONY_DF_8BIT_ALAW	0x00000002
-
-#define HARMONY_SS_MONO		0x00000000
-#define HARMONY_SS_STEREO	0x00000001
-
-/*
- * Channels Mask in mixer register
- * try some "reasonable" default gain values
- */
-
-#define HARMONY_GAIN_TOTAL_SILENCE 0x00F00FFF
-
-/* the following should be enough (mixer is 
- * very sensible on harmony)
- */
-#define HARMONY_GAIN_DEFAULT       0x0F2FF082
-
-
-/* useless since only one card is supported ATM */
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Harmony device.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Harmony device.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable Harmony device.");
-
-/* Register offset (from base hpa) */
-#define REG_ID		0x00
-#define REG_RESET	0x04
-#define REG_CNTL	0x08
-#define REG_GAINCTL	0x0C
-#define REG_PNXTADD	0x10
-#define REG_PCURADD	0x14
-#define REG_RNXTADD	0x18
-#define REG_RCURADD	0x1C
-#define REG_DSTATUS	0x20
-#define REG_OV		0x24
-#define REG_PIO		0x28
-#define REG_DIAG	0x3C
-
-/*
- * main harmony structure
- */
+#include "harmony.h"
 
-typedef struct snd_card_harmony {
-
-	/* spinlocks (To be done) */
-	spinlock_t mixer_lock;
-	spinlock_t control_lock;
-
-	/* parameters */	
-	int irq;
-	unsigned long hpa;
-	int id;
-	int rev;
-	
-	u32 current_gain;
-	int data_format;		/* HARMONY_DF_xx_BIT_xxx */
-	int sample_rate;		/* HARMONY_SR_xx_KHZ */
-	int stereo_select;	/* HARMONY_SS_MONO or HARMONY_SS_STEREO */
-	int format_initialized;
-	
-	unsigned long ply_buffer;
-	int ply_buf;
-	int ply_count;
-	int ply_size;
-	int ply_stopped;
-	int ply_total;
-	
-	unsigned long cap_buffer;
-	int cap_buf;
-	int cap_count;
-	int cap_size;
-	int cap_stopped;
-	int cap_total;
-
-	struct parisc_device *pa_dev;
-
-	struct snd_dma_device dma_dev;
-
-	/* the graveyard buffer is used as recording buffer when playback, 
-	 * because harmony always want a buffer to put recorded data */
-	struct snd_dma_buffer graveyard_dma;
-	int graveyard_count;
-	
-	/* same thing for silence buffer */
-	struct snd_dma_buffer silence_dma;
-	int silence_count;
-
-	/* alsa stuff */
-	snd_card_t *card;
-	snd_pcm_t *pcm;
-	snd_pcm_substream_t *playback_substream;
-	snd_pcm_substream_t *capture_substream;
-	snd_info_entry_t *proc_entry;
-} snd_card_harmony_t;
-
-static snd_card_t *snd_harmony_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-/* wait to be out of control mode */
-static inline void snd_harmony_wait_cntl(snd_card_harmony_t *harmony)
-{
-	int timeout = 5000;
+static struct parisc_device_id snd_harmony_devtable[] = {
+	/* bushmaster / flounder */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, 
+	/* 712 / 715 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, 
+	/* pace */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, 
+	/* outfield / coral II */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F },
+	{ 0, }
+};
 
-	while ( (gsc_readl(harmony->hpa+REG_CNTL) & HARMONY_CNTL_C) && --timeout)
-	{
-		/* Wait */ ;	
-	}
-	if (timeout == 0) DPRINTK(KERN_DEBUG PFX "Error: wait cntl timeouted\n");
-}
+MODULE_DEVICE_TABLE(parisc, snd_harmony_devtable);
 
+#define NAME "harmony"
+#define PFX  NAME ": "
 
-/*
- * sample rate routines 
- */
-static unsigned int snd_card_harmony_rates[] = {
-	5125, 6615, 8000, 9600,
+static unsigned int snd_harmony_rates[] = {
+	5512, 6615, 8000, 9600,
 	11025, 16000, 18900, 22050,
 	27428, 32000, 33075, 37800,
 	44100, 48000
 };
 
-static snd_pcm_hw_constraint_list_t hw_constraint_rates = {
-	.count = ARRAY_SIZE(snd_card_harmony_rates),
-	.list = snd_card_harmony_rates,
-	.mask = 0,
-};
-
-#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
-
-/* bits corresponding to the entries of snd_card_harmony_rates */
 static unsigned int rate_bits[14] = {
 	HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ,
 	HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ,
@@ -267,642 +91,627 @@ static unsigned int rate_bits[14] = {
 	HARMONY_SR_44KHZ, HARMONY_SR_48KHZ
 };
 
-/* snd_card_harmony_rate_bits
- * @rate:	index of current data rate in list
- * returns: harmony hex code for registers
- */
-static unsigned int snd_card_harmony_rate_bits(int rate)
+static snd_pcm_hw_constraint_list_t hw_constraint_rates = {
+	.count = ARRAY_SIZE(snd_harmony_rates),
+	.list = snd_harmony_rates,
+	.mask = 0,
+};
+
+inline unsigned long
+harmony_read(harmony_t *h, unsigned r)
 {
-	unsigned int idx;
-	
-	for (idx = 0; idx < ARRAY_SIZE(snd_card_harmony_rates); idx++)
-		if (snd_card_harmony_rates[idx] == rate)
-			return rate_bits[idx];
-	return HARMONY_SR_44KHZ; /* fallback */
+	return __raw_readl(h->iobase + r);
 }
 
-/*
- * update controls (data format, sample rate, number of channels)
- * according to value supplied in data structure
- */
-void snd_harmony_update_control(snd_card_harmony_t *harmony) 
+inline void
+harmony_write(harmony_t *h, unsigned r, unsigned long v)
 {
-	u32 default_cntl;
-	
-	/* Set CNTL */
-	default_cntl = (HARMONY_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 */
-	
-	/* initialize CNTL */
- 	snd_harmony_wait_cntl(harmony);
-	
-	gsc_writel(default_cntl, harmony->hpa+REG_CNTL);
-	
+	__raw_writel(v, h->iobase + r);
 }
 
-/*
- * interruption controls routines
- */
+static void
+harmony_wait_for_control(harmony_t *h)
+{
+	while (harmony_read(h, HARMONY_CNTL) & HARMONY_CNTL_C) ;
+}
 
-static void snd_harmony_disable_interrupts(snd_card_harmony_t *chip) 
+inline void
+harmony_reset(harmony_t *h)
 {
- 	snd_harmony_wait_cntl(chip);
-	gsc_writel(0, chip->hpa+REG_DSTATUS); 
+	harmony_write(h, HARMONY_RESET, 1);
+	mdelay(50);
+	harmony_write(h, HARMONY_RESET, 0);
 }
 
-static void snd_harmony_enable_interrupts(snd_card_harmony_t *chip) 
+static void
+harmony_disable_interrupts(harmony_t *h)
 {
- 	snd_harmony_wait_cntl(chip);
-	gsc_writel(HARMONY_DSTATUS_IE, chip->hpa+REG_DSTATUS); 
+	u32 dstatus;
+	harmony_wait_for_control(h);
+	dstatus = harmony_read(h, HARMONY_DSTATUS);
+	dstatus &= ~HARMONY_DSTATUS_IE;
+	harmony_write(h, HARMONY_DSTATUS, dstatus);
 }
 
-/*
- * interruption routine:
- * The interrupt routine must provide adresse of next physical pages 
- * used by harmony
- */
-static int snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+static void
+harmony_enable_interrupts(harmony_t *h)
 {
-	snd_card_harmony_t *harmony = (snd_card_harmony_t *)dev;
-	u32 dstatus = 0;
-	unsigned long hpa = harmony->hpa;
-	
-	/* Turn off interrupts */
-	snd_harmony_disable_interrupts(harmony);
-	
-	/* wait for control to free */
- 	snd_harmony_wait_cntl(harmony);
-	
-	/* Read dstatus and pcuradd (the current address) */
-	dstatus = gsc_readl(hpa+REG_DSTATUS);
-	
-	/* Check if this is a request to get the next play buffer */
+	u32 dstatus;
+	harmony_wait_for_control(h);
+	dstatus = harmony_read(h, HARMONY_DSTATUS);
+	dstatus |= HARMONY_DSTATUS_IE;
+	harmony_write(h, HARMONY_DSTATUS, dstatus);
+}
+
+static void
+harmony_mute(harmony_t *h)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&h->mixer_lock, flags);
+	harmony_wait_for_control(h);
+	harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE);
+	spin_unlock_irqrestore(&h->mixer_lock, flags);
+}
+
+static void
+harmony_unmute(harmony_t *h)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&h->mixer_lock, flags);
+	harmony_wait_for_control(h);
+	harmony_write(h, HARMONY_GAINCTL, h->st.gain);
+	spin_unlock_irqrestore(&h->mixer_lock, flags);
+}
+
+static void
+harmony_set_control(harmony_t *h)
+{
+	u32 ctrl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&h->lock, flags);
+
+	ctrl = (HARMONY_CNTL_C      |
+		(h->st.format << 6) |
+		(h->st.stereo << 5) |
+		(h->st.rate));
+
+	harmony_wait_for_control(h);
+	harmony_write(h, HARMONY_CNTL, ctrl);
+
+	spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static irqreturn_t
+snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	u32 dstatus;
+	harmony_t *h = dev;
+
+	spin_lock(&h->lock);
+	harmony_disable_interrupts(h);
+	harmony_wait_for_control(h);
+	dstatus = harmony_read(h, HARMONY_DSTATUS);
+	spin_unlock(&h->lock);
+
 	if (dstatus & HARMONY_DSTATUS_PN) {
-		if (harmony->playback_substream) {
-			harmony->ply_buf += harmony->ply_count;
-			harmony->ply_buf %= harmony->ply_size;
-		
-			gsc_writel(harmony->ply_buffer + harmony->ply_buf,
-					hpa+REG_PNXTADD);
-		
-			snd_pcm_period_elapsed(harmony->playback_substream);
-			harmony->ply_total++;
+		if (h->psubs) {
+			spin_lock(&h->lock);
+			h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
+			h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */
+
+			harmony_write(h, HARMONY_PNXTADD, 
+				      h->pbuf.addr + h->pbuf.buf);
+			h->stats.play_intr++;
+			spin_unlock(&h->lock);
+                        snd_pcm_period_elapsed(h->psubs);
 		} else {
-			gsc_writel(harmony->silence_dma.addr + 
-				   (HARMONY_BUF_SIZE*harmony->silence_count),
-				   hpa+REG_PNXTADD);
-			harmony->silence_count++;
-			harmony->silence_count %= SILENCE_BUFS;
+			spin_lock(&h->lock);
+			harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
+			h->stats.silence_intr++;
+			spin_unlock(&h->lock);
 		}
 	}
-	
-	/* Check if we're being asked to fill in a recording buffer */
+
 	if (dstatus & HARMONY_DSTATUS_RN) {
-		if (harmony->capture_substream) {
-			harmony->cap_buf += harmony->cap_count;
-			harmony->cap_buf %= harmony->cap_size;
-		
-			gsc_writel(harmony->cap_buffer + harmony->cap_buf,
-					hpa+REG_RNXTADD);
-		
-			snd_pcm_period_elapsed(harmony->capture_substream);
-			harmony->cap_total++;
+		if (h->csubs) {
+			spin_lock(&h->lock);
+			h->cbuf.buf += h->cbuf.count;
+			h->cbuf.buf %= h->cbuf.size;
+
+			harmony_write(h, HARMONY_RNXTADD,
+				      h->cbuf.addr + h->cbuf.buf);
+			h->stats.rec_intr++;
+			spin_unlock(&h->lock);
+                        snd_pcm_period_elapsed(h->csubs);
 		} else {
-			/* graveyard buffer */
-			gsc_writel(harmony->graveyard_dma.addr +
-				   (HARMONY_BUF_SIZE*harmony->graveyard_count),
-				   hpa+REG_RNXTADD);
-			harmony->graveyard_count++;
-			harmony->graveyard_count %= GRAVEYARD_BUFS;
+			spin_lock(&h->lock);
+			harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
+			h->stats.graveyard_intr++;
+			spin_unlock(&h->lock);
 		}
 	}
-	snd_harmony_enable_interrupts(harmony);
+
+	spin_lock(&h->lock);
+	harmony_enable_interrupts(h);
+	spin_unlock(&h->lock);
 
 	return IRQ_HANDLED;
 }
 
-/* 
- * proc entry
- * this proc file will give some debugging info
- */
-
-static void snd_harmony_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static unsigned int 
+snd_harmony_rate_bits(int rate)
 {
-	snd_card_harmony_t *harmony = (snd_card_harmony_t *)entry->private_data;
-
-	snd_iprintf(buffer, "LASI Harmony driver\nLaurent Canet <canetl@esiee.fr>\n\n");
-	snd_iprintf(buffer, "IRQ %d, hpa %lx, id %d rev %d\n",
-			harmony->irq, harmony->hpa,
-			harmony->id, harmony->rev);
-	snd_iprintf(buffer, "Current gain %lx\n", (unsigned long) harmony->current_gain);
-	snd_iprintf(buffer, "\tsample rate=%d\n", harmony->sample_rate);
-	snd_iprintf(buffer, "\tstereo select=%d\n", harmony->stereo_select);
-	snd_iprintf(buffer, "\tbitperchan=%d\n\n", harmony->data_format);
-	
-	snd_iprintf(buffer, "Play status:\n");
-	snd_iprintf(buffer, "\tstopped %d\n", harmony->ply_stopped);
-	snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->ply_buffer, harmony->ply_count);
-	snd_iprintf(buffer, "\tbuf %d size %d\n\n", harmony->ply_buf, harmony->ply_size);
-	
-	snd_iprintf(buffer, "Capture status:\n");
-	snd_iprintf(buffer, "\tstopped %d\n", harmony->cap_stopped);
-	snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->cap_buffer, harmony->cap_count);
-	snd_iprintf(buffer, "\tbuf %d, size %d\n\n", harmony->cap_buf, harmony->cap_size);
-
-	snd_iprintf(buffer, "Funny stats: total played=%d, recorded=%d\n\n", harmony->ply_total, harmony->cap_total);
-		
-	snd_iprintf(buffer, "Register:\n");
-	snd_iprintf(buffer, "\tgainctl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_GAINCTL));
-	snd_iprintf(buffer, "\tcntl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_CNTL));
-	snd_iprintf(buffer, "\tid: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_ID));
-	snd_iprintf(buffer, "\tpcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PCURADD));
-	snd_iprintf(buffer, "\trcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RCURADD));
-	snd_iprintf(buffer, "\tpnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PNXTADD));
-	snd_iprintf(buffer, "\trnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RNXTADD));
-	snd_iprintf(buffer, "\tdstatus: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_DSTATUS));
-	snd_iprintf(buffer, "\tov: %lx\n\n", (unsigned long) gsc_readl(harmony->hpa+REG_OV));
+	unsigned int i;
 	
-}
+	for (i = 0; i < ARRAY_SIZE(snd_harmony_rates); i++)
+		if (snd_harmony_rates[i] == rate)
+			return rate_bits[i];
+
+	return HARMONY_SR_44KHZ;
+}
+
+static snd_pcm_hardware_t snd_harmony_playback =
+{
+	.info =	(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 
+		 SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER),
+	.formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW |
+		    SNDRV_PCM_FMTBIT_A_LAW),
+	.rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 |
+		  SNDRV_PCM_RATE_KNOT),
+	.rate_min = 5512,
+	.rate_max = 48000,
+	.channels_min =	1,
+	.channels_max =	2,
+	.buffer_bytes_max = MAX_BUF_SIZE,
+	.period_bytes_min = BUF_SIZE,
+	.period_bytes_max = BUF_SIZE,
+	.periods_min = 1,
+	.periods_max = MAX_BUFS,
+	.fifo_size = 0,
+};
 
-static void __devinit snd_harmony_proc_init(snd_card_harmony_t *harmony)
+static snd_pcm_hardware_t snd_harmony_capture =
 {
-	snd_info_entry_t *entry;
-	
-	if (! snd_card_proc_new(harmony->card, "harmony", &entry))
-		snd_info_set_text_ops(entry, harmony, 2048, snd_harmony_proc_read);
-}
-
-/* 
- * PCM Stuff
- */
+        .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                 SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID |
+                 SNDRV_PCM_INFO_BLOCK_TRANSFER),
+        .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW |
+                    SNDRV_PCM_FMTBIT_A_LAW),
+        .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 |
+		  SNDRV_PCM_RATE_KNOT),
+        .rate_min = 5512,
+        .rate_max = 48000,
+        .channels_min = 1,
+        .channels_max = 2,
+        .buffer_bytes_max = MAX_BUF_SIZE,
+        .period_bytes_min = BUF_SIZE,
+        .period_bytes_max = BUF_SIZE,
+        .periods_min = 1,
+        .periods_max = MAX_BUFS,
+        .fifo_size = 0,
+};
 
-static int snd_card_harmony_playback_ioctl(snd_pcm_substream_t * substream,
-				         unsigned int cmd,
-				         void *arg)
+static int
+snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd)
 {
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	unsigned long flags;
 
-static int snd_card_harmony_capture_ioctl(snd_pcm_substream_t * substream,
-					unsigned int cmd,
-					void *arg)
-{
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
+	if (h->st.capturing)
+		return -EBUSY;
 
-static int snd_card_harmony_playback_trigger(snd_pcm_substream_t * substream,
-					   int cmd)
-{
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	
+	spin_lock_irqsave(&h->lock, flags);
 	switch (cmd) {
-		case SNDRV_PCM_TRIGGER_STOP:
-			if (harmony->ply_stopped) 
-				return -EBUSY;
-			harmony->ply_stopped = 1;
-			snd_harmony_disable_interrupts(harmony);
-			break;
-		case SNDRV_PCM_TRIGGER_START:
-			if (!harmony->ply_stopped)
-				return -EBUSY;
-			harmony->ply_stopped = 0;
-			/* write the location of the first buffer to play */
-			gsc_writel(harmony->ply_buffer, harmony->hpa+REG_PNXTADD);
-			snd_harmony_enable_interrupts(harmony);
-			break;
-		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		case SNDRV_PCM_TRIGGER_SUSPEND:
-			DPRINTK(KERN_INFO PFX "received unimplemented trigger: %d\n", cmd);
-		default:
-			return -EINVAL;
+	case SNDRV_PCM_TRIGGER_START:
+		h->st.playing = 1;
+		harmony_write(h, HARMONY_PNXTADD, h->pbuf.addr);
+		harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
+		harmony_unmute(h);
+		harmony_enable_interrupts(h);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		h->st.playing = 0;
+		harmony_mute(h);
+		harmony_disable_interrupts(h);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	default:
+		spin_unlock_irqrestore(&h->lock, flags);
+		snd_BUG();
+		return -EINVAL;
 	}
+	spin_unlock_irqrestore(&h->lock, flags);
+	
 	return 0;
 }
 
-static int snd_card_harmony_capture_trigger(snd_pcm_substream_t * substream,
-					  int cmd)
+static int
+snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	
-	switch (cmd) {
-		case SNDRV_PCM_TRIGGER_STOP:
-			if (harmony->cap_stopped) 
-				return -EBUSY;
-			harmony->cap_stopped = 1;
-			snd_harmony_disable_interrupts(harmony);
-			break;
-		case SNDRV_PCM_TRIGGER_START:
-			if (!harmony->cap_stopped)
-				return -EBUSY;
-			harmony->cap_stopped = 0;
-			snd_harmony_enable_interrupts(harmony);
-			break;
-		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		case SNDRV_PCM_TRIGGER_SUSPEND:
-			DPRINTK(KERN_INFO PFX "Received unimplemented trigger: %d\n", cmd);
-		default:
-			return -EINVAL;
-	}
-	return 0;
+        harmony_t *h = snd_pcm_substream_chip(ss);
+	unsigned long flags;
+
+	if (h->st.playing)
+		return -EBUSY;
+
+	spin_lock_irqsave(&h->lock, flags);
+        switch (cmd) {
+        case SNDRV_PCM_TRIGGER_START:
+		h->st.capturing = 1;
+                harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
+                harmony_write(h, HARMONY_RNXTADD, h->cbuf.addr);
+		harmony_unmute(h);
+                harmony_enable_interrupts(h);
+		break;
+        case SNDRV_PCM_TRIGGER_STOP:
+		h->st.capturing = 0;
+                harmony_mute(h);
+                harmony_disable_interrupts(h);
+		break;
+        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+        case SNDRV_PCM_TRIGGER_SUSPEND:
+	default:
+		spin_unlock_irqrestore(&h->lock, flags);
+		snd_BUG();
+                return -EINVAL;
+        }
+	spin_unlock_irqrestore(&h->lock, flags);
+		
+        return 0;
 }
 
-/* set data format */
-static int snd_harmony_set_data_format(snd_card_harmony_t *harmony, int pcm_format)
+static int
+snd_harmony_set_data_format(harmony_t *h, int fmt, int force)
 {
-	int old_format = harmony->data_format;
-	int new_format = old_format;
-	switch (pcm_format) {
+	int o = h->st.format;
+	int n;
+
+	switch(fmt) {
 	case SNDRV_PCM_FORMAT_S16_BE:
-		new_format = HARMONY_DF_16BIT_LINEAR;
+		n = HARMONY_DF_16BIT_LINEAR;
 		break;
 	case SNDRV_PCM_FORMAT_A_LAW:
-		new_format = HARMONY_DF_8BIT_ALAW;
+		n = HARMONY_DF_8BIT_ALAW;
 		break;
 	case SNDRV_PCM_FORMAT_MU_LAW:
-		new_format = HARMONY_DF_8BIT_ULAW;
+		n = HARMONY_DF_8BIT_ULAW;
+		break;
+	default:
+		n = HARMONY_DF_16BIT_LINEAR;
 		break;
 	}
-	/* re-initialize silence buffer if needed */
-	if (old_format != new_format)
-		snd_pcm_format_set_silence(pcm_format, harmony->silence_dma.area,
-					   (HARMONY_BUF_SIZE * SILENCE_BUFS * 8) / snd_pcm_format_width(pcm_format));
 
-	return new_format;
+	if (force || o != n) {
+		snd_pcm_format_set_silence(fmt, h->sdma.area, SILENCE_BUFSZ / 
+					   (snd_pcm_format_physical_width(fmt)
+					    / 8));
+	}
+
+	return n;
 }
 
-static int snd_card_harmony_playback_prepare(snd_pcm_substream_t * substream)
+static int
+snd_harmony_playback_prepare(snd_pcm_substream_t *ss)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
 	
-	harmony->ply_size 			= snd_pcm_lib_buffer_bytes(substream);
-	harmony->ply_count 			= snd_pcm_lib_period_bytes(substream);
-	harmony->ply_buf			= 0;
-	harmony->ply_stopped		= 1;
+	if (h->st.capturing)
+		return -EBUSY;
 	
-	/* initialize given sample rate */
-	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
+	h->pbuf.size = snd_pcm_lib_buffer_bytes(ss);
+	h->pbuf.count = snd_pcm_lib_period_bytes(ss);
+	h->pbuf.buf = 0;
+	h->st.playing = 0;
 
-	/* data format */
-	harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
-
-	/* number of channels */
-	if (runtime->channels == 2)
-		harmony->stereo_select = HARMONY_SS_STEREO;
-	else
-		harmony->stereo_select = HARMONY_SS_MONO;
-	
-	DPRINTK(KERN_INFO PFX "Playback_prepare, sr=%d(%x), df=%x, ss=%x hpa=%lx\n", runtime->rate,
-				harmony->sample_rate, harmony->data_format, harmony->stereo_select, harmony->hpa);
-	snd_harmony_update_control(harmony);
-	harmony->format_initialized = 1;
-	harmony->ply_buffer = runtime->dma_addr;
+	h->st.rate = snd_harmony_rate_bits(rt->rate);
+	h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
 	
+	if (rt->channels == 2)
+		h->st.stereo = HARMONY_SS_STEREO;
+	else
+		h->st.stereo = HARMONY_SS_MONO;
+
+	harmony_set_control(h);
+
+	h->pbuf.addr = rt->dma_addr;
+
 	return 0;
 }
 
-static int snd_card_harmony_capture_prepare(snd_pcm_substream_t * substream)
+static int
+snd_harmony_capture_prepare(snd_pcm_substream_t *ss)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	
-	harmony->cap_size 			= snd_pcm_lib_buffer_bytes(substream);
-	harmony->cap_count 			= snd_pcm_lib_period_bytes(substream);
-	harmony->cap_count			= 0;
-	harmony->cap_stopped		= 1;
-
-	/* initialize given sample rate */
-	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
-	
-	/* data format */
-	harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
-	
-	/* number of channels */
-	if (runtime->channels == 1)
-		harmony->stereo_select = HARMONY_SS_MONO;
-	else if (runtime->channels == 2)
-		harmony->stereo_select = HARMONY_SS_STEREO;
-		
-	snd_harmony_update_control(harmony);
-	harmony->format_initialized = 1;
-	
-	harmony->cap_buffer = runtime->dma_addr;
+        harmony_t *h = snd_pcm_substream_chip(ss);
+        snd_pcm_runtime_t *rt = ss->runtime;
 
-	return 0;
+	if (h->st.playing)
+		return -EBUSY;
+
+        h->cbuf.size = snd_pcm_lib_buffer_bytes(ss);
+        h->cbuf.count = snd_pcm_lib_period_bytes(ss);
+        h->cbuf.buf = 0;
+	h->st.capturing = 0;
+
+        h->st.rate = snd_harmony_rate_bits(rt->rate);
+        h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
+
+        if (rt->channels == 2)
+                h->st.stereo = HARMONY_SS_STEREO;
+        else
+                h->st.stereo = HARMONY_SS_MONO;
+
+        harmony_set_control(h);
+
+        h->cbuf.addr = rt->dma_addr;
+
+        return 0;
 }
 
-static snd_pcm_uframes_t snd_card_harmony_capture_pointer(snd_pcm_substream_t * substream)
+static snd_pcm_uframes_t 
+snd_harmony_playback_pointer(snd_pcm_substream_t *ss)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	unsigned long rcuradd;
-	int recorded;
-	
-	if (harmony->cap_stopped) return 0;
-	if (harmony->capture_substream == NULL) return 0;
-
-	rcuradd = gsc_readl(harmony->hpa+REG_RCURADD);
-	recorded = (rcuradd - harmony->cap_buffer);
-	recorded %= harmony->cap_size;
-		
-	return bytes_to_frames(runtime, recorded);
-}
+	snd_pcm_runtime_t *rt = ss->runtime;
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	unsigned long pcuradd;
+	unsigned long played;
 
-/*
- */
+	if (!(h->st.playing) || (h->psubs == NULL)) 
+		return 0;
 
-static snd_pcm_uframes_t snd_card_harmony_playback_pointer(snd_pcm_substream_t * substream)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	int played;
-	long int pcuradd = gsc_readl(harmony->hpa+REG_PCURADD);
-	
-	if ((harmony->ply_stopped) || (harmony->playback_substream == NULL)) return 0;
-	if ((harmony->ply_buffer == 0) || (harmony->ply_size == 0)) return 0;
-	
-	played = (pcuradd - harmony->ply_buffer);
-	
-	printk(KERN_DEBUG PFX "Pointer is %lx-%lx = %d\n", pcuradd, harmony->ply_buffer, played);	
-
-	if (pcuradd > harmony->ply_buffer + harmony->ply_size) return 0;
-	
-	return bytes_to_frames(runtime, played);
-}
-
-static snd_pcm_hardware_t snd_card_harmony_playback =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 
-					SNDRV_PCM_INFO_JOINT_DUPLEX | 
-					SNDRV_PCM_INFO_MMAP_VALID |
-					SNDRV_PCM_INFO_BLOCK_TRANSFER),
-	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | 
-					SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW),
-	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5500,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	MAX_BUFFER_SIZE,
-	.period_bytes_min =	HARMONY_BUF_SIZE,
-	.period_bytes_max =	HARMONY_BUF_SIZE,
-	.periods_min =		1,
-	.periods_max =		MAX_BUFS,
-	.fifo_size =		0,
-};
+	if ((h->pbuf.addr == 0) || (h->pbuf.size == 0))
+		return 0;
+	
+	pcuradd = harmony_read(h, HARMONY_PCURADD);
+	played = pcuradd - h->pbuf.addr;
+
+#ifdef HARMONY_DEBUG
+	printk(KERN_DEBUG PFX "playback_pointer is 0x%lx-0x%lx = %d bytes\n", 
+	       pcuradd, h->pbuf.addr, played);	
+#endif
+
+	if (pcuradd > h->pbuf.addr + h->pbuf.size) {
+		return 0;
+	}
+
+	return bytes_to_frames(rt, played);
+}
 
-static snd_pcm_hardware_t snd_card_harmony_capture =
+static snd_pcm_uframes_t
+snd_harmony_capture_pointer(snd_pcm_substream_t *ss)
 {
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 
-					SNDRV_PCM_INFO_JOINT_DUPLEX | 
-					SNDRV_PCM_INFO_MMAP_VALID |
-					SNDRV_PCM_INFO_BLOCK_TRANSFER),
-	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | 
-					SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW),
-	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5500,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	MAX_BUFFER_SIZE,
-	.period_bytes_min =	HARMONY_BUF_SIZE,
-	.period_bytes_max =	HARMONY_BUF_SIZE,
-	.periods_min =		1,
-	.periods_max =		MAX_BUFS,
-	.fifo_size =		0,
-};
+        snd_pcm_runtime_t *rt = ss->runtime;
+        harmony_t *h = snd_pcm_substream_chip(ss);
+        unsigned long rcuradd;
+        unsigned long caught;
+
+        if (!(h->st.capturing) || (h->csubs == NULL))
+                return 0;
+
+        if ((h->cbuf.addr == 0) || (h->cbuf.size == 0))
+                return 0;
+
+        rcuradd = harmony_read(h, HARMONY_RCURADD);
+        caught = rcuradd - h->cbuf.addr;
+
+#ifdef HARMONY_DEBUG
+        printk(KERN_DEBUG PFX "capture_pointer is 0x%lx-0x%lx = %d bytes\n",
+               rcuradd, h->cbuf.addr, caught);
+#endif
+
+        if (rcuradd > h->cbuf.addr + h->cbuf.size) {
+		return 0;
+	}
+
+        return bytes_to_frames(rt, caught);
+}
 
-static int snd_card_harmony_playback_open(snd_pcm_substream_t * substream)
+static int 
+snd_harmony_playback_open(snd_pcm_substream_t *ss)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
 	int err;
 	
-	harmony->playback_substream = substream;
-	runtime->hw = snd_card_harmony_playback;
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
+	h->psubs = ss;
+	rt->hw = snd_harmony_playback;
+	snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 
+				   &hw_constraint_rates);
 	
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+	err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
 		return err;
 	
 	return 0;
 }
 
-static int snd_card_harmony_capture_open(snd_pcm_substream_t * substream)
+static int
+snd_harmony_capture_open(snd_pcm_substream_t *ss)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-	
-	harmony->capture_substream = substream;
-	runtime->hw = snd_card_harmony_capture;
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
+        harmony_t *h = snd_pcm_substream_chip(ss);
+        snd_pcm_runtime_t *rt = ss->runtime;
+        int err;
+
+        h->csubs = ss;
+        rt->hw = snd_harmony_capture;
+        snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                   &hw_constraint_rates);
 
+        err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+        if (err < 0)
+                return err;
+
+        return 0;
 }
 
-static int snd_card_harmony_playback_close(snd_pcm_substream_t * substream)
+static int 
+snd_harmony_playback_close(snd_pcm_substream_t *ss)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	
-	harmony->playback_substream = NULL;
-	harmony->ply_size 			= 0;
-	harmony->ply_buf			= 0;
-	harmony->ply_buffer			= 0;
-	harmony->ply_count			= 0;
-	harmony->ply_stopped		= 1;
-	harmony->format_initialized = 0;
-	
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	h->psubs = NULL;
 	return 0;
 }
 
-static int snd_card_harmony_capture_close(snd_pcm_substream_t * substream)
+static int
+snd_harmony_capture_close(snd_pcm_substream_t *ss)
 {
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	
-	harmony->capture_substream = NULL;
-	harmony->cap_size 			= 0;
-	harmony->cap_buf			= 0;
-	harmony->cap_buffer			= 0;
-	harmony->cap_count			= 0;
-	harmony->cap_stopped		= 1;
-	harmony->format_initialized = 0;
-	
-	return 0;
+        harmony_t *h = snd_pcm_substream_chip(ss);
+        h->csubs = NULL;
+        return 0;
 }
 
-static int snd_card_harmony_hw_params(snd_pcm_substream_t *substream, 
-	                   snd_pcm_hw_params_t * hw_params)
+static int 
+snd_harmony_hw_params(snd_pcm_substream_t *ss,
+		      snd_pcm_hw_params_t *hw)
 {
 	int err;
-	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
+	harmony_t *h = snd_pcm_substream_chip(ss);
+	
+	err = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw));
+	if (err > 0 && h->dma.type == SNDRV_DMA_TYPE_CONTINUOUS)
+		ss->runtime->dma_addr = __pa(ss->runtime->dma_area);
 	
-	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-	if (err > 0 && harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS)
-		substream->runtime->dma_addr = __pa(substream->runtime->dma_area);
-	DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err,
-			(unsigned long)substream->runtime->dma_addr);
 	return err;
 }
 
-static int snd_card_harmony_hw_free(snd_pcm_substream_t *substream) 
+static int 
+snd_harmony_hw_free(snd_pcm_substream_t *ss) 
 {
-	snd_pcm_lib_free_pages(substream);		
-	return 0;
+	return snd_pcm_lib_free_pages(ss);
 }
 
-static snd_pcm_ops_t snd_card_harmony_playback_ops = {
-	.open =			snd_card_harmony_playback_open,
-	.close =		snd_card_harmony_playback_close,
-	.ioctl =		snd_card_harmony_playback_ioctl,
-	.hw_params = 	snd_card_harmony_hw_params,
-	.hw_free = 		snd_card_harmony_hw_free,
-	.prepare =		snd_card_harmony_playback_prepare,
-	.trigger =		snd_card_harmony_playback_trigger,
- 	.pointer =		snd_card_harmony_playback_pointer,
+static snd_pcm_ops_t snd_harmony_playback_ops = {
+	.open =	snd_harmony_playback_open,
+	.close = snd_harmony_playback_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_harmony_hw_params,
+	.hw_free = snd_harmony_hw_free,
+	.prepare = snd_harmony_playback_prepare,
+	.trigger = snd_harmony_playback_trigger,
+ 	.pointer = snd_harmony_playback_pointer,
 };
 
-static snd_pcm_ops_t snd_card_harmony_capture_ops = {
-	.open =			snd_card_harmony_capture_open,
-	.close =		snd_card_harmony_capture_close,
-	.ioctl =		snd_card_harmony_capture_ioctl,
-	.hw_params = 	snd_card_harmony_hw_params,
-	.hw_free = 		snd_card_harmony_hw_free,
-	.prepare =		snd_card_harmony_capture_prepare,
-	.trigger =		snd_card_harmony_capture_trigger,
-	.pointer =		snd_card_harmony_capture_pointer,
+static snd_pcm_ops_t snd_harmony_capture_ops = {
+        .open = snd_harmony_capture_open,
+        .close = snd_harmony_capture_close,
+        .ioctl = snd_pcm_lib_ioctl,
+        .hw_params = snd_harmony_hw_params,
+        .hw_free = snd_harmony_hw_free,
+        .prepare = snd_harmony_capture_prepare,
+        .trigger = snd_harmony_capture_trigger,
+        .pointer = snd_harmony_capture_pointer,
 };
 
-static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony)
+static int 
+snd_harmony_pcm_init(harmony_t *h)
 {
 	snd_pcm_t *pcm;
 	int err;
 
-	/* Request that IRQ */
-	if (request_irq(harmony->irq, snd_card_harmony_interrupt, 0 ,"harmony", harmony)) {
-		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony->irq);
-		return -EFAULT;
-	}
+	harmony_disable_interrupts(h);
 	
-	snd_harmony_disable_interrupts(harmony);
-	
-   	if ((err = snd_pcm_new(harmony->card, "Harmony", 0, 1, 1, &pcm)) < 0)
+   	err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm);
+	if (err < 0)
 		return err;
 	
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops);
- 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_harmony_capture_ops); 
-	
-	pcm->private_data = harmony;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+			&snd_harmony_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_harmony_capture_ops);
+
+	pcm->private_data = h;
 	pcm->info_flags = 0;
-	strcpy(pcm->name, "Harmony");
-	harmony->pcm = pcm;
+	strcpy(pcm->name, "harmony");
+	h->pcm = pcm;
+
+	h->psubs = NULL;
+	h->csubs = NULL;
 	
 	/* initialize graveyard buffer */
-	harmony->dma_dev.type = SNDRV_DMA_TYPE_DEV;
-	harmony->dma_dev.dev = &harmony->pa_dev->dev;
-	err = snd_dma_alloc_pages(harmony->dma_dev.type,
-				  harmony->dma_dev.dev,
-				  HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
-				  &harmony->graveyard_dma);
-	if (err == -ENOMEM) {
-		/* use continuous buffers */
-		harmony->dma_dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
-		harmony->dma_dev.dev = snd_dma_continuous_data(GFP_KERNEL);
-		err = snd_dma_alloc_pages(harmony->dma_dev.type,
-					  harmony->dma_dev.dev,
-					  HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
-					  &harmony->graveyard_dma);
-	}
+	h->dma.type = SNDRV_DMA_TYPE_DEV;
+	h->dma.dev = &h->dev->dev;
+	err = snd_dma_alloc_pages(h->dma.type,
+				  h->dma.dev,
+				  BUF_SIZE*GRAVEYARD_BUFS,
+				  &h->gdma);
 	if (err < 0) {
-		printk(KERN_ERR PFX "can't allocate graveyard buffer\n");
+		printk(KERN_ERR PFX "cannot allocate graveyard buffer!\n");
 		return err;
 	}
-	harmony->graveyard_count = 0;
 	
 	/* initialize silence buffers */
-	err = snd_dma_alloc_pages(harmony->dma_dev.type,
-				  harmony->dma_dev.dev,
-				  HARMONY_BUF_SIZE*SILENCE_BUFS,
-				  &harmony->silence_dma);
+	err = snd_dma_alloc_pages(h->dma.type,
+				  h->dma.dev,
+				  BUF_SIZE*SILENCE_BUFS,
+				  &h->sdma);
 	if (err < 0) {
-		printk(KERN_ERR PFX "can't allocate silence buffer\n");
+		printk(KERN_ERR PFX "cannot allocate silence buffer!\n");
 		return err;
 	}
-	harmony->silence_count = 0;
 
-	if (harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS) {
-		harmony->graveyard_dma.addr = __pa(harmony->graveyard_dma.area);
-		harmony->silence_dma.addr = __pa(harmony->silence_dma.area);
-	}
-
-	harmony->ply_stopped = harmony->cap_stopped = 1;
-	
-	harmony->playback_substream = NULL;
-	harmony->capture_substream = NULL;
-	harmony->graveyard_count = 0;
-
-	err = snd_pcm_lib_preallocate_pages_for_all(pcm, harmony->dma_dev.type,
-						    harmony->dma_dev.dev,
-						    MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
+	/* pre-allocate space for DMA */
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm, h->dma.type,
+						    h->dma.dev,
+						    MAX_BUF_SIZE, 
+						    MAX_BUF_SIZE);
 	if (err < 0) {
-		printk(KERN_ERR PFX "buffer allocation error %d\n", err);
-		// return err;
+		printk(KERN_ERR PFX "buffer allocation error: %d\n", err);
+		return err;
 	}
 
+	h->st.format = snd_harmony_set_data_format(h,
+		SNDRV_PCM_FORMAT_S16_BE, 1);
+
 	return 0;
 }
 
-/*
- * mixer routines
- */
-
-static void snd_harmony_set_new_gain(snd_card_harmony_t *harmony)
+static void 
+snd_harmony_set_new_gain(harmony_t *h)
 {
-	DPRINTK(KERN_INFO PFX "Setting new gain %x at %lx\n", harmony->current_gain, harmony->hpa+REG_GAINCTL);
-	/* Wait until we're out of control mode */
- 	snd_harmony_wait_cntl(harmony);
-	
-	gsc_writel(harmony->current_gain, harmony->hpa+REG_GAINCTL);
+ 	harmony_wait_for_control(h);
+	harmony_write(h, HARMONY_GAINCTL, h->st.gain);
 }
 
-#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-  .info = snd_harmony_mixercontrol_info, \
-  .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \
-  .private_value = ((left_shift) | ((right_shift) << 8) | ((mask) << 16) | ((invert) << 24)) }
-
-static int snd_harmony_mixercontrol_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int left_shift = (kcontrol->private_value) & 0xff;
-	int right_shift = (kcontrol->private_value >> 8) & 0xff;
+static int 
+snd_harmony_mixercontrol_info(snd_kcontrol_t *kc, 
+			      snd_ctl_elem_info_t *uinfo)
+{
+	int mask = (kc->private_value >> 16) & 0xff;
+	int left_shift = (kc->private_value) & 0xff;
+	int right_shift = (kc->private_value >> 8) & 0xff;
 	
-	uinfo->type = (mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER);
-	uinfo->count = (left_shift == right_shift) ? 1 : 2;
+	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : 
+		       SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = left_shift == right_shift ? 1 : 2;
 	uinfo->value.integer.min = 0;
 	uinfo->value.integer.max = mask;
+
 	return 0;
 }
- 
-static int snd_harmony_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol);
-	int shift_left = (kcontrol->private_value) & 0xff;
-	int shift_right = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	unsigned long flags;
+
+static int 
+snd_harmony_volume_get(snd_kcontrol_t *kc, 
+		       snd_ctl_elem_value_t *ucontrol)
+{
+	harmony_t *h = snd_kcontrol_chip(kc);
+	int shift_left = (kc->private_value) & 0xff;
+	int shift_right = (kc->private_value >> 8) & 0xff;
+	int mask = (kc->private_value >> 16) & 0xff;
+	int invert = (kc->private_value >> 24) & 0xff;
 	int left, right;
+	unsigned long flags;
 	
-	spin_lock_irqsave(&harmony->mixer_lock, flags);
-	left = (harmony->current_gain >> shift_left) & mask;
-	right = (harmony->current_gain >> shift_right) & mask;
+	spin_lock_irqsave(&h->mixer_lock, flags);
+
+	left = (h->st.gain >> shift_left) & mask;
+	right = (h->st.gain >> shift_right) & mask;
 
 	if (invert) {
 		left = mask - left;
@@ -910,21 +719,24 @@ static int snd_harmony_volume_get(snd_kc
 	}
 	ucontrol->value.integer.value[0] = left;
 	ucontrol->value.integer.value[1] = right;
-	spin_unlock_irqrestore(&harmony->mixer_lock, flags);
+
+	spin_unlock_irqrestore(&h->mixer_lock, flags);
 
 	return 0;
 }  
 
-static int snd_harmony_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol);
-	int shift_left = (kcontrol->private_value) & 0xff;
-	int shift_right = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	unsigned long flags;
+static int 
+snd_harmony_volume_put(snd_kcontrol_t *kc, 
+		       snd_ctl_elem_value_t *ucontrol)
+{
+	harmony_t *h = snd_kcontrol_chip(kc);
+	int shift_left = (kc->private_value) & 0xff;
+	int shift_right = (kc->private_value >> 8) & 0xff;
+	int mask = (kc->private_value >> 16) & 0xff;
+	int invert = (kc->private_value >> 24) & 0xff;
 	int left, right;
-	int old_gain = harmony->current_gain;
+	int old_gain = h->st.gain;
+	unsigned long flags;
 	
 	left = ucontrol->value.integer.value[0] & mask;
 	right = ucontrol->value.integer.value[1] & mask;
@@ -933,213 +745,249 @@ static int snd_harmony_volume_put(snd_kc
 		right = mask - right;
 	}
 	
-	spin_lock_irqsave(&harmony->mixer_lock, flags);
-	harmony->current_gain = harmony->current_gain & ~( (mask << shift_right) | (mask << shift_left));
- 	harmony->current_gain = harmony->current_gain | ((left << shift_left) | (right << shift_right) );
-	snd_harmony_set_new_gain(harmony);
-	spin_unlock_irqrestore(&harmony->mixer_lock, flags);
+	spin_lock_irqsave(&h->mixer_lock, flags);
+
+	h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) );
+ 	h->st.gain |=  ( (left << shift_left) | (right << shift_right) );
+	snd_harmony_set_new_gain(h);
+
+	spin_unlock_irqrestore(&h->mixer_lock, flags);
 	
-	return (old_gain - harmony->current_gain);
+	return (old_gain - h->st.gain);
 }
 
-#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/sizeof(snd_kcontrol_new_t))
+#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \
+                          sizeof(snd_kcontrol_new_t))
+
+#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,                \
+  .info = snd_harmony_mixercontrol_info,                             \
+  .get = snd_harmony_volume_get, .put = snd_harmony_volume_put,      \
+  .private_value = ((left_shift) | ((right_shift) << 8) |            \
+                   ((mask) << 16) | ((invert) << 24)) }
 
 static snd_kcontrol_new_t snd_harmony_controls[] = {
-HARMONY_VOLUME("PCM Capture Volume", 12, 16, 0x0f, 0),
-HARMONY_VOLUME("Master Volume", 20, 20, 0x0f, 1),
-HARMONY_VOLUME("PCM Playback Volume", 6, 0, 0x3f, 1),
+	HARMONY_VOLUME("Playback Volume", HARMONY_GAIN_LO_SHIFT, 
+		       HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),
+	HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,
+		       HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0),
 };
 
-static void __init snd_harmony_reset_codec(snd_card_harmony_t *harmony)
-{
- 	snd_harmony_wait_cntl(harmony);
-	gsc_writel(1, harmony->hpa+REG_RESET);
-	mdelay(50);		/* wait 50 ms */
-	gsc_writel(0, harmony->hpa+REG_RESET);
-}
-
-/*
- * Mute all the output and reset Harmony.
- */
-
-static void __init snd_harmony_mixer_reset(snd_card_harmony_t *harmony)
+static void __init 
+snd_harmony_mixer_reset(harmony_t *h)
 {
-	harmony->current_gain = HARMONY_GAIN_TOTAL_SILENCE;
-	snd_harmony_set_new_gain(harmony);
-	snd_harmony_reset_codec(harmony);
-	harmony->current_gain = HARMONY_GAIN_DEFAULT;
-	snd_harmony_set_new_gain(harmony);
+	harmony_mute(h);
+	harmony_reset(h);
+	h->st.gain = HARMONY_GAIN_DEFAULT;
+	harmony_unmute(h);
 }
 
-
-static int __init snd_card_harmony_mixer_init(snd_card_harmony_t *harmony)
+static int __init 
+snd_harmony_mixer_init(harmony_t *h)
 {
-	snd_card_t *card = harmony->card;
+	snd_card_t *card = h->card;
 	int idx, err;
 
-	snd_assert(harmony != NULL, return -EINVAL);
+	snd_assert(h != NULL, return -EINVAL);
 	strcpy(card->mixername, "Harmony Gain control interface");
 
 	for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
-		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_harmony_controls[idx], harmony))) < 0)
+		err = snd_ctl_add(card, 
+				  snd_ctl_new1(&snd_harmony_controls[idx], h));
+		if (err < 0)
 			return err;
 	}
 	
-	snd_harmony_mixer_reset(harmony);
+	snd_harmony_mixer_reset(h);
 
 	return 0;
 }
 
-static int snd_card_harmony_create(snd_card_t *card, struct parisc_device *pa_dev, snd_card_harmony_t *harmony)
+static int
+snd_harmony_free(harmony_t *h)
 {
-	u32	cntl;
-	
-	harmony->card = card;
-	
-	harmony->pa_dev = pa_dev;
+        if (h->gdma.addr)
+                snd_dma_free_pages(&h->gdma);
+        if (h->sdma.addr)
+                snd_dma_free_pages(&h->sdma);
 
-	/* Set the HPA of harmony */
-	harmony->hpa = pa_dev->hpa;
-	
-	harmony->irq = pa_dev->irq;
-	if (!harmony->irq) {
-		printk(KERN_ERR PFX "no irq found\n");
-		return -ENODEV;
-	}
+	if (h->irq >= 0)
+		free_irq(h->irq, h);
 
-	/* Grab the ID and revision from the device */
-	harmony->id = (gsc_readl(harmony->hpa+REG_ID)&0x00ff0000) >> 16;
-	if ((harmony->id | 1) != 0x15) {
-		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", harmony->id);
-		return -EBUSY;
-	}
-	cntl = gsc_readl(harmony->hpa+REG_CNTL);
-	harmony->rev = (cntl>>20) & 0xff;
+	if (h->iobase)
+		iounmap(h->iobase);
 
-	printk(KERN_INFO "Lasi Harmony Audio driver h/w id %i, rev. %i at 0x%lx, IRQ %i\n",	harmony->id, harmony->rev, pa_dev->hpa, harmony->irq);
-	
-	/* Make sure the control bit isn't set, although I don't think it 
-	   ever is. */
-	if (cntl & HARMONY_CNTL_C) {
-		printk(KERN_WARNING PFX "CNTL busy\n");
-		harmony->hpa = 0;
-		return -EBUSY;
+	parisc_set_drvdata(h->dev, NULL);
+
+	kfree(h);
+	return 0;
+}
+
+static int
+snd_harmony_dev_free(snd_device_t *dev)
+{
+	harmony_t *h = dev->device_data;
+	return snd_harmony_free(h);
+}
+
+static int __devinit
+snd_harmony_create(snd_card_t *card, 
+		   struct parisc_device *padev, 
+		   harmony_t **rchip)
+{
+	int err;
+	harmony_t *h;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_harmony_dev_free,
+	};
+
+	*rchip = NULL;
+
+	h = kmalloc(sizeof(*h), GFP_KERNEL);
+	if (h == NULL)
+		return -ENOMEM;
+
+	memset(&h->st, 0, sizeof(h->st));
+	memset(&h->stats, 0, sizeof(h->stats));
+	memset(&h->pbuf, 0, sizeof(h->pbuf));
+	memset(&h->cbuf, 0, sizeof(h->cbuf));
+
+	h->hpa = padev->hpa;
+	h->card = card;
+	h->dev = padev;
+	h->irq = padev->irq;
+	h->iobase = ioremap_nocache(padev->hpa, HARMONY_SIZE);
+	if (h->iobase == NULL) {
+		printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n",
+		       padev->hpa);
+		err = -EBUSY;
+		goto free_and_ret;
 	}
-	
+		
+	err = request_irq(h->irq, snd_harmony_interrupt, 0,
+			  "harmony", h);
+	if (err) {
+		printk(KERN_ERR PFX "could not obtain interrupt %d",
+		       h->irq);
+		goto free_and_ret;
+	}
+
+	spin_lock_init(&h->mixer_lock);
+	spin_lock_init(&h->lock);
+
+        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+                                  h, &ops)) < 0) {
+                goto free_and_ret;
+        }
+
+	*rchip = h;
+
 	return 0;
+
+free_and_ret:
+	snd_harmony_free(h);
+	return err;
 }
-	
-static int __init snd_card_harmony_probe(struct parisc_device *pa_dev)
+
+static int __devinit
+snd_harmony_probe(struct parisc_device *padev)
 {
+	int err;
 	static int dev;
-	snd_card_harmony_t *chip;
 	snd_card_t *card;
-	int err;
-	
-	if (dev >= SNDRV_CARDS)
+	harmony_t *h;
+	static int index = SNDRV_DEFAULT_IDX1;
+	static char *id = SNDRV_DEFAULT_STR1;
+
+	h = parisc_get_drvdata(padev);
+	if (h != NULL) {
 		return -ENODEV;
-	if (!enable[dev]) {
-		dev++;
-		return -ENOENT;
 	}
-	
-	snd_harmony_cards[dev] = snd_card_new(index[dev], id[dev], THIS_MODULE,
-			    sizeof(snd_card_harmony_t));
-	card = snd_harmony_cards[dev];
-				
+
+	card = snd_card_new(index, id, THIS_MODULE, 0);
 	if (card == NULL)
 		return -ENOMEM;
-	chip = (struct snd_card_harmony *)card->private_data;
-	spin_lock_init(&chip->control_lock);
-	spin_lock_init(&chip->mixer_lock);
-	
-	if ((err = snd_card_harmony_create(card, pa_dev, chip)) < 0) {
-		printk(KERN_ERR PFX "Creation failed\n");
-		snd_card_free(card);
-		return err;
+
+	err = snd_harmony_create(card, padev, &h);
+	if (err < 0) {
+		goto free_and_ret;
 	}
-	if ((err = snd_card_harmony_pcm_init(chip)) < 0) {
-		printk(KERN_ERR PFX "PCM Init failed\n");
-		snd_card_free(card);
-		return err;
+
+	err = snd_harmony_pcm_init(h);
+	if (err < 0) {
+		goto free_and_ret;
 	}
-	if ((err = snd_card_harmony_mixer_init(chip)) < 0) {
-		printk(KERN_ERR PFX "Mixer init failed\n");
-		snd_card_free(card);
-		return err;
+
+	err = snd_harmony_mixer_init(h);
+	if (err < 0) {
+		goto free_and_ret;
 	}
-	
-	snd_harmony_proc_init(chip);
-	
-	strcpy(card->driver, "Harmony");
-	strcpy(card->shortname, "ALSA driver for LASI Harmony");
-	sprintf(card->longname, "%s at h/w, id %i, rev. %i hpa 0x%lx, IRQ %i\n",card->shortname, chip->id, chip->rev, pa_dev->hpa, chip->irq);
 
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
+	strcpy(card->driver, "harmony");
+	strcpy(card->shortname, "Harmony");
+	sprintf(card->longname, "%s at 0x%lx, irq %i",
+		card->shortname, h->hpa, h->irq);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		goto free_and_ret;
 	}
 
-	printk(KERN_DEBUG PFX "Successfully registered harmony pcm backend & mixer %d\n", dev);
 	dev++;
-	return 0;
-}
+	parisc_set_drvdata(padev, h);
 
-static struct parisc_device_id snd_card_harmony_devicetbl[] = {
- { 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, }
-};
+	return 0;
 
-MODULE_DEVICE_TABLE(parisc, snd_card_harmony_devicetbl);
+free_and_ret:
+	snd_card_free(card);
+	return err;
+}
 
-/*
- * bloc device parisc. c'est une structure qui definit un device
- * que l'on trouve sur parisc. 
- * On y trouve les differents numeros HVERSION correspondant au device
- * en question (ce qui permet a l'inventory de l'identifier) et la fonction
- * d'initialisation du chose 
- */
+static int __devexit
+snd_harmony_remove(struct parisc_device *padev)
+{
+	harmony_t *h = parisc_get_drvdata(padev);
+	snd_card_free(h->card);
+	return 0;
+}
 
-static struct parisc_driver snd_card_harmony_driver = {
-	.name		= "Lasi ALSA Harmony",
-	.id_table	= snd_card_harmony_devicetbl,
-	.probe		= snd_card_harmony_probe,
+static struct parisc_driver snd_harmony_driver = {
+	.name = "harmony",
+	.id_table = snd_harmony_devtable,
+	.probe = snd_harmony_probe,
+	.remove = snd_harmony_remove,
 };
 
-static int __init alsa_card_harmony_init(void)
+static int __init 
+alsa_harmony_init(void)
 {
 	int err;
-	
-	if ((err = register_parisc_driver(&snd_card_harmony_driver)) < 0) {
-		printk(KERN_ERR "Harmony soundcard not found or device busy\n");
+
+	err = register_parisc_driver(&snd_harmony_driver);
+	if (err < 0) {
+		printk(KERN_ERR PFX "device not found\n");
 		return err;
 	}
 
 	return 0;
 }
 
-static void __exit alsa_card_harmony_exit(void)
+static void __exit
+alsa_harmony_fini(void)
 {
-	int idx;
-	snd_card_harmony_t *harmony;
+	int err;
+
+	err = unregister_parisc_driver(&snd_harmony_driver);
+	if (err < 0) {
+		printk(KERN_ERR PFX "failed to unregister\n");
+	}
 	
-	for (idx = 0; idx < SNDRV_CARDS; idx++)
-	{
-		if (snd_harmony_cards[idx] != NULL)
-		{	
-			DPRINTK(KERN_INFO PFX "Freeing card %d\n", idx);
-			harmony = snd_harmony_cards[idx]->private_data;
-			free_irq(harmony->irq, harmony);
-			printk(KERN_INFO PFX "Card unloaded %d, irq=%d\n", idx, harmony->irq);
-			snd_card_free(snd_harmony_cards[idx]);
-		}
-	}	
-	if (unregister_parisc_driver(&snd_card_harmony_driver) < 0)
-		printk(KERN_ERR PFX "Failed to unregister Harmony driver\n");
+	return;
 }
 
-module_init(alsa_card_harmony_init)
-module_exit(alsa_card_harmony_exit)
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
+MODULE_DESCRIPTION("Harmony sound driver");
+
+module_init(alsa_harmony_init);
+module_exit(alsa_harmony_fini);
diff --git a/sound/parisc/harmony.h b/sound/parisc/harmony.h
new file mode 100644
--- /dev/null
+++ b/sound/parisc/harmony.h
@@ -0,0 +1,151 @@
+/* Hewlett-Packard Harmony audio driver
+ * Copyright (C) 2004, Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef __HARMONY_H__
+#define __HARMONY_H__
+
+struct harmony_buffer {
+        unsigned long addr;
+        int buf;
+        int count;
+        int size;
+        int coherent;
+};
+
+typedef struct snd_card_harmony {
+        int irq;
+
+        unsigned long hpa; /* hard physical address */
+        void __iomem *iobase; /* remapped io address */
+
+        struct parisc_device *dev;
+
+        struct {
+                u32 gain;
+                u32 rate;
+                u32 format;
+                u32 stereo;
+		int playing;
+		int capturing;
+        } st;
+
+        struct snd_dma_device dma; /* playback/capture */
+        struct harmony_buffer pbuf;
+	struct harmony_buffer cbuf;
+
+        struct snd_dma_buffer gdma; /* graveyard */
+        struct snd_dma_buffer sdma; /* silence */
+
+        struct {
+                unsigned long play_intr;
+	        unsigned long rec_intr;
+                unsigned long graveyard_intr;
+                unsigned long silence_intr;
+        } stats;
+
+        snd_pcm_t *pcm;
+        snd_card_t *card;
+        snd_pcm_substream_t *psubs;
+	snd_pcm_substream_t *csubs;
+        snd_info_entry_t *proc;
+
+        spinlock_t lock;
+        spinlock_t mixer_lock;
+} harmony_t;
+
+#define MAX_PCM_DEVICES     1
+#define MAX_PCM_SUBSTREAMS  4
+#define MAX_MIDI_DEVICES    0
+
+#define HARMONY_SIZE       64
+
+#define BUF_SIZE     PAGE_SIZE
+#define MAX_BUFS     10
+#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE)
+
+#define PLAYBACK_BUFS    MAX_BUFS
+#define RECORD_BUFS      MAX_BUFS
+#define GRAVEYARD_BUFS   1
+#define GRAVEYARD_BUFSZ  (GRAVEYARD_BUFS*BUF_SIZE)
+#define SILENCE_BUFS     1
+#define SILENCE_BUFSZ    (SILENCE_BUFS*BUF_SIZE)
+
+#define HARMONY_ID       0x000
+#define HARMONY_RESET    0x004
+#define HARMONY_CNTL     0x008
+#define HARMONY_GAINCTL  0x00c
+#define HARMONY_PNXTADD  0x010
+#define HARMONY_PCURADD  0x014
+#define HARMONY_RNXTADD  0x018
+#define HARMONY_RCURADD  0x01c
+#define HARMONY_DSTATUS  0x020
+#define HARMONY_OV       0x024
+#define HARMONY_PIO      0x028
+#define HARMONY_DIAG     0x03c
+
+#define HARMONY_CNTL_C          0x80000000
+#define HARMONY_CNTL_ST         0x00000020
+#define HARMONY_CNTL_44100      0x00000015      /* HARMONY_SR_44KHZ */
+#define HARMONY_CNTL_8000       0x00000008      /* HARMONY_SR_8KHZ */
+
+#define HARMONY_DSTATUS_ID      0x00000000 /* interrupts off */
+#define HARMONY_DSTATUS_PN      0x00000200 /* playback fill */
+#define HARMONY_DSTATUS_RN      0x00000002 /* record fill */
+#define HARMONY_DSTATUS_IE      0x80000000 /* interrupts on */
+
+#define HARMONY_DF_16BIT_LINEAR 0x00000000
+#define HARMONY_DF_8BIT_ULAW    0x00000001
+#define HARMONY_DF_8BIT_ALAW    0x00000002
+
+#define HARMONY_SS_MONO         0x00000000
+#define HARMONY_SS_STEREO       0x00000001
+
+#define HARMONY_GAIN_SILENCE    0x00F00FFF
+#define HARMONY_GAIN_DEFAULT    0x0FF00000
+
+#define HARMONY_GAIN_HE_SHIFT   27
+#define HARMONY_GAIN_HE_MASK    (1 << HARMONY_GAIN_HE_SHIFT)
+#define HARMONY_GAIN_LE_SHIFT   26
+#define HARMONY_GAIN_LE_MASK    (1 << HARMONY_GAIN_LE_SHIFT)
+#define HARMONY_GAIN_SE_SHIFT   25
+#define HARMONY_GAIN_SE_MASK    (1 << HARMONY_GAIN_SE_SHIFT)
+#define HARMONY_GAIN_IS_SHIFT   24
+#define HARMONY_GAIN_IS_MASK    (1 << HARMONY_GAIN_IS_SHIFT)
+
+#define HARMONY_GAIN_MA         0x0f
+#define HARMONY_GAIN_MA_SHIFT   20
+#define HARMONY_GAIN_MA_MASK    (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT)
+
+#define HARMONY_GAIN_IN         0x0f
+#define HARMONY_GAIN_LI_SHIFT   16
+#define HARMONY_GAIN_LI_MASK    (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT)
+#define HARMONY_GAIN_RI_SHIFT   12
+#define HARMONY_GAIN_RI_MASK    (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT)
+
+#define HARMONY_GAIN_OUT        0x3f
+#define HARMONY_GAIN_LO_SHIFT   6
+#define HARMONY_GAIN_LO_MASK    (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT)
+#define HARMONY_GAIN_RO_SHIFT   0
+#define HARMONY_GAIN_RO_MASK    (HARMONY_GAIN_OUT << HARMONY_GAIN_RO_SHIFT)
+
+#define HARMONY_MAX_OUT (HARMONY_GAIN_RO_MASK >> HARMONY_GAIN_RO_SHIFT)
+#define HARMONY_MAX_IN  (HARMONY_GAIN_RI_MASK >> HARMONY_GAIN_RI_SHIFT)
+#define HARMONY_MAX_MON (HARMONY_GAIN_MA_MASK >> HARMONY_GAIN_MA_SHIFT)
+
+#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
+
+#endif /* __HARMONY_H__ */
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -514,5 +514,15 @@ config SND_VX222
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-vx222.
 
-endmenu
+config SND_HDA_INTEL
+	tristate "Intel HD Audio"
+	depends on SND
+	select SND_PCM
+	help
+	  Say Y here to include support for Intel "High Definition
+	  Audio" (Azalia) motherboard devices.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-intel.
 
+endmenu
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_SND) += \
 	ca0106/ \
 	cs46xx/ \
 	emu10k1/ \
+	hda/ \
 	ice1712/ \
 	korg1212/ \
 	mixart/ \
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -56,6 +56,7 @@ typedef struct {
 	const char *name;
 	int (*patch)(ac97_t *ac97);
 	int (*mpatch)(ac97_t *ac97);
+	unsigned int flags;
 } ac97_codec_id_t;
 
 static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
@@ -103,8 +104,9 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x41445372, 0xffffffff, "AD1981A",		patch_ad1981a,	NULL },
 { 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },
 { 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },
-{ 0x414c4300, 0xffffff00, "ALC100/100P", 	NULL,		NULL },
-{ 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL,		NULL },
+{ 0x41445378, 0xffffffff, "AD1986",		patch_ad1985,	NULL },
+{ 0x414c4300, 0xffffff00, "ALC100,100P", 	NULL,		NULL },
+{ 0x414c4710, 0xfffffff0, "ALC200,200P",	NULL,		NULL },
 { 0x414c4721, 0xffffffff, "ALC650D",		NULL,	NULL }, /* already patched */
 { 0x414c4722, 0xffffffff, "ALC650E",		NULL,	NULL }, /* already patched */
 { 0x414c4723, 0xffffffff, "ALC650F",		NULL,	NULL }, /* already patched */
@@ -143,11 +145,11 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x49434552, 0xffffffff, "VT1616i",		patch_vt1616,	NULL }, // VT1616 compatible (chipset integrated)
 { 0x49544520, 0xffffffff, "IT2226E",		NULL,		NULL },
 { 0x49544561, 0xffffffff, "IT2646E",		patch_it2646,	NULL },
-{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48",	NULL,		NULL }, // only guess --jk
+{ 0x4e534300, 0xffffffff, "LM4540,43,45,46,48",	NULL,		NULL }, // only guess --jk
 { 0x4e534331, 0xffffffff, "LM4549",		NULL,		NULL },
 { 0x4e534350, 0xffffffff, "LM4550",		NULL,		NULL },
 { 0x50534304, 0xffffffff, "UCB1400",		NULL,		NULL },
-{ 0x53494c20, 0xffffffe0, "Si3036/8",		NULL,		mpatch_si3036 },
+{ 0x53494c20, 0xffffffe0, "Si3036,8",		NULL,		mpatch_si3036 },
 { 0x54524102, 0xffffffff, "TR28022",		NULL,		NULL },
 { 0x54524106, 0xffffffff, "TR28026",		NULL,		NULL },
 { 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028,	NULL }, // added by xin jin [07/09/99]
@@ -156,25 +158,26 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",		NULL,		NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",		NULL,		NULL },
-{ 0x574d4C03, 0xffffffff, "WM9703/WM9707/WM9708/WM9717", patch_wolfson03, NULL},
-{ 0x574d4C04, 0xffffffff, "WM9704M/WM9704Q",	patch_wolfson04, NULL},
-{ 0x574d4C05, 0xffffffff, "WM9705/WM9710",	patch_wolfson05, NULL},
+{ 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
+{ 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q",	patch_wolfson04, NULL},
+{ 0x574d4C05, 0xffffffff, "WM9705,WM9710",	patch_wolfson05, NULL},
 { 0x574d4C09, 0xffffffff, "WM9709",		NULL,		NULL},
-{ 0x574d4C12, 0xffffffff, "WM9711/WM9712",	patch_wolfson11, NULL},
+{ 0x574d4C12, 0xffffffff, "WM9711,WM9712",	patch_wolfson11, NULL},
+{ 0x574d4c13, 0xffffffff, "WM9713,WM9714",	patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF},
 { 0x594d4800, 0xffffffff, "YMF743",		NULL,		NULL },
 { 0x594d4802, 0xffffffff, "YMF752",		NULL,		NULL },
 { 0x594d4803, 0xffffffff, "YMF753",		patch_yamaha_ymf753,	NULL },
-{ 0x83847600, 0xffffffff, "STAC9700/83/84",	patch_sigmatel_stac9700,	NULL },
-{ 0x83847604, 0xffffffff, "STAC9701/3/4/5",	NULL,		NULL },
+{ 0x83847600, 0xffffffff, "STAC9700,83,84",	patch_sigmatel_stac9700,	NULL },
+{ 0x83847604, 0xffffffff, "STAC9701,3,4,5",	NULL,		NULL },
 { 0x83847605, 0xffffffff, "STAC9704",		NULL,		NULL },
-{ 0x83847608, 0xffffffff, "STAC9708/11",	patch_sigmatel_stac9708,	NULL },
-{ 0x83847609, 0xffffffff, "STAC9721/23",	patch_sigmatel_stac9721,	NULL },
+{ 0x83847608, 0xffffffff, "STAC9708,11",	patch_sigmatel_stac9708,	NULL },
+{ 0x83847609, 0xffffffff, "STAC9721,23",	patch_sigmatel_stac9721,	NULL },
 { 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744,	NULL },
-{ 0x83847650, 0xffffffff, "STAC9750/51",	NULL,		NULL },	// patch?
-{ 0x83847652, 0xffffffff, "STAC9752/53",	NULL,		NULL }, // patch?
-{ 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756,	NULL },
-{ 0x83847658, 0xffffffff, "STAC9758/59",	patch_sigmatel_stac9758,	NULL },
-{ 0x83847666, 0xffffffff, "STAC9766/67",	NULL,		NULL }, // patch?
+{ 0x83847650, 0xffffffff, "STAC9750,51",	NULL,		NULL },	// patch?
+{ 0x83847652, 0xffffffff, "STAC9752,53",	NULL,		NULL }, // patch?
+{ 0x83847656, 0xffffffff, "STAC9756,57",	patch_sigmatel_stac9756,	NULL },
+{ 0x83847658, 0xffffffff, "STAC9758,59",	patch_sigmatel_stac9758,	NULL },
+{ 0x83847666, 0xffffffff, "STAC9766,67",	NULL,		NULL }, // patch?
 { 0, 	      0,	  NULL,			NULL,		NULL }
 };
 
@@ -438,111 +441,81 @@ static int snd_ac97_ad18xx_update_pcm_bi
 }
 
 /*
- *
+ * Controls
  */
 
-static int snd_ac97_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
-	static char *texts[8] = {
-		"Mic", "CD", "Video", "Aux", "Line",
-		"Mix", "Mix Mono", "Phone"
-	};
-
+	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
+	
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 2;
-	uinfo->value.enumerated.items = 8;
-	if (uinfo->value.enumerated.item > 7)
-		uinfo->value.enumerated.item = 7;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
+	uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
+	uinfo->value.enumerated.items = e->mask;
 	
-	val = snd_ac97_read_cache(ac97, AC97_REC_SEL);
-	ucontrol->value.enumerated.item[0] = (val >> 8) & 7;
-	ucontrol->value.enumerated.item[1] = (val >> 0) & 7;
+	if (uinfo->value.enumerated.item > e->mask - 1)
+		uinfo->value.enumerated.item = e->mask - 1;
+	strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]);
 	return 0;
 }
 
-static int snd_ac97_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
 	unsigned short val;
 	
-	if (ucontrol->value.enumerated.item[0] > 7 ||
-	    ucontrol->value.enumerated.item[1] > 7)
-		return -EINVAL;
-	val = (ucontrol->value.enumerated.item[0] << 8) |
-	      (ucontrol->value.enumerated.item[1] << 0);
-	return snd_ac97_update(ac97, AC97_REC_SEL, val);
-}
-
-#define AC97_ENUM_DOUBLE(xname, reg, shift, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_enum_double, \
-  .get = snd_ac97_get_enum_double, .put = snd_ac97_put_enum_double, \
-  .private_value = reg | (shift << 8) | (invert << 24) }
-
-static int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts1[2] = { "pre 3D", "post 3D" };
-	static char *texts2[2] = { "Mix", "Mic" };
-	static char *texts3[2] = { "Mic1", "Mic2" };
-	char **texts = NULL;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
+	val = snd_ac97_read_cache(ac97, e->reg);
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1);
+	if (e->shift_l != e->shift_r)
+		ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1);
 
-	switch (reg) {
-	case AC97_GENERAL_PURPOSE:
-		switch (shift) {
-		case 15: texts = texts1; break;
-		case 9: texts = texts2; break;
-		case 8: texts = texts3; break;
-		}
-	}
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	if (uinfo->value.enumerated.item > 1)
-		uinfo->value.enumerated.item = 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 	return 0;
 }
 
-static int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
 	unsigned short val;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
+	unsigned short mask;
 	
-	val = (snd_ac97_read_cache(ac97, reg) >> shift) & 1;
-	if (invert)
-		val ^= 1;
-	ucontrol->value.enumerated.item[0] = val;
-	return 0;
+	if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+		return -EINVAL;
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = (e->mask - 1) << e->shift_l;
+	if (e->shift_l != e->shift_r) {
+		if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+			return -EINVAL;
+		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+		mask |= (e->mask - 1) << e->shift_r;
+	}
+	return snd_ac97_update_bits(ac97, e->reg, mask, val);
+}
+
+/* save/restore ac97 v2.3 paging */
+static int snd_ac97_page_save(ac97_t *ac97, int reg, snd_kcontrol_t *kcontrol)
+{
+	int page_save = -1;
+	if ((kcontrol->private_value & (1<<25)) &&
+	    (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
+	    (reg >= 0x60 && reg < 0x70)) {
+		unsigned short page = (kcontrol->private_value >> 26) & 0x0f;
+		down(&ac97->page_mutex); /* lock paging */
+		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+	}
+	return page_save;
 }
 
-static int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void snd_ac97_page_restore(ac97_t *ac97, int page_save)
 {
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	
-	if (ucontrol->value.enumerated.item[0] > 1)
-		return -EINVAL;
-	val = !!ucontrol->value.enumerated.item[0];
-	if (invert)
-		val = !val;
-	return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift);
+	if (page_save >= 0) {
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+		up(&ac97->page_mutex); /* unlock paging */
+	}
 }
 
+/* volume and switch controls */
 int snd_ac97_info_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -564,7 +537,9 @@ int snd_ac97_get_volsw(snd_kcontrol_t * 
 	int rshift = (kcontrol->private_value >> 12) & 0x0f;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0x01;
-	
+	int page_save;
+
+	page_save = snd_ac97_page_save(ac97, reg, kcontrol);
 	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;
 	if (shift != rshift)
 		ucontrol->value.integer.value[1] = (snd_ac97_read_cache(ac97, reg) >> rshift) & mask;
@@ -573,6 +548,7 @@ int snd_ac97_get_volsw(snd_kcontrol_t * 
 		if (shift != rshift)
 			ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
 	}
+	snd_ac97_page_restore(ac97, page_save);
 	return 0;
 }
 
@@ -584,8 +560,10 @@ int snd_ac97_put_volsw(snd_kcontrol_t * 
 	int rshift = (kcontrol->private_value >> 12) & 0x0f;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0x01;
+	int err, page_save;
 	unsigned short val, val2, val_mask;
 	
+	page_save = snd_ac97_page_save(ac97, reg, kcontrol);
 	val = (ucontrol->value.integer.value[0] & mask);
 	if (invert)
 		val = mask - val;
@@ -598,48 +576,11 @@ int snd_ac97_put_volsw(snd_kcontrol_t * 
 		val_mask |= mask << rshift;
 		val |= val2 << rshift;
 	}
-	return snd_ac97_update_bits(ac97, reg, val_mask, val);
-}
-
-#define AC97_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_ac97_info_volsw, \
-  .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
-  .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
-
-static int snd_ac97_getput_page(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol,
-			 int (*func)(snd_kcontrol_t *, snd_ctl_elem_value_t *))
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int err;
-
-	if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
-	    (reg >= 0x60 && reg < 0x70)) {
-		unsigned short page_save;
-		unsigned short page = (kcontrol->private_value >> 25) & 0x0f;
-		down(&ac97->page_mutex); /* lock paging */
-		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
-		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
-		err = func(kcontrol, ucontrol);
-		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-		up(&ac97->page_mutex); /* unlock paging */
-	} else
-		err = func(kcontrol, ucontrol);
+	err = snd_ac97_update_bits(ac97, reg, val_mask, val);
+	snd_ac97_page_restore(ac97, page_save);
 	return err;
 }
 
-/* for rev2.3 paging */
-int snd_ac97_page_get_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_get_volsw);
-}
-
-/* for rev2.3 paging */
-int snd_ac97_page_put_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_put_volsw);
-}
-
 static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = {
 AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
 AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1)
@@ -659,14 +600,21 @@ static const snd_kcontrol_new_t snd_ac97
 	AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0);
 
 
-static const snd_kcontrol_new_t snd_ac97_control_capture_src = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Capture Source",
-	.info = snd_ac97_info_mux,
-	.get = snd_ac97_get_mux,
-	.put = snd_ac97_put_mux,
+static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"};
+static const char* std_3d_path[] = {"pre 3D", "post 3D"};
+static const char* std_mix[] = {"Mix", "Mic"};
+static const char* std_mic[] = {"Mic1", "Mic2"};
+
+static const struct ac97_enum std_enum[] = {
+AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, std_rec_sel),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, std_3d_path),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, std_mix),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, std_mic),
 };
 
+static const snd_kcontrol_new_t snd_ac97_control_capture_src = 
+AC97_ENUM("Capture Source", std_enum[0]); 
+
 static const snd_kcontrol_new_t snd_ac97_control_capture_vol =
 AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0);
 
@@ -686,12 +634,12 @@ typedef enum {
 } ac97_general_index_t;
 
 static const snd_kcontrol_new_t snd_ac97_controls_general[7] = {
-AC97_ENUM_DOUBLE("PCM Out Path & Mute", AC97_GENERAL_PURPOSE, 15, 0),
+AC97_ENUM("PCM Out Path & Mute", std_enum[1]),
 AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0),
 AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
 AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0),
-AC97_ENUM_DOUBLE("Mono Output Select", AC97_GENERAL_PURPOSE, 9, 0),
-AC97_ENUM_DOUBLE("Mic Select", AC97_GENERAL_PURPOSE, 8, 0),
+AC97_ENUM("Mono Output Select", std_enum[2]),
+AC97_ENUM("Mic Select", std_enum[3]),
 AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0)
 };
 
@@ -1185,7 +1133,7 @@ snd_kcontrol_t *snd_ac97_cnew(const snd_
 /*
  * create mute switch(es) for normal stereo controls
  */
-static int snd_ac97_cmute_new(snd_card_t *card, char *name, int reg, ac97_t *ac97)
+static int snd_ac97_cmute_new_stereo(snd_card_t *card, char *name, int reg, int check_stereo, ac97_t *ac97)
 {
 	snd_kcontrol_t *kctl;
 	int err;
@@ -1196,7 +1144,7 @@ static int snd_ac97_cmute_new(snd_card_t
 
 	mute_mask = 0x8000;
 	val = snd_ac97_read(ac97, reg);
-	if (ac97->flags & AC97_STEREO_MUTES) {
+	if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) {
 		/* check whether both mute bits work */
 		val1 = val | 0x8080;
 		snd_ac97_write(ac97, reg, val1);
@@ -1254,7 +1202,7 @@ static int snd_ac97_cvol_new(snd_card_t 
 /*
  * create a mute-switch and a volume for normal stereo/mono controls
  */
-static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, ac97_t *ac97)
+static int snd_ac97_cmix_new_stereo(snd_card_t *card, const char *pfx, int reg, int check_stereo, ac97_t *ac97)
 {
 	int err;
 	char name[44];
@@ -1265,7 +1213,7 @@ static int snd_ac97_cmix_new(snd_card_t 
 
 	if (snd_ac97_try_bit(ac97, reg, 15)) {
 		sprintf(name, "%s Switch", pfx);
-		if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0)
+		if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0)
 			return err;
 	}
 	check_volume_resolution(ac97, reg, &lo_max, &hi_max);
@@ -1277,6 +1225,8 @@ static int snd_ac97_cmix_new(snd_card_t 
 	return 0;
 }
 
+#define snd_ac97_cmix_new(card, pfx, reg, ac97)	snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97)
+#define snd_ac97_cmute_new(card, name, reg, ac97)	snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97)
 
 static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97);
 
@@ -1327,7 +1277,8 @@ static int snd_ac97_mixer_build(ac97_t *
 
 	/* build surround controls */
 	if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
-		if ((err = snd_ac97_cmix_new(card, "Surround Playback", AC97_SURROUND_MASTER, ac97)) < 0)
+		/* Surround Master (0x38) is with stereo mutes */
+		if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
 			return err;
 	}
 
@@ -1357,8 +1308,9 @@ static int snd_ac97_mixer_build(ac97_t *
 	}
 	
 	/* build PC Speaker controls */
-	if ((ac97->flags & AC97_HAS_PC_BEEP) ||
-	    snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP)) {
+	if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && 
+		((ac97->flags & AC97_HAS_PC_BEEP) ||
+	    snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
 		for (idx = 0; idx < 2; idx++)
 			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
 				return err;
@@ -1367,9 +1319,11 @@ static int snd_ac97_mixer_build(ac97_t *
 	}
 	
 	/* build Phone controls */
-	if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
-		if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
-			return err;
+	if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
+		if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
+			if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
+				return err;
+		}
 	}
 	
 	/* build MIC controls */
@@ -1387,15 +1341,19 @@ static int snd_ac97_mixer_build(ac97_t *
 	}
 	
 	/* build CD controls */
-	if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
-		if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
-			return err;
+	if (!(ac97->flags & AC97_HAS_NO_CD)) {
+		if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
+			if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
+				return err;
+		}
 	}
 	
 	/* build Video controls */
-	if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
-		if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
-			return err;
+	if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
+		if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
+			if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
+				return err;
+		}
 	}
 
 	/* build Aux controls */
@@ -1441,17 +1399,18 @@ static int snd_ac97_mixer_build(ac97_t *
 	}
 
 	/* build Capture controls */
-	if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
-		return err;
-	if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
-		if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)
+	if (!(ac97->flags & AC97_HAS_NO_REC_GAIN)) {
+		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
 			return err;
+		if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
+			if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)
+				return err;
+		}
+		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
+			return err;
+		snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
+		snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
 	}
-	if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
-		return err;
-	snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
-	snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
-
 	/* build MIC Capture controls */
 	if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {
 		for (idx = 0; idx < 2; idx++)
@@ -1527,7 +1486,7 @@ static int snd_ac97_mixer_build(ac97_t *
 	}
 
 	/* build S/PDIF controls */
-	if (ac97->ext_id & AC97_EI_SPDIF) {
+	if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) {
 		if (ac97->build_ops->build_spdif) {
 			if ((err = ac97->build_ops->build_spdif(ac97)) < 0)
 				return err;
@@ -1593,6 +1552,7 @@ static int snd_ac97_test_rate(ac97_t *ac
 static void snd_ac97_determine_rates(ac97_t *ac97, int reg, int shadow_reg, unsigned int *r_result)
 {
 	unsigned int result = 0;
+	unsigned short saved;
 
 	if (ac97->bus->no_vra) {
 		*r_result = SNDRV_PCM_RATE_48000;
@@ -1602,6 +1562,7 @@ static void snd_ac97_determine_rates(ac9
 		return;
 	}
 
+	saved = snd_ac97_read(ac97, reg);
 	if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE)
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
 				     AC97_EA_DRA, 0);
@@ -1640,6 +1601,10 @@ static void snd_ac97_determine_rates(ac9
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
 				     AC97_EA_DRA, 0);
 	}
+	/* restore the default value */
+	snd_ac97_write_cache(ac97, reg, saved);
+	if (shadow_reg)
+		snd_ac97_write_cache(ac97, shadow_reg, saved);
 	*r_result = result;
 }
 
@@ -1663,6 +1628,18 @@ static unsigned int snd_ac97_determine_s
 	return result;
 }
 
+/* look for the codec id table matching with the given id */
+static const ac97_codec_id_t *look_for_codec_id(const ac97_codec_id_t *table,
+						unsigned int id)
+{
+	const ac97_codec_id_t *pid;
+
+	for (pid = table; pid->id; pid++)
+		if (pid->id == (id & pid->mask))
+			return pid;
+	return NULL;
+}
+
 void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
 {
 	const ac97_codec_id_t *pid;
@@ -1671,35 +1648,30 @@ void snd_ac97_get_name(ac97_t *ac97, uns
 		printable(id >> 24),
 		printable(id >> 16),
 		printable(id >> 8));
-	for (pid = snd_ac97_codec_id_vendors; pid->id; pid++)
-		if (pid->id == (id & pid->mask)) {
-			strcpy(name, pid->name);
-			if (ac97) {
-				if (!modem && pid->patch)
-					pid->patch(ac97);
-				else if (modem && pid->mpatch)
-					pid->mpatch(ac97);
-			} 
-			goto __vendor_ok;
-		}
-	return;
+	pid = look_for_codec_id(snd_ac97_codec_id_vendors, id);
+	if (! pid)
+		return;
 
-      __vendor_ok:
-	for (pid = snd_ac97_codec_ids; pid->id; pid++)
-		if (pid->id == (id & pid->mask)) {
-			strcat(name, " ");
-			strcat(name, pid->name);
-			if (pid->mask != 0xffffffff)
-				sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
-			if (ac97) {
-				if (!modem && pid->patch)
-					pid->patch(ac97);
-				else if (modem && pid->mpatch)
-					pid->mpatch(ac97);
-			}
-			return;
+	strcpy(name, pid->name);
+	if (ac97 && pid->patch) {
+		if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
+		    (! modem && ! (pid->flags & AC97_MODEM_PATCH)))
+			pid->patch(ac97);
+	} 
+
+	pid = look_for_codec_id(snd_ac97_codec_ids, id);
+	if (pid) {
+		strcat(name, " ");
+		strcat(name, pid->name);
+		if (pid->mask != 0xffffffff)
+			sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
+		if (ac97 && pid->patch) {
+			if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
+			    (! modem && ! (pid->flags & AC97_MODEM_PATCH)))
+				pid->patch(ac97);
 		}
-	sprintf(name + strlen(name), " id %x", id & 0xff);
+	} else
+		sprintf(name + strlen(name), " id %x", id & 0xff);
 }
 
 /**
@@ -1841,6 +1813,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97
 	char name[64];
 	unsigned long end_time;
 	unsigned int reg;
+	const ac97_codec_id_t *pid;
 	static snd_device_ops_t ops = {
 		.dev_free =	snd_ac97_dev_free,
 	};
@@ -1891,6 +1864,14 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97
 		goto __access_ok;
 	}
 
+	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
+	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
+	if (ac97->id && ac97->id != (unsigned int)-1) {
+		pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);
+		if (pid && (pid->flags & AC97_DEFAULT_POWER_OFF))
+			goto __access_ok;
+	}
+
 	snd_ac97_write(ac97, AC97_RESET, 0);	/* reset to defaults */
 	if (bus->ops->wait)
 		bus->ops->wait(ac97);
@@ -1917,6 +1898,9 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97
 		snd_ac97_free(ac97);
 		return -EIO;
 	}
+	pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);
+	if (pid)
+		ac97->flags |= pid->flags;
 	
 	/* test for AC'97 */
 	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) {
@@ -1955,10 +1939,12 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97
 	if (ac97_is_audio(ac97)) {
 		/* nothing should be in powerdown mode */
 		snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);
-		snd_ac97_write_cache(ac97, AC97_RESET, 0);		/* reset to defaults */
-		udelay(100);
+		if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) {
+			snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */
+			udelay(100);
+			snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);
+		}
 		/* nothing should be in powerdown mode */
-		snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);
 		snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0);
 		end_time = jiffies + (HZ / 10);
 		do {
@@ -2225,9 +2211,11 @@ void snd_ac97_resume(ac97_t *ac97)
 	}
 
 	snd_ac97_write(ac97, AC97_POWERDOWN, 0);
-	snd_ac97_write(ac97, AC97_RESET, 0);
-	udelay(100);
-	snd_ac97_write(ac97, AC97_POWERDOWN, 0);
+	if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) {
+		snd_ac97_write(ac97, AC97_RESET, 0);
+		udelay(100);
+		snd_ac97_write(ac97, AC97_POWERDOWN, 0);
+	}
 	snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0);
 
 	snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
@@ -2331,6 +2319,35 @@ int snd_ac97_swap_ctl(ac97_t *ac97, cons
 	return -ENOENT;
 }
 
+#if 1
+/* bind hp and master controls instead of using only hp control */
+static int bind_hp_volsw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	int err = snd_ac97_put_volsw(kcontrol, ucontrol);
+	if (err > 0) {
+		unsigned long priv_saved = kcontrol->private_value;
+		kcontrol->private_value = (kcontrol->private_value & ~0xff) | AC97_HEADPHONE;
+		snd_ac97_put_volsw(kcontrol, ucontrol);
+		kcontrol->private_value = priv_saved;
+	}
+	return err;
+}
+
+/* ac97 tune: bind Master and Headphone controls */
+static int tune_hp_only(ac97_t *ac97)
+{
+	snd_kcontrol_t *msw = ctl_find(ac97, "Master Playback Switch", NULL);
+	snd_kcontrol_t *mvol = ctl_find(ac97, "Master Playback Volume", NULL);
+	if (! msw || ! mvol)
+		return -ENOENT;
+	msw->put = bind_hp_volsw_put;
+	mvol->put = bind_hp_volsw_put;
+	snd_ac97_remove_ctl(ac97, "Headphone Playback", "Switch");
+	snd_ac97_remove_ctl(ac97, "Headphone Playback", "Volume");
+	return 0;
+}
+
+#else
 /* ac97 tune: use Headphone control as master */
 static int tune_hp_only(ac97_t *ac97)
 {
@@ -2341,6 +2358,7 @@ static int tune_hp_only(ac97_t *ac97)
 	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
 	return 0;
 }
+#endif
 
 /* ac97 tune: swap Headphone and Master controls */
 static int tune_swap_hp(ac97_t *ac97)
@@ -2472,7 +2490,7 @@ static int apply_quirk_str(ac97_t *ac97,
 	}
 	/* for compatibility, accept the numbers, too */
 	if (*typestr >= '0' && *typestr <= '9')
-		return apply_quirk(ac97, (int)simple_strtol(typestr, NULL, 10));
+		return apply_quirk(ac97, (int)simple_strtoul(typestr, NULL, 10));
 	return -EINVAL;
 }
 
diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h
--- a/sound/pci/ac97/ac97_local.h
+++ b/sound/pci/ac97/ac97_local.h
@@ -23,15 +23,28 @@
  */
 
 #define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((shift) << 12) | ((mask) << 16) | ((invert) << 24))
-#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) (AC97_SINGLE_VALUE(reg,shift,mask,invert) | ((page) << 25))
+#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) (AC97_SINGLE_VALUE(reg,shift,mask,invert) | (1<<25) | ((page) << 26))
 #define AC97_SINGLE(xname, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_volsw, \
   .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
   .private_value =  AC97_SINGLE_VALUE(reg, shift, mask, invert) }
 #define AC97_PAGE_SINGLE(xname, reg, shift, mask, invert, page)		\
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_volsw, \
-  .get = snd_ac97_page_get_volsw, .put = snd_ac97_page_put_volsw, \
+  .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
   .private_value =  AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) }
+#define AC97_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_ac97_info_volsw, \
+  .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
+  .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
+#define AC97_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
+  .mask = xmask, .texts = xtexts }
+#define AC97_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
+	AC97_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
+#define AC97_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_enum_double, \
+  .get = snd_ac97_get_enum_double, .put = snd_ac97_put_enum_double, \
+  .private_value = (unsigned long)&xenum }
 
 /* ac97_codec.c */
 extern const char *snd_ac97_stereo_enhancements[];
@@ -42,8 +55,6 @@ void snd_ac97_get_name(ac97_t *ac97, uns
 int snd_ac97_info_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
 int snd_ac97_get_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
-int snd_ac97_page_get_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
-int snd_ac97_page_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit);
 int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix);
 int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix);
@@ -51,6 +62,9 @@ int snd_ac97_swap_ctl(ac97_t *ac97, cons
 void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst);
 void snd_ac97_restore_status(ac97_t *ac97);
 void snd_ac97_restore_iec958(ac97_t *ac97);
+int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 
 int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg,
 				unsigned short mask, unsigned short value);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -305,6 +305,136 @@ int patch_wolfson11(ac97_t * ac97)
 	return 0;
 }
 
+static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
+static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
+static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
+static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
+
+static const struct ac97_enum wm9713_enum[] = {
+AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
+AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
+AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
+AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
+AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
+AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
+AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
+AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
+AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
+AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
+AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
+AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
+AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
+AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
+AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
+AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
+AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
+AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
+AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
+AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
+AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
+AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
+AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
+AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
+AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
+AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
+AC97_ENUM("Record Select Left", wm9713_enum[3]),
+AC97_ENUM("Record Select Right", wm9713_enum[4]),
+};
+
+static int patch_wolfson_wm9713_specific(ac97_t * ac97)
+{
+	int err, i;
+	
+	for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
+		if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
+			return err;
+	}
+	snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
+	
+	for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
+		if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
+			return err;
+	}
+	snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
+	
+	for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
+		if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
+			return err;
+	}
+	snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
+	snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
+	
+	for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
+		if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
+			return err;
+	}
+	snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
+	
+	for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
+		if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
+			return err;
+	}
+	snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
+	snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
+	
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static void patch_wolfson_wm9713_suspend (ac97_t * ac97)
+{
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xfeff);
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xffff);
+}
+
+static void patch_wolfson_wm9713_resume (ac97_t * ac97)
+{
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
+	snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0);
+}
+#endif
+
+static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
+	.build_specific = patch_wolfson_wm9713_specific,
+#ifdef CONFIG_PM	
+	.suspend = patch_wolfson_wm9713_suspend,
+	.resume = patch_wolfson_wm9713_resume
+#endif
+};
+
+int patch_wolfson13(ac97_t * ac97)
+{
+	ac97->build_ops = &patch_wolfson_wm9713_ops;
+
+	ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
+		AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
+	snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
+	snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0);
+
+	return 0;
+}
+
 /*
  * Tritech codec
  */
@@ -392,9 +522,36 @@ int patch_sigmatel_stac9700(ac97_t * ac9
 	return 0;
 }
 
+static int snd_ac97_stac9708_put_bias(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int err;
+
+	down(&ac97->page_mutex);
+	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+	err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010,
+				   (ucontrol->value.integer.value[0] & 1) << 4);
+	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0);
+	up(&ac97->page_mutex);
+	return err;
+}
+
+static const snd_kcontrol_new_t snd_ac97_stac9708_bias_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Sigmatel Output Bias Switch",
+	.info = snd_ac97_info_volsw,
+	.get = snd_ac97_get_volsw,
+	.put = snd_ac97_stac9708_put_bias,
+	.private_value = AC97_SINGLE_VALUE(AC97_SIGMATEL_BIAS2, 4, 1, 0),
+};
+
 static int patch_sigmatel_stac9708_specific(ac97_t *ac97)
 {
+	int err;
+
 	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
+	if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
+		return err;
 	return patch_sigmatel_stac97xx_specific(ac97);
 }
 
@@ -1571,7 +1728,7 @@ static int alc655_iec958_route_put(snd_k
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 
 	return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12,
-				     (unsigned short)ucontrol->value.enumerated.item[0],
+				     (unsigned short)ucontrol->value.enumerated.item[0] << 12,
 				     0);
 }
 
@@ -2009,10 +2166,13 @@ int patch_cm9761(ac97_t *ac97)
 {
 	unsigned short val;
 
-	/* CM9761 has no Master and PCM volume although the register reacts */
-	ac97->flags |= AC97_HAS_NO_MASTER_VOL | AC97_HAS_NO_PCM_VOL;
-	snd_ac97_write_cache(ac97, AC97_MASTER, 0x8000);
-	snd_ac97_write_cache(ac97, AC97_PCM, 0x8000);
+	/* CM9761 has no PCM volume although the register reacts */
+	/* Master volume seems to have _some_ influence on the analog
+	 * input sounds
+	 */
+	ac97->flags |= /*AC97_HAS_NO_MASTER_VOL |*/ AC97_HAS_NO_PCM_VOL;
+	snd_ac97_write_cache(ac97, AC97_MASTER, 0x8808);
+	snd_ac97_write_cache(ac97, AC97_PCM, 0x8808);
 
 	ac97->spec.dev_flags = 0; /* 1 = model 82 revision B */
 	if (ac97->id == AC97_ID_CM9761_82) {
@@ -2032,7 +2192,8 @@ int patch_cm9761(ac97_t *ac97)
         ac97->ext_id |= AC97_EI_SPDIF;
 	/* to be sure: we overwrite the ext status bits */
 	snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0);
-	snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0209);
+	/* Don't set 0x0200 here.  This results in the silent analog output */
+	snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009);
 	ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
 
 	/* set-up multi channel */
@@ -2057,8 +2218,10 @@ int patch_cm9761(ac97_t *ac97)
 		val = 0x0214;
 	else
 		val = 0x321c;
-	snd_ac97_write_cache(ac97, AC97_CM9761_MULTI_CHAN, val);
 #endif
+	val = snd_ac97_read(ac97, AC97_CM9761_MULTI_CHAN);
+	val |= (1 << 4); /* front on */
+	snd_ac97_write_cache(ac97, AC97_CM9761_MULTI_CHAN, val);
 
 	/* FIXME: set up GPIO */
 	snd_ac97_write_cache(ac97, 0x70, 0x0100);
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -28,6 +28,7 @@ int patch_wolfson03(ac97_t * ac97);
 int patch_wolfson04(ac97_t * ac97);
 int patch_wolfson05(ac97_t * ac97);
 int patch_wolfson11(ac97_t * ac97);
+int patch_wolfson13(ac97_t * ac97);
 int patch_tritech_tr28028(ac97_t * ac97);
 int patch_sigmatel_stac9700(ac97_t * ac97);
 int patch_sigmatel_stac9708(ac97_t * ac97);
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -553,7 +553,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *p
 {
 	ac97_bus_t *bus;
 	int i, cidx, r, ok_flag;
-	unsigned int reg_ok = 0;
+	unsigned int reg_ok[4] = {0,0,0,0};
 	unsigned char reg;
 	int err = 0;
 
@@ -602,14 +602,14 @@ int snd_ac97_pcm_open(struct ac97_pcm *p
 					snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i);
 					continue;
 				}
-				if (reg_ok & (1 << (reg - AC97_PCM_FRONT_DAC_RATE)))
+				if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE)))
 					continue;
 				//printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate);
 				err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate);
 				if (err < 0)
 					snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err);
 				else
-					reg_ok |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE));
+					reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE));
 			}
 		}
 	}
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -188,7 +188,7 @@ typedef struct snd_ali_channel_control {
 
 struct snd_ali_stru_voice {
 	unsigned int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
 	    midi: 1,
 	    mode: 1,
@@ -199,7 +199,7 @@ struct snd_ali_stru_voice {
 	snd_pcm_substream_t *substream;
 	snd_ali_voice_t *extra;
 	
-	int running: 1;
+	unsigned int running: 1;
 
 	int eso;                /* final ESO value for channel */
 	int count;              /* runtime->period_size */
@@ -1894,7 +1894,7 @@ static int __devinit snd_ali_mixer(ali_t
 }
 
 #ifdef CONFIG_PM
-static int ali_suspend(snd_card_t *card, unsigned int state)
+static int ali_suspend(snd_card_t *card, pm_message_t state)
 {
 	ali_t *chip = card->pm_private_data;
 	ali_image_t *im;
@@ -1936,7 +1936,7 @@ static int ali_suspend(snd_card_t *card,
 	return 0;
 }
 
-static int ali_resume(snd_card_t *card, unsigned int state)
+static int ali_resume(snd_card_t *card)
 {
 	ali_t *chip = card->pm_private_data;
 	ali_image_t *im;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -104,8 +104,7 @@ typedef struct {
 	struct pci_dev *pci;
 	unsigned long gcr;
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 } snd_card_als4000_t;
 
@@ -566,21 +565,80 @@ static void __devinit snd_als4000_config
 	spin_unlock_irq(&chip->reg_lock);
 }
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_als4000_create_gameport(snd_card_als4000_t *acard, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+	int io_port;
+
+	if (joystick_port[dev] == 0)
+		return -ENODEV;
+
+	if (joystick_port[dev] == 1) { /* auto-detect */
+		for (io_port = 0x200; io_port <= 0x218; io_port += 8) {
+			r = request_region(io_port, 8, "ALS4000 gameport");
+			if (r)
+				break;
+		}
+	} else {
+		io_port = joystick_port[dev];
+		r = request_region(io_port, 8, "ALS4000 gameport");
+	}
+
+	if (!r) {
+		printk(KERN_WARNING "als4000: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	acard->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "als4000: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ALS4000 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(acard->pci));
+	gameport_set_dev_parent(gp, &acard->pci->dev);
+	gp->io = io_port;
+	gameport_set_port_data(gp, r);
+
+	/* Enable legacy joystick port */
+	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+
+	gameport_register_port(acard->gameport);
+
+	return 0;
+}
+
+static void snd_als4000_free_gameport(snd_card_als4000_t *acard)
+{
+	if (acard->gameport) {
+		struct resource *r = gameport_get_port_data(acard->gameport);
+
+		gameport_unregister_port(acard->gameport);
+		acard->gameport = NULL;
+
+		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_als4000_create_gameport(snd_card_als4000_t *acard, int dev) { return -ENOSYS; }
+static inline void snd_als4000_free_gameport(snd_card_als4000_t *acard) { }
+#endif
+
 static void snd_card_als4000_free( snd_card_t *card )
 {
 	snd_card_als4000_t * acard = (snd_card_als4000_t *)card->private_data;
+
 	/* make sure that interrupts are disabled */
 	snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0);
 	/* free resources */
-#ifdef SUPPORT_JOYSTICK
-	if (acard->res_joystick) {
-		if (acard->gameport.io)
-			gameport_unregister_port(&acard->gameport);
-		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
-		release_resource(acard->res_joystick);
-		kfree_nocheck(acard->res_joystick);
-	}
-#endif
+	snd_als4000_free_gameport(acard);
 	pci_release_regions(acard->pci);
 	pci_disable_device(acard->pci);
 }
@@ -596,7 +654,6 @@ static int __devinit snd_card_als4000_pr
 	opl3_t *opl3;
 	unsigned short word;
 	int err;
-	int joystick = 0;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
@@ -640,26 +697,9 @@ static int __devinit snd_card_als4000_pr
 	acard->gcr = gcr;
 	card->private_free = snd_card_als4000_free;
 
-	/* disable all legacy ISA stuff except for joystick */
-#ifdef SUPPORT_JOYSTICK
-	if (joystick_port[dev] == 1) {
-		/* auto-detect */
-		long p;
-		for (p = 0x200; p <= 0x218; p += 8) {
-			if ((acard->res_joystick = request_region(p, 8, "ALS4000 gameport")) != NULL) {
-				joystick_port[dev] = p;
-				break;
-			}
-		}
-	} else if (joystick_port[dev] > 0)
-		acard->res_joystick = request_region(joystick_port[dev], 8, "ALS4000 gameport");
-	if (acard->res_joystick)
-		joystick = joystick_port[dev];
-	else
-		joystick = 0;
-#endif
-	snd_als4000_set_addr(gcr, 0, 0, 0, joystick);
-	
+	/* disable all legacy ISA stuff */
+	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0);
+
 	if ((err = snd_sbdsp_create(card,
 				    gcr + 0x10,
 				    pci->irq,
@@ -711,12 +751,7 @@ static int __devinit snd_card_als4000_pr
 		}
 	}
 
-#ifdef SUPPORT_JOYSTICK
-	if (acard->res_joystick) {
-		acard->gameport.io = joystick;
-		gameport_register_port(&acard->gameport);
-	}
-#endif
+	snd_als4000_create_gameport(acard, dev);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -250,6 +250,7 @@ struct snd_atiixp_dma {
 	int running;
 	int pcm_open_flag;
 	int ac97_pcm_type;	/* index # of ac97_pcm to access, -1 = not used */
+	unsigned int saved_curptr;
 };
 
 /*
@@ -1375,6 +1376,8 @@ static int __devinit snd_atiixp_mixer_ne
 		ac97.pci = chip->pci;
 		ac97.num = i;
 		ac97.scaps = AC97_SCAP_SKIP_MODEM;
+		if (! chip->spdif_over_aclink)
+			ac97.scaps |= AC97_SCAP_NO_SPDIF;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
 			chip->ac97[i] = NULL; /* to be sure */
 			snd_printdd("atiixp: codec %d not available for audio\n", i);
@@ -1398,14 +1401,18 @@ static int __devinit snd_atiixp_mixer_ne
 /*
  * power management
  */
-static int snd_atiixp_suspend(snd_card_t *card, unsigned int state)
+static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state)
 {
 	atiixp_t *chip = card->pm_private_data;
 	int i;
 
 	for (i = 0; i < NUM_ATI_PCMDEVS; i++)
-		if (chip->pcmdevs[i])
+		if (chip->pcmdevs[i]) {
+			atiixp_dma_t *dma = &chip->dmas[i];
+			if (dma->substream && dma->running)
+				dma->saved_curptr = readl(chip->remap_addr + dma->ops->dt_cur);
 			snd_pcm_suspend_all(chip->pcmdevs[i]);
+		}
 	for (i = 0; i < NUM_ATI_CODECS; i++)
 		if (chip->ac97[i])
 			snd_ac97_suspend(chip->ac97[i]);
@@ -1417,7 +1424,7 @@ static int snd_atiixp_suspend(snd_card_t
 	return 0;
 }
 
-static int snd_atiixp_resume(snd_card_t *card, unsigned int state)
+static int snd_atiixp_resume(snd_card_t *card)
 {
 	atiixp_t *chip = card->pm_private_data;
 	int i;
@@ -1433,6 +1440,17 @@ static int snd_atiixp_resume(snd_card_t 
 		if (chip->ac97[i])
 			snd_ac97_resume(chip->ac97[i]);
 
+	for (i = 0; i < NUM_ATI_PCMDEVS; i++)
+		if (chip->pcmdevs[i]) {
+			atiixp_dma_t *dma = &chip->dmas[i];
+			if (dma->substream && dma->running) {
+				dma->ops->enable_dma(chip, 1);
+				writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
+				       chip->remap_addr + dma->ops->llp_offset);
+				writel(dma->saved_curptr, chip->remap_addr + dma->ops->dt_cur);
+			}
+		}
+
 	return 0;
 }
 #endif /* CONFIG_PM */
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -39,7 +39,7 @@ MODULE_DESCRIPTION("ATI IXP MC97 control
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
@@ -606,21 +606,20 @@ static snd_pcm_uframes_t snd_atiixp_pcm_
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data;
 	unsigned int curptr;
+	int timeout = 1000;
 
-	spin_lock(&chip->reg_lock);
-	curptr = readl(chip->remap_addr + dma->ops->dt_cur);
-	if (curptr < dma->buf_addr) {
-		snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr);
-		curptr = 0;
-	} else {
+	while (timeout--) {
+		curptr = readl(chip->remap_addr + dma->ops->dt_cur);
+		if (curptr < dma->buf_addr)
+			continue;
 		curptr -= dma->buf_addr;
-		if (curptr >= dma->buf_bytes) {
-			snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes);
-			curptr = 0;
-		}
+		if (curptr >= dma->buf_bytes)
+			continue;
+		return bytes_to_frames(runtime, curptr);
 	}
-	spin_unlock(&chip->reg_lock);
-	return bytes_to_frames(runtime, curptr);
+	snd_printd("atiixp-modem: invalid DMA pointer read 0x%x (buf=%x)\n",
+		   readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
+	return 0;
 }
 
 /*
@@ -1108,7 +1107,7 @@ static int __devinit snd_atiixp_mixer_ne
 /*
  * power management
  */
-static int snd_atiixp_suspend(snd_card_t *card, unsigned int state)
+static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state)
 {
 	atiixp_t *chip = card->pm_private_data;
 	int i;
@@ -1122,18 +1121,18 @@ static int snd_atiixp_suspend(snd_card_t
 	snd_atiixp_aclink_down(chip);
 	snd_atiixp_chip_stop(chip);
 
-	pci_set_power_state(chip->pci, 3);
+	pci_set_power_state(chip->pci, PCI_D3hot);
 	pci_disable_device(chip->pci);
 	return 0;
 }
 
-static int snd_atiixp_resume(snd_card_t *card, unsigned int state)
+static int snd_atiixp_resume(snd_card_t *card)
 {
 	atiixp_t *chip = card->pm_private_data;
 	int i;
 
 	pci_enable_device(chip->pci);
-	pci_set_power_state(chip->pci, 0);
+	pci_set_power_state(chip->pci, PCI_D0);
 	pci_set_master(chip->pci);
 
 	snd_atiixp_aclink_reset(chip);
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -290,10 +290,9 @@ snd_vortex_probe(struct pci_dev *pci, co
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = vortex_gameport_register(chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+
+	vortex_gameport_register(chip);
+
 #if 0
 	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
 			       sizeof(snd_vortex_synth_arg_t), &wave) < 0
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -272,7 +272,7 @@ static void vortex_Vort3D_InitializeSour
 
 /* Driver stuff. */
 static int __devinit vortex_gameport_register(vortex_t * card);
-static int __devexit vortex_gameport_unregister(vortex_t * card);
+static void vortex_gameport_unregister(vortex_t * card);
 #ifndef CHIP_AU8820
 static int __devinit vortex_eq_init(vortex_t * vortex);
 static int __devexit vortex_eq_free(vortex_t * vortex);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2480,7 +2480,8 @@ static void vortex_codec_init(vortex_t *
 	int i;
 
 	for (i = 0; i < 32; i++) {
-		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0);
+		/* the windows driver writes -i, so we write -i */
+		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), -i);
 		msleep(2);
 	}
 	if (0) {
@@ -2502,7 +2503,7 @@ static void vortex_codec_init(vortex_t *
 		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8);
 	}
 	for (i = 0; i < 32; i++) {
-		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0);
+		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), -i);
 		msleep(5);
 	}
 	hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0xe8);
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
--- a/sound/pci/au88x0/au88x0_game.c
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -44,20 +44,20 @@
 
 static unsigned char vortex_game_read(struct gameport *gameport)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport_get_port_data(gameport);
 	return hwread(vortex->mmio, VORTEX_GAME_LEGACY);
 }
 
 static void vortex_game_trigger(struct gameport *gameport)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport_get_port_data(gameport);
 	hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff);
 }
 
 static int
 vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport_get_port_data(gameport);
 	int i;
 
 	*buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf;
@@ -73,7 +73,7 @@ vortex_game_cooked_read(struct gameport 
 
 static int vortex_game_open(struct gameport *gameport, int mode)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport_get_port_data(gameport);
 
 	switch (mode) {
 	case GAMEPORT_MODE_COOKED:
@@ -94,40 +94,42 @@ static int vortex_game_open(struct gamep
 	return 0;
 }
 
-static int vortex_gameport_register(vortex_t * vortex)
+static int __devinit vortex_gameport_register(vortex_t * vortex)
 {
-	if ((vortex->gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL)) == NULL) {
-		return -1;
+	struct gameport *gp;
+
+	vortex->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
+		return -ENOMEM;
 	};
-	
-	vortex->gameport->driver = vortex;
-	vortex->gameport->fuzz = 64;
-
-	vortex->gameport->read = vortex_game_read;
-	vortex->gameport->trigger = vortex_game_trigger;
-	vortex->gameport->cooked_read = vortex_game_cooked_read;
-	vortex->gameport->open = vortex_game_open;
-
-	gameport_register_port((struct gameport *)vortex->gameport);
-
-/*	printk(KERN_INFO "gameport%d: %s at speed %d kHz\n",
-		vortex->gameport->number, vortex->pci_dev->name, vortex->gameport->speed);
-*/
+
+	gameport_set_name(gp, "AU88x0 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev));
+	gameport_set_dev_parent(gp, &vortex->pci_dev->dev);
+
+	gp->read = vortex_game_read;
+	gp->trigger = vortex_game_trigger;
+	gp->cooked_read = vortex_game_cooked_read;
+	gp->open = vortex_game_open;
+
+	gameport_set_port_data(gp, vortex);
+	gp->fuzz = 64;
+
+	gameport_register_port(gp);
+
 	return 0;
 }
 
-static int vortex_gameport_unregister(vortex_t * vortex)
+static void vortex_gameport_unregister(vortex_t * vortex)
 {
-	if (vortex->gameport != NULL) {
+	if (vortex->gameport) {
 		gameport_unregister_port(vortex->gameport);
-		kfree(vortex->gameport);
+		vortex->gameport = NULL;
 	}
-	return 0;
 }
 
 #else
-
-static inline int vortex_gameport_register(vortex_t * vortex) { return 0; }
-static inline int vortex_gameport_unregister(vortex_t * vortex) { return 0; }
-
+static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; }
+static inline void vortex_gameport_unregister(vortex_t * vortex) { }
 #endif
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -26,6 +26,7 @@ static int __devinit snd_vortex_mixer(vo
 	memset(&ac97, 0, sizeof(ac97));
 	// Intialize AC97 codec stuff.
 	ac97.private_data = vortex;
+	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
 	vortex->isquad = ((vortex->codec == NULL) ?  0 : (vortex->codec->ext_id&0x80));
 	return err;
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -20,7 +20,7 @@
  * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
  * It remains stuck,and DMA transfers do not happen. 
  */
-
+#include <sound/asoundef.h>
 #include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
@@ -431,61 +431,77 @@ static char *vortex_pcm_name[VORTEX_PCM_
 };
 
 /* SPDIF kcontrol */
-static int
-snd_vortex_spdif_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[] = { "32000", "44100", "48000" };
 
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+static int snd_vortex_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-		uinfo->value.enumerated.item =
-		    uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name,
-	       texts[uinfo->value.enumerated.item]);
 	return 0;
 }
-static int
-snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 
-	if (vortex->spdif_sr == 32000)
-		ucontrol->value.enumerated.item[0] = 0;
-	if (vortex->spdif_sr == 44100)
-		ucontrol->value.enumerated.item[0] = 1;
-	if (vortex->spdif_sr == 48000)
-		ucontrol->value.enumerated.item[0] = 2;
+static int snd_vortex_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
 	return 0;
 }
-static int
-snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+
+static int snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
-	static unsigned int sr[3] = { 32000, 44100, 48000 };
+	ucontrol->value.iec958.status[0] = 0x00;
+	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
+	ucontrol->value.iec958.status[2] = 0x00;
+	switch (vortex->spdif_sr) {
+	case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
+	case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
+	case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
+	}
+	return 0;
+}
 
-	//printk("vortex: spdif sr = %d\n", ucontrol->value.enumerated.item[0]);
-	vortex->spdif_sr = sr[ucontrol->value.enumerated.item[0] % 3];
-	vortex_spdif_init(vortex,
-			  sr[ucontrol->value.enumerated.item[0] % 3], 1);
+static int snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int spdif_sr = 48000;
+	switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
+	case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
+	case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
+	case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
+	}
+	if (spdif_sr == vortex->spdif_sr)
+		return 0;
+	vortex->spdif_sr = spdif_sr;
+	vortex_spdif_init(vortex, vortex->spdif_sr, 1);
 	return 1;
 }
-static snd_kcontrol_new_t vortex_spdif_kcontrol __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "SPDIF SR",
-	.index = 0,
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-	.private_value = 0,
-	.info = snd_vortex_spdif_info,
-	.get = snd_vortex_spdif_get,
-	.put = snd_vortex_spdif_put
+
+/* spdif controls */
+static snd_kcontrol_new_t snd_vortex_mixer_spdif[] __devinitdata = {
+	{
+		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+		.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+		.info =		snd_vortex_spdif_info,
+		.get =		snd_vortex_spdif_get,
+		.put =		snd_vortex_spdif_put,
+	},
+	{
+		.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+		.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+		.info =		snd_vortex_spdif_info,
+		.get =		snd_vortex_spdif_mask_get
+	},
 };
 
 /* create a pcm device */
 static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr)
 {
 	snd_pcm_t *pcm;
+	snd_kcontrol_t *kctl;
+	int i;
 	int err, nr_capt;
 
 	if ((chip == 0) || (idx < 0) || (idx > VORTEX_PCM_LAST))
@@ -520,13 +536,13 @@ static int __devinit snd_vortex_new_pcm(
 					      0x10000, 0x10000);
 
 	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
-		snd_kcontrol_t *kcontrol;
-
-		if ((kcontrol =
-		     snd_ctl_new1(&vortex_spdif_kcontrol, chip)) == NULL)
-			return -ENOMEM;
-		if ((err = snd_ctl_add(chip->card, kcontrol)) < 0)
-			return err;
+		for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
+			kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
+			if (!kctl)
+				return -ENOMEM;
+			if ((err = snd_ctl_add(chip->card, kctl)) < 0)
+				return err;
+		}
 	}
 	return 0;
 }
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -160,19 +160,19 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF332
 #endif
 	    
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-#ifdef SUPPORT_JOYSTICK
-static int joystick[SNDRV_CARDS];
-#endif
-
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
+
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard.");
+
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard.");
+
 #ifdef SUPPORT_JOYSTICK
+static int joystick[SNDRV_CARDS];
 module_param_array(joystick, bool, NULL, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard.");
 #endif
@@ -189,8 +189,7 @@ struct _snd_azf3328 {
 	unsigned long mixer_port;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 
 	struct pci_dev *pci;
@@ -1222,6 +1221,63 @@ static int __devinit snd_azf3328_pcm(azf
 
 /******************************************************************/
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_azf3328_config_joystick(azf3328_t *chip, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) {
+		printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "AZF3328 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->io = 0x200;
+	gameport_set_port_data(gp, r);
+
+	snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+			      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+static void snd_azf3328_free_joystick(azf3328_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = gameport_get_port_data(chip->gameport);
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+		/* disable gameport */
+		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+				      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_azf3328_config_joystick(azf3328_t *chip, int dev) { return -ENOSYS; }
+static inline void snd_azf3328_free_joystick(azf3328_t *chip) { }
+#endif
+
+/******************************************************************/
+
 static int snd_azf3328_free(azf3328_t *chip)
 {
         if (chip->irq < 0)
@@ -1236,16 +1292,7 @@ static int snd_azf3328_free(azf3328_t *c
 
         synchronize_irq(chip->irq);
       __end_hw:
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick) {
-		gameport_unregister_port(&chip->gameport);
-		/* disable gameport */
-		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
-				      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
-		release_resource(chip->res_joystick);
-		kfree_nocheck(chip->res_joystick);
-	}
-#endif
+	snd_azf3328_free_joystick(chip);
         if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	pci_release_regions(chip->pci);
@@ -1373,28 +1420,6 @@ static int __devinit snd_azf3328_create(
 	return 0;
 }
 
-#ifdef SUPPORT_JOYSTICK
-static void __devinit snd_azf3328_config_joystick(azf3328_t *chip, int joystick)
-{
-	unsigned char val;
-
-	if (joystick == 1) {
-		if ((chip->res_joystick = request_region(0x200, 8, "AZF3328 gameport")) != NULL)
-			chip->gameport.io = 0x200;
-	}
-
-	val = inb(chip->io2_port + IDX_IO2_LEGACY_ADDR);
-	if (chip->res_joystick)
-		val |= LEGACY_JOY;
-	else
-		val &= ~LEGACY_JOY;
-
-	outb(val, chip->io2_port + IDX_IO2_LEGACY_ADDR);
-	if (chip->res_joystick)
-		gameport_register_port(&chip->gameport);
-}
-#endif
-
 static int __devinit snd_azf3328_probe(struct pci_dev *pci,
 					  const struct pci_device_id *pci_id)
 {
@@ -1465,9 +1490,9 @@ static int __devinit snd_azf3328_probe(s
 "azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n");
 #endif
 
-#ifdef SUPPORT_JOYSTICK
-	snd_azf3328_config_joystick(chip, joystick[dev]);
-#endif
+	if (snd_azf3328_config_joystick(chip, dev) < 0)
+		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+			      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
 
 	pci_set_drvdata(pci, card);
 	dev++;
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -41,7 +41,7 @@ MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
 		"{Brooktree,Bt879}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1,7 +1,7 @@
 /*
  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- *  Version: 0.0.21
+ *  Version: 0.0.22
  *
  *  FEATURES currently supported:
  *    Front, Rear and Center/LFE.
@@ -75,6 +75,8 @@
  *  0.0.21
  *    Add 4 capture channels. (SPDIF only comes in on channel 0. )
  *    Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.)
+ *  0.0.22
+ *    Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901
  *
  *  BUGS:
  *    Some stability problems when unloading the snd-ca0106 kernel module.
@@ -169,6 +171,7 @@ static ca0106_names_t ca0106_chip_names[
 	 { 0x10051102, "AudigyLS [SB0310b]"} , /* Unknown AudigyLS that also says SB0310 on it */
 	 { 0x10061102, "Live! 7.1 24bit [SB0410]"} , /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */
 	 { 0x10071102, "Live! 7.1 24bit [SB0413]"} , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
+	 { 0x10091462, "MSI K8N Diamond MB [SB0438]"}, /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
 	 { 0, "AudigyLS [Unknown]" }
 };
 
@@ -184,9 +187,9 @@ static snd_pcm_hardware_t snd_ca0106_pla
 	.rate_max =		192000,
 	.channels_min =		2,  //1,
 	.channels_max =		2,  //6,
-	.buffer_bytes_max =	(32*1024),
+	.buffer_bytes_max =	((65536 - 64) * 8),
 	.period_bytes_min =	64,
-	.period_bytes_max =	(16*1024),
+	.period_bytes_max =	(65536 - 64),
 	.periods_min =		2,
 	.periods_max =		8,
 	.fifo_size =		0,
@@ -203,9 +206,9 @@ static snd_pcm_hardware_t snd_ca0106_cap
 	.rate_max =		48000,
 	.channels_min =		2,
 	.channels_max =		2,
-	.buffer_bytes_max =	(32*1024),
+	.buffer_bytes_max =	((65536 - 64) * 8),
 	.period_bytes_min =	64,
-	.period_bytes_max =	(16*1024),
+	.period_bytes_max =	(65536 - 64),
 	.periods_min =		2,
 	.periods_max =		2,
 	.fifo_size =		0,
@@ -510,6 +513,8 @@ static int snd_ca0106_pcm_prepare_playba
 	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0);
 	snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);
 	snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
+	/* FIXME  test what 0 bytes does. */
+	snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes
 	snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0);
 	snd_ca0106_ptr_write(emu, 0x07, channel, 0x0);
 	snd_ca0106_ptr_write(emu, 0x08, channel, 0);
@@ -1133,7 +1138,9 @@ static int __devinit snd_ca0106_create(s
         snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
 	chip->capture_source = 3; /* Set CAPTURE_SOURCE */
 
-        if ((chip->serial == 0x10061102) || (chip->serial == 0x10071102) ) { /* The SB0410 and SB0413 use GPIO differently. */
+        if ((chip->serial == 0x10061102) || 
+	    (chip->serial == 0x10071102) ||
+	    (chip->serial == 0x10091462)) { /* The SB0410 and SB0413 use GPIO differently. */
 		/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
 		outl(0x0, chip->port+GPIO);
 		//outl(0x00f0e000, chip->port+GPIO); /* Analog */
@@ -1200,7 +1207,9 @@ static int __devinit snd_ca0106_probe(st
 		snd_card_free(card);
 		return err;
 	}
-        if ((chip->serial != 0x10061102) && (chip->serial != 0x10071102) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */
+        if ((chip->serial != 0x10061102) && 
+	    (chip->serial != 0x10071102) && 
+	    (chip->serial != 0x10091462) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */
 		if ((err = snd_ca0106_ac97(chip)) < 0) {
 			snd_card_free(card);
 			return err;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -156,6 +156,8 @@ MODULE_PARM_DESC(joystick_port, "Joystic
 #define CM_CHIP_MASK2		0xff000000
 #define CM_CHIP_039		0x04000000
 #define CM_CHIP_039_6CH		0x01000000
+#define CM_CHIP_055		0x08000000
+#define CM_CHIP_8768		0x20000000
 #define CM_TDMA_INT_EN		0x00040000
 #define CM_CH1_INT_EN		0x00020000
 #define CM_CH0_INT_EN		0x00010000
@@ -328,6 +330,13 @@ MODULE_PARM_DESC(joystick_port, "Joystic
 #define CM_REG_CH0_FRAME2	0x84
 #define CM_REG_CH1_FRAME1	0x88	/* 0-15: count of samples at bus master; buffer size */
 #define CM_REG_CH1_FRAME2	0x8C	/* 16-31: count of samples at codec; fragment size */
+#define CM_REG_MISC_CTRL_8768	0x92	/* reg. name the same as 0x18 */
+#define CM_CHB3D8C		0x20	/* 7.1 channels support */
+#define CM_SPD32FMT		0x10	/* SPDIF/IN 32k */
+#define CM_ADC2SPDIF		0x08	/* ADC output to SPDIF/OUT */
+#define CM_SHAREADC		0x04	/* DAC in ADC as Center/LFE */
+#define CM_REALTCMP		0x02	/* monitor the CMPL/CMPR of ADC */
+#define CM_INVLRCK		0x01	/* invert ZVPORT's LRCK */
 
 /*
  * size of i/o region
@@ -458,7 +467,7 @@ struct snd_stru_cmipci {
 	int opened[2];	/* open mode */
 	struct semaphore open_mutex;
 
-	int mixer_insensitive: 1;
+	unsigned int mixer_insensitive: 1;
 	snd_kcontrol_t *mixer_res_ctl[CM_SAVED_MIXERS];
 	int mixer_res_status[CM_SAVED_MIXERS];
 
@@ -471,8 +480,7 @@ struct snd_stru_cmipci {
 	snd_rawmidi_t *rmidi;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 
 	spinlock_t reg_lock;
@@ -674,7 +682,7 @@ static int snd_cmipci_hw_free(snd_pcm_su
 /*
  */
 
-static unsigned int hw_channels[] = {1, 2, 4, 5, 6};
+static unsigned int hw_channels[] = {1, 2, 4, 5, 6, 8};
 static snd_pcm_hw_constraint_list_t hw_constraints_channels_4 = {
 	.count = 3,
 	.list = hw_channels,
@@ -685,6 +693,11 @@ static snd_pcm_hw_constraint_list_t hw_c
 	.list = hw_channels,
 	.mask = 0,
 };
+static snd_pcm_hw_constraint_list_t hw_constraints_channels_8 = {
+	.count = 6,
+	.list = hw_channels,
+	.mask = 0,
+};
 
 static int set_dac_channels(cmipci_t *cm, cmipci_pcm_t *rec, int channels)
 {
@@ -704,13 +717,20 @@ static int set_dac_channels(cmipci_t *cm
 			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C);
 			snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
 		}
-		if (channels == 6) {
+		if (channels >= 6) {
 			snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
 			snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
 		} else {
 			snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
 			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
 		}
+		if (cm->chip_version == 68) {
+			if (channels == 8) {
+				snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C);
+			} else {
+				snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C);
+			}
+		}
 		spin_unlock_irq(&cm->reg_lock);
 
 	} else {
@@ -1504,6 +1524,7 @@ static int snd_cmipci_playback_open(snd_
 	if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0)
 		return err;
 	runtime->hw = snd_cmipci_playback;
+	runtime->hw.channels_max = cm->max_channels;
 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
 	cm->dig_pcm_status = cm->dig_status;
 	return 0;
@@ -1518,6 +1539,10 @@ static int snd_cmipci_capture_open(snd_p
 	if ((err = open_device_check(cm, CM_OPEN_CAPTURE, substream)) < 0)
 		return err;
 	runtime->hw = snd_cmipci_capture;
+	if (cm->chip_version == 68) {	// 8768 only supports 44k/48k recording
+		runtime->hw.rate_min = 41000;
+		runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+	}
 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
 	return 0;
 }
@@ -1537,8 +1562,10 @@ static int snd_cmipci_playback2_open(snd
 			runtime->hw.channels_max = cm->max_channels;
 			if (cm->max_channels == 4)
 				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_4);
-			else
+			else if (cm->max_channels == 6)
 				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_6);
+			else if (cm->max_channels == 8)
+				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8);
 		}
 		snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
 	}
@@ -2108,8 +2135,8 @@ typedef struct snd_cmipci_switch_args {
 	int reg;		/* register index */
 	unsigned int mask;	/* mask bits */
 	unsigned int mask_on;	/* mask bits to turn on */
-	int is_byte: 1;		/* byte access? */
-	int ac3_sensitive: 1;	/* access forbidden during non-audio operation? */
+	unsigned int is_byte: 1;		/* byte access? */
+	unsigned int ac3_sensitive: 1;	/* access forbidden during non-audio operation? */
 } snd_cmipci_switch_args_t;
 
 static int snd_cmipci_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -2346,6 +2373,11 @@ static int __devinit snd_cmipci_mixer_ne
 	spin_unlock_irq(&cm->reg_lock);
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_mixers); idx++) {
+		if (cm->chip_version == 68) {	// 8768 has no PCM volume
+			if (!strcmp(snd_cmipci_mixers[idx].name,
+				"PCM Playback Volume"))
+				continue;
+		}
 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cmipci_mixers[idx], cm))) < 0)
 			return err;
 	}
@@ -2496,32 +2528,98 @@ static void __devinit query_chip(cmipci_
 		}
 	} else {
 		/* check reg 0Ch, bit 26 */
-		if (detect & CM_CHIP_039) {
+		if (detect & CM_CHIP_8768) {
+			cm->chip_version = 68;
+			cm->max_channels = 8;
+			cm->can_ac3_hw = 1;
+			cm->has_dual_dac = 1;
+			cm->can_multi_ch = 1;
+		} else if (detect & CM_CHIP_055) {
+			cm->chip_version = 55;
+			cm->max_channels = 6;
+			cm->can_ac3_hw = 1;
+			cm->has_dual_dac = 1;
+			cm->can_multi_ch = 1;
+		} else if (detect & CM_CHIP_039) {
 			cm->chip_version = 39;
-			if (detect & CM_CHIP_039_6CH)
-				cm->max_channels  = 6;
+			if (detect & CM_CHIP_039_6CH) /* 4 or 6 channels */
+				cm->max_channels = 6;
 			else
 				cm->max_channels = 4;
 			cm->can_ac3_hw = 1;
 			cm->has_dual_dac = 1;
 			cm->can_multi_ch = 1;
 		} else {
-			cm->chip_version = 55; /* 4 or 6 channels */
-			cm->max_channels  = 6;
-			cm->can_ac3_hw = 1;
-			cm->has_dual_dac = 1;
-			cm->can_multi_ch = 1;
+			printk(KERN_ERR "chip %x version not supported\n", detect);
 		}
 	}
+}
 
-	/* added -MCx suffix for chip supporting multi-channels */
-	if (cm->can_multi_ch)
-		sprintf(cm->card->driver + strlen(cm->card->driver),
-			"-MC%d", cm->max_channels);
-	else if (cm->can_ac3_sw)
-		strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_cmipci_create_gameport(cmipci_t *cm, int dev)
+{
+	static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
+	struct gameport *gp;
+	struct resource *r = NULL;
+	int i, io_port = 0;
+
+	if (joystick_port[dev] == 0)
+		return -ENODEV;
+
+	if (joystick_port[dev] == 1) { /* auto-detect */
+		for (i = 0; ports[i]; i++) {
+			io_port = ports[i];
+			r = request_region(io_port, 1, "CMIPCI gameport");
+			if (r)
+				break;
+		}
+	} else {
+		io_port = joystick_port[dev];
+		r = request_region(io_port, 1, "CMIPCI gameport");
+	}
+
+	if (!r) {
+		printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	cm->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+	gameport_set_name(gp, "C-Media Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(cm->pci));
+	gameport_set_dev_parent(gp, &cm->pci->dev);
+	gp->io = io_port;
+	gameport_set_port_data(gp, r);
+
+	snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+
+	gameport_register_port(cm->gameport);
+
+	return 0;
 }
 
+static void snd_cmipci_free_gameport(cmipci_t *cm)
+{
+	if (cm->gameport) {
+		struct resource *r = gameport_get_port_data(cm->gameport);
+
+		gameport_unregister_port(cm->gameport);
+		cm->gameport = NULL;
+
+		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_cmipci_create_gameport(cmipci_t *cm, int dev) { return -ENOSYS; }
+static inline void snd_cmipci_free_gameport(cmipci_t *cm) { }
+#endif
 
 static int snd_cmipci_free(cmipci_t *cm)
 {
@@ -2541,14 +2639,8 @@ static int snd_cmipci_free(cmipci_t *cm)
 
 		free_irq(cm->irq, (void *)cm);
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (cm->res_joystick) {
-		gameport_unregister_port(&cm->gameport);
-		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-		release_resource(cm->res_joystick);
-		kfree_nocheck(cm->res_joystick);
-	}
-#endif
+
+	snd_cmipci_free_gameport(cm);
 	pci_release_regions(cm->pci);
 	pci_disable_device(cm->pci);
 	kfree(cm);
@@ -2623,7 +2715,15 @@ static int __devinit snd_cmipci_create(s
 	cm->max_channels = 2;
 	cm->do_soft_ac3 = soft_ac3[dev];
 
-	query_chip(cm);
+	if (pci->device != PCI_DEVICE_ID_CMEDIA_CM8338A &&
+	    pci->device != PCI_DEVICE_ID_CMEDIA_CM8338B)
+		query_chip(cm);
+	/* added -MCx suffix for chip supporting multi-channels */
+	if (cm->can_multi_ch)
+		sprintf(cm->card->driver + strlen(cm->card->driver),
+			"-MC%d", cm->max_channels);
+	else if (cm->can_ac3_sw)
+		strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
 
 	cm->dig_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
 	cm->dig_pcm_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
@@ -2757,31 +2857,9 @@ static int __devinit snd_cmipci_create(s
 	snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97);
 #endif /* USE_VAR48KRATE */
 
-#ifdef SUPPORT_JOYSTICK
-	if (joystick_port[dev] > 0) {
-		if (joystick_port[dev] == 1) { /* auto-detect */
-			static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
-			int i;
-			for (i = 0; ports[i]; i++) {
-				joystick_port[dev] = ports[i];
-				cm->res_joystick = request_region(ports[i], 1, "CMIPCI gameport");
-				if (cm->res_joystick)
-					break;
-			}
-		} else {
-			cm->res_joystick = request_region(joystick_port[dev], 1, "CMIPCI gameport");
-		}
-	}
-	if (cm->res_joystick) {
-		cm->gameport.io = joystick_port[dev];
-		snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-		gameport_register_port(&cm->gameport);
-	} else {
-		if (joystick_port[dev] > 0)
-			printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+	if (snd_cmipci_create_gameport(cm, dev) < 0)
 		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-	}
-#endif
+
 	snd_card_set_dev(card, &pci->dev);
 
 	*rcmipci = cm;
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -495,7 +495,7 @@ struct snd_cs4281 {
 	unsigned int midcr;
 	unsigned int uartm;
 
-	struct snd_cs4281_gameport *gameport;
+	struct gameport *gameport;
 
 #ifdef CONFIG_PM
 	u32 suspend_regs[SUSPEND_REGISTERS];
@@ -1238,38 +1238,29 @@ static void __devinit snd_cs4281_proc_in
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_cs4281_gameport {
-	struct gameport info;
-	cs4281_t *chip;
-} cs4281_gameport_t;
-
 static void snd_cs4281_gameport_trigger(struct gameport *gameport)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	cs4281_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return);
 	snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
 }
 
 static unsigned char snd_cs4281_gameport_read(struct gameport *gameport)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	cs4281_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return 0);
 	return snd_cs4281_peekBA0(chip, BA0_JSPT);
 }
 
 #ifdef COOKED_MODE
 static int snd_cs4281_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
+	cs4281_t *chip = gameport_get_port_data(gameport);
 	unsigned js1, js2, jst;
 	
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	snd_assert(chip, return 0);
 
 	js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
@@ -1282,10 +1273,12 @@ static int snd_cs4281_gameport_cooked_re
 	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
 	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
 
-	for(jst=0;jst<4;++jst)
-		if(axes[jst]==0xFFFF) axes[jst] = -1;
+	for (jst = 0; jst < 4; ++jst)
+		if (axes[jst] == 0xFFFF) axes[jst] = -1;
 	return 0;
 }
+#else
+#define snd_cs4281_gameport_cooked_read	NULL
 #endif
 
 static int snd_cs4281_gameport_open(struct gameport *gameport, int mode)
@@ -1303,31 +1296,43 @@ static int snd_cs4281_gameport_open(stru
 	return 0;
 }
 
-static void __devinit snd_cs4281_gameport(cs4281_t *chip)
+static int __devinit snd_cs4281_create_gameport(cs4281_t *chip)
 {
-	cs4281_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk(KERN_ERR "cannot allocate gameport area\n");
-		return;
-	}
-	memset(gp, 0, sizeof(*gp));
-	gp->info.open = snd_cs4281_gameport_open;
-	gp->info.read = snd_cs4281_gameport_read;
-	gp->info.trigger = snd_cs4281_gameport_trigger;
-#ifdef COOKED_MODE
-	gp->info.cooked_read = snd_cs4281_gameport_cooked_read;
-#endif
-	gp->chip = chip;
-	chip->gameport = gp;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "CS4281 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->open = snd_cs4281_gameport_open;
+	gp->read = snd_cs4281_gameport_read;
+	gp->trigger = snd_cs4281_gameport_trigger;
+	gp->cooked_read = snd_cs4281_gameport_cooked_read;
+	gameport_set_port_data(gp, chip);
 
 	snd_cs4281_pokeBA0(chip, BA0_JSIO, 0xFF); // ?
 	snd_cs4281_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-	gameport_register_port(&gp->info);
+
+	gameport_register_port(gp);
+
+	return 0;
 }
 
+static void snd_cs4281_free_gameport(cs4281_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
 #else
-#define snd_cs4281_gameport(chip) /*NOP*/
+static inline int snd_cs4281_create_gameport(cs4281_t *chip) { return -ENOSYS; }
+static inline void snd_cs4281_free_gameport(cs4281_t *chip) { }
 #endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
 
 
@@ -1337,12 +1342,8 @@ static void __devinit snd_cs4281_gamepor
 
 static int snd_cs4281_free(cs4281_t *chip)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport) {
-		gameport_unregister_port(&chip->gameport->info);
-		kfree(chip->gameport);
-	}
-#endif
+	snd_cs4281_free_gameport(chip);
+
 	if (chip->irq >= 0)
 		synchronize_irq(chip->irq);
 
@@ -1376,8 +1377,8 @@ static int snd_cs4281_dev_free(snd_devic
 
 static int snd_cs4281_chip_init(cs4281_t *chip); /* defined below */
 #ifdef CONFIG_PM
-static int cs4281_suspend(snd_card_t *card, unsigned int state);
-static int cs4281_resume(snd_card_t *card, unsigned int state);
+static int cs4281_suspend(snd_card_t *card, pm_message_t state);
+static int cs4281_resume(snd_card_t *card);
 #endif
 
 static int __devinit snd_cs4281_create(snd_card_t * card,
@@ -1893,9 +1894,7 @@ static irqreturn_t snd_cs4281_interrupt(
 			c = snd_cs4281_peekBA0(chip, BA0_MIDRP);
 			if ((chip->midcr & BA0_MIDCR_RIE) == 0)
 				continue;
-			spin_unlock(&chip->reg_lock);
 			snd_rawmidi_receive(chip->midi_input, &c, 1);
-			spin_lock(&chip->reg_lock);
 		}
 		while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_TBF) == 0) {
 			if ((chip->midcr & BA0_MIDCR_TIE) == 0)
@@ -1990,7 +1989,7 @@ static int __devinit snd_cs4281_probe(st
 		snd_card_free(card);
 		return err;
 	}
-	snd_cs4281_gameport(chip);
+	snd_cs4281_create_gameport(chip);
 	strcpy(card->driver, "CS4281");
 	strcpy(card->shortname, "Cirrus Logic CS4281");
 	sprintf(card->longname, "%s at 0x%lx, irq %d",
@@ -2037,7 +2036,7 @@ static int saved_regs[SUSPEND_REGISTERS]
 
 #define CLKCR1_CKRA                             0x00010000L
 
-static int cs4281_suspend(snd_card_t *card, unsigned int state)
+static int cs4281_suspend(snd_card_t *card, pm_message_t state)
 {
 	cs4281_t *chip = card->pm_private_data;
 	u32 ulCLK;
@@ -2082,7 +2081,7 @@ static int cs4281_suspend(snd_card_t *ca
 	return 0;
 }
 
-static int cs4281_resume(snd_card_t *card, unsigned int state)
+static int cs4281_resume(snd_card_t *card)
 {
 	cs4281_t *chip = card->pm_private_data;
 	unsigned int i;
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -1217,9 +1217,7 @@ static irqreturn_t snd_cs46xx_interrupt(
 			c = snd_cs46xx_peekBA0(chip, BA0_MIDRP);
 			if ((chip->midcr & MIDCR_RIE) == 0)
 				continue;
-			spin_unlock(&chip->reg_lock);
 			snd_rawmidi_receive(chip->midi_input, &c, 1);
-			spin_lock(&chip->reg_lock);
 		}
 		while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) {
 			if ((chip->midcr & MIDCR_TIE) == 0)
@@ -2690,37 +2688,28 @@ int __devinit snd_cs46xx_midi(cs46xx_t *
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_cs46xx_gameport {
-	struct gameport info;
-	cs46xx_t *chip;
-} cs46xx_gameport_t;
-
 static void snd_cs46xx_gameport_trigger(struct gameport *gameport)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	cs46xx_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return);
 	snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 }
 
 static unsigned char snd_cs46xx_gameport_read(struct gameport *gameport)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	cs46xx_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return 0);
 	return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io);
 }
 
 static int snd_cs46xx_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
+	cs46xx_t *chip = gameport_get_port_data(gameport);
 	unsigned js1, js2, jst;
-	
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+
+	snd_assert(chip, return 0);
 
 	js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2);
@@ -2751,33 +2740,44 @@ static int snd_cs46xx_gameport_open(stru
 	return 0;
 }
 
-void __devinit snd_cs46xx_gameport(cs46xx_t *chip)
+int __devinit snd_cs46xx_gameport(cs46xx_t *chip)
 {
-	cs46xx_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk("cannot allocate gameport area\n");
-		return;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cs46xx: cannot allocate memory for gameport\n");
+		return -ENOMEM;
 	}
-	memset(gp, 0, sizeof(*gp));
-	gp->info.open = snd_cs46xx_gameport_open;
-	gp->info.read = snd_cs46xx_gameport_read;
-	gp->info.trigger = snd_cs46xx_gameport_trigger;
-	gp->info.cooked_read = snd_cs46xx_gameport_cooked_read;
-	gp->chip = chip;
-	chip->gameport = gp;
+
+	gameport_set_name(gp, "CS46xx Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gameport_set_port_data(gp, chip);
+
+	gp->open = snd_cs46xx_gameport_open;
+	gp->read = snd_cs46xx_gameport_read;
+	gp->trigger = snd_cs46xx_gameport_trigger;
+	gp->cooked_read = snd_cs46xx_gameport_cooked_read;
 
 	snd_cs46xx_pokeBA0(chip, BA0_JSIO, 0xFF); // ?
 	snd_cs46xx_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-	gameport_register_port(&gp->info);
-}
 
-#else
+	gameport_register_port(gp);
 
-void __devinit snd_cs46xx_gameport(cs46xx_t *chip)
-{
+	return 0;
 }
 
+static inline void snd_cs46xx_remove_gameport(cs46xx_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
+#else
+int __devinit snd_cs46xx_gameport(cs46xx_t *chip) { return -ENOSYS; }
+static inline void snd_cs46xx_remove_gameport(cs46xx_t *chip) { }
 #endif /* CONFIG_GAMEPORT */
 
 /*
@@ -2893,12 +2893,7 @@ static int snd_cs46xx_free(cs46xx_t *chi
 	if (chip->active_ctrl)
 		chip->active_ctrl(chip, 1);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport) {
-		gameport_unregister_port(&chip->gameport->info);
-		kfree(chip->gameport);
-	}
-#endif
+	snd_cs46xx_remove_gameport(chip);
 
 	if (chip->amplifier_ctrl)
 		chip->amplifier_ctrl(chip, -chip->amplifier); /* force to off */
@@ -3704,7 +3699,7 @@ static struct cs_card_type __devinitdata
  * APM support
  */
 #ifdef CONFIG_PM
-static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state)
+static int snd_cs46xx_suspend(snd_card_t *card, pm_message_t state)
 {
 	cs46xx_t *chip = card->pm_private_data;
 	int amp_saved;
@@ -3728,7 +3723,7 @@ static int snd_cs46xx_suspend(snd_card_t
 	return 0;
 }
 
-static int snd_cs46xx_resume(snd_card_t *card, unsigned int state)
+static int snd_cs46xx_resume(snd_card_t *card)
 {
 	cs46xx_t *chip = card->pm_private_data;
 	int amp_saved;
diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile
--- a/sound/pci/emu10k1/Makefile
+++ b/sound/pci/emu10k1/Makefile
@@ -5,7 +5,7 @@
 
 snd-emu10k1-objs := emu10k1.o emu10k1_main.o \
 		    irq.o memory.o voice.o emumpu401.o emupcm.o io.o \
-		    emuproc.o emumixer.o emufx.o timer.o
+		    emuproc.o emumixer.o emufx.o timer.o p16v.o
 snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
 snd-emu10k1x-objs := emu10k1x.o
 
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -138,7 +138,15 @@ static int __devinit snd_card_emu10k1_pr
 	if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) {
 		snd_card_free(card);
 		return err;
-	}		
+	}
+	/* This stores the periods table. */
+	if (emu->audigy && emu->revision == 4) { /* P16V */	
+		if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) {
+			snd_p16v_free(emu);
+			return -ENOMEM;
+		}
+	}
+
 	if ((err = snd_emu10k1_mixer(emu)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -149,6 +157,16 @@ static int __devinit snd_card_emu10k1_pr
 		return err;
 	}
 
+	if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if (emu->audigy && emu->revision == 4) { /* P16V */	
+		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
 	if (emu->audigy) {
 		if ((err = snd_emu10k1_audigy_midi(emu)) < 0) {
 			snd_card_free(card);
@@ -180,23 +198,11 @@ static int __devinit snd_card_emu10k1_pr
 	}
 #endif
  
-	if (emu->audigy && (emu->serial == 0x10011102) ) {
-		strcpy(card->driver, "Audigy2");
-		strcpy(card->shortname, "Sound Blaster Audigy2_Value");
-	} else if (emu->audigy && (emu->revision == 4) ) {
-		strcpy(card->driver, "Audigy2");
-		strcpy(card->shortname, "Sound Blaster Audigy2");
-	} else if (emu->audigy) {
-		strcpy(card->driver, "Audigy");
-		strcpy(card->shortname, "Sound Blaster Audigy");
-	} else if (emu->APS) {
-		strcpy(card->driver, "E-mu APS");
-		strcpy(card->shortname, "E-mu APS");
-	} else {
-		strcpy(card->driver, "EMU10K1");
-		strcpy(card->shortname, "Sound Blaster Live!");
-	}
-	sprintf(card->longname, "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
+	strcpy(card->driver, emu->card_capabilities->driver);
+	strcpy(card->shortname, emu->card_capabilities->name);
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
+		 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -291,7 +291,7 @@ get_voice(snd_emux_t *emu, snd_emux_port
 			if (vp->ch < 0) {
 				/* allocate a voice */
 				emu10k1_voice_t *hwvoice;
-				if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 0, &hwvoice) < 0 || hwvoice == NULL)
+				if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, &hwvoice) < 0 || hwvoice == NULL)
 					continue;
 				vp->ch = hwvoice->number;
 				emu->num_voices++;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -39,6 +39,7 @@
 
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include "p16v.h"
 
 #if 0
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc.");
@@ -178,14 +179,17 @@ static int __devinit snd_emu10k1_init(em
 		tmp &= 0xfffff1ff;
 		tmp |= (0x2<<9);
 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
-
+		
 		/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
-		outl(0x600000, emu->port + 0x20);
-		outl(0x14, emu->port + 0x24);
-
+		snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);
 		/* Setup SRCMulti Input Audio Enable */
-		outl(0x6E0000, emu->port + 0x20);
-		outl(0xFF00FF00, emu->port + 0x24);
+		/* Use 0xFFFFFFFF to enable P16V sounds. */
+		snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF);
+
+		/* Enabled Phased (8-channel) P16V playback */
+		outl(0x0201, emu->port + HCFG2);
+		/* Set playback routing. */
+		snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4);
 	}
 	if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
 		/* Hacks for Alice3 to work independent of haP16V driver */
@@ -205,6 +209,15 @@ static int __devinit snd_emu10k1_init(em
 		/* Setup SRCMulti Input Audio Enable */
 		outl(0x7b0000, emu->port + 0x20);
 		outl(0xFF000000, emu->port + 0x24);
+
+		/* Setup SPDIF Out Audio Enable */
+		/* The Audigy 2 Value has a separate SPDIF out,
+		 * so no need for a mixer switch
+		 */
+		outl(0x7a0000, emu->port + 0x20);
+		outl(0xFF000000, emu->port + 0x24);
+		tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */
+		outl(tmp, emu->port + A_IOCFG);
 	}
 
 
@@ -587,6 +600,8 @@ static int snd_emu10k1_free(emu10k1_t *e
 	if (emu->port)
 		pci_release_regions(emu->pci);
 	pci_disable_device(emu->pci);
+	if (emu->audigy && emu->revision == 4) /* P16V */	
+		snd_p16v_free(emu);
 	kfree(emu);
 	return 0;
 }
@@ -597,6 +612,85 @@ static int snd_emu10k1_dev_free(snd_devi
 	return snd_emu10k1_free(emu);
 }
 
+/* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */
+
+static emu_chip_details_t emu_chip_details[] = {
+	/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
+	 .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", 
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1,
+	 .spk71 = 1} ,
+	{.vendor = 0x1102, .device = 0x0008, 
+	 .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
+	 .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spk71 = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
+	 .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spk71 = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102,
+	 .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spk71 = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
+	 .driver = "Audigy2", .name = "Audigy 2 [SB0240]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spk71 = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
+	 .driver = "Audigy2", .name = "Audigy 2 EX [1005]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spdif_bug = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
+	 .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ca0151_chip = 1,
+	 .spk71 = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004,
+	 .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", 
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .spdif_bug = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
+	 .driver = "EMU10K1", .name = "E-mu APS [4001]", 
+	 .emu10k1_chip = 1,
+	 .ecard = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
+	 .driver = "EMU10K1", .name = "SB Live 5.1", 
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0002,
+	 .driver = "EMU10K1", .name = "SB Live [Unknown]", 
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1} ,
+	{ } /* terminator */
+};
+
 int __devinit snd_emu10k1_create(snd_card_t * card,
 		       struct pci_dev * pci,
 		       unsigned short extin_mask,
@@ -608,15 +702,14 @@ int __devinit snd_emu10k1_create(snd_car
 	emu10k1_t *emu;
 	int err;
 	int is_audigy;
+	unsigned char revision;
+	const emu_chip_details_t *c;
 	static snd_device_ops_t ops = {
 		.dev_free =	snd_emu10k1_dev_free,
 	};
 	
 	*remu = NULL;
 
-	// is_audigy = (int)pci->driver_data;
-	is_audigy = (pci->device == 0x0004) || ( (pci->device == 0x0008) );
-
 	/* enable PCI device */
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
@@ -626,15 +719,6 @@ int __devinit snd_emu10k1_create(snd_car
 		pci_disable_device(pci);
 		return -ENOMEM;
 	}
-	/* set the DMA transfer mask */
-	emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
-	if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
-	    pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
-		snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
-		kfree(emu);
-		pci_disable_device(pci);
-		return -ENXIO;
-	}
 	emu->card = card;
 	spin_lock_init(&emu->reg_lock);
 	spin_lock_init(&emu->emu_lock);
@@ -649,8 +733,43 @@ int __devinit snd_emu10k1_create(snd_car
 	emu->irq = -1;
 	emu->synth = NULL;
 	emu->get_synth_voice = NULL;
+	/* read revision & serial */
+	pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
+	emu->revision = revision;
+	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
+	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
+	emu->card_type = EMU10K1_CARD_CREATIVE;
+	snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model);
 
-	emu->audigy = is_audigy;
+	for (c = emu_chip_details; c->vendor; c++) {
+		if (c->vendor == pci->vendor && c->device == pci->device) {
+			if (c->subsystem == emu->serial) break;
+			if (c->subsystem == 0) break;
+		}
+	}
+	if (c->vendor == 0) {
+		snd_printk(KERN_ERR "emu10k1: Card not recognised\n");
+		kfree(emu);
+		pci_disable_device(pci);
+		return -ENOENT;
+	}
+	emu->card_capabilities = c;
+	if (c->subsystem != 0)
+		snd_printdd("Sound card name=%s\n", c->name);
+	else
+		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial);
+	
+	is_audigy = emu->audigy = c->emu10k2_chip;
+
+	/* set the DMA transfer mask */
+	emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
+	if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
+	    pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
+		snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
+		kfree(emu);
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
 	if (is_audigy)
 		emu->gpr_base = A_FXGPREGBASE;
 	else
@@ -696,30 +815,15 @@ int __devinit snd_emu10k1_create(snd_car
 	emu->memhdr->block_extra_size = sizeof(emu10k1_memblk_t) - sizeof(snd_util_memblk_t);
 
 	pci_set_master(pci);
-	/* read revision & serial */
-	pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&emu->revision);
-	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
-	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
-	emu->card_type = EMU10K1_CARD_CREATIVE;
-	if (emu->serial == 0x40011102) {
+
+	if (c->ecard) {
 		emu->card_type = EMU10K1_CARD_EMUAPS;
 		emu->APS = 1;
-		emu->no_ac97 = 1; /* APS has no AC97 chip */
-	}
-	else if (emu->revision == 4 && emu->serial == 0x10051102) {
-		/* Audigy 2 EX has apparently no effective AC97 controls
-		 * (for both input and output), so we skip the AC97 detections
-		 */
-		snd_printdd(KERN_INFO "Audigy2 EX is detected. skipping ac97.\n");
-		emu->no_ac97 = 1;	
-	}
-	
-	if (emu->revision == 4 && (emu->model == 0x2001 || emu->model == 0x2002)) {
-		/* Audigy 2 ZS */
-		snd_printdd(KERN_INFO "Audigy2 ZS is detected. setting 7.1 mode.\n");
-		emu->spk71 = 1;
 	}
+	if (! c->ac97_chip)
+		emu->no_ac97 = 1;
 	
+	emu->spk71 = c->spk71;
 	
 	emu->fx8010.fxbus_mask = 0x303f;
 	if (extin_mask == 0)
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -749,6 +749,7 @@ static int snd_emu10k1x_ac97(emu10k1x_t 
 
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.private_data = chip;
+	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
 }
 
@@ -1278,10 +1279,8 @@ static void do_emu10k1x_midi_interrupt(e
 			mpu401_clear_rx(emu, midi);
 		} else {
 			byte = mpu401_read_data(emu, midi);
-			spin_unlock(&midi->input_lock);
 			if (midi->substream_input)
 				snd_rawmidi_receive(midi->substream_input, &byte, 1);
-			spin_lock(&midi->input_lock);
 		}
 	}
 	spin_unlock(&midi->input_lock);
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -468,10 +468,13 @@ int snd_emu10k1_fx8010_unregister_irq_ha
 static void snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
 				 u32 op, u32 r, u32 a, u32 x, u32 y)
 {
+	u_int32_t *code;
 	snd_assert(*ptr < 512, return);
+	code = (u_int32_t *)icode->code + (*ptr) * 2;
 	set_bit(*ptr, icode->code_valid);
-	icode->code[(*ptr)   * 2 + 0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
-	icode->code[(*ptr)++ * 2 + 1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
+	code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
+	code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
+	(*ptr)++;
 }
 
 #define OP(icode, ptr, op, r, a, x, y) \
@@ -480,10 +483,13 @@ static void snd_emu10k1_write_op(emu10k1
 static void snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr,
 					u32 op, u32 r, u32 a, u32 x, u32 y)
 {
+	u_int32_t *code;
 	snd_assert(*ptr < 1024, return);
+	code = (u_int32_t *)icode->code + (*ptr) * 2;
 	set_bit(*ptr, icode->code_valid);
-	icode->code[(*ptr)   * 2 + 0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
-	icode->code[(*ptr)++ * 2 + 1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
+	code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
+	code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
+	(*ptr)++;
 }
 
 #define A_OP(icode, ptr, op, r, a, x, y) \
@@ -628,7 +634,8 @@ static int snd_emu10k1_verify_controls(e
 	snd_ctl_elem_id_t __user *_id;
 	snd_ctl_elem_id_t id;
 	emu10k1_fx8010_control_gpr_t __user *_gctl;
-	emu10k1_fx8010_control_gpr_t gctl;
+	emu10k1_fx8010_control_gpr_t *gctl;
+	int err;
 	
 	for (i = 0, _id = icode->gpr_del_controls;
 	     i < icode->gpr_del_control_count; i++, _id++) {
@@ -637,29 +644,42 @@ static int snd_emu10k1_verify_controls(e
 		if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
 			return -ENOENT;
 	}
+	gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
+	if (! gctl)
+		return -ENOMEM;
+	err = 0;
 	for (i = 0, _gctl = icode->gpr_add_controls;
 	     i < icode->gpr_add_control_count; i++, _gctl++) {
-		if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
-			return -EFAULT;
-		if (snd_emu10k1_look_for_ctl(emu, &gctl.id))
+		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+			err = -EFAULT;
+			goto __error;
+		}
+		if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
 			continue;
 		down_read(&emu->card->controls_rwsem);
-		if (snd_ctl_find_id(emu->card, &gctl.id) != NULL) {
+		if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
 			up_read(&emu->card->controls_rwsem);
-			return -EEXIST;
+			err = -EEXIST;
+			goto __error;
 		}
 		up_read(&emu->card->controls_rwsem);
-		if (gctl.id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
-		    gctl.id.iface != SNDRV_CTL_ELEM_IFACE_PCM)
-			return -EINVAL;
+		if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
+		    gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
+			err = -EINVAL;
+			goto __error;
+		}
 	}
 	for (i = 0, _gctl = icode->gpr_list_controls;
 	     i < icode->gpr_list_control_count; i++, _gctl++) {
 	     	/* FIXME: we need to check the WRITE access */
-		if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
-			return -EFAULT;
+		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+			err = -EFAULT;
+			goto __error;
+		}
 	}
-	return 0;
+ __error:
+	kfree(gctl);
+	return err;
 }
 
 static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl)
@@ -676,52 +696,59 @@ static int snd_emu10k1_add_controls(emu1
 {
 	unsigned int i, j;
 	emu10k1_fx8010_control_gpr_t __user *_gctl;
-	emu10k1_fx8010_control_gpr_t gctl;
-	snd_emu10k1_fx8010_ctl_t *ctl, nctl;
+	emu10k1_fx8010_control_gpr_t *gctl;
+	snd_emu10k1_fx8010_ctl_t *ctl, *nctl;
 	snd_kcontrol_new_t knew;
 	snd_kcontrol_t *kctl;
 	snd_ctl_elem_value_t *val;
 	int err = 0;
 
 	val = (snd_ctl_elem_value_t *)kmalloc(sizeof(*val), GFP_KERNEL);
-	if (!val)
-		return -ENOMEM;
+	gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
+	nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
+	if (!val || !gctl || !nctl) {
+		err = -ENOMEM;
+		goto __error;
+	}
+
 	for (i = 0, _gctl = icode->gpr_add_controls;
 	     i < icode->gpr_add_control_count; i++, _gctl++) {
-		if (copy_from_user(&gctl, _gctl, sizeof(gctl))) {
+		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
 			err = -EFAULT;
 			goto __error;
 		}
-		snd_runtime_check(gctl.id.iface == SNDRV_CTL_ELEM_IFACE_MIXER ||
-		                  gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error);
-		snd_runtime_check(gctl.id.name[0] != '\0', err = -EINVAL; goto __error);
-		ctl = snd_emu10k1_look_for_ctl(emu, &gctl.id);
+		snd_runtime_check(gctl->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER ||
+		                  gctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error);
+		snd_runtime_check(gctl->id.name[0] != '\0', err = -EINVAL; goto __error);
+		ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
 		memset(&knew, 0, sizeof(knew));
-		knew.iface = gctl.id.iface;
-		knew.name = gctl.id.name;
-		knew.index = gctl.id.index;
-		knew.device = gctl.id.device;
-		knew.subdevice = gctl.id.subdevice;
+		knew.iface = gctl->id.iface;
+		knew.name = gctl->id.name;
+		knew.index = gctl->id.index;
+		knew.device = gctl->id.device;
+		knew.subdevice = gctl->id.subdevice;
 		knew.info = snd_emu10k1_gpr_ctl_info;
 		knew.get = snd_emu10k1_gpr_ctl_get;
 		knew.put = snd_emu10k1_gpr_ctl_put;
-		memset(&nctl, 0, sizeof(nctl));
-		nctl.vcount = gctl.vcount;
-		nctl.count = gctl.count;
+		memset(nctl, 0, sizeof(*nctl));
+		nctl->vcount = gctl->vcount;
+		nctl->count = gctl->count;
 		for (j = 0; j < 32; j++) {
-			nctl.gpr[j] = gctl.gpr[j];
-			nctl.value[j] = ~gctl.value[j];	/* inverted, we want to write new value in gpr_ctl_put() */
-			val->value.integer.value[j] = gctl.value[j];
-		}
-		nctl.min = gctl.min;
-		nctl.max = gctl.max;
-		nctl.translation = gctl.translation;
+			nctl->gpr[j] = gctl->gpr[j];
+			nctl->value[j] = ~gctl->value[j];	/* inverted, we want to write new value in gpr_ctl_put() */
+			val->value.integer.value[j] = gctl->value[j];
+		}
+		nctl->min = gctl->min;
+		nctl->max = gctl->max;
+		nctl->translation = gctl->translation;
 		if (ctl == NULL) {
 			ctl = (snd_emu10k1_fx8010_ctl_t *)kmalloc(sizeof(*ctl), GFP_KERNEL);
-			if (ctl == NULL)
-				continue;
+			if (ctl == NULL) {
+				err = -ENOMEM;
+				goto __error;
+			}
 			knew.private_value = (unsigned long)ctl;
-			memcpy(ctl, &nctl, sizeof(nctl));
+			*ctl = *nctl;
 			if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
 				kfree(ctl);
 				goto __error;
@@ -731,15 +758,17 @@ static int snd_emu10k1_add_controls(emu1
 			list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
 		} else {
 			/* overwrite */
-			nctl.list = ctl->list;
-			nctl.kcontrol = ctl->kcontrol;
-			memcpy(ctl, &nctl, sizeof(nctl));
+			nctl->list = ctl->list;
+			nctl->kcontrol = ctl->kcontrol;
+			*ctl = *nctl;
 			snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
 			                          SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
 		}
 		snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
 	}
       __error:
+	kfree(nctl);
+	kfree(gctl);
 	kfree(val);
 	return err;
 }
@@ -768,40 +797,47 @@ static int snd_emu10k1_list_controls(emu
 {
 	unsigned int i = 0, j;
 	unsigned int total = 0;
-	emu10k1_fx8010_control_gpr_t gctl;
+	emu10k1_fx8010_control_gpr_t *gctl;
 	emu10k1_fx8010_control_gpr_t __user *_gctl;
 	snd_emu10k1_fx8010_ctl_t *ctl;
 	snd_ctl_elem_id_t *id;
 	struct list_head *list;
 
+	gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
+	if (! gctl)
+		return -ENOMEM;
+
 	_gctl = icode->gpr_list_controls;	
 	list_for_each(list, &emu->fx8010.gpr_ctl) {
 		ctl = emu10k1_gpr_ctl(list);
 		total++;
 		if (_gctl && i < icode->gpr_list_control_count) {
-			memset(&gctl, 0, sizeof(gctl));
+			memset(gctl, 0, sizeof(*gctl));
 			id = &ctl->kcontrol->id;
-			gctl.id.iface = id->iface;
-			strlcpy(gctl.id.name, id->name, sizeof(gctl.id.name));
-			gctl.id.index = id->index;
-			gctl.id.device = id->device;
-			gctl.id.subdevice = id->subdevice;
-			gctl.vcount = ctl->vcount;
-			gctl.count = ctl->count;
+			gctl->id.iface = id->iface;
+			strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
+			gctl->id.index = id->index;
+			gctl->id.device = id->device;
+			gctl->id.subdevice = id->subdevice;
+			gctl->vcount = ctl->vcount;
+			gctl->count = ctl->count;
 			for (j = 0; j < 32; j++) {
-				gctl.gpr[j] = ctl->gpr[j];
-				gctl.value[j] = ctl->value[j];
+				gctl->gpr[j] = ctl->gpr[j];
+				gctl->value[j] = ctl->value[j];
 			}
-			gctl.min = ctl->min;
-			gctl.max = ctl->max;
-			gctl.translation = ctl->translation;
-			if (copy_to_user(_gctl, &gctl, sizeof(gctl)))
+			gctl->min = ctl->min;
+			gctl->max = ctl->max;
+			gctl->translation = ctl->translation;
+			if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
+				kfree(gctl);
 				return -EFAULT;
+			}
 			_gctl++;
 			i++;
 		}
 	}
 	icode->gpr_list_control_total = total;
+	kfree(gctl);
 	return 0;
 }
 
@@ -994,17 +1030,19 @@ static int __devinit _snd_emu10k1_audigy
 	u32 ptr;
 	emu10k1_fx8010_code_t *icode = NULL;
 	emu10k1_fx8010_control_gpr_t *controls = NULL, *ctl;
+	u32 *gpr_map;
 	mm_segment_t seg;
 
 	spin_lock_init(&emu->fx8010.irq_lock);
 	INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
 
 	if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL ||
-	    (icode->gpr_map = kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), GFP_KERNEL)) == NULL ||
+	    (icode->gpr_map = (u_int32_t __user *)kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), GFP_KERNEL)) == NULL ||
 	    (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(*controls), GFP_KERNEL)) == NULL) {
 		err = -ENOMEM;
 		goto __err;
 	}
+	gpr_map = (u32 *)icode->gpr_map;
 
 	icode->tram_data_map = icode->gpr_map + 512;
 	icode->tram_addr_map = icode->tram_data_map + 256;
@@ -1065,10 +1103,10 @@ static int __devinit _snd_emu10k1_audigy
 	snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
 	gpr += 2;
 
-	/* Music Playback */
+	/* Synth Playback */
 	A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
 	A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
-	snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Playback Volume", gpr, 100);
+	snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
 	gpr += 2;
 
 	/* Wave (PCM) Capture */
@@ -1077,10 +1115,10 @@ static int __devinit _snd_emu10k1_audigy
 	snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
 	gpr += 2;
 
-	/* Music Capture */
+	/* Synth Capture */
 	A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
 	A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
-	snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Capture Volume", gpr, 0);
+	snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
 	gpr += 2;
 
 	/*
@@ -1331,8 +1369,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 	/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
 
 	/* IEC958 Optical Raw Playback Switch */ 
-	icode->gpr_map[gpr++] = 0x1008;
-	icode->gpr_map[gpr++] = 0xffff0000;
+	gpr_map[gpr++] = 0;
+	gpr_map[gpr++] = 0x1008;
+	gpr_map[gpr++] = 0xffff0000;
 	for (z = 0; z < 2; z++) {
 		A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
 		A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
@@ -1341,7 +1380,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 		A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
 		A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
 		A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
-		A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+		if ((z==1) && (emu->card_capabilities->spdif_bug)) {
+			/* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
+			snd_printk("Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
+			A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
+			A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+		} else {
+			A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+		}
 	}
 	snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0);
 	gpr += 2;
@@ -1358,6 +1404,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
 #endif
 
+	/* EFX capture - capture the 16 EXTINs */
+	for (z = 0; z < 16; z++) {
+		A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+	}
+	
 	/*
 	 * ok, set up done..
 	 */
@@ -1373,16 +1424,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 
 	seg = snd_enter_user();
 	icode->gpr_add_control_count = nctl;
-	icode->gpr_add_controls = controls;
+	icode->gpr_add_controls = (emu10k1_fx8010_control_gpr_t __user *)controls;
 	err = snd_emu10k1_icode_poke(emu, icode);
 	snd_leave_user(seg);
 
  __err:
- 	if (controls != NULL)
-		kfree(controls);
+	kfree(controls);
 	if (icode != NULL) {
-		if (icode->gpr_map != NULL)
-			kfree(icode->gpr_map);
+		kfree((void *)icode->gpr_map);
 		kfree(icode);
 	}
 	return err;
@@ -1448,6 +1497,7 @@ static int __devinit _snd_emu10k1_init_e
 	emu10k1_fx8010_code_t *icode;
 	emu10k1_fx8010_pcm_t *ipcm = NULL;
 	emu10k1_fx8010_control_gpr_t *controls = NULL, *ctl;
+	u32 *gpr_map;
 	mm_segment_t seg;
 
 	spin_lock_init(&emu->fx8010.irq_lock);
@@ -1455,12 +1505,13 @@ static int __devinit _snd_emu10k1_init_e
 
 	if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	if ((icode->gpr_map = kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t), GFP_KERNEL)) == NULL ||
+	if ((icode->gpr_map = (u_int32_t __user *)kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t), GFP_KERNEL)) == NULL ||
             (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(emu10k1_fx8010_control_gpr_t), GFP_KERNEL)) == NULL ||
 	    (ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL)) == NULL) {
 		err = -ENOMEM;
 		goto __err;
 	}
+	gpr_map = (u32 *)icode->gpr_map;
 
 	icode->tram_data_map = icode->gpr_map + 256;
 	icode->tram_addr_map = icode->tram_data_map + 160;
@@ -1515,19 +1566,19 @@ static int __devinit _snd_emu10k1_init_e
 	ipcm->etram[0] = 0;
 	ipcm->etram[1] = 1;
 
-	icode->gpr_map[gpr + 0] = 0xfffff000;
-	icode->gpr_map[gpr + 1] = 0xffff0000;
-	icode->gpr_map[gpr + 2] = 0x70000000;
-	icode->gpr_map[gpr + 3] = 0x00000007;
-	icode->gpr_map[gpr + 4] = 0x001f << 11;
-	icode->gpr_map[gpr + 5] = 0x001c << 11;
-	icode->gpr_map[gpr + 6] = (0x22  - 0x01) - 1;	/* skip at 01 to 22 */
-	icode->gpr_map[gpr + 7] = (0x22  - 0x06) - 1;	/* skip at 06 to 22 */
-	icode->gpr_map[gpr + 8] = 0x2000000 + (2<<11);
-	icode->gpr_map[gpr + 9] = 0x4000000 + (2<<11);
-	icode->gpr_map[gpr + 10] = 1<<11;
-	icode->gpr_map[gpr + 11] = (0x24 - 0x0a) - 1;	/* skip at 0a to 24 */
-	icode->gpr_map[gpr + 12] = 0;
+	gpr_map[gpr + 0] = 0xfffff000;
+	gpr_map[gpr + 1] = 0xffff0000;
+	gpr_map[gpr + 2] = 0x70000000;
+	gpr_map[gpr + 3] = 0x00000007;
+	gpr_map[gpr + 4] = 0x001f << 11;
+	gpr_map[gpr + 5] = 0x001c << 11;
+	gpr_map[gpr + 6] = (0x22  - 0x01) - 1;	/* skip at 01 to 22 */
+	gpr_map[gpr + 7] = (0x22  - 0x06) - 1;	/* skip at 06 to 22 */
+	gpr_map[gpr + 8] = 0x2000000 + (2<<11);
+	gpr_map[gpr + 9] = 0x4000000 + (2<<11);
+	gpr_map[gpr + 10] = 1<<11;
+	gpr_map[gpr + 11] = (0x24 - 0x0a) - 1;	/* skip at 0a to 24 */
+	gpr_map[gpr + 12] = 0;
 
 	/* if the trigger flag is not set, skip */
 	/* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
@@ -1608,19 +1659,19 @@ static int __devinit _snd_emu10k1_init_e
 	snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
 	gpr += 4;
 
-	/* Music Playback Volume */
+	/* Synth Playback Volume */
 	for (z = 0; z < 2; z++)
 		VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
-	snd_emu10k1_init_stereo_control(controls + i++, "Music Playback Volume", gpr, 100);
+	snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
 	gpr += 2;
 
-	/* Music Capture Volume + Switch */
+	/* Synth Capture Volume + Switch */
 	for (z = 0; z < 2; z++) {
 		SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
 		VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
 	}
-	snd_emu10k1_init_stereo_control(controls + i++, "Music Capture Volume", gpr, 0);
-	snd_emu10k1_init_stereo_onoff_control(controls + i++, "Music Capture Switch", gpr + 2, 0);
+	snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
+	snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
 	gpr += 4;
 
 	/* Surround Digital Playback Volume (renamed later without Digital) */
@@ -1930,6 +1981,24 @@ static int __devinit _snd_emu10k1_init_e
 	if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
 		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
 
+	/* EFX capture - capture the 16 EXTINS */
+	OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
+	OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
+	OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
+	OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
+	/* Dont connect anything to FXBUS2 1 and 2.  These are shared with 
+	 * Center/LFE on the SBLive 5.1.  The kX driver only changes the 
+	 * routing when it detects an SBLive 5.1.
+	 *
+	 * Since only 14 of the 16 EXTINs are used, this is not a big problem.  
+	 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture 
+	 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture 
+	 * channel.
+	 */
+	for (z = 4; z < 14; z++) {
+		OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
+	}
+
 	if (gpr > tmp) {
 		snd_BUG();
 		err = -EIO;
@@ -1949,19 +2018,16 @@ static int __devinit _snd_emu10k1_init_e
 		goto __err;
 	seg = snd_enter_user();
 	icode->gpr_add_control_count = i;
-	icode->gpr_add_controls = controls;
+	icode->gpr_add_controls = (emu10k1_fx8010_control_gpr_t __user *)controls;
 	err = snd_emu10k1_icode_poke(emu, icode);
 	snd_leave_user(seg);
 	if (err >= 0)
 		err = snd_emu10k1_ipcm_poke(emu, ipcm);
       __err:
-      	if (ipcm != NULL)
-		kfree(ipcm);
-	if (controls != NULL)
-		kfree(controls);
+	kfree(ipcm);
+	kfree(controls);
 	if (icode != NULL) {
-		if (icode->gpr_map != NULL)
-			kfree(icode->gpr_map);
+		kfree((void *)icode->gpr_map);
 		kfree(icode);
 	}
 	return err;
@@ -2064,7 +2130,7 @@ static int snd_emu10k1_fx8010_info(emu10
 	memset(info, 0, sizeof(info));
 	info->card = emu->card_type;
 	info->internal_tram_size = emu->fx8010.itram_size;
-	info->external_tram_size = emu->fx8010.etram_pages.bytes;
+	info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
 	fxbus = fxbuses;
 	extin = emu->audigy ? audigy_ins : creative_ins;
 	extout = emu->audigy ? audigy_outs : creative_outs;
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -3,6 +3,7 @@
  *                   Takashi Iwai <tiwai@suse.de>
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips / mixer routines
+ *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
  *
  *  BUGS:
  *    --
@@ -67,6 +68,91 @@ static int snd_emu10k1_spdif_get_mask(sn
 	return 0;
 }
 
+static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = {"44100", "48000", "96000"};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_audigy_spdif_output_rate_get(snd_kcontrol_t * kcontrol,
+                                 snd_ctl_elem_value_t * ucontrol)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int tmp;
+	unsigned long flags;
+	
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
+	switch (tmp & A_SPDIF_RATE_MASK) {
+	case A_SPDIF_44100:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	case A_SPDIF_48000:
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	case A_SPDIF_96000:
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	default:
+		ucontrol->value.enumerated.item[0] = 1;
+	}
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return 0;
+}
+
+static int snd_audigy_spdif_output_rate_put(snd_kcontrol_t * kcontrol,
+                                 snd_ctl_elem_value_t * ucontrol)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int reg, val, tmp;
+	unsigned long flags;
+
+	switch(ucontrol->value.enumerated.item[0]) {
+	case 0:
+		val = A_SPDIF_44100;
+		break;
+	case 1:
+		val = A_SPDIF_48000;
+		break;
+	case 2:
+		val = A_SPDIF_96000;
+		break;
+	default:
+		val = A_SPDIF_48000;
+		break;
+	}
+
+	
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
+	tmp = reg & ~A_SPDIF_RATE_MASK;
+	tmp |= val;
+	if ((change = (tmp != reg)))
+		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_audigy_spdif_output_rate =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Audigy SPDIF Output Sample Rate",
+	.count =	1,
+	.info =         snd_audigy_spdif_output_rate_info,
+	.get =          snd_audigy_spdif_output_rate_get,
+	.put =          snd_audigy_spdif_output_rate_put
+};
+
 static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
                                  snd_ctl_elem_value_t * ucontrol)
 {
@@ -139,6 +225,8 @@ static void update_emu10k1_send_volume(e
 	}
 }
 
+/* PCM stream controls */
+
 static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
@@ -345,6 +433,200 @@ static snd_kcontrol_new_t snd_emu10k1_at
 	.put =          snd_emu10k1_attn_put
 };
 
+/* Mutichannel PCM stream controls */
+
+static int snd_emu10k1_efx_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = emu->audigy ? 8 : 4;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
+	return 0;
+}
+
+static int snd_emu10k1_efx_send_routing_get(snd_kcontrol_t * kcontrol,
+                                        snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
+	int idx;
+	int num_efx = emu->audigy ? 8 : 4;
+	int mask = emu->audigy ? 0x3f : 0x0f;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	for (idx = 0; idx < num_efx; idx++)
+		ucontrol->value.integer.value[idx] = 
+			mix->send_routing[0][idx] & mask;
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return 0;
+}
+
+static int snd_emu10k1_efx_send_routing_put(snd_kcontrol_t * kcontrol,
+                                        snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
+	int change = 0, idx, val;
+	int num_efx = emu->audigy ? 8 : 4;
+	int mask = emu->audigy ? 0x3f : 0x0f;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	for (idx = 0; idx < num_efx; idx++) {
+		val = ucontrol->value.integer.value[idx] & mask;
+		if (mix->send_routing[0][idx] != val) {
+			mix->send_routing[0][idx] = val;
+			change = 1;
+		}
+	}	
+
+	if (change && mix->epcm) {
+		if (mix->epcm->voices[ch]) {
+			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
+					&mix->send_routing[0][0]);
+		}
+	}
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_emu10k1_efx_send_routing_control =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "Multichannel PCM Send Routing",
+	.count =	16,
+	.info =         snd_emu10k1_efx_send_routing_info,
+	.get =          snd_emu10k1_efx_send_routing_get,
+	.put =          snd_emu10k1_efx_send_routing_put
+};
+
+static int snd_emu10k1_efx_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = emu->audigy ? 8 : 4;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
+}
+
+static int snd_emu10k1_efx_send_volume_get(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
+	int idx;
+	int num_efx = emu->audigy ? 8 : 4;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	for (idx = 0; idx < num_efx; idx++)
+		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return 0;
+}
+
+static int snd_emu10k1_efx_send_volume_put(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
+	int change = 0, idx, val;
+	int num_efx = emu->audigy ? 8 : 4;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	for (idx = 0; idx < num_efx; idx++) {
+		val = ucontrol->value.integer.value[idx] & 255;
+		if (mix->send_volume[0][idx] != val) {
+			mix->send_volume[0][idx] = val;
+			change = 1;
+		}
+	}
+	if (change && mix->epcm) {
+		if (mix->epcm->voices[ch]) {
+			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
+						   &mix->send_volume[0][0]);
+		}
+	}
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return change;
+}
+
+
+static snd_kcontrol_new_t snd_emu10k1_efx_send_volume_control =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "Multichannel PCM Send Volume",
+	.count =	16,
+	.info =         snd_emu10k1_efx_send_volume_info,
+	.get =          snd_emu10k1_efx_send_volume_get,
+	.put =          snd_emu10k1_efx_send_volume_put
+};
+
+static int snd_emu10k1_efx_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xffff;
+	return 0;
+}
+
+static int snd_emu10k1_efx_attn_get(snd_kcontrol_t * kcontrol,
+                                snd_ctl_elem_value_t * ucontrol)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
+	unsigned long flags;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	ucontrol->value.integer.value[0] = mix->attn[0];
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return 0;
+}
+
+static int snd_emu10k1_efx_attn_put(snd_kcontrol_t * kcontrol,
+				snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
+	int change = 0, val;
+
+	spin_lock_irqsave(&emu->reg_lock, flags);
+	val = ucontrol->value.integer.value[0] & 0xffff;
+	if (mix->attn[0] != val) {
+		mix->attn[0] = val;
+		change = 1;
+	}
+	if (change && mix->epcm) {
+		if (mix->epcm->voices[ch]) {
+			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
+		}
+	}
+	spin_unlock_irqrestore(&emu->reg_lock, flags);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_emu10k1_efx_attn_control =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "Multichannel PCM Volume",
+	.count =	16,
+	.info =         snd_emu10k1_efx_attn_info,
+	.get =          snd_emu10k1_efx_attn_get,
+	.put =          snd_emu10k1_efx_attn_put
+};
+
 static int snd_emu10k1_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -524,6 +806,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.private_data = emu;
 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
+		ac97.scaps = AC97_SCAP_NO_SPDIF;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0)
 			return err;
 		if (emu->audigy) {
@@ -578,7 +861,22 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 	if ((err = snd_ctl_add(card, kctl)))
 		return err;
 
-	/* intiailize the routing and volume table for each pcm playback stream */
+	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
+		return -ENOMEM;
+	if ((err = snd_ctl_add(card, kctl)))
+		return err;
+	
+	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
+		return -ENOMEM;
+	if ((err = snd_ctl_add(card, kctl)))
+		return err;
+	
+	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
+		return -ENOMEM;
+	if ((err = snd_ctl_add(card, kctl)))
+		return err;
+
+	/* initialize the routing and volume table for each pcm playback stream */
 	for (pcm = 0; pcm < 32; pcm++) {
 		emu10k1_pcm_mixer_t *mix;
 		int v;
@@ -598,17 +896,34 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
 	}
 	
+	/* initialize the routing and volume table for the multichannel playback stream */
+	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
+		emu10k1_pcm_mixer_t *mix;
+		int v;
+		
+		mix = &emu->efx_pcm_mixer[pcm];
+		mix->epcm = NULL;
+
+		mix->send_routing[0][0] = pcm;
+		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
+		for (v = 0; v < 2; v++)
+			mix->send_routing[0][2+v] = 13+v;
+		if (emu->audigy)
+			for (v = 0; v < 4; v++)
+				mix->send_routing[0][4+v] = 60+v;
+		
+		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
+		mix->send_volume[0][0]  = 255;
+		
+		mix->attn[0] = 0xffff;
+	}
+	
 	if (! emu->APS) { /* FIXME: APS has these controls? */
 		/* sb live! and audigy */
 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
 			return -ENOMEM;
 		if ((err = snd_ctl_add(card, kctl)))
 			return err;
-		if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) {
-			/* already defined by ac97, remove it */
-			/* FIXME: or do we need both controls? */
-			remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT));
-		}
 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
 			return -ENOMEM;
 		if ((err = snd_ctl_add(card, kctl)))
@@ -620,6 +935,10 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 			return -ENOMEM;
 		if ((err = snd_ctl_add(card, kctl)))
 			return err;
+		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
+			return -ENOMEM;
+		if ((err = snd_ctl_add(card, kctl)))
+			return err;
 	} else if (! emu->APS) {
 		/* sb live! */
 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
@@ -627,6 +946,10 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 		if ((err = snd_ctl_add(card, kctl)))
 			return err;
 	}
-
+	if (emu->audigy && emu->revision == 4) { /* P16V */
+		if ((err = snd_p16v_mixer(emu)))
+			return err;
+	}
+		
 	return 0;
 }
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -86,10 +86,8 @@ static void do_emu10k1_midi_interrupt(em
 			mpu401_clear_rx(emu, midi);
 		} else {
 			byte = mpu401_read_data(emu, midi);
-			spin_unlock(&midi->input_lock);
 			if (midi->substream_input)
 				snd_rawmidi_receive(midi->substream_input, &byte, 1);
-			spin_lock(&midi->input_lock);
 		}
 	}
 	spin_unlock(&midi->input_lock);
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -2,6 +2,7 @@
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips / PCM routines
+ *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
  *
  *  BUGS:
  *    --
@@ -82,43 +83,71 @@ static void snd_emu10k1_pcm_efx_interrup
 	}
 #endif
 	snd_pcm_period_elapsed(emu->pcm_capture_efx_substream);
+}	 
+
+static snd_pcm_uframes_t snd_emu10k1_efx_playback_pointer(snd_pcm_substream_t * substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	emu10k1_pcm_t *epcm = runtime->private_data;
+	unsigned int ptr;
+
+	if (!epcm->running)
+		return 0;
+	ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;
+	ptr += runtime->buffer_size;
+	ptr -= epcm->ccca_start_addr;
+	ptr %= runtime->buffer_size;
+
+	return ptr;
 }
 
 static int snd_emu10k1_pcm_channel_alloc(emu10k1_pcm_t * epcm, int voices)
 {
-	int err;
+	int err, i;
 
 	if (epcm->voices[1] != NULL && voices < 2) {
 		snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]);
 		epcm->voices[1] = NULL;
 	}
-	if (voices == 1 && epcm->voices[0] != NULL)
-		return 0;		/* already allocated */
-	if (voices == 2 && epcm->voices[0] != NULL && epcm->voices[1] != NULL)
-		return 0;
-	if (voices > 1) {
-		if (epcm->voices[0] != NULL && epcm->voices[1] == NULL) {
-			snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]);
-			epcm->voices[0] = NULL;
+	for (i = 0; i < voices; i++) {
+		if (epcm->voices[i] == NULL)
+			break;
+	}
+	if (i == voices)
+		return 0; /* already allocated */
+
+	for (i = 0; i < ARRAY_SIZE(epcm->voices); i++) {
+		if (epcm->voices[i]) {
+			snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
+			epcm->voices[i] = NULL;
 		}
 	}
-	err = snd_emu10k1_voice_alloc(epcm->emu, EMU10K1_PCM, voices > 1, &epcm->voices[0]);
+	err = snd_emu10k1_voice_alloc(epcm->emu,
+				      epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX,
+				      voices,
+				      &epcm->voices[0]);
+	
 	if (err < 0)
 		return err;
 	epcm->voices[0]->epcm = epcm;
 	if (voices > 1) {
-		epcm->voices[1] = &epcm->emu->voices[epcm->voices[0]->number + 1];
-		epcm->voices[1]->epcm = epcm;
+		for (i = 1; i < voices; i++) {
+			epcm->voices[i] = &epcm->emu->voices[epcm->voices[0]->number + i];
+			epcm->voices[i]->epcm = epcm;
+		}
 	}
 	if (epcm->extra == NULL) {
-		err = snd_emu10k1_voice_alloc(epcm->emu, EMU10K1_PCM, 0, &epcm->extra);
+		err = snd_emu10k1_voice_alloc(epcm->emu,
+					      epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX,
+					      1,
+					      &epcm->extra);
 		if (err < 0) {
 			// printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame);
-			snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]);
-			epcm->voices[0] = NULL;
-			if (epcm->voices[1])
-				snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]);
-			epcm->voices[1] = NULL;
+			for (i = 0; i < voices; i++) {
+				snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
+				epcm->voices[i] = NULL;
+			}
 			return err;
 		}
 		epcm->extra->epcm = epcm;
@@ -225,22 +254,39 @@ static unsigned int emu10k1_select_inter
 		return CCCA_INTERPROM_2;
 }
 
+/*
+ * calculate cache invalidate size 
+ *
+ * stereo: channel is stereo
+ * w_16: using 16bit samples
+ *
+ * returns: cache invalidate size in samples
+ */
+static int inline emu10k1_ccis(int stereo, int w_16)
+{
+	if (w_16) {
+		return stereo ? 24 : 26;
+	} else {
+		return stereo ? 24*2 : 26*2;
+	}
+}
 
 static void snd_emu10k1_pcm_init_voice(emu10k1_t *emu,
 				       int master, int extra,
 				       emu10k1_voice_t *evoice,
 				       unsigned int start_addr,
-				       unsigned int end_addr)
+				       unsigned int end_addr,
+				       emu10k1_pcm_mixer_t *mix)
 {
 	snd_pcm_substream_t *substream = evoice->epcm->substream;
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];
 	unsigned int silent_page, tmp;
 	int voice, stereo, w_16;
 	unsigned char attn, send_amount[8];
 	unsigned char send_routing[8];
 	unsigned long flags;
 	unsigned int pitch_target;
+	unsigned int ccis;
 
 	voice = evoice->number;
 	stereo = runtime->channels == 2;
@@ -273,10 +319,9 @@ static void snd_emu10k1_pcm_init_voice(e
 		memcpy(send_amount, &mix->send_volume[tmp][0], 8);
 	}
 
+	ccis = emu10k1_ccis(stereo, w_16);
+	
 	if (master) {
-		unsigned int ccis = stereo ? 28 : 30;
-		if (w_16)
-			ccis *= 2;
 		evoice->epcm->ccca_start_addr = start_addr + ccis;
 		if (extra) {
 			start_addr += ccis;
@@ -310,7 +355,12 @@ static void snd_emu10k1_pcm_init_voice(e
 	snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
 	snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
 	pitch_target = emu10k1_calc_pitch_target(runtime->rate);
-	snd_emu10k1_ptr_write(emu, CCCA, voice, evoice->epcm->ccca_start_addr |
+	if (extra)
+		snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr |
+			      emu10k1_select_interprom(pitch_target) |
+			      (w_16 ? 0 : CCCA_8BITSELECT));
+	else
+		snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) |
 			      emu10k1_select_interprom(pitch_target) |
 			      (w_16 ? 0 : CCCA_8BITSELECT));
 	// Clear filter delay memory
@@ -398,6 +448,35 @@ static int snd_emu10k1_playback_hw_free(
 	return 0;
 }
 
+static int snd_emu10k1_efx_playback_hw_free(snd_pcm_substream_t * substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	emu10k1_pcm_t *epcm;
+	int i;
+
+	if (runtime->private_data == NULL)
+		return 0;
+	epcm = runtime->private_data;
+	if (epcm->extra) {
+		snd_emu10k1_voice_free(epcm->emu, epcm->extra);
+		epcm->extra = NULL;
+	}
+	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+		if (epcm->voices[i]) {
+			snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
+			epcm->voices[i] = NULL;
+		}
+	}
+	if (epcm->memblk) {
+		snd_emu10k1_free_pages(emu, epcm->memblk);
+		epcm->memblk = NULL;
+		epcm->start_addr = 0;
+	}
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
 static int snd_emu10k1_playback_prepare(snd_pcm_substream_t * substream)
 {
 	emu10k1_t *emu = snd_pcm_substream_chip(substream);
@@ -407,20 +486,80 @@ static int snd_emu10k1_playback_prepare(
 
 	start_addr = epcm->start_addr;
 	end_addr = snd_pcm_lib_period_bytes(substream);
-	if (runtime->channels == 2)
+	if (runtime->channels == 2) {
+		start_addr >>= 1;
 		end_addr >>= 1;
+	}
 	end_addr += start_addr;
 	snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,
-				   start_addr, end_addr);
+				   start_addr, end_addr, NULL);
+	start_addr = epcm->start_addr;
 	end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);
 	snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],
-				   start_addr, end_addr);
+				   start_addr, end_addr,
+				   &emu->pcm_mixer[substream->number]);
 	if (epcm->voices[1])
 		snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1],
-					   start_addr, end_addr);
+					   start_addr, end_addr,
+					   &emu->pcm_mixer[substream->number]);
 	return 0;
 }
 
+static int snd_emu10k1_efx_playback_prepare(snd_pcm_substream_t * substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	emu10k1_pcm_t *epcm = runtime->private_data;
+	unsigned int start_addr, end_addr;
+	unsigned int channel_size;
+	int i;
+
+	start_addr = epcm->start_addr;
+	end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);
+
+	/*
+	 * the kX driver leaves some space between voices
+	 */
+	channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK;
+
+	snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,
+				   start_addr, start_addr + (channel_size / 2), NULL);
+
+	/* only difference with the master voice is we use it for the pointer */
+	snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],
+				   start_addr, start_addr + channel_size,
+				   &emu->efx_pcm_mixer[0]);
+
+	start_addr += channel_size;
+	for (i = 1; i < NUM_EFX_PLAYBACK; i++) {
+		snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i],
+					   start_addr, start_addr + channel_size,
+					   &emu->efx_pcm_mixer[i]);
+		start_addr += channel_size;
+	}
+
+	return 0;
+}
+
+static snd_pcm_hardware_t snd_emu10k1_efx_playback =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min =		NUM_EFX_PLAYBACK,
+	.channels_max =		NUM_EFX_PLAYBACK,
+	.buffer_bytes_max =	(64*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(64*1024),
+	.periods_min =		2,
+	.periods_max =		2,
+	.fifo_size =		0,
+};
+
 static int snd_emu10k1_capture_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * hw_params)
 {
@@ -439,6 +578,7 @@ static int snd_emu10k1_capture_prepare(s
 	emu10k1_pcm_t *epcm = runtime->private_data;
 	int idx;
 
+	/* zeroing the buffer size will stop capture */
 	snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
 	switch (epcm->type) {
 	case CAPTURE_AC97ADC:
@@ -478,67 +618,86 @@ static int snd_emu10k1_capture_prepare(s
 	return 0;
 }
 
-static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, emu10k1_voice_t *evoice)
+static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, int extra, emu10k1_voice_t *evoice)
 {
 	snd_pcm_runtime_t *runtime;
-	unsigned int voice, i, ccis, cra = 64, cs, sample;
+	unsigned int voice, stereo, i, ccis, cra = 64, cs, sample;
 
 	if (evoice == NULL)
 		return;
 	runtime = evoice->epcm->substream->runtime;
 	voice = evoice->number;
+	stereo = (!extra && runtime->channels == 2);
 	sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;
-	if (runtime->channels > 1) {
-		ccis = 28;
-		cs = 4;
-	} else {
-		ccis = 30;
-		cs = 2;
-	}
-	if (sample == 0)	/* 16-bit */
-		ccis *= 2;
-	for (i = 0; i < cs; i++)
+	ccis = emu10k1_ccis(stereo, sample == 0);
+	// set cs to 2 * number of cache registers beside the invalidated
+	cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;
+	if (cs > 16) cs = 16;
+	for (i = 0; i < cs; i++) {
 		snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);
+		if (stereo) {
+			snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);
+		}
+	}
 	// reset cache
 	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);
 	snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
-	if (runtime->channels > 1) {
+	if (stereo) {
 		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
 		snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
 	}
 	// fill cache
 	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
+	if (stereo) {
+		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
+	}
 }
 
-static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra)
+static void snd_emu10k1_playback_prepare_voice(emu10k1_t *emu, emu10k1_voice_t *evoice,
+					       int master, int extra,
+					       emu10k1_pcm_mixer_t *mix)
 {
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	emu10k1_pcm_mixer_t *mix;
-	unsigned int voice, pitch, pitch_target, tmp;
-	unsigned int attn;
+	unsigned int attn, vattn;
+	unsigned int voice, tmp;
 
 	if (evoice == NULL)	/* skip second voice for mono */
 		return;
 	substream = evoice->epcm->substream;
 	runtime = substream->runtime;
-	mix = &emu->pcm_mixer[substream->number];
 	voice = evoice->number;
-	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
-	pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+
 	attn = extra ? 0 : 0x00ff;
 	tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;
+	vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0;
 	snd_emu10k1_ptr_write(emu, IFATN, voice, attn);
-	snd_emu10k1_ptr_write(emu, VTFT, voice, (mix->attn[tmp] << 16) | 0xffff);
-	snd_emu10k1_ptr_write(emu, CVCF, voice, (mix->attn[tmp] << 16) | 0xffff);
-	snd_emu10k1_voice_clear_loop_stop(emu, voice);		
-	if (extra)
-		snd_emu10k1_voice_intr_enable(emu, voice);
+	snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | 0xffff);
+	snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | 0xffff);
 	snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f);
+	snd_emu10k1_voice_clear_loop_stop(emu, voice);
+}	
+
+static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra)
+{
+	snd_pcm_substream_t *substream;
+	snd_pcm_runtime_t *runtime;
+	unsigned int voice, pitch, pitch_target;
+
+	if (evoice == NULL)	/* skip second voice for mono */
+		return;
+	substream = evoice->epcm->substream;
+	runtime = substream->runtime;
+	voice = evoice->number;
+
+	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
+	pitch_target = emu10k1_calc_pitch_target(runtime->rate);
 	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
-	if (master)
+	if (master || evoice->epcm->type == PLAYBACK_EFX)
 		snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
 	snd_emu10k1_ptr_write(emu, IP, voice, pitch);
+	if (extra)
+		snd_emu10k1_voice_intr_enable(emu, voice);
 }
 
 static void snd_emu10k1_playback_stop_voice(emu10k1_t *emu, emu10k1_voice_t *evoice)
@@ -563,16 +722,21 @@ static int snd_emu10k1_playback_trigger(
 	emu10k1_t *emu = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	emu10k1_pcm_t *epcm = runtime->private_data;
+	emu10k1_pcm_mixer_t *mix;
 	int result = 0;
 
 	// printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));
 	spin_lock(&emu->reg_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		snd_emu10k1_playback_invalidate_cache(emu, epcm->extra);	/* do we need this? */
-		snd_emu10k1_playback_invalidate_cache(emu, epcm->voices[0]);
+		snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);	/* do we need this? */
+		snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]);
 		/* follow thru */
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		mix = &emu->pcm_mixer[substream->number];
+		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);
+		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);
+		snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);
 		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0);
 		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0);
 		snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);
@@ -601,10 +765,10 @@ static int snd_emu10k1_capture_trigger(s
 	emu10k1_pcm_t *epcm = runtime->private_data;
 	int result = 0;
 
-	// printk("trigger - emu10k1 = %p, cmd = %i, pointer = %i\n", emu, cmd, substream->ops->pointer(substream));
 	spin_lock(&emu->reg_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		// hmm this should cause full and half full interrupt to be raised?  
 		outl(epcm->capture_ipr, emu->port + IPR);
 		snd_emu10k1_intr_enable(emu, epcm->capture_inte);
 		// printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs);
@@ -680,6 +844,56 @@ static snd_pcm_uframes_t snd_emu10k1_pla
 	return ptr;
 }
 
+
+static int snd_emu10k1_efx_playback_trigger(snd_pcm_substream_t * substream,
+				        int cmd)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	emu10k1_pcm_t *epcm = runtime->private_data;
+	int i;
+	int result = 0;
+
+	spin_lock(&emu->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		// prepare voices
+		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {	
+			snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);
+		}
+		snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);
+
+		/* follow thru */
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);
+		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0,
+						   &emu->efx_pcm_mixer[0]);
+		for (i = 1; i < NUM_EFX_PLAYBACK; i++)
+			snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, 0,
+							   &emu->efx_pcm_mixer[i]);
+		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0);
+		snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);
+		for (i = 1; i < NUM_EFX_PLAYBACK; i++)
+			snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0);
+		epcm->running = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		epcm->running = 0;
+		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {	
+			snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
+		}
+		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+	spin_unlock(&emu->reg_lock);
+	return result;
+}
+
+
 static snd_pcm_uframes_t snd_emu10k1_capture_pointer(snd_pcm_substream_t * substream)
 {
 	emu10k1_t *emu = snd_pcm_substream_chip(substream);
@@ -707,9 +921,9 @@ static snd_pcm_hardware_t snd_emu10k1_pl
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000,
 	.rate_min =		4000,
-	.rate_max =		48000,
+	.rate_max =		96000,
 	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(128*1024),
@@ -768,6 +982,13 @@ static void snd_emu10k1_pcm_mixer_notify
 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_attn, idx, activate);
 }
 
+static void snd_emu10k1_pcm_efx_mixer_notify(emu10k1_t *emu, int idx, int activate)
+{
+	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_routing, idx, activate);
+	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_volume, idx, activate);
+	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_attn, idx, activate);
+}
+
 static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime)
 {
 	emu10k1_pcm_t *epcm = runtime->private_data;
@@ -775,6 +996,53 @@ static void snd_emu10k1_pcm_free_substre
 	kfree(epcm);
 }
 
+static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	emu10k1_pcm_mixer_t *mix;
+	int i;
+
+	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+		mix = &emu->efx_pcm_mixer[i];
+		mix->epcm = NULL;
+		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
+	}
+	return 0;
+}
+
+static int snd_emu10k1_efx_playback_open(snd_pcm_substream_t * substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	emu10k1_pcm_t *epcm;
+	emu10k1_pcm_mixer_t *mix;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int i;
+
+	epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL);
+	if (epcm == NULL)
+		return -ENOMEM;
+	epcm->emu = emu;
+	epcm->type = PLAYBACK_EFX;
+	epcm->substream = substream;
+	
+	emu->pcm_playback_efx_substream = substream;
+
+	runtime->private_data = epcm;
+	runtime->private_free = snd_emu10k1_pcm_free_substream;
+	runtime->hw = snd_emu10k1_efx_playback;
+	
+	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+		mix = &emu->efx_pcm_mixer[i];
+		mix->send_routing[0][0] = i;
+		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
+		mix->send_volume[0][0] = 255;
+		mix->attn[0] = 0xffff;
+		mix->epcm = epcm;
+		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1);
+	}
+	return 0;
+}
+
 static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream)
 {
 	emu10k1_t *emu = snd_pcm_substream_chip(substream);
@@ -969,6 +1237,19 @@ static snd_pcm_ops_t snd_emu10k1_capture
 	.pointer =		snd_emu10k1_capture_pointer,
 };
 
+/* EFX playback */
+static snd_pcm_ops_t snd_emu10k1_efx_playback_ops = {
+	.open =			snd_emu10k1_efx_playback_open,
+	.close =		snd_emu10k1_efx_playback_close,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_emu10k1_playback_hw_params,
+	.hw_free =		snd_emu10k1_efx_playback_hw_free,
+	.prepare =		snd_emu10k1_efx_playback_prepare,
+	.trigger =		snd_emu10k1_efx_playback_trigger,
+	.pointer =		snd_emu10k1_efx_playback_pointer,
+	.page =			snd_pcm_sgbuf_ops_page,
+};
+
 static void snd_emu10k1_pcm_free(snd_pcm_t *pcm)
 {
 	emu10k1_t *emu = pcm->private_data;
@@ -996,7 +1277,7 @@ int __devinit snd_emu10k1_pcm(emu10k1_t 
 
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-	strcpy(pcm->name, "EMU10K1");
+	strcpy(pcm->name, "ADC Capture/Standard PCM Playback");
 	emu->pcm = pcm;
 
 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
@@ -1012,6 +1293,39 @@ int __devinit snd_emu10k1_pcm(emu10k1_t 
 	return 0;
 }
 
+int __devinit snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	snd_pcm_substream_t *substream;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+
+	if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0)
+		return err;
+
+	pcm->private_data = emu;
+	pcm->private_free = snd_emu10k1_pcm_free;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops);
+
+	pcm->info_flags = 0;
+	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
+	strcpy(pcm->name, "Multichannel Playback");
+	emu->pcm = pcm;
+
+	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
+		if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)
+			return err;
+
+	if (rpcm)
+		*rpcm = pcm;
+
+	return 0;
+}
+
+
 static snd_pcm_ops_t snd_emu10k1_capture_mic_ops = {
 	.open =			snd_emu10k1_capture_mic_open,
 	.close =		snd_emu10k1_capture_mic_close,
@@ -1047,7 +1361,7 @@ int __devinit snd_emu10k1_pcm_mic(emu10k
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops);
 
 	pcm->info_flags = 0;
-	strcpy(pcm->name, "EMU10K1 MIC");
+	strcpy(pcm->name, "Mic Capture");
 	emu->pcm_mic = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
@@ -1114,7 +1428,7 @@ static int snd_emu10k1_pcm_efx_voices_ma
 
 static snd_kcontrol_new_t snd_emu10k1_pcm_efx_voices_mask = {
 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-	.name = "EFX voices mask",
+	.name = "Captured FX8010 Outputs",
 	.info = snd_emu10k1_pcm_efx_voices_mask_info,
 	.get = snd_emu10k1_pcm_efx_voices_mask_get,
 	.put = snd_emu10k1_pcm_efx_voices_mask_put
@@ -1385,13 +1699,23 @@ int __devinit snd_emu10k1_pcm_efx(emu10k
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops);
 
 	pcm->info_flags = 0;
-	strcpy(pcm->name, "EMU10K1 EFX");
+	strcpy(pcm->name, "Multichannel Capture/PT Playback");
 	emu->pcm_efx = pcm;
 	if (rpcm)
 		*rpcm = pcm;
 
-	emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A;
-	emu->efx_voices_mask[1] = 0;
+	/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs 
+	 * to these
+	 */	
+	
+	/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
+	if (emu->audigy) {
+		emu->efx_voices_mask[0] = 0;
+		emu->efx_voices_mask[1] = 0xffff;
+	} else {
+		emu->efx_voices_mask[0] = 0xffff0000;
+		emu->efx_voices_mask[1] = 0;
+	}
 	snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -140,38 +140,38 @@ static void snd_emu10k1_proc_read(snd_in
 		/* 29 */ "???",
 		/* 30 */ "???",
 		/* 31 */ "???",
-		/* 32 */ "???",
-		/* 33 */ "???",
-		/* 34 */ "???",
-		/* 35 */ "???",
-		/* 36 */ "???",
-		/* 37 */ "???",
-		/* 38 */ "???",
-		/* 39 */ "???",
-		/* 40 */ "???",
-		/* 41 */ "???",
-		/* 42 */ "???",
-		/* 43 */ "???",
-		/* 44 */ "???",
-		/* 45 */ "???",
-		/* 46 */ "???",
-		/* 47 */ "???",
-		/* 48 */ "???",
-		/* 49 */ "???",
-		/* 50 */ "???",
-		/* 51 */ "???",
-		/* 52 */ "???",
-		/* 53 */ "???",
-		/* 54 */ "???",
-		/* 55 */ "???",
-		/* 56 */ "???",
-		/* 57 */ "???",
-		/* 58 */ "???",
-		/* 59 */ "???",
-		/* 60 */ "???",
-		/* 61 */ "???",
-		/* 62 */ "???",
-		/* 33 */ "???"
+		/* 32 */ "FXBUS2_0",
+		/* 33 */ "FXBUS2_1",
+		/* 34 */ "FXBUS2_2",
+		/* 35 */ "FXBUS2_3",
+		/* 36 */ "FXBUS2_4",
+		/* 37 */ "FXBUS2_5",
+		/* 38 */ "FXBUS2_6",
+		/* 39 */ "FXBUS2_7",
+		/* 40 */ "FXBUS2_8",
+		/* 41 */ "FXBUS2_9",
+		/* 42 */ "FXBUS2_10",
+		/* 43 */ "FXBUS2_11",
+		/* 44 */ "FXBUS2_12",
+		/* 45 */ "FXBUS2_13",
+		/* 46 */ "FXBUS2_14",
+		/* 47 */ "FXBUS2_15",
+		/* 48 */ "FXBUS2_16",
+		/* 49 */ "FXBUS2_17",
+		/* 50 */ "FXBUS2_18",
+		/* 51 */ "FXBUS2_19",
+		/* 52 */ "FXBUS2_20",
+		/* 53 */ "FXBUS2_21",
+		/* 54 */ "FXBUS2_22",
+		/* 55 */ "FXBUS2_23",
+		/* 56 */ "FXBUS2_24",
+		/* 57 */ "FXBUS2_25",
+		/* 58 */ "FXBUS2_26",
+		/* 59 */ "FXBUS2_27",
+		/* 60 */ "FXBUS2_28",
+		/* 61 */ "FXBUS2_29",
+		/* 62 */ "FXBUS2_30",
+		/* 63 */ "FXBUS2_31"
 	};
 
 	emu10k1_t *emu = entry->private_data;
@@ -184,7 +184,7 @@ static void snd_emu10k1_proc_read(snd_in
 	snd_iprintf(buffer, "Card                  : %s\n",
 		    emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative"));
 	snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size);
-	snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes);
+	snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2);
 	snd_iprintf(buffer, "\n");
 	snd_iprintf(buffer, "Effect Send Routing   :\n");
 	for (idx = 0; idx < NUM_G; idx++) {
@@ -221,7 +221,7 @@ static void snd_emu10k1_proc_read(snd_in
 			snd_iprintf(buffer, "  Output %02i [%s]\n", idx, outputs[idx]);
 	}
 	snd_iprintf(buffer, "\nAll FX Outputs        :\n");
-	for (idx = 0; idx < 32; idx++)
+	for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++)
 		snd_iprintf(buffer, "  Output %02i [%s]\n", idx, outputs[idx]);
 	snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1);
 	snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1);
@@ -322,6 +322,26 @@ static long snd_emu10k1_fx8010_read(snd_
 	return 0;
 }
 
+static void snd_emu10k1_proc_voices_read(snd_info_entry_t *entry, 
+				  snd_info_buffer_t * buffer)
+{
+	emu10k1_t *emu = entry->private_data;
+	emu10k1_voice_t *voice;
+	int idx;
+	
+	snd_iprintf(buffer, "ch\tuse\tpcm\tefx\tsynth\tmidi\n");
+	for (idx = 0; idx < NUM_G; idx++) {
+		voice = &emu->voices[idx];
+		snd_iprintf(buffer, "%i\t%i\t%i\t%i\t%i\t%i\n",
+			idx,
+			voice->use,
+			voice->pcm,
+			voice->efx,
+			voice->synth,
+			voice->midi);
+	}
+}
+
 #ifdef CONFIG_SND_DEBUG
 static void snd_emu_proc_io_reg_read(snd_info_entry_t *entry,
 				     snd_info_buffer_t * buffer)
@@ -393,7 +413,7 @@ static void snd_ptr_write(emu10k1_t *emu
 
 
 static void snd_emu_proc_ptr_reg_read(snd_info_entry_t *entry,
-				      snd_info_buffer_t * buffer, int iobase, int offset, int length)
+				      snd_info_buffer_t * buffer, int iobase, int offset, int length, int voices)
 {
 	emu10k1_t *emu = entry->private_data;
 	unsigned long value;
@@ -405,7 +425,7 @@ static void snd_emu_proc_ptr_reg_read(sn
 	snd_iprintf(buffer, "Registers 0x%x\n", iobase);
 	for(i = offset; i < offset+length; i++) {
 		snd_iprintf(buffer, "%02X: ",i);
-		for (j = 0; j < 4; j++) {
+		for (j = 0; j < voices; j++) {
 			if(iobase == 0)
                 		value = snd_ptr_read(emu, 0, i, j);
 			else
@@ -446,25 +466,25 @@ static void snd_emu_proc_ptr_reg_write20
 static void snd_emu_proc_ptr_reg_read00a(snd_info_entry_t *entry,
 					 snd_info_buffer_t * buffer)
 {
-	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0, 0x40);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0, 0x40, 64);
 }
 
 static void snd_emu_proc_ptr_reg_read00b(snd_info_entry_t *entry,
 					 snd_info_buffer_t * buffer)
 {
-	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0x40, 0x40);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0x40, 0x40, 64);
 }
 
 static void snd_emu_proc_ptr_reg_read20a(snd_info_entry_t *entry,
 					 snd_info_buffer_t * buffer)
 {
-	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0, 0x40);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0, 0x40, 4);
 }
 
 static void snd_emu_proc_ptr_reg_read20b(snd_info_entry_t *entry,
 					 snd_info_buffer_t * buffer)
 {
-	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0x40, 0x40);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0x40, 0x40, 4);
 }
 #endif
 
@@ -482,22 +502,22 @@ int __devinit snd_emu10k1_proc_init(emu1
 		entry->c.text.write = snd_emu_proc_io_reg_write;
 	}
 	if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) {
-		snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read00a);
+		snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a);
 		entry->c.text.write_size = 64;
 		entry->c.text.write = snd_emu_proc_ptr_reg_write00;
 	}
 	if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) {
-		snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read00b);
+		snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b);
 		entry->c.text.write_size = 64;
 		entry->c.text.write = snd_emu_proc_ptr_reg_write00;
 	}
 	if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) {
-		snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read20a);
+		snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a);
 		entry->c.text.write_size = 64;
 		entry->c.text.write = snd_emu_proc_ptr_reg_write20;
 	}
 	if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) {
-		snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read20b);
+		snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b);
 		entry->c.text.write_size = 64;
 		entry->c.text.write = snd_emu_proc_ptr_reg_write20;
 	}
@@ -506,6 +526,9 @@ int __devinit snd_emu10k1_proc_init(emu1
 	if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
 		snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read);
 
+	if (! snd_card_proc_new(emu->card, "voices", &entry))
+		snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read);
+
 	if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) {
 		entry->content = SNDRV_INFO_CONTENT_DATA;
 		entry->private_data = emu;
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -91,6 +91,38 @@ void snd_emu10k1_ptr_write(emu10k1_t *em
 	}
 }
 
+unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu, 
+					  unsigned int reg, 
+					  unsigned int chn)
+{
+	unsigned long flags;
+	unsigned int regptr, val;
+  
+	regptr = (reg << 16) | chn;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	outl(regptr, emu->port + 0x20 + PTR);
+	val = inl(emu->port + 0x20 + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+	return val;
+}
+
+void snd_emu10k1_ptr20_write(emu10k1_t *emu, 
+				   unsigned int reg, 
+				   unsigned int chn, 
+				   unsigned int data)
+{
+	unsigned int regptr;
+	unsigned long flags;
+
+	regptr = (reg << 16) | chn;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	outl(regptr, emu->port + 0x20 + PTR);
+	outl(data, emu->port + 0x20 + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
 void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb)
 {
 	unsigned long flags;
@@ -170,6 +202,63 @@ void snd_emu10k1_voice_intr_ack(emu10k1_
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
+void snd_emu10k1_voice_half_loop_intr_enable(emu10k1_t *emu, unsigned int voicenum)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	/* voice interrupt */
+	if (voicenum >= 32) {
+		outl(HLIEH << 16, emu->port + PTR);
+		val = inl(emu->port + DATA);
+		val |= 1 << (voicenum - 32);
+	} else {
+		outl(HLIEL << 16, emu->port + PTR);
+		val = inl(emu->port + DATA);
+		val |= 1 << voicenum;
+	}
+	outl(val, emu->port + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+void snd_emu10k1_voice_half_loop_intr_disable(emu10k1_t *emu, unsigned int voicenum)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	/* voice interrupt */
+	if (voicenum >= 32) {
+		outl(HLIEH << 16, emu->port + PTR);
+		val = inl(emu->port + DATA);
+		val &= ~(1 << (voicenum - 32));
+	} else {
+		outl(HLIEL << 16, emu->port + PTR);
+		val = inl(emu->port + DATA);
+		val &= ~(1 << voicenum);
+	}
+	outl(val, emu->port + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+void snd_emu10k1_voice_half_loop_intr_ack(emu10k1_t *emu, unsigned int voicenum)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	/* voice interrupt */
+	if (voicenum >= 32) {
+		outl(HLIPH << 16, emu->port + PTR);
+		voicenum = 1 << (voicenum - 32);
+	} else {
+		outl(HLIPL << 16, emu->port + PTR);
+		voicenum = 1 << voicenum;
+	}
+	outl(voicenum, emu->port + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
 void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum)
 {
 	unsigned long flags;
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
--- a/sound/pci/emu10k1/irq.c
+++ b/sound/pci/emu10k1/irq.c
@@ -33,7 +33,7 @@
 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	emu10k1_t *emu = dev_id;
-	unsigned int status, orig_status;
+	unsigned int status, status2, orig_status, orig_status2;
 	int handled = 0;
 
 	while ((status = inl(emu->port + IPR)) != 0) {
@@ -73,6 +73,21 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 				val >>= 1;
 				pvoice++;
 			}
+			val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
+			for (voice = 0; voice <= voice_max; voice++) {
+				if (voice == 0x20)
+					val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
+				if (val & 1) {
+					if (pvoice->use && pvoice->interrupt != NULL) {
+						pvoice->interrupt(emu, pvoice);
+						snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
+					} else {
+						snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
+					}
+				}
+				val >>= 1;
+				pvoice++;
+			}
 			status &= ~IPR_CHANNELLOOP;
 		}
 		status &= ~IPR_CHANNELNUMBERMASK;
@@ -134,7 +149,7 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 		}
 		if (status) {
 			unsigned int bits;
-			snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+			//snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
 			//make sure any interrupts we don't handle are disabled:
 			bits = INTE_FXDSPENABLE |
 				INTE_PCIERRORENABLE |
@@ -155,5 +170,20 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 		}
 		outl(orig_status, emu->port + IPR); /* ack all */
 	}
+	if (emu->audigy && emu->revision == 4) { /* P16V */	
+		while ((status2 = inl(emu->port + IPR2)) != 0) {
+			u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
+			emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]);
+			orig_status2 = status2;
+			if(status2 & mask) {
+				if(pvoice->use) {
+					snd_pcm_period_elapsed(pvoice->epcm->substream);
+				} else { 
+					snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
+				}
+			}
+			outl(orig_status2, emu->port + IPR2); /* ack all */
+		}
+	}
 	return IRQ_RETVAL(handled);
 }
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/emu10k1/p16v.c
@@ -0,0 +1,736 @@
+/*
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *  Driver p16v chips
+ *  Version: 0.22
+ *
+ *  FEATURES currently supported:
+ *    Output fixed at S32_LE, 2 channel to hw:0,0
+ *    Rates: 44.1, 48, 96, 192.
+ *
+ *  Changelog:
+ *  0.8
+ *    Use separate card based buffer for periods table.
+ *  0.9
+ *    Use 2 channel output streams instead of 8 channel.
+ *       (8 channel output streams might be good for ASIO type output)
+ *    Corrected speaker output, so Front -> Front etc.
+ *  0.10
+ *    Fixed missed interrupts.
+ *  0.11
+ *    Add Sound card model number and names.
+ *    Add Analog volume controls.
+ *  0.12
+ *    Corrected playback interrupts. Now interrupt per period, instead of half period.
+ *  0.13
+ *    Use single trigger for multichannel.
+ *  0.14
+ *    Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.
+ *  0.15
+ *    Force buffer_size / period_size == INTEGER.
+ *  0.16
+ *    Update p16v.c to work with changed alsa api.
+ *  0.17
+ *    Update p16v.c to work with changed alsa api. Removed boot_devs.
+ *  0.18
+ *    Merging with snd-emu10k1 driver.
+ *  0.19
+ *    One stereo channel at 24bit now works.
+ *  0.20
+ *    Added better register defines.
+ *  0.21
+ *    Integrated with snd-emu10k1 driver.
+ *  0.22
+ *    Removed #if 0 ... #endif
+ *
+ *
+ *  BUGS:
+ *    Some stability problems when unloading the snd-p16v kernel module.
+ *    --
+ *
+ *  TODO:
+ *    SPDIF out.
+ *    Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz.
+ *    Currently capture fixed at 48000Hz.
+ *
+ *    --
+ *  GENERAL INFO:
+ *    Model: SB0240
+ *    P16V Chip: CA0151-DBS
+ *    Audigy 2 Chip: CA0102-IAT
+ *    AC97 Codec: STAC 9721
+ *    ADC: Philips 1361T (Stereo 24bit)
+ *    DAC: CS4382-K (8-channel, 24bit, 192Khz)
+ *
+ *  This code was initally based on code from ALSA's emu10k1x.c which is:
+ *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.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
+ *
+ */
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/info.h>
+#include <sound/emu10k1.h>
+#include "p16v.h"
+
+#define SET_CHANNEL 0  /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
+#define PCM_FRONT_CHANNEL 0
+#define PCM_REAR_CHANNEL 1
+#define PCM_CENTER_LFE_CHANNEL 2
+#define PCM_UNKNOWN_CHANNEL 3
+#define CONTROL_FRONT_CHANNEL 0
+#define CONTROL_REAR_CHANNEL 3
+#define CONTROL_CENTER_LFE_CHANNEL 1
+#define CONTROL_UNKNOWN_CHANNEL 2
+
+/* Card IDs:
+ * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2002 -> Audigy2 ZS 7.1 Model:SB0350
+ * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1007 -> Audigy2 6.1    Model:SB0240
+ * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1002 -> Audigy2 Platinum  Model:SB msb0240230009266
+ * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2007 -> Audigy4 Pro Model:SB0380 M1SB0380472001901E
+ *
+ */
+
+ /* hardware definition */
+static snd_pcm_hardware_t snd_p16v_playback_hw = {
+	.info =			(SNDRV_PCM_INFO_MMAP | 
+				 SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */
+	.rates =		SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 ,
+	.rate_min =		48000,
+	.rate_max =		192000,
+	.channels_min =		8, 
+	.channels_max =		8,
+	.buffer_bytes_max =	(32*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(16*1024),
+	.periods_min =		2,
+	.periods_max =		8,
+	.fifo_size =		0,
+};
+
+static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime)
+{
+	snd_pcm_t *epcm = runtime->private_data;
+  
+	if (epcm) {
+        	//snd_printk("epcm free: %p\n", epcm);
+		kfree(epcm);
+	}
+}
+
+/* open_playback callback */
+static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, int channel_id)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+        emu10k1_voice_t *channel = &(emu->p16v_voices[channel_id]);
+	emu10k1_pcm_t *epcm;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL);
+        //snd_printk("epcm kcalloc: %p\n", epcm);
+
+	if (epcm == NULL)
+		return -ENOMEM;
+	epcm->emu = emu;
+	epcm->substream = substream;
+        //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
+  
+	runtime->private_data = epcm;
+	runtime->private_free = snd_p16v_pcm_free_substream;
+  
+	runtime->hw = snd_p16v_playback_hw;
+
+        channel->emu = emu;
+        channel->number = channel_id;
+
+        channel->use=1;
+	//snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
+        //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+        //channel->interrupt = snd_p16v_pcm_channel_interrupt;
+        channel->epcm=epcm;
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+                return err;
+
+	return 0;
+}
+
+/* close callback */
+static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	//snd_pcm_runtime_t *runtime = substream->runtime;
+        //emu10k1_pcm_t *epcm = runtime->private_data;
+        emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
+/* FIXME: maybe zero others */
+	return 0;
+}
+
+static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream)
+{
+	return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL);
+}
+
+/* hw_params callback */
+static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream,
+				      snd_pcm_hw_params_t * hw_params)
+{
+	int result;
+        //snd_printk("hw_params alloc: substream=%p\n", substream);
+	result = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+        //snd_printk("hw_params alloc: result=%d\n", result);
+	//dump_stack();
+	return result;
+}
+
+/* hw_free callback */
+static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream)
+{
+	int result;
+        //snd_printk("hw_params free: substream=%p\n", substream);
+	result = snd_pcm_lib_free_pages(substream);
+        //snd_printk("hw_params free: result=%d\n", result);
+	//dump_stack();
+	return result;
+}
+
+/* prepare playback callback */
+static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	//emu10k1_pcm_t *epcm = runtime->private_data;
+	int channel = substream->pcm->device - emu->p16v_device_offset;
+	u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel));
+	u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
+	int i;
+	u32 tmp;
+	
+        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
+        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
+	//snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes);
+	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
+        switch (runtime->rate) {
+	case 44100:
+	  snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */
+	  break;
+	case 48000:
+	  snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */
+	  break;
+	case 96000:
+	  snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */
+	  break;
+	case 192000:
+	  snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */
+	  break;
+	default:
+	  snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */
+	  break;
+	}
+	/* FIXME: Check emu->buffer.size before actually writing to it. */
+        for(i=0; i < runtime->periods; i++) {
+		table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
+		table_base[(i*2)+1]=period_size_bytes<<16;
+	}
+ 
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel));
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0);
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
+	snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0);
+	snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0);
+	snd_emu10k1_ptr20_write(emu, 0x08, channel, 0);
+
+	return 0;
+}
+
+static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb)
+{
+	unsigned long flags;
+	unsigned int enable;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	enable = inl(emu->port + INTE2) | intrenb;
+	outl(enable, emu->port + INTE2);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+static void snd_p16v_intr_disable(emu10k1_t *emu, unsigned int intrenb)
+{
+	unsigned long flags;
+	unsigned int disable;
+
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	disable = inl(emu->port + INTE2) & (~intrenb);
+	outl(disable, emu->port + INTE2);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+/* trigger_playback callback */
+static int snd_p16v_pcm_trigger_playback(snd_pcm_substream_t *substream,
+				    int cmd)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime;
+	emu10k1_pcm_t *epcm;
+	int channel;
+	int result = 0;
+	struct list_head *pos;
+        snd_pcm_substream_t *s;
+	u32 basic = 0;
+	u32 inte = 0;
+	int running=0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		running=1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	default:
+		running=0;
+		break;
+	}
+        snd_pcm_group_for_each(pos, substream) {
+                s = snd_pcm_group_substream_entry(pos);
+		runtime = s->runtime;
+		epcm = runtime->private_data;
+		channel = substream->pcm->device-emu->p16v_device_offset;
+		//snd_printk("p16v channel=%d\n",channel);
+		epcm->running = running;
+		basic |= (0x1<<channel);
+		inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);
+                snd_pcm_trigger_done(s, substream);
+        }
+	//snd_printk("basic=0x%x, inte=0x%x\n",basic, inte);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		snd_p16v_intr_enable(emu, inte);
+		snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)| (basic));
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(basic));
+		snd_p16v_intr_disable(emu, inte);
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+	return result;
+}
+
+/* pointer_playback callback */
+static snd_pcm_uframes_t
+snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream)
+{
+	emu10k1_t *emu = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	emu10k1_pcm_t *epcm = runtime->private_data;
+	snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+	int channel = substream->pcm->device - emu->p16v_device_offset;
+	if (!epcm->running)
+		return 0;
+
+	ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);
+	ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);
+	ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);
+	if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);
+	ptr2 = bytes_to_frames(runtime, ptr1);
+	ptr2+= (ptr4 >> 3) * runtime->period_size;
+	ptr=ptr2;
+        if (ptr >= runtime->buffer_size)
+		ptr -= runtime->buffer_size;
+
+	return ptr;
+}
+
+/* operators */
+static snd_pcm_ops_t snd_p16v_playback_front_ops = {
+	.open =        snd_p16v_pcm_open_playback_front,
+	.close =       snd_p16v_pcm_close_playback,
+	.ioctl =       snd_pcm_lib_ioctl,
+	.hw_params =   snd_p16v_pcm_hw_params_playback,
+	.hw_free =     snd_p16v_pcm_hw_free_playback,
+	.prepare =     snd_p16v_pcm_prepare_playback,
+	.trigger =     snd_p16v_pcm_trigger_playback,
+	.pointer =     snd_p16v_pcm_pointer_playback,
+};
+
+int snd_p16v_free(emu10k1_t *chip)
+{
+	// release the data
+	if (chip->p16v_buffer.area) {
+		snd_dma_free_pages(&chip->p16v_buffer);
+		//snd_printk("period lables free: %p\n", &chip->p16v_buffer);
+	}
+	return 0;
+}
+
+static void snd_p16v_pcm_free(snd_pcm_t *pcm)
+{
+	emu10k1_t *emu = pcm->private_data;
+	//snd_printk("snd_p16v_pcm_free pcm: called\n");
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+	emu->pcm = NULL;
+}
+
+int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm)
+{
+	snd_pcm_t *pcm;
+	snd_pcm_substream_t *substream;
+	int err;
+        int capture=0;
+  
+	//snd_printk("snd_p16v_pcm called. device=%d\n", device);
+	emu->p16v_device_offset = device;
+	if (rpcm)
+		*rpcm = NULL;
+        //if (device == 0) capture=1; 
+	if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
+		return err;
+  
+	pcm->private_data = emu;
+	pcm->private_free = snd_p16v_pcm_free;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops);
+
+	pcm->info_flags = 0;
+	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
+	strcpy(pcm->name, "p16v");
+	emu->pcm = pcm;
+
+	for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 
+	    substream; 
+	    substream = substream->next) {
+		if ((err = snd_pcm_lib_preallocate_pages(substream, 
+							 SNDRV_DMA_TYPE_DEV, 
+							 snd_dma_pci_data(emu->pci), 
+							 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */
+			return err;
+		//snd_printk("preallocate playback substream: err=%d\n", err);
+	}
+
+	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 
+	      substream; 
+	      substream = substream->next) {
+ 		if ((err = snd_pcm_lib_preallocate_pages(substream, 
+	                                           SNDRV_DMA_TYPE_DEV, 
+	                                           snd_dma_pci_data(emu->pci), 
+	                                           64*1024, 64*1024)) < 0)
+			return err;
+		//snd_printk("preallocate capture substream: err=%d\n", err);
+	}
+  
+	if (rpcm)
+		*rpcm = pcm;
+  
+	return 0;
+}
+
+static int snd_p16v_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+        uinfo->count = 2;
+        uinfo->value.integer.min = 0;
+        uinfo->value.integer.max = 255;
+        return 0;
+}
+
+static int snd_p16v_volume_get(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol, int reg, int high_low)
+{
+        emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+        u32 value;
+
+        value = snd_emu10k1_ptr20_read(emu, reg, high_low);
+	if (high_low == 1) {
+        	ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
+        	ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
+	} else {
+        	ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */
+        	ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */
+	}
+        return 0;
+}
+
+static int snd_p16v_volume_get_spdif_front(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER7;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_get_spdif_center_lfe(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER7;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+static int snd_p16v_volume_get_spdif_unknown(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER8;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+static int snd_p16v_volume_get_spdif_rear(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER8;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_get_analog_front(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER9;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_get_analog_center_lfe(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER9;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+static int snd_p16v_volume_get_analog_rear(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER10;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_get_analog_unknown(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER10;
+        return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol, int reg, int high_low)
+{
+        emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+        u32 value;
+        value = snd_emu10k1_ptr20_read(emu, reg, 0);
+        //value = value & 0xffff;
+	if (high_low == 1) {
+		value &= 0xffff;
+	        value = value | ((0xff - ucontrol->value.integer.value[0]) << 24) | ((0xff - ucontrol->value.integer.value[1]) << 16);
+	} else {
+		value &= 0xffff0000;
+        	value = value | ((0xff - ucontrol->value.integer.value[0]) << 8) | ((0xff - ucontrol->value.integer.value[1]) );
+	}
+        	snd_emu10k1_ptr20_write(emu, reg, 0, value);
+        return 1;
+}
+
+static int snd_p16v_volume_put_spdif_front(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER7;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_spdif_center_lfe(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER7;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_spdif_unknown(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER8;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_spdif_rear(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER8;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_analog_front(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER9;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_analog_center_lfe(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER9;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_analog_rear(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 1;
+	int reg = PLAYBACK_VOLUME_MIXER10;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static int snd_p16v_volume_put_analog_unknown(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+	int high_low = 0;
+	int reg = PLAYBACK_VOLUME_MIXER10;
+        return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
+}
+
+static snd_kcontrol_new_t snd_p16v_volume_control_analog_front =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD Analog Front Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_analog_front,
+        .put =          snd_p16v_volume_put_analog_front
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD Analog Center/LFE Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_analog_center_lfe,
+        .put =          snd_p16v_volume_put_analog_center_lfe
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD Analog Unknown Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_analog_unknown,
+        .put =          snd_p16v_volume_put_analog_unknown
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD Analog Rear Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_analog_rear,
+        .put =          snd_p16v_volume_put_analog_rear
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD SPDIF Front Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_spdif_front,
+        .put =          snd_p16v_volume_put_spdif_front
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD SPDIF Center/LFE Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_spdif_center_lfe,
+        .put =          snd_p16v_volume_put_spdif_center_lfe
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD SPDIF Unknown Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_spdif_unknown,
+        .put =          snd_p16v_volume_put_spdif_unknown
+};
+
+static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear =
+{
+        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name =         "HD SPDIF Rear Volume",
+        .info =         snd_p16v_volume_info,
+        .get =          snd_p16v_volume_get_spdif_rear,
+        .put =          snd_p16v_volume_put_spdif_rear
+};
+
+int snd_p16v_mixer(emu10k1_t *emu)
+{
+        int err;
+        snd_kcontrol_t *kctl;
+        snd_card_t *card = emu->card;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_front, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_rear, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_center_lfe, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_unknown, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_front, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_rear, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_center_lfe, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_unknown, emu)) == NULL)
+                return -ENOMEM;
+        if ((err = snd_ctl_add(card, kctl)))
+                return err;
+        return 0;
+}
+
diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/emu10k1/p16v.h
@@ -0,0 +1,299 @@
+/*
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *  Driver p16v chips
+ *  Version: 0.21
+ *
+ *  FEATURES currently supported:
+ *    Output fixed at S32_LE, 2 channel to hw:0,0
+ *    Rates: 44.1, 48, 96, 192.
+ *
+ *  Changelog:
+ *  0.8
+ *    Use separate card based buffer for periods table.
+ *  0.9
+ *    Use 2 channel output streams instead of 8 channel.
+ *       (8 channel output streams might be good for ASIO type output)
+ *    Corrected speaker output, so Front -> Front etc.
+ *  0.10
+ *    Fixed missed interrupts.
+ *  0.11
+ *    Add Sound card model number and names.
+ *    Add Analog volume controls.
+ *  0.12
+ *    Corrected playback interrupts. Now interrupt per period, instead of half period.
+ *  0.13
+ *    Use single trigger for multichannel.
+ *  0.14
+ *    Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.
+ *  0.15
+ *    Force buffer_size / period_size == INTEGER.
+ *  0.16
+ *    Update p16v.c to work with changed alsa api.
+ *  0.17
+ *    Update p16v.c to work with changed alsa api. Removed boot_devs.
+ *  0.18
+ *    Merging with snd-emu10k1 driver.
+ *  0.19
+ *    One stereo channel at 24bit now works.
+ *  0.20
+ *    Added better register defines.
+ *  0.21
+ *    Split from p16v.c
+ *
+ *
+ *  BUGS:
+ *    Some stability problems when unloading the snd-p16v kernel module.
+ *    --
+ *
+ *  TODO:
+ *    SPDIF out.
+ *    Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz.
+ *    Currently capture fixed at 48000Hz.
+ *
+ *    --
+ *  GENERAL INFO:
+ *    Model: SB0240
+ *    P16V Chip: CA0151-DBS
+ *    Audigy 2 Chip: CA0102-IAT
+ *    AC97 Codec: STAC 9721
+ *    ADC: Philips 1361T (Stereo 24bit)
+ *    DAC: CS4382-K (8-channel, 24bit, 192Khz)
+ *
+ *  This code was initally based on code from ALSA's emu10k1x.c which is:
+ *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.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
+ *
+ */
+
+/********************************************************************************************************/
+/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers                     */
+/********************************************************************************************************/
+                                                                                                                           
+/* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE.
+ * The sample rate is also controlled by the same registers that control the rate of the EMU10K2 sample rate converters.
+ */
+
+/* Initally all registers from 0x00 to 0x3f have zero contents. */
+#define PLAYBACK_LIST_ADDR	0x00		/* Base DMA address of a list of pointers to each period/size */
+						/* One list entry: 4 bytes for DMA address, 
+						 * 4 bytes for period_size << 16.
+						 * One list entry is 8 bytes long.
+						 * One list entry for each period in the buffer.
+						 */
+#define PLAYBACK_LIST_SIZE	0x01		/* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000  */
+#define PLAYBACK_LIST_PTR	0x02		/* Pointer to the current period being played */
+#define PLAYBACK_UNKNOWN3	0x03		/* Not used */
+#define PLAYBACK_DMA_ADDR	0x04		/* Playback DMA addresss */
+#define PLAYBACK_PERIOD_SIZE	0x05		/* Playback period size. win2000 uses 0x04000000 */
+#define PLAYBACK_POINTER	0x06		/* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */
+#define PLAYBACK_FIFO_END_ADDRESS	0x07		/* Playback FIFO end address */
+#define PLAYBACK_FIFO_POINTER	0x08		/* Playback FIFO pointer and number of valid sound samples in cache */
+#define PLAYBACK_UNKNOWN9	0x09		/* Not used */
+#define CAPTURE_DMA_ADDR	0x10		/* Capture DMA address */
+#define CAPTURE_BUFFER_SIZE	0x11		/* Capture buffer size */
+#define CAPTURE_POINTER		0x12		/* Capture buffer pointer. Sample currently in ADC */
+#define CAPTURE_FIFO_POINTER	0x13		/* Capture FIFO pointer and number of valid sound samples in cache */
+#define CAPTURE_P16V_VOLUME1	0x14		/* Low: Capture volume 0xXXXX3030 */
+#define CAPTURE_P16V_VOLUME2	0x15		/* High:Has no effect on capture volume */
+#define CAPTURE_P16V_SOURCE     0x16            /* P16V source select. Set to 0x0700E4E5 for AC97 CAPTURE */
+						/* [0:1] Capture input 0 channel select. 0 = Capture output 0.
+						 *                                       1 = Capture output 1.
+						 *                                       2 = Capture output 2.
+						 *                                       3 = Capture output 3.
+						 * [3:2] Capture input 1 channel select. 0 = Capture output 0.
+						 *                                       1 = Capture output 1.
+						 *                                       2 = Capture output 2.
+						 *                                       3 = Capture output 3.
+						 * [5:4] Capture input 2 channel select. 0 = Capture output 0.
+						 *                                       1 = Capture output 1.
+						 *                                       2 = Capture output 2.
+						 *                                       3 = Capture output 3.
+						 * [7:6] Capture input 3 channel select. 0 = Capture output 0.
+						 *                                       1 = Capture output 1.
+						 *                                       2 = Capture output 2.
+						 *                                       3 = Capture output 3.
+						 * [9:8] Playback input 0 channel select. 0 = Play output 0.
+						 *                                        1 = Play output 1.
+						 *                                        2 = Play output 2.
+						 *                                        3 = Play output 3.
+						 * [11:10] Playback input 1 channel select. 0 = Play output 0.
+						 *                                          1 = Play output 1.
+						 *                                          2 = Play output 2.
+						 *                                          3 = Play output 3.
+						 * [13:12] Playback input 2 channel select. 0 = Play output 0.
+						 *                                          1 = Play output 1.
+						 *                                          2 = Play output 2.
+						 *                                          3 = Play output 3.
+						 * [15:14] Playback input 3 channel select. 0 = Play output 0.
+						 *                                          1 = Play output 1.
+						 *                                          2 = Play output 2.
+						 *                                          3 = Play output 3.
+						 * [19:16] Playback mixer output enable. 1 bit per channel.
+						 * [23:20] Capture mixer output enable. 1 bit per channel.
+						 * [26:24] FX engine channel capture 0 = 0x60-0x67.
+						 *                                   1 = 0x68-0x6f.
+						 *                                   2 = 0x70-0x77.
+						 *                                   3 = 0x78-0x7f.
+						 *                                   4 = 0x80-0x87.
+						 *                                   5 = 0x88-0x8f.
+						 *                                   6 = 0x90-0x97.
+						 *                                   7 = 0x98-0x9f.
+						 * [31:27] Not used.
+						 */
+
+						/* 0x1 = capture on.
+						 * 0x100 = capture off.
+						 * 0x200 = capture off.
+						 * 0x1000 = capture off.
+						 */
+#define CAPTURE_RATE_STATUS		0x17		/* Capture sample rate. Read only */
+						/* [15:0] Not used.
+						 * [18:16] Channel 0 Detected sample rate. 0 - 44.1khz
+						 *                               1 - 48 khz
+						 *                               2 - 96 khz
+						 *                               3 - 192 khz
+						 *                               7 - undefined rate.
+						 * [19] Channel 0. 1 - Valid, 0 - Not Valid.
+						 * [22:20] Channel 1 Detected sample rate. 
+						 * [23] Channel 1. 1 - Valid, 0 - Not Valid.
+						 * [26:24] Channel 2 Detected sample rate. 
+						 * [27] Channel 2. 1 - Valid, 0 - Not Valid.
+						 * [30:28] Channel 3 Detected sample rate. 
+						 * [31] Channel 3. 1 - Valid, 0 - Not Valid.
+						 */
+/* 0x18 - 0x1f unused */
+#define PLAYBACK_LAST_SAMPLE    0x20		/* The sample currently being played. Read only */
+/* 0x21 - 0x3f unused */
+#define BASIC_INTERRUPT         0x40		/* Used by both playback and capture interrupt handler */
+						/* Playback (0x1<<channel_id) Don't touch high 16bits. */
+						/* Capture  (0x100<<channel_id). not tested */
+						/* Start Playback [3:0] (one bit per channel)
+						 * Start Capture [11:8] (one bit per channel)
+						 * Record source select for channel 0 [18:16]
+						 * Record source select for channel 1 [22:20]
+						 * Record source select for channel 2 [26:24]
+						 * Record source select for channel 3 [30:28]
+						 * 0 - SPDIF channel.
+						 * 1 - I2S channel.
+						 * 2 - SRC48 channel.
+						 * 3 - SRCMulti_SPDIF channel.
+						 * 4 - SRCMulti_I2S channel.
+						 * 5 - SPDIF channel.
+						 * 6 - fxengine capture.
+						 * 7 - AC97 capture.
+						 */
+						/* Default 41110000.
+						 * Writing 0xffffffff hangs the PC.
+						 * Writing 0xffff0000 -> 77770000 so it must be some sort of route.
+						 * bit 0x1 starts DMA playback on channel_id 0
+						 */
+/* 0x41,42 take values from 0 - 0xffffffff, but have no effect on playback */
+/* 0x43,0x48 do not remember settings */
+/* 0x41-45 unused */
+#define WATERMARK            0x46		/* Test bit to indicate cache level usage */
+						/* Values it can have while playing on channel 0. 
+						 * 0000f000, 0000f004, 0000f008, 0000f00c.
+						 * Readonly.
+						 */
+/* 0x47-0x4f unused */
+/* 0x50-0x5f Capture cache data */
+#define SRCSel			0x60            /* SRCSel. Default 0x4. Bypass P16V 0x14 */
+						/* [0] 0 = 10K2 audio, 1 = SRC48 mixer output.
+						 * [2] 0 = 10K2 audio, 1 = SRCMulti SPDIF mixer output.
+						 * [4] 0 = 10K2 audio, 1 = SRCMulti I2S mixer output.
+						 */
+						/* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */
+						/* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */
+						/* SRC48 and SRCMULTI sample rate select and output select. */
+						/* 0xffffffff -> 0xC0000015
+						 * 0xXXXXXXX4 = Enable Front Left/Right
+						 * Enable PCMs
+						 */
+
+/* 0x61 -> 0x6c are Volume controls */
+#define PLAYBACK_VOLUME_MIXER1  0x61		/* SRC48 Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER2  0x62		/* SRC48 High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER3  0x63		/* SRCMULTI SPDIF Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER4  0x64		/* SRCMULTI SPDIF High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER5  0x65		/* SRCMULTI I2S Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER6  0x66		/* SRCMULTI I2S High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER7  0x67		/* P16V Low to SRCMULTI SPDIF mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER8  0x68		/* P16V High to SRCMULTI SPDIF mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER9  0x69		/* P16V Low to SRCMULTI I2S mixer input volume control. */
+						/* 0xXXXX3030 = PCM0 Volume (Front).
+						 * 0x3030XXXX = PCM1 Volume (Center)
+						 */
+#define PLAYBACK_VOLUME_MIXER10  0x6a		/* P16V High to SRCMULTI I2S mixer input volume control. */
+						/* 0x3030XXXX = PCM3 Volume (Rear). */
+#define PLAYBACK_VOLUME_MIXER11  0x6b		/* E10K2 Low to SRC48 mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER12 0x6c		/* E10K2 High to SRC48 mixer input volume control. */
+
+#define SRC48_ENABLE            0x6d            /* SRC48 input audio enable */
+						/* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */
+						/* [23:16] The corresponding P16V channel to SRC48 enabled if == 1.
+						 * [31:24] The corresponding E10K2 channel to SRC48 enabled.
+						 */
+#define SRCMULTI_ENABLE         0x6e            /* SRCMulti input audio enable. Default 0xffffffff */
+						/* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */
+						/* [7:0] The corresponding P16V channel to SRCMulti_I2S enabled if == 1.
+						 * [15:8] The corresponding E10K2 channel to SRCMulti I2S enabled.
+						 * [23:16] The corresponding P16V channel to SRCMulti SPDIF enabled.
+						 * [31:24] The corresponding E10K2 channel to SRCMulti SPDIF enabled.
+						 */
+						/* Bypass P16V 0xff00ff00 
+						 * Bitmap. 0 = Off, 1 = On.
+						 * P16V playback outputs:
+						 * 0xXXXXXXX1 = PCM0 Left. (Front)
+						 * 0xXXXXXXX2 = PCM0 Right.
+						 * 0xXXXXXXX4 = PCM1 Left. (Center/LFE)
+						 * 0xXXXXXXX8 = PCM1 Right.
+						 * 0xXXXXXX1X = PCM2 Left. (Unknown)
+						 * 0xXXXXXX2X = PCM2 Right.
+						 * 0xXXXXXX4X = PCM3 Left. (Rear)
+						 * 0xXXXXXX8X = PCM3 Right.
+						 */
+#define AUDIO_OUT_ENABLE        0x6f            /* Default: 000100FF */
+						/* [3:0] Does something, but not documented. Probably capture enable.
+						 * [7:4] Playback channels enable. not documented.
+						 * [16] AC97 output enable if == 1
+						 * [30] 0 = SRCMulti_I2S input from fxengine 0x68-0x6f.
+						 *      1 = SRCMulti_I2S input from SRC48 output.
+						 * [31] 0 = SRCMulti_SPDIF input from fxengine 0x60-0x67.
+						 *      1 = SRCMulti_SPDIF input from SRC48 output.
+						 */
+						/* 0xffffffff -> C00100FF */
+						/* 0 -> Not playback sound, irq still running */
+						/* 0xXXXXXX10 = PCM0 Left/Right On. (Front)
+						 * 0xXXXXXX20 = PCM1 Left/Right On. (Center/LFE)
+						 * 0xXXXXXX40 = PCM2 Left/Right On. (Unknown)
+						 * 0xXXXXXX80 = PCM3 Left/Right On. (Rear)
+						 */
+#define PLAYBACK_SPDIF_SELECT     0x70          /* Default: 12030F00 */
+						/* 0xffffffff -> 3FF30FFF */
+						/* 0x00000001 pauses stream/irq fail. */
+						/* All other bits do not effect playback */
+#define PLAYBACK_SPDIF_SRC_SELECT 0x71          /* Default: 0000E4E4 */
+						/* 0xffffffff -> F33FFFFF */
+						/* All bits do not effect playback */
+#define PLAYBACK_SPDIF_USER_DATA0 0x72		/* SPDIF out user data 0 */
+#define PLAYBACK_SPDIF_USER_DATA1 0x73		/* SPDIF out user data 1 */
+/* 0x74-0x75 unknown */
+#define CAPTURE_SPDIF_CONTROL	0x76		/* SPDIF in control setting */
+#define CAPTURE_SPDIF_STATUS	0x77		/* SPDIF in status */
+#define CAPURE_SPDIF_USER_DATA0 0x78		/* SPDIF in user data 0 */
+#define CAPURE_SPDIF_USER_DATA1 0x79		/* SPDIF in user data 1 */
+#define CAPURE_SPDIF_USER_DATA2 0x7a		/* SPDIF in user data 2 */
+
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c
--- a/sound/pci/emu10k1/timer.c
+++ b/sound/pci/emu10k1/timer.c
@@ -1,10 +1,8 @@
 /*
  *  Copyright (c) by Lee Revell <rlrevell@joe-job.com>
- *  
+ *                   Clemens Ladisch <clemens@ladisch.de>
  *  Routines for control of EMU10K1 chips
  *
- *  Copied from similar code by Clemens Ladisch in the ymfpci driver
- * 
  *  BUGS:
  *    --
  *
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -1,8 +1,11 @@
 /*
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *                   Creative Labs, Inc.
+ *                   Lee Revell <rlrevell@joe-job.com>
  *  Routines for control of EMU10K1 chips - voice manager
  *
+ *  Rewrote voice allocator for multichannel support - rlrevell 12/2004
+ * 
  *  BUGS:
  *    --
  *
@@ -30,25 +33,62 @@
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
-static int voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int pair, emu10k1_voice_t **rvoice)
+/* Previously the voice allocator started at 0 every time.  The new voice 
+ * allocator uses a round robin scheme.  The next free voice is tracked in 
+ * the card record and each allocation begins where the last left off.  The 
+ * hardware requires stereo interleaved voices be aligned to an even/odd 
+ * boundary.  For multichannel voice allocation we ensure than the block of 
+ * voices does not cross the 32 voice boundary.  This simplifies the 
+ * multichannel support and ensures we can use a single write to the 
+ * (set|clear)_loop_stop registers.  Otherwise (for example) the voices would 
+ * get out of sync when pausing/resuming a stream.
+ *							--rlrevell
+ */
+
+static int voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int number, emu10k1_voice_t **rvoice)
 {
-	emu10k1_voice_t *voice, *voice2;
-	int idx;
+	emu10k1_voice_t *voice;
+	int i, j, k, first_voice, last_voice, skip;
 
 	*rvoice = NULL;
-	for (idx = 0; idx < 64; idx += pair ? 2 : 1) {
-		voice = &emu->voices[idx];
-		voice2 = pair ? &emu->voices[idx+1] : NULL;
-		if (voice->use || (voice2 && voice2->use))
+	first_voice = last_voice = 0;
+	for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
+		// printk("i %d j %d next free %d!\n", i, j, emu->next_free_voice);
+		i %= NUM_G;
+
+		/* stereo voices must be even/odd */
+		if ((number == 2) && (i % 2)) {
+			i++;
 			continue;
+		}
+			
+		skip = 0;
+		for (k = 0; k < number; k++) {
+			voice = &emu->voices[(i+k) % NUM_G];
+			if (voice->use) {
+				skip = 1;
+				break;
+			}
+		}
+		if (!skip) {
+			// printk("allocated voice %d\n", i);
+			first_voice = i;
+			last_voice = (i + number) % NUM_G;
+			emu->next_free_voice = last_voice;
+			break;
+		}
+	}
+	
+	if (first_voice == last_voice)
+		return -ENOMEM;
+	
+	for (i=0; i < number; i++) {
+		voice = &emu->voices[(first_voice + i) % NUM_G];
+		// printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
 		voice->use = 1;
-		if (voice2)
-			voice2->use = 1;
 		switch (type) {
 		case EMU10K1_PCM:
 			voice->pcm = 1;
-			if (voice2)
-				voice2->pcm = 1;
 			break;
 		case EMU10K1_SYNTH:
 			voice->synth = 1;
@@ -56,26 +96,27 @@ static int voice_alloc(emu10k1_t *emu, e
 		case EMU10K1_MIDI:
 			voice->midi = 1;
 			break;
+		case EMU10K1_EFX:
+			voice->efx = 1;
+			break;
 		}
-		// printk("voice alloc - %i, pair = %i\n", voice->number, pair);
-		*rvoice = voice;
-		return 0;
 	}
-	return -ENOMEM;
+	*rvoice = &emu->voices[first_voice];
+	return 0;
 }
 
-int snd_emu10k1_voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int pair, emu10k1_voice_t **rvoice)
+int snd_emu10k1_voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int number, emu10k1_voice_t **rvoice)
 {
 	unsigned long flags;
 	int result;
 
 	snd_assert(rvoice != NULL, return -EINVAL);
-	snd_assert(!pair || type == EMU10K1_PCM, return -EINVAL);
+	snd_assert(number, return -EINVAL);
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (;;) {
-		result = voice_alloc(emu, type, pair, rvoice);
-		if (result == 0 || type != EMU10K1_PCM)
+		result = voice_alloc(emu, type, number, rvoice);
+		if (result == 0 || type == EMU10K1_SYNTH || type == EMU10K1_MIDI)
 			break;
 
 		/* free a voice from synth */
@@ -84,7 +125,7 @@ int snd_emu10k1_voice_alloc(emu10k1_t *e
 			if (result >= 0) {
 				emu10k1_voice_t *pvoice = &emu->voices[result];
 				pvoice->interrupt = NULL;
-				pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
+				pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
 				pvoice->epcm = NULL;
 			}
 		}
@@ -103,7 +144,7 @@ int snd_emu10k1_voice_free(emu10k1_t *em
 	snd_assert(pvoice != NULL, return -EINVAL);
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	pvoice->interrupt = NULL;
-	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
+	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
 	pvoice->epcm = NULL;
 	snd_emu10k1_voice_init(emu, pvoice->number);
 	spin_unlock_irqrestore(&emu->voice_lock, flags);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -430,7 +430,7 @@ struct _snd_ensoniq {
 #endif
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
+	struct gameport *gameport;
 #endif
 };
 
@@ -1734,43 +1734,99 @@ static int __devinit snd_ensoniq_1370_mi
 #endif /* CHIP1370 */
 
 #ifdef SUPPORT_JOYSTICK
-static int snd_ensoniq_joystick(ensoniq_t *ensoniq, long port)
-{
+
 #ifdef CHIP1371
-	if (port == 1) { /* auto-detect */
-		for (port = 0x200; port <= 0x218; port += 8)
-			if (request_region(port, 8, "ens137x: gameport"))
+static int __devinit snd_ensoniq_get_joystick_port(int dev)
+{
+	switch (joystick_port[dev]) {
+	case 0: /* disabled */
+	case 1: /* auto-detect */
+	case 0x200:
+	case 0x208:
+	case 0x210:
+	case 0x218:
+		return joystick_port[dev];
+
+	default:
+		printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]);
+		return 0;
+	}
+}
+#else
+static inline int snd_ensoniq_get_joystick_port(int dev)
+{
+	return joystick[dev] ? 0x200 : 0;
+}
+#endif
+
+static int __devinit snd_ensoniq_create_gameport(ensoniq_t *ensoniq, int dev)
+{
+	struct gameport *gp;
+	int io_port;
+
+	io_port = snd_ensoniq_get_joystick_port(dev);
+
+	switch (io_port) {
+	case 0:
+		return -ENOSYS;
+
+	case 1: /* auto_detect */
+		for (io_port = 0x200; io_port <= 0x218; io_port += 8)
+			if (request_region(io_port, 8, "ens137x: gameport"))
 				break;
-		if (port > 0x218) {
-			snd_printk("no gameport available\n");
+		if (io_port > 0x218) {
+			printk(KERN_WARNING "ens137x: no gameport ports available\n");
 			return -EBUSY;
 		}
-	} else
-#endif
-	{
-		if (!request_region(port, 8, "ens137x: gameport")) {
-			snd_printk("gameport io port 0x%03x in use", ensoniq->gameport.io);
+		break;
+
+	default:
+		if (!request_region(io_port, 8, "ens137x: gameport")) {
+			printk(KERN_WARNING "ens137x: gameport io port 0x%#x in use\n", io_port);
 			return -EBUSY;
 		}
+		break;
 	}
-	ensoniq->gameport.io = port;
+
+	ensoniq->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n");
+		release_region(io_port, 8);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ES137x");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(ensoniq->pci));
+	gameport_set_dev_parent(gp, &ensoniq->pci->dev);
+	gp->io = io_port;
+
 	ensoniq->ctrl |= ES_JYSTK_EN;
 #ifdef CHIP1371
 	ensoniq->ctrl &= ~ES_1371_JOY_ASELM;
-	ensoniq->ctrl |= ES_1371_JOY_ASEL((ensoniq->gameport.io - 0x200) / 8);
+	ensoniq->ctrl |= ES_1371_JOY_ASEL((io_port - 0x200) / 8);
 #endif
 	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
-	gameport_register_port(&ensoniq->gameport);
+
+	gameport_register_port(ensoniq->gameport);
+
 	return 0;
 }
 
-static void snd_ensoniq_joystick_free(ensoniq_t *ensoniq)
+static void snd_ensoniq_free_gameport(ensoniq_t *ensoniq)
 {
-	gameport_unregister_port(&ensoniq->gameport);
-	ensoniq->ctrl &= ~ES_JYSTK_EN;
-	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
-	release_region(ensoniq->gameport.io, 8);
+	if (ensoniq->gameport) {
+		int port = ensoniq->gameport->io;
+
+		gameport_unregister_port(ensoniq->gameport);
+		ensoniq->gameport = NULL;
+		ensoniq->ctrl &= ~ES_JYSTK_EN;
+		outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+		release_region(port, 8);
+	}
 }
+#else
+static inline int snd_ensoniq_create_gameport(ensoniq_t *ensoniq, long port) { return -ENOSYS; }
+static inline void snd_ensoniq_free_gameport(ensoniq_t *ensoniq) { }
 #endif /* SUPPORT_JOYSTICK */
 
 /*
@@ -1810,10 +1866,7 @@ static void __devinit snd_ensoniq_proc_i
 
 static int snd_ensoniq_free(ensoniq_t *ensoniq)
 {
-#ifdef SUPPORT_JOYSTICK
-	if (ensoniq->ctrl & ES_JYSTK_EN)
-		snd_ensoniq_joystick_free(ensoniq);
-#endif
+	snd_ensoniq_free_gameport(ensoniq);
 	if (ensoniq->irq < 0)
 		goto __hw_end;
 #ifdef CHIP1370
@@ -2043,9 +2096,7 @@ static void snd_ensoniq_midi_interrupt(e
 		if ((status & mask) == 0)
 			break;
 		byte = inb(ES_REG(ensoniq, UART_DATA));
-		spin_unlock(&ensoniq->reg_lock);
 		snd_rawmidi_receive(ensoniq->midi_input, &byte, 1);
-		spin_lock(&ensoniq->reg_lock);
 	}
 	spin_unlock(&ensoniq->reg_lock);
 
@@ -2313,22 +2364,9 @@ static int __devinit snd_audiopci_probe(
 		snd_card_free(card);
 		return err;
 	}
-#ifdef SUPPORT_JOYSTICK
-#ifdef CHIP1371
-	switch (joystick_port[dev]) {
-	case 1: /* auto-detect */
-	case 0x200:
-	case 0x208:
-	case 0x210:
-	case 0x218:
-		snd_ensoniq_joystick(ensoniq, joystick_port[dev]);
-		break;
-	}
-#else
-	if (joystick[dev])
-		snd_ensoniq_joystick(ensoniq, 0x200);
-#endif
-#endif /* SUPPORT_JOYSTICK */
+
+	snd_ensoniq_create_gameport(ensoniq, dev);
+
 	strcpy(card->driver, DRIVER_NAME);
 
 	strcpy(card->shortname, "Ensoniq AudioPCI");
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -72,6 +72,10 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938},"
                 "{ESS,ES1969},"
 		"{TerraTec,128i PCI}}");
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 #ifndef PCI_VENDOR_ID_ESS
 #define PCI_VENDOR_ID_ESS		0x125d
 #endif
@@ -237,8 +241,8 @@ struct _snd_es1938 {
 	spinlock_t mixer_lock;
         snd_info_entry_t *proc_entry;
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 #ifdef CONFIG_PM
 	unsigned char saved_regs[SAVED_REG_SIZE];
@@ -1381,7 +1385,7 @@ static unsigned char saved_regs[SAVED_RE
 };
 
 
-static int es1938_suspend(snd_card_t *card, unsigned int state)
+static int es1938_suspend(snd_card_t *card, pm_message_t state)
 {
 	es1938_t *chip = card->pm_private_data;
 	unsigned char *s, *d;
@@ -1398,7 +1402,7 @@ static int es1938_suspend(snd_card_t *ca
 	return 0;
 }
 
-static int es1938_resume(snd_card_t *card, unsigned int state)
+static int es1938_resume(snd_card_t *card)
 {
 	es1938_t *chip = card->pm_private_data;
 	unsigned char *s, *d;
@@ -1418,6 +1422,39 @@ static int es1938_resume(snd_card_t *car
 }
 #endif /* CONFIG_PM */
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_es1938_create_gameport(es1938_t *chip)
+{
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "es1938: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ES1938");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->io = chip->game_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void snd_es1938_free_gameport(es1938_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
+#else
+static inline int snd_es1938_create_gameport(es1938_t *chip) { return -ENOSYS; }
+static inline void snd_es1938_free_gameport(es1938_t *chip) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int snd_es1938_free(es1938_t *chip)
 {
 	/* disable irqs */
@@ -1425,10 +1462,8 @@ static int snd_es1938_free(es1938_t *chi
 	if (chip->rmidi)
 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport.io)
-		gameport_unregister_port(&chip->gameport);
-#endif
+	snd_es1938_free_gameport(chip);
+
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	pci_release_regions(chip->pci);
@@ -1698,10 +1733,7 @@ static int __devinit snd_es1938_probe(st
 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);
 	}
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	chip->gameport.io = chip->game_port;
-	gameport_register_port(&chip->gameport);
-#endif
+	snd_es1938_create_gameport(chip);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -586,6 +586,7 @@ struct snd_es1968 {
 	spinlock_t reg_lock;
 	spinlock_t ac97_lock;
 	struct tasklet_struct hwvol_tq;
+	unsigned int in_suspend;
 
 	/* Maestro Stuff */
 	u16 maestro_map[32];
@@ -605,8 +606,7 @@ struct snd_es1968 {
 #endif
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 };
 
@@ -1938,6 +1938,9 @@ static void es1968_update_hw_volume(unsi
 	outb(0x88, chip->io_port + 0x1e);
 	outb(0x88, chip->io_port + 0x1f);
 
+	if (chip->in_suspend)
+		return;
+
 	if (! chip->master_switch || ! chip->master_volume)
 		return;
 
@@ -2404,13 +2407,14 @@ static void snd_es1968_start_irq(es1968_
 /*
  * PM support
  */
-static int es1968_suspend(snd_card_t *card, unsigned int state)
+static int es1968_suspend(snd_card_t *card, pm_message_t state)
 {
 	es1968_t *chip = card->pm_private_data;
 
 	if (! chip->do_pm)
 		return 0;
 
+	chip->in_suspend = 1;
 	snd_pcm_suspend_all(chip->pcm);
 	snd_ac97_suspend(chip->ac97);
 	snd_es1968_bob_stop(chip);
@@ -2419,9 +2423,10 @@ static int es1968_suspend(snd_card_t *ca
 	return 0;
 }
 
-static int es1968_resume(snd_card_t *card, unsigned int state)
+static int es1968_resume(snd_card_t *card)
 {
 	es1968_t *chip = card->pm_private_data;
+	struct list_head *p;
 
 	if (! chip->do_pm)
 		return 0;
@@ -2442,14 +2447,81 @@ static int es1968_resume(snd_card_t *car
 	/* restore ac97 state */
 	snd_ac97_resume(chip->ac97);
 
+	list_for_each(p, &chip->substream_list) {
+		esschan_t *es = list_entry(p, esschan_t, list);
+		switch (es->mode) {
+		case ESM_MODE_PLAY:
+			snd_es1968_playback_setup(chip, es, es->substream->runtime);
+			break;
+		case ESM_MODE_CAPTURE:
+			snd_es1968_capture_setup(chip, es, es->substream->runtime);
+			break;
+		}
+	}
+
 	/* start timer again */
 	if (chip->bobclient)
 		snd_es1968_bob_start(chip);
 
+	chip->in_suspend = 0;
 	return 0;
 }
 #endif /* CONFIG_PM */
 
+#ifdef SUPPORT_JOYSTICK
+#define JOYSTICK_ADDR	0x200
+static int __devinit snd_es1968_create_gameport(es1968_t *chip, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+	u16 val;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	r = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport");
+	if (!r)
+		return -EBUSY;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "es1968: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &val);
+	pci_write_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04);
+
+	gameport_set_name(gp, "ES1968 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->io = JOYSTICK_ADDR;
+	gameport_set_port_data(gp, r);
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void snd_es1968_free_gameport(es1968_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = gameport_get_port_data(chip->gameport);
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_es1968_create_gameport(es1968_t *chip, int dev) { return -ENOSYS; }
+static inline void snd_es1968_free_gameport(es1968_t *chip) { }
+#endif
+
 static int snd_es1968_free(es1968_t *chip)
 {
 	if (chip->io_port) {
@@ -2460,13 +2532,7 @@ static int snd_es1968_free(es1968_t *chi
 
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick) {
-		gameport_unregister_port(&chip->gameport);
-		release_resource(chip->res_joystick);
-		kfree_nocheck(chip->res_joystick);
-	}
-#endif
+	snd_es1968_free_gameport(chip);
 	snd_es1968_set_acpi(chip, ACPI_D3);
 	chip->master_switch = NULL;
 	chip->master_volume = NULL;
@@ -2693,17 +2759,7 @@ static int __devinit snd_es1968_probe(st
 		}
 	}
 
-#ifdef SUPPORT_JOYSTICK
-#define JOYSTICK_ADDR	0x200
-	if (joystick[dev] &&
-	    (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport")) != NULL) {
-		u16 val;
-		pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &val);
-		pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04);
-		chip->gameport.io = JOYSTICK_ADDR;
-		gameport_register_port(&chip->gameport);
-	}
-#endif
+	snd_es1968_create_gameport(chip, dev);
 
 	snd_es1968_start_irq(chip);
 
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -64,7 +64,7 @@ module_param_array(id, charp, NULL, 0444
 MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
-module_param_array(tea575x_tuner, bool, NULL, 0444);
+module_param_array(tea575x_tuner, int, NULL, 0444);
 MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner.");
 
 /*
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/Makefile
@@ -0,0 +1,7 @@
+snd-hda-intel-objs := hda_intel.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o
+ifdef CONFIG_PROC_FS
+snd-hda-codec-objs += hda_proc.o
+endif
+
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o snd-hda-codec.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_codec.c
@@ -0,0 +1,1856 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include "hda_local.h"
+
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("Universal interface for High Definition Audio Codec");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * vendor / preset table
+ */
+
+struct hda_vendor_id {
+	unsigned int id;
+	const char *name;
+};
+
+/* codec vendor labels */
+static struct hda_vendor_id hda_vendor_ids[] = {
+	{ 0x10ec, "Realtek" },
+	{ 0x13f6, "C-Media" },
+	{ 0x434d, "C-Media" },
+	{} /* terminator */
+};
+
+/* codec presets */
+#include "hda_patch.h"
+
+
+/**
+ * snd_hda_codec_read - send a command and get the response
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command and read the corresponding response.
+ *
+ * Returns the obtained response value, or -1 for an error.
+ */
+unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct,
+				unsigned int verb, unsigned int parm)
+{
+	unsigned int res;
+	down(&codec->bus->cmd_mutex);
+	if (! codec->bus->ops.command(codec, nid, direct, verb, parm))
+		res = codec->bus->ops.get_response(codec);
+	else
+		res = (unsigned int)-1;
+	up(&codec->bus->cmd_mutex);
+	return res;
+}
+
+/**
+ * snd_hda_codec_write - send a single command without waiting for response
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command without waiting for response.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+			 unsigned int verb, unsigned int parm)
+{
+	int err;
+	down(&codec->bus->cmd_mutex);
+	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
+	up(&codec->bus->cmd_mutex);
+	return err;
+}
+
+/**
+ * snd_hda_sequence_write - sequence writes
+ * @codec: the HDA codec
+ * @seq: VERB array to send
+ *
+ * Send the commands sequentially from the given array.
+ * The array must be terminated with NID=0.
+ */
+void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
+{
+	for (; seq->nid; seq++)
+		snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
+}
+
+/**
+ * snd_hda_get_sub_nodes - get the range of sub nodes
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @start_id: the pointer to store the start NID
+ *
+ * Parse the NID and store the start NID of its sub-nodes.
+ * Returns the number of sub-nodes.
+ */
+int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id)
+{
+	unsigned int parm;
+
+	parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
+	*start_id = (parm >> 16) & 0x7fff;
+	return (int)(parm & 0x7fff);
+}
+
+/**
+ * snd_hda_get_connections - get connection list
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+			    hda_nid_t *conn_list, int max_conns)
+{
+	unsigned int parm;
+	int i, j, conn_len, num_tupples, conns;
+	unsigned int shift, num_elems, mask;
+
+	snd_assert(conn_list && max_conns > 0, return -EINVAL);
+
+	parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
+	if (parm & AC_CLIST_LONG) {
+		/* long form */
+		shift = 16;
+		num_elems = 2;
+	} else {
+		/* short form */
+		shift = 8;
+		num_elems = 4;
+	}
+	conn_len = parm & AC_CLIST_LENGTH;
+	num_tupples = num_elems / 2;
+	mask = (1 << (shift-1)) - 1;
+
+	if (! conn_len)
+		return 0; /* no connection */
+
+	if (conn_len == 1) {
+		/* single connection */
+		parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0);
+		conn_list[0] = parm & mask;
+		return 1;
+	}
+
+	/* multi connection */
+	conns = 0;
+	for (i = 0; i < conn_len; i += num_elems) {
+		parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i);
+		for (j = 0; j < num_tupples; j++) {
+			int range_val;
+			hda_nid_t val1, val2, n;
+			range_val = parm & (1 << (shift-1)); /* ranges */
+			val1 = parm & mask;
+			parm >>= shift;
+			val2 = parm & mask;
+			parm >>= shift;
+			if (range_val) {
+				/* ranges between val1 and val2 */
+				if (val1 > val2) {
+					snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", val1, val2);
+					continue;
+				}
+				for (n = val1; n <= val2; n++) {
+					if (conns >= max_conns)
+						return -EINVAL;
+					conn_list[conns++] = n;
+				}
+			} else {
+				if (! val1)
+					break;
+				if (conns >= max_conns)
+					return -EINVAL;
+				conn_list[conns++] = val1;
+				if (! val2)
+					break;
+				if (conns >= max_conns)
+					return -EINVAL;
+				conn_list[conns++] = val2;
+			}
+		}
+	}
+	return conns;
+}
+
+
+/**
+ * snd_hda_queue_unsol_event - add an unsolicited event to queue
+ * @bus: the BUS
+ * @res: unsolicited event (lower 32bit of RIRB entry)
+ * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
+ *
+ * Adds the given event to the queue.  The events are processed in
+ * the workqueue asynchronously.  Call this function in the interrupt
+ * hanlder when RIRB receives an unsolicited event.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
+{
+	struct hda_bus_unsolicited *unsol;
+	unsigned int wp;
+
+	if ((unsol = bus->unsol) == NULL)
+		return 0;
+
+	wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE;
+	unsol->wp = wp;
+
+	wp <<= 1;
+	unsol->queue[wp] = res;
+	unsol->queue[wp + 1] = res_ex;
+
+	queue_work(unsol->workq, &unsol->work);
+
+	return 0;
+}
+
+/*
+ * process queueud unsolicited events
+ */
+static void process_unsol_events(void *data)
+{
+	struct hda_bus *bus = data;
+	struct hda_bus_unsolicited *unsol = bus->unsol;
+	struct hda_codec *codec;
+	unsigned int rp, caddr, res;
+
+	while (unsol->rp != unsol->wp) {
+		rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE;
+		unsol->rp = rp;
+		rp <<= 1;
+		res = unsol->queue[rp];
+		caddr = unsol->queue[rp + 1];
+		if (! (caddr & (1 << 4))) /* no unsolicited event? */
+			continue;
+		codec = bus->caddr_tbl[caddr & 0x0f];
+		if (codec && codec->patch_ops.unsol_event)
+			codec->patch_ops.unsol_event(codec, res);
+	}
+}
+
+/*
+ * initialize unsolicited queue
+ */
+static int init_unsol_queue(struct hda_bus *bus)
+{
+	struct hda_bus_unsolicited *unsol;
+
+	unsol = kcalloc(1, sizeof(*unsol), GFP_KERNEL);
+	if (! unsol) {
+		snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
+		return -ENOMEM;
+	}
+	unsol->workq = create_workqueue("hda_codec");
+	if (! unsol->workq) {
+		snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
+		kfree(unsol);
+		return -ENOMEM;
+	}
+	INIT_WORK(&unsol->work, process_unsol_events, bus);
+	bus->unsol = unsol;
+	return 0;
+}
+
+/*
+ * destructor
+ */
+static void snd_hda_codec_free(struct hda_codec *codec);
+
+static int snd_hda_bus_free(struct hda_bus *bus)
+{
+	struct list_head *p, *n;
+
+	if (! bus)
+		return 0;
+	if (bus->unsol) {
+		destroy_workqueue(bus->unsol->workq);
+		kfree(bus->unsol);
+	}
+	list_for_each_safe(p, n, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		snd_hda_codec_free(codec);
+	}
+	if (bus->ops.private_free)
+		bus->ops.private_free(bus);
+	kfree(bus);
+	return 0;
+}
+
+static int snd_hda_bus_dev_free(snd_device_t *device)
+{
+	struct hda_bus *bus = device->device_data;
+	return snd_hda_bus_free(bus);
+}
+
+/**
+ * snd_hda_bus_new - create a HDA bus
+ * @card: the card entry
+ * @temp: the template for hda_bus information
+ * @busp: the pointer to store the created bus instance
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp)
+{
+	struct hda_bus *bus;
+	int err;
+	static snd_device_ops_t dev_ops = {
+		.dev_free = snd_hda_bus_dev_free,
+	};
+
+	snd_assert(temp, return -EINVAL);
+	snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL);
+
+	if (busp)
+		*busp = NULL;
+
+	bus = kcalloc(1, sizeof(*bus), GFP_KERNEL);
+	if (bus == NULL) {
+		snd_printk(KERN_ERR "can't allocate struct hda_bus\n");
+		return -ENOMEM;
+	}
+
+	bus->card = card;
+	bus->private_data = temp->private_data;
+	bus->pci = temp->pci;
+	bus->modelname = temp->modelname;
+	bus->ops = temp->ops;
+
+	init_MUTEX(&bus->cmd_mutex);
+	INIT_LIST_HEAD(&bus->codec_list);
+
+	init_unsol_queue(bus);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) {
+		snd_hda_bus_free(bus);
+		return err;
+	}
+	if (busp)
+		*busp = bus;
+	return 0;
+}
+
+
+/*
+ * find a matching codec preset
+ */
+static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec)
+{
+	const struct hda_codec_preset **tbl, *preset;
+
+	for (tbl = hda_preset_tables; *tbl; tbl++) {
+		for (preset = *tbl; preset->id; preset++) {
+			u32 mask = preset->mask;
+			if (! mask)
+				mask = ~0;
+			if (preset->id == (codec->vendor_id & mask))
+				return preset;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * snd_hda_get_codec_name - store the codec name
+ */
+void snd_hda_get_codec_name(struct hda_codec *codec,
+			    char *name, int namelen)
+{
+	const struct hda_vendor_id *c;
+	const char *vendor = NULL;
+	u16 vendor_id = codec->vendor_id >> 16;
+	char tmp[16];
+
+	for (c = hda_vendor_ids; c->id; c++) {
+		if (c->id == vendor_id) {
+			vendor = c->name;
+			break;
+		}
+	}
+	if (! vendor) {
+		sprintf(tmp, "Generic %04x", vendor_id);
+		vendor = tmp;
+	}
+	if (codec->preset && codec->preset->name)
+		snprintf(name, namelen, "%s %s", vendor, codec->preset->name);
+	else
+		snprintf(name, namelen, "%s ID %x", vendor, codec->vendor_id & 0xffff);
+}
+
+/*
+ * look for an AFG node
+ *
+ * return 0 if not found
+ */
+static int look_for_afg_node(struct hda_codec *codec)
+{
+	int i, total_nodes;
+	hda_nid_t nid;
+
+	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
+	for (i = 0; i < total_nodes; i++, nid++) {
+		if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) ==
+		    AC_GRP_AUDIO_FUNCTION)
+			return nid;
+	}
+	return 0;
+}
+
+/*
+ * codec destructor
+ */
+static void snd_hda_codec_free(struct hda_codec *codec)
+{
+	if (! codec)
+		return;
+	list_del(&codec->list);
+	codec->bus->caddr_tbl[codec->addr] = NULL;
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+	kfree(codec);
+}
+
+static void init_amp_hash(struct hda_codec *codec);
+
+/**
+ * snd_hda_codec_new - create a HDA codec
+ * @bus: the bus to assign
+ * @codec_addr: the codec address
+ * @codecp: the pointer to store the generated codec
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp)
+{
+	struct hda_codec *codec;
+	char component[13];
+	int err;
+
+	snd_assert(bus, return -EINVAL);
+	snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL);
+
+	if (bus->caddr_tbl[codec_addr]) {
+		snd_printk(KERN_ERR "hda_codec: address 0x%x is already occupied\n", codec_addr);
+		return -EBUSY;
+	}
+
+	codec = kcalloc(1, sizeof(*codec), GFP_KERNEL);
+	if (codec == NULL) {
+		snd_printk(KERN_ERR "can't allocate struct hda_codec\n");
+		return -ENOMEM;
+	}
+
+	codec->bus = bus;
+	codec->addr = codec_addr;
+	init_MUTEX(&codec->spdif_mutex);
+	init_amp_hash(codec);
+
+	list_add_tail(&codec->list, &bus->codec_list);
+	bus->caddr_tbl[codec_addr] = codec;
+
+	codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID);
+	codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
+	codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
+
+	/* FIXME: support for multiple AFGs? */
+	codec->afg = look_for_afg_node(codec);
+	if (! codec->afg) {
+		snd_printk(KERN_ERR "hda_codec: no AFG node found\n");
+		snd_hda_codec_free(codec);
+		return -ENODEV;
+	}
+
+	codec->preset = find_codec_preset(codec);
+	if (! *bus->card->mixername)
+		snd_hda_get_codec_name(codec, bus->card->mixername,
+				       sizeof(bus->card->mixername));
+
+	if (codec->preset && codec->preset->patch)
+		err = codec->preset->patch(codec);
+	else
+		err = snd_hda_parse_generic_codec(codec);
+	if (err < 0) {
+		snd_hda_codec_free(codec);
+		return err;
+	}
+
+	snd_hda_codec_proc_new(codec);
+
+	sprintf(component, "HDA:%08x", codec->vendor_id);
+	snd_component_add(codec->bus->card, component);
+
+	if (codecp)
+		*codecp = codec;
+	return 0;
+}
+
+/**
+ * snd_hda_codec_setup_stream - set up the codec for streaming
+ * @codec: the CODEC to set up
+ * @nid: the NID to set up
+ * @stream_tag: stream tag to pass, it's between 0x1 and 0xf.
+ * @channel_id: channel id to pass, zero based.
+ * @format: stream format.
+ */
+void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag,
+				int channel_id, int format)
+{
+	snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
+		    nid, stream_tag, channel_id, format);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID,
+			    (stream_tag << 4) | channel_id);
+	msleep(1);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
+}
+
+
+/*
+ * amp access functions
+ */
+
+#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64)
+#define INFO_AMP_CAPS	(1<<0)
+#define INFO_AMP_VOL	(1<<1)
+
+/* initialize the hash table */
+static void init_amp_hash(struct hda_codec *codec)
+{
+	memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash));
+	codec->num_amp_entries = 0;
+}
+
+/* query the hash.  allocate an entry if not found. */
+static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key)
+{
+	u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash);
+	u16 cur = codec->amp_hash[idx];
+	struct hda_amp_info *info;
+
+	while (cur != 0xffff) {
+		info = &codec->amp_info[cur];
+		if (info->key == key)
+			return info;
+		cur = info->next;
+	}
+
+	/* add a new hash entry */
+	if (codec->num_amp_entries >= ARRAY_SIZE(codec->amp_info)) {
+		snd_printk(KERN_ERR "hda_codec: Tooooo many amps!\n");
+		return NULL;
+	}
+	cur = codec->num_amp_entries++;
+	info = &codec->amp_info[cur];
+	info->key = key;
+	info->status = 0; /* not initialized yet */
+	info->next = codec->amp_hash[idx];
+	codec->amp_hash[idx] = cur;
+
+	return info;
+}
+
+/*
+ * query AMP capabilities for the given widget and direction
+ */
+static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
+
+	if (! info)
+		return 0;
+	if (! (info->status & INFO_AMP_CAPS)) {
+		if (!(snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_AMP_OVRD))
+			nid = codec->afg;
+		info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ?
+						    AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+		info->status |= INFO_AMP_CAPS;
+	}
+	return info->amp_caps;
+}
+
+/*
+ * read the current volume to info
+ * if the cache exists, read from the cache.
+ */
+static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
+			 hda_nid_t nid, int ch, int direction, int index)
+{
+	u32 val, parm;
+
+	if (info->status & (INFO_AMP_VOL << ch))
+		return;
+
+	parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
+	parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+	parm |= index;
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm);
+	info->vol[ch] = val & 0xff;
+	info->status |= INFO_AMP_VOL << ch;
+}
+
+/*
+ * write the current volume in info to the h/w
+ */
+static void put_vol_mute(struct hda_codec *codec,
+			 hda_nid_t nid, int ch, int direction, int index, int val)
+{
+	u32 parm;
+
+	parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
+	parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
+	parm |= index << AC_AMP_SET_INDEX_SHIFT;
+	parm |= val;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
+}
+
+/*
+ * read/write AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
+ */
+int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
+	if (! info)
+		return 0;
+	get_vol_mute(codec, info, nid, ch, direction, index);
+	return info->vol[ch];
+}
+
+int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
+	if (! info)
+		return 0;
+	get_vol_mute(codec, info, nid, ch, direction, idx);
+	if (info->vol[ch] == val && ! codec->in_resume)
+		return 0;
+	put_vol_mute(codec, nid, ch, direction, idx, val);
+	info->vol[ch] = val;
+	return 1;
+}
+
+
+/*
+ * AMP control callbacks
+ */
+/* retrieve parameters from private_value */
+#define get_amp_nid(kc)		((kc)->private_value & 0xffff)
+#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
+#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
+#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
+
+/* volume */
+int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 nid = get_amp_nid(kcontrol);
+	u8 chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	u32 caps;
+
+	caps = query_amp_caps(codec, nid, dir);
+	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; /* num steps */
+	if (! caps) {
+		printk(KERN_WARNING "hda_codec: num_steps = 0 for NID=0x%x\n", nid);
+		return -EINVAL;
+	}
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = chs == 3 ? 2 : 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = caps;
+	return 0;
+}
+
+int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+
+	if (chs & 1)
+		*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f;
+	if (chs & 2)
+		*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
+	return 0;
+}
+
+int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	int val;
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	if (chs & 1) {
+		val = *valp & 0x7f;
+		val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
+		valp++;
+	}
+	if (chs & 2) {
+		val = *valp & 0x7f;
+		val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80;
+		change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
+	}
+	return change;
+}
+
+/* switch */
+int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	int chs = get_amp_channels(kcontrol);
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = chs == 3 ? 2 : 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+
+	if (chs & 1)
+		*valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80) ? 0 : 1;
+	if (chs & 2)
+		*valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80) ? 0 : 1;
+	return 0;
+}
+
+int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	int val;
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	if (chs & 1) {
+		val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f;
+		val |= *valp ? 0 : 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
+		valp++;
+	}
+	if (chs & 2) {
+		val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
+		val |= *valp ? 0 : 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
+	}
+	return change;
+}
+
+/*
+ * SPDIF out controls
+ */
+
+static int snd_hda_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_hda_spdif_cmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
+					   IEC958_AES0_NONAUDIO |
+					   IEC958_AES0_CON_EMPHASIS_5015 |
+					   IEC958_AES0_CON_NOT_COPYRIGHT;
+	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY |
+					   IEC958_AES1_CON_ORIGINAL;
+	return 0;
+}
+
+static int snd_hda_spdif_pmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
+					   IEC958_AES0_NONAUDIO |
+					   IEC958_AES0_PRO_EMPHASIS_5015;
+	return 0;
+}
+
+static int snd_hda_spdif_default_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;
+	ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;
+
+	return 0;
+}
+
+/* convert from SPDIF status bits to HDA SPDIF bits
+ * bit 0 (DigEn) is always set zero (to be filled later)
+ */
+static unsigned short convert_from_spdif_status(unsigned int sbits)
+{
+	unsigned short val = 0;
+
+	if (sbits & IEC958_AES0_PROFESSIONAL)
+		val |= 1 << 6;
+	if (sbits & IEC958_AES0_NONAUDIO)
+		val |= 1 << 5;
+	if (sbits & IEC958_AES0_PROFESSIONAL) {
+		if ((sbits & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015)
+			val |= 1 << 3;
+	} else {
+		if ((sbits & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015)
+			val |= 1 << 3;
+		if (! (sbits & IEC958_AES0_CON_NOT_COPYRIGHT))
+			val |= 1 << 4;
+		if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))
+			val |= 1 << 7;
+		val |= sbits & (IEC958_AES1_CON_CATEGORY << 8);
+	}
+	return val;
+}
+
+/* convert to SPDIF status bits from HDA SPDIF bits
+ */
+static unsigned int convert_to_spdif_status(unsigned short val)
+{
+	unsigned int sbits = 0;
+
+	if (val & (1 << 5))
+		sbits |= IEC958_AES0_NONAUDIO;
+	if (val & (1 << 6))
+		sbits |= IEC958_AES0_PROFESSIONAL;
+	if (sbits & IEC958_AES0_PROFESSIONAL) {
+		if (sbits & (1 << 3))
+			sbits |= IEC958_AES0_PRO_EMPHASIS_5015;
+	} else {
+		if (val & (1 << 3))
+			sbits |= IEC958_AES0_CON_EMPHASIS_5015;
+		if (! (val & (1 << 4)))
+			sbits |= IEC958_AES0_CON_NOT_COPYRIGHT;
+		if (val & (1 << 7))
+			sbits |= (IEC958_AES1_CON_ORIGINAL << 8);
+		sbits |= val & (0x7f << 8);
+	}
+	return sbits;
+}
+
+static int snd_hda_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned short val;
+	int change;
+
+	down(&codec->spdif_mutex);
+	codec->spdif_status = ucontrol->value.iec958.status[0] |
+		((unsigned int)ucontrol->value.iec958.status[1] << 8) |
+		((unsigned int)ucontrol->value.iec958.status[2] << 16) |
+		((unsigned int)ucontrol->value.iec958.status[3] << 24);
+	val = convert_from_spdif_status(codec->spdif_status);
+	val |= codec->spdif_ctls & 1;
+	change = codec->spdif_ctls != val;
+	codec->spdif_ctls = val;
+
+	if (change || codec->in_resume) {
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8);
+	}
+
+	up(&codec->spdif_mutex);
+	return change;
+}
+
+static int snd_hda_spdif_out_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hda_spdif_out_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = codec->spdif_ctls & 1;
+	return 0;
+}
+
+static int snd_hda_spdif_out_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned short val;
+	int change;
+
+	down(&codec->spdif_mutex);
+	val = codec->spdif_ctls & ~1;
+	if (ucontrol->value.integer.value[0])
+		val |= 1;
+	change = codec->spdif_ctls != val;
+	if (change || codec->in_resume) {
+		codec->spdif_ctls = val;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
+				    AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80));
+	}
+	up(&codec->spdif_mutex);
+	return change;
+}
+
+static snd_kcontrol_new_t dig_mixes[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_cmask_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_pmask_get,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_default_get,
+		.put = snd_hda_spdif_default_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
+		.info = snd_hda_spdif_out_switch_info,
+		.get = snd_hda_spdif_out_switch_get,
+		.put = snd_hda_spdif_out_switch_put,
+	},
+	{ } /* end */
+};
+
+/**
+ * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
+ * @codec: the HDA codec
+ * @nid: audio out widget NID
+ *
+ * Creates controls related with the SPDIF output.
+ * Called from each patch supporting the SPDIF out.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
+{
+	int err;
+	snd_kcontrol_t *kctl;
+	snd_kcontrol_new_t *dig_mix;
+
+	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+		kctl = snd_ctl_new1(dig_mix, codec);
+		kctl->private_value = nid;
+		if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)
+			return err;
+	}
+	codec->spdif_ctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+	codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
+	return 0;
+}
+
+/*
+ * SPDIF input
+ */
+
+#define snd_hda_spdif_in_switch_info	snd_hda_spdif_out_switch_info
+
+static int snd_hda_spdif_in_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = codec->spdif_in_enable;
+	return 0;
+}
+
+static int snd_hda_spdif_in_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned int val = !!ucontrol->value.integer.value[0];
+	int change;
+
+	down(&codec->spdif_mutex);
+	change = codec->spdif_in_enable != val;
+	if (change || codec->in_resume) {
+		codec->spdif_in_enable = val;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val);
+	}
+	up(&codec->spdif_mutex);
+	return change;
+}
+
+static int snd_hda_spdif_in_status_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned short val;
+	unsigned int sbits;
+
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+	sbits = convert_to_spdif_status(val);
+	ucontrol->value.iec958.status[0] = sbits;
+	ucontrol->value.iec958.status[1] = sbits >> 8;
+	ucontrol->value.iec958.status[2] = sbits >> 16;
+	ucontrol->value.iec958.status[3] = sbits >> 24;
+	return 0;
+}
+
+static snd_kcontrol_new_t dig_in_ctls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
+		.info = snd_hda_spdif_in_switch_info,
+		.get = snd_hda_spdif_in_switch_get,
+		.put = snd_hda_spdif_in_switch_put,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_in_status_get,
+	},
+	{ } /* end */
+};
+
+/**
+ * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls
+ * @codec: the HDA codec
+ * @nid: audio in widget NID
+ *
+ * Creates controls related with the SPDIF input.
+ * Called from each patch supporting the SPDIF in.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
+{
+	int err;
+	snd_kcontrol_t *kctl;
+	snd_kcontrol_new_t *dig_mix;
+
+	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
+		kctl = snd_ctl_new1(dig_mix, codec);
+		kctl->private_value = nid;
+		if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)
+			return err;
+	}
+	codec->spdif_in_enable = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & 1;
+	return 0;
+}
+
+
+/**
+ * snd_hda_build_controls - build mixer controls
+ * @bus: the BUS
+ *
+ * Creates mixer controls for each codec included in the bus.
+ *
+ * Returns 0 if successful, otherwise a negative error code.
+ */
+int snd_hda_build_controls(struct hda_bus *bus)
+{
+	struct list_head *p;
+
+	/* build controls */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		int err;
+		if (! codec->patch_ops.build_controls)
+			continue;
+		err = codec->patch_ops.build_controls(codec);
+		if (err < 0)
+			return err;
+	}
+
+	/* initialize */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		int err;
+		if (! codec->patch_ops.init)
+			continue;
+		err = codec->patch_ops.init(codec);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/*
+ * stream formats
+ */
+static unsigned int rate_bits[][3] = {
+	/* rate in Hz, ALSA rate bitmask, HDA format value */
+	{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
+	{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
+	{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
+	{ 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */
+	{ 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */
+	{ 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */
+	{ 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */
+	{ 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */
+	{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
+	{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
+	{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
+	{ 0 }
+};
+
+/**
+ * snd_hda_calc_stream_format - calculate format bitset
+ * @rate: the sample rate
+ * @channels: the number of channels
+ * @format: the PCM format (SNDRV_PCM_FORMAT_XXX)
+ * @maxbps: the max. bps
+ *
+ * Calculate the format bitset from the given rate, channels and th PCM format.
+ *
+ * Return zero if invalid.
+ */
+unsigned int snd_hda_calc_stream_format(unsigned int rate,
+					unsigned int channels,
+					unsigned int format,
+					unsigned int maxbps)
+{
+	int i;
+	unsigned int val = 0;
+
+	for (i = 0; rate_bits[i][0]; i++)
+		if (rate_bits[i][0] == rate) {
+			val = rate_bits[i][2];
+			break;
+		}
+	if (! rate_bits[i][0]) {
+		snd_printdd("invalid rate %d\n", rate);
+		return 0;
+	}
+
+	if (channels == 0 || channels > 8) {
+		snd_printdd("invalid channels %d\n", channels);
+		return 0;
+	}
+	val |= channels - 1;
+
+	switch (snd_pcm_format_width(format)) {
+	case 8:  val |= 0x00; break;
+	case 16: val |= 0x10; break;
+	case 20:
+	case 24:
+	case 32:
+		if (maxbps >= 32)
+			val |= 0x40;
+		else if (maxbps >= 24)
+			val |= 0x30;
+		else
+			val |= 0x20;
+		break;
+	default:
+		snd_printdd("invalid format width %d\n", snd_pcm_format_width(format));
+		return 0;
+	}
+
+	return val;
+}
+
+/**
+ * snd_hda_query_supported_pcm - query the supported PCM rates and formats
+ * @codec: the HDA codec
+ * @nid: NID to query
+ * @ratesp: the pointer to store the detected rate bitflags
+ * @formatsp: the pointer to store the detected formats
+ * @bpsp: the pointer to store the detected format widths
+ *
+ * Queries the supported PCM rates and formats.  The NULL @ratesp, @formatsp
+ * or @bsps argument is ignored.
+ *
+ * Returns 0 if successful, otherwise a negative error code.
+ */
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+				u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
+{
+	int i;
+	unsigned int val, streams;
+
+	val = 0;
+	if (nid != codec->afg &&
+	    snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+		if (val == -1)
+			return -EIO;
+	}
+	if (! val)
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+
+	if (ratesp) {
+		u32 rates = 0;
+		for (i = 0; rate_bits[i][0]; i++) {
+			if (val & (1 << i))
+				rates |= rate_bits[i][1];
+		}
+		*ratesp = rates;
+	}
+
+	if (formatsp || bpsp) {
+		u64 formats = 0;
+		unsigned int bps;
+		unsigned int wcaps;
+
+		wcaps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+		streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+		if (streams == -1)
+			return -EIO;
+		if (! streams) {
+			streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+			if (streams == -1)
+				return -EIO;
+		}
+
+		bps = 0;
+		if (streams & AC_SUPFMT_PCM) {
+			if (val & AC_SUPPCM_BITS_8) {
+				formats |= SNDRV_PCM_FMTBIT_U8;
+				bps = 8;
+			}
+			if (val & AC_SUPPCM_BITS_16) {
+				formats |= SNDRV_PCM_FMTBIT_S16_LE;
+				bps = 16;
+			}
+			if (wcaps & AC_WCAP_DIGITAL) {
+				if (val & AC_SUPPCM_BITS_32)
+					formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+				if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24))
+					formats |= SNDRV_PCM_FMTBIT_S32_LE;
+				if (val & AC_SUPPCM_BITS_24)
+					bps = 24;
+				else if (val & AC_SUPPCM_BITS_20)
+					bps = 20;
+			} else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|AC_SUPPCM_BITS_32)) {
+				formats |= SNDRV_PCM_FMTBIT_S32_LE;
+				if (val & AC_SUPPCM_BITS_32)
+					bps = 32;
+				else if (val & AC_SUPPCM_BITS_20)
+					bps = 20;
+				else if (val & AC_SUPPCM_BITS_24)
+					bps = 24;
+			}
+		}
+		else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */
+			formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
+			bps = 32;
+		} else if (streams == AC_SUPFMT_AC3) { /* should be exclusive */
+			/* temporary hack: we have still no proper support
+			 * for the direct AC3 stream...
+			 */
+			formats |= SNDRV_PCM_FMTBIT_U8;
+			bps = 8;
+		}
+		if (formatsp)
+			*formatsp = formats;
+		if (bpsp)
+			*bpsp = bps;
+	}
+
+	return 0;
+}
+
+/**
+ * snd_hda_is_supported_format - check whether the given node supports the format val
+ *
+ * Returns 1 if supported, 0 if not.
+ */
+int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
+				unsigned int format)
+{
+	int i;
+	unsigned int val = 0, rate, stream;
+
+	if (nid != codec->afg &&
+	    snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+		if (val == -1)
+			return 0;
+	}
+	if (! val) {
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+		if (val == -1)
+			return 0;
+	}
+
+	rate = format & 0xff00;
+	for (i = 0; rate_bits[i][0]; i++)
+		if (rate_bits[i][2] == rate) {
+			if (val & (1 << i))
+				break;
+			return 0;
+		}
+	if (! rate_bits[i][0])
+		return 0;
+
+	stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (stream == -1)
+		return 0;
+	if (! stream && nid != codec->afg)
+		stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+	if (! stream || stream == -1)
+		return 0;
+
+	if (stream & AC_SUPFMT_PCM) {
+		switch (format & 0xf0) {
+		case 0x00:
+			if (! (val & AC_SUPPCM_BITS_8))
+				return 0;
+			break;
+		case 0x10:
+			if (! (val & AC_SUPPCM_BITS_16))
+				return 0;
+			break;
+		case 0x20:
+			if (! (val & AC_SUPPCM_BITS_20))
+				return 0;
+			break;
+		case 0x30:
+			if (! (val & AC_SUPPCM_BITS_24))
+				return 0;
+			break;
+		case 0x40:
+			if (! (val & AC_SUPPCM_BITS_32))
+				return 0;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		/* FIXME: check for float32 and AC3? */
+	}
+
+	return 1;
+}
+
+/*
+ * PCM stuff
+ */
+static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	return 0;
+}
+
+static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   unsigned int stream_tag,
+				   unsigned int format,
+				   snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+	return 0;
+}
+
+static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0);
+	return 0;
+}
+
+static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info)
+{
+	if (info->nid) {
+		/* query support PCM information from the given NID */
+		if (! info->rates || ! info->formats)
+			snd_hda_query_supported_pcm(codec, info->nid,
+						    info->rates ? NULL : &info->rates,
+						    info->formats ? NULL : &info->formats,
+						    info->maxbps ? NULL : &info->maxbps);
+	}
+	if (info->ops.open == NULL)
+		info->ops.open = hda_pcm_default_open_close;
+	if (info->ops.close == NULL)
+		info->ops.close = hda_pcm_default_open_close;
+	if (info->ops.prepare == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.prepare = hda_pcm_default_prepare;
+	}
+	if (info->ops.prepare == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.prepare = hda_pcm_default_prepare;
+	}
+	if (info->ops.cleanup == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.cleanup = hda_pcm_default_cleanup;
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_build_pcms - build PCM information
+ * @bus: the BUS
+ *
+ * Create PCM information for each codec included in the bus.
+ *
+ * The build_pcms codec patch is requested to set up codec->num_pcms and
+ * codec->pcm_info properly.  The array is referred by the top-level driver
+ * to create its PCM instances.
+ * The allocated codec->pcm_info should be released in codec->patch_ops.free
+ * callback.
+ *
+ * At least, substreams, channels_min and channels_max must be filled for
+ * each stream.  substreams = 0 indicates that the stream doesn't exist.
+ * When rates and/or formats are zero, the supported values are queried
+ * from the given nid.  The nid is used also by the default ops.prepare
+ * and ops.cleanup callbacks.
+ *
+ * The driver needs to call ops.open in its open callback.  Similarly,
+ * ops.close is supposed to be called in the close callback.
+ * ops.prepare should be called in the prepare or hw_params callback
+ * with the proper parameters for set up.
+ * ops.cleanup should be called in hw_free for clean up of streams.
+ *
+ * This function returns 0 if successfull, or a negative error code.
+ */
+int snd_hda_build_pcms(struct hda_bus *bus)
+{
+	struct list_head *p;
+
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		unsigned int pcm, s;
+		int err;
+		if (! codec->patch_ops.build_pcms)
+			continue;
+		err = codec->patch_ops.build_pcms(codec);
+		if (err < 0)
+			return err;
+		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+			for (s = 0; s < 2; s++) {
+				struct hda_pcm_stream *info;
+				info = &codec->pcm_info[pcm].stream[s];
+				if (! info->substreams)
+					continue;
+				err = set_pcm_default_values(codec, info);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * snd_hda_check_board_config - compare the current codec with the config table
+ * @codec: the HDA codec
+ * @tbl: configuration table, terminated by null entries
+ *
+ * Compares the modelname or PCI subsystem id of the current codec with the
+ * given configuration table.  If a matching entry is found, returns its
+ * config value (supposed to be 0 or positive).
+ *
+ * If no entries are matching, the function returns a negative value.
+ */
+int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl)
+{
+	struct hda_board_config *c;
+
+	if (codec->bus->modelname) {
+		for (c = tbl; c->modelname || c->pci_vendor; c++) {
+			if (c->modelname &&
+			    ! strcmp(codec->bus->modelname, c->modelname)) {
+				snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
+				return c->config;
+			}
+		}
+	}
+
+	if (codec->bus->pci) {
+		u16 subsystem_vendor, subsystem_device;
+		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
+		for (c = tbl; c->modelname || c->pci_vendor; c++) {
+			if (c->pci_vendor == subsystem_vendor &&
+			    c->pci_device == subsystem_device)
+				return c->config;
+		}
+	}
+	return -1;
+}
+
+/**
+ * snd_hda_add_new_ctls - create controls from the array
+ * @codec: the HDA codec
+ * @knew: the array of snd_kcontrol_new_t
+ *
+ * This helper function creates and add new controls in the given array.
+ * The array must be terminated with an empty entry as terminator.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
+{
+	int err;
+
+	for (; knew->name; knew++) {
+		err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/*
+ * input MUX helper
+ */
+int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo)
+{
+	unsigned int index;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = imux->num_items;
+	index = uinfo->value.enumerated.item;
+	if (index >= imux->num_items)
+		index = imux->num_items - 1;
+	strcpy(uinfo->value.enumerated.name, imux->items[index].label);
+	return 0;
+}
+
+int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux,
+			  snd_ctl_elem_value_t *ucontrol, hda_nid_t nid,
+			  unsigned int *cur_val)
+{
+	unsigned int idx;
+
+	idx = ucontrol->value.enumerated.item[0];
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (*cur_val == idx && ! codec->in_resume)
+		return 0;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+			    imux->items[idx].index);
+	*cur_val = idx;
+	return 1;
+}
+
+
+/*
+ * Multi-channel / digital-out PCM helper functions
+ */
+
+/*
+ * open the digital out in the exclusive mode
+ */
+int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_used) {
+		up(&codec->spdif_mutex);
+		return -EBUSY; /* already being used */
+	}
+	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+/*
+ * release the digital out
+ */
+int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	down(&codec->spdif_mutex);
+	mout->dig_out_used = 0;
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+/*
+ * set up more restrictions for analog out
+ */
+int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
+				  snd_pcm_substream_t *substream)
+{
+	substream->runtime->hw.channels_max = mout->max_channels;
+	return snd_pcm_hw_constraint_step(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+}
+
+/*
+ * set up the i/o for analog out
+ * when the digital out is available, copy the front out to digital out, too.
+ */
+int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     snd_pcm_substream_t *substream)
+{
+	hda_nid_t *nids = mout->dac_nids;
+	int chs = substream->runtime->channels;
+	int i;
+
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+		if (chs == 2 &&
+		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
+		    ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+			/* setup digital receiver */
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   stream_tag, 0, format);
+		} else {
+			mout->dig_out_used = 0;
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		}
+	}
+	up(&codec->spdif_mutex);
+
+	/* front */
+	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
+	if (mout->hp_nid)
+		/* headphone out will just decode front left/right (stereo) */
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
+	/* surrounds */
+	for (i = 1; i < mout->num_dacs; i++) {
+		if (i == HDA_REAR && chs == 2) /* copy front to rear */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format);
+		else if (chs >= (i + 1) * 2) /* independent out */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,
+						   format);
+	}
+	return 0;
+}
+
+/*
+ * clean up the setting for analog out
+ */
+int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	hda_nid_t *nids = mout->dac_nids;
+	int i;
+
+	for (i = 0; i < mout->num_dacs; i++)
+		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+	if (mout->hp_nid)
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
+		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		mout->dig_out_used = 0;
+	}
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+
+/**
+ * snd_hda_suspend - suspend the codecs
+ * @bus: the HDA bus
+ * @state: suspsend state
+ *
+ * Returns 0 if successful.
+ */
+int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
+{
+	struct list_head *p;
+
+	/* FIXME: should handle power widget capabilities */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		if (codec->patch_ops.suspend)
+			codec->patch_ops.suspend(codec, state);
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_resume - resume the codecs
+ * @bus: the HDA bus
+ * @state: resume state
+ *
+ * Returns 0 if successful.
+ */
+int snd_hda_resume(struct hda_bus *bus)
+{
+	struct list_head *p;
+
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		if (codec->patch_ops.resume)
+			codec->patch_ops.resume(codec);
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_resume_ctls - resume controls in the new control list
+ * @codec: the HDA codec
+ * @knew: the array of snd_kcontrol_new_t
+ *
+ * This function resumes the mixer controls in the snd_kcontrol_new_t array,
+ * originally for snd_hda_add_new_ctls().
+ * The array must be terminated with an empty entry as terminator.
+ */
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
+{
+	snd_ctl_elem_value_t *val;
+
+	val = kmalloc(sizeof(*val), GFP_KERNEL);
+	if (! val)
+		return -ENOMEM;
+	codec->in_resume = 1;
+	for (; knew->name; knew++) {
+		int i, count;
+		count = knew->count ? knew->count : 1;
+		for (i = 0; i < count; i++) {
+			memset(val, 0, sizeof(*val));
+			val->id.iface = knew->iface;
+			val->id.device = knew->device;
+			val->id.subdevice = knew->subdevice;
+			strcpy(val->id.name, knew->name);
+			val->id.index = knew->index ? knew->index : i;
+			/* Assume that get callback reads only from cache,
+			 * not accessing to the real hardware
+			 */
+			if (snd_ctl_elem_read(codec->bus->card, val) < 0)
+				continue;
+			snd_ctl_elem_write(codec->bus->card, NULL, val);
+		}
+	}
+	codec->in_resume = 0;
+	kfree(val);
+	return 0;
+}
+
+/**
+ * snd_hda_resume_spdif_out - resume the digital out
+ * @codec: the HDA codec
+ */
+int snd_hda_resume_spdif_out(struct hda_codec *codec)
+{
+	return snd_hda_resume_ctls(codec, dig_mixes);
+}
+
+/**
+ * snd_hda_resume_spdif_in - resume the digital in
+ * @codec: the HDA codec
+ */
+int snd_hda_resume_spdif_in(struct hda_codec *codec)
+{
+	return snd_hda_resume_ctls(codec, dig_in_ctls);
+}
+#endif
+
+/*
+ * symbols exported for controller modules
+ */
+EXPORT_SYMBOL(snd_hda_codec_read);
+EXPORT_SYMBOL(snd_hda_codec_write);
+EXPORT_SYMBOL(snd_hda_sequence_write);
+EXPORT_SYMBOL(snd_hda_get_sub_nodes);
+EXPORT_SYMBOL(snd_hda_queue_unsol_event);
+EXPORT_SYMBOL(snd_hda_bus_new);
+EXPORT_SYMBOL(snd_hda_codec_new);
+EXPORT_SYMBOL(snd_hda_codec_setup_stream);
+EXPORT_SYMBOL(snd_hda_calc_stream_format);
+EXPORT_SYMBOL(snd_hda_build_pcms);
+EXPORT_SYMBOL(snd_hda_build_controls);
+#ifdef CONFIG_PM
+EXPORT_SYMBOL(snd_hda_suspend);
+EXPORT_SYMBOL(snd_hda_resume);
+#endif
+
+/*
+ *  INIT part
+ */
+
+static int __init alsa_hda_init(void)
+{
+	return 0;
+}
+
+static void __exit alsa_hda_exit(void)
+{
+}
+
+module_init(alsa_hda_init)
+module_exit(alsa_hda_exit)
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_codec.h
@@ -0,0 +1,604 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.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.
+ *
+ *  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 __SOUND_HDA_CODEC_H
+#define __SOUND_HDA_CODEC_H
+
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+
+/*
+ * nodes
+ */
+#define	AC_NODE_ROOT		0x00
+
+/*
+ * function group types
+ */
+enum {
+	AC_GRP_AUDIO_FUNCTION = 0x01,
+	AC_GRP_MODEM_FUNCTION = 0x02,
+};
+	
+/*
+ * widget types
+ */
+enum {
+	AC_WID_AUD_OUT,		/* Audio Out */
+	AC_WID_AUD_IN,		/* Audio In */
+	AC_WID_AUD_MIX,		/* Audio Mixer */
+	AC_WID_AUD_SEL,		/* Audio Selector */
+	AC_WID_PIN,		/* Pin Complex */
+	AC_WID_POWER,		/* Power */
+	AC_WID_VOL_KNB,		/* Volume Knob */
+	AC_WID_BEEP,		/* Beep Generator */
+	AC_WID_VENDOR = 0x0f	/* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT		0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE		0x0b00
+#define AC_VERB_GET_PROC_COEF			0x0c00
+#define AC_VERB_GET_COEF_INDEX			0x0d00
+#define AC_VERB_PARAMETERS			0x0f00
+#define AC_VERB_GET_CONNECT_SEL			0x0f01
+#define AC_VERB_GET_CONNECT_LIST		0x0f02
+#define AC_VERB_GET_PROC_STATE			0x0f03
+#define AC_VERB_GET_SDI_SELECT			0x0f04
+#define AC_VERB_GET_POWER_STATE			0x0f05
+#define AC_VERB_GET_CONV			0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL		0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE	0x0f08
+#define AC_VERB_GET_PIN_SENSE			0x0f09
+#define AC_VERB_GET_BEEP_CONTROL		0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE		0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT		0x0f0d
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL		0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT		0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE		0x300
+#define AC_VERB_SET_PROC_COEF			0x400
+#define AC_VERB_SET_COEF_INDEX			0x500
+#define AC_VERB_SET_CONNECT_SEL			0x701
+#define AC_VERB_SET_PROC_STATE			0x703
+#define AC_VERB_SET_SDI_SELECT			0x704
+#define AC_VERB_SET_POWER_STATE			0x705
+#define AC_VERB_SET_CHANNEL_STREAMID		0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL		0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE		0x708
+#define AC_VERB_SET_PIN_SENSE			0x709
+#define AC_VERB_SET_BEEP_CONTROL		0x70a
+#define AC_VERB_SET_EAPD_BTLENALBE		0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1		0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2		0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL		0x70f
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0	0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3	0x71f
+#define AC_VERB_SET_CODEC_RESET			0x7ff
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID		0x00
+#define AC_PAR_SUBSYSTEM_ID		0x01
+#define AC_PAR_REV_ID			0x02
+#define AC_PAR_NODE_COUNT		0x04
+#define AC_PAR_FUNCTION_TYPE		0x05
+#define AC_PAR_AUDIO_FG_CAP		0x08
+#define AC_PAR_AUDIO_WIDGET_CAP		0x09
+#define AC_PAR_PCM			0x0a
+#define AC_PAR_STREAM			0x0b
+#define AC_PAR_PIN_CAP			0x0c
+#define AC_PAR_AMP_IN_CAP		0x0d
+#define AC_PAR_CONNLIST_LEN		0x0e
+#define AC_PAR_POWER_STATE		0x0f
+#define AC_PAR_PROC_CAP			0x10
+#define AC_PAR_GPIO_CAP			0x11
+#define AC_PAR_AMP_OUT_CAP		0x12
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE			(0xff<<0)
+#define AC_FGT_TYPE_SHIFT		0
+#define AC_FGT_UNSOL_CAP		(1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY		(0xf<<0)
+#define AC_AFG_IN_DELAY			(0xf<<8)
+#define AC_AFG_BEEP_GEN			(1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO			(1<<0)	/* stereo I/O */
+#define AC_WCAP_IN_AMP			(1<<1)	/* AMP-in present */
+#define AC_WCAP_OUT_AMP			(1<<2)	/* AMP-out present */
+#define AC_WCAP_AMP_OVRD		(1<<3)	/* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD		(1<<4)	/* format override */
+#define AC_WCAP_STRIPE			(1<<5)	/* stripe */
+#define AC_WCAP_PROC_WID		(1<<6)	/* Proc Widget */
+#define AC_WCAP_UNSOL_CAP		(1<<7)	/* Unsol capable */
+#define AC_WCAP_CONN_LIST		(1<<8)	/* connection list */
+#define AC_WCAP_DIGITAL			(1<<9)	/* digital I/O */
+#define AC_WCAP_POWER			(1<<10)	/* power control */
+#define AC_WCAP_LR_SWAP			(1<<11)	/* L/R swap */
+#define AC_WCAP_DELAY			(0xf<<16)
+#define AC_WCAP_DELAY_SHIFT		16
+#define AC_WCAP_TYPE			(0xf<<20)
+#define AC_WCAP_TYPE_SHIFT		20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES			(0xfff << 0)
+#define AC_SUPPCM_BITS_8		(1<<16)
+#define AC_SUPPCM_BITS_16		(1<<17)
+#define AC_SUPPCM_BITS_20		(1<<18)
+#define AC_SUPPCM_BITS_24		(1<<19)
+#define AC_SUPPCM_BITS_32		(1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM			(1<<0)
+#define AC_SUPFMT_FLOAT32		(1<<1)
+#define AC_SUPFMT_AC3			(1<<2)
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
+#define AC_PINCAP_PRES_DETECT		(1<<2)	/* presence detect capable */
+#define AC_PINCAP_HP_DRV		(1<<3)	/* headphone drive capable */
+#define AC_PINCAP_OUT			(1<<4)	/* output capable */
+#define AC_PINCAP_IN			(1<<5)	/* input capable */
+#define AC_PINCAP_BALANCE		(1<<6)	/* balanced I/O capable */
+#define AC_PINCAP_VREF			(7<<8)
+#define AC_PINCAP_VREF_SHIFT		8
+#define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
+/* Vref status (used in pin cap and pin ctl) */
+#define AC_PIN_VREF_HIZ			(1<<0)	/* Hi-Z */
+#define AC_PIN_VREF_50			(1<<1)	/* 50% */
+#define AC_PIN_VREF_GRD			(1<<2)	/* ground */
+#define AC_PIN_VREF_80			(1<<4)	/* 80% */
+#define AC_PIN_VREF_100			(1<<5)	/* 100% */
+
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET		(0x7f<<0)  /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT		0
+#define AC_AMPCAP_NUM_STEPS		(0x7f<<8)  /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT	8
+#define AC_AMPCAP_STEP_SIZE		(0x7f<<16) /* step size 0-32dB in 0.25dB */
+#define AC_AMPCAP_STEP_SIZE_SHIFT	16
+#define AC_AMPCAP_MUTE			(1<<31)    /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT		31
+
+/* Connection list */
+#define AC_CLIST_LENGTH			(0x7f<<0)
+#define AC_CLIST_LONG			(1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP			(1<<0)
+#define AC_PWRST_D1SUP			(1<<1)
+#define AC_PWRST_D2SUP			(1<<2)
+#define AC_PWRST_D3SUP			(1<<3)
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN			(1<<0)
+#define AC_PCAP_NUM_COEF		(0xff<<8)
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
+#define AC_KNBCAP_DELTA			(1<<8)
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE			(1<<8)
+#define AC_AMP_GAIN			(0x7f)
+#define AC_AMP_GET_INDEX		(0xf<<0)
+
+#define AC_AMP_GET_LEFT			(1<<13)
+#define AC_AMP_GET_RIGHT		(0<<13)
+#define AC_AMP_GET_OUTPUT		(1<<15)
+#define AC_AMP_GET_INPUT		(0<<15)
+
+#define AC_AMP_SET_INDEX		(0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT		8
+#define AC_AMP_SET_RIGHT		(1<<12)
+#define AC_AMP_SET_LEFT			(1<<13)
+#define AC_AMP_SET_INPUT		(1<<14)
+#define AC_AMP_SET_OUTPUT		(1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE			(1<<0)
+#define AC_DIG1_V			(1<<1)
+#define AC_DIG1_VCFG			(1<<2)
+#define AC_DIG1_EMPHASIS		(1<<3)
+#define AC_DIG1_COPYRIGHT		(1<<4)
+#define AC_DIG1_NONAUDIO		(1<<5)
+#define AC_DIG1_PROFESSIONAL		(1<<6)
+#define AC_DIG1_LEVEL			(1<<7)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_VREFEN		(0x7<<0)
+#define AC_PINCTL_IN_EN			(1<<5)
+#define AC_PINCTL_OUT_EN		(1<<6)
+#define AC_PINCTL_HP_EN			(1<<7)
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE		(0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
+#define AC_DEFCFG_MISC			(0xf<<8)
+#define AC_DEFCFG_COLOR			(0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT		12
+#define AC_DEFCFG_CONN_TYPE		(0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT	16
+#define AC_DEFCFG_DEVICE		(0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT		20
+#define AC_DEFCFG_LOCATION		(0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT	24
+#define AC_DEFCFG_PORT_CONN		(0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT	30
+
+/* device device types (0x0-0xf) */
+enum {
+	AC_JACK_LINE_OUT,
+	AC_JACK_SPEAKER,
+	AC_JACK_HP_OUT,
+	AC_JACK_CD,
+	AC_JACK_SPDIF_OUT,
+	AC_JACK_DIG_OTHER_OUT,
+	AC_JACK_MODEM_LINE_SIDE,
+	AC_JACK_MODEM_HAND_SIDE,
+	AC_JACK_LINE_IN,
+	AC_JACK_AUX,
+	AC_JACK_MIC_IN,
+	AC_JACK_TELEPHONY,
+	AC_JACK_SPDIF_IN,
+	AC_JACK_DIG_OTHER_IN,
+	AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+	AC_JACK_CONN_UNKNOWN,
+	AC_JACK_CONN_1_8,
+	AC_JACK_CONN_1_4,
+	AC_JACK_CONN_ATAPI,
+	AC_JACK_CONN_RCA,
+	AC_JACK_CONN_OPTICAL,
+	AC_JACK_CONN_OTHER_DIGITAL,
+	AC_JACK_CONN_OTHER_ANALOG,
+	AC_JACK_CONN_DIN,
+	AC_JACK_CONN_XLR,
+	AC_JACK_CONN_RJ11,
+	AC_JACK_CONN_COMB,
+	AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+	AC_JACK_COLOR_UNKNOWN,
+	AC_JACK_COLOR_BLACK,
+	AC_JACK_COLOR_GREY,
+	AC_JACK_COLOR_BLUE,
+	AC_JACK_COLOR_GREEN,
+	AC_JACK_COLOR_RED,
+	AC_JACK_COLOR_ORANGE,
+	AC_JACK_COLOR_YELLOW,
+	AC_JACK_COLOR_PURPLE,
+	AC_JACK_COLOR_PINK,
+	AC_JACK_COLOR_WHITE = 0xe,
+	AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+	AC_JACK_LOC_NONE,
+	AC_JACK_LOC_REAR,
+	AC_JACK_LOC_FRONT,
+	AC_JACK_LOC_LEFT,
+	AC_JACK_LOC_RIGHT,
+	AC_JACK_LOC_TOP,
+	AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+	AC_JACK_LOC_EXTERNAL = 0x00,
+	AC_JACK_LOC_INTERNAL = 0x10,
+	AC_JACK_LOC_SEPARATE = 0x20,
+	AC_JACK_LOC_OTHER    = 0x30,
+};
+enum {
+	/* external on primary chasis */
+	AC_JACK_LOC_REAR_PANEL = 0x07,
+	AC_JACK_LOC_DRIVE_BAY,
+	/* internal */
+	AC_JACK_LOC_RISER = 0x17,
+	AC_JACK_LOC_HDMI,
+	AC_JACK_LOC_ATAPI,
+	/* others */
+	AC_JACK_LOC_MOBILE_IN = 0x37,
+	AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+	AC_JACK_PORT_COMPLEX,
+	AC_JACK_PORT_NONE,
+	AC_JACK_PORT_FIXED,
+	AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS	16
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS	0x0f
+
+/*
+ * Structures
+ */
+
+struct hda_bus;
+struct hda_codec;
+struct hda_pcm;
+struct hda_pcm_stream;
+struct hda_bus_unsolicited;
+
+/* NID type */
+typedef u16 hda_nid_t;
+
+/* bus operators */
+struct hda_bus_ops {
+	/* send a single command */
+	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
+		       unsigned int verb, unsigned int parm);
+	/* get a response from the last command */
+	unsigned int (*get_response)(struct hda_codec *codec);
+	/* free the private data */
+	void (*private_free)(struct hda_bus *);
+};
+
+/* template to pass to the bus constructor */
+struct hda_bus_template {
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+};
+
+/*
+ * codec bus
+ *
+ * each controller needs to creata a hda_bus to assign the accessor.
+ * A hda_bus contains several codecs in the list codec_list.
+ */
+struct hda_bus {
+	snd_card_t *card;
+
+	/* copied from template */
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+
+	/* codec linked list */
+	struct list_head codec_list;
+	struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */
+
+	struct semaphore cmd_mutex;
+
+	/* unsolicited event queue */
+	struct hda_bus_unsolicited *unsol;
+
+	snd_info_entry_t *proc;
+};
+
+/*
+ * codec preset
+ *
+ * Known codecs have the patch to build and set up the controls/PCMs
+ * better than the generic parser.
+ */
+struct hda_codec_preset {
+	unsigned int id;
+	unsigned int mask;
+	unsigned int subs;
+	unsigned int subs_mask;
+	unsigned int rev;
+	const char *name;
+	int (*patch)(struct hda_codec *codec);
+};
+	
+/* ops set by the preset patch */
+struct hda_codec_ops {
+	int (*build_controls)(struct hda_codec *codec);
+	int (*build_pcms)(struct hda_codec *codec);
+	int (*init)(struct hda_codec *codec);
+	void (*free)(struct hda_codec *codec);
+	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+#ifdef CONFIG_PM
+	int (*suspend)(struct hda_codec *codec, pm_message_t state);
+	int (*resume)(struct hda_codec *codec);
+#endif
+};
+
+/* record for amp information cache */
+struct hda_amp_info {
+	u32 key;		/* hash key */
+	u32 amp_caps;		/* amp capabilities */
+	u16 vol[2];		/* current volume & mute*/
+	u16 status;		/* update flag */
+	u16 next;		/* next link */
+};
+
+/* PCM callbacks */
+struct hda_pcm_ops {
+	int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		    snd_pcm_substream_t *substream);
+	int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		     snd_pcm_substream_t *substream);
+	int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       unsigned int stream_tag, unsigned int format,
+		       snd_pcm_substream_t *substream);
+	int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       snd_pcm_substream_t *substream);
+};
+
+/* PCM information for each substream */
+struct hda_pcm_stream {
+	unsigned int substreams;	/* number of substreams, 0 = not exist */
+	unsigned int channels_min;	/* min. number of channels */
+	unsigned int channels_max;	/* max. number of channels */
+	hda_nid_t nid;	/* default NID to query rates/formats/bps, or set up */
+	u32 rates;	/* supported rates */
+	u64 formats;	/* supported formats (SNDRV_PCM_FMTBIT_) */
+	unsigned int maxbps;	/* supported max. bit per sample */
+	struct hda_pcm_ops ops;
+};
+
+/* for PCM creation */
+struct hda_pcm {
+	char *name;
+	struct hda_pcm_stream stream[2];
+};
+
+/* codec information */
+struct hda_codec {
+	struct hda_bus *bus;
+	unsigned int addr;	/* codec addr*/
+	struct list_head list;	/* list point */
+
+	hda_nid_t afg;	/* AFG node id */
+
+	/* ids */
+	u32 vendor_id;
+	u32 subsystem_id;
+	u32 revision_id;
+
+	/* detected preset */
+	const struct hda_codec_preset *preset;
+
+	/* set by patch */
+	struct hda_codec_ops patch_ops;
+
+	/* resume phase - all controls should update even if
+	 * the values are not changed
+	 */
+	unsigned int in_resume;
+
+	/* PCM to create, set by patch_ops.build_pcms callback */
+	unsigned int num_pcms;
+	struct hda_pcm *pcm_info;
+
+	/* codec specific info */
+	void *spec;
+
+	/* hash for amp access */
+	u16 amp_hash[32];
+	int num_amp_entries;
+	struct hda_amp_info amp_info[128]; /* big enough? */
+
+	struct semaphore spdif_mutex;
+	unsigned int spdif_status;	/* IEC958 status bits */
+	unsigned short spdif_ctls;	/* SPDIF control bits */
+	unsigned int spdif_in_enable;	/* SPDIF input enable? */
+};
+
+/* direction */
+enum {
+	HDA_INPUT, HDA_OUTPUT
+};
+
+
+/*
+ * constructors
+ */
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp);
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp);
+
+/*
+ * low level functions
+ */
+unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct,
+				unsigned int verb, unsigned int parm);
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int parm);
+#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
+int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id);
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns);
+
+struct hda_verb {
+	hda_nid_t nid;
+	u32 verb;
+	u32 param;
+};
+
+void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq);
+
+/* unsolicited event */
+int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
+
+/*
+ * Mixer
+ */
+int snd_hda_build_controls(struct hda_bus *bus);
+
+/*
+ * PCM
+ */
+int snd_hda_build_pcms(struct hda_bus *bus);
+void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag,
+				int channel_id, int format);
+unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels,
+					unsigned int format, unsigned int maxbps);
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
+int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
+				unsigned int format);
+
+/*
+ * Misc
+ */
+void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
+
+/*
+ * power management
+ */
+#ifdef CONFIG_PM
+int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
+int snd_hda_resume(struct hda_bus *bus);
+#endif
+
+#endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_generic.c
@@ -0,0 +1,906 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Generic widget tree parser
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/* widget node for parsing */
+struct hda_gnode {
+	hda_nid_t nid;		/* NID of this widget */
+	unsigned short nconns;	/* number of input connections */
+	hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; /* input connections */
+	unsigned int wid_caps;	/* widget capabilities */
+	unsigned char type;	/* widget type */
+	unsigned char pin_ctl;	/* pin controls */
+	unsigned char checked;	/* the flag indicates that the node is already parsed */
+	unsigned int pin_caps;	/* pin widget capabilities */
+	unsigned int def_cfg;	/* default configuration */
+	unsigned int amp_out_caps;	/* AMP out capabilities */
+	unsigned int amp_in_caps;	/* AMP in capabilities */
+	struct list_head list;
+};
+
+/* pathc-specific record */
+struct hda_gspec {
+	struct hda_gnode *dac_node;	/* DAC node */
+	struct hda_gnode *out_pin_node;	/* Output pin (Line-Out) node */
+	struct hda_gnode *pcm_vol_node;	/* Node for PCM volume */
+	unsigned int pcm_vol_index;	/* connection of PCM volume */
+
+	struct hda_gnode *adc_node;	/* ADC node */
+	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
+	unsigned int cur_cap_src;	/* current capture source */
+	struct hda_input_mux input_mux;
+	char cap_labels[HDA_MAX_NUM_INPUTS][16];
+
+	unsigned int def_amp_in_caps;
+	unsigned int def_amp_out_caps;
+
+	struct hda_pcm pcm_rec;		/* PCM information */
+
+	struct list_head nid_list;	/* list of widgets */
+};
+
+/*
+ * retrieve the default device type from the default config value
+ */
+#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+
+/*
+ * destructor
+ */
+static void snd_hda_generic_free(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p, *n;
+
+	if (! spec)
+		return;
+	/* free all widgets */
+	list_for_each_safe(p, n, &spec->nid_list) {
+		struct hda_gnode *node = list_entry(p, struct hda_gnode, list);
+		kfree(node);
+	}
+	kfree(spec);
+}
+
+
+/*
+ * add a new widget node and read its attributes
+ */
+static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid)
+{
+	struct hda_gnode *node;
+	int nconns;
+
+	node = kcalloc(1, sizeof(*node), GFP_KERNEL);
+	if (node == NULL)
+		return -ENOMEM;
+	node->nid = nid;
+	nconns = snd_hda_get_connections(codec, nid, node->conn_list, HDA_MAX_CONNECTIONS);
+	if (nconns < 0) {
+		kfree(node);
+		return nconns;
+	}
+	node->nconns = nconns;
+	node->wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+	node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+
+	if (node->type == AC_WID_PIN) {
+		node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP);
+		node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+	}
+
+	if (node->wid_caps & AC_WCAP_OUT_AMP) {
+		if (node->wid_caps & AC_WCAP_AMP_OVRD)
+			node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP);
+		if (! node->amp_out_caps)
+			node->amp_out_caps = spec->def_amp_out_caps;
+	}
+	if (node->wid_caps & AC_WCAP_IN_AMP) {
+		if (node->wid_caps & AC_WCAP_AMP_OVRD)
+			node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP);
+		if (! node->amp_in_caps)
+			node->amp_in_caps = spec->def_amp_in_caps;
+	}
+	list_add_tail(&node->list, &spec->nid_list);
+	return 0;
+}
+
+/*
+ * build the AFG subtree
+ */
+static int build_afg_tree(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	int i, nodes, err;
+	hda_nid_t nid;
+
+	snd_assert(spec, return -EINVAL);
+
+	spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP);
+	spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP);
+
+	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	if (! nid || nodes < 0) {
+		printk(KERN_ERR "Invalid AFG subtree\n");
+		return -EINVAL;
+	}
+
+	/* parse all nodes belonging to the AFG */
+	for (i = 0; i < nodes; i++, nid++) {
+		if ((err = add_new_node(codec, spec, nid)) < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+
+/*
+ * look for the node record for the given NID
+ */
+/* FIXME: should avoid the braindead linear search */
+static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->nid == nid)
+			return node;
+	}
+	return NULL;
+}
+
+/*
+ * unmute (and set max vol) the output amplifier
+ */
+static int unmute_output(struct hda_codec *codec, struct hda_gnode *node)
+{
+	unsigned int val, ofs;
+	snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid);
+	val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+	if (val >= ofs)
+		val -= ofs;
+	val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+	val |= AC_AMP_SET_OUTPUT;
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+/*
+ * unmute (and set max vol) the input amplifier
+ */
+static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index)
+{
+	unsigned int val, ofs;
+	snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index);
+	val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+	if (val >= ofs)
+		val -= ofs;
+	val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+	val |= AC_AMP_SET_INPUT;
+	// awk added - fixed to allow unmuting of indexed amps
+	val |= index << AC_AMP_SET_INDEX_SHIFT;
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+/*
+ * select the input connection of the given node.
+ */
+static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node,
+				   unsigned int index)
+{
+	snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index);
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index);
+}
+
+/*
+ * clear checked flag of each node in the node list
+ */
+static void clear_check_flags(struct hda_gspec *spec)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		node->checked = 0;
+	}
+}
+
+/*
+ * parse the output path recursively until reach to an audio output widget
+ *
+ * returns 0 if not found, 1 if found, or a negative error code.
+ */
+static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
+			     struct hda_gnode *node)
+{
+	int i, err;
+	struct hda_gnode *child;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node->type == AC_WID_AUD_OUT) {
+		if (node->wid_caps & AC_WCAP_DIGITAL) {
+			snd_printdd("Skip Digital OUT node %x\n", node->nid);
+			return 0;
+		}
+		snd_printdd("AUD_OUT found %x\n", node->nid);
+		if (spec->dac_node) {
+			/* already DAC node is assigned, just unmute & connect */
+			return node == spec->dac_node;
+		}
+		spec->dac_node = node;
+		if (node->wid_caps & AC_WCAP_OUT_AMP) {
+			spec->pcm_vol_node = node;
+			spec->pcm_vol_index = 0;
+		}
+		return 1; /* found */
+	}
+
+	for (i = 0; i < node->nconns; i++) {
+		child = hda_get_node(spec, node->conn_list[i]);
+		if (! child)
+			continue;
+		err = parse_output_path(codec, spec, child);
+		if (err < 0)
+			return err;
+		else if (err > 0) {
+			/* found one,
+			 * select the path, unmute both input and output
+			 */
+			if (node->nconns > 1)
+				select_input_connection(codec, node, i);
+			unmute_input(codec, node, i);
+			unmute_output(codec, node);
+			if (! spec->pcm_vol_node) {
+				if (node->wid_caps & AC_WCAP_IN_AMP) {
+					spec->pcm_vol_node = node;
+					spec->pcm_vol_index = i;
+				} else if (node->wid_caps & AC_WCAP_OUT_AMP) {
+					spec->pcm_vol_node = node;
+					spec->pcm_vol_index = 0;
+				}
+			}
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Look for the output PIN widget with the given jack type
+ * and parse the output path to that PIN.
+ *
+ * Returns the PIN node when the path to DAC is established.
+ */
+static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
+					   struct hda_gspec *spec,
+					   int jack_type)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->type != AC_WID_PIN)
+			continue;
+		/* output capable? */
+		if (! (node->pin_caps & AC_PINCAP_OUT))
+			continue;
+		if (jack_type >= 0) {
+			if (jack_type != get_defcfg_type(node))
+				continue;
+			if (node->wid_caps & AC_WCAP_DIGITAL)
+				continue; /* skip SPDIF */
+		} else {
+			/* output as default? */
+			if (! (node->pin_ctl & AC_PINCTL_OUT_EN))
+				continue;
+		}
+		clear_check_flags(spec);
+		err = parse_output_path(codec, spec, node);
+		if (err < 0)
+			return NULL;
+		else if (err > 0) {
+			/* unmute the PIN output */
+			unmute_output(codec, node);
+			/* set PIN-Out enable */
+			snd_hda_codec_write(codec, node->nid, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+			return node;
+		}
+	}
+	return NULL;
+}
+
+
+/*
+ * parse outputs
+ */
+static int parse_output(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *node;
+
+	/*
+	 * Look for the output PIN widget
+	 */
+	/* first, look for the line-out pin */
+	node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT);
+	if (node) /* found, remember the PIN node */
+		spec->out_pin_node = node;
+	/* look for the HP-out pin */
+	node = parse_output_jack(codec, spec, AC_JACK_HP_OUT);
+	if (node) {
+		if (! spec->out_pin_node)
+			spec->out_pin_node = node;
+	}
+
+	if (! spec->out_pin_node) {
+		/* no line-out or HP pins found,
+		 * then choose for the first output pin
+		 */
+		spec->out_pin_node = parse_output_jack(codec, spec, -1);
+		if (! spec->out_pin_node)
+			snd_printd("hda_generic: no proper output path found\n");
+	}
+
+	return 0;
+}
+
+/*
+ * input MUX
+ */
+
+/* control callbacks */
+static int capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_cap_src;
+	return 0;
+}
+
+static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+	return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+				     spec->adc_node->nid, &spec->cur_cap_src);
+}
+
+/*
+ * return the string name of the given input PIN widget
+ */
+static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
+{
+	unsigned int location = get_defcfg_location(node);
+	switch (get_defcfg_type(node)) {
+	case AC_JACK_LINE_IN:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Line";
+		return "Line";
+	case AC_JACK_CD:
+		if (pinctl)
+			*pinctl |= AC_PIN_VREF_GRD;
+		return "CD";
+	case AC_JACK_AUX:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Aux";
+		return "Aux";
+	case AC_JACK_MIC_IN:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Mic";
+		return "Mic";
+	case AC_JACK_SPDIF_IN:
+		return "SPDIF";
+	case AC_JACK_DIG_OTHER_IN:
+		return "Digital";
+	}
+	return NULL;
+}
+
+/*
+ * parse the nodes recursively until reach to the input PIN
+ *
+ * returns 0 if not found, 1 if found, or a negative error code.
+ */
+static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
+			       struct hda_gnode *node)
+{
+	int i, err;
+	unsigned int pinctl;
+	char *label;
+	const char *type;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node->type != AC_WID_PIN) {
+		for (i = 0; i < node->nconns; i++) {
+			struct hda_gnode *child;
+			child = hda_get_node(spec, node->conn_list[i]);
+			if (! child)
+				continue;
+			err = parse_adc_sub_nodes(codec, spec, child);
+			if (err < 0)
+				return err;
+			if (err > 0) {
+				/* found one,
+				 * select the path, unmute both input and output
+				 */
+				if (node->nconns > 1)
+					select_input_connection(codec, node, i);
+				unmute_input(codec, node, i);
+				unmute_output(codec, node);
+				return err;
+			}
+		}
+		return 0;
+	}
+
+	/* input capable? */
+	if (! (node->pin_caps & AC_PINCAP_IN))
+		return 0;
+
+	if (node->wid_caps & AC_WCAP_DIGITAL)
+		return 0; /* skip SPDIF */
+
+	if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) {
+		snd_printk(KERN_ERR "hda_generic: Too many items for capture\n");
+		return -EINVAL;
+	}
+
+	pinctl = AC_PINCTL_IN_EN;
+	/* create a proper capture source label */
+	type = get_input_type(node, &pinctl);
+	if (! type) {
+		/* input as default? */
+		if (! (node->pin_ctl & AC_PINCTL_IN_EN))
+			return 0;
+		type = "Input";
+	}
+	label = spec->cap_labels[spec->input_mux.num_items];
+	strcpy(label, type);
+	spec->input_mux.items[spec->input_mux.num_items].label = label;
+
+	/* unmute the PIN external input */
+	unmute_input(codec, node, 0); /* index = 0? */
+	/* set PIN-In enable */
+	snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+
+	return 1; /* found */
+}
+
+/*
+ * parse input
+ */
+static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *node;
+	int i, err;
+
+	snd_printdd("AUD_IN = %x\n", adc_node->nid);
+	clear_check_flags(spec);
+
+	// awk added - fixed no recording due to muted widget
+	unmute_input(codec, adc_node, 0);
+	
+	/*
+	 * check each connection of the ADC
+	 * if it reaches to a proper input PIN, add the path as the
+	 * input path.
+	 */
+	for (i = 0; i < adc_node->nconns; i++) {
+		node = hda_get_node(spec, adc_node->conn_list[i]);
+		if (! node)
+			continue;
+		err = parse_adc_sub_nodes(codec, spec, node);
+		if (err < 0)
+			return err;
+		else if (err > 0) {
+			struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items];
+			char *buf = spec->cap_labels[spec->input_mux.num_items];
+			int ocap;
+			for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) {
+				if (! strcmp(buf, spec->cap_labels[ocap])) {
+					/* same label already exists,
+					 * put the index number to be unique
+					 */
+					sprintf(buf, "%s %d", spec->cap_labels[ocap],
+						spec->input_mux.num_items);
+				}
+			}
+			csrc->index = i;
+			spec->input_mux.num_items++;
+		}
+	}
+
+	if (! spec->input_mux.num_items)
+		return 0; /* no input path found... */
+
+	snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items);
+	for (i = 0; i < spec->input_mux.num_items; i++)
+		snd_printdd("  [%s] IDX=0x%x\n", spec->input_mux.items[i].label,
+			    spec->input_mux.items[i].index);
+
+	spec->adc_node = adc_node;
+	return 1;
+}
+
+/*
+ * parse input
+ */
+static int parse_input(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+
+	/*
+	 * At first we look for an audio input widget.
+	 * If it reaches to certain input PINs, we take it as the
+	 * input path.
+	 */
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->wid_caps & AC_WCAP_DIGITAL)
+			continue; /* skip SPDIF */
+		if (node->type == AC_WID_AUD_IN) {
+			err = parse_input_path(codec, node);
+			if (err < 0)
+				return err;
+			else if (err > 0)
+				return 0;
+		}
+	}
+	snd_printd("hda_generic: no proper input path found\n");
+	return 0;
+}
+
+/*
+ * create mixer controls if possible
+ */
+#define DIR_OUT		0x1
+#define DIR_IN		0x2
+
+static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
+			unsigned int index, const char *type, const char *dir_sfx)
+{
+	char name[32];
+	int err;
+	int created = 0;
+	snd_kcontrol_new_t knew;
+
+	if (type)
+		sprintf(name, "%s %s Switch", type, dir_sfx);
+	else
+		sprintf(name, "%s Switch", dir_sfx);
+	if ((node->wid_caps & AC_WCAP_IN_AMP) &&
+	    (node->amp_in_caps & AC_AMPCAP_MUTE)) {
+		knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
+		   (node->amp_out_caps & AC_AMPCAP_MUTE)) {
+		knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	}
+
+	if (type)
+		sprintf(name, "%s %s Volume", type, dir_sfx);
+	else
+		sprintf(name, "%s Volume", dir_sfx);
+	if ((node->wid_caps & AC_WCAP_IN_AMP) &&
+	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
+		knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
+		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
+		knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	}
+
+	return created;
+}
+
+/*
+ * check whether the controls with the given name and direction suffix already exist
+ */
+static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir)
+{
+	snd_ctl_elem_id_t id;
+	memset(&id, 0, sizeof(id));
+	sprintf(id.name, "%s %s Volume", type, dir);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	if (snd_ctl_find_id(codec->bus->card, &id))
+		return 1;
+	sprintf(id.name, "%s %s Switch", type, dir);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	if (snd_ctl_find_id(codec->bus->card, &id))
+		return 1;
+	return 0;
+}
+
+/*
+ * build output mixer controls
+ */
+static int build_output_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	int err;
+
+	err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index,
+			   "PCM", "Playback");
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/* create capture volume/switch */
+static int build_input_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *adc_node = spec->adc_node;
+	int err;
+
+	if (! adc_node)
+		return 0; /* not found */
+
+	/* create capture volume and switch controls if the ADC has an amp */
+	err = create_mixer(codec, adc_node, 0, NULL, "Capture");
+
+	/* create input MUX if multiple sources are available */
+	if (spec->input_mux.num_items > 1) {
+		static snd_kcontrol_new_t cap_sel = {
+			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+			.name = "Capture Source",
+			.info = capture_source_info,
+			.get = capture_source_get,
+			.put = capture_source_put,
+		};
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0)
+			return err;
+		spec->cur_cap_src = 0;
+		select_input_connection(codec, adc_node, spec->input_mux.items[0].index);
+	}
+	return 0;
+}
+
+
+/*
+ * parse the nodes recursively until reach to the output PIN.
+ *
+ * returns 0 - if not found,
+ *         1 - if found, but no mixer is created
+ *         2 - if found and mixer was already created, (just skip)
+ *         a negative error code
+ */
+static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec,
+			       struct hda_gnode *node, struct hda_gnode *dest_node,
+			       const char *type)
+{
+	int i, err;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node == dest_node) {
+		/* loopback connection found */
+		return 1;
+	}
+
+	for (i = 0; i < node->nconns; i++) {
+		struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]);
+		if (! child)
+			continue;
+		err = parse_loopback_path(codec, spec, child, dest_node, type);
+		if (err < 0)
+			return err;
+		else if (err >= 1) {
+			if (err == 1) {
+				err = create_mixer(codec, node, i, type, "Playback");
+				if (err < 0)
+					return err;
+				if (err > 0)
+					return 2; /* ok, created */
+				/* not created, maybe in the lower path */
+				err = 1;
+			}
+			/* connect and unmute */
+			if (node->nconns > 1)
+				select_input_connection(codec, node, i);
+			unmute_input(codec, node, i);
+			unmute_output(codec, node);
+			return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * parse the tree and build the loopback controls
+ */
+static int build_loopback_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+	const char *type;
+
+	if (! spec->out_pin_node)
+		return 0;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->type != AC_WID_PIN)
+			continue;
+		/* input capable? */
+		if (! (node->pin_caps & AC_PINCAP_IN))
+			return 0;
+		type = get_input_type(node, NULL);
+		if (type) {
+			if (check_existing_control(codec, type, "Playback"))
+				continue;
+			clear_check_flags(spec);
+			err = parse_loopback_path(codec, spec, spec->out_pin_node,
+						  node, type);
+			if (err < 0)
+				return err;
+			if (! err)
+				continue;
+		}
+	}
+	return 0;
+}
+
+/*
+ * build mixer controls
+ */
+static int build_generic_controls(struct hda_codec *codec)
+{
+	int err;
+
+	if ((err = build_input_controls(codec)) < 0 ||
+	    (err = build_output_controls(codec)) < 0 ||
+	    (err = build_loopback_controls(codec)) < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * PCM
+ */
+static struct hda_pcm_stream generic_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int build_generic_pcms(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	if (! spec->dac_node && ! spec->adc_node) {
+		snd_printd("hda_generic: no PCM found\n");
+		return 0;
+	}
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "HDA Generic";
+	if (spec->dac_node) {
+		info->stream[0] = generic_pcm_playback;
+		info->stream[0].nid = spec->dac_node->nid;
+	}
+	if (spec->adc_node) {
+		info->stream[1] = generic_pcm_playback;
+		info->stream[1].nid = spec->adc_node->nid;
+	}
+
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_codec_ops generic_patch_ops = {
+	.build_controls = build_generic_controls,
+	.build_pcms = build_generic_pcms,
+	.free = snd_hda_generic_free,
+};
+
+/*
+ * the generic parser
+ */
+int snd_hda_parse_generic_codec(struct hda_codec *codec)
+{
+	struct hda_gspec *spec;
+	int err;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL) {
+		printk(KERN_ERR "hda_generic: can't allocate spec\n");
+		return -ENOMEM;
+	}
+	codec->spec = spec;
+	INIT_LIST_HEAD(&spec->nid_list);
+
+	if ((err = build_afg_tree(codec)) < 0)
+		goto error;
+
+	if ((err = parse_input(codec)) < 0 ||
+	    (err = parse_output(codec)) < 0)
+		goto error;
+
+	codec->patch_ops = generic_patch_ops;
+
+	return 0;
+
+ error:
+	snd_hda_generic_free(codec);
+	return err;
+}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_intel.c
@@ -0,0 +1,1451 @@
+/*
+ *
+ *  hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio.
+ *
+ *  Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *                     PeiSen Hou <pshou@realtek.com.tw>
+ *
+ *  This program is free software; you can redistribute it 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.
+ *
+ *  CONTACTS:
+ *
+ *  Matt Jared		matt.jared@intel.com
+ *  Andy Kopp		andy.kopp@intel.com
+ *  Dan Kogan		dan.d.kogan@intel.com
+ *
+ *  CHANGES:
+ *
+ *  2004.12.01	Major rewrite by tiwai, merged the work of pshou
+ * 
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_codec.h"
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static char *model[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
+MODULE_PARM_DESC(model, "Use the given board model.");
+
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
+			 "{Intel, ICH6M},"
+			 "{Intel, ICH7},"
+			 "{Intel, ESB2}}");
+MODULE_DESCRIPTION("Intel HDA driver");
+
+#define SFX	"hda-intel: "
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP			0x00
+#define ICH6_REG_VMIN			0x02
+#define ICH6_REG_VMAJ			0x03
+#define ICH6_REG_OUTPAY			0x04
+#define ICH6_REG_INPAY			0x06
+#define ICH6_REG_GCTL			0x08
+#define ICH6_REG_WAKEEN			0x0c
+#define ICH6_REG_STATESTS		0x0e
+#define ICH6_REG_GSTS			0x10
+#define ICH6_REG_INTCTL			0x20
+#define ICH6_REG_INTSTS			0x24
+#define ICH6_REG_WALCLK			0x30
+#define ICH6_REG_SYNC			0x34	
+#define ICH6_REG_CORBLBASE		0x40
+#define ICH6_REG_CORBUBASE		0x44
+#define ICH6_REG_CORBWP			0x48
+#define ICH6_REG_CORBRP			0x4A
+#define ICH6_REG_CORBCTL		0x4c
+#define ICH6_REG_CORBSTS		0x4d
+#define ICH6_REG_CORBSIZE		0x4e
+
+#define ICH6_REG_RIRBLBASE		0x50
+#define ICH6_REG_RIRBUBASE		0x54
+#define ICH6_REG_RIRBWP			0x58
+#define ICH6_REG_RINTCNT		0x5a
+#define ICH6_REG_RIRBCTL		0x5c
+#define ICH6_REG_RIRBSTS		0x5d
+#define ICH6_REG_RIRBSIZE		0x5e
+
+#define ICH6_REG_IC			0x60
+#define ICH6_REG_IR			0x64
+#define ICH6_REG_IRS			0x68
+#define   ICH6_IRS_VALID	(1<<1)
+#define   ICH6_IRS_BUSY		(1<<0)
+
+#define ICH6_REG_DPLBASE		0x70
+#define ICH6_REG_DPUBASE		0x74
+#define   ICH6_DPLBASE_ENABLE	0x1	/* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL			0x00
+#define ICH6_REG_SD_STS			0x03
+#define ICH6_REG_SD_LPIB		0x04
+#define ICH6_REG_SD_CBL			0x08
+#define ICH6_REG_SD_LVI			0x0c
+#define ICH6_REG_SD_FIFOW		0x0e
+#define ICH6_REG_SD_FIFOSIZE		0x10
+#define ICH6_REG_SD_FORMAT		0x12
+#define ICH6_REG_SD_BDLPL		0x18
+#define ICH6_REG_SD_BDLPU		0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL	0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+#define MAX_ICH6_DEV		8
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define AZX_MAX_FRAG		(PAGE_SIZE / (MAX_ICH6_DEV * 16))
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
+/* max number of PCM devics per card */
+#define AZX_MAX_PCMS		8
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE	0x01
+#define RIRB_INT_OVERRUN	0x04
+#define RIRB_INT_MASK		0x05
+
+/* STATESTS int mask: SD2,SD1,SD0 */
+#define STATESTS_INT_MASK	0x07
+#define AZX_MAX_CODECS		3
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
+#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT	20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
+#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
+#define SD_INT_COMPLETE		0x04	/* completion interrupt */
+#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM	0xff		/* all stream interrupts */
+#define ICH6_INT_CTRL_EN	0x40000000	/* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN	0x80000000	/* global interrupt enable bit */
+
+/* GCTL reset bit */
+#define ICH6_GCTL_RESET		(1<<0)
+
+/* CORB/RIRB control, read/write pointer */
+#define ICH6_RBCTL_DMA_EN	0x02	/* enable DMA */
+#define ICH6_RBCTL_IRQ_EN	0x01	/* enable IRQ */
+#define ICH6_RBRWP_CLR		0x8000	/* read/write pointer clear */
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES	256
+#define ICH6_MAX_RIRB_ENTRIES	256
+
+
+/*
+ * Use CORB/RIRB for communication from/to codecs.
+ * This is the way recommended by Intel (see below).
+ */
+#define USE_CORB_RIRB
+
+/*
+ * Define this if use the position buffer instead of reading SD_LPIB
+ * It's not used as default since SD_LPIB seems to give more accurate position
+ */
+/* #define USE_POSBUF */
+
+/*
+ */
+
+typedef struct snd_azx azx_t;
+typedef struct snd_azx_rb azx_rb_t;
+typedef struct snd_azx_dev azx_dev_t;
+
+struct snd_azx_dev {
+	u32 *bdl;			/* virtual address of the BDL */
+	dma_addr_t bdl_addr;		/* physical address of the BDL */
+	volatile u32 *posbuf;			/* position buffer pointer */
+
+	unsigned int bufsize;		/* size of the play buffer in bytes */
+	unsigned int fragsize;		/* size of each period in bytes */
+	unsigned int frags;		/* number for period in the play buffer */
+	unsigned int fifo_size;		/* FIFO size */
+
+	void __iomem *sd_addr;		/* stream descriptor pointer */
+
+	u32 sd_int_sta_mask;		/* stream int status mask */
+
+	/* pcm support */
+	snd_pcm_substream_t *substream;	/* assigned substream, set in PCM open */
+	unsigned int format_val;	/* format value to be set in the controller and the codec */
+	unsigned char stream_tag;	/* assigned stream */
+	unsigned char index;		/* stream index */
+
+	unsigned int opened: 1;
+	unsigned int running: 1;
+};
+
+/* CORB/RIRB */
+struct snd_azx_rb {
+	u32 *buf;		/* CORB/RIRB buffer
+				 * Each CORB entry is 4byte, RIRB is 8byte
+				 */
+	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
+	/* for RIRB */
+	unsigned short rp, wp;	/* read/write pointers */
+	int cmds;		/* number of pending requests */
+	u32 res;		/* last read value */
+};
+
+struct snd_azx {
+	snd_card_t *card;
+	struct pci_dev *pci;
+
+	/* pci resources */
+	unsigned long addr;
+	void __iomem *remap_addr;
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct semaphore open_mutex;
+
+	/* streams */
+	azx_dev_t azx_dev[MAX_ICH6_DEV];
+
+	/* PCM */
+	unsigned int pcm_devs;
+	snd_pcm_t *pcm[AZX_MAX_PCMS];
+
+	/* HD codec */
+	unsigned short codec_mask;
+	struct hda_bus *bus;
+
+	/* CORB/RIRB */
+	azx_rb_t corb;
+	azx_rb_t rirb;
+
+	/* BDL, CORB/RIRB and position buffers */
+	struct snd_dma_buffer bdl;
+	struct snd_dma_buffer rb;
+	struct snd_dma_buffer posbuf;
+};
+
+/*
+ * macros for easy use
+ */
+#define azx_writel(chip,reg,value) \
+	writel(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readl(chip,reg) \
+	readl((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writew(chip,reg,value) \
+	writew(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readw(chip,reg) \
+	readw((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writeb(chip,reg,value) \
+	writeb(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readb(chip,reg) \
+	readb((chip)->remap_addr + ICH6_REG_##reg)
+
+#define azx_sd_writel(dev,reg,value) \
+	writel(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readl(dev,reg) \
+	readl((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writew(dev,reg,value) \
+	writew(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readw(dev,reg) \
+	readw((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writeb(dev,reg,value) \
+	writeb(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readb(dev,reg) \
+	readb((dev)->sd_addr + ICH6_REG_##reg)
+
+/* for pcm support */
+#define get_azx_dev(substream) (azx_dev_t*)(substream->runtime->private_data)
+
+/* Get the upper 32bit of the given dma_addr_t
+ * Compiler should optimize and eliminate the code if dma_addr_t is 32bit
+ */
+#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
+
+
+/*
+ * Interface for HD codec
+ */
+
+#ifdef USE_CORB_RIRB
+/*
+ * CORB / RIRB interface
+ */
+static int azx_alloc_cmd_io(azx_t *chip)
+{
+	int err;
+
+	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
+	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				  PAGE_SIZE, &chip->rb);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
+		return err;
+	}
+	return 0;
+}
+
+static void azx_init_cmd_io(azx_t *chip)
+{
+	/* CORB set up */
+	chip->corb.addr = chip->rb.addr;
+	chip->corb.buf = (u32 *)chip->rb.area;
+	azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
+	azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
+
+	/* set the corb write pointer to 0 */
+	azx_writew(chip, CORBWP, 0);
+	/* reset the corb hw read pointer */
+	azx_writew(chip, CORBRP, ICH6_RBRWP_CLR);
+	/* enable corb dma */
+	azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN);
+
+	/* RIRB set up */
+	chip->rirb.addr = chip->rb.addr + 2048;
+	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
+	azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
+
+	/* reset the rirb hw write pointer */
+	azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
+	/* set N=1, get RIRB response interrupt for new entry */
+	azx_writew(chip, RINTCNT, 1);
+	/* enable rirb dma and response irq */
+#ifdef USE_CORB_RIRB
+	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
+#else
+	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN);
+#endif
+	chip->rirb.rp = chip->rirb.cmds = 0;
+}
+
+static void azx_free_cmd_io(azx_t *chip)
+{
+	/* disable ringbuffer DMAs */
+	azx_writeb(chip, RIRBCTL, 0);
+	azx_writeb(chip, CORBCTL, 0);
+}
+
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int para)
+{
+	azx_t *chip = codec->bus->private_data;
+	unsigned int wp;
+	u32 val;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= para;
+
+	/* add command to corb */
+	wp = azx_readb(chip, CORBWP);
+	wp++;
+	wp %= ICH6_MAX_CORB_ENTRIES;
+
+	spin_lock_irq(&chip->reg_lock);
+	chip->rirb.cmds++;
+	chip->corb.buf[wp] = cpu_to_le32(val);
+	azx_writel(chip, CORBWP, wp);
+	spin_unlock_irq(&chip->reg_lock);
+
+	return 0;
+}
+
+#define ICH6_RIRB_EX_UNSOL_EV	(1<<4)
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void azx_update_rirb(azx_t *chip)
+{
+	unsigned int rp, wp;
+	u32 res, res_ex;
+
+	wp = azx_readb(chip, RIRBWP);
+	if (wp == chip->rirb.wp)
+		return;
+	chip->rirb.wp = wp;
+		
+	while (chip->rirb.rp != wp) {
+		chip->rirb.rp++;
+		chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
+
+		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+		res = le32_to_cpu(chip->rirb.buf[rp]);
+		if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
+			snd_hda_queue_unsol_event(chip->bus, res, res_ex);
+		else if (chip->rirb.cmds) {
+			chip->rirb.cmds--;
+			chip->rirb.res = res;
+		}
+	}
+}
+
+/* receive a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+	azx_t *chip = codec->bus->private_data;
+	int timeout = 50;
+
+	while (chip->rirb.cmds) {
+		if (! --timeout) {
+			snd_printk(KERN_ERR "azx_get_response timeout\n");
+			chip->rirb.rp = azx_readb(chip, RIRBWP);
+			chip->rirb.cmds = 0;
+			return -1;
+		}
+		msleep(1);
+	}
+	return chip->rirb.res; /* the last value */
+}
+
+#else
+/*
+ * Use the single immediate command instead of CORB/RIRB for simplicity
+ *
+ * Note: according to Intel, this is not preferred use.  The command was
+ *       intended for the BIOS only, and may get confused with unsolicited
+ *       responses.  So, we shouldn't use it for normal operation from the
+ *       driver.
+ *       I left the codes, however, for debugging/testing purposes.
+ */
+
+#define azx_alloc_cmd_io(chip)	0
+#define azx_init_cmd_io(chip)
+#define azx_free_cmd_io(chip)
+
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int para)
+{
+	azx_t *chip = codec->bus->private_data;
+	u32 val;
+	int timeout = 50;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= para;
+
+	while (timeout--) {
+		/* check ICB busy bit */
+		if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
+			/* Clear IRV valid bit */
+			azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID);
+			azx_writel(chip, IC, val);
+			azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY);
+			return 0;
+		}
+		udelay(1);
+	}
+	snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val);
+	return -EIO;
+}
+
+/* receive a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+	azx_t *chip = codec->bus->private_data;
+	int timeout = 50;
+
+	while (timeout--) {
+		/* check IRV busy bit */
+		if (azx_readw(chip, IRS) & ICH6_IRS_VALID)
+			return azx_readl(chip, IR);
+		udelay(1);
+	}
+	snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS));
+	return (unsigned int)-1;
+}
+
+#define azx_update_rirb(chip)
+
+#endif /* USE_CORB_RIRB */
+
+/* reset codec link */
+static int azx_reset(azx_t *chip)
+{
+	int count;
+
+	/* reset controller */
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
+
+	count = 50;
+	while (azx_readb(chip, GCTL) && --count)
+		msleep(1);
+
+	/* delay for >= 100us for codec PLL to settle per spec
+	 * Rev 0.9 section 5.5.1
+	 */
+	msleep(1);
+
+	/* Bring controller out of reset */
+	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
+
+	count = 50;
+	while (! azx_readb(chip, GCTL) && --count)
+		msleep(1);
+
+	/* Brent Chartrand said to wait >= 540us for codecs to intialize */
+	msleep(1);
+
+	/* check to see if controller is ready */
+	if (! azx_readb(chip, GCTL)) {
+		snd_printd("azx_reset: controller not ready!\n");
+		return -EBUSY;
+	}
+
+	/* detect codecs */
+	if (! chip->codec_mask) {
+		chip->codec_mask = azx_readw(chip, STATESTS);
+		snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+	}
+
+	return 0;
+}
+
+
+/*
+ * Lowlevel interface
+ */  
+
+/* enable interrupts */
+static void azx_int_enable(azx_t *chip)
+{
+	/* enable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
+		   ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
+}
+
+/* disable interrupts */
+static void azx_int_disable(azx_t *chip)
+{
+	int i;
+
+	/* disable interrupts in stream descriptor */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_sd_writeb(azx_dev, SD_CTL,
+			      azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
+	}
+
+	/* disable SIE for all streams */
+	azx_writeb(chip, INTCTL, 0);
+
+	/* disable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
+		   ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
+}
+
+/* clear interrupts */
+static void azx_int_clear(azx_t *chip)
+{
+	int i;
+
+	/* clear stream status */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
+	}
+
+	/* clear STATESTS */
+	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
+	/* clear rirb status */
+	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+
+	/* clear int status */
+	azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
+}
+
+/* start a stream */
+static void azx_stream_start(azx_t *chip, azx_dev_t *azx_dev)
+{
+	/* enable SIE */
+	azx_writeb(chip, INTCTL,
+		   azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+	/* set DMA start and interrupt mask */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
+		      SD_CTL_DMA_START | SD_INT_MASK);
+}
+
+/* stop a stream */
+static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev)
+{
+	/* stop DMA */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
+		      ~(SD_CTL_DMA_START | SD_INT_MASK));
+	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+	/* disable SIE */
+	azx_writeb(chip, INTCTL,
+		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+}
+
+
+/*
+ * initialize the chip
+ */
+static void azx_init_chip(azx_t *chip)
+{
+	unsigned char tcsel_reg;
+
+	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
+	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
+	 * Ensuring these bits are 0 clears playback static on some HD Audio codecs
+	 */
+	pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &tcsel_reg);
+	pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, tcsel_reg & 0xf8);
+
+	/* reset controller */
+	azx_reset(chip);
+
+	/* initialize interrupts */
+	azx_int_clear(chip);
+	azx_int_enable(chip);
+
+	/* initialize the codec command I/O */
+	azx_init_cmd_io(chip);
+
+#ifdef USE_POSBUF
+	/* program the position buffer */
+	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+	azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
+#endif
+}
+
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
+{
+	azx_t *chip = dev_id;
+	azx_dev_t *azx_dev;
+	u32 status;
+	int i;
+
+	spin_lock(&chip->reg_lock);
+
+	status = azx_readl(chip, INTSTS);
+	if (status == 0) {
+		spin_unlock(&chip->reg_lock);
+		return IRQ_NONE;
+	}
+	
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev = &chip->azx_dev[i];
+		if (status & azx_dev->sd_int_sta_mask) {
+			azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
+			if (azx_dev->substream && azx_dev->running) {
+				spin_unlock(&chip->reg_lock);
+				snd_pcm_period_elapsed(azx_dev->substream);
+				spin_lock(&chip->reg_lock);
+			}
+		}
+	}
+
+	/* clear rirb int */
+	status = azx_readb(chip, RIRBSTS);
+	if (status & RIRB_INT_MASK) {
+		if (status & RIRB_INT_RESPONSE)
+			azx_update_rirb(chip);
+		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+	}
+
+#if 0
+	/* clear state status int */
+	if (azx_readb(chip, STATESTS) & 0x04)
+		azx_writeb(chip, STATESTS, 0x04);
+#endif
+	spin_unlock(&chip->reg_lock);
+	
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * set up BDL entries
+ */
+static void azx_setup_periods(azx_dev_t *azx_dev)
+{
+	u32 *bdl = azx_dev->bdl;
+	dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;
+	int idx;
+
+	/* reset BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(azx_dev, SD_BDLPU, 0);
+
+	/* program the initial BDL entries */
+	for (idx = 0; idx < azx_dev->frags; idx++) {
+		unsigned int off = idx << 2; /* 4 dword step */
+		dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;
+		/* program the address field of the BDL entry */
+		bdl[off] = cpu_to_le32((u32)addr);
+		bdl[off+1] = cpu_to_le32(upper_32bit(addr));
+
+		/* program the size field of the BDL entry */
+		bdl[off+2] = cpu_to_le32(azx_dev->fragsize);
+
+		/* program the IOC to enable interrupt when buffer completes */
+		bdl[off+3] = cpu_to_le32(0x01);
+	}
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev)
+{
+	unsigned char val;
+	int timeout;
+
+	/* make sure the run bit is zero for SD */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START);
+	/* reset stream */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET);
+	udelay(3);
+	timeout = 300;
+	while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
+	       --timeout)
+		;
+	val &= ~SD_CTL_STREAM_RESET;
+	azx_sd_writeb(azx_dev, SD_CTL, val);
+	udelay(3);
+
+	timeout = 300;
+	/* waiting for hardware to report that the stream is out of reset */
+	while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
+	       --timeout)
+		;
+
+	/* program the stream_tag */
+	azx_sd_writel(azx_dev, SD_CTL,
+		      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) |
+		      (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT));
+
+	/* program the length of samples in cyclic buffer */
+	azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);
+
+	/* program the stream format */
+	/* this value needs to be the same as the one programmed */
+	azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val);
+
+	/* program the stream LVI (last valid index) of the BDL */
+	azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1);
+
+	/* program the BDL address */
+	/* lower BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);
+	/* upper BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
+
+#ifdef USE_POSBUF
+	/* enable the position buffer */
+	if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+		azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+#endif
+	/* set the interrupt enable bits in the descriptor control register */
+	azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
+
+	return 0;
+}
+
+
+/*
+ * Codec initialization
+ */
+
+static int __devinit azx_codec_create(azx_t *chip, const char *model)
+{
+	struct hda_bus_template bus_temp;
+	int c, codecs, err;
+
+	memset(&bus_temp, 0, sizeof(bus_temp));
+	bus_temp.private_data = chip;
+	bus_temp.modelname = model;
+	bus_temp.pci = chip->pci;
+	bus_temp.ops.command = azx_send_cmd;
+	bus_temp.ops.get_response = azx_get_response;
+
+	if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0)
+		return err;
+
+	codecs = 0;
+	for (c = 0; c < AZX_MAX_CODECS; c++) {
+		if (chip->codec_mask & (1 << c)) {
+			err = snd_hda_codec_new(chip->bus, c, NULL);
+			if (err < 0)
+				continue;
+			codecs++;
+		}
+	}
+	if (! codecs) {
+		snd_printk(KERN_ERR SFX "no codecs initialized\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+
+/*
+ * PCM support
+ */
+
+/* assign a stream for the PCM */
+static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
+{
+	int dev, i;
+	dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
+	for (i = 0; i < 4; i++, dev++)
+		if (! chip->azx_dev[dev].opened) {
+			chip->azx_dev[dev].opened = 1;
+			return &chip->azx_dev[dev];
+		}
+	return NULL;
+}
+
+/* release the assigned stream */
+static inline void azx_release_device(azx_dev_t *azx_dev)
+{
+	azx_dev->opened = 0;
+}
+
+static snd_pcm_hardware_t azx_pcm_hw = {
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_RESUME),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	AZX_MAX_BUF_SIZE,
+	.period_bytes_min =	128,
+	.period_bytes_max =	AZX_MAX_BUF_SIZE / 2,
+	.periods_min =		2,
+	.periods_max =		AZX_MAX_FRAG,
+	.fifo_size =		0,
+};
+
+struct azx_pcm {
+	azx_t *chip;
+	struct hda_codec *codec;
+	struct hda_pcm_stream *hinfo[2];
+};
+
+static int azx_pcm_open(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned long flags;
+	int err;
+
+	down(&chip->open_mutex);
+	azx_dev = azx_assign_device(chip, substream->stream);
+	if (azx_dev == NULL) {
+		up(&chip->open_mutex);
+		return -EBUSY;
+	}
+	runtime->hw = azx_pcm_hw;
+	runtime->hw.channels_min = hinfo->channels_min;
+	runtime->hw.channels_max = hinfo->channels_max;
+	runtime->hw.formats = hinfo->formats;
+	runtime->hw.rates = hinfo->rates;
+	snd_pcm_limit_hw_rates(runtime);
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
+		azx_release_device(azx_dev);
+		up(&chip->open_mutex);
+		return err;
+	}
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	azx_dev->substream = substream;
+	azx_dev->running = 0;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	runtime->private_data = azx_dev;
+	up(&chip->open_mutex);
+	return 0;
+}
+
+static int azx_pcm_close(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	unsigned long flags;
+
+	down(&chip->open_mutex);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	azx_dev->substream = NULL;
+	azx_dev->running = 0;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	azx_release_device(azx_dev);
+	hinfo->ops.close(hinfo, apcm->codec, substream);
+	up(&chip->open_mutex);
+	return 0;
+}
+
+static int azx_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int azx_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+
+	/* reset BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(azx_dev, SD_BDLPU, 0);
+	azx_sd_writel(azx_dev, SD_CTL, 0);
+
+	hinfo->ops.cleanup(hinfo, apcm->codec, substream);
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int azx_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
+	azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
+	azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
+	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
+							 runtime->channels,
+							 runtime->format,
+							 hinfo->maxbps);
+	if (! azx_dev->format_val) {
+		snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n",
+			   runtime->rate, runtime->channels, runtime->format);
+		return -EINVAL;
+	}
+
+	snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n",
+		    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
+	azx_setup_periods(azx_dev);
+	azx_setup_controller(chip, azx_dev);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
+	else
+		azx_dev->fifo_size = 0;
+
+	return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
+				  azx_dev->format_val, substream);
+}
+
+static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	azx_t *chip = apcm->chip;
+	int err = 0;
+
+	spin_lock(&chip->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_START:
+		azx_stream_start(chip, azx_dev);
+		azx_dev->running = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		azx_stream_stop(chip, azx_dev);
+		azx_dev->running = 0;
+		break;
+	default:
+		err = -EINVAL;
+	}
+	spin_unlock(&chip->reg_lock);
+	if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
+	    cmd == SNDRV_PCM_TRIGGER_STOP) {
+		int timeout = 5000;
+		while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
+			;
+	}
+	return err;
+}
+
+static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	unsigned int pos;
+
+#ifdef USE_POSBUF
+	/* use the position buffer */
+	pos = *azx_dev->posbuf;
+#else
+	/* read LPIB */
+	pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size;
+#endif
+	if (pos >= azx_dev->bufsize)
+		pos = 0;
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+static snd_pcm_ops_t azx_pcm_ops = {
+	.open = azx_pcm_open,
+	.close = azx_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = azx_pcm_hw_params,
+	.hw_free = azx_pcm_hw_free,
+	.prepare = azx_pcm_prepare,
+	.trigger = azx_pcm_trigger,
+	.pointer = azx_pcm_pointer,
+};
+
+static void azx_pcm_free(snd_pcm_t *pcm)
+{
+	kfree(pcm->private_data);
+}
+
+static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
+				      struct hda_pcm *cpcm, int pcm_dev)
+{
+	int err;
+	snd_pcm_t *pcm;
+	struct azx_pcm *apcm;
+
+	snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL);
+	snd_assert(cpcm->name, return -EINVAL);
+
+	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+			  cpcm->stream[0].substreams, cpcm->stream[1].substreams,
+			  &pcm);
+	if (err < 0)
+		return err;
+	strcpy(pcm->name, cpcm->name);
+	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
+	if (apcm == NULL)
+		return -ENOMEM;
+	apcm->chip = chip;
+	apcm->codec = codec;
+	apcm->hinfo[0] = &cpcm->stream[0];
+	apcm->hinfo[1] = &cpcm->stream[1];
+	pcm->private_data = apcm;
+	pcm->private_free = azx_pcm_free;
+	if (cpcm->stream[0].substreams)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
+	if (cpcm->stream[1].substreams)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci),
+					      1024 * 64, 1024 * 128);
+	chip->pcm[pcm_dev] = pcm;
+
+	return 0;
+}
+
+static int __devinit azx_pcm_create(azx_t *chip)
+{
+	struct list_head *p;
+	struct hda_codec *codec;
+	int c, err;
+	int pcm_dev;
+
+	if ((err = snd_hda_build_pcms(chip->bus)) < 0)
+		return err;
+
+	pcm_dev = 0;
+	list_for_each(p, &chip->bus->codec_list) {
+		codec = list_entry(p, struct hda_codec, list);
+		for (c = 0; c < codec->num_pcms; c++) {
+			if (pcm_dev >= AZX_MAX_PCMS) {
+				snd_printk(KERN_ERR SFX "Too many PCMs\n");
+				return -EINVAL;
+			}
+			err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
+			if (err < 0)
+				return err;
+			pcm_dev++;
+		}
+	}
+	return 0;
+}
+
+/*
+ * mixer creation - all stuff is implemented in hda module
+ */
+static int __devinit azx_mixer_create(azx_t *chip)
+{
+	return snd_hda_build_controls(chip->bus);
+}
+
+
+/*
+ * initialize SD streams
+ */
+static int __devinit azx_init_stream(azx_t *chip)
+{
+	int i;
+
+	/* initialize each stream (aka device)
+	 * assign the starting bdl address to each stream (device) and initialize
+	 */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_dev->bdl = (u32 *)(chip->bdl.area + off);
+		azx_dev->bdl_addr = chip->bdl.addr + off;
+#ifdef USE_POSBUF
+		azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
+#endif
+		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+		azx_dev->sd_int_sta_mask = 1 << i;
+		/* stream tag: must be non-zero and unique */
+		azx_dev->index = i;
+		azx_dev->stream_tag = i + 1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static int azx_suspend(snd_card_t *card, pm_message_t state)
+{
+	azx_t *chip = card->pm_private_data;
+	int i;
+
+	for (i = 0; i < chip->pcm_devs; i++)
+		if (chip->pcm[i])
+			snd_pcm_suspend_all(chip->pcm[i]);
+	snd_hda_suspend(chip->bus, state);
+	azx_free_cmd_io(chip);
+	pci_disable_device(chip->pci);
+	return 0;
+}
+
+static int azx_resume(snd_card_t *card)
+{
+	azx_t *chip = card->pm_private_data;
+
+	pci_enable_device(chip->pci);
+	pci_set_master(chip->pci);
+	azx_init_chip(chip);
+	snd_hda_resume(chip->bus);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+/*
+ * destructor
+ */
+static int azx_free(azx_t *chip)
+{
+	if (chip->remap_addr) {
+		int i;
+
+		for (i = 0; i < MAX_ICH6_DEV; i++)
+			azx_stream_stop(chip, &chip->azx_dev[i]);
+
+		/* disable interrupts */
+		azx_int_disable(chip);
+		azx_int_clear(chip);
+
+		/* disable CORB/RIRB */
+		azx_free_cmd_io(chip);
+
+		/* disable position buffer */
+		azx_writel(chip, DPLBASE, 0);
+		azx_writel(chip, DPUBASE, 0);
+
+		/* wait a little for interrupts to finish */
+		msleep(1);
+
+		iounmap(chip->remap_addr);
+	}
+
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void*)chip);
+
+	if (chip->bdl.area)
+		snd_dma_free_pages(&chip->bdl);
+	if (chip->rb.area)
+		snd_dma_free_pages(&chip->rb);
+#ifdef USE_POSBUF
+	if (chip->posbuf.area)
+		snd_dma_free_pages(&chip->posbuf);
+#endif
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+	kfree(chip);
+
+	return 0;
+}
+
+static int azx_dev_free(snd_device_t *device)
+{
+	return azx_free(device->device_data);
+}
+
+/*
+ * constructor
+ */
+static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip)
+{
+	azx_t *chip;
+	int err = 0;
+	static snd_device_ops_t ops = {
+		.dev_free = azx_dev_free,
+	};
+
+	*rchip = NULL;
+	
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+
+	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+	
+	if (NULL == chip) {
+		snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&chip->reg_lock);
+	init_MUTEX(&chip->open_mutex);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
+		kfree(chip);
+		pci_disable_device(pci);
+		return err;
+	}
+
+	chip->addr = pci_resource_start(pci,0);
+	chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0));
+	if (chip->remap_addr == NULL) {
+		snd_printk(KERN_ERR SFX "ioremap error\n");
+		err = -ENXIO;
+		goto errout;
+	}
+
+	if (request_irq(pci->irq, azx_interrupt, SA_INTERRUPT|SA_SHIRQ,
+			"HDA Intel", (void*)chip)) {
+		snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+		err = -EBUSY;
+		goto errout;
+	}
+	chip->irq = pci->irq;
+
+	pci_set_master(pci);
+	synchronize_irq(chip->irq);
+
+	/* allocate memory for the BDL for each stream */
+	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				       PAGE_SIZE, &chip->bdl)) < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
+		goto errout;
+	}
+#ifdef USE_POSBUF
+	/* allocate memory for the position buffer */
+	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				       MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
+		goto errout;
+	}
+#endif
+	/* allocate CORB/RIRB */
+	if ((err = azx_alloc_cmd_io(chip)) < 0)
+		goto errout;
+
+	/* initialize streams */
+	azx_init_stream(chip);
+
+	/* initialize chip */
+	azx_init_chip(chip);
+
+	/* codec detection */
+	if (! chip->codec_mask) {
+		snd_printk(KERN_ERR SFX "no codecs found!\n");
+		err = -ENODEV;
+		goto errout;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) {
+		snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+		goto errout;
+	}
+
+	*rchip = chip;
+	return 0;
+
+ errout:
+	azx_free(chip);
+	return err;
+}
+
+static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	azx_t *chip;
+	int err = 0;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (! enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (NULL == card) {
+		snd_printk(KERN_ERR SFX "Error creating card!\n");
+		return -ENOMEM;
+	}
+
+	if ((err = azx_create(card, pci, &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	strcpy(card->driver, "HDA-Intel");
+	strcpy(card->shortname, "HDA Intel");
+	sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+
+	/* create codec instances */
+	if ((err = azx_codec_create(chip, model[dev])) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* create PCM streams */
+	if ((err = azx_pcm_create(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* create mixer controls */
+	if ((err = azx_mixer_create(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	snd_card_set_pm_callback(card, azx_suspend, azx_resume, chip);
+	snd_card_set_dev(card, &pci->dev);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	pci_set_drvdata(pci, card);
+	dev++;
+
+	return err;
+}
+
+static void __devexit azx_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+/* PCI IDs */
+static struct pci_device_id azx_ids[] = {
+	{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
+	{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
+	{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, azx_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+	.name = "HDA Intel",
+	.id_table = azx_ids,
+	.probe = azx_probe,
+	.remove = __devexit_p(azx_remove),
+	SND_PCI_PM_CALLBACKS
+};
+
+static int __init alsa_card_azx_init(void)
+{
+	return pci_module_init(&driver);
+}
+
+static void __exit alsa_card_azx_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_azx_init)
+module_exit(alsa_card_azx_exit)
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_local.h
@@ -0,0 +1,161 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Local helper functions
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.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.
+ *
+ *  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 __SOUND_HDA_LOCAL_H
+#define __SOUND_HDA_LOCAL_H
+
+/*
+ * for mixer controls
+ */
+#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
+	  .info = snd_hda_mixer_amp_volume_info, \
+	  .get = snd_hda_mixer_amp_volume_get, \
+	  .put = snd_hda_mixer_amp_volume_put, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
+	  .info = snd_hda_mixer_amp_switch_info, \
+	  .get = snd_hda_mixer_amp_switch_get, \
+	  .put = snd_hda_mixer_amp_switch_put, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+#define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \
+	HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+#define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \
+	HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \
+	HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction)
+
+int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
+int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
+int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
+
+/*
+ * input MUX helper
+ */
+#define HDA_MAX_NUM_INPUTS	8
+struct hda_input_mux_item {
+	const char *label;
+	unsigned int index;
+};
+struct hda_input_mux {
+	unsigned int num_items;
+	struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS];
+};
+
+int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo);
+int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux,
+			  snd_ctl_elem_value_t *ucontrol, hda_nid_t nid,
+			  unsigned int *cur_val);
+
+/*
+ * Multi-channel / digital-out PCM helper
+ */
+
+enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */
+enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
+
+struct hda_multi_out {
+	int num_dacs;		/* # of DACs, must be more than 1 */
+	hda_nid_t *dac_nids;	/* DAC list */
+	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
+	hda_nid_t dig_out_nid;	/* digital out audio widget */
+	int max_channels;	/* currently supported analog channels */
+	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
+};
+
+int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout);
+int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout);
+int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
+				  snd_pcm_substream_t *substream);
+int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     snd_pcm_substream_t *substream);
+int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout);
+
+/*
+ * generic codec parser
+ */
+int snd_hda_parse_generic_codec(struct hda_codec *codec);
+
+/*
+ * generic proc interface
+ */
+#ifdef CONFIG_PROC_FS
+int snd_hda_codec_proc_new(struct hda_codec *codec);
+#else
+static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
+#endif
+
+/*
+ * Misc
+ */
+struct hda_board_config {
+	const char *modelname;
+	int config;
+	unsigned short pci_vendor;
+	unsigned short pci_device;
+};
+
+int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl);
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
+
+/*
+ * power management
+ */
+#ifdef CONFIG_PM
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
+int snd_hda_resume_spdif_out(struct hda_codec *codec);
+int snd_hda_resume_spdif_in(struct hda_codec *codec);
+#endif
+
+/*
+ * unsolicited event handler
+ */
+
+#define HDA_UNSOL_QUEUE_SIZE	64
+
+struct hda_bus_unsolicited {
+	/* ring buffer */
+	u32 queue[HDA_UNSOL_QUEUE_SIZE * 2];
+	unsigned int rp, wp;
+
+	/* workqueue */
+	struct workqueue_struct *workq;
+	struct work_struct work;
+};
+
+#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_patch.h
@@ -0,0 +1,17 @@
+/*
+ * HDA Patches - included by hda_codec.c
+ */
+
+/* Realtek codecs */
+extern struct hda_codec_preset snd_hda_preset_realtek[];
+/* C-Media codecs */
+extern struct hda_codec_preset snd_hda_preset_cmedia[];
+/* Analog Devices codecs */
+extern struct hda_codec_preset snd_hda_preset_analog[];
+
+static const struct hda_codec_preset *hda_preset_tables[] = {
+	snd_hda_preset_realtek,
+	snd_hda_preset_cmedia,
+	snd_hda_preset_analog,
+	NULL
+};
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/hda_proc.c
@@ -0,0 +1,298 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ * 
+ * Generic proc interface
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+
+static const char *get_wid_type_name(unsigned int wid_value)
+{
+	static char *names[16] = {
+		[AC_WID_AUD_OUT] = "Audio Output",
+		[AC_WID_AUD_IN] = "Audio Input",
+		[AC_WID_AUD_MIX] = "Audio Mixer",
+		[AC_WID_AUD_SEL] = "Audio Selector",
+		[AC_WID_PIN] = "Pin Complex",
+		[AC_WID_POWER] = "Power Widget",
+		[AC_WID_VOL_KNB] = "Volume Knob Widget",
+		[AC_WID_BEEP] = "Beep Generator Widget",
+		[AC_WID_VENDOR] = "Vendor Defined Widget",
+	};
+	wid_value &= 0xf;
+	if (names[wid_value])
+		return names[wid_value];
+	else
+		return "UNKOWN Widget";
+}
+
+static void print_amp_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+	unsigned int caps;
+	if (dir == HDA_OUTPUT)
+		caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
+	else
+		caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP);
+	if (caps == -1 || caps == 0) {
+		snd_iprintf(buffer, "N/A\n");
+		return;
+	}
+	snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n",
+		    caps & AC_AMPCAP_OFFSET,
+		    (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
+		    (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
+		    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
+}
+
+static void print_amp_vals(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int dir, int stereo)
+{
+	unsigned int val;
+	if (stereo) {
+		val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
+					  AC_AMP_GET_LEFT |
+					 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
+					  AC_AMP_GET_INPUT));
+		snd_iprintf(buffer, "0x%02x ", val);
+	}
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
+				 AC_AMP_GET_RIGHT |
+				 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
+				  AC_AMP_GET_INPUT));
+	snd_iprintf(buffer, "0x%02x\n", val);
+}
+
+static void print_pcm_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+	unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (pcm == -1 || stream == -1) {
+		snd_iprintf(buffer, "N/A\n");
+		return;
+	}
+	snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n",
+		    pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf);
+}
+
+static const char *get_jack_location(u32 cfg)
+{
+	static char *bases[7] = {
+		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
+	};
+	static unsigned char specials_idx[] = {
+		0x07, 0x08,
+		0x17, 0x18, 0x19,
+		0x37, 0x38
+	};
+	static char *specials[] = {
+		"Rear Panel", "Drive Bar",
+		"Riser", "HDMI", "ATAPI",
+		"Mobile-In", "Mobile-Out"
+	};
+	int i;
+	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
+	if ((cfg & 0x0f) < 7)
+		return bases[cfg & 0x0f];
+	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
+		if (cfg == specials_idx[i])
+			return specials[i];
+	}
+	return "UNKNOWN";
+}
+
+static const char *get_jack_connection(u32 cfg)
+{
+	static char *names[16] = {
+		"Unknown", "1/8", "1/4", "ATAPI",
+		"RCA", "Optical","Digital", "Analog",
+		"DIN", "XLR", "RJ11", "Comb",
+		NULL, NULL, NULL, "Other"
+	};
+	cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
+	if (names[cfg])
+		return names[cfg];
+	else
+		return "UNKNOWN";
+}
+
+static const char *get_jack_color(u32 cfg)
+{
+	static char *names[16] = {
+		"Unknown", "Black", "Grey", "Blue",
+		"Green", "Red", "Orange", "Yellow",
+		"Purple", "Pink", NULL, NULL,
+		NULL, NULL, "White", "Other",
+	};
+	cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
+	if (names[cfg])
+		return names[cfg];
+	else
+		return "UNKNOWN";
+}
+
+static void print_pin_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	static char *jack_types[16] = {
+		"Line Out", "Speaker", "HP Out", "CD",
+		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
+		"Line In", "Aux", "Mic", "Telephony",
+		"SPDIF In", "Digitial In", "Reserved", "Other"
+	};
+	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
+	unsigned int caps;
+
+	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+	snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
+	if (caps & AC_PINCAP_IN)
+		snd_iprintf(buffer, " IN");
+	if (caps & AC_PINCAP_OUT)
+		snd_iprintf(buffer, " OUT");
+	if (caps & AC_PINCAP_HP_DRV)
+		snd_iprintf(buffer, " HP");
+	snd_iprintf(buffer, "\n");
+	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+	snd_iprintf(buffer, "  Pin Default 0x%08x: %s at %s %s\n", caps,
+		    jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
+		    jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
+		    get_jack_location(caps));
+	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
+		    get_jack_connection(caps),
+		    get_jack_color(caps));
+}
+
+
+static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	struct hda_codec *codec = entry->private_data;
+	char buf[32];
+	hda_nid_t nid;
+	int i, nodes;
+
+	snd_hda_get_codec_name(codec, buf, sizeof(buf));
+	snd_iprintf(buffer, "Codec: %s\n", buf);
+	snd_iprintf(buffer, "Address: %d\n", codec->addr);
+	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
+	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
+	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+	snd_iprintf(buffer, "Default PCM: ");
+	print_pcm_caps(buffer, codec, codec->afg);
+	snd_iprintf(buffer, "Default Amp-In caps: ");
+	print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
+	snd_iprintf(buffer, "Default Amp-Out caps: ");
+	print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
+
+	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	if (! nid || nodes < 0) {
+		snd_iprintf(buffer, "Invalid AFG subtree\n");
+		return;
+	}
+	for (i = 0; i < nodes; i++, nid++) {
+		unsigned int wid_caps = snd_hda_param_read(codec, nid,
+							   AC_PAR_AUDIO_WIDGET_CAP);
+		unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
+			    get_wid_type_name(wid_type), wid_caps);
+		if (wid_caps & AC_WCAP_STEREO)
+			snd_iprintf(buffer, " Stereo");
+		else
+			snd_iprintf(buffer, " Mono");
+		if (wid_caps & AC_WCAP_DIGITAL)
+			snd_iprintf(buffer, " Digital");
+		if (wid_caps & AC_WCAP_IN_AMP)
+			snd_iprintf(buffer, " Amp-In");
+		if (wid_caps & AC_WCAP_OUT_AMP)
+			snd_iprintf(buffer, " Amp-Out");
+		snd_iprintf(buffer, "\n");
+
+		if (wid_caps & AC_WCAP_IN_AMP) {
+			snd_iprintf(buffer, "  Amp-In caps: ");
+			print_amp_caps(buffer, codec, nid, HDA_INPUT);
+			snd_iprintf(buffer, "  Amp-In vals: ");
+			print_amp_vals(buffer, codec, nid, HDA_INPUT,
+				       wid_caps & AC_WCAP_STEREO);
+		}
+		if (wid_caps & AC_WCAP_OUT_AMP) {
+			snd_iprintf(buffer, "  Amp-Out caps: ");
+			print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
+			snd_iprintf(buffer, "  Amp-Out vals: ");
+			print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+				       wid_caps & AC_WCAP_STEREO);
+		}
+
+		if (wid_type == AC_WID_PIN) {
+			unsigned int pinctls;
+			print_pin_caps(buffer, codec, nid);
+			pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
+			if (pinctls & AC_PINCTL_IN_EN)
+				snd_iprintf(buffer, " IN");
+			if (pinctls & AC_PINCTL_OUT_EN)
+				snd_iprintf(buffer, " OUT");
+			if (pinctls & AC_PINCTL_HP_EN)
+				snd_iprintf(buffer, " HP");
+			snd_iprintf(buffer, "\n");
+		}
+
+		if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
+		    (wid_caps & AC_WCAP_FORMAT_OVRD)) {
+			snd_iprintf(buffer, "  PCM: ");
+			print_pcm_caps(buffer, codec, nid);
+		}
+
+		if (wid_caps & AC_WCAP_CONN_LIST) {
+			hda_nid_t conn[HDA_MAX_CONNECTIONS];
+			int c, conn_len;
+			conn_len = snd_hda_get_connections(codec, nid, conn,
+							   HDA_MAX_CONNECTIONS);
+			snd_iprintf(buffer, "  Connection: %d\n", conn_len);
+			snd_iprintf(buffer, "    ");
+			for (c = 0; c < conn_len; c++)
+				snd_iprintf(buffer, " 0x%02x", conn[c]);
+			snd_iprintf(buffer, "\n");
+		}
+	}
+}
+
+/*
+ * create a proc read
+ */
+int snd_hda_codec_proc_new(struct hda_codec *codec)
+{
+	char name[32];
+	snd_info_entry_t *entry;
+	int err;
+
+	snprintf(name, sizeof(name), "codec#%d", codec->addr);
+	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);
+	return 0;
+}
+
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/patch_analog.c
@@ -0,0 +1,445 @@
+/*
+ * HD audio interface patch for AD1986A
+ *
+ * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+struct ad1986a_spec {
+	struct semaphore amp_mutex;	/* PCM volume/mute control mutex */
+	struct hda_multi_out multiout;	/* playback */
+	unsigned int cur_mux;		/* capture source */
+	struct hda_pcm pcm_rec[2];	/* PCM information */
+};
+
+#define AD1986A_SPDIF_OUT	0x02
+#define AD1986A_FRONT_DAC	0x03
+#define AD1986A_SURR_DAC	0x04
+#define AD1986A_CLFE_DAC	0x05
+#define AD1986A_ADC		0x06
+
+static hda_nid_t ad1986a_dac_nids[3] = {
+	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
+};
+
+static struct hda_input_mux ad1986a_capture_source = {
+	.num_items = 7,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "CD", 0x1 },
+		{ "Aux", 0x3 },
+		{ "Line", 0x4 },
+		{ "Mix", 0x5 },
+		{ "Mono", 0x6 },
+		{ "Phone", 0x7 },
+	},
+};
+
+/*
+ * PCM control
+ *
+ * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
+ */
+
+#define ad1986a_pcm_amp_vol_info	snd_hda_mixer_amp_volume_info
+
+static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *ad = codec->spec;
+
+	down(&ad->amp_mutex);
+	snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
+	up(&ad->amp_mutex);
+	return 0;
+}
+
+static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *ad = codec->spec;
+	int i, change = 0;
+
+	down(&ad->amp_mutex);
+	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
+		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
+		change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+	}
+	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
+	up(&ad->amp_mutex);
+	return change;
+}
+
+#define ad1986a_pcm_amp_sw_info		snd_hda_mixer_amp_volume_info
+
+static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *ad = codec->spec;
+
+	down(&ad->amp_mutex);
+	snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
+	up(&ad->amp_mutex);
+	return 0;
+}
+
+static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *ad = codec->spec;
+	int i, change = 0;
+
+	down(&ad->amp_mutex);
+	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
+		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
+		change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+	}
+	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
+	up(&ad->amp_mutex);
+	return change;
+}
+
+/*
+ * input MUX handling
+ */
+static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo);
+}
+
+static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux;
+	return 0;
+}
+
+static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad1986a_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol,
+				     AD1986A_ADC, &spec->cur_mux);
+}
+
+/*
+ * mixers
+ */
+static snd_kcontrol_new_t ad1986a_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "PCM Playback Volume",
+		.info = ad1986a_pcm_amp_vol_info,
+		.get = ad1986a_pcm_amp_vol_get,
+		.put = ad1986a_pcm_amp_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "PCM Playback Switch",
+		.info = ad1986a_pcm_amp_sw_info,
+		.get = ad1986a_pcm_amp_sw_get,
+		.put = ad1986a_pcm_amp_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
+	},
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad1986a_mux_enum_info,
+		.get = ad1986a_mux_enum_get,
+		.put = ad1986a_mux_enum_put,
+	},
+	HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1986a_init_verbs[] = {
+	/* Front, Surround, CLFE DAC; mute as default */
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* Downmix - off */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* HP, Line-Out, Surround, CLFE selectors */
+	{0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Mono selector */
+	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Mic selector: Mic 1/2 pin */
+	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Line-in selector: Line-in */
+	{0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Mic 1/2 swap */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Record selector: mic */
+	{0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Mic, Phone, CD, Aux, Line-In amp; mute as default */
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* PC beep */
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{ } /* end */
+};
+
+
+static int ad1986a_init(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, ad1986a_init_verbs);
+	return 0;
+}
+
+static int ad1986a_build_controls(struct hda_codec *codec)
+{
+	int err;
+
+	err = snd_hda_add_new_ctls(codec, ad1986a_mixers);
+	if (err < 0)
+		return err;
+	err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * Analog playback callbacks
+ */
+static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     snd_pcm_substream_t *substream)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int ad1986a_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					snd_pcm_substream_t *substream)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+						format, substream);
+}
+
+static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					snd_pcm_substream_t *substream)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 snd_pcm_substream_t *substream)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					  struct hda_codec *codec,
+					  snd_pcm_substream_t *substream)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format);
+	return 0;
+}
+
+static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0);
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream ad1986a_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 6,
+	.nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */
+	.ops = {
+		.open = ad1986a_playback_pcm_open,
+		.prepare = ad1986a_playback_pcm_prepare,
+		.cleanup = ad1986a_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream ad1986a_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = AD1986A_ADC, /* NID to query formats and rates */
+	.ops = {
+		.prepare = ad1986a_capture_pcm_prepare,
+		.cleanup = ad1986a_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream ad1986a_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = AD1986A_SPDIF_OUT, 
+	.ops = {
+		.open = ad1986a_dig_playback_pcm_open,
+		.close = ad1986a_dig_playback_pcm_close
+	},
+};
+
+static int ad1986a_build_pcms(struct hda_codec *codec)
+{
+	struct ad1986a_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 2;
+	codec->pcm_info = info;
+
+	info->name = "AD1986A Analog";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture;
+	info++;
+
+	info->name = "AD1986A Digital";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback;
+
+	return 0;
+}
+
+static void ad1986a_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+#ifdef CONFIG_PM
+static int ad1986a_resume(struct hda_codec *codec)
+{
+	ad1986a_init(codec);
+	snd_hda_resume_ctls(codec, ad1986a_mixers);
+	snd_hda_resume_spdif_out(codec);
+	return 0;
+}
+#endif
+
+static struct hda_codec_ops ad1986a_patch_ops = {
+	.build_controls = ad1986a_build_controls,
+	.build_pcms = ad1986a_build_pcms,
+	.init = ad1986a_init,
+	.free = ad1986a_free,
+#ifdef CONFIG_PM
+	.resume = ad1986a_resume,
+#endif
+};
+
+static int patch_ad1986a(struct hda_codec *codec)
+{
+	struct ad1986a_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	init_MUTEX(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 6;
+	spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
+	spec->multiout.dac_nids = ad1986a_dac_nids;
+	spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
+
+	codec->patch_ops = ad1986a_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_analog[] = {
+	{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
+	{} /* terminator */
+};
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/patch_cmedia.c
@@ -0,0 +1,621 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for C-Media CMI9880
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* board config type */
+enum {
+	CMI_MINIMAL,	/* back 3-jack */
+	CMI_MIN_FP,	/* back 3-jack + front-panel 2-jack */
+	CMI_FULL,	/* back 6-jack + front-panel 2-jack */
+	CMI_FULL_DIG,	/* back 6-jack + front-panel 2-jack + digital I/O */
+	CMI_ALLOUT,	/* back 5-jack + front-panel 2-jack + digital out */
+};
+
+struct cmi_spec {
+	int board_config;
+	unsigned int surr_switch: 1;	/* switchable line,mic */
+	unsigned int no_line_in: 1;	/* no line-in (5-jack) */
+	unsigned int front_panel: 1;	/* has front-panel 2-jack */
+
+	/* playback */
+	struct hda_multi_out multiout;
+
+	/* capture */
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	unsigned int cur_mux[2];
+
+	/* channel mode */
+	unsigned int num_ch_modes;
+	unsigned int cur_ch_mode;
+	const struct cmi_channel_mode *channel_modes;
+
+	struct hda_pcm pcm_rec[2];	/* PCM information */
+};
+
+/*
+ * input MUX
+ */
+static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+				     spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+/*
+ * shared line-in, mic for surrounds
+ */
+
+/* 3-stack / 2 channel */
+static struct hda_verb cmi9880_ch2_init[] = {
+	/* set line-in PIN for input */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* set mic PIN for input, also enable vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* route front PCM (DAC1) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{}
+};
+
+/* 3-stack / 6 channel */
+static struct hda_verb cmi9880_ch6_init[] = {
+	/* set line-in PIN for output */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set mic PIN for output */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* route front PCM (DAC1) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{}
+};
+
+/* 3-stack+front / 8 channel */
+static struct hda_verb cmi9880_ch8_init[] = {
+	/* set line-in PIN for output */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set mic PIN for output */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* route rear-surround PCM (DAC4) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
+	{}
+};
+
+struct cmi_channel_mode {
+	unsigned int channels;
+	const struct hda_verb *sequence;
+};
+
+static struct cmi_channel_mode cmi9880_channel_modes[3] = {
+	{ 2, cmi9880_ch2_init },
+	{ 6, cmi9880_ch6_init },
+	{ 8, cmi9880_ch8_init },
+};
+
+static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_modes, return -EINVAL);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = spec->num_ch_modes;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		spec->channel_modes[uinfo->value.enumerated.item].channels);
+	return 0;
+}
+
+static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
+	return 0;
+}
+
+static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_modes, return -EINVAL);
+	if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
+		ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
+	if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
+	    ! codec->in_resume)
+		return 0;
+
+	spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
+	snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence);
+	spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels;
+	return 1;
+}
+
+/*
+ */
+static snd_kcontrol_new_t cmi9880_basic_mixer[] = {
+	/* CMI9880 has no playback volumes! */
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = cmi_mux_enum_info,
+		.get = cmi_mux_enum_get,
+		.put = cmi_mux_enum_put,
+	},
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+/*
+ * shared I/O pins
+ */
+static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = cmi_ch_mode_info,
+		.get = cmi_ch_mode_get,
+		.put = cmi_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+/* AUD-in selections:
+ * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
+ */
+static struct hda_input_mux cmi9880_basic_mux = {
+	.num_items = 4,
+	.items = {
+		{ "Front Mic", 0x5 },
+		{ "Rear Mic", 0x2 },
+		{ "Line", 0x1 },
+		{ "CD", 0x7 },
+	}
+};
+
+static struct hda_input_mux cmi9880_no_line_mux = {
+	.num_items = 3,
+	.items = {
+		{ "Front Mic", 0x5 },
+		{ "Rear Mic", 0x2 },
+		{ "CD", 0x7 },
+	}
+};
+
+/* front, rear, clfe, rear_surr */
+static hda_nid_t cmi9880_dac_nids[4] = {
+	0x03, 0x04, 0x05, 0x06
+};
+/* ADC0, ADC1 */
+static hda_nid_t cmi9880_adc_nids[2] = {
+	0x08, 0x09
+};
+
+#define CMI_DIG_OUT_NID	0x07
+#define CMI_DIG_IN_NID	0x0a
+
+/*
+ */
+static struct hda_verb cmi9880_basic_init[] = {
+	/* port-D for line out (rear panel) */
+	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-E for HP out (front panel) */
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* route front PCM to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-A for surround (rear panel) */
+	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-G for CLFE (rear panel) */
+	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-H for side (rear panel) */
+	{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-C for line-in (rear panel) */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* port-B for mic-in (rear panel) with vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-F for mic-in (front panel) with vref */
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* CD-in */
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* route front mic to ADC1/2 */
+	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{} /* terminator */
+};
+
+static struct hda_verb cmi9880_allout_init[] = {
+	/* port-D for line out (rear panel) */
+	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-E for HP out (front panel) */
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* route front PCM to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-A for side (rear panel) */
+	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-G for CLFE (rear panel) */
+	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-C for surround (rear panel) */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-B for mic-in (rear panel) with vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-F for mic-in (front panel) with vref */
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* CD-in */
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* route front mic to ADC1/2 */
+	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{} /* terminator */
+};
+
+/*
+ */
+static int cmi9880_build_controls(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
+	if (err < 0)
+		return err;
+	if (spec->surr_switch) {
+		err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
+		if (err < 0)
+			return err;
+	}
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	}
+	if (spec->dig_in_nid) {
+		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int cmi9880_init(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	if (spec->board_config == CMI_ALLOUT)
+		snd_hda_sequence_write(codec, cmi9880_allout_init);
+	else
+		snd_hda_sequence_write(codec, cmi9880_basic_init);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int cmi9880_resume(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cmi9880_init(codec);
+	snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
+	if (spec->surr_switch)
+		snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+	if (spec->dig_in_nid)
+		snd_hda_resume_spdif_in(codec);
+
+	return 0;
+}
+#endif
+
+/*
+ * Analog playback callbacks
+ */
+static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+						format, substream);
+}
+
+static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					  struct hda_codec *codec,
+					  snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x03, /* NID to query formats and rates */
+	.ops = {
+		.open = cmi9880_playback_pcm_open,
+		.prepare = cmi9880_playback_pcm_prepare,
+		.cleanup = cmi9880_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x08, /* NID to query formats and rates */
+	.ops = {
+		.prepare = cmi9880_capture_pcm_prepare,
+		.cleanup = cmi9880_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in cmi9880_build_pcms */
+	.ops = {
+		.open = cmi9880_dig_playback_pcm_open,
+		.close = cmi9880_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in cmi9880_build_pcms */
+};
+
+static int cmi9880_build_pcms(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "CMI9880";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture;
+
+	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = "CMI9880 Digital";
+		if (spec->multiout.dig_out_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+		}
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static void cmi9880_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+/*
+ */
+
+static struct hda_board_config cmi9880_cfg_tbl[] = {
+	{ .modelname = "minimal", .config = CMI_MINIMAL },
+	{ .modelname = "min_fp", .config = CMI_MIN_FP },
+	{ .modelname = "full", .config = CMI_FULL },
+	{ .modelname = "full_dig", .config = CMI_FULL_DIG },
+	{ .modelname = "allout", .config = CMI_ALLOUT },
+	{} /* terminator */
+};
+
+static struct hda_codec_ops cmi9880_patch_ops = {
+	.build_controls = cmi9880_build_controls,
+	.build_pcms = cmi9880_build_pcms,
+	.init = cmi9880_init,
+	.free = cmi9880_free,
+#ifdef CONFIG_PM
+	.resume = cmi9880_resume,
+#endif
+};
+
+static int patch_cmi9880(struct hda_codec *codec)
+{
+	struct cmi_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+	if (spec->board_config < 0) {
+		snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+		spec->board_config = CMI_FULL_DIG; /* try everything */
+	}
+
+	switch (spec->board_config) {
+	case CMI_MINIMAL:
+	case CMI_MIN_FP:
+		spec->surr_switch = 1;
+		if (spec->board_config == CMI_MINIMAL)
+			spec->num_ch_modes = 2;
+		else {
+			spec->front_panel = 1;
+			spec->num_ch_modes = 3;
+		}
+		spec->channel_modes = cmi9880_channel_modes;
+		spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
+		spec->input_mux = &cmi9880_basic_mux;
+		break;
+	case CMI_FULL:
+	case CMI_FULL_DIG:
+		spec->front_panel = 1;
+		spec->multiout.max_channels = 8;
+		spec->input_mux = &cmi9880_basic_mux;
+		if (spec->board_config == CMI_FULL_DIG) {
+			spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+			spec->dig_in_nid = CMI_DIG_IN_NID;
+		}
+		break;
+	case CMI_ALLOUT:
+		spec->front_panel = 1;
+		spec->multiout.max_channels = 8;
+		spec->no_line_in = 1;
+		spec->input_mux = &cmi9880_no_line_mux;
+		spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+		break;
+	}
+
+	spec->multiout.num_dacs = 4;
+	spec->multiout.dac_nids = cmi9880_dac_nids;
+
+	spec->adc_nids = cmi9880_adc_nids;
+
+	codec->patch_ops = cmi9880_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_cmedia[] = {
+	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
+ 	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
+	{} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/hda/patch_realtek.c
@@ -0,0 +1,1503 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for ALC 260/880/882 codecs
+ *
+ * Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver is free software; you can redistribute it 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* ALC880 board config type */
+enum {
+	ALC880_MINIMAL,
+	ALC880_3ST,
+	ALC880_3ST_DIG,
+	ALC880_5ST,
+	ALC880_5ST_DIG,
+	ALC880_W810,
+};
+
+struct alc_spec {
+	/* codec parameterization */
+	unsigned int front_panel: 1;
+
+	snd_kcontrol_new_t* mixers[2];
+	unsigned int num_mixers;
+
+	struct hda_verb *init_verbs;
+
+	char* stream_name_analog;
+	struct hda_pcm_stream *stream_analog_playback;
+	struct hda_pcm_stream *stream_analog_capture;
+
+	char* stream_name_digital;
+	struct hda_pcm_stream *stream_digital_playback;
+	struct hda_pcm_stream *stream_digital_capture;
+
+	/* playback */
+	struct hda_multi_out multiout;
+
+	/* capture */
+	unsigned int num_adc_nids;
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	unsigned int cur_mux[3];
+
+	/* channel model */
+	const struct alc_channel_mode *channel_mode;
+	int num_channel_mode;
+
+	/* PCM information */
+	struct hda_pcm pcm_rec[2];
+};
+
+/* DAC/ADC assignment */
+
+static hda_nid_t alc880_dac_nids[4] = {
+	/* front, rear, clfe, rear_surr */
+	0x02, 0x05, 0x04, 0x03
+};
+
+static hda_nid_t alc880_w810_dac_nids[3] = {
+	/* front, rear/surround, clfe */
+	0x02, 0x03, 0x04
+};
+
+static hda_nid_t alc880_adc_nids[3] = {
+	/* ADC0-2 */
+	0x07, 0x08, 0x09,
+};
+
+#define ALC880_DIGOUT_NID	0x06
+#define ALC880_DIGIN_NID	0x0a
+
+static hda_nid_t alc260_dac_nids[1] = {
+	/* front */
+	0x02,
+};
+
+static hda_nid_t alc260_adc_nids[2] = {
+	/* ADC0-1 */
+	0x04, 0x05,
+};
+
+#define ALC260_DIGOUT_NID	0x03
+#define ALC260_DIGIN_NID	0x06
+
+static struct hda_input_mux alc880_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x3 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+static struct hda_input_mux alc260_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x1 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+/*
+ * input MUX handling
+ */
+static int alc_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+				     spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+/*
+ * channel mode setting
+ */
+struct alc_channel_mode {
+	int channels;
+	const struct hda_verb *sequence;
+};
+
+
+/*
+ * channel source setting (2/6 channel selection for 3-stack)
+ */
+
+/*
+ * set the path ways for 2 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc880_threestack_ch2_init[] = {
+	/* set pin widget 1Ah (line in) for input */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* set pin widget 18h (mic1) for input, for mic also enable the vref */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* mute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	/* mute for Mic1 PW */
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	{ } /* end */
+};
+
+/*
+ * 6ch mode
+ * need to set the codec line out and mic 1 pin widgets to outputs
+ */
+static struct hda_verb alc880_threestack_ch6_init[] = {
+	/* set pin widget 1Ah (line in) for output */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set pin widget 18h (mic1) for output */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* unmute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* unmute for Mic1 PW */
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* for rear channel output using Line In 1
+	 * set select widget connection (nid = 0x12) - to summer node
+	 * for rear NID = 0x0f...offset 3 in connection list
+	 */
+	{ 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 },
+	/* for Mic1 - retask for center/lfe */
+	/* set select widget connection (nid = 0x10) - to summer node for
+	 * front CLFE NID = 0x0e...offset 2 in connection list
+	 */
+	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 },
+	{ } /* end */
+};
+
+static struct alc_channel_mode alc880_threestack_modes[2] = {
+	{ 2, alc880_threestack_ch2_init },
+	{ 6, alc880_threestack_ch6_init },
+};
+
+
+/*
+ * channel source setting (6/8 channel selection for 5-stack)
+ */
+
+/* set the path ways for 6 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc880_fivestack_ch6_init[] = {
+	/* set pin widget 1Ah (line in) for input */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* mute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	{ } /* end */
+};
+
+/* need to set the codec line out and mic 1 pin widgets to outputs */
+static struct hda_verb alc880_fivestack_ch8_init[] = {
+	/* set pin widget 1Ah (line in) for output */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* unmute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* output for surround channel output using Line In 1 */
+	/* set select widget connection (nid = 0x12) - to summer node
+	 * for surr_rear NID = 0x0d...offset 1 in connection list
+	 */
+	{ 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 },
+	{ } /* end */
+};
+
+static struct alc_channel_mode alc880_fivestack_modes[2] = {
+	{ 6, alc880_fivestack_ch6_init },
+	{ 8, alc880_fivestack_ch8_init },
+};
+
+/*
+ * channel source setting for W810 system
+ *
+ * W810 has rear IO for:
+ * Front (DAC 02)
+ * Surround (DAC 03)
+ * Center/LFE (DAC 04)
+ * Digital out (06)
+ *
+ * The system also has a pair of internal speakers, and a headphone jack.
+ * These are both connected to Line2 on the codec, hence to DAC 02.
+ * 
+ * There is a variable resistor to control the speaker or headphone
+ * volume. This is a hardware-only device without a software API.
+ *
+ * Plugging headphones in will disable the internal speakers. This is
+ * implemented in hardware, not via the driver using jack sense. In
+ * a similar fashion, plugging into the rear socket marked "front" will
+ * disable both the speakers and headphones.
+ *
+ * For input, there's a microphone jack, and an "audio in" jack.
+ * These may not do anything useful with this driver yet, because I
+ * haven't setup any initialization verbs for these yet...
+ */
+
+static struct alc_channel_mode alc880_w810_modes[1] = {
+	{ 6, NULL }
+};
+
+/*
+ */
+static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item >= 2)
+		uinfo->value.enumerated.item = 1;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		spec->channel_mode[uinfo->value.enumerated.item].channels);
+	return 0;
+}
+
+static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	ucontrol->value.enumerated.item[0] =
+		(spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1;
+	return 0;
+}
+
+static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int mode;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	mode = ucontrol->value.enumerated.item[0] ? 1 : 0;
+	if (spec->multiout.max_channels == spec->channel_mode[mode].channels &&
+	    ! codec->in_resume)
+		return 0;
+
+	/* change the current channel setting */
+	spec->multiout.max_channels = spec->channel_mode[mode].channels;
+	if (spec->channel_mode[mode].sequence)
+		snd_hda_sequence_write(codec, spec->channel_mode[mode].sequence);
+
+	return 1;
+}
+
+
+/*
+ */
+
+/* 3-stack mode
+ * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b
+ *                 HP=0x19
+ */
+static snd_kcontrol_new_t alc880_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc880_ch_mode_info,
+		.get = alc880_ch_mode_get,
+		.put = alc880_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+/* 5-stack mode
+ * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16
+ *                 Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19
+ */
+static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc880_ch_mode_info,
+		.get = alc880_ch_mode_get,
+		.put = alc880_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 3,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/*
+ */
+static int alc_build_controls(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	int i;
+
+	for (i = 0; i < spec->num_mixers; i++) {
+		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	}
+	if (spec->dig_in_nid) {
+		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/*
+ * initialize the codec volumes, etc
+ */
+
+static struct hda_verb alc880_init_verbs_three_stack[] = {
+	/* Line In pin widget for input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* unmute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute front mixer amp left (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute rear mixer amp left and right (volume = 0) */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute rear mixer amp left and right (volume = 0) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+	/* using rear surround as the path for headphone output */
+	/* unmute rear surround mixer amp left and right (volume = 0) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* PASD 3 stack boards use the Mic 2 as the headphone output */
+	/* need to program the selector associated with the Mic 2 pin widget to
+	 * surround path (index 0x01) for headphone output */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* need to retask the Mic 2 pin widget to output */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B)
+	 * to support the input path of analog loopback
+	 * Note: PASD motherboards uses the Line In 2 as the input for front panel
+	 * mic (mic 2)
+	 */
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
+	/* unmute CD */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic 1 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* unmute Line In 2 (for PASD boards Mic 2) */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+	/* Unmute input amps for the line out paths to support the output path of
+	 * analog loopback
+	 * the mixers on the output path has 2 inputs, one from the DAC and one
+	 * from the mixer
+	 */
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Surround (used as HP) out path */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute C/LFE out path */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */
+	/* Unmute rear Surround out path */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{ }
+};
+
+static struct hda_verb alc880_init_verbs_five_stack[] = {
+	/* Line In pin widget for input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* unmute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute front mixer amp left and right (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* five rear and clfe */
+	/* unmute rear mixer amp left and right (volume = 0)  */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute clfe mixer amp left and right (volume = 0) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+	/* using rear surround as the path for headphone output */
+	/* unmute rear surround mixer amp left and right (volume = 0) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* PASD 3 stack boards use the Mic 2 as the headphone output */
+	/* need to program the selector associated with the Mic 2 pin widget to
+	 * surround path (index 0x01) for headphone output
+	 */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* need to retask the Mic 2 pin widget to output */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer
+	 * widget(nid=0x0B) to support the input path of analog loopback
+	 */
+	/* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/
+	/* unmute CD */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic 1 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* unmute Line In 2 (for PASD boards Mic 2) */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+	/* Unmute input amps for the line out paths to support the output path of
+	 * analog loopback
+	 * the mixers on the output path has 2 inputs, one from the DAC and
+	 * one from the mixer
+	 */
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Surround (used as HP) out path */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute C/LFE out path */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */
+	/* Unmute rear Surround out path */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{ }
+};
+
+static struct hda_verb alc880_w810_init_verbs[] = {
+	/* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* front channel selector/amp: output 0: unmuted, max volume */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* front out pin: muted, (no volume selection)  */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* front out pin: NOT headphone enable, out enable, vref disabled */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* surround channel selector/amp: output 0: unmuted, max volume */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* surround out pin: muted, (no volume selection)  */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* surround out pin: NOT headphone enable, out enable, vref disabled */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* c/lfe channel selector/amp: output 0: unmuted, max volume */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* c/lfe out pin: muted, (no volume selection)  */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* c/lfe out pin: NOT headphone enable, out enable, vref disabled */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* hphone/speaker input selector: front DAC */
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+	/* hphone/speaker out pin: muted, (no volume selection)  */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	{ }
+};
+
+static int alc_init(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	snd_hda_sequence_write(codec, spec->init_verbs);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int alc_resume(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	alc_init(codec);
+	for (i = 0; i < spec->num_mixers; i++) {
+		snd_hda_resume_ctls(codec, spec->mixers[i]);
+	}
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+	if (spec->dig_in_nid)
+		snd_hda_resume_spdif_in(codec);
+
+	return 0;
+}
+#endif
+
+/*
+ * Analog playback callbacks
+ */
+static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+						format, substream);
+}
+
+static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream alc880_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x02, /* NID to query formats and rates */
+	.ops = {
+		.open = alc880_playback_pcm_open,
+		.prepare = alc880_playback_pcm_prepare,
+		.cleanup = alc880_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x07, /* NID to query formats and rates */
+	.ops = {
+		.prepare = alc880_capture_pcm_prepare,
+		.cleanup = alc880_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+	.ops = {
+		.open = alc880_dig_playback_pcm_open,
+		.close = alc880_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static int alc_build_pcms(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+	int i;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = spec->stream_name_analog;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
+	for (i = 0; i < spec->num_channel_mode; i++) {
+		if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
+		    info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
+		}
+	}
+
+	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = spec->stream_name_digital;
+		if (spec->multiout.dig_out_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+		}
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static void alc_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+/*
+ */
+static struct hda_codec_ops alc_patch_ops = {
+	.build_controls = alc_build_controls,
+	.build_pcms = alc_build_pcms,
+	.init = alc_init,
+	.free = alc_free,
+#ifdef CONFIG_PM
+	.resume = alc_resume,
+#endif
+};
+
+/*
+ */
+
+static struct hda_board_config alc880_cfg_tbl[] = {
+	/* Back 3 jack, front 2 jack */
+	{ .modelname = "3stack", .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST },
+
+	/* Back 3 jack, front 2 jack (Internal add Aux-In) */
+	{ .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST },
+
+	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
+	{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG },
+
+	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
+	{ .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG },
+
+	/* Back 5 jack, front 2 jack */
+	{ .modelname = "5stack", .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST },
+	{ .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST },
+
+	/* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
+	{ .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG },
+
+	{ .modelname = "w810", .config = ALC880_W810 },
+	{ .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 },
+
+	{}
+};
+
+static int patch_alc880(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int board_config;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
+	if (board_config < 0) {
+		snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n");
+		board_config = ALC880_MINIMAL;
+	}
+
+	switch (board_config) {
+	case ALC880_W810:
+		spec->mixers[spec->num_mixers] = alc880_w810_base_mixer;
+		spec->num_mixers++;
+		break;
+	case ALC880_5ST:
+	case ALC880_5ST_DIG:
+		spec->mixers[spec->num_mixers] = alc880_five_stack_mixer;
+		spec->num_mixers++;
+		break;
+	default:
+		spec->mixers[spec->num_mixers] = alc880_base_mixer;
+		spec->num_mixers++;
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_3ST_DIG:
+	case ALC880_5ST_DIG:
+	case ALC880_W810:
+		spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+		break;
+	default:
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_3ST:
+	case ALC880_3ST_DIG:
+	case ALC880_5ST:
+	case ALC880_5ST_DIG:
+	case ALC880_W810:
+		spec->front_panel = 1;
+		break;
+	default:
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_5ST:
+	case ALC880_5ST_DIG:
+		spec->init_verbs = alc880_init_verbs_five_stack;
+		spec->channel_mode = alc880_fivestack_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes);
+		break;
+	case ALC880_W810:
+		spec->init_verbs = alc880_w810_init_verbs;
+		spec->channel_mode = alc880_w810_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes);
+		break;
+	default:
+		spec->init_verbs = alc880_init_verbs_three_stack;
+		spec->channel_mode = alc880_threestack_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes);
+		break;
+	}
+
+	spec->stream_name_analog = "ALC880 Analog";
+	spec->stream_analog_playback = &alc880_pcm_analog_playback;
+	spec->stream_analog_capture = &alc880_pcm_analog_capture;
+
+	spec->stream_name_digital = "ALC880 Digital";
+	spec->stream_digital_playback = &alc880_pcm_digital_playback;
+	spec->stream_digital_capture = &alc880_pcm_digital_capture;
+
+	spec->multiout.max_channels = spec->channel_mode[0].channels;
+
+	switch (board_config) {
+	case ALC880_W810:
+		spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids);
+		spec->multiout.dac_nids = alc880_w810_dac_nids;
+		// No dedicated headphone socket - it's shared with built-in speakers.
+		break;
+	default:
+		spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids);
+		spec->multiout.dac_nids = alc880_dac_nids;
+		spec->multiout.hp_nid = 0x03; /* rear-surround NID */
+		break;
+	}
+
+	spec->input_mux = &alc880_capture_source;
+	spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
+	spec->adc_nids = alc880_adc_nids;
+
+	codec->patch_ops = alc_patch_ops;
+
+	return 0;
+}
+
+/*
+ * ALC260 support
+ */
+
+/*
+ * This is just place-holder, so there's something for alc_build_pcms to look
+ * at when it calculates the maximum number of channels. ALC260 has no mixer
+ * element which allows changing the channel mode, so the verb list is
+ * never used.
+ */
+static struct alc_channel_mode alc260_modes[1] = {
+	{ 2, NULL },
+};
+
+snd_kcontrol_new_t alc260_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+	/* use LINE2 for the output */
+	/* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */
+	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb alc260_init_verbs[] = {
+	/* Line In pin widget for input */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* LINE-2 is used for line-out in rear */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* select line-out */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* LINE-OUT pin */
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* enable HP */
+	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* enable Mono */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* unmute amp left and right */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute Line-Out mixer amp left and right (volume = 0) */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* unmute HP mixer amp left and right (volume = 0) */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* unmute Mono mixer amp left and right (volume = 0) */
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* mute LINE-2 out */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
+	/* unmute CD */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x07,  AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic */
+	{0x07,  AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Headphone out path */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Mono out path */
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{ }
+};
+
+static struct hda_pcm_stream alc260_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x2,
+};
+
+static struct hda_pcm_stream alc260_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x4,
+};
+
+static int patch_alc260(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->mixers[spec->num_mixers] = alc260_base_mixer;
+	spec->num_mixers++;
+
+	spec->init_verbs = alc260_init_verbs;
+	spec->channel_mode = alc260_modes;
+	spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
+
+	spec->stream_name_analog = "ALC260 Analog";
+	spec->stream_analog_playback = &alc260_pcm_analog_playback;
+	spec->stream_analog_capture = &alc260_pcm_analog_capture;
+
+	spec->multiout.max_channels = spec->channel_mode[0].channels;
+	spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
+	spec->multiout.dac_nids = alc260_dac_nids;
+
+	spec->input_mux = &alc260_capture_source;
+	spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
+	spec->adc_nids = alc260_adc_nids;
+
+	codec->patch_ops = alc_patch_ops;
+
+	return 0;
+}
+
+/*
+ * ALC882 support
+ *
+ * ALC882 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+
+static struct alc_channel_mode alc882_ch_modes[1] = {
+	{ 8, NULL }
+};
+
+static hda_nid_t alc882_dac_nids[4] = {
+	/* front, rear, clfe, rear_surr */
+	0x02, 0x03, 0x04, 0x05
+};
+
+static hda_nid_t alc882_adc_nids[3] = {
+	/* ADC0-2 */
+	0x07, 0x08, 0x09,
+};
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+
+static struct hda_input_mux alc882_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x1 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+#define alc882_mux_enum_info alc_mux_enum_info
+#define alc882_mux_enum_get alc_mux_enum_get
+
+static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	const struct hda_input_mux *imux = spec->input_mux;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
+	hda_nid_t nid = capture_mixers[adc_idx];
+	unsigned int *cur_val = &spec->cur_mux[adc_idx];
+	unsigned int i, idx;
+
+	idx = ucontrol->value.enumerated.item[0];
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (*cur_val == idx && ! codec->in_resume)
+		return 0;
+	for (i = 0; i < imux->num_items; i++) {
+		unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    v | (imux->items[i].index << 8));
+	}
+	*cur_val = idx;
+	return 1;
+}
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static snd_kcontrol_new_t alc882_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 3,
+		.info = alc882_mux_enum_info,
+		.get = alc882_mux_enum_get,
+		.put = alc882_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb alc882_init_verbs[] = {
+	/* Front mixer: unmute input/output amp left and right (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* Rear mixer */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* CLFE mixer */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* Side mixer */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+	/* Front Pin: to output mode */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Front Pin: mute amp left and right (no volume) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* select Front mixer (0x0c, index 0) */
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Rear Pin */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Rear Pin: mute amp left and right (no volume) */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* select Rear mixer (0x0d, index 1) */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* CLFE Pin */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* CLFE Pin: mute amp left and right (no volume) */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* select CLFE mixer (0x0e, index 2) */
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* Side Pin */
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Side Pin: mute amp left and right (no volume) */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* select Side mixer (0x0f, index 3) */
+	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+	/* Headphone Pin */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Headphone Pin: mute amp left and right (no volume) */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* select Front mixer (0x0c, index 0) */
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Mic (rear) pin widget for input and vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Front Mic pin widget for input and vref at 80% */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Line In pin widget for input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+	/* FIXME: use matrix-type input source selection */
+	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	/* Input mixer2 */
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	/* Input mixer3 */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	/* ADC1: unmute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* ADC2: unmute amp left and right */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* ADC3: unmute amp left and right */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* Unmute front loopback */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute rear loopback */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Mute CLFE loopback */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+	/* Unmute side loopback */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{ }
+};
+
+static int patch_alc882(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->mixers[spec->num_mixers] = alc882_base_mixer;
+	spec->num_mixers++;
+
+	spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+	spec->dig_in_nid = ALC880_DIGIN_NID;
+	spec->front_panel = 1;
+	spec->init_verbs = alc882_init_verbs;
+	spec->channel_mode = alc882_ch_modes;
+	spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes);
+
+	spec->stream_name_analog = "ALC882 Analog";
+	spec->stream_analog_playback = &alc880_pcm_analog_playback;
+	spec->stream_analog_capture = &alc880_pcm_analog_capture;
+
+	spec->stream_name_digital = "ALC882 Digital";
+	spec->stream_digital_playback = &alc880_pcm_digital_playback;
+	spec->stream_digital_capture = &alc880_pcm_digital_capture;
+
+	spec->multiout.max_channels = spec->channel_mode[0].channels;
+	spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids);
+	spec->multiout.dac_nids = alc882_dac_nids;
+
+	spec->input_mux = &alc882_capture_source;
+	spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+	spec->adc_nids = alc882_adc_nids;
+
+	codec->patch_ops = alc_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_realtek[] = {
+	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
+ 	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+	{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
+	{} /* terminator */
+};
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c
--- a/sound/pci/ice1712/ak4xxx.c
+++ b/sound/pci/ice1712/ak4xxx.c
@@ -126,12 +126,16 @@ int snd_ice1712_akm4xxx_init(akm4xxx_t *
 {
 	struct snd_ak4xxx_private *priv;
 
-	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-	if (priv == NULL)
-		return -ENOMEM;
+	if (_priv != NULL) {
+		priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+		if (priv == NULL)
+			return -ENOMEM;
+		*priv = *_priv;
+	} else {
+		priv = NULL;
+	}
 	*ak = *temp;
 	ak->card = ice->card;
-	*priv = *_priv;
         ak->private_value[0] = (unsigned long)priv;
 	ak->private_data[0] = ice;
 	if (ak->ops.lock == NULL)
diff --git a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h
--- a/sound/pci/ice1712/envy24ht.h
+++ b/sound/pci/ice1712/envy24ht.h
@@ -106,7 +106,7 @@ enum {
 #define VT1724_REG_I2C_BYTE_ADDR	0x11	/* byte */
 #define VT1724_REG_I2C_DATA		0x12	/* byte */
 #define VT1724_REG_I2C_CTRL		0x13	/* byte */
-#define   VT1724_I2C_EEPROM		0x80	/* EEPROM exists */
+#define   VT1724_I2C_EEPROM		0x80	/* 1 = EEPROM exists */
 #define   VT1724_I2C_BUSY		0x01	/* busy bit */
 
 #define VT1724_REG_GPIO_DATA	0x14	/* word */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -1014,21 +1014,9 @@ static int snd_ice1712_pro_trigger(snd_p
 static void snd_ice1712_set_pro_rate(ice1712_t *ice, unsigned int rate, int force)
 {
 	unsigned long flags;
-	unsigned char val;
+	unsigned char val, old;
 	unsigned int i;
 
-	spin_lock_irqsave(&ice->reg_lock, flags);
-	if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
-						 ICE1712_PLAYBACK_PAUSE|
-						 ICE1712_PLAYBACK_START)) {
-		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
-	}
-	if (!force && is_pro_rate_locked(ice)) {
-		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
-	}
-
 	switch (rate) {
 	case 8000: val = 6; break;
 	case 9600: val = 3; break;
@@ -1049,8 +1037,22 @@ static void snd_ice1712_set_pro_rate(ice
 		rate = 48000;
 		break;
 	}
-	outb(val, ICEMT(ice, RATE));
 
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
+						 ICE1712_PLAYBACK_PAUSE|
+						 ICE1712_PLAYBACK_START)) {
+	      __out:
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+	if (!force && is_pro_rate_locked(ice))
+		goto __out;
+
+        old = inb(ICEMT(ice, RATE));
+	if (!force && old == val)
+		goto __out;
+	outb(val, ICEMT(ice, RATE));
 	spin_unlock_irqrestore(&ice->reg_lock, flags);
 
 	if (ice->gpio.set_pro_rate)
@@ -2405,6 +2407,7 @@ static int __devinit snd_ice1712_chip_in
 		udelay(200);
 		snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0);
 	}
+	snd_ice1712_set_pro_rate(ice, 48000, 1);
 
 	return 0;
 }
@@ -2545,6 +2548,7 @@ static int __devinit snd_ice1712_create(
 	ice->cs8427_timeout = cs8427_timeout;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	init_MUTEX(&ice->i2c_mutex);
 	init_MUTEX(&ice->open_mutex);
 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -27,6 +27,7 @@
 #include <sound/rawmidi.h>
 #include <sound/i2c.h>
 #include <sound/ak4xxx-adda.h>
+#include <sound/ak4114.h>
 #include <sound/pcm.h>
 
 
@@ -335,11 +336,13 @@ struct _snd_ice1712 {
 
 	struct semaphore open_mutex;
 	snd_pcm_substream_t *pcm_reserved[4];
+	snd_pcm_hw_constraint_list_t *hw_rates; /* card-specific rate constraints */
 
 	unsigned int akm_codecs;
 	akm4xxx_t *akm;
 	struct snd_ice1712_spdif spdif;
 
+	struct semaphore i2c_mutex;	/* I2C mutex for ICE1724 registers */
 	snd_i2c_bus_t *i2c;		/* I2C bus */
 	snd_i2c_device_t *cs8427;	/* CS8427 I2C device */
 	unsigned int cs8427_timeout;	/* CS8427 reset timeout in HZ/100 */
@@ -355,12 +358,13 @@ struct _snd_ice1712 {
 		unsigned int (*get_data)(ice1712_t *ice);
 		/* misc operators - move to another place? */
 		void (*set_pro_rate)(ice1712_t *ice, unsigned int rate);
+		void (*i2s_mclk_changed)(ice1712_t *ice);
 	} gpio;
 	struct semaphore gpio_mutex;
 
 	/* other board-specific data */
 	union {
-		/* additional i2c devices for EWS boards*/
+		/* additional i2c devices for EWS boards */
 		snd_i2c_device_t *i2cdevs[3];
 		/* AC97 register cache for Aureon */
 		struct aureon_spec {
@@ -375,6 +379,10 @@ struct _snd_ice1712 {
 			unsigned int config;
 			unsigned short boxconfig[4];
 		} hoontech;
+		struct {
+			ak4114_t *ak4114;
+			unsigned int analog: 1;
+		} juli;
 	} spec;
 
 };
@@ -477,7 +485,7 @@ struct snd_ice1712_card_info {
 	char *driver;
 	int (*chip_init)(ice1712_t *);
 	int (*build_controls)(ice1712_t *);
-	int no_mpu401: 1;
+	unsigned int no_mpu401: 1;
 	unsigned int eeprom_size;
 	unsigned char *eeprom_data;
 };
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -47,6 +47,8 @@
 #include "vt1720_mobo.h"
 #include "pontis.h"
 #include "prodigy192.h"
+#include "juli.h"
+#include "phase.h"
 
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -59,6 +61,8 @@ MODULE_SUPPORTED_DEVICE("{"
 	       VT1720_MOBO_DEVICE_DESC
 	       PONTIS_DEVICE_DESC
 	       PRODIGY192_DEVICE_DESC
+	       JULI_DEVICE_DESC
+	       PHASE_DEVICE_DESC
 		"{VIA,VT1720},"
 		"{VIA,VT1724},"
 		"{ICEnsemble,Generic ICE1724},"
@@ -401,23 +405,11 @@ static void snd_vt1724_set_pro_rate(ice1
 {
 	unsigned long flags;
 	unsigned char val, old;
-	unsigned int i;
+	unsigned int i, mclk_change;
 
 	if (rate > get_max_rate(ice))
 		return;
 
-	spin_lock_irqsave(&ice->reg_lock, flags);
-	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 
-	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
-		/* running? we cannot change the rate now... */
-		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
-	}
-	if (!force && is_pro_rate_locked(ice)) {
-		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
-	}
-
 	switch (rate) {
 	case 8000: val = 6; break;
 	case 9600: val = 3; break;
@@ -439,8 +431,21 @@ static void snd_vt1724_set_pro_rate(ice1
 		val = 0;
 		break;
 	}
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 
+	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
+		/* running? we cannot change the rate now... */
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+	if (!force && is_pro_rate_locked(ice)) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+
 	old = inb(ICEMT1724(ice, RATE));
-	if (old != val)
+	if (force || old != val)
 		outb(val, ICEMT1724(ice, RATE));
 	else if (rate == ice->cur_rate) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
@@ -450,6 +455,7 @@ static void snd_vt1724_set_pro_rate(ice1
 	ice->cur_rate = rate;
 
 	/* check MT02 */
+	mclk_change = 0;
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
 		if (rate > 96000)
@@ -458,25 +464,23 @@ static void snd_vt1724_set_pro_rate(ice1
 			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
 		if (val != old) {
 			outb(val, ICEMT1724(ice, I2S_FORMAT));
-			if (ice->eeprom.subvendor == VT1724_SUBDEVICE_REVOLUTION71) {
-				/* FIXME: is this revo only? */
-				/* assert PRST# to converters; MT05 bit 7 */
-				outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
-				spin_unlock_irqrestore(&ice->reg_lock, flags);
-				mdelay(5);
-				spin_lock_irqsave(&ice->reg_lock, flags);
-				/* deassert PRST# */
-				outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
-			}
+			mclk_change = 1;
 		}
 	}
 	spin_unlock_irqrestore(&ice->reg_lock, flags);
 
+	if (mclk_change && ice->gpio.i2s_mclk_changed)
+		ice->gpio.i2s_mclk_changed(ice);
+	if (ice->gpio.set_pro_rate)
+		ice->gpio.set_pro_rate(ice, rate);
+
 	/* set up codecs */
 	for (i = 0; i < ice->akm_codecs; i++) {
 		if (ice->akm[i].ops.set_rate_val)
 			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
 	}
+	if (ice->spdif.ops.setup_rate)
+		ice->spdif.ops.setup_rate(ice, rate);
 }
 
 static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream,
@@ -714,6 +718,13 @@ static snd_pcm_hardware_t snd_vt1724_2ch
 static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (ice->hw_rates) {
+		/* hardware specific */
+		runtime->hw.rate_min = ice->hw_rates->list[0];
+		runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1];
+		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+		return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, ice->hw_rates);
+	}
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		/* I2S */
 		/* VT1720 doesn't support more than 96kHz */
@@ -1866,6 +1877,8 @@ static struct snd_ice1712_card_info *car
 	snd_vt1720_mobo_cards,
 	snd_vt1720_pontis_cards,
 	snd_vt1724_prodigy192_cards,
+	snd_vt1724_juli_cards,
+	snd_vt1724_phase_cards,
 	NULL,
 };
 
@@ -1878,23 +1891,34 @@ static void wait_i2c_busy(ice1712_t *ice
 	int t = 0x10000;
 	while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--)
 		;
+	if (t == -1)
+		printk(KERN_ERR "ice1724: i2c busy timeout\n");
 }
 
 unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr)
 {
+	unsigned char val;
+
+	down(&ice->i2c_mutex);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
-	return inb(ICEREG1724(ice, I2C_DATA));
+	val = inb(ICEREG1724(ice, I2C_DATA));
+	up(&ice->i2c_mutex);
+	//printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+	return val;
 }
 
 void snd_vt1724_write_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr, unsigned char data)
 {
+	down(&ice->i2c_mutex);
 	wait_i2c_busy(ice);
+	//printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(data, ICEREG1724(ice, I2C_DATA));
 	outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
+	up(&ice->i2c_mutex);
 }
 
 static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice, const char *modelname)
@@ -1906,7 +1930,8 @@ static int __devinit snd_vt1724_read_eep
 	if (! modelname || ! *modelname) {
 		ice->eeprom.subvendor = 0;
 		if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0)
-			ice->eeprom.subvendor = (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
+			ice->eeprom.subvendor =
+				(snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
 				(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 
 				(snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | 
 				(snd_vt1724_read_i2c(ice, dev, 0x03) << 24);
@@ -2114,6 +2139,7 @@ static int __devinit snd_vt1724_create(s
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
 	init_MUTEX(&ice->open_mutex);
+	init_MUTEX(&ice->i2c_mutex);
 	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
 	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
 	ice->gpio.set_data = snd_vt1724_set_gpio_data;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/ice1712/juli.c
@@ -0,0 +1,230 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for ESI Juli@ cards
+ *
+ *	Copyright (c) 2004 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it 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 <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "juli.h"
+
+/*
+ * chip addresses on I2C bus
+ */
+#define AK4114_ADDR		0x20		/* S/PDIF receiver */
+#define AK4358_ADDR		0x22		/* DAC */
+
+/*
+ * GPIO pins
+ */
+#define GPIO_FREQ_MASK		(3<<0)
+#define GPIO_FREQ_32KHZ		(0<<0)
+#define GPIO_FREQ_44KHZ		(1<<0)
+#define GPIO_FREQ_48KHZ		(2<<0)
+#define GPIO_MULTI_MASK		(3<<2)
+#define GPIO_MULTI_4X		(0<<2)
+#define GPIO_MULTI_2X		(1<<2)
+#define GPIO_MULTI_1X		(2<<2)		/* also external */
+#define GPIO_MULTI_HALF		(3<<2)
+#define GPIO_INTERNAL_CLOCK	(1<<4)
+#define GPIO_ANALOG_PRESENT	(1<<5)		/* RO only: 0 = present */
+#define GPIO_RXMCLK_SEL		(1<<7)		/* must be 0 */
+#define GPIO_AK5385A_CKS0	(1<<8)
+#define GPIO_AK5385A_DFS0	(1<<9)		/* swapped with DFS1 according doc? */
+#define GPIO_AK5385A_DFS1	(1<<10)
+#define GPIO_DIGOUT_MONITOR	(1<<11)		/* 1 = active */
+#define GPIO_DIGIN_MONITOR	(1<<12)		/* 1 = active */
+#define GPIO_ANAIN_MONITOR	(1<<13)		/* 1 = active */
+#define GPIO_AK5385A_MCLK	(1<<14)		/* must be 0 */
+#define GPIO_MUTE_CONTROL	(1<<15)		/* 0 = off, 1 = on */
+
+static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val)
+{
+	snd_vt1724_write_i2c((ice1712_t *)private_data, AK4114_ADDR, reg, val);
+}
+        
+static unsigned char juli_ak4114_read(void *private_data, unsigned char reg)
+{
+	return snd_vt1724_read_i2c((ice1712_t *)private_data, AK4114_ADDR, reg);
+}
+
+/*
+ * AK4358 section
+ */
+
+static void juli_akm_lock(akm4xxx_t *ak, int chip)
+{
+}
+
+static void juli_akm_unlock(akm4xxx_t *ak, int chip)
+{
+}
+
+static void juli_akm_write(akm4xxx_t *ak, int chip,
+			   unsigned char addr, unsigned char data)
+{
+	ice1712_t *ice = ak->private_data[0];
+	 
+	snd_assert(chip == 0, return);
+	snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data);
+}
+
+/*
+ * change the rate of envy24HT, AK4358
+ */
+static void juli_akm_set_rate_val(akm4xxx_t *ak, unsigned int rate)
+{
+	unsigned char old, tmp, dfs;
+
+	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+		return;
+	
+	/* adjust DFS on codecs */
+	if (rate > 96000) 
+		dfs = 2;
+	else if (rate > 48000)
+		dfs = 1;
+	else
+		dfs = 0;
+	
+	tmp = snd_akm4xxx_get(ak, 0, 2);
+	old = (tmp >> 4) & 0x03;
+	if (old == dfs)
+		return;
+	/* reset DFS */
+	snd_akm4xxx_reset(ak, 1);
+	tmp = snd_akm4xxx_get(ak, 0, 2);
+	tmp &= ~(0x03 << 4);
+	tmp |= dfs << 4;
+	snd_akm4xxx_set(ak, 0, 2, tmp);
+	snd_akm4xxx_reset(ak, 0);
+}
+
+static akm4xxx_t akm_juli_dac __devinitdata = {
+	.type = SND_AK4358,
+	.num_dacs = 2,
+	.ops = {
+		.lock = juli_akm_lock,
+		.unlock = juli_akm_unlock,
+		.write = juli_akm_write,
+		.set_rate_val = juli_akm_set_rate_val
+	}
+};
+
+static int __devinit juli_add_controls(ice1712_t *ice)
+{
+	return snd_ice1712_akm4xxx_build_controls(ice);
+}
+
+/*
+ * initialize the chip
+ */
+static int __devinit juli_init(ice1712_t *ice)
+{
+	static unsigned char ak4114_init_vals[] = {
+		/* AK4117_REG_PWRDN */	AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+		/* AK4114_REQ_FORMAT */	AK4114_DIF_I24I2S,
+		/* AK4114_REG_IO0 */	AK4114_TX1E,
+		/* AK4114_REG_IO1 */	AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+		/* AK4114_REG_INT0_MASK */ 0,
+		/* AK4114_REG_INT1_MASK */ 0
+	};
+	static unsigned char ak4114_init_txcsb[] = {
+		0x41, 0x02, 0x2c, 0x00, 0x00
+	};
+	int err;
+	akm4xxx_t *ak;
+
+#if 0
+	for (err = 0; err < 0x20; err++)
+		juli_ak4114_read(ice, err);
+	juli_ak4114_write(ice, 0, 0x0f);
+	juli_ak4114_read(ice, 0);
+	juli_ak4114_read(ice, 1);
+#endif
+	err = snd_ak4114_create(ice->card,
+				juli_ak4114_read,
+				juli_ak4114_write,
+				ak4114_init_vals, ak4114_init_txcsb,
+				ice, &ice->spec.juli.ak4114);
+	if (err < 0)
+		return err;
+
+	ice->spec.juli.analog = ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT;
+
+	if (ice->spec.juli.analog) {
+		printk(KERN_INFO "juli@: analog I/O detected\n");
+		ice->num_total_dacs = 2;
+		ice->num_total_adcs = 2;
+
+		ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL);
+		if (! ak)
+			return -ENOMEM;
+		ice->akm_codecs = 1;
+		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0)
+			return err;
+	}
+	
+	return 0;
+}
+
+
+/*
+ * Juli@ boards don't provide the EEPROM data except for the vendor IDs.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char juli_eeprom[] __devinitdata = {
+	0x20,	/* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */
+	0x80,	/* ACLINK: I2S */
+	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
+	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
+	0x9f,	/* GPIO_DIR */
+	0xff,	/* GPIO_DIR1 */
+	0x7f,	/* GPIO_DIR2 */
+	0x9f,	/* GPIO_MASK */
+	0xff,	/* GPIO_MASK1 */
+	0x7f,	/* GPIO_MASK2 */
+	0x16,	/* GPIO_STATE: internal clock, multiple 1x, 48kHz */
+	0x80,	/* GPIO_STATE1: mute */
+	0x00,	/* GPIO_STATE2 */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
+	{
+		.subvendor = VT1724_SUBDEVICE_JULI,
+		.name = "ESI Juli@",
+		.model = "juli",
+		.chip_init = juli_init,
+		.build_controls = juli_add_controls,
+		.eeprom_size = sizeof(juli_eeprom),
+		.eeprom_data = juli_eeprom,
+	},
+	{ } /* terminator */
+};
diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/ice1712/juli.h
@@ -0,0 +1,10 @@
+#ifndef __SOUND_JULI_H
+#define __SOUND_JULI_H
+
+#define JULI_DEVICE_DESC		"{ESI,Juli@},"
+
+#define VT1724_SUBDEVICE_JULI		0x31305345	/* Juli@ */
+
+extern struct snd_ice1712_card_info  snd_vt1724_juli_cards[];
+
+#endif	/* __SOUND_JULI_H */
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
new file mode 100644
--- /dev/null
+++ b/sound/pci/ice1712/phase.c
@@ -0,0 +1,138 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1724 (Envy24)
+ *
+ *   Lowlevel functions for Terratec PHASE 22
+ *
+ *	Copyright (c) 2005 Misha Zhilin <misha@epiphan.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
+ *
+ */
+
+/* PHASE 22 overview:
+ *   Audio controller: VIA Envy24HT-S (slightly trimmed down version of Envy24HT)
+ *   Analog chip: AK4524 (partially via Philip's 74HCT125)
+ *   Digital receiver: CS8414-CS (not supported in this release)
+ *
+ *   Envy connects to AK4524
+ *	- CS directly from GPIO 10
+ *	- CCLK via 74HCT125's gate #4 from GPIO 4
+ *	- CDTI via 74HCT125's gate #2 from GPIO 5
+ *		CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "phase.h"
+
+static akm4xxx_t akm_phase22 __devinitdata = {
+	.type = SND_AK4524,
+	.num_dacs = 2,
+	.num_adcs = 2,
+};
+
+static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
+	.caddr =	2,
+	.cif =		1,
+	.data_mask =	1 << 4,
+	.clk_mask =	1 << 5,
+	.cs_mask =	1 << 10,
+	.cs_addr =	1 << 10,
+	.cs_none =	0,
+	.add_flags = 	1 << 3,
+	.mask_flags =	0,
+};
+
+static int __devinit phase22_init(ice1712_t *ice)
+{
+	akm4xxx_t *ak;
+	int err;
+
+	// Configure DAC/ADC description for generic part of ice1724
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_PHASE22:
+		ice->num_total_dacs = 2;
+		ice->num_total_adcs = 2;
+		ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO
+		break;
+	default:
+		snd_BUG();
+		return -EINVAL;
+	}
+
+	// Initialize analog chips
+	ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL);
+	if (! ak)
+		return -ENOMEM;
+	ice->akm_codecs = 1;
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_PHASE22:
+		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)
+			return err;
+		break;
+	}
+
+	return 0;
+}
+
+static int __devinit phase22_add_controls(ice1712_t *ice)
+{
+	int err = 0;
+
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_PHASE22:
+		err = snd_ice1712_akm4xxx_build_controls(ice);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static unsigned char phase22_eeprom[] __devinitdata = {
+	0x00,	/* SYSCONF: 1xADC, 1xDACs */
+	0x80,	/* ACLINK: I2S */
+	0xf8,	/* I2S: vol, 96k, 24bit*/
+	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
+	0xFF,	/* GPIO_DIR */
+	0xFF,	/* GPIO_DIR1 */
+	0xFF,	/* GPIO_DIR2 */
+	0x00,	/* GPIO_MASK */
+	0x00,	/* GPIO_MASK1 */
+	0x00,	/* GPIO_MASK2 */
+	0x00,	/* GPIO_STATE: */
+	0x00,	/* GPIO_STATE1: */
+	0x00,	/* GPIO_STATE2 */
+};
+
+struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
+	{
+		.subvendor = VT1724_SUBDEVICE_PHASE22,
+		.name = "Terratec PHASE 22",
+		.model = "phase22",
+		.chip_init = phase22_init,
+		.build_controls = phase22_add_controls,
+		.eeprom_size = sizeof(phase22_eeprom),
+		.eeprom_data = phase22_eeprom,
+	},
+	{ } /* terminator */
+};
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
new file mode 100644
--- /dev/null
+++ b/sound/pci/ice1712/phase.h
@@ -0,0 +1,34 @@
+#ifndef __SOUND_PHASE_H
+#define __SOUND_PHASE_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for Terratec PHASE 22
+ *
+ *	Copyright (c) 2005 Misha Zhilin <misha@epiphan.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
+ *
+ */      
+
+#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"
+
+#define VT1724_SUBDEVICE_PHASE22	0x3b155011
+
+/* entry point */
+extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+
+#endif /* __SOUND_PHASE */
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -36,12 +36,12 @@
 #include "prodigy192.h"
 #include "stac946x.h"
 
-static void stac9460_put(ice1712_t *ice, int reg, unsigned char val)
+static inline void stac9460_put(ice1712_t *ice, int reg, unsigned char val)
 {
 	snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val);
 }
 
-static unsigned char stac9460_get(ice1712_t *ice, int reg)
+static inline unsigned char stac9460_get(ice1712_t *ice, int reg)
 {
 	return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg);
 }
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -33,6 +33,15 @@
 #include "envy24ht.h"
 #include "revo.h"
 
+static void revo_i2s_mclk_changed(ice1712_t *ice)
+{
+	/* assert PRST# to converters; MT05 bit 7 */
+	outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
+	mdelay(5);
+	/* deassert PRST# */
+	outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
+}
+
 /*
  * change the rate of envy24HT, AK4355 and AK4381
  */
@@ -119,6 +128,17 @@ static struct snd_ak4xxx_private akm_rev
 	.mask_flags = 0,
 };
 
+static unsigned int rates[] = {
+	32000, 44100, 48000, 64000, 88200, 96000,
+	176400, 192000,
+};
+
+static snd_pcm_hw_constraint_list_t revo_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list = rates,
+	.mask = 0,
+};
+
 static int __devinit revo_init(ice1712_t *ice)
 {
 	akm4xxx_t *ak;
@@ -135,6 +155,8 @@ static int __devinit revo_init(ice1712_t
 		return -EINVAL;
 	}
 
+	ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed;
+
 	/* second stage of initialization, analog parts and others */
 	ak = ice->akm = kcalloc(2, sizeof(akm4xxx_t), GFP_KERNEL);
 	if (! ak)
@@ -151,6 +173,8 @@ static int __devinit revo_init(ice1712_t
 		break;
 	}
 
+	ice->hw_rates = &revo_rates; /* AK codecs don't support lower than 32k */
+
 	return 0;
 }
 
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
--- a/sound/pci/ice1712/vt1720_mobo.c
+++ b/sound/pci/ice1712/vt1720_mobo.c
@@ -101,6 +101,15 @@ struct snd_ice1712_card_info snd_vt1720_
 		.eeprom_size = sizeof(k8x800_eeprom),
 		.eeprom_data = k8x800_eeprom,
 	},
+	{
+		.subvendor = VT1720_SUBDEVICE_9CJS,
+		.name = "Chaintech 9CJS",
+		/* identical with k8x800 */
+		.chip_init = k8x800_init,
+		.build_controls = k8x800_add_controls,
+		.eeprom_size = sizeof(k8x800_eeprom),
+		.eeprom_data = k8x800_eeprom,
+	},
 	{ } /* terminator */
 };
 
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
--- a/sound/pci/ice1712/vt1720_mobo.h
+++ b/sound/pci/ice1712/vt1720_mobo.h
@@ -26,11 +26,13 @@
 
 #define VT1720_MOBO_DEVICE_DESC        "{Albatron,K8X800 Pro II},"\
 				       "{Chaintech,ZNF3-150},"\
-				       "{Chaintech,ZNF3-250},"
+				       "{Chaintech,ZNF3-250},"\
+				       "{Chaintech,9CJS},"
 
 #define VT1720_SUBDEVICE_K8X800		0xf217052c
 #define VT1720_SUBDEVICE_ZNF3_150	0x0f2741f6
 #define VT1720_SUBDEVICE_ZNF3_250	0x0f2745f6
+#define VT1720_SUBDEVICE_9CJS		0x0f272327
 
 extern struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
 
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -55,6 +55,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA
 		"{Intel,ICH6},"
 		"{Intel,ICH7},"
 		"{Intel,6300ESB},"
+		"{Intel,ESB2},"
 		"{Intel,MX440},"
 		"{SiS,SI7012},"
 		"{NVidia,nForce Audio},"
@@ -118,12 +119,15 @@ MODULE_PARM_DESC(xbox, "Set to 1 for Xbo
 #ifndef PCI_DEVICE_ID_INTEL_ESB_5
 #define PCI_DEVICE_ID_INTEL_ESB_5	0x25a6
 #endif
-#ifndef PCI_DEVICE_ID_INTEL_ICH6_3
-#define PCI_DEVICE_ID_INTEL_ICH6_3	0x266e
+#ifndef PCI_DEVICE_ID_INTEL_ICH6_18
+#define PCI_DEVICE_ID_INTEL_ICH6_18	0x266e
 #endif
 #ifndef PCI_DEVICE_ID_INTEL_ICH7_20
 #define PCI_DEVICE_ID_INTEL_ICH7_20	0x27de
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ESB2_14
+#define PCI_DEVICE_ID_INTEL_ESB2_14	0x2698
+#endif
 #ifndef PCI_DEVICE_ID_SI_7012
 #define PCI_DEVICE_ID_SI_7012		0x7012
 #endif
@@ -443,6 +447,7 @@ static struct pci_device_id snd_intel8x0
 	{ 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
 	{ 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
 	{ 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */
+	{ 0x8086, 0x2698, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB2 */
 	{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7012 */
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE */
@@ -1059,7 +1064,7 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	ichdev_t *ichdev = get_ichdev(substream);
 	size_t ptr1, ptr;
-	int civ, timeout = 10;
+	int civ, timeout = 100;
 	unsigned int position;
 
 	spin_lock(&chip->reg_lock);
@@ -1067,8 +1072,10 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 		civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
 		ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
 		position = ichdev->position;
-		if (ptr1 == 0)
-			udelay(1);
+		if (ptr1 == 0) {
+			udelay(10);
+			continue;
+		}
 		if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
 		    ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
 			break;
@@ -1761,6 +1768,12 @@ static struct ac97_quirk ac97_quirks[] _
 	},
 	{
 		.vendor = 0x1028,
+		.device = 0x012c,
+		.name = "Dell Precision 650",	/* AD1981A */
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
+		.vendor = 0x1028,
 		.device = 0x012d,
 		.name = "Dell Precision 450",	/* AD1981B*/
 		.type = AC97_TUNE_HP_ONLY
@@ -1772,6 +1785,12 @@ static struct ac97_quirk ac97_quirks[] _
 		.type = AC97_TUNE_HP_ONLY
 	},
 	{
+		.vendor = 0x1028,
+		.device = 0x0163,
+		.name = "Dell Unknown",	/* STAC9750/51 */
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
 		.vendor = 0x103c,
 		.device = 0x006d,
 		.name = "HP zv5000",
@@ -1838,6 +1857,12 @@ static struct ac97_quirk ac97_quirks[] _
 		.type = AC97_TUNE_HP_ONLY
 	},
 	{
+		.vendor = 0x10cf,
+		.device = 0x1253,
+		.name = "Fujitsu S6210",	/* STAC9750/51 */
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
 		.vendor = 0x10f1,
 		.device = 0x2665,
 		.name = "Fujitsu-Siemens Celsius",	/* AD1981? */
@@ -2012,7 +2037,8 @@ static int __devinit snd_intel8x0_mixer(
 	/* FIXME: my test board doesn't work well with VRA... */
 	if (chip->device_type == DEVICE_ALI)
 		pbus->no_vra = 1;
-	pbus->dra = 1;
+	else
+		pbus->dra = 1;
 	chip->ac97_bus = pbus;
 
 	ac97.pci = chip->pci;
@@ -2320,7 +2346,7 @@ static int snd_intel8x0_free(intel8x0_t 
 /*
  * power management
  */
-static int intel8x0_suspend(snd_card_t *card, unsigned int state)
+static int intel8x0_suspend(snd_card_t *card, pm_message_t state)
 {
 	intel8x0_t *chip = card->pm_private_data;
 	int i;
@@ -2345,7 +2371,7 @@ static int intel8x0_suspend(snd_card_t *
 	return 0;
 }
 
-static int intel8x0_resume(snd_card_t *card, unsigned int state)
+static int intel8x0_resume(snd_card_t *card)
 {
 	intel8x0_t *chip = card->pm_private_data;
 	int i;
@@ -2713,8 +2739,9 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" },
 	{ PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" },
 	{ PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" },
-	{ PCI_DEVICE_ID_INTEL_ICH6_3, "Intel ICH6" },
+	{ PCI_DEVICE_ID_INTEL_ICH6_18, "Intel ICH6" },
 	{ PCI_DEVICE_ID_INTEL_ICH7_20, "Intel ICH7" },
+	{ PCI_DEVICE_ID_INTEL_ESB2_14, "Intel ESB2" },
 	{ PCI_DEVICE_ID_SI_7012, "SiS SI7012" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -35,6 +35,7 @@
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
+#include <sound/control.h>
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -46,6 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA
 		"{Intel,82801CA-ICH3},"
 		"{Intel,82801DB-ICH4},"
 		"{Intel,ICH5},"
+		"{Intel,ICH6},"
+		"{Intel,ICH7},"
 	        "{Intel,MX440},"
 		"{SiS,7013},"
 		"{NVidia,NForce Modem},"
@@ -54,7 +57,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA
 		"{NVidia,NForce3 Modem},"
 		"{AMD,AMD768}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
@@ -93,6 +96,12 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 code
 #ifndef PCI_DEVICE_ID_INTEL_ICH5_6
 #define PCI_DEVICE_ID_INTEL_ICH5_6	0x24d6
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH6_6
+#define PCI_DEVICE_ID_INTEL_ICH6_6	0x266d
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH7_6
+#define PCI_DEVICE_ID_INTEL_ICH7_6	0x27dd
+#endif
 #ifndef PCI_DEVICE_ID_SI_7013
 #define PCI_DEVICE_ID_SI_7013		0x7013
 #endif
@@ -247,7 +256,7 @@ struct _snd_intel8x0m {
 	snd_pcm_t *pcm[2];
 	ichdev_t ichd[2];
 
-	int in_ac97_init: 1;
+	unsigned int in_ac97_init: 1;
 
 	ac97_bus_t *ac97_bus;
 	ac97_t *ac97;
@@ -268,6 +277,8 @@ static struct pci_device_id snd_intel8x0
 	{ 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH3 */
 	{ 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
 	{ 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */
+	{ 0x8086, 0x266d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH6 */
+	{ 0x8086, 0x27dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH7 */
 	{ 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD768 */
 	{ 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7013 */
@@ -281,9 +292,60 @@ static struct pci_device_id snd_intel8x0
 #endif
 	{ 0, }
 };
+static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
+					    snd_ctl_elem_value_t *ucontrol);
+static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
+					    snd_ctl_elem_value_t *ucontrol);
+static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
+					     snd_ctl_elem_info_t *uinfo);
+
+#define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff))
+#define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff)
+#define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff)
+
+static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = {
+  { .name  = "Off-hook Switch",
+    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+    .info  = snd_intel8x0m_switch_default_info,
+    .get   = snd_intel8x0m_switch_default_get,
+    .put   = snd_intel8x0m_switch_default_put,
+    .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH)
+  }
+};
 
 MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
 
+static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
+					     snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
+					    snd_ctl_elem_value_t *ucontrol)
+{
+	unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
+	unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
+	intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int status;
+	status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0;
+	ucontrol->value.integer.value[0] = status;
+	return 0;
+}
+static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
+					    snd_ctl_elem_value_t *ucontrol)
+{
+	unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
+	unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
+	intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask;
+	return snd_ac97_update_bits(chip->ac97, reg,
+				    mask, new_status);
+}
 /*
  *  Lowlevel I/O - busmaster
  */
@@ -638,17 +700,12 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 
 static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 {
-	ichdev_t *ichdev = get_ichdev(substream);
 	/* hook off/on on start/stop */
-	/* TODO: move it to ac97 controls */
+	/* Moved this to mixer control */
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
-				     AC97_GPIO_LINE1_OH, AC97_GPIO_LINE1_OH);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
-				     AC97_GPIO_LINE1_OH, ~AC97_GPIO_LINE1_OH);
 		break;
 	default:
 		return -EINVAL;
@@ -890,6 +947,7 @@ static int __devinit snd_intel8x0_mixer(
 	ac97_t *x97;
 	int err;
 	unsigned int glob_sta = 0;
+	unsigned int idx;
 	static ac97_bus_ops_t ops = {
 		.write = snd_intel8x0_codec_write,
 		.read = snd_intel8x0_codec_read,
@@ -921,10 +979,14 @@ static int __devinit snd_intel8x0_mixer(
 		return err;
 	}
 	chip->ac97 = x97;
-	if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97 ) {
+	if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97) {
 		chip->ichd[ICHD_MDMIN].ac97 = x97;
 		chip->ichd[ICHD_MDMOUT].ac97 = x97;
 	}
+	for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) {
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0)
+			goto __err;
+	}
 
 	chip->in_ac97_init = 0;
 	return 0;
@@ -1078,7 +1140,7 @@ static int snd_intel8x0_free(intel8x0_t 
 /*
  * power management
  */
-static int intel8x0m_suspend(snd_card_t *card, unsigned int state)
+static int intel8x0m_suspend(snd_card_t *card, pm_message_t state)
 {
 	intel8x0_t *chip = card->pm_private_data;
 	int i;
@@ -1091,7 +1153,7 @@ static int intel8x0m_suspend(snd_card_t 
 	return 0;
 }
 
-static int intel8x0m_resume(snd_card_t *card, unsigned int state)
+static int intel8x0m_resume(snd_card_t *card)
 {
 	intel8x0_t *chip = card->pm_private_data;
 	pci_enable_device(chip->pci);
@@ -1298,6 +1360,8 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_INTEL_ICH3_6, "Intel 82801CA-ICH3" },
 	{ PCI_DEVICE_ID_INTEL_ICH4_6, "Intel 82801DB-ICH4" },
 	{ PCI_DEVICE_ID_INTEL_ICH5_6, "Intel ICH5" },
+	{ PCI_DEVICE_ID_INTEL_ICH6_6, "Intel ICH6" },
+	{ PCI_DEVICE_ID_INTEL_ICH7_6, "Intel ICH7" },
 	{ 0x7446, "AMD AMD768" },
 	{ PCI_DEVICE_ID_SI_7013, "SiS SI7013" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP_MODEM, "NVidia nForce" },
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -51,7 +51,7 @@
 //#define K1212_LARGEALLOC		1
 
 // ----------------------------------------------------------------------------
-// the following enum defines the valid states of the Korg 1212 I/O card.
+// Valid states of the Korg 1212 I/O card.
 // ----------------------------------------------------------------------------
 typedef enum {
    K1212_STATE_NONEXISTENT,		// there is no card here
@@ -85,6 +85,8 @@ typedef enum {
    K1212_DB_ConfigureMiscMemory   = 6,    // tells card where other buffers are.
    K1212_DB_TriggerFromAdat       = 7,    // tells card to trigger from Adat at a specific
                                           //    timecode value.
+   K1212_DB_DMAERROR              = 0x80, // DMA Error - the PCI bus is congestioned.
+   K1212_DB_CARDSTOPPED           = 0x81, // Card has stopped by user request.
    K1212_DB_RebootCard            = 0xA0, // instructs the card to reboot.
    K1212_DB_BootFromDSPPage4      = 0xA4, // instructs the card to boot from the DSP microcode
                                           //    on page 4 (local page to card).
@@ -93,11 +95,9 @@ typedef enum {
    K1212_DB_StartDSPDownload      = 0xAF  // tells the card to download its DSP firmware.
 } korg1212_dbcnst_t;
 
-#define K1212_ISRCODE_DMAERROR      0x80
-#define K1212_ISRCODE_CARDSTOPPED   0x81
 
 // ----------------------------------------------------------------------------
-// The following enumeration defines return codes for DeviceIoControl() calls
+// The following enumeration defines return codes 
 // to the Korg 1212 I/O driver.
 // ----------------------------------------------------------------------------
 typedef enum {
@@ -116,11 +116,6 @@ typedef enum {
    K1212_CMDRET_NoAckFromCard,         // the card never acknowledged a command
    K1212_CMDRET_BadParams,             // bad parameters were provided by the caller
 
-   // --------------------------------------------------------------
-   // the following return errors are specific to the wave device
-   // driver interface.  These will not be encountered by users of
-   // the 32 bit DIOC interface (a.k.a. custom or native API).
-   // --------------------------------------------------------------
    K1212_CMDRET_BadDevice,             // the specified wave device was out of range
    K1212_CMDRET_BadFormat              // the specified wave format is unsupported
 } snd_korg1212rc;
@@ -400,9 +395,14 @@ struct _snd_korg1212 {
         u16 leftADCInSens;           // ADC left channel input sensitivity
         u16 rightADCInSens;          // ADC right channel input sensitivity
 
-	int opencnt;			// Open/Close count
-	int setcnt;			// SetupForPlay count
-	int playcnt;			// TriggerPlay count
+	int opencnt;		     // Open/Close count
+	int setcnt;		     // SetupForPlay count
+	int playcnt;		     // TriggerPlay count
+	int errorcnt;		     // Error Count
+	unsigned long totalerrorcnt; // Total Error Count
+
+	int dsp_is_loaded;
+	int dsp_stop_is_processed;
 
 };
 
@@ -610,7 +610,7 @@ static snd_korg1212rc snd_korg1212_Send1
 static void snd_korg1212_SendStop(korg1212_t *korg1212)
 {
 	if (! korg1212->stop_pending_cnt) {
-		writel(0xffffffff, &korg1212->sharedBufferPtr->cardCommand);
+		korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
 		/* program the timer */
 		korg1212->stop_pending_cnt = HZ;
 		korg1212->timer.expires = jiffies + 1;
@@ -622,9 +622,10 @@ static void snd_korg1212_SendStopAndWait
 {
 	unsigned long flags;
 	spin_lock_irqsave(&korg1212->lock, flags);
+	korg1212->dsp_stop_is_processed = 0;
 	snd_korg1212_SendStop(korg1212);
 	spin_unlock_irqrestore(&korg1212->lock, flags);
-	sleep_on_timeout(&korg1212->wait, (HZ * 3) / 2);
+	wait_event_timeout(korg1212->wait, korg1212->dsp_stop_is_processed, (HZ * 3) / 2);
 }
 
 /* timer callback for checking the ack of stop request */
@@ -633,9 +634,10 @@ static void snd_korg1212_timer_func(unsi
         korg1212_t *korg1212 = (korg1212_t *) data;
 	
 	spin_lock(&korg1212->lock);
-	if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0) {
+	if (korg1212->sharedBufferPtr->cardCommand == 0) {
 		/* ack'ed */
 		korg1212->stop_pending_cnt = 0;
+		korg1212->dsp_stop_is_processed = 1;
 		wake_up(&korg1212->wait);
 #if K1212_DEBUG_LEVEL > 1
 		K1212_DEBUG_PRINTK("K1212_DEBUG: Stop ack'ed [%s]\n", stateName[korg1212->cardState]);
@@ -647,7 +649,8 @@ static void snd_korg1212_timer_func(unsi
 			add_timer(&korg1212->timer);
 		} else {
 			snd_printd("korg1212_timer_func timeout\n");
-			writel(0, &korg1212->sharedBufferPtr->cardCommand);
+			korg1212->sharedBufferPtr->cardCommand = 0;
+			korg1212->dsp_stop_is_processed = 1;
 			wake_up(&korg1212->wait);
 #if K1212_DEBUG_LEVEL > 0
 			K1212_DEBUG_PRINTK("K1212_DEBUG: Stop timeout [%s]\n", stateName[korg1212->cardState]);
@@ -850,15 +853,12 @@ static int snd_korg1212_SetMonitorMode(k
 
 static inline int snd_korg1212_use_is_exclusive(korg1212_t *korg1212)
 {
-	unsigned long flags;
 	int ret = 1;
 
-	spin_lock_irqsave(&korg1212->lock, flags);
 	if ((korg1212->playback_pid != korg1212->capture_pid) &&
 	    (korg1212->playback_pid >= 0) && (korg1212->capture_pid >= 0)) {
 		ret = 0;
 	}
-	spin_unlock_irqrestore(&korg1212->lock, flags);
 	return ret;
 }
 
@@ -1179,18 +1179,23 @@ static irqreturn_t snd_korg1212_interrup
 #if K1212_DEBUG_LEVEL > 0
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DNLD count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
 #endif
-                        if (korg1212->cardState == K1212_STATE_DSP_IN_PROCESS)
+                        if (korg1212->cardState == K1212_STATE_DSP_IN_PROCESS) {
+				korg1212->dsp_is_loaded = 1;
 				wake_up(&korg1212->wait);
+			}
                         break;
 
                 // ------------------------------------------------------------------------
                 // an error occurred - stop the card
                 // ------------------------------------------------------------------------
-                case K1212_ISRCODE_DMAERROR:
+                case K1212_DB_DMAERROR:
 #if K1212_DEBUG_LEVEL > 1
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
 #endif
-                        writel(0, &korg1212->sharedBufferPtr->cardCommand);
+			snd_printk(KERN_ERR "korg1212: DMA Error\n");	
+			korg1212->errorcnt++;
+			korg1212->totalerrorcnt++;
+			korg1212->sharedBufferPtr->cardCommand = 0;
 			snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP);
                         break;
 
@@ -1198,11 +1203,11 @@ static irqreturn_t snd_korg1212_interrup
                 // the card has stopped by our request.  Clear the command word and signal
                 // the semaphore in case someone is waiting for this.
                 // ------------------------------------------------------------------------
-                case K1212_ISRCODE_CARDSTOPPED:
+                case K1212_DB_CARDSTOPPED:
 #if K1212_DEBUG_LEVEL > 1
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ CSTP count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
 #endif
-                        writel(0, &korg1212->sharedBufferPtr->cardCommand);
+			korg1212->sharedBufferPtr->cardCommand = 0;
                         break;
 
                 default:
@@ -1267,7 +1272,9 @@ static int snd_korg1212_downloadDSPCode(
 	if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Start DSP Download RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
 #endif
 
-	if (! sleep_on_timeout(&korg1212->wait, HZ * CARD_BOOT_TIMEOUT))
+	korg1212->dsp_is_loaded = 0;
+	wait_event_timeout(korg1212->wait, korg1212->dsp_is_loaded, HZ * CARD_BOOT_TIMEOUT);
+	if (! korg1212->dsp_is_loaded )
 		return -EBUSY; /* timeout */
 
 	snd_korg1212_OnDSPDownloadComplete(korg1212);
@@ -1439,6 +1446,7 @@ static int snd_korg1212_playback_open(sn
 	korg1212->playback_pid = current->pid;
         korg1212->periodsize = K1212_PERIODS;
 	korg1212->channels = K1212_CHANNELS;
+	korg1212->errorcnt = 0;
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
@@ -1457,7 +1465,7 @@ static int snd_korg1212_capture_open(snd
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]);
 #endif
 
-        snd_pcm_set_sync(substream);    // ???
+        snd_pcm_set_sync(substream);
 
 	snd_korg1212_OpenCard(korg1212);
 
@@ -1614,7 +1622,7 @@ static int snd_korg1212_prepare(snd_pcm_
         	spin_unlock_irq(&korg1212->lock);
 		return -EAGAIN;
 		/*
-		writel(0, &korg1212->sharedBufferPtr->cardCommand);
+		korg1212->sharedBufferPtr->cardCommand = 0;
 		del_timer(&korg1212->timer);
 		korg1212->stop_pending_cnt = 0;
 		*/
@@ -2118,6 +2126,7 @@ static void snd_korg1212_proc_read(snd_i
         snd_iprintf(buffer, "Idle mon. State: %d\n", korg1212->idleMonitorOn);
         snd_iprintf(buffer, "Cmd retry count: %d\n", korg1212->cmdRetryCount);
         snd_iprintf(buffer, "      Irq count: %ld\n", korg1212->irqcount);
+        snd_iprintf(buffer, "    Error count: %ld\n", korg1212->totalerrorcnt);
 }
 
 static void __devinit snd_korg1212_proc_init(korg1212_t *korg1212)
@@ -2235,6 +2244,7 @@ static int __devinit snd_korg1212_create
 	korg1212->opencnt = 0;
 	korg1212->playcnt = 0;
 	korg1212->setcnt = 0;
+	korg1212->totalerrorcnt = 0;
 	korg1212->playback_pid = -1;
 	korg1212->capture_pid = -1;
         snd_korg1212_setCardState(korg1212, K1212_STATE_UNINITIALIZED);
@@ -2273,7 +2283,7 @@ static int __devinit snd_korg1212_create
 #endif
 
         if ((korg1212->iobase = ioremap(korg1212->iomem, iomem_size)) == NULL) {
-		snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", korg1212->iomem,
+		snd_printk(KERN_ERR "korg1212: unable to remap memory region 0x%lx-0x%lx\n", korg1212->iomem,
                            korg1212->iomem + iomem_size - 1);
                 snd_korg1212_free(korg1212);
                 return -EBUSY;
@@ -2284,7 +2294,7 @@ static int __devinit snd_korg1212_create
                           "korg1212", (void *) korg1212);
 
         if (err) {
-		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+		snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq);
                 snd_korg1212_free(korg1212);
                 return -EBUSY;
         }
@@ -2332,7 +2342,7 @@ static int __devinit snd_korg1212_create
 
 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
 				sizeof(KorgSharedBuffer), &korg1212->dma_shared) < 0) {
-		snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer));
+		snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer));
                 snd_korg1212_free(korg1212);
                 return -ENOMEM;
         }
@@ -2349,7 +2359,7 @@ static int __devinit snd_korg1212_create
 
 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
 				korg1212->DataBufsSize, &korg1212->dma_play) < 0) {
-		snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
+		snd_printk(KERN_ERR "korg1212: can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 snd_korg1212_free(korg1212);
                 return -ENOMEM;
         }
@@ -2363,7 +2373,7 @@ static int __devinit snd_korg1212_create
 
 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
 				korg1212->DataBufsSize, &korg1212->dma_rec) < 0) {
-		snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
+		snd_printk(KERN_ERR "korg1212: can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 snd_korg1212_free(korg1212);
                 return -ENOMEM;
         }
@@ -2395,7 +2405,7 @@ static int __devinit snd_korg1212_create
 
 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
 				korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) {
-		snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
+		snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
                 snd_korg1212_free(korg1212);
                 return -ENOMEM;
         }
@@ -2424,11 +2434,12 @@ static int __devinit snd_korg1212_create
         if (snd_korg1212_downloadDSPCode(korg1212))
         	return -EBUSY;
 
-	printk(KERN_INFO "dspMemPhy       = %08x U[%08x]\n"
-               "PlayDataPhy     = %08x L[%08x]\n"
-               "RecDataPhy      = %08x L[%08x]\n"
-               "VolumeTablePhy  = %08x L[%08x]\n"
-               "RoutingTablePhy = %08x L[%08x]\n"
+	snd_printk(KERN_ERR 
+	       "korg1212: dspMemPhy = %08x U[%08x], "
+               "PlayDataPhy = %08x L[%08x]\n"
+	       "korg1212: RecDataPhy = %08x L[%08x], "
+               "VolumeTablePhy = %08x L[%08x]\n"
+               "korg1212: RoutingTablePhy = %08x L[%08x], "
                "AdatTimeCodePhy = %08x L[%08x]\n",
 	       (int)korg1212->dma_dsp.addr,    UpperWordSwap(korg1212->dma_dsp.addr),
                korg1212->PlayDataPhy,     LowerWordSwap(korg1212->PlayDataPhy),
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -820,7 +820,7 @@ struct snd_m3 {
 	unsigned long iobase;
 
 	int irq;
-	int allegro_flag : 1;
+	unsigned int allegro_flag : 1;
 
 	ac97_t *ac97;
 
@@ -957,6 +957,13 @@ static struct m3_quirk m3_quirk_list[] =
 		.device = 0x80f1,
 		.amp_gpio = 0x03,
 	},
+	/* LEGEND ZhaoYang 3100CF */
+	{
+		.name = "LEGEND ZhaoYang 3100CF",
+		.vendor = 0x1509,
+		.device = 0x1740,
+		.amp_gpio = 0x03,
+	},
 	/* END */
 	{ NULL }
 };
@@ -2385,7 +2392,7 @@ static int snd_m3_free(m3_t *chip)
  * APM support
  */
 #ifdef CONFIG_PM
-static int m3_suspend(snd_card_t *card, unsigned int state)
+static int m3_suspend(snd_card_t *card, pm_message_t state)
 {
 	m3_t *chip = card->pm_private_data;
 	int i, index;
@@ -2417,7 +2424,7 @@ static int m3_suspend(snd_card_t *card, 
 	return 0;
 }
 
-static int m3_resume(snd_card_t *card, unsigned int state)
+static int m3_resume(snd_card_t *card)
 {
 	m3_t *chip = card->pm_private_data;
 	int i, index;
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1062,7 +1062,7 @@ static int snd_mixart_free(mixart_mgr_t 
 		free_irq(mgr->irq, (void *)mgr);
 
 	/* reset board if some firmware was loaded */
-	if(mgr->hwdep->dsp_loaded) {
+	if(mgr->dsp_loaded) {
 		snd_mixart_reset_board(mgr);
 		snd_printdd("reset miXart !\n");
 	}
@@ -1203,7 +1203,7 @@ static void snd_mixart_proc_read(snd_inf
 	snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx);
 
 	/* stats available when embedded OS is running */
-	if (chip->mgr->hwdep->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) {
+	if (chip->mgr->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) {
 		snd_iprintf(buffer, "- hardware -\n");
 		switch (chip->mgr->board_type ) {
 		case MIXART_DAUGHTER_TYPE_NONE     : snd_iprintf(buffer, "\tmiXart8 (no daughter board)\n\n"); break;
@@ -1381,7 +1381,7 @@ static int __devinit snd_mixart_probe(st
 		}
 	}
 
-	/* init firmware status (mgr->hwdep->dsp_loaded reset in hwdep_new) */
+	/* init firmware status (mgr->dsp_loaded reset in hwdep_new) */
 	mgr->board_type = MIXART_DAUGHTER_TYPE_NONE;
 
 	/* create array of streaminfo */
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
--- a/sound/pci/mixart/mixart.h
+++ b/sound/pci/mixart/mixart.h
@@ -112,7 +112,7 @@ struct snd_mixart_mgr {
 	struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
 
 	/* hardware interface */
-	snd_hwdep_t *hwdep;
+	unsigned int dsp_loaded;      /* bit flags of loaded dsp indices */
 	unsigned int board_type;      /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
 
 	struct snd_dma_buffer flowinfo;
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -142,26 +142,35 @@ static int mixart_enum_connectors(mixart
 	u32 k;
 	int err;
 	mixart_msg_t request;
-	mixart_enum_connector_resp_t connector;
-	mixart_audio_info_req_t  audio_info_req;
-	mixart_audio_info_resp_t audio_info;
-
-	audio_info_req.line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
-	audio_info_req.micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
-	audio_info_req.cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
+	mixart_enum_connector_resp_t *connector;
+	mixart_audio_info_req_t  *audio_info_req;
+	mixart_audio_info_resp_t *audio_info;
+
+	connector = kmalloc(sizeof(*connector), GFP_KERNEL);
+	audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
+	audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
+	if (! connector || ! audio_info_req || ! audio_info) {
+		err = -ENOMEM;
+		goto __error;
+	}
+
+	audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
+	audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
+	audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
 
 	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
 	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */
 	request.data = NULL;
 	request.size = 0;
 
-	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
-	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
+	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
 		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
-		return -EINVAL;
+		err = -EINVAL;
+		goto __error;
 	}
 
-	for(k=0; k < connector.uid_count; k++) {
+	for(k=0; k < connector->uid_count; k++) {
 		mixart_pipe_t* pipe;
 
 		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
@@ -170,25 +179,25 @@ static int mixart_enum_connectors(mixart
 			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
 		}
 		if(k & 1) {
-			pipe->uid_right_connector = connector.uid[k];   /* odd */
+			pipe->uid_right_connector = connector->uid[k];   /* odd */
 		} else {
-			pipe->uid_left_connector = connector.uid[k];    /* even */
+			pipe->uid_left_connector = connector->uid[k];    /* even */
 		}
 
-		/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+		/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 
 		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
 		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
-		request.uid = connector.uid[k];
-		request.data = &audio_info_req;
-		request.size = sizeof(audio_info_req);
+		request.uid = connector->uid[k];
+		request.data = audio_info_req;
+		request.size = sizeof(*audio_info_req);
 
-		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
 		if( err < 0 ) {
 			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
-			return err;
+			goto __error;
 		}
-		/*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+		/*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
 	}
 
 	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
@@ -196,13 +205,14 @@ static int mixart_enum_connectors(mixart
 	request.data = NULL;
 	request.size = 0;
 
-	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
-	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
+	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
 		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
-		return -EINVAL;
+		err = -EINVAL;
+		goto __error;
 	}
 
-	for(k=0; k < connector.uid_count; k++) {
+	for(k=0; k < connector->uid_count; k++) {
 		mixart_pipe_t* pipe;
 
 		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
@@ -211,28 +221,34 @@ static int mixart_enum_connectors(mixart
 			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
 		}
 		if(k & 1) {
-			pipe->uid_right_connector = connector.uid[k];   /* odd */
+			pipe->uid_right_connector = connector->uid[k];   /* odd */
 		} else {
-			pipe->uid_left_connector = connector.uid[k];    /* even */
+			pipe->uid_left_connector = connector->uid[k];    /* even */
 		}
 
-		/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+		/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 
 		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
 		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
-		request.uid = connector.uid[k];
-		request.data = &audio_info_req;
-		request.size = sizeof(audio_info_req);
+		request.uid = connector->uid[k];
+		request.data = audio_info_req;
+		request.size = sizeof(*audio_info_req);
 
-		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
 		if( err < 0 ) {
 			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
-			return err;
+			goto __error;
 		}
-		/*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+		/*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
 	}
+	err = 0;
 
-	return 0;
+ __error:
+	kfree(connector);
+	kfree(audio_info_req);
+	kfree(audio_info);
+
+	return err;
 }
 
 static int mixart_enum_physio(mixart_mgr_t *mgr)
@@ -546,6 +562,7 @@ int snd_mixart_setup_firmware(mixart_mgr
 		release_firmware(fw_entry);
 		if (err < 0)
 			return err;
+		mgr->dsp_loaded |= 1 << i;
 	}
 	return 0;
 }
@@ -573,7 +590,7 @@ static int mixart_hwdep_dsp_status(snd_h
 	strcpy(info->id, "miXart");
         info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
 
-	if (mgr->hwdep->dsp_loaded & (1 <<  MIXART_MOTHERBOARD_ELF_INDEX))
+	if (mgr->dsp_loaded & (1 <<  MIXART_MOTHERBOARD_ELF_INDEX))
 		info->chip_ready = 1;
 
 	info->version = MIXART_DRIVER_VERSION;
@@ -599,6 +616,9 @@ static int mixart_hwdep_dsp_load(snd_hwd
 	}
 	err = mixart_dsp_load(mgr, dsp->index, &fw);
 	vfree(fw.data);
+	if (err < 0)
+		return err;
+	mgr->dsp_loaded |= 1 << dsp->index;
 	return err;
 }
 
@@ -619,8 +639,7 @@ int snd_mixart_setup_firmware(mixart_mgr
 	hw->ops.dsp_load = mixart_hwdep_dsp_load;
 	hw->exclusive = 1;
 	sprintf(hw->name,  SND_MIXART_HWDEP_ID);
-	mgr->hwdep = hw;
-	mgr->hwdep->dsp_loaded = 0;
+	mgr->dsp_loaded = 0;
 
 	return snd_card_register(mgr->chip[0]->card);
 }
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1267,7 +1267,7 @@ snd_nm256_peek_for_sig(nm256_t *chip)
  * APM event handler, so the card is properly reinitialized after a power
  * event.
  */
-static int nm256_suspend(snd_card_t *card, unsigned int state)
+static int nm256_suspend(snd_card_t *card, pm_message_t state)
 {
 	nm256_t *chip = card->pm_private_data;
 
@@ -1278,7 +1278,7 @@ static int nm256_suspend(snd_card_t *car
 	return 0;
 }
 
-static int nm256_resume(snd_card_t *card, unsigned int state)
+static int nm256_resume(snd_card_t *card)
 {
 	nm256_t *chip = card->pm_private_data;
 
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1183,15 +1183,14 @@ static int snd_rme32_playback_fd_ack(snd
 {
 	rme32_t *rme32 = snd_pcm_substream_chip(substream);
 	snd_pcm_indirect_t *rec, *cprec;
-	unsigned long flags;
 
 	rec = &rme32->playback_pcm;
 	cprec = &rme32->capture_pcm;
-	spin_lock_irqsave(&rme32->lock, flags);
+	spin_lock(&rme32->lock);
 	rec->hw_queue_size = RME32_BUFFER_SIZE;
 	if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE))
 		rec->hw_queue_size -= cprec->hw_ready;
-	spin_unlock_irqrestore(&rme32->lock, flags);
+	spin_unlock(&rme32->lock);
 	snd_pcm_indirect_playback_transfer(substream, rec,
 					   snd_rme32_pb_trans_copy);
 	return 0;
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -47,8 +47,6 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
-static int line_outs_monitor[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0}; /* Send all inputs/playback to line outs */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
@@ -56,10 +54,6 @@ module_param_array(id, charp, NULL, 0444
 MODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
-module_param_array(precise_ptr, bool, NULL, 0444);
-MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).");
-module_param_array(line_outs_monitor, bool, NULL, 0444);
-MODULE_PARM_DESC(line_outs_monitor, "Send all input and playback streams to line outs by default.");
 MODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
 MODULE_DESCRIPTION("RME Hammerfall DSP");
 MODULE_LICENSE("GPL");
@@ -445,6 +439,7 @@ struct _hdsp {
 	snd_pcm_substream_t  *playback_substream;
         hdsp_midi_t           midi[2];
 	struct tasklet_struct midi_tasklet;
+	int		      use_midi_tasklet;
 	int                   precise_ptr;
 	u32                   control_register;	     /* cached value */
 	u32                   control2_register;     /* cached value */
@@ -472,7 +467,6 @@ struct _hdsp {
 	pid_t                 capture_pid;
 	pid_t                 playback_pid;
 	int                   running;
-        int                   passthru;              /* non-zero if doing pass-thru */
 	int                   system_sample_rate;
 	char                 *channel_map;
 	int                   dev;
@@ -659,13 +653,13 @@ static int snd_hdsp_load_firmware_from_c
 
 	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 		
-		snd_printk ("loading firmware\n");
+		snd_printk ("Hammerfall-DSP: loading firmware\n");
 
 		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 		
 		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
-			snd_printk ("timeout waiting for download preparation\n");
+			snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
 			return -EIO;
 		}
 		
@@ -674,7 +668,7 @@ static int snd_hdsp_load_firmware_from_c
 		for (i = 0; i < 24413; ++i) {
 			hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]);
 			if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
-				snd_printk ("timeout during firmware loading\n");
+				snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
 				return -EIO;
 			}
 		}
@@ -687,7 +681,7 @@ static int snd_hdsp_load_firmware_from_c
 		}
 		
 		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
-			snd_printk ("timeout at end of firmware loading\n");
+			snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n");
 		    	return -EIO;
 		}
 
@@ -697,11 +691,11 @@ static int snd_hdsp_load_firmware_from_c
 		hdsp->control2_register = 0;
 #endif
 		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
-		snd_printk ("finished firmware loading\n");
+		snd_printk ("Hammerfall-DSP: finished firmware loading\n");
 		
 	}
 	if (hdsp->state & HDSP_InitializationComplete) {
-		snd_printk("firmware loaded from cache, restoring defaults\n");
+		snd_printk("Hammerfall-DSP: firmware loaded from cache, restoring defaults\n");
 		spin_lock_irqsave(&hdsp->lock, flags);
 		snd_hdsp_set_defaults(hdsp);
 		spin_unlock_irqrestore(&hdsp->lock, flags); 
@@ -714,16 +708,6 @@ static int snd_hdsp_load_firmware_from_c
 
 static int hdsp_get_iobox_version (hdsp_t *hdsp)
 {
-	int err;
-	
-	if (hdsp_check_for_iobox (hdsp)) {
-		return -EIO;
-	}
-
-	if ((err = snd_hdsp_enable_io(hdsp)) < 0) {
-		return err;
-	}
-		
 	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 	
 		hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM);
@@ -759,7 +743,7 @@ static int hdsp_check_for_firmware (hdsp
 {
 	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
 	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
-		snd_printk("firmware not present.\n");
+		snd_printk("Hammerfall-DSP: firmware not present.\n");
 		hdsp->state &= ~HDSP_FirmwareLoaded;
 		return -EIO;
 	}
@@ -787,7 +771,7 @@ static int hdsp_fifo_wait(hdsp_t *hdsp, 
 		udelay (100);
 	}
 
-	snd_printk ("wait for FIFO status <= %d failed after %d iterations\n",
+	snd_printk ("Hammerfall-DSP: wait for FIFO status <= %d failed after %d iterations\n",
 		    count, timeout);
 	return -1;
 }
@@ -809,7 +793,7 @@ static int hdsp_write_gain(hdsp_t *hdsp,
 	
 	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) {
 
-		/* from martin bjÃ¶rnsen:
+		/* from martin bjornsen:
 		   
 		   "You can only write dwords to the
 		   mixer memory which contain two
@@ -922,7 +906,7 @@ static int hdsp_spdif_sample_rate(hdsp_t
 	default:
 		break;
 	}
-	snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status);
+	snd_printk ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status);
 	return 0;
 }
 
@@ -1008,7 +992,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 	if (!(hdsp->control_register & HDSP_ClockModeMaster)) {	
 		if (called_internally) {
 			/* request from ctl or card initialization */
-			snd_printk("device is not running as a clock master: cannot set sample rate.\n");
+			snd_printk("Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n");
 			return -1;
 		} else {		
 			/* hw_param request while in AutoSync mode */
@@ -1016,11 +1000,11 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 			int spdif_freq = hdsp_spdif_sample_rate(hdsp);
 		
 			if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) {
-				snd_printk("Detected ADAT in double speed mode\n");
+				snd_printk("Hammerfall-DSP: Detected ADAT in double speed mode\n");
 			} else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) {
-				snd_printk("Detected ADAT in quad speed mode\n");			
+				snd_printk("Hammerfall-DSP: Detected ADAT in quad speed mode\n");			
 			} else if (rate != external_freq) {
-				snd_printk("No AutoSync source for requested rate\n");
+				snd_printk("Hammerfall-DSP: No AutoSync source for requested rate\n");
 				return -1;
 			}		
 		}	
@@ -1102,7 +1086,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 	}
 
 	if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
-		snd_printk ("cannot change speed mode (capture PID = %d, playback PID = %d)\n",
+		snd_printk ("Hammerfall-DSP: cannot change speed mode (capture PID = %d, playback PID = %d)\n",
 			    hdsp->capture_pid,
 			    hdsp->playback_pid);
 		return -EBUSY;
@@ -1143,68 +1127,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 	return 0;
 }
 
-static void hdsp_set_thru(hdsp_t *hdsp, int channel, int enable)
-{
-
-	hdsp->passthru = 0;
-
-	if (channel < 0) {
-
-		int i;
-
-		/* set thru for all channels */
-
-		if (enable) {
-			for (i = 0; i < hdsp->max_channels; i++) {
-				hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), UNITY_GAIN);
-			}
-		} else {
-			for (i = 0; i < hdsp->max_channels; i++) {
-				hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), MINUS_INFINITY_GAIN);
-			}
-		}
-
-	} else {
-		int mapped_channel;
-
-		snd_assert(channel < hdsp->max_channels, return);
-
-		mapped_channel = hdsp->channel_map[channel];
-
-		snd_assert(mapped_channel > -1, return);
-
-		if (enable) {
-			hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,mapped_channel,mapped_channel), UNITY_GAIN);
-		} else {
-			hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,mapped_channel,mapped_channel), MINUS_INFINITY_GAIN);
-		}
-	}
-}
-
-static int hdsp_set_passthru(hdsp_t *hdsp, int onoff)
-{
-	if (onoff) {
-		hdsp_set_thru(hdsp, -1, 1);
-		hdsp_reset_hw_pointer(hdsp);
-		hdsp_silence_playback(hdsp);
-
-		/* we don't want interrupts, so do a
-		   custom version of hdsp_start_audio().
-		*/
-
-		hdsp->control_register |= (HDSP_Start|HDSP_AudioInterruptEnable|hdsp_encode_latency(7));
-
-		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
-		hdsp->passthru = 1;
-	} else {
-		hdsp_set_thru(hdsp, -1, 0);
-		hdsp_stop_audio(hdsp);		
-		hdsp->passthru = 0;
-	}
-
-	return 0;
-}
-
 /*----------------------------------------------------------------------------
    MIDI
   ----------------------------------------------------------------------------*/
@@ -1345,6 +1267,7 @@ static void snd_hdsp_midi_input_trigger(
 		}
 	} else {
 		hdsp->control_register &= ~ie;
+		tasklet_kill(&hdsp->midi_tasklet);
 	}
 
 	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
@@ -2741,16 +2664,32 @@ static int snd_hdsp_get_autosync_ref(snd
 	return 0;
 }
 
-#define HDSP_PASSTHRU(xname, xindex) \
+#define HDSP_LINE_OUT(xname, xindex) \
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
-  .info = snd_hdsp_info_passthru, \
-  .put = snd_hdsp_put_passthru, \
-  .get = snd_hdsp_get_passthru \
+  .info = snd_hdsp_info_line_out, \
+  .get = snd_hdsp_get_line_out, \
+  .put = snd_hdsp_put_line_out \
+}
+
+static int hdsp_line_out(hdsp_t *hdsp)
+{
+	return (hdsp->control_register & HDSP_LineOut) ? 1 : 0;
+}
+
+static int hdsp_set_line_output(hdsp_t *hdsp, int out)
+{
+	if (out) {
+		hdsp->control_register |= HDSP_LineOut;
+	} else {
+		hdsp->control_register &= ~HDSP_LineOut;
+	}
+	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+	return 0;
 }
 
-static int snd_hdsp_info_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_hdsp_info_line_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -2759,61 +2698,106 @@ static int snd_hdsp_info_passthru(snd_kc
 	return 0;
 }
 
-static int snd_hdsp_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
-
+	
 	spin_lock_irq(&hdsp->lock);
-	ucontrol->value.integer.value[0] = hdsp->passthru;
+	ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
 	spin_unlock_irq(&hdsp->lock);
 	return 0;
 }
 
-static int snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
 	int change;
 	unsigned int val;
-	int err = 0;
-
+	
 	if (!snd_hdsp_use_is_exclusive(hdsp))
 		return -EBUSY;
-
 	val = ucontrol->value.integer.value[0] & 1;
 	spin_lock_irq(&hdsp->lock);
-	change = (ucontrol->value.integer.value[0] != hdsp->passthru);
-	if (change)
-		err = hdsp_set_passthru(hdsp, val);
+	change = (int)val != hdsp_line_out(hdsp);
+	hdsp_set_line_output(hdsp, val);
 	spin_unlock_irq(&hdsp->lock);
-	return err ? err : change;
+	return change;
 }
 
-#define HDSP_LINE_OUT(xname, xindex) \
+#define HDSP_PRECISE_POINTER(xname, xindex) \
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
-  .info = snd_hdsp_info_line_out, \
-  .get = snd_hdsp_get_line_out, \
-  .put = snd_hdsp_put_line_out \
+  .info = snd_hdsp_info_precise_pointer, \
+  .get = snd_hdsp_get_precise_pointer, \
+  .put = snd_hdsp_put_precise_pointer \
 }
 
-static int hdsp_line_out(hdsp_t *hdsp)
+static int hdsp_set_precise_pointer(hdsp_t *hdsp, int precise)
 {
-	return (hdsp->control_register & HDSP_LineOut) ? 1 : 0;
+	if (precise) {
+		hdsp->precise_ptr = 1;
+	} else {
+		hdsp->precise_ptr = 0;
+	}
+	return 0;
 }
 
-static int hdsp_set_line_output(hdsp_t *hdsp, int out)
+static int snd_hdsp_info_precise_pointer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
-	if (out) {
-		hdsp->control_register |= HDSP_LineOut;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hdsp_get_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+	
+	spin_lock_irq(&hdsp->lock);
+	ucontrol->value.integer.value[0] = hdsp->precise_ptr;
+	spin_unlock_irq(&hdsp->lock);
+	return 0;
+}
+
+static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int val;
+	
+	if (!snd_hdsp_use_is_exclusive(hdsp))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0] & 1;
+	spin_lock_irq(&hdsp->lock);
+	change = (int)val != hdsp->precise_ptr;
+	hdsp_set_precise_pointer(hdsp, val);
+	spin_unlock_irq(&hdsp->lock);
+	return change;
+}
+
+#define HDSP_USE_MIDI_TASKLET(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdsp_info_use_midi_tasklet, \
+  .get = snd_hdsp_get_use_midi_tasklet, \
+  .put = snd_hdsp_put_use_midi_tasklet \
+}
+
+static int hdsp_set_use_midi_tasklet(hdsp_t *hdsp, int use_tasklet)
+{
+	if (use_tasklet) {
+		hdsp->use_midi_tasklet = 1;
 	} else {
-		hdsp->control_register &= ~HDSP_LineOut;
+		hdsp->use_midi_tasklet = 0;
 	}
-	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
 	return 0;
 }
 
-static int snd_hdsp_info_line_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_hdsp_info_use_midi_tasklet(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -2822,17 +2806,17 @@ static int snd_hdsp_info_line_out(snd_kc
 	return 0;
 }
 
-static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_hdsp_get_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
 	
 	spin_lock_irq(&hdsp->lock);
-	ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
+	ucontrol->value.integer.value[0] = hdsp->use_midi_tasklet;
 	spin_unlock_irq(&hdsp->lock);
 	return 0;
 }
 
-static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_hdsp_put_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
 	int change;
@@ -2842,8 +2826,8 @@ static int snd_hdsp_put_line_out(snd_kco
 		return -EBUSY;
 	val = ucontrol->value.integer.value[0] & 1;
 	spin_lock_irq(&hdsp->lock);
-	change = (int)val != hdsp_line_out(hdsp);
-	hdsp_set_line_output(hdsp, val);
+	change = (int)val != hdsp->use_midi_tasklet;
+	hdsp_set_use_midi_tasklet(hdsp, val);
 	spin_unlock_irq(&hdsp->lock);
 	return change;
 }
@@ -3139,8 +3123,9 @@ HDSP_AUTOSYNC_SAMPLE_RATE("External Rate
 HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
 HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
 HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
-HDSP_PASSTHRU("Passthru", 0),
 HDSP_LINE_OUT("Line Out", 0),
+HDSP_PRECISE_POINTER("Precise Pointer", 0),
+HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
 };
 
 static snd_kcontrol_new_t snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
@@ -3240,11 +3225,11 @@ snd_hdsp_proc_read(snd_info_entry_t *ent
 	snd_iprintf(buffer, "Status register: 0x%x\n", status);
 	snd_iprintf(buffer, "Status2 register: 0x%x\n", status2);
 	snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff);
-
 	snd_iprintf(buffer, "MIDI1 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut0));
 	snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
 	snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
 	snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
+	snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_tasklet ? "on" : "off");
 
 	snd_iprintf(buffer, "\n");
 
@@ -3252,7 +3237,7 @@ snd_hdsp_proc_read(snd_info_entry_t *ent
 
 	snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes);
 	snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp));
-	snd_iprintf(buffer, "Passthru: %s\n", hdsp->passthru ? "yes" : "no");
+	snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off");
 	snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off");
 
 	snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2);
@@ -3612,40 +3597,6 @@ static int snd_hdsp_set_defaults(hdsp_t 
 		}
 	}
 	
-	if ((hdsp->io_type != H9652) && line_outs_monitor[hdsp->dev]) {
-		
-		int lineouts_base;
-		
-		snd_printk ("sending all inputs and playback streams to line outs.\n");
-
-		/* route all inputs to the line outs for easy monitoring. send
-		   odd numbered channels to right, even to left.
-		*/
-		if (hdsp->io_type == H9632) {
-			/* this is the phones/analog output */
-			lineouts_base = 10;
-		} else {
-			lineouts_base = 26;
-		}
-		
-		for (i = 0; i < hdsp->max_channels; i++) {
-			if (i & 1) { 
-				if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN) ||
-				    hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN)) {
-				    return -EIO;
-				}    
-			} else {
-				if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN) ||
-				    hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN)) {
-				    
-				    return -EIO;
-				}
-			}
-		}
-	}
-
-	hdsp->passthru = 0;
-
 	/* H9632 specific defaults */
 	if (hdsp->io_type == H9632) {
 		hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB);
@@ -3709,21 +3660,29 @@ static irqreturn_t snd_hdsp_interrupt(in
 	}
 	
 	if (midi0 && midi0status) {
-		/* we disable interrupts for this input until processing is done */
-		hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
-		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
-		hdsp->midi[0].pending = 1;
-		schedule = 1;
+		if (hdsp->use_midi_tasklet) {
+			/* we disable interrupts for this input until processing is done */
+			hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
+			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+			hdsp->midi[0].pending = 1;
+			schedule = 1;
+		} else {
+			snd_hdsp_midi_input_read (&hdsp->midi[0]);
+		}
 	}
-	if (midi1 && midi1status) {
-		/* we disable interrupts for this input until processing is done */
-		hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
-		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
-		hdsp->midi[1].pending = 1;
-		schedule = 1;
+	if (hdsp->io_type != Multiface && hdsp->io_type != H9632 && midi1 && midi1status) {
+		if (hdsp->use_midi_tasklet) {
+			/* we disable interrupts for this input until processing is done */
+			hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
+			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+			hdsp->midi[1].pending = 1;
+			schedule = 1;
+		} else {
+			snd_hdsp_midi_input_read (&hdsp->midi[1]);
+		}
 	}
-	if (schedule)
-	    tasklet_hi_schedule(&hdsp->midi_tasklet);
+	if (hdsp->use_midi_tasklet && schedule)
+		tasklet_hi_schedule(&hdsp->midi_tasklet);
 	return IRQ_HANDLED;
 }
 
@@ -3838,10 +3797,10 @@ static int snd_hdsp_hw_params(snd_pcm_su
 	if (hdsp_check_for_firmware(hdsp)) {
 		if (hdsp->state & HDSP_FirmwareCached) {
 			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-				snd_printk("Firmware loading from cache failed, please upload manually.\n");
+				snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
 			}
 		} else {
-			snd_printk("No firmware loaded nor cached, please upload firmware.\n");
+			snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
 		}
 		return -EIO;
 	}
@@ -3957,10 +3916,10 @@ static int snd_hdsp_trigger(snd_pcm_subs
 	if (hdsp_check_for_firmware(hdsp)) {
 		if (hdsp->state & HDSP_FirmwareCached) {
 			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-				snd_printk("Firmware loading from cache failed, please upload manually.\n");
+				snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
 			}
 		} else {
-			snd_printk("No firmware loaded nor cached, please upload firmware.\n");
+			snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
 		}
 		return -EIO;
 	}
@@ -4035,10 +3994,10 @@ static int snd_hdsp_prepare(snd_pcm_subs
 	if (hdsp_check_for_firmware(hdsp)) {
 		if (hdsp->state & HDSP_FirmwareCached) {
 			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-				snd_printk("Firmware loading from cache failed, please upload manually.\n");
+				snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
 			}
 		} else {
-			snd_printk("No firmware loaded nor cached, please upload firmware.\n");
+			snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
 		}
 		return -EIO;
 	}
@@ -4057,7 +4016,11 @@ static snd_pcm_hardware_t snd_hdsp_playb
 				 SNDRV_PCM_INFO_NONINTERLEAVED |
 				 SNDRV_PCM_INFO_SYNC_START |
 				 SNDRV_PCM_INFO_DOUBLE),
+#ifdef SNDRV_BIG_ENDIAN
+	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
+#else
 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
+#endif
 	.rates =		(SNDRV_PCM_RATE_32000 |
 				 SNDRV_PCM_RATE_44100 | 
 				 SNDRV_PCM_RATE_48000 | 
@@ -4082,7 +4045,11 @@ static snd_pcm_hardware_t snd_hdsp_captu
 				 SNDRV_PCM_INFO_MMAP_VALID |
 				 SNDRV_PCM_INFO_NONINTERLEAVED |
 				 SNDRV_PCM_INFO_SYNC_START),
+#ifdef SNDRV_BIG_ENDIAN
+	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
+#else
 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
+#endif
 	.rates =		(SNDRV_PCM_RATE_32000 |
 				 SNDRV_PCM_RATE_44100 | 
 				 SNDRV_PCM_RATE_48000 | 
@@ -4290,10 +4257,10 @@ static int snd_hdsp_playback_open(snd_pc
 	if (hdsp_check_for_firmware(hdsp)) {
 		if (hdsp->state & HDSP_FirmwareCached) {
 			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-				snd_printk("Firmware loading from cache failed, please upload manually.\n");
+				snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
 			}
 		} else {
-			snd_printk("No firmware loaded nor cached, please upload firmware.\n");
+			snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
 		}
 		return -EIO;
 	}
@@ -4306,11 +4273,6 @@ static int snd_hdsp_playback_open(snd_pc
 	runtime->dma_area = hdsp->playback_buffer;
 	runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
 
-	if (hdsp->capture_substream == NULL) {
-		hdsp_stop_audio(hdsp);
-		hdsp_set_thru(hdsp, -1, 0);
-	}
-
 	hdsp->playback_pid = current->pid;
 	hdsp->playback_substream = substream;
 
@@ -4373,10 +4335,10 @@ static int snd_hdsp_capture_open(snd_pcm
 	if (hdsp_check_for_firmware(hdsp)) {
 		if (hdsp->state & HDSP_FirmwareCached) {
 			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-				snd_printk("Firmware loading from cache failed, please upload manually.\n");
+				snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
 			}
 		} else {
-			snd_printk("No firmware loaded nor cached, please upload firmware.\n");
+			snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
 		}
 		return -EIO;
 	}
@@ -4389,11 +4351,6 @@ static int snd_hdsp_capture_open(snd_pcm
 	runtime->dma_area = hdsp->capture_buffer;
 	runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
 
-	if (hdsp->playback_substream == NULL) {
-		hdsp_stop_audio(hdsp);
-		hdsp_set_thru(hdsp, -1, 0);
-	}
-
 	hdsp->capture_pid = current->pid;
 	hdsp->capture_substream = substream;
 
@@ -4553,12 +4510,12 @@ static int hdsp_get_peak(hdsp_t *hdsp, h
 	}
 	for (i = 0; i < 26; ++i) {
 		if (copy_u64_le(&peak_rms->playback_rms[i],
-				hdsp->iobase + HDSP_playbackRmsLevel + i * 8,
-				hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4))
+				hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4,
+				hdsp->iobase + HDSP_playbackRmsLevel + i * 8))
 			return -EFAULT;
 		if (copy_u64_le(&peak_rms->input_rms[i], 
-				hdsp->iobase + HDSP_inputRmsLevel + i * 8,
-				hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4))
+				hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4,
+				hdsp->iobase + HDSP_inputRmsLevel + i * 8))
 			return -EFAULT;
 	}
 	return 0;
@@ -4574,7 +4531,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		hdsp_peak_rms_t __user *peak_rms = (hdsp_peak_rms_t __user *)arg;
 
 		if (!(hdsp->state & HDSP_FirmwareLoaded)) {
-			snd_printk(KERN_ERR "firmware needs to be uploaded to the card.\n");
+			snd_printk(KERN_ERR "Hammerfall-DSP: firmware needs to be uploaded to the card.\n");
 			return -EINVAL;
 		}
 
@@ -4593,7 +4550,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		int i;
 		
 		if (!(hdsp->state & HDSP_FirmwareLoaded)) {
-			snd_printk("Firmware needs to be uploaded to the card.\n");	
+			snd_printk("Hammerfall-DSP: Firmware needs to be uploaded to the card.\n");	
 			return -EINVAL;
 		}
 		spin_lock_irqsave(&hdsp->lock, flags);
@@ -4618,7 +4575,6 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
 		info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
 		info.line_out = (unsigned char)hdsp_line_out(hdsp);
-		info.passthru = (unsigned char)hdsp->passthru;
 		if (hdsp->io_type == H9632) {
 			info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
 			info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
@@ -4661,7 +4617,6 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		}
 		break;
 	}
-#ifndef HDSP_FW_LOADER
 	case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
 		hdsp_firmware_t __user *firmware;
 		u32 __user *firmware_data;
@@ -4674,7 +4629,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
 			return -EBUSY;
 
-		snd_printk("initializing firmware upload\n");
+		snd_printk("Hammerfall-DSP: initializing firmware upload\n");
 		firmware = (hdsp_firmware_t __user *)argp;
 
 		if (get_user(firmware_data, &firmware->firmware_data)) {
@@ -4696,18 +4651,20 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		}
 		
 		if (!(hdsp->state & HDSP_InitializationComplete)) {
-			snd_hdsp_initialize_channels(hdsp);
-		
+			if ((err = snd_hdsp_enable_io(hdsp)) < 0) {
+				return err;
+			}
+			
+			snd_hdsp_initialize_channels(hdsp);		
 			snd_hdsp_initialize_midi_flush(hdsp);
 	    
 			if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
-				snd_printk("error creating alsa devices\n");
+				snd_printk("Hammerfall-DSP: error creating alsa devices\n");
 			    return err;
 			}
 		}
 		break;
 	}
-#endif
 	case SNDRV_HDSP_IOCTL_GET_MIXER: {
 		hdsp_mixer_t __user *mixer = (hdsp_mixer_t __user *)argp;
 		if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE))
@@ -4794,6 +4751,7 @@ static int snd_hdsp_enable_io (hdsp_t *h
 	int i;
 	
 	if (hdsp_fifo_wait (hdsp, 0, 100)) {
+		snd_printk("Hammerfall-DSP: enable_io fifo_wait failed\n");
 		return -EIO;
 	}
 	
@@ -4859,24 +4817,25 @@ static int snd_hdsp_create_alsa_devices(
 	int err;
 	
 	if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
-		snd_printk("Error creating pcm interface\n");
+		snd_printk("Hammerfall-DSP: Error creating pcm interface\n");
 		return err;
 	}
 	
 
 	if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
-		snd_printk("Error creating first midi interface\n");
+		snd_printk("Hammerfall-DSP: Error creating first midi interface\n");
 		return err;
 	}
 
-
-	if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
-		snd_printk("Error creating second midi interface\n");
-		return err;
+	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
+		if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
+			snd_printk("Hammerfall-DSP: Error creating second midi interface\n");
+			return err;
+		}
 	}
 
 	if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) {
-		snd_printk("Error creating ctl interface\n");
+		snd_printk("Hammerfall-DSP: Error creating ctl interface\n");
 		return err;
 	}
 
@@ -4889,7 +4848,7 @@ static int snd_hdsp_create_alsa_devices(
 	hdsp->playback_substream = NULL;
 
 	if ((err = snd_hdsp_set_defaults(hdsp)) < 0) {
-		snd_printk("Error setting default values\n");
+		snd_printk("Hammerfall-DSP: Error setting default values\n");
 		return err;
 	}
 	
@@ -4898,7 +4857,7 @@ static int snd_hdsp_create_alsa_devices(
 			hdsp->port, hdsp->irq);
 	    
 		if ((err = snd_card_register(card)) < 0) {
-			snd_printk("error registering card\n");
+			snd_printk("Hammerfall-DSP: error registering card\n");
 			return err;
 		}
 		hdsp->state |= HDSP_InitializationComplete;
@@ -4923,9 +4882,7 @@ static int __devinit hdsp_request_fw_loa
 		if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
 			return 0;
 	}
-	if (hdsp_check_for_iobox (hdsp))
-		return -EIO;
-
+	
 	/* caution: max length of firmware filename is 30! */
 	switch (hdsp->io_type) {
 	case Multiface:
@@ -4941,16 +4898,16 @@ static int __devinit hdsp_request_fw_loa
 			fwfile = "digiface_firmware_rev11.bin";
 		break;
 	default:
-		snd_printk(KERN_ERR "hdsp: invalid io_type %d\n", hdsp->io_type);
+		snd_printk(KERN_ERR "Hammerfall-DSP: invalid io_type %d\n", hdsp->io_type);
 		return -EINVAL;
 	}
 
 	if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
-		snd_printk(KERN_ERR "hdsp: cannot load firmware %s\n", fwfile);
+		snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile);
 		return -ENOENT;
 	}
 	if (fw->size < sizeof(hdsp->firmware_cache)) {
-		snd_printk(KERN_ERR "hdsp: too short firmware size %d (expected %d)\n",
+		snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n",
 			   (int)fw->size, (int)sizeof(hdsp->firmware_cache));
 		release_firmware(fw);
 		return -EINVAL;
@@ -4958,7 +4915,7 @@ static int __devinit hdsp_request_fw_loa
 #ifdef SNDRV_BIG_ENDIAN
 	{
 		int i;
-		u32 *src = (void *)fw->data;
+		u32 *src = (u32*)fw->data;
 		for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++)
 			hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) |
 				((*src & 0x0000ff00) << 8)  |
@@ -4969,17 +4926,25 @@ static int __devinit hdsp_request_fw_loa
 	memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache));
 #endif
 	release_firmware(fw);
-	
+		
 	hdsp->state |= HDSP_FirmwareCached;
 
 	if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
 		return err;
 		
 	if (!(hdsp->state & HDSP_InitializationComplete)) {
+		if ((err = snd_hdsp_enable_io(hdsp)) < 0) {
+			return err;
+		}
+
+		if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) {
+			snd_printk("Hammerfall-DSP: error creating hwdep device\n");
+			return err;
+		}
 		snd_hdsp_initialize_channels(hdsp);
 		snd_hdsp_initialize_midi_flush(hdsp);
 		if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
-			snd_printk("error creating alsa devices\n");
+			snd_printk("Hammerfall-DSP: error creating alsa devices\n");
 			return err;
 		}
 	}
@@ -4988,8 +4953,7 @@ static int __devinit hdsp_request_fw_loa
 #endif
 
 static int __devinit snd_hdsp_create(snd_card_t *card,
-				     hdsp_t *hdsp,
-				     int precise_ptr)
+				     hdsp_t *hdsp)
 {
 	struct pci_dev *pci = hdsp->pci;
 	int err;
@@ -5004,6 +4968,8 @@ static int __devinit snd_hdsp_create(snd
 	hdsp->midi[1].input = NULL;
 	hdsp->midi[0].output = NULL;
 	hdsp->midi[1].output = NULL;
+	hdsp->midi[0].pending = 0;
+	hdsp->midi[1].pending = 0;
 	spin_lock_init(&hdsp->midi[0].lock);
 	spin_lock_init(&hdsp->midi[1].lock);
 	hdsp->iobase = NULL;
@@ -5019,6 +4985,7 @@ static int __devinit snd_hdsp_create(snd
 	tasklet_init(&hdsp->midi_tasklet, hdsp_midi_tasklet, (unsigned long)hdsp);
 	
 	pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
+	hdsp->firmware_rev &= 0xff;
 	
 	/* From Martin Bjoernsen :
 	    "It is important that the card's latency timer register in
@@ -5032,27 +4999,17 @@ static int __devinit snd_hdsp_create(snd
 	strcpy(card->driver, "H-DSP");
 	strcpy(card->mixername, "Xilinx FPGA");
 
-	switch (hdsp->firmware_rev & 0xff) {
-	case 0xa:
-	case 0xb:
-	case 0x32:
+	if (hdsp->firmware_rev < 0xa) {
+		return -ENODEV;
+	} else if (hdsp->firmware_rev < 0x64) {
 		hdsp->card_name = "RME Hammerfall DSP";
-		break;
-
-	case 0x64:
-	case 0x65:
-	case 0x68:
+	} else if (hdsp->firmware_rev < 0x96) {
 		hdsp->card_name = "RME HDSP 9652";
 		is_9652 = 1;
-		break;
-	case 0x96:
-	case 0x97:
+	} else {
 		hdsp->card_name = "RME HDSP 9632";
 		hdsp->max_channels = 16;
-		is_9632 = 1;
-		break;
-	default:
-		return -ENODEV;
+		is_9632 = 1;	
 	}
 
 	if ((err = pci_enable_device(pci)) < 0) {
@@ -5065,56 +5022,65 @@ static int __devinit snd_hdsp_create(snd
 		return err;
 	hdsp->port = pci_resource_start(pci, 0);
 	if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) {
-		snd_printk("unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
+		snd_printk("Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
 		return -EBUSY;
 	}
 
 	if (request_irq(pci->irq, snd_hdsp_interrupt, SA_INTERRUPT|SA_SHIRQ, "hdsp", (void *)hdsp)) {
-		snd_printk("unable to use IRQ %d\n", pci->irq);
+		snd_printk("Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
 		return -EBUSY;
 	}
 
 	hdsp->irq = pci->irq;
-	hdsp->precise_ptr = precise_ptr;
+	hdsp->precise_ptr = 1;
+	hdsp->use_midi_tasklet = 1;
 
 	if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) {
 		return err;
 	}
 	
-	if (!is_9652 && !is_9632 && hdsp_check_for_iobox (hdsp)) {
-		/* no iobox connected, we defer initialization */
-		snd_printk("card initialization pending : waiting for firmware\n");
-		if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
-			return err;
+	if (!is_9652 && !is_9632) {
+		/* we wait 2 seconds to let freshly inserted cardbus cards do their hardware init */
+ 		if ((1000 / HZ) < 2000) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((2000 * HZ + 999) / 1000);
+		} else {
+			mdelay(2000);
+		}
+
+		if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
+#ifdef HDSP_FW_LOADER
+			if ((err = hdsp_request_fw_loader(hdsp)) < 0) {
+				/* we don't fail as this can happen
+				   if userspace is not ready for
+				   firmware upload
+				*/
+				snd_printk("Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n");
+			} else {
+				/* init is complete, we return */
+				return 0;
+			}
+#endif
+			/* no iobox connected, we defer initialization */
+			snd_printk("Hammerfall-DSP: card initialization pending : waiting for firmware\n");
+			if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
+				return err;
+			}
+			return 0;
+		} else {
+			snd_printk("Hammerfall-DSP: Firmware already present, initializing card.\n");	    
+			if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) {
+				hdsp->io_type = Multiface;
+			} else {
+				hdsp->io_type = Digiface;
+			}
 		}
-		return 0;
 	}
 	
 	if ((err = snd_hdsp_enable_io(hdsp)) != 0) {
 		return err;
 	}
 	
-	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
-#ifdef HDSP_FW_LOADER
-		if ((err = hdsp_request_fw_loader(hdsp)) < 0)
-			return err;
-#else
-		snd_printk("card initialization pending : waiting for firmware\n");
-		if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
-			return err;
-		}
-		return 0;
-#endif
-	} 
-	
-	snd_printk("Firmware already loaded, initializing card.\n");
-	
-	if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) {
-		hdsp->io_type = Multiface;
-	} else {
-		hdsp->io_type = Digiface;
-	}
-
 	if (is_9652) {
 	        hdsp->io_type = H9652;
 	}
@@ -5143,6 +5109,7 @@ static int snd_hdsp_free(hdsp_t *hdsp)
 {
 	if (hdsp->port) {
 		/* stop the audio, and cancel all interrupts */
+		tasklet_kill(&hdsp->midi_tasklet);
 		hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable);
 		hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register);
 	}
@@ -5194,7 +5161,7 @@ static int __devinit snd_hdsp_probe(stru
 	hdsp->pci = pci;
 	snd_card_set_dev(card, &pci->dev);
 
-	if ((err = snd_hdsp_create(card, hdsp, precise_ptr[dev])) < 0) {
+	if ((err = snd_hdsp_create(card, hdsp)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -46,6 +46,10 @@ MODULE_DESCRIPTION("S3 SonicVibes PCI");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 #ifndef PCI_VENDOR_ID_S3
 #define PCI_VENDOR_ID_S3             0x5333
 #endif
@@ -242,8 +246,8 @@ struct _snd_sonicvibes {
 	snd_kcontrol_t *master_mute;
 	snd_kcontrol_t *master_volume;
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 };
 
@@ -1163,15 +1167,47 @@ static void __devinit snd_sonicvibes_pro
 
  */
 
+#ifdef SUPPORT_JOYSTICK
 static snd_kcontrol_new_t snd_sonicvibes_game_control __devinitdata =
 SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0);
 
-static int snd_sonicvibes_free(sonicvibes_t *sonic)
+static int __devinit snd_sonicvibes_create_gameport(sonicvibes_t *sonic)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (sonic->gameport.io)
-		gameport_unregister_port(&sonic->gameport);
+	struct gameport *gp;
+
+	sonic->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "SonicVibes Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(sonic->pci));
+	gameport_set_dev_parent(gp, &sonic->pci->dev);
+	gp->io = sonic->game_port;
+
+	gameport_register_port(gp);
+
+	snd_ctl_add(sonic->card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
+
+	return 0;
+}
+
+static void snd_sonicvibes_free_gameport(sonicvibes_t *sonic)
+{
+	if (sonic->gameport) {
+		gameport_unregister_port(sonic->gameport);
+		sonic->gameport = NULL;
+	}
+}
+#else
+static inline int snd_sonicvibes_create_gameport(sonicvibes_t *sonic) { return -ENOSYS; }
+static inline void snd_sonicvibes_free_gameport(sonicvibes_t *sonic) { }
 #endif
+
+static int snd_sonicvibes_free(sonicvibes_t *sonic)
+{
+	snd_sonicvibes_free_gameport(sonic);
 	pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port);
 	pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port);
 	if (sonic->irq >= 0)
@@ -1332,7 +1368,6 @@ static int __devinit snd_sonicvibes_crea
 	snd_sonicvibes_debug(sonic);
 #endif
 	sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION);
-	snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) {
 		snd_sonicvibes_free(sonic);
@@ -1459,10 +1494,8 @@ static int __devinit snd_sonic_probe(str
 		snd_card_free(card);
 		return err;
 	}
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	sonic->gameport.io = sonic->game_port;
-	gameport_register_port(&sonic->gameport);
-#endif
+
+	snd_sonicvibes_create_gameport(sonic);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -157,7 +157,7 @@ static int __devinit snd_trident_probe(s
 	}
 #endif
 
-	snd_trident_gameport(trident);
+	snd_trident_create_gameport(trident);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -48,8 +48,8 @@ static int snd_trident_pcm_mixer_build(t
 static int snd_trident_pcm_mixer_free(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream);
 static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #ifdef CONFIG_PM
-static int snd_trident_suspend(snd_card_t *card, unsigned int state);
-static int snd_trident_resume(snd_card_t *card, unsigned int state);
+static int snd_trident_suspend(snd_card_t *card, pm_message_t state);
+static int snd_trident_resume(snd_card_t *card);
 #endif
 static int snd_trident_sis_reset(trident_t *trident);
 
@@ -3110,37 +3110,28 @@ static int __devinit snd_trident_mixer(t
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_trident_gameport {
-	struct gameport info;
-	trident_t *chip;
-} trident_gameport_t;
-
 static unsigned char snd_trident_gameport_read(struct gameport *gameport)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	trident_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return 0);
 	return inb(TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
 static void snd_trident_gameport_trigger(struct gameport *gameport)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	trident_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return);
 	outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
 static int snd_trident_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
+	trident_t *chip = gameport_get_port_data(gameport);
 	int i;
 
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	snd_assert(chip, return 0);
 
 	*buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf;
 
@@ -3154,10 +3145,9 @@ static int snd_trident_gameport_cooked_r
 
 static int snd_trident_gameport_open(struct gameport *gameport, int mode)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return -1);
-	chip = gp->chip;
+	trident_t *chip = gameport_get_port_data(gameport);
+
+	snd_assert(chip, return 0);
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -3173,30 +3163,42 @@ static int snd_trident_gameport_open(str
 	}
 }
 
-void __devinit snd_trident_gameport(trident_t *chip)
+int __devinit snd_trident_create_gameport(trident_t *chip)
 {
-	trident_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk("cannot allocate gameport area\n");
-		return;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "trident: cannot allocate memory for gameport\n");
+		return -ENOMEM;
 	}
-	memset(gp, 0, sizeof(*gp));
-	gp->chip = chip;
-	gp->info.fuzz = 64;
-	gp->info.read = snd_trident_gameport_read;
-	gp->info.trigger = snd_trident_gameport_trigger;
-	gp->info.cooked_read = snd_trident_gameport_cooked_read;
-	gp->info.open = snd_trident_gameport_open;
-	chip->gameport = gp;
 
-	gameport_register_port(&gp->info);
+	gameport_set_name(gp, "Trident 4DWave");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+
+	gameport_set_port_data(gp, chip);
+	gp->fuzz = 64;
+	gp->read = snd_trident_gameport_read;
+	gp->trigger = snd_trident_gameport_trigger;
+	gp->cooked_read = snd_trident_gameport_cooked_read;
+	gp->open = snd_trident_gameport_open;
+
+	gameport_register_port(gp);
+
+	return 0;
 }
 
-#else
-void __devinit snd_trident_gameport(trident_t *chip)
+static inline void snd_trident_free_gameport(trident_t *chip)
 {
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
 }
+#else
+int __devinit snd_trident_create_gameport(trident_t *chip) { return -ENOSYS; }
+static inline void snd_trident_free_gameport(trident_t *chip) { }
 #endif /* CONFIG_GAMEPORT */
 
 /*
@@ -3661,12 +3663,7 @@ int __devinit snd_trident_create(snd_car
 
 static int snd_trident_free(trident_t *trident)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (trident->gameport) {
-		gameport_unregister_port(&trident->gameport->info);
-		kfree(trident->gameport);
-	}
-#endif
+	snd_trident_free_gameport(trident);
 	snd_trident_disable_eso(trident);
 	// Disable S/PDIF out
 	if (trident->device == TRIDENT_DEVICE_ID_NX)
@@ -3921,7 +3918,7 @@ static void snd_trident_clear_voices(tri
 }
 
 #ifdef CONFIG_PM
-static int snd_trident_suspend(snd_card_t *card, unsigned int state)
+static int snd_trident_suspend(snd_card_t *card, pm_message_t state)
 {
 	trident_t *trident = card->pm_private_data;
 
@@ -3947,7 +3944,7 @@ static int snd_trident_suspend(snd_card_
 	return 0;
 }
 
-static int snd_trident_resume(snd_card_t *card, unsigned int state)
+static int snd_trident_resume(snd_card_t *card)
 {
 	trident_t *trident = card->pm_private_data;
 
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c
--- a/sound/pci/trident/trident_synth.c
+++ b/sound/pci/trident/trident_synth.c
@@ -525,7 +525,7 @@ static int snd_trident_simple_put_sample
 	if (trident->synth.current_size + size > trident->synth.max_size)
 		return -ENOMEM;
 
-	if (verify_area(VERIFY_READ, data, size))
+	if (!access_ok(VERIFY_READ, data, size))
 		return -EFAULT;
 
 	if (trident->tlb.entries) {
@@ -570,7 +570,7 @@ static int snd_trident_simple_get_sample
 		shift++;
 	size <<= shift;
 
-	if (verify_area(VERIFY_WRITE, data, size))
+	if (!access_ok(VERIFY_WRITE, data, size))
 		return -EFAULT;
 
 	/* FIXME: not implemented yet */
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -367,7 +367,7 @@ struct _snd_via82xx {
 	unsigned int mpu_port_saved;
 #endif
 
-	unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
+	unsigned char playback_volume[2]; /* for VIA8233/C/8235; default = 0 */
 
 	unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */
 
@@ -394,8 +394,7 @@ struct _snd_via82xx {
 	snd_info_entry_t *proc_entry;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 };
 
@@ -942,8 +941,8 @@ static int snd_via8233_playback_prepare(
 	snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
 	snd_via82xx_channel_reset(chip, viadev);
 	snd_via82xx_set_table_ptr(chip, viadev);
-	outb(chip->playback_volume[viadev->reg_offset / 0x10][0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L));
-	outb(chip->playback_volume[viadev->reg_offset / 0x10][1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R));
+	outb(chip->playback_volume[0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L));
+	outb(chip->playback_volume[1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R));
 	outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */
 	     (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | /* stereo */
 	     rbits | /* rate */
@@ -1497,17 +1496,15 @@ static int snd_via8233_dxs_volume_info(s
 static int snd_via8233_dxs_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	via82xx_t *chip = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
-	ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0];
-	ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1];
+	ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[0];
+	ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[1];
 	return 0;
 }
 
 static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	via82xx_t *chip = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
-	unsigned long port = chip->port + 0x10 * idx;
+	unsigned int idx;
 	unsigned char val;
 	int i, change = 0;
 
@@ -1516,19 +1513,21 @@ static int snd_via8233_dxs_volume_put(sn
 		if (val > VIA_DXS_MAX_VOLUME)
 			val = VIA_DXS_MAX_VOLUME;
 		val = VIA_DXS_MAX_VOLUME - val;
-		change |= val != chip->playback_volume[idx][i];
-		if (change) {
-			chip->playback_volume[idx][i] = val;
-			outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i);
+		if (val != chip->playback_volume[i]) {
+			change = 1;
+			chip->playback_volume[i] = val;
+			for (idx = 0; idx < 4; idx++) {
+				unsigned long port = chip->port + 0x10 * idx;
+				outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i);
+			}
 		}
 	}
 	return change;
 }
 
 static snd_kcontrol_new_t snd_via8233_dxs_volume_control __devinitdata = {
-	.name = "VIA DXS Playback Volume",
+	.name = "PCM Playback Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.count = 4,
 	.info = snd_via8233_dxs_volume_info,
 	.get = snd_via8233_dxs_volume_get,
 	.put = snd_via8233_dxs_volume_put,
@@ -1635,11 +1634,70 @@ static int __devinit snd_via82xx_mixer_n
 	return 0;
 }
 
+#ifdef SUPPORT_JOYSTICK
+#define JOYSTICK_ADDR	0x200
+static int __devinit snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy)
+{
+	struct gameport *gp;
+	struct resource *r;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport");
+	if (!r) {
+		printk(KERN_WARNING "via82xx: cannot reserve joystick port 0x%#x\n", JOYSTICK_ADDR);
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "VIA686 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->io = JOYSTICK_ADDR;
+	gameport_set_port_data(gp, r);
+
+	/* Enable legacy joystick port */
+	*legacy |= VIA_FUNC_ENABLE_GAME;
+	pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, *legacy);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+static void snd_via686_free_gameport(via82xx_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = gameport_get_port_data(chip->gameport);
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy)
+{
+	return -ENOSYS;
+}
+static inline void snd_via686_free_gameport(via82xx_t *chip) { }
+#endif
+
+
 /*
  *
  */
 
-static int snd_via8233_init_misc(via82xx_t *chip, int dev)
+static int __devinit snd_via8233_init_misc(via82xx_t *chip, int dev)
 {
 	int i, err, caps;
 	unsigned char val;
@@ -1657,9 +1715,18 @@ static int snd_via8233_init_misc(via82xx
 			return err;
 	}
 	if (chip->chip_type != TYPE_VIA8233A) {
-		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
-		if (err < 0)
-			return err;
+		/* when no h/w PCM volume control is found, use DXS volume control
+		 * as the PCM vol control
+		 */
+		snd_ctl_elem_id_t sid;
+		memset(&sid, 0, sizeof(sid));
+		strcpy(sid.name, "PCM Playback Volume");
+		sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		if (! snd_ctl_find_id(chip->card, &sid)) {
+			err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
+			if (err < 0)
+				return err;
+		}
 	}
 
 	/* select spdif data slot 10/11 */
@@ -1671,7 +1738,7 @@ static int snd_via8233_init_misc(via82xx
 	return 0;
 }
 
-static int snd_via686_init_misc(via82xx_t *chip, int dev)
+static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev)
 {
 	unsigned char legacy, legacy_cfg;
 	int rev_h = 0;
@@ -1718,15 +1785,6 @@ static int snd_via686_init_misc(via82xx_
 		mpu_port[dev] = 0;
 	}
 
-#ifdef SUPPORT_JOYSTICK
-#define JOYSTICK_ADDR	0x200
-	if (joystick[dev] &&
-	    (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport")) != NULL) {
-		legacy |= VIA_FUNC_ENABLE_GAME;
-		chip->gameport.io = JOYSTICK_ADDR;
-	}
-#endif
-
 	pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy);
 	pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
 	if (chip->mpu_res) {
@@ -1741,10 +1799,7 @@ static int snd_via686_init_misc(via82xx_
 		pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy);
 	}
 
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick)
-		gameport_register_port(&chip->gameport);
-#endif
+	snd_via686_create_gameport(chip, dev, &legacy);
 
 #ifdef CONFIG_PM
 	chip->legacy_saved = legacy;
@@ -1781,16 +1836,12 @@ static void __devinit snd_via82xx_proc_i
  *
  */
 
-static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
+static int snd_via82xx_chip_init(via82xx_t *chip)
 {
-	ac97_t ac97;
 	unsigned int val;
 	int max_count;
 	unsigned char pval;
 
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.private_data = chip;
-
 #if 0 /* broken on K7M? */
 	if (chip->chip_type == TYPE_VIA686)
 		/* disable all legacy ports */
@@ -1842,11 +1893,6 @@ static int __devinit snd_via82xx_chip_in
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
 		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
 
-	/* and then reset codec.. */
-	snd_via82xx_codec_ready(chip, 0);
-	snd_via82xx_codec_write(&ac97, AC97_RESET, 0x0000);
-	snd_via82xx_codec_read(&ac97, 0);
-
 #if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
@@ -1888,6 +1934,15 @@ static int __devinit snd_via82xx_chip_in
 		}
 	}
 
+	if (chip->chip_type != TYPE_VIA8233A) {
+		int i, idx;
+		for (idx = 0; idx < 4; idx++) {
+			unsigned long port = chip->port + 0x10 * idx;
+			for (i = 0; i < 2; i++)
+				outb(chip->playback_volume[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i);
+		}
+	}
+
 	return 0;
 }
 
@@ -1895,7 +1950,7 @@ static int __devinit snd_via82xx_chip_in
 /*
  * power management
  */
-static int snd_via82xx_suspend(snd_card_t *card, unsigned int state)
+static int snd_via82xx_suspend(snd_card_t *card, pm_message_t state)
 {
 	via82xx_t *chip = card->pm_private_data;
 	int i;
@@ -1920,10 +1975,10 @@ static int snd_via82xx_suspend(snd_card_
 	return 0;
 }
 
-static int snd_via82xx_resume(snd_card_t *card, unsigned int state)
+static int snd_via82xx_resume(snd_card_t *card)
 {
 	via82xx_t *chip = card->pm_private_data;
-	int idx, i;
+	int i;
 
 	pci_enable_device(chip->pci);
 	pci_set_power_state(chip->pci, 0);
@@ -1939,11 +1994,6 @@ static int snd_via82xx_resume(snd_card_t
 		pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, chip->spdif_ctrl_saved);
 		outb(chip->capture_src_saved[0], chip->port + VIA_REG_CAPTURE_CHANNEL);
 		outb(chip->capture_src_saved[1], chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
-		for (idx = 0; idx < 4; idx++) {
-			unsigned long port = chip->port + 0x10 * idx;
-			for (i = 0; i < 2; i++)
-				outb(chip->playback_volume[idx][i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i);
-		}
 	}
 
 	snd_ac97_resume(chip->ac97);
@@ -1973,14 +2023,9 @@ static int snd_via82xx_free(via82xx_t *c
 		kfree_nocheck(chip->mpu_res);
 	}
 	pci_release_regions(chip->pci);
+
 	if (chip->chip_type == TYPE_VIA686) {
-#ifdef SUPPORT_JOYSTICK
-		if (chip->res_joystick) {
-			gameport_unregister_port(&chip->gameport);
-			release_resource(chip->res_joystick);
-			kfree_nocheck(chip->res_joystick);
-		}
-#endif
+		snd_via686_free_gameport(chip);
 		pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy);
 		pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg);
 	}
@@ -2114,6 +2159,7 @@ static int __devinit check_dxs_list(stru
 		{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
 		{ .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
 		{ .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
+		{ .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
 		{ .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
 		{ .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
 		{ .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -55,7 +55,7 @@ MODULE_DESCRIPTION("VIA VT82xx modem");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C modem,pci}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
@@ -940,14 +940,10 @@ static void __devinit snd_via82xx_proc_i
 
 static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
 {
-	ac97_t ac97;
 	unsigned int val;
 	int max_count;
 	unsigned char pval;
 
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.private_data = chip;
-
 	pci_read_config_byte(chip->pci, VIA_MC97_CTRL, &pval);
 	if((pval & VIA_MC97_CTRL_INIT) != VIA_MC97_CTRL_INIT) {
 		pci_write_config_byte(chip->pci, 0x44, pval|VIA_MC97_CTRL_INIT);
@@ -996,13 +992,6 @@ static int __devinit snd_via82xx_chip_in
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
 		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
 
-	/* and then reset codec.. */
-#if 0 /* do we need it? when? */
-	snd_via82xx_codec_ready(chip, 0);
-	snd_via82xx_codec_write(&ac97, AC97_RESET, 0x0000);
-	snd_via82xx_codec_read(&ac97, 0);
-#endif
-
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
 				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
@@ -1034,7 +1023,7 @@ static int __devinit snd_via82xx_chip_in
 /*
  * power management
  */
-static int snd_via82xx_suspend(snd_card_t *card, unsigned int state)
+static int snd_via82xx_suspend(snd_card_t *card, pm_message_t state)
 {
 	via82xx_t *chip = card->pm_private_data;
 	int i;
@@ -1051,7 +1040,7 @@ static int snd_via82xx_suspend(snd_card_
 	return 0;
 }
 
-static int snd_via82xx_resume(snd_card_t *card, unsigned int state)
+static int snd_via82xx_resume(snd_card_t *card)
 {
 	via82xx_t *chip = card->pm_private_data;
 	int i;
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -22,6 +22,7 @@
 
 #include <sound/driver.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/control.h>
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -79,6 +79,97 @@ static struct pci_device_id snd_ymfpci_i
 
 MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids);
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_ymfpci_create_gameport(ymfpci_t *chip, int dev,
+						int legacy_ctrl, int legacy_ctrl2)
+{
+	struct gameport *gp;
+	struct resource *r = NULL;
+	int io_port = joystick_port[dev];
+
+	if (!io_port)
+		return -ENODEV;
+
+	if (chip->pci->device >= 0x0010) { /* YMF 744/754 */
+
+		if (io_port == 1) {
+			/* auto-detect */
+			if (!(io_port = pci_resource_start(chip->pci, 2)))
+				return -ENODEV;
+		}
+	} else {
+		if (io_port == 1) {
+			/* auto-detect */
+			for (io_port = 0x201; io_port <= 0x205; io_port++) {
+				if (io_port == 0x203)
+					continue;
+				if ((r = request_region(io_port, 1, "YMFPCI gameport")) != NULL)
+					break;
+			}
+			if (!r) {
+				printk(KERN_ERR "ymfpci: no gameport ports available\n");
+				return -EBUSY;
+			}
+		}
+		switch (io_port) {
+		case 0x201: legacy_ctrl2 |= 0 << 6; break;
+		case 0x202: legacy_ctrl2 |= 1 << 6; break;
+		case 0x204: legacy_ctrl2 |= 2 << 6; break;
+		case 0x205: legacy_ctrl2 |= 3 << 6; break;
+		default:
+			printk(KERN_ERR "ymfpci: invalid joystick port %#x", io_port);
+			return -EINVAL;
+		}
+	}
+
+	if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) {
+		printk(KERN_ERR "ymfpci: joystick port %#x is in use.\n", io_port);
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+
+	gameport_set_name(gp, "Yamaha YMF Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gameport_set_dev_parent(gp, &chip->pci->dev);
+	gp->io = io_port;
+	gameport_set_port_data(gp, r);
+
+	if (chip->pci->device >= 0x0010) /* YMF 744/754 */
+		pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, io_port);
+
+	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, legacy_ctrl | YMFPCI_LEGACY_JPEN);
+	pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+void snd_ymfpci_free_gameport(ymfpci_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = gameport_get_port_data(chip->gameport);
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_ymfpci_create_gameport(ymfpci_t *chip, int dev, int l, int l2) { return -ENOSYS; }
+void snd_ymfpci_free_gameport(ymfpci_t *chip) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
 					   const struct pci_device_id *pci_id)
 {
@@ -86,9 +177,6 @@ static int __devinit snd_card_ymfpci_pro
 	snd_card_t *card;
 	struct resource *fm_res = NULL;
 	struct resource *mpu_res = NULL;
-#ifdef SUPPORT_JOYSTICK
-	struct resource *joystick_res = NULL;
-#endif
 	ymfpci_t *chip;
 	opl3_t *opl3;
 	char *str;
@@ -138,17 +226,6 @@ static int __devinit snd_card_ymfpci_pro
 			legacy_ctrl |= YMFPCI_LEGACY_MEN;
 			pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]);
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_port[dev] == 1) {
-			/* auto-detect */
-			joystick_port[dev] = pci_resource_start(pci, 2);
-		}
-		if (joystick_port[dev] > 0 &&
-		    (joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport")) != NULL) {
-			legacy_ctrl |= YMFPCI_LEGACY_JPEN;
-			pci_write_config_word(pci, PCIR_DSXG_JOYBASE, joystick_port[dev]);
-		}
-#endif
 	} else {
 		switch (fm_port[dev]) {
 		case 0x388: legacy_ctrl2 |= 0; break;
@@ -178,34 +255,6 @@ static int __devinit snd_card_ymfpci_pro
 			legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO;
 			mpu_port[dev] = 0;
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_port[dev] == 1) {
-			/* auto-detect */
-			long p;
-			for (p = 0x201; p <= 0x205; p++) {
-				if (p == 0x203) continue;
-				if ((joystick_res = request_region(p, 1, "YMFPCI gameport")) != NULL)
-					break;
-			}
-			if (joystick_res)
-				joystick_port[dev] = p;
-		}
-		switch (joystick_port[dev]) {
-		case 0x201: legacy_ctrl2 |= 0 << 6; break;
-		case 0x202: legacy_ctrl2 |= 1 << 6; break;
-		case 0x204: legacy_ctrl2 |= 2 << 6; break;
-		case 0x205: legacy_ctrl2 |= 3 << 6; break;
-		default: joystick_port[dev] = 0; break;
-		}
-		if (! joystick_res && joystick_port[dev] > 0)
-			joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport");
-		if (joystick_res) {
-			legacy_ctrl |= YMFPCI_LEGACY_JPEN;
-		} else {
-			legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO;
-			joystick_port[dev] = 0;
-		}
-#endif
 	}
 	if (mpu_res) {
 		legacy_ctrl |= YMFPCI_LEGACY_MIEN;
@@ -226,19 +275,10 @@ static int __devinit snd_card_ymfpci_pro
 			release_resource(fm_res);
 			kfree_nocheck(fm_res);
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_res) {
-			release_resource(joystick_res);
-			kfree_nocheck(joystick_res);
-		}
-#endif
 		return err;
 	}
 	chip->fm_res = fm_res;
 	chip->mpu_res = mpu_res;
-#ifdef SUPPORT_JOYSTICK
-	chip->joystick_res = joystick_res;
-#endif
 	strcpy(card->driver, str);
 	sprintf(card->shortname, "Yamaha DS-XG (%s)", str);
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
@@ -292,12 +332,8 @@ static int __devinit snd_card_ymfpci_pro
 			return err;
 		}
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (chip->joystick_res) {
-		chip->gameport.io = joystick_port[dev];
-		gameport_register_port(&chip->gameport);
-	}
-#endif
+
+	snd_ymfpci_create_gameport(chip, dev, legacy_ctrl, legacy_ctrl2);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2079,14 +2079,7 @@ static int snd_ymfpci_free(ymfpci_t *chi
 		release_resource(chip->fm_res);
 		kfree_nocheck(chip->fm_res);
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (chip->joystick_res) {
-		if (chip->gameport.io)
-			gameport_unregister_port(&chip->gameport);
-		release_resource(chip->joystick_res);
-		kfree_nocheck(chip->joystick_res);
-	}
-#endif
+	snd_ymfpci_free_gameport(chip);
 	if (chip->reg_area_virt)
 		iounmap(chip->reg_area_virt);
 	if (chip->work_ptr.area)
@@ -2142,7 +2135,7 @@ static int saved_regs_index[] = {
 };
 #define YDSXGR_NUM_SAVED_REGS	ARRAY_SIZE(saved_regs_index)
 
-static int snd_ymfpci_suspend(snd_card_t *card, unsigned int state)
+static int snd_ymfpci_suspend(snd_card_t *card, pm_message_t state)
 {
 	ymfpci_t *chip = card->pm_private_data;
 	unsigned int i;
@@ -2161,7 +2154,7 @@ static int snd_ymfpci_suspend(snd_card_t
 	return 0;
 }
 
-static int snd_ymfpci_resume(snd_card_t *card, unsigned int state)
+static int snd_ymfpci_resume(snd_card_t *card)
 {
 	ymfpci_t *chip = card->pm_private_data;
 	unsigned int i;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -272,12 +272,17 @@ static void pdacf_config(dev_link_t *lin
 	client_handle_t handle = link->handle;
 	pdacf_t *pdacf = link->priv;
 	tuple_t tuple;
-	cisparse_t parse;
+	cisparse_t *parse = NULL;
 	config_info_t conf;
 	u_short buf[32];
 	int last_fn, last_ret;
 
 	snd_printdd(KERN_DEBUG "pdacf_config called\n");
+	parse = kmalloc(sizeof(*parse), GFP_KERNEL);
+	if (! parse) {
+		snd_printk(KERN_ERR "pdacf_config: cannot allocate\n");
+		return;
+	}
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	tuple.Attributes = 0;
 	tuple.TupleData = (cisdata_t *)buf;
@@ -286,9 +291,10 @@ static void pdacf_config(dev_link_t *lin
 	tuple.DesiredTuple = CISTPL_CONFIG;
 	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
 	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-	link->conf.ConfigBase = parse.config.base;
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	link->conf.ConfigBase = parse->config.base;
 	link->conf.ConfigIndex = 0x5;
+	kfree(parse);
 
 	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
 	link->conf.Vcc = conf.Vcc;
@@ -342,7 +348,7 @@ static int pdacf_event(event_t event, in
 		link->state |= DEV_SUSPEND;
 		if (chip) {
 			snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n");
-			snd_pdacf_suspend(chip->card, 0);
+			snd_pdacf_suspend(chip->card, PMSG_SUSPEND);
 		}
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
@@ -361,7 +367,7 @@ static int pdacf_event(event_t event, in
 			pcmcia_request_configuration(link->handle, &link->conf);
 			if (chip) {
 				snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n");
-				snd_pdacf_resume(chip->card, 0);
+				snd_pdacf_resume(chip->card);
 			}
 		}
 		snd_printdd(KERN_DEBUG "resume done!\n");
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
@@ -134,8 +134,8 @@ pdacf_t *snd_pdacf_create(snd_card_t *ca
 int snd_pdacf_ak4117_create(pdacf_t *pdacf);
 void snd_pdacf_powerdown(pdacf_t *chip);
 #ifdef CONFIG_PM
-int snd_pdacf_suspend(snd_card_t *card, unsigned int state);
-int snd_pdacf_resume(snd_card_t *card, unsigned int state);
+int snd_pdacf_suspend(snd_card_t *card, pm_message_t state);
+int snd_pdacf_resume(snd_card_t *card);
 #endif
 int snd_pdacf_pcm_new(pdacf_t *chip);
 irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -255,7 +255,7 @@ void snd_pdacf_powerdown(pdacf_t *chip)
 
 #ifdef CONFIG_PM
 
-int snd_pdacf_suspend(snd_card_t *card, unsigned int state)
+int snd_pdacf_suspend(snd_card_t *card, pm_message_t state)
 {
 	pdacf_t *chip = card->pm_private_data;
 	u16 val;
@@ -275,7 +275,7 @@ static inline int check_signal(pdacf_t *
 	return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0;
 }
 
-int snd_pdacf_resume(snd_card_t *card, unsigned int state)
+int snd_pdacf_resume(snd_card_t *card)
 {
 	pdacf_t *chip = card->pm_private_data;
 	int timeout = 40;
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
--- a/sound/pcmcia/vx/vx_entry.c
+++ b/sound/pcmcia/vx/vx_entry.c
@@ -346,7 +346,7 @@ static int vxpocket_event(event_t event,
 		link->state |= DEV_SUSPEND;
 		if (chip && chip->card->pm_suspend) {
 			snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
-			chip->card->pm_suspend(chip->card, 0);
+			chip->card->pm_suspend(chip->card, PMSG_SUSPEND);
 		}
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
@@ -366,7 +366,7 @@ static int vxpocket_event(event_t event,
 			pcmcia_request_configuration(link->handle, &link->conf);
 			if (chip && chip->card->pm_resume) {
 				snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
-				chip->card->pm_resume(chip->card, 0);
+				chip->card->pm_resume(chip->card);
 			}
 		}
 		snd_printdd(KERN_DEBUG "resume done!\n");
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -22,6 +22,7 @@
 
 #include <sound/driver.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <asm/io.h>
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -11,7 +11,7 @@ comment "ALSA PowerMac requires INPUT"
 
 config SND_POWERMAC
 	tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
-	depends on SND && I2C && INPUT
+	depends on SND && I2C && INPUT && PPC_PMAC
 	select SND_PCM
 	help
 	  Say Y here to include support for the integrated sound device.
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
--- a/sound/ppc/Makefile
+++ b/sound/ppc/Makefile
@@ -3,7 +3,7 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
+snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o toonie.o keywest.o beep.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -24,6 +24,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include "pmac.h"
@@ -35,7 +37,7 @@ struct snd_pmac_beep {
 	int hz;
 	int nsamples;
 	short *buf;		/* allocated wave buffer */
-	unsigned long addr;	/* physical address of buffer */
+	dma_addr_t addr;	/* physical address of buffer */
 	struct input_dev dev;
 };
 
@@ -217,12 +219,8 @@ int __init snd_pmac_attach_beep(pmac_t *
 		return -ENOMEM;
 
 	memset(beep, 0, sizeof(*beep));
-	beep->buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
-	if (! beep->buf) {
-		kfree(beep);
-		return -ENOMEM;
-	}
-	beep->addr = virt_to_bus(beep->buf);
+	beep->buf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
+					&beep->addr, GFP_KERNEL);
 
 	beep->dev.evbit[0] = BIT(EV_SND);
 	beep->dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
@@ -255,7 +253,8 @@ void snd_pmac_detach_beep(pmac_t *chip)
 {
 	if (chip->beep) {
 		input_unregister_device(&chip->beep->dev);
-		kfree(chip->beep->buf);
+		dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
+				  chip->beep->buf, chip->beep->addr);
 		kfree(chip->beep);
 		chip->beep = NULL;
 	}
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -76,8 +76,6 @@ static int keywest_attach_adapter(struct
 	new_client->flags = 0;
 
 	strcpy(i2c_device_name(new_client), keywest_ctx->name);
-
-	new_client->id = keywest_ctx->id++; /* Automatically unique */
 	keywest_ctx->client = new_client;
 	
 	/* Tell the i2c layer a new client has arrived */
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -27,21 +27,20 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include "pmac.h"
 #include <sound/pcm_params.h>
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
 #include <asm/pmac_feature.h>
-#else
-#include <asm/feature.h>
-#endif
+#include <asm/pci-bridge.h>
 
 
 #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
 static int snd_pmac_register_sleep_notifier(pmac_t *chip);
 static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
-static int snd_pmac_suspend(snd_card_t *card, unsigned int state);
-static int snd_pmac_resume(snd_card_t *card, unsigned int state);
+static int snd_pmac_suspend(snd_card_t *card, pm_message_t state);
+static int snd_pmac_resume(snd_card_t *card);
 #endif
 
 
@@ -57,22 +56,29 @@ static int tumbler_freqs[1] = {
 /*
  * allocate DBDMA command arrays
  */
-static int snd_pmac_dbdma_alloc(pmac_dbdma_t *rec, int size)
+static int snd_pmac_dbdma_alloc(pmac_t *chip, pmac_dbdma_t *rec, int size)
 {
-	rec->space = kmalloc(sizeof(struct dbdma_cmd) * (size + 1), GFP_KERNEL);
+	unsigned int rsize = sizeof(struct dbdma_cmd) * (size + 1);
+
+	rec->space = dma_alloc_coherent(&chip->pdev->dev, rsize,
+					&rec->dma_base, GFP_KERNEL);
 	if (rec->space == NULL)
 		return -ENOMEM;
 	rec->size = size;
-	memset(rec->space, 0, sizeof(struct dbdma_cmd) * (size + 1));
+	memset(rec->space, 0, rsize);
 	rec->cmds = (void __iomem *)DBDMA_ALIGN(rec->space);
-	rec->addr = virt_to_bus(rec->cmds);
+	rec->addr = rec->dma_base + (unsigned long)((char *)rec->cmds - (char *)rec->space);
+
 	return 0;
 }
 
-static void snd_pmac_dbdma_free(pmac_dbdma_t *rec)
+static void snd_pmac_dbdma_free(pmac_t *chip, pmac_dbdma_t *rec)
 {
-	if (rec)
-		kfree(rec->space);
+	if (rec) {
+		unsigned int rsize = sizeof(struct dbdma_cmd) * (rec->size + 1);
+
+		dma_free_coherent(&chip->pdev->dev, rsize, rec->space, rec->dma_base);
+	}
 }
 
 
@@ -237,7 +243,7 @@ static int snd_pmac_pcm_prepare(pmac_t *
 	/* continuous DMA memory type doesn't provide the physical address,
 	 * so we need to resolve the address here...
 	 */
-	offset = virt_to_bus(runtime->dma_area);
+	offset = runtime->dma_addr;
 	for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) {
 		st_le32(&cp->phy_addr, offset);
 		st_le16(&cp->req_count, rec->period_size);
@@ -664,8 +670,8 @@ int __init snd_pmac_pcm_new(pmac_t *chip
 	chip->capture.cur_freqs = chip->freqs_ok;
 
 	/* preallocate 64k buffer */
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 
-					      snd_dma_continuous_data(GFP_KERNEL),
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      &chip->pdev->dev,
 					      64 * 1024, 64 * 1024);
 
 	return 0;
@@ -757,28 +763,10 @@ snd_pmac_ctrl_intr(int irq, void *devid,
 /*
  * a wrapper to feature call for compatibility
  */
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
 static void snd_pmac_sound_feature(pmac_t *chip, int enable)
 {
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
 	ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);
-#else
-	if (chip->is_pbook_G3) {
-		pmu_suspend();
-		feature_clear(chip->node, FEATURE_Sound_power);
-		feature_clear(chip->node, FEATURE_Sound_CLK_enable);
-		big_mdelay(1000); /* XXX */
-		pmu_resume();
-	}
-	if (chip->is_pbook_3400) {
-		feature_set(chip->node, FEATURE_IOBUS_enable);
-		udelay(10);
-	}
-#endif
 }
-#else /* CONFIG_PM && CONFIG_PMAC_PBOOK */
-#define snd_pmac_sound_feature(chip,enable) /**/
-#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
 
 /*
  * release resources
@@ -786,8 +774,6 @@ static void snd_pmac_sound_feature(pmac_
 
 static int snd_pmac_free(pmac_t *chip)
 {
-	int i;
-
 	/* stop sounds */
 	if (chip->initialized) {
 		snd_pmac_dbdma_reset(chip);
@@ -813,9 +799,9 @@ static int snd_pmac_free(pmac_t *chip)
 		free_irq(chip->tx_irq, (void*)chip);
 	if (chip->rx_irq >= 0)
 		free_irq(chip->rx_irq, (void*)chip);
-	snd_pmac_dbdma_free(&chip->playback.cmd);
-	snd_pmac_dbdma_free(&chip->capture.cmd);
-	snd_pmac_dbdma_free(&chip->extra_dma);
+	snd_pmac_dbdma_free(chip, &chip->playback.cmd);
+	snd_pmac_dbdma_free(chip, &chip->capture.cmd);
+	snd_pmac_dbdma_free(chip, &chip->extra_dma);
 	if (chip->macio_base)
 		iounmap(chip->macio_base);
 	if (chip->latch_base)
@@ -826,12 +812,23 @@ static int snd_pmac_free(pmac_t *chip)
 		iounmap(chip->playback.dma);
 	if (chip->capture.dma)
 		iounmap(chip->capture.dma);
+#ifndef CONFIG_PPC64
 	if (chip->node) {
+		int i;
+
 		for (i = 0; i < 3; i++) {
-			if (chip->of_requested & (1 << i))
-				release_OF_resource(chip->node, i);
+			if (chip->of_requested & (1 << i)) {
+				if (chip->is_k2)
+					release_OF_resource(chip->node->parent,
+							    i);
+				else
+					release_OF_resource(chip->node, i);
+			}
 		}
 	}
+#endif /* CONFIG_PPC64 */
+	if (chip->pdev)
+		pci_dev_put(chip->pdev);
 	kfree(chip);
 	return 0;
 }
@@ -879,8 +876,11 @@ static void __init detect_byte_swap(pmac
  */
 static int __init snd_pmac_detect(pmac_t *chip)
 {
-	struct device_node *sound;
+	struct device_node *sound = NULL;
 	unsigned int *prop, l;
+	struct macio_chip* macio;
+
+	u32 layout_id = 0;
 
 	if (_machine != _MACH_Pmac)
 		return -ENODEV;
@@ -906,29 +906,43 @@ static int __init snd_pmac_detect(pmac_t
 		chip->is_pbook_G3 = 1;
 	chip->node = find_devices("awacs");
 	if (chip->node)
-		return 0; /* ok */
+		sound = chip->node;
 
 	/*
 	 * powermac G3 models have a node called "davbus"
 	 * with a child called "sound".
 	 */
-	chip->node = find_devices("davbus");
+	if (!chip->node)
+		chip->node = find_devices("davbus");
 	/*
 	 * if we didn't find a davbus device, try 'i2s-a' since
 	 * this seems to be what iBooks have
 	 */
-	if (! chip->node)
+	if (! chip->node) {
 		chip->node = find_devices("i2s-a");
+		if (chip->node && chip->node->parent &&
+		    chip->node->parent->parent) {
+			if (device_is_compatible(chip->node->parent->parent,
+						 "K2-Keylargo"))
+				chip->is_k2 = 1;
+		}
+	}
 	if (! chip->node)
 		return -ENODEV;
-	sound = find_devices("sound");
-	while (sound && sound->parent != chip->node)
-		sound = sound->next;
+
+	if (!sound) {
+		sound = find_devices("sound");
+		while (sound && sound->parent != chip->node)
+			sound = sound->next;
+	}
 	if (! sound)
 		return -ENODEV;
 	prop = (unsigned int *) get_property(sound, "sub-frame", NULL);
 	if (prop && *prop < 16)
 		chip->subframe = *prop;
+	prop = (unsigned int *) get_property(sound, "layout-id", NULL);
+	if (prop)
+		layout_id = *prop;
 	/* This should be verified on older screamers */
 	if (device_is_compatible(sound, "screamer")) {
 		chip->model = PMAC_SCREAMER;
@@ -961,25 +975,65 @@ static int __init snd_pmac_detect(pmac_t
 		chip->freq_table = tumbler_freqs;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	if (device_is_compatible(sound, "AOAKeylargo")) {
-		/* Seems to support the stock AWACS frequencies, but has
-		   a snapper mixer */
-		chip->model = PMAC_SNAPPER;
-		// chip->can_byte_swap = 0; /* FIXME: check this */
-		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
+	if (device_is_compatible(sound, "AOAKeylargo") ||
+	    device_is_compatible(sound, "AOAbase") ||
+	    device_is_compatible(sound, "AOAK2")) {
+		/* For now, only support very basic TAS3004 based machines with
+		 * single frequency until proper i2s control is implemented
+		 */
+		switch(layout_id) {
+		case 0x48:
+		case 0x46:
+		case 0x33:
+		case 0x29:
+		case 0x24:
+			chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
+			chip->model = PMAC_SNAPPER;
+			chip->can_byte_swap = 0; /* FIXME: check this */
+			chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
+			break;
+		case 0x3a:
+			chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
+			chip->model = PMAC_TOONIE;
+			chip->can_byte_swap = 0; /* FIXME: check this */
+			chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
+			break;
+		}
 	}
 	prop = (unsigned int *)get_property(sound, "device-id", NULL);
 	if (prop)
 		chip->device_id = *prop;
 	chip->has_iic = (find_devices("perch") != NULL);
 
+	/* We need the PCI device for DMA allocations, let's use a crude method
+	 * for now ...
+	 */
+	macio = macio_find(chip->node, macio_unknown);
+	if (macio == NULL)
+		printk(KERN_WARNING "snd-powermac: can't locate macio !\n");
+	else {
+		struct pci_dev *pdev = NULL;
+
+		for_each_pci_dev(pdev) {
+			struct device_node *np = pci_device_to_OF_node(pdev);
+			if (np && np == macio->of_node) {
+				chip->pdev = pdev;
+				break;
+			}
+		}
+	}
+	if (chip->pdev == NULL)
+		printk(KERN_WARNING "snd-powermac: can't locate macio PCI"
+		       " device !\n");
+
 	detect_byte_swap(chip);
 
 	/* look for a property saying what sample rates
 	   are available */
 	prop = (unsigned int *) get_property(sound, "sample-rates", &l);
 	if (! prop)
-		prop = (unsigned int *) get_property(sound, "output-frame-rates", &l);
+		prop = (unsigned int *) get_property(sound,
+						     "output-frame-rates", &l);
 	if (prop) {
 		int i;
 		chip->freqs_ok = 0;
@@ -1006,7 +1060,8 @@ static int __init snd_pmac_detect(pmac_t
 /*
  * exported - boolean info callbacks for ease of programming
  */
-int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol,
+				 snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 2;
@@ -1015,7 +1070,8 @@ int snd_pmac_boolean_stereo_info(snd_kco
 	return 0;
 }
 
-int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol,
+			       snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -1077,8 +1133,10 @@ int __init snd_pmac_add_automute(pmac_t 
 	int err;
 	chip->auto_mute = 1;
 	err = snd_ctl_add(chip->card, snd_ctl_new1(&auto_mute_controls[0], chip));
-	if (err < 0)
+	if (err < 0) {
+		printk(KERN_ERR "snd-powermac: Failed to add automute control\n");
 		return err;
+	}
 	chip->hp_detect_ctl = snd_ctl_new1(&auto_mute_controls[1], chip);
 	return snd_ctl_add(chip->card, chip->hp_detect_ctl);
 }
@@ -1092,6 +1150,7 @@ int __init snd_pmac_new(snd_card_t *card
 	pmac_t *chip;
 	struct device_node *np;
 	int i, err;
+	unsigned long ctrl_addr, txdma_addr, rxdma_addr;
 	static snd_device_ops_t ops = {
 		.dev_free =	snd_pmac_dev_free,
 	};
@@ -1113,32 +1172,59 @@ int __init snd_pmac_new(snd_card_t *card
 	if ((err = snd_pmac_detect(chip)) < 0)
 		goto __error;
 
-	if (snd_pmac_dbdma_alloc(&chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
-	    snd_pmac_dbdma_alloc(&chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
-	    snd_pmac_dbdma_alloc(&chip->extra_dma, 2) < 0) {
+	if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
+	    snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
+	    snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0) {
 		err = -ENOMEM;
 		goto __error;
 	}
 
 	np = chip->node;
-	if (np->n_addrs < 3 || np->n_intrs < 3) {
-		err = -ENODEV;
-		goto __error;
-	}
+	if (chip->is_k2) {
+		if (np->parent->n_addrs < 2 || np->n_intrs < 3) {
+			err = -ENODEV;
+			goto __error;
+		}
+		for (i = 0; i < 2; i++) {
+#ifndef CONFIG_PPC64
+			static char *name[2] = { "- Control", "- DMA" };
+			if (! request_OF_resource(np->parent, i, name[i])) {
+				snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+				err = -ENODEV;
+				goto __error;
+			}
+			chip->of_requested |= (1 << i);
+#endif /* CONFIG_PPC64 */
+			ctrl_addr = np->parent->addrs[0].address;
+			txdma_addr = np->parent->addrs[1].address;
+			rxdma_addr = txdma_addr + 0x100;
+		}
 
-	for (i = 0; i < 3; i++) {
-		static char *name[3] = { NULL, "- Tx DMA", "- Rx DMA" };
-		if (! request_OF_resource(np, i, name[i])) {
-			snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+	} else {
+		if (np->n_addrs < 3 || np->n_intrs < 3) {
 			err = -ENODEV;
 			goto __error;
 		}
-		chip->of_requested |= (1 << i);
+
+		for (i = 0; i < 3; i++) {
+#ifndef CONFIG_PPC64
+			static char *name[3] = { "- Control", "- Tx DMA", "- Rx DMA" };
+			if (! request_OF_resource(np, i, name[i])) {
+				snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+				err = -ENODEV;
+				goto __error;
+			}
+			chip->of_requested |= (1 << i);
+#endif /* CONFIG_PPC64 */
+			ctrl_addr = np->addrs[0].address;
+			txdma_addr = np->addrs[1].address;
+			rxdma_addr = np->addrs[2].address;
+		}
 	}
 
-	chip->awacs = ioremap(np->addrs[0].address, 0x1000);
-	chip->playback.dma = ioremap(np->addrs[1].address, 0x100);
-	chip->capture.dma = ioremap(np->addrs[2].address, 0x100);
+	chip->awacs = ioremap(ctrl_addr, 0x1000);
+	chip->playback.dma = ioremap(txdma_addr, 0x100);
+	chip->capture.dma = ioremap(rxdma_addr, 0x100);
 	if (chip->model <= PMAC_BURGUNDY) {
 		if (request_irq(np->intrs[0].line, snd_pmac_ctrl_intr, 0,
 				"PMac", (void*)chip)) {
@@ -1166,7 +1252,8 @@ int __init snd_pmac_new(snd_card_t *card
 	snd_pmac_sound_feature(chip, 1);
 
 	/* reset */
-	out_le32(&chip->awacs->control, 0x11);
+	if (chip->model == PMAC_AWACS)
+		out_le32(&chip->awacs->control, 0x11);
 
 	/* Powerbooks have odd ways of enabling inputs such as
 	   an expansion-bay CD or sound from an internal modem
@@ -1218,6 +1305,8 @@ int __init snd_pmac_new(snd_card_t *card
 	return 0;
 
  __error:
+	if (chip->pdev)
+		pci_dev_put(chip->pdev);
 	snd_pmac_free(chip);
 	return err;
 }
@@ -1233,7 +1322,7 @@ int __init snd_pmac_new(snd_card_t *card
  * Save state when going to sleep, restore it afterwards.
  */
 
-static int snd_pmac_suspend(snd_card_t *card, unsigned int state)
+static int snd_pmac_suspend(snd_card_t *card, pm_message_t state)
 {
 	pmac_t *chip = card->pm_private_data;
 	unsigned long flags;
@@ -1254,7 +1343,7 @@ static int snd_pmac_suspend(snd_card_t *
 	return 0;
 }
 
-static int snd_pmac_resume(snd_card_t *card, unsigned int state)
+static int snd_pmac_resume(snd_card_t *card)
 {
 	pmac_t *chip = card->pm_private_data;
 
@@ -1294,10 +1383,10 @@ static int snd_pmac_sleep_notify(struct 
 
 	switch (when) {
 	case PBOOK_SLEEP_NOW:
-		snd_pmac_suspend(chip->card, 0);
+		snd_pmac_suspend(chip->card, PMSG_SUSPEND);
 		break;
 	case PBOOK_WAKE:
-		snd_pmac_resume(chip->card, 0);
+		snd_pmac_resume(chip->card);
 		break;
 	}
 	return PBOOK_SLEEP_OK;
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -60,7 +60,8 @@ typedef struct snd_pmac_dbdma pmac_dbdma
  * DBDMA space
  */
 struct snd_pmac_dbdma {
-	unsigned long addr;
+	dma_addr_t dma_base;
+	dma_addr_t addr;
 	struct dbdma_cmd __iomem *cmds;
 	void *space;
 	int size;
@@ -93,7 +94,8 @@ struct snd_pmac_stream {
  */
 
 enum snd_pmac_model {
-	PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, PMAC_SNAPPER
+	PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER,
+	PMAC_SNAPPER, PMAC_TOONIE
 };
 
 struct snd_pmac {
@@ -101,6 +103,7 @@ struct snd_pmac {
 
 	/* h/w info */
 	struct device_node *node;
+	struct pci_dev *pdev;
 	unsigned int revision;
 	unsigned int manufacturer;
 	unsigned int subframe;
@@ -110,6 +113,7 @@ struct snd_pmac {
 	unsigned int has_iic : 1;
 	unsigned int is_pbook_3400 : 1;
 	unsigned int is_pbook_G3 : 1;
+	unsigned int is_k2 : 1;
 
 	unsigned int can_byte_swap : 1;
 	unsigned int can_duplex : 1;
@@ -157,6 +161,7 @@ struct snd_pmac {
 	snd_kcontrol_t *speaker_sw_ctl;
 	snd_kcontrol_t *drc_sw_ctl;	/* only used for tumbler -ReneR */
 	snd_kcontrol_t *hp_detect_ctl;
+	snd_kcontrol_t *lineout_sw_ctl;
 
 	/* lowlevel callbacks */
 	void (*set_format)(pmac_t *chip);
@@ -187,6 +192,7 @@ int snd_pmac_burgundy_init(pmac_t *chip)
 int snd_pmac_daca_init(pmac_t *chip);
 int snd_pmac_tumbler_init(pmac_t *chip);
 int snd_pmac_tumbler_post_init(void);
+int snd_pmac_toonie_init(pmac_t *chip);
 
 /* i2c functions */
 typedef struct snd_pmac_keywest {
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -95,6 +95,13 @@ static int __init snd_pmac_probe(void)
 		if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
 			goto __error;
 		break;
+	case PMAC_TOONIE:
+		strcpy(card->driver, "PMac Toonie");
+		strcpy(card->shortname, "PowerMac Toonie");
+		strcpy(card->longname, card->shortname);
+		if ((err = snd_pmac_toonie_init(chip)) < 0)
+			goto __error;
+		break;
 	case PMAC_AWACS:
 	case PMAC_SCREAMER:
 		name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS";
diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c
new file mode 100644
--- /dev/null
+++ b/sound/ppc/toonie.c
@@ -0,0 +1,379 @@
+/*
+ * Mac Mini "toonie" mixer control
+ *
+ * Copyright (c) 2005 by Benjamin 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.
+ *
+ *   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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include "pmac.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+struct pmac_gpio {
+	unsigned int addr;
+	u8 active_val;
+	u8 inactive_val;
+	u8 active_state;
+};
+
+struct pmac_toonie
+{
+	struct pmac_gpio	hp_detect_gpio;
+	struct pmac_gpio	hp_mute_gpio;
+	struct pmac_gpio	amp_mute_gpio;
+	int			hp_detect_irq;
+	int			auto_mute_notify;
+	struct work_struct	detect_work;
+};
+
+
+/*
+ * gpio access
+ */
+#define do_gpio_write(gp, val) \
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val)
+#define do_gpio_read(gp) \
+	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0)
+#define tumbler_gpio_free(gp) /* NOP */
+
+static void write_audio_gpio(struct pmac_gpio *gp, int active)
+{
+	if (! gp->addr)
+		return;
+	active = active ? gp->active_val : gp->inactive_val;
+	do_gpio_write(gp, active);
+	DBG("(I) gpio %x write %d\n", gp->addr, active);
+}
+
+static int check_audio_gpio(struct pmac_gpio *gp)
+{
+	int ret;
+
+	if (! gp->addr)
+		return 0;
+
+	ret = do_gpio_read(gp);
+
+	return (ret & 0xd) == (gp->active_val & 0xd);
+}
+
+static int read_audio_gpio(struct pmac_gpio *gp)
+{
+	int ret;
+	if (! gp->addr)
+		return 0;
+	ret = ((do_gpio_read(gp) & 0x02) !=0);
+	return ret == gp->active_state;
+}
+
+
+enum { TOONIE_MUTE_HP, TOONIE_MUTE_AMP };
+
+static int toonie_get_mute_switch(snd_kcontrol_t *kcontrol,
+				  snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	struct pmac_toonie *mix = chip->mixer_data;
+	struct pmac_gpio *gp;
+
+	if (mix == NULL)
+		return -ENODEV;
+	switch(kcontrol->private_value) {
+	case TOONIE_MUTE_HP:
+		gp = &mix->hp_mute_gpio;
+		break;
+	case TOONIE_MUTE_AMP:
+		gp = &mix->amp_mute_gpio;
+		break;
+	default:
+		return -EINVAL;;
+	}
+	ucontrol->value.integer.value[0] = !check_audio_gpio(gp);
+	return 0;
+}
+
+static int toonie_put_mute_switch(snd_kcontrol_t *kcontrol,
+				   snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	struct pmac_toonie *mix = chip->mixer_data;
+	struct pmac_gpio *gp;
+	int val;
+
+	if (chip->update_automute && chip->auto_mute)
+		return 0; /* don't touch in the auto-mute mode */
+
+	if (mix == NULL)
+		return -ENODEV;
+
+	switch(kcontrol->private_value) {
+	case TOONIE_MUTE_HP:
+		gp = &mix->hp_mute_gpio;
+		break;
+	case TOONIE_MUTE_AMP:
+		gp = &mix->amp_mute_gpio;
+		break;
+	default:
+		return -EINVAL;;
+	}
+	val = ! check_audio_gpio(gp);
+	if (val != ucontrol->value.integer.value[0]) {
+		write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);
+		return 1;
+	}
+	return 0;
+}
+
+static snd_kcontrol_new_t toonie_hp_sw __initdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Headphone Playback Switch",
+	.info = snd_pmac_boolean_mono_info,
+	.get = toonie_get_mute_switch,
+	.put = toonie_put_mute_switch,
+	.private_value = TOONIE_MUTE_HP,
+};
+static snd_kcontrol_new_t toonie_speaker_sw __initdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "PC Speaker Playback Switch",
+	.info = snd_pmac_boolean_mono_info,
+	.get = toonie_get_mute_switch,
+	.put = toonie_put_mute_switch,
+	.private_value = TOONIE_MUTE_AMP,
+};
+
+/*
+ * auto-mute stuffs
+ */
+static int toonie_detect_headphone(pmac_t *chip)
+{
+	struct pmac_toonie *mix = chip->mixer_data;
+	int detect = 0;
+
+	if (mix->hp_detect_gpio.addr)
+		detect |= read_audio_gpio(&mix->hp_detect_gpio);
+	return detect;
+}
+
+static void toonie_check_mute(pmac_t *chip, struct pmac_gpio *gp, int val,
+			      int do_notify, snd_kcontrol_t *sw)
+{
+	if (check_audio_gpio(gp) != val) {
+		write_audio_gpio(gp, val);
+		if (do_notify)
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &sw->id);
+	}
+}
+
+static void toonie_detect_handler(void *self)
+{
+	pmac_t *chip = (pmac_t*) self;
+	struct pmac_toonie *mix;
+	int headphone;
+
+	if (!chip)
+		return;
+
+	mix = chip->mixer_data;
+	snd_assert(mix, return);
+
+	headphone = toonie_detect_headphone(chip);
+
+	DBG("headphone: %d, lineout: %d\n", headphone, lineout);
+
+	if (headphone) {
+		/* unmute headphone/lineout & mute speaker */
+		toonie_check_mute(chip, &mix->hp_mute_gpio, 0,
+				  mix->auto_mute_notify, chip->master_sw_ctl);
+		toonie_check_mute(chip, &mix->amp_mute_gpio, 1,
+				  mix->auto_mute_notify, chip->speaker_sw_ctl);
+	} else {
+		/* unmute speaker, mute others */
+		toonie_check_mute(chip, &mix->amp_mute_gpio, 0,
+				  mix->auto_mute_notify, chip->speaker_sw_ctl);
+		toonie_check_mute(chip, &mix->hp_mute_gpio, 1,
+				  mix->auto_mute_notify, chip->master_sw_ctl);
+	}
+	if (mix->auto_mute_notify) {
+		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &chip->hp_detect_ctl->id);
+	}
+}
+
+static void toonie_update_automute(pmac_t *chip, int do_notify)
+{
+	if (chip->auto_mute) {
+		struct pmac_toonie *mix;
+		mix = chip->mixer_data;
+		snd_assert(mix, return);
+		mix->auto_mute_notify = do_notify;
+		schedule_work(&mix->detect_work);
+	}
+}
+
+/* interrupt - headphone plug changed */
+static irqreturn_t toonie_hp_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	pmac_t *chip = devid;
+
+	if (chip->update_automute && chip->initialized) {
+		chip->update_automute(chip, 1);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/* look for audio gpio device */
+static int find_audio_gpio(const char *name, const char *platform,
+			   struct pmac_gpio *gp)
+{
+	struct device_node *np;
+  	u32 *base, addr;
+
+	if (! (np = find_devices("gpio")))
+		return -ENODEV;
+
+	for (np = np->child; np; np = np->sibling) {
+		char *property = get_property(np, "audio-gpio", NULL);
+		if (property && strcmp(property, name) == 0)
+			break;
+		if (device_is_compatible(np, name))
+			break;
+	}
+	if (np == NULL)
+		return -ENODEV;
+
+	base = (u32 *)get_property(np, "AAPL,address", NULL);
+	if (! base) {
+		base = (u32 *)get_property(np, "reg", NULL);
+		if (!base) {
+			DBG("(E) cannot find address for device %s !\n", name);
+			return -ENODEV;
+		}
+		addr = *base;
+		if (addr < 0x50)
+			addr += 0x50;
+	} else
+		addr = *base;
+
+	gp->addr = addr & 0x0000ffff;
+
+	/* Try to find the active state, default to 0 ! */
+	base = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+	if (base) {
+		gp->active_state = *base;
+		gp->active_val = (*base) ? 0x5 : 0x4;
+		gp->inactive_val = (*base) ? 0x4 : 0x5;
+	} else {
+		u32 *prop = NULL;
+		gp->active_state = 0;
+		gp->active_val = 0x4;
+		gp->inactive_val = 0x5;
+		/* Here are some crude hacks to extract the GPIO polarity and
+		 * open collector informations out of the do-platform script
+		 * as we don't yet have an interpreter for these things
+		 */
+		if (platform)
+			prop = (u32 *)get_property(np, platform, NULL);
+		if (prop) {
+			if (prop[3] == 0x9 && prop[4] == 0x9) {
+				gp->active_val = 0xd;
+				gp->inactive_val = 0xc;
+			}
+			if (prop[3] == 0x1 && prop[4] == 0x1) {
+				gp->active_val = 0x5;
+				gp->inactive_val = 0x4;
+			}
+		}
+	}
+
+	DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
+	    name, gp->addr, gp->active_state);
+
+	return (np->n_intrs > 0) ? np->intrs[0].line : 0;
+}
+
+static void toonie_cleanup(pmac_t *chip)
+{
+	struct pmac_toonie *mix = chip->mixer_data;
+	if (! mix)
+		return;
+	if (mix->hp_detect_irq >= 0)
+		free_irq(mix->hp_detect_irq, chip);
+	kfree(mix);
+	chip->mixer_data = NULL;
+}
+
+int snd_pmac_toonie_init(pmac_t *chip)
+{
+	struct pmac_toonie *mix;
+
+	mix = kmalloc(sizeof(*mix), GFP_KERNEL);
+	if (! mix)
+		return -ENOMEM;
+
+	chip->mixer_data = mix;
+	chip->mixer_free = toonie_cleanup;
+
+	find_audio_gpio("headphone-mute", NULL, &mix->hp_mute_gpio);
+	find_audio_gpio("amp-mute", NULL, &mix->amp_mute_gpio);
+	mix->hp_detect_irq = find_audio_gpio("headphone-detect",
+					     NULL, &mix->hp_detect_gpio);
+
+	strcpy(chip->card->mixername, "PowerMac Toonie");
+
+	chip->master_sw_ctl = snd_ctl_new1(&toonie_hp_sw, chip);
+	snd_ctl_add(chip->card, chip->master_sw_ctl);
+
+	chip->speaker_sw_ctl = snd_ctl_new1(&toonie_speaker_sw, chip);
+	snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+
+	INIT_WORK(&mix->detect_work, toonie_detect_handler, (void *)chip);
+
+	if (mix->hp_detect_irq >= 0) {
+		snd_pmac_add_automute(chip);
+
+		chip->detect_headphone = toonie_detect_headphone;
+		chip->update_automute = toonie_update_automute;
+		toonie_update_automute(chip, 0);
+
+		if (request_irq(mix->hp_detect_irq, toonie_hp_intr, 0,
+				"Sound Headphone Detection", chip) < 0)
+			mix->hp_detect_irq = -1;
+	}
+
+	return 0;
+}
+
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -35,12 +35,19 @@
 #include <sound/core.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
+#include <asm/machdep.h>
 #include <asm/pmac_feature.h>
-#endif
 #include "pmac.h"
 #include "tumbler_volume.h"
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
 /* i2c address for tumbler */
 #define TAS_I2C_ADDR	0x34
 
@@ -76,28 +83,35 @@ enum {
 };
 
 typedef struct pmac_gpio {
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
 	unsigned int addr;
-#else
-	void __iomem *addr;
-#endif
-	int active_state;
+	u8 active_val;
+	u8 inactive_val;
+	u8 active_state;
 } pmac_gpio_t;
 
 typedef struct pmac_tumbler_t {
 	pmac_keywest_t i2c;
 	pmac_gpio_t audio_reset;
 	pmac_gpio_t amp_mute;
+	pmac_gpio_t line_mute;
+	pmac_gpio_t line_detect;
 	pmac_gpio_t hp_mute;
 	pmac_gpio_t hp_detect;
 	int headphone_irq;
+	int lineout_irq;
+	unsigned int save_master_vol[2];
 	unsigned int master_vol[2];
+	unsigned int save_master_switch[2];
 	unsigned int master_switch[2];
 	unsigned int mono_vol[VOL_IDX_LAST_MONO];
 	unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
 	int drc_range;
 	int drc_enable;
 	int capture_source;
+	int anded_reset;
+	int auto_mute_notify;
+	int reset_on_sleep;
+	u8  acs;
 } pmac_tumbler_t;
 
 
@@ -113,6 +127,7 @@ static int send_init_client(pmac_keywest
 							regs[0], regs[1]);
 			if (err >= 0)
 				break;
+			DBG("(W) i2c error %d\n", err);
 			mdelay(10);
 		} while (count--);
 		if (err < 0)
@@ -130,6 +145,7 @@ static int tumbler_init_client(pmac_keyw
 		TAS_REG_MCS, (1<<6)|(2<<4)|(2<<2)|0,
 		0, /* terminator */
 	};
+	DBG("(I) tumbler init client\n");
 	return send_init_client(i2c, regs);
 }
 
@@ -144,36 +160,38 @@ static int snapper_init_client(pmac_keyw
 		TAS_REG_ACS, 0,
 		0, /* terminator */
 	};
+	DBG("(I) snapper init client\n");
 	return send_init_client(i2c, regs);
 }
 	
 /*
  * gpio access
  */
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
 #define do_gpio_write(gp, val) \
 	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val)
 #define do_gpio_read(gp) \
 	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0)
 #define tumbler_gpio_free(gp) /* NOP */
-#else
-#define do_gpio_write(gp, val)	writeb(val, (gp)->addr)
-#define do_gpio_read(gp)	readb((gp)->addr)
-static inline void tumbler_gpio_free(pmac_gpio_t *gp)
-{
-	if (gp->addr) {
-		iounmap(gp->addr);
-		gp->addr = NULL;
-	}
-}
-#endif /* CONFIG_PPC_HAS_FEATURE_CALLS */
 
 static void write_audio_gpio(pmac_gpio_t *gp, int active)
 {
 	if (! gp->addr)
 		return;
-	active = active ? gp->active_state : !gp->active_state;
-	do_gpio_write(gp, active ? 0x05 : 0x04);
+	active = active ? gp->active_val : gp->inactive_val;
+	do_gpio_write(gp, active);
+	DBG("(I) gpio %x write %d\n", gp->addr, active);
+}
+
+static int check_audio_gpio(pmac_gpio_t *gp)
+{
+	int ret;
+
+	if (! gp->addr)
+		return 0;
+
+	ret = do_gpio_read(gp);
+
+	return (ret & 0xd) == (gp->active_val & 0xd);
 }
 
 static int read_audio_gpio(pmac_gpio_t *gp)
@@ -652,10 +670,11 @@ static int snapper_put_mix(snd_kcontrol_
 
 
 /*
- * mute switches
+ * mute switches. FIXME: Turn that into software mute when both outputs are muted
+ * to avoid codec reset on ibook M7
  */
 
-enum { TUMBLER_MUTE_HP, TUMBLER_MUTE_AMP };
+enum { TUMBLER_MUTE_HP, TUMBLER_MUTE_AMP, TUMBLER_MUTE_LINE };
 
 static int tumbler_get_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
@@ -664,8 +683,19 @@ static int tumbler_get_mute_switch(snd_k
 	pmac_gpio_t *gp;
 	if (! (mix = chip->mixer_data))
 		return -ENODEV;
-	gp = (kcontrol->private_value == TUMBLER_MUTE_HP) ? &mix->hp_mute : &mix->amp_mute;
-	ucontrol->value.integer.value[0] = ! read_audio_gpio(gp);
+	switch(kcontrol->private_value) {
+	case TUMBLER_MUTE_HP:
+		gp = &mix->hp_mute;	break;
+	case TUMBLER_MUTE_AMP:
+		gp = &mix->amp_mute;	break;
+	case TUMBLER_MUTE_LINE:
+		gp = &mix->line_mute;	break;
+	default:
+		gp = NULL;
+	}
+	if (gp == NULL)
+		return -EINVAL;
+	ucontrol->value.integer.value[0] = !check_audio_gpio(gp);
 	return 0;
 }
 
@@ -681,8 +711,19 @@ static int tumbler_put_mute_switch(snd_k
 #endif	
 	if (! (mix = chip->mixer_data))
 		return -ENODEV;
-	gp = (kcontrol->private_value == TUMBLER_MUTE_HP) ? &mix->hp_mute : &mix->amp_mute;
-	val = ! read_audio_gpio(gp);
+	switch(kcontrol->private_value) {
+	case TUMBLER_MUTE_HP:
+		gp = &mix->hp_mute;	break;
+	case TUMBLER_MUTE_AMP:
+		gp = &mix->amp_mute;	break;
+	case TUMBLER_MUTE_LINE:
+		gp = &mix->line_mute;	break;
+	default:
+		gp = NULL;
+	}
+	if (gp == NULL)
+		return -EINVAL;
+	val = ! check_audio_gpio(gp);
 	if (val != ucontrol->value.integer.value[0]) {
 		write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);
 		return 1;
@@ -694,8 +735,11 @@ static int snapper_set_capture_source(pm
 {
 	if (! mix->i2c.client)
 		return -ENODEV;
-	return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS,
-					 mix->capture_source ? 2 : 0);
+	if (mix->capture_source)
+		mix->acs = mix->acs |= 2;
+	else
+		mix->acs &= ~2;
+	return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
 }
 
 static int snapper_info_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -822,6 +866,14 @@ static snd_kcontrol_new_t tumbler_speake
 	.put = tumbler_put_mute_switch,
 	.private_value = TUMBLER_MUTE_AMP,
 };
+static snd_kcontrol_new_t tumbler_lineout_sw __initdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Line Out Playback Switch",
+	.info = snd_pmac_boolean_mono_info,
+	.get = tumbler_get_mute_switch,
+	.put = tumbler_put_mute_switch,
+	.private_value = TUMBLER_MUTE_LINE,
+};
 static snd_kcontrol_new_t tumbler_drc_sw __initdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DRC Switch",
@@ -838,31 +890,84 @@ static snd_kcontrol_new_t tumbler_drc_sw
 static int tumbler_detect_headphone(pmac_t *chip)
 {
 	pmac_tumbler_t *mix = chip->mixer_data;
-	return read_audio_gpio(&mix->hp_detect);
+	int detect = 0;
+
+	if (mix->hp_detect.addr)
+		detect |= read_audio_gpio(&mix->hp_detect);
+	return detect;
+}
+
+static int tumbler_detect_lineout(pmac_t *chip)
+{
+	pmac_tumbler_t *mix = chip->mixer_data;
+	int detect = 0;
+
+	if (mix->line_detect.addr)
+		detect |= read_audio_gpio(&mix->line_detect);
+	return detect;
 }
 
 static void check_mute(pmac_t *chip, pmac_gpio_t *gp, int val, int do_notify, snd_kcontrol_t *sw)
 {
-	//pmac_tumbler_t *mix = chip->mixer_data;
-	if (val != read_audio_gpio(gp)) {
+	if (check_audio_gpio(gp) != val) {
 		write_audio_gpio(gp, val);
 		if (do_notify)
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &sw->id);
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &sw->id);
 	}
 }
 
 static struct work_struct device_change;
 
-static void
-device_change_handler(void *self)
+static void device_change_handler(void *self)
 {
 	pmac_t *chip = (pmac_t*) self;
 	pmac_tumbler_t *mix;
+	int headphone, lineout;
 
 	if (!chip)
 		return;
 
 	mix = chip->mixer_data;
+	snd_assert(mix, return);
+
+	headphone = tumbler_detect_headphone(chip);
+	lineout = tumbler_detect_lineout(chip);
+
+	DBG("headphone: %d, lineout: %d\n", headphone, lineout);
+
+	if (headphone || lineout) {
+		/* unmute headphone/lineout & mute speaker */
+		if (headphone)
+			check_mute(chip, &mix->hp_mute, 0, mix->auto_mute_notify,
+				   chip->master_sw_ctl);
+		if (lineout && mix->line_mute.addr != 0)
+			check_mute(chip, &mix->line_mute, 0, mix->auto_mute_notify,
+				   chip->lineout_sw_ctl);
+		if (mix->anded_reset)
+			big_mdelay(10);
+		check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+			   chip->speaker_sw_ctl);
+		mix->drc_enable = 0;
+	} else {
+		/* unmute speaker, mute others */
+		check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify,
+			   chip->speaker_sw_ctl);
+		if (mix->anded_reset)
+			big_mdelay(10);
+		check_mute(chip, &mix->hp_mute, 1, mix->auto_mute_notify,
+			   chip->master_sw_ctl);
+		if (mix->line_mute.addr != 0)
+			check_mute(chip, &mix->line_mute, 1, mix->auto_mute_notify,
+				   chip->lineout_sw_ctl);
+		mix->drc_enable = 1;
+	}
+	if (mix->auto_mute_notify) {
+		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &chip->hp_detect_ctl->id);
+		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &chip->drc_sw_ctl->id);
+	}
 
 	/* first set the DRC so the speaker do not explode -ReneR */
 	if (chip->model == PMAC_TUMBLER)
@@ -877,31 +982,11 @@ device_change_handler(void *self)
 static void tumbler_update_automute(pmac_t *chip, int do_notify)
 {
 	if (chip->auto_mute) {
-		pmac_tumbler_t *mix = chip->mixer_data;
+		pmac_tumbler_t *mix;
+		mix = chip->mixer_data;
 		snd_assert(mix, return);
-		if (tumbler_detect_headphone(chip)) {
-			/* mute speaker */
-			check_mute(chip, &mix->amp_mute, 1, do_notify, chip->speaker_sw_ctl);
-			check_mute(chip, &mix->hp_mute, 0, do_notify, chip->master_sw_ctl);
-			mix->drc_enable = 0;
-
-		} else {
-			/* unmute speaker */
-			check_mute(chip, &mix->amp_mute, 0, do_notify, chip->speaker_sw_ctl);
-			check_mute(chip, &mix->hp_mute, 1, do_notify, chip->master_sw_ctl);
-			mix->drc_enable = 1;
-		}
-		if (do_notify) {
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-				       &chip->hp_detect_ctl->id);
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-			               &chip->drc_sw_ctl->id);
-		}
-
-		/* finally we need to schedule an update of the mixer values
-		   (master and DRC are enough for now) -ReneR */
+		mix->auto_mute_notify = do_notify;
 		schedule_work(&device_change);
-
 	}
 }
 #endif /* PMAC_SUPPORT_AUTOMUTE */
@@ -950,37 +1035,67 @@ static struct device_node *find_compatib
 }
 
 /* find an audio device and get its address */
-static unsigned long tumbler_find_device(const char *device, pmac_gpio_t *gp, int is_compatible)
+static long tumbler_find_device(const char *device, const char *platform, pmac_gpio_t *gp, int is_compatible)
 {
 	struct device_node *node;
-	u32 *base;
+	u32 *base, addr;
 
 	if (is_compatible)
 		node = find_compatible_audio_device(device);
 	else
 		node = find_audio_device(device);
 	if (! node) {
+		DBG("(W) cannot find audio device %s !\n", device);
 		snd_printdd("cannot find device %s\n", device);
 		return -ENODEV;
 	}
 
 	base = (u32 *)get_property(node, "AAPL,address", NULL);
 	if (! base) {
-		snd_printd("cannot find address for device %s\n", device);
-		return -ENODEV;
-	}
+		base = (u32 *)get_property(node, "reg", NULL);
+		if (!base) {
+			DBG("(E) cannot find address for device %s !\n", device);
+			snd_printd("cannot find address for device %s\n", device);
+			return -ENODEV;
+		}
+		addr = *base;
+		if (addr < 0x50)
+			addr += 0x50;
+	} else
+		addr = *base;
 
-#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
-	gp->addr = (*base) & 0x0000ffff;
-#else
-	gp->addr = ioremap((unsigned long)(*base), 1);
-#endif
+	gp->addr = addr & 0x0000ffff;
+	/* Try to find the active state, default to 0 ! */
 	base = (u32 *)get_property(node, "audio-gpio-active-state", NULL);
-	if (base)
+	if (base) {
 		gp->active_state = *base;
-	else
-		gp->active_state = 1;
+		gp->active_val = (*base) ? 0x5 : 0x4;
+		gp->inactive_val = (*base) ? 0x4 : 0x5;
+	} else {
+		u32 *prop = NULL;
+		gp->active_state = 0;
+		gp->active_val = 0x4;
+		gp->inactive_val = 0x5;
+		/* Here are some crude hacks to extract the GPIO polarity and
+		 * open collector informations out of the do-platform script
+		 * as we don't yet have an interpreter for these things
+		 */
+		if (platform)
+			prop = (u32 *)get_property(node, platform, NULL);
+		if (prop) {
+			if (prop[3] == 0x9 && prop[4] == 0x9) {
+				gp->active_val = 0xd;
+				gp->inactive_val = 0xc;
+			}
+			if (prop[3] == 0x1 && prop[4] == 0x1) {
+				gp->active_val = 0x5;
+				gp->inactive_val = 0x4;
+			}
+		}
+	}
 
+	DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
+	    device, gp->addr, gp->active_state);
 
 	return (node->n_intrs > 0) ? node->intrs[0].line : 0;
 }
@@ -990,15 +1105,60 @@ static void tumbler_reset_audio(pmac_t *
 {
 	pmac_tumbler_t *mix = chip->mixer_data;
 
-	write_audio_gpio(&mix->audio_reset, 0);
-	big_mdelay(200);
-	write_audio_gpio(&mix->audio_reset, 1);
-	big_mdelay(100);
-	write_audio_gpio(&mix->audio_reset, 0);
-	big_mdelay(100);
+	if (mix->anded_reset) {
+		DBG("(I) codec anded reset !\n");
+		write_audio_gpio(&mix->hp_mute, 0);
+		write_audio_gpio(&mix->amp_mute, 0);
+		big_mdelay(200);
+		write_audio_gpio(&mix->hp_mute, 1);
+		write_audio_gpio(&mix->amp_mute, 1);
+		big_mdelay(100);
+		write_audio_gpio(&mix->hp_mute, 0);
+		write_audio_gpio(&mix->amp_mute, 0);
+		big_mdelay(100);
+	} else {
+		DBG("(I) codec normal reset !\n");
+
+		write_audio_gpio(&mix->audio_reset, 0);
+		big_mdelay(200);
+		write_audio_gpio(&mix->audio_reset, 1);
+		big_mdelay(100);
+		write_audio_gpio(&mix->audio_reset, 0);
+		big_mdelay(100);
+	}
 }
 
 #ifdef CONFIG_PMAC_PBOOK
+/* suspend mixer */
+static void tumbler_suspend(pmac_t *chip)
+{
+	pmac_tumbler_t *mix = chip->mixer_data;
+
+	if (mix->headphone_irq >= 0)
+		disable_irq(mix->headphone_irq);
+	if (mix->lineout_irq >= 0)
+		disable_irq(mix->lineout_irq);
+	mix->save_master_switch[0] = mix->master_switch[0];
+	mix->save_master_switch[1] = mix->master_switch[1];
+	mix->save_master_vol[0] = mix->master_vol[0];
+	mix->save_master_vol[1] = mix->master_vol[1];
+	mix->master_switch[0] = mix->master_switch[1] = 0;
+	tumbler_set_master_volume(mix);
+	if (!mix->anded_reset) {
+		write_audio_gpio(&mix->amp_mute, 1);
+		write_audio_gpio(&mix->hp_mute, 1);
+	}
+	if (chip->model == PMAC_SNAPPER) {
+		mix->acs |= 1;
+		i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
+	}
+	if (mix->anded_reset) {
+		write_audio_gpio(&mix->amp_mute, 1);
+		write_audio_gpio(&mix->hp_mute, 1);
+	} else
+		write_audio_gpio(&mix->audio_reset, 1);
+}
+
 /* resume mixer */
 static void tumbler_resume(pmac_t *chip)
 {
@@ -1006,6 +1166,11 @@ static void tumbler_resume(pmac_t *chip)
 
 	snd_assert(mix, return);
 
+	mix->acs &= ~1;
+	mix->master_switch[0] = mix->save_master_switch[0];
+	mix->master_switch[1] = mix->save_master_switch[1];
+	mix->master_vol[0] = mix->save_master_vol[0];
+	mix->master_vol[1] = mix->save_master_vol[1];
 	tumbler_reset_audio(chip);
 	if (mix->i2c.client && mix->i2c.init_client) {
 		if (mix->i2c.init_client(&mix->i2c) < 0)
@@ -1029,36 +1194,61 @@ static void tumbler_resume(pmac_t *chip)
 	tumbler_set_master_volume(mix);
 	if (chip->update_automute)
 		chip->update_automute(chip, 0);
+	if (mix->headphone_irq >= 0)
+		enable_irq(mix->headphone_irq);
+	if (mix->lineout_irq >= 0)
+		enable_irq(mix->lineout_irq);
 }
 #endif
 
 /* initialize tumbler */
 static int __init tumbler_init(pmac_t *chip)
 {
-	int irq, err;
+	int irq;
 	pmac_tumbler_t *mix = chip->mixer_data;
 	snd_assert(mix, return -EINVAL);
 
-	tumbler_find_device("audio-hw-reset", &mix->audio_reset, 0);
-	tumbler_find_device("amp-mute", &mix->amp_mute, 0);
-	tumbler_find_device("headphone-mute", &mix->hp_mute, 0);
-	irq = tumbler_find_device("headphone-detect", &mix->hp_detect, 0);
+	if (tumbler_find_device("audio-hw-reset",
+				"platform-do-hw-reset",
+				&mix->audio_reset, 0) < 0)
+		tumbler_find_device("hw-reset",
+				    "platform-do-hw-reset",
+				    &mix->audio_reset, 1);
+	if (tumbler_find_device("amp-mute",
+				"platform-do-amp-mute",
+				&mix->amp_mute, 0) < 0)
+		tumbler_find_device("amp-mute",
+				    "platform-do-amp-mute",
+				    &mix->amp_mute, 1);
+	if (tumbler_find_device("headphone-mute",
+				"platform-do-headphone-mute",
+				&mix->hp_mute, 0) < 0)
+		tumbler_find_device("headphone-mute",
+				    "platform-do-headphone-mute",
+				    &mix->hp_mute, 1);
+	if (tumbler_find_device("line-output-mute",
+				"platform-do-lineout-mute",
+				&mix->line_mute, 0) < 0)
+		tumbler_find_device("line-output-mute",
+				   "platform-do-lineout-mute",
+				    &mix->line_mute, 1);
+	irq = tumbler_find_device("headphone-detect",
+				  NULL, &mix->hp_detect, 0);
 	if (irq < 0)
-		irq = tumbler_find_device("keywest-gpio15", &mix->hp_detect, 1);
+		irq = tumbler_find_device("headphone-detect",
+					  NULL, &mix->hp_detect, 1);
+	if (irq < 0)
+		irq = tumbler_find_device("keywest-gpio15",
+					  NULL, &mix->hp_detect, 1);
+	mix->headphone_irq = irq;
+ 	irq = tumbler_find_device("line-output-detect",
+				  NULL, &mix->line_detect, 0);
+ 	if (irq < 0)
+		irq = tumbler_find_device("line-output-detect",
+					  NULL, &mix->line_detect, 1);
+	mix->lineout_irq = irq;
 
 	tumbler_reset_audio(chip);
-
-	/* activate headphone status interrupts */
-  	if (irq >= 0) {
-		unsigned char val;
-		if ((err = request_irq(irq, headphone_intr, 0,
-				       "Tumbler Headphone Detection", chip)) < 0)
-			return err;
-		/* activate headphone status interrupts */
-		val = do_gpio_read(&mix->hp_detect);
-		do_gpio_write(&mix->hp_detect, val | 0x80);
-	}
-	mix->headphone_irq = irq;
   
 	return 0;
 }
@@ -1071,6 +1261,8 @@ static void tumbler_cleanup(pmac_t *chip
 
 	if (mix->headphone_irq >= 0)
 		free_irq(mix->headphone_irq, chip);
+	if (mix->lineout_irq >= 0)
+		free_irq(mix->lineout_irq, chip);
 	tumbler_gpio_free(&mix->audio_reset);
 	tumbler_gpio_free(&mix->amp_mute);
 	tumbler_gpio_free(&mix->hp_mute);
@@ -1086,7 +1278,7 @@ int __init snd_pmac_tumbler_init(pmac_t 
 	int i, err;
 	pmac_tumbler_t *mix;
 	u32 *paddr;
-	struct device_node *tas_node;
+	struct device_node *tas_node, *np;
 	char *chipname;
 
 #ifdef CONFIG_KMOD
@@ -1102,21 +1294,38 @@ int __init snd_pmac_tumbler_init(pmac_t 
 
 	chip->mixer_data = mix;
 	chip->mixer_free = tumbler_cleanup;
+	mix->anded_reset = 0;
+	mix->reset_on_sleep = 1;
 
+	for (np = chip->node->child; np; np = np->sibling) {
+		if (!strcmp(np->name, "sound")) {
+			if (get_property(np, "has-anded-reset", NULL))
+				mix->anded_reset = 1;
+			if (get_property(np, "layout-id", NULL))
+				mix->reset_on_sleep = 0;
+			break;
+		}
+	}
 	if ((err = tumbler_init(chip)) < 0)
 		return err;
 
 	/* set up TAS */
 	tas_node = find_devices("deq");
 	if (tas_node == NULL)
+		tas_node = find_devices("codec");
+	if (tas_node == NULL)
 		return -ENODEV;
 
 	paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+	if (paddr == NULL)
+		paddr = (u32 *)get_property(tas_node, "reg", NULL);
 	if (paddr)
 		mix->i2c.addr = (*paddr) >> 1;
 	else
 		mix->i2c.addr = TAS_I2C_ADDR;
 
+	DBG("(I) TAS i2c address is: %x\n", mix->i2c.addr);
+
 	if (chip->model == PMAC_TUMBLER) {
 		mix->i2c.init_client = tumbler_init_client;
 		mix->i2c.name = "TAS3001c";
@@ -1152,23 +1361,49 @@ int __init snd_pmac_tumbler_init(pmac_t 
 	chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip);
 	if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
 		return err;
+	if (mix->line_mute.addr != 0) {
+		chip->lineout_sw_ctl = snd_ctl_new1(&tumbler_lineout_sw, chip);
+		if ((err = snd_ctl_add(chip->card, chip->lineout_sw_ctl)) < 0)
+			return err;
+	}
 	chip->drc_sw_ctl = snd_ctl_new1(&tumbler_drc_sw, chip);
 	if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
 		return err;
 
-
 #ifdef CONFIG_PMAC_PBOOK
+	chip->suspend = tumbler_suspend;
 	chip->resume = tumbler_resume;
 #endif
 
 	INIT_WORK(&device_change, device_change_handler, (void *)chip);
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
-	if (mix->headphone_irq >=0 && (err = snd_pmac_add_automute(chip)) < 0)
+	if ((mix->headphone_irq >=0 || mix->lineout_irq >= 0)
+	    && (err = snd_pmac_add_automute(chip)) < 0)
 		return err;
 	chip->detect_headphone = tumbler_detect_headphone;
 	chip->update_automute = tumbler_update_automute;
 	tumbler_update_automute(chip, 0); /* update the status only */
+
+	/* activate headphone status interrupts */
+  	if (mix->headphone_irq >= 0) {
+		unsigned char val;
+		if ((err = request_irq(mix->headphone_irq, headphone_intr, 0,
+				       "Sound Headphone Detection", chip)) < 0)
+			return 0;
+		/* activate headphone status interrupts */
+		val = do_gpio_read(&mix->hp_detect);
+		do_gpio_write(&mix->hp_detect, val | 0x80);
+	}
+  	if (mix->lineout_irq >= 0) {
+		unsigned char val;
+		if ((err = request_irq(mix->lineout_irq, headphone_intr, 0,
+				       "Sound Lineout Detection", chip)) < 0)
+			return 0;
+		/* activate headphone status interrupts */
+		val = do_gpio_read(&mix->line_detect);
+		do_gpio_write(&mix->line_detect, val | 0x80);
+	}
 #endif
 
 	return 0;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -1141,7 +1141,7 @@ static int init_usb_pitch(struct usb_dev
 		data[0] = 1;
 		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
 				   dev->devnum, iface, ep);
 			return err;
@@ -1167,14 +1167,14 @@ static int init_usb_sample_rate(struct u
 		data[2] = rate >> 16;
 		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
 				   dev->devnum, iface, fmt->altsetting, rate, ep);
 			return err;
 		}
 		if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
 			snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n",
 				   dev->devnum, iface, fmt->altsetting, ep);
 			return 0; /* some devices don't support reading */
@@ -1606,62 +1606,65 @@ static int hw_rule_format(snd_pcm_hw_par
 	return changed;
 }
 
+#define MAX_MASK	64
+
 /*
  * check whether the registered audio formats need special hw-constraints
  */
 static int check_hw_params_convention(snd_usb_substream_t *subs)
 {
 	int i;
-	u32 channels[64];
-	u32 rates[64];
+	u32 *channels;
+	u32 *rates;
 	u32 cmaster, rmaster;
 	u32 rate_min = 0, rate_max = 0;
 	struct list_head *p;
+	int err = 1;
 
-	memset(channels, 0, sizeof(channels));
-	memset(rates, 0, sizeof(rates));
+	channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
+	rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
 
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *f;
 		f = list_entry(p, struct audioformat, list);
 		/* unconventional channels? */
 		if (f->channels > 32)
-			return 1;
+			goto __out;
 		/* continuous rate min/max matches? */
 		if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) {
 			if (rate_min && f->rate_min != rate_min)
-				return 1;
+				goto __out;
 			if (rate_max && f->rate_max != rate_max)
-				return 1;
+				goto __out;
 			rate_min = f->rate_min;
 			rate_max = f->rate_max;
 		}
 		/* combination of continuous rates and fixed rates? */
 		if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) {
 			if (f->rates != rates[f->format])
-				return 1;
+				goto __out;
 		}
 		if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) {
 			if (rates[f->format] && rates[f->format] != f->rates)
-				return 1;
+				goto __out;
 		}
 		channels[f->format] |= (1 << f->channels);
 		rates[f->format] |= f->rates;
 	}
 	/* check whether channels and rates match for all formats */
 	cmaster = rmaster = 0;
-	for (i = 0; i < 64; i++) {
+	for (i = 0; i < MAX_MASK; i++) {
 		if (cmaster != channels[i] && cmaster && channels[i])
-			return 1;
+			goto __out;
 		if (rmaster != rates[i] && rmaster && rates[i])
-			return 1;
+			goto __out;
 		if (channels[i])
 			cmaster = channels[i];
 		if (rates[i])
 			rmaster = rates[i];
 	}
 	/* check whether channels match for all distinct rates */
-	memset(channels, 0, sizeof(channels));
+	memset(channels, 0, MAX_MASK * sizeof(u32));
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *f;
 		f = list_entry(p, struct audioformat, list);
@@ -1675,11 +1678,16 @@ static int check_hw_params_convention(sn
 	cmaster = 0;
 	for (i = 0; i < 32; i++) {
 		if (cmaster != channels[i] && cmaster && channels[i])
-			return 1;
+			goto __out;
 		if (channels[i])
 			cmaster = channels[i];
 	}
-	return 0;
+	err = 0;
+
+ __out:
+	kfree(channels);
+	kfree(rates);
+	return err;
 }
 
 
@@ -2936,7 +2944,7 @@ static int snd_usb_extigy_boot_quirk(str
 		snd_printdd("sending Extigy boot sequence...\n");
 		/* Send message to force it to reconnect with full interface. */
 		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
-				      0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ);
+				      0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000);
 		if (err < 0) snd_printdd("error sending boot message: %d\n", err);
 		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
 				&dev->descriptor, sizeof(dev->descriptor));
@@ -2968,6 +2976,9 @@ static int snd_usb_create_quirk(snd_usb_
 	case QUIRK_MIDI_FIXED_ENDPOINT:
 	case QUIRK_MIDI_YAMAHA:
 	case QUIRK_MIDI_MIDIMAN:
+	case QUIRK_MIDI_NOVATION:
+	case QUIRK_MIDI_MOTU:
+	case QUIRK_MIDI_EMAGIC:
 		return snd_usb_create_midi_interface(chip, iface, quirk);
 	case QUIRK_COMPOSITE:
 		return create_composite_quirk(chip, iface, quirk);
@@ -2980,6 +2991,8 @@ static int snd_usb_create_quirk(snd_usb_
 		return create_ua700_ua25_quirk(chip, iface);
 	case QUIRK_AUDIO_EDIROL_UA1000:
 		return create_ua1000_quirk(chip, iface);
+	case QUIRK_IGNORE_INTERFACE:
+		return 0;
 	default:
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
@@ -3276,7 +3289,7 @@ static void snd_usb_audio_disconnect(str
 		}
 		usb_chip[chip->index] = NULL;
 		up(&register_mutex);
-		snd_card_free_in_thread(card);
+		snd_card_free(card);
 	} else {
 		up(&register_mutex);
 	}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -157,6 +157,10 @@ struct snd_usb_audio {
 #define QUIRK_MIDI_STANDARD_INTERFACE	6
 #define QUIRK_AUDIO_EDIROL_UA700_UA25	7
 #define QUIRK_AUDIO_EDIROL_UA1000	8
+#define QUIRK_IGNORE_INTERFACE		9
+#define QUIRK_MIDI_NOVATION		10
+#define QUIRK_MIDI_MOTU			11
+#define QUIRK_MIDI_EMAGIC		12
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -171,7 +175,10 @@ struct snd_usb_audio_quirk {
 
 /* data for QUIRK_MIDI_FIXED_ENDPOINT */
 struct snd_usb_midi_endpoint_info {
-	int8_t out_ep, in_ep;	/* ep number, 0 autodetect */
+	int8_t   out_ep;	/* ep number, 0 autodetect */
+	uint8_t  out_interval;	/* interval for interrupt endpoints */
+	int8_t   in_ep;	
+	uint8_t  in_interval;
 	uint16_t out_cables;	/* bitmask */
 	uint16_t in_cables;	/* bitmask */
 };
@@ -190,6 +197,13 @@ struct snd_usb_midi_endpoint_info {
 
 /* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */
 
+/* for QUIRK_IGNORE_INTERFACE, data is NULL */
+
+/* for QUIRK_MIDI_NOVATION and _MOTU, data is NULL */
+
+/* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info
+ * structure (out_cables and in_cables only) */
+
 /*
  */
 
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -1,7 +1,7 @@
 /*
  * usbmidi.c - ALSA USB MIDI driver
  *
- * Copyright (c) 2002-2004 Clemens Ladisch
+ * Copyright (c) 2002-2005 Clemens Ladisch
  * All rights reserved.
  *
  * Based on the OSS usb-midi driver by NAGANO Daisuke,
@@ -38,6 +38,7 @@
 #include <sound/driver.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -49,6 +50,13 @@
 #include <sound/rawmidi.h>
 #include "usbaudio.h"
 
+
+/*
+ * define this to log all USB packets
+ */
+/* #define DUMP_PACKETS */
+
+
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("USB Audio/MIDI helper module");
 MODULE_LICENSE("Dual BSD/GPL");
@@ -77,22 +85,33 @@ typedef struct snd_usb_midi_in_endpoint 
 typedef struct usbmidi_out_port usbmidi_out_port_t;
 typedef struct usbmidi_in_port usbmidi_in_port_t;
 
+struct usb_protocol_ops {
+	void (*input)(snd_usb_midi_in_endpoint_t*, uint8_t*, int);
+	void (*output)(snd_usb_midi_out_endpoint_t*);
+	void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t);
+	void (*init_out_endpoint)(snd_usb_midi_out_endpoint_t*);
+	void (*finish_out_endpoint)(snd_usb_midi_out_endpoint_t*);
+};
+
 struct snd_usb_midi {
 	snd_usb_audio_t *chip;
 	struct usb_interface *iface;
 	const snd_usb_audio_quirk_t *quirk;
 	snd_rawmidi_t* rmidi;
+	struct usb_protocol_ops* usb_protocol_ops;
 	struct list_head list;
 
 	struct snd_usb_midi_endpoint {
 		snd_usb_midi_out_endpoint_t *out;
 		snd_usb_midi_in_endpoint_t *in;
 	} endpoints[MIDI_MAX_ENDPOINTS];
+	unsigned long input_triggered;
 };
 
 struct snd_usb_midi_out_endpoint {
 	snd_usb_midi_t* umidi;
 	struct urb* urb;
+	int urb_active;
 	int max_transfer;		/* size of urb buffer */
 	struct tasklet_struct tasklet;
 
@@ -113,6 +132,7 @@ struct snd_usb_midi_out_endpoint {
 #define STATE_SYSEX_2	6
 		uint8_t data[2];
 	} ports[0x10];
+	int current_port;
 };
 
 struct snd_usb_midi_in_endpoint {
@@ -121,6 +141,8 @@ struct snd_usb_midi_in_endpoint {
 	struct usbmidi_in_port {
 		snd_rawmidi_substream_t* substream;
 	} ports[0x10];
+	int seen_f5;
+	int current_port;
 };
 
 static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep);
@@ -156,25 +178,34 @@ static int snd_usbmidi_urb_error(int sta
 }
 
 /*
- * Receives a USB MIDI packet.
+ * Receives a chunk of MIDI data.
  */
-static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
-				     uint8_t packet[4])
+static void snd_usbmidi_input_data(snd_usb_midi_in_endpoint_t* ep, int portidx,
+				   uint8_t* data, int length)
 {
-	int cable = packet[0] >> 4;
-	usbmidi_in_port_t* port = &ep->ports[cable];
+	usbmidi_in_port_t* port = &ep->ports[portidx];
 
 	if (!port->substream) {
-		snd_printd("unexpected port %d!\n", cable);
+		snd_printd("unexpected port %d!\n", portidx);
 		return;
 	}
-	if (!port->substream->runtime ||
-	    !port->substream->runtime->trigger)
+	if (!test_bit(port->substream->number, &ep->umidi->input_triggered))
 		return;
-	snd_rawmidi_receive(port->substream, &packet[1],
-			    snd_usbmidi_cin_length[packet[0] & 0x0f]);
+	snd_rawmidi_receive(port->substream, data, length);
 }
 
+#ifdef DUMP_PACKETS
+static void dump_urb(const char *type, const u8 *data, int length)
+{
+	snd_printk(KERN_DEBUG "%s packet: [", type);
+	for (; length > 0; ++data, --length)
+		printk(" %02x", *data);
+	printk(" ]\n");
+}
+#else
+#define dump_urb(type, data, length) /* nothing */
+#endif
+
 /*
  * Processes the data read from the device.
  */
@@ -183,12 +214,9 @@ static void snd_usbmidi_in_urb_complete(
 	snd_usb_midi_in_endpoint_t* ep = urb->context;
 
 	if (urb->status == 0) {
-		uint8_t* buffer = (uint8_t*)ep->urb->transfer_buffer;
-		int i;
-
-		for (i = 0; i + 4 <= urb->actual_length; i += 4)
-			if (buffer[i] != 0)
-				snd_usbmidi_input_packet(ep, &buffer[i]);
+		dump_urb("received", urb->transfer_buffer, urb->actual_length);
+		ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
+						   urb->actual_length);
 	} else {
 		if (snd_usbmidi_urb_error(urb->status) < 0)
 			return;
@@ -200,71 +228,107 @@ static void snd_usbmidi_in_urb_complete(
 	}
 }
 
+static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
+{
+	snd_usb_midi_out_endpoint_t* ep = urb->context;
+
+	spin_lock(&ep->buffer_lock);
+	ep->urb_active = 0;
+	spin_unlock(&ep->buffer_lock);
+	if (urb->status < 0) {
+		if (snd_usbmidi_urb_error(urb->status) < 0)
+			return;
+	}
+	snd_usbmidi_do_output(ep);
+}
+
 /*
- * Converts the data read from a Midiman device to standard USB MIDI packets.
+ * This is called when some data should be transferred to the device
+ * (from one or more substreams).
  */
-static void snd_usbmidi_in_midiman_complete(struct urb* urb, struct pt_regs *regs)
+static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
 {
-	if (urb->status == 0) {
-		uint8_t* buffer = (uint8_t*)urb->transfer_buffer;
-		int i;
+	struct urb* urb = ep->urb;
+	unsigned long flags;
 
-		for (i = 0; i + 4 <= urb->actual_length; i += 4) {
-			if (buffer[i + 3] != 0) {
-				/*
-				 * snd_usbmidi_input_packet() doesn't check the
-				 * contents of the message, so we simply use
-				 * some random CIN with the desired length.
-				 */
-				static const uint8_t cin[4] = {
-					0x0, 0xf, 0x2, 0x3
-				};
-				uint8_t ctl = buffer[i + 3];
-				buffer[i + 3] = buffer[i + 2];
-				buffer[i + 2] = buffer[i + 1];
-				buffer[i + 1] = buffer[i + 0];
-				buffer[i + 0] = (ctl & 0xf0) | cin[ctl & 3];
-			} else {
-				buffer[i + 0] = 0;
-			}
-		}
+	spin_lock_irqsave(&ep->buffer_lock, flags);
+	if (ep->urb_active || ep->umidi->chip->shutdown) {
+		spin_unlock_irqrestore(&ep->buffer_lock, flags);
+		return;
 	}
-	snd_usbmidi_in_urb_complete(urb, regs);
+
+	urb->transfer_buffer_length = 0;
+	ep->umidi->usb_protocol_ops->output(ep);
+
+	if (urb->transfer_buffer_length > 0) {
+		dump_urb("sending", urb->transfer_buffer,
+			 urb->transfer_buffer_length);
+		urb->dev = ep->umidi->chip->dev;
+		ep->urb_active = snd_usbmidi_submit_urb(urb, GFP_ATOMIC) >= 0;
+	}
+	spin_unlock_irqrestore(&ep->buffer_lock, flags);
 }
 
-static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
+static void snd_usbmidi_out_tasklet(unsigned long data)
 {
-	snd_usb_midi_out_endpoint_t* ep = urb->context;
+	snd_usb_midi_out_endpoint_t* ep = (snd_usb_midi_out_endpoint_t *) data;
 
-	if (urb->status < 0) {
-		if (snd_usbmidi_urb_error(urb->status) < 0)
-			return;
-	}
 	snd_usbmidi_do_output(ep);
 }
 
+/* helper function to send static data that may not DMA-able */
+static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
+				 const void *data, int len)
+{
+	int err;
+	void *buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	memcpy(buf, data, len);
+	dump_urb("sending", buf, len);
+	err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len,
+			   NULL, 250);
+	kfree(buf);
+	return err;
+}
+
 /*
- * Converts standard USB MIDI packets to what Midman devices expect.
+ * Standard USB MIDI protocol: see the spec.
+ * Midiman protocol: like the standard protocol, but the control byte is the
+ * fourth byte in each packet, and uses length instead of CIN.
  */
-static void snd_usbmidi_convert_to_midiman(struct urb* urb)
+
+static void snd_usbmidi_standard_input(snd_usb_midi_in_endpoint_t* ep,
+				       uint8_t* buffer, int buffer_length)
 {
-	uint8_t* buffer = (uint8_t*)urb->transfer_buffer;
 	int i;
 
-	for (i = 0; i + 4 <= urb->transfer_buffer_length; i += 4) {
-		uint8_t cin = buffer[i];
-		buffer[i + 0] = buffer[i + 1];
-		buffer[i + 1] = buffer[i + 2];
-		buffer[i + 2] = buffer[i + 3];
-		buffer[i + 3] = (cin & 0xf0) | snd_usbmidi_cin_length[cin & 0x0f];
-	}
+	for (i = 0; i + 3 < buffer_length; i += 4)
+		if (buffer[i] != 0) {
+			int cable = buffer[i] >> 4;
+			int length = snd_usbmidi_cin_length[buffer[i] & 0x0f];
+			snd_usbmidi_input_data(ep, cable, &buffer[i + 1], length);
+		}
+}
+
+static void snd_usbmidi_midiman_input(snd_usb_midi_in_endpoint_t* ep,
+				      uint8_t* buffer, int buffer_length)
+{
+	int i;
+
+	for (i = 0; i + 3 < buffer_length; i += 4)
+		if (buffer[i + 3] != 0) {
+			int port = buffer[i + 3] >> 4;
+			int length = buffer[i + 3] & 3;
+			snd_usbmidi_input_data(ep, port, &buffer[i], length);
+		}
 }
 
 /*
  * Adds one USB MIDI packet to the output buffer.
  */
-static inline void output_packet(struct urb* urb,
-	       			 uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3)
+static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0,
+					       uint8_t p1, uint8_t p2, uint8_t p3)
 {
 
 	uint8_t* buf = (uint8_t*)urb->transfer_buffer + urb->transfer_buffer_length;
@@ -276,12 +340,29 @@ static inline void output_packet(struct 
 }
 
 /*
+ * Adds one Midiman packet to the output buffer.
+ */
+static void snd_usbmidi_output_midiman_packet(struct urb* urb, uint8_t p0,
+					      uint8_t p1, uint8_t p2, uint8_t p3)
+{
+
+	uint8_t* buf = (uint8_t*)urb->transfer_buffer + urb->transfer_buffer_length;
+	buf[0] = p1;
+	buf[1] = p2;
+	buf[2] = p3;
+	buf[3] = (p0 & 0xf0) | snd_usbmidi_cin_length[p0 & 0x0f];
+	urb->transfer_buffer_length += 4;
+}
+
+/*
  * Converts MIDI commands to USB MIDI packets.
  */
 static void snd_usbmidi_transmit_byte(usbmidi_out_port_t* port,
 				      uint8_t b, struct urb* urb)
 {
 	uint8_t p0 = port->cable;
+	void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t) =
+		port->ep->umidi->usb_protocol_ops->output_packet;
 
 	if (b >= 0xf8) {
 		output_packet(urb, p0 | 0x0f, b, 0, 0);
@@ -370,63 +451,237 @@ static void snd_usbmidi_transmit_byte(us
 	}
 }
 
-/*
- * Moves data from one substream buffer to the URB transfer buffer.
- */
-static void snd_usbmidi_transmit(snd_usb_midi_out_endpoint_t* ep, int port_idx)
+static void snd_usbmidi_standard_output(snd_usb_midi_out_endpoint_t* ep)
 {
 	struct urb* urb = ep->urb;
-	usbmidi_out_port_t* port = &ep->ports[port_idx];
+	int p;
 
-	while (urb->transfer_buffer_length < ep->max_transfer) {
-		uint8_t b;
-		if (snd_rawmidi_transmit_peek(port->substream, &b, 1) != 1) {
-			port->active = 0;
-			break;
+	/* FIXME: lower-numbered ports can starve higher-numbered ports */
+	for (p = 0; p < 0x10; ++p) {
+		usbmidi_out_port_t* port = &ep->ports[p];
+		if (!port->active)
+			continue;
+		while (urb->transfer_buffer_length + 3 < ep->max_transfer) {
+			uint8_t b;
+			if (snd_rawmidi_transmit(port->substream, &b, 1) != 1) {
+				port->active = 0;
+				break;
+			}
+			snd_usbmidi_transmit_byte(port, b, urb);
 		}
-		snd_usbmidi_transmit_byte(port, b, urb);
-		snd_rawmidi_transmit_ack(port->substream, 1);
 	}
 }
 
+static struct usb_protocol_ops snd_usbmidi_standard_ops = {
+	.input = snd_usbmidi_standard_input,
+	.output = snd_usbmidi_standard_output,
+	.output_packet = snd_usbmidi_output_standard_packet,
+};
+
+static struct usb_protocol_ops snd_usbmidi_midiman_ops = {
+	.input = snd_usbmidi_midiman_input,
+	.output = snd_usbmidi_standard_output, 
+	.output_packet = snd_usbmidi_output_midiman_packet,
+};
+
 /*
- * This is called when some data should be transferred to the device
- * (from one or more substreams).
+ * Novation USB MIDI protocol: number of data bytes is in the first byte
+ * (when receiving) (+1!) or in the second byte (when sending); data begins
+ * at the third byte.
  */
-static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
+
+static void snd_usbmidi_novation_input(snd_usb_midi_in_endpoint_t* ep,
+				       uint8_t* buffer, int buffer_length)
 {
-	int p;
-	struct urb* urb = ep->urb;
-	unsigned long flags;
+	if (buffer_length < 2 || !buffer[0] || buffer_length < buffer[0] + 1)
+		return;
+	snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1);
+}
 
-	spin_lock_irqsave(&ep->buffer_lock, flags);
-	if (urb->status == -EINPROGRESS || ep->umidi->chip->shutdown) {
-		spin_unlock_irqrestore(&ep->buffer_lock, flags);
+static void snd_usbmidi_novation_output(snd_usb_midi_out_endpoint_t* ep)
+{
+	uint8_t* transfer_buffer;
+	int count;
+
+	if (!ep->ports[0].active)
+		return;
+	transfer_buffer = ep->urb->transfer_buffer;
+	count = snd_rawmidi_transmit(ep->ports[0].substream,
+				     &transfer_buffer[2],
+				     ep->max_transfer - 2);
+	if (count < 1) {
+		ep->ports[0].active = 0;
 		return;
 	}
+	transfer_buffer[0] = 0;
+	transfer_buffer[1] = count;
+	ep->urb->transfer_buffer_length = 2 + count;
+}
 
-	urb->transfer_buffer_length = 0;
-	for (p= 0; p < 0x10; ++p)
-		if (ep->ports[p].active)
-			snd_usbmidi_transmit(ep, p);
+static struct usb_protocol_ops snd_usbmidi_novation_ops = {
+	.input = snd_usbmidi_novation_input,
+	.output = snd_usbmidi_novation_output,
+};
 
-	if (urb->transfer_buffer_length > 0) {
-		if (ep->umidi->quirk && ep->umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
-			snd_usbmidi_convert_to_midiman(urb);
+/*
+ * Mark of the Unicorn USB MIDI protocol: raw MIDI.
+ */
 
-		urb->dev = ep->umidi->chip->dev;
-		snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
+static void snd_usbmidi_motu_input(snd_usb_midi_in_endpoint_t* ep,
+				   uint8_t* buffer, int buffer_length)
+{
+	snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
+}
+
+static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep)
+{
+	int count;
+
+	if (!ep->ports[0].active)
+		return;
+	count = snd_rawmidi_transmit(ep->ports[0].substream,
+				     ep->urb->transfer_buffer,
+				     ep->max_transfer);
+	if (count < 1) {
+		ep->ports[0].active = 0;
+		return;
 	}
-	spin_unlock_irqrestore(&ep->buffer_lock, flags);
+	ep->urb->transfer_buffer_length = count;
 }
 
-static void snd_usbmidi_out_tasklet(unsigned long data)
+static struct usb_protocol_ops snd_usbmidi_motu_ops = {
+	.input = snd_usbmidi_motu_input,
+	.output = snd_usbmidi_motu_output,
+};
+
+/*
+ * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching.
+ */
+
+static void snd_usbmidi_emagic_init_out(snd_usb_midi_out_endpoint_t* ep)
 {
-	snd_usb_midi_out_endpoint_t* ep = (snd_usb_midi_out_endpoint_t *) data;
+	static const u8 init_data[] = {
+		/* initialization magic: "get version" */
+		0xf0,
+		0x00, 0x20, 0x31,	/* Emagic */
+		0x64,			/* Unitor8 */
+		0x0b,			/* version number request */
+		0x00,			/* command version */
+		0x00,			/* EEPROM, box 0 */
+		0xf7
+	};
+	send_bulk_static_data(ep, init_data, sizeof(init_data));
+	/* while we're at it, pour on more magic */
+	send_bulk_static_data(ep, init_data, sizeof(init_data));
+}
+
+static void snd_usbmidi_emagic_finish_out(snd_usb_midi_out_endpoint_t* ep)
+{
+	static const u8 finish_data[] = {
+		/* switch to patch mode with last preset */
+		0xf0,
+		0x00, 0x20, 0x31,	/* Emagic */
+		0x64,			/* Unitor8 */
+		0x10,			/* patch switch command */
+		0x00,			/* command version */
+		0x7f,			/* to all boxes */
+		0x40,			/* last preset in EEPROM */
+		0xf7
+	};
+	send_bulk_static_data(ep, finish_data, sizeof(finish_data));
+}
+
+static void snd_usbmidi_emagic_input(snd_usb_midi_in_endpoint_t* ep,
+				     uint8_t* buffer, int buffer_length)
+{
+	/* ignore padding bytes at end of buffer */
+	while (buffer_length > 0 && buffer[buffer_length - 1] == 0xff)
+		--buffer_length;
+
+	/* handle F5 at end of last buffer */
+	if (ep->seen_f5)
+		goto switch_port;
 
-	snd_usbmidi_do_output(ep);
+	while (buffer_length > 0) {
+		int i;
+
+		/* determine size of data until next F5 */
+		for (i = 0; i < buffer_length; ++i)
+			if (buffer[i] == 0xf5)
+				break;
+		snd_usbmidi_input_data(ep, ep->current_port, buffer, i);
+		buffer += i;
+		buffer_length -= i;
+
+		if (buffer_length <= 0)
+			break;
+		/* assert(buffer[0] == 0xf5); */
+		ep->seen_f5 = 1;
+		++buffer;
+		--buffer_length;
+
+	switch_port:
+		if (buffer_length <= 0)
+			break;
+		if (buffer[0] < 0x80) {
+			ep->current_port = (buffer[0] - 1) & 15;
+			++buffer;
+			--buffer_length;
+		}
+		ep->seen_f5 = 0;
+	}
+}
+
+static void snd_usbmidi_emagic_output(snd_usb_midi_out_endpoint_t* ep)
+{
+	int port0 = ep->current_port;
+	uint8_t* buf = ep->urb->transfer_buffer;
+	int buf_free = ep->max_transfer;
+	int length, i;
+
+	for (i = 0; i < 0x10; ++i) {
+		/* round-robin, starting at the last current port */
+		int portnum = (port0 + i) & 15;
+		usbmidi_out_port_t* port = &ep->ports[portnum];
+
+		if (!port->active)
+			continue;
+		if (snd_rawmidi_transmit_peek(port->substream, buf, 1) != 1) {
+			port->active = 0;
+			continue;
+		}
+
+		if (portnum != ep->current_port) {
+			if (buf_free < 2)
+				break;
+			ep->current_port = portnum;
+			buf[0] = 0xf5;
+			buf[1] = (portnum + 1) & 15;
+			buf += 2;
+			buf_free -= 2;
+		}
+
+		if (buf_free < 1)
+			break;
+		length = snd_rawmidi_transmit(port->substream, buf, buf_free);
+		if (length > 0) {
+			buf += length;
+			buf_free -= length;
+			if (buf_free < 1)
+				break;
+		}
+	}
+	ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
 }
 
+static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
+	.input = snd_usbmidi_emagic_input,
+	.output = snd_usbmidi_emagic_output,
+	.init_out_endpoint = snd_usbmidi_emagic_init_out,
+	.finish_out_endpoint = snd_usbmidi_emagic_finish_out,
+};
+
+
 static int snd_usbmidi_output_open(snd_rawmidi_substream_t* substream)
 {
 	snd_usb_midi_t* umidi = substream->rmidi->private_data;
@@ -483,6 +738,12 @@ static int snd_usbmidi_input_close(snd_r
 
 static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t* substream, int up)
 {
+	snd_usb_midi_t* umidi = substream->rmidi->private_data;
+
+	if (up)
+		set_bit(substream->number, &umidi->input_triggered);
+	else
+		clear_bit(substream->number, &umidi->input_triggered);
 }
 
 static snd_rawmidi_ops_t snd_usbmidi_output_ops = {
@@ -511,57 +772,6 @@ static void snd_usbmidi_in_endpoint_dele
 }
 
 /*
- * For Roland devices, use the alternate setting which uses interrupt
- * transfers for input.
- */
-static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi)
-{
-	struct usb_interface* intf;
-	struct usb_host_interface *hostif;
-	struct usb_interface_descriptor* intfd;
-
-	if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) != 0x0582)
-		return NULL;
-	intf = umidi->iface;
-	if (!intf || intf->num_altsetting != 2)
-		return NULL;
-
-	hostif = &intf->altsetting[0];
-	intfd = get_iface_desc(hostif);
-	if (intfd->bNumEndpoints != 2 ||
-	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
-	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
-		return NULL;
-
-	hostif = &intf->altsetting[1];
-	intfd = get_iface_desc(hostif);
-	if (intfd->bNumEndpoints != 2 ||
-	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
-	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
-		return NULL;
-
-	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
-		    intfd->bAlternateSetting);
-	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
-			  intfd->bAlternateSetting);
-	return get_endpoint(hostif, 1);
-}
-
-static struct usb_endpoint_descriptor* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi)
-{
-	struct usb_interface* intf = umidi->iface;
-	struct usb_host_interface *hostif;
-	struct usb_interface_descriptor *intfd;
-	if (!intf)
-		return NULL;
-	hostif = &intf->altsetting[0];
-	intfd = get_iface_desc(hostif);
-	if (intfd->bNumEndpoints < 1)
-		return NULL;
-	return get_endpoint(hostif, 0);
-}
-
-/*
  * Creates an input endpoint.
  */
 static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
@@ -569,7 +779,6 @@ static int snd_usbmidi_in_endpoint_creat
 					  snd_usb_midi_endpoint_t* rep)
 {
 	snd_usb_midi_in_endpoint_t* ep;
-	struct usb_endpoint_descriptor* int_epd;
 	void* buffer;
 	unsigned int pipe;
 	int length;
@@ -580,17 +789,12 @@ static int snd_usbmidi_in_endpoint_creat
 		return -ENOMEM;
 	ep->umidi = umidi;
 
-	if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
-		int_epd = snd_usbmidi_get_midiman_int_epd(umidi);
-	else
-		int_epd = snd_usbmidi_get_int_epd(umidi);
-
 	ep->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!ep->urb) {
 		snd_usbmidi_in_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	if (int_epd)
+	if (ep_info->in_interval)
 		pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);
 	else
 		pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
@@ -600,10 +804,10 @@ static int snd_usbmidi_in_endpoint_creat
 		snd_usbmidi_in_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	if (int_epd)
+	if (ep_info->in_interval)
 		usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
 				 snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
-				 ep, int_epd->bInterval);
+				 ep, ep_info->in_interval);
 	else
 		usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
 				  snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
@@ -613,12 +817,12 @@ static int snd_usbmidi_in_endpoint_creat
 	return 0;
 }
 
-static int snd_usbmidi_count_bits(uint16_t x)
+static unsigned int snd_usbmidi_count_bits(unsigned int x)
 {
-	int i, bits = 0;
+	unsigned int bits = 0;
 
-	for (i = 0; i < 16; ++i)
-		bits += (x & (1 << i)) != 0;
+	for (; x; x >>= 1)
+		bits += x & 1;
 	return bits;
 }
 
@@ -660,8 +864,9 @@ static int snd_usbmidi_out_endpoint_crea
 		snd_usbmidi_out_endpoint_delete(ep);
 		return -ENOMEM;
 	}
+	/* we never use interrupt output pipes */
 	pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
-	ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1) & ~3;
+	ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
 	buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
 	if (!buffer) {
 		snd_usbmidi_out_endpoint_delete(ep);
@@ -680,6 +885,9 @@ static int snd_usbmidi_out_endpoint_crea
 			ep->ports[i].cable = i << 4;
 		}
 
+	if (umidi->usb_protocol_ops->init_out_endpoint)
+		umidi->usb_protocol_ops->init_out_endpoint(ep);
+
 	rep->out = ep;
 	return 0;
 }
@@ -712,8 +920,11 @@ void snd_usbmidi_disconnect(struct list_
 	umidi = list_entry(p, snd_usb_midi_t, list);
 	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
 		snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
-		if (ep->out && ep->out->urb)
+		if (ep->out && ep->out->urb) {
 			usb_kill_urb(ep->out->urb);
+			if (umidi->usb_protocol_ops->finish_out_endpoint)
+				umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
+		}
 		if (ep->in && ep->in->urb)
 			usb_kill_urb(ep->in->urb);
 	}
@@ -819,6 +1030,13 @@ static struct {
 	/* M-Audio MidiSport 8x8 */
 	{0x0763, 0x1031, 8, "%s Control"},
 	{0x0763, 0x1033, 8, "%s Control"},
+	/* MOTU Fastlane */
+	{0x07fd, 0x0001, 0, "%s MIDI A"},
+	{0x07fd, 0x0001, 1, "%s MIDI B"},
+	/* Emagic Unitor8/AMT8/MT4 */
+	{0x086a, 0x0001, 8, "%s Broadcast"},
+	{0x086a, 0x0002, 8, "%s Broadcast"},
+	{0x086a, 0x0003, 4, "%s Broadcast"},
 };
 
 static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi,
@@ -928,7 +1146,8 @@ static int snd_usbmidi_get_ms_info(snd_u
 	for (i = 0; i < intfd->bNumEndpoints; ++i) {
 		hostep = &hostif->endpoint[i];
 		ep = get_ep_desc(hostep);
-		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK &&
+		    (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
 			continue;
 		ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra;
 		if (hostep->extralen < 4 ||
@@ -944,6 +1163,8 @@ static int snd_usbmidi_get_ms_info(snd_u
 				}
 			}
 			endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+				endpoints[epidx].out_interval = ep->bInterval;
 			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
 				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
@@ -955,6 +1176,8 @@ static int snd_usbmidi_get_ms_info(snd_u
 				}
 			}
 			endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+				endpoints[epidx].in_interval = ep->bInterval;
 			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
 				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
@@ -964,38 +1187,93 @@ static int snd_usbmidi_get_ms_info(snd_u
 }
 
 /*
- * If the endpoints aren't specified, use the first bulk endpoints in the
- * first alternate setting of the interface.
+ * On Roland devices, use the second alternate setting to be able to use
+ * the interrupt input endpoint.
+ */
+static void snd_usbmidi_switch_roland_altsetting(snd_usb_midi_t* umidi)
+{
+	struct usb_interface* intf;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
+
+	intf = umidi->iface;
+	if (!intf || intf->num_altsetting != 2)
+		return;
+
+	hostif = &intf->altsetting[1];
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints != 2 ||
+	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
+	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
+		return;
+
+	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
+		    intfd->bAlternateSetting);
+	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
+			  intfd->bAlternateSetting);
+}
+
+/*
+ * Try to find any usable endpoints in the interface.
  */
-static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
-				       snd_usb_midi_endpoint_info_t* endpoint)
+static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi,
+					snd_usb_midi_endpoint_info_t* endpoint,
+					int max_endpoints)
 {
 	struct usb_interface* intf;
 	struct usb_host_interface *hostif;
 	struct usb_interface_descriptor* intfd;
 	struct usb_endpoint_descriptor* epd;
-	int i;
+	int i, out_eps = 0, in_eps = 0;
+
+	if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582)
+		snd_usbmidi_switch_roland_altsetting(umidi);
 
 	intf = umidi->iface;
 	if (!intf || intf->num_altsetting < 1)
 		return -ENOENT;
-	hostif = intf->altsetting;
+	hostif = intf->cur_altsetting;
 	intfd = get_iface_desc(hostif);
-	if (intfd->bNumEndpoints < 1)
-		return -ENOENT;
 
 	for (i = 0; i < intfd->bNumEndpoints; ++i) {
 		epd = get_endpoint(hostif, i);
-		if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+		if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK &&
+		    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
 			continue;
-		if (!endpoint->out_ep && endpoint->out_cables &&
-		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
-			endpoint->out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-		if (!endpoint->in_ep && endpoint->in_cables &&
-		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-			endpoint->in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+		if (out_eps < max_endpoints &&
+		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+			endpoint[out_eps].out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+				endpoint[out_eps].out_interval = epd->bInterval;
+			++out_eps;
+		}
+		if (in_eps < max_endpoints &&
+		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			endpoint[in_eps].in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+				endpoint[in_eps].in_interval = epd->bInterval;
+			++in_eps;
+		}
 	}
-	return 0;
+	return (out_eps || in_eps) ? 0 : -ENOENT;
+}
+
+/*
+ * Detects the endpoints for one-port-per-endpoint protocols.
+ */
+static int snd_usbmidi_detect_per_port_endpoints(snd_usb_midi_t* umidi,
+						 snd_usb_midi_endpoint_info_t* endpoints)
+{
+	int err, i;
+	
+	err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS);
+	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+		if (endpoints[i].out_ep)
+			endpoints[i].out_cables = 0x0001;
+		if (endpoints[i].in_ep)
+			endpoints[i].in_cables = 0x0001;
+	}
+	return err;
 }
 
 /*
@@ -1034,7 +1312,7 @@ static int snd_usbmidi_detect_yamaha(snd
 	if (!endpoint->in_cables && !endpoint->out_cables)
 		return -ENOENT;
 
-	return snd_usbmidi_detect_endpoint(umidi, endpoint);
+	return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
 }
 
 /*
@@ -1098,11 +1376,11 @@ static int snd_usbmidi_create_endpoints_
 		return err;
 
 	ep_info.in_ep = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	ep_info.in_interval = get_endpoint(hostif, 0)->bInterval;
 	ep_info.in_cables = endpoint->in_cables;
 	err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
 	if (err < 0)
 		return err;
-	umidi->endpoints[0].in->urb->complete = snd_usb_complete_callback(snd_usbmidi_in_midiman_complete);
 
 	if (endpoint->out_cables > 0x0001) {
 		ep_info.out_ep = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
@@ -1203,6 +1481,7 @@ int snd_usb_create_midi_interface(snd_us
 	umidi->chip = chip;
 	umidi->iface = iface;
 	umidi->quirk = quirk;
+	umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
 
 	/* detect the endpoint(s) to use */
 	memset(endpoints, 0, sizeof(endpoints));
@@ -1213,16 +1492,31 @@ int snd_usb_create_midi_interface(snd_us
 		case QUIRK_MIDI_FIXED_ENDPOINT:
 			memcpy(&endpoints[0], quirk->data,
 			       sizeof(snd_usb_midi_endpoint_info_t));
-			err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
+			err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
 			break;
 		case QUIRK_MIDI_YAMAHA:
 			err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
 			break;
 		case QUIRK_MIDI_MIDIMAN:
+			umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
 			memcpy(&endpoints[0], quirk->data,
 			       sizeof(snd_usb_midi_endpoint_info_t));
 			err = 0;
 			break;
+		case QUIRK_MIDI_NOVATION:
+			umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
+			err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+			break;
+		case QUIRK_MIDI_MOTU:
+			umidi->usb_protocol_ops = &snd_usbmidi_motu_ops;
+			err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+			break;
+		case QUIRK_MIDI_EMAGIC:
+			umidi->usb_protocol_ops = &snd_usbmidi_emagic_ops;
+			memcpy(&endpoints[0], quirk->data,
+			       sizeof(snd_usb_midi_endpoint_info_t));
+			err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
+			break;
 		default:
 			snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 			err = -ENXIO;
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -305,7 +305,7 @@ static int get_ctl_value(usb_mixer_elem_
 				    request,
 				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 				    validx, cval->ctrlif | (cval->id << 8),
-				    buf, val_len, HZ / 10) >= 0) {
+				    buf, val_len, 100) >= 0) {
 			*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
 			return 0;
 		}
@@ -343,7 +343,7 @@ static int set_ctl_value(usb_mixer_elem_
 				    request,
 				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 				    validx, cval->ctrlif | (cval->id << 8),
-				    buf, val_len, HZ / 10) >= 0)
+				    buf, val_len, 100) >= 0)
 			return 0;
 	snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
 	return -EINVAL;
@@ -1519,7 +1519,7 @@ int snd_usb_create_mixer(snd_usb_audio_t
 
 	/* check the mapping table */
 	for (map = usbmix_ctl_maps; map->vendor; map++) {
-		if (map->vendor == le16_to_cpu(dev->idVendor) && map->product == le16_to_cpu(dev->idProduct)) {
+		if (map->vendor == state.vendor && map->product == state.product) {
 			state.map = map->map;
 			chip->ignore_ctl_error = map->ignore_ctl_error;
 			break;
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -72,6 +72,8 @@ YAMAHA_DEVICE(0x1007, "MOTIF8"),
 YAMAHA_DEVICE(0x1008, "UX96"),
 YAMAHA_DEVICE(0x1009, "UX16"),
 YAMAHA_INTERFACE(0x100a, 3, "EOS BX"),
+YAMAHA_DEVICE(0x100c, "UC-MX"),
+YAMAHA_DEVICE(0x100d, "UC-KX"),
 YAMAHA_DEVICE(0x100e, "S08"),
 YAMAHA_DEVICE(0x100f, "CLP-150"),
 YAMAHA_DEVICE(0x1010, "CLP-170"),
@@ -86,6 +88,7 @@ YAMAHA_DEVICE(0x1019, "CVP-208"),
 YAMAHA_DEVICE(0x101a, "CVP-210"),
 YAMAHA_DEVICE(0x101b, "PSR-1100"),
 YAMAHA_DEVICE(0x101c, "PSR-2100"),
+YAMAHA_DEVICE(0x101d, "CLP-175"),
 YAMAHA_DEVICE(0x101e, "PSR-K1"),
 YAMAHA_DEVICE(0x1020, "EZ-250i"),
 YAMAHA_DEVICE(0x1021, "MOTIF ES 6"),
@@ -125,9 +128,12 @@ YAMAHA_DEVICE(0x5005, "ACU16-C"),
 YAMAHA_DEVICE(0x5006, "NHB32-C"),
 YAMAHA_DEVICE(0x5007, "DM1000"),
 YAMAHA_DEVICE(0x5008, "01V96"),
+YAMAHA_DEVICE(0x5009, "SPX2000"),
 YAMAHA_DEVICE(0x500a, "PM5D"),
 YAMAHA_DEVICE(0x500b, "DME64N"),
 YAMAHA_DEVICE(0x500c, "DME24N"),
+YAMAHA_DEVICE(0x500d, NULL),
+YAMAHA_DEVICE(0x500e, NULL),
 YAMAHA_DEVICE(0x7000, "DTX"),
 YAMAHA_DEVICE(0x7010, "UB99"),
 #undef YAMAHA_DEVICE
@@ -629,6 +635,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 {
+	USB_DEVICE(0x0582, 0x0042),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "RS-70",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0044),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
@@ -685,19 +704,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 {
-	USB_DEVICE(0x0582, 0x0065),
-	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
-		.vendor_name = "EDIROL",
-		.product_name = "PCR-1",
-		.ifnum = 0,
-		.type = QUIRK_MIDI_FIXED_ENDPOINT,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0001,
-			.in_cables  = 0x0003
-		}
-	}
-},
-{
 	/*
 	 * This quirk is for the "Advanced Driver" mode. If off, the UA-3FX
 	 * is standard compliant, but has only 16-bit PCM.
@@ -732,6 +738,45 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		.type = QUIRK_MIDI_STANDARD_INTERFACE
 	}
 },
+{
+	USB_DEVICE(0x0582, 0x0065),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "PCR-1",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0003
+		}
+	}
+},
+{
+	USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "SP-606",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x006d),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "FANTOM-X",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
 {	/*
 	 * This quirk is for the "Advanced" modes of the Edirol UA-25.
 	 * If the switch is not in an advanced setting, the UA-25 has
@@ -763,6 +808,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		}
 	}
 },
+{
+	USB_DEVICE(0x0582, 0x0075),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "BOSS",
+		.product_name = "DR-880",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
 
 /* Midiman/M-Audio devices */
 {
@@ -876,6 +934,22 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 			 * but captured samples are big-endian (see usbaudio.c).
 			 */
 			{
+				.ifnum = 0,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
 				.ifnum = 4,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
@@ -884,6 +958,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
 			{
+				.ifnum = 6,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
 				.ifnum = 7,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
@@ -936,27 +1014,81 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "M-Audio",
 		.product_name = "OmniStudio",
-		.ifnum = 9,
-		.type = QUIRK_MIDI_MIDIMAN,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0001,
-			.in_cables  = 0x0001
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 4,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 5,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 6,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 7,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 8,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 9,
+				.type = QUIRK_MIDI_MIDIMAN,
+				.data = & (const snd_usb_midi_endpoint_info_t) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
 		}
 	}
 },
 
 /* Mark of the Unicorn devices */
 {
-	/* thanks to Woodley Packard <sweaglesw@thibs.menloschool.org> */
+	/* thanks to Robert A. Lerche <ral 'at' msbit.com> */
 	USB_DEVICE(0x07fd, 0x0001),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "MOTU",
 		.product_name = "Fastlane",
-		.ifnum = 1,
-		.type = QUIRK_MIDI_FIXED_ENDPOINT,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0003,
-			.in_cables  = 0x0003
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_MIDI_MOTU
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
 		}
 	}
 },
@@ -972,6 +1104,47 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	
 },
 
+/* Emagic devices */
+{
+	USB_DEVICE(0x086a, 0x0001),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Emagic",
+		/* .product_name = "Unitor8", */
+		.ifnum = 2,
+		.type = QUIRK_MIDI_EMAGIC,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x80ff,
+			.in_cables  = 0x80ff
+		}
+	}
+},
+{
+	USB_DEVICE(0x086a, 0x0002),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Emagic",
+		/* .product_name = "AMT8", */
+		.ifnum = 2,
+		.type = QUIRK_MIDI_EMAGIC,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x80ff,
+			.in_cables  = 0x80ff
+		}
+	}
+},
+{
+	USB_DEVICE(0x086a, 0x0003),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Emagic",
+		/* .product_name = "MT4", */
+		.ifnum = 2,
+		.type = QUIRK_MIDI_EMAGIC,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x800f,
+			.in_cables  = 0x8003
+		}
+	}
+},
+
 {
 	USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
@@ -982,6 +1155,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 
+/* Novation EMS devices */
+{
+	USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation",
+		.product_name = "ReMOTE Audio/XStation",
+		.ifnum = 4,
+		.type = QUIRK_MIDI_NOVATION
+	}
+},
+{
+	USB_DEVICE_VENDOR_SPEC(0x1235, 0x0002),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation",
+		.product_name = "Speedio",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_NOVATION
+	}
+},
+{
+	USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation",
+		.product_name = "ReMOTE25",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_NOVATION
+	}
+},
+
 {
 	/*
 	 * Some USB MIDI devices don't have an audio control interface,
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -226,7 +226,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_
 		if (err)
 			snd_printk("usb_set_interface error \n");
 		else
-			err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6*HZ);
+			err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000);
 		kfree(buf);
 	}
 	if (err)
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -1,6 +1,11 @@
 /*
  * usbusy2y.c - ALSA USB US-428 Driver
  *
+2005-04-14 Karsten Wiese
+	Version 0.8.7.2:
+	Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom.
+	Tested ok with kernel 2.6.12-rc2.
+
 2004-12-14 Karsten Wiese
 	Version 0.8.7.1:
 	snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open.
@@ -143,7 +148,7 @@
 
 
 MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
-MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
 
@@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct 
 	if (ptr) {
 		usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr);
 		struct list_head* p;
-		if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP)	// on 2.6.1 kernel snd_usbmidi_disconnect()
-			return;					// calls us back. better leave :-) .
 		usX2Y->chip.shutdown = 1;
 		usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
 		usX2Y_unlinkSeq(&usX2Y->AS04);
@@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct 
 		}
 		if (usX2Y->us428ctls_sharedmem) 
 			wake_up(&usX2Y->us428ctls_wait_queue_head);
-		snd_card_free_in_thread((snd_card_t*)ptr);
+		snd_card_free((snd_card_t*)ptr);
 	}
 }
 
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -415,7 +415,6 @@ static int usX2Y_urbs_allocate(snd_usX2Y
 	unsigned int pipe;
 	int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 	struct usb_device *dev = subs->usX2Y->chip.dev;
-	struct usb_host_endpoint *ep;
 
 	pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
 			usb_rcvisocpipe(dev, subs->endpoint);
